2018年7月8日日曜日

SVGの色をCSS上で変えてしまう方法


こんにちは、オフィス狛デザイン部のSatoです。

先日、アイコンをSVGで作成した際に、マウスオーバーすると色が変わったりするようなことがしたいなぁ……と思うことがありました。
普段なら商用フリーでCDNのアイコンフォントをアイコンにしてしまったりするのですが、今回は少し特殊なアイコンでそれもできず……。
SVGの色をテキストのようにCSSで変えたりできないものかと思って調べたらできる様子!
試してみた所、なんとか自分でもできたのでやり方をメモしたいと思います。

やり方は簡単。<svg>か親要素のCSSにfill: カラーコード;を追加するだけです。
ちなみに値を「currentColor」にするとなんとcolor設定されている色になります。
HTML
<a href="#"><svg>(本来はここにインラインで記載)</svg>Button</a>
CSS
a{color: #3ab28f;}
a:active{color: #3ddaa3;}
svg{fill: currentColor;}
こんな感じですね。
ただし、<img>タグや<object>タグではこの方法では色を読み込んでくれないようです。
最初自分はそこで躓いたのでご注意ください。

正直、自分は今までSVGのことを「どんなに拡大しても画像が荒れないすごい画像形式」くらいにしか思っていなかったのですがこんな事もできるんですね!びっくりしました。


,

2018年7月2日月曜日

Amazon S3 で サイト公開(HTTPS)する。(3)問い合わせフォーム準備編その2


オフィス狛 技術部のKoma(Twitterアカウントの中の人&CEO)です。

前回は、Webサイトの問い合わせフォームから問い合わせされた内容をS3バケットへテキスト形式で保存するところまで行いました。
今回は、S3に保存されたら、その内容をメールで送信したいと思います。

※メールを送信する為のAWS SES(Simple Email Service)については説明を省きます。SESの設定が終わった状態で下記の手順を行って下さい。

1)ポリシー(Policy)の作成

まずは、AWSコンソール上のIAMのページへ遷移し、左側のメニューから「Policies」を選択。
その後、左上の「Create policy」をクリックします。


Serviceは、「CloudWatch Logs」
Actionは、「CreateLogStream」、「CreateLogGroup」、「PutLogEvents」
Resourceは「all resources」を選択して、
右下の「Review policy」をクリックします。


最後にNameとDescriptionを入力し、「Create policy」を選択します。


作成に成功しました。


2)ロール(Role)の作成

続いてロールを作成していきます。先程と同じくAWSコンソール上のIAMのページへ遷移し、
左側のメニューから「Roles」を選択します。


Select type of trusted entityは「AWS service」を選択。
Choose the service that will use this roleは「Lambda」を選択して、
右下の「Next: Permissions」をクリックします。


まずはFilterで「Policy type」を選択します。
続いてAttach permissions policiesでは「AmazonSESFullAccess」をチェックします。
(検索ボックスで「SES」と入力すると、フィルターが掛かって選択が楽です)


次にFilterで「Customer managed」を選択し、先程作成したポリシーにチェックを入れます。
(検索ボックスの中身を消さないと一覧に出て来ないのでご注意を)
右下の「Next: Review」をクリックします。


最後、Role nameを入力して、右下の「Create role」をクリックします。


作成に成功しました。


3)Lambda Functionの作成

AWSコンソール上のLambdaのページへ遷移し、「Create a function」を選択。


「Author from scratch」を選択し、Name等の必要な情報を入力します。
Runtimeは「Node.js」を選択して下さい。
Roleは「Choose an existing role」を選択し、Existing roleは、先程作成したロールを選択します。


作成直後の状態です。
ここで、左側の「Add triggers」から、「S3」を選択します。


対象のバケットを選択し、Event typeは「PUT」を選択します。 「Add」をクリックします。

続いて、Node.jsのプログラムを貼り付けます。


貼り付けるプログラムは以下の通りです。
'use strict';

console.log('Loading function');

const aws = require('aws-sdk');
const s3 = new aws.S3({ apiVersion: '2006-03-01' });
const ses = new aws.SES({ apiVersion: '2010-12-01', region: 'us-east-1' });

