orangeProse別館

orangeProse(本ブログ)の補助

Gulpに挑戦

f:id:hidex7777:20150506225331p:plain ずっとフロントエンドのタスクランナーにはGruntを使っていましたが、Gulpがどんなものか触ってみたくなったので、勉強のために導入してみました。

なお、私の環境は

です。プロジェクトディレクトリはgit初期化済みで、リモートリポジトリもadd済みです。

インストール

まずNode.jsを最新版にします。Windows版はインストーラで一発です。

> node -v
v0.12.2
> npm -v
2.7.4

gulpをグローバルインストールします。

> npm install gulp -g
> gulp -v
> [11:10:14] CLI version 3.8.11

初期化など

プロジェクトディレクトリに移動してpackage.jsonファイルを作ります。

> npm init

gulpをローカルインストール。

> npm i -D gulp

gulpfileをCoffeeScriptで書きたいので、coffee-scriptをローカルインストールします。

> npm i -D coffee-script

.gitignoreファイルにnode_modules/を書いておきます。

node_modules/

ここまでをgit pushしておきます。

> git status
> git add .
> git commit -m "install gulp"
> git push origin master

各種モジュールのインストール

おそらく次のモジュールを使うことになるのであらかじめインストールしておきます:

  • gulp-sass
  • gulp-imagemin
  • gulp-coffee
  • gulp-concat
  • gulp-uglify
  • gulp-plumber
  • gulp-webserver
> npm i -D gulp-sass gulp-imagemin gulp-coffee gulp-concat gulp-uglify gulp-plumber gulp-webserver

gulpfile.coffeeのテスト

プラグインをいろいろ入れておきながらなんですが、gulpfileを書くのは初めてなので、テスト的なものを書いておきます。

gulp = require 'gulp'

gulp.task 'hello', ->
  console.log 'hello world!'

gulp.task 'default', ['hello']

結果

> gulp
[11:48:47] Requiring external module coffee-script/register
[11:48:47] Using gulpfile ~\dev\mysite\gulpfile.coffee
[11:48:47] Starting 'hello'...
hello world!
[11:48:47] Finished 'hello' after 177 μs
[11:48:47] Starting 'default'...
[11:48:47] Finished 'default' after 14 μs

うまくいきました。

タスクを書いていく

やることは、

  • ./src/imageにある画像を軽量化して./dist/imageに配置
  • ./src/coffeeにあるcoffeeファイルをコンパイル、結合、圧縮して./dist/jsに配置
  • ./src/scssにあるscssファイルをコンパイルして./dist/cssに配置
  • scss, coffee, htmlに変更があったらリロード
  • scssとcoffeeのコンパイルにエラーがあっても止めない

gulp-imagemin

imagemin = require 'gulp-imagemin'

gulp.task 'img', ->
  gulp.src ['./src/image/*.jpg', './src/image/*.png']
    .pipe imagemin()
    .pipe gulp.dest './dist/image'

gulp.task 'default', ['img']

gulp-plumber, gulp-coffee, gulp-concat, gulp-uglify

plumber = require 'gulp-plumber'
coffee = require 'gulp-coffee'
concat = require 'gulp-concat'
uglify = require 'gulp-uglify'

gulp.task 'js', ->
  gulp.src './src/coffee/*.coffee'
    .pipe plumber()
    .pipe coffee()
    .pipe concat 'all.min.js'
    .pipe uglify()
    .pipe gulp.dest './dist/js'

gulp.task 'default', ['img', 'js']

gulp-sass

sass = require 'gulp-sass'

gulp.task 'css', ->
  gulp.src './src/scss/*.scss'
    .pipe plumber()
    .pipe sass()
    .pipe gulp.dest './dist/css'

gulp.task 'default', ['img', 'js', 'css']

watchの記述

gulp.task 'watch', ->
  gulp.watch './src/coffee/*.coffee', ['js']
  gulp.watch './src/scss/*.scss', ['css']
  gulp.watch './dist/*.html', ['watch']

gulp.task 'default', ['img', 'js', 'css', 'watch']

webserverの記述

webserver = require 'gulp-webserver'

gulp.task 'webserver', ->
  gulp.src './dist'
    .pipe webserver{
      host: 'localhost'
      livereload: true
     }

gulp.task 'default', ['img', 'js', 'css', 'watch', 'webserver']

http://localhost:8000にアクセスできるようになりました。

できあがったgulpfile.coffeeはGistsにあります。

iiyamaのディスプレイがよかった話(グラボが壊れたと思ったらそうでもなかった)

年末年始には自分のための仕事を進めるつもりだったのだけれど、12月30日、ディスプレイにほとんどなにもうつらなくなってしまった。1月1日に解決するまで、約48時間、パソコンを使えなくて、仕事にならなかった(古いタイプの人間なので、タブレットスマホだけで仕事はムリ)。

ハードにはほんとうに疎いので、ふつうはもっと迅速に通常モードに復帰できるのだろうけれど、まあ、年末年始で顧客の仕事に影響が出なくてよしとしておこう、今回は。

前兆
1週間前ぐらいから、PCの電源を入れてもディスプレイがONにならない。いったんケーブルを抜き差しするとONになる。

こういう症状が1週間続いた後、12月30日の夜、

  • ケーブルを抜き差しすると1秒ほどうつるがすぐに真っ暗に
  • ディスプレイの電源をOFF/ONすると同様に1秒復帰

という状態になった。

スペック:

再起動したり電源切ったりしてるうちにCMOSがどうのこうのという画面になった。

f:id:hidex7777:20150101222837j:plain

