RCWはファイナライズで自動的にReleaseするっぽい。検証してみた。

正攻法で考えると、ReleaseComObject を必ず行う。なのだけど。。。

CLR 徹底解剖: オブジェクトの有効期間を管理する

マネージ コードから COM コンポーネントを使用する場合、tlbimp.exe を使用
していわゆるランタイム呼び出し可能ラッパー (RCW) を生成します。RCW によっ
て COM コンポーネントの機能がマネージ環境に公開されます。なお、tlbimp.exe 
は、Visual Studio® で COM コンポーネントを参照するとバックグラウンドで実行
されます。RCW はデバッガで System.__ComObject と表示されるので、簡単に識別
できます。RCW は、COM オブジェクトへのアンマネージ ポインタを 1 つ保持し、
オブジェクトで AddRef および Release を呼び出す .NET 型です。AddRef はコン
ポーネントが作成されると呼び出され、Release は RCW がファイナライズされると
呼び出されます。

という記事をみつけた。
「ReleaseはRCWがファイナライズされると呼び出されます。」と書かれてる。

これはつまり、
ReleaseComObject を全く行わずとも、GCでファイナライズを強制実行させればCOMも解放できるということか?

試してみる。
流れとしては、
フォームの上のボタンを押すとExcel呼び出してセルに書いたりする。
最後にファイナライズを強制実行する。

using System.Runtime.InteropServices;
:
       private void button1_Click(object sender, System.EventArgs e)
       {
           this.excel_ctrl();

           // 以下を、excel_ctrl の中に入れてしまうと、Excelプロセスが残るのでここに配置してみた。
           System.GC.Collect();                  // アクセス不可能なオブジェクトを除去
           System.GC.WaitForPendingFinalizers(); // ファイナライゼーションが終わるまでスレッド待機
           System.GC.Collect();                  // ファイナライズされたばかりのオブジェクトに関連するメモリを開放
       }

       private void excel_ctrl()
       {
           Excel.Application excel = new Excel.Application();
           excel.Visible = true;

           excel.Workbooks.Add(Type.Missing);
           Excel.Worksheet worksheet = (Excel.Worksheet)excel.ActiveSheet;

           ((Excel.Range)worksheet.get_Range("C6", Type.Missing)).Value2 = "Hello";
           ((Excel.Range)worksheet.get_Range("C6", Type.Missing)).Interior.ColorIndex = 6;

           ((Excel.Worksheet)excel.ActiveSheet).get_Range("C7", Type.Missing).Value = "xxx";
           ((Excel.Worksheet)excel.ActiveSheet).get_Range("C7", Type.Missing).Borders.ColorIndex = 7;

           ((Excel.Worksheet)excel.ActiveSheet).Copy(excel.ActiveSheet, Type.Missing);

           excel.Quit();
       }

Excelプロセス残らない。
ちょっと驚いた。

ただし、Finalizeでのリソース解放は最終手段であるし、実際
Object.Finalize メソッド (System)
によると、

  • ガベージ コレクション実行中のファイナライザの実行時期は未定義です。
  • 2 つのオブジェクトのファイナライザが特定の順序で実行されることは保証されません。

とあるので、これに頼ってしまってよいのか疑問は残るんだけどね。

C#からExcelを操作するライブラリ

はじめに。

C#からPIAでExcelCOM使うとリークしてしまうのが難点。

ExcelCOMに1枚クラスを被せることで
使いにくいExcelCOMの存在をできるだけ隠蔽することを試みます。

  • クラスを被せることのメリット
    • COMの解放(Marshal.ReleaseComObject)のことを考えなくてよくなる。
      • わずらわしいリークに悩まされることが激減する。
    • COMの戻り値を適切な型にキャストしたりしなくてよい。
      • キャストミスによるトラブルに悩まされることが激減する。
      • インテリセンス(入力支援)が効くので作業効率アップ。
  • クラスを被せることのデメリット
    • ExcelのCOMオブジェクト、メソッド、プロパティを1つずつラッピングする必要がある。
      • 膨大なので全てをラッピングするのは不可能なので、よく使いそうなものだけ対応。

