OmniAICreator/Qiita-1.07M huggingface dataset:
S3にアップロードされた画像にCache-Controlを付与する

## はじめに

某メディアをGoogleのPageSpeed Insightsで解析したところ、「最適化についての提案」という項目の中で「ブラウザのキャッシュを活用する」というのがありました。


>静的リソースの HTTP ヘッダー内で、有効期日や最大経過時間を設定すると、ブラウザがネットワークからではなくローカル ディスクから以前にダウンロードしたリソースを読み込むようになります。
>
>次のキャッシュ可能なリソースでブラウザのキャッシュを活用してください:

とのことなので今回はS3に置いたコンテンツ(今回は画像)にCache-Controlを付けました。

S3に保存されている画像にCache-Controlを付けるには幾つか方法がありますが僕の場合はS3に上げている画像の枚数をそれほど多くなかったので
愚直にAWSコンソールから設定しました。

## フォルダを選択してメタデータを変更する
やり方は簡単で、S3のWeb UIから対象のオブジェクトを選び右クリックから `Change metadata` を選択する。
<img width="629" alt="スクリーンショット 2018-08-21 10.00.15.png" src="https://qiita-image-store.s3.amazonaws.com/0/117824/d3f5fed5-527b-aa84-1033-a47e2b43d25d.png">



## Cache-Controlを追加する
>キャッシュ期間は少なくとも 1 週間、静的アセットや更新頻度の低いアセットについては最大で 1 年間とすることをおすすめします。
>https://developers.google.com/speed/docs/insights/LeverageBrowserCaching

Select a keyで `Cache-Control` を選択後、valueに適当な値を入れる。

キャッシュする時間が決まってない場合は上記の記述に従い、604800秒 = 7日を設定すれば良いかと思います。
<img width="647" alt="スクリーンショット 2018-08-21 10.11.41.png" src="https://qiita-image-store.s3.amazonaws.com/0/117824/457ae644-6725-c096-927c-c89ce9d37425.png">


## curlで確認
```
$ curl -I https://hoge.s3.amazonaws.com/uploads/article/ogp/2301/hoge.jpg
HTTP/1.1 200 OK
x-amz-id-2: wQvkuRebVq+nuTCkTMIygoWd8S5cccvvv2R7vv6vSGie0GMjwv+g10=
x-amz-request-id: 509711FF6290094F
Date: Tue, 21 Aug 2018 01:13:00 GMT
Last-Modified: Sat, 18 Aug 2018 07:23:22 GMT
ETag: "a9a811111111047b84d6af2a31cc"
Cache-Control: max-age=604800
Accept-Ranges: bytes
Content-Type: image/jpeg
Content-Length: 47370
Server: AmazonS3
```
オープンポート確認方法

##ncを使う場合(netcat)
```
10548が空いているかどうか確認
$ nc -v -z -w 1 127.0.0.1 10548
80-500のどれが空いているかどうか確認（タイムアウトは1秒）
$ nc -z -w 1 127.0.0.1 80-500
```
データ拡張ライブラリAugmentorの画像変換機能だけを利用する

