ヤルキデナイズド

Unclassified Articles on Software and IT

Dark Souls: The Board Game ルールブック意訳

ダークソウルのボードゲームのルールブックを意訳しています。文章の構成は原文を踏襲していますが、文意が読み取りづらい箇所・絵や実物を見ないと分かりづらい箇所は適宜言い回しを変えたり、ヒントを補ったりしてあります。

2017年9月10日現在、後半のいくつかのセクションは翻訳作業中です。


ゲームの準備

セットアップ

まずマップタイルを配置していく。周囲に余裕がある場所に篝火タイルを置く。ミニボスタイルとメインボスタイルはしばらく使わないので除けておく。(ヒント:マップタイルは箱と同じ大きさの正方形のタイル。篝火タイルは丸いマスが描かれていないマップタイル。ミニボスタイルは中央にドクロのマスがあるマップタイル。メインボスタイルは中央にドクロ+王冠のマスがあるマップタイル。)

残り6枚の通常タイルをシャッフルしランダムに4枚を選ぶ。篝火タイルを始点に、タイル四辺に描かれた出入口が繋がるようにして好きに並べる。選ばなかった残り2枚の通常タイルは使わないので箱に戻す。篝火タイルからもっとも遠い通常タイルの、他のタイルと接していない出入口に霧の入口トークンを置く。(ヒント:普通のタイルは丸いマス目が描かれたマップタイル。両面あり、どちらを表にしてもよい。霧の入口は親指大の白い板。)

篝火スパークダイヤルを篝火タイルに置く。ダイヤルの切り込みから見える数字は(6−プレイヤー人数)に合わせる。

ミニボスのモデル1体を好きに選び、そのミニボスの遭遇カードと行動カードのセットを用意する。(ヒント:ミニボスの遭遇カードと行動カードは大きいほうのカード。そのミニボスの絵が描いてある。)

遭遇カードをレベルごとの山に分けてそれぞれシャッフルする。(ヒント:遭遇カードは小さいほうのカードで、背面に紫の円+ソウルのマークが描かれている。レベル1〜3の3種類)

ミニボスの遭遇カード下辺に書いてある遭遇レベルを見て、対応するレベルと枚数の遭遇カードを山から引き、通常タイルの上に1枚ずつ伏せて置く。ただし、篝火タイルに近いほどレベルが低く、遠くなるにつれて高くなるように置いていく。使わなかった遭遇カードは箱にしまう。

プレイヤーにキャラクターボード、キャラクターモデル、初期装備カードを配る。(ヒント:初期装備カードは小さいほうのカード。表面右上に、キャラクターのクラスに応じた武器のアイコンが描いてある。)

(ヒント:以降、「キャラクター」はプレイヤーの分身となる登場人物を指す。敵のことはキャラクターと呼ばない。)

初期装備の武器・防具をキャラクターボードの右手・左手スロットに好きに置く。鎧を体スロットに置く。エスト瓶トークン、アクショントークン、幸運トークン各1個を、表(絵が明るいほう)を上にして、ボードの対応するマークに置く。ボードの各能力値バーの Base レベルに白いキューブを置く。

共通トレジャーカード、クラス別トレジャーカード(参加キャラクター分のみ、各クラス5枚)をまとめてシャッフルし、トレジャーデッキとして篝火タイルに置く。(ヒント:トレジャーカードは小さいカード。共通トレジャーカードは表面右上に宝箱アイコンがあって、アイコンに他のマークが付加されていないもの。クラス別トレジャーカードは宝箱アイコンの上にクラスを表す白い武器マークがあり、かつ青いマークがないもの。)

残りのトークンをプレイヤーの手の届く場所に置く。

ミニボス撃破後のメインボスセットアップ

配置されている篝火タイル以外のマップタイルを回収し、初期セットアップと同様の手順で配置しなおす。篝火スパークダイヤルを初期値まで回復する。

メインボスのフィギュアとカードのセットを選び、初期セットアップと同様に遭遇カードを選んで配置しなおす。

キャラクターモデルを篝火タイルに配置し、スパークを消費せずに休息効果を得る。

すでにあるトレジャーデッキに次のカードを加えてシャッフルする:クラス別の変異トレジャーカード(参加キャラクター分のみ、各クラス5枚)と、ランダムに5枚選んだ伝説のトレジャーカード。(ヒント:変異トレジャーカードは、トレジャーカード表面右上に宝箱アイコン+クラスを表す白い武器マーク+青いマークがあるもの。伝説のトレジャーカードはボスの顔アイコン+赤いマークがあるもの。)

篝火タイル

XXX 翻訳中……

マップのノード