ライブラリ仕様

  • 特徴
    • Marshal.ReleaseComObject はライブラリ側で自動で行う。
    • Excel2000、ExcelXP(2002) PIA 対応。(#defineで指定)
  • その他
    • Excel2003、2007 PIA でも使えるかもしれません。
    • PIAは.NETとCOMのI/Fなので、開発をExcel2000PIAで行っていれば、(COMレベルの互換性によりますが)ExcelXP以上でも動くはず。

Visual C# Express 2008 で作ったもの一式はこちら。
http://goungoun.dip.jp/app/upload/libSimpleExcel/libSimpleExcel20090210.zip

対応してるExcelオブジェクト、メソッド、プロパティ一覧

対応しているのは次のクラス(Excelオブジェクト)、メソッド、プロパティ
のみです。足りないものは既存のものを参考に追加してください。

  • class Application
    • bool Visible
    • bool DisplayAlerts
    • Workbooks Workbooks
    • void Quit()
  • class Workbooks
    • Workbook Open(string filename_,bool read_only_,Excel.XlFileFormat format_,string delimiter_)
    • Workbook Open(string filename_, bool read_only_)
    • Workbook Add()
    • int Count
    • Workbook this[int idx_]
    • Workbook this[string name_]
  • class Workbook
    • Sheets Sheets
  • class Sheets
    • int Count
    • Worksheet this[int idx_]
    • Worksheet this[string name_]
  • class Worksheet
    • string Name
    • void Delete()
    • void CopyAfter(Worksheet aft_)
    • void CopyBefore(Worksheet bef_)
    • Range Cells
    • Range Range
    • Range Rows(int row_)
    • Range Columns(int col_)
  • class Range
    • Range this[int row_, int col_]
    • Range this[Range cell1_, Range cell2_]
    • Range Resize(int row_, int col_)
    • bool Delete()
    • bool Delete(Excel.XlDeleteShiftDirection direction_)
    • object Value
    • Font Font
    • Interior Interior
  • class Font
    • int ColorIndex
    • bool Bold
  • class Interior
    • int ColorIndex
    • Excel.XlPattern Pattern

PIAの入手方法

Office2000なら、Interop.Excel.dll
OfficeXPなら、Microsoft.Office.Interop.Excel.dll

入手先は、

Office2000なら。
プロジェクト→参照の追加→COMタブ→
Microsoft Excel 9.0 Object Livraly 1.3
X:\Program Files\Microsoft Office\Office\EXCEL9.OLB

Office XP PIAなら。
Microsoft Office XP 用の PIA (Primary Interop Assemblies) のダウンロード
http://support.microsoft.com/kb/328912/ja


ソース

lib.SimpleExcel.cs(ライブラリ側)

使用するPIAの種類に応じて先頭のdefineを切り替える。

//#define PIA_OFFICE_2000
#define PIA_OFFICE_XP

using System;
using System.Collections;
using System.Runtime.InteropServices;
#if PIA_OFFICE_XP
using Excel = Microsoft.Office.Interop.Excel;
#endif

namespace lib.SimpleExcel
{
    /// <summary>
    /// Excel関連のオブジェクトを分類する為の独自クラス
    /// </summary>
    public class Object : Base
    {
        private string _type_name = "";

        public Object(Base parent_, object comobj_)
            : base(parent_, comobj_)
        {
            if (comobj_ == null)
            {
                this._type_name = "null";
            }
            else if (Marshal.IsComObject(comobj_))
            {
                if ((comobj_ as Excel.Range) != null)
                {
                    this._type_name = "Excel.Range";
                }
                else if ((comobj_ as Excel.Range) != null)
                {
                    this._type_name = "Excel.Range";
                }
            }
            if (this._type_name == "")
            {
                Type t = comobj_.GetType();
                this._type_name = t.FullName;
            }
        }

        public string TypeName
        {
            get { return this._type_name; }
        }
    }

    /// <summary>
    /// Base
    /// </summary>
    public abstract class Base : IDisposable
    {
        private static int _com_object_counter = 0;
        private Base _parent = null;
        private ArrayList _childs = null;
        protected object _comobj = null;

        /// <summary>
        /// 現在使用中の Excel COM の数
        /// 0 でない場合、Excelプロセス が開放されていないことになるので、
        /// 本ライブラリでExcel操作後は、必ず0になっている*はず*
        /// </summary>
        public static int ComObjectCounter
        {
            get { return Base._com_object_counter; }
        }

        /// <summary>
        /// Excelのプロセスを取得
        /// IDとウィンドウタイトルから素性を判断できる。
        /// </summary>
        /// <param name="msg_"></param>
        /// <returns></returns>
        public static System.Diagnostics.Process[] GetExcelProcess(ref string msg_)
        {
            System.Diagnostics.Process[] ps =
                System.Diagnostics.Process.GetProcessesByName("Excel");

            msg_ = "";
            foreach (System.Diagnostics.Process p in ps)
            {
                msg_ += string.Format("Id:{0} Title:{1} \r\n", p.Id, p.MainWindowTitle);
            }
            return ps;
        }

        public Base(Base parent_, object comobj_)
        {
            //          if (parent_ == null)
            //          {
            //              System.Windows.Forms.MessageBox.Show("null");
            //          }

            this._parent = parent_;
            if (parent_ != null)
            {
                parent_.AddChild(this);
            }

            this._childs = new ArrayList();

            this._comobj = comobj_;
            if (Marshal.IsComObject(this._comobj))
            {
                Base._com_object_counter++;
            }
        }

        public object ComObject
        {
            get { return this._comobj; }
        }

        protected void AddChild(Base obj_)
        {
            this._childs.Add(obj_);
        }

        public void Dispose()
        {
            // 子を破棄
            if (this._childs != null)
            {
                for (int idx = 0; idx < this._childs.Count; idx++)
                {
                    Base obj = (Base)this._childs[idx];
                    obj.Dispose();
                }
                this._childs = null;
            }

            // 自分を破棄
            if (this._comobj != null && Marshal.IsComObject(this._comobj))
            {
                Marshal.ReleaseComObject(this._comobj);
                Base._com_object_counter--;
            }
            this._comobj = null;

            // 親情報を削除
            this._parent = null;

            GC.Collect();   // 一応と思っていたら、これがないとExcelで一般保護違反がでることがあった。
        }
    }

    /// <summary>
    /// Excel.Application
    /// </summary>
    public class Application : Base
    {
        public Application()
            : base(null, new Excel.Application())
        {
        }

        private Excel.Application _application
        {
            get { return (Excel.Application)this._comobj; }
        }

        public bool Visible
        {
            get { return this._application.Visible; }
            set { this._application.Visible = value; }
        }

        public bool DisplayAlerts
        {
            get { return this._application.DisplayAlerts; }
            set { this._application.DisplayAlerts = value; }
        }

        public Workbooks Workbooks
        {
            get { return new Workbooks(this, this._application.Workbooks); }
        }

        public void Quit()
        {
            this._application.Quit();
        }
    }

    /// <summary>
    /// Excel.Workbooks
    /// </summary>
    public class Workbooks : Base
    {
        public Workbooks(Base parent_, object comobj_)
            : base(parent_, comobj_)
        {
        }

        private Excel.Workbooks _workbooks
        {
            get { return (Excel.Workbooks)this._comobj; }
        }

        private object _workbooks_open(string Filename, object UpdateLinks, object ReadOnly, object Format, object Password, object WriteResPassword, object IgnoreReadOnlyRecommended, object Origin, object Delimiter, object Editable, object Notify, object Converter, object AddToMru, object Local, object CorruptLoad)
        {
#if PIA_OFFICE_2000
            object ret = this._workbooks.Open(Filename, UpdateLinks, ReadOnly, Format, Password, WriteResPassword, IgnoreReadOnlyRecommended, Origin, Delimiter, Editable, Notify, Converter, AddToMru);
#endif
#if PIA_OFFICE_XP
            object ret = this._workbooks.Open(Filename, UpdateLinks, ReadOnly, Format, Password, WriteResPassword, IgnoreReadOnlyRecommended, Origin, Delimiter, Editable, Notify, Converter, AddToMru, Local, CorruptLoad);
#endif
            return ret;
        }

        public Workbook Open(
            string filename_,
            bool read_only_,
            Excel.XlFileFormat format_,
            string delimiter_
            )
        {
            return new Workbook(this, this._workbooks_open(
                filename_,
                Type.Missing,
                read_only_,
                format_,
                Type.Missing,
                Type.Missing,
                Type.Missing,
                Type.Missing,
                delimiter_,
                Type.Missing,
                Type.Missing,
                Type.Missing,
                Type.Missing,
                Type.Missing,
                Type.Missing));
        }

        public Workbook Open(string filename_, bool read_only_)
        {
            return new Workbook(this, this._workbooks_open(
                filename_,
                Type.Missing,
                read_only_,
                Type.Missing,
                Type.Missing,
                Type.Missing,
                Type.Missing,
                Type.Missing,
                Type.Missing,
                Type.Missing,
                Type.Missing,
                Type.Missing,
                Type.Missing,
                Type.Missing,
                Type.Missing));
        }

        public Workbook Add()
        {
            return new Workbook(this, this._workbooks.Add(Type.Missing));
        }

        public int Count
        {
            get { return this._workbooks.Count; }
        }

        public Workbook this[int idx_]
        {
            get { return new Workbook(this, this._workbooks.get_Item(idx_)); }
        }

        public Workbook this[string name_]
        {
            get { return new Workbook(this, this._workbooks.get_Item(name_)); }
        }
    }

    /// <summary>
    /// Excel.Workbook
    /// </summary>
    public class Workbook : Base
    {
        public Workbook(Base parent_, object comobj_)
            : base(parent_, comobj_)
        {
        }

        private Excel.Workbook _workbook
        {
            get { return (Excel.Workbook)this._comobj; }
        }

        public Sheets Sheets
        {
            get { return new Sheets(this, this._workbook.Sheets); }
        }
    }

    /// <summary>
    /// Excel.Sheets
    /// </summary>
    public class Sheets : Base
    {
        public Sheets(Base parent_, object comobj_)
            : base(parent_, comobj_)
        {
        }

        private Excel.Sheets _sheets
        {
            get { return (Excel.Sheets)this._comobj; }
        }

        public int Count
        {
            get { return this._sheets.Count; }
        }

        public Worksheet this[int idx_]
        {
            get { return new Worksheet(this, this._sheets.get_Item(idx_)); }
        }

        public Worksheet this[string name_]
        {
            get { return new Worksheet(this, this._sheets.get_Item(name_)); }
        }
    }

    /// <summary>
    /// Excel.Worksheet
    /// </summary>
    public class Worksheet : Base
    {
        public Worksheet(Base parent_, object comobj_)
            : base(parent_, comobj_)
        {
        }

        private Excel.Worksheet _worksheet
        {
            get { return (Excel.Worksheet)this._comobj; }
        }

        public string Name
        {
            get { return this._worksheet.Name; }
            set { this._worksheet.Name = value; }
        }

        public void Delete()
        {
            this._worksheet.Delete();
        }

        public void CopyAfter(Worksheet aft_)
        {
            // 指定したワークシートの右側へコピー
            // this._worksheet を aft_ の 右側へコピー
            this._worksheet.Copy(Type.Missing, aft_._comobj);
        }

        public void CopyBefore(Worksheet bef_)
        {
            // 指定したワークシートの左側へコピー
            // this._worksheet を bef_ の 左側へコピー
            this._worksheet.Copy(bef_._comobj, Type.Missing);
        }

        public Range Cells
        {
            get { return new Range(this, this._worksheet.Cells); }
        }

        public Range Range
        {
            get { return new Range(this, this._worksheet.Cells); }
        }

        public Range Rows(int row_)
        {
            return new Range(this, this._worksheet.Rows[row_, Type.Missing]);
        }

        public Range Columns(int col_)
        {
            return new Range(this, this._worksheet.Columns[Type.Missing, col_]);
        }
    }

    /// <summary>
    /// Excel.Range
    /// </summary>
    public class Range : Base
    {
        public Range(Base parent_, object comobj_)
            : base(parent_, comobj_)
        {
        }

        private Excel.Range _range
        {
            get { return (Excel.Range)this._comobj; }
        }

        public Range this[int row_, int col_]
        {
            get { return new Range(this, this._range.get_Item(row_, col_)); }
        }

        public Range this[Range cell1_, Range cell2_]
        {
            get { return new Range(this, this._range.get_Range(cell1_._comobj, cell2_._comobj)); }
        }

        public Range Resize(int row_, int col_)
        {
            return new Range(this, this._range.get_Resize(row_, col_));
        }

        public bool Delete()
        {
            return (bool)this._range.Delete(Type.Missing);
        }

        public bool Delete(Excel.XlDeleteShiftDirection direction_)
        {
            return (bool)this._range.Delete(direction_);
        }

        public object Value
        {
#if PIA_OFFICE_2000
            get { return this._range.Value; }
            set { this._range.Value = value; }
#endif
#if PIA_OFFICE_XP
            get { return this._range.get_Value(Excel.XlRangeValueDataType.xlRangeValueDefault); }
            set { this._range.set_Value(Excel.XlRangeValueDataType.xlRangeValueDefault, value); }
#endif
        }

        public Font Font
        {
            get { return new Font(this, this._range.Font); }
        }

        public Interior Interior
        {
            get { return new Interior(this, this._range.Interior); }
        }
    }

    /// <summary>
    /// Excel.Font
    /// </summary>
    public class Font : Base
    {
        public Font(Base parent_, object comobj_)
            : base(parent_, comobj_)
        {
        }

        private Excel.Font _font
        {
            get { return (Excel.Font)this._comobj; }
        }

        public int ColorIndex
        {
            get { return (int)this._font.ColorIndex; }
            set { this._font.ColorIndex = value; }
        }

        public bool Bold
        {
            get { return (bool)this._font.Bold; }
            set { this._font.Bold = value; }
        }
    }

    /// <summary>
    /// Excel.Interior
    /// </summary>
    public class Interior : Base
    {
        public Interior(Base parent_, object comobj_)
            : base(parent_, comobj_)
        {
        }

        private Excel.Interior _interior
        {
            get { return (Excel.Interior)this._comobj; }
        }

        public int ColorIndex
        {
            get { return (int)this._interior.ColorIndex; }
            set { this._interior.ColorIndex = value; }
        }

        public Excel.XlPattern Pattern
        {
            get { return (Excel.XlPattern)this._interior.Pattern; }
            set { this._interior.Pattern = value; }
        }
    }

}
Form1.cs(使用例)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            lib.SimpleExcel.Application obj_app = new lib.SimpleExcel.Application();

            // 確実にオブジェクトを開放する為、usingは必須
            using (obj_app)
            {
                obj_app.DisplayAlerts = false;
                obj_app.Visible = true;

                // 新規Workbookを開く
                lib.SimpleExcel.Workbook obj_workbook = obj_app.Workbooks.Add();

                // 不要なSheetを削除
                //      MessageBox.Show(obj_workbook.Sheets.Count.ToString());
                while (obj_workbook.Sheets.Count != 1)
                {
                    obj_workbook.Sheets[2].Delete();
                }
                //      MessageBox.Show(obj_workbook.Sheets.Count.ToString());

                // Sheet名付け
                lib.SimpleExcel.Worksheet obj_sheet = obj_workbook.Sheets[1];
                obj_sheet.Name = "data";

                // 配列データをシートへ複写
                object[,] data = {
                    { "データ0-0", "データ0-1" },
                    { "データ1-0", "データ1-1" },
                };
                obj_sheet.Cells[1, 1].Value = data; // これでは1セルしかコピーされない。
                obj_sheet.Range[obj_sheet.Cells[3, 1], obj_sheet.Cells[4, 2]].Value = data;         // 明示的に範囲指定
                obj_sheet.Cells[5, 1].Resize(data.GetLength(1), data.GetLength(0)).Value = data;    // 配列データをGetLengthして範囲指定

                // セル値を読む
                object val_obj = obj_sheet.Cells[4, 2].Value;
                if ((val_obj as string) != null)
                {
                    MessageBox.Show((string)val_obj);
                }

                // 取得した型を読む
                lib.SimpleExcel.Object obj1 = new lib.SimpleExcel.Object(null, val_obj);
                //      MessageBox.Show(obj1.TypeName);

                // 範囲でセル値を読む
                val_obj = obj_sheet.Range[obj_sheet.Cells[3, 1], obj_sheet.Cells[3, 2]].Value;
                string str = "";
                if ((val_obj as object[,]) != null)
                {
                    object[,] obj2 = (object[,])val_obj;
                    for (int row = 1; row <= obj2.GetLength(0); row++)
                    {
                        for (int col = 1; col <= obj2.GetLength(1); col++)
                        {
                            if ((obj2[row, col] as string) != null)
                            {
                                str += (string)obj2[row, col] + ",";
                            }
                        }
                        str += "\n";
                    }
                }
                //      MessageBox.Show(str);

                // 行削除
                obj_sheet.Rows(1).Delete();
                obj_sheet.Rows(1).Delete();
                obj_sheet.Rows(1).Delete();
                obj_sheet.Rows(1).Delete();

                obj_app.Quit();

                //      MessageBox.Show("ComObjectCounter=" + lib.SimpleExcel.Base.ComObjectCounter.ToString());
            }
            //  MessageBox.Show("ComObjectCounter=" + lib.SimpleExcel.Base.ComObjectCounter.ToString());
            obj_app = null;

        }
    }
}

