OmniAICreator/Qiita-1.07M huggingface dataset:
embulk-input-bigqueryでエラー /  (NoMethodError) undefined method `query_results' for nil:NilClass

# 環境
- embulk 0.9.22
- embulk-input-bigquery 0.0.9

# 現象

[medjed/embulk-input-bigquery](https://github.com/medjed/embulk-input-bigquery)で実行時エラー

```
org.embulk.exec.PartialExecutionException: org.jruby.exceptions.RaiseException: (NoMethodError) undefined method `query_results' for nil:NilClass
        at org.embulk.exec.BulkLoader$LoaderState.buildPartialExecuteException(BulkLoader.java:340)
        at org.embulk.exec.BulkLoader.doRun(BulkLoader.java:566)
        at org.embulk.exec.BulkLoader.access$000(BulkLoader.java:35)
        at org.embulk.exec.BulkLoader$1.run(BulkLoader.java:353)
        at org.embulk.exec.BulkLoader$1.run(BulkLoader.java:350)
        at org.embulk.spi.Exec.doWith(Exec.java:22)
        at org.embulk.exec.BulkLoader.run(BulkLoader.java:350)
        at org.embulk.EmbulkEmbed.run(EmbulkEmbed.java:242)
        at org.embulk.EmbulkRunner.runInternal(EmbulkRunner.java:290)
        at org.embulk.EmbulkRunner.run(EmbulkRunner.java:154)
        at org.embulk.cli.EmbulkRun.runSubcommand(EmbulkRun.java:431)
        at org.embulk.cli.EmbulkRun.run(EmbulkRun.java:90)
        at org.embulk.cli.Main.main(Main.java:64)
Caused by: org.jruby.exceptions.RaiseException: (NoMethodError) undefined method `query_results' for nil:NilClass
        at RUBY.run(/tmp/embulk-test/bundle/vendor/bundle/jruby/2.3.0/gems/embulk-input-bigquery-0.0.9/lib/embulk/input/bigquery.rb:88)
        at RUBY.run(uri:classloader:/gems/embulk-0.9.22-java/lib/embulk/input_plugin.rb:107)
```

# 原因

configにBQのlocation指定が無かった（対象データはUS locationではなかった）

```config.yml
in:
  type: bigquery
  project: foo_project
  keyfile: /path/to/foo.json
  location: asia-northeast1 # ココが必須
  sql: "select * from `foo_project.bar_dataset.foobar_table"

out:
  type: stdout
```

小一時間悩んで、pluginのソースみて理解。
Slackのシングルチャンネルゲストがずっと非アクティブのまま

エンタメ系企業の社内もろもろを担当しているakibinです。

#現象
Slackのユーザは一定期間（14日）使用していないと自動的にステータスが非アクティブとなり、課金対象から外れますが、非アクティブになったシングルチャンネルゲストが使用を再開してもステータスが非アクティブからアクティブに変わらじ、非アクティブのままなので「なんでやの？」となった

#Slackに問い合わせてみよう！
というわけで問い合わせて得られた回答が以下です。
> シングルチャンネルゲストは請求対象外のアカウントである為、該当ユーザーがシングルチャンネルゲストの場合は、アクティブユーザユーザーであっても、管理画面上では非アクティブと表示される仕様となっています。（非アクティブユーザー = 請求対象から外されるシステムのため）

おお？そうなんだ…ちょっと試しにシングルチャンネルを作成してみる。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/504009/a809cb06-511c-89ed-1669-46b711922f7a.png" width=70%>

ステータスは「-」になってますね。ここから一定期間使用していないとステータスが非アクティブになるみたいですね。そして、また使用再開してもスターテスは非アクティブのままと。
うーん、そうなるとシングルチャンネルゲストの実際のステータス（アクティブ化否か）はどうやって確認すればいいんだろ？もう一度Slackに聞いてみました。
> Slack でデフォルトで提供している機能としてはないのですが、次のAPIメソッド：users.getPresence（https://api.slack.com/methods/users.getPresence ）を利用すれば、ご要望とされるデータは取り出せますのでご参考ください。なお、摘出できるデータはJSONフォーマットのため、ご自分で多少加工していただくことが必要となります。

実際には試していませんが、ご丁寧に教えてくれました。ありがとうSlackのご担当者さん！

というわけで、Slackに聞かないとわからない内容なので記事を書いてみました。ご参考あれ！

#おまけ
全然関係ないですが、この記事を書いている途中に聞いていたチック・チック・チック（！！！）というアメリカのロックバンド（レーベルはイギリスのワープ・レコード）の2017年のアルバム「Shake The Shudder」の1曲目の**［The One 2］**という曲を初めて聴きまして、かっこよすぎて鼻血が出ました。シンセベースかっこいい〜〜。


＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊
◆ Twitterアカウント
@AkibinMusic

◆ Youtubeチャンネル
https://www.youtube.com/channel/UC-JOpwEnJn3gCrUA4NdCYgg
skelearnでのOne-hot encoderのメモ

```python 
from sklearn.preprocessing import *
y = ["a","b","c"]
y = class_le.fit_transform(y)
ohe = OneHotEncoder()
class_le = LabelEncoder()
ohe.fit(y.reshape(len(y),1))
y = ohe.transform(y.reshape(len(y),1)).toarray()
y
#array([[1., 0., 0.],
#       [0., 1., 0.],
#       [0., 0., 1.]])
ohe.inverse_transform(y)
#array([[0],
#       [1],
#       [2]])
```
AWS の NAT インスタンスを CloudFormation で作る

See: https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/VPC_NAT_Instance.html

NAT ゲートウェイだと楽なんだけど、あまり性能いらないのに高かったので NAT インスタンスを作成した。

NAT インスタンスでは "送信元/送信先チェック" を無効にしなきゃいけないんだけど、instance attribute の変更は CloudFormation でできないようなので、UserData で初回起動時にコマンド実行するようにした。

下記は Availability Zone `ap-northeast-1a` に作成する例。

```yaml
# セキュリティグループ
SecurityGroupNat:
  Type: AWS::EC2::SecurityGroup
  Properties:
    SecurityGroupIngress:
      - CidrIp: (サブネットのアドレス範囲)
        Description: HTTP
        FromPort: 80
        IpProtocol: tcp
        ToPort: 80
      - CidrIp: (サブネットのアドレス範囲)
        Description: HTTPS
        FromPort: 443
        IpProtocol: tcp
        ToPort: 443
    SecurityGroupEgress:
      - CidrIp: 0.0.0.0/0
        Description: HTTP
        FromPort: 80
        IpProtocol: tcp
        ToPort: 80
      - CidrIp: 0.0.0.0/0
        Description: HTTPS
        FromPort: 443
        IpProtocol: tcp
        ToPort: 443
    VpcId: (VPC の ID)

# "送信元/送信先チェック" を無効にするコマンドを実行するための IAM プロファイル/ロール
NatInstanceProfile:
  DependsOn:
    - NatInstanceRole
  Type: AWS::IAM::InstanceProfile
  Properties:
    Roles:
      - !Ref NatInstanceRole