データ拡張ライブラリとして有名な[Augmentor](https://github.com/mdbloice/Augmentor)、色々な変換がサポートされていて良いのですが、何故かデータ拡張した画像をファイル出力させたがるフシがあります。KerasやPyTorch向けのGeneratorもあるのですが、[ここのIssue](https://github.com/mdbloice/Augmentor/issues/119)にあるように、(入力画像, ラベル) のペアしか対応しておらず、(入力画像, 出力画像) のようにsegmentationのマスク画像のようなものを（公式のGeneratorでは）扱うことができません。

画像変換機能だけ提供してくれてれば良いのですが、丁度良さげな関数がないようです。一応 `p.torch_transform()` で1枚画像を変換する関数を取ってこれる（PyTorch専用というわけではない）のですが、(入力画像, マスク画像) といったペア画像を同じ変換で変換することができません。

ということで、`p.torch_transform()` を参考に画像変換を行う関数を作ってみます。Augmentor内部では画像はPIL.Imageである前提があるのでNumPy配列から変換していますが、最初からPIL.Imageを使う場合は変換は不要です。あと、本来はBGR->RGB変換もしないといけないのですが、色に関わる変換を使わなければ問題ないので、そのままにしています。ちなみに色（やコントラスト）に関する変換もマージ済みのこの[PR](https://github.com/mdbloice/Augmentor/pull/110)で実装されています。


```python
import random
from PIL import Image
import numpy as np
import cv2
import Augmentor


def get_transform_func():
    # 変換のパイプラインはここで定義する
    p = Augmentor.Pipeline()
    p.flip_left_right(probability=0.5)
    p.rotate(probability=1, max_left_rotation=5, max_right_rotation=5)
    p.zoom_random(probability=1, percentage_area=0.95)

    def transform_images(images):
        images = [Image.fromarray(image) for image in images]
        for operation in p.operations:
            r = round(random.uniform(0, 1), 1)
            if r <= operation.probability:
                images = operation.perform_operation(images)
        images = [np.array(image) for image in images]
        return images
    return transform_images


def main():
    target = np.zeros((256, 512, 3), dtype=np.uint8)
    transform_images = get_transform_func()

    while True:
        image1 = np.zeros((256, 256, 3), dtype=np.uint8)
        cv2.rectangle(image1, (100, 100), (200, 200), (255, 0, 0), -1)
        image2 = np.zeros((256, 256, 3), dtype=np.uint8)
        cv2.rectangle(image2, (100, 100), (200, 200), (255, 255, 255), -1)
        images = [image1, image2]
        images = transform_images(images)
        target[:, :256] = images[0]
        target[:, 256:] = images[1]

        cv2.imshow("transformed images", target)
        key = cv2.waitKey(-1)

        # "q": quit
        if key == 113:
            return 0


if __name__ == '__main__':
    main()
```

え？[imgaug](https://github.com/aleju/imgaug)？[albumentations](https://github.com/albu/albumentations)？
プロシージャルワークフローを料理に例えて考える

## はじめに
プロシージャルワークフローについて説明する文章がまとまったので思い切って投稿してみました。
専門学生の戯言なので何の説得力もありませんがご容赦ください。

## プロシージャルって何？
ゲーム業界で最近話題の技術分野です。
「プロシージャ」とは関係がないので注意してください。
直訳すると「手続き的な」という意味の単語ですが、一般的にはテクスチャやモデルやアニメーション等を自動生成する技術と解釈されています。
しかし、プロシージャル＝自動生成という訳ではなくて、その辺の説明をこれからしていこうと思います。

## プロシージャルワークフローを理解する
プロシージャルワークフローとはプロシージャルの技術を用いて効率的にコンテンツを制作することで、検索すると具体的な実例が複数出てきます。

しかし、具体例をいくら見てもプロシージャルワークフローへの理解は中々進みませんし、かといって抽象的に理解できるかと言うと自分の頭では文章化することはできませんでした。
そこで、ここからは一般的に共感できる**"料理"**に例えながら、プロシージャルワークフローの中身とメリットを考えていきたいと思います。

料理に例える理由は、**「Houdini」**というモデルやエフェクトをプロシージャルに作成するためのツールの中で、自分が設定した作業工程の結果をシーン上に反映させることを**"Cooking"**と呼称していたため、プロシージャルワークフローと料理に共通点があると思ってのことです。

## 料理 = 材料 + 調理器具 + レシピ + 調理

料理を完成させるために必要なものは何かを考えてみると、大きく**材料・調理器具・レシピ・調理**に分かれていると考えられます。
つまり、**レシピ通りに調理器具を使って材料を調理する**ことで料理は完成します。

これらは下記のようにゲーム制作の作業工程ともリンクしています。

- **料理**
　完成品（テクスチャ、モデル、アニメーション、エフェクト）
- **材料**
　データ（統計、地図情報、ランダム、レベルデザイン、ゲーム中の状況）
- **調理器具**
　アルゴリズム、ツール、フレームワーク、開発エンジン
- **レシピ**
　完成品を作るための手順
- **調理**
　実行、出力

こういった必要なものを分解するということはプロシージャルワークフローを考える際にとても重要になってきます。

## 野菜炒めを作ってみる
料理が出来上がるまでの流れを、野菜炒めを例に見ていきたいと思います。

### 必要なもの

- 材料
野菜（キャベツ、ニンジン、玉ねぎ、ピーマンなど）
油（サラダ油、ゴマ油など）
調味料（塩コショウ、しょうゆなど）

- 調理器具
包丁、まな板、フライパン、コンロ

- レシピ
①野菜を包丁で一口サイズに切る
②フライパンに油をしく
③コンロでフライパンを加熱
④野菜を入れて炒める
⑤調味料で味付け
⑥皿に盛り付ける


### 材料や調理器具にムラがある
ポイントは、材料と調理器具が完全に一致することはほとんどない点です。
野菜炒めにおいて、使用する野菜の種類は決まっていませんし、同じ種類の野菜でも大きさや味は均一ではありません。
また、包丁やフライパンについても各家庭でメーカーや材質が異なっています。
そのため、炒める時間や味付けの分量はある程度調整する必要が出てきます。

これがプロシージャルワークフローの**一つ目のメリット**で、材料となるデータをいじるだけで差分のあるレプリカを大量に生成することができるます。

これは３Ｄアセット（モデルやモーション）の作成でパンク寸前の制作現場では特に需要があり、オープンワールドゲームを最小限のコストで制作する際には必須とも言えるほどに活用できます。

また状況にフィットするように差分を調整できる点も役立ちます。
例えば足を上げるモーションで正面の段差の高さに応じて足を上げる高さや体の傾きを調整するように設定することができます。

### 家庭でも美味しい料理が作れる
もう一つのポイントが、材料と調理器具とレシピさえあれば簡単に料理が完成する点です。
たいていの材料や調理器具がスーパー等で購入できてレシピがネットから取得できる現代において、料理を作ることはそれほど難しくありません。
実際に調理するスキルがなくても、解決する代替手段はいくらでもあります（カット野菜を使う、時間や量を測る等）。

これが**二つ目のメリット**で、３Ｄアセットを作成する際に料理人（デザイナー）の負担を極端に減らすことができます。

これまでの開発現場では料理人（デザイナー）が注文を元に、材料（参考資料、ラフ）を仕入れて調理器具（ツール）を吟味してレシピを考案して調理して、ようやくオリジナルな完成品を生み出していました。

プロシージャルワークフローでは

- 材料はプランナーが用意
- 調理器具はプログラマーが用意
- レシピはデザイナーが用意
- 調理はツールやエンジンが実行

というように、必要なものを役職ごとに分担して揃えられます。
結果としてデザイナーの負担を軽減することができ、プランナーのアイデアをすぐに完成品に反映させることができます。

また、「必要なものがすべて揃えば実行するだけで完成品が出来上がる」という事象をもって、ここでようやく**"自動生成"**が成立します。
**「プロシージャルは自動生成」**という解釈に対してここにきてようやく理解ができました。

## まとめ
プロシージャルワークフローとは、差分のあるレプリカを効率的に作成する工程のことを指します。

もちろん一流の作品は一流のプロフェッショナルたちの創意工夫によって生み出されますが、すべてをオリジナルで作っていては労力に対して人も時間も圧倒的に足りません。
限りある人と時間の中で最大限のコンテンツを作成するために、プロシージャルワークフローの重要性はこれから増していくばかりだと思いました。
erlangのバージョンを上げたらphoenixが起動しなくなった

## バージョン情報

* elixir 1.5.1
* phoenix 1.3.0

## 内容

ある日、いつものようにphoenixサーバを起動しようとしたら下記のようなエラーになった。

```
$ mix phx.server
=SUPERVISOR REPORT==== 21-Aug-2018::09:37:27.995612 ===
    supervisor: {local,'Elixir.Logger.Supervisor'}
    errorContext: start_error
    reason: noproc
    offender: [{pid,undefined},
               {id,'Elixir.Logger.ErrorHandler'},
               {mfargs,
                   {'Elixir.Logger.Watcher',start_link,
                       [{error_logger,'Elixir.Logger.ErrorHandler',
                            {true,false,500}}]}},
               {restart_type,permanent},
               {shutdown,5000},
               {child_type,worker}]
=CRASH REPORT==== 21-Aug-2018::09:37:28.006225 ===
  crasher:
    initial call: application_master:init/4
    pid: <0.80.0>
    registered_name: []
    exception exit: {{shutdown,
                         {failed_to_start_child,'Elixir.Logger.ErrorHandler',
                             noproc}},
                     {'Elixir.Logger.App',start,[normal,[]]}}
      in function  application_master:init/4 (application_master.erl, line 138)
    ancestors: [<0.79.0>]
    message_queue_len: 1
    messages: [{'EXIT',<0.81.0>,normal}]
    links: [<0.79.0>,<0.42.0>]
    dictionary: []
    trap_exit: true
    status: running
    heap_size: 376
    stack_size: 27
    reductions: 193
  neighbours:

=INFO REPORT==== 21-Aug-2018::09:37:28.008886 ===
    application: logger
    exited: {{shutdown,
                 {failed_to_start_child,'Elixir.Logger.ErrorHandler',noproc}},
             {'Elixir.Logger.App',start,[normal,[]]}}
    type: temporary
=SUPERVISOR REPORT==== 21-Aug-2018::09:37:33.061893 ===
    supervisor: {local,'Elixir.Logger.Supervisor'}
    errorContext: start_error
    reason: noproc
    offender: [{pid,undefined},
               {id,'Elixir.Logger.ErrorHandler'},
               {mfargs,
```

先日何も考えずにerlangをアップデートしたのが怪しいと感じたため、次のコマンドでerlangのバージョンを戻してみたところ、解決した。

```
$ brew switch erlang 20.3.7
```

## 別解

別の方法として、elixirのtravis.ymlを見る限りは、elixir 1.7であればerlang21でも動くらしい。
https://github.com/elixir-lang/elixir/blob/v1.7/.travis.yml
Visual Studio Code設定

## settings

```json
{
  "workbench.startupEditor": "newUntitledFile",
  "editor.minimap.enabled": false,
  "eslint.autoFixOnSave": true,
  "eslint.validate": [
      "javascript",
      {
        "language": "typescript",
        "autoFix": true
      },
      {
        "language": "vue",
        "autoFix": true
      },
  ],
}
```

## extensions

* Japanese Language Pack for VS Code
* Vetur
* ESLint
* EditorConfig for VS Code
とりあえず Promise な XMLHttpRequest したい時に書くコード

- ブラウザの開発コンソールとかでとりあえず ajax なことしたい時に使う
- とりあえず get のみ。post は内容をちょっと変えればできる
- cors は何もしてないので実行したいページに行って実行してください（例の場合なら yahoo のページへ行って実行する）

```js
(() => {
    const getUrl = (url) => {
        return new Promise((resolve, reject) => {
            const req = new XMLHttpRequest();
            req.open('get', url, true);
            req.responseType = 'document';
            req.onload = () => {
                if (req.status === 200) {
                    resolve(req.response);
                } else {
                    reject(new Error(req.statusText));
                }
            };
            req.onerror = () => {
                reject(new Error(req.statusText));
            }
            req.send();
        });
    };

    getUrl('https://www.yahoo.co.jp')
    .then((response) => {
        console.log('success', response);
    })
    .catch((response) => {
        console.log('failed.', response);
    });
})();
```

## 参考

JavaScript Promiseの本
http://azu.github.io/promises-book/

XMLHttpRequestで取得したHTMLにDOMでアクセスしたい
https://qiita.com/yuki549/items/9f5ed466e3687cb7de8e
【Swift】UIViewの透過(alpha)はコードで書かなくてもstoryboardで設定できる。

##UIViewの透過(alpha)はコードで書かなくてもstoryboardで設定できる。

透過にする方法すごく探したのに(基礎的すぎて逆に・・・)見つけられなかったのでメモ。

<img width="1011" alt="スクリーンショット 2018-08-19 23.21.14.png" src="https://qiita-image-store.s3.amazonaws.com/0/186535/ed523c57-cb5a-3722-c7d4-9c7474340a69.png">

赤枠内のopacityのバーで~~View~~**色の透過**を設定できる。
※コメントでご指摘をいただいて、修正しました。↑

##追記(2018/09/01)

@lovee さんからコメントでいただいたのと同じ内容ですが、
念のため記事にも追記させていただきます。
反映が遅くなってしまいましたが、ご指摘ありがとうございました:bow_tone1:
<img width="992" alt="スクリーンショット 2018-09-01 23.45.53.png" src="https://qiita-image-store.s3.amazonaws.com/0/186535/f666839a-444c-1dff-855d-d1c433655775.png">

Opacityが色の透過で、alphaがViewの透過。

##補足： ```.alpha```
>このプロパティの値は、〜の範囲の浮動小数点数です。ここで、は完全に透明であり、完全に不透明であることを表します。このプロパティの値を変更すると、現在のビューのアルファ値のみが更新されます。ただし、そのアルファ値によって与えられる透明度は、そのサブビューを含むビューのすべてのコンテンツに影響します。たとえば、そのアルファ値がサブビューで親ビューに埋め込まれ、そのアルファ値もスクリーン上に表示されます。

引用(Google日本語訳済み)：https://developer.apple.com/documentation/uikit/uiview/1622417-alpha




ちなみに

<img width="304" alt="スクリーンショット 2018-09-01 23.48.58.png" src="https://qiita-image-store.s3.amazonaws.com/0/186535/ca2b0db8-5aad-d55b-500a-f55a676c2a69.png">

画面中央にぼやっとButtonが・・・・ちゃんと透けました(^o^)
Githubでラベル色を100種類作ってみた (ランダム生成)


## 理由

Githubのラベル色作成の仕様がいつの間にか変わっていた。
自分の好きな色が出てくるまで何度も更新ボタンを押すのがつらい。

![image](https://user-images.githubusercontent.com/13635059/44372250-ff42c280-a51d-11e8-814b-d06d4f52b819.png)

Webでポチポチと100回の単純作業。

だが長い人生を考えれば、きっと時間の節約になるはずだ。

今後、Githubで好きなラベル色が欲しくなったら、このレポジトリを見返せば良い。
カラーコードのサイトは山ほどあるけれど、Githubでの見え方を確認するにはGithubに作ってしまうのが手っ取り早いよね。


## 結果

おそらく色の種類は固定されておらず、見やすい色なら何種類でも出てくる様子。

![image](https://user-images.githubusercontent.com/13635059/44372210-d6223200-a51d-11e8-83a0-c8dc201b0439.png)

## サンプル用レポジトリ

https://github.com/YumaInaura/github-label-colors/labels

## Links

- [Gist](https://gist.github.com/YumaInaura/dc637cc22b0c5e400a9fe0b3e5bbcbee)








<!-- Update From Qiita API -->

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
VMware Workstation Player for Linuxで自動選択以外のNICを使ってブリッジ接続する

複数のNICを持つPC上のVMware Workstation Playerで、ブリッジ接続を行う場合、Windows版であれば「アダプタの設定」ダイアログボックスからブリッジ接続で使用するNICを選択できますが、Linux版ではそのダイアログボックスが無いっぽいです（もしかしたら、すごく深いところにあるかもしれません）。  
で、適当に購入したNUC7i7DNHEにVMware Workstation Player for Linuxをインストールしたところ、ブリッジ接続が無線LANを向いてしまったので、有線LANに切り替える方法を調べてみました。


# 有線LAN用の仮想ブリッジ作成

仮想ブリッジ（ここではvmnet2）を作成し、そこに有線LAN NICを設定します。
手打ちでもよいのですが、PCを起動するたびに実行する必要があるためシェルにしました。
ファイル名は何でもよいので、ここでは「set_vmnet2」とします。
ちなみに、vmnetXXは99まで作成できるらしいです。


```bash:set_vmnet2
#!/bin/sh

WIREDNIC='enp0s31f6'

# 仮想ブリッジ(vmnet2)作成
vmnet-bridge -n 2 -i ${WIREDNIC} -d /var/run/vmnet-bridge-2.pid -1vmnet2

# vmnet2用のキャラクタデバイスを作成
mknod -m 600 /dev/vmnet2 c 119 2

# 作成したvmnetを起動？
vmnet-netifup -d /var/run/vmnet-netifup-vmnet2.pid /dev/vmnet2 vmnet2

# 実NICをプロミスキャスモードに設定
ifconfig ${WIREDNIC} promisc
```


## set_vmnet2の自動実行

古き良きLinuxの場合はシェルの実行方法をrc.localに記述しておけば、OS起動時に自動実行してくれましたが、systemdになってからその辺の仕組みが変わったらしく、Ubuntu18.04にはrc.localそのものが無かったりします。  
  
一応、下記のようなファイル（ここではset_vmnet2.service）を作成し、systemdに登録しておくと、とりあえずOS起動時にvmnet2を作成してくれます（set_vmnet2.serviceの中身は、とりあえず動く程度のもので、正しく記述できているか自信がないです）。

```text:set_vmnet2.service
[Unit]
Description=Set VMNet2
ConditionFileIsExecutable=set_vmnet2のフルパス
After=vmware.service

[Service]
Type=forking
ExecStart=set_vmnet2のフルパス
TimeoutSec=0
RemainAfterExit=yes
SysVStartPriority=99

[Install]
WantedBy=multi-user.target
```

vmware.serviceの後で実行するようにしないと、うまく通信できないみたいです。

```shell:systemdへの登録
$ sudo systemctl enable set_vmnet2.serviceのフルパス
```



# VMXファイルの編集

VMXファイル（VMWareの仮想マシン構成ファイル）の「connectionType」と「vnet」を、下記のように編集します。
VMXファイルはただのテキストファイルなので、viとかで編集できます。

```text:VMXファイルの編集
ethetnet0.connectionType = "custom"
ethernet0.vnet = "vmnet2"
```



# 参考サイト

- [Creating and using of vmnet2 - vmnet7 and vmnet9 on Linux](https://communities.vmware.com/docs/DOC-2422)
- [view: [vmware] automatically re-create vmnet devices on startup - mkvmnet script](http://www.posteet.com/view/120)
- [/dev/vmnet* (vmware-player)](http://jlug.ml.users.narkive.com/fW4xIxHd/dev-vmnet-vmware-player)
AppletクラスとJAppletクラスの違いについて

仕事でAppletクラスとJAppletの違いについて調査したので、その内容をまとめたサイトのリンクを貼ってみる

・AppletとJAppletの違いについて
https://afternoon-garden-70542.herokuapp.com/diarydetails/show/details/?id=77

そのうち廃止になるAppletについて今更書いてもしょうがない気がするけれど、JavaでGUIのアプリを作るときはAWTを使うのは絶対やめたほうがいい、という教訓になるのかもしれないので
Postfix のメール転送の設定を確認する

## aliases の設定
```
vi /etc/aliases
newaliases
postfix reload
```
`newaliases` コマンドは `This mode of operation is implemented by running the postalias(1) command.` とマニュアルに記載されているので `postalias` コマンドを別途実行する必要はない。

また `Note: it may take a minute or so before an alias database update becomes visible. Use the "postfix reload" command to eliminate this delay.` とマニュアルに記載があるので `postfix reload` コマンドを実行すると即時反映される。

## aliases.db をダンプして確認
```
file /etc/aliases.db
```
`file` コマンドで `/etc/aliases.db` を確認すると `/etc/aliases.db: Berkeley DB (Hash, version 9, native byte-order)` と返ってくることから Berkeley DB ファイルだと分かる。

```
db_dump -p /etc/aliases.db
```
`db_dump` コマンドで中身を確認することができる。
行末に `\00` というコードが付加される。

```
strings /etc/aliases.db
```
`strings` コマンドで参照すると余計な `\00` は表示されないのでこちらの方が見やすいかもしれない。
情報処理技術者試験　プロジェクトマネージャ試験（PM）の対策と有用性について

# はじめに

IPAのプロジェクトマネージャ試験（以降PM）に合格した時の勉強方法や、その時点の私の実務経験値、保有スキルなどを書きます。

あと、資格の有用性について書いてみようと思います。
「情報処理技術者の資格は実務には役に立たない」と言う方もいます。確かに試験に合格することを目的として勉強している人もいると思いますが、「役に立たつかどうかは資格を持っている人しかわからない」というのが持論なので、資格保有者としての有用性について書いてみようと思います。

# 合格した時の実務経験値と保有スキル
- ソフトウェアの開発経験
15年前後、要件定義／設計／コーディング／テスト／運用まで一通り経験済み（使用言語については試験に影響しないため省略）
ちなみにPMBOKと違い、PMはソフトウェア開発のマネージメントを想定しているため、開発経験が無いと合格は難しいと思います。
<br>

- プロジェクトマネージャの実務経験
５案件ぐらい？（ただし、実務上のPM／PLの役割定義はあいまいだと思います。また、メンバーの中で一番キャリアが長いため、事実上のマネージャ？みたいな事もよくあると思いますので参考程度で）
<br>

- 保有資格
IPA応用情報技術者、セキュリティスペシャリスト、ベンダー系の開発言語資格２つほど


# 勉強方法
参考書を１冊＋過去問題の繰り返し
私は翔泳社のEXAMPRESSシリーズが合うので、良くお世話になっています。

参考書を読む　⇒　過去問を解く　⇒　間違えたところを参考書で復習するという勉強のサイクルです。
午後Ⅱは論述式で長文を書く必要がある為、慣れておく必要があります。２～３案件をモデルに10回ぐらい書きました。

試験は２回目で合格しましたが、勉強時間は１回目、２回目共に70時間程度です。

## 試験対策
- 午前Ⅰ試験の免除制度を利用する。
筆記試験なので１日の字を書いていると結構疲れます。午前Ⅰの免除制度を利用して負担を減らしましょう。（ITなのに試験はアナログですね･･･）
私の場合は応用情報を先に取得して、免除制度を利用してPMを受けました。
<br>

- 午後Ⅱ（論述式）対策として、事前に書くネタを用意しておく事が必要です。
ただし、実務経験をベースにしないとリアリティが出ないため、実務でのPL/PM経験が無いと厳しいと思います。
実務経験が無い場合は、シナリオ提供者が必要だと思いますが、現実的ではありません。
また、参考書に書いてあるとは思いますが、論文の中にはPM試験の知識体系に従った知識を幾つか盛り込む必要があります。
例えば
<br>
  - 若手の多いプロジェクトチーム　⇒　プロジェクトチームの育成を達成した。
  - リリース直前にユーザーから難しい変更要望を受けた　⇒　ステコミに対し調整を実施し、段階的リリースで対応した。
<br>

などを論文に盛り込む事や、過去の経験から「こうしておけば良かったなー」と反省したことを成功事例に変換して書きました。
成功事例に変換する理由ですが、解答に失敗したプロジェクトとして書いてはいけないようです。

その他の事は参考書で勉強すれば何とかなると思います。

# 有用性
当然のことながら、資格を持っていてマイナスになる事はほとんどありません。

プラスの方向に出た場面としては、実務でマネージメントをする際の基本的な考え方として使えます。
今までは上司、先輩のマネや過去案件の成果物を踏襲したマネージメントでしたが、勉強で得た知識をベースにしたマネージメント手法にする事で、管理の抜け漏れが減りました。
新しく学んだ手法も使ってみようという気持ちになりますが、メンバーが慣れていたり、報告を受ける側が理解しやすい手法を選択することが現実的です。


また、新規案件の面談時にPM資格保持を評価されることもありました。
PM/PLの能力は業務経歴書から判断し難い能力ですが、PM資格を持っていると、ユーザーコントロールやベンダーコントロール、プロジェクトチーム運営が出来そうだと評価されます。

試験勉強をしていて気付いたのは、コミュニケーションスキルを知識体系の一つとして扱っていた事です。
チームメンバーのモチベーションの上げかた、直接交渉するユーザーに問題がある場合のエスカレーション方法など、困ったとき／困る状況になる前の動きかたを有効に使っています。

その他、PDCAや報･連･相の重要性を改めて理解する良い機会になったと思いますので、私の結論としては｢役に立つ資格｣でした。

# まとめ
実務でPM／PL経験を積むことに加え、PM資格を取得することでマネージメント慣れします。
慣れて来るとPMのポジションでは無くてもリスクマネージメントやタイムマネージメントはやる癖が付きます。
また、メンバー負荷の平準化など、ついつい気になってしまいます。
どんなポジションでも、プロジェクトを俯瞰するようになったのだと思います。


ただ、私の担当する案件規模がそれほど大きくないため、メンバーの詳細な動きをイメージするマネージメント方法になっています。
なので、1000人月とか経験したことのないプロジェクトのPMは知識があっても出来ないと思います。
ほぼCSSだけで、LPでよくある上下左右からフェードインするやつを実装する


![image.png](https://qiita-image-store.s3.amazonaws.com/0/127520/a07d98cc-6c81-026d-36f5-dd7cb1cf202c.png)

# 背景
- LP実装のフロントエンドを担当
- Ruby on RailsのView内にてフロントエンド組み込み前提
- デザインカンプにアニーメーション、インタラクションの仕様は無かったが、昨今全く動かないLPの方が少ないのではと思った
- デザイナーにインタラクション考えてもらうのも確認フロー大変だし、Railsにプラグイン組み込む検証リスクなど諸々あり、1回あきらめた
- 諦めてからが試合開始
- 変更に強いCSSアニメーション主軸にスクロールインタラクション作れればと思った
- ゴニョゴニョしたら意外と出来た

![](https://i.gyazo.com/2e8ab79996cdb2edb5fec3cb0b90256e.gif)

## 実装内容

## CSSアニメーション実装
- `.anm_mod`デフォルト = 下から元来の位置に戻りつつフェードイン。速度ノーマル
- `&.left, &.right` 左右から元来の位置に戻りつつフェードイン
- `&.delay, &.fast` フェードイン速度遅め、早め
- 上記２点の設定で、フェードイン方向（３方向）とスピード（３段階）を調整出来ます
- 数値を変えれば任意の動きも可能ですので、自由に変更してみてください

```scss
.animation {
 ...
 .anm_mod {
  // 一度透明にしておく
  opacity: 0;
  // デフォルトでは下方向（から上に向かう）に設定
  transform: translate3d(0, 100%, 0);
  // デフォルトでは1秒に設定
  transition: all 1s ease;
  ...
  &.left {
   transform: translate3d(-100%, 0, 0);
  }
  &.right {
   transform: translate3d(100%, 0, 0);
  }
  &.delay {
   transition: all 2s ease;
  }
  &.fast {
   transition: all 0.8 ease;
  }
 }
}

.animation .anm_mod.active {
  // jsでスクロール値に来たら　activeクラスが付与されるので、透明を解除しながらUIパーツが元の位置に戻る作用をする
 opacity: 1;
 transform: translate3d(0, 0, 0);
}
```

### javaScript
- CSSのみで行きたかったですが、スクロール値の取得だけはCSSでは不可能であったため、スクロール値取得用途のみに絞りこみ、一部jQueryは使いました
- `.animationブロック`内の `.anm_modモジュール`を対象にします
- モジュールの位置と、スクロール値、画面の高さを取得します
- .anm_modモジュールがスクロールの位置まで来たら、`active`クラスを付与
- 再度TOPまで戻れば`active`を解除する仕様
- jsではスクロールによる`active`クラスの有無だけを作用させる
- フェードイアニメーション自体はCSSにさせる　 < これをjsで処理するプラグインは多いですが、CSSで代替可能ですので、今回ここが一番のポイントとなります。

```js
$(window).scroll(function() {
 　　// .animation 配下の　.anm_modを対象に見る
 $(".animation .anm_mod").each(function() {
  // スクロール中、各UIパーツ　.anm_modがブラウザ画面内に入ったら activeクラスが付与される
  const position = $(this).offset().top;
  const scroll = $(window).scrollTop();
  const windowHeight = $(window).height();
  if (scroll > position - windowHeight) {
   $(this).addClass("active");
  }
  // スクロール中、トップ画面付近まで戻ったら activeクラスを解除 ＝ 何度でもスクロールアニメが表現可能。一度しかアニメーションしたく無ければここを削除してください。
  if (scroll < 100) {
   $(this).removeClass("active");
  }
 });
});
```

## HTML実装例

```html
 <div class="animation">
  <div class="anm_mod left delay">
   anm_mod left delay
  </div>
  <div class="anm_mod right fast">
   anm_mod right fast
  </div>
 </div>
```


# 実装結果

## CodePen
<p data-height="565" data-theme-id="dark" data-slug-hash="mGbEbm" data-default-tab="css,result" data-user="agdg" data-pen-title="Scroll Fadein CSS Animation" class="codepen">See the Pen <a href="https://codepen.io/agdg/pen/mGbEbm/">Scroll Fadein CSS Animation</a> by Asagiri (<a href="https://codepen.io/agdg">@agdg</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>
【Swift】 Decimal型のアンダーフロー 、オーバーフロー

SwiftのDecimal型のアンダーフローに少し戸惑ったので書きました。

結論から書けば、
アンダーフロー → 突然大きい値になる
オーバーフロー → NaNになる

早速、アンダーフローを起こして見ましょう。

内部10進数計算のDecimal型の変数に0.02を入れて、10回掛け合わせるプログラムです。

```swift
import Foundation

var cur = Decimal(string:"0.02")!
cur *= cur
cur *= cur
cur *= cur
cur *= cur
cur *= cur
cur *= cur
cur *= cur
cur *= cur
cur *= cur
cur *= cur
```

結果は以下の通り。
<img width="1377" alt="swift underflow overflow" src="https://qiita-image-store.s3.amazonaws.com/0/138773/723458e2-eff2-6a5c-3a6a-74e250f842a4.png">

スクショが少し見にくいので結果を書き写すと以下の通り。
⓪0.02
①0.0004
②0.00000016
③0.0000000000000256
④0.00000000000000000000000000065536
⑤0.0000000000000000000000000000000000000000000000000000004294967296
⑥0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018446744073709551616
⑦340282366920938463463374607431768211460
⑧115792089237316195423570985008687907856000000000000000000000000000000000000000
⑨13407807929942597099574024998205846128100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
⑩NaN

0 < a < 1となる数を掛け合わせれば値はどんどん小さくなるはずですが、途中アンダーフローを起こしているので、1以上の大きい数になって（⑦）、さらにそれを掛け合わして今度はオーバフローを起こして最終的にNaNになってますね（⑩）。

https://qiita.com/Hiroki_Kawakami/items/1867a1ff91fee5b90d61
上のURLを参考にするとDecimal型でアンダーフローの恐れがある場合は、掛け算の時に両辺の絶対値が1未満の時にもし答えの絶対値が1以上になるときは、チェックをした方が良さそうですね。
JavaおじさんがPythonを使えるようになるまでの全記録（Djangoのクエリ式としてのF() - 後編）

#はじめに
そろそろタイトル変えてもいい気がする。
まあ単なる備忘録なのだけど、何書いてるかわかるタイトルにするべきよねー。

というわけでナンバリングやめてみました。
なお、Djangoのクエリ式の前編は[こっち](https://qiita.com/kjnghr/items/841db95e0f4febda953f)ね。F()についての説明と排他制御に関して記載してます。

#Fの使い方あれこれ
##F()の割り当てはモデルの保存後も続く
モデルフィールドに割り当てられたF（）オブジェクトはモデルインスタンスの保存後も保持され、各save（）に適用されます。 例えば以下のコードを考えます：

```
reporter = Reporters.objects.get(name='Tintin')
reporter.stories_filed = F('stories_filed') + 1
reporter.save()

reporter.name = 'Tintin Jr.'
reporter.save()
```

stories_filed はこの場合2回更新されます。もし初期値が1なら最終的な値は3になります。

...さて、これなんでこんなことになるのかね？
仮説としては``reporter.stories_filed = F('stories_filed') + 1``の行で``reporter.stories_filed``のフィールドに更新用のSQLがセットされるから、ってことになるのかしら。
これはちょっと後で深掘りしてみよう。

##フィルター内でF()を使う
F（）はQuerySetフィルタでも非常に便利です。
Filterは、Pythonの値ではなくフィールドの値に基づいてオブジェクトのセットをフィルタリングすることを可能にします。
これは、クエリでF（）式を使用することで文書化されます。

##F() を annotation と一緒に使う
ここ、見出しだけ日本語なんだよなー。

以下のように異なるフィールドを算術演算と組み合わせることで、F（）を使用してモデル上に動的フィールドを作成することができます。

```
company = Company.objects.annotate(
    chairs_needed=F('num_employees') - F('num_chairs'))
```

（訳注：これはCompanyオブジェクトのそれぞれについてannotateでchairs_neededを導出属性として計算する。具体的には従業員数（num_employees)から椅子の数(num_chairs)を引いたもの）

結合しているフィールドの型が異なる場合は、返されるフィールドの種類をDjangoに伝える必要があります。 F（）はoutput_fieldを直接サポートしていないので、ExpressionWrapperで式をラップする必要があります：

```
from django.db.models import DateTimeField, ExpressionWrapper, F

Ticket.objects.annotate(
    expires=ExpressionWrapper(
        F('active_at') + F('duration'), output_field=DateTimeField()))
```

（訳注：この例だとactive_atがDateTimeField型でdurationがDuration型と想定しているので、この2つの列の演算を行う場合はExpressionWrapperを使う必要があり、output_fieldが何型になるのかを指定する必要がある）

外部キーなどのリレーショナルフィールドを参照する場合、F（）はモデルインスタンスではなくプライマリキー値を返します。

```
>> car = Company.objects.annotate(built_by=F('manufacturer'))[0]
>> car.manufacturer
<Manufacturer: Toyota>
>> car.built_by
3
```

（訳注：この例だとCompanyテーブルの最初の行([0])のmanufacturer列に含まれる外部キーをもとにbuilt_byを設定している。そのため、モデルオブジェクトとしてcar.manufacturerは参照先のオブジェクトが表示されるが、導出属性のbuilt_byはpkの値が入ってくる）

##null値を含んだソートにF()を使用する
フィールドのヌル値の順序を制御するには、F（）とExpression.asc（）またはdesc（）のnulls_firstまたはnulls_lastキーワード引数を使用します。 デフォルトでは、順序はデータベースによって異なります。
たとえば、連絡を受けた企業の連絡を受けていない企業（last_contactedがnull）を分類するにはこう書きます：

```
from django.db.models import F
Company.object.order_by(F('last_contacted').desc(nulls_last=True))
```

（訳注：ここではCompanyテーブルのlast_contacted列がnullである行はソート時に最後に持っていくことを設定している。前回のソースを見るとわかるけどFにascとdescが定義されているのでこんな使い方になる）

というわけでF()単独のトピックはこんなとこかなー。
データベースの関数を使用する場合のFunc()とかGROUP BY句を使うためのAggregate()とかサブクエリを扱うためのSubQueryとかいろいろあるのでそれぞれちゃんとコードとして作らないといかんねー。

まあでも今夜はこの辺で。
エラーがでて実行できません...わかる方教えてください！あと、コード長くて申し訳ございません！

require "date"
class BookInfo
    def initialize(title,author,page,publish_date)
        @title = title
        @author = author
        @page = page
        @publish_date = publish_date
    end
    attr_accessor :title, :author, :page, :publish_date
    def to_s
    "#{title},#{author},#{page},#{publish_date}"
    end
    def toFormattedString(sep = "\n")
        "書籍名:#{@title}#{sep}著者名:#{@author}#{sep}ページ数:#{@page}ページ#{sep}
        発刊日:#{@publish_date}#{sep}"
    end
end

 class BookInfoManager
     def initialize
         @book_infos = {}
     end
     def setUp
         @book_infos["Yamada2005"]  = BookInfo.new(
             "モバイルボヘミアン",
             "加味真",
             618,
             Date.new(2018,6,18)
             )
         @book_infos["ooba2006"] = BookInfo.new(
             "読書",
             "加味真",
             619,
             Date.new(2017,6,18)
         )
     end
     def addBookInfo
         book_info = BookInfo.new("","",0,Date.new)
         print "\n"
         print "キー:"
         key = gets.chomp
         print "書籍名:"
         book_info.title = gets.chomp
         print "著者名:"
         book_info.author = gets.chomp
         print "ページ数:"
         book_info.page = gets.chomp.to_i
         print "発刊年:"
         year = gets.chomp.to_i
         print "発刊月:"
         month = gets.chomp.to_i
         print "発刊日:"
         day = gets.chomp.to_i
         boook_info.publish_date = Date.new(yaer,month,day)
     end
     def listAllBookInfos
         puts "\n---------------------"
         @book_infos.each {
             |key,value|
             print info.toFormattedString
         puts "\n-------------------------"
         }
     end
     def run
         while true do
         print "
         1.蔵書データの登録
         2.蔵書データの表示
         9.終了
        　番号を選んでください(1,2,9):"
        　
        　num = gets.chomp
        　case num
        　when "1"
        　    addBookInfo
        　when "2" 
        　    listAllBookInfos
        　when "9" 
        　  
        　end
          end
     end
end
book_info_manager = BookInfoManager.new
book_info_manager.setUp
book_info_manager.run
php-master-changes 2018-08-20

# 2018-08-20
## bukka: Fix bug [#76705](https://bugs.php.net/bug.php?id=76705) (unusable ssl => peer_fingerprint in stream_context_create())
- https://github.com/php/php-src/commit/4c542e6c13ca0d1b3944efee715a4dadb4794c7c
- ext/openssl のバグ修正
- GET_VER_OPT() が実は変数 val を書き換えるマクロで、値を利用するまでに再度書き換えられてもよいよう、書き換えられる前の値を保存するよう修正してある

## carusogabriel: Make array parsing parameters error messages consistency with ZPP failure
- https://github.com/php/php-src/commit/efbf846fd256f0cd8a745d98182cb1f95d1e57f8
- 配列関数へ配列以外を渡した際のエラーメッセージを、通常の型エラーと同様の書式で実際にどの型の値が渡されたかを添えるよう修正

## sodabrew: [ci skip] Correct minor typo (GC_GLAGS to GC_FLAGS)
- https://github.com/php/php-src/commit/1621f1739d80b481348102e82360d0c24f4c5e0e
- UPGRADING.INTERNALS の typo を修正

## dstogov: Avoid hash lookups in BIND_STATIC and BIND_LEXICAL opcode handlers.
- https://github.com/php/php-src/commit/b8828926f2f6bc9d109960c2d4e2d399f7c0dc5c
- BIND_STATIC と BIND_LEXICAL のオペコードでハッシュのルックアップを削減
- extended_value にハッシュテーブル bucket 内の当該 zval へのオフセットを詰めている
    - オフセットが奇数になることはないので ZEND_BIND_REF のフラグとあわせてパックして詰められる、という奴かな
Addressable Assets Systemで AsObservable

前に似たような奴を描いたけど今回も同様の拡張
ただの変換だけど備忘録的に残しとく

```csharp:AddressableAssetAsObservable.cs

   public static class AddressableAssetAsObservable
    {
        public static IObservable<IAsyncOperation<TObject>> AsObservable<TObject>(this IAsyncOperation<TObject> addressableAsync)
        {
            return Observable.FromEvent<IAsyncOperation<TObject>>(
                h => addressableAsync.Completed += h,
                h => addressableAsync.Completed -= h);
        }
        
    }
```

こうすることで


```csharp:DataLoader.cs

public class DataLoader
{
    public async UniTask<SettingData> Load()
    {
        var textAsset = await Addressables.LoadAsset<TextAsset>("honyararaData")
            .AsObservable()
            .First();

        var settingData = JsonUtility.FromJson<SettingData>(textAsset.Result.text);

        return settingData;
    }
}

```

とか書ける。


```csharp:MogemogeGameObject.cs

public class csharp:MogemogeGameObject:MonoBehaviour
{
    void Start()
    {
        Addressables.LoadAsset<Texture2D>("icon")
            .AsObservable()
            .Subscribe(texture => icon.material.SetTexture("_MainTex", texture))
            .AddTo(this);
    }
}

```

みたいに書き慣れた感じで書ける。
nilを含んだ配列のソート


ソートしようとしている配列にnilが含まれているとエラーとなる。

```irb
irb(main):003:0> [1,2,nil,4,5].sort
Traceback (most recent call last):
        3: from /Users/colorbox/.rbenv/versions/2.5.0/bin/irb:11:in `<main>'
        2: from (irb):3
        1: from (irb):3:in `sort'
ArgumentError (comparison of Integer with nil failed)
```


配列内の値にもよるが`to_i`や`to_s`を利用することで安全にソート可能。

```irb
irb(main):004:0> [1,2,nil,4,5].sort { |a,b| a.to_s <=> b.to_s }
=> [nil, 1, 2, 4, 5]
```

もしくは`compact`などを利用しても良い

```irb
irb(main):009:0> [1,2,nil,4,5].compact.sort
=> [1, 2, 4, 5]
```
docker-composeでLAMP環境構築中にハマったメモ

LAMP環境をXAMPPからDockerに移す初心者がはまりがちなポイントをまとめました。
## docker-compose.ymlやDockerfileを設置して`docker-compose up`したけど、思い通りに動かない...
### そもそも`docker-compose build`でビルドしたか？できているか？
 - `docker ps -a`で停止中コンテナを確認。
 - すべてのコンテナ名が一覧にある：ビルドはできているけど、起動に失敗している　→2の「ない」へ
 - 一部またはすべてが一覧にない：念のため`docker-compose down`してから、もう一度`docker-compose build`を実行してログを見る。
 - 最終行のコマンドはdocker-compose.ymlのserverに書いた最後のセクションのDockerfileの内容まで走っているか？

### コンテナは起動しているか？
#### `docker ps`で起動中コンテナを確認
 - ある：起動している
 - ない：コンテナが起動していないので、1に戻ってupまたはbuildとupの再試行（だめなら-dつけずに画面でエラーをモニタする）

確認ポイント：`docker exec -it <コンテナID>`で中を見てみる
volumes:に書いたディレクトリ指定、接続IP/ホスト名/ポート番号、など

#### 今コンテナがどういう状態かわからない...
安定して動くまでは`docker-compose up -d`ではなく`docker-compose up`を使うこと。(写経の時に-dオプションがついてることがありがち)
コンテナ名で始まるログが非同期に流れてくるので、停止したり、エラーが発生していないものがないかを全体的に確認する。
`<コンテナ名> exited with code 1`などの終了ステータスが出ていることもある。
参考：[終了ステータス | UNIX &amp; Linux コマンド・シェルスクリプト リファレンス](https://shellscript.sunone.me/exit_status.html)

## 公式MySQLイメージ編
※執筆時はイメージにmysql:5.7を指定して、5.7.23が取得されています。
### ユーザー作成エラー
> ERROR 1396 (HY000): Operation CREATE USER failed for 'root'@'localhost'

例えばdocker-compose.ymlで

```docker-compose.yml
services:
　...
  mysql:
    environment:
      ...
      MYSQL_USER: root
```
のように、ユーザー名をrootで指定していると出たり出なかったりする。（出ないこともあった

## php:7.2-apache-stretch イメージ編
php.iniをvolumes:セクションで上書きしているときに、手元のphp.iniに書いてあるextension指定がコンテナでは使用できない状態でエラーが表示されていることがあるが、動作はしている。(その拡張を使わなければ動いているので無視しても…
拡張を使おうと思ったらDockerfileのRUNコマンドを使ってOSのパッケージインストールとあわせて、`docker-php-ext-install`を使う。

(以下随時追記...)

## リンク
dockerでコンテナが立ち上がらないときやってみること
https://qiita.com/mom0tomo/items/35dfacb628df1bd3651e
GitHubで過去１年分毎日草を生やすワンライナー

# 動作確認環境
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin17)

# ワンライナー

適当なリポジトリで以下を実行すると過去365日に1日ずつ空コミットのログを作成します。

```shell
for i in {1..365} ; do d=`LANG=C date -v-${i}d "+%a %b %d %H:%M:%S %Y -0900"`; git commit --allow-empty -m "YEAH" --date="$d"; done
```

pushすると365日毎日コミットした（してない）コミットログがプッシュされ、GitHubにたくさん草が生えます。

<img width="750" alt="スクリーンショット 2018-08-21 1.17.45.png" src="https://qiita-image-store.s3.amazonaws.com/0/220908/58fe3b07-ea21-6ada-f0e8-c1e25cee3569.png">

こちらを参考にさせていただきました。
http://neos21.hatenablog.com/entry/2016/11/20/012724
PythonでSSHトンネリングしてAmazon Aurora MySQLに繋ぐ

# はじめに
業務でsshを使って踏み台のAmazon EC2サーバーに繋いでそこからAmazon Aurora MySQLに繋いでSQLを実行するということをやっているのですが、いちいちコマンドを打つのが面倒なので、Pythonでその辺の処理を自動化したいと思います。

# Requirements
```
mysql-connector-python
sshtunnel
```
以上のモジュールをpipを使ってPyPIから取ってきます。

```
$ pip install mysql-connector-python sshtunnel
```

# Example code
```py
import mysql.connector
from sshtunnel import SSHTunnelForwarder

SSH_BASTION_ADDRESS = '**.**.***.**'  # ここに踏み台のEC2サーバーのIPアドレスを入れる
SSH_PORT = 22
SSH_USER = 'ec2-user'
SSH_PKEY_PATH = os.path.expanduser('~/key.pem')  # ここにsshで繋ぐときのキーファイルを指定する
MYSQL_HOST = 'foo.bar.ap-northeast-1.rds.amazonaws.com'  # ここにAmazon Aurora MySQLのアドレスを書く
MYSQL_PORT = 3306
MYSQL_USER = 'root'
MYSQL_PASS = 'foo'
MYSQL_DB = 'db'


if __name__ == '__main__':
    with SSHTunnelForwarder(
        (SSH_BASTION_ADDRESS, SSH_PORT),
        ssh_pkey=SSH_PKEY_PATH,
        ssh_username=SSH_USER,
        remote_bind_address=(MYSQL_HOST, MYSQL_PORT),
        local_bind_address=('0.0.0.0', MYSQL_PORT),
    ):
        connection = mysql.connector.connect(
            host='127.0.0.1',
            port=MYSQL_PORT,
            user=MYSQL_USER,
            passwd=MYSQL_PASS,
            db=MYSQL_DB,
            charset='utf8'
        )
        pass  # 何かクエリを叩いたりする
        connection.close()
```
sedでダブルクォーテーションの中にある文字列を抽出する 

# 概要
1. sedでダブルクォーテーションの中にある文字列を抽出する
2. 1.を基に以下を詳細におさらいする
    * 2-1. sedコマンド
    * 2-2. 正規表現

# 1. sedでダブルクォーテーションの中にある文字列を抽出する

記事がありましたので引用します。
コマンドや正規表現について詳細には書かれておりませんでしたので、2.で確認していきます。

- (引用)[sedやgrepなどを使ってLinux/UNIXでダブルクォーテーション・シングルクォーテーションに囲まれた文字列を抽出する](https://orebibou.com/2016/07/sed%E3%82%84grep%E3%81%AA%E3%81%A9%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6linuxunix%E3%81%A7%E3%83%80%E3%83%96%E3%83%AB%E3%82%AF%E3%82%A9%E3%83%BC%E3%83%86%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%83%BB/)

>sedでダブルクォーテーションやシングルクォーテーションに囲まれた文字列を抽出する場合は、以下のようにする。

````
sed 's/^.*"\(.*\)".*$/\1/' # ダブルクォーテーションの場合
sed "s/^.*'\(.*\)'.*$/\1/" # シングルクォーテーションの場合
````

````
blacknon@BS-PUB-UBUNTU-01:~$ echo 'aaa="aaa"' | sed 's/^.*"\(.*\)".*$/\1/'
aaa
blacknon@BS-PUB-UBUNTU-01:~$ echo "bbb='bbb'" | sed "s/^.*'\(.*\)'.*$/\1/"
bbb
```` 

# 2-1. sedコマンドを確認する
```
sed 's/hoge/piyo/g foo.txt'         #foo.txt中の全てのhogeをpiyoに置換
cat foo.txt | sed 's/hoge/piyo/g'   #foo.txt中の全てのhogeをpiyoに置換
````
`sed`は文字列を置換するコマンドです。
`s/置換前/置換後/`と書くことで置換前の文字列を置換後の文字列に変更できるようになります。
また`g`をつけることで、置換前の文字列全てを置換できます。(以降は扱いません。)

# 2-2. 正規表現を確認する

````
sed 's/^.*"\(.*\)".*$/\1/'
````

`^.*"\(.*\)".*$`を`\1`に置換しています。
`^.*"\(.*\)".*$`を確認してみます。

- `^`:文字列の先頭
- `.*`:任意の文字(文字列)
    - `.`:任意の1文字
    - `*`:0回以上の繰り返し
- `"` `"`:ダブルクォーテーション
- `\(` `\)`:文字列の指定　抽出したい文字列(今回はダブルクォーテーション)の内側に記載
- `$`:文字列の末尾

「文字列の先頭`^`から末尾`$`まで」、つまり「文字列全体」を置換の対象にしており、
`"` `"`の内側の文字列を`\(` `\)`で括っています。
これにより、`\(` `\)`の内側の文字列を`\1`という変数に抽出できます。
例えば、`\(hoge\)foo\(bar\)`を考えてみると、

- `\1`=`hoge`
- `\2`=`bar`

になります。 
以上から、`\(` `\)`内の文字列が`\1`に抽出し、文字列全体を抽出した文字列に置換しています。

確認ですが、上記方法での置換例を挙げると、

- `aaa="bbb"` -> `bbb`
- `hoge"foo"hoge` -> `foo` 

になりますね。

以上です。読んでいただき、ありがとうございました。

#参考
- [sedやgrepなどを使ってLinux/UNIXでダブルクォーテーション・シングルクォーテーションに囲まれた文字列を抽出する](https://orebibou.com/2016/07/sed%E3%82%84grep%E3%81%AA%E3%81%A9%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6linuxunix%E3%81%A7%E3%83%80%E3%83%96%E3%83%AB%E3%82%AF%E3%82%A9%E3%83%BC%E3%83%86%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%83%BB/)
- [忘れっぽい人のための正規表現チートシート](https://qiita.com/tossh/items/635aea9a529b9deb3038)
- [正規表現メモ](http://www.kt.rim.or.jp/~kbk/regex/regex.html#SED)
UnityのIKで地面の形に合わせて足がつくようにした

# 環境
Unity2017.3.1p4
Windows10

#リポジトリ
下記リンク
Asset/Scripts/FootIK.cs
[リポジトリ公開してます](https://github.com/JohnnyBoss1206/3DUtility)
# How to

1. Animatorの中からIKを有効にさせたいレイヤーの歯車をクリック
2. 出てきたWindowのIKPassをONに
3. Scene上にある対象のGameObjectを選択し、Animatorがアタッチされているのと同じGameObjectにFootIKをアタッチ
4. Inspectorから地面のレイヤーネームを設定したら完了

![ikpass](https://cl.ly/0j0G0I1j240t/IKPass.jpg)

# 結果
左のUnityChanが通常状態、右がFootIKが有効状態

![footik](https://cl.ly/1R3S3Q06463P/FootIK.jpg)


#ソース
```c#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FootIK : MonoBehaviour {
	[SerializeField]
	private Vector3 offset = new Vector3(0,0.1f,0);
	[SerializeField]
	private float rayRange = 1f;
	[SerializeField]
	private string fieldLayerName = "Field";

	private Animator animator;
	
	private Transform _transform;
	public new Transform transform {
		get
		{
			if (_transform == null)
			{
				_transform = gameObject.transform;
			}
			return _transform;
		}
	}


	void Start()
	{
		animator = GetComponent<Animator>();
	}

	void OnAnimatorIK()
	{
		//右足
		var ray = new Ray(animator.GetIKPosition(AvatarIKGoal.RightFoot), -transform.up);
		RaycastHit hit;
		if (Physics.Raycast(ray, out hit, rayRange, LayerMask.GetMask(fieldLayerName)))
		{
			Quaternion rightRotation = Quaternion.FromToRotation(transform.up, hit.normal) * transform.rotation;
			//weightはとりあえず1で固定しておく（0f:元のアニメーション,1f:IKを完全に反映）
			animator.SetIKPositionWeight(AvatarIKGoal.RightFoot, 1);
			animator.SetIKRotationWeight(AvatarIKGoal.RightFoot, 1);
			animator.SetIKPosition(AvatarIKGoal.RightFoot, hit.point + offset);
			animator.SetIKRotation(AvatarIKGoal.RightFoot, rightRotation);
		}

		//左足
		ray = new Ray(animator.GetIKPosition(AvatarIKGoal.LeftFoot), -transform.up);
		if (Physics.Raycast(ray, out hit, rayRange, LayerMask.GetMask(fieldLayerName)))
		{
			Quaternion leftRotaion = Quaternion.FromToRotation(transform.up, hit.normal) * transform.rotation;
			
			animator.SetIKPositionWeight(AvatarIKGoal.LeftFoot, 1);
			animator.SetIKRotationWeight(AvatarIKGoal.LeftFoot, 1);
			animator.SetIKPosition(AvatarIKGoal.LeftFoot, hit.point + offset);
			animator.SetIKRotation(AvatarIKGoal.LeftFoot, leftRotaion);
		}
	}
}



```

# もし動かない場合は
3DモデルのFBXを選択し、RigタブのConfigureをクリック

![configure](https://cl.ly/3b2j0u2Z233I/configure)

Mappingが正常に行われているか確認したほうがよい
![mapping](https://cl.ly/2f1F1y1K3o2L/mapping)
GraphQLの性能で気にすべき点のメモ

# クライアント側で気にすべき点

## Dataloaderを使う

自分の環境では一番有効だった手段。
`Dataloader`導入には以下の手順を踏む。

- batching用の関数(keyのリストを受け取ってvalueのリストを返す)を定義してあげる。

```typescript
// この例ではkeyはaddressというstring, valueはany (LocationというGraphQL型が入っている)
	type BatchLocation = (addresses: string[]) => Promise<any[]>

	const batchLocations: BatchLocation = async addresses => {
		const locations = await locationBinding.query.locations({ where: {address_in: addresses}}) //ここは適宜変えてください。
		const locationMap: { [key: string]: any } = {}
		// return locations.
		locations.forEach(element => {
			locationMap[element.address] = element;
		});
		return addresses.map(address => locationMap[address])
	}
	const batchLoader = new DataLoader<string, any>(batchLocations);
```

- resolverの中で上記batch用関数を呼ぶ

```typescript
location: {
	resolve: async (parent: any, args: any, context: any, info: any) => {
		let location = await batchLoader.load(<string>parent.address) //ここ
		return location
	}
}
```

参考動画。
https://www.youtube.com/watch?v=_FQ1ZEWIn2s


## apollo-linkは何を使う？

こんなに種類が。。。

- 生のHttpLink(link1)
- 生のHttpLinkで重複排除だけしてみる(link2)
- ちょっと凝ってBatchHttpLinkを使ってさらに重複排除してみる(link3)
- HTTPLinkDataloaderを使う(link4)

```typescript
import { HttpLink } from 'apollo-link-http'
import { BatchHttpLink } from 'apollo-link-batch-http'
import { HTTPLinkDataloader } from 'http-link-dataloader' // not applicable
import { DedupLink } from 'apollo-link-dedup'
import fetch from 'node-fetch'	

const link1 = new HttpLink({uri, fetch})
const link2 = new DedupLink().concat(new HttpLink({uri, fetch}))
const link3 = new DedupLink().concat(new BatchHttpLink({uri, fetch}))
const link4 = new  HTTPLinkDataloader({uri})
```

基本的なふるまいの傾向です。

- BatchHttpLinkは、HttpLinkに比べ、**レイテンシが劣化、スループットは向上**
- DedupLinkは、重複が多そうなときに効果ありそう
- HTTPLinkDataloaderは効果がよく分からない（というかまともに動かない。。。）

ほかにもこんな手が。

- apollo-link-stateを使う

### 参考

https://www.youtube.com/watch?v=_FQ1ZEWIn2s
https://github.com/facebook/dataloader

https://medium.com/slite/avoiding-n-1-requests-in-graphql-including-within-subscriptions-f9d7867a257d
https://medium.com/@gajus/using-dataloader-to-batch-requests-c345f4b23433

# サーバ側で気にすべき点

- キャッシュを使う
Go言語　Macにインストール

# はじめに
Go言語が一番年収が高いということでお勉強したことをまとめていきます。
その方が頭に入るし。（たぶん）
ただの備忘録になるとは思いますがあしからず。。。

#インストールの前に
Playgroundがあるみたいなので、簡単なやつはここ[Go Playground](https://play.golang.org)で実行できるみたい。

#インストール
Macの場合はHomebrewでインストールできる。

```
brew install go
```

#ビルド＆実行
サンプルコードを作成します。

```hello.go
package main

import "fmt"

func main() {
  fmt.Println("Hello World")
}
```

ターミナルを開いてビルド＆実行していきます。
コンパイル＆ビルドするときはgo buildコマンドを実行します。

```
$ go build hello.go
```

するとhelloファイルができているはず。

```
$ ls
hello           hello.go
```

ではhelloを実行してみましょう。

```
$ ./hello
Hello World
```

Hello Worldが出力されてます！


なんか即時ビルド＆実行できるらしく、その場合はgo runコマンドを実行。

```
$ go run hello.go
Hello World
```

この場合はコンパイルしたファイルは生成されないみたいです。

インストール編はここまで。
ではでは。

###参考
http://cuto.unirita.co.jp/gostudy/
windows server2016 記憶域を試す

windows機能の記憶域プールを作ったり消したりいぢめたりしてみる準備を行います。

# ざっくり環境
- Hyper-V環境(ホストはwindows10)
- windows server2016

win10上のHyper-Vにてwindowsserver2016を動作させてます。

#準備
仮想HDDを適当な数作成し登録する。
![01.PNG](https://qiita-image-store.s3.amazonaws.com/0/282669/53bef0f2-743e-b86b-0d2e-d45686d82e74.png)

サーバー上だとこんな感じ。1から5が今回追加した仮想HDD
今回はすでにGPTでフォーマットしてます。
![02.PNG](https://qiita-image-store.s3.amazonaws.com/0/282669/1602da1d-ec7f-3a17-9a5f-bdf746ab6d9a.png)

じゅんび終わり。

# 記憶域プールを作る

サーバーマネージャから「ファイルサービスと記憶域サービス」をクリック
![03.PNG](https://qiita-image-store.s3.amazonaws.com/0/282669/dda905e9-5dd3-7bdf-c909-eab9b815ca2c.png)

記憶域プールをクリック
![04.PNG](https://qiita-image-store.s3.amazonaws.com/0/282669/557f9fe2-5e50-f922-fd47-fba3de07aaea.png)

タスク→記憶域プールの新規作成をクリック
![05.PNG](https://qiita-image-store.s3.amazonaws.com/0/282669/45c809e4-7fd6-7944-81b7-3a7cb7822241.png)

ウィザードなので適当に進めます。
物理ディスクはすべて選択。
![06.PNG](https://qiita-image-store.s3.amazonaws.com/0/282669/0a9c7824-3f93-e7f0-847a-6b2fbb742dde.png)

作成終わり。
せっかくなので下のチェックボックスにチェックを入れる。
![07.PNG](https://qiita-image-store.s3.amazonaws.com/0/282669/a8e54fab-f4c7-5b45-fa18-8027892c1260.png)

#仮想ディスクを作る。
さっきの続きです。
![08.PNG](https://qiita-image-store.s3.amazonaws.com/0/282669/a1f3d003-90fb-34fd-cdcd-1aefa4cf2fe3.png)
ウィザード形式なので適当に進めます。
記憶域のレイアウトは今回はミラーを選択。
![09.PNG](https://qiita-image-store.s3.amazonaws.com/0/282669/2192bf0b-4963-0d3a-0595-054be3ea6c05.png)

回復性は3wayミラー
![10.PNG](https://qiita-image-store.s3.amazonaws.com/0/282669/761ca69d-7e6d-08de-ce46-04e8c0a23c35.png)

とりあえず最大サイズで設定。
![11.PNG](https://qiita-image-store.s3.amazonaws.com/0/282669/e5064e89-4ba3-5da5-908c-efb0831c63d2.png)

仮想ディスク完成
せっかくなので下のチェックボックスにチェックを入れる
![12.PNG](https://qiita-image-store.s3.amazonaws.com/0/282669/1b57c0c9-1837-b2b0-e8ad-7a969bea1522.png)

#ボリューム作成

毎度の如くウィザードなので一部割愛
ドライブレターはEとします。
![13.PNG](https://qiita-image-store.s3.amazonaws.com/0/282669/bb2d2f72-1a74-b83e-4338-311705a90069.png)

フォーマットはNTFS
![14.PNG](https://qiita-image-store.s3.amazonaws.com/0/282669/1d41c4e7-30cb-3275-04b6-1e04e0ee09ae.png)

ボリューム完成
![15.PNG](https://qiita-image-store.s3.amazonaws.com/0/282669/bbfa8f9f-77d0-0c74-d749-bcf5f8a6b3fb.png)

#確認
10GByteのHDDを5本束ねて14GByteのストレージが完成しました。素晴らしいですね。
3way mirrorなのでディスク2台までの障害なら耐えられるはずです。
![16.PNG](https://qiita-image-store.s3.amazonaws.com/0/282669/70b87b60-21d2-bc01-8483-dc1e05edc3fc.png)

長くなってしまったので次回意図的に障害を起こしたりして遊び倒します。
さくらのVPSでIPv6に対応する（ubuntu16.04）

さくらのVPSにおいて、IPv6はデフォルトでは無効化されているようです。
それを知らずにAAAAレコードを登録してしまい、通信不良を起こしてしまっていました。
（コンパネにIPv6アドレス書いてあったからなんだいけるのか、と思ってしまった）
対応内容を備忘録として残しておきます。
内容が間違っている場合やマズい場合は、ご指摘いただけると大変助かります。

## IPv6を有効にする
とはいえ、公式サイトに有効化の方法が書いてあったので、この通りに操作すればひとまずIPv6の通信が可能になります。
https://help.sakura.ad.jp/hc/ja/articles/115000066021-IPv6有効化手順-Ubuntu-16-04-

## iptables
IPv6での通信を受けるようになったので、ip6tablesを確認しておきます。

```
ip6tables -L
```

もしガバガバだった場合、iptablesと同様に使うポート以外は制限しておきましょう。

### もしufwを使う場合
ufwを使うのが楽ですが、さくらのVPSの場合、デフォルトの設定として`/etc/iptables/iptables.rules`が適用されます。
こいつがあるとufwをenableしてサーバを再起動したとしても、この設定が有効になり、ufwはinactiveにされちゃいます。
なので、適当なディレクトリに移しちゃいましょう。
> 参考：http://blog.mogmet.com/how-to-enable-ufw-on-sakura-vps/


```bash:例
mv /etc/iptables/iptables.rules /home/ubuntu/
```

あと、ufwが`IPV6=yes`になっているか確認を忘れずにしておきます。

```
vi /etc/default/ufw
```

```config:/etc/default/ufw
# Set to yes to apply rules to support IPv6 (no means only IPv6 on loopback
# accepted). You will need to 'disable' and then 'enable' the firewall for
# the changes to take affect.
IPV6=yes
```

あとは普通にufwで設定できます。

## webサーバの設定確認
ApacheやnginxなどのWebサーバの設定を確認し、IPv6をlistenするように設定を変更しておきます。

nginxの場合はこんな感じです。
`nginx -V`で`--with-ipv6`があるか確認しておいたほうがいいですが、最近のnginxならデフォルトでONのはず。

```
server {
  listen 80;
  listen [::]:80; #←これを追加
  ~
}
```

## AAAAレコードを設定する
DNSのAAAAレコードにさくらのVPSコントロールパネルより確認できるサーバのIPv6アドレスを設定します。

## IPv6で接続できるか確認
最後にIPv6で接続できるか確認します。
http://ipv6-test.com/validate.php

## 最後に
こんな感じでIPv6に対応することができました。
CentOSでも大体同じ対応でいけるかと思います。
インフラ周りはよくわからなくてよくわからないですけど、いい勉強になりました。
ネストしたオブジェクトのプロパティ指定を Proxy により取得

# 多次元的なオブジェクトのプロパティ指定をパスのように取得したい

## TypeScript

TypeScript により多次元のパスを型として抽出する例が Stack Overflow にあった。

https://stackoverflow.com/questions/58434389/typescript-deep-keyof-of-a-nested-object/58436959#58436959

## サンプル

下記のような事例において値である `def` ではなく
プロパティの指定を `a.b.c` のような形で取得したい場合が時に時々発生するかもしれません

```javascript
const multipleDimension = {
  a: {
    b: {
      c: 'def'
    }
  }
};
console.log(multipleDimension.a.b.c); // def
```

## Proxy を使用して高次元のアクセス

[How to use javascript proxy for nested objects - Stack Overflow](https://stackoverflow.com/questions/41299642/how-to-use-javascript-proxy-for-nested-objects#answer-41300128) のネストしたオブジェクトへの操作の事例を応用し・・・

```javascript
const tracer = {
  // 経路格納用
  route: [],
  get(target, prop) {
    if (target.base === target) {
      // 根元で初期化
      this.route = [];
    }
    if (/^toPath$/.test(prop)) {
      return this.route;
    } else {
      // 経路を保持
      this.route.push(prop);
      // toPath を完結させるためのダミーオブジェクト
      const nextTarget = target[prop] instanceof Object ? target[prop] : {};
      return new Proxy(nextTarget, tracer);
    }
  },
};

/**
 * @type { <T>(target: T; tracer: tracer) => T }
 */
const tracerProxyFactory = (target, tracer) => {
  // 根元の比較対象を保持しておく
  const baseTarget = {
    ...target,
    get base() {
      return this;
    },
  };
  return new Proxy(baseTarget, tracer);
};

const multipleDimension = {
  a: {
    b: {
      c: 'def',
    },
  },
  abc: {
    def: {
      ghi: 'jkl',
    },
  },
};

const b = {
  a: {
    b: {
      c: 'def',
    },
  },
  abc: {
    def: {
      ghi: 'jkl',
    },
  },
};

const tracerProxy = tracerProxyFactory(multipleDimension, tracer);
const tp = tracerProxyFactory(b, tracer);
console.log('RESULT', tracerProxy.a.b.toPath); // ["a", "b"]
console.log('RESULT', tp.a.b.toPath); // ["a", "b"]
console.log('RESULT', tracerProxy.abc.def.ghi.toPath); // ["abc", "def", "ghi"]
// 未定義のものもうけつけてしまった・・・
console.log('RESULT', tracerProxy.a.b.c.d.e.f.g.toPath); // ["a", "b", "c", "e", "f"]
```

もう少しなんとかなりそうなものですが・・・とりあえずこれで
Scalaを対話的に実行する

ScalaをRead Eval Print Loop(REPL)を使って対話形式で実行した。
`$ sbt console`
でScalaをREPLで実行できる。

```
scala> println("Hello, World!")
Hello, World!

scala> "Hello, World!"
res1: String = Hello, World!
```
文字列だけを入力すると型Stringが表示された。Scalaは静的な型を持つ。プログラム実行前に型があっているか調べられるということ。

```
scala> 0xff
res2: Int = 255
```
0xは16進数を示す。16進数が10進数で表示された。

```
scala> 1e308
res3: Double = 1.0E308
```
Doubleの範囲内の数

```
scala> 9223372036854775807L
res4: Long = 9223372036854775807
```
64bitの整数

```
scala> 9223372036854775808L
<console>:1: error: integer number too large
       9223372036854775808L
```
Long型の範囲を超えているのでエラーになった。

```
scala> 9223372036854775807
<console>:1: error: integer number too large
       9223372036854775807
```
Long型を示すLがないのでエラーになった。

```
scala> 922337203685477580.7
res5: Double = 9.2233720368547763E17
```
少数点がつくとDouble型の範囲内

```
scala> 1.00000000000000000001 == 1
res6: Boolean = true
```

```
scala> 1.000000000000001 == 1
res20: Boolean = false
```
Doubleなどの浮動小数点数は近似された値で表現されるためtrueになる。

```
scala> "\u3042"
res7: String = あ
```

```
scala> "\ud842\udf9f"
res8: String = 𠮟
```
文字コードを入力している。

`+` `-` `*` `/` `%`などが使える。
`dbl.asInstanceOf[Int]`で型の変換ができる。

```
scala> 4.5/2
res25: Double = 2.25

scala> (res25).asInstanceOf[Int]
res26: Int = 2
```

```
scala> 2147483647 +1
res29: Int = -2147483648

scala> 9223372036854775807L + 1
res30: Long = -9223372036854775808
```

型の最大値を超えると最小値になった。調べたところ言語によって挙動は違うらしい。

#変数
Scalaには２種類の変数があり、valは一度変数に値を入れると変更できない。varは変更ができる。基本的にvalが使われる。また、varでもvalでも型を宣言しなくてもコンパイラが型を推論してくれる。pythonと似てる。

```
scala> var x = 3*3
x: Int = 9

scala> x = "Hello"
<console>:12: error: type mismatch;
 found   : String("Hello")
 required: Int
       x = "Hello"
           ^

```

変数の型を宣言することもできる。

```
scala> val x: Int = 4*4
x: Int = 16
```

練習問題
Q. ¥3,950,000を年利率2.3％の単利で8か月間借り入れた場合の利息はいくらか（円未満切り捨て）

```
scala> val x = 3950000 * 0.023 / 12 * 8 
x: Double = 60566.666666666664

scala> val y = (x).asInstanceOf[Int]
y: Int = 60566

```

Q. 定価¥1,980,000の商品を値引きして販売したところ、原価1.6％にあたる¥26,400の損失となった。割引額は定価の何パーセントであったか

```
scala> val x = 100*(1-((26400/0.016)-26400)/1980000)
x: Double = 18.000000000000004
```