2012年12月26日水曜日

twitterの自動フォロワー管理ツールをつくってみた

GAE × Python2.7 × Twitter Api1.1でtwitterの自動フォロワー管理ツールをつくりました。


最初フォロー・フォロー削除共に1日480件という設定にしていたら、アップして数時間で速やかにtwitterからアカウント凍結されました。。まあさすがに1日48件なら大丈夫だろうと思ってるんですが、2回目以降凍結されると復活が困難らしいので、近日中にtwitterで新たな船出を迎えるかもしれません。

機能は下記になります。自分的にはかなり素早く作った方で、仕事終わりに半分寝ながらつくっていたので抜け漏れが結構ある可能性があります。今のところこれで特に問題なく動いているのですが、稼働させたばかりなので根本的なミスをしている可能性もあります。

・設定したキーワードをつぶやいている人を自動でフォローする
 (キーワードは3つまで設定できる)
・1日当たりのフォロー数も自由に設定可能(様々なリスクがあるので最大100件まで)
・フォローしてから一定期間経ってもリフォローされない場合は、フォロー解除する
・フォロー解除までの日数も自由に設定可能
・1日当たりのフォロー解除数も自由に設定可能(同じく最大100件まで)
 (でも100件でも十分凍結対象になりうるらしい。)
・フォロー解除したくないアカウントは、twitterのリストに登録しておけば、
 フォロー解除対象から外れる
・フォローする際は、以前フォロー削除したアカウントかどうかを確認して、
 以前のフォロー削除から一定期間が経過していない場合はフォローしない

このぐらい。リフォロー機能はまだない。

今回はtweepyという、python用のtwitter API操作モジュールを使いました。ただtwitter API 1.1 にtweepyが対応していなかったのですが、こちらsakitoさんという人がtweepy2というのを作ってくれていたのでこれを使わせていただきました。今回作った限りでは問題なく動いてます。ありがたいです。

2012年12月23日日曜日

GAEで純粋Django1.4を使う

環境はMacです。Eclipse×GAE×Python2.7を使ってます。純粋Djangoを使えるようになっていることを知ったので使ってみたいと思います。

参考にしたサイトは、下記2点です。

Windows7 x64 で、GAE/P(1.7.0) + Django 1.3 の環境を構築する
GAE 1.6+Django 1.2

前提としてGAEの基本的な開発環境はインストールされているものとします。

Djangoのインストール

まず、Djangoをローカル環境にインストールします。

僕はまずeasy_installをインストールしました。
sudo curl -O http://peak.telecommunity.com/dist/ez_setup.py

sudo python2.7 ez_setup.py

参考にpython2.7 ez_setup.pyの結果もメモしておきます。
Downloading http://pypi.python.org/packages/2.7/s/setuptools/setuptools-0.6c11-py2.7.egg
Processing setuptools-0.6c11-py2.7.egg
Copying setuptools-0.6c11-py2.7.egg to /opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages
Adding setuptools 0.6c11 to easy-install.pth file
Installing easy_install script to /opt/local/Library/Frameworks/Python.framework/Versions/2.7/bin
Installing easy_install-2.7 script to /opt/local/Library/Frameworks/Python.framework/Versions/2.7/bin

Installed /opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/setuptools-0.6c11-py2.7.egg
Processing dependencies for setuptools==0.6c11
Finished processing dependencies for setuptools==0.6c11

上記のeasy_install-2.7がインストールされたフォルダをPATHに追加します。
export PATH=/opt/local/Library/Frameworks/Python.framework/Versions/2.7/bin:$PATH

Djangoをeasy_install-2.7を使ってインストールします。
sudo easy_install-2.7 django

Djangoプロジェクトを作成する

Djangoを使わないなら、Google App Engine Launcherでプロジェクトを作成できますが、Djangoを使う場合、まずはdjango-admin.pyを使ってプロジェクトを作ります。

任意のフォルダにcdで移動してから、下記を実行します。
django-admin.py startproject myproject

任意のフォルダの中に、myprojectフォルダが出来、その中にまたmyprojectフォルダが出来、その中に下記4ファイルが出来ます。

__init__.py
settings.py
urls.py
wsgi.py

app.yamlとmain.pyの作成

今回はこれらファイルと同じ場所に、app.yamlとmain.pyを作成します。

app.yaml
application: myproject
version: 1
runtime: python27
api_version: 1
threadsafe: yes

handlers:
- url: /favicon\.ico
  static_files: favicon.ico
  upload: favicon\.ico

- url: .*
  script: main.app

libraries:
- name: django
  version: "1.4"

main.py
import os
# specify the name of your settings module
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'

import django.core.handlers.wsgi
app = django.core.handlers.wsgi.WSGIHandler()

Google App Engine Launcherへの登録と起動

次に、Google App Engine Launcherに登録します。 File > Add Existing Applicationにて、作成したプロジェクトのフォルダー(myprojectの中のmyproject)を登録します。 LauncherでRun > Browse して、下記のようなページが出たらDjnago連動成功。


MacのPATH追加方法

ターミナルで下記のようにやるようだ。

export PATH=/usr/local/bin/endo/yuta:$PATH

追加したいパスをPATH=の後に書いて、最後に:$PATHを追加する

MacにPython2.7をMacPortsを使ってインストールする

macにpython2.7をインストールしようと思って色々調べていたら、MacPortsがあればターミナル上で超簡単にインストールできるということで、MacPortsをインストールしようと思ったら、MacPortsにはXcoe Toolsのインストールが前提になるということだったので、Xcode Tools -> MacPorts -> Python2.7の順にインストールした。

Xcode Toolsはこのサイトから'Xcode Tools'を調べてDVDイメージみたいな900MB超のやつをダウンロードしてインストールしたら問題なくOKだった。

MacPortsはこのサイトから自分のmac osバージョンに合わせてダウンロードして、インストールしたら問題なくOKだった。

上記はこのサイトを参照した。

その後、下記のようにPython2.7をインストールしようとした。

sudo port install python27

しかし、下記のようなエラーになった。

Error: Unable to open port: can't read "build.cmd": Failed to locate 'make' in path: '/opt/local/bin:/opt/local/sbin:/bin:/sbin:/usr/bin:/usr/sbin' or at its MacPorts configuration time location, did you move it?

下記のサイトを参考にした。
■[MacPorts]MacPortsで Error: Unable to open port: can't read "build.cmd" とエラーが出た時の対処方法

僕がダウンロードした、Xcode ToolsのDVDイメージは、"xcode312_2621_developerdvd.dmg"だったが、これには"Packages"というフォルダがある。その中の"DeveloperToolsCLI.pkg"をインストールしたら、エラーが出ずにPython2.7をインストールできるようになった。