exports.handler = (event, context, callback) => {
    const bucket = event.Records[0].s3.bucket.name;
    const key = decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, ' '));
    const params = {
        Bucket: bucket,
        Key: key
    };

    s3.getObject(params, (err, data) => {
        if (err) {
            console.log(err);
            const message = `Error getting object ${key} from bucket ${bucket}. Make sure they exist and your bucket is in the same region as this function.`;
            console.log(message);
            callback(message);
        } else {
            const json = JSON.parse(data.Body.toString());
            const message = `
                名前: ${json.name}           
                MAIL: ${json.email}
                問い合わせ日時:
                ${json.date}
                問い合わせ内容:
                ${json.comments}
                `
            const params = {
                Destination: {
                    ToAddresses: [process.env.TOADDRESS]
                },
                Message: {
                    Body: {
                        Text: {
                            Charset: "UTF-8",
                            Data: message
                        }
                    },
                    Subject: {
                        Charset: "UTF-8",
                        Data: "フォームからのお問い合わせ"
                    }
                },
                Source: process.env.SOURCEADDRESS
            };
            ses.sendEmail(params, function (err, data) {
                if (err) console.log(err, err.stack);
                else console.log(data);
            });
        }
    });
};

プログラムに環境変数を使っているので、値を設定します。
SOURCEADDRESSが送信元(=from)アドレスで、
TOADDRESSが送信先(=to)アドレスです。


以上でLambdaの設定が完了となります。
Lambda作成後、前回作成した問い合わせフォームから、問い合わせを行うと・・・
この後、S3側のトリガー設定などが残っているのですが、以降は、独自ドメインの設定を行った後にやって行こうと思います。
と言う事で、WebサイトへのアクセスはS3のURLを利用しているので、 次回はRoute53を使用して、独自ドメインでの運用を可能にしていきたいと思います。

次回:Amazon S3 で サイト公開(HTTPS)する。(4)Route 53を使用した独自ドメイン運用
前回:Amazon S3 で サイト公開(HTTPS)する。(3)問い合わせフォーム準備編その1


, , ,

2018年6月26日火曜日

Amazon S3 で サイト公開(HTTPS)する。(3)問い合わせフォーム準備編その1


オフィス狛 技術部のKoma(Twitterアカウントの中の人&CEO)です。

前回からだいぶ時間が経ってしまいました。
さて、前回までで、S3へサイトを移管する事が出来ましたが、サイトによっては問題が発生します。
そう、S3は単にストレージに過ぎないので、サーバサイドのプログラム(PHPなど)は動かすことが出来ません。
弊社のホームページですと、「問い合わせフォーム」が該当します。

旧サイトでは、「問い合わせフォーム」から問い合わせ内容をPOSTし、Webサーバ側のPHPファイルを実行し、メール送信処理を行っていました。
けれど、S3ではPHPを実行する事は出来ません。

という事で、代替案として、以下の方法を取ろうと思います。
・問い合わせフォームにて入力された内容を専用のS3バケットへテキストファイルとして保存
・S3バケットへの保存をトリガーに、Lambdaファンクションでメール送信

早速、実施して行きましょう。

1)identity poolの作成

まずは、AWSコンソール上のAmazon Cognitoのページへ。

・Step 1:Create identity pool
「Identity pool name」に適当な名前を設定し、「Enable access to unauthenticated identities」にチェックを付け、「Create Pool」を押します。

・Step 2:Set permissions
IAM Roleを選択します。
このタイミングで作成する事も可能なので、今回は、「Create a new IAM Role」を選択し、
Roleの名前を付けて、「Allow」を押します。

※Cognitoについては、こちらを参照。

そうすると、identity pool id が発行されるので、メモっておきます。

ここでやっている事は、『S3へファイルをアップロードする為の認証情報を作成している』、と思って頂ければ良いと思います。

2)IAM Roleへ権限付与

AWSコンソールで、IAM Roleを見ると、先程新規で作ったRoleが見れると思います。

次はこのRoleにS3へのファイルアップロード権限を付与します。
先程の画面でRoleをクリックすると、下記の画面に遷移しますので、
「Add inline policy」をクリックします。

・Visual editorでポリシー作成
JSONを直接貼り付けて説明しているサイトが多いのですが、それだと意味を理解しないで使ってしまうと思うんですよね。
と、言う訳で、視覚的にポリシー作成を行なって行きます。
「Choose a service」をクリックします。

まずはサービスの選択ですが、S3と検索ボックスに入力すると、S3が選べるので、クリックします。