マップタイルに描かれた黄色・ピンク・赤のマス目をノードと呼ぶ。

  • ノードの種類
    • 黄色:普通のノード
    • 赤:遭遇ノード
    • ピンク:地形ノード
    • ドクロマーク:ミニボスノード
    • ドクロ+王冠マーク:メインボスノード
  • タイルの出入口のある辺に隣接するノードは「進入ノード」でもある。(ヒント:遭遇時にキャラクターモデルを置く場所は進入ノードのいずれかとする。)
  • あるノードから縦横ナナメの8方向で隣り合うノードは、そのノードの「隣接ノード」と呼ぶ。

戦闘中、1つのノードに複数のモデルを置くことがある。ただし1つのノードに置ける数には上限がある。

  • 1つのノードに置けるモデルは3つまで。4つめのモデルが進入すると他のモデルを押し出す。
  • 1つのノードに置けるボスモデルは1つまで。2つめのボスが進入すると1つめを押し出す。

(ヒント:押し出されるモデルの候補が複数ある場合、プレイヤーが好きに1つ選ぶ。押し出されたモデルはプレイヤーが好きに選んだ隣接ノードに置く。)

装備について

  • プレイヤーは左右の手スロットに各スロット1つまでの片手武器を装備できる。または片方の手スロットに1つの両手武器を装備できるが、その場合他方の手スロットには何も装備できない。
  • プレイヤーは合計3つまでの武器を所持でき、手スロットに装備していないものは予備スロットに置く。

キャラクターの能力について

キャラクターはいくつかの能力を持っている。能力はキャラクターボード上のトークンで表される。能力は一度使うと篝火で休息するまで使えなくなる。(ヒント:「休息するまで使えない」は英語で once per spark と説明される。)

  • 特殊アクション:トークンが表のとき裏返して特殊アクションを使う。(ヒント:特殊アクションはキャラクターボード左上の囲みに書いてある。使えるタイミングはクラスごとに異なる。)
  • エスト瓶:トークンが表のとき裏返して、自分の耐久バーの黒キューブと赤キューブをすべて除去する。(ヒント:キャラクターの手番中のみ使える。)
  • 幸運:トークンが表のとき裏返して、自分の攻撃・防御・回避の判定ダイスいずれか1個を振り直す。

以上の3つの能力はゲーム開始時には使える状態になっている。残り火だけは、トレジャーデッキから残り火カードを引いたら使えるようになる。

  • 残り火:トークンを持っている間ならいつでも、3以上のダメージを受けたとき1ダメージ軽減する。残り火カードをトレジャーデッキから入手したとき、残り火を持っていない好きなキャラクター1人のボードに残り火トークンを置く。パーティーが敗北して篝火に戻ったらすべてのキャラクターボードの残り火トークンを取り除く。(ヒント:残り火トークンに裏表はない。残り火は1キャラクター1個まで持てる。すべてのキャラクターが残り火を持っているときにトレジャーデッキから残り火カードを引いたら、それをデッキに戻してシャッフルし、引き直す。)

探索

ゲーム中、パーティーはマップタイル四辺の出入口を通じて隣のタイルに移動できる。ただし遭遇状態では移動できない。裏向きの遭遇カードのあるタイルにパーティーが進入すると遭遇状態となり、遭遇カードを表にして敵との戦闘を開始する。敵との戦闘に勝利したら遭遇カードは表のまま置いておく。以降そのマップでは遭遇状態にならない。霧の入口のあるマップタイルで戦闘に勝利して遭遇カードを表にしたら、以降は遭遇状態でなければいつでもボス戦を開始できる。

パーティーが敗北するか自ら選ぶかして篝火で休息したら、すべてのマップタイルの遭遇カードを裏返す。裏向きの遭遇カードがあるマップタイルに進入したら再び遭遇状態になる。(ヒント:篝火で休息したら霧の入口の状態もリセットされる。ボス戦を始めるには再び霧の入口のあるマップタイルを攻略しなければならない。)

遭遇のセットアップ

敵と遭遇したら、そのマップタイルに敵モデルや地形トークンを配置して戦闘の準備をする。

1ゲーム中に同じマップタイルで何度も遭遇することがあるため、前回の遭遇で配置したトークンが残っていれば、まずその処理を行う。

  • トークンが残っていればすべて表向きにする。(ヒント:樽トークンの表面は樽が壊れていないほう。)
  • トークンが残っていればすべて裏返す。(ヒント:罠トークンの裏面は黄色いマークのあるほう。)
  • 宝箱トークンはそのままの向きで置いておく。(ヒント:つまり、パーティーが篝火で休息しても宝箱は復活しない。)

  • 遭遇カードの情報をもとに、タイルに敵モデルと地形要素(樽・宝箱・墓石)トークンを配置する。

  • そのタイルで初めての遭遇のとき:遭遇カード下辺に罠マークが描かれているなら、使っていない罠トークンすべてを裏返してよく混ぜ、タイルの通常ノードに1個ずつ裏向きで置く。ただし通路のある壁沿いの通常ノードには置かない。

