お知らせ

現在サイトのリニューアル作業中のため、全体的にページの表示が乱れています。
投稿日:
ジャンル::サイト運営

前々からこのブログの画像と文字の配置について悩んでいたが、結論が出たのでスタイルを変えることにした。

以前は以下のような方式だったのだが、補足説明と次の画像の説明の境界があいまいで判読しづらかった。

<画像の説明>
<画像>

<補足説明>

今回はこれを以下の形に刷新した。

<画像>

<画像の説明>

<補足説明>

この形式にしたことにより画像を区切り文章ができるため、どちらの画像に対する文章なのかが判別しやすくなった。

何故この形式にしたかは単純で、デイリーポータルZ海の見える駅 〜徒歩0分の景勝地〜など、この書式を採用しているサイトが多いからだ。これらのサイトでは加えて画像タイトルと判るような枠UIもついているが、文章構成が面倒になるので今のところそこまでするつもりはない。一応CSSで画像の上のパディングを広げることで、区切りを判別しやすくはしている。

変更前 変更後
before-img.png
after-img.png

変化としては上の表の通り。通常の画像は、画像個別にfigure > a > imgとなっており、文章はPタグで囲まれているため、Pタグの後ろの全figureに対しmargin-topを指定して対処している。

div.body-main p~figure {
  margin-top: 1em;
}

adiaryの生成するHTMLは画像を挿入したときに前後にPタグを挿入する挙動をするため、手前に文章がなくても妙な空白が生まれてしまうが、現状は許容としている。

このPタグにはMarkdownで書いた画像の前後の行の文字列が入り、brを回避するように実装されているようで、修正が面倒なため、新ブログシステムを開発し、そっちに移行したときに対応したい気がしている。

あああ
<画像>
いいい

例えば、上記であれば以下のHTMLが生成される感じだ。

<p>あああ</p>
<figure><a href="画像パス"><img src="サムネ"></a></figure>
<p>いいい</p>

今回の対応では以下の形式にしているため、前後のPタグの中身は空白になる。要するにゴミが出ている。

<画像>

<画像の説明>

<補足説明>

<画像>

<画像の説明>

<補足説明>

...

今回の対応で対象となった記事は112、変更箇所となる文章行と画像行のセットは約1,089箇所にも及んだため、どこかの記事が置換ミスで壊れている可能性がある。ただまぁ読めなくはないと思う。

paste-image-2025-29-5_1-28-40-152.png

このブログはテキストファイルでデータを持っているため、置換作業はVSCodeの一括置換を主に使っていて、一応できる限り目検で怪しいところはチェックしている。たまにメタデータを破壊しそうになっていたり「以下」という文言が含まれていたり、二行連続で画像が続いているなどで整合性が取れなくなっている個所は極力て出直している。

ただどうしても万博記や、しょい地巡礼辺りは画像点数が余りにも多いので文章中に「以下」がないかを機械的に見て、上から下まで流し見した程度にとどまっているため、一部崩れている可能性は否定できない。

ひとまずこの作業をしている中でadiaryのコードをあれこれ見ていたところ、保守性に限界を感じてきたので、adiaryのデータフォーマットと互換性のあるブログシステムをPHP辺りで作りたい機運が高まった。気が向いたら作るかもしれない。

DBはテキストDBだと一括置換がしやすいとかは確かにあるのだが、システム保守やパフォーマンス面ではSQLiteが最強だと思っているので、恐らくテキストDBは捨てる気がする…。

パフォーマンス面についてはウチのように記事数が多いサイトだとSQLiteは1ファイルにデータが収まる関係でファイルI/Oの回数が減る分、オーバーヘッドが減ると考えているためだ。実際adiaryは時として重くなる。WordPressほどではないにせよ、看過していると今後の記事増加に耐えられない気もする。

