drkcore

2012/01/06 06:00:46

moin2の16の特徴の中から気になったもの

MoinMoin 2.0のビッグニュースに16個あげられていたんだが気になったものを

Sphinx-based docs

Sphinxベースのドキュメントになって読みやすい。でもmake pdflatexはこけた

Storage Layers: stores, backends, middlewares

ストレージにファイルだけではなくsqlalchemyで使えるRDBやKyoto Cabinetなんかも使える。

Tree based transformations

これに惹かれた

input -> converter -> DOM tree -> converter -> output

という変換経路をたどるのでフォーマットの変換ができる。つまりwikiのコンテンツを好きなフォーマットで取り出せるので、特にReSTで取り出してSphinxにもっていけるようになるのでデータの再利用がしやすそう。

GUI editor update and different approach

ckeditorが使える。WYSIWYGはイントラのサービスでは必須。

Themeing with Jinja2 templating engine

Flask-Themesを使っているので、自分用のテーマを作ってみる予定

Packaging

virtualenvのおかげで、環境を汚さずすむので便利。あとquickinstallスクリプトがインストールの面倒をほぼすべて見てくれるので超楽チン

2012/01/04 21:29:48

moin2はFlaskベース

コミュニティーベースのコラボレーションツールを探している。

個人的にはSphinxのWeb Supportがいいんじゃないかと思っているんだが、うちのITリテラシーを考えるとちょっと無理すぎるかなぁと断念した。

論文が電子化されているけどpdfは単なる紙の模倣でつまんないがHTML化されてパラグラフ単位とかfigure単位でコメントしたり編集できたりすれば、レビューも作りやすいし、実験はいいけど解釈はクズみたいなトータルでの判断に悩むような論文も切り取れるし、レターみたいな内容が薄いんだか知識を入れ込めなかったんだか分からないような中途半端な文章も好き勝手に補足できる。つまり真のマッシュアップが待っているわけです。

単語に分解して相関を取るとかそういうのとは逆方向に、文脈をつなぎあわせてより抽象とか本質を目指すようなことがやりやすくなるわけですな。正直論文の最後に載っているリファレンスは、島根の場所が知りたいのに日本のあたりを指してるわけで残念な仕組みだよなと思ってるのでもう少し、位置情報を高精度化すれば面白いのにとずっと思っているんだけどなかなかそうはならないのはみんな著者のストーリーを読むのが好きなのかね?他人事なのでどうでもいいけど。

で、音でいうところのサンプリングというか、パラグラフ単位でコメントを入れられる仕組みっていうのは未来があると思っている、RWHで未来を見たというかちょっと感動した。まぁ、そういうのをイントラに構築できたら良かったんだけど現状は難しそうだ(ヨーヨーヨー)。

かといってwikiはなぁ、、、Sphinxっぽく文書出力できる良い感じのwikiが欲しいなぁと思いながら調べていたらmoin2がFlaskベースでフォーマットの変換がしっかりしてそう。ReSTでもOKなのでSphinx->pdfってのもやりやすそう。

moin2

あとは知っているフレームワークなので手を入れやすそうってのもある。化学構造のエディタとか組み込まないといけないし。それからmoin2のソースコード読むのも勉強になるし、モチベーション的にもよろしいです。

まぁそんな感じで今年は、wikiベースの創薬用コラボレーションツールを作ってみるかなと。

2011/11/11 06:45:57

Flaskでhamlish-jinjaを使う

Express+Jadeで幾つか書いていたらJadeの読みやすさに慣れてしまった。

FlaskでもHamlっぽい記法を使いたいなぁとググッてみたらhaml and flaskというエントリをみつけたので、この通りに入れてみた。

-extends "layout.html"

-block title
  Page Not Found

-block body
  %h1 << Page Not Found
  %p
    %a href="{{ url_for('show_entries') }}" << go somewhere nice

  %p << or find by tag
  %div.tags
  %script type="text/javascript"
    |$.getJSON('{{ url_for('show_jsontags') }}', null, 
    |  function(json){
    |    for (i in json.tags.sort()){
    |      $('div.tags').append("<a href=\"/tag/" + json.tags[i] + "\">" + json.tags[i] + "</a> ");
    |    }
    |  }
    |);

かなり読みやすくなった。入れ子をインデントで表現するのでPythonistaにはありがたいですね。ちなみにこっちがもとのjinjaのテンプレート。

{% extends "layout.html" %}
{% block title %}Page Not Found{% endblock %}
{% block body %}
  <h1>Page Not Found</h1>
  <p><a href="{{ url_for('show_entries') }}">go somewhere nice</a></p>
  <h1>or find by tag</h1>
  <div class=tags></div>