MacPortsを使ってインストールしたPython2.7は、/opt/local/binに保存される。

2012年12月20日木曜日

Androidアプリ - Callcenter Calculator コールセンター計算機 をつくりました。


Titaniumでコールセンター計算機をつくりました。

Callcenter Calculator - コールセンター計算機です。入電数や処理時間などを入力すると、必要席数やコストを算出します。必要席数はアーランC式によって計算します。 月間入電数、平均通話時間、平均後処理時間、目標応答率、管理者比率などを設定すると共に、SV、オペレータの支払い時給や社保、交通費、シェアード運用有無などを設定することで、必要席数とコストを試算します。またコールセンターをアウトソーシングした場合(あるいはアウトソーシングサービスとして販売する場合)の売値及び利益率なども合わせて試算します。



Google play: コールセンター計算機

2012年9月30日日曜日

JavaScriptのDate関数を試してみる

date関数は、getYearすると、1900年からの差分を返すようです。とほほにはブラウザによって変わると書いてあるが、Chromeは少なくともそうなっていますし、アンドロイド&titaniumもそうなようです。

setYearをdd.setYear(dd.getYear()+1);といった形でやると、Yearは113になります(今が2012なので)。よって、dd.setYear(dd.getYear()+1901);にすると、Yearは2013になるようです。

var ee = dd;とすると、eeはddの参照が入るようで、eeを変更するとddも変更されます。

あと、今が9月30日の場合は、1日足すと10月1日になるはずですが、こういった処理はしっかりやってくれます。例えば、dd.setDate(dd.getDate()+1);とすると、今が9月30日ならば、10月1日のdateオブジェクトに変更されてます。

<script type="text/javascript">
var dd = new Date();
document.write(dd+"<br />");

var y = dd.getYear();
document.write(y+"<br />");

dd.setYear(dd.getYear()+1);
document.write(dd+"<br />");

dd = new Date();
dd.setYear(dd.getYear()+1901);
document.write(dd+"<br />");

document.write(dd.getYear()+"<br />");

dd.setDate(dd.getDate()+1);
document.write(dd+"<br />");

dd.setDate(dd.getDate()-2);
document.write(dd+"<br />");
</script>

2012年9月17日月曜日

Titanium とAppcelerator Cloud Services(BaaS)

ついに腰を据えてとりあえずTitaniumをやることに決めました。iPhoneでもAndroidでもアプリをJavascriptベースで作れるもので、Phonegapとかよりも速いらしい。Appcelerator Cloud Services(ACS)というBaasを自社で持っているため、Titaniumとの連動性が高い点も良さそう。iPhoneであればアプリ内課金に公式モジュールが対応しているようで、Android版モジュールもあるようだが、まだバグが多いようだという情報のみ発見した。まだ出来たてのようだ。 下記は、TitaniumでACSを使ってみたサンプルプログラムのコード
var Cloud = require('ti.cloud');
Cloud.debug = true;

Titanium.UI.setBackgroundColor('#0f0');

var win = Titanium.UI.createWindow({
 backgroundColor: '#000'
});

var label1 = Titanium.UI.createLabel({
 text: 'Sample1',
 color: '#ff0',
 font: {
  fontFamily: 'Arial',
  fontSize: '70px',
  fontWeight: 'bold'},
 top: '10px'
});

var label2 = Titanium.UI.createLabel({
 text: '',
 color: '#f0c',
 font: {
  fontFamily: 'Arial',
  fontSize: '30px',
  fontWeight: 'normal'},
 top: '100px'
});

var textField = Titanium.UI.createTextField({
 value: '',
 borderStyle: Titanium.UI.INPUT_BORDERSTYLE_ROUNDED,
 width: '200px',
 top: '150px'
});

var button = Titanium.UI.createButton({
 title: 'ボタン',
 top: '250px',
 width: '200px',
 height: '80px'
});

button.addEventListener('click',function(e){ 
 label2.text = 'User登録中...';
 
 Cloud.Users.create({
     username: textField.value,
     password: textField.value,
     password_confirmation: textField.value,
 }, function (e) {
     if (e.success) {
   label2.text = 'User登録が完了しました!';
     } else {
         label2.text = 'User登録に失敗しました。';
     }
 });
});

win.add(label1);
win.add(label2);
win.add(textField);
win.add(button);

win.open();

2012年6月26日火曜日

スマホアプリとWEBサーバの連動



スマホアプリ開発で、WEBのサーバと連動したい場合、HTML5でやりぬくパターンと、インターフェースをアプリ開発してサーバーと連動するケースと両方ある。サーバー連動方法はまあ何かしらあるはずだが、どちらかというと、HTML5でやりぬけた方が楽だ。でもメニューボタンを使いたくなるのは人間の性であり、これが機能しないアプリというのは残念である。例えばアプリをつくるけどもブラウザ表示機能を全面に使いつつ、メニューボタンは各URLに紐づけるということが出来るとお手軽である。ログイン機能なんかもHTML5様がやってくれるので新たにスマホの為に頭を使うことは非常に少ない。気になるのはWEBサイト用のapiだった場合に、勝手にきちんとモバイル画面用の表示になってくれるのかという点があるが、恐らくなってくれるに一票。すくなくともpaypalは自動認識して自動切替すると書いてあった。これなら簡単そうだし、今つくってみてるWEBページがそのまま使えるし、まあcssとかjavascriptとかで調整は必要だけど、アプリにもなる。これの簡易アプリを試しに作ってみよう。

追記
2012年6月27日現在、BaaSだとかモバイルバックエンドだとかいうサービスのことを初めて知りました。これはロリポップにお世話にならなくてもアマゾンにお世話にならなくても、サーバ側のデータベースから、ソーシャル連携から、ユーザ管理から、プッシュ通知から、何から何までパッケージ化して提供してくれる、クラウドのサービスプラットフォームでした。これはモバイルバックエンドということでモバイルを想定しているものの、iPhoneとAndroidでしか使えないわけではなく、HTML5でも使えるのでPC用でも使えるわけであります。果たして私が微妙に慣れ親しんだCakePHPやMySQLは過去の遺産になるのだろうか。tiggziでドラッグ&ドロップでインターフェースを作り、BaaSをAPI連携させればもう本格アプリができてしまうのでないか?BaaSがどの程度柔軟にサーバ側の処理をいじることができるのか試してみよう。ちなみにtiggziで用意されているMongoDBとかいうやつは確かNoSQLとかいうやつだった気がするが、まあはっきりいって詳細はわかっていない。簡単にいうと従来のSQLではないことは確かだ。これもtiggziでの使われ方はBaaSなんだろう。

