【経済】マルサスの間違い

今の世界の人口って70億越えたんでしたか。
小学校だか中学校だかの社会の時間に20年先、50年先とかの人口増加のグラフとか習ったけど、
それに対して恐怖の感情があったのを覚えています。

食糧・資源不足がおきて、そのために戦争がおこり、人口が減って、あ、それで人口増加の問題解決できた、ということは戦争は必要悪?と思うとうわー、恐ろしいこと今考えてしまった、と。

そんなことを最初に本にしたのがマルサスという人らしくて「人口論(1798)」は有名らしい。
マルサス

1.人は生きていくために食べる
2.人はエロい

を絶対的な真実とみなし、そこから人口の増加は食料の供給を上回ることを計算。常に貧困層があると考えました。計算内容はよく分からんけどそういうことらしい。

だから社会福祉で貧困対策したって意味無いよ〜という過激な思想みたいなので、初版は匿名でだしたのかなぁ。当時貧困対策法が論議されていたフランスで大反響だったようです。

人口論から200年たって、日本なんかは人口減になってるところをみるとマルサス間違ってるんじゃないかと思うわけです。ええ、計算部分は理解せずに書いてます、そう思うだけです。


貧しいとこほど子供が多いのに、なんで経済的に豊かになると経済的な理由で子供を少なくするのか。こんなことが起こるとは200年前に思いつくわけないですよね。

僕の考えでは、鍵になるのは家電じゃないかとにらんでます。
家電があると奥さんの家事が楽になります。
時間ができるので子供の教育に時間が割けます。
すると「こんなに大変だったら5人も6人も無理だわ〜」
となるのでは。

あえてマルサスの絶対真理にひとつ足すとすると

3.人は将来にわたって怠けものである

でしょうか。昔は人手が足りないのでいつか楽しようと子供も増やし、現在では何人も高等教育受けさせようと思ったら親がすげー働かないといけないのは眼に見えているので子供の数を抑えるんでは。

人口増加対策には生活保障より家電です。

iPhoneで未送信のメールを削除するには

アカウントを削除したり、面倒なことをしないで未送信にたまったメールを削除する方法

iPhoneで間違えた送信アドレスを送信してしまうと、ずっと未送信のまま何度も送信しようとして、どこで削除していいのか分からなくなります。

そんな時は「設定」>「メール/連絡先/カレンダー」にアカウントを追加します。gmailなど無料のWEBメールアカウントを持っていなければ取りましょう。
アカウントを追加したら、メールアプリを起動。これまでより一つ上の階層に「メールボックス」が現れますので、画面上部バーから戻ってメールボックスまできたら未送信カテゴリが出現、これで消せます。

EC-CUBEで銀行決済モジュールを作る

EC-CUBE店舗のカスタマイズを頼まれました。

銀行決済とクレジットカード決済をつけると。クレジットカード決済は愛媛銀行のものを使い、既存の有償オプションモジュールでは対応できるか分からず、モジュールとして自作することになりました。

銀行決済では購入完了の前に振込先を表示するだけでカスタマイズが簡単なので、そのやり方について書いておきます。

まず無料の決済モジュールを入れてみて調べたところ、モジュールのファイルは
[eccube]/data/downloads/module
([eccube]はインストールしたディレクトリまでの絶対パス
の下に入ることが分かりました。ここにモジュールフォルダを作っておきます。

決済でここのファイルを呼び出すようにするには、DBデータを直接変えるのが一番簡単でした。
dtb_paymentテーブルのmemo03に先ほど作った[eccube]/data/downloads/module/[モジュールディレクトリ名]/c
を入れると決済選択後のload_payment_module.phpがそのファイルをインクルードするわけです。
こちらでも説明しています。
http://d.hatena.ne.jp/red_snow/20090618/1245305496
memo03なんて名前のカラム名を使うところが「えぇ〜〜」な感じです。eccubeというのはコードは割りと読みやすいのですが、基本設計はけっこう行き当たりばったりというか後から実装しただろう部分でおかしなところが残っているようです。修正したくなりますけどぐっと我慢。

インクルードされるファイルでは好きに書いちゃっていいわけですが、とりあえず他と合わせようかと思い

[eccube]/data/downloads/module/[モジュールディレクトリ名]/mu-ginkou.php

<?php
require_once(realpath(dirname( __FILE__)) . "/LC_Page_Mdl_MuGinkou_Helper.php");

$objPage = new LC_Page_Mdl_MuGinkou_Helper();
$objPage->init();
$objPage->process();

としました。

LC_Page_Mdl_MuGinkou_Helper.php]

読み込まれるLC_Page_Mdl_MuGinkou_Helper.phに処理を書いていきます。

<?php
// {{{ requires
// モバイルサイトで読み込まれないのでrequireしておく。
//require_once(CLASS_PATH. "SC_CampaignSession.php");
//require_once(realpath(dirname( __FILE__)). '/LC_Page_Mdl_MuGinkou_Config.php');
//require_once(realpath(dirname( __FILE__)). "/LC_Helper_Send_Payment.php");
//require_once(DATA_PATH. 'module/Request.php');

