Articles tagged with: ライフログ

息吹


私が書店でSFの新刊本を、しかもハードカバーで購入するのは初めてかもしれない。
本書はその中でお勧めされていたので購入した。
とてもよりすぐりの九編が続く本書は、二度読んだほうが良さそうだ。
特に、一度目を読むタイミングが集中できない環境にあった場合は。

私も本稿を書くにあたってざっと斜め読みした。
すると、本書の奥深さをより理解できた。

「商人と錬金術師の門」
本編を一言で表すとタイムワープものだ。
だが、その舞台は新鮮だ。アラビアン・ナイトの千夜一夜物語を思わせるような、バグダッドとカイロを舞台にした時空の旅。
とある小道具屋に立ち寄った主人公は、時間をさかのぼることができる不思議な門を店主のバシャラートに見せられる。右から入ると未来へ、左から潜ると過去へ進める。
この機構は論理的に現代物理学の範疇で可能らしい。
この門に関する複数のエピソードがバシャラートから語られ、それに魅入られた主人公は自らも旅を決意する。

ここで語っているのは、未来も過去も同じ人の運命という概念だ。今までのタイムワープもので定番になっていた設定は、過去を変えると未来が変わり、変わったことで新たな時間の線が続く。行為によって新たな時間線ができることによってストーリーの可能性が広がる。だから、登場人物は過去にさかのぼって未来を変えようとする。
だが、本編では未来は過去の延長にある。つまり、従来のタイムワープものの設定に乗っかっていない。それが逆に新鮮で印象に残る。

卵が先か、鶏が先か。わからない。だが、人は結局、宿命に縛られる。ある視点ではそのような閉塞感を感じる一編だ。
だが、その閉塞感は、自分の努力を否定するものではない。それもまた、人生を描く一つの視点だ。それが本編の余韻となっている。

「息吹」
並行宇宙。そして平衡状態になると終わるとされる宇宙。二つの「へいこう」をテーマにしているのが本編だ。
本編は、地球とはどこか別の場所、または時代が舞台だ。未知の存在の生命体、もしくは機械体が自らの存在する宇宙の終わりを予感する物語だ。
空気の流れが平衡状態になりつつあることにより、生命を駆動する動力が失われる。それを回避し、食い止めようと努力する語り手は人ではない。それどころか、現代のこの星の存在ですらない。

限られた紙数であるにもかかわらず、平衡に向かう宇宙のマクロと、自らを解剖する語り手のミクロな描写を平行で書くあたりが良かった。一つの短編の中でマクロとミクロを同時に書き記す離れ業。それが本編の凄さである。

「予期される未来」
わずかな紙数の本編。
未来を予測できる機械が行き渡ったことで、自由意志を否定されたと自らで動くことをやめた人々。そのようなディストピアの世界を描いている。

本編は、一年ちょっと先の未来からメッセージを送ってきた存在が語り手となっている。その存在は、決定論を受け入れた上で、嘘と自己欺瞞で乗り切れとアドバイスを送る。その冷徹な現実認識を決定論として認めなければならない。強烈なメッセージだ。

「ソフトウェア・オブジェクトのライフサイクル」
本編を読んでいると、AIBOやファービー、またはたまごっちなどの育てゲームを思い出す。どれも数年でブームを終えている。

本編にはディジエントという人工知能を有したペットのような存在が登場する。それらは動物の代替のペットとして人々に受け入れられた。だが、育てるのは難しく、飼い主の手を煩わせる。人々は飼いならせなくなったティジェントを手放し、運営する会社は廃業する。
たが、一部の人々は、手元に残されたディジエントを育てようと努力する。同じ保護者同士でコミュニティを作り、ディジエントとの共生やディジエントの自立に向けて模索する。本編はディジエントの保護者である主人公の葛藤が描かれる。ディジエントを世の中に適応させるにはどうすればよいか。

保護者がディジエントに気をもむ様子は、通常の子育てやペットの飼い主とは違う。まるで障害を抱えた子供を持つ親のようにも思える。通常の子育てと違った難しさが、本書に人間やペットと違う何かを育てることの困難さを予言している。

ディジエントに法人格を持たせることや、ディジエント同士のセックスなど微妙な問題にまで話を膨らませている。
私たちもそのうち、高度なAIと共生することもあるだろう。その時、倫理的・感情的な問題とどう折り合うのだろう。予言に満ちた一編だ。

「デイシー式全自動ナニー」
20世紀初頭に発明されたとする当時の産物のナニー(ベビーシッター)。当時にあって新奇な技術が人々から見放されていく様子を研究論文の体裁をとって描いているのが本編だ。

全自動の存在に人の成長を委ねることのリスク。本編は、現代から考えると昔の技術を扱っている。だが、ここで書かれているのは間違いなく未来の技術信仰への疑問だ。
私たちは今、人工知能に人類のあらゆる判断を委ねようとしている。そこから考えられる著者のメッセージは明白だ。

「偽りのない事実、偽りのない気持ち」
本編は人の生活のあらゆる面を記録するライフログがテーマだ。
私もライフログについては本のレビューを書いたこともあるし、自分なりの考えをブログにアップしたこともある。

人々は、自らの記憶があやふやであることに救われている。あやふやな記憶によって、人間関係はあいまいに成り立っている。そのあいまいさがある時は人を救い、ある時は人を悩ませる。
リメンという機械によって、ライフログが当たり前になった未来。人々は、リメンによって自分の過ちに気づく。本編の登場人物である親子の関係と二人の間にある記憶の食い違いが強制的に正されていく。

本編が優れているのは、もう一つ別の物語を並行で描いていることだ。ティブ族と言うどこかの部族が、口承で伝えられてきた部族の歴史が、文字や紙によってなり変わられていく痛みを書いている。古い文化から新しい文化へ。そこで起こる文化の変容。それは人類が新たなツールを発明してきた度に引き受けてきた痛みそのものだ。痛みとは、自分が誤っていたと気づくこと。自分が正しくなかったことではなく。

