怠惰な人のカロリー管理~~~

この記事は VOYAGE GROUP Advent Calenderの22日目の記事となっております。

前置き~~~~~

こんにちは、今年新卒で入社した @takeru0911です。早いもので入社して8カ月も経過しました。

皆様のご指導のたまもので技術力が少しずつ成長しているという実感がありますが、技術力よりも圧倒的に成長したことがあります。

はい、 体重 です。

大学入学時からすると驚きの30kg増、大学院入学時からだとなんと25kg程度太りました。 この圧倒的な成長の傾きは衰えることなく入社してさらに勢いを増しております。

その圧倒的(体重)成長曲線のイメージは下のような感じです。

f:id:tkr911:20161221214444g:plain

(こちら縦軸が体重で、横軸が時間tと思っていただければ)

どちらも圧倒的ですが、入社後の成長具合がよくわかるかと思います。

成長するのはとても良いことですがこのままいくとちょっと良くないことが起きかねないとダイエットを決意したのが入社して一カ月も経たないときでした。

そのあと、ダイエットするためにいろいろなことを行いました。

このうちの 摂取カロリーを記録 、というのが地味なようで自分の体質を把握する意味でもいい感じに効いてくるらしいです(ネット調べ)

でもめんどくさくないですか?

毎回の食事のカロリーをいちいち調べて、なんかに記録して、というのを毎食行うなんてちょっと信じられないですよね。

できる人心の底から尊敬します、僕には無理です(無理でした、一週間くらいでやめました)

でも最近は補助するアプリもあって、これなら私でもいけるのでは・・・!?と使ってみたりしました。

ダメでした

例えば、おにぎり って検索すると、梅にぎり、鮭にぎり、そのほかいっぱいのおにぎり。

あれですよね、選択するのめんどくさいですよね。 これがおにぎり2個とかになると、いくつ食べたかを入力してとかなるわけですよ。

なんにしてもこれを食事のたびに食品ごとに行うのはちょっと辛いですよね。

とは言え最近いろいろな方面の方々に会うたびに

「太った?」 「痩せた方がいい」

と言われるので、痩せるためにカロリー管理をするにはどうしたら良いのか?と本気出して考えてみました。

結果、自分みたいな怠惰マンでもカロリーを管理できるようなものは自分でしか生み出せないと考えて、もう作るしか無いか・・・という結論に至りました。

前置き終わり。

カロリ~~~~~

ここまでの前置きでどんな感じなら、とても怠惰な自分でもカロリーを管理できるか分かってきた気がします。

  • 入力するだけ
  • あいまいでも選択しないでいい
  • 選択肢が複数あってもいい感じにサマる
  • 一つのページで完結する

上の条件をGoogle Spreadsheetで実現することにしました、google application script(gas)便利ですね(ぼくはExcelVBAのほうが書き慣れてて好きです)

あと食品のカロリーはapiで取得します

カロリーapi~~~~~

食品のカロリーの取得には カロリー api でぐぐって上のほうで出てきた↓のものを使用させていただきました。

blog.24th.jp

このapi結構気に入っていて、例えばおにぎりって叩くと、↓みたいにおにぎりで部分一致するものをすべて返してくれます(calがカロリーですね)。

<Result>
  <food>
    <id>77</id>
    <name>おにぎり紀州梅</name>
    <cal>148</cal>
  </food>
  <food>
    <id>102</id>
    <name>おにぎり</name>
    <cal>180</cal>
  </food>
</Result>

怠惰な私は、シーチキンおにぎりを食べようが、鮭おにぎりを食べようが(面倒なので) おにぎり で登録したがります。 なのでこの部分一致で返ってきたものをいい感じにサマれば、どんなおにぎりを食べようがなんとなくそれっぽいカロリーになるはずです(?)

ではapi叩いて、xmlをparseしていい感じにサマるのをgasで書きましょう。

xmlのparseあたりはここらへんを参考にしました。

unguis.cre8or.jp

//apiたたいてカロリーxmlを取得
function fetchCalorieXml(foodName){
  var feedURL = "http://24th.jp/test/api_cal.php?submit=on&name=" + foodName;
  var response = UrlFetchApp.fetch(feedURL);
  return response.getContentText();
}

//取得したxmlをparseしてカロリー取得
//該当する食品があったら良い感じにカロリーをさまる
function parseCalorieXml(contentText){
  var xml = XmlService.parse(contentText);
  var items = xml.getRootElement().getChildren('food'); 
  var sumCal = 0;

  if(items.length == 0){
    return 0;
  }

  for(var i = 0; i < items.length; i++) {
    var cal = Number(items[i].getChild("cal").getText());
    sumCal = cal + sumCal
  }
  //いい感じにサマる
  return sumCal / items.length;
}

