ホーム ブログ ページ 28

Trelloで簡単タスク管理

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。


タスク管理の方法は、紙に書き出す、付箋を使って管理する、タスク管理ツールを使うなど人それぞれだと思います。 今回は、私が普段から使っているタスク管理ツールを紹介します。

Trelloとは?

Trelloとは、Fog Creek Softwareが2011年に開発したウェブアプリケーションです。
基本的に無料で使うことができ、付箋を扱うのに近い感覚でタスク管理を行うことができます。
それでは、実際に画面を見てみましょう。
enter image description here
[Fig1. 初期画面]

何もない青い画面が出てきます。この画面を ボード と呼び、全ての付箋が集まる画面です。しかし、このままでは付箋を貼ることはできません。

画面の「リストを追加」からリストを追加しましょう。
enter image description here
[Fig2. リスト作成]

ここでは例として、[ToDo], [Doing], [Done]の3リストを作成しました。
1つのタスクを書いた付箋は、このリストの中に作成します。作成した付箋のことを、 カード と呼びます。
タスクには重要度や要件によってラベル(Fig2中、カードについている緑と黄色のタグ)を付けることができます。

カードはタスクの進行状況に合わせて動かすことができます。
enter image description here
[Fig3. カードを動かす]

これにより、タスクの進行度合いが視覚的に把握できます。

また、TrelloはスマートフォンやPC、タブレットといった様々な端末で使うことができます。
PCで使う際には、私はGoogle Chromeで利用することをお勧めします。
その理由は、便利なアドオンの存在です。

あわせて使うと便利なアドオン

Elegantt for Trelloについて

ガントチャートというものがあります。
これについては触れませんが、Elegantt for Trelloはカードからガントチャートを作成するというアドオンです。
画面を見てみましょう。
enter image description here
[Fig4. Elegantt for Trello]

ガントチャートが作成されています。

また、ガントチャートからタスクの進行度合いが分かります。
enter image description here
[Fig5. 進行度合い1]

「やること1」の進行度合いは0%となっています。タスクの進行に合わせてカードを右のリストに移動させることにより、進行度合いも増加します。

enter image description here
[Fig6. 進行度合い2]

逆に左のリストに戻せば、進行度合いは減少します。

Card Colors for Trelloについて

このアドオンを入れていない状態では、カードの色は白となっています(「やること2」、「やること3」のように)。
Card Colors for Trelloは、カードの色を一番最初につけたラベルの色、またはついているラベルの色を混ぜた色とすることができます。
これによって、カードの色から重要度、要件を判断することができます。より視覚的にタスクを管理できるということですね。

おわりに

Trelloは個人で使うも良し、チームで使うも良しの大変便利なツールです。
皆さんもガンガン使ってみましょう。

【cron × Gmail】バッチ実行エラーを手軽に監視しよう

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

今回のお話

こんにちは。いくたです。
宝塚歌劇公式サイトの更新を5分ごとに巡回して通知するボットを作りました。

このようにほぼ常時動いてるようなプログラムを組む時には、 何かしらエラーが発生した時に気づけるような仕組み が必要です。
今回はcronのメール送信機能を使って手軽にエラーの監視をしていきます。

cron以外にもスケジューラは色々とありますが、サーバーをわざわざ立てたりログローテーションを設定したりと面倒なことが多そうです。
そこでcronで使える お手軽 な運用・監視方法を考えました。

(ボットの紹介は今回の趣旨とは違いますが、よかったらフォローしてください。)
https://twitter.com/PolarChildren

このボットの大まかな仕組み

  1. サイトの更新履歴ページの一番上(最新)をNokogiriでスクレイピングして取得(スクレイピングについて詳しく知りたい方はこちらの記事もご覧ください)
  2. 前回の結果(テキストファイルに保存してある)と比べる
  3. 違いがあれば各所(twitter/slack/line)に通知する
  4. 新しい結果をテキストファイルで保存

この一連のプログラムを5分に1回動かしているのが cron です。

cronとは?

cronとはUnix系のOSで使われるシステムで、様々なコマンドを定時実行してくれます。
詳しい設定方法などはこちらの記事を参考にしました。

今回作ったボットのcron設定

$ crontab -l
# 実行時の出力内容をメールで送ってくれる(ボット専用のメールアドレスを取得)
MAILTO="test.mail.for.bot@mail.com"

# cronの書式
# 分 時 日 月 曜日 実行したいコマンド
# サイト更新監視バッチ(毎時間の0分から55分まで5分毎に実行)
0-55/5 * * * * /bin/bash -lc 'ruby ~/scripts/takarazuka/update_catcher.rb'

/bin/bash -lc の -l はログインシェルと同じ環境で実行したい時使うオプションで、 -c は引数にとった文字列( ruby ~/scripts 〜 以下)をコマンドとして実行するオプションです。

MAILTO を使うことで実行時の出力をメールに転送することができます。

# こんな感じのメールが来る
=====
From: サーバー
To: test.mail.for.bot@mail.com
Subject: Cron <サーバー> /bin/bash -lc 'ruby ~/scripts/takarazuka/update_catcher.rb'
-----
[debug] -- START --
[debug] loaded setting file.
[debug] execute: takarazuka
[debug] result is OK.
[debug] {:title=>"花組公演『ポーの一族』ムービーページ 更新!", :link=>"https://kageki.hankyu.co.jp/revue/2018/ponoichizoku/movie.html"}
[debug] This site is updated.
[debug] tweeted
[debug][message]
宝塚歌劇公式ホームページが更新されました。
【花組公演『ポーの一族』ムービーページ 更新!】
https://kageki.hankyu.co.jp/revue/2018/ponoichizoku/movie.html
[debug] -- END --
=====

メールを使ってエラー通知

ボット専用のメールは普段見ないのでエラーがあっても気づけません。
そこでエラーのログが出力されたメールを、普段使っているメールアドレスに転送するようにしました。

例外エラーをキャッチする

まず、プログラム内でエラーをキャッチして [error] と出力させます。
後々メールで出力結果を送った時に固定文字’error’でエラーメールを振り分けます。

puts '[debug] -- START --'
begin
  # サイトの更新を監視して通知する UpdateCatcher のインスタンスを生成・実行
  UpdateCatcher.new.execute
rescue StandardError => error
  # 例外エラーをキャッチして出力する
  puts "[error] #{error}"
end
puts '[debug] -- END --'

メールのフィルタ・転送を設定する

Gmailにはメールを条件で分けて処理するフィルタ機能があります。
Gmailのフィルタルールの作成方法

このフィルタ機能を使って、本文中に’error’が含まれるメールだけを自分のメールアドレスに転送します。
これで実行時に何かエラーが発生しても、すぐに気づいて対処できます。

# こんな感じのメールが来る
=====
From: サーバー
To: test.mail.for.bot@mail.com
Subject: Cron <サーバー> /bin/bash -lc 'ruby ~/scripts/takarazuka/update_catcher.rb'
-----
[debug] -- START --
[debug] loaded setting file.
[debug] execute: takarazuka
[error] Failed to open TCP connection to kageki.hankyu.co.jp:443 (getaddrinfo: Name or service not known)
[debug] -- END --
=====

メリット

メリット① 容量を気にしなくていい

RubyのLoggerを使えば割と簡単にログを出すこともできます。
しかし、サーバーにログを残すということは、多少なりとも容量を気にして管理することが必要です。

そこでログを出さずに全てメールで送ることでサーバーの容量を気にせず使えます。
(代わりにメールサーバーのディスク容量を圧迫していくので、自分のメールアドレスに全ログ送るのはやめましょう)

メリット② 必要な情報が検索しやすい

過去の実行状況を確認したいときも、送信日時(実行日時)やキーワードでメールを検索すればまとめて確認することができます。
個人的にはテキストファイルのログよりブラウザで確認できるほうが分かりやすくて気に入っています。

メリット③ Gmailのフィルター機能で応用が利く

Gmailのフィルター機能は細かくカスタマイズが可能です。
先ほどは転送機能を紹介しましたが、既読にしたりフラグを立てたりすることもできます。

Gmailのフィルタルールの作成方法

私の場合はエラーメール以外は既読にして、エラーメールはフラグをつけて後から探しやすくしています。

スクリーンショット 2017-11-29 13.34.41.png
エラーメールのフィルタ設定

デメリット

デメリット① 実行自体出来なかった場合気づけない

この仕組みはRubyが実行できる前提なので、なんらかの理由で実行ができなかった場合(ファイルが壊れてるとか)エラーを正しくキャッチできない場合があります。

# こんな感じのメールが来る
=====
From: サーバー
To: test.mail.for.bot@mail.com
Subject: Cron <サーバー> /bin/bash -lc 'ruby ~/scripts/takarazuka/update_catcher.rb.hoge'
-----
ruby: No such file or directory -- /home/ikuta/scripts/takarazuka/update_catcher.rb.hoge (LoadError)
=====

これだと ‘error’の文字列に引っかからないので自分のメールアドレスには転送されません。
本来なら、cronで標準エラーを受け取ってメールする設定をする必要があります。
その場合、Rubyで例外エラーをキャッチすると異常終了ではなく正常終了するので、スクリプトの方も工夫が必要です。

参考:
cronの設定について
Unix :: cron / 標準エラー(STDERR)のみアラートメールする

デメリット② 頻繁にメールを送るとスパム認定されるかもしれない

今の所問題なくメールは送られていますが、昼も夜もなく5分に1回メールを送っているのでGmailに目をつけられてスパム認定されてしまう可能性もあります。

デメリット③ 汎用性がない

ログとしてファイルに出力すれば、そのデータからいろんなことを分析することができます。
今回のボットでいえば、「サイトの更新がどれだけ頻繁に起きているか」とか「何曜日が一番更新されやすい」とかです。
しかし、今回はメールで全て送ってしまって手元に何も残らないので、出力を眺めることしかできません。

まとめ

今回紹介した方法は業務レベルでは使えませんが、趣味でやっている分にはこれで充分かと思います。

それでは、今日はこの辺で。
読んでいただき、ありがとうございました。

rubyで抽象メソッドを表現する

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

rubyについて調べていたら抽象クラス/メソッドをサポートしていないようでした。
ですが抽象メソッドのようなものを簡単に表現できるようなのでそれを紹介したいと思います。


オーバーライドしなきゃエラー!


抽象メソッドはオーバーライドを強制するのが目的なので、オーバーライドされてなければエラーする形で実装してやれば表現できます。

class GameObject

  # GameObjectを継承した描画の実行はこれを呼び出す
  def draw
    draw_proc
  end

  # これを子クラスでオーバーライドしないと
  # drawから呼ばれてエラーになる
  def draw_proc
    raise "call abstract !"
  end

end


class Circle < GameObject
  def draw_proc
    puts "丸だよ"
  end
end


class Box < GameObject
  def draw_box
    puts "四角だよ"
  end
end
circle = Circle.new
circle.draw
=> 丸だよ

box = Box.new
box.draw
=> RuntimeError: call abstract !

draw_procを継承していないBoxクラスから描画メソッドを呼び出したらちゃんとエラーを出してくれました。