よって、スマホアプリとサーバ連携に関しては、HTML5でやりぬくパターン(インターフェースをHTML5で作りCSSとJavascriptでスマホに最適化するだけ)、インターフェースをアプリ開発し、サーバと連動させるパターン(これのお手軽バージョンがBaasなんだろう)、インタフェースの大枠だけアプリ開発しつつ、中身はHTML5で作成したWEBページを埋め込むパターンの大きく3つあるのだ。

2012年6月24日日曜日

cakePHP - formヘルパーのメモ

cakePHP1.3使ってます。

formヘルパーは便利です。何でもAjaxでやりたいのであれば便利さは限定されるのかもしれませんが、それでもエラーがある場合のチェック機能などを使うとそれはそれで便利に使えるのかもしれません。今回はform登録をAjax機能を使わずに実施する想定で、Userテーブルに名前と生年月日と性別を登録する超シンプルな構成を想定します。formヘルパー自体今までほとんど無視していましたので、便利な機能を覚えるためにメモります。

テーブル - users

フィールド種別照合順序NULLデフォルト値その他
idint(11)いいえNoneauto_increment
namevarchar(30)utf8_unicode_ciいいえNone
birthdateはいNULL
gendervarchar(2)utf8_unicode_ciはいNULL

モデル - user.php

<?php 
class User extends appModel{
    var $name = 'User';
    
    public $validate = array(
        'name' => array(
            'rule' => 'notEmpty',
            'message' => 'nameは必ず入力してください'),
        'birth' => 'date',
        'gender' => array(
            'rule' => array('inList', array('男性','女性')),
            'message' => '「男性」か「女性」を入力してください。')
    );
}
?>

コントローラー - formtests_controller.php

<?php 
class FormtestsController extends AppController{
    public $name = 'Formtests';
    public $uses = array('User');
    public $layout = 'formtests';
    
    function index(){
        if(!empty($this->data)){
            if($this->User->save($this->data)){
                $this->redirect('./');
            }
        }
    }

}
?>

ビュー - index.cpt

<h1>Form Test</h1>

<?php echo $form->create('Formtest',array('action'=>'index')); ?>
<?php echo $form->input('User.name',array('label'=>'名前')); ?>
<?php echo $form->input('User.birth',array('label'=>'生年月日','dateFormat'=>'YMD','minYear'=>date('Y')-80,'maxYear'=>date('Y'),'separator'=>'/','monthNames'=>false)); ?>
<?php echo $form->input('User.gender',array('label'=>'性別','options'=>array('男性'=>'男性','女性'=>'女性'))); ?>
<?php echo $form->submit('add'); ?>
<?php echo $form->end(); ?>

css

body{
    background-color:#999;
    font-family:'Trebuchet MS', Trebuchet, sans-serif;
    font-size:12px;
    margin:10px;
}
h1{
    font-size:30px;
}
.error-message{
    color:#f00;
}
label{
    display:block;
    width:70px;
    float:left;
}

2012年6月17日日曜日

ストレス無しでGoogleマップを使ったサイトが作れる「gmaps.js」を使ってみる

ストレス無しでGoogleマップを使ったサイトが作れる「gmaps.js」で知った、gmaps.jsを使ってみます。
まずここで、ダウンロードします。ソースコードをコピペしてgmaps.jsを作成しました。ところで、google map APIはあまり使ったことがないので、とりあえずそもそもの使い方を確認しよう。

Google Maps APIのそもそもの使い方

GoogleマップのAPIは正式には今はGoogle Maps JavaScript API V3というらしい。これのチュートリアルを見ながらそもそもの使い方を大体覚えたい。チュートリアルにあるHTMLコードをコピペ(コピペした後で、titleを加えて、sensor=set_to_true_or_falseというところを、sensor=falseに変更して、スタイルは別ファイルで定義した。)したところ、地図が表示された。どうもid登録なんかは不要なようだ。その代わり使い方によっては有料になるようだ。
<!DOCTYPE html>
<html>
<head>
<title>gmaps test</title>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<link rel="stylesheet" type="text/css" href="./css/cake.gmaps.css" />
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script type="text/javascript">
  function initialize() {
    var latlng = new google.maps.LatLng(-34.397, 150.644);
    var myOptions = {
      zoom: 8,
      center: latlng,
      mapTypeId: google.maps.MapTypeId.ROADMAP
    };
    var map = new google.maps.Map(document.getElementById("map"),
        myOptions);
  }
</script>
</head>
<body onload="initialize()">
  <div id="map"></div>
</body>
</html>

このように地図が表示された。中心の経度・緯度情報と、ズームレベルと、地図のタイプを決めて初期化しているようだ。地図のタイプは、ROADMAP、SATELLITE、HYBRID、TERRAINなどがあるようだ。タイプは色々他にも設定ができるようだ。

住所を経度・緯度情報に変換することをジオコーディングというらしいが、そういうこともお手軽に出来るようだ。

これでGoogle Maps APIのイメージがつかめたので、いざgmaps.jsを使ってみよう。

gmaps.js で地図を表示する

gmaps.jsはjQueryを使っているのでjQueryを読み込まないといけない。当然最初につくったgmaps.jsも読み込まないといけない。gmaps.jsで上記と同じ地図を表示するには、下記のようになります。
<!DOCTYPE html>
<html>
<head>
<title>gmaps test</title>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<link rel="stylesheet" type="text/css" href="./css/cake.gmaps.css" />
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.1/jquery.min.js"></script>
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script type="text/javascript" src="./js/gmaps.js"></script>
<script type="text/javascript">
    var map;
    $(document).ready(function(){
        map = new GMaps({
            div: '#map',
            zoom: 8,
            lat: -34.397,
            lng: 150.644
        });
    });
</script>
</head>
<body>
  <div id="map"></div>
</body>
</html>
zoomはデフォルトで15になっているようだ。15のままでよければzoomは記載しなくてよい。マップタイプはデフォルトでROADMAPになっているようだ。ROADMAP以外にしたい場合は、mapTypeId: google.maps.MapTypeId.HYBRIDなどと追記すればよい。

gmaps.jsでジオコーディングする

