Преглед на файлове

monk 0.40.0 source added

nitrologic преди 10 години
родител
ревизия
5697319761
променени са 4 файла, в които са добавени 8064 реда и са изтрити 0 реда
  1. 8064 0
      monk.bmx
  2. BIN
      monk.icns
  3. BIN
      monk.o
  4. BIN
      monktoolbar.png

+ 8064 - 0
monk.bmx

@@ -0,0 +1,8064 @@
+' monk.bmx 
+
+Strict
+
+Framework MaxGUI.Drivers
+Import MaxGUI.ProxyGadgets
+
+Import brl.eventqueue
+Import brl.standardio
+Import brl.filesystem
+Import brl.system
+Import brl.ramstream
+Import pub.freeprocess
+Import brl.pngloader
+Import brl.timer
+Import brl.maxutil
+Import brl.retro
+
+Import pub.stdc
+
+?Win32
+Import "monk.o"
+?
+
+AppTitle = "Monk"
+
+Const VERSION$="0.40.00"
+Const ABOUT$="Monk "+VERSION+" - (c) 2014 Simon Armstrong"
+
+Incbin "monkicon.png"
+Incbin "monktoolbar.png"
+
+?Linux
+Incbin "window_icon.png"
+?
+
+Const TIMER_FREQUENCY=30
+
+Global BCC_VERSION$="{unknown}"	'not valid until codeplay opened
+
+Const EOL$="~n"
+
+Const FileTypes$="monkey,bmx,bbdoc,txt,ini,doc,plist,bb,cpp,c,cc,m,cxx,s,glsl,hlsl,lua,py,h,hpp,html,htm,css,js,bat,mm,as,java,bbx,cs,xml,properties,template"
+Const FileTypeFilters$="Code Files:"+FileTypes$+";All Files:*"
+
+Const WIKI_URL$="http://blitz-wiki.appspot.com/"
+Const WIKI_LOCAL$="/docs/blitz-wiki.appspot.com/"
+Const WIKI_LOCAL_SUFFIX$="4d8a.html"
+
+Const WIKI_ARGS$="?format=mobile"
+Const WIKI_HOST$="blitz-wiki.appspot.com"
+Const WIKI_INDEX$="w/index"
+Const WIKI_RSS_INDEX$="w/index.rss"
+Const WIKI_SITE_INDEX$="sitemap.xml"
+
+Const CLOUDHOST$="commondatastorage.googleapis.com"
+Const CLOUD$="http://"+CLOUDHOST+"/monkeycoder.co.nz/"
+
+Const MonkeyWords$=";"+..
+	"void;strict;public;private;property;"+..
+	"bool;int;float;string;array;object;mod;continue;exit;"+..
+	"include;import;module;extern;"+..
+	"new;self;super;eachin;true;false;null;not;"+..
+	"extends;abstract;final;native;select;case;default;"+..
+	"const;local;global;field;method;function;class;interface;implements;"+..
+	"and;or;shl;shr;end;if;then;else;elseif;endif;while;wend;repeat;until;forever;for;to;step;next;return;inline;"+..
+	"#rem;"
+
+Const MonkeyFunctions$=";"+..
+	"Error;Print;LoadState;LoadString;Millisecs;SaveState;SetUpdateRate;UpdateRate;"+..
+	"Cls;DeviceHeight;DeviceWidth;DrawCircle;DrawEllipse;DrawImage;DrawImageRect;DrawLine;DrawOval;DrawPoint;DrawPoly;DrawRect;DrawText;GetAlpha;GetBlend;GetColor;GetFont;GetMatrix;GetScissor;LoadImage;PopMatrix;PushMatrix;Rotate;Scale;SetAlpha;SetBlend;SetColor;SetFont;SetMatrix;SetScissor;Transform;Translate;"+..
+	"AccelX;AccelY;AccelZ;DisableKeyboard;EnableKeyboard;GetChar;JoyDown;JoyHit;KeyDown;KeyHit;MouseDown;MouseHit;MouseX;MouseY;TouchDown;TouchHit;TouchX;TouchY;"+..
+	"ChannelState;LoadSound;MusicState;PauseChannel;PauseMusic;PlayMusic;PlaySound;ResumeChannel;ResumeMusic;SetChannelPan;SetChannelRate;SetChannelVolume;SetMusicVolume;StopChannel;StopMusic;"+..
+	"HALFPI;Pi;TWOPI;"+..
+	"ACos;ACosr;ASin;ASinr;ATan;ATan2;ATan2r;ATanr;Abs;Ceil;Clamp;Cos;Cosr;Exp;Floor;Log;Max;Min;Pow;Sgn;Sin;Sinr;Sqrt;Tan;Tanr;"+..
+	"List;Map;Stack;Set;FloatList;FloatMap;FloatStack;FloatSet;IntList;IntMap;IntStack;IntSet;StringList;StringMap;StringStack;StringSet;"+..
+	"AppArgs;AppPath;ChangeDir;CopyDir;CopyFile;CreateDir;CurrentDir;DeleteDir;DeleteFile;Execute;ExitApp;ExtractDir;FileSize;FileTime;FileType;GetEnv;LoadDir;LoadString;RealPath;SaveString;SetEnv;StripAll;StripDir;StripExt;"
+
+?MacOS
+Global SVNCMD$="/usr/bin/svn"
+Const LABELOFFSET=2
+?Win32
+Global SVNCMD$="svn"
+Const LABELOFFSET=4
+?Linux
+Global SVNCMD$="/usr/bin/svn"
+Const LABELOFFSET=0
+?
+
+Const MENUNEW=1
+Const MENUOPEN=2
+Const MENUCLOSE=3
+Const MENUSAVE=4
+Const MENUSAVEAS=5
+Const MENUSAVEALL=6
+Const MENUPRINT=7
+Const MENUQUIT=8
+
+Const MENUUNDO=9
+Const MENUREDO=10
+Const MENUCUT=11
+Const MENUCOPY=12
+Const MENUPASTE=13
+Const MENUSELECTALL=14
+Const MENUGOTO=15
+Const MENUINDENT=16
+Const MENUOUTDENT=17
+Const MENUFIND=18
+Const MENUFINDNEXT=19
+Const MENUREPLACE=20
+Const MENUNEXT=21
+Const MENUPREV=22
+Const MENUBUILD=23
+Const MENURUN=24
+
+Const MENUSTEP=25
+Const MENUSTEPIN=26
+Const MENUSTEPOUT=27
+Const MENUSTOP=28
+
+Const MENULOCKBUILD=29
+Const MENUUNLOCKBUILD=30
+Const MENUBUILDMODULES=31
+Const MENUBUILDALLMODULES=32
+
+Const MENUQUICKENABLED=33
+Const MENUDEBUGENABLED=34
+Const MENUGUIENABLED=35
+
+Const MENUCOMMANDLINE=36
+'Const MENUSYNCMODS=37
+Const MENUIMPORTBB=38
+Const MENUFINDINFILES=39
+Const MENUPROJECTMANAGER=40
+Const MENUSHOWCONSOLE=41
+Const MENUOPTIONS=42
+
+Const MENUHOME=43
+Const MENUBACK=44
+Const MENUFORWARD=45
+Const MENUQUICKHELP=46
+Const MENUABOUT=47
+
+Const MENUNEWVIEW=48
+Const MENUDOCMODS=49
+
+Const MENUTRIGGERDOCMODS=50
+Const MENUTRIGGERSYNCDOCS=51
+
+Const MENUCLOSEALL=53
+
+Const MENUREFRESH=54
+Const MENUBROWSE=55
+Const MENUSHELL=56
+Const MENUPROPS=57
+
+Const MENUUPDATE=58
+Const MENUCOMMIT=59
+
+Const MENUCLOSEOTHERS=60
+
+Const MENUTHREADEDENABLED=61
+
+Const MENUCANCEL=62
+Const MENUESCAPE=63
+Const MENUBACKSPACE=64
+
+Const MENUREMOVE=65
+
+Const MENURECENT=256
+
+Const TB_BACK=0
+Const TB_FORWARDS=1
+Const TB_REFRESH=2
+Const TB_HOME=3
+
+Const TB_NEW=4
+Const TB_OPEN=5
+Const TB_CLOSE=6
+Const TB_SAVE=7
+Const TB_CUT=8
+Const TB_COPY=9
+Const TB_PASTE=10
+Const TB_FIND=11
+Const TB_BUILD=12
+Const TB_BUILDRUN=13
+Const TB_STEP=14
+Const TB_STEPIN=15
+Const TB_STEPOUT=16
+Const TB_STOP=17
+Const TB_CONTINUE=18
+
+Const TAB$=Chr(9)
+Const QUOTES$=Chr(34)
+
+Global TEMPCOUNT
+Global is_demo
+Global codeplay:TCodePlay
+
+Function CheckDemo()
+	If Not is_demo Return 1
+	Notify "This feature is unavailable in the demo version of BlitzMax."
+	Return 0
+End Function
+
+codeplay=New TCodePlay
+codeplay.Initialize
+
+While codeplay.running
+	codeplay.poll
+Wend
+
+End
+
+Function Quote$(a$)		'add quotes to arg if spaces found
+	Local	p
+	If Not a.length Return
+	If a[0]=34 Return a	'already quoted
+	p=a.find(" ")
+	If p=-1 Return a	'no spaces
+	Return Chr(34)+a+Chr(34)		
+End Function
+
+Type TToken
+	Field token$
+	Field help$
+	Field anchor$	
+	Field key
+	Method Create:TToken(t$,h$,a$,keyword)
+		token=t
+		help=h
+		anchor=a
+		key=keyword
+		Return Self
+	End Method
+End Type
+
+Type TQuickHelp
+	Field map:TMap=New TMap	'key=lower(token) value=token:TToken
+		
+	Method AddCommand:TQuickHelp(t$,l$,a$,keyword=True)
+		map.Insert t.ToLower(),New TToken.Create(t$,l$,a$,keyword)
+	End Method
+	
+	Method Token$(cmd$)
+		Local t:TToken = TToken(map.ValueForKey(cmd.toLower()))
+		If t 
+			If t.key Return t.token	'keywords get capitalized
+			If cmd=t.token Return cmd
+		EndIf
+	End Method
+
+	Method Key(cmd$)
+		Local t:TToken = TToken(map.ValueForKey(cmd.toLower()))
+		If t Return t.key
+	End Method
+	
+	Method Help$(cmd$)
+		Local t:TToken = TToken(map.ValueForKey(cmd.toLower()))
+		If t Return t.help
+	End Method
+	
+	Method Link$(cmd$)
+		Local t:TToken = TToken(map.ValueForKey(cmd.toLower()))
+		If t Return t.anchor
+	End Method
+
+	Function LoadMonkeyCommands:TQuickHelp(monkeypath$,host:TCodePlay)
+		Local	qh:TQuickHelp
+		Local	i,c,p,q
+		Local	token$,help$,anchor$
+		
+		qh=New TQuickHelp
+
+		For Local l$ = EachIn MonkeyWords.Split(";")
+
+			If l="" Continue
+		
+			token=l
+			help=""
+			anchor=""
+			
+			q=l.findlast("|")
+			If q>=0
+				help=l[..q]
+				anchor=l[q+1..]
+			EndIf			
+
+			token=l[..1].ToUpper()+l[1..]
+			anchor="wiki:"+token
+
+			qh.AddCommand token,help,anchor			
+			qh.AddCommand token,help,anchor
+		Next
+		
+		For Local l$ = EachIn MonkeyFunctions.Split(";")
+			token=l
+			help="press F1 again to jump see docs on "+l	'TODO: quickhelp array please
+			anchor$="wiki:"+l
+			qh.AddCommand token,help,anchor,False
+		Next
+
+'		qh.ParseHelp monkeypath,"/docs/Modules"
+		
+		Return qh
+	End Function
+	
+	
+	Function LoadCommandsTxt:TQuickHelp(bmxpath$)
+		Local	text$
+		Local	qh:TQuickHelp
+		Local	i:Int,c,p,q
+		Local	token$,help$,anchor$
+		Try
+			text=CacheAndLoadText(bmxpath+"/docs/html/Modules/commands.txt")
+		Catch exception:Object
+			Return Null
+		EndTry
+		If Not text Return Null
+		qh=New TQuickHelp
+		For Local l$ = EachIn Text.Split("~n")
+			For i=0 Until l.length
+				c=l[i]
+				If c=Asc("_") Continue
+				If c>=Asc("0") And c<=Asc("9") Continue
+				If c>=Asc("a") And c<=Asc("z") Continue
+				If c>=Asc("A") And c<=Asc("Z") Continue
+				Exit
+			Next
+			token$=l[..i]
+			help$=""
+			anchor$=""
+			q=l.findlast("|")
+			If q>=0
+				help=l[..q]
+				anchor=l[q+1..]
+			EndIf			
+			qh.AddCommand token,help,anchor
+		Next
+		Return qh
+	End Function
+End Type
+
+Const TOOLSHOW=1
+Const TOOLREFRESH=2
+Const TOOLNEW=3
+Const TOOLOPEN=4
+Const TOOLCLOSE=5
+Const TOOLSAVE=6
+Const TOOLHELP=7
+Const TOOLUNDO=8
+Const TOOLREDO=9
+Const TOOLCUT=10
+Const TOOLCOPY=11
+Const TOOLPASTE=12
+Const TOOLQUICKSAVE=13
+Const TOOLSAVEAS=14
+Const TOOLGOTO=15
+Const TOOLFIND=16
+Const TOOLFINDNEXT=17
+Const TOOLREPLACE=18
+Const TOOLBUILD=19
+Const TOOLRUN=20
+Const TOOLLOCK=21
+Const TOOLUNLOCK=22
+Const TOOLSELECT=23
+Const TOOLSELECTALL=24
+Const TOOLINDENT=25
+Const TOOLOUTDENT=26
+Const TOOLACTIVATE=27
+Const TOOLNAVIGATE=28
+Const TOOLNEWVIEW=29
+Const TOOLMENU=30
+Const TOOLPRINT=31
+Const TOOLERROR=32
+Const TOOLOUTPUT=32
+Const TOOLARCHIVE=33
+Const TOOLHISTORY=34
+Const TOOLINDEX=35
+Const TOOLESCAPE=36
+Const TOOLBACKSPACE=37
+Const TOOLCRAWL=38
+
+Type TTool
+	Method Invoke(command,argument:Object=Null)
+	End Method
+End Type
+
+Type TRequester
+	
+	Const STYLE_OK% = 1, STYLE_CANCEL% = 2
+	Const STYLE_DIVIDER% = 4, STYLE_STATUS% = 8
+	Const STYLE_RESIZABLE% = 16, STYLE_STDBORDER% = 32
+	Const STYLE_MODAL% = 64
+
+	Field	host:TCodePlay
+	Field	window:TGadget,ok:TGadget,cancel:TGadget,divider:TGadget
+	Field	centered, modal
+
+	Method initrequester(owner:TCodeplay,label$,w=260,h=60,flags=STYLE_OK|STYLE_CANCEL|STYLE_DIVIDER,oktext$="OK")
+		
+		host=owner
+		If (flags&STYLE_MODAL) Then flags:|STYLE_STDBORDER
+		
+		If (flags & (STYLE_CANCEL|STYLE_OK)) Then h:+32;If (flags&STYLE_DIVIDER) Then h:+12
+		
+		Local windowflags% = WINDOW_TITLEBAR|WINDOW_HIDDEN|WINDOW_CLIENTCOORDS
+		If (flags & STYLE_STATUS) Then windowflags:|WINDOW_STATUS
+		If (flags & STYLE_RESIZABLE) Then windowflags:|WINDOW_RESIZABLE
+		If Not (flags & STYLE_STDBORDER) Then windowflags:|WINDOW_TOOL
+		
+		window=CreateWindow(label,0,0,w,h,host.window,windowflags)
+		
+		If (flags & STYLE_RESIZABLE) Then
+			If (flags & STYLE_STDBORDER) Then SetMaxWindowSize(window,ClientWidth(Desktop()),ClientHeight(Desktop()))
+			SetMinWindowSize(window,w,h)
+		EndIf
+		
+		If (flags & STYLE_OK) Then
+			
+			ok=CreateButton(oktext,ClientWidth(window)-101,ClientHeight(window)-32,95,26,window,BUTTON_OK)
+			SetGadgetLayout(ok,EDGE_CENTERED,EDGE_ALIGNED,EDGE_CENTERED,EDGE_ALIGNED)
+			
+			If (flags & STYLE_CANCEL) Then
+				cancel=CreateButton("Cancel",6,ClientHeight(window)-32,95,26,window,BUTTON_CANCEL)
+				SetGadgetLayout(cancel,EDGE_ALIGNED,EDGE_CENTERED,EDGE_CENTERED,EDGE_ALIGNED)
+			EndIf
+			
+		Else
+			If (flags & STYLE_CANCEL) Then
+				cancel=CreateButton("Close",ClientWidth(window)-101,ClientHeight(window)-32,95,26,window,BUTTON_CANCEL)
+				SetGadgetLayout(cancel,EDGE_CENTERED,EDGE_ALIGNED,EDGE_CENTERED,EDGE_ALIGNED)
+			EndIf
+		EndIf
+		
+		If (flags & STYLE_DIVIDER) And (flags & (STYLE_OK|STYLE_CANCEL)) Then
+			divider = CreateLabel( "", 6, ClientHeight(window)-42, ClientWidth(window)-12, 4, window, LABEL_SEPARATOR )
+			SetGadgetLayout(divider,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_CENTERED,EDGE_ALIGNED)
+		EndIf
+		
+		If (flags & STYLE_MODAL) Then modal = True Else modal = False
+	
+	End Method
+	
+	Method Show()
+		Local	x,y,w,h,win:TGadget
+		If Not centered
+			win=host.window		
+			w=GadgetWidth(window)
+			h=GadgetHeight(window)
+			x=GadgetX(win)+(GadgetWidth(win)-w)/2
+			y=GadgetY(win)+(GadgetHeight(win)-h)/2
+			SetGadgetShape window,x,y,w,h
+			centered=True
+		EndIf
+		host.HookRequester Self
+		ShowGadget window
+		ActivateGadget window
+		PollSystem
+	End Method
+	
+	Method Hide()
+		EnableGadget host.window
+		HideGadget window
+		host.UnhookRequester Self
+		host.SelectPanel host.currentpanel
+	End Method
+	
+	Method IsModal()
+		Return modal
+	EndMethod
+	
+	Method Poll()
+	End Method
+End Type
+
+Type TPanelRequester Extends TRequester
+	Field	tabber:TGadget
+	Field	panels:TGadget[]
+	Field	index
+	
+	Method InitPanelRequester(owner:TCodeplay,label$,w=280,h=128)		
+		InitRequester owner,label,w,h,STYLE_OK|STYLE_CANCEL|STYLE_STDBORDER|STYLE_MODAL
+		tabber=CreateTabber(6,6,w-12,h-12,window)
+		SetGadgetLayout tabber,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED
+	End Method
+
+	Method SetPanelIndex(i)
+		HideGadget panels[index]
+		index=i
+		ShowGadget panels[index]
+		SelectGadgetItem tabber,index	
+	End Method
+	
+	Method SetPanel(panel:TGadget)
+		Local	i
+		For Local p:TGadget = EachIn panels
+			If p=panel SetPanelIndex i;Exit
+			i:+1
+		Next
+	End Method
+	
+	Method AddPanel:TGadget(name$)
+		Local	panel:TGadget
+		panel=CreatePanel(0,0,ClientWidth(tabber),ClientHeight(tabber),tabber)
+		SetGadgetLayout panel,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED
+		HideGadget panel
+		AddGadgetItem tabber,name
+		panels=panels[..panels.length+1]
+		panels[panels.length-1]=panel
+		Return panel
+	End Method
+	
+	Method RemovePanel(panel)
+	End Method
+	
+End Type
+
+Type TCmdLineRequester Extends TRequester
+	Field	label:TGadget,textfield:TGadget
+
+	Method Poll()
+		Select EventSource()
+			Case window
+				If EventID()=EVENT_WINDOWCLOSE
+					Hide
+				EndIf
+			Case ok
+				If EventID()=EVENT_GADGETACTION
+					host.SetCommandLine TextFieldText(textfield)
+					Hide
+				EndIf			
+			Case cancel
+				If EventID()=EVENT_GADGETACTION
+					SetGadgetText textfield,host.GetCommandLine()
+					Hide
+				EndIf
+			Default
+				Return 0
+		End Select
+		Return 1
+	End Method
+	
+	Method Show()
+		SetGadgetText textfield,host.GetCommandLine()
+		Super.Show()
+		ActivateGadget textfield
+	End Method
+
+	Function Create:TCmdLineRequester(host:TCodePlay)
+		Local	cmd:TCmdLineRequester = New TCmdLineRequester
+		cmd.initrequester(host,"Program Command Line",260,60,STYLE_OK|STYLE_CANCEL|STYLE_DIVIDER|STYLE_MODAL)
+		cmd.label=CreateLabel("Program command line",6,8,260,20,cmd.window)
+		cmd.textfield=CreateTextField(6,30,ClientWidth(cmd.window)-12,21,cmd.window)
+		Return cmd
+	End Function
+End Type
+
+Type TGotoRequester Extends TRequester
+	Field	linenumber:TGadget
+
+	Method Show()
+		Super.Show()
+		ActivateGadget linenumber
+	End Method
+
+	Method Poll()
+		Local	Line,data,Text$
+		Select EventSource()
+			Case linenumber
+				If EventID() = EVENT_GADGETACTION
+					Text = GadgetText(linenumber)
+					If Text And (Int(Text) <> Text) Then SetGadgetText linenumber, Int(Text)
+				EndIf
+			Case window
+				If EventID()=EVENT_WINDOWCLOSE
+					Hide
+				EndIf
+			Case ok
+				Line=Int(GadgetText(linenumber))
+				Hide
+				host.activepanel.Invoke TOOLGOTO,String(Line)
+			Case cancel
+				Hide
+			Default
+				Return 0
+		End Select
+		Return 1
+	End Method
+
+	Function Create:TGotoRequester(host:TCodePlay)
+		Local	seek:TGotoRequester = New TGotoRequester
+		seek.initrequester(host,"Goto Line",260,66,STYLE_OK|STYLE_CANCEL|STYLE_DIVIDER|STYLE_MODAL,"Goto")
+		CreateLabel("Line Number",6,8+4,114,20,seek.window)
+		seek.linenumber=CreateTextField(150,8,ClientWidth(seek.window)-(150+6),21,seek.window)
+		SetGadgetFilter( seek.linenumber, IntegerFilter )
+		Return seek
+	End Function
+	
+	Function IntegerFilter:Int( event:TEvent, context:Object )
+		Select event.id
+			Case EVENT_KEYCHAR
+				If event.data >= Asc("0") And event.data <= Asc("9") Return True
+				If event.data = 8 Or event.data = 127 Or event.data = 13 Return True
+				Return False
+			Case EVENT_KEYDOWN
+				Return True
+		EndSelect
+	EndFunction
+	
+End Type
+
+Type TColor
+	Field	red,green,blue
+
+	Method Set(rgb)
+		red=(rgb Shr 16)&$FF
+		green=(rgb Shr 8)&$FF
+		blue=rgb&$FF
+	End Method
+
+	Method ToString$()
+		Return ""+red+","+green+","+blue
+	End Method
+
+	Method FromString(s$)
+		Local	p=s.Find(",")+1
+		If Not p Return
+		Local q=s.Find(",",p)+1
+		If Not q Return
+		red=Int(s[..p-1])
+		green=Int(s[p..q-1])
+		blue=Int(s[q..])
+	End Method
+
+	Method Request()
+		If RequestColor(red,green,blue)
+			red=RequestedRed()
+			green=RequestedGreen()
+			blue=RequestedBlue()
+			Return True
+		EndIf				
+	End Method	
+End Type
+
+Type TTextStyle
+
+	Field	label:TGadget,panel:TGadget,combo:TGadget
+	Field	underline:TGadget, Color:TColor
+	Field	flags
+	
+	Method Set(rgb,bolditalic)
+		Color.set(rgb)
+		flags=bolditalic
+	End Method
+
+	Method Format(textarea:TGadget,pos,length,emphasise:Int = False)
+		Local tmpFlags:Int = flags
+		If emphasise Then tmpFlags:|TEXTFORMAT_BOLD
+		FormatTextAreaText textarea,Color.red,Color.green,Color.blue,tmpFlags,pos,length
+	End Method
+
+	Method ToString$()
+		Return ""+Color.red+","+Color.green+","+Color.blue+","+flags
+	End Method
+
+	Method FromString(s$)
+		Local	p,q,r
+		p=s.Find(",")+1;If Not p Return
+		q=s.Find(",",p)+1;If Not q Return
+		r=s.Find(",",q)+1;If Not r Return
+		Color.red=Int(s[..p-1])
+		Color.green=Int(s[p..q-1])
+		Color.blue=Int(s[q..r-1])
+		flags=Int(s[r..])
+	End Method
+
+	Method Poll()
+		Select EventSource()
+			Case panel
+				If EventID()=EVENT_MOUSEDOWN
+					Return Color.Request()
+				EndIf
+			Case combo
+				flags=(flags&~3)|SelectedGadgetItem(combo)
+				Return True
+			Case underline
+				If EventData() Then flags:|TEXTFORMAT_UNDERLINE Else flags:&~TEXTFORMAT_UNDERLINE
+				Return True
+		End Select
+	End Method
+	
+	Method Refresh()
+		SetPanelColor panel,Color.red,Color.green,Color.blue
+		SelectGadgetItem combo,flags&3
+		SetButtonState(underline,(flags&TEXTFORMAT_UNDERLINE <> 0))
+	End Method
+
+	Function Create:TTextStyle(name$,xpos,ypos,window:TGadget)
+		Local	s:TTextStyle
+		s=New TTextStyle
+		s.Color=New TColor
+		s.label=CreateLabel(name,xpos,ypos+4,90,24,window)
+		s.panel=CreatePanel(xpos+94,ypos,24,24,window,PANEL_BORDER|PANEL_ACTIVE)
+		SetPanelColor s.panel,255,255,0
+		s.combo=CreateComboBox(xpos+122,ypos,96,24,window)
+		s.underline=CreateButton("Underline",xpos+226,ypos,ClientWidth(window)-(xpos+220),24,window,BUTTON_CHECKBOX)
+		AddGadgetItem s.combo,"Normal"
+		AddGadgetItem s.combo,"Bold"
+		AddGadgetItem s.combo,"Italic"
+		AddGadgetItem s.combo,"Bold + Italic"
+		Return s
+	End Function
+End Type
+
+Function SetContainerColor(gadget:TGadget,c:TColor,level)
+	Local p:TGadget
+	
+	If level=1 p=gadget.parent.parent.parent
+	If level=2 p=gadget.parent.parent
+	If level=3 p=gadget.parent
+
+	If c
+		SetGadgetColor p,c.red,c.green,c.blue,True
+	Else
+		RemoveGadgetColor p
+	EndIf
+
+End Function
+
+Type TGadgetStyle
+	
+	Global fntLibrary:TGUIFont[] =	[TGuiFont(Null), LookupGuiFont(GUIFONT_SYSTEM), LookupGuiFont(GUIFONT_MONOSPACED), ..
+							LookupGuiFont(GUIFONT_SANSSERIF), LookupGuiFont(GUIFONT_SERIF), ..
+							LookupGuiFont(GUIFONT_SCRIPT) ]
+
+	Field label:TGadget,fpanel:TGadget,bpanel:TGadget,fcombo:TGadget,fbutton:TGadget
+	Field font_name$
+	Field font_size:Double
+	Field fg:TColor
+	Field bg:TColor
+	Field font_type = GUIFONT_SYSTEM, font:TGUIFont = fntLibrary[font_type]
+
+	Method Apply(gadget:TGadget,container=0,colorcontainer=False)
+		SetGadgetFont gadget,font
+		SetGadgetColor gadget,bg.red,bg.green,bg.blue,True
+		SetGadgetColor gadget,fg.red,fg.green,fg.blue,False
+		If container
+			If colorcontainer		
+				SetContainerColor gadget,bg,container
+			Else
+				SetContainerColor gadget,Null,container
+			EndIf			
+		EndIf
+	End Method
+	
+	Method Set(fg_rgb,bg_rgb,ftype,fname$="",fsize=0)
+		fg.set(fg_rgb)
+		bg.set(bg_rgb)
+		If Not fntLibrary[ftype] Then
+			font_name=fname
+			font_size=fsize
+		Else
+			font_name=FontName(fntLibrary[ftype])
+			font_size=FontSize(fntLibrary[ftype])
+		EndIf
+		font_type=ftype
+	End Method
+
+	Method ToString$()
+		Return font_name+","+font_size+","+fg.ToString()+","+bg.ToString()+","+font_type
+	End Method
+	
+	Function GetArg$(a$ Var)
+		Local p = a.Find(",")
+		If p=-1 Then p=a.length
+		Local r$ = a$[..p]
+		a$=a$[p+1..]
+		Return r$
+	End Function
+	
+	Method FromString(s$)		
+		font_name=GetArg(s$)
+		font_size=Double(GetArg(s$))
+		fg.red=Int(GetArg(s$))
+		fg.green=Int(GetArg(s$))
+		fg.blue=Int(GetArg(s$))
+		bg.red=Int(GetArg(s$))
+		bg.green=Int(GetArg(s$))
+		bg.blue=Int(GetArg(s$))
+		font_type=Int(GetArg(s$))
+		If fntLibrary[font_type] Then
+			font_name=FontName(fntLibrary[font_type])
+			font_size=FontSize(fntLibrary[font_type])
+		EndIf
+	End Method
+
+	Method Poll()
+		Local	f:TGUIFont
+		Select EventSource()
+			Case fpanel
+				If EventID()=EVENT_MOUSEDOWN
+					Return fg.Request()
+				EndIf
+			Case bpanel
+				If EventID()=EVENT_MOUSEDOWN
+					Return bg.Request()
+				EndIf
+			Case fcombo, fbutton
+				If EventSource() = fcombo Then
+					If Not (EventData() < 0) Then
+						font_type = EventData()
+						f = fntLibrary[font_type]
+					EndIf
+				Else
+					font_type = 0
+					SelectGadgetItem fcombo, font_type
+				EndIf
+				If Not f Then f=RequestFont(font)
+				If f
+					font_name=FontName(f)
+					font_size=FontSize(f)
+					Return True
+				EndIf				
+		End Select
+	End Method
+	
+	Method Refresh()
+		font=fntLibrary[font_type]
+		If Not font Then font=LoadGuiFont(font_name,font_size)
+		SetPanelColor fpanel,fg.red,fg.green,fg.blue
+		SetPanelColor bpanel,bg.red,bg.green,bg.blue
+		SelectGadgetItem fcombo, font_type
+		Local tmpFloatText$[] = String(font_size).Split(".")
+		If tmpFloatText.length > 1 Then tmpFloatText[1] = tmpFloatText[1][..Min(2,tmpFloatText[1].length)]
+		SetGadgetText fbutton,font_name+" : "+".".Join(tmpFloatText)+"pt"
+	End Method
+
+	Function Create:TGadgetStyle(name$,xpos,ypos,window:TGadget)
+		Local	s:TGadgetStyle
+		s=New TGadgetStyle
+		s.fg=New TColor
+		s.bg=New TColor
+		s.label=CreateLabel(name,xpos,ypos+LABELOFFSET,66,50,window)
+		s.fpanel=CreatePanel(xpos+68,ypos,24,24,window,PANEL_BORDER|PANEL_ACTIVE)
+		s.bpanel=CreatePanel(xpos+96,ypos,24,24,window,PANEL_BORDER|PANEL_ACTIVE)
+		s.fbutton=CreateButton("..",xpos+122,ypos+30,ClientWidth(window)-(xpos+128),24,window)
+		s.fcombo=CreateComboBox(xpos+122,ypos,ClientWidth(window)-(xpos+128),24,window)
+		AddGadgetItem s.fcombo, "User Defined Font", GADGETITEM_DEFAULT
+		AddGadgetItem s.fcombo, "GUI Default Font"
+		AddGadgetItem s.fcombo, "Monospaced Font"
+		AddGadgetItem s.fcombo, "Sans Serif Font"
+		AddGadgetItem s.fcombo, "Serif Font"
+		AddGadgetItem s.fcombo, "Script Font"
+		Return s
+	End Function
+End Type
+
+Const NORMAL=0
+Const COMMENT=1
+Const QUOTED=2
+Const KEYWORD=3
+Const NUMBER=4
+Const MATCHING=5
+
+Type TOptionsRequester Extends TPanelRequester
+' panels
+	Field configpanel:TGadget
+	Field optionspanel:TGadget
+	Field editorpanel:TGadget
+	Field toolpanel:TGadget
+' settings
+	Field showtoolbar,restoreopenfiles,autocapitalize,syntaxhighlight,autobackup,autoindent,hideoutput
+	Field bracketmatching, externalhelp,systemkeys,sortcode,archivecode,runserver,colorcontainers,offlinedocs
+	Field tabsize
+	Field editfontname$,editfontsize
+	Field editcolor1:TColor
+	Field editcolor2:TColor
+	Field outputfontname$,outputfontsize,outputcolor:TColor
+' exter tools	
+	Field activetarget$
+	Field activetemplate$
+' states
+	Field editfont:TGUIFont
+' gadgets
+	Field bmxfolder:TGadget[2]
+	Field monkeyfolder:TGadget[2]
+
+	Field tabbutton:TGadget
+	Field editpanel1:TGadget
+	Field editpanel2:TGadget
+	Field editbutton:TGadget
+	Field buttons:TGadget[16]
+	Field styles:TTextStyle[]
+	Field textarea:TGadget
+	Field outputstyle:TGadgetStyle
+	Field navstyle:TGadgetStyle
+	Field dirty
+	Field undo:TBank
+
+	Method Show()
+		RefreshGadgets()
+		Super.Show()
+	EndMethod
+	
+	Method Snapshot()
+		If Not undo undo=CreateBank(8192)
+		Local stream:TStream=CreateBankStream(undo)
+		Write stream
+		stream.close
+	End Method
+	
+	Method Restore()
+		If Not undo Return
+		Local stream:TStream=CreateBankStream(undo)
+		Read stream
+		stream.close
+	End Method
+
+	Method SetDefaults()
+		
+		archivecode=True
+		bracketmatching=True
+		showtoolbar=True
+		colorcontainers=False
+		offlinedocs=False
+		
+		restoreopenfiles=True
+		autocapitalize=True 
+		syntaxhighlight=True
+		autobackup=False
+		
+		autoindent=True
+		tabsize=4
+		activetarget="html5"
+		activetemplate="monkey app"
+
+		'marks!
+		?Win32
+		editfontname$="Courier New"
+		editfontsize=12
+		
+		?Macos
+		editfontname$="Monaco"
+		editfontsize=12
+		?
+		
+		editcolor1.set( $f0f8ff )		'non-monkey
+		editcolor2.set( $ffffff )		'monkey
+		styles[NORMAL].set( $000000,0 )
+		styles[COMMENT].set( $ff0000,0 )
+		styles[QUOTED].set( $ff00ff,0 )
+		styles[KEYWORD].set( $0000ff,0 )
+		styles[NUMBER].set( $000000,0 )
+		styles[MATCHING].set( $000000,0 )
+		
+		Rem
+		editfontname$=FontName(TGadgetStyle.fntLibrary[GUIFONT_MONOSPACED])
+		editfontsize=FontSize(TGadgetStyle.fntLibrary[GUIFONT_MONOSPACED])
+		editcolor1.set( $334455 )
+		editcolor2.set( $404040 )
+		styles[NORMAL].set( $ffffff,0 )
+		styles[COMMENT].set( $bbeeff,0 )
+		styles[QUOTED].set( $00ff66,0 )
+		styles[KEYWORD].set( $ffff00,0 )
+		styles[NUMBER].set( $40ffff,0 )
+		styles[MATCHING].set( $99aadd,0 )
+		EndRem
+		
+		outputstyle.set(0,-1,GUIFONT_MONOSPACED)
+		navstyle.set(0,-1,GUIFONT_SYSTEM)
+		RefreshGadgets
+	End Method
+
+	Method Write(stream:TStream)
+		stream.WriteLine "[Options]"
+		stream.WriteLine "showtoolbar="+showtoolbar
+		stream.WriteLine "restoreopenfiles="+restoreopenfiles
+		stream.WriteLine "autoformat="+autocapitalize
+		stream.WriteLine "syntaxhighlight="+syntaxhighlight
+		stream.WriteLine "bracketmatching="+bracketmatching
+		stream.WriteLine "autobackup="+autobackup
+		stream.WriteLine "autoindent="+autoindent
+		stream.WriteLine "tabsize="+tabsize
+		stream.WriteLine "activetarget="+activetarget
+		stream.WriteLine "activetemplate="+activetemplate
+		stream.WriteLine "editfontname="+editfontname
+		stream.WriteLine "editfontsize="+editfontsize
+		stream.WriteLine "editcolor="+editcolor1.ToString()
+		stream.WriteLine "editcolor2="+editcolor2.ToString()
+		stream.WriteLine "normal_style="+styles[NORMAL].ToString()
+		stream.WriteLine "comment_style="+styles[COMMENT].ToString()
+		stream.WriteLine "quote_style="+styles[QUOTED].ToString()
+		stream.WriteLine "keyword_style="+styles[KEYWORD].ToString()
+		stream.WriteLine "number_style="+styles[NUMBER].ToString()
+		stream.WriteLine "matched_style="+styles[MATCHING].ToString()
+		stream.WriteLine "console_style="+outputstyle.ToString()	'Renamed from 'output_style' to bump users to default monospace font.
+		stream.WriteLine "navi_style="+navstyle.ToString()	'Renamed from 'nav_style' to bump users to default treeview font.
+		stream.WriteLine "hide_output="+hideoutput
+		stream.WriteLine "external_help="+externalhelp
+		stream.WriteLine "system_keys="+systemkeys
+		stream.WriteLine "sort_code="+sortcode
+		stream.WriteLine "archive_code="+archivecode
+		stream.WriteLine "run_server="+runserver
+		stream.WriteLine "color_containers="+colorcontainers
+		stream.WriteLine "offline_docs="+offlinedocs
+	End Method
+
+	Method Read(stream:TStream)
+		Local	f$,p,a$,b$,t
+		While Not stream.Eof()
+			f$=stream.ReadLine()
+			If f$="" Or (f$[..1]="[" And f$<>"[Options]") Exit
+			p=f.find("=")
+			a$=f[..p]
+			b$=f[p+1..]
+			t=Int(b)
+			Select a$
+				Case "showtoolbar" showtoolbar=t
+				Case "restoreopenfiles" restoreopenfiles=t
+				Case "autoformat" autocapitalize=t
+				Case "syntaxhighlight" syntaxhighlight=t
+				Case "bracketmatching" bracketmatching=t
+				Case "autobackup" autobackup=t
+				Case "autoindent" autoindent=t
+				Case "tabsize" tabsize=t		
+				Case "activetarget" activetarget=b
+				Case "activetemplate" activetemplate=b
+				Case "editfontname" editfontname=b
+				Case "editfontsize" editfontsize=t
+				Case "editcolor" editcolor1.FromString(b)		
+				Case "editcolor2" editcolor2.FromString(b)		
+				Case "normal_style" styles[NORMAL].FromString(b)
+				Case "comment_style" styles[COMMENT].FromString(b)
+				Case "quote_style" styles[QUOTED].FromString(b)
+				Case "keyword_style" styles[KEYWORD].FromString(b)
+				Case "number_style" styles[NUMBER].FromString(b)
+				Case "matched_style" styles[MATCHING].FromString(b)
+				Case "console_style" outputstyle.FromString(b)	'Renamed from 'output_style' to bump users to default monospace font.
+				Case "navi_style" navstyle.FromString(b)	'Renamed from 'nav_style' to bump users to default treeview font.
+				Case "hide_output" hideoutput=t
+				Case "external_help" externalhelp=t
+				Case "system_keys" systemkeys=t
+				Case "sort_code" sortcode=t
+				Case "archive_code" archivecode=t
+				Case "run_server" runserver=t
+				Case "color_containers" colorcontainers=t
+				Case "offline_docs" offlinedocs=t
+			End Select
+		Wend		
+		RefreshGadgets
+	End Method
+	
+	Method RefreshGadgets()
+		Local rgb:TColor,flags
+		editfont=LoadGuiFont(editfontname,editfontsize)
+
+		SetGadgetText(bmxfolder[0], host.bmxpath)
+		SetGadgetText(monkeyfolder[0], host.monkeypath)
+				
+		SetButtonState buttons[0],showtoolbar
+		SetButtonState buttons[1],restoreopenfiles
+		SetButtonState buttons[2],autocapitalize
+		SetButtonState buttons[3],syntaxhighlight
+		SetButtonState buttons[4],bracketmatching
+		SetButtonState buttons[5],autobackup
+		SetButtonState buttons[6],autoindent
+		SetButtonState buttons[7],hideoutput
+		SetButtonState buttons[8],externalhelp
+		SetButtonState buttons[9],systemkeys
+		SetButtonState buttons[10],sortcode
+		SetButtonState buttons[11],archivecode
+		SetButtonState buttons[12],runserver
+		SetButtonState buttons[13],colorcontainers
+		SetButtonState buttons[14],offlinedocs
+		
+		SelectGadgetItem tabbutton,Min(Max(tabsize/2-1,0),7)
+		SetPanelColor editpanel1,editcolor1.red,editcolor1.green,editcolor1.blue
+		SetPanelColor editpanel2,editcolor2.red,editcolor2.green,editcolor2.blue
+		SetGadgetText editbutton,editfontname+" : "+editfontsize + "pt"
+		For Local i:Int = 0 Until styles.length
+			styles[i].Refresh
+		Next
+		LockTextArea textarea
+		SetTextAreaColor textarea,editcolor2.red,editcolor2.green,editcolor2.blue,True
+		SetGadgetFont textarea,editfont
+		styles[NORMAL].format(textarea,0,TEXTAREA_ALL)
+		styles[COMMENT].format(textarea,0,12)
+		styles[MATCHING].format(textarea,24,1)
+		styles[NUMBER].format(textarea,25,3)
+		styles[NUMBER].format(textarea,31,1)
+		styles[MATCHING].format(textarea,32,1)
+		styles[NUMBER].format(textarea,36,1)
+		styles[KEYWORD].format(textarea,39,5)
+		styles[QUOTED].format(textarea,46,10)
+		UnlockTextArea textarea
+		outputstyle.Refresh
+		navstyle.Refresh
+		dirty=True
+	End Method
+
+	Method Poll()
+		Local font:TGUIFont
+		Local refresh
+		Local processed = 1
+		Local path$
+		For Local i:Int = 0 Until styles.length
+			refresh:|styles[i].Poll()
+		Next
+		refresh:|outputstyle.Poll()
+		refresh:|navstyle.Poll()
+		Select EventID()
+			Case EVENT_GADGETACTION, EVENT_WINDOWCLOSE
+				Select EventSource()
+				
+					Case bmxfolder[1]
+						path=RequestDir("Locate BlitzMax Installation")
+						If path And FileType(path)=FILETYPE_DIR
+							host.bmxpath=path
+							SetGadgetText bmxfolder[0],path
+							host.InitBMXPaths
+						EndIf
+					
+					Case monkeyfolder[1]
+						path=RequestDir("Locate Monkey Installation")
+						If path And FileType(path)=FILETYPE_DIR
+							host.monkeypath=path
+							SetGadgetText monkeyfolder[0],path
+							host.InitMonkeyPaths
+						EndIf				
+				
+					Case buttons[0];showtoolbar=ButtonState(buttons[0]);dirty=1
+					Case buttons[1];restoreopenfiles=ButtonState(buttons[1])
+					Case buttons[2];autocapitalize=ButtonState(buttons[2]);dirty=1
+					Case buttons[3];syntaxhighlight=ButtonState(buttons[3]);dirty=1
+					Case buttons[4];bracketmatching=ButtonState(buttons[4])
+					Case buttons[5];autobackup=ButtonState(buttons[5])
+					Case buttons[6];autoindent=ButtonState(buttons[6])
+					Case buttons[7];hideoutput=ButtonState(buttons[7])
+					Case buttons[8];externalhelp=ButtonState(buttons[8])
+					Case buttons[9];systemkeys=ButtonState(buttons[9]);dirty=2
+					Case buttons[10];sortcode=ButtonState(buttons[10]);dirty=3
+					Case buttons[11];archivecode=ButtonState(buttons[11]);dirty=3
+					Case buttons[12];runserver=ButtonState(buttons[12]);dirty=3
+					Case buttons[13];colorcontainers=ButtonState(buttons[13]);dirty=1
+					Case buttons[14];offlinedocs=ButtonState(buttons[14])
+					Case tabber;SetPanelIndex SelectedGadgetItem(tabber)
+					Case ok
+						Hide()
+						Select dirty
+							Case 1
+								host.RefreshAll
+							Case 2
+								host.Restart
+							Case 3
+								host.Rethink
+						End Select
+						dirty=False
+						SnapShot()
+					Case window
+						If EventID()=EVENT_WINDOWCLOSE
+							Restore()
+							dirty=False
+							Hide()
+						EndIf
+					Case cancel
+						Restore()
+						dirty=False
+						Hide()
+					Case tabbutton
+						tabsize=(SelectedGadgetItem(tabbutton)+1)*2
+						refresh=True
+					Case editpanel1
+						If EventID()=EVENT_MOUSEDOWN
+							refresh=editcolor1.Request()
+						EndIf
+					Case editpanel2
+						If EventID()=EVENT_MOUSEDOWN
+							refresh=editcolor2.Request()
+						EndIf
+					Case editbutton
+						font=RequestFont(editfont)
+						If font
+							editfontname=FontName(font)
+							editfontsize=FontSize(font)
+							refresh=True
+						EndIf
+					Default
+						processed = 0
+				EndSelect
+			Case EVENT_MOUSEDOWN
+				Select EventSource()
+					Case editpanel1
+						If EventID()=EVENT_MOUSEDOWN
+							editcolor1.Request()
+							refresh=True
+						EndIf
+					Case editpanel2
+						If EventID()=EVENT_MOUSEDOWN
+							editcolor2.Request()
+							refresh=True
+						EndIf
+					Default
+						processed = 0
+				EndSelect
+		EndSelect
+		If refresh Then RefreshGadgets()
+		Return processed
+	End Method
+	
+	Method InitOptionsRequester(host:TCodePlay)		
+		Local w:TGadget
+		Local cw
+		InitPanelRequester(host,"Options",380,430)
+' init values for text background
+		editcolor1=New TColor
+		editcolor2=New TColor
+' init gadgets
+		configpanel=AddPanel("Tools")
+		optionspanel=AddPanel("Options")
+		editorpanel=AddPanel("Editor")
+		toolpanel=AddPanel("Tools")
+		
+		w=configpanel		
+		cw=ClientWidth(w)
+		Local cy
+		
+		cy=6		
+		CreateLabel("BlitzMax Path",6,cy,90,24,w)
+		bmxfolder[0]=CreateComboBox(6,cy+32,cw-70,26,w,COMBOBOX_EDITABLE)
+		bmxfolder[1]=CreateButton("..",cw-50,CY+30,34,26,w)
+
+		cy:+80
+		CreateLabel("Monkey Path",6,cy,90,24,w)
+		monkeyfolder[0]=CreateComboBox(6,cy+32,cw-70,26,w,COMBOBOX_EDITABLE)
+		monkeyfolder[1]=CreateButton("..",cw-50,cy+30,34,26,w)	
+
+		w=optionspanel		
+		cw=ClientWidth(w)
+		buttons[0]=CreateButton("Show Toolbar",6,6,cw-12,26,w,BUTTON_CHECKBOX)
+		buttons[1]=CreateButton("Open Files at Startup",6,34,cw-12,26,w,BUTTON_CHECKBOX)
+		buttons[2]=CreateButton("Auto Capitalize",6,60,cw-12,26,w,BUTTON_CHECKBOX)
+		buttons[3]=CreateButton("Syntax Highlighting",6,86,cw-12,26,w,BUTTON_CHECKBOX)
+		buttons[4]=CreateButton("Enable .bmx Bracket Matching",6,112,cw-12,26,w,BUTTON_CHECKBOX)
+		buttons[5]=CreateButton("Auto Backup"+" to .bak",6,138,cw-12,26,w,BUTTON_CHECKBOX)
+		buttons[6]=CreateButton("Auto Indent",6,164,cw-12,26,w,BUTTON_CHECKBOX)
+		buttons[7]=CreateButton("Hide Output When Process Completes",6,190,cw-12,26,w,BUTTON_CHECKBOX)
+		buttons[8]=CreateButton("Use External Help Browser",6,216,cw-12,26,w,BUTTON_CHECKBOX)
+		buttons[9]=CreateButton("Use OS Specific Shortcut Keys",6,242,cw-12,26,w,BUTTON_CHECKBOX)
+		buttons[10]=CreateButton("Sort Nodes in Code View",6,268,cw-12,26,w,BUTTON_CHECKBOX)
+		buttons[11]=CreateButton("Archive Code",6,292,cw-12,26,w,BUTTON_CHECKBOX)
+		buttons[12]=CreateButton("Internal HTTP Server on localhost:8080",6,316,cw-12,26,w,BUTTON_CHECKBOX)
+		buttons[13]=CreateButton("Color Containers",6,340,cw-12,26,w,BUTTON_CHECKBOX)
+		buttons[14]=CreateButton("Offline Docs",6,364,cw-12,26,w,BUTTON_CHECKBOX)
+
+		w=editorpanel
+		cw=ClientWidth(w)
+		CreateLabel("Background",6,6+4,90,24,w)
+		editpanel1=CreatePanel(100,6,24,24,w,PANEL_BORDER|PANEL_ACTIVE)
+		editpanel2=CreatePanel(100,32,24,24,w,PANEL_BORDER|PANEL_ACTIVE)
+		editbutton=CreateButton("..",128,6,cw-134,24,w)
+		
+		tabbutton=CreateComboBox(128,36,cw-134,24,w)
+		For Local i=1 To 8
+			AddGadgetItem tabbutton,"Tab Size:"+(i*2)
+		Next
+		
+		styles=New TTextStyle[6]
+		styles[NORMAL]=TTextStyle.Create("Plain Text",6,66,w)
+		styles[COMMENT]=TTextStyle.Create("Remarks",6,96,w)
+		styles[QUOTED]=TTextStyle.Create("Strings",6,126,w)
+		styles[KEYWORD]=TTextStyle.Create("Keywords",6,156,w)
+		styles[NUMBER]=TTextStyle.Create("Numbers",6,186,w)
+		styles[MATCHING]=TTextStyle.Create("Matchings",6,216,w)
+		
+		textarea=CreateTextArea(6,250,cw-12,ClientHeight(w)-256,w,TEXTAREA_READONLY)
+		SetGadgetText textarea,"'Sample Code~n~nresult = ((2.0 * 4) + 1)~nPrint( ~qResult: ~q + result )~n"
+		
+		w=toolpanel
+		cw=ClientWidth(w)
+		outputstyle=TGadgetStyle.Create("Output: ",6,6,w)
+		navstyle=TGadgetStyle.Create("Navbar: ",6,66,w)
+
+		SetDefaults()
+		SetPanel configpanel
+		
+		SnapShot
+	End Method
+	
+	Function Create:TOptionsRequester(host:TCodePlay)
+		Local	o:TOptionsRequester
+		o=New TOptionsRequester
+		o.InitOptionsRequester host
+		Return o
+	End Function
+	
+End Type
+
+
+Type TFindRequester Extends TRequester
+
+	Field	combo:TGadget
+
+	Function Create:TFindRequester(host:TCodePlay)
+
+		Local	seek:TFindRequester
+
+		seek=New TFindRequester
+		seek.initrequester(host,"Find",280,66,STYLE_OK|STYLE_CANCEL|STYLE_DIVIDER|STYLE_MODAL,"Find")
+
+		CreateLabel("Find",6,12,82,24,seek.window)		
+		seek.combo=CreateComboBox(88,8,ClientWidth(seek.window)-(88+6),26,seek.window,COMBOBOX_EDITABLE)
+
+'		seek.findterm=CreateTextField(88,8,ClientWidth(seek.window)-(88+6),21,seek.window)
+		Return seek
+	End Function
+	
+	Method ShowFind(term$="")
+		Local previous$=GadgetText(combo)				
+		If previous			
+			For Local item=0 Until CountGadgetItems(combo)
+				If previous=GadgetItemText(combo,item)
+					RemoveGadgetItem combo,item
+					Exit 
+				EndIf
+			Next					
+			InsertGadgetItem combo,0,previous
+		EndIf		
+		SetGadgetText(combo,term)
+		Super.Show()
+		ActivateGadget combo
+	End Method
+
+	Method Poll()
+		Local	find$,data		
+		Select EventSource()
+			Case window
+				If EventID()=EVENT_WINDOWCLOSE
+					Hide()
+				EndIf
+			Case ok
+				If EventID() = EVENT_GADGETACTION
+					find=GadgetText(combo)
+					If find
+						Hide()
+						host.activepanel.Invoke TOOLFINDNEXT,find
+					Else
+						Notify "You must enter a search string to find!", True
+						ActivateGadget combo
+					EndIf
+				EndIf
+			Case cancel
+				If EventID() = EVENT_GADGETACTION Then Hide()
+			Default
+				Return 0
+		End Select
+		Return 1
+	End Method
+
+End Type
+
+Type TFindRequesterOLD Extends TRequester
+	Field	findterm:TGadget
+	
+	Method ShowFind(term$="")
+		If term SetGadgetText(findterm,term)
+		Super.Show()
+		ActivateGadget findterm
+	End Method
+
+	Method Poll()
+		Local	find$,data		
+		Select EventSource()
+			Case window
+				If EventID()=EVENT_WINDOWCLOSE
+					Hide()
+				EndIf
+			Case ok
+				If EventID() = EVENT_GADGETACTION
+					If TextFieldText(findterm)
+						find=TextFieldText(findterm)
+						Hide()
+						host.activepanel.Invoke TOOLFINDNEXT,find
+					Else
+						Notify "You must enter a search string to find!", True
+						ActivateGadget findterm
+					EndIf
+				EndIf
+			Case cancel				
+				'If EventID() = EVENT_GADGETACTION Then 
+				Hide()
+			Default
+				Return 0
+		End Select
+		Return 1
+	End Method
+
+	Function Create:TFindRequester(host:TCodePlay)
+		Local	seek:TFindRequester
+		seek=New TFindRequester
+		seek.initrequester(host,"Find",280,66,STYLE_OK|STYLE_CANCEL|STYLE_DIVIDER|STYLE_MODAL,"Find")
+		CreateLabel("Find",6,12,82,24,seek.window)
+
+'		seek.findterm=CreateTextField(88,8,ClientWidth(seek.window)-(88+6),21,seek.window)
+		seek.combo=CreateComboBox(88,8,ClientWidth(seek.window)-(88+6),21,seek.window)
+
+		Return seek
+	End Function
+End Type
+
+Type TNewRequester Extends TRequester
+	Field	target:TGadget
+	Field fullpath$
+	
+	Method Poll()
+		Local	find$,data		
+		Select EventSource()
+			Case window
+				If EventID()=EVENT_WINDOWCLOSE
+					Hide()
+				EndIf
+			Case ok
+				If EventID() = EVENT_GADGETACTION
+					Hide
+					'NewFile
+				EndIf
+			Case cancel
+				If EventID() = EVENT_GADGETACTION Then Hide()
+			Default
+				Return 0
+		End Select
+		Return 1
+	End Method
+	
+	Function ReadNewTemplates(monkeypath$,target:TGadget,activetemplate$)
+		Local t$[]		
+		Local flags
+		t=LoadDir(monkeypath+"/templates")
+		For Local i$=EachIn t
+			flags=0
+			If i=activetemplate flags=GADGETITEM_DEFAULT
+			AddGadgetItem target," "+i.ToUpper(),flags,-1,"",i
+		Next
+	End Function
+
+	Function Create:TNewRequester(host:TCodePlay)
+		Local	seek:TNewRequester
+		seek=New TNewRequester
+		seek.initrequester(host,"New File",280,66,STYLE_OK|STYLE_CANCEL|STYLE_DIVIDER|STYLE_MODAL,"Create")
+		CreateLabel("Template:",4,14,82,28,seek.window)		
+		seek.target=CreateComboBox(92,10,ClientWidth(seek.window)-(92+6),28,seek.window)
+		ReadNewTemplates(host.monkeypath,seek.target,host.options.activetemplate)		
+		Return seek
+	End Function
+End Type
+
+
+Type TMonkeyRequester Extends TRequester
+	Field target:TGadget
+	Field fullpath$
+	Field runmonkey
+	Field debugmonkey
+		
+	Method ShowMonkey(path$,run,debug)
+		fullpath=host.FullPath(path)
+		runmonkey=run
+		debugmonkey=debug
+		Show()
+		ActivateGadget target		
+	End Method
+	
+	Method Build()
+		Local cmd$
+		Local xtra$
+		cmd$=quote(host.transpath)		
+		If Not debugmonkey cmd$:+" -config=release"
+		xtra$=String(GadgetItemExtra(target,SelectedGadgetItem(target)))
+		cmd$:+" -target="+xtra
+		host.options.activetarget=xtra
+		If runmonkey
+			cmd$:+" -run"
+		EndIf
+		cmd$:+" "+quote(fullpath)
+		host.execute cmd,"Translating "+StripExt(StripDir(fullpath))+"~n"+cmd+"~n"
+	End Method
+	
+	Method Poll()
+		Local	find$,data		
+		Select EventSource()
+			Case window
+				If EventID()=EVENT_WINDOWCLOSE
+					Hide()
+				EndIf
+			Case ok
+				If EventID() = EVENT_GADGETACTION
+					Hide
+					Build
+				EndIf
+			Case cancel
+				If EventID() = EVENT_GADGETACTION Then Hide()
+			Default
+				Return 0
+		End Select
+		Return 1
+	End Method
+	
+	Function ReadMonkeyTargets( monkeypath$,target:TGadget,activetarget$ )
+		Local cd$=CurrentDir()
+		ChangeDir monkeypath+"/bin"
+
+		Local cmd$
+?win32
+		cmd="transcc_winnt"
+?macos
+		cmd="./transcc_macos"
+?
+		Local process:TProcess=CreateProcess( cmd$,HIDECONSOLE )
+		If Not process
+			'ERROR! can't run trans?
+			Return
+		EndIf
+		
+		Local output$
+		Repeat
+			Delay 10
+			Local bytes:Byte[]=process.pipe.ReadPipe()
+			If bytes
+				output:+String.FromBytes( bytes,bytes.length )
+			EndIf
+		Until Not process.Status()
+		
+		ChangeDir cd
+		
+		For Local t$=EachIn output.Split( "~n" )
+			t=t.Trim()
+			If Not t.StartsWith( "Valid targets: " ) Continue
+			Local bits$[]=t.Split( " " )
+			For Local i=2 Until bits.length
+				Local flags
+				If bits[i]=activetarget flags=GADGETITEM_DEFAULT
+				AddGadgetItem target," "+bits[i].ToUpper(),flags,-1,"",bits[i]
+			Next
+			Return
+		Next
+
+	End Function
+
+	Function Create:TMonkeyRequester(host:TCodePlay)
+		Local	seek:TMonkeyRequester
+		seek=New TMonkeyRequester
+		seek.initrequester(host,"Monkey Build",280,66,STYLE_OK|STYLE_CANCEL|STYLE_DIVIDER|STYLE_MODAL,"Build")
+		CreateLabel("Target:",4,14,82,28,seek.window)		
+		seek.target=CreateComboBox(92,10,ClientWidth(seek.window)-(92+6),28,seek.window)
+		ReadMonkeyTargets(host.monkeypath,seek.target,host.options.activetarget)		
+		Return seek
+	End Function
+End Type
+
+Type TReplaceRequester Extends TRequester
+	Field	findterm:TGadget,replaceterm:TGadget
+	Field	findnext:TGadget,replaceit:TGadget,replaceall:TGadget
+	
+	Method Show()
+		Super.Show()
+		ActivateGadget findterm
+	End Method
+
+	Method Poll()
+		Local	find$,Replace$
+		Select EventSource()
+			Case window
+				If EventID()=EVENT_WINDOWCLOSE
+					Hide()
+				EndIf
+			Case cancel
+				If EventID() = EVENT_GADGETACTION Then Hide
+			Case ok
+				If EventID() = EVENT_GADGETACTION Then
+					If TextFieldText(findterm) Then
+						find=TextFieldText(findterm)
+						host.activepanel.Invoke TOOLFINDNEXT,find
+					Else
+						Notify "You must enter a search string to find!", True
+						ActivateGadget findterm
+					EndIf
+				EndIf
+			Case replaceit
+				If EventID() = EVENT_GADGETACTION Then
+					Replace=TextFieldText(replaceterm)
+					If host.activepanel.Invoke(TOOLREPLACE,Replace)
+						host.activepanel.Invoke TOOLFINDNEXT,find
+					EndIf
+				EndIf
+			Case replaceall
+				If EventID() = EVENT_GADGETACTION Then
+					find=TextFieldText(findterm)
+					Replace=TextFieldText(replaceterm)
+					host.activepanel.Invoke TOOLREPLACE,find+Chr(0)+Replace
+				EndIf
+			Default
+				Return 0
+		End Select
+		Return 1
+	End Method
+
+	Function Create:TReplaceRequester(host:TCodePlay)
+		Local x,y
+		Local	seek:TReplaceRequester
+		seek=New TReplaceRequester
+		seek.initrequester(host,"Find and Replace",380,80,STYLE_OK|STYLE_CANCEL|STYLE_DIVIDER,"Find Next")
+		
+		y=11
+		CreateLabel( "Find",6,y+4,88,24,seek.window )
+		seek.findterm=CreateTextField( 96,y,168,21,seek.window )
+
+		y:+32		
+		CreateLabel( "Replace With",6,y+4,88,24,seek.window )
+		seek.replaceterm=CreateTextField( 96,y,168,21,seek.window )
+
+		x=ClientWidth(seek.window)-102
+		y=8
+		seek.replaceit=CreateButton("Replace",x,y,96,26,seek.window)
+		seek.replaceall=CreateButton("Replace All",x,y+32,96,26,seek.window)
+		
+		Return seek
+	End Function
+End Type
+
+Type TEventHandler Extends TTool
+	Method OnEvent() Abstract
+End Type
+
+Type TToolPanel Extends TEventHandler
+	Field	name$,path$
+	Field	panel:TGadget
+	Field	index
+	Field	active
+	
+	Method Show()
+	End Method
+End Type
+
+Type TView
+	Field	node:TGadget
+	Field	state
+End Type
+
+Type TNode Extends TTool
+	Const	HIDESTATE=0
+	Const	CLOSEDSTATE=1
+	Const	OPENSTATE=2
+
+	Field	name$,sortname$
+	Field	parent:TNode
+	Field	kids:TList=New TList
+	Field	views:TView[]
+' activate program	
+	Field	target:TTool
+	Field	action
+	Field	argument:Object
+
+	Method SortKids( ascending=True )
+		Local term:TLink=kids._head
+		Repeat
+			Local link:TLink=kids._head._succ
+			Local sorted=True
+			Repeat
+				Local succ:TLink=link._succ
+				If succ=term Exit
+				Local cc=TNode(link._value).sortname.Compare( TNode(succ._value).sortname )
+				If (cc>0 And ascending) Or (cc<0 And Not ascending)
+					Local link_pred:TLink=link._pred
+					Local succ_succ:TLink=succ._succ
+					link_pred._succ=succ
+					succ._succ=link
+					succ._pred=link_pred
+					link._succ=succ_succ
+					link._pred=succ
+					succ_succ._pred=link
+					sorted=False
+				Else
+					link=succ
+				EndIf
+			Forever
+			If sorted Return
+			term=link
+		Forever
+	End Method
+
+	Method FindArgument:TNode(arg:Object)
+		Local	n:TNode,r:TNode,a$
+		If arg.Compare(argument)=0 Return Self
+		a$=(String(arg)).ToLower()
+		If a And a=(String(argument)).toLower() Return Self
+		For n=EachIn kids
+			r=n.FindArgument(arg)
+			If r Return r
+		Next
+	End Method
+	
+	?Debug
+	Method Dump(indent$="")
+		Local	n:TNode		
+		Print indent+name
+		indent:+"~t"
+		For n=EachIn kids
+			n.Dump indent
+		Next
+	End Method		
+	?
+	
+	Method IsHidden()
+		Local	v:TView
+		If Not parent Return False
+		For v=EachIn parent.views
+			If v.state=OPENSTATE Return False
+		Next
+		Return True
+	End Method
+	
+	Method SetAction(tool:TTool,cmd,arg:Object=Null)
+		target=tool
+		action=cmd
+		argument=arg
+	End Method
+
+	Method Hide(v:TView=Null)	'null means hide in all views
+		For Local n:TNode = EachIn kids
+			n.hide v
+		Next
+		If v
+			If v.node FreeTreeViewNode v.node;v.node=Null
+		Else
+			For v=EachIn views
+				If v.node FreeTreeViewNode v.node;v.node=Null
+			Next
+		EndIf
+	End Method
+	
+	Method Detach()
+		Hide()
+		If parent parent.kids.remove Self;parent=Null
+	End Method
+	
+	Method FreeKids()
+		For Local n:TNode = EachIn kids
+			n.free
+		Next
+	End Method
+	
+	Method Free()
+		FreeKids()
+		Detach()
+		target=Null;argument=Null;views=Null
+	End Method
+	
+	Method Invoke(command,arg:Object=Null)
+		Select command
+		Case TOOLACTIVATE,TOOLMENU
+			If target Return target.Invoke(action,argument)
+		End Select
+	End Method
+	
+	Method Find:TNode(treeviewnode:TGadget,view=0)
+		Local	n:TNode,r:TNode
+		Local	v:TView
+		v=getview(view)
+		If v And v.node=treeviewnode Return Self
+		For n=EachIn kids
+			r=n.Find(treeviewnode,view)
+			If r Return r
+		Next
+	End Method
+	
+	Method SetNode(treeviewnode:TGadget,view=0)
+		Local	v:TView = getview(view)
+		v.node=treeviewnode
+		open view
+	End Method
+	
+	Method HighLight(view=-1)
+		Local	v:TView
+		If view=-1
+			For view=0 Until views.length
+				HighLight view
+			Next
+			Return
+		EndIf
+		v=GetView(view)
+		If v.node SelectTreeViewNode v.node
+	End Method
+	
+	Method Open(view=-1)
+		Local	v:TView
+		If view=-1
+			For view=0 Until views.length
+				Open view
+			Next
+			Return
+		EndIf
+		v=GetView(view)
+		If v.state<>OPENSTATE
+			v.state=OPENSTATE
+			RefreshView view
+'			If v.node ExpandTreeViewNode v.node
+		EndIf
+	End Method
+	
+	Method Close(view=0)
+		Local	v:TView = GetView(view)
+		If v.state<>CLOSEDSTATE
+			v.state=CLOSEDSTATE
+'			If v.node CollapseTreeViewNode v.node
+		EndIf
+	End Method
+	
+	Method GetState(view=0)
+		Return GetView(view).state
+	End Method
+
+	Method GetView:TView(view=0)
+		If view>=views.length
+			views=views[..view+1]
+		EndIf
+		If Not views[view] views[view] = New TView
+		Return views[view]
+	End Method
+	
+	Method GetIndex()
+		Local	node:TNode
+		Local	i		
+		If parent
+			For node=EachIn parent.kids
+				If node=Self Return i
+				i:+1
+			Next
+		EndIf
+	End Method
+	
+	Method Refresh()
+		For Local i:Int = 0 Until views.length
+			RefreshView i
+		Next
+	End Method
+	
+	Method RefreshView(view=0)
+		Local	n:TNode,quick,nodeToOpen:TGadget
+		Local	v:TView,vv:TView
+		Local	node
+		If parent And parent.getstate(view)=CLOSEDSTATE quick=True		
+		v=getview(view)
+		If v.node And parent
+			If GadgetText(v.node) <> name Then
+				ModifyTreeViewNode v.node,name
+			EndIf
+			If v.state=OPENSTATE nodeToOpen = v.node;quick = False
+		Else
+			If parent And name
+				vv=parent.getview(view)
+				If vv.node
+					v.node=InsertTreeViewNode(GetIndex(),name,vv.node)
+					If v.state=HIDESTATE v.state=CLOSEDSTATE					
+					If vv.state=OPENSTATE nodeToOpen = vv.node
+					quick=False
+				EndIf
+			EndIf
+		EndIf
+		If quick Return
+		If Not kids Return
+		For n=EachIn kids
+			n.RefreshView view
+		Next
+		If nodeToOpen Then ExpandTreeViewNode nodeToOpen
+	End Method
+
+	Method NodeAfter:TNode(node:TNode)
+		Local	link:TLink
+		If node	link=kids.FindLink(node)
+		If link link=link.NextLink()
+		If link Return TNode(link.Value())	
+	End Method
+
+	Method Sync(snap:TNode)
+		Local	snapkid:TNode
+		Local	currentkid:TNode
+		Local	kid:TNode
+		Local	t:TNode
+		Local	link:TLink
+
+		If snap.name<>name Return
+		If kids.Count() currentkid=TNode(kids.First())
+		For snapkid=EachIn snap.kids
+' if same name in list
+			kid=currentkid
+			While kid
+				If kid.name=snapkid.name Exit
+				kid=NodeAfter(kid)
+			Wend
+' then remove entries in front			
+			If kid
+				While currentkid<>kid
+					t=currentkid
+					currentkid=NodeAfter(currentkid)			
+					t.free()
+				Wend
+			EndIf
+' if same name sync else insert
+			If currentkid And currentkid.name=snapkid.name	'merge values if same name
+				currentkid.Sync snapkid
+				currentkid=NodeAfter(currentkid)
+			Else
+				snapkid.detach
+				If currentkid
+					link=kids.FindLink(currentkid)
+					kids.InsertBeforeLink snapkid,link
+				Else
+					kids.AddLast snapkid
+				EndIf
+				snapkid.parent=Self
+			EndIf
+		Next
+' remove any entries at end
+		While currentkid
+			t=currentkid
+			currentkid=NodeAfter(currentkid)			
+			t.free()
+		Wend
+		Refresh()
+	End Method
+
+	Method SetName(n$)
+		name=n
+	End Method
+		
+	Method AddNode:TNode(name$)
+		Local	v:TNode
+		v=New TNode
+		v.setname name
+		Append v
+		Return v
+	End Method
+	
+	Method Append(v:TNode)
+		v.parent=Self
+		kids.AddLast v
+	End Method	
+	
+	Method AddFirst(kid:TNode)
+		kid.Detach
+		kid.parent=Self
+		kids.AddFirst kid
+	End Method	
+
+	Method FindNode:TNode(withname$)
+		Local kid:TNode,node:TNode
+		If name=withname Return Self
+		For kid=EachIn kids
+			node=kid.FindNode(withname)
+			If node Return node
+		Next		
+	End Method
+
+	Function CreateNode:TNode(name$)
+		Local	node:TNode
+		node=New TNode
+		node.setname name
+		Return node
+	End Function
+	
+End Type
+
+Type TServerPanel Extends TToolPanel
+	Field host:TCodePlay
+	Field resetbutton:TGadget
+	Field htmlview:TGadget
+	Field portnumber
+
+	Method Invoke(command,argument:Object=Null)
+		Local	href$
+		If Not htmlview Return
+		Select command
+			Case TOOLCUT
+				GadgetCut htmlview
+			Case TOOLCOPY
+				GadgetCopy htmlview
+			Case TOOLPASTE
+				GadgetPaste htmlview
+			Case TOOLSHOW
+				ActivateGadget htmlview	
+				host.SetTitle
+				host.options.outputstyle.Apply htmlview,1,host.options.colorcontainers
+			Case TOOLNAVIGATE
+				href$=String(argument)
+				If href Go href
+			Case TOOLPRINT
+				GadgetPrint htmlview
+		End Select
+	End Method
+
+	Method OnEvent()
+		Local	url$,p,t$
+		If htmlview 
+'			PollServer
+			If EventSource()=htmlview
+				Select EventID()
+					Case EVENT_GADGETACTION				'NAVIGATEREQUEST
+						url$=String( EventExtra() )
+				End Select			
+			EndIf
+		EndIf
+	End Method
+		
+	Method Go(url$,internal=False)
+		Local	node:TNode
+'		DebugLog "Go!"
+		HtmlViewGo htmlview,url
+		host.SelectPanel Self
+		ActivateGadget htmlview			
+	End Method
+	
+	Method Home()
+		Go "http://localhost:8080/index.htm",True
+	End Method
+	
+	Method Forward()
+		HtmlViewForward htmlview
+	End Method
+
+	Method Back()
+		HtmlViewBack htmlview
+	End Method
+	
+	Method Open(port)	
+		If htmlview And portnumber=port
+			codeplay.SelectPanel Self
+			Return
+		EndIf		
+		portnumber=port
+'		RunServer port
+		codeplay.addpanel(Self)		
+		Local style=0 'HTMLVIEW_NONAVIGATE		'HTMLVIEW_NOCONTEXTMENU
+		htmlview=CreateHTMLView(0,0,ClientWidth(panel),ClientHeight(panel),panel,style)		
+		SetGadgetLayout htmlview,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED
+		Home
+		Hide()
+	End Method
+
+	Method Hide()
+		If htmlview
+			host.RemovePanel Self
+		EndIf
+	End Method
+	
+	Method Close()
+		If htmlview
+			If panel host.RemovePanel Self
+			FreeGadget htmlview
+			htmlview=Null
+			DebugLog "closing server"
+'			CloseServer
+		EndIf
+	End Method	
+
+	Function Create:TServerPanel(host:TCodePlay)
+		Local root
+		Local p:TServerPanel = New TServerPanel
+		p.host=host
+		p.name="localhost"
+		Return p
+	End Function
+
+End Type
+
+
+Type THelpPanel Extends TToolPanel
+
+	Field host:TCodePlay
+	Field htmlview:TGadget
+	Field oldpanel:TToolPanel
+
+	Method AddLink:TNode(parent:TNode,name$,href$)
+		Local	n:TNode
+		If parent
+			n=parent.AddNode(name)
+		Else
+			n=host.helproot
+		EndIf
+		If href href=RealPath(href)
+		n.SetAction(Self,TOOLNAVIGATE,href)
+		Return n
+	End Method
+
+	Method AddBMXLink:TNode(parent:TNode,name$,href$)
+		Local	n:TNode
+		If parent
+			n=parent.AddNode(name)
+		Else
+			n=host.bmxhelproot
+		EndIf
+		If href href=RealPath(href)
+		n.SetAction(Self,TOOLNAVIGATE,href)
+		Return n
+	End Method
+
+
+	Method ImportLinks( node:TNode,path$ )
+
+		Local t$=path+"/index.html"
+		If FileType( t )<>FILETYPE_FILE Return
+
+		node=AddBMXLink( node,StripDir( path ),t )
+
+		Local map:TMap=New TMap
+		
+		'scan for html files
+		For Local e$=EachIn LoadDir( path )
+			If e="index.html" Continue
+			Local p$=path+"/"+e
+			Select FileType( p )
+			Case FILETYPE_DIR
+				ImportLinks node,p
+			Case FILETYPE_FILE
+				If Not e.StartsWith( "_" ) And ExtractExt( e ).Tolower()="html"
+					map.Insert StripExt( e ),p
+				EndIf
+			End Select
+		Next
+
+		'scan for anchors in index.html...
+		'
+		'note: anchors must be quote enclosed and of simple form <a name="blah">
+		Local c$=CacheAndLoadText( t ),i
+		Repeat
+			i=c.Find( "<a name=~q",i )
+			If i=-1 Exit
+			i:+9
+			Local i2=c.Find( "~q>",i )
+			If i2=-1 Exit
+			Local q$=c[i..i2]
+			If q.StartsWith( "_" ) Continue
+			map.Insert q,t+"#"+q
+			i=i2+1
+		Forever
+
+		For Local kv:TKeyValue=EachIn map
+			AddBMXLink node,String( kv.Key() ),String( kv.Value() )
+		Next
+
+	End Method
+
+	Method SyncDocs()
+		If Not host.bmxpath Return
+	
+		host.bmxhelproot.FreeKids
+
+		ImportLinks Null,host.bmxpath+"/docs/html"
+
+		Local link:TNode
+		For Local m$=EachIn EnumModules()
+			If m.StartsWith( "brl." ) Or m.StartsWith( "pub." ) Or m.StartsWith("maxgui.") Continue
+			Local p$=ModulePath( m )+"/doc/commands.html"
+			If FileType( p )<>FILETYPE_FILE Continue
+			If Not link link=AddBMXLink( host.bmxhelproot,"Third party modules","" )
+			AddBMXLink link,m,p
+		Next
+
+		link=AddBMXLink( host.bmxhelproot,"Index","" )
+		
+		If FileType( host.bmxpath+"/docs/html/Modules/commands.txt" )=FILETYPE_FILE
+			Local comm$=CacheAndLoadText( host.bmxpath+"/docs/html/Modules/commands.txt" )
+			For Local Line$=EachIn comm.Split( "~n" )
+				Local bits$[]=Line.Split( "|" )
+				If bits.length<>2 Continue
+				Local i=bits[0].Find( " : " )
+				If i<>-1 bits[0]=bits[0][..i]
+				AddBMXLink link,bits[0],host.bmxpath+bits[1]
+			Next
+		EndIf
+			
+		host.bmxhelproot.Refresh
+	End Method
+
+	Method Invoke(command,argument:Object=Null)
+		Local	href$
+		If Not htmlview Return
+		Select command
+			Case TOOLFIND
+				host.findreq.ShowFind
+			Case TOOLESCAPE
+				If oldpanel host.SelectPanel oldpanel
+			Case TOOLBACKSPACE
+				Back			
+			Case TOOLCUT
+				GadgetCut htmlview
+			Case TOOLCOPY
+				GadgetCopy htmlview
+			Case TOOLPASTE
+				GadgetPaste htmlview
+			Case TOOLSHOW
+'				ActivateGadget htmlview	
+				host.SetTitle
+				host.options.outputstyle.Apply htmlview,1,host.options.colorcontainers
+			Case TOOLREFRESH
+				host.options.outputstyle.Apply htmlview,1,host.options.colorcontainers
+			Case TOOLNAVIGATE
+				href$=String(argument)
+				If href Go href
+			Case TOOLPRINT
+				GadgetPrint htmlview
+		End Select
+	End Method
+
+	Method OnEvent()
+		Local	url$,p,t$
+		If EventSource()=htmlview
+			Select EventID()
+				Case EVENT_GADGETMENU
+					DebugLog CurrentEvent.toString()
+					
+				Case EVENT_GADGETDONE
+'					DebugLog "GadgetDone!"
+				Case EVENT_GADGETACTION				'NAVIGATEREQUEST
+'					DebugLog "GadgetAction!"
+					url$=String( EventExtra() )
+					
+					
+					If url[..5]="http:" And Not url.StartsWith(WIKI_URL) And Not url.StartsWith(CLOUD)
+						OpenURL url
+					'Else If url.EndsWith( "\modules\index.html" )
+					'	OpenURL url
+					Else
+						p=url.findlast(".")
+						If p>-1
+							t$=url[p..].tolower()
+							If t$=".bmx" Or t$=".monkey"
+								If url.Find( "file://" )=0
+									url=url[7..]
+									?Win32
+									url=url[1..]
+									?
+								EndIf
+								url=url.Replace("%20"," ")
+								Local source:TOpenCode=host.OpenSource(url)
+								'If source source.MakePathTemp
+							Else
+								url=url.Replace("\","/")
+								Go url$
+							EndIf
+						EndIf
+					EndIf
+			End Select			
+		EndIf
+	End Method
+	
+	
+	Method Home()		
+		Local url$		
+		url="monkey:/docs/html/Home.html"
+		Go url
+	End Method
+	
+	Method Go(url$,internal=False)
+		Local	node:TNode
+		
+		If url.startsWith("monkey:")
+			If Not host.monkeypath Return	'silent fail			
+			url="file://"+host.monkeypath+url[7..]
+		EndIf
+
+		DebugLog "url="+url
+		
+		If url.startsWith("wiki:")
+			url=url[5..]
+			If host.options.offlinedocs
+				url=host.monkeypath+WIKI_LOCAL+url+WIKI_LOCAL_SUFFIX
+			Else
+				url=WIKI_URL+url+WIKI_ARGS
+			EndIf
+		EndIf
+
+		If host.options.externalhelp And Not internal
+			PollSystem
+			OpenURL url
+			MinimizeWindow host.window
+			PollSystem
+			Return
+		EndIf
+		
+		DebugLog "go:"+url
+
+		HtmlViewGo htmlview,url
+	
+		If host.currentpanel<>Self oldpanel=host.currentpanel
+
+		host.SelectPanel Self
+		
+		If host.helproot
+			node=host.helproot.FindArgument(RealPath(url))
+		EndIf
+		
+		If node
+			node.Highlight
+'		Else
+'			print "node not found"
+		EndIf		
+		ActivateGadget htmlview			
+	End Method
+		
+	Method Forward()
+		HtmlViewForward htmlview
+	End Method
+
+	Method Back()
+		HtmlViewBack htmlview
+	End Method
+
+	Function Create:THelpPanel(host:TCodePlay)
+		Local	root,style
+		Local	p:THelpPanel = New THelpPanel
+		p.host=host
+		p.name="Docs"
+		codeplay.addpanel(p)
+?win32
+		style=HTMLVIEW_NONAVIGATE		'HTMLVIEW_NOCONTEXTMENU
+?macos
+		style=HTMLVIEW_NONAVIGATE		'HTMLVIEW_NOCONTEXTMENU
+?
+		p.htmlview=CreateHTMLView(0,0,ClientWidth(p.panel),ClientHeight(p.panel),p.panel,style)		
+		SetGadgetLayout p.htmlview,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED
+'		p.Home
+		p.SyncDocs
+		Return p
+	End Function
+
+End Type
+
+Type TSearchResult
+	
+	Field filepath$
+	Field char%, Line%
+	Field linestring$
+	
+	Method AddToListbox( pGadget:TGadget )
+		AddGadgetItem pGadget, "[" + Line + ", " + char + "] " + filepath, 0, -1, StripWhitespace(linestring,char), Self
+	EndMethod
+	
+	Method Set:TSearchResult(pFilePath$,pChar%,pLine%,pLineString$)
+		filepath = pFilePath
+		char = pChar
+		Line = pLine
+		linestring = pLineString
+		Return Self
+	EndMethod
+	
+	Function StripWhitespace$(pString$,pChar%)
+		If pString.length < pChar Then Return pString
+		Local outString$
+		For Local i:Int = 0 Until pString.length
+			Select pString[i]
+				Case Asc(" "), Asc("~t"), Asc("~n"), Asc("~r")
+					If outString And Not outString.EndsWith(" ") Then outString:+" "
+				Default
+					outString:+pString[i..i+1]
+			EndSelect
+		Next
+		Return outString
+	EndFunction
+	
+EndType
+
+Type TSearchRequester Extends TRequester
+	
+	Const strSearchText$ = "Search"
+	Const strStopSearchText$ = "Stop Search"
+	
+'	Global strFileExts$[][] = [["bmx"],filetypes.Split(","),String[](Null)]
+	Global strFileExts$[][] = [["monkey"],filetypes.Split(","),String[](Null)]
+	
+	Field	findbox:TGadget,typebox:TGadget,pathbox:TGadget,pathbutton:TGadget,pathsubdir:TGadget,results:TGadget
+	Field lstSearchResults:TList = New TList
+	
+	Field safetyCount% = -1, safetyThreshold = 500, safetyResetCount% = 0
+	
+	Method Poll()
+		Local id:Int = EventID()
+		Local data:Int = EventData()
+		Select EventSource()
+			Case results
+				Select id
+					Case EVENT_GADGETACTION
+						Local tmpSearchResult:TSearchResult = TSearchResult(EventExtra())
+						If tmpSearchResult Then
+							host.DebugSource( tmpSearchResult.filepath, tmpSearchResult.Line, tmpSearchResult.char )
+							'Hide()
+						EndIf
+				EndSelect
+			Case pathbutton
+				If EventID()=EVENT_GADGETACTION
+					Local tmpString$ = RequestDir( "Choose a folder to search...",GadgetText(pathbox))
+					If tmpString Then SetGadgetText(pathbox,tmpString)
+				EndIf
+			Case window
+				If EventID()=EVENT_WINDOWCLOSE Then Hide()
+			Case findbox
+				If EventID() = EVENT_GADGETACTION Then
+					If GadgetText(findbox) Then EnableGadget(ok) Else DisableGadget(ok)
+				EndIf
+			Case ok
+				If EventID()=EVENT_GADGETACTION
+					If safetyCount < 0 Then StartSearch() Else safetyCount = -2
+				EndIf
+			Case cancel
+				If EventID()=EVENT_GADGETACTION Then Hide()
+		End Select
+	End Method
+	
+	Method Hide()
+		safetyCount = -2
+		Super.Hide()
+	EndMethod
+	
+	Method ShowWithPath( pPath$ )
+		If pPath Then SetGadgetText( pathbox, pPath )
+		Show()
+		ActivateGadget( findbox )
+	EndMethod
+	
+	Method StartSearch()
+		
+		PollSystem()
+		
+		Select FileType(RealPath(GadgetText(pathbox)))
+			Case FILETYPE_NONE
+				Notify "The specified path does not exist!",True
+				ActivateGadget(pathbox)
+				Return
+			Case FILETYPE_FILE
+				Notify "The path entered is for a file, please enter the path of a directory.",True
+				ActivateGadget(pathbox)
+				Return
+		EndSelect
+		
+		If Not GadgetText(findbox) Then
+			Notify "You must enter a search string to find!",True
+			ActivateGadget(findbox);Return
+		EndIf
+		
+		safetyResetCount = 0
+		safetyCount = 0
+		SetGadgetText ok, strStopSearchText;
+		ClearGadgetItems results
+		SearchPath( GadgetText(pathbox), strFileExts[SelectedGadgetItem(typebox)], GadgetText(findbox).ToLower(), ButtonState(pathsubdir) )
+		SetGadgetText ok, strSearchText
+		safetyCount = -1
+		SetStatusText window, "Search complete! Found "+CountGadgetItems(results)+" instance(s)!"
+		
+	EndMethod
+	
+	Method SearchPath(pPath$,pFileType$[],pString$,pRecurse% = True)
+		
+		pPath$ = RealPath(pPath)						'Make sure we are using a real path
+		
+		Local tmpSearchDir$[] = LoadDir(pPath,True)			'Load directors contents into string array
+		If Not tmpSearchDir Then Return					'Return if the directory is invalid
+		tmpSearchDir.Sort()							'Sort the contents alphabetically
+		
+		SetStatusText window, "Searching: "+ pPath			'And let user know which directory is being searched
+		
+		Local tmpFullPath$
+		
+		For Local tmpItem$ = EachIn tmpSearchDir
+			
+			tmpFullPath = pPath + "/" + tmpItem
+			
+			Select FileType(tmpFullPath)
+				Case FILETYPE_NONE;Continue                              'Skip item if, for whatever reason, it doesn't exist
+				Case FILETYPE_FILE                                       'If file, then check extension and search if valid
+					If Not pFileType
+						SearchFile(tmpFullPath,pString)
+					Else
+						Local tmpExt$ = ExtractExt(tmpFullPath).ToLower$()
+						For Local tmpValidExt$ = EachIn pFileType
+							If tmpExt = tmpValidExt Then SearchFile(tmpFullPath,pString)
+						Next
+					EndIf
+				Case FILETYPE_DIR                                        'If folder, then we might have to search recursively
+					If pRecurse Then SearchPath(tmpFullPath,pFileType,pString,pRecurse)
+			EndSelect
+			
+			If Not ShouldContinue() Then Return
+			
+		Next
+		
+		PollSystem();If PeekEvent() Then host.Poll()			'Let the system update as we could be searching a while
+		
+	EndMethod
+	
+	Method SearchFile(pPath$,pString$)
+		Local tmpText$ = CacheAndLoadText( pPath ), tmpLines$[], tmpFindPos%, tmpCharCount%, tmpLineNo%
+		Local tmpStringLength% = pString.length, tmpChunkLines$[], tmpPrevLines$
+		
+		If tmpText Then
+			tmpLines = tmpText.Split("~n")
+			tmpText = tmpText.ToLower()
+			tmpFindPos = tmpText.Find(pString)
+			While ShouldContinue() And tmpFindPos > -1
+				tmpChunkLines = tmpText[..tmpFindPos].Split("~n")
+				tmpPrevLines = "~n".Join(tmpChunkLines[..tmpChunkLines.length-1])
+				tmpLineNo:+(tmpChunkLines.length)-1
+				Local tmpSearchResult:TSearchResult = New TSearchResult.Set(pPath,tmpFindPos-tmpPrevLines.length,tmpLineNo+1,tmpLines[tmpLineNo])
+				tmpSearchResult.AddToListbox(results);safetyCount:+1
+				tmpCharCount:+tmpFindPos+tmpStringLength
+				tmpText = tmpText[tmpFindPos+tmpStringLength..]
+				tmpFindPos = tmpText.Find(pString)
+			Wend
+		EndIf
+	EndMethod
+	
+	Method ShouldContinue()
+		If safetyCount < 0 Then Return False
+		If safetyCount >= safetyThreshold Then
+			Local instances=safetyResetCount*safetyThreshold+safetyCount
+			If Confirm( "There have been "+instances+" instances found.~n~nWould you like To Continue?") Then
+				safetyCount = 0
+				safetyResetCount:+1
+			Else
+				safetyCount = -1
+				Return False
+			EndIf
+		EndIf
+		Return True
+	EndMethod
+	
+	Function Create:TSearchRequester(host:TCodePlay)
+		Local	search:TSearchRequester = New TSearchRequester
+		search.initrequester(host,"Find In Files",440,280,STYLE_CANCEL|STYLE_DIVIDER|STYLE_OK|STYLE_STATUS|STYLE_RESIZABLE,strSearchText)
+		DisableGadget(search.ok)
+		
+		SetGadgetLayout(CreateLabel("Find",6,8+4,95,24,search.window),EDGE_ALIGNED,EDGE_CENTERED,EDGE_ALIGNED,EDGE_CENTERED)
+		search.findbox=CreateTextField(103,8,ClientWidth(search.window)-(103+6),21,search.window);SetGadgetLayout(search.findbox,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_CENTERED)
+		
+		
+		SetGadgetLayout(CreateLabel("File Types",6,42,95,24,search.window),EDGE_ALIGNED,EDGE_CENTERED,EDGE_ALIGNED,EDGE_CENTERED)
+		search.typebox=CreateComboBox(103,38,ClientWidth(search.window)-(103+6),24,search.window);SetGadgetLayout(search.typebox,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_CENTERED)
+		
+		AddGadgetItem( search.typebox, "Monkey Files",GADGETITEM_DEFAULT,-1,"*.monkey" )
+		AddGadgetItem( search.typebox, "BlitzMax Files",0,-1,"*.bmx" )
+		AddGadgetItem( search.typebox, "Code Files",0,-1,fileTypes )
+		AddGadgetItem( search.typebox, "All Files (Warning: Includes Binary Files)",0,-1,"*")
+		
+		SetGadgetLayout(CreateLabel("Search Path",6,72,95,48,search.window),1,0,1,0)
+		search.pathbox=CreateTextField(103,68,ClientWidth(search.window)-(103+6+30+6),21,search.window);SetGadgetLayout(search.pathbox,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_CENTERED)
+		search.pathbutton=CreateButton("..",ClientWidth(search.window)-(34+6),65,34,26,search.window);SetGadgetLayout(search.pathbutton,EDGE_CENTERED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_CENTERED)
+		SetGadgetText(search.pathbox, CurrentDir())
+		
+		search.pathsubdir=CreateButton("Search sub-directories",103,98,ClientWidth(search.window)-(103+6),20,search.window,BUTTON_CHECKBOX);SetGadgetLayout(search.pathsubdir,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_CENTERED)
+		SetButtonState(search.pathsubdir,True)
+		
+		search.results=CreateListBox(6,128,ClientWidth(search.window)-12,280-(128+6),search.window);SetGadgetLayout(search.results,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED)
+		
+		Return search
+	End Function
+End Type
+
+
+Type TProjectRequester Extends TRequester
+	Field	projects:TProjects
+	Field	listbox:TGadget
+	Field	add:TGadget
+	Field	remove:TGadget
+	Field	props:TGadget
+	Field	moveup:TGadget
+	Field	movedown:TGadget
+	Field	Current:TProjectFolderNode
+
+	Method Invoke(command,arg:Object=Null)
+		Select command
+		Case TOOLACTIVATE
+			Refresh
+		End Select
+	End Method
+	
+	Method SetCurrent(i)
+		If i=-1
+			DisableGadget remove
+			DisableGadget moveup
+			DisableGadget movedown
+			DisableGadget props
+			Current=Null
+		Else
+			Current=TProjectFolderNode(GadgetItemExtra(listbox,i))
+			If Current
+				EnableGadget remove
+				EnableGadget props
+				EnableGadget moveup
+				EnableGadget movedown
+			EndIf
+		EndIf
+	End Method
+
+	Method Poll()
+		Local	index
+		Select EventSource()
+			Case window
+				If EventID()=EVENT_WINDOWCLOSE Then Hide()
+			Case add
+				If EventID() = EVENT_GADGETACTION Then
+					projects.NewProject
+					Refresh
+				EndIf
+			Case remove
+				If EventID() = EVENT_GADGETACTION Then
+					projects.RemoveProject SelectedGadgetItem(listbox)
+					Refresh
+				EndIf
+			Case cancel
+				If EventID() = EVENT_GADGETACTION Then Hide
+			Case props
+				If EventID() = EVENT_GADGETACTION And Current
+					host.projectprops.Open(Current)
+				EndIf
+			Case listbox
+				If EventID()=EVENT_GADGETSELECT
+					SetCurrent SelectedGadgetItem(listbox)	'EventData()
+				ElseIf EventID()=EVENT_GADGETACTION
+					SetCurrent SelectedGadgetItem(listbox)
+					host.projectprops.Open(Current)
+				EndIf
+			Case moveup
+				If EventID()=EVENT_GADGETACTION Then
+					index=projects.MoveProject(SelectedGadgetItem(listbox),-1)
+					Refresh
+					SelectGadgetItem listbox,index
+					SetCurrent(index)
+				EndIf
+			Case movedown
+				If EventID()=EVENT_GADGETACTION Then
+					index=projects.MoveProject(SelectedGadgetItem(listbox),1)
+					Refresh
+					SelectGadgetItem listbox,index
+					SetCurrent(index)
+				EndIf
+		End Select
+	End Method
+
+	Method Refresh()
+		ClearGadgetItems listbox
+		For Local node:TNode = EachIn projects.kids
+			If TFolderNode(node)'node.argument
+				AddGadgetItem listbox,node.name,0,-1,"",node
+			EndIf
+		Next
+		SetCurrent -1
+	End Method
+	
+	Method Open(projnode:TProjects)
+		projects=projnode
+		Refresh
+		Show
+	End Method
+	
+	Function Create:TProjectRequester(host:TCodePlay)
+		Local x,y
+		Local	proj:TProjectRequester = New TProjectRequester
+	
+		proj.initrequester(host,"Project Manager",400,168,STYLE_CANCEL|STYLE_DIVIDER|STYLE_MODAL)
+		proj.listbox=CreateListBox( 6,8,244,154,proj.window )
+		
+		x=ClientWidth(proj.window)-144
+		proj.add=CreateButton("Add Project",x,8,138,26,proj.window)
+		proj.remove=CreateButton("Remove Project",x,40,138,26,proj.window)
+
+		proj.moveup=CreateButton("Move Up",x,72,138,26,proj.window)
+		proj.movedown=CreateButton("Move Down",x,104,138,26,proj.window)
+
+		proj.props=CreateButton("Properties",x,136,138,26,proj.window)
+
+		DisableGadget proj.remove
+		DisableGadget proj.moveup
+		DisableGadget proj.movedown
+		DisableGadget proj.props
+		Return proj
+	End Function
+End Type
+
+Type TProjectProperties Extends TRequester
+	Field proj:TProjectFolderNode
+	Field newproj:Int = False				'If 'True' then cancel/close deletes project.
+	Field localname:TGadget
+	Field localpath:TGadget
+	Field pathbutton:TGadget
+	Field path:TGadget
+	Field user:TGadget
+	Field password:TGadget
+	Field checkout:TGadget
+	Field update:TGadget
+	Field commit:TGadget
+	Field poprequester:TRequester	'hack for restoring to projectmanager requester
+	Field dirty
+	
+	Method Invoke(command,arg:Object=Null)
+		Select command
+		Case TOOLACTIVATE
+			Refresh
+		End Select
+	End Method
+	
+	Method Tidy()
+		newproj = False
+		If dirty
+			proj.Set GadgetText(localname),GadgetText(localpath),GadgetText(path),GadgetText(user),GadgetText(password)
+			dirty=False
+		EndIf
+	End Method
+	
+	Method Poll()
+		If (EventID() <> EVENT_GADGETACTION) And (EventID() <> EVENT_WINDOWCLOSE) Then Return
+		Select EventSource()
+			Case localname,localpath,path,user,password
+				dirty=True
+			Case pathbutton
+				Local dir$=RequestDir("Select the project folder")
+				If dir
+					If dir[dir.length-1..]="/"	'fltk hack
+						dir=dir[..dir.length-1]
+					EndIf
+					SetGadgetText localpath,dir
+					If GadgetText(localname)=""
+						SetGadgetText localname,StripDir(dir)
+					EndIf
+					dirty=True
+				EndIf				
+			Case checkout
+				Tidy()
+				Hide()
+				proj.CheckoutVersion()
+Rem
+			Case commit
+				Tidy
+				Hide				
+				proj.CommitVersion		
+			Case update
+				Tidy
+				Hide				
+				proj.UpdateVersion		
+EndRem
+			Case ok
+				Tidy()
+				Hide()
+			Case cancel
+				Hide()
+			Case window
+				If EventID()=EVENT_WINDOWCLOSE
+					Hide()
+				EndIf
+		End Select
+	End Method
+	
+	Method Hide()
+		If proj And newproj Then proj.Free()
+		EnableGadget host.window
+		HideGadget window
+		host.UnhookRequester Self'poprequester
+		If poprequester poprequester.Show
+	End Method
+
+	Method Refresh()
+		SetGadgetText localname,proj.GetName()
+		SetGadgetText localpath,proj.path
+		SetGadgetText path,proj.svnpath
+		SetGadgetText user,proj.svnuser
+		SetGadgetText password,proj.svnpass
+	End Method
+	
+	Method Open(projnode:TProjectFolderNode, newproject:Int = False)
+		newproj=newproject
+		proj=projnode
+		Refresh()
+		Show()
+	End Method
+	
+	Function Create:TProjectProperties(host:TCodePlay)
+		Local	proj:TProjectProperties = New TProjectProperties
+		proj.initrequester(host,"Project Properties",480,250,STYLE_OK|STYLE_CANCEL|STYLE_DIVIDER|STYLE_MODAL)
+		proj.modal = True
+		
+		Local projectdetails:TGadget = CreatePanel(6,8,ClientWidth(proj.window)-12,85,proj.window,PANEL_GROUP,"Project Details")
+		
+		Local i,n,y
+		y=4
+
+		CreateLabel("Name",6,y+4,72,24,projectdetails)
+		proj.localname=CreateTextField(88,y,ClientWidth(projectdetails)-(88+6),21,projectdetails)
+'		proj.pathbutton=CreateButton("..",434,y,34,28,projectdetails)
+		y:+30
+
+		CreateLabel("Path",8,y+4,72,24,projectdetails)
+		proj.localpath=CreateTextField(88,y,ClientWidth(projectdetails)-(88+34+6+6),21,projectdetails)
+		proj.pathbutton=CreateButton("..",ClientWidth(projectdetails)-(34+6),y-3,34,26,projectdetails)
+		y:+30
+
+
+		Local svnbox:TGadget = CreatePanel(6,101,ClientWidth(proj.window)-12,144,proj.window,PANEL_GROUP,"Subversion Control")
+		y=4
+		CreateLabel("URL",8,y+LABELOFFSET,72,24,svnbox)
+		proj.path=CreateTextField(88,y,ClientWidth(svnbox)-92,21,svnbox)
+		y:+30
+		CreateLabel("Username",8,y+LABELOFFSET,72,24,svnbox)
+		proj.user=CreateTextField(88,y,ClientWidth(svnbox)-92,21,svnbox)
+		y:+30
+		CreateLabel("Password",8,y+LABELOFFSET,72,24,svnbox)
+		proj.password=CreateTextField(88,y,ClientWidth(svnbox)-92,21,svnbox,TEXTFIELD_PASSWORD)		
+		y:+30
+		proj.checkout=CreateButton("Check Out Project",ClientWidth(svnbox)-154,ClientHeight(svnbox)-32,150,28,svnbox)
+'		proj.update=CreateButton("Update Project",180,y+10,150,28,svnbox)
+'		proj.commit=CreateButton("Commit Project",340,y+10,150,28,svnbox)
+		y:+40
+
+		Return proj
+	End Function
+End Type
+
+Function GetInfo$(a$ Var)
+	Local p,r$
+	p=a.Find("|")+1
+	If p=0 p=a.length+1
+	r$=a$[..p-1]
+	a$=a$[p..]
+	Return r$	
+End Function
+
+Type TFolderNode Extends TNode
+	Field	owner:TNode
+	Field	path$
+	Field	scanned
+	Field	version
+	Field	foldertype
+	
+	Const PROJECTFOLDER=0
+	Const DIRECTORYFOLDER=1
+	Const FILEFOLDER=2
+
+	Method FindFolderFromPath:TFolderNode(dir$)
+		Local result:TFolderNode
+		If path=dir Return Self
+		For Local folder:TFolderNode = EachIn kids
+			result=folder.FindFolderFromPath(dir)
+			If result Return result
+		Next
+	End Method
+	
+	Method SetName(n$)
+		If version Then n:+"("+version+")"
+		Super.SetName( n )
+		Refresh
+	End Method
+		
+	Method SetVersion(ver)
+		version=ver
+		SetName StripDir(path)
+	End Method
+	
+	Method Write(stream:TStream)
+		Local isopen
+		If GetState()=OPENSTATE isopen=True
+		If version Or isopen
+			stream.WriteLine "proj_data="+path+"|"+isopen+"|"+version+"|"
+		EndIf
+		For Local folder:TFolderNode = EachIn kids
+			folder.Write(stream)
+		Next
+	End Method
+
+	Method ProjectHost:TCodePlay()
+		Local n:TNode = Self
+		While n
+			If TProjects(n) Return TProjects(n).host
+			n=n.parent
+		Wend
+	End Method
+
+	Method ProjectNode:TProjectFolderNode()
+		Local n:TNode = Self
+		While n
+			If TProjectFolderNode(n) Return TProjectFolderNode(n)
+			n=n.parent
+		Wend
+	End Method
+
+	Method RunSVN(cmd$,about$,refresh)
+		
+		Local host:TCodePlay = ProjectHost()
+		If Not host Notify "Node host not found.";Return
+		
+		Local project:TProjectFolderNode = ProjectNode()
+		If Not project Notify "Node project not found.";Return
+		
+		If project.svnuser
+			cmd:+" --username "+project.svnuser
+			If project.svnpass cmd:+" --password "+project.svnpass
+		EndIf
+
+		If refresh
+			host.execute cmd,about,MENUREFRESH,True,Self
+		Else
+			host.execute cmd,about,0,0,Self
+		EndIf
+	End Method
+	
+	Method UpdateVersion()
+		Local cmd$=svncmd+" update"
+		cmd:+" "+quote(path)
+		RunSVN cmd,"Updating "+path,True
+	End Method
+	
+	Method CommitVersion()
+		Local cmd$=svncmd+" commit"
+		cmd:+" -m ~qmy comment~q"
+		cmd:+" "+quote(path)
+		RunSVN cmd,"Committing "+path,False
+	End Method
+	
+	Method Remove()
+		
+	End Method
+	
+	Method Open(view=-1)
+		Update(True)
+		Super.Open view
+	End Method
+
+	Method AddFileNode:TNode(file$)
+		Local	n:TNode
+		Local ext$	
+		If (","+FileTypes+",").Contains(","+ExtractExt(file).toLower()+",") Then
+			n=AddNode(StripDir(file))
+			n.SetAction(owner,TOOLOPEN,file)
+			ext=ExtractExt(file$).ToLower()
+			n.sortname=ext+n.name
+			Return n
+		EndIf
+	End Method
+
+	Method AddFolderNode:TNode(path$)
+		Local	n:TFolderNode = TFolderNode.CreateFolderNode(path,DIRECTORYFOLDER)
+		n.owner = owner
+		n.sortname=" "+n.name
+		Append n
+		Return n
+	End Method
+
+	Method Scan(o:TNode)
+		Local p$
+		Local flist:TList = New TList
+		
+		owner=o
+		
+		For Local f$ = EachIn LoadDir(path,True)
+			If f[..1] = "." Then Continue
+			p$=path+"/"+f
+			Select FileType(p$)
+				Case FILETYPE_FILE
+					AddFileNode p$
+				Case FILETYPE_DIR
+					AddFolderNode p$
+			End Select	
+		Next
+		
+		SortKids
+		scanned = True
+		
+	End Method
+	
+	Method ScanKids()
+		For Local f:TFolderNode = EachIn kids
+			f.owner = owner
+			f.Update(False)
+		Next
+	End Method
+	
+	Method Rescan()
+		scanned = False
+		Update()
+	EndMethod
+	
+	Method Update( alwaysScanKids:Int = False )
+		If Not scanned Then
+			FreeKids()
+			Scan owner
+		EndIf
+		If alwaysScanKids Or Not IsHidden() Then ScanKids()
+		Refresh()
+	End Method
+	
+	Method Invoke(command,argument:Object=Null)
+		Local host:TCodePlay
+		Local cmd,p
+		Local Line$
+	
+		host=ProjectHost()
+
+		If Not host 
+			DebugStop
+			Notify "Node host not found."
+			Return
+		EndIf
+		
+		Select command
+		Case TOOLOUTPUT
+			Line$=String(argument)
+			p=Line.find(" revision ")
+			If p>-1
+				SetVersion Int(Line[p+10..])
+			EndIf
+'			If line[..12]="At revision "
+'			DebugLog "TOOLOUTPUT:"+line
+			Return
+		Case TOOLERROR
+			Line$=String(argument)
+'			DebugLog "TOOLERROR:"+line
+			Return
+		Case TOOLMENU
+			cmd=Int(String(argument))
+			Select cmd
+			Case 0		'special toolmenu-command=0 fired by rightbutton node context
+				Highlight			
+				Local menu:TGadget
+				menu=host.projects.projmenu
+				PopupWindowMenu host.window,menu,Self
+			Case MENUREFRESH
+				Rescan()
+			Case MENUBROWSE
+				OpenURL RealPath(path)
+			Case MENUSHELL
+				Local cd$=CurrentDir()
+				ChangeDir RealPath(path)
+?MacOS
+				host.execute "/bin/bash","Shell Terminal"
+?Linux
+				host.execute "/bin/bash","Shell Terminal"
+?Win32
+				host.execute "cmd","Shell Terminal - Type Exit To End"
+?
+				ChangeDir cd
+			Case MENUUPDATE
+				UpdateVersion
+			Case MENUCOMMIT
+				CommitVersion
+'			Case MENUPROPS
+'				host.projectprops.Open(Self)
+			Case MENUFINDINFILES
+				host.searchreq.ShowWithPath( RealPath(path) )
+			End Select
+		End Select
+	End Method	
+
+	Function CreateFolderNode:TFolderNode(path$,foldertype)
+		Local	n:TFolderNode = New TFolderNode
+'		n.host=host
+		n.SetName( StripDir(path) )
+		n.path = path
+		n.foldertype = foldertype
+		Return n
+	End Function
+End Type
+
+Type TProjectFolderNode Extends TFolderNode
+	
+	Field owner:TProjects
+	Field svnpath$,svnuser$,svnpass$,svnversion
+	Field svnerr$
+	
+	Method CheckoutVersion()	'to do - needs to move old version to temp?
+		Local cmd$ = svncmd+" checkout"
+		cmd:+" "+quote(svnpath)
+		cmd:+" "+quote(path)
+		RunSVN cmd,"Checking out "+svnpath+" to "+path,True
+	End Method
+
+	Function Crypt$(a$)
+		Local b$,c
+		For Local i:Int = 0 Until a.length
+			c=a[i]
+			If c>31 c:~((i*-5)&31)
+			b:+Chr(c&255)
+		Next
+		Return b
+	End Function
+	
+	Method GetName$()
+		If name="." Return ""
+		Return name
+	End Method
+
+	Method ToString$()
+		Local prj$
+		Local isopen
+		If GetState()&OPENSTATE isopen=True
+		prj=name+"|"+path+"|"+svnpath+"|"+svnuser+"|"+crypt(svnpass)+"|"+isopen+"|"+version
+		Return prj
+	End Method
+
+	Method Write(stream:TStream)
+		stream.WriteLine "proj_node="+ToString()
+		For Local folder:TFolderNode = EachIn kids
+			folder.Write(stream)
+		Next
+	End Method
+	
+	Method FromString(info$)
+		Local n$ = GetInfo(info)
+		If Not n Then n = "."
+		SetName( n )
+		path=GetInfo(info)
+		If path path=owner.host.FullPath(path)
+		svnpath=GetInfo(info)
+		svnuser=GetInfo(info)
+		svnpass=GetInfo(info)
+		Scan(owner)
+		Local isopen,vers
+		isopen=Int(GetInfo(info))
+		If isopen
+			Open
+		EndIf	
+		vers=Int(GetInfo(info))
+		If vers
+			SetVersion vers
+		EndIf
+	End Method
+	
+	Method Remove()
+		owner.RemoveProject(GetIndex())
+	End Method
+	
+	Method Invoke(command,argument:Object=Null)
+		Local cmd
+		Select command
+		Case TOOLMENU
+			cmd=Int(String(argument))
+			Select cmd
+			Case MENUPROPS
+				Return owner.host.projectprops.Open(Self)				
+			Case MENUREMOVE
+				Remove
+				Return
+			End Select
+		End Select
+		Return Super.Invoke(command,argument)
+	End Method
+
+	Method Set(n$,p$,s$,user$,pass$)
+		path=owner.host.FullPath(p)
+		setname n
+		svnpath=s
+		svnuser=user
+		svnpass=pass
+		Rescan()
+		owner.host.projectreq.Refresh()
+	End Method
+
+	Function CreateProjectNode:TProjectFolderNode(projects:TProjects,info$)
+		Local n:TProjectFolderNode = New TProjectFolderNode
+		n.owner=projects
+		n.FromString(info)
+		n.foldertype=PROJECTFOLDER
+		Return n
+	End Function
+
+End Type
+
+Type TProjects Extends TNode
+	Field host:TCodePlay
+	Field addproj:TNode
+	Field projmenu:TGadget
+	Field projmenuprops:TGadget
+
+	Method RemoveProject(index)
+		Local	node:TNode
+		If index<0 Or index>=kids.Count() Return
+		node=TNode(kids.ValueAtIndex(index))
+		If node node.Free
+		Refresh
+	End Method			
+	
+	Method MoveProject(index,dir)
+		Local node:TNode
+		Local link:TLink
+		If index<0 Or index>=kids.Count() Return index
+		node=TNode(kids.ValueAtIndex(index))
+		If node
+			addproj.Detach
+			node.Hide
+			link=kids.FindLink(node)
+			If dir>0
+				If link link=link._succ
+				If link
+					kids.Remove node
+					kids.InsertAfterLink node,link
+					index:+1
+				EndIf
+			Else
+				If link link=link._pred
+				If link
+					kids.Remove node
+					kids.InsertBeforeLink node,link			
+					index:-1
+				EndIf
+			EndIf		
+			Append addproj
+			Refresh
+		EndIf
+		Return index
+	End Method			
+
+	Method NewProject()
+		addproj.Detach
+		Local proj:TProjectFolderNode = TProjectFolderNode.CreateProjectNode(Self,"")
+'		proj.scan(Self)
+		Append proj
+		Append addproj
+		host.projectprops.Open(proj, True)
+		Refresh
+	End Method
+
+	Method AddProject(data:TList)
+		Local project:TProjectFolderNode
+		Local folder:TFolderNode
+		For Local info$ = EachIn data
+			If Not project
+				addproj.Detach
+				project=TProjectFolderNode.CreateProjectNode(Self,info)
+				Append project
+				Append addproj
+				Refresh
+			Else
+				Local path$
+				Local popen
+				Local pversion
+				path=GetInfo(info)
+				popen=Int(GetInfo(info))
+				pversion=Int(GetInfo(info))
+				folder=project.FindFolderFromPath(path)
+				If folder
+					folder.SetVersion pversion
+					folder.ReScan()
+					If popen Then folder.Open()
+				EndIf		
+			EndIf
+		Next
+	End Method
+
+	Method Write(stream:TStream)
+		For Local project:TProjectFolderNode = EachIn kids
+			project.Write(stream)		
+		Next
+	End Method
+
+	Method Invoke(command,argument:Object=Null)
+		Select command
+		Case TOOLNEW
+			NewProject
+		Case TOOLOPEN
+			host.OpenSource String(argument)
+		End Select
+	End Method
+				
+	Function CreateProjects:TProjects(host:TCodePlay)
+		Local p:TProjects = New TProjects
+		p.SetName("Projects")
+		p.host=host		
+		p.addproj=p.AddNode("Add Project")
+		p.addproj.SetAction p,TOOLNEW
+
+		p.projmenu=CreateMenu("Proj",0,Null)
+		CreateMenu "Refresh",MENUREFRESH,p.projmenu
+		CreateMenu "Find in Files",MENUFINDINFILES,p.projmenu
+		CreateMenu "Explore",MENUBROWSE,p.projmenu
+		CreateMenu "Shell",MENUSHELL,p.projmenu
+		CreateMenu "",0,p.projmenu
+		CreateMenu "Update Version",MENUUPDATE,p.projmenu
+		CreateMenu "Commit Version",MENUCOMMIT,p.projmenu
+		CreateMenu "",0,p.projmenu
+		CreateMenu "Remove",MENUREMOVE,p.projmenu
+		p.projmenuprops=CreateMenu("Properties",MENUPROPS,p.projmenu)
+		host.projectreq.projects=p
+		Return p
+	End Function
+End Type
+
+Type TByteBuffer Extends TStream
+	Field	bytes:Byte[]
+	Field	readpointer
+
+	Method Read( buf:Byte Ptr,count )
+		If count>readpointer count=readpointer
+		If Not count Return
+		MemCopy buf,bytes,count
+		readpointer:-count
+		If readpointer MemMove bytes,Varptr bytes[count],readpointer
+		Return count
+	End Method
+	
+	Method ReadLine$()
+		For Local i:Int = 0 Until readpointer
+			If bytes[i]=10 Or bytes[i] = 0 Then
+				Local tmpBytes:Byte[] = New Byte[i+1]
+				If i And bytes[i-1] = 13 Then i:-1
+				Read(tmpBytes,tmpBytes.length)
+				Return String.FromBytes(tmpBytes, i)
+			EndIf
+		Next
+	EndMethod
+	
+	Method WriteFromPipe( pipe:TPipeStream )
+		Local	n,m,count = pipe.ReadAvail()
+		n=readpointer+count
+		If n>bytes.length
+			m=Max(bytes.length*1.5,n)
+			bytes=bytes[..m]
+		EndIf
+		pipe.Read( Varptr bytes[readpointer], count )
+		readpointer=n
+		Return count
+	EndMethod
+	
+	Method Write( buf:Byte Ptr,count )
+		Local	n,m
+		n=readpointer+count
+		If n>bytes.length
+			m=Max(bytes.length*1.5,n)
+			bytes=bytes[..m]
+		EndIf
+		MemCopy Varptr bytes[readpointer],buf,count
+		readpointer=n
+		Return count
+	End Method	
+	
+	Method LineAvail()
+		For Local i:Int = 0 Until readpointer
+			If bytes[i]=10 Return True
+		Next
+	End Method
+
+	Method FlushBytes:Byte[]()
+		Local res:Byte[] = bytes[..readpointer]
+		readpointer = 0
+		Return res
+	End Method
+End Type
+
+Type TObj
+	Field	addr$,sync,refs,syncnext
+	Method ShouldSync( pDebugTree:TDebugTree )
+		If sync < pDebugTree.sync Then pDebugTree.QueueSync( Self )
+	EndMethod
+	Method HasSynced( pSync% )
+		sync = pSync;syncnext = False
+	EndMethod
+End Type
+
+Type TVar Extends TNode
+
+	Field	owner:TDebugTree
+	Field	obj:Object
+
+	Method Free()
+		If TObj(obj) owner.RemoveObj TObj(obj)
+		obj=Null
+		Super.Free()
+	End Method
+
+	Method SetVarName(n$)
+		Local	p
+		name=n
+' if object ref set addr$ field	
+		If name.find("$=")=-1 And name.find( ":String=" )=-1 And name.find(")=$")=-1
+			p=name.find("=$")
+			If p<>-1
+				If TObj(obj) Then
+					If TObj(obj).addr <> name[p+2..] Then
+						TDebugTree.RemoveObj TObj(obj)
+					Else
+						TObj(obj).refs:-1
+					EndIf	
+				EndIf				
+				obj=TDebugTree.AddObj(name[p+2..])
+				'Request object dump if we are visible now that
+				'we have updated our own object pointer.
+				If Not IsHidden() Then Request()
+				Return
+			EndIf
+			p=name.find("=Null")
+			If p<>-1
+				FreeKids
+				TDebugTree.RemoveObj TObj(obj)
+				obj=Null
+			EndIf
+		EndIf
+	End Method
+	
+	Method AddVar(name$)
+		Local	v:TVar=New TVar
+		v.owner=owner
+		Append v
+		v.setvarname name
+	End Method
+	
+	Method SetValue(val:TVar)
+		Local	v:TVar,w:TVar,i,kidsarray:Object[]
+' if this is a reference to same object refresh values
+		If obj And obj=val.obj
+			If kids.IsEmpty()
+				For v=EachIn val.kids
+					AddVar v.name
+				Next
+			Else
+				kidsarray = kids.ToArray()
+				For v=EachIn val.kids
+					If i<kidsarray.length
+						w=TVar(kidsarray[i])
+						If w w.SetVarName v.name
+					Else
+						AddVar v.name
+					EndIf
+					i:+1
+				Next
+				kidsarray = Null	
+			EndIf
+			Refresh
+		EndIf	
+' recurse so all references are updated
+		If IsHidden() Then Return				'parent And parent.state=CLOSEDSTATE Return
+		For v=EachIn kids
+			v.SetValue val
+		Next
+	End Method
+	
+	Method Open(open=-1)
+		For Local kid:TVar = EachIn kids
+			kid.Request()
+		Next
+		Super.Open(open)
+	EndMethod
+	
+	Method Request()
+		If TObj(obj) Then TObj(obj).ShouldSync(owner)
+	EndMethod
+	
+End Type
+
+Type TScope Extends TVar
+	Field	tree:TDebugTree
+	Field	file$,Line,column
+
+	Method Invoke(command,argument:Object=Null)
+		Select command
+			Case TOOLACTIVATE
+				tree.SelectScope Self,True
+		End Select
+	End Method
+	
+	Method SetScope(s:TScope)
+		Local	v:TVar
+		file=s.file
+		Line=s.Line
+		column=s.column
+		s.obj=Self
+		SetValue s
+	End Method
+	
+	Method SetFile(debugtree:TDebugTree,f$)
+		tree=debugtree
+		Local p=f.Find("<")+1
+		Local q=f.Find(">")+1
+		Local r=f.Find(",")+1
+		If p And q And r
+			file=f[..p-1]
+			Line=Int(f[p..r-1])
+			column=Int(f[r..q-1])
+		EndIf
+		obj=Self
+	End Method
+	
+	Method Request()
+		For Local kid:TVar = EachIn kids
+			kid.Request()
+		Next
+	EndMethod
+	
+End Type
+
+Type TDebugTree Extends TVar
+	Global	sync
+	Global	objmap:TMap = CreateMap()
+	Field	host:TCodePlay
+	Field	instack:TList
+	Field	inscope:TScope
+	Field	invar:TVar
+	Field	infile$
+	Field	inexception$
+	Field	firststop
+	Field	cancontinue
+	
+	Method Reset()
+'		host.SetMode host.DEBUGMODE
+		SetStack( New TList )
+		ClearMap objmap
+		instack=Null
+		inscope=Null
+		invar=Null
+		infile=""
+		inexception=""
+		sync=0
+		firststop=True
+		cancontinue=False
+	End Method
+
+	Function AddObj:TObj(addr$)
+		Local	o:TObj = TObj(MapValueForKey( objmap, addr ))
+		If o Then
+			o.refs:+1
+		Else
+			o=New TObj
+			o.addr=addr
+			o.refs=1
+			MapInsert objmap, addr, o
+		EndIf
+		Return o
+	End Function
+
+	Function FindObj:TObj(addr$)
+		Return TObj(MapValueForKey( objmap, addr ))
+	End Function
+	
+	Function RemoveObj(obj:TObj)		':TObj
+		If obj Then
+			obj.refs:-1
+			If Not obj.refs Then MapRemove objmap, obj.addr
+		EndIf
+	End Function
+
+	Method SyncVars()
+		sync:+1
+		For Local tmpVar:TVar = EachIn kids
+			tmpVar.Request()
+		Next
+	End Method
+	
+	Method QueueSync( pObj:TObj )
+		If Not pObj Then Return
+		'Sync as soon as the debug pipe is clear
+		'(see TOuputPanel.SendDumpRequests()).
+		pObj.syncnext = True
+	EndMethod
+			
+	Method SetStack(list:TList)
+		Local	openscope:TScope
+		Local	s:TScope
+		Local	count,i
+
+		count=kids.count()			'root.varlist.count()
+		For Local scope:TScope = EachIn list
+			If i>=count
+				Append scope		'root.Append scope
+				s=scope
+			Else
+				s=TScope(kids.ValueAtIndex(i))
+' simon was here				
+				If s.name=scope.name
+					s.SetScope scope
+					scope.Free
+				Else
+					While kids.count()>i
+						s=TScope(kids.Last())
+						s.free
+					Wend
+					Append scope
+					s=scope
+					count=i+1
+				EndIf
+				
+			EndIf
+			If firststop
+				If host.IsSourceOpen(s.file) openscope=s
+			Else
+				openscope=s
+			EndIf
+			i:+1
+		Next
+		While kids.count()>i
+			s=TScope(kids.Last())
+			s.free
+		Wend
+		If list.IsEmpty() Return
+		If Not openscope openscope=TScope(list.First())
+		If openscope SelectScope openscope,True
+		Refresh
+		firststop=False
+	End Method
+
+	Method SelectScope(scope:TScope,open)
+		If Not scope Return		
+		host.SetMode host.DEBUGMODE	' simon was here, smoved from reset
+		If scope.file host.DebugSource scope.file,scope.Line,scope.column
+		scope.Open()
+'		If open
+'			SelectTreeViewNode scope.node
+'			scope.open
+'		EndIf
+	End Method
+	
+	Method ProcessError$(Line$)
+		Local	p
+		
+		While p < Line.length
+			If Line[p]=$3E Then p:+1 Else Exit		'">"
+		Wend
+		
+		If p = Line.length Return
+		If p Then Line = Line[p..]
+
+		If Not Line.StartsWith("~~>") Return Line
+		Line=Line[2..]
+
+		If invar
+			If Line="}"
+				SetValue invar		'root
+				invar.Free
+				invar=Null
+			Else
+'				If Not invar.name
+'					invar.name=line
+'				Else
+					invar.AddVar Line
+'				EndIf
+			EndIf
+			Return
+		EndIf
+		
+		If instack 			
+			If Line="}"
+				
+				SetStack instack
+				instack=Null
+				inscope=Null
+				'Request first object dumps, and bump sync count
+				SyncVars
+				If inexception
+					Notify inexception
+					inexception=""
+				EndIf
+				Return
+			EndIf
+			
+			If infile
+				If Line="Local <local>"
+				Else
+					inscope=New TScope
+'					Print "inscope.line="+line
+					inscope.name=Line
+					inscope.owner=Self
+					instack.AddLast inscope
+				EndIf
+				If inscope inscope.setfile Self,infile
+				infile=""
+				Return
+			EndIf
+
+			If Line.StartsWith("@") And Line.Contains("<")
+				infile=Line[1..]
+			Else
+				If inscope inscope.AddVar Line
+			EndIf
+
+			Return
+		EndIf
+
+		If Line.StartsWith("Unhandled Exception:")
+			inexception=Line
+			host.output.WritePipe "t"
+			cancontinue=False
+			Return
+		EndIf
+
+		If Line="StackTrace{"
+			instack=New TList
+			Return
+		EndIf
+
+		If Line="Debug:" Or Line="DebugStop:"
+			host.output.WritePipe "t"
+			If Not cancontinue Then
+				cancontinue=True
+				host.RefreshToolbar()
+			EndIf
+			Return
+		EndIf					
+		
+		If Line.StartsWith("ObjectDump@")
+			p=Line.find("{",11)
+			If p=-1 Return Line
+			Line=Line[11..p]
+			invar=New TVar
+			invar.obj=FindObj(Line)
+			invar.owner=Self
+			Return
+		EndIf
+		
+	End Method
+
+	Function CreateDebugTree:TDebugTree(host:TCodePlay)
+		Local	d:TDebugTree = New TDebugTree
+		d.owner=d
+		d.SetName "Debug"
+		d.host=host
+		d.Open
+		Return d		
+	End Function
+End Type
+
+Type TNodeView
+	Field	owner:TNavBar
+	Field	root:TNode
+	Field	treeview:TGadget
+	Field	index
+	
+	Method NewView()
+		Local	n:TNode,hnode:TGadget
+		hnode=SelectedTreeViewNode(treeview)
+		n=root.Find(hnode,index)
+		If n And n.parent owner.AddView n
+	End Method
+
+	Method OnEvent()
+		Local	n:TNode = root.Find(TGadget(EventExtra()),index)
+		If Not n Return	'probably an eventgadgetselect -1 Notify("could not find in root");Return
+
+		Select EventID()
+			Case EVENT_GADGETSELECT
+				n.invoke(TOOLSELECT)				
+			Case EVENT_GADGETACTION
+				n.invoke(TOOLACTIVATE)				
+			Case EVENT_GADGETMENU
+				n.invoke(TOOLMENU,Self)
+			Case EVENT_GADGETOPEN
+				n.open index
+			Case EVENT_GADGETCLOSE
+				n.close index
+		End Select
+	End Method
+End Type
+
+Type TNavBar Extends TEventHandler
+	Field	host:TCodePlay
+	Field	tabber:TGadget
+	Field	viewlist:TList=New TList
+	Field	selected:TNodeView
+	Field	navmenu:TGadget
+	
+	Method SelectedView()
+		If selected Return selected.index
+	End Method
+		
+	Method SelectView(index)
+		Local	n:TNodeView
+		If index>=viewlist.count() Return
+		n=TNodeView(viewlist.ValueAtIndex(index))
+		If Not n Print "selectview failed";Return
+		If n<>selected
+			If selected HideGadget selected.treeview
+			selected=n
+		EndIf
+		ShowGadget n.treeview
+		SelectGadgetItem tabber,index
+	End Method
+	
+	Method AddView(node:TNode)
+		Local	n:TNodeView
+		Local	index,root:TGadget
+		For n=EachIn viewlist
+			If n.root=node SelectView n.index;Return
+		Next
+		n=New TNodeView
+		n.owner=Self
+		n.root=node
+		n.treeview=CreateTreeView(0,0,ClientWidth(tabber),ClientHeight(tabber),tabber)
+		host.options.navstyle.Apply n.treeview,1,host.options.colorcontainers
+		SetGadgetLayout n.treeview,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED
+		HideGadget n.treeview
+
+		n.index=viewlist.Count()
+		viewlist.AddLast n		
+		
+		AddGadgetItem tabber,node.name
+		root=TreeViewRoot(n.treeview)
+		node.setnode root,n.index
+		SelectView n.index
+		Return n.index
+	End Method
+
+	Method OnEvent()
+		If EventSource()=tabber
+			SelectView SelectedGadgetItem(tabber)				
+		End If
+		If selected And EventSource()=selected.treeview
+			selected.OnEvent
+		EndIf
+	End Method
+
+	Method Refresh()
+		For Local view:TNodeView = EachIn viewlist
+			host.options.navstyle.Apply view.treeview,1,host.options.colorcontainers
+		Next
+	End Method
+
+	Method Invoke(command,argument:Object=Null)
+		If command=TOOLREFRESH Refresh()		
+		If command=TOOLNEWVIEW And selected selected.NewView
+	End Method
+
+	Function CreateNavMenu:TGadget()
+		Local	edit:TGadget = CreateMenu("&Nav",0,Null)
+		CreateMenu "&New View",MENUNEWVIEW,edit
+		Return edit
+	End Function
+
+	Function Create:TNavBar(host:TCodePlay, parent:TGadget)	',root:TNode)
+		Local	n:TNavBar = New TNavBar
+		n.host=host	
+		n.tabber=CreateTabber(0,0,ClientWidth(parent),ClientHeight(parent),parent)
+		SetGadgetLayout(n.tabber,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED)
+'		n.AddView root
+		n.navmenu=CreateNavMenu()
+		Return n		
+	End Function
+
+End Type
+
+Type TOutputPanel Extends TToolPanel	'used build and run
+
+	Field	host:TCodePlay
+	Field	output:TGadget
+	
+	Field	process:TProcess
+	Field	pipe:TStream
+
+	Field	wpipe:TTextStream
+
+	Field	user$,cmdline$,err$,post$
+	Field	errbuffer:TByteBuffer
+	Field	outputmenu:TGadget
+	Field	posttool:TTool
+	
+	Field transerror
+
+	Method ClearDumpRequests()
+		For Local o:TObj = EachIn MapValues(host.debugtree.objmap)
+			o.HasSynced(o.sync)
+		Next
+	EndMethod
+	
+	Method SendDumpRequests()
+		For Local o:TObj = EachIn MapValues(host.debugtree.objmap)
+			If o.syncnext Then
+				If o.addr <> "00000000" Then WritePipe "d"+o.addr
+				o.HasSynced( host.debugtree.sync )
+			EndIf
+		Next
+	EndMethod
+	
+	Method Clear()
+		If Not output Open()
+		SetGadgetText output,""
+	End Method
+	
+	Method WriteAscii(mess$)
+		If Not output Open()
+		AddTextAreaText output,mess.Replace("~0","")
+	End Method
+
+	Method Write(utf8$)
+		Local mess$,c,d		
+		If Not output Open()
+		For Local i:Int = 0 Until utf8.Length		
+			c=utf8[i]
+			If c<128
+				mess:+Chr(c)
+				d=0
+				Continue
+			EndIf
+			If d
+				mess:+Chr((d-192)*64+(c-128))				
+				d=0
+				Continue
+			EndIf
+			d=c
+		Next
+		AddTextAreaText output,mess.Replace("~0","")
+	End Method
+
+	Method Execute(cmd$,mess$="",exe$="",home=True,owner:TTool=Null)
+		If Not output Open()
+		If Not mess$ mess$=cmd$
+		err$=""
+		post$=exe
+		posttool=owner
+		host.SelectPanel Self
+		host.debugtree.Reset
+				
+		If process And ProcessStatus(process)
+			Delay 500
+			If ProcessStatus(process)
+				Notify "Current process still busy "+cmdline+"."
+				Return
+			EndIf
+		EndIf
+		cmd=cmd.Trim()
+		process=CreateProcess(cmd$,HIDECONSOLE)
+				
+		If Not process Then Notify "Process failed to start "+cmd+".";Return
+
+		pipe=Process.pipe
+		wpipe=TTextStream.Create(pipe,TTextStream.UTF8)
+
+		cmdline=cmd
+		If home Clear
+		Write( mess+"~n" )
+		errbuffer = New TByteBuffer
+		host.RefreshToolbar	
+
+	End Method
+
+	Method WritePipe(l$)	
+		Try
+			If pipe pipe.WriteLine(l)
+		Catch ex:TStreamWriteException
+			Write "Process debug failure. Cannot write:~n"+l+"~n"
+			Stop
+		EndTry	
+	End Method
+
+	Method Go()
+		WritePipe "r"
+		host.debugtree.cancontinue = False
+		host.SelectPanel Self
+		host.RefreshToolbar()
+	End Method
+	
+	Method StepOver()
+		ClearDumpRequests()
+		WritePipe "s"
+	End Method
+	
+	Method StepIn()
+		ClearDumpRequests()
+		WritePipe "e"
+	End Method
+
+	Method StepOut()
+		ClearDumpRequests()
+		WritePipe "l"
+	End Method
+	
+	Method Stop()
+		If Not process Return		
+		process.Terminate()
+		FlushPipes process.pipe,process.err		
+		process.Close()
+		process=Null
+		Write "~nProcess Terminated~n"
+		host.DebugExit()
+		Close()
+	End Method
+	
+	Method Wait()
+		While process And process.status()
+			PollSystem
+		Wend
+	End Method
+	
+	Method Invoke(command,argument:Object=Null)
+		Select command
+			Case TOOLSHOW
+				host.SetTitle()
+				If output 
+					ActivateGadget output	
+					host.options.outputstyle.apply output,1,host.options.colorcontainers
+				EndIf
+			Case TOOLREFRESH
+				host.options.outputstyle.apply output,1,host.options.colorcontainers
+			Case TOOLCLOSE
+				host.RemovePanel Self
+				output=Null
+			Case TOOLCUT
+				GadgetCut output
+			Case TOOLCOPY
+				GadgetCopy output
+			Case TOOLPASTE
+				GadgetPaste output
+			Case TOOLSELECTALL
+				If output SelectTextAreaText output
+			Case TOOLESCAPE
+				Escape
+'			Case TOOLBACKSPACE
+'				out.writechar(KEY_BACKSPACE)
+		End Select
+	End Method
+	
+	Method Close()
+		host.SelectPanel host.activepanel
+	End Method
+	
+	Method Escape()
+		Stop
+		Close
+	End Method
+	
+	Function outputfilter(event:TEvent,context:Object)
+		Local out:TOutputPanel=TOutputPanel(context)
+		If Not out Return
+		Select event.id
+			Case EVENT_KEYDOWN
+				If event.data=27
+					out.Escape()
+					Return 0
+				EndIf
+			Case EVENT_KEYCHAR
+'				Print "output_keychar "+event.data
+				out.writechar(event.data)
+		End Select
+		Return 1
+	End Function
+	
+	Method OnEvent()
+		If EventSource()=output
+			If EventID()=EVENT_GADGETMENU
+				PopupWindowMenu host.window,outputmenu
+			EndIf
+		EndIf
+' Case EVENT_TIMERTICK
+		If Not process Return		
+		
+		ReadPipes process.pipe,process.err
+		
+		If Not process.status()
+			process.terminate
+			FlushPipes process.pipe,process.err
+			process.close()
+			process = Null
+			Write "~nProcess Complete~n"
+			host.DebugExit
+			
+			If transerror
+				transerror=False
+			Else
+				host.SelectPanel Self
+			EndIf
+
+			If err
+				host.ParseError err
+			Else
+				If post$
+					Local menuaction=Int(post)
+					If menuaction
+						host.OnMenu menuaction,posttool
+'					Else				
+'						Execute post$,"","",False,0
+					EndIf
+				Else
+					If host.options.hideoutput Close()
+				EndIf
+			EndIf
+		EndIf	
+		
+	End Method
+		
+	Method FlushPipes(pipe:TPipeStream,errpipe:TPipeStream)
+		ReadPipes(pipe,errpipe)
+		Local bytes:Byte[] = errbuffer.flushbytes()
+		If bytes
+			Local Line$=String.FromBytes(bytes,Len bytes)
+			Line=Line.Replace(Chr(13),"")
+			If Line<>">" Write Line
+		EndIf
+	End Method
+
+	Method ProcessTransOutput(line$)
+		Local file$,row,mess$
+		Local p,q,r
+		
+		q=line.find( "<" )
+		If q=-1 Return False
+		p=line.find( "> : Error : ",q+1 )
+		If p=-1 Return False
+		
+		file=line[..q]
+		r=file.findlast("~n")
+		file=file[r+1..]
+	
+		row=Int(line[q+1..p])
+		mess=line[p+12..]
+
+		host.SelectError file,1,row
+		Notify "Compile Error~n~n"+mess
+		host.SetStatus mess		
+		
+		transerror=True
+		
+		Return True
+	End Method
+
+		
+	Method ReadPipes(pipe:TPipeStream,errpipe:TPipeStream)
+		Local	status
+		Local	bytes:Byte[],line$
+
+		bytes=pipe.ReadPipe()
+		If bytes
+			Line$=String.FromBytes(bytes,Len bytes)
+			line=line.Replace(Chr(13),"")
+			If Not ProcessTransOutput(line)	'todo: if ismonkey only
+				Write line
+			EndIf
+		EndIf
+		
+		If errpipe.ReadAvail() Then
+			errbuffer.WriteFromPipe(errpipe)
+		Else
+			SendDumpRequests()
+		EndIf
+		
+'		If bytes Write String.FromBytes(bytes,bytes.length)
+		While errbuffer.LineAvail()
+			line$=errbuffer.ReadLine()
+			line=host.debugtree.ProcessError(line)
+			If line
+				Write line+"~n"
+				err:+line+"~n"
+			EndIf
+		Wend
+		
+	End Method
+	
+	Method WriteChar(char)
+		Local	pipe:TPipeStream
+				
+		If Not process Return		
+		pipe=process.pipe
+		If char=3			'CTRL-C
+			Stop()
+		EndIf
+		If char=13			'ENTER
+'			Write Chr(10)
+			pipe.WriteLine user$
+			user=""
+		EndIf
+		If char=8 And user.length			'DELETE
+'			Local pos=TextAreaLen(output)
+'			If pos SetTextAreaText output,"",pos-1,1,TEXTAREA_CHARS
+			user=user[..user.length-1]
+		EndIf
+		If char>31
+'			Write Chr(char)
+			user:+Chr(char)
+		EndIf
+	End Method
+		
+	Method Open()
+		If output Then
+			codeplay.SelectPanel Self
+			Return
+		EndIf
+		codeplay.addpanel(Self)		
+		output=CreateTextArea(0,0,ClientWidth(panel),ClientHeight(panel),panel,TEXTAREA_WORDWRAP)
+		SetGadgetLayout output,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED
+		SetGadgetFilter output,outputfilter,Self		
+		SetGadgetText output," "	'simon was here		
+		host.options.outputstyle.apply output,1,host.options.colorcontainers
+	End Method
+
+	Function CreateOutputMenu:TGadget()
+		Local	edit:TGadget = CreateMenu("Edit",0,Null)
+		CreateMenu "Cut",MENUCUT,edit
+		CreateMenu "Copy",MENUCOPY,edit
+		CreateMenu "Paste",MENUPASTE,edit
+		CreateMenu "",0,edit
+		CreateMenu "Stop",MENUSTOP,edit
+		Return edit
+	End Function
+
+	Function Create:TOutputPanel(host:TCodePlay)
+		Local	o:TOutputPanel = New TOutputPanel
+		o.host=host		
+		o.name="Output"
+		o.outputmenu=CreateOutputMenu()
+'		o.Open
+		Return o
+	End Function
+
+End Type
+
+Type TCodeNode Extends TNode
+	Field	owner:TOpenCode
+	Field	pos,count
+	'Field	groups:TMap=New TMap
+
+	Method Invoke(command,argument:Object=Null)
+		Select command
+			Case TOOLACTIVATE
+				owner.ShowPos(pos)
+		End Select
+	End Method
+
+	Method Sync(snap:TNode)	
+		If snap.name<>name SetName(snap.name)
+		Local	n:TCodeNode = TCodeNode(snap)
+		If n pos=n.pos;count=n.count
+		Super.Sync(snap)
+	End Method
+	
+	Method SetName(n$)
+		Local	p = n.find("'")
+		If p<>-1 n=n[..p]
+		name=n.Trim()
+'		If owner.host.options.sortcode
+		sortname=n
+	End Method
+	
+	Method Free()
+		owner = Null
+		Super.Free()
+	End Method
+	
+	Method AddCodeNode:TCodeNode(n$,p0,p1)
+		
+		Local t$
+		Local i:Int = n.find(" ")	'if space then group
+		
+		If i>0
+			t=n[..i]
+			n=n[i+1..]
+Rem
+			p=TNode(groups.ValueForKey(t))
+			If Not p
+				p=AddNode(t+"s")
+				p.Open
+				groups.insert t,p
+			EndIf
+EndRem
+		EndIf
+		
+		Local c:TCodeNode = New TCodeNode
+		c.owner=owner
+		c.setname n$
+		c.pos=p0
+		c.count=p1-p0
+		Append(c)
+		
+		Return c
+		
+	End Method
+End Type
+
+Type TDiff
+	Field	pos,count,del$,add$,pos0,count0,pos1,textchange = True
+End Type
+
+Type TOpenCode Extends TToolPanel
+		
+	Field host:TCodePlay
+	Field textarea:TGadget
+	Field dirty=True
+	Field filesrc$,cleansrc$,cleansrcl$
+	Field Current:TDiff
+	Field undolist:TList=New TList
+	Field redolist:TList=New TList
+	Field helpcmd$,helpstring$
+	Field seek$
+	Field cursorpos,cursorlen,cursorline
+	Field oldpos,oldlen
+	Field isbmx,isc,iscpp,ishtml,ismonkey
+	Field deferpos = -1
+	Field tidyqueue1 = -1, tidyqueue2 = -1
+	Field editmenu:TGadget
+	Field codenode:TCodeNode
+	Field dirtynode,uc
+	
+	Function IsNotAlpha(c)
+		If c<48 And c<>35 Return True
+		If c>=58 And c<65 Return True
+		If c>=91 And c<95 Return True
+		If c>=96 And c<97 Return True
+		If c>=123 Return True
+	End Function
+	
+	Function WordAtPos$(a$,p)
+		Local	c,q,r,n
+	' string literal
+		q=a.findlast(EOL$,a.length-p)
+		If q=-1 q=0
+		For q=q To p-1
+			If a[q]=34 Then
+				n=Not n
+				r=q
+			EndIf
+		Next
+		If n	
+			q=a.Find("~q",r+1)+1
+			If q=0 q=a.length
+			Return a[r..q]
+		EndIf
+	' alphanumeric
+		p=Min(p,a.length-1)	'simon was here - crash when checking at last char
+		For p=p Until 0 Step -1	'simon was here unto->to
+			If IsNotAlpha(a$[p]) Continue
+			Exit
+		Next
+		For q=p-1 To 0 Step -1
+			If IsNotAlpha(a$[q]) Exit
+		Next
+		For r=p To a.length-1
+			If IsNotAlpha(a$[r]) Exit
+		Next
+		Return a[q+1..r]
+	End Function
+	
+	Function FirstDiff(s0$,s1$)
+		Local	n = Min(s0.length,s1.length)
+		For Local i:Int = 0 Until n
+			If s0[i]<>s1[i] Return i
+		Next
+		Return n		
+	End Function
+	
+	Function LastDiff(s0$,s1$)
+		Local n = Min(s0.length,s1.length)
+		Local i = s0.length-1
+		Local j = s1.length-1
+		While n>0
+			If s0[i]<>s1[j] Exit
+			i:-1;j:-1;n:-1
+		Wend
+		Return i+1
+	End Function
+	
+	Method parsebmx(n:TCodeNode)
+		Local	src$,Line,col
+		Local	p,p1,r,t,m,f,l,e
+
+		src=cleansrcl
+		p1=src.length
+		p=-1;r=-1;t=-1;m=-1;f=-1;l=-1
+		While p<p1			'update rem,type,method,function,label pointers
+			While r<=p
+				r=FindToken("rem",src,r+1)
+			Wend
+			While t<=p
+				t=FindToken("type",src,t+1)
+			Wend
+			While m<=p
+				m=FindToken("method",src,m+1)
+			Wend
+			While f<=p
+				f=FindToken("function",src,f+1)
+			Wend
+			While l<=p
+				l=FindLabel(src,l+1)
+			Wend
+			If r<t And r<m And r<f And r<l
+				p=FindEndToken("rem",src,r+1,True)
+				Continue
+			EndIf
+			p=Min(t,Min(m,Min(f,l)))
+			If p=src.length Exit		
+			While (n And n.parent And p>n.pos+n.count)
+				If Not TCodeNode(n.parent)
+					If n.parent.parent
+						n = TCodeNode(n.parent.parent)
+					Else
+						n = Null
+					EndIf
+				Else
+					n=TCodeNode(n.parent)
+				EndIf
+			Wend
+			If t<m And t<f And t<l
+				e=src.find(EOL,t)
+				n=n.AddCodeNode(cleansrc[t..e],t,FindEndToken("type",src,t,True))
+				p=t+1
+				Continue
+			EndIf
+			If m<f And m<l
+				e=src.find(EOL,m)
+				n.AddCodeNode(cleansrc[m..e],m,e)
+				p=m+1
+				Continue
+			EndIf
+			If f<l
+				e=src.find(EOL,f)
+				n.AddCodeNode(cleansrc[f..e],f,e)
+				p=f+1
+				Continue		
+			Else
+				e=src.find(EOL,l)
+				n.AddCodeNode(cleansrc[l..e],l,e)
+				p=l+1
+				Continue				
+			EndIf
+		Wend
+	End Method
+
+	Method parsemonkey(root:TCodeNode)
+		Local src$,Line,col
+		Local p,p1,r,t,m,f,l,e
+		Local n:TCodeNode
+
+		n=root
+		src=cleansrcl
+		p1=src.length
+		p=-1;r=-1;t=-1;m=-1;f=-1;
+		l=p1
+		While p<p1			'update rem,type,method,function,label pointers
+			While r<=p
+				r=FindToken("#rem",src,r+1)
+			Wend
+			While t<=p
+				t=FindToken("class",src,t+1)
+			Wend
+			While m<=p
+				m=FindToken("method",src,m+1)
+			Wend
+			While f<=p
+				f=FindToken("function",src,f+1)
+			Wend
+			If r<t And r<m And r<f And r<l
+				p=FindToken("#end",src,r+1)
+				Continue
+			EndIf
+			p=Min(t,Min(m,Min(f,l)))
+			If p=src.length Exit		
+			If t<m And t<f And t<l
+				e=src.find(EOL,t)
+				n=root.AddCodeNode(cleansrc[t..e],t,p1)     'FindEndToken2("class",src,t,True))
+				p=t+1
+				Continue
+			EndIf
+			If m<f And m<l
+				e=src.find(EOL,m)
+				n.AddCodeNode(cleansrc[m..e],m,e)
+				p=m+1
+				Continue
+			EndIf
+			If f<l
+				e=src.find(EOL,f)
+				n.AddCodeNode(cleansrc[f..e],f,e)
+				p=f+1
+				Continue		
+			Else
+				e=src.find(EOL,l)
+				n.AddCodeNode(cleansrc[l..e],l,e)
+				p=l+1
+				Continue				
+			EndIf
+		Wend
+	End Method
+	
+	Method GetNode:TNode()
+		Local	root:TCodeNode = New TCodeNode
+		root.name = StripDir(path)
+		root.owner = Self
+		root.count = cleansrc.length
+		If isbmx parsebmx(root)
+		If ismonkey parsemonkey(root)
+		If codenode
+			If host.options.sortcode root.sortkids
+			codenode.Sync(root)	
+			root.Free()
+		Else
+			codenode=root
+		EndIf
+		Return codenode
+	End Method
+		
+	Method ShowPos(pos)
+		host.SelectPanel( Self )
+		Local line=TextAreaLine(textarea,pos)
+		SelectTextAreaText textarea,line,1,TEXTAREA_LINES		
+		UpdateCursor()
+		ActivateGadget( textarea )
+	End Method
+
+	Method Debug(Line,column)
+		If line>0 line:-1
+		SelectTextAreaText textarea,line,1,TEXTAREA_LINES		
+		UpdateCursor()
+	End Method
+
+	Method Edit()
+		SelectTextAreaText( textarea,cursorpos,0,TEXTAREA_CHARS )
+		ActivateGadget( textarea )
+		UpdateStatus()
+	End Method
+	
+	Method UpdateStatus()
+		Local	c = cursorpos+cursorlen
+		If cursorline Then c:-TextAreaChar(textarea,cursorline-1)
+		host.SetStatus helpstring+"~t~t"+"Line: "+cursorline+" Char: "+(c+1)
+	End Method
+	
+	Method UpdateCursor()
+		oldpos=cursorpos
+		oldlen=cursorlen
+		cursorpos=TextAreaCursor(textarea,TEXTAREA_CHARS)
+		cursorlen=TextAreaSelLen(textarea,TEXTAREA_CHARS)
+		If cursorpos<>oldpos Or cursorlen<>oldlen
+			Local l = TextAreaLine(textarea,cursorpos)+1
+			If l<>cursorline And dirtynode
+				GetNode().Refresh
+				dirtynode=False
+				If (deferpos>=0) UpdateCode	'SetCode cleansrc
+			EndIf
+			cursorline=l
+			UpdateStatus()
+			BracketMatching(cleansrcl)
+			If (tidyqueue1 >= 0 Or tidyqueue2 >= 0) Then UpdateCode()
+			PollSystem
+		EndIf
+	End Method
+
+' tdiff - pos del$ add$
+
+	Method CalcDiff:TDiff(src$)
+		Local	d:TDiff
+		If src.length<>cleansrc.length
+			d=New TDiff
+			d.pos0=cursorpos
+			d.count0=cursorlen
+			d.pos=oldpos
+			d.count=oldlen
+			If cursorlen And oldlen							'block modified
+				d.del=cleansrc[oldpos..oldpos+oldlen]
+				d.add=src[oldpos..cursorpos+cursorlen]
+				d.pos1=oldpos
+			Else
+				If cursorpos<=oldpos And cursorlen<=oldlen	'backspace
+					d.del=cleansrc[cursorpos..cursorpos+cleansrc.length-src.length]
+					d.pos1=cursorpos
+				Else										'insert
+					d.del=cleansrc[oldpos..oldpos+oldlen]
+					d.add=src[oldpos..cursorpos+cursorlen]
+					d.pos1=oldpos
+				EndIf
+			EndIf	
+		Else		
+			If cursorpos>oldpos									'overwrite
+				d=New TDiff
+				d.pos0=cursorpos
+				d.count0=cursorlen
+				d.pos=oldpos
+				d.count=oldlen
+				d.del=cleansrc[oldpos..cursorpos]
+				d.add=src[oldpos..cursorpos]
+				d.pos1=oldpos
+				If d.del = d.add Then d.textchange=False
+			EndIf
+		EndIf
+		Return d	
+	End Method
+
+	Method UpdateCode(makeundo=True)
+		Local cpos
+		Local src$ = TextAreaText(textarea)
+		Local d:TDiff = CalcDiff(src)
+		If d
+			If makeundo And d.textchange
+				undolist.AddLast d
+				redolist.Clear
+			EndIf
+			SetCode src,d
+			If d.textchange Then dirtynode=True
+		EndIf
+		If (deferpos >= 0) Or (tidyqueue1 >= 0) Or (tidyqueue2 >= 0) Then SetCode src
+	End Method
+	
+	Method Undo()
+		Local	d:TDiff
+		If undolist.IsEmpty() Return
+		d=TDiff(undolist.RemoveLast())
+		redolist.AddLast d
+		SetTextAreaText textarea,d.del,d.pos1,d.add.length
+		SelectTextAreaText(textarea,d.pos,d.count)
+		SetCode TextAreaText(textarea),d
+		UpdateCursor
+	End Method
+
+	Method Redo()
+		Local	d:TDiff
+		If redolist.IsEmpty() Return
+		d=TDiff(redolist.RemoveLast())
+		undolist.AddLast d
+		SetTextAreaText textarea,d.add,d.pos,d.del.length
+		SelectTextAreaText(textarea,d.pos0,d.count0)
+		UpdateCursor
+		SetCode TextAreaText(textarea),d
+	End Method
+	
+	Method RefreshContainers()
+		Local rgb:TColor
+		If ismonkey
+			rgb=host.options.editcolor2
+		Else
+			rgb=host.options.editcolor1
+		EndIf
+		If host.options.colorcontainers
+			SetContainerColor textarea,rgb,1 
+		Else
+			SetContainerColor textarea,Null,1 
+		EndIf
+	End Method
+		
+	Method RefreshStyle()
+	
+		Local rgb:TColor
+		Local charwidth=host.options.editfont.CharWidth(32)
+		
+		SetTextAreaTabs textarea,host.options.tabsize*charwidth
+		SetTextAreaFont textarea,host.options.editfont
+		
+		If ismonkey
+			rgb=host.options.editcolor2
+		Else
+			rgb=host.options.editcolor1
+		EndIf
+		SetTextAreaColor textarea,rgb.red,rgb.green,rgb.blue,True
+	
+	End Method
+
+	Method Refresh()
+		Local rgb:TColor
+		Local src$
+		RefreshStyle
+		RefreshContainers
+		rgb=host.options.styles[0].Color
+		SetTextAreaColor textarea,rgb.red,rgb.green,rgb.blue,False
+		src=cleansrc
+		cleansrc=""
+		cleansrcl=""
+		cursorpos=0
+		SetCode(src)
+	End Method
+
+	Function IsntAlphaNumeric(c)		'lowercase test only
+		If c=35 Return False '# is now special
+		If c<48 Return True
+		If c>=58 And c<95 Return True
+		If c=96 Return True
+		If c>=123 Return True
+	End Function
+	
+	Function IsntAlphaNumericOrQuote(c)		'lowercase test only
+		If c=35 Return False '# is now special
+		If c=34 Return False
+		If c<48 Return True
+		If c>=58 And c<95 Return True
+		If c=96 Return True
+		If c>=123 Return True
+	End Function
+
+	Function IsCode(src$,p)
+		Local n
+		Local l = src.FindLast(EOL$,src.length-p)
+		If l=-1 l=0
+		Local q = src.Find("'",l)
+		If q<>-1 And q<p Return
+		q=l
+		While q<p
+			q=src.Find(QUOTES$,q)+1
+			If q=0 Exit
+			If q<=p n:+1
+		Wend
+		Return Not(n&1)
+	End Function
+
+	Function FindLabel(src$,pos)
+		Local	p,q,c
+		While pos>=0
+			p=src.Find("#",pos)
+			If p=-1 Exit
+			q=p
+			While q>0
+				q:-1
+				c=src[q]
+				If c=13 Return p
+				If c=10 Return p
+				If c=32 Or c=9 Continue
+				Exit
+			Wend
+			If q<0 Return p
+			pos=p+1
+		Wend
+		Return src.length	
+	End Function
+	
+	Function FindToken(token$,src$,pos)	'lowercase src only!
+		Local p,c
+		Local n=token.length
+		While pos>=0
+			p=src.Find(token,pos)
+			If p=-1 Exit
+			c=10 If p>0 c=src[p-1]
+			If isntalphanumeric(c)
+				If p+n<src.length c=src[p+n]
+				If isntalphanumeric(c)
+					If iscode(src,p)
+						If p<4 Or src[p-4..p]<>"end " Return p
+					EndIf
+				EndIf
+			EndIf
+			pos=p+1
+		Wend
+		Return src.length
+	End Function
+
+	Function FindEndToken(token$,src$,pos,returnlast=False)	'if true returns first character after endtoken
+		Local	p,q,e$,n
+		
+		p=pos
+		e$="end"+token
+		n=e.length
+		While p<src.length
+			p=src.Find(e$,p)
+			If p=-1 Exit
+			If p+n=src.length Or isntalphanumeric(src[p+n])
+				If iscode(src,p)
+					If p=0 Or isntalphanumeric(src[p-1]) Exit
+				EndIf
+			EndIf
+			p=p+n
+		Wend
+		If p=-1 p=src.length Else If returnlast p:+n
+		q=pos
+		e$="end "+token
+		n=e.length
+		While q<src.length
+			q=src.Find(e$,q)
+			If q=-1 Exit
+			If q+n=src.length Or isntalphanumeric(src[q+n])
+				If iscode(src,q)
+					If q=0 Or isntalphanumeric(src[q-1]) Exit
+				EndIf
+			EndIf
+			q=q+n
+		Wend
+		If q=-1 q=src.length Else If returnlast q:+n
+		Return Min(p,q)
+	End Function
+
+' class,method,function,
+' if,for,while,repeat
+' endif,next,wend,until,forever
+
+	Function FindEndToken2(token$,src$,pos,returnlast=False)
+		Local	p,q,e$,n
+		
+		p=pos
+		e$="end"+token
+		n=e.length
+		While p<src.length
+			p=src.Find(e$,p)
+			If p=-1 Exit
+			If p+n=src.length Or isntalphanumeric(src[p+n])
+				If iscode(src,p)
+					If p=0 Or isntalphanumeric(src[p-1]) Exit
+				EndIf
+			EndIf
+			p=p+n
+		Wend
+		If p=-1 p=src.length Else If returnlast p:+n
+		q=pos
+		e$="end "+token
+		n=e.length
+		While q<src.length
+			q=src.Find(e$,q)
+			If q=-1 Exit
+			If q+n=src.length Or isntalphanumeric(src[q+n])
+				If iscode(src,q)
+					If q=0 Or isntalphanumeric(src[q-1]) Exit
+				EndIf
+			EndIf
+			q=q+n
+		Wend
+		If q=-1 q=src.length Else If returnlast q:+n
+		Return Min(p,q)
+	End Function
+
+
+	Function IsFirstCharOnLine(src$,pos)
+		Local	c
+		For Local i:Int = 1 To pos
+			c=src[pos-i]
+			If c=10 Or c=13 Return True
+			If c>32 Return False
+		Next
+		Return True
+	End Function
+
+' rem and endrem must be first nonwhitespace on line - following funcs are for lowercase src only
+
+	Method FindRem(src$,pos)
+		Local remtoken$
+		DebugStop
+		If ismonkey remtoken="#rem" Else remtoken="rem" 
+		While pos<src.length
+			pos=FindToken(remtoken,src,pos)
+			If pos=src.length Exit
+			If IsFirstCharOnLine(src,pos) Return pos
+			pos:+1
+		Wend
+		Return pos
+	End Method
+
+	Method FindEndRem(src$,pos,returnlast=False)
+		Local	i,c		
+		Local remtoken$
+		If ismonkey 
+			While pos<src.length
+				pos=FindToken("#end",src,pos)
+				If pos=src.length Exit
+				If IsFirstCharOnLine(src,pos)
+					If returnlast
+						pos:+4
+					EndIf
+					Return pos
+				EndIf
+				pos:+1
+			Wend		
+		Else		
+			While pos<src.length
+				pos=FindEndToken("rem",src,pos)
+				If pos=src.length Exit
+				If IsFirstCharOnLine(src,pos)
+					If returnlast
+						If src[pos+5]=Asc("e") Or src[pos+5]=Asc("E") pos:+1
+						pos:+6
+					EndIf
+					Return pos
+				EndIf
+				pos:+1
+			Wend
+		EndIf
+		Return src.length
+	End Method
+
+	Method FindPrevRem(src$,pos)	'lowercase src only!
+		Local p,c
+		Local remtoken$
+		If ismonkey remtoken="#rem" Else remtoken="rem" 
+		While pos>0
+			If pos>src.length Exit	'fixed endrem on lastline overrun
+			p=src.FindLast(remtoken,src.length-pos)
+			If p=-1 Exit						
+			If ismonkey And IsFirstCharOnLine(src,p) Return p			
+			If isntalphanumeric(src[p+3]) And IsFirstCharOnLine(src,p) Return p			
+			pos=p-1
+		Wend
+		Return -1
+	End Method
+	
+	Method IsRemmed(pos,src$)
+		Local p = FindPrevRem(src$,Min(pos+3,src.length))
+		If p<0 Return
+		p=FindEndRem(src$,p)
+		If p<0 Or pos<p Return True
+	EndMethod
+	
+	Method WasRemmed(pos,src$)
+		Local s$ = cleansrcl
+		Local p = (src.length-s.length)
+		If p<0 pos:-p
+		p=FindPrevRem(s$,Min(pos+3,s.length))
+		If p<0 Return
+		p=FindEndRem(s$,p)
+		If pos<p Return True
+	End Method
+
+	Method CheckDirty(src$)
+		SetDirty (Not (src=filesrc And undolist.IsEmpty()))
+	End Method
+	
+	Method HasTidyQueue()
+		Return ((deferpos >= 0) Or (tidyqueue1 >= 0) Or (tidyqueue2 >= 0))
+	EndMethod
+	
+	Method ClearTidyQueue(start,endpos)
+		If start<=deferpos And deferpos < endpos Then deferpos = -1
+		If start<=tidyqueue1 And tidyqueue1 < endpos Then tidyqueue1 = -1
+		If start<=tidyqueue2 And tidyqueue2 < endpos Then tidyqueue2 = -1
+	EndMethod
+	
+	Method SetCode(src$,diff:TDiff=Null)
+		Local	same,i,p,startp,p1,q,r,a,n,t$,h$,lsrc$,r0,r1,cpos,autocap
+		Local	style:TTextStyle[5],s:TTextStyle
+' update dirty flag	
+		CheckDirty src
+		same = Not ((diff) Or (src<>cleansrc))
+		If same And Not (diff Or HasTidyQueue()) Then Return	
+		If (Not isbmx And Not ismonkey) Or Not host.options.syntaxhighlight	'Or Not host.quickhelp
+			If Not same Then
+				cleansrc=src
+				cleansrcl=src.ToLower()
+			EndIf
+			Return
+		EndIf
+' doit
+		autocap=host.options.autocapitalize
+		If same Then lsrc = cleansrcl Else lsrc=src.ToLower()
+		cpos=TextAreaCursor(textarea,TEXTAREA_CHARS)
+		LockTextArea textarea
+		style=host.options.styles
+' calculate highlight region
+		
+		If diff
+			p=diff.pos
+			p1=p+diff.add.length
+			If Not diff.add.length Then
+				p:-diff.del.length
+			EndIf
+		ElseIf HasTidyQueue()
+			p=src.length
+			If (deferpos>=0) Then
+				p = Min(p,deferpos)
+				p1 = Max(p1,deferpos+1)
+			EndIf
+			If (tidyqueue1>=0) Then
+				p = Min(p,tidyqueue1)
+				p1 = Max(p1, tidyqueue1+1)
+			EndIf
+			If (tidyqueue2>=0) Then
+				p = Min(p,tidyqueue2)
+				p1 = Max(p1, tidyqueue2+1)
+			EndIf
+		Else
+			p=firstdiff(src,cleansrc)
+			p1=lastdiff(src,cleansrc)
+		EndIf
+		q=src.length-cleansrc.length
+		If p1-p<q p1=p+q
+		If p1<p p1=p
+		
+' round region to line breaks
+		'Print "p="+p+" p1="+p1
+		If p>src.length p=src.length
+		p=src.findlast(EOL,src.length-(p-1))+1
+		p1=src.find(EOL,p1)+1
+		If p1=0 p1=src.length
+' if endrem between p0,p1 and next rem after p1 move p1 forwards
+		r1=FindEndRem(lsrc,p)
+		If r1<p1 And wasremmed(r1+6,lsrc)
+			r0=FindRem(lsrc,r1+6)
+			If r0>p1 p1=r0
+		EndIf
+' if rem between p0,p1 and matching endrem after p1 move p1 forewards
+		r0=FindPrevRem(lsrc,p1)
+		If r0>=p And r0+3<>cpos	'defer fix
+			r1=FindEndRem(lsrc,r0,True)
+			If r1>p1 p1=r1
+		EndIf
+' if rem before p0 and matching endrem after p0 highlight to endrem and move p0 forwards
+		r0=FindPrevRem(lsrc,p)
+		If r0<>-1 And r0<p
+			r1=FindEndRem(lsrc,r0,True)
+			If r1>p
+				s=style[COMMENT]
+				If r1>p s.Format(textarea,p,r1-p)
+				If autocap And r1<src.length
+					If lsrc[r1-6..r1]="endrem" And src[r1-6..r1]<>"EndRem" SetTextAreaText textarea,"EndRem",r1-6,6
+					If lsrc[r1-7..r1]="end rem" And src[r1-7..r1]<>"End Rem" SetTextAreaText textarea,"End Rem",r1-7,7
+				EndIf
+				ClearTidyQueue(p,r1)
+				p=r1
+			EndIf
+		EndIf	
+' if was remmed and now isn't move p1 down to nearest rem or endrem
+		If WasRemmed(p,lsrc)
+			r0=FindRem(lsrc,p)
+			r1=FindEndRem(lsrc,r0,True)
+			p1=Max(p1,Min(r0,r1))	
+		EndIf
+' highlight code
+		ClearTidyQueue(p,p1)
+		
+		s=style[NORMAL]
+		If p1>p s.format(textarea,p,p1-p)
+		startp = p
+		
+		While p<p1
+			a=src[p]
+' quoted strings
+			If a=34
+				q=p1
+
+' use a quotecount to block unformed string tokenizing				
+				n=src.Find(EOL,p+1)
+				If n>p1 n=p1
+				Local quotecount=0
+				For Local odd=p Until n
+					If src[odd]=34 quotecount:+1
+				Next
+				
+				r=src.Find(Chr(34),p+1)
+' closing quote to 
+				If r>-1 And r<q And (quotecount&1=0) q=r+1
+
+				r=src.Find(EOL,p+1)
+				If r>-1 And r<q q=r
+
+				s=style[QUOTED]
+				s.format(textarea,p,q-p)
+				p=q
+				Continue
+			EndIf
+' single line comments
+			If a=39
+				q=p1
+				r=src.Find(EOL,p+1)
+				If r>-1 And r<q q=r
+				s=style[COMMENT]
+				s.format(textarea,p,q-p)
+				p=q
+				Continue				
+			EndIf
+' tokens
+			If (a>=65 And a<91) Or (a>=97 And a<123) Or (a=95) Or (a=35) '# now valid
+				q=p+1
+				While q<p1
+					a=src[q]
+					If a<48 And a<>35 Exit	'changed to include dot (chr 47)
+					If a>=58 And a<65 Exit
+					If a>=91 And a<95 Exit
+					If a=96 Exit
+					If a>122 Exit
+					q:+1
+				Wend
+				t$=src[p..q]
+				Local remtoken$="Rem"
+				If isbmx And host.quickhelp h$=host.quickhelp.token(t$)
+				If ismonkey h$=host.monkeyhelp.token(t$);remtoken="#rem"
+				If h$
+					If h$<>t$ And autocap 'And isbmx
+						If cpos<p Or cpos>q
+							SetTextAreaText textarea,h,p,h.length
+						Else
+							deferpos=q
+						EndIf
+					EndIf
+					s=style[KEYWORD]
+					If h$=remtoken And IsFirstCharOnLine(lsrc,p)	' Not (p>4 And lsrc[p-4..p]="End ")
+						If q<>cpos
+							q=FindEndRem(lsrc,p,True)
+							s=style[COMMENT]
+						Else
+							deferpos=q
+						EndIf						
+					EndIf
+					s.format(textarea,p,q-p)
+				EndIf
+				p=q
+				Continue
+			EndIf
+' numbers
+			If (p=0 Or IsntAlphaNumeric(lsrc[p-1])) And ((a>=$30 And a<$3A) Or (a=$24) Or (a=$25) Or (a=$2E))	'0-9, $, %, .
+				q=p+1
+				Local hexed:Int = (a=$24), binaried:Int = (a=$25), dots:Int = (a=$2E)
+				Local valid:Int = Not(hexed Or binaried Or dots)
+				
+				While q<(p1)
+					a=lsrc[q]
+					q:+1
+					If (a>=$30 And a<$3A) Then
+						valid = True
+						Continue	'0-9
+					EndIf
+					If hexed
+						If (a>=$61 And a<$67) Then	'a-f (only test lower as 'a' var is from lsrc)
+							valid = True
+							Continue
+						EndIf
+					EndIf
+					If (a=$2E) Then
+						'Hex or Binary literals don't support decimal points
+						If Not (hexed Or binaried) Then
+							dots:+1
+							'Fix for slicing '..' syntax
+							If src[q-2] = $2E Then
+								dots:-2
+								q:-2
+								Exit
+							EndIf
+							'End Fix
+							Continue
+						EndIf
+					EndIf
+					If Not IsntAlphaNumeric(a) Then valid = False
+					q:-1
+					Exit
+				Wend
+				If valid And dots < 2 Then style[NUMBER].format(textarea,p,(q-p))
+				'Fix for slicing '..' syntax
+				If q<src.length And (src[q]=Asc(".")) Then q:+1
+				If q<src.length And (src[q]=Asc(".")) Then q:+1
+				'End Fix
+				p=q
+				Continue
+			EndIf
+			p:+1
+		Wend
+		BracketMatching(lsrc,startp,p1,True)
+		UnlockTextArea textarea
+		If Not same
+			cleansrc=src
+			cleansrcl=lsrc
+		EndIf
+'		CheckDirty src	simon was here
+	End Method
+	
+	Field currentbrackets:Int[]
+	
+	Method BracketMatching(lsrc$,cln1=-1,cln2=-1,alwaysfind:Int = False)
+		
+		Local check:Int, depth:Int, style:TTextStyle[] = host.options.styles
+		Local otherchar:Int = 0, absotherchar:Int = 0, othercharpos:Int = 0, limit:Int
+		Local currentchar:Int = 0, currentcharpos:Int = Max(cursorpos-1,0)
+		
+		If cursorlen Then Return
+		
+		If currentbrackets Then
+			If Not(cln2 > currentbrackets[0] And cln1 <= currentbrackets[0]) Then
+				If currentbrackets[0]>-1 Then tidyqueue1 = currentbrackets[0]
+			EndIf
+			If Not(cln2 > currentbrackets[1] And cln1 <= currentbrackets[1]) Then
+				If currentbrackets[1]>-1 Then tidyqueue2 = currentbrackets[1]
+			EndIf
+			currentbrackets = Null
+			If Not alwaysfind Then Return
+		EndIf
+		
+		If host.options.bracketmatching And isbmx And Not IsRemmed(currentcharpos,lsrc) Then
+			
+			limit = Min(lsrc.length,currentcharpos+2)
+			
+			While currentcharpos >= 0 And currentcharpos < limit
+				If IsCode(lsrc,currentcharpos) Then
+					Select lsrc[currentcharpos]
+						Case Asc("(");otherchar = Asc(")");Exit
+						Case Asc("{");otherchar = Asc("}");Exit
+						Case Asc("[");otherchar = Asc("]");Exit
+						' Negate char code to search backwards
+						Case Asc(")");otherchar = -Asc("(");Exit
+						Case Asc("}");otherchar = -Asc("{");Exit
+						Case Asc("]");otherchar = -Asc("[");Exit
+					EndSelect
+				EndIf
+				currentcharpos:+1
+			Wend
+			
+			If otherchar Then
+				
+				absotherchar = (Abs otherchar)
+				currentchar = lsrc[currentcharpos]
+				
+				LockTextArea textarea
+				style[MATCHING].format(textarea, currentcharpos, 1)
+				currentbrackets = [currentcharpos,-1]
+				
+				othercharpos =  currentcharpos+(otherchar/absotherchar)
+				
+				While othercharpos < lsrc.length And othercharpos >= 0
+					
+					If IsCode(lsrc,othercharpos) Then
+						Select lsrc[othercharpos]
+							Case Asc(" "), Asc("~t")
+								'Do nothing
+							Case Asc("'")
+								Exit
+							Case absotherchar
+								If check < 0 Then Exit Else check = 0
+								If depth Then
+									depth:-1
+								Else
+									style[MATCHING].format(textarea, othercharpos, 1)
+									currentbrackets[1] = othercharpos
+									UnlockTextArea textarea
+									Return
+								EndIf
+							Case Asc("~n")
+								If (otherchar/absotherchar) > 0 Then
+									If check = 2 Then check = 0 Else Exit
+								Else
+									If check < 0 Then Exit Else check = -2
+								EndIf
+							Case Asc(".")	
+								check:+1
+							Default
+								If check < 0 Then Exit Else check = 0
+								If lsrc[othercharpos] = lsrc[currentcharpos] Then depth:+1
+						EndSelect
+					EndIf
+					
+					othercharpos:+(otherchar/absotherchar)
+					
+				Wend
+				
+				UnlockTextArea textarea
+				
+			EndIf
+			
+		EndIf
+		
+	EndMethod
+	
+	Method AutoIndent()
+		Local	p,q
+		Local c = TextAreaCursor(textarea,TEXTAREA_CHARS)
+		Local n = TextAreaSelLen(textarea,TEXTAREA_CHARS)
+		If c<cleansrc.length
+			p=cleansrc.FindLast(EOL,cleansrc.length-(c-1))+1
+			q=p
+			While cleansrc[q]=9 And q<c
+				q:+1
+			Wend
+			If q>c q=c
+		EndIf
+		SetTextAreaText textarea,EOL$+cleansrc[p..q],c,n
+		SelectTextAreaText textarea,c+1+q-p,0			
+		UpdateCursor
+		UpdateCode
+	End Method
+	
+	Method IndentCode()
+		Local	a$
+' blockindent
+		Local p0 = TextAreaCursor(textarea,TEXTAREA_LINES)
+		Local p1 = TextAreaSelLen(textarea,TEXTAREA_LINES)
+' v122: make sure the entire block is selected (start cursor pos may in the middle of the line)
+		SelectTextAreaText textarea , p0 , p1 , TEXTAREA_LINES
+		UpdateCursor
+		For Local i:Int = 0 Until p1
+			a$="~t"+TextAreaText(textarea,p0+i,1,TEXTAREA_LINES)
+			SetTextAreaText textarea,a$,p0+i,1,TEXTAREA_LINES
+		Next
+		SelectTextAreaText textarea,p0,p1,TEXTAREA_LINES
+		UpdateCursor
+		UpdateCode
+	End Method
+
+	Method OutdentCode()
+		Local	a$,modified
+' blockoutdent
+		Local p0 = TextAreaCursor(textarea,TEXTAREA_LINES)
+		Local p1 = TextAreaSelLen(textarea,TEXTAREA_LINES)
+' v122: make sure the entire block is selected (start cursor pos may in the middle of the line)
+		SelectTextAreaText textarea , p0 , p1 , TEXTAREA_LINES
+		UpdateCursor
+		For Local i:Int = 0 Until p1
+			a$=TextAreaText(textarea,p0+i,1,TEXTAREA_LINES)
+			If a[0]=9 a$=a$[1..];modified=True
+			SetTextAreaText textarea,a$,p0+i,1,TEXTAREA_LINES
+		Next
+		If Not modified
+			For Local i:Int = 0 Until p1
+				a$=TextAreaText(textarea,p0+i,1,TEXTAREA_LINES)
+				If a[0]=32 a$=a$[1..]
+				SetTextAreaText textarea,a$,p0+i,1,TEXTAREA_LINES
+			Next	
+		EndIf
+		SelectTextAreaText textarea,p0,p1,TEXTAREA_LINES
+		UpdateCursor
+		UpdateCode
+	End Method
+
+	Function FilterKey(event:TEvent,context:Object)
+'		If event.id<>EVENT_KEYCHAR Return 1
+		Local id=event.id
+		Local key=event.data
+		Local mods=event.mods
+		Local this:TOpenCode=TOpenCode(context)
+?MacOS
+		If key=25 And mods=MODIFIER_SHIFT key=KEY_TAB
+?
+		If id=EVENT_KEYCHAR And this And key=KEY_TAB And TextAreaSelLen( this.textarea,TEXTAREA_CHARS )
+			Select mods
+				Case MODIFIER_NONE
+					this.IndentCode
+				Case MODIFIER_SHIFT
+					this.OutdentCode
+			End Select
+			Return 0
+		EndIf
+
+		If id=EVENT_KEYDOWN And key=KEY_ENTER And this And this.host.options.autoindent
+			this.AutoIndent()
+			Return 0
+		EndIf
+		
+		Return 1
+	End Function
+
+	Method OnEvent()
+ 		Select EventSource()
+			Case textarea
+				Select EventID()
+					Case EVENT_GADGETMENU
+						PopupWindowMenu host.window,editmenu
+					Case EVENT_GADGETACTION
+						UpdateCode
+					Case EVENT_GADGETSELECT
+						UpdateCursor
+				End Select
+		End Select
+	End Method
+			
+	Method SetDirty( bool )
+		If dirty=bool Return
+		dirty=bool
+		name=StripDir(path)
+		If (dirty) name:+"*"
+		If (host.lockedpanel=Self) name="build:"+name
+		host.RefreshPanel Self
+		PollSystem
+	End Method
+	
+	Method SetLocked( bool )
+		Local locked:TOpenCode = TOpenCode(host.lockedpanel)
+		If locked And locked<>Self locked.SetLocked False
+		name=StripDir(path)
+		If (dirty) name:+"*"
+		If (bool)
+			name="build:"+name
+			host.lockedpanel=Self
+		Else
+			host.lockedpanel=Null
+		EndIf
+		host.RefreshPanel Self
+	End Method
+	
+	Method Help()
+		If isbmx And Not host.quickhelp Return
+		If ismonkey And Not host.monkeyhelp Return
+		Local p = TextAreaCursor(textarea,TEXTAREA_CHARS)
+		Local a$ = WordAtPos(cleansrc,p)
+		
+		helpcmd=a	' quick help disabled in monk, straight to real help
+		
+		If a=helpcmd
+			
+			Local l$
+			If isbmx 
+				l$ = host.quickhelp.link(a$)
+				If l
+					host.helppanel.go host.bmxpath+l$
+				EndIf
+			EndIf
+			If ismonkey 
+				l$ = host.monkeyhelp.link(a$)				
+				If l<>"" host.helppanel.go l$
+			EndIf
+		Else
+			helpcmd=a$
+			If isbmx helpstring$=host.quickhelp.help(a$)
+			If ismonkey helpstring$=host.monkeyhelp.help(a$)
+			UpdateStatus	'host.setstatus helpstring$
+		EndIf
+	End Method
+
+	Method Find()
+		Local p=TextAreaCursor(textarea,TEXTAREA_CHARS)
+		Local term$=""
+		If cleansrc[p]<>32 term=WordAtPos(cleansrc,p)
+		host.findreq.ShowFind term
+	End Method
+		
+	Method FindNext(s$)
+		If s seek=s Else s=seek
+		Local p = TextAreaCursor(textarea,TEXTAREA_CHARS)
+		p:+TextAreaSelLen(textarea,TEXTAREA_CHARS)
+' case insensitive
+		Local l$ = s.toLower()
+		p=cleansrcl.Find(l$,p)
+		If p=-1 p=cleansrcl.Find(l$)
+' case sensitive
+'		p=cleansrc.Find(s$,p+1)
+'		if p=-1 p=cleansrc.Find(s$)
+		If p=-1
+			Notify "Could not find '"+s+"'."
+			Return False
+		Else
+			SelectTextAreaText textarea,p,Len s,TEXTAREA_CHARS
+			UpdateCursor
+			Return True
+		EndIf
+	End Method
+
+	Method ReplaceAll(s$,r$)
+		Local t$ = TextAreaText( textarea ).ToLower()
+		Local c = TextAreaCursor(textarea,TEXTAREA_CHARS),i,p
+		s = s.ToLower()
+		Repeat
+			Local i2=t.Find( s,i )
+			If i2=-1 Exit
+			p:+i2-i
+			i=i2+s.length
+			SelectTextAreaText textarea,p,s.length
+			UpdateCursor
+			UpdateCode		
+			SetTextAreaText textarea,r,p,s.length
+			If p<c c=c+r.length-s.length			
+			p:+r.length
+			SelectTextAreaText textarea,p,0
+			UpdateCursor
+			UpdateCode
+		Forever
+		SelectTextAreaText textarea,c,0
+		UpdateCursor
+	End Method
+	
+	Method FindReplace(r$)
+		Local n, f$, x$
+		Local p = r.Find("~0")
+		If p>0
+			f$=r[..p]
+			r$=r[p+1..]
+			ReplaceAll f$,r$
+		Else
+			p=TextAreaCursor(textarea,TEXTAREA_CHARS)
+			n=TextAreaSelLen(textarea,TEXTAREA_CHARS)
+			If Not n Return
+			SetTextAreaText textarea,r$,p,n
+			SelectTextAreaText textarea,p+r.length,0
+			UpdateCursor
+			UpdateCode		
+		EndIf
+		Return True
+	End Method
+	
+	Method ReadSource(path$)
+		Local	src$		
+		src=CacheAndLoadText(path)
+		src=src.Replace(Chr(13),"")
+		src=src.Replace(Chr(11),"")
+		LockTextArea textarea
+		SetTextAreaText textarea,src
+		UnlockTextArea textarea
+		filesrc=TextAreaText(textarea)
+		cleansrc=""
+		cleansrcl=""
+		ActivateGadget textarea		
+	End Method
+	
+	Method SaveSource(file$)
+		If host.options.autobackup
+			DeleteFile file+".bak"
+			RenameFile file,file+".bak"
+		EndIf
+		Local src$ = TextAreaText(textarea)
+
+Rem
+		If ismonkey	'new non-ascii strip search monkey patrol
+			Local i
+			Local notascii
+			For i=0 Until src.Length
+				If src[i]>127 Or src[i]<0 
+					notascii=True
+				EndIf
+			Next
+			If notascii And Confirm("Strip non-ascii characters found in~n"+file+"?")
+				For i=0 Until src.Length
+					If src[i]>127 Or src[i]<0 
+						src=src.Replace(src[i..i+1]," ")
+					EndIf
+				Next
+
+				LockTextArea textarea
+				SetTextAreaText textarea,src
+				UnlockTextArea textarea
+
+			EndIf
+			
+		EndIf
+EndRem
+
+		filesrc=src
+		src=src.Replace(Chr(13),Chr(10))
+		src=src.Replace(Chr(11),"")
+		Local txt$ = src.Replace$(Chr(10),Chr(13)+Chr(10))		
+
+' let archiver back up old
+		If host.history
+			Local pathdata:Object[2]
+			pathdata[0]=path
+			pathdata[1]=txt
+			host.history.Invoke TOOLARCHIVE,pathdata
+		EndIf
+		
+		Try
+			SaveText txt,file
+		Catch exception:Object
+			Local err$=String(exception)
+			Notify "Save Error~n"+err
+			Return False
+		EndTry
+				
+		path=host.FullPath$(file)
+		dirty=True
+		SetDirty False
+		host.AddRecent(path$)
+		Return True
+	End Method
+
+	Method BuildSource(quick,debug,threaded,gui,run)
+		Local cmd$,out$,arg$		
+		
+		If ismonkey
+			host.monkeyreq.ShowMonkey path,run,debug
+			Return
+		Else If isbmx Or isc Or iscpp
+			cmd$=quote(host.bmkpath)
+			cmd$:+" makeapp"
+			If run cmd$:+" -x"
+			If debug cmd$:+" -d" Else cmd$:+" -r"	'-v
+			If threaded cmd$:+" -h"
+			If gui cmd$:+" -t gui"
+			If Not quick cmd$:+" -a"
+			If debug Or threaded
+				out=StripExt(host.FullPath(path))
+				If debug out:+".debug"
+				If threaded out:+".mt"
+				cmd:+" -o "+quote(out$)+" "
+			EndIf		
+			cmd$:+" "+quote(host.FullPath(path))
+			If run
+				arg$=host.GetCommandLine()
+				If arg cmd$:+" "+arg
+			EndIf
+			host.execute cmd,"Building "+StripExt(StripDir(path))	',exe$
+		Else
+			If ishtml
+				host.helppanel.Go "file://"+path
+			Else
+'see what the system shell thinks of the file
+				Local cd$=CurrentDir()
+				ChangeDir ExtractDir(path)
+				cmd=StripDir(path)
+				host.execute cmd,"Building "+cmd
+				ChangeDir cd
+			EndIf			
+		EndIf
+'		print cmd
+	End Method
+	
+	Method Save()
+		Local	file$ = path
+		If host.IsTempPath(path)
+			file=RequestFile("Save As",FileTypeFilters,True,"")
+			If file="" Return False
+			If ExtractExt(file)="" file=file+".monkey"		'".bmx"
+			dirty=True
+		EndIf
+		If dirty SaveSource(file)
+		Return True
+	End Method
+' common command interface
+
+	Method Invoke(command,argument:Object=Null)
+		Local	file$,ex$
+		Local	p,res
+		Select command
+			Case TOOLSHOW
+				host.SetCodeNode GetNode()
+				host.SetTitle path				
+				If textarea 
+					ActivateGadget textarea				
+					RefreshContainers
+				EndIf
+			Case TOOLCLOSE
+				If dirty 'Or host.IsTempPath(path)
+					Invoke(TOOLSHOW)
+					p=Proceed("Save changes to "+name+"?")	'the current file?
+					If p=-1 Return True
+					If p=1
+						If Not Save() Return True
+					EndIf
+				EndIf
+				If codenode Then
+					codenode.Free()
+					codenode=Null
+				EndIf
+				'Added just in case MaxGUI driver doesn't handle properly.
+				SetGadgetFilter textarea,Null,Null
+				'Seb gone.
+				host.RemovePanel Self
+				FreeGadget(editmenu)
+			Case TOOLSAVE
+				Save
+			Case TOOLQUICKSAVE
+				file=path
+				If dirty SaveSource(file)
+			Case TOOLSAVEAS
+				file=path
+				If host.IsTempPath(path) file$=""
+				file=RequestFile("Save As",FileTypeFilters,True,file)
+				If file="" Return
+				ex$=ExtractExt(file)
+				If ex$=""
+					file=file+".monkey"
+					ismonkey=True
+				Else
+					If host.bmxpath isbmx=(ex.ToLower()="bmx")
+					ishtml=(ex.ToLower()="html")
+					isc=(ex.ToLower()="c")
+					iscpp=(ex.ToLower()="cpp" Or ex.ToLower()="cxx")
+					ismonkey=(ex.ToLower()="monkey")
+				EndIf				
+				SaveSource(file$)
+				Refresh()
+				GetNode().Refresh
+				SetDirty False
+				host.SetTitle path
+			Case TOOLGOTO
+				Local Line=Int(String(argument))
+				SelectTextAreaText textarea,Line-1,0,TEXTAREA_LINES				
+				UpdateCursor
+				ActivateGadget textarea		
+			Case TOOLFIND
+				Find
+			Case TOOLFINDNEXT
+				Return FindNext(String(argument))
+			Case TOOLREPLACE
+				Return FindReplace(String(argument))	
+			Case TOOLBUILD
+				BuildSource host.quickenabled,host.debugenabled,host.threadedenabled,host.guienabled,False
+			Case TOOLRUN
+				BuildSource host.quickenabled,host.debugenabled,host.threadedenabled,host.guienabled,True
+			Case TOOLLOCK
+				SetLocked True
+			Case TOOLUNLOCK
+				SetLocked False			
+			Case TOOLHELP
+				Help()
+			Case TOOLUNDO
+				Undo()
+			Case TOOLREDO
+				Redo()
+			Case TOOLREFRESH
+				Refresh()
+			Case TOOLCUT
+				GadgetCut textarea
+				UpdateCursor()
+				UpdateCode()
+			Case TOOLCOPY
+				GadgetCopy textarea
+			Case TOOLPASTE
+				GadgetPaste textarea
+				UpdateCursor()
+				UpdateCode()
+			Case TOOLSELECTALL
+				SelectTextAreaText textarea
+				UpdateCursor()
+			Case TOOLINDENT
+				IndentCode()
+			Case TOOLOUTDENT
+				OutdentCode()
+			Case TOOLPRINT
+				GadgetPrint textarea
+		End Select
+	End Method
+		
+	Function CreateEditMenu:TGadget()
+		Local	edit:TGadget = CreateMenu("Edit",0,Null)
+		CreateMenu "Quick Help",MENUQUICKHELP,edit
+		CreateMenu "",0,edit
+		CreateMenu "Cut",MENUCUT,edit
+		CreateMenu "Copy",MENUCOPY,edit
+		CreateMenu "Paste",MENUPASTE,edit
+		CreateMenu "",0,edit
+		CreateMenu "Select All",MENUSELECTALL,edit
+		CreateMenu "",0,edit
+		CreateMenu "Block Indent",MENUINDENT,edit
+		CreateMenu "Block Outdent",MENUOUTDENT,edit
+		CreateMenu "",0,edit
+		CreateMenu "Find",MENUFIND,edit
+		CreateMenu "Find Next",MENUFINDNEXT,edit
+		CreateMenu "Replace",MENUREPLACE,edit
+		CreateMenu "Goto Line",MENUGOTO,edit
+		Return edit
+	End Function
+	
+	Method MakePathTemp()
+' prepends "." to file name with code borrowed from SaveAs		
+		Local file$=ExtractDir(path)+"/."+StripDir(path)
+		SaveSource(file$)
+'		Refresh
+		GetNode().Refresh
+'		setdirty False
+		host.SetTitle path
+	End Method
+	
+	Function Create:TOpenCode(path$,host:TCodePlay)
+		Local	code:TOpenCode
+		Local	stream:TStream
+		Local	isnew
+		If path
+			If FileType(path)<>FILETYPE_FILE
+				Return Null
+			EndIf
+			stream=ReadFile(path)
+			If Not stream
+'				Notify "Open could not read from "+path		
+				Return Null
+			EndIf
+			CloseFile stream
+		Else
+			TEMPCOUNT:+1
+'			path=host.bmxpath+"/tmp/untitled"+TEMPCOUNT+".bmx"
+'			path=host.monkpath+"/tmp/untitled"+TEMPCOUNT+".monkey"
+			path=RequestFile("Create New File","",True,"untitled"+TEMPCOUNT+".monkey")
+			isnew=True
+		EndIf
+		code=New TOpenCode
+		code.host=host
+		code.active=True
+		code.path=host.FullPath(path)
+		code.editmenu=CreateEditMenu()
+		codeplay.addpanel(code)
+		
+		Local margin=12	
+?win32
+		margin=0
+?		
+		code.textarea=CreateTextArea(margin,0,ClientWidth(code.panel)-margin,ClientHeight(code.panel),code.panel,0)
+		
+'		code.textarea=CreateTextArea(0,0,ClientWidth(code.panel),ClientHeight(code.panel),code.panel,0)
+		SetGadgetFilter code.textarea,code.FilterKey,code
+		SetTextAreaText code.textarea,"~n"
+		SetGadgetLayout code.textarea,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED
+
+		If ExtractExt(path).toLower()="bmx" code.isbmx=True
+		If ExtractExt(path).toLower()="c" code.isc=True
+		If ExtractExt(path).toLower()="cpp" code.iscpp=True
+		If ExtractExt(path).toLower()="cxx" code.iscpp=True
+		If ExtractExt(path).toLower()="html" code.ishtml=True
+		If ExtractExt(path).toLower()="htm" code.ishtml=True
+		If ExtractExt(path).toLower()="monkey" code.ismonkey=True
+
+		code.Refresh()
+		
+		If isnew
+			code.SaveSource path
+			code.filesrc="~n"
+			ActivateGadget code.textarea
+		Else
+			host.UpdateProgress "Reading Stream"
+			code.ReadSource(path)
+		EndIf
+		
+				
+		code.UpdateCode False
+		code.filesrc=TextAreaText(code.textarea)
+		Return code
+	End Function
+
+End Type
+
+Type TRect
+	Field		x,y,w,h
+
+	Method Set(xpos,ypos,width,height)
+		x=xpos;y=ypos;w=width;h=height
+	End Method
+	
+	Method ToString$()
+		Return ""+x+","+y+","+w+","+h
+	End Method
+
+	Method FromString(s$)
+		Local	p,q,r
+		p=s.Find(",")+1;If Not p Return
+		q=s.Find(",",p)+1;If Not q Return
+		r=s.Find(",",q)+1;If Not r Return
+		x=Int(s[..p-1])
+		y=Int(s[p..q-1])
+		w=Int(s[q..r-1])
+		h=Int(s[r..])
+	End Method
+	
+	Method IsOutside(tx,ty,tw,th)
+		If x+w<=tx Or y+h<=ty Return True
+		If x>=tx+tw Or y>=ty+th Return True	
+	End Method
+
+End Type
+
+Type THistoryNode Extends TNode
+	Field owner:THistoryPlugin
+	Field path$
+	Field archive$
+
+	Method Invoke(command,argument:Object=Null)
+		Select command
+			Case TOOLACTIVATE
+				codeplay.OpenSource archive
+		End Select
+	End Method
+
+	Method SetDetails(o:THistoryPlugin,n$,p$,a$)
+		owner=o
+		SetName n
+		path=p
+		archive=a
+		SetAction(owner,TOOLACTIVATE,Self)
+	End Method
+End Type
+
+Type THistoryPlugin Extends TTool
+
+	Field	historycommand
+	Field	historyroot:TNode
+	Field	versions:TMap
+	Field	locations:TMap
+
+	Function FindValue( list:TList,value:Object )
+		Local index
+		For Local value2:Object=EachIn list
+			If value.Compare( value2 )=0 Return index
+			index:+1
+		Next			
+		Return -1
+	End Function
+
+	Method Archive(path$,Text$)
+		Local dest$,version$,location$,hpath$
+		
+		hpath=HistoryPath()
+		If hpath="" Return
+		
+		version=String(versions.ValueForKey(path))
+		version=String(1+Int(version))
+		versions.Insert path,version
+		
+		dest=StripAll(path)
+		
+		Local paths:TList
+		paths=TList(locations.ValueForKey(dest))
+		If Not paths
+			paths=New TList
+			locations.Insert dest,paths
+		EndIf
+		
+		Local index=FindValue(paths,path)+1
+		If index=0
+			paths.AddLast path
+			index=paths.Count()
+		EndIf	
+		location=String(index)
+			
+		dest=StripAll(path)
+		dest:+"_"+location
+		dest:+"_"+version
+		dest:+"."+ExtractExt(path)		
+
+		dest$=hpath+"/"+dest
+		SaveText Text,dest
+
+'		DebugLog "history:path="+path+"~ntext="+text
+		
+		Local n:THistoryNode
+		Local o:THistoryNode
+		Local filename$
+
+		filename=StripDir(path)
+
+		n=THistoryNode(historyroot.FindNode(filename))
+		
+		If Not n n=New THistoryNode
+		n.setdetails(Self,filename,"",path$)
+		
+		o=New THistoryNode
+		o.setdetails(Self,filename+"("+version+")",path,dest$)
+		n.AddFirst o
+	
+		historyroot.AddFirst n
+		historyroot.Refresh
+		
+		WriteHistory
+	End Method
+
+	Method ReadHistory()
+		Local path$,vers$
+		Local dest$,destlist:TList,d$
+		Local node:THistoryNode
+		Local nodee:THistoryNode
+		Local n$,p$,a$,hpath$
+		
+		hpath=HistoryPath()
+		
+		If Not hpath Return
+		Local f:TStream=ReadFile(hpath+"/history.txt")
+		If f 
+			While Not Eof(f)
+				Local l$=ReadLine(f)
+				Select l
+					Case "version"
+						path$=ReadLine(f)
+						vers$=ReadLine(f)
+						ReadLine f
+						versions.Insert path,vers
+					Case "location"					
+						dest$=ReadLine(f)
+						destlist=New TList
+						While True
+							d$=ReadLine(f)
+							If Not d$ Exit
+							destlist.AddLast d
+						Wend
+					Case "history"
+						n$=ReadLine(f)
+						p$=ReadLine(f)
+						a$=ReadLine(f)
+						node=New THistoryNode
+						node.setdetails Self,n,p,a
+						historyroot.Append node
+						While True
+							n$=ReadLine(f)
+							If Not n Exit
+							p$=ReadLine(f)
+							a$=ReadLine(f)
+							nodee=New THistoryNode
+							nodee.setdetails Self,n,p,a
+							node.Append nodee
+						Wend				
+				End Select
+			Wend
+			CloseStream f
+		EndIf
+	End Method
+	
+	Method WriteHistory()
+		Local hpath$
+		hpath=HistoryPath()
+		If Not hpath Return
+		Local f:TStream=WriteFile(hpath+"/history.txt")
+		If f 
+'versions		
+			Local path$
+			For path=EachIn versions.keys()
+				WriteLine f,"version"
+				WriteLine f,path
+				WriteLine f,String(versions.ValueForKey(path))
+				WriteLine f,""
+			Next
+'locations
+			Local dest$,loc$
+			Local paths:TList
+			For dest$=EachIn locations.keys()
+				WriteLine f,"location"
+				WriteLine f,dest
+				paths=TList(locations.ValueForKey(dest))
+				For loc=EachIn paths
+					WriteLine f,loc
+				Next
+				WriteLine f,""
+			Next
+'historyroot			
+			Local nodee:THistoryNode			
+			Local node:THistoryNode			
+			For node=EachIn historyroot.kids
+				WriteLine f,"history"
+				WriteLine f,node.name
+				WriteLine f,node.path
+				WriteLine f,node.archive
+				For nodee=EachIn node.kids
+					WriteLine f,nodee.name
+					WriteLine f,nodee.path
+					WriteLine f,nodee.archive
+				Next			
+				WriteLine f,""
+			Next
+			CloseStream f
+		EndIf
+	End Method
+
+	Method Invoke(command,argument:Object=Null)	
+		Select command
+'			Case "RESET"	'new for 9.06
+			Case TOOLARCHIVE
+				Local pathdata:Object[]=Object[](argument)
+				If Not pathdata Or pathdata.length<>2 Return
+				Local path$=String(pathdata[0])
+				Local Text$=String(pathdata[1])
+				Archive path,Text
+			Case TOOLHISTORY
+				' do history requester
+				Notify "History Requester coming soon..."		
+			Default
+				Notify "history invoke with unknown command "+command
+		End Select
+	End Method
+		
+	Method Open:Object(path$)
+	End Method
+
+'Historyrequester.Show
+
+	Method HistoryPath$()
+		Local h$
+		h=""
+		If codeplay.options.archivecode
+			h=codeplay.monkpath+"/history"
+			If FileType(h)=0 
+				If Not CreateDir(h) 
+					Notify "Unable to create history directory "+h
+					h=""
+				EndIf
+			EndIf
+		EndIf
+		Return h
+	End Method
+	
+	Method EnableHistory(host:TCodePlay)
+		If historyroot Return
+		historyroot=host.root.AddNode("History")
+		versions=New TMap
+		locations=New TMap
+		ReadHistory
+		historyroot.Refresh		
+		host.root.Refresh
+	End Method
+	
+	Method DisableHistory()
+		If historyroot 
+			historyroot.free
+			historyroot=Null
+		EndIf
+	End Method
+
+End Type
+
+
+Type TCodePlay
+
+	Const EDITMODE=1
+	Const DEBUGMODE=2
+	
+	Field bmxpath$
+	Field bmkpath$
+	Field monkeypath$
+	Field transpath$
+	Field monkpath$
+	Field inipath$
+	
+	Field panels:TToolPanel[]
+	Field helppanel:THelpPanel
+	Field currentpanel:TToolPanel
+
+	Field output:TOutputPanel
+	Field serverpanel:TServerPanel
+
+	Field lockedpanel:TToolPanel
+	Field activepanel:TToolPanel
+	
+	Field cmdlinereq:TCmdLineRequester
+	Field cmdline$
+'	Field syncmodsreq:TSyncModsRequester
+	Field gotoreq:TGotoRequester
+	Field monkeyreq:TMonkeyRequester
+	Field findreq:TFindRequester
+	Field replacereq:TReplaceRequester
+	Field options:TOptionsRequester
+'	Field progress:TProgressRequester
+	Field activerequesters:TList = New TList
+	Field projectreq:TProjectRequester
+	Field projectprops:TProjectProperties
+	Field searchreq:TSearchRequester	
+	
+	Field eventhandlers:TList=New TList
+	Field window:TGadget,menubar:TGadget,toolbar:TGadget,client:TGadget,tabbar:TGadget
+	Field split:TSplitter
+	Field debugtree:TDebugTree
+	
+	Field root:TNode
+	Field helproot:TNode
+	Field bmxhelproot:TNode
+	Field monkeyhelproot:TNode
+	Field wiki:TWiki
+	Field projects:TProjects
+	Field coderoot:TNode
+	Field navbar:TNavBar	
+
+	Field mode
+	Field debugcode:TOpenCode
+
+	Field quickenable:TGadget,quickenabled	'menu,state
+	Field debugenable:TGadget,debugenabled	'menu,state
+	Field threadedenable:TGadget,threadedenabled
+	Field guienable:TGadget,guienabled		'menu,state
+	Field quickhelp:TQuickHelp
+	Field monkeyhelp:TQuickHelp
+	Field running
+	Field recentmenu:TGadget
+	Field recentfiles:TList=New TList
+	Field recentmenus:TGadget[]
+	Field openlist:TList=New TList
+	Field openlock$
+	Field projlist:TList=New TList
+	Field winsize:TRect=New TRect
+	Field winmax,tooly,splitpos,debugview,navtab
+	Field progress,splitorientation
+
+	Field history:THistoryPlugin
+
+?MacOS	
+	Method RanlibMods()
+		Local cmd$=Quote( bmxpath+"/bin/bmk" )+" ranlibdir "+Quote( bmxpath+"/mod" )
+		system_ cmd
+	End Method
+?
+
+	Method CheckBMXVersion$()
+		Local	process:TProcess
+		Local	bytes:Byte[]
+		Local	cmd$,version$
+
+		BCC_VERSION=""
+		cmd$=bmxpath+"/bin/bcc"
+		
+?win32
+		cmd:+".exe"
+?
+		
+		cmd=Quote(cmd)
+		process=CreateProcess(cmd$,HIDECONSOLE)
+		If process
+			Repeat
+				Delay 10
+				bytes=process.pipe.ReadPipe()
+				If bytes
+					version:+String.FromBytes(bytes,bytes.length)
+				EndIf
+			Until Not process.Status()
+		EndIf
+
+		BCC_VERSION=version.Trim()
+		
+	End Method
+	
+	Method OpenProgress(message$)
+'		progress.Open message
+		DisableGadget window
+		SetStatus message
+		progress=-1
+	End Method
+
+	Method CloseProgress()
+'		progress.Hide
+		SetStatus ""
+		EnableGadget window
+		progress=0
+	End Method
+	
+	Method UpdateProgress(message$,value=0)		'returns false if cancelled
+'		Return progress.Update(message,value)
+		If progress
+			If progress/5<>value/5
+				SetStatus message+" "+value+"%"
+				progress=value
+'				Pollsystem
+			EndIf
+		EndIf
+	End Method
+
+	Method FullPath$(path$)
+		If path[..8]="$BMXPATH" path=bmxpath+path[8..]
+		If Not path.Contains("::") Then path = RealPath(path)
+?win32
+		path=path.Replace("\","/")
+?
+		Return path
+	End Method
+
+	Method IsTempPath(path$)
+		If path[..bmxpath.length+5]=monkpath+"/tmp/" Return True
+	End Method
+	
+	Method AddDefaultProj(p$)
+		Local projdata:TList = New TList
+		projdata.AddLast p
+		projlist.AddLast projdata
+	End Method
+
+	Method ReadConfig()
+		Local	stream:TStream
+		Local	f$,p,a$,b$
+' defaults		
+		Local wh=GadgetHeight(Desktop())-80'32
+		Local ww=wh
+		Local wx=(GadgetWidth(Desktop())-ww)/2
+		Local wy=(GadgetHeight(Desktop())-wh)/2
+		winsize.set( wx,wy,ww,wh )
+		quickenabled=False
+		debugenabled=True
+		threadedenabled=False
+		guienabled=True	
+		splitpos=200;splitorientation = SPLIT_VERTICAL
+' read ini
+		stream=ReadFile(inipath)
+		If Not stream
+			AddDefaultProj "monkey|."
+			Return
+		EndIf
+		
+		options.read(stream)		
+		options.Snapshot
+
+		Local projdata:TList
+		
+		While Not stream.Eof()
+			f$=stream.ReadLine()
+			p=f.find("=")
+			If p=-1 Continue
+			a$=f[..p]
+			b$=f[p+1..]
+			Select a$
+				Case "ide_version"
+					' bump upgrade tricks				
+				Case "monkey_path"
+					monkeypath=b$
+				Case "blitzmax_path"
+					bmxpath=b$
+				Case "file_recent"
+					recentfiles.addlast b$
+				Case "file_open"
+					openlist.addlast b$
+				Case "prg_quick"
+					quickenabled=Int(b$)
+				Case "prg_debug"
+					debugenabled=Int(b$)
+				Case "prg_threaded"
+					threadedenabled=Int(b$)
+				Case "prg_gui"
+					guienabled=Int(b$)
+				Case "cmd_line"
+					cmdline=b$
+				Case "prg_locked"
+					openlock=b$
+				Case "win_size"
+					winsize.FromString(b$)
+				Case "win_max"
+					winmax=Int(b$)
+				Case "split_position"
+					splitpos=Int(b$)
+				Case "split_orientation"
+					splitorientation=Int(b$)
+				Case "proj_node"
+					projdata=New TList
+					projdata.AddLast b
+					projlist.AddLast projdata
+				Case "proj_data"
+					If projdata projdata.AddLast b
+				'Case "sync_state"
+					'syncmodsreq.FromString b$
+			End Select
+		Wend
+		stream.close()		
+	End Method
+	
+	Method WriteConfig()
+		Local	panel:TToolPanel
+		Local	node:TNode
+		Local	f$
+		
+		Local	stream:TStream = WriteFile(inipath)
+		If Not stream Return
+' options
+		options.Write(stream)
+' defaults		
+		stream.WriteLine "[Defaults]"
+		stream.WriteLine "ide_version="+VERSION
+		stream.WriteLine "monkey_path="+monkeypath
+		stream.WriteLine "blitzmax_path="+bmxpath
+		stream.WriteLine "prg_quick="+quickenabled
+		stream.WriteLine "prg_debug="+debugenabled
+		stream.WriteLine "prg_threaded="+threadedenabled
+		stream.WriteLine "prg_gui="+guienabled
+		stream.WriteLine "win_size="+winsize.ToString()
+		stream.WriteLine "win_max="+winmax
+		stream.WriteLine "split_position="+SplitterPosition(split)
+		stream.WriteLine "split_orientation="+SplitterOrientation(split)
+		stream.WriteLine "cmd_line="+cmdline
+		'stream.WriteLine "sync_state="+syncmodsreq.ToString()
+		If lockedpanel stream.WriteLine "prg_locked="+lockedpanel.path
+		For f$=EachIn recentfiles
+			stream.WriteLine "file_recent="+f$
+		Next
+		For Local panel:TToolPanel = EachIn panels
+			f$=panel.path
+			If f$ And Not IsTempPath(f$) stream.WriteLine "file_open="+f$
+		Next
+		projects.Write(stream)	
+		stream.close
+	End Method
+	
+	Method CloseAll(dontask,inccurrent=True)	'returns true if successful
+		Local	count, cancel
+		For Local panel:TToolPanel = EachIn panels
+			If TOpenCode(panel) And (inccurrent Or currentpanel <> panel) count:+1
+		Next
+		If (Not count) Or dontask Or Confirm("Monk needs to close all documents before continuing.")
+			For Local panel:TToolPanel = EachIn panels[..]	'Use a copy of the original array for iterating.
+				If (inccurrent Or currentpanel <> panel) And panel.invoke(TOOLCLOSE) Then
+					cancel=True
+					Exit
+				EndIf
+			Next
+			Return Not cancel
+		EndIf
+	End Method
+
+	Method Quit()
+		WriteConfig()
+		If CloseAll(True) 
+			serverpanel.Close
+			running=False
+		EndIf
+	End Method
+
+	Method DebugExit()
+		If debugcode
+			debugtree.cancontinue = False
+			debugcode.Edit		'restore cursor etc.	
+			debugcode=Null
+		EndIf
+		SetMode EDITMODE
+		RefreshToolbar()
+	End Method
+		
+	Method DebugSource(path$,Line,column)
+		Local	code:TOpenCode
+		path=FullPath(path)
+		code=OpenSource(path)
+		If Not code Then
+			Notify("Failed to open '"+path+"'.", True)
+			Return
+		EndIf
+		If debugcode And debugcode<>code Then debugcode.Edit()	'restore cursor etc.
+		debugcode=code
+		debugcode.debug(Line,column)	
+		ActivateWindow window
+		PollSystem
+	End Method
+	
+	Method SetMode(m)
+		If mode=m Return
+		ActivateWindow window
+		Select m
+		Case DEBUGMODE
+			navtab=navbar.SelectedView()
+			navbar.SelectView debugview
+		Case EDITMODE
+			navbar.SelectView navtab
+		End Select
+		mode=m
+		RefreshToolbar
+	End Method
+	
+	Method RefreshMenu()
+		UpdateWindowMenu window
+	EndMethod
+	
+	Method RefreshToolbar()
+		Local	i
+' sourceedit buttons
+		If THelpPanel(CurrentPanel)
+			DisableGadgetItem toolbar,TB_CLOSE
+		Else
+			EnableGadgetItem toolbar,TB_CLOSE
+		EndIf
+		If TOpenCode(CurrentPanel)
+			EnableGadgetItem toolbar,TB_SAVE
+			For i=TB_CUT To TB_FIND
+				EnableGadgetItem toolbar,i
+			Next
+		Else
+			DisableGadgetItem toolbar,TB_SAVE
+			For i=TB_CUT To TB_FIND
+				DisableGadgetItem toolbar,i
+			Next			
+		EndIf
+' debug buttons
+		If mode = DEBUGMODE And debugtree.cancontinue Then
+			If GadgetItemIcon( toolbar, TB_BUILDRUN ) = TB_BUILDRUN Then
+				ModifyGadgetItem( toolbar, TB_BUILDRUN, "", 0, TB_CONTINUE, "Continue" )
+			EndIf
+		Else
+			If GadgetItemIcon( toolbar, TB_BUILDRUN ) <> TB_BUILDRUN Then
+				ModifyGadgetItem( toolbar, TB_BUILDRUN, "", 0, TB_BUILDRUN, "Build and Run" )
+			EndIf
+		EndIf
+		For i=TB_STEP To TB_STEPOUT
+			If mode=DEBUGMODE And debugtree.cancontinue Then
+				EnableGadgetItem toolbar,i
+			Else
+				DisableGadgetItem toolbar,i
+			EndIf
+		Next
+' stop button		
+		If output And output.process
+			EnableGadgetItem toolbar,TB_STOP
+		Else
+			DisableGadgetItem toolbar,TB_STOP
+		EndIf		
+	End Method
+	
+	Method IsSourceOpen(path$)
+		Local	p$ = FullPath(path)
+		For Local panel:TToolPanel = EachIn panels
+			If panel.path=p Return True
+		Next
+	End Method
+	
+	Method OpenSource:TOpenCode(path$)
+		Local	code:TOpenCode
+		Local	ext$,p$
+		If path$="."
+			path$=RequestFile("Open File",FileTypeFilters )
+			If path$="" Return
+		EndIf
+' check if already open
+		p$=FullPath(path).ToLower()
+		For Local panel:TToolPanel = EachIn panels
+			If panel.path.ToLower()=p
+				SelectPanel panel
+				Return TOpenCode(panel)
+			EndIf
+		Next
+' open based on extension		
+'		Select ExtractExt(Upper(path$))
+'		Case "BMX","TXT","BB","CPP","C","S","I","H","HTML","CSS","BAT","FS","VS","README",""
+			OpenProgress "Loading "+StripDir(path)
+			code=TOpenCode.Create(path,Self)
+			If code
+				AddRecent code.path
+			EndIf
+			CloseProgress
+			If code
+				ActivateGadget code.textarea
+				code.GetNode().Refresh
+			EndIf
+			Return code
+'		end select
+	End Method
+	
+	Method AddRecent(path$)
+		For Local f$ = EachIn recentfiles
+			If f$=path$ recentfiles.Remove(f$);Exit
+		Next
+		recentfiles.AddFirst(path$)
+		RefreshRecentFiles
+		UpdateWindowMenu window
+	End Method
+	
+	Method RefreshRecentFiles()
+		Local	n
+		For Local m:TGadget = EachIn recentmenus
+			FreeMenu m
+		Next
+		n=Min(recentfiles.count(),16)
+		recentmenus=New TGadget[n]
+		n=0
+		For Local f$ = EachIn recentfiles
+			recentmenus[n]=CreateMenu(f$,MENURECENT+n,recentmenu)
+			n:+1
+			If n=16 Exit
+		Next
+	End Method
+	
+	Method BuildModules(buildall)
+		Local cmd$,out$,exe$
+		output.Stop
+		SaveAll
+		cmd$=quote(bmkpath)
+		cmd$:+" makemods "
+		
+		If buildall cmd$:+"-a "
+		If threadedenabled cmd:+"-h "
+		
+		Execute cmd,"Building Modules"
+	End Method
+
+	Method ImportBB()
+		Local f$ = RequestFile("Import .bb file","bb" )
+		If Not f$ Return
+		Local cmd$ = Quote(bmkpath$)
+		cmd$:+" convertbb "
+		cmd$:+quote(FullPath(f$))
+		Execute cmd,"Converting "+StripExt(StripDir(f$))
+		output.wait
+		OpenSource(StripExt(f$)+".bmx")
+	End Method
+
+	Method GetCommandLine$()
+		Return cmdline
+	End Method
+
+	Method SetCommandLine(Text$)
+		cmdline=Text
+	End Method
+	
+	Method SetStatus(Text$)
+		SetStatusText window,Text
+	End Method
+
+	Method Execute(cmd$,mess$="",post$="",home=True,tool:TTool=Null)
+		If Not output output=TOutputPanel.Create(Self)
+		output.execute cmd$,mess$,post$,home,tool
+	End Method
+
+	Method SelectError(path$,column,Line)
+		Local	panel:TOpenCode,found
+		For panel=EachIn panels
+			If panel.path=path found=True;Exit
+		Next
+		If Not found panel=OpenSource(path)
+		If panel
+			SelectPanel panel
+			panel.Debug Line,column
+		EndIf
+	End Method
+	
+	Method ParseError(err$)
+		Local		mess$,file$,p,q
+		Local		Line,column
+		
+' bcc error
+		If err$[..13]="Compile Error"
+			err=err[14..]
+			p=err.find(EOL$)
+			If p=-1 p=err.length
+			mess=err[..p]
+			err=err[p+1..]
+			If err[..1]="["
+				p=err.find("]")
+				If p=-1 p=err.length
+				file$=err[1..p]
+				p=file.find(";")+1
+				If p=0 p=err.length
+				q=file.find(";",p)+1
+				If q=0 q=err.length
+				Line=Int(file[p..q-1])
+				column=Int(file[q..])
+				file=FullPath(file[..p-1])				
+				SelectError file,column,Line
+			EndIf
+			Notify "Compile Error~n~n"+mess
+			SetStatus mess
+			Return
+		EndIf
+		
+		Return
+
+' gcc error
+		err=err.Replace(EOL+"   "," ")
+		While err
+			p=err.find(EOL)
+			If p=-1 p:+err.length	'equiv. to p=err.length-1 ;-)
+			mess=err[..p]
+			err=err[p+1..]
+			p=0
+			Repeat
+				p=mess.Find(":",p)+1
+				If p=0 Exit
+				q=mess.Find(":",p)
+				If q<>-1
+					file=mess[..p-1]
+					Line=Int(mess[p..q])
+					If Line
+						mess=mess[q+1..]
+						SelectError file,column,Line
+						Notify "Compile Error~n~n"+mess
+						Return
+					EndIf
+					p=q+1
+				EndIf
+			Forever
+		Wend
+	End Method
+		
+	Method AddPanel(tabpanel:TToolPanel)
+		Local panel:TGadget,index
+		
+		index=CountGadgetItems(tabbar)
+		If panels.length<=index panels=panels[..index+1]
+		AddGadgetItem(tabbar,tabpanel.name$,GADGETITEM_DEFAULT)
+		
+		Local margin=0
+		Local style=0'PANEL_GROUP
+		
+		panel=CreatePanel(margin,0,ClientWidth(tabbar)-margin,ClientHeight(tabbar),tabbar,style)
+		SetGadgetLayout panel,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED
+
+		tabpanel.panel=panel
+		
+		tabpanel.index=index
+		panels[index]=tabpanel
+		SelectPanel tabpanel
+
+		AddHandler tabpanel
+	End Method
+
+	Method InsertPanel(tabpanel:TToolPanel,index)
+		Local panel:TGadget,count,n,i
+
+		count=CountGadgetItems(tabbar)
+		If index>count index=count
+		
+		n=panels.length
+		panels=panels[..n+1]
+		For i=n Until index Step -1		
+			panels[i]=panels[i-1]
+			panels[i].index=i
+		Next
+		
+		InsertGadgetItem tabbar,index,tabpanel.name$,GADGETITEM_DEFAULT 
+		
+		Local margin=0
+		Local style=0'PANEL_GROUP
+		
+		panel=CreatePanel(margin,0,ClientWidth(tabbar)-margin,ClientHeight(tabbar),tabbar,style)
+		SetGadgetLayout panel,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED
+
+		tabpanel.panel=panel
+		
+		tabpanel.index=index
+		panels[index]=tabpanel
+		SelectPanel tabpanel
+
+		AddHandler tabpanel
+	End Method
+
+	Method AddHandler(handler:TEventHandler)
+		eventhandlers.addlast handler
+	End Method
+
+	Method RemovePanel(tabpanel:TToolPanel)
+		Local p:TToolPanel[]
+		Local index
+
+		eventhandlers.remove tabpanel
+' unset debugcode
+		If debugcode=tabpanel debugcode=Null
+' activate next panel
+		If tabpanel=activepanel activepanel=helppanel
+		If tabpanel=lockedpanel lockedpanel=Null
+		If tabpanel=currentpanel
+			index=tabpanel.index+1
+			If index>=panels.length index=panels.length-2
+			SelectPanel panels[index]
+		EndIf
+' remove from array
+		p=panels
+		panels=panels[..panels.length-1]
+		For index=tabpanel.index To panels.length-1
+			panels[index]=p[index+1]
+			panels[index].index=index
+		Next
+' remove gadget	- simon come here,  placing before remove needs fix in fltk
+		FreeGadget tabpanel.panel
+		RemoveGadgetItem tabbar,tabpanel.index
+		tabpanel.panel=Null
+		RefreshBuildOptions		
+	End Method
+		
+	Method HookRequester(req:TRequester)
+		If Not activerequesters.Contains(req) Then
+			If req.IsModal() Then
+				For Local tmpRequester:TRequester = EachIn activerequesters
+					DisableGadget tmpRequester.window
+				Next
+				DisableGadget window
+			EndIf
+			activerequesters.AddFirst(req)
+		EndIf
+	End Method
+	
+	Method UnhookRequester(req:TRequester)
+		If activerequesters.Contains(req) Then
+			activerequesters.Remove(req)
+			If req.IsModal() Then
+				For Local tmpRequester:TRequester = EachIn activerequesters
+					EnableGadget tmpRequester.window
+				Next
+				EnableGadget window
+			EndIf
+		EndIf
+	EndMethod
+	
+	Method SetTitle(title$="")
+		If title title=" - "+title
+		SetGadgetText window,"Monk"+title
+	End Method
+	
+	Method SelectPanel(panel:TToolPanel)	
+		Local	curr:TToolPanel = currentpanel
+		currentpanel=panel
+		If curr And curr<>currentpanel
+			SelectGadgetItem tabbar,panel.index
+			ShowGadget panel.panel
+			If panel.active activepanel=panel
+			HideGadget curr.panel
+			RefreshToolbar
+		EndIf
+		currentpanel.Invoke TOOLSHOW
+		RefreshBuildOptions
+	End Method
+		
+	Method RefreshPanel(panel:TToolPanel)	'call after a name change
+		ModifyGadgetItem( tabbar,panel.index,panel.name )	
+		RefreshBuildOptions		
+	End Method
+
+	Function OutsideDesktop(winrect:TRect)
+		Local x,y,w,h
+		Local desk:TGadget = Desktop()
+		x=GadgetX(desk)
+		y=GadgetY(desk)
+		w=GadgetWidth(desk)
+		h=GadgetHeight(desk)
+		Return winrect.IsOutside(x,y,w,h)
+	End Function
+
+	Method SetCodeNode(code:TNode)
+		Local node:TNode
+		If coderoot.kids.count() node=TNode(coderoot.kids.First())
+		If node=code Return
+		If node node.Detach
+		If code
+			coderoot.Append code
+			coderoot.Refresh
+			coderoot.Open
+			code.Open
+		EndIf
+	End Method
+	
+	Method MakeDocs()	
+		Local mkdocs
+		If FileType( bmxpath+"/docs/html/User Guide/index.html" )<>FILETYPE_FILE
+			CreateDir bmxpath+"/docs/html"
+			CreateFile bmxpath+"/docs/html/index.html"
+			mkdocs=True
+		EndIf
+'build docs if not there		
+' simon was here: no docmods
+'		If mkdocs
+'			If Confirm( "Documentation not found.~n~nWould you like to rebuild documentation now?") ) And CloseAll( False ) DocMods
+'		EndIf
+	End Method
+	
+	Method InitMonkeyPaths()
+		If Not monkeypath Return		
+?win32
+		transpath=monkeypath+"/bin/transcc_winnt"
+?macos
+		transpath=monkeypath+"/bin/transcc_macos"		
+'A bit rude! This turns off the 'app was downloaded from the internet' warning
+'that prevents MServer from running cleanly.
+'
+'		system_ "xattr -d com.apple.quarantine ~q"+monkeypath+"/bin/mserver_macos.app~q"
+?
+	End Method
+	
+	Method InitBMXPaths()	
+		If Not bmxpath Return
+		bmkpath=bmxpath+"/bin/bmk"	
+'		TestBCC()
+		CheckBMXVersion()
+	End Method
+
+	Method Initialize()		
+		Local	open:TOpenCode
+		Local	dir$,nomods,pname$,p
+		Local	stream:TStream
+
+		monkpath=AppDir
+		CreateDir monkpath+"/tmp"
+		If FileType( monkpath+"/tmp" )<>FILETYPE_DIR
+			Notify "Unable to create Monk 'tmp' directory."
+			End
+		EndIf
+				
+		inipath=monkpath+"/monk."+ComputerName$()+".ini"
+				
+		window=CreateWindow("Monk",20,20,760,540,Null,WINDOW_TITLEBAR|WINDOW_RESIZABLE|WINDOW_STATUS|WINDOW_HIDDEN|WINDOW_ACCEPTFILES|WINDOW_MENU)
+		
+		?Linux
+		SetGadgetPixmap(window, LoadPixmapPNG("incbin::window_icon.png"), GADGETPIXMAP_ICON )
+		?
+		
+		options=TOptionsRequester.Create(Self)
+		ReadConfig()		
+		InitMonkeyPaths
+		InitBMXPaths
+			
+		cmdlinereq=TCmdLineRequester.Create(Self)
+		'syncmodsreq=TSyncModsRequester.Create(Self)
+		gotoreq=TGotoRequester.Create(Self)
+		findreq=TFindRequester.Create(Self)
+		replacereq=TReplaceRequester.Create(Self)
+		projectreq=TProjectRequester.Create(Self)
+		projectprops=TProjectProperties.Create(Self)
+		searchreq=TSearchRequester.Create(Self)
+		monkeyreq=TMonkeyRequester.Create(Self)
+	
+
+		toolbar=CreateToolbar("incbin::monktoolbar.png",0,0,0,0,window )
+		RemoveGadgetItem toolbar, TB_CONTINUE
+		
+		SetToolbarTips toolbar, ["New","Open","Close","Save","","Cut","Copy","Paste","Find","",..
+		                         "Build","Build and Run","Step","Step In","Step Out","Stop","","Home","Back","Forward"]
+
+		If Not options.showtoolbar Then HideGadget toolbar
+		
+		If OutsideDesktop(winsize)
+			winsize.set(20,20,760,540)		
+		EndIf
+				
+		SetGadgetShape(window, winsize.x, winsize.y, winsize.w, winsize.h)
+
+		client=window
+		
+		split=CreateSplitter(0,0,ClientWidth(client),ClientHeight(client),client,SPLIT_VERTICAL)
+		SetGadgetLayout(split,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED)
+		
+		tabbar=CreateTabber(0,0,ClientWidth(SplitterPanel(split,SPLITPANEL_MAIN)),ClientHeight(SplitterPanel(split,SPLITPANEL_MAIN)),SplitterPanel(split,SPLITPANEL_MAIN))
+		SetGadgetLayout(tabbar,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED)
+
+		InitMenu
+		InitHotkeys
+		
+		debugtree=TDebugTree.CreateDebugTree(Self)
+
+		root=TNode.CreateNode("Project")
+										
+		projects=TProjects.CreateProjects(Self)		
+		root.Append projects
+
+'		wikiroot=root.AddNode("Wiki")
+	
+'		opencoderoot=root.AddNode("Open")
+		coderoot=TNode.CreateNode("Code")
+		coderoot.Open()
+
+		helproot=root.AddNode("Docs")
+
+		If monkeypath
+			monkeyhelproot=helproot.AddNode("Monkey")
+		EndIf
+
+		If bmxpath
+			bmxhelproot=helproot.AddNode("BlitzMax")
+		EndIf
+
+		history=New THistoryPlugin
+		navbar=TNavBar.Create(Self,SplitterPanel(split,SPLITPANEL_SIDEPANE))
+
+		navbar.AddView root
+		navbar.AddView coderoot
+		debugview=navbar.AddView(debugtree)
+		navbar.SelectView 0
+
+		If helproot helproot.Open
+		projects.Open
+
+		AddHandler navbar
+	
+		SetMode EDITMODE
+					
+		If bmxpath quickhelp=TQuickHelp.LoadCommandsTxt(bmxpath)
+
+		monkeyhelp=TQuickHelp.LoadMonkeyCommands(monkeypath,Self)
+
+		helppanel=THelpPanel.Create(Self)
+		output=TOutputPanel.Create(Self)
+		serverpanel=TServerPanel.Create(Self)
+				
+		activepanel=helppanel
+
+'		wiki=TWiki.CreateWiki(Self)
+'		root.Append wiki
+
+		Rethink
+		RefreshAll
+		
+		If bmxpath MakeDocs
+						
+		helppanel.Home()
+				
+' scan projects in projlist
+		For Local pdata:TList = EachIn projlist
+			projects.AddProject pdata
+		Next
+		
+'open files from .ini restorelist		
+		If options.restoreopenfiles
+			For Local f$=EachIn openlist
+				open=OpenSource(f$)
+				If open And f$=openlock open.SetLocked(True)
+			Next
+		EndIf
+				
+' open files specified in command line		
+		For Local i:Int = 1 Until AppArgs.length
+			open=OpenSource(AppArgs[i])
+		Next
+		
+		PollSystem
+		
+		SetSplitterPosition(split,splitpos);SetSplitterOrientation(split,splitorientation)
+		
+		If winmax MaximizeWindow(window)
+		ShowGadget window	
+		
+		PollSystem
+		running=True
+		
+		CreateTimer(TIMER_FREQUENCY)
+		
+		'If nomods syncmodsreq.Show		
+	End Method
+Rem	
+	Method TestBCC()
+		Local dir$
+?Win32
+		CreateFile bmxpath+"/tmp/t.exe"
+		If FileType( bmxpath+"/tmp/t.exe" ) <> FILETYPE_FILE
+			Notify "Unable to write Monk files in current directory.~n"+..
+			"Please run Monk as administrator or vacate to more permissable environment."
+			End
+		DeleteFile bmxpath+"/tmp/t.exe"
+?
+
+
+		bmkpath=bmxpath+"/bin/bmk"
+
+?Win32
+		bmkpath:+".exe"
+?
+		dir$=bmxpath+"/mod"
+		If FileType(dir)=FILETYPE_NONE
+			If Not CreateDir(dir)
+				Notify "Failed to create %1 directory:~n%2".Replace("%1","Module").Replace("%2",dir)
+				End
+			EndIf
+			nomods=True
+		EndIf
+		dir$=bmxpath+"/tmp"
+		If FileType(dir)=FILETYPE_NONE
+			If Not CreateDir(dir)
+				Notify "Failed to create %1 directory:~n%2".Replace("%1","Temp").Replace("%2",dir)
+				End
+			EndIf
+		EndIf
+		dir$=bmxpath+"/cfg"
+		If FileType(dir)=FILETYPE_NONE
+			If Not CreateDir(dir)
+				Notify "Failed to create %1 directory:~n%2".Replace("%1","Config").Replace("%2",dir)
+				End
+			EndIf
+		EndIf
+	End Method
+EndRem
+	
+	Method DocMods()
+		Local cmd$=quote(bmxpath+"/bin/makedocs")
+		execute cmd,"Rebuilding documentation...",MENUTRIGGERSYNCDOCS
+	?MacOS
+		RanLibMods()
+	?
+	End Method
+		
+	Method SyncDocs()
+		helppanel.SyncDocs()
+		quickhelp=TQuickHelp.LoadCommandsTxt(bmxpath)
+		helppanel.Home
+	End Method
+
+	Method InitMenu()
+		Local menu:TGadget
+		Local file:TGadget
+		Local edit:TGadget
+		Local program:TGadget
+		Local tools:TGadget
+		Local help:TGadget
+		Local buildoptions:TGadget
+		Local buildmods:TGadget
+		Local buildallmods:TGadget
+		Local syncmods:TGadget
+		Local docmods:TGadget
+		Local importbb:TGadget
+
+		Local MENUMOD=MODIFIER_COMMAND
+
+		If options.systemkeys
+			MENUMOD=MODIFIER_CONTROL
+		EndIf
+
+		menu=WindowMenu(window)
+
+		file=CreateMenu("&File",0,menu)
+		CreateMenu "&New",MENUNEW,file,KEY_N,MENUMOD
+		CreateMenu "&Open...",MENUOPEN,file,KEY_O,MENUMOD
+		recentmenu=CreateMenu("Open &Recent",0,file)
+		CreateMenu "",0,file
+		CreateMenu "&Close Tab",MENUCLOSE,file,KEY_W,MENUMOD
+		CreateMenu "Close All Tabs",MENUCLOSEALL,file,KEY_W,MENUMOD|MODIFIER_SHIFT
+		CreateMenu "Close Other Tabs",MENUCLOSEOTHERS,file,KEY_W,MENUMOD|MODIFIER_ALT
+		CreateMenu "",0,file
+		CreateMenu "&Save",MENUSAVE,file,KEY_S,MENUMOD
+		CreateMenu "Save &As",MENUSAVEAS,file,KEY_S,MENUMOD|MODIFIER_SHIFT
+		CreateMenu "Save A&ll",MENUSAVEALL,file
+		CreateMenu "",0,file
+
+		If options.systemkeys
+?MacOS
+			CreateMenu "&Next Tab",MENUNEXT,file,KEY_RIGHT,MENUMOD
+			CreateMenu "&Previous Tab",MENUPREV,file,KEY_LEFT,MENUMOD
+?Not MacOS
+			CreateMenu "&Next Tab",MENUNEXT,file,KEY_RIGHT,MODIFIER_ALT
+			CreateMenu "&Previous Tab",MENUPREV,file,KEY_LEFT,MODIFIER_ALT
+?
+		Else
+			CreateMenu "&Next Tab",MENUNEXT,file,KEY_RIGHT,MENUMOD
+			CreateMenu "&Previous Tab",MENUPREV,file,KEY_LEFT,MENUMOD		
+		EndIf
+		CreateMenu "",0,file
+		importbb=CreateMenu("Import BB Project...",MENUIMPORTBB,file)
+		CreateMenu "",0,file
+		CreateMenu "IDE Options",MENUOPTIONS,file
+		CreateMenu "&Project Manager",MENUPROJECTMANAGER,file	
+		CreateMenu "",0,file
+		CreateMenu "Print",MENUPRINT,file,KEY_P,MENUMOD
+?Not MacOS
+		CreateMenu "",0,file
+		CreateMenu "Exit",MENUQUIT,file
+?
+		edit=CreateMenu("&Edit",0,menu)
+		CreateMenu "&Undo",MENUUNDO,edit,KEY_Z,MENUMOD
+?MacOS
+		CreateMenu "&Redo",MENUREDO,edit,KEY_Z,MENUMOD|MODIFIER_SHIFT
+?Not MacOS
+		CreateMenu "&Redo",MENUREDO,edit,KEY_Y,MENUMOD
+?
+		CreateMenu "",0,edit
+		CreateMenu "Cu&t",MENUCUT,edit,KEY_X,MENUMOD
+		CreateMenu "&Copy",MENUCOPY,edit,KEY_C,MENUMOD
+		CreateMenu "&Paste",MENUPASTE,edit,KEY_V,MENUMOD
+		CreateMenu "",0,edit
+		CreateMenu "Select &All",MENUSELECTALL,edit,KEY_A,MENUMOD
+		CreateMenu "",0,edit
+		CreateMenu "Block Indent",MENUINDENT,edit,KEY_CLOSEBRACKET,MENUMOD
+		CreateMenu "Block Outdent",MENUOUTDENT,edit,KEY_OPENBRACKET,MENUMOD
+		CreateMenu "",0,edit
+		CreateMenu "&Find...",MENUFIND,edit,KEY_F,MENUMOD
+?MacOS
+		CreateMenu "Find Next",MENUFINDNEXT,edit,KEY_G,MENUMOD
+		CreateMenu "&Replace...",MENUREPLACE,edit,KEY_H,MENUMOD
+		CreateMenu "&Goto Line...",MENUGOTO,edit,KEY_L,MENUMOD
+?Not MacOS
+		CreateMenu "Find Next",MENUFINDNEXT,edit,KEY_F3
+		CreateMenu "&Replace...",MENUREPLACE,edit,KEY_H,MENUMOD
+		CreateMenu "&Goto Line...",MENUGOTO,edit,KEY_G,MENUMOD
+?
+		CreateMenu "",0,edit
+		CreateMenu "Find in F&iles",MENUFINDINFILES,edit,KEY_F,MENUMOD|MODIFIER_SHIFT
+		
+		program=CreateMenu("&Program",0,menu)
+		CreateMenu "&Build",MENUBUILD,program,KEY_B,MENUMOD
+		CreateMenu "Build and &Run",MENURUN,program,KEY_R,MENUMOD
+
+		buildoptions=CreateMenu("Build Options",0,program)
+		debugenable=CreateMenu("Debug Build",MENUDEBUGENABLED,buildoptions)
+		quickenable=CreateMenu("Quick Build",MENUQUICKENABLED,buildoptions)
+		threadedenable=CreateMenu("Threaded Build",MENUTHREADEDENABLED,buildoptions)
+
+		CreateMenu "Command &Line",MENUCOMMANDLINE,program
+		CreateMenu "",0,program
+		CreateMenu "&Step",MENUSTEP,program,KEY_F9
+		CreateMenu "Step &In",MENUSTEPIN,program,KEY_F10
+		CreateMenu "Step &Out",MENUSTEPOUT,program,KEY_F11
+		CreateMenu "&Terminate",MENUSTOP,program
+
+		guienable=CreateMenu("Build GUI App",MENUGUIENABLED,buildoptions)
+		CreateMenu "",0,program
+		CreateMenu "&Lock Build File",MENULOCKBUILD,program
+		CreateMenu "&Unlock Build File",MENUUNLOCKBUILD,program
+		CreateMenu "",0,program
+		'syncmods=CreateMenu("Synchronize Modules...",MENUSYNCMODS,program)
+		'CreateMenu "",0,program
+		buildmods=CreateMenu("Build &Modules",MENUBUILDMODULES,program,KEY_D,MENUMOD)
+		buildallmods=CreateMenu("Rebuild &All Modules",MENUBUILDALLMODULES,program)
+		docmods=CreateMenu("&Rebuild Documentation",MENUDOCMODS,program)
+		
+		help=CreateMenu("&Help",0,menu)
+		CreateMenu "&Home",MENUHOME,help
+		CreateMenu "&Back",MENUBACK,help
+		CreateMenu "&Forward",MENUFORWARD,help
+		CreateMenu "&Quick Help",MENUQUICKHELP,help,KEY_F1
+		CreateMenu "About Monk",MENUABOUT,help
+		
+		If quickenabled CheckMenu quickenable
+		If debugenabled CheckMenu debugenable
+		If threadedenabled CheckMenu threadedenable
+		If guienabled CheckMenu guienable
+
+		If Not bmxpath
+			DisableMenu buildmods
+			DisableMenu buildallmods
+			DisableMenu docmods
+			DisableMenu importbb
+		EndIf
+		
+?Win32		
+		Local mingw$=getenv_("MINGW")
+		If Not mingw
+			DisableMenu buildmods
+			DisableMenu buildallmods
+		EndIf
+?		
+		If is_demo
+			DisableMenu syncmods
+		EndIf
+		
+		RefreshRecentFiles
+		UpdateWindowMenu window
+	End Method
+
+	Method RunCode()
+		If mode=DEBUGMODE And debugtree.cancontinue
+			output.Go()
+			Return
+		EndIf
+		output.Stop()
+		SaveAll()
+		If lockedpanel
+			lockedpanel.invoke TOOLRUN
+		Else
+			activepanel.invoke TOOLRUN
+		EndIf
+	End Method
+	
+	Method BuildCode()
+		output.Stop()
+		SaveAll()
+		If lockedpanel
+			lockedpanel.invoke TOOLBUILD
+		Else
+			activepanel.invoke TOOLBUILD
+		EndIf
+	End Method
+		
+	Method RefreshBuildOptions()
+		Local monkeybuild
+		Local codepanel:TOpenCode
+				
+		If lockedpanel
+			codepanel=TOpenCode(lockedpanel)
+		Else
+			codepanel=TOpenCode(activepanel)
+		EndIf
+		
+		If codepanel And codepanel.ismonkey
+			DisableMenu quickenable
+			DisableMenu threadedenable
+			DisableMenu guienable
+		Else
+			EnableMenu quickenable
+			EnableMenu threadedenable
+			EnableMenu guienable
+		EndIf
+
+		UpdateWindowMenu window
+
+	End Method
+	
+	Method ShowAbout()
+		Notify (ABOUT.Replace( "{bcc_version}",BCC_VERSION ))
+	End Method
+		
+	Method AddEventHotKey(key,mods,id,data)
+		SetHotKeyEvent key,mods,CreateEvent(id,Null,data)
+	End Method
+		
+	Method InitHotkeys()
+		AddEventHotKey KEY_F5,MODIFIER_NONE,EVENT_MENUACTION,MENURUN
+		AddEventHotKey KEY_F7,MODIFIER_NONE,EVENT_MENUACTION,MENUBUILD
+		AddEventHotKey KEY_ESCAPE,MODIFIER_NONE,EVENT_MENUACTION,MENUESCAPE
+'		AddEventHotKey KEY_BACKSPACE,MODIFIER_NONE,EVENT_MENUACTION,MENUBACKSPACE
+	End Method
+		
+	Method SaveAll()
+		For Local panel:TToolPanel = EachIn panels
+			panel.invoke TOOLQUICKSAVE						
+		Next
+	End Method
+	
+	Method Rethink()
+		If options.archivecode
+			history.EnableHistory(Self)
+		Else
+			history.DisableHistory
+		EndIf
+		
+		If options.runserver 
+			serverpanel.Open(8080)
+		Else
+			serverpanel.Close()
+		EndIf
+		
+	End Method
+	
+	Method Restart()
+		If Confirm("Monk would like to restart.")
+			Quit
+		EndIf
+	End Method
+	
+	Method RefreshAll()	
+' hide/show toolbar
+		If options.showtoolbar Then ShowGadget toolbar Else HideGadget toolbar
+' refresh panels
+		For Local panel:TToolPanel = EachIn panels
+			panel.invoke TOOLREFRESH						
+		Next
+' refresh navbar
+		navbar.invoke TOOLREFRESH
+	End Method
+
+	Method SnapshotWindow()
+		If WindowMaximized(window)
+			winmax=True
+		Else
+			If Not WindowMinimized(window)
+				winmax=False
+				winsize.x=GadgetX(window)
+				winsize.y=GadgetY(window)
+				winsize.w=GadgetWidth(window)
+				winsize.h=GadgetHeight(window)
+			EndIf
+		EndIf
+		options.showtoolbar = Not GadgetHidden(toolbar)
+	End Method
+	
+	Method OnMenu(menu,extra:Object=Null)
+		Local	index
+		
+		Local	tool:TTool = TTool(extra)
+		If tool
+			tool.invoke(TOOLMENU,""+menu)
+			Return
+		EndIf
+	
+		Select menu
+			Case MENUESCAPE
+				currentpanel.invoke TOOLESCAPE
+'			Case MENUBACKSPACE
+'				currentpanel.invoke TOOLBACKSPACE
+			Case MENUNEW
+				OpenSource ""
+			Case MENUOPEN
+				OpenSource "."
+			Case MENUCLOSE
+				currentpanel.invoke TOOLCLOSE
+			Case MENUCLOSEALL
+				CloseAll True
+			Case MENUCLOSEOTHERS
+				CloseAll True, False
+			Case MENUSAVE
+				currentpanel.invoke TOOLSAVE						
+			Case MENUSAVEAS			
+				currentpanel.invoke TOOLSAVEAS						
+			Case MENUSAVEALL
+				SaveAll()
+			Case MENUPRINT
+				currentpanel.invoke TOOLPRINT						
+			Case MENUQUIT,MENUESCAPE
+				Quit()
+			Case MENUGOTO
+				gotoreq.Show()
+			Case MENUFIND
+				currentpanel.invoke TOOLFIND
+			Case MENUFINDNEXT
+				currentpanel.invoke TOOLFINDNEXT
+			Case MENUREPLACE
+				replacereq.Show()
+
+			Case MENUUNDO currentpanel.invoke TOOLUNDO
+			Case MENUREDO currentpanel.invoke TOOLREDO
+
+			Case MENUCUT currentpanel.invoke TOOLCUT
+			Case MENUCOPY currentpanel.invoke TOOLCOPY
+			Case MENUPASTE currentpanel.invoke TOOLPASTE
+			Case MENUSELECTALL currentpanel.invoke TOOLSELECTALL
+										
+			Case MENUBUILD
+				BuildCode()
+			Case MENURUN
+				RunCode()
+
+			Case MENUBUILDMODULES
+				If CheckDemo() BuildModules False
+			Case MENUBUILDALLMODULES
+				If CheckDemo() BuildModules True	
+			'Case MENUSYNCMODS
+			'	If CheckDemo() And CloseAll(False) syncmodsreq.Show
+			Case MENUDOCMODS
+				If CheckDemo() And CloseAll(False) DocMods
+			Case MENUTRIGGERDOCMODS
+				DocMods()
+			Case MENUTRIGGERSYNCDOCS
+				SyncDocs()
+				
+			Case MENUSTEP If output output.StepOver()
+			Case MENUSTEPIN If output output.StepIn()
+			Case MENUSTEPOUT If output output.StepOut()
+			Case MENUSTOP If output output.Stop()
+
+			Case MENULOCKBUILD
+				activepanel.invoke TOOLLOCK
+			Case MENUUNLOCKBUILD
+				If lockedpanel lockedpanel.invoke TOOLUNLOCK
+			
+			Case MENUCOMMANDLINE cmdlinereq.Show
+			
+			Case MENUQUICKENABLED
+				If quickenabled
+					quickenabled=False
+					UncheckMenu quickenable							
+				Else
+					quickenabled=True
+					CheckMenu quickenable
+				EndIf
+				UpdateWindowMenu window
+
+			Case MENUDEBUGENABLED
+				If debugenabled
+					debugenabled=False
+					UncheckMenu debugenable							
+				Else
+					debugenabled=True
+					CheckMenu debugenable
+				EndIf
+				UpdateWindowMenu window
+				
+			Case MENUTHREADEDENABLED
+				If threadedenabled
+					threadedenabled=False
+					UncheckMenu threadedenable							
+				Else
+					threadedenabled=True
+					CheckMenu threadedenable
+				EndIf
+				UpdateWindowMenu window
+				
+			Case MENUGUIENABLED
+				If guienabled
+					guienabled=False
+					UncheckMenu guienable							
+				Else
+					guienabled=True
+					CheckMenu guienable
+				EndIf
+				UpdateWindowMenu window
+
+			Case MENUIMPORTBB
+				ImportBB
+				
+			Case MENUFINDINFILES
+				If activepanel Then searchreq.ShowWithPath( ExtractDir(activepanel.path) ) Else searchreq.Show()
+				
+			Case MENUPROJECTMANAGER
+				projectreq.Open projects
+			Case MENUSHOWCONSOLE
+				If output Then output.Open()
+
+			Case MENUOPTIONS
+				options.Show()
+				
+			Case MENUNEXT
+				If Not currentpanel Return
+				index=currentpanel.index+1
+				If index=panels.length index=0
+				SelectPanel panels[index]
+
+			Case MENUPREV
+				If Not currentpanel Return
+				index=currentpanel.index-1
+				If index<0 index=panels.length-1
+				SelectPanel panels[index]
+			
+			Case MENUQUICKHELP
+				currentpanel.invoke TOOLHELP
+			
+			Case MENUHOME
+				helppanel.Home()
+				SelectPanel helppanel
+			Case MENUBACK
+				helppanel.Back()
+				SelectPanel helppanel
+			Case MENUFORWARD
+				helppanel.Forward()
+				SelectPanel helppanel
+			Case MENUABOUT
+				ShowAbout
+			Case MENUINDENT
+				currentpanel.invoke TOOLINDENT
+			Case MENUOUTDENT
+				currentpanel.invoke TOOLOUTDENT
+				
+			Case MENUNEWVIEW
+				navbar.invoke TOOLNEWVIEW
+				
+		End Select
+		
+		If menu>=MENURECENT
+			Local f:String = String(recentfiles.ValueAtIndex(menu-MENURECENT))
+			If f$ OpenSource f$
+		EndIf
+	End Method
+	
+	Method poll()
+		
+		Local	src:TGadget
+		Local event = WaitEvent()
+				
+		If Not activerequesters.IsEmpty()
+			Select event
+				Case EVENT_MENUACTION
+					src = ActiveGadget()
+					If src And (GadgetClass(src) = GADGET_TEXTFIELD) Then
+						Select EventData()
+							Case MENUSELECTALL
+								ActivateGadget(src)
+							Case MENUCOPY
+								GadgetCopy(src)
+							Case MENUPASTE
+								GadgetPaste(src)
+							Case MENUCUT
+								GadgetCut(src)								
+						EndSelect
+						Return
+					EndIf
+					src = Null					
+					Select EventData()
+						Case MENUESCAPE
+							For Local activerequester:TRequester = EachIn activerequesters
+								activerequester.Hide
+							Next
+							Return
+					End Select
+					
+				Case EVENT_MOUSEENTER,EVENT_MOUSELEAVE,EVENT_GADGETLOSTFOCUS
+					Return
+			End Select
+			
+			For Local activerequester:TRequester = EachIn activerequesters
+				If activerequester.Poll() Then Return
+			Next
+		EndIf
+		
+		For Local handler:TEventHandler = EachIn eventhandlers
+			handler.OnEvent()
+		Next
+		
+		src = TGadget(EventSource())
+
+		Select event
+			Case EVENT_GADGETACTION
+				Select EventSource()
+					Case toolbar
+						Select EventData()
+							Case TB_NEW OpenSource ""
+							Case TB_OPEN OpenSource "."
+							Case TB_CLOSE currentpanel.invoke TOOLCLOSE
+							Case TB_SAVE currentpanel.invoke TOOLSAVE	
+							Case TB_CUT currentpanel.invoke TOOLCUT
+							Case TB_COPY currentpanel.invoke TOOLCOPY
+							Case TB_PASTE currentpanel.invoke TOOLPASTE
+							Case TB_FIND currentpanel.invoke TOOLFIND
+							Case TB_BUILD BuildCode
+							Case TB_BUILDRUN RunCode
+							Case TB_STEP If output output.stepover
+							Case TB_STEPIN If output output.stepin
+							Case TB_STEPOUT If output output.stepout
+							Case TB_STOP If output output.Stop
+							Case TB_HOME helppanel.Home;SelectPanel helppanel
+							Case TB_BACK helppanel.Back;SelectPanel helppanel
+							Case TB_FORWARDS helppanel.Forward;SelectPanel helppanel
+						End Select
+						
+					Case tabbar
+						Local index = EventData()
+						If index>=0 And index<panels.length
+							SelectPanel panels[index]
+						EndIf
+				End Select
+				
+			Case EVENT_WINDOWACCEPT, EVENT_APPOPENFILE
+				OpenSource EventText()
+				
+			Case EVENT_APPTERMINATE
+				Quit()
+				
+			Case EVENT_WINDOWACTIVATE
+				If (src=window) Then SelectPanel currentpanel
+				
+			Case EVENT_WINDOWCLOSE
+				If (src=window) Then Quit()
+				
+			Case EVENT_WINDOWMOVE, EVENT_WINDOWSIZE
+				If (src=window) Then SnapshotWindow()
+				
+			Case EVENT_MENUACTION
+				OnMenu EventData(),EventExtra()
+
+		EndSelect
+	EndMethod
+
+EndType
+
+Function CacheAndLoadText$(url:Object)
+	Local tmpResult$
+	Local tmpBytes:Byte[] = LoadByteArray(url)
+	url = CreateRamStream( tmpBytes, tmpBytes.length, True, False )
+	tmpResult = LoadText(url)
+	TRamStream(url).Close()
+	Return tmpResult
+EndFunction
+
+
+Type TWiki Extends TNode
+
+	Field host:TCodePlay
+	
+	Field indexnode:TNode
+	Field wikinode:TNode
+	Field filesnode:TNode
+	
+	Field menunode:TNode
+	
+	Field wikimenu:TGadget
+
+	Field spider:TCrawler
+	
+	Field wikidir$
+
+	Const ALOOF=0
+	Const INDEXING=1
+	Const CRAWLING=2
+
+	Field state
+
+	Field crawlcount
+
+	Field totalloads
+	Field totalbytes
+	
+	Field dirtytree
+			
+	Method FetchDir(dir$,node:TNode)
+		For Local file$=EachIn LoadDir(wikidir+"/"+dir)
+			Local f:TNode
+			f=node.FindNode(file)					
+			If f=Null
+				f=node.AddNode(file)				
+				dirtytree=True
+			EndIf
+			Local path$=file
+			If dir.Length>0 path=dir+"/"+file
+			Select FileType(wikidir+"/"+path)
+				Case FILETYPE_DIR
+					FetchDir(path,f)
+				Case FILETYPE_FILE
+					spider.LinkFile(path)
+			End Select
+		Next
+	End Method
+	
+	Method OnLoad(dir$,url$,content$)
+
+		SaveText content,wikidir+"/"+url				
+
+		totalloads:+1
+		totalbytes:+content.Length
+		
+		Local parts$[]
+		parts=(dir+"/"+url).Split("/")
+		
+		Local n:TNode
+		n=wikinode
+		For Local part$=EachIn parts	'url.Split("/")
+			Local f:TNode
+			f=n.FindNode(part)
+			If f=Null
+				f=n.AddNode(part)				
+				dirtytree=True
+			EndIf
+			n=f			
+		Next
+
+	End Method
+	
+	Function CreateWiki:TWiki(host:TCodePlay)
+		Local p:TWiki = New TWiki
+
+		p.wikimenu=CreateMenu("Wiki",0,Null)
+		CreateMenu "Refresh",MENUREFRESH,p.wikimenu
+
+		p.wikidir=AppDir+"/wiki"
+		
+		p.SetName("Wiki")
+		p.host=host		
+
+		p.indexnode=p.AddNode("Index")
+
+		p.wikinode=p.AddNode("Offline")
+
+'		p.wikinode=TFolderNode.CreateFolderNode(p.wikidir,TFolderNode.DIRECTORYFOLDER)
+'		p.wikinode.owner=p
+'		p.Append(p.wikinode)
+
+		p.filesnode=p.AddNode("Files")
+		
+		p.setAction(p,TOOLMENU,p)
+
+		p.indexnode.SetAction(p,TOOLMENU,p.indexnode)
+		p.wikinode.SetAction(p,TOOLMENU,p.wikinode)
+		p.filesnode.SetAction(p,TOOLMENU,p.filesnode)
+		
+		p.wikimenu=CreateMenu("Wiki",0,Null)
+		CreateMenu "Refresh",MENUREFRESH,p.wikimenu
+		CreateMenu "Cancel",MENUCANCEL,p.wikimenu
+		
+		p.spider=New TCrawler
+		p.spider.setOwner p
+
+		p.FetchDir "",p.wikinode
+		p.BuildIndex
+		
+		Return p
+	End Function
+
+	Method Invoke(command,argument:Object)
+	
+		DebugLog "Invoke:"+command+","+String(Argument)
+
+		Select command
+		
+			Case TOOLMENU			
+				Local cmd=Int(String(argument))
+				
+				Select cmd				
+					Case 0
+						menunode=TNode(argument)		
+						Select menunode
+							Case Self
+								Return
+								Highlight			
+							Case indexnode
+								indexnode.Highlight
+							Case wikinode
+								wikinode.Highlight
+							Case filesnode
+								filesnode.Highlight
+						End Select		
+						PopupWindowMenu host.window,wikimenu,Self
+					Case MENUREFRESH					
+						Select menunode				
+							Case indexnode
+								Select state
+									Case ALOOF
+										PullIndex
+									Case INDEXING
+										StopIndex
+									Case CRAWLING
+										StopCrawl
+								End Select							
+							Case wikinode
+								Select state
+									Case ALOOF
+										CrawlWiki
+									Case INDEXING
+										StopIndex
+									Case CRAWLING
+										StopCrawl
+								End Select							
+						End Select
+					Case MENUCANCEL			
+							Select menunode								
+								Case indexnode
+									If state=INDEXING StopIndex
+								Case wikinode
+									If state=CRAWLING StopCrawl
+							End Select
+				End Select
+		End Select
+	End Method
+
+	Method BuildFiles()
+	End Method
+	
+	Method BuildIndex()
+		Local index$
+		Local dir$
+		dir=wikidir+"/"+WIKI_SITE_INDEX	
+		If FileType(dir)<>FILETYPE_FILE
+			DebugLog "Problem building wiki index"
+			Return
+		EndIf				
+		indexnode.FreeKids		
+		index=LoadString(dir)					
+		Local words$[]
+		Local i		
+		words=index.Split("<loc>")		
+		For i=1 Until words.Length
+			Local word$=words[i]
+			Local p=word.find("</loc>")
+			If p=-1 Continue			
+			Local title$=word[..p]			
+			If title.startsWith(WIKI_URL)
+				title=title[WIKI_URL.Length..]				
+				Local n:TNode
+				Local href$=WIKI_URL+title+WIKI_ARGS
+				n=indexnode.AddNode(title)				
+				n.SetAction(host.helppanel,TOOLNAVIGATE,href)								
+			EndIf			
+		Next		
+		indexnode.Refresh
+	End Method
+		
+	Method Poll()
+	
+		Select state
+			Case INDEXING
+				If spider.Busy()
+					spider.Poll()
+				Else
+					DebugLog "Finished Index"
+					BuildIndex
+					StopIndex
+				EndIf				
+			Case CRAWLING
+				If spider.Busy()
+					spider.Poll()					
+					crawlcount:+1
+					If crawlcount&31=1						
+						Local count=spider.filelist.Count()						
+						wikinode.SetName "Crawling... "+totalloads+"/"+(count+totalloads)
+						wikinode.Refresh						
+					EndIf
+				Else
+					DebugLog "Finished Crawl"
+					StopCrawl					
+				EndIf
+		End Select
+	End Method
+	
+	Method PullIndex()
+		Local dir$=wikidir
+		
+		If FileType(dir)=FILETYPE_NONE
+			CreateDir dir
+		EndIf			
+
+		If FileType(dir)=FILETYPE_NONE
+			Notify "Wiki unable to use dir "+dir
+			Return
+		EndIf
+		
+		spider.Crawl(WIKI_HOST,WIKI_SITE_INDEX,dir,False)
+
+		state=INDEXING
+			
+		indexnode.SetName "Indexing..."
+		indexnode.Refresh
+
+	End Method
+	
+	Method CrawlWiki()
+		Local dir$=wikidir
+		
+		If FileType(dir)=FILETYPE_NONE
+			CreateDir dir
+		EndIf			
+
+		If FileType(dir)=FILETYPE_NONE
+			Notify "Wiki unable to use dir "+dir
+			Return
+		EndIf
+		
+		spider.Crawl(WIKI_HOST,WIKI_INDEX+WIKI_ARGS,dir,True)
+		state=CRAWLING
+			
+		wikinode.SetName "Crawling..."
+		wikinode.Refresh
+	End Method
+	
+	Method StopCrawl()
+		spider.Stop
+		state=ALOOF
+		wikinode.SetName "Wiki"
+		wikinode.Refresh
+		
+		wikinode.RefreshView
+	End Method
+
+	Method StopIndex()
+		state=ALOOF
+		indexnode.SetName "Index"
+		indexnode.Refresh
+	End Method
+
+End Type
+
+
+Type TCrawler
+	Const CRAWLERLEGS=5
+
+	Field owner:TWiki
+	
+	Field host$
+	Field legs:TGet[CRAWLERLEGS]		
+	Field busycount
+	Field filelist:TList	
+	Field names:TMap	
+	Field cachepath$	
+	Field recurse
+
+	Method New()
+		For Local i=0 Until CRAWLERLEGS
+			legs[i]=New TGet
+		Next
+		filelist=New TList
+		names=New TMap
+	End Method
+	
+	Method SetOwner(wiki:TWiki)
+		owner=wiki
+	End Method
+	
+	Method Stop()
+		Local get:TGet
+		For get=EachIn legs
+			get.Stop
+		Next
+	End Method
+		
+	Method Busy()
+		If filelist.Count()>0 Or busycount>0 Return True
+		Return False
+	End Method
+
+	Method Crawl(host0$,path$,dir0$,recurse0=True)
+		host=host0
+		cachepath=dir0
+		filelist.AddLast(path)
+		recurse=recurse0
+	End Method
+	
+	Method LinkFile(url$)
+		names.Insert url,Null				
+	End Method 
+	
+	Method UpdateContent(url$,content$,headers$)	
+		names.Insert url,content		
+		url=url.Replace("?","%3F")			
+
+		Local cachedir$=cachepath		
+		Local dir$=""
+
+		Local d=url.FindLast("/")		
+		If d>-1
+			dir=url[..d]			
+			url=url[d+1..]
+
+			cachedir$:+cachepath+"/"+dir						
+			If FileType(cachedir)=FILETYPE_NONE
+				CreateDir cachedir
+			EndIf			
+		EndIf		
+		
+		owner.OnLoad dir,url,content
+
+'		DebugLog "wrote "+dir+"/"+url		
+'		DebugLog content
+
+		If Not recurse Return
+
+		Local srch$="href=~q"
+		Local p=0
+		Local q=0
+		While p<content.Length	
+			p=content.Find(srch,p)
+			If p=-1 Exit			
+			p:+srch.Length
+			q=content.Find("~q",p+1)
+			If q=-1 Exit			
+			Local ref$=content[p..q]						
+			If ref.StartsWith("http:") Continue
+			If ref.StartsWith("https:") Continue			
+
+			If ref.Find("?r=")>-1 Continue
+			If ref.Find("?page=")>-1 Continue
+			If ref.EndsWith(".rss") Continue
+
+			If ref.StartsWith("/")
+				ref=ref[1..]				
+				
+				If names.Contains(ref) Continue								
+				
+				DebugLog "crawling "+ref
+
+				names.Insert ref,Null
+				filelist.AddLast ref
+			EndIf						
+		Wend		
+	End Method
+				
+	Method Poll()	
+		Local get:TGet
+		For get=EachIn legs		
+			get.Poll
+			If get.finished And get.url<>Null
+				Local result$=get.result
+				Local url$=get.url				
+				get.url=Null
+				busycount:-1
+				Local header$				
+				Local p=result.Find("~r~n~r~n")				
+				If p<>-1		
+					header=result[..p]
+					result=result[p+4..]					
+					UpdateContent url,result,header										
+				EndIf				
+			EndIf
+		Next
+				
+		For get=EachIn legs
+			If get.url=Null And filelist.Count()>0		
+				Local path$=String(filelist.RemoveFirst())				
+				get.fromHost(host,path)
+				busycount:+1
+			EndIf
+		Next		
+		
+	End Method	
+
+End Type
+	
+
+Type TGet
+
+	Const GETBUFFERSIZE=1200000
+	Const MAXREADSIZE=65536
+	
+	Field socket:TSocket
+	Field ip
+	Field host$
+	Field url$	
+	Field disconnected
+	Field finished
+	Field result$
+
+	Field bytebuffer:Byte[GETBUFFERSIZE+1]
+	Field bytepos
+	
+	Method New()
+	End Method
+	
+	Method fromHost:TGet(host0$,path$,port=80)
+		socket=CreateTCPSocket() 
+		host=host0
+		ip=HostIp(host)
+		url=path
+		disconnected=True
+		bytepos=0
+		finished=False
+		result=""		
+		ConnectSocket socket,ip,port	
+
+'		socket.SetNonBlocking 1
+
+		Return Self
+	End Method
+	
+	Method Stop()
+		CloseSocket socket
+		finished=True
+		url=Null
+	End Method
+	
+	Method Poll()		
+		If finished Return		
+		If url=Null Return		
+
+		If disconnected
+			Local isconnected=SocketConnected(socket)		
+			If isconnected
+				disconnected=False
+				Local msg$				
+				msg = "GET /"+url+" HTTP/1.0~r~n"
+				msg :+ "Host: "+host+"~r~n"
+				msg :+ "User-Agent: MonkClient~r~n"
+				msg :+ "Accept: */*~r~n"
+				msg :+ "~r~n"				
+				Local cmsg:Byte Ptr
+				Local bytes				
+				cmsg=msg.ToCString()
+				bytes=msg.Length				
+				socket.Send(cmsg,bytes)				
+			Else			
+				Return
+			EndIf
+		EndIf
+				
+		Local n=SocketReadAvail(socket)		
+
+		If n>0			
+			If bytepos+n>GETBUFFERSIZE n=GETBUFFERSIZE-bytepos			
+
+			If n=0 'we have buffer overflow
+				DebugLog "Buffer Overflow url="+url+" bytepos="+bytepos
+				finished=True	
+				Return
+			EndIf			
+			
+			If n>MAXREADSIZE n=MAXREADSIZE
+			
+			n=socket.Recv(Varptr bytebuffer[bytepos],n)			
+
+			bytepos:+n		
+		Else
+			Local isconnected=SocketConnected(socket)		
+			If Not isconnected			
+				bytebuffer[bytepos]=0				
+				result=String.FromCString(bytebuffer)
+				finished=True				
+				Return			
+			EndIf
+		EndIf
+				
+	End Method
+	
+End Type
+
+
+
+

BIN
monk.icns


BIN
monk.o


BIN
monktoolbar.png