NatInstanceRole:
  Type: AWS::IAM::Role
  Properties:
    AssumeRolePolicyDocument:
      {
        "Version": "2012-10-17",
        "Statement": [
          {
            "Effect": "Allow",
            "Principal": {
              "Service": "ec2.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
          }
        ]
      }
    Policies:
      -
        PolicyDocument:
          {
            "Version": "2012-10-17",
            "Statement": [
              {
                "Sid": "VisualEditor0",
                "Effect": "Allow",
                "Action": "ec2:ModifyInstanceAttribute",
                "Resource": "*" # ModifyInstanceAttribute はリソースの制限はできないみたい...
              }
            ]
          }
        PolicyName: allow-modify-instance-attribute

# NAT インスタンス
NatInstance:
  Type: AWS::EC2::Instance
  Properties:
    AvailabilityZone: ap-northeast-1a
    IamInstanceProfile: !Ref NatInstanceProfile
    ImageId: ami-00d29e4cb217ae06b # マーケットプレイスで amzn-ami-vpc-nat で検索して選ぶ
    InstanceType: t3.nano
    NetworkInterfaces:
      - AssociatePublicIpAddress: "true"
        DeviceIndex: "0"
        GroupSet:
          - !Ref SecurityGroupNat
        SubnetId: (サブネットの ID)
    # "送信元/送信先チェック" を無効にするコマンドを初回起動時に実行
    UserData:
      'Fn::Base64': |
        #!/bin/bash
        INSTANCEID=$(curl -s -m 60 http://169.254.169.254/latest/meta-data/instance-id)
        aws --region ap-northeast-1 ec2 modify-instance-attribute --instance-id $INSTANCEID --source-dest-check "{\"Value\": false}"
```
Laravel Excel で 出力したxlsxファイルが開けない時の対処法

#問題
Laravel Excelで出力したxlsxファイルをExcelで開くと

```
ファイル形式またはファイル拡張子が正しくありません。
ファイルが破損しておらず、ファイル拡張子とファイル形式が一致していることを確認してください
```
とエラーが出て開けませんでした。

#環境
Laravel 6.6
Laravel-excel 3.1

#対処法

公式にも同様のissueが上がっており解決策がありました

`<?php`が残っていたり先頭行に空白があると該当のエラーが出るそうです。

>Hi everyone,

>I spend my day to understand this unworkable download function. PHPSpreadSheet seems to use PHP buffer. And depending on your PHP configuration some warnings or errors could interfer with the output.

LaravelExcelで使われているPHPSpreadSheetのバッファを使用しており、構成によっては出力に影響を与えるとのことです。

示していただけたコードがこちら。

```php:
// in controller
ob_end_clean(); // this
ob_start(); // and this
return Excel::download(new MyExport, 'file.xls');
```

ずっと開けなかったのですが、開けました。

#参考
本当に感謝です
https://github.com/Maatwebsite/Laravel-Excel/issues/1673
修理したPCで修理前のBluetoothデバイスを削除しようとして、「削除に失敗しました」と出た話

# はじまり
Qiitaに書くような内容はもう少し技術的なことかもしれないんですが、備忘録。
デバイスマネージャーを使って解決。

解決策（本題）の項以外は本題と関係ないので流していただいて大丈夫です。

Microsoftフォーラムに寄せられたこの質問と同様の事象が起こりました。
[Bluetooth デバイスの削除ができず「削除に失敗しました」と表示されます](https://answers.microsoft.com/ja-jp/windows/forum/all/bluetooth/12d474ae-9239-4a6b-9ddf-378dde0ff0d1?lc=1041)
フォーラムではシステムの復元で直ったとのことですが、自分は修理が原因と思しき別の事象なので検証することにしました。

# 状態の比較
### マイクロソフトコミュニティ
マイクロソフトコミュニティでは、CCleanerで消去したレジストリが実は、Bluetoothデバイスの紐付け関連のレジストリだったようで、デバイスが消去できなくなったというもの。
CCleanerはレジストリ消去時にバックアップを取ることを勧めるので、質問者の方はこのバックアップによって動作を正常にし、Bluetoothデバイスの削除に成功したようです。

### 自分のパソコン
キーボード不調の再発のためメーカーに修理依頼。
マザーボード交換で返ってきたものの、従来使っていたBluetoothマウスが接続できず、デバイスの削除をしようとして、「削除に失敗しました」というメッセージが出てしまいました。
新しいマウスを接続しても2つ同じ型番が出て、元の動作しない方のデバイス表示は消えませんでした。
Windows 10の設定アプリはもちろん、コントロールパネルでも同様のエラーで失敗してしまいました。
削除できていないので、再起動してももちろん残っています。再起動後も削除はできませんでした。

#### 機種について
##### PC
ノートPC、HP製。
HP Spectre x360 13 (2018年モデル)

* パフォーマンスモデル
* Windows 10 Home
* intel Core i7-8700U
* RAM 16GB

##### Bluetoothデバイス
M590
Logicool、おそらくBluetooth 4.1？

# 解決策（本題）
デバイスマネージャーを使うことで解決しました。

デバイスマネージャーを起動(Windowsボタンを右クリックすると選べます)し、Bluetoothを選択。
ここで表示されるのは、現時点で接続されているものだけなので、`メニューバー->表示->非表示のデバイスの表示`で非表示(つまりアクティブでない、接続されていない)のデバイスを表示します。

薄いアイコン(つまり非アクティブ)で、設定アプリやコントロールパネルのデバイス名と同じものを右クリックして、`デバイスのアンインストール`を選びます。

確認画面が出るので、`アンインストール`を押しましょう。

これでアンインストールが終わったら、設定アプリを見てみましょう。使えない方のデバイスが消えているはずです！

# あとがき
なぜここらへんでデバイスの残骸が残ったのか…。もう少し調べたら何かわかるかもだけど面倒なのでやめます。
ただ、マザーボードが交換されたことは関係がありそう。
FreeNAS-11.2-U5で発生したディスク故障とカーネルパニックの対策

## ディスクが壊れた。ブートしない。

FreeNAS-11.2-U5でデータドライブの一つがSMARTエラーを吐き故障。
ひとまずディスクを取り外してブートしたが、以下のエラーを吐いてKernel Panicしてしまう。

	solaris assert: dmu_object_cvlaim(zfsvfs->z_os, obj, DMU_OT_PLAIN_FILE_CONTENTS, 0, obj_type, bounslen, tx) == 0 (0x11 = 0x0), file: /freenas-releng/freenas/_BE/os/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c, line: 819 cpuid = 0
	（以下略）

次の様な対応でとりあえずブートすることができた。

## 対応内容

* 1 すべてのデータドライブをはずすとFreeNAS自体をブートさせることができるので、まずそのようにしてブートする

* 2 管理コンソールにログインする

* 3 System → Tunables → Tunables → Add で次の値を追加する

キー | 値
-----|------
 Variables | vfs.zfs.zil_replay_disable
 Value | 1
 Type | sysctl

SSHでログインして /etc/sysctl.conf を書き換えても効果がないのでGUIから設定する必要がある。

* 4 シャットダウンし、健全なディスクのみ戻し起動すると、カーネルパニックを起こすこと無く起動する。

あとは一般的なZFSの対処で回復できそうな気がします。私の場合はDEGRADED状態でデータにアクセスできたので、重要なデータのバックアップを行ってから、ディスクの交換とリビルドを行う予定です。

## 参考

* [panic: solaris assert: dmu_object_claim - how to recover?](https://www.ixsystems.com/community/threads/panic-solaris-assert-dmu_object_claim-how-to-recover.81250/)
* [All data lost after power loss #8910](https://github.com/zfsonlinux/zfs/issues/8910#issuecomment-502381050)
Google Play Console のリリース管理について整理しよう

- Android アプリのリリースには Google Play Console を使いますが、リリースには複数のバージョンに分けて段階的にリリースして行くことができます。
- 本記事では Google Play Console の段階リリースについて整理しようと思います。

# 対象となる方
- Android アプリ開発者で今後アプリリリースしようと思っている方。

# Doc
- [公式Help](https://support.google.com/googleplay/android-developer#topic=3450769)


# リリース管理ってなに？
- Google Play Store のリリースを段階的に行うための方法
- 公式に、『製品版としてアプリをリリースする前に、テストすることをおすすめします。』と記載
    - いきなりリリース:zap:的なのりはやめておこう

## 段階的って？
リリース管理の段階として、以下の段階が用意されています。

- 内部テスト版
- クローズドテスト版
- オープンテスト版
- 製品版

# 各リリース段階の整理

## 内部テスト版:robot:
- 利用ユーザーはGoogle Play Store内の『テスター管理』を利用
- 最大100名が利用できる
- 課金アプリの場合、テストユーザーは課金の必要は無し

## クローズドテスト版:robot:
- 利用ユーザーはGoogle Play Store内の『テスター管理』を利用
- テスト対象のAPKをトラックという単位で作成
    - 1トラック、50リストのテスターリストを登録可能
    - 1リスト、2000人までテスターを登録可能
- 課金アプリの場合、テストユーザーは課金処理を実施する必要がある
    - PlayStore内でユーザー単位にアプリライセンスを付与できるのでそれによって課金済み状態に擬似的にできる

## オープンテスト版:robot:
- Google Play Store からユーザーが検索して利用することができる
- 開発元が公開しているオプトインURLから参加する事も可能
- テスト対象は開発元が上限（最低1000名〜）を決めている場合にはその数に従う
    - 上限がない場合には、制限なしとなる
- 課金アプリの場合、テストユーザーは課金処理を実施する必要がある
    - PlayStore内でユーザー単位にアプリライセンスを付与できるのでそれによって課金済み状態に擬似的にできる

## 製品版:ribbon:
- Google Play Store 一般公開されたバージョン
- もちろん課金アプリは課金処理が必要

# さいごに
- Android開発をし、世の中に公開するには、Google Play Store での公開が不可欠です！
- しっかりテストを行い、Bestな状態でリリースして行きましょう:relaxed:

これからも楽しいアプリ開発をしていきましょう:dancer_tone1:
MacのUnityで空エラーがでた場合の対処方法(Unity2019.3.0f5)

# 概要
Unity2019.3.0f5をMacで起動したら、以下のような空のエラーが発生してビルドできなくなりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163629/446bbceb-9327-62b4-8539-8215bcf299af.png)

この投稿は、その対処法になります。

# 動作環境
* Unity2019.3.0f5
* Mac OSX Catalina 10.15.2 

# Windowsの場合
Windowsの場合も、同じようなエラーが起きてたみたいです。
その場合は以下のやり方でなおるそうです。

https://helpdesk.unity3d.co.jp/hc/ja/articles/360037037212-%E7%A9%BA%E3%81%AE%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88%E3%82%A8%E3%83%A9%E3%83%BC%E3%81%8C%E5%87%BA%E3%81%A6%E3%82%B3%E3%83%B3%E3%83%91%E3%82%A4%E3%83%AB%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%8F%E3%81%AA%E3%82%8B%E5%95%8F%E9%A1%8C%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6

今回の対応も似たようなやり方です。

# 本題
とりあえず原因を特定させるためにEditor.logを確認します。

```bash
-----CompilerOutput:-stdout--exitcode: 137--compilationhadfailure: True--outfile: Temp/UnityEngine.UI.dll
-----CompilerOutput:-stderr----------
Failed to initialize CoreCLR, HRESULT: 0x80004005
-----EndCompilerOutput---------------
```

以下のようなエラーがでてた場合Unityの中にある「csc」ファイルが何らかの理由で正常に動作しなくなってるっぽいです。
(本当はそれをなおしたかったけど断念…)

## というわけで、応急処置

対象のUnityの「パッケージの内容を表示」とすると、ディレクトリ内部にアクセスできます。
そこから、 Contents -> Tools -> RoslynScripts -> unity_csc.sh を編集します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163629/c7180f7c-a02f-0a98-e555-c480379f2018.png)

と、その前にMacの中にcscがあるか確認。
このcscは、C#のコンパイラだそうです。

```bash:cscがあるか探す
$ find /Library/Frameworks -name csc
/Library/Frameworks/Mono.framework/Versions/5.18.0/bin/csc
/Library/Frameworks/Mono.framework/Versions/5.18.0/Commands/csc
/Library/Frameworks/Mono.framework/Versions/6.6.0/bin/csc
/Library/Frameworks/Mono.framework/Versions/6.6.0/Commands/csc
/Library/Frameworks/Mono.framework/Versions/5.16.0/bin/csc
/Library/Frameworks/Mono.framework/Versions/5.16.0/Commands/csc
```

ない場合はどうするべきかはわかりません。
あれば、以下のように書き換えたら動くようになります。

```bash:unity_csc.shの23行目あたり
#eval "\"$CSC_NET_CORE\" /shared "$@"" #コメントアウト
eval "\"/Library/Frameworks/Mono.framework/Versions/Current/bin/csc\" /shared "$@"" #書き換え
```

これで、ぼくは動くようになりました。
よかったよかった(´・ω・`)
RubyでLeetCodeを解いてみた Reverse Integer

https://leetcode.com/problems/reverse-integer/

>Given a 32-bit signed integer, reverse digits of an integer.

```ruby
# @param {Integer} x
# @return {Integer}
def reverse(x)
    if x.positive?
      y = x.to_s.reverse.to_i
    else
      y = x.to_s.reverse.to_i*-1
    end
    return  0 if ( y > 2147483646 || y < -2147483647)
    y
end
```

rubyはover flowの扱いが特殊みたいで
生々しい実装になってしまいました😀😀😀
ウェブサーバに攻撃試行があるけどどうしたらいい?


[自前のサーバーでブログを開設した途端、世界中から怪しい攻撃が来た話](https://qiita.com/KMim/items/60c1ce893c09872acd15)にもあるように、EC2インスタンスは常時攻撃にさらされます。
# tl; dr

- 攻撃試行は回避できないが、導入されていないツールへの試行はさほど害はない。（ログが見づらくなるくらい）
- たとえばブログサイトを開設する場合、まずS3, GCSなどサーバを構築しないサービス（はやりの言葉だとサーバレスですね）で提供できないか検討する
- サーバを構築する場合、構築中はSecurity Group, Firewall rulesなどで自分以外からのアクセスをブロックし、公式ドキュメントにのっとって安全な設定ができてから一般公開しましょう

# そもそも攻撃試行が来ないようにしたい
無理です。インターネット上では常時大量のbotたちが脆弱性を探しています。IPアドレスで総当たりで攻撃していると思われるので、インターネット上にサーバがある以上どうしても避けられないと考えるべきです。

![yaruo.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19807/5689e43e-14e9-f54f-aca5-949a9515c817.png)

攻撃の試行があるのはしょうがないとして、ここではブログを開設するとして、どのように対策したら攻撃が成功しないか考えてみます。いくら攻撃試行があっても、成功しなければログが汚くなるくらいしか影響がありません。

# 攻撃が成功すると何がよくないのか
先述の通り、導入されていないツールやミドルウェアへの攻撃は過度に恐れる心配はありません。では、実際に攻撃が成功してしまった場合どんな悪影響があるのでしょうか。以下に代表的な例を挙げてみます。

- ページの改ざん：たとえばCMSへの不正ログインが成功してしまった場合、ページが改ざんされる可能性が高いでしょう。そこでウィルス配信などが行われると目も当てられないことになります。
- 攻撃の踏み台になる：攻撃された場合でも、見た目ではなにも変わらないものの、他のサーバやシステムに侵入するための足場にされることがあります。これをやられると、あたかも自分のサーバが伏せアクセスしていることになってしまい、あらぬ疑いをかけられてしまいます。

# まずサーバなしでなんとかならないか
サーバを立てること自体が主目的でなければ、**サーバを立てずになんとかすることを検討しましょう**。サーバを立てなければ、攻撃を受ける面も少なくなります。
サーバを立てる場合でも、PHP, Rubyなどを有効化しなければ、攻撃を受けるリスクを軽減できます。サーバ上で動かすプログラムはなるべく最小限にしましょう。

ブログを開設するとして、サーバ上で動かすシステムではなく、[hugo](https://gohugo.io/)などのように、ローカルで静的なHTMLを生成してサーバは静的なファイル送信だけというブログシステムもあります。
静的なファイルの配信だけで完結するのであれば、AWSならS3、GCPならGCSなどで十分かもしれません。

# サーバを立てる場合にどうしよう
検討した上でサーバが必要ということになった場合、何に気をつけたらよいでしょうか。

まず、**構築途中のサーバに注意しましょう**。構築中のサーバは設定やパスワードがデフォルトのままだったりするので、攻撃が成功しやすい状態といえます。実際攻撃のログを見てみると、不適切な設定になっているサーバからデータを抜き出そうとするような攻撃が多いです。
設定方法はツールの提供元サイトにベストプラクティスが書かれているはずなので、それを参考にしてください。（先人たちのブログはもしかしたら古い情報かもしれません）

ちょっとの間だけなら大丈夫、と思っても人間の「ちょっとの間」はコンピューターにとっては十分長い時間です。

構築中はSecurity Groupで一時的にアクセス元IPアドレス制限をかける（作業途中にIPアドレスが変わったら少し面倒ですが、都度変更します）など、グローバルに接続できないようにするのが安全です。その上でOSのパッケージ更新や設定修正などを行い、一通りの設定ができた段階で一般公開します。

お金がある人はApplication Load BalancerやCloudFrontにAWS WAFとマネージドルールを導入することで、よく知られた攻撃はブロックできますが、結構高いので個人だと難しいかもしれません。

# まとめ
ウェブサーバが攻撃試行を受けるのは、規模にかかわらずインターネットに公開している以上避けられません。
まず自分でサーバを立てないという選択肢を選べないか考えましょう。その上でサーバを構築するのであれば、インターネットに公開できる準備ができるまでは外からアクセスできないようにしておきましょう。
サーバ上でブログツールなどのプログラムを動かすのであれば、公式ドキュメントを参考に構築しましょう。

# Note
気をつけるべきことは他にもあるのですが、全部網羅するのは難しいので概要の紹介だけになります。
思い出したら追記するかもしれません。こういうことを書いてほしいとかあれば、コメントください。
【Django】formでzipのバリデーションをしようとして沼にはまった話 【TDD】

# Djangoさん「UnicodeDecodeError: 'utf-8' codec can't decode byte 0xbb in position 10: invalid start byte」

formのFileFieldに複数ファイルをまとめたzipをアップロードして保存しようとするとこのエラーになった。
結論から言うと、テストの時に放り投げていたデータ形式が悪かったみたい。

ただ、通るようになってエラーを再現しようとするとなぜかクリアするので、エラーの再現が困難なのが意味わからない。めっちゃ困ってたのに・・・

# 解決策
まずエラーが出てたときは、

```python:tests.py

self.zip_error_test = File(open('tdd.zip'))
file_data = {'upload_train_file': uploadedFile }
form = DocumentForm(file_data)
form.is_valid()
```

端折りますがこんな感じでした。
こんなことするとdjangoさんが怒ります。
ちなみに1つのファイルを固めたZIPでも同じように怒られました。

下のように変更すると解決しました。

```python:tests.py
with open("tdd.zip", mode="rb") as f:
   uploadedFile = InMemoryUploadedFile(f, "field", "tdd.zip", "application/x-zip-compressed", 100, None, content_type_extra={})
   file_data = {'field': uploadedFile }
   form = DocumentForm(request, data, file_data)
   self.assertFalse(form.is_valid(), f"error:{form.errors}/複数ファイル入ったZIPがバリデーションされませんでした")
```

はい。
これで動きます。
やったね。

# 原因は何だったのか。
いろいろ考えました。
そもそも`forms.py`のカスタムバリデーションに書いていたので、それが原因なのかなと思ってみたり、
`cleaned_data`を持ってきてるのがダメなのかなと思ってto_python()をいじってみたり。
`forms.py`ではファイルを保存できないのかな、とかもういろいろ考えてました。

ふと思い立ってテストではなく、実際にHTMLのフォームからアップロードしたらどうなるんだろうとおもってやってみた結果

<b>通りました。</b>

これはformで受け取ってるデータ違うんじゃねと思って、viewsとtestsで受け取っているデータの型を見比べてみました。
すると

```python:forms.py
def clean_field(self):
    print(type(self.cleaned_data['field']))

# views >　django.core.files.uploadedfile.InMemoryUploadedFile
# tests >　django.forms.widgets.ClearableFileInput
```

わーお違ってるやーん

これのせいだったので、テストのほうのアップロードを先述のものに変更したわけです。

これにて一件落着です。
おかげでFormについて詳しくなれた気がします。
いわゆる完全に理解したってやつですね。かんぺきです。

# まとめ
解決したあとにこの記事書こうと思って、再度エラーになるであろうコードを書くとなぜかクリア。
マジで謎。
上記で通るって書いているけど

```python:tests.py
with open("tdd.zip", mode="rb") as f:
   file_data = {'field': f}
   form = DocumentForm(request, data, file_data)
   self.assertFalse(form.is_valid(), f"error:{form.errors}/複数ファイル入ったZIPがバリデーションされませんでした")
```

これでも通ります。何でですかね。通らなかったんですよ？
何なら`mode="rb"`をなくしても通ります。なんでなんですかね。エラー出てたんですよ？本当です。しんじて。

もしかすると再起動かけるとまた動かなくなっちゃうかもと思って上のほうのコードにしています。
明示的にクラスを変えればさすがに問題ないでしょう。

ということでzipがなぜか保存できない現象の解決方法でした。

多分来週くらいの私が、この件で得たformの知識をまとめてくれます。
期待してます。
Ubuntu18.04でC# Hello Worldメモ


# 概要

UbuntuでC#の開発をしたかったのでHello Worldしたメモ。

**以下の記事を参考に自分で試してみたメモなので、これらの記事以上の内容はありません。**

* https://qiita.com/maccha_XD/items/248563d296dee0ab9cc7
* https://qiita.com/LemonLeaf/items/0531f5479315ee858eb9
* https://qiita.com/matsuda_sinsuke/items/76068f4c396887459803

# 環境

```
$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=18.04
DISTRIB_CODENAME=bionic
DISTRIB_DESCRIPTION="Ubuntu 18.04.3 LTS"
```

# Install Mono

```
$ sudo apt -y install mono-devel
$ mono --version
Mono JIT compiler version 4.6.2 (Debian 4.6.2.7+dfsg-1ubuntu1)
Copyright (C) 2002-2014 Novell, Inc, Xamarin Inc and Contributors. www.mono-project.com
	TLS:           __thread
	SIGSEGV:       altstack
	Notifications: epoll
	Architecture:  amd64
	Disabled:      none
	Misc:          softdebug
	LLVM:          supported, not enabled.
	GC:            sgen
$ mcs --version
Mono C# compiler version 4.6.2.0
```

# Ubuntu18.04でC# Hello World

```HelloWorld.cs
using System;

public class HelloWorld {
    public static void Main() {
        Console.WriteLine("hello world!");
    }
}
```

```
$ mcs ./HelloWorld.cs
$ ls
HelloWorld.cs  HelloWorld.exe
$ mono ./HelloWorld.exe
hello world!
$ ./HelloWorld.exe
hello world!
```

# まとめ

Monoを使えばUbuntuでC#の開発ができそう
spheroを動かしてみる③

## 今回のお題
円を描く
円の定義：外角が非常に細かい図形

## 工程
基本設計→詳細設計→実装→テストの順に実施

## 基本設計
円を描くための基本動作を考える

案① 細かく曲がりながら進むことで円になる
案② 角度をつけながら進むことで綺麗な円になる
今回は案①を採用し、基本動作は以下の二つで、その二つをループする想定です。

1. 進行角度を決める
2. 直進する
 
以降は上記の動作を繰り返していく

## 詳細設計

・ 角度を決めながら動かないと、円が作れない
・ 角度を細かくすることで、円になる

## 実装
詳細設計を元に作成を行った。
![最初のコーディング.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469881/de9633f0-92d5-bf76-4028-832ca30fbc0f.png)


 **テスト結果**
直進のみ行い、円を描くことができなかった。

 **できなかった理由を考える**
 テストすると「角度」は絶対値の状態で進む方向は変わっていないため、直進しかしなかった。
 →角度を変えながら進む必要があるため、「変数」を使用した。
 再テスト後、曲がることはできたが動きが大きすぎた。
 →一度の進行で進む距離が長いため、スピードを落とすことで距離の調整を行った。
 
 二点を踏まえて作成したフローチャートは以下
 
## 実際に作成したプログラム
![実際のコーディング.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469881/2bee14a6-cabc-66df-9cb4-e8d4ba0a5167.png)

 
## テスト結果
 円を描くことができた。
Pandasで特定の文字列を含む/含まない行を抽出

型が文字列のpandas DataFrameに対して、ある特定の文字列を含む行や含まない行を抽出する方法をメモします。
まず、こういうデータを準備します。

```python:データの定義
>>> df = pd.DataFrame ({"col_A":["dataA_1","dataA_2","dataA_3","dataA_4"],"col_B":["dataB_1","dataB_2","dataB_3","dataB_4"]})
>>> df
     col_A    col_B
0  dataA_1  dataB_1
1  dataA_2  dataB_2
2  dataA_3  dataB_3
3  dataA_4  dataB_4
```

で、col_Aに特定の文字列が含まれる行を調べるには下記でいけます

```python:特定の文字列を含む場合の条件抽出
>>> df[df['col_A'].str.contains('A_1')]
     col_A    col_B
0  dataA_1  dataB_1
```

なぜなら

```python:特定の文字列を含む場合の条件抽出
>>> df['col_A'].str.contains('A_1')
0     True
1    False
2    False
3    False
```
だからです。

で、一方、col_Aに特定の文字列が含まれない行を調べるには下記でいけます.


```python:特定の文字列を含まない場合の条件抽出
>>> df[~df['col_A'].str.contains('A_1')]
     col_A    col_B
1  dataA_2  dataB_2
2  dataA_3  dataB_3
3  dataA_4  dataB_4
```

なぜなら"~"をつけると反転するからです。

```python:解説
>>> df['col_A'].str.contains('A_1')
0     True
1    False
2    False
3    False
Name: col_A, dtype: bool
>>> ~df['col_A'].str.contains('A_1')
0    False
1     True
2     True
3     True
Name: col_A, dtype: bool
```


[数字の場合はこちら][1]
[1]:https://qiita.com/NP_Systems/items/05a79e0372bf9c9003e5


NP-Sytems（ https://np-sys.com )。
zabbixの外部チェックでaws連携した時にハマったこと

# やりたかったこと

EC2やRDSの監視をzabbixでやりたかったが、RDSにはZabbixAgentが載せられないので
RDSのメトリクスを取得して監視を試みた。
awsコマンドでメトリクスを取得するスクリプトを作って、Zabbixの外部チェックでスクリプトを設定し定時実行する流れです。

# 環境
CentOS7
※ EC2ではなくローカルのVM


# ハマったこと
基本的な設定は以下の記事をなぞりましたが、自分の場合はもう少し考慮が必要でした。
恐らくEC2の環境ならあまり気にしなくて良いのだと思います。
zabbixの設定が〜というよりはLINUX関連のハマりです。

参考
[zabbix外部チェックでcloudwatch連携](https://qiita.com/t-okibayashi/items/1422a9a98878d8f9b579)


## zabbixユーザでawsコマンドが実行できない
スクリプトがきちんと動くか確認をとったところ、awsコマンドがうまく動かなかった。

```
$ sudo -u zabbix /usr/lib/zabbix/externalscripts/cloudwatch.sh -n AWS/RDS -m ReadLatency -s Maximum
/usr/lib/zabbix/externalscripts/cloudwatch.sh: line 16: aws: command not found
```

問題：
rootユーザにawscliをインストールしていたので、zabbixでawsが実行できなかった。
zabbixはnologinユーザなのでインストール方法を変える必要があった。

解決:
インストールのoptionを変える。

```bash
## これだとuser限定でインストールされちゃう
$ sudo pip install awscli --upgrade --user
$ echo 'export PATH=$PATH:~/.local/bin' >> ~/.bash_profile
$ source ~/.bash_profile
$ which aws
/root/.local/bin/aws

## これなら誰でも使える
$ sudo pip install awscli --ignore-installed six
$ which aws
/bin/aws
```

## 認証情報がない
awsが実行できたので再度実行してみるも、認証情報がないと怒られた。

```bash
$ sudo -u zabbix /usr/lib/zabbix/externalscripts/cloudwatch.sh -n AWS/RDS -m ReadLatency -s Maximum
Unable to locate credentials. You can configure credentials by running "aws configure".
```

`.aws`をどこに格納したら良いのか。 `/usr/lib/zabbix/.aws`か？
とも思ってやりましたが違うようで、試しに以下のコマンドを打ったらどこに格納すべきか判明しました。

```bash
$ sudo -u zabbix aws configure
AWS Access Key ID [None]:****
AWS Secret Access Key [None]:****
Default region name [None]: 
Default output format [None]: json

[Errno 13] Permission denied: '/var/lib/zabbix'
```
なるほどそこか！

あとは色々作って完成です。

```bash
$ mkdir /var/lib/zabbix
$ mkdir /var/lib/zabbix/.aws
$ vim /var/lib/zabbix/.aws/config
$ vim /var/lib/zabbix/.aws/credentials
$ chmod 755 /var/lib/zabbix/.aws/config 
$ chmod 755 /var/lib/zabbix/.aws/credentials
 
$ sudo -u zabbix /usr/lib/zabbix/externalscripts/cloudwatch.sh -n AWS/RDS -m ReadLatency -s Maximum
0.0118
```

zabbixの画面でも無事に取得できているようでした。めでたしめでたし。
![スクリーンショット 2020-01-17 17.58.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104642/cb494b9b-b62d-6d7c-65b0-3c95957d17a7.png)


# 最後に
認証情報でハマりましたが、監視サーバをEC2でzabbixを使うなら
アクセスキーを使わずIAMロールで接続できるようにすることをお勧めします。
そうすれば`aws configure`の設定は不要になります。
MATLAB で、あの目玉を作ろう。

# 金曜の夕方はやる気が出ない。

　誰かに見られてたらやる気が出るかもしれない！ということで、あいつの出番ですね。

# MATLAB で、こっちを見るアイツを作ってみよう。

　数分でできますね。rectangle で丸を描く。

```matlab:meyes.m
function meyes

F = figure(66);
A = axes;
L = rectangle('Position',[1 0 2 4],'Curvature',[1 1],'LineWidth',9);
R = rectangle('Position',[4 0 2 4],'Curvature',[1 1],'LineWidth',9);
Lb = rectangle('Position',[2 2 0.2 0.2],'Curvature',[1 1],'LineWidth',5,'FaceColor','k');
Rb = rectangle('Position',[5 2 0.2 0.2],'Curvature',[1 1],'LineWidth',5,'FaceColor','k');

A.Position = [0 0 1 1];
axis([0 7 0 4])
axis off
axis equal
```

いい感じ。

![eyes.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/475339/fbf1c732-f926-ad19-f82a-92fc4740bbf4.png)

けど正面しか見ないし、瞳孔が開いてる。

# カーソルを追わせよう。

WindowButtonMotionFcn を書けばいいね。

```matlab:meyes.m
function meyes

F = figure(66);
A = axes;
L = rectangle('Position',[1 0 2 4],'Curvature',[1 1],'LineWidth',9);
R = rectangle('Position',[4 0 2 4],'Curvature',[1 1],'LineWidth',9);
Lb = rectangle('Position',[2 2 0.2 0.2],'Curvature',[1 1],'LineWidth',5,'FaceColor','k');
Rb = rectangle('Position',[5 2 0.2 0.2],'Curvature',[1 1],'LineWidth',5,'FaceColor','k');

F.WindowButtonMotionFcn = @Move;
A.Position = [0 0 1 1];
axis([0 7 0 4])
axis off
axis equal

    function Move (~,~)
        xy = A.CurrentPoint;
        Lb.Position = [([xy(1),xy(3)] - [2,2])./[7,3]+[2 2]  0.2  0.2];
        Rb.Position = [([xy(1),xy(3)] - [5,2])./[7,3]+[5 2]  0.2  0.2];
    end
end
```

![eye_cursor.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/475339/cc5cc964-3103-12e9-75f0-314371c70f88.png)

追うようになりました！
終わり！


# ところで、そもそも Xeyes ってなんなんだろう・・・

　Linux の動作チェックにしか使ったことがないけど、調べてみたら30年くらい前の古典プログラムですね。
https://ja.wikipedia.org/wiki/Xeyes
MC Works64で画面起動時にコマンドを実行する

GraphWorksで画面起動時に何のトリガも無しでコマンドを実行したいと前々から思っていたが、コレを使えば出来たのでメモメモ。
画面起動時に初期値を書き込むときなんか便利。

やり方は簡単。ボタンを配置してダイナミックプロパティの「InitialClick」をTrueにするだけ。
これでランタイム開始時にコマンドを実行してくれる。
後はボタンを非表示にしておけばいい。

以下は、ローカル変数に現在時刻を書き込んでみるサンプル
![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/504156/a5709e0b-767b-c368-fb23-15bb82ba3f49.png)

ランタイムしてみた画面が以下。
![無題2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/504156/2094b6c2-208c-2ec1-6a69-98705832dbaf.png)
[Python]type関数から型名を文字列で取得してみた

# Motive
[paiza](https://paiza.jp/)でRPGゲームとコード学習を融合した[コードクロニクル](https://paiza.jp/codechronicle)が最近リリースされました。

<img width="100%" src="https://paiza.jp/codechronicle/images/chronicle_bnr_960_280.png">


それで試しに問題をといていったのですが、入門者向けなので基本的な構文についての問題が繰り返し出題される形式だったので難易度は難しくないですが、下記の問題が出題されました。(全く同一ではないです。)

```Python

#piの変数型を出力してください
pi = 3.14

print("") #int, str, floatのどれかを入力してください。
```

答えは `print("float")` とすればいいのですが `type`関数がせっかくあるので利用できないかと考えたとです。:rolling_eyes: 

# Method

シンプルに`type`関数を使うと、、、

```python
>> type(pi)
#<class 'float'> 
```

の通りクラスの型が出力されます。

単純に `str()` を使えばいいかなと思ったのですが、、、

```python
>> str(type(pi))
#"<class 'float'>"
```
`"<class 'float'>"` が文字列として出力されるので、期待している`float`とは異なります。

[Python document](https://docs.python.org/ja/3/)で[type関数](https://docs.python.org/ja/3/library/functions.html#type)について読んでみると、

*name 文字列はクラス名で、 `__name__` 属性になります。*

と書かれていたのでクラスの属性を取得すれば`float`が取得できます。

```Python
>> type(pi).__name__
# `float`
```

# Digest

`#変数型を出力してください` の問題が出たときは整数・文字列・小数点のいずれかの型でも
`type(pi).__name__`
と書けば正解になる銀の弾です。:gun:

# Future
[コードクロニクル](https://paiza.jp/codechronicle)なんすけど、来年度から政府がゴリ押し:robot:で進めているプログラム学習に合わせたアプリゲームだと思うのですが、、、
ゲームバランスを考えつつ問題を作る、問題を作る仕組みを設計すると開発メンバーを揃えないと運用が厳しそうです。
入門者向けであればこの難易度でいいかもしれません。

# Reference
- [コードクロニクル](https://paiza.jp/codechronicle)
- [type関数](https://docs.python.org/ja/3/library/functions.html#type)
Vostoro 3252 スモールシャーシWindows8.1再インストール

Dell Vostoro 3252 スモールシャーシのWindows8.1再インストールメモ。

Dellは同じ品名でもケースにより構成違うことありますが、外付けACアダプタモデルです。

検証用にWindows8.1をインストールしたのですが、クリーンインストール後WindowsUpdateしたあとデバイスマネージャーを確認すると二つ×がついてました。

ドライバはDellのサポートページでServiceTagを入れたらダウンロードできます。

以下をインストールすればｘが消えた。

- チップセットドライバー
- Realtek RTS5710 Card Reader Driver

なおCard Readerはインストールしたらインストールエラーになりました。lhaplusでインストールファイルを展開してデバイスマネージャーでドライバの展開場所を指定したらインストール成功。（何を言ってるかわからないならやめとくのをお勧めします。）

あと、ダウンロードページでBIOSに「緊急」と書いてあるファイルが置いてあるのでも導入もおすすめします。
Node.js: Redis のキーの一覧を取得

## ライブラリーのインストール

```bash
sudo npm install -g redis
```
## プログラム

```js:redis_list.js
#! /usr/local/bin/node
// ---------------------------------------------------------------
//	redis_list.js
//
//					Mar/25/2023
//
// ---------------------------------------------------------------
'use strict'

const redis = require('redis')

// ---------------------------------------------------------------
async function main()
{
	const client = redis.createClient()

	await client.connect()

	const keys = await client.keys('*')
	console.log (keys)
	console.log("keys.length = " + keys.length)
	console.log ("keys[0] = " + keys[0])

	await client.disconnect()

	console.error ("*** 終了 ***")
}

// ---------------------------------------------------------------
console.error ("*** 開始 ***")
main()

// ---------------------------------------------------------------
```

## 実行結果

```text
$ export NODE_PATH=/usr/local/lib/node_modules
$ ./redis_list.js
*** 開始 ***
[
  't1859', 't1858',
  't1857', 't1855',
  't1851', 't1853',
  't1852', 't1854',
  't1856'
]
keys.length = 9
keys[0] = t1859
*** 終了 ***

```

## 確認したバージョン

```text
$ node --version
v22.3.0
```

関連ページ
[Node.js: Redis のデータを読む](https://qiita.com/ekzemplaro/items/277fce6168dab745264f)
ConoHaで接続許可ポートをsshにしつつmoshも通す方法

[ConoHa](https://conoha.jp/vps)には「接続許可ポート」という機能があって、コントロールパネルからVPSへのポート制限を行うことができます。

<img width="1329" alt="port1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44152/a73e04f5-3a42-5a5a-6b5d-6eedb6715985.png">

この設定を「全て許可」で運用しても問題はありませんが、一般的には使うポートだけを許可するのが良いとされています。サーバー上で意図しないプログラムが動いていた場合などでも、外部からの通信を遮断することができるからです。

## moshでポートが通らない

私は普段sshではなく[mosh](https://mosh.org/)を使っています。moshはsshの代替のようなツールで、接続が切れた場合の自動再接続や、優れたローカルエコーがあるのでとても便利です。

moshの実際の挙動は、まずsshでサーバーに接続を行い、認証が完了した後にサーバー上で``mosh-server``と言うコマンドが実行されてクライアントとの接続が確立します。なので、moshは単体では使えません。必ずsshとセットで使うことになります。

sshは``22/tcp``を使いますが、moshは``60000-61000/udp``を使います。上記のスクリーンショットのように、コントロールパネルからsshのポートだけを許可しても、udpを使うmoshは使うことができません。とは言っても「全て許可」での運用は避けたいものです。

## セキュリティグループを使う

ConoHaには[セキュリティグループ](https://www.conoha.jp/docs/neutron-create_secgroup.php)と言う機能があって、接続元のIPアドレスやポート番号を使ってパケットフィルタリングを行えます。前述の「接続許可ポート」もこのセキュリティグループを使って実装されています。なので、moshを使うにはセキュリティグループを使って60000-61000/udpを許可してあげればよいのです。

本来セキュリティグループは[ConoHa API](https://conoha.jp/docs)を使って作業するのですが、結構大変です。[conoha-net](https://github.com/hironobu-s/conoha-net)というCLIツールを使うと簡単に操作することができます。

> 参考
> [ConoHaでセキュリティグループを設定する](https://qiita.com/hironobu_s/items/1bb6a8886ae91bb553c9)

conoha-netやセキュリティグループの詳細は上の記事を読めばわかります。なのでここではやり方だけ解説します。


```shell

# conoha-netのインストール
# これはLinux向けですが、OSXやWindowsのインストール方法もREADME.mdにあります
curl -sL https://github.com/hironobu-s/conoha-net/releases/download/current/conoha-net-linux.amd64.gz | zcat > conoha-net && chmod +x ./conoha-net

# 環境変数の設定
# APIの設定については下記URLを参考にしてください
# https://github.com/hironobu-s/conoha-net#1-%E8%AA%8D%E8%A8%BC
export OS_USERNAME="gncu*****"
export OS_PASSWORD="********"
export OS_AUTH_URL="https://identity.tyo1.conoha.io/v2.0"
export OS_TENANT_ID="*******************************"

# VPS一覧を見てみる
./conoha-net list

NameTag    IPv4               IPv6                                    SecurityGroups
my-vps     150.95.***.**      2400:8500:1302:829:***:***:***:***      gncs-ipv6-all, gncs-ipv4-all, default

# moshを通すためのルールを格納するセキュリティグループ(permit-mosh)を作る
./conoha-net create-group permit-mosh

# 60000-61000/udpを許可するルールをpermit-moshに追加する
./conoha-net create-rule -p 60000-61000 -P udp permit-mosh

# permit-moshをVPS(my-vps)にアタッチする
./conoha-net attach -n my-vps permit-mosh

# 正しく設定されたか確認
# permit-moshが追加されていればOK
./conoha-net list

NameT      IPv4               IPv6                                    SecurityGroups
my-vps     150.95.***.**      2400:8500:1302:829:***:***:***:***      gncs-ipv6-all, permit-mosh, gncs-ipv4-all, default
```

これでmoshがつながるはずです。

```
mosh 150.95.***.**
```
演算子早見表

##・論理演算子(!, &&, ||, not, and, or)

!a                   # a が false であれば
a && b               # a かつ b が true であれば
a || b               # a または b が true であれば
not a                # a が false であれば
a and b              # a かつ b が true であれば
a or b               # a または b が true であれば

##・比較演算子(==, !=, <, >, <=, >=, <=>, ===)

a == b        # a と b が等しい
a != b        # a と b が等しくない
a < b         # a が b よりも小さい
a > b         # a が b よりも大きい
a <= b        # a が b 以下である
a >= b        # a が b 以上である


##・代入演算子(=, +=, -=, *=, /=, %=, **=, &=, |=, ^=, <<=, >>=)

a = b         # a に b を代入する
a += b        # a = a + b に同じ
a -= b        # a = a - b に同じ
a *= b        # a = a * b に同じ
a /= b        # a = a / b に同じ
a %= b        # a = a % b に同じ
a **= b       # a = a ** b に同じ
a &= b        # a = a & b に同じ
a |= b        # a = a | b に同じ
a ^= b        # a = a ^ b に同じ
a <<= b       # a = a << b に同じ
a >>= b       # a = a >> b に同じ
a &&= b       # a && (a = b) に同じ
a ||= b       # a || (a = b) に同じ
##まとめ
優先順位に注意ですね
MySQL Workbenchでupdate文を実行したら「Error Code: 1175」のエラーが出た

# はじめに
MySQL Workbenchにて、update文を実行したら、以下のエラーが出たので対処法を残します

```
Error Code: 1175. You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column.  To disable safe mode, toggle the option in Preferences -> SQL Editor and reconnect.	0.0017 sec
```

# 環境
MySQL Workbench 8.0

# 結論
「Safe Updates」の設定をオフにすることで、エラーはでなくなります


# 設定方法

- MySQL Workbenchを起動して、メニューを以下の順で選択します
    - 「MySQLWorkbench」→「Preferences」

- 左のメニューの「SQL Editor」を選択して、一番下までスクロールすると「Safe Updates」の設定があるので、チェックをはずして、「OK」ボタンをクリックします（以下イメージ参照）

<img width="797" alt="image.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103774/b5b82b06-fb78-95a7-0260-61afb91a2b15.jpeg">

- データベースに再接続すれば、設定が有効になり、update文が実行できます

# まとめ
設定を変更することで、update文が実行できるようになりますが、オフにすることでwhere句なしで更新できてしまうので、本番環境にアクセスするときは気をつけましょう
設定をオンにしておくとよいかと思います
Git 取り消したい系4選

#注意書き
場合によっては後戻りできなくなる可能性がありますので、
くれぐれもしっかり確認して、自己責任でお願い致します。

###git addを取り消す
```bash
//初めてのgit addを取り消す
$git rm --cached -r . //addした全ファイル
$git rm --cached -r (ファイル名) //指定ファイル

//2回目以降のgit addを取り消す
$git reset HEAD
$git reset HEAD (ファイル名)
```
--cachedを付けることで管理対象から外します
付けないとファイルが消えてしまうので注意！！

###git commitを取り消す
```bash
$git reset --soft HEAD^
```
--softはHEADの位置のみ戻します
--hardなどのオプションもありますが、ものすごくわかり易く解説してくださってる方がいるので見てみて下さい。
[git resetのオプション](https://qiita.com/shuntaro_tamura/items/db1aef9cf9d78db50ffe)

###変更点の取り消し
git statusしたら modifyで出てくるようなgitで追跡されているファイルの変更を取り消します

```bash
$git checkout .
```

###新規ファイルの取り消し
git statusしたら new fileで出てくるようなgitで追跡されていないファイルを取り消します（無くなったことになります)

```bash
$git clean (オプション)
```
[git cleanのオプション](https://gotohayato.com/content/104/)


##鼓舞
お互い、これらを出来るだけ使わなくていいように、よく確認してgit管理しましょう！
Let's use git safety!!
AWS CDKでVPC作ろうとしたら作れなかったとき

CloudFormationからAWS CDKに乗り換えようとして今日も元気にビルドを失敗したので解決方法をメモっておく。

### やりたいこと

私はただAWSのサンプルをビルドしたかっただけなんだ…！！
https://github.com/aws-samples/aws-cdk-examples/tree/master/python/ecs/fargate-load-balanced-service

###無慈悲なCREATE_FAILED

CloudFormationと違って抽象化が激しいので、一行でVPCを作れるんですよ。
その代わり中身を全く知らない。

##### VPCができる魔法の素晴らしいコード

``` Python
vpc = ec2.Vpc(
  self, "MyVpc",
  max_azs=2
)
```

##### 無慈悲に幻想を打ち砕くCREATE_FAILED

``` bash
$ cdk deploy
　　～略～
Do you wish to deploy these changes (y/n)? y
　　～略～
  9/36 | 7:11:35 AM | CREATE_COMPLETE      | AWS::EC2::VPC                             | MyVpc (MyVpcF9F0CA6F) 
　　～略～
 10/36 | 7:11:38 AM | CREATE_FAILED        | AWS::EC2::Subnet                          | MyVpc/PublicSubnet1/Subnet (MyVpcPublicSubnet1SubnetF123456) Value (ap-northeast-1a) for parameter availabilityZone is invalid. Subnets can currently only be created in the following availability zones: ap-northeast-1d, ap-northeast-1c, ap-northeast-1b. (Service: AmazonEC2; Status Code: 400; Error Code: InvalidParameterValue; Request ID: xxxxx-xxxx-xxxx-xxxx-xxxxxxxxx)
```

##### 彼が私に伝えたかったこと

```
Subnets can currently only be created in the following availability zones: 
ap-northeast-1d, ap-northeast-1c, ap-northeast-1b.
```

はい。Subnetを作る時にアベイラビリティーゾーンに振り回されるのはCloudFormationの頃から慣れてます。慣れてるなりにさっさと解決したいのにどうすればいいのか分からず途方に暮れる。
ap-northeast-1aに作ろうとして怒られたんだろうなという事くらいは分かる。逆に言うとなんでそこに作ろうとしたのかまったく知らないんですよこっちは。

### 解決方法

cdk.context.json っていうファイルにavailability-zonesの指定があるので、`ap-northeast-1a`があったら消す。
指定がなかったら下記の内容を追記する。

``` cdk.out/cdk.context.json
  "availability-zones:account=123456789999:region=ap-northeast-1": [
    "ap-northeast-1b",
    "ap-northeast-1c",
    "ap-northeast-1d"
  ]
```

### おわり

3時間くらい悩んだ…。つらかった……。
まだまだCDKと仲良くなれない。

ところでgitignoreを見るとcdk.context.jsonがignoreされてるっぽいのですが、この設定って本当はどこに書いておくものなのかご存知の賢者様がいらっしゃれば教えていただけると嬉しいです。

～追記～
コマンドで設定したりcdk.jsonに書いたりソースコード内で指定したりしなさいって書いてありました^q^

> * Through the --context option to the cdk command.
> * In the context key of the project's cdk.json file.
> * In the context key of a ~/cdk.json file.
> * In code using the construct.node.setContext method.

>https://docs.aws.amazon.com/cdk/latest/guide/context.html
【Nuxt.js】plugin実践編：vue-scrolltoでスムーズにスクロール

# vue-scrolltoとは
ページ内リンク(アンカーリンク)で
スクロールしながら指定場所に飛びます🧚‍♀️💫
**【公式】**
https://www.npmjs.com/package/vue-scrollto

# 比較: vue-scrollto未使用
味気ない🌀
nuxt-linkを使うと1回しか機能しない
a hrefでやれば解決するけど…
どうせならnuxt-link使いたいじゃない

![anchor.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469755/12a2d9b6-20fd-9815-78b8-751c9fe76f80.gif)

```index.vue
<template>
 <div class="page">
   <nuxt-link to="#anchor">
     下に飛ぶ
   </nuxt-link>
   <div id="anchor">
     とべた！
   </div>
 </div>
</template>
```

# 比較: vue-scrollto使用
スクロールバーに着目👀
スルスルっとスクロール🍒
通常と違い、何回でもとべますね。
コードはstep順に記載していきます✍️

![scrollto.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469755/c68248eb-e6bb-a239-3c00-ecb222815c16.gif)

# step1: インストール

```bash:ターミナル
$ npm i vue-scrollto
```

```bash:file
pages/
--| sample.vue

plugins/
--| vue-scrollto.js

nuxt.config.js
```

# step2: /pluginsにjsファイルを追加
**【vue-scrollto.js】**
・Nuxt.jsでpluginを使用時の書き方
https://ja.nuxtjs.org/api/configuration-plugins/

・オプションは公式の
　**Options**項目で確認できます。

　**duration**: スクロール継続時間
　**easing**: 速度の緩急
　**offset**: 遷移後の位置調整
　　　　  少しだけ上に設定すると⭕️

easingに関してはここが参考になります！
https://note.com/ritar/n/n5e8ed0e07917

```vue-scrollto.js
import Vue from 'vue'
import VueScrollTo from 'vue-scrollto'

Vue.use(VueScrollTo, {
 duration: 700,
 easing: [0, 0, 0.1, 1],
 offset: -100,
})
```

# step3: nuxt.config.jsのpluginsに記載

```nuxt.config.js
plugins: [
  '~plugins/vue-scrollto'
],
```

vue-scrollto.jsに記載したoptionsは
modulesに記載することもできます。
vue-scrollto公式の**Nuxt.js**項目で確認できます。

ただvue-scrollto.jsに書いた方が
まとまって分かりやすいと思います💡

```nuxt.config.js
 modules: [
   ['vue-scrollto/nuxt', { duration: 700 }],
 ],
```

# step4: テンプレートでページ内リンクを作成
**【sample.vue】**
・nuxt-link toの中にv-scroll-toを入れる
　toが2個あって変な感じがしますが
　どちらも必要なので削らないように✏️
・リンク先を''で囲む

この書き方は
vue-scrollto公式の
**Usage**項目で確認できます。

```sample.vue
<template>
 <div class="page">
   <nuxt-link
     v-scroll-to="'#anchor'"
     to
   >
     下にとぶ
   </nuxt-link>
   <div id="anchor">
     とべた！
   </div>
 </div>
</template>
```



これで完成です🤗🎉

# ローカルver
一応ローカルの書き方も。
vue-scrollto.jsをまるごとコピペで⭕️
オプションもdata内に書けば適応されます。

```sample.vue
<template>
 <div class="page">
   <nuxt-link
     v-scroll-to="'#anchor'"
     to
   >
     下にとぶ
   </nuxt-link>
   <div id="anchor">
     とべた！
   </div>
 </div>
</template>

<script>
import Vue from 'vue'
import VueScrollTo from 'vue-scrollto'

Vue.use(VueScrollTo, {
 duration: 700,
 easing: [0, 0, 0.1, 1],
 offset: -100,
})

export default {
 data () {
   return {
     options: {
       el: '#anchor',
       onDone: (el) => console.log(el)
     }
   }
 }
}
</script>

<style lang="scss" scoped>
 #anchor {
   margin-top: 1000px;
 }
</style>
```


今まで週3で投稿していましたが
来週から月水の2回に変更致します💡
自社サービスに手をつけているためです。
お楽しみに🌟

落ち着いたらまた週3になるかも？
ECSでdocker volumeマウントのownerを指定する

ECSでdocker volumeをマウントするとownerはrootになります。
指定したい場合は、タスク定義のボリューム定義で、`dockerVolumeConfiguration.driverOpts` を指定しましょう。
例えば、tmpfsとしてボリュームを作成してownerをuid=1000, gid=1000にしたいときは、

```json
  "volumes": [
    {
      "name": "sharedtmp",
      "dockerVolumeConfiguration": {
        "autoprovision": true,
        "scope": "shared",
        "driverOpts": {
          "type": "tmpfs",
          "device": "tmpfs",
          "o": "uid=1000,gid=1000"
        }
      }
    }
  ]
```

こうすることで ボリューム作成の際に以下のようにオプションをつけて作成してくれます。

```bash
$ docker volume create --opt type=tmpfs --opt device=tmpfs --opt o=uid=1000,gid=1000 sharedtmp
```

ElasticBeanstalkからECSを使う場合も、Dockerrun.aws.jsonに同じように書くだけです。
以上です。
Javascriptコーディングでグローバル汚染を防ぐために即時関数を利用する方法

Javascriptを用いた開発を行うときに、一般的に出回っている入門書のように、jsファイル内でそのまま変数を定義すると、他のjsファイルを読み込んだ際に、変数がバッティングしてコンテンツの機能が停止することがあります。
こういったことはバグの元ですし、特にチーム開発では大きな支障があります。

それを防ぐために、一つのjsファイル内で作成した変数が他コンテンツに干渉しないようにする必要があります。

具体的には、jsファイルを即時関数で囲うことになります。
以下に2通りのひな型を記します。


```javascript

(function (root) {


  var initialize = 以下略
  var insert = 以下略

  root.SomeThing = root.SomeThing || {};
  
  // 他のjsファイルで用いたい関数を以下に記述
  root.SomeThing.Main = { 
    initialize: initialize,
    insert: insert
  };

}(typeof window === 'object' ? window : typeof global === 'object' ? global : this));
```


多数の関数や定数を流用したい場合は以下のやりかたもあります。

```javascript

(function(root) {

  var SomethingConst = {};  //←ナニモノか連想配列を定義します（ここでは例としてSomethingConstとする）

  /*ここに、定義したい定数を用意します。定数は「SomethingConst.honyarara =」と言う形で記述*/

  root.SomethingConst = SomethingConst; //←rootのメソッドとして実行したい関数を設定

}(typeof window === 'object' ? window : typeof global === 'object' ? global : this));
```
GCP CloudFunctionsの実行IPアドレスを固定化する方法

# 2020/02/03　追記
CloudFunctionsのIP固定ですが、proxyサーバ立てないでマネージドでも出来るようになりました！
https://cloud.google.com/functions/docs/networking/network-settings?hl=ja#associate-static-ip

下記に書いた構成からproxyサーバを外していただき
CloudFunctionsの設定で
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80769/cfd2859f-ed30-179d-2d95-49839598014d.png)
`すべてのトラフィックをVPCコネクタ経由でルーティングする`

に変更すればproxyサーバ無くてもIPの固定が出来ます！

# はじめに
gcp の[CloudFunctions](https://cloud.google.com/functions/?hl=ja)は便利ですが、IPが固定されていなく、VPC内での起動も出来ないのでNATを通す事も出来ません。
IP制限がされているサービスに対してCloudFunctionsでアクセスしたい場合ってありませんか？
私はありました！！

単純にproxy通せば出来るのですが、その場合proxyサーバに対するアクセスのIPを固定出来なく、[ServerlessVPCAccess](https://cloud.google.com/vpc/docs/configure-serverless-vpc-access?hl=ja)を使って出来ないかな？と考え、セキュアにIP固定化する事が出来ました！！！

これでもうIP制限なんて怖くない！！！！

# 構成
<img width="786" alt="スクリーンショット 2020-01-17 15.48.21.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80769/aeb7e1ad-2479-c261-b681-48b242799379.png">

CloudFunctionsからServerlessVPCAccessを使って、内部IPでVPC内のproxyにアクセスします。
proxy経由をして外に出ればCloudFunctionsの実行IPはNATのIPとなります。

それぞれの設定方法など見ていきましょう

## ServerlessVPCAcess
[ServerlessVPCAccess](https://cloud.google.com/vpc/docs/configure-serverless-vpc-access?hl=ja)こちらのドキュメントを参照してproxyが立っているsubnetにアクセス出来るコネクタを作成しましょう

設定するIPは接続するVPC内のIPと重複しないようにしなければいけません。
ここで設定したIPでVPC内のリソースへアクセスすることになります。

## proxyサーバ
GCEをたて、そこにsquidをつかってproxyサーバをたてました

squidのたて方は以下になります


```bash

# squidのインストール
sudo apt install squid

# 設定ファイルの修正
sudo vi /etc/squid/squid.conf

# 1194行目あたりにある以下をコメントアウト
# http_access deny all

# 1612行目あたりにあるportを任意の番号に変更(3128はsquidデフォルトなので使わない)
http_port 33228

# ファイルの末尾に以下を追加
# ServerlessVPCAccessのIPを追加
acl myacl src X.X.X.X/28
http_access allow myacl
http_access deny all

# プロキシサーバ接続端末のIP隠蔽
forwarded_for off

# プロキシ経由のアクセスをアクセス先に隠蔽
request_header_access X-Forwarded-For deny all
request_header_access Via deny all
request_header_access Cache-Control deny all

# squidの再起動
sudo service squid restart

# proxyのログ確認する場合は以下のファイルを確認
/var/log/squid/access.log
```

squidサーバが出来たら、以下の通信を許可するファイアーウォールを作って、GCEにつけましょう
tcp [ServeressVPCAccessのIP]:[squidのport]

## CloudFunctions
CloudFunctionsでServerlessVPCAccessを使うには権限設定をしなくてはいけません。
[こちら](https://cloud.google.com/functions/docs/connecting-vpc?hl=ja)のページを参考に、権限設定を行い、ServerlessVPCAccessのコネクタを使うCloudFunctionsを作りましょう。

IPの確認をしたいのみでしたら以下のソースで確認出来ます

```python
def hello_world(request):
  import urllib.request


  # グローバルIPアドレスを取得
  ip = urllib.request.urlopen('http://checkip.dyndns.com/').read().decode('utf-8')
  return ip
```

CloudFunctionsからのアクセスをproxyサーバ通すには環境変数の設定が必要になります。
以下の環境変数を設定します
http_proxy http://[proxyサーバの内部IP]:[proxyサーバのport]

## CloudNat
[こちら](https://cloud.google.com/nat/docs/?hl=ja)のドキュメントを参考にproxyサーバがあるVPCにCloudNatをたてましょう


# おわりに
以上で設定は完了です。
CloudFunctionsのテスト実行をして、アウトプットにCloudNatのIPが出てきたら成功です！！

今回はproxyサーバを1台だけたてて、proxyサーバの内部IPを使いましたが、こちらをインスタンスグループとして、ロードバランサーたてるなどするとエンドポイントも変わらず、冗長性もたもてる構成にすることが出来ます。
「あー」とか「うわー」は正しい日本語か？

入力値がひらがなかを検査するメソッドをテストしていて気付きました。
「あー」とか「うわー」は正しいか？

```
bool check(str){
    return ひらがなの範囲.Has(str);
}

debug.print(check("あー"));
```

なぜかFalseが帰ってくる。

「ひらがなの範囲」は、文字コードの範囲で
3041「ぁ」〜309F「ゟ」
を指定しています。
[wikipedia ひらがなのコード表](https://ja.wikipedia.org/wiki/%E5%B9%B3%E4%BB%AE%E5%90%8D_(Unicode%E3%81%AE%E3%83%96%E3%83%AD%E3%83%83%E3%82%AF))

よく見ると、あれ？
「ー（長音）」がない！？

調べてみました。
どうやら、**[本来ひらがなには長音が存在しない](https://benesse.jp/kyouiku/200711/20071120-53.html)**らしい。
つまり、「あー」とか「うわー」は日本語としては正しくない、という事でしょう。

えー（←また使ってしまった）知らなかった。
小学校でならってたのかなぁ…
でもまぁ普通に使ってると思うので、今回は30FC（カタカナの「ー」）を「ひらがなの範囲」に追加することにしました。


しかし驚きました。
HTML ,CSS

![girl02_angry.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563190/9a6cdb40-9ed6-eb27-45f7-5af16e435fab.png)

　　　　売れない時のスナカワさん
## 要素
子要素と親要素の関係を再確認。
### clearfix
　👉float現象を阻止。
    左右に要素が回りこむようになるだけでなく要素が宙に浮いた状態になるのでそれを防止できる。

### display: flex;
　👉縦並びだった子要素を横並びにできる。

### position: relative;
　👉親要素に付与すると、子要素の基準を自身の要素として指定することができる。

### position: absolute;
　👉要素の配置を絶対指定する。

### hover,visited
　👉擬似要素（擬似クラスとの単語の使い分けがちょっと何言ってるかわからなかったです。）
【Sass】おすすめプラグイン

###はじめに
アルバイトでSassを使ってるうちにPostCSSに救われているなーと感じることが多い今日この頃。
Sassは1人で開発する場合は導入・学習コストの方が高く感じ、コンパイルさえ出来ればいいか。。という感じになってしまいます。
でも1人で開発するでも便利なプラグインありますのでここで紹介させてください。

###対象
チーム開発を行う機会のない駆け出しエンジニアの方や学生

###目次
1,PostCSSとは
2,PostCSSのインストール
3,PostCSSのおすすめプラグイン

##１,PostCSSとは

PostCSSはNode.js製のCSS変換ツール。SassとCSSの両方に使える。

##2,PostCSSのインストール

Sass環境構築が完了していることを前提で話を進めます。

```
npm install --save-dev gulp-postcss
```

↑これだけでPostCSSのインストール完了です。

```gulpfile.js
//var gulp = require('gulp');
//var sass = require('gulp-sass');
var postcss = require('gulp-postcss');

```

↑パッケージのインストールは完了したのでgulpfile.jsファイルに読み込む設定をします。

##3,PostCSSのオススメプラグイン
###Autoprefixcer
・ベンダープレフィックスを自動付与してくれるプラグイン。
（display:flex;をよく使うので便利だと感じました）
#####インストール方法
まずプロジェクトのディレクトリ直下で

```
npm install --save-dev autoprefixer
```

↑これでパッケージのインストールが完了したので
　　・gulpfile.jsに読み込み
　　・タスクに追加
の２つを行います。

```gulpfile.js
//var gulp = require('gulp');
//var sass = require('gulp-sass');
//var postcss = require('gulp-postcss');
var autoprefixer = require('autoprefixer');/*Autoprefixerをgulpfile.jsに読み込ませる*/
gulp.task('sass', function() {
  //return gulp.src('./sass/**/*.scss')
    //.pipe(sass({outputStyle: 'expanded'}))
    .pipe(postcss([autoprefixer()]))/*タスクにautoprefixerを追加*/
    //.pipe(gulp.dest('./css'));
});
```
###CSS-MQPakcer
・メディアクエリがバラバラの位置にコンパイルされるのを防ぎ、メディアクエリを綺麗にまとめるプラグイン。
（これを入れておくだけで、コンパイルされるCSSのコード量が大幅に減ったので必須だなと感じました。）
#####インストール方法
まずプロジェクトのディレクトリ直下で

```
npm install --save-dev css-mqpacker
```

↑これでパッケージのインストールが完了したので、Autoprefixerと同様に
　　・gulpfile.jsに読み込み
　　・タスクに追加
の２つを行います。

```gulpfile.js
//var gulp = require('gulp');
//var sass = require('gulp-sass');
//var postcss = require('gulp-postcss');
var mqpacker = require('css-mqpacker');/*MQPackerをgulpfile.jsに読み込ませる*/
gulp.task('sass', function() {
  //return gulp.src('./sass/**/*.scss')
    //.pipe(sass({outputStyle: 'expanded'}))
    .pipe(postcss([mqpacker()]))/*タスクにMQPackerを追加*/
    //.pipe(gulp.dest('./css'));
});
```
###おわりに
コピペして頂けたらすぐに使えると思います。
自分もまだSassを使い始めて1ヶ月ぐらいなのでもっと勉強していきます。
便利なのでSass勉強したての方はぜひインストールしてみてください！！
【Rails】メールアドレスを記憶する

ログインフォームに「次回からメールアドレスの入力を省略する」というチェックボックスをつけて、次回ログインフォームにアクセスした時にメールアドレスが自動で入力される機能を実装したので、実装方法を記録します。

###全体の流れ
- ログインフォームにチェックボックスをを設置
- チェックされた状態でログインしたら、メールアドレスを暗号化してcookieに保存
- 次回以降のログイン時、cookieにメールアドレスが保存されているかを確認して、あれば利用
- チェックを外した状態でログインしたら、cookieに保存されているメールアドレスを削除

###Controller
```rb
def create
  customer = Customer.find_by(email: params[:session][:email].downcase)
  if customer&.authenticate(params[:session][:password])
    if params[:session][:remember] == '1'
     #cookieを登録
      cookies.permanent.signed[:wbEmail] = params[:session][:email]
    else
     #cookieを削除
      cookies.permanent.signed[:wbEmail] = nil
    end
    log_in customer
    flash[:success] = 'ログインしました'
    redirect_to root_url
  else
    flash.now[:danger] = 'メールアドレスとパスワードの組み合わせが正しくありません'
    render 'new'
  end
end
```

###ログインフォーム
```erb
<%= form_with scope: :session, url: login_path, local: true do |f| %>
    <label>メールアドレス</label>
    <% if cookies.permanent[:Email].blank? %>
    <%= f.email_field :email %>
    <% else %>
    <%= f.email_field :email, value: cookies.permanent.signed[:Email] %>
    <% end %>

    <label>パスワード</label>
    <%= f.password_field :password %>

    <% if cookies.permanent[:Email].blank? %>
    <%= f.check_box :remember, id: "check1" %>
    <% else %>
      <%= f.check_box :remember, id: "check1", checked: true %>
    <% end %>
    <label for="check1">次回からメールアドレスの入力を省略する</label>

  <%= f.submit "ログイン" %>
<% end %>
```