下記のようにするとジオコーディングが使える。確かにお手軽だ。下記のコードだとマーカーまでつけている。
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<title>gmaps test</title>
<link rel="stylesheet" type="text/css" href="./css/cake.gmaps.css" />
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.1/jquery.min.js"></script>
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script type="text/javascript" src="./js/gmaps.js"></script>
<script type="text/javascript">
    $(document).ready(function(){
      map = new GMaps({
        div: '#map',
        lat: -34.397,
        lng: 150.644
      });
      $('#geocoding_form').submit(function(e){
        e.preventDefault();
        GMaps.geocode({
          address: $('#address').val().trim(),
          callback: function(results, status){
            if(status=='OK'){
              var latlng = results[0].geometry.location;
              map.setCenter(latlng.lat(), latlng.lng());
              map.addMarker({
                lat: latlng.lat(),
                lng: latlng.lng()
              });
            }
          }
        });
      });
    });
</script>

</head>
<body>
    <form method="post" id="geocoding_form">
        <label for="address">住所:</label>
        <div class="input">
            <input type="text" id="address" name="address" />
            <input type="submit" class="btn" value="Search" />
        </div>
    </form><br />
    <div id="map"></div>
</body>
</html>

gmaps.jsでジオコーディングする2

今度は、渋谷のヒカリエの場所を最初から出すようにしよう。ヒカリエの場所にはマーカーもつけよう。
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<title>gmaps test</title>
<link rel="stylesheet" type="text/css" href="./css/cake.gmaps.css" />
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.1/jquery.min.js"></script>
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script type="text/javascript" src="./js/gmaps.js"></script>
<script type="text/javascript">
    var rikkyo = '東京都 豊島区西池袋3-34-1';
    $(document).ready(function(){
      map = new GMaps({
        div: '#map',
        lat: 1,
        lng: 1
      });
      GMaps.geocode({
          address: rikkyo,
          callback: function(results, status){
            if(status=='OK'){
              var latlng = results[0].geometry.location;
              map.setCenter(latlng.lat(), latlng.lng());
              map.addMarker({
                lat: latlng.lat(),
                lng: latlng.lng()
              });
            }
          }
      });
    });
</script>
</head>
<body>
    <div id="map"></div>
</body>
</html>

ヒカリエがうまく表示されないので立教大学を表示してみた。ページを読み込むと、立教大学の住所を経度・緯度情報に変換し、立教大学の経度・緯度情報を地図の中央にセットしている様です。

gmaps.jsでジオコーディングとオーバーレイする

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<title>gmaps test</title>
<link rel="stylesheet" type="text/css" href="./css/cake.gmaps.css" />
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.1/jquery.min.js"></script>
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script type="text/javascript" src="./js/gmaps.js"></script>
<script type="text/javascript">
    var rikkyo = '東京都 豊島区西池袋3-34-1';
    $(document).ready(function(){
      GMaps.geocode({
          address: rikkyo,
          callback: function(results, status){
            if(status=='OK'){
              var latlng = results[0].geometry.location;
              var map = new GMaps({
                  div: '#map',
                  lat: latlng.lat(),
                  lng: latlng.lng()
                });
              map.drawOverlay({
                  lat: map.getCenter().lat(),
                  lng: map.getCenter().lng(),
                  content: '<div class="overlay">Rikkyo<div class="overlay_arrow above"></div></div>',
                  verticalAlign: 'top',
                  horizontalAlign: 'center'
              });
            }
          }
      });
    });
</script>
</head>
<body>
        <div id="map"></div>
</body>
</html>
スタイルシートは下記です。
#map{
  width:300px;
  height:300px;
}
.overlay{
  display:block;
  text-align:center;
  color:#fff;
  font-size:15px;
  line-height:17px;
  opacity:0.8;
  background:#905;
  border:solid 3px #905;
  border-radius:4px;
  box-shadow:2px 2px 10px #333;
  text-shadow:1px 1px 1px #666;
  padding:0 4px;
}

.overlay_arrow{
  left:50%;
  margin-left:-8px;
  width:0;
  height:0;
  position:absolute;
}
.overlay_arrow.above{
  bottom:-7px;
  border-left:8px solid transparent;
  border-right:8px solid transparent;
  border-top:8px solid #905;
}
.overlay_arrow.below{
  top:-7px;
  border-left:8px solid transparent;
  border-right:8px solid transparent;
  border-bottom:8px solid #905;
}

これなら企業のホームページのアクセスマッップなんかをgoogle maps apiで作るのも超お手軽ですね。

gmaps.jsでポリゴンとインフォウィンドウする

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<title>gmaps test</title>
<link rel="stylesheet" type="text/css" href="./css/cake.gmaps.css" />
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.1/jquery.min.js"></script>
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script type="text/javascript" src="./js/gmaps.js"></script>
<script type="text/javascript">
$(document).ready(function(){
    var map;
    var ll = path = g = [];
    ll[0] = [35.7305222 , 139.7039449];
    ll[1] = [35.7127036 , 139.76327730000003];
    ll[2] = [35.70935559999999 , 139.71944410000003];
    path = [ll[0],ll[1],ll[2]];
    g = [(ll[0][0]+ll[1][0]+ll[2][0])/3,(ll[0][1]+ll[1][1]+ll[2][1])/3];
    map = new GMaps({
        div: '#map',
        zoom: 13,
        lat: g[0],
        lng: g[1],
     });
    polygon = map.drawPolygon({
        paths: path,
        strokeColor: '#f09',
        strokeOpacity: 0.3,
        strokeWeight: 0.3,
        fillColor: '#f09',
        fillOpacity: 0.3
    });
    for(var i=0;i<ll.length;i++){
        map.addMarker({
            lat: ll[i][0],
            lng: ll[i][1],
            icon: './img/sugi.png',
            infoWindow: {
              content: sugi(i)
            }
        });
    }
});
function sugi(idx){
    if(idx == 0){
        return '<p>立教大学</p><p>白いワイシャル着てナポリタン食べてやったぜ〜</p>';
    }else if(idx == 1){
        return '<p>東京大学</p><p>白いワイシャル着てミートソーススパゲッティー食べてやったぜ〜</p>';
    }else{
        return '<p>早稲田大学</p><p>白いワイシャル着てトマトスパゲッティー食べてやったぜ〜</p>';
    }
}
</script>
</head>
<body>
    <div id="map"></div>
</body>
</html>

東京大学、早稲田大学、立教大学の場所をすぎちゃんが指し示し、この3地点を赤色の三角形で囲った様。

すぎちゃんをクリックすると、ねたをつぶやく様。

cakePHP1.3 - 画像のアップロードの研究

cakePHP1.3で画像をアップロードできるようにします。 参考にするサイトはツチノコラボです。

研究用にUptestsコントローラーをつくりました。
Uptestsコントローラーのindexアクションにアップロード処理をつくります。ちなみに、今回はデータベースにファイルを保存するのではなく、フォルダに格納します。最終的には、ファイル名をデータベースで管理できるようにしたいと思います。

Viewの設定

