TECH PLAY

株式会社LIFULL

株式会社LIFULL の技術ブログ

660

こんにちは、上津原です。 Couchbase [Tokyo] 2014、 Couchbase Liteの日本発公式発表があるので行ってきました。 会場はほぼ満員でした。年に一度しか無いイベントですしね。 Couchbase Server側の話は置いといて、自分の土俵のCouchbase Lite側に絞ってレポートします。 プレゼンテーション Couchbase Liteのプレゼンテーションは、ジェシカさんという女性の方が行いました。 ざっくりとCouchbase Liteとはどういうもので、どんなふうに動くのか、ということを話していて、要約すると以下の様な感じでした。 CouchbaseLiteは世界初のモバイル向けNoSQL ローカルデータをCouchbase Sync Gatewayを経由してSyncする Couchbase Sync Gatewayは、Channelを使って、閲覧可能な情報を制限することができる Channelは、ドキュメントにつけるタグのようなもの FacebookやPersonaを使って認証できるよ Syncもとっても簡単でお手軽に出来るよ パージして、モバイルローカル上のデータだけ消すこともできるよ そしてTodoLite( https://github.com/couchbaselabs/TodoLite-iOS )のデモ TodoのiOSアプリケーションで、CouchbaseLiteでデータ管理をしている。 Facebook認証も入っていて、任意のユーザとTodoを共有できるもの。 あれ、この前まで動いてなかったのに動いてる…。 聞いてみたら、最近動くようになったとのこと。これは僕も動かしてみなければ。 ジェシカさんに僕が個人的に聞いたこと Q: CouchbaseLiteは、モバイルアプリ技術者が単独で使うために作ってる?それともサーバ側の人も一緒に使う用に作ってる? A: CouchbaseLiteのSyncは、モバイル技術者が一人で開発するものではなく、サーバーサイド技術者とコラボレートして利用することを想定してるよ。 Q: CouchbaseServerを理解せずに触って、ViewとかQueryの考え方がよくわからない事が多かったんだけど、モバイル技術者のために、ViewとかQueryのチュートリアルとか無いの? A: ドキュメントがちょっとずつ充実してきてるから見てね。 ViewやQueryの使い方はCouchbaseServerとほぼ同じだからそっちの資料を参考に学ぶといいよ。 動いているものは、さっきのTodoLiteがgithubにあるからコードリーディングして学んでね。 Q: TodoLite以外サンプルアプリ動かそうとしたら動かないんだけど… A: CouchChatとかはもう全然触られてないから、あれは動かないよ。開発者も飽きちゃったみたい。 TodoLiteしか動かないと思う。ごめんね。 最後にジェシカさんから: わからないことはコミュニティかメールでで聞いてくれれば答えるよ。 あなたの問題はみんなの問題だし、わかりにくいのは良くないからね。 バグとかみつけても教えてね 。 一緒に出席してたCouchbaseServer技術者の友達にCouchbaseLiteについてどう思うか聞いた 「ものは面白いけど、SyncGatewayがセキュアなのかどうかが気になる。  SyncGatewayとCouchbaseの間になにかミドルウェアを挟んで対処する必要があるかもなあ。  ゲームだとそこをついてチートするユーザとかがいるからそこの対処ができないとしんどい。」 まとめ Couchbase Liteは使いやすいし、導入も簡単だけど、SyncするためにCouchbaseServerを導入するかどうかがやっぱり気になるところ。(もちろん、実装すればCouchbaseを使わなくてもSyncできるよ!) beta2ということもあって、まだまだ発展途上なCouchbaseLiteだけど、認証なども加わり、ネットワークと連携する強力なモバイルデータベースとなる可能性は十分秘めていると思います。 CouchbaseServerの需要が高まるに連れて、CouchbaseLiteの需要も一緒に上がっていくのかな〜というイメージです。 そしてCouchbase [Tokyo] 2014は、Couchbaseの開発者やセールスの皆さんと話ができるチャンスです。 そして英語ができない僕でも、3次会のカラオケでCHA-LA HEAD-CHA-LAをみんなで歌えちゃうくらいのフレンドリーさがあります。 次のCouchbase [Tokyo]は来年になっちゃうけど、ミートアップもちょいちょいやったりしているので、ちょっと興味があるくらいでもうれしいので参加者が増えていくといいな〜と思います。 あんまりみんな知らない、新しい、面白い技術って、わくわくするでしょ?
今回は、ここまで作ってきたデータをCouchDBと同期してみたいと思います。 この同期機能もCouchbase Liteの大きな特徴です。 Push、Pullどちらも機能を兼ね備えておりかつ、実装が簡単なのが特徴です。 普段にありがちなAPI問い合わせのメソッドなども書く必要は一切ありません。 同期対象は、CouchDB、またはCouchbase(CouchbaseはSyncGatewayが必要)となっています。 今回は、CouchDBとのSyncの方が簡単なのでそちらを見て行きましょう。 まず同期対象となるCouchDBを用意しなくてはいけません。 まずは以下に登録してください。 Cloudantに登録 Cloudant https://cloudant.com/ 値段は、使用料が毎月5ドル以下なら無料となっており、ちょっと触ってみる程度なら課金されません。 登録完了し、サインインすると、ダッシュボードが表示されます。 上部にある、New databaseに作りたいデータベース名を入力し、Createでデータベースを作成します。 これができれば準備完了です。 Replicationしよう! レプリケーション先の準備ができれば、あとはコードを書くだけです。 gist8331915 URL部分は、各自以下のとおり変更を行ってください。 yourId:先ほど登録したID password:先ほど登録したパスワード dbName:先ほど作成したデータベース名 設定できたら、viewDidLoadでこのメソッドを呼出し、Runしてみてください。 これだけで同期はできているはずです。 Cloudantの「Your database」にある、先ほど作成したdatabaseを選択し、ドキュメント情報を見てみましょう。 CouchbaseLiteで作成したドキュメントがそっくりそのまま同期されているはずです。 補足 実は、同期するだけなら、 NSArray *repls = [ap.database replicateWithURL:[NSURL URLWithString:@"https://yourId:password@yourId.cloudant.com/dbName"] exclusively:YES];<br> この項目だけで出来ます。 下に続いているpullとpushは、こちらが任意のタイミングでPull(GET)やPush(Post)を行うために必要になります。 任意のタイミングで同期する これも非常に簡単です。 先ほど作成した、pull、pushに対してメッセージをひとつ送るだけです。 [ pull start] [ push start] これだけで同期を開始します。 進捗を追う 進捗を追うには、最初に設定したobserverを追います。 公式では、completeを追っていましたが、時々completeしないことがあるので、modeを追っています gist8331912 CBLReplicationMode には4つのモードが有り、 kCBLReplicationStopped, / *< The replication is finished or hit a fatal error. / kCBLReplicationOffline, / *< The remote host is currently unreachable. / kCBLReplicationIdle, / *< Continuous replication is caught up and waiting for more changes. / kCBLReplicationActive / *< The replication is actively transferring data. / が存在します。 kCBLReplicationStopped になると、レプリケーション完了、もしくはエラーのモードなので、そこを終了点として持ちます。 このコードでは、同期が完了したらDBを読み直す処理をしています。 ざっくりですが、このような感じでCouchbase LiteとCouchDBを同期することができます。
サムです。 2014/1/15ついに "Google Analytics SDK for iOS" が version 3.0.3 で 64bit 対応版のSDKが公開されました。 変更ログ Google Developers にある 変更ログ には次のように記されていました。 This release contains: ・Added support for 64-bit iOS 7.0 SDK. ・Removed libGoogleAnalytics_debug.a, it’s part of the libGoogleAnalyticsServices.a library. ・Cleaned up CuteAnimals build file for Google Analytics. ・64-bit対応しました。 ・libGoogleAnalytics_debug.a を削除し、libGoogleAnalyticsServices.a に統合した。 ・Google Analytics Services SDK 内にある Exsample Code: CuteAnimals/ をクリーンアップした。 SDKの入手について SDKのダウンロードは Google Developers からできます。 また、Google Analytics は CocoaPods にも対応しており、Podfileに次のライブラリを追加すればOKです pod 'GoogleAnalytics-iOS-SDK', '3.0.3' ビルドしているアーキテクチャの確認 Xcode BuildSettings > Architectures > Architectures を確認する。 Standard architectures (including 64 bit) (armv7, armv7s, arm64) なら64-bitビルド Standard arcitectures (armv7, armv7s) なら32-bitビルドです。 さいごに これまで多くのDeveloperが64-bit対応を見送っておりましたが、やっとこさGoogleも対応してきましたね、これは素直に喜べます。
上津原です。 今回は、Couchbase Liteの機能のひとつである、LiveQuery機能を見ていきたいと思います。 LiveQueryとは、指定したクエリ結果に影響するデータ変更があった場合、自動で通知を出してくれる機能です。 例えば、すべてのドキュメントを呼び出していた時ならば、何かしらデータベースに変更(ドキュメントの追加、削除、更新)が行われた場合に通知が上がってくる、というものです。 これを利用することによって、 変更があった時にすぐに表示に反映する 変更があったらすぐに同期を行う などの対応などが可能になります。 コードはとってもシンプルです。 以下のようになります。 gist8143715 以上です。 KeyPathが「row」じゃなくて「rows」なのでそこに注意が必要です。 通知が取れれば、ここでpushするなり、表示を更新するなりやればリアルタイム反映が可能になります。 これで、データが編集されればそれに対して即時対応や、UIの更新などを行うことが出来、非常に便利です。 欲しい機能が予めこうやって用意されているのはうれしいですね。
Apple原理主義者の大坪です。 PinterestのiOSアプリが3.0にバージョンアップするにあたり、どのような検討がなされたかがPinterest Engineering Blog Making Pinterest — Behind the Pins: Building Pinterest 3.0 for iOS に公開されています。 iOS7公開後にどのような「バージョンアップ」を行ったかがわかり興味深いので、内容について紹介しつつあれこれ書ければと。 - Ver3.0を作るにあたって大きなポイントは以下の3点だったとのこと。 UICollectionViewの採用とiOS5のサポート停止 iOS7の新機能、View間Transitionの採用 ジェスチャの見直し まず一点目。私もUICollectionViewの概要を知った時には驚きましたが、その機能を使う為にはiOS5以前のサポートを諦めなくてはならない。これをどこで行うかは各社悩ましいところだと思います。 私の理解では2点目と3点目は関連しています。PinterestのiOSアプリには、複数の写真情報を提示している一覧画面と、その中の写真をタップした時に表示される詳細画面が存在している。 アプリの使用状況を調査したところ、多くのユーザが詳細画面を長い時間使っており、かつ別の詳細情報を観る時に、「戻る」ボタンで一覧に戻り、次の詳細情報を観る、という行動をしていることがわかったとのこと。 そのため 詳細画面から左右にスワイプして前後の詳細情報を閲覧できるようにした 一覧画面から詳細画面に遷移する際、そうした「左右へのスワイプ」が可能なことを示すため、一覧中の一つの写真が拡大して、詳細画面になるような遷移(iOS7から可能になった機能です)を採用した とのこと。このように彼らはインタラクションフローの見直しと合わせてiOS7の新機能をとりいれ、結果としてユーザがより便利かつ直感的に使えるようにアプリを改善したのでしょう。 この「一覧画面」「詳細画面」の関連付けについては悩むことが多いです。作る側としては、きっぱり分けてその間を遷移させればよい、ということになるのですが、Pinsterestの解析結果に現れているように必ずしもそれはユーザの直感に合致しているわけではない。二つの異なる情報レベルをもった画面を登ったり降りたりするのではなく、直接同じレベル(例えば詳細画面)にある別の情報に移動できた方がうれしい。その点で、今回Pinterestが用いた方法は参考になる点が多いのではないでしょうか。 - 最後に一点。「iOS7以降では動きのデザインがより重要になる」という主張をしている身としては、彼らが挙げている「改善点」の2、3点目がいずれも「動き」に関するものであることに興味を惹かれます。全体の操作フローを見る立場と、画面遷移の動きをコードで実現する立場双方が協力してできあがった新しいインタラクションではないかな、と想像するわけですが。
今まで、NSDictionaryを使ってドキュメントをCRUDをしてきましたが、実はモデルを使ったほうが俄然使いやすいです! なので、今回はCBLModelというクラスを利用していきます。 これを使うことにより、面倒だったNSDictionaryの作成などがなくなります。 以下のように宣言します。 CBLModel ひとつのドキュメントに格納したいデータを、上記のようにプロパティ宣言をし、.mで@dynamic宣言をすればそれだけでおしまいです。 とっても簡単です。 ドキュメント作成 CBLModelでCreate ドキュメント読み込み CBLModelでRead ドキュメント更新 CBLModelでUpdate ドキュメント削除 CBLModelでDelete いかがでしょう。Modelを使うことで、今まであったDictionaryの操作がなくなり、プロパティへ直接アクセスすることで操作が可能になります。 ドキュメント操作時に出てきていたCBLDocumentも読み込み時にしか出てきません。 作成、更新はputではなく、saveを使うように変わり、意味的にもちょっとわかりやすくなります。 モデル化のメリット プロパティによる値の明確化 作成、更新が容易になる NSDate,NSDataなどの利用が容易になる いちいちこのドキュメントには何が入ってて…とかログで確認したくもないですし、NSDictioary直で触るの嫌だから、このために新たに自作モデルクラスを…なんて事になってしまってはものすごい手間です。 そして、NSDateやNSDataを内部で補完する機能を持っているので、何も考えずにプロパティ宣言をして値を渡してしまえば簡単に保存してくれます。ちなみに、NSDataはbase64に勝手に変換してくれます。 おそらくモデルを利用することがCouchbase Liteの基本となるかな、と。
Apple原理主義者であることを公言している大坪と申します。 少し昔話をしましょう。今から7年前、2007年1月9日の早朝、私は寝ぼけ眼でAppleのサイトを開きました。この日はMacWorldの初日。数時間前にSteve Jobsがキーノートスピーチを行ったはず。そしてそこでは新しい携帯電話が発表されると噂されていたからです。 Appleのサイトをあれこれクリックするうち動画があることに気が付きます。それを見た瞬間眠気はどこかに吹き飛びました。なんだこれは。動揺しつつも自分に言い聞かせます。 「いや、これはデモに違いない。実機でこんなするする動くわけがない」 そう思いながらキーノートスピーチの動画を見続ける。信じ難いことですが、Appleのサイトに載っていた「動き」がそのまま実機で-小さい携帯電話上で-動いている。( 動画 ) 観ているうち、頭の中に一つの考えがぐるぐる回りだしました。 「これは ドレッドノート だ」 そう考えたのは私だけではないようです。Androidの父、Andy Rubinはその時Las Vegasで会議のため移動中でした。しかしJobsが発表したものを知ると、車を止めさせwebcastに見入ったといいます。そして言った言葉が “Holy crap,” he said to one of his colleagues in the car. “I guess we’re not going to ship that phone.” 引用元: The Day Google Had to 'Start Over' on Android - Fred Vogelstein - The Atlantic 「なんということだ。」彼は車の中で言った。「(今開発中の)あの携帯電話を出すわけにはいかないな」 Googleは2005年からAndroidを開発していました。その時プロジェクトメンバーは一週間に60-80時間働き(はい、そこで皮肉な笑みを浮かべないように)その年の終わりまでに製品として発表する予定だったのですが。 同じくGoogleのChris DeSalvoはこう言ったそうです。 “As a consumer I was blown away. I wanted one immediately. But as a Google engineer, I thought ‘We’re going to have to start over.’” 一消費者としは、ぶっ飛ばされた思いだ。すぐにでも手に入れたい。しかしGoogleのエンジニアとしては”全部やり直しだ” - さて時は戻って2013年。Steve Jobsの命日の前日に NYタイムスにこの日のプレゼンテーションの内幕を語った記事 が公開されました。かなり前に発表されてますし、日本語訳もいくつかあるのですが、あまりに面白いので紹介せずにはいられない。これを読むと、私も含めた多くの人(Andy Rubinを含む)が「ぶっとぶ程の衝撃」を受けたiPhoneのデモが薄氷を踏むようなものだったことがわかります。そしてデモを支えたエンジニア達の気持ちが少し想像できるように思います。 すばらしい日本語訳は オリジナル iPhone のデビューは大きな賭けだった — iPhone 開発秘話 | maclalala2 にあります。ここでは私が特に興味を惹かれた点だけを訳します。 Jobs had been practicing for five days, yet even on the last day of rehearsals the iPhone was still randomly dropping calls, losing its Internet connection, freezing or simply shutting down. Jobsは五日間に渡ってプレゼンのリハーサルをしていた。しかし最終日でさえiPhoneは通話を受け損なったり、ネットへの接続が切れたり、フリーズしたり単に異常終了していた。 まずここで驚くべきは、あのプレゼンのリハーサルは五日間にも渡って行われていた、ということ。良いプレゼンを行う「秘訣」についてはいろいろな議論がありますが、ある方が書いた言葉が一番真実に近いのかもしれません。 「結局練習じゃないか」 It worked fine if you sent an e-mail and then surfed the Web. If you did those things in reverse, however, it might not. Hours of trial and error had helped the iPhone team develop what engineers called “the golden path,” a specific set of tasks, performed in a specific way and order, that made the phone look as if it worked. メールを送ってその後にWebを見る場合はちゃんと動いた、しかし順序を変えると動かない。何時間にもわたる試行錯誤の末、iPhoneチームは「ゴールデンパス」を発見した。指定されたタスクを指定された順番で動かした場合だけ、iPhoneはちゃんと動作した。 ソフトウェアエンジニアであれば、この「ゴールデンパス」がどんなものか想像できると思います。そうなんですよね。なぜか順番を変えると動く。落ちる。何故だ。 Jobs wanted the demo phones he would use onstage to have their screens mirrored on the big screen behind him. (中略) So he had Apple engineers spend weeks fitting extra circuit boards and video cables onto the backs of the iPhones he would have onstage. (中略) But making the setup work flawlessly, given the iPhone’s other major problems, seemed hard to justify at the time. Jobsは使っているiPhoneの画面をそのままスクリーンに映し出したがった。そのため、Appleのエンジニアは数週間に渡って追加の基板とビデオケーブルをiPhoneに追加した。しかし他に問題が多数存在していることを考えると、スクリーンへの投影をうまく行う努力をする価値があるかどうかは疑問だった。 この日のデモを見て、Jobsが実際に使っているiPhoneの画面をスクリーンに投影したときは正直驚きました。仮にiPhoneが現在のように完成度が高いものであっても、そうした「余分な回路+機能」をつけてデモをすることは度胸のいることです。ましてやiPhone自身がバグだらけだった当時において「なんでこんな事をしなくちゃいけないんだ。カメラで操作画面写せばいいじゃないか」とエンジニアは呪ったのではないか、、と想像します。私がその立場なら間違いなくそう言って荒れます。(そしてクビになります) And audience members had to be prevented from getting on the frequency being used. “Even if the base station’s ID was hidden” — that is, not showing up when laptops scanned for Wi-Fi signals — “you had 5,000 nerds in the audience,” Grignon says. “They would have figured out how to hack into the signal.” The solution, he says, was to tweak the AirPort software so that it seemed to be operating in Japan instead of the United States. Japanese Wi-Fi uses some frequencies that are not permitted in the U.S. 観客が無線LANの周波数を使うのを防がなくてはならない。「無線LANのIDは隠されているが-PCからただWifiを検索しただけでは表示されない-観客の中には5000人のコンピュータオタクがいる。無線LANがハックされない、という保証はない」そのため、無線LANの周波数を米国ではなく、日本で使われているものにした。日本向けの周波数は米国では使用が禁じられている。 確かにデモをしているiPhoneが無線LANを使用していると知った瞬間(あるいはそうでなくても)無線LANを利用しようと「何か」を始める人は観客の中にたくさんいたに違いありません。しかしそこまで気を使うか?また米国内で使用が禁止されている周波数を使うとは問題では無いのか? Appleはそこまで配慮しました。彼らにとってはデモの成功が全てであり「いや、観客にそこまでする人がいるとは想定外でした」などという言い訳が通じる状況ではなかったのでしょう。 同じような「細心の注意」は次のパラグラフにも現れます。 Then, with Jobs’s approval, they preprogrammed the phone’s display to always show five bars of signal strength regardless of its true strength. The chances of the radio’s crashing during the few minutes that Jobs would use it to make a call were small, but the chances of its crashing at some point during the 90-minute presentation were high. “If the radio crashed and restarted, as we suspected it might, we didn’t want people in the audience to see that,” Grignon says. “So we just hard-coded it to always show five bars.” ジョブスの許可を得て、実際の電波強度に関係なく電波強度バーが常に5本出るようにプログラムした。ジョブスが電話をする数分の間に無線モジュールがクラッシュする確率は少なかったが、90分のプレゼンの間一度もクラッシュしないとは思えなかった。Grignonはこう語っている「無線モジュールがクラッシュして再起動しても、それを観客に悟られたくはなかった。そのため常に5本バーが表示されるようにプログラムした」 エンジニアであれば一度はこういう「無理やり正常表示」をやった経験があるのではないでしょうか。もちろんクラッシュしないように改善するのがいいのだけど追い詰められるとそうも言っていられなくなる。しかしこうした「捏造」の行き着く先は、「全部嘘の全編ムービー再生」であり、どこかで歯止めをかける必要があります。 さて、Demo専用のビデオ出力、表示プログラムまで装備したiPhoneのデモが始まります。Jobsはメールを送り、メッセージを送り、いくつかのwebサイトをSafariで開いてみせる。Iveにその場で電話をかけたり、スターバックスに「持ち帰りでラテを4000。おっと番号違いだ」と冗談で電話をしたりします。 この日のJobsは自信に満ちており、自分が素晴らしい製品を発表できる喜びに満ちているように見えました。しかし彼が手順を一つ間違えただけで、iphoneはクラッシュし、未完成な製品であることが世界中に「披露」されていたはずです。 そうした「裏の事情」を知っていたエンジニア達は、このプレゼンテーションをどのように見守っていたのか。 By the end, Grignon wasn’t just relieved; he was drunk. He’d brought a flask of Scotch to calm his nerves. “And so there we were in the fifth row or something — engineers, managers, all of us — doing shots of Scotch after every segment of the demo. There were about five or six of us, and after each piece of the demo, the person who was responsible for that portion did a shot. When the finale came — and it worked along with everything before it, we all just drained the flask. It was the best demo any of us had ever seen. And the rest of the day turned out to be just a [expletive] for the entire iPhone team. We just spent the entire rest of the day drinking in the city. It was just a mess, but it was great.” 最後にはGignonはただホッとしただけではく、酔っ払っていた。彼は神経を鎮めるためスコッチを持ち込んでいた「関わったエンジニア、マネージャーはみんな5列目あたりにいた。デモの部分部分が終わる度にスコッチを飲んでいた。5−6人いたかな?自分が担当している部分のデモが終わる度にスコッチを一気飲み。デモが終わる頃ボトルも空になっていた。あれは今まで観た中で最高のデモだった。その日はiPhoneチームにとって最高だった。街にでて飲みまくった。めちゃくちゃだったが、素晴らしい日だった。」 - 最近行われたApple-サムソンの裁判で、フィル・シラーはこう言ったと伝えられています。 "There were huge risks [with the first iPhone]," he said. "We had a saying inside the company that it was a 'bet the company' product.. 引用元: Apple's Schiller: iPhone was a 'bet the company' product | Apple - CNET News 最初のiPhoneは大きな賭けだった。社内では「これは会社自体を賭ける製品だ」と言っていた。 素晴らしくはあるが、まだ未完成の製品を使って、あのプレゼンテーションをしたSteve Jobsはやはり並みの人間ではなかった。私なら処理待ちを示すインジケーター(あのくるくる回る奴です)が一回回るごとに寿命が縮んでいたことでしょう。少し表示が遅ければ、その瞬間動揺を隠せなかったでしょう。 プレゼンの後半、Jobsが「発売は6月」と言ったところで失望の声が上がりました。Jobsはその声に対して「6月に発売する製品をなぜ今日発表するか?これからFCCの認可を得なくてはならないが、FCCから情報が漏れるより自分たちで発表したかったからだ」 それを聞いた私は「6月まで待たなくちゃならないのか。まったく時間のかかる手続きには困ったものだ」と思いました。しかしエンジニア達の本当の戦いはおそらくここから始まったのではないか。この時のiPhoneの完成度がどの程度のものであったのか、当時書かれた別の記事を引用します。 MacworldのAppleブースに展示された2台のiPhoneは、ケースを取り囲む来場者の視線にさらされながら、のんきにぐるぐる回っている。そう、特別な人でなければ触ることはできない。 ちなみに2台しかないにもかかわらず10日昼過ぎ(現地時間)には1台がハングアップして画面が暗くなってしまっている。 引用元: Macworld Conference & Expo2007:ショウケースに守られた「iPhone」、実際の使い心地は? - ITmedia PC USER 手順を固定したり、いざとなればニセの表示を行うことでデモは(ヒヤヒヤながら)乗り切ることができる。しかし製品はそうした言い訳をまったく考慮しない人たちの手に渡るのです。たった6ヶ月でそこまで製品の完成度を上げ、量産しなくてはならない。 「それからの6ヶ月の物語」が語られることがあるのかないのかわかりません。今はただその苦闘を想像していましょう。それとともに苦闘が素晴らしい製品に結実したエンジニアたちの幸運(苦闘と製品の質の間には不幸なことに常に相関関係があるわけではありません)をうらやましく思いながら。
ネクストでエンジニアをやっています瀧川です。 今回は最近先輩と共同でやった小さめのWEBアプリを作った時に表題の環境を整えるところを担当したのでその紹介をしたいと思います。 同様の記事はネット上にいくつかあったのですが、僕自身これを行うときの段階では node.jsで開発するのも初めてで MongoDBを扱ったこともなく ElasticSearchにいたっては名前を聞いたこともない という無能っぷりだったので色々苦労しました。 そのため、備忘録ということで書かせていただいております。 ただ、本題からずれすぎるのもアレなのでここでは表題のものそれぞれについて細かく説明しません。 あくまでこれらの連携を実現させる方法についてのみ書きます。 一応、それぞれを超カンタンに説明すると node.js … サーバーサイドJavaScript MongoDB … ドキュメント指向データベース Open Source Distributed Real Time Search & Analytics | Elasticsearch … 全文検索エンジン といったところです。 リンク先は各公式HP。 それでは、本題に入りたいと思います。 ElasticSearchとMongoDBを連携させる いまさらですが、ElasticSearchは全文検索エンジンです。 なので何かを検索します。 今回、その「何か」とはMongoDBのもつスキーマなので、MongoDBのもつデータをElasticSearchのクラスタと連携する必要があるわけです。 まずはその設定を行います。 ElasticSearchのプラグインを入れる ElasticSearchのインストールが完了しているなら、plugin というコマンドが使えるようになっているはずです。それを使って $ plugin -install elasticsearch/elasticsearch-mapper-attachments/ 1 . 8 . 0 $ plugin -i com.github.richardwilly98.elasticsearch/elasticsearch-river-mongodb/ 1 . 7 . 0 と実行してください。 もしこのときすでにElasticSearchが起動している場合には、プラグインを認識するために再起動させてください。 補足すると、ElasticSearchにはRiverというクラスタにデータを流し込むサービスがあって、 それのmongoDB版のプラグインが river-mongodb になります。 これを使うことでMongoDBのデータをElasticSearchに流し込むことができます。 mapper-attachmentsのほうは恥ずかしながらなぜ必要なのか正確にはよくわかっていませんが、 きっと型マッピングを扱うために必要なんだと思っております。 なにはともあれ、これでElasticSearch側はmongoDBのデータを受け入れる準備ができました。 簡単! 次はMongoDB側です。 MongoDBのReplicaSetを用意する river-mongodbプラグインはなにやらMongoDBのインスタンスがReplicaSet(レプリケーション)として起動していないとうまく動かないらしいので、 ReplicaSetの設定をし、それを起動してやる必要があります。 まずは ReplicaSet用のディレクトリ(データ保存/ログ保存)を作成します。 もちろん名前などは適宜おこのみでつけてください。 $ mkdir /data/mongo/rs0 $ mkdir /data/mongo/log 作成したディレクトリを使用し、ノードを起動します。 $ mongod --replSet testrep --port 27017 --dbpath /data/mongo/rs0 --logpath /data/mongo/log/rs0.log & ちゃんと起動していることを確認するため、立ち上げたポートにブラウザでアクセスしてみます。 ローカルで作業しているならば http://localhost:27017/ へアクセス。 アクセス先で You are trying to access MongoDB on the native driver port. For http diagnostic access, add 1000 to the port number と表示されていれば成功です。 このメッセージの指示どおり+1000番のポート(今回の例だと http://localhost:28017/ )へアクセスすると管理画面となります。 ここまででレプリケーションの下準備は完了しました。 レプリケーション本来の目的として考えるとノードが1つだけって意味があるのか不明ですが、 今回はElasticSearchとの連携だけが目的なのでこのまま進みます。 これでReplicaSetを動かすための下準備はできました。 あとはコンソールから設定と初期化を行います。 まずはmongoコマンドを実行。ポート番号はもちろん先ほど起動したレプリケーションのポートです。 $ mongo -port = 27017 実行したらrs.initiateというコマンドで初期化します。 > config = { _id: 'testrep' , members: [{ _id: 0, host: 'localhost:27017' }]} ; > rs.initiate( config ); _idキーは先ほど用意したreplSetの名前 members._idはおこのみで members.hostは先ほどブラウザでアクセスしたURL という感じに読み替えてください。 最後に > rs. status (); を実行し、特にエラーが出なければ("ok"の値が1であれば)設定完了です。 これでmongoDB側も準備が完了しました。 最後にElasticSearchのCollection, Indexとの関連付けを行います。 ElasticSearchのCollection, Indexとの関連付け ElasticSearchの設定はcurlコマンドを使います。 僕はここでよくタイポを起こしてウオオオオオー!となることが多かったのでシェルスクリプトで書いて実行していくのがおすすめです。 ということで下記のようなシェルスクリプトを実行します。 (ElasticSearhは9200番ポートで立ち上がっている前提) #! /bin/sh curl -XPUT " localhost:9200/_river/test_es/_meta " -d ' { "type": "mongodb", "mongodb": { "db": "test_es", "collection": "collectionName", "servers": [ { "host": "127.0.0.1", "port": 27017 } ], "options": { "secondary_read_preference": true } }, "index": { "name": "indexName", "type": "typeName" } } ' curlコマンドで指定しているURLの"test_es"がIndex名になります。 mongodb.db, mongodb.collection, mongodb.indexの設定は各々実際に使用する際に適したものをつけてください。 実行後、 http://localhost:9200/ river/test_es/ meta にアクセスしたときに { "_index" : "_river" , "_type" : "test_es" , "_id" : "_meta" , "_version" :1, "exists" : true , "_source" : { "type" : "mongodb" , "mongodb" : { "db" : "testEs" , "collection" : "collectionNames" , "servers" : [ { "host" : "127.0.0.1" , "port" : 27017 } ] , "options" : { "secondary_read_preference" : true } } , "index" : { "name" : "indexName" , "type" : "typeName" } }} と表示されていればOKです。 これでようやく連携部分は完了です。 最後にnode.jsから操作してみましょう。 Node.jsからの操作 まずは必要なモジュールをインストールしましょう。 $ npm install mongoose $ nom install es 名称からお察しの通り、mongooseがMongoDB、esがElasticSearch用のモジュールとなります。 まずは適当にデータを登録。(直接DBから入れろという話は置いといて) var mongoose = require( 'mongoose' ) , Schema , Model , db ; // MongoDBへアクセス db = mongoose.connect( 'mongodb://localhost:27017/testEs' ) // Schemaの設定 Schema = new mongoose.Schema( { name: { type: String , trim: true } , type: { type: String , trim: true } } ); // コレクションを生成 Model = db.model( 'collectionName' , Schema); // 適当にデータを入れる var neko = new Model( { name: "mike" , type: "siamese" } ); // 保存 neko.save( function (err) { console.log(err); } ); これでエラーがでなければ、nekoをMongoDBに登録できています。 さて、いよいよこの情報をElasticSearchから取得します。 // 関連付けたindex, typeを設定 var elasticsearch = require( 'es' ) , config = { _index: 'indexName' , _type: 'typeName' } , es = elasticsearch(config) ; // 全文検索開始 es.search( { query: { query_string : { query : "mike" } } } , function (err, data) { console.log(data); console.log(err); } ); これを実行すると、下記のような結果が帰ってくるかと思います。 //出力結果 { took: 2, timed_out: false , _shards: { total: 5, successful: 5, failed: 0 } , hits: { total: 1, max_score: 0.23953635, hits: [ [ Object ] ] } } これが確認できれば完了です。 data.hitsオブジェクトがもつ、hitsという配列(ややこしい)の中にデータが入っています。 お疲れ様でした。 // ちなみに // もちろんtypeでも取得可能 es.search( { query: { query_string : { query : "siamese" } } } , function (err, data) { console.log(data); console.log(err); } ); //出力結果 { took: 2, timed_out: false , _shards: { total: 5, successful: 5, failed: 0 } , hits: { total: 1, max_score: 0.23953635, hits: [ [ Object ] ] } } こんなかんじで、なんとか表題の連携をさせることができました。 探り探りいろんなことを試しながらこの設定をしたのでどこか抜けなどありましたらぜひご一報を。 この環境が整え終わると、すべてがJSで完結してる"風"な気持ちになれて嬉しいですね。
大坪と申します。Simple Exampleシリーズと称して「ググれば見つかるけど、ちょっとわかりづらい」iOS上でのテクニックについて ・実行できるサンプルプロジェクト付(動かないとわかんない) ・肝心な部分を動かすのに必要最低限のコードを書く。余計なものは一切つけない(ごてごて余計なものがあるとどこが肝かわからない) をモットーにサンプルコードを解説&公開していきます。第一弾は「UICollectionViewのframeをアニメーション付きで変更する」方法について。 UICollectionViewというのは私見では実に偉大な画面部品で、あちこちで使いたくなります。その際「何かのアクションでUICollectionViewのframeを変更する」ということがあると思います。 というわけで、 githubにおいた のサンプルコードを実行してみてください。こんな画面が表示されるはずです。 左端にUICollectionViewが表示されています。画面右側一番上の"Frame Change"を押してみてください。いきなりUICollectionViewの外枠とセルが変化します。 プログラム的には UICollectionView.frame = newFrame; (ViewController.mのsimpleChange:(UIButton*) buttonの処理 としただけです。 これで用が足りる場合もあるでしょうが、iOSでプログラムを書いていると「アニメーションで変化させたい」と思うことでしょう。実際UIView animationWithDuration:は偉大で、ブロックの中に変化させる処理を書けば、たいていのことはアニメーションで変化させてくれます。ではさっそくframeの変更処理をUIView animationWithDuration:の中にいれてやりましょう。 画面のFrame Change + UIView animationを押すとこの処理が実行されます。 確かにアニメーションするのですが、なんとなく動きが期待と違うと思います。とくにUICollectionViewの幅が狭くなる時には、セルが縦一列にいきなり移動し、そのあとアニメーション付きでUICollectionViewのframeが変化する。これはあまり美しくない。 というわけで、一番下のCombo Changeを押してみてください。frameの変形だけではなく、セルの移動にもアニメーションがついたのがわかると思います。 これをどうやって実現しているかというと、ViewController.mのcomboChange:(UIButton*) buttonをみてください。 ほとんどの処理は先ほどのanimChangeと同じですが、その外側に_collectionViewController.collectionView performBatchupdates:がついています。これがつくとセルまでちゃんとアニメーションしてくれる、というわけでした。 みんな大好きStackoverflowにもいくつか回答があるのですが、そこにたどり着くまでかなり苦労したので、ご参考になれば。
はじめまして、長沢です。 弊社では最近一部サービスでAWS および Ruby を利用しているのですが、 今回はAWSの AWS SDK for Ruby を利用して クロスアカウントアクセス をやってみようと思います。 簡単に クロスアカウントアクセスについての説明 クロスアカウントアクセスとは、一言で言うと、異なるAWSアカウントをまたいだリソースの操作を行う事ができる機能です。 クロスアカウントアクセスの方法は IAM Role の AssumeRole API を利用します。 IAM Roleを利用したクロスアカウント API アクセスの方法の詳しい説明は こちら この記事たちを読めば大体は分かります。 個人的に思った注意しなくてはいけないところ (個人的にはまったところ) は AMIユーザーでなければクロスアカウントアクセスは出来ない 認証先のIAM Role の Trust Relationships は適切に設定して権限を管理する と言ったところでしょうか。 の部分に関しては最初は気づかずに Role で AssumeRole をしようとしていて、下記のエラーメッセージが出ていました。 "Roles may not be assumed by federated users" 事前準備(Webコンソール上でクロスアカウントアクセスの設定) 最初にWebコンソールを利用してアカウントの下記のAWSの公式ブログにあるような設定をしましょう。(ここでの説明は割愛致します) Delegating API Access to AWS Services Using IAM Roles | AWS Blog また、こちらの サーバーワークス様のブログ も大変分かりやすいです。 早速やってみる 上記の事前準備の設定が済んだら、 2つのAWSアカウントA、Bがあって それぞれ S3バゲット “account-a-bucket”(アカウントA) 、 “account-b-bucket”(アカウントB) が作成されていたときに、 クロスアカウントアクセスの仕組みを利用して、 アカウントAの IAM User “homes” が、アカウントBのS3に対してRead Only 権限をもつ IAM Role “s3-viewer” としてふるまい、アカウントBのS3バゲット名を取得する といったようなことを実現するためのコードを書いてみます。 コードの流れを簡単に説明すると、 IAMユーザーのアクセスキー、シークレットキーを利用してSTSにアクセス sts.assume_roleのAPIを利用して Credentialを取得 取得したCredentialを利用してアカウントBにアクセス といった感じです。 ※ 利用したRubyは 1.9.3-p327 です。 ※ キーがシンボルのHashの記法が 1.8.x と少々異なりますのでご注意ください。 cross_account_access.rb require ' aws-sdk ' # 設定 AWS .config({ region : ' ap-northeast-1 ' , access_key_id : ' アカウントAのhomesユーザーのアクセスキー ' , secret_access_key : ' homesユーザーのシークレットキー ' , }) # AssumeRole対象のIAM Role のARN assume_role_arn = ' arn:aws:iam::{アカウントBのID}:role/s3-viewer ' # session名は任意の文字列 assume_role_session_name = ' homess3viewersession ' # S3オブジェクトの取得(アカウントA) s3_a = AWS :: S3 .new puts ' ===== Account A Buckets ===== ' # バゲット名を出力 s3_a.buckets.each do | bucket | puts bucket.name end puts # STSオブジェクトの取得 sts = AWS :: STS .new # AssumeRoleを呼び出し一時的な認証情報を受け取る assume_info = sts.assume_role( role_arn : assume_role_arn, role_session_name : assume_role_session_name, ) # 認証情報の上書き AWS .config({ access_key_id : assume_info[ :credentials ][ :access_key_id ], secret_access_key : assume_info[ :credentials ][ :secret_access_key ], session_token : assume_info[ :credentials ][ :session_token ], }) # S3オブジェクトの取得(アカウントB) s3_b = AWS :: S3 .new puts ' ===== Account B Buckets ===== ' # バゲット名を出力 s3_b.buckets.each do | bucket | puts bucket.name end puts 実行してみます $ ruby cross_account_access.rb ===== Account A Buckets ===== account-a-bucket ===== Account B Buckets ===== account-b-bucket うまくできているようです! 念のため、アカウントA,B それぞれの IAM Policy や Trust Relationship の設定を以下に記載いたします。 アカウント A の設定 IAM User “homes” の Policy (STSのAssumeRoleとS3の閲覧に権限をつけている) { "Statement": [ { "Effect": "Allow", "Action": "sts:AssumeRole", "Resource": "*" }, { "Effect": "Allow", "Action": [ "s3:Get*", "s3:List*" ], "Resource": "*" } ] } ちなみに、STSで AssumeRole しようとして、 もしそのRoleに対して権限がないときは下記のようなエラーが出ます。 A client error (AccessDenied) occurred: User: arn:aws:iam::{AのアカウントID}:user/homes is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam::{BのアカウントID}:role/s3-viewer アカウント B の設定 IAM Role “s3-viewer” の Policy(S3の閲覧に権限をつけている) { " Version ": " 2012-10-17 ", " Statement ": [ { " Effect ": " Allow ", " Action ": [ " s3:Get* ", " s3:List* " ] , " Resource ": " * " } ] } Trust Relationship { "Version": "2008-10-17", "Statement": [ { "Sid": "", "Effect": "Allow", "Principal": { "AWS": [ "arn:aws:iam::{AのアカウントID(12桁)}:user/homes" ] }, "Action": "sts:AssumeRole" } ] } もし、上記のPrincipalの箇所が "Principal": { "AWS": [ "arn:aws:iam::{AのアカウントID(12桁)}:root" ] } としてしまうと、 そのアカウントの全ユーザーがデフォルトでアクセスできることになってしまうので注意が必要です。 株式会社ネクストでは、一緒に世の中をもっと便利に楽しくしたい仲間を募集中です。 主体的に楽しみながら仕事できる方からのエントリーお待ちしています! http://recruit.next-group.jp/
ガジェット大好き、カメラ大好きな非エンジニアです。 360度全天球カメラRICOH THETAを買ってみたので、品川オフィスと合わせてちょっとだけご紹介です。 THETAはスティク型のカメラです。両面に魚眼レンズが付いていて、1回のシャッターで空間をまるっと撮影できます。 手にフィットする形状で、95グラムという軽量さ。荷物が多いガジェット持ちにはうれしい配慮です。 撮影は中央のシャッターボタンを押すだけ。起動が早いので、シャッターチャンスは逃しません。これまたうれしい! iPhone/Androidアプリを使用すればリモート撮影することも可能です。 ということで、本日は品川オフィスのリモート撮影に挑戦したいと思います。 こんな感じTHETAを設置します。 そして、アプリのボタンをぽちっと押すと本体から「キュイン」と可愛い音が鳴ります。 撮影はこれで完了! 撮影した写真はアプリ上で楽しむことも出来ますが、専用のビューワーで共有することもできます。 専用のビューワーは、こんな風に自分のWebサイトに埋め込むことができます。 品川オフィス受付 - Spherical Image - RICOH THETA 専用のビューワーを使用せずに見ると湾曲したJPG画像ですが、ヘッドマウントディスプレイ「Oculus Rift」、3D空間を再現する「Photosynth」などでも楽しむことができます。 撮影画像には位置情報もつけられるので、ライフログなどを付けるのにも良さそうです。 品川フロントビル - Spherical Image - RICOH THETA 一眼の魚眼レンズで撮影して、切って、貼ってみたいな作業不要です。 解像度やISO感度などは一眼レフには遠く及びませんが、 なにせ手軽!楽しい!撮影したときには気づかなかった、自分が見えていない場所も映っていたりといろいろなシーンで活躍しそう。 ただ、残念な点がいくつかあります。 ファームウェアのアップデートがあることを期待しつつも、 セルフタイマーがなーーーいッ! 撮影用の専用リモコンが欲しいッ!!! などなど・・・。 あぁうちのエンジニアなにか開発してくれないかなぁ |д゚)チラッ とつぶやきつつ、本日も「キュイン」と撮影! RICOH THETA: https://theta360.com/ja/
さて、前回にReadとCreateをしたので、次はDelete、Updateをしましょう! ドキュメント更新 前回同様、Updateは、NSDictionaryを操作します。 簡単にいえば、ドキュメント内容をNSDictionaryで受け取って、中身を入れ替えてまたセットし直すという感じです。 まず、この時点で、UITableViewを配置している前提としています。 流れは ドキュメントをMutableDictionaryで受け取る Bool値を入れ替える CBLDocumentに値をputする という感じになります。 Couchbase LiteをCBLDocumentベースで更新 見て分かる通り、ほぼCreateと変わりません。 いうなれば、CBLDocumentを作成する時が、untitledなのか、documentWithIDなのかの差です。 ドキュメント削除 削除は簡単。 流れは 削除する対象のCBLDocumentを作成 CBLDocumentをdeleteする Couchbase LiteをCBLDodumentで削除 こちらもほとんど他のとやり方は変わりません。 まとめ CUDの流れは CBLDocumentを作成 putなりdeleteなりする Rは CBLQuery作成してDocumentを取得 イテレータでArrayに込めなおす って感じですね。 ここまでNSDictionaryで作成したりなんだりしましたが、次回はモデルを使った操作も見てみましょう。 株式会社ネクストでは、一緒に世の中をもっと便利に楽しくしたい仲間を募集中です。 主体的に楽しみながら仕事できる方からのエントリーお待ちしています! http://recruit.next-group.jp/
大坪と申します。12/4-6に高知で行われましたWISS2013に参加しました。2年前WISSについて私はこう書きました。 WISS の正式名称は「インタラクティブシステムと ソフトウェア に関するワークショップ」だが、誰もこの名前で呼びはしない。ほとんどの場合「ういっす」と呼ぶ。では WISS とは何か?公式サイト ( http://www.wiss.org/WISS2011/ ) には以下のような文字が並んでいる。 「WISS は、2泊3日の泊り込み形式で、インタラクティブシステムにおける未来を切り拓くような新しいアイディア・技術を議論するワークショップです。この分野において国内でもっともアクティブな学術会議のひとつであり、例年170名以上の参加者が朝から深夜まで活発で意義深い情報交換をおこなっています。」 しかし WISS に参加することの意味は、これだけの文字で語り尽くせるものではない。 via: WISS2011 参加報告 - 株式会社ネクスト エンジニアBlog WISSがどのような場か?ということについては、上記引用元を参照していただくとして、今年印象的だった点について書きます。 - WISSとはなにか?その答えは人によって違うでしょうが、今年特に記憶に残ったのはプログラム委員長五十嵐教授の 「WISS発表中に行う議論は、参加者全員によるブレーンストーミングのようなものだ」 でした。WISSはあくまでもワークショップ。完成した研究に「権威付け」を与えるような場ではなく、まだ未完成だが興味深いideaに関して議論を行い発展させていく場所である、と。 そう考えれば重要なのは「人と人とのコミュニケーション」である、という結論が導かれるわけです。しかしここに問題が。エンジニアとか「理系」と呼ばれる人の中には、コードやガジェットやコンピュータとコミュニケートすることは得意でも、対人コミュニケーションには二の足を踏んでしまう、という人も多いのではないでしょうか。(少なくとも私はそうです) しかしそうした「問題」を解決するのもテクノロジーの役割。宿泊を伴うカンファレンスで、食事の時どこに座るかは常に気を使う問題です。周りが知らない人ばかりだと何を喋っていいかわからない。しかし知り合いばかりで固まっていては進歩がない。こうした機会だから有名なあの人とお話したいけど勇気が出ない。 そうした問題に解決策を与えてくれるのが、去年から運用されている「夕食時席ぎめシステム」。事前に「こんな話題について語りたい」「◯◯さんとお話したい」「誰かと、誰かが一緒のテーブルになると面白いんじゃないか」という希望を登録しておけば、できるだけその要望に沿う形で夕食の席が決まる。とはいえ席について最初の数分は 「そもそもなぜこの顔ぶれになったのか」 で皆が悩むことになります。 今年もこのシステムには大変お世話になりました。二日目の晩に同じテーブルになったのは、神戸大学の西田准教授。彼はWISS2006で「遠くの3次元より近くの2次元」という言葉とともに大いに議論をよんだ「 萌え木;拡張現実による植物育成支援 」の著者であるとともに、夕食席ぎめシステムの開発者でもあります。西田さんからは「萌え」の心について大変興味深い話を聞かせてもらえました。話が盛り上がりすぎて、他の人達が夕食場から立ち去ったあともずっと居残り、ホテルの人たちにご迷惑をお掛けしてしまったのではないかと少し反省しております。 その後のナイトセッションでは、大学での情報系の教育の悩み、社会から期待されていることは何なのか。そもそもSEなる奇妙な職種の人はプログラムを一行も書かなくても、、とかそんな議論ができました。睡眠時間の確保に何よりも情熱を燃やす私が、(私にとっては)夜遅くまで話し込んでいた、というのは稀有の出来事です。 WISSは通常交通の便があまりよくない場所で開催されます。なぜかというと夜に外にでかけてしまうのを防止するためだとか昔聞いたような。今年は珍しく高知城から歩いて数分の便利の良い場所で開催されましたが、夕食後に抜け出してどこかに行こう、などという人はあまりいなかったのではないかと思います。というかもったいない。 - 前WISSプログラム委員長の後藤さんは朝一番 「皆さん。おはようございます!」 と凛とした挨拶で眠気を吹き飛ばしてくれました。プログラム委員長は代わりましたがこの「朝の挨拶」はちゃんと受け継がれているようです。その後には様々な分野の発表が続く。参加者は発表の間もチャットシステムを使って議論を行います。 昨今Twitterを利用してカンファレンスの参加者が議論することは珍しくありませんが、WISSのチャットはクローズドシステムということもあり、発現量が桁違いです。使われているのはシンプルなチャットですが、一点だけ特徴が。「これは同意」という発言に対して「同意ボタン」を押すとその発言が大きくなります。また最終日には「見たくない発言を小さくするボタン」が追加で実装されました。 過去には「2次元チャット」など様々なチャットシステムが使われたのですが、結局シンプルなテキストチャット+同意ボタンに収束してきた、というのは大変興味深い点です。 もう一つ発表時の試みで興味深いのは、外部へのインターネット接続制限です。人間はどうしても馴染みのある、居心地のよい環境に閉じこもりがち。発表を聞き質疑応答であるいはチャットで議論を交わすべき、とわかっていてもついFacebookを見てしまう、仕事のメールに返信をしてしまう、あるいは研究室独自のチャットシステムに引きこもってしまう。 そうした問題を解消するため、去年から登壇発表中は外部へインターネット接続ができなくなっています。これに対しては様々な議論が有り、例えばチャットでの議論に先行研究を参照したい、という要望に答えて、接続できる範囲が調整され続けています。 私はこの取り組みに基本的に大賛成しています。今から10年ほど前の「将来予想図」では「だれでもどこでもインターネット」が実現すればすばらしい未来が来る、と脳天気な絵が描かれていました。しかし現実はどうでしょう?どこにいてもSNSにアクセスし続けることが本当に「すばらしい未来」につながっているのでしょうか?誰かと話している時ですら、スマホの画面をいじり続けるのが我々が目指した未来でしょうか?情報技術がもたらす恩恵と問題のバランスに関しては常に問い直し、見直しをかける必要がある。これはそうした取組の一つとして大変意義あるものだと思います。 - 全ての日程が終了した後には非公式エクスカーション「沢田マンションツアー」が行われました。沢田マンションとはなにか? Wikipedia によれば 沢田嘉農 (さわだ かのう、 1927年 8月11日- 2003年 3月16日)は、高知県生まれ。幼少時に雑誌で見た「 アパート 」の様子に感動して、集合住宅の建築・経営を一生の仕事にすると思い定める。 via: 沢田マンション - Wikipedia 沢田嘉農氏の 「これはすごい。絶対これを作ってやる」 という思いは、WISS参加者の心情にぴったりではないか。マンションを設計したことも、建築した経験がなくてもとにかく作ってしまう。WISSでは常に新しい試みが実践され、かつ研究として発表される。つまり前例がないことが当然なわけです。前例や経験はなくても 「これがあるべきだ」 と考えれば作って発表し、それに対して皆が議論をする。沢田マンション屋上にある手作りクレーンにWISSでデモされていた数々の「手作りデバイス」のイメージを重ねあれこれ考えていました。 - じゃあお前は他人が作ったものについて議論をするためだけに行ったのか、と問われれば「いやデモ発表をしました」と答えます。おそらく日本で一番(世界でも有数かもしれません)UIやUXに関して意見を持っている人達相手にデモをするのは度胸のいることですが、「 へやくる! 」に実際に触っていただき議論をさせてもらいました。 物理的高さと言語の壁に挑む筆者 意見をいただけた方に感謝です。さて来年の開催場所はまだアナウンスされていませんが、WISSでの議論に貢献するためにはどんな方法があるか、今から頭を悩ませております。 =========================================== 株式会社ネクストでは、一緒に世の中をもっと便利に楽しくしたい仲間を募集中です。 主体的に楽しみながら仕事できる方からのエントリーお待ちしています! http://recruit.next-group.jp/
こんにちは、@nazomikanです この記事は(JavaScript - Client Side - Advent Calendar 2013)の15日目の記事です。 @teramako 妙な古臭さを感じるのだが…。 http://d.hatena.ne.jp/teramako/20131216/p1 と的確な斧をいただいたので記事を修正しています これまで標準化されていなかった __proto__ がES6で標準化されようとしています。 参考: draft_proto_spec_rev2.pdf (大変古かったので差し替えました。) 参考: Object.prototype.__proto__ ※ まだドラフトで確定ではないのでご注意ください。 Object.prototype.__proto__ Enumerable : false Configurable : true 内部変数のUnderscoreProtoEnabledの真偽によってこのプロパティの操作を追跡するかしないかを決定します。 UnderscoreProtoEnabledは Object.prototpye をもっていればデフォルトでtrueになります。 重要なのは __proto__ は Object.prototype 上にいると明言されるようになったこと と、 __proto__ の UnderscoreProtoEnabled の挙動が明言されたこと。 (Rev20 Oct 28 2013の時点で UnderscoreProtoEnabled の内部プロパティに関する記述が消えてました) 元となるのは この話 __proto__ 標準化の背景 我らが唯一神のDouglasのGood Partsにこんなコードがあった。 that.on = function (type, ....) { .... var registry = {}; .... if (registry.hasOwnProperty(type)) { registry[type].push(handler); } else { registry[type] = [handler]; } .... }; なんの変哲もないコードのように見えるがこのコードは本当の意味でセーフティではないのだ。 いちゃもんをつけるような話になりかねないのだが、例えばなんらかのモンキーパッチ(Object.prototypeへの変更を加えたりとか)によって registry が hasOwnProperty を持っていない可能性もある。 これは hasOwnProperty を uncurryThis で初期時に束縛していれば解決できる。 var uncurryThis = Function.prototype.bind.bind(Function.prototype.call) , hasOwn = uncurryThis(Object.prototype.hasOwnProperty) ; //... that.on = function (type, ....) { .... var registry = {}; .... if (hasOwn(registry, type)) { registry[type].push(handler); } else { registry[type] = [handler]; } .... }; ... はじめて見る人は面食らうかもしれないがちょっと前に(ここ) http://wiki.ecmascript.org/doku.php?id=conventions:safe_meta_programming で流行った安全なコードだ。 付録的に末尾に書いといたので興味があれば見てほしい。 とりあえず、 uncurryThis を用いたことによって、たとえ registry がモンキーパッチや Object.create(null) でhasOwnPropertyをもっていなかったとしても安全に動作するように変更できた。 これでこのコードは安全になったように見える。 しかし問題はまだあった。 ここからが本題で、 type という変数が関数の外から渡されてきていることに注目したい。 この type は hasOwnProperty によってのみバリデーションをされている。 そう、ここが論点なのだ。 話の流れ的に分かるかもしれないが type が __proto__ という文字列だったときに問題が起きる。 これまで __proto__ は特に標準化もしていなかったためにそれぞれのブラウザ間で以下のような場合に評価結果が異なってくるのだ。 [{}.hasOwnProperty('__proto__'), {}.__proto__.hasOwnProperty('__proto__')] false,false // Chrome true,true // WebKit Nightly false,true // FF Nightly false,false // Opera 12 alpha throws TypeError // IE10 Preview 2 (2011/12/26の時の話です) IEが __proto__ をサポートしてないがためにexceptionを発生させるが、そんなことは問題ではない。 ここで驚くのはWebKit Nightlyの挙動でしょう。 {}.hasOwnProperty('__proto__') の挙動がこのブラウザでだけ true を指し示している。 最初のコードをもう一度見直してみよう that.on = function (type, ....) { .... var registry = {}; .... if (registry.hasOwnProperty(type)) { //....(1) registry[type].push(handler); // ....(2) } else { registry[type] = [handler]; } .... }; 先ほどの実行結果を元に考えると type の値が __proto__ という文字列だった場合、(1)は if (registry.hasOwnProperty('__proto__')) { となり、Webkit Nightlyでのみ true を返すことになる。 これによって(1)を通過し、(2)を実行する時に registry['__proto__'].push(handler); となり、 __proto__ はobjectなので Object.prototype.push なんてもってないよとばかりにエラーを発生させるのだ。 とまぁ、こんなブラウザ間での挙動が引き起こした穴を埋めるため標準化が始まりました。 今後(といっても確定ではないが)、 __proto__ は Object.prototype 上にいると定義されるわけなので [{}.hasOwnProperty('__proto__'), {}.__proto__.hasOwnProperty('__proto__')] の実行結果は [false, true] に統一されていくのでしょう。 setPrototypeOf ここまで __proto__ 標準化の流れについて色々書きましたがES6からは Object.setPrototypeOf が定義されつつあるので __proto__ 系の操作はそちらを通して行われるほうが今後としてはよいようです。 @teramakoさんまさかりありがとうございました(^-^)/ おまけ( uncurryThis ) 以外と難しいので説明 obj.func1 func1において this の指す値は obj になる。 そう、つまりこの形において this とは . より左の部分を指す つまり var uncurryThis = Function.prototype.bind.bind(Function.prototype.call) は Function.prototype.bind の this を Function.prototype.call に変更している(= . より前を差し替えている)という風に言えるので Function.prototype.call.bind と等価だと言える。 さらにそれをふまえた上で var uncurryThis = Function.prototype.bind.bind(Function.prototype.call), hasOwn = uncurryThis(Object.prototype.hasOwnProperty); if (hasOwn(registry, type)) を見てみると var uncurryThis = Function.prototype.bind.bind(Function.prototype.call), // === Function.prototype.call.bind hasOwn = uncurryThis(Object.prototype.hasOwnProperty); // === Function.prototype.call.bind(Object.prototype.hasOwnProperty) // === Object.prototype.hasOwnProperty.call if (hasOwn(registry, type)) // === if (Object.prototype.hasOwnProperty.call(registry, this)) と等価であることがわかる。 こんな感じでcallのthisを束縛してモンキーパッチに対抗するみたいな方法のことです。 株式会社ネクストでは、一緒に世の中をもっと便利に楽しくしたい仲間を募集中です。 主体的に楽しみながら仕事できる方からのエントリーお待ちしています! http://recruit.next-group.jp/
こんにちは上津原です。 今回はUnityネタです。 現在Unity3Dを触っているのですがやっと面白くなってきました! そしてそこで、調べてなかなか出てこなかった「一人称視点でモノを浮き上がらせて移動させる方法」について書いてみようと思います。 具体的に説明すると こんな風に下に落ちているオブジェクトを こんな風に中心点で維持して持ち上げる方法ということになります。 調べてみると、方法は2種類ありました。 MainCameraをParentにする方法 FiexdJointを活用する方法 それぞれ紹介していきます。 MainCameraをParentにする方法 対象となるオブジェクトを、カメラのParentに指定して、グルーピングしてしまう方法です。 コードは以下のようになります。 ※動かす対象に「Target」タグをつけています。 Unityでモノを持ち上げ、離す。左クリックで物体をとらえ、 左クリックで落とす、右クリックで投 ... 上記ソースは、ついでに持ち上げた時に右クリックすると前方に投げるファンクションも含まれています。 この方法の特徴 モノを持ち上げて移動しているとき、その場から動かない設定をしているオブジェクト、またはリジットボディを設定していないモノにぶつかった場合、コリジョンを無視する結果となります。 動かすことにできるものにぶつかった場合は、Massを無視してあたったシテを移動させます。 持ち上げている物体がすり抜けてしまう、というわけです。 なので、その方が都合がいいぞ、という場合はこちらを利用するといいかもしれません。 FiexdJointを活用する方法 対象となるオブジェクトとカメラをPhysicsの機能である「Fixed Joint」でつないでしまう方法です。 こちらの方法は、上記方法と違い、モノをすり抜けずにあたり判定をきちんと保って移動させることができます。 実装はは以下のようになります。 まず、MainCameraにPhysicsの中にある、FixedJointを追加します。 FixedJointを追加すると、勝手にRigitBodyが追加されます。 「Mass」を適当な値にし、 「Is Kinetic」にチェックを入れます。 これを入れないとカメラが落ちて行ってしまうので気を付けてください。 そしてコードは以下のようになります。 あたり判定を保ったままオブジェクトを移動させる。 こちらのソースは、前方に投げるアクションはついていません。 この方法の特徴 前述しましたが、持ち上げたもののあたり判定を保ち続けることができます。 Massのことも考慮され、重いものを動かすことはできないし、軽いものは動かすことができます。 そして通り抜けられないモノにあたるとブルブルしてちょっと怖い結果にはなります。 まとめ 物理の法則を考慮する必要がないならParentに! 考慮する必要がないのならFixed Jointがいい! という考えに落ち着きました。 どっちを使うにせよ、こんなにお手軽に実装できてしまうのがすごい。Unity恐るべし。 株式会社ネクストでは、一緒に世の中をもっと便利に楽しくしたい仲間を募集中です。 主体的に楽しみながら仕事できる方からのエントリーお待ちしています! http://recruit.next-group.jp/
jadeを知る
こんにちは、@nazomikanです (この記事はNode.js Advent Calendar 2013の10日めの記事です) nodeでテンプレートエンジンといえばjade その一方で公式ドキュメントで書かれていることだけではだいたい痒い所に手が届かないのでissueから拾い集めたノウハウとか将来的な話とかを書きます 属性の存在が条件によって分かれるケースの書き方 url が存在するときdata-url属性をつける //truthy: <p data-url="xxx"> //falsy: <p> in jade: p(data-url=(url ? url : false)) 属性の値が条件によって分かれるケースの書き方 bool がtruthyの時は class="is-show" を、そうでない時は class="is-hide" をつける //truthy: <p class="is-show"> //falsy: <p class="is-hide"> in jade: p(data-url="is-#{bool ? 'show' : 'hide'}") 子要素にテキストとDOM要素が並列に存在しているケースの書き方 <p> この商品は<span class="price">10,000</span>円です </p> in jade: p | この商品は span.price 10,000 | 円です エスケープしたい変数とエスケープしたくない文字列が混在してる時の書き方 <p> この部屋の広さは#{space}m&sup2です </p> in jade: p | この部屋の広さは#{space}m != &sup2 | です if/elseで出し分けた要素の子要素を記述したい時の書き方 // bool is true <p> <a href="#"> <img src="./hoge.jpg"> </a> </p> // bool is false <p> <span> <img src="./hoge.jpg"> </span> </p> in jade(うまくいかないケース1): p if bool a(href="#") else span img(src="./hoge.jpg") -> elseの時だけしかでない in jade(うまくいかないケース2): p if bool a(href="#") else span img(src="./hoge.jpg") -> pの直接の子要素になる in jade(うまくいかないケース3): p if bool a(href="#") else span img(src="./hoge.jpg") -> elseの時にspanの兄弟要素として出る end とかないのでこの辺は mixin を使うしかない in jade(正攻法): mixin wrap(bool) if bool a(href="#") else span p +wrap(bool) img(src="./hoge.jpg") こんな荒業もある p #{bool ? 'a': 'span'} img でもこれは属性かくのうまくできないので辛い また、 | で続く文字列がプレーンなテキストになるのを利用して単純に開始タグと閉じタグで挟むという方法もあるにはある if bool | <a href="#"> else | <span> #inner-div if bool | </a> else | </span> 個人的にはラップしたいタグの階層が同じ場合は #{bool ?'a(href="#")' : 'span'} で済ませて、階層がごっそり違う場合はmixinを使うようにしてる 動的にインクルードしたい時の書き方 inclide ./#{foo}.jade みたいなことをしたいと誰しもが夢を見るが現在のところカスタマイズ無しでは無理 caseを用いて泥臭くやるしかない in jade: case foo when 'a' include a.jade when 'b' include b.jade //- ... checked=checkedとかdisabled=disabledとかを条件に応じて出し分けたい時の書き方 // bool is true <p checked="checked"> // bool is false <p> in jade: p(checked=bool) data-*にjsonを流し込みたい <p data-person={"name":"nazomikan"} in jade: - var person = JSON.stringify({name: "nazomikan"}) p(data-person="#{person}") inlineのブロックを使いたい時 インラインのブロックを使いたいこともあるでしょう タグの宣言後に : を使えばネストしたタグがかけるのでそれを利用してblockも書きましょう parent.jade h1: block article_title child.jade include parent block artiicle_title | awesome article 親ブロックの中身を継承したい時の書き方 parent.jade block contents p parent child.jade include parent block contents p child とあった時、評価結果は以下のようになる <p>child</p> これを <p>parent</p> <p>child</p> といった感じで親のブロックの中身を継承したいときは block append xxx を利用する parent.jade block contents p parent child.jade include parent block append contents p child とすると <p>parent</p> </p>child</p> が得られる また、前に挿入したいときは block prepend xxx で実現できる 実は yield が使える langage referenceには記載されてなかったけど平然と yield キーワードをサポートしている includeと組み合わせることで使える main.jade div include partial li main side partial.jade ul yeild li partial side1 li partial side2 とすることで以下のような結果を得ることができる <div> <ul> <li>main side</li> <li>partial side1</li> <li>partial side2</li> </ul> </div> タグの圧縮を解除したい場合 基本的にjadeではデフォルトでタグが下記のように圧縮されるようになっている <!DOCTYPE html><html><head><title>Express</title><link rel="stylesheet" href="/stylesheets/style.css"></head><body><p>Hello World</p></body></html> これをインデントのついた状態に表示したいときは以下のようにする 生のjade var html = jade.render('jade string', { pretty: true }); in Express(v3.x) app.locals.pretty = true in Express(v2.x) app.configure(function(){ app.set('views', dirname + '/views'); app.set('view engine', 'jade'); app.set('view options', { pretty: true }); // <- here app.use(express.bodyParser()); app.use(express.methodOverride()); app.use(app.router); app.use(express.static(dirname + '/public')); }); パフォーマンスを上げる jadeは現時点のデフォルト設定で十分に高速なテンプレートエンジンですが設定と実装次第ではさらに高速化させることができます namespaceを導入する jadeは通常以下の手順でコンパイルされます var fn = jade.compile("p #{title}", {}); fn({title: 'Title'}); template文字列の中で title という変数でアクセスできてますが、オブジェクト渡ししてるのに、なぜ xxx.title という形じゃないのか不思議ですね それは内部的に with 構文を利用してオブジェクトプロパティの変数展開をおこなっているからです ある程度jsに精通している方ならわかると思いますが with は構文内で与えられたオブジェクトのプロパティを変数に展開できるという機能があり、それまでの処理内容によって展開される変数に変化がおこるという動的スコープの性質をもっています これは実行前最適化に対して非常に厄介な問題で with 構文が処理中に含まれているとその部分に対して最適化が行えなくなります この問題を解決するためのオプションが self: true です このオプションを設定するとテンプレート内で self.title という形で変数にアクセスできるようになります 常に self という名前空間を通して変数にアクセスすることによって with 構文を回避できるというものです これを踏まえて先ほどの処理を書き換えると以下のようになります var fn = jade.compile("p #{self.title}", {self: true}); fn({title: 'Title'}); 結構中の人的には絶賛されてる機能みたいです tj: I like self muuuuch danielbeardsley: This is a crazy performance increase: 490ms -> 27ms Running the benchmarks shows jade-self takes 27ms, where jade takes 490ms. The fastest non-jade templating engine was ejs and it ran the test in 89ms. Go Jade! この ベンチ のことだと思います かなり高速化されてますね ejsと比べても数倍早いみたいですね compileDebugを本番時に切る jadeにはデバッグ用に compileDebug というオプションがあります これを切ると単純にデバッグ用にとってた情報をとらなくなるので早くなります といっても最低限の最低限の情報は出るので安心ください エラーログを見比べてみましょう 適当なファイルで参照エラーを出してみたときのエラーです わざと間違えたコード - var title = self.title h1= title p Welcome to #{sel.title} //- ここが間違い sel -> self compileDebug: true 500 ReferenceError: /home/nazomikan/node_workspace/jade_test/views/index.jade:10<br/> 8| - var title = self.title<br/> 9| h1= title<br/> > 10| p Welcome to #{sel.title}<br/> 11| <br/> 12| <br/><br/>sel is not defined at ....(以下コールスタック) compileDebug: false 500 ReferenceError: sel is not defined at ....(以下コールスタック) compileDebug: true の時は中のテンプレートも文字列まで表示してくれてるようになってます 開発時は true , 本番時には false にして切ってしまうのが推奨されています 将来のことを考える jadeはこんなにも普及してる一方でまだメジャーバージョンではないという反面もあります。(2013/11時点でv0.35.0) まだ用意されているsyntaxの中で廃止や追加がかなりの数、検討されています。 以降の項目を確認しましょう !!! はv1.0.0で消滅する html2jadeとかで <!DOCTYPE html> <html> </html> と打ち込むと !!! 5 と変換されますがこのsyntaxは廃止されますので注意が必要です 書きやすい反面、jade初学者には大変読みづらいという意見がでて廃止に至りました 参考 もともと !!! は doctype のエイリアスなのでこう書くのが将来的にも生き残る書き方になります doctype 5 代入構文( - 無し)が削除される 今まで、 (1) - var a = 1 - var b = 2 a = b span #{a} みたいな感じで書くと <span>2</span> って感じに評価されていたのですがこの a = b という代入演算子が使えなくなります 下記のように - を前につけてあげるとこれからも使えます (2) - var a = 1 - var b = 2 - a = b span #{a} これはjadeからjsにコンパイルされたときの状態に問題があったため削除されることになりました - ありであれば式はそのまま評価されます (1)を評価すると以下のようにjsに変換されます function anonymous(locals) { var buf = []; var a = 1; var b = 2; var a = b; { buf.push("<span>" + jade.escape((jade.interp = a) == null ? "" : jade.interp) + "</span>"); } return buf.join(""); } var a = b となって二重定義されていることに注目してください (2)を評価すると var a = b の部分が a = b と評価されます これは以下のようにスコープのネストが発生した場合に問題を起こします mixin parent() div block mixin check(value1, value2) +parent unless value2 value2 = value1 | value1 = #{value1}, value2 = #{value2} +check(1, 2) これは value1 = 1, value2 = 2 を期待した処理ですが実際には value1 = 1, value2 = 1 と解釈されます なぜならこの処理は以下のようにjsに評価されるからです function anonymous(locals) { var buf = []; var parent_mixin = function() { var block = this.block, attributes = this.attributes || {}, escaped = this.escaped || {}; buf.push("<div>"); block && block(); buf.push("</div>"); }; var check_mixin = function(value1, value2) { var block = this.block, attributes = this.attributes || {}, escaped = this.escaped || {}; parent_mixin.call({ block: function() { if (!value2) { var value2 = value1; // ここに注目 } buf.push("value1 = " + jade.escape((jade.interp = value1) == null ? "" : jade.interp) + ", value2 = " + jade.escape((jade.interp = value2) == null ? "" : jade.interp) + " "); } }); }; check_mixin(1, 2); return buf.join(""); } check_mixin 内の parent_mixin 呼び出し時の block のスコープの中で var value2 = value1 と評価された式があります この block のスコープ内では value2 はスコープチェインを通して check_mixin の引数の value2 を参照したいのにここで var 宣言されたことによって、このスコープ内でhoistingが発生し、一つ上の if (!value2) { の式の value2 が undefined になります そのため、評価されない予定だった var value2 = value1 が評価されてしまう結果になります ちなみに - をつけて以下のように書くと mixin parent() div block mixin check(value1, value2) +parent unless value2 - value2 = value1 | value1 = #{value1}, value2 = #{value2} +check(1, 2) jsに以下のように変換されます function anonymous(locals) { var buf = []; var parent_mixin = function() { var block = this.block, attributes = this.attributes || {}, escaped = this.escaped || {}; buf.push("<div>"); block && block(); buf.push("</div>"); }; var check_mixin = function(value1, value2) { var block = this.block, attributes = this.attributes || {}, escaped = this.escaped || {}; parent_mixin.call({ block: function() { if (!value2) { value2 = value1; //ここに注目 } buf.push("value1 = " + jade.escape((jade.interp = value1) == null ? "" : jade.interp) + ", value2 = " + jade.escape((jade.interp = value2) == null ? "" : jade.interp) + " "); } }); }; check_mixin(1, 2); return buf.join(""); } この場合は value2 = value1; に var がついていないためhoistingが発生せず意図した value1 = 1, value2 = 2 という値が得られます こういった複雑な問題から - 無しで記述される代入構文が削除されます クライアントサイドでのjadeの利用においてIE8以下のサポートがなくなる クライアントサイドでjadeを利用してますっていう声はあまり聞きませんが、サポートがなくなるそうです 古いブラウザに対する狂気じみた対応のせいで全ブラウザでのパフォーマンスが劣化するのにはもうやめだ モダンブラウザこそが真にサポートされるべきなんだ! みたいな感じのようです 株式会社ネクストでは、一緒に世の中をもっと便利に楽しくしたい仲間を募集中です。 主体的に楽しみながら仕事できる方からのエントリーお待ちしています! http://recruit.next-group.jp/
秋山です。 「littleBits」という気軽に電子工作が楽しめるガジェットがあります。 littleBits(リトルビッツ) littleBits は、様々な機能をもったモジュールがあり、それらをつなげることで特定の動作を楽しめるものです。 モジュール同士をつなぐには両端についている磁石でつなぐので非常に簡単ですし、間違った接続をしようとすると磁石が反発しあうので、知識のないお子様でも色々な電子工作ができるようになっています。 今回は少しだけどんなものか紹介します。 こんな箱に入ってきました。 先日、facebookで35%offのクーポンを配布していたので、勢い余ってDelux Kitを購入しました。 すでに持っていた知人からもモジュールは多いほうがいいよ、とアドバイスもらったので、そりゃそうか。多いことはいいことだ。と迷うこと無くDeluxをカートに投下。 海外発送なのですが、注文から3日で届くスピード出荷! さっそく中を開けるとモジュールびっしり。 子供に扱いやすくするためか思ったより小さく、カラフルで見てるだけでワクワクしてきますね。 ということで、眺めていてもしかたがないので軽く動かしてみましょう。 電源は基本的に付属の9V形電池を使用します。 それと、Powerモジュールを接続することで電源供給ができるようになります。 さっそくRGB LEDモジュールを使ってLEDを光らせてみます。 おわかり頂けただろうか… LEDが点灯していることを。 このLEDは今は点灯しっぱなしです。 PowerモジュールとRGB LEDモジュールの間に、Pulseモジュールを挟んでみます。 おー、LEDが点滅し始めました。 簡単ですね。 では次はServo motorモジュールを使って、動くものを作ってみましょう。 RGB LEDモジュールをServo motorモジュールに変えるだけです。 うん、これも簡単。 こんな感じに安心・安全・簡単に電子工作を楽しむことができます。 ダンボールや3Dプリンターなどを使って車を作ったり、ピタゴラスイッチのようなものを作ったり、色々と楽しめそうです。 littleBitsは年末年始、暇をしてるあなたにピッタリなガジェットではないでしょうか。 私はこれで年を越せそうです。 =========================================== 株式会社ネクストでは、一緒に世の中をもっと便利に楽しくしたい仲間を募集中です。 主体的に楽しみながら仕事できる方からのエントリーお待ちしています! http://recruit.next-group.jp/
ネクストにもOculus Riftがやって来ました! Oculus Riftとは http://www.oculusvr.com/ OculusVR社が開発中のバーチャルリアリティヘッドマウントディスプレイです。 6軸ヘッドトラッキング機能がついていて、首を右に向ければ右を見れるし、上を見れば上を見れる。 視野角も非常に広く高い没入感を得られます。 早速なので、Unity上で開発環境を作ってみましょう。 ※Oculus Rift SDKを動かすにはUnityProが必要です。 1.Oculus Riftデベロッパー登録 まずはデベロッパー登録をします。 https://developer.oculusvr.com/ 必要事項を入力し、登録します。 登録にはお金はかからないのでご心配なく。 2.SDKのダウンロード&インポート Unity 4 Pro Integration をダウンロードします。 そのファイル展開すると以下のようになります。 次に、Oculusに対応したいUnityプロジェクトを開き 先ほどダウンロードしたディレクトリの OculusUnityIntegration/OculusUnityIntegration.unitypackage をダブルクリックします。 そうすると、unityへ必要ファイルのインポートが始まります。 3.プロジェクトをOculusに対応 インポートされた OVR の中にある、Prefabs/OVRPlayerControllerをSceneにドロップすれば完了です。 ゲーム画面が2画面に分割されます。 あとは、BuildすればOK!とっても簡単ですね〜。こんなに簡単にVRの環境ができちゃうとは、すごい。 ============================================== 株式会社ネクストでは、一緒に世の中をもっと便利に楽しくしたい仲間を募集中です。 主体的に楽しみながら仕事できる方からのエントリーお待ちしています! http://recruit.next-group.jp/
さて、前回ビルドまで完了したので、今回は早速、データの作成、保存。 そして読み込みをやってみましょう。 CouchbaseLiteは、JSONドキュメントが基本です。 なので、データ自体も連想配列形式で作成します。というわけでNSDictionary形式でデータを作ります。 ViewController.mに以下のコードを追加していきます。 ドキュメント作成 流れ的には以下のようになります。 1.連番を作る ※CouchbaseLiteにはドキュメントを表すユニークなIDを作る機能はありますが、連番を作る機能はありません。 2.新規にのドキュメントを作成する 3.ドキュメントをデータベースにPutする // 新規ドキュメントの作成 - ( void )createDocument{ // Appdelegateを呼ぶ AppDelegate *ap = (AppDelegate *)[[UIApplication sharedApplication] delegate]; // カウントの読み込み NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults]; // カウントが0だったら1にする // ※連番を作る機能がないので、ここで作成する int num = [userDefault integerForKey:NUMBER_KEY]; if (num == 0 ) { num = 1 ; } // カウント文字列の作成 NSString *numberStr = [NSString stringWithFormat: @" %d " ,num]; // ドキュメントを追加 NSDictionary *contents = @{ @"text" : numberStr, @"check" : [NSNumber numberWithBool:NO], @"created_at" : [CBLJSON JSONObjectWithDate: [NSDate date]]}; // 無記名ドキュメントの取得 CBLDocument* doc = [ap.database untitledDocument]; // ドキュメントの追加 NSError* error; if (![doc putProperties: contents error: &error]){ // 失敗したらアラートを表示 [ self showErrorAlert: @"Couldn't save the new item" ]; } else { // 成功したらカウントを上げる NSLog( @"Save Complete!" ); + +num; // ユーザデフォルトのに保存 [userDefault setInteger:num forKey:NUMBER_KEY]; [userDefault synchronize]; } } // 失敗時のアラート表示 - ( void )showErrorAlert:(NSString *)message{ UIAlertView *alert = [[UIAlertView alloc] initWithTitle: @"Error" message:message delegate: nil cancelButtonTitle: @"OK" otherButtonTitles: nil , nil ]; [alert show]; } CBLDocument: ひとつのデータを指します。一枚のJSONと考えて貰えれば一番わかりやすいかと。 ドキュメントそれ自体ではあるが、自身の保存、更新、削除機能もこのオブジェクトに入っています。 ここで注意する点は、databaseを使ってカラのドキュメントを作成する点です。 普通に考えると、CBLDocumentをnewすればいいんじゃ?となりますが、CBLDocumentそれ自体がPutする機能を持っておりかつ、CBLDocumentのdatabaseプロパティはReadOnlyなので後からセットすることができません。 なので、databaseと関連付けるためにdatabaseを使ってCBLDocumentを作成するというわけです。 余談:はじめDocument作って、Databaseに渡すという構図を想像してたのでチョビっとハマりました。 ドキュメントの読み込み そして次に、読み込みをしてみます。 コードは以下のようになります。 1.データを保管するArrayを作成 2.すべてのデータを読み込むQueryを作成 3.Arrayに取得したドキュメントを追加 @implementation ViewController { NSMutableArray *dataArray; //CBLデータを格納するArray } - ( void )viewDidLoad { [ super viewDidLoad]; // 格納配列の初期化 dataArray = [[NSMutableArray alloc] init]; //Documentを作成 [ self createDocument]; // すべてのDocumentを読み出す [ self loadAllDocuments]; } - ( void )loadAllDocuments{ AppDelegate *ap = ApplicationDelegate; // ArrayをClear [dataArray removeAllObjects]; // すべてのクエリを読み込む CBLQuery *allQuary = [ap.database queryAllDocuments]; for (CBLQueryRow* row in allQuary.rows) { // document取得 CBLDocument* doc = [ap.database documentWithID: row.key]; NSDictionary* contents = doc.properties; // data 追加 [dataArray addObject:contents]; } // 時間順に並び替えをする NSSortDescriptor *sortDispNo = [[NSSortDescriptor alloc] initWithKey: @"created_at" ascending:NO]; NSArray *sortDescArray = [NSArray arrayWithObjects:sortDispNo, nil ]; [dataArray setArray:[dataArray sortedArrayUsingDescriptors:sortDescArray]]; NSLog( @" %@ " , dataArray); } CBLQuery CouchbaseLiteを操作するQueryオブジェクト。 データベースで言うと、このオブジェクトにSQLを渡せばその結果がこのオブジェクト内に生成されます。 後に出てくるView機能などもこのCBLQueryを利用します。 ここでは、予め実装されている全ドキュメントを呼び出すクエリ「queryAllDocuments」を使って、全ドキュメントを取得するCBLQueryを作成しています。 CBLQueryRow CBLQuery内には、rowsというプロパティ内にクエリの結果が生成されておりその中のエンティティ的な立ち位置。 これらを実行すると、コンソールに今データベースに入っているドキュメントデータが表示されます。 起動時に1度しか追加していないので、1個しか出ないかと思います。 たくさん表示したい場合は何度か起動するか、for文でも作って回して貰えれば。 ここまでくれば、データはNSDictionaryが入ったArrayになっています。 Arrayに入っちゃえばもうこっちのもん!好き勝手利用できるようになります。やったね! では今日はこれくらいで、次回には削除、更新をしようと思います。
株式会社ネクストの花多山です。 前回の記事 海外研修 北欧に行ってきたよ - 株式会社ネクスト エンジニアBlog で 社内制度のひとつである「選抜海外研修」について触れましたが、 今回は現在開催中の制度である「クリエイターの日」について紹介したいと思います。 このクリエイターの日とは何かと言いますと、 クリエイター(エンジニア、デザイナー、プランナー等)が通常業務の枠を離れて、新たな技術やサービスの探求に取り組むことができる制度です。 希望者は四半期ごとに最大で7日間(年間合計で最大28日)合宿形式で研究・開発を行います。 某企業の20%ルールのネクスト版と言ったら分かりやすいでしょうか。 これまでクリエイターの日から生み出されたプロダクト(といっても一部になりますが)は、以下のサイトからご覧いただけます。 クリエイターの日 ただいま、第3四半期(10月~12月)の合宿期間中で、今回は11チーム(約30名)が鋭意活動中です。 活動中の風景をいくつか紹介してみましょう。 Node.jsチーム。ただいまリーダーW君(新卒2年目)の説教タイム中。 UI・UXにこだわったiPhoneアプリを開発中のようです。 黙々と作業をしておられます。 ただいま、Couchbase Liteの調査中とのことです。 お絵かきをしてますね。いったい何ができるんでしょうか? とまあ、各チーム自由なスタイルで最大7日間の合宿活動を頑張っております。 この後は、12月に社内で成果報告会を実施する予定で、どんな発表があるのか、今から楽しみにしています。