2013年01月15日

[Python]xmlrpclibを使ってブログにエントリ投稿する方法

今回はPythonからブログへ投稿する方法をご紹介する。
XML-RPCを公開しているブログサービスなら以下のやり方でプログラムからブログ記事を投稿できる。cronなどに登録すれば自動投稿も可能になる。
続きを読む
posted by 寄り道退屈男 at 21:39 | Comment(0) | TrackBack(0) | Python

2013年01月13日

[Python]feedparserライブラリでRSSフィードを簡単に処理

RSSなどのフィードをPythonプログラムから簡単に利用する方法をご紹介しよう。
今回はfeedparserというライブラリを使う。
続きを読む
posted by 寄り道退屈男 at 23:20 | Comment(0) | TrackBack(0) | Python

2012年12月29日

[CSS3]画像を使わずにCSSだけでグラデーションを実現する方法

画像を使わないで見出しの背景などのグラデーションをかける方法を紹介する。
FirefoxやChromeだけでなく、邪悪なIEにもちゃんと対応させるよ。

続きを読む
posted by 寄り道退屈男 at 11:40 | Comment(0) | TrackBack(0) | Webデザイン

2012年12月28日

[CSS3]画像を使わずに「角丸」を実現する方法

見出しやボタンなどの角を丸くする方法。

以前は「角」に使う画像なんかを使ってうまくレイアウトするテニクカルなやりかたが主流だったが、CSS3になってから驚くほど簡単に綺麗なコードが書けるようになった。スタイルシートだけで表現でき、画像の準備も必要ない。
これは覚えておいて損はない。

早速見てみよう。


続きを読む
posted by 寄り道退屈男 at 10:39 | Comment(0) | TrackBack(0) | Webデザイン

2012年04月20日

[Python]正規表現を使って半角記号を除去する方法。

ASCIIコード表を見ながら、除去したい記号を選ぶ。

!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_abcdefghijklmnopqrstuvwxyz{|}~


