OSDN Git Service

[YCへマージ]
[winbottle/winbottle.git] / bottleclient / MainForm.pas
index c7e0fbf..e4ace7d 100755 (executable)
@@ -9,16 +9,17 @@ interface
 
 uses
   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
-  Menus, StdCtrls, ComCtrls, BRegExp, BottleDef, BottleSstp,
-  DirectSstp, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient,
-  IdSLPP20, SsParser, ImgList, AppEvnts, TaskTray, StdActns,
+  Menus, StdCtrls, ComCtrls, BRegExp, BottleDef, BottleSstp, DirectSstp,
+//  IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdSLPP20,
+  SsParser, ImgList, AppEvnts, TaskTray, StdActns,
   ActnList, MPlayer, MenuBar, ToolWin,
   IniFiles, ExtCtrls, ShellAPI, Contnrs,
-  ConstEditor, Buttons, Clipbrd, HeadValue, Logs,
-  IdException, HttpThread, IdHTTP, LogDownload,
+  ConstEditor, Buttons, Clipbrd, HeadValue, Logs, MultipleChoiceEditor,
+//  IdException, HttpThread, IdHTTP, LogDownload,
   ScriptConsts, DateUtils, BottleChainRule, BottleChainEvent,
   SakuraSeekerInstance, HEditor, HTSearch, heClasses, heFountain,
-  SakuraScriptFountain, SppList, SurfacePreview, XDOM_2_3_J3;
+  SakuraScriptFountain, SppList, SurfacePreview, XDOM_2_3_J3, SsPlayTime,
+  RegexUtils, StrReplace, StrReplaceDialog, ReplacePresetEditor;
 
 type
   TSurfacePreviewType = (spHint, spEditor);
@@ -122,14 +123,12 @@ type
     mnLeaveThisChannel: TMenuItem;
     N4: TMenuItem;
     mnGotoVote: TMenuItem;
-    mnGotoGLog: TMenuItem;
     mnGoToHelp: TMenuItem;
     btnSend: TButton;
     btnConfirm: TButton;
     btnClear: TButton;
     mnExitAllChannels: TMenuItem;
     actAgreeMessage: TAction;
-    IdSLPP20: TIdSLPP20;
     btnIfGhost: TButton;
     actPrevGhost: TAction;
     actNextGhost: TAction;
@@ -137,7 +136,6 @@ type
     mnNextGhost: TMenuItem;
     actResetGhost: TAction;
     mnResetGhost: TMenuItem;
-    timDisconnectCheckTimer: TTimer;
     DirectSstp: TDirectSstp;
     actDownloadLog: TAction;
     actFMOExplorer: TAction;
@@ -160,7 +158,6 @@ type
     actResetPlugins: TAction;
     N7: TMenuItem;
     mnResetPlugins: TMenuItem;
-    ReplaceDialog: TReplaceDialog;
     actReplace: TAction;
     N10: TMenuItem;
     mnReplace: TMenuItem;
@@ -171,12 +168,29 @@ type
     actAbout: TAction;
     actEditCopy: TEditCopy;
     tbtnSendToLogWindow: TToolButton;
+    SsPlayTime: TSsPlayTime;
+    actUndo: TAction;
+    actRedo: TAction;
+    mnUndo: TMenuItem;
+    mnRedo: TMenuItem;
+    N9: TMenuItem;
+    mnPresetReplaceRoot: TMenuItem;
+    ScriptBackup: TTimer;
+    OpenDialog: TOpenDialog;
+    mnFileOpen: TMenuItem;
+    actFileOpen: TAction;
+    actFileSaveAs: TAction;
+    mnSaveAs: TMenuItem;
+    SaveDialog: TSaveDialog;
+    N11: TMenuItem;
+    mnSave: TMenuItem;
+    actFileSave: TAction;
     procedure actConfirmExecute(Sender: TObject);
     procedure FormCreate(Sender: TObject);
     procedure FormDestroy(Sender: TObject);
     procedure actSendExecute(Sender: TObject);
-    procedure HTTPSuccess(Sender: TObject);
-    procedure HTTPFailure(Sender: TObject);
+//    procedure HTTPSuccess(Sender: TObject);
+//    procedure HTTPFailure(Sender: TObject);
     procedure actStartClick(Sender: TObject);
     procedure actStopExecute(Sender: TObject);
     procedure FormShow(Sender: TObject);
@@ -203,11 +217,11 @@ type
     procedure LabelTimerTimer(Sender: TObject);
     procedure actCopyAllExecute(Sender: TObject);
     procedure actCopyAllNoReturnExecute(Sender: TObject);
-    procedure Slpp20SlppEvent(Sender: TObject; EventType: TIdSlppEventType;
-      const Param: String);
+//    procedure Slpp20SlppEvent(Sender: TObject; EventType: TIdSlppEventType;
+//      const Param: String);
     procedure actSettingExecute(Sender: TObject);
     procedure memScriptKeyPress(Sender: TObject; var Key: Char);
-    procedure Slpp20Disconnect(Sender: TObject);
+//    procedure Slpp20Disconnect(Sender: TObject);
     procedure actClearBottlesExecute(Sender: TObject);
     procedure SakuraSeekerDetectResultChanged(Sender: TObject);
     procedure mnGetNewIdClick(Sender: TObject);
@@ -222,7 +236,6 @@ type
       var Handled: Boolean);
     procedure mnLeaveThisChannelClick(Sender: TObject);
     procedure mnGotoVoteClick(Sender: TObject);
-    procedure mnGotoGLogClick(Sender: TObject);
     procedure tabChannelMouseMove(Sender: TObject; Shift: TShiftState; X,
       Y: Integer);
     procedure mnGoToHelpClick(Sender: TObject);
@@ -239,10 +252,11 @@ type
     procedure actPrevGhostExecute(Sender: TObject);
     procedure actNextGhostExecute(Sender: TObject);
     procedure actResetGhostExecute(Sender: TObject);
-    procedure timDisconnectCheckTimerTimer(Sender: TObject);
+//    procedure timDisconnectCheckTimerTimer(Sender: TObject);
     procedure actDownloadLogExecute(Sender: TObject);
     procedure cbxTargetGhostChange(Sender: TObject);
     procedure actFMOExplorerExecute(Sender: TObject);
+    // \8eÀ\8dÛ\82Ì\8f\88\97\9d\82ÍLogInsertCue\82Ö\88Ú\93®
     procedure actInsertCueExecute(Sender: TObject);
     procedure FormResize(Sender: TObject);
     procedure actCopyExecute(Sender: TObject);
@@ -254,44 +268,56 @@ type
     procedure actRecallScriptBufferExecute(Sender: TObject);
     procedure actEditorPreviewExecute(Sender: TObject);
     procedure actResetPluginsExecute(Sender: TObject);
-    procedure IdSLPP20Connect(Sender: TObject);
+//    procedure IdSLPP20Connect(Sender: TObject);
     procedure actReplaceExecute(Sender: TObject);
-    procedure ReplaceDialogFind(Sender: TObject);
-    procedure ReplaceDialogReplace(Sender: TObject);
     procedure actSendToEditorExecute(Sender: TObject);
     procedure actSendToLogWindowExecute(Sender: TObject);
     procedure memScriptDragOver(Sender, Source: TObject; X, Y: Integer;
       State: TDragState; var Accept: Boolean);
     procedure memScriptDragDrop(Sender, Source: TObject; X, Y: Integer);
     procedure actDeleteLogItemExecute(Sender: TObject);
+    procedure memScriptSelectionChange(Sender: TObject; Selected: Boolean);
+    procedure actUndoExecute(Sender: TObject);
+    procedure actRedoExecute(Sender: TObject);
+//    procedure IdSLPP20ConnectFailed(Sender: TObject);
+    procedure ScriptBackupTimer(Sender: TObject);
+    procedure actFileOpenExecute(Sender: TObject);
+    procedure actFileSaveAsExecute(Sender: TObject);
+    procedure actFileSaveExecute(Sender: TObject);
   private
     FSleeping: boolean;  // \94z\91\97\83X\83\8a\81[\83v\92\86\82©\82Ç\82¤\82©
     FStatusText: String;
-    FConnecting: boolean;
-    FAdded: boolean;
+//    FConnecting: boolean;
+//    FAdded: boolean;
     FBooted: boolean; //\8f\89\89ñ\8bN\93®\92Ê\90M\97p
+//    FEndSession: Boolean; // Windows\8fI\97¹\82ð\8c\9f\92m\82µ\82Ätrue\82É\82È\82é
     FOriginalCaption: String;
-    FAutoAddAfterGetChannel: boolean; //\83`\83\83\83\93\83l\83\8b\8eæ\93¾\8cã\82É\83_\83C\83A\83\8d\83O\82È\82µ\82É
+//    FAutoAddAfterGetChannel: boolean; //\83`\83\83\83\93\83l\83\8b\8eæ\93¾\8cã\82É\83_\83C\83A\83\8d\83O\82È\82µ\82É
                                       //\83`\83\83\83\93\83l\83\8b\82É\8eQ\89Á\82·\82é\82©\82Ç\82¤\82©
     FConstDir: String;
     FSppDir: String;
     //
-    FMutex: THandle; //Mutex\83I\83u\83W\83F\83N\83g\81c\93ñ\8fd\8bN\93®\96h\8e~\97p
+//    FNowChannel: String; //\8c»\8dÝ\91I\91ð\82³\82ê\82Ä\82¢\82é\83`\83\83\83\93\83l\83\8b
+//    JoinChannelsBackup: TStringList; //\88ê\8e\9e\8eg\97p
     //
-    FNowChannel: String; //\8c»\8dÝ\91I\91ð\82³\82ê\82Ä\82¢\82é\83`\83\83\83\93\83l\83\8b
-    JoinChannelsBackup: TStringList; //\88ê\8e\9e\8eg\97p
+//    FScriptModified: boolean; // \83X\83N\83\8a\83v\83g\82ª\95Ï\8dX\82³\82ê\82Ä\82¢\82é\82©\82Ç\82¤\82©\81B
+//                              // \83\8d\81[\83J\83\8b\8am\94F\8b­\90§\97p\83t\83\89\83O\81BTRichEdit.Modified\82Í
+//                              //\95Ê\82Ì\97p\93r\82Å\8eg\82Á\82Ä\82¢\82é\82Ì\82Å\8eg\82¦\82È\82¢
     //
-    FScriptModified: boolean; // \83X\83N\83\8a\83v\83g\82ª\95Ï\8dX\82³\82ê\82Ä\82¢\82é\82©\82Ç\82¤\82©\81B
-                              // \83\8d\81[\83J\83\8b\8am\94F\8b­\90§\97p\83t\83\89\83O\81BTRichEdit.Modified\82Í
-                              //\95Ê\82Ì\97p\93r\82Å\8eg\82Á\82Ä\82¢\82é\82Ì\82Å\8eg\82¦\82È\82¢
+    FScriptBackupModified: boolean; // \83X\83N\83\8a\83v\83g\83o\83b\83N\83A\83b\83v\83t\83\89\83O
+    FScriptBackupFile: string;      // \8c»\8dÝ\82Ì\83o\83b\83N\83A\83b\83v\83t\83@\83C\83\8b\96¼
+    FScriptBackupDir: string;       // \83o\83b\83N\83A\83b\83v\90æ\82Ì\83t\83H\83\8b\83_\96¼
     //
-    FDragTabIndex: integer; //\83^\83u\83h\83\89\83b\83O\83h\83\8d\83b\83v\8aÖ\98A
-    FDragTabDest: integer;  //\83h\83\8d\83b\83v\82·\82é\88Ê\92u(\82·\82®\89E\82É\82­\82é\83^\83u\82Ì\83C\83\93\83f\83b\83N\83X)
+    FFileModified: boolean;       //\83t\83@\83C\83\8b\93à\97e\82ª\95Ï\8dX\82³\82ê\82Ä\82¢\82é\82©\81B
+    FFileName: string;            //\90V\8bK\82©\8aù\91\83t\83@\83C\83\8b\82Ì\94»\92f\81A\82Ü\82½\82Í\8aù\91\83t\83@\83C\83\8b\82Ì\8fê\8f\8a
+    //
+//    FDragTabIndex: integer; //\83^\83u\83h\83\89\83b\83O\83h\83\8d\83b\83v\8aÖ\98A
+//    FDragTabDest: integer;  //\83h\83\8d\83b\83v\82·\82é\88Ê\92u(\82·\82®\89E\82É\82­\82é\83^\83u\82Ì\83C\83\93\83f\83b\83N\83X)
     //
     FBottleSstp: TBottleSstp; // \8dÄ\91\97\83v\83\8d\83O\83\89\83\80
     //
-    FHttp: THTTPDownloadThread; //HTTP\83_\83E\83\93\83\8d\81[\83h\83X\83\8c\83b\83h(\83C\83\93\83X\83^\83\93\83X\82Í1\8cÂ\82Ì\82Ý)
-    FBeginConnectFailCount: integer; //\89½\93x\82à\90Ú\91±\8e¸\94s\82µ\82½\82ç\83\8a\83g\83\89\83C\92\86\8e~
+//    FHttp: THTTPDownloadThread; //HTTP\83_\83E\83\93\83\8d\81[\83h\83X\83\8c\83b\83h(\83C\83\93\83X\83^\83\93\83X\82Í1\8cÂ\82Ì\82Ý)
+//    FBeginConnectFailCount: integer; //\89½\93x\82à\90Ú\91±\8e¸\94s\82µ\82½\82ç\83\8a\83g\83\89\83C\92\86\8e~
     //
     FVisiblePreviewGhost: String;
     FVisiblePreviewSurface: integer; //\83T\81[\83t\83B\83X\83v\83\8c\83r\83\85\81[\82Å\8c©\82¦\82Ä\82¢\82é\82à\82Ì
@@ -304,34 +330,36 @@ type
     //
     FScriptBuffer: TObjectList;  //\83X\83N\83\8a\83v\83g\83N\83\8a\83A\83o\83b\83t\83@
     //
-    //\88È\89º\81A\8d\91\90¨\92²\8d¸\82ð\89ß\93x\82É\91\97\90M\82µ\82È\82¢\82½\82ß\82Ì\95Ï\90\94
-    FLastGhostList: String;    //\83S\81[\83X\83g\83\8a\83X\83g\82Ì\95\8e\9a\97ñ
-    FLastGhostListSend: Int64; //\8d\91\90¨\92²\8d¸\82ð\8dÅ\8cã\82É\91\97\90M\82µ\82½\8e\9e\8d\8f
-    //
     FWM_TaskBarCreated: WORD; // \83^\83X\83N\83o\81[\93o\98^\97p\83E\83B\83\93\83h\83E\83\81\83b\83Z\81[\83WID
     //
-    procedure SetStatusText(const Value: String);
+//    procedure SetStatusText(const Value: String);
     procedure SetSleeping(const Value: boolean);
     procedure YenETrans;
-    procedure SetConnecting(const Value: boolean);
-    procedure SetAdded(const Value: boolean);
+//    procedure SetConnecting(const Value: boolean);
+//    procedure SetAdded(const Value: boolean);
     procedure mnConstClick(Sender: TObject);
     procedure mnConstGroupClick(Sender: TObject);
-    property Added: boolean read FAdded write SetAdded;
+    procedure mnPresetReplaceClick(Sender: TObject);
+//    property Added: boolean read FAdded write SetAdded;
     property Sleeping: boolean read FSleeping write SetSleeping;