まずViewにformをつくります。index.ctpを下記のように作成しました。
<h1>Update Test</h1>

<?php
    $options = array(
        'action'=>'index',
        'type'=>'file'
    );
    echo $form->create('Uptest', $options);
?>
<?php echo $form->file('file_name') ?>
<?php echo $form->submit('送信'); ?>
<?php echo $form->end(); ?>
画面イメージは下記のようになります。

ちなみに、作成されるHTMLソースは下記のようになります。
<h1>Update Test</h1>

<form action="/cake/uptests" id="UptestIndexForm" enctype="multipart/form-data" method="post" accept-charset="utf-8">
<div style="display:none;"><input type="hidden" name="_method" value="POST" /></div>
<input type="file" name="data[Uptest][file_name]" id="UptestFileName" /><br />
<div class="submit"><input type="submit" value="送信" /></div>
</form>

Controllerの設定

次にUptestsコントローラーをつくります。下記コードでファイルのアップロードは出来るようになります。
<?php 
Configure::write('upload.path', 'img/upload');

class UptestsController extends AppController{
    public $name = 'Uptests';
    public $uses = array();
    public $layout = 'uptests';
    
    //画像アップロード
    public function index(){
        //データチェック
        if (empty($this->data)) return;
        if(!(is_uploaded_file($this->data['Uptest']['file_name']['tmp_name']))) return;

        //アップロードするファイルの場所
        $uploaddir = Configure::read('upload.path');
        $uploadfile = $uploaddir.DS.basename($this->data['Uptest']['file_name']['name']);
        
        // 同じ名前のファイルがすでに存在すれば、別名に変える
        $info = pathinfo($uploadfile);
        $i = 1;
        while(file_exists($uploadfile)){
            $i++;
            $file_name = basename($info['basename'],'.'.$info['extension']).
                '_'.$i.'.'.$info['extension'];
            $uploadfile = $info['dirname'].DS.$file_name;
            $this->data['Uptest']['file_name']['name'] = $file_name;
        }
        
        //画像をテンポラリーの場所から、正式な置き場所へ移動
        if (move_uploaded_file($this->data['Uptest']['file_name']['tmp_name'], $uploadfile)){
            chmod($uploadfile, 0666);
        }else {
            $this->Session->setFlash("ファイルのアップロードに失敗しました。");
        }
    }
}
?>
一番上の行の、Configure::write('upload.path', 'img/upload');というのは、upload.pathにimg/uploadと設定している様です。Configureメソッドは、ここに説明が書いてあります。
upload.pathは、ファイルをアップロードするパスのことで、app/webrootフォルダを基準にしたパスになります。よって、app/webroot/img/uploadにファイルをアップロードすると設定していることになります。ちなみに、uploadフォルダは、このコードですと事前に作成しておく必要がありますし、フォルダの権限設定も書き込み可能にしておく必要があります。

これで、フォームでファイルを選択して送信ボタンを押すと、ファイル名の重複を回避しながら、uploadフォルダにファイルが保存できるようになりました。

アップデートファイルのチェック

次に、ファイル名、ファイルのサイズ、拡張子をチェックして、条件に合うファイルのみアップロードするようにします。

ファイル名は半角英数字(英語は小文字のみ)とアンダーバーで30文字以内をルールにします。
if(!preg_match('/^[a-z0-9_]{1,30}$/',$this->data['Uptest']['file_name']['name'])) return;

ファイルのサイズは、$this->data['Uptest']['file_name']['size']に入っていますので、これをチェックするロジックを作ればOKです。
if($this->data['Uptest']['file_name']['size']>500000) return;

拡張子は、$this->data['Uptest']['file_name']['type']に入っていますので、これをチェックするロジックを作ればOKです。拡張子は、jpg,png,gifのみOKにします。
if($this->data['Uptest']['file_name']['type'] != 'image/jpeg' &&
    $this->data['Uptest']['file_name']['type'] != 'image/png' &&
    $this->data['Uptest']['file_name']['type'] != 'image/gif') return;

まとめ

あとは、データベースでファイル名を管理すればいいのですが、テストの為にユーザテーブル作るのめんどくさいのでやめましょう。ユーザテーブルがあったとして、イメージカラムつくって格納すればいいだけだし、例えばイメージを3つまで登録できるようにするのであれば、カラム3つ作ればよいです。アップデート前に3つすでに登録されているか確認して登録済みであればエラーを出すか、どれかと入れ替えるか確認する画面を表示したりすればいいかと存じます。

最後にまとめのコードを記載して終了します。

↓ビュー
<h1>Update Test</h1>

<?php
    $options = array(
        'action'=>'index',
        'type'=>'file'
    );
    echo $form->create('Uptest', $options);
?>
<?php echo $form->file('file_name') ?>
<?php echo $form->submit('送信'); ?>
<?php echo $form->end(); ?>

<?php if(!empty($err)) echo $err;?>
↓コントローラー
<?php 
Configure::write('upload.path', 'img/upload');

class UptestsController extends AppController{
    public $name = 'Uptests';
    public $uses = array();
    public $layout = 'uptests';
    
    //画像アップロード
    public function index(){
        //データチェック
        if (empty($this->data)) return;
        if(!(is_uploaded_file($this->data['Uptest']['file_name']['tmp_name']))) return;
        
        //ファイル名チェック
        if(!preg_match('/^[a-z0-9_]{1,30}$/',$this->data['Uptest']['file_name']['name'])){
            $this->set('err','ファイル名は半角小文字英数字とアンダーバーで30文字以内にしてください。');
            return;
        }
            
        //ファイルサイズチェック
        if($this->data['Uptest']['file_name']['size']>500000){
            $this->set('err','ファイルサイズは500KB未満にしてください。');
            return;
        }
        
        //拡張子チェック
        if($this->data['Uptest']['file_name']['type'] != 'image/jpeg' &&
           $this->data['Uptest']['file_name']['type'] != 'image/png'  &&
           $this->data['Uptest']['file_name']['type'] != 'image/gif'){
                $this->set('err','ファイルはJPG,PNG,GIFのいずれかにしてください。');
                return;
        }
        
        //アップロードするファイルの場所
        $uploaddir = Configure::read('upload.path');
        $uploadfile = $uploaddir.DS.basename($this->data['Uptest']['file_name']['name']);
        
        // 同じ名前のファイルがすでに存在すれば、別名に変える
        $info = pathinfo($uploadfile);
        $i = 1;
        while(file_exists($uploadfile)){
            $i++;
            $file_name = basename($info['basename'],'.'.$info['extension']).
                '_'.$i.'.'.$info['extension'];
            $uploadfile = $info['dirname'].DS.$file_name;
            $this->data['Uptest']['file_name']['name'] = $file_name;
        }
        
        //画像をテンポラリーの場所から、正式な置き場所へ移動
        if (move_uploaded_file($this->data['Uptest']['file_name']['tmp_name'], $uploadfile)){
            chmod($uploadfile, 0666);
        }else {
            $this->set('err','ファイルのアップロードに失敗しました。');
        }
    }
    
}
?>

