エンジニア募集のお知らせ
Unity エンジニア 募集します!!
株式会社 Abby エビイ では現在、Unity エンジニア を募集しています。
会社の場所や基本的な募集要項は以下を参照して下さい。
今回は Unity エンジニアの募集になります。
以前の募集にも書きましたが私個人としてはスキルも大事ですが、積極性や今後ののびしろがある方も採用したいと思っています。
この業界は多岐に渡り様々な知識が必要です。現状出来なくても当たり前の事は多いと思いますがまずはゲームを作りたいという情熱、そして向上心があり、伸びてくれる人材を募集します。
もちろん一緒に働く現メンバーは上記に当てはまる素晴らしいメンバーですよ :)
興味がある方は一度会社に遊びに来て下さい。
Unityへの取り組みもチャレンジですが、私自身去年の暮からキーボードの自作から組み込み系を勉強し始めました。
日々ARMのボードを文鎮化させてまたブートローダー書きこんだり、Pro microを文鎮化させたり、段ボールに入ったAndroidに喋りかけて日本語を認識させたりしています。
興味がある、一緒に働きたい方は、info@abby.co.jp までメールお願いします。
もしくは Twitter や Facebook で@mopemope宛まで連絡してください。
皆様からのご応募お待ちしております。
なお、東方神起のメンバーは募集していませんのでご了承ください。
社員募集と Let's split を使い始めてるという話
東京が死んで 僕が生まれた ...
こんにちは、人修羅です。
ジュリアナー!!トーキョー!
最近めっきり寒くなりましたが、皆さんどうお過ごしですか?え?ガチャの排出率を変えるのに忙しいって?
Good!
今回久々にブログを書きました。書いている理由は Let's split
を手に入れたからです。
手に入れてから1ヶ月以上経っていますが、最近まともに使い始めてるのでその辺の話をしたいと思います。
その前に社員募集のお知らせです。
社員募集のお知らせ
株式会社Abby エビイ では現在、社員を絶賛募集しています。
会社紹介
弊社の仕事内容としましては、ゲームの開発がメインです。
今回の募集は箱庭ゲーム開発になります。
募集要項
東京本社でプログラマを募集しています。勤務地は中目黒になります。
箱庭ゲームのサーバサイド Go
プログラマと Unity
の経験があるプログラマを募集しています。
今後のゲーム開発を見据え Unity
のリードプログラマとして働ける方を募集します。
Go
プログラマに関しては、箱庭ゲームにおけるサーバサイドの開発になります。
既にクレヨンしんちゃんやムーミンなどの大きなタイトルのサーバサイドを Go
で作っている実績があります。
どちらかに興味ある方、話を聞いてみたい方は是非 info@abby.co.jp
にメール、あるいはTwitterなどで私(@mopemope)まで連絡していただければと思います!
皆様の応募お持ちしております。
では続き。
Let's split とは
Let's split
とは最近巷を騒がせている分離型格子配列キーボードです。
Let's split
の特徴は分離型、格子配列の他 40% キーボードである点です。
通常のキーボードの 40% しかキー数がなく片方 24 キー、計 48 キーしかありません。
非常にコンパクトで、キー数が足りないわけですが、その部分はファームウェアで補います。
ファームウェアは qmk_firmware
でユーザー自身プログラミングして自由にキーマップを設定することができます。
Let's split
は略してレツプリなどの愛称でも呼ばれおり、2017年爆発的に人気が出たキーボードのひとつです。
。(今後はレツプリと略す)
レツプリいいなあと思ってたところ、レツプリ組み立て屋こと id:kumatoki 氏が売りに出している情報を得、即入手しました。
id:kumatoki 氏にはここでお礼を申し上げたいと思います。ありがとうございました。
ではレツプリを手に入れるまでの経緯を振り返ってみます。
2016年 空前の Ergodox ブーム
2016年、分離型キーボードにとても注目が集まりました。
注目が集まった理由は件の記事ですが、その中でもやはり Ergodox
の存在はとても大きかったと思います。
出始めの頃は、自分で組み立てる必要がありましたが、Ergodox EZ
の出現により一気に普及しました。
私自身もちょっと購入を検討してはいましたが購入を見送っていました。
2017年 Let's split, そして自作ブーム
2017年、既に Ergodox
は市民権を得、挫折組がメルカリに売り出すぐらいにメジャーになりました。
Ergodox
が素晴らしいのは事実なのですが、やはりデメリットもあります。
それは以下でした。
- 筐体が大きい
- 親指キーとの距離が遠い
- キー数が多く設定するのが大変そう
個人的にはキーの間がほどよく近いコンパクトなものを探していましたが既製品ではなかなかない状態でした。
前年 Ergodox
の流れもあったせいかキットによる自作キーボード、あるいは本当にキーボードを自作するブームが本格化してきました。
様々な組み立てキーボードが出てきていましたが、格子配列、コンパクトなものが多かったと思います。
なかでも Planck
は有名でしたが分離型ではありませんでした。
そこでとあるユーザーがこの Planck
を Ergodox
よろしく分離型にしてしまおうというコンセプトで PCB を公開しました。
それが Let's split
です。
Let's split
は必要なものを全て自分ではんだ付けして組み立てなければいけないのですが自作ブームの流れにのり流行しました。
レツプリで火がついたのかわかりませんが、最近では国内外でキーボードを自作する人がどんどん増え自作キーボードコミュニティの活動が活発になってきてるように思います。
40% キーボードの実用性、キーマップ
40% キーボードはやはりとてもコンパクトです。かさばらないのでフェルトケースに入れて持ち歩くことが十分に可能です。
この点がやはり一番の魅力でしょう。
しかしキー数が 48 に対するデメリットはどうでしょうか? 実用に耐えうるのか気になる方もいるかと思います。
実際に 40% キーボード は実用的なのでしょうか?これは個人差があるためなんともいえないとこですがコンパクト好きであれば多少はデメリットも許容できるのではないかと思います。
それに著名なプログラマもレツプリを使っているぐらいです。きっと良いはずです。
Let's Split のキー設定が固まってきた。今度は Ergodox Infinity だ。 (そして周囲に呆れられる)
— Yukihiro Matsumoto (@yukihiro_matz) 2017年11月12日
正直、万人向けではないと思いますが、設定をいじくりまわすのが大好きな人にはやりがい、いじりがいがあるシロモノだと思います。
またコンパクトな格子配列キーボードだと指の移動距離は本当に小さくなります。指の移動距離を最小限にしたい人、ホームポジションを矯正し直したい人にはとてもよい選択肢になるでしょう。
またキーマップはいくらでもカスタマイズできます。個人にあったキーマップを作成できればむしろ効率を上げることができます。
格子配列でカスタマイズ可能なキーボードを使い始めるとわかるのですが、カスタマイズが自由な分、自分とって打ちにくいキーはどんどん打たなくなり、捨てるようになります。
レツプリではキー数が少ないためこの現象が顕著にでてきます。レイヤーを使う前提であるレツプリでは打ちにくいキーは別レイヤーの打ちやすい位置にマッピングしてしまおうと割り切りが発生するからです。
また打ちにくいキーがあることを一旦認識してしまうとベースとなる配列ですら見直したくなります。
例えば QWERTY
配列の場合、小指で最上段 P
を押すのは正直辛いです。となると最上段を少なく使うキー配列を使いたくなってくるわけです。
また記号の類のキーマップはキー数の関係から独自にマッピングするしかありません。 覚え直す必要があるなら思い切ってベース配列も変えてしまうのもアリだと思います。
キー配列はDOVRAK
, COLEMAK
, WORKMAN
, NORMAN
, 独自配列
など自分になったものを選ぶと良いと思います。
また最下段では親指を使うことも意識すると思いますが、親指にいくつキーを割り当てるかも個人差が出てくると思います。
私も当初はQWERTY
を使っていましたが打ちにくさから COLEMAK
に乗り換えました。COLEMAK
を選択した理由は以下です。
QWERTY
だとP
を小指で打つのがしんどかったQWERTY
だとN
を打つのがしんどかったQWERTY
からの移行コストが小さい- ショートカットで使うキー
Q
,A
,Z
,X
,C
,V
はQWERTY
と変わらない - ホームポジションでの使用頻度が高い
gtypist
で練習ができる
使い始めの頃、ホームポジションからズレると戻ってこれないような感じでした。
そのため、なるべくホームポジションから動かさなくてもいいようにホームポジションでの使用頻度が高い COLEMAK
を試すとマシになったのでそのまま使っています。
移動距離のことを考えると WORKMAN
でもいいかも知れません。
参考までに以下は私の現在のキーマップです。使用しているのはおよそ 36 キーで minidox
などでも対応できるようにしています。
またラップトップに合わせて日本語配列で使用しています。
(あまり意味ないですが)
/* COLEMAK * ,-----------------------------------------, ,-----------------------------------------, * | Q | W | F | P | G | | | | J | L | U | Y | : | * |------+------+------+------+------+------| |------+------+------+------+------+------| * | A | R | S | T | D | | | | H | N | E | I | O | * |------+------+------+------+------+------| |------+------+------+------+------+------| * | Z | X | C | V | B | | | | K | M | , | . | / | * |------+------+------+------+------+------| |------+------+------+------+------+------| * | | | | CTRL |DEL/R |SP/SFT| |EN/SFT| BS/L | ALT | | | | * `-----------------------------------------' `-----------------------------------------' */ /* EMACS(COLEMAK) * ,-----------------------------------------, ,-----------------------------------------, * | Q | W | F | P | G | | | | J | L | U | Y | : | * |------+------+------+------+------+------| |------+------+------+------+------+------| * | A | R | S | T | D | | | | H | N | E | I | O | * |------+------+------+------+------+------| |------+------+------+------+------+------| * | Z | X | C | V | B | | | | K | M | , | . | / | * |------+------+------+------+------+------| |------+------+------+------+------+------| * | | | | CTRL |DEL/R |SP/SFT| |EN/EM2| BS/L | ALT | | | | * `-----------------------------------------' `-----------------------------------------' */ /* EMACS2(COLEMAK Shortcut Layer) * ,-----------------------------------------, ,-----------------------------------------, * |RESET | M-W | C-F | C-Y | C-G | | | | M-. | E-LT | UP | E-GT | | * |------+------+------+------+------+------| |------+------+------+------+------+------| * | C-A | C-R | C-S | C-T | | | | | M-% | LEFT |DOWN |RIGHT | | * |------+------+------+------+------+------| |------+------+------+------+------+------| * | C-Z | C-X | C-C | | C-B | | | | M-x | C-; | C-: | C-| | M-; | * |------+------+------+------+------+------| |------+------+------+------+------+------| * | | | | C-SL | M-D |C-SPC | | | | | | | | * `-----------------------------------------' `-----------------------------------------' */ /* LOWER (Symbol) * ,-----------------------------------------, ,-----------------------------------------, * | ! | " | # | $ | % | | | | & | ' | ` | | | yen | * |------+------+------+------+------+------| |------+------+------+------+------+------| * | ESC | @ | { | } | _ | | | | ~ | = | : | / | * | * |------+------+------+------+------+------| |------+------+------+------+------+------| * | | | ( | ) | \ | | | | ^ | - | ; | . | + | * |------+------+------+------+------+------| |------+------+------+------+------+------| * | | | | | HENK | GUI | | | | ALT | | | | * `-----------------------------------------' `-----------------------------------------' */ /* RAISE (Num + Fn + Others) * ,-----------------------------------------, ,-----------------------------------------. * | 1 | 2 | 3 | 4 | 5 | | | | 6 | 7 | 8 | 9 | 0 | * |------+------+------+------+------+------| |------+------+------+------+------+------| * | TAB | F1 | F2 | F3 | F4 | | | | F5 | F6 | [ | ] | @ | * |------+------+------+------+------+------| |------+------+------+------+------+------| * | _ | F7 | F8 | F9 | F10 | | | | F11 | F12 | ( | ) | - | * |------+------+------+------+------+------| |------+------+------+------+------+------| * | | | | | | | | GUI | MHEN | ALT | | | | * `-----------------------------------------' `-----------------------------------------' */ /* MISC (GUI) * ,-----------------------------------------, ,-----------------------------------------. * |RESET | WhDn | MsUp | WhUp |WRKSP1| | | |UWRKSP| PgDn | Up | PgUp |RESET | * |------+------+------+------+------+------| |------+------+------+------+------+------| * | | MsLf | MsDn | MsRg |WRKSP2| | | |DWRKSP| Left | Down |Right | | * |------+------+------+------+------+------| |------+------+------+------+------+------| * | | | Copy |Paste | GUI | | | |COLEMA|EMACS | Mute |VolDn |VolUp | * |------+------+------+------+------+------| |------+------+------+------+------+------| * | | | |LClick|RClick| | | |EN/CTL|BS/ALT| | | NONE | * `-----------------------------------------' `-----------------------------------------' */ /* MISC2 (GUI + Arrow) * ,-----------------------------------------, ,-----------------------------------------. * |RESET | | | | | | | | | | Up | |RESET | * |------+------+------+------+------+------| |------+------+------+------+------+------| * | TAB | | | | | | | | | Left | Down |Right | TAB | * |------+------+------+------+------+------| |------+------+------+------+------+------| * | | | | | | | | | | | | | | * |------+------+------+------+------+------| |------+------+------+------+------+------| * | | | | ALT | GUI | | | | GUI | ALT | | | NONE | * `-----------------------------------------' `-----------------------------------------' */ /* NONE * ,-----------------------------------------, ,-----------------------------------------, * | | | | | | | | | | | | | | * |------+------+------+------+------+------| |------+------+------+------+------+------| * | | | | | | | | | | | | | | * |------+------+------+------+------+------| |------+------+------+------+------+------| * | | | | | | | | | | | | | | * |------+------+------+------+------+------| |------+------+------+------+------+------| * | | | | | | | | | | | | |COLEMA| * `-----------------------------------------' `-----------------------------------------' */
A
, O
は LT で MISC
, Z
, /
には LT で MISC2
が割り当てられています。
EMACS
レイヤーの ENTER は LT で EMACS2
レイヤーでショートカットを割り当てています。
元々 Emacs
のキーバインドが爆発しているので hydra
でまとめています。
メインでよく使う機能の類は C-Z
に割りあてているのでショートカットはこれぐらいで足りています。
親指には 3 キー割当していますが、LT との組み合わせで計 5 キー割当しています。
レツプリで親指 3 キーを押しやすい形で割り当てるために親指が内側に入りすぎないように最外側から通常キーを割り当てています。
結果、最内側のキーを捨てる形になっています。
NONE
レイヤーは同時押ししやすいかなどレイアウトの確認を行うためのレイヤーになっています。
今後
レツプリは親指部分のキーに関して考慮がありません。親指を積極的に割当たい派にとってはもっとよい選択肢があるはずです。
世の中には同じようなことを考える人はやはりいて、それらの問題を解消しようとしているキーボードが幾つかあります。
コンパクトでかつ親指を使うことを意識した代表的なキーボードには以下のようなものがあります。
Minidox
は GB もあまり行われてないらしく、自前でPCBを発注したりと少々手間がかかります。
Iris
に関しては keeb.io
で扱っており比較的容易に手に入りそうです。私も Iris
を組み立てるため PCB, ケースをオーダーしました。
Iris
を組み上げた際にはまた報告したいと思います。
株式会社Abby エビイ で働くチャンス到来の話
社員を募集する話
どうもタツヤカワゴエの生まれ変わりです。
皆さん、無駄に Ruby コミッタに絡んで燃えてませんか?
今日は株式会社Abby エビイ で社員を募集する話を書きたいと思います。
どっちかっていうと急募の類です。はい。
base64で書くと怒らるので素で書きます。
募集要項
私の会社、株式会社Abby エビイ では事業拡大に伴い、パワーが足りなくなってきたためプログラマを数名募集したいと思います。会社の場所や基本的な募集要項は以下を参照して下さい。
割とプログラマフレンドリーな会社です。就業時間、開発環境(机もでかい)もそうですが、書籍、必要機材なども割と自由がききます。(本当に必要であれば!) 私は開発時にはArch Linuxを入れたマシンを3台を使っています。
採用している技術の採択理由はメンバーのスキル、安定性、学習コストを重視したものになっています。変にエッジなものは採択していません。ですが、エキスパートであるならばこの部分はいくらでも自由に変更することは可能です。もちろん責任もついてまわりますが。
サーバーサイドに関して言えば
- デプロイが楽(1バイナリファイルになる)
- 並列処理が簡単
- まともなパッケージシステムが存在
- IOがスケールする(意識させず非同期IOが使える)
という基準で言語を選んでいますが、そうなるとGo
, Haskell
ぐらいになってきます。メンバーのスキルを考えると学習コストの低いGo
がベストであろうということでGo
を採択しています。
あと私のチームに関してはメンバーのスキル向上のためプロジェクト開始時にはちょっとしたチャレンジ、改善を盛り込むようにしています。もちろんプロジェクト途中でも少しずつその部分も変わっていったり追加されます。仕事を通じてスキルアップが少しでもできるよう取り組んでいます。
以前の募集にも書きましたが私個人としてはスキルも大事ですが、積極性や今後ののびしろがある方を優先に採用したいと思っています。
この業界は多岐に渡り様々な知識が必要です。現状出来なくても当たり前の事は多いので現状のスキルとよりも向上心があり、伸びてくれる人材を探しています。
もちろん一緒に働く現メンバーは上記に当てはまる素晴らしいメンバーです:)
興味がある方は一度会社に遊びに来て下さい。
興味がある、一緒に働きたい方は、info@abby.co.jp までメールお願いします。
もしくは Twitter や Facebook で@mopemope宛まで連絡してください。
皆様からのご応募お待ちしております。
なお、東方神起のメンバーは募集していませんのでご了承ください。
Semicolonless Java を実現する話
Semicolonless Java を実現する話
デンジャラス!ゾンビ!!!
こんにちは!ゲームマスターこと 檀 黎斗 です!
2000 年問題でバグスターウィルス見つけたの僕ですから!!
からのー
ジュリアナー!!トーキョー!
こんにちわ、ジョン・ロビンソンこと半ズボンの宇宙人です。
↓
↓
↓
↓
↓
↓
↓
どうです?なんていうかアメブロっぽい感じっていうの?ムカつくでしょ??
そうでしょう!そうでしょう!
ところでみなさん、Java 書いてますか?Generics 理解してますか?
無駄にドリコムのスライドに釣られてませんか?
今回は Semicolonless Java について書いてみたいと思います。
Semicolonless Java
Semicolonless Java とはその名の通り、セミコロンを使わずに Java でプログラミングすることです。
ある種のパズル、コードゴルフの類に近いといった方が良いかも知れません。
簡単な例ですが、Hello world を出力するプログラムは以下のように書きます。
public class Hello { public static void main(String[] args) { if (null == System.out.printf("Hello world")){} } }
まあこのようにセミコロンを回避しつつコードを書いていくのですが、正直遊びの範疇をでません。
では本当の Semicolonless Javaは実現できないのでしょうか?
近年では ES6, Golang などセミコロンを書かなくても良い言語をよく目にするようになりました。
確かにセミコロンを書く必要のない言語の方が煩わしくないし、見た目もスッキリして人気がありそうです。
Java もそのようにセミコロンをなくせばもっと人気がでそうです。
従来の Java のコードをほぼそのままにセミコロンレスを実現することはできないものなのでしょうか?
JSR 199: Java Compiler API
Java には Java Compiler をプログラムから操作する API があります。
JSR 199: Java Compiler API です。javax.tools パッケージに属しています。
簡単な例を挙げます。
App.java
import java.io.File; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; import javax.tools.JavaCompiler; import javax.tools.JavaFileObject; import javax.tools.StandardJavaFileManager; import javax.tools.ToolProvider; import javax.tools.JavaCompiler.CompilationTask; public class App { public static void main(String[] args) throws Exception { final String sourceFile = "./helloworld.java"; final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); try (StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, StandardCharsets.UTF_8)) { List<File> sourceFileList = new ArrayList<File>(); sourceFileList.add(new File(sourceFile)); final Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromFiles(sourceFileList); final CompilationTask task = compiler.getTask(null, fileManager, null, null, null, compilationUnits); final boolean result = task.call(); if (result) { System.out.println("Compilation was successful"); } else { System.out.println("Compilation failed"); } } } }
ToolProvider.getSystemJavaCompiler()
から JavaCompiler
を取得、FileManager
でコンパイル対象を設定、
CompilerTask
を実行してコンパイルするような流れになります。
さてこの API ではどれくらいの事が可能なのでしょうか?
主に操作するとすれば以下の 2 クラスだと思います。
javax.tools.JavaCompiler.CompilationTask
見てみるとあの API は AnnotaionProcessor を絡めることは出来るかも知れません。
ですがコンパイラーの挙動を変更するなどといったカスタマイズ要件に対しては貧弱すぎてほぼ何もできないように見えます。
やはりセミコロンレスを実現するには処理系そのものを改修しないといけないのでしょうか??
Real world Java Compiler API
javax.tools.*
公開されている API では何もカスタマイズのしようがないのは事実です。
ですが世の中にはこの Compiler API を実際に使用して様々なことをやっているプロダクトが多数存在します。
ではどうしているのでしょうか?実際に使用している例を元に見ていきたいと思います。
ErrorProneの場合
最近、導入されることが多くなってきてる ErrorProne
ですが、この ErrorProne
もこの API を使用しています。
ErrorProne
はコンパイル時に静的解析を行います。そのため、この API でカスタマイズした静的解析付きコンパイラーを提供します。
土台になる部分のコードは以下のようになっています。
BaseErrorProneJavaCompiler.java
@Override public CompilationTask getTask( Writer out, JavaFileManager fileManager, DiagnosticListener<? super JavaFileObject> diagnosticListener, Iterable<String> options, Iterable<String> classes, Iterable<? extends JavaFileObject> compilationUnits) { ErrorProneOptions errorProneOptions = ErrorProneOptions.processArgs(options); List<String> remainingOptions = Arrays.asList(errorProneOptions.getRemainingArgs()); ImmutableList<String> javacOpts = ImmutableList.copyOf(remainingOptions); javacOpts = defaultToLatestSupportedLanguageLevel(javacOpts); javacOpts = setCompilePolicyToByFile(javacOpts); final JavacTaskImpl task = (JavacTaskImpl) javacTool.getTask( out, fileManager, diagnosticListener, javacOpts, classes, compilationUnits); setupMessageBundle(task.getContext()); RefactoringCollection[] refactoringCollection = {null}; task.addTaskListener( createAnalyzer(errorProneOptions, task.getContext(), refactoringCollection)); return new CompilationTask() { @Override public void setProcessors(Iterable<? extends Processor> processors) { task.setProcessors(processors); } @Override public void setLocale(Locale locale) { task.setLocale(locale); } @Override public Boolean call() { return wrapPotentialRefactoringCall( task.call(), new PrintWriter(out, true), refactoringCollection[0]); } }; }
注目ポイントは以下の部分です。
final JavacTaskImpl task =
(JavacTaskImpl)
javacTool.getTask(
out, fileManager, diagnosticListener, javacOpts, classes, compilationUnits);
ハイ!きました! JavacTaskImpl
!
ということで実際にカスタマイズしようとするとあのAPIでは貧弱すぎなので cast
して使用しているというのが現実です。
ErrorProne
は JavacTaskImpl
へ cast
することで使える addTaskListener
メソッドを使って静的解析を行っているのです。
簡単に addTaskListener
メソッドの説明をしておくとコンパイラーは幾つかのステージを踏んでクラスファイルを生成するのですが、このメソッドはその各ステージ、成果物作成毎に呼ばれるコールバックを設定するメソッドです。
- ステージ情報
- 対象成果物
ステージ開始、終了時に特定のメソッドが呼ばれるので ErrorProne
はその情報を元に解析を行っているのです。
その他にも JavacTask
(JavacTaskImpl
) は使われています。
ENSIME
の Java
の型情報の取得、補完情報なども JavacTask
を使用して解析されています。
では JavacTaskImpl
を使うとどれくらいのことができるのでしょうか?
セミコロンレスは実現できるのでしょうか??
Parser 載せ替え Hack
セミコロンレスを実現するにはシンプルに考えて AST
を作成時にセミコロンの有無を無視してくれれば良さそうです。
AST
を作成する Parser
実装を差し替えることができればなんとかなりそうですね。
ですが、Parser
を載せ替えるには ParserFactory
をなんらかの方法でコンパイラに読み込ませる必要があります。
この辺からは com.sun.tools.*
の知識が必要となってきますが、みなさんご存知のことでしょうからあまり深くふれないことにします。
Context
コンパイラ部は他のクラスと情報をやりとりする際に Context
クラスを使用しています。
このクラスは HashTable
のクラスのような構造でコンパイラ部で使用するものが雑多に詰まっています。
この中には ParserFactory
なども含まれています。
Context
をコンパイラが実行する前に取得し、なんらかの方法で Context
に ParserFactory
を載せることができれば…。
では早速チャレンジしてみましょう。
実装
当たり前ですが、Parser
部はすべて package-private
になっており、外部からは修正できないようになっています。
そのため、プロジェクト内で com.sun.tools.javac.parser
を定義し差し替えます。
SemicolonlessParser.java
package com.sun.tools.javac.parser; import static com.sun.tools.javac.parser.Tokens.TokenKind.SEMI; public class SemicolonlessParser extends JavacParser { protected SemicolonlessParser(final SemicolonlessParserFactory parserFactory, final Lexer lexer, final boolean b, final boolean b1, final boolean b2) { super(parserFactory, lexer, b, b1, b2); } @Override public void accept(final Tokens.TokenKind tk) { if (token.kind == tk) { nextToken(); } else if (tk == SEMI) { } else { super.accept(tk); } } }
とても雑な実装ですが、とりあえずセミコロン判定を無視していきます。
そしてこの Parser
を適用するための ParserFactory
を実装します。
SemicolonlessParserFactory.java
package com.sun.tools.javac.parser; import com.sun.tools.javac.util.Context; public class SemicolonlessParserFactory extends ParserFactory { protected SemicolonlessParserFactory(final Context context) { super(context); } public static SemicolonlessParserFactory instance(final Context context) { SemicolonlessParserFactory instance = (SemicolonlessParserFactory) context.get(parserFactoryKey); if (instance == null) { instance = new SemicolonlessParserFactory(context); } return instance; } @Override public JavacParser newParser(final CharSequence input, final boolean keepDocComments, final boolean keepEndPos, final boolean keepLineMap) { final Lexer lexer = scannerFactory.newScanner(input, keepDocComments); return new SemicolonlessParser(this, lexer, keepDocComments, keepLineMap, keepEndPos); } }
重要な実装はこれぐらいです。
どうでしょうか?とてもコード量が少なくて楽勝な感じがしてきましたね。
ではこれを Context
に設定して使用してもらうようにコンパイラ部を書いてみましょう。
BaseSemicolonlessCompiler.java
import com.sun.tools.javac.api.JavacTaskImpl; import com.sun.tools.javac.parser.SemicolonlessParserFactory; import com.sun.tools.javac.util.Context; import javax.annotation.processing.Processor; import javax.lang.model.SourceVersion; import javax.tools.*; import java.io.InputStream; import java.io.OutputStream; import java.io.Writer; import java.nio.charset.Charset; import java.util.Locale; import java.util.Set; public class BaseSemicolonlessCompiler implements JavaCompiler{ private final JavaCompiler javaCompiler; public BaseSemicolonlessCompiler(){ this.javaCompiler = ToolProvider.getSystemJavaCompiler(); } @Override public CompilationTask getTask(Writer out, JavaFileManager fileManager, DiagnosticListener<? super JavaFileObject> diagnosticListener, Iterable<String> options, Iterable<String> classes, Iterable<? extends JavaFileObject> compilationUnits) { final JavacTaskImpl task = (JavacTaskImpl) javaCompiler.getTask(out, fileManager, diagnosticListener, options, classes, compilationUnits); replaceParser(task); return new CompilationTask() { @Override public void setProcessors(Iterable<? extends Processor> processors) { task.setProcessors(processors); } @Override public void setLocale(Locale locale) { task.setLocale(locale); } @Override public Boolean call() { return task.call(); } }; } @Override public StandardJavaFileManager getStandardFileManager(DiagnosticListener<? super JavaFileObject> diagnosticListener, Locale locale, Charset charset) { return this.javaCompiler.getStandardFileManager(diagnosticListener, locale, charset); } @Override public int isSupportedOption(String option) { return 0; } @Override public int run(InputStream in, OutputStream out, OutputStream err, String... arguments) { return this.javaCompiler.run(in, out, err, arguments); } @Override public Set<SourceVersion> getSourceVersions() { return this.javaCompiler.getSourceVersions(); } private void replaceParser(final JavacTaskImpl compilerTask) { final Context context = compilerTask.getContext(); SemicolonlessParserFactory.instance(context); } }
重要なのは replaceParser
メソッドのみです。
JavacTaskImpl
に cast
すると getContext
メソッドが見えるようになり、Context
を操作することができます。
ParserFactory.instance
にセットしてしまえば準備完了です。
では簡単に呼び出せるようにさらに実装をしていきましょう。
SemicolonlessCompiler.java
import javax.tools.*; import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class SemicolonlessCompiler { public CompileResult compile(final List<File> sourceFileList, final File output) throws IOException { final JavaCompiler compiler = new BaseSemicolonlessCompiler(); try (StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, StandardCharsets.UTF_8)) { final Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromFiles(sourceFileList); final DiagnosticCollector<JavaFileObject> diagnosticCollector = new DiagnosticCollector<>(); final List<String> compileOptions = Arrays.asList( "-g", "-deprecation", "-d", output.getCanonicalPath(), "-source", "1.8", "-target", "1.8", "-encoding", "UTF-8" ); final JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnosticCollector, compileOptions, null, compilationUnits); final boolean result = task.call(); return new CompileResult(result, diagnosticCollector.getDiagnostics()); } } public class CompileResult { private final boolean success; private List<Diagnostic<? extends JavaFileObject>> diagnostics = new ArrayList<>(); CompileResult(final boolean success, final List<Diagnostic<? extends JavaFileObject>> diagnostics) { this.success = success; this.diagnostics = new ArrayList<>(diagnostics); } public boolean isSuccess() { return success; } public List<Diagnostic<? extends JavaFileObject>> getDiagnostics() { return diagnostics; } } }
動作確認にための簡単なテストを書いて実行してみましょう。
SemicolonlessCompilerTest.java
import org.junit.Test; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import static org.junit.Assert.*; public class SemicolonlessCompilerTest { @Test public void testCompile() throws IOException { final File out = new File(System.getProperty("java.io.tmpdir"), "out"); out.mkdirs(); final SemicolonlessCompiler compiler = new SemicolonlessCompiler(); final List<File> targets = new ArrayList<>(); final File file = new File("./src/test/resources/Hello.java").getCanonicalFile(); assertTrue(file.exists()); targets.add(file); final SemicolonlessCompiler.CompileResult compileResult = compiler.compile(targets, out); assertEquals(true, compileResult.isSuccess()); } }
コンパイル対象は以下です。もちろんセミコロンレスです。
Hello.java
public class Hello { public void greeting() { System.out.println("Hello world") } public static void main(String[] args) throws Exception { new Hello().greeting() } }
テストを実行すると tmpdir
の out
に Hello.class
ができているはずです。
そのディレクトリへ移動し、実行してみると…。
$ java Hello Hello world
成功しました!
これでいくらでもセミコロンレスにできそうです!!!
とざっくり Java コンパイラーの挙動を変える方法を紹介してみました。
今回、作成したものは以下から参照できます。興味のある方は見て動かしてみて下さい。
Abby 社員募集について
最後に現在 株式会社Abby では社員を募集しています。
現在進行系のプロジェクトでは以下のような技術を使用しています。(主なもの)
興味がある方は info@abby.co.jp までメールを下さい。
もしくはTwitterやFacebookで@mopemope宛まで連絡してください。
そして一度弊社まで遊びにきてください。皆様からの応募お待ちしております。
(あのeseharaでさえ一度遊びに来てるので多くの場合問題ないと思います)
あと Emacs
で Java
書きたい狂人のコントリビューターも募集中です!!
なお、東方神起のメンバーは募集していませんのでご了承ください。
2015 振り返り
2015 振り返り
2015 年はアウトプットはあまりありませんでした。ただ今後への投資という意味でなかなか成果があった年ではないかと思います。
後半はほぼ Go を書いていた気がしますが、やはり、軽量プロセス、速度、配布の容易さという点を重視したものに投資してきたかなあという印象です。
後半、開発環境系を見直しました。
Clojure
Clojure は以前より使っていたのですが、やっと ClojureScript の実戦投入をしました。
UI は Reagent (React) を使用した SPA です。
やはり少数精鋭で Clojure を使うと生産性の桁が違うというところを実感しました。
Java 案件は全て Clojure でも構わないくらいでしょう。
Javascript
やっと少しずつですが最近の流行りっぽいものに追随しはじめました。
ES6 も導入し、よりモダンな環境を使うように移行してきています。
最近は vuejs + webpack でフロントエンドを構築しています。
React については素で使う気がしないので Reagent などを使わない場合には無理に使用しないという方針です。
Go
某ゲームサーバーなどで導入開始しました。Go 1.4 → Go 1.5 へのアップグレードも行いました。
小さな問題はありましたがほぼ問題ないといっていいぐらいの安定っぷりです。
Erlang(LFE)
重い腰をあげてやっと Erlang を少し勉強しはじめました。
普通に Erlang を書いても仕方がないので LFE で書いています。
結論としてはよほどのことがない限りうちでは 使うことはない です。
Haskell
寝かせていた Haskell をまた勉強しはじめました。Lens など放置してた部分を少しずつ勉強し始めています。
今年は stackage, stack などの登場により更に開発のしきいが下がったと思います。
勉強がてら過去に書いていたツールなどもライブラリ更新、 stack 対応などもしました。
開発環境
Arch Linux を相変わらずメインに使っています。
ibus-mozc の点が気になったので fcitx へ乗り換え、ついでに ibus を使わないので Gnome3 をやめ xmonad を再度導入しました。
xmonad も真面目に設定を書いたので快適度があがりました。
zsh → fish への乗り換えもしました。人のコピペで作られた zsh を捨てることにより本当に必要な環境を構築できたと思います。
emacs 環境も見直し、ac -> company に乗り換えたりなどもしました。
rkt → docker に出戻りしました。rkt は新しいカーネルでハングするなどの問題がありつらみしかありません。
CI には drone を導入しています。
まとめ
バンドやろうぜ!
TGludXgg44Gu44Ot44Kw44Kk44Oz44KS44GL44Gj44GT6Imv44GP44GX44KI44GG44Gu5be7Cg==
この記事はPyspa Advent Calendar 2015のエントリとして書かれました。
IyBMaW51eCDjga7jg63jgrDjgqTjg7PjgpLjgYvjgaPjgZPoia/jgY/jgZfjgojjgYbjga7lt7sK CuOBk+OCk+OBq+OBoeOBr++8geWkp+ixqumZoumCquawl+OBp+OBme+8gQoK5LuK5Zue44Gv44Ov 44Kk44Or44OJ44KI44Gt44Gh44KD44KT44Gu6Kmx44KS44GX44KI44GG44Go5oCd44Gj44Gf44Gu 44Gn44GZ44GM44CB5b2T5bGA44GL44KJ5Zyn5Yqb44GM44GL44GL44Gj44Gm44GX44G+44GECuOB iuiUteWFpeOCiuOBq+OBquOBo+OBpuOBl+OBvuOBhOOBvuOBl+OBn+OAggoK6Z2e5bi444Gr5q6L 5b+144Gn44GZ44CCCgrjgZXjgabjgIHjgb/jgarjgZXjgpPjgZTlrZjnn6Xjga7jgojjgYbjgavj g5fjg63jgrDjg6njg57jga/ml6XjgIXjgrXjgqTjgrHjg4fjg6rjg4Pjgq/jgpLpo5/jgaPjgabj govjga7jgafjgZnjgYzjgIHjgZ3jga4K5LqL44Gr44Gk44GE44Gm44Gv6Kqw44KC6Kem44KM44G+ 44Gb44KT44CCCgrjgarjgZzjgafjgZfjgofjgYbjgYvvvJ8KCuKApuOAggoK4oCm44CCCgrlg5Xj goLop6bjgozjgarjgYTjgZPjgajjgavjgZfjgb7jgZnjgILjgILjgIIKClB5U3BhIOmWouOBl+OB puipseOBmeOBqOOBhuOBo+OBi+OCiuOBl+OBn+OBk+OBqOOCkuOBl+OCg+OBueOCiuOBi+OBreOB quOBhOOBl+OAgeS7luOBruOCiOOBreOCgOOCieOBruipseOCkuOBmeOCi+OBqArljbPjgIHntKDo oYzoqr/mn7vljqgg4oaSIOeCjuS4iuOBmeOCi+OBruOBp+OChOOCgeOBpuOBiuOBjeOBvuOBmeOA ggoK44G+44Gf56eB44Gu6Kmx44GX44Gm44GE44Gq44GE6YGO5Y6744Gu6Kmx44Gv44OX44Oz44Kz 44Os5paw5bm05Lya44Gn5qmf5Lya44GM44Ki44Os44Gw6Kmx44GX44G+44GZ44CCCgrjgafjgIHj g43jgr/jgYzjgarjgYTjga7jgafjganjgYbjgZfjgojjgYbjgYvjgajmgJ3jgaPjgabjgYTjgZ/j gokgYGxpZ2h0ZG0td2Via2l0LWdyZWV0ZXJgIOOCkuS9v+OBo+OBpuOBnwrjgZPjgajjgpLmgJ3j gYTlh7rjgZfjgZ/jga7jgafjgZ3jgozjgavjgaTjgYTjgaYgMiDjgJwgMyDmlofmm7jjgY3jgZ/j gYTjgajmgJ3jgYTjgb7jgZnjgIIKCiMjIExpZ2h0RE0KCkxpZ2h0RE0g44Gv44Kv44Ot44K544OH 44K544Kv44OI44OD44OX44Gu44OH44Kj44K544OX44Os44Kk44Oe44ON44O844K444Oj44Gn44GZ 44CCCgrlibLjgajlpJrjgY/jga7jg4fjgqPjgrnjg4jjg6rjg5Pjg6Xjg7zjgrfjg6fjg7Pjgafk vb/jgYjjgb7jgZnjgIIKCui7vemHj+OBp+WfuuacrOeahOOBquapn+iDveOBq+a6luaLoOOBl+OB puOBiuOCiuOAgVVJ6YOo44Go44Ot44K444OD44Kv6YOo44GM5oq96LGh5YyW44GV44KM44Gm44GK 44KK44Kr44K544K/44Oe44Kk44K644GMCuWPr+iDveOBq+OBquOBo+OBpuOBhOOBvuOBmeOAggoK 44Gd44Gu44Gf44KB44CBTGlnaHRETSDjga/jg63jgrDjgqTjg7MoVUkp6YOo44KS44Kr44K544K/ 44Oe44Kk44K644GV44KM44KL44GT44Go44GM5aSa44GP44Gd44Gu6YOo5YiG44GvIGBncmVldGVy YArjgajjgZfjgabjg5Hjg4PjgrHjg7zjgrjjg7PjgrDjgZXjgozjgabjgYTjgb7jgZnjgIIKCu+8 iFVidW50dSDjgafjga8gdW5pdHktZ3JlZXRlciDjgYzkvb/nlKjjgZXjgozjgabjgYTjgb7jgZnv vIkKCiMjIEdyZWV0ZXIKCkdyZWV0ZXIg44GvIGBsaWdodGRtLWd0ay1ncmVldGVyYCwgYGxpZ2h0 ZG0ta2RlLWdyZWV0ZXJgIOOBquOBqeOBhOOCjeOBhOOCjeOBguOCi+OBruOBp+OBmeOBjOOAgQrj gqvjgrnjgr/jg57jgqTjgrrlj6/og73jgajjgYTjgaPjgabjgoLmlbflsYXjgYzpq5jjgZ3jgYbj gavopovjgYjjgb7jgZnjgIIKCuOCguOBo+OBqOewoeWNmOOBq+OCq+OCueOCv+ODnuOCpOOCuuOB p+OBjeOBquOBhOOBp+OBl+OCh+OBhuOBi++8nwoK44CM44Gv44GE77yBU1RBUOe0sOiDnuOBr+OB guOCiuOBvuOBme+8geOAjQoK44Go6KiA44KP44KT44Gw44GL44KK57Ch5Y2Y44Gr44Kr44K544K/ 44Oe44Kk44K644GZ44KL5pa55rOV44GM44GC44KK44G+44GZ44CC44Gd44KM44GvIGBsaWdodGRt LXdlYmtpdC1ncmVldGVyYArjgpLkvb/jgYbmlrnms5XjgafjgZnjgIIKCu+8iOOBiuOBvOOAnO+8 iQoKIyMgV2Via2l0LUdyZWV0ZXIKCmBsaWdodGRtLXdlYmtpdC1ncmVldGVyYCDjga/jgZ3jga7l kI3jga7pgJrjgorjg4bjg7zjg57jgasgYHdlYmtpdGAg44GM5L2/55So44Gn44GN44G+44GZ44CC CgpIVE1MLCBDU1Mg44OG44O844Oe44KS5L2c44KK44CB44Ot44Kw44Kk44Oz44Ot44K444OD44Kv 6YOo44KSIEphdmFzY3JpcHQg44Gn44Gh44KH44Gh44KH44Gj44Go5pu444GR44Gw5a6M5oiQ44Gn 44GZ44CCCgrjgarjgpPjgabjgYrmiYvou73jgarjgpPjgaDvvIHvvIEKCuOBvuOBmuOBryBgbGln aHRkbS13ZWJraXQtZ3JlZXRlcmAg44KS44Kk44Oz44K544OI44O844Or44GX44CB5pyJ5Yq544Gr 44GX44G+44GZ44CCCgpgL2V0Yy9saWdodGRtL2xpZ2h0ZG0uY29uZmAg44Gn6Kit5a6a44Gn44GN 44G+44GZ44CCCgpgYGAKW1NlYXQ6Kl0KLi4uCmdyZWV0ZXItc2Vzc2lvbj1saWdodGRtLXdlYmtp dC1ncmVldGVyCi4uLgpgYGAKCuasoeOBqyBgbGlnaHRkbS13ZWJraXQtZ3JlZXRlcmAg44Gu6Kit 5a6a44KSIGAvZXRjL2xpZ2h0ZG0vbGlnaHRkbS13ZWJraXQtZ3JlZXRlci5jb25mYArjgavmm7jj gY3jgb7jgZnjgIIKCmBgYApbZ3JlZXRlcl0KYmFja2dyb3VuZD0KdGhlbWUtbmFtZT1DbGVhcmxv b2tzCndlYmtpdC10aGVtZT1tYWMKZm9udC1uYW1lPVJpY3R5IDE0CnhmdC1hbnRpYWxpYXM9dHJ1 ZQp4ZnQtZHBpPTk2CnhmdC1oaW50c3R5bGU9c2xpZ2h0CnhmdC1yZ2JhPXJnYgpgYGAKCumHjeim geOBquOBruOBryBgd2Via2l0LXRoZW1lYCDjgafjgZnjgILjgZPjga7jg4bjg7zjg57lkI3jgafl j4LnhafjgZfjgavooYzjgY/jg4fjgqPjg6zjgq/jg4jjg6rjgYzmsbrjgb7jgorjgb7jgZnjgIIK CuWPgueFp+OBmeOCiyBgL3Vzci9zaGFyZS9saWdodGRtLXdlYmtpdC90aGVtZXMvPHdlYmtpdC10 aGVtZT4vYCDjgafjgZnjgIIKCuS4iuiomOioreWumuOBquOCiSBgbWFjYCDjgajjgarjgaPjgabj gYTjgovjga7jgacgYC91c3Ivc2hhcmUvbGlnaHRkbS13ZWJraXQvdGhlbWVzL21hYy9gIOOCkuWP gueFpwrjgZfjgb7jgZnjgIIg44OG44O844Oe44Gv44OH44Kj44Os44Kv44OI44Oq44GU44Go44Gr 5YiG44GR44KJ44KM44KL44Gu44Gn6KSH5pWw44OG44O844Oe44KS44Kk44Oz44K544OI44O844Or 44GX44CB5YiH44KKCuabv+OBiOOCi+OBk+OBqOOBjOOBp+OBjeOBvuOBmeOAggoK5a6f6Zqb44Gr 44Ot44Kw44Kk44Oz5pmC44Gr6Kqt44G/6L6844G+44KM44KL44Gu44Gv44OG44O844Oe5YaFIGBp bmRleC50aGVtZWAg44Gn44GZ44CCCgrku6XkuIvjgavkvovjgpLmm7jjgY3jgb7jgZnjgIIKCmBg YApbdGhlbWVdCm5hbWU9VGVzdCBUaGVtZQpkZXNjcmlwdGlvbj1UZXN0IFdlYmtpdCBUaGVtZQpl bmdpbmU9bGlnaHRkbS13ZWJraXQtZ3JlZXRlcgp1cmw9aW5kZXguaHRtbApzZXNzaW9uPXhtb25h ZApgYGAKCmB1cmxgIOOBjOWun+mam+OBq+iqreOBv+i+vOOBvuOCjOOCi+ODleOCoeOCpOODq+OB q+OBquOCiuOBvuOBmeOAggrkuIroqJjjgafjga9VSeOAgeODreOCuOODg+OCr+OBquOBqeOBryBg aW5kZXguaHRtbGAg44Gr6KiY6L+w44GX44Gm44GE44GN44G+44GZ44CCCgojIyDlrp/ot7UKCuOB p+OBr+Wun+ijheS+i+OCkuimi+OBpuOBv+OBvuOBl+OCh+OBhuOAggoK6Kmz44GX44GP44Gv6Kqs 5piO44GX44G+44Gb44KT44GM44GK44GK44KI44Gd44Gu6Zuw5Zuy5rCX44Gv6Kej44KL44Go5oCd 44GE44G+44GZ44CCCgpgaW5kZXguaHRtbGAKCmBgYGh0bWwKPGh0bWw+CjxoZWFkPgo8bGluayBy ZWw9InN0eWxlc2hlZXQiIHR5cGU9InRleHQvY3NzIiBocmVmPSJzdHlsZS5jc3MiIC8+CjxzY3Jp cHQgdHlwZT0idGV4dC9qYXZhc2NyaXB0IiBzcmM9InNjcmlwdC5qcyI+PC9zY3JpcHQ+CjwvaGVh ZD4KCjxib2R5IG9ubG9hZD0iaW5pdGlhbGl6ZSgpIiBvbmNvbnRleHRtZW51PSJyZXR1cm4gZmFs c2U7Ij4KICA8ZGl2IGNsYXNzPSJoZWFkZXIiPjxzcGFuIGlkPSJjdXJyZW50X3RpbWUiIGNsYXNz PSJ0aW1lIj48L3NwYW4+PC9kaXY+CiAgPGRpdiBjbGFzcz0ibG9naW5fY29udGVudCI+CiAgICA8 ZGl2IGNsYXNzPSJsb2dpbl9jb250YWluZXIiPgogICAgICA8ZGl2IGNsYXNzPSJjZW50ZXIiPgog ICAgICAgIDxkaXYgaWQ9InVzZXJfdGVtcGxhdGUiIGNsYXNzPSJ1c2VyIGhpZGRlbiBzbW9vdGgg YnV0dG9uIj4KICAgICAgICAgIDxkaXYgY2xhc3M9InVzZXJfaW1hZ2Vfd3JhcHBlciI+IDxpbWcg Y2xhc3M9InVzZXJfaW1hZ2UiIHNyYz0iIi8+IDwvZGl2PgogICAgICAgICAgPHNwYW4gY2xhc3M9 InVzZXJfbmFtZSI+PC9zcGFuPgogICAgICAgIDwvZGl2PgogICAgICA8L2Rpdj4KICAgICAgPGRp diBpZD0icGFzc3dvcmRfY29udGFpbmVyIiBjbGFzcz0iY2VudGVyIGhpZGRlbiBzbW9vdGgiPgog ICAgICAgIDxmb3JtIGFjdGlvbj0iamF2YXNjcmlwdDogcHJvdmlkZV9zZWNyZXQoKSIgY2xhc3M9 InBhc3N3b3JkX3Byb21wdCI+CiAgICAgICAgICA8aW5wdXQgaWQ9InBhc3N3b3JkX2VudHJ5IiB0 eXBlPSJwYXNzd29yZCIgcGxhY2Vob2xkZXI9IlBhc3N3b3JkIiAvPgogICAgICAgIDwvZm9ybT4K ICAgICAgPC9kaXY+CiAgICA8L2Rpdj4KICA8L2Rpdj4KICA8ZGl2IGlkPSJtZXNzYWdlIiBjbGFz cz0ic21vb3RoIj4KICAgIDxkaXYgaWQ9Im1lc3NhZ2VfY29udGVudCI+PC9kaXY+CiAgPC9kaXY+ CiAgPGRpdiBjbGFzcz0iZm9vdGVyIj4KICAgICAgPGRpdiBpZD0iYWN0aW9uX3RlbXBsYXRlIiBj bGFzcz0iYWN0aW9uIGJ1dHRvbiI+CiAgICAgICAgPGRpdiBjbGFzcz0iYWN0aW9uX2ltYWdlX3dy YXBwZXIiPjxpbWcgY2xhc3M9ImFjdGlvbl9pbWFnZSIgc3JjPSIiLz48L2Rpdj4KICAgICAgICA8 c3BhbiBjbGFzcz0iYWN0aW9uX2xhYmVsIj48L3NwYW4+CiAgICAgIDwvZGl2PgogIDwvZGl2Pgo8 L2JvZHk+CjwvaHRtbD4KCmBgYAoKYHNjcmlwdC5qc2AKCmBgYGphdmFzY3JpcHQKdmFyIHRpbWVf cmVtYWluaW5nID0gMDsKdmFyIHNlbGVjdGVkX3VzZXIgPSBudWxsOwp2YXIgdmFsaWRfaW1hZ2Ug PSAvLipcLihwbmd8c3ZnfGpwZ3xqcGVnfGJtcCkkL2k7CgovLy8vLy8vLy8vLy8vLy8vLy8vLy8v Ly8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwovLyBDQUxMQkFDSyBBUEkuIENhbGxlZCBieSB0aGUg d2Via2l0IGdyZWVldGVyCi8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8v Ly8vLy8vCgovLyBjYWxsZWQgd2hlbiB0aGUgZ3JlZXRlciBhc2tzIHRvIHNob3cgYSBsb2dpbiBw cm9tcHQgZm9yIGEgdXNlcgpmdW5jdGlvbiBzaG93X3Byb21wdCh0ZXh0KSB7CiAgdmFyIHBhc3N3 b3JkX2NvbnRhaW5lcj0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoInBhc3N3b3JkX2NvbnRhaW5l ciIpOwogIHZhciBwYXNzd29yZF9lbnRyeT0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoInBhc3N3 b3JkX2VudHJ5Iik7CgogIGlmICghaXNWaXNpYmxlKHBhc3N3b3JkX2NvbnRhaW5lcikpIHsKICAg IHZhciB1c2Vycz0gZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCgiLnVzZXIiKTsKICAgIHZhciB1 c2VyX25vZGU9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoIiMiICsgc2VsZWN0ZWRfdXNlcik7CiAg ICB2YXIgcmVjdD0gdXNlcl9ub2RlLmdldENsaWVudFJlY3RzKClbMF07CiAgICB2YXIgcGFyZW50 UmVjdD0gdXNlcl9ub2RlLnBhcmVudEVsZW1lbnQuZ2V0Q2xpZW50UmVjdHMoKVswXTsKICAgIHZh ciBjZW50ZXI9IHBhcmVudFJlY3Qud2lkdGgvMjsKICAgIHZhciBsZWZ0PSBjZW50ZXIgLSByZWN0 LndpZHRoLzIgLSByZWN0LmxlZnQ7CiAgICB2YXIgaSA9IDA7CiAgICBpZiAobGVmdCA8IDUgJiYg bGVmdCA+IC01KSB7CiAgICAgIGxlZnQ9IDA7CiAgICB9CiAgICBmb3IgKGk9IDA7IGkgPCB1c2Vy cy5sZW5ndGg7IGkrKykgewogICAgICB2YXIgbm9kZT0gdXNlcnNbaV07CiAgICAgIHNldFZpc2li bGUobm9kZSwgbm9kZS5pZCA9PSBzZWxlY3RlZF91c2VyKTsKICAgICAgbm9kZS5zdHlsZS5sZWZ0 PSBsZWZ0OwogICAgfQoKICAgIHNldFZpc2libGUocGFzc3dvcmRfY29udGFpbmVyLCB0cnVlKTsK ICAgIHBhc3N3b3JkX2VudHJ5LnBsYWNlaG9sZGVyPSB0ZXh0LnJlcGxhY2UoIjoiLCAiIik7CiAg fQogIHBhc3N3b3JkX2VudHJ5LnZhbHVlPSAiIjsKICBwYXNzd29yZF9lbnRyeS5mb2N1cygpOwp9 CgovLyBjYWxsZWQgd2hlbiB0aGUgZ3JlZXRlciBhc2tzIHRvIHNob3cgYSBtZXNzYWdlCmZ1bmN0 aW9uIHNob3dfbWVzc2FnZSh0ZXh0KSB7CiAgdmFyIG1lc3NhZ2U9IGRvY3VtZW50LnF1ZXJ5U2Vs ZWN0b3IoIiNtZXNzYWdlX2NvbnRlbnQiKTsKICBtZXNzYWdlLmlubmVySFRNTD0gdGV4dDsKICBp ZiAodGV4dCkgewogICAgZG9jdW1lbnQucXVlcnlTZWxlY3RvcigiI21lc3NhZ2UiKS5jbGFzc0xp c3QucmVtb3ZlKCJoaWRkZW4iKTsKICB9IGVsc2UgewogICAgZG9jdW1lbnQucXVlcnlTZWxlY3Rv cigiI21lc3NhZ2UiKS5jbGFzc0xpc3QuYWRkKCJoaWRkZW4iKTsKICB9CiAgbWVzc2FnZS5jbGFz c0xpc3QucmVtb3ZlKCJlcnJvciIpOwp9CgovLyBjYWxsZWQgd2hlbiB0aGUgZ3JlZXRlciBhc2tz IHRvIHNob3cgYW4gZXJyb3IKZnVuY3Rpb24gc2hvd19lcnJvcih0ZXh0KSB7CiAgIHNob3dfbWVz c2FnZSh0ZXh0KTsKICAgdmFyIG1lc3NhZ2U9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCJtZXNz YWdlX2NvbnRlbnQiKTsKICAgbWVzc2FnZS5jbGFzc0xpc3QuYWRkKCJlcnJvciIpOwp9CgovLyBj YWxsZWQgd2hlbiB0aGUgZ3JlZXRlciBpcyBmaW5pc2hlZCB0aGUgYXV0aGVudGljYXRpb24gcmVx dWVzdApmdW5jdGlvbiBhdXRoZW50aWNhdGlvbl9jb21wbGV0ZSgpIHsKICBpZiAobGlnaHRkbS5p c19hdXRoZW50aWNhdGVkKSB7CiAgICBsaWdodGRtLmxvZ2luKGxpZ2h0ZG0uYXV0aGVudGljYXRp b25fdXNlciwgbGlnaHRkbS5kZWZhdWx0X3Nlc3Npb24pOwogIH0gZWxzZSB7CiAgICBzaG93X2Vy cm9yKCJBdXRoZW50aWNhdGlvbiBGYWlsZWQiKTsKICAgIHN0YXJ0X2F1dGhlbnRpY2F0aW9uKHNl bGVjdGVkX3VzZXIpOwogIH0KfQoKLy8gY2FsbGVkIHdoZW4gdGhlIGdyZWV0ZXIgd2FudHMgdXMg dG8gcGVyZm9ybSBhIHRpbWVkIGxvZ2luCmZ1bmN0aW9uIHRpbWVkX2xvZ2luKHVzZXIpIHsKICAg bGlnaHRkbS5sb2dpbiAobGlnaHRkbS50aW1lZF9sb2dpbl91c2VyKTsKICAgLy8gc2V0VGltZW91 dCgndGhyb2JiZXIoKScsIDEwMDApOwp9CgovLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8K Ly8gSW1wbGVtZW50YXRpb24KLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCmZ1bmN0aW9u IHN0YXJ0X2F1dGhlbnRpY2F0aW9uKHVzZXJuYW1lKSB7CiAgIGxpZ2h0ZG0uY2FuY2VsX3RpbWVk X2xvZ2luKCk7CiAgIHNlbGVjdGVkX3VzZXI9IHVzZXJuYW1lOwogICBsaWdodGRtLnN0YXJ0X2F1 dGhlbnRpY2F0aW9uKHVzZXJuYW1lKTsKfQoKZnVuY3Rpb24gcHJvdmlkZV9zZWNyZXQoKSB7CiAg IHNob3dfbWVzc2FnZSgiTG9nZ2luZyBpbi4uLiIpOwogICB2YXIgZW50cnkgPSBkb2N1bWVudC5x dWVyeVNlbGVjdG9yKCcjcGFzc3dvcmRfZW50cnknKTsKICAgbGlnaHRkbS5wcm92aWRlX3NlY3Jl dChlbnRyeS52YWx1ZSk7Cn0KCmZ1bmN0aW9uIHNob3dfdXNlcnMoKSB7CiAgdmFyIHVzZXJzID0g ZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCgiLnVzZXIiKTsKICBmb3IgKHZhciBpPSAwOyBpIDwg dXNlcnMubGVuZ3RoOyBpKyspIHsKICAgIHNldFZpc2libGUodXNlcnNbaV0sIHRydWUpOwogICAg dXNlcnNbaV0uc3R5bGUubGVmdD0gMDsKICB9CiAgc2V0VmlzaWJsZShkb2N1bWVudC5xdWVyeVNl bGVjdG9yKCIjcGFzc3dvcmRfY29udGFpbmVyIiksIGZhbHNlKTsKICBzZWxlY3RlZF91c2VyPSBu dWxsOwp9CgpmdW5jdGlvbiB1c2VyX2NsaWNrZWQoZXZlbnQpIHsKICBpZiAoc2VsZWN0ZWRfdXNl ciAhPSBudWxsKSB7CiAgICBzZWxlY3RlZF91c2VyPSBudWxsOwogICAgbGlnaHRkbS5jYW5jZWxf YXV0aGVudGljYXRpb24oKTsKICAgIHNob3dfdXNlcnMoKTsKICB9IGVsc2UgewogICAgc2VsZWN0 ZWRfdXNlcj0gZXZlbnQuY3VycmVudFRhcmdldC5pZDsKICAgIHN0YXJ0X2F1dGhlbnRpY2F0aW9u KGV2ZW50LmN1cnJlbnRUYXJnZXQuaWQpOwogIH0KICBzaG93X21lc3NhZ2UoIiIpOwogIGV2ZW50 LnN0b3BQcm9wYWdhdGlvbigpOwogIHJldHVybiBmYWxzZTsKfQoKZnVuY3Rpb24gc2V0VmlzaWJs ZShlbGVtZW50LCB2aXNpYmxlKSB7CiAgaWYgKHZpc2libGUpIHsKICAgIGVsZW1lbnQuY2xhc3NM aXN0LnJlbW92ZSgiaGlkZGVuIik7CiAgfSBlbHNlIHsKICAgIGVsZW1lbnQuY2xhc3NMaXN0LmFk ZCgiaGlkZGVuIik7CiAgfQp9CgpmdW5jdGlvbiBpc1Zpc2libGUoZWxlbWVudCkgewogIHJldHVy biAhZWxlbWVudC5jbGFzc0xpc3QuY29udGFpbnMoImhpZGRlbiIpOwp9CgpmdW5jdGlvbiB1cGRh dGVfdGltZSgpIHsKICB2YXIgdGltZT0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoImN1cnJlbnRf dGltZSIpOwogIHZhciBkYXRlPSBuZXcgRGF0ZSgpOwoKICB2YXIgaGggPSBkYXRlLmdldEhvdXJz KCk7CiAgdmFyIG1tID0gZGF0ZS5nZXRNaW51dGVzKCk7CiAgdmFyIHNzID0gZGF0ZS5nZXRTZWNv bmRzKCk7CiAgdmFyIHN1ZmZpeD0gIkFNIjsKICBpZiAoaGggPiAxMikgewogICAgaGg9IGhoIC0g MTI7CiAgICBzdWZmaXg9ICJQTSI7CiAgfQogIGlmIChoaCA8IDEwKSB7aGggPSAiMCIraGg7fQog IGlmIChtbSA8IDEwKSB7bW0gPSAiMCIrbW07fQogIGlmIChzcyA8IDEwKSB7c3MgPSAiMCIrc3M7 fQogIHRpbWUuaW5uZXJIVE1MPSBoaCsiOiIrbW0gKyAiICIgKyBzdWZmaXg7Cn0KCi8vLy8vLy8v Ly8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KLy8gSW5pdGlhbGl6YXRpb24KLy8vLy8vLy8vLy8v Ly8vLy8vLy8vLy8vLy8vLy8vLy8vLwoKZnVuY3Rpb24gaW5pdGlhbGl6ZSgpIHsKICBzaG93X21l c3NhZ2UoIiIpOwogIGluaXRpYWxpemVfdXNlcnMoKTsKICBpbml0aWFsaXplX2FjdGlvbnMoKTsK ICBpbml0aWFsaXplX3RpbWVyKCk7Cn0KCmZ1bmN0aW9uIGluaXRpYWxpemVfdXNlcnMoKSB7CiAg dmFyIHRlbXBsYXRlID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcigiI3VzZXJfdGVtcGxhdGUiKTsK ICB2YXIgcGFyZW50ID0gdGVtcGxhdGUucGFyZW50RWxlbWVudDsKICBwYXJlbnQucmVtb3ZlQ2hp bGQodGVtcGxhdGUpOwoKICBmb3IgKHZhciBpID0gMDsgaSA8IGxpZ2h0ZG0udXNlcnMubGVuZ3Ro OyBpKyspIHsKICAgIHZhciB1c2VyPSBsaWdodGRtLnVzZXJzW2ldOwogICAgdmFyIHVzZXJOb2Rl PSB0ZW1wbGF0ZS5jbG9uZU5vZGUodHJ1ZSk7CgogICAgdmFyIGltYWdlID0gdXNlck5vZGUuZ2V0 RWxlbWVudHNCeUNsYXNzTmFtZSgidXNlcl9pbWFnZSIpWzBdOwogICAgdmFyIG5hbWUgPSB1c2Vy Tm9kZS5nZXRFbGVtZW50c0J5Q2xhc3NOYW1lKCJ1c2VyX25hbWUiKVswXTsKICAgIG5hbWUuaW5u ZXJIVE1MPSB1c2VyLmRpc3BsYXlfbmFtZTsKCiAgICBpZiAodXNlci5pbWFnZSkgewogICAgICBp bWFnZS5zcmMgPSB1c2VyLmltYWdlOwogICAgICBpbWFnZS5vbmVycm9yPSBmdW5jdGlvbihlKSB7 CiAgICAgICAgZS5jdXJyZW50VGFyZ2V0LnNyYz0gImltZy9hdmF0YXIuc3ZnIjsKICAgICAgfTsK ICAgIH0gZWxzZSB7CiAgICAgIGltYWdlLnNyYyA9ICJpbWcvYXZhdGFyLnN2ZyI7CiAgICB9Cgog ICAgdXNlck5vZGUuaWQ9IHVzZXIubmFtZTsKICAgIHVzZXJOb2RlLm9uY2xpY2s9IHVzZXJfY2xp Y2tlZDsKICAgIHBhcmVudC5hcHBlbmRDaGlsZCh1c2VyTm9kZSk7CiAgfQogIHNldFRpbWVvdXQo c2hvd191c2VycywgNDAwKTsKfQoKZnVuY3Rpb24gaW5pdGlhbGl6ZV9hY3Rpb25zKCkgewogIHZh ciB0ZW1wbGF0ZSA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoIiNhY3Rpb25fdGVtcGxhdGUiKTsK ICB2YXIgcGFyZW50ID0gdGVtcGxhdGUucGFyZW50RWxlbWVudDsKICBwYXJlbnQucmVtb3ZlQ2hp bGQodGVtcGxhdGUpOwoKICBpZiAobGlnaHRkbS5jYW5fc3VzcGVuZCkgewogICAgYWRkX2FjdGlv bigic2xlZXAiLCJTbGVlcCIsICJpbWcvc2xlZXAuc3ZnIiwgZnVuY3Rpb24oZSkge2xpZ2h0ZG0u c3VzcGVuZCgpOyBlLnN0b3BQcm9wYWdhdGlvbigpO30sIHRlbXBsYXRlLCBwYXJlbnQpOwogIH0K ICBpZiAobGlnaHRkbS5jYW5fcmVzdGFydCkgewogICAgYWRkX2FjdGlvbigicmVzdGFydCIsICJS ZXN0YXJ0IiwgImltZy9yZXN0YXJ0LnN2ZyIsIGZ1bmN0aW9uKGUpIHtsaWdodGRtLnJlc3RhcnQo KTsgZS5zdG9wUHJvcGFnYXRpb24oKTt9LCB0ZW1wbGF0ZSwgcGFyZW50KTsKICB9CiAgaWYgKGxp Z2h0ZG0uY2FuX3NodXRkb3duKSB7CiAgICBhZGRfYWN0aW9uKCJzaHV0ZG93biIsICJTaHV0ZG93 biIsICJpbWcvc2h1dGRvd24uc3ZnIiwgZnVuY3Rpb24oZSkge2xpZ2h0ZG0uc2h1dGRvd24oKTsg ZS5zdG9wUHJvcGFnYXRpb24oKTt9LCB0ZW1wbGF0ZSwgcGFyZW50KTsKICB9Cn0KCmZ1bmN0aW9u IGluaXRpYWxpemVfdGltZXIoKSB7CiAgdXBkYXRlX3RpbWUoKTsKICBzZXRJbnRlcnZhbCh1cGRh dGVfdGltZSwgMTAwMCk7Cn0KCmZ1bmN0aW9uIGFkZF9hY3Rpb24oaWQsIG5hbWUsIGltYWdlLCBj bGlja2hhbmRsZXIsIHRlbXBsYXRlLCBwYXJlbnQpIHsKICB2YXIgYWN0aW9uX25vZGUgPSB0ZW1w bGF0ZS5jbG9uZU5vZGUodHJ1ZSk7CiAgYWN0aW9uX25vZGUuaWQ9ICJhY3Rpb25fIiArIGlkOwog IHZhciBpbWdfbm9kZSA9IGFjdGlvbl9ub2RlLnF1ZXJ5U2VsZWN0b3JBbGwoIi5hY3Rpb25faW1h Z2UiKVswXTsKICB2YXIgbGFiZWxfbm9kZT0gYWN0aW9uX25vZGUucXVlcnlTZWxlY3RvckFsbCgi LmFjdGlvbl9sYWJlbCIpWzBdOwogIGxhYmVsX25vZGUuaW5uZXJIVE1MPSBuYW1lOwogIGltZ19u b2RlLnNyYz0gaW1hZ2U7CiAgYWN0aW9uX25vZGUub25jbGljaz0gY2xpY2toYW5kbGVyOwogIHBh cmVudC5hcHBlbmRDaGlsZChhY3Rpb25fbm9kZSk7Cn0KYGBgCgpgc3R5bGUuY3NzYAoKYGBgY3Nz CmJvZHkgewogICAgYmFja2dyb3VuZC1pbWFnZTogdXJsKCdiZy5qcGcnKTsKICAgIGRpc3BsYXk6 IHRhYmxlOwogICAgaGVpZ2h0OiAxMDAlOwogICAgd2lkdGg6IDEwMCU7CiAgICBtYXJnaW46IDA7 CgogICAgZm9udC1zaXplOiAxNHB0OwogICAgdGV4dC1zaGFkb3c6IDFweCAxcHggM3B4IGJsYWNr OwogICAgLXdlYmtpdC11c2VyLXNlbGVjdDogbm9uZTsKfQoKaW5wdXQgewogIGJvcmRlcjogMXB4 IHNvbGlkIHdoaXRlOwogIGJvcmRlci1yYWRpdXM6IDRweDsKICBwYWRkaW5nOiA0cHg7CiAgYm94 LXNoYWRvdzogMCAwIDJweCAxcHggd2hpdGU7CgogIC13ZWJraXQtdHJhbnNpdGlvbjogYm94LXNo YWRvdyAwLjNzIGVhc2UtaW4tb3V0Owp9CgppbnB1dDpmb2N1cyB7CiAgb3V0bGluZTogbm9uZTsK ICBib3gtc2hhZG93OiAwIDAgNXB4IDJweCAjN0RCRUYxOwp9CgphIHsKICB0ZXh0LWRlY29yYXRp b246IG5vbmU7Cn0KCi5zbW9vdGggewogIC13ZWJraXQtdHJhbnNpdGlvbjogdmlzaWJpbGl0eSAw cywgb3BhY2l0eSAwLjNzLCBsZWZ0IDAuNHM7Cn0KCi5oaWRkZW4gewogIG9wYWNpdHk6IDA7CiAg dmlzaWJpbGl0eTogaGlkZGVuOwogIC13ZWJraXQtdHJhbnNpdGlvbi1kZWxheTogMC4zcywgMHMs IDBzOwp9CgouY2VudGVyIHsKICB0ZXh0LWFsaWduOiBjZW50ZXI7Cn0KCi5idXR0b24gewogIGN1 cnNvcjogcG9pbnRlcjsKfQoKLmhlYWRlciB7CiAgaGVpZ2h0OiAzMCU7Cn0KCi5mb290ZXIgewog IHRleHQtYWxpZ246IGNlbnRlcjsKICBoZWlnaHQ6IDEwMHB4Owp9CgouZm9vdGVyLCAuaGVhZGVy IHsKICBkaXNwbGF5OiB0YWJsZS1yb3c7CiAgd2lkdGg6IDEwMCU7CiAgY29sb3I6ICNCMkIyQjI7 Cn0KCi50aW1lIHsKICBmbG9hdDogcmlnaHQ7CiAgbGluZS1oZWlnaHQ6IDI1cHg7CiAgZm9udC1z aXplOiAxMXB0OwogIG1hcmdpbi1yaWdodDogMTBweDsKICBtYXJnaW4tdG9wOiAycHg7Cn0KCi5s b2dpbl9jb250ZW50IHsKICBkaXNwbGF5OiB0YWJsZS1yb3c7Cn0KCi5sb2dpbl9jb250YWluZXIg ewogIGRpc3BsYXk6IHRhYmxlLWNlbGw7CiAgdmVydGljYWwtYWxpZ246IG1pZGRsZTsKfQoKI21l c3NhZ2UgewogIGRpc3BsYXk6IHRhYmxlLXJvdzsKICBoZWlnaHQ6IDEyMHB4OwogIC13ZWJraXQt dHJhbnNpdGlvbjogdmlzaWJpbGl0eSAwcywgb3BhY2l0eSAwLjNzLCBoZWlnaHQgMC4zczsKfQoK I21lc3NhZ2UuaGlkZGVuIHsKICBoZWlnaHQ6IDBweDsKfQoKI21lc3NhZ2VfY29udGVudCB7CiAg ZGlzcGxheTogdGFibGUtY2VsbDsKICB2ZXJ0aWNhbC1hbGlnbjogdG9wOwogIHRleHQtYWxpZ246 IGNlbnRlcjsKICBjb2xvcjogI0VGRUZFRjsKfQoKI21lc3NhZ2VfY29udGVudC5lcnJvciB7CiAg Y29sb3I6ICNGNTU7Cn0KCi51c2VyIHsKICBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7CiAgbWFyZ2lu LWxlZnQ6IDIwcHg7CiAgbWFyZ2luLXJpZ2h0OiAyMHB4OwogIG1hcmdpbi1ib3R0b206IDIwcHg7 CiAgcG9zaXRpb246IHJlbGF0aXZlOwp9CgoudXNlcjphY3RpdmUgewogIG9wYWNpdHk6IDAuNTsK fQoKLnVzZXJfaW1hZ2Vfd3JhcHBlciB7CiAgd2lkdGg6IDgwcHg7CiAgaGVpZ2h0OiA4MHB4OwoK ICBib3JkZXItcmFkaXVzOiA2MHB4OwogIGJveC1zaGFkb3c6IDAgMCAxcHggMXB4ICMyMjIsIGlu c2V0IDAgMCAycHggMXB4ICMyMjI7CiAgYm9yZGVyOiAycHggc29saWQgI0VFRTsKICBiYWNrZ3Jv dW5kOiAtd2Via2l0LXJhZGlhbC1ncmFkaWVudChjaXJjbGUsICNGRkYsICM5OTkpOwp9CgoudXNl cl9pbWFnZV93cmFwcGVyOmhvdmVyIHsKICBib3gtc2hhZG93OiAgMCAwIDFweCAxcHggIzIyMiwg aW5zZXQgMCAwIDJweCAxcHggIzIyMiwgMCAwIDVweCAycHggIzdEQkVGMTsKfQoKLnVzZXJfaW1h Z2UgewogIHdpZHRoOiA4MHB4OwogIGhlaWdodDogODBweDsKICBib3JkZXItcmFkaXVzOiA2MHB4 Owp9CgoudXNlcl9uYW1lIHsKICBkaXNwbGF5OiBibG9jazsKICBtYXJnaW4tdG9wOiAxNXB4Owog IGNvbG9yOiAjRUZFRkVGOwp9CgouYWN0aW9uIHsKICBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7CiAg d2lkdGg6IDgwcHg7CiAgbWFyZ2luLWxlZnQ6IDQwcHg7CiAgbWFyZ2luLXJpZ2h0OiA0MHB4Owp9 CgouYWN0aW9uX2ltYWdlIHsKICBoZWlnaHQ6IDUwcHg7CiAgd2lkdGg6IDUwcHg7CgogIG1hcmdp bi1ib3R0b206IDVweDsKfQoKLmFjdGlvbl9sYWJlbCB7CiAgY29sb3I6ICNCMkIyQjI7Cn0KYGBg Cg==
株式会社Abby 社員募集のお知らせ
株式会社Abby 社員募集のお知らせ
ジュリアナー!!トーキョー!
こんにちわ、ジョン・ロビンソンこと半ズボンの宇宙人です。
株式会社Abbyでは業務拡大に伴い、共に働いてくれる仲間を募集しています。
以前事務所は恵比寿にあったのですが、クックパッドがくるということで逃げるように中目黒に事務所を移転しました。
事務所などは会社のサイトを参照して下さい。
今まではシステム開発メインでやっていましたが、現在はアプリの開発にシフトしています。
http://www.abby.co.jp/service.html
社内には優秀なメンバーも揃っています。いろいろな技術的な話もできるので技術者にとっては刺激の多い環境だと思います。
- @yone098
- @shinsan68k
- @__garsue__
- 先日入社した@matcha014こと通称チャランボ
社内は明るく@yone098 が最新ギャグを教えてくれたりします。お笑い好きにもたまらない現場になっています。
@yone098 のギャグの例(あくまで一例です):
- 「ようかーいにんげーん!しーっとるけー!ヒャーッホホッ!!」
- 「ジュンスでーす!」「ユチョンでーす!」「三波春夫でございます!」(バシッ!)
- 「こん平でーす!!!」(コンパイルが通る度絶叫するギャグ)
最近では@__garsue__の一発ギャグ「聞いてるよー!」(聞いてないよの口調で)も流行っています。
募集要項
弊社では現在、東京本社でプログラマを募集しています。
仕事内容はモバイルアプリ開発がメインになります。
詳細は他の人も書いているのでそちらを参照して下さい。
AbbyでJava技術者募集(急募) - しんさんの出張所 はてな編
上記でも書いてあるとおりiOS向けアプリも全てJavaで開発しているのでメインはJavaでの開発になります。
そのためJavaでの開発経験がある方を募集しています。
Javaという点では@shinsan68kがエグいほどのエキスパートで彼ほどJavaを書ける人を私は見たことがありません。そのためJavaプログラマであれば彼に学ぶことをすごく多いと思います。
Javaの経験が無くても、他のプログラミング言語で得意なものがある人も一度遊びにきてみてください。
OS、開発環境などは個人の好きなように構築しています。NetBeansを使う人も入れば私のようにArch Linux + Emacsを使っている人もいます。
私個人としてはスキルも大事ですが、積極性や今後ののびしろがある方を優先に採用したいと思っています。
この業界は多岐に渡り様々な知識が必要です。現状出来なくても当たり前の事は多いので現状のスキルとよりも向上心があり、伸びてくれる人材を探しています。
(もちろん一緒に働く現メンバーは上記に当てはまる素晴らしいメンバーですよ:))
興味がある方は一度会社に遊びに来て下さい。
一緒に働きたい方は、info@abby.co.jp までメールを下さい。
もしくはTwitterやFacebookで@mopemope宛まで連絡してください。
皆様からの応募お待ちしております。
なお、東方神起のメンバーは募集していませんのでご了承ください。