おわりに


rubyでプログラミングしていて「これエラーにならないんだ」と思うところが多々ありました。
それもそのはずで、そもそもrubyの設計思想がストレスなくプログラムを楽しめるようにといったものらしいのですが、c++を使っていた自分からするとある程度縛りの効いたルールがある方が安心して動けるので、この記事を書くに至ったわけです。
でもせっかく自由に楽しくがモットーの言語なのにそれを制限するのも変な感じがするので自由さを生かすような設計をしていきたいですね。

【roo】ExcelファイルをRailsで読み込む

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

今回は使っていて便利だった、excelを読み込むライブラリ【roo】について書きたいと思います。

はじめに

 約10年ぶりぐらいにバッティングセンターに行ったらバットにボールがほとんど掠りもせずに全身筋肉痛になりました、むらさきです。
 今回は、.xlsxファイルから必要な情報を抜き出して使うことがあった時に利用したrooというライブラリについてまとめたいと思います。

rooとは?

 rooとはスプレッドシートの読み込みができるライブラリです。.xlsや.xlsx、.odsや.csvなどに利用できます。google spreadsheetにも利用できるようです。
 読み込み専用で書き込みや新規作成等はできません。

インストール方法

 rooのインストールは

 gem install roo

 で簡単に行えます。

使ってみよう

インストールが終わったので実際に使ってみましょう。
今回は下のシートを使用します。rooは読み込み専用のライブラリなので、データを読み込んで表示させてみます。

enter the description

1.読み込みたいファイルを指定する

require 'roo'

xlsx = Roo::Excelx.new(file_path)

.xlsxファイルを取得する際には上記のように読み込みたいファイルのパスを指定して書きます。
.xlsxファイル以外の場合は

Roo::Excel.new(file_path)             #.xlsファイル
Roo::Csv.new(file_path)               #.csvファイル
Roo::OpenOffice.new(file_path)        #.odsファイル

と書く事で指定できます。

2.使用するsheetを指定する

xlsx.default_sheet = 'spices'
xlsx.default_sheet = xlsx.sheets[0]

直接sheet名を入力するか、sheetsの配列から指定するができます。

3.指定したセルに入っているデータを表示する
例として「ターメリック」と「シナモン」を取り出したいとします。
「ターメリック」はシートの2行、2列目
「シナモン」はシートの5行、2列目なので

xlsx.cell(2,2)   #=> "ターメリック"
xlsx.cell(5,2)   #=> "シナモン"

とすることで取得できます。

4.ループで取得する
最後に、例として材料の名前だけをすべて表示します。

2.upto(xlsx.last_row) do |row|  
  p xlsx.cell(row, 2)    #2列目を1行ずつ取得する
end  #=> "ターメリック","ナツメグ","唐辛子","シナモン","クミン","コリアンダー"

おわりに

いかがだったでしょうか。読み込みだけですがとても簡単に扱える便利なライブラリでした。
rooという名前だったのでシートにカレーのスパイスを使ったんですがスパイスを調べる際にセルフ飯テロをかましました。カレー食べたい。

椅子が変われば環境も変わる?良い椅子のすすめ

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

作業環境を改善したいそんなときにデスクワークと密接な関係をもつ椅子の話です。

 腰痛肩こり眼精疲労・・・。日々長時間デスクワークを行うとこれらの体の負担も著しくなります。そこで日々の労働から体の負担を軽くしより効率よく作業できるような環境にするために重要なのが椅子です。今回は労働者の体に合わせて考えられたワーキングチェアについてお話いたします。

▼こだわりの3つの性能

 座っていても疲れにくい椅子は人間工学などあらゆる分野から考え抜かれたデザインをしています。具体的には以下の3点に注目し作られています。

体圧が分散されるデザイン

 物に座ると身体の表面に圧力がかかります。硬いものに座れば安定しているものの局部的に圧力がかかり、しかし柔らかいものに座れば圧力は分散されますが姿勢が崩れやすくなってしまいます。椅子の座面は体の圧力が分散され、かつ安定感を持って座れる程よい固さ追求しています。また体に沿ったデザインにすることで椅子との接触面積を広げることで、圧力の分散と姿勢保持を両立させています。