2012年6月2日土曜日

JavaScriptでアーランCによりコールセンターの必要席数を計算する

アーランC式は下記になります。


アーランC式はこのページのように、別の計算方法もありまして、別の方法だと待ち時間をインプットするようですが、上記の式は待ち時間のインプット不要バージョンです。アーランC式がなぜこのような式になるのかは全然分かりませんが、コールセンターの必要席数試算でアーランC式がよく使われています。

アーランC式をJavaScriptで計算できるようにしたのが下記になります。大体アーランが700を超えるとJavaScriptの数字の取り扱いキャパシティーの関係上エラーになりますので、アーラン700を上限にしました。アーランはコール数×平均処理時間÷3600で出します。

1時間当たり着信数
平均処理時間
応答率%

2012年5月25日金曜日

cakePHPでfacebookアプリをつくる(ログアウト)

facebookが用意してくれているSDKを使う前提です。
ログアウトは下記のように、$facebook->destroySession();として、セッションを削除します。
public function logout(){
        $facebook = $this->createFacebook();
        $facebook->destroySession();
        $this->redirect('/');
}

2012年5月20日日曜日

cakePHPでfacebookアプリをつくる(facebookでログイン)

cakePHPだと普通のPHPのSDKなどがうまく使えなかったりする場合がおます。

facebookはtwitterのapiと比較すると非常に懇切丁寧でありまして、ドキュメントも分かり易ければ実際の操作も非常にお手軽になっているケースが多く、加えてJavascriptだろうがPHPだろうが、スマホネイティブだろうが、なんでもそれに合わせたSDKを用意してくれています。私はPHP特にcakePHPでfacebookからログインできるようなサイトをつくろうと思って調べていたところ、下記ページを発見いたしました。

CakePHPでFacebookにConnect、wallに投稿する機能つくってみました。

これを見て、facebookが用意してくれているSDKを問題なく使えることが分かりました。ただ、「作業手順4.facebook-php-sdkのbase_facebook.phpをすこしいじる。」という記載があったのですが、これもすっとばしてもいけるんじゃないかという適当な予想のもとやってみたらすっとばしてもログイン機能の実装までにおいては問題ございませんでした。メモとしてログイン機能の実装のコードを記載します。

コードの前に、準備作業のポイントも記載します。

2012年5月19日土曜日

Bloggerにtwitter,Facebook「いいね!」,g+,はてブのボタンを設置する方法

下記をコピペして、一番上の行の「ツイッターユーザー名」を自分のユーザー名に変更するだけ。
<a class='twitter-share-button' data-count='horizontal' data-lang='en' data-via='ツイッターユーザー名' expr:data-text='data:title + &quot;: &quot;+ data:post.title' expr:data-url='data:post.url' href='http://twitter.com/share'>Tweet</a>  
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=&quot;//platform.twitter.com/widgets.js&quot;;fjs.parentNode.insertBefore(js,fjs);}}(document,&quot;script&quot;,&quot;twitter-wjs&quot;);</script>

<iframe allowTransparency='true' expr:src='&quot;http://www.facebook.com/plugins/like.php?href=&quot; + data:post.url + &quot;&amp;send=false&amp;layout=button_count&amp;width=450&amp;show_faces=false&amp;action=like&amp;colorscheme=light&amp;font&amp;height=21&quot;' frameborder='0' scrolling='no' style='border:none; overflow:hidden; width:130px; height:21px;'/>

