Vimで正規表現を使ってスネークケースとキャメルケースを相互変換する
Vimでスネークケースとキャメルケースを相互に変換する方法を紹介します。
スネークケース -> キャメルケース
以下のような文字列を変換する
hoge_fuga_piyo_foo_bar_baz
コマンドラインモードで以下のように入力
:%s/\v_(.)/\u\1/g
結果
hogeFugaPiyoFooBarBaz
スネークケース -> アッパーキャメルケース(パスカルケース)
以下のような文字列を変換する
hoge_fuga_piyo_foo_bar_baz
コマンドラインモードで以下のように入力
:%s/\v(^|_)(.)/\u\2/g
結果
HogeFugaPiyoFooBarBaz
キャメルケース -> スネークケース
以下のような文字列を変換
hogeFugaPiyoFooBarBaz
コマンドラインモードで以下のように入力
%s/\v([a-z]\@=)([A-Z])/\1_\l\2/g
結果
hoge_fuga_piyo_foo_bar_baz
雨は夜更け過ぎにコミットログへ変わるクソアプリを作った
この記事はクソアプリ2 Advent Calendar 2019 - Qiitaの24日目の記事です。
作ったクソアプリ
「雨は夜更け過ぎにコミットログに変わる」クソアプリを作りました。
聖夜に空を見上げるとコミットログがふわふわと降ってくる。
あぁ今年はこんなコードを書いたっけなぁと思いを馳せながら眺める光景はきっと美しく、荒んだ心を癒やしてくれるに違いないと思って作りましたがそんなことはありませんでした。
おわり
これは何か
GitHub APIを通してリポジトリのコミットログを取得し、そのコミットログを雪とともに降らせるアプリです。
右上にリポジトリ名を入力してEnterすると、好きなリポジトリのコミットログを降らせることができます(Privateリポジトリは不可)。
試してみてくれると喜びます。
なにで作ったか
three.jsを使ったWebGLのアプリです。
PCではマウス操作で、AndroidやiOSではジャイロを使って全方位を見渡せるようになっています。 three.jsで提供されているクラスやライブラリを使って、今回のアプリは簡単に実装可能でした。
実際のところ3Dに関する知識やWebGLに関する低レイヤーな部分についてはほとんど分かっていないのですが、それでも何となく動くものが作れるというのはthree.jsのすごさでしょう。
コードは以下にあります。
苦労した点 その1
とにかくロードに時間がかかる
three.jsはminifyしたものでも約600KBのファイルサイズです。
その他の今回使用したライブラリを含めたbundleしたJavaScriptファイルは、nginxでgzipして配信しても約500KBとなっています。
webpackのTree Shakingで使用しないコードを削ぎ落とせないか考えたのですが、現時点においてはTree Shakingに対応できていないようでした。
three.jsの本体だけでなく、アセットもファイルサイズが大きくなりがちです。
このアプリでは背景に360°の全天球画像を使用しています。
背景を画面いっぱいに表示するため、それなりの解像度が必要かつ、Retinaでも表示することを考えると解像度を落としづらいという問題があります。
そのため、背景画像だけで485KBにもなってしまいました。
fontもかなりのファイルサイズになります。
three.jsでtextをレンダリングするには、fontデータをJSON形式に変換したものが必要です(これはfacetype.jsで生成できます)。
欧文フォントであれば数十キロバイト程度ですが、和文フォントとなると数MB〜十数MBにもなります。
今回使用した和文フォントのJSONは、gzipで配信してもなお2MBの巨大ファイルとなってしまいました。
これらのファイルをダウンロードするにはかなりの時間を要するため、なんらかのごまかしが必要です。
ローディング時間をごまかす
このアプリで使用するすべてのリソースサイズを合計すると3MBにもなります。
環境にもよりますが、すべてのロード完了までには結構な時間がかかってしまうでしょう。
特にWifiに接続していないモバイル環境では致命的です。
そこで、いくつかのステップでユーザーに離脱されないようにごまかしを施しました。
script要素のdefer属性
まず、メインのJavaScriptファイルとなるbundle.jsのscript要素にdefer
属性を付与し、500KBのbundle.jsのロード完了まで「何も表示されない」という最悪の状況を回避します。
よく意味が分からないテキストを表示
つづいて、よく意味が分からないテキストを表示し、時間稼ぎをします。
「こいつは何をいっているんだ?」という疑問でほんの少し時間を稼げたら幸いです。
「雨は夜更け過ぎにコミットログへ変わる」がそれです。
ローディングステータスの表示
それだけでは時間が稼ぎきれないので、ローディングステータスを表示します。
フリーズしている訳ではなく、確実にロードが進行していることをユーザーに伝えます。
単純なスピーナーでは進行状況を伝えられないので、全体のアセット数とロード完了したアセット数をテキストで表示しています。
three.jsで提供されているLoadingManager
を使用すると、アセットのローディング状況をイベントで取得可能です。
参考: https://threejs.org/docs/#api/en/loaders/managers/LoadingManager
とりあえずサンプルリポジトリのコミットログを降らせる
ひとまずアプリを動かせる最低限のローディングが完了したら、サンプルとなる自前のリポジトリのコミットログを降らせてしまいます。
このサンプルを動かしている裏では、ファイルサイズの大きい和文フォントのJSONをロードしており、ユーザーが任意のリポジトリを指定した際に日本語を表示できるように備えます。
サンプルリポジトリのコミットメッセージには英字のみを使用し、和文フォントを必要としないためサイズの小さい欧文フォントでまかなっています。
以上
このような感じでごまかしている気でいますが、1Mbps以下の通信速度のような環境ではロード完了までかなりの忍耐が必要になります。
昼休みなどの混み合う時間帯は厳しいかもしれません。
苦労した点 その2
テキストのオブジェクト生成処理が重い
テキストのオブジェクト(TextGeometry)の生成処理がとても重く、かなりの時間を要します。
100文字前後のテキストで百数十ミリ秒の処理時間がかかっていました。
これはMacBookPro 2019で実行した結果なので、スマホなどの非力なデバイスだとさらに遅くなります。
このアプリでは最大100コミットログを表示しているため、すべてのTextGeometryを生成するのに数秒〜数十秒かかります。
JavaScriptはシングルスレッドで動作するため、TextGeometryの生成処理が動いている間はrequestAnimationFrameの呼び出しがされずフリーズしてしまいます。
WebWorkerに処理を委譲しようとするも失敗
これを解決するため、TextGeometryの生成処理をWebWorkerに委譲できないか試してみましたが失敗しました。
WebWorkerで生成したオブジェクトをメッセージで送受信する際に、そのオブジェクトが持つ関数が失われてしまったためです。
これはメッセージをJSONにシリアライズする際に、関数を省略してしまう仕様によるものでした。
関数を残したままJSON化させる方法もあります。
参考: https://qiita.com/suetake/items/52ec9d22e978ceb3111c
しかし、詳細は忘れてしまいましたが、この方法では別の問題が発生しうまくいきませんでした。
別の方法として、Object3DクラスのtoJSON
で取得したJSONをWebWorkerから送信し、受信側でJSONLoaderを用いてdeserializeする方法を試してみましたが、TextGeometryには対応しておらずこれも失敗に終わりました。
下はうまくいかなかったコードの例です。
const geo = new THREE.TextGeometry('hogehoge'); const serialized = geo.toJSON(); const jsonLoader = new THREE.JSONLoader(); const parsed = jsonLoader.parse(serialized); // ここのパースで「TextGeometryは未対応」というエラーとなる const deserialized = parsed.geometry;
TextGeometryをTextBufferGeometryに変更
その後、調べているとTextBufferGeometry
というものの存在を知りました。
そもそも、GeometryはBufferGeometryを扱いやすくしたものらしいのですが、処理コスト的はBufferGeometryに劣るということでした(よく分かっていない)。
TextGeometryをTextBufferGeometryに変えてみるとそれだけで、おおよそ5分の1の処理時間になりました。
根本的な解決にはなっていませんが、ひとまずパフォーマンスの問題は軽減されたので妥協しています。
three.jsを初めて触ってハマった点
いくつか、はちゃめちゃにハマった点があるので、これからthree.js(WebGL)をやろうとする方が同じ轍を踏まないように記してみます。
スマホでジャイロが機能しない
これは、httpsでないページではDeviceOrientationEvent
(ジャイロ)の検知が許可されないという問題によるものでした。
Let's encryptを使うなどしてhttps化する必要があります。
Mobile Safariでジャイロが機能しない
Mobile Safariはジャイロがデフォルトで無効になっているため、iOSの設定からジャイロ機能をONにする必要があります。
参考: https://tips.spacely.co.jp/ios12-2_safari_gyro/
サンプルコードが動かない
使っているthree.jsのバージョンが異なることによって動かない場合がありました。
three.jsはセマンティックバージョニングを採用していないため分かりづらいのですが、バージョンによっては破壊的変更が含まれます。
サンプルコードで使用しているバージョンを記載してくれていることが多いので、それを確認するようにしたほうが良さそうです。
特定の端末でのみ動作しない
これはthree.jsは関係ない話ですが…
webpackのdevtool
をeval
にしてビルドしたjsをiPhoneで動作確認したところ動作しない事象に遭遇しました。
devtool
を'inline-cheap-source-map
に変更したところ問題が解消されたため、おそらく特定のブラウザの特定のバージョンにおいてeval
での解釈に問題があり動作しなかったと思われます。
特定の端末で不可解な事象に陥った場合にはwebpackを疑ってみるのも良いかもしれません。
おわりに
素敵なクリスマス・イブを!! 🎄🎁🥂🎅🏻✨
サブ4目指して初マラソンを走ったら惨敗した話
初マラソン
3/10に初のフルマラソン挑戦である「はなももマラソン」に出場しました。
フルマラソンは初でしたが、ハーフマラソンは3回経験があります。
ハーフマラソンの自己ベストは1時間45分(キロ5分)です。
フルマラソンは、サブ4を目標としていました。
ハーフマラソンの記録からして、この目標はそれほど難しくないものと考えていました。
結果
5時間58分
めちゃくそに考えが甘かったです。完全に惨敗しました。
序盤、サブ4ペースであるキロ5分40秒を目安に走っていました。
しかし、参加者の多いレースであるため、スタート直後はなかなか自分のペースで走れません。
5km地点ぐらいでやっと自分のペースの集団に位置取りでき、やっとここからが本番という感じでした。
そう思ったのも束の間、10km地点ぐらいで異変が生じました。キロ5分40秒という自分のハーフマラソンのペースから比べてもだいぶゆるいはずでしたが、息が苦しくペースを保つのがやっとという状況でした。
その後、14km時点で苦しさから逃れるようにトイレに立ち寄り、これはもうサブ4は無理だなとこの時点で諦めざるを得ませんでした。
18km地点くらいで、ついに歩いてしまいました。ハーフでも一度も歩いたことはありませんでしたが、1週間ほど前に発症した風邪が、マラソン当日もまだ完治していなかったのだと思われます。
そこからは少し走っては歩くを繰り返すレースとなりました。
そして、苦しさと同時に空腹と喉の渇きも強く感じていました。
当日の朝、腹痛でろくに朝食をとらずにレースに臨んだため、序盤からエネルギー切れを起こしていたのです。
20km地点で提供されたバナナと、沿道の方にもらったチョコレートに大いに助けられ、エネルギーを回復し耐え忍びました。
25km地点くらいからは足の痛みも大きくなりました。一度に走れる距離もどんどん短くなり、200mほど走っては500m歩くぐらいになっていたと思います。
ここからはひたすら痛みとの戦いでした。
30km地点でのこり12km、時間にして2時間(この時点ではキロ10分〜12分ペースでした)もあることに半ば絶望していました。足が痛いしタイムもボロボロだし、棄権の方法が分かっていれば棄権していたかもしれません。しかし、どうやって棄権するのか分からないため、それも叶わずただ歩き続けました。
35km地点ぐらいで沿道の方から梅干しをもらいました。この梅干しが最高にうまかった。この梅干しは人生通してうまかったものランキング、ベスト10に入るだろうと思われます。
40km地点付近で「残り10分で関門が閉じらますよ」と声をかけてもらいました。幸い、関門まで100mくらいまで来ていたのでクリアできたのですが、危うく関門でリタイアとなる状況にちょっと情けなさを感じました。
40km地点を超え、残り2kmだけとなったことろで、実はまだ走る余力があるのではないか、という謎の活力が湧いてきました。足の痛みを無視して普段のフォームで走ってみると、意外と走れる。
もうこのまま走ってゴールしてしまえと、最後の2キロはキロ5分30分ぐらいのペースで走りました。
結果、5時間58分。
当初のサブ4という目標には遠く及ばないですが、フルマラソンの厳しさを学べたことは収穫でした。
反省点
- 前日はよく眠る
- よく眠るための対策を取ること
- 朝ごはんをよく食べる
- 沢山食べること
- 走る前にもゼリー飲料で補給しておく
- エイドをもつこと
- ゼリー
- チョコレート
- 塩飴
- ドリンクをもつこと
- 給水所だけでは足りなかったため
- 序盤はペースを抑える
- 真冬のレースにする
- 自分は暑がりで気温が1桁台でないと汗をかきすぎてしまうため
- 長距離練習をもっとする
- 脚の筋力が不足していたと感じるため
次の目標
サブ4
次はサブ4を達成したいです。
仕事中にTwitterを見てサボっていることをSlackに晒しだすChrome拡張を作った
先日、slack-chikuryというChrome拡張を公開しました。
これはなにか
仕事中にTwitterなどを開くと、Slackのstatusにサボっていることを晒しだすChrome拡張です。
動作例
アイコン
数字はその日の合計サボり時間(分)です。
Slack
表示しているページのタイトルも表示されます。仕事に関係のないページを見ているのもバレバレです。
なぜ作ったか
仕事の手が止まったとき、ついTwitterを開いてしまうことはないでしょうか。自分はあります。
ビルド、テスト、CI、npm install、docker-compose upなど、あらゆる場面で細かな待ち時間が発生し、そのたびにTwitterを開く誘惑に駆られ、誘惑に負けます。
そして、その時間が生産性を落としているように感じました。
自分の意志では改善を期待できないため、外からの監視の目を頼り、脅威を作り出すことで改善を試みる狙いです。
使い方
Chrome拡張のインストール
以下のリンクから拡張をインストールしてください。
https://chrome.google.com/webstore/detail/slack-chikury/bgeefbiianafjfckcacgjkeglnijljoi?hl=ja&gl=JP
SlackのOAuth tokenを発行する
Slackのstatusの変更リクエストを実行するために、OAuth AccessTokenが必要です。
Slackのappsページを開きます。
Create New Appをクリック
App名を入力、WorkSpaceを選択し、 CreateAppをクリック
Add features and functionalityのPermissionsをクリック
ページ中頃のSelect Permission Scopesで Modify user’s profile
を選択し、Save Changes
ページ上部のOAuth Tokens & Redirect URLsで、Install App to Workspaceをクリック
Authorizeをクリック
OAuth Access Tokenをコピー
OAuth tokenを設定する
Chrome拡張のポップアップを表示し、コピーしたOAuth Tokenをペースト
オプション
拡張のポップアップより以下を設定できます。
- Time Range
- この拡張を有効にする時間の範囲です
- Day of the week
- この拡張を有効にする曜日です
- Emoji
- チクり時にstatusに表示するEmojiです
- Sabori URLs
- チクリ対象にするURLです
- 入力パターンは Match Patterns - Google Chrome を参照してください
効果はあったか?
Twitterを見る時間はゼロになりませんが、衆目に晒されている感覚を得ることで時間はだいぶ削減されました。
1日のサボり時間を数字で見れるので、自分がどれだけ集中していないかの指標とし、サボり傾向にあるときは「Twitterを見る」以外の方法でリフレッシュできないかといった対策を試みています。
おわりに
みなさんもサボりを晒して生産性を上げていきましょう。
Issue, PullRequestも歓迎です。
Swagger UIをすこしだけ見やすくしてみた
OpenAPIを採用するプロジェクトが増え、Swagger UIで生成されたAPIドキュメントを見る機会も多くなりました。
目にする機会が増えると、ドキュメント上の見づらい部分(個人の感想です)が少し目に付きます。
そこで、Swagger UIのドキュメントをStyleをイジって「すこしだけ」見やすくできないか試みてみました。
Style変更箇所
見づらいと感じたのは以下の点です。
- RequestやResponseのExample
- Responseのテーブル
これらの箇所のStyleを変更してみました。
RequestやResponseのExample
Before
フォントサイズが小さく、weightが太めに設定されているため、文字が潰れて見づらい。
After
- フォントサイズを大きめに変更
- 12px -> 15px
- weightをnormalに変更
- フォントを等幅のものに変更
Responseのテーブル
Before
Statusコードとその説明までの横幅が広く、目を動かす必要がある。
また、行の区切りを示す表示がなく、どこまでがどのStatusコードの説明か判別しづらい。
After
- Statusコードを右寄せにし、説明の近くに配置
- 行の区切りにborderを表示
Styleの全容
.swagger-ui .opblock-body pre, .swagger-ui .response-col_description__inner div.markdown { font-size: 15px; font-style: normal; font-weight: normal; } .swagger-ui .opblock-body pre { font-family: "Courier New", Consolas, monospace; } .responses-table .response { border-top: 1px solid rgba(59,65,81,.2); } .swagger-ui .response-col_status { text-align: right; padding-right: 15px !important; } .swagger-ui table tbody tr td { padding-bottom: 10px; } .swagger-ui .model { font-size: 14px; }
このStyleを適用する方法
このStyleを使ってみたい!、という方がいるかどうかはさておき、このStyleを適用するための方法をご案内します。
ユーザースタイルシートを適用するためのブラウザ拡張がいくつかあります。
それらをブラウザに導入することで、独自のStyleをwebページに適用することが可能です。
個人的には Stylus
という拡張をおすすめします(Chrome, Firefoxともにあり)。
以下に、Stylusを使用する場合の具体的な手順を説明します。
Stylusのインストール
以下のリンクより拡張をブラウザに追加します。
Styleの追加
以下のリンクよりStyleをインストールします。
https://userstyles.org/styles/168032/swagger-ui-slightly-easy-to-see
完了!
以上で完了です。
実際にSwagger UIのドキュメントを開いて、Styleが適用されているか確認してみてください。
https://petstore.swagger.io/#/pet/addPet
おわりに
もっとこうしたほうが良いのでは?とか、いやいやあなたのStyleのほうが見づらいよ!、とかご意見あればお待ちしております。
荒ぶるSlackのEmojiを静める方法
この記事はSlack Advent Calendar 2018の4日目の記事です。
追記
Preferencesの Accesibility - Animation - Allow animated images and emoji
のチェックを外すことでアニメーションを止められることが分かりました 😂
ご指摘ありがとうございました 🙇🏻
アホやな…
Emoji
私の参加するワークスペースには、多種多様なEmojiがたくさん登録されています。
そのなかでも一際目を引くEmojiがあります。
荒ぶるEmoji
アニメーションするEmojiは楽しいのですが、これが画面上に並びすぎると治安が悪くなります。
Emojiが目立ってしまい文字を読む注意が削がれ、集中が途切れてしまいます。
これはどうにかしなければ…
Emojiのアニメーションを止めたい
Emojiのアニメーションを止めてしまおう、と考えました。
javascriptでアニメーションgifを操作できるか調べてみたところ、その方法は存在するようで、ライブラリとして提供されているものをいくつか確認できます。
しかし、これらの実装はあまりお手軽ではなく少々ヘビーな印象を受けました。
もっとライトにどうにかできないものかと思案していたところ、Slackユーザー名の隣に表示される「ステータス」のEmojiはアニメーションしていないことに気づきました。
これはどうやってアニメーションを止めているのでしょうか 🤔
ステータスのEmojiはURLが異なる
デベロッパーツールを開いて確認してみたところ、ステータスのEmojiは通常のタイムラインのEmojiとは異なるURLが使われていることが分かりました。
タイムライン上の絵文字URL
https://emoji.slack-edge.com/*.gif
ステータスの絵文字URL
https://slack-imgs.com/?c=1&o1=gu&url=*
そして、ステータスのEmojiに使われているslack-imgs.com
でクエリパラメータurl=
に通常のEmojiのURLを渡すと、アニメーションgifの1枚を切り出して返してくれる機能を持つようです。
他の c
や o1
のパラメータがどういった値を受け取るのか分からないのですが、値の組み合わせによって他の機能も呼び出せるのかもしれません。
アニメーションを止めるコード
‼️ 以降はブラウザでSlackを使うことを前提とした内容です ‼️
上記のステータスのEmojiで使われているURLを使用して、タイムライン上のEmojiのアニメーションを止めてみます。
下のようなコードを Tampermonkey や Greasemonkey などの拡張機能を使ってSlackのページ上で実行します。
const observer = new MutationObserver(() => { Array.from(document.querySelectorAll('.emoji.emoji-sizer')).forEach(emoji => { const backgroundImage = emoji.style.backgroundImage || ''; const m = backgroundImage.match(/^url\("(https:\/\/emoji\.slack-edge\.com\/.*\.gif)"\)$/); if (m) { emoji.style.backgroundImage = `url("https://slack-imgs.com/?c=1&o1=gu&url=${encodeURIComponent(m[1])}")`; } }); }); observer.observe(document.querySelector('#client-ui'), { childList: true, subtree : true });
DOMの変更が検知された際に、Emojiの background-image: url(***)
をすべて置き換えてしまうというスクリプトです。
ブックマークレット
サクッと試してみたい方は、下のワンライナーをSlackを開いているタブのアドレスバーにコピペして実行してください。
単純にコピペすると先頭の javascript:
が消えてしまうので、そこだけ手入力する必要があるようです。
javascript:const observer=new MutationObserver(()=>{Array.from(document.querySelectorAll('.emoji.emoji-sizer')).forEach(emoji=>{const backgroundImage=emoji.style.backgroundImage||'';const m=backgroundImage.match(/^url\("(https:\/\/emoji\.slack-edge\.com\/.*\.gif)"\)$/);if(m){emoji.style.backgroundImage = `url("https://slack-imgs.com/?c=1&o1=gu&url=${encodeURIComponent(m[1])}")`;}});});observer.observe(document.querySelector('#client-ui'), {childList: true,subtree: true});
アニメーションしていたEmojiが止まって見えるようになったら成功です 🎉
(止まらない場合は、別のチャンネルを表示して戻ってみてください)
おわりに
Slackに気を取られ過ぎない環境を作って、集中できる時間を増やしていきたいですね!
Qiitaの記事の鮮度を測りやすくするためのChrome拡張を作った
これは何?
Qiitaの記事に投稿日時を表示させるChrome拡張です。
なぜ作った?
Qiitaでは、記事の「最終更新日時」を先頭に表示しており、投稿後に一度も更新されていない場合においてのみ「投稿日時」が表示されます。
更新日時をマウスオーバーすると投稿日時が表示されますが、ひと目で確認することはできません。
そしてQiitaでは情報の鮮度を警告する仕組みとして「1年以上経過しています」のアラートを表示する機能が備わっていますが、これは「最終更新日時」を基準に表示されています。
そのため、ちょっとしたtypoを修正するだけでこのアラートは消えてしまいます。
個人的には、このアラートと最終更新日時のみを頼りに記事の鮮度を測るのは情報が不足しているように感じていました。
中には記事を随時アップデートして最新の情報を取り込んでいる記事もあるのでしょうが、そのような記事は少数であるはずです。
投稿日時を基準に記事の鮮度を測るのが多くの場合で自然であるように感じていたため、この拡張を作りました。
こんな感じで表示されます
投稿から1年以内
投稿から1年より前かつ2年以内
投稿から2年より前
おわり
< よかったら使ってみてね
chrome.google.com
Issue, PullRequestもお待ちしております github.com