2020年6月30日火曜日

angularでの複数チェックボックスの取り扱い。


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

最近久々にAngularプロジェクトを開発する機会があり、そこでまたいろいろと勉強になったことがあったので、ご存知の方には基本的なお話しなのかとは思いますが、今回は「angularで複数のチェックボックスを使った記述方法」の一例をご紹介できればと思います。

■作りたい画面

今回作る画面のイメージとしては、下記のような登録画面で、基本情報の入力と共にチェックボックスが複数設置され、その内容をフォーム送信して登録というようなシンプルな画面構造を想定します。

画面イメージ



■コンポーネント

まずコンポーネント側の記述ですが、今回フォーム送信を行うので、Angularのリアクティブフォームから、FormControl、FormGroup、FormBuilder、FormArrayクラスをそれぞれ利用します。 各クラスの細かな説明はAngularの公式ドキュメント内のリアクティブフォームの説明を見ていただいたほうがわかりやすいかもですが、めちゃくちゃざっくり書くとこんな感じかなと思います。
FormControl:単一入力欄の制御
FormGroup:FormControlのグループ化
FormBuilder:FormControlの作成に使う(FormControlをたくさん扱う場合にインスタンス不要)
FormArray:FormGroup内の配列要素コントロールの制御
さらに、今回は入力の必須チェックも行いたいので、Validatorsクラスもインポートします。

では、実際に上記をインポートし、コンポーネント側を記述します。
export class AppComponent implements OnInit {
  favoriteFruitsList: {key: string, value: string}[] = [
    {key: '1', value: 'りんご'},
    {key: '2', value: 'バナナ'},
    {key: '3', value: 'みかん'},
    {key: '4', value: 'ぶどう'},
  ];

  checkBoxFormArray: FormArray;
  groups: FormGroup[] = [];

  form: FormGroup = this.formBuilder.group(
    {
      name: ['', [Validators.required]],
      age: ['', [Validators.required]],
      tel: ['', [Validators.required]],
      formFavoriteFruitsList: this.formBuilder.array(this.groups, [Validators.required, this.checkBoxValidator]),
    }
  );

  constructor(
    private formBuilder: FormBuilder,
    public v: UserValidator,
  ) {}

  ngOnInit() {
    this.v.formGroup = this.form;
  }

  checkBoxValidator(control: FormArray) {
    for (let i = 0, loop_cnt = control.length; i < loop_cnt; i++) {
      if (control.at(i).value) {
        return null;
      }
    }
    return { unChecked: true };
  }

  onChange(value, isChecked: boolean) {
    this.checkBoxFormArray = this.form.get('formFavoriteFruitsList') as FormArray;
    if (isChecked) {
      this.checkBoxFormArray.push(new FormControl(value));
    } else {
      const index = this.checkBoxFormArray.controls.findIndex(x => x.value === value);
      this.checkBoxFormArray.removeAt(index);
    }
  }

  onSubmit() {
   // 登録処理
  }

}