罠と宝箱について

  • 遭遇中、裏向きの罠トークンのあるノードにキャラクターが乗ったら、トークンを表にして罠を発動する。プレイヤーは罠ダメージを防御できないが、回避を試みることはできる。一度発動した罠は、その遭遇中は表のままにし、二度と発動しない。罠は敵によっては発動しない。
  • 宝箱はそのタイルのすべての敵を倒した後で開けられる。開けたらトレジャーカードデッキから2枚引く。いずれかのキャラクターが装備可能ならすぐに装備してもよい。装備しなかったカードは篝火タイルのインベントリに送る。

遭遇の流れ

  • そのゲームの初めての戦闘なら、最初に行動するキャラクターを好きに選ぶ。そうでなければ、前回の戦闘で最後に行動したキャラクターの次のキャラクターが最初に行動する。
  • 最初に行動するキャラクターにアグロトークンを乗せる。(ヒント:アグロトークンはドクロマークのトークン。 Aggro は「敵に狙われている状態」という意味。)
  • 戦闘を開始する。戦闘では1キャラクターが行動→すべての敵が行動→次のキャラクターが行動(時計回りの順)→すべての敵が行動……を繰り返す。
  • 敵をすべて倒し、キャラクターが誰も死んでいなかったらパーティーの勝利となる。キャラクターが1人でも死んだ時点でパーティーは敗北し、篝火タイルに戻って休息を行う。

戦闘の基本

XXX 翻訳中…

メモ:攻撃の対象は普通1つのノードの1体、または1つのノードの全員(味方同士、敵同士は攻撃し合わない)。ボスのみ複数ノードへの攻撃ができる。 攻撃を防御または resist し、ダメージが0になってもヒット扱いになる。押し出しなどの効果は受ける。回避するとヒットではない。 スタミナを消費すると耐久バーに左から黒ブロックを1個置く。 ダメージを受けると耐久バーに右から赤ブロックを1個置く。 10ブロック溜まるとキャラクターは死ぬ。一人でも死ぬとパーティーは負け。

押し出しはスタミナを消費しない。ボスは押し出されない。押し出し先はアクションしたモデルから最も遠い隣接ノード。候補が複数あればプレイヤーが好きに選ぶ。 敵の移動に押し出し効果がある場合、移動先ノードのプレイヤーキャラクターは押し出される先を選んで移動する。

コンディションは複数種類を同時に受けることがある。同一の効果は重複しない。コンディションを持つモデルの行動が終わったらコンディションを取り除く。また遭遇が終わったらキャラクターからコンディションを取り除く。 出血:攻撃されたら追加ダメージ2を受ける。一度攻撃を受けたら出血効果は解消される。 毒:行動の終わりに1ダメージを受ける。 凍傷:歩行、走行、回避の消費スタミナが1増える。敵が凍傷になったら、移動力の値を1減らす。 よろめき(stagger):武器アクションの消費スタミナが1増える。敵がよろめき状態になったら、攻撃力を1減らす。

キャラクターの行動

キャラクターの行動開始時に以下の処理を行う。

  • スタミナを2得る(=黒キューブを2個取り除く)。
  • アグロトークンを得る。
  • 左右の手スロットと予備スロットの装備を入れ替えてもよい。

次に移動と攻撃を行う。どちらが先でもいいが、移動→攻撃→移動はできない。

キャラクターの移動には3種類ある。

  • 歩行:1行動中に1回だけ。スタミナ消費なしで1ノードに移動する。
  • 走行:1行動中に何度でも。1スタミナを消費して1ノード移動する。
  • 回避:敵の行動中に、キャラクターが攻撃を受けたら回避を試みることができる。移動したければ1ノード移動し、次に回避判定ダイスを振る。

(ヒント:移動は必ず隣接ノードを経由する。上記の移動のほかに、押し出し効果を受けてノードを移動することがある。)

攻撃は左右の手スロットに装備した武器を使い、最大1回まで行える。武器には何段階かの強さの攻撃方法を持つ。 [n] の数のスタミナを消費し、描かれた色と個数の攻撃判定ダイスを振って、出目の合計を攻撃ダメージとする。

XXX 攻撃ダメージの処理について……

