誕生日から星座を取得するライブラリ
誕生日から星座を取得するライブラリを作った。
Dateオブジェクトを渡して {id: 1, name: 'やぎ座'} の形式のオブジェクトを返すfunction。ついでにJSFiddleのiframe埋め込みを使って貼り付けてみた。
JSFiddleでmochaを使う設定はこちらのテンプレートサイトをベースにした。 http://azu.github.com/js-test-fiddle/
Ruby on Railsへの道
ようやくたどり着いた。。行き着くべき場所に。。
自分が今までWebアプリケーション開発で利用してきたフレームワークを順に並べてみると以下のようになる。
- SAStruts(Java)
- Slim3(Java-Google App Engine)
- CodeIgniter(PHP)
- Express(JavaScript-Node.js)
あまり気に入らなかったものはこの中に含めていない(Springとか)。
実際にこれらを使ってみた感想は、どれもシンプルで開発効率が高い素晴らしいフレームワークだということ。開発を楽しくさせてくれるフレームワークだと思った。
これらのフレームワークには共通する事柄がある。
それは、多かれ少なかれRuby on Rails の影響を受けているということ。
この流れだとどう考えても次に使うフレームワークはRuby on Railsしかあり得ない。 どう考えても。
ということで次はRuby on Rails を使う仕事をする。 なんとしても。
GitベースのWiki gollumを使い始めた
よさげなWikiを求めて
技術Tipsとかをまとめておきたいけど公開まではしたくない..みたいなプライベートWikiが欲しくてよさげなものを探してみた。
dokuwikiとかも試してみたけど、デザインがシンプルなgollumがよさげだったのでこれにした。Githubっぽいし。
データベース等は使わずにGitに保存され管理される仕組みらしい。
環境
CentOS 5.9 (さくらVPS)
Webサーバ: nginx 1.2.3
インストール
ruby-gemでインストール可能
# gem install gollum
この時rubyのバージョンが1.8.7以上でないとエラーになる(1.8.5だとエラーになった)
リポジトリの作成
保存用のgitリポジトリを作成
# git init /var/git/wiki/gollumn.git
起動
ベースとなるgitリポジトリを指定して実行する。
$ gollum /var/git/wiki/gollum.git
でOK。
ポート番号はデフォルトでは4567になる
URLのベースパスを変更したい場合は--base-pathオプションを指定する
nginxの設定
認証機能が特に無いのでBasic認証をかけておく
パスワードを作成
# htpasswd -c /var/www/.htpasswd user1
nginx.confの設定
server{ listen 80; server_name <hostname>; location / { auth_basic "Admin control panel"; auth_basic_user_file "/var/www/.htpasswd"; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_pass http://localhost:4567; } }
これで設定完了!
実際に使ってみて
デザインがシンプルでかつ使いやすい!
編集ページは左側がエディタになって右側がプレビューになってる。 markdown記法が使える。
とりあえずしばらく使ってみる
2,3日使ってみたところ、いい感じ。とりあえずどんどんストックしていくつもり。
参考にしたサイト
Redisのメモリ使用量がmaxを超えた場合の挙動
Redisのメモリ使用量がmaxを超えた場合の挙動について検証してみた。
環境: version: 2.4.16
Redisではタイムアウト時間を設定したキーは時間を超えると自動で削除され、タイムアウト時間を設定しないと永続的に保存される。
また、メモリの空き領域がなくなった場合、期限のあるものから削除されていく(デフォルトの設定の場合)。
注意すべき点は、期限が設定されていないキーは削除対象にならないということである。
実際にその挙動を検証してみた。
まず、検証しやすいようにメモリの使用可能な量を以下の値に設定しておく(redis.conf)
#新たにキーを保存した際にmaxmemoryエラーにならないぎりぎりの値 maxmemory 910KB
maxmemory-policy は 以下を設定
#LRUアルゴリズムを使用して期限切れになったセットのキーを削除 maxmemory-policy volatile-lru
この状態で、メモリがMaxを超えるまでキーを追加していってみる。※期限は設定せずに保存
redis 127.0.0.1:6379> set a 111111111111111111111111 OK redis 127.0.0.1:6379> set b 111111111111111111111111 OK redis 127.0.0.1:6379> set c 111111111111111111111111 OK redis 127.0.0.1:6379> set d 111111111111111111111111 OK redis 127.0.0.1:6379> set e 111111111111111111111111 OK redis 127.0.0.1:6379> set f 111111111111111111111111 OK redis 127.0.0.1:6379> set g 111111111111111111111111 (error) ERR command not allowed when used memory > 'maxmemory'
7つ目のキーを追加したところでmaxmemoryを超えてエラーになった。
maxmemory-policy : volatile-lru の場合、メモリのMAXを超えた場合は期限切れのものから削除されるが、この場合期限切れのキーが一つも存在しないためエラーになった。
maxmemory-policy がvolatile-ttl, volatile-lru, volatile-random の場合も挙動は同じだった。
maxmemory-policy をallkeys-lru (どれかのキーをランダムに削除) にしてみると
redis 127.0.0.1:6379> set g 111111111111111111111111 OK
追加できた。
キーの一覧を確認すると "a" が消えていた
redis 127.0.0.1:6379> keys * 1) "c" 2) "d" 3) "e" 4) "f" 5) "g" 6) "b"
allkeys-lruの場合は期限が設定されていなくとも自動で削除されることが確認できた。
LRUアルゴリズムのため、最も使われてないものが削除対象になる。
allkeys-randomの場合も同様
redis 127.0.0.1:6379> set h 111111111111111111111111 OK redis 127.0.0.1:6379> keys * 1) "c" 2) "d" 3) "e" 4) "f" 5) "g" 6) "h"
今回は"b"が削除された。
■まとめ
期限を設定していないキーはメモリ使用量がmaxに達した場合に自動削除対象にならない(maxmemory-policyがvolatile-***の場合)ので注意。
キャッシュとしてredisを運用している場合、誤って期限を設定しないキーが保存されてしまうと削除されずに残り続けてしまう。
また、期限を設定していないキーであっても、maxmemory-policyがallkeys-lru、allkeys-randomの場合は削除対象となる。何らかの理由でキーに期限を設定せずに運用する場合はこれらに設定をすればよいと思われる。
Google App Engineアプリ Category Editor を公開しました
カテゴリを編集するためのアプリ Category Editor を公開しました。
Google App Engine for Java を利用しています。
このツールは、ツリー構造のデータを編集するためのものです。Googleアカウントでログインすることで、自身が作成したカテゴリツリーを保存、公開することができます。
このツールを作成した理由は、以前からこういったツリーを編集することのみに特化したツールが欲しかったというのがあります。
ツリー構造的なものを表現するためのものは身近にいくつか存在します。エクスプローラをつかってフォルダ階層を作ったり、Excelを使って列をずらして階層を表現したり。また、データを保存したりするWebアプリケーションなどでは、データの保存先を整理するためにツリーが使われたりします。ただ、それらはあくまで別のことをするのが目的のアプリケーションで、ツリーを作るために特化しているものではありません。そのため、この一点に特化した目的のアプリがあってもいいのではないかということで作成しました。
用途としては、以下のような用途に使えるのではないかと思っています。
- 階層構造のあるデータを整理してマスタ的な感じで保存しておく(例えば組織図や地区分類、生物の分類など)
- 文章の見出しの整理
- 頭の中で考えていることを羅列し整理する(どちらかというとマインドマップに近いかも)
- 何かの作業で使いそうなテキストをテンプレート的に登録しておき利用する
このツールは、作ったカテゴリは他人に公開することもできるようにもなっているため、複数人で共有することもできます。
まだ機能的に最低限の機能しかありませんが、今後様々な機能の拡張を行っていこうと思っています。現時点で考えているのは以下のような機能です。
- インポート・エクスポート機能
- クリップボードにコピー機能
- リンク機能
触っていただいた方、もしよろしければ感想をいただけると嬉しいです。
appspot.com 環境でリダイレクトループしてしまう
appspot.com環境にアプリケーションをデプロイし、存在しないURLにアクセスすると、404エラーとならず以下のようなリダイレクトループが発生してしまった。
開発環境では発生しなかったのに、何故?という感じで調べていると、以下のような情報が。。
@knj77: jsp-configでinclude-prelude指定すると”存在する”ファイルに対してもリダイレクトループが発生する模様。static-filesに拡張子を指定しまくるか、jsp-configの設定を外すと直る。 #appengine
確かに
*.jsp
false
UTF-8
false
/common.jsp
この記述を外したところ、画面に「Error: NOT_FOUND」とデカデカとした文字が表示され、リダイレクトはしなくなった。
なぜこれを記述しているとリダイレクトループするのかわからないけれど、とりあえずinclude-preludeを利用せずに個別のJSPにそれぞれ記述ことで回避することにした。
しかし、この現象、最初は自分のプログラムが間違ってリダイレクトループさせてしまってるのかと思ってしまった。。
App Engine for Javaでのデプロイ時にBad Requestエラーが出て認証できない
App Engine for java でアプリケーションをデプロイしようとしたところ、以下のエラーが発生した。
com.google.api.client.http.HttpResponseException: 400 Bad Request
at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:209)
at com.google.api.client.auth.oauth.AbstractOAuthGetToken.execute(AbstractOAuthGetToken.java:64)
at com.google.gdt.eclipse.login.GoogleLogin.authorizeStep1(GoogleLogin.java:535)
at com.google.gdt.eclipse.login.GoogleLogin.logIn(GoogleLogin.java:416)
at com.google.appengine.eclipse.core.deploy.ui.DeployProjectHandler.execute(DeployProjectHandler.java:51)
at com.google.appengine.eclipse.core.deploy.ui.DeployProjectAction.run(DeployProjectAction.java:13)
at org.eclipse.ui.internal.PluginAction.runWithEvent(PluginAction.java:251)
at org.eclipse.jface.action.ActionContributionItem.handleWidgetSelection(ActionContributionItem.java:584)
at org.eclipse.jface.action.ActionContributionItem.access$2(ActionContributionItem.java:501)
at org.eclipse.jface.action.ActionContributionItem$5.handleEvent(ActionContributionItem.java:411)
このブログ記事に、システム日付を直したらよいとあったのでシステム日付を確認して見たところ、確かに10分ほどずれていた。。正しい時間に調節したところ、無事に認証処理に進めました。
以上。