form: FormGroup = this.formBuilder.group(...
の記述で、まずはフォームの初期設定をおこないます。
ここでチェックボックスとなるformFavoriteFruitsListはarray()メソッドでフォーム配列とし、さらにその中でチェックボックスをグループ化しています。これはcheckBoxValidatorでチェックボックスの必須チェックの為にこのような記述にしておきます。
ちなみにここで作成したcheckBoxValidatorは、チェックボックスのいずれかにチェックが入っているかのバリデーションで、Validatorsクラスには無いオリジナルのバリデーションになります。
onChangeについてはhtml側の記載で説明します。

■html

<form [formGroup]="form" (ngSubmit)="onSubmit()">
  <h2>名前</h2><input type="text" formControlName="name">
  <h2>年齢</h2><input type="text" formControlName="age">
  <h2>電話</h2><input type="text" formControlName="tel">
  <h2>好きな果物</h2>
  <ng-container formArrayName="formFavoriteFruitsList">
    <ng-container *ngFor="let item of favoriteFruitsList;">
      <label>
        <input type="checkbox" [value]="item.key" (change)="onChange(item.key, $event.target.checked)"><span>{{ item.value }}</span>
      </label>
    </ng-container>
  </ng-container>
  <button type="submit">登録</button>
</form>

ここでformArrayNameにコンポーネント側で設定したformFavoriteFruitsListを記載します。
これによりこのチェックボックスは配列要素のフォームとして扱います。
またここで、コンポーネント側に作成した、チェックボックスをチェックした時に発火するonChangeを使います。
チェックをON、OFFする際に、checkBoxFormArrayの配列内で、値を追加、削除する関数になります。
これにより、submitした時に、実際にチェックした値だけフォーム送信されます。


今回記載した内容はあくまで一例で、結構他の記載方法もあるようで、もしかしたらもう少し簡単に書ける部分もあるかもしれません。
また画面的には非常にシンプルなのですが、まだAngularのリアクティブフォームの使い方をうまく把握できていないと最初は難しく、結構苦戦しました(苦笑)。

自分のようなAngular初心者の方で、もしご参考になればと思います。

2020年6月4日木曜日

nodemonを使用して、コード変更後に自動でNode.jsのアプリを再起動する方法。


オフィス狛 技術部のmmm(むー)です。

Node.jsで動いているアプリケーションのコードの修正をした後、サーバーの再起動が必要になリます。
コードを修正した後、毎回手動で再起動するのは面倒ですし、再起動し忘れることもあります。
nodemonを使用すれば、その煩わしい作業を自動化できます😶

nodemonとは
nodemonとはNode.jsベースのアプリケーションのコードの変更を監視し、変更があった際に自動でサーバーの再起動をしてくれるツールです。
参考:https://nodemon.io/

【前提条件】
Nodeとnpmがインストールされていること

1. nodemonのインストール

使用したいプロジェクト配下に移動し、下記を実行します。
devDependencies オプションは開発環境でのみ使用するため、今回つけています。
$ cd ~/<プロジェクトパス>
$ npm install nodemon --save-dev

--save-dev オプションを使用してインストールすると、 package.json に下記のように追記されます。
devDependencies 配下のパッケージは本番環境で npm install --production コマンドを実行すると除外されます。
// package.json

"devDependencies": {
    "nodemon": "^2.0.3"
  }

2. nodemonでアプリケーションを実行する

package.jsonに nodeコマンドの代わりにnodemonで起動するscriptを追加します。
script名(start-watch)は自分可変です。
   // package.json

"scripts": {
     "start": "node src/index.js",
     "start-watch": "nodemon src/index.js", // 🌟追加
     "test": "echo \"Error: no test specified\" && exit 1"
   },

nodemonを使用して、アプリを起動します。
$ npm run start-watch

下記のように起動ログが出力されれば、起動成功です。
 [nodemon] watching path(s): *.*
 [nodemon] watching extensions: js,mjs,json
 [nodemon] starting `node src/index.js`

コードに何か変更があった場合、下記のようにログが出力されます。
 [nodemon] restarting due to changes...
 [nodemon] starting `node src/index.js`

また手動で再起動したい場合は、 rs コマンドを打ってください
$ rs
 
 [nodemon] starting `node src/index.js`

以上となります。
インストールして少し設定するだけで、開発が楽になるのでまだ使用していない方はぜひお試しください🍭

2020年5月28日木曜日

SUZURIでオリジナルグッズを作りました。


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

弊社のWEBサイトなどで使用しているイラストのグッズをSUZURIというサービスで作成し、社員が注文した現物が届きましたので紹介します。


SUZURIはpngまたはjpg画像を1枚アップロードするだけでオリジナルプリントのグッズが販売できるようになるサービスです。
Tシャツなどのポピュラーなアイテム以外にも赤ちゃんのよだれかけなどの様々なアイテムに、注文がある度に印刷して発送してくれます。
在庫の管理をしなくてよいので売れるかどうかを気せずに、気軽にオリジナルの絵柄のグッズをオンライン販売できるのが有難いですね。


試しにいろいろなグッズを作ってしまいました。
グラスなど調整が必要なグッズもありましたが基本的にWEBサイトなどに使用した画像のカラーモードを変えただけの画像をほぼそのままアップロードするだけでオリジナルプリントのアイテムのモックアップが自動的に生成されました。
(ちなみに調整が一番大変だったのはスマートフォンケースでした。自動的にいろいろな端末のケースが作られてしまうのでシンプルな絵柄のものでないと調整が難しく感じました)

また、利益分も個人的に100円単位で設定できるのが有難いと思います。(弊社のグッズは利益分は初期設定または初期設定以下に設定にしてあります。)


今回、サイトで作ったTシャツとステッカーを社員が購入したので実物の写真を撮影してみました。
(Tシャツの上に置いて撮影したステッカー自体の色が暗いので雑なコラージュのようになってしまいました…)

綺麗に印刷されていますね。写真では分かりにくいかもしれませんが、Tシャツ自体は厚手で非常にしっかりした作りです。
あまりにも作業が簡単なのでもっと安っぽい印刷かと思いましたがほとんど普通にお店で売っているプリントTシャツと同じようなプリントなのではないでしょうか…?

カラーモードをRGB(画面で表示する際のカラーモード)→CMYK(印刷する際のカラーモード)に変更したので少々くすんでいるかと思いましたが非常に色も鮮やかに見えます……!
個人的にはTシャツは大満足の出来です。

ステッカーの方はモックアップをPC画面で見た時よりも少し暗めの色になってしまっていますね。ステッカー自体の色が暗い色だからでしょうか…?
でも印刷自体は色ムラもなくかなり綺麗だと思います。


現在オフィス狛のSUZURIのページの方でオリジナルグッズをオンライン販売中ですので気になる方はぜひアクセスしてみてはいかがでしょうか。
私も緊急事態宣言がおさまり次第、トートバックを買おうかと思っています。

2020年5月19日火曜日

MacOS Catalinaはデフォルトのログインシェルがbashではないらしい。



オフィス狛のyuckieee(ゆっきー)です。
最近Angularの環境構築をする機会があったのですが、その際以下の事象に悩まされました。

「ターミナルを起動するたびに"source ~/.bash_profile"を実行しないとパスが通らない!!!」

最初は毎回コマンド叩いてたのですが、煩わしくなって調べたら簡単な話でした...。
そこで本事象の原因や対処方法について軽くまとめておきます。

事象の原因

MacOS Cataliaからデフォルトログインシェルが「bash」から「zsh」に変更された事で、設定対象と読み込み対象のシェルが食い違っていることで本事象が発生していました。

もう少し細かく説明すると、環境構築方法を説明した多くの記事はbash(.bash_profile等)にパス設定する手順が書かれています。 ですが、MacOS Catalinaからはデフォルトのログインシェルが変更されており、ログイン時に読み込まれるのはzshの設定ファイルです。 いくらbashに設定を追加しても読み込まれることはなく、毎回強制読み込みコマンド("source ~/.bash_profile")を実行する必要があるのでした。
そりゃそうだ...。

現状の設定確認

それでは、実際にデフォルトのログインシェルの設定状況を確認してみましょう。
ターミナルを起動し、以下のコマンドを実行してください。

$ echo $SHELL
/bin/zsh

実行結果が"/bin/bash"以外であれば、パスを書き込むべきは".bash_profile"ではありません。

なぜデフォルトログインシェルが切り替わったのか?

公式での見解は見つからなかったのですが、幾つか記事を参照しているとライセンス問題と推測する声が多くありました。 そもそもmacOS Mojave以下のデフォルトログインシェルはbashですが、バージョンは最新(2020/05/08時点でver5.0)ではないようです。
セキュリティ上、最新化すべきと考えるのが自然ですが、ライセンス問題から旧バージョンのままとなっていたと思われます。
そして、この解決策として、ライセンスに課題を抱えるbash最新化ではなく、別のシェル(zsh)への乗り換えを選択したのでしょう。多分。

対応方法

対応方法としては、大きく2パターンが考えられます。

 パターン① zsh用の設定を行う
 パターン② デフォルトのログインシェルをbashに切り替える

切り替わった理由を推し量ると、推奨される対応方法はパターン①だと思います。
また、もしbashに切り替えるなら最新化もセットで行う必要がありそうです。

とはいえ、今回はパターン①、②双方の切り替え方法をご紹介しておきます。

パターン①zsh用の設定を行う

パスを通すだけであれば、基本的に設定ファイル名称を変更すれば済みます。
bash設定ファイルとの対比は以下のとおり。
bash zsh 補足
.bash_profile .zprofile ログイン時 (SSH ログインも含む) に実行
.bashrc .zshrc 新しいターミナルセッションごとに実行

指定例は以下のとおり。
今まで".bash_profile"を指定していた箇所をzsh用の".zprofile"に置き換えるのみです。
$ echo export PATH='/usr/local/bin:$PATH' >> ~/.zprofile
$ vim .zprofile

既に".bash_profile"にパスを設定している場合は、ファイルコピーで対応が可能です。
$ cp .bash_profile .zprofile

パターン②デフォルトのログインシェルをbashに切り替える

推奨ではないと思われますが、以下の手順でbashへの切り替えも可能です。
まず、切り替え対象のシェルが利用可能か確認するため、以下のコマンドを実行します。
bashに切り替える場合、本リスト内に"/bin/bash"があればOKです。
$ cat /etc/shells
# List of acceptable shells for chpass(1).
# Ftpd will not allow users to connect who are not using
# one of these shells.
/bin/bash
/bin/csh
/bin/dash
/bin/ksh
/bin/sh
/bin/tcsh
/bin/zsh

前項の確認結果を基にシェルの切り替えコマンドを実行します。
実行時にパスワードを求められるので入力してください。
$ chsh -s /bin/bash
Changing shell for ユーザー名.
Password for ユーザー名: 🗝

再度デフォルトログインシェルを確認し、切り替わっていればOKです。
$ echo $SHELL
/bin/bash

パスを直ぐに通したい場合は、以下のコマンドでパスを読み込ませます。
$ source ~/.bash_profile

Appleのサポートページでは、この他にもシステム環境設定画面からシェルを切り替える方法なども紹介されています。
Apple公式サポート:zshをMacのデフォルトシェルとして使う

【 おまけ 】

bash切り替え後にターミナルを立ち上げると以下のようなメッセージが表示されます。
「デフォルトシェルはzshに変わったから切り替えて!」と言うようなメッセージです。
 The default interactive shell is now zsh.
 To update your account to use zsh, please run `chsh -s /bin/zsh`.
 For more details, please visit https://support.apple.com/kb/HT208050.

本メッセージは、以下のコマンドを実行することで非表示にできます。
 $ export BASH_SILENCE_DEPRECATION_WARNING=1

事象が解決しない場合に確認すべきこと

ログインシェルの設定はソフトウェア単位にも設定可能な場合がありますので、そちらが有効となっていないか確認してみてください。

例としてターミナルでの設定確認方法をご紹介します。
ターミナルを起動し、[ターミナル] > [環境設定]を開き、環境設定画面[一般]タブの[開くシェル]設定が[コマンド(完全パス)]になっている場合、こちらの設定が優先となっています。





まとめ

セキュリティ上の懸念やAppleの対応(zshに切り替え)を考えると、個人的には利用者側もzshに切り替えるのが最善だと思います。
私もbashに切り替えるのではなく、zshの使用に切り替えるよう対応しました。
また、改めて環境構築周りの知識を強化しなければと反省。

2020年5月8日金曜日

AWS EC2でプロキシサーバー(Linux)を構築する。


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

最近担当したプロジェクトで、開発用に用意した複数のAmazon WorkSpaces(Windows)から、外部の開発用VPNへ接続する必要があったのですが、 VPNに接続可能なIPアドレスが1つという制限がありましたので、EC2でプロキシサーバーを構築することにしました。

AWSであれば、NAT(インスタンス、ゲートウェイ)でも実現可能ですが、 今回の開発環境では、一部ネットワークの接続制限がありましたので、プロキシサーバーを選択しました。

最低限の設定にはなりますが、手順をご紹介します。
※VPC、サブネット等は、事前に作成されている前提です

1.EC2インスタンス作成(Linux)

プロキシサーバー用のEC2インスタンス(Linux)を作成します。
細かい手順は省略させていただきますが、注意点としては以下のようになります。
・インスタンスタイプは最小を選択
・「インスタンスの詳細の設定」で、「自動割り当てパブリックIP」は「無効化」に設定
 ※後で「Elastic IPアドレス」を関連付けます

2.Elastic IPアドレスの割り当てとEC2への関連付け

EC2サービスの「Elastic IP」から、プロキシサーバー用の固定IPアドレスを割り当てます。
・スコープ:VPC
・パブリックIPv4 アドレスプール:Amazon の IPv4 アドレスプール

続けて、割り当てたIPアドレスを選択して、Actionの「Elastic IP アドレスの関連付け」から、1.で作成したEC2に関連付けます。

3.Squidの設定

プロキシサーバー用のEC2インスタンス(Linux)に、プロキシサーバーソフトの「Squid」を、以下の手順で設定します。

①Squidインストール
sudo yum install -y squid

②Squid有効化
sudo systemctl enable squid

③有効化の確認(squid.serviceがenabledであること)
sudo systemctl list-unit-files -t service | grep squid

④Squid設定ファイル修正
設定ファイルに、プロキシサーバーに接続するIPアドレスを設定します。

※注意
必ず、「http_access deny all」の記述より「上」に設定してください。
(上記は「そのほかのアクセスはすべて拒否する」という意味になりますので、下に設定してしまうと有効になりません)


sudo vim /etc/squid/squid.conf

【追記内容】
# 接続したいIPアドレスを指定(複数指定可能)
acl myip src [IPアドレス1]/32
acl myip src [IPアドレス2]/32

# 接続したいIPを許可
http_access allow myip

⑤Squidリロード
設定ファイルを反映する場合、再読み込みを行います。
sudo systemctl reload squid

⑥squidアクセスログ確認
ログでアクセス状況を確認することもできます。
sudo cat /var/log/squid/access.log

4.WorkSpaces(Windows)側の設定

最後に接続側の設定です。
インターネットオプションから、「接続」タブの「LANの設定」ボタン押下します。

続けて「プロキシサーバーを使用する」をチェックして、
・アドレス:2.で割り当てたElastic IPアドレス
・ポート:Squid設定ファイルにの「http_port」に定義されているポート番号(デフォルトは3128)

※プロキシサーバーを使用したくない接続先がある場合は、「詳細設定」ボタンから、例外を指定してください。


以上が、必要最低限の設定になります。

接続側のグローバルIPを確認(確認くん など)すると 「2.Elastic IPアドレス」のIPアドレスが、表示されると思います。


,

2020年4月14日火曜日

JSON ServerとFaker.jsを使って、大量のダミーデータがあるREST APIサーバーの作り方


オフィス狛 技術部のmmm(むー)です。

フロント担当になったけど、APIがまだ作成されていない... Databaseもない...
そんな時のために大量のダミーデータがあるREST APIサーバーの作り方をご説明します😶

【前提条件】
Nodeとnpmがインストールされていること

1. JSON Serveのインストール

JSON Serverを使用すると、REST APIのモックサーバーを簡単に作成できます。

使用したいプロジェクト配下に移動し、下記を実行します。
$ cd ~/<プロジェクトパス>
$ npm install --save json-server 

# もしグローバルインストールしたい場合はこちら
$ npm install -g json-server

2. Faker.jsのインストール

Faker.jsを使用すると、大量のダミーデータを簡単に作成することができます。

Faker.jsのデータを保存する用に新たなファイルを作成します。
$ vi database.json

中身は下記のようにしてください。
{
     "info": []
 }

Faker.jsをインストールします。
$ npm install faker --save

Faker.jsでデータを作成する用のファイルを作成します。
$ vi generate.js

中身は下記のようにしてください。
(これは一例なので、名前とメールアドレスがセットのデータを10個作成していますが、必要なデータに合わせて変更してください)
var faker = require('faker');
 
 var database = { info: []};
 
 for (var i = 1; i<= 10; i++) {
   database.products.push({
     id: i,
     name: faker.name.findName(),
     email: faker.internet.email(),
   });
 }
 
 console.log(JSON.stringify(database));


以下のURLのNameSpacesに 、Faker.jsの用意されているダミーデータが記載されていますので必要なものを使用してください。
http://marak.github.io/faker.js/index.html

generate.jsのコードを実行して、出力結果をdatabase.jsonに書き込みます。
$ node generate.js > database.json

database.json中身が下記のようになりました。
$ cat database.json

 {"products":[
  {"id":1,"name":"Newton Kris","email":"Precious40@hotmail.com"},
  {"id":2,"name":"Dee Hackett","email":"Kasandra.Trantow91@gmail.com"},
  ~ 省略 ~
  {"id":10,"name":"Alvera Russel","email":"Felicia57@hotmail.com"}
 ]}

database.json のデータを返す、jsonServerを起動します。
$ json-server --watch database.json
 
  #  下記のように表示されたら、起動成功です
   \{^_^}/ hi!
 
   Loading database.json
   Done
 
   Resources
   http://localhost:3000/info
 
   Home
   http://localhost:3000

ブラウザにて、http://localhost:3000/info にアクセスしてみましょう。
作成したデータが表示されているはずです。

3. コマンドラインから確認する場合

curlコマンドを使用して確認します。
 # GET:全てのデータ取得
 $ curl -X GET "http://localhost:3000/info"
 
 # GET:「idが1」のデータだけ取得
 $ curl -X GET "http://localhost:3000/info/1/"
 
 # POST:「idが11」「nameがhoge」「emailがfuga@gmail.com」のデータ作成
 $ curl -X POST -d "id=11&name="hoge"&email=fuga@gmail.com" "http://localhost:3000/info"
 
 # PUT:idが1のデータの「nameをtest」「emailをupdate@gmail.com」に更新
 $ curl -X PUT -d "name=test&email=update@gmail.com" "http://localhost:3000/info/1"
 
 # DELETE:「idが11」のデータを削除
 $ curl -X DELETE "http://localhost:3000/info/11"

🍭 以下おまけ

既存プロジェクトのpackage.jsonのscript箇所に、データを作成するコマンドとjsonServerを起動するコマンドを入れると 便利です。

   // 一例として、angularのプロジェクトのpackage.json
   "scripts": {
     "ng": "ng",
     "start": "ng serve",
     "build": "ng build",
     "test": "ng test",
     "lint": "ng lint",
     "e2e": "ng e2e",
     "generate": "node generate.js > database.json", // 追加
     "server": "json-server --watch database.json" // 追加
   },

下記のようにスクリプトを実行することができます。
# ダミーデータの作成
 $ npm run generate
 
 # jsonServerの起動
 $ npm run server


以上となります。
簡単に使用できるので、REST APIサーバーが至急必要な場合はぜひ試してみてください。

2020年3月31日火曜日

iOSでViewの一部分を角丸にしたい時の拡張クラスの作り方。


こんにちは、オフィス狛 モバイル開発担当Aika-yuy です。
今回の投稿は、viewなどの一部分を角丸にしたい場合にインスペクタから設定できるようにする拡張クラスをご紹介します。
iOS11以降は、バージョンアップして以前より簡単に部分的に角丸にできるようになりました。


〜iOS10の設定方法

let path = UIBezierPath(roundedRect:layer.bounds,
                                byRoundingCorners:[//角丸にしたい場所を指定
                                                                    .topRight,
                                                               .topLeft,
                                                                    .bottomRight,
                                                                    .bottomLeft
                                                                   ],
                                cornerRadii: CGSize(width: XX, height: XX))
        let maskLayer = CAShapeLayer()
        maskLayer.path = path.cgPath
        layer.mask = maskLayer


iOS11〜の設定方法

layer.maskedCorners = [//角丸にしたい場所を指定
                                       .layerMaxXMaxYCorner,//右上
                                       .layerMinXMaxYCorner,//左上
                                          .layerMaxXMinYCorner,//右下
                                       .layerMinXMinYCorner//左下
                                         ]


CustomViewを作成しました

角丸の位置の指定は、ビット値で設定しているため、cornersではそれぞれの角丸に設定された値の合計を出しています。
class CustomView : UIView {
    @IBInspectable var cornerRadius: CGFloat = 0.0 { didSet { self.setNeedsLayout() } }
    @IBInspectable var cornerTopRight: Bool = false { didSet { self.setNeedsLayout() } }
    @IBInspectable var cornerTopLeft: Bool = false { didSet { self.setNeedsLayout() } }
    @IBInspectable var cornerBottomRight: Bool = false { didSet { self.setNeedsLayout() } }
    @IBInspectable var cornerBottomLeft: Bool = false { didSet { self.setNeedsLayout() } }
    
    private var corners: UInt {
        return UInt((cornerTopLeft ? 2 : 0) + (cornerTopLeft ? 1 : 0) + (cornerBottomRight ? 8 : 0) + (cornerBottomLeft ? 4 : 0))
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        self.setcornerRadius()
    }
    
    private func setcornerRadius() {
        layer.cornerRadius = self.cornerRadius
        if #available(iOS 11.0, *) {
            layer.maskedCorners = CACornerMask(rawValue: corners)
        } else {
            let path = UIBezierPath(roundedRect: layer.bounds,
                                    byRoundingCorners: UIRectCorner(rawValue: self.corners),
                                    cornerRadii: CGSize(width: self.cornerRadius, height: self.cornerRadius))
            let maskLayer = CAShapeLayer()
            maskLayer.path = path.cgPath
            layer.mask = maskLayer
        }
        layer.masksToBounds = self.cornerRadius > 0
    }
}













