Модераторы: Vitalik

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> [ENG] SynEdit2.0.3stable + CodeFolding(MyStix0.31), For english users 
:(
    Опции темы
Sep.
Дата 8.9.2006, 18:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 109
Регистрация: 22.7.2004

Репутация: нет
Всего: 6



Mod for highlighting current foldrange looks good, but there too many Repaint calls. If i typing quick, CPU load go up to 40%, and there visual flashing, when press Up or Down. So i decided to write new function, that will repaint only IndentGuides. Now i have 20% load (including statusbar update) and no flashing. And i implement highlighting only for deepest indentguide too.
But there is problem - when i close window, i get AV. I think it because of calling to RepaintGuides when component already destoyed. Is there any standart way to know about destroying?
There is the mod, changes temporary marked as //sepa:
SynEdit.pas
Код

    procedure PaintTextLines(AClip: TRect; const aFirstRow, aLastRow,
      FirstCol, LastCol: integer); virtual;
    procedure PaintGuides(nLine,cRow,ScrolledXBy: integer; rcLine: TRect); //sepa
    procedure RepaintGuides; //sepa
    procedure RecalcCharExtent;

PaintLines
Код

...
        //### Code Folding ###
        // Indent guides painting
        PaintGuides(nLine, cRow, ScrolledXBy, rcLine);//sepa

        {if Length(IndentGuides[nLine - 1]) > 0 then
          begin
...

add to any part of file
Код

procedure TCustomSynEdit.PaintGuides(nLine,cRow,ScrolledXBy: integer; rcLine: TRect);
var
  OldColor,tmpColor: TColor;
  i,j,X,Y,L: integer;
begin
  OldColor := Canvas.Pen.Color;
  L:=0;
  if (CodeFolding.Enabled) and (CodeFolding.IndentGuides) and ((cRow = 1)
  or (RowToLine(cRow) <> RowToLine(cRow - 1))) then begin
    //search deepest foldrange
    for i := fAllFoldRanges.AllCount - 1 downto 0 do
    if (fAllFoldRanges[i].Level > L)and
       (CaretY >= fAllFoldRanges[i].FromLine)and
       (CaretY <= fAllFoldRanges[i].ToLine)
    then
       L:=fAllFoldRanges[i].Level;

    //paint loop
    for i := 0 to fAllFoldRanges.AllCount - 1 do
    with fAllFoldRanges[i] do
      if (not Collapsed) and (not ParentCollapsed)
      and (FromLine < nLine) and (ToLine > nLine) then
      begin
        Y := rcLine.Top;
        X := GetLineIndentChars(Self.Lines, FromLine-1)* CharWidth; //Level * CharWidth * TabWidth;  //###mod IndentGuides calculation fix

        //if fHighlightedFoldRange <> fAllFoldRanges[i] then
        //###mod highlight current IndentGuide
        if (L=Level)and
           (CaretY >= FromLine)and
           (CaretY <= ToLine)
        then Canvas.Pen.Color := clBlack //higlighted
        else Canvas.Pen.Color := clGray;
        //###mod highlight current IndentGuide

        if X - ScrolledXBy > 0 then
        begin
          X := Gutter.RealGutterWidth(Gutter.CharWidth) + X - ScrolledXBy;

          tmpColor := Canvas.Pen.Color;
          if Canvas.Pen.Color=clGray then Canvas.Pen.Color := clWindow
          else Canvas.Pen.Color := rgb(160,160,255); //highlighted color
          Canvas.MoveTo(X, Y);
          Canvas.LineTo(X, rcLine.Bottom);
          Canvas.Pen.Color := tmpColor;

          if LineHeight mod 2 = 0 then
            while Y < rcLine.Bottom do
            begin
              Canvas.MoveTo(X, Y);
              Inc(Y);
              Canvas.LineTo(X, Y);
              Inc(Y);
            end
          else
          begin
            if nLine mod 2 = 1 then
              Inc(Y);

            while Y < rcLine.Bottom do
            begin
              Canvas.MoveTo(X, Y);
              Inc(Y);
              Canvas.LineTo(X, Y);
              Inc(Y);
            end;
          end;
        end;

      end; //paint loop
  end;//if codefolding
  Canvas.Pen.Color := OldColor;
end;

procedure TCustomSynEdit.RepaintGuides;
var
  nLine,cRow,ScrolledXBy: integer;
  rcLine: TRect;
begin
   try
    HideCaret;
    rcLine.Left:=Gutter.RealGutterWidth(Gutter.CharWidth);
    rcLine.Right:=rcLine.Left+CharsInWindow*CharWidth;
    rcLine.Top:=0;
    rcLine.Bottom:=fTextHeight;
    ScrolledXBy:=(LeftChar-1)*CharWidth;
    for nLine:=RowToLine(TopLine) to RowToLine(TopLine)+LinesInWindow do begin
      for cRow := LineToRow(nLine) to LineToRow(nLine+1) -1 do begin
        PaintGuides(nLine,cRow,ScrolledXBy,rcLine);
        rcLine.Top:=rcLine.Bottom;
        inc(rcLine.Bottom, fTextHeight);
      end;
    end;
   finally
     UpdateCaret;
   end;
end;

and change calls to new procedure
TCustomSynEdit.MouseDown
Код

...
    DoOnGutterClick(Button, X, Y)
  end
  else RepaintGuides; //###mod highlight current IndentGuide
  SetFocus;
{$IFNDEF SYN_CLX}
...

DoOnCommandProcessed
Код

...
  if CodeFolding.IndentGuides then begin
    case Command of
      ecCut, ecPaste, ecUndo, ecRedo, ecDeleteLastChar, ecDeleteChar:
        CheckIfAtMatchingKeywords;
    end;
    RepaintGuides; //###mod highlight current IndentGuide
  end;
  //### End Code Folding ###
...

Have you such bug here? If i add exit; to start of TCustomSynEdit.RepaintGuides; then bug moves away.
--------------------
Syn - TotalCommander lister plugin |  SynTree - coders sourcebook  
PM MAIL   Вверх
Seldon
Дата 8.9.2006, 20:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 114
Регистрация: 23.12.2005
Где: Minsk

Репутация: нет
Всего: 2



Цитата(Sep. @  8.9.2006,  18:27 Найти цитируемый пост)
Is there any standart way to know about destroying?

Код

if csDestroying in ComponentState then

--------------------
MiBEditor v2.Alpha 10 - Программерский редактор
PM MAIL WWW   Вверх
Sep.
Дата 8.9.2006, 20:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 109
Регистрация: 22.7.2004

Репутация: нет
Всего: 6



2Seldon
Thanx! Works ok now if i use
Код

procedure TCustomSynEdit.RepaintGuides;
var
  nLine,cRow,ScrolledXBy: integer;
  rcLine: TRect;
begin
   if csDestroying in ComponentState then exit;
   try
    HideCaret;
...

But i found other way =)
TCustomSynEdit.DoOnCommandProcessed
Код

  if CodeFolding.IndentGuides then begin
    case Command of
      ecCut, ecPaste, ecUndo, ecRedo, ecDeleteLastChar, ecDeleteChar:
        CheckIfAtMatchingKeywords;
      ecUp, ecDown, ecPageUp, ecPageDown, ecPageTop, ecPageBottom,
      ecEditorTop, ecEditorBottom, ecGotoXY:
        RepaintGuides;  //###mod highlight current IndentGuide
    end;
  end;
  //### End Code Folding ###

So it repaint indent guides only when needed. I think it more optimized version.
--------------------
Syn - TotalCommander lister plugin |  SynTree - coders sourcebook  
PM MAIL   Вверх
DavidCl0nel
Дата 10.9.2006, 12:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 44
Регистрация: 31.7.2006
Где: Berlin/Germany

Репутация: 1
Всего: 1



>>ecUp, ecDown, ecPageUp, ecPageDown, ecPageTop, ecPageBottom,
>>ecEditorTop, ecEditorBottom, ecGotoXY:
>>   RepaintGuides; 

Then you should have problems, if you move the cursor by clicking somewhere.... Then it isnt Updated. Or is ecGotoXY used, if you click?

I test your PaintGuides Monday. smile


Код
tmpColor := Canvas.Pen.Color;
          if Canvas.Pen.Color=clGray then Canvas.Pen.Color := clWindow
          else Canvas.Pen.Color := rgb(160,160,255); //highlighted color
          Canvas.MoveTo(X, Y);
          Canvas.LineTo(X, rcLine.Bottom);
          Canvas.Pen.Color := tmpColor;

This is your new "bold" guide-code? Why you set it to clWindow? You draw it then white? Why? 
PM MAIL   Вверх
Sep.
Дата 11.9.2006, 06:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 109
Регистрация: 22.7.2004

Репутация: нет
Всего: 6



Цитата
Then you should have problems, if you move the cursor by clicking somewhere

Why? I use call to RepaintGuide from TCustomSynEdit.MouseDown, so all clicks are hooked.
Цитата
This is your new "bold" guide-code? Why you set it to clWindow? You draw it then white? Why? 

Now i repaint guides without repainting window. So if i use BG color when paint highlight line, then i need use BG color when i paint non-highlighted line or there will left non-repainted pixels. I select for highlighting - clBlack dots on light-blue BG, for normal - clGray dots on clWindow BG. You can disable this part of code, and only dots left, without any BG.
--------------------
Syn - TotalCommander lister plugin |  SynTree - coders sourcebook  
PM MAIL   Вверх
DavidCl0nel
Дата 11.9.2006, 10:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 44
Регистрация: 31.7.2006
Где: Berlin/Germany

Репутация: 1
Всего: 1



Ah, I see. I try your code, but have a problem now

Код
X := Gutter.RealGutterWidth(Gutter.CharWidth) + X - ScrolledXBy;

In both new functions he don't know Gutter.CharWidth.

I replaced it with only CharWidth
Код
X := Gutter.RealGutterWidth(CharWidth) + X - ScrolledXBy;

and this works.

Edit: While merging the source with SynMix I see your changes in SynEditMiscClasses. Now it works.

And I changed the code to my own style (red=highlightet, other=grey dots). But it is a better way to redraw now, even tough I dont have such cpu loads while typing. Do you have an old computer? Never mind, it works good now.




Last problem is the Gutter hiding the folding marks if you have a really big font size.
Edit: No you solved it, but the problem with folding keywords in strings and comments is unsolved yet.


Some other things while Merging:
- I dont use it, but what are your changes with SynRegExpr?
- I see your changes in comments in ScanForFoldRanges. It doesn't work yet, right? Uncommenting looks like no change in this behaviour.
- I have definitely delete some code in comments. It is very old sometimes (like the IndentGuides-thing with FreeMem at the end with your AV, you remember). Or my complete new GetSelText has in your code the old version in comments. Or the Bitmap-function that isnt needed or called somewhere. All these things shouldnt work, even if you try to uncomment it. This only confusing a other programmer now. At the end of day i send my source and it should be nearly the same (only my little other wishes "red guides" and my problem with the [...]-sign) should be the difference. It makes it more easy to merge in later versions, if we dont stumble every time over this things.




Это сообщение отредактировал(а) DavidCl0nel - 11.9.2006, 11:20
PM MAIL   Вверх
Seldon
Дата 11.9.2006, 18:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 114
Регистрация: 23.12.2005
Где: Minsk

Репутация: нет
Всего: 2



can I with current codefolding engine do such thing:
user select text, launch some command and selected text become folding region?
--------------------
MiBEditor v2.Alpha 10 - Программерский редактор
PM MAIL WWW   Вверх
DavidCl0nel
Дата 12.9.2006, 10:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 44
Регистрация: 31.7.2006
Где: Berlin/Germany

Репутация: 1
Всего: 1



Answer from mail:

>>I've found that you have:
>>i mean that:
>>look at ending comments.

Right, i have changed it. But for my case it was not important, because i have fold ranges in Keywords, so he is only in the second case-branch.

>>Your solution for KeyDown better than nothing. Post it on forum and we
>>all will think about it =)