RDBは今回のような一括置換に対しての保守性は悪いが、総合的なパフォーマンスはいいし、置換に関しては最悪WordPressにあるSearch Replace DBみたいなやつを作れば使い勝手が悪くとも出来なくはないと思うのと、基本的にまず発生しないはずなので考慮しない方向で行きたい。

投稿日:
開発::設計言語::TypeScript

例外設計についての個人的に思っていることを書き出してみる。整理できていないがいったん現状。TypeScriptのケースを意識して考えているが、根幹は例外スローのある言語ではどれも共通だと考えている。

例外とは何か?

本記事で扱う例外とはthrow new Error("ほげほげ");のように、いわゆるスローされ、try-catchされるものを指して扱う。

例外を多用しない

例外は多用しないことが望ましく、原則として処理が続行不能になる場合を除き、使わないほうが良いと考えている。これはスローされた例外は可視化されづらく、適切にハンドリングされないケースがよくあるからだ。

例外は構造化されたプログラムを破壊する

構造されたプログラムとは順次・反復・分岐の基本構造を階層的に組み合わせたものであり、いわゆる上から下に読めばわかるもの、構造化プログラミングによって作られるものだ。上から下に流れるため非常にわかりやすい。

これに対して存在するのがgotoを用いたプログラムだ。gotoを使うとコードの色んな場所に前後しながらジャンプすることが可能で、可読性を損ねてしまう。

そして例外は基本的にgotoのような存在である。例外が起きると例外オブジェクトが投げられ、これはどこに行きつくか予想することが難しい。行きつく先がなければ最悪プログラムがクラッシュする恐れすらある。

例外は処理コストが重い

恐らく大抵の言語において例外をcatchする行為はコストが重い。これはJavaでは特に有名な話だと思うが、Java以外でもそうだと思う。例えばNode.jsでtry-catchで例外を処理するプログラムと、if-elseで処理するプログラムを書き、その実行速度を比較するとif-elseの方が早い。

以下はエラーハンドリングをifで行うプログラムと、try-catchで行うプログラムを作り、100万回走行させたときの処理時間だ。catchに入るケースでは処理速度が低下することが分かる。例外が投げられず、tryの中に納まる限りは低下しない。

処理 処理時間(ms)
If正常系 4,453
If異常系 4,204
try-catch正常系 4,341
try-catch異常系 7,883

これは例外が投げられる場合、最寄りのcatchポイントを探索するのに時間がかかるからではないかと考えている。

Node.js向け検証コード

前述の処理時間を出すのに使ったプログラム

// ==== 実行用共通部品
const execIf = (input) => {
  if (input === 1) {
    return true;
  } else {
    return false;
  }
};

const execThrow = (input) => {
  if (input === 1) {
    return true;
  } else {
    throw new Error('ERR');
  }
};

// ==== コールバック処理計測用関数
const getExecFuncElapsed = (cb) => {
  const startAt = +new Date();
  for (let i = 0; i < 1_000_000; i++) {
    cb();
  }
  return +new Date() - startAt;
};

// ==== If/try-catch検証用、コールバック処理群
const execIfOk = () => {
  const ret = execIf(1);
  if (ret) {
    console.log('OK=');
  }
};

const execIfNg = () => {
  const ret = execIf(0);
  if (ret === false) {
    console.log('ERR');
  }
};

const execThrowOk = () => {
  try {
    execThrow(1);
    console.log('OK=');
  } catch (e) {
    console.log('ERR');
  }
};
const execThrowNg = () => {
  try {
    execThrow(0);
    console.log('OK=');
  } catch (e) {
    console.log('ERR');
  }
};

// ==== 計測処理
const elapsedIfOk = getExecFuncElapsed(execIfOk);
const elapsedIfNg = getExecFuncElapsed(execIfNg);
const elapsedThrowOk = getExecFuncElapsed(execThrowOk);
const elapsedThrowNg = getExecFuncElapsed(execThrowNg);