google chrome で pukiwiki の セクション編集ができない。

google chrome 試してみた。
速くていいんだけど、pukiwikiのセクション編集(secedit.inc.php)ができない。

  • pukiwikibasic認証を使ってる。
  • 普通の「編集」は行える。
  • ところが、セクションの横に編集アイコンが表示されない。

$_SERVERを見てみると、PHP_AUTH_USER が含まれていないので、
chromeが ユーザ名/パスワード を送ってきていないのだろう。
(firefoxでは含まれてた)

解決方法は今のところ不明。

lingr rhaco-ja 私的メモ 2008-08から今日まで

最近rhacoから遠のいてたので rhaco-ja を読んでみた。
ついでに私的メモ

!!20080801、nazo LivedoorAuth作る
http://www.lingr.com/room/rhaco-ja/archives/2008/08/01#msg-43866443

!!20080801、tokushima Variable::parseJson作る(Variable::toJsonの逆)
http://www.lingr.com/room/rhaco-ja/archives/2008/08/01#msg-43880050

!!20080804、riaf mixiエコーで遊んでる
http://www.lingr.com/room/rhaco-ja/archives/2008/08/04#msg-44131805
submitボタンに名前がないとBrowser->submit()できないとかなんとか

!!20080805、google groupsに投稿
http://www.lingr.com/room/rhaco-ja/archives/2008/08/05#msg-44140336
# network.http.RequestLoginでは同一ブラウザセッションで複数ログイン情報を保持するようにはなっていません。
# 仕様です。

