2014年5月30日金曜日

[JavaScript] JScriptでメール送信ができる (Outlook, Gmail)

宛先や内容は毎回異なるが、ほぼ定型のメールを毎月送る定常業務がだるい~
ので自動化しようと調べてみたら、Jscriptでメール送信ができると知った。

[Outlook]
OutlookとWSHでメール送信 - くじらはんど★ブログ

[Gmail]
定型メールの送信を自動化する~GmailとJavaScriptの華麗な連携技(第13回)《クジラ飛行机「仕事に役立つJavaScript入門」》

社用メーラはOutlookなのでとりあえず上記を試してみたところ、難なく成功。
社員番号がエイリアスになっているので、宛先の設定も楽。

即バッチ作って来月から運用する。

2014年5月24日土曜日

手拍子とグルーヴ

グルーヴ=?



いつどこで聞いたか完全に忘れたけれども、「手っ取り早くグルーヴを感じたり作り出したいのなら、グルーヴのある演奏に合わせて手拍子をすることだ」というアイデアが離れないでいる。

ここから「グルーヴしたけりゃその時はこっちから手拍子するわ」、グルーヴに対する-良く言えば-積極性または-悪く言えば-強制性の否定が個人の音楽鑑賞・体験スタイルが形作られた。

このスタイルを軸に、ミュージシャンのライブで煽られる手拍子には長らく頑として拒否する姿勢を保ってきた。というより、グルーヴを表に押し出さない演奏またはグルーヴの無い演奏を前に手拍子"してあげる"ことの虚しさを払拭できずにいた。

手拍子は一体感を産み、これはグルーヴの有無に依らないと思う。ともすればその一体感が音楽的な体験(ここで言うグルーヴにより生み出されるもの)なのか、当事者間のリレーション(ミュージシャンとリスナーの間、またはリスナー同士)へのアウェアネスなのか、その境界は曖昧になる。この境界線がぼやけていることこそ、ショウビジネスとの親和性の高さに紐付いているのは別の話だが、時偶この事実によって音楽的な体験が矮小化されているのではないかと思うこともある。矮小化とは言わないまでも、比率やプライオリティを下げられているように感じる。


ここまではリスナー側の話だがステージに立つとまた話が変わる。
観客に手拍子をしてもらうと気持ちが良い。手拍子でなくても同調的な行動をとってもらうと、ライブそもそもの高揚感もあいまって、自分たちを中心に生み出される大きなエネルギーを感じる。はっきり言ってこれはやみつきになる。煽りたくなるのも当然に思えてくる。


…とまで書いて何が言いたいのかよくわからなくなった。。

2014年5月21日水曜日

読みたい記事メモ

Qiitaのメール、個人的にいつも見失う


[SQL] IN句の検索リストに列名を指定する

SQLのIN句の説明や実際の使用例を見ていると
[列名] IN ([検索リスト])
という記述が多い。
しかし、検索値をIN句の前に持ってきて列名を列挙することもできる。
[検索値] IN ([列名リスト])
この用法は、類似する情報を複数のカラムで持つような場合に使える。
--最高音か最低音がC#
'C#' IN (top_note, bottom_note)
あまり使いどころが無さそうに見えるが、正規化されていないテーブル設計を前にすると結構使えたり…。

2014年5月17日土曜日

Mac mini買った

Mac mini買った。
音楽編集とiPhoneアプリ開発が目的で、とにかく安値でMacの環境が欲しいと思って選択した。

「Mac miniは2012年から新作が出ておらず、そろそろ"来る"だろうからやめた方が良い」的な話は聞いていたけど、それにしても価格が魅力的だったのでまぁいいかという感じ。

Apple Days | Apple製品の発売周期まとめ


早速、Xcodeをインストールしててきとうに動かしてみたところ、何かしらの高揚感ある。

が、
初MacでOSに慣れてないとのと、Windows準拠キーボード使用のせい?で作業効率の低さがやばい。

当面は『詳細!Objective-C』読みつつ頑張る。
画像加工アプリでも作ってみよう。


【参考】