// ==== 結果出力
console.table({ elapsedIfOk, elapsedIfNg, elapsedThrowOk, elapsedThrowNg });

いつ例外を使うか?

基本的には大域脱出がしたいケースのみで使うべきだろう。最悪ハンドリングされずとも、基底階層でcatchされれば、それでよいケースで使うのが最も無難だと考える。

大域脱出とは要するにgotoだ。多重ネストや深い高階関数から浅い階層に一気にすり抜けるときに有効だろう。逆に一階層とか、抜ける階層が浅いレベルでは使わないほうが良い。

例えば処理が続行不能になったケースでは例外をスローし、基底階層でcatchし、エラーログを吐く、クライアントに対してエラーメッセージを返すなどの処理があればよいと考える。

但し例外を使うときは極力カスタム例外を使ったほうがよいと考える。

フレームワークやライブラリの例外をどう扱うか?

例えばバリデーションエラーやHttpClient系の4xx, 5xx系の例外スローはラッパーを作り、例外をエラーオブジェクトに変換するのも一つだと考える。

HTTP GETを行うクライアント関数であれば以下のようなラッパーを作り、正常時は正常レスポンスを返し、異常時でかつ想定内であればエラーオブジェクトを返す、そして想定外の例外であればリスローする、といった処理をすることができる。

const httpGet = (url) => {
  try {
    return fetch(url);
  } catch (e) {
    if (e instanceof AbortError) {
      return createHttpErrorObj(e);
    } else {
      throw e;
    }
  }
}

こうすることで呼び出し元は正常時であればHTTPリクエストをそのままステータスコードに応じて処理し、Abortされた場合はリトライ、完全に予期せぬ内容であれば例外を基底階層まで飛ばして処理を中断するといったこともできる。

リトライに規定回数失敗した場合は、この関数の呼び元でnew OutOfTimesHttpRetryError()みたいな例外をスローするとよいだろう。

カスタム例外を使う

カスタム例外とは例外クラスを継承した例外クラスだ。

例えばC#ではExceptionのほかに、それを継承したSystemExceptionや、IndexOutOfRangeExceptionなど、様々なカスタム例外が存在する。

LaravelにもAuthorizationExceptionをはじめとし、多様なExceptionが存在する

これらに限らず、大抵の言語やフレームワークには相応のカスタム例外が用意されているのが一般的で、業務システムやC2のプロダクトでも、例外をスローするケースではカスタム例外を作ることが望ましいと考える。

カスタム例外があると例外種別ごとにフィルタリングすることが可能になり、柔軟にハンドリングしやすく、ロギングの際にも例外種別を記録することで、後々の障害調査でも便利になるため有用だ。

例外を握りつぶさない

例外は時として握りつぶされることがある。そういう必要があるケースも少なからずあるだろう。しかし基本的に例外は握りつぶさないほうがよい。

例外は望ましくない現象が起きているはずで、本質的にハンドリングする必要がある。単に握りつぶしているだけでコメントやテストも書かれていなければ、もし例外が起きたとき、処理が正常に進むのかどうかコードから読み取ることが困難だ。

仮にテストがあったとしてもコードを読むときのコストが増えるので、基本的に握りつぶさないほうがよいだろう。

スローする場合は、例外クラスを用いる

JavaScript系では以下のようなエラーオブジェクトを作るケースもあると思うが、スローする場合は使わないほうが良い。

{
  __type: 'HogeError',
  message: 'fufagfuga',
  payload: someObject
}

paste-image-2025-57-4_12-56-48-850.png

スローする場合はErrorクラスを継承したカスタムエラーをスローすべきだ。これはカスタムエラーにはスタックトレースなど、障害調査をするときなどに例外として標準的な情報が格納されているほか、instanceofでフィルタしやすい、クラスは型情報を持つのでリファクタが容易、error.__type === 'HogeError'は言語機能の再実装に近く標準的ではないからだ。テストフレームワークでも例外をキャッチするためのアサーションではErrorクラスの継承が必須となっているケースがあるため、TypeScriptでは型検査が上手く通らないケースがある。

