Candy, Vitamin or Painkiller

He's half man and half machine rides the metal monster

8月の絵文字界隈

なかなか面白いトピックが多かったのでちょこっとまとめてみました。

Unicode11.0の絵文字プロポーザル

8/3にワーキングドラフトが公開されました。新たに64種類の絵文字が候補に挙がっています。

http://www.unicode.org/L2/L2017/17284-emoji-recs.pdf

注目はL2/17-082で提案された頭髪絵文字でしょうか。これは既存の絵文字と頭髪絵文字を組み合わせることで髪型を表現しようというものです。
赤毛や白髪、カールした髪型やツルツルピカピカな頭を表現するための文字が提案されています。

f:id:todokr:20170902180536p:plain

http://www.unicode.org/L2/L2017/17082-natural-hair-color.pdf

一部の絵文字については、固有のコードポイントを割り当てるのか、それとも合字やZWJとして表現するのかで議論が紛糾している印象です。
たとえばSMILING FACE WITH CAPEというスーパーマン的ヒーローを表す顔絵文字が提案されているのですが、「一般的に顔絵文字はEmotionを表すものだが、これはRoleを表すものなので単体の絵文字ではなくZWJで表すべきである」という意見などが挙がっています。

f:id:todokr:20170902180806p:plain

いわば絵文字セマンティクス的な概念が誕生しているような気がしてなかなか興味深いです。意味的には単体の絵文字にするべきではないような気もしますが、かといってZWJが理想的かというとそうでもなく、フォントへの依存を高めてしまうのでなかなかに悩ましい問題ではあります。

Android 8.0 Oreoのリリースと収録された絵文字

Android 8.0 OreoではUnicode Emoji 5.0がフルサポートされ、新たに69種類の絵文字が加わりました。

f:id:todokr:20170902174432j:plain

https://blog.emojipedia.org/android-8-0-emoji-changelog/?utm_campaign=Emoji%2BWrap&utm_medium=web&utm_source=Emoji_Wrap_16

f:id:todokr:20170902175015p:plain

Face Vomitingなどは気分を害した際に積極的に使っていきたい感じがあります。

ハッシュタグ10周年とhashflag

news.livedoor.com

Twitterハッシュタグが10周年です。
あまり知られていない気がするのですが、Twiiterでは特定のハッシュタグの末尾に自動的に(Twitterオリジナルの)絵文字が追加されます。

f:id:todokr:20170902175030p:plain

これはhashflagsと呼ばれるもので、一覧は下記で確認できます。

hashfla.gs

メールで絵文字を使うと「仕事ができない」とみなされるという傾向があるという調査結果

www.forbes.com

調査によれば、笑顔の写真付きメールを受け取った場合、受信者は相手の温かさと能力を高く評価する傾向があるものの、スマイル入りメールを受け取った場合は温かさを高く、能力を低く評価する傾向があるということです。
「職場で顔文字や絵文字を使用したい場合は、職場の文化をまず理解してください」はまあそのとおりだと思います。

Facebook Emojiにblack peopleの家族絵文字が追加

blog.emojipedia.org

Facebook Emojiに新しくblack peopleの家族を表現する絵文字が125種類追加されました。
ちなみにこの分野はMicrosoft Emojiが先行していて、昨年のWindows10には52,000種類の家族絵文字が追加されています。

実際にはコードポイントのレベルで絵文字が追加されているわけではなく、ZWJに対応するフォントが増えた形ですね。
このあたりの仕組みの話は去年のEmoji Advent Calendarで記事を書きました。

qiita.com

Adobeジェンダーレス絵文字

news.livedoor.com

デザイナーのポール・ハントさんはEmojiconでも登壇をしていました。
デザインからジェンダーを切り離すことがいかに難しいかを実感させられますが、それでも理想の状態を追い求める姿には胸を打たれるものがあります。
絵文字というのは社会学政治学とテクノロジーの交差点にあたる分野なのかも知れません。自分が絵文字を面白いと思う理由はそのあたりにあるのかなという気もしました。

9月もいろいろあったらまとめるかもしれません…

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のリポジトリにアクセスしてログイン。