続いてアクションですが、S3にファイルを格納(Put)する必要があるので、
「PutObject」と「PutObjectAcl」をチェックします。
(他にもたくさんのアクションがあるので、ここでも検索ボックスに「PutObject」と入力しておくと楽です。)

次に、対象となるバケットを選択します。
「Specific」を選択してから、「Add ARN」をクリックします。

表示されたポップアップでバケット名をします。(バケットは前もって作っておいて下さい)
バケット内のオブジェクトは全てを対象とします。

バケットを選んだ後はこんな感じになります。
確認後、「Review policy」をクリックします。

最後、ポリシーに名前を付けて、「Create policy」でポリシーを作成します。

出来上がったポリシーのjsonはこんな感じです。
結構な手順記載しましたが、内容自体はこれだけ。

3)CORSの設定

サイトがあるドメイン(S3バケット)と問い合わせ内容を保持するドメイン(S3バケット)は違うので、
CORS(Cross-Origin Resource Sharing)を設定する必要があります。
これを設定しないと、後に用意するjavascriptプログラムから問い合わせファイルをアップロードすることが出来ません。

では、AWSコンソール上で、問い合わせ内容を保存するS3バケットを選択し、
Permissionsタブから、「CORS configuration」を選択し、編集を行います。

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
    <AllowedOrigin>http://officekoma.co.jp.xxxxxxxxxxxxxxxxxx</AllowedOrigin>
    <AllowedMethod>PUT</AllowedMethod>
    <MaxAgeSeconds>3000</MaxAgeSeconds>
    <AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
「AllowedOrigin」には、問い合わせフォームがあるサイトのドメイン(S3バケットURL)を指定します。
これを「*」にしてしまうと、先程のidentity pool idを知っていれば、そこら中のドメインからファイルがアップロード出来てしまうので要注意です。

4)問い合わせフォームとアップロードプログラムの作成

後は問い合わせフォーム(html)とアップロードプログラム(javascript)の作成です。

弊社サイトの問い合わせフォームは以下のようになっています。

・問い合わせフォーム(html)
<!doctype html>
<html lang="ja">
<head>
  <!-- 中略 -->
  <script src="https://sdk.amazonaws.com/js/aws-sdk-2.200.0.min.js"></script>
  <script src="../js/s3Upload.js"></script>
  <!-- 中略 -->
</head>
<body>
  <!-- 中略 -->
  <h1>お問い合わせはこちらからお願いします。</h1>
  <p>フォームからの送信に失敗する場合、お手数ですが <a href="mailto:info@officekoma.co.jp">info@officekoma.co.jp</a> まで直接ご連絡ください。<br>
  ※商品・サービスの売り込み、その他営業活動・勧誘などには返信できかねますのでご遠慮ください</p>
  <script type="text/javascript" src="../js/form-validation.js"></script>
  <div class="form_control setting_center">
    <form id="contactForm" action="#">
      <fieldset>
        <p>お名前または会社名(Name)<span class="required">※必須</span></p> <input name="name"  id="name" type="text" class="form_box" autocomplete="name" required />
        <p>メールアドレス(Email)<span class="required">※必須</span></p><input name="email"  id="email" type="text" class="form_box" autocomplete="email" required />
        <p>問い合わせ内容(Comments)<span class="required">※必須</span></p>
        <textarea name="comments" id="comments" class="form_box" rows="4" cols="40" ></textarea>
        <div class="input_submit"><input type="button" value="送信 " name="submit" id="submit"  /></div>
      </fieldset>
      <p id="error" class="warning">送信に失敗しました。恐れ入りますが、再度入力をお願いします。</p>
    </form>
    <p id="success" class="success">お問合わせを送信いたしました。ありがとうございました。内容を確認後、早急にご返信させていただきます。もし数日中に返事が無い場合は、正しく受信できなかった可能性がありますので、恐れ入りますが再度のご連絡をお願いします。</p>
  </div>
  <!-- 中略 -->
</body>
</html>