<g:plusone expr:href='data:post.url' size='medium'/>
<!-- この render 呼び出しを適切な位置に挿入してください -->
<script type='text/javascript'>
  window.___gcfg = {lang: &#39;ja&#39;};

  (function() {
    var po = document.createElement(&#39;script&#39;); po.type = &#39;text/javascript&#39;; po.async = true;
    po.src = &#39;https://apis.google.com/js/plusone.js&#39;;
    var s = document.getElementsByTagName(&#39;script&#39;)[0]; s.parentNode.insertBefore(po, s);
  })();
</script>

<a class='hatena-bookmark-button' data-hatena-bookmark-layout='standard' expr:data-hatena-bookmark-title='data:blog.pageTitle' expr:href='&quot;http://b.hatena.ne.jp/entry/&quot; + data:post.url' title='このエントリーをはてなブックマークに追加'>
<img alt='このエントリーをはてなブックマークに追加' height='20' src='http://b.st-hatena.com/images/entry-button/button-only.gif' style='border: none;' width='20'/>
</a>
<script async='async' charset='utf-8' src='http://b.st-hatena.com/js/bookmark_button.js' type='text/javascript'/>

2012年5月6日日曜日

cakePHP1.3 POSTとGETの判別

cakePHPでPOSTとGETを判別するには、下記のようにやるらしい。
if ($this->RequestHandler->isPost()) {
        // POSTの場合
} else {
        // GETの場合
}
当然ながらisGet()という関数も用意されているらしい。

http://my-memolog.blogspot.jp/2011/03/cakephppostget.html

2012年1月31日火曜日

CSS - jQueryで垂直中央に配置する

jQueryを使ってボタンを親要素の高さの真ん中に配置したいと思います。単純なことですが、ちょっとはまったので、切り出して試しました。cssでheightを100%にするの忘れてたり、jQueryでtopを設定するときに'px'の2文字を入れ忘れたりしていただけでしたが、せっかく切り出して試したのでメモります。


下記のコードはブラウザで上記のような画面になります。まさしくボタンが中央に配置されています。

Html

<div id="box">
     <ul>
          <li class="a">aaaaaa
          <li class="b">bbbbbb
          <li class="c"><input id="btn" type="button" value="cccccc" />
     </ul>
</div>

css

#box{
     height:150px;
     background-color:#333;
     width:400px;
}
ul{
     margin:0;
     padding:0 10px;
     list-style-type: none;
     height:100%;
}
li{
     float:left;
}
.a{
     width:100px;
     background-color:#f00;
     height:100%;
}
.b{
     width:150px;
     background-color:#0f0;
}
.c{
     width:100px;
     background-color:#00f;
     height:100%;
     position:relative;
}
#btn{
     position:absolute;
}

javascript

$(function(){
     $(document).ready(function(){
          var btnh = $('#btn').outerHeight(true);
          var ch = $('.c').outerHeight(true);
          $('#btn').css('top',(ch-btnh)/2+'px');
     });
});

2012年1月30日月曜日

jQuery+CSS3サンプル

jQueryとCSS3を使ったサイトのサンプルを作ってみました。

jQueryをちょっとばかにしてたけどかなり色々できて面白い。スマホだとIE対応等の為に重くなっているらしいので、もっと軽いjQueryみたいなやつが沢山でているそうです。同じような使い方であることを祈ります。

このサンプルは、ここで見られます。

このサンプルは、画面がロードされるとメニューが横から飛んできます。メニューはアコーディオンになっていて、アクティブなメニューと非アクティブなメニューで色分けされます。後は、ローダーもspinnerというプラグインを使って入れてみました。このプラグインは分かり易いし便利です。あとは、ポップアップしてFacebookみたいに登録完了を告げてちょっとしたらポップアップが消えていくようにしました。インターネットが重い場合は、最初のメニューが横から飛んでくる前に画面に表示されちゃうかもしれません。最初は透明にするなりしておけばよかった。

2012年1月29日日曜日

消費税増税

国には予算があり、予算に基づいて僕らにいいことしてくれます。でも予算が税収を大きく上回っております
12年度予算案の一般会計総額は90兆3339億円。新規国債発行額は44兆2440億円と政府の財政健全化目標を守ったが、国債への依存度は49.0%とほぼ半分に達し、当初予算ベースで過去最悪を更新した。過去に編成した補正予算も含めると、国債発行額が税収見通しを上回るのは4年連続。
税収が40兆円くらいしかないから、国債を予算の穴埋めをするために新規で44兆円発行したのかなと思ってるんだけどあってるかな?でもこれ見ると国は特別会計っていうのがあって、ひっくるめると1年間で220兆円使ってるらしい。なんだか分からなくなてきた。国債の利払いとかも特別会計なのかしら。もうちょい調べないと全然わからないや。 なにしろ、金ないし、借金も限界やし、税金もっととらないとどうしようもないし、一番インパクトあるのは消費税やし、ということまでは分かったと言えるのだろうか?でも消費税増税しても、220兆円から考えるとまだインパクト少ないし、これから全体的にどうするのかは分からんし、ということだろうか?

2012年1月22日日曜日

cakePHP1.3でデータベース操作の研究(MySQL)(2)

今回はまだ調べてないデータベース操作を試してみます。試したいのは、テーブルを検索するときにフィールドの条件にリストを使うこと。リストを使う場合に部分一致が可能かどうかというのも試したい。あと、日付関連のデータをテーブルに格納する最適な方法と、格納されたテーブルの最適な検索等の方法を調べたい。

今回は、前回の英単語帳ではなく極めてシンプルなテーブル構成にしたい。テーブルは1つだけあり、名前はusersである。cakePHPのモデル名はよってUserになる。ちなみにモデルのファイル名は、user.phpである。フィールドは、id、name、have、wantの4フィールドを持つ。idはプライマリキーでauto_incrementにする。単なるテストなので、idは適当にmediumint(9)にしてある。nameはvarchar(50)で、haveとwantはtextにした。

今回のお試し用に作成した、test_controller.phpの全文は下記のとおり。

<?php 
class TestController extends AppController{
    public $name = 'test';
    public $uses = array('User');
 
    public function index(){
        $this->del();
        $this->put_user();
        $result = $this->search();
        $this->set('result',$result);
    }
 
    private function put_user(){
        $put_cnt = 2;
        for($i=0;$i<$put_cnt;$i++){
            if($i==0){
                $data = array('User' => array(
                    'name' => $i,
                    'have' => '1,2,3,4',
                    'want' => '5,6,7,8'
                ));
            }else{
                $data = array('User' => array(
                    'name' => $i,
                    'have' => '5',
                    'want' => '1'
                ));
            }
            $this->User->create();
            $this->User->save($data);
        }
    }
 
    private function del(){
        $user = $this->User->find('all',null);
        foreach($user as $u){
            $this->User->delete($u['User']['id']);
        }
    }
 
    private function search(){
        $user = $this->User->findByName('0');
        $list_h = $this->str_to_list($user['User']['have']);
        $list_w = $this->str_to_list($user['User']['want']);
 
        $params = array(
            'conditions' => array(
                'User.have' => $list_w,
                'User.want' => $list_h
        ));
        $user = $this->User->find('all',$params);
        return $user;
    }
 
    private function str_to_list($str){
        if($str == ''){
            return array();
        }else{
            return split(",", $str);
        }
    }
}
?>

2012年1月17日火曜日

cakePHP1.3でデータベース操作の研究(MySQL)

cakePHPのデータベース操作を研究します。データベースはMySQLです。cakePHPのバージョンは1.3を使ってます。cakePHPはバージョン毎に結構変化が色々あるようなので、cakePHP2.0との違いは早く調べておこうと思います。どんなデータをつくるかというと、分かり易いのがいいので英単語帳をイメージしてテーブルを作ってみます。

テーブル構成

テーブル構成は下記を想定してます。言葉遣いが間違っている可能性はありますが、iuwは、uwとiwを参照します。uwはuserとwordを参照します。cakePHPのJOINの構文を見ると、wordはuwを沢山持っていると言います。word hasmany uwとなります。逆にiuwはuwに属するといいます。iuw belongsTo uwとなります。



各テーブルの項目

各テーブルのフィールドは下記を想定しています。テスト機能つけたり色々一応想定して項目をつけました。まあ全部つくるか分かりませんがモチベーションが続くまで研究してみます。

usersid,name,image,discription
wordsid,word
imisid,imi
uwsid,user_id,word_id,count,seitouritsu,seigo
iwsid,imi_id,word_id,goodcnt,badcnt
iuwsid,uw_id,iw_id

2012年1月11日水曜日

トランザクション

トランザクションとは、
関連する複数の処理を一つの処理単位としてまとめたもの。金融機関のコンピュータシステムにおける入出金処理のように、一連の作業を全体として一つの処理として管理するために用いる。
GAEのデータベースは何でもトランザクションになっていたということだな。
トランザクションを使うと複数のクエリをまとめて1つの処理として扱うことができる。処理の途中でエラーになって処理を取り消したいような場合はROLLBACKをすることで変更内容を元に戻すことができる。
とみぞーノートに書いてある。 とみぞーノートを見ると、トランザクションを開始して、コミットするまでは、他の誰かがデータを参照してもトランザクション中の人が操作しているデータは見えないようだ。コミットするとトランザクションが終了するようだ。データを全部元に戻すには、ロールバックするらしい。単純な仕組みではある。確かinnoDBというのはトランザクションが使えるし、ロックが行単位の為、デッドロックになることは少ないとかなんかの雑誌に書いてあったな。

cakePHPでトランザクション

(※以下の情報は古かったのでcakePHP1.3の場合はここのやり方になります)

cakePHPでのトランザクションの使い方がこのページに書いてある。まずはapp/model/以下にあるapp_model.phpに以下を追加する必要があるらしい。

function begin()
{
    $db =& ConnectionManager::getDataSource($this->useDbConfig);
    $db->begin($this);
}
    
function commit()
{
    $db =& ConnectionManager::getDataSource($this->useDbConfig);
    $db->commit($this);
}
    
function rollback()
{
    $db =& ConnectionManager::getDataSource($this->useDbConfig);
    $db->rollback($this);
}

そして、実際に使う様がこのページに載っている。cakePHP1.3の場合だそうだ。

$this->Event->begin(); // トランザクションの開始
if($this->Event->save($this->data)){
    $this->Event->commit(); // コミット
    // 登録できたらリダイレクト
    $this->redirect('.');
}else{
    $this->Event->rollback(); // ロールバック
    $this->Session->setFlash('データの保存に失敗しました');
}

あとで試してみよう。

2012年1月9日月曜日

cakePHPプロジェクト作成する際のファイル構成

そんなページありませんといわれないように、cakePHPプロジェクトを作成する際には、下記ファイルとフォルダを全部コピペしましょう。
  • appフォルダ
  • cakeフォルダ
  • pluginsフォルダ
  • vendorsフォルダ
  • .gitignore
  • .htaccess
  • index.php

2012年1月2日月曜日

Css - あふれた文字を「...」に変換する

下記のように、divの中に、長い文字列があるが、divの幅を固定したい場合、下記のようなcss設定によってあふれた文字を「...」に変換することができる。これによって、div幅を固定しながら文字列が続くことも表現できる為、スマートである。

divの例

<div id="afuretamoji">ああああああああいいいいいいううううううううえええええええおおおおおおおお</div>

css設定例

div#afuretamoji{
 font-size:10px;
 color: #06c;
 background-color: #def;
 border:1px solid #589;
 width:100px;
 max-width:100px;
 height:70px;
 overflow:hidden;
 white-space:nowrap;
 text-overflow:ellipsis;
}
「max-width:100px;」でdivの最大幅を決めている。
「overflow:hidden;」で、あふれた文字を表示しないようにしている。
「white-space:nowrap;」で、複数行表示を禁止している。
「text-overflow:ellipsis;」で、あふれた場合に、「...」を表示するようにしている。