<script type="text/javascript">
$.getJSON('{{ url_for('show_jsontags') }}', null, 
function(json){
  for (i in json.tags.sort()){
   $('div.tags').append("<a href=\"/tag/" + json.tags[i] + "\">" + json.tags[i] + "</a> ");
  }
}
);
</script>
{% endblock %}

pipとかeasy_installで0.1を入れるとdiv#idとかdiv.classという記法が使えないので、GitHubの最新版を入れたほうがよいです。


ところで、HTML5においてセマンティクスが重視されると、デザインまわりはCSSに集約されていきHTMLタグとデザインっていうのは分離されていくと思うんですね(rdfとか昔っからあるし)。

セマンティクスってデザイナーというよりはプログラマー側が考えることだろうから、マークアップエンジニアとか呼ばれているヒト達はCSSエンジニアとかそういう名称になっていくの?

よくわからんので、今度誰かに聞いてみよう

ProductName HTML5&CSS3実践入門 最新Web標準を使いこなす (The Pragmatic Programmers)
ブライアンP.ホーガン
インプレスジャパン / 2940円 ( 2011-07-08 )


静岡(東部のあたり)ではHTML5の入門書の読書会をしています(宣伝)

2011/11/09 18:45:46

Flask-Cacheを使ってみた

自作のブログシステムのなかにデータベースに頻繁にアクセスしすぎて困るAPIがあるので、Flask-Cacheを使ってキャッシュするようにした。

設定を読ませてからcacheの設定をしないといけない(まぁ当たり前か)のだけどapp.config.from_objectで読ませる前にCacheしてたらキャッシュが効かなくてちょっとはまった。

CACHE_TYPE = 'simple'

app = Flask(__name__)
app.config.from_object(__name__)
cache = Cache(app) # 設定読ませたあとに

ソースは読んでたらキャッシュのタイプはwerkzeugに任せているらしいので、そっちのドキュメントを読めば大丈夫な感じですね。

2011/08/17 20:18:44

blohg - Mercurial+Flaskのブログシステム

blohgってのが面白そうだったのでコードを読みつつ手元のmacbookにインストールして触ってみた。

sudo easy_install-2.7 blohg
mkdir myblohg
cd myblohg/
blohg initrepo
hg commit -Am 'initial commit'
blohg runserver

エントリを追加する場合にはcontent/post/にあたらしくrstファイルを追加してaddしてコミットする。

blohg

で、コード読んでたら

from werkzeug.contrib.atom import AtomFeed, FeedEntry

ってあって、werkzeugにフィード生成用の仕組みが用意されていることを知った。自分のブログ(Flask製)ではfeedgeneratorを使っているのだけど、こっちでもいいかなと思った。

おまけ

fujinismもblohgベースに変えようかなぁ

2011/07/27 20:02:13

FlaskでDrag and Drop APIとXHR2で画像をポストする

HTMLガイドブックはphpなのでFlaskでやってみた。この本は良書ですね、オススメです(最後のほうにNode.jsのサンプルも載ってるし)。

ProductName 徹底解説 HTML5 APIガイドブック コミュニケーション系API編
小松 健作
秀和システム / 2730円 ( 2010-12 )


青い囲みの中にドラッグドロップするとアップロードされるが、ドラッグドロップAPIのためにスペースを用意するっていうのはなんかいまいちだなぁ。もうちょっと洗練されたドラッグドロップのインターフェースはないものかね。

file_upload

ディレクトリ構成

$ tree
.
├── static
│   └── uploads
├── templates
│   └── index.html
└── uploader.py

サーバー側

from flask import Flask, request, url_for, render_template, make_response
import os

DEBUG = True
SECRET_KEY = 'development key'
UPLOAD_FOLDER = 'static/uploads'
ALLOWED_EXTENSIONS = set(['txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'])

app = Flask(__name__)
app.config.from_object(__name__)

def allowed_file(filename):
    return '.' in filename and \
           filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS

@app.route('/')
def show_index():
    return render_template('index.html')

@app.route('/upload', methods=['POST'])
def do_upload():
    file = request.files['xhr2upload']
    if file and allowed_file(file.filename):
        filename = file.filename
        file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
    response = make_response(url_for('static', filename='uploads/'+filename, _external=True))
    response.headers['Access-Control-Allow-Origin'] = '*'
    return response

if __name__ == '__main__':
    app.run()

クライアント側(templates/index.html)

