2024年11月29日金曜日

GoogleSpreadSheetで月ごとに色を分ける方法

GoogleSpreadSheetで月ごとに色を分ける方法

概要

特定のカラムで日時を管理している場合に月ごとにセルの色を変更する方法を紹介します
条件付き書式ではできないので GoogleAppScript を使います

環境

  • GoogleSpreadSheet (2024/11/29時点)
  • GoogleAppScript (2024/11/29時点)

特定の色に変更する方法

事前に30色分(30ヶ月分)用意しています
何度実行しても同じ色になるようにしています

B2 カラムで日時を管理している想定です
B2 カラムの1行目はヘッダで2行目から日時データの想定です
B2 カラムの日時はフォーマットが Date になっていることが条件です

function colorRowsByMonth() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  const lastRow = sheet.getLastRow(); // シート内の最終行を取得
  const range = sheet.getRange(2, 2, lastRow - 1, 1); // B列の2行目から最終行まで取得
  const values = range.getValues(); // データを2次元配列で取得
  const colors = {}; // 月ごとの色を保持するオブジェクト
  const colorPalette = getLargeFixedColorPalette(); // 固定された30色の薄い色パレット
  let paletteIndex = 0;

  for (let i = 0; i < values.length; i++) { // ヘッダーをスキップ
    const date = values[i][0]; // 日時が入力されているカラム (A列の場合)
    if (date instanceof Date) { // 日付形式か確認
      const monthKey = Utilities.formatDate(date, Session.getScriptTimeZone(), "yyyy/MM");
      // 月ごとの色を設定(未登録なら新しい色を割り当て)
      if (!colors[monthKey]) {
        colors[monthKey] = colorPalette[paletteIndex % colorPalette.length];
        paletteIndex++;
      }
      // B2から下に行の背景色を設定
      sheet.getRange(i + 2, 2, 1, 1).setBackground(colors[monthKey]);
    }
  }
}

// 固定された30個の薄い色のパレットを生成する関数
function getLargeFixedColorPalette() {
  return [
    "#FFCCCC", "#FFEECC", "#FFFFCC", "#CCFFCC", "#CCE5FF",
    "#CCCCFF", "#FFCCE5", "#FFE4B5", "#D8BFD8", "#B0E0E6",
    "#F0E68C", "#E6E6FA", "#F5DEB3", "#FFDAB9", "#F0FFF0",
    "#FFF0F5", "#FFFACD", "#E0FFFF", "#FAFAD2", "#D3D3D3",
    "#FFC0CB", "#B0C4DE", "#ADD8E6", "#DDA0DD", "#D9F2E6",
    "#F2E2D2", "#F5F5DC", "#FBE5D6", "#EBF4FA", "#FAEBD7"
  ];
}

月分だけ色を用意する方法

例えば 2024/01 と 2025/01 は同じセルの色にしたい場合などはこちらを使います
こちらの方法は12色準備すれば OK なので色の追加などは不要です

function colorRowsByMonth() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  const lastRow = sheet.getLastRow(); // シート内の最終行を取得
  const range = sheet.getRange(2, 2, lastRow - 1, 1); // B列の2行目から最終行まで取得
  const values = range.getValues(); // データを2次元配列で取得
  const monthColors = getMonthColors(); // 月ごとの色を取得

  for (let i = 0; i < values.length; i++) { // ヘッダーをスキップ
    const date = values[i][0]; // 日時が入力されているカラム (A列の場合)
    if (date instanceof Date) { // 日付形式か確認
      const month = date.getMonth(); // 月を取得(0: 1月, 11: 12月)
      const color = monthColors[month]; // 月に対応する色を取得
      // B2から下に行の背景色を設定
      sheet.getRange(i + 2, 2, 1, 1).setBackground(color);
    }
  }
}