ゼロから始めるMacintosh開発環境構築(OS X Mavericks編)ーこれからプログラミングを始める人のためにー(1) | IT系のインターンシップならエンジニアインターン - 
初心者でも5分で作れそうなiPhoneアプリ講座 : IT速報 - 

[SQL] sum (case when ~)で異なる条件の集計をまとめて取得する

既存システムに参照だけのview(画面、帳票)を追加。
項目ごとの表示桁数はフォントや枠サイズを基準に定められたが、現行でその桁数を超えるデータがどれだけあるのかわからないというので調査することになった。
(順序が逆な気がするが)

やりたいこと


  • 表示する項目の文字数が指定の桁を超えるレコードの数を集計する
  • 対象の項目は複数あり、それぞれで指定の桁数(=条件)は異なる
  • 文字数制限とは別に、いくつかの条件で絞込も行う

最初に考えたのは以下のような感じ。
条件ごとにcountした結果を愚直に結合。

select *

from
 -- 名称が10文字を超えるレコードの件数
 (select
   '名称' as column_name
  ,count(*) as product_count
 from
  t_product p
 where
  p.color = 'red'  -- 共通条件
  and length(p.name) > 10
 )

 union all

 -- コードが4文字を超えるレコードの件数
 (select
   'コード' as column_name
  ,count(*) as product_count
 from
  t_product p
 where
  p.color = 'red'  -- 共通条件
  length(p.cd) > 4
 )

 -- 以下、似たような条件が続く...

実行計画とったら非常に遅い、かつwhere句の条件が重複しているなど"何か悪いことをしている"感が凄かったので、条件付きで集計するにはSUM(CASE WHEN ...)を参考に考えなおした。

select
  count(*) as 総数
 ,sum(case when length(p.name) > 10 then 1 else 0 end) as 名称
 ,sum(case when length(p.cd) > 4 then 1 else 0 end) as コード
 -- 以下、似たような条件が続く...
 
from
 t_product p
where
 p.color = 'red'


もともとwhere句に書いていた項目ごとの条件をcase whenにブチ込みつつ、共通条件は共通化させる。だいぶすっきりしつつ実行計画もまぁまともな数値が出たので良かった。

これにさらに区分ごとの条件なんかを足していき、最終的には以下のようなSQLをブン投げて調査を終えた。

select
  count(*) as 総数
 ,case when p.type = 'a' -- aの場合はnameのlengthだけで判断
            then sum(case when length(p.name) > 10 then 1 else 0 end)
       when p.type = 'b' -- bの場合はnameとcolorを結合したlengthで判断
            then sum(case when length(p.name || p.color) > 15 then 1 else 0 end)
       else -1 -- a,b以外のtypeの場合は集計対象外
       end as 名称
 ,sum(case when length(p.cd) > 4 then 1 else 0 end) as コード
 -- 以下、似たような条件が続く...
 
from
 t_product p
where
 p.color = 'red'
group by
 p.type
order by
 p.type

今回はまさしく↓状態だった
「カウントする=COUNT関数」しか頭になく…(以下略)

【環境】

oracle 11g

【参考】

条件付きで集計するにはSUM(CASE WHEN ...)
MySQLでの条件付きSUM,COUNT

【2014/6/7追記】

上記のテクニックが最近読み始めた『達人に学ぶSQL徹底指南書』に載っていた。

曰く、
WHERE句で条件分岐させるのは素人のやること。プロはSELECT句で分岐させる。

実践的なパターンが多く掲載されており、常々SQL力の不足を感じていた自分には丁度良い。

2014年5月10日土曜日

[Perl] 画像を指定の枠に収まるようにリサイズ&余白を透明化

業務で必要になり、Perlでの画像加工処理を書いた。

実現したいこと

  1. 画像のアスペクト比を維持したまま、指定したサイズの枠に収まるようにリサイズ
  2. 指定したサイズの枠の中心に画像を貼り付け、余白は透明にする

今回は透明のキャンバスを作り、その上にリサイズした画像を貼り付けることで実現する。
そのコードが下記。

use Image::Magick;