It was
Код

procedure TCustomSynEdit.KeyDown(var Key: Word; Shift: TShiftState);
...
  if (ssShift in Shift) and ((Key = 50 {2}) or (Key = 55 {7})) then
    ScanForFoldRanges(fAllFoldRanges, Lines);  
end;

...and it didn't work correctly. It was at the end of the KeyDown, so CommandProcessor has add the character to memo, and I can see it in DebugMode in Lines, but he didn't scan correctly and delete the fold range smile. And the if clause is region-specific, my " is on Shift+2 and / on Shift+7. On other keyboard layouts this wouldn't work. It was only a "hard" try and it didnt work, so we need a better check.

The real procedure from you that he ignore keywords in " or / works, but you have to force the update (like destroy and restore an other keyword), that he handle the other keywords.
Maybe the "CheckIfAtMatchingKeywords" should be changed to work vor whole lines, but it wouldn't work for multiline comments then. Hmm Hmm.



>>And good news for you and other non-russian ppl. Administration are
>>working on translate forum to english. There new sub-forum for SynEdit
>>& SynUniHL on english. Look here if you can't find our thread.
>>http://forum.vingrad.ru/index.php?showforum=255
>>And you can switch language of forum in your user panel, i can say
>>where you need to press. Or look thru online translator.