攻撃のアイコンについて:

  • 黒、青、オレンジのダイスアイコン:攻撃判定ダイス。出目は黒<青<オレンジの順で強い。
  • 独自の射程(武器を振るアイコンと数字):攻撃によっては武器カードに描かれた基本の射程とは異なる射程を持つ。
  • シフト(十字アイコンと数字):シフトアイコンがダイスアイコンの前にあれば、最大で表示された数のノードぶん、攻撃の前に移動できる。シフトアイコンがダイスアイコンの後ろにあれば、同様に攻撃の後に移動できる。移動はスタミナを消費せず、歩行や走行としてカウントされない。
  • 範囲攻撃(●アイコン):攻撃対象の1ノードにいるすべての敵にダメージ。攻撃判定ダイスを振るのは1回だけ(=敵ごとに振らない)。
  • 遠距離武器(槍のアイコンと0):自分と同じノードにいる敵を攻撃対象にできない。主に槍と弓につく。
  • 連続攻撃(回る矢印のアイコンと数字):攻撃を複数回行う。1回ごとに攻撃方法を選んで攻撃判定ダイスを振る。

敵の行動

脅威レベルの高い敵から順に行動する。同レベルならプレイヤーが順番を選ぶ。(ヒント:脅威レベルは敵の行動カード左上の数字。)

敵の移動パターン(敵の行動カードの十字マークで表される):
  • 標的となるキャラクターを定める。
    • 十字マーク右上のアイコンが○:もっとも近いキャラクターを標的とする。
    • 十字マーク右上のアイコンがドクロ:アグロトークンを持つキャラクターを標的とする。
    • 標的の候補が複数いる場合、次の条件を順に見てマッチするキャラクターを選ぶ:アグロトークンを持つ→挑発(Taunt)レベルが高い
  • 十字マークの上辺の数字ぶん近づく、または下辺の数字ぶん遠ざかる。
    • 近づいて標的と同じノードに到達するか、遠ざかってマップタイルの隅に接したらそれ以上移動しない。
    • 複数ノードを移動する場合、標的は最初に決めた相手とする=移動1ステップごとに判定しない。
  • 十字マーク左上のアイコンが盾:押し出し効果。盾アイコンに数字があれば押し出しダメージ効果。移動先の各ノードで押し出し判定をする。敵が元いたノードにいるキャラクターは押し出し対象にならない。

移動の経路となるノードの候補が複数あるときはプレイヤー好きに選ぶ。

敵の攻撃

XXX 翻訳中……

敵の攻撃力は固定値。防御するプレイヤー側が相殺の度合いをダイスロールで決める。物理攻撃ならキャラクターの物理防御力で相殺し、魔法攻撃ならキャラクターの魔法耐性で相殺する。相殺した結果ダメージが0になっても押し出し効果や状態効果は通常通り受ける。

物理防御力を計算するには、キャラクターの左右の手スロットと鎧スロットに装備しているアイテムを見る。それらのアイテムカードの左下の盾アイコンに描かれた色と個数のダイスをまとめて振り、出目を合算した値が物理防御力になる。魔法耐性を計算するには、装備しているアイテムカードの左下、盾アイコンの右隣にある丸いアイコンを参照して、同様にダイスを振る。

キャラクターは防御をしない代わりに回避を試みることができる。まず1スタミナを消費する。移動したければ隣接ノードに移動してもよい。装備しているアイテムカードの回避アイコンを見てに描かれた個数の回避ダイスをまとめて振る。敵の遭遇カード右端の回避難易度を見て、出目が回避難易度の数値と等しいか上回れば回避に成功し、キャラクターはダメージも効果も受けない。回避に失敗すれば通常通りにダメージと効果を受ける。

ボスの行動

XXX 翻訳中……

ボスの台座には十字の線が入っており、その延長線をもってマップタイルを4つの象限に区切る。象限の境目にいるキャラクターは両方の象限に属する扱いになる。キャラクターがボスと同じノードへと移動したら、直前にいた象限と同じ象限に属することとする。ボスのいるノードから離れるときは同じ象限内のノードに移動する。(ヒント:たとえば、ボスがいるノードに正面から入ったら離れるときは正面方向にしか移動できないということ。正面から背後に回り込むにはボスから離れたノードを大回りする必要がある。)

マップタイルの隅でボスがキャラクターを押し出してキャラクターが移動するとき、キャラクターが今いる象限の中に移動できるノードがなければ、壁沿いの好きな隣接ノードに移動する。

ボスを移動させるときはモデルの向きを常に意識する。台座の十字の延長線がノードを横切るように、つまりボスは8方向のいずれかを向くようにすること。ボがスキャラクターを標的にして近づくように移動する場合、まず標的のいるノードが正面の象限に収まるようにボスを向け、それから移動する。逆に標的から遠ざかるように移動する場合、まずボスの隣接ノードのうち標的からもっとも遠いノードが背面の象限に収まるようにボスを向け、それから移動する。(ヒント:バックする形になる。)