例えば、全ての半角記号を表す正規表現は、[!-/:-@[-`{-~] である。以下はこの正規表現を使って文字列から半角記号だけを取り除くサンプルである。

import re

str = "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_abcdefghijklmnopqrstuvwxyz{|}~"
print re.sub(re.compile("[!-/:-@[-`{-~]"), '', str)


これを実行すると以下のように出力される。

0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz



おまけとして、数字だけを抽出したい場合の例も紹介しよう。

import re

str = "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_abcdefghijklmnopqrstuvwxyz{|}~"
print re.sub(re.compile("[!-/:-~]"), '', str)


実行するとこのように表示される。

0123456789

posted by 寄り道退屈男 at 16:32 | Comment(0) | TrackBack(0) | Python

2012年04月09日

Firefoxアドオンを作る。その2

前回はFirefox拡張機能アドオンの作り方を紹介した。

今回は理解をもう少しだけ深めるために、別のアドオンを作ってみよう。

今回作るのは、「入力文字列内にURLがあれば、それに自動的にリンク(aタグ)を貼った文字列を出力するアドオン」である。

このアドオンは、オートリンク機能を搭載していないブログシステムを使っている人には少しだけ役に立つかも知れない。

アドオンIDは適当に autolink@yourdomain.com とした。

今回開発に使った環境は、 Firefox 11.0 と Windows7 である。

というわけで、まずはファイル構成から。

autolink@yourdomain.com/
  index.rdf
  chrome.manifest
  chrome/
    content/
      autolink.xul
      firefoxOverlay.xul
    locale/
      en-US/
        autolink.dtd
      ja-JP/
        autolink.dtd
    skin/


各ファイルの中身は以下の通りだ。

index.rdf
<?xml version="1.0" encoding="UTF-8"?>

<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>autolink@yourdomain.com</em:id>
<em:name>autolink Extension</em:name>
<em:version>1.0</em:version>
<em:creator>Your Name</em:creator>
<em:description>Autolink Extension Add-on.</em:description>
<em:targetApplication>
<Description>
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
<em:minVersion>3.0</em:minVersion>
<em:maxVersion>11.0.*</em:maxVersion>
</Description>
</em:targetApplication>
</Description>
</RDF>



chrome.manifest
content autolink chrome/content/
locale autolink en-US chrome/locale/en-US/
locale autolink ja-JP chrome/locale/ja-JP/
skin autolink classic/1.0 chrome/skin/
overlay chrome://browser/content/browser.xul chrome://autolink/content/firefoxOverlay.xul



chrome/content/firefoxOverlay.xul
<?xml version="1.0"?>

<!DOCTYPE overlay SYSTEM "chrome://autolink/locale/autolink.dtd">
<overlay id="autolinkOverlay"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

<menupopup id="viewSidebarMenu">
<menuitem key="key_openAutolink" observes="viewAutolink" />
</menupopup>

<keyset id="mainKeyset">
<key id="key_openAutolink" command="viewAutolink"
key="&openAutolink.commandkey;"
modifiers="&openAutolink.modifierskey;" />
</keyset>

<broadcasterset id="mainBroadcasterSet">
<broadcaster id="viewAutolink"
label="&autolink.title;"
autoCheck="false"
type="checkbox"
group="sidebar"
sidebarurl="chrome://autolink/content/autolink.xul"
sidebartitle="&autolink.title;"
oncommand="toggleSidebar('viewAutolink');" />
</broadcasterset>
</overlay>



chrome/content/autolink.xul
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css" ?>
<?xml-stylesheet href="chrome://browser/skin/browser.css" type="text/css" ?>
<!-- ローカリゼーション -->
<!DOCTYPE page SYSTEM "chrome://autolink/locale/autolink.dtd">

<page id="sbSidebarExample"
title="&autolink.title;"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

<vbox flex="1">
<!-- 入力用テキストボックス -->
<textbox id="t1" multiline="true" rows="20"/>
<!-- 出力用テキストボックス(Read Only) -->
<textbox id="t2" multiline="true" readonly="true" flex="1"/>
<script type="application/x-javascript"><![CDATA[
/*
入力用テキストボックスからカーソルが外れた時(onblur)にオートリンクを貼った文字列を表示するイベント処理を追加
*/
var t1 = document.getElementById("t1");
t1.addEventListener(
"blur",
function(){
var t1 = document.getElementById("t1");
var t2 = document.getElementById("t2");
t2.value = t1.value.replace(
/(http:\/\/[\x21-\x7e]+)/gi,
"<a href=\"$1\" target=\"_blank\">$1</a>"
);
}
);

/*
出力用テキストボックスにフォーカスがセットされた時(onfocus)に文字列が全選択されるイベント処理を追加
*/
var t2 = document.getElementById("t2");
t2.addEventListener(
"focus",
function(){
this.select();
}
);
]]></script>

</vbox>
</page>


入力用テキストエリアに textarea ではなく、textbox を使っているところがポイントだ。XULでは両方とも textbox で表現できるのである。詳しくはこちらを参照のこと。


chrome/locale/en-US/autolink.dtd
<!ENTITY autolink.title "Autolinker">
<!ENTITY openAutolink.commandkey "E">
<!ENTITY openAutolink.modifierskey "shift accel">


chrome/locale/ja-JP/autolink.dtd
<!ENTITY autolink.title "オートリンカー">
<!ENTITY openAutolink.commandkey "E">
<!ENTITY openAutolink.modifierskey "shift accel">



以上である。

今回はスタイルシート(skin/)は省略した。

動作テストや配布パッケージの作り方についても、前回のエントリを見ていただけると分かると思うので今回は省略する。


参考になるサイト


XUL - MDN
こちらはXULで使えるコントロールの一覧などの情報である。今回使ったtextboxなどの他にも多くの便利なコントロールがあるのでこちらを見て勉強すると良いだろう。



Firefox 3 Hacks ―Mozillaテクノロジ徹底活用テクニック
江村 秀之 池田 譲治 下田 洋志 松澤 太郎 dynamis
オライリージャパン
売り上げランキング: 395037


PR:お買い物はAmazonで
posted by 寄り道退屈男 at 08:42 | Comment(0) | TrackBack(0) | Firefox

2012年04月07日

Firefoxアドオンを作る

アドオンには以下の3つの種類がある。

 1. 拡張機能
 2. プラグイン
 3. テーマ

今回はアドオンとして最も利用頻度が高い 1. の「拡張機能」を作ってみる。


実際に作ってみる



プログラミングは「習うより慣れよ」である。

というわけで、「サイドバー簡易ブラウザ」アドオンなんてのをサンプルとして作ってみたいと思う。このアドオンは、読んで字の如く、サイドバーに簡易ブラウザを表示する拡張機能アドオンである。

アドオン名は、 sidebarexample ということで話を進める。

まずはざっとフォルダ構成から見て欲しい。説明は後ほど。


index.rdf
chrome.manifest
chrome/
  content/
    firefoxOverlay.xul
    sidebarexample.xul
  locale/
    en-US/
      sidebarexample.dtd
    ja-JP/
      sidebarexample.dtd
  skin/
    sidebarexample.css


これと同じフォルダ構成を構築する。各ファイルの中身はとりあえず今は空のままで良い。

上のフォルダ・ファイル構成ができたら、今度はファイルの中身を記述していく。


index.rdf
<?xml version="1.0" encoding="UTF-8"?>

<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<!-- 適当なアドオンID(メアドじゃないよ!) -->
<em:id>sidebarexample@yourdomain.com</em:id>
<!-- アドオン名 -->
<em:name>sidebarexample Extension</em:name>
<!-- バージョン -->
<em:version>1.0</em:version>
<!-- 作者 -->
<em:creator>Your Name</em:creator>
<!-- アドオンの説明 -->
<em:description>Example extension for creation and registration of a sidebar.</em:description>

<!-- このアドオンが対象とするアプリ -->
<em:targetApplication>
<Description>
<!-- firefoxのアプリID -->
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
<!-- firefoxの対応バージョン -->
<em:minVersion>3.0</em:minVersion>
<em:maxVersion>11.0.*</em:maxVersion>
</Description>
</em:targetApplication>

</Description>
</RDF>


index.rdfはアドオンの基本情報である。

firefox用アドオンを作る場合は、上のように {ec8030f7-c20a-464f-9b0e-13a3a9e97384} 固定でOK。

ただしfirefoxの対応バージョンの設定には気をつけるべし。ユーザが利用するFirefoxバージョンが minVersion と maxVersion の間になければ、作ったアドオンが有効にならないからである。


chrome.manifest
content sidebarexample chrome/content/
locale sidebarexample en-US chrome/locale/en-US/
locale sidebarexample ja-JP chrome/locale/ja-JP/
skin sidebarexample classic/1.0 chrome/skin/
overlay chrome://browser/content/browser.xul chrome://sidebarexample/content/firefoxOverlay.xul


chrome.manifestはリソースの構成である。
contentやlocale、skin、overlayの在り処が記述されている。

contentはxul(デザイン)ファイルなどの格納場所、localeはロケール別のメッセージリソースdtdの格納場所、skinはスタイルシートcssの格納場所である。overlay(オーバーレイ)はこの後説明する。


chrome/content/firefoxOverlay.xul
<?xml version="1.0"?>

<!DOCTYPE overlay SYSTEM "chrome://sidebarexample/locale/sidebarexample.dtd">
<overlay id="sidebarExampleOverlay"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

<menupopup id="viewSidebarMenu">
<menuitem key="key_openSidebarExample" observes="viewSidebarExample" />
</menupopup>

<keyset id="mainKeyset">
<key id="key_openSidebarExample"
command="viewSidebarExample"
key="&openSidebarExample.commandkey;"
modifiers="&openSidebarExample.modifierskey;" />
</keyset>

<broadcasterset id="mainBroadcasterSet">
<broadcaster id="viewSidebarExample"
label="&sidebarexample.title;"
autoCheck="false"
type="checkbox"
group="sidebar"
sidebarurl="chrome://sidebarexample/content/sidebarexample.xul"
sidebartitle="&sidebarexample.title;"
oncommand="toggleSidebar('viewSidebarExample');" />
</broadcasterset>
</overlay>


firefoxOverlay.xulは、Firefoxの表示メニューのサイドバーの中に今回作るアドオンを表示させるためのデザイン定義である。このように元アプリ(Firefox)の拡張ポイントに機能を拡張することを overlay(オーバーレイ)という。


chrome/content/sidebarexample.xul
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css" ?>
<?xml-stylesheet href="chrome://browser/skin/browser.css" type="text/css" ?>
<!-- アドオン独自css -->
<?xml-stylesheet href="chrome://sidebarexample/skin/sidebarexample.css" type="text/css" ?>
<!-- ローカリゼーション -->
<!DOCTYPE page SYSTEM "chrome://sidebarexample/locale/sidebarexample.dtd">

<page id="sbSidebarExample"
title="&sidebarexample.title;"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

<vbox flex="1">
<!-- "URLを入力"ラベル -->
<label id="label1" value="&sidebarexample.inputurl;" />

<!-- "URLを入力"テキストボックス -->
<textbox id="textbox1" value="&sidebarexample.defaulturl;" />

<!-- ロードボタン -->
<button label="&sidebarexample.load;"
oncommand="loadURL();"
context="button-context"/>

<!-- ブラウザコンポーネント -->
<browser id="browser1"
src="&sidebarexample.defaulturl;"
flex="1"
type="content-primary" />

<script type="application/x-javascript"><![CDATA[
function loadURL() {
var b1 = document.getElementById("browser1");
var url = document.getElementById("textbox1").value;
b1.loadURI(url)
}
]]></script>

</vbox>
</page>


こちらのxulはアドオン自身のデザイン定義である。HTMLやJavascriptで表現している。


chrome/locale/en-US/sidebarexample.dtd
<!ENTITY sidebarexample.title "Sidebar Example">
<!ENTITY sidebarexample.load "Load">
<!ENTITY sidebarexample.defaulturl "http://sunabako.sblo.jp/">
<!ENTITY sidebarexample.inputurl "Input URL">
<!ENTITY openSidebarExample.commandkey "E">
<!ENTITY openSidebarExample.modifierskey "shift accel">


chrome/locale/ja-JP/sidebarexample.dtd
<!ENTITY sidebarexample.title "サイドバー簡易ブラウザ">
<!ENTITY sidebarexample.load "ロード">
<!ENTITY sidebarexample.defaulturl "http://sunabako.sblo.jp/">
<!ENTITY sidebarexample.inputurl "URLを入力">
<!ENTITY openSidebarExample.commandkey "E">
<!ENTITY openSidebarExample.modifierskey "shift accel">


これらのdtdファイルは、ローカリゼーション(多言語対応)のためのメッセージリソースである。

例えば、sidebarexample.xulの中の &sidebarexample.inputurl; のような記述は、このdtdファイル内の sidebarexample.inputurl と紐付けされて文言が表示される。言うまでもないが、Firefoxユーザのロケール別に表示文言が変わる。日本語環境なら ja-JP/sidebarexample.dtd が、英語環境なら en-US/sidebarexample.dtd の文言が参照されるのだ。


chrome/skin/sidebarexample.css
#label1 {
color:blue;
}


こちらは見たまんまスタイルシート。sidebarexample.xulのHTMLに適用されている。


テスト



万が一設定を壊してしまっても他のプロファイルに影響を及ぼさないためにも念のためfirefoxの開発用プロファイル(例えば dev という名前で)を作っておこう。

では先ほど作ったアドオンをテストしてみよう。今作った開発用プロファイル(dev)のプロファイルフォルダ(Win7の場合の例:C:/Users/hogeUser/AppData/Roaming/Mozilla/Firefox/Profiles/*******.dev/)の直下に extensions フォルダを新規作成し、そこにindex.rdfで設定したID(この場合、sidebarexample@yourdomain.com)と同じ名前のフォルダを作成し、このフォルダの中に index.rdf, chrome.manifest, chrome などをざっくりコピーする。

この状態でfirefoxを再起動すれば、このアドオンをインストールするかどうかの確認画面が出るはずだ。ここでインストールを了承し、もう一度再起動すればアドオンがインストールされているはずだ。

メニューバーの「表示」→「サイドバー」の中に、「サイドバー簡易ブラウザ」(ロケールが英語の場合は「Sidebar Example」)というのが表示されていれば成功である。


配布パッケージxpiを作る



作ったアドオンを配布する際は、xpiファイルというパッケージに固めて配布する。xpiといってもただのzip圧縮されたファイル群だ。

index.rdf, chrome.manifest, chrome/ をガツッと一まとめにzip圧縮し、拡張子を .xpi にすればOKである。

できたxpiファイルをfirefoxにドラッグ・アンド・ドロップすれば、インストールが始まるはずだ。もしもxpiが正しく作られていなければ、この時点で「壊れています」のメッセージが表示される。




以上がfirefoxアドオン開発の基本である。
次回はさらに理解を深めるため、もうひとつ別のアドオンを作ってみようと思う。


参考にさせていただいたサイト


Firefox 11 for developers - MDN
アドオンを開発する - MDN


Firefox 3 Hacks ―Mozillaテクノロジ徹底活用テクニック
江村 秀之 池田 譲治 下田 洋志 松澤 太郎 dynamis
オライリージャパン
売り上げランキング: 395037


PR:お買い物はAmazonで
posted by 寄り道退屈男 at 19:29 | Comment(1) | TrackBack(0) | Firefox

2012年04月03日

[C++]POSIXスレッド標準(pthread)を使ったマルチスレッドプログラミング

今回はPOSIXスレッド標準(pthread.h)を利用したC++マルチスレッドプログラミング手法を紹介する。

下のサンプルソースは、二つのスレッド間(thread1, thread2)で共通の変数(count)を整合性を保ちながら利用(カウントアップ)する例である。

折角なので wait と signal の処理も盛り込んでみた。waitで待たされたスレッド(thread1)は、もう一つのスレッド(thread2)からのsignalにより待ち状態が解除される。

hoge.c
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> // usleepを使うため

/**
* 関数定義
*/
// スレッド関数1
void* threadFunc1(void* param);
// スレッド関数2
void* threadFunc2(void* param);


/**
* グローバル変数
*/
// スレッド間で変数を保護するmutex
pthread_mutex_t mutex;
// スレッド間で状態を判断するcond
pthread_cond_t cond;
// スレッド間で共有してみる変数
int count = 0;


/**
* メイン関数
*/
int main(int argc, char* argv[]) {

// スレッド1識別変数の宣言
pthread_t thread1;
// スレッド2識別変数の宣言
pthread_t thread2;


printf("initializing mutex...\n");

// mutex初期化
pthread_mutex_init(&mutex, NULL);


printf("initializing cond...\n");

// cond初期化
pthread_cond_init(&cond, NULL);


printf("creating thread1...\n");

// スレッド1の生成
pthread_create(&thread1, NULL, threadFunc1, NULL);

printf("creating thread2...\n");

// スレッド2の生成
pthread_create(&thread2, NULL, threadFunc2, NULL);

printf("joining thread1...\n");

// スレッド1の終了待ち
pthread_join(thread1, NULL);

printf("joining thread2...\n");

// スレッド2の終了待ち
pthread_join(thread2, NULL);


printf("destroying mutex...\n");

// mutex破棄
pthread_mutex_destroy(&mutex);

printf("mutex destroyed...\n");

return EXIT_SUCCESS;
}


/**
* スレッド関数1実装:
* signalが来るまでwaitするスレッド。
*/
void* threadFunc1(void* param) {

while (1) {

// mutexロック
pthread_mutex_lock(&mutex);

count++;

printf("thread1: waiting... count=%d\n", count);

// signal待ち
pthread_cond_wait(&cond, &mutex);

printf("thread1: go!\n");

// mutexアンロック
pthread_mutex_unlock(&mutex);

usleep(10000);
}

}

/**
* スレッド関数2実装:
* waitしているスレッドにシグナルを送信するスレッド。
*/
void* threadFunc2(void* param) {

while (1) {

// mutexロック
pthread_mutex_lock(&mutex);

count++;

printf("thread2: sending signal... count=%d\n", count);

/**
* wait中のスレッドに対してsignal送信。
* 複数スレッドへのsignal送信は、pthread_cond_broadcast(&cond)を使う。
*/
pthread_cond_signal(&cond);

// mutexアンロック
pthread_mutex_unlock(&mutex);

usleep(5000);
}
}


これをコンパイルするときは下のように -lpthread を指定する。

$ gcc pthread.c -lpthread


コンパイル出力された a.exe を実行すると、下のような結果が出力される。

$ a
initializing mutex...
initializing cond...
creating thread1...
creating thread2...
joining thread1...
thread1: waiting... count=1
thread2: sending signal... count=2
thread1: go!
thread2: sending signal... count=3
thread1: waiting... count=4
thread2: sending signal... count=5
thread1: go!
thread2: sending signal... count=6
thread1: waiting... count=7
thread2: sending signal... count=8
thread1: go!
thread2: sending signal... count=9
thread1: waiting... count=10
thread2: sending signal... count=11
thread1: go!
thread2: sending signal... count=12
thread1: waiting... count=13
thread2: sending signal... count=14
thread1: go!
thread2: sending signal... count=15
thread1: waiting... count=16
thread2: sending signal... count=17
thread1: go!
thread2: sending signal... count=18
thread1: waiting... count=19
thread2: sending signal... count=20
thread1: go!
thread2: sending signal... count=21
thread1: waiting... count=22
thread2: sending signal... count=23
thread1: go!
thread2: sending signal... count=24
thread1: waiting... count=25
thread2: sending signal... count=26
thread1: go!
thread2: sending signal... count=27
thread1: waiting... count=28
thread2: sending signal... count=29
thread1: go!
thread2: sending signal... count=30
thread1: waiting... count=31
thread2: sending signal... count=32
thread1: go!
thread2: sending signal... count=33
thread1: waiting... count=34
thread2: sending signal... count=35
thread1: go!
thread2: sending signal... count=36
thread1: waiting... count=37
thread2: sending signal... count=38
thread1: go!
thread2: sending signal... count=39
thread1: waiting... count=40
thread2: sending signal... count=41
thread1: go!
thread2: sending signal... count=42
thread2: sending signal... count=43
thread1: waiting... count=44
thread2: sending signal... count=45
thread1: go!


共通変数 count の操作(カウントアップ)が、ロック処理(pthread_mutex_lock)とアンロック処理(pthread_mutex_unlock)の間で実行されているので、二つのスレッド間で整合性が保たれ、正しくカウントアップされているのが分かる。

そして、thread1は、thread2からのGoサイン(pthread_cond_signal)が来るまで pthread_cond_wait で処理を待っているのも分かるはずだ。

signal送信側(thread2)は待機中スレッド(thread1)がwait中だろうが何だろうがシグナルを垂れ流す。上のログで、偶に sending signal... が2回連続して出力されているのはそのためである。

注意すべき点としては、pthread_cond_signal が一つのスレッドに対するsignal送信しか行わないということである。複数スレッドにまとめてsignal送信したい時は、pthread_cond_signal ではなく、 pthread_cond_broadcast を利用すること。


参考にさせていただいたサイト


マルチスレッドプログラミング - onishi-lab.jp


C++プログラミング入門
グレゴリー サティア ダウグ ブラウン
オライリー・ジャパン
売り上げランキング: 61971

PR:お買い物はAmazonで
posted by 寄り道退屈男 at 11:33 | Comment(0) | TrackBack(0) | C++