!!20080805、shigepon YahooMAServiceうごかんで悩む
http://www.lingr.com/room/rhaco-ja/archives/2008/08/05#msg-44173755
arboとかはtrunkに追従してないので地雷っと
ん?Yahoo側?ま。いいか。

!!20080805、riaf mysqlトランザクションエラーにはまる
http://www.lingr.com/room/rhaco-ja/archives/2008/08/05#msg-44187832

!!20080806、tokushima Rhaco::import("org.rhaco.arbo.network.SvnLogger")
http://www.lingr.com/room/rhaco-ja/archives/2008/08/06#msg-44212067
# いまさらなんだけど
# Rhaco::import("org.rhaco.arbo.network.SvnLogger")
# にしてもいい?

!!20080806、frameworkfightは9末
http://www.lingr.com/room/rhaco-ja/archives/2008/08/06#msg-44248001

!!20080806、Variable::parseJsonのバグとか
http://www.lingr.com/room/rhaco-ja/archives/2008/08/06#msg-44256530

!!20080806、yabeken projext.xmlデザイナ作る
http://www.lingr.com/room/rhaco-ja/archives/2008/08/06#msg-44270972
20080813 サービス化
http://www.lingr.com/room/rhaco-ja/archives/2008/08/13#msg-44707280

!!20080807、shigepon TableObjectUtil::extractionTableColumnが消えててはまる
http://www.lingr.com/room/rhaco-ja/archives/2008/08/07#msg-44311102
# !http://rhaco.org/svn/rhaco/3155/trunk/database/TableObjectUtil.php
# 1.4.9でdeprecated
# きっとやってることが単純で、使用することがなかったから消したんだなぁ