・アップロードプログラム(javascript)
「contactBucketName」、「bucketRegion」、「IdentityPoolId」をそれぞれの環境に合わせて変更して下さい。
jQuery(document).ready(function($) {
    var contactBucketName = 'homepage-contact';
    var bucketRegion = 'hogehoge';
    var IdentityPoolId = 'hogehoge:xxxxxxxxxxxxxxxxxxxxxxxxxxx';

    AWS.config.update({
        region: bucketRegion,
        credentials: new AWS.CognitoIdentityCredentials({
            IdentityPoolId: IdentityPoolId
        })
    });

    var s3 = new AWS.S3({
        params: {Bucket: contactBucketName},
    });

    // hide messages 
    $("#error").hide();
    $("#success").hide();

    // on submit...
    $("#contactForm #submit").click(function() {
        $("#error").hide();
        
        //name
        var name = $("input#name").val();
        if(name == ""){
            $("#error").fadeIn().text("名前を入力してください。(Name required.)");
            $("input#name").focus();
            return false;
        }
        
        // email
        var email = $("input#email").val();
        if(email == ""){
            $("#error").fadeIn().text("メールアドレスを入力してください。(Email required.)");
            $("input#email").focus();
            return false;
        }

        var now = new Date();
        var obj = {"name":$("input#name").val(), "email":$("input#email").val() ,"comments":$("#comments").val(), "date": now.toLocaleString()};
        var blob = new Blob([JSON.stringify(obj, null, 2)], {type:'text/plain'});
        s3.putObject({Key: now.getTime() + ".txt", ContentType: "text/plain", Body: blob, ACL: "public-read"},
        function(err, data){
            if(err !== null){
                $("#error").fadeIn();
            }
            else{
                $("#success").fadeIn();
                $("#contactForm").fadeOut();
            }
        });
    });

    return false;
});

5)動作確認

実際に問い合わせを行うと、下記のようにファイルがアップロードされます。


ちょっと長くなってしまいましたが、これでPHP無しでも、サイトからの問い合わせの内容を確認する事が出来るようになりました。

とは言うものの、これだと、毎回能動的にS3のバケットを確認しないと問い合わせが確認出来ないので、現実的はありません。
次回は、問い合わせ内容をメールで送信する方法を記事にします。
(なんだか本質とは離れていっていますが、一応「サイトのhttps化」の一環です。)

次回:Amazon S3 で サイト公開(HTTPS)する。(3)問い合わせフォーム準備編その2
前回:Amazon S3 で サイト公開(HTTPS)する。(2)S3での公開準備編


, , , ,

2018年6月25日月曜日

knexライブラリのIN句でプレースホルダを使うときの注意点


オフィス狛 技術部のHammarです。

node.js、Postgresqlという開発環境で、knexというSQLライブラリを利用して開発をしているのですが、今回はIN句でプレースホルダを使って配列をセットしてクエリを作成した時にハマったことを書いてみようと思います。

通常knexライブラリでIN句を使ってクエリを作成するとこんな感じになると思います。
    knex
        .select('name')
        .from('users')
        .whereIn('id', [1, 2, 3]);
■出力SQL
    select `name` from `users` where `id` in (1, 2, 3);

そして上記を応用してIN句にプレースホルダを使うとするとこのような感じになります。
    knex
        .select('name')
        .from('users')
        .whereRaw('id IN (?, ?, ?)', [1, 2, 3]);
■出力SQL
    select `name` from `users` where `id` in (1, 2, 3);

で、実際のプログラムではこのIN句の中を配列の変数で扱ってクエリを作ることが多いと思いますが、その場合はこんな感じになると思います。
    const array = [1, 2, 3];

    knex
        .select('name')
        .from('users')
        .whereRaw('id in (?)', [array]);

このクエリでも基本的に問題なく動きますが、このクエリだと配列の中の値をすべて文字列として認識してしまい、数値項目に対してこのクエリを実行するとsyntaxエラーとなってしまうんです。
上記のクエリの場合、idというカラムがint型の場合は下記のようなクエリがながれてしまい値が取れません。
■出力SQL
    select `name` from `users` where `id` in ("1", "2", "3");

いろいろと調べてみてようやくたどり着いたのが、プレースホルダを??にするという対応でした。
https://github.com/tgriesser/knex/issues/1537

でこんな感じになります。単純に?を2つにしただけ。
    const array = [1, 2, 3];

    knex
        .select('name')
        .from('users')
        .whereRaw('id in (??)', [array]);
■出力SQL
    select `name` from `users` where `id` in (1, 2, 3);

これで意図する値の取得ができるようになりました。

この事象はpostgresqlだけ?なのか、ほかのmysql等のRDBではどうなのかはわかりませんが、posgresqlでknexライブラリを使う際には上記を参考にしてみてください。

2018年6月13日水曜日