「大いなる沈黙」
本書の末尾には、著者自身による創作ノートのようなものが付されている。それによると本編は、もともと映像作品を補足するスクリプトとして表示していたテキストだったと言う。それを短編小説として独自に抜き出したものが本編だ。
フェルミのパラドックスとは、なぜ宇宙が静かなのかと言う謎への答えだ。宇宙に進出する前に絶滅してしまう種族が多いため、宇宙はこれだけ静かとのパラドックスだ。

「オムファロス」
進化論と考古学。
アメリカではいまだに、この世は創造主によって創造されたことを信じる人がいると言う。それもたくさん。

彼らにとっては人類こそが宇宙で唯一の存在なのだろう。彼らが仮定した創造主とは、私たちにとって絶対的な上位の存在だ。それは同時に、私たち自身が絶対的な存在だと仮定した前提がある。もちろん、この広大な宇宙の中で太陽系などほんの一握りですらない。チリよりも細かいミクロの存在だ。全体の中で人類の位置を客観的に示すことこそ、本編の目的だとも言える。

「不安は自由のめまい」
プリズムと言う機械を起動する。その時点から時間軸は二つに分岐する。分岐した側の世界と量子レベルで通信ができるようになった世界。本編はそのような設定だ。
別の可能性の自分と通信ができる。このような斬新なアイディアによって書かれた本編はとても興味深い。周りを見渡して自分の人生に後悔がない人などいるだろうか。自分が失ったであろう可能性と話す。それはある人によっては麻薬にも等しい効果がある。常に後悔の中に生きる人間の弱さとそこにつけ込む技術。考えさせられる。

‘2020/06/08-2020/06/13


SNSはライフログツール

portrait

はじめに

今回、kintone advent calendarで記事「ライフログのkintone 盛り alasqlとGoogle chartを添えて」を書きました。
記事の中では私はライフログをこう表しました。「システムが行った作業の結果がログ。ウェブ上にログを残すからウェブログ。略してブログ。そして、人生のイベントを記録するのがライフログ。」

記事を書いている私の心に居座っていたのは「私にとってライフログとは何か」です。
いったい、ライフログの本質ってなんだろう。私にとってのライフログは実践可能なものだろうか、と。
その結果、私にとってSNS「ソーシャル・ネットワーク・サービス」がすなわちライフログにほかならないことに気づきました。

人生の意味とライフログ

人は何のために生きるべきか。
これは古来から延々と考え続けられてきたテーマです。人は誰もが死にます。一個人としての意識は死んだ瞬間、消え去る。後には何も残らない。貧富の差も、宗教の違いも、身分の差も関係なく平等に死は訪れる。これは霊界通信を読むまでもなく、生きている人にとって疑いのない真理です。
ただ、それをもって人生をむなしいと捉えるのは間違い。一人一人の個人は、人類という種を構成する一部であると考えれば、私という個人の意識は絶たれても、人類としての存続は続く。そう考えれば死のむなしさの恐怖から逃れられるのではないでしょうか。
そして生の意義とは、人類という種の存続になにがしかの寄与をすることにあると思います。それは子を作り育てるだけではありません。子を養わなくても、人類が存続するため、社会に貢献することだって立派な行いです。
そして私はもう一つ寄与できる事があるのではないかと思います。それは時代の集合意識をのちの世に残すことです。

人類の集合意識。
それは各時代、各地域によってさまざまな形を持ちます。
かつての常識は今の非常識。東のしきたりは西のタブー。だからこそ、古人によって描かれた日記の類が、将来の歴史家にとってその地その時代を映し出す第一級の資料とされるのです。
ただ、一方で現代とは日ごとに膨大な写真や文章が生み出される時代。だから今の時代をトータルで捉えたければ、それらをビッグデータとして解析することで事足りるかもしれません。
ですが、そうしたとらえ方では時代の全体としてしか精神をとらえきれないような気がしています。
一個人としての連続した言動、日々のつぶやきや日記として残された意識の断片をつなげると、そこには一貫した意識が残されるのではないかと思うのです。私はそれこそがライフログの意味だと思います。
だから私自身のライフログが重要なのは私自身よりも、むしろ未来の人々が参照する時代意識の資料としてではないかと思っています。
むしろ私は、ライフログを日々の膨大なイベントを忘れるために使っています。いったんSNSにあげてしまえば、速やかに忘れ去る。必要があれば取り出す。そして一人の個人の生きた歴史としてのちの世に委ねる。個人史のサンプルとして。
私はライフログとはそういう営みだととらえています。

今回の記事をキッカケとして、私にとってSNSとはすなわちライフログの手段、と肚に落ちました。

SNSとライフログ

そもそも人はなぜこれほどSNSにハマるのでしょうか?
自己表現、自己顕示、承認欲求、つながりの明示化、人脈作り、商機の拡大。その動機は人によってさまざまです。
利用者の抱える多様なニーズに合わせ、いかようにも使える可能性があったからこそ、SNSはここまで支持されたはず。
では私にとってのニーズは何か。SNSを通して、発信し続ける理由はなんなのか。それを自らに問うた時、出てきた答えがライフログだったのです。
今回の記事をキッカケに、SNSの意味がやっと見えたように思います。

ここでSNSの一般的な意味を考えてみます。SNSは古くはfriendsterやmixi、LinkedInから、今のFacebook、Twitter、Instagramなどに至るまで多くのサービスが産まれては消えて行きました。
今もまだ、いくつものサービスがしのぎを削っています。全てを合わせるとかなりの利用者数を誇り、ハマる人は1日何時間もSNSに浸っていると聞きます。
SNSはそんなところから企業の生産性悪化の元凶として、また鬱などの元凶として槍玉にあげられる一方、イベント集客やつながりの構築が便利になり、遠方の友人の消息を知るのにも使われています。

さらに考えを進めると、SNSによって特性が違うことにも気づきました。
例えばFacebookです。最近、Facebookばなれがよく言われます。当のFacebookから、よくアンケートを求められ、Facebook自身も危機感をもっている事を感じます。
若年層がFacebookから離れた原因として、中高年のキラキラ成功体験がFacebookに埋め尽くされているのがウザい、という声をよく聞きます。多分私の書いている内容もその一つなのでしょう。

