ゲーミングディスプレイ買った

動機

数ヶ月前からめちゃめちゃに Apex をやっているんだけど、ずっとリフレッシュレートが 75Hz のディスプレイ1でプレイしていた。

www.lenovo.com


ゲーミングディスプレイにして世界が変わった!みたいな発言をインターネットでよく見るので前から 144Hz 以上のディスプレイが気になっていたんだけど、ブラックフライデーでめっちゃ安くなっていたので思い切って買ってみた。

www.lenovo.com

lenovo にしたのは、今持ってるディスプレイとデザイン合わせたいからだけでそれ以上の理由は特にない。

ちなみに今見たらブラックフライデー終わっても新たにサイバーマンデーセールが始まって価格は据え置きなので、多分一生安くなっていると思う。

使用感

なんかヌルヌルする!!!!

劇的な変化はない。若干当て感良くなったのと気がするのと、インファイト強くなった気がするけどあくまで気がする程度。

そもそももう30過ぎなので反射神経のほうが付いてこないのかもしれない。

無情。



  1. ちなみにこれは仕事用で、USB Type-C に対応していて、外部電源供給容量が十分だったので買った。

MFA アプリのデータが消滅すると破滅する

もう4年くらい iPhone7 を使っていたんだけど、 最近 Lightning 端子の接触が悪くケーブルの下に何か物をおいて角度を付けないと充電できないという不便極まりない状態だったので iPhone SE(第二世代)に機種変更した。

クイックスタート機能でデータ移行をしていたところ、残り4分のところで一生進まずどうしたものかと思っていたけど、写真とかメールとかの重要なデータは移行されていそうなのでまぁいいかと強制停止させた。

で、よく見たら一部のアプリのデータがちゃんと移行されていなかった。そのうち、MFA認証に使っている Google Authenticator のデータが消滅しているのがめっちゃ困った。


  • AWS(IAMユーザ)

    • 自分ではどうすることもできないので, 管理者の人に頼んで一旦 MFA 無効にしてもらってログインして再設定
  • Amazon

  • GitHub

    • 同じく他のPCにセッション残っていたので再設定
    • こちらは電話番号登録していたらそちらに認証コード送ることもできそうなのでなんとかなりそう
  • Facebook

    • 同じく他のPC(以下同文)
    • そもそも使ってないので消してもいいんだけど, 昔 Facebook でアカウント登録したサービスがあってそれが何か把握していないのでうかつに消せない…


すべてが無に返されたので、他にどのサービスで MFA 有効にしてたのかすら把握できていない状況…

多分しばらくしてなにかのサービスにログインしようとしたら、 MFA 要求されて積みそう。


調べてみると同じ事象に遭遇した人結構居るようで、Mirosoft Authenticator ならマイクロソフトアカウントにデータ保存してくれるらしいのでそっちに移行しようかな…と思っている。

ascii.jp

npm パッケージを beta 版で publish する

開発中の npm パッケージを publish して動作確認する必要があったのでその時の手順メモ.

バージョン指定

npm パッケージの package.jsonversion を, 1.0.0-beta.0 のように末尾に-beta-? が付くように書き換える.

またはnpm version premajor --preid betaコマンド打つと上記と同じような感じに書き換えてくれる.

https://docs.npmjs.com/cli/v6/commands/npm-version

特にbetaという文字列でなければいけないということではないので, nextでもnightlyでも開発中バージョンとわかるものであれば良さそうだけど様々なリポジトリ見る限りはbetaが多そう?

publish

npm publish --tag beta のようにタグを指定して publish する.

ちなみに, タグを付けないと default でlatest タグが設定される.

https://docs.npmjs.com/cli/v6/commands/npm-publish

使うとき

npm install hogehoge@beta のようにタグ指定でインストールすればよい.

またはnpm install hogehoge@1.0.0-beta.0 のようにバージョン直指定でもよい.

在宅ワーク中に家族に会議中だとアピールするライフハック

現在在宅ワーク中なわけだけど, 家族にミーティング中ですとアピールするために, ミーティングはいい感じのランプを点灯させたりしている。

f:id:magaming:20211005194559j:plain
こんなやつ

ただミーティング始まる/終わったときに手動でON/OFFするの面倒なので, 自動化してみた。

事前準備

まずは遠隔で操作できるように, スマートプラグを用意。

TP-Link のやつが安いのでそれにした。IFTTT 対応しているなら別なやつでもよさそう。Amazon でポチったら速攻届いたので, Webhook の設定して HTTP request 投げて点いたり消えたりしたのを確認。