-    property StatusText: String read FStatusText write SetStatusText;
+//    property StatusText: String read FStatusText write SetStatusText;
     function GetScriptText: String;
     procedure ChangeTaskIcon;
     procedure ShowHintLabel(const Mes: String; Col: TColor = clBlue);
     procedure UpdateLayout;
-    procedure DispatchBottle(EventType: TIdSlppEventType; Dat: THeadValue);
+//    procedure DispatchBottle(EventType: TIdSlppEventType; Dat: THeadValue);
+    procedure DispatchBottle(Dat: THeadValue; LogTime: TDateTime;
+      Vote, Agree: integer);
     //\83`\83\83\83\93\83l\83\8b\8aÖ\8cW
-    procedure UpdateChannelInfo(Dat: THeadValue);
-    procedure UpdateJoinChannelList(Dat: THeadValue);
-    procedure NoLuidError;
+//    procedure UpdateChannelInfo(Dat: THeadValue);
+//    procedure UpdateJoinChannelList(Dat: THeadValue);
+    procedure UpdateJoinChannelList;
+    procedure UpdateChannelList;
+//    procedure NoLuidError;
     procedure UpdateIfGhostBox;
     function BuildMenuConditionCheck(const IfGhost, Ghost: String): boolean;
     procedure BuildMenu(Root: TMenuItem; Simple: boolean);
+    procedure BuildReplaceMenu(Root: TMenuItem);
     procedure PlaySound(const FileName: String);
     //TBottleSstp\8aÖ\8cW\83C\83x\83\93\83g\83n\83\93\83h\83\89
     procedure BottleSstpResendCountChange(Sender: TObject);
@@ -348,13 +376,31 @@ type
       Before, After: array of String): String; overload;
     function TagReplace(Script: String;
       Before, After: TStrings): String; overload;
+    // \83T\81[\83t\83B\83X\82ð\95Ï\8a·\82·\82é
+    function ReplaceSurface(Script: String; Params: TCollection): String;
     procedure ClearEditor;
     procedure CopyFromLogToEditor(Log: TLogItem);
     //
-    procedure AppendTextLog(const FileName, Line: String);
+    procedure AppendTextLog(const FileName, Line: String; FAppend: boolean);
     procedure AppendXMLLog(const FileName: String; Args: THeadValue);
+    //\8e©\93®\95Û\91\90Ý\92è
+    procedure SetScriptAutoBackup;
+    //\92P\91Ì\83t\83@\83C\83\8b\93ü\8fo\97Í\8aÖ\8cW
+    procedure PerformFileOpen(const AFileName: string);
+    procedure PerformFileSave(const AFileName: string);
+    procedure SetFileName(const FileName: string; Reset, SetNewFile: boolean);
+    function CheckFileModified(Sender: TObject): integer;
+    function FileSave(Sender: TObject): integer;
+    function FileSaveAs(Sender: TObject): integer;
+    procedure EditerStatusChange;
+    procedure SetFileModified(Value: boolean);
+    function CheckFileExt(const FileName: string): boolean;
+    procedure DeleteBackupFile(const FileName: string);
+
   protected
     procedure WndProc(var Message: TMessage); override;
+//    procedure WMQueryEndSession(var msg: TWMQueryEndSession);
+//      message WM_QUERYENDSESSION;
   public
     function DoTrans(var Script: String;
       Options: TScriptTransOptions): String; overload;
@@ -362,17 +408,23 @@ type
       Options: TScriptTransOptions; out FoundURL: boolean): String; overload;
     function ScriptTransForSSTP(const Script: String;
       out Error: String): String; overload;
-    procedure BeginConnect;
-    procedure RetryBeginConnect;
-    procedure EndConnect;
+//    procedure BeginConnect;
+//    procedure RetryBeginConnect;
+//    procedure EndConnect;
     procedure ConstructMenu(Simple: boolean);
-    property Connecting: boolean read FConnecting write SetConnecting;
+//    property Connecting: boolean read FConnecting write SetConnecting;
     property BottleSstp: TBottleSstp read FBottleSstp;
     function GhostNameToSetName(const Ghost: String): String;
-    procedure PostCommand(const Command: array of String); overload;
-    procedure PostCommand(Command: TStrings); overload;
-    procedure PostSetChannel(Channels: TStrings);
+//    procedure PostCommand(const Command: array of String); overload;
+//    procedure PostCommand(Command: TStrings); overload;
+//    procedure PostSetChannel(Channels: TStrings);
     procedure SaveChainRuleList;
+    //DispatchBottle()\82Ö\83o\83C\83p\83X
+    procedure BottleCnv(Log: TLogItem);
+    //\83u\83\89\83E\83U\94»\92f\82ÆURL\88ø\93n\82µ
+    procedure OpenBrowser(const Url: string);
+    //Log\83E\83B\83\93\83h\83E\82©\82ç\8fð\8c\8f\95t\82Å\8cÄ\82Î\82ê\82é
+    procedure LogInsertCue(TestAction, SelectAll: boolean);
   end;
 
 
@@ -390,10 +442,13 @@ const
   IconDisconnected = 18;
   IconSleep        = 19;
   IconSleepDisconnected = 20;
+  IconYC                = 47;
 
   WarningColor = clRed;
 
   SendButtonLongHint = 'Bottle\82Ì\91\97\90M';
+  NewFileTitle       = '\96¼\8fÌ\96¢\92è';     // \90V\8bK\83^\83C\83g\83\8b
+  StdBackupFile      = 'Script.bak';   // FileCheck\8ew\92è\82Ì\8ag\92£\8eq\82ð\8eg\82¤
 
 function Token(const Str: String; const Delimiter: char;
   const Index: integer): String;
@@ -402,8 +457,9 @@ function StringReplaceEx(const Before: String; List: THeadValue): String;
 
 implementation
 
-uses SendConfirm, SettingForm, ChannelListForm, LogForm,
+uses SettingForm, LogForm,
   MessageBox, FMOExplorer, EditorTalkShow;
+//SendConfirm, ChannelListForm,
 
 {$R *.DFM}
 
@@ -461,14 +517,32 @@ end;
 {TfrmSender}
 
 procedure TfrmSender.actConfirmExecute(Sender: TObject);
-var AScript, Err, AGhost: String;
-    Item: TLogItem;
+var
+  AScript, Err, AGhost: String;
+  Item: TLogItem;
+  Choice: integer;
 begin