CustomViewを使用すると、インスペクタからon/offで部分的に角丸を設定できるようになります。 細かい角丸の設定が必要な際は使ってみてください!

2020年2月28日金曜日

knex.jsで発生した問題と対処方法(Invalid columnエラー、returningで取得できない)


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

弊社ではknex.jsを一部のプロジェクトで使用しているのですが、
これまで開発中にハマってしまった事象と対処方法を2点ご紹介したいと思います。

【環境】
・node.js:12.14.0
・knex.js:0.15.2
・SQL Server 2017

1.「Invalid column name」エラー

内部結合でand条件を追加するため、マニュアルを参考に下記のように記述したのですが、エラーが発生しました。
  const number = '1234';
  return await knex
    .select('id')
    .from('tbl_1')
    .innerJoin('tbl_2', function cond() {
      this.on('tbl_2.id', 'tbl_1.id');
      this.andOn('tbl_2.number', number);
    });

エラー内容)
Invalid column name '1234'.

function内で変数を使用すると、カラム名として扱われてしまいまいた。
対処として、プレースホルダを使用すると、値として正しく扱うことができました。

対処方法:プレースホルダを使用する)
  const number = '1234';
  return await knex
    .select('id')
    .from('tbl_1')
    .innerJoin('tbl_2', function cond() {
      this.on('tbl_2.id', 'tbl_1.id');
      this.andOn(knex.raw('tbl_2.number = ?', [number]),
      );
    });

