子どもにプログラムを教える(予定)〜STEP0考察

No Comments

ゲームが好きな子どもだと、おそらく「プログラムしてみたい!」と思い始める子も多いと思う。
スムーズにプログラムを学習できるように導いてあげるにはどうすればいいのか、考えてみた。

この考えのゴールを表現すると
「自分の子どもにプログラムを教えてあげる機会を作りたい」

おそらく「プログラムはじめて!」の導入で有名なものといえばscratchだろう。
処理を指示内容が書かれたブロックを組み合わせて作り上げていくもので、Webブラウザからアクセスできて直感的にブロックを組み合わせて何かを作る体験をすることができるので、ロジックの理解には最適。
例えばscratchを使わせたとしてもこのツールを勝手にやらせるんじゃなくて、一緒に授業形式で見せながらやるほうがいいんだろうな、と思っている。
「勝手に読んで頑張ってね〜」はなかなか続かないからね・・・

さて、言語としてのプログラムを敷居低く覚えてもらうには何から着手すればいいのだろうか?

僕は、タイミングとしては四則演算がわかりはじめたタイミングがいいと思っている。
言語を教えようと思っても、英語(ローマ字)とか変数になるアルファベットとか、四則演算がわかっていたほうがイメージがつきやすいと考えているからだ。そうなると小4くらいからなのだろうか。

想定に基づき、分数の問題をとくためには?で考えてみた。が・・・、躓いてしまう。

■とりあえず解かせようと思う分数の問題を考えてみた。

\frac{1}{2} + \frac{2}{3} = \frac{3}{6} + \frac{4}{6} = \frac{7}{6} = 1\frac{1}{6}

小学生的には仮分数を帯分数に表現することが多いと思う。

■Pythonで解いてみた
(はじめてのプログラムにはPythonではどうだろうか、と考えてみた)

x = float(1)/2+float(2)/3
print x

Pythonだと整数が入っている変数を割り算すると小数点以下が切り捨てになるようなので値のどこかにfloatを設定するといいようです。
この時点でfloatの出現する説明が難しい。「おまじない」くらいか。

■解(Atom Runnerを使って計算してみました)

Atom Runner: sample.py
1.16666666667

あってるけど、あってない・・・こういう答えは求めてないだろう、きっと。
この問題の場合は、小数を分数で回答する処理を書かないといけなそう・・・と言うことで、まずは以下に着目して進めていこうと考えた。

  • 整数の足し算、引き算
  • 整数の掛け算

これなら、簡素な計算式で解が求められる。割り算のあまりを出せてあげると非常に便利だなーとも思ったが、あまりを出すためのMODを教えるのは難しいので整数にフォーカスして足し算・引き算・掛け算から教えていくことで慣れてもらおうと考えた。

次回以降、小学生用プログラムを教えるための解説台本を作成していくことにしようと思う。

■参考サイト
Scratch

https://scratch.mit.edu

https://scratch.mit.edu

wp-latex/数式をWordPressに記述する

No Comments

数式を記述したかったので、LaTeXを書けるプラグインを試してみました。

https://wordpress.org/plugins/wp-latex/

■サンプルにあったコード

e^{\i \pi} + 1 = 0
e^{\i \pi} + 1 = 0

■掛け算も楽々。

\frac{1}{5} \times \frac{2}{3}
\frac{1}{5} \times \frac{2}{3}[/latex]

RaspberryPiでCRON

No Comments

RaspberryPiを購入して半年くらいになりますが、「コレだ!」という活用法がなく部屋のオブジェと化していきそうでしたが、今回ようやく宅内WEBサーバとして動くことになりました。

RaspberryPi

RaspberryPi

 
XYLITOLキシリトールのガムと比較しても、むちゃくちゃ小さい!
僕のRaspberryPiは、固定IP化してSSHで接続しています。

crontabを設定。

sudo crontab -e

ssh_crontab

CRONTABの設定は以下のサイトが参考になりました。
Raspberrypiのcrontabが動かない時の解決策 -robonrcoの雑記帳

今回は、同じラズパイに設定したWEBサーバ(apacheを使用しました)に設置したスクリプトをwgetで動かす、という仕組み。
10分おきに実施していくことにします。

スクリプト側は、公開中のWEBサービスに設置したAPIを更新する仕組みにしているので、
これまで手動で実施する必要があったコンテンツ更新を劇的に早く更新することができるようになりました。めっちょ便利。

