<< 前へ | Home

PR: 今だから始める!ECショップ開業    こんなこともできる!Webサービス    結婚式は神前式で    エコカーがこれからの主流    本気の婚活!!    みんなのリサイクル意識    引越しのタイミング    語学を学ぶための基礎   

物理CD販売は同期ライセンスと共に終焉するのか?

レーベル会社は同期ライセンスと共に終焉するのかもしれない。

cdbabyはインディー(特定のレーベル会社と契約せずに活動している音楽家)のためのサイトで、サイトは英語しかないけど日本からも使える。

基本はダウンロード販売で、Freeプランならタダで出せる。登録すると、こんな感じのアーティストページというのがcdbabyのサイトにできる。

これに対して、Standardプランを選択するとiTunesとかAmazon mp3を含めた様々な販売サイトに自動的にアップロードしてくれる。これはアルバム1つで$59で、あと販売にあたってバーコードを取るのに$20かかるので、だいたい1アルバム10k円くらいか。たまにディスカウントがあるようなので、急がないならFreeプランで上げておいて安くなった時にStandardプランにアップグレードするといいかも。試しに申し込んでみたところ、1週間くらいで、Amazonミュージックストアに上がってきた

販促用にダウンロードカードというのがあって、これも申し込んでみた。外見はこんな感じ。redeemコードが印刷されていて、100枚セットだった。表記が英語だし配送料がかかるので、日本では微妙かも。

Proプランというのもあって、これは物理的なCDも作成できるが、自動的に店舗に置かれるわけではなく、cdbabyの倉庫に積まれるだけで店舗からリクエストがあれば発送されるという形式なので、よほど有名にならないと意味が無いだろう。そもそも日本ではProプランは提供されていない。

もう1つStandardプランを使うと、YouTubeの同期ライセンスというのを選択できる(追加料金なし)。この同期ライセンスというのが興味深い仕組みで、これを使うとcdbabyで作成した音楽がYouTubeに著作権者(つまり自分)として登録される。この音楽を全く別の人がコピーして動画の中に埋め込んでYouTubeにアップロードすると、YouTubeが判別して自動的にその動画に広告を挿入し、その広告料が著作権者に支払われる。

自分の音楽がたまたま大ヒットした動画の中に埋め込まれれば、結構な収入になるそうだ。これまでは音楽が勝手にYouTubeに上げられないようにするというのが常識だったわけだが(今でもレーベル会社はそうだろう)、それが大きく変わろうとしているようで、インディー系の場合は、むしろどんどんコピーして動画で使ってくれ、という方向になってきている。更に今の仕組みだと広告料が著作権者にしか入らないから、半分は動画の作成者にも配分しようという方向で検討されているようで、コピー大歓迎という方向に進んでいる。いよいよ旧システムであるCD販売は終焉するのかもしれない。

Gradle徹底入門を献本いただきました

Gradle徹底入門を献本いただきました。ありがとうございます。

なかなか読む時間がとれなかったが、正月休みでようやく読み込むことができた。「入門」とあるけど、きちんとアーキテクチャから解説されているので、十分な知識が得られるだろう。

