private void btnOk_Click(object sender, EventArgs e)
    {
        if (oldPlugins != null)
        {
            // 削除されたスクリプトをアンインストールする
            foreach (string file in oldPlugins)
            {
                if (!getPlugins().Contains(file))
                {
                    string name = getPluginName(file);
                    if (name != "")
                    {
                        string script_path = Path.Combine(Utility.getScriptPath(), name + ".txt");
                        if (File.Exists(script_path))
                        {
                            PortUtil.deleteFile(script_path);
                        }
                    }
                }
            }
        }

        foreach (string file in getPlugins())
        {
            if (!File.Exists(file))
            {
                continue;
            }

            string name = getPluginName(file);
            if (name == "")
            {
                continue;
            }
            char[] invalid_classname = new char[] { ' ', '!', '#', '$', '%', '&', '\'', '(', ')', '=', '-', '~', '^', '`', '@', '{', '}', '[', ']', '+', '*', ';', '.' };
            foreach (char c in invalid_classname)
            {
                name = name.Replace(c, '_');
            }
            string text = TEXT;
            string code = text.Replace("{0}", name);
            code = code.Replace("{1}", file);
            using (StreamWriter sw = new StreamWriter(Path.Combine(Utility.getScriptPath(), name + ".txt"))) {
                sw.WriteLine(code);
            }
        }

        if (AppManager.mMainWindow != null)
        {
            VoidDelegate deleg = new VoidDelegate(AppManager.mMainWindow.updateScriptShortcut);
            if (deleg != null)
            {
                AppManager.mMainWindow.Invoke(deleg);
            }
        }
    }
    public static bool Edit(VsqFile vsq)
    {
        using (RenderAsUtau dlg = new RenderAsUtau()) {
            if (dlg.ShowDialog() == DialogResult.OK)
            {
                Singer    = dlg.txtSinger.Text;
                Resampler = dlg.txtResampler.Text;
                WavTool   = dlg.txtWavtool.Text;
                string script   = Path.Combine(Application.StartupPath, Path.Combine("script", "Render As UTAU.cs"));  //Script.ScriptPath;
                string temp_dir = Path.Combine(Path.GetDirectoryName(script), Path.GetFileNameWithoutExtension(script));

#if DEBUG
                if (!Directory.Exists(temp_dir))
                {
                    Directory.CreateDirectory(temp_dir);
                }
                StreamWriter sw = new StreamWriter(Path.Combine(temp_dir, "log.txt"));
#endif
                // 原音設定を読み込み
                Dictionary <string, OtoArgs> config = new Dictionary <string, OtoArgs>();
                string singer_name = Path.GetFileName(Singer);
                string config_file = Path.Combine(Singer, "oto.ini");
#if DEBUG
                sw.WriteLine("Singer=" + Singer);
                sw.WriteLine("singer_name=" + singer_name);
                sw.WriteLine("config_file=" + config_file);
#endif
                if (File.Exists(config_file))
                {
                    using (cp932reader sr = new cp932reader(config_file)) {
                        string line;
                        while (sr.Peek() >= 0)
                        {
                            try {
                                line = sr.ReadLine();
                                String[] spl       = line.Split('=');
                                String   file_name = spl[0]; // あ.wav
                                String   a2        = spl[1]; // ,0,36,64,0,0
                                String   a1        = Path.GetFileNameWithoutExtension(file_name);
                                spl = a2.Split(',');
                                OtoArgs oa = new OtoArgs();
                                oa.Alias          = spl[0];
                                oa.msOffset       = int.Parse(spl[1]);
                                oa.msConsonant    = int.Parse(spl[2]);
                                oa.msBlank        = int.Parse(spl[3]);
                                oa.msPreUtterance = int.Parse(spl[4]);
                                oa.msOverwrap     = int.Parse(spl[5]);
                                config.Add(a1, oa);
                            } catch {
                            }
                        }
                    }
                }

                int         track = AppManager.getSelected();
                List <Phon> phons = new List <Phon>();
                if (!Directory.Exists(temp_dir))
                {
                    Directory.CreateDirectory(temp_dir);
                }
                int    count       = -1;
                double sec_end     = 0;
                double sec_end_old = 0;
                for (Iterator <VsqEvent> itr = vsq.Track.get(track).getNoteEventIterator(); itr.hasNext();)
                {
                    VsqEvent item = itr.next();
                    count++;
                    double sec_start = vsq.getSecFromClock(item.Clock);
                    sec_end_old = sec_end;
                    sec_end     = vsq.getSecFromClock(item.Clock + item.ID.Length);
                    float t_temp = (float)(item.ID.Length / (sec_end - sec_start) / 8.0);
                    if ((count == 0 && sec_start > 0.0) || (sec_start > sec_end_old))
                    {
                        double sec_start2 = sec_end_old;
                        double sec_end2   = sec_start;
                        float  t_temp2    = (float)(item.Clock / (sec_end2 - sec_start2) / 8.0);
                        phons.Add(new Phon("R", Path.Combine(Singer, "R.wav"), item.Clock, t_temp2, true));
                        count++;
                    }
                    string lyric = item.ID.LyricHandle.L0.Phrase;
                    string note  = NoteStringFromNoteNumber(item.ID.Note);
#if DEBUG
                    sw.WriteLine("note=" + note);
#endif
                    string millisec = ((int)((sec_end - sec_start) * 1000) + 50).ToString();

                    //4_あ_C#4_550.wav
                    string filename = Path.Combine(temp_dir, count + "_" + item.ID.Note + "_" + millisec + ".wav");
#if DEBUG
                    sw.WriteLine("filename=" + filename);
                    sw.WriteLine();
#endif
                    if (File.Exists(filename))
                    {
                        PortUtil.deleteFile(filename);
                    }

                    phons.Add(new Phon(lyric, filename, item.ID.Length, t_temp, false));

                    OtoArgs oa = new OtoArgs();
                    if (config.ContainsKey(lyric))
                    {
                        oa = config[lyric];
                    }
                    int    velocity     = 100;
                    int    moduration   = 100;
                    string flags        = "L";
                    int    time_percent = 100;
                    //                                                                                          C4             100                  L             0                   550              0                      0                  100              100
                    string arg = "\"" + Path.Combine(Singer, lyric + ".wav") + "\" \"" + filename + "\" \"" + note + "\" " + time_percent + " " + flags + " " + oa.msOffset + " " + millisec + " " + oa.msConsonant + " " + oa.msBlank + " " + velocity + " " + moduration;

                    using (System.Diagnostics.Process p = new System.Diagnostics.Process()) {
                        p.StartInfo.FileName         = (InvokeWithWine ? "wine \"" : "\"") + Resampler + "\"";
                        p.StartInfo.Arguments        = arg;
                        p.StartInfo.WorkingDirectory = temp_dir;
                        p.StartInfo.WindowStyle      = System.Diagnostics.ProcessWindowStyle.Hidden;
                        p.Start();
                        p.WaitForExit();
                    }
                }
#if DEBUG
                sw.Close();
#endif

                string filebase = "temp.wav";
                string file     = Path.Combine(temp_dir, filebase);
                if (File.Exists(file))
                {
                    PortUtil.deleteFile(file);
                }
                string file_whd = Path.Combine(temp_dir, filebase + ".whd");
                if (File.Exists(file_whd))
                {
                    PortUtil.deleteFile(file_whd);
                }
                string file_dat = Path.Combine(temp_dir, filebase + ".dat");
                if (File.Exists(file_dat))
                {
                    PortUtil.deleteFile(file_dat);
                }

                // wavtoolを呼び出す
                for (int i = 0; i < phons.Count; i++)
                {
                    OtoArgs oa = new OtoArgs();
                    if (config.ContainsKey(phons[i].Lyric))
                    {
                        oa = config[phons[i].Lyric];
                    }
                    // 次の音符の先行発声とオーバーラップを取得
                    OtoArgs oa_next = new OtoArgs();
                    if (i + 1 < phons.Count)
                    {
                        if (config.ContainsKey(phons[i + 1].Lyric))
                        {
                            oa_next = config[phons[i + 1].Lyric];
                        }
                    }
                    int    mten = oa.msPreUtterance + oa_next.msOverwrap - oa_next.msPreUtterance;
                    string arg  = filebase + " \"" + phons[i].FileName + "\" 0 " + phons[i].ClockLength + "@" + string.Format("{0:f2}", phons[i].Tempo) + mten.ToString("+#;-#;0");
                    if (phons[i].ModeR)
                    {
                        arg += " 0 0";
                    }
                    else
                    {
                        arg += " 0 5 35 0 100 100 100 " + oa.msOverwrap; // エンベロープ
                    }

                    using (System.Diagnostics.Process p = new System.Diagnostics.Process()) {
                        p.StartInfo.FileName         = (InvokeWithWine ? "wine \"" : "\"") + WavTool + "\"";
                        p.StartInfo.Arguments        = arg;
                        p.StartInfo.WorkingDirectory = temp_dir;
                        p.StartInfo.WindowStyle      = System.Diagnostics.ProcessWindowStyle.Hidden;
                        p.Start();
                        p.WaitForExit();
                    }
                }

                // 波形とヘッダを結合
                using (FileStream fs = new FileStream(file, FileMode.Create)) {
                    string[] files  = new string[] { file_whd, file_dat };
                    int      buflen = 512;
                    byte[]   buff   = new byte[buflen];
                    for (int i = 0; i < files.Length; i++)
                    {
                        using (FileStream fs2 = new FileStream(files[i], FileMode.Open)) {
                            int len = fs2.Read(buff, 0, buflen);
                            while (len > 0)
                            {
                                fs.Write(buff, 0, len);
                                len = fs2.Read(buff, 0, buflen);
                            }
                        }
                    }
                }

                // 後片付け
                foreach (Phon ph in phons)
                {
                    if (!ph.ModeR)
                    {
                        if (File.Exists(ph.FileName))
                        {
                            PortUtil.deleteFile(ph.FileName);
                        }
                    }
                }
                if (File.Exists(file_whd))
                {
                    PortUtil.deleteFile(file_whd);
                }
                if (File.Exists(file_dat))
                {
                    PortUtil.deleteFile(file_dat);
                }

                if (saveFileDialog.ShowDialog() == DialogResult.OK)
                {
                    if (File.Exists(saveFileDialog.FileName))
                    {
                        PortUtil.deleteFile(saveFileDialog.FileName);
                    }
                    LastWave = saveFileDialog.FileName;
                    PortUtil.moveFile(file, saveFileDialog.FileName);
                }
                else
                {
                    PortUtil.deleteFile(file);
                }
                return(true);
            }
            else
            {
                return(false);
            }
        }
    }