OmniAICreator/Qiita-1.07M huggingface dataset:
GoogleFormで集めたアンケートデータをRで扱えるように加工する(3:加工-複数回答)

# 1. GoogleFormデータの加工(複数回答)

## 1-1. 複数回答加工用の関数を準備します
```R
# データの加工(複数回答用関数の準備) ----
F_set_choice <- function(org_ans_list, q_index, student_id, ans_str, mat, mat_else) {
  # 複数回答ベクトルを配列にして、回答文字列から配列番号を探して1を立てたマトリックスを返す
  # ans_str は、";"区切りの文字列
  
  each_ans_list = unlist(org_ans_list[q_index])  # 複数回答のリストを端からベクトルとして結合して 1 つのベクトルとしてまとめる
  
  #if(is.na(ans_str)){
  if(ans_str == ""){
    
    # 空文字列(無選択)の場合はNAをセットする(デフォルトで0が埋まっているため)
    mat[student_id, ] = matrix(NA, nrow = 1, ncol = ncol(mat))
    
  }else{
    
    sep = ";"                                   # 複数回答は ;区切り
    ans_list = unlist(strsplit(ans_str, sep))   # 複数回答を sep で分割して、ベクトル配列へ変換
    
    # 複数回答の各項目に関して、org_ans_list 中でのインデックスを求める
    # 完全一致かつ最初にヒットしたインデックスを取得する
    for (i in 1:length(ans_list)) {
      ans_index = match(ans_list[i], each_ans_list)
      if (is.na(ans_index)) {
        # org_ans_list に含まれない場合NAが返るものを、「その他」とみなす
        mat_else[student_id, 1] = ans_list[i]
      } else {
        # org_ans_list に含まれる場合は、該当の配列を1で上書きする
        mat[student_id, ans_index] = as.integer(1)
      }
    }
    
  }
  return (list(mat, mat_else))
}
```

```R
F_MakeMultipleFlagList <- function(org_ans_list, q_index, ans) {
  # 複数回答を選択肢分横に展開して、1/0フラグを立てたリストを作成する
  
  # すべての要素が 0 の matrix を作成
  sample_num = length(ans[,1])  # サンプル数（行）
  each_ans_list = unlist(org_ans_list[q_index])
  choice_num = length(each_ans_list)
  mat = matrix(as.integer(0), nrow=sample_num, ncol=choice_num)  # サンプル数(行) × 選択肢数(列)
  
  # 選択肢に無い場合(その他)は、回答内容の文字列をそのままセットする。サンプル数(行) × 1(列)
  #- mat_else = matrix("", nrow=sample_num, ncol=1)  
  mat_else = matrix(NA, nrow=sample_num, ncol=1)  
  
  for (sample_id in 1:sample_num) {
    mat_list = F_set_choice(org_ans_list, q_index, sample_id, ans[sample_id,], mat, mat_else)
    mat = mat_list[[1]]         # 選択肢から1が立ったもの
    mat_else = mat_list[[2]]    # 「その他」の文字列
  }
  
  return (list(mat, mat_else))
}
```

```R
F_SetMultipleColName <- function(df, colname.org){
  # 複数回答分解列に列名をつける(10以上なら2桁にする)

  col_digit <- if_else((ncol(df) > 9) , true = 2, false = 1)  #カラム数2桁(99)まで対応
  for (i in 1:ncol(df)) {
    colname.new <- paste(colname.org, "_", formatC(i, width = col_digit, flag = "0"), sep = "")  # Q02_1, Q11_01 など
    names(df)[i] <- colname.new
  }
  return(df)
}
```

## 1-2. データ加工をします(複数回答)
```R
# データの加工(2：複数回答) ----
# 項目名を加工
dat <- dplyr::rename(dat, "Q02" = "好きな食べ物をいくつでも")

# 選択肢の回答文字列
org_ans_q <- c(
  "かつ丼",
  "ラーメン",
  "鳥から",
  "かつ丼・ミニラーメンセット"
)
org_ans_list <- list(org_ans_q)

mat_list = F_MakeMultipleFlagList(org_ans_list, 1, data.frame(dat$Q02))

dfTemp1 <- data.frame(mat_list[[1]])  # マージ用df作成
dfTemp2 <- data.frame(mat_list[[2]])  # マージ用df作成

dfTemp1 <- F_SetMultipleColName(dfTemp1, "Q02")
dat <- cbind(dat, dfTemp1)
names(dfTemp2)[1] <- "Q02_Z"  #「その他」の項目名
dat <- cbind(dat, dfTemp2)
```

## 1-3. データ加工後
元データ Q02 と、変換後の Q02_1 ～ Q02_4, Q02_Z をご覧ください
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/672647/b22a51dd-e50f-f4c9-1058-a50245582da7.png)
グラフをダブルクリックして軸をリセットする　Bokehの場合

