c4se記:さっちゃんですよ☆

.。oO(さっちゃんですよヾ(〃l _ l)ノ゙☆)

.。oO(此のblogは、主に音樂考察Programming に分類されますよ。ヾ(〃l _ l)ノ゙♬♪♡)

音樂は SoundCloud 等に公開中です。

考察は現在は主に Scrapbox で公表中です。

Programming は GitHub で開発中です。

はてなリモートインターンシップ 2021 の講義資料が公開された

はてなリモートインターンシップ 2021 の講義資料が公開された。

developer.hatenastaff.com

私は microservice に就いての講義を擔當した。

speakerdeck.com

他の講義の資料も上記に公開されてある。

自分の講義を反省的に檢討すれば、抽象的な體系を述べるのではなく、架空でもよい事例を幾つか擧げそれを基に具體的に microservice の構築や運用や改善を議論した方が好かったと思ふ。しかし私が講義を構成する時には、私見の範圍には、事例をだう體系的に竝べ議論するか、或る事を述べた時に何を述べてゐないのか自覺する爲の記述は無かった。今は有る。上の資料だ。

以下の論理構成は自前のものだ。充分に先行研究を調べてゐないから獨自のものとは言はないし、獨自ではないと思ふ。

  • [user の求め]<-(物事を提供する)<-[仕組み (= service)] の圖式で、schema 1st や service mesh 迄、統一的に論旨を捻じ通した
  • 自己相似的な構造の下で microservice を定義した
  • 組織の局所的な合理性に依る cost と、microservice・SRE・CI/CD を對應させ說明した
  • deploy の 3 段階 : build-deploy-release を明言した

調べた記録は以下に在る。

scrapbox.io

JPEG / PNG 畫像を可逆壓縮する Python script を Clojure (Babashka) で書き直した

先日書いた以下の記事で Python の script を貼り附けた。

c4se.hatenablog.com

しかし今は Clojure (Babashka) で書く事に決めてあるので、書き直した。Windows 版の Babashka (bb.exe) ではなく Linux 版 (bb) を呼んでゐる。WSL2 で作業するのでこれで困らないが、かうした理由は、

  1. 日本語 file 名を WSL2 上の bash から引數で與へ、java.io.shell/sh を呼ぶと encoding が bug る。file が NTFS 上に在るか WSL2 上に在るかは關はりが無い
  2. bb.exe から Linux program を、この場合は zopflipng を起動できない

どちらも解決不能ではなささうだが、普段 WSL2 上で生きてゐるから bb を使ふ事にした。

#!/usr/bin/env bb
;; Optimize JPEG images by mozjpeg & PNG images by zopflipng.
;;
;; Usage :
;; ag -0 -g '\.((jp(e?)g)|png)$' | xargs -0 -t -n2 -P$(nproc) /mnt/c/<PATH TO>/imageoptim.clj


(defn sh
  [& args]
  (println "+" (str/join " " args))
  (let [{:keys [exit out err]} (apply shell/sh args)]
    (if (not= 0 exit) (throw (Exception. err)) :ok)
    (println out)
    out))


(defn as-image
  [filename]
  {:filename filename
   :type (cond
           (or (str/ends-with? filename ".jpg") (str/ends-with? filename ".jpeg")) "JPEG"
           (str/ends-with? filename ".png") "PNG"
           :else (throw (Exception. (str "Can not detect file type: " filename))))})


(defn compress-jpeg
  [image]
  (let [input-filename (:filename image)
        output-filename (str (java.util.UUID/randomUUID) ".jpg")
        _ (sh "jpegtran.exe" "-copy" "none" "-optimize" "-outfile" output-filename input-filename)
        input-file (io/file input-filename)
        output-file (io/file output-filename)]
    (println (str input-filename " " (.length input-file) " -> " (.length output-file)))
    (.renameTo output-file input-file)))