`

背骨が自然なS字曲線を描けるようなデザイン

 人間の背骨は2本足で立ったときのバランスをとるために常にS字のようなゆるやかなカーブを描いています。しかし座った途端このS字形状は崩れ、アーチ型に歪んでしまいます。そうすると腰や椎間板への負担も大きくなり、やがて腰痛や疲れ、内臓の圧迫などの疲労へと繋がっていきます。そこで注目されたのが背もたれの形状です。人間の背骨の曲線に合わせたデザインや骨盤を支えより安定感のある座り心地を追求したデザインなど、背骨に対するサポート機能が数多く備わっています。中には体が前すべりしてしまわないよう座面の一部に傾斜をつけたものもあります。

自分に合った高さに調節できる設計

 人間の体に合わせたデザインとはいうものの使う人によって体格の違いや姿勢差などが生じます。いくら良い椅子であっても足が届かなかったり、背もたれの曲線が合わなかったりすると折角のサポート機能も意味がありません。自分の身長や姿勢に合わせて座りやすい高さや角度に調整できることも椅子選びの中で大切な要素です。

▼こだわりの機能と形状

 3つの要素を追求した結果、そのこだわりは椅子の形状や付属機能に反映されています。
肘掛の有無や、もたれかかった方向へ傾くロッキング機能、背もたれ一つにしても背の高いものから低いものと多種多様です。

背もたれの高さ

 背もたれはおおまかに「ハイバック」「ミドルバック」「ローバック」の三種類の大きさに分かれます。背もたれの高いハイバックは頭部までもたれかけられるので首の負担が減ります。そのため1日3時間以上の長時間作業でも疲れにくい状態で過ごせます。ただしサイズも大きく部屋の広さによってはかなりの圧迫感が生じます。ミドルバックはハイバック・ローバックの中間の高さです。ハイバックのように3時間以上の作業にも適切、というわけではないのですが、ある程度の時間なら疲れ辛く作業ができ、部屋もあまり圧迫されないサイズ感となっています。最近ではヘッドレストが付属しているものが多いですね。ローバックは上記の二つよりも更に背もたれが低くコンパクトな印象。背が低い為視界を遮ることなく一人暮らしの部屋にほどよくおさまるサイズです。価格も一番安いのですが、長時間作業をするには不向きな為、1日1時間と短時間作業を行う人におすすめです。

肘掛

 肘掛があるとやはり腕の負担がかなり軽減されます。腕は体全体の16%もの重量をもっており、マウス作業やタイピングするときは宙吊り状態になりがちです。肘掛があることによって腕の重みが肘部分で分散され、かつ安定した状態で作業を行うことができます。また肘掛に肘を置いたポーズは肩甲骨周りの筋肉を休められるポーズにもなっているのでデスクワークの最中にこまめに行うのもおすすめです。
ただ、作業机の高さによってはひじかけが邪魔で机の下に収まらない場合もあります。購入の際は肘掛の高さが調節可能かどうかなのも含めて、机との兼ね合いも見ながらの検討が必要です。

ロッキング機能と高さ調節

 ロッキング機能があると椅子を自由な角度に傾けられるので椅子に座ったままで楽な姿勢がとれます。体に合った角度に倒したまま作業ができるという点でもポイントが高いですね。椅子の高さ調節は個々に違う机や画面の高さ、または使っている個人の脚の長さによって調節しなければならないので非常に重要です。まず、変更できる高さの中に自分の体に合った高さがあるもの。そして簡単に自分の好きな高さに微調整できるものがおすすめです。

前傾型後傾型

 ひとくくりにデスクワークといっても業種によって仕事中にとる姿勢は前傾と後傾の二種類に分かれます。前傾はアナログや液晶タブレットを使用したイラスト業務、もしくは作業をする際いつも前のめりになってしまう人にはうってつけです。後傾はキーボードでタイピングするタイプのものから何かと汎用性の高い姿勢がとれるようになっています。
後傾に比べ前傾タイプのものは数が少ないのですが、作業中によくとる姿勢を思い浮かべながら作業スタイルに合った一品を探すと良いと思われます。

▼今からできる作業環境の改善

 ここまで紹介してきましたが、高価なものや種類も様々でなかなか購入に踏み切れなかったり、手元に届くまで待つまでの間もどうにか作業環境を改善したいと思う場合もあります。
そんなときは
・画面を高くするなどして無理のない姿勢で作業できる環境にする
・腰の後ろや体の下にクッションを敷いて無理なく正しい姿勢で座る
・画面の明るさを下げ眼精疲労から来る肩こりを和らげる
といったことを試してみるのも良いかもしれません。

▼最後に

 そんな考え抜かれた椅子でも全ての肉体的負担から解放してくれるわけではありません。どんなに良い椅子に座っていても長時間作業すれば疲れは表れます。気分転換に立ち上がったり目を休めたりなど合間に休憩を取りながらデスクワークに励んでください。

Rubyで大域脱出

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

Rubyの大域脱出の紹介と、大域脱出のためにエラーを利用するなって話と、そもそも大域脱出を考える時は設計がおかしい可能性があるので考え直しましょうって話です。

はじめに

お疲れ様です、くろすです。

ようこそ、ここは黒魔術の入口だよ

大域脱出

rubyには大域脱出用のメソッドがあります。
throw..catchです。
普段書くようなコードで見るような関数ではないので、存在を知らない人も多いと思います。
動き的には普段見るコードで言う所のraise..rescueみたいなヤツです。
深いところからズバッと抜けられるので気持ちがいいです。

ただraise..rescueみたいなヤツと思って使うのはやめましょう、怪我の元です。

まず、raise..rescueですが、これは 例外処理 に使います。
例外クラスの部分を見ていただければわかると思いますが、ruby本体では例外をErrorの名を冠せず使ってる場所はかなり少ないです。
結果として大域脱出できますが、本質的にはエラーハンドリングのために存在しているよう思えます。

次に、throw..catchですが、これは大域脱出に使います。大域脱出専用です。
引数で指定したオブジェクトをthrowしないと怒られれます。

実用例

まず、エラーを大域脱出のために使っちゃったコードを見てみましょう。
なんとも運のいいことにが過去記事で使っちゃってるんですね。
肥大化するAIと対峙する時に覚えておきたいこと
この記事こんなことが書いてあります。

 (略)
 class NotIntelligence < StandardError; end

 def self.get_ai(code)
   # ai = AIManager.get_ai(code).new(code)のように呼ばれた時の大域脱出で使う
   raise NotIntelligence unless @codes_to_ai.keys.include?(code)
   @codes_to_ai[code]
 end
 (略)

アホになれないcodeを割り振られた子たちはNotIntelligenceエラーを返されるという、なんとも分かりにくい説明コードを書いてしまいました。

この記事では肝心の大域脱出に当たる部分が書かれていませんが、おそらくこんな感じになるかと。

(というか AIManager.get_ai(code).new(code) ってめっちゃ気持ち悪いですね、このコード書いたヤツだ )
ai = 
  begin
    AIManager.get_ai(code).new(code)
  rescue
    nil
  end

さあ危険な匂いがして来ましたね!!!
これでも動きます。残念ながら動いてしまいます。
NotIntelligence は StandardErrorを継承しているのでrescueで掬い上げられてしまいます。
全員が全部を理解して書いていれば問題ないのですが、そんなことは無理です。諦めましょう。

つまりこうすればいいんでしょ?

rescue NotIntelligence

と言われそうな気もしますが、そもそもNotIntelligenceはエラーではないのでrescue..raiseを使うのはやめましょう、というお話です。

throw..catchで書き直すとこんな感じですね。

def self.get_ai(code)
  unless @codes_to_ai.keys.include?(code)
    throw :not_intelligence, nil
  else
    @codes_to_ai[code]
  end
end
ai = catch :not_intelligence do
     AIManager.get_ai(code).new(code)
   end

そもそも使わなくていい

ここまで大域脱出について書きましたが、そもそも使わなくていい場合が多いです。設計を見直した方がいいと思います。
今回の場合はaiの定義場所を見たときどういう場合はaiが生成されないかを明確にしたかったのと、AIインスタンスを作成する場合にAIクラスが存在しない可能性があることを意識したくないので大域脱出を使用してますが、そもそもコメントで十分ですし、AIManager(Managerってクラス名も悪い)側で基本的なAIを必ず生成すれば使用する側からはAIがあるかないかを考えずに使用できます。
get_aiとかいうクラスを返す頭悪いコードもいらないですし、設計した私がアホです。

options = { code: code }
ai = AIBuilder.build_by(options)

class AIBuilder
  def build_by(code: nil)
    if @codes_to_ai.keys.include?(code)
      @codes_to_ai[code].new(code)
    else
      DefaultAI.new
    end
  end
end

こんな感じの方がいいですね。AIBuilderには@codes_to_aiが定義されてないので動かないんですけど。

じゃあどんな時に使えばいいのかという疑問がありますが、長いメソッドチェーンを途中で切り上げたい場合や、自前でvalidationを作る場合に他の処理と同列に書きたい場合などは大域脱出使えるんじゃないかと思います。
あまり見ないコードなのでわかりやすさは置いといてって感じになりますし、
効果的って意味じゃなく、あくまで使用可能って意味での「使える」って感じしかしないですけど。

複数ループの中から脱出したい & そのループの数をうまいこと減らそうとすると生成されてしまうarrayが要素数に比例してでかくなる & その要素数が外から操作できるので危険
みたいなすごく特殊な状況じゃないと使えない気がしますし、そんな状況だと普通の人ならメソッドにして値をreturnすると思います。

深い木構造の検索をかけて該当のものが見つかり次第脱出とかなら使えますかね……
もうちょっと面白い使い方ないかなぁ……

終わりに

関数途中のただ処理を切り上げるだけのreturnって、個人的には広義のgotoな気がしてあんまり使いたくないから大域脱出の紹介したんですけど、throw..catchほど直接的にgotoな感じはしないからうーん…って感じです。
returnに比べてthrow..catchの方が意味を持って処理を切り上げられる上に深いところからも脱出できるんで使い勝手いいんじゃないかとは思いますが、そういう目的だと実際に使えるかは微妙ってところですかね。

大域脱出のことを考えてたら、考えが継続渡しに流れ、schemeならcall/ccだなーと考えつつググるとどうもrubyにもcallccが黒魔術としてあるらしいことを知り、でもそんなコード誰も読めなくなってしまうと闇に葬りました。
ただ闇のコードは書いてて楽しいので、そのうち何か記事にするかもしれません。

【git】変更を一時退避する

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

pushしないといけない変更をpushしないまま、新たに中途半端に変更を加えてしまった時のコマンド
 

保存

まず現在の変更を保存します。
addとかしていたら全部戻します。

git stash save

このコマンドで保存ができます。(saveは省略可能です。)
これでdiffをチェックするとdiffがなくなっているので、pushができるようになります。

確認

保存されているのを確認するにはこのコマンドを利用します。

git stash list

このコマンドを利用すると

stash@{0}: WIP on sample_branch: 889808 commit_comment

というように一時保存したリストが出てきます。
もっと詳細な変更を見たい場合はこのコマンドを利用します。

git stash show <スタッシュ名>

<スタッシュ名>の部分にはリストに出てきた「stash@{0}」などを入れます。
このコマンドを利用すると

 sample.txt | 1 +
 1 file changed, 1 insertion(+)

このように変更したファイルなどを参照することができます。
 

変更を戻す

変更を戻すにはこのコマンドを利用します。

git stash apply <スタッシュ名>

あまりスタッシュが残ってしまうとどれがどれだかわからなくなってしまうので、削除も行います。

git stash drop <スタッシュ名>

リストを確認すると消えていることがわかります。
定期的に整理を行うことをおすすめします。
ちなみに、このコマンド

git stash pop <スタッシュ名>

復活させて削除、これら2つを一気に行ってくれます。
 

最後に

半年ほど前、初めて使った時に何をやったのか変更消してしまったので、二度と使うものかと思いながら仕事をしていました。
つい先日どうしてもその日にpushしないといけないものをpushしないまま新しいタスクに着手し、このコマンドを叩くことになりました。
今回は失敗しなかったので、またも備忘録です。
前回はpopとdropを間違えたのか?もう何をやって消してしまったのか思い出せませんが、気をつけて使用しましょう…。

モーション用ミニキャラクターの作り方②

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

はじめに

今回はキャラクターチップの表情差分の作り方をご紹介いたします。

表情差分

キャラチップを作成するのに重要になる一つが表情です。
表情はユーザーの視点が集まりやすく、演出にも関わる部分だからです。
喜怒哀楽のパターンがあれば大体の表現ができます。
enter image description here
まず設定に必要なパーツを考えます。
キャラクターの性格や現場のルールによって必要なパーツも変わっていくと思います。
アクションであれば攻撃をする勢いのある表情や、ダメージを受ければ痛い表情などがあるとモーションとして動かすのに魅力が出ます。

作る際のポイント

デフォルトの目を中心基準にして作っていき、パーツを切り替えた際に違和感がないようにします。
enter image description here
・目
笑顔のパーツなら瞼が下がるので、目の全体の高さが下がります。
描く時はデフォルト目の不透明度を下げて別レイヤーで上から描くとズレにくいです。

・口
これも目と同様通常状態のパーツから差分を作っていきます。
小さいパーツなので、遠目で見てバランスが合っているか調整していきます。
個人的には少し小さめに描いた方がちびキャラなどは可愛く見えるかと思います。

まとめ

量産する必要があるチップテクスチャは、パーツの型(骨組み)を使いまし装飾(髪型・服装・目など)を付けていくことが多いと思います。
そのため最初の型パーツを作成する場合はある程度先を見越して、後々問題点が出ても対応できるようおこなっていくのが大切です。

セオリーを知る ~プレイヤー編~

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

どんなジャンルのゲームにも「こうすべき」というセオリーは存在する。 セオリーを知らなければ損をするし、特に対人要素がある場合は致命的な不利へと繋がる。

セオリー初級 ~基礎プレイング~

 今回はセオリーとして分かりやすい対戦カードゲーム(※マジック:ザ・ギャザリングや遊☆戯☆王などのこと)を例にする。
 対戦カードゲームにおいて、「いかに盤面にモンスターを残して相手に攻撃を通すか」は最重要の課題となる。逆に「いかに相手の盤面にモンスターを残さず、攻撃を受けないか」というのも成り立つ。この観点から、デッキに採用するモンスターはできるだけ「やられにくい」「場持ちが良い」ものを選び、対戦時はモンスター同士のバトルで自分のモンスターだけが生き残るようにプレイするのがセオリーとなる。これが出来なければ勝てないと言っても過言ではない。

セオリー中級 ~逆転を意識する~

 初級で示したように、モンスター同士のバトルで対戦が進行する場合、先に盤面で有利を築いた側がずっと有利であることがままある。それを抑えるために対戦カードゲームではその状況をひっくり返すカードが用意されている。
 例えば「盤面のモンスターを全て破壊する」「相手にしかモンスターがいなければ簡単に出せる」といったものである。こういったものへの対策として、「手札に出せるモンスターはいるけど、全体破壊をされたら取り返しがつかなくなるからあえて出さない」といったプレイングが必要になる。ここが出来れば対戦ではまずまず勝てるようになってくる。

セオリー上級 ~セオリーを昇華する~

 例えば相手がモンスターを数ターン出さなかったらどうすべきだろうか。初級・中級から考えて、全体破壊を警戒して少量のモンスターで様子見しつつ攻撃するのが「最善」と言えそうだ。しかし上級者同士の対戦ではしばしば「最良」ではないことがある。つまり、「全体破壊を警戒されることを見越したプレイング」である場合だ。
 もちろん全体破壊をくらったら取り返しがつかないのだが、「最良のプレイ」は全力で攻撃することであったということが起こりうる。ここをできるだけ正確にするためには「全てのカードを知る」「相手が使ったカードを覚える」「相手のデッキを推し量る」ということが必須となる。「相手のデッキに入れられる全体破壊は5ターン目までは使用できない」ことが分かっていれば大きく有利になる。

まとめ

 ここで挙げた以外にもセオリーはたくさん存在するが、とりあえずこれらを押さえておけば戦うことは十分できるだろう。逆に知らなければ戦いにすらならないのは最初に述べた通りだ。
 今回は対戦カードゲームを例にしたが、「基礎」と「基礎のメタとなる逆転」があり、それらをより高度なものにする要素が大抵のゲームには存在している。もし伸び悩んでいるなら一度立ち返って考えてみてはいかがだろうか。

joinをベン図で表現

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

joinとは

 joinは、データベースの検索時に複数のテーブルをまとめて、検索を行うsql文です。joinには、内部結合と外部結合の2種類の方法が存在します。これらの説明は、次のセクションで行います。

内部結合(inner join)

 内部結合は、複数のテーブルを結合するときに指定する条件式に当てはまるデータのみ取得します。sqlは以下のように書きます。また、inner joinjoinと省略することもできます。
select * from テーブルA inner join テーブルB on 条件式
 内部結合の結果がどこを表しているのか分かりやすく説明する為に、数学の集合を図で表現するベン図を用いて説明します。先ほども説明しましたが内部結合は、テーブルAとテーブルBのデータを含んでいる(紐づいている)データを取得します。数学の集合で表現するとテーブルA ⋂ テーブルBになります。
enter image description here

外部結合(left outer join, right outer join)

 外部結合は内部結合とは違い、結合元のデータをすべて取得し、条件式に当てはまるデータに関しては、結合先のデータも取得します。ここで言う結合元,結合先をsql文で説明すると、テーブルAが結合元、テーブルBが結合先となります。また、left outer join,right outer joinは、left join,right joinに省略することができます。
select * from テーブルA left outer join テーブルB on 条件式
 left joinは、「結合元のデータを全て取得し、条件式に当てはまる結合先のデータも取得」します。
enter image description here
 right joinは、「結合先のデータを全て取得し、条件式に当てはまる結合元のデータも取得」します。
enter image description here

まとめ

  • 紐づいているデータのみ取得したい場合
    • 内部結合
  • データを全て取得し、関連データも取得したい場合
    • 外部結合

s3cmdでオブジェクトストレージのバケットにIP制限

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

‘aws-sdk’のようなgemを使用せずに、s3cmdコマンドを使用して s3のオブジェクトストレージバケットにIP制限を行ったのでメモ代わりに

s3cmd設定

※事前にAWSのアカウント作成してください。

$ yum -y --enablerepo epel install s3cmd
$ s3cmd —-configure
Access Key: xxxx
Secret Key: xxxx
(ほかは全てエンターのみでOK)

s3cmd lsで一覧が表示されれば設定完了。
接続できない場合はここら辺の設定を変えてください。

$ vim ~/.s3cfg
host_base = hedgehog
host_bucket = tegetege
signature_v2 = True

バケットにポリシーが設定されていないことを確認。

$ s3cmd info バケット名
   Location:  us-east-1
   Payer:     BucketOwner
   Expiration Rule: none
   policy:    none
   cors:      none
   ACL:       xxxx: FULL_CONTROL

実践

わかりやすいようにバケット名と制限IPのカラムを持つテーブルを用意。

# Table name: hoges
#  id                  :integer          not null, primary key
#  bucket_name :string           not null
#  limit_ips           :text     # json形式で保持
#  created_at          :datetime         not null
#  updated_at          :datetime         not null

class Hoge < ActiveRecord::Base
  def parse_limit_ips
    limit_ips.present? ? JSON.parse(limit_ips) : []
  end

  def set_policy_to_bucket
    create_extract_dir
    open(json_tmp_path, 'w') do |io|
      io.puts(tmp_policy_format)
    end
    # s3cmdのsetpolicyオプションを使用して、対象バケットにポリシーを設定する
    `s3cmd setpolicy #{json_tmp_path} s3://#{bucket_name}`
    delete_extract_dir
  end

  private

  # policyファイルを保持するディレクトリを作成
  def create_extract_dir
    FileUtils.mkdir_p extract_dir
  end

  # ディレクトリ名
  def extract_dir
    File.join Rails.root, :tmp.to_s, :bucket_policy.to_s
  end

 # ファイルパス
  def json_tmp_path
    File.join extract_dir, 'policy.json'
  end

 # ディレクトリごと削除
  def delete_extract_dir
    FileUtils.rm_rf extract_dir
  end

  def tmp_policy_format
    <<-"EOS"
    {
      "Id": "#{SecureRandom.hex}",  # 任意の文字列
      "Statement": [
        {
          "Sid": "#{SecureRandom.hex}", # 任意の文字列
          "Action": ["s3:GetObject"],
          "Effect": “Deny”, # 指定した内容に対しアクセスを拒否する <=> Allow
          "Resource": "arn:aws:s3:::#{bucket_name}/*”,
          "Condition": {
            “NotIpAddress": {  # 以下に含まれるIP以外
              "aws:SourceIp": #{parse_limit_ips}
            }
          },
          "Principal": {
            "AWS": ["*"]
          }
        }
      ]
    }
    EOS
  end
