OmniAICreator/Qiita-1.07M huggingface dataset:
エックスサーバーにssh接続する方法（ターミナル利用）

sshで接続してみてということを言われたのでその時の忘備録です。

尚今回はsshの設定はすでにされていたのでリンクだけご紹介してます。
ご理解ください。

ちなみにやることはこちらの通り。

    1.エックスサーバーでsshの設定
    2.秘密鍵の設置
    3.秘密鍵のファイル名の変更
    4.sshディレクトリと秘密鍵のパーミッションを変更
    5.ログイン

##1.エックスサーバーでsshの設定

こちらを参照してください。
https://www.xserver.ne.jp/manual/man_server_ssh.php

##2.秘密鍵の設置

ダウンロードしたsecret.keyを以下のコマンドで移動します

    #ファイルの移動
    $ mv ~/Downloads/secret.key ~/.ssh/

.sshディレクトリがないという方は下記コマンドで作成してください。

    #.sshディレクトリの作成
    $ mkdir ~/.ssh
　　　　　
ちなみにこの.sshディレクトリがどこにあるかというとこちらにあります。
![スクリーンショット 2022-01-28 23.39.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494487/930a8b19-612e-ab09-21d6-ccef62fa6bcf.png)

色が少し薄いのは隠しファイルと呼ばれるものだからです。ちなみに隠しファイルの表示させたいならFinderで「command」＋「shift」＋「.」同時押しで見れるようになります。

##3.秘密鍵のファイル名の変更

秘密鍵の名前を変更します。この時通常だとid_rsaとするのですが、
その他の秘密鍵もある場合は任意の名前を。今回はid_xserver_rsaで設定します。

    #まずは.sshディレクトリに移動
    $cd ~/.ssh/
　　
     
    #名前の変更
    $mv secret.key id_xserver_rsa

##4.sshディレクトリと秘密鍵のパーミッションを変更

    $ chmod 700 ~/.ssh
　

    $ chmod 600 ~/.ssh/id_xserver_rsa

このコマンドと数字はなんなんだって方がほとんどだと思うので、気になる方はこちらの記事も読んでみると少し理解できるかもです。
http://itdoc.hitachi.co.jp/manuals/3021/3021313320/JPAS0348.HTM

##5.ログイン

    $ ssh -i id_xserver_rsa -p 10022 サーバーID.xsrv.jp -l mysqlユーザーネーム

その後に最初にログインするときに何か聞かれるのでyesと入力してください。

mysqlを設定していないという方はこちらでもOKかもです。

    $ ssh -l サーバーID -i 秘密鍵ファイル名(今回はid_xserver_rsa) サーバーID.xsrv.jp -p 10022

ちなみにこちらは僕はダメでしたw
SeleniumでSlackに自動でログインする