SpringBoot 1.3 から 1.5 へのバージョンアップでハマったこと


オフィス狛 技術部 CTOの Taka-yamです。

あるJavaのプロジェクトでSpring Frameworkの脆弱性問題により
SpringBoot1.31から1.51へアップデートする必要がありました。

その際に、やはり思った通りにはいかず、いくつかハマった点がありましたので、
ここで情報共有します。

まず最初のエラーです。
ServletContext resource [/hoge] defined by 'spring.datasource.schema' does not exist

このエラーは「datasource.schemaが存在しない」と出ています。
どうやら Spring Boot1.5 から、デフォルトでDBの初期化処理を行おうとし、schema.sqlやdata.sqlというファイルをクラスパスのルートから探しに行くようです。
今ままではこのような処理を行っていなかったため、当然ファイルは存在せずエラーとなっていました。

対策としては、下記のプロパティをapplication.ymlに追加します。
spring:datasource:initialize: false

次は下記のエラーが出ました。
java.lang.ClassNotFoundException: org.springframework.session.hazelcast.HazelcastFlushMode

これはspring-sessionのバージョンを間違えており、2系のバージョンを指定していたため、
SpringBoot1.51では依存関係が解決できないことが原因でした。
バージョンを変更し、無事に解決できました。

最後に下記のエラーが出ました。
No Spring Session store is configured: set the 'spring.session.store-type'

これもSpringBoot1.5からの特徴でspring.session.store-typeを指定しないとエラーになるように変わりました。
今回は何も使用していないため、何も指定しないように設定します。
spring:session:store-type: none

以上でエラーが解決され、無事に動作も確認ができました。
計画的ではなく、突発的なアップデートの際には色々と調査が必要ですね。

,

2018年6月10日日曜日

knexライブラリで動的パラメータを使ったlike検索をする方法


オフィス狛 技術部 CTOの Taka-yamです。
Node.js のアプリケーションを開発していて、
SQLを構築するためにknexというライブラリを活用しています。
http://knexjs.org

素のSQLに近い形でfluentにSQLを構築できるので大変便利なのですが、
動的パラメータでlike検索を行うとした際に値の設定方法ではまったので共有します。

下記のようなユーザテーブルがあるとします。
User
id: String
name: String

textという変数に入力された値が格納されているとして
ユーザテーブルのnameカラムにあいまい検索を行うとします。

まず最初に思いついたのが、
knex(‘user’).whereRaw(“name like ‘%?%’”, text);

これはエラーとなります。
type \"like\" does not exist"

次に思いついたのが、
knex(‘user’).where('name', 'like', knex.raw('%?%', text));

これもエラーになります。
syntax error at or near \"%\""

次に思いついたのが、
knex(‘user’).whereRaw(‘name like %' + text + '%');

これもエラーになります。
syntax error at or near \"%\""

次に思いついたのが、
knex(‘user’).whereRaw("name like '%" + text + "%'");

これはうまくいきました。

ですが、このような文字列連結をすると弊社で使用している Lint に怒られてgit commitさえ出来ません。(lint-stagedでcommit制限掛けているので)

なので、最終的に、
knex(‘user’).where(‘name’, 'like', `%${text}%`);

となりました。

結論を見ればすごい単純なことなのですが、
結構はまったので、もし同じようなことで困っている人の助けになれば幸いです。

PostgreSQLで「あればUPDATE、なければINSERT」のUPSERTをやってみる


オフィス狛 技術部のHammarです。

よくデータベースを操作する処理で、あるキーでデータがあればUPDATE、なければINSERTするーというような場面が多々あると思います。
通常はまずはそのキーで件数をSELECTして、件数が0件ならINSERT処理へ、0件以上ならUPDATE処理へ分岐させるというような感じの処理の流れが、まあよくある感じかなと思います。

じつはこれを1回のクエリで行うことができるのですが、PostgresqlやMysql等でやり方がそれぞれ違います。
今回はPostgresqlでのやり方で、自分が少しハマった部分や注意点も含めて書こうと思います。

■UPSERT

「データがあればUPDATE、なければINSERTする」という処理はUPSERTと呼ばれています。INSERT(追加)とUPDATE(更新)の両方の機能を併せ持っていることから、UPDATE + INSERTで、UPSERTということのようです。

PostgresqlはバージョンによってこのUPSERTのやり方が変わってきます。
Postgresql 9.5以上でCONFLICTというUPSERTができる機能が備わりましたが、それより前のバージョンではこの機能が使えないので、CTE(共通テーブル式)という構文を利用して下記のようなクエリでUPSERT的なことが可能です。
(ちなみにCTEとはこちらに詳しく書かれています)

■CTEを使ったUPSERT的なクエリ

  WITH upsert AS (
        UPDATE test_table
        SET
            name = val_name
        WHERE
            id = val_id
        RETURNING val_id
    )
    INSERT INTO test_table (val_id, val_name)
    SELECT val_id, val_name From test_table
    WHERE not exists (SELECT id FROM upsert);

上記のクエリでUPSERT的な動きとなり、自分もこの方法で処理を書いていたのですが、この方法で1つハマったことが起きました。
通常テーブルにレコードが何件かある状態で上記のクエリは問題ないのですが、テーブルにレコードが1件もない(初期状態)の場合、「なければINSERT」となるので本来ならレコードが登録されるはずなのですが、なぜか上記のクエリではレコードが登録されず、テーブルは空のままでした。
原因は不明なのですが、恐らくSELECT句でNULL判定できずに登録するものがないと判断されるようです。(ただ、試しにNOT NULLでやってもうまくいきませんでした)
ということで上記の方法は厳密には使えないことがわかったので、どうしようかとちょっと悩みましたが自分の開発環境がPostgresql 9.5以上であることがわかり、ならばあたらしく備わったCONFLICTという機能を使ってみようということで、下記のようなクエリを作成します。

■CONFLICT機能を利用したクエリ

    INSERT INTO test_table (id, name)
    VALUES (val_id, val_name)
    ON CONFLICT (id)
    DO UPDATE SET name = val_name;

短くていいですね!
ON CONFLICTにキーを指定して存在確認し、レコードがあればUPDATE、なければINSERTというようになっています。ただこのクエリにも1つ注意点があり、ON CONFLICTに指定する項目はUNIQUE制約がある項目でないとこのクエリはエラーとなってしまいます。なので、テーブルの指定の項目にUNIQUE制約をつけて使うようにしてください(複数項目でUNIQUEとなる場合は複合UNIQUE制約をつける)

CTEを使ったクエリでも本来ならうまくできると思うんですが、自分の環境が悪いのかそもそもの問題なのかは今のところわかっていません。ただCONFLICT機能のほうがクエリ的にもすっきりですし、かなり使えると思うのでPostgresql 9.5以上の環境があればこちらを使ったほうがいいと思います。


2018年5月31日木曜日

InVisionStudioを使ってアニメーションするモックアップを作成してみた。


こんにちは、オフィス狛デザイン部のSatoです。
時代の波に追いつきたいと思い、一時期話題になったあのプロトタイプソフトの記事を書いてみました。(ちょっと遅いか)

先月InVision Studioのearly accessのメールが届いたのですが、SketchもXDも使った事の無い私は、通常の操作もあまりうまくできずに使うのを後回しにしていたのですが、公式の動画を見たり公式のGETTING STARTEDを見たりして、やっとアニメーションをつけたりする所までできるようになりました。


作ったモックアップ(iphoneXサイズ)
気になる部分はありますが!(なぜか色を変えたら一部のオブジェクトがプレビュー時だけ消えてしまった…?バグでしょうか?)InVision Studioで作った動いてるモックアップです!
InVision StudioだとInVisionでお馴染みのリンクでの画面の遷移の再現や固定ヘッダーの再現だけでなくぬるぬるパーツが動きます!言葉で説明するのが難しい動きもこれでエンジニアさんに伝えられますね!


一番手こずったのがアニメーション機能で作る横から出てくるメニューだったので個人的に作り方を解説します。
(UIを載せるとよろしく無いそうなので、詳しいアニメーション機能についてはこちらの公式の説明を読んでみてください!)

横から入ってくるメニューは最初アニメーションのTransitionをPresetに設定し横にずれるような動きに設定してどうにかしようと思ったのですが、なかなかメニューが横から動くようには見えてくれませんでした……。

しかし、元の画面要素をコンポーネントとして登録し、別にコンポーネント化させたメニューを見切れるように配置し、TransitionをMotionにしてあげるといい感じに動いてくれました。

応用すれば色々な表現が可能になりますね!

唯一、使っていて大きな欠点だなと思った点は日本語対応。
InVision Studio内は日本語もきちんと打ち込めますが、右上のプレビューボタンの横のアップロードボタンでInVisionにプロトタイプとしてアップロードできるという機能を使った後にプレビューで見てみると日本語部分が綺麗に消えてしまいました。
InVisionのソフトなのに日本語を使うとInVisionにうまい具合にアップできないのは痛い……。
こんなに素敵なのにクライアントさんにモックアップとして見せるのはまだ無理そうなのが勿体無い気がしますが、early accessだし海外製だから仕方ない。

他にも不具合な気がする不思議な挙動や実装されていない機能などありますが使う価値は大いにあると思います。
何よりearly access版は今の所(2018年5月現在)無料です!ぜひみなさま使ってみてください。

,

2018年5月13日日曜日

クラウドサービスの種類について。(新人さん向け)


オフィス狛 技術部のHammarです。

この度、4月からオフィス狛へ参画しました。
役割的にはマネージャー兼プログラマー(何でも屋?)です。
これから、よろしくお願いします。
さて、参画後初のブログ記事ということで、4月入社の新人さんへ、IT用語の説明を記載しようと思います。
今回は『クラウド』についてです。

最近は多種多様なクラウドサービスが本当に多くなってきました。Amazon、Microsoft、Google、といったいわゆるクラウドBIG3を筆頭に中小さまざまなクラウドサービスが存在しています。
一概にクラウドサービスを利用するといっても、実はクラウドの利用形態によっていくつか分類されるのをご存知でしょうか。またその利用形態ごとのどういう機能を利用するかによってどのクラウドサービスを選ぶかの基準にもなってきます。
クラウドを利用した開発をするにあたって、そのクラウドサービスの種類についてちょっと勉強したことをまとめてみたいと思います。

そもそもクラウドとは

クラウドコンピューティング(英: cloud computing)は、インターネットなどのコンピュータネットワークを経由して、コンピュータ資源をサービスの形で提供する利用形態である。略してクラウドと呼ばれることも多い。 wikipedia

もう少しざっくり書くと、ユーザーはサーバーやストレージなどのインフラやソフトウエアなど物理的に持つ必要がなく、インターネット等を利用していつでも手軽にサービスを利用できる技術です。
上記の意味合いでは身近にあるGoogleのGmailはメールに特化したクラウドサービスです。

このクラウドサービスの種類についてですが、クラウドサービスには実は細かくわけると「SaaS」、「PaaS」、「IaaS」という種類があります(もう少し細かく「DaaS」というのもあります)

■SaaSについて

「Software as a Service」の略で「サース」と呼びます。
その名の通りソフトウェアをクラウドで利用できるサービスになります。
上記に書いたメールサービスなどがこれにあたります。
ほかにもDropbox等のクラウドストレージサービスやMicrosoft Office 365などのオフィスソフトも代表例になります。SaaSはすでにアプリケーションとしてすぐに利用できる状態で、エンドユーザーが一番身近に使うサービスが多いのではないかと思います。

■PaaSについて

「Platform as a Service」の略で、「パース」と呼ばれています。
プラットフォームのクラウドサービスということで、プラットフォーム「土台となる環境」をクラウド上で利用できるサービスになります。
開発者はシステムの開発に必要な土台となる環境(アプリケーションとOSをつなぐミドルウェアやDB管理システム、プログラミング言語、OS等がすでに利用できる状態でアプリケーションを開発できるので、いちいち開発環境を整える必要がなく、すぐに開発に取り掛かることができます。
代表例としてはGoogle App Engine やMicrosoft Azureあたりになります。AWSもサービスの内容によってはPaaSになりますね。

■IaaSについて

「Infrastructure as a Service」の略で、「イアース」や「アイアース」と呼ばれます。
インフラストラクチャ―のクラウドサービスなので、サーバーやストレージ、ネットワークをクラウド上で利用できるサービスになります。
サーバを利用する際に必要なハードウェアのスペックやOSを、ユーザーが自分で選んで利用することが可能です。PaaSとは違いインフラだけの利用なので、開発者が細かく設定を自由に設計することができます。
代表例としてはGoogle Compute EngineやAWSのEC2がこれにあたります。


これらの「SaaS」、「PaaS」、「IaaS」の種類の違いがわかると、開発時にどのクラウドサービスを使えばよいのかがわかってくると思います。

含まれている機能要素の順に
【SaaS:すぐに使える】>【PaaS:基本的な準備あり】> 【IaaS:インフラだけ】
になるでしょうか。

開発基本に考えた場合、基本的にはPaaSを利用する機会が多いと思いますが、案件内容や状況によってメリット、デメリットをクラウドサービスを考えて選択できるのではないかと思います。


2018年5月11日金曜日

Photoshopのレイヤー名検索したい時に使える機能


こんにちは、オフィス狛 デザイン部のSatoです。

先日、Photoshopでの作業中に、とある言葉の入ったレイヤーだけ抽出したい!という場面がありました。
 イメージ的には下の画像のような状態です。


Photoshopでレイヤー検索ができるかわからなかったので、とりあえず「Command⌘(Ctrl)」+「F」を押下した所、検索画面のようなポップアップが出てきてくれました。
検索したいレイヤー名を入れると、ちゃんとレイヤー名検索ができました!やったー!

ただ、検索結果をクリックするとポップアップが消えてしまうので、キーワードが入ったレイヤー名のレイヤーを色々見比べようとすると少し不便でした。


先日はこの機能だけ使い作業をしていたのですが、調べてみると実はもっとレイヤー名だけ抽出する場合に便利な機能がありました。
「Command⌘(Ctrl)」+「shift(Alt)」+「F」を押下するとレイヤーの上に入力部分が出てきました。ここに検索したい言葉を入れるとその言葉の入ったレイヤー名のみを表示してくれました!

この機能はCS6で実装された機能らしいです。もっと早く知っておきたかった!


補足しますと最初に記載した「Command⌘」+「F」は、レイヤーの検索という面では「Command⌘」+「shift」+「F」に劣りますが、アドビ公式のチュートリアルや情報の検索、adobe stockの画像を検索しワンクリックでライブラリに選択した画像(コピーライト入り)が登録される機能などがあるので、非常に便利です。

また、1つの手でショートカットキーが押せる「Command⌘」+「F」の方が手早く検索できるので、複数件のレイヤーを確認したい場合以外は、この検索機能がおすすめです。

2018年5月10日木曜日

AWS Windowsサーバで Spring Boot の MessageResource の {0} が展開されない場合の解決方法


オフィス狛 技術部 CTOの Taka-yamです。

先日、Spring BootのプログラムをAWSのWindowsサーバにデプロイした際に「あれ?」と思ったことがあったので記載します。

利用したEC2: Microsoft Windows Server 2012 Base - ami-1380926f

Spring Bootではエラーメッセージなどを表示するのみ properties ファイルを利用し、
下記のようにプレースフォルダーを利用しています。

ErrorsCommonInvalid =入力した内容にエラーがあります。
ErrorsCommonRequired ={0}は必ず入力してください。

AWSの無料利用枠を利用していた関係上、Windowsサーバが英語版になっているため、言語や時刻の設定を変更しました。
設定方法はたくさんの良い記事があるので参考リンクを載せて割愛します。
http://blog.serverworks.co.jp/tech/2016/06/20/windows-server-2012-r2-japanese-localization/

設定も完了し、実際に動かしてみても特に問題ないかなと思ったところ、

入力した内容にエラーがあります。// 〇
{0}は必ず入力してください。 // あれ?

という結果に。

元々はオンプレミスのWindowsサーバで動かしており、そっちの環境設定と比べてみても違う箇所が見当たらずしばらく悩むことに、、、

悩んだ結果とうとう見つけたのがこちらでした。

@Bean
ReloadableResourceBundleMessageSource messageSource() {

    Locale.setDefault(Locale.JAPAN); // ←これ!!!!!!!

    ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
    messageSource.setBasenames("classpath:messages/messages");
    messageSource.setCacheSeconds(0);
    messageSource.setDefaultEncoding("UTF-8");
    return messageSource;
}

Springでメッセージリソースを読み込む際にリソースが変更されたらメッセージも変更される様にしたいので ReloadableResourceBundleMessageSource を使っていたのですが、 ここのロケールが ja_JP になっていないようです。

システムのロケールを変更しても、サーバのデフォルトのロケール設定は変わらなかったのか?
ちょっと根本的な原因はわかっていませんが、解決策としてはロケールはきちんと指定するということでした。

こういう暗黙の設定による罠、気が付かない内に潜り込んでいることがあるので怖いですね。

, ,