OmniAICreator/Qiita-1.07M huggingface dataset:
railsでのbootstrap導入方法

#はじめに
rubygemのbootstrap4が英文でわかりづらかったので今後のためにもすぐbootatrapを導入できるように残しておきます。

#導入方法
Gemfileにbootstarpと依存するjqueryのGemを入れます。

```ruby:qiita.rb
  gem 'bootstrap', '~> 5.0.0.alpha3'
  gem 'jquery-rails'
```

ターミナルでインストールします。

```
$bundle install
```

railsで最初から入っているapplication.cssをapplication.scssに変更します。
そこでbootstrapが使えるようにimportします。

```application.scss
@import "bootstarp";
```

最後にjqueryとの依存関係を示すコードをapplication.jsに記述します。

```app/javascript/packs/application.js
//= require jquery3
//= require popper
//= require bootstrap-sprockets
```

コンパイルを早くしたい方はこちらを

```app/javascript/packs/application.js
//= require jquery3
//= require popper
//= require bootstrap
```

これで導入は完了です。

公式のrubygem導入方法: [bootstarp.ruby-gem](https://github.com/twbs/bootstrap-rubygem/blob/master/README.md#a-ruby-on-rails)

#最後に
実装してrails sコマンドを実行した時にエラーが起きる場合もあるのでそれの対処法も他記事に載せておきます。
[Blocked hostエラー](https://qiita.com/masaki_326/items/c8e25877d29ec3665945)
Centos7にてcomposer installを行うと「Your requirements could not be resolved to an installable set of packages.」と怒られた


## なにが起こったか
Centos7に運用中のLaravelプロジェクトをクローンしてcomposer installしたらコケた。

```
$ composer install
Loading composer repositories with package information
Installing dependencies (including require-dev) from lock file
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - Installation request for php-di/invoker 2.1.0 -> satisfiable by php-di/invoker[2.1.0].
    - php-di/invoker 2.1.0 requires php >=7.3 -> your PHP version (7.2.28) does not satisfy that requirement.
  Problem 2
    - Installation request for doctrine/dbal 2.11.1 -> satisfiable by doctrine/dbal[2.11.1].
    - doctrine/dbal 2.11.1 requires php ^7.3 -> your PHP version (7.2.28) does not satisfy that requirement.
  Problem 3
    - php-di/invoker 2.1.0 requires php >=7.3 -> your PHP version (7.2.28) does not satisfy that requirement.
    - mnapoli/silly 1.7.2 requires php-di/invoker ~2.0 -> satisfiable by php-di/invoker[2.1.0].
    - Installation request for mnapoli/silly 1.7.2 -> satisfiable by mnapoli/silly[1.7.2].

```
## 解決方法
エラーメッセージを見る限りPHPのバージョン問題だったので、PHPを7.2から7.4へアップデートした。
※正確にはPHP7.3以上を求められていた。

### PHP7.4インストール
```
$ sudo yum install -y --enablerepo=remi-php74 php which
み込んだプラグイン:fastestmirror, langpacks
Loading mirror speeds from cached hostfile
 * base: ty1.mirror.newmediaexpress.com
 * epel: nrt.edge.kernel.org
 * extras: ty1.mirror.newmediaexpress.com
 * remi-php74: ftp.riken.jp
 * remi-safe: ftp.riken.jp
 * updates: ty1.mirror.newmediaexpress.com
...
```

### PHPインストール確認

```
$ php -v
PHP 7.4.13 (cli) (built: Nov 24 2020 10:03:34) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
    with Zend OPcache v7.4.13, Copyright (c), by Zend Technologies
    with Xdebug v2.9.8, Copyright (c) 2002-2020, by Derick Rethans

```
Android実装時にお世話になったページ 2020/11/26

## なにか

毎回、同じ問題に、同じ検索して、同じページで解決してるので。。。

## NavigationでActivityに遷移したい、そしてstartDestinationにパラメータを渡したい。

まぁ、公式ドキュメントを読めって話なんですが、ついStack Overflowのリンクから踏んでしまう。

[Stack Overflow "Navigation Architecture Component- Passing argument data to the startDestination"](https://stackoverflow.com/a/55373926)

で、このコメントから公式ドキュメントに飛びました。

[Android Developers "ナビゲーション コンポーネントに移行する"](https://developer.android.com/guide/navigation/navigation-migrate#pass_activity_destination_args_to_a_start_destination_fragment)

## NavigationでBottomSheetDialogFragmentを表示したい

[Stack Overflow "How to create BottomSheetDialogFragment using Navigation Architecture Component?"](https://stackoverflow.com/a/56513593)

## BottomSheetDialogFragmentを角丸にしたい

[note "BottomSheetDialogFragmentの角を丸くする"](https://note.com/yasukotelin/n/nb1c877358d4a)

## BottomSheetDialogFragmentを画面いっぱいに表示したい（画面の高さを設定したい）

[ツレヅレナルママニ "BottomSheetをフルスクリーン状態で表示する方法"](https://tkhs0604.hatenablog.com/entry/fullscreen-bottomsheet)

## さいごに

今日は、ピンポイントで日本語サイトがヒットした。
🩰yawacom - 🐭APIの設計書を書く

## APIってなに？
例えば下記のように，ユーザがユーザIDを入力すると，そのユーザの性別を返す，といったような仕様のことです（超ざっくりです．入力はユーザじゃなくて他のDBの時もありますし）．
![その他.002.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149433/2a1c5c62-446e-cd6d-b41b-0272d5051cbf.jpeg)


## なぜ設計書を書くのか？
どういう値を受け取ってなにを返すのか，自分の頭が整理できます．
またこれから会社に入ってチームで開発するとき，チームメンバーで機能や仕様の共有のためにも設計書は必須です．逆に設計書を受け取って開発することもあります．


## 設計書を書いてみよう
今回は[Swagger](https://editor.swagger.io/)と呼ばれる，変数名とかをぶちこむだけでいい感じの設計書を勝手に作ってくれるエディタを使用しました．ブラウザ上で使えます．
<img width="1440" alt="Swagger" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149433/3d913e40-cf02-c86f-52ea-edf4727f9596.png">

こんな感じで左に書き込むと右におしゃれな設計書ができあがっていきます．すごい．

書き終えたらヘッダーのFile▼から`Save as YAML`で保存しましょう．YAMLはそのまま「ヤムル」と読むそうです．
今回のアプリのYAMLは[GitLab](https://gitlab.com/kno3a87/mikuaka/-/blob/master/swagger.yaml)にあります．（GitLabでもYAMLがきれいに見えて感動してます）
マルチスケールシミュレーション特論： google recruit

\![ruby-2.5.5p157](<https://img.shields.io/badge/ruby-2.5.5p157-brightgreen>) 


# はじめに

今回はマルチスケールシミュレーション特論という大学院の授業で ruby を使った課題があったのでプログラムを作成してみた

-   **課題**{e(自然対数の底)の値で連続する 10 桁の数のうち，最初の素数}を求めよ


# 手法

e は以下のように定義されている

```
e = 2.71828182845904523536028747135266249775
    7247093699959574966967627724076630353547
    5945713821785251664274274663919320030599
    2181741359662904357290033429526059563073
    81323286279434907632338298807531952510190
```

以下のような **手順** で今回は進めていこうと思う


## 手順

-   e.txt というテキストファイルに e の値を保存しておく
-   e.txt から値を読み込む
-   2.7 の部分の "." を除去して 10 桁毎に値を区切る
-   区切った値が素数かを判定する


# プログラム

```ruby
 1  #!/usr/bin/env ruby
 2  require 'prime'
 3  
 4  def divide_per_ten
 5    f = File.open("e.txt")
 6    s = f.read.delete(".")
 7    start_index, goal_index = 0, 10
 8    while true do
 9      if prime_decision(s[start_index, goal_index].to_i) == true then
10        puts s[start_index, goal_index]
11        break
12      end
13      start_index = start_index + 1
14    end
15  end
16  
17  def prime_decision(num)
18    return Prime.prime?(num)
19  end
20  
21  divide_per_ten
```


## 各関数の説明

-   divide\_per\_ten 関数：ファイルから e の値を読み込み、10 桁毎に区切ってprime\_decision 関数に渡す

-   prime\_decision 関数：素数の判定を行って、true or false を返り値として渡す


## GitHub

コードは以下の URL から閲覧できます

-   <https://github.com/taiseiyo/google_recruit>


# 結果

実行すると以下のような答えがでてきます

```
7427466391
```


# さいごに

是非、おもしろいなと思ったら LGTM してくれると今後の励みになるのでお願いします!!

(LGTM されると嬉しくて踊りだします)



------
 - **source** ~/Downloads/git/enjoy_unix_lecture_materials/grad_members_20f/members/taiseiyo/memos/google.org
個人用パソコンセットアップ(mac)

#パソコンを変えたとき用のやることまとめ

##vscodeダウンロード
https://code.visualstudio.com/download

##homebrewのインストール
https://brew.sh/index_ja
ターミナルにペースト

```
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```

##gitのダウンロード 
https://git-scm.com/download/mac
ターミナルにペースト

```
brew install git
```

##vscodeとgitの接続
###ユーザー名の登録
ターミナルにペースト

```
git config --global user.name "GitHubに登録しているユーザー名"
```
###ユーザーアドレスの設定
ターミナルにペースト

```
git config --global user.email "GitHubに登録しているメールアドレス"
```
###githubとvscodeの接続をオープンエディタの画面から？
なんか接続するための画面が出てくるのでそれを許可

###ssh鍵を作成する
ターミナルに貼り付ける

```
ssh-keygen
```
これを入れたらとりあえずenterしたらpasを作成しろと出るので作成
そしてもう一度入力

###ssh鍵の登録
ターミナルに貼る

```
ssh-add -K パスワードを入れたファイル?
```
###正しく登録されたかの確認

```
ssh-add -l
```
###鍵の中身をコピー

```
pbcopy < ファイル名
```
GithubのSettingsを開き、Githubに鍵登録
New SSH keyを押して鍵に命名
そして鍵部分に先程コピーされたものをそのまま入れる

###鍵接続

```
ssh-add ファイル名.pub
```

##vscode設定
###code .を使えるようにする
command + shift + p
Shellと入れる
installを選ぶ

###拡張機能
liveserverの追加

##node周りセットアップ
###nodebrewインストール

```
brew install nodebrew
```

###node.jsインストール
先にディレクトリ作成してるといい感じ

```
mkdir -p ~/.nodebrew/src
```
安定版のをインストール

```
nodebrew install-binary stable
```

パスを通す

```
echo 'export PATH=$HOME/.nodebrew/current/bin:$PATH' >> ~/.bash_profile
```

##ngrokインストール
https://www.joint-media.co.jp/2844.html
brewでインストール

##mySql接続
###npm

```
npm install mysql
```

##python
###pythonを直接インストール
https://www.python.org/downloads/

###anacondaインストール
https://www.anaconda.com/products/individual
guiとcli両方インストールしてもいいかもしれない

##セットアップ色々
https://prog-8.com/docs/python-env
これ通りにやれば基本間違いない

##ターミナル起動自動化
https://ry0.github.io/blog/2015/10/21/open-terminal-shortcut/#gsc.tab=0
上記記事通り作成
command + shift + oで設定

##vscodeからchromeを開く
下記コードを一番上のディレクトリに入れておく

```
alias chrome='open -a "Google Chrome"'
```
chromeと押すとchromeが開くようになる

##完了

##参考にさせていただいた記事
git登録周り
https://note.com/cd_ss_829/n/n4e7d80723381
https://qiita.com/yu0313/items/4f95fc0b7e544c42e107

公開鍵周り
https://www.velumi.com/guides/vs-code-get-permission-denied-publickey-mac/
https://qiita.com/luccafort/items/92d9643ac9ddecc0cadd
https://www.atnr.net/permission-denied-error-on-git-pushing/
https://qiita.com/takuyanin/items/c6a097028a837052c90c
https://qiita.com/tnatsume00/items/e147662368d02e6416d2

vscode設定周り
https://qiita.com/ayatokura/items/69c96306e3dee501e19b
ctfの環境と便利な道具たち

##はじめに
自分がctf（capture the flag）を行っている環境、便利だと思ったソフトウェア、ウェブサイトを紹介します。
OSは__windows10__です
binnary exploit, reverse engineering, pwnなどなどにはまだ手を出していないです。初心者が書いているために物足りない方、違う意見の方もいると思いますが、一意見として受け取っていただけると幸いです。


##環境について
* [Oracle VM virtualBox]
(https://www.oracle.com/jp/virtualization/technologies/vm/downloads/virtualbox-downloads.html)
仮想環境はVirtualBoxの無料版を使ってます。今のところ特に機能が足りないと思ったことはないです。VMwareなど別に有名なものもあるので自分に合ったものを選べばいいと思います。

* [Kali Linux](https://www.offensive-security.com/kali-linux-vm-vmware-virtualbox-image-download/)
 linuxディストリビューションの一種です。VMで使ってます。ペネトレーションテストなどに使われているそうです。ただ、まだあんまり使いこなせてる感がないです。


##ソフトウェア
* [VScode](https://azure.microsoft.com/ja-jp/products/visual-studio-code/)
コードエディタです。普段から使っているものをそのまま使うのが良いと思います。デフォルトのターミナル？をwslにしている以外はほとんど設定はいじってません。

* [Wireshark] (https://www.wireshark.org/download.html)
 .pcapのファイルとか（ネットワーク関係）を開くのに使ってます。どんなジャンルを解きたいかにもよると思いますが必須と言って差し支えはないと思います。

* [FanBinEdit] (https://www.wabiapp.com/FavBinEdit/)
 バイナリエディタです。たくさんのオプションがあるので自分の好きなものを選べばいいと思います。

* [GIMP](https://www.gimp.org/)
 画像処理ソフトです。必須ではないと思いますが、無料ソフトで、ダウンロードしておいても損はないと思います。

* [EditThisCookie](https://chrome.google.com/webstore/detail/editthiscookie/fngmhnnpilhplaeedifhccceomclgfbg?hl=ja)
 chromeのextensionです。Cookieの編集ができます。

##便利なwebサイト
* [cryptii](https://v2.cryptii.com/text/select)
 クラシカルな暗号を解くのに使えます。一回目は手でといてもいいと思いますが、それ以降は自動化したほうがいいと思います。自作でもいいと思います。

* [Passwor drecovery] (https://passwordrecovery.io/)
 オンラインでつかえるパスワードリカバリーサイトです。パスワードがついたzipファイルを開いたりやsha256の逆算？とかに使えます。自作でもいいと思います。

##最後に
ここに書いてあるのはあくまで私が使っているものです。自分に合ったものを使ったほうがいいと思います。CTFを始めようか悩んでいる人は[cpawCTF](https://ctf.cpaw.site/)や[picoCTF](https://picoctf.org/)をのぞいてみるといいと思います。あとは英語の勉強を...
Symfonyの認可について


# 初めに

`User`に紐づいた`Post`エンティティがあったとき「自分の所有する`Post`以外は見れない」という用件を達成するにはどのような実装方法があるか、という話です。

# 最も単純な方法

最も単純な方法は、コントローラーでログインしている`User`の`Post`かどうか判断する方法です。特に難しいこともありません。
が、しかし、 アクセス権を確認する際に同じようなコードが至る所に出てきてしまうことが容易に想像できます。

```php
    /**
     * @Route("/{id}/detail", name="post_detail")
     */
    public function edit(Post $post)
    {
        $user = $this->getUser();
        if ($post->getUser() !== $user) {
            throw $this->createAccessDeniedException();
        }
        ...
    }
```

# Voterを用いる方法

Symfonyには`Voter`という認可のための仕組みがあります[^voter]。
こちらを用いることで、認可のロジックを分離することができ、あらゆる箇所で使い回すことが出来るようになります。

makeコマンドで作れます。

```
bin/console make:voter

 The name of the security voter class (e.g. BlogPostVoter):
 > PostVoter

 created: src/Security/Voter/PostVoter.php
```

makeコマンドで作ると雛形が作成されます。今回は閲覧だけなのでこのように書き換えます。


```php:src/Security/Voter/PostVoter.php
<?php

namespace App\Security\Voter;

use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
use Symfony\Component\Security\Core\User\UserInterface;

class PostVoter extends Voter
{
    protected function supports($attribute, $subject)
    {
        return in_array($attribute, ['VIEW'])
            && $subject instanceof \App\Entity\Post;
    }

    protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
    {
        $user = $token->getUser();
        if (!$user instanceof UserInterface) {
            return false;
        }

        switch ($attribute) {
            case 'VIEW':
                return $subject->getUser() === $user; // $subjectに認可対象のエンティティが入る
        }

        return false;
    }
}
```

これを、コントローラーからこのようにして呼び出すことができます。内部では`Voter`の`voteOnAttribute`メソッドが呼び出され、アクセス権がないと判断されると、自動で`AccessDeniedException`が投げられます。

```php
    /**
     * @Route("/{id}/detail", name="post_detail")
     */
    public function edit(Post $post)
    {
        $this->denyAccessUnlessGranted('VIEW', $post);
        ...
    }
```

# 更に美しく

コントローラーでの認可に限った話で言えば、アノテーションを使うことで更にメソッド内部をすっきりさせることができます。
認可のためのコードがメソッド内に1行も現れず、本来のロジックのみに集中出来るのでとても見やすくて良いと思います。

```php
    /**
     * @Route("/{id}/detail", name="post_detail")
     * @IsGranted("VIEW", subject="post")
     */
    public function edit(Post $post)
    {
        ...
    }
```


# 参考文献

[^voter]: https://symfony.com/doc/current/security/voters.html
firebaseのsetメソッドの使い方と活用方法

#firebaseって何？
個人的には費用面、手軽さなど、多方面で最強のアーキテクチャだと思っています。

#firebaseのデータ登録、更新について
| 処理内容 | 登録 | 更新 |
|:-:|:-:|:-:|
| addメソッド  | 〇  | ×  |
| updateメソッド  | ×  | 〇  |
| setメソッド  | 〇  | 〇  |

上記のように、新規登録にも更新にも使えるsetメソッドですが、addメソッド、updateメソッドとちょっと使い方が違うんですよね。
そのあたりをわかりやすくまとめられたらと思っています。


#(データの新規追加)addメソッドとsetメソッドの違いについて
一番大きな違いは、ドキュメントIDを自動発行するかどうかという違いです。

addメソッド：ドキュメントIDを自動発行する。
setメソッド：ドキュメントIDを自動発行しない。

使い分け！！
ドキュメントIDにこだわらない場合（どんな値でも良いっす！）はaddメソッドを使うのが楽！
ドキュメントIDを指定したい場合は、setメソッドを利用する。

いろんなところで言われている内容ではあると思いますが、ドキュメントIDを自動発行して、setメソッドを利用することもできます。

```set.js
// ドキュメントをランダムIDで発行
const ref = firebase.firestore().collection('test').doc();
// 先ほど取得したドキュメントのIDを明示的に指定
await firebase.firestore().collection('test').doc(ref.id).set({
  name: テスト太郎,
  phone: 080-0000-0000
})
.then(function(){
  // データ登録成功時の処理
  // firebaseコマンドは、promiseオブジェクトなので、thenでつなげられる。
})
.catch(function(err){
  // データ登録失敗時
});
```

addメソッドの場合は、上記のソース上から、ドキュメントIDを取得してくる処理がまるまる省略できるってことですね。

ざっくり分けて、firebaseのデータ登録機能には以下の2工程に分けられます。
①ドキュメントIDを発行
②データ更新

上記を一つにまとめているのが、addメソッド、別々に分けているのがsetメソッドです。

#（データ更新）updateメソッドと、setメソッドの違い
一番大きな違いは、特定のフィールドのみ更新するか、全部上書きするかの違いです。

updateメソッド：指定したフィールドのみ更新
setメソッド：全て更新

例えば、以下のようなコレクションがあったとします。

コレクション名：test
　ドキュメントID：1234567890abcdefg
　　name：テスト太郎,
　　phone：080-0000-0000,
　　address：東京都千代田区

```updateメソッド.js
firebase.firestore().collection('test').doc('1234567890abcdefg').update({
  name:テスト次郎
});
```

```setメソッド.js
firebase.firestore().collection('test').doc('1234567890abcdefg').set({
  name:テスト次郎
});
```

単純にメソッドが違うだけですね。
これが、それぞれどうなるのかを見てみましょう。

updateメソッド
コレクション名：test
　ドキュメントID：1234567890abcdefg
　　***name：テスト次郎,　←　ここのみ更新***
　　phone：080-0000-0000,
　　address：東京都千代田区


setメソッド
コレクション名：test
　ドキュメントID：1234567890abcdefg
　　name：テスト次郎,
※全上書きされ、明示的に記載したものだけが残る。


#setの活用方法を考えてみた
以下の条件なんかの時はsetメソッドが輝きます。
***・ドキュメントIDが指定したIDである。（自動生成ではない）***
***・新規作成と更新が同ソース内に両方とも含まれる。***
 →　データがなかった場合は、新規作成、あった場合は更新みたいなケースですね。

上記のようなときは、setメソッドを利用することによって、新規作成なのか、更新なのかを考慮する必要がなく、ソースを記載することができます。

普通に利用しようとすると、ちょっと使いづらいsetメソッドですが、設計次第でかなり便利なメソッドになります。
開発環境で更新したGithubのコードを本番環境でpull

git fetch origin master
↓
git reset --hard origin/master（強制的にpullする）
↓
EC2インスタンス再起動（これをしないとunicornの起動時にエラー）
↓
unicorn_rails -c /var/www/rails/mumu(アプリの名前)/config/unicorn.conf.rb -D -E production(unicornの起動)
↓
sudo nginx -s reload（Nginxの再起動）
↓
sudo service mysqld start（mysqlを起動していなかったら）
ポケモンでTypeScriptおもしれーってなる(型エイリアスまで)

## 型エイリアス typeとは

型宣言をtypeで記述することができる。

```ts
type Age = number
let age: Age = 15
```

## オブジェクト

もちろんオブジェクトもできる。
`?`を使うと必ず記述しなくても良くなる。

```ts
let o: { a: number, b?: string } = {
  a: 2
}
console.log(o.a) // -> 2
console.log(o.b) // -> undefined
```

## readonly

オブジェクトのプロパティを書き換え禁止にできる。
変数で言うconst。

```ts
let o3: {
  readonly id: number
} = { id: 3 }
o3.id = 2 // -> エラー
```


## ポケモンとtypeでいちゃいちゃする

以上を踏まえてあれこれ触る。

```ts
type Action = {1: string, 2?: string, 3?: string, 4?: string }
type Pokemon = {
  readonly abst: string,
  readonly name: string,
  actions: Action
}
let pityu: Pokemon = {
  abst: 'ピカチュウの進化前',
  name: 'ピチュー',
  actions: {1: 'たいあたり', 2: 'しっぽをふる'}
}
pikatyu.actions[3] = "でんきショック"
```
CentOS8にRcloneインストールしてGoogleDriveの特定フォルダの中身表示するとこまでやるん

#前提条件
GoogleDriveの接続認証の際にブラウザ上での操作があります。
まず、GUIデスクトップ環境を用意する必要があります。


#本家サイトを参考にしつつrcloneのインストールまで
本家サイト
https://rclone.org/install/

まずはrcloneをダウンロードして解凍。

```
curl -O https://downloads.rclone.org/rclone-current-linux-amd64.zip
unzip rclone-current-linux-amd64.zip
```

解凍したrcloneをパスが通ってる場所へコピー。
実行権限付与。


```
cd rclone-*-linux-amd64
cp rclone /usr/bin/
chown root:root /usr/bin/rclone
chmod 755 /usr/bin/rclone
```

rcloneが使えるように設定。
（必要なものはインストール）

```
mkdir -p /usr/local/share/man/man1
cp rclone.1 /usr/local/share/man/man1/

yum install man
yum install man-pages

mandb
```

下記コマンドでrcloneのバージョンが取得できればインストール終了。

```
rclone version
```

#rcloneのエントリ（GoogleDrive接続設定）を作る
下記コマンドで設定作成開始。

```
rclone config
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/6ecb0675-546b-d75f-930b-9060689413aa.png)
と聞いてくるから、『新しい設定作るよ』って意味で ```n``` 。

---

お次は『name』って聞いてくるから、自分の好きな接続名を入力。
今回は ```GoogleDriveSync``` としました。

---

お次は『接続の種類は何にする？』って聞いてくる。
GoogleDriveだから…
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/267f855f-87b0-faa1-da90-13dc279d0239.png)
```13``` を。
この番号はrcloneのバージョンによって変わる可能性あるから、表示された内容をよく読んだ方がいいと思います。

---

そしたら『client_id』『client_secret』をどうするか聞いてくるけど、設定無しで。（何も入力せずえんたー）

---

次は『scope』（アクセス権どうする？）って聞いてくる。
今回はアップロードもダウンロードもするから ```1```　で

---

『root_folder_id』『service_account_file』をどうするか聞いてくるけど、設定無しで。（何も入力せずえんたー）

---

その次は『Edit advanced config?』って聞いてくるので ```n``` 。

---

そして『Remote config?』って聞いてくるから ```y``` 。

---

少し待つとブラウザ開くからGoogleアカウントへログイン。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/e108629b-7f3b-111b-3a33-32f9ee40b9e4.png)
認証して下図が出ればOK。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/85774a5b-7309-b991-4b9a-58acacb2b3fe.png)

---

そしたら『Configure this as a team drive?』って聞いてくるけど、個人で使うだけだから ```n``` 。

---

そのあとtokenとかの接続情報が表示されるので ```y``` で。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/ae47ec6e-5df9-659d-6696-7829519ce391.png)

---

最後に下図のように設定できたよって見せてくれるから ```q``` で終了。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/3589e26a-d763-0cac-221d-3a776b54e68e.png)


#GoogleDriveの特定フォルダの中身を表示してみよう！
GoogleDriveのルート直下にある『ゆるきゃん』フォルダの中身を下記コマンドで表示！

```
rclone ls GoogleDriveSync:'ゆるきゃん'
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/a173e365-2294-8be3-2088-985e3e312495.png)
OKですね。


* ルートに対してlsするとGoogleDrive内のファイルを一気にぜーんぶ表示しようとしちゃうので注意！（テストフォルダー作って確認した方がいいです）
* フォルダパスに平仮名などが含まれている場合、シングルクオテーション囲わないとフォルダー見つからないよエラーになります。


#蛇足
インストール～GoogleDriveのファイル一覧取得まで割とすんなり行けました。

rcloneはGoogleDrive以外にもいろんなクラウドストレージに対応しているようです。
ストレージの乗り換えや使い分けなんかする時もスムーズに行けそうです。

ファイル一覧取得した時にGoogleAPIと時刻ずれてるよ的な警告出るけど、個人で使う分にはそこまで気にしなくてもいいかな…って思う。


#参考サイトさん
Rcloneの本家サイトのGoogleDriveのマニュアル
https://rclone.org/drive/


参考サイト
https://www.harumaki.net/2016/06/23/rclone_google-drive-for-linux/


#次の記事
[CentOS8にインストールしたRcloneでGoogleDriveに対してダウンロードとアップロードなど](https://qiita.com/waokitsune/items/279b1643f8204ecc3cb5)


#バージョン
CentOS Linux release 8.2.2004 (Core)
超絶便利なGoogle Drive File Streamをインストールしない理由がない

# Google Drive File Stream使っていますか？
- Google Drive File Streamとは？
    - 端的に言うとmacのFinderやコマンドラインツールからGoogle Driveを操作できるアプリです！
 
# ってことでさっそく本題(秒で出来ます！)
今回は**Homebrew**を使ってることを前提としています。(わからない人はググってみてください)

1. ``` brew install --cask google-drive ```
2. Passwordが求められるのでMacのログイン時に利用しているPasswordを入力
3. Launchpadにアプリが表示されるので開く
    1. セキュリティチェックを求められるため、システム環境設定のセキュリティとプライバシーをクリック
    2. general(一般)をクリック
    3. 下半分に許可する項目あるため許可
4. 上のバーにアプリのアイコンが表示されるためそこをクリックして任意のアカウントにログイン

# まとめ
たったこれだけです。
ってことで、ぜひ騙されたと思ってやってみてください！

# 追記
Google Drive File Streamで何ができるのか、

1. まず第一にwebブラウザを立ち上げなくて済む！
2. Drive上のパワポなど、一度ダウンロードしないと編集できないファイルが直接編集できる！
    - 本来であれば, ダウンロードして, 編集して, 再度アップロードという手間がかかる。。。
3. フォルダをローカルに移動させるときにわざわざzipファイルにせずに済む！
4. Finderの機能(Air Dropだったり複数のファイル名の変更だったり)が使える！
    - Driveの共有ではAirDropなどは使えませんがFinderからだと可能になります！
5. コマンドラインツールでファイル管理ができる！
    - 慣れるととても便利です！

その他にもいろいろあるんですが疲れてきたのでこの辺でまとめさせていただきます。
便利な機能があればそれもぜひコメントしていただけると嬉しいです！
ひな祭り[Ruby]

#ひな祭り[Ruby]問題
#問題
ひな祭りの準備をしましょう。あなたが持っている 10 体の人形を "A", "B", "C", "D", "E", "F", "G", "H", "I", "J" で表します。ひな壇の各段 (計 3 段) に並べる人形の数が与えられるので、各段にならべる人形の記号を改行区切りで出力してください。人形は必ずもとの A, B, C, ... の順番で並べます。

例)

各段にならべる人形の数: 2, 3, 5

→ 人形の並べ方:

AB
CDE
FGHIJ
#入力される値
入力は以下のフォーマットで与えられます。

h_1 h_2 h_3
ひな壇の 1 段目、2 段目、3 段目に並べる人形の数を表す整数 h_1, h_2, h_3 がこの順に半角スペース区切りで与えられます。入力は 1 行となり、末尾に改行が 1 つ入ります。
#期待する出力
ひな壇への人形の並べ方を以下の形式で出力してください。

s_1
s_2
s_3
ひな壇の 1 段目、2 段目、3 段目に並べる人形を表す文字列 s_1, s_2, s_3 をこの順に改行区切りで出力してください。

s_i (1 ≦ i ≦ 3) は i 段目に並べる人形の記号をアルファベット順に結合した文字列です。
#入力例1
2 3 5
#出力例1
AB
CDE
FGHIJ
#入力例2
1 1 8
#出力例2
A
B
CDEFGHIJ
#入力例3
3 4 3
#出力例3
ABC
DEFG
HIJ
#アドバイス頂いた結果
```java:
ns = gets.split.map(&:to_i)
str = "ABCDEFGHIJ"
i = 0
ns.each do |n|
  puts str[i, n]
  i += n
end
```
##このほかにも Array#shift で求めるコードも！
#以上！
【保存版】Flaskで画像を操作する際の6パターンを書き分ける



[Flask上で画像を操作する際のソースコードのパターンについての記事は移動しました。](https://np-sys.com/general/%e3%80%90%e4%bf%9d%e5%ad%98%e7%89%88%e3%80%91flask%e3%81%a7%e7%94%bb%e5%83%8f%e3%82%92%e6%93%8d%e4%bd%9c%e3%81%99%e3%82%8b%e9%9a%9b%e3%81%ae6%e3%83%91%e3%82%bf%e3%83%bc%e3%83%b3%e3%82%92%e6%9b%b8/)
seedで初期データを生成するコードで使ったメソッド

#はじめに
　先日、投稿した「[初期データをseeds.rbに記述して、ゲストログイン機能のエラーを解決してみた](https://qiita.com/TerToEer_sho/items/497030d3acd60342da18)」でseeds.rbに初期データを作成したときに使ったいくつかのメソッドについて、説明する。

##基本の書き方
```ruby:seeds.rb
モデル名.メソッド(カラム名: 値)
```

###create!
基本は、これかと…
単純に、「作って！」というやつ。
同じidや一意性のバリデーションによってエラーになることもあるので、注意が必要。
###first_or_create_by!
中学英語みたいだが、`first`と`or`とつくので、
「id=1が存在しなければ、作るよ！」みないな意味。
つまり、初期データを作成する、ターミナルで`rails db:seed`を行う前に、データが存在すると、seed.rbで作成したデータは保存されない。

###find_or_create_by!
同じく中学英語みたい。
「テーブルになければ、作るよ！」みたいな意味。

##おわりに
　idのカラムを指定することができるが、その後に、生成するidが、seeds.rbで指定したidからの連番になってしまう。
ex)id=100をseeds.rbで記述していると、その次に情報を保存すると、id=101になる。
アジャイルチームをどう評価すればいいの??

## Agile Japan 2020
[アジャイルチームの成果指標設計、進め方と注意点
-開発チームの事業貢献を見える化するには](https://2020.agilejapan.jp/session.html#)

の感想になります。

- [講演資料](https://2020.agilejapan.jp/pdf/DAY1_CH2_1100.pdf)

## 生産性には２つの種類がある
- 物的生産性
    - 単位あたりの産出量
- 付加価値生産性
    - 産出量あたりの付加価値
    - アジャイルな開発で求めているのはこっち

どの企業もアジャイルに取り組む理由は

- ユーザーが求めているものを早く取り入れたい
- 試行錯誤のサイクルを早く

が大きいと思います。

アジャイル開発をやって見たいからという理由で取り組んでいるところは少ないはず...

### チームの評価指標は何を設定している？

今まではこのような指標がメインとなっていました。

- ベロシティ(スプリントごとのストーリーポイントカード消化数)の向上
- とにかく早くリリースできるように

決して間違っていないと思うのですが、
この評価指標は`付加価値生産性`ではなく`物的生産性`に該当するかと...

これでは、アジャイル開発を導入しようとした理由とチームの目標はずれてしまっています。
ここは講演を聞いて「確かに...」と。


## チームのレベルに合わせて評価指標を設定すべし

- レベル１
    - スプリントを正しく回せているか
    - フレームワークに則って作業できているか
- レベル2
    - フレームワークに則って作業できているか
    - 事業KPIに紐づいた指標
- レベル3
    - 事業KPIに紐づいた指標

### レベル1

レベル1のチームは簡単にいうと初心者チームです。
チームに何名かアジャイル経験がないメンバーがいる状況をイメージしてください。

このようなチームには以下の点を指標にします。

- スクラムイベントを実施できているか
- PBIの見積もりは正しいか
- PBIのユーザーストーリー、受け入れ条件はReadyの状態でスプリントプランニング迎えることができているか
- ベロシティが上昇しているか
- スプリント内に発生する追加タスク(スプリントバックログ)は多くないか
- スプリントの中断はしていないか
- レトロスペクティブで決めたTRYを実施し、効果が現れているか

「うちのチームちゃんとスクラム(アジャイル)開発できてるよね。」って言えるチームになるのが目標です。
フレームワーク通りにできていないチームが事業の目標の話をしたって、チームがバラバラになるだけです。
まずは形だけでもできるようになりましょう。


### レベル2

レベル2のチームは当たり前にフレームワーク通り実施できるようになってきたチームです。

このようなチームには以下の点を指標に追加にします。

- 事業価値に繋がるものをリリースできているか

この指標は`「リリースできているか」`が含まれているので、大前提としてチームが作成したプロダクトがリリースされていることが重要となります。

ようやく、アジャイルを導入するなかで重要な点である「付加価値生産性」が指標として追加されます。

ある程度成熟してきた段階で、付加価値生産性ってどう評価されているか気にします。
結局、ユーザーが求めているプロダクトをつくれているかはリリースしてみないとわかりません。
だからこのタイミングで指標に追加します。


### レベル3

レベル3のチームはベテラン軍団です。
メンバーの変更もほとんどなく継続してスプリントを回せているチームです。

このようなチームには以下の点を指標にします。

- 事業価値に繋がるものをリリースできているか
- ユーザーの利用率がUPしているか
- ユーザーからの評価はどうか

レベル2と同様に、リリースしたプロダクトについての評価がメインになります。
まさに事業レベルの指標です。


## まとめ(感想)
### チームの成長具合によって、評価する基準を変えてあげること。

今まで開発メンバーとして参加していた私は正直レベル１のことしか考えていませんでした。
理由は以下になります。

- リリーススパンが長い
    - そもそもリリース一度もしていない
    - 単純に遅い
- メンバーの入れ替えが激しい

こんな状態でした。
まずは最小構成でもいいからリリースしてみる、可能な限りメンバー交代しないことがレベル2へレベルアップできる近道ではないかと思いました。

### 他のチームと比べて評価しない

- 同じプロダクト
- 同じ状況

なチームは2つ以上存在しないと思います。
比べることよりも、そのチーム自体が成長しているかを評価した方が何倍も価値があると思います。
同じ条件でないチームを比べるのは簡単そうではありますが、難しすぎると思います。

### 開発メンバー1人ずつ評価するのは極力さける

よくあるのは`ゴリラ`なメンバーがいる場合です。

`ゴリラ`は技術力もあり、その人が発言してしまったらその意見をすぐ採用されてしまうような人です。
このような`ゴリラ`が誕生してしまうのは**開発メンバー1人ずつ評価している**からなのではだと思います。

その人に聞けば問題ない、助けてくれるというのは非常にいいことですが、偏りすぎると悪影響です。
特にその`ゴリラ`がチームから離脱することになると大変なことになります。

メンバー１人ずつではなく、チームとしてどうなのかを評価していけば`ゴリラ`的な存在ではなく、`リーダー`的な存在が誕生するのではないでしょうか。

### 定期的に指標となるものを決めるイベントを設ける

ただスプリントイベントを回していてもチームメンバーは今どこを評価されているのか意外と把握出来ていません。
3ヶ月くらいの間隔で今のチームが求められてるものは何なのかをチームメンバーだけでなく、ステークホルダーと話して、明確な指標を作成して行くべきなのではないかと思った。

やっぱり人間は明確なゴールや基準があると頑張れる気がする。

### まだまだアジャイル、スクラム知らんなぁ

AgileJapanに参加するまでは、スプリントイベントを回せていれば十分だろって思っていたところもあった。
私はレベル1のチームしか経験したことないので、まずはレベル2のチーム作りをしていきたい。
PHP8をWindows10にインストールする

PHP8をWindows10にインストールします。64bit版

## Visual C++ 2015-2019 再頒布可能パッケージのインストール

PHP8を動かすには、**Visual C++ 2015-2019 再頒布可能パッケージ** のインストールが必要です。
事前にインストールしてください。

直リンク：https://aka.ms/vs/16/release/vc_redist.x64.exe
公式ヘルプ：https://support.microsoft.com/ja-jp/help/2977003/

## PHP8 のダウンロード

PHP公式サイトから、PHP8 をダウンロードする。

https://windows.php.net/download/

いろいろありますが「**VS16 x64 Thread Safe**」のzipファイルを選択します。
解凍したら、今回は``C:/php``に配置するとします。

## php.ini の設定
PHPの設定ファイルを編集します。

PHPフォルダにある``php.ini-development``を複製し、``php.ini``と名前を変更します。

そしたら``php.ini``を開いて編集します。
設定については詳しく説明しませんが、代表的な設定例を紹介しておきます。
行頭の``;``を削除すると設定が有効になります。

```
;タイムゾーン
date.timezone = "Asia/Tokyo"

;エクステンションフォルダをフルパスで
extension_dir = "C:/php/ext"

;必要に応じて各種エクステンションを読み込む
extension=mbstring
extension=gd
```

## 環境変数の設定

環境変数のPathにPHPのパスを追加する作業です。

スタートボタンを右クリック → **検索**。
検索ボックスに``環境変数``と入力して、「環境変数を編集」を開きます。

![名称未定-12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/70356/a39bd946-07e8-1978-9eb7-b3bdf910ef38.png)
ユーザ環境変数にある``Path``を編集する

![名称未定-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/70356/287d90bd-88ea-fe4e-4a82-40cd3d9fa387.png)
PHPのパスである``C:/php``を新規に加えてください

## 動作確認

PHPが正常に動作するか、コマンドラインから確認する作業です。

スタートボタンを右クリック → **PowerShell** を起動。
コマンドに``php -v``と入力して、次のように表示されればOKです。

![名称未定-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/70356/6acbf718-a2ec-9950-5433-2bbdcad49365.png)


## Apache の設定
PHPをApacheに組み込む設定を行います。

Apacheの``conf/httpd.conf``を開いて、ファイルの最後に次の３行を加えてください

```
LoadModule php_module "C:/php/php8apache2_4.dll"
PHPIniDir "C:/php/"
AddHandler application/x-httpd-php .php
```

これでApacheを再起動すれば、PHPが読み込まれます。
``phpinfo();``などで動作確認してみよう。

### エクステンションが読み込めない場合
ApacheからPHPのエクステンションが読み込めない場合は、次のことを試してください。

- php.iniの``extension_dir``がフルパスになっているか確認する
- curlを利用する場合は``php/libssh2.dll``を``apache/bin``にコピーする
- sqlite3を利用する場合は``php/libsqlite3.dll``を``apache/bin``にコピーする
GoのEchoでオリジン間リソース共有の問題を解決

# やりたいこと
フロント側の `http://localhost:8080/` からバックエンド側の `http://localhost:8080/` を呼び出したい
しかし以下のエラーがフロント側で出ていたので、これを解決したい

```
Access to XMLHttpRequest at 'http://localhost:8000' from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
```

オリジン管理ソース共有に関してはこの記事では解説しませんが、 [こちらの記事](https://qiita.com/att55/items/2154a8aad8bf1409db2b) がわかりやすかったです

## 環境情報
- vue
    - 2.6
- go
    - 1.15
    - echoをサーバーとして使用

# 解決方法
以下の設定を追加

```
e := echo.New()

// 以下を追加
e.Use(middleware.CORSWithConfig(middleware.CORSConfig{
    AllowOrigins: []string{"http://localhost:8080"},
    AllowMethods: []string{http.MethodGet, http.MethodPost, http.MethodPost, http.MethodDelete},
}))
```

無事フロント側からアクセスできる様になりました！

# 参考
- なんとなく CORS がわかる...はもう終わりにする。
    - https://qiita.com/att55/items/2154a8aad8bf1409db2b
- CORS Middleware
    - https://echo.labstack.com/middleware/cors
reactで別のコンポーネントを引数を渡しつつ呼び出す場合


## 呼び出す側
`<コンポーネント名 props名="値"/>`の要領で書く

```react
<td><GetPod name="vamdemic111aaa-app"/></td>
```

## 呼び出される側
- propsに入る
- `this.props.name`で使うことができる


```react
class GetPod extends Component {
    constructor(props) {
        super(props);
        this.state = {
            podstatus: ''
        }
    }

    // renderの前に実行される
    componentWillMount() {
    const json = {"Name":this.props.name};
    const convert_json = JSON.stringify(json);
    const obj = JSON.parse(convert_json);
    console.log(obj)
    console.log(this.props.name)
    const request = axios.create({
        baseURL: "http://127.0.0.1:1323",
        headers: {
            'Content-Type': 'application/json',
        },
        responseType: 'json',
        method: "GET"
   })

   request.get("/getpodstatus", obj)
        .then(request => {
           this.setState({
               // podstatus: request.data.items[0].status.phase
               podstatus: request.data.items[0].status.phase
           })
           console.log(this.state.podstatus)
       })
    }

    // コンポーネントが呼ばれたらstateを返すようにする
    render() {
        return <p>{this.state.podstatus}</p> ;
    }
}

```
【macOS】スクロールできるNSTextViewを生成する

macOSアプリを開発する中でNSTextViewを使っているにも関わらず、（テキストが表示領域より多くなっても）スクロールできない問題に悩まされたので、その解決法を紹介します。

# 問題

コードでNSTextViewを生成＆追加するとき、以下のようにするとテキストが下端まで行ってもスクロールすることができません。

```swift
// スクロールできないTextViewの例

class ViewController: NSViewController {
    private let textView = NSTextView()

    override func viewDidLoad() {
        super.viewDidLoad()

        view.addSubview(textView)

        // ウィンドウいっぱいにTextViewを設置
        textView.translatesAutoresizingMaskIntoConstraints = false
        textView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
        textView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
        textView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
        textView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
    }
}
```

# 解法

スクロールできるNSTextViewを生成するためには、`NSTextView.scrollableTextView()`メソッドを使い、以下のように実装するとうまくいきます。

```swift
// スクロールできるTextViewの例

class ViewController: NSViewController {
    private let scrollView = NSTextView.scrollableTextView()

    private lazy var textView: NSTextView = {
        let view = scrollView.documentView as! NSTextView
        return view
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        view.addSubview(scrollView)

        // ウィンドウいっぱいにTextViewを設置
        scrollView.translatesAutoresizingMaskIntoConstraints = false
        scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
        scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
        scrollView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
        scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
    }
}
```

## NSTextViewを継承したクラスの場合

NSTextViewを継承したカスタムTextViewの場合でも、同様に`scrollableTextView()`メソッドを使用することで`textView`オブジェクトを取り出して扱えます。

```swift
// カスタムTextView
class MyTextView: NSTextView {
    ...
}

class ViewController: NSViewController {
    private let scrollView = MyTextView.scrollableTextView()

    private lazy var textView: MyTextView = {
        let view = scrollView.documentView as! MyTextView
        return view
    }()

    ...
}
```



# 参考
https://stackoverflow.com/questions/58426739/nstextview-scrolling
hugoのshortcodesで湯婆婆

## はじめに

だいぶ乗り遅れた感はあるのですが、hugoのshortcodesでやってる人はみつからなかったので、チャレンジです。
hugoはmarkdownから静的なhtmlを生成するツールですが、生成過程でちょっとした独自のスクリプトを定義して使えます。

## 下準備

新しいサイトを作成します。

```console
$ hugo new site yuba-ba
```

適当なテンプレートをダウンロードします。
今日はhermitを使うことにします。

```console
$ cd yuba-ba
$ git clone https://github.com/Track3/hermit.git themes/hermit
```

config.tomlも書き換えます。

```toml:config.toml
baseURL = "http://example.org/"
languageCode = "ja-jp"
title = "湯婆婆"
theme = "hermit"
```

## コード

layouts/shortcodesの下にyuba-ba.htmlという名前で作ります。

```html:layouts/shortcodes/yuba-ba.html
{{ $name := .Get 0 }}
{{ $new_name := index (split $name "" | shuffle) 0 }}

契約書だよ。そこに名前を書きな。<br />
フン。{{ $name }}というのかい。贅沢な名だねぇ。<br />
今からお前の名前は{{ $new_name }}だ。いいかい、{{ $new_name }}だよ。分かったら返事をするんだ、{{ $new_name }}!!<br />
```

呼び出す方も作成します。

contents/index.mdを作成します。

```md:contents/index.md
---
title: "湯婆婆"
date: 2020-11-26T13:00:00Z
draft: false
---
{{< yuba-ba 山田太郎 >}}
```

## 実行

```console
$ hugo server --bind=0.0.0.0 -b http://example.org:1313
```

ブラウザでアクセスしてみます。

![yubaba1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245486/31d64957-5643-7a01-c655-fffce52de59c.png)

いい感じです。

## 湯婆婆エラー

```md:contents/index.md
---
{{< yuba-ba >}}
```

に変えてみます。

![yubaba2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245486/66ca745e-87a6-16a3-704e-4208492c811b.png)

おっと、エラーになりません。
仕切り直しです。

## エラー処理

エラー処理を入れるのは本望ではないのですが、なかなかいいやり方が見つからなかったので妥協します。

```html:layouts/shortcodes/yuba-ba.html
{{ $name := .Get 0 }}
{{ if eq $name nil }}{{errorf "湯婆婆エラー"}}{{end}}
{{ $new_name := index (split $name "" | shuffle) 0 }}

契約書だよ。そこに名前を書きな。<br />
フン。{{ $name }}というのかい。贅沢な名だねぇ。<br />
今からお前の名前は{{ $new_name }}だ。いいかい、{{ $new_name }}だよ。分かったら返事をするんだ、{{ $new_name }}!!<br />
```

## 湯婆婆エラー リベンジ

![error.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245486/8096d2da-3564-91ca-4cba-bf545fe3d8b6.png)

できました。

## おわりに

なんとかできましたが、エラー処理を書いてしまったので、ちょっと負けた気分です。
【Java】インターフェイスを実装するimplementsについて

#プログラミング勉強日記
2020年11月25日
インターフェイスを継承してクラスを定義するときに必要なimplementsについてまとめる。

#implementsとは
　implementsの説明をする前にインターフェイスの説明を簡単にする。インターフェイスは、メソッドの戻り値とメソッド名、引数といった使用のみを定義したもので、実際の処理を持たないクラスのようなものである。intefaceを使って型宣言を行うことはできるが、メソッドの定義がないとプログラムは実行できないので、そこでimplementsを使う。つまり、インターフェイスに定義されているメソッドを定義しているクラスであると指定する。
　仕様を言い換えると約束事で、約束通りの使い方をすると約束通りの結果になるということをあらかじめ決めておくことで、そのメソッドを使う側は実際の作りを気にしなくてよく、そのメソッドを作る側は仕様さえ守ればいつでも好きなように実装を変えることができる。

#implementsの書き方
　あるクラスにインターフェイスを実装するには下記のように、クラス名の後ろにimplementsを書き、さらにその後ろにインターフェイス名を書く。インターフェイスに抽象メソッドが定義されているならクラスではその抽象メソッドの内容を実際に作る抽象メソッドの実装をしないといけない。(実装しないと、コンパイルエラーになる。)
　抽象クラスにインターフェイスを実装する場合は、インターフェイスの抽象メソッドの実装は必要ない。

```java:implementsの書き方
class クラス名 implements インターフェイス名 {
}

// 抽象メソッドが定義されている場合
class クラス名 implements インターフェイス名 {
 インターフェイスの抽象メソッド() {
 抽象メソッドの実装;
 }
}
```

　インターフェイスを複数implementsすることもでき、その場合はimplementsの後ろに実装したいインターフェイスを`,`(カンマ)で続ける。この場合は、<b>クラスで実装したいインターフェイスにあるすべての抽象メソッドを作成しないといけない</b>。

```java:インターフェイスを複数implementsする場合
class クラス名 implements インターフェイス名1, インターフェイス名2, ... {
 インターフェイス1の抽象メソッド() {
 抽象メソッドの実装;
 }
 
 インターフェイス2の抽象メソッド() {
 抽象メソッドの実装;
 }
 
}
```

#サンプルコード
　ボタンをクリックするごとにボタンのテキストの表示が変わるプログラムを作成した。

　アクションやイベントの処理に関連するクラスでは、ActionListenerというインターフェイスを実装する。そうしたクラスによって作成されたオブジェクトは、アクションやイベントが発生するとコンポーネントのaddActionListenerメソッドが呼び出される。

```java
package Sample;

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;

public class Sample extends JFrame implements ActionListener{
	private static final long serialVersionUID = 1L; 
	private JLabel L1;
	private JButton b1;
	
	public Sample() {
		setLayout(null); 
		this.setSize(200, 200);
		this.setDefaultCloseOperation(EXIT_ON_CLOSE); 
		L1 = new JLabel("テスト用ボタン");
		b1 = new JButton("Click me");
		L1.setBounds(50, 10, 100, 20);
		b1.setBounds(new Rectangle(50, 80, 90, 30));
		b1.addActionListener(this);
		
		this.add(L1);
		this.add(b1);
		this.setVisible(true);
	}

	public void actionPerformed(ActionEvent ev) {
		if(b1.getText() == "ON") 
			b1.setText("OFF");
		else 
			b1.setText("ON");
		
		System.out.println("you clicked");
	}

	public static void main(String[] args) {
		new Sample();
	}
	
}

```

#参考文献
[よくわかる! Javaのインターフェイスを実装する”implements”](https://engineer-club.jp/java-implements)
[インターフェースを実装！Javaでimplementsを使う方法【初心者向け】](https://techacademy.jp/magazine/17414)
UTC ベースで時間データを扱う: JavaScript 版  (IoTプログラミング)

「UTC ベースで時間データを扱う(IoTプログラミング)」
https://qiita.com/nanbuwks/items/e3714f6b0b6b0b8585f4

では C で　UTC を扱う記事を書きました。

今回は　JavaScript でUTCを扱う方法です。

# UNIX 時間 → Date オブジェクト

UNIX時間 1606323269 ( UTC 2020年11月25日 16:54:29 ) を worktime に格納しているとします。

これを JavaScript の Date スクリプトにして、更に文字列形式に変換し出力するには以下のようにします。

```
      worktime=1606323269;
      datetime = new Date(worktime*1000);
      stringline=(datetime.toLocaleString());
      document.write(stringline);

```

Dataオブジェクト内部には1970年1月1日からの時間が UTC ベースで格納されています。
UNIX 時間も1970年1月1日からの UTC ベースのカウントですが、UNIX 時間は秒単位なのに対し Date オブジェクトはミリ秒単位なので 1000 倍します。

これの出力は

```

2020/11/26 1:54:29

```
となります。日本の Timezone になって出てきましたね。

UTCとする場合には


```

      stringline=(datetime.toUTCString());

```

とし、出力は

```

Wed, 25 Nov 2020 16:54:29 GMT
```
となります。

しかしこの形式は日本でよく使われる YYYY/MM/DD hh: mm:ss 形式ではないですし、数値で月を表示して IoT　で処理しやすくしたい場合もあります。

UTC でなおかつ日本形式にしたい場合は先の toLocaleString を使い、

```

      stringline=(datetime.toLocaleString('ja-JP', { timeZone: 'UTC' }));
```
とすると

```

2020/11/25 16:54:29
```

が取得できます。
ELBのhealth checkが永久にunhealthに・・・

久しぶりに記事を投稿させて頂きます！やっとポートフォリオの作成が一段落して、転職活動中なのですが、一段落したので書かせていただきます。今回の内容は検索しても中々原因を見つけられず、たまたま原因を発見したので、初学者の方で同じように詰まっている方向けに簡単にアウトプット致します！

## 内容
今回railsで作成したポートフォリオをEC2上にnginxとともに立てました。それから、[acm](https://aws.amazon.com/jp/certificate-manager/)を利用するためにelbを導入したのですが、elbを立ててEC2上のnginxを再起動してもelbのhelth checkがunhealthに・・・。nginxのlistenポートやその他設定を何度確認するも分からず・・・。
  
## 原因
nginx側でhttp2を認識していないことが原因でした。これだけで半日使ってしまいました・・・

## 解決
elbの作成時にターゲットグループのprotcol versionを1に落として作成したところ解決しました！あと、試してはないのですが、[こちらの記事](https://qiita.com/Aruneko/items/8c11f9e45a33457c3c1f)でnginxをhttp2でlistenするようにした方がベターかもしれません！
【Ruby ~基本(コマンド/メソッド)~】勉強メモ

Rubyの復習。
ほぼ自分の勉強メモです。
過度な期待はしないでください。

Rubyファイル
-
Rubyファイルには、`.rb`という拡張子を付ける
<br>
irbコマンド
-
irbコマンドは、ターミナルから直接Rubyのプログラムを動かすことができる機能。
ちなみに、irbは「Interactive Ruby」の略。

```.text:ターミナル
sample@sampleMBP ~ % irb
// エンターキーで実行
irb(main):001:0> "Hello! こんにちは！"
// このように表示されれば成功
=> "Hello! こんにちは！"
// 終了するときは、exitと記述して実行
irb(main):002:0> exit
sample@sampleMBP ~ % 
```
<br>
rubyコマンド
-
rubyコマンドはRubyに関するさまざまな操作が実行できるコマンド。
Rubyファイルをプログラムとして実行するためには、
ターミナルに`ruby [実行したいRubyファイルのパス]`と打ち込む。

```.text:ターミナル
// Rubyファイルを実行するには、ファイルがあるディレクトリ迄移動する
// 今回で有ればsampleディレクトリにあるsample.rbというRubyファイルを実行
sample@sampleMBP sample % ruby sample.rb
"hello, GitHubDesktop."
```
<br>
出力命令
-
「puts "○○"」と書くと、putsの後の○○という文字がコンソールに出力される。

```.rb:×××.rb
# 文字の出力
puts "Hello World"
# 数値の出力
puts 77
# 数値の計算
puts 7 + 7
# 文字の連結
puts "Hello" + "World"
```

```.text:出力結果
Hello World

77

14

Hello World
```
<br>

入力命令
-
- getsメソッド

ターミナルに値の入力機能を起動するメソッド。
getsをコードに記述すると、記述した行を読み込んだ段階で入力機能が起動し、
ターミナル画面は入力待ちの状態になる。

ちなみに、getsメソッドで入力された値は、<b>末尾に改行がついた文字列</b>になる。

```.rb:×××.rb
input = gets

puts "明日の天気は#{input}です。"
```

```.text:ターミナル
~ % ruby ×××.rb
# 入力した文字
晴れ
# 出力結果
明日の天気は晴れ
です。
```
<br>

- chompメソッド

chompメソッドは、文字列の末尾に存在する改行を取り除いた文字列を返す。

```.rb:×××.rb
input = gets.chomp

puts "明日の天気は#{input}です。"
```

```.text:ターミナル
~ % ruby ×××.rb
# 入力した文字
くもり
# 出力結果 改行されずに1行で出力される
明日の天気はくもりです。
```
<br>

<br>
メソッド
-
- lengthメソッド

lengthメソッドは、文字列の文字数を数える。

```.rb:×××.rb
puts "Hello World".length
```

```.text:出力結果
11
```
<br>

- to_sメソッド

数値を文字列に変換する。
ちなみに、 to_sのsの意味は「string(文字列)」

```.text:ターミナル
# 数値「20」にto_sメソッドをつけて実行
irb(main):001:0> 20.to_s
=> "20"
```
<br>

- to_iメソッド

文字列を数値に変換する。
ちなみに、 to_iのiの意味は「integer(整数)」

```.text:ターミナル
# 文字列「30」にto_iメソッドをつけて実行
irb(main):001:0> "30".to_i
=> 30
```
<br>
バックスラッシュ記法
-
\(バックスラッシュ) から始まる文字の記法のこと。
バックスラッシュの入力は、`option + ¥`
バックスラッシュ記法が適応されるのは文字を "(ダブルクォーテーション)で囲んだときの。

\n で　→　改行

```.rb:×××.rb
puts "ようこそ！\n日本へ！"
```

```.text:出力結果
ようこそ！
日本へ！
```
Nginx について纏めてみる

Linuc2の学習のために、Nginxについて纏めてみる。
Apacheと同じぐらい利用するが、こちらもあまり細かな設定までは気にしたことがないので、纏めてみた。


# インストール

私は Amazon Linux2 を良く使いますが、Amazon Linux2 では標準で Nginx の yum 向けパッケージが提供されていません。

そのため、↓の手順で追加する必要がある。

[Amazon Linux 2にExtrasレポジトリからNginxをインストールする](https://dev.classmethod.jp/articles/install-nginx-on-amazon-linux2-from-extras-repository/)

# 主な設定ファイル

|ファイル|説明|
|---|---|
|/etc/nginx/nginx.conf|メイン設定ファイル|
|/etc/nginx/conf.d/default.conf|デフォルトサーバーの設定ファイル|
|/etc/nginx/conf.d/ssl/conf|SSLの設定ファイル|
|/etc/nginx/conf.d/virtual.conf|バーチャルホストの設定ファイル|

基本書式 ： `ディレクティブ　値;`

ブロック構造をとるディレクティブもあります。
**親ブロックで設定した内容は子ブロックにも引き継がれます。**

```
ディレクティブ{
  他のディレクティブ；　
　...
}
```

|ディレクティブ|説明|コンテキスト|
|---|---|---|
|include|他の設定ファイルを読み込む|全て|
|user|ワーカープロセスの実行ユーザー|main|
|worker_processes|ワーカープロセス数|main|
|worker_connections|1つのワーカープロセスが同時に処理できるコネクション数|events|
|log_format|アクセスログの書式定義|http|
|access_log|アクセスログのパスとログレベル|http,server,location|
|error_log|エラーログファイルのパスとログレベル|main,http,server.location|
|listen|リクエストを受け付けるポート番号|server|
|server_name|サーバー名|server|
|keepalive_requests|一度の接続で受け付けることのできるリクエスト数の上限|http,server,location|
|keepalive_timeout|キープアライブのタイムアウトまでの秒数|http,server,location|
|server_tokens|バージョン番号の表示|http,server,location|
|root|ドキュメントルート|http,server,location|
|index|インデックスファイル|http,server,location|
|autoindex|インデックスリスト表示のon/off|http,server,location|
|error_page|エラーコードとエラーページノURI|http,server,location|
|rewrite|リダイレクトの設定|server,location|
|fastcgi_pass|FastCGI サーバへリクエストをプロキシする|
|fastcgi_param|FastCGIサーバに渡すパラメータの設定を指定する|

コンテキスト内には様々なディレクティブでパラメータを指定します。

例えば、別のサイトへリダイレクトさせるには、次のように設定します。
※一時的なリダイレクトの場合は、permanent を redirect に書き換えます。

```
server {
  listen 80;
  server_name www.example.com;
  rewrite ^(.*)$ http://www.example.net$1 permanent;
```

# SSL/TLS

|SSL関連のディレクティブ|説明|
|---|---|
|ssl|onなら有効|
|ssl_certificate|サーバー証明書ファイル、中間CA証明書ファイル|
|ssl_certificate_key|サーバー秘密鍵ファイル|
|ssl_protocols|バージョン|
|ssl_ciphers|暗号アルゴリズム|

```:nginx.conf
http {
  ssl_ciphers:ECDHE-RSA-AES128-SHA;
  ssl_protocols TLSv1.2;
  ssl_prefer_server_ciphers on;
  ssl_session_tickets off;
  ssl_stapling on;
  ssl_stapling_verify on;
}

server {
  ssl on;
  listen 443 ssl;
  server_name www.example.com;
  ssl_certificate ssl/server.crt;
  ssl_certificate_key ssl/server.key;
  root /var/www/html;
  location / {
    index  index.html index.htm;
}
```

[Nginx で ssl_protocols や ssl_ciphers を省略するとどうなるのか？](https://qiita.com/QUANON/items/ea5eb0cde586fe253d00)

# リバースプロキシ

|リバースプロキシ関連のディレクティブ|説明|
|---|---|
|proxy_pass|プロキシ先URI|
|proxy_http_version|httpのバージョン|
|proxy_set_header|プロキシ先に送られるリクエストヘッダの定義|

```:nginx.conf
server{
　　listen 80 default_server;
    server_name www.example.com;

    location / {
        proxy_pass    http://192.168.0.1;

        proxy_set_header    1.1;
        proxy_set_header    Host $http_host;
        proxy_set_header    X-Real-IP $remote_addr;
        proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}
```

クライアントからのアクセスではなく、リバースプロキシからのアクセスが記録されてしまいます。
そこでヘッダーを書き換えて、本来のアクセス元をWebサーバーが記録できるようにするためには、
**proxy_set_header** ディレクティブで、Hostヘッダ、X-Real-IPヘッダー、X-Forwarded-Forヘッダーを定義します。
pythonエンジニア認定基礎試験に合格した

#受験のきっかけ
就職活動の際に、面接でpythonを使ってアンケートを分析したことがあると言ったら、面接官の方から「python認定エンジニア試験を受験してみたら？」と勧められたので。当時、IT系の資格を一つも持っていなかったのも受験の動機でした。

##勉強を始める前のレベル
PyQと言うpythonを学べるサイトで基本的な文法やデータ分析について一通り学んでおり、一定の知識は身に付いている程度。ただ、文法は自信がないが調べながらなら相関や決定木を実装できました。

#勉強方法
pythonチュートリアルを読みながら、理解できないコードを実際に動かしながらやってました。テキストにあるコードを頭の中でどのような処理がされるのか、を自分で理解するまで動かしました。デバック機能を使いまくり、とにかく納得するまでやるのが良いかなと思います。
一通りテキストを読んで、コードを動かしたあとは公式ホームページにある模擬テストを一日一回やってました。間違えた問題をどこが間違っているのか、なんで正解したのかを徹底的に分析したのが重要だと思います。あと、問題は必ずテキストを基に作られているので、間違えた問題を参考にテキストにマーカーを引いて、後日見直しをしました。

#実際に受験して
1000点中の900点でした。残りの100点、何を間違えてたんだ。時間は60分ありますが、見直ししても30分ほど余裕がありました。すぐに結果がわかるので、終了のタイミングを伸ばし伸ばしにしてしまいます。
受験日は会場によってはほぼ毎日受けられるところもあるので要確認です。一番最初に受験日を決めて勉強するのが良いと思います。
Node.js基礎　備忘録


#リクエストの対処する仕組み

##スレッドモデル(Apache)

リクエストが来た際にスレッドを作成して対応する
※スレッドは同時にひとつのリクエストしか処理できない。
新しいリクエストが来た際には、新しいリクエストを作成して対応する

###問題
スレッドを作成するとメモリを消費するため、スレッドの作成限界がある。
リクエストが多い場合、スレッドが立ちあげれず、リクエストが待ち状態になる。

##イベントループ(Node.js)

メインスレッドとバックスレッドの２つがあり、動作している。

メインスレッドには、処理待ちのキューがあり、リクエストが来た際には、キューに登録する。
※新しくスレッドは作成しない

キューをループで回し、バックグランドで動くスレッドに渡し、そちらで処理を実行していく。

###プログラムを書く際は、ループをブロックしないように記述する。(Non-blocking)
時間がかかりそうな処理は、コールバック関数で実装する


メインで動くスレッドが、新規に作成されない為、シングルスレッドと呼ばれる。
Windows環境でなるべく汚さずPython環境を乱立させる。

# 0. はじめに
## 0-1. やること
Windowsで出来る限り環境を汚さず、Python環境を乱立させます。

## 0-2. 動作検証環境
Window 10 Pro Ver 1909 (Build 18363.1198)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/210304/c40dc008-1ed6-ebb8-7230-a7d5df9f1688.png)

# 1. 手順
## 1-1. 作業フォルダの作成
お好みでフォルダを作成する。

```
C:\Python
├　env　←Python格納フォルダ
└　project　←スクリプトファイル(*.py)格納フォルダ
```


## 1-2. Pythonのダウンロード
以下のURLより、使用したいバージョンの「embeddable zip file」をダウンロードする。
例：python-3.8.6-embed-amd64.zip
https://www.python.org/downloads/windows/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/210304/a03beae8-eb10-c707-c46d-55316cf591c0.png)

## 1-3. 資材の格納
ダウンロードしたzipファイルを解凍し、envフォルダ配下に格納する。
env直下にpython.exe等を配置するのではなく、お好みの環境名称のサブフォルダを切って格納してください。
以下の例では、「python-3.8.6」という名称のフォルダ配下に個々のファイルがあるイメージです。

```
C:\Python
├　env
│　└　python-3.8.6　←例えば、「python-3.8.6」という名称のフォルダにして格納する。
└　project
```

## 1-4. 起動用batの作成
デスクトップ等、起動しやすい場所に以下を作成する。
1-3で作成した環境名(フォルダ名)をbatファイル名にしてください。

``` python-3.8.6.bat
@echo off
cls

set envname=%~n0
set work_dir=C:\Python\project
set python_dir=C:\Python\env\%envname%
set script_dir=C:\Python\env\%envname%\Scripts

set PATH=%python_dir%;%script_dir%;%PATH%
cd /d %work_dir%

cmd /k title %envname%
```

## 1-5. pipのインストール
### 1-5-1. get-pip.pyの取得
以下のURLよりget-pip.pyをダウンロードし、projectフォルダに格納する。
https://bootstrap.pypa.io/get-pip.py

```
C:\Python
├　env
│　└　python-3.8.6
└　project
　└　get-pip.py
```

### 1-5-2. コンフィグ修正
C:\Python\env\python-3.8.6\python38._pthをテキストエディタで開き、5行目のコメントアウトを解除(#を削除)する。
フォルダ名・環境名は適宜読み替えてください。
python**._pthの**はPythonのバージョンにより異なります。
(Python 3.8.*ならpython38._pth、Python 3.9.*ならpython39._pth)

### 1-5-3. get-pip.pyの実行
で作成したbatを起動し、pipをインストールする。

```
> python get-pip.py
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/210304/c623166e-ea67-94a4-096a-1cd813de12f5.png)

# 1-6. 環境を乱立させる！
同様の手順でenv配下にお好きな環境を作成する。
削除したければフォルダ削除でOK。
環境の起動(切り替え？)は1-4で作成するbatの選択を変えるだけ。
(batのフォルダ名とenv配下のフォルダ名を合わせるだけ)

```
C:\Python
├　env
│　├　python-3.8.6
│　├　python-3.7.9
│　├　myenv1
│　├　myenv2
│　└　myenv3
└　project
　└　get-pip.py
```

# 2. ポイント
* embeddable版にはインストール版と異なる制約もありますが、ちょっと触ってみるくらいであれば問題なさそうです。
* python資材そのものを分けて使用する為、venv等の仮想機能は使用しません(できません)。その代わり、バージョン自体を混在させる(Python 3.7とPython 3.8等)ことは容易です。
* 資材を置くだけなので本来はフルパスで呼び出すかパスを通さないと実行できません。この手順内ではbatで環境変数をいじっていますが、同プロンプト内でしか有効になりません。(故に環境を汚しません)
* 意図した環境が動いているか自信がない場合には、pip -Vコマンドを実行すればインストール先フォルダパスも表示されるので確認できます。(一応コマンドプロンプトの枠にも表示しています。)
* 環境名(フォルダ名)を変更した場合には、pipを再インストール(get-pip.pyを再実行してください。
* project配下に自作のスクリプトを格納していくイメージです。同フォルダ内の別スクリプトファイルをimportする場合には、適切にパスを追加するか、各環境のフォルダ直下に以下のpthファイル(ファイル名は任意)を作成しておけば解消できるようです。

``` python:current.pth
import sys; sys.path.append('')
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/210304/f82f9c89-6375-ca16-5c60-7d275facbb0f.png)

# 3. 参考
Windowsで環境を極力汚さずにPythonを動かす方法 (Python embeddable版)
　https://qiita.com/rhene/items/68941aced93ccc9c3071
超軽量、超高速な配布用Python「embeddable python」
　https://qiita.com/mm_sys/items/1fd3a50a930dac3db299
CoreMLモデルのサイズを小さくする量子化でモデルの精度はどう変わるのか

モバイルに載せるなら、モデルのサイズは小さいほうがいいと思う。
量子化とは、重みパラメータを、例えばFloat_32からFloat_16にして早めの桁で切り上げるようにすること。

**実際のモデルを量子化して、どれくらいサイズが小さくなるのか、精度はどう変わるのか、をやってみた。**
![スクリーンショット 2020-11-25 23.04.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/e8dd8d36-17b6-cb55-b97d-f093a4f3c5e9.png)

deeplabv３のxeptionバックボーンバージョンでセマンティックセグメンテーションを比較（背景ぼかし）。

xeptionバックボーンのdeeplabv３のmlmodelのサイズは165.１MB。
MobileNetバックボーンだとModelが8.6MBなので、xeptionの方が精度はずっといいとはいえ、さすがにもうちょっと小さくしたいところ。

#CoreMLModelの量子化の方法

```shell
from coremltools.models.neural_network import quantization_utils

# 可能な値はnbits = 16, 8, 7, 6, ...., 1
nbits = 16
quantized_model = quantization_utils.quantize_weights(model, nbits)
coremltools.utils.save_spec(quantized_model, 'quantizedDeepLab.mlmodel')
# Tips： 量子化したmlmodelは、なぜか.save（Path）メソッドが使えないので、coremltools.utils.save_specで保存します。
```
#結果
|モデル  |サイズ（MB）  |速度（s） |使用メモリ（MB）|
|---|---|---|---|
| Float32 |165.1|315  |477|
| Float16 |82.6  |2.72  |477|
| Float8 |41.8  |2.77  |477|

**モデルのサイズは見事に半分半分になった。**
しかし、実行速度と使用メモリは変わらなかった。

さて、セグメンテーションの精度はというと・・・



左から【オリジナル】　　【Float32】　　　【Float16】　　　　　【Float8】
　　　　　　　　　　　　１６５MB　　　　８２MB　　　　　　　４１MB
![IMG_2906.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/fd033694-5c7e-73d5-a000-7c873b212e9c.jpeg)![x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/e300283d-ea39-41ce-7450-3c09b80ce3a0.png)![１６.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/65624015-07e0-c58a-7062-7346b52c682f.png)![８.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/802cc2d4-cb36-fd25-aaf2-8c0d4e8ee19c.png)

おわかりいただけたであろうか？
**３２と１６ではほぼ全くセグメント精度は変わらない。
「８だとさすがに雑になるでしょ」と思いきや、あにはからんや、これもほとんど変わらない。**
よく見ると右下の花をぼかしが少し侵食しているが、これくらいなら十分３２と同じように使える。

**バンドルするモデルのサイズを小さくしたければ、量子化は有効な選択肢になると思う。**
他のタスクでどう違ってくるのかは試してないけど。
＊今回はLinearというデフォルトの量子化方法を使った。Coremltoolsの引数で別の種類も選択できるらしい。

🐣
****

お仕事のご相談こちらまで
rockyshikoku@gmail.com

Core MLを使ったアプリを作っています。
機械学習関連の情報を発信しています。

[Twitter](https://twitter.com/JackdeS11)
[Medium](https://medium.com/@rockyshikoku)