ブラウザの操作を自動化するライブラリ「[**Selenium**](https://www.selenium.dev/documentation/)」を使って[**Slack**](https://slack.com/intl/ja-jp/)のログインを自動化するプログラムの一例です。

```py:auto-login.py
# （Selenium 4.1.0 で動作確認済み）
# webdriver は使用しているChromeのバージョンに合わせて以下のページから取得する。
# https://chromedriver.chromium.org/downloads

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.chrome import service as fs
import time

# parameters
slackurl    = 'sample.slack.com'        # Slack URL
mailaddress = 'sample@gmail.com'        # 登録済みメールアドレス
mypassword  = 'abrakadabra'             # ログインパスワード
waittime    = 10.0                      # (sec.) 通信速度 & PCスペックに応じて調整
logintime   = 100.0                     # (sec.) 適宜調整
driverpath  = 'C:/Users/[user名]/Downloads/chromedriver_win32/chromedriver.exe' # webdriver が置かれている path を指定
url         = 'https://app.slack.com/client/XXXYYYZZZ/AAABBBCCC'                # 目的地となる Slack WorkSpace のURL


try:
    # Webページにアクセス
    chrome_service = fs.Service(executable_path=driverpath)
    driver = webdriver.Chrome(service=chrome_service)
    driver.maximize_window()  #全画面表示にする (オプション)
    driver.get(url)
    driver.implicitly_wait(waittime)  # 遷移待ち

    # Slack WorkSpace の選択
    ch_element = driver.find_element(By.ID, 'domain')
    ch_element.send_keys(slackurl)
    ch_element.send_keys(Keys.ENTER)
    driver.implicitly_wait(waittime)  # 遷移待ち

    # 自動ログイン
    mail_element = driver.find_element(By.ID, 'email')
    mail_element.send_keys(mailaddress)
    password_element = driver.find_element(By.ID, 'password')
    password_element.send_keys(mypassword)
    password_element.send_keys(Keys.ENTER)
    driver.implicitly_wait(waittime)  # 遷移待ち

    # 自動ログインに成功
    print('Successfully logged in:')
    url     = driver.current_url    # URLを取得する (オプション)
    title   = driver.title          # タイトルを取得する (オプション)
    print(url, title)

    # 任意時間ログイン状態を維持
    time.sleep(logintime)

finally:
    # セッションの終了
    driver.quit()
    print("Done.")
```

>セキュリティの問題が生じない範囲で適宜改変してご利用下さい。
NSObjectについてちょっと深堀りしてみた

## 概要

普段何気なく使用しているNSObjectについて、改めて調べまとめました。

なお、筆者はSwift、Objective-C及びアプリ開発初心者のため、内容の正確性をしっかり保証することができません。もし、不正確な表現などございましたら、コメントいただけると幸いです。

## NSObjectとは

Cocoaフレームワークにおける数少ないルートクラスで、NSObjectを継承することで、動的型付けであるObj-Cランタイムの柔軟性を教授することができます。

### その柔軟性とは？

**メソッド呼び出しをランタイム時に動的に行えます。**

より詳細には、NSObjectを継承するサブクラスのメソッド呼び出し時には `objc_msgSend()`によるインターセプションを介するため、ランタイム時にメソッド呼び出し先を柔軟に変えること（通称Swizzling）などが可能になります。

たとえば以下の一行目のようなコードはコンパイラによって、 `objc_msgSend`の呼び出しに置き換えられます。

```objectivec
[obj message];
// 👇こうなる
objc_msgSend(obj, @selector(message));
```

ただし、こうした柔軟性はObj-Cが動的型付け言語故行えることであり、Swiftランタイムではコンパイル時に静的に型が決まる必要があるため、こういった柔軟で動的な挙動を得るためにはNSObject、すなわちObj-Cランタイムの力を借りる必要が出てきます。

例えば、我々がよく使うIBOutletなどのKeyValueコーディングはまさにこの機能を使用していることになります。（UIViewはNSObjectですしおすし）SwiftはObj-Cランタイムという巨人の方に乗っかっていると言えますね。

## NSObjectを継承しないクラスについて

では、NSObjectを継承していないクラスの場合はどうなんでしょうか？

結論、NSObjectと継承しないSwift上のクラスは、 メソッド呼び出し時に前述の `objc_msgSend()`を介しません。

ただし、NSObjectを継承していなくても、そのクラスはObj-Cクラスであり、NSObjectとの互換性を持った一部の関数の実装のみ行っているようです。また、Obj-Cランタイムメタデータもランタイム側から提供されないようです。

## 動的なメソッド呼び出しに関連する@objcとdynamicについて

### `@objc`はSwift上の実装をObj-Cから参照できるようにする

Obj-C上からSwiftで書かれたクラスのメソッドやプロパティにアクセスするためには `@objc`アトリビュートが必要になります。#selectorで呼び出す場合、必ず呼び出し先に `@objc`を付けることになりますが、これもObj-Cランタイムの動的なメソッド呼び出しを活用するためです。

### `dynamic`が付いた関数やプロパティの呼び出しには、Dynamic dispatchを使用することをコンパイラに知らせる

> Apply this modifier to any member of a class that can be represented by Objective-C. When you mark a member declaration with the `dynamic` modifier, access to that member is always dynamically dispatched using the Objective-C runtime. Access to that member is never inlined or devirtualized by the compiler.
> 

> Because declarations marked with the `dynamic` modifier are dispatched using the Objective-C runtime, they must be marked with the `objc` attribute.
> 

> [https://docs.swift.org/swift-book/ReferenceManual/Declarations.html#//apple_ref/swift/grammar/declaration-modifiers](https://docs.swift.org/swift-book/ReferenceManual/Declarations.html#//apple_ref/swift/grammar/declaration-modifiers)
> 

`dynamic`キーワードを付けることで、その関数やプロパティへのアクセスは、必ずDinamyc Dispatchを介することになります。そのため、パフォーマンスの観点で悪影響があることから、使用時にはそういった観点を持ったほうが良いかも知れません。

## 参考リンク

[What is NSObject? When do Swift developers need to use NSObject?](https://www.quora.com/What-is-NSObject-When-do-Swift-developers-need-to-use-NSObject#VqdUw)

[To the depth of @objc and dynamic in Swift](https://varun04tomar.medium.com/to-the-depth-of-objc-and-dynamic-in-swift-b5472800b85d)

[What Does the Dynamic Keyword Mean in Swift 3](https://cocoacasts.com/what-does-the-dynamic-keyword-mean-in-swift-3/)

[mikeash.com: Friday Q&A 2012-11-16: Let's Build objc_msgSend](https://www.mikeash.com/pyblog/friday-qa-2012-11-16-lets-build-objc_msgsend.html)
ダイエットの進捗報告を爆速でするショートカットを作ってみた(LINE,Twitter)

#:pushpin:はじめに
こんにちは。初投稿です。
フォトウェディングに向けたダイエットのため、パーソナルトレーニングに通ってます:lifter_tone1:
トレーニング初回、トレーナーから「朝と夜の体重・体脂肪率、1日の水分摂取量をLINEで報告してください」と指示されました。
体重計とヘルスケアアプリは連携済みなので、ヘルスケアアプリからポチポチ入力していたものの...

**やっぱりめんどくさい！**

と、いうことで「ショートカット」という純正アプリを使って自動化させました。
また、ちょっと楽しくなってきたので、twitterに体重・体脂肪率を投稿するバージョンも作ってみました。
ダイエットアカウントで体重報告をされてる方がよくいるので需要があるといいなあと思ってます:relaxed:

#:pushpin:そもそもショートカットって何？
![514B0274-C0BF-45BF-87BA-15F57E593AEB.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518596/5f0db16b-ee5d-d3a7-3704-fdd1dc4160a4.jpeg)

>ショートカットとは
>
>ショートカットは、Appでの1つまたは複数の作業を素早く完了するための機能です。「ショートカット」Appでは、複数の手順を組み合わせた独自のショートカットを作成できます。例えば、海の波情報を取り込み、ビーチまでの所要時間をチェックし、サーフミュージックのプレイリストを再生する、という「サーフタイム」ショートカットを構築できます。

https://support.apple.com/ja-jp/guide/shortcuts/welcome/ios


#:pushpin:朝と夜の体重・体脂肪率、1日の水分摂取量をLINEで報告
ヘルスケアアプリからショートカット起動当日の最古の体重・体脂肪率を朝、最新の体重・体脂肪率を夜としてデータを取得します・1日の摂取水分量を自分で入力し、パーソナルトレーナーとのLINEに投稿します。

https://www.icloud.com/shortcuts/03793122e9f04e379d795af0889b105a

【注意】LINEの送信先をダミーにしているので、適切な送信先にしてください。
![スクリーンショット 2022-01-28 23.35.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518596/8fc4a570-24d7-4a7f-3a14-f3df5499f53f.png)

こんな感じで動きます。
![76F8C461-9FD5-4DE9-AE68-4C3898513169.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518596/444a4db2-f862-2518-1ecf-c2aa3d794b21.png)![1F7762D0-1FDA-47A2-B10E-C5B5D0665424.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518596/99994493-b2c0-7494-cc7b-346616d9c047.jpeg)


#:pushpin:twitterに体重・体脂肪率を投稿
ヘルスケアアプリからショートカット起動当日の体重・体脂肪率を取得してツイートします。

https://www.icloud.com/shortcuts/27e7d15e115b43ecb06ce5fa31318e95

こんな感じで動きます。
![trim.2614B384-CA2A-4485-90DF-24C6BE855414.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518596/b2e36222-19dc-d43f-3477-7ef32018f8a0.gif)
Ubuntu Server 20.04.3 LTS 構築#4 セキュリティ設定3

<前回の内容>
clamavのウイルス定義ファイルの更新

実施日:2022/01/18～
<<今回の内容>>
ローカルバージョンの更新

前回はウイルス定義ファイルの更新エラーの対応をしました。
今回はローカルバージョンの更新作業を行います。

調べてみると、レポジトリの更新が必要。
下記のコマンドを実行するとバージョンアップが出来るとのこと。
早速、コマンドを実行します。

[コマンド]
sudo apt-get install python-software-properties
sudo add-apt-repository ppa:ubuntu-clamav /ppa
python～は関係性がないと思いつつも、試しに実行。
cannot add ppa:'ppa:~ubuntu-clamav /clamav/ppa'
ERROR:'~ubuntu-clamav 'user or team doesnot exist
やはり、実行が出来ないとエラーメッセージが表示されました。

レポジトリの設定ファイルが
/etc/apt/sourcies.list
又は
/etc/apt/sources.list.d/
に存在するそうなので、実際に確認
/etc/apt/sources.list.d/には何もなかったです。

更に調べてみると、レポジトリ自体の更新が必要とのことです。

[コマンド]
apt update
実行すると、アップグレード可能なものが9個ありました。

[コマンド]
apt list --upgradable
アップグレード出来るものを確認
･clamav-base
･clamav-daemon
･clamav-freshclam
･clamdscan
･libclamav
･linux-generic
･linux-headers-generic
･linux-image-generic

[コマンド]
apt upgrade
※-yを付けて実行し忘れたので、途中で[Y]を入力する羽目に。
freshclamのバージョンアップについて確認画面が表示され、
アップグレードを選択。再起動を実施しました。

[コマンド]
freshclam
ローカルバージョンが更新されたと表示され、確認出来ました。

本日は此処迄です。

次回#5　セキュリティ設定4
Rspec、FactoryBotで使う【sequence】って何？

##sequence(シーケンス)とは

```tasks.rb
FactoryBot.define do
  factory :task do
    sequence(:title, "title_1") #ここ
    content { "content" }
    status { :todo }
    deadline { 1.week.from_now }
    association :user
  end
end
```
``:task do``内の１行目にある
**``sequence(:title, "title_1")``**この``sequence``にあたる。

```コンソール.
'title_1'.next
=> "title_2"

'title_7'.next
=> "title_8"
```
``title_1``に``.next``をつけてコンソールで確認してみると、次の数字が含んだ``title_2``となった。

**sequence**の単語の意味は「順番・順序」となるので、``.next``で次の数字が表示される意味となったのかも。

>
**.next**はruby自体の機能で、**末尾の数値を増やす機能がある**

ただしこれを日本語でやろうとすると、

```コンソール.
'タスク_1'.next
=> "タスク_2"

'タスク_9'.next
=> "タスグ_0"
```

``9``の次が``0``になっていたり、``タスグ``となっていたりして正しく表示されていない。
**英字 + 記号 + 数字**が発動条件のよう。

他にも

```コンソール.
sequence(:reserve_on, Date.today)
#今日、明日、明後日、という感じで順に生成される

sequence(:color, %w[red green blue].cycle)
#cycleを使うと、red green blue がこの順番で繰り返される
```

``cycle``は本番環境では上手くいかないので注意。

```user.rb
sequence(:email) { |n| "user_#{n}@example.com" }

user1 = FactoryBot.create(:user)
# 結果→　example1@example.com

user2 = FactoryBot.create(:user)
# 結果→　example2@example.com
```
このファクトリが呼び出されるたびに、``n``の部分に数字が一つずつ増えて入るため、一意性が保たれる。

##参考記事
[FactoryBot (旧FactoryGirl) の sequence と .next](https://qiita.com/kuboon/items/8897aca59dc968ca6d3c)
【solidity】mappingの使い方解説

##mappingとは
mappingとは、配列のようにkeyとvalueを紐づけて保管し、後から参照できるようにする型です。
参考までにドキュメントの引用です。
>マッピング型は mapping(_KeyType => _ValueType) という構文で宣言します。_KeyType はどの基本型でも入ります。つまりどのビルトインの型に加え、bytes と string が使えます。ユーザー定義、もしくはコントラクト型、enum、マッピング、構造体、bytes と string を除いた配列は使用できません。_ValueType はマッピングを含めて、どの型でもとることができます。
引用元：https://solidity-jp.readthedocs.io/ja/latest/types.html#mapping-types

##mappingの特徴および配列との違い
上記のドキュメントに書いてある点がほとんどですが、配列と違う点を挙げると以下の通り
①keyは入力した値のハッシュ値で保存される（厳密にはkeyは保存されてない?）
②valueからkeyを検索できない
③valueはnullを返すことはなく、無い場合は初期値を返す（これはsolidity自体の特徴？）
　（例：uintは"0",addressは"0x0",stringは"",boolは"false"
④マッピングは長さを持たない
⑤storageにデータが保存される

keyを入力してvalueを参照する点に関しては配列と同様だが、そもそも長さを持ってなかったりと違う点も多いようですね

##コード
以下、ドキュメントのコードにコメントを追加しました

    pragma solidity ^0.8.0;

    contract MappingExample {
        //addressがkey、uintがvalue、balansesは格納する変数
        mapping(address => uint) public balances;

        //set関数により、key=msg.senderとvalue=newBalanceを紐づけてbalancesに格納する
        function set(uint newBalance) public {
            balances[msg.sender] = newBalance;
        }
        //readValue関数により、keyにmsg.senderを入力しvalueを参照する
        function readValue() public view returns (uint) {
            return balances[msg.sender];
        }
    }

##おわり
以上です。間違い等あればコメントにてご指摘ください。
ありがとうございます。
LinqPad: Free 版で nuget 使いたい！って時

# 背景
LinqPad Free 版使ってても、外部 Library 使いたい時ちょっと面倒ですよね。
そんな時どうするか？ってのをメモ

こんな感じで、NuGet 使う為には、Developer 以上のライセンスが必要
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/58704281-25b3-be00-4471-a3c4d846e4c6.png)

# 環境
LinqPad 7.1.5 （6 でも同様だった記憶）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/b5ef1f00-2777-7635-ad8d-aab8bcebad3a.png)
Visual Studio 2019 Version 16.11.9

# 概要
非常に単純で、以下するだけ。
是非、会社では経費を使って購入しましょう :laughing:  日本の販売代理店もあればもっと売れるような・・あるのかな？

1. Visual Studio で適当なプロジェクトを作成し、必要なライブラリを VS の NuGet でインストール
1. LinqPad で VS でインストールした DLL を参照

## Visual Studio で適当なプロジェクトを作成し、必要なライブラリを VS の NuGet でインストール
VS NuGet でライブラリインストール
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/10d845a7-0e28-e2f1-a139-7b0d7c6c197b.png)

## LinqPad で VS でインストールした DLL を参照
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/e53b69b5-6edf-9203-c8d8-6c76f52a64eb.png)

Visual Studio での Default の Package 置き場はたぶん以下。

> %userprofile%\.nuget\packages

あとは使うだけ。

# 利用例
実際に CsvHelper を使って例。
簡単なデータ確認とかには便利かな、なんて。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/1617b401-8ecf-3751-5f2e-ed81916802f6.png)

# あとがき
いつの間にか、Version が 7 に上がってたのであげてみた。
DateOnly/TimeOnly まで対応してるのが地味に嬉しい。
WSL2 に Docker Engine をインストール(Docker Desktop なし)

[前回](https://qiita.com/blueskyarea/items/020d9eb02955ef0ea717)、WSL2で Ubuntu20.04LTS環境の構築を行いました。
Docker を使いたいため、WSL2 に Docker Engineをインストールした際の手順を残します。
Docker Desktop なしでインストールしていますが、WSL2公式においては Docker Desktop for Windows を利用することを推奨しています。

#### 目次
1. Install docker on wsl
2. Install docker-compose on wsl

#### 1. Install docker on wsl

##### 1-1 パッケージ一覧を更新
```
$ sudo apt update
Get:1 http://security.ubuntu.com/ubuntu focal-security InRelease [114 kB]
Get:2 http://archive.ubuntu.com/ubuntu focal InRelease [265 kB]
（略）
Reading state information... Done
251 packages can be upgraded. Run 'apt list --upgradable' to see them.
```

##### 1-2 パッケージのインストール
```
$ sudo apt install -y \
>     ca-certificates \
>     curl \
>     gnupg \
>     lsb-release
Reading package lists... Done
Building dependency tree
（略）
Running hooks in /etc/ca-certificates/update.d...
done.
```
ca-certificates ： Ubuntu ベースの Docker コンテナで SSL 接続をするため

##### 1-3 Dockerのofficial_GPG_key追加
```
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
```

##### 1-4 Dockerリポジトリ情報の登録
```
$ echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
```

##### 1-5 パッケージ一覧を更新
```:リポジトリ情報を更新したので念のため
$ sudo apt update
Get:1 https://download.docker.com/linux/ubuntu focal InRelease [57.7 kB]
Get:2 https://download.docker.com/linux/ubuntu focal/stable amd64 Packages [13.5 kB]
(略)
Fetched 2818 kB in 4s (759 kB/s)
Reading package lists... Done
```

##### 1-6 Docker Engine のインストール
```
$ sudo apt install -y docker-ce docker-ce-cli containerd.io
Reading package lists... Done
Building dependency tree
(略)
Processing triggers for man-db (2.9.1-1) ...
Processing triggers for systemd (245.4-4ubuntu3) ...
```

##### 1-7 Docker Group にユーザを所属させる
```:sudo無しでdockerコマンド実行させるため
$ sudo usermod -aG docker $USER
```

##### 1-8 Docker service 起動設定
```:WSL起動時にDockerService起動させるため(パスワード要求される)
cat <<EOF >> ~/.bashrc
# For Docker service start
sudo /etc/init.d/docker start
EOF
```
WSL2ではsystemdがPID1で起動しない。
WSL2起動時にsystemd で docker daemonを起動させる方法があるのかもしれませんが、分かりません。

##### 1-9 動作確認
```
$ docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
(略)
Hello from Docker!
This message shows that your installation appears to be working correctly.
(略)
```

#### 2. Install docker-compose on wsl

##### 2-1 docker-compose インストール
```
$ sudo curl -L "https://github.com/docker/compose/releases/download/1.24.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
```

##### 2-2 実行権限付与
```
$ sudo chmod +x /usr/local/bin/docker-compose
```

##### 2-3 シンボリックリンク設定
```:docker-composeで実行できるように
$ sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
```

##### 2-4 バージョン確認
```
$ docker-compose --version
docker-compose version 1.24.1, build 4667896b
```
Ubuntu Server 20.04.3 LTS 構築#3 セキュリティ設定2

<前回の内容>
clamavのインストール迄

実施日:2022/01/18～
<<今回の内容>>
clamavのウイルス定義ファイルの更新

前回はclamavを導入し、実際に無害なウイルスを導入し動作するところまで確認しました。

その際に定義ファイル更新でエラーが発生していたので、その解消をしました。

[エラー]
ERROR:/var/log/clamav/freshclam.log is locked by another process
ERROR:problem with internal logger(UpdateLogFile = /var/log/clamav/freshclam.log) 
ERROR:initsiza :libfreshclam init failed
ERROR:Initialize error!

手動で定義ファイルを更新すると、発生するようで解消方法として、一旦ログファイルを削除すると解消するそうです。
[コマンド]
rm /var/log/clamav/freshclam.log
touch /var/log/clamav/freshclam.log
chown clamav:clamav | /var/log/clamav/freshclam.log

再度、手動で更新するとエラーメッセージは表示されませんでした。
但し、更新画面中に現行バージョン:0.103.2　推奨バージョン:0.103.5と表示がありましたので、
定義ファイルを更新してもバージョン自体は更新されないようです。

本日はここまでにします。
ローカルバージョンアップは次回になります。

次回#4　セキュリティ設定3
NotionでID列を追加する

# tl;dr

`id()` 関数を使おう。

# はじめに：一意に識別できる列が欲しい

notion.soを使ったタスク管理をやりはじめました。

よくあるやつです。

![スクリーンショット 2022-01-27 13.24.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82681/169ed173-1190-09f7-a14a-a17a30b4c74d.png)

日常のタスク管理ならこれで十分なのですが、チケット管理システムとして使おうとすると、GitHubのプルリクとNotion上のタスクをひも付けたいのでID列が欲しいところです。

# 解決： `id()` 関数を使う

調べてみるとそのものずばり `id()` というページ（エントリー）ごとに一意な文字列を返す関数があることに気づきました。
追加してみましょう。

1. ページ上部の `プロパティ` を選択する
1. ポップアップ下部の `プロパティを追加` を選択し、プロパティを追加する
    1. プロパティ名：なんでもOK。今回は `ID(full)` にしました
    1. プロパティの種類： `関数`
1. ポップアップを閉じ、テーブルビューの最右端に追加された `ID(full)` の、ヘッダー以外の行を選択する
1. 図のように `数式を入力してください` の欄に `id()` と入力し、 `完了` ボタンを押下する

![スクリーンショット 2022-01-27 13.30.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82681/dbc8766e-1f38-bc5a-beef-09f04eb17ef4.png)

この操作によって、以下の図のとおり各行に対してID列が追加されました。

![スクリーンショット 2022-01-28 22.14.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82681/f5420488-36e4-e395-c033-29527ba1cce7.png)

ID列は全Notionページを通じて一意な文字列となっています（ので、後半部は白抜きマスクしています）。
`https://notion.so/＜ID列＞` と指定するとそのページへのリンクとなります。

# おまけ：言いやすいように縮める

さて、ID(full)列ですが、どうにも長ったらしいです。
GitHubのプルリク連携の用途では長かろうが短かろうがよいのですが、人間同士が打ち合わせする際
、人間が口に出して言うのにこうも長い文字列は好ましくありません。

冒頭の4文字ぐらいに縮めてしまいましょう。

前出の方法で新たなプロパティを追加してください。
ただしプロパティ名は `ID(short)`　、 `数式を入力してください` の欄には下図のように `slice(id(), 0, 4)` としてください。

![スクリーンショット 2022-01-28 22.16.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82681/1df5d5b6-a653-16e7-579f-3fcd7de349b6.png)

冒頭の4文字だけになりました。

# おわりに

めでたしめでたし
外部からDatabricks上のMLflowを使用する

MLOpsを効果的に実施するためのフレームワークである[MLFlow](https://mlflow.org/)はあらゆる環境での機械学習を一元的に管理することが可能です。DatabricksではこのMLflowをマネージドサービスとして提供しており、Databricks上での機械学習はもちろん、Databricks環境以外での機械学習についても連携することが可能です。


この記事では、
Databricksの外部環境(ローカルPC上など)からワークスペース内のMLflowを使用する方法について説明します。

以下のステップで実行していきます。

1. DatabricksワークスペースにMLflowのexperimentを作成する
1. Databricks上のMLflowにアクセスするための情報確認
1. 外部環境からMLflowのコードを実行する(runを実行する)
1. Databricks上のMLflowページからrunの結果を確認する

## 1. DatabricksワークスペースにMLflowのexperimentを作成する

Databricksのワークスペース内に今回使用するMLflowのExperimentを作成します。
"Home"または"Workspace"アイコンからNotebookディレクトリを開き、右クリックメニューから`Create > MLflow Experiment`で作成できます。

![mlflowexperiment](https://raw.githubusercontent.com/ktmrmshk/dbdoc/main/docs/mlflowremote/mlflowexperiment.png)

作成されたMLflow ExperimentのページからExperiment IDを確認します。
この例では以下の通りです。

* `Experiment ID: 275506464251973`

![eperimentid](https://raw.githubusercontent.com/ktmrmshk/dbdoc/main/docs/mlflowremote/eperimentid.png)

## 2. Databricks上のMLflowにアクセスするための情報確認

外部からDatabricks上のMLflowを参照するには以下の情報が必要になります。

* ワークスペースのURL
  - ワークスペースURLはブラウザのアドレスバーから確認できます。
  - (例: `https://ktmxxxxxxxxxxxxxxxx422.cloud.databricks.com/`)
* User Access Token
  - ワークスペースの右上にある"User Settings"からトークンを発行してください。

## 3. 外部環境からMLflowのコードを実行する(runを実行する)

外部環境(ローカルPCなど)からMLflowを実行します。
ここでは、Linux環境で実行する例を見ていきます。
MLflowをインストールし、アクセスするための環境変数を設定します。

```bash
$ pip install mlflow

### インストールされたversion確認
$ mlflow --version
mlflow, version 1.17.0

### 環境変数を設定
export MLFLOW_TRACKING_URI='databricks' <= 固定
export DATABRICKS_HOST='https://ktmxxxxxxxxxxxxxxxx422.cloud.databricks.com/'
export DATABRICKS_TOKEN='dapi632xxxxxxxxxxxxxxxxxxxxxxx' <=発行したToken
```

簡単なMLflowコードを実行します。

サンプル:`mlflow_ctr.py` 

```python
import mlflow

with mlflow.start_run(run_name='foobar123', experiment_id='275506464251973') as run:
    mlflow.set_tag('team_label', 'teamA123')
```

実行します。

```bash
$ python mlflow_ctr.py
```



## 4. Databricks上のMLflowページからrunの結果を確認する

再びDatabricks上のMLflow Experimentページを参照します。
上記で実行したrunの情報が登録されていることが確認できます。

![run](https://raw.githubusercontent.com/ktmrmshk/dbdoc/main/docs/mlflowremote/run.png)


## 参考

* [MLflow Documentation](https://www.mlflow.org/docs/latest/index.html)
* [MLflow ガイド](https://docs.microsoft.com/ja-jp/azure/databricks/applications/mlflow/)
SearchViewのフォーカスの当て方、外し方

#はじめに

SearchViewは少々クセの強いUIですが、検索窓の実装には比較的使用頻度の高いUIですよね。
画面遷移時にフォーカスを当てたり、外したりすることがたまにあったりしますが、いつも調べている気がしますので、まとめておこうと思います。

#フォーカスの当て方

まず、フォーカスを当てるためには、以下を設定する必要があります。

```
searchView.requestFocus()
searchView.requestFocusFromTouch()
```

上記を設定することでフォーカスを当てることができます。
ただし、キーボードは立ち上がりません。

キーボードも合わせて立ち上げる必要がある場合は以下を設定する必要があります。

```
searchView.setOnQueryTextFocusChangeListener { v, _ -> v?.showKeyboard() }
```

SearchViewはフォーカスが当たったのを待ってからキーボードを表示する処理を実行しないとキーボードが立ち上がらない、といった罠があります。
この点注意が必要です。

#フォーカスの外し方

外し方に関しては簡単です。
以下を呼ぶことでフォーカスを外すことができます。

```
searchView.clearFocus()
```

#さいごに
いつも同じ罠を踏んでは調べてみたいなことをしている気がしていて、日常の業務でも意外と無駄が多い気がしています。
なるべく無駄を削減して効率よく日々の業務をこなせるよう、細かい内容でもどんどんまとめていこうと思います。
jQueryの$(document).on('click', 'セレクタ', function(){〜});を生JS（Vanilla JS）で書きたい

はじめまして、ARCHETYPの副社長テクニカルディレクターの神谷です。

プロジェクトでがっつりコードを書くことがめっきり減ってしまいまして、アウトプットする場所がなくなってしまったので、ちょっとしたTips系の記事などを気の向くまま書いていきたいと思います。

今回は**jQueryを使っていたところを生JSに変更していく**時のコードを書いてみました。
まずは動的に追加される要素にも対応可能にするイベントハンドリングの例です。

サンプルとしてアコーディオンUIで考えてみたいと思います。
タイトル部分をクリックすると中身の表示非表示を切り替えるサンプルです。

##HTML
ここは非常にシンプルに、タイトル（.title）とコンテンツ（.panel）が存在している状態。

```html
<div id="wrap">
  <div class="item">
    <div class="title"><p>title</p></div>
    <div class="panel">
      <p>aaaaaa<br>bbbbb<br>ccccc</p>
    </div>
  </div>
  <div class="item">
    <div class="title"><p>title</p></div>
    <div class="panel show">
      <p>aaaaaa<br>bbbbb<br>ccccc</p>
    </div>
  </div>
</div>
```



##JavaScript

```javascript
document.addEventListener('click', (event) => {
  let title = event.target.closest('.title'); //子要素も含めて取得
  if( title ) {
    let item = title.closest('.item');
    let panel = item.querySelector('.panel');
    panel.classList.toggle('show');
  }
});
```
1. documentにイベントを設定
2. `event.target` を参照して要素がクリックされたかを判別
3. `if`で要素の存在有無を判定
4. ifの中は実際の処理。今回はコンテンツ（.panel）にクラスをトグルで制御しています。やりたい処理に応じて書き換えます。

2で`closest` で絞り込んでいるのは、特定の要素（今回だと `.title` ）の子要素（`p`）をクリックすると、`event.target` が `p` になってしまうのでclosestで自身も含めた親要素を捜査しています。

## サンプル
最後にサンプルを以下に置いておきますね。
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="LYOVmrK" data-user="kamipoo" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/kamipoo/pen/LYOVmrK">
  Untitled</a> by kamipoo (<a href="https://codepen.io/kamipoo">@kamipoo</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

書き方だけでいったらjQuery使った方が断然シンプルではあります。
便利に使うなら独自でヘルパー関数作るとかした方が良さそうですね。

ARCHETYPではShopifyテーマ、Shopifyアプリ、Webサイト/サービスなどの開発を行うエンジニアを募集中です！
正社員、副業などとわず募集です！（フルリモートも相談可です！）
https://www.archetyp.jp/recruit/
気になる方はお気軽にエントリーお待ちしております！
例外処理は投球練習

# Exception

#### それ程頭が言い訳でもない人がプログラミングを理解する過程を書いてます。
Exceptionは基底クラスで、RuntimeExceptionやlogicExceptionが有り、それぞれ...
いや、分かりにくいな。となったので走り書きではありますがまとめてみた。
別にオブジェクト指向やクラスを理解していなくても読めるのでご安心を。

例外処理は、
- データベースに接続した際に接続できなかったり
- バリデーションでエラーが起きているときなどに
こういうエラーが起きてるよ！　とエラーの報告をしてもらって、
そのエラーをキャッチすることでどのようなエラーが起きているか探りやすくする仕組みです。

```PHP
try{
  //この中に処理を書きます
}catch(Exception $e){
  //エラーをキャッチした後に行う処理を書きます
}
```

#### 投球練習
野球だとピッチャーがボールを投げます。
→キャッチャーが受けます

コレを例外を投げる
→例外をキャッチする
と置き換えて考えてみる。
Error: the kotlin language client server crashed 5 times in the last 3 minutes

VSCodeの[Kotlin](https://marketplace.visualstudio.com/items?itemName=fwcd.kotlin)というextentionを入れて、remote debugをしようとしたところ発生したエラー。

```
the kotlin language client server crashed 5 times in the last 3 minutes
```

同様のエラーは[Java extension pack](https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-pack)を入れた際に一緒に入る、Java Serverも発生するようです。
今回はKotlinですが、解決方法はほぼ一緒ではないかと思います。

# 原因
1. extensionsの競合
1. extensions自体が何かで不具合
1. Javaのパスが通っていない
1. Javaのパスは通っているが、優先順位が下になっている
1. Javaのパスを変更したが、再起動していない
1. (dockerを使っている場合)ホストマシンからコンテナ絵のポートフォワードが成功していない
1. (macの場合)temurinを使用している
1. VSCodeをアンインストールし、再度インストールする
1. ディレクトリが置かれているパスに日本語がある
1. 再起動していない

## ① extensionsの競合
これはひとつずつ潰していくしかありません。
Lombok Extension消したり、Kotlin Extension消したり色々やる。

## ② extensions自体が何かで不具合
KotlinのExtensionをアンインストールし、再インストールしてみる。

## ③ Javaのパスが通っていない
以下のコマンドを叩いて、 `%JAVA_HOME%`と出た場合はパスが通っていないためパスを通す。
【参考】https://www.javadrive.jp/start/install/index4.html

```
¥User > echo %JAVA_HOME%
%JAVA_HOME%
```

パスが通ると以下のようになる。

```
¥User > echo %JAVA_HOME%
C¥Program Files¥Java¥jdk-17.0.2
```

## ④ Javaのパスは通っているが、優先順位が下になっている
javaのパスは、以下の２つがあるよう。
Windowsの場合、パスの順番で優先順位が異なるため、②の`C¥Program Files¥Java¥jdk-17.0.2`を上にする。
※jdkのバージョンは異なります

①`C¥Program Files¥Common Files¥Oracle¥Java¥javapath¥java`
②`C¥Program Files¥Java¥jdk-17.0.2`

## ⑤ Javaのパスを変更したが、再起動していない
④のようなパスを変更した場合、再起動しないと反映されない場合がある。
再起動しましょう。

## ⑥(dockerを使っている場合)ホストマシンからコンテナへのポートフォワードが成功していない
dockerの設定ファイルを見直しましょう。

## ⑦(macの場合)temurinを使用いる場合、OpenJDKに変更する
temyrinを用いているとうまくできない時がある模様。temurinをOpen JDKにしてみましょう。

## ⑧ VSCodeをアンインストールし、再度インストールする
VSCodeを一回消すと直った事例もある模様。
【参考】https://atmarkit.itmedia.co.jp/ait/articles/1810/12/news026.html

## ⑨ ディレクトリが置かれているパスに日本語がある
例えば `C¥User¥ほげほげ`のように、ユーザ名が日本語だったりすると不具合の温床になり得ます。
日本語が原因かもしれません。英語にしましょう。

## ⑩ 再起動していない
PCを再起動する。
それでもできない場合は最終手段です。シャットダウンして一日寝ましょう。
UIStackView.addArrangedSubview()のアニメーションを無効にする方法

# やりたかったこと

UIStackView上に動的にボタンを追加する処理をつくったが、表示時にうにょーんとアニメーションしてしまう。
見栄えが悪いのでやめたい。

# 試したこと

```swift
UIView.performWithoutAnimation {
    stackView.addArrangedSubview(view)
}
```

performWithoutAnimationで無効になるもんだと思ってこうやってみたが効果なし。

# 解決策

StackOverflowより
[addArrangedSubview without animations](https://stackoverflow.com/questions/35439390/addarrangedsubview-without-animations)

```swift
stackView.addArrangedSubview(view)

UIView.performWithoutAnimation {
    stackView.setNeedsLayout()
    stackView.layoutIfNeeded()
}
```

addArrangedSubview()の時点ではアニメーションは発生していなくてlayoutIfNeeded()による描画処理時にアニメーションしているということなのかな。

勉強になりました。
Dynamics 365 Finance and Operations ~ 2022年 Wave1（共通系・インフラ系編） ~

[前回](https://qiita.com/TaichiKayama/items/821c12a2948702c79dc8)に続いて、2022年 Wave1 D365 のモジュールのうち、共通系・インフラ系の部分をまとめました。内容がまだ明らかになっていないものも多いので、速報の日本語訳程度だとお考え下さい。

https://docs.microsoft.com/en-us/dynamics365-release-plan/2022wave1/finance-operations/finance-operations-crossapp-capabilities/planned-features

#クライアント・ユーザビリティの機能
|機能|メモ  |GA  |注目度　|
|:---|:---|:---:|:----:|
|Updates to client feature states with version 10.0.25|複数行コントロールにドロップダウンリスト・ルックアップ機能が追加、IEの非サポート、電子メール送信制限 etc.|2022/4|○|
|Updates to saved views and personalization|[パーソナライズ（個人ビュー）・保存されたビュー](https://qiita.com/TaichiKayama/items/88d9e23637bb9cde4688)にダイアログやワークスペースのビューが追加|2022/4|○|
|Vertically scrolling workspaces|ワークスペースのセクションが（水平に配置されるのではなく）垂直に積み重ねられ、折りたたみ可能になるように調整されるとのこと|2022/4|△|

#データ連携の機能
|機能|メモ|GA|注目度　|
|:---|:---|:---:|:----:|
|Specify which data is exported to Azure Data Lake|[Export to Azure Data Lake](https://qiita.com/TaichiKayama/items/0f431e377ecf5e3c1f81)でエクスポートされるデータのコントロールが可能に（大きいデータ型のフィールドもエクスポート可能になったり、機密データは除外したり）。|-|◎|
|One Azure Synapse experience for all Dynamics 365 data|[Export to Azure Data Lake](https://qiita.com/TaichiKayama/items/0f431e377ecf5e3c1f81)でADLSに貯められたデータは、Azure Synapseワークスペースに接続して、T-SQL・Spark・Synapseパイプライン・Power BIなどの任意のツールを使用してデータを操作できる。D365 CEのデータも同様に操作できる。|-|◎|

#RSATの機能
|機能  |メモ  |GA  |注目度　|
|:---|:---|:---:|:----:|
|Support of test case variants|複数回にわたって、バリエーションを変えて実行するテストケースを作りたいときに有用。テストケースのメンテが楽になる|2022/5|◎|
|Improved integration with Azure DevOps|いくつかはRSATでAzure DevOpsの機能が使えるようになる。つまりAzure DevOpsに詳しくない開発者に嬉しい|2022/6|○|
|Improvements to the Task recorder experience|タスクレコーダーの機能が強化（SSRSやドキュメントアップロードなどのシステムコントロールに対して対応可能→領収書のアップロードなどのEXシナリオとかで有用か）|2022/8|○|
|Improved Azure DevOps experience|Azure DevOpsは機能が多いが、RSAT用に必要な機能を使えればいいので、そういうエクスペリエンスにしてくれるらしい|2022/9|○|
[Laravel]同一モデル間での複数リレーション

# [Laravel]同一モデル間での複数リレーション

## 何をするか
既にリレーションが出来ているモデル間にもう一つリレーションを足したい

## 今回のシチュエーション

| users|
| ---- |
| id |
| name |

| comments |
| ---- |
| id |
| user_id |
| mention_user_id |

仕事のコード使えないので、まあこんな感じで雑いですけどテーブルがあったとします。ここでcommentsテーブルは、user_idのユーザーによってmention_user_idのユーザーにメンションされたコメントとします。
commentsテーブルのuser_idカラムはもちろんusersテーブルのidカラムと紐付いています。
ここでmention_user_idからもusersテーブルのidカラムとリレーションを紐付けてnameカラムとかを引っ張ってきたいのです。

## 方法
結論としては以下です。

```
// Userモデル
public function MentionUserComments()
{
　　return $this->hasMany(Comment::class, 'mention_user_id');
}
```

```
// Commentモデル
public function MentionUserComments()
{
　　return $this->belongsTo(User::class, 'mention_user_id');
}
```

という感じで第二引数に外部キーを指定します。
本来第二引数を指定しない場合はlaravel様がメソッド名を確認して自動でやってくれてる規約をオーバーライドしてる場合と同じですね。
という感じで意外と同一モデル間でもリレーションは複数つなげるみたいです。

## 最後に
一つのモデルでリレーション取ってる記事とかはあったのですが、２つのモデル感で複数リレーション取ってる記事はなかったのでホンマに出来るんかいなと思いながら試行錯誤したので備忘録とします。
同じ壁にぶち当たった悩めるエンジニアの一助になれば幸いです。
AWS Cognito - SER_PASSWORD_AUTH vs USER_SRP_AUTH

## はじめに
cognito の ユーザープール認証について調べたのでメモしておきます。

## ユーザープール認証フローの選択

##### ADMIN_USER_PASSWORD_AUTH
サーバーサイドでの認証で使用します。

##### CUSTOM_AUTH
チャレンジと、レスポンスの確認が 3 つの AWS Lambda トリガーを通じて制御される。 
（TODO）

##### USER_PASSWORD_AUTH
ユーザー名（メールアドレス）とパスワードをベースとした認証方式。

##### USER_SRP_AUTH
SRPフローはネットワーク経由でパスワードを送信しないため USER_PASSWORD_AUTH よりもセキュア。
USER_PASSWORD_AUTH を使用するよりは USER_SRP_AUTH を選択したい。

SRP（Secure Remote Password）については以下の記事がシンプルでした。

https://zenn.dev/link/comments/00ce34735b6407

# 本題 USER_PASSWORD_AUTH vs USER_SRP_AUTH

#### USER_PASSWORD_AUTH のリクエスト

```js
Amplify.configure({
  Auth: {
    authenticationFlowType: "USER_PASSWORD_AUTH",
    ...
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62209/0307cf21-43ee-a964-7a76-c266d933739e.png)

#### USER_SRP_AUTH のリクエスト

```js
Amplify.configure({
  Auth: {
    authenticationFlowType: "USER_SRP_AUTH",
    ...
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62209/cce63d34-5c15-6607-eeed-ee9307d400c3.png)


# USER_SRP_AUTH フローによる認証（React.js）

1. ユーザープールにユーザーを登録しておく

2. アプリクライアントの認証フローの設定から `ALLOW_USER_SRP_AUTH` を有効にする。

3. パッケージをインストール（`npm install aws-amplify`）

4. 実装

```App.jsx
import { useState } from "react";
import { Amplify, Auth } from "aws-amplify";

// https://docs.amplify.aws/lib/auth/start/q/platform/js/#configure-your-application
Amplify.configure({
  Auth: {
    region: "ap-northeast-1",
    userPoolId: "xxxxxxxx",
    userPoolWebClientId: "xxxxxxxxxxxxxxxxx",
    authenticationFlowType: "USER_SRP_AUTH",
  },
});

function App() {
  const [username, setUsername] = useState("");
  const [password, setPassword] = useState("");

  const login = async () => {
    const user = await Auth.signIn(username, password);
    if (user.challengeName === "NEW_PASSWORD_REQUIRED") {
       // アカウントステータスが「FORCE_CHANGE_PASSWORD」の場合同じパスワードで設定を上書きし、「CONFIRMED」に変更する
      Auth.completeNewPassword(user, password);
    }
    // この時点で local storage に認証情報が格納される
    console.log(JSON.stringify(user, null, 2));
  };

  const logout = async () => {
    await Auth.signOut();
  };

  return (
    <div className="App">
      <input type="text" onChange={(e) => setUsername(e.target.value)} />
      <input type="text" onChange={(e) => setPassword(e.target.value)} />
      <button onClick={login}>login</button>
      <button onClick={logout}>logout</button>
    </div>
  );
}

export default App;
```
ちなみに認証トークンはローカルストレージに保存されます。（XSSに気をつけよう）
以下を参考に実装してます。

https://docs.amplify.aws/lib/auth/emailpassword/q/platform/js/
GASでスプレッドシートの操作先ファイルの指定の仕方

#1.環境
| 項目       |       名前 |   
|:-----------------|------------------|
| アプリ    　　　　|Google Chrome           |

#2.前提
スプレッドシートのシート名が「シート1」で、A１の値が「hello world」であること。
![sapl1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2509814/7f57a6a5-f3bb-001f-d189-a0a8ba8d4949.png)

#2.IDで指定するやり方
```sample.gs
function op_ID() {
  // IDを取得する
  sp = SpreadsheetApp.openById('上の画像でURLを黒で塗りつぶした箇所をここに入れる');
  // シートを指定する
  sh = sp.getSheetByName('シート1');
  // 指定シートのA1の値を取得する
  ra = sh.getRange('A1').getValues();
  // 値を出力する、「hello world」が出力される。
  Logger.log(ra);
}
```

#3.URLで指定するやり方
```sample.gs
function op_url() {
  // URLを取得する
  sp = SpreadsheetApp.openByUrl('上の画像のURL');
  // シートを指定する
  sh = sp.getSheetByName('シート1');
  // 指定シートのA1の値を取得する
  ra = sh.getRange('A1').getValues();
  // 値を出力する
  Logger.log(ra);
}
```

#3.開いているやつを指定するやり方
```sample.gs
function op_av() {
  // 開いているファイルを取得する
  sp = SpreadsheetApp.getActiveSpreadsheet();
  // シートを指定する
  sh = sp.getSheetByName('シート1');
  // 指定シートのA1の値を取得する
  ra = sh.getRange('A1').getValues();
  // 値を出力する
  Logger.log(ra);
}
```
超初心者講座～MVCモデルについて～

今回はMVCモデルについてとにかくわかりやすく解説していきます。
Webシステムの開発を学習しようとしたら「MVCモデル」という言葉が頻繁にでてきますが、実際にサービスを作った経験が無いと、
「モデルはシステムの中でビジネスロジックを担当する」
などと急に言われてもイメージしずらいかと思います。
なので今回は全くWebシステムの開発をしたことが無い方でも気軽にお読みいただける内容で解説を進めていきます。

## MVCモデルとは

MVCモデルとは、Webシステムのもつ機能を役割ごとに大きく３つに分けて開発を進めていく方法のことです。
３つの役割とは
・**M**odel
・**V**iew
・**C**ontroller
です。
この３つの頭文字をとってMVCとなります。

前提として、このように役割ごとに分けなくても動くサービスは作れます。
ならばなぜ役割を分けるのかというと、システム開発では複数の人が開発に携わる中で、エラーが起きたり、開発メンバーが入れ替わったり、機能の改良が必要になったりさまざまなことが起きます。

そのようなことが起きた際に、機能ごとの分類分けができていない状態で数十万行のコードから１つの処理を探すのはとても時間がかかってしまいます。
それを防ぐためにMVCモデルという方法を使うことで、機能ごとにコードを整理整頓してプロジェクトにかかわる全員が共通認識を持って効率的に開発を進めることができるようになります。

## Model、View、Controllerそれぞれの役割

`Model（モデル）`
　データベースと直接やりとりしたり、データベースからとってきた値を加工したりするときはここにコードを書きます。

`View（ビュー）`
　実際に見ている画面に表示されるものはここに書きます。

`Controller（コントローラー）`
　全体の中心にいます。モデルやビューに指令を出し、処理の中核を担います。

## さらに具体的に！

インターネット上の掲示板を使っているとしましょう。
実際に以下の行動をしたときにそれぞれどこのどんな処理が動いているか見ていきましょう。
**①投稿を入力する画面を表示した。**
１，`Controller`「投稿入力画面を表示したいという命令が来た。投稿入力画面のファイルは〇〇フォルダの△△にあります。」
↓
２，`View`「はい私が投稿入力画面のファイルです。文字や画像の大きさ、背景の色など画面のデザインが書いてあります。私を表示してください。」
↓
投稿入力画面が表示される！

**②タイトル、本文を入力し、投稿ボタンを押した。**
１，`Controller`「投稿するという命令が来た。投稿モデルさんタイトルと本文を登録してください。」
↓
２，`Model`「はい、投稿モデルです。データベースの投稿テーブルにタイトル、本文を登録します．．．登録が完了しました。」
↓
３，`Controller`「登録が完了したという返答が来た。投稿完了画面を表示したい。投稿完了画面のファイルは〇〇フォルダの□□にあります。」
↓
４，`View`「はい私が投稿完了画面のファイルです。私を表示してください。」
↓
投稿完了画面が表示される！

**③マイページのプロフィール編集画面からユーザー名を変更した。**
１，`Controller`「ユーザー名を変更するという命令が来た。会員モデルさんユーザー名を更新してください。」
↓
２，`Model`「はい、会員モデルです。データベースの会員テーブルから該当する会員を見つけ、その会員のユーザー名を更新します．．．更新が完了しました。」
↓
３，`Controller`「更新が完了したという返答が来た。更新完了画面を表示したい。更新完了画面のファイルは◇◇フォルダの●●にあります。」
↓
４，`View`「はい私が更新完了画面のファイルです。私を表示してください。」
↓
更新完了画面が表示される！

以上が具体的な流れです。
上記の文章をコードにしたものが、実際にそれぞれのファイルに書かれます。

## まとめ
いかがでしたでしょうか。上記が理解できていればあとは実際にサービスを作り細かい部分の理解を深めていきましょう。
あくまでもソフトウェアの設計モデルの一つなので、MVCモデル以外にも色々な考え方があり、プロジェクトごとに細かな体系は異なります。
この記事を読んで。サービスを作っていくときはコードを整理整頓し、役割ごとに分け、処理を追いやすくすると皆がストレスなくエラーの出にくいサービスになるんだと思っていただけたら幸いです。
【Ruby】Date で月末の日付を得る

Ruby で，年と月が与えられてその月の月末の日付を得るにはどうするか。
言うまでもなく月末が何日かは月によって異なるし，2 月は年によっても異なる。

[Date.new](https://docs.ruby-lang.org/ja/3.1/method/Date/s/civil.html) の仕様の基本を知っていれば簡単なのだが知らなかった（てへ）。

```rb
require "date" 

year = 2022
month = 2

puts Date.new(year, month, -1) # => 2022-02-28
```

「年・月・日」の「日」を指定する第三引数に負数を与えると，月末から数えた日と解釈されるのであった（`-1` だと末日，`-2` だとその前日，など）。

既に日付オブジェクトが与えられているときに，その月の末日を得るには

```rb
require "date"

date = Date.new(2022, 2, 14)

puts date.then{ Date.new(_1.year, _1.month, -1) }
# => 2022-02-28
```

みたいにして計算できる。
Cloud Tasks ClientでServiceAccountの鍵を使う

# 1. サービスアカウントの鍵を用意する

※ 鍵を持っている場合、この手順はスキップしてください。

IAMと管理 > [サービスアカウント](https://console.cloud.google.com/iam-admin/serviceaccounts)
から既存のアカウントを選ぶか、新しく作成します

鍵を追加 > 新しい鍵を作成 > JSONをダウンロードします

![スクリーンショット 2022-01-28 19.52.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453380/f2e26dfa-005c-a2a2-2092-6894f9fe50b1.png)

# 2. 必要な情報を抜き出す

以下のようなJSONがダウンロードできたと思います。

```json:
{
  "type": "service_account",
  "project_id": "",
  "private_key_id": "",
  "private_key": "",
  "client_email": "",
  "client_id": "",
  "auth_uri": "",
  "token_uri": "",
  "auth_provider_x509_cert_url": "",
  "client_x509_cert_url": ""
}
```

以下の情報を取り出します（コードで利用します）

- projectId : project_id
- clientEmail : client_email
- privateKey : private_key

# 3. コードで利用
```typescript:
// サービスアカウントの情報を定義します
const projectId = serviceAccount.projectId;
const clientEmail = serviceAccount.clientEmail;
const privateKey = serviceAccount.privateKey;
const location = 'asia-northeast1'; // プロジェクトに合わせて変えてください

if (!projectId || !clientEmail || !privateKey)
  throw new Error('Missing service account credentials');
const client = new CloudTasksClient({
  projectId,
  credentials: {
    client_email: clientEmail,
    private_key: privateKey,
  },
});
const parent = client.locationPath(projectId, location);
```

CloudTasksClientのcredentialsにclientEmailとprivateKeyを含めるのがポイントです。

（環境変数GOOGLE_APPLICATION_CREDENTIALSにサービスアカウントキーのパスを指定でもいいです）

# 4. サービスアカウントに権限を付与

サービスアカウントに権限がないと以下のようなエラーが出ることがあります。

```
(node:1) UnhandledPromiseRejectionWarning: Error: 7 PERMISSION_DENIED: The principal (user or service account) lacks IAM permission "cloudtasks.queues.list" for the resource "projects/{ProjectID}/locations/asia-northeast1" (or the resource may not exist).
```

IAMと管理 > [IAM](https://console.cloud.google.com/iam-admin/iam)
からサービスアカウントにCloud Tasks関連の権限を与えます

編集から
![スクリーンショット 2022-01-28 20.11.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453380/4984c9fb-a4fd-9eb3-5e5e-eb43f5d096ee.png)

「クラウドタスク管理者」を追加します（必要に応じて絞ってください）
![スクリーンショット 2022-01-28 20.12.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453380/496c482e-b1a4-10e1-7f8a-7fdb78cd3174.png)
本番稼働中のRailsアプリでダウンタイムを発生させずにカラム名を変更したい

本番稼働中のRailsアプリで、カラム名を変更したいという状況が最近ありました。
単純に `rename_column :models, :before_column, :after_column` とやろうと思いましたが、こうするとダウンタイムが発生してしまうことが分かりました。
そこでいろいろ調査して、実際に自分がダウンタイムを発生させずにカラム名を変更できた方法を書き残したいと思います。
この他にもやり方はいくつもありそうですが、１つの例として参考にしていただけますと幸いです。

## 環境

- Ruby 3.0.1
- Rails 6.0.4

## 手順

1. カラム追加とデータ移行
2. 既存ロジックの修正とignored_columns指定
3. カラム削除

## カラム追加とデータ移行

### カラム追加

リネーム後のカラムを追加します。

```ruby
add_column :models, :after_column, :boolean
```

### データ移行

`before_column` → `after_column` のデータ移行を行います。
自分は直接SQLを叩いて対応しました。

```sql
UPDATE models SET after_column = before_column;
```

## 既存ロジックの修正とignored_columns指定

### 既存ロジックの修正

`before_column` を参照している箇所を修正します。
`after_column` を参照するように修正します。

#### APIの破壊的な変更ではない場合

```diff
- if before_column
+ if after_column
    # 処理
  end
```

#### APIの破壊的な変更の場合

フロントやアプリが参照している場合は注意が必要です。
ざっくり以下の手順が必要になると思います。

1. バックエンド側で、既存APIのロジック修正と新規APIの追加
2. フロントエンド側で、既存APIから新規APIに参照先を変更
3. バックエンド側で、既存APIの削除

以下にGraphQLを使っている場合の例を示します。

##### バックエンド側で、既存APIのロジック修正と新規APIの追加

```diff:app/graphql/types/model.rb
  field before_column, Boolean, 'リネーム前のカラム'
+ field after_column, Boolean, 'リネーム後のカラム'
+ def before_column
+   after_column
+ end
```

##### フロントエンド側で、既存APIから新規APIに参照先を変更

```diff:query.graphql
  query ModelQuery($id: Int!) {
    model(id: $id) {
-     beforeColumn
+     afterColumn
    }
  }
```

##### バックエンド側で、既存APIの削除

```diff:app/graphql/types/model.rb
- field before_column, Boolean, 'リネーム前のカラム'
  field after_column, Boolean, 'リネーム後のカラム'
- def before_column
-   after_column
- end
```

### ignored_columns指定

以下の記述を該当モデルに追加します。
これにより、Railsからリネーム前のカラムが見えないようにします。

```ruby
self.ignored_columns = %i[before_column]
```

## カラム削除

リネーム前のカラムを削除します。

```ruby
remove_column :models, :before_column
```

## 参考

- [ActiveRecordモデルのカラムを消すときにignored_columnsが必要な理由](https://tech.prog-8.com/entry/2020/12/08/093310)
- [稼働中RailsアプリのDBに対してカラム追加・削除する](https://qiita.com/SoarTec-lab/items/a192d381323cb741538e)
- [Ruby on RailsでDB マイグレーションする際にシステム障害を回避するための工夫](https://techblog.lclco.com/entry/2019/01/31/180000)
- [Rails アプリでオンラインでカラムの削除やリネームを行うには](https://eagletmt.hateblo.jp/entry/2017/09/24/004709)
複数フォルダ内のファイルをシェルスクリプトで並列実行する


任意のフォルダ内の全てのファイルに対してコマンドを実行したいときに使う

```
find [指定のフォルダまでのパス]/* -type d | xargs  -L 1 -P [並列数] sh -c 'cd "$0" && [コマンド] `
```
### 例
```
├─ parent
 │
 ├──child1
 | └─test1
 ├──child2
 | └─test2
 ├──child3
 | └─test3
```
上記のような構造の場合いかのような結果となる

```
$ find parent/* -type d | xargs  -L 1 -P 3 sh -c 'cd "$0" && ls'
$ test1test2test3
```
nginxのデフォルト有効モジュールリスト

毎度、ググっても出てこない小ネタを取り扱っております。
本記事は個人的な見解であり、筆者の所属するいかなる団体にも関係ございません。

# 0. はじめに

某社内のサービスでnginxを使っているのですが、Nginxのperlモジュールのおかげでログローテーションする度にnginxが落ちて困ったのでperlモジュールを削除したのですが、そもそもnginxのモジュールで必要かどうかをよく調べもせずにデフォルトのまま使っていました。

しかし、どこにもモジュールについて何が何をしているかをまとめているページがなかったので、ついカッとなって自分でリストを作りました。後悔はしていません。(間違いがあればご指摘ください。大歓迎です)

参考にした情報リンク

http://nginx.org/en/docs/

# 1. ダイナミックモジュール一覧

nginxのパッケージでデフォルトでインストールされるダイナミックモジュール

nginxモジュール有効ファイル|機能|要不要
---------|------|----
10-mod-http-ndk.conf|よく分からないのですが、Lua等の拡張機能を使うときに必要なモジュールのようです。ndkはNginxDevelopmentKitの略かと。|LuaやPerlモジュールを使わないなら不要だと思うが、その他必要としているモジュールもあるかもしれない
[50-mod-http-auth-pam.conf](https://github.com/sto/ngx_http_auth_pam_module)|BASIC認証のためのモジュール|BASIC認証しないなら不要
[50-mod-http-cache-purge.conf](https://github.com/nginx-modules/ngx_cache_purge)|fastcgi,scgi,proxy,uwsgiのキャッシュを削除するモジュール|まあ、あまり要らないはず
[50-mod-http-dav-ext.conf](https://github.com/arut/nginx-dav-ext-module)|WebDAVプロトコルに拡張メソッド(PROPFIND,OPTIONS,LOCK,UNLOCK )を追加するモジュール|普通は不要
[50-mod-http-echo.conf](https://github.com/openresty/echo-nginx-module#echo)|echoメソッドを追加するモジュール|普通は不要
[50-mod-http-fancyindex.conf](https://github.com/aperezdc/ngx-fancyindex)|autoindexをもっと高機能にして便利にしたもの|普通は不要
[50-mod-http-geoip.conf](http://nginx.org/en/docs/http/ngx_http_geoip_module.html)|GeoIPで国別にアクセス制限するもの|普通は不要
[50-mod-http-geoip2.conf](https://github.com/leev/ngx_http_geoip2_module)|GeoIPで国別にアクセス制限するもの|普通は不要
[50-mod-http-headers-more-filter.conf](https://github.com/openresty/headers-more-nginx-module)|ヘッダー情報を自由に書き換えるモジュール|普通は不要
[50-mod-http-image-filter.conf](http://nginx.org/en/docs/http/ngx_http_image_filter_module.html)|画像をリサイズしたり回転させたり変換させたりするモジュール|普通は不要
[50-mod-http-lua.conf](https://github.com/openresty/lua-nginx-module)|Lua言語を使ってNginxを拡張するモジュール|普通は不要
[50-mod-http-subs-filter.conf](https://github.com/yaoweibin/ngx_http_substitutions_filter_module)|出力と入力の両方を変換できるモジュール|普通は不要
[50-mod-http-uploadprogress.conf](https://github.com/masterzen/nginx-upload-progress-module)|ファイルのアップロードの進行状況をアップストリームサーバーに送信するモジュール|普通は不要
[50-mod-http-upstream-fair.conf](https://www.nginx.com/resources/wiki/modules/fair_balancer/)|バックエンドに最小稼働のサーバーに割り振るモジュール|複数のバックエンドを使う場合は必要
[50-mod-http-xslt-filter.conf](http://nginx.org/en/docs/http/ngx_http_xslt_module.html)|XSLTスタイルシートを使用してXML応答を変換するフィルター|普通は不要
[50-mod-mail.conf](http://nginx.org/en/docs/mail/ngx_mail_core_module.html)|各種メールプロトコルを扱うモジュール|普通は不要
[50-mod-nchan.conf](https://github.com/slact/nchan)|nginxをPub/Subサーバーとして使うモジュール|普通は不要
[50-mod-stream.conf](http://nginx.org/en/docs/stream/ngx_stream_core_module.html)|streamディレクティブのモジュール|普通は不要

# 2. 結果

結果的にほとんど無効でも問題ないという調査結果になりました。
MBOXからCSVへのコンバーター - MBOXファイルをCSV形式にエクスポートする

<p>このブログでは、MBOXをCSV形式に変換するための完璧なソリューションについて説明します。 これが必要な場合は、このブログを続けてください。</p>

<p>MBOXは、Thunderbird、Gmail、SeaMonkey、Apple Mailなど、電子メールメッセージを保存するためのほとんどのアプリケーションでサポートされていることは誰もが知っています。 1つのMBOXファイルには、特定の電子メールアカウントの多くのデータが永続的に含まれています。</p>

<p>一方、CSV（コンマ区切り値）は、特定の行と列の情報を含むデータのリストです。 すべてのものが適切に維持されているため、ほとんどのユーザーはデータをCSV形式で保存することを好みます。</p>

<p>多くのユーザーは、データを適切に取得するために、添付ファイルとともにMBOXをCSV形式に変換したいと考えています。</p>

<p>インターネット上に利用可能な手動ソリューションがないため、MBOXをCSVにインポートするときに望ましい結果を得るインスタントソリューションの1つを考え出しました。</p>

<h2>MBOXをCSV形式に変換するためのユーザークエリ</h2>

<p>「こんにちは。システムにThunderbirdMBOXファイルがたくさんあります。それらをCSV形式に変換して、別々の列のデータを適切に取得したいと思います。また、MBOXファイルから連絡先を実行するのにも役立ちます。 私は過去4日間解決策を見つけようとしていましたが、それを見つけることができませんでした。 誰かが私に最高のMBOXからCSVファイルへの変換ツールの1つについて教えてもらえますか？」</p>

<h2>MBOXからCSVにデータをエクスポートするためのインスタントソリューション</h2>
<p>統合ユーティリティの1つである<a href="MBOXからCSVへのコンバーター"><b>MBOXからCSVへのコンバーター</b></a>を使用して、MBOXファイルを添付ファイル付きのCSV形式に変換することをお勧めします。</p>
<p>このユーティリティは、ユーザーの拡張機能を提供し、技術ユーザーと非技術ユーザーの両方が簡単に使用できます。 また、特定のインテントを使用して特定の電子メールを検索するためのフィルター検索オプションを提供します。</p>
<p>MBOXからCSVへの変換ツールは、データを失うことなく、MBOXファイルを1サイクルで大量にExcelCSVに変換します。</p>
<p>無料のオンライン変換ツールをダウンロードして、プロセスを続行してください。</p>
<h3>MBOXファイルをMBOX形式に変換する方法は？</h3>
<p>マシンにソフトウェアをダウンロードして実行します。</p>
<p>次に、フォルダの選択をクリックし、ファイルを選択してMBOXファイルをロードします。</p>
<p>このアプリケーションは、それらを左側のパネルにロードします。 フォルダを確認して、[次へ]をクリックします。</p>
<p>次に、[変換]をクリックし、ファイル保存オプションとして[CSV]を選択します。</p>
<p>宛先パスを選択し、[変換]ボタンをクリックして変換プロセスを開始します。</p>
<h3>MBOXからCSVソフトウェアへの機能：</h3>
<p>このツールを使用すると、ユーザーは電子メールの添付ファイルを使用して1回の操作でデータの一括変換を行うことができます。</p>
<p>ユーザーは、電子メールアドレス、電話番号、および添付ファイルを個別にダウンロードできます。</p>
<p>他の複数のファイル形式やメールサービスにデータを転送することが可能です。</p>
<p>高度なフィルターオプションを使用すると、ファイル名、ファイルサイズ、宛先、CC、Bcc、電子メールヘッダー、および電子メールに含まれるその他のキーワードなど、さまざまなインテントを使用して特定の電子メールを検索できます。</p>
<p>このユーティリティは、Windows 7、8、10、Windows Vista、WindowsXPなどのすべてのバージョンのWindowsOSと互換性があります。</p>
<p>それ自体で十分なので、追加のインストールを行う必要はありません。</p>
<h3>最後の言葉</h3>
<p>したがって、上記のステップバイステップの手順に従って、1回の試行でMBOXを一括でCSVに変換します。 ソフトウェアは拡張機能を使用して開発されており、正確な結果が得られます。</p>
<p>このMBOXからCSVへのコンバーターは、ユーザーのニーズに応じて機能します。 ほとんどの専門家は、変換プロセスを実行するためにこのソフトウェアも推奨しています。</p>
Pythonで絶対URL+相対URL（結合）でつまずいた件 [スクレイピング,クロール（クローリング）,データ分析]

##要は以下のようの処理を実装<br><br>https://www.対象のサイト.com (絶対URL) + /docs/101(相対URL)<br>　　　　　　　　　　　↓<br>https://www.対象のサイト.com/docs/101 (絶対URL)としたい。
##①架空のDom構造を作る
```
from bs4 import BeautifulSoup

# <--実際のサイトでクロールver ※実際のサイトでクロールしたいときはコメントアウトをはずしてください

# from selenium import webdriver
# from selenium.webdriver.chrome.options import Options
# from time import sleep

# options = Options()
# #WebDriver(ブラウザ)の起動
# DRIVER_PATH = '/Users\あなたのUer名\Desktop\Selenium\chromedriver'

# driver = webdriver.Chrome(executable_path=DRIVER_PATH, chrome_options=options)

#//クロールver-->

#https://www.対象のサイト.com のhtmlが以下にあるとします.
html = """
<!DOCTYPE html>
<html lang="jp">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <div class="category">
      <div class="doc">
        <span class="s">タイトル: <a href="/docs/101">相対パス1</a></span>
      </div>
    </div>
    <div class="category">
      <div class="doc">
        <span class="s">タイトル: <a href="/docs/279">相対パス2</a></span>
      </div>
    </div>
    <div class="category">
      <div class="doc">
        <span class="s">タイトル: <a href="/docs/312">相対パス3</a></span>
      </div>
    </div>
</body>
</html>
"""

html = BeautifulSoup(html, 'html')
```
##➁相対パスを取得し、現在のURLと結合する
実際のサイトで現在のURLディレクトリを取得する場合は

```
base_join_url = driver.current_url
```
等にすると良いです。

```
for documents in categories_all:
    #aタグに相対パスがあるので
    documents_tag_a = documents.select('.doc a')[0]

    # hrefの値を取り出す
    href_link = documents_tag_a.get("href")

    # ベースURLと相対パスを結合する
    base_join_url = 'https://www.対象のサイト.com'
    links = base_join_url + href_link
    #確認
    print(links)
```
###https://www.対象のサイト.com/docs/101<br>https://www.対象のサイト.com/docs/279<br>https://www.対象のサイト.com/docs/312<br>上記のURLが取得でき、print出来ています。


#実際のURLでクロールしたい場合以下の処理を追加
```
# 実際のサイトでクロールver
#URLを開く
#     sleep(3)
#     driver.get(links)
#ブラウザバック
#
#     sleep(3)
#     driver.back()
```
MacのTerminalでBASE64のファイルをencode/decodeする

macOS Monterey 12.1 で動作確認。（もしかすると Command Line Tools for Xcode のインストールが必要かも）

## encode

```
> base64 -i <input_file_name> -o <output_file_name>  
```

## decode

```
> base64 -d -i <input_file_name> -o <output_file_name>  
```