ボスの行動カードの、十字の移動マーク右上に標的アイコンがない場合、ボスは向きを変えずに移動する。

ボスの直前の行動カードには、ボスの攻撃の対象になる緑象限、攻撃の対象にならない黒象限、防御力が弱まる赤象限がある。赤象限に対する攻撃はロールするダイスを1追加する。


メモ

  • 左右の手スロットそれぞれに攻撃可能なアイテムを装備している場合、1回の攻撃行動中にそれぞれ1回まで攻撃を行うことができる。

avr-gcc 6.2.0 で qmk_firmware のビルドに失敗したメモ

TL:DR; avr-gcc49 を使えばよい。

背景

Ergodox EZ というキーボードを所有しているのだが、これは qmk_firmware というファームウェアを書き込んで動作カスタマイズできる。 Mac でビルドするには

brew tap osx-cross/avr
brew install avr-libc
brew install dfu-programmer

cd /path/to/qmk_firmware/keyboard/ergodox_ez
make KEYMAP=$my_keymap

とする。

ビルドが失敗するようになった

avr-gcc のバージョンを6.2.0に上げたらビルドが失敗するようになった。エラーログは以下:

$ make KEYMAP=uasi

-------- begin --------
avr-gcc (GCC) 6.2.0
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.


Size before:
   text    data     bss     dec     hex filename
  18144      52     191   18387    47d3 ergodox_ez.elf


mkdir -p obj_ergodox_ez
Compiling C: ergodox_ez.c
avr-gcc -c -mmcu=atmega32u4 -gdwarf-2 -DF_CPU=16000000UL -DINTERRUPT_CONTROL_ENDPOINT -DBOOTLOADER_SIZE=512 -DF_USB=16000000UL -DARCH=ARCH_AVR8 -DUSB_DEVICE_ONLY -DUSE_FLASH_DESCRIPTORS -DUSE_STATIC_OPTIO
NS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)" -DFIXED_CONTROL_ENDPOINT_SIZE=8  -DFIXED_NUM_CONFIGURATIONS=1 -DPROTOCOL_LUFA -DBOOTMAGIC_ENABLE -DMOUSEKEY_ENABLE -DMOUSE_ENABLE -
DEXTRAKEY_ENABLE -DNO_PRINT -DNO_DEBUG -DCOMMAND_ENABLE -DNKRO_ENABLE -DSLEEP_LED_ENABLE -DNO_SUSPEND_POWER_DOWN -DVERSION=518562f -Os -funsigned-char -funsigned-bitfields -ffunction-sections -fdata-secti
ons -fno-inline-small-functions -fpack-struct -fshort-enums -fno-strict-aliasing -Wall -Wstrict-prototypes -Wa,-adhlns=obj_ergodox_ez/ergodox_ez.lst -I. -I../.. -I../../tmk_core -I../../quantum -I../../qu
antum/keymap_extras -I../../quantum/audio -I../../tmk_core/protocol/lufa -I../../tmk_core/protocol/lufa/LUFA-git -I../../tmk_core/common -std=gnu99 -include config.h -MMD -MP -MF .dep/obj_ergodox_ez_ergod
ox_ez.o.d  ergodox_ez.c -o obj_ergodox_ez/ergodox_ez.o
In file included from ../../tmk_core/common/matrix.h:21:0,
                 from ergodox_ez.h:4,
                 from ergodox_ez.c:1:
/usr/local/Cellar/avr-gcc/6.2.0/lib/gcc/avr/6.2.0/include/stdint.h:9:26: fatal error: stdint.h: No such file or directory
 # include_next <stdint.h>
                          ^
compilation terminated.
make: *** [obj_ergodox_ez/ergodox_ez.o] Error 1

avr-gcc をダウングレードしたらビルドできるようになった

avr-gcc を4.9にダウングレードしたらビルドできるようになった。ダウングレードの手順は以下:

brew unlink avr-libc avr-gcc
brew install avr-libc49
brew link avr-libc49 avr-gcc49

npm パッケージの unpublish に関するゴタゴタの大まかなまとめ

(最終更新:3月24日16:50ごろ)

事件の流れ

何が問題だったのか