my $src = "cat.png";       # 読み込むファイル名
my $dst = "dst.png";       # 出力する画像ファイル名
my $canvas_width = '600';  # 枠の幅
my $canvas_height = '400'; # 枠の高さ
 
# 透明のcanvasを作成
my $canvas = Image::Magick->new;
$canvas -> Set(size=>$canvas_width . 'x' . $canvas_height);
$canvas -> ReadImage('xc:white');
$canvas -> Transparent(color=>'White');

# 画像を読み込む
my $src_image = Image::Magick->new;
$src_image -> Read("$src");
my($src_width, $src_height) = $src_image -> Get('width', 'height');

# 画像とcanvasのアスペクト比を比較
my $canvas_ratio = $canvas_width / $canvas_height;
my $src_ratio = $src_width / $src_height;
my $magnification = 0;

# 画像がcanvasに対して縦長の場合
if ($canvas_ratio > $src_ratio) {
 # 高さの比を倍率にする
 $magnification = $canvas_height / $src_height;

# 画像がcanvasに対して横長、もしくは完全一致の場合
} elsif ($canvas_ratio <= $src_ratio) {
 # 幅の比を倍率にする
 $magnification = $canvas_width / $src_width;
}

# 倍率を指定してリサイズ
$src_image -> Resize(width=>int($src_width  * $magnification),
     height=>int($src_height * $magnification));

# 画像を重ねる
$canvas->Composite(image=>$src_image, compose=>'over', gravity=>'Center');

# 画像を出力
$canvas->Write("$dst");


【実行結果】

この猫の画像(1600x1200)を


600x400の枠に収めようとすると、出力結果はこんな感じになる。
クリックするとリサイズの効果と、左右に透明の余白があることがわかる(はず)。

とはいえあまりにわかりにくいのでExcelに貼り付け、画像に枠線を付けてみたのが↓。


Perlは半年以上前にいくつか手探りでバッチ作ったけど、それを除けばほとんど書いたことなし。
今回は文法をおさらいしつつ書いたけど、いまいちPerlの文化というか作法みたいなのはわからず…。

そして、Image::Magick便利。

【環境】

ActivePerl 5.16.3
Image::Magick 6.8.9

【参考】

Matsup's blog: FreeBSDでPerlMagick(その4)図形の描画と画像の加工
PerlMagickで画像の大きさを変更する(Image::Magick) | ぺんラボ
Perl::ImageMagickでよく使うコマンドとサンプル | くろひつじのメモ帳


【追記(2014/05/11)】

そういえば拡張子によっては透過って対応してないような…と思い、png/gif/jpgと試していった。
そしたらjpgだと余白が透過になっておらず、調べるとjpgは透過できないぽい。

透過背景とか使いたい場合は対応している拡張子で保存するようにする。

また、Image::MagickのRead/Write処理では記述した拡張子で読み込み/保存を行ってくれるとのこと。



2014年5月5日月曜日

[Java] POIで、読み込んだExcelファイルから図形を取得して値をセットする

Excelファイル(※2007以降の.xlsx形式)から目的の図形を取得し、値をセットする。
今回はテキストボックスを取得してセットするサンプル。

既に対象のWorkbookとSheetを取得している状態から。
// 図形描画の為のXSSFDrawingから図形のListを取得
XSSFDrawing drawing = sheet.createDrawingPatriarch();
List<XSSFShape> shapeList = drawing.getShapes();

// Listから目的の図形を探索
for (XSSFShape sh : shapeList) {
  // (1)実際の型を確認
  if (sh instanceof XSSFSimpleShape) {
     XSSFSimpleShape ss = (XSSFSimpleShape) sh;
     // (2)テキストの値をkeyに対象かどうか判断
     if (ss.getText().equals("key")) {
      ss.setText("value you want to set");
     }
  }
}

(1)Listで取得されるオブジェクトはXSSFShapeのサブクラス(※)であり、検査せずにSimpleShapeとして扱おうとするとClassCastExceptionが発生する。
 ※こいつら。↓
  XSSFConnector, XSSFGraphicFrame, XSSFPicture, XSSFShapeGroup, XSSFSimpleShape。