fetchClorieXmlapiを叩いて取得されたxmlparseCalorieXml に渡すだけです。

サマる箇所はもし複数ヒットしたら平均をとって返すとかいうなんの捻りもない内容になってます。

User Defined Calorie(UDC)

このapiのおかげで基本的な食事はカバーできます。

しかしよく食べるけど一般的ではないなにか(会社で売られる弁当とか)とか、大量の飲み物や食べ物を食べる会(飲み会)の場合はちょっとapiだけだと辛いですね。

なのでユーザーが独自のカロリーを登録できるようにしました。

はい、いわゆる User Defined Calorie(UDC)機能の実装です。

本当に何の捻りもない実装です。 下の画像みたいにUDC sheetに食べ物の名前と、カロリー数を書いてその値を取得するだけです。

f:id:tkr911:20161221223314p:plain

将軍ってのは会社に来る弁当屋さんの名前で、カロリー数は適当です。 飲み会は飲み会ですね、夜飲み会があるとこれを入力すれば面倒なことなしです、素晴らしい!!(このくらい割り切らないと絶対続かないので)

これを普通にgasで実装ですね。

なんも捻りもないのでコードは載せないです。

食べた数をわけるのめんどい!!

朝ごはんに私はおにぎりを2つ食べてカフェラテを飲むのですが、それぞれの食べた個数を↓みたいに複数のセルに書いていくのは無理ですね。

食べたもの 個数
おにぎり 2
カフェラテ 1

一つのセルにこんな感じで入力したいですよね

おにぎり*2,カフェラテ

この入力でいい感じにカロリー計算してくれたら、毎朝全く同じメニューの私は補完が効いて朝ごはんの登録は を入力するだけでとても楽になります。

というわけでこれもgasでできるように実装しましょう。 普通に , でsplitして、splitされた文字列を * でsplitするだけです。

//複数食品があったら、なんか分解する
//カレー*2とかあったら個数もなんかやる
function parseInputFood(inputText){
  var splitText = inputText.split(",")
  var foods = [];
  for(var i = 0; i < Number(splitText.length); i++){
    var cnt = 1;

    var text = splitText[i];
    //なんこか食べたら
    var splitAsta = text.split("*");
    if(splitAsta.length > 1){
      cnt = splitAsta[1];
    }
   
    var foodName = splitAsta[0];

    foods.push(
      {
        name: foodName,
        cnt: cnt
      }
    );
  }
  return foods;
}

普通ですー。

なんやかんやで↓みたいな感じにわりと楽な感じにカロリーを計算できるようになりました。

f:id:tkr911:20161222092332g:plain

ちなみにapiにもUDCにもない食品は、UDCに登録してね☆って言われます。

まとめ

いろいろバグというか、実装が足りない部分もありますがこれくらいで十分かなと思います。 ほとんど書いたことないので読みにくかったり、もっときれいに書けるやんってところが多々あると思いますがご容赦を。

でもなんだか自分でこういうのを作ると、長続きするような気がします。 ダイエットでカロリー管理が続かなかった方がもしいれば自分で作ってみるのも良いかもしれないですね

ちなみに書いたコードはgistにあげておきました。 スクリプトエディタでこれをぺって貼り付けて、プロジェクトトリガーでシートの編集時に動くように登録すれば動くかと思います。

カロリー計算するマン · GitHub

それでは来年ではダイエット成功の報告ができると信じてさようなら~!

次の VOYAGE GROUP Advent Calendar の記事をお楽しみに~~~~~

KotlinでVue.jsを動かしてみた

この記事はVOYAGE GROUP Advent Calendar 2015の12日目となります。

こんにちは,VOYAGE GROUPの16卒内定者の@takeru0911です.内定者でだれかAdventなCalendar書かないか?と聞かれたのでチャレンジしてみました.

最近私が結構触っているKotlinについて少し書いてみようかなと思って書いてみます. 当初は巡回サンタさん問題を蟻コロニー最適化で解こうかな,と思ってました(解いてみて記事も書き終わってました)が当日になってこっちの方が良いのでは(?)と謎の発想により書いてみました.

今回のコードなんかはこちらです.

github.com

Kotlinについて

JetBrain社が開発しているJVM言語です. 静的型付け言語とか型安全とかNull安全とかAndroid開発が捗るとか特徴あります. 他にもいろいろ語るべきことはあるかと思いますがKotlin Advent Calendarがあるのでそちらをぜひお読み下さい.