-  AScript := GetScriptText;
+  // Partial Confirmation
+  if memScript.SelText <> '' then
+  begin
+    Choice := 0;
+    if not Pref.AutoPartialConfirm then
+      if not MultipleChoiceEdit('\8am\94F', ['\91I\91ð\95\94\95ª\82Ì\82Ý', '\83X\83N\83\8a\83v\83g\91S\91Ì'], Choice) then
+        Exit;
+    if Choice = 0 then
+    begin
+      AScript := memScript.SelText;
+      AScript := StringReplace(Pref.PartialConfirmFormat, '|', AScript, []);
+    end else
+      AScript := GetScriptText;
+  end else
+    AScript := GetScriptText;
+  AScript := StringReplace(AScript, #13#10, '', [rfReplaceAll]);
+
   if Length(AScript) = 0 then Exit;
   YenETrans;
   AScript := ScriptTransForSSTP(AScript, Err);
-  if AScript = '' then
+  if Err <> '' then
   begin
     ShowMessage(Err);
     Exit;
@@ -476,8 +550,10 @@ begin
 
   if cbxTargetGhost.ItemIndex > 0 then
     AGhost := cbxTargetGhost.Text
+{ \95K\82¸\8ew\92è\82³\82ê\82é\82Í\82¸
   else if FNowChannel <> '' then
     AGhost := ChannelList.Channel[FNowChannel].Ghost
+}
   else
     AGhost := '';
 
@@ -498,7 +574,7 @@ begin
     Item.Free;
   end;
 
-  FScriptModified := false;
+//  FScriptModified := false;
 end;
 
 procedure TfrmSender.FormCreate(Sender: TObject);
@@ -512,6 +588,8 @@ begin
   FSppDir := ExtractFileDir(Application.ExeName)+'\spp';
   Spps.LoadFromDirectory(FSppDir);
   ConstructMenu(false);
+  BuildReplaceMenu(mnPresetReplaceRoot);
+  FScriptBackupDir := ExtractFileDir(Application.ExeName) + '\temp\';
 
   Str := TStringList.Create;
   try
@@ -523,7 +601,7 @@ begin
         Str.LoadFromFile(ExtractFilePath(Application.ExeName)+'defrule.txt');
         BottleChainRuleList := StringToComponent(Str.Text) as TBottleChainRuleList;
       except
-        Showmessage('defrule.txt\93Ç\82Ý\8d\9e\82Ý\92\86\82É\92v\96½\93I\83G\83\89\81[\82ª\94­\90\82µ\82Ü\82µ\82½\81Bdefrule.txt\82ð\8dÄ\83C\83\93\83X\83g\81[\83\8b\82µ\82Ä\82­\82¾\82³\82¢\81B');
+        ShowMessage('defrule.txt\93Ç\82Ý\8d\9e\82Ý\92\86\82É\92v\96½\93I\83G\83\89\81[\82ª\94­\90\82µ\82Ü\82µ\82½\81Bdefrule.txt\82ð\8dÄ\83C\83\93\83X\83g\81[\83\8b\82µ\82Ä\82­\82¾\82³\82¢\81B');
         Application.Terminate;
         Application.ProcessMessages;
         Exit;
@@ -535,20 +613,6 @@ begin
 
   FOriginalCaption := Self.Caption;
 
-  {$IFDEF NOMUTEX}
-  ShowMessage('\93ñ\8fd\8bN\93®\8b\96\89Â\83o\81[\83W\83\87\83\93\82Å\82·\81B'#13#10 + VersionString);
-  {$ELSE}
-  FMutex := CreateMutex(nil, true, 'SSTPBottleClient2');
-  if GetLastError = ERROR_ALREADY_EXISTS then begin
-    Beep;
-    ShowMessage('SSTP Bottle Client\82Í\93ñ\8fd\8bN\93®\82Å\82«\82Ü\82¹\82ñ');
-    CloseHandle(FMutex);
-    Application.Terminate;
-    Application.ProcessMessages; //WM_QUIT\82ð\97¬\82·
-    Exit;
-  end;
-  {$ENDIF}
-
   UpdateLayout;
   mnShowToolBar.Checked := Pref.ShowToolBar;
   mnShowConstBar.Checked := Pref.ShowConstBar;
@@ -562,7 +626,6 @@ begin
 
   // URL\83W\83\83\83\93\83v\90æ\82ð\83q\83\93\83g\95\8e\9a\97ñ\82Æ\82µ\82Ä\90Ý\92è
   mnGoToHP.Hint := Pref.HomePage;
-  mnGotoGlog.Hint := Pref.GLogPage;
   mnGotoVote.Hint := Pref.VotePage;
   mnGotoHelp.Hint := Pref.HelpPage;
 
@@ -577,6 +640,9 @@ begin
     Application.Terminate;
   end;
 
+  // \8dÄ\90\8e\9e\8aÔ\90\84\92è\83R\83\93\83|\81[\83l\83\93\83g\82É\83p\83\89\83\81\81[\83^\82ð\8ew\92è
+  SsPlayTime.PlayTimeParams := Pref.PlayTimeParams;
+
   // \83\81\83C\83\93\83E\83B\83\93\83h\83E\82Ì\88Ê\92u\82Æ\83T\83C\83Y\82ð\95\9c\8bA
   with Pref.SenderWindowPosition do begin
     Self.Left   := Left;
@@ -593,7 +659,9 @@ begin
   // \83^\83X\83N\83g\83\8c\83C\82É\83A\83C\83R\83\93\82ð\92Ç\89Á
   ChangeTaskIcon;
   // \83`\83\83\83\93\83l\83\8b\8eQ\89Á\8aÖ\8cW\82Ì\83^\83u\82Ì\8f\88\97\9d\82È\82Ç(\83`\83\83\83\93\83l\83\8b\95s\8eQ\89Á\82Å\8f\89\8aú\89»)
-  UpdateJoinChannelList(nil);
+//  UpdateJoinChannelList(nil);
+  //\8f\89\8aú\89»
+  UpdateJoinChannelList;
 
   // SSTP\8dÄ\91\97\83I\83u\83W\83F\83N\83g
   FBottleSstp := TBottleSstp.Create(false);
@@ -621,19 +689,17 @@ begin
     Bottom := Self.Top + Self.Height - 1;
   end;
 
-  if JoinChannelsBackup <> nil then JoinChannelsBackup.Free;
+//  if JoinChannelsBackup <> nil then JoinChannelsBackup.Free;
 
   ScriptConstList.Save;
 
   SaveChainRuleList;
   BottleChainRuleList.Free;
 
-  {$IFDEF BOTTLEMUTEX}
-  ReleaseMutex(FMutex);
-  {$ENDIF}
 end;
 
 
+{
 procedure TfrmSender.SetConnecting(const Value: boolean);
 begin
   FConnecting := Value;
@@ -656,19 +722,30 @@ begin
     Screen.Cursor := crDefault;
   end;
 end;
+}
 
 // \83\81\83b\83Z\81[\83W\91\97\90M
 procedure TfrmSender.actSendExecute(Sender: TObject);
-var Talk, Ghost: String;
-    Command: TStringList;
-    Err: String;
-    F: TextFile;
-begin
-  if Length(GetScriptText) = 0 then begin
+var
+  Talk, AGhost: String;
+//  Command: TStringList;
+  Err: String;
+//  F: TextFile;
+  Item: TLogItem;
+begin
+  //\83t\83\89\83O
+  if not Pref.SendAction then
+  begin
+    ShowHintLabel('\93®\8dì\82ª\96¢\90Ý\92è\82Å\82·');
+    Exit;
+  end;
+  if Length(GetScriptText) = 0 then
+  begin
     ShowMessage('\83X\83N\83\8a\83v\83g\82ª\8bó\82Å\82·\81B');
     Exit;
   end;
 
+{
   if Pref.LUID = '' then begin
     NoLuidError;
     Exit;
@@ -683,8 +760,20 @@ begin
     ShowMessage(FNowChannel + ' \82Í\8eó\90M\90ê\97p\82Å\82·');
     Exit;
   end;
+}
 
-  if Pref.NeedConfirmBeforeSend and FScriptModified then begin
+  YenETrans;
+  Talk := StringReplace(GetScriptText, #13#10, '', [rfReplaceAll]);
+  Err := DoTrans(Talk, [toWarnMessySurface, toWarnCheck]);
+  if Err <> '' then
+  begin
+    MessageDlg(Err, mtWarning, [mbOk], 0);
+    Exit;
+  end;
+
+{
+  if Pref.NeedConfirmBeforeSend and FScriptModified then
+  begin
     MessageDlg('\91\97\90M\91O\82É\83\8d\81[\83J\83\8b\8am\94F\82µ\82Ä\82­\82¾\82³\82¢\81B', mtError, [mbOk], 0);
     Exit;
   end;
@@ -692,19 +781,32 @@ begin
   if not Pref.NoConfirm then begin
     if not SendConfirmDialog(FNowChannel, cbxTargetGhost.Text) then Exit;
   end;
+}
 
-  YenETrans;
-  Talk := GetScriptText;
-  Err := DoTrans(Talk, [toWarnMessySurface, toWarnCheck]);
-  if Err <> '' then begin
-    MessageDlg(Err, mtWarning, [mbOk], 0);
-    Exit;
+  AGhost := '';
+  if cbxTargetGhost.ItemIndex > 0 then AGhost := cbxTargetGhost.Text;
+  //\92P\91Ì\83A\83N\83V\83\87\83\93
+  Item := TLogItem.Create;
+  try
+    with Item do
+    begin
+      MID := '';
+      Channel := 'local';
+      LogTime := now();
+      Script := Talk;
+      Ghost := AGhost;
+      Votes := 0;
+      Agrees := 0;
+    end;
+    BottleCnv(Item);
+  except
+    Item.Free;
   end;
-  Command := nil;
-  Ghost := '';
-  if cbxTargetGhost.ItemIndex > 0 then Ghost := cbxTargetGhost.Text;
+  ShowHintLabel('[local]\82Ö\91\97\90M\82µ\82Ü\82µ\82½');
+
+{
+  Command := TStringList.Create;
   try
-    Command := TStringList.Create;
     with Command do begin
       Add('Command: sendBroadcast');
       Add('Channel: ' + FNowChannel);
@@ -727,8 +829,10 @@ begin
   WriteLn(F, Format('%s,%s,%s,%s', [FNowChannel, Ghost, FormatDateTime('yy/mm/dd hh:nn:ss', Now), Talk]));
   Flush(F);
   CloseFile(F);
+}
 end;
 
+{
 procedure TfrmSender.BeginConnect;
 begin
   if Pref.LUID = '' then begin
@@ -737,45 +841,30 @@ begin
   end;
   IdSlpp20.LUID := Pref.LUID;
   self.Cursor := crHourGlass;
-  try
-    if IdSlpp20.Connected then IdSlpp20.Disconnect;
-    if Pref.UseHttpProxy then begin
-      IdSlpp20.Host := Pref.ProxyAddress;
-      IdSlpp20.Port := Pref.ProxyPort;
-      IdSlpp20.ProxyMode := true;
-    end else begin
-      IdSlpp20.Host := 'bottle.mikage.to';
-      IdSlpp20.Port := 9871;
-      IdSlpp20.ProxyMode := false;
-    end;
-    IdSlpp20.Connect;
-  except
-    on EIdException do begin
-      Added := false;
-      if FBeginConnectFailCount = 0 then begin
-        Inc(FBeginConnectFailCount);
-        Beep;
-        if Pref.UseHttpProxy then
-          ShowMessage('HTTP Proxy\82ð\92Ê\82\82ÄSSTP Bottle\83T\81[\83o\82É\90Ú\91±\82Å\82«\82Ü\82¹\82ñ\82Å\82µ\82½\81B'#13#10 +
-                      '\83l\83b\83g\83\8f\81[\83N\82Ì\8fó\91Ô\81EProxy\82Ì\8fó\91Ô\82ð\8am\94F\82µ\82Ä\82­\82¾\82³\82¢\81B'#13#10 +
-                      '\82 \82é\82¢\82Í\83T\81[\83o\82ª\83_\83E\83\93\82µ\82Ä\82¢\82é\89Â\94\\90«\82ª\82 \82è\82Ü\82·\81B')
-        else
-          ShowMessage('SSTP Bottle\83T\81[\83o\82É\90Ú\91±\82Å\82«\82Ü\82¹\82ñ\82Å\82µ\82½\81B'#13#10 +
-                      '\83l\83b\83g\83\8f\81[\83N\82É\8cq\82ª\82Á\82Ä\82¢\82é\82©\8am\94F\82µ\82Ä\82­\82¾\82³\82¢\81B'#13#10 +
-                      '\82 \82é\82¢\82Í\83T\81[\83o\82ª\83_\83E\83\93\82µ\82Ä\82¢\82é\89Â\94\\90«\82ª\82 \82è\82Ü\82·\81B');
-      end else
-        Inc(FBeginConnectFailCount);
-    end;
+  if IdSlpp20.Connected then IdSlpp20.Disconnect;
+  if Pref.UseHttpProxy then begin
+    IdSlpp20.Host := Pref.ProxyAddress;
+    IdSlpp20.Port := Pref.ProxyPort;
+    IdSlpp20.ProxyMode := true;
+  end else begin
+    IdSlpp20.Host := Pref.BottleServer;
+    IdSlpp20.Port := Pref.BottleServerPort;
+    IdSlpp20.ProxyMode := false;
   end;
+  IdSlpp20.ConnectServer;
   self.Cursor := crDefault;
 end;
+}
 
+{
 procedure TfrmSender.EndConnect;
 begin
   IdSlpp20.OnDisconnect := nil;
   IdSlpp20.Disconnect;
 end;
+}
 
+{
 procedure TfrmSender.SetAdded(const Value: boolean);
 begin
   if FAdded = Value then Exit;
@@ -789,7 +878,9 @@ begin
     ShowHintLabel('SSTP Bottle\83T\81[\83o\82©\82ç\90Ø\92f\82³\82ê\82Ü\82µ\82½!', WarningColor);
   end;
 end;
+}
 
+{
 procedure TfrmSender.HTTPSuccess(Sender: TObject);
 var Str, ResStr, Command: String;
     HeadValue: THeadValue;
@@ -803,7 +894,8 @@ begin
     try
       HeadValue := THeadValue.Create(Str);
     except
-      ShowMessage('SSTP Bottle\83T\81[\83o\82ª\89ð\90Í\82Å\82«\82È\82¢\83G\83\89\81[\82ð\95Ô\82µ\82Ü\82µ\82½\81B');
+      Beep;
+      frmMessageBox.ShowMessage('SSTP Bottle\83T\81[\83o\82ª\89ð\90Í\82Å\82«\82È\82¢\83G\83\89\81[\82ð\95Ô\82µ\82Ü\82µ\82½\81B');
       Exit;
     end;
     Command := HeadValue['Command'];
@@ -811,11 +903,11 @@ begin
     if ResStr = 'Err' then begin
       if HeadValue['ExtraMessage'] <> '' then begin
         Beep;
-        ShowMessage('SSTP Bottle\83T\81[\83o\82ª\8e\9f\82Ì\83G\83\89\81[\82ð\95Ô\82µ\82Ü\82µ\82½:'#13#10 +
+        frmMessageBox.ShowMessage('SSTP Bottle\83T\81[\83o\82ª\8e\9f\82Ì\83G\83\89\81[\82ð\95Ô\82µ\82Ü\82µ\82½:'#13#10 +
                      HeadValue['ExtraMessage']);
       end else begin
         Beep;
-        ShowMessage('SSTP Bottle\83T\81[\83o\82ª\89½\82ç\82©\82Ì\83G\83\89\81[\82ð\95Ô\82µ\82Ü\82µ\82½\81B');
+        frmMessageBox.ShowMessage('SSTP Bottle\83T\81[\83o\82ª\89½\82ç\82©\82Ì\83G\83\89\81[\82ð\95Ô\82µ\82Ü\82µ\82½\81B');
       end;
     end;
     if (Command = 'sendBroadcast') and (ResStr = 'OK') then begin
@@ -888,7 +980,7 @@ begin
     if (Command = 'setChannels') then begin
       if ResStr <> 'OK' then begin
         Beep;
-        ShowMessage('\83`\83\83\83\93\83l\83\8b\90Ý\92è\82É\8e¸\94s\82µ\82Ü\82µ\82½\81B\82à\82¤\88ê\93x\93o\98^\82µ\82È\82¨\82µ\82Ä\82­\82¾\82³\82¢');
+        frmMessageBox.ShowMessage('\83`\83\83\83\93\83l\83\8b\90Ý\92è\82É\8e¸\94s\82µ\82Ü\82µ\82½\81B\82à\82¤\88ê\93x\93o\98^\82µ\82È\82¨\82µ\82Ä\82­\82¾\82³\82¢');
         ShowHintLabel('\83`\83\83\83\93\83l\83\8b\90Ý\92è\82É\8e¸\94s\82µ\82Ü\82µ\82½', WarningColor);
       end;
     end;
@@ -897,9 +989,12 @@ begin
     HeadValue.Free;
   end;
 end;
+}
 
 procedure TfrmSender.actStartClick(Sender: TObject);
 begin
+  ShowHintLabel('SSTP Bottle\83T\81[\83o\82É\82Í\90Ú\91±\82Å\82«\82Ü\82¹\82ñ', WarningColor);
+{
   if Pref.LUID = '' then begin
     NoLuidError;
     Exit;
@@ -912,35 +1007,41 @@ begin
     FAutoAddAfterGetChannel := false;
     PostCommand(['Command: getChannels']);
   end;
+}
 end;
 
 procedure TfrmSender.actStopExecute(Sender: TObject);
 begin
+  ShowHintLabel('SSTP Bottle\83T\81[\83o\82É\82Í\90Ú\91±\82Å\82«\82Ü\82¹\82ñ', WarningColor);
+{
   // \8b­\90§\8dÄ\90Ú\91±\82ð\8ds\82¤
-  IdSlpp20.OnDisconnect := nil;
-  if IdSlpp20.Connected then IdSlpp20.Disconnect;
-  FAutoAddAfterGetChannel := true;
-  BeginConnect;
-  IdSlpp20.OnDisconnect := Slpp20Disconnect;
+  FBeginConnectFailCount := 0; // \8e©\93®\8dÄ\90Ú\91±\83J\83E\83\93\83^\83\8a\83Z\83b\83g
+  RetryBeginConnect;
+}
 end;
 
 procedure TfrmSender.FormShow(Sender: TObject);
 begin
   if FBooted or Application.Terminated then Exit;
+{
   //LUID\82ª\8eæ\93¾\82³\82ê\82Ä\82¢\82ê\82Î\91\81\91¬\93o\98^\81B\82»\82¤\82Å\82È\82¯\82ê\82ÎLUID\8eæ\93¾\81B
   if Pref.LUID <> '' then BeginConnect
   else mnGetNewIdClick(Self);
   FAutoAddAfterGetChannel := Pref.AutoStart;
+}
   FBooted := true;
-  frmLog.Show;
+  if NOT Pref.NotShowLog then frmLog.Show;  // \8bN\93®\8e\9e\82É\83\8d\83O\83E\83B\83\93\83h\83E\82ð\95\\8e¦\82·\82é\82©
   frmSurfacePreview.Show;
   Self.Show;
   SakuraSeeker.BeginDetect;
   SakuraSeekerDetectResultChanged(self);
-  if SakuraSeeker.Count = 0 then
+  SetScriptAutoBackup;                      // \8e©\93®\95Û\91\90Ý\92è\82Ì\83\8d\81[\83h
+{
+  if (SakuraSeeker.Count = 0) and (Pref.NotWarnGhostIsntExists = False) then
     frmMessageBox.ShowMessage('\83S\81[\83X\83g(SSTP\83T\81[\83o)\82ª1\82Â\82à\8bN\93®\82µ\82Ä\82¢\82Ü\82¹\82ñ\81B'#13#10 +
       'SSTP Bottle\82ð\97\98\97p\82·\82é\82½\82ß\82É\82Í\81A\83S\81[\83X\83g\82ð\93¯\8e\9e\82É\8bN\93®\82µ\82Ä\82­\82¾\82³\82¢\81B'#13#10 +
       '\8fÚ\8d×\82Í\83w\83\8b\83v\82ð\82²\97\97\89º\82³\82¢\81B');
+}
 end;
 
 procedure TfrmSender.actAboutClick(Sender: TObject);
@@ -971,11 +1072,29 @@ begin
 end;
 
 procedure TfrmSender.memScriptChange(Sender: TObject);
-var Script: String;
 begin
+  //\83G\83f\83B\83^\93à\97e\82ª\95Ï\8dX\82³\82ê\82½\82Æ\82«
+  EditerStatusChange;             // \83X\83e\81[\83^\83X\8dX\90V\82Ö
+  FScriptBackupModified := true;  // \8e©\93®\95Û\91\8dÄ\8aJ
+  SetFileModified(true);          // \83t\83@\83C\83\8b\95Ï\8dX\83t\83\89\83O
+end;
+
+procedure TfrmSender.EditerStatusChange;
+var
+  Script: String;
+  Text: String;
+begin
+  // \83X\83e\81[\83^\83X\95Ï\8dX
+  // \93à\97e\82ª\83h\83\89\83b\83O\82³\82ê\82½\82Æ\82«\82à\8cÄ\82Ñ\8fo\82³\82ê\82é
   Script := StringReplace(GetScriptText, #13#10, '', [rfReplaceAll]);
-  StatusBar.Panels[PanelBytes].Text := IntToStr(length(Script)) + '\83o\83C\83g';
-  FScriptModified := true;
+  if Pref.NotScriptTime then
+    // \83o\83C\83g\90\94\82¾\82¯\95\\8e¦
+    Text := Format('%d\83o\83C\83g', [Length(Script)])
+  else
+    // \83o\83C\83g\90\94\81{\97\\91ª\8e\9e\8aÔ\95\\8e¦
+    Text := Format('%d\83o\83C\83g/%d\95b', [Length(Script), SsPlayTime.PlayTime(Script) div 1000]);
+  StatusBar.Panels[PanelBytes].Text := Text;
+//  FScriptModified := true;
   EditorPreview;
 end;
 
@@ -1024,7 +1143,7 @@ end;
 
 procedure TfrmSender.FormClose(Sender: TObject; var Action: TCloseAction);
 begin
-  EndConnect;
+//  EndConnect;
   TaskTray.Registered := false;
 end;
 
@@ -1064,18 +1183,20 @@ end;
 
 procedure TfrmSender.ChangeTaskIcon;
 var Ico: TIcon;
-    IcoNum: integer;
+//    IcoNum: integer;
 begin
+{
   if Added then begin
     if Sleeping then IcoNum := IconSleep else IcoNum := IconConnected;
   end else begin
     if Sleeping then IcoNum := IconSleepDisconnected
     else IcoNum := IconDisconnected;
   end;
+}
   try
     Ico := TIcon.Create;
     try
-      imgIcon.GetIcon(IcoNum, Ico);
+      imgIcon.GetIcon(IconYC, Ico);  // IconNum
       TaskTray.Icon := Ico;
       TaskTray.Registered := true;
     finally
@@ -1088,11 +1209,13 @@ begin
   end;
 end;
 
+{
 procedure TfrmSender.SetStatusText(const Value: String);
 begin
   FStatusText := Value;
   StatusBar.Panels[PanelStatus].Text := Value;
 end;
+}
 
 procedure TfrmSender.ApplicationEventsHint(Sender: TObject);
 var id: integer;
@@ -1101,6 +1224,7 @@ begin
   begin
     StatusBar.Panels[PanelStatus].Text := GetLongHint(Application.Hint);
     Application.HintColor := clInfoBk;
+{ \91\97\90M\83{\83^\83\93\8aÖ\98A
     if (Application.Hint = SendButtonLongHint)
     and (FNowChannel <> '') then
     begin
@@ -1108,6 +1232,7 @@ begin
       Application.HintColor := clYellow;
       Application.ActivateHint(Mouse.CursorPos);
     end;
+}
     if IsSurfaceTag(Application.Hint, id) and Pref.SurfacePreviewOnHint then
     begin
       // \83T\81[\83t\83B\83X\83v\83\8c\83r\83\85\81[
@@ -1128,6 +1253,9 @@ begin
   //ConstMenuBar.Menu := nil;
   ConstMenuBar.AutoSize := false;
   ConstMenuBar.Width := 1000;
+  // \83\81\83j\83\85\81[\82ð\88ê\93x\8fÁ\82·
+  // \82È\82º\82©2\89ñ\96Ú\88È\8d~\82Ì\95\\8e¦\82ª\82¨\82©\82µ\82­\82È\82é
+  ConstMenuBar.Menu := nil;
   ConstMenuBar.Menu := ConstBarMenu;
   ConstMenuBar.AutoSize := true;
 end;
@@ -1188,7 +1316,7 @@ begin
     SynchronizedColor.Color := Pref.TalkColorS;
   end;
   memScript.Ruler.Visible := Pref.ShowRuler;
-  memScript.Ruler.Color := Pref.TalkColorH;
+  memScript.Ruler.Color := Pref.TextColor;
   memScript.Color := Pref.BgColor;
 
   ToolBar.Visible := Pref.ShowToolBar;
@@ -1201,6 +1329,7 @@ begin
       tpTop:    Align  := alTop;
       tpBottom: Align := alBottom;
     end;
+    TabWidth := Pref.TabWidth;
   end;
 end;
 
@@ -1311,8 +1440,8 @@ begin
         Script := Script + '\h';
         for i := 0 to UrlCount-1 do begin
           Script := Script + Format('\n{%s}(%s)', [UrlName[i], Url[i]]);
-          Script := Script + Format('\n{%s}', [UrlCancel]);
         end;
+        Script := Script + Format('\n{%s}', [UrlCancel]);
       end;
     end else
       FoundUrl := false;
@@ -1365,7 +1494,7 @@ end;
 
 procedure TfrmSender.mnGoToHPClick(Sender: TObject);
 begin
-  ShellExecute(Handle, 'open', PChar(Pref.HomePage), nil, nil, SW_SHOW);
+  OpenBrowser(Pref.HomePage);
 end;
 
 procedure TfrmSender.ShowHintLabel(const Mes: String; Col: TColor);
@@ -1402,6 +1531,7 @@ begin
   Clip.SetTextBuf(PChar(Str));
 end;
 
+{
 procedure TfrmSender.Slpp20SlppEvent(Sender: TObject; EventType: TIdSlppEventType;
   const Param: String);
 var HeadValue: THeadValue;
@@ -1413,15 +1543,24 @@ begin
         //\83\81\83b\83Z\81[\83W\8eó\90M
         DispatchBottle(EventType, HeadValue);
       end;
+
       etMemberCount: begin
+        //\91\8d\8eQ\89Á\8eÒ\90\94
         StatusBar.Panels[PanelMembers].Text := HeadValue['Num'] + '\90l'
       end;
+
       etChannelCount: begin
+        //\83`\83\83\83\93\83l\83\8b\95Ê\8eQ\89Á\8eÒ\90\94
         try
-          ChannelList.Channel[HeadValue['Channel']].Members := StrToInt(HeadValue['Num']);
+          if HeadValue['Channel'] <> '' then begin
+            if ChannelList.Channel[HeadValue['Channel']] <> nil then begin
+              ChannelList.Channel[HeadValue['Channel']].Members := StrToInt(HeadValue['Num']);
+            end;
+          end;
         except
         end;
       end;
+
       etConnectOk: begin
         ShowHintLabel('SSTP Bottle\83T\81[\83o\82Æ\92Ê\90M\8am\97§\81B');
         Added := true;
@@ -1429,34 +1568,50 @@ begin
         //\83`\83\83\83\93\83l\83\8b\8e©\93®\93o\98^
         if not Connecting then
           PostCommand(['Command: getChannels']);
-        SakuraSeeker.BeginDetect;
+        try
+          SakuraSeeker.BeginDetect;
+        except
+          on E: Exception do ShowHintLabel(E.Message,WarningColor);
+        end;
       end;
+
       etChannelList: begin
         UpdateJoinChannelList(HeadValue);
         // \8dÅ\8cã\82É\8eQ\89Á\82µ\82Ä\82¢\82½\83`\83\83\83\93\83l\83\8b\82ð\8bL\98^\82·\82é
         if JoinChannelsBackup = nil then JoinChannelsBackup := TStringList.Create;
         JoinChannelsBackup.Assign(JoinChannels);
       end;
+
       etCloseChannel: begin
-        with JoinChannels do
-          if IndexOf(HeadValue['Channel']) >= 0 then
-            Delete(IndexOf(HeadValue['Channel']));
-        with tabChannel do begin
-          if Tabs.IndexOf(HeadValue['Channel']) >= 0 then
-            Tabs.Delete(Tabs.IndexOf(HeadValue['Channel']));
-          if Tabs.Count > 0 then TabIndex := 0 else TabIndex := -1;
-          tabChannelChange(self);
+        //\83`\83\83\83\93\83l\83\8b\94p\8e~
+        if HeadValue['Channel'] <> '' then begin
+          with JoinChannels do
+            if IndexOf(HeadValue['Channel']) >= 0 then
+              Delete(IndexOf(HeadValue['Channel']));
+          with tabChannel do begin
+            if Tabs.IndexOf(HeadValue['Channel']) >= 0 then
+              Tabs.Delete(Tabs.IndexOf(HeadValue['Channel']));
+            if Tabs.Count > 0 then TabIndex := 0 else TabIndex := -1;
+            tabChannelChange(self);
+          end;
+          ShowHintLabel(HeadValue['Channel'] + '\83`\83\83\83\93\83l\83\8b\82Í\94p\8e~\82³\82ê\82Ü\82µ\82½',
+                        WarningColor);
+          frmLog.AddCurrentSystemLog('SYSTEM', HeadValue['Channel'] + '\83`\83\83\83\93\83l\83\8b\82Í\94p\8e~\82³\82ê\82Ü\82µ\82½');
+          frmMessageBox.ShowMessage(HeadValue['Channel'] + '\83`\83\83\83\93\83l\83\8b\82Í\94p\8e~\82³\82ê\82Ü\82µ\82½');
         end;
-        ShowHintLabel(HeadValue['Channel'] + '\83`\83\83\83\93\83l\83\8b\82Í\94p\8e~\82³\82ê\82Ü\82µ\82½',
-                      WarningColor);
-        frmLog.AddCurrentSystemLog('SYSTEM', HeadValue['Channel'] + '\83`\83\83\83\93\83l\83\8b\82Í\94p\8e~\82³\82ê\82Ü\82µ\82½');
-        frmMessageBox.ShowMessage(HeadValue['Channel'] + '\83`\83\83\83\93\83l\83\8b\82Í\94p\8e~\82³\82ê\82Ü\82µ\82½');
       end;
+
       etForceBroadcastInformation: begin
-        if HeadValue['Type'] = 'Vote' then begin
-          frmLog.VoteLog(HeadValue['MID'], StrToIntDef(HeadValue['Num'], 0));
-        end else if HeadValue['Type'] = 'Agree' then begin
-          frmLog.AgreeLog(HeadValue['MID'], StrToIntDef(HeadValue['Num'], 0));
+        //\93\8a\95[\81^\93¯\88Ó\81^\82»\82Ì\91¼\83u\83\8d\81[\83h\83L\83\83\83X\83g\8fî\95ñ
+        if HeadValue['MID'] <> '' then begin
+          try //Num\82ª\90\94\92l\82Å\82È\82©\82Á\82½\82Æ\82«\91Î\8dô
+            if HeadValue['Type'] = 'Vote' then begin
+              frmLog.VoteLog(HeadValue['MID'], StrToIntDef(HeadValue['Num'], 0));
+            end else if HeadValue['Type'] = 'Agree' then begin
+              frmLog.AgreeLog(HeadValue['MID'], StrToIntDef(HeadValue['Num'], 0));
+            end;
+          except
+          end;
         end;
       end;
     end;
@@ -1464,12 +1619,13 @@ begin
     HeadValue.Free;
   end;
 end;
+}
 
 procedure TfrmSender.BottleSstpResendCountChange(Sender: TObject);
 begin
   StatusBar.Panels[PanelCount].Text := IntToStr(FBottleSstp.CueCount) + '\8c\8f';
   try
-    TaskTray.TipString := 'SSTP Bottle Client (' +
+    TaskTray.TipString := 'Yasagure Client (' +
                           IntToStr(FBottleSstp.CueCount) + '\8c\8f)';
   except
     ; // \83^\83X\83N\83g\83\8c\83C\93o\98^\8e¸\94s\82ð\96³\8e\8b\82·\82é
@@ -1478,7 +1634,10 @@ begin
 end;
 
 procedure TfrmSender.actSettingExecute(Sender: TObject);
+var
+  FTBackupMode: boolean;
 begin
+  FTBackupMode := Pref.ScriptBackupMode;
   Application.CreateForm(TfrmSetting, frmSetting);
   try
     frmSetting.Execute;
@@ -1489,9 +1648,16 @@ begin
     frmSetting := nil;
   end;
   //
+  BuildReplaceMenu(mnPresetReplaceRoot);
   UpdateLayout;
   tabChannel.Repaint;
   frmLog.UpdateWindow;
+  SetScriptAutoBackup;  //\83X\83N\83\8a\83v\83g\8e©\93®\95Û\91\90Ý\92è\8dX\90V
+  UpdateChannelList;    //\83`\83\83\83\93\83l\83\8b\83S\81[\83X\83g\8dÄ\83\8d\81[\83h
+
+  // \83o\83b\83N\83A\83b\83v\83\82\81[\83h\82ª\95Ï\8dX\82³\82ê\82½\82Æ\82«FScriptBackupFile\82à\95Ï\8dX\82·\82é
+  if FTBackupMode <> Pref.ScriptBackupMode then
+    SetFileName(FFileName, false, false);
 end;
 
 procedure TfrmSender.memScriptKeyPress(Sender: TObject; var Key: Char);
@@ -1499,6 +1665,7 @@ begin
   if (Key = #13) or (Key = #10) then Key := Char(0);
 end;
 
+{
 procedure TfrmSender.Slpp20Disconnect(Sender: TObject);
 begin
   Added := false;
@@ -1506,6 +1673,7 @@ begin
   frmLog.AddCurrentSystemLog('SYSTEM', '\83T\81[\83o\82©\82ç\90Ø\92f\82³\82ê\82Ü\82µ\82½');
   if not Application.Terminated then RetryBeginConnect;
 end;
+}
 
 procedure TfrmSender.SetSleeping(const Value: boolean);
 begin
@@ -1527,44 +1695,11 @@ begin
 end;
 
 procedure TfrmSender.SakuraSeekerDetectResultChanged(Sender: TObject);
-var i: integer;
-    GhostList: String;
-    Http: THTTPDownloadThread;
-    SendOk: boolean;
 begin
   UpdateIfGhostBox; // \83h\83\8d\83b\83v\83_\83E\83\93\82Ì\92\86\90g\82ð\8f\91\82«\8a·\82¦\82é
-
-  if (FLastGhostListSend <> 0) and
-    (GetTickCount < FLastGhostListSend + 1000*60) then
-  begin
-    Exit;
-  end;
-  FLastGhostListSend := GetTickCount;
-
-  //\8d\91\90¨\92²\8d¸\82É\8eQ\89Á
-  if FBooted and not Pref.NoSendGhostList and (SakuraSeeker.Count > 0) then begin
-    GhostList := 'CCC=' + ParamsEncode('\88¤');
-    GhostList := GhostList + '&LUID=' + Pref.LUID;
-    SendOk := false;
-    for i := 0 to SakuraSeeker.Count-1 do begin
-      if SakuraSeeker[i].Name <> '' then begin//\82±\82ê\82ª\82È\82¢\82Æ\82½\82Ü\82ÉFMO\89ó\82ê\82Å\8bó\82Ì\83S\81[\83X\83g\82ð\91\97\82Á\82Ä\82µ\82Ü\82¤
-        GhostList := GhostList + '&GHOST=' + ParamsEncode(SakuraSeeker[i].SetName);
-        SendOk := true;
-      end;
-    end;
-    if SendOk and (FLastGhostList <> GhostList) then begin
-      FLastGhostList := GhostList;
-      Http := THTTPDownloadThread.Create(BottleServer, Pref.CgiNameGhost, GhostList);
-      if Pref.UseHttpProxy then begin
-        Http.ProxyServer := Pref.ProxyAddress;
-        Http.ProxyPort   := Pref.ProxyPort;
-      end;
-      Http.FreeOnTerminate := true;
-      Http.Resume;
-    end;
-  end;
 end;
 
+{
 procedure TfrmSender.UpdateChannelInfo(Dat: THeadValue);
 var i: integer;
     Ch: TChannelListItem;
@@ -1582,12 +1717,15 @@ begin
   end;
   UpdateLayout;
 end;
+}
 
 procedure TfrmSender.mnGetNewIdClick(Sender: TObject);
 begin
-  PostCommand(['Command: getNewId', 'Agent: ' + VersionString]);
+  ShowHintLabel('LUID\82Ì\8eæ\93¾\82Í\82Å\82«\82Ü\82¹\82ñ', WarningColor);
+//  PostCommand(['Command: getNewId', 'Agent: ' + VersionString]);
 end;
 
+{
 procedure TfrmSender.NoLuidError;
 begin
   Beep;
@@ -1595,9 +1733,11 @@ begin
               '\83w\83\8b\83v\83\81\83j\83\85\81[\82Ì[LUID\8eæ\93¾]\82©\82çID\82ð\8eæ\93¾\82µ\82Ä\82­\82¾\82³\82¢\81B'#13#10+
               '\82±\82Ì\91\80\8dì\82ÍClient\8f\89\89ñ\8bN\93®\8e\9e\82É1\89ñ\82¾\82¯\95K\97v\82Å\82·\81B');
 end;
+}
 
 procedure TfrmSender.tabChannelChange(Sender: TObject);
 begin
+{
   if tabChannel.TabIndex >= 0 then begin
     FNowChannel := tabChannel.Tabs[tabChannel.TabIndex];
     actSend.Hint := Format('\81u%s\81v\82É\91\97\90M|%s', [FNowChannel, SendButtonLongHint]);
@@ -1607,28 +1747,34 @@ begin
   end;
   tabChannel.Repaint; //\82±\82ê\82ª\82È\82¢\82Æ\90F\82ª\95Ï\82í\82ç\82È\82¢\82±\82Æ\82ª\82 \82é
   ConstructMenu(true);
+}
 end;
 
 procedure TfrmSender.actPrevChannelExecute(Sender: TObject);
 begin
+{
   with tabChannel do begin
     if Tabs.Count = 0 then Exit;
     if TabIndex=0 then TabIndex := Tabs.Count-1
     else TabIndex := TabIndex-1;
   end;
   tabChannelChange(Self);
+}
 end;
 
 procedure TfrmSender.actNextChannelExecute(Sender: TObject);
 begin
+{
   with tabChannel do begin
     if Tabs.Count = 0 then Exit;
     if TabIndex=Tabs.Count-1 then TabIndex := 0
     else TabIndex := TabIndex+1;
   end;
   tabChannelChange(Self);
+}
 end;
 
+{
 procedure TfrmSender.UpdateJoinChannelList(Dat: THeadValue);
 var i: integer;
     nodat: boolean;
@@ -1648,8 +1794,9 @@ begin
     Tabs.Clear;
     for i := 0 to JoinChannels.Count-1 do begin
       //\8eó\90M\90ê\97p\83`\83\83\83\93\83l\83\8b\82Í\95\\8e¦\82µ\82È\82¢
-      if not ChannelList.Channel[JoinChannels[i]].NoPost then
-        Tabs.Add(JoinChannels[i]);
+      if ChannelList.Channel[JoinChannels[i]] <> nil then
+        if not ChannelList.Channel[JoinChannels[i]].NoPost then
+          Tabs.Add(JoinChannels[i]);
     end;
     Tabs.EndUpdate;
     // \8c³\82©\82ç\83`\83\83\83\93\83l\83\8b\82É\8eQ\89Á\82µ\82Ä\82¢\82½\8fê\8d\87\82Í
@@ -1683,6 +1830,7 @@ begin
     actSend.Enabled := true;
   end;
 end;
+}
 
 procedure TfrmSender.cbxTargetGhostDropDown(Sender: TObject);
 begin
@@ -1710,8 +1858,10 @@ begin
 end;
 
 
-procedure TfrmSender.DispatchBottle(EventType: TIdSlppEventType;
-  Dat: THeadValue);
+procedure TfrmSender.DispatchBottle(Dat: THeadValue; LogTime: TDateTime;
+  Vote, Agree: integer);
+//procedure TfrmSender.DispatchBottle(EventType: TIdSlppEventType;
+//  Dat: THeadValue);
 var Opt: TSstpSendOptions;
     Event: TBottleChainBottleEvent;
     Script, Sender, Ghost, Channel, ErrorMes: String;
@@ -1722,24 +1872,30 @@ var Opt: TSstpSendOptions;
     Action: TBottleChainAction;
     LogNameList: TStringList;
     CueItem: TLogItem;
-    ReplaceHash: THeadValue; 
+    ReplaceHash: THeadValue;
 begin
+  Channel := Dat['Channel'];
+
   Opt := [];
   if Pref.NoTranslate then Opt := Opt + [soNoTranslate];
   if Pref.NoDescript  then Opt := Opt + [soNoDescript];
-  Channel := Dat['Channel'];
+{
   case EventType of
     etScript: Sender := Channel;
     etForceBroadcast: Sender := '\81y\82¨\92m\82ç\82¹\81z';
     etUnicast: Sender := Dat['SenderUID'];
   end;
+}
+  Sender := Channel; //\92Ê\8fí
 
   //\96Ú\95W\83S\81[\83X\83g(\83I\81[\83o\81[\83\89\83C\83h\88È\91O)\8c\88\92è
   if Dat['IfGhost'] <> '' then begin
     Ghost := Dat['IfGhost'];
   end else begin
     if ChannelList.Channel[Channel] <> nil then
-      Ghost := ChannelList.Channel[Channel].Ghost;
+      Ghost := ChannelList.Channel[Channel].Ghost
+    else
+      Ghost := '';
   end;
   Dat['TargetGhost'] := Ghost;
 
@@ -1747,22 +1903,28 @@ begin
   ReplaceHash := THeadValue.Create;
   ReplaceHash['%channel%'] := SafeFileName(Dat['Channel']);
   ReplaceHash['%ghost%'] := SafeFileName(Dat['IfGhost']);
-  ReplaceHash['%date%'] := FormatDateTime('yy-mm-dd', Now());
-  ReplaceHash['%year%'] := FormatDateTime('yyyy', Now());
-  ReplaceHash['%month%'] := FormatDateTime('mm', Now());
-  ReplaceHash['%day%'] := FormatDateTime('dd', Now());
-  ReplaceHash['%hour%'] := FormatDateTime('hh', Now());
-  ReplaceHash['%minute%'] := FormatDateTime('nn', Now());
+  ReplaceHash['%date%'] := FormatDateTime('yy-mm-dd', LogTime);
+  ReplaceHash['%year%'] := FormatDateTime('yyyy', LogTime);
+  ReplaceHash['%yy%'] := FormatDateTime('yy', LogTime);
+  ReplaceHash['%month%'] := FormatDateTime('mm', LogTime);
+  ReplaceHash['%day%'] := FormatDateTime('dd', LogTime);
+  ReplaceHash['%hour%'] := FormatDateTime('hh', LogTime);
+  ReplaceHash['%minute%'] := FormatDateTime('nn', LogTime);
 
   Event := TBottleChainBottleEvent.Create;
   try
     Event.Data := Dat;
+{
     if EventType = etScript then Event.LogType := ltBottle
     else Event.LogType := ltSystemLog;
+}
+    Event.LogType := ltBottle; //\92Ê\8fí
 
     //\83X\83N\83\8a\83v\83g\95Ï\8a·
     Script := ScriptTransForSSTP(Dat['Script'], ErrorMes);
-    if ErrorMes <> '' then begin
+    //\96â\91è\82Ì\97L\82é\95r\82É\91Î\82·\82é\93®\8dì
+    if (ErrorMes <> '') AND (NOT Pref.ErrScript) then
+    begin
       frmLog.AddCurrentSystemLog('SYSTEM', '\96â\91è\82Ì\82 \82é\89Â\94\\90«\82Ì\82 \82é\83X\83N\83\8a\83v\83g\82ª\93Í\82¢\82½\82½\82ß\81A'+
                     '\94z\91\97\82³\82ê\82Ü\82¹\82ñ\82Å\82µ\82½\81@\81c '+Dat['Script']);
       Exit;
@@ -1807,27 +1969,31 @@ begin
           begin
             Dat['TargetGhost'] := (Action as TBottleChainOverrideGhostAction).TargetGhost;
           end;
-          if Action is TBottleChainQuitAction then Application.Terminate;
+          if Action is TBottleChainQuitAction then
+            Application.Terminate;
           if Action is TBottleChainSaveTextLogAction then
             AppendTextLog(StringReplaceEx((Action as TBottleChainSaveTextLogAction).FileName, ReplaceHash),
               Format('%s,%s,%s,%s', [Dat['Channel'], Dat['IfGhost'],
-                FormatDateTime('yy/mm/dd hh:nn:ss', Now), Dat['Script']]));
+                FormatDateTime('yy/mm/dd hh:nn:ss', LogTime), Dat['Script']]), true);
           if Action is TBottleChainSaveXMLLogAction then
             AppendXMLLog(StringReplaceEx((Action as TBottleChainSaveXMLLogAction).FileName, ReplaceHash),
               Dat);
+          if Action is TBottleChainSurfaceReplaceAction then
+            Script := ReplaceSurface(Script, (Action as TBottleChainSurfaceReplaceAction).Params);
         end;
         if BreakFlag then Break;
       end;
 
       if Dat['Script'] <> '' then begin
         for i := 0 to LogNameList.Count-1 do
-          frmLog.AddCurrentScriptLog(LogNameList[i], Dat['Script'], Sender, Dat['MID'], Dat['IfGhost']);
-        if NoDispatch then begin
+          frmLog.AddCurrentScriptLog(LogNameList[i], Dat['Script'], Sender, Dat['MID'], Dat['IfGhost'],
+            LogTime, Vote, Agree);
+        if NoDispatch or Pref.NotSSTP then begin
           frmLog.SetBottleState(Dat['MID'], lsOpened);
         end else begin
           Ghost := Dat['TargetGhost']; // \83I\81[\83o\81[\83\89\83C\83h\82³\82ê\82Ä\82¢\82é\89Â\94\\90«\82ª\82 \82é
           CueItem := TLogItem.Create(ltBottle, Dat['MID'], Dat['Channel'],
-            Script, Ghost, Now());
+            Script, Ghost, LogTime);
           try
             FBottleSstp.Push(CueItem);
           except
@@ -1836,14 +2002,16 @@ begin
         end;
       end;
 
+{
       if Dat['DialogMessage'] <> '' then begin
         Beep;
         frmMessageBox.ShowMessage(
-          DateTimeToStr(Now) + #13#10 +
+          DateTimeToStr(LogTime) + #13#10 +
           'SSTP Bottle\83T\81[\83o\82©\82ç\82¨\92m\82ç\82¹'#13#10+Dat['DialogMessage']);
         for i := 0 to LogNameList.Count-1 do
           frmLog.AddCurrentSystemLog(LogNameList[i], Dat['DialogMessage']);
       end;
+}
 
       //\89¹\82Ì\8dÄ\90
       if (Sound <> '') then PlaySound(Sound);
@@ -1860,6 +2028,7 @@ procedure TfrmSender.YenETrans;
 var St, Le, i: integer;
     Orig, Text: String;
 begin
+  if Pref.NotYenETrans then exit; // \e\83`\83F\83b\83N\82µ\82È\82¢
   St := memScript.SelStart;
   Le := memScript.SelLength;
   Orig := GetScriptText;
@@ -1885,6 +2054,7 @@ begin
   memScript.SelLength := Le;
 end;
 
+{
 procedure TfrmSender.PostCommand(const Command: array of String);
 var PostStr: TStringList;
     i: integer;
@@ -1900,7 +2070,9 @@ begin
     PostStr.Free;
   end;
 end;
+}
 
+{
 procedure TfrmSender.PostCommand(Command: TStrings);
 var PostStr: String;
 begin
@@ -1908,7 +2080,7 @@ begin
   PostStr := Command.Text;
   PostStr := ParamsEncode(PostStr);
   try
-    FHttp := THTTPDownloadThread.Create(BottleServer, Pref.CgiName, PostStr);
+    FHttp := THTTPDownloadThread.Create(Pref.BottleServer, Pref.CgiName, PostStr);
     if Pref.UseHttpProxy then begin
       FHttp.ProxyServer := Pref.ProxyAddress;
       FHttp.ProxyPort   := Pref.ProxyPort;
@@ -1924,10 +2096,13 @@ begin
     end;
   end;
 end;
+}
 
 procedure TfrmSender.actVoteMessageExecute(Sender: TObject);
-var Log: TLogItem;
+//var Log: TLogItem;
 begin
+  ShowHintLabel('\93\8a\95[\82Å\82«\82Ü\82¹\82ñ', WarningColor);
+{
   if frmLog.lvwLog.Selected = nil then Exit;
   Log := frmLog.SelectedBottleLog[frmLog.lvwLog.Selected.Index] as TLogItem;
   if Log = nil then Exit;
@@ -1938,12 +2113,15 @@ begin
     'LUID: ' + Pref.LUID,
     'MID: ' + Log.MID
   ]);
+}
 end;
 
 
 procedure TfrmSender.actAgreeMessageExecute(Sender: TObject);
-var Log: TLogItem;
+//var Log: TLogItem;
 begin
+  ShowHintLabel('\93¯\88Ó\82Å\82«\82Ü\82¹\82ñ', WarningColor);
+{
   if frmLog.lvwLog.Selected = nil then Exit;
   Log := frmLog.SelectedBottleLog[frmLog.lvwLog.Selected.Index] as TLogItem;
   if Log = nil then Exit;
@@ -1954,6 +2132,7 @@ begin
     'LUID: ' + Pref.LUID,
     'MID: ' + Log.MID
   ]);