それは、Facebookに書かれる内容の多くが過ぎ去った事という実情に関係しそうです。そう思いませんか?
今日のイベントの結果。こんな食事を食べた。こんな景色を見てきた。こんな内容で登壇した。こんな記事を読んだ。エトセトラエトセトラ。もちろん私自身が書く内容もそう。
そこには実名主義であるFacebookの特質が潜んでいそうです。実名であるがゆえに、未来の展望も控えめにしか書けない。なぜなら書いたことに責任が生ずるから。大風呂敷は広げた以上、きちんと畳まねばなりません。そして未確定な予言である以上、必要最小限のことしか書けない。

それに対し、Twitterは実名も仮名も許されています。
そして140字という制限があるため、そもそも込み入ったことが書けません。つまり理屈や自慢が入りにくい。
わが国のTwitter利用率は諸国の中でも高いと聞きますが、それはおそらくFacebookの実名主義や人との距離感が日本人には合わないからだと思います。むしろ最近の技術者界隈ではTwitterの方が情報発信ツールとして重視されているような感触も持っています。
それもまた、未来志向であるTwitterの特性なのかもしれません。

ただ、過去志向であれ、未来志向であれ、個人を発信することに違いありません。
記事のシェアや他人のつぶやきをRetweetすることだって個人の意見の発信です。つまりはその時々の関心事であり、全てはその人の生きた証です。
よく言われるのが、発信する内容がプライベート寄りだと避けられてしまうということ。
ですが私に言わせると、そもそも対象が公共だろうが閉じたサークル内だろうが、内容が仕事のことだろうがプライベートのことだろうが、発信すること自体がすでに自分の顕示だと思っています。全ては「自分語り」なのです。
SNSとは結局、自分を顕示し、語ると同時に、記録してくれるツールに過ぎません。
でもそれを認めると、かえってスッキリしませんか?。
そして最後に書いた「記録する」という点こそ、SNSがライフログツールである理由だと思うのです。

SNSとは発信する人がその時々で生きる証(行動、言葉、考え)を記録するツールだと考えられないでしょうか。つまりライフログ。
今日何を食べた。こんなキレイな景色をみた。セミナーで登壇した、私はこういう意見がある、他人はこう言っていると紹介する。全てはその人の人生のログです。
ここまで考えを煮詰めてゆくと、私がなぜ今までSNSへの書き込みを続けているのかが腑に落ちました。

もちろん、SNSの重要な機能としてネットワーキングは外せません。ですがネットワークを構築するには、まずあなた自身がどういう人間か開示しないことには、相手もトモダチにはなってくれません。
その意味でもSNSのベースとは自己顕示のツールと考えてあながち的外れではないと思います。

一方で、プライバシーの問題もあります。
自分の行動を開示することによる不利益をおそれる。もっともなことです。
死んだあとにまで自分の行動を詮索されるのはいやだ。そう思う人もいます。当然です。
自分が死んだらライフログもまとめて闇に葬って欲しいと思う。当たり前です。
SNSなどしょせん、ビジネスのつながりが構築できて、その場の承認欲求が満たせればいい、そう思う人もいるのも理解できます。
だからこそSNOWやSnapchatやInstagramのStoriesのような一定時間で投稿が消えるSNSにプライベートな内容を書く利用者が流出しているのでしょう。

そもそも、若い頃はだれもライフログなど興味を持ちません。未来が輝いて見える以上、過去には興味をもたないものです。
私もそうでした。私の20代のころの記録などほとんど残っていません。なので、今になって過去のことをブログに書く度に苦労しています。
そもそも40半ばになった今ですら、過去の記録を覚えていようとも、しがみつこうとも思いませんし。

だからこそ、SNSをライフログツールととらえるとよいのではないかと思うのです。目的は完全にプライベート。将来の自分のために記録するための、今の行動の詳細な情報を忘れてしまうためのツール。
老年に入って死が近づけば「終活」の一環で過去のアカウントを消してしまってもよいし、先に述べた通り時代精神の資料としてのちの世に委ねるのもあり。
当初からSNSをビジネス目的のみで考えず、ライフログの副産物として何かしらの反応があったらそれはありがたく利用させていただく。
こう考えるとSNSへの付き合い方がずっと楽になるのではないでしょうか。
少なくとも私はSNSを巡回し、「いいね」を押して回るのをやめてからは時間もできました。そしてずいぶんと楽になりました。

今回の記事を書いてみて、ライフログとSNSの関係がはっきりするとともに、SNSへの付き合い方への指針のようなものが自分にたったのではないかと思います。
結局のところ、日々の人生は「どう幸せに生き、どう悔いなく死ぬか」にかかっているのですから。


ライフログのkintone盛り alasql仕込みのGoogle Chart添え


1.読まなくてもいい献立の前書き

  目次へ↓

唐突ですが皆さん、ライフログって言葉覚えてますか? 何!忘れた? そんな言葉あったっけ?

それならば説明しましょう!システムが行った作業の結果がログ。ウェブ上にログを残すからウェブログ。略してブログ。そして、人生のイベントを記録するのがライフログ。今やこの言葉は、数多くの新語とともにハードディスクの肥やしと成り果てています。

ところが、まだ忘れるのは早い!という訳で、kintoneでライフログです。

このライフログという概念は2000年代の初め頃に産声をあげていたといいます。ITジャーナリストの佐々木俊尚氏は、2010年の秋に発表した『キュレーションの時代』の中でライフログの概念は2010年代の間にはまだ根付かないだろう、と的確に予言されています。なぜなら、日本にはプライバシーの公開に気持ち悪さを持つ人が大多数だから、と。つまり、ライフログとはまだこれからの概念なのです。佐々木氏はその本の中で、ライフログを集めるツールとしてFourSquare_logoをプッシュしています。このFourSquare_logoですが、ある時期に仕様が迷走したこともあって日本ではすっかり影を潜めてしまいました。ですが、海外では位置とモノを関連付けたデータをがっちり握った企業として存在感を保っているようです。FourSquare_logoとは、一言でいうと訪問場所でチェックインすることで自分がいつどこにいたかを後世の自分、またはどこかの物好きのために記録しておくツールです。それはまさにライフログ。なお『キュレーションの時代』はかつて弊社のブログでも取り上げています。