ちなみにちょっと試したい,触ってみたいといった場合はWeb上で動かすことも可能(Try Online)となっております.

KotlinでJS

KotlinはJavaScriptコンパイルするコンパイラーを搭載しております. Androidに関して,Kotlin今すごく盛り上がっていますが,AltJSとしてのKotlinの記事はあまり見かけないし,せっかくなので遊びがてら少し触れてみようと思います. 仕組みとかは公式のドキュメント見るか日本語だと少し古いですが

yyyank.blogspot.jp

上記の記事が参考になります.

Hello World

はじめにHello Worldをさせてみます. 下のコードがconsole.log('hello world')を実行するコードです.

fun main(args: Array<String>){
    console.log("hello world")
}

このコードをコンパイルするとこんなjsのコードに生まれ変わります.

(function (Kotlin) {
  'use strict';
  var _ = Kotlin.defineRootPackage(null, /** @lends _ */ {
    main_kand9s$: function (args) {
      console.log('hello world');
    }
  });
  Kotlin.defineModule('hello', _);
  _.main_kand9s$([]);
}(Kotlin));

mainmain_kand9s$という名前の関数に変換されていることがわかりますね.Kotlinというオブジェクトに対して関数をつけていくような感じで動いていきます(多分).

Vue.jsを動かす

ここからが本題です. hello worldできたんでじゃあなんかのライブラリを動かしてみるかと思い,インターン*1で使ったVue.jsを動かしてみようと思いました.(Vue.jsについてもはしょります)

目標としては単純ですが,テキストボックスに入力した文字列がリアルタイムにどこかしらの要素に反映されるような単純なアプリを目指します.

KotlinでJSのライブラリを使う際は一部を除いて*2,そのライブラリのインターフェースの定義が必要となります. ここら辺はこの記事を参考にさせていただきました.

arata.hatenadiary.com

scala-js-ts-importerという便利なツールがあるらしい,ならkotlin-js-ts-importerもあるやろ!と思ってぐぐったところ

_人人人人人人_

>ないです!!<

 ̄^Y^Y^Y^Y^Y ̄

自分が探した限りありませんでした.悲しい(もしご存知の方がおられましたら教えていただけると,とてもとても嬉しいです). ないものは仕方ないので上の記事や下のリポジトリを参考にTypeScript → Scala → Kotlinとなるようにインターフェースを手作業で変換することにしました.

github.com

github.com

正直わりと似ていたりしたのでそんなに苦労はしませんでした.

Scala Kotlin
js.native noImpl
@JSName("") @native("")

上の表に対応するような形でそれぞれ書き換えたくらいだった気がします.(細かいところは他にもちょいちょいありましたが・・・)

実際に作ったkotlinコードです.

import vue.Vue

@native("window")
val w: dynamic = noImpl

fun main(args: Array<String>) {
  Vue.config.delimiters = arrayOf("{!", "!}")

  val option = json(
          Pair("el", "#app"),
          Pair("data",
                  json(
                          Pair("text", "")
                  )
          ),
          Pair("methods",
                  json(
                          Pair("clickedResetBtn", {
                            w.app.`$data`.text = ""
                          })

                  ))
  )
  w.app = Vue(option)
}

Pairはキーバリュなオブジェクトで,これを用いてjsのオブジェクトを作ります. 変数wにjsのnativeなオブジェクトwindowを割り当てたりしています.

実行結果は以下の様な感じです. f:id:tkr911:20151212102622g:plain

ちゃんとテキストに入力したのがリアルタイムに反映されているかと思います.

まとめ

あまり情報が多くなく(数というより種類),なかなか苦労しましたがなんとか動かせました. 自分もいつもはKotlinでAndroidを書いていますが,たまにはこうしてaltJSとして書くのも面白いので時々は書いて,情報をしっかり追っていければなと思います.

明日は@TachibanaKaoruさんです!お楽しみに!

*1:VOUYAGE GROUPインターンTreasure

*2:jQueryは使用可能

Javaの常識を変えるらしいPlay Framework~チュートリアルの4~

! この記事はJavaの常識を変えるらしいPlay Framework~チュートリアルの3~のつづきです。

公式ページのチュートリアル的には次は別なんだけど、せっかくだからGETとかのリクエストパラメータの取得をやる。

リクエストパラメータの取得

Play FrameworkのController側で、テキストボックスからGETリクエストされたパラメータの値を取得して表示してみる。 - 感謝のプログラミング 10000時間 を参考にしてやってみよう。