npm の仕様

  • パッケージの所有者がパッケージを unpublish できるようになっていること
    • メジャーなパッケージマネージャの多くは unpublish に相当する操作をユーザーに提供しない
    • 代わりとして unlist (NuGet)yank (Cargo) といった操作を提供することがある
    • unlist/yank されたパッケージはリポジトリの一覧には表示されなくなるが、依存解決中にそのパッケージをダウンロードすることは可能
    • 本当の緊急時のみリポジトリ管理者の手でパッケージが削除されることはある
  • unpublish されたパッケージのネームスペースを他人が乗っ取れるようになっていること
    • 同一バージョンの再 publish はできないものの、別のバージョンで悪意のあるコードを publish すると依存元パッケージを攻撃できる可能性がある

人的要因

  • 代理人と作者のやりとりにおいてお互いの態度がよろしくなかったこと
  • 法務関係の事態とはいえ、 npm 運営が作者の許可を得ずパッケージを unpublish したパッケージの所有権を移し替えたこと
    • npm のパッケージ名に関する紛争解決ポリシーによれば、ユーザー間で問題が解決できなければ運営が調停するとされる
  • 抗議のためとはいえ、作者が多数のパッケージを一度に unpublish したこと
    • 混乱を招くことは承知していたようだが、 left-pad に依存する babel まで壊れることは予測していなかったと思う
  • npm 運営が社内の合意もおろそかに unpublish の取り消しを実行したこと

関連記事

余談:

  • 一般的なパッケージマネージャのつくりに興味がある人にはこの記事がおすすめ。 Go のパッケージマネージャを新規設計する視点から問題領域などを分析してる:So you want to write a package manager — Medium
    • “パッケージ管理は厄介な領域だ。本当に厄介だ。表面上は純粋に技術的に解決可能と見える。そう考えて取り組んだ者は皆、避けがたい次なる結論に至る:ソフトウェアはおそろしい。人々はおそろしい。シナリオは無数にあり、何ひとつまともには動かない。証明可能なことに、何ひとつまともには動かない。人生とは逆巻くカオスとエントロピーの渦の中の無意味な摂動。”

感想

  • JS 界隈に単機能モジュールを多数組み合わせて使う風潮があるため被害が広がったなという感じ
  • unpublish 操作はユーザーに開放しないほうがいいと思う
    • npm は他のパッケージリポジトリと比べてパッケージ数が桁違いに多いため、 npm 社としては unpublish を依頼制にしたくないんだろうけど
    • パッケージ作者に無断で管理者がパッケージを削除することは、法に反するコンテンツを含む場合などはやむを得ないだろうが、今回のケースは微妙
  • Objective-C/Swift のパッケージマネージャ CocoaPods は Pods ディレクトリ(依存先パッケージのソースコードを集約するディレクトリ)をバージョン管理することを推奨している。こうすると万が一依存先パッケージが削除されても影響を受けない。デメリットもあるがよいプラクティスだと思う

ブコメ返信

id:teppeis

今回のケースではunpublishが禁止されても乗っ取りは防げるけどエコシステムの破壊は免れなかった。iOS詳しく知らないけどCocoaPodsはプラットフォーム限定できてビルド不要という違いがあるのでは。

ユーザーによる unpublish が禁止されていたとしたら、管理者権限での kik の unpublish によって依存関係が壊れることこそ免れないものの、その他多数のパッケージの突然の unpublish は為されず、被害は比較的小さく済んだはず。

CocoaPods で Pods ディレクトリのバージョン管理が現実的なのは、 Pods ディレクトリにパッケージのソースコードだけが保存されるから。ビルドは必要だが生成物は別のディレクトリに出力される。

ソースコードとプラットフォーム依存のバイナリを同じディレクトリに保存する npm や Ruby の Bundler などでは真似できなそう。

Mac の Safari のキャッシュから画像その他を取り出すメモ

(以下の内容は Safari 8.0.6 現在のもの)

~/Library/Caches/com.apple.Safari/fsCachedData に blob が保存されている。 file コマンドで画像かどうか判別して適当に拡張子をつけてやれば復元できる。

% file fsCachedData/000DFAD8-B02E-47A2-AFA0-36D985C47D20
(略)/000DFAD8-B02E-47A2-AFA0-36D985C47D20: PNG image data, 64 x 64, 8-bit/color RGBA, non-interlaced

Finder で blob ファイルを選ぶと上手いことプレビューしてくれるのでそれでもいい。

f:id:uasi:20150619104639p:plain

その他レスポンスデータなどは ~/Library/Caches/com.apple.Safari/Cache.db に記録されている。これはただの SQLite3 データベースファイル。 BLOB カラムには binary plist らしきものが入っている。

% sqlite3 Cache.db 'SELECT * FROM cfurl_cache_schema_version;'
104