www.wassyoi-hack.com

Chrome 拡張を作る

弊社ではミーティングに Google Meets を使用しているので, meet.google.com ドメインを開いたときにランプを点灯, 閉じたら消灯, みたいにしたい。今回はそれ用の Chrome 拡張を作った。どうやら chrome.tabs API を使えば現在開いているタブ一覧とかを取得できるので, それを使ってみる。

developer.chrome.com

manifes.json はこんな感じ。

{
  "manifest_version": 2,
  "name": "Google Meets 開いたらランプつけるくん",
  "description": "Google Meets 開いたらランプつけてくれます",
  "version": "1.0",
  "background": {
    "scripts": ["event.js"],
    "persistent": false
  },
  "permissions": ["tabs", "*://maker.ifttt.com/*"]
}

permissions に ifttt のドメインを指定しているのは, こうしないと CORS エラーで怒られるため。あとは適当に js 本体を用意。

const googleMeetsDomain = "meet.google.com";
const turnOnUrl =
  "https://maker.ifttt.com/hogehogehogel";
const turnOffUrl =
  "https://maker.ifttt.com/fugafugafuga";

var isTurnOn = 0;

function watchTabs() {
  chrome.tabs.query({}, (tabs) => {
    const isOpeningMeets = tabs.some((tab) => {
      return tab.url.match(/meet.google.com/);
    });

    if (isOpeningMeets && !isTurnOn) {
      request(turnOnUrl);
      isTurnOn = 1;
    }

    if (!isOpeningMeets && isTurnOn) {
      request(turnOffUrl);
      isTurnOn = 0;
    }
  });
}

function request(url) {
  var req = new XMLHttpRequest();
  req.open("GET", url);
  req.send();
}

chrome.tabs.onUpdated.addListener(watchTabs);
chrome.tabs.onRemoved.addListener(watchTabs);

chrome.tabs.query で全タブの url をなめて, Meets の url が含まれていれば ON, 含まれていないなら OFF する感じ。onRemoved はタブを閉じたとき、onUpdated はタブが更新されたときのイベント。Chrome 自体を閉じたときはこれだとダメだけど, あんまり困ってないのでまぁよいか, となっている。

実際の様子

f:id:magaming:20211006201118g:plain

Meets だけじゃなくて, 例えば youtube でご機嫌な動画を流したときにミラーボールを点灯するとか, 仕事中に Twitter を見始めたら吹き矢が飛んでくる, みたいなことに応用が効きそう。

Firebase Authentication の匿名ユーザーを削除する

Firebase Authentication で匿名ユーザーを使う場合, プランに関わらずユーザーアカウントの上限は1億までになっている。

Firebase Authentication の上限


つまり1億PV以上になると新たに匿名ユーザーを作れず破滅する可能性があるので, 定期的にユーザーの削除が必要になってくる。


めちゃめちゃバズらないと1億PVはそうそう行かなそうだけど, 可能性はゼロではないので対策しておいたほうがよさそう。


匿名ユーザーの削除は Firebase 側では自動でやってくれたりはしないので、自動でスクリプトなどを用意する必要がある。


今回は golang で削除スクリプトを実装した。

package main

import (
    "context"
    "fmt"
    "log"
    "os"
    "time"

    firebase "firebase.google.com/go/v4"
    "firebase.google.com/go/v4/auth"
    "google.golang.org/api/iterator"
)

const maxDeletableUsersCount = 1000

func main() {
    ctx := context.Background()

    app, err := firebase.NewApp(ctx, nil)
    if err != nil {
        log.Fatalf("error new firebase app: %s\n", err)
    }

    auth, err := app.Auth(ctx)
    if err != nil {
        log.Fatalf("error create auth client: %s\n", err)
    }

    users, err := getInactiveAnonymousUsers(ctx, auth)
    if err != nil {
        log.Fatalf("error get users: %s\n", err)
    }

    fmt.Printf("%v個の匿名ユーザーアカウントが削除されます。よろしいですか? [y/n]:", len(users))

    var answer string
    fmt.Scan(&answer)

    if answer != "y" && answer != "Y" {
        os.Exit(1)
    }

    successCount, failureCount, err := deleteUsers(ctx, auth, users)
    if err != nil {
        log.Fatalf("error delete users, error:%s, success:%v, failure:%v\n", err, successCount, failureCount)
    }

    fmt.Printf("delete user complete, success:%v, failure:%v\n", successCount, failureCount)
}