(2)APIDocなんかを読み漁ったけれども、定義した名前から図形を取得する方法がわからず。とりあえずテキストから判断するやり方で記述。


【環境】

 POI 3.10
 Java SE7

【参考】

XSSFSimpleShape (POI API Documentation)


[追記 2014/5/7] 

上記のやり方で値をセットすると、図形にもともと設定されていたフォントや揃方がクリアされてデフォルト値になってしまうことがわかった。

もともと設定されていたフォントなどを維持したままテキストのみを置き換える場合は下記のようにテキストを分解し、テキストの最小単位(TextRun)に対して操作を行わなければいけないらしい。

// 上記の11行目から
if (ss.getText().equals("key")) {
  for (XSSFTextParagraph p : ss.getTextParagraphs()) {
   for (XSSFTextRun r : p.getTextRuns()) {
    r.setText("value you want to set");  // ※1
   }
  }
}
※1 改行を含む文字列をブチ込んでも大丈夫だった。だがParagraphの扱いがよくわかっていないので、複数行を操作する場合はもう少し工夫が必要なのかもしれない。

FontはFontクラスで管理してたり、AlignはTextParagraphで管理していたり。Excelの実装自体がそうなのかもしれないけど、Excel上の設定と各オブジェクトの結びつきがわかりづらく、直感的に操作しづらい。。

2014年5月2日金曜日

[Java] enum型にデータと振る舞いを持たせる

Effective Java第二版でJavaの勉強中。

「項目 30  int定数の代わりに enum を使用する」にて紹介されている、
"enum型にデータと振る舞いを持たせる"コードを真似して書いてみた。
// 面積の単位ごとのデータ、メソッドを定義
private enum Unit {
HEIBEI ("㎡"){
  String getArea(double area) {
   return area + this.toString();
  }
 },
 TSUBO ("坪"){
  String getArea(double area) {
   return area * 0.3025 + this.toString();
  }
 };

 private final String unitName;

 // コンストラクタ
 Unit(String unitName) { this.unitName = unitName; }

 // すべての定数にオーバーライドを強制する
 abstract String getArea(double area);

 // カスタム文字列表現
 @Override
 public String toString() {
  return unitName;
 }


 // 一意の文字列表現から定数を取得できるようMap化しておく
 private static final Map stringToEnum = new HashMap<>();
 static {
   for (Unit unit : values())
    stringToEnum.put(unit.toString(), unit);
 }

 // 一意の文字列表現から定数を取得する(toStringと対)
 public Unit fromString(String unitName) {
  return stringToEnum.get(unitName);
 }
}

// 定義したenumを利用する
public static void main(String[] args) {
 double area = 320.25;

 System.out.println(Unit.HEIBEI.getArea(area));
 System.out.println(Unit.TSUBO.getArea(area));
}
実行結果
320.25㎡
96.875625坪

これまでenum型については、
バッドプラクティスとして知られる"int enumパターン"(下記)の代用として定数を列挙する、ぐらいにしか使ったことがなかった。。
// No More int enum pattern!!
public static final int HEIBEI = 1;
public static final int TSUBO  = 2;

2014年5月1日木曜日

[Java] POIで、名前が定義されているセルに値をセットする

Excelファイル(※2007以降の.xlsx形式)から名前が定義されているセルを取得し、値をセットする。

既に対象のWorkbookとSheetを取得している状態から。
XSSFName name = workbook.getName("cell's Name");
CellReference ref = new CellReference(name.getRefersToFormula());
XSSFRow row = sheet.getRow(ref.getRow());
XSSFCell cell = row.getCell(ref.getCol());
cell.setCellValue("value you want to set");

上記コードにて、単一のセルにも結合されたセルにも値をセットできることを確認済み。
結合されたセルは範囲で取得したりする必要があるかと思ったけど、今のところ問題無さそう。

また、存在しないセル名を指定している場合、1行目のworkbook#getNameはNullを返すので注意。

【環境】

 POI 3.10
 Java SE7

【参考】

POIで名前定義されているセルを取得する話 - kelkronsoの日記 -
POIで、名前定義の入ったカラムから値を取得。 - るいもの戯れ言 -