投稿日:
技術::AIソフトウェア::Open WebUI

Open WebUIを使ってローカルLLMとチャットしてみたのでその記録。

確認環境

実行環境はWindows 11。

Env Ver
ollama 0.9.0
Open WebUI 0.6.6

やり方

Open WebUIをセットアップ済みという前提で進める。

  1. Ollamaをインストールする
  2. 使いたいモデルを探す
  3. ollama pull <モデル名>でモデルを取得する
    • 物次第だが数~数十GB程度ある
  4. Open WebUIを起動する
  5. 管理者設定の接続を開きOllamaをONにする(デフォルトはONのはず)
    paste-image-2025-58-4_0-57-43-743.png
  6. 管理者設定のモデルを開き、pullしてきたモデルを有効化する

Ollamaサーバーの起動方法

Ollamaをインストールした直後はOllamaサーバーが勝手に起動するが、それ以降は手動で起動する必要がある。

paste-image-2025-53-4_0-52-30-334.png

Windowsの場合スタートメニューから起動できる。Ollamaサーバーが起動していない場合、LLMとして使えないので注意。

所感

Intel Core i7 13700 + GeForce RTX 4070 Ti程度の環境では生成速度の遅さゆえに到底実用に耐えるものではなかった。質問への回答品質もあまりよくなく、実用性は疑問だ。チューニングすれば使えるのかもしれないが、よくわかっていない。

今回試した結果ではRPはGemini以上に破綻するので微妙だった。文章をある程度整理する力はある様に見えるので、用途次第では活路があるのかもしれない。

以下に実行した結果を記録している。

gemma3:27b

恐らくGoogle AI Studioにもいる子。

出力内容

gemma.png

真贋のほどはさておき、中々力の入った文章を出してくる。流石にローカルLLMの中でも注目されているモデルだけある。

しかし出力に3分半程度もかかっており、まったく実用性がない。無料の選択肢という意味ではGeminiやCopilotを使ったほうが遥かによいだろう。

マシン負荷

gemma1.png

GPU負荷はないもののCPU負荷が強い。VRAMが足りないとCPUで処理するみたいな情報をチラッと見たのでグラボの性能不足の可能性もある。

lucas2024/mistral-nemo-japanese-instruct-2408:q8_0

CyberAgentが作ったとされているモデルのOllama版?

出力内容

mistral.png

こちらも真贋のほどはさておき、中々いい感じの文章を出してくれる。

生成速度はgemma3:27bよりは早いものの、それでも1分ほどかかっていた。

マシン負荷

mistral1.png

CPU負荷はgemma3:27bよりやや低く、GPU負荷が少し上がる傾向があった。

マシン負荷

20250604_014915707.JPG
20250604_014918911.JPG

うちのマシンは200mmファンを四基、CPUにはNoctuaのヒートシンクに120mmファン、リアには140mmファンを装備しているが、gemma3:27bだとこれらがフル回転するので凄まじかった。

StableDiffusionやFF14ベンチ程度ではフル回転することはない。

関連記事

投稿日:
文芸::アニメ文芸::映画

20250531_150322289.JPG
20250531_150346981.JPG

プリプリの舞台挨拶付き上映にT・ジョイ梅田の席を取ったら「卓球少女 -閃光のかなたへ-」という珍しそうな作品を見かけたので、本作を観た鑑賞録。

内容的には中国のアニメスタジオが制作した卓球をテーマにした美少女スポ根ものといった感じだが、独特な表現や雰囲気の作品で、これは中々ない作品だと思ったので、その内容を書いてゆく。

異色の中国2Dアニメ

本作は日本で作られたといわれても違和感がないほどに日本的な絵柄の2Dアニメだ。中国のアニメ映画は3D作品が多いか、2Dであっても独特の絵柄であることも少なくない印象だが、本作は非常に日本的だった。