RaspberryPiを使用した自宅サーバは電源容量も気にする必要がないほど少ないので(ケータイの充電器で動いているので)、
365D24Hのサーバとしては優秀なのではないかと思われます。

■電源容量
5V/700mA~1200mA マイクロUSB使用。

僕のモデルはTypeBですが、今だとTypeB+が出ています。UKから輸入せずとも、国内でもほぼ同額で購入できるのも嬉しいですね。輸入に2週間以上かかったからなぁ・・・。

NetBeans IDE 8.0 でpython環境を作る

No Comments

RaspberryPiを手に入れたこともあって、Pythonに急に興味が出てきました。
Mac環境下になにやら専用のIDE入れたりするのは重くてしんどいなー、NetBeansでなんとかできないだろうか、と思いGoogleで検索していると、以下サイトが大変参考になりました。

おべんきょーぶろぐ:Netbeans7.3でpythonの環境を整えてみる

備忘録としてメモしておきます。
大変簡単でした!有益な情報提供感謝いたします!

■ツール->プラグイン を開く

スクリーンショット 2014-07-30 5.35.37

■「設定」タブに以下URLを追加

http://deadlock.netbeans.org/hudson/job/nbms-and-javadoc/lastStableBuild/artifact/nbbuild/nbms/updates.xml.gz

スクリーンショット 2014-07-30 5.37.12

■使用可能なプラグインに「Python」が追加される

スクリーンショット 2014-07-30 5.37.36

■PythonとJthonをインストール。
Pythonだけインストールしようとすると、依存しているのでJthonもインストールして!といわれます。

スクリーンショット 2014-07-30 5.37.54

■何やらもりもりインストールされる

スクリーンショット 2014-07-30 5.38.12

■インストール完了、再起動を促される。再起動。

スクリーンショット 2014-07-30 5.42.09

■無事表示されました!

スクリーンショット 2014-07-30 5.43.19

■無事Hello World!が表示。

スクリーンショット 2014-07-30 6.00.56

SkyDrive(OneDrive)APIを使用してファイルをアップロードする

No Comments

ファイルストレージサービスのAPI公開と言うと、ヤフー・オンラインストレージ「Yahoo!ボックス」がAPIを公開したり、DropBoxやMicrosoftのSkyDrive(新名称:OneDrive)などもAPI公開をしていたり、利用者や開発者にとって利便性のある機能を提供してくれています。これは本当に感謝。
自分自身でストレージエリアなどのハードウェアを持たずとも利用できる、ものすごく便利な世の中になりました。独り歩きしている「クラウド」という用語もAPIを利用することによってより実感できます。

ヤフー、オンラインストレージ「Yahoo!ボックス」のAPI公開 | マイナビニュース

■「SkyDrive」の名称を「OneDrive」に改称

米Microsoftは1月27日(現地時間)、クラウドストレージサービス「SkyDrive」の名称を「OneDrive」に改称すると発表した。具体的な日程はまだ不明だが、「すぐに」となっている。ユーザー側で必要な手続きはない。
 これは、Microsoftが英衛星放送のBSkyBが2011年から争っていた「SkyDrive」の商標をめぐる裁判で2013年8月に成立した和解の条件によるものとみられる。この和解条件は、MicrosoftがBSkyBの商標「SKY」を侵害しているとする判決を受け入れて控訴しない代わりに、BSkyBはMicrosoftがサービス名を変更する準備が整うまでSkyDriveという名称の利用を認めるというものだった。

Microsoft、「SkyDrive」を「OneDrive」に改称へ – ITmedia ニュース

その中で、MicrosoftのSkyDrive(新名称OneDrive)のAPI機能を利用してファイルを共有する機能を今回試してみました。
当初、DropboxのCoreAPIを利用しようとしましたが、「64bit版で使え!」みたいな警告が出たので、今回はSkyDriveで試しています。
どのAPIもOAuth→ファイルアップロードとなる概ねの流れは変わらないので、ライブラリを使わずとも自作でもいけないことはないような気がしますが、今回は少々面倒を避けてしまったので端折ります。

■参考サイト
第48回 SkyDrive API 概要(1):使ってみよう! Windows Live SDK/API|gihyo.jp … 技術評論社
現在サンプルがリンク切れでしたので、ソースコードをサンプル環境で試してみました。
OAuthで認証して、SkyDrive内のフォルダを閲覧、及びファイルのアップロードを行います。

<注意点>

  • “tmp/”フォルダに適切なアクセス権限を与えるべし
  • 先にSkyDrive/Developperにアプリ登録を進めておく必要があります
  • Scope設定は適切に