グラフ上をダブルクリックすると、軸がリセットされる機能って便利ですよね。
Plotlyにはその機能がデフォルトでついていますが、Bokehにはついていません。ですが、実は一行で実装できるのです。
[このissues](https://github.com/bokeh/bokeh/issues/4698)に実装方法が書いてあったので、参考にして簡単なグラフを作ってみました。

```python
from bokeh.plotting import figure, save, output_file
from bokeh.models import ColumnDataSource, CustomJS
from bokeh.events import DoubleTap
from bokeh.sampledata.stocks import MSFT
import pandas as pd

output_file('MSFT.html')

df = pd.DataFrame(MSFT)
df.date = pd.to_datetime(df.date)
source = ColumnDataSource(df)

# ここの設定値にグラフがリセットされる
p = figure(x_axis_type='datetime', y_range=(0, 200))
p.line(x='date', y='close', source=source)

# この一行のコードで、軸リセットを実装している
p.js_on_event(DoubleTap, CustomJS(args=dict(p=p), code='p.reset.emit()'))

save(p)
```

リセット機能がワタシ的に超重要だったのですが、これでBokehに移行できそうです。BokehのColumnDataSourceでいろんなデータをリンクさせられるのがすごく便利😀
DNSのゾーン情報を再読み込みする

# はじめに

職場の社内DNSサーバーでプライマリDNSのゾーン情報を書き換えた後、数時間が経過してもセカンダリDNSのゾーン情報が更新されませんでした。
そこで手動でセカンダリDNSのゾーン情報を更新（再読み込み）する方法を調べたので、それを備忘録としてまとめてみました。

# 使用するコマンド

## retransfer 

* マスターサーバからスレーブサーバへにゾーン情報を転送します。
 * 以下の `reload` や `reload {ゾーン名}` を使ってもゾーン情報が更新されない時に使います。

```bash:
[root@localhost ~]# rndc retransfer example.com
```

# その他関連するコマンド

## reload

* 設定ファイル（named.conf）と、更新されているゾーン情報の再読み込みを行います。
  * 「更新されているゾーン情報」とは、SOAレコードのシリアル番号が増えているものを指します。

```bash:
[root@localhost ~]# rndc reload
```

## reload {ゾーン名}

* {ゾーン名}に指定したゾーン情報だけを再読み込みしますが、更新されていなければ再読み込みされません。
  * 「更新されているゾーン情報」とは、SOAレコードのシリアル番号が増えているものを指します。

```bash:
[root@localhost ~]# rndc reload {ゾーン名}
```
VBA(マクロ)　よく使うコマンドメモ

順次追加していきます。

# セルへ入力

**Cells(行番号,列番号)**

```vb:
Cells(1, 1) = 1
```

# セルまたは範囲を選択

**Cells(行番号,列番号).select**
**Range(範囲).select**

```vb:
Cells(1, 1).Select
Range("A1:C3").Select
```

# 途中終了

**Exit Sub**

```vb:
Exit Sub
```

# メッセージボックスを表示

**MsgBox 内容**

```vb:
MsgBox "Hello World"
```

# 背景色を変更

**(セルまたは範囲).Interior.Color = RGB(赤, 緑, 青)**

```vb:
Cells(1, 1).Interior.Color = RGB(100, 100, 100)
Range("A1:C3").Interior.Color = RGB(100, 100, 100)
```

# フォント色を変更

**(セルまたは範囲).Font.Color = RGB(赤, 緑, 青)**

```vb:
Cells(1, 1).Font.Color = RGB(100, 100, 100)
Range("A1:C3").Font.Color = RGB(100, 100, 100)
```

# 太字

**(セルまたは範囲).Font.Bold = True**

```vb:
Cells(1, 1).Font.Bold = True
Range("A1:C3").Font.Bold = True
```

# 斜字

**(セルまたは範囲).Font.Italic = True**

```vb:
Cells(1, 1).Font.Italic = True
Range("A1:C3").Font.Italic = True
```

# 上書き保存

**ActiveWorkbook.Save**

```vb:
ActiveWorkbook.Save
```

# 【広告】
## 『Excelでリバーシを作ろう!!　マクロ、VBAを1から学ぶ』

Excelのマクロ(VBA)で「三目並べ」「マインスイーパー」「リバーシ」を作る解説本です！
マクロ、VBAが全くわからない人でも大丈夫！　丁寧な解説と図でしっかり理解しながら楽しくプログラミングを学ぶ事ができます！
**値段：300円(Kindle Unlimited対象)**

サンプルとして「準備」～「三目並べ」を無料公開しています。

https://qiita.com/sano192/items/9a47e6d73373d01e31fb

**【kindle】**

https://www.amazon.co.jp/dp/B09XLM42MW

**【booth(pdf】**

https://sano192.booth.pm/items/3785312
モジュールバンドラーってなに？

## モジュール化とは
モジュール化とは、別ファイルに分割すること。コードの管理をしやすくすることで、大規模開発などにも対応できる。
* 他のコードとの依存性を少なくし、変更、拡張がしやすくなる
* 変数名の競合をさせないことで、名前空間の汚染を防ぐことができる
* 機能ごとにモジュール化するため、再利用がしやすい

## モジュールバンドラーとは

> **モジュールバンドラーは複数のJavascriptファイルの依存関係を解析して、一つのファイルとしてまとめてくれる（バンドル）機能**があります。モジュールバンドラーによってバンドルされたファイルはそのまま読み込ませて使用することができます。これにより、開発者はファイルの依存関係を気にすることなく、Javascriptファイルを使用することが可能になりました。依存関係を気にすることがなくなったおかげで、大規模な開発などでもJavascriptを導入しやすくなりました。
> 
引用：[https://it-kyujin.jp/article/detail/1675/](https://it-kyujin.jp/article/detail/1675/)

JSにはもともとファイルをまとめる機能が存在せず、依存関係の解消にかなり手こずっていた背景がある。
そこに登場したのが、モジュールバンドラー。引用にもある通り、依存関係を気にする必要がなくなったことで、大規模開発にも対応できるようになった。

## モジュールバンドラーの代表格、「Webpack」
Webpackはもジュールバンドラールーツのこと。Node.js環境で使われる。
WebpackにはNode.jsの環境が必須。Node.jsのパッケージを管理するnpmも必須
* 依存関係のあるJavaScriptのモジュールを解決
* 読み込み順を気にせず、1回のリクエストで済むため効率的
* JavaScriptモジュールをブラウザで扱える形に簡単に変換できる
* ローダやプラグインなどが豊富 
 
記事の投稿を通して、今まではなんとなくインストールして使っていたWebpack。
現代の開発において、なぜモジュールバンドラーが必要なのか、その重要性を理解できました。
ROI とは

## 勉強前イメージ

復旧時間的なやつだっけ？
RTO的な？

## 調査

### ROI とは

Return On Investment の略で、アールオーアイと呼ばれています。
投資収益率や投資利益率のことを指します。
投資した額に対してどれだけ利益を得られたかを計る指標で、%で表されます。
数値が高ければ効果的な投資ができている、数値が低ければ見直すべき箇所がある というようなものになります。

ROIを出すメリットに関しては
行った施策に関して採算が取れているか、また今後注力すべきかなど計ることができますが、
デメリットとしては
ROIだけでは短期的な効果だけで見てしまう可能性があります。

ROIの求め方は以下になります。

```
利益÷投資額×100
```

## 勉強後イメージ

全然違った上にそもそも技術的な話でもない。。。
でも費用対効果はマーケティングだけじゃないのでどっかでまた目にするかも

## 参考

- [マーケティングでのROI（費用対効果）の考え方](https://promote.list-finder.jp/article/marke_all/roi/)
GoogleColaboratoryでpythonだけでなくRustも試せる環境を作る

# なぜやるか

- 下のリンクの書籍は`Python`と`Rust`を比較しているもので、これを読みたいのだが環境設定は面倒に感じたため。
  -  https://www.socym.co.jp/book/1351

# やったこと

1. `GoogleColaboratory`上のコードセルで`!apt install cargo`を実行することにより`rustc`コマンドを実行できるようにした。

2. マジックコマンドの`%%writefile hoge.rs`を使うことによって`hoge.rs`ファイルを`GoogleColaboratory`上で作成した。

3. 実際に`GoogleColaboratory`上で`Rust`の`Hello World`が実行できることを確認した。

# 参考文献
1.は`%%writefile`を使って`GoogleColaboratory`上で`C++`ファイルを実行する流れを紹介しているサイトです。2.は、`Rust`のインストール方法について触れているサイトです。`Rust`カーネルを利用する方法についても触れていますが、私はまだ試していません。3.は、実際に記事の内容を実行した`.ipynb`ファイルになります。

1. https://you1dan.hatenablog.com/entry/2022/01/09/090102
2. https://gist.github.com/korakot/ae95315ea6a3a3b33ee26203998a59a3
3. https://github.com/yaminabeworks/qiitakiji/blob/main/hello_rust.ipynb

# 感想
- `C++`も同様に書けるので、`C++`で書かれたコードを`Rust`に直していく際に便利だと感じた。

# 次にやる、この記事に関連すること
- 上で紹介した書籍を読み進める。
自社でウエブサイト制作「ＩＴメモ」

こんにちは！
茨城県のリラクゼーションサロン「シャムの国」です。　鹿嶋市と神栖市のタイ古式のお店です。　自社でウエブサイトを制作しています。　ホームページは、WordPressのLightning（G3・スキンなし)で制作しています。　　
苦労話も多く、同じ境遇の方に何かお役に立てればと思います。　
https://www.siamcountry-spa.com/website/
PythonとSeleniumを使ってkeio.jpに自動ログインする方法

# TL;DR

[keio.jp](http://www.keio.jp)に自動でログインする簡単な方法についてのメモ

# 自動ログイン

### 1. Webサイトの調査
[keio.jp](http://www.keio.jp)（正式名称は"Keio Single Sign-On System"）にログインするとき，次のようなページ遷移(HTTP Request)を辿っています。

1. `http://www.keio.jp` (Top page)
1. `https://auth.keio.jp` (SSO login page)
1. `https://gslbs.adst.keio.ac.jp/student/index.html` (Syllabus page)
1. `https://www.edu.keio.jp/ess2/login?` (Class support page)

このように、閲覧までにページ遷移（サーバ側との情報の受け渡し）が発生するウェブサイトを**動的サイト**と呼び、URLに飛べばすぐに閲覧可能なブログなどの**静的サイト**と区別されます。

なお、現代的なウェブサイトは、フロントエンドにはJavaScript(リクエスト毎にHTMLを生成する)、バックエンドにはRDBとそれを処理するスクリプト(リクエスト毎にデータを処理する)が仕込まれていることがほとんどですから、多くが動的サイトになります。

### 2. ツール選定

Web上のURLにアクセスする処理をコーディングするときに，**BeautifulSoup**のようなWebスクレイピングライブラリでは、Javascriptやページリダイレクションを含む動的なWebサイト（例：[keio.jp](https://keio.jp)）には対応できないため不十分です。そこで今回は、Pythonの動的なWebスクレイピングライブラリ**Selenium**と，Google Chromeをコマンドラインで制御するためのブラウザ専用のドライバとして**ChromeDriver**を使うことにします．

- **Selenium**のインストール方法については，[公式リファレンス](https://www.seleniumqref.com/introduction/webdriver_intro.html)を読んでください（大抵の場合，`pip install selenium`でOKです）．
- **ChromeDriver**のインストール方法についても，[Seleniumのドキュメントページ](https://www.selenium.dev/ja/documentation/webdriver/getting_started/install_drivers/
)を参考にしてください（Win/Mac環境のちがいに注意！）．

ChromeDriverを用いて、仮想的なブラウザ環境を作ることで、ユーザがサイト内でページ遷移する動作を、スクリプト上で再現できます。

### 3. スクリプト実装

K大の学生であれば、以下のスクリプトを使って[keio.jp](http://www.keio.jp)に自動ログインすることができます．あなたの学内メールアドレスとパスワードを入力し，Pythonの実行環境が整ったマシンに対してコマンドラインから命令を実行してください．

```python
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException

ID = "*****" # Please fill in your e-mail address at keio.jp (yukichi.fukuzawa@keio.jp) 
PW = "*****" # Please fill in your password in keio.jp

# Optional settings of chrome driver
options = webdriver.ChromeOptions()
options.add_argument('--headless')

# Boot chrome driver
driver = webdriver.Chrome("/usr/local/bin/chromedriver", options=options)
driver.set_page_load_timeout(15) # Time out 15 sec

# GET (HTML Page)
driver.get("https://auth.keio.jp")

# Find elements and POST (send keys to the input tag)
id_element = driver.find_element_by_name("j_username")
id_element.send_keys(ID)
pw_element = driver.find_element_by_name("j_password")
pw_element.send_keys(PW)

# Click login button
login_button = driver.find_element_by_name("_eventId_proceed")
login_button.click()

# GET (HTML Page)
driver.get("https://gslbs.adst.keio.ac.jp/student/index.html")

# GET (HTML Page)
driver.get("https://www.edu.keio.jp/ess2/login?")

# Close chrome driver
driver.quit()
```

SSO認証が終われば，HTTPリクエストによってHTMLファイルを取得し，好きなように必要な情報を取り出すことができます．

# 参考文献

- [The Selenium Browser Automation Project > Getting started > Quick tour](https://selenium.dev/documentation/en/getting_started/quick/#webdriver
)
【Azure】CloudshellからAdd-AzureADGroupMemberを実行できない

【2022/4/27追記】
2022/4/27に確認したところ、
CloudshellからもAdd-AzureADGroupMemberを実行できるようになっていましたが、
備忘として記事は残します。

AzureのCloudshellから、Add-AzureADGroupMemberを実行したところ、
よくわからないエラーに遭遇したので、対応方法を備忘録として残します。

【事象】
AzureのCloudshellから以下形式でAdd-AzureADGroupMemberを実行した際、エラーが発生し、ユーザをグループに追加できません。(2022/4/15時点)
なお、2週間ほど前は問題なく実行できていました。-


```powershell:Cloudshell上でAdd-AzureADGroupMemberを実行した際のエラー
Add-AzureADGroupMember -ObjectId "グループのオブジェクトID" -RefObjectId "ユーザのオブジェクトID"

Add-AzureADGroupMember: Error occurred while executing AddGroupMember 
Code: Request_BadRequest
Message: The URI 'https://graph.windows.net//xxx/directoryObjects/xxx' is not valid since it is not based on 'https://graph.windows.net/83dee3a9-071b-4190-b93f-823ba60f7a75/'.
RequestId: 928fd737-97d9-474c-8584-218751281f04
DateTimeStamp: Fri, 15 Apr 2022 12:34:36 GMT
HttpStatusCode: BadRequest
HttpStatusDescription: Bad Request
HttpResponseStatus: Completed
```

エラーに表示されたURLを叩くと、
Request_DataContractVersionMissingと記載されていました。

```xml:リンク先の記載内容
<error xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<code>Request_DataContractVersionMissing</code>
<message xml:lang="en">The specified api-version is invalid. The value must exactly match a supported version.</message>
</error>
```

【回避策①：az ad group member addコマンドを使用】
az ad group member addコマンドであれば、
従来通りCloudshellから実行可能です。
実効結果はAdd-AzureADGroupMemberと同じです。

```powershell:az ad group member addコマンドを使用
az ad group member add --group "グループのオブジェクトID" --member-id "ユーザのオブジェクトID" 
```
ちなみに2022/4/15時点だと以下警告が表示されます。
Microsoft Graph APIへの移行に伴い、
az ad group member addは--additional-propertiesオプションが削除される予定とのことです。
```
The underlying Active Directory Graph API will be replaced by Microsoft Graph API in Azure CLI 2.37.0. 
Please carefully review all breaking changes introduced during this migration: https://docs.microsoft.com/cli/azure/microsoft-graph-migration
```

【回避策②：ローカル環境のPowershellから実行】
ローカル環境のPowershellにて、azureadモジュールをインストール後、
Add-AzureADGroupMemberを実行すれば問題なくユーザをグループに追加できます。
```powershell:ローカル環境のPowershellからAdd-AzureADGroupMemberを実行
import-module azuread
Connect-AzureAD
Add-AzureADGroupMember -ObjectId "グループのオブジェクトID" -RefObjectId "ユーザのオブジェクトID"
```

【Add-AzureADGroupMemberが実行できなくなった原因】
ローカルのPowershellからはAdd-AzureADGroupMemberコマンドを実行できているので、
Cloudshell側の環境に原因があると思われますが、具体的な原因については不明です。
現状はaz ad group member addコマンドに切り替えるのが一番コストが少ない対応方法かと思います。

Cloudshellは便利ですが、MS社の都合で環境が変化する点を留意したうえで使用する必要があると改めて感じました。
【Git】メッセージのみコミットする方法

# 概要
「メッセージだけコミットする方法なんだったっけ」と、使う場面が少ないからこそ役立つ忘備録。

# メッセージのみコミットする
```shell
# メッセージを作成
git commit --allow-empty -m"<commit message>"

# git push
git push origin <branch>
```


# おまけ(これもよく調べ直しがち)

### ブランチ作成&切り替え
```shell
git checkout -b <branch>
```
scratch　始めました

僕は、最近、scratch　を始めました。

Qiitaをやっていなくて、すいません

https://www.scratch.mit.edu/users/5648597　

多分、上のやつを押しても、プロフを開かないと思うので、
自分で、https://www.scratch.mit.edu/users/5648597　　　　
コピペしてください
です。
フォローをお願いします。
拡散もお願いします
ライフサイクル　呼び出されるタイミング早見表



ライフサイクルのメソッドがそれぞれどのタイミングで呼ばれるかの早見表を自分のメモ用に作成しました
# ライフサイクル早見表
|メソッド名 |呼び出されるタイミングと説明|
|:-|:---|
|onCreate() |アクティビティの生成時。アクティビティの初期化は通常ここで行われる|
|onStart() |アクティビティが表示されるとき。複数回呼び出される可能性がある|
|onResume() |アクティビティがフォアグラウド(画面上で操作できる状態)になり、ユーザーの操作を受け付けるとき|
|onPause() |アクティビティがフォアグラウンドでなくなるとき|
|onStop() |アクティビティが非表示になったとき|
|onRestart() |バックグラウンドから、再びフォアグラウンドになる前。onStop()からアクティビティが再表示されるとき|
|onDestory()|アクティビティが破棄されるとき|


# 最後に
こうして改めて見ると、ライフサイクルとアクティビティの関係が親密なのを再確認しました。
また、「android ライフサイクル」などで検索すると　画像がわかりやすい画像が出てきますが
具体的にどのタイミングで呼ばれるのかということを言語化することでより理解が深まったと思います。
いつまでも，古いママやってんじゃねえよって話(6)

https://qiita.com/yatra9/items/a4b58020ebf478b87a1e

ここに書くのも，それでも，Julia 1.7.2 での話。そのうち古くなる。

# 18. 対角要素の1つ下に1,2,3,4が並ぶ5x5行列を作成する (★☆☆)

```Julia
Z = diagm(1:4, -1)
--> UndefVarError: diagm not defined
```

`using LinearAlgebra` を加えても

```
--> MethodError: no method matching diagm(::UnitRange{Int64}, ::Int64)
```

書き方が変わったのだ

```Julia
using LinearAlgebra
Z = diagm(-1 => 1:4)

5×5 Matrix{Int64}:
 0  0  0  0  0
 1  0  0  0  0
 0  2  0  0  0
 0  0  3  0  0
 0  0  0  4  0
```
nyうryおkうdえkいnあい時

# 問題
IMEがaiueoだけ日本語に変換してしまう．
```
にゅうりょくできない → nyうryおkうdえkいnあい
```

# 環境
- エディション: Windows 10 Home
- バージョン: 21H2
- OSビルド: 10944.1586


# 解決方法
`設定>時刻と言語>日本語>オプション>Microsoft IME>オプション>全般>互換性`で以前のバージョンを使っている場合にエラーが発生する．この設定をオフにすると解消できた．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/422520/8f77a6eb-f0a5-4cef-0508-2809100a142c.png)

Windows10のバージョン20H2のバグである．
RHEL8にFESSとElasticsearchをインストール

#内容
Elasticsearch v8.1.2
Fess 14.0.1
を導入するために行った手順

#環境・前提条件
* Red Hat Enterprise Linux 8.5

#参考情報
* [公式](https://fess.codelibs.org/ja/)

#手順

* JDKをインストール
yum install javaで入る1.8.0では一部バージョンの違いでエラーになるので注意
```Bash
sudo yum install -y java-17-openjdk
```
* Elasticsearchのインストール(RPMでの導入）
基本は公式サイトの[Install Elasticsearch with RPM](https://www.elastic.co/guide/en/elasticsearch/reference/current/rpm.html)の手順の通り

```Bash
wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.1.2-x86_64.rpm
sudo rpm --install elasticsearch-8.1.2-x86_64.rpm
```

* Elasticsearchプラグインのインストール

```Bash
sudo /usr/share/elasticsearch/bin/elasticsearch-plugin install org.codelibs:elasticsearch-analysis-fess:8.1.0
sudo /usr/share/elasticsearch/bin/elasticsearch-plugin install org.codelibs:elasticsearch-analysis-extension:8.1.0
sudo /usr/share/elasticsearch/bin/elasticsearch-plugin install org.codelibs:elasticsearch-minhash:8.1.0
```

* elasticsearch-configsyncのインストール

```Bash
curl -o /tmp/configsync.zip https://repo.maven.apache.org/maven2/org/codelibs/elasticsearch-configsync/7.15.0/elasticsearch-configsync-8.1.0.zip
sudo mkdir -p /usr/share/elasticsearch/modules/configsync
sudo unzip -d /usr/share/elasticsearch/modules/configsync /tmp/configsync.zip
```

* Elasticsearchの設定変更

```Bash:/etc/elasticsearch/elasticsearch.yml
configsync.config_path: /var/lib/elasticsearch/config
xpack.security.enabled: false
```

* FESSのインストール

```Bash
wget https://github.com/codelibs/fess/releases/download/fess-14.0.1/fess-14.0.1.rpm
sudo rpm -ivh fess-14.0.1.rpm
```

* Elasticsearch・FESSの起動

```Bash
sudo systemctl daemon-reload
sudo systemctl enable elasticsearch
sudo systemctl enable fess
sudo systemctl start elasticsearch
sudo systemctl start fess
```

* FirewallにElasticsearch（9200）とFess（8080）を追加
※9200は不要？
```Bash
sudo firewall-cmd --permanent --add-port={9200,8080}/tcp
sudo firewall-cmd --reload
```

* http\://ipaddress:8080/にアクセス

ログイン画面が表示されました
![FESS.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523652/b8347c22-a594-5722-51da-61b47f6ef323.png)
Goでバブルソート

最近またアルゴリズムの勉強を始めようと思い、まずはバブルソートを作ってみました。以前はこういう系はPythonでやってたんですが、最近Goの勉強もしてるのでGoで作ってみました。

こちらのオンラインエディタが勝手にフォーマットもしてくれて便利でした。
https://go.dev/play/

## コード

```go
package main

import "fmt"

func main() {
	numbers := [10]int{9, 8, 7, 6, 5, 4, 3, 2, 1, 0}

	switched := true
	for maxIndex := len(numbers) - 1; switched && 0 < maxIndex; maxIndex-- {
		switched = false

		for i := 0; i < maxIndex; i++ {
			left := numbers[i]
			right := numbers[i+1]

			if left > right {
				numbers[i] = right
				numbers[i+1] = left

				switched = true
			}
		}

	}

	fmt.Println(numbers) // [0 1 2 3 4 5 6 7 8 9]
}

```

## バブルソートの考え方
- 配列の右端か左端の隣り合う2つの要素を見比べて、あるべき順序と逆であれば入れ替える（たとえば「小→大」になってほしい配列で[5,1]っていう並びがあれば入れ替える）
- 上記の処理を1個ずつ位置をずらしながら配列の全長に対して行っていく（配列の左から1個目と2個目、2個目と3個目...）
- 上記の処理をワンセット行うと最大もしくは最小の数が配列の右端もしくは左端にたどり着く（たとえば「小→大」にしたい配列で左→右に並び替えを行うと最大の数が右端に来る）
- 確定している最大もしくは最小の値は抜いて残りの配列に対して同じソートを行っていく
- 並び替えが発生しなくなるもしくは比較対象の配列の長さが1になるまで行う

今回の配列の並び順の変化はこうなりました
```
[8 9 7 6 5 4 3 2 1 0]
[8 7 9 6 5 4 3 2 1 0]
[8 7 6 9 5 4 3 2 1 0]
[8 7 6 5 9 4 3 2 1 0]
[8 7 6 5 4 9 3 2 1 0]
[8 7 6 5 4 3 9 2 1 0]
[8 7 6 5 4 3 2 9 1 0]
[8 7 6 5 4 3 2 1 9 0]
[8 7 6 5 4 3 2 1 0 9]
[7 8 6 5 4 3 2 1 0 9]
[7 6 8 5 4 3 2 1 0 9]
[7 6 5 8 4 3 2 1 0 9]
[7 6 5 4 8 3 2 1 0 9]
[7 6 5 4 3 8 2 1 0 9]
[7 6 5 4 3 2 8 1 0 9]
[7 6 5 4 3 2 1 8 0 9]
[7 6 5 4 3 2 1 0 8 9]
[6 7 5 4 3 2 1 0 8 9]
[6 5 7 4 3 2 1 0 8 9]
[6 5 4 7 3 2 1 0 8 9]
[6 5 4 3 7 2 1 0 8 9]
[6 5 4 3 2 7 1 0 8 9]
[6 5 4 3 2 1 7 0 8 9]
[6 5 4 3 2 1 0 7 8 9]
[5 6 4 3 2 1 0 7 8 9]
[5 4 6 3 2 1 0 7 8 9]
[5 4 3 6 2 1 0 7 8 9]
[5 4 3 2 6 1 0 7 8 9]
[5 4 3 2 1 6 0 7 8 9]
[5 4 3 2 1 0 6 7 8 9]
[4 5 3 2 1 0 6 7 8 9]
[4 3 5 2 1 0 6 7 8 9]
[4 3 2 5 1 0 6 7 8 9]
[4 3 2 1 5 0 6 7 8 9]
[4 3 2 1 0 5 6 7 8 9]
[3 4 2 1 0 5 6 7 8 9]
[3 2 4 1 0 5 6 7 8 9]
[3 2 1 4 0 5 6 7 8 9]
[3 2 1 0 4 5 6 7 8 9]
[2 3 1 0 4 5 6 7 8 9]
[2 1 3 0 4 5 6 7 8 9]
[2 1 0 3 4 5 6 7 8 9]
[1 2 0 3 4 5 6 7 8 9]
[1 0 2 3 4 5 6 7 8 9]
[0 1 2 3 4 5 6 7 8 9]
```

## Goに関しての個人的ポイント

外側のループはWhileのイメージだったけど、GoではWhileが存在しない（!）のでforを使った
```go
for maxIndex := len(numbers) - 1; switched && 0 < maxIndex; maxIndex-- {}
```


## 参考
- [Go言語(golang)のループ for, for..range, foreach, while](https://golang.hateblo.jp/entry/2019/10/07/171630#for%E6%96%87)
PowerAutomate: Delve へのリンクを作って投稿者を紹介する

# 背景
Teams 内に別情報源から情報転送する場合に、投稿者を表示することがあります。
そんな場合に、投稿者名のリンクに、Delve リンクを仕込むとその人がどんな人なのかが紹介できていいかな？と

Yammer の投稿、Share の通知、別 Team の投稿、etc.

# 概要
1. [ユーザー情報を取得](#ユーザー情報を取得)
1. [Delve へのリンク作成](#delve-へのリンク作成)
1. [あとは使うだけ](#post-a-message-での利用例)

# 詳細
## ユーザー情報を取得
[ユーザーを検索する (V2)](https://docs.microsoft.com/ja-jp/connectors/office365users/#%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E3%82%92%E6%A4%9C%E7%B4%A2%E3%81%99%E3%82%8B-(v2)) には以下のように記載
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/e0391ea3-1c25-a107-a28c-5512e5958c4b.png)
ドキュメント（↑）に従ってユーザーを検索する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/bd9982db-c129-2936-a4f4-8f01d4a67057.png)

:::note warn
一意になる前提で、top を 1 としているが、複数見つかる可能性があるならなんらかの対処が必要
:::

## Delve へのリンク作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/047b5a20-3202-6a3f-d877-f19573c0ae14.png)

Delve へのユーザーリンクは以下な感じなので、検索した UserID を渡してやればよい。
> https://jpn.delve.office.com/?u={userID}&v=work

UserID は、ユーザーを検索する(Search for users) は、Id で取得
> first(outputs('Search_for_users_(V2)')?['body/value']).Id

また、取得したユーザーの表示名として、DisplayName を利用
> first(outputs('Search_for_users_(V2)')?['body/value']).DisplayName

```json:HTML形式でのTag A の作成例
<a href="https://jpn.delve.office.com/?u=@{first(outputs('Search_for_users_(V2)')?['body/value']).Id}&v=work">@{first(outputs('Search_for_users_(V2)')?['body/value']).DisplayName}</a>
```
:::note warn
ユーザーを検索する(Search for users) は複数取得されるので、一点にする為、first() を利用
:::

## Post a Message での利用例
Compose の出力をそのまま出すだけの単純な例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/bcc6a385-5e90-8ea7-d741-edec4808b55c.png)
表示名と、Delve へのリンクがこんな感じに動作
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/cbe2d7f7-219a-44be-7ca0-7be7a8c1a89b.png)
実際に踏んでると・・
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/fc09b826-ecb0-9cea-5b5b-cb667ea19813.png)

# あとがき
Yammer なんかだと、Yammer 内の User ID で、対象ユーザーの投稿一覧とかに飛んだ方が便利なときもあるので、使い分けかな
mailto: とかにするって手もありますよね

# keyword
how to make delve link when transfer
月初と月末の日にちを取得　その月の最初、最後の曜日の日にちを取得　PHP

## 用途
月初と月末の日にちを取得したい時に使う。
その月の最初、最後の曜日の日にちを取得したい時に使う。（例：最初の月曜日の日にち。最後の月曜日の日にち）

## 使用方法
**現在の月の月初と月末の日にちを取得**
```php:例
// 2022/04/15に行っている
$firstDay = date('d', strtotime('first day of'));
$lastDay = date('d', strtotime('last day of'));

var_dump($firstDay);
// '01'
var_dump($lastDay);
// '30'
```
※date の第一引数に `y-m-d` と入力すると `22-04-01` という形式で返ってくる。
　
**指定した月の月初と月末の日にちを取得**
```php:例
$hoge = "2000-01"
$firstDay = date('d', strtotime('first day of' . $hoge));
$lastDay = date('d', strtotime('last day of' . $hoge));

var_dump($firstDay);
// '01'
var_dump($lastDay);
// '31'
```
　
**現在の月の最初と最後の月曜日の日にちを取得**
```php:例
// 2022/04/15に行っている
$firstMonday = date('y-m-d', strtotime('first mon of'));
$lastMonday = date('y-m-d', strtotime('last mon of'));

var_dump($firstMonday);
// '22-04-04'
var_dump($lastMonday);
// '22-04-25'
```
※ `'last mon of'` の `mon` を各曜日に変えると指定の曜日の日にちを取得できる。
　
　
参考記事
https://www.php.net/manual/ja/datetime.formats.relative.php
実機(Android端末)で実行する方法

# 初め
端末 ：OPPO Reno A
androidバージョン       ：９
こちらの端末を使って実機でのアプリ実行の流れを説明していきます
# 早速
① 
設定→端末情報と進みビルド番号の項目を数回タップします
「デベロッパーになりました」とトーストが表示されるので、確認次第前の画面に戻ります
![Screenshot_2022-04-15-21-19-44-13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2394054/c8fdc29e-dced-758a-2793-b9704db411fb.png)



②
その他の設定→開発者オプション（①をやっていないと表示されていない可能性があります）と進みます
開発者オプションはオンオフを切り替えることが可能です
![Screenshot_2022-04-15-21-19-51-20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2394054/d1cd6c05-37b3-a636-210f-2e7a79a2f36a.png)


開発者オプション→USBデバッグのスイッチをタップすると
「USBデバッグを有効にしますか？」という確認のダイアログが表示されるのでOKをタップ

![Screenshot_2022-04-15-21-19-54-37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2394054/00c79134-8904-6e95-9c15-fa613ac2f3b3.png)
③
USBケーブルでPCと実機(android端末)を接続
AndroidStudioでアプリを実行します

右上の方にある緑の▷の横に繋がれた実機の端末名が表示されていることを確認し
緑の▷をタップ

![スクリーンショット 2022-04-15 21.12.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2394054/dbd501df-ca61-cbf0-1962-9d41686fc30c.png)

実機でアプリを実行することができます！
![Screenshot_2022-04-15-21-14-08-02_ee015900260ab508ba0bf0f18dc28a83.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2394054/7106fca3-1eb2-ddd9-0a40-856913f1141d.png)
いつまでも，古いママやってんじゃねえよって話(5)

https://qiita.com/yatra9/items/a4b58020ebf478b87a1e

ここに書くのも，それでも，Julia 1.7.2 での話。そのうち古くなる。

# 11. 3x3 の単位行列を作成 (★☆☆)

```Julia
Z = eye(3)
--> UndefVarError: eye not defined   廃止されたのね
```

何通りもある

```Julia
using LinearAlgebra

Array{Int}(I, 3, 3)
3×3 Matrix{Int64}:
 1  0  0
 0  1  0
 0  0  1
Array{Float64}(I, 3, 3)

diagm(0 => repeat([1], 3))
diagm(0 => repeat([1.0], 3))

diagm(0 => ones(Int, 3))
diagm(0 => ones(3))

Diagonal(ones(Int, 3))
Diagonal(ones(3))

Matrix(Diagonal(ones(Int, 3)))
Matrix(Diagonal(ones(3)))
```

まだまだいっぱいあってですね，ひとつひとつ記事にしていたら顰蹙もの...
いつまでも，古いママやってんじゃねえよって話(4)

https://qiita.com/yatra9/items/a4b58020ebf478b87a1e

ここに書くのも，それでも，Julia 1.7.2 での話。そのうち古くなる。

# 10. [1,2,0,0,4,0] の非ゼロ要素の番号を取得 (★☆☆)

```Julia
nz = find([1, 2, 0, 0, 4, 0])
--> UndefVarError: find not defined

nz = findall(!isequal(0), [1, 2, 0, 0, 4, 0])
3-element Vector{Int64}:
 1
 2
 5
```

その他

```Julia
nz = findall(!=(0), [1, 2, 0, 0, 4, 0])
nz = findall(x -> x != 0, [1, 2, 0, 0, 4, 0])
```
GitHubでリポジトリをSSHに移行したときのメモ

GitHubのリポジトリ接続をSSHにした時のメモ。

# 公開鍵・秘密鍵生成
鍵を入れるためのフォルダを作成。

```
% mkdir ~/.ssh && cd ~/.ssh  
```
RSA暗号で鍵を生成。
```
% ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (~/.ssh/id_rsa): id_git_rsa
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in id_git_rsa
Your public key has been saved in id_git_rsa.pub
```
`id_git_rsa`の部分は任意の名前。空欄にするとid_rsaになる。
このコマンドを実行するとカレントディレクトリに鍵が吐き出されるので、`~/.ssh`にいなければいけない（もしくは絶対パス指定）。

configファイルに鍵の名前を追記。
```
% cat << 'EOF' > config
> Host github github.com
>  HostName github.com
>  IdentityFile ~/.ssh/id_git_rsa
>  User git
> EOF
```
# 公開鍵をGitHubにアップロード

https://github.com/settings/keys

に移動し、右上の「New SSH Key」をクリック。
Titleに`id_git_rsa`（または自分の鍵の名前）、Keyに公開鍵の内容を入力。内容は次のコマンドで出力。

```
% cat id_git_rsa.pub
```

# 接続の検証

```
% ssh -T github
```
フィンガープリントを確かめろ、みたいなことを言われるので確認。良ければyesと打つ。
```
Hi (ACCOUNT_NAME)! You've successfully authenticated, but GitHub does not provide shell access.
```
これでSSH接続は成功。

# git remote originの書き換え
GitHubでSSHのURLをコピーしてくる。リポジトリページの「Code」で「git@github.com...」みたいなやつ。

```
% git remote set-url origin (SSH_REPOSITORY_URL)
```
これで書き換え完了。一応確認する。
```
% git pull origin main
```
つながったら成功。

# 参考

https://qiita.com/shizuma/items/2b2f873a0034839e47ce#github%E3%81%A8%E3%82%84%E3%82%8A%E3%81%A8%E3%82%8A%E3%81%99%E3%82%8B

https://qiita.com/minoringo/items/917e325892733e0d606e
エンジニア駆動DXへの招待 ～チームの隙間を埋めるための3つの提案～

以下のイベントで登壇させていただきました。

https://increments.connpass.com/event/243190/

> 昨今では「DX」がバズワードとなり、さまざまな企業がデジタル領域の改善を行なっています。 しかし、手段のみが先行し、本質的な変革が行われずに終わってしまう場合も少なくありません。DXを推進していくためには、エンジニアとビジネス部門の伴走が欠かせません。
>当イベントは「エンジニア駆動で進めるDX」をテーマに、エンジニアが推進するDXの可能性や主導するエンジニアのあり方についてゲストをお招きし、お話しいただきます。


## 登壇資料

https://speakerdeck.com/yasuoyasuo/enziniaqu-dong-dxhefalsezhao-dai-timufalsexi-jian-womai-merutamefalse3tufalseti-an

## 当発表の期待
### 対象：
- エンジニア＆デザイナーの方
- そうした方々のチームMgr職にあたる方

### 狙い：
- DXトレンド＆気運をチームの成果とご自身のキャリアアップに前向きに活かすためのご提案

### こちらではお話しないこと：
- 具体的な技術論には触れません


## リンク集

### 1．DXに対する現状認識

https://www.slideshare.net/TokorotenNakayama/dx-240495124

https://note.com/naoto111/n/nebd8adf8e69e

https://speakerdeck.com/yuzutas0/20210623

https://www.kikuya-bisyodo.co.jp/

https://www.kikuya-bisyodo.co.jp/logistics

https://note.com/nhk_syuzai/n/n96fdcdf4200d

https://kahoku.news/articles/20220409khn000011.html

https://note.com/yasuoyasuo/n/n234f87a69fd5

### 2．エンジニア駆動DXとは？

https://www.nttdata.com/jp/ja/data-insight/2017/012602/

### 3．3つの提案

https://speakerdeck.com/sho7650/herokudejin-sugushi-meruwebsabisu

https://dxcriteria.cto-a.org/

https://qiita.com/yasuoyasuo/items/cc4dd2b439553f384816

https://qiita.com/yasuoyasuo/items/1eb7298f91a44dce7abc

https://qiita.com/yasuoyasuo/items/c43783316a4d141a140f

https://qiita.com/yasuoyasuo/items/37cc24440b278363339e

## ご紹介した書籍

[GIVE & TAKE「与える人」こそ成功する時代 (単行本) | アダム グラント, 楠木 建 |本 | 通販 | Amazon](https://amzn.to/3KReehV)

[ITIL はじめの一歩 スッキリわかるITILの基本と業務改善のしくみ (IT Service Management教科書) | 最上 千佳子 |本 | 通販 | Amazon](https://amzn.to/3vnuzEq)

[スッキリわかる 日商簿記3級 第13版 [テキスト&問題集] (スッキリわかるシリーズ) | 滝澤 ななみ |本 | 通販 | Amazon](https://amzn.to/3Ogf2iD)

[「会社四季報」業界地図 2022年版 | 東洋経済新報社 |本 | 通販 | Amazon ](https://amzn.to/3ruWJMF)

[人を動かす　新装版 | カーネギー, デール, Carnegie, Dale, 博, 山口 |本 | 通販 | Amazon](https://amzn.to/3uKntLl)

[社内プレゼンの資料作成術【完全版】 | 前田 鎌利 |本 | 通販 | Amazon](https://amzn.to/3jEWHO7)
画像キャッシュを部分的に無効化する

Imagemagickを深掘りするため、ユーザー画像とアイテム画像を合成させて、簡易的に試着ができるという機能を実装していた。

![9ab908fcf945ef3911f996ea2d4757e7.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2584427/6c34fefb-aa1f-127b-cdc3-432f7e5790ba.jpeg)

上の画像はパンツの画像とユーザー画像を合成させているが、それぞれのアイテムページから試着ページに遷移するとそのアイテムの画像とユーザーの画像が合成されるという機能で、
例えばジャケットのページで試着ボタンを押すとジャケットの画像とユーザー画像が合成される様になっている。

が、

ローカル環境では問題なく動いていたのに、AWSにアップロードした後試着ページを表示させると一番最初に合成した画像が別の試着ページに遷移しても表示されてしまい、二回目以降は試着できなくなってしまった。

[![Image from Gyazo](https://i.gyazo.com/e7acf256fae711472adf205a55a8837a.png)](https://gyazo.com/e7acf256fae711472adf205a55a8837a)
ログやディレクトリ内を見ると問題なく機能は動いている。

# 原因

結論から言えば画像キャッシュが悪さをしていた。
「Ctrl」+「Shift」+「R」を押してキャッシュを削除してみたところ、正しい画像が合成された画像が表示された

      result.format("jpg")
      if Rails.env.production? 
        result.write("public/assets/virtualfitting#{current_user.id}.jpg")
        FileUtils.chmod(0644,"public/assets/virtualfitting#{current_user.id}.jpg"){current_user.id}.jpg"
      else
        result.write("public/images/virtualfitting#{current_user.id}.jpg")
      end

今回の仕様上、無駄に画像ファイルを増やさない為に上記の様に画像のURLが一人のユーザーにつき一つになるように設定している。
つまり、同じURLになってしまうが為にアプリケーションが画像キャッシュを保存してしまい、違うページで画像合成を行なってもキャッシュとして保存されていた画像が表示されてしまい、二回目以降は正しく動かなくなってしまっていた。

そこで

Cache Busting(キャッシュバスティング）という技法を使い、この画像合成機能のページに表示させる画像だけキャッシュを使わず毎回新しい画像であるということを認識させることにした。
```HTMLファイル
<%= image_tag "/assets/virtualfitting#{current_user.id}.jpg?#{Time.now.to_i}", class: "virtual-image1" %>
```
こうしておく事で、違うページで画像を表示させる際に、毎回新しい画像としてアプリに認識させることができた。

この技法は　WEBサービスの保守や開発で、JavaScriptやスタイルシート、画像などの静的リソースを更新した際、しばしば「確認したけど、更新されてないよ」とか云われて、「ブラウザのキャッシュを消してからもう一度見てみてください」みたいなやり取りを防止させるのにも役立つらしい。

参考にしたURL
https://ka2.org/optimize-browser-cache-of-static-resources
Laravelのコレクション型

# コレクション型
***配列を拡張した型でLaravel独自の型***みたいです。
データベースからデータを取得すると、コレクション型になっているみたいです。

# 関数
コレクション型で使える代表的な関数を一部紹介します。

# 公式ドキュメント
ここに詳細が載っているので見てください・

https://readouble.com/laravel/8.x/ja/collections.html#method-count

### chunk
コレクションを指定したサイズで複数の小さなコレクションに分割する関数です。

```TestController.php
class TestController extends Controller
{
    
     public function index()
    {
        $values = Test::all(); //Testモデルから取ってくる

        $values = collect([1, 2, 3, 4, 5, 6, 7]);
        $chunks = $values->chunk(4);
        $chunks->all();
        
        // [[1, 2, 3, 4], [5, 6, 7]]

        dd($values);

       return view('tests.test',compact('values'));
       //viewのファイル
     }
}
```

```
Illuminate\Support\Collection {#380 ▼
  #items: array:7 [▼
    0 => 1
    1 => 2
    2 => 3
    3 => 4
    4 => 5
    5 => 6
    6 => 7
  ]
}
```

表示を変えていきます。

```TestController.php
class TestController extends Controller
{
    
     public function index()
    {
        $values = Test::all(); //Testモデルから取ってくる

        $values = collect([1, 2, 3, 4, 5, 6, 7]);
        $chunks = $values->chunk(4);
        $chunks->toArray();　 //ここを変えた
       
        // [[1, 2, 3, 4], [5, 6, 7]]

        dd($chunks);  //ここを変えた

       return view('tests.test',compact('values'));
       //viewのファイル
     }
}
```

```
Illuminate\Support\Collection {#1338 ▼
  #items: array:2 [▼
    0 => Illuminate\Support\Collection {#1339 ▼
      #items: array:4 [▼
        0 => 1
        1 => 2
        2 => 3
        3 => 4
      ]
    }
    1 => Illuminate\Support\Collection {#1337 ▼
      #items: array:3 [▶]
    }
  ]
}
```

### count
コレクションのアイテム数を返します。

```TestController.php
class TestController extends Controller
{
    
     public function index()
    {
        $values = Test::all(); //Testモデルから取ってくる
        $values = collect([1, 2, 3, 4,]);
        $values->count();

        dd($values);

       return view('tests.test',compact('values'));
       //viewのファイル
     }
}
```

```
lluminate\Support\Collection {#380 ▼
  #items: array:5 [▶]
}
```

### first
指定された真偽テストをパスしたコレクションの最初の要素を返します。

```php
collect([1, 2, 3, 4])->first(function ($value, $key) {
    return $value > 2;
});

// 3
```

```php
collect([1, 2, 3, 4])->first();

// 1
```


# 参考資料
https://www.udemy.com/course/phpbeginnertolaravel/
ransackを使った検索機能実装

この記事は勉強した内容をアウトプットし、理解を深めるための学習用記事になっています。
説明の間違えている点などありましたらご指摘いただけると幸いです。
# ransackを使った検索機能実装について

## 実装手順

#### 1. gemに'ransack'を追加してインストール
```ruby
gem 'ransack'
```
```ruby
$ bundle install
```
bundle install後にサーバーを立ち上げ直すのを忘れていて３０分くらいエラーで引っかかりました、、、
bundle install後にはrails sを忘れずに！

#### 2. コントローラでの記述
このときに私は事前に投稿の一覧を表示させるとずっと勘違いしていました。なので投稿一覧用の変数# @dishes = Dish.allを準備していました。
調べているとransackではデフォルトで一覧画面できるみたいです！
```ruby
def index
    # @dishes = Dish.all
    @q = Dish.ransack(params[:q])
    @searchs = @q.result(distinct: true)
  end
```
#### 3. ビューでの記述
以下の記述でデフォルトの投稿一覧、検索フォーム、検索結果一覧が表示できます。
すごい便利ですね、、

 search_form_for @q do |f| は
検索フォームの記述でsearch_form_forはransack独自の記述。
@qにはコントローラの記述によりDishモデルのidが格納されている。

[カラム]_contと記述することであいまい検索が可能になり検索した用語と一部がマッチすれば検索結果として表示される。
そのほかにも色々指定できるみたいなので試してみようと思います。


コントローラで記述している@sesrchsに検索結果が格納され、あとはeach文で検索結果を表示させる。
```ruby
<%= search_form_for @q do |f| %>
  <%= f.label :introduction, "Keyword" %>
  <%= f.search_field :introduction_cont %>
   <%= f.submit "検索" %>
<% end %>

<% @searchs.each do |result| %>
    <%= image_tag result.dish_image, size: "100x100" %>
    <%= result.dish_name %>
  <% end %>

```

## 勉強になった点
1. bunndle install後はrails sでサーバーを再度立ち上げる。

2. ransackを使う際はデフォルトで一覧が表示される

------

検索方法がほかにも色々と存在するみたいなので指定して試してみようと思います。
ここまで見ていただきありがとうございました。
引き続き学習頑張ります。
[OutSystems]標準ログのトップレベルログとドリルログを整理する

OutSystems標準のログには、一連のリクエストの入り口となるトップレベルのログと、トップレベルのログと関連付けられるドリルログに分類される。一連の処理を関連付けて調査するためには、トップレベルのログのRequest_Key属性をドリルログのフィルタに使う。

公式ドキュメントで、トップレベルのログに分類されるものについての記述がちょっと古そうなので、動作を整理して、動作確認してみる。

# 2022/4/10時点でのドキュメント
[トップレベルのログ](https://success.outsystems.com/ja-jp/Documentation/11/Managing_the_Applications_Lifecycle/Monitor_and_Troubleshoot/Logging_database_and_architecture/The_log_tables_and_views#.E3.83.88.E3.83.83.E3.83.97.E3.83.AC.E3.83.99.E3.83.AB.E3.81.AE.E3.83.AD.E3.82.B0)によると、

> 「トップレベル」とみなされるのは以下のログです。
>
> - 画面 - このログのエントリ1つに対し、モバイルデバイスのWebアプリケーションまたはレスポンシブWebアプリケーションへのアクセスが1つマッピングされます。
> - 連携（サブタイプが「公開」）- このログのエントリ1つに対し、プラットフォームが公開するWebサービスへのアクセス（SOAPまたはREST）が1つマッピングされます。
> - モバイルリクエスト - このログのエントリ1つに対し、モバイルWebアプリケーションのサーバー側ロジックへのアクセスが1つマッピングされます。
> - 反復ジョブ - このログのエントリ1つに対し、バッチジョブまたはタイマーによる実行が1つマッピングされます。

とあり、原文（英語）も参照して考えると、Service CenterのMonitoringにある以下のログがトップレベルログであると思われる。

- Traditional Web Requests
- Screen Requests
- Integrations (Type=Exposed)
- Timers

Service Actionsはトップレベルログでは？　とも思うが、この後の動作確認結果を受けると、ドリルログであるらしい。

# 動作確認
## 基礎知識
トップレベルログ1レコードごとに一意のRequest_Keyが発行される。
例えば、1つのScreen Requests (Reactive Web App画面のScreen ActionからのServer Action呼出に対応）に紐づく一連のドリルログが持つRequest_Keyが一意。

サーバー処理中でRequest_Keyを取得するには、PlatformRuntime_APIモジュールにあるRequest_GetKey Actionを呼び、そのOutput Parameterを見れば良い。

このあたりは以前にQiitaに書いた。
[Request_GetKeyでログの関連付けを見られる](https://qiita.com/jyunji_watanabe/items/fd544ed1d62179454a08)

## 調査用実装
以下のような構成のモジュールとActionを用意した。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/be34b610-ac97-b3e2-5b01-db264b24e01a.png)

処理の流れは、Consumerモジュールでボタンをクリックすると

1. Screen Actionで同じモジュールのServer Actionを呼ぶ
1. 1のServer Action内でProducer1モジュールのServer Actionを呼ぶ
1. 2のServer Action内でProducer2モジュールのServer Actionを呼ぶ
1. 2のServer Action内でProducer2モジュールのService Actionを呼ぶ
1. 2のServer Action内でProducer2モジュールのExpose REST APIをConsumeして呼ぶ

1-5の各ActionでRequest_GetKey Actionを実行してRequest_Keyを取得し、LogMessage Actionでログ出力する。

## 確認結果
一連の処理の起点となるのは、Screen Actionから呼ぶServer Action。この情報は、Service CenterのMonitoring > Screen RequestsのログをExport to ExcelボタンでExcelに出力すると、Request_Key列で確認できる。つまり、この場合のトップレベルログはScreen Requests。

確認した結果は「c16feb96-59a5-4644-88cc-d0701b429ab9」だった。
LogMessageで出力したログは、General Logに出力されるので確認してみる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/7578ebe9-9fe0-c1f2-cd22-11bae9f9cf4b.png)

結果を見ると、1-4までが同じRequest_Keyを持っていて、Expose REST APIだけが別のRequest_Keyを持つということらしい。（Server ActionとService Actionはドリルログで、Expose REST APIはトップレベルのログということになる）

（個人的に）意外にもService Actionは一連のログの一部とみなされるようだった。
【PHP】PDF内のQRコードを読み取る

# はじめに
PDF内のQRコードをサーバーサイドで読み取りたいと思い、なんだかんだと調べて簡単な実装は出来たのですが、商用利用は難しそうだということで業務に使えなかった方法をここに載せます。

# 1. 環境 
- Windows10 64bit
- xampp
- PHP8.1

# 2. 使用したライブラリ

| ライブラリ名 | version | ライセンス | ざっくりした概要 |
|:-:|:-:|:-:|:-:|
|   [endroid/qrCode](https://github.com/endroid/qr-code) |  4.4.8 |MIT   |   QRコードの読み取りを行うことが出来る |
| [Imagemagick](https://imagemagick.org/)  |  7.1.0 | GPL互換の独自ライセンス |   画像操作することが出来る |
|   [Ghostscript](https://www.ghostscript.com/) |  9.56.1  |  AGPLか商用のデュアルライセンス | PDFを読み取って画像に変換したりできる  |

# 3.実装
```php:index.php
<?php
require __DIR__ . "/vendor/autoload.php";
use Zxing\QrReader;

/*白紙のページ+QRのPDFの読み取り*/
//2Pを指定する
//ページ指定をしたくないときは[]を付けなければOK
$pdf = __DIR__.'/test.pdf[1]';
$text="";//初期値

$image = new imagick($pdf);
$qrcode = new QrReader($image, QrReader::SOURCE_TYPE_RESOURCE);
$text = $qrcode->text();

echo "pdfファイルのQRコード読み取り結果<br>";
print $text;
$image->clear();
```
# 4.結果
上記を実行すると、無事PDF内のQRコードの内容を読みとることが出来ました！
しかし、Imagemagickが使用しているGhostscriptは**AGPLと商用のデュアルライセンス**です。

# 5.AGPLって？
使うならソースを全公開しろ！！！というライセンスです。詳しくは調べてね！

# 6.結論
Ghostscript、何とかして利用できないかと調べていたのですが結局下記理由で断念しました。
- AGPL版：利用してソース全公開は要件的に難しい
- 商用ライセンス版：ネット上には参考料金がない
- 英語でコミュニケーションを取る必要があり時間的に厳しい

# その他
いろいろPHP関連のPDF→画像化するライブラリを見てみましたが、中身を見るとImageMagickを使用している（＝Ghostscriptが無いとiMagickにPDF渡すとエラーが発生する）というものが結構ありました。
うっかりライセンス違反をしないよう気を付けよう！

# 参考
- [imagickを使うためにImageMagickの最新版をインストールする話](https://qiita.com/SHIN_DEVELOP/items/c60eb9cd592f4a6a0f00)
- [「さようなら ImageMagick」の考察](https://qiita.com/yoya/items/2076c1f5137d4041e3aa)
ImportError: cannot import name ‘xxx’ from partially initialized moduleの対処法

# エラーが出た状況
このエラーが出たのが1つのファイルに色々コードを記述して、だいぶごちゃごちゃしてきたので、複数ファイルに分けようとしていました。
そしたらファイルを複数に分けた後、「ImportError: cannot import name ‘xxx’ from partially initialized module」が出てきやがりました。


# 原因：循環import
このエラーの原因は循環importでした。
循環importとはなんだよという方のために説明いたします。


ファイルA
```
import ファイルB
```

ファイルB
```
import ファイルA
```

めちゃくちゃ簡潔に書くとこんな感じです。
ファイルAでファイルBをインポート、ファイルBでファイルA。
両方のファイルでファイルを呼び出し合っていることによりこのエラーが発生してあります。

この両方からファイルを呼び出し合っているところを解決してあげるとエラーが消えました🤗


# 終わりに
初心者エンジニアですので何かありましたらコメントしていただけるとありがたいです！☺️
非検査例外は正しいプログラムを書くことで回避できる

## この記事で学習 

https://qiita.com/ts7i/items/d7f6c1cd5a14e55943d4

## 理解が深まったところ

- 多段の呼び出し階層への対応

### 検査例外

正しいプログラムを書いても、回避できない例外。


検査例外とは、呼び出し元に何らかの対処を強制する例外である。
対処しないと、コンパイルエラーが発生する。
Exceptionクラスを継承するすべてのものである。
基本的な対処としては以下。


- try-catchで捕捉する方法
- throwsで呼び出し元にゆだねる方法

代表的なものに、以下がある。

- IOException(入出力関係の例外)
- SQLException(DB系の例外)
- ClassNotFoundException(クラスが見つからない)

### 非検査例外

正しいプログラムを書くことで、回避できる例外。

非検査例外とは、検査例外のような呼び出し元での対処が強制されない例外である。
例えば、Integer.parseInt(String) メソッドは非検査例外の NumberFormatException を送出する可能性があるが、コンパイルエラーは出力されない。
代わりに実行時にエラーが発生する。

Runtime Exceptionクラス系であり、以下のものに代表される。

・NullPointerException(ぬるぽ)
・ArrayIndexOutOfBoundsException(配列で存在しない要素へのアクセス)
・IllegalArgumentException(不正な引数をメソッドに渡した)



https://freelance-jak.com/technology/java/1157/
サーブレットJSPについて


# サーブレット / JSPの基本を学ぶ。

## 参考図書
基礎からのサーブレット/JSP

https://www.amazon.co.jp/-/en/%E5%AE%AE%E6%9C%AC-%E4%BF%A1%E4%BA%8C/dp/479734041X


## サーブレットとは

サーブレットとは、簡単にいうと、「サーバー上で動作するJavaプログラム」のこと。
ブラウザなどのWebクライアントを対象とした、動的な処理をして結果を返すWebサーバー上で動くプログラムのこと。
通常のJavaアプリケーションはmain()関数が呼ばれて実行されるが、サーブレットは、クライアントからリクエストがあった際に、サーバーから呼び出されて実行される。

## JSPとは

HTMLページを作成するための、サーブレットの拡張技術。
サーブレットの処理の中に、HTMLの内容を書き出す処理を記述し、Webクライアントへレスポンスを返していた。
しかし可読性の低さなどから、HTMLの中にJava言語でプログラムを記述することができるようになった。
これにより、デザイナーとプログラマの作業が分担でき、開発効率が上がるなどの恩恵が受けられるようになった。

## 基本的な使われ方
 
1. サーブレットがリクエストを受ける。
2. サーブレットでDBアクセスなどの動的な処理を実行し、結果のオブジェクトをJSPにforwardする。
3. JSPはサーブレットから受け取った動的な情報をもとに、HTMLを作成し、クライアントにレスポンスとして返す。
4. Webクライアントは、HTMLのformタグなどを使用し、リクエストをサーブレットに送る。
5. 1 に戻る。

これが、"超"基本/原始的な、サーブレット/JSPの使われ方だ。

## その他の基本的な要素

あとは、この辺はおさえておきたい。

- セッション
- フィルタ
- サーブレットのライフサイクル
- データベースの利用

↓このサイトが、非常にわかりやすくシンプルで理解深まった。

https://www.javadrive.jp/servlet/

## 番外 Tomcatとは
オープンソースのアプリケーションサーバー。サーブレットを動作させるには、アプリケーションサーバーが必要。Tomcatは、HTTPサーバーを内部に持っており、別途HTTPサーバーを用意する必要はない。
GitLabをDockerで立ててプロジェクトをクローンする

### gitlabサーバの起動



```sh
// Dockerデーモンの起動:
sudo service docker start
// 停止したコンテナの起動:
docker start コンテナ名
// 全コンテナ停止:
docker stop $(docker ps -q)
// 全コンテナ削除: 
docker rm $(docker ps -q -a)
// 全イメージ削除: 
docker rmi $(docker images -q)
```



### PowerShellで以下のコマンドで80番ポートが開いているかを確認。

```powershell
Test-NetConnection -ComputerName localhost -Port 80
```

#公式のDocの方法でやってみる。

https://docs.gitlab.com/ee/install/docker.html


### インストールとRun
Docker Engine上で以下を実行。

```sh
export GITLAB_HOME=/srv/gitlab
```

```sh
sudo docker run --detach \
  --hostname gitlab.example.com \
  --publish 443:443 --publish 80:80 --publish 22:22 \
  --name gitlab \
  --restart always \
  --volume $GITLAB_HOME/config:/etc/gitlab \
  --volume $GITLAB_HOME/logs:/var/log/gitlab \
  --volume $GITLAB_HOME/data:/var/opt/gitlab \
  --shm-size 256m \
  gitlab/gitlab-ee:latest
```

以下のコマンドで進捗を確認できる。

```sh
sudo docker logs -f gitlab
```

以下のコマンドでDockerのコンテナ内からパスワードを取得する。ユーザー名`root`でログイン。

```sh
sudo docker exec -it gitlab grep 'Password:' /etc/gitlab/initial_root_password
```
適当にプロジェクトを作成し、SSHでのクローン用のURLをメモ。

git@localhost:root/test.git

### クローン

Windows環境で簡単にGitを操作できるように、tortoiseGitをSSHClientでインストール

https://tortoisegit.org/download/

user/.ssh/id_rsa.pubをコピーし、GitLabの Preference > SSH Keyにコピペして追加。

右クリックから、`git@localhost:root/test.git`を指定して、クローン。


## まとめ

今までやりたかったことがやっとできた、、。
まずは公式ドキュメントを探そう。。確実にスムーズにいくはず。従えばよいだけ・・。



https://starmint.net/windows11-right-click-menu-old-style.html
DockerでHttpサーバーを動かす


https://qiita.com/aimufodna/items/147b27d2b06b38f9c594

↑前回の記事で、Dockerを動かす環境を整えたので、実際に動かしてみる。

## Docker run

以下のコマンドを実行するだけ。


```sh
# コンテナ名：con1
docker container run --name con1 -d -it -p 81:80 -v /tmp/dir1:/usr/local/apache2/htdocs httpd 
```

これを実行すると、初回はpullが行われる。

`/tmp/dir1`配下に適当な`index.html`ファイルを作成する。

`localhost:81`にアクセスすると、作成したhtmlにアクセスできる。

ファイルは、
powershellから、以下のコマンドで転送もできる。

```sh
scp -r C:\Users\User1\Downloads\tpl_090\tpl_090/index.html user@<IPアドレス>:/tmp/dir2/
```

## コンテナをもう一つ実行してみる。

ポートマッピングが競合しないように気を付ける。また、ファイルシステムは同じでも別でもＯＫ。
`index.html`の内容を少し変えて、配置する。

```sh
# コンテナ名：con2
docker container run --name con2 -d -it -p 82:80 -v /tmp/dir2:/usr/local/apache2/htdocs httpd 
```

`localhost:82`にアクセスすると、作成したhtmlにアクセスできる。


## まとめ

簡単にコンテナを起動し、Apatcheサーバーを立ち上げることができる。
WordPressのウィジェットブロックエディターを無効にする方法

WordPress5.8以降、ウィジェット編集画面の仕様が大幅に変更されました。
UIがブロックエディター形式に変更され、ウィジェットの使い勝手が大幅に変わりました。

従来のウィジェット編集画面に慣れている方向けに、編集画面を元に戻す方法をご紹介します。
以下の2通りの方法があります。お好きな方法をお試しください。

## プラグインで従来の編集画面に戻す方法

WordPress公式のプラグイン「Classic Widgets」を使うともっとも簡単です。少なくとも2022年までサポートされています。
プラグイン「Classic Widgets」を有効化するだけで簡単に従来のウィジェット編集画面に戻すことができ、すべてのウィジェットを従来通りご利用いただけます。
プラグインについては公式ページを参考にご覧ください。

https://ja.wordpress.org/plugins/classic-widgets/

## ウィジェットブロックエディターを無効にする方法

この方法は**テーマファイルを編集するので、必ずバックアップを取ってから行ってください。**
ここで紹介するコードをそのままコピペするだけでウィジェットの編集画面を従来のものに戻せます。

プラグインを使わずに新しいウィジェット編集画面を無効にするには、下記を`functions.php`に追記します。

```php
/**
 * ウィジェットブロックエディター無効化
 */
add_filter( 'use_widgets_block_editor', '__return_false' );
```

または、下記を`functions.php`に追記しても大丈夫です。

```php
/**
 * ウィジェットブロックエディター無効化
 */
function disable_widgets_block_editor() {
  remove_theme_support( 'widgets-block-editor' );
}
add_action( 'after_setup_theme', 'disable_widgets_block_editor' );
```
Java開発環境を構築

## Java実行環境を構築

### Javaをインストールする

まずはJavaをインストールする。職場で使用しているので、Amazon Corretto 11 をインストールする。
公式のドキュメントから、Windows_×64のJDK .msiをダウンロード。

https://docs.aws.amazon.com/ja_jp/corretto/latest/corretto-11-ug/windows-7-install.html

※自動でJAVA_HOMEとPATHを通してくれているようだ。

もし、PATHが通っていなかったらPATHを通す。

https://www.javadrive.jp/start/install/index4.html#section3

https://qiita.com/sta/items/63e1048025d1830d12fd

インストールされているかを確認。

```cmd
C:\Users\User1>java --version
openjdk 11.0.13 2021-10-19 LTS
OpenJDK Runtime Environment Corretto-11.0.13.8.1 (build 11.0.13+8-LTS)
OpenJDK 64-Bit Server VM Corretto-11.0.13.8.1 (build 11.0.13+8-LTS, mixed mode)
```

---

### Mavenをインストールする。

https://qiita.com/Junichi_M_/items/20daee936cd0c03c3115

インストールされているかを確認。

```cmd
C:\Users\User1>mvn -v
Apache Maven 3.8.4 (9b656c72d54e5bacbed989b64718c159fe39b537)
Maven home: C:\apache-maven-3.8.4
Java version: 11.0.13, vendor: Amazon.com Inc., runtime: C:\Program Files\Amazon Corretto\jdk11.0.13_8
Default locale: ja_JP, platform encoding: MS932
OS name: "windows 10", version: "10.0", arch: "amd64", family: "windows"
```



---

### Eclipseをインストールする。

Eclipseには、主に3パターンのインストール方法があるといえる。（個人の意見です。）

- Eclipse公式サイトからインストーラをダウンロードしインストールする方法
- Eclipse公式サイトからzipファイルとしてダウンロードして展開する方法
- Pleiades All in Oneをダウンロードして展開する方法

筆者は、2つ目の「Eclipse公式サイトからzipファイルとしてダウンロードして展開する方法」をお勧めする。
この方法は、Eclipseを動かすためのJavaなどがアーカイブされているのと、zipを展開するだけで使用できるので簡単。

以下の公式からpackageとしてダウンロードする。
※ 単純にDownloadするとインストーラをダウンロードしてしまうので注意。

その中で、「Eclipse IDE for Enterprise Java and Web Developers」をダウンロードする。
Webアプリなどの開発を行うには、こちらを使用する。

https://www.eclipse.org/downloads/packages/

---

### Tomcatをインストールする。

https://eng-entrance.com/java-servlet-tomcat-install

64-bit Windows zipをダウンロード。



https://tokkan.net/jspservlet/mvnj.html

https://eng-entrance.com/servlet-web-annotation
WSL2のUbuntsuにSSH接続する



## UbuntsuにSSH接続

Ubuntuでは、デフォルトではクリップボードが使えないとのこと。

いろいろ設定して有効にできるようだが、結構めんどくさそうだった。
いつも使っているSSHクライアントから操作すれば、慣れた使い方ができるのではと思い接続を試みた。
簡単にいくと思ったが、苦戦した。（２時間くらい）

※ やる意味があるのかどうかは知りません。

## SSH接続の基本

SSH接続の基本として、以下は押さえたい。

- サーバー側の設定では、ユーザー名とパスワードのみで接続できる。
- 公開鍵と秘密鍵を生成する。
- サーバー側には公開鍵を登録する。
- クライアントは秘密鍵を用いてサーバーにSSH接続する。
- サーバーは22番ポートを開けている。
- サーバーはsshのデーモンが動いている。

## パスワードで接続する方法

まずは、Ubuntu（サーバー側）の設定
まずは、以下のコマンドでopensshをインストールする。
つまり、SSHの接続先として準備をする。

```sh
sudo apt-get install openssh-server
```

以下のコマンドで、設定ファイルを開いて、編集する。

```sh
sudo nano /etc/ssh/sshd_config
```
※`/etc/ssh`配下に各種設定ファイルが存在する。


`PasswordAuthentication `をyesにして、パスワードでのSSH接続を許可する設定に変更。

```sh
# 変更前
PasswordAuthentication no

# 変更後
PasswordAuthentication yes
```

設定変更後、以下のコマンドで再起動し、設定を反映させる。

```sh
sudo /etc/init.d/ssh restart

# 現在の状態を確認
sudo /etc/init.d/ssh status
```
また、22番ポートを開放する。

```sh
sudo ufw allow 22
```


以下のコマンドで、サーバー側のIPアドレスを確認。

```sh
ifconfig
```
コマンドがないと言われたら以下でコマンドを使えるようにする。
```sh
sudo apt install net-tools
```
`eth0:`の`inet`の値がホストのIPアドレスになる。


あとは、SSHクライアントで

- IP
- ユーザー名
- パスワード

でSSH接続。これでできるはず。
あとは、後述する公開鍵での接続に切り替えるのがセキュリティ上望ましい。

### トラブルシューティング

`Permission denied (publickey)`

と言われる場合には。
サーバー側のパスワードでの接続OKの設定が反映されていない。
そのため、登録されていない鍵で認証しようとしてエラーになる。

また、鍵を使用した接続を試みている際は、
以下のコマンドでデバッグログを表示することができる。

```
ssh -vT <ユーザー名>@<IPアドレス>
```

https://ormcat.net/blog/20210509_github-denied-publickey/


## 公開鍵でのアクセス


### まずは、サーバー側の設定

サーバー側には、公開鍵が登録されている必要がある。

具体的には、`~/.ssh/authorized_keys `に公開鍵が登録されている必要がある。

※そもそもサーバー側に`~/.ssh`ディレクトリがない場合は、以下のコマンドを実行すると、`id_rsa ` `id_rsa.pub`が作られると同時にディレクトリ`.ssh`も作成される。

```sh
ssh-keygen
```

### クライアント側の設定
http://uubunt.blogspot.com/2012/03/windows7ubuntu1110ssh.html

上記の⑥、⑦を参考に。

powershellから、以下のコマンドで生成する。

```sh
ssh-keygen -t rsa
```
Windowsでは、`C:\Users\User1\.ssh`配下に`id_rsa`と`id_rsa.pub`が作られる。

※Linuxの場合は、`/home/user/.ssh/id_rsa`に作られる。


###サーバー側に作成した公開鍵を登録する。
場所は ~/.ssh 直下で、ファイル名は `authorized_keys` とします。このファイルの場所と名前は設定で変更することができますが、特に支障がなければデフォルトのものにしておくことをおすすめします。

公開鍵をアップロードするのがめんどうな場合は公開鍵をクリップボードにコピーして、サーバ側に `authorized_keys` を生成してペーストするという原始的な方法でも可です。


### 接続してみる。

サーバー側のsshdのデーモンを起動。

```
sudo /etc/init.d/ssh start
```

エラーが発生


```
sshd: no hostkeys available -- exiting. sshd
```

ホストキーがないと。。

以下のコマンドで解決

```
sudo ssh-keygen -A
```
ssh-keygenのオプション
-A	ホスト鍵（/etc/ssh/ssh_host_key、/etc/ssh/ssh_host_dsa_key）を生成する（root権限が必要）


これでsshdのデーモンが起動したので、SSHクライアントから接続を試みる。

秘密鍵を用いて、接続できた。