結果

ああああああああいいいいいいううううううううえええええええおおおおおおおお

jQuery - メニューをマウスオーバーしたら色変える

非常に簡単な話ですがメモ。大体jQueryも分かってきたのですが、cssの設定方法などもいくつかパターンがあるようで、あとbackground-colorという記載が通常のcssの表記法だと思うのですが、jQueryの場合は、backgroundColorだったりしてなんかややこしい。多分キャメル法で統一されたりしてるのかも。そうじゃなかったら一々確認するのめんどくさいですからね。 下記は、ul#menuの子供にliが沢山あって、liにはそれぞれ固有のidが割り振られている状態を想定しています。


$(function(){
 $('ul#menu li').mouseover(function(){menu_mouseover($(this).attr('id'));});
 $('ul#menu li').mouseout(function(){menu_mouseout($(this).attr('id'));});
});

function menu_mouseover(id){
 $('ul#menu li#'+id).css('backgroundColor','#0cf');
}

function menu_mouseout(id){
 $('ul#menu li#'+id).css('backgroundColor','#09c');
}

Javascript - GETリクエストパラメータを取得する

window.location.search.substringで取得できる。
取得したものは正規表現やsplitで必要なところを取り出す必要がある。
下記はidがキーのパラメータの値(数字)を取り出す様。
var query = window.location.search.substring(1); 
if(query.match(/id=(\d+)/)){
    alert(RegExp.$1);
}

2012年1月1日日曜日

ミクロ経済学

『この世で一番おもしろいミクロ経済学』を読んだ。超分かり易かった。ただ広く浅くで超概要しかわからない。

サンクコスト(sunk cost)

サンクコストは埋没費用ともよばれ、すでに投資済みのコストのことをいいます。あるいはすでにやってしまったことをいいます。既にやってしまっていることを理由に次の施策を決定することはおかしい。腹痛になったので、ビオフェルミン飲むか、トイレに行くかを検討した際に、腹痛なのでトイレに行くのではなく、ビオフェルミンを飲むことにする、というのはおかしい。

お金の価値

お金は時間に伴い価値がかわります。利子により銀行に預けてるだけでその価値は1年後に上がるわけですから、今すぐにA円もらうのがいいか、1年後にB円貰うのがよいかを検討するには、利子率をもとにB円の現在価値を求めて、それをA円と比較します。

利子率をrとし、将来のお金をXとし、経過年数をnとすれば、現在価値PVは、PV = X / (1 + r)^n となります。
r = 0.05;
X = 200000;
n = 10;
PV = X/Math.pow((1+r),n);
document.write(PV);


毎年X円を、n年間貰える場合、この現在価値PVは、
r = 0.05;
X = 10000;
n = 20;
PV = 0;
for(i=0;i<n;i++){
    PV += X/Math.pow((1+r),i+1);
}
document.write(PV);


毎年一定額を貰えるようなケースを年賦(ねんふ)というらしい。年賦金の現在価値の公式がある。 PV = X * (1 - (1 / (1 + n)^n)) / r が公式らしい。証明を今度探すか。
r = 0.05;
X = 10000;
n = 20;
PV = X*(1-(1/Math.pow(1+r,n)))/r;
document.write(PV);


なんと、永遠に毎年一定額貰える場合も、現在価値を簡単に求められる。

現在価値は下記のような式で表すことができる。
[式a] PV = X / (1 + r)^1 + X / (1 + r)^2 + X / (1 + r)^3 ..........
この式の両辺に、(1 + r)をかけると、下記のようになる。
[式b] PV(1 + r) = X + X / (1 + r)^1 + X / (1 + r)^2 + X / (1 + r)^3 ..........
[式b]から[式a]を引くと下記のようになる。
PV * r = X
よって、現在価値PVは、下記になる。
PV = X / r

その他

その他もろもろの超概要を説明してくれている。リスクの考え方、取引のメリット、取引の制約がなければ取引は双方の取引メリットがなくなるまで続くとか、ゲーム理論、パレート最適、パレート改善とか、オークションとか、需要曲線、供給曲線とか、税金とか。