そんで、BIOSに入ると(Windowsはディスプレイ電源のON/OFFで1秒ぐらいしかうつってくれないけどBIOSは4秒ぐらいうつる)、CMOSリセットしてないのに、たしかにDate/Timeが設定されていない状態だった。

この時点での仮説と対応:

マザボの電池切れ
翌日ホームセンターで電池を買うことにしよう
グラボがお亡くなりになった
Amazonで安いグラボをポチった
ディスプレイ(の電源)がお亡くなりになった
どうしよう?
マザボがお亡くなりになった
MacBook Proポチった

最悪、MBPをポチったので、それまでパソコン使うの諦めることにした。

12月31日

マザーボードボタン電池はCR2032というらしい。

それでいろいろ調べると、どうやらCR2032とは、

ということらしい。そしてPanasonic一択らしい。把握。

で買ってきた。

f:id:hidex7777:20150101222913j:plain

Amazonバルク品がクソ安く売ってるけど待ってらんないので買った。

マザボの電池を抜いて、CMOSクリアして(MSIだとclrボタンがある)、こいつを入れた。

PCの電源入れるも、変化なし。

Amazonからグラボが翌日届く予定なので、今日はこのぐらいにしといたる。

ムシャクシャして「笑ってはいけない」を忘れて(というか大晦日だということさえ忘れていた)Ingressしに出かけた。

帰省中と思わしき、名も知らぬAgentたちが、旅の恥はかき捨てとばかりに無理リンク貼りまくっていて(一部だとは思うけれど)「これが『お題』というやつか……」とうなだれる。

1月1日

前日、30日にポチったグラボが出荷されて、1日には届く、というメールがすでに入っていた。何時になるかわからないので、いちおう、以前入っていたグラボを一度抜いて、別のスロットに入れるなどしてみた(ドスパラのハード不調はこれで治ることが多い)。が、何の変化もない。

昼過ぎ、ポチっていた玄人志向グラフィックカードが届く。これ:

f:id:hidex7777:20150101223021j:plain

f:id:hidex7777:20150101223051j:plain

2011年発売で、5000円切っている。ゲームとかしないので(Ingress以外は)、うつればいいのだ。

前のドライバをアンインストールして、これを挿す。

うあー。変化がない!

次の段階だ!

夕方。

パソコン工房に出向く。地方のファスト風土なイオンタウンにはマイルドなヤンキーたちの自家用車が大集合している。つうか満車だ! なんで1月1日から2300台収容の駐車場が満車になってんだ!

中略。

ACERにするかiiyamaにするかで(4秒ぐらい)迷ってiiyamaにした。ProLite XB2380HS-B2。

23インチワイドでIPS方式パネル。解像度は普通の安いやつ同等(Retinaには対応しないぐらいの)で1920x1080。

ドット抜け保障つきで20000円ぐらい。

f:id:hidex7777:20150101223125j:plain

ああ、もしこれでも変化なしだったら、次の可能性、マザボがお亡くなりになった、となってしまい(でも出力はしているのだからそれはないはずなんだけど)、いつ届くかわからないMBPを待つことになってしまう……そしてディスプレイは無駄に2枚余って、ということはMBPでトリプルディスプレイ……などと嬉しそうに妄想していたら、うつった。

今回の結論は、ディスプレイ(のたぶん電源)が問題だった、ということだった。しかしこの結論を出すには、うちにある他のディスプレイをつなげばすぐにわかったことではなかろうか……。

MBP期待。

Herokuチートシート:ネイキッドドメインとメール送信まで

f:id:hidex7777:20140915194425j:plain

さいきん、自サイトをHerokuで運用するようになったので、忘れないように自分用にメモ。

方針は次の通り:

  • アプリサーバにはUnicornを使う
  • ネイキッドドメインで運用(www.foobar.comじゃなくてfoobar.comで)
  • メールを送信する(ActionMailerを使う)
  • ドメイン維持(年980円ぐらい?)以外は無料で
  • いちおうMXレコードの登録まではやったたけど受信がめんどくせーのでやるならMandrill(メールのプラグイン)のAPIを各自見てくだしゃんせ

Heroku用にGemfileを書く

ruby '2.0.0'

gem 'rails', '4.0.5'

group :production do
  gem 'pg', '0.15.1'
  gem 'rails_12factor', '0.0.2'
  gem 'unicorn'
end

gemのアップデート。

$ bundle install --without production
$ bundle update
$ bundle install
$ git commit -a -m "Update Gemfile.lock for Heroku"

--without productionはremembered optionなのでコマンドに保存される。

Unicornの設定

$ touch config/unicorn.rb
$ vi config/unicron.rb

worker_processes Integer(ENV["WEB_CONCURRENCY"] || 3)
timeout 15
preload_app true

before_fork do |server, worker|
  Signal.trap 'TERM' do
    puts 'Unicorn master intercepting TERM and sending myself QUIT instead'
    Process.kill 'QUIT', Process.pid
  end

  defined?(ActiveRecord::Base) and
    ActiveRecord::Base.connection.disconnect!
end

after_fork do |server, worker|
  Signal.trap 'TERM' do
    puts 'Unicorn worker intercepting TERM and doing nothing. Wait for master to send QUIT'
  end

  defined?(ActiveRecord::Base) and
    ActiveRecord::Base.establish_connection
end

config/environments/production.rb

config.assets.compile = true

データベースの設定

config/database.yml

production:
  adapter: postgresql
  encoding: unicode
  # database: db/production.sqlite3
  pool: 5
  # timeout: 5000

Procfileとforemanでのテスト

./Procfile

web: bundle exec unicorn -p $PORT -c ./config/unicorn.rb

Unicornがローカル開発環境にインストールされている必要があるけど)