!!20080807、kanonji project.xmlを書くのにXMLエディタとか使ってます?
http://www.lingr.com/room/rhaco-ja/archives/2008/08/07#msg-44312403

!!20080807、project*.xsdの話
http://www.lingr.com/room/rhaco-ja/archives/2008/08/07#msg-44312825
xsdはテキトー

!!20080807、riaf む、COOKIEの値は request->session に入るのか
http://www.lingr.com/room/rhaco-ja/archives/2008/08/07#msg-44321364
クッキーなんかー

!!20080807、riaf LoginCondition だけ使い回そうと思ってるので
http://www.lingr.com/room/rhaco-ja/archives/2008/08/07#msg-44321761
あー。singletonじゃないんだよね。。。
newすれば同じオブジェクトが生成されるんだろうけど。ちょっときもい。
cloneすればいいのか。

!!20080807、shigepon PDTってちゃんとコメントの@paramにクラス名書いたら補完してくれるんだ!知らなかった
http://www.lingr.com/room/rhaco-ja/archives/2008/08/07#msg-44322181
# tokushima
# それでフルパスで書くかクラス名だけにするか悩みます
補完優先=クラス名だけ
がいいなぁ。。

!!20080807、shigepon データ作成君はsqliteのdbが必須になるんですが(しかもサイズが・・・)どうしましょう?
http://www.lingr.com/room/rhaco-ja/archives/2008/08/07#msg-44327086

!!20080808、shigepon あれーBirthday型でinsert出来ないっすよ><
http://www.lingr.com/room/rhaco-ja/archives/2008/08/08#msg-44354082
http://www.lingr.com/room/rhaco-ja/archives/2008/08/08#msg-44377570

!!20080808、shigepon rhacoconveyorで出展してくれないかと言われたんですが、どーしよーか悩み中・・・
http://www.lingr.com/room/rhaco-ja/archives/2008/08/08#msg-44380625

!!20080808、tokushima つーわけでCSVのパーサ作った
http://www.lingr.com/room/rhaco-ja/archives/2008/08/08#msg-44384350

!!20080808、tokushima http://blog.shigepon.com/snippet42 へのつっこみ
http://www.lingr.com/room/rhaco-ja/archives/2008/08/08#msg-44394358

!!20080809、tokushima php4捨てて、rhaco2.0へな話
http://www.lingr.com/room/rhaco-ja/archives/2008/08/09#msg-44420539

!!20080809、frameworkfightとかrhaco2とかtry〜catchとかphp5.3の話
http://www.lingr.com/room/rhaco-ja/archives/2008/08/09#msg-44454830

!!20080809、tokushima parseJson vs json_decode
http://www.lingr.com/room/rhaco-ja/archives/2008/08/09#msg-44459650

!!20080810、shigepon potファイル辞書変換サービス作った
http://www.lingr.com/room/rhaco-ja/archives/2008/08/10#msg-44487854

!!20080811、jigen mysqlカラム名予約語使える?
http://www.lingr.com/room/rhaco-ja/archives/2008/08/11#msg-44606038

!!20080811、kanonji 配列からXMLを生成できたりするクラス、あったりしませんか?
http://www.lingr.com/room/rhaco-ja/archives/2008/08/11#msg-44617705

!!20080812、tokushima 仕様かえまくりますよ?w
http://www.lingr.com/room/rhaco-ja/archives/2008/08/12#msg-44697761
rhaco2.0の話。はりきってらっしゃる。イヒ

!!20080813 tokushima arbo,jajaのPHP5棲み分けをした方がいいのか、全部PHP5で書き直すのかw
http://www.lingr.com/room/rhaco-ja/archives/2008/08/13#msg-44705089

!!20080813 tokushima すでに1.6.0もreleasedだったり
http://www.lingr.com/room/rhaco-ja/archives/2008/08/13#msg-44733978

!!20080813 kanonji Rhaco::constant()に使える定数名って何かルールありますか?
http://www.lingr.com/room/rhaco-ja/archives/2008/08/13#msg-44746764

!!20080813 nazo 普通にnetwork.services.WassrAuthで作りますよw
http://www.lingr.com/room/rhaco-ja/archives/2008/08/15#msg-44877724

!!20080813 tokushima ところで、今後getter/setter的なメソッド定義はやめるよ
http://www.lingr.com/room/rhaco-ja/archives/2008/08/15#msg-44888541
rhaco2.0の話
# tokushima
# ところで、今後getter/setter的なメソッド定義はやめるよ
# $hoge->getAbc() とかしてたのは $hoge->abc()になっていくよ public $abc だよ
# いいね?
# lang.model.Obj継承するよ いいね?
# ついでにsetは$hoge->abc("bbbb"); だよ
# ついでに、boolean を返すのは $hoge->isAbc() だよ
# だから、全部アプリ書き直す覚悟してねw
# tokushima
# getVariable()
# とかもvar()かvariable()に変えると思うよ わかったね?w
# tokushima
# static なライブラリ系はあんまり使い方変わらないと思うよ よかったねw
# ただObject系は、内部仕様かわるかもよ ハッシュ返してたのをstdClass返したりするかもよ
# だいたいの方針は分かったね? 今2.0.0に手を出すのは危険な事は分かったね?w

!!20080818 tokushima
http://www.lingr.com/room/rhaco-ja/archives/2008/08/18#msg-45113530
rhaco2.0の話

!!20080819 shigepon テンプレート内容を当てはめた結果を出力しないで得る方法って他にありましたっけ?
http://www.lingr.com/room/rhaco-ja/archives/2008/08/19#msg-45166007
# tokushima
# Flow->parser()->read()ですかね

!!20080819 tokushima 誰かwassrの購読ユーザ一覧を取得するの作って><
http://www.lingr.com/room/rhaco-ja/archives/2008/08/19#msg-45166669