% sqlite3 Cache.db .schema
CREATE TABLE cfurl_cache_schema_version(schema_version INTEGER);
CREATE TABLE cfurl_cache_response(entry_ID INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,     version INTEGER, hash_value INTEGER, storage_policy INTEGER, request_key TEXT UNIQUE,   time_stamp NOT NULL DEFAULT CURRENT_TIMESTAMP, partition TEXT);
CREATE TABLE cfurl_cache_blob_data(entry_ID INTEGER PRIMARY KEY, response_object BLOB, request_object BLOB,               proto_props BLOB, user_info BLOB);
CREATE TABLE cfurl_cache_receiver_data(entry_ID INTEGER PRIMARY KEY, isDataOnFS INTEGER, receiver_data BLOB);
CREATE INDEX request_key_index ON cfurl_cache_response(request_key);
CREATE INDEX time_stamp_index ON cfurl_cache_response(time_stamp);
CREATE INDEX proto_props_index ON cfurl_cache_blob_data(entry_ID);
CREATE INDEX receiver_data_index ON cfurl_cache_receiver_data(entry_ID);

cfurl_cache_response.request_key は URL の文字列。ただし末尾に '[' + request_host + ']' が付属している場合がある。

cfurl_cache_receiver_data.receiver_data は UUID の文字列(大文字ハイフン区切りの形式)。 fsCachedData ディレクトリに UUID を名前とするバイナリファイルが格納されている。

はてなブログのプロフィールに Qiita と Twitter のリンクを追加する

サイドバーのプロフィールを便利にしたかったのでしてみた。サイドバーには任意のリンクを表示する項目も追加できるが、場所を取るので今回は使わなかった。

f:id:uasi:20150331193721p:plain

このようにはてなIDの横に Qiita と Twitter のIDを並べることにした。プロフィール部分はユーザーがカスタマイズできるようになっていないため、 JavaScript でガッと書き換える。

はてなブログのダッシュボードを開き、「設定>詳細設定>headに要素を追加」に以下のコードを書いた。

<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css" rel="stylesheet">
<script type="text/javascript" src="//code.jquery.com/jquery-2.1.3.min.js"></script>
<script type="text/javascript">
// <!--
jQuery.noConflict();
jQuery(function() {
  jQuery('.hatena-module-profile a.hatena-id-link').after(
    ' / <a href="http://qiita.com/uasi">' +
    '<span class="fa-stack" style="font-size: 50%">' +
    '<i class="fa fa-square fa-stack-2x"></i>' +
    '<i class="fa fa-search fa-stack-1x fa-inverse fa-2x"></i>' +
    '</span>' +
    'uasi</a>' +
    ' / <a href="https://twitter.com/uasi">' +
    '<i class="fa fa-twitter"></i>' +
    'uasi</a>'
  );
});
// Qiita icon is adapted from http://qiita.com/hkusu/items/fda8d8178dd693f95f3c
// -->
</script>

うまくいったので満足。

なお Font Awesome の既存アイコンを重ねて Qiita のロゴ風にする技はFontAwesome - Font Awesome で Qiitaロゴっぽいアイコンを表現 - Qiitaを参考にさせていただいた。

Safari に Flash Player をインストールできないときはオフラインインストーラを使うとよさそう

SafariFlash Player プラグインをアップデートしろとせっつくのでインストールしようとしたが、何度やってもエラーが出る。

f:id:uasi:20150130103810p:plain

いろいろ試してもダメだったので別のページからインストーラをダウンロードしたらあっさりインストールできた。

Adobe Flash Playerの配布 | Adobe

↑このページの “DMGインストーラーのダウンロード”(.dmg 直リンク)からダウンロードした。

今回インストールできなかったのはバージョン16だったが、バージョン12か13のときもインストールできず、その次のバージョンのベータ版をインストールした覚えがある。

Adobe のフォーラムのスレッドを見るに、管理者権限のないユーザーがオンラインインストーラを使うと発生する問題のようだ。ベータ版はオフラインインストーラなのでうまくいったということか。


環境:

いろいろ試してダメだったこと:

  • Safari 以外のアプリケーションもすべて終了
  • Flash Player プラグインをアンインストール
  • ディスクユーティリティでアクセス権を修復
  • インストーラをディスクイメージから取り出してデスクトップに置く(→実行するとダイアログが空になる不具合が出た)

インストールに失敗したときのログ( ~/Library/Logs/FlashPlayerInstallManager.log ):

2015-01-30 10:35:23 +0900 [I]  IM: ---------- log start ----------
2015-01-30 10:35:23 +0900 [I]  IM: All install checks pass
2015-01-30 10:35:23 +0900 [W]  IM: Unexpected umask value for process: 0
2015-01-30 10:35:23 +0900 [I]  IM: User does not have any processes that need to be closed.
2015-01-30 10:35:23 +0900 [I]  IM: [install started]
2015-01-30 10:35:23 +0900 [E]  RA: Unable to launch FPInstallHelper. Error = 'launch path not accessible'

