OmniAICreator/Qiita-1.07M huggingface dataset:
バッチファイル＆VBScriptでフォルダマウントとリネーム処理（パス名変更）を自動化する

業務PCをキッティングする際にいちいちGUIで社内ファイルサーバをネットワークドライブのマウントして...フォルダ名（パス表示）を変更して...っていう作業って面倒ですよね。面倒な作業をぱぱっとバッチファイルとVBScriptでやってしまう方法をお試ししたいと思います。

# イメージ
Before
![フォルダリネーム.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/655033/fdc82215-0d29-981d-a4ef-88e7898ad202.png)



Bfter
![スライド2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/655033/90cb5062-c633-83aa-fe0e-51a44107c49e.png)


# 今回のゴール
バッチファイルとVBScriptを利用し、ワンクリックで、フォルダマウントおよびマウントしたフォルダのリネーム処理を行う。


# 前提
 - Windows OS環境
 - ネットワークドライブにマウントできるユーザ権限があること
 - セキュリティソフトなどでVBScriptの動作制限がされていないこと


# やってみた

まずネットワークドライブにマウントするためのコマンドを記述したバッチファイルを作りましょう。
メモ帳などを開き、以下コマンドを記述後に、拡張子を[.bat]で保存してください。

    #新規にネットワークドライブをマウント
    net use Z: \\192.168.0.233\d\大阪本社
    #マウントしたフォルダ名（パス名）をVBScriptで「大阪本社（Z:)」に変更
    cscript.exe "Renamefolder.vbs" Z "大阪本社"

\\192.168.0.233\dの部分は実環境に合わせて変更してください。

次にリネーム処理をするVBScriptファイルを作成します。
同じくメモ帳を開いて、以下コマンドを記述後に、ファイル名=Renamefolderで、拡張子を[.vbs]にして保存してください。
ちなみにVBScriptファイルは以下の中身変えずにこのままで動作します。

    ' ネットワークドライブのボリュームラベル変更
    ' 第一引数： ドライブレター 
    ' 第二引数： 変更したい名前

    Dim oParam
    Set oParam = WScript.Arguments

    strDrive = oParam(0)&":\"
    strName = oParam(1)

    With CreateObject("Shell.Application").NameSpace(strDrive)
    .Items().Item().Name = strName
    End With

あとはこの２つのファイルを同じフォルダに格納してください。

バッチファイルを動作させれば、VBScriptファイル（Renamefolder.vbs）を動作させにいき、ワンクリックでマウントしたフォルダをリネーム処理して、フォルダ名（パス名）を変更することができます。

# おわりに
他にも色々とやりようはあるのでは？と思いますが私の技術力の問題で、これが限界でしたm(_ _)m
バッチファイルの中のコマンドでフォルダ名リネーム処理までできればいいのですが、仕様上できないみたいですね...なんか方法ないかなと探してたどり着いたのがVBScritpでした。そしてコードの書けない哀れなSEさん（自分）なりに頑張ってみましたので、お役に立てれば幸いです。
~~コードの書ける人はもっと初心者に優しい記述をお願いしたい(´;ω;｀)~~
拡張子を .zi_ から .zip へ変更し、ZIP 形式のファイルを解凍する

自分で使用するために、以下の記事のバッチファイルを書きなおしました。