Weeeh smile It works good now, some of my profile i could change, but there are some other russian words on some places, but it is more easy to handle it now. So I dont need Babylon as much as before. ;)




>>user select text, launch some command and selected text become folding region?
That is no part of the code folding. But I think you can solve it with the other SynMemo-Helper-Controls. Syn has the possibility to AutoComplete text. In Delphi IDE you can for example type "cases" and press Ctrl+J and he replace the word with
Код
    case  of
      : ;
      : ;
    end;

This is also possible to do this with Syn. I haven't work with this, so I have no idea how to exactly do this, but you can download the "real" SynEdit-source code. There are many examples and one is for this AutoComplete. I have tried it only as an user, I haven't engaged how to do this.

But with this you can create such regions by adding the second keyword (and the other part of the code block) with AutoComplete. Then he had to reparse the content and automatically draw foldregions.


Это сообщение отредактировал(а) DavidCl0nel - 12.9.2006, 10:21
PM MAIL   Вверх
Seldon
Дата 12.9.2006, 11:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 114
Регистрация: 23.12.2005
Где: Minsk

Репутация: нет
Всего: 2



no-no smile
user selects text, and he wants it as folding region, i.e. he wants collapse\uncollapse lines that he selected.
Sorry for my bad English  smile Maybe Sep write my question smile I describe him  in Russian what I whant.
--------------------
MiBEditor v2.Alpha 10 - Программерский редактор
PM MAIL WWW   Вверх
DavidCl0nel
Дата 12.9.2006, 13:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 44
Регистрация: 31.7.2006
Где: Berlin/Germany