require_once(CLASS_PATH . "pages/LC_Page.php");

//require_once(realpath(dirname( __FILE__)) . "/include.php");

// モジュールコード

define("MDL_MUGINKOU_CODE", "mdl_mu-ginkou");

class LC_Page_Mdl_MuGinkou_Helper extends LC_Page {

    /**
     * コンストラクタ
     *
     * @return void
     */
    function LC_Page_Mdl_MuGinkou_Helper() {
    }

    /**
     * Page を初期化する.
     *
     * @return void
     */
    function init() {
        parent::init();
        session_cache_limiter('private-no-expire');
    }

    /**
     * Page のプロセス.
     *
     * @return void
     */
    function process() {
		parent::process();
		$objView = (SC_MobileUserAgent::isMobile()) ? new SC_MobileView() : new SC_SiteView();
        $objSiteInfo = $objView->objSiteInfo;
        $objCartSess = new SC_CartSession();
        $objSiteSess = new SC_SiteSession();

		// ユーザユニークIDの取得と購入状態の正当性をチェック


		$uniqid = SC_Utils_Ex::sfCheckNormalAccess($objSiteSess, $objCartSess);

		$this->tpl_uniqid = $uniqid;


		switch($_POST['mode']) {
			// 完了ページへ
			case 'send':
            
				//echo 'send';
	
			$objSiteSess->setRegistFlag();
	
			$this->sendRedirect($this->getLocation(URL_SHOP_COMPLETE), true);
	
           exit;
	
			break;
			// 戻る
	
       case 'return':
		
		// 正常な推移であることを記録しておく
	
           $objSiteSess->setRegistFlag();
	
           $this->sendRedirect($this->getLocation(URL_SHOP_PAYMENT), true);
	
			exit;
	
           break;
			default:
				break;
        }
		$this->tpl_mainpage = MODULE_PATH . MDL_MUGINKOU_CODE. "/ginkou.tpl";	// テンプレートファイルを指定
		$objView->assignobj($this);
		$objView->display(SITE_FRAME);
	}


}
?>

ginkou.tpl

テンプレートファイル

<!--▼CONTENTS-->
<div id="under02column">
  <div id="under02column_shopping">

    <form name="form1" id="form1" method="post" action="<!--{$smarty.server.PHP_SELF|escape}-->">
    <input type="hidden" name="mode" value="send">
    <input type="hidden" name="uniqid" value="<!--{$tpl_uniqid}-->">
    

<p>銀行振込を選択された方は、<span style="color:red;">本日より1週間以内に下記口座に代金をお振込下さい。</span>なお、振込手数料がかかる場合はお客様の負担とさせて頂きますので、あらかじめご了承下さい。</p>
<br />
<p>お振込を確認しましたら、メールでご連絡致します。</p>
<p>※お支払金額等に誤りがある場合には、お電話差し上げる事もございます。</p>
<br />
<p>お支払口座:</p>
<p>○○銀行 ○○支店   普通預金   ○○○○○○○○○○</p>
<br />

    
    <p>
    以上の内容をメモしたうえで、下記「注文完了ページへ」ボタンをクリックしてください。<br />
    </p>

      <div class="tblareabtn">
        <a href="#" onclick="document.form2.submit(); return false;" onmouseover="chgImgImageSubmit('<!--{$TPL_DIR}-->img/common/b_back_on.gif',back03)" onmouseout="chgImgImageSubmit('<!--{$TPL_DIR}-->img/common/b_back.gif',back03)"><img src="<!--{$TPL_DIR}-->img/common/b_back.gif" width="150" height="30" alt="戻る" border="0" name="back03" id="back03"/></a>&nbsp;
        <input type="image" onclick="return fnCheckSubmit();" onmouseover="chgImgImageSubmit('<!--{$TPL_DIR}-->img/common/b_complete_on.gif',this)" onmouseout="chgImgImageSubmit('<!--{$TPL_DIR}-->img/common/b_complete.gif',this)" src="<!--{$TPL_DIR}-->img/common/b_complete.gif" width="150" height="30" alt="注文完了ページへ" border="0" name="next" id="next" />
      </div>
    </form>
    <form name="form2" id="form2" method="post" action="./load_payment_module.php" autocomplete="off">
      <input type="hidden" name="mode" value="return">            
    </form>
  </div>
</div>
<!--▲CONTENTS-->

苦労したのはユーザー用のヘッダ・フッタを表示するところ。最初、テンプレートファイルに直接書いてみたりしたのですが、ソースをみているうちに$objView->display(SITE_FRAME);でだせることが分かりました。
コンテンツ内のテンプレートファイルを指定するには$objView->_smarty->_tpl_vars['tpl_mainpage']を変えればいいので

$this->tpl_mainpage = MODULE_PATH . MDL_MUGINKOU_CODE. "/ginkou.tpl"; // テンプレートファイルを指定
$objView->assignobj($this);
$objView->display(SITE_FRAME);

としてやることで表示できるようになりました。

クレジットカードについても同じようにカード番号入力フォームなど作ってやりました。こちらは省略。

cakePHPシェルで最初に画面クリアされるのをやめる

