OmniAICreator/Qiita-1.07M huggingface dataset:
動的にフォームを追加、削除する

# 追加した分もDBに保存したい

初投稿です。

フォームを追加、削除する記事はいくつかあったのですが、
DBに保存できるようにする記事は見つけられなかったので備忘録として投稿します。

初学者なのでアラが目立つコードだと思いますが、どなたかの役に立てば幸いです。

間違えや、添削があればコメントにて教えていただければものすごく嬉しいです。


```ruby:new.html.rb

<!--動的に追加、削除できる材料、分量のフォームを別テーブル(ingredients)に保存-->
<%= javascript_pack_tag 'addForm.js'%>

  <%= f.fields_for :ingredients do |ingredient| %>

    <div id="ingredient-main">
      <div id="ingredient-form">
        <div id="add-form">
          <%= ingredient.text_field :name, id:"ingredient-name_0",  placeholder: "材料-0" %>
        </div>
        <div id="add-form">
          <%= ingredient.text_field :amount, id:"ingredient-amount_0", placeholder: "分量-0" %>
        </div>
        <div class="delete" id='add-form'>
          <button type="button" id="ingredient-btn_0" class="delete-btn" >
            削除
          </button>
        </div>
      </div>
    </div>
  <% end %>
    
```








```javascript:addForm.js


let formNum = 0

//ページがロードされると...
window.addEventListener("load", function () {
  
  //材料追加ボタンの要素をidから取得
  const addButton = document.getElementById("add-btn");

  //取得したボタンをクリックすると...
  addButton.addEventListener("click", function() {

    //1行目で変数宣言したformNumに1を足す。(formNumに1が＋される)
    formNum += 1

    //材料と分量のフォーム、削除ボタンを取得,formListに代入
    const formList = document.getElementById("ingredient-main")

    //html要素を取り出し記入,idとplaceholderの0に指定していたところに
    //${formNum}を挿入することで、一つ目のフォームにはingredient-name_0、
    //二つ目はingredient-name_1、三つ目はingredient-name_2と足されていく
    const html = ` <div id="ingredient-form">
                    <div id="add-form">
                      <input id="ingredient-name_${formNum}" placeholder="材料-${formNum}"
 　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　type="text" name="repertoire[ingredients_attributes][${formNum}][name]">
                    </div>
                    <div id="add-form">
                      <input id="ingredient-amount_${formNum}" placeholder="分量-${formNum}" 
　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　type="text" name="repertoire[ingredients_attributes][${formNum}][amount]"> 
　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　</div>
                    <div class="delete" id='add-form'>
                      <button type="button" id="ingredient-btn_${formNum}" class="delete-btn" >
                        削除
                      </button>
                    </div>
                  </div>`;

    //insertAdjacentHTMLでノードを複製、挿入場所を16行目で定義したformList内に指定する。
    //引数のbeforeendで複製場所を末尾に指定,htmlで複製するものを指定する。
    //この一行での処理を要約すると、
    //『(html)を複製(insertAdjacentHTML)し、(formList)の末尾(beforeend)に挿入する』
    formList.insertAdjacentHTML('beforeend', html);

    //全ての削除ボタンを取得、deleteBtnsに定義する
    const deleteBtns = document.querySelectorAll('.delete-btn')

    //削除ボタンをforEachで繰り返し処理
    deleteBtns.forEach((btn) => {
      //deleteBtns要素(btn)をクリックすると53行目sample関数が実行される
      btn. addEventListener('click', sample)
})
  })
  //deleteBtnsのparentNode(親ノード)のさらにparentNode(親ノード)をremove(削除)する関数
  function sample() {
    this.parentNode.parentNode.remove()
  }

})

```


フォームを追加する考え方自体はシンプルだと思うのですが、思うように行かずこのコード実装で何日も溶かしてしまいました...

反省を次に生かします。

最後まで読んでいただき、ありがとうございました。
jQueryのJSON.parse()で「Uncaught SyntaxError: Unexpected token o in JSON at position 1」が発生したときの対処法

jQueryのJSON.parse()で「Uncaught SyntaxError: Unexpected token o in JSON at position 1」が発生したので、その時の対処法を記事に上げました。