Репутация: 1
Всего: 1



My english isn't very good too. ;)

Hmm, you want to fold your current selection (independent from all code folding keywords)? That wouldn't be easy.

I could imagine, that you can add the selection text as an foldregion, so he can parse and find this, so you can fold it.
But what the Memo should do, if your selection isn't unique? If you select a block what occur also later in the text? Should it be also possible to fold this? If you add the region he will find this block also.
What is, if you dont want to fold this block or if you edit it, so he can't find the text for foldrange? Maybe then you have add another time the similar (edited) block.
And this foldranges (that he should fold exactly this text) can't saved somewhere.

It's difficult..





Edit: The / " forced rescan can be (needs much cpu i know, but it works...) done in KeyPress.
Код
procedure TCustomSynEdit.KeyPress(var Key: Char);
...
  Rescanforfoldranges;
end;


It is very bad to scan every character you type, but it works to see, that your other procedure works good. But If you remove a charakter with backspace he don't call this procedure, so you had to type an other character to restore the foldrange.
Now we need a little bit more intelligence there...

Это сообщение отредактировал(а) DavidCl0nel - 12.9.2006, 14:32
PM MAIL   Вверх
Sep.
Дата 13.9.2006, 10:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 109
Регистрация: 22.7.2004

Репутация: нет
Всего: 6



Цитата

user selects text, and he wants it as folding region, i.e. he wants collapse\uncollapse lines that he selected.

I think it need to write new procedure in TSynEdit, which simply adds selected text in fFoldRanges but this text will be deleted on next RescanForFoldRanges. So may be it need to add new UserFoldRanges array and add it on each Rescan. I think it isn't so difficult to implement, but have no free time those couple of days =( I'll look for it when have some time, but may be someone implement it faster and better than i =)
Цитата

but there are some other russian words on some places,

Administaration working on this, they wants totally reorganize forum =)

Это сообщение отредактировал(а) Sep. - 13.9.2006, 10:14
--------------------
Syn - TotalCommander lister plugin |  SynTree - coders sourcebook  
PM MAIL   Вверх
DavidCl0nel
Дата 13.9.2006, 14:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 44
Регистрация: 31.7.2006
Где: Berlin/Germany

Репутация: 1
Всего: 1



2 things...


>>but this text will be deleted on next RescanForFoldRanges

At the moment I call it every time in TCustomSynEdit.LinesChanged at the end of procedure. All other KeyDown/KeyPress or such things aren't called everytime. The Delete-Key (not Backspace) wasn't handled by KeyPress... It make some cpu usage, if now always rescan, but if I hold a key down and he adds permanently characters into the memo i got only cpu usage < 10%, and that is not a problem I think.

But I have found a little problem with your Scan-workaround that i use. It has a problem, if you collapse a block above. Some other foldranges after the collapsed foldrange (i have no idea what and why this foldranges) were removed. Do you have this problem too?