kintoneは言うまでもなく優れたプラットホームサービスですし、仕事の改善にはテキメンに効きます。それはもう間違いない。でも、プライベートな使い方だってできるのですよ。ワークライフバランスを充実させるにはプライベートでもkintoneを使い倒したほうがいいと思いませんかみなさん!?

私にとって幸いなことにkintoneFourSquare_logoの連携事例はウェブにほぼ皆無です。そこは青い大海原、ブルーオーシャン!というわけでささやかですが、連携事例を公開したいと思います。あわせて、これもkintoneとの連携事例が極めて少ないGoogle Chartと絡めて。題して「ライフログのkintone盛り alasql仕込みのGoogle Chart添え」

2.ご用意いただく材料

  目次へ↑

ちなみにこのレシピの内容を再現せんと志す奇特な方は、以下のものをご用意ください。

  • FourSquare_logoのアカウント(チェックイン用のアプリSwarm_logoも忘れずに)
  • kintoneのスタンダードプラン
  • phpが動き、cronが実行できるサーバー(レンタルサーバーでも可)
  • Google Maps Platform上で動くライブラリを呼び出すためのAPI KEYの入手。こちらをご参考に

このレシピは2018年12月時点の「さくらのレンタルサーバー スタンダード」(phpは7.2.10(CGI版))で動作することを確認しております。
また、Google Maps Platformで動くAPIについては、月あたり40000リクエストまでが無料枠内だそうです。このレシピはプライベート利用なので、そこまでいかないことを念頭においています。
ちなみに、みんな大好き「zapier」でも、Swarm_logoでチェックインする度にkintoneに新たなレコードを追加できます。が、それをいっちゃぁおしめえよ、ということでお付き合いいただければ幸いです。
このレシピは一日単位でkintoneにライフログを一括で登録することに意義を持たせています。そして激動の一日を振り返りつつ、自分をねぎらいたい、そして昨日を忘れ去りたい「あ・な・た」の味方になることも!

なお、いうまでもなく、ライフログはみだりに公開するものではありませんぞ。このレシピのせいであなたのデイリーライフに何か問題が起こっても責任は取れませんのであしからず〜

3.献立の出来上がりイメージとレシピ

  目次へ↑

FourSquare_logoはAPIがOAUTH付きで公開されています。なので私の策略はこうです。まず、午前0時を過ぎたあたりでFourSquare_logoの前日分のチェックインデータをkintoneにシュっと放り込んでやろう。そして溜まったデータをウヒャヒャと一覧で眺めてみよう。ついでに今年、どんぐらい国や県を訪れたんやろう、と地図に出して一人ニヤけて悦にいる。うーん、ダークロースト。

まずは着地点をお見せします。上が世界の長井。下が日本の長井です。

世界の中心で長井を晒す

日本の中心で長井を晒す

ともにkintoneのカスタマイズビューではなく通常の一覧を使って長井を晒しています。世界地図は日本と台湾に色がついており、日本地図は東京が最も濃く、次に神奈川。データはFourSquare_logoSwarm_logo)でチェックインしたデータをphpでkintoneに取り込みます。地図を書き込むのは一覧画面のヘッダスペースです。そのため、世界地図版と日本地図版で一覧を分けています。

kintoneのアプリの構造はこんなんです。

フィールド名 フィールドコード
場所 場所 文字列(1行)
文字列(1行)
都道府県 都道府県 文字列(1行)
コメント コメント 文字列(1行)
日時 日時 日時

あと、アプリの設定画面で下図の3つのファイルを登録してください。
https://www.gstatic.com/charts/loader.js
とhttps://cdnjs.cloudflare.com/ajax/libs/alasql/0.4.11/alasql.min.js
はCDNから使います。最後のjsファイルはこの後説明します。
kintone_app

ここであらためて全体の構成図をご覧いただきましょう。一目瞭然とはこのことですね。

構成図

4.FourSquareの下ごしらえ

  目次へ↑

日々のチェックイン履歴をFourSquare_logoに溜める方法は、簡単に書くとこんな感じです。

  • Swarm_logoのアプリを立ち上げ、チェックインしたい場所でチェックインボタンを押す。
  • Swarm_logoの候補の一覧にその場所が登場します。
  • 登場しなくても検索すれば場所が指定できます。
  • 指定した場所でチェックイン(構成図の①)を行えば時間とともに自動的に記録(構成図の②)されます。気が向けばコメントも入れられます。

どうです?モンスターボールを投げなくてもよいし、ポータルを三角形で囲わなくてもよいのです。簡単ですよねFourSquare_logo

さて、今回の記事ではAccessTokenをFourSquare_logoから取得する処理(構成図の③)から説明します。AccessTokenはこのレシピの中で一度取得するだけです。なぜ一度だけでよいかというと、AccessTokenはユーザーを特定するのに使われるからです。つまり、一度AccessTokenを取得しておけば、何度でも使いまわしができるのです。FourSquare_logoには他にもたくさんのAPIが用意されています。処理によってはその都度AccessTokenを取らねばならず、ソースも複雑な下ごしらえが求められることもあります。ですが、このレシピではユーザーのチェックイン情報だけをとるのが目的なので、一度きりでよいのです。

5.FourSquareのAPI KeyとAPI Secretを取り寄せる

  目次へ↑

まず、https://ja.foursquare.com/にアクセスしてください。

FourSquarePage

そして、右上の開発者をクリックします。

すると、https://developer.foursquare.com/にページが遷移します。

FourSquareDeveloperPage

がでたら、右上のCreate Accountからアカウントを作成してください。

多分、FourSquare_logoで作ったアカウントがそのまま開発者アカウントとして引き継がれるはずです。

そしたら下図のようにMy Appsを選びましょう。アプリの作成のリンクがあるはずです。

FourSquareMyApp

こんな風に入れてください。

FourSquareMyAppRegist

この中で重要なのは3点。

  • Client ID、Client Secretは次の作業で使うのでちゃんとメモっておきましょう。
  • Client ID、Client Secretは墓まで持っていきましょう。人に教えちゃダメ!
  • Redirect URI (s)もちゃんと考えておきましょう。これは次の作業でこさえるスクリプトのURIです。