func getInactiveAnonymousUsers(ctx context.Context, auth *auth.Client) ([]string, error) {
    var users []string

    iter := auth.Users(ctx, "")
    for {
        user, err := iter.Next()
        if err == iterator.Done {
            break
        }

        if err != nil {
            return nil, err
        }

        // 匿名ユーザーではない場合削除しない
                 // 匿名ユーザーしかいない場合は問答無用で削除してしまってよさそう
        if len(user.ProviderUserInfo) > 0 {
            continue
        }

        // LastLogInTimeStamp は ミリ秒 までを含めた値が返ってくるのに対し
        // time.Unix()は 秒 までを含めた値が返ってくるので, 比較できるように丸める
        // https://firebase.google.com/docs/reference/admin/java/reference/com/google/firebase/auth/UserMetadata#public-long-getlastsignintimestamp
        lastLogInTimestamp := user.UserMetadata.LastLogInTimestamp / time.Second.Milliseconds()
        // 1ヶ月以上ログインしていないユーザーを削除対象にする
        if lastLogInTimestamp < time.Now().AddDate(0, -1, 0).Unix() {
            users = append(users, user.UID)
            fmt.Printf("deletable user, uid:%s, last login:%v \n", user.UID, time.Unix(lastLogInTimestamp, 0))
        }
    }

    return users, nil
}

func deleteUsers(ctx context.Context, auth *auth.Client, uIDs []string) (successCount int, failureCount int, err error) {
    successCount = 0
    failureCount = 0

    // auth.DeleteUsers で削除できるユーザーは1000件までなので, スライスを1000件に分割して繰り返し実行する
    for len(uIDs) > maxDeletableUsersCount {
        slice := uIDs[0:maxDeletableUsersCount]
        uIDs = uIDs[maxDeletableUsersCount:]
        result, err := auth.DeleteUsers(ctx, slice)
        if err != nil {
            return successCount, failureCount, err
        }
        successCount += result.SuccessCount
        failureCount += result.FailureCount
    }

    result, err := auth.DeleteUsers(ctx, uIDs)
    if err != nil {
        return successCount, failureCount, err
    }
    successCount += result.SuccessCount
    failureCount += result.FailureCount

    return successCount, failureCount, nil
}

あとはこれを cron 等で定期的に実行してあげれば安心。

【Golang】VSCodeで自動生成されるテストコードをカスタマイズする

こんにちは。Goのテスト、書いていますか?
私はめちゃめちゃ書いています。

VSCode拡張機能(vscode-go)を入れることで、テストコードを自動生成することができることを最近知ったのですが、これがとても便利です。

使い方は以下の記事でまとめられています。

kdnakt.hatenablog.com

これはめちゃめちゃ便利なのですが、デフォルトだと少し物足ないところがあったので、カスタムテンプレートを作成しました。

GitHub - Magaming/gotests-templates

vscode-goは内部でgotestsを使っているので、それ用のテンプレートを用意している形です。
具体的には次のようなことをしています。

  • go-cmpを使う
    • 標準だと reflect.DeepEqualで比較しているが、これだとtime.Time型を含んだ構造体の比較とかで死ぬ
      • go-cmpは、そこだけ無視して比較ができるのでめちゃめちゃ便利
  • %v --> %#v にする
    • フィールド名が出たほうがデバッグに役立ちそうなのでそうしている
  • あとはメッセージの文言少し変えているけどまぁこれは好みの問題

テンプレートをローカルに置いて、VSCodeのsetting.jsonに設定を加えれば反映されてあとはハッピーです。

"go.generateTestsFlags": [
  "-template_dir",
  "/your_local_directory/gotests-templates/templates"
]

皆様もテンプレート作って幸せな生活をしてはいかがでしょうか。

カウントダウンタイマーアプリを作った

1月末で現職を退職予定なんだけど、「いつまで出社なの?」とよく聞かれるので、退職までの残り時間をシェアできるアプリを作った。
timer-maker.com

スキルセット

フロントエンド:React.js + TypeScript
ホスティング:Netlify

最初firebaseを使おうと思ったけど、入力項目がタイトルと日付の2項目だけなのでURLパラメータに保存することにした。
それならフロント側だけ考えれば済むので。

Netlify所感

静的サイトホスティングにはNetlifyいいよ!巷でウワサだったで使ってみた結果。

メリット
デメリット

ない

最後に

timer-maker.com

2020.1.31 追記

OGP画像が生成できるようになりました!