　[拡張子 .zi や .zi_ を .zip にするバッチファイルをつくってみた](https://qiita.com/kob58im/items/eaa2a2ff6475a80fbc90)

```bat:2021-02-22.bat
@echo off

set SELF=%~n0
set HELP=Usage: %SELF% FILE

setlocal
  set SOURCE=
  set TARGET=
  
  if "%~1" == "" (
    echo %HELP% >&2
    exit /b 1
  )
  if not exist "%~1" (
    echo %SELF%: file not found >&2
    exit /b 1
  )
  
  :: Outlook Message Attachments folder
  :: e.g. %LOCALAPPDATA%\Microsoft\Windows\INetCache\Content.Outlook\[0-9A-Z]{8}
  set SOURCE=%~dp1
  set SOURCE=%SOURCE:~0,-1%
  set f=%~n1
  set e=%~x1
  
  if not "%e%" == ".zi_" (
    echo %SELF%: file extension not match >&2
    exit /b 1
  )
  
  if not defined "%TARGET%" (
    set TARGET=%USERPROFILE%\Desktop
  )
  
  copy "%SOURCE%\%f%%e%" "%TARGET%\%f%.zip" > NUL || (
    echo %SELF%: failed to copy file >&2
    exit /b 1
  )
  
  if not exist "%TARGET%\%f%.zip" (
    echo %SELF%: file not found >&2
    exit /b 1
  )
  
  tar -xf "%TARGET%\%f%.zip" || (
    echo %SELF%: failed to extract file >&2
    exit /b 1
  )
  
  exit /b 0
endlocal
```
deviseでメールアドレスとパスワード以外をDBに保存する方法

#ユーザーの名前をDBに保存する方法
deviseではDBに保存できるカラムが決まっています。なので他のカラム情報をDBに保存する際は、ストロングパラメーターの設定が必要です。
設定はapp/controllers/application_controller.rbに記述します。
※deviseのコントローラーの処理を記述する時は、application_controller.rbに記述すると良いです。

```app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  before_action :configure_permitted_parameters, if: :devise_controller?

  private
  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up, keys: [:name])
  end
```

上記のように記述します。
まず、

```app/controllers/application_controller.rb
before_action :configure_permitted_parameters, if: :devise_controller?
```
この一文ですが、deviseのコントローラーから呼び出されたかどうかを記述しています。

```app/controllers/application_controller.rb
private
  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up, keys: [:name])
  end
```
そして、deviseのコントローラーから呼び出された場合、ユーザーの名前もDBに保存することを許可しています。
ちなみにconfigure_permitted_parametersは慣習的な記述なので自由に決めても問題ありません。

今回は、name・・・つまりユーザー名をDBに保存する許可をしましたが、age・・・年齢、birthplace・・・出身とか必要な許可をしてあげることが出来ます。
WindowsはなぜCドライブに入っているのか

# はじめに
昔話です。こういう細かいことが気になって先に進めなくなる人が、一人でも楽になれば幸いです。

# なぜAやBではなくCドライブなのか
Windowsのドライブは必ずCドライブから始まるのはなぜか。追加のディスクやUSBメモリはEやFになったりしますが、なぜ始まりがCなのか。

# 答え：先にAとBがあったから
昔のパソコンにはフロッピーディスクという1MBくらいの磁気ディスクを差し込むスロットが2つついており、これらがAドライブとBドライブと呼ばれておりました。Aドライブは起動ディスクやOS用、Bドライブはデータ用といった感じで使われていました。時はPC-9801シリーズの全盛期でした。

そんなある日、大容量で高速なハードディスクなるものが普及し始めると、データを格納するための拡張領域として利用することが一般的になっていきました。しかし初めの頃のハードディスクは非常にデリケートで、ちょっとした振動でデータが壊れてしまいます。そこでメインはフロッピーのA,Bドライブで、ハードディスクはおまけの**Cドライブ**という下積み時代が始まります。

時代が流れてハードディスクが安定してくるとOSもデータもCドライブのハードディスク受け持つことが多くなってきます。そうなると遅くて容量の小さいフロッピーの用途は、データの持ち運びや市販ソフトの流通など、役割がどんどん縮小していきます。

そんなころ、CDやDVDという大容量で高速な光学デバイスが登場、Dドライブという新たな立場で台頭します。さらにはUSBという接続方式が登場することにより、パソコンには好きな時に好きなデバイスをつなぐことができるようになるのです。こうして役割を完全に失ったフロッピーは静かに時代から消えていくのでした。AドライブとBドライブは永久欠番となり、CドライブはWindowsのメインドライブレター(ドライブを表す記号)として今に至ります。

```:MS-DOS
C:\>dir  
```

# おわりに
書きながら思い出したことですが、2000年頃の話、MACユーザーで「ドライブ」とかいう仕組みをダサいという人がいました。しかしここまでくると伝統を守り続けるクールさが感じられると思うのですがいかがでしょうか。
プロセスのシグナルマスクの状態を見るツールを作ってみた

## はじめに

プロセスがシグナルを無視しているのかシグナルハンドラを設定してるのかデフォルトなのかを知りたくなったのでツールを作ってみました。探せば「[How can I check what signals a process is listening to?](https://unix.stackexchange.com/questions/85364/how-can-i-check-what-signals-a-process-is-listening-to)」とかいくつかあるのですが、個人的に POSIX シェル準拠にしたかったのとプロセスグループへの対応やシンプルな出力が欲しかったので。

ソースコード: https://github.com/ko1nksm/psig

## 使い方

シグナルの情報は `/proc/<PID>/status` から取得しているので procfs に対応しているシステム（Linux等）でのみ動作します。ただし WSL1 では情報が取れませんでした。おまけでケーパビリティにも対応しています。

```console
Usage: psig [options]... [<pid> | 0 | -]...

  0: current proccess id
  -: parent proccess id
  no arguments: same as 'psig -'

Options:
  -g, --pgroup      Specify as a process group id
  -c, --capability  Include capability
  -h, --help        Display help
```

引数で指定した PID （複数可）を以下のように出力します。PID として `0` を指定した場合は psig コマンド自身、`-` を指定するか引数を省略した場合は親プロセスの情報を出力します。

```console
$ psig 0
Name:psig State:R (running) PPID:17481 PID:20693 PGID:20693 SigQ:0/99217
Command: /bin/sh /home/koichi/bin/psig 0
SigIgn: 34:RTMIN
SigCgt: 2:INT 17:CHLD
```

## 出力例

出力例として各シェルのデフォルトのシグナルマスクの状態です。

```sh:all.sh
#!/bin/sh
for sh in sh bash mksh ksh posh yash zsh "busybox ash"; do
  echo "==== $sh ===="
  $sh "$@"
done
```

```sh:signal.sh
#!/bin/sh
psig
```

```console:出力
$ ./all.sh signal.sh
==== sh ====
Name:sh State:S (sleeping) PPID:20618 PID:20619 PGID:20618 SigQ:0/99217
Command: sh signal.sh
SigIgn: 34:RTMIN
SigCgt: 2:INT 17:CHLD

==== bash ====
Name:bash State:S (sleeping) PPID:20618 PID:20625 PGID:20618 SigQ:0/99217
Command: bash signal.sh
SigBlk: 17:CHLD
SigIgn: 3:QUIT 34:RTMIN
SigCgt: 2:INT 17:CHLD

==== mksh ====
Name:mksh State:S (sleeping) PPID:20618 PID:20633 PGID:20618 SigQ:0/99217
Command: mksh signal.sh
SigIgn: 34:RTMIN
SigCgt: 1:HUP 2:INT 3:QUIT 14:ALRM 15:TERM 17:CHLD 28:WINCH

==== ksh ====
Name:ksh State:S (sleeping) PPID:20618 PID:20644 PGID:20618 SigQ:0/99217
Command: ksh signal.sh
SigIgn: 34:RTMIN
SigCgt: 1:HUP 2:INT 3:QUIT 14:ALRM 15:TERM 17:CHLD 28:WINCH

==== posh ====
Name:posh State:S (sleeping) PPID:20618 PID:20655 PGID:20618 SigQ:0/99217
Command: posh signal.sh
SigIgn: 34:RTMIN
SigCgt: 1:HUP 2:INT 3:QUIT 15:TERM

==== yash ====
Name:yash State:S (sleeping) PPID:20618 PID:20663 PGID:20618 SigQ:0/99217
Command: yash signal.sh
SigIgn: 34:RTMIN
SigCgt: 17:CHLD

==== zsh ====
Name:zsh State:S (sleeping) PPID:20618 PID:20673 PGID:20618 SigQ:0/99217
Command: zsh signal.sh
SigBlk: 2:INT
SigIgn: 3:QUIT 34:RTMIN
SigCgt: 1:HUP 17:CHLD 28:WINCH

==== busybox ash ====
Name:busybox State:S (sleeping) PPID:20618 PID:20682 PGID:20618 SigQ:0/99217
Command: busybox ash signal.sh
SigIgn: 3:QUIT 34:RTMIN
SigCgt: 2:INT 17:CHLD
```
そうだ、SQLを勉強しよう16

#はじめに
本日から、DDLに入りました。

##テーブル作成

```sql
CREATE TABLE テーブル名 (
列名A 列Aの型名,
列名B 列Bの型名,
)
```

##型の種類(例)

|データ種|型名|
|---|---|
|数値|INTEGER|
|固定長文字列|CHAR
|可変長文字列|VARVHAR
|日付|DATE|
|時刻|TIME|

##テーブルの削除

```sql

DROP TABLE テーブル名
```

##最後に
DMLではINSERT文だったなぁなど、違いを意識して覚えていこうと思います。
ポートフォリオ　学習フェアサービス

## 初めに
フロントエンドをVue.jsを用いて非同期処理実装しています。
バックエンドにLaravelを用いて画像をAWSのS3に保存しています。

## URL
本サービス：https://studysharemanagement.herokuapp.com/
Github:https://github.com/Tanaka-Kizuki/book-search.git

## アプリの概要
勉強内容、時間を共有して皆で切磋琢磨するサービスです。
webAOI"OpenDB"を用いてISBNコードを入力することで書籍情報を検索し
登録することで学習記録に記載することが可能。
書籍の画像も登録できるので目視的に学習内容が把握できます。
いいね機能を実装しているので他の学習者を応援することができます。

## 機能一覧
◉ユーザー管理登録
　○新規登録(管理者のみ有効)
　○ログイン、ログアウト機能
　○アイコン登録(AWS S3)
◉学習管理システム
　○学習開始
　○学習終了
　○学習時間の算出(15分繰り上げ)
◉いいね機能
　　https://qiita.com/tanaka2020/items/8ec8ae0fdd3ad4409c74
　　https://qiita.com/tanaka2020/items/2f87594be2fb53b23958
　　↑実装方法は別記事でまとめています。
◉書籍検索・登録
　○ISBNコードを入力し書籍の検索(OpenDB API)
　○本棚：学習している書籍の登録

## 使用技術
◉フロントエンド
　○HTML/CSS
　○JavaScript
　○Vue.js 4.3.1
◉バックエンド
　○PHP 7.4.9
　○Laravel　7.27.0
◉インフラ
　○mysql 8.0.21
　○heroku

## 工夫した点、苦労した点
◉ユーザー管理
　・ユーザー毎のアイコンを設定可能
◉学習管理システム
　・2回連続スタート打刻ができないように実装
◉書籍検索・登録
　・書籍検索をAPIを用いてAxiosで非同期処理

## 最後に
　1人では勉強がなかなか続かない人でも継続して学習できるように学習内容と時間を共有できるサービスを作成しました。使用書籍はAPIを用いてデータを取得出来るので画像付きで目視的にも内容を確認できます。
PHPで暗号化した情報をGoogle Colab(Python)で復号する

Google Colabでインターネット上にある情報にアクセスできるのは便利だ。個人情報や機密情報をインターネット上に置くのはもってのほかだが、インターネット上に公開して問題ないが第三者に利用されたくないので暗号化しておくといった場合があるかもしれない。（というか、このあたりは自己責任で）

まず、PHPで暗号化して出力する方から。AES256(CBCモード)で暗号化する。

```php
$message = "Hello"
$plaintext = sprintf("%s %s",date("Y-m-d"),$message);
$cipher = "aes-256-cbc";
$ivlen = openssl_cipher_iv_length($cipher);
$iv = openssl_random_pseudo_bytes($ivlen);
$key = "12345678901234567890123456789012";
$ciphertext_raw = openssl_encrypt($plaintext,$cipher,$key,$options=OPENSSL_RAW_DATA,$iv);
$hmac = hash_hmac('sha256', $ciphertext_raw, $key, $as_binary=true);
$ciphertext = base64_encode( $iv.$ciphertext_raw );
print($ciphertext);
```

1234...で書いているAESの鍵は

```openssl rand -base64 1000 | dd of=sample.key bs=32 count=1```

などで生成したものを使う。

次にGoogle Colab。事前にpycryptoをインストールしておく。

```pip install pycrypto```

`example.com`のログをpandasで格納し、1行ごとに復号する。

```py
import base64
from Crypto import Random
from Crypto.Cipher import AES
import pandas as pd

df = pd.read_csv("https://example.com/test.php",header=None)

key = "12345678901234567890123456789012"

for index,data in df.iterrows():
  c = base64.b64decode(data[0])
  iv = c[:AES.block_size]
  cipher = AES.new(key, AES.MODE_CBC, iv)
  s = cipher.decrypt(c[AES.block_size:])
  s = s[:-ord(s[len(s)-1:])]
  print(s)
```

iv(initial vector)の扱いが各言語のリファレンスごとに微妙に違って苦労したが、とりあえずPHPで出力したAES暗号をGoogle Colabで復号できるようになった。

繰り返すが、暗号化すれば公開していいというものではないので、扱いは自己責任で。
Swift UITableViewで三つの選択肢から一つのみ選択できるように

三つの選択肢のなか、一つしか選択できないようなデモを作ってみて
computed propertiesとTableViewの理解を深めたと思うのでメモしておきます。

1.三つのアイテムの選択状態のcomputed propertiesを作ります
選択するとチェックマークを付与して、選択していないアイテムはチェックマークが付与されていない状態にするには、選択状態が変わるたびにTableViewを更新してほしいので、tableView.reloadDataを呼び出します。

```Swift
var aSelected: Bool = true{
    didSet{
        tableView.reloadData()
    }
}
var bSelected: Bool = false{
    didSet{
        tableView.reloadData()
    }
}
var cSelected: Bool = false{
    didSet{
        tableView.reloadData()
    }
}
var selectedStatus:[Bool]{
    return [aSelected, bSelected, cSelected]
}
```
画面に入る時（無操作の状態で）デフォルト一番目が選択状態、二番目と三番目は未選択状態にするため、
最初に表示するTableViewのCellを設定するところではこのように書きます。

```Swift
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
    let cell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
    cell.textLabel!.text = listContentOne[indexPath.row]

    if selectedStatus[indexPath.row]{
        cell.accessoryType = .checkmark
    }
    return cell
}
```

2.TableViewのCellがタップする時の処理

```Swift
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    if indexPath.row == 0{
        self.aSelected = true
        self.bSelected = false
        self.cSelected = false
    }else if indexPath.row == 1{
        self.aSelected = false
        self.bSelected = true
        self.cSelected = false
    }else if indexPath.row == 2{
        self.aSelected = false
        self.bSelected = false
        self.cSelected = true
    }
}
```

3.TableView.reloadDataが呼び出された後、以下が実行されるためUI更新に必要な処理を書きます。

```Swift
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    if selectedStatus[indexPath.row]{
        cell.accessoryType = .checkmark
    }else{
        cell.accessoryType = .none
    }
}
```

まとめると、
computed propertiesを作っておいて、値が変わったらtableView.reloadDataを呼び出すように。
値が変わるたびに実行してほしい処理をtableViewの「willDisplay cell」の中で書く。
UITableViewとcomputed propertiesへの理解が深まりました！

出来上がりはこんなイメージです。
![スクリーンショット 2021-02-22 22.57.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/644086/85ce7d68-1c72-1283-6ceb-976ede56e49f.png)
【メモ】Laravel × Vue.jsでのハマった事

まず，初学者です。
メモです。


#何が起こったか

Vueでボタンを作成しlaravelのblade内にコンポーネントで適用しようとした所，全然表示されない。という事が起こりました。

```~~.blade.php
<div class="content">

    <div id="app">
        <example-component></example-component>
    </div>
    
    <script src="{{ mix('js/app.js') }}"></script>

</div>

```
って感じでこのcontentのdivが5つぐらいあったんだけど，

```
    <div id="app">
        <example-component></example-component>
    </div>
    
    <script src="{{ mix('js/app.js') }}"></script>
```
これをその5つのcontent内にコピペすれば，表示されるんじゃないかと思ったんだけど1個しか表示されないという。
コンポーネントのやり方違うのか？？ってめちゃ考えてたり，調べたりしたんだけど全然わからなく、、、、
諦めずに調べていたら（https://note.com/hokurojump/n/n8fc0948f42fe）
パッと閃いたんですよね。
これ下記を1個1個にやるんじゃなくて，全体に囲んだらいいんじゃね？と、、

```
<div id="app">
<div>
```

いや，最初からわかるだろ！！！！とツコッミたくなると思うけど我慢して下さい（笑）

ということで




#解決

```~~.blade.php
<div id="app">
    <div class="content">

        <example-component></example-component>

    </div>
    <div class="content">

        <example-component></example-component>

    </div>
    <div class="content">

        <example-component></example-component>
    
    </div>
</div>
    <script src="{{ mix('js/app.js') }}"></script>


```

全部に適用されました！！！！
APIを使用し、PythonからInstagramの情報を取得する方法


#APIを使用し、PythonからInstagramの情報を取得する方法

```python:instagram.py

from instagram_basic_display.InstagramBasicDisplay import InstagramBasicDisplay

instagram_basic_display = InstagramBasicDisplay(app_id ='********', app_secret='**********', redirect_url='https://localhost:8080/')

#ig_codeにはredirect_urlに記載されているcodeが入る
auth_token = instagram_basic_display.get_o_auth_token(ig_code)

#auth_tokenから取得したaccess_tokenが代入される
instagram_basic_display.set_access_token(auth_token['access_token'])
ig_profile = instagram_basic_display.get_user_profile()
```

#ターミナルでの実行
```
#python manage.py shell を実行
>>>from instagram_basic_display.InstagramBasicDisplay import InstagramBasicDisplay
>>>instagram_basic_display = InstagramBasicDisplay(app_id ='********', app_secret='**********', redirect_url='https://localhost:8080/')

#ig_codeにはredirect_urlに記載されているcodeが入る
>>>ig_code =''
>>>auth_token = instagram_basic_display.get_o_auth_token(ig_code)
>>>auth_token
#abcdefgは例、実際はもっと量が多い
{'access_token': 'abcdefg', 'user_id': 12345678912345678}

>>>instagram_basic_display.set_access_token('abcdefg')
>>>ig_profile = instagram_basic_display.get_user_profile()
>>>ig_profile
{'account_type': 'PERSONAL', 'id': '12345678912345678', 'media_count': 1, 'username': 'admin.test'}
```

*これらを行う前にfacebook for developers でinstagram_basic_displayの設定を行う必要がある
[facebook for developers](https://developers.facebook.com/?locale=ja_JP)
【備忘録】Laravel8 tailwindをsassで使う

***

####１． npmを使ってtailwindのインストール
※確かJetStreamをインストールすると一緒についてくるので不要な場合スキップ
※dockerを使用してる場合は適切なコンテナの中でnpmコマンドを使うこと（ローカルで叩いたり、間違ったコンテナで叩いてハマったので）


```
$ npm install tailwindcss
```

***

###２． 設定用ファイルを作成


```
$ npx tailwind init
```

プロジェクトのルートディレクトリにtailwind.config.jsが出来上がる

```tailwind.config.js
const defaultTheme = require('tailwindcss/defaultTheme');

module.exports = {
    purge: [
        './vendor/laravel/jetstream/**/*.blade.php',
        './storage/framework/views/*.php',
        './resources/views/**/*.blade.php',
    ],

    theme: {
        extend: {
            fontFamily: {
                sans: ['Nunito', ...defaultTheme.fontFamily.sans],
            },
        },
    },

    variants: {
        extend: {
            opacity: ['disabled'],
        },
    },

    plugins: [require('@tailwindcss/forms'), require('@tailwindcss/typography')],
};
```

***

###3. webpack.mix.jsを編集

```tailwind.config.js
const mix = require('laravel-mix');
const tailwindcss = require('tailwindcss');//追記



mix.sass('resources/sass/app.scss', 'public/css')
    .options({ 
        processCssUrls: false, //公式ドキュメント参照
        postCss: [ tailwindcss('./tailwind.config.js') ], 
    }); 

    //　JetStreamインストール時に生成されてた書き換え前の内容
    //
    // .postCss('resources/css/app.css', 'public/css', [
    //     require('postcss-import'),
    //     require('tailwindcss'),
    //     require('autoprefixer'),
    // ])

if (mix.inProduction()) {
    mix.version();
}

```

***

###4. resource/sass/app.scssを編集（追加）

```app.scss
@import 'tailwindcss/base';
@import 'tailwindcss/components';
@import 'tailwindcss/utilities';
```

***

###5. ビルドする

```
//変更をリアルタイムに表示
$ npm run watch

//押すたび変更を表示
$ npm run dev
```

***

###参考

公式ドキュメント
https://tailwindcss.com/
公式ドキュメント（日本語）
https://tailwindcss-ja.entap.app/

***
[メモ] アソシエーション失敗 [未解決]

#エラー概要
何回も同じエラーが出て前に進めないので、失敗した記述をメモ。
gift機能が実装できません。



やりたいこと
・giftsテーブルに値が保存される

実際のエラー（ブラウザにはエラーが出ません）
[![Image from Gyazo](https://i.gyazo.com/f68a1692bec3751ce896452e0daa2102.png)](https://gyazo.com/f68a1692bec3751ce896452e0daa2102)
[![Image from Gyazo](https://i.gyazo.com/d0aac605e08aaafc875e478df1d73843.png)](https://gyazo.com/d0aac605e08aaafc875e478df1d73843)

```gifts_table.rb
class CreateGifts < ActiveRecord::Migration[6.0]
  def change
    create_table :gifts do |t|
      t.integer    :price,    null: false
      t.references :giver,    foreign_key: { to_table: :users }
      t.references :receiver, foreign_key: { to_table: :profiles }
      t.timestamps
    end
  end
end
```

```gifts_controller.rb
class GiftsController < ApplicationController
  before_action :find_profile, only: [:gift_params, :new, :create]
  def new
    @gift = Gift.new
  end

  def create
    @gift = Gift.create(gift_params)
    binding.pry
    if current_user.save
      redirect_to root_path
    else
      render :new
    end
  end

  private
  def gift_params
    params.require(:gift).permit(:price).merge(giver_id: current_user.id, receiver_id: @profile.user_id)
  end

  def find_profile
    @profile = Profile.find(params[:profile_id])
  end
end
```



---

#試したこと
アソシエーションの変更（何パターンか検証した）

```ruby:gift.rb
class Gift < ApplicationRecord
  belongs_to :giver, class_name: 'User'
  belongs_to :receiver, class_name: 'Profile'
end
```

```ruby:profile.rb
class Profile < ApplicationRecord

# 失敗した組み合わせ

 has_many :gifts, foreign_key: 'receiver_id'
 has_many :givers, through: :gifts, source: :receiver

#他にもたくさん失敗しましたが、忘れました

end
```

```ruby:user.rb
class User < ApplicationRecord

# 失敗した組み合わせ

 has_many :gifts, foreign_key: 'giver_id'
 has_many :receivers, through: :gifts, source: :giver



end
```

---
ルーティングの変更

```ruby:routes.rb
Rails.application.routes.draw do

  resources :profiles, only: [:new, :create, :show, :edit, :update] do
     resource :gifts, only: [:new, :create]
  end
```

　　　　↑↓　#どっちも失敗

```ruby:routes.rb
Rails.application.routes.draw do

  resources :users do
    resource :gifts, only: [:new, :create]
  end
  resources :profiles, only: [:new, :create, :show, :edit, :update]
```

ずっと同じエラー（Receiverを入力してください）が発生します。
「俺の仮想マシンルーターがこんなに速いはずはないわ」と思って作ったけどゲスト OS の設定でどうにか出来るよって話

# 概要
この記事は「[「俺の仮想マシンルーターがこんなに速いはずはないわ」と思って作った件](https://qiita.com/soprano1125/items/d92d135436fd9d2db2b7)」の解決編~~の雑まとめ~~です。

# (~~先に~~)まとめ
[SpeedTest by Ookla](https://www.speedtest.net/result/10970941050)
![10970941050.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19210/7cfbbc7e-b114-66f3-ab1e-8e457a83ea4a.png)

# きっかけ
ある日、なんとなく『そういえば PF が遅くてなんだかなーって人はいるんだろうか』と Twitter で「[FreeBSD pf slow](https://twitter.com/search?q=FreeBSD%20pf%20slow&src=recent_search_click&f=live)」と検索したら同じように「なんだかなー」ってツイートがあったのでちょっと読み進めてみました。

ふと「[Are you using FreeBSD on EC2 and networking is slow when enabling pf?](https://twitter.com/hrgnmpf/status/461900227591831552)」というツイートが目に入りました。
『まぁ EC2 も仮想マシンだしちょっと関連ありそうだなぁ』と思いリンクを開いてみたところ『「net.inet.tcp.tso」を0にすると早くなるかもよ？』と FreeBSD のフォーラムに書かれていました。

# 調べてみた
## ところで TSO is 何？
[TSO(TCP Segmentation Offload)について](https://qiita.com/hana_shin/items/dd91b40cd9f6b316d8e3) - @hana_shin
>TSOは、NICが送信パケットをMTU長に分割する仕組みです。
>以前は、カーネルで分割していましたが、最近はNICでパケットを分割することができます。
>NICでパケットを分割することでカーネルの負荷を低減することができます。

## FreeBSD 的に影響はあるの？
[Configuration - Advanced Configuration Options - Networking Tab](https://docs.netgate.com/pfsense/en/latest/config/advanced-networking.html#hardware-large-receive-offloading) - pfSense[^pfsense] Documentation[^c6h12o6]
>This option is not desirable for routers and firewalls, but can benefit workstations and appliances. It is disabled by default, and should remain disabled unless the firewall is acting primarily or solely in an appliance/endpoint role.

# なら設定を入れてみた
```shell:sysctl.conf(抜粋)
# NIC is slow
net.inet.tcp.tso=0
```
```shell:rc.conf(抜粋)
# e1000e
ifconfig_em0="-lro -tso"
ifconfig_em1="inet 192.168.0.1 netmask 255.255.255.0 -lro -tso"
```
まず em にオプションを追加してみましたが Ookla のスピードテストで測ったところ[以前の結果](https://qiita.com/soprano1125/items/d92d135436fd9d2db2b7#%E8%A8%88%E6%B8%AC%E7%B5%90%E6%9E%9C)とあまり変わらず。
ここでふと「あ、そういえば virtio でダウンがすげぇ出てたから virtio で試してみよう！」と思い浮かびました。

```shell:rc.conf(抜粋)
# virtio
ifconfig_vtnet0="-lro -tso"
ifconfig_vtnet1="inet 192.168.0.1 netmask 255.255.255.0 -lro -tso"
```
スピードテストの結果を見て思わず『うわっ、すげぇ出てんじゃん！！！』と叫んでしまいました。

# まとめ
![10970941050.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19210/7cfbbc7e-b114-66f3-ab1e-8e457a83ea4a.png)

(　ﾟдﾟ) ポカーン・・・
　
(つд⊂)ｺﾞｼｺﾞｼ

(；ﾟдﾟ) ・・・
　
(つд⊂)ｺﾞｼｺﾞｼｺﾞｼ

![10970941050.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19210/7cfbbc7e-b114-66f3-ab1e-8e457a83ea4a.png)

(　Д )　ﾟ　ﾟ …！？

# (ちょっとした)考察
仮想化する以前の FreeBSD ルーターには(新しくても2011年に買った)蟹さんの NIC を使っていたせいかこの設定は入れていませんでした。一応ギ蟹だったんですけど TSO なんていう高尚な機能は付いていなかったのかもしれないまま、仮想化した FreeBSD ルーターに設定することなく使わなかったんだろうと思います。
~~次に検証するときは sysctl を設定せずに ifconfig のオプションだけでも変えられるか試してみたいですねぇ。。。~~

# おまけ
スピードテストを何回やって 100[Mbps] 超えしたことを確認したときに勝利の BGM として脳内で流れたのは「[恋せよガオガイガー](https://nico.ms/sm424909)」でした。~~**4シャア！ 借りをまとめて返してやったぞ！！**~~

[^pfsense]: [pfSense - Wikipedia](https://ja.wikipedia.org/wiki/PfSense)
[^c6h12o6]: [FreeBSDの通信性能が悪いと感じたらLRO, TSOオプションをオフにしてみよう](https://blog.c6h12o6.org/post/freebsd-router-network-perf/)
schedule_interval=Noneの場合はnext_execution_time=prev_execution_time=execution_time

# schedule_interval=Noneの場合、next_execution_timeはどうなる？

Airflowのデフォルト変数には `next_execution_time` という、次の実行時の `execution_time` が格納される変数があります。
これはDAGがスケジュール設定されている（schedule_intervalがNoneではない）ときに意味のある値なのですが、スケジュール設定されていない（schedule_intervalがNoneである）ときにどうなるか調べました。

# 確認したバージョン

* Airflow 1.10.9

# 確認手順

schedule_interval=NoneのDAGを作り、Airflowコンソール上から手動実行する。

# 結果1： schedule_interval=Noneの場合、next_execution_timeはexecution_timeと同じ値になる

スケジュール設定がない以上次の実行も何もないのでNoneが入るのかなと思いましたが、意外にも `execution_time` と同じ値が入っていました。

# 結果2： schedule_interval=Noneの場合、prev_execution_timeはexecution_timeと同じ値になる

`next_execution_time` の対になる `prev_execution_time` （前回実行時の `execution_time` が格納される変数）も気になって調べてみました。
その結果、こちらも `execution_time` と同じ値が入っていました。

「2回目を実行したら1回目の `execution_time` が入るかな？」と思い何度か繰り返しましたが、そんなことはなく結果は常に `execution_time` と同じ値でした。

# 結論：schedule_interval=Noneの場合はnext_execution_time=prev_execution_time=execution_time

以上より、schedule_interval=Noneの場合は常にnext_execution_time=prev_execution_time=execution_timeになることがわかりました。

Noneではないのでis not Noneを期待したユーザーコードでエラーが出ることはありませんが、ちょっと気持ち悪さもありますね。

# 付録

## 確認コード

```execution_time_test.py
import airflow
from airflow import DAG
from airflow.operators.bash_operator import BashOperator
from datetime import timedelta

default_args = {
    "owner": "airflow",
    "depends_on_past": False,
    "start_date": airflow.utils.dates.days_ago(1),
    "retries": 1,
    "retry_delay": timedelta(minutes=5),
}

dag = DAG(
    "execution_date_test",
    default_args=default_args,
    catchup=False,
    schedule_interval=None
)

templated_command = """
    echo "execution_date={{ execution_date }}"
    echo "next_execution_date={{ next_execution_date }}"
    echo "prev_execution_date={{ prev_execution_date }}"
"""

t3 = BashOperator(
    task_id="templated",
    bash_command=templated_command,
    dag=dag,
)
```

## 実行結果のログ

```log
*** Log file does not exist: /usr/local/airflow/logs/execution_date_test/templated/2021-02-22T12:57:52.434900+00:00/1.log

（省略）

[2021-02-22 12:57:58,851] {{bash_operator.py:115}} INFO - Running command: 
    echo "execution_date=2021-02-22T12:57:52.434900+00:00"
    echo "next_execution_date=2021-02-22T12:57:52.434900+00:00"
    echo "prev_execution_date=2021-02-22T12:57:52.434900+00:00"
[2021-02-22 12:57:58,859] {{bash_operator.py:122}} INFO - Output:
[2021-02-22 12:57:58,860] {{bash_operator.py:126}} INFO - execution_date=2021-02-22T12:57:52.434900+00:00
[2021-02-22 12:57:58,860] {{bash_operator.py:126}} INFO - next_execution_date=2021-02-22T12:57:52.434900+00:00
[2021-02-22 12:57:58,860] {{bash_operator.py:126}} INFO - prev_execution_date=2021-02-22T12:57:52.434900+00:00

（省略）
```
CentOS7でTLS1.0を無効化したらWebmailのRainloopでメール読めなくなった

#はじめに

職場（どっかの大学）で以下の環境でメール読み書きしてました。

-メールサーバ: CentOS7.x 
 Dovecot + IMAP(NonSSLでのアクセス禁止)+Postfix

-クライアント: CentOS7.x
 Webmail Rainloop-1.14

ソフトウエアDovecot/PostfixはCentOS7.xに最初から入ってるのです。Rainloop-1.14はソースコードからインストールしました。

先月、職場のセキュリティ検査でTLS1.0を無効にしなさいと指摘されました。

#TLS1.0を無効にしました。

Dovecot:
>ssl_protocols = !SSLv2 !SSLv3 !TLSv1

Postfix:
>smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1
>smtpd_tls_protocols = !SSLv2, !SSLv3,  !TLSv1

#Rainloopでメールが読めなくなりました(>_<)

ログ(/var/log/maillog)を見ると以下のようなエラーが出てます。

> TLS handshaking: SSL_accept() failed: error:140760FC:SSL routines:SSL23_GET_CLIENT_HELLO:unknown protocol, ....

いろいろ調べると、WebmailのRainLoopがTLS1.0でアクセスしているようです。

#Rainloopのソース読んでみました。

わかんないです。

#もしかしてPHPが古いのでは。。
CentOS7内蔵のPHPは5.4です。Googleで「php5.4 TLS1.1」で検索するとTLS1.1は未対応みたいな話が出てきます。

#それか！
phpの野良リポジトリを導入しましてphp5.4からphp7.4にバージョンアップしました。

無事Rainloopでメールにアクセスできるようになりました(^_^)

（この作業、他の環境をぶち壊す危険があるため、詳細は省きます。自己責任でググって作業ください。）

以上です。
【iOS】いつの間にかサポート外OSの端末で新規インストールできなくなった

# 概要
iOSアプリ開発で悩ましい、サポートiOSの終了において、過去と挙動が変わっていたためまとめました。
サポートを切る＝IPHONEOS_DEPLOYMENT_TARGETでOSバージョンを変更する、の前提です。

# 想定と事象
想定

|  OS  |  新規インストール  |
|---|---|
| 対象外 | 対応しているうちの最新バージョンが落ちる |
| 対象内|  最新バージョンが落ちる  |

事象

|  OS  |  新規インストール  |
|---|---|
| 対象外 | AppSotoreでアプリ名を検索：ヒットしない <br>サイトからAppStoreに誘導：「iOSXX.X以降が必要です。iPhone,iPad,およびiPod touchに対応。」という文言が表示されており、ダウンロードボタンは非活性|
| 対象内|  最新バージョンが落ちる  |

# 過去(2013~)はできてた
> 今日（米国時間9/17）、あるRedditユーザーが、App StoreでiOSの旧バージョンを使っているユーザーが、互換性のある最後のバージョンのアプリをダウンロードできるようになったことを発見した。

[Apple offering 'last compatible version' of iOS apps for older hardware | Engadget](https://www.engadget.com/2013-09-17-apple-ios-last-compatible-version-app-iphone-ipod-ipad.html)
他にも検索すると、2013年あたりの記事は日本語も英語もちらほら出てくるので、間違いなさそうです。

# いつからできなくなった？
私の過去ログだと2018年くらいまではできていたようです。
ただ正確&正式な情報はなく、[ニュース - Apple Developer](https://developer.apple.com/jp/news/)を追ってみるも、見れるかぎり（2020年03月04日まで）該当するニュースはありませんでした。

# AppStoreの設定
[旧バージョンのダウンロードを不可にする - App Store Connect ヘルプ](https://help.apple.com/app-store-connect/#/dev435af0db6)にある、
最終互換バージョンの設定は「すべて」になっていました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208579/124a8b18-559e-61c0-624d-0f7fbe8fdff3.png)
ので、ここの設定は無関係のようです。
Appleのバグの可能性もまだある？

# あくまでできないのは新規インストールのみ
以下の条件が揃えば、インストール可です。

- 過去にそのアプリをダウンロードしたことがある
- サポート外OSの端末でも、以前と同じApple IDでApp Storeにサインインしている

参考：[古いiPadを有効活用！ アプリの旧バージョンをダウンロードして使う方法 | できるネット](https://dekiru.net/article/20452/)
railsで作ったアプリの本番環境の画像保存先をS3に変更する

# 開発環境
Mac OS Catalina 10.15.7
ruby 2.6系
rails 6.0系

# 本番環境
nginx 1.18.0
AWS(EC2, S3, ALB, Route53)

# 前提
- capistranoのによる自動デプロイを導入しています
- 無料枠の関係で、本番環境にのみS3を導入します
- AWSには登録済みとします

# バケット作成

まずはAWSにログインして、ヘッダーの「サービス」 をクリックします。
一覧表示されるサービス名の中から、S3を選択しましょう。

![スクリーンショット 2021-02-22 20.52.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1035658/17f3ca4e-3a0a-822c-f4a4-5ee563da468f.png)

S3を選択したら、バケットを作成をクリックしてバケットを作成します。![スクリーンショット 2021-02-22 20.54.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1035658/66dec0ba-5c50-3cde-cd13-d58a1b07cfdf.png)

任意のバケット名を入力し、リージョンを「アジアパシフィック（東京）」にしましょう。

![スクリーンショット 2021-02-22 20.57.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1035658/f16f22b9-10ae-92de-5193-1fc8ec2c76b1.png)

その後、ブロックパブリックアクセスのバケット設定をします。
以下のようにチェックをつけてください。
一番上の「ブロックパブリックアクセスのバケット設定」のチェックを外すと、以下のチェックボックスが選択可能になります。


![スクリーンショット 2021-02-22 20.59.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1035658/ef0bb6eb-14e6-e79f-4666-59991a19d8c1.png)

チェックできたら他は特に変更せず、バケットを作成しましょう

# バケットポリシー設定

作成したバケットをクリックして、「アクセス許可」からバケットポリシーの編集をします。

![スクリーンショット 2021-02-22 21.13.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1035658/d41e35b2-20e6-acf7-1304-063fedc2c1b5.png)

バケットポリシーに以下を貼り付けましょう。

```
{
   "Version": "2012-10-17",
   "Id": "Policy1544152951996",
   "Statement": [
       {
           "Sid": "Stmt1544152948221",
           "Effect": "Allow",
           "Principal": {
               "AWS": "ユーザーのARN"
           },
           "Action": "s3:*",
           "Resource": "arn:aws:s3:::作成したバケット名"
       }
   ]
}
```

できたら変更を保存をクリックします。

# aws-sdk-s3を導入

ここからはrails側です。
まず、S3を使用するために必要なGemfileを導入します。

Gemfileに以下を追記

```
gem "aws-sdk-s3", require: false
```
```
#gemfile記述後
bundle install
```

# production.rbを編集

production.rbの画像保存先をamazonの変更します。

```config/environments/production.rb
config.active_storage.service = :amazon
```

# storage.yml編集

strage.ymlを編集します。access_key_idとsecret_access_keyはこの後、環境変数に設定します。

```storage.yml
local:
  service: Disk
  root: <%= Rails.root.join("storage") %>

## 以下を追記
amazon:
  service: S3
  region: ap-northeast-1
  bucket: 作成した自身の「バケット名」を入力
  access_key_id: <%= ENV['AWS_ACCESS_KEY_ID'] %>
  secret_access_key:  <%= ENV['AWS_SECRET_ACCESS_KEY'] %>

```

# 環境変数を設定する

ターミナルで環境変数を設定します。
既に設定してある場合は飛ばしてもらって大丈夫です。

```
vim ~/.zshrc
```
iを押してインサートモードに移行した後、以下を追記

```
export AWS_ACCESS_KEY_ID="ご自身のCSVファイルのAccess key ID"
export AWS_SECRET_ACCESS_KEY="ご自身のCSVファイルのSecret access key"
```

追記後はescキーでインサートモードを終了した後、:wqで保存しましょう。

その後、ターミナルで以下のコマンドを打ちましょう。

```
source ~/.zshrc
```

# Heroku上に環境変数を設定する(Herokuを使っている場合)

Herokuにあげている場合は環境変数を追加する必要があります。（EC2にデプロイしている人はおそらく既に設定してあると思います）

```
# ターミナル
% heroku config:set AWS_ACCESS_KEY_ID="自身のCSVファイルのAccess key ID"
```

```
# ターミナル
% heroku config:set AWS_SECRET_ACCESS_KEY="自身のCSVファイルのSecret access key"
```

```
#ターミナル
% git push heroku master
```

EC2であれば再びデプロイし直せば、S3に画像が保存されます。
以上です。
Email Studio の基本 ⇒ Email Studio の設定

１．次の記述のうち、権限とロールの違いを最もよく表しているのはどれですか?
２．メールドメイン認証で確認されるのは何ですか?
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634241/06209745-3321-1a63-f916-10cf4262f4d7.png)
CentOS7でTLS1.0を無効化したらMewでメール読めなくなった

#はじめに

職場（どっかの大学）で以下の環境でメール読み書きしてました。

-メールサーバ: CentOS7.x 
 Dovecot + IMAP(NonSSLでのアクセス禁止)+Postfix

-クライアント: CentOS7.x
 Emacs + stunnel + Mew6.8

ソフトウエアDovecot/Postfix/Emacs/stunnelはCentOS7.xに最初から入ってるのです。Mew6.8はソースコードからインストールしました。

先月、職場のセキュリティ検査でTLS1.0を無効にしなさいと指摘されました。

#TLS1.0を無効にしました。

Dovecot:
>ssl_protocols = !SSLv2 !SSLv3 !TLSv1

Postfix:
>smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1
>smtpd_tls_protocols = !SSLv2, !SSLv3,  !TLSv1

#Mewでメールが読めなくなりました(>_<)

ログ(/var/log/maillog)を見ると以下のようなエラーが出てます。

> TLS handshaking: SSL_accept() failed: error:140760FC:SSL routines:SSL23_GET_CLIENT_HELLO:unknown protocol, ....

いろいろ調べると、クライアントのEmacs + stunnelがTLS1.0でアクセスしているようです。

#Mewのソース読んでみました。

stunnelにTLS1.1以上でアクセスするように指示を出さないといけないようです。

「man stunnel」およびMewのソースコードmew-ssl.elを見る限り以下の設定でよさげです。

> (setq mew-prog-ssl-arg "sslVersion=TLSv1.2\n")

各自の~/.emacsに加筆ください。

以上です。
OneTab （Chrome on Mac） のデータを復旧 - ver. 1.50以降の場合

#前提

 - 初稿ではとりあえずChrome on Macで動作確認しました。
 - 本稿で対象とするOneTabのバージョンは1.50以降（概ね2021年2月中旬以降）です。
 - TimeMachineによるバックアップが必要です。
 - OneTabのデータは、特定のディレクトリにlevelDBで保存されています。
 - **ver. 1.50以降では、保存ディレクトリが変更**となっている模様です。


#Quick Answer

 - Chromeを終了します。
 - 次のディレクトリの中身を、デスクトップなり任意の場所に**移動**してバックアップします（事実上ほとんど使いません）。

```
/Users/ユーザー名/Library/Application Support/Google/Chrome/Default/Local Extension Settings/chphlpgkkbolifaimnlloiipkdnihall 
```

 - TimeMachineで同じディレクトリをリストアします。ただし、何らかの理由で、リストアしてChromeを起動してもlevelDBが不整合を起こして自動的にlevelDBが初期化されてしまうことがあります。そうなると、結局見た目としてはOneTabはクラッシュしたままデータは戻りません。この場合は、TimeMachineのバックアップを一つづつ順番に遡ってリストアしてみます。私の経験上、1日〜2日分遡るとどこかで正常にリストアできるバックアップに辿り着きました。
 - Chromeを起動します。

#詳細

**OneTabのデータが保存されているディレクトリは、ver. 1.50以降では次の場所に変更された**模様です。

```
/Users/ユーザー名/Library/Application Support/Google/Chrome/Default/Local Extension Settings/chphlpgkkbolifaimnlloiipkdnihall/
```


その前のver. 1.35以前では、次のディレクトリにやはりlevelDBで保存されていました。

```
/Users/ユーザー名/Library/Application Support/Google/Chrome/Default/Local Storage/leveldb/
```

ただ、このバージョンの保存場所では他のChrome拡張ともlevelDBを共有していたようで、1.50でそこから分離したのではないかと思います。

さらに前のバージョンでは、一つ上のディレクトリに次のファイル名でSQLiteで保存されていました。

```
/Users/ユーザー名/Library/Application Support/Google/Chrome/Default/Local Storage/chrome-extension_chphlpgkkbolifaimnlloiipkdnihall_0.localstorage
```

これらの過去の保存場所にはOneTabのデータは既になく、ver. 1.50にアップデートされた段階で自動的に保存場所も変更されます。従って、 ver. 1.50以降でLocal Storage以下を探すもしくはリストアしても、データは戻ってきません。最新の保存場所からリストアしてください。

#参考ページ
[https://www.reddit.com/r/chrome/comments/76k23b/onetab_lost_all_tabs_recovery/](https://www.reddit.com/r/chrome/comments/76k23b/onetab_lost_all_tabs_recovery/)
Error: ADB exited with exit code 1 Performing Streamed Installというエラーが発生した時の対処法

Flutterでモバイルアプリの開発も終盤に差し掛かり、アプリを実機でリリースモードでデバッグしようとするとタイトルにあるようなエラーが発生して、かなりてこずったのでエラーの原因を探る過程を共有するために記事を上げました。同じエラーで困っている方は参考にしてみてください。

まずは実際にエラーをググってみてヒントになりそうな質問がstack overflow にあり、様々な解決のヒントがあったので順繰りに試してみた
参考
https://stackoverflow.com/questions/56367108/adb-exited-with-exit-code-1

このサイトに挙げられた解決方法は
Maybe your device/emulator's storage is full
実機の容量が満タンで新しいアプリをインストールする余地がない
→実機ではそんなことはなかった

Invalid package name
package nameに大文字とかが含まれていてエラーが生じている
→package name も問題がなかった。

flutter clean をすればいいよ
→確かによくこれでエラー治るけど今回はダメだった

Allow 'installing apps from usb' on your phone if you get this error on physical device
→スマホ側ではUSBの接続の許可をしているのは確認した。

turn off the virus protection and it works fine in debug mode
→ウイルスソフトの解除やプレイストアや実機のプロテクトの解除もしてみたけどダメだった

こんな感じでstack overflow の解法が全滅してやばくね？となり検索方法を変えつつもうちょっと調べることに

するとまたもやstack overflow に似たトピックがあることを発見しこちらを試してみることに
参考
https://stackoverflow.com/questions/59405894/a-problem-was-found-with-the-configuration-of-task-appprocessdebugresources

これはgradleファイルの対象SDKに実機が含まれていないのではないのかという指摘あり、実際にSDKを30までに対象を広げると無事エラーが解決した。

結構この辺りのエラーの原因はいろいろなところに潜んでいることがわかったので、もし同じエラーで詰まっていたら上に挙げた解法を試してみたり、他にも試行錯誤してみてください。
【Rails】コントローラー内の記述をメソッド化してモデルに定義　←　1人のユーザーの全投稿に紐づくイイね数表示

## 概要
下記記事を参考に作成したコントローラー内のロジックを
何度も記述しておりましたのでリファクタリングのため、
メソッド化してモデルに定義しました。
その際、インスタンスメゾッド？クラスメゾッド？なにそれ…！となりましたので
ざっくり理解した内容と合わせて記事にしました。

参考：[【Rails】ユーザー１人の全ての投稿に紐づく「イイね」の合計数を表示する方法](https://yumanoblog.com/rails-likes/)
参考：[【Ruby】クラスメソッドとインスタンスメソッドについてザクッと分かりやすく説明してみる](https://qiita.com/hogeta_/items/27221675638cdc9bde6b)
参考：[Railsのモデルに書いたメソッドってどうやってコントローラで使うの？](https://qiita.com/leavescomic1/items/99f32f45cd04035f146c)


## 元の記述
一部カットしていますが、今回モデルに移す
『userが持つ全投稿のいいね合計を算出するロジック』はこのように記述しています。
※今回投稿はhoge、いいねはfavorite。いいね合計はインスタンス変数@favorites_countへ格納します。

```ruby:users_controller.rb
  def show
    @user = User.find(params[:id])
# ユーザーが持つ全投稿のいいね合計
    @hoges = @user.hoges
    @favorites_count = 0
    @hoges.each do |hoge|
      @favorites_count += answer.favorites.count
    end
  end
```

## インスタンスメソッド化してモデルに定義
先に結論から記載します。

```ruby:users_controller.rb
  def show
    @user = User.find(params[:id])
#　all_favoritesというメソッドを別途モデルに定義する
    @favorites_count = @user.all_favorites
  end
```

```ruby:user.rb
  def all_favorites
    favorites_count = 0
    hoges.each do |hoge|
      favorites_count += hoge.favorites.count
    end
#　favorites_countを返してほしいので最後に記述
    favorites_count
  end
```

## 記述内容理解
備忘録のため記載します。
間違い、補足があればご教示いただけますと幸いです。

モデルに記述するメソッドは大きく、クラスメソッドとインスタンスメソッドがあります。

+ クラスメソッド：クラスオブジェクトから呼び出す。
+ インスタンスメソッド：インスタンスオブジェクトから呼び出す。

今回は、userに紐づく形でメゾッドを呼び出すため、インスタンスメソッドです。
※User.find(params[:id])で取得した@userに紐づくイメージです。

インスタンスメソッド内では、インスタンスをselfとして記述することができます(省略可能)。
省略しましたが、下記のようにも記述できます。
（なお、元々コントローラーにあった@hoges = @user.hogesはhoges = hogesと同意になり、省略できます。
　また、@が付いてないのはView等に渡す変数ではないからです。）

```ruby:user.rb
  def all_favorites
    favorites_count = 0
#　コントローラー内の@userをここではselfと記述可能。
#　self.hogesは@user.hogesの意味
    self.hoges.each do |hoge|
      favorites_count += hoge.favorites.count
    end
    favorites_count
  end
```
コントローラーで@user.all_favoritesと記述しているので、@userの全投稿に紐づくいいね数ですが
例えば、rails cで、User.find(1).all_favoritesとやると、id1のuserの全投稿に紐づくいいね数が取得できます。

なお、1点補足で、インスタンスメソッドを使用する際は、
1つのデータから呼び出すことが必須になります。
つまり、user.all_favoritesはイケますが、users.all_favoritesは呼び出せず、エラーになりますのでご注意ください。
この辺りはインスタンスとは？のような話になるかと思いますが、まだよく分かりません・・
【図解あり】Rails6でBootstrapを導入してトップページを作成する

Rails6でアプリケーションにBootstrapを導入した際の手順をまとめてみました。
###### 完成形
![cook.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1140333/f8c0aa10-2606-0b9d-8876-888500ea432f.jpeg)
Bootstrapの導入までは以下をコピペ

##Bootstrapの導入

##### jQuery、Bootstrap、popper.jsの導入
```:ターミナル
yarn add jquery bootstrap popper.js
```
##### webpackの設定
```javascript:config/webpack/environment.js
const { environment } = require('@rails/webpacker')

//ここから
const webpack = require('webpack')
environment.plugins.append(
  'Provide',
  new webpack.ProvidePlugin({
    $: 'jquery/src/jquery',
    jQuery: 'jquery/src/jquery',
    Popper: ['popper.js', 'default']
  })
)
//ここまでを追加

module.exports = environment
```
##### javascriptフォルダ内にstylesheetsとapplication.scssを作成
```:ターミナル
mkdir app/javascript/stylesheets
touch app/javascript/stylesheets/application.scss
```

##### Bootstrap、CSSをインポート
```javascript:app/javascript/packs/application.js
import 'bootstrap';
import '../stylesheets/application';
```

```scss:app/javascript/stylesheets/application.scss
@import '~bootstrap/scss/bootstrap';
```
##### アプリケーションのheadに以下を追記
```ruby:app/views/layouts/application.html.erb
<%= stylesheet_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
```
##### 画像を読み込ませる
バックグラウンドに画像を挿入する場合は作成してください

```:ターミナル
mkdir app/javascript/images
```
resolved_paths:[　]の中に'app/javascript/images', 'app/assets/images'を記述

```yml:config/webpacker.yml
resolved_paths: ['app/javascript/images', 'app/assets/images']
```

導入完了

## トップページの作成
#####コントローラーとビューの作成
```:ターミナル
rails g controller home index
```
```ruby:config/routes.rb
Rails.application.routes.draw do
  root to: 'home#index'
end
```
##### ビューの編集
```erb:app/views/home/index.html.erb
<div class="jumbotron">
  <div class='index-content text-center'>
    <h1 class='home-index'>レシピを共有しよう!</h1>

    <div class='index-btn d-flex justify-content-around'>
      <%= link_to '新規登録', "#", class: "btn btn-success btn-lg" %>
      <%= link_to 'ログイン', "#", class: "btn btn-success btn-lg" %>
    </div>
  </div>
</div>
```
ここまででこんな感じ
![top.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1140333/335e97cd-64c0-03fc-8f6b-33488e37f0fc.png)

#####CSSをあてる
```:ターミナル
touch app/javascript/stylesheets/home.scss
```
```scss:app/javascript/stylesheets/application.scss
@import '~bootstrap/scss/bootstrap';
@import './home.scss'; #追記
```
app/javascript/imagesに適当な画像を配置する
![img.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1140333/d3ad596f-98b5-31ee-64cf-c0b8f6d11553.jpeg)

```scss:app/javascript/stylesheets/home.scss
.jumbotron{
  background-image: url('../images/cooking.jpg');
  background-size: cover;
  width: 100%;
  height: 100vh;
}

.home-index{
  font-weight: bold;
  font-size: 50px;
  color: purple;
  text-shadow:0 0 10px #FF0;
}

.index-content{
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%,-50%);
}

.index-btn{
  margin-top: 20px;
}
```
完成
![cook.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1140333/f8c0aa10-2606-0b9d-8876-888500ea432f.jpeg)
Cities:Skylines　MOD

Japanese Localization Mod (日本語化MOD)
https://steamcommunity.com/sharedfiles/filedetails/?id=427164957

Extra Landscaping Tools 地形変更MOD
https://steamcommunity.com/sharedfiles/filedetails/?id=502750307
地形、樹木、資源、水源、海水面の高さを変える。あらゆる地形変更が可能なMOD

More Network Stuff+Prefab Hook
https://steamcommunity.com/sharedfiles/filedetails/?id=512314255

https://steamcommunity.com/workshop/filedetails/?id=530771650
航路と空路を設定できるMOD

Automatic Bulldoze v2
https://steamcommunity.com/sharedfiles/filedetails/?id=639486063
廃墟化した建物を自動化するMOD

81 Tiles (Fixed for 1.2+)
https://steamcommunity.com/sharedfiles/filedetails/?id=576327847
タイルを81タイル解放可能するMOD

TM:PE V11 STABLE (Traffic Manager: President Edition)
https://steamcommunity.com/sharedfiles/filedetails/?id=1637663252
【Xcode12】ワイヤレスでiPhone実機でビルドを出来るように設定した時に「iPhone is not connected」と表示された

#はじめに
USBポートが少ないMacを使用しているため、実機でビルドするためにUSBを付け替える作業が面倒だと感じ、ワイヤレスでできないか調べました。
ワイヤレスでiPhone実機をビルドする方法を見つけました。

しかし「iPhone is not connected」と表示され、ワイヤレスで実機のビルドができなかったので解決策を調べました。

解決したので、やり方を残しておこうと思います。

#環境
Xcode12.3
Swift5.3.2
macOS Catalina 10.15.4

#iPhone実機をワイヤレスでビルドする方法
[こちらのサイト](https://qiita.com/tzono/items/7a926c0b2e6ffa696f1d)を参照にして設定しました。

#エラーが発生
「iPhone is not connected」という表示がXcodeでされて、実機をワイヤレスでビルド出来ませんでした。

#確認した事
・MacとiPhoneが同一のネットワークになっているかどうか（Macだけ有線になっているのはダメみたいで、両方無線になっている必要があるようです）

#解決した方法
※iPhone実機をワイヤレスでビルドする方法は設定済み
[stackoverflow](https://stackoverflow.com/questions/46014400/iphone-not-connected/47320586)で書かれていた方法を参考に下記の方法を試しました。

1.Xcodeを再起動
2.iPhoneを再起動
3.USB経由でiPhoneを接続する
4.アプリを実行する
5.USBを外し、wifi経由で再度実行する

この方法で、wifi経由で実行ができるようになりました。

#参照サイト
https://qiita.com/tzono/items/7a926c0b2e6ffa696f1d
https://stackoverflow.com/questions/46014400/iphone-not-connected/47320586
https://god48.com/xcode-wireless-build

#終わりに
ワイヤレスでiPhone実機ビルドが出来るようになったおかげで、手間が減って楽になりました。

間違いなどがあれば、優しく教えていただけると嬉しいです。

[Twitter](https://twitter.com/koara1237)やっています。
SpringSecurityでURLパラメーターでアクセス制御する

よくなにかのグループや部門ごとにアクセスをさせたいそんな時に使えるかも知れない

## 前提
* Spring Securty 4.1以降  
  ※Spring Boot2.1系も既にEoLを迎えてて、それの依存先にあるSpring Security5.4系なのでEoL無視してなければ問題ないはず
* 記事サンプルではDBなし

## 注意
本記事ではユーザーごとにURLパラメーターによるアクセス制御は実現されますが、操作先の要素がそのグループに属しているか？はそれぞれで整合性の検証をしないと他のグループの要素をURL埋め込みすることで可能なので、実用する際には注意すること

## 記事のサンプル構成
* グループ  
  権限対象
* アイテム
  グループから紐付くもの
* ユーザー
  個別に権限が設定される操作者、今回はグループごとに操作可否を設定

※すべてIDを持つ

## ユーザーの権限割り当て

```org.springframework.security.core.userdetails.UserDetailsService``` を実装したサービスクラスでグループごとの権限を持ったユーザーを返す。
ここで返すユーザークラスが後述の権限判定で使えるものとなるので要件に合わせたクラスとする。
サンプルではCustomUser

## 権限判定の実装
Beanであれば何でもよいが、取り得る引数に制限があるので注意
[リクエスト](https://docs.spring.io/spring-security/site/docs/current/reference/html5/#el-access-web)や[共通組み込み関数](https://docs.spring.io/spring-security/site/docs/current/reference/html5/#el-common-built-in)あたりが取得しうる。

今回は認証済みユーザーと機能を利用するのに要求する権限、そしてURLのグループIDを引数とする。そうすると下記のようなメソッドとなる。

```java:GroupPermission
boolean hasAuthority(CustomUser user, String groupId, String authority)
```
判定は各自お好みで作成

## 権限設定
```org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter``` を継承して ```configure(HttpSecurity http)```にて行う。

```java:SecurityConfig
	protected void configure(HttpSecurity http) throws Exception {
		http
			.authorizeRequests()
				.mvcMatchers(HttpMethod.GET, "/item/{groupId}/{itemId}")
					.access("isAuthenticated() and @groupPermission.hasAuthority(principal, #groupId, 'ADMIN')")

```
isAuthenticated()を設定するのは未認証の際、そのままCustomUserを引数とする関数に渡すとエラーとなるためで無いときの処理やキャストを自前で行うなら不要
```@【Bean名】``` で任意のBeanを呼び出すことが可能。```{groupId}``` と ```#groupId```が今回のポイントでパス変数が#付きへバインドしてくれる。
そのほかは前述の通り取り得る引数は制限があるので注意、指定の詳細はSpring ELなのでそちらを参照

### 改良
上記が基本的な記述ではあるが生Stringのためタイプミスもしやすく補完も効かないため、要件が固まり次第簡易DSL的なものを用意する方が安全と思われる。
例えば```groupPermission.hasAuthority```に対応した```String hasGroupAuthority(String pathVariableName, String authority)```といったメソッドを用意することで以下のよう短くできる。

```java:SecurityConfig
	protected void configure(HttpSecurity http) throws Exception {
		http
			.authorizeRequests()
				.mvcMatchers(HttpMethod.GET, "/item/{groupId}/{itemId}")
					.access(hasGroupAuthority("groupId", "ADMIN"))

```
例ではEnumを使用していないが、もちろんそれらの使用も可能
※SpELで扱うと完全修飾クラス名記述が必要で長くなるため本記事ではカット


## ソース
今回サンプルで作ったもの
https://github.com/tac-yacht/Sample_SpringSecurity_RoleIsSeparatedForEachGroup

## 参考文献
```What’s New in Spring Security 4.1```にちゃんと書いてますね。
https://docs.spring.io/spring-security/site/docs/4.1.0.RELEASE/reference/htmlsingle/#authorization-improvements

### リファレンス類
* https://docs.spring.io/spring-security/site/docs/current/reference/html5/#el-access
* https://github.com/thymeleaf/thymeleaf-extras-springsecurity

### 外部記事
* https://www.baeldung.com/spring-optional-path-variables
* https://www.baeldung.com/spring-security-expressions
* https://www.baeldung.com/spring-security-create-new-custom-security-expression
* https://medium.com/sfl-newsroom/spring-security-expression-based-access-control-56411a60ab3b
ElevatedButtonを使ってみる

FlutterのUIのお勉強をしたので備忘録を残しておく。

今日のテーマは、
https://api.flutter.dev/flutter/material/ElevatedButton-class.html
ElevatedButtonをいい感じで使ってみたい。

https://api.flutter.dev/flutter/material/RaisedButton-class.html
もともとはRaisedButtonだけど、今はRaisedButtonはobsolete（廃止）になっていて、Flutter1.22.0以降はElevatedButtonを使ってくださいとのことです。

RaisedButtonの説明にもあるように、
FlatButton, RaisedButton, and OutlineButton have been replaced by TextButton, ElevatedButton, and OutlinedButton respectively.
ということなので、

`FlatButton → Textbutton`
`Raisedbutton → ElevatedButton`
`OutlineButton → OutlinedButton`
となったようです。

paddingだったりfontsizeも変えることができて、オリジナルのボタンを作ることができそうですね。

```
 ElevatedButton(
   onPressed: () {},
   child: Text('いいね'),
   style: ElevatedButton.styleFrom(
     primary: Color(0xFF005731),
     onPrimary: Colors.white,
     padding: EdgeInsets.symmetric(
         horizontal: 100,
         vertical: 5,
      ),
     textStyle: TextStyle(
         fontSize: 15.0,
         fontWeight: FontWeight.bold,
      ),
     shape: RoundedRectangleBorder(
     borderRadius: BorderRadius.circular(10),
   ),
 ),
),
```
できたボタンはこんな感じです。
![スクリーンショット 2021-02-22 21.13.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/998564/a6ffdae1-d4d3-7d60-91d5-abc19d370bf0.png)


〈参考〉
https://www.kindacode.com/article/working-with-elevatedbutton-in-flutter/
railsでpostgresqlを使うと2度目の投稿データ編集時に、1回目の編集データが下段にずれる

先日ポートフォリオを作成時に編集データが下段にずれてしまい、困ったため備忘録として投稿します。
これだけではなんのことかわからないと思うので内容をご確認ください！


#アソシエーション
![スクリーンショット 2021-02-22 20.37.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1036177/886b0af1-c6c0-87c9-7095-2711e236198e.png)
#コントローラー
```cooks_controller.rb
  def new
    @cook = Cook.new
    8.times { @cook.materials.build }
  end
```
このような形で新規投稿時に、食材と分量を最大8種類入れることができるようにしています。

#ビュー
```_cook_form.html.slim
div.cook-post-container
    div.col-12
      = form_with model: cook, local: true do |f|

　　　　　省略

        div.form-group
          label for="inputMaterial" ◆材料
          span style="font-size:14px;" ※8種類上の場合は調理方法欄に追記
          <br>
          = f.fields_for :materials do |material_fields|
            div.material-container
              div.material-box
                = material_fields.text_field :material, placeholder: "食材、調味料等", class: "my-2 cook-mobile"
              div.qty-box
                = material_fields.text_field :qty, placeholder: "分量", class: "my-2 cook-mobile"
              <br>
　　　　　　省略
       
          = f.submit "投稿する", class: "w-100 cook-mobile"
```
親モデルであるCookモデルのform_withにネストする形でfields_forを使用。

#発生した問題
Materialテーブルにおいて、2度目の編集時に1回目に編集したデータが下段にずれる！
（上記のfields_forの中身です）

例）
■新規投稿時
食材　分量
肉　　100g
空欄　空欄
空欄　空欄
空欄　空欄
空欄　空欄
空欄　空欄
空欄　空欄
空欄　空欄

■1回目の編集時
食材　分量
肉　　100g
塩　　5g　←追加
空欄　空欄
空欄　空欄
空欄　空欄
空欄　空欄
空欄　空欄
空欄　空欄

■2回目の編集時
食材　分量
肉　　100g
空欄　空欄
空欄　空欄
空欄　空欄
空欄　空欄
空欄　空欄
塩　　5g

このように2回目の編集時に1回目に追加した「塩・5g」が下段にずれて表示されてしまっていました。

#解決策
```material.rb
class Material < ApplicationRecord
  belongs_to :cook
  default_scope { order(:id) } #これを追記
end
```
default_scope { order(:id) }を記入することでデフォルトの表示順を変更してあげると、更新順に並びます。
※メンターの方いわく、default_scopeは非推奨であるため使用しないほうが良いとのこと

今回の原因はメンターの方が言うにはpostgresqlの仕様とのことでした。
本番環境ではMysqlを使用したため、default_scope { order(:id) }の記載がなくても更新順に表示されました。

#最後に
解決策でdefault_scope { order(:id) }を紹介しましたが、おそらく他にもっと良い方法があります。
私自身は本番環境でMysqlを使用したため他の解決策は探しませんでした！笑

以上です！