+}
 end;
 
 
@@ -1967,15 +2146,18 @@ end;
 
 procedure TfrmSender.tabChannelContextPopup(Sender: TObject;
   MousePos: TPoint; var Handled: Boolean);
-var Ch: String;
+//var Ch: String;
 begin
+{
   with tabChannel do begin
     Tag := IndexOfTabAt(MousePos.X, MousePos.Y);
     if Tag < 0 then Handled := true;
     Ch := Tabs[Tag];
   end;
+}
 end;
 
+{
 procedure TfrmSender.PostSetChannel(Channels: TStrings);
 var PostStr: TStringList;
     i: integer;
@@ -1996,11 +2178,13 @@ begin
     PostStr.Free;
   end;
 end;
+}
 
 procedure TfrmSender.mnLeaveThisChannelClick(Sender: TObject);
-var Ch: String;
-    Chs: TStringList;
+//var Ch: String;
+//    Chs: TStringList;
 begin
+{
   // \8ew\92è\82µ\82½\83`\83\83\83\93\83l\83\8b\82©\82ç\94²\82¯\82é
   with tabChannel do
     Ch := Tabs[Tag]; // \94²\82¯\82½\82¢\83`\83\83\83\93\83l\83\8b\96¼
@@ -2016,39 +2200,38 @@ begin
   finally
     Chs.Free;
   end;
+}
 end;
 
 procedure TfrmSender.mnGotoVoteClick(Sender: TObject);
 begin