一方で鍛えられた肢体や筋肉を強調したアグレッシブな描写が多く、これは日本の美少女アニメには余りない要素で、ここは本作で特徴的な要素といえるだろう。

お色気皆無

日本のアニメと比べると圧倒的にお色気がない。本作の舞台は高校だが、押し並べて胸が薄い。モブキャラに一人巨乳が居た程度で、驚くほど薄い。ここまで健全方向に倒した作品も珍しい。

公式のキャラ紹介に至っては、ほぼ絶壁で、ガタイがいいのもあり、男…?と首をかしげてしまった。恐らくこれは中国の表現規制も関係していると思う。

ただこの色気のなさは本作のスポ根精神を遺憾なく引き立てるのに随分役立ったと思う。煩悩がない。シュッとしている。

シャワーシーンすらシャワーヘッドが出てくるだけという潔さである。

タイトルやロゴ、OP/EDのローカライズ

本作はタイトルや、そのロゴ、OP/EDがローカライズされている。邦題は「卓球少女 -閃光のかなたへ-」だが、原題は「白色闪电 Pingpong!」だ。

タイトルロゴに小さくTAKKYUUUUUUUUUUとあるが、これもローカライズだろう。こういった些細なところまで力を入れているのはいいと思った。

因みに卓球は日本語であり、Table tennisとも関係ないらしい。中国語では卓球は乒乓球と書き、この文字列は作中で何度も出てくる。

登場人物の多様性

OPに出てきたキャラだけの話だが、異様なまでに多様なタイプをカバーしているように感じた。

真面目メガネっ子、クールビューティー、そばかす娘、じゃじゃ馬、目の下ホクロ、天真爛漫などなど、やたら手幅くカバーされている。性癖ブレイカーか何かか?いや、そんな意図はないと思うが。

顔のバリエーションがすごいので日本アニメにありがちな髪の色でキャラを区別するといった要素は薄めに見えた。書き分けが凄まじい。

またビジュアルだけでなく、キャラクターの性格も各キャラかなり尖っていて、ここまでキャラが立っていて確立した魅力を持つ作品もなかなかないと思った。

意外と日本と変わらない学生生活

本作はいわゆる学園ものになるので、中国の高校の風景も出てくるわけだが、そこまで日本と変わらない。精々教室の入り口にICT的なモニタがある程度で、校舎の作りや机など大まかな雰囲気は日本そのものだ。

初年度は教科書を配ったり、授業も黒板に板書したり、プリントを配ったり、教師に当てられて発表したり、まんま日本だ。大きな違いといえば精々制服がジャージなことくらいだろうか?

校舎の様子などは実際に高校に行って取材をしたそうだが、制作陣は教室の入り口に電子掲示板があることに驚いたという。

リアリティの凄い卓球

卓球の練習シーンではおよそ卓球と関係ない特訓が出てくる。例えばシャトルラン的なことをしていたり、縄跳びをするなど。基礎的な体力づくりや体幹作りが描かれる作品は珍しいと思う。

また卓球のシーンは躍動的で、目にも止まらない高速なやり取りや、コートから打ち出された球をスライディングで打ち返すなど、かなりダイナミックな表現が多く、見ていて興奮した。筋肉の描写もよく、スポーツマンを見ている感じがすごかった。ここまで汗臭さを感じる作品はめったにないと思う。

実際に試合のシーンは現実の試合を参考に、辻褄が合うように作りこんでいるらしく、リアリティの追及が半端ない。サーブ権にまで配慮して作りこんでいるのは流石だ。日本の作品だとスポーツに限らず、ルールの不備を指摘されるものも少なくないだろう。例えば響け!ユーフォニアムでは楽器の持ち方が違うという指摘がよくあった気がする。