!!20080819 tokushima conveyor 1.6.0で動くようにするべきかなぁ
http://www.lingr.com/room/rhaco-ja/archives/2008/08/19#msg-45177721

!!20080819 kanonji 以前rhacoはMTVを採用している見たいな事を聞いたような聞かなかったような
http://www.lingr.com/room/rhaco-ja/archives/2008/08/19#msg-45183578

!!20080819 tokushima 要約すると
http://www.lingr.com/room/rhaco-ja/archives/2008/08/19#msg-45185229
rhaco2.0の話

!!20080820 kanonji 1.5から1.6に変えたらaddr.Lがimportされなくなってて若干はまったりしましたけどw
http://www.lingr.com/room/rhaco-ja/archives/2008/08/20#msg-45213970

!!20080820 kanonji Logger::setPublisherって function debug($value){独自の処理}等を定義したobjを渡すんですか?
http://www.lingr.com/room/rhaco-ja/archives/2008/08/20#msg-45215264

!!20080820 kanonji あっれ、テンプレートの{$f.text2html}の$fって中身なんですか?
http://www.lingr.com/room/rhaco-ja/archives/2008/08/20#msg-45245328

!!20080821 shigepon DbUtilにcreateは無いって書きましたが良かったでしょうか?
http://www.lingr.com/room/rhaco-ja/archives/2008/08/21#msg-45308108

!!20080821 yabeken generic.Viewsでproject.xmlでdefineした定数をテンプレート内から呼ぶ方法ってありますか?
http://www.lingr.com/room/rhaco-ja/archives/2008/08/21#msg-45318275

!!20080821 kanonji いろんなクラスがsetVariable()、getVariable()持ってるじゃないですか?
http://www.lingr.com/room/rhaco-ja/archives/2008/08/21#msg-45344657
# tokushima
# んー
# Rhacoグローバル変数なイメージで
# TagParserはテンプレート変数で
# RequestはPOST/GETですね

!!20080822 tokushima

の話
http://www.lingr.com/room/rhaco-ja/archives/2008/08/22#msg-45348524

!!20080822 shigepon nazoさんがOpenIDを実装してくれるんですか!?すげー!
http://www.lingr.com/room/rhaco-ja/archives/2008/08/22#msg-45382720

!!20080822 tokushima Atom0.3とかRSS1.0/0.9ってまだいりますかねー?
http://www.lingr.com/room/rhaco-ja/archives/2008/08/22#msg-45384531

!!20080822 yabeken DateUtil::weekday($year,$month,$day); //曜日を返す。が欲しいけどどうしたものか・・・
http://www.lingr.com/room/rhaco-ja/archives/2008/08/22#msg-45391118

!!20080822 yabeken 1.6.1コミットルール
http://www.lingr.com/room/rhaco-ja/archives/2008/08/22#msg-45395810
# yabeken
# 1.6.1コミットルール
# テストに通っていないコードはコミットしない。
# テストの追加は認めるが、バグ以外でのテストの修正は認めない。
# コミットログに追加したメソッドと、追加した理由を書く。
# phpdocとdoctestはきちんと書く。

!!20080822 nazo http://nazone.info/tmp/openidrhaco.zip
http://www.lingr.com/room/rhaco-ja/archives/2008/08/22#msg-45401901

!!20080822 kanonji Variable::toSimpleTag()で配列をXMLに変換してるんですが、配列の値に<とか>とか&があるのを何とかしてくれる機能って無いですか?
http://www.lingr.com/room/rhaco-ja/archives/2008/08/22#msg-45402664

!!20080823 tokushima getHoge setHoge verifyHoge arrayHoge
http://www.lingr.com/room/rhaco-ja/archives/2008/08/23#msg-45429899
rhaco2.0の話

!!20080823 kanonji rhacoだとvalidateとverifyは同じ意味だったんですか?
http://www.lingr.com/room/rhaco-ja/archives/2008/08/23#msg-45440083

!!20080823 tokushima dbUtilでのチェックでverify失敗したら***Exceptionがraisされていて、それをで表示できます
http://www.lingr.com/room/rhaco-ja/archives/2008/08/23#msg-45440648

!!20080826 tokushima Objって名前どうなんだろとか思いだしている今日この頃
http://www.lingr.com/room/rhaco-ja/archives/2008/08/26#msg-45697305
命名ってむずかしい

!!20080823 tokushima Pear::DocTest vs Rhaco
http://www.lingr.com/room/rhaco-ja/archives/2008/08/26#msg-45718444

!!20080827 NEKOGET rhacoTシャツ着たアバタ
http://www.lingr.com/room/rhaco-ja/archives/2008/08/27#msg-45793585
cool!

!!20080829 nazo rhacoのtrunkって今はもう動いてないんですか?
http://www.lingr.com/room/rhaco-ja/archives/2008/08/29#msg-45933357
# tokushima
# 1.6.*はgoogle codeでバグ修正程度をやってます
# sfのtrunkは2.0が固まるまで放置
# ので、1.6.
# 1.6.*はgoogle codeが最新です

!!20080829 tokushima DBもPDOにしようかね
http://www.lingr.com/room/rhaco-ja/archives/2008/08/29#msg-45974174

!!20080831 toHashでintval http://fixdap.com/p/rhaco/16968/
http://www.lingr.com/room/rhaco-ja/archives/2008/08/31#msg-46124590

!!20080901 riaf テンプレートで変数を国際化関数にぶちこみたいときはどうしたらいいですか
http://www.lingr.com/room/rhaco-ja/archives/2008/09/01#msg-46137834
# tokushima
# _({$hoge}) でうまくいかなかったら $parser->setVariabe("hoge",Message::_("ほげほげ"));
# どっちか

!!20080901 kanonji # RewriteRule ^(.+)$ index.php?%{QUERY_STRING}&pathinfo=$1 [L] これってindex.php?foo=bar&pathinfo=hoge見たいになると思うんですが
http://www.lingr.com/room/rhaco-ja/archives/2008/09/01#msg-46138494

!!20080901 kanonji validateの話、TableObjectUtil::cast、TableObjectVerify::verifyとか
http://www.lingr.com/room/rhaco-ja/archives/2008/09/01#msg-46178390