ローカル環境の環境変数を./.envに。

$ echo "RACK_ENV=development" >> .env
$ echo "PORT=3000" >> .env
$ echo ".env" >> .gitignore
$ git add .gitignore
$ git commit -m "add .env to .gitignore"

foremanでテスト

$ gem install foreman
$ foreman start

ログインする

$ heroku login

または

$ heroku auth:login

ログアウトする

$ heroku logout

または

$ heroku logout

アプリを作成してデプロイ

$ heroku create foobar

または

$ heroku create

からの

$ git push heroku master
$ heroku run rake db:migrate
$ heroku ps:scale web=1
$ heroku ps
$ heroku open

サブドメイン名をリネームする

$ heroku rename foobar

必要ないけど。いちおう。

デプロイに失敗したときは

$ rake assets:precompile
$ git add .
$ git commit -m "add precompiled assets for Heroku"
$ git push heroku master

デプロイ時のエラーを取得

$ heroku logs

または

$ heroku logs --tail

実行環境の確認

$ heroku run console
Ruby console for foobar.herokuapp.com
>> Rails.env
=> "production"
>> Rails.env.production?
=> true

SSLを使う場合

config/environments/production.rb

FooBar::Application.configure do
(…)
  config.force_ssl = true
(…)
end
$ git commit -a -m "add SSL in production"
$ git push heroku
$ heroku run rake db:migrate

本番データベースをリセットする

$ heroku pg:reset DATABASE
$ heroku run rake db:migrate

アプリを強制再起動する

$ touch foo
$ git add foo
$ git commit -m "foo"
$ git push horoku

再度デプロイすればいいということ。

どのアカウントでログインしているのか

$ heroku auth:whoami

CloudFlareでネイキッドドメイン

CloudFlareドメインを入れろと言われたら、自分のドメインを入力(例としてここではfoobar.comとする)。スキャンがはじまる。

DNS Records for foobar.com:

CNAME foobar.com is an alias of hoge.fuga.com ACTIVE

みたいに書いてある画面の設定アイコンをクリック。というか、あとでも設定できる。DNS Zone設定で、CNAMEのfoobar.comのValueをfoobar.herokuapp.comにすればよい。

ネームサーバを変えろと言われるので、お名前ドットコムとかの、自分のドメインを管理しているネームサーバを言われたとおりに変える。

http://foobar.comでアクセスできるのを確認する。

ネイキッドドメインの方針。

  • www.foobar.comにアクセスしたらfoobar.comにリダイレクトする。
  • foo.foobar.comのような存在しないサブドメインも同様。

DNS Zoneを次のように設定:

  • CNAME www foobar.herokuapp.com
  • CNAME * foobar.herokuapp.com

My websitesのページで設定アイコンをクリックしてPage Rulesを選択。

f:id:hidex7777:20140915202746p:plain

無料なら3パターンまでルールを登録できる。

Add new ruleで*.foobar.com

Forwarding http://foobar.com

Forwarding type Permanent 301

(参考記事)

メールを送れるようにする

まずGmailから直接送れるか、試してみる

Gmail使って大量メール一斉送信をすると、そっこーでアカウントロックされるとのことなので、一通でも無理なのか、試してみる。

開発環境と同じ設定を書いてみる。

ActionMailerでは

default from: 'FooBar <foobar@gmail.com>'

みたいに、gmailから送信されたことにしている。

confib/environments/producution.rb

  config.action_mailer.raise_delivery_errors = false
  config.action_mailer.delivery_method = :smtp
  config.action_mailer.smtp_settings = {
    :enable_starttls_auto => true,
    :address => 'smtp.gmail.com',
    :port => '587',
    :domain => 'smtp.gmail.com',
    :authentication => 'plain',
    :user_name => 'foobar@gmail.com',
    :password => 'foobar'
  }

ダメだった。

一通でも、不正なログインで、ブロック。親切設計のGoogle

プラグインを使う

2014.09.10時点で使用できるメールプラグイン(SMSを除く)

  • Mandrill(月12000通無料)(Mandrill.comにログインしたら1時間250通のリミットもあるようなことが書いてあった)
  • Mailgun(1日300通無料=月9000通)
  • Mail2Webhookβ(受信メールをWEBアプリへのPOSTとして扱うプラグイン
  • CloudMailIn(月200通)
  • SendGrid(1日200通無料=月6000通)
  • Postmark(月10000通無料)

第一候補がMandrillで第二候補がPostmark。

けっきょくMandrillでよさげだったので、ここではMandrillだけ紹介する。

Mandrill

$ heroku addons:add mandrill:starter

でもプロヴィジョンできるけれどもドキュメントみながらやりたいのでHerokuのアドオンページからログインする。

(Oh...クレカ登録してなかったからハネられた…)

Mandrillのドキュメントを見ながら進める。

MANDRILL_APIKEYというのが使えるようになっているはずなので、確認する。

$ heroku config:get MANDRILL_APIKEY
foobarfoobarfoobarfoob

$ heroku config -s
↑これで環境変数が見られる。ユーザ名も記録しておいたほうがよい。

開発環境でテスト。Foremanで.envにMANDRILL_APIKEYを書いておく(↓の設定ファイルを使うならユーザ名も必要か)。

MANDRILL_APIKEY=foobarfoobarfoobarfoob

設定サンプルを見ながらconfig/environments/production.rbを書き換える。

  config.action_mailer.raise_delivery_errors = false
  config.action_mailer.delivery_method = :smtp
  config.action_mailer.smtp_settings = {
    :enable_starttls_auto => true,
    :address => 'smtp.mandrillapp.com',
    :port => '587',
    :domain => 'heroku.com',
    :authentication => 'plain',
    :user_name => ENV['MANDRILL_USERNAME'],
    :password => ENV['MANDRILL_APIKEY']
  }

できた。Gmailで受信すると、送信者名の隣に「経由」って出てなんとなく嫌だけど仕方がない。

受信もする場合:MXレコードの設定

http://mandrill.com/にユーザ名(heroku config -sで分かる)とパスワード(APIキーがパスワード)でログインできるので、ログインしてみる。

Inboundセクションで、ドメインを入力できるので自分のドメインを入れる。

DNSでMXを設定してないのでinvalidと出ている。

DNS Settings]ボタンをクリックすると、DNSサーバ名が2つ表示される。