// 1月から12月までの固定色を返す関数
function getMonthColors() {
  return [
    "#FFCCCC", // 1月 - 薄い赤
    "#FFEECC", // 2月 - 薄いオレンジ
    "#FFFFCC", // 3月 - 薄い黄色
    "#CCFFCC", // 4月 - 薄い緑
    "#CCE5FF", // 5月 - 薄い青
    "#CCCCFF", // 6月 - 薄い紫
    "#FFCCE5", // 7月 - 薄いピンク
    "#FFE4B5", // 8月 - 薄いベージュ
    "#D8BFD8", // 9月 - 薄いモーブ
    "#B0E0E6", // 10月 - 薄い水色
    "#F0E68C", // 11月 - 薄いカーキ
    "#E6E6FA"  // 12月 - 薄いラベンダー
  ];
}

最後に

レコードが増えたら再度 GAS を実行する必要があるのが不便です
(条件付き書式でもできる方法があるのだろうか)

2024年11月27日水曜日

chrome のブックマークレットでボタンを押したあとにinputに値を入力しイベントを強制発火する方法

chrome のブックマークレットでボタンを押したあとにinputに値を入力しイベントを強制発火する方法

概要

テキスト入力用のフォームなどにイベントが設定されてある場合はブックマークレットでは強制的にイベントを発火させる必要があります

環境

  • macOS 15.1.1
  • Google Chrome 131.0.6778.86

ブックマークレット(js)

javascript:(function(){
    var button = document.querySelector('input.pc-tab__hidden-input[type="checkbox"][name="pnav-group"]');
    if (button) {
        button.click();
    } else {
        alert('ボタンが見つかりません');
        return;
    }
    setTimeout(function() {
        var input = document.getElementById('search-text');
        if (input) {
            input.value = 'スイカゲーム';
            var event = new Event('input', { bubbles: true });
            input.dispatchEvent(event);
        } else {
            alert('入力フィールドが見つかりません');
        }
    }, 500);
})();

chrome への登録

あとは chrome のブックマークへ上記 Javascript を登録すれば OK です

最後に

ブックマークレットは対象のURLを開いてから実行する必要があるので注意してください

ブックマークレットだけで特定の URL を開いた上で JavaScript を実行することは難しいようです

ボタンを押してからテキストフィールドに入力するまでに0.5秒待っていますが画面がうまく動作しない場合は値を調整してください

2024年11月26日火曜日

nvm 自身を更新する方法

nvm 自身を更新する方法

概要

Homebrew の場合は brew update でいいですが curl でインストールスクリプトを使ってインストールした場合は再度 curl を叩く必要があります

環境

  • nvm 0.40.1

コマンド

  • curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash

バージョンの部分はアップデートしたい最新バージョンにしてください

最後に

nvm 自身に update コマンドはないようです
バージョンを調べるのは少し面倒ですがこれが公式のようです

参考サイト

2024年11月25日月曜日

StackEdit でこのアプリはブロックされますが出る場合の対応用法

StackEdit でこのアプリはブロックされますが出る場合の対応用法

概要

一度ワークスペースをクリーンアップします