!!20080901 nazo 前に言ったformのvalidationの話の予感!
http://www.lingr.com/room/rhaco-ja/archives/2008/09/01#msg-46179212
そのあたりは、みんなテキトー?にやってるんだー
2ヶ月前ぐらいからおいらも悩んで、
rhacoの上に俺俺フレームワーク?作ってとかやってたんだけど放置。
project.xmlに書いてるValidateを取り込めるようにした
FormValidaterクラス作って、それを各クラス用にカスタマイズしてとかやろうとしてた。

!!20080901 kanonji Request::isValid()で見るExceptionTrigger::invalid("request");ってどういった類の例外が入るんでしょう?
http://www.lingr.com/room/rhaco-ja/archives/2008/09/01#msg-46182006

!!20080902 tokushima search_fields,ordering,form_display,list_display
http://www.lingr.com/room/rhaco-ja/archives/2008/09/02#msg-46258523
# tokushima
# です
# list_displayが一覧表示
# search_fieldsが一覧での検索対象
# orderingが一覧での表示順序"ordering"=>"column1,-column2"

!!20080903 kanonji $result=$db->select(new Product(),new Criteria(...)); new Product()ってなんか冗長じゃないのかな
http://www.lingr.com/room/rhaco-ja/archives/2008/09/03#msg-46352746

!!20080904 kanonji TableObjec、beforeInsert() beforeUpdate() verify*() とかの話
http://www.lingr.com/room/rhaco-ja/archives/2008/09/04#msg-46422660

!!20080904 kanonji potの話
http://www.lingr.com/room/rhaco-ja/archives/2008/09/04#msg-46424559
potは未開拓>おいら

!!20080904 nazo 最近のらこらーはViewsを使うのが基本なんでしょうか><
http://www.lingr.com/room/rhaco-ja/archives/2008/09/04#msg-46427208

!!20080904 shigepon rhacoのデフォルトテンプレートをcssだけ書き換えたいなーと思ったことあります
http://www.lingr.com/room/rhaco-ja/archives/2008/09/04#msg-46435657
# shigepon
# ¶ 例えばrhacoのresources/templates/generic/views以下とか
# Viewsで特にテンプレート指定しないとここのファイルが使われるはずなんですが
# 中身はこのままで良いんですが、デザイン(CSS)だけ変えたいなーと思ったことがあるんです
# shigepon
# form_displayで順序や表示したい内容を呼び出すというやり方もここに書いてます。ここを参考にしないとまず分からないっすw

!!20080905 nazo OpenIDが動かないのを調べる
http://www.lingr.com/room/rhaco-ja/archives/2008/09/05#msg-46512561

!!20080905 yabeken IE+HTTPSでダウンロードするときは、session_cache_limiter("public")とかないわー
http://www.lingr.com/room/rhaco-ja/archives/2008/09/05#msg-46521501
# yabeken
# usesessionオーバーライドすることにします
# 普段はnocache
# DL時はpublic

!!20080905 nazo OpenID livedoorとyahooもログインできるようになった
http://www.lingr.com/room/rhaco-ja/archives/2008/09/05#msg-46525223

!!20080905 kanonji RequestLoginはstaticに使うみたいな事を見かけたんですがExample extends Flowのメソッドで$this->loginRequired($condition, $this);こう使うのはNGですか?
http://www.lingr.com/room/rhaco-ja/archives/2008/09/05#msg-46531515

!!20080905 shigepon はExceptionの全件表示以外の個別表示とかできませんよね
http://www.lingr.com/room/rhaco-ja/archives/2008/09/06#msg-46559098

!!20080909 kanonji いつの間にかtrunkは2.0化していたのか!
http://www.lingr.com/room/rhaco-ja/archives/2008/09/09#msg-46811833
rhaco2.0 がtrunkに

!!20080909 tokushima cast不評なのか!?><
http://www.lingr.com/room/rhaco-ja/archives/2008/09/09#msg-46861795

男性にもわかるネイルの話。

私が思って*た*ネイルのイメージ

  • 「マニキュア」っていう言葉は知ってる。それ以外はなんだかよくわからん。。。
  • カラフルだったり、つやがでてたり。
  • もこもこいろいろつけてたりする人もいる。
  • 小さなビンに入っていて、においがきつい。
  • すごい綺麗なのはネイルサロンでやってもらう。高そう。

ひょんなことから、いろいろ調べた。
想像していたより興味深かったので、メモっておく。
女性との話題づくりに悩んでいる人には、ネイルをネタにするのお勧め。

ネイルサロン、マニキュア、アクリルネイル、ジェルネイル の超手抜き説明

ネイルサロンでは、マニキュアとかアクリルネイルとかジェルネイルとかをプロがやってくれる。
ネイルサロンで使ってる材料とか器具が何か特別かといえば、必ずしもそうではない。

ネイルかわいいよね。

ネイルサロン行ってみる。

  • さすがにプロだから綺麗だ。
  • だが、金額も高価。シンプルに塗るだけでも両手で1万円とか。


普段は、自分でささっと、ほどほどに綺麗にできたらなぁ。

「マニキュア」塗ってみる。

  • 塗るだけなので、お手軽。入手も簡単。
  • 塗ってる途中で固まってしまい、綺麗に塗るのはあんがい難しい。
  • 綺麗に塗れても、部分的にはがれやすい。(持ちが悪い)
  • 強烈なにおいがある。


「アクリルネイル」ってどうよ?

  • 強度、光沢は文句なし。
  • しかし、いろいろと高度なテクニックが必要。
  • 個人じゃハードル高いよね。


「ジェルネイル」ってどうよ?

  • 強度、光沢いいよ。
  • 樹脂を塗る→UVライト当てる→硬化
  • UVライトに当てるまでは、自由にできる。
  • 個人でも比較的容易

これで決定!ってものは無い。どの方法も一長一短
*自分にあった方法*を模索する必要がある。

あと、用語はすごくたくさんあって、
それがブランド名なのか、技術名なのか、一般名称なのか、ネイルやってる女性でも難解かと。