2.insertした値を「returning」で取得できない

「returning」を使うとinsertした行の、指定したカラムの値を取得することができます。
(マニュアルを見ると、PostgreSQL、MSSQL、およびOracleで使用できるようです)

通常は以下のように記述します。この場合、insertしたデータのidの値「2」を取得できます。
(insertする値を取得するというちょっと意味のないことをしていますが、本来はオートインクリメントの値などを取得したい時などに使用します)

  return await knex
    .insert({ id: 2, memo: 'メモ' })
    .into('memo_tbl')
    .returning('id');

次に、insert句にknex.rawを使用して記述してみると、値が取得できませんでした。

NG:値が取得できない)
  return await knex
    .insert(knex.raw("(id, memo) VALUES (2, 'メモ')"))
    .into('memo_tbl')
    .returning('id');

対処として、returningは使用せず、SQL Serverで同じく操作した行の値を取得するOUTPUT句をそのまま記述することで値を取得することができました。
(OUTPUT句はSQL Serverで使用可能です。他のデータベースは異なります)

対処方法:OUTPUT句をそのまま記述する)
  return await knex
    .insert(knex.raw("(id, memo) OUTPUT INSERTED.id VALUES (2, 'メモ')"))
    .into('memo_tbl');


今回ご紹介した事象のように、一見すると正しい記述のようですが、
思わぬところで期待通りに動作しないことがありますので、ご注意ください。