>> So may be it need to add new UserFoldRanges array and add it on each Rescan
I wouldn't do that in a new array, because then you have always look in both arrays in all parts of source code.
And I wouldn't add the range as such ("hey there are a part of code from line 12 to 20 that you can fold"), i would add the selected text as a keyword, so the common parse procedure will find it. This was my first idea. So you don't engange "in the middle" of all procedures - you define a new keyword. Reason->Action. That was my idea.
But my version is invalid if you change any character of the foldrange.

Maybe with your idea it is better to handle after editing inside the text. But what is, if you add some lines above it. If the foldranges are updated by the little procedure, that only add or subtract the number of new lines, then it would work. But what is, when he decided to rescan the complete text? Then you can collapse lines 12 to 20, but the text is now from 13 to 21....

Hmm Hmm Hmm.



>>Administaration working on this, they wants totally reorganize forum =)
I have read translated parts of it, but I think now its ok. If I have the complete GUI in english I can navigate good. Elsewhise I never had found the nice bird. ;) So the forumnames maybe had to changed into english. The threads can stay be in russian, and if somebody decided to write it in english like me, than he can do that. I have read something about more than this both languages... even german. That isnt needed....

Это сообщение отредактировал(а) DavidCl0nel - 13.9.2006, 14:54
PM MAIL   Вверх
llutti
Дата 27.9.2006, 02:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 3
Регистрация: 21.9.2006
Где: Blumenau, Brazil

Репутация: 1
Всего: 1



Hi,

  I found a minor bug in the procedure TCustomSynEdit.PaintGutter. When I use the codefolding, the display the number of line in gutter don't work ok.


  The original code:

...
        s := fGutter.FormatLineNumber( cLine );

        //### Code Folding ###
        // Calculate the number to show on gutter
        if CodeFolding.Enabled then
          s := IntToStr(GetRealLineNumber(cLine));  // Problem I found
        //### End Code Folding ###
....

  The new code
...
        s := fGutter.FormatLineNumber( cLine );

        //### Code Folding ###
        // Calculate the number to show on gutter
        if CodeFolding.Enabled then
          s := fGutter.FormatLineNumber(GetRealLineNumber(cLine));  // Problem I found
        //### End Code Folding ###
....



   The best regards,

Luciano
PM MAIL   Вверх
PaulIsh
Дата 1.10.2006, 09:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 2
Регистрация: 30.9.2006

Репутация: нет
Всего: нет



Yearstarday I tried your modified SynEdit. 
I found some bugs:
1. If I paste code from clipboard with enabled codefilding synedit does not show folding images for this code.
  Example for Delphi syntax highlighter:
Код

  begin
    try
      for i := 0 to 10 do
        a := a + 1;
    except
    end;
  end.

2. Second problem for this code, is that folding rule "begin end" works as it defined and fold first begin and first and. But first end in this example finish try except block. Of cource I can define one more folding rule "try end", but I don't need it. So, how can I define block rule, that should not folding?

Если кому надо, могу повторить сообшение по русски smile

Это сообщение отредактировал(а) PaulIsh - 1.10.2006, 10:00
PM MAIL   Вверх
DavidCl0nel
Дата 2.10.2006, 11:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 44
Регистрация: 31.7.2006
Где: Berlin/Germany

Репутация: 1
Всего: 1



@llutti: OK.

@PaulIsh:
1. I dont have this problem with my own folding ranges. Do you your SynUniHighlighter-Way (only use the component) or do you add your own folding ranges like me with SynMemo.CodeFolding.FoldRegions.Add(rtKeyWord....) ?


2. Yes it is a problem. But how he can ignore the first end, if he dont know, that this belongs to try?  So he found the first end, but it is the wrong. If you add the try-end-folding it should works. But you can try to use SynMemo.CodeFolding.FoldRegions.SkipRegions.Add().
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Rules and hints for the forum "SynUniHighlighter"
Vit
Vitalik

Hello, dear user!

This is official forum for SynUniHighlighter component and unofficial forum for SynEdit, Codefolding and all related projects.


Some rules for the forum:

1. Do not create new topic if exactly the same already exists.

2. Don't ask several questions in the same topic. One topic - one question.

3. If discussion changes to far from original topic context, then create a separate thread for new discussion subject.


If you already registered then click here to log in.


If you havent't registered yet then click here and register. You need to type username, password (twice), email (twice) and security code.

Next you need go here and choose English language instead of Russian and press Enter.


Some hints for enghlish-speaking users:

- create new topic;     - create new vote;     - answer to the topic.


With regards, Vit, Vitalik.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | SynUniHighlighter and SynEdit (English Language) | Следующая тема »


 




[ Время генерации скрипта: 0.1730 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.