記事一覧

GitHubを伺か更新ファイル置き場にする

GitHubって何よ

Secure source code hosting and collaborative development - GitHub

里々YAYAが置かれてるGoogle Codeってありますよね。あれの遠い親戚です。バージョン管理システムのリポジトリホスティングサービスです。

Gitの使い方を覚えてみたくなったので、勉強がてら先日作ったPLUGINのソースをアップしてみました。

nikolat's daumaker at master - GitHub

ついでに色々実験してみた

GitHubに伺かのコードなんぞアップしてる人なんてあまり見かけないですが、意外と相性がいいのではないかと考えました。

長所
  • httpsで直接ファイルにアクセスできる->SSPはhomeurlにhttpsを指定できる->ネットワーク更新ファイル置き場として機能する
  • ソースコード一式をtar.gzまたはzipでダウンロードできる->SSPに直接インストールできる
  • Gitコマンドにより一括アップロードが可能、除外ファイルも楽々指定
  • readme.txtが表示されている
短所
  • GitはWindowsにやさしくないし設定が大変
  • HTTPリクエストでファイルの更新時刻を返してくれない(これはDropboxとかにも言えることなんだけど)

SoSiReMiとは何だったのか

ここまで色々できてバージョン管理までできるとなるとSoSiReMiは要らない子…いやいや、更新時刻が取得できないのはSiReFaSoとか作ってる身からするとかなりマイナスですね。

ちょっとした作り捨てのPLUGINとか置いておく分には便利そうなのでもうしばらく使い込んでみようと思います。

サイト移転時のリダイレクト関連のメモ

.htaccessとか

少し早めに「Nikola Tesla Center」から「SiReFaSo」への移転作業をしていました。師走にバタバタするのも何なので、余裕のあるうちに。

.htaccessでリダイレクトすればいいんだろーとタカを括っていたのですが、land.toサーバでは何か色々制限があって使えない記述があったりで苦労しました。後半でsitemixサーバについても触れてみます。

やりたいこと

「 http://nikola.ps.land.to/ntc/ 」およびそれ以下のディレクトリへのアクセスを「 http://sirefaso.appspot.com/ 」以下へマッピングさせる。ただし、「 http://nikola.ps.land.to/ntc/plugin/ntcmanager/ 」を除く。

pluginディレクトリ以下にはpluginの更新用ファイルが入っていて、起動時の更新の確認やネットワーク更新でアクセスがあるのですが、これはSiReFaSoに転送されても困るので。

普通に301リダイレクト

最初に書いたのはこんな感じのものです。

Redirect permanent /ntc/ http://sirefaso.appspot.com/

これで /ntc/ ディレクトリ以下に対するアクセスは全てSiReFaSoにマッピングされて転送されますが、plugin以下へのアクセスも転送されてしまいます。

RewriteRuleを使う

次に書いたのがこんな感じのものです。

RewriteEngine on
RewriteRule ^/ntc/((?!plugin).)*$ http://sirefaso.appspot.com/$1 [R=301]
RewriteEngine off

正規表現でpluginディレクトリだけを例外として、 /ntc/ ディレクトリ以下に対するアクセスをSiReFaSoにマッピングできます。

ローカルのApacheでは転送できたのですが、 land.to で試したら 500 Internal Server Error になりました。よくわかりませんが、使えないっぽいです。

RedirectMatchを使う

最初に書いたRedirectの親戚でしょうか、正規表現を使う書き方もできるんですね。

RedirectMatch permanent ^/ntc/((?!plugin).)*$ http://sirefaso.appspot.com/$1

これもローカルのApacheでは転送できたのですが、 land.to で試したら 500 Internal Server Error になりました。

下位ディレクトリであらためて.htaccess指定で上書きする

もうこれしか思いつきませんでした。 /ntc/ ディレクトリの.htaccessには最初に書いた通りにし、 /ntc/plugin/ntcmanager/ ディレクトリに.htaccessを置いて以下のように設定します。

Redirect gone /ntc/plugin/ntcmanager/

リダイレクトさえしなければ200を返しても構わないと思っていましたが、上位ディレクトリの指定をRedirectで上書きする必要があったので、もう更新しないしいっそ410 Goneでよかろう、という判断です。これでplugin更新問い合わせはSiReFaSoには来なくなりました。

ついでにsitemixについて

sitemixにある「ついっとゅう」の配布ページも移転したのでリダイレクトさせたいのですが、こちらは.htaccessそのものが使えません。PHPが使えるのでそれでなんとかしてみます。

http://nikola.sitemix.jp/twittyu/ へのアクセスのみで良いので、とりあえずindex.phpを作成して以下のように書きます。