,

Angularのバージョンアップ(7から8)後に「An unhandled exception occurred: Job name "..getProjectMetadata" does not exist.」が発生した場合の対処。


こんにちは。
最近は、CI/CD周りの環境構築にどっぷり浸かっていましたKoma(Twitterアカウントの中の人&CEO)です。
CI/CD周りはいずれ投稿するとして、今日はAngularのアップデート時に発生したエラーの解消方法です。

結論から言うと、バージョン「9」がリリースされた今だけ限定の事象ではあるのですが、
日本語で解決策を載せているサイトが無かったので、勢いで書きました。

(1)エラーが出る前にやっていたこと

今回やっていたことは以下の通りです。
・既存のAngularプロジェクトのバージョンをアップデート(8.2へ)
・既存のバージョンは「7.2」

バージョンアップ自体は、いつもの通り、Angular Update Guideを参考に行なっています。

(2)エラーの内容

アップデート自体は、うまく行ったのですが、その後の起動(ng serve)で下記のエラーが発生しました。
An unhandled exception occurred: Job name "..getProjectMetadata" does not exist.

(3)対応した内容

実は、本家のissueにも登録されている内容なのですが、
アップデート後に、「npm audit fix」をやってしまった事が原因です。
(というか、普通やりますけど)

「npm audit fix」によって、関連のプラグインがアップデートされますが、
この時、「@angular-devkit/build-angular」のバージョンが上がってしまうことに問題があります。
「npm audit fix」後の package.jsonを見ると・・・・
"@angular-devkit/build-angular": "^0.900.4",
となっています。
これが、Angular 9用のバージョンなのですが、今回アップデートしようとしているのはバージョン8なので、エラーになってしまうのですね。

と言うことで、
"@angular-devkit/build-angular": "~0.803.24",
に戻したところ、エラーはなくなり、無事に起動(ng serve)出来ました。

気持ち的には、「Angular 9」にアップデートしたいところなのですが、使用しているプラグインの対応を待たないといけないので、もどかしいところですね。
(時間さえあれば、プラグインの更新に貢献したいところなのですが・・・)

さて、これから残り3サイトのアップデートを行おうと思います。😭
しんどいけど、アップデートされず放置されているシステムが世の中に溢れていることを考えると、
アップデート出来るだけ、恵まれてますね😄