ネイルする人が気にするところ。

  • つやが良いか?(照り、クリア感がよいほうがよいねって話)
  • 日常生活においてはがれ難い、ハゲにくいか?(持ちがよいか?って話)
    • リフトしないか?(自爪が部分的に浮いてくること)
  • 自爪へのダメージが小さいか?(綺麗に見えても、剥がしたときに自爪ぼろぼろとかやだよ。って話)
  • リムーブ(自爪のみに戻すこと)が容易か?(剥がすのに、削るのに、何時間もかかるって大変よね。って話)
  • コスト

主なネイルアート

細かいのをあげるときりがないので、主なもののみ。

爪自身の話

  • スカルプチュア(スカルプ):爪を伸ばす(人工爪)

塗料の塗り方の話

  • グラデーション:色を段階的に変えていくこと(説明するまでもないか)
  • フレンチ:爪のベースと、先っぽの色を変えて塗ること。(ベース透明で、先っぽが白とか)

塗料以外の何かを使う話

  • 3Dアート:爪の上に立体的なアートを施す(ぬるだけじゃなくって、何かをのっける)
  • ラメ:主に金とか銀とかきらきらしたパウダーのこと。(透明なジェルに混ぜて塗ったり、ふりかけて使ったり)

これらを組み合わせる。
フレンチにしておいて、ワンポイントに3D使ってみたりとか。
ラメを徐々に加えていって、グラデーションしてみたりとか。

ネイルの手順の超手抜き説明

まず、自爪のお手入れ(甘皮をあげたり取ったり)をして、ベースコートを全体に塗ります。
その上に、別の色を塗ったり、3Dを置いたり。デザインによっては何度かこれを繰り返します。
最後に、仕上げのトップコートを塗って完成。
その後のメンテナンスとしては、数日おきにトップコートを塗りなおしたりもします。

構造はこんな感じ。

 --------------
 トップコート(透明)
 --------------
 必要なら色付きを重ねたり、3Dを置いたり。
 --------------
 ベースコート(透明とか色付き)
 --------------
 自爪
 --------------

まぁ、サンドウィッチ構造ですね。

女性と話するときのきっかけに使えるんじゃないかな。

別に、合コンとかそういうのじゃなくっても、奥さんとか彼女とかとの話題としてもいいと思う。

予備知識無しに話をふっても「全く知らないくせに」と軽くあしらわれるだろうから、ちょっと予習しておくのが良いと思います。
少しでも知識を持っておけば、相手の説明も理解しやすいはずです。

  • 専門用語を覚えておく。
    • 上に上げたものだけでも十分かと。
  • 爪が長かったら「それスカルプ?」とか。
  • グラデーションとフレンチは簡単に見分けられる。
  • ワンポイントで3Dつかってたら、そこは見逃すなってこと。(要は誉めポイント)
  • 難しい用語がたくさんあるから、そういうのが出てきたら「xxxってどういう意味?」とか話をふればよい。
    • ネイルやってる人でも知らない用語はたくさんある。
  • 爪の見た目で話して、次に「ネイルする人が気にするところ」に話題を展開すれば広がりが出る。
  • 「ネイル自分でやってるの?」とか。「綺麗に仕上げるのは難しいって聞いたよ」とか。

"ネイルアート 基本" でネット検索してみてください。

その他

  • 最近はネイルアート用品が簡単に入手できるので、個人でもプロ顔負けのネイルアートを行っている人も多い。
  • 足にするのは「ペディキュア」って呼ぶ。
  • 女性が化粧として行うことが多いが、爪の割れを防止する目的でスポーツ選手が使うこともある。

「ジェルネイル」の話

  • 赤外線紫外線で硬化するアクリル樹脂を用いる。
  • マニキュアと比べると、特有のにおいがない。紫外線に当てるまで硬化しないので造形が自由。硬い。

「付け爪」の話

  • 人工の爪を自分の爪に付ける。2種類ある。
  • 「ネイルチップ」
    • 通常付け爪といえばこれのこと。
    • 主にプラスチック製でテープや接着剤で自爪に付けて使用する。
  • 「スカルプチュア」
    • アクリル樹脂(粘度のある液体)などを直接盛り、爪の延長や補強を行う。

マニキュア
http://ja.wikipedia.org/wiki/%E3%83%9E%E3%83%8B%E3%82%AD%E3%83%A5%E3%82%A2

ネイルアート
http://ja.wikipedia.org/wiki/%E3%83%8D%E3%82%A4%E3%83%AB%E3%82%A2%E3%83%BC%E3%83%88

大勢で集まったとき、俺がカルパッチョを独占することを世間の常識とせよ

http://anond.hatelabo.jp/20080829053234

増田がブクマに反応して追記してるんだが、それを読んで思うところがあったので書いてみる。

カルパッチョが好きでたまらない。独占したい」が第一優先事項であるなら 「一人で食いに行く」のは、自分の行動だけで実行できる、最も簡単な対処方法でしょ。
それを否定するのに全力投球で追記ってさ。
もはや目的は「大勢で集まったとき、俺がカルパッチョを独占することを世間の常識とせよ」にしか見えないよ?
おちつけっての。

増田への返信はこれぐらいにしておいて、本題ですが。
仕事でこういう人と付き合わざるを得ない状況だと最悪。

世の中には「相手を自分色に染めないと納得できない人」がいる。

  • うかつにも「人それぞれだよね」的な意見をいっちゃうと「お前のいうことももっともだけどさ。これこれだから、うんたらかんたら・・・。ということで、俺のが理にかなってるんだ!」とか必死に誘導してくる。
  • 「じゃぁ、こうしてみればお互いハッピーになれるんじゃないかな?」とか提案しても、「ちがうちがう。今までの話聞いてんの?うんたらかんたら・・・。ということで、俺のが理にかなってるんだ!」とか必死に誘導してくる。

もうね。
「自分の中で答えが決まってて、自分語りに必死で、一分も折れるつもりないなら、最初からそういってくれ。
変なゲームに付き合いたくないわ」って言いたくなる。

もっとも、相手が愚痴聞いて欲しいだけなら「うんうん」って聞き役に徹すればいいんだけどねぇ。
"普通" とか "常識" って言葉を多様するのもどうかと思う。経験上そういう人ほど "自分=普通=常識" をより所として、"自分の意見を一分でも変えるつもりはない" な人が多いと感じる。