Application Urlという項目もありますが、ここは適当でよいです。他の項目も商用で使わなければ空白でよいはず。

6.FourSquareのアクセストークンの取り寄せとソースの仕込み方

  目次へ↑

続いて、アクセストークンを取得するためのphpを示しましょう。98行。38ステップです。

コメントに内容は記載しているので、まずはソースを味わってみてください。

設定A ⇒ 条件分岐B ⇒ 条件分岐C ⇒ 処理D ⇒ 処理E ⇒ 処理F ⇒ 条件分岐G ⇒ 処理H ⇒ 条件分岐I ⇒ 処理Jの順に進みます。

  // 設定A //
  // マイアプリで表示されたClient ID
  $client_id = 'KOKONIHAHONMAYATTARARANDAMUNAMOJIRETSUGAHAITTORUNEN';
  // マイアプリで表示されたClient Secret
  $client_secret = 'SEYAKEDOKOKONISOREDASHITARAORENOKOUDOUGABARERUKARADASAHENNEN';
  // リダイレクトURL (このスクリプト自身のアドレスです)
  $redirect_uri = 'https://*****.*****.ne.jp/*****/****_*********.php';
  // アクセストークン取得URLのベース
  $access_token_baseurl = 'https://foursquare.com/oauth2/access_token';
  // 認証URLのベース
  $authenticate_baseurl = 'https://foursquare.com/oauth2/authenticate';

  // 結果表示HTML用
  $html = '';
  // 結果表示見出し
  $html .= '<h2>実行結果</h2>';

  // 条件分岐B //
  //初回は$_GET['code']がなく中の処理は実行されない。「許可」され、リダイレクトされた場合に実行
  if( isset( $_GET['code'] ) 
    && !empty( $_GET['code'] ) 
    && is_string( $_GET['code'] ) ) {
    // 処理E //
    // 認証画面でFourSquareの実行が許可されると$_GET['code']付きでこのスクリプトが呼び出される。
    // アクセストークンの取得に利用するコード
    $code = $_GET['code'];
    // 処理F //
    // アクセストークン取得のためのパラメータを設定したUrlを組み立てる。
    // リクエストURL
    $request_url = 
      $access_token_baseurl . 
        '?client_id=' . $client_id . 
        '&client_secret=' . $client_secret . 
        '&grant_type=authorization_code' . 
        '&redirect_uri=' . rawurlencode( $redirect_uri ) . 
        '&code=' . $_GET['code'] . 
        '&state=users/self';
    // curlを初期化する
    $curl = curl_init();
    curl_setopt( $curl , CURLOPT_URL , $request_url );
    curl_setopt( $curl , CURLOPT_HEADER, 1 );
    // 証明書の検証を行わない
    curl_setopt( $curl , CURLOPT_SSL_VERIFYPEER , false );
    // curl_execの結果を文字列で返す
    curl_setopt( $curl , CURLOPT_RETURNTRANSFER , true );
    // タイムアウトの秒数
    curl_setopt( $curl , CURLOPT_TIMEOUT , 5 );
    // 実行し、結果を$jsonに代入
    $res1 = curl_exec( $curl );
    $res2 = curl_getinfo( $curl );
    curl_close( $curl );
    // 取得したJSONデータ(ヘッダーサイズでTrimしないとFourSquareはエラーになる)
    $json = substr( $res1, $res2['header_size'] );

    // JSONをオブジェクト型に変換する
    $obj = json_decode( $json );

    // 条件分岐G //
    if( !isset( $obj->access_token ) ) {
      // アクセストークンを取得できなかった場合
      $error = 'アクセストークンを上手く取得することができませんでした。';
    } else {
      // 処理H //
      // アクセストークンを[$access_token]に代入する
      $access_token = $obj->access_token;
      // アクセストークンをブラウザーに出力する
      $html .= '<p>取得したアクセストークンは <b><mark>' . 
        $access_token . '</mark></b>です。</p>';
    }
  } elseif( isset( $_GET['error'] ) ) {
    // 「拒否」して返された場合怒る。
    $error = 'なんで「許可」してくれへんの!?';
  } else {
    // 条件分岐C //
    // 初回はこの処理が行われるはず。
    header( 'Location: ' . $authenticate_baseurl . 
      '?client_id=' . $client_id . 
      '&response_type=code' . 
      '&redirect_uri=' . rawurlencode( $redirect_uri ) );
    // 処理D //
    // headerの後はexit()
    exit;
  }

  // 条件分岐I //
  // エラー判定
  if( isset( $error ) && !empty( $error ) ) {
    $html .= '<p><mark>' . $error . '</mark>' . 
      'もう一度、認証をするには、' . 
      '<a href="' . explode( '?' , $_SERVER['REQUEST_URI'] )[0] . '">こちら</a>' . 
      'をクリックして下さい。</p>' ;
  } else {
    // 処理J //
    // ブラウザーに[$html]を出力 (結果としてアクセストークンの文字列が表示されます)
    echo $html;
  }

もう一度上の処理をおさらいします。
・最初にこのスクリプトが呼ばれた際、URLにcodeパラメーターはついていません。
・だからBの条件でEFGHの処理は行われず、条件分岐Cの処理が実行されます。
・その中ではLocationヘッダを送信しています。なので、その下の処理Dでただちに認証画面にリダイレクトされます(認証画面は割愛します)。
・そこで認証が終われば、再びこのスクリプトがcodeパラメーター付きで呼ばれるよう、処理DのLocationヘッダの中にredirect_uriパラメーターを指定しています。
・再びこのスクリプトが実行されると、今度は条件分岐Bで処理E、Fが実行されます。
・FではFourSquare_logoのアクセストークンを返すAPIが呼ばれます。
・なので、無事にアクセストークンが返ってくるという流れです。お判りでしょうか?

そしたらこのスクリプトファイルをどこかのウェブサーバーに送ってください。phpファイルの実行権限付きで。先ほどFourSquare_logoのマイアプリの設定でRedirect Url (s)に入力していただきましたが、その内容と合わせておいてください。

たとえばhttps://hanamogera.com/mokeke/foursqaure_tokun_yokose.phpに送るとします。そしたらブラウザーのアドレスバーに直接上のアドレスを指定し、実行します。