-  ShellExecute(Handle, 'open', PChar(Pref.VotePage), nil, nil, SW_SHOW);
-end;
-
-procedure TfrmSender.mnGotoGLogClick(Sender: TObject);
-begin
-  ShellExecute(Handle, 'open', PChar(Pref.GLogPage), nil, nil, SW_SHOW);
+  OpenBrowser(Pref.VotePage);
 end;
 
 procedure TfrmSender.tabChannelMouseMove(Sender: TObject;
   Shift: TShiftState; X, Y: Integer);
-var Index: integer;
-    Ch: String;
+//var Index: integer;
+//    Ch: String;
 begin
+{
   with tabChannel do begin
     Index := IndexOfTabAt(X, Y);
     Ch := Tabs[Index];
     Hint := Ch + ': ' + IntToStr(ChannelList.Channel[Ch].Members) + '\90l';
   end;
+}
 end;
 
 procedure TfrmSender.mnGoToHelpClick(Sender: TObject);
 begin
-  ShellExecute(Handle, 'open', PChar(Pref.HelpPage), nil, nil, SW_SHOW);
+  OpenBrowser(Pref.HelpPage);
 end;
 
 procedure TfrmSender.tabChannelMouseDown(Sender: TObject;
   Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
-var Index: integer;
+//var Index: integer;
 begin
+{
   with tabChannel do begin
     Index := IndexOfTabAt(X, Y);
     if Index = -1 then Exit; //\83^\83u\82ª\82È\82¢\82Ì\82Å\83h\83\89\83b\83O\82Å\82«\82È\82¢
@@ -2058,13 +2241,15 @@ begin
       FDragTabDest := -1;     //\83h\83\89\83b\83O\98g\90ü\95`\89æ\83t\83\89\83O\83N\83\8a\83A\82Ì\82½\82ß
     end;
   end;
+}
 end;
 
 procedure TfrmSender.tabChannelDragOver(Sender, Source: TObject; X,
   Y: Integer; State: TDragState; var Accept: Boolean);
-var TargetRect: TRect;
-    OldDest: integer;
+//var TargetRect: TRect;
+//    OldDest: integer;
 begin
+{
   Accept := Source = tabChannel;
   if not Accept then Exit;
   with tabChannel do begin
@@ -2097,24 +2282,29 @@ begin
       end;
     end;
   end;
+}
 end;
 
 procedure TfrmSender.tabChannelDragDrop(Sender, Source: TObject; X,
   Y: Integer);
-var DestIndex: integer;
+//var DestIndex: integer;
 begin
+{
   with tabChannel do begin
     DestIndex := IndexOfTabAt(X, Y);
     Tabs.Move(FDragTabIndex, DestIndex);
   end;
+}
 end;
 
 procedure TfrmSender.tabChannelEndDrag(Sender, Target: TObject; X,
   Y: Integer);
 begin
+{
   //\8b­\90§\93I\82É\83^\83u\82ð\8dÄ\95`\89æ\82³\82¹\82é\81B\98g\90ü\8fÁ\82µ\91Î\8dô
   tabChannel.Tabs.BeginUpdate;
   tabChannel.Tabs.EndUpdate;
+}
 end;
 
 procedure TfrmSender.cbxTargetGhostDrawItem(Control: TWinControl;
@@ -2162,9 +2352,33 @@ end;
 procedure TfrmSender.FormCloseQuery(Sender: TObject;
   var CanClose: Boolean);
 begin
-  if not Pref.ConfirmOnExit then Exit;
-  if MessageDlg('SSTP Bottle Client\82ð\8fI\97¹\82µ\82Ü\82·', mtConfirmation,
-                mbOkCancel, 0) = mrCancel then CanClose := false;
+{
+  if (not Pref.ConfirmOnExit) or FEndSession then
+  begin
+    Exit;
+  end;
+}
+  if Pref.ConfirmOnExit then
+    if MessageDlg('Yasagure Client\82ð\8fI\97¹\82µ\82Ü\82·', mtConfirmation,
+                mbOkCancel, 0) = mrCancel then
+    begin
+      CanClose := false;
+      exit;
+    end;
+
+  //\83t\83@\83C\83\8b\82Ì\8dX\90V\83`\83F\83b\83N\81i\83G\83f\83B\83^\95\94\81j
+  if CheckFileModified(Self) = idCancel then
+  begin
+    CanClose := false;
+    exit;
+  end;
+  //\83\8d\83O\81i\83^\83u\81j\93à\97e\82Ì\95Ï\8dX\83`\83F\83b\83N
+  if frmLog.CheckLog(Self) = idCancel then
+  begin
+    CanClose := false;
+    exit;
+  end;
+  DeleteBackupFile(FScriptBackupFile);   // \88ê\8e\9e\83t\83@\83C\83\8b\8dí\8f\9c\82Ö
 end;
 
 procedure TfrmSender.UpdateIfGhostBox;
@@ -2212,15 +2426,17 @@ begin
   end;
 end;
 
+{
 procedure TfrmSender.HTTPFailure(Sender: TObject);
 begin
   SysUtils.Beep;
   Beep;
   ShowHintLabel('SSTP Bottle\83T\81[\83o\82Æ\82Ì\90Ú\91±\82É\8e¸\94s\82µ\82Ü\82µ\82½', WarningColor);
-  ShowMessage('SSTP Bottle\83T\81[\83o\82Æ\82Ì\90Ú\91±\82É\8e¸\94s\82µ\82Ü\82µ\82½'#13#10 +
+  frmMessageBox.ShowMessage('SSTP Bottle\83T\81[\83o\82Æ\82Ì\90Ú\91±\82É\8e¸\94s\82µ\82Ü\82µ\82½'#13#10 +
     (Sender as THTTPDownloadThread).LastErrorMessage);
   Connecting := false;
 end;
+}
 
 procedure TfrmSender.actPrevGhostExecute(Sender: TObject);
 var i: integer;
@@ -2265,9 +2481,10 @@ begin
   cbxTargetGhostChange(self);
 end;
 
+{
 procedure TfrmSender.timDisconnectCheckTimerTimer(Sender: TObject);
 begin
-  if (IdSlpp20.LastReadTimeInterval > BottleServerTimeOut) then begin
+  if (IdSlpp20.LastReadTimeInterval > Pref.ReconnectWait * 60000) then begin
     SysUtils.Beep;
     frmLog.AddCurrentSystemLog('SYSTEM', 'SSTP Bottle\83T\81[\83o\82Æ\82Ì\90Ú\91±\82ª\83^\83C\83\80\83A\83E\83g\82µ\82Ü\82µ\82½');
     if IdSlpp20.Connected then IdSlpp20.Disconnect;
@@ -2282,13 +2499,18 @@ begin
     end;
   end;
 end;
+}
 
+{
 procedure TfrmSender.RetryBeginConnect;
 begin
   if FBeginConnectFailCount < 3 then begin
     // \90Ø\92f\82³\82ê\82Ä\82¢\82ê\82Î\8dÄ\90Ú\91±
+    IdSlpp20.OnDisconnect := nil;
+    if IdSlpp20.Connected then IdSlpp20.Disconnect;
     FAutoAddAfterGetChannel := true;
     BeginConnect;
+    IdSlpp20.OnDisconnect := Slpp20Disconnect;
   end else if FBeginConnectFailCount = 3 then begin
     frmLog.AddCurrentSystemLog('SYSTEM', '\8dÄ\90Ú\91±\8e©\93®\83\8a\83g\83\89\83C\82ð\92\86\8e~\82µ\82Ü\82·');
     frmMessageBox.ShowMessage(
@@ -2299,8 +2521,10 @@ begin
     Inc(FBeginConnectFailCount);
   end;
 end;
+}
 
 procedure TfrmSender.actDownloadLogExecute(Sender: TObject);
+{
 var BottleLog: TBottleLogList;
     Title: String;
     Cond: TBottleLogDownloadCondition;
@@ -2316,16 +2540,19 @@ var BottleLog: TBottleLogList;
     if hour > 0 then Result := Result + Format('%d\8e\9e\8aÔ', [hour]);
     if (min  > 0) or (Result = '') then Result := Result + Format('%d\95ª', [min]);
   end;
+}
 begin
+  ShowHintLabel('\83\8d\83O\82Ì\83_\83E\83\93\83\8d\81[\83h\82Í\82Å\82«\82Ü\82¹\82ñ', WarningColor);
+{
   Application.CreateForm(TfrmLogDownload, frmLogDownload);
   try
     if frmLogDownload.Execute then begin
       with frmLogDownload do begin
         if IsRange then begin
           if CompareDate(DateLo, DateHi) = 0 then
-            Title := FormatDateTime('yy/mm/dd', DateLo)
+            Title := FormatDateTime('yy-mm-dd', DateLo)
           else
-            Title := FormatDateTime('yy/mm/dd', DateLo) + ' - ' + FormatdateTime('yy/mm/dd', DateHi);
+            Title := FormatDateTime('yy-mm-dd', DateLo) + ' - ' + FormatdateTime('yy-mm-dd', DateHi);
         end else begin
           Title := Format('\89ß\8b\8e%s', [TimeStr(RecentCount)]);
         end;
@@ -2359,6 +2586,7 @@ begin
   finally
     frmLogDownload.Release;
   end;
+}
 end;
 
 function TfrmSender.BuildMenuConditionCheck(const IfGhost,
@@ -2391,7 +2619,9 @@ begin
   // Simple = false \82Ì\8fê\8d\87\82Í\83\81\83j\83\85\81[\82ð\8a®\91S\82É\8dÄ\8d\\92z\82·\82é\81B
   // Simple = true \82Ì\8fê\8d\87\82Í\83S\81[\83X\83g\8aÖ\8cW\82Ì\82Ý\8dÄ\8d\\92z\82·\82é\82Ì\82Å\8d\82\91¬\81B
   if cbxTargetGhost.ItemIndex > 0 then Ghost := cbxTargetGhost.Text
-  else if FNowChannel <> '' then Ghost := ChannelList.Channel[FNowChannel].Ghost;
+//  else if FNowChannel <> '' then Ghost := ChannelList.Channel[FNowChannel].Ghost;
+  else
+    Ghost := '';
 
   // \8aù\91\82Ì\83\81\83j\83\85\81[\8dí\8f\9c
   if Simple then begin
@@ -2400,12 +2630,9 @@ begin
       if ScriptConstList.GetMenuByID(Root.Items[i].Tag).IfGhost <> '' then
         Root.Items[i].Free;
     end;
-  end else begin
+  end else
     // \91S\95\94\8dí\8f\9c
-    for i := Root.Count-1 downto 0 do begin
-      Root.Items[i].Free;
-    end;
-  end;
+    Root.Clear;
 
   count := -1;
   for i := 0 to ScriptConstList.Count-1 do begin
@@ -2420,11 +2647,14 @@ begin
         end;
 
       Menu1 := TMenuItem.Create(Root);
-      Menu1.Caption := ScriptConstList[i][j].Caption;
-      Menu1.Hint    := ScriptConstList[i][j].Caption;
-      Menu1.AutoHotkeys := maManual;
-      Menu1.Tag := ScriptConstList[i][j].ID;
-      Menu1.OnClick := mnConstGroupClick;
+      with Menu1 do
+      begin
+        Caption := ScriptConstList[i][j].Caption;
+        Hint    := ScriptConstList[i][j].Caption;
+        AutoHotkeys := maManual;
+        Tag := ScriptConstList[i][j].ID;
+        OnClick := mnConstGroupClick;
+      end;
 
       if not Simple then begin
         Root.Add(Menu1);
@@ -2528,9 +2758,9 @@ begin
   frmLog.SetBottleState(MID, lsPlaying);
 end;
 
-procedure TfrmSender.actInsertCueExecute(Sender: TObject);
+procedure TfrmSender.LogInsertCue(TestAction, SelectAll: boolean);
 var InsertItem: TLogItem;
-    i, errCount, Res: integer;
+    i, errCount, Res, Tstart: integer;
     Log: TBottleLogList;
     ErrorMes: String; // \83X\83N\83\8a\83v\83g\82Ì\83G\83\89\81[\82Ì\93à\97e
 begin
@@ -2547,37 +2777,50 @@ begin
   if Log = nil then Exit;
   FBottleSSTP.OnResendCountChange := nil;
   errCount := 0;
-  for i := frmLog.lvwLog.Selected.Index downto 0 do begin
+  if SelectAll then Tstart := frmLog.lvwLog.Items.Count-1  // \8ew\92è\82³\82ê\82½\83^\83u\82Ì\91S\90\94
+  else Tstart := frmLog.lvwLog.Selected.Index;             // \91I\91ð\82³\82ê\82Ä\82¢\82é\8fê\8f\8a\82©\82ç
+  for i := Tstart downto 0 do begin
     if (Log[i] as TLogItem).LogType <> ltBottle then Continue;
     InsertItem := TLogItem.Create(Log[i] as TLogItem);
     try
-      InsertItem.Script := ScriptTransForSSTP(InsertItem.Script, ErrorMes);
-      if ErrorMes <> '' then
+      //\83A\83N\83V\83\87\83\93\82ª\97L\8cø\82Å\82 \82ê\82Î\83X\83N\83\8a\83v\83g\82Ì\95Ï\8a·\82µ\82È\82¢
+      if TestAction then
+      begin
+        BottleCnv(InsertItem); // \8c^\95Ï\8a·\82Æ\8eó\90M
+        frmLog.StatusBar.Panels[1].Text := Format('\8ec\82è%d\8c\8f', [i]);
+        frmLog.StatusBar.Update;
+      end else
       begin
-        Res := MessageDlg('\83X\83N\83\8a\83v\83g\82É\96â\91è\82ª\82 \82é\89Â\94\\90«\82ª\82 \82è\82Ü\82·\81B' +
-          '\8dÄ\90\82µ\82Ü\82·\82©?'#13#10 + ErrorMes, mtWarning,
-          mbYesNoCancel, 0);
-        if Res = mrNo then
-          raise Exception.Create('Script Syntax Error')
-        else if Res = mrCancel then
+        InsertItem.Script := ScriptTransForSSTP(InsertItem.Script, ErrorMes);
+        if ErrorMes <> '' then
         begin
-          InsertItem.Free;
-          FBottleSstp.Clear;
-          frmLog.AllBottleOpened;
-          Break;
+          Res := MessageDlg('\83X\83N\83\8a\83v\83g\82É\96â\91è\82ª\82 \82é\89Â\94\\90«\82ª\82 \82è\82Ü\82·\81B' +
+            '\8dÄ\90\82µ\82Ü\82·\82©?'#13#10 + ErrorMes, mtWarning,
+            mbYesNoCancel, 0);
+          if Res = mrNo then
+            raise Exception.Create('Script Syntax Error')
+          else if Res = mrCancel then
+          begin
+            InsertItem.Free;
+            FBottleSstp.Clear;
+            frmLog.AllBottleOpened;
+            Break;
+          end;
         end;
+        //\83`\83\83\83\93\83l\83\8b\83S\81[\83X\83g\91Î\8dô
+        if InsertItem.Ghost = '' then
+          if ChannelList.Channel[InsertItem.Channel] <> nil then
+            InsertItem.Ghost := ChannelList.Channel[InsertItem.Channel].Ghost;
+        FBottleSSTP.Push(InsertItem);
+        frmLog.SetBottleState(InsertItem.MID, lsUnopened);
       end;
-      if InsertItem.Ghost = '' then begin
-        if ChannelList.Channel[InsertItem.Channel] <> nil then
-        InsertItem.Ghost := ChannelList.Channel[InsertItem.Channel].Ghost;
-      end;
-      FBottleSSTP.Push(InsertItem);
-      frmLog.SetBottleState(InsertItem.MID, lsUnopened);
     except
       InsertItem.Free;
       Inc(errCount);
     end;
   end;
+  if TestAction then
+    frmLog.StatusBar.Panels[1].Text := '\8a®\97¹';
   if errCount > 0 then
     ShowMessage(Format('%d\8c\8f\82Ì\83{\83g\83\8b\82É\96â\91è\82ª\82 \82Á\82½\82½\82ß\8dÄ\90\82Å\82«\82Ü\82¹\82ñ\81B', [errCount]));
   FBottleSSTP.OnResendCountChange := BottleSstpResendCountChange;
@@ -2585,6 +2828,11 @@ begin
   frmLog.lvwLog.Invalidate;
 end;
 
+procedure TfrmSender.actInsertCueExecute(Sender: TObject);
+begin
+  LogInsertCue(false, false); // \92Ê\8fí\82Ì\98A\91±\8dÄ\90\82ð\82·\82é
+end;
+
 function TfrmSender.ScriptTransForSSTP(const Script: String;
   out Error: String): String;
 var TransOpt: TScriptTransOptions;
@@ -2636,6 +2884,16 @@ begin
   memScript.SelectAll;
 end;
 
+procedure TfrmSender.actUndoExecute(Sender: TObject);
+begin
+  memScript.Undo;
+end;
+
+procedure TfrmSender.actRedoExecute(Sender: TObject);
+begin
+  memScript.Redo;
+end;
+
 function TfrmSender.IsSurfaceTag(const Script: String;
   var ID: integer): boolean;
 begin
@@ -2678,8 +2936,12 @@ var Ghost: String;
 begin
   if cbxTargetGhost.ItemIndex > 0 then
     ghost := cbxTargetGhost.Text
+  else
+    ghost := '';
+{  \8eè\93®\82Ì\82Í\82¸
   else if FNowChannel <> '' then
     ghost := ChannelList.Channel[FNowChannel].Ghost;
+}
 
   // \93ñ\8fd\95\\8e¦\82Ì\97}\90§
   if (FVisiblePreviewGhost = Ghost) and (FVisiblePreviewSurface = Surface) and
@@ -2750,7 +3012,7 @@ begin
   if FScriptBuffer.Count = 0 then
     Exit;
   memScript.Lines.Assign(FScriptBuffer[0] as TStringList);
-  memScriptChange(Self);
+  EditerStatusChange;
   ShowHintLabel('\83X\83N\83\8a\83v\83g\82ð\8cÄ\82Ñ\8fo\82µ\82Ü\82µ\82½');
 end;
 
@@ -2763,9 +3025,11 @@ begin
       Script := StringReplace(GetScriptText, #13#10, '', [rfReplaceAll]);
       Ghost := '';
       if cbxTargetGhost.ItemIndex > 0 then
-        Ghost := cbxTargetGhost.Text
+        Ghost := cbxTargetGhost.Text;
+{ \8eè\93®\82Å\8ew\92è\82³\82ê\82é
       else if FNowChannel <> '' then
         Ghost := ChannelList.Channel[FNowChannel].Ghost;
+}
       frmEditorTalkShow.TalkShowFrame.View(Script, Ghost);
     end;
 end;
@@ -2789,10 +3053,12 @@ begin
   Spps.LoadFromDirectory(FSppDir);
 end;
 
+{
 procedure TfrmSender.IdSLPP20Connect(Sender: TObject);
 begin
   ShowHintLabel('SSTP Bottle\83T\81[\83o\82ª\8c©\82Â\82©\82è\82Ü\82µ\82½');
 end;
+}
 
 // \83X\83N\83\8a\83v\83g\92\86\82Ì\83^\83O\82ð\92u\8a·\82·\82é
 // \83T\83C\83Y\89Â\95Ï\82Ì\94z\97ñ\83p\83\89\83\81\81[\83^\94Å
@@ -2870,45 +3136,36 @@ begin
     inherited;
 end;
 
-// \8c\9f\8dõ\81E\92u\8a·\83_\83C\83A\83\8d\83O\82ð\8f\89\8aú\89»\82µ\82Ä\95\\8e¦
+// \92u\8a·
 procedure TfrmSender.actReplaceExecute(Sender: TObject);
+var
+  Form: TfrmStrReplaceDialog;
+  Lines: String;
+  Options: TReplaceFlags;
 begin
-  with ReplaceDialog do
-  begin
-    FindText := '';
-    ReplaceText := '';
-    Execute;
-  end;
-end;
-
-// \8c\9f\8dõ\81E\92u\8a·
-procedure TfrmSender.ReplaceDialogFind(Sender: TObject);
-var Opt: TSearchOptions;
-begin
-  Opt := [sfrDown];
-  if frMatchCase in ReplaceDialog.Options then
-    Opt := Opt + [sfrMatchCase];
-  if frWholeWord in ReplaceDialog.Options then
-    Opt := Opt + [sfrWholeWord];
-  memScript.Search(ReplaceDialog.FindText, Opt);
-end;
-
-// \8c\9f\8dõ\81E\92u\8a·
-procedure TfrmSender.ReplaceDialogReplace(Sender: TObject);
-var Opt: TSearchOptions;
-begin
-  Opt := [sfrDown];
-  if frMatchCase in ReplaceDialog.Options then
-    Opt := Opt + [sfrMatchCase];
-  if frWholeWord in ReplaceDialog.Options then
-    Opt := Opt + [sfrWholeWord];
-  if frReplaceAll in ReplaceDialog.Options then
-    while memScript.Search(ReplaceDialog.FindText, Opt) do
-      memScript.SelText := ReplaceDialog.ReplaceText
-  else
-  begin
-    if memScript.Search(ReplaceDialog.FindText, Opt) then
-      memScript.SelText := ReplaceDialog.ReplaceText
+  Application.CreateForm(TfrmStrReplaceDialog, Form);
+  try
+    if Form.Execute then
+    begin
+      with Form.Pair do
+      begin
+        Lines := memScript.Lines.Text;
+        Options := [rfReplaceAll];
+        if IgnoreCase then
+          Options := Options + [rfIgnoreCase];
+        if UseRegExp then
+          Lines := StringReplaceRegExp(Lines, BeforeStr, AfterStr, Options)
+        else
+          Lines := StringReplace(Lines, BeforeStr, AfterStr, Options);
+      end;
+      if Lines <> memScript.Lines.Text then
+      begin
+        memScript.SelectAll;
+        memScript.SelText := Lines;
+      end;
+    end;
+  finally
+    Form.Release;
   end;
 end;
 
@@ -2930,7 +3187,8 @@ begin
     Ghost := cbxTargetGhost.Text
   else
     Ghost := '';
-  frmLog.AddCurrentScriptLog('\83N\83\8a\83b\83v', Script, ClipChannel, '', Ghost);
+  frmLog.AddCurrentScriptLog('\83N\83\8a\83b\83v', Script, ClipChannel, '', Ghost, Now(), 0, 0);
+  SetFileModified(false); // \95Ï\8dX\82³\82ê\82Ä\82¢\82È\82¢\82±\82Æ\82É\82µ\82Ä\83N\83\8a\83A\82³\82¹\82é
   ClearEditor;
 end;
 
@@ -2958,17 +3216,25 @@ begin
 end;
 
 procedure TfrmSender.CopyFromLogToEditor(Log: TLogItem);
+var
+  Ghost: string;
 begin
   if Log.LogType <> ltBottle then Exit;
   frmSender.actClear.Execute; // \8c»\8dÝ\82Ì\83X\83N\83\8a\83v\83g\82ð\83N\83\8a\83b\83v\82·\82é(\90Ý\92è\82É\82æ\82Á\82Ä)
   memScript.Lines.Clear;
   memScript.Lines.Add(Log.Script);
-  if Log.Ghost <> '' then
+  SetFileName(Log.MID, true, false);  // \81ª\82Å\93à\97e\82ª\8dX\90V\82³\82ê\82é\82Ì\82Å\8dÄ\93x\90V\8bK\82É
+  Ghost := Log.Ghost;
+  //\83`\83\83\83\93\83l\83\8b\83S\81[\83X\83g\91Î\8dô
+  if Ghost = '' then
+    if ChannelList.Channel[Log.Channel] <> nil then
+      Ghost := ChannelList.Channel[Log.Channel].Ghost;
+  if Ghost <> '' then
   begin
     // \83S\81[\83X\83g\96¼\82ð\83{\83b\83N\83X\82É\93ü\82ê\82é
     // \96³\97\9d\96î\97\9d\83S\81[\83X\83g\96¼\82ð\92Ç\89Á\82µ\82Ä\82©\82ç\8dÄ\8d\\92z\82·\82é\82±\82Æ\82Å
     // \96³\97\9d\96î\97\9d\83S\81[\83X\83g\96¼\82ª\83{\83b\83N\83X\82É\93ü\82é
-    cbxTargetGhost.Items.Add(Log.Ghost);
+    cbxTargetGhost.Items.Add(Ghost);
     cbxTargetGhost.ItemIndex := cbxTargetGhost.Items.Count-1;
     UpdateIfGhostBox;
     cbxTargetGhost.Invalidate;
@@ -2987,6 +3253,7 @@ begin
   frmLog.SelectedBottleLog.Delete(frmLog.lvwLog.Selected.Index);
   frmLog.UpdateWindow;
   frmLog.lvwLogChange(Self, nil, ctState);
+  frmLog.SelectedBottleLog.LogModified := true; // \95Ï\8dX\82³\82ê\82½
 end;
 
 procedure TfrmSender.ClearEditor;
@@ -2995,6 +3262,10 @@ var TmpScript: String;
     DoSaveBuffer: boolean;
     SavedScript: TStringList;
 begin
+  // \90Ý\92è\82É\82æ\82è\83N\83\8a\83A\8e\9e\82É\83t\83@\83C\83\8b\83Z\81[\83u\82·\82é\82©\8am\94F\82·\82é
+  // \8e©\93®\83N\83\8a\83b\83v\82ª\97L\8cø\82Å\82 \82ê\82Î\83X\83L\83b\83v\82·\82é
+  if (NOT Pref.NotCheckClear) AND (NOT Pref.AutoClip) then
+    if CheckFileModified(Self) = idCancel then abort;
   // \83X\83N\83\8a\83v\83g\82Ì\83N\83\8a\83A
   // \82Ü\82¸\81A\83X\83N\83\8a\83v\83g\83N\83\8a\83A\83o\83b\83t\83@\82É\8c»\8dÝ\82Ì\83X\83N\83\8a\83v\83g\82ð\95Û\91\82·\82é
   DoSaveBuffer := false;
@@ -3023,23 +3294,31 @@ begin
   memScript.SelStart := Position-1;
 
   if Visible then memScript.SetFocus;
-  FScriptModified := false;
-  memScriptChange(self);
+//  FScriptModified := false;
+
+  SetFileName(NewFileTitle, true, true);    // \83t\83@\83C\83\8b\82ð\90V\8bK\88µ\82¢\82É\82·\82é
+  EditerStatusChange;                       // \83X\83e\81[\83^\83X\8dX\90V
 end;
 
-procedure TfrmSender.AppendTextLog(const FileName, Line: String);
+procedure TfrmSender.AppendTextLog(const FileName, Line: String; FAppend: boolean);
 var
   F: TextFile;
 begin
   //\91\97\90M\83\8d\83O\95Û\91
-  AssignFile(F, FileName);
-  if FileExists(FileName) then
-    Append(F)
-  else
-    Rewrite(F);
-  WriteLn(F, Line);
-  Flush(F);
-  CloseFile(F);
+  try
+    ForceDirectories(ExtractFileDir(FileName));
+    AssignFile(F, FileName);
+    if FileExists(FileName) AND FAppend then  // \92Ç\8bL\82©\8fã\8f\91\82«\94»\92è
+      Append(F)
+    else
+      Rewrite(F);
+    WriteLn(F, Line);
+    Flush(F);
+    CloseFile(F);
+  except
+    on E: Exception do
+      frmLog.AddCurrentSystemLog('SYSTEM', '\83e\83L\83X\83g\83\8d\83O\95Û\91\82É\8e¸\94s\81F'+E.Message);
+  end;
 end;
 
 procedure TfrmSender.AppendXMLLog(const FileName: String; Args: THeadValue);
@@ -3051,42 +3330,43 @@ var
   Parser: TXmlToDomParser;
   DOM: TdomDocument;
 begin
-  if not FileExists(FileName) then
-  begin
-    // Create empty XML log file
-    Impl := TDomImplementation.create(nil);
-    try
-      Parser := TXmlToDomParser.create(nil);
-      Parser.DOMImpl := Impl;
+  try // Long try block to handle all kinds of exception in this method
+    if not FileExists(FileName) then
+    begin
+      // Create empty XML log file
+      Impl := TDomImplementation.create(nil);
       try
+        ForceDirectories(ExtractFileDir(FileName));
+        Parser := TXmlToDomParser.create(nil);
+        Parser.DOMImpl := Impl;
         try
-          DOM := Parser.fileToDom(ExtractFilePath(Application.ExeName)+'xbtl.dat');
-          with DOM do
-          begin
-            documentElement.setAttribute('saved',
-              FormatDateTime('yy/mm/dd hh:nn:ss', Now));
-            documentElement.setAttribute('generator', VersionString);
-            documentElement.setAttribute('version', '1.0');
-          end;
-          // \82±\82ê\82Í\96¾\8e¦\93I\82ÉFree\82µ\82È\82­\82Ä\82æ\82¢
-          F := TFileStream.Create(FileName, fmCreate or fmShareExclusive);
           try
-            DOM.writeCodeAsShiftJIS(F);
-          finally
-            F.Free;
+            DOM := Parser.fileToDom(ExtractFilePath(Application.ExeName)+'xbtl.dat');
+            with DOM do
+            begin
+              documentElement.setAttribute('saved',
+                FormatDateTime('yy/mm/dd hh:nn:ss', Now));
+              documentElement.setAttribute('generator', VersionString);
+              documentElement.setAttribute('version', '1.0');
+            end;
+            // \82±\82ê\82Í\96¾\8e¦\93I\82ÉFree\82µ\82È\82­\82Ä\82æ\82¢
+            F := TFileStream.Create(FileName, fmCreate or fmShareExclusive);
+            try
+              DOM.writeCodeAsShiftJIS(F);
+            finally
+              F.Free;
+            end;
+          except
+            frmLog.AddCurrentSystemLog('SYSTEM', 'XML\83\8d\83O\95Û\91\82É\8e¸\94s\82µ\82Ü\82µ\82½');
           end;
-        except
-          frmLog.AddCurrentSystemLog('SYSTEM', 'XML\83\8d\83O\95Û\91\82É\8e¸\94s\82µ\82Ü\82µ\82½');
+        finally
+          Parser.DOMImpl.freeDocument(DOM);
+          Parser.Free;
         end;
-      finally
-        Parser.DOMImpl.freeDocument(DOM);
-        Parser.Free;
+      finally;
+        Impl.Free;
       end;
-    finally;
-      Impl.Free;
     end;
-  end;
-  try
     F := TFileStream.Create(FileName, fmOpenReadWrite or fmShareExclusive);
     try
       P := -11;
@@ -3118,7 +3398,453 @@ begin
       F.Free;
     end;
   except
-    frmLog.AddCurrentSystemLog('SYSTEM', 'XML\83\8d\83O\95Û\91\82É\8e¸\94s\82µ\82Ü\82µ\82½');
+    on E: Exception do
+      frmLog.AddCurrentSystemLog('SYSTEM', 'XML\83\8d\83O\95Û\91\82É\8e¸\94s\82µ\82Ü\82µ\82½:'+E.Message);
+  end;
+end;
+
+procedure TfrmSender.memScriptSelectionChange(Sender: TObject;
+  Selected: Boolean);
+var
+  SelText: String;
+begin
+  SelText := memScript.SelText;
+  if SelText <> '' then
+  begin
+    StatusBar.Panels[PanelBytes].Text := Format('(%d\83o\83C\83g)', [Length(SelText)]);
+  end else
+  begin
+    EditerStatusChange;
+  end;
+end;
+
+function TfrmSender.ReplaceSurface(Script: String;
+  Params: TCollection): String;
+var
+  Flag, OldLeaveEscape, OldEscapeInvalidMeta: boolean;
+  OldStr, Tag: String;
+  i, j, k, Cur: integer;
+  Item: TSurfaceReplaceItem;
+  Before: TSurfaceReplaceBeforeItem;
+begin
+  Result := '';
+  Cur := 0;
+  with SsParser do
+  begin
+    OldStr := InputString;
+    OldLeaveEscape := LeaveEscape;
+    OldEscapeInvalidMeta := EscapeInvalidMeta;
+    LeaveEscape := true;
+    EscapeInvalidMeta := false;
+    InputString := Script;
+  end;
+  for i := 0 to SsParser.Count-1 do
+  begin
+    if SsParser.MarkUpType[i] <> mtTag then
+    begin
+      Result := Result + SsParser.Str[i];
+      Continue;
+    end;
+    Tag := SsParser.Str[i];
+    if SsParser.Match(Tag, '\s%d') = 2 then
+      Cur := Ord(Tag[3]) - Ord('0')
+    else if SsParser.Match(Tag, '\s[%D]') > 0 then
+      Cur := StrToInt(SsParser.GetParam(Tag, 1))
+    else
+    begin
+      Result := Result + Tag;
+      Continue;
+    end;
+    Flag := false;
+    for j := 0 to Params.Count-1 do
+    begin
+      Item := Params.Items[j] as TSurfaceReplaceItem;
+      for k := 0 to Item.Before.Count-1 do
+      begin
+        Before := Item.Before.Items[k] as TSurfaceReplaceBeforeItem;
+        if (Cur >= Before.FromNo) and (Cur <= Before.ToNo) then
+        begin
+          Flag := true;
+          Result := Result + Format('\s[%d]', [Item.After]);
+          Break;
+        end;
+      end;
+      if Flag then
+        Break;
+    end;
+    if not Flag then
+      Result := Result + Tag;
+  end;
+  with SsParser do
+  begin
+    LeaveEscape := OldLeaveEscape;
+    EscapeInvalidMeta := OldEscapeInvalidMeta;
+    InputString := OldStr;
+  end;
+end;
+
+{
+procedure TfrmSender.WMQueryEndSession(var msg: TWMQueryEndSession);
+begin
+  // Windows\82ª\8fI\97¹\82µ\82æ\82¤\82Æ\82µ\82Ä\82¢\82é\82Ì\82ð\8a´\92m\82·\82é
+  FEndSession := true;
+  inherited;
+end;
+}
+
+{
+procedure TfrmSender.IdSLPP20ConnectFailed(Sender: TObject);
+begin
+  Added := false;
+  if FBeginConnectFailCount = 0 then
+  begin
+    Beep;
+    if Pref.UseHttpProxy then
+      frmMessageBox.ShowMessage('HTTP Proxy\82ð\92Ê\82\82ÄSSTP Bottle\83T\81[\83o\82É\90Ú\91±\82Å\82«\82Ü\82¹\82ñ\82Å\82µ\82½\81B'#13#10 +
+                  '\83l\83b\83g\83\8f\81[\83N\82Ì\8fó\91Ô\81EProxy\82Ì\8fó\91Ô\82ð\8am\94F\82µ\82Ä\82­\82¾\82³\82¢\81B'#13#10 +
+                  '\82 \82é\82¢\82Í\83T\81[\83o\82ª\83_\83E\83\93\82µ\82Ä\82¢\82é\89Â\94\\90«\82ª\82 \82è\82Ü\82·\81B')
+    else
+      frmMessageBox.ShowMessage('SSTP Bottle\83T\81[\83o\82É\90Ú\91±\82Å\82«\82Ü\82¹\82ñ\82Å\82µ\82½\81B'#13#10 +
+                  '\83l\83b\83g\83\8f\81[\83N\82É\8cq\82ª\82Á\82Ä\82¢\82é\82©\8am\94F\82µ\82Ä\82­\82¾\82³\82¢\81B'#13#10 +
+                  '\82 \82é\82¢\82Í\83T\81[\83o\82ª\83_\83E\83\93\82µ\82Ä\82¢\82é\89Â\94\\90«\82ª\82 \82è\82Ü\82·\81B');
+  end;
+  ShowHintLabel('SSTP Bottle Server\90Ú\91±\82É\8e¸\94s\82µ\82Ü\82µ\82½', WarningColor);
+  Inc(FBeginConnectFailCount);
+end;
+}
+
+procedure TfrmSender.BuildReplaceMenu(Root: TMenuItem);
+var
+  i: integer;
+  Presets: TReplacePresetCollection;
+  NewItem: TMenuItem;
+begin
+  Root.Clear;
+  Presets := Pref.ReplacePresets.Presets;
+  for i := 0 to Presets.Count-1 do
+  begin
+    NewItem := TMenuItem.Create(Root);
+    with NewItem do
+    begin
+      Caption := Presets[i].Title;
+      ShortCut := Presets[i].ShortCut;
+      AutoHotkeys := maManual;
+      Hint := Presets[i].Pairs.StringExpression;
+      Tag := i;
+      OnClick := mnPresetReplaceClick;
+    end;
+    Root.Add(NewItem);
+  end;
+  Root.Enabled := Presets.Count > 0;
+end;
+
+procedure TfrmSender.mnPresetReplaceClick(Sender: TObject);
+var
+  Preset: TReplacePreset;
+  Lines, New: string;
+begin
+  // \83v\83\8a\83Z\83b\83g\92u\8a·\82ð\8eÀ\8ds
+  Preset := Pref.ReplacePresets.Presets[(Sender as TMenuItem).Tag];
+  Lines := memScript.Lines.Text;
+  New := Preset.Pairs.ExecuteReplace(Lines);
+  if New <> Lines then
+  begin
+    memScript.SelectAll;
+    memScript.SelText := New;
+  end;
+  if Preset.ConfirmAfterReplace then
+  begin
+    btnConfirm.Click;
+  end;
+end;
+
+procedure TfrmSender.BottleCnv(Log: TLogItem);
+var
+  HeadValue: THeadValue;
+begin
+  //HeadValue\8c^\82Ö
+  HeadValue := THeadValue.Create;
+  HeadValue['MID'] := Log.MID;
+  HeadValue['Channel'] := Log.Channel;
+//  HeadValue['SEND'] := 'SSTP/1.4';
+//  HeadValue['Sender'] := 'SSTP Bottle ' + Log.Channel;
+  HeadValue['IfGhost'] := Log.Ghost;
+  HeadValue['Script'] := Log.Script;
+//  HeadValue['Charset'] := 'Shift_JIS';
+//  HeadValue['DialogMessage'] := Log.Script;
+  try
+    //\83\81\83b\83Z\81[\83W\8eó\90M\8f\88\97\9d\82Ö
+    DispatchBottle(HeadValue, Log.LogTime, Log.Votes, Log.Agrees);
+  finally
+    HeadValue.Free;
+  end;
+end;
+
+procedure TfrmSender.SetScriptAutoBackup;
+begin
+  //\83o\83b\83N\83A\83b\83v\83^\83C\83}\81[\82Ö\92l\82Ì\83Z\83b\83g
+  frmSender.ScriptBackup.Enabled := Pref.ScriptBackup;
+  frmSender.ScriptBackup.Interval := Pref.ScriptBackupTime * 60000;
+end;
+
+procedure TfrmSender.ScriptBackupTimer(Sender: TObject);
+var
+  Script: string;
+begin
+  // \83X\83N\83\8a\83v\83g\82Ì\83o\83b\83N\83A\83b\83v
+  if FScriptBackupModified then
+  begin
+    Script := FormatDateTime('yy/mm/dd hh:nn:ss', Now) + #13#10 + GetScriptText;
+
+    AppendTextLog(FScriptBackupDir + FScriptBackupFile, Script,
+      not Pref.ScriptBackupMode);
+
+    ShowHintLabel('\83o\83b\83N\83A\83b\83v\8eÀ\8ds');
+    FScriptBackupModified := False;
+  end;
+end;
+
+procedure TfrmSender.UpdateChannelList;
+var
+  Ch: TChannelListItem;
+  i: integer;
+begin
+  // \83`\83\83\83\93\83l\83\8b\83S\81[\83X\83g\92è\8b`
+  ChannelList.Clear;
+  // \83t\83\89\83O\82ð\8c©\82Ä\94»\92f
+  if NOT Pref.GhostCh then exit;
+  if (Pref.GhostChList.Count mod 2) = 1 then
+  begin
+    Pref.GhostChList.Add(''); // \95s\91«\82µ\82Ä\82¢\82é\82Ì\82Å\93K\93\96\82É\92Ç\89Á
+    ShowMessage('\83`\83\83\83\93\83l\83\8b\82ð\8dÄ\90Ý\92è\82µ\82Ä\82­\82¾\82³\82¢');
+    exit;
+  end;
+  i := 0;
+  while i < Pref.GhostChList.Count-1 do
+  begin
+    Ch := TChannelListItem.Create;
+    Ch.Name    := Pref.GhostChList.Strings[i];
+    Ch.Ghost   := Pref.GhostChList.Strings[i+1];
+    Ch.Info    := '';
+    Ch.NoPost  := false;
+    Ch.Members := 0;
+    Ch.WarnPost:= false;
+    ChannelList.Add(Ch);
+    i := i + 2;
+  end;
+end;
+
+procedure TfrmSender.UpdateJoinChannelList;
+begin
+  UpdateChannelList;  // \83`\83\83\83\93\83l\83\8b\90Ý\92è
+  with tabChannel do  // \96¢\8eg\97p
+  begin
+    OnChange := nil;
+    Tabs.BeginUpdate;
+    Tabs.Clear;
+    Tabs.EndUpdate;
+    actSend.Hint := Format('\91\97\90M|%s', [SendButtonLongHint]);
+    actNextChannel.Enabled := false;
+    actPrevChannel.Enabled := false;
+    OnChange := tabChannelChange;
+  end;
+end;
+
+procedure TfrmSender.PerformFileOpen(const AFileName: string);
+begin
+  // \8eÀ\8dÛ\82É\83t\83@\83C\83\8b\82ð\8aJ\82­
+  Screen.Cursor := crHourGlass;
+  try
+    memScript.Lines.LoadFromFile(AFileName);
+    SetFileName(AFileName, true, true);
+    Pref.TextDir := ExtractFileDir(AFileName);
+  except
+    on E: Exception do
+    begin
+      ShowMessage('\83G\83\89\81[:'#13#10#13#10 + E.Message);
+      SetFileName(NewFileTitle, true, true);  // \8e¸\94s\82µ\82½\8e\9e\82Í\83^\83C\83g\83\8b\8f\89\8aú\89»\81B
+    end;
+  end;
+  Screen.Cursor := crDefault;
+  memScript.SetFocus;
+  EditerStatusChange;
+end;
+
+procedure TfrmSender.PerformFileSave(const AFileName: string);
+begin
+  // \8eÀ\8dÛ\82É\95Û\91\82·\82é
+  Screen.Cursor := crHourGlass;
+  try
+    memScript.Lines.SaveToFile(AFileName);
+    SetFileModified(false);
+    Pref.TextDir := ExtractFileDir(AFileName);
+  except
+    on E: Exception do
+      ShowMessage('\83G\83\89\81[:'#13#10#13#10 + E.Message);
+  end;
+  Screen.Cursor := crDefault;
+end;
+
+procedure TfrmSender.actFileOpenExecute(Sender: TObject);
+begin
+  // \8aJ\82­
+  if CheckFileModified(Self) = idCancel then exit;
+  OpenDialog.InitialDir := Pref.TextDir;
+  if OpenDialog.Execute then
+    if CheckFileExt(OpenDialog.FileName) then // \8ag\92£\8eq\82Ì\83`\83F\83b\83N
+      PerformFileOpen(OpenDialog.FileName);
+end;
+
+procedure TfrmSender.SetFileName(const FileName: string; Reset, SetNewFile: boolean);
+var
+  FPath: string;
+begin
+  // \83^\83C\83g\83\8b\95Ï\8dX\82Æ\83t\83@\83C\83\8b\83p\83X\83Z\83b\83g
+  // \82à\82µ\81A\91æ\93ñ\88ø\90\94\82ªfalse\82È\82ç\83^\83C\83g\83\8b\82¾\82¯\95Ï\8dX
+  if Reset then
+  begin
+    SetFileModified(false);               // \95Ï\8dX\96³\82µ\82É
+    FScriptBackupModified := false;       // \8e©\93®\95Û\91\88ê\8e\9e\92â\8e~
+    DeleteBackupFile(FScriptBackupFile);  // \88ê\8e\9e\83t\83@\83C\83\8b\8dí\8f\9c\82Ö
+  end;
+
+  if SetNewFile then
+    FFileName := FileName;                // \8d¡\8c»\8dÝ\82Ì\95Ò\8fW\83t\83@\83C\83\8b\96¼
+
+  FPath := ExtractFileName(FileName);
+
+  if Pref.ScriptBackupMode then
+    FScriptBackupFile := FormatDateTime('yymmddhhnnss', Now) + FPath
+  else
+    FScriptBackupFile := StdBackupFile;
+  Self.Caption := Format('%s - %s', [FPath, FOriginalCaption]);
+end;
+
+function TfrmSender.CheckFileModified(Sender: TObject): integer;
+var
+  Res: integer;
+begin
+  // \83t\83@\83C\83\8b\82Ì\95Ï\8dX\82ð\8am\94F
+  // Result := idCancel\82Å\8fI\97¹\91j\8e~
+  if FFileModified then
+  begin
+    Res := MessageDlg(Format('\83t\83@\83C\83\8b %s \82Í\95Ï\8dX\82³\82ê\82Ä\82¢\82Ü\82·\81B'#13#10#13#10 +
+      '\95Û\91\82µ\82Ü\82·\82©\81H', [FFileName]), mtConfirmation, mbYesNoCancel, 0);
+    if Res = idYes then Res := FileSave(Self);
+  end else
+    Res := idNo;
+  Result := Res;
+end;
+
+function TfrmSender.FileSave(Sender: TObject): integer;
+var
+  Res: integer;
+begin
+  // \8fã\8f\91\82«
+  if FFileName = NewFileTitle then
+    Res := FileSaveAs(Sender)       // \96¼\91O\82ð\95t\82¯\82Ä\95Û\91\82Ö
+  else
+  begin
+    PerformFileSave(FFileName);     // \8eÀ\8dÛ\82É\95Û\91\82·\82é\82Ö
+    Res := idNo;
+  end;
+  Result := Res;
+end;
+
+function TfrmSender.FileSaveAs(Sender: TObject): integer;
+var
+  Res: integer;
+begin
+  // \96¼\91O\82ð\95t\82¯\82Ä\95Û\91
+  Res := idYes;
+  SaveDialog.FileName := ExtractFileName(FFileName);
+  SaveDialog.InitialDir := Pref.TextDir;
+  if SaveDialog.Execute then
+  begin
+    if CheckFileExt(SaveDialog.FileName) = false then // \8ag\92£\8eq\83`\83F\83b\83N
+    begin
+      Res := idCancel;
+      abort;
+    end;
+    if FileExists(SaveDialog.FileName) then
+      Res := MessageDlg(Format('%s \82Í\8aù\82É\91\8dÝ\82µ\82Ä\82¢\82Ü\82·\81B'#13#10 + '\8fã\8f\91\82«\82µ\82Ü\82·\82©\81H',
+        [SaveDialog.FileName]), mtConfirmation, mbYesNoCancel, 0);
+    if Res = idYes then
+    begin
+      PerformFileSave(SaveDialog.FileName);
+      SetFileName(SaveDialog.FileName, true, true);
+    end;
+  end else
+    Res := idCancel;
+  Result := Res;
+end;
+
+procedure TfrmSender.actFileSaveAsExecute(Sender: TObject);
+begin
+  // \96¼\91O\82ð\95t\82¯\82Ä\95Û\91\8cÄ\82Ñ\8fo\82µ
+  FileSaveAs(Self);
+end;
+
+procedure TfrmSender.actFileSaveExecute(Sender: TObject);
+begin
+  // \8fã\8f\91\82«\95Û\91\8cÄ\82Ñ\8fo\82µ
+  FileSave(Self);
+end;
+
+procedure TfrmSender.SetFileModified(Value: boolean);
+begin
+  // \83t\83@\83C\83\8b\95Ï\8dX\83t\83\89\83O\82Æ\95\\8e¦\95Ï\8dX
+  if Value then
+    StatusBar.Panels[PanelConnecting].Text := '\95Ï\8dX'
+  else
+    StatusBar.Panels[PanelConnecting].Text := '';
+  FFileModified := Value;
+end;
+
+procedure TfrmSender.OpenBrowser(const Url: string);
+var
+  Command: string;
+begin
+  if Pref.BrowserExeName = '' then
+  begin
+    ShellExecute(Handle, 'open', PChar(Url), nil, nil, SW_SHOW);
+  end else
+  begin
+    Command := Pref.BrowserExeName + ' ' + Url;
+    WinExec(PChar(Command), SW_SHOW);
+  end;
+end;
+
+function TfrmSender.CheckFileExt(const FileName: string): boolean;
+var
+  Res: boolean;
+begin
+  // \8ag\92£\8eq.bak\82Ì\83t\83@\83C\83\8b\82Í\93Ç\8f\91\82«\82µ\82È\82¢\81B
+  Res := true;
+  if LowerCase(ExtractFileExt(FileName)) = '.bak' then  // StdBackupFile\82Æ\93¯\8ag\92£\8eq
+  begin
+    beep;
+    ShowMessage('\8ag\92£\8eqbak\82Í\88µ\82¦\82Ü\82¹\82ñ\81B'#13#10 + '\91¼\82Ì\83G\83f\83B\83^\82ð\8eg\97p\82µ\82Ä\82­\82¾\82³\82¢\81B');
+    Res := false;
+  end;
+  Result := Res;
+end;
+
+procedure TfrmSender.DeleteBackupFile(const FileName: string);
+var
+  FPath: string;
+begin
+  // \8fã\8f\91\95Û\91\82Ì\88ê\8e\9e\83t\83@\83C\83\8b\82ð\8dí\8f\9c
+  if Pref.NoDeleteBackupFile or (FileName = '') or
+    (StdBackupFile = FileName) then exit;
+
+  FPath := FScriptBackupDir + FileName;
+  try
+    if FileExists(FPath) then
+      DeleteFile(FPath);
+  except
+    on E: Exception do
+      ShowMessage('\88ê\8e\9e\83t\83@\83C\83\8b\8dí\8f\9c\83G\83\89\81[:'#13#10#13#10 + E.Message);
   end;
 end;