[jQueryのJSON.parse()で「Uncaught SyntaxError: Unexpected token o in JSON at position 1」が発生したときの対処法](https://kuro-suke.com/734/)
Databricksノートブックのユニットテストをやってみる

こちらの[ノートブックのテスト](https://qiita.com/taka_yayoi/items/ef3b05c29104b12a16a6)で説明されている内容を実際に試してみました。

テスト対象の関数を宣言します。入力された文字列の順序を逆にする関数です。

```py:Python
def reverse(s):
    return s[::-1]
```

[unittest](https://docs.python.org/3/library/unittest.html)を用いたテスト用コードを作成します。

```py:Python
import unittest

class TestHelpers(unittest.TestCase):
    def test_reverse(self):
        self.assertEqual(reverse('abc'), 'cba')
```

ユニットテストを実行します。

```py:Python
r = unittest.main(argv=[''], verbosity=2, exit=False)
assert r.result.wasSuccessful(), 'Test failed; see logs above'
```

期待した通りに動作するのでテストにパスします。
![Screen Shot 2022-05-19 at 13.54.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/fa6f5d14-6c7e-25c4-c8aa-41600e097d2a.png)

テストに失敗するように故意に関数を変更します。

```py:Python
def reverse(s):
    #return s[::-1]
    return "test"
```

期待している出力ではないためテストに失敗します。
![Screen Shot 2022-05-19 at 13.56.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/8bb097fa-74aa-d427-9e9f-4e3c31ad43d4.png)

# ウィジェットの活用

[ウィジェット](https://qiita.com/taka_yayoi/items/4df1fd723bdab9a99b08)を追加することで、テスト時の動作と通常時の動作を切り替えることができます。

```py:Python
dbutils.widgets.dropdown("Mode", "Test", ["Test", "Normal"])
```

```py:Python
import unittest

class TestHelpers(unittest.TestCase):
    def test_reverse(self):
        self.assertEqual(reverse('abc'), 'cba')

if dbutils.widgets.get("Mode") == "Test":
  r = unittest.main(argv=[''], verbosity=2, exit=False)
  assert r.result.wasSuccessful(), 'Test failed; see logs above'
else:
  print(reverse("desrever"))
```
![Screen Shot 2022-05-19 at 14.00.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/b53b98c8-6fa7-b575-9d97-1307854720fb.png)

PyTestとの連携に関しては、こちらの記事を参照ください。

https://qiita.com/maroon-db/items/ccafbaaeecab4d532355

### Databricks 無料トライアル

[Databricks 無料トライアル](https://databricks.com/jp/try-databricks)
【Angular】AngularでBootstrapを使う際の初期設定方法

# 1. インストール
Boostrapをnpmでインストールします。本記事ではバージョン4.5.0を指定しています。
```terminal
$ npm install bootstrap@4.5.0
```
# 2. ファイル設定
プロジェクト直下のangular.jsonファイルを編集し、以下を追加して完了です。
```json: angular.json
// 元からある"src/styles.css"より前に追加する
"styles": [
     "./node_modules/bootstrap/dist/css/bootstrap.min.css",  // 追加
     "src/styles.css"
                        ],
```
【Heroku】Herokuに画像をアップロードできない / 画像表示できない問題を解決する

# はじめに
HerokuにDjangoアプリをデプロイした際、ローカルでは表示されていた画像が表示されなくなったり、アップロード機能でアップロードした画像も表示されなかったり、という問題に直面しました。
Herokuでは画像を表示したりアップロードしたりすることができない仕様のようです。
この問題を解決してくれる、Cloudinaryについてご紹介します。

# Cloudinaryの使い方
### 1. Herokuでの設定
Herokuにログインし、アプリの管理画面に移動します。
管理画面の「Overview」タブの画面上部にある「Configure Add-ons➡️」をクリックします。
![スクリーンショット-2022-03-30-13.31.50-1536x600.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1280658/4b956c37-fe35-707a-07fb-89405391de8a.png)
「Find more add ons」ボタンを押下します。
![スクリーンショット-2022-03-30-13.35.23-1024x292.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1280658/3cffab52-0e1b-d985-556c-f156b03181ab.png)
Heroku Add Onのサイトに飛びますので、画面右上の検索窓から「Cloudinary – Image and Video Management」と検索してインストールします。StarterのFreeプランで大丈夫です。
![スクリーンショット-2022-03-30-13.39.28-1024x409.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1280658/ab0d01f4-2bd1-f77d-9462-149b0240014e.png)
Herokuに支払い情報の登録をしていない場合、アドオンをインストールできないので、まだの方はそちらを済ませてからインストールしてください。

### 2. ライブラリをインストール
次に、必要なライブラリをインストールしていきます。
仮想環境に入っている状態でインストールするよう注意してください。
```terminal
$ pip install Pillow
$ pip install django-cloudinary-storage
# 動画がある場合はこっち
$ pip install django-cloudinary-storage
```

`requirements.txt`を更新します。
```terminal
$ pip freeze > requirements.txt
```

### 3. Djangoの設定
Djangoの`settings.py`を編集します。
##### 3.1 INSTALLED_APPSの追加
書く順番が違うと設定がうまくいかないので、下記をそのままコピペしてください。

```python: settings.py
#メディアファイルのみの場合
INSTALLED_APPS = [
    #...
    'django.contrib.staticfiles',
    'cloudinary_storage',
    'cloudinary',
    #...
]

#メディアファイル以外もある場合
INSTALLED_APPS = [
    #...
    'cloudinary_storage',
    'django.contrib.staticfiles',
    'cloudinary',
    #...
]
```
##### 3.2 SECRET KEYの追加
アプリ管理画面の「Overview」タブにある「Installed add-ons」から、Cloudianryのダッシュボードに移動します。
![スクリーンショット-2022-03-30-20.22.31-1536x541.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1280658/53b6b92b-323b-9597-d7a2-de85ef0b5420.png)

「Cloud Name」「API Key」「API Secret」をコピーして`settings.py`に以下のように追加します。

```python: settings.py
#setting.pyの最後に追加でOK
CLOUDINARY_STORAGE  = {
    'CLOUD_NAME':'your_cloud_name',
    'API_KEY':'your_CLOUDINARY_API_KEY',
    'API_SECRET':'your_CLOUDINARY_API_SECRET'
}
```
##### 3.3 画像ファイルのパス設定
```python: settings.py
DEFAULT_FILE_STORAGE = 'cloudinary_storage.storage.MediaCloudinaryStorage'
```

### 4. デプロイ
以上の設定が完了したらデプロイします。
画像が問題なく表示/アップロードできるようになっていることを確認してください。
```terminal
$ git push heroku master
```
python if文の条件の判定順

すこし気になることがあり、if条件判定順について確認してみた。（個人的メモ）

下のコードのように配列長より長い数値が入りうる変数で配列の要素をチェックする際に、if文を一気に書いた方がインデントが減るので確認してみた。(phpだと定義されている（と認識している）ので、個人的にはよく使っていた)

```python
import numpy as np
array_Test = np.repeat(True,10)
for i in range(0,15):
    if i < len(array_Test) and array_Test[i]==True:#配列の要素をチェックすることを強調
        print(i,"True")
    else:
        print(i,"False")
## 結果
# 0 True
# 1 True
# 2 True
# 3 True
# 4 True
# 5 True
# 6 True
# 7 True
# 8 True
# 9 True
# 10 False
# 11 False
# 12 False
# 13 False
# 14 False
```

これで、配列より長くないということでエラーは起こさない。
if文の条件の判定順はpythonでも左からとして使えそう。
【Rails】バリデーションに引っ掛かったカラムを取得する

# コード
```ruby
@user.errors.attribute_names
=> ["name", "email", "tel"]
```
`errors.attrbute_names`で引っ掛かったカラムの配列を取得できます。

# 詳細
今回はJSを使わずにバリデーションに引っ掛かった項目のinputの下に、
エラーメッセージを表示しなければいけなかったので、
どこのメッセージを表示するかの判定に引っ掛かったカラム名が欲しくて調べました。
```ruby:controller
def create
  @user = User.new(user_params)
  return redirect_to action: :new, errors: @user.errors.attribute_names if @user.valid?
  # 以下バリデーションが通った時の処理
end
```
これだと`errors`の内容がクエリに入ってしまうし、
入力済みの内容も保持したかったので、
実際には`flash`で渡しました。
```ruby:controller
def new
  @user = flash.present? ? User.new(flash[:user_params]) : User.new
  @errors = flash[:errors]
end

def create
  @user = User.new(user_params)
  if @user.valid?
    flash[:errors] = @user.errors.attribute_names
    flash[:user_params] = user_params
    return redirect_to action: :new
  end
  # 以下バリデーションが通った時の処理
end
```

# 追記
該当のカラムがエラーに含まれているかの判定だけなら、
`attribute_name`はなくても`errors.include?`でいけました。
今回はviewでのエラーメッセージを個々の場所に表示する為、
それぞれの該当箇所でカラムがエラーに含まれているかを知りたかったので
```slim:view
= @user.errors.include?(:name)
```
で大丈夫でした。

ということは、`redirecet_to`ではなく`render`でも大丈夫です。
```ruby:controller
def create
  @user = User.new(user_params)
  return render :new if @user.invalid?
end
```
```slim:view
// エラーの中にnameが含まれていなければis-hidden（非表示用に設定したクラス）で非表示
div class="error-message #{'is-hidden' unless @user.errors.include?(:name)}"
  | 名前を入力してください

```
アクション間での値の受け渡しなども必要なくなり、
すっきりしました！
Jetson AGX XavierにSSDを装着する

# 環境
- Jetson AGX Xavier
- Ubuntu 18.04
- jetpack 4.5

![icon_Jetson AGX Xavier.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1689380/3f5ea56c-be8d-56c7-cd3f-1bd6aca5c0d1.png)

# やりたい事
Jetson AGX Xavier にSSDを装着して、dockerが使用する領域をSSDに移したい

## 使ったSSD
![61QEkDvrFcL._AC_SX679_.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1689380/9bf31ab2-9c88-91b0-5e32-4109f36b4920.jpeg)

https://www.amazon.co.jp/gp/product/B082VZKK3L/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&th=1

# 取り付け
![ssd001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1689380/95a2889d-8a0b-1078-5f43-3b79f6b1af71.png)
裏側のネジ4か所を外す
![ssd003.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1689380/1f49bbb4-735c-2142-a675-228689a9a2bc.jpeg)



# インストール方法
- SSDの認識を確認
~~~
ls /dev/nvme0n1
~~~
- マウント
~~~
cd ~/
sudo mkfs.ext4 /dev/nvme0n1
sudo mkdir nvme
sudo mount /dev/nvme0n1 /home/jetson/nvme
~~~
-vi等で /etc/fstabにデバイスを追加する
~~~
/dev/nvme0n1 /home/jetson/nvme ext4 defaults 0 1
~~~
再起動する
~~~
/dev/nvme0n1 /home/jetson/nvme ext4 defaults 0 1
~~~
dockerを移動する
~~~
sudo docker info
sudo service docker stop
sudo mv /var/lib/docker /home/jetson/nvme/
sudo ln -s /home/jetson/nvme/docker /var/lib/
~~~
zramを無効にする
~~~
cd /etc/systemd
sudo mv nvzramconfig.sh nvzramconfig.sh.orig
~~~
swapを移動する
~~~
sudo fallocate -l 32G /home/jetson/nvme/swapfile
sudo chmod 600 /home/jetson/nvme/swapfile
sudo mkswap /home/jetson/nvme/swapfile
sudo swapon /home/jetson/nvme/swapfile
~~~
-vi等で /etc/fstabにswapを追加する
~~~
/home/jetson/nvme/swapfile swap swap defaults 0 0
~~~
Dockerを再起動
~~~
sudo service docker start
~~~

# 確認方法
~~~
docker inspect [コンテナID]
~~~

## 参考にした記事
[Docker](https://hub.docker.com/)
【DICOM】【入門】Pydicomの使い方

# はじめに
はじめてPydicomでDICOMファイルをどうにかしたい！という方向けです。
ここでは、Pydicomのインストール方法、DICOMファイルの情報表示・画像表示の方法までご紹介します。

# １. Pydicomをインストールする
```terminal
$ pip install pydicom
```

# ２.  DICOMのメタデータを表示する
まず、JIRAが公開している[DICOMサンプルデータ](https://www.jira-net.or.jp/dicom/dicom_data_01_02.html)をダウンロードしましょう。（どれか１つ選んでください。）
DICOMのメタデータには、患者情報、モダリティ情報など様々な情報が詰まっています。
メタデータ一覧は[こちら](https://www.liberworks.co.jp/know/know_dicomTag.html)から確認できます。

### ■ 全メタデータを表示する
```python: example.py
import pydicom

file = pydicom.dcmread('sample/sample.dcm')

print(file)
```

出力結果
```terminal
Dataset.file_meta -------------------------------
(0002, 0000) File Meta Information Group Length  UL: 174
(0002, 0001) File Meta Information Version       OB: b'\x00\x01'
(0002, 0002) Media Storage SOP Class UID         UI: Computed Radiography Image Storage
....
```

### ■ 特定のメタデータのみ表示する
特定のメタデータのみ表示するには、keywordで指定する方法・タグで指定する方法の２種類あります。

```python: example.py
import pydicom

file = pydicom.dcmread('sample/sample.dcm')

print(file.PatientName)           # keywordで指定
print(file.[(0x0010, 0x0010)])    # タグで指定
```

ちなみに、keywordの確認はこのようにできます。
```python: example.py
ds[0x00100010].keyword
# 'PatientName'とコンソール出力される
```
# ３. DICOM画像を表示する
DICOM画像の表示には、Matplotlib、GDCM、pylibjpegが必要なのでインストールしておきます。
```terminal
$ pip install matplotlib
$ pip install -U python-gdcm
$ pip install pylibjpeg
```

### ■ 画像を表示する
```python: example.py
import pydicom
import matplotlib.pyplot as plt

file = pydicom.dcmread('sample/sample.dcm')
img = file.pixel_array
plt.imshow(img)
plt.show()
```

### ■ ウィンドウ処理をして画像表示する
ウィンドウ処理とは、幅広い幅の画素値を持つ画像のある特定の濃度域のみを，表示系の濃度域［0（暗）～255（明）］に変換して表示する処理のことです。

つまり、画像を見やすくするために、コントラストや明るさを調整する処理のことを指します。

DICOMデータに、WindowCenterやWindowWidthなどのデータがある場合はこの処理を行なったほうが良いです。

```python: example.py
import pydicom
import matplotlib.pyplot as plt

file = pydicom.dcmread('filepath')
wc = file.WindowCenter
ww = file.WindowWidth
img = file.pixel_array

#ウィンドウ処理
window_max = wc + ww /2
window_min = wc - ww /2
img = 255*(img-window_min)/(window_max - window_min)
img[img > 255] = 255
img[img < 0] = 0
plt.show(img)
plt.show()
```
複数の条件式がある分岐のincludesを使った便利な書き方

複数の条件式がある場合のすっきりした書き方です。

例えば、以下の様な複数の条件式に当てはまる場合に処理をしたい場合、自分は`||`で繋げてベタ書いてしまいがちです。

```
if (
  key === 'exclude_completed' ||
  key === 'exclude_checked' ||
  key === 'exclude_assigned'
) {
  //処理をする
}
```

レビューで `arrayのincludesメソッド` を使う方がいいですよって指摘を受けて、いつも忘れてしまうので備忘録のため記事に残そうと思いました。

```
if (
  ['exclude_completed', 'exclude_checked', 'exclude_assigned'].includes(key)
) {
  //処理をする
}

//配列部分は外に切り出してさらにスッキリさせてもいいですね。
const array = ['exclude_completed', 'exclude_checked', 'exclude_assigned'];

if ( array.includes(key) ) {
  //処理をする
}
```

includesの詳しい解説は[こちら](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/includes)

`[配列].includes(配列の中で探したい値)`
配列に探したい値があるかチェックして、あればtrue、なければfalseが返る。

```
const array1 = [1, 2, 3];

console.log(array1.includes(2));
// expected output: true

console.log(array1.includes(4));
// expected output: false
```

と今回はincludesを使った便利なtipsでした。
【Django】DjangoアプリにBasic認証をかける

# はじめに
wsgi-basic-authを使ったDjangoアプリにBasic認証をかけるための方法をご紹介します。
シンプルで簡単なのでオススメです。

# １. ライブラリをインストールする
```terminal
$ pip install wsgi-basic-auth
```

# ２. .envファイルの設定
.envファイルに、Basic認証のIDとパスワードを追加します。
 ```.env
WSGI_AUTH_CREDENTIALS=ID:password
```

# ３. wsgi.pyの編集
wsgi.pyに以下を追加してください。（settings.pyと同じディレクトリにあります。）
```wsgi.py
from wsgi_basic_auth import BasicAuth

application = BasicAuth(application)
```

# 4. runserverして確認する
Basic認証が設定できているかを確認します。
```terminal
$ python manage.py runserver
```

ページをリロードすると、ログインのポップアップが画面上部に現れます。
![basic_authentification.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1280658/e73d58e6-8bd8-bad6-3364-8a37a5cbe941.png)

先ほど.envファイルに設定したIDとパスワードを入力し、ログインできたら成功です！
【Django】既存のmodelに外部キーを追加し、再度migrationする

# はじめに
既存のModelに外部キー(Foreign Key)を追加しmigrationしてDBに反映させる手順と、起きやすいエラー・その対処法についてご紹介します。

# 1. 既存のModelに外部キーを追加
Studentモデルに外部キーを追加し、test appのClassモデルと紐付けて、生徒をクラス単位で管理できるようにする想定で書いていきます。

```python: models.py
from django.db import models
from test.models import Class

class Student(models.Model):
     # Foreign Key追加
     class_id = models.ForeignKey(Class, models.DO_NOTHING)
```

# 2. Makemigrationsする
```terminal
$ python manage.py makemigrations
```

このとき、次のような質問が表示されることがあります。
```terminal
You are trying to add a non-nullable field 'class_id' to student without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
 1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
 2) Quit, and let me add a default in models.py
```

これは、「class_idフィールドには何らかの値を入れる必要があるよ〜」という意味です。
この場合、次の２つの対処方法があります。

１つ目は、フィールドにdefault=1を追加する方法です。追加したら、再度makemigrationsをします。

```python: models.py
class Student(models.Model):
     class_id = models.ForeignKey(Class, models.DO_NOTHING, default=1) 
```

２つ目は、上記の質問が表示された時に「1」を選択し、デフォルト値として「1」を入力する方法があります。

```terminal
Select an option: 1
Please enter the default value now, as valid Python
The datetime and django.utils.timezone modules are available, so you can do e.g. timezone.now
Type 'exit' to exit this prompt
>>> 1
Migrations for 'student':
  student\migrations\0010_student_class.py
    - Add field class_id to student
```

# ３. migrateする
migrateしてDBに変更を反映します。
```terminal
$ python manage.py migrate
```

ここで、紐付け先のテーブル（この記事ではClassテーブル）に先ほど設定した id=1 のデータが無いと、次のようなエラーが出ます。
```terminal
psycopg2.errors.ForeignKeyViolation: テーブル"student_student"への挿入、更新は外部キー制約"student_student_class_id_dbc8139b_fk_class_id"に違反しています
DETAIL:  テーブル"class"にキー(class_id)=(1)がありません
```

この場合は直接テーブルに、idカラムに1のデータを追加してあげるとmigrateが通ります。
rails5 progate 整理メモ　password_digest

# passwordカラムとpassword_digestカラム
passwordカラムを消して、password_digestを追加しても今までのコードを```書き換える必要はない```
```rb
[1] pry(main)> user = User.find_by(id: 1)
  User Load (0.1ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
=> #<User:0x0000557002159a88
 id: 1,
 name: "にんじゃわんこ",
 email: "wanko@prog-8.com",
 created_at: Tue, 18 Apr 2017 17:06:52 JST +09:00,
 updated_at: Tue, 18 Apr 2017 17:06:52 JST +09:00,
 image_name: "default_user.jpg",
 password_digest: nil>

[2] pry(main)> user.password = "ninjawanko"
=> "ninjawanko"

[3] pry(main)> user.password_digest
=> "$2a$10$u6vPLYIpgUDJUNduRr0RJe69OPDLhKlVeBs60uY/K4pU3ZeoCTxR2"

[4] pry(main)> user.save
   (0.1ms)  begin transaction
  User Exists (0.1ms)  SELECT  1 AS one FROM "users" WHERE "users"."email" = ? AND ("users"."id" != ?) LIMIT ?  [["email", "wanko@prog-8.com"], ["id", 1], ["LIMIT", 1]]
  SQL (0.2ms)  UPDATE "users" SET "updated_at" = ?, "password_digest" = ? WHERE "users"."id" = ?  [["updated_at", "2022-05-18 15:44:11.041719"], ["password_digest", "$2a$10$u6vPLYIpgUDJUNduRr0RJe69OPDLhKlVeBs60uY/K4pU3ZeoCTxR2"], ["id", 1]]
   (4.1ms)  commit transaction
=> true
```
## 思ったこと
```user.password_digest```でパスワードはハッシュ化されるのか。

# ハッシュ化されたパスワードを用いたログイン
フォームに入力されるメールアドレスを基にユーザーを取得する。
フォームに入力されたパスワードと取得したユーザーのパスワードが一致するか判断する。

## authenticateメソッド
has_secure_passwordメソッドを有効にすると、authenticateメソッドを使えるようになります。
### どのようなメソッドか？
authenticateメソッドは渡された引数をハッシュ化し、password_digestの値と一致するかどうかを判定する

## 実際やってみる。
```users_controller.rb
.
.
.
    @user = User.find_by(email: params[:email])
    # if文の条件を&&とauthenticateメソッドを用いて書き換えてください
    if @user && @user.authenticate(email: params[:email])
.
.
.
```
これでどうだろうか？
```rb
if @user && @user.authenticate(email: params[:email])
```
ここの部分が間違っているような気がする。
```rb
if @user && @user.authenticate(params[:password])
```
```email```の部分が間違っていた。
インスタンス変数の持つpassword属性とparams[:password]で入力されたパスワードとされる文字列が一致するか判断する。
IBM Cloud Object Storage(ICOS)で、Amazon S3互換ツールでのアクセス（HMAC認証）を有効にする

# 概要
この記事では、IBM Cloud Object Storage（ICOS）にAmazon S3互換のツール・ライブラリでアクセスするために必要なHMAC認証を有効にし、「アクセスキーID」、「シークレットアクセスキー」を生成・利用できるようにする手順を紹介します。

ICOSでは、専用のAPI（IBM Cloud Object Storage API)の他、Amazon S3互換のツール・ライブラリを使用することが可能です。ICOSのドキュメントでも、[AWS CLI](https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-aws-cli)、[s3fs](https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-s3fs)、[Minio Client](https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-minio)、[rclone](https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-rclone)といったツールに関する記載があります。

rcloneを使おうと思って上記ドキュメントを読んでいたところ、ICOSにアクセスするために「アクセスキーID」、「シークレットアクセスキー」が必要と書かれているものの、ICOSのサービス資格情報で該当する項目が存在せず、しばらく迷ったため、当記事を執筆しました。


# HMAC認証を有効にする手順
IBM CloudのWebコンソールで、ICOSの対象インスタンスのページにアクセスし、「サービス資格情報」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386149/03a7ab1f-33e9-0755-1336-38b633d4b8e0.png)


「新規資格情報」ボタンをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386149/9aba0980-6ae1-e829-cb99-b782337ef9c4.png)


名前、役割を設定します。加えて、「詳細オプション」を展開し、「HMAC資格情報を含める」を「オン」に変更します。これによりHMAC認証が有効となり、「アクセスキーID」、「シークレットアクセスキー」が生成されます。最後に「追加」ボタンをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386149/1440e3b3-2ad8-9c84-8d15-76b4b51500b1.png)


作成した資格情報を展開します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386149/88c17d1f-ba21-1f3e-09b9-339a820989a3.png)


すると、以下のようなJSON形式で資格情報が表示され、「cos_hmac_keys」という項目の配下に「access_key_id」（アクセスキーID）、「secret_access_key」（シークレットアクセスキー）が表示されます。

```javascript
{
  (中略)
  "cos_hmac_keys": {
     "access_key_id": ".......",
     "secret_access_key": "......"
  },
  (中略)
}
```

以上です。
MySQL 日付'0000-00-00'を許容する

## 前置き

先日、開発環境のデータベースに大量のレコードを取り込んだ際に下記のエラーが表示されました。

```pre
Invalid default value for 'date'
-- `日付`のデフォルト値が無効です
```

原因として、取り込んだレコードの`date`のカラムに`0000-00-00`が存在したため、上記のエラーが表示される状態でした。

MySQLのサーバー設定(SQLモード)ではバージョンにもよりますが、日付型ではデフォルト値が`0000-00-00`は許容されてない場合がございます。

なのでSQLモードを変更することで`0000-00-00`の日付を許容することが出来ます。

## SQLモードを変更する

```pre
# まずはSQLモードの設定を確認する
mysql> SELECT @@GLOBAL.sql_mode;
+-------------------------------------+
| @@GLOBAL.sql_mode                   |
+-------------------------------------+
| NO_ZERO_DATE,NO_ENGINE_SUBSTITUTION |
+-------------------------------------+
※NO_ZERO_DATEが日付に0が入っているレコードが許容しない設定


# NO_ZERO_DATEを無効にする
mysql> SET GLOBAL sql_mode = 'NO_ENGINE_SUBSTITUTION';
+------------------------+
| @@GLOBAL.sql_mode      |
+------------------------+
| NO_ENGINE_SUBSTITUTION |
+------------------------+
```

## まとめ
MySQLのSQLモードについては公式のページは[こちら](https://dev.mysql.com/doc/refman/5.6/ja/sql-mode.html)です。

日付に関してエラーが表示された場合は、SQLモードの設定を確認してみましょう。
Nginxでモジュール追加せずPath=/でないcookieにsecure属性を付与

# 問題
よく紹介されている
```
proxy_cookie_path / "/; secure";
```
のような記述でcookieをsecure化しようとしたらできなかったので調査

# 環境等
Nginx :1.20.0
OS : Ubuntu18.04

# 結論
[本家のproxy_cookie_pathの解説](https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_cookie_path)によると
```
proxy_cookie_path / "/; secure";
```
は、Path=/の場合に有効な技の模様  

```
proxy_cookie_path ~(.*) "$1; secure";
```
の記述により、設定Pathの値にかかわらずsecure化された。

そもそも
[Re: CookieのPath属性は本当に安全性に寄与しないのか](https://qiita.com/ockeghem/items/6590b2e18af1d062e780)
Path=/にすれば済む話なのだろうけれども
ROS コマンドチートシート 

ROSコマンドのチートシート
ROS1対象
随時アップデート予定
齟齬があればコメください
# MASTER
##### Master起動

```
roscore
```
# NODES
##### Node list取得
```
rosnode list
```
##### Node情報取得
```
rosnode info [node]
```

##### Node を強制終了
```
rosnode kill [node]
```

##### 任意のノードが動作しているかどうか確認(pingの送信)
```
rosnode ping [node]
```
# TOPIC通信
##### topicリスト表示
```
rostopic list
```
##### topic情報取得
```
rostopic info [topic]
```
##### 手動パブリッシュ
```
rostopic pub [-r freq][topic][msg_type][msg]
```
##### パブリッシュ情報の表示
```
rostopic echo [topic]
``` 
# ROS MESSAGES
##### 利用可能なメッセージリストの表示
```
rosmsg list
```
##### メッセージ構成の確認
```
rosmsg show [msg_type]
```
# SERVICE通信
##### 利用可能なサービスタイプの表示
```
rossrv list
```
##### サービスタイプの構成を表示
```
rossrv show [srv_type]
```
##### 現在可動しているサービスリストの表示
```
rosservice list
```
##### 現在可動しているサービスの詳細情報を表示
```
rosservice info [srv]
```

##### サービスの呼出
```
rosservice call [srv][srv_type][request]
```
# ファイルシステム
##### ROSパッケージへ移動
```
roscd [package]
```
##### ROSパッケージの中身を表示
```
rosls [package]
```
##### ノード単体の起動
```
rosrun [package][node name] 　# masterの起動が必要
```
##### ローンチファイルの起動
```
roslaunch [package][launch name]
```
# デバッグ
##### qrt_graphでノード間のつながりを表示
```
rosrun rqt_graph rqt_graph
```
##### TFツリーの表示
```
rosrun rqt_tf_tree rqt_tf_tree
```
##### TFフレーム情報の表示
```
rosrun tf tf_monitor
```
##### 指定した2つのTFの相対位置を表示
```
rosrun tf tf_echo [frame_src][frame_dst]
```
部屋のCO2濃度監視

# Motivation

- テレワーク等々で部屋に引きこもり活動していると、換気を忘れてしまうことが多々

- 部屋のCO2濃度が上がると、なんかいろいろとよくないらしい

https://www.mhlw.go.jp/content/10906000/000698849.pdf

※ ビル管理法の空気環境基準においては、換気量ではなく、二酸化炭素の濃度を 1000ppm 以下とすることを規定し、二酸化炭素濃度を定期的に測定することを求めている
※ 800ppm でオレンジ、1000ppm で赤に光る視覚指示を推奨


# 購入するもの

[カスタム (CUSTOM) CO2モニター CO2-mini](https://www.amazon.co.jp/dp/B00I3XJ9LM)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1017662/1dc8a82d-9078-59d3-5ee3-cf9a3febd428.png)

## 製品サイト
https://www.co2meter.com/products/co2mini-co2-indoor-air-quality-monitor

## アプリ(Windows)
https://www.zyaura.com/support-detail/software-nodatalogger/

# Installation

## ① CO2モニターをPCに刺し、Windowsアプリを起動

グラフ出てくる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1017662/d2352de2-e3e8-8858-4387-1eddf67ca99d.png)


## ② ログ出力先の確認

アプリが`Windowsアプリの配置先\<年>\<月>\<日>.CSV`にログを出していることを確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1017662/29054203-d8db-0677-72d9-7340603dab96.png)


## ③ ログ確認・アラート通知処理の作成

②のログを定期的に確認する処理を作成。
例：WSLのcronにshellを登録して、30分おきに監視。1000ppmで適当なWEBHOOKに通知


### monitorCO2.sh

```bash
#!/bin/bash

# ②のログ出力先を指定
DIR_ROOT="/mnt/c/Users/ittooo66/PerfLogs/ZyAura_USB_HUB_PC_software_NoDatalog"
# PPM取得処理
PPM=`tail -n 1 $DIR_ROOT/$(date '+%Y/%m/%d').CSV | cut -d , -f 2`
# 通知閾値
THRESHOLD=1000
# 通知先Webhook
TARGET_WEBHOOK="https://discord.com/api/webhooks/HOGEHOGE/FUGAFUGA-PIYOPIYO"
# 通知メッセージ
message="HIGH CO2 DENSITY : $PPM ppm"

# CO2濃度が閾値以上の時、WEBHOOK通知(Discordだとこんな感じ)
if [ $PPM -gt $THRESHOLD ] ; then
        curl -s -X POST -H 'Content-Type: application/json' -d '{"content": '\""$message"\"'}' $TARGET_WEBHOOK
fi
```

### crontab -l
```cron
# CO2監視
*/30 * * * * /mnt/c/Users/ittooo66/PerfLogs/monitorCO2.sh
```

# 参考

WSLがcrontabデフォルトで起動してくれないため、以下有識者を参照

https://qiita.com/yuinyan/items/4e23d9bd90f93988a88c

WSLインストールは以下有識者を参照

https://qiita.com/matarillo/items/61a9ead4bfe2868a0b86

CO2モニターは複数バージョン(暗号化有verと無ver?)あるらしく、Verによってはアプリ変えないとダメみたい。以下有識者を参照

https://donadona.hatenablog.jp/entry/2020/10/19/023049
REST ClientでファイルアップロードのAPIを投げる

## 送信側

REST Clientで例としてtext, png, csv, wavの4つのファイルを送信する

```test.http
POST https://api.example.com/user/upload
Content-Type: multipart/form-data; boundary=boundary

--boundary
Content-Disposition: form-data; name="text"; filename="sample.txt"
Content-Type: text/plain

text contents
--boundary
Content-Disposition: form-data; name="image"; filename="sample.png"
Content-Type: image/png

< ./sample.png
--boundary
Content-Disposition: form-data; name="csv"; filename="sample.csv"
Content-Type: text/csv

< ./sample.csv
--boundary
Content-Disposition: form-data; name="wav"; filename="sample.wav"
Content-Type: audio/wav

< ./sample.wav
--boundary--
```

ポイント
- リクエストのContent-Typeを`multipart/form-data`にする
- boundary(境界線)の名前は任意で決められる
- 各ファイルごとに--(境界線名)で区切る
- ファイルの終了は--(境界線名)--
- 各ファイルのnameは受け取る時の配列キーになる
- 各ファイルのContent-TypeはアップロードしたいMIMEタイプを指定する
- 各ヘッダとデータの間は一行空ける
- `<`は入力ストリームでデータへのファイルパスを指定する(テキストの場合はデータをベタ書きでもOK)

## 受け取り側(Laravelの場合)

コントローラ
```
class UpdateController extends DefaultController
{
    public function uploadSample(Request $request): JsonResponse
        $files = $request->file();

        $text_file = $files['text'];
        $image_file = $files['image'];
        $csv_file = $files['csv'];
        $wav_file = $files['wav'];
}
```

ルーティング
```
Route::post('/user/upload', [UpdateController::class, 'uploadSample']);
```

## 参考
https://github.com/Huachao/vscode-restclient#request-body

https://stackoverflow.com/questions/61473990/how-to-post-an-image-with-form-data-in-rest-client-for-vscode

https://zenn.dev/optimisuke/articles/9d4ab7d9c57b3e

https://qiita.com/kunihiros/items/e11daacfd62d85d83c06
ヘッドレスCMSってなんですの？

最近耳にするようになりました、ヘッドレスCMS。

ヘッドレス…頭…を無くす…？
一体…何をレスしているの…？

そう疑問に思っている方も多いハズ。わたしもその一人。
ということで今回はヘッドレスCMSについて理解を深めていきたいと思います。

## ヘッドレスCMSの特徴とは

ヘッドレスCMSとはずばり、バックエンドだけを提供するCMSのこと。
つまりフロントエンドいらず。ヘッドレス。ということです。
フロントエンドいらずと書きましたが、正確には自由に選択できるというのが、
一番の特徴です。

## 登場・普及の背景

どのデバイスからでもユーザーには最適な体験を提供するべき。ということから、
ワンソースマルチデバイスへのニーズの高まりが背景としてあります。

また、たくさんのサービスやデータなどが、すでにWeb上に公開されており、
これらのAPIをもっと活用しようという考え方が広がっているため普及し始めていると考えれます。

## 何がすごいの？

### メリット1：ワンソースマルチデバイス

ヘッドレスCMSは吐き出されるAPIを使って、コンテンツを配信します。
APIを利用するのでワンソースで様々なフロントエンドデバイスに対応できます。

### メリット2：分業作業できる

従来のCMS（WordPressでイメージしてもらうと分かりやすいかも？）では、
フロントエンドの作業後にCMS化という流れが一般的かと思いますが、
ヘッドレスCMSの場合、分業できるのでフロントエンドとバックエンドが同時に構築できます。

## なんだか難しそう…

### デメリット1：構成が複雑

自由度が高いということは、選定しなければならない事項も多くなります。
最適なスキーマも考えなければなりませんが、そのためのCMSです。

### デメリット2：必要技術スキルの高さ
マルチデバイスなので当たり前ですが、Web以外にもアプリやサイネージなど、
要件にあわせて各デバイスに詳しいエンジニアが必要になります。

## わたしたちへの影響は…？

正直すぐにお仕事レベルでの影響はないと考えています。
CMSの選択肢が増えただけなので、まだまだ動的CMSの需要が多いと思うからです。
ただ、それぞれの特徴は理解できるように勉強をしていきましょう。
ザッとまとめました。

### 静的CMSの特徴

- セキュア。障害復旧が早い
- ローコスト
- 配信手順にいくつかステップができる

### 動的CMSの特徴

- リアルタイム更新が可能
- シンプルな更新フロー
- 実装期間、費用がかかる

### ヘッドレスCMSの特徴

- コンテンツの編集、管理、出力に特化
- 比較的短い実装期間
- お客さんへのラーニングコストがかかりそう

## 結び
ヘッドレスCMSとは…
API経由でコンテンツを提供するCMSのこと。
簡単に言うと、API生成ツールである。

### 参考にさせていただいた記事
https://codezine.jp/article/detail/15054
https://blog.microcms.io/what-is-headlesscms/
【IBM Security Verify 】管理者画面からのテーマ管理について

# はじめに
以前ご紹介したテーマの管理が、管理者画面から行えるようになりました。

テーマファイルのカスタマイズ例は、[IBM Security Verify API の テーマ機能で画面カスタマイズする～実践編～](https://qiita.com/fitz/items/a9c25490d33cf689ea51)を参照ください。

# 1.テーマのアップロード
ユーザーエクスペリエンス-ブランド設定からテーマ管理が行えます。
![theme-gui (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678692/5508e5c6-90f7-888c-1575-df26d57668f4.png)

ダウンロードしたテーマをカスタマイズしてみます。

```page_style.css
/* css for customization
   Add styling here to override classes from <tenant>/usc/css/stateless.css 
*/
body, body.tile-background {
    background: #c3f1fa;
    background-repeat: no-repeat;
    background-position: 15% 50%;
    background-size: 30%;
    background-image: url(https://1.cms.s81c.com/sites/default/files/2018-12/pw_sec_saasss_600x340-72r.jpg.jpeg);
```

ファイルをアップロードします。
![theme-gui (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678692/5492de12-8659-59db-7224-1c50303f1d5a.png)

テーマの登録が完了しました。
![theme-gui (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678692/781d358d-898d-efe8-821f-be6d1bb6252d.png)

アプリケーションにテーマを割り当てて動作確認します。
![theme-gui (4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678692/14dddbdc-fd4d-184f-ed82-7e3ec90c93f2.png)


# 2.テンプレート用のAPIについて
テーマ機能がリリースされる前のテンプレート機能で用いるAPIが非推奨となっています。
詳細はマニュアル ["非推奨の API"](https://www.ibm.com/docs/ja/security-verify?topic=policies-deprecated-apis)を参照ください。

|![theme-gui (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678692/df2e7bc4-e779-9efe-3997-c5e4727826b0.png)
|:--|

# 最後に
REST APIを利用せずにテーマのカスタマイズができるようになったので便利になりました！！
Railsチュートリアル第3章で学んだこと

第3章ではこれから作っていくsampleアプリの簡易的なページを作りました。

簡易的なページを作っていく中で簡単なテストも書いていきました

今回はコントローラーのテストを書きました。

test "should get home" do
  get static_pages_home_url
  assert_response :success
end

これの意味はHomeページのテスト。GETリクエストをhomeアクションに対して発行（=送信）せよ。そうすれば、リクエストに対するレスポンスは［成功］になるはずという意味らしい。

このテストを先に書いてREDになるのであとはルーティング→コントローラー→ビューページを
してGREENにしてこのテストOKみたいな感じらしい

これを各ページやっていきました。

あとは各ページの重複したコードををリファクタリングすることも学びました。

Railsのいいとこはリファクタリングしやすいところなのかもしれない。
[備忘録]anacondaを介さないインストールの仕方

ここでは、anacondaを使わずにgeopandasやgdalなどコマンドプロンプトでインストールが難しいライブラリをインストールし、pythonの実行環境を構築する方法をまとめます。

まず、anacondaはプログラムが保存されるパスに日本語があると正しくセットアップされません。また、パスの日本語を変更するのはかなり面倒なので、anacondaを使わずにgeopandasなど曲者のライブラリのインストール方法を記述します。

〇環境
→Windows 11

〇対象
→パスに日本語が入っている人
→anacondaの起動が面倒な人
→Python IDLEを使って、自動化したい人など

①Pythonのインストール
まだ、インストールしていなければpythonのインストールをしてください。https://www.python.org/downloads/

geopandasなどマニアックなライブラリを使用する際のおすすめは、最新バージョンよりも2つほど古いものを使用することです。ライブラリの更新は最新バージョンが発表されてから行われるので、使用できない可能性が大いにあるからです。2022年5月現在はpython 3.10.4までがリリースされているので、**3.8.9**や**3.8.10**が良いと思われます。

②geopandasなどのwheelファイルを入手
次にgeopandasのもととなるwheelファイルをダウンロードします。こちらのサイトから、目的のライブラリを探してください。(ctlr + Fでページ内の特定の言葉を探すことができます。)
https://www.lfd.uci.edu/~gohlke/pythonlibs/
ライブラリについても、最新版ではなく、最新版から2つほど古いものであれば問題なく動くと思います。

gdalのバージョン一覧(cp39など)についている64や32などは使用しているPCのビットを表しています。ご自身のPCのビットを確認して選択してください。
例
**GDAL‑3.4.3‑cp39‑cp39‑win_amd64.whl**
**GDAL‑3.4.3‑cp39‑cp39‑win32.whl**

geopandasに関して、fiona、shapely、pyproj、rtreeなどが不可欠なライブラリなのでこちらも入手してください。

③コマンドプロンプトでの操作
②の作業でライブラリのwheelを入手したら、コマンドプロンプトを開きます。Windowsボタンを開き、検索項目に「コマンドプロンプト」と入力すれば現れます。ここに以下のコードを記述します。
wheelを保存したファイルを仮にDownloadsとすると
```
cd Downloads
```

とコマンドプロンプトに入力してください。これにより、処理をする場所がDownloadsに移ります。
次に以下の3つのコードのうち、どれか処理が成功するものを試してください。
```
pip install GDAL‑3.4.3‑cp39‑cp39‑win_amd64.whl
py -m pip install GDAL‑3.4.3‑cp39‑cp39‑win_amd64.whl
python -m pip install GDAL‑3.4.3‑cp39‑cp39‑win_amd64.whl
```
ほかのライブラリでも、上記のような手順で作業を行うことでgdalやgeopandasなどの曲者をインストールできます。

海外のサイトにもやり方が多く乗っているので、ここでの方法ができなければ探してやってみてください。
GAS(Google Apps Script) メニュー追加

# 便利なGAS
スプレッドシートなどで使える　Google Apps Script(gas)
使いこなすと自動化とか作業効率を上げたりと色々便利そうなので
初歩的な関数のお話し。
と言ってもまんまJavaScriptです。

## メニューに実行したい機能(関数)を追加
スプレッドシートにあるメニュー(ファイル、表示、編集....)に独自のメニューを追加する方法
```
function onOpen() {
  var myMenu=[
    {name: "関数の実行", functionName: "myFunction"},
  ];
  SpreadsheetApp.getActiveSpreadsheet().addMenu("独自メニュー",myMenu);
}
```
onOpenが最初に実行されるもの
PHPで言うconstructやGoで言うinitみたいなものだと思います。
.addMenuでメニューに追加できる。
3行目のfunctionNameで作成した関数を登録し、名前をつけるだけ！

## 独自関数
javascriptに無いgasの独自関数
```
Logger.log("test");//console.logの様なもの

//シートの取得
const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
const sheet1 = spreadsheet.getSheetByName('シートの名前');

//セルの取得
.getRange(x, x, x, x)//セルの取得(範囲)
.getValue()//セルの取得(値)
.getValues()

var range = sheet.getRange(1, 1, 2, 2);
Logger.log(range.getValue());

の様に範囲を指定して値を取得する様に使用する
```

この辺りはgasの独自の関数でよく使う
Kali Linux2022.1 でハッキングラボをつくってみる9 無線LANへのハッキング2 WEPをハッキング基礎

# はじめに
無線LANの暗号化方式WEPのパスワード解析を行っていきます。
「ハッキング・ラボのつくりかた」p.533-542に沿った記事と成っています。

:::note alert
注意事項
記事で紹介されている行為を他人や団体、インフラなどの許可を得ずに行った場合、犯罪となる可能性が有ります。
あくまでも、記事の内容は情報セキュリティの学習です。読者様の所有・管理の機器、システムでのみ実行してください。
また、読者さまのシステムにトラブルが起きたとしても、私は責任を負いかねます。
:::
# WEPとIVの簡易説明
WEPの暗号化には、IVという補助情報から構成される暗号化キーとWEPキー（パスワード）を組み合わせて使用している。

同書p.535より
>IVはパケットごとに異なるので、各パケットがユニークな鍵ストリームを持ちます。ストリーム暗号は共通鍵の一種であるため、送信者と受信者の両者がIVを知らなければなりません。そのため、IVは平文の形でパケットに格納されています。しかし、IVは24ビットと短いため、大量のパケットを収集すると、同じIVを持つ２つ以上のパケットが揃います。よって、大量のIVを集めることで、WEPの暗号化鍵、そしてWEPキーを特定できます。

なお、24ビットつまり2の２４乗なら、16777216以上のパケットを集めないと、同じIVが重複しないはずだが、IVに使われている乱数は完全なものでなく、それより少ないパケット数でも重複する。これから行う解析は、IVを大量に集めて行う。

# ハッキング（パスワード解析）
- WEPを使用しているAPを探す

`iw dev`あるいは`iwconfig　wlan0`でmonitorモードに成っていることを確認する。
WEPのAPを探す。事前に、"test"というWEPのアクセスポイントを用意した。
airodump-ngで実行。同書ではairodumpとなっているが、おそらく誤記。
```
sudo airodump-ng wlan0
```

- 解析に必要なキャプチャを収集

```
mkdir cracking_wep_test
cd cracking_wep_test
sudo airodump-ng --channel <target_channel> --bssid <target_bssid> --write cracking_wep wlan0 
```
![VirtualBox_kali-linux-2022.1-wep_crack01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535888/bff4bb67-c7d5-3523-4840-ac8077684a92.png)

--writeには、生成されるファイルの接頭語を指定する。
生成されるファイルは５つある。何回もキャプチャを繰り返すと、一つのフォルダに大量の生成されたファイルがあふれるので、プロジェクトごとにフォルダ分け（フォルダ名：接頭語+日時といったフォルダを作成しておいてから、そのフォルダ内で上記のコマンドを実行する）すると、分別されてわかりやすくなると思う。


- aircrack-ngによる解析
airodump-ngは実行したまま、新規に別の端末を立ち上げて、次のコマンドを実行する。
```
aircrack-ng cracking_wep_test-01.cap
```
解析がはじまる。パケット数が足りないと解析には失敗する。失敗したら、"Attack will be restarted every 5000 captured ivs."とあるとおり、5000ivs貯まるごとに再度解析を実行する。
下の画像では、20000ivsでは解析できなかった。。
![VirtualBox_kali-linux-2022.1-wep_crack02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535888/23ab6d9d-443f-0648-968e-da431f24c671.png)

airodump-ngを終了させてから、再度aircrack-ngを実行しても良い。
そうしたら、解析に成功した。
もちろん、"55555"という非常に単純なパスワードだからだ。
![VirtualBox_kali-linux-2022.1-wep_crack03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535888/207ce8e0-f60b-ae92-fcfa-2971a541fe2d.png)

# おわりに
次は、キー（パスワード）の一部が判明しているときのWEPのパスワード解析をやります。
参考にしたもの
「ハッキング・ラボのつくりかた」
SwiftUI + MVVM + Firebase を利用して Twitter に似たアプリを開発した話

## SwiftUI + MVVM + Firebase を利用して Twitter に似たアプリを開発する
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199441/d505435e-2c47-d960-57d9-f56219bf8659.png" width="200">

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199441/95fbd2a9-1da0-edc3-e0e9-93c15f2195ba.png" width="200">

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199441/0d8e25e2-e387-ff5a-9e9e-125439d7c752.png" width="200">

## 参考にした YouTube
https://www.youtube.com/watch?v=3pIXMwvJLZs

### この動画で学べること
- SwiftUI を利用した画面の開発方法
- Firebase を利用したログイン機能・ユーザ登録機能の実装方法
- Firebase を利用したデータの永続化

### 感想
- 無料で Firebase を利用したアプリの開発手法を学べるのは良い
- Apple が公開している SwiftUI Tutorial を学び終えた人には、最適の教材だと感じた
- クロージャの使い所が腑に落ちた

## GitHub リポジトリ
※ Firebase と連携するために必要なファイル `GoogleService-Info` は `.gitignore` で管理対象外にしている

https://github.com/tanakadaichi1989/TwitterSwiftUIYoutube

## 開発環境
|項目|内容|
|---|---|
|PC| MacBook Air(M1,2020） メモリ：16GB ストレージ：1TB |
|言語|Swift|
|IDE|Xcode|
git cloneからflutter pub get

## 概要
Flutter初心者です。環境構築で詰まったのでメモ書き。
FlutterのプロジェクトをGitHubからcloneしてきた際、環境構築の手順としては
まずfirebaseと連携するために
```
flutterfire configure
```
pubspec.yamlファイルに記述されているパッケージをダウンロード・インストールするため
```
flutter pub get
```
```
flutter run
```
でエラー
```
Error: CocoaPods's specs repository is too out-of-date to satisfy dependencies.
To update the CocoaPods specs, run:
  pod repo update



Error running pod install
Error launching application on iPhone 13 Pro Max.
```

## 対処
iosフォルダにあるPodfileとPodfile.lockを削除する。

プロジェクトフォルダにて下記コマンドを実行
```
flutter clean
```

iosフォルダで
```
cd ios
pod repo update
```

最後プロジェクトフォルダにて
```
flutter run
```

以上でiosは動いた。
GoogleAppScriptでGoogleDriveフォルダ内のファイル一覧を取得

# やりたいこと

GoogleDriveフォルダ内にあるスプレッドシートのURLと最終更新日を
スプレッドシートに出力したい

# やってみた

```JavaScript
function getFileList() {
  
  var sheet = SpreadsheetApp.openById('スプレッドシートIDを記入').getSheetByName('シート名');
  var Allfiles = DriveApp.getFolderById('フォルダIDを記入').getFiles();

  let row = 1; //開始行
  const reg = /^.*シート$/;  //末尾が｢シート｣で終わるものを抜き出したかったため正規表現で記載
  
  while (Allfiles.hasNext()) {
    
    let file = Allfiles.next();
    
    let name = file.getName();
    let lasttime = file.getLastUpdated()
    let url = file.getUrl();
 
    if (name.match(reg)) { //条件に合致するファイル名のみ書き込み
      sheet.getRange(row, 2).setValue(name);
      sheet.getRange(row, 3).setValue(lasttime);      
      sheet.getRange(row, 4).setValue(url);      
      row++;
    }
  }  
}

```

`hasnext()`は、まだ取り出していないファイルが存在するかどうかを判定、戻り値はtrue/false
`next()`は、まだ取り出していないファイルを取り出す、戻り値はFileオブジェクト

今回は、ファイル名、最終更新時間、URLのみを取得しましたが、
ファイル関数は他にも取得できる情報があります。
https://developers.google.com/apps-script/reference/drive/drive-app

本当は、最終更新時間と共に、最終更新ユーザも取得したかったのですが、
今のところ方法は見つかっていません…



# 参考
https://excel-ubara.com/apps_script1/GAS037.html
を参考にしました。
knockout.jsでコンポーネントの同期非同期Loading のコントロール

# knockout.jsでコンポーネントの同期非同期Loading のコントロール
knockout.jsでコンポーネントを作成する時にそのコンポーネントの呼び出しを同期的に行うのかそれとも非同期で行うのかということを指定できるオプションがある。

```js
ko.components.register('my-component', {
    viewModel: { ... anything ... },
    template: { ... anything ... },
    synchronous: true // ←こいつのこと
});
```

何も書かなければデフォルトは false になる。

### ではなぜ通常コンポーネント読み込みは非同期になるのか。
常に非同期のポリシーは他の言語でも確立されていて慣習的に行われている。
開発者が典型的な非同期プロセスが時に同期的に完了したりまたその逆の場合について考慮しないことによって潜在的なバグの可能性を軽減する。

つまりそのように書くことで全体としてバグになる可能性を下げているという認識。

### なぜ同期のローディングを有効にする場合があるのか
特定のコンポーネントのコピーの長いリストを注入しようとして(例えばforeachバインディングの内部で）、そしてコンポーネントの定義がそれまでの使用によって既にメモリ内に存在している場合、全ての新しいコピーは同期的に注入され、単一のDOMの再構築のみを引き起こすので特にモバイルでのパフォーマンスのために適している.

非同期でコンポーネントのロードが行われると要素それぞれに対してDOMの再構築が行われ、メモリーを圧迫したり不要な読み込みが行われたりするためパフォーマンスが下がる恐れがある。
そのような時は意図的に同期的な読み込みに設定する。
jQueyでページ判断する

```javascript
$(window).on("load", function () {
  // URLの取得
  var url = location.href;

  // パスの取得
  var path = location.pathname;

  if (path == "/hoge.html") {
    //hogeページの時
  }

  if (path == "/foo/") {
    
  }
  if (path == "/foo/sample.html") {
    
  }
  console.log(url);
  console.log(path);
});
```
QiitaにおけるFontAwesomeを使用したHTMLインジェクションのテスト

<i class="fa fa-spin fa-3x fa-fw" aria-hidden="true"> 
<i class="fa fa-refresh fa-spin fa-3x fa-fw" aria-hidden="true"></i>
<i class="fa fa-refresh fa-spin fa-3x fa-fw" aria-hidden="true"></i>
<i class="fa fa-refresh fa-spin fa-3x fa-fw" aria-hidden="true"></i>
<i class="fa fa-refresh fa-spin fa-3x fa-fw" aria-hidden="true"></i>
<i class="fa fa-refresh fa-spin fa-3x fa-fw" aria-hidden="true"></i>
</i>
React hook 何？？

# React hooksって何？
最初にreactを勉強するときに一番疑問になるものと思います。
React hooksは16.8のreactバージョンの新し特徴です。
実はReact hooksはただ色々な機能集まって一つになるものです。
この機能あるからClassコンポーネント使わずに特徴を使われる。
たとえば。。。
以前stateがfunctionコンポーネントに使うことができないですがreact Hooksのおかげでそれをできます。
それまだ一つだけですまだたくさんあります。
![1_44aJtUU8arzFDn_7QjzMyw.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2543632/2fc6a556-bad4-5f14-f0ab-c9680df0184a.png)
この記事でreact hooksにどんな機能があるかは一緒勉強したいと思います、それは
- useState
- useEffect
- use ref
- useMemo
- useCallback


今後の記事に一つ一つ説明したいと思います。
Salesforce単体テストメソッドの実行

テストを実行するには、次のいずれかを使用します。

◆Salesforce ユーザインターフェース
　https://developer.salesforce.com/docs/atlas.ja-jp.apexcode.meta/apexcode/apex_testing_unit_tests_running.htm#UISectionTitle
◆Visual Studio Code 向け Salesforce 拡張機能
　https://forcedotcom.github.io/salesforcedx-vscode/
　https://qiita.com/shunkosa/items/98f107dd532166e8d4a6
◆Lightning プラットフォーム開発者コンソール
　https://developer.salesforce.com/docs/atlas.ja-jp.apexcode.meta/apexcode/apex_testing_unit_tests_running.htm#DevConsoleTestsRunningSectionTitle
◆API
　https://developer.salesforce.com/docs/atlas.ja-jp.apexcode.meta/apexcode/apex_testing_unit_tests_running.htm#APISectionTitle
初めてのブックマークレット

## 概要
前々からブックマークレットの自作には興味があったので、今回は重い腰を上げて簡単なプログラムを書いてみました。（都内SE1年目）

## 使用方法
1.ブラウザーでブックマークを追加し、URL 欄に下記コードをペースト（名前は任意）
2.任意のページを開き、保存したブックマークを選択

成功すると alert表示と共にフォルダーパスの文字列をクリップボードにコピーします

```javascript
javascript:
let text = location.href;
navigator.clipboard.writeText(text);
alert("Copied !\n--\n" + text);
```

## ブックマークレットの第一歩
ブックマークレットはJavascriptで書かれたプログラムです。
なのでその先頭に```javascript:```を明記しなければ機能しません。（明記していなければそもそもブックマークに登録できない）

#### HelloWorld
```javascript
javascript:alert("Hello World");
```

## 総括
本当に簡単なブックマークレットですが、駆け出しの極第一歩といった所でしょうか。現状だとWindowsでしか機能しないみたいです。（要勉強）次回の記事ではブックマークレットに関してもう少し深堀してみます。
MAMPでstartボタンが押せなくなった

2022/05/19

m1 Macで MAMPを使用していたところ、前日まで普通に動作していたのに、朝起動したら突然動かなくなった。

StopボタンがStartボタンに切り替わらず、ポートを調べても未使用のまま。
DBのバックアップをとって再インストールしようと思ったらWebStartボタンも押せなくて詰みました。

そのとき、MAMP PROで適当にstartボタンを押していたら(stopも押したかも)、なぜか無料のMAMPのstartボタンが復旧して押せるようになりました。

なんかの起動フラグが無料版とPRO版で共有になっていて無料版でバグってフラグ切り替えできていなかったのがリセットされたのかもしれません。

なお、PRO版に課金とかはしておらず、こうなってダメ元で触っただけです。
[Webを支える技術] 第4部 ハイパーメディアフォーマット　個人的重要部分まとめ

# HTMLとはなにか
HTMLはHyper Markup Languageの略。もともとあったSGMLという構造化文章のためのマークアップ言語をベースに開発したHTML4．01、より仕様をシンプルにしたXML、HTMLをSGMLベースからXMLベースにXHTML1.0などがある。
## HTML5
現在策定中、急速に普及しているHTML5ではSGML構文とXML構文が用意されている。特にXMLに限定した場合にはXHTML5と呼ばれる。また、HTML5ではHTML系の構文とXHTMLの構文の混在が許されている。

## XMLの基礎知識
### 属性
要素は複数の属性を持つことができる。開始タグは属性を複数持つことができるが、同じ名前の属性は一つだけしか記述できない。
### 実体参照と文字参照
&lt;　"　などの文字は実体参照を用いて表現することができる。< の場合は
```
&lt;
```
で表現可能。
実体参照に以外にも、文字参照を用いて表現することもできる。
文字参照はunicodeの番号で文字を指定する。例えばコピーライト記号(©)は
```
&#169;
```
で表現可能。

## XML宣言
XMLを利用する際にはファイルの先頭にXML宣言を書く。バージョンは1.0や1.1があるが、1.0を用いるのが主流。

## 名前空間
複数のXMLフォーマットを用いるときは名前空間を利用することができる。要素と属性に対して名前空間をつけることができ、特にデフォルトで適用されるもの、接頭辞をつけなくても適用されるものをローカル属性と呼び、接頭辞をつけて表現するものをグローバル属性と呼ぶ。

## HTMLの構成要素
ヘッダでメタデータを記述。タイトルや他のリソースへのリンクなど。
ボディで表示したい文字やボタンなどの記述をしていく。

## リンク関係
a属性とlink属性はそれぞれrel属性を持てる。rel属性にリンク元のリソースとリンク先のリソースがどのような関係にあるのかを記述する。

# microformats
## RDFとmicroformats
プログラムで処理可能な情報の意味を記述する仕様として1990年代後半にRDFが登場した。けれども
- 記述が複雑になりがち
- 統一的な記述がしづらい
- 対象データとは独立したメタデータが必要

等の問題点があり普及しなかった。この問題点を解消したのがmicroformats。
microformatsはHTML文書そのものにメタデータを埋め込む技術。

# Atom
## Atomとはなにか
RSSの仕様が乱立している中、拡張性のあるフィードの標準フォーマット作成がAtomの目的の一つ。
RSSでは主にフィードで使われていたが、atoｍは検索エンジンや写真管理など多様な目的とapiとして活用することができる。
## メンバリソース
atomにおける最小リソース単位のこと。例えばブログでいえば1つ1つの記事がメンバリソース。
メンバリソースは __エントリリソース__ , __メディアリソース__ に分かれる。XMLで表現することが可能なのがエントリリソース、テキストなどで表現できない画像や動画などの情報はメディアリソースと呼ばれる。
## コレクションリソース
複数のメンバリソースを含むリソースのこと。コレクションリソースは階層化できないため、コレクションリソースにコレクションリソースを含むことはできない。

## Atom Publishing Protocol
Atom pubを用いるとブラウザ以外のwebクライアントからブログを投稿したりシステム同士を連携することができる。CRUDを実装するためのプロトコル。RESTに則っている。
# Json
## Jsonとはなにか
javascript notation objectの略。javascriptの記法で記述することができる。
## データ型
組み込みではオブジェクト、配列、文字列、数値、ブーリアン、nullがデータ型として用意されている。
## JSONP
JSONP (JSON with padding) は、クロスサイト環境で他のオリジンから JSON データを取得するために考案された仕組み。あるオリジンから、他のオリジンで生成された JSON データを読み出そうとしても、Same-Origin Policyにより、取得したjsonデータへのアクセスは拒否される。
```
<script src="...">
```
 で他のオリジンのJavaScriptを読み込めることを利用し、用意したコールバック関数のスクリプトを呼び出すことで、他オリジンが生成した JSON データを読み出すことを可能にする。
VSCode ESLintとPrettierを保存時に自動整形する設定メモ

VSCode ESLintとPrettierを保存時に自動整形する設定メモです。


```json:.vscode/settings.json 
{
  "editor.formatOnSave": true,
  "prettier.enable": true,
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  }
}
```
Create Your Pages


[Trailhead関係　個別の課題別 に戻る](https://qiita.com/Keiji_otsubo/items/56eb7a90bb72138ece1f)

[Build Your Career in the Salesforce Ecosystem> Build your Personal Portfolio on Salesforce> Add Pages to Your Site](https://qiita.com/Keiji_otsubo/items/57dc9839e0e5286d2079)


# 最初の部分で既に先に進めないという質問、ホームが違う。

[I want to take the next step "Create Your Pages". But, I cannot find Page Properties and down arrow on the home tab.](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000HDMJVSA5)
Google Colaboratory で Julia を使う

Google Colaboratory で Julia を使う

以下をクリックすると，ブラウザが Google Colaboratory のノートブックを開く。

[Julia_Colab_Notebook_Template.ipynb - Colaboratory - Google](https://colab.research.google.com/github/ageron/julia_notebooks/blob/master/Julia_Colab_Notebook_Template.ipynb)

基本的には，上のページに書かれているようにすればよいが，ダメ押しの注意点 3 つ

- JULIA_VERSION="1.7.1" は自分のほしいバージョンに変更する
- JULIA_PACKAGES="IJulia BenchmarkTools Plots" から BenchmarkTools Plots を外す
- ブラウザのページをリロードする
Google Colaboratory で R を使う

Google Colaboratory で R を使う

以下の内容の雛形ファイル.ipynb を作り，

```Json
{
  "cells": [],
  "metadata": {
    "colab": {
      "collapsed_sections": [],
      "name": "Title",
      "toc_visible": true,
      "provenance": []
    },
    "kernelspec": {
      "display_name": "R",
      "name": "ir"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
```

Google Colaboratory の「ファイル --> ノートブックをアップロード」で作っておいた雛形ファイルを指定して読み込む。

アレヤコレヤが終わって，たとえば

```R
t.test(1:6, 3:10)
```

と入力して，以下の結果が表示されれば OK.

```
	Welch Two Sample t-test

data:  1:6 and 3:10
t = -2.5981, df = 11.979, p-value = 0.02334
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -5.5163747 -0.4836253
sample estimates:
mean of x mean of y 
      3.5       6.5 
```