すると結果が以下のように表示されるはずです。このマーカー部分をコピーしておきましょう。

アクセストークン

おめでとうございます。アクセストークンはこれであなたのものです。ついに調理人として存分に腕を振るう時が来たのです!!

7.FourSquareからCheckinデータの取り寄せとソースの仕込み方

  目次へ↑

続いては、いよいよAccessTokenを使ってFourSquare_logoにデータくれ!とおねだり (構成図の④) してみましょう!もらったデータをkintoneにシュッと投げ込むまで(構成図の⑤)のphpも説明します。まずはphpを以下に示します。115行。64ステップです。

こちらもコメントに内容は記載しているので、まずはソースを味わってみてください。
先のスクリプトはソースに大分シェフの手を加えましたが、このスクリプトは素材の味を生かすような作りにしています。

設定A ⇒ 設定B ⇒ 設定C ⇒ 設定D ⇒ 設定E ⇒ 条件分岐F ⇒ 条件分岐G ⇒ 処理H ⇒ 処理I ⇒ 処理J ⇒ 処理Kの順に進みます。

  // 設定A //
  // アクセストークン (前の処理で取ってきた文字列です)
  $access_token = 'YATTAYOAKUSESUTOKUNTORETAYOKOREDESIAWASENINARERUNE';

  // 設定項目 (ここはアクセストークン以外はデフォルト)
  $params = array(
    'oauth_token' => $access_token ,// アクセストークン (これでユーザーが認識される)
    'locale' => 'ja' ,              // ローカライズ (jaは日本)
    'm' => 'swarm' ,                // モード (foursquare OR swarm)
    'v' => '20150801' ,             // バージョン (APIのバージョン。今のところ左の年月日)
    'limit' => '250'                // 取得件数 (250が上限)
  ) ;
  // 設定B //
  // GETメソッドで指定した場合 (設定項目のパラメーターを差し替える)
  foreach( array( 'locale' , 'm' , 'limit' , 'sort' , 'afterTimestamp' , 'beforeTimestamp' ) as $val ) {
    if( isset( $_GET[ $val ] ) && $_GET[ $val ] != '' ) {
      $params[ $val ] = $_GET[ $val ] ;
    }
  }

  // 設定C //
  // 設定項目 (日付や並び替えなどの条件を追加します。例えば2018/11/30の00:15時点で実行されたとします。
             するとstrtotime("today")は2018-11-30 00:00:00が返されます。
              strtotime("yesterday")は2018-11-29 00:00:00が返されます。
              それをもとにした$params["afterTimestamp"]は2018-11-29 00:00:00より後のチェックインデータを、
              それをもとにした$params["beforeTimestamp"]は2018-11-30 00:00:00より前のチェックインデータを取得します。
              $params["sort"]はoldestfirstを指定すると上記の日付範囲のチェックインデータのうち古いものを最初に取得します。
              ここ重要です。kintoneライフログ調理師試験に出ますので、要おさらい!!) //
  $today = strtotime("today");
  $yesterday = strtotime("yesterday");
  $params["afterTimestamp"]=$yesterday;
  $params["beforeTimestamp"]=$today;
  $params["sort"]="oldestfirst";

  // リクエストURL (usersの次のselfは固定文字)
  $request_url = 'https://api.foursquare.com/v2/users/self/checkins?' . http_build_query( $params );

  // 設定D //
  // cURLでリクエスト
  $curl = curl_init();
  curl_setopt( $curl , CURLOPT_URL , $request_url );
  curl_setopt( $curl , CURLOPT_HEADER, 1 );
  curl_setopt( $curl , CURLOPT_SSL_VERIFYPEER , false );
  curl_setopt( $curl , CURLOPT_RETURNTRANSFER , true );
  curl_setopt( $curl , CURLOPT_TIMEOUT , 5 );
  $res1 = curl_exec( $curl );
  $res2 = curl_getinfo( $curl );
  curl_close( $curl );

  // 設定E //
  // 取得したJSONデータをオブジェクト形式に変換する (ヘッダーサイズでTrimしないとFourSquareはエラーになる)
  $json = substr( $res1, $res2['header_size'] );
  $obj = json_decode( $json );

  // 条件分岐F //
  // エラー判定 (metaのcodeの値が200だと正常に取得されている)
  if( !$obj || !isset($obj->meta->code) || $obj->meta->code != 200 ) {
    //ログ出力して調査!
  } else {
    // 説明
    $data = array();
    $count = 0;
    // 条件分岐G //
    //取得したデータオブジェクトの -> response -> checkins -> itemsの中をループする //
    foreach( $obj->response->checkins->items as $item ) {
      // 処理H //
      //$itemの中にはチェックインの場所についての栄養が豊富に含まれています。緯度経度やコメントや市長など。詳しくはhttps://developer.foursquare.com/docs/api/users/checkins //
      // チェックインID
      $id = $item->id ;
      // ベニューのID
      $venue_id = $item->venue->id ;
      // ベニューの国 (国名は日本語で取得できる)
      $venue_country = $item->venue->location->country;
      // ベニューの都道府県 (取得した後、Google Chartの都合で末尾の「都」「府」「県」は除去する)
      $venue_prefecture = $item->venue->location->state;
      switch ($venue_prefecture){
        case '北海道':
          break;
        default:
          $venue_prefecture = mb_substr($venue_prefecture,0,-1, "UTF-8") ;
          break;
      }
      // ベニューの名前 (改行は除去しておく)
      $venue_name = str_replace(array("\r\n", "\r", "\n"), '', $item->venue->name);
      // チェックイン日時(オフセットと合わせる。要は日本の時間に合わせる)
      $createdAt = $item->createdAt + 54000 - 86400;
      // 日時の整形 (kintoneにあった日付データ形式に変更する)
      $createdAt = date( 'Y-m-d' , $createdAt )."T".date( 'H:i:s' , $createdAt ) ;
      // コメント (改行は除去しておく)
      $shout = ( isset($item->shout) ) ? str_replace(array("\r\n", "\r", "\n"), '', $item->shout) : '';
      // kintoneに投げるデータです。フィールドコードとデータ型を合わせることを忘れずに。
      // 処理I //
      //kintoneに投げるデータをここで指定します。文字列データは文字列型にキャストしておくとふっくら仕上がります //
      $data[$count] = array(
        "場所" => array("value" => (string)$venue_name),
        "コメント" => array("value" => (string)$shout),
        "国" => array("value" => (string)$venue_country),
        "都道府県" => array("value" => (string)$venue_prefecture),
        "日時" => array("value" => $createdAt)
      );
      $count++;
    }
  }

  // 処理J //
  // kintoneの対象のアプリIDを指定する。(1111というのはダミーです)。FourSquareからのデータもあわせて。
  $postdata = array("app" => 1111,records=>$data);
  // 処理K //
  // kintoneのアクセストークンを指定する。ベーシック認証がある場合はそちらもあわせて指定。
  $headers = array(
    "X-Cybozu-API-Token:" . "kintoneNOAPURISETTEIDESHUTOKUDEKIRUTOKUN",
    "Authorization:" . "Basic " . base64_encode("YUUZAAID:PASUWAADO"),
    "Content-Type:" . "application/json"
  );
  // 以下の******はお使いのkintoneのサブドメインを入れてください。
  $curl = curl_init('https://******.cybozu.com/k/v1/records.json');
  curl_setopt($curl, CURLOPT_POST, true);
  curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
  curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($postdata,JSON_UNESCAPED_UNICODE));
  curl_setopt($curl, CURLOPT_HEADER, true);
  // curlで出たエラーを補足するためのものです。
  $fp = fopen('curl.log', 'a');
  // 詳細な情報を出力する
  curl_setopt($curl, CURLOPT_VERBOSE, true);
  // STDERR の代わりにエラーを出力するファイルポインタ
  curl_setopt($curl, CURLOPT_STDERR, $fp);
  if(curl_exec($curl) === false){
    //ログ出力して調査!
  } else {
    return true;
  }
  curl_close($curl);