Nexus Repository Manager

左側のメニューからStaging Repositoriesを選択し、先ほどリリースした自分のライブラリにチェックを入れる。
チェックを入れたら上のメニューのCloseをクリック。しばらく待って完了したらReleaseをクリックしてMaven Centralへリリースを行う。

f:id:todokr:20170728184748p:plain

絵文字URL短縮サービスをつくりました😎

f:id:todokr:20170710194311p:plain

※ 2020年5月現在、サービスは停止中です。

Unicode Emojiを利用したURL短縮サービスを作ってみました。

何かしら絵文字を使ったサービスを作ってみたいなーとは以前から考えていたのですが、「絵文字の種類数を基数としたN進数でURLを短縮するのはどうだろう?」と思いついたのでやってみました。

バックエンドはScala + PlayをElastic Beanstalkで動かしています。短縮URLのリダイレクトにはS3のWebsite Redirect Location機能を使っています。 (今考えればAWS JavaScript SDK + Cognito + S3でサーバーレスにしてもよかったかも知れません...)

遊び半分で作ってみたものなのでずっとサービスとして提供し続けられるかは分かりませんが、ふとした折に使っていただけると幸いですw

http://emoji-url-shortener.com/

Scala Days 2017 Copenhagen 3日目

f:id:todokr:20170604040655p:plain

とうとう最終日です。

Keynote: Open source is just about the source, isn’t it?

最終日のキーノートはApache Mahoutのファウンダーである@mainecさんによるOSSについてのセッションです。

続きを読む

長時間のフライトで役立ったグッズ

Scala Daysに参加するため、昨日からコペンハーゲンに来ています。

日本からのフライトは10時間ほどかかるのですが、昨年のサンフランシスコへのフライト(13時間!)では完全に腰を撃破されてしまったため、今回は快適に過ごせるように便利グッズをいくつか持ち込んでみました。

Rock Dan(収納ケース付き)フットレスト

座席前のテーブルに引っ掛け、足を乗せて使うものです。見た目も構造も簡素なのですが大変効果がありました。足を投げ出せるだけでだいぶ違います。
もともとは¥8,000ほどするものらしいですが、今は83%オフ(!)で¥1,000ちょっとなのでエイヤーと買ってしまいました。このくらいの価格で買えるなら2~3時間のフライトでも持っていて損はないと思います。

HOMECUBE 改良版 エアーピロー

膨らませて使う大型の枕です。大型と言ってもそこまで大量に息を吹き込む必要はありませんでした。
折りたたんだ状態では小さい水筒ほどのサイズなので、カバンにぽんと入れて持っていきました。(使った後自分でたたむのはなかなか大変でしたが…)

f:id:todokr:20170531161414p:plain

飛行機の座席を倒しづらいシーンはままあると思うのですが(いかついお兄さんが後ろに座ってるとか)、そういう際にこういう枕があると非常に便利だと思います。
中がちょっとした空洞になっているので、中でスマホや携帯ゲーム機を使ったりもできます。以前にちょっと話題になった1人ダンボールシアターと同じ要領ですね。

腰も無事フライトに耐えきったので、今日からのScala Daysを楽しみたいと思います!

「JSONにコメント書きたい!」って思ったあなたにはHjsonがおすすめ。

f:id:todokr:20160423202157p:plain

JSONにコメントを残したいなあと思うことは多々あるかと思います。 特に設定ファイルの場合、「なぜこの値にしているのか」「取りうる値の範囲」などの情報を残しておけるとありがたそうですね。

先日、Hjsonなるものを発見しました。コメントが残せる以外にも、末尾のカンマやクオーテーションが不要だったりと、なかなか快適そうです。

Javaでの実装があるので、これをScalaから利用してみます。
hjson-java

hjson-javaをScalaから利用するサンプル

出力

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を扱う既存のコードにすんなりと組み込めるという点ではこちらに分がありそうです。

Java以外にもJS、PythonC#、.Net、PHPでの実装があるようです。

Packages for Developers

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)

まだ改良の余地はありますが、これでひとまず判定ができるようになります。