では、より良いAngularライフを❗️


2020年2月27日木曜日

nodenvでプロジェクトごとにnode.jsのバージョンを切り替える方法。


オフィス狛 技術部のmmm(むー)です。

nodenvを使用してローカル環境のプロジェクトごとにnode.jsのバージョンを切り替える方法を説明します。
もちろん全てのプロジェクトで最新のバージョンを使用するべきですが、難しい時もありますよね...¯\_(ツ)_/¯

【環境】
MacOS Mojava
バージョン 10.14.6

1. anyenvのインストール

anyenvをインストールします。
(anyenvとは、ローカル環境で言語ごとに複数のバージョンを使用するためのツールです。node.jsだけでなく、pythonやPHPにも使用できます🍭)
➜ 😶git clone https://github.com/riywo/anyenv ~/.anyenv

パスを通す
➜ 😶echo 'export PATH="$HOME/.anyenv/bin:$PATH"' >> ~/.bash_profile
➜ 😶echo 'eval "$(anyenv init -)"' >> ~/.bash_profile

shelの再起動
➜ 😶exec $SHELL -l

anyenvの初期化
➜ 😶anyenv install --init

2.nodenvとnode-buildのインストール

nodenvをインストールします。
➜ 😶anyenv install nodenv

node-buildをインストールします。
➜ 😶brew install node-build

default-packagesファイル作成する。
➜ 😶echo yarn >> $NODENV_ROOT/default-packages
  // 実行しないと 後続作業でnodeをインストールするときに下記エラーがでる
  // nodenv: default-packages file not found

3.node.jsのインストール

インストールできるnode.jsのバージョン一覧を確認する。
➜ 😶nodenv install --list

使用したいバージョンをインストールする。
➜ 😶nodenv install <バージョン>

4.プロジェクトで使用するnode.jsのバージョンの設定

使用したいプロジェクト配下へ移動する。
➜ 😶cd <プロジェクトパス>

そのプロジェクトで使用するバージョン指定する。
➜ 😶nodenv local <バージョン>

// プロジェクト配下ディレクトリで使用するNode.jsのバージョンが「.node-version」に記載される
➜ 😶cat .node-version
 10.12.0

設定したバージョンと同じものが表示されていれば成功。
➜ 😶node -v
10.12.0 

補足1)インストールしたNode.jsのバージョン一覧を表示
➜ 😶ls ~/.anyenv/envs/nodenv/versions

補足2)アンインストールする場合
➜ 😶nodenv uninstall <バージョン>


以上となります。
最新のバージョンを使用するべきですが、プロジェクトごとに違うバージョンのnode.jsを使用しないといけない際はぜひ参考にしてください。

2020年2月26日水曜日

package.json内にscriptsの記述を設定する(npm-scripts)


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

node.jsを使った開発を行う時に、JavaScriptライブラリのパッケージマネージャーであるnpmを使いますが、このnpmにはプロジェクトの情報管理ファイルであるpackege.jsonがあります。
基本的なpackege.jsonの記載方法については割愛しますが、このpackege.json内にscriptsという記述を設定することによって、独自のコマンドを設定することができます。
これによって、例えばローカルサーバーの起動や停止等、良く使うコマンドを設定しておけば、いろいろコマンドを打たずに済むといった感じになります。

例えばAngularの開発では、package.jsonには下記のようにscriptsの記載したりします。

  "scripts": {
    "start": "ng serve",
    "test": "ng test",
    "build": "ng build",
    "copy": "cpx ./dist/* ../server/",
    "precommit": "lint-staged",
    "ng": "ng",
  },

とscripts内にいくつかのコマンドを設定しておきます。そして、

$ npm run [スクリプト名]

と打てば上記で設定したコマンドが実行されます。
よく使うコマンドは独自に作っておけば結構楽な場合があります。

また、上記scriptsには予約語があり、start、stop、restart、testが予約語として用意されています。
なので、たとえばstartのスクリプトを実行するときは、npm run startと打たなくても

$ npm start

とコマンドを打つだけで実行可能です。

もっと細かくいろいろ設定したりもできます。
たとえばscriptsに記述したコマンドを複数一気に実行したい場合、以下のようにscript内に記述しておきます。

  "scripts": {
    "start": "ng serve",
    "test": "ng test",
    "all": "run-s build copy",  // 追加
    "build": "ng build",
    "copy": "cpx ./dist/* ../server/",
    "precommit": "lint-staged",
    "ng": "ng",
  },

そして、上記スクリプト名の"all"を

$ npm run all

と実行すれば、"build"と"copy"というスクリプトが実行されます。

    "all": "run-s build copy"

の記述の run-s というコマンドが、複数実行で直列に実行するnpm-run-allのショートカットの意味で、指定したスクリプトを順番に実行してくれます。
また、応用で run-p というコマンドもあるのですが、こちらも複数実行ですが、スクリプトを並列に実行するコマンドになります。

上記以外にももっといろいろ細かく設定できるようなのですが、まずは上記のような設定で、ライトに使い始めてもいいかなと思いました。

2020年2月21日金曜日

Gitブランチ間の差分ステップ数を取得する。

はじめまして、オフィス狛のyuckieee(ゆっきー)です。

初投稿となる今回は、技術よりではなく開発付帯作業で使えそうなツールをご紹介しようと思います。

はじめに

みなさんが関わっているプロジェクトが、割とガッチリしたところだと「生産性の分析」のために開発ステップ数を集計されているのではないでしょうか。
例えば、母体のソースコードのステップ数、変更後の追加・修正・削除ステップ数などです。

狛ではソースコードをGitで管理しており、Git自体にもブランチ間の差分をとるdiffコマンドが存在します。ですが、このdiffコマンドがイケていない(笑)

そこで、幾つかネットで探して、最終的に「cloc」というオープンソースのツールを導入してみることにしました。
これが割と快適だったので、導入方法や出力イメージなどをご紹介します。

1.clocについて