<!doctype html>
<html>
  <head>
  <meta charset="utf-8">
  <title>File Uploader</title>
  <script src="//ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.js"></script>
  <style>
  #dropbox {
    width: 500px;
    height: 200px;
    border: 1px solid blue;
    background: #eee;
  }
  #urllists {
    margin-top: 30px;
    width: 400px;
    height: 300px;
    overflow: auto;
    floar: left;
    boader: 1px solid blue;
  }
  #currentimage {
    margin-left: 420px;
    margin-top: 30px;
  }
  </style>
  </head>
<body>
<h1>File Uploader</h1>
<div id=dropbox></div>
<div id=urllists></div>
<div id=currentimage></div>
<script>
var DnDUploader = function (base_id) {
  if(typeof(base_id) != "string" || base_id.length == 0 || document.getElementById(base_id) == null)
    return false;

  var __body = document.getElementsByTagName('body')[0];
  var parent = document.getElementById(base_id);
  __body.addEventListener("drop", function(e){e.stopPropagation();e.preventDefault();}, false);
  __body.addEventListener("dragenter", function(e){e.stopPropagation();e.preventDefault();}, false);
  __body.addEventListener("dragover", function(e){e.stopPropagation();e.preventDefault();}, false);
  parent.addEventListener("drop", function(e){e.stopPropagation();e.preventDefault();_handleDrop(e);}, false);
  parent.addEventListener("dragenter", function(e){e.stopPropagation();e.preventDefault();}, false);
  parent.addEventListener("dragover", function(e){e.stopPropagation();e.preventDefault();}, false);

  var _handleDrop = function(e) {
    var x = e.layerX, y = e.layerY;
    var dt = e.dataTransfer, files = dt.files, count = files.length;

    var types = [
            'image/png',
            'image/gif',
            'image/jpeg'
    ];

    for (var i=0; i < count; i++) {
    if (files[i].fileSize < 1048576) {
        var file = files[i];
        var type = file.type;
        var filename = file.fileName;

        if($.inArray(file.type, types) == -1) {
        alert(file.type + 'はサポート外です。');
        continue;
        }

        var reader = new FileReader();
        reader.readAsDataURL(file);
        _upload(file);

        reader.onload = function(e) {
        var fileData = e.target.result;
        _drawImage(x, y, fileData);
        }
    } else {
        alert('ファイルが大きすぎます');
    }
    }
  };

    var _drawImage = function(x, y, file) {
    var imgElement = document.createElement('img');
    imgElement.src = file;
    imgElement.style.position = 'absolute';
    imgElement.style.display = 'none';
    parent.appendChild(imgElement);

    setTimeout(function(e) {
        var o_w = imgElement.width;
        var o_h = imgElement.height;
        imgElement.width = o_w > 100 ? 100 : o_w;
        imgElement.height = parseInt( o_h * imgElement.width / o_w);

        var w = imgElement.width;
        var h = imgElement.height;
        imgElement.style.left = (x-w / 2)+'px';
        imgElement.style.top = (y-h / 2)+'px';
        imgElement.style.display = 'block';
    },1);
    };

    var _upload = function(file) {
    var fd = new FormData();
    fd.append("xhr2upload", file);
    var xhr = new XMLHttpRequest()
    xhr.open("POST", "http://www.kzfmix.com:5000/upload");
    xhr.send(fd);

    xhr.onload = function(e) {
        var url = e.target.responseText;
        $('#urllists').prepend('<p><a href="' + url + '">'+url+'</a></p>');
        $('#currentimage').html('<img src="' +url+ '">');
    }
    }
}

DnDUploader('dropbox');
</script>
</body>
</html>

2011/07/26 20:09:09

FlaskでXHR2を試す

XHR2はJSONPと比べてどんなメリットがあるんだろうか?

JSONPで行っている事は、外部のJavascriptを読み込んでいることに他ならず、不用意に利用することは大変危険な行為です。

ProductName 徹底解説 HTML5 APIガイドブック コミュニケーション系API編
小松 健作
秀和システム / 2730円 ( 2010-12 )


まぁ、JSONPはハック色が強いですからね。

というわけで、クロスドメイン間で通信ができるというXHR2を試してみた。

サーバーのコード

ログ見てわかったんだがPOSTメソッドの時はOPTIONSで問い合わせないっぽい。なのでコメントアウトしても動いた。Access-Control-Allow-Originは必須で、コレがないと動かない。

from flask import Flask, make_response, request

app = Flask(__name__)
app.debug = True

#@app.route('/events', methods=['OPTIONS'])
#def view_events():
#   response = make_response()
#   response.headers['Access-Control-Allow-Origin'] = '*'
#   return response

@app.route('/events', methods=['POST'])
def show_events():
   u = request.form['username']
   p = request.form['password']
   response = make_response("user: %s, pass: %s" % (u, p))
   response.headers['Access-Control-Allow-Origin'] = '*'
   return response