別タブでCloudFlare開く。

自分のドメインDNS Settingsを開く。

TypeをMX、Nameを自分のドメインに、ValueをMandrillのサーバ、Priorityを10。

もう一行に、もう一つのMandrillサーバ名入れて、Priorityを20。

[I'm done]なんちゃらボタンを押す。

Mandrillに戻って[Test]ボタンを押すとvalidになる。

ActionMailerのコード(差出人のところ)を書き換える。

default from: 'FooBar <info@foobar.com>'

このドメインへの送信(こっちからすれば、受信)は、InboundにあるRoutesを設定する。

アプリに対するPOSTデータとして送信されるので、うまいことフックするアプリを書く。

APIドキュメントを参照されたし。

(参考記事)

Chefのufwクックブック

f:id:hidex7777:20140730230625j:plain

Chefのufwクックブックの使い方がいまいちわからなかったので、公式のREADMEを訳してみました。

結論。nodeのjsonに直接ファイアウォールのルールを記述してしまっていいみたいですが(じっさい、ぼくは目下のところ、ステージング環境と本番環境の2つのノードしか考えていないのでそれが楽かもしれない)、練習も兼ねて、ロールでAttributeを管理するのがいいかなー、と思っています。

『Chef実践入門』にも「Chefで複数ノードを管理する必要が出てきたら迷わずロールを導入しましょう」(p.104)と書いてあります(第4章執筆id:naoya)。

(誤訳の責任はとらないので、よろしくお願い致します。英語としてよくわからん部分があったのでLang-8でネイティブに聞きましたが"This guy's language use is a mess"って言ってました。そのネイティブの解釈にも疑問があったので、この訳は俺様解釈で訳しています)


説明

Ubuntu上のUncomplicated Firewall (ufw)を設定します。ランリストにufwレシピをインクルードすると、ファイアウォールはenableになり、デフォルトで、SSHとICMP pingをのぞいたすべてをDENYします。

ルールをそのノードに付け加えるには、rolesにおける['firewall']['rules']Attributeにルールを加えるか、そのノードに直接加えます。firewallクックブックは、他のレシピからも直接ルールを適用するのに使うことができるLWRPを持っています〔訳注:ufwクックブックはfirewallクックブックに依存しています〕。明示的にルールを削除する必要はありません。変更やリセットのときにそのルールが再評価されます。ルールは、順序が明示されていないかぎり、ランリストの順に適用されます。

要件

Ubuntu 10.04と11.04でテストしました。

レシピ(recipes)

デフォルト(default)

defaultレシピは、適用すべきファイアウォール・ルールのリストを、ロールやノード自体に加えられた['firewall']['rules']Attributeから探します。そして、ルールのリストが、規定の順にノードに対して適用されます。

無効(disable)

disableレシピは現存するファイアウォールを無効化する必要がある場合に使われます。おそらくそれはテストのためでしょう。たとえ他のufwレシピがenableにしようとしても、ufwファイアウォールは無効化されます。

このレシピを削除しても、自動的に再有効化されるわけではありません。['firewall']['state']の値をクリアし、ファイアウォール・ルールの再計算を強制する必要があるでしょう。これはknife node editで行うことができます。

データバッグ(databag)

databagレシピは、ファイアウォール・ルールを適用するために、firewallデータバッグの中を見ます。それは、ロールのためのランリストの精査、およびデータバッグ項目にマップするキーのためのレシピ名の精査にもとづきます。そして、ファイアウォール・ルールは規定の順に適用されます。

ルールを適用するために、['firewall']['rules']Attributeがセットされた後で、databagレシピはdefaultレシピを呼び出します。なので、もし望むならロールとデータバッグ項目をミックスすることもできます(まずロールの適用、それからデータバッグの内容)。

レシピ(recipes)

recipesレシピはnode[<recipe>]['firewall']['rules']Attributeをもつレシピのランリストの精査にもとづいて、ファイアウォール・ルールを適用します。これらはnode['firewall']['rules']に追加され、そのノードに適用されます。クックブックはレシピのためのAttributeをつぎのように定義することができます:

attributes/default.rb for test cookbook

default['test']['firewall']['rules'] = [
  {"test"=> {
      "port"=> "27901",
      "protocol"=> "udp"
    }
  }
]
default['test::awesome']['firewall']['rules'] = [
   {"awesome"=> {
       "port"=> "99427",
       "protocol"=> "udp"
     }
   },
   {"awesome2"=> {
      "port"=> "99428"
     }
   }
]

'test::awesome'ルールは、その特定のレシピがランリストにある場合のみ適用されることに注意してください。レシピで適用されるファイアウォール・ルールは、ロールAttributeで定義されるルールのあとで適用されます。

セキュリティレベル(securitylevel)

securitylevelレシピは、強制される必要があるnode['firewall']['securitylevel']設定がある場合に使われます。これは設定されていないリファレンス実装です。

アトリビュート(Attributes)

ロールとそのノードは['firewall']['rules']Attributeセットを持つことができます。このAttributeはハッシュのリストであり、そのキーはルール名に、その値はパラメータのハッシュになります。適用の順序はランリストにもとづきます。

ロール例

name "fw_example"
description "Firewall rules for Examples"
override_attributes(
  "firewall" => {
    "rules" => [
      {"tftp" => {}},
      {"http" => {
          "port" => "80"
        }
      },
      {"block tomcat from 192.168.1.0/24" => {
          "port" => "8080",
          "source" => "192.168.1.0/24",
          "action" => "deny"
        }
      },
      {"Allow access to udp 1.2.3.4 port 5469 from 1.2.3.5 port 5469" => {
          "protocol" => "udp",
          "port" => "5469",
          "source" => "1.2.3.4",
          "destination" => "1.2.3.5",
          "dest_port" => "5469"
        }
      },
      {"allow to tcp ports 8000-8010 from 192.168.1.0/24" => {
          "port_range" => "8000..8010",
          "source" => "192.168.1.0/24",
          "protocol" => "tcp" //ポートレンジを使う場合プロトコルは必須です
        }
      }
    ]
  }
)

データバッグ(data_bags)

firewallデータバッグはdatabagレシピとともに使われます。それはロール名にマッピングする項目を含むでしょう(例:'apache'ロールは'firewall'データバッグのなかの'apache'項目にマッピングする)。ロールかレシピがキーになります(role[webserver]は'webserver'、recipe[apache2]は'apache2')。もしレシピで規定するファイアウォール・ルールがあれば、'::'を'__'(アンダースコアふたつ)と置き換える必要があります(例:recipe[apache2::mod_ssl]はデータバッグ項目においては'apache2__mod_ssl'です)。

データバッグにおける項目は、['firewall']['rules']Attributeに適用するための'rules'ハッシュ配列を含みます。

% knife data bag create firewall
% knife data bag from file firewall examples/data_bags/firewall/apache2.json
% knife data bag from file firewall examples/data_bags/firewall/apache2__mod_ssl.json

'firewall'データバッグ項目の例

{
    "id": "apache2",
    "rules": [
        {"http": {
            "port": "80"
        }},
        {"block http from 192.168.1.0/24": {
            "port": "80",
            "source": "192.168.1.0/24",
            "action": "deny"
        }}
    ]
}

リソース/プロバイダ(Resources/Providers)

firewallクックブックはfirewallfirewall_ruleというLWRPを提供します。そのためにufwプロバイダはあります。

ライセンスと著作者

Author:: Matt Ray (<matt@opscode.com>)

Copyright:: 2011 Opscode, Inc.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.


訳語の選択はできるだけ『実践Chef入門』に習いましたが、完全ではありません。

はてな朗読会第1回公演会

タイトルは嘘です。はてな朗読会というものがあるわけではなく(たぶん。はてなスペースに「朗読」スペースはあります)、はてなユーザーによる朗読会というわけでもないです。朗読者ではてなユーザーはぼくだけです(たぶん。知らないだけでじつは、とかだったら面白いけど)。

主催はふくしま現代朗読会で、第1回公演会のタイトルは「第一回 言葉で奏でるコンサート 宮沢賢治の世界」です。タイトルからもわかるように、「宮沢賢治縛り」でいきます。「やまなし」「いちょうの実」「セロひきのゴーシュ」「雨ニモマケズ」の4編を読みます。ぼくは「いちょうの実」の予定です。朗読教室の生徒(ぼくを含む)が前半2編、プロの話し手が後半2編を読みます。

フライヤーはこんな感じ:

f:id:hidex7777:20140711223605j:plain

  • 日時:2014年9月20日(土)13:30~
  • 場所:ホテルハマツ1階ロビー

ホテルハマツって、福島県郡山市でたぶん一番でかいホテルです。

入場無料なので、当日フラッとお寄りいただければ幸いです。

予習はどうするか

宮沢賢治を前もって読んでおいたほうがいいのか、と聞かれたら、聴き手が読んでいなくとも楽しめるように、朗読者はがんばります、というのがたてまえですが、読んでいたらなおいっそう楽しめる、というのが朗読の世界です。

個人的にはちくま文庫からでている全集をおすすめします。新潮文庫とかは省略や修正が多い。それと、ちくま文庫の全集には「異稿」も(研究上明らかになっているものに関しては)入っているので、「宮沢賢治をちゃんと読む」ためには必須ともいえます。

というのは、宮沢賢治の作品は、生前に発表されたもののほうが少く、しかも彼は、しょっちゅう、それもかなりドラスティックに改稿に改稿を重ねる作家でした。「最終稿」とか「決定稿」というものはないと言ってもよいでしょう。具体的には、かの有名な「銀河鉄道の夜」には「第4次稿」まであるのですが、それは4つの原稿用紙の束があるというのではなくて、さまざまな筆記具で、さまざまな用紙を使って、書き加えたり削除したりを繰り返しているプロセスが大雑把に言って4段階ある、というにすぎず、「第4次稿」とされているものも「削除し忘れ」による矛盾点があって(削除されたはずの人物がいきなりセリフを言ったり)、現在我々が「宮沢賢治の作品」として読んでいる「銀河鉄道の夜」は後年に研究者(発掘者)が手直しをしたものでしかないのです。

「やまなし」

宮沢賢治が生前に出版した単著は、童話集『注文の多い料理店』と詩集『春と修羅』(第1集)のみですが、同人誌や新聞・雑誌への寄稿はいくつかあります。この「やまなし」も『岩手毎日新聞』に寄稿されたものです。今回の公演会で朗読される作品で、生前に発表されたものはこれだけです。

ちくま文庫版全集では第8巻に収録されています。第8巻には他に「注文の多い料理店」なども所収。

教科書で読んだよ、という方も多いかと思いますが、むしろ最近だと『花もて語れ』で久しぶりに読んだという方が多いかと。「クラムボン」のあれです(発音は「クランボン」)。

『花もて語れ』はこの記事執筆時点で12巻まで出ていますが(13巻で完結予定)、宮沢賢治作品が頻出なので、いちおう全巻読破しておくと良いかと思います(Kindle版だと32%オフ、現時点でポイントが30%バックなのでお得です。最新刊の12巻はまだKindle版が出てないですが)。

f:id:hidex7777:20140711224831j:plain

今回の公演会では、この「やまなし」しかかぶってないのですが、「朗読」にとって宮沢賢治は、釣りにとってのフナのようなもので、「賢治にはじまり賢治に終わる」と言ったら……過言かもしれませんが、『花もて語れ』で「宮沢賢治はどう読まれうるか」ということをイメージしていただければ、楽しめるかと思います。

「いちょうの実」

全集では第5巻に収録(「いてふの実」)。他に「貝の火」や「よだかの星」といった、斎藤環ラカンを説明するために引用した童話も所収。それから「風野又三郎」も(有名なのは「風の又三郎」の方)。

『花もて語れ』に「おきなぐさ」の朗読が出てきますが(6~7巻)、「おきなぐさ」の原稿表紙裏に「花鳥童話集」として11篇の童話題名が列挙されていて、その中のひとつが「いてふの実」。

「セロひきのゴーシュ」

全集では第7巻に収録。他に「銀河鉄道の夜」「風の又三郎」も所収。前述したように、「銀河鉄道の夜」がいかにドラスティックに書きなおされたのか、その図解が面白いので、解説も必読。

「セロひきのゴーシュ」は、東百道氏が「朗読がうまくなるプロセスをストーリーにしたもの」(大意)と言っているように、朗読者にとってはひとつの重要な道標ともいえる作品。

雨ニモマケズ

全集では第10巻に収録。他に「農民芸術概論」など所収。第10巻は手帳やノートに残されたメモなどを集めた巻で、超マニアック。

雨ニモマケズ」も手帳に鉛筆書きされたメモで、詩として残されたものではない(一般には詩として受容されていますが)。解釈としてもさまざまで、手帳の右ページで終わりとするか(「サウイフモノニ/ワタシハナリタイ」で終わり)、左ページまでを含むとするか(「南無無辺行菩薩/南無上行菩薩/南無多宝如来南無妙法蓮華経/南無釈迦牟尼仏/南無浄行菩薩/南無安立行菩薩」で終わり)によって、出版形態が異なったりします(新潮文庫の賢治詩集は「ページで終わり」派)。

あと、賢治の詩は無題が多く、これも(そもそも詩として書かれていないので当たり前ですが)無題の作品ですが、たいてい第一行を〔雨ニモマケズ〕のような書き方でタイトルの代わりにすることが多いようです。

本題 広告出稿募集

公演会は入場無料ですが、パンフレットが配られます。印刷代とかを広告でまかないます。ぜひ日本の知性のトップを担うはてなユーザーの皆様方におかれましては、広告枠を購入していただきたく!

パンフレットは100~200部ぐらい配布されます。

カラーです。(1)2分の1ページ・縦122mm×横166mm、(2)4分の1ページ・縦61mm×横166mm、(3)8分の1ページ・縦58mm×横81mm、の3サイズ。

価格は(1)20,000円、(2)10,000円、(3)5,000円。

フォトショ・イラレのCS5対応で350dpi、CMYKで。jpgでRGBでもいいそうです。

ご連絡はGMailにお願いします(@の前がhidex7777)

かなり久しぶりにAndroid SDKに触ったのでメモ(基礎の基礎)

f:id:hidex7777:20140603201618j:plain

Android SDKが見つかんねーな(自分のPCに)、と思ったら、OSのクリーンインストールをして以来、ダウンロードすらしていなかった!

そんぐらい触ってないと、何をどうしたらddmsとかができるのかとかまで忘れている!

そんなわけで自分用メモに手順書を残しておくぜ・・・

Android SDKをダウンロードする

http://developer.android.com/sdk/index.html

ここの「DOWNLOAD FOR OTHER PLATFORMS」にあるSDK Tools Onlyのzipをダウンロードする。

ADTバンドルとかいらねー。

ダウンロードしたら解凍、android-sdk-windowsとかいうフォルダが生まれた!

こいつをC:\に配置!

パスとかは後回し!

JDKをダウンロードする

http://www.oracle.com/technetwork/java/javase/downloads/index.html

ここの最新版(でいいのかな?)をダウンロードする。

インストール済みのJDKは1.7系統だけど、1.8系統が出ているみたいだ(記事執筆時点)。

ぼくはWindowsの64bit環境だからそのexeをダウンロードすることにした。

JDKのインストールはexeのおおせのままに・・・

PATHを通す

先に入っていたJDK1.7のパスを書き換えてしまうかな・・・

C:\Program Files\Java\jdk1.8.0_05\bin;C:\android-sdk-windows\tools;C:\android-sdk-windows\platform-tools

にパスを通した。platform-toolsはこれからダウンロードすることになるのだ・・・

コマンドプロンプト

>java -version
java version "1.8.0_05"
Java(TM) SE Runtime Environment (build 1.8.0_05-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.5-b02, mi

なかなかによさそうだぞ!

SDK managerを使う

Windows版だと、SDK manager.exeというのがついてくる。

ダブルクリックしてしばらくたつと、GUI画面が立ち上がる。

なにやら通信しているが、しばらくするとDone、とメッセージ。

Toolsにチェック、Androidなんちゃらのチェックははずす、Android Support Libraryのチェックもはずす、Google USB Driverのチェックはいちおう入れたままにしておく。

Install 12 Packagesをクリック!

Accept License→Install!

今回はAndroidなんちゃらをインストールしなかったので、思ったよりも時間がかからなかった。

Android SDK Managerを閉じる。

platform-tools/というディレクトリがつくられて、ここにadbがある。

コマンドプロンプトを再起動して

>adb devices
List of devices attached

もしAndroid端末が接続されていて、adb接続もされているのであれば、Listになんかしら表示されるはず。

されないということは、さらになにかが必要なのだ。

Android側の設定

機種によってはGoogle USB Driverでは認識してもらえないことがある。

F-05Dのような極悪非道な充電式カイロなんかがそうだ。

ググって

http://spf.fmworld.net/oss/driver/f-05d/

のようなサイトからダウンロードする。

F-05Dはadb接続を可能にするためにいろいろとめんどくさすぎるぞ!

ドライバをインストールした後もadb_usb.iniがないからandroid update adbコマンドを打ったり、iniファイルに文字列がないから自分で書き込んだり・・・

menu→本体設定→アプリケーション→開発→USBデバッグにチェック。

USBケーブルでPCに接続。

コマンドddms

Dalvik Debug Monitorが開く。

接続されているデバイスを選択して、Device→Screen Captureでスクリーンショットがとれたりする。

Android4.0以降は、デバイス側で簡単にスクショとれるんだけどね。

いろいろ作業が終わったらadb kill-serverでプロセスを終了しておく。

いまさらながらBower入れてGruntでcss-modal

f:id:hidex7777:20140602010208j:plain

いまフロントエンドのみの案件にとりかかっているのですが、いわゆるモーダルウィンドウが必要なケースが出てきました。

なんとなーく「jQueryでいいよなー」と考えていたのですが、「そーいやCSSだけでできるのがなんかあったよなー」と思い出し、

を試してみることにしました。

bowerインストール

Bowerはnpmみたいなパッケージマネージャです。

そんでBowerはNode.jsのパッケージです。なのでNode.jsのパッケージマネージャであるnpmでインストールできます。

ややこしいですね。

Bowerの基本的なことはfrom scratch様の記事

らへんを参考にさせていただきました。

まずNode.jsのアップデートから始めるのが基本ですが、ぼくの環境はWindowsなのでアップデートするにはインストーラ使うしかないです。

Windowsじゃない方は

$ node -v
$ sudo npm cache clean -f
$ sudo npm install -g n
$ sudo n stable
$ node -v

でアップデート。

Windowsだとnコマンドが使えないです(n --helpだけ使えますw)。

この記事を書いている時点で、Windowsで利用できる最新版が0.10.28みたいです。

つぎにBowerのインストール。

(たぶんWindowsだと、Gitがインストールされていることが必須です)

>npm install -g bower
>bower -v
1.3.3

bower init

使いたいパッケージと目的が決まってるので、いきなり現行の開発環境に行きたくなりますが、テストから始めるのが良いかと思います。

さっき現行の開発環境で試しながらやってたら、とあるディレクトリがきれいさっぱり消えてなくなりました。

gitがなかったら死んでました。

>mkdir bowertest
>cd bowertest
>git init

.gitignoreファイル
node_modules/
bower_components/

>git add .
>git commit -m "init bowertest"
>bower init

めっちゃいろいろ聞かれますが、

[?] main file: index.js
[?] add commonly ignored files to ignore list?: Yes

このふたつの項目は「公開するライブラリ(Bowerにレジストする)なら」重要、とfrom scratch様の記事には書いてあった。

ここでは公開するライブラリの制作目的でなく、プロダクトの制作にのみ使うことを想定していますが、いちおう上記のように答えました。

あと、公開されないようにprivateのマークを付けるか、と聞かれるので

[?] would you like to mark this package as private which prevents it from being accidentally published to the registry? Yes

これもYesにしました。

最後に書きだされるbower.jsonファイルが良さそうかどうか聞かれるのでこれもYesで答えます。

とりまcss-modalをインストール

>bower install css-modal --save-dev

bower.jsonのdevDependenciesにcss-modalが記述されます。

インストールしてみると、./bower_components/css-modal/以下にいろいろとファイルが置かれていますが、このうち必要なのはmodal.scssとmodal.jsだけです。

そんでもってscssファイルは/dev/scssディレクトリに、jsファイルは/dist/jsディレクトリに配置したいとします。

手作業でやるのでは自動化している意味がないので、Gruntでディレクトリ・レイアウトを指定することにします。

grunt-bower-task

bowerでパッケージをインストールすると、ディレクトリ構造ごと持ってくるので、レイアウト的に使いづらい。

レイアウトを使いやすいようにするgrunt-bower-taskをインストールします。

まだgrunt-cliがインストールされていなければ:

>npm install -g grunt-cli

まだカレントディレクトリがGruntで運用されていなければ:

>npm init
>npm install grunt --save-dev

package.jsonのdevDependenciesにgruntが記述されます。

>npm install grunt-bower-task --save-dev

終わったら、Gruntが使うpackage.jsonファイルのdevDependenciesにgrunt-bower-taskが記述されています。

Gruntfile.coffeeにbowerの挙動を記述します

module.exports = (grunt) ->
  pkg = grunt.file.readJSON 'package.json'
  #config
  grunt.initConfig
    bower:
      install:
        options:
          #ターゲットディレクトリを指定します
          targetDir: './lib'
          #byTypeでファイルの種類ごとにディレクトリを分けます
          layout: 'byType'
          #bower installタスクを実行したいか否か
          install: true
          #詳細ログを出すか
          verbose: true
          #インストール前にターゲットディレクトリを削除するか
          cleanTargetDir: true
          #必要なファイルをターゲットディレクトリにコピーした後にbower_components/を削除するか
          cleanBowerDir: false
     #plugin
     for taskName of pkg.devDependencies
          grunt.loadNpmTasks taskName if taskName.substring(0, 6) is "grunt-"

return

とりあえずこの設定でインストールを実行してみます。

>grunt bower:install

/lib/css-modal/にmodal.jsとmodal.scssがインストールされました!

cleanBowerDirをfalseにしたので、bower_components/も残っています。

bower_components/css-modal/bower.jsonをみると、"main"にmodal.scssとmodal.jsが書いてあるので、必要なファイルのみ/lib/以下にコピーされたわけです。

exportsOverride

layoutをbyTypeにしたのに、ファイルタイプごとに分けられず、/css-modal/以下に2ファイルとも配置されてしまいました。

これはタイプが定義されていないためです。

bower.jsonファイルで定義します:

  "devDependencies": {
    "css-modal": "~1.0.4"
  },
  "exportsOverride": {
    "css-modal": {
      "js": "**/*.js",
      "scss": "**/*.scss"
    }
  }
}

このように定義してgrunt bower:installを実行すると、

  • /lib/scss/css-modal/modal.scss
  • /lib/js/css-modal/modal.js

のようにタイプ分けしてくれます。

今回のケースではcss-modalしかインストールしていないので、よけいにゴチャゴチャしたように見えますが、いろんなパッケージをbowerでインストールしたときは、こっちのほうが便利なケースがあるかもしれません。

ファイルタイプでのレイアウトよりコンポーネントでのレイアウトのほうがいい、という場合は、layoutオプションを'byComponent'にします。

grunt-contrib-copy

もしかしたらgrunt-bower-taskでうまいことやれば、最終目的配置までやれるのかもしれませんが(layoutオプションに関数を定義できます)、めんどくさいので、grunt-contrib-copyを使って、決め打ちでコピーしてしまいます。

どうせファイル名がわかっているので。

>npm install grunt-contrib-copy --save-dev

package.jsonに追記されました。

Gruntfile.coffeeでコピーのタスクを記述します:

module.exports = (grunt) ->
  pkg = grunt.file.readJSON 'package.json'
  #config
  grunt.initConfig
    bower:
      install:
        options:
          targetDir: './lib'
          layout: 'byType'
          install: true
          verbose: true
          cleanTargetDir: true
          cleanBowerDir: true
    copy:
      cssModalScss:
        expand: true
        cwd: "lib/scss/css-modal/"
        src: "modal.scss"
        dest: "dev/scss/"
        flatten: true
        filter: 'isFile'
      cssModalJs:
        expand: true
        cwd: "lib/js/css-modal/"
        src: "modal.js"
        dest: "dist/js/"
        flatten: true
        filter: 'isFile'
  #plugin
  for taskName of pkg.devDependencies
    grunt.loadNpmTasks taskName if taskName.substring(0, 6) is "grunt-"
  #tasks
  grunt.registerTask "bowerinstall", [
    "bower:install"
    "copy:cssModalScss"
    "copy:cssModalJs"
  ]
return

こんどはcleanBowerDirをtrueにしてみました。

(copyの書き方も、もっとうまいことできるかと思いますがめんどくさいので1ファイルごと書いています)

これでgrunt bowerinstallを実行すると、/bower_components/ディレクトリが消え、/lib/以下に配置された各ファイルが、目的の場所にコピーされました。

css-modal

そういえば、この記事は、CSS-Modalを使うために書き始めたのでした。

完全に忘れていた。

CSS-Modalは、cssのみを使ってモーダルウィンドウを表現するライブラリです。

ただしIE8との互換性やESCキーでモーダルを消す、などの機能のためにmodal.jsも使うことになります(jsがなくても、IE8で機能することは機能するらしいです)。

使い方は簡単で

@import 'modal';

でscssファイルにインポートして、モーダルウィンドウになるパーツに対して

.my-modal-section{
  @extend %modal;
}

のように適用するだけです。

注意点は、

  • modal.scssは_modal.scssにリネームして使ったほうがいいかなー
  • _modal.scssの1行目に@charset "UTF-8";を書かないとたぶんエラーが出る
  • csslintはオフる

HTMLのマークアップはこんな感じ

<div class="work">
    <figure class="workimg">
         <a href="#modal-work01"><img src="img/dummy300.png"></a>
    </figure>
    <dl>
         <dt class="worktitle">モーダル作品1</dt>
         <dd class="workdesc">モーダル作品についての説明です。モーダル作品についての説明です。モーダル作品についての説明です。</dd>
    </dl>
    <section class="modal-work" id="modal-work01" tabindex="-1" role="dialog" aria-hidden="true">
         <div class="modal-inner">
              <div class="modal-content"><img src="img/work_01_image.jpg" alt="作品01"></div>
         </div>
         <a href="#!" class="modal-close" title="Close this modal" data-close="Close" data-dismiss="modal">×</a>
    </section>
</div><!-- /.work -->

imgにaのhrefで#modal-work01へのトリガー、モーダルウィンドウ側はhrefに#!でトップに移動しないようにする。

f:id:hidex7777:20140602010208j:plain

ちょっと気になるのは、CLOSEしたときにURLに#!がついてしまうことかなー。