routesファイルの修正は必要なくてcontrollerを変えればいいみたいなので前の記事で作った/show/:idを/show?pageみたいな感じにしてみます

    public static Result show() {
        String page = Form.form().bindFromRequest().get("page");

        return ok(index.render(page));
    }

Form.form().bindFromRequest().get("page");これですねー、このメソッドで"page"を取得するみたい。 じゃあpostのときはと言いますと同じようにしていいみたい。個人的には区別していて欲しかった。

Javaの常識を変えるらしいPlay Framework~チュートリアルの3~

!これはJavaの常識を変えるらしいPlay Framework~チュートリアルの3~の続きです。

httpルーティング

だいぶチュートリアルらしくなってまいりました。ルーティングとはなんぞやとかはおググりください。

Playでは/project/conf/routesなるファイルにルーティングを追加していくらしいです。では実際にみてよう。

# Routes
# This file defines all application routes (Higher priority routes first)
# ~~~~

# Home page
GET     /                          controllers.Application.index()

# Map static resources from the /public folder to the /assets URL path
GET     /assets/*file               controllers.Assets.at(path="/public", file)

ほーん、なるほど。

/にGETリクエストが飛んできたら controllersパッケージのApplicationクラスのindexっていうメソッドを呼び出すらしい。

では該当ファイル(/project/app/controllers/Applicationを見てよう

package controllers;

import play.*;
import play.mvc.*;

import views.html.*;

public class Application extends Controller {

    public static Result index() {
        return ok(index.render("Your new application is ready."));
    }

}

対応するメソッドがあった。

index.render()はよくわかりませんが、引数のStringを何かしらで描画するんでしょう。

じゃあなんか適当なの追加してみよう。GETで/testにリクエストしたら同じものが表示されるようにするにはroutesファイルに

GET     /test                      controllers.Application.index()

で行ける気がする。

実際できるのでお試しを

ほかにも引数とか渡したいときはこんなふうにしてみればいい routesファイル

GET     /show/:id                      controllers.Application.show(id: Int)

Application.java

    public static Result show(int id) {
        return ok(index.render("Your new application is ready." + id));
    }

わかりやすい。癖で型をIntではなくintにしそうになるのは気をつけねば、ここらへんはScalaにならっているらしい。

あとこの引数は正規表現でも行けるみたい 優先順位とかは先に宣言されたものになるらしいので気をつけていきたい

リバースルーティング

リバースルーティング・・・?なんぞ?Web初心者にはわからないことがいっぱいだ。

redirectさせたいときとかPlayではredirect(String uri)を使うんだけど、このURIが変更されたらめんどくさい。 そんなときにリバースルーティングを使えば柔軟に行けそう。 一言で言えば逆引き、コントローラーに対応するURI返してくれる便利なやつ。

さっきの例で/look/:idにGETリクエストしたら/show/:idにリダイレクトしたいって場合を考える。

まずroutesファイルに

GET     /look/:id                      controllers.Application.look(id: Int)

でもってApplication.javaに対応するメソッド

    public static Result look(int id) {
        return redirect("/play/show/" + id);
    }

で、要求は満たせるんだけど、showがリファクタリングとかされると動かなくなるのでApplication.javaをリバースルーティング使って

    public static Result look(int id) {
        return redirect(controllers.routes.Application.show(id));
    }

ってすることで/show/:idが/hoge/:idになったとしてもURIを逆引きしてくれる感じ。

ここでcontrollers.routes.Application.show(id)ってなってるのはおまじないって書いてもいいんだけど、公式を見るといいと思います。

やっぱJavaはたのしいなあ

Javaの常識を変えるらしいPlay Framework~チュートリアルの2~

! この記事はJavaの常識を変えるらしいPlay Frameworkの続きです.

というわけでチュートリアルを続けていきます。今日は飲み会なので張り切って行きましょう。

新しいアプリケーションの作成

activatorコマンドで簡単に新しいPlayアプリケーション作成できるらしい。ほい

$ activator new tutorial-app play-java
Fetching the latest list of templates...

OK, application "tutorial-app" is being created using the "play-java" template.

To run "tutorial-app" from the command line, "cd tutorial-app" then:
/home/user/play-test/tutorial-app/activator run

To run the test for "tutorial-app" from the command line, "cd tutorial-app" then:
/home/user/play-test/tutorial-app/activator test

To run the Activator UI for "tutorial-app" from the command line, "cd tutorial-app" then:
/home/user/play-test/tutorial-app/activator ui

おーなんかいろいろできた。ちなみにこれJavaですけどScala大好きっ子なら

$ activator new tutorial-app play-scala

Scalaアプリケーションもいけるみたいよ。 activator恐ろしい子・・・!そのうちまとめよう。 新しく作成されたディレクトリいって

activator

とか叩けばPlay consoleに入れるらしい、、、Play Console ...?多分次のチュートリアルでわかる気がする

実際何が作られるかは公式見た方が分かると思うので見よう。でも構造が個人的にわかりやすくてすごく好き。

Play Console

なんかよくわかんないけど、開発をサポートしてくれるらしい、ちなみにTabで補完効いた

まずはhelpコマンド、例えばrun

$ help run
Runs a main class, passing along arguments provided on the command line.

なるほどmain class実行して引数に従ってゴニョゴニョしてくれるらしい

次、runコマンド

$ run
[info] Updating {file:/home/user/play-test/tutorial-app/}root...
[info] Resolving jline#jline;2.11 ...
[info] downloading file:/home/user/activator-1.3.2/repository/org.scala-lang/scala-library/2.11.1/jars/scala-library.jar ...
[info]  [SUCCESSFUL ] org.scala-lang#scala-library;2.11.1!scala-library.jar (439ms)
[info] downloading file:/home/user/activator-1.3.2/repository/com.typesafe.play/play-java_2.11/2.3.8/jars/play-java_2.11.jar ..
[info]  [SUCCESSFUL ] com.typesafe.play#play-java_2.11;2.3.8!play-java_2.11.jar (57ms)
.
.
.
--- (Running the application, auto-reloading is enabled) ---

[info] play - Listening for HTTP on /0:0:0:0:0:0:0:0:9000

(Server started, use Ctrl+D to stop and go back to the console...)

最初runした時はupdate多くていろいろ表示されるけど結局サーバー起動するよー、Ctrl+Dで止められるよーでいいんじゃなかろうか でブラウザで適当にlocalhostに9000番でアクセスすれば下の画像みたいになる f:id:tkr911:20150417101339p:plain sakuraVPSとかで借りてるサーバで動かしたいなら下のサイト参考にしてみるといいと思います。ぼくはそうしました。 nginxからPlay Frameworkを呼ぶ ただ上記のままだとエラー出ちゃうので(上の図みたいな)locationの/play/を/playと変えたら動いた。

疲れたので今日はここまでで

Javaの常識を変えるらしいPlay Framework

Play Frameworkとは

なぜやるのか

インストール!

1.JavaのInstall

yumyumと思ったんだけどJava7までしかないので以下を参考にJava8をInstall
RPMを使って java 8 を CentOS 6.5 にインストール

javaとjavacで入ってるかを確認

$ java -version
java version "1.8.0_45"
Java(TM) SE Runtime Environment (build 1.8.0_45-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.45-b02, mixed mode)
$ javac -version
javac 1.8.0_45

2. Activatorのインストール

よく知らんがsbtやらを勝手に入れてくれる頭のいい子らしい 公式ページいってダウンロードしてPath通せばいいらしいのでそのようにする

できたのか確認するため以下コマンドを

$ activator -help
Usage: activator <command> [options]

  Command:
  ui                 Start the Activator UI
  new [name] [template-id]  Create a new project with [name] using template [template-id]
  list-templates     Print all available template names
  -h | -help         Print this message

  Options:
  -v | -verbose      Make this runner chattier
  -d | -debug        Set sbt log level to debug
  -mem <integer>     Set memory options (default: , which is -Xms1024m -Xmx1024m -XX:MetaspaceSize=64m -XX:MaxMetaspaceSize=256m)
  -jvm-debug <port>  Turn on JVM debugging, open at the given port.

  # java version (default: java from PATH, currently java version "1.8.0_45")
  -java-home <path>  Alternate JAVA_HOME

  # jvm options and output control
  -Dkey=val          Pass -Dkey=val directly to the java runtime
  -J-X               Pass option -X directly to the java runtime
                     (-J is stripped)

  # environment variables (read from context)
  JAVA_OPTS          Environment variable, if unset uses ""
  SBT_OPTS           Environment variable, if unset uses ""
  ACTIVATOR_OPTS     Environment variable, if unset uses ""

In the case of duplicated or conflicting options, the order above
shows precedence: environment variables lowest, command line options highest.

雰囲気良さそうなので次へ...と思ったらPlayでやるために必要なインストールはこれで完了らしい・・・ 楽ちん! 次は公式Homepageのチュートリアルに従って簡単ななにかをつくろうか