このスクリプトもウェブサーバーに送ってください。ファイルの実行権限付きで。あと、ファイルのUrlはきちんとメモしておいてくださいね(^_^)

次にcronの設定を行います。cron実行のための構文はサーバーによって違います。ここに載せているcron設定はさくらインターネットの例ですが、phpファイルの実行パスと、スクリプトのファイル名はどのサーバーでも求められるはずです。このレシピは毎日00:15に自動で実行するように設定しています。

Cron設定1

cron2-1

8.kintone上でデータの盛り付け

  目次へ↑

さて、7までのレシピ(2018/12時点の)に忠実に行うとチェックインデータは毎日順調にkintoneに流れ込むはず。あとはデータを盛り付けるだけ。「ライフログのkintone盛り alasql仕込みのGoogle Chart添え」とうたっている以上、最後の仕上げにGoogle Chartを添えるのを忘れるなかれ。それぞれの一覧ごとに違うマップを表示するJavaScriptを以下に示します。この中でkintoneのデータをalasqlで集計し、その結果をGoogle Chartで地図に表示しています。

世界地図の場合、処理A ⇒ 条件分岐B ⇒ 処理C ⇒ 処理D ⇒ 処理E ⇒ 処理V ⇒ 処理F ⇒ 処理W ⇒ 処理G ⇒ 処理H ⇒ 処理I ⇒ 処理J ⇒ 処理Kの順に進みます。
日本地図の場合、処理A ⇒ 条件分岐L ⇒ 処理M ⇒ 処理N ⇒ 処理O ⇒ 処理V ⇒ 処理P ⇒ 処理W ⇒ 処理Q ⇒ 処理R ⇒ 処理S ⇒ 処理T ⇒ 処理Uの順に進みます。