(defn compress-png
  [image]
  (let [input-filename (:filename image)
        output-filename (str (java.util.UUID/randomUUID) ".png")
        _ (sh "/mnt/c/<PATH TO>/zopflipng" "-m" "--lossy_transparent" input-filename output-filename)
        input-file (io/file input-filename)
        output-file (io/file output-filename)]
    (println (str input-filename " " (.length input-file) " -> " (.length output-file)))
    (.renameTo output-file input-file)))


(defn compress
  [image]
  (case (:type image)
    "JPEG" (compress-jpeg image)
    "PNG" (compress-png image)
    (throw (Exception. (str "Unknown image type" (:type image))))))


(doseq [filename *command-line-args*]
  (-> filename as-image compress))

何をしてゐるか知ってゐる program は、programming 言語に或る程度關はらず讀めるものだ。

JPEG / PNG 畫像を可逆壓縮する @ Windows

畫像を Internet に上げる前に壓縮する習慣を持ってゐる。macOS では ImageOptim を使ってゐるが、Windows では無い。

imageoptim.com

JPEG 畫像は mozjpeg で、PNG 畫像は zopfli で可逆壓縮できればよい。以下の通りにやってゐる。

mozjpeg は scoop で入れる。今なら winget でよい。これで WSL2 からも jpegtran.exe が呼べる。

scoop install mozjpeg

zopfli は WSL2 で build してある。

git clone https://github.com/google/zopfli.git
cd zopfli
make

これ等を Python から呼ぶ。

#!/usr/bin/env python3
"""
Optimize JPEG images by mozjpeg & PNG images by zopflipng.

Usage :
ag -0 -g '\.((jp(e?)g)|png)$' | xargs -0 -t -n2 -P$(nproc) /mnt/c/<PATH TO>/imageoptim.py
"""
import os
import subprocess
from shlex import quote
import sys
import uuid


class Image:
    @classmethod
    def from_input_file_name(cls, input_file_name: str) -> "Image":
        if input_file_name.endswith(".jpg") or input_file_name.endswith(".jpeg"):
            return JpegImage(input_file_name)
        elif input_file_name.endswith(".png"):
            return PngImage(input_file_name)
        raise f"Can not detect fle type: {input_file_name}"

    input_file_name: str
    output_file_name: str

    def compress(self) -> None:
        raise NotImplementedError()


class JpegImage(Image):
    def __init__(self, input_file_name: str):
        self.input_file_name = input_file_name
        self.output_file_name = f"{uuid.uuid4()}.jpg"

    def compress(self) -> None:
        try:
            command = f"jpegtran.exe -copy none -optimize -outfile {quote(self.output_file_name)} {quote(self.input_file_name)}"
            print(command)
            subprocess.check_call(command, shell=True)
            print(f"{self.input_file_name} {os.stat(self.input_file_name).st_size} -> {os.stat(self.output_file_name).st_size}")
            os.replace(self.output_file_name, self.input_file_name)
        except subprocess.CalledProcessError as err:
            print(err)
            if os.path.isfile(self.output_file_name):
                os.remove(self.output_file_name)


class PngImage(Image):
    def __init__(self, input_file_name: str):
        self.input_file_name = input_file_name
        self.output_file_name = f"{uuid.uuid4()}.png"

    def compress(self) -> None:
        try:
            command = f"/mnt/c/<PATH TO>/zopflipng -m --lossy_transparent {quote(self.input_file_name)} {quote(self.output_file_name)}"
            print(command)
            subprocess.check_call(command, shell=True)
            print(f"{self.input_file_name} {os.stat(self.input_file_name).st_size} -> {os.stat(self.output_file_name).st_size}")
            os.replace(self.output_file_name, self.input_file_name)
        except subprocess.CalledProcessError as err:
            print(err)
            if os.path.isfile(self.output_file_name):
                os.remove(self.output_file_name)


for input_file_name in sys.argv[1:]:
    Image.from_input_file_name(input_file_name).compress()

昔書いたので Python だ。今なら Clojure で書く。書き直すか…。

追記 2021-09-19 書き直した。 c4se.hatenablog.com

書く程の事ではなかったが書いた。