<?php
    define('CLIENT_ID',     'XXXXXXXXXXXXXX'); // Client ID と Client Secret を設定してください
    define('CLIENT_SECRET', 'XXXXXXXXXXXXXXXXXXXXXXXXXX'); //
    define('REDIRECT_URI',  'http%3A%2F%2Fwww.relaxsize.com%2Fsample%2Fms%2Fdemo.php'); // Redirect 先を設定してください

    // Access Token 処理
    if (isset($_GET['code']) && preg_match('/^[A-Fa-f0-9\-]+$/', $_GET['code'])) {
        // 認可画面からのリダイレクト

        // Access Token 取得
        $tokens = getTokens($_GET['code']);
        if (!$tokens) {
            $body = "Error";
        } else if (array_key_exists('error', $tokens)) {
            $body = htmlspecialchars($tokens['error']['error_description'], ENT_QUOTES, 'UTF-8');
        } else {
            $token = $tokens['access_token'];
            setcookie('AccessToken', $token, 0);
        }

    } else if (isset($_COOKIE['AccessToken'])) {
        $token = $_COOKIE['AccessToken'];
    }

    // ***.php?folder_id=xxx のようにクエリーに Folder オブジェクトの ID が
    // 指定されている場合、そのフォルダー内のアイテムを表示する
    if (isset($_GET['id']) && preg_match('/^[A-Za-z0-9!\.]+$/', $_GET['id'])) {
        $path = $_GET['id'] . '/files';
    } else {
        $path = 'me/skydrive/files';
    }

    // REST API 呼び出しと HTML 生成
    if ($token && !$body) {
        $body = createList($token, $path);
    }

    // サインインしていない場合は認可画面へのリンクを表示
    if (!$body) {
        $signInUri = 'https://oauth.live.com/authorize' .
            '?client_id=' . CLIENT_ID .
            '&scope=wl.signin%20wl.skydrive%20wl.skydrive_update' . // Scope に wl.skydrive を指定
            '&response_type=code' .
            '&display=popup' .
            '&locale=ja' .
            '&redirect_uri=' . REDIRECT_URI;
    }

    if (is_uploaded_file($_FILES["upfile"]["tmp_name"])) {
    // 一時保存ディレクトリ
    $dir = "tmp/";

    // ファイル名を新しく付ける
    $tmp = $_FILES["upfile"]["name"];
    $file = uniqid('', true) . substr($tmp, strrpos($tmp, '.'));

    if (move_uploaded_file($_FILES["upfile"]["tmp_name"], $dir . $file)) {
    // アップロードされたファイルを一時保存先へ移動し,成功した場合
    // SkyDrive へアップロード
    $res = upload_to_skydrive($token, $dir . $file);
    if ($res === false) {
    $msg = "Error";
    } else if (array_key_exists('error', $res)) {
    // エラーメッセージが返ってきた場合
    $msg = htmlspecialchars($res['error']['message'], ENT_QUOTES, 'UTF-8');
    } else {
    // アップロード成功が成功した場合
    $msg = 'アップロード完了: <a href="' . $res['source'] . '">' . htmlspecialchars($file, ENT_QUOTES, 'UTF-8') . '</a>';
    }

    // 一時ファイル削除
    @unlink($dir . $file);
    } else {
    $msg = 'アップロード失敗';
    }

    }

    function upload_to_skydrive($token, $file) {
    $url = 'https://apis.live.net/v5.0/me/skydrive/files';
    var_dump(filesize(realpath($file)));
    $data = array("file" => "@" . $file);
    $ch = curl_init();

    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array("Authorization: Bearer $token"));
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

    // (サーバー証明書を検証しない)
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);

    // エラーの場合 false を返す
    $res = curl_exec($ch);
    if ($no = curl_errno($ch)) {
    echo $no;
    return false;
    }
    curl_close($ch);
    return json_decode($res, true);
    }

    // REST API 呼出しと HTML 生成
    function createList($token, $path) {
        $res = callRestApi($token, $path);
        if ($res === false) {
            return "Error";
        } else if (array_key_exists('error', $res)) {
            return htmlspecialchars($res['error']['message'], ENT_QUOTES, 'UTF-8');
        } else {
            $body = '<ul>';
            foreach ($res['data'] as $val) {
                $name = htmlspecialchars($val['name'], ENT_QUOTES, 'UTF-8');
                if ($val['type'] === 'folder' || $val['type'] === 'album') {
                    $body .= '<li><a href="?id=' . $val['id'] . '">' . $name . '</a></li>';
                } else {
                    $body .= '<li>' . $name . '</li>';
                }
            }
            $body .= '</ul>';
            return $body;
        }
    }

    // 認可コードからアクエストークン取得
    function getTokens($code) {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL,
            'https://oauth.live.com/token' .
            '?client_id=' . CLIENT_ID .
            '&redirect_uri=' . REDIRECT_URI .
            '&client_secret=' . CLIENT_SECRET .
            '&code=' . $code .
            '&grant_type=authorization_code');
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

        // (サーバー証明書を検証しない)
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);

        // エラーの場合 false を返す
        $res = curl_exec($ch);
        if ($no = curl_errno($ch)) {
            return false;
        }
        curl_close($ch);
        return json_decode($res, true);
    }

    // REST API の呼び出し (GET メソッドのみ 対応)
    function callRestApi($token, $path) {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL,
            'https://apis.live.net/v5.0/' .
            $path .
            '?access_token=' . $token);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HTTPGET, true);

        // (サーバー証明書を検証しない)
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);

        // エラーの場合 false を返す
        $res = curl_exec($ch);
        if ($no = curl_errno($ch)) {
            return false;
        }
        curl_close($ch);
        return json_decode($res, true);
    }