end

Allowだとなぜか効かない…。なのでDenyとNotIpAddressの組み合わせにしました。
(原因は不明。他記事にもAllowは効かなかったという記載がちらほら)

注意点

  • Resourceオプションはダウンロード時とアップロード時によって若干異なる。 上記のコードはダウンロード時のポリシー設定の内容ですが、アップロード時は少し異なります。
"Action": ["s3:PutObject”, “s3:PutObjectAcl”],
.
.
"Resource": [
  “arn:aws:s3:::#{bucket_name}”,
  “arn:aws:s3:::#{bucket_name}/*”
]
.
.

Actionはオブジェクトストレージにファイル(Object)を置くのでPut。
Resourceはバケット自体の記載も必要みたいです。(記載がないと403 or 404)

  • SourceIPに設定できるIPの表記方法はCIDRフォーマット
可
123.123.234.123
123.213.234.21/24

不可
123.231.23.*

反映確認/ポリシー解除

バケットにポリシーが設定されているか
$ s3cmd info バケット名

ポリシーをデフォルトに戻す
$ s3cmd delpolicy s3://<バケット名>

Kali Linux 2018.4 導入と日本語化

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

Kali Linux 2018.4 を VirtualBox にインストールして日本語化を行ってみました。Kali Linuxは、セキュリティ診断用ツールが標準で用意されている、Linuxディストリビューションです。バージョン2017.3から日本語利用までの流れが随分と楽になりました。

新バージョン2020

はじめに

Kali Linuxは、セキュリティ診断ツールを含むLinuxディストリビューションです。利用の仕方により不正アクセス行為と判断される可能性ががあります。またサービス停止やデータの破損が起こる場合もありますので事前にバックアップを行うなどしてください。そして必要に応じて管理者の許可を得て利用してください。

今回は、バージョン2017.3で行っておりますが、2018.4でも同様の方向で行うことができるのを確認しております。
また、PC本体へのインストールや、Light版の利用は、下記の記事などを参照してください。

Kali Linuxの特徴などについて

  • Debian派生のLinuxディストリビューションです。
  • デジタルフォレンジック、ペネトレーションテスト(侵入テスト)用などのツールが用意されている。
  • 基本的に、root権限で作業を行う。
  • 現在は、ローリングリリースを採用している。
  • バージョン2018.4がリリースされた。

Kali Linux 公式サイト
https://www.kali.org/

主な収録ツール

Kali Linuxには多数のツールが導入されています。
Nmap、Aircrack-ng、Wireshark、Metasploit Framework、Armitage、Burp SuiteOWASP ZAP、BeEF、sqlmap、wpscan など

※Burp Suiteの日本語化については、Burp Suiteを日本語化する方法として記事を書いております。
※Owasp ZAPについては、Mac版のOWASP ZAPで脆弱性チェックの設定として記事を書いております。

VirtualBox上にインストールする

仮想化ソフトウェア、VirtualBoxをインストールし、Kali Linuxのイメージを導入、起動させます。

VirtualBoxをインストールする

あらかじめ下記サイトからダウンロードを行いVirtualBoxをインストールしてください。
今回は、バージョン5.2.0に、Extension Packを導入してますが最新版で問題ないと思います。

VirtualBox 公式サイト
https://www.virtualbox.org/

Kali Linux イメージファイルのダウンロード

Kali Linux Downloads – Virtual Images イメージファイルのダウンロード先
https://www.offensive-security.com/kali-linux-vmware-virtualbox-image-download/

記事を確認しなおしてる時点で、直接ダウンロード出来るのはバージョン2018.4です。
中段の画像赤丸で囲ったKali Linux VirtualBox Imagesタブをクリックし、環境に適したものをダウンロードします。
(これタブですから、タブ押すと下の表が変わってVirtualBoxのイメージ選べますからね)
(名前の方をクリックしよう。Torrentって書いてある方は、イメージファイルを入手するのに別途アプリが必要です。)

Kali Linux ダウンロード

Kali Linux 仮想アプライアンスのインポートと設定

VirtualBoxを起動し、ファイル、仮想アプライアンスのインポートで、先ほどダウンロードしたkali-linux-2017.3-vbox-amd64.ovaを選択しインポートします。

Kali Linux インポート

トラブルを避けるため、すべてのネットワークカードのMACアドレスを再初期化にチェックを入れます。

Kali Linux VirtualBox MACアドレス設定

デフォルトの設定でも問題はないですが、ネットワークの割り当ては、診断対象環境との通信の関係上、DHCPで割り振られる環境などでは ブリッジなどがよいかと思います。仮想マシン同士で、テストする場合などは NATネットワークを選んでください。その他は、好みによって設定を変更します。私はCPUは、2コア使用でメモリを4GBぐらいにしています。

Kali Linux VirtualBox 設定

Kali Linux上の設定

Kali Linuxの起動とログイン

起動ボタンを押し、しばし眺めます。
Kali Linuxの起動を行いログインします。Kali Linuxのパスワードは、toorに設定されています。
 ユーザー名:root
 パスワード:toor
Usernameに、「root」と入力しNextボタンを押します、Passwordに、「toor」と入力しSign Inを押します。

Kali Linux ログイン画面

日本語関連パッケージの導入

ここで日本語関連パッケージをまとめて導入してしまいます。
画面左側の黒っぽいアイコンのターミナルを起動します。

Kali Linux ターミナル

そして下記のコマンドを入力します。しばらく時間がかかります。
画面がロックしてしまったら、パスワードを入力して解除しましょう。
また、エラーが出るようでしたら、右上のネットワークの接続について確認してみてください。
ホストPCでインターネットに接続できるようでしたら、一度仮想マシンのネットワーク設定をNATなどにしてみてください。

# apt-get install -y task-japanese task-japanese-desktop
Kali Linux コマンド入力

タイムゾーンの設定

次にタイムゾーンの設定をします。
画面の右上、電源右の▼をクリックし、設定画面を開きます。

Kali Linux 設定起動

そしてスクロールして、Details を選択し、更に Date & Time を選択し、Time ZoneをJSTにします。

Kali Linux タイムゾーン

日本語表示と日本語キーボードの設定

次に日本語表示と日本語キーボードの設定をします。
一つ画面を右上のボタンで戻り、上にスクロールして、 Region & Language をクリックします。

Kali Linux Region & Language

上記を参考に、Language、 Formatの変更します。(Formatは自動的に選択される)
また、Input SourcesでJapaneseの追加と順序の変更を行います。使用しなければUSを削除してしまっても問題ないです。英語キーボードを利用している場合は、USで問題ないはずです。
一通り済んだら、LanguageのとこのRestartを押して、ログアウトします。
再度ログインしなおすと日本語が有効になっているはずです。

Kali Linux 日本語化

今回のバージョンでは、特に日本語変換に関する設定を行わなくても利用できます。
ウェブブラウザも、この状態で日本語表記になります。

パッケージの更新

最後に既存のパッケージを最新に更新してしまいましょう。
画面左側の黒っぽいアイコンのターミナルを起動します。
そして下記のコマンドを入力します。しばらく時間がかかり、確認のため途中にyやニュース閉じるのにqの入力が必要となります。

# apt-get update
# apt-get upgrade

その他

動作の軽い、lightdmとxfceを使用したかったので、下記を行いました。

# apt-get install task-xfce-desktop

上記コマンドで、途中lightdmを選択し導入。
再起動し、ログイン画面でxfceを選択してログインします。

Kali Linux 2018.4 導入完了

Kali Linux 2018.4 を、VirtualBoxにインストールし日本語表示、日本語キーボードの利用、日本語変換が行えるようになりました。
バージョン2018.4で追加された機能、ツールは公式ブログの記事、Kali Linux 2018.4 Releaseで簡単に紹介されています。
Kaliの新バージョンをベースにCTFなどに参加してみてはいかがでしょうか。

関連記事など

脆弱性診断サービスなど

弊社、アピリッツではセキュリティ診断サービスを行っております。
下記リンクから内容の確認と、問い合わせが可能です。

http://security.appirits.com/

pythonでコマンドを扱う

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

pythonで標準入力と標準出力を扱います。

概要

pythonに慣れていて手軽に書けるので、他の言語でできることでもなるべくpythonでやりたいです。
ローカルマシンのプロセスをダンプする必要があったんですが、シェルスクリプトを書きたくなかったのでpythonで書きました。

コード

pythonのバージョンは3.6.1です。

import subprocess
import shlex
import os
from datetime import datetime

command = "ps alx"
log_file = os.path.dirname(os.path.abspath(__file__)) + "/process.log"

def main():
    buf_list = []
    buf_list.append(get_current_time())

    for i in readline_stdout():
        buf_list.append(i)

    write_file_to_log(buf_list)


# 現在時刻を取得
def get_current_time():
    current_time = datetime.now().strftime("%Y/%m/%d %H:%M:%S") + " ---------------------------------------------------------------------------------\n"
    return current_time


# 標準出力を一行ずつ受け取る
def readline_stdout():
    proc = subprocess.Popen(shlex.split(command), stdout = subprocess.PIPE, stderr = subprocess.PIPE)

    while True:
        line = proc.stdout.readline()
        yield line.decode("utf-8")

        if not line and proc.poll() is not None:
            break


# ファイルに出力
def write_file_to_log(logs):
    file = open(log_file, 'a')
    file.writelines(logs)


if __name__ == "__main__":
    main()
# 実行結果の一部
2017/11/22 18:00:22 ---------------------------------------------------------------------------------
  UID   PID  PPID CPU PRI NI      VSZ    RSS WCHAN  STAT   TT       TIME COMMAND
    0     1     0   0  37  0  2536056   6748 -      Ss     ??    1:00.50 /sbin/launchd
    0    50     1   0  37  0  2550352  37604 -      Ss     ??    0:08.14 /usr/libexec/UserEventAgent (System)
    0    51     1   0   4  0  2515384   2672 -      Ss     ??    0:01.24 /usr/sbin/syslogd
    0    53     1   0  20  0   663372   1216 -      Ss     ??    0:00.56 /Applications/.esets/Contents/MacOS/esets_ctl
    0    54     1   0  20  0  2498064  10000 -      Ss     ??    0:01.52 /System/Library/PrivateFrameworks/Uninstall.framework/Resources/uninstalld
    0    55     1   0  37  0  2546936  12252 -      Ss     ??    0:02.51 /usr/libexec/kextd

ポイント

ポイントは2つです。
1. subprocessを使って標準入力と標準出力を扱う
2. shlexを使って文字列をシェルスタイルでパースする

subprocessを使って標準入力と標準出力を扱う

pythonでコマンドを扱う方法はcmdやos.system()など複数ありますが、subprocessを使うのがスタンダードなやり方っぽいです。

shlexを使う

今回のスクリプトを書いている中での最大の学びはshlexです。
たとえば、今回のコマンドは”ps alx”をそのまま渡してるんですが、shlex.split()を使わない場合は、[“ps”, “alx”]としてやる必要があります。
長いコマンドを処理したい時は面倒なので、shlexを使ってやると非常に便利です。

追記

shlex.splitを使わなくても、subprocess.Popemの引数にshell = True パラメーターを与えてやると"ps alx"でもうまくいきます。
shell = True パラメーターで処理をする利点は、"ps alx | grep hogeみたいにパイプ(“|”)を使ったコマンドが利用できるということです。
shlex.splitでパイプの入ったコマンドを利用しようとすると上手く処理できません。

追記その2

出力先ファイルのパス指定を修正しました。
cronで回したときに”process.log”だと実行時のパスが一致しないので、絶対パスを取得してやる必要がある。

VPNに触れてみる〜その0〜

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。


VPNとは何ぞ、から実際につなげてみるまで。今回はVPN自身のお話。

はじめに

ある日、外部にあるサーバにVPNで接続するようにとのお達しを受けたのですが、現在MacOS使用中の、ネットワーク知識ほぼ皆無な自分は公式ページで確認したり様々なページを閲覧したりして接続方法を模索していました。

VPNサーバへの接続はそこまで時間はかかりませんでしたが、VPN側のネットワークにあるサーバに接続できず、ここからが大変でした。自分の設定が間違っているのかと思い、サーバへの接続方法を調べ、実際に試してみるもののVPN側へのサーバへはアクセスできず、Windows側とルーティングテーブルを見比べても特に差があるように見えなかったため難儀していました。ネットワークに関して専門的な知識が多く必要なのかなとも思いましたが、ルーティング等試行錯誤しているうちに無事接続できたので、その紹介を。

ただし、今回は手順ではなく、VPNとは何かというところをざっくりと。(なのでその「0」です)

トランスポートモードとトンネルモード

VPNの話の前に、まずは関連した暗号化方式を。

トランスポートモード

トランスポートモードは送信するパケットのうち、データに関わる部分を暗号化して送信する方式です。IPヘッダは暗号化しないため、2つの端末同士で通信を行う際に利用できる方式となります。その都合上、インターネットを介する場合はNATを利用する必要があります。

NAT:パケットヘッダに含まれるIPを別のIPに置き換える技術。外部送信するためにプライベートIPをグローバルIPへ変換するのに使われることが多い。

トンネルモード

トンネルモードは送信するパケットのうち、データに加えて自身のIPヘッダも暗号化し、送信する方式です。IPヘッダも暗号化されるため送信先などがわからなくなりますが、こちらは暗号化する際に、暗号化する側(サーバなど)で新規にIPヘッダを付与するため、送信元の情報を隠したまま通信することができます。ただし新規のIPヘッダを付与する必要上、パケット長が大きくなる特徴があります。

この2つがVPNに関連して利用されているモードですが、主流はトンネルモードのようです。
本記事はこのトンネルモードを利用したVPNの話になります。

VPNとは

VPN (Virtual Private Network:仮想プライベートネットワーク)とはインターネットを通じてプライベートネットワークを構築する技術でできたネットワークです。インターネットを通じてネットワークを構築する、という点が重要で、これをすることにより、ある拠点と、離れた拠点を擬似的に同じネットワークに所属させることができます。

例えば友人のPCと自分のPCを同じVPNサーバのネットワークに所属させると、実際は外部ネットワークを通じているにもかかわらず、同じプライベートネットワークにいるかのように操作できます。
これが複数拠点でつなぐ話になれば、離れた拠点のネットワークを同じVPNに所属させることで、すべて同一のプライベートネットワークとして扱うことができます。

enter image description here
通常、拠点間ではグローバルでしかネットワークが繋がっていない(黒枠)が、VPNを利用すると、一つの拠点であるかのようにふるまう

専用回線を使ってネットワークを構築することと同じようですが、インターネットを通じて構築している違いがあるため、VPNサーバに到達できる経路が複数あれば一部脱落しても到達できるメリットがあります。

VPNの使い道

・外部のPCをサーバへ接続する際に、同じネットワークに所属させる
・複数の拠点を1つのネットワークとしてみなすようにする

という用途でしょうか。他にも使い道がありそうな気がします。
ファイルサーバがある場合、遠く離れていても、VPNでそちらと通信できるので単純な目的にとどまることはなさそうです。

おわりに

ざっくりとVPNについてまとめてみました。次回は、実際にVPNサーバへの接続方法をまとめていきたいと思います。
接続構成ですが、あるPCをVPNサーバと接続するリモートアクセスを予定しています。


関連:
VPNに触れてみる〜その1〜
VPNに触れてみる〜その2〜

第6回「本場のプランナーって仕事場で実際何してるのー?」

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

みなさんお久しぶりです!Lionです。
前回の記事いかがだったでしょうか?
ゲームプランナーには「コミュニケーション能力が大事!」というのが少しでも伝わりましたら、嬉しいです!
さて、本日は「第6回 本場のゲームプランナーって仕事場で実際何してるのー?」について話させていただきます。

仕事場でゲームプランナーがやっていること

enter image description here
基本的に仕様書作成やデータ作成がゲームプランナーの主な仕事になります。
例えば、毎月のイベントの仕様書や売り物になるキャラクターの仕様書などを作成し、作成後はデータを作り、きちんと動作するかの検証を行い、ゲームバランスが崩れないか?などのバランス調整を日々行うといった感じですね。
※これ以外にもまだまだたくさん仕事はありますが、すべて書いているときりがないので割愛します。

では、もう少し詳しく仕事のフローを紹介するために、今回は「よくあるイベントの仕様書ってどうやって作るの?作成した後は何をするの?」などお伝えします。

ゲーム内で行われるイベント

enter image description here
昨今のソーシャルゲームには欠かせない毎月のイベント。
PVPや収集系、レイドボスなど、たくさんありますよね。
私が所属しているプロジェクトにも、もちろんこのようなイベントはあります。
では、例を挙げて「イベントがレイドボス討伐」の場合は、仕様書からユーザーが遊べるまでどのようなフローを踏んでいるか?を詳しく書いていきます。

まずはイベントの仕様書作成から!

まずは、イベントで何をするか?ユーザーにどう遊んでもらうか?を書き出して仕様書にします。
レイドボスと戦って遊んでもらうのであれば、最低限以下のようなことを気を付けないといけないです。

①どれくらいのユーザーがクリアできるかを決める
②レイドボスの強さ
③どうやってユーザーに攻略させるか
④ボスを倒した際の報酬
⑤ボスと戦える期間の設定

①ですが、ボスを作る前に過去のクリア人数や現在のゲーム内ユーザー環境を分析して「これくらいのユーザーがクリアできるように設計しよう!」と目標を決めます。このように大まかでもいいので達成したい目標を作っておくと仕様書は割と作成しやすくなります。

①でクリア人数を決めたら、次は②と③にいきます。
ゲーム内のユーザー資産やキャラ育成度、過去のレイドボスのクリア人数などを分析してどれくらいの強さにすれば目標が達成できるか?を考えながらレイドボスのステータスや使う技などを考えていきます。

また、ユーザーにどうやって攻略させるかも一緒に組み込んでいきます。
例えば、「○○ターン目になると雷属性弱点になるから雷攻撃をしなきゃ!」や「HPをある程度減らさないと即死攻撃をしてくるからHPを○○ターンまでに減らしきらなきゃ!」など…。
ユーザーが実際に戦って攻略法を見出さないといけないように仕様を考えます。
※攻略性がなければ、ゲームとして面白くないですからね…w

レイドボスの仕様ができたら、次は④の報酬を考えないといけないです。
もちろん、強いボスに勝ったんですからそれなりに良い報酬を置くようにしています。
良い報酬というのは、「ユーザーがもらってお得なもの」程度の報酬ってことです。
※「最強の○○」レベルのアイテムやキャラを報酬にすると、今後の運営に支障が出てしまうので、報酬はすごく慎重に決定しなければいけないのです。

そして、最後に⑤のイベント期間の設定ですね。
当たり前といえば当たり前のことですが、ユーザーに「この期間からこの期間までと明確化」してあげることで、ユーザーが一日のサイクルのどのタイミングで遊ぼうか考えるようになります。
※例えばイベント期間が長いとまったり遊ぶorイベント期間が短いと平日でも夜遅くまで遊ぶなど

細かいところは省いていますが、こういった工程を踏むことで仕様書が完成します。

仕様書はできた!その後は何するの?

仕様書ができた後に必要なフローとして、5個あります。

①デザイナーにレイドボスのキャラチップを作ってもらう
②ゲーム内にレイドボスのデーターを作成して、テスト環境に反映
③動作検証とバランス検証のテスト項目書を作成
④テスト環境でテスターに動作検証とバランス検証をしてもらう
⑤テスト検証結果から不具合修正やバランス調整を行う

まず①ですが、新しく実装するボスのキャラチップがなければリリースはできません。
そこで、「立ち絵のイラストやどういうアクションやエフェクトをして欲しいなどの資料」をデザイナーにお渡しします。
ここで重要になってくるのが、「ただ、資料を渡すだけではいけない」ということです。
資料を基に話し合って「互いに認識のずれがないか?」を確認するのが一番大事になってきます。
※でないと、想像していたものと違うものが出来上がった時に修正時間とられちゃいますからね…w

デザイナーの作成と並行して、こちらでは②のゲーム内データを作成します。
新規実装がいるような内容の場合は、事前にエンジニアと会話をして実装してもらうように依頼します。
しかし、既存構造でデータが作成できるのであれば、ゲームプランナーが作成します。
※あくまで、私の会社ではそうしています。他の会社が全て同じではないのでご注意を…。

データ作成が完了したら③のテスト項目書を作成します。
これは、結構大事な資料で、テスターが資料を見たときに「何を検証すればいいか?検証する意図は何か?」をきちんと記載しておかなければなりません。
でなければ、こちらが検証して欲しい内容の意図が伝わっていなかった場合、その結果は不十分となってしまい、本当にリリースしていいかどうか判断がつかなくなってしまう恐れがあるからです。
そのため、時間がかかってもいいので、明確に書くように心がけています。

①~③がそろえば、いよいよ④のテスト用の環境にデータを反映します。
反映後は、ある程度は自分で反映したデータをチェックし、その後にテスターにテスト項目書をお渡しして、検証してもらうという形になります。

検証が終わったら、いよいよ⑤の不具合修正や最終バランス調整を行います。
動作検証の結果では、ボスが指定の技を使っていなかったり、意図してない挙動をしていた場合は原因を調査し自分で修正するか、技術的な面である場合はエンジニアに修正依頼をお願いしたりします。
バランス検証の結果では、ボスのパラメーターや使う技の強さを変えるかを検討しデータを変更します。データ変更後、テスターに動作チェックを再度依頼します。
※大幅なバランス変更がはいいた場合は2回目のバランス検証を依頼するときもあります。
この工程がすべて完了すると最後の項目に移ります。

最後の項目とは?

最後の項目とは、メンテ前に自分と上司で、アップデートするデータが正しいかどうかを確認するチェック作業です。
ここが最後の砦で、ここでチェックを怠ってしまうと「気づけなかった不具合が本番のゲーム環境で発生した」なんてことが起こりうるかもしれないので、チェック資料を作成して慎重に確認していきます。
ここで問題なければ、メンテ日にデータを反映します。
本番の環境にデータが反映された後は、もう一回フリーチェックを行い、問題ないと最終チェックをがとれればメンテを解放して、ユーザーは新しいイベントのレイドボスと戦えるようになります。

しかし、まだ終わりではありません。メンテ解放後は1時間~2時間くらいはユーザーを監視します。
もし何かあった場合は、すぐに上司に報告し対応策を考え、ユーザーに告知をするという迅速な対応をできるようにしておくためです。
これらが全て完了してやっと「新しいイベントのレイドボスを実装した!」と言えるようになります。

ここまで話してみて

enter image description here
いかがだったでしょうか?
この話を読んでみた人の中で「ゲームプランナーって仕様書作成するだけじゃないんだ!」と思った方多いんじゃないでしょうか?
ゲームプランナーは「やれることは何でもやるなんでも屋さん」と思っていただければいいかなと思います。
※テスターの代わりに自らデータ検証をするときも多々あります。
仕様書作成、デザイナーやテスターへ依頼、依頼用資料の作成、ゲーム内のデータ作成、テスト検証、バランス調整などなどやることいっぱいなのです!
だからこそ、むちゃくちゃ楽しい職業だと自分は思っています!
なぜなら、「ゲームを制作する色々な背景をみることができる」のですから!
この記事を読んだ新卒の方がいましたら「是非ゲームプランナー目指してほしい」です(=゚ω゚)ノ
さて、次回の記事ですが「第7回 来年に流行りそうなゲームは何か?」という
深い話をしたいなと思います。
※お話しできる範囲でしか話せないのであしからず…w
最近、寒くて布団に出たくない症候群に陥っていますが、みなさん寝坊とかしないように気を付けてくださいね(´・ω・`)ノシ

sedコマンドでテキストの加工

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

ソースコード内の文字列置換(空白スペースの削除)を行う際に、一つ一つvimで開いてやっていたのですが、煩わしくなったので何かいい方法が無いかと調べたところ、sedコマンドが便利でした。
(sedは「stream editor」の略だそうです)

sedコマンドの使い方

直接ファイル名を指定したり、標準出力をパイプで渡すことでテキストの加工を行えます。

# 基本的な使い方
sed [オプション] (ファイル名)

# 以下、使い方の一例
# ファイル名を直接指定して文字列を置換する場合
sed -e 's/hogehoge/bizzbuzz/g' test.text  

# パイプで渡して置換する場合
cat test.text | sed -e 's/hogehoge/bizzbuzz/g'

sedコマンドで出来ること

sedコマンドで出来る処理はかなり多いです。
今回は、自分が利用した物について紹介したいと思います。

文字列の置換-sコマンド-

sコマンドを使うと文字列の置換を行うことが出来ます。

sコマンドは、vimと同じような形で記述出来るので、非常に楽です。

またアドレスを利用すると、指定した行のみ置換をするといったことが出来るようになります。

アドレスや置換する文字列には、正規表現を使用出来るので、柔軟な対応を行うことが出来ます。

# sコマンドの使い方
sed '(アドレス) s/(置換前の文字列)/(置換後の文字列)/'


# 使い方の一例
# sample.txt
foo: bar
hoge: huga
bizz: bar

$ sed 's/bar/buzz/' sample.txt
foo: buzz
hoge: huga
bizz: buzz

# bizzの行だけ置換
$ sed '/bizz/' 's/bar/buzz/' sample.txt
foo: bar
hoge: huga
bizz: buzz

行の削除 -dコマンド-

dコマンドでは、アドレスや行番号を指定して行を削除することが出来ます。

#アドレスを指定して行削除
$ sed '/bizz/ d' sample.txt
foo: bar
hoge: huga

# 行番号を指定して削除
$ sed '3 d' sample.txt
foo: bar
hoge: huga

おわりに

sedコマンドでは、今回紹介した2つ以外にも多くのコマンドが実装されているようです。

sedや、その他のコマンドについてもよく理解して、上手く扱えるように精進していきたいと思います。

UnityのTextGeneratorについて

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

UnityがuGUIのTextを描画するのに色々キャッシュしておくためのクラス、TextGeneratorを使って色々できます。

TextGeneratorとは・何に使えるのか

TextGenerator はTextの描画に使われているらしいです。
uGUIのソースコードは公開されており、 UI/UnityEngine.UI/UI/Core/Text.cs を読んでみると出てきます。

ざっくり言うと Populate または PopulateWithError で描画に必要なデータを生成してくれるものです。
Populate には、描画したい文字列とフォントやフォントサイズ、文字寄せ位置などの設定を入れておく TextGenerationSettings を渡します。

普通にTextを使っているぶんには直接これを触る必要は全くないのですが、
文字列がどう描画されるのかを知りたいときに非常にお世話になります。

Textの高さをどのくらいにするつもりか知りたい

チャットのような、文章によってオブジェクトの大きさが変わるものでオブジェクトプーリングを行うときにテキストがどのくらいの高さになるのか知りたくて使いました。

GetPreferredHeight といういかにもよさそうな関数がありますが、これには現在バグがあるようで、思った通りの結果を返してくれません。

https://issuetracker.unity3d.com/issues/textgenerator-dot-getpreferredwidth-slash-height-ignores-textgenerationsettings

GetPreferredHeight がいつか使えるようになるまでは文字の高さと何行になるかを求めて自力で計算することになります。

行数を求めたいとき文字数を単純に割るだけでは全角半角混じりの文章にうまく対応できないため、単純な割り算では計算できません。
ここでTextGeneratorに行数を教えてもらう必要が出てきます。

スクリプトリファレンスにもあるようにgeneratorを作ってPopulateに文字列とテキスト生成用の設定(後述)を渡すと、generatorからVertices や文字情報や行の情報などが得られるようになります。
generatorからほしいのは lineCount、Textの行数です。

public float GetLineCount(string text, TextGenerateSettings setting){
    var generator = new TextGenerator();
    generator.Populate(text, setting);
    return generator.lineCount;
}

TextGenerationSettingsは文字のフォント、フォントサイズ、領域のサイズなどを指定するためのものです。
スクリプトリファレンスの例のように作って一から代入しても問題ないですが、
Textの GetGenerationSettingsでフォントやサイズを取ってこられます。
この場合はテキストを描画する範囲だけ渡せばいいです。

var setting = sampleText.GetGenerationSettings(new Vector2 (440f, 1000f));

文字の高さを求めるのは TextGenerator ではできないのでこの記事では省略しますが、
汎用性を求めないなら行数に適当な数字をかけたり足したりしてもそれなりになります。

補遺・ルビ付けたい

上に挙げたlineCount以外にも様々なpropertyがあります。

最近なんとかルビをうまくつけられないか調べたり考えたりしています。

  • lines で各行の高さや行頭の文字のインデックスがはいったUILineInfoのリストが得られる
  • characters で各文字の幅などが入ったUICharInfoのリストが得られる

このあたりが使えそうです。
charactersでルビを付けたい文字の位置が分かればそのあたりににTextが置けたらいいんじゃないかなという気がします。私が実装することがあれば次の記事になるかもしれません。

Googleデータスタジオで4つのディメンションを使う方法

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

Googleアナリティクスはピボットテーブルを用いて3つまでディメンションを重ねることができますが、4つとなるとピボットテーブルでは不可能。今回はGoogleデータポータルを用いて4つのディメンションでピボットテーブルを作る方法をご紹介します。

この記事でまとめられていること

こんにちは。株式会社アピリッツでアナリストをしているssekiです。
最近、Googleデータポータルで「ピボットテーブル」なる機能を見かけました。
どうやら知らないうちに新規追加されたみたいですね。

ピボットテーブルというと、Googleアナリティクスにも同名の機能があります。
Googleアナリティクスでは、行のディメンション2つと列のディメンション1つの最大3ディメンションまでソートできる機能でした。しかし、マイレポートで使えないことと、自由度が低いことから利用シーンが少ない機能という印象です。
enter image description here
※本記事の画像はGoogleのデモアカウントデータを用いています。

それでは、Googleデータポータルではどうなのかということで実際に使ってみたところ、
Googleアナリティクスよりもはるかに綺麗で、4つのディメンションを使えるピボットテーブルであることがわかりました。
今回は、ピボットテーブルの使い方についてご紹介いたします。

ピボットテーブルとは

そもそも、ピボットテーブルって何?という方のために簡単にご説明いたします。

ピボットテーブルはクロス集計と呼ばれる、2つ以上の項目を組み合わせても見やすい集計方法を実現するための表になります。
Excelを使っているとピボットテーブルという名前を目にしたことがあるかもしれませんが、主にExcelで用いる機能になります。

Googleアナリティクスやデータポータルでも同様で、2つ以上のディメンションを行と列に設置することで、大量のデータを集計したり分析したりすることができます。

Googleデータポータルにおけるピボットテーブルの使い方

それでは、Googleデータポータルでのピボットテーブルの使い方を見ていきましょう。
まずは、グラフ・表を選択する部分からピボットテーブルを選びます。
下図の赤枠で囲われた蛍のようなマークをクリックします。
enter image description here

次に、グラフ・表を作る時と同様にキャンバス上で枠を書いていくと、下図のようにピボットテーブルが表示されます。
Googleアナリティクスデータを用いた場合は、デフォルトが参照元×メディアのピボットテーブルになっています。
なお、ピボットテーブルはページ内に1つしか置くことができない仕様となっているため、蛍マークがグレー化しているのがわかります。
enter image description here

最後に、表のプロパティ画面でディメンションと指標を選択すると下図のようなピボットテーブルが完成します。
enter image description here

上記の例では、デバイスカテゴリ×ユーザータイプ×性別×年齢の4つのディメンションを重ねたピボットテーブルを作りました。
アナリティクスのピボットテーブルに比べ見た目がかなりきれいですね。これは重宝しそう。

Googleデータポータルのピボットテーブルにおける注意点

一見便利そうなピボットテーブルですが、現段階でできないことも多くあります。
個人的に特に注意すべき点を4つ挙げてご紹介します。

【1】ディメンションは2行×2列の最大4つまで
2行×2列を超えるピボットテーブルを作ることはそうそうないですが、設定できる数に限りがあるので注意です。

【2】指標は1つしか設定できない
1つのピボットテーブルに複数の指標を入れることができません。また、1ページ内に設置できるピボットテーブルは1つだけなので、複数指標を使いたい場合は、別ページにコピーして作る必要があります。

【3】エクスポートしても普通の表形式データ(ピボットテーブルではない)
csvファイルやスプレッドシートなどにエクスポートする際、ピボットテーブルのままエクスポートされません。その場合、必要であればExcelやスプレッドシートで再度ピボットテーブルを作る手間がかかることに注意です。

【4】カラーバーやヒートマップなどをセル内に含められない
個人的に一番もやもやした部分ですが、大量のデータを扱う上でカラーバーやヒートマップによるデータの可視化ができないので注意です。また、セッション数などの数値データでは全体における占有率が見たくなるのですが、これも難しそうです。

まとめ:この機能はどんな人におすすめか

今回はGoogleデータポータルでピボットテーブルを作る方法、および4つのディメンションを使えるといった話をご紹介しました。
Googleアナリティクスでピボットテーブルを作る機能は以前からあったものの、使いづらさや見た目上の問題のために使っていない人も多いと思います。
Googleデータポータルで手軽にクロス集計ができるようになったため、定点観測用のみならず、一時的な分析においても活用されやすいのではないでしょうか。

ただし、ピボットテーブルを用いて細かく見ても「このデータを出してどうなるの?」といったケースは多くあります。
そのため、むやみやたらにディメンションを含めるのではなく、サイトの目標に応じた仮説実証のためにこうしたツールをうまく使っていきましょう。

「エーテル」のルーツを辿る

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

ファンタジー作品の中にたびたび姿を現す「エーテル」という物質。今回は現実世界での「エーテル」の歴史を遡ってみたいと思います。

エーテルとは

ファンタジー作品中での「エーテル」と言えば、主に魔法に関係する物質であることが多いです。
僕が出会った「エーテル」は魔法を使うためのエネルギー補充アイテムであったり、ファンタジックな事柄を説明できちゃう便利物質だったり、錬金術っぽいことに必要な物質だったりしました。
では、現実世界での「エーテル」とは一体何なのでしょうか。調べてみると次の3つほどが該当しました

現実世界のエーテルとは・・・
①:有機化合物を分類する際の種類の一つ
 └①の分類の中の特にジエチルエーテルという物質を指す場合も
②:光を伝える媒質と考えられていた仮想の物質
③:古代ギリシャの四大元素説で説明できない第五の元素として提唱されたもの

以下で一つ一つ紹介していきたいと思います。

①有機化合物の「エーテル」

高校で化学を専攻した方は覚えがあるかもしれません。
化学での「エーテル」は構造式R-O-R’であらわされる有機化合物の総称です。酸素Oの両端にあるRとR’は炭素と水素からなるアルキル基(CH3-等)などの有機基がくっつきます。この酸素の両端に有機基(R,R’のこと)がついている結合はエーテル結合と呼ばれています。
この「エーテル」に分類される有機化合物の中でも、特にジエチルエーテルのことをエーテルと呼称することもあります。
ジエチルエーテルは水には溶けないような、油のようなものを溶かしてくれるため、溶媒としての使用や、燃料としての利用もされています。また過去にはお酒の代用として飲用されていたことがあるようで、飲むとお酒と同じような酩酊を味わえたそうです。(ある意味で魔法の飲み物だったのかも知れません。)
enter image description here

②光を伝える「エーテル」

17世紀~19世紀ごろの科学者たちは、光が波の性質を持っていることを、光の屈折や干渉などの現象から知っていました。
ここで、地球上での波を考えると、水の波であれば水そのもの、音の波であれば空気を振動させる、のように全て何かを媒介にして「波」という現象を起こしています。
そこで当時の科学者は、光が波であれば、それを媒介するものがこの空間にあるはずだと考えていました。その光を媒介する物質が「エーテル」です。科学者たちはおよそ200年にもわたって、この「エーテル」の存在を見つけようと様々な実験を行っていましたが、精度不足によって「エーテル」があるのかないのか分かっていませんでした。しかし、その後、マイケルソン・モーレーの実験によって高精度で「エーテル」の存在を確かめる実験が行われました。その結果は「エーテル」は存在しないというものでした。この後も「エーテル」はもっと複雑な性質を持っているから見つからなかったのだ、という意見を支持する科学者たちもいましたが、その後に、複雑な性質さえも否定する実験結果が発表され、とうとう「エーテル」は架空の存在となってしまいました。(この業績によってマイケルソンはノーベル賞を受賞しています。)

③四大元素説の「エーテル」

かつて古代ギリシャの哲学者は、この世の物質は大きく四つの元素が基盤となっていると考えていました。この四つとは火・空気・水・土と呼ばれるものであり、地球上のすべての物質はこの四つの元素に種々の性質が加わったりすることで構成されていると考えられていました。
アリストテレスもこの考えを受け継いでおり、これら四つの元素は、「プリマ・マテリア」と呼ばれる何も性質を持たない純粋な物質に対して、「熱・冷」と「湿・乾」という性質が加わわることで、先の四つの元素が構成されると考えました。
この四つの元素には固有の場所があるとされ、水・土は下へ沈み、火・空気は上へ昇ると考えられていました。
しかし、遥か天上で運動を続けている天体にはこれらの性質が当てはまらないため、天体はこれら四元素とは別の第五の元素が構成していると考えました。この第五の元素と呼ばれているものが「エーテル」です。
enter image description here
実は①と②のエーテルは、この第五の元素「エーテル」が命名元となっているのです。
①は揮発性の高さから天上へ昇っている様子をなぞらえて、②は天界に満ちた物質という側面から。それぞれ全く別の物質が、場所も時代も違えど「エーテル」という名称にたどり着いたのは面白いですね。

終わりに

いかがだったでしょうか。ファンタジーな物質のルーツを辿ると、スタートは夢も希望もないただの化学物質でしたが、最終的には古代ギリシャの世界設定にたどり着いてしまいました。昔の人にとってはまさに生きる世界がファンタジーだったのかもしれません。

Googleデータポータルで4つのディメンションを使う方法

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

Googleアナリティクスはピボットテーブルを用いて3つまでディメンションを重ねることができますが、4つとなるとピボットテーブルでは不可能。今回はGoogleデータポータルを用いて4つのディメンションでピボットテーブルを作る方法をご紹介します。

この記事でまとめられていること

こんにちは。株式会社アピリッツでアナリストをしているssekiです。
最近、Googleデータポータルで「ピボットテーブル」なる機能を見かけました。
どうやら知らないうちに新規追加されたみたいですね。

ピボットテーブルというと、Googleアナリティクスにも同名の機能があります。
Googleアナリティクスでは、行のディメンション2つと列のディメンション1つの最大3ディメンションまでソートできる機能でした。しかし、マイレポートで使えないことと、自由度が低いことから利用シーンが少ない機能という印象です。
enter image description here
※本記事の画像はGoogleのデモアカウントデータを用いています。

それでは、Googleデータポータルではどうなのかということで実際に使ってみたところ、
Googleアナリティクスよりもはるかに綺麗で、4つのディメンションを使えるピボットテーブルであることがわかりました。
今回は、ピボットテーブルの使い方についてご紹介いたします。

ピボットテーブルとは

そもそも、ピボットテーブルって何?という方のために簡単にご説明いたします。

ピボットテーブルはクロス集計と呼ばれる、2つ以上の項目を組み合わせても見やすい集計方法を実現するための表になります。
Excelを使っているとピボットテーブルという名前を目にしたことがあるかもしれませんが、主にExcelで用いる機能になります。

Googleアナリティクスやデータポータルでも同様で、2つ以上のディメンションを行と列に設置することで、大量のデータを集計したり分析したりすることができます。

Googleデータポータルにおけるピボットテーブルの使い方

それでは、Googleデータポータルでのピボットテーブルの使い方を見ていきましょう。
まずは、グラフ・表を選択する部分からピボットテーブルを選びます。
下図の赤枠で囲われた蛍のようなマークをクリックします。
enter image description here

次に、グラフ・表を作る時と同様にキャンバス上で枠を書いていくと、下図のようにピボットテーブルが表示されます。
Googleアナリティクスデータを用いた場合は、デフォルトが参照元×メディアのピボットテーブルになっています。
なお、ピボットテーブルはページ内に1つしか置くことができない仕様となっているため、蛍マークがグレー化しているのがわかります。
enter image description here

最後に、表のプロパティ画面でディメンションと指標を選択すると下図のようなピボットテーブルが完成します。
enter image description here

上記の例では、デバイスカテゴリ×ユーザータイプ×性別×年齢の4つのディメンションを重ねたピボットテーブルを作りました。
アナリティクスのピボットテーブルに比べ見た目がかなりきれいですね。これは重宝しそう。

Googleデータポータルのピボットテーブルにおける注意点

一見便利そうなピボットテーブルですが、現段階でできないことも多くあります。
個人的に特に注意すべき点を4つ挙げてご紹介します。

【1】ディメンションは2行×2列の最大4つまで
2行×2列を超えるピボットテーブルを作ることはそうそうないですが、設定できる数に限りがあるので注意です。

【2】指標は1つしか設定できない
1つのピボットテーブルに複数の指標を入れることができません。また、1ページ内に設置できるピボットテーブルは1つだけなので、複数指標を使いたい場合は、別ページにコピーして作る必要があります。

【3】エクスポートしても普通の表形式データ(ピボットテーブルではない)
csvファイルやスプレッドシートなどにエクスポートする際、ピボットテーブルのままエクスポートされません。その場合、必要であればExcelやスプレッドシートで再度ピボットテーブルを作る手間がかかることに注意です。

【4】カラーバーやヒートマップなどをセル内に含められない
個人的に一番もやもやした部分ですが、大量のデータを扱う上でカラーバーやヒートマップによるデータの可視化ができないので注意です。また、セッション数などの数値データでは全体における占有率が見たくなるのですが、これも難しそうです。

まとめ:この機能はどんな人におすすめか

今回はGoogleデータポータルでピボットテーブルを作る方法、および4つのディメンションを使えるといった話をご紹介しました。
Googleアナリティクスでピボットテーブルを作る機能は以前からあったものの、使いづらさや見た目上の問題のために使っていない人も多いと思います。
Googleデータポータルで手軽にクロス集計ができるようになったため、定点観測用のみならず、一時的な分析においても活用されやすいのではないでしょうか。

ただし、ピボットテーブルを用いて細かく見ても「このデータを出してどうなるの?」といったケースは多くあります。
そのため、むやみやたらにディメンションを含めるのではなく、サイトの目標に応じた仮説実証のためにこうしたツールをうまく使っていきましょう。

高速にステーキを作ろう!!(ActiveRecordの速さを追い求める.2)

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

3はある、かもしれないような気がする。

ステーキを作るコード

 美味しいステーキを(ステーキに)作りたいが為に、以下のようなコードがありました(疑似コードも書いたので面倒ならそれを読んでください)。

class Cow < ActiveRecord::Base
  DEAD = 0.freeze
  ALIVE = 1.freeze
  SICK = 2.freeze

  def create_steak!(part, solt_vol, pepper_vol, bake_time, rest_time)
    self.slaughter! if self.is_alive?
    beef = Beef.find_by(cow_id: self.id, part: part)
    return if beef.nil?
    beef.steak!(solt_vol, pepper_vol, bake_time, rest_time)
  end
=begin
def ステーキ作る!(部位、塩の量、胡椒の量、焼く時間、休ませる時間)
  牛が生きていたら屠畜する
  肉が得られなかったら作れないのでさよなら
  肉をステーキにする
end
=end

  def slaughter!
    return if !self.is_alive?
    before_status = self.life_status
    self.life_status = DEAD
    self.dead_time = Time.now
    self.save
    if before_status != SICK
      Beef::PART.each do |part|
        Beef.create(cow_id: self.id, part: part)
      end
    end
  end
=begin
def 屠畜!
  もう死んでたらおしまい
  屠畜して時間を記録
  牛が病気じゃなかったら部位毎に肉を取得
end
=end

  def is_alive?
    self.life_status != DEAD
  end
end
=begin
def 生きてる?
  生きてるかどうか返す
end
=end
class Beef < ActiveRecord::Base
  PART = ["Loin", "Libeye", "Sirloin", "Spencer Roll", "Tenderloin", "Top Sirloin Butt", ...]
  RECIPE_NAME = ["YAKINIKU", "STEAK", "BEEF STEW", "BEEF CURRY", "BEEF STROGANOF"]
  validate :recipe_include?, :part_include?

  def steak!(solt_vol, pepper_vol, bake_time, rest_time)
    self.solt_volume += solt_vol
    self.pepper_volume += pepper_vol
    self.bake_time += bake_time
    self.is_cooked = true
    self.rest_time = rest_time
    self.recipe_name = "STEAK"
    self.save
    self
  end
=begin
def ステーキにする!(塩の量、胡椒の量、焼く時間、休ませる時間)
  塩を振る
  胡椒を振る
  焼く
  調理済ステータスにする
  休ませる
  レシピ名を与える
  保存
end
=end

  def recipe_include?
    if self.is_cooked
      unless RECIPE_NAME.include?(self.recipe_name)
        error.add(:recipe_name, "Recipe not found.")
      end
    end
  end
=begin
def そのレシピある?
  調理済なら
    レシピ名調べて無かったらエラー
end
=end

  def part_include?
    unless PART.include?(self.part)
      error.add(:part, "Part not found")
    end
  end
=begin
def その部位ある?
  部位名調べて無かったらエラー
end
=end
end

Cow Model(簡略化してます)

id          : integer
life_status : integer
dead_time   : datetime

Beef Model(簡略化してます)

id            : integer
cow_id        : integer
part          : string
is_cooked     : boolean
solt_volume   : float(g)
pepper_volume : float(g)
rest_time     : integer(sec)
bake_time     : integer(sec)
recipe_name   : string

 さて、このコードでCowインスタンスが存在すれば(cowとする)、

cow.create_steak!("Sirloin", 2.0, 1.0, 90, 90)

の一文で塩を2g、胡椒を1g、それから90秒焼いて90秒休ませたサーロインステーキが作れてしまいます(これ以上凝るとコード長が大変な事になるので妥協しました)。

沢山サーロインステーキを作りたい

 さて、沢山サーロインステーキを作りたいときにはどうしたら良いでしょう。
 まず、沢山の牛を用意しなければいけません。新鮮な肉が良いので、生きている牛を1000匹用意しましょう(もちろん病気の牛は除外します)。

cows = Cow.where(life_status: Cow::ALIVE).take(1000)

 それから1000個のステーキを作りましょう。

cows.each do |cow|
  cow.create_steak!("Sirloin", 2.0, 1.0, 90, 90)
end

 ……遅い! とても遅い!
 何故?
 そりゃあ、一匹一匹、屠畜して、塩胡椒を振って、焼いて休ませて、を繰り返してるから(一匹毎にSQLを発行、1000 * n回のSQLの発行が起きているから)ですよ。
 1000匹一気に屠畜して、1000個のサーロインに一気に塩胡椒を振って、1000個のサーロインを焼いて休ませてあげた方が速いに決まってます。
 その為には、やはり、それ用の沢山ステーキを作るコードを書きましょう。
 ただ、一つgemが必要です。
 activerecord-importというgemで、これを使えば、

models = []
1000.times do |n|
  models << Model.new(...)
end
Model.import(models)

 という感じで、一括insertが出来るようになります(gemを使わなくとも、一括insertするSQL文をコード上で生成して生SQLでダイレクトに挿入するという力技で出来る事は出来ます)。
 さて、大量にステーキを高速に作るために、Cowモデルにメソッドを作りましょう。

def self.create_steaks!(num, part, solt_vol, pepper_vol, bake_time, rest_time)
  last_insert_id = Beef.maximum(:id) + 1 #確実では無いかも
  now = Time.now
  cow_ids = Cow.where(life_status: Cow::ALIVE).limit(num).pluck(:id)
  return if cow_ids.length < num
  Cow.where(id: cow_ids).update_all(life_sttus: Cow::DEAD, dead_time: now)
  beefs = []
  steak_beef_ids = []
  cow_ids.each do |cow_id|
    BEEF::PART.each do |p|
      beef = BEEF.new(id: last_insert_id, cow_id: self.id, part: p)
      last_insert_id += 1
      beefs << beef
      steak_beef_ids << beef.id if p == part
    end
  end
  Beef.import(beefs)
  Beef.where(id: steak_beef_ids).update_all(solt_volume: solt_vol, pepper_volume: pepper_vol, bake_time: bake_time, is_cook: true, rest_time: rest_time, recipe_name: "STEAK")
=begin
def ステーキを沢山作る!(牛の数, 部位, 塩の量, 胡椒の量, 焼く時間, 休ませる時間)
  最後の肉のIDを取得
  現在時間を取得
  生きている牛のIDを、数だけ取得
  生きている牛が数だけ居なかったらおしまい
  そのIDの牛全てを屠畜
  そのIDの牛全てに対して牛肉を作成。指定された部位のIDは別に分けておく
  指定された部位の肉を焼いて更新
end
=end
end

 このコードだと、下の1行で1000個のステーキが作れます!(生きている牛が1000体以上居たらに限りますが)

Cow.create_steaks!(1000, 2.0, 1.0, 90, 90)

 そして、このコードはどれだけステーキを焼こうともSQLの呼び出し回数は固定です(newはSQLの呼び出しになりません)。
 直感的にも屠畜場から調理場へ行って肉を焼いて屠畜場に戻って……を何回と繰り返すのではなく、屠畜場で一気に処理して、それから調理場へ全ての肉を運んで全ての肉を焼いて……とした方が早いとは分かると思います。
 一つ一つのSQLは重いですが、単純に行うよりはずっと早いです。
 ただ、注意点が3つほどあります。

IDを自分で振る必要がある

 importではオートインクリメントの値を計算してくれません。

last_insert_id = Beef.maximum(:id) + 1 #確実では無いかも

 この行はその為ですね。#確実では無いかも、というのは、オートインクリメントの値を取ってきていないからです。オートインクリメントの値を取る方法を少し調べてみたりはしましたが、中々見つからなかったので、今回はこれにしました。

バリデーションをしてくれない

 importは、DBに直接働きかける為、トリガなどを一切無視しまう事が原因です。なので、このメソッドは、予想外の値が入らない事が前提条件となるでしょう。それか、バリデーションを自分でimportの前に入れておくか、とか。

他のActiveRecord関連のgemと相性が悪い

 バリデーションをしてくれない、という事と同じで、DBに直接働きかけるという点が原因です。
 例えば、水平分散DBを実現するactiverecord-turntableというgemの、uniqueなID管理を統括してくれるsequenceと相性が良くないです。
 import処理を行った後も、その連番の値を管理してくれている数値が更新されないので、次に普通にcreateとかしようとすると、idが重複しているよ! と怒られてしまいます。
 なので、sequenceを使っているmodelに関しては、import処理を行った後に、以下のように、sequenceの値を進めてあげる必要が出てきます。

Beef.connection.next_sequence_value("beefs_id_seq", num)
#加算した分(num)だけ、シーケンスの値を進める

最後に

 Railsの処理速度で一番ボトルネックになりやすいのは、SQLの呼び出しでしょう。
 そのSQLの処理時間を減らす為には主に、
・出来るだけモデルそのままではなく、必要な情報だけを取得するようにする
・呼び出し回数そのものを減らす
という事になってくると思います。
 特に呼び出し回数を減らす、という点においては、今回の高速化においての主な方法だった、一回のSQLで一括読み込み/書き出しをする、という他に、メモ化する、Redisでキャッシュに書き込んで、そちらから取得する、等々色んな方法があります。

最近人気な記事