sbtからMaven Centralにライブラリをpublishする
毎回ググり直している気がするのでメモを…
初回のpublishはsbtのドキュメント通りにやれば問題ない(なかったと思う)です。
sbt Reference Manual — Using Sonatype
2回目以降の手順については以下。
1. sbtからpublishSignedタスクを実行する
$ sbt publishSigned
2. PGPパスフレーズを入力
Please enter PGP passphrase (or ENTER to abort)
と聞かれるのでを入力。
パスフレーズは初回時に自分で設定しているはずなので頑張って思い出す。
3. SonatypeからCentral Repositoryにリリース
2が成功するとSonatype社のリポジトリにリリースがされる。
ここからMaven Centralに向けて再度リリースをする。
ここからの手順はこちらを参考に。 central.sonatype.org
まずはSonotypeのリポジトリにアクセスしてログイン。
左側のメニューからStaging Repositories
を選択し、先ほどリリースした自分のライブラリにチェックを入れる。
チェックを入れたら上のメニューのClose
をクリック。しばらく待って完了したらRelease
をクリックしてMaven Centralへリリースを行う。
絵文字URL短縮サービスをつくりました😎
※ 2020年5月現在、サービスは停止中です。
Unicode Emojiを利用したURL短縮サービスを作ってみました。
何かしら絵文字を使ったサービスを作ってみたいなーとは以前から考えていたのですが、「絵文字の種類数を基数としたN進数でURLを短縮するのはどうだろう?」と思いついたのでやってみました。
バックエンドはScala + PlayをElastic Beanstalkで動かしています。短縮URLのリダイレクトにはS3のWebsite Redirect Location機能を使っています。 (今考えればAWS JavaScript SDK + Cognito + S3でサーバーレスにしてもよかったかも知れません...)
遊び半分で作ってみたものなのでずっとサービスとして提供し続けられるかは分かりませんが、ふとした折に使っていただけると幸いですw
Scala Days 2017 Copenhagen 3日目
とうとう最終日です。
Keynote: Open source is just about the source, isn’t it?
Stuff open source projects need to care about that aren’t code:
— Jan Lehnardt (@janl) 2016年3月23日
- People
- Name & trademark enforcement
- Copyright
- License
- Patents
- PR
最終日のキーノートはApache Mahoutのファウンダーである@mainecさんによるOSSについてのセッションです。
続きを読む長時間のフライトで役立ったグッズ
Scala Daysに参加するため、昨日からコペンハーゲンに来ています。
日本からのフライトは10時間ほどかかるのですが、昨年のサンフランシスコへのフライト(13時間!)では完全に腰を撃破されてしまったため、今回は快適に過ごせるように便利グッズをいくつか持ち込んでみました。
Rock Dan(収納ケース付き)フットレスト
座席前のテーブルに引っ掛け、足を乗せて使うものです。見た目も構造も簡素なのですが大変効果がありました。足を投げ出せるだけでだいぶ違います。
もともとは¥8,000ほどするものらしいですが、今は83%オフ(!)で¥1,000ちょっとなのでエイヤーと買ってしまいました。このくらいの価格で買えるなら2~3時間のフライトでも持っていて損はないと思います。
HOMECUBE 改良版 エアーピロー
膨らませて使う大型の枕です。大型と言ってもそこまで大量に息を吹き込む必要はありませんでした。
折りたたんだ状態では小さい水筒ほどのサイズなので、カバンにぽんと入れて持っていきました。(使った後自分でたたむのはなかなか大変でしたが…)
飛行機の座席を倒しづらいシーンはままあると思うのですが(いかついお兄さんが後ろに座ってるとか)、そういう際にこういう枕があると非常に便利だと思います。
中がちょっとした空洞になっているので、中でスマホや携帯ゲーム機を使ったりもできます。以前にちょっと話題になった1人ダンボールシアターと同じ要領ですね。
腰も無事フライトに耐えきったので、今日からのScala Daysを楽しみたいと思います!
「JSONにコメント書きたい!」って思ったあなたにはHjsonがおすすめ。
JSONにコメントを残したいなあと思うことは多々あるかと思います。 特に設定ファイルの場合、「なぜこの値にしているのか」「取りうる値の範囲」などの情報を残しておけるとありがたそうですね。
先日、Hjsonなるものを発見しました。コメントが残せる以外にも、末尾のカンマやクオーテーションが不要だったりと、なかなか快適そうです。
Javaでの実装があるので、これをScalaから利用してみます。
hjson-java
出力
Name: Shunsuke Tadokoro Colors: ["red","green","blue"] Greet: Hello, HJSON! Regex: ^\d{2,4}\.\w+?-\d+ HTML: <h1>HTML Element</h1> 若さ 若さってなんだ ふりむかないことさ 愛ってなんだ ためらわないことさ
ここまで簡潔に書きたいならそもそもYAMLでいいのではという気もしますが、 通常のJSONもHjsonとしてパースできるという後方互換性(?)があるので、 JSONを扱う既存のコードにすんなりと組み込めるという点ではこちらに分がありそうです。
ScalaでウェブページのCharsetを取得する
サイトのエンコードは、
- HTML, head内のmeta charset
- レスポンスヘッダのContent-Type内
の2箇所に記述してあるケースが多いのですが、前者はサイト作成者の記述ミスが多々あるため信用できず、後者もまれにエンコード名として異常な文字列が入っていることがあります。
(以前、charset=%E6%96%87%E5%AD%97%E3%82%B3%E3%83%BC%E3%83%89
という胸騒ぎがする指定を発見し、いざデコードしてみるとcharset=文字コード
が出てくるというハートウォーミングな出来事がありました。マジかよ。)
そのため、エンコードを判定する機能が必要になります。
今回、判定にはMozilla製エンコード検出ライブラリuniversalchardetのJava実装版であるjuniversalchardetを利用しました。
juniversalchardet - Google Code Archive
エンコードを判別したいバイト列をUniversalDetectorクラスのインスタンスにハンドリングさせエンコード名を取得、と利用するようです。
Javaから利用するサンプルコードが公式にあります。
ただなんでもかんでもこいつに判定させるのはパフォーマンス的によろしくなさそうなので、 あくまでも「Content-Typeのcharsetが存在しない、もしくはエンコードとして扱えない文字列が指定されている場合」のみ判定をを行うのがよさそうです。
import java.nio.charset.Charset import scala.util.{Failure, Success, Try} import org.mozilla.universalchardet.UniversalDetector /** * Content-Typeヘッダからcharsetを取得する。 * ただし、Content-Typeで指定されたcharsetがエンコーディング名として不正な場合は、渡されたバイト列からcharsetを検出する。 * エンコーディング名として正しいcharsetがContent-Typeから取得できず、渡されたバイト列からも検出できない場合はNoneを返す。 */ protected def getCharset(contentType: String, bytes: Array[Byte]): Option[String] = { def _detect(bytes: Array[Byte]): Option[String] = { val ud = new UniversalDetector(null) ud.handleData(bytes, 0, 1024) // パフォーマンスを考慮し、先頭1024バイトのみで判定する ud.dataEnd() Option(ud.getDetectedCharset) } """.*charset=(.+)""".r.findAllIn(contentType).matchData .map(_.group(1)).toList.headOption.flatMap { charsetName => Try { Charset.forName(charsetName) } match { case Success(_) => Some(charsetName) case Failure(_) => _detect(bytes) } } } val res = ... // レスポンス val contentType: String = res.getContentType val bodyAsBytes: Array[Byte] = res.getResponseBodyAsBytes val charset: Option[String] = getCharset(contentType, bodyAsBytes)
まだ改良の余地はありますが、これでひとまず判定ができるようになります。