制作にあたってはスタッフにいた卓球の経験者や、プロのコーチを召還するなど、かなり再現性には力を入れたようだ。

リアリティの追及

本作は中国の視聴者が見たときに違和感を持たないように、現在の中国の風景を再現することに注力したとのことで、全体的にリアリティが強い。タピオカを飲むシーンも出てくる。つまりタピオカ屋は中国にも進出しているわけだ。

エンディングでは舞台となったであろう浙江省杭州市上城区の名所的なものが紹介されており、聖地巡礼したくなるような仕組みが非常によかった。トラペジウムでテカポ湖に行った人がいることを考えると、より身近な杭州に行こうと思う人もいるかもしれない。本作はそこまで刺さる作品ではないと思うので、行く日本人がどれほどいるかは未知数だが…。

またリアリティを追求する傍らで、序盤でジャン・ルオイが走っているシーンなどでは伝統的中国の風景をミックスしているという点も見逃せないところだ。

最後に

全体的に作りが精緻で、切れ味のいいスポ根作品だと感じた。そして本作は未完のままEDを迎えている。原作は6話まであり、今回はそのうち3話までを総集編として合体させたものらしいので、是非続編にも期待したい。

上映館は多くなく、特に西日本での上映館が極端に少ないが、個人的には今年の推し作品の一つだ。王道だがキャラ的にはジャン・ルオイ、ワン・ルーの組み合わせが好きだ。どこか抜けてるクールキャラとお調子ツンデレ委員長キャラはかなりいい。どっちもイケメンだし!

またパンフレットの表紙はいい紙を使っており、巻末には中国側スタッフが日本語を交えて書いたものもあり、是非触って読みたいアイテムだ。

投稿日:
料理::レシピ::麺類

10分程度で作れる即席パスタ。パスタなのかは怪しい

20250603_000240627.JPG

材料

材料 分量
揖保の糸 手延パスタ 龍の夢 1束
からし菜 数本
ブラウンマッシュルーム 2個
ポークランチョンミート 5mmスライス1枚
サラダ油 大さじ1

調理方法

パスタの具

茹でる湯を沸かしながら作ると効率が良い

  1. からし菜を3cm幅くらいに切る
    karashina.jpg
  2. マッシュルームを薄くスライスする
  3. ポークランチョンミートを5mm幅くらいにスライスし、更にそれを拍子木切りにする
  4. フライパンに油を引く
  5. マッシュルームとからし菜をフライパンに入れ1分くらい中火で蒸し焼きにする
  6. フライパンの蓋を外す
  7. ポークランチョンミートをフライパンに入れ、全体的にしんなりするまで炒める
    20250601_235415468.JPG

    この写真ではランチョンミートを2枚使ったので材料表の分量と異なる
  8. とろ火にしておく

パスタ

アルデンテ風味にするため短めに茹でる

  1. 1Lの水を沸騰させる
  2. パスタを入れる
  3. 30秒茹でる。1分でもいいかも?
  4. ザルにあげ、そうめんのようによく洗う
    • 30秒だと多少折れるが気にしない

仕上げ

  1. パスタの具を炒めたフライパンにパスタを入れ、麺が柔らかくなるまで中火で炒める

備考

パスタに炒め油が染み込むと味が効いておいしくなる。

正直食べてみた感想として、揖保の糸 手延パスタ 龍の夢がパスタなのかは怪しいと思った。デュラム小麦を使っているそうだが、セモリナ粉とは書かれていないし、麺の味は中華麺が近いと感じた。原材料にかん水が入っている時点で中華麺らしさがある。触感はもちもちしていて、独特の感触だった。少なくともそうめんでないことだけは確かだが、パスタとも言い互い。多分中華麺が一番近い。

余談だが、からし菜とマッシュルームは小野市産を使っており、揖保乃糸はたつの市産なので、油とランチョンミート以外は兵庫県産。油は国産、ランチョンミートはデンマーク産である。