「cloc(Count Lines of Code)」は、指定ディレクトリ又はファイルのステップ数を解析してくれる便利ツールです。Git diffコマンドとの大きな違いは、ブランチ間の差分ステップ数を「追加」「変更」「削除」で識別し、カウントしてくれる点です。
 現在、オープンソースとしてGitHubに公開されており無償で利用が可能です。

 GitHub : cloc
 ※clocは、他のソースからコピーされた部分を除きGNU General Public License v2の下でライセンスされています。

2.導入方法

「cloc」は、MacBookやWindows、Linuxなど幅広いOSで利用が可能です。
今回は、私が開発で使っているのがMacBookなので、そちらへの導入方法をご紹介します。

インストール環境:MacOS Catalina バージョン 10.15.2

①HomeBrewをインストール

今回は、HomeBrewを使用してインストールするため、HomeBrew自体をインストールします。 MacOSへのインストール要件はコチラを参照ください。

最初に対象のMacにHomeBrewがインストールされているかどうか確認します。
% brew --version
zsh: command not found: brew

インストールされていない場合は、ターミナルから下記のコマンドを実行し、インストールしてください。 ※インストールコマンドはHomeBrewの公式ページより取得
% /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

実行完了後、正常にインストールされた事を確認します。
% brew --version
Homebrew 2.2.5

②clocをインストール

cloc本体のインストールを行います。
ターミナルを立ち上げ、以下のコマンドを実行してください。
% brew install cloc

実行完了後、正常にインストールされた事を確認します。
% cloc --version
1.84

導入作業はこれで完了です🎉

3.利用方法

主目的はブランチ間の差分ステップ数取得ですが、今回は2つ利用方法をご紹介します。

パターン① 現行のブランチに対するステップ数解析

①ターミナルを立ち上げ、該当のGitローカルリポジトリに対しclocコマンドを実行します
% cloc /Users/yuckieeee/Gitローカルリポジトリ

<実行結果(例)>
    3000 text files.
    3000 unique files.                                          
      500 files ignored.

github.com/AlDanial/cloc v 1.84  T=5.70 s (355.9 files/s, 33435.9 lines/s)
-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
Java                           350           4000              350          25000
XML                            250           2500              300         12000
 ・
 ・
 ・
-------------------------------------------------------------------------------
SUM:                          1500       10000            2000     60000
-------------------------------------------------------------------------------

パターン② ブランチ間のステップ数の差分解析

①比較対象のブランチ2つをGitからダウンロードしてください
 GitLabだとリポジトリのトップ画面右上にダウンロードアイコンがあります。

②ターミナルを立ち上げ、ダウンロード先のディレクトリに移動します

③下記のclocコマンドを実行してください
 zipやtarのままでもステップ数の解析が可能です。
% cloc --diff master.tar branch.tar
※圧縮ファイルの場合は、拡張子まで指定してください

<実行結果(例)>
     300 text files.
     300 text files.
          0 files ignored.                                         

github.com/AlDanial/cloc v 1.84  T=1.55 s (337.8 files/s, 22344.2 lines/s)
-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
Kotlin
 same                          200           1800            400          12000
 modified                      90                  0                 0               180
 added                             3             300           122              1300
 removed                         0                 0                0                100
XML
 same                          100            800             50            10000
  ・
  ・
  ・
-------------------------------------------------------------------------------
SUM:
 same                          100           200           100          10000
 modified                       20                0                3               100
 added                           20            200           150            1800
 removed                      30               10               0               100
-------------------------------------------------------------------------------

これでブランチ間の追加・修正・削除ステップ数が確認できました。 clocは、改行、コメントやコードごとに集計されるので、非常に分かり易いです。
欲を言うなら、パータン②のダウンロード作業が無くなってくれれば最高です☺️←

4.コマンドオプション

最後に、重宝しそうなオプションをいくつか紹介して終わろうと思います。

・比較対象を指定

clocはディレクトリ、ファイル、Git hashによる比較対象の指定が可能です。
Git hashでのコマンド指定を例示します。
// ローカルリポジトリに遷移
% cd /Users/yuckieeee/ローカルリポジトリ/
// 対象コミットのハッシュを確認する
% git log
// 上記で確認したハッシュを指定する
% cloc --diff <コミットハッシュ①> <コミットハッシュ②> 

・ファイルごとに解析結果を表示

何も指定しない場合は、プログラム言語ごとに集計されます。
ファイル単位に確認したい場合は、以下のように--by-fileオプションを追加すればOKです。
% cloc --diff master.tar branch.tar --by-file

・CSVファイル出力

CSVファイル出力したい場合は、以下のようにcsvタイプ指定と出力先指定をすればOKです。
% cloc --diff master.tar branch.tar --csv > result.csv

まとめ

開発の付帯作業の必要性は分かるものの、出来るだけ時間を掛けたくなですよね。。
これからも便利そうなツールや機能があれば紹介していきたいと思います。

2020年2月5日水曜日

Spring Fest 2019に参加してきました。


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

去年、Spring Fest 2019(12/18 御茶ノ水ソラシティ)が開催されました。
弊社プロジェクトの一部でSpring Bootを使用しているため、情報収集を目的に今回初めて参加してみました。
年々参加者数が増えているとのことで、とてもたくさんの方が来場されていました。

と言うことで、年は明けてしまいましたが、感想をブログに残したいと思います。

【公式ページ】
https://springfest2019.springframework.jp/

基調講演

Spring Boot 2.2の概要、2.3の紹介がありました。
そのなかでも気になったのが、今後、Spring Bootはリリース周期が1年から6ヶ月と短くなるそうで、バージョンアップのタイミングにも注意が必要になりそうです。また、2.1系は2020/11にEOLとなるそうです。

Spring Boot爆速開発超絶技巧

サムライズムさん
https://speakerdeck.com/yusuke/spring-boot-and-intellij-idea-technique
これまで開発では、STSしか使用したことが無かったのですが、「IntelliJ IDEA」とはどのようなものか、タイトルにも興味があり参加してみました。
極力キーのみで操作するということで、様々なショートカットを使用したデモでは、早い、便利と大変驚きました。
機会があれば無料版を弄ってみようと思います。

徹底解剖Spring MVCアーキテクチャー -DispatcherServletの中身を覗いてきました