?>
<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="utf-8" />
        <title>SkyDrive Sample</title>
    </head>
    <body>
        <?php
        if ($signInUri) {
        ?>
        <div><a href="<?php echo $signInUri; ?>">サインイン</a></div>
        <?php
        } else {
            echo $body;
        }
        ?>


        <form action="demo.php" method="POST" enctype="multipart/form-data">
  <div>
    SkyDrive へファイルをアップロードします。<br />
    <input type="file" name="upfile" size="30" />
      <input type="submit" value="アップロード" />
  </div>
</form>
<div class="message"><?php echo $msg; ?></div>
    </body>
</html>

このコラム、すごく参考になりました。
著者の松江さん、この場を借りて御礼申し上げます。

■実行サンプル
SkyDrive Sample | relaxsize

cakephpでCSVダウンロードさせたい

No Comments

配列に格納された情報をCSV形式でダウンロードをさせたいケースありますよね。

今回はcakePHPを使って、以下の方法で実装しました。
あるControllerの1つのアクションで実行することを想定しています。

function csv_download(){
          $this->autoRender = false; //Viewは使用しない
          Configure::write('debug', 0); //デバッグコードを出さない
          $csv_file = sprintf("csv_%s.csv", date("Ymd-hi")); 
          header ("Content-disposition: attachment; filename=" . $csv_file);
          header ("Content-type: application/octet-stream; name=" . $csv_file);
          $buf = array(
                              mb_convert_encoding("注文番号", "SJIS", "UTF-8"),
                              mb_convert_encoding("注文日", "SJIS", "UTF-8"),
                              mb_convert_encoding("金額"."\r\n", "SJIS", "UTF-8")
          );
          $out = implode(",",$buf);
          print($out);
          foreach($data as $list){
                  $buf = array(
                                   $list['id'],
                                   mb_convert_encoding($list['date'], "SJIS", "UTF-8"),
                                   mb_convert_encoding($list['price'], "SJIS", "UTF-8"),
                 );
                 $out = '"'.implode('","',$buf).'"'."\r\n";
                 print($out);
          }
}
mb_convert_encoding($list['date'], "SJIS", "UTF-8"),

mb_convert_encodingは、CSVファイルをMicrosoft Excelで開いて編集するときにUTF-8だと文字化けしてしまいますので、あらかじめ文字コードをSJISに変換しておきます。

$out = '"'.implode('","',$buf).'"'."\r\n";

PHP: implode – Manual

implode関数は配列を文字列により連結してくれる便利な関数なのですが、たとえば入力された情報を出力する場合、カンマ「,」を入れたデータを入力されてしまうと、Excel等で開いた際に1セルずれてしまうことがあります。その状況を回避するためにあらかじめダブルコーテーションで囲ってしまえ!というおまじないです。

array(
“hoge”,
“ho,ge”,
“hoge”
)

こんな時にimplode関数を使用すると・・・

“hoge”,”ho,ge”,”hoge”

と出力されます。

指定のactionだけbeforeFilterで処理させたくない場合

No Comments