cakePHPでshellスクリプトを書くと、デフォルトで画面をクリアしてWelcomeメッセージを表示する。


このWelcomeメッセージを消すやり方は分かった。
CakePHPのコンソールアプリ実行時の「Welcome to Cakephp…」を消す方法 - akiyan.com


しかし画面消去はどこで出力しているのか分からない。


出力されている文字はe"ESC[H""ESCe[2J"(ESCはバイナリで1B)。
調べているとエスケープシーケンスというらしい。え、\(バックスラッシュ)のことじゃないの、と思ったけど、両方エスケープシーケンスという。
1バイト目にエスケープを入れたらASCIIで(制御コード)拡張とみなされ、続けて文字を入力することでスクリーン制御できるというもの。
なにができるかは端末により異なるが、DECのVT100のものが事実上の標準。


phpのバッチでターミナル上で色をつける方法 - maru.cc@はてな
PHPでの書き方もあった

$ php -r 'echo pack('c',0x1B) . "[1;34m" . "hoge" . pack('c',0x1B) . "[0m\n";'

とするとターミナル上で文字に色がつくのを確認。


そこでこのような書き方をcakePHPがしているのかと"0x1B"や"[2J"で検索かけてみるのだけど

$ find . -type f -print | xargs grep '0x1B'
$ find . -type f -print | xargs grep '[2J'

みつからない。

いったいどうなってるんだろうと思い、cakePHPのコミュニティで質問してみた。
するとなんと、Welcomeメッセージを消すやり方を参考にした、akiyanさんから回答が。

現行の1.3.xのAPIドキュメントを確認したところ、記事通り、
vendors/shells/**.php で、_welcomeメソッドを定義してあげれば
画面クリアもウェルカムメッセージも消えてくれるはずです。

尚、画面クリア自体はShell::_welcome()内からShellDispatcher::clear()が呼ばれ、($this->Dispatcher->clear())
ShellDispatcher::clear()の中では、実行環境によってclearコマンドかclsコマンドが実行されていました。

さっそく1.3をダウンロードしてみてみると、
cake/console/libs/shell.phpの中に

function _welcome() {
	$this->Dispatch->clear();
	$this->out();
	$this->out('Welcome to CakePHP v' . Configure::version() . ' Console');
	$this->hr();
	$this->out('App : '. $this->params['app']);
	$this->out('Path: '. $this->params['working']);
	$this->hr();
}

clearしている命令があるじゃあないか。
ちなみにclear関数は

function clear() {
	if (empty($this->params['noclear'])) {
		if ( DS === '/') {
			passthru('clear');
		} else {
			passthru('cls');
		}
	}
}

としていた。なるほど、UNIXコマンドを使っているのか〜。それに、noclearで抑制することもできる、と。

それと、1.2で画面クリアを抑制する方法もokinakaさんに教えてもらった。

cake 1.2.x では、cake/console/cake 中に
直接 clear コマンドが記述されてました。
今まではこれを削除して対処してました。

えっ、と思ってcake/console/cakeをみたら、一発目にclearコマンドを実行していた。
これに気づかないとは、自分らしい・・・いや、思い込みは怖いものだ。UNIXコマンドを使っているとは思ってなかった。

ちなみに1.3でのnoclearのパラメータ設定の仕方は

TERM=xterm;export TERM;/home/www/htdocs/cake/console/cake test -app /home/www/htdocs/app -noclear

のようにコマンドの最後に-noclearをつけるだけ。これで画面クリアはされなくなる。

cakePHPとjQueryでXMLデータを受信する

cakePHPからjQueryを使ってXMLを取得するのだけど、どうもうまくXMLとして読み込めない。

もしかして出力しているXML生成プログラムののヘッダに問題があるのかと思ってHTTPヘッダをみると
Content-Type:text/html; charset=utf8
になっている。

あれ・・・?アクションの中で

<?
header('Content-Type: application/xml');

としていたのに。どこかでContent-Typeが上書きされているらしい。

MT Systems - CakePHP AjaxでJSONデータの出力の仕方とcontent-typeについて
を参考にコントローラにリクエストハンドラコンポーネントを追加して、拡張子で判別するように変えてみた。


でもContent-Typeは変らない。

app/views/layouts/xml/default.ctpにヘッダ出力をいれてやっとContent-Typeが変った。

<?php
header('Content-Type: application/xml');
echo $xml->header();//XML宣言を出力
echo $content_for_layout;

フレームワークは難しいな。こんなとこ詰まるようなところじゃないのに。アクションのbefore_filterにいれた

<?
function beforeFilter()
{
	if($this->action=='ajax_search'){
		Configure::write('debug',0);
		$this->RequestHandler->setContent('xml');
		$this->RequestHandler->respondAs('Content-Type: application/xml');
	}
}

respondAsがなぜ効かなかったのか、調べる気力もない。

とにかくこれで、jQueryを使ってXMLとしてデータ受信できるだろうか

jQuery.ajax({
	url : "/concerns/ajax_search/<?= $concern['Concern']['id'] ?>/type:mutter.xml", 
	type : "get",
	success : function(data){
		console.log(data.getElementsByTagName('target'));
	}
});

うまくいけた!