if __name__ == '__main__':
   app.run(host='www.kzfmix.com')

クライアントのコード

普通にXMLHttpRequestをnewしてPOSTメソッドでsendする

<!DOCTYPE html>
<html>
<head>
<title>xhr2 test</title>
</head>
<body>
<script>
document.addEventListener("DOMContentLoaded", function(){
 var formData = new FormData();
 formData.append('username', 'myuser');
 formData.append('password', 'mypass');

 var xhr = new XMLHttpRequest();
 xhr.open("POST", "http://www.kzfmix.com:5000/events");
 xhr.send(formData);
 xhr.onerror = function(e) {
   console.log("ERROR");
   console.log(e);
 }

 xhr.onload = function(e) {
   console.log("LOAD");
   console.log(e);
   console.log(xhr.status);
   console.log(xhr.statusText);
   console.log(xhr.responseText);
   alert(xhr.responseText);
 }
}, false);
</script>
</body>
</html>

実行結果

xhr2_test

異なるドメイン(オリジン)間でデータの受け渡しが出来てる

$ python xhr2.py 
 * Running on http://www.kzfmix.com:5000/
 * Restarting with reloader...
124.41.xx.xxx - - [26/Jul/2011 19:23:51] "POST /events HTTP/1.1" 200 -
124.41.xx.xxx - - [26/Jul/2011 19:24:04] "POST /events HTTP/1.1" 200 -

2011/07/19 10:28:12

本譲ります的なサイトをGAE+Flaskで作ってみた

昨日作ったものだけど、成果発表をしていないのでこのエントリでしてみたいと思う。

こんな感じのサイトで、認証はTwitterのOAuth、本の管理はbooklogの本棚APIを使ってます。

譲れる本の一覧を表示して、欲しい本があったらreplyしてもらって、手渡しで渡すと。

そんだけ。

まぁ、譲るぜオーラを漂わせるわけではなくて、あくまでイベントのついでに、物々交換的な機能があれば便利なんじゃないかと常々考えてたのでShizuDevつくる会で作ってみたと。

それからGAEも触りたかったしね。

xooqってどっからつけたかというと、はじめに本の交換だからbooxって名づけようと思っていたのだけど、やはりいありがちすぎて既に存在していたので、ひっくり返したらまぁOKだったという(一意性を担保するにはひっくり返せという教えが役に立った)。

前回ちょっと書いて放置してたら半年ほど経過してしまったが、今回みんなで集まったおかげで集中して作業できてよかった。

以下、自分で考えたオススメポイント。

住所バレしない

郵送だと住所書かないといけないのでちょっと嫌ですよね。なので会って渡す、コレ基本。イベントに行くついでにちょっと渡してくるというお手軽感。

Androidのbooklogアプリ便利

読み終わったらAndroidのアプリでスキャンして既読管理しているので、ついでにもう読まないであろう本は「交換してもいい本」カテゴリに入れてしまう、そんだけでOK。パソコン開いて作業しなくてよいので楽ちんですね。

ATNDでどのイベントに参加するかわかるようになってる

とりあえず表示するようにしただけ。やっつけ仕事っぽいがそのうちどうにかする。

2011/07/03 21:16:59

Flask + GAE + Twitter OAuth

18日にやろっかなーと思っていたのだけど、今日時間があったのでOAuth認証を実装してみた。

ProductName プログラミング Google App Engine
Dan Sanderson
オライリージャパン / 3570円 ( 2011-01-24 )


というわけで、18日はなにしようかなぁ。jQMobileで血圧管理システムをつくってみようか、中断してる文献管理システムの構築再開しようか。

2011/06/14 21:27:36

RESTfulでお悩み中

Flaskにはjsonifyって関数があるから、いま作ってるサービスをRESTにしようと思ったんだけど細かいところでうまい実装が思いつかなかったり、そもそもきちんと理解してないことも発覚してRESTful Webサービスを読み直している。

ProductName RESTful Webサービス
Leonard Richardson
オライリー・ジャパン / 3990円 ( 2007-12-21 )


とりあえずJSON用のRESTを実装して、クライアントとしてのwebはそっちをアクセスするようにしたほうがいいのかなぁと。

ただ、そうするとURIがぶつかるからJSON用のAPIのほうは/v1/をpathの先頭につけたけど。

あと、FlaskのjsonifyってSqlalchemyの結果をそのまま渡すと駄目で、dictionaryを組み立てて渡さないとあかんのね。これがちょっとめんどくさい

7章のブックマークサービスをRoRで実装する章をFlaskで再実装するという修行をしないとあかんのかなぁ、、、