cakePHPではController内の各アクションを実行する前に、beforeFilter()を設定している場合、これが先に実行されます。
Controller内の特定アクションは実行させない、などの処理はbeforeFilter内に記載しておくとよさそうです。

More

サーバー変数、$_SERVERで知る環境情報

No Comments

「サーバー自身のIPアドレスを知る」など、phpでサーバーに関する環境変数は、$_SERVER変数を利用することで確認することができます。

■現在のスクリプトが実行されているサーバーのIPアドレスを知りたい

echo $_SERVER['SERVER_ADDR'];

■現在の該当ページにアクセスしているユーザーのIPアドレスを知りたい

echo $_SERVER['REMOTE_ADDR'];

詳しくはドキュメントも公開されているのでこちらも参考に。
PHP: $_SERVER – Manual

僕は何を思ったか、表示されたIPがあまりにきれいすぎて信用できなかったので、2つのファイルを作り、お互いにアクセスさせあうという暴挙に出ます。

main.php

<?php
var_dump(file_get_contents("http://www.hoge.com/sub.php"));
?>

sub.php

<?php
var_dump($_SERVER['REMOTE_ADDR']);//アクセスされたユーザIPを表示する。
?>

作成したファイルをWEBサーバにアップロードしてアクセス・・・

http://www.hoge.com/main.php

を実行すると、main.php→sub.phpにアクセスしたときのユーザIP(すなわち自分自身のIP)を取得。
結果的に同じIPが取得できたのでよかったのですが。何がしたかったのかと言われると「信用ならない」という若干理解不能な行動でしたが・・・。

cakePHPだと、こういうのも用意されていますが、
「危険」だの「非推奨」だの出てきますので、割愛します。

$this->RequestHandler->getClientIP();

ドキュメントからも消えているので、非推奨なんでしょう、と勝手に解釈しました。
リクエストハンドリング — CakePHP Cookbook 2.x ドキュメント

cake2.XのPaginator

No Comments

使っていくうちに「けっこう便利だなー」と思うのが、cake2.X系のPaginator。ページ付けを素早く作れるのが特徴。

セット方法もカンタンな宣言で実装できるので、非常に便利。

■コントローラー側

public $components = array('Paginator');
//~~~
$this->Paginator->settings = array(
'fields' => null,
'limit' => $limit ,
'conditions' => $conditions,
'order' => array(
'Data.id' => 'desc'
)
);
$result_data = $this->Paginator->paginate('Data');

 $this->set("list",$result_data);

■View側
テーブルの上部にはDivで囲んだ件数などが配置されることを想定しています。
表示されるリストはテーブルで表示していくサンプルです。

<div class="pagenatorHeader">
<?php
echo $this->Paginator->counter(
'{:start}-{:end}&nbsp;/&nbsp;{:count}'
);
?>&nbsp;
<?php echo $this->Paginator->prev(__('前'), array('tag' => 'p','class' => 'pagenator'));?>
<?php echo $this->Paginator->next(__('次'), array('tag' => 'p','class' => 'pagenator'));?>
</div>

<table>
<thead>
<tr>
<th><?php echo $this->Paginator->sort('created', 'ご注文日', array('model' => 'Data'));?></th>
<th><?php echo $this->Paginator->sort('id', 'ID', array('model' => 'Data'));?></th>
<th><?php echo $this->Paginator->sort('listdata', 'リスト', array('model' => 'Data'));?></th>
</tr>
</thead>
<?php foreach($list as $value):?>
<tr>
<td><?php echo date("Y/m/d H:i",strtotime($value['Data']['created']));?></td>
<td><?php echo $value['Data']['id'];?></td>
<td><?php echo $value['Data']['listdata'];?></td>
</tr>
<?php endforeach;?>
</table>

いくつかのおまじないだけで、ページ繰りができてしまうので、けっこう便利です。
CakePHPは便利な反面、たまに何かを犠牲にしてしまっているときがあるので、そこだけ注意が必要です。特にアソシエーションをたくさん張っているときなど思いがけずデータが重くなることがあり、レスポンスの時間には気を配ったほうがよさそうです。

関連ページ:キーワード数が10万語を突破したのでpaginateするようにしてみた

名曲発掘:砂原良徳の「The Telephone Call」

No Comments

砂原良徳と言えば、電気グルーヴの「まりん」のイメージが強いのだけれど、系統としてクラフトワークやYMOの影響は強く受けている。
僕の感覚としては結構ポップなものを聞かせてくれる、イメージです。

砂原良徳が影響を受けているKraftwerkとは?

More

Older Entries