(function () {
  "use strict";
  // 処理V //
  // 再帰処理による一回のリクエスト制限を超えた全レコードを取得 //
  function fetchRecords(appId, opt_query, opt_fields, opt_offset, opt_limit, opt_records) {
    var query = opt_query || '';
    var offset = opt_offset || 0;
    var limit = opt_limit || 500;
    var allRecords = opt_records || [];
    var params = {app: appId, query: query + ' limit ' + limit + ' offset ' + offset };
    if (opt_fields) params.fields = opt_fields;
    return kintone.api(kintone.api.url('/k/v1/records', true), 'GET', params).then(function(resp) {
      allRecords = allRecords.concat(resp.records);
      if (resp.records.length === limit) {
        return fetchRecords(appId, query, opt_fields, offset + limit, limit, allRecords);
      }
      return allRecords;
    });
  }

  // 処理W //
  // json形式で取得したkintoneのレコードをalasqlで扱えるようレコードセット形式に変換 //
  function convertToRows(records) {
    var rows = records.map(function(record){
      var keys = Object.keys(record);
      var row = {};
      keys.map(function(key){
        row[key] = record[key].type === 'NUMBER' ? Number(record[key].value) : record[key].value;
      });
      return row;
    });
    return rows;
  }

  // 一覧ページ
  kintone.events.on('app.record.index.show', function(event) {
    // 処理A //
    //Google Cloud Platformで発行したAPI KEYです。
    //API KEYがない場合、以下の処理Cでgoogle.charts.load('upcoming', {'packages':['geochart']});としても動きますが、世界地図の色塗りができません。また、コンソールでエラーが表示されます。
    //作成したプロジェクトの認証はリファラーを限定するとよいです。https://subdomain.cybozu.com/* のように指定すると、対象のサブドメインに対して動作します。https://akvabit.cybozu.com/だと動きませんので注意が必要です。
    //あと、許可するAPIですが、「Maps JavaScript API」「Geolocation API」「Geocoding API」の三つを有効にしています。
    const ApiKey = 'k54u6 jkrawyeie-wkjykethiudarwhyeiu_rekyjur';
    // 条件分岐B //
    //世界地図ビューの場合 //
    if (event.viewId === 5351051) {
      // 処理C //
      //google chartを読み込む。種類は地図 //
      google.charts.load('upcoming', {'packages':['geochart'],'mapsApiKey':ApiKey});
      // 処理D //
      //google chartの読み込みが完了したらコールバックでdrawWorldMapを呼び出す //
      google.charts.setOnLoadCallback(drawWorldMap);
      function drawWorldMap() {
        var obj = {};
        // 処理E //
        //このファイルの3-17行のfetchRecords関数を呼び出す。対象アプリは自分で、フィールドは[場所][国] //
        fetchRecords(event.appId, '', ['場所', '国']).then(function(records) {
          // 処理F //
          //取得したレコードをSqlで扱えるようなレコードセットの形式に変換するconvertToRows関数(このファイルの20-30行)をご参照 //
          obj.rs1 = convertToRows(records);
          // 処理G //
          //alasqlでsql文のソースを組み上げ、バインドパラメータに処理Fで得たレコードセットをセットする //
          var result = 
            alasql(
              "SELECT t.[国], COUNT(t.[場所]) as [回数] \
              FROM ? AS t \
              GROUP BY t.[国] \
              ORDER BY t.[国]", [obj.rs1]);
          // 処理H //
          //google chartのデータテーブルのインスタンスを新たに確保する //
          var data = new google.visualization.DataTable();
          // 処理I //
          //google chartのデータテーブルの列と行を追加します。alasqlでグループ集計された国ごとの訪問回数です。 //
          data.addColumn('string', '国');
          data.addColumn('number', '訪問場所数');
          result.forEach(value => {
            data.addRow([value["国"], value["回数"]]);
          });
          // 処理J //
          //google chartの世界地図の色塗りの書式を設定する //
          var options = {
            datalessRegionColor: '#ffffff',
            colorAxis:{
                maxValue:500,
                colors:['#D8F6CE','#21610B']
            }
          };
          // 処理K //
          //google chartの世界地図のデータに処理Iで格納した内容を代入し、kintoneのヘッダスペースに描画する //
          var chart = new google.visualization.GeoChart(kintone.app.getHeaderSpaceElement());
          chart.draw(data, options);
        });
      }
    // 条件分岐L //
    //日本地図ビューの場合 //
    } else if (event.viewId === 5351053) {
      // 処理M //
      //google chartを読み込む。種類は地図 //
      google.charts.load('upcoming', {'packages':['geochart'],'mapsApiKey':ApiKey});
      // 処理N //
      //google chartの読み込みが完了したらコールバックでdrawJapanMapを呼び出す //
      google.charts.setOnLoadCallback(drawJapanMap);
      function drawJapanMap() {
        var obj = {};
        // 処理O //
        //このファイルの3-17行のfetchRecords関数を呼び出す。対象アプリは自分で、フィールドは[場所][都道府県] //
        fetchRecords(event.appId, '', ['場所', '都道府県']).then(function(records) {
          // 処理P //
          //取得したレコードをSqlで扱えるようなレコードセットの形式に変換するconvertToRows関数(このファイルの20-30行)をご参照 //
          obj.rs1 = convertToRows(records);
          // 処理Q //
          //alasqlでsql文のソースを組み上げ、バインドパラメータに処理Pで得たレコードセットをセットする //
          var result = 
            alasql(
              "SELECT a.[都道府県], COUNT(a.[場所]) as [回数] \
              FROM ? AS a \
              GROUP BY a.[都道府県] \
              ORDER BY a.[都道府県]", [obj.rs1]);
          // 処理R //
          //google chartのデータテーブルのインスタンスを新たに確保する //
          var data = new google.visualization.DataTable();
          // 処理S //
          //google chartのデータテーブルの列と行を追加します。alasqlでグループ集計された都道府県ごとの訪問回数です。 //
          data.addColumn('string', '都道府県');
          data.addColumn('number', '訪問場所数');
          result.forEach(value => {
            data.addRow([value["都道府県"], value["回数"]]);
          });
          // 処理T //
          //google chartの地図を日本地図の都道府県とし、色塗りの書式を設定する //
          var options = {
            region: 'JP',
            resolution: 'provinces',
            datalessRegionColor: '#ffffff',
            colorAxis:{
                maxValue:600,
                colors:['#F2FBEF','#21610B']
            }
          };
          // 処理U //
          //google chartの世界地図のデータに処理Sで格納した内容を代入し、kintoneのヘッダスペースに描画する //
          var chart = new google.visualization.GeoChart(kintone.app.getHeaderSpaceElement());
          chart.draw(data, options);
        });
      }
    }
  });
})();

いかがでしょうか? ここはカスタマイズビューでリッチにデータを表現しても良いですし、条件に応じて絞り込めば、さらに面白いこともできます。チェックインデータにはカテゴリーもありますので、例えば訪れた酒場だけを抜き出し都道府県で図示したり、訪れたラーメン屋だけを都道府県で抜き出すことだってできます。例えば私の趣味ですが、今までに訪れた滝を色分けすればこうなります。城とすればこう。駅だとこう。他にも登った山や訪れた蒸留所や酒蔵、ブルワリー。各地の日本酒や世界の酒、料理などで色分けしても面白そうです。
残念なことにGoogle chartはまだ市町村には対応していません。もしそうなればもっと面白いライフログが作れそうです。もちろん、地図で塗り分けるほかにもGoogle chartはかなりのグラフの種類を用意しています。そこは皆様の自由です。
なお、ライフログとは、別に人様に見せて放浪癖を誇るものでも、旅行経験を自慢するものでもありません。あくまでもプライベートな利用がよろしいかと思います。ご自身の今までの人生とこれから残された人生に何を成すかを定める助けになればそれで十分です。そのあたり、ライフログについての私の考えは、このレシピ同時に書いたこちらで世に問うてみました。またご覧頂ければ幸いです。
このレシピをまとめるなら、要するにkintoneをプライベート用途に使おうよ、との主旨です。そういう使い方がもっと増えればkintoneはより身近なものになるのですから!

9.当レシピの参考にさせていただいたブログ

  目次へ↑

最後になりましたが、このレシピを作るのに、以下の5サイトを参考にさせていただきました。ありがとうございました。

 Foursquare(Swarm) APIの使い方まとめ (サンプルコード付き)
 Get Check-Ins for a User
 kintone でSQLを使う
 GoogleのGeochartを使ってみた
Google Maps Platform