TECH PLAY

株式会社LIFULL

株式会社LIFULL の技術ブログ

660

突然ですがOrigami原理主義者狂喜乱舞のニュースがあったので取り急ぎ報告です。 IDEO 有名ですよね。「デザインといえばIDEO」とは言いすぎでしょうか。しかしそれくらい頻繁に引用されるのも事実です。 先日そのIDEOが彼らが「開発」したインタラクションデザインツール Avocado を公開しました。 Does your brain hurt looking at this? Mine did, too. Building the iOS Keyboard patch kept me up all night, requiring me to jump back and forth between Quartz Composer and Xcode. via: Neat Effects, No Code Required | IDEO Labs 画面をみて「あれ?これQuartz Composerじゃないか?」と思った方。あなたは鋭い。このAvocadoというのは彼らの言葉を借りれば AvocadoはOrigamiの上で動き、さらにいくつか便利なパッチを追加したものだ ということになります。FAQによれば、AvocadoはOrigamiを含んでいるので、AvocadoをインストールすればOrigamiも自動的にインストールされる。 じゃあ何が新たに可能になったか、ですが一番わかり易いのがCarousel 写真を並べて、スワイプで一枚ずつ送る。良く使いますよね。もちろんOrigamiをつかってがんばれば可能なのですが、Carouselパッチを使えばこんだけです。 いや素晴らしい。素晴らしいですよね?ね?(うざry) ーーー というわけで、Avocadoを試すやり方です。ちょっとわかりづらいと感じたのは私だけなのだろうか。。 1)まず このページ を参照して、Quartz Composerのインストールまで行う。OrigamiはAvocadoをインストールすると自動的に入る(らしい)のでここでインストールしなくてもいいです。 2)iii. Download and install Avocado  ←のリンクをクリック。するとAvocadoのパッケージがダウンロードされる。 自動的にzipが解凍されてできたAvocado.mpkgをダブルクリックするとインストーラーが立ち上がり、Avocadoがインストールされます。 3)とりあえずExampleを動かしたいですよね?ね?(ウry) このページ のDownload Zipをクリックしてまるごとダウンロードしましょう。でもってその中のExamplesフォルダを見るとあれこれ入っています。先ほどのCarouselやものすごい力作の「キーボード」がはいってます。 ーーー というわけで、これを使えばいろいろなことがもっと簡単になるのかな、、と思いつつあれこれ触っている今日この頃。私が何をそんなに喜んでいるかといえば、デザイン分野で確固たる地位を築いているIDEOがQuartz Composerを(少なくとも選択肢の一つとして)選択し、ソフトウェアを公開してきたこと。Quartz Composer自体いつサポートされなくなってもおかしくないような状況だったわけですが、これで少しは安心して使えるかな、、とか言っているそばからOS X Yosemiteでサポートされなくなったら発狂するわけですが。
Apple原理主義者の大坪です。例によって先日見つけた文章を和訳しつつあれこれ書きたいと思います。題名は" Design is About Intent "-「デザインとは意図のことである」 この文章中の主張についてはおそらく様々な意見があると思いますが、私は読んでいる最中に3度は大笑いしたことを申し添えておきます。 - - - - - - - 有名で敬意を払われている企業にはそれぞれのコア・バリューがあります。この文章によればToyotaのそれは生産システムであり、GEはシックス・シグマで有名です。ではAppleのコア・バリューは何かと問われれば Apple is about  design . via: Rampant Innovation | John R. Moran on strategy and innovation Appleはデザインの会社だ。 「デザイン」。昨今デザイン思考とかd.SchoolとかIDEOとかが語られ、ともすれば With the worthy aim of making design accessible to the rest of us, they’ve broken down “design thinking” into  step-by-step frameworks , which generally involve empathetic understanding, creative ideation, and experimental prototyping. via: Rampant Innovation | John R. Moran on strategy and innovation だいぶ意訳:デザインを普通の人にも使えるようにするため、デザイン思考はステップ・バイ・ステップのフレームワークとして定義された。多くの場合ユーザの感情の理解、創造的なアイディア出し、それにプロトタイピングが含まれる。 個人的な意見ですが、こうした「デザインプロセス」について読む度、何かが決定的に欠けている、と思うことが多い。この文章も次にそうした点について述べます。 But I fear that “design” has moved too quickly to the tools and techniques stage - the “how,” instead of the “what.” via: Rampant Innovation | John R. Moran on strategy and innovation デザインがあまりにも早くツールやテクニックになってしまっているのではないかと危惧している。「What:何を」ではなく「How:どうやって」になっていないか。 ではこの文章の著者が考える「デザイン」とは何なのか?それは Intent:意図 であると主張します。なんだそんなことは当たり前ではないか、と言うことは簡単ですが難しいのはその意図を細部にまで徹底させること。Appleがその点で徹底していることを示すエピソードが2つ挙げられていて、ひとつはDesign担当のVP Jonathan Iveについて “he’s known to use ‘arbitrary’ as a term of abuse.” 彼にとって「任意の」という言葉は悪態と同じだ もう一つは故Steve Jobsのもので彼の妻によれば “We spent a lot of time asking ourselves, ‘What is the purpose of a sofa?’” via: Rampant Innovation | John R. Moran on strategy and innovation 私達は「ソファーはなぜ必要なんだろう?」と長い間議論したものです 別の言葉で言えば、「なぜ製品のこの部分はこうなっているのか?」と聞かれた時に「なんとなく」という言葉はありえず、「それはこういう理由からです」と即座に返答ができなければならない。 こういう文章を読むと日々「なーんでもいいんじゃなーい」と言っている私などは果たしてApple原理主義者と名乗る資格があるのか不安になってくるわけですが気にせず先に進みます。 この文章では次に「3つのデザイン上でのごまかし」が取り上げられます。それはなんなのか。 The first evasion: Preserving:現状維持 「デザイン」する上での判断を避けるもっとも良い方法は、そもそも疑問を持たないこと。「車輪の再発明をするな」というのは多くの場合有効な言葉ですが、新しい物を殺すという点でも有効。この文章では「Microsoft Surfaceや新しいBlackberryに物理的キーボードが付いている」ことがその例として挙げられていますが、これに関しては異論を述べたい人も多いでしょう。 この文章の主張を私なりに解釈すれば、 「タブレットには絶対キーボードが必要なんだ」 ではなく 「今のPCにはキーボードがあるから、タブレットにもキーボードをつけよう」 と考えるのがよくない、ということなのかなと。非常に微妙な線ではありますが。 さて2番めは The second evasion: Copying:コピー この点に関しては、最近サムソンがやり玉にあげられることが多い。こんな サイト まであるほどです。私のような年代の人間だと 「そうだよなあ。コピーばかりで独創性がない、って言葉は一昔前に日本企業に向けられていたけど、最近はもう非難すらしてもらえないのか」 と寂しくなりますが、それはそれ。 Appleも時としてコピーすることが知られていますし、そもそもMacintoshのGUIだってXeroxのPalo Alto研究所から、と言いたい人もいるでしょう。それに対するこの文章の答えは The difference is that Apple seems biased to design based on its own intent first, and copy second; its rivals tend to copy first. via: Rampant Innovation | John R. Moran on strategy and innovation Appleが他の企業と異なるのは、自らの意図に従ってデザインすることが第一で、コピーが2番目になっていること。競合企業はコピーすることを第一にしている。 Apple原理主義者の意見ですが、Appleはコピーした特徴であってもApple製品の一部として消化して出してくる、と思っています。 さて3番めは The third evasion: Delegating:他人まかせ Delegateという言葉は「権限移譲」とかいう意味。なんだそれはと思われるかもしれませんが、具体例を挙げたほうがわかりやすい。この文章では3つのカテゴリーに分けられており A) Offering a wide range of product choice:幅広い製品バリエーション サムソンが非常に多くの種類のスマホ、タブレットを作っていることは時々揶揄の対象になります。この文章の言葉で言えば"spray and pray" - 撒き散らしてあたるように祈る-とでもいいましょうか。 もちろんそれを意図的にやる、という方針もあるのでしょうが設計上の判断を避ける良い方法とも言えます。 もう一つ例として挙げられているのが再びMicrosoftのSurface。Windows RT+ARM CPUを搭載したSurfaceとWindows+Intel CPUを搭載したSurface Pro。どちらが当たるかわからない時は「幅広いユーザニーズに応えるため」両方の選択肢を提供する、というのもひとつの理屈でしょう。しかしコンシューマーからみれば「で何が違うの?」と混乱するだけ。 挙げられている例えが面白いので訳します。 As an analogy, giving someone birthday money instead of taking the time to choose a gift seems eminently logical - why limit the recipient’s choices? But the gifts we remember most fondly are seldom checks. via: Rampant Innovation | John R. Moran on strategy and innovation たとえだが、誕生日プレゼントに時間をかけて何かを選ぶのではなく、お金をあげるのは論理的な方法だ。なぜ受け取る側の選択肢を狭めてしまうのか?しかしお金(原文:チェック-小切手)が「印象に残ったプレゼント」であることは滅多にない B) Trying to offer an omni-functional product:なんでもできる製品 特定の用途を念頭に、それをすばらしく上手に行える製品を作るのではなく、「誰が何をするときも役に立つ」製品をつくること。挙げられている例のうちわかりやすいのが、(三度目ですが)Microsoft Surface。 ラップトップPCでもある。Tabletとしても使える。どちらのユーザにも対応できる製品であり、文字面で聞くと非常によく思える。 Surface Pro3の発表 でもその点をしきりに強調していました。96%のiPad所有者はラップトップも買っている。なぜ2つ必要なんだ?Surfaceなら一つでOK。自分が何を買いたいか迷った時も、Surfaceを買えば間違いない。 私の左脳は「これは実に見事なロジックだ」と理解している。誰もがなんでもできる製品、という言葉にこれほどふさわしいものはない。 しかし現実を見ましょう。彼らはまだ市場で成功しているとは言えない。(未来のことはわかりませんが)なぜ売れないのか? 我々の頭のなかには「機能が増えることはいいことだ」という固定概念が存在しています。"Less is more"と字面でわかったような気になってもなかなか勇気をもって削ることはできない。あれもできる、これもできる。それと引き換えにシステムは複雑になり、どちらの用途にも中途半端になる。 勇気を持って「それを削り、こちらにフォーカスしよう」という決断こそが「デザイン」のコアである「意図」。 これは私見ですが、タブレット用の全画面UIと、従来のPC用のデスクトップ画面を「妥協無く共存」させたWindows8のUIもこうした観点から見ることもできるかもしれません。 さて、おそらくもっとも議論を呼ぶであろう3点目。 C) Deciding based on user testing:ユーザテストで判断する この点においては、IT業界の巨人達とAppleは極端な違いを見せています。A/BテストはWebサービスにおいて広く用いられており、有用だ、とこの文章は述べます。しかし 「それはデザインではない」 とも。 この文章によればGoogle/Facebook/Amazon 3社ともが「主観ではなくデータ、ユーザテストの結果で判断する」と述べているとのこと。しかしながら特にGoogleとAppleの間で顕著ですが、NexusのデザインがiPhone/iPadのデザインより優れている、という意見はあまり聞いたことがない。 それであれば、「ユーザテストを元に決断する」という方法が「他人まかせ」の一つの形態になってはいないか、という議論もなりたつのではないか。 この点を考える時いつも私の頭に浮かぶのは、ある雑誌でみた4コマ漫画です。年配の教授が「長期にわたるテストと解析の結果、A案のほうがB案より優位に良いことが判明した」と研究成果を述べている。それに対して学生が次のように質問する。 「えーっとどうやって言えばいいかな。もし両方共ゴミだったとしたら?」 A案とB案を比較することはデータで議論できる。しかしそもそも「優れた案」はデータから産む事ができるものでしょうか? - - - - - - - この文章は「Appleの製品はデザインが優れている」という観点で書かれています。しかしながらサーバーサイド主体のサービスになると、私のような狂信的Apple原理主義者でも首を傾げざるをえないことが多い。iCloudはそもそもどうやって使う物なのか。Googleのような有用なサービスをなぜAppleは「デザイン」することができないのか。 しかし「手に取って触る製品」になるとそうした関係は逆転します。この「差異」については未だに結論が得られません。 ユーザがインターネットに触る場所がPCからモバイルに移るにつれ、「手に取って触る製品」のインタフェースの重要性が増してきている。それではサーバーを活用したサービス+手に取る製品のデザインはどのような形で行うべきなのか。この答えはまだでていないように思います。
Origami原理主義者の大坪です。Origamiの存在を知り、取り乱した挙句サンプルなど公開し始めたけど誰も見てくれないんだろうなあ、と思っていたのですが。 ちゃんと読んでくれる人がいたどころかリクエストまでいただき嬉しい限りなわけです。というわけで今回はそのリクエストを原型にした「ボタンを押すと横からメニューがでてきて、背景画像がすりガラスになる」をやります。 今回の完成形はこれです。 右下にわざとらしく存在している"Side Menu"というボタンを押すと横からメニューが出てくる。それとともに背景画像が「すりガラス」を通したようになる。 ここで背景画像をタップするとメニューが消え、すりガラス効果がなくなる。 しかしなんですね。こうやってオリジナルの「課題」を作ると自分にかっこいい画面を作る能力がないことに悲しくなります。しかしこれはあくまでも"Simple Example"。重要なのはOrigamiでどう動きを構築するかであって、画面のデザインじゃない。だから誰も気にしませんよね?ね?ね?(ウザい) というわけで、 第一回目の記事 を参考にして、下の図までつくりましょう。ここからRender in Imageパッチの中身を作っていきます。Render in Imageの下のほうをダブルクリックして中にはいりましょう。 まずあれこれ配置 Github からファイルをダウンロードし、assetsというフォルダの中を見る。background.jpg,sideMenu.pngという2つのファイルがはいっています。これを1つずつEditorの画面にドラッグ&ドロップします。ImageパッチとそれにつながったLayerパッチがそれぞれ追加されるはずです。ついでにPatch LibraryからClearを追加します。Clearパッチの右上の数字を1に、backgroundにつながったLayerパッチの右上の数字を2,sideMenuにつながったLayerパッチの右上の数字を3にしましょう。するとこんな感じになります。 なんとなく表示されていますが、サイドからでてくるはずのメニューの位置が絶望的にずれています。まずこれを直しましょう。 sideMenuがつながったLayerパッチを選択し、Patch Inspectorを開きます。ここで先日フェンリル株式会社で行われた Origamiの講習 で教わった技を使ってみます。Anchor PointというメニューがCenterになっていると思いますが、これをTop Leftにする。するとSideMenuの左上が、iPhone画面の左上になります。これは楽ですね。 というわけで、背景画像の上にメニューが表示された状態になりました。例によって「ここまで長い道のりだった」と感慨にふけることは可能ですが、まだ何も動いていないことを思い出しましょう。先は長いのです。 メニューを出したり引っ込めたり というわけでまずボタンを配置しましょう。Patch LibraryからButtonを探してEditorに追加します。Patch Inspectorを使ってあれこれパラメータを設定してください。多分誰がやっても私ほどひどいデザインにはならないと思うので、大丈夫です。(何が) Anchor PointをBottom Rightに設定すると、細かい数字をいじらなくても画面右下に配置されるのが便利です。 さて、ここから動かすための仕組みを作っていきます。これから書くのはひとつの「パターン」になっていて、今までもでてきたしこれからも出てくるので「パターン」を意識しながらつないでください。 Interaction2パッチを追加して、右上の◯からButtonという文字の左にある◯につなぐ Switchパッチを追加し、Interaction2のClickからSwitchのTurn Onにつなぐ(ボタンを押した時は、メニューがでるだけなので、こうします) Classic Animationsパッチを追加し、SwitchパッチのOn/OffからNumberにつなぐ Transitionパッチを追加し、Classic AnimationsパッチのProgressからTransitionのProgressにつなぐ TransitionパッチのValueをsideMenuがつながっているLayerのX Positionにつなぐ。 ここで 青いパッチ(Layer,Buttonなど)→Interaction2→Switch→Animation(ClassicだったりBouncyだったり)→Transition というのがここで言うパターンで、「何かを押すと、何かが変わる」という汎用的な動作を実現するのに使えます。 次にパラメータを設定します。 TransitionパッチのStart Valueを-362に、End Valueを0に設定する。 今回使うメニュー画像の幅が362なので、初期状態では画面の外にでておいてもらって、End Valueになったところで中にはいってもらえればよいわけです。 この段階でボタンを押すとメニューがにゅいっとでてきます。わーいと思いますが次の瞬間何をしても引っ込まないことに気がつくでしょう。なぜかといえば、ボタンにつながったInteraction2パッチの出力は、SwitchのTurn Onだけにつながっており、Offにできない。というわけで、もうひと息がんばり「背景画像を押したらメニューが引っ込む処理」を作りましょう。 Interaction2パッチをもう一つ追加し、右上の丸から背景画像がつながったLayerパッチの左上の丸につなぐ 新しく追加したInteraction2パッチのClickからSwitchパッチのTurn Offにつなぐ ここまでやるとこんな風になるはずです。 というわけでViewerを開き、ボタンを押しましょう。メニューがにゅいっとでる。背景画像を押すとメニューが引っ込む。何度かやっているとじわっと喜びがこみ上げてきますよね?ね?ね?(ウザry) すりガラスにしたり戻したり というわけで残った処理「すりガラスにしたり戻したり」を作りましょう。まず「とにかくすりガラス」処理を作ります。 Patch Libraryから"Gaussian Blur"というパッチを追加します 追加したGaussian BlurパッチをBackgroundイメージとLayerの間に入れます。Bacground ImageのimageをGaussian Blurの左側のimageに、Gaussian Blurの右側のimageからLayerのimageにつなぎます こんな感じになります。 Viewerをみてみると、背景画像がすりガラスのようになっていることがわかります。Gaussian Blurパッチを選んだ状態でPatch Inspectorを開き、Radiusを変化させてみましょう。0の時には元の画像が表示され、Radiusを増やすにつれボケが強くなっていくことがわかると思います。 というわけでやることはSide menuがでているときはこのRadiusの値をたとえば10にして、引っ込んでいる時は0にする、ということになります。ということは、Side menuがでるでない、とトリガーは同じで、値の範囲を変えるところだけ別にすればよい、ということになります。 というわけで Transitionパッチをもう一つ追加 Classic AnimationのProgressを追加したTransitionパッチのProgressにつなぐ TransitionパッチのValueをGaussian BlurのRadiusにつなぐ TransitionパッチのStart Valueを0に、End Valueを30にする(この値は適当) これが今回の完成形です。 Viewerを開いて、ボタンを押したり背景画像をおしたりしてみましょう。私の環境だと多少処理がひっかかりますが、背景画像がぼやけたりメニューが動いたりします。ここまで来ればあなたの頭からはSide menuの画像が「いかがなものか」という出来である事実などは抜け落ちているはずです。 というわけでOrigamiの例その3でした。ここからFacebook paperのプロトを作るまでの道のりははるか遠く思わず気を失いそうになりますが、それは考えないことにします。 今回のファイルは Github に置きました。
紹介 株式会社ネクスト 金融グループでシステムエンジニアとして勤務している金成奉です。 近年多くの企業が、POI (Point of Interest、位置情報) やGIS関連データ(区画ポリゴン、道路のラインなど)を扱うようになりました。 GIS関連データを扱う際、システムエンジニアが最初に接するのが、空間データベースです。 何年か前からGIS関連オープンソースは、UbuntuOSに最適化され、世界の開発者達もUbuntuOSを利用する傾向が強くなり、日本の企業で一番多く使われているCentOSでは、コンパイル構築すら難しくなりました。 そのため、CentOSでオープンソースを利用して空間データベースを構築する方法を簡単に紹介致します。 最新バージョンのCentOS及びオープンソースを利用して、PostGIS及びpgRouting(ルート検索機能)を構築します。 構築概要 CentOSがインストールされているVPSまた実機での構築となります。 用途としては空間データベース専用マシーンを前提としています。 コンパイルの設定オプションは、「--prefix=/usr」としているため、「/usr/local」などのディレクトリにインストールする際は、オプションを適宜変更してください。 Linuxバージョン確認 #Linuxバージョン確認 cat /proc/version Linux version 2.6.32-431.3.1.el6.x86_64 (mockbuild@c6b10.bsys.dev.centos.org) (gcc version 4.4.7 20120313 (Red Hat 4.4.7-4) (GCC) ) #1 SMP Fri Jan 3 21:39:27 UTC 2014 OSバージョンの確認 #OSバージョン確認 cat /etc/redhat-release CentOS release 6.5 (Final) ユーザー確認 cat /etc/passwd useradd potgres OpenSSLバージョン(HeartBleedセキュリティ確認) openssl version OpenSSL 1.0.1e-fips 11 Feb 2013 以下のバージョンであれば、安全(最後が5.7以上) openssl.x86_64 1.0.1e-16.el6_5.7 基本アップデート実行 #アップデートを行い、OSを最新の状態にする。 yum install yum-fastestmirror #アップデートパッケージをチェックする #すべてアップデートするか、チェックしたリストを選んで個別にアップデートする。 yum check-update #構わずアップデートを行う。 yum update コンパイル環境構築 #基本コンパイル環境インストール yum -y install autoconf yum -y install automake yum -y install libtool.x86_64 yum -y install flex.x86_64 yum -y install bison.x86_64 yum -y install gcc.x86_64 yum -y install gcc-c++.x86_64 yum -y install make.x86_64 yum -y install kernel-headers.x86_64 yum -y install kernel-devel.x86_64 #最新GISサポートPostgreSQL-9.3.4コンパイル環境構築 yum -y install subversion.x86_64 yum -y install libxml2-devel.x86_64 yum -y install json-c-devel.x86_64 yum -y install openssl-devel.x86_64 yum -y install readline-devel.x86_64 yum -y install zlib-devel.x86_64 yum -y install expat-devel.x86_64 yum -y install libcurl-devel.x86_64 yum -y install xerces-c-devel.x86_64 yum -y install unixODBC-devel.x86_64 yum -y install sqlite-devel.x86_64 yum -y install libspatialite-devel.x86_64 yum -y install libspatialite.x86_64 yum -y install openjpeg-devel.x86_64 yum -y install openjpeg-libs.x86_64 yum -y install pcre-devel.x86_64 yum -y install ocaml-csv-devel.x86_64 yum -y install geos-devel.x86_64 yum -y install pam-devel.x86_64 yum -y install uuid-devel.x86_64 yum -y install python-devel.x86_64 yum -y install perl-devel.x86_64 yum -y install tcl.x86_64 yum -y install tcl-devel.x86_64 yum -y install cmake yum -y install cmake28.x86_64 yum -y install CUnit-devel.x86_64 yum -y install libtiff-devel.x86_64 yum -y install libjpeg-turbo-devel.x86_64 yum -y install hdf-devel.x86_64 yum -y install hdf5-devel.x86_64 yum -y install netcdf-devel.x86_64 yum -y install jasper-devel.x86_64 yum -y install nas-devel.x86_64 yum -y install gsl-devel.x86_64 yum -y install libdap.x86_64 yum -y install proj.x86_64 yum -y install proj-devel.x86_64 yum -y install proj-epsg.x86_64 yum -y install proj-nad.x86_64 yum -y install proj-static.x86_64 yum -y install ogdi-devel.x86_64 yum -y install boost.x86_64 yum -y install boost-math.x86_64 yum -y install boost-devel.x86_64 yum -y install gmp-devel.x86_64 yum -y install mpfr-devel.x86_64 yum -y install qt-devel.x86_64 yum -y install qt3-devel.x86_64 yum -y install gtk+-devel.x86_64 コンパイルインストール #PostgreSQL-9.3.4コンパイル・インストール #PostgreSQLはroot権限で実行できないため、以下のユーザーを追加する #make時はオプション「-j6」を指定して並列でコンパイルする。 #重要:PostgreSQLのバックエンドやファンクションの多くがC++言語で書かれているため、 # 安定運用のためにはstdc++ラブラリーをリンクして原因不明のトラブルを回避する。 wget http://ftp.postgresql.org/pub/source/v9.3.4/postgresql-9.3.4.tar.gz tar zxvf postgresql-9.3.4.tar.gz cd postgresql-9.3.4 LDFLAGS=-lstdc++ ./configure --prefix=/usr --libdir='${prefix}/lib64' make -j8 world make install-world cd .. #libgeotiff コンパイルインストール wget http://download.osgeo.org/geotiff/libgeotiff/libgeotiff-1.4.0.tar.gz tar xvfz libgeotiff-1.4.0.tar.gz cd libgeotiff-1.4.0 ./configure --prefix=/usr --libdir='${prefix}/lib64' --with-zlib=/usr --with-jpeg=/usr --enable-incode-epsg make -j8 make install cd .. #計算幾何(Computational Geometry Algorithms Library)ライブラリー #CGALのコンパイル・インストール wget https://gforge.inria.fr/frs/download.php/33525/CGAL-4.4.tar.gz tar zxvf CGAL-4.4.tar.gz cd CGAL-4.4 #★★以下修正注意★★ #ヘッダー修正ファイル:include/CGAL/Mpzf.h #57行目に以下の定義を追加して保存する。 vi include/CGAL/Mpzf.h #ifndef mpn_sqr #define mpn_sqr(dest,a,n) mpn_mul_n(dest,a,a,n) #endif #インストールライブラリーのディレクトリを変更してからcmakeを実行する #ライブラリーのインストール先の「/usr/lib」から「/usr/lib64」に変更する。 #cmake28バージョンを使う場合もあるため注意する。 sed -i -e "s|CGAL_INSTALL_LIB_DIR \"lib\"|CGAL_INSTALL_LIB_DIR \"lib64\"|g" CMakeLists.txt cmake -DBOOST_ROOT=/usr \ -DCMAKE_BUILD_TYPE=Release -DBOOST_LIBRARYDIR=/usr/lib64 \ -DWITH_GMP=y -DGMP_INCLUDE_DIR=/usr/include -DGMP_LIBRARIES_DIR=/usr/lib64 \ -DMPFR_INCLUDE_DIR=/usr/include -DMPFR_LIBRARIES_DIR=/usr/lib64 \ -DCMAKE_INSTALL_PREFIX=/usr . make -j8 make install cd .. #遺伝的アルゴリズム(genetic algorithm) #GAUL コンパイル・インストール wget http://sourceforge.net/projects/gaul/files/gaul-devel/0.1850-0/gaul-devel-0.1850-0.tar.gz tar zxvf gaul-devel-0.1850-0.tar.gz cd gaul-devel-0.1850-0 ./configure --prefix=/usr --libdir='${prefix}/lib64' --enable-slang=no make -j8 make install cd .. #GoogleのKMLサーポートライブラリーコンパイル・インストール #--disable-swigに設定して他言語のライブラリーを無効にする。必要な場合は、JDKなどを先にインストールする。 svn checkout http://libkml.googlecode.com/svn/trunk/ libkml-1.3.0 cd libkml-1.3.0 ./autogen.sh ./configure --prefix=/usr --libdir='${prefix}/lib64' --disable-swig make -j8 make install cd .. #GDAL(Geospatial Data Abstraction Library) のコンパイル・インストール wget http://download.osgeo.org/gdal/1.10.1/gdal-1.10.1.tar.gz tar zxvf gdal-1.10.1.tar.gz cd gdal-1.10.1 ./configure --prefix=/usr --libdir='${prefix}/lib64' make -j8 make install cd .. #CGALラッパー(SFCGAL)インストール(PostGIS) #バックグラウンドで3Dデータをハンドリングする際に使われるが、必要ソフトが #CentOS-6.5にはインストールされているGCCやBOOSTバージョンとは合わないため、 #コンパイルができない。自力でGCCとBOOSTをコンパイル・インストールする場合、 #以下の方法でコンパイルし、ライブラリーをPostGISに組み込む。 #wget https://github.com/Oslandia/SFCGAL/archive/v1.0.4.tar.gz #mv v1.0.4.tar.gz SFCGAL-1.0.4.tar.gz #tar xvf SFCGAL-v1.0.4.tar.gz #cmake28 -DCMAKE_INSTALL_PREFIX=/usr . # #cmake28 -DBOOST_ROOT=/usr \ # -DCMAKE_BUILD_TYPE=Release -DBOOST_LIBRARYDIR=/usr/lib64 \ # -DWITH_GMP=y -DGMP_INCLUDE_DIR=/usr/include -DGMP_LIBRARIES_DIR=/usr/lib64 \ # -DMPFR_INCLUDE_DIR=/usr/include -DMPFR_LIBRARIES_DIR=/usr/lib64 \ # -DCMAKE_INSTALL_PREFIX=/usr . #PostGIS2コンパイルインストール wget http://download.osgeo.org/postgis/source/postgis-2.1.2.tar.gz tar zxvf postgis-2.1.2.tar.gz cd postgis-2.1.2 ./configure --prefix=/usr --libdir='${prefix}/lib64' make -j8 make install cd ../ #pgRoutin-2.0.0コンパイルインストール wget https://github.com/pgRouting/pgrouting/archive/v2.0.0.tar.gz mv v2.0.0.tar.gz pgrouting-2.0.0.tar.gz tar zxvf pgrouting-2.0.0.tar.gz cd pgrouting-2.0.0 mkdir build cd build cmake28 -DWITH_DD=ON -DBoost_NO_BOOST_CMAKE=ON .. make -j8 make install cd ../../ DB設定 #postgresユーザがなければ追加する useradd postgres mkdir -p /var/pgsql/data chown -R postgres:postgres /var/pgsql/ #DBの初期化 #--encoding:DBのデフォルト文字エンコーディング設定オプション。UTF-8指定 #--no-locale:--no-localeは--locale=Cと同じ意味。Cロケール以外の設定では性能に影響が出る場合がある。 su postgres -c'/usr/bin/initdb --encoding=UTF-8 --no-locale -D /var/pgsql/data' #サービスに追加し、サービスとして運用する。 cp postgresql-9.3.4/contrib/start-scripts/linux /etc/init.d/postgres #ファイルを開きディレクトリに合わせて修正 vi /etc/init.d/postgres prefix=/usr PGDATA="/var/pgsql/data" #実行権限設定 chmod 700 /etc/init.d/postgres #サービスに登録 chkconfig postgres on #DB起動 #/etc/init.d/postgres start #サービス起動 service postgres start GIS テンプレート作成 #PostGISテンプレートDB作成(PostgreSQL-9.3.4での「postgis/pgrouting」サポート) su postgres createdb -U postgres -T template0 -E UTF-8 template_gis psql -d template_gis -c "CREATE EXTENSION postgis;" psql -d template_gis -c "CREATE EXTENSION postgis_topology;" psql -d template_gis -c "CREATE EXTENSION fuzzystrmatch;" psql -d template_gis -c "CREATE EXTENSION postgis_tiger_geocoder;" psql -d template_gis -c "CREATE EXTENSION pgrouting;" #GISサーポートデータベース作成 createdb -U postgres -T template_gis -E UTF-8 testgis pgbench(DBベンチマーク) #以下のオプションで初期化し一般性能を確認する。 #チューニングを行わない状態で確認後、調整しする。 #スケーリングファクター[-s]単位:10万件 #100万件のデータ[-s 10]検証 #10万件当たり15MBディスク容量 pgbench -i -s 10 testgis #条件を指定してベンチマーク #検索処理のみ実行する #同時に接続するクライアント数は10 #1クライアントあたりのトランザクション数は100 #読み込みのみのオプションでテスト pgbench -S -c 10 -t 100 testgis #結果サンプル starting vacuum...end. transaction type: SELECT only scaling factor: 10 query mode: simple number of clients: 10 number of threads: 1 number of transactions per client: 100 number of transactions actually processed: 1000/1000 tps = 13445.739717 (including connections establishing) tps = 19127.041812 (excluding connections establishing) PostgreSQLの自動チューニング設定スクリプト #注意:以下のスクリプトは、上記の方法でインストールした場合のみです。 #他で使用する場合は適宜変更してご使用ください。 #読み込みが圧倒的に多い場合は、「web」オプションを選択すると性能が向上します。 sh pgsql_autoconf.sh web vi pgsql_autoconf.sh #!/bin/sh # pgsql_autoconf.sh: # # This script automatically detects system RAM and other resources # and modifies $PG_DATA_DIR/postgresql.conf to configure the server # for one of three uses: web, oltp, or data warehousing. # # Author: rocket357@users.sourceforge.net # License: BSD # # このスクリプトは以下のスライド発表の際に使われたようです: # http://www.slideshare.net/oscon2007/performance-whack-a-mole # # 以下の内容は上のURLを参考に作成されました。 # "What Color Is My Application" の部分です。 # # web = web application backend # 1) DB smaller than RAM # 2) 90% or more simple read queries # oltp = online transaction processing # 1) db slightly larger than RAM, up to 1 TB # 2) 20-40% small data write queries # 3) some long transactions # dw = data warehousing # 1) large to huge databases (100 GB to 100 TB) # 2) large complex report queries # 3) large bulk loads of data # 4) also called "Decision Support" or "Business Intelligence" # CHANGELOG # v0.1 - Initial post to LQ.org set -e # bomb out if something goes wrong... if [ ! `whoami` = 'root' ]; then echo "This script needs to run as root because" echo "it alters shm{max,mni,all}" exit fi if [ -z "$1" ]; then echo "Usage: ./pgsql_autoconf.sh [template]" echo "Where [template] is one of:" echo " 'web' (web backend server)" echo " 'oltp' (online transaction processing)" echo " 'dw' (data warehouse)" echo "See http://www.slideshare.net/oscon2007/performance-whack-a-mole" echo "for further explanation." exit fi echo -n "Will this machine be dedicated (i.e. PostgreSQL is the only active service)? (y/n) " read dedicated ################################### ### USER CONFIGURABLE VARIABLES ### ################################### # 構築環境によって下の設定内容は異なりますので、適宜変更してください。 PGHOMEDIR=/var/pgsql PGDATADIR=$PGHOMEDIR/data CONFIG_FILE=/var/pgsql/data/postgresql.conf TEMP_FILE=${CONFIG_FILE}.TMP # performance-whack-a-mole (上記リンク参照) SHARED_BUFFER_RATIO=0.25 EFFECTIVE_CACHE_RATIO=0.67 if [ "$1" = "web" ]; then # web backend server NUM_CONN=400 WORK_MEM=512 # kB CHECKPOINT_SEG=8 MAINT_WORK_MEM=128MB elif [ "$1" = "oltp" ]; then # online transaction processing if [ $dedicated = 'y' ]; then NUM_CONN=50 WORK_MEM=8192 # kB else NUM_CONN=200 WORK_MEM=2048 # kB fi CHECKPOINT_SEG=16 MAINT_WORK_MEM=128MB elif [ "$1" = "dw" ]; then # data warehousing NUM_CONN=100 WORK_MEM=131072 # kB CHECKPOINT_SEG=64 MAINT_WORK_MEM=1024MB fi ####################################### ### END USER CONFIGURABLE VARIABLES ### ####################################### # first let's locate the configuration file... if [ -e $CONFIG_FILE ]; then echo "Backing up original config file to $CONFIG_FILE.BACKUP" cp $CONFIG_FILE $CONFIG_FILE.BACKUP echo "Backing up /etc/sysctl.conf to $PGHOMEDIR/sysctl.conf.BACKUP" cp /etc/sysctl.conf $PGHOMEDIR/sysctl.conf.BACKUP fi OS_TYPE=`uname -s` ### LINUX if [ "$OS_TYPE" = "Linux" -o "$OS_TYPE" = "GNU/Linux" ]; then SYSCTL_KERNEL_NAME="kernel" MAX_MEM=`grep MemTotal /proc/meminfo | sed -e 's/^[^0-9]*//' | cut -d' ' -f1` OS_PAGE_SIZE=`getconf PAGE_SIZE` ### OPENBSD elif [ "$OS_TYPE" = "OpenBSD" ]; then SYSCTL_KERNEL_NAME="kern.shminfo" MAX_MEM=$(echo "scale=0; `dmesg | grep \"real mem\" | cut -d\"=\" -f2 | cut -d\"(\" -f1`/1024" | bc -l ) # convert to kB OS_PAGE_SIZE=`sysctl hw.pagesize | cut -d'=' -f2` ### UNKNOWN else echo "$OS_TYPE isn't supported! Please send an e-mail to rocket357@users.sourceforge.net to have this OS added!" exit fi echo "Done!" # make sure work_mem isn't greater than total memory divided by number of connections... WORK_MEM_KB=$(echo "scale=0; $MAX_MEM/$NUM_CONN" | bc -l) if [ $WORK_MEM_KB -gt $WORK_MEM ]; then while [ $WORK_MEM -lt $WORK_MEM_KB ]; do WORK_MEM_TEMP=$(echo "scale=0; $WORK_MEM*2" | bc -l) if [ $WORK_MEM_TEMP -lt $WORK_MEM_KB ]; then WORK_MEM=$(echo "scale=0; $WORK_MEM*2" | bc -l) else WORK_MEM_KB=0 fi done WORK_MEM_KB=$WORK_MEM; fi WORK_MEM=$(echo "scale=0; $WORK_MEM_KB/1024" | bc -l)MB # OS settings HOSTNAME=`hostname` # shm{mni,all,max} are critical to PostgreSQL starting. # They must be high enough for these settings: # max_connections # max_prepared_transactions # shared_buffers # wal_buffers # max_fsm_relations # max_fsm_pages echo -n "Checking the current kernel's shared memory settings..." # SHMMAX # # (BLOCK_SIZE + 208) * ((MAX_MEM * 1024) / PAGE_SIZE) * $SHARED_BUFFER_RATIO) SHMMAX=`sysctl $SYSCTL_KERNEL_NAME.shmmax | cut -d'=' -f2` OPTIMAL_SHMMAX=`echo "scale=0; (8192 + 208) * (($MAX_MEM * 1024) / $OS_PAGE_SIZE) * $SHARED_BUFFER_RATIO" | bc -l | cut -d'.' -f1`0 if [ $SHMMAX -lt $OPTIMAL_SHMMAX ]; then sysctl $SYSCTL_KERNEL_NAME.shmmax=$OPTIMAL_SHMMAX echo "$SYSCTL_KERNEL_NAME.shmmax=$OPTIMAL_SHMMAX" >> /etc/sysctl.conf fi # SHMMNI # # 4096 - 8192 SHMMNI=`sysctl $SYSCTL_KERNEL_NAME.shmmni | cut -d'=' -f2` OPTIMAL_SHMMNI=32768 # systems with large amounts of RAM, drop if you don't have 128GB or so... if [ $SHMMNI -lt $OPTIMAL_SHMMNI ]; then sysctl $SYSCTL_KERNEL_NAME.shmmni=$OPTIMAL_SHMMNI echo "$SYSCTL_KERNEL_NAME.shmmni=$OPTIMAL_SHMMNI" >> /etc/sysctl.conf fi # SHMALL # # SHMMAX / PAGE_SIZE SHMALL=`sysctl $SYSCTL_KERNEL_NAME.shmall | cut -d'=' -f2` OPTIMAL_SHMALL=`echo "scale=0; $OPTIMAL_SHMMAX / $OS_PAGE_SIZE" | bc -l | cut -d'.' -f1` if [ $SHMALL -lt $OPTIMAL_SHMALL ]; then sysctl $SYSCTL_KERNEL_NAME.shmall=$OPTIMAL_SHMALL echo "$SYSCTL_KERNEL_NAME.shmall=$OPTIMAL_SHMALL" >> /etc/sysctl.conf fi # convert MAX_MEM to MB MAX_MEM=$(echo "scale=0; $MAX_MEM/1024" | bc -l) SHARED_BUFFERS=$(echo "scale=0; $MAX_MEM * $SHARED_BUFFER_RATIO" | bc -l | cut -d'.' -f1) # There has been debate on this value on the postgresql mailing lists. # You might not get any performance gain over 8 GB. Please test! if [ $SHARED_BUFFERS -gt 12000 ]; then SHARED_BUFFERS=12000MB; else SHARED_BUFFERS="$SHARED_BUFFERS"MB fi if [ "$OS_TYPE" = "Linux" -o "$OS_TYPE" = "GNU/Linux" ]; then echo "Setting virtual memory sysctls" sysctl vm.swappiness=0 echo "vm.swappiness=0" >>/etc/sysctl.conf sysctl vm.overcommit_memory=2 echo "vm.overcommit_memory=2" >>/etc/sysctl.conf # >8GB RAM? Don't let dirty data build up...this can cause latency issues! # These settings taken from "PostgreSQL 9.0 High Performance" by Gregory Smith if [ $MAX_MEM -gt 8192 ]; then echo 2 > /proc/sys/vm/dirty_ratio echo 1 > /proc/sys/vm/dirty_background_ratio else echo 10 > /proc/sys/vm/dirty_ratio echo 5 > /proc/sys/vm/dirty_background_ratio fi fi WAL_BUFFERS="16MB" EFFECTIVE_CACHE_SIZE=$(echo "scale=0; $MAX_MEM * $EFFECTIVE_CACHE_RATIO" | bc -l | cut -d'.' -f1)MB ### NOW THE FUN STUFF!! echo "Applying system configuration settings to the server..." echo "This system appears to have $MAX_MEM MB maximum memory..." if [ -e $CONFIG_FILE ]; then echo "Setting data_directory to: $PGDATADIR" echo "Setting listen_addresses to: '*'" echo "Setting port to: 5432" echo "Setting max_connections to: $NUM_CONN" echo "Setting shared_buffers to: $SHARED_BUFFERS" echo "Setting work_mem to: $WORK_MEM" echo "Setting effective_cache_size to: $EFFECTIVE_CACHE_SIZE" echo "Setting checkpoint_segments to: $CHECKPOINT_SEG" echo "Setting maintenance_work_mem to: $MAINT_WORK_MEM" echo "Setting wal_buffers to: $WAL_BUFFERS" sed \ -e "s@[#]*data_directory = .*@data_directory = \'$PGDATADIR\'@" \ -e "s/[#]*listen_addresses = .*/listen_addresses = \'\*\'/" \ -e "s/[#]*port = .*/port = 5432/" \ -e "s/[#]*max_connections = .*/max_connections = $NUM_CONN/" \ -e "s/[#]*ssl = .*/ssl = false/" \ -e "s/[#]*shared_buffers = .*/shared_buffers = $SHARED_BUFFERS/" \ -e "s/[#]*work_mem = .*/work_mem = $WORK_MEM/" \ -e "s/[#]*effective_cache_size = .*/effective_cache_size = $EFFECTIVE_CACHE_SIZE/" \ -e "s/[#]*checkpoint_segments = .*/checkpoint_segments = $CHECKPOINT_SEG/" \ -e "s/[#]*maintenance_work_mem = .*/maintenance_work_mem = $MAINT_WORK_MEM/" \ -e "s/[#]*wal_buffers = .*/wal_buffers = $WAL_BUFFERS/" \ -e "s/[#]*cpu_tuple_cost = .*/cpu_tuple_cost = 0.002/" \ -e "s/[#]*cpu_index_tuple_cost = .*/cpu_index_tuple_cost = 0.0002/" \ -e "s/[#]*cpu_operator_cost = .*/cpu_operator_cost = 0.0005/" \ $CONFIG_FILE > $TEMP_FILE mv $TEMP_FILE $CONFIG_FILE else echo "Unable to locate the PostgreSQL config file! Can't continue!" exit 1 fi echo "Done!" 確認と設定反映 sysctl -p service postgres restart
こんにちは。藤原と申します。 新社会人の皆さんや、この4月に環境が変わった皆さんは、そろそろ慣れてきた頃でしょうか? 日々の業務の中で面白さを感じることもあれば、焦りや戸惑いを感じたり、 もしかしたらマンネリを感じたりすることもあるかもしれません。 そんな時には、自分の会社の外から刺激を受けるということを試してほしいと思っています。 エンジニアには「勉強会」という絶好の機会があります。 せっかくの勉強会を楽しんでもらうために、試してほしいことをいくつか書きたいと思います。 まずは探して申し込んでみましょう。 普段やっていることはもちろん、やっていないことでも興味があるキーワードがあれば是非参加してみましょう。 もしくはこの人に会ってお話を伺ってみたい!というのも立派な理由だと思いますし、Facebookやtwitterなどで勧めてもらったから行くというのも良いと思います。 「ATND」「connpass」「doorkeeper」「こくちーず」などのイベント告知サイトに、 たくさんの勉強会がありますので、その中から探してみてください。 また「IT勉強会カレンダー」「upmeetup.info」などの、勉強会の予定をカレンダーでまとめているサービスもありますので、こちらも利用してみる良いと思います。 ただし、申し込んだあとに、仕事の都合やその他の理由でいけなくなった場合は、すぐにキャンセルをしましょう。 人気のある勉強会はキャンセル待ちをしている人がいるケースが多いので、参加できないことがわかった時点で、枠を必ず譲りましょう。 また、勉強会を開催してくれる方々にも迷惑がかかりますので、ドタキャンは絶対しないようにしましょう。 勉強会を開催する側からしても、参加してくれる人が多いのは本当に嬉しい悲鳴なんですが、ドタキャンが少なからずいて、キャンセル待ちをしていた人が参加できなくなって申し訳ない思いをさせてしまったりとか、心苦しいこともあります。 名刺を持って行きましょう。 自分の身分を明かした上で勉強会に参加する、ということは勇気がいるかもしれません。 ただ、名刺があることによって、話しかけるきっかけを作ることが出来たり、その1枚の名刺から思わぬ話が広がることもあります。 勉強会によっては名刺交換タイムを取っているケースも有ります。 社外に知り合いを作り、刺激を受ける良い機会ですので、できれば名刺を持参しましょう。 また主催した方と名刺交換しておくと、次の勉強会の案内をいただけたりするメリットも有ります。 できれば懇親会に参加してみましょう。 勉強会終了後にはおおよその場合、懇親会もしくはビアバッシュという形で飲み会が行われます。 勉強会の中で質問できなかったことや、他にも聞いてみたい事がある人は、この懇親会が一番のチャンスです。 講師の方や他の参加者により突っ込んだ話を伺うことが出来たり、社外に自分と同じような立場の知り合いを作ることが出来る絶好の機会です。 「どうしても話しかけにくい」「なかなか思い切って聞くことが出来ない」なんていうこともあるかもしれません。 その際は運営スタッフの方に声をかけてみましょう。 きっと間を取り持ってくれるはずですし、いろいろ聞いてくれると思います。 終わったらブログを書いてみましょう。 折角勉強会に参加したのですから、その内容や感想をまとめる意味でブログを書いてみましょう。 自分の知識の整理にもなりますし、もしかしたら思わぬフィードバックがもらえるかもしれません。 また、勉強会によっては、ブログを書くことで特典をつけてくれるものもあります。 自分自身、運営スタッフとしてブログを読ませてもらうこともありますが、率直な感想や、貴重なご意見をもらうことが出来て大変嬉しいですし、また厳しい意見などは、今後の勉強会運営を改善するための貴重なご意見として、活用させて頂いてます。 最後に もし勉強会に参加することに面白さを感じたら、その応用編として「小規模な勉強会」「勉強会のスタッフになってみる」というのも大変おもしろいと思います。 今まで自分が参加していた勉強会のスタッフになると、いろんな裏側が分かったり、講師の方とお近づきになる機会が増えたりと、いろんなメリットがあります。 もちろん大変なことも多いですが、それ以上に充実感が得られると思います。 また、もし良ければ弊社のスマートデバイスアプリエンジニア2名が6/3にレバレジーズ株式会社様にて講演をさせていただきますので、ぜひご参加いただければと思います。 【ヒカ☆ラボ】「HOME'S」の開発スタッフが語るスマートデバイスアプリ開発秘話( http://connpass.com/event/6204/ ) この記事を読んでいただいた一人でも多くの方が、勉強会に興味を持っていただき、参加してみようかな?と思っていただければ、大変嬉しく思います。
こんにちは、鈴木です。仕事でMacを使う機会が多くなりました。 ある程度のツールはWindowsでもMacでも同じように使えるのですが、 MacのExcelはWindowsのコマンドと結構違うのです。 WindowsのOfficeにずいぶん長く慣れてきたので、 MacのExcelコマンドにいまさら慣れる気もないなあ。 キーも多いし。。。 これは不便!なんとか便利にしたい! というわけで、自分なりの解決方法を紹介します。 [免責事項] 本記載と紹介したソフトウェアについては自己の責任に基づいてご利用ください 今回紹介したソフトウェアと株式会社ネクストは関係がありません 実現したいこと F2でセルの編集を始めたい! デフォルトショートカットコマンド:[control] + [U] ↓ 再現したいショートカットコマンド:[F2] セル内の改行を使いやすくしたい! デフォルトショートカットコマンド:[alt] + [option] + [enter]  ↓ 再現したいショートカットコマンド:[fn] + [enter] やること KeyRemap4MacBookをインストール   https://pqrs.org/macosx/keyremap4macbook/index.html.ja KeyRemap4MacBookを設定  基本的にこのソフトは起動中ずっとキーの役割を入れ替えることができるアプリなのですが、今回はMac用のExcelが起動しているときだけ有効になる設定を用います。 KeyRemap4Macbookのprivate.xmlを編集 [Misc & Uninstall] > [Open private.xml] private.xmlが格納してあるディレクトリが開くので、 好きなテキストエディタで下記のように 以下の 項目を記載してください。 もともと他の設定が入っている場合は追記するようにしてください。 下記部分的に抜粋 <list> <item> <name>[Excel] Fn & Return to ReturnInCell</name> <identifier>private.app_excel_Fn&Return</identifier> <only>EXCEL</only> <autogen> --KeyToKey-- KeyCode::RETURN, ModifierFlag::FN, KeyCode::RETURN, ModifierFlag::OPTION_L | ModifierFlag::COMMAND_L </autogen> </item> <item> <name>[Excel] F2 to EditCell</name> <identifier>private.app_excel_f2</identifier> <only>EXCEL</only> <autogen> --KeyToKey-- KeyCode::F2, KeyCode::U, ModifierFlag::CONTROL_L </autogen> </item> </list> 編集後の例 [ChangeKey]タブでReloadXMLを押すと、 さっきの項目が表示されるので、チェックします。 これで、Windowsと同じように、F2でセルの編集を開始、 fnとリターンキー同時押しでセル内改行、ができるようになりました! 日々の仕事も改善して効率的に楽しくしたいですね。 もう少し詳しく知りたい方へ 利用できるKeyCode/ModiferFlag一覧 List of KeyCode https://github.com/tekezo/KeyRemap4MacBook/blob/version_9.3.0/src/bridge/generator/keycode/data/KeyCode.data/ List of ModifierFlag https://github.com/tekezo/KeyRemap4MacBook/blob/version_9.3.0/src/bridge/generator/keycode/data/ModifierFlag.data/ List of ConsumerKeyCode (Brightness Control, Audio Volume Control, Music Control, etc) https://github.com/tekezo/KeyRemap4MacBook/blob/version_9.3.0/src/bridge/generator/keycode/data/ConsumerKeyCode.data/ List of PointingButton https://github.com/tekezo/KeyRemap4MacBook/blob/version_9.3.0/src/bridge/generator/keycode/data/PointingButton.data/ 構文例 KeyをKeyに変えるとき  Spaceを押ししたときに、Tabにする <autogen> KeyToKey KeyCode::SPACE, KeyCode::TAB</autogen>  一つ目のKeyCodeが変更前、二つ目のKeyCodeが変更後。それをカンマで区切る KeyとModifierをKeyに変えるとき  Space,Control_Lを同時押ししたときに、Tabにする <autogen> KeyToKey KeyCode::SPACE, ModifierFlag::CONTROL_L, KeyCode::TAB </autogen>  一つ目のKeyCodeから二つ目のKeyCodeまでが変更前、それ以降が変更後 KeyとModifierをKeyとModifierに変えるとき  Space,Control_Lを同時押ししたときに、Tab,Control_L同時押しにする <autogen> KeyToKey KeyCode::SPACE, ModifierFlag::CONTROL_L, KeyCode::TAB, ModifierFlag::CONTROL_L </autogen>    一つ目のKeyCodeから二つ目のKeyCodeまでが変更前、それ以降が変更後   Keyと複数のModifierをKeyに変えるとき  Space,Control_L,Fnを同時押ししたときに、Tabにする <autogen> KeyToKey KeyCode::SPACE, ModifierFlag::CONTROL_L | ModifierFlag::FN, KeyCode::TAB </autogen> 一つ目のKeyCodeから二つ目のKeyCodeまでが変更前、それ以降が変更後 かつ一つ目の修飾子と二つ目の修飾子の間はカンマではなくパイプで区切る KeyとModifierをKeyとModifierに変えるとき  Space,Control_Lを同時押ししたときに、Tab,Control_Lにする <autogen> KeyToKey KeyCode::SPACE, ModifierFlag::CONTROL_L, KeyCode::TAB, ModifierFlag::CONTROL_L </autogen>  一つ目のKeyCodeから二つ目のKeyCodeまでが変更前、それ以降が変更後、特定のKeyとModiferの組み合わせのみ反応するようにする  Space,Fnを同時押ししたときに、Tabにして、Space,Fn,<任意のキー>で反応しないようにする <autogen> KeyToKey KeyCode::SPACE, ModifierFlag::FN | ModifierFlag::NONE, KeyCode::TAB </autogen>  明示的に | ModifierFlag::NONE を加えればいいみたいです 参考URL KeyRemap4MacBook - マニュアル https://pqrs.org/macosx/keyremap4macbook/document.html.ja KeyRemap4MacBook - private.xml Reference Manual https://pqrs.org/macosx/keyremap4macbook/xml.html.ja 動作を確認した環境 MacOS ver. 10.8.4 Microsoft Excel for Mac 2011 ver. 14.1.0 KeyRemap4MacBook ver. 8.4.0 CotEditor ver.1.4.1
最近「Apple原理主義者」と合わせ「Origami原理主義者」と名乗ろうかと考えている大坪です。 先日行われたFacebookの f8 デベロパーカンファレンス での Origami のデモを紹介します。 まずこのビデオ。新しくなったFacebook Messengerアプリに関するプレゼンですが.. この「Facebook Messengerアプリ」のように見えるものは、一行のコードも含まず、デザイナーが「空いた時間を使って一週間で作った」とのこと。 このプレゼン中で述べられているOrigami(Quartz Composer)の特徴は Visual: not like Javascript Real time : not like After Effects Non-Linear: not like Flash Photoshopで静的なイメージを作るより、少しデザインにかかる時間は増える。しかし開発全体で観れば大きな時間の節約になる。 他にも例えばメッセージ一覧画面のデザインを決めるまでにどれだけのパターンを試したのか、アイコンを何種類試し最終的なデザインに落ち着いたのか、サウンドは、など見所が満載のプレゼンテーションです。 もう一つは本家Paperのプレゼンテーション中のデモ。(画面左上のOrigamiアイコンに注意してください) このビデオを見ると、Paperが実際のコードで動く前に、Origamiで非常に詳細に「デザイン」されていたことが見て取れます。 このプレゼンをしているのはPaperのEngineeringチームのマネージャなのですが、 「このプロトをみているうちに、心配になってきた」 と言っています。そりゃそうだろう。Origami上で見事に動いても、同じことが実コードで再現できるとは限りません。このプロトのように「誰も観た事がない」ようなインタラクションが実現されていればなおさらのことです。 どうしたらこのような動きが実現できるのか?「普通に実装」するとこんなぎこちない動きになってしまいます。 ああ、、そうだよ。普通に作るとこうなっちゃうんだよ(体験談) ではここからPaperチームはどのような方法をとったか、についてはまた別の機会に(とか書いちゃっていいのか) このプレゼンの最後の方にこういう文字がでてきます。 "Accept the challenge of ambitious design" 野心的なデザインのチャレンジを受けて立つ Paperのデザインチームは 「今使うことができる画面部品」 からスタートしたのではなく 「モバイルアプリのUIはどうあるべきか」 からスタートし、Origamiでプロトを作り上げました。エンジニアチームはそれを 「信じられないくらいスルスル動く」 実際のアプリに結実させた。 マウスとキーボードで、離れた場所にある大画面を操作するデスクトップアプリのUIと、手のひらの中にあるディスプレイをタッチで操作するモバイルアプリのUIは根本的に違うものであるべきではないか。こうして文字にすると当たり前のようですが、我々はまだこの「違い」に気が付き始めたところなのかもしれません。 とかなんとか取り乱しているのは私だけですか?そうですか。
はじめまして、株式会社ネクスト リッテルラボラトリーの清田です。 もともと、私は大学の研究者だったころに創業メンバーとして関わった大学発ベンチャー「リッテル」にて、図書館などの膨大な情報をさがしやすくするシステムなどの研究開発にたずさわっていました。 2011年にネクストにジョイン してからは、 HOME'S の膨大なログデータの裏にかくれた潜在的なニーズの発見など、情報レコメンデーション技術の研究開発に日々取り組んでいます。 今回、これまでの研究成果のひとつとして、 スマートフォンアプリ「ホームズくんのこれからシアター」をリリース しました。 ( iOS と Android 、両方に対応しています) ホームズくん や劇場のなかにいる動物たちからの質問にタッチ操作で答えていくだけで、理想の住まいへホームズくんが案内してくれるというコンセプトのアプリです。 アプリの制作にあたっては、 面白法人カヤック さんに多大なご協力をいただきました。 インストールはこちらから iOS(iPhone、iPod、iPad) Android この記事では、「ホームズくんのこれからシアター」の裏側にあるコンセプトをいくつかお伝えしたいと思います。 「理想の住まい」にどうやって案内するか? 家探しをしたことがある方はご存知のとおり、最初から思い描いていた条件(場所、値段、間取り、築年数、楽器可や南向きなどのこだわり条件、その他もろもろ)がすべて一致する物件にいきなり出会えることは、まずありません。 家探しをする人は、さまざまな制約(収入、家族構成、勤務先・通学先、引越しの時期など)がある中で、現実に存在する物件をみながら、「どの条件を優先するか」「どの条件を妥協するか」という決断を迫られます。 より満足できる住まいはどれかと悩みながらも、物件検索サイトでの検索や物件の見学、身近な人への相談などの行動を続けることで、決断に近づいていきます。 最終的に契約を決めた物件が、最初に思い描いていた条件からだいぶかけ離れていることも少なくありません。 家探しにかぎらず、何かを「探す」というプロセスでは、人間がもっている知識が、情報に出会うことで変化しつづけることが知られています。 イギリスの情報学者ブルックスは、情報に出会うことで知識がどう変化するかを、以下の式(ブルックスの方程式)で端的に表現しています *1 *2 。 K[S] + ΔI = K[S + ΔS] K[S]: 情報を得る前のSに対する知識 ΔI: 獲得した情報 K[S+ΔS]: 情報を得た後の知識 この式は、人間の知識は出会った情報が単純に足し算されるわけではなく、情報と出会うことで知識の構造自体がダイナミックに変化しつづけることを表しています。 ブルックスの方程式を、家探しをしている人にあてはめてみましょう。 「出会った物件や物件情報が住まい探しの条件をそのまま左右する」という理解は、正しくないことがわかります。 「物件や物件情報との出会いをきっかけとして、自分が本当は何を次の住まいに求めているのかをじっくり考えることによって、理想の住まいにより近づくために、自分の知識を変化させていく」というのが、本来の住まい探しのあり方だということが言えるのではないでしょうか。 「理想の住まい」に案内するために、ユーザーに質問を投げかけるという「ホームズくんのこれからシアター」のコンセプトは、「ユーザーがじっくり考えるきっかけをつくることが、結局は理想の住まいにたどりつく近道である」という考え方からきています。 「理想の住まい」へのヒントをどうやって提案するか? 「ホームズくんのこれからシアター」では、2〜3個の質問回答を数回繰り返した後、ユーザーが住まいに対して求めていると思われる条件を、ホームズくんがヒントとしていくつか提案してくれます。 「質問でユーザーが選んだ選択肢」と、「ホームズくんが提案してくれるヒント」をどのように結びつけるかについては、現時点では明確な正解はありません。 ただ、「理想の住まいかどうかを決めるのはけっきょく本人の主観」であり、「理想の住まいに対する知識は変化しつづける」というブルックスの方程式の考え方を前提とすると、 ベイズ確率 の概念は非常に参考になります。 「これからシアター」の裏側では、ベイズ確率の概念を利用して、質問でユーザーが選んだ選択肢によって、ユーザーに提案するヒント(の確率)を更新していくという仕組みが動いています。 以下の図にあるように、たとえば「将来不安に思っていることは?」という質問で選んだ選択肢によって、ユーザーが「ファミリー向け物件」にどれくらい関心をもっているかを表す数値(確率)を更新していくことで、どのヒントを提案するかを決めています。 住まい探しをするユーザーのニーズはどのように変化するか? 住まい探しをするユーザーの本当のニーズを知るのは、簡単ではありません。 住まい探しをつづけるユーザーは、情報を受け取りながら「理想の住まい」へ近づくために、住まいへのニーズを変化させていきます。 どのように自分のニーズを変化させているかは、ユーザー自身でさえうまく説明できないものです。 ユーザーの行動(物件情報の検索、閲覧、物件の見学、契約など)の裏にかくれた本当のニーズを探るため、ネクストではログデータの分析やアンケートなど、さまざまな取り組みをつづけています。 ここでは、自然言語処理の分野でよく利用されているLatent Dirichlet Allocation(LDA、潜在的トピックモデルの一種)によるログデータ分析の取り組みを紹介します。 HOME'Sなどの物件検索サイトを使って住まい探しをするユーザーは、一度のサイト訪問だけで住まい探しを完結させることはむしろまれで、数日間〜数週間にわたって物件情報を探しつづけるのがふつうです。 場合によっては、不動産会社に足を運んだあともサイトで検索したりもします。 そこで、一度のサイト訪問(セッション)を「文書」、サイト訪問内でのユーザー行動(検索操作、検索条件、物件情報閲覧など)を「文書中に出現するキーワード」になぞらえて、LDAによる分析を試みました。 上の図は、(おもに賃貸物件を探している)ユーザーのニーズが、時間の経過とともにどのように変化していくかを可視化したものです。 はじめはただ漠然と物件リストを眺めていたユーザーが、訪問回数を重ねるにつれてより具体的な行動(物件情報の閲覧、お気に入りへの登録、物件検索条件の変更、不動産会社への問い合わせ)に移っていく様子がわかります。 また、「 地図での検索 しか使わないユーザーが一定割合いること」「不動産会社への問い合わせから数日後、物件名などをサーチエンジンで検索してHOME'Sを再訪するユーザーがいること」なども読み取れます。 上の図は、 住まい探しに役立つコンテンツ の閲覧ログを対象に、同様の分析を試みたものです。 住まい探しをはじめるユーザーの興味はすべて同じではなく、「住まい自体」「次の住まい」「ライフプラン」など、いくつかの異なる興味をきっかけに住まい探しをはじめていること 漠然とした興味をもっているユーザーは、「住み替えニーズ」や「住まいのイメージ」を扱ったコンテンツの閲覧をへて、具体的な住まい探しの行動を起こせるように自らの住まいへのニーズを明確にしていっていること などが読み取れます。 おわりに 「これからシアター」では、「住まい探しのイメージを具体化させるのに役立つ質問は何か」「ユーザーの真のニーズを把握するには、どんなユーザー行動の分析が有用か」といった研究課題に、アプリの運用をつうじて取り組んでいく予定です。 アプリの運用から得られた知見についても、エンジニアブログなどを通じて発信していきます。 ぜひ実際にアプリをさわっていただき、多くのフィードバックをいただけるとうれしいです! 参考文献 *1 : B. C. Brookes. 1980. The foundation of information science. Part I. Philosophical aspects. Journal of Information Science, 2, 125-133. PDF *2 : 三輪眞紀子. 2003. 情報検索のスキル −未知の問題をどう解くか. 中公新書, 1714, 中央公論新社. Amazon
こんにちは、上津原です。今回はCouchbaseネタです。 前回のCouchbase MeetUpに引き続き、今回も弊社ネクストで開催いたしました。 今回は、このブログでも何度か紹介していたモバイル向けのNoSQLデータベース、Couchbase Liteのハンズオンを行いました。 今回は、私が前に立って来ていただいた皆さんにCouchbaseLiteを動かしてCRUDをしてCloudantとSyncするまでをやってもらいました。 その際のスライドとプロジェクトを公開します。 スライド&プロジェクト Couchbase liteハンズオン from ssd kfk 課題プロジェクト 解答プロジェクト 応用プロジェクト これらのプロジェクトの中に入っているSync(Replication)の部分ですが、私のCloudantのURLが入っています。さすがにここでIDとパスワードを公開するわけにも行かないので、利用の際はご自身でCloudantのアカウントを作成して利用いただければと思います。 あと、ハンズオンということもあって詳しい説明は省かれています。詳しいことをしえいたい方はぜひ私に声をかけてもらえればと思います。 第2回も予定しています。 昨日のハンズオンではCloudant(CouchDB)とのSyncでしたが、次回はCouchbaseとSyncGatewayを利用したSyncができればと思っています。 初のハンズオンということで人数も少なくやりましたが、次回は多分ちょっと人数も増やせるかな、と思っています。また、こういう内容でやって欲しいとか、もう一度このハンズオンをやって欲しいなどありましたらご意見お寄せ頂ければと思います。
こんにちは、上津原です。 相変わらずUnrealEngine4に翻弄されて頭から煙を出しています。 そろそろ機関車トーマスの異名を得てもいい頃かもしれません。 さて、今回は丸1日半ハマったHTTP通信がやっとこさ動いたので残しておこうと思います。 BluePrintで出来なかったからC++だ! 最初はBluePrintでさくっとできるんだろう、だって今21世紀だぜ?とか思っていたのですが甘かったです。そんなノードは用意されていませんでした。 そういうわけでコードで書くしかなくなり、1年半ぶりにC++を触ることとなりました。 とりあえず クイックスタート を一通りやって、さあ実践!そして撃沈。Objective-C→cocos2d-x→Unityとやってきましたが、同じC++でもcocos2dxとは全く違う書き方。甘く見ていました。 本題のコード コードは以下のようにすれば動きました。 Actorを元に、HelloWorldというクラスを作成しています。 ↓長くなっちゃったのでクリックして見てください。 ハマりポイント あまり理解しきれていないので、詳しいことは何ともですが、 「Http.h」をincludeするためにBuild.csに PrivateDependencyModuleNames.AddRange(new string[] { "HTTP" }); を追加する必要があった という点が一番ハマりポイントで、どうやったらパスが通るのかわからず、ず~~っと止まっていました。やっぱりハマるポイントは些細なことなのね…。 とりあえずこのように書けば、HTTP通信が通る、ということになります。 この後JSONのパースも行ったのですが、それはまた別の記事で紹介しますね。 お礼 最後にこれらは https://www.facebook.com/groups/unrealuserj/permalink/566215020144037/?stream_ref=2 https://answers.unrealengine.com/questions/31079/http%E9%80%9A%E4%BF%A1%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6.html などのコミュニティで助言をいただきました。助言いただいたみなさんありがとうございました!
古川です。 search component plugin 後編です。 search component plugin 前編 で作成した MyQueryComponent.java にスコア計算をするための処理を追加していきます。 Collector の作成 以前の記事 で紹介しましたが、luceneのcollectorクラスを使うと、ソートのためのスコア計算を柔軟に定義することができます。 そこで、フィールドx、フィールドy の値を使って、 score = a*x*x + b*x*y + c*y*y + d*x + e*y + f というスコア値を計算する MyCollectorクラスを作成します。 MyCollector.java package jp.co.homes.searchcomponent; import java.io.IOException; import java.util.Collections; import java.util.ArrayList; import java.util.Comparator; import org.apache.lucene.index.IndexReader; import org.apache.lucene.search.Collector; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.ScoreDoc; import org.apache.lucene.search.FieldCache; import org.apache.lucene.util.PriorityQueue; import org.apache.lucene.index.AtomicReader; import org.apache.lucene.index.AtomicReaderContext; public class MyCollector extends Collector { private static final String FIELD_X = "x"; private static final String FIELD_Y = "y"; private int docBase; private int totalHits; private FieldCache.Floats x; private FieldCache.Floats y; private HitQueue pq; private ScoreDoc pqTop; private float maxScore; private float[] coefficients; public MyCollector(float[] _coefficients, int maxLen) { this.pq = new HitQueue(maxLen, true); this.pqTop = this.pq.top(); this.maxScore = Float.NEGATIVE_INFINITY; this.coefficients = _coefficients; } @Override public void setNextReader(AtomicReaderContext context) throws IOException { AtomicReader reader = context.reader(); this.docBase = context.docBase; this.x = FieldCache.DEFAULT.getFloats(reader, FIELD_X, false); this.y = FieldCache.DEFAULT.getFloats(reader, FIELD_Y, false); } @Override public void setScorer(Scorer socorer){} @Override public boolean acceptsDocsOutOfOrder(){ return true; } @Override public void collect(int doc) { totalHits++; float x = (float)this.x.get(doc); float y = (float)this.y.get(doc); float score = this.coefficients[0]*x*x; score += this.coefficients[1]*x*y; score += this.coefficients[2]*y*y; score += this.coefficients[3]*x; score += this.coefficients[4]*y; score += this.coefficients[5]; if (score < pqTop.score) { // 現在の最低点より小さいスコアの // ドキュメントは無視 return; } if (this.maxScore < score) { this.maxScore = score; } int docid = this.docBase + doc; // 今先頭にあるスコアを、新しい値に交換 this.pqTop.doc = docid; this.pqTop.score = score; // 新しい値のスコアを登録しHitQueueを再構築 // 一番小さい値を持つオブジェクトがキューの先頭になる pqTop = pq.updateTop(); } public int getTotalHits() { return this.totalHits; } public float getMaxScore() { return this.maxScore; } public ScoreDoc[] getResults() { int queueSize = this.pq.size(); ScoreDoc[] results = new ScoreDoc[queueSize]; for (int i=0; i<queueSize; i++) { results[i] = this.pq.pop(); } return results; } // プライオリティーキュー class HitQueue extends PriorityQueue<ScoreDoc> { HitQueue(int size, boolean prePopulate) { super(size, prePopulate); } @Override public ScoreDoc getSentinelObject() { return new ScoreDoc(Integer.MAX_VALUE, Float.NEGATIVE_INFINITY); } @Override public final boolean lessThan(ScoreDoc hitA, ScoreDoc hitB) { return hitA.score < hitB.score; } } } Search Component Plugin 実装 前回作成した、MyQueryComponent.java を、このMyCollectorクラスを使ってスコア計算するよう変更します。 MyQueryComponent.java package jp.co.homes.searchcomponent; import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.Query; import org.apache.lucene.search.Filter; import org.apache.lucene.search.ScoreDoc; import org.apache.lucene.search.ConstantScoreQuery; import org.apache.solr.client.solrj.SolrServerException; import org.apache.solr.common.SolrDocument; import org.apache.solr.common.SolrException; import org.apache.solr.common.params.*; import org.apache.solr.common.util.NamedList; import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.response.ResultContext; import org.apache.solr.response.SolrQueryResponse; import org.apache.solr.schema.FieldType; import org.apache.solr.search.QParser; import org.apache.solr.search.QParserPlugin; import org.apache.solr.search.QueryParsing; import org.apache.solr.search.ReturnFields; import org.apache.solr.search.DocSet; import org.apache.solr.search.DocList; import org.apache.solr.search.DocSlice; import org.apache.solr.search.SolrIndexSearcher; import org.apache.solr.search.SolrReturnFields; import org.apache.solr.search.SyntaxError; import org.apache.solr.handler.component.SearchComponent; import org.apache.solr.handler.component.ResponseBuilder; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.List; public class MyQueryComponent extends SearchComponent { public static final String COMPONENT_NAME = "my_query" ; @Override public void prepare(ResponseBuilder rb) throws IOException { SolrQueryRequest req = rb.req; SolrParams params = req.getParams(); if (!params.getBool(COMPONENT_NAME, true )) { return ; } SolrQueryResponse rsp = rb.rsp; ReturnFields returnFields = new SolrReturnFields( req ); rsp.setReturnFields( returnFields ); int flags = 0 ; if (returnFields.wantsScore()) { flags |= SolrIndexSearcher.GET_SCORES; } rb.setFieldFlags( flags ); String defType = params.get(QueryParsing.DEFTYPE, QParserPlugin.DEFAULT_QTYPE); String queryString = rb.getQueryString(); if (queryString == null ) { queryString = params.get( CommonParams.Q ); rb.setQueryString(queryString); } try { QParser parser = QParser.getParser(rb.getQueryString(), defType, req); Query q = parser.getQuery(); if (q == null ) { q = new BooleanQuery(); } rb.setQuery( q ); rb.setSortSpec( parser.getSort( true ) ); rb.setQparser(parser); rb.setScoreDoc(parser.getPaging()); String[] fqs = req.getParams().getParams(CommonParams.FQ); if (fqs!= null && fqs.length!= 0 ) { List<Query> filters = rb.getFilters(); filters = filters == null ? new ArrayList<Query>(fqs.length) : new ArrayList<Query>(filters); for (String fq : fqs) { if (fq != null && fq.trim().length()!= 0 ) { QParser fqp = QParser.getParser(fq, null , req); filters.add(fqp.getQuery()); } } if (!filters.isEmpty()) { rb.setFilters( filters ); } } } catch (SyntaxError e) { throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e); } } @Override public void process(ResponseBuilder rb) throws IOException { SolrQueryRequest req = rb.req; SolrQueryResponse rsp = rb.rsp; SolrParams params = req.getParams(); if (!params.getBool(COMPONENT_NAME, true )) { return ; } SolrIndexSearcher searcher = req.getSearcher(); SolrIndexSearcher.QueryCommand cmd = rb.getQueryCommand(); // スコア計算なしで、ヒットするドキュメントID一覧を取得 DocSet ds = null ; if (cmd.getFilterList() == null ) { ds = searcher.getDocSet(cmd.getQuery()); } else { List<Query> newList = new ArrayList<Query>(cmd.getFilterList().size() + 1 ); newList.add(cmd.getQuery()); newList.addAll(cmd.getFilterList()); ds = searcher.getDocSet(newList); } // ヒット件数を取得 DocList dl = null ; int numHits = ds.size(); int requestOffset = cmd.getOffset(); int requestLen = cmd.getLen(); if (numHits < requestOffset) { dl = new DocSlice( 0 , 0 , new int [ 0 ], null , numHits, 0.0f ); } else { int queueSize = requestOffset + requestLen; if (numHits < queueSize) { queueSize = numHits; } // result セットされている値を docset をluceneFilter // 独自スコア計算用のcollector として、 // 独自collectorを使ってスコア計算 Query luceneQuery = new ConstantScoreQuery(ds.getTopFilter()); float [] coefficients = parseMyParmas(params); // 必要なサイズだけ MyCollector collector = new MyCollector(coefficients, queueSize); searcher.search(luceneQuery, null , collector); // 結果を取得 ScoreDoc[] docs = collector.getResults(); float maxScore = collector.getMaxScore(); // レスポンス用に加工 int [] ids = new int [queueSize]; float [] scores = new float [queueSize]; for ( int i= 0 ; i<queueSize; i++) { ScoreDoc sc = docs[i]; // 小さい順に取り出してるので大きい順に並べ替え int index = queueSize - 1 - i; ids[index] = sc.doc; scores[index] = sc.score; } dl = new DocSlice( 0 , queueSize, ids, scores, numHits, maxScore); dl = dl.subset(requestOffset, queueSize - requestOffset); } ResultContext ctx = new ResultContext(); ctx.docs = dl; ctx.query = rb.getQuery(); rsp.add( "response" , ctx); rsp.getToLog().add( "hits" , numHits); } private float [] parseMyParmas(SolrParams params) { float [] coefficients = new float [ 6 ]; String buf = params.get( "myparams" ); String[] myparams = buf.split( "," ); for ( int i= 0 ; i<myparams.length; i++) { coefficients[i] = Float.parseFloat(myparams[i]); } return coefficients; } @Override public String getDescription() { return "my query component" ; } @Override public String getSource() { return "$URL: dummy $" ; } } コンパイル・設定 前回同様なので省略します。 動作確認 solr を起動して、前回作成したmyfunc を使ったクエリと、今回作成したmy_select の検索結果が同じであることを確認します。 myfunc(function query plugin) http://localhost:8983/solr/collection1/select?echoParams=none&q=*:*&fq=x:[0 TO 500]&fl=id,x,y,myfunc(x,y,1,2,3,4,5,6)&sort=myfunc(x,y,1,2,3,4,5,6) desc&rows=3 <result name = "response" numFound = "500773" start = "0" > <doc> <str name = "id" > id789132 </str> <float name = "x" > 500.0 </float> <float name = "y" > 999.0 </float> <float name = "myfunc(x,y,1,2,3,4,5,6)" > 4250004.0 </float> </doc> <doc> <str name = "id" > id96466 </str> <float name = "x" > 499.0 </float> <float name = "y" > 999.0 </float> <float name = "myfunc(x,y,1,2,3,4,5,6)" > 4247003.0 </float> </doc> <doc> <str name = "id" > id882478 </str> <float name = "x" > 499.0 </float> <float name = "y" > 999.0 </float> <float name = "myfunc(x,y,1,2,3,4,5,6)" > 4247003.0 </float> </doc> </result> my_select(search component plugin) http://localhost:8983/solr/collection1/my_select?echoParams=none&q=*:*&fq=x:[0 TO 500]&fl=id,x,y,score&myparams=1,2,3,4,5,6&rows=3 <result name = "response" numFound = "500773" start = "0" maxScore = "4250004.0" > <doc> <str name = "id" > id789132 </str> <float name = "x" > 500.0 </float> <float name = "y" > 999.0 </float> <float name = "score" > 4250004.0 </float> </doc> <doc> <str name = "id" > id96466 </str> <float name = "x" > 499.0 </float> <float name = "y" > 999.0 </float> <float name = "score" > 4247003.0 </float> </doc> <doc> <str name = "id" > id882478 </str> <float name = "x" > 499.0 </float> <float name = "y" > 999.0 </float> <float name = "score" > 4247003.0 </float> </doc> </result> scoreが同じ場合のソート順が微妙に違うため、ときどき順序が前後しますが、score値は同じで、どちらも大きい順に並んでいることが分かります。 速度評価 スコア計算に関連する引数を変更しながら、5回クエリを実行してQTimeの平均値を計算してみました。 myfunc(function query plugin) 15.4ms my_select(search component plugin) 11.6ms search component plugin でも高速なスコア計算が実現できることが確認できました。 まとめ search component plugin を使った独自ソートの実現方法を紹介しました。実際に使う場合には、きちんとしたエラー処理や SolrIndexSearcher.java の中で行われているようなクエリキャッシュの仕組みを追加していく必要がありますが、大体こんな感じでいけそうです。 function query plugin で実現できないソート用スコア計算が必要になった時は、search component plugin を使った方法を検討してみても良いかもしれません。
先日おもしろい記事に出会いました。" The design decisions behind the tech industry’s beloved anonymous Secret app " という題名なのですが、この"Secret"というのが形容詞だと思っていたので文意をとるのに時間がかかりました。これは"Secret"というアプリの名称なのですね。 記事を読むと、デザインが特徴的らしいのですがいまいちイメージが湧かない。 日本語のApp Storeで検索をしてもでてこないので Facebook Paper のときのように米国サイトからダウンロードしてみると... 追記:2014/5/27 日本のApp Storeからもダウンロードできるようになりました。 いや、これ面白いわ。(読者をおいてけぼりにした自己満足) 仕組みが極めてシンプルで アカウントは登録するが、Secretの投稿、コメントはすべて匿名。(投稿者の住んでいる都市名だけは表示される) 電話番号を登録すれば、それを手がかりに「友達」と繋がることはできる。ただ「友達」が誰かはわからない。 Secretは画面に一列に表示。写真+コメントで縦スクロールだけで閲覧できる。 それぞれのSecretには、ハートマークをクリックするか、コメントをすることができる。ただしコメントができるのは「友達」だけ Secretにつけられたコメントには、ランダムにアイコンが割り当てられる(そのSecretの中では共通) Secretは最初「友達」だけに公開され、「友達」がだれかハートマークをつければ、より多くの人に公開される。 日本語の記事 はこちらにあります。元記事を読むと、「Tech Industryでの買収とかレイオフの噂で賑わっている」らしいのですが *1 使ってみた限り実にいろいろなSecretが投稿されています。 こういう感動的なのや 「母親は”いついい男と結婚するの?”といつも聞く。私はレズビアンだと何度も言っているのに」 という考えさせられるものもあり。かと思えば 「今は昼。シャツの中に靴下が片方はいっていることに今気がついた」 という脱力系のSecretもあります。もっともこうした「匿名の噂アプリ」は他者に対する無責任な中傷を広めてしまう危険性を持っていることにも注意する必要がある。いや、すでにTwitterがそうした役割を担っている、という議論もあるでしょうし、そもそもインターネット自体が,,という意見もあるでしょう。 というような「アプリの位置づけ」に対する議論とは別に、このアプリのUIは良く考えられており,,という詳細な考察は Design Details: Secret for iOS を見ていただくとして、このアプリのリードデザイナーChrys Bader氏が挙げた「プロダクトデザインの原則」と「ソーシャルのホームランを打つための3つのルール」を紹介します。 Secret以前にもこうした「匿名で書き込みができる」掲示板もアプリもあったのですが、なぜSecretはこれほど話題になっているのか?そうした疑問に対する答えの一端がそれらから伺えると思うからです。 まずプロダクトデザインの原則ですが Start from emotion — This isn’t a new concept , says Bader, but Apple’s design team embodies this and I agree with them. Tell a story — The user should be able to fit the whole product in his or her mind at once. You should be able to think about what Secret is and not spend more than one brain cycle piecing it together. Keep a balance — Positive experiences need to outweigh the negative ones (which can be prevalent on an anonymous app). The experience needs to be a net positive. Live by constraints — It’s great to use “blue-sky thinking” to brainstorm and come up with ideas, but when it comes time to implementing design, set constraints. via: The design decisions behind the tech industry’s beloved anonymous Secret app — Tech News and Analysis 感情から始める: これは新しい話ではないがAppleのデザインチームは実践しておりそれに同意 ストーリーを語る: ユーザはそのアプリが何をするものか瞬時に理解できなくてはならない バランスを保つ: ポジティブな要素がネガティブな要素を上回っていなければならない。 制約を意識する: ブレストの時は制約を外して考えるのがよいが、実装段階では制約を意識しなくては これらのうち「ストーリーを語る」についてこのアプリのデザインは特に印象的です。上のようにコンセプトを文字で説明しようと思えばかなり苦労するのですが、ダウンロードして触り、投稿されているSecretをみればたちまち「このアプリが何をするものなのか」が理解できる。 さて、次は「ソーシャルのホームランを打つための3つのルール」 Allow for a novel form of self expression Make it stupidly simple to express yourself Make it rewarding. 引用元: The design decisions behind the tech industry’s beloved anonymous Secret app — Tech News and Analysis 自分を表現する新しい方法を提供する 馬鹿げているくらい簡単に自分を表現できるようにする 投稿した甲斐があるようにする 匿名でなければ告白できないような秘密を、文章と背景画像だけで表現させる。これは「馬鹿げているくらい簡単に自分を表現できる」「自分を表現する新しい方法を提供する」こと。そしてそれに対してこれまた匿名の人達からフィードバックがもらえる。これによって投稿者は「投稿した甲斐があった」と感じることができる。 原則は言葉でしかないが、実際にアプリに具現化させているところには感服せざるを得ません。 Facebook paperとかこのアプリを使っていると、 「コンテンツが主役」 というデザイン原則が徹底していることに気がつきます。それとともにやはりiPhoneアプリはスワイプ(つまり画面をすい、っとすること)操作を基本にしたほうが自然である、とも。 またそれぞれのアプリの詳細に凝らされた工夫、こだわりには感嘆させられます。それがただの「自己満足」ではなく使う側の楽しさ、満足感につながっている。 iPhoneが発表されてから7年。モバイルアプリのUIはまだまだ進化し続けています。いや、楽しい。 *1 : NikeのFuel Band開発チームレイオフの噂も Secret から広まったようです
こんにちは、UE4に悪戦苦闘中の上津原です。 Rayの作成ができたので記事にしておきます。 Rayってなんじゃ? Rayとは 指定した一定距離内にオブジェクトがあるかどうか確かめるもの です。 オブジェクトががあればそのオブジェクトを取得できます。 これを応用すれば、遠くにあるものを動かしたりできるのです!ヒューカックイイ! 実際のBluePrint 実際作ったものはこちらです。 大きい画像はこちら ※今回のBPはFPSの状態を基本としています。 簡単な説明 基本として「Single Line Trace for Object」を利用します。これらに「どこから(Start)」「どこまで(End)」オブジェクトがあるか確認をするかを指定したり「何を認識するか」を指定したりします。 まずは「どこから」「どこまで」を作ります。First Person Cameraの位置を取得し作成します。 開始地点はカメラのWorld Locationで問題ありません。 最終地点は、Forward Vectorを取得しそれを乗算します。今回は500となっていますが、この乗算値がどれくらいの距離でRayを打つかが決まるので、任意で変えれば遠くでも近くにでも変更ができます。そしてその値をWorld Locationに足す。そうしないとカメラの位置からRayが飛ばされなくなってしまいます。 そして、Object Typesを指定しなくてはいけません。取得したい「Object Type」のArrayをセットします。今回は「WorldDynamic」を指定していますが、壁とか動かないモノを取得したい場合は「WorldStatic」にすれば検出するようです。 そして最後に、DrawDebugTypeを「ForDuration」に指定します。これは別にやらなくてもいいんですが、発射したRayが見えるようになるので開発中は出しておくと分かりやすいです。 ReturnValueには、成功、失敗のBoolが返ってきます。OutHitには、ヒット時の各種情報がまとまって返ってきます。これはそのままでは使えないのでBrakeして情報を分割しています。 これでRayは完成 これでPlayしてみると、以下のような変な赤い串のようなものが表示されるはずです。 ↓これは一度出してからわかりやすいように横から見ています。 この赤いラインがRayです。やったね! ここから持ち上げもついでに入れてみる 持ち上げるためのBlue Printは以下のようにしてみました。 大きい画像はこちら カメラにアタッチしたりデタッチしたりするだけです。 そうすると、こんな風になります。 まだ持ち上げているハコにPhysicsはつけてないのでちょっと不自然ですがこんな感じで動かせるようになりました。ちなみに、Physicsを持っているものはAttachできないので場だもう少し付け足しが必要になります。 Blue Print難しいけど面白い Blue Printって、理解しやすいやらそうじゃないやらわからない感じもしますけど、慣れてくるとなかなか楽しいもんですね~。 何かまた報告できるものができたら記事にします。それでは~。
こんにちは、上津原です。 最近Unityに加え、Unreal Engine4( https://www.unrealengine.com/ )も触り始めました。 Unityと使い勝手が違うので、チュートリアルを見て勉強しながら操作しているのですが、忘れないうちに記事にしてしまおうと思います。 Unreal Engineとは、 Unreal Engine(アンリアルエンジン)は、Epic Gamesより開発されたゲームエンジンである。1998年にファーストパーソン・シューティングゲーム (FPS) である『Unreal』で初めて実装された。 Wikipwdia はい、3Dゲームエンジンです。 僕自身、Epic Gamesの「 Gears of war 」がしたくてXbox360を買ったクチなので、使う前から存在自体は知っていました。 そのころから「スゲーな~、かっこいいな~」と思っていて、前職でスマホゲームとかに関わっていたときに「アンリアルとか使えたらかっこいいですよね」と気軽に言ったら「あんな高いもん使えるか!」と一蹴されたのはいい思い出です。 そんな「高くて使えるか!」と一蹴されていたUnreal Engineですが、なんと今なら 「毎日コーヒー1杯我慢すれば買える価格」 約月額2000円で使えてしまうのです(!) Unreal Engineのパワー 「でも2000円のゲームエンジンなんて、機能制限してるんじゃない?」なんて思われるかもしれませんがそんなことはなく、むしろ2000円でソースコードまで読めちゃう、ほんとにこれ2000円でいいの?と思っちゃうほどの充実っぷりです。 どんなクオリティのものができるのかというと、こんなかんじ Unreal Engine 4 Features Trailer -- GDC 2014 - YouTube ヒュー!ワンダフル! この性能が月額2000円だなんて本当にびっくりです! チュートリアルが動画なのが点数高い チュートリアルが動画で公開されています。 現時点で(2014/4/21)65本ものビデオチュートリアルが! https://www.youtube.com/playlist?list=PLZlv_N0_O1gaCL2XjKluO7N2Pmmw9pvhE 英語がわからない人でも、動画を見ながら同じようにマネをすれば、使い方が把握できます。 字幕も出しておけば「今なんて言った?」というのも読めばなんとなくわかるので非常に役立ちます。 そしてチュートリアルをやってみた結果がこちら これはチュートリアルの一番上にある「Creating a Level」を一通りやっていじくったものです。 これが触り始めて1日目でできちゃうのがすごい。ワンダフル! ほかにも面白い機能が いじくってて感動したのは、Directional Light(太陽)の角度を変えると、勝手に夕日などの表現がされることです。 左上の電球がDirectional Lightです。ライトの矢印は右下を指しています。 この状態でプレイをすると… このように空は青く、上の方に太陽が描画されます。 では今度は太陽の矢印を真横に向けて… プレイをしてみると まあきれいな夕焼け! 適当ににいじくってたらいきなりこれになったので、最初すごく感動しました。 UnityでRoom VRを作ったときはSkyBoxを変更していたのですが、その必要もなくなるのか?とちょっと期待できちゃいます。 豊富な機能 どんな機能があるのかなー?などは、以下のスライドが非常に役立つので見てみてください。 はじめてのUnreal Engine 4 from Shun Sasaki 私自身理解の及ばない機能が目いっぱいありますw どこまで使うかはさておき、全力で土下座するレベルなのはなんとなく伝わります。 Unityとのちがい そして気になるポイントは、Unityとどう違う?どっちが使いやすい?だと思います。 私の個人的な感触では以下のような感じです。 Unreal Engine 4が優れている点 光の表現がUnityより手軽に美しい表現ができる。 Blue Printの採用により、非プログラマでもプログラムが可能に。 安い!!! Unityが優れている点 コードでプログラムが書けるので、学習コストが低い。 コミュニティ活動が活発で資料が多い 無料版がある 簡単にまとめて言うと、 UE4は高性能で安いけど無料版はない。そして資料(特に日本語の)が少ないからちょっと苦労するかも。 Unityは無料版があって資料も多くてとっつきやすい。でもプロ版は16万円。 といった感じ。 使用感は慣れればいいと思うので、その辺は割愛します。 Unityはこれから5がリリース予定なのでそこでまた新たな局面も見えそうです。 そんな感じで今回はここまでです。 この値段で最高峰の3Dゲームエンジンが触れるのはとってもお買い得だと思うので、ぜひ気になってるなって人は使ってみるとよいと思います!
こんにちは 上津原です。 今回から実装編に入っていきます。 基本的に実装編では、各機能がどんなふうにできていったかを紹介していきたいと思います。 今回は 「朝~夜の日照のシミュレーション」 について話をしていきます。 OculusRiftでSkyboxがぶれて見える件 普通にUnityでやるようにSkyboxを設定すると、Riftを通してみたとき、タブって見えます。 これは、OculusRiftのSDKでは、立体になるように左右の目でちょっとずれた映像を出しているのですが、Skyboxに関しては左右が全く同じ映像が出ているため起きるようです。 ↑左右の立方体の市場微妙に違うが、空の表示はだいたい同じになっている。これだと立体視されない。 それの対応のため Stereoarts Homepage さんの、「SkyboxMesh.cs」を利用させていただきました。 これを利用することで、Skyboxがブレることなく表示することができました。 ↑左右の雲の描画にずれが生まれ、Riftでみてもぶれなくなっている。 使い方も非常に簡単で、カラのGameObjectを作成して、Skyboxmesh.csをそいつにドロップ。そうしたらInspector内にあるSkyboxの部分に表示したいSkyboxを設定すれば表示が可能です。この際、あらかじめ設定していたSkyboxの設定は抜いておきましょう。 ちなみに、ここでSkyboxを指定した時点ではSceneでSkyboxは表示されません。実行時に描画がされるので何も見た目が変わらなくても大丈夫です。 時間帯の変更について 今回のアプリケーションでは、朝、昼、夕方、夜の4つの時間帯の体験が可能です。これらはDirectional Lightの向き、強さ、色変更と、Skyboxの変更を行っています。 つくりは非常に簡単で、Directional Light用のScriptを作り、そこから向き、強さ、色の変更と、上で紹介したSkymapmeshへとアクセスし光の具合を変更しています。 こんな感じであとからでも把握しやすいように各マテリアルはインスペクタに表示されるよう作っています。 ちなみに角度はそれぞれ固定となっています。 最終的には、太陽の動きを日付や時間帯を指定することでリアルな太陽光のシミュレーションができるようにしたいと思っています。 影の描画について 今回は、PCスペックの都合上影の描画はDirectional Lightのみとしており、室内の光に関しては影の生成が行われない作りとなっていました。 その結果、いまいちリアルな描写ができていないという現状があるため、ここもPCスペックの見直しを行い、室内光源からの影の描写なども対応予定です。 最も苦労した点 Skyboxmeshへのアクセスでした。SkyboxmeshはC#で書かれており、こちらのスクリプトはJavaScriptだったため、どのようにアクセスをすればいいか?という点が一番の問題でした。 そこで、Skyboxmeshに以下のコードを追加させていただきました。こうすることで外からSkyboxマテリアルを渡すことでSkyboxを変更できるように対応しました。 gist9952286 気を付けるべき点は、「skymesh」というタグがついたオブジェクトをいったんすべて削除しなくてはならない点です。 削除せずに変更をしようとすると見た目は変わってくれませんので、そこに気をつけなくてはいけないです。 これがでができてしまえばあとは簡単で、Javascriptから、 var skyboxMeshObj : GameObject = GameObject.FindGameObjectWithTag("SkyBox"); var skyBoxMesh : SkyboxMesh; skyBoxMesh = skyboxMeshObj.GetComponent("SkyboxMesh"); skyBoxMesh.Change(noonSkybox); などしてやれば変更ができます。(Skyboxmeshの入っているオブジェクトには「Skybox」タグがついています) 日あたりは部屋にとって大事なステータス みなさんも賃貸などを選ぶときに、日当たりは重視されるかと思います。 ここがよりリアルになれば、VRでの物件選びへの道が大きく前進すると思います。今後日当たりはより現実に近いものにしていきたいですね。
Apple原理主義者の大坪です。 さて、Facebookが公開した「インタラクションデザインのPhotoshop」Origamiについて 使い方を書いてみた ものの 「そもそも誰が読んでくれるのか」 と疑問に思っていたのも事実。少なくとも一人は読んで、動かしてしかも初期バージョンの間違いまで指摘してくれたことに意を強くし、次には 「もう少し実際的な例を説明しなくていいのか」 という強迫観念にとらわれ始めたわけです。 というわけでOrigamiのサンプル第2弾は「コンテンツをスクロールして、一番上までいくとツールバーがにゅいっと隠れたり出たりする」です。具体的にはこんなのです。 ちょっと縦横比が狂ってくる気がしますが、気のせいです。細かい事を気にしすぎると折角の春の訪れに気がつかないかもしれませんよ(言い訳)こういう風に動くものを作れると 「ほら、こうやってスクロールしていくとこのメニューがにゅいっと隠れて、下にスクロールするとまたでてきて。いや、これは”にゅいっ”じゃなくて”すっ”でちょっとイメージが違う」 とか不毛な言葉によるやりとりをしなくてもいいと思うのです。 さて、あとで学位を返上しろとか言われると困るので最初に白状しますが、今回説明する内容は Prototyping with Facebook Origami にほんの少し修正を加えたものです。自分なりにアレンジしようとかあれこれ考えたのですけど、元の動画が非常に良くできており、変な事やるとかえって読んでくれた方の理解を損なうと判断しました。 というわけでお前のわけのわからん文章など読んでられるか、というかたは 元コンテンツ を参照していただくことにして、やおら説明を始めるのです。 とにかく画像を表示 OrigamiをインストールしたQuartz Composerを立ち上げましょう。それは何のことだ?というかたは 前回の記事 を参照してください。 でもって以下の図のところまで同様に作ってください。空のiPhoneイメージが表示されてるけど、これからRender in Imageパッチの中身を作らなくちゃね、というところまでです。 ここまでできたら、Render in Imageパッチをダブルクリックし、中身を作って行きましょう。 まず表示する画面のパーツを作ります。最初にClearパッチを追加します(これを忘れると妙なことが起こります) 今回作る物は三つの部品から構成されています。 Header(一番上の部分です) Toolbar(Headerの下にあり、コンテンツをスクロールすると出たりかくれたりする部分) Feed(Facebookのタイムラインみたいで、上下にスクロールする部分) Github においてあるファイルの中のassetsフォルダを観ると、その中に三つの画像があります。Render in ImageをダブルクリックしたEditor画面にHeader.pngファイルをドラッグ&ドロップしましょう。するといきなりImageパッチとそれに接続されたLayerパッチが現れ、ViewerのほうにはHeaderの画像が真ん中に表示されます。 ををこれは簡単だ、というわけで調子にのって残る二つの画像をドラッグ&ドロップします。また忘れないうちにそれぞれのLayerパッチの名前を部品の名前に変更しておきましょう。パッチの一番上にある"Layer"という文字をダブルクリックすると名前が変更できます。 こんな風になるはずです(ドラッグ&ドロップの順番によっては、表示が少し異なるかもしれませんが、気にすることはありません) なんだか景気よく画像が表示されましたが問題が二つ。第一に位置がみんな真ん中になっている。第二に最初に追加したはずのHeaderはどこに行ってしまったのか。 まず2番目の問題から直しましょう。これは一回目にも書いた「表示順」の問題です。(画面クリアを除いて)一番下(というか裏側)に表示されてほしいものから順番に番号を設定して行く必要がある。この場合一番下にあるべきはFeedです。というわけで Clear:1 Feed:2 Toolbar:3(Toolbarは後でHeaderの下に隠れてほしいのでこの順番です) Header:4 という風に、パッチ左上の数字を設定します。するとHeaderの画像は確かにFeedの上に表示されるようになったけど、まだ真ん中にごちゃっとしている。 というわけで、各パーツの表示位置を修正していきます。さてどこをどう設定すればよいでしょう? それを調べるために、ツールバーの"Parameters"というボタンを押します。すると画面右側にこんな画面が現れる。 今編集しているのは、Render in Imageパッチの中身です。でもってこの表示を信じれば、そのサイズは幅640,縦1136らしい。これはiPhone5の画面サイズのそのものです。 Quartz composerでは画面の中央が座標の原点(0,0)で、画像の位置は中心座標で指定するようです。Header画像の大きさは640 x 128ですから、これが一番上に表示されるためには,,, (1136 ÷ 2)- (128 ÷ 2) = 504 というわけで、Headerを表示しているLayerパッチの Y Positionに504を設定しましょう。するとめでたくHeadrの画像が一番上に行く筈です。ToolBarはHeaderの下にあり、かつ高さが88だから 504 - (128÷2) - (88÷2) = 396 というわけでToolbarのY Positionに396を設定します。これでめでたくそれっぽい表示になりました。 画像を眺めながらしばし満足感に浸ります。ああ、長い道のりだった。しかし遠からず 「まだ全然動かないじゃないか」 という厳然たる事実に直面することになる。ではここから動きをつけましょう。 とにかくスクロール まずFeed画面をスクロールさせましょう。そのためにPatch LibraryからScrollというパッチを探してEditorに追加します。 それでもって以下のようにつなぎます。 Scrollパッチの右上にある○からFeedパッチの左上にある○に。 FeedにつながっているImageパッチのImageからScrollのImageに ScrollのY PositionからFeedのY Positionに。 つなぎ終わるとこん感じになります。 この段階でViewerを表示させ、Feedのところをマウスでドラッグしてみましょう。ちゃんとスクロールするはずです。 今回はY方向(つまり縦方向)だけのスクロールなので線を一カ所だけつなぎましたが、例えば縦横方向に自由にスクロールさせたければ、ScrollのX PositionからFeedのY Positionにつなげばよいです。:すいません。この部分記述が間違ってました。お詫びして削除します。 なんでImageの出口を二手に分かれてつなぐ必要があるのかなあ、と30秒ほど悩みましたが、多分Scrollの内部でイメージの大きさを調べてよしなにスクロールさせているのでしょう。 さて、ここで私が2回やった失敗です。Quartz Composer字が小さいですよね。少なくとも私のような年の人間にとっては細かい。目が見えなくなってくると「だいたいこんなんでいいんでないかい」と適当にやる作業が増えます。というわけでScrollのY Positionから出た線をFeedの "Y Position" ではなく "Y Rotation" につないでしまったのでした。すると何が起こるか?上下にスクロールさせようとドラッグするとFeedの絵がぐりんと回転します。慌てて正しい入り口につなぎ直すがまだ表示がおかしいまま。こういう時は、Feedパッチを選んだ状態でPatch Inspectorを開き、Y Rotationの値を0に設定しましょう。 Toolbarをにゅいっと隠す さて、めでたくFeedがスクロールするようになったので次には「スクロールしていくとツールバーがにゅいっと隠れる」動きを実現しまししょう。 まず一回目でも使ったTransitionパッチを追加します。このTransitionパッチというのは、Progressという値を0から1に設定するとそれに応じて望んだ範囲の値を出力してくれるものでした。今はToolBarの位置を合わせるためにY Positionに396を設定していました。この値をTransitionのStart Valueに設定します。ToolBarイメージの高さは88ですから、End Valueを484にしましょう。そしてTransitionのValue出口をtoolBarのY Positionにつなぎます。 この状態で一つ実験してみましょう。Transitionを選んだ状態でPatch Inspectorを開きProgressという値の横にある丸いものをぐりぐり回してみましょう。Progressの値が変化するとともに、Viewerの中のToolBarの位置が変わることがわかると思います。 つまりToolBarを動かす為には、「何かのきっかけで0と1の値を切り替える」ことができればよいことになります。さてどうしよう。 ここでConditionalパッチをEditorに追加しましょう。Patch Inspectorを使って中身をみると "First ValueがSecond Valueに対して<いろいろな条件>ならば" と書いてあるような気がします。条件が変わればConditionalパッチの出力が変わるのでしょう。よし、っというわけででConditionalのResultをTransitionのProgressにつなぎます。ちょと待て、ResultをProgressにつないでいいのか?なんだか言葉違うけど。 パッチの説明を読むとConditionalパッチの出力は真(True)か偽(False)からしいのですが細かい事は気にしない。計算機が本当にやっているのは2進数の計算でその世界では1が真で0が偽。だったら細かい事には目をつぶってつなげるはず。ではどういう条件が満足された時にこの値を切り替えるか。 やらんとしていることは「Feedがスクロールして行って上の方にいったらToolbarを隠す」ことです。この「スクロールして上の方に行ったら」とは具体的にどういうことか。実際にやってみましょう。Feedパッチを選んだ状態でPatch Inspectorを開く。Viewerの中でFeedを上下にやってPatch InspectorのY Position欄の値が変わるのを観ましょう。 Feedが上にいくとY Positionの値が増えることがわかると思います。というわけでなんとなく「ここらへんでToolbarが引っ込んでほしい」と思う値を覚えておきます。 さて、Conditionalパッチに戻ります。ScrollからY PositionをひっぱっていってConditional パッチのFirst Valueにつなぎます。そしてSecond Valueには先ほど覚えた「ここらへんでひっこんでの値」(ここでは-520にしています)を。そしてConditionのところには"Is Greater Than"を選びます。ScrollのY Positionの値が-520より大きくなったら出力の値が1になるわけです。 でもってConditionalパッチの出口をTransitionパッチのProgressにつないでやる。Viewerでタイムラインをスクロールさせてみましょう。タイムラインが上にいくとToolBarが隠れ、下に戻すと再度表示されることがわかると思います。 わーいできた、と喜ぶのは少し早い。確かにToolBarは出たり隠れたりするのですが急に出たり消えたりする。やりたかったのは「にゅいっ」と出たり入ったりすることでした。ではどうしよう。ここで「にゅいっ」を実現してくれるClassic Animationというパッチを追加しましょう。 これをさっきエンジニア的良心の呵責を覚えながら直接つないだConditionalとTransitionの間にいれてやります。具体的には ConditionalパッチのResultをClassic AnimationパッチのNumberにつなぐ Classic AnimationパッチのProgressをTransitionパッチのProgressにつなぐ これが今回の最終形です。 Viewerを使ってスクロールしてみましょう。さっきは「がっこん」と出たり消えたりしていたToolbarが「にゅいっ」と出たり入ったりするはずです。 さきほどいれたClassic Animationというパッチを選んでPathc Inspectorを開きます。DurationとCurveという値が設定できることに気がつきます。Durationというのはアニメーションが行われる時間。たとえばこれを2にするとものすごくゆっくりToolbarがでたりはいったりします。Curveはアニメーションの「にゅいっ」具合を変えるものです。正直それぞれの言葉にどういう意味があるかわかっていません。私はこのパラメータをあまりいじった事がありませんが、きっと良いデザイナーはこのCurveの種類にこだわるのだと想像します。 というわけで、いつも作業しているマシンがお亡くなりになってしまった失望のあまり書いてしまったOrigamiの使い方講座その2でございましたがいかがでしょう。今回くらい動いてくれるとなんだか 「これでインタラクションデザインができる!」 という気分になりますよね。ね。ね。(ウザい) エンジニアとしては時々「こんなに苦労してOrigami覚えるなら、Objective-Cで書いたほうが早い!」と叫びたい衝動にも駆られるわけですが、そこはぐっと我慢。きっとこのOrigamiはインタラクションデザイナーとエンジニアの共通言語に成りうると信じたい訳です。 「えーっ、これ想像していた動きと違う!」 というデザイナーの叫びと 「なら最初からそう言ってよ!」 というエンジニアの怨嗟の声が少しでも減らせるのではないか。とはいっても叫び声自体の回数は大して減らず内容が 「えーっ、この動きOrigamiのと違う!」by デザイナー と 「なら自分でプログラムしてみろよ!」by プログラマー に代わるだけかもしれませんが。
Apple原理主義者の大坪です。 「Google先生に"Facebook Paper Origami"+日本語記事でお伺いをたてた結果が何故これほど少ないのか」 と疑問に思う今日この頃です。ひょっとして私一人だけが錯乱しているのでしょうか。 という根本的な疑問からは目をそらして、昨日見つけた文章について紹介します。 Paperでもっともわかりやすい「新インタラクション」はiPhoneを傾けることで、画面より大きな画像を閲覧する“tilt-to-explore”でしょう。(下の動画の52秒あたりから) それが初めて披露された時の様子は以下のようだったとのこと。 “Everyone’s jaws just dropped,” remembers Michael Reckhow, who was sitting beside Matas that afternoon. “Everyone started exchanging these glances that were like: ‘What did he just do?’” 引用元: Facebook Paper Has Forever Changed the Way We Build Mobile Apps | Wired Enterprise | Wired.com いいかげんな訳:Matasの隣に座っていたMichael Rechhowはこう語る。「みんな顎が外れるほど驚いた。お互い顔を見合わせて”今彼はなにをやったんだ?”と言わんばかりだった」 しかしここで驚くべきはその結果だけではない。"tilt-to-explore"を開発したMike Matasはプログラマーではなく、Objective-Cは知らない。彼はOrigamiを使ってそのプロトタイプを作り上げたのです。 プロトタイプ作成にOrigamiを使うことのメリットは、このように表現されています。 “With your typical programming language, you have to type in a bunch of code and hit ‘compile,’ and a minute later, you see what you built,” he says. “It’s almost like you’re trying to learn how to play the piano and you have a piano where you hit a couple of keys and then hit a compile button and a minute later you hear what you played.” Origami changes this. 引用元:前掲記事と同じ 普通のプログラミング言語では、山ほどコードを書いて「コンパイルボタン」を押す。すると一分後にその結果をみることができる。これはまるでピアノの練習をしているのに、鍵盤を叩いてから一分後に音が聞こえるようなもんだ。Origamiはこれを変えた。 OrigamiはQuartz Composerで作られており、パラメータやパッチ(「何か」をしてくれる単位です)の結合やパラメータを変更すれば、即座にその結果が動作に反映される。このツールを使っての"tilt-to-explore"の開発はこんな風に行われたとのこと。 Matas had the idea one evening at home — after attempts to add an automatic “Ken Burns effect” to Paper failed to, well, pan out — and the next morning, he spent a few hours mocking it up with Origami. 引用元:前掲記事と同じ 自動的に Ken Burns Effect がつくような機能を実現しようとして失敗した後、 Matasは家で良いアイディアを思いついた。そして次の朝数時間作業してOrigamiのtilt-to-exploreのモックを作り上げた。 さて、ここからは 「そうかー。デザイナーの皆さん、Origami使ってがんばってねー」 と他人ごとのように考えていたエンジニアの皆さんの顔が青くなるような話がでてきます。 Paperの実装方法を考えていて気がついたのですが、あのアプリは見かけよりずっと複雑にできている。少なくともApple標準部品を持ってきて「はいできました」という類のものではない。 *1 Engineer達は、そのアプリを作り上げるためにOrigamiとは別のTool-Tweakという名前-を作り上げたそうです。(このツールはまだ公開されていません) There are times when the app runs literally dozens of physics simulations that all work in concert — Grant worked on an animation that involved 42 virtual springs — and Tweaks provides a way of instantly changing the behavior of each and every one of these simulations. 引用元:前掲記事と同じ アプリ内部ではお互いに協調しあう物理シミュレーションが何ダースも同時に動いていることがある。例えばGrantは仮想的なバネが42個必要なアニメーションを作ったことがある。Tweakを使えば、そうした計算のパラメータを即座に変更することができる。 初期バージョンのPhoto Viewerは、車の中で使うと振動やら加速度で変な動きをしたとのこと。 “When we first built it, it felt pretty good in your hand,” he says. “But we noticed that, the more places we took it, it began to fall apart.” With Tweaks, as he rode home on the Facebook shuttle, he could instantly adjust and readjust the filters used to eliminate any irrelevant movement, identifying what worked and what didn’t without having to rebuild and recompile. 引用元:前掲記事と同じ 最初に作った時、普通に使うぶんには上手く動いた。しかしいろんな場所で使ってみると問題が見つかった。帰宅するために乗っていたFacebookシャトルバスの中で、Tweakを使いコンパイルなしでフィルターの調整を行い、何がうまくいって何がうまくいかないかを見つけることができた。 シャトルバスの中でそんなデバッグしたら車酔いするじゃないか、とか言っている場合ではありません。まだ観ぬtweakを使えば、どこでもパラメータチューニングができてしまうのです。つまり彼らは 「こんな複雑なモデルのデバッグは大変だから、モデルを簡単にしよう」 ではなく 「こんな複雑なモデルのデバッグは大変だから、デバッグを簡単にするツールをつくろう」 と考え実際に作ったわけです。 Ok, エンジニア同士諸君。話はまだ終わっていない。 このように、Paperの動作は、かなり複雑な計算の上に成り立っているので通常のアプリの作り方ではうまく動かないとのこと。UIに関連するタスクは全て同一CPUコアで動かし、他のタスクは別のコアに任せる必要があります。そうした「タスク毎のCPUコアへの割当」を柔軟に行うため、彼ら自身でアプリエンジンを開発したそうです。(名前はないそうですが) この(名無しのアプリエンジン)を使えば、どのタスクをどのコアに割り当てるかが細かく制御できる。これによって、写真をスクロールしていくときに、前の写真がまだ開き終わってないうちに処理を中断し、別のCPUコアでデコードした画像をスムーズに表示できるとのこと。つまり彼らは 「このインタラクションは今のCPUじゃスムーズに動かないから、止めよう」 ではなく 「このインタラクションは今のCPUじゃスムーズに動かないから、動かす為のエンジンを作ろう」 と考え、実行した訳です。 彼らが作り上げたツールはOrigamiだけではなかったのですね... などと書いているとだんだん気が滅入ってきます。あれですよ。 マリアナ沖海戦 の前に日本の造船所で一生懸命空母を作っちゃいるけれど、太平洋の向こう側では一週間に1隻空母が竣工していたような状況を思い浮かべたりするわけですよ。 いや、大丈夫。別に我々はFacebookと喧嘩をしているわけではない。Tweakや(名無しのアプリエンジン)もいつかきっとOpen Sourceとして公開されることでしょう。それらを使い、デザイナーとエンジニアがideaと知恵を合わせれば、きっとPaperチームが「公開するんじゃなかった」と後悔するようなインタラクションが実装できるに違いない,,と無理矢理かつ前向な言葉をもってこの文章を締めくくるのでした。 *1 : 具体的にどう複雑かは こちらのページ を参照してください。
古川です。 前回 から少し時間がたってしまいましたが、独自ソートを実現の続きで、search component plugin を使って実現する方法を、二回に分けて紹介します。solr が持っている検索の機能をすべて満たした実装は難しいので、 他のコンポーネントとの組み合わせ グルーピング処理 分散検索 はあきらめて、とにかく検索にヒットしたドキュメントを望みの順番で返すことができるsearch component を作成することを目的とします。 今回はまず、solr の search component plugin の作り方を紹介します。前回と違い、とりあえずこうすれば動いたという感じなので、間違えている点あれば、ご指摘いただければ幸いです。 Search Component の作成 solr におけるデフォルトの検索コンポーネントは、SearchComponent クラスを継承して実装されています。 solr/core/src/java/org/apache/solr/handler/component/SearchComponent.java SearchComponent.java のコードを見ると、以下4つの関数を実装すればよいことが分かります。 public abstract void prepare(ResponseBuilder rb) throws IOException; public abstract void process(ResponseBuilder rb) throws IOException; public abstract String getDescription(); public abstract String getSource(); 次に、Solr の検索コンポーネントの本体 QueryComponent.java をベースに、分散と、グルーピングに関連する部分を除いたクラス MyQueryComponent.java を作成します。 solr/core/src/java/org/apache/solr/handler/component/QueryComponent.java package jp.co.homes.searchcomponent; import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.Query; import org.apache.lucene.search.ScoreDoc; import org.apache.solr.client.solrj.SolrServerException; import org.apache.solr.common.SolrDocument; import org.apache.solr.common.SolrException; import org.apache.solr.common.params.*; import org.apache.solr.common.util.NamedList; import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.response.ResultContext; import org.apache.solr.response.SolrQueryResponse; import org.apache.solr.schema.FieldType; import org.apache.solr.search.QParser; import org.apache.solr.search.QParserPlugin; import org.apache.solr.search.QueryParsing; import org.apache.solr.search.ReturnFields; import org.apache.solr.search.SolrIndexSearcher; import org.apache.solr.search.SolrReturnFields; import org.apache.solr.search.SyntaxError; import org.apache.solr.handler.component.SearchComponent; import org.apache.solr.handler.component.ResponseBuilder; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.List; public class MyQueryComponent extends SearchComponent { public static final String COMPONENT_NAME = "my_query" ; @Override public void prepare(ResponseBuilder rb) throws IOException { SolrQueryRequest req = rb.req; SolrParams params = req.getParams(); if (!params.getBool(COMPONENT_NAME, true )) { return ; } SolrQueryResponse rsp = rb.rsp; ReturnFields returnFields = new SolrReturnFields( req ); rsp.setReturnFields( returnFields ); int flags = 0 ; if (returnFields.wantsScore()) { flags |= SolrIndexSearcher.GET_SCORES; } rb.setFieldFlags( flags ); String defType = params.get(QueryParsing.DEFTYPE, QParserPlugin.DEFAULT_QTYPE); String queryString = rb.getQueryString(); if (queryString == null ) { queryString = params.get( CommonParams.Q ); rb.setQueryString(queryString); } try { QParser parser = QParser.getParser(rb.getQueryString(), defType, req); Query q = parser.getQuery(); if (q == null ) { q = new BooleanQuery(); } rb.setQuery( q ); rb.setSortSpec( parser.getSort( true ) ); rb.setQparser(parser); rb.setScoreDoc(parser.getPaging()); String[] fqs = req.getParams().getParams(CommonParams.FQ); if (fqs!= null && fqs.length!= 0 ) { List<Query> filters = rb.getFilters(); filters = filters == null ? new ArrayList<Query>(fqs.length) : new ArrayList<Query>(filters); for (String fq : fqs) { if (fq != null && fq.trim().length()!= 0 ) { QParser fqp = QParser.getParser(fq, null , req); filters.add(fqp.getQuery()); } } if (!filters.isEmpty()) { rb.setFilters( filters ); } } } catch (SyntaxError e) { throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e); } } @Override public void process(ResponseBuilder rb) throws IOException { SolrQueryRequest req = rb.req; SolrQueryResponse rsp = rb.rsp; SolrParams params = req.getParams(); if (!params.getBool(COMPONENT_NAME, true )) { return ; } SolrIndexSearcher searcher = req.getSearcher(); if (rb.getQueryCommand().getOffset() < 0 ) { throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "'start' parameter cannot be negative" ); } long timeAllowed = ( long )params.getInt( CommonParams.TIME_ALLOWED, - 1 ); SolrIndexSearcher.QueryCommand cmd = rb.getQueryCommand(); cmd.setTimeAllowed(timeAllowed); SolrIndexSearcher.QueryResult result = new SolrIndexSearcher.QueryResult(); searcher.search(result,cmd); rb.setResult( result ); ResultContext ctx = new ResultContext(); ctx.docs = rb.getResults().docList; ctx.query = rb.getQuery(); rsp.add( "response" , ctx); rsp.getToLog().add( "hits" , rb.getResults().docList.matches()); } @Override public String getDescription() { return "my query component" ; } @Override public String getSource() { return "$URL: dummy $" ; } } コンパイル 以下のjarファイルにpathを通して、上記ファイルをコンパイルして、homes-serch-component.jar を作成します(jar ファイル名は何でも構いません) solr-4.6.1/example/solr-webapp/webapp/WEB-INF/lucene-core-4.6.1.jar solr-4.6.1/example/solr-webapp/webapp/WEB-INF/solr-core-4.6.1.jar solr-4.6.1/example/solr-webapp/webapp/WEB-INF/solr-solrj-4.6.1.jar 設定 前回同様、作成したjarファイルをcollection1フォルダのlib以下にコピーします。 cp homes-function-search-component.jar solr-4.6.1/example/solr/collection1/lib solrconfig.xml の、hilighting コンポーネント設定の後に、今回作成した MyQueryComponent にアクセスするための設定を追加します。これで、 http://localhost:8983/solr/collection1/my_select にアクセスするとMyQueryComponentにクエリが渡されるようになります。 <searchComponent class = "solr.HighlightComponent" name = "highlight" > <highlighting> <!-- 省略 実際にはhighligの設定がある--> </highlighting> </searchComponent> <!-- 追加分 --> <searchComponent name = "MyQueryComponent" class = "jp.co.homes.searchcomponent.MyQueryComponent" /> <requestHandler name = "/my_select" class = "solr.SearchHandler" > <arr name = "components" > <str> MyQueryComponent </str> </arr> </requestHandler> 動作確認 solr を起動します。solr には前回投入したインデックスが既に存在していると仮定します。 cd ./solr-4.6.1/example java -jar start.jar & 通常のsolr検索selectと、新しく作成したmy_selectの検索結果が同じであることを確認します。 select http://localhost:8983/solr/collection1/select?echoParams=none&q=*:*&fl=x,y,myfunc(x,y,1,2,3,4,5,6)&sort=x asc,y desc <result name = "response" numFound = "1000006" start = "0" > <doc> <str name = "id" > id828205 </str> <float name = "x" > 0.0 </float> <float name = "y" > 999.0 </float> </doc> <doc> <str name = "id" > id91438 </str> <float name = "x" > 0.0 </float> <float name = "y" > 998.0 </float> </doc> <doc> <str name = "id" > id628349 </str> <float name = "x" > 0.0 </float> <float name = "y" > 998.0 </float> </doc> </result> my_select http://localhost:8983/solr/collection1/my_select?echoParams=none&q=*:*&fl=x,y,myfunc(x,y,1,2,3,4,5,6)&sort=x asc,y desc <result name = "response" numFound = "1000006" start = "0" > <doc> <str name = "id" > id828205 </str> <float name = "x" > 0.0 </float> <float name = "y" > 999.0 </float> </doc> <doc> <str name = "id" > id91438 </str> <float name = "x" > 0.0 </float> <float name = "y" > 998.0 </float> </doc> <doc> <str name = "id" > id628349 </str> <float name = "x" > 0.0 </float> <float name = "y" > 998.0 </float> </doc> </result> グルーピングや、分散検索以外は同じはずなので、当たり前ですが同じ結果が取得できています。 次に、グルーピングを行うクエリを実行してみます。 select http://localhost:8983/solr/collection1/select?group=true&group.field=x&echoParams=none&q=*:*&fl=x,y,myfunc(x,y,1,2,3,4,5,6)&rows=2 <lst name = "grouped" > <lst name = "x" > <int name = "matches" > 1000006 </int> <arr name = "groups" > <lst> <float name = "groupValue" > 1.0 </float> <result name = "doclist" numFound = "997" start = "0" > <doc> <float name = "x" > 1.0 </float> <float name = "y" > 4.0 </float> <float name = "myfunc(x,y,1,2,3,4,5,6)" > 87.0 </float> </doc> </result> </lst> <lst> <float name = "groupValue" > 2.0 </float> <result name = "doclist" numFound = "975" start = "0" > <doc> <float name = "x" > 2.0 </float> <float name = "y" > 5.0 </float> <float name = "myfunc(x,y,1,2,3,4,5,6)" > 138.0 </float> </doc> </result> </lst> </arr> </lst> </lst> my_select http://localhost:8983/solr/collection1/my_select?group=true&group.field=x&echoParams=none&q=*:*&fl=x,y,myfunc(x,y,1,2,3,4,5,6)&rows=2 <result name = "response" numFound = "1000006" start = "0" > <doc> <float name = "x" > 1.0 </float> <float name = "y" > 4.0 </float> <float name = "myfunc(x,y,1,2,3,4,5,6)" > 87.0 </float> </doc> <doc> <float name = "x" > 2.0 </float> <float name = "y" > 5.0 </float> <float name = "myfunc(x,y,1,2,3,4,5,6)" > 138.0 </float> </doc> </result> グルーピング関連の部分を削除したので、my_select の方は、groupを指定しても、通常の検索が行われていることが分かります。 まとめ グルーピングや分散処理を除けば、SearchComponent は意外とシンプルな構造でした。次回は、MySearchComponent.java に 以前 紹介した 自作のCollectorクラスを使う方法を組み込んで、独自ソートを実現します。
サムです。前回の「 GameController.frameworkをつかってG550ゲームパッドとSpriteKitゲームを接続してみよう 」に引き続き今回は、接続したG550のボタンに応じたイベントを取得してみます。 0. 前回まで GameController.frameworkをつかってG550ゲームパッドとSpriteKitゲームを接続してみよう 1. ポーズ&リスタート(一時停止と再開)のイベント まず、すべてのゲームコントローラには、ポーズボタンがあります。 このボタンはほとんどのゲームでは、ゲームの一時停止、および再開というイベントが走ると思います。 このイベントには、コントローラオブジェクトの controllerPausedHandler プロパティにブロック処理を追加することで可能になります。 GameController.framework自体には、ゲームの一時停止におけるユーザインターフェースは提供されていません ポーズボタンを押したときのゲーム停止などは、自分たちで実装する必要があります。 2. A/B/X/Yボタン、Dパッド、L/Rトリガーのイベント 今回使用しているゲームコントローラは G550 です。このコントローラは GCGamepad クラスを使います。 他にも GCExtendedGamepad クラスというGCGamepadクラスと比べると、ボタン数が多いゲームコントローラもあります。 すべてのボタンのイベントを取得するには、 GCGamePad オブジェクトの valueChangedHandler プロパティにブロック処理を追加するだけです。 この処理では、ボタンが押されるたびにイベントが発生して、押されたボタンの処理が実行されます。 ボタンの同時押しなどのイベントを設定したいときにつかいましょう ボタンごとのイベントを設定したい場合は、ボタンオブジェクト自体に valueChangedHandler プロパティにブロック処理を追加するだけです。 これで、ボタンのステータスを見張ることが出来ます。 まとめ ゲームコントローラは、 GCGamePadクラスだけではなくGCExtendedGamepadクラスも必ず実装 しましょう 何のコントローラを使うかは、ユーザが決めることですからね。 これらのソースコードは GitHubで公開 しております。 参考、引用元 Apple Developer - Game Controller Programming Guide
こんにちわ、社内でアジャイル推進をしている非エンジニアな鈴木です。 2014/3/19 第2回「 Scrum Masters Night(スクラムマスターズナイト) 」の参加レポートです。 今回はヤフー株式会社さんのオフィスで開催、同会場で行われた懇親会もスポンサー付きで「タダ!」これは参加するしかありません。ということで行ってきました! 基本的に 第一回目 と同じオープンスペース方式で行われました。 今回は最初のテーマとして、 チームのメトリクスについて スプリントゴール(ストーリー)どうしてますか? スクラムマスターのキャリアパス チームがプロセスを気にするためにどうすればよいか? が選ばれました。 どれも気になるテーマではあったのですが、「スクラムマスターのキャリアパス」を選択しました。 スクラムマスターのキャリアパス まずテーマの背景としてあったのが、同じような役割の人を増やしたいが、スクラムマスターの先のキャリアが見えない。 キャリアを重ねた先に個人として、会社として何があるのか?という疑問です。 スクラムマスターには次の2タイプがいると思います。 チーム中からスクラムマスターという役割をまかされたタイプ 推進役やコーチとしてスクラムマスターを専任しているタイプ どちらも初期段階はチームを成功に導き、スクラム開発を導入していく。 そして、少しずつスケールを大きくしていく。コーチであれば、後任者を育てるなどなど。 けれど、そうして導入が済み自己組織化が完全にされたら、スクラムマスターの仕事はなくなります。 とすると、元のエンジニアやプランナーに戻るのか?また新たな現場を求めてさまよい歩くのか? (完全な自己組織化というのがあり得るかはおいといて・・・。) なんだか、やっぱり先が見えませんスクラムマスター。 スクラムマスターの役割 スクラムマスターはどんなチームや組織で役割を果たしているのか、何をしているかという点についても話しをしました。 スクラムマスターは手法が目的にならないように、 スクラムのプロセスを守る人 チームを新しい方向に導いて行く人 チームがよい仕事が出来るようにする人 外的要因からチームを守る人 などと、一般的に言われています。 スクラムマスターは、チームの実行力や自己組織化を高めていくのが役割です。 ※但し、チーム内でリーダーシップを発揮してはならない。 そして、「※」の部分が重要で、従来型のリーダーとは異なったファシリテーション能力とコミュニケーション能力が求められます。また、なにか具体的な成果物というものは生み出しません。 スクラムマスターのスキルパス そんなスクラムマスターに求められるスキルパスはどんなものでしょうか? スクラム開発を含めたさまざまなフレームワークに関する知識 CIや開発基盤を改善する手法に関する知識 Fearless changeや組織パターンなどの組織に関する知識 コーチング、ティーチング、メンタリング、ファシリテーションの能力 謙虚さ 人たらし 組織やチームからの信頼 などなど、プロジェクト管理に必要な知識、相手を気持ちよく動かすことができる能力と気持ちを引き出すコミュニケーション能力が必要であるという意見が出てきました。 最終ゴールはマリッサ・メイヤー? では、そんなスクラムマスターのゴールは何でしょう? Dreamforce 2013の記事 でYahoo!CEO マリッサ・メイヤーが、自身の仕事についてこんな風に語っていたのが印象に残っています。 なにか大きなプランを立てて、それを社員にやらせるということではなく、どんなアイディアがあるのかを聞き、アイディアを実行するように許可するのが私の役割。 道をクリアにし、障害物を取り除き、仕事がやりやすいような環境を作ること。チームが攻撃をして、エグゼクティブがディフェンスをすることが理想の姿 なんだかこれってスクラムマスター的ではありませんか? スクラムマスターをつきつめていくと、チームのあり方だけではなく組織のあり方というところも考えなくてはなりません。 CEOは究極ですが、人材育成、評価制度、組織変更といった「組織のデザイン」まで行うのが最終目標かもしれません。 やはり社外の方との交流は楽しい いろんなバックグラウンドの方と同じテーマで語ると、それまでとは違った視点を見つけることができたり、自分の考えの整理や裏付けができます。 この経験をその場限りのものにせず、次のステップへつなげていくことができるようになればと思いました。 スポンサーの耳元でささやいてくださった 高橋さん 、運営者のみなさま、参加者のみなさま、楽しい時間をありがとうございました! 次回は、4月21日に開催予定。 もちろん次回も参加したいです。ですが、いつか弊社でも開催したいっ!などと、次のステップへつなげるための発言を残しつつ、今回のレポートを終わりたいと思います。