<?php
header('HTTP/1.1 301 Moved Permanently'); 
header('Location: http://midolaso.appspot.com/tw/twittyu/'); 
?>

そしてindex.htmlを削除します。これが残っていると優先的に表示されてしまうので。これで転送されるようになりました。

301と302の違い?「移転しました」じゃダメなの?

上記では 301 Moved Permanently を使用しています。これは恒久的な転送という意味です。302 Found は一時的な転送。「べ、別に移転したわけじゃないんだからねっ!一時的なものなんだからっ!」という旨をGoogleさんに伝えるときは302を使います。

「移転しました」と書いたHTMLファイルをアップしただけでは 200 OK を返し続けることになるのでGoogleさんには移転のお知らせは伝わりません。移転するときは 301 Moved Permanently を返すのがWebに優しいエチケットみたいなものです。

GHOSTからNARとupdates2.dauを作成

DnDじゃなくて

GHOST自身が作成する方法

NAR

\![execute,compressarchive]を使う

さくらスクリプト@wiki - さくらスクリプト/未分類

updates2.dau

YAYAで頑張って作る

YAYAで頑張って作ってみた

100行プログラミング。 Download => daumaker.nar

  • developer_options.txtを読んで除外ファイルを考慮している。
  • profileフォルダやvarフォルダはデフォルトで除いている。
  • GHOSTのルートディレクトリにupdates2.dauが作成される。
  • updates2.dauの正式な書式の仕様って何処にあるの?
OnMenuExec
{
  "\![get,property,OnGetGhostPathFromPlugin,ghostlist(%(sender)).path]\e"

  res_event = 'OnPluginExec'
  res_reference[0] = "Version=%(version())"
  res_reference[1] = 'From=DauMaker'
}

OnGetGhostPathFromPlugin
{
  _path = reference[0]
  sys.fnc.MakeUpdates2Dau(SUBSTR(_path, 0, STRLEN(_path) - 1))

  res_event = 'OnUpdatedataCreated'
  res_marker = version()
}