Gradleは、あまり深く考えなくても適当にやりたいことをWeb検索しながらビルド定義をいじっていれば、それなりに使えてしまうので、きちんとアーキテクチャを調べずに来てしまっている感がある。特にWeb検索して見つかるGradle API(http://www.gradle.org/docs/current/javadoc/)をビルド定義の中でどうやって使うのかとか、タスク定義に出てくる、task xxx(type: Copy)のtypeって何? とか、あとビルド定義の中に出てくる以下のような表記の意味とかについて適当な理解のままだった。

[compileJava, compileTestJava]*.options*.encoding = defaultEncoding

多分、そういう人は多いんじゃないかな。本書は分量が多いけど、全部読まなくても、第2、3部を読めばGradleの基本的なアーキテクチャが分かるのでお勧めだ。特に、6.1.3から始まるスクリプトブロック、ドメインオブジェクトの解説は必見だろう。あと、7.2の依存関係まわりの解説も読んでおきたい。特にキャッシュの回りの挙動などは良く知らないと思い通りに動かなくて悩むことになる。

他にも色々と知らかった部分が見つかった。例えばプロパティファイルでのシステムプロパティの指定は、gradle.propertiesでも、-Dオプションでも出来るが、antとは反対で-Dオプションの方が優先度が低いのだ。これって使いにくいような気がするんだけど(普通、デフォルトはgradle.propertiesで記述して、一部アドホックに変えたい時に-Dで指定すると思うので)。こういうのって書籍などで改めて読まないと気付かなかったかもしれない。

そういえば「プロパティ」も何となく使っていたけど、システムプロパティ、拡張プロパティ、プロジェクトプロパティの特性や指定方法がまとめられているので、今後は適切な活用ができそうだ。プロジェクトではGradle知らない人が大半なので、このあたりの設計が結構重要だったりする。

次は誰かsbt徹底入門書いてくれないかなぁ

トルコ行進曲

最後のところは、コンピュータに弾かせるのも結構むずかしい。
モーツァルト ピアノソナタ 第11番 第三楽章「トルコ行進曲」

楽譜付き

monitでcheck programを使用する時の注意

monitでcheck programを使ってハマったのでメモ。

とあるサービスを提供するWebアプリを監視するため、以下のようなconfを作成した。

check program test path /home/shanai/test/ping.sh
    if status > 0 then exec /home/shanai/test/restart.sh

ping.shはhttpie使ってWebアプリに簡単なリクエストを送ってみて、正しい応答が無ければ非0を返すスクリプト。restart.shは、Webアプリを再起動するスクリプト。ところが、これが全くうまく動作しない。わざとWebアプリを落とすと、そこから復帰できない。restart.shは呼ばれているのだけど、ping.shが正常にならない。ログを見るとこんな感じで、monitは正しく動作しているように見えるが、なぜかping.shが0を返さない。しかもターミナルから、ping.shを実行してみると0が返っている。

[JST Aug 30 20:32:08] error    : 'test' '/home/shanai/test/ping.sh' failed with exit status (1) -- no output from program
[JST Aug 30 20:32:08] info     : 'test' exec: /home/shanai/test/restart.sh
[JST Aug 30 20:32:38] error    : 'test' '/home/shanai/test/ping.sh' failed with exit status (1) -- no output from program
[JST Aug 30 20:32:38] info     : 'test' exec: /home/shanai/test/restart.sh
[JST Aug 30 20:33:08] error    : 'test' '/home/shanai/test/ping.sh' failed with exit status (1) -- no output from program
[JST Aug 30 20:33:08] info     : 'test' exec: /home/shanai/test/restart.sh

最初はping.shに何か問題があるのかと、httpieのかわりにcurlを使ったりしたけど全く変わらず。そこでping.shとrestart.shを以下のようなダミーに置き替えて様子を見てみた。

--- ping.sh ---

#!/bin/sh
echo "Ping started on " `date` >>/tmp/log
sleep 3
echo "Ping ended on " `date` >>/tmp/log
exit 1
--- restart.sh ---

#!/bin/sh
echo "Restart started on " `date` >>/tmp/log
sleep 10
echo "Restart ended on " `date` >>/tmp/log

ping.shの方は3秒、restart.shの方は少し長めに10秒かかる処理と想定。前後でログを入れてみた。そしてログを見ると、そこには予想の斜め上を行く結果が残されていた。

Ping started on  Sat Aug 30 20:31:38 JST 2014
Ping ended on  Sat Aug 30 20:31:41 JST 2014
Restart started on  Sat Aug 30 20:32:08 JST 2014
Ping started on  Sat Aug 30 20:32:08 JST 2014
Ping ended on  Sat Aug 30 20:32:11 JST 2014
Restart ended on  Sat Aug 30 20:32:18 JST 2014
Restart started on  Sat Aug 30 20:32:38 JST 2014
Ping started on  Sat Aug 30 20:32:38 JST 2014
Ping ended on  Sat Aug 30 20:32:41 JST 2014
Restart ended on  Sat Aug 30 20:32:48 JST 2014
Restart started on  Sat Aug 30 20:33:08 JST 2014
Ping started on  Sat Aug 30 20:33:08 JST 2014
Ping ended on  Sat Aug 30 20:33:11 JST 2014
Restart ended on  Sat Aug 30 20:33:18 JST 2014

最初のPingが終了した後、Restartはすぐには開始せず、monitの監視間隔(今回は30秒に設定)後になってRestartが開始している。しかも、Restart開始と同時に(!)、次のPingが開始している。これではPingが成功するわけがない。何せWebアプリを再起動したタイミングでPingが走ってしまうのだ。つまり、当初は以下のような動作だと思っていたのだが(monit.logだけ見れば、そのように誤解してしまう...)

  • ping.shを実行(失敗)
  • restart.shを実行
  • monitの監視間隔分の待ち
  • 最初に戻る

実際は以下のように動作していた。

  • ping.shを実行(失敗)
  • monitの監視間隔分の待ち
  • restart.sh、ping.shを同時実行
  • 上から2番目に戻る

つまり、check programを使う時は、2行目以降に復帰処理を書いてはいけない。以下のように書くべきなのだろう。

check program test path /home/shanai/test/pingAndRestart.sh
    if status > 0 then alert

check programの行に指定するプログラムで状態を調べて、必要ならリカバリ処理までやってから状態を返す。2行目以降にはリカバリ処理は書かずに、せいぜいalertなど、状態監視とバッティングしても問題ない処理を記載する。

フルスクラッチから1日でCMSを作る シェルスクリプト高速開発手法入門 を読んだ

「フルスクラッチから1日でCMSを作る シェルスクリプト高速開発手法入門」を送っていただきました。

シェルスクリプトでWebアプリケーションを書いてしまう本で、それだけ聞くと単なるキワモノ系な感じがするかもしれないけれど、1冊で3度おいしい本。

まずWebアプリケーションの基本が学べる。というか理解していないと途中で付いていけなくなる恐れあり。しかしこのあたりは理解していないといけないところだと思うので、この本の内容が理解できなかったら、なんとかフレームワークに頼る前にきちんと調べて理解しておくべきだと思う。脆弱性まわりも丁寧に解説されていて素晴しい。

2つ目として、この本は良くあるトリッキーなコードはほとんど使われておらず、非常に純朴なシェルスクリプトで構築されている。それでもシェルスクリプトとそれを支えるツールの思わぬ使い方が学べる。自分もsort -Rでシャフルできるとか <<< を使うことで変数の内容を標準入力として使えるとかは知らなかった。

3つ目にエンジニアとして考え方の基礎が学べる。特にチューニングのところが良いし、なぜwhileを避けるべきかとか、ちゃんと理由が書かれている。あと割り切りがうまい。日本人ってとにかくこの割り切りというやつが苦手で「この程度で十分じゃない」というのが出来ずに無用に造り込んでしまうことが多い。特に面白かったのがサイトのアクセスカウンタのところ。普通ならカウンタ値が書かれたファイルを使うところだけど、そうすると同時アクセスされた時にどうやってカウンタを更新するのか、ロックするのかなどやっかいだ。この本では echo 1 >> counterでカウンタファイルを1バイトごとに大きくしていく。ファイルサイズ=アクセス数だ。アペンドだから同時更新に悩まなくて済む。そのかわりアクセス数が増えればカウンタファイルのサイズが無制限に膨らむことになる。しかしその程度のこといいではないか。仮に100万回その記事が読まれたとしても、たかだか1MBだ。今では大騒ぎするほどのサイズじゃない。

最後に、こういう本を出版してくれたKADOKAWAさんに拍手を送りたい。

鎌倉のあじさい

去年は行けなかった鎌倉。いつもながら凄い混雑だった。

左可井で、いつもの穴子丼。トイレが増設されて2つになってた。


浄妙寺へ。



いつもの猫さんとご対面


長谷寺へ。毎年新しい品種が増えている気がする




汗だくになりながら登っていく




複雑な色合い


これから色付くのかな







ほたるぶくろ




るいもが帰ってきた。

お花を幾つもいただいて、るいもは幸せに天に登って行けたと思います。


TracLightningのJenkinsのJob設定をまとめてやるためのメモ。

今のプロジェクトで、Jenkinsのビルドでたまにソースコードの中身が2重になる(1つのファイルに同じん内容が2回書かれている)状態になることがある。原因は不明で、どうもSubversionとWindowsとの食い合わせっぽい。Jenkinsのジョブ設定で、ワークスペースの更新のデフォルトがsvn updateになっているのを、新規チェックアウトにすると緩和される気がするので、ひとまず全部変更しておこうかと思ったものの、既に数100のジョブがあってとても手でやるのは無理。

JenkinsのAPIを使おうと思ったものの、隔絶環境なのでwgetもcurlも無ければ、Rubyも無くてスクリプト言語系はPerlのみ。Javaでゴリゴリ書くのは辛いなと途方に暮れていたところ、TracLightningなので中にPythonが入っていることを思い出し、ちょっと試してみる。

第一の難関はログインのところ。Firebugで見てみると、TracLightningのデフォルトはDigest認証のよう。これはPythonのurllib2に入っているHttpDigestAuthHandlerを使ってみたら、あっさり突破できた。あとは、ElementTreeをXMLパーサに使用すれば問題無し。以下はjobの一覧を読み出す例:

import urllib2
import xml.etree.ElementTree as ET
URL = 'http://server/jenkins/api/xml'
Realm = 'trac'
Username = 'username'
Password = 'password'

authhandler = urllib2.HTTPDigestAuthHandler()
authhandler.add_password(Realm, URL, Username, Password)
opener = urllib2.build_opener(authhandler)
urllib2.install_opener(opener)
page_content = urllib2.urlopen(URL).read()

elem = ET.fromstring(page_content)
for job in elem.findall(".//job"):
    print job.find(".//name").text
    print job.find("./url").text

以下はjob設定の読み出し例。GETリクエストで読み出し。POSTすれば更新できる。

import urllib2
import xml.etree.ElementTree as ET
URL = 'http://server/jenkins/job/xxx_job/config.xml'
Realm = 'trac'
Username = 'username'
Password = 'password'

authhandler = urllib2.HTTPDigestAuthHandler()
authhandler.add_password(Realm, URL, Username, Password)
opener = urllib2.build_opener(authhandler)
urllib2.install_opener(opener)
page_content = urllib2.urlopen(URL).read()

elem = ET.fromstring(page_content)
elem.find(".//scm/workspaceUpdater").set("class", "hudson.scm.subversion.CheckoutUpdater")
urllib2.urlopen(URL, ET.tostring(elem))

これらをまとめて、全てのジョブのワークスペース更新の方法を、svn updateから新規チェックアウトに変更する例:

import urllib2
import xml.etree.ElementTree as ET

class Jenkins:
    def __init__(self, url, userName, password):
        self.userName = userName
        self.password = password
        self.url = url if url.endswith('/') else url + '/'

    def _setCredential(self, url):
        authHandler = urllib2.HTTPDigestAuthHandler()
        authHandler.add_password('trac', url, self.userName, self.password)
        urllib2.install_opener(urllib2.build_opener(authHandler))

    def _createUrl(self, urlSuffix):
        return self.url + urllib2.quote(urlSuffix.encode('utf-8'))

    def _httpGet(self, urlSuffix):
        accessUrl = createUrl(urlSuffix)
        self.setCredential(accessUrl)
        content = urllib2.urlopen(accessUrl).read()
        return ET.fromstring(content)

    def _httpPost(self, urlSuffix, postXml):
        accessUrl = createUrl(urlSuffix)
        self._setCredential(accessUrl)
        urllib2.urlopen(accessUrl, ET.tostring(postXml))

    def getJobList(self):
        return self._httpGet('api/xml')

    def getJobSettings(self, jobName):
        return self._httpGet('job/%s/config.xml' % jobName)
        
    def setJobSettings(self, jobName, xml):
        self._httpPost('job/%s/config.xml' % jobName, xml)

if __name__ == '__main__':
    jenkins = Jenkins('http://your-server/jenkins', 'username', 'password')
    for job in jenkins.getJobList().findall(".//job"):
        jobName = job.find(".//name").text
        jobSettings = jenkins.getJobSettings(jobName)
        workUpdater = jobSettings.find(".//scm/workspaceUpdater")
        if not workUpdater is None:
            workUpdater.set("class", "hudson.scm.subversion.CheckoutUpdater")
            jenkins.setJobSettings(jobName, jobSettings)

隔絶環境でメモを取りながら作業したのでtypoとかあったらごめんなさい。

このサイトの掲載内容は私自身の見解であり、必ずしもIBMの立場、戦略、意見を代表するものではありません。
日本アイ・ビー・エム 花井 志生 Since 1997.6.8