2015-01-30 10:35:23 +0900 [E]  RA: 
Attributes for '/var/folders/zz/zyxvpxvq6csfxvn_n0000000000000/T/FPInstallHelper':
 {
    NSFileCreationDate = "2015-01-23 21:28:30 +0000";
    NSFileExtensionHidden = 0;
    NSFileGroupOwnerAccountID = 0;
    NSFileGroupOwnerAccountName = wheel;
    NSFileHFSCreatorCode = 0;
    NSFileHFSTypeCode = 0;
    NSFileModificationDate = "2015-01-23 21:28:30 +0000";
    NSFileOwnerAccountID = 0;
    NSFileOwnerAccountName = root;
    NSFilePosixPermissions = 2541;
    NSFileReferenceCount = 1;
    NSFileSize = 22784;
    NSFileSystemFileNumber = 31520882;
    NSFileSystemNumber = 16777220;
    NSFileType = NSFileTypeRegular;
}

2015-01-30 10:35:23 +0900 [E]  RA: 
Attributes for '/var/folders/zz/zyxvpxvq6csfxvn_n0000000000000/T':
 {
    NSFileCreationDate = "2014-10-05 06:07:38 +0000";
    NSFileExtensionHidden = 0;
    NSFileGroupOwnerAccountID = 0;
    NSFileGroupOwnerAccountName = wheel;
    NSFileModificationDate = "2015-01-30 01:35:23 +0000";
    NSFileOwnerAccountID = 0;
    NSFileOwnerAccountName = root;
    NSFilePosixPermissions = 449;
    NSFileReferenceCount = 19;
    NSFileSize = 646;
    NSFileSystemFileNumber = 19103629;
    NSFileSystemNumber = 16777220;
    NSFileType = NSFileTypeDirectory;
}

2015-01-30 10:35:24 +0900 [E]  IM: [install failed: 30]
2015-01-30 10:35:24 +0900 [E]  IM: Install failed with error code: 30.
2015-01-30 10:35:24 +0900 [I]  IM: ----------  log end  ----------

.dev で終わる hostname のとき gem install が(ある条件で)失敗するようになった

追記:うまい要約を見つけたので貼っておく。


最近 .dev TLD が新設された影響か、 hostname が .dev で終わる手元のマシンで gem install するとコケるようになった:

$ hostname
foo.dev
$ sudo /opt/rbenv/versions/2.2.0/bin/gem install bundler --no-document
ERROR:  While executing gem ... (Gem::RemoteFetcher::FetchError)
    Errno::ECONNREFUSED: Connection refused - connect(2) for "your-dns-needs-immediate-attention.dev" port 443 (https://your-dns-needs-immediate-attention.dev/quick/Marshal.4.8/bundler-1.7.11.gemspec.rz)

具体的には次のいずれかの条件を満たす環境で再現する:

  • hostname が .dev で終わり、かつ /etc/resolv.conf の search フィールドが設定されていない
  • /etc/resolv.conf の search フィールドが dev を含む

1番目の条件は Ruby の Resolv ライブラリの挙動に由来する。 /etc/resolv.conf に search が設定されていないとき、 Resolv は hostname の TLD を search の値として扱うようになっている(resolv.rb の1010行目あたりを参照)。また RubyGems の名前解決の挙動とも関係する(この記事のコメントを参照)。

この問題を回避するには /etc/resolv.conf に適当な search hoge fuga を設定すればよい。ただし hoge fuga は dev を含まないこと。

search を設定できない事情があるなら hostname を変える。 TLD を含まないようにするかテスト用の TLD を使う。 RFC 2606 によれば、テスト用途に使える TLD は予約済みの4つのうち .test.example の2つである。このどちらかを使えばよい。

あるいは .x などの1文字の TLD が使えるかもしれない。仕様上は正しいが、これまでに1文字の TLD が登録されことはない。

参考:


ブコメ返信

(gem の source を FQDN にすればいいという指摘について) id:happy_siro こういうこと?

$ sudo /opt/rbenv/versions/2.2.0/bin/gem sources list
*** CURRENT SOURCES ***

https://rubygems.org./

だめっぽい。

$ sudo /opt/rbenv/versions/2.2.0/bin/gem install bundler --no-document
ERROR:  While executing gem ... (Gem::RemoteFetcher::FetchError)
    Errno::ECONNREFUSED: Connection refused - connect(2) for "your-dns-needs-immediate-attention.dev" port 443 (https://your-dns-needs-immediate-attention.dev/quick/Marshal.4.8/bundler-1.7.11.gemspec.rz)