環境

  • StackEdit (2024/11/25時点

クリーンアップ

右ペインのメニューから「Reset application」を選択します

Restrict Access で Google Drive に再アクセス

Synchronize -> Add Google Drive Account で再度アカウントを接続します

これで「このアプリはブロックされます」の警告が出なくなります

オプション: Blogger アカウントを再接続する

Publish -> Add Blogger account で接続します

最後に

久しぶりに StackEdit を開くと発生したりします
素直にクリーンアップして各種サービスを再接続してあげましょう

2024年11月23日土曜日

ruby で parallel する場合にはデータをスライスしてから実行したほうがいいかもしれない

ruby で parallel する場合にはデータをスライスしてから実行したほうがいいかもしれない

概要

そうしないとプロセスが複数立ち上がっても CPU の使用率が偏る気がします

環境

  • macOS 15.1.1
  • Ruby 3.3.5
  • parallel 1.26.3

サンプルコード

def analyze
  @data.each_slice(batch_size) do |sliced_data|
    tweets = Parallel.map(sliced_data, in_processes: parallel_process_count) do |d|
      parse_and_add_tweet(d['tweet']['full_text'])
    end
    @tweets.append(tweets)
  end
end
  • batch_size は @data / CPU 数
  • parallel_process_count は CPU 数
  • Parallel.map で各コアが処理した結果は @tweets に結合していく
  • こうすることで各コアに均等に処理するデータが渡り処理が効率化される (各コアのCPU使用率がちゃんと均等化される)

2024年11月22日金曜日

Ruby で Thread によるシングルコアとマルチコア化について

Ruby で Thread によるシングルコアとマルチコア化について

概要

Ruby は GVL の関係で基本はスレッド化してもシングルコアでしか動きません
てっとり早くマルチコア化した場合は parallel を使います

環境

  • macOS 15.1.1
  • Ruby 3.3.5
  • parallel 1.26.3

Thread 化する前のコード

配列を単純に順番に処理する関数です

スレッド化することを前提にコードを作成しており add はインスタンス変数の配列にデータを登録するよういになっています
またインスタンス変数は基本的に順番を保証しないことを考慮した作りにしたほうがいいです (Thread でどんどん処理されるので)

def parse_and_add_tweet(full_text)
  tweet = Tweet.new(full_text, @mecab)
  tweet.analyze
  add(tweet)
end

def exec
  @data.each do |d|
    parse_and_add_tweet(d['tweet']['full_text'])
  end
end

通常の Thread

配列のデータをスライスしてスライスしたデータをスレッドに渡して処理させるようなコードに変更します

thread_batch_size は作成するスレッド数ごとにデータが均等に割り当たるようにしています

def thread_batch_size
  (@data.size / thread_count.to_f).ceil
end

def thread_count
  32
end

def parse_and_add_tweet(full_text)
  tweet = Tweet.new(full_text, @mecab)
  tweet.analyze
  add(tweet)
end

def analyze
  threads = []
  @data.each_slice(thread_batch_size) do |sliced_data|
    threads << Thread.new do
      sliced_data.each do |d|
        parse_and_add_tweet(d['tweet']['full_text'])
      end
    end
  end
  threads.each(&:join)
end

これで実行するとわかりますがシングルコアの CPU を100%使用しますが残りのコアは何もしていないことが確認できます

parallel を使う

parallel_process_count は CPU コア数になります
こちらの方が単純に書くことができます
また実行するとすべての CPU が使われ 100% になっていることが確認できると思います

def parallel_process_count
  Parallel.processor_count
end

def parse_and_add_tweet(full_text)
  tweet = Tweet.new(full_text)
  tweet.analyze
  add(tweet)
end

def analyze
  @tweets = Parallel.map(@data, in_processes: parallel_process_count) do |d|
    parse_and_add_tweet(d['tweet']['full_text'])
  end
end

parallel を使う際は少し工夫が必要なのでそれに関しては後述のトラブルシューティングに記載しています

結果比較

通常 の Thread

1775.98s user 2.64s system 99% cpu 29:40.44 total

parallel を使う

3552.51s user 269.73s system 701% cpu 9:04.50 total

3-4倍くらい速くなりました

トラブルシューティング

'dump': no _dump_data is def ined for class FFI::Pointer (TypeError)

parallel にわたすブロックに Marshal.dump できない値は渡せません
今回で言うと mecab オブジェクトが FFI::Pointer をクラスを使っており渡せないので mecab オブジェクトの生成は Tweet クラス側の initialize ではなく各種関数側で行うように修正しました

最後に

  • そんなに処理時間がかからない -> 通常のループ
  • シングルコアは MAX に使いたい -> Thread を使ったループ
  • マルチコアであるだけリソースを使いたい -> parallel を使ったループ

という感じで使い分けるといいかなと思います
parallel の場合ほぼリソースを食い尽くすことができてしまうので他のプロセスの邪魔にならないように注意しましょう

参考サイト

2024年11月21日木曜日

CryptographyDeprecationWarning: TripleDES has been moved to cryptography.hazmat.decrepit.ciphers.algorithms.TripleDES and will be removed from this module in 48.0.0. 対策

CryptographyDeprecationWarning: TripleDES has been moved to cryptography.hazmat.decrepit.ciphers.algorithms.TripleDES and will be removed from this module in 48.0.0. 対策

概要

paramiko を import する際に warning が出るのでてっとり早く対応する方法を紹介します

環境

  • Ubuntu 24.04.1
  • Python 3.10.2
  • paramiko 2.12.0

対応前

python
Python 3.10.2 (main, Feb 16 2024, 16:09:49) [GCC 11.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import paramiko
/add_disk1/.local/share/virtualenvs/api-UwQw2i9A/lib/python3.10/site-packages/paramiko/pkey.py:82: CryptographyDeprecationWarning: TripleDES has been moved to cryptography.hazmat.decrepit.ciphers.algorithms.TripleDES and will be removed from this module in 48.0.0.
  "cipher": algorithms.TripleDES,
/add_disk1/.local/share/virtualenvs/api-UwQw2i9A/lib/python3.10/site-packages/paramiko/transport.py:253: CryptographyDeprecationWarning: TripleDES has been moved to cryptography.hazmat.decrepit.ciphers.algorithms.TripleDES and will be removed from this module in 48.0.0.
  "class": algorithms.TripleDES,

対応後

python
Python 3.10.2 (main, Feb 16 2024, 16:09:49) [GCC 11.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import warnings
>>> from cryptography.utils import CryptographyDeprecationWarning
>>> warnings.simplefilter('ignore', CryptographyDeprecationWarning)
>>> import paramiko

最後に

warnings の使い方は 3.10 版になります
3.11 系からは少し違うので注意してください

参考サイト

2024年11月20日水曜日

GCP のインスタンスで swap 領域を作成する方法

GCP のインスタンスで swap 領域を作成する方法

概要

メモ

環境

  • e2-micro

コマンド

sudo dd if=/dev/sda1 of=/swapfile bs=1M count=8192
sudo chmod 600 /swapfile
sudo mkswap -f /swapfile
sudo swapon /swapfile
swapon -s

fstab

  • sudo vim /etc/fstab
/swapfile1  swap   swap    defaults   0 0

最後に

昔の f1 シリーズだとスワップがないと動作しないケースがあったが最近の e2 ではスワップなしでも問題ないケースが多いです

それでもメモリ領域が足りない場合にはスワップを作成して対応してください

2024年11月19日火曜日

Sinatra 4.1.0 から permitted_hosts を有効にする必要があります

Sinatra 4.1.0 から permitted_hosts を有効にする必要があります

概要

XFH を使ったオープンリダイレクトの脆弱性を指摘され rack_protection を使ったホスト名 認証を導入したので設定が必要になります
許可されていないホストからのアクセスは Host not permitted になります

環境

  • macOS 15.1
  • Ruby 3.3.5
  • Sinatra 4.1.0

対応方法

host_authorization で permitted_hosts に許可したホスト名を指定します

すべてのホストを許可する場合は空の配列で OK です

require "sinatra/base"

class ExampleApp < Sinatra::Base
  # disable it only for development
  configure :development do
    set :host_authorization, { permitted_hosts: [] }
  end

  # but enable it for production for some domains
  configure :production do
    set :host_authorization, { permitted_hosts: [".example.com"] }
  end

  get("/") { "OK" }
end

最後に

デフォルトでは拒否状態になっているので本番にデプロイする場合は必ず設定する必要があります

参考サイト

mosquitto を docker で起動する方法

mosquitto を docker で起動する方法

概要

公式イメージを使ってブローカーを起動する方法を紹介します
認証などはない設定なので検証目的で使いましょう

環境

  • macOS 15.1
  • docker 27.3.1
  • mosquitto 2.0.20

mosquitto.conf

  • vim mosquitto.conf
listener 1883
allow_anonymous true

起動

  • docker run --rm -it -p 1883:1883 -v $(pwd)/mosquitto.conf:/mosquitto/config/mosquitto.conf eclipse-mosquitto

動作確認

sub

  • docker run --rm eclipse-mosquitto mosquitto_sub -t test/topic -p 1883 -h 192.168.1.48

pub

  • docker run --rm eclipse-mosquitto mosquitto_pub -t test/topic -p 1883 -h 192.168.1.48 -m "hoge"

ログ

1731982775: mosquitto version 2.0.20 starting
1731982775: Config loaded from /mosquitto/config/mosquitto.conf.
1731982775: Opening ipv4 listen socket on port 1883.
1731982775: Opening ipv6 listen socket on port 1883.
1731982775: mosquitto version 2.0.20 running
1731982775: New connection from 172.17.0.1:64478 on port 1883.
1731982775: New client connected from 172.17.0.1:64478 as auto-49D03FC4-BBCD-BB77-6AEE-EED2DFA56542 (p2, c1, k60).
1731982805: New connection from 172.17.0.1:55614 on port 1883.
1731982805: New client connected from 172.17.0.1:55614 as auto-D312CD16-EB8D-8E19-7129-5619E4130433 (p2, c1, k60).
1731982805: Client auto-D312CD16-EB8D-8E19-7129-5619E4130433 disconnected.

最後に

実際に使う場合には ACL などの機能を使ってトピックにアクセス制御を設定しましょう

参考サイト

2024年11月18日月曜日

trivy で TooManyRequests が出る場合はリポジトリの参照先を複数指定しよう

trivy で TooManyRequests が出る場合はリポジトリの参照先を複数指定しよう

概要

--db-repository オプションと --java-db-repository オプションを使います
環境変数でも指定可能です
今回は Gitlab CI で使う方法を紹介します

環境

  • Gitlab 17.3.3
  • trivy 0.57.0

.gitlab-ci.yml

stages:
  - test

trivy-scan:
  stage: test
  image:
    name: aquasec/trivy:latest
    entrypoint: ['']
  variables:
    TRIVY_DB_REPOSITORY: public.ecr.aws/aquasecurity/trivy-db,aquasec/trivy-db,ghcr.io/aquasecurity/trivy-db
    TRIVY_JAVA_DB_REPOSITORY: public.ecr.aws/aquasecurity/trivy-java-db,aquasec/trivy-java-db,ghcr.io/aquasecurity/trivy-java-db
  script:
    - trivy --version
    - trivy clean --all
    - trivy image --download-db-only

最後に

リポジトリ先はカンマ区切りで指定できるので自分でミラーを作成して指定しても OK です

参考サイト

2024年11月7日木曜日

Google Cloud Storage でバケット内にオブジェクトがある場合でもバケットごと削除する方法

Google Cloud Storage でバケット内にオブジェクトがある場合でもバケットごと削除する方法

概要

gsutil を使う方法を紹介します

環境

  • macOS 15.0.1
  • gsutil 5.30

コマンド

  • gsutil rm -r gs://sound-bucket-log

参考サイト

2024年11月6日水曜日

iPhoneとChromeのパスワードを同期する方法

iPhoneとChromeのパスワードを同期する方法

概要

忘れるのでメモ

環境

  • iPhone 14 (iOS 18.0.1)
  • Chrome 130.0.6723.92

方法

設定 -> 一般 -> 自動入力とパスワード -> Chrome

のトグルをオンにする

最後に

iOS のバージョンによっては操作変わるかもです

2024年11月5日火曜日

App Engine APIs are not enabled 対策

App Engine APIs are not enabled 対策

概要

対応方法を紹介します

エラー詳細

  • gcloud app logs tail -s default
2024-10-29 04:54:19 default[20241029t134559]  2024/10/29 04:54:19 internal.flushLog: Flush RPC: Call error 7: App Engine APIs are not enabled, please add app_engine_apis: true to your app.yaml to enable.

環境

  • google-cloud-sdk 491.0.0
  • golang runtime 122

app.yaml を修正

以下を追加します

app_engine_apis: true

最後に

最新のラインタイムv2を使う場合は必要です

2024年11月1日金曜日

mtail を使って nginx にアクセスが来ているかを Prometheus で監視する方法

mtail を使って nginx にアクセスが来ているかを Prometheus で監視する方法

概要

mtail指定したログの行数を Promethues 用のメトリックスとして返してくれる exporter です
今回は nginx と連携して nginx のログを監視する compose を紹介します

環境

  • Ubuntu 24.04
  • docker 27.3.1
  • mtail 3.0.8

compose.yaml

nginx を起動しアクセスログをホスト側でマウントします
mtail 側ではホスト側のマウントした nginx のログを更にコンテナ側にマウントします

mtail の公式イメージは dockerhub で公開されていないので Dockerfile.mtail を作成し自分でビルドしてイメージを作成します

あとは mtail の設定を作成します

services:
  nginx:
    image: nginx:latest
    container_name: nginx_server
    ports:
      - "8080:80"
    volumes:
      - ./nginx/log:/var/log/nginx
    networks:
      - monitoring_net

  mtail:
    container_name: mtail_monitor
    build:
      context: .
      dockerfile: Dockerfile.mtail
    ports:
      - "3903:3903"
    volumes:
      - ./nginx/log:/var/log/nginx:ro
      - ./mtail/progs:/mtail/progs:ro
    networks:
      - monitoring_net
    command: >
      -logtostderr
      -logs /var/log/nginx/access.log
      -progs /mtail/progs

networks:
  monitoring_net:
    driver: bridge

Dockerfile.mtail

golang は執筆時の最新を使っています
mtail 自体のインストールはバイナリまたは自分でソースビルドするしかないので今回はバイナリファイルを使います

また mtail でメトリックスを取得するためのポートを expose します

FROM golang:1.23.2

RUN wget https://github.com/google/mtail/releases/download/v3.0.8/mtail_3.0.8_linux_amd64.tar.gz
RUN tar zvxf mtail_3.0.8_linux_amd64.tar.gz
RUN mv mtail /go/bin

EXPOSE 3903

ENTRYPOINT ["/go/bin/mtail"]

mtail/progs/log.mtail

mtail 用の設定ファイルを作成します
アクセスがきたときにカウントする変数を用意します
今回は nginx のどのパスにアクセスが来てもカウントをプラス1するようにします

counter nginx_requests_total

/^.*$/ {
  nginx_requests_total++
}

動作確認

  • docker compose up -d

で各種コンテナを作成しましょう

  • curl localhost:3903/metrics

にアクセスするとメトリックスが確認できます
更に

  • curl localhost:8080

にアクセスし再度メトリックスを確認するとカウンタが1進んでいるのが確認できると思います

おまけ: 特定のパスのみカウントする方法

  • vim nginx/nginx.conf
events {}

http {
    server {
        listen 80;
        
        location /status {
            default_type application/json;
            return 200 '{"status":"ok"}';
        }

        # 他のリクエストをデフォルトの404にする場合
        location / {
            return 404;
        }
    }
}
  • vim compose.yaml
services:
  nginx:
    image: nginx:latest
    container_name: nginx_server
    ports:
      - "8080:80"
    volumes:
      - ./nginx/log:/var/log/nginx
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
    networks:
      - monitoring_net

  mtail:
    container_name: mtail_monitor
    build:
      context: .
      dockerfile: Dockerfile.mtail
    ports:
      - "3903:3903"
    volumes:
      - ./nginx/log:/var/log/nginx:ro
      - ./mtail/progs:/mtail/progs:ro
    networks:
      - monitoring_net
    command: >
      -logtostderr
      -logs /var/log/nginx/access.log
      -progs /mtail/progs

networks:
  monitoring_net:
    driver: bridge
  • vim mtail/progs/log.mtail
counter nginx_requests_total

/status/ {
  nginx_requests_total++
}

最後に

mtail を使ってログの行数を Promethues のメトリックス形式で取得する方法を紹介しました
mtail 側からログファイルにアクセスできればどんなファイルでも監視することができます

ファイルは単純なテキストファイルなどでも良いです