カサレアルさん
https://www.slideshare.net/ssuser070fa9/spring-fest-2019spring-mvc
Spring MVCのアーキテクチャーをソースコードリーディングで解説されていました。
スライドの内容が主にソースコードでしたので、なかなか説明に追いつけずに苦労しましたが、内部構造まで説明があり、他のセッションと比べて内容が深かったです。
(周りの参加者の皆さんは、ノートPCやタブレットでスライドを参照されて便利そうでした。。。次回は用意しようと思います)

システム間連携を担うSpring Integrationのエンタープライズ開発での活用

NTT DATAさん
https://www.slideshare.net/apkiban/spring-integration-207667949
異なる仕様やオンプレ×クラウドなどのシステム間連携が増える中で、システム間連携の技術として、Enterprise Integration Patternsで推奨されている「非同期メッセージング」を実現するために「Spring Integration」を紹介されていました。
「Message」、「Channel」、「Endpoint」のキーワードとフローを用いた概要と、実際の作成ステップなど説明があり、勉強になりました。

Spring Developer のための コンテナ入門

Google Cloudさん

Kubernetes、Jibと勉強不足で初めて聞く単語でしたが、Jibを使用することでJavaのアプリケーションのDockerコンテナを簡単に作成できることに驚きました。Kubernetesについては、コンテナ管理(監視や制御)を知ることができました。

JSP/JSF から Spring Web + Thymeleaf への移行

伊賀 敏樹さん
https://www.slideshare.net/ssuser2e0217/practical-migration-from-jsp-to-thymeleaf
Thymeleafの紹介と利点についてのセッションでした。Thymeleafは使用しているので復習になりました。

Springアプリケーションのテスト道具 使いどころ、使わないどころ

いろふさん
https://speakerdeck.com/irof/decide-to-use-test-tool-for-spring-application
Springのテスト道具として、JUnit 5、Mockito、Spring Test、Selenium、Dockerの紹介から始まり、
「原則として、テストしたいことの近くでテストを行う」、「道具の向き不向きを考えてテスト道具の使いどころを見極める」ということに重点を置いて説明されていました。
Springというより、テストについて改めて勉強になったセッションでした。


1日のセッションを通じて、自身はまだまだスキル不足だと実感しましたが、新しい情報を得ることができ、非常に勉強になりました。
次回も是非参加したいと思います。


Illustratorで作ったボタンをCSSで再現したい。


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

今回はIllustratorでデザインを作ったオブジェクトのグラデーションなどの設定をCSSで再現したい時に使える機能をご紹介します。
この機能のを使えばグラデーションが細かいボタンをの色をCSSで数分で再現できるのでコーディングがかなり楽になります。最高の機能なのでもうAdobeに足を向けて寝れません!


Illustratorのグラデーション機能を使い作成したボタンを用意しました。
色が多くて設定も少し複雑なのでCSSで再現するのが大変そうです。


今回は「CSSプロパティ」という機能を利用してグラデーションの色味などの設定を書き出していきます。

最初にCSSプロパティパネルをワークスペースに表示させます。
Illustratorメニューバーの「ウィンドウ」の「CSSプロパティ」をクリックします。
CSSプロパティパネルがワークスペースに表示されます。

グラデーションの設定をコピーしたいオブジェクトのオブジェクト名を設定します。
オブジェクト名がclass名になるので、class名で使用できる文字以外(全角英数字や日本語など)を入れると何も設定を変更していない場合エラーでCSSを生成してくれません…(書き出しオプションで「名称未設定オブジェクト用に CSS を生成」にチェックを入れると書き出してくれるようになるようです)

グラデーションの設定をコピーしたいオブジェクトを選択するとCSSプロパティパネルにCSSが表示されます。
選択スタイルをコピーボタンをクリックすると生成されたCSSが全てコピーされます。
これをcssファイルにペーストすると色、角丸の角度などが設定できました。

ボタンの高さや幅、ボタンの中のフォントサイズなどの調整は必要ですがIllustratorで作ったボタンをほぼそのまま再現できます。
CSSのグラデーションに苦手意識があったのでいつも時間がかかっていたのですが、この機能を知ってから数分でグラデーションを再現できるようになったので助かっています。


2020年1月27日月曜日

2020年オフィス狛の年賀状の制作秘話



新年あけましておめでとうございます!オフィス狛 デザイン部のSatoです。
今年もどうぞよろしくお願いいたします。

もう一月も終わってしまいそうですが、デザイン部の年明け初めての記事ですので今年の年賀状のおはなしをしようと思います。
(今まで全然紹介してこなかったのですが、2018年の年賀状から毎年私がイラストを描いています)


2020年の年賀状はこちら!

弊社サイトやSNSなどのアイコンなどで登場している狛犬ちゃん(社内ではたまに「こまちゃん」と呼ばれています)が今年の干支であるネズミの着ぐるみを着ている……という可愛い(自画自賛)テイストなイラストがメインな年賀状です。


最初は時事ネタを毎年取り入れているので元号発表のシーンのパロディっぽくしてみたり迷走していたのですが、
「Satoさん、ジョ●ョって知ってますか?
ジョ●ョ6部の主人公がスタ●ド攻撃のせいで小さくなってネズミの毛皮を着ぐるみのように被るシーンがあるんですよ……。
あれみたいにこまちゃんがネズミの着ぐるみを着ていたらすごく可愛いと思うんです」
というアドバイスを受けて、ファンシーグッズを出しているメーカーの年賀状を色々参考にしつつシンプルにネズミ着ぐるみ可愛いですよという直球なイラストを描きました。
(ここだけの話ですが、ジョ●ョは3部までしか読んでいないので6部の主人公がネズミの毛皮を被るシーンはいまだに見ていません

年賀状用に描いたイラストに辿り着くまでこんな感じのラフを描いたりしていました↓


メインのイラスト以外にも、ネズミのイラストに合わせてブラシツールで描いた四角を散らしてみたり手書きっぽい雰囲気のフォントを使ってみたりしてみました。
Happy New Year!の部分のフォントはフリーフォントのしろくまフォントを使用しています。
手書き風なのに幼くなりすぎないオシャレなフォントなので大好きです。


今年は来年の年賀状はどうしようかな?と考えたり普段描かないのでイラストを練習したり一年を過ごそうと思います!ガンバルゾ💪(´・_・`💪)