sys.fnc.MakeUpdates2Dau
{
  _path = _argv[0]
  _delim = CHR(0x01)
  _ignore = sys.fnc.getIgnoeFiles(_path, _delim)
  _files = SPLIT(sys.fnc.getUpdateFiles(_path, _delim, _ignore), _delim)
  _fname = _path + '\updates2.dau'
  if !FOPEN(_fname, 'w')
    return
  foreach _files; _f {
    _relative_path = REPLACE(REPLACE(_f, _path + '\', ''), '\', '/')
    _hash = TOLOWER(FDIGEST(_f, 'MD5'))
    FWRITE(_fname, _relative_path + CHR(0x01) + _hash + CHR(0x01))
  }
  FCLOSE(_fname)
}

sys.fnc.getUpdateFiles
{
  _path = _argv[0]
  _delim = _argv[1]
  _ignorestr = _argv[2]

  _ignores = SPLIT(_ignorestr, _delim)
  if !_ignorestr; _ignores = IARRAY()
  _ignore_default = '\\profile|\\var|updates2\.dau|update\.txt|ngm\.dat'

  _fenum = FENUM(_path, _delim)
  if !_fenum; return
  _fs = SPLIT(_fenum, _delim)
  _ret = ''
  foreach _fs; _f {
    if RE_MATCH(_f, _ignore_default); continue
    _sub_ret = ''
    if SUBSTR(_f, 0, 1) == '\' {
      if ASEARCH(_path + _f + '\', _ignores) >= 0; continue
      _sub_ret = sys.fnc.getUpdateFiles(_path + _f, _delim, _ignorestr)
      if !_sub_ret; continue
    }
    else {
      if ASEARCH(_path + '\' + _f, _ignores) >= 0; continue
      _sub_ret = _path + '\' + _f
    }
    if _ret != ''; _ret += _delim
    _ret += _sub_ret
  }
  _ret
}

sys.fnc.getIgnoeFiles
{
  _path = _argv[0]
  _delim = _argv[1]

  _fname = _path + '\developer_options.txt'
  if !FOPEN(_fname, 'r')
    return

  _ret = ''
  while 1 {
    if (_line = FREAD(_fname)) == -1; break
    _params = IARRAY()
    foreach _line; _l {
      _params ,= CUTSPACE(_l)
    }
    if ASEARCH('noupdate', _params) >= 1 {
      if _ret != ''; _ret += _delim
      _ret += REPLACE(_path + '\' + _params[0], '/', '\')
    }
  }
  FCLOSE(_fname)

  _ret
}

version
{
  'DauMaker/1.0'
}

HTML5でinputのpattern属性とCSS

pattern属性

HTML5ではinputにpattern属性というのがあって、送信前に入力値を正規表現でチェックして制限できる。Operaなどは既にこの仕様に対応している。

<input type="text" name="postcode" value="" pattern="\d{3}-\d{4}" />

これは聞いたことがあったので、SoSiReMiでも使っているのだけれど、入力値の状態をCSSで感知できるというのを昨日知った。

以下で実際に試してみた。Opera, Safari, Google Chromeで入力値に応じて表示が変わる。Firefoxは3.6.11では対応していなかったので4に期待。

JavaScript無しでも色んなことができるようになって便利(その分覚えることが多いけど)。

続きを読む

共有変数プラグインを試してみた

共有変数プラグイン

SSP/2.2.42より標準添付された、ゴースト間共有変数処理用プラグインです。詳しくはreadme.txtを参照。

使ってみる

書き込み

readme.txtの41行目にOnSharedValueReadって書いてありますけどOnSharedValueWriteの間違いです。

{
  _pluginID = 'ABED14AF-F34B-4ff2-95B7-30ED37D5802D'

  _script = "\![raiseplugin,%(_pluginID),OnSharedValueWrite,きー,ばりゅー]"
  _script += '\0かきこみー\e'

  _script
}

readme.txtにもありますが、「ゴースト名」を指定することはできません。たぶんSenderを読んでるんだと思います(今回は「ごーすとじてん」)。別ゴースト領域への書き込みを防ぐための仕様のようです。

読み込み
{
  _pluginID = 'ABED14AF-F34B-4ff2-95B7-30ED37D5802D'

  _script = "\![raiseplugin,%(_pluginID),OnSharedValueRead,ごーすとじてん,きー,かー]\e"

  _script
}
OnSharedValueRead
{
  _script = '\0\_qごーすとじてんのでーた\n' + sys.fnc.ShowReference() + '\e'

  _script
}
sys.fnc.ShowReference
{
  _s = ''
  for _i = 0; _i < ARRAYSIZE(reference); _i++ {
    _s += "Reference%(_i): %(reference[_i])\n"
  }
  _s
}

//こんなresponseが返ってくる
//Reference0: ごーすとじてん
//Reference1: きー
//Reference2: ばりゅー
//Reference3: かー

先程保存した「きー」に対する「ばりゅー」が返ってきます。「かー」は存在しないので次のReferenceは空欄。これは他のGHOSTからも読めます(ていうかそのためのPLUGIN)。

リスト表示
{
  _pluginID = 'ABED14AF-F34B-4ff2-95B7-30ED37D5802D'

  _script = "\![raiseplugin,%(_pluginID),OnSharedValueGhostList]\e"

  _script
}
OnSharedValueGhostList
{
  _script = '\0\_q' + sys.fnc.ShowReference() + '\e'

  _script
}
sys.fnc.ShowReference
{
  _s = ''
  for _i = 0; _i < ARRAYSIZE(reference); _i++ {
    _s += "Reference%(_i): %(reference[_i])\n"
  }
  _s
}
//こんなresponseが返ってくる
//Reference0: ごーすとじてん

そのPLUGINを利用しているGHOSTのリストが返ってきます。

ちょっと意地悪をしてみる

SSPのタグを使わず直接PLUGINにrequestを投げてみます。

#define C_CRLF CHR(0xd)+CHR(0xa)

foo
{
  _dll_path = '..\..\..\..\plugin\shared_value\shared_value.dll'

  _r_load = LOADLIB(_dll_path)
  if _r_load == 0 {
    '\0失敗\e'
    return
  }
  //ホントはLOAD直後にversionをリクエストするのが流儀
  //だけど今回は省略

  _reqheader = "/
    GET PLUGIN/2.0%(C_CRLF)/
    Charset: UTF-8%(C_CRLF)/
    ID: OnSharedValueWrite%(C_CRLF)/
    Sender: AYA%(C_CRLF)/
    Reference0: hoge%(C_CRLF)/
    Reference1: fuga%(C_CRLF)/
    "
  _reqheader += C_CRLF

  _result = REQUESTLIB(_dll_path, _reqheader)//responseは 204 No Content

  UNLOADLIB(_dll_path)

  '\0書き込み完了\e'
}

YAYAはSAORIに限らず伺かのプロトコルなら何でも投げられます。今回はSenderをAYAとしたのでAYAさんの名前で保存されました。Senderを偽装ずれば他のGHOSTのデータを改竄できそう(やらないけど)。

何に使う?

YAYAから直接利用できたので当然他のPLUGINからも利用出来ます。ウチでも音楽再生PLUGINなどを公開していますが、再生リストを全てのGHOSTと共有可能にしてみるとか。音楽再生機能を持つGHOSTは数あれど、それぞれ登録し直さないといけないのも不便ですし。

…でもこれは全てのGHOSTに書き込み権限が無いと逆に不便ですね。もう少し色々考えてみようと思います。

ゴーストの更新を捕捉するあれやこれの予定

NTCとかSiReFaSoとか

SiReFaSoを稼働させてから4ヶ月が経過しました。独自に巡回が出来るようにしてからも目立った不具合もなく安定しているようです。

Nikola Tesla Centerの方は、11月末頃に稼働を停止して、1ヶ月ほど移転のお知らせを掲載した後、12月末以降はSiReFaSoに転送しようと考えています。

ただの巡回アンテナではありますが、私がまともに作ったWeb上のシステムとしては初めてのものでした。至らない点も多く不安定なものでしたが、改修を重ね、一年以上経過した今も尚稼働を続けることが出来ています。数百体のGHOSTが登録され、多くの方々に利用して頂きました。ありがとうごさいます。

大量のデータを扱えるよう作成し直したSiReFaSoの方を、これからもどうぞよろしくお願い致します。

NAR専用アップローダーを作ってみた

NAR専用アップローダー

こんなのを作ってみました。

SoSiReMi - 伺かアップローダー

いきさつ

ついっとゅう」置き場をGoogle App Engineに引っ越そうと思って認証まわりの機能も全部移植したのですが、FTPが使えないのでネットワーク更新をどうしたものか悩んでいました。そこでHTTPで直接NARごとアップして、サーバー側でZIP展開して再配置してみたところ、思い通りに動いたので、誰でも使えるようにアップローダーにしてみました。

仕様

何も考えずにNARをアップしただけで勝手にネットワーク更新に対応されます。

  • descript.txtにcraftmanurlとhomeurlが無い場合アップロードされたページのURLを自動補完
  • type,ghostとか書いてない場合も自動補完
  • updates2.dau自動作成
  • readme.txtやthumbnail.pngのプレビュー
  • 簡易アクセス解析機能付き
  • SiReFaSoに自動登録
出来ないこと
  • calendar skin, calendar plugin, directory service setting, supplement 非対応
  • 複数インストール形式(ghost with plugin/headline等)非対応
  • 10MB以上のNARは無理

でも、お高いんでしょう?

今ならゴーストフォルダを登録してクリック一つでアップロードできる更新支援ツールが無料で付いてきます。

SoSiReMiUpdater.zip

WindowsXP以降、.NET Framework 2.0以上で動きます。

narをアップするところという便利なものが既にあるわけで

更新を予定していてネットワーク更新対応が難しい場合はSoSiReMiを使ってみてはいかがでしょうか。配布ページとしてブログに紹介記事を書いてNARに直リンみたいな使い方でもいいと思います(「ついっとゅう」もそうしています)。

せっかく作ったのでどなたか使ってやってください。

Ghostの配布サイトURLで検索できるBookmarklet

URL検索できるBookmarkletを書いた

NTCの検索窓の下に配布サイトURL用検索窓を足すBookmarkletを書いてみました。IE6でも動作します。

Add URL Search Box on NTC - Hatena::Let

ファイル 88-1.png

特定ドメインのサイトのGhostを探す時に便利かもしれません。

配布元が移転した場合

Ghostの配布元やhomeurlが変更された場合にそれを自動で検出する手段がないので、以後の更新が捕捉できなくなります(登録し直した場合は新しい方のデータで上書きできます)。サイトが消滅した場合は3時間後には自動的にデータが削除されます。

プログラミンで遊んでみた

プログラミン

文部科学省SUGEEEEEE

作ってみた

続きを読む

SSP/2.2.36 の \[enter/leave,selectmode] を試してみた

SSP/2.2.36 の新機能

SSP/2.2.36で新たにShell上でマウスによる範囲選択を行うための仕様が追加されています。

Ghostは通常マウスでドラッグされるとマウスと一緒にShellが動いていくわけですが、範囲選択モードの状態ではShellが固定され、選択された座標がSHIORIに通知されます。

ファイル 86-1.png

Ghostの当たり判定を囲めば、Coordinの代わりになりそうです。

*
:選択してねー。\![enter,selectmode,rect]

*OnSelectModeBegin
#選択モード開始

*OnSelectModeMouseDown
$nop【タブ】(split(バイト値,1)(R2)(バイト値,1),)
$X1【タブ】(S0)
$Y1【タブ】(S1)

*OnSelectModeMouseUp
$nop【タブ】(split(バイト値,1)(R2)(バイト値,1),)
$X2【タブ】(S0)
$Y2【タブ】(S1)
:\![leave,selectmode]うぃ。
選択された領域は「(X1),(Y1),(X2),(Y2)」だね。
$nop【タブ】
$X1【タブ】
$Y1【タブ】
$X2【タブ】
$Y2【タブ】