OmniAICreator/Qiita-1.07M huggingface dataset:
ログイン機能例

```
<?php

try
{

$post=sanitize($_POST);
$staff_code=$post['code'];
$staff_pass=$post['pass'];

$staff_pass= md5($staff_pass);

$dsn = 'mysql:dbname=hoge;host=localhost;charset=utf8';
$user='root';
$password='';
$dbh = new PDO($dsn, $user, $password);
$dbh->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);

$sql = 'SELECT name FROM mst_staff WHERE code=? AND password=?';
$stmt = $dbh->prepare($sql);
$data[]=$staff_code;
$data[]=$staff_pass;
$stmt->execute($data);

$dbh =null;

$rec = $stmt->fetch(PDO::FETCH_ASSOC);

if($rec==false)
{
  print 'スタッフコードかパスワードが間違っています。<br/>';
  print '<a href="staff_login.html">戻る</a>';
}
else
{
  // $recがtrueであればログイン成功です
  session_start();
  $_SESSION['login']=1;
  $_SESSION['staff_code']=$staff_code;
  $_SESSION['staff_name']=$rec['name'];
  header('Location: staff_top.php');
  exit();
}
}
catch(Exception $e)
{
  print 'ただいま障害により大変ご迷惑をお掛けしております。';
  exit();
}

?>
```
Twitterのリスト内ツイートを取得する際の`slug`の確認方法

TwitterのリストをAPIで使用する際、例えば`ninomiyt`アカウントの`sample`リストを取得する際、以前は素直に以下のようなコードを書けば取得できました。

node.jsの[twitterライブラリ](https://www.npmjs.com/package/twitter)で書いていますが、他の言語でも概ね似たコードになると思います。

```javascript
const response = await client.get("lists/statuses", {
    "owner_screen_name": "ninomiyt",
    "slug": "sample",
    "count": 100,
});
```


<img width="360" alt="スクリーンキャプチャ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127762/988ad06d-e63d-76f6-73a7-8e11af297441.png">


しかし、現在は新規作成したリストは、slugが作成した名前そのものではなく、`名前-数値`という値がセットされるようです。以下のようなコードで、`lists/list`を使って取得して確かめてください。

```javascript
const result = await client.get("lists/list", {
    "screen_name": "ninomiyt" // あなたのアカウント名に書き換えてね！
});
console.log(result);
```
【Python】csv・txtファイルの行データを読み込み、リストに1次元配列として格納する




![csv・txtファイルの行データを読み込み、リストに格納する.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695597/19934027-e810-3a76-ef5f-2fa517610e4f.gif)


読み込んだ行データをリストに格納する作業がよくあったので、関数化して実装していきたいと思います。

## 実装
Python 3.7.6

- txtファイル

```:txt
Apple
Grape
Orange
Melon
Peach
```
- CSVファイル

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695597/94d25411-28ce-1e62-898b-8a18fcb839eb.png" width=50%>



引数にtxtかcsvのfileパスを指定すると、読み込んだデータをリストとして返します。

```python
import csv 
import itertools # 2次元配列=>1次元配列にするため


TEXT_FILE = 'sample.txt'
CSV_FILE = 'sample.csv'

def read_txtfile_as_list(filePath=None):
    """ 
    テキストファイルを読み込み、リストとして返します。

    Parameters
    ----------
    filePath : str

    Returns
    -------
    item_list : list of str
    """
    with open(filePath, 'r') as f:
        text_data = [line.strip() for line in f]
    return text_data

def read_csvfie_as_list(filePath=None):
    """ 
    CSVファイルを読み込み、リストとして返します。

    Parameters
    ----------
    filePath : str 

    Returns
    -------
    item_list : list of str
    """
    with open(filePath, 'r') as f:
        csv_data =  [line for line in csv.reader(f)]
    # return sum(csv_data, []) 簡易的な書き方 こっちだと処理が遅い
    return list(itertools.chain.from_iterable(csv_data))

def read_file_as_list(filePath=None):
    """ 
    テキストファイルかCSVファイルを読み込み、リストとして返します。

    Parameters
    ----------
    filePath : str

    Returns
    -------
    item_list : list of str
    """
    if filePath[-4:] == '.txt':
        with open(filePath, 'r') as f:
            text_data = [line.strip() for line in f]
        return text_data
    elif filePath[-4:] == '.csv':
        with open(filePath, 'r') as f:
            csv_data =  [line for line in csv.reader(f)]
            return list(itertools.chain.from_iterable(csv_data))
    else:
        return None


# テキストファイルの中身を表示
text_samp1 = read_txtfile_as_list(TEXT_FILE)
print(text_samp1)

# OUTPUT: ['Apple', 'Grape', 'Orange', 'Melon', 'Peach']

# CSVファイルの中身を表示
csv_samp1 = read_csvfie_as_list(CSV_FILE)
print(csv_samp1)

# OUTPUT: ['dog', 'cat', 'cow', 'fox', 'monkey']

# テキスト・CSVファイルの中身を表示
text_samp2 = read_file_as_list(TEXT_FILE)
csv_samp2 = read_file_as_list(CSV_FILE)

print(text_samp2)
print(csv_samp2)

# OUTPUT: ['Apple', 'Grape', 'Orange', 'Melon', 'Peach']
# OUTPUT: ['dog', 'cat', 'cow', 'fox', 'monkey']
```

書いている途中で行データだけを読み込むのであれば、標準の`readlines`メソッドで読み込めるので、csvライブラリをインポートする必要性はなかったなーと思ったのですが、今後、csvファイルの中身をリストにする機会があるかもしれないと思ったので、一応、残しておきます。
python3でyamlファイルを読み込む

yamlファイルは、設定ファイルに使われることが多いようです。

```yaml:config.yaml
hyperparameterA:
  name: 'ModelName_AAA'
  param1: 1
  param2: 2
hyperparameterB:
  name: 'ModelName_BBB'
  param1: 3
  param2: 4
```

```python:test.py
import yaml

with open('config.yml', 'r') as yml:
    config = yaml.safe_load(yml)

print('--- A ---')
print('name: ', config['hyperparameterA']['name'])
print('param1: ', config['hyperparameterA']['param1'])
print('param2: ', config['hyperparameterA']['param2'])
print('--- B ---')
print('name: ', config['hyperparameterB']['name'])
print('param1: ', config['hyperparameterB']['param1'])
print('param2: ', config['hyperparameterB']['param2'])
```

実行

```shell
$ python3 test.py
--- A ---
name:  ModelName_AAA
param1:  1
param2:  2
--- B ---
name:  ModelName_BBB
param1:  3
param2:  4
```

# `YAMLLoadWarning: calling yaml.load() without Loader=... is deprecated, as the default Loader is unsafe. Please read https://msg.pyyaml.org/load for full details.`

`yaml.load(yml)`を使うとwarningが出る。

```python:test.py
import yaml

with open('config.yml', 'r') as yml:
    config = yaml.load(yml)

print('--- A ---')
print('name: ', config['hyperparameterA']['name'])
print('param1: ', config['hyperparameterA']['param1'])
print('param2: ', config['hyperparameterA']['param2'])
print('--- B ---')
print('name: ', config['hyperparameterB']['name'])
print('param1: ', config['hyperparameterB']['param1'])
print('param2: ', config['hyperparameterB']['param2'])
```

```shell
$ python3 test.py
YAMLLoadWarning: calling yaml.load() without Loader=... is deprecated, as the default Loader is unsafe. Please read https://msg.pyyaml.org/load for full details.
```

``yaml.safe_load(yml)``もしくは、`yaml.load(yml, Loader=yaml.SafeLoader)`を使うとwarningが出なくなる。

# 参考
[Pythonで設定ファイルを読み込んでみる（YAMLファイル）](https://techblog.recochoku.jp/2234)
[【後編】YAMLを使ってPyTorchのOptimizerのパラメータ管理をすごく簡単にする方法](https://rightcode.co.jp/blog/information-technology/pytorch-yaml-optimizer-parameter-management-simple-method-complete#YAML_Optimizer)
[pythonでyamlの扱い](https://qiita.com/dustingu/items/1d19aee73ff6e5135b73)
[Java]StringBuilder、StringBuffer、プラス演算子、concat、joinによる文字列結合の処理速度比較

文字列を結合する方法は色々あるけど「StringBuilder」か「StringBuffer」が推奨されているみたいなので、「StringBuilder」と「StringBuffer」とそれ以外でどのくらい処理速度が違うのか比較してみた。
比較したのは「StringBuilder」「StringBuffer」「プラス演算子」「concat」「join」で、"1"から"10000"までを文字列結合したときの処理速度を比較してみた。

結果から見てみると、

|StringBuilder|StringBuffer|プラス演算子|concat|join|
|:--:|:--:|:--:|:--:|:--:|
|2ms|3ms|208ms|102ms|8ms|

となり、ほぼ予想通りでStringBuilderとStringBufferがダントツで早くプラス演算子とconcatが遅かったが、Listに詰める処理とか入ってるjoinが思いのほか早かった。
また、測定した各結合処理のコードは以下の通り。

```java:StringBuilder.java
public static void main(String[] args) {
	String st = "";
	long startTime = System.currentTimeMillis();
	StringBuilder sbi = new StringBuilder();
	for(int i = 0; i < 10000; i++) {
		sbi.append(String.valueOf(i+1));
	}
	st = sbi.toString();
	long endTime = System.currentTimeMillis();
	System.out.println("文字列長さ：" +  st.length());
	System.out.println("処理時間：" +  (endTime - startTime) + "ms");
}
```
```java:StringBuffer.java
public static void main(String[] args) {
	String st = "";
	long startTime = System.currentTimeMillis();
	StringBuffer sbf = new StringBuffer();
	for(int i = 0; i < 10000; i++) {
		sbf.append(String.valueOf(i+1));
	}
	st = sbf.toString();
	long endTime = System.currentTimeMillis();
	System.out.println("文字列長さ：" +  st.length());
	System.out.println("処理時間：" +  (endTime - startTime) + "ms");
}
```
```java:StringPlus.java
public static void main(String[] args) {
	String st = "";
	long startTime = System.currentTimeMillis();
	for(int i = 0; i < 10000; i++) {
		st = st + String.valueOf(i+1);
	}
	long endTime = System.currentTimeMillis();
	System.out.println("文字列長さ：" +  st.length());
	System.out.println("処理時間：" +  (endTime - startTime) + "ms");
}
```
```java:StringConcat.java
public static void main(String[] args) {
	String st = "";
	long startTime = System.currentTimeMillis();
	for(int i = 0; i < 10000; i++) {
		st = st.concat(String.valueOf(i+1)) ;
	}
	long endTime = System.currentTimeMillis();
	System.out.println("文字列長さ：" +  st.length());
	System.out.println("処理時間：" +  (endTime - startTime) + "ms");
}
```
```java:StringJoin.java
public static void main(String[] args) {
	String st = "";
	long startTime = System.currentTimeMillis();
	List<String> list = new ArrayList<String>();
	for(int i = 0; i < 10000; i++) {
		list.add(String.valueOf(i+1));
	}
	st = String.join("", list);
	long endTime = System.currentTimeMillis();
	System.out.println("文字列長さ：" +  st.length());
	System.out.println("処理時間：" +  (endTime - startTime) + "ms");
}
```
【Rails】form_withの使い分け

#はじめに
はじめまして。元ものづくりエンジニアのまついです。独学でRailsを勉強している初学者です。
私と同じようなRails初学者の方でもわかりやすいように、そして私自身の備忘録として記事をアウトプットしていきたいと思います。

#もくじ

 1. form_withとは？　form_tag, form_forとの違いは？
 2. form_withの使い方
 3. URL指定の場合
 4. モデル指定の場合
 5. まとめ

#1. form_withとは？　form_tag, form_forとの違いは？
まずform_with、form_tag、form_forヘルパーとは__Railsで使用されるフォームを生成するヘルパーのことです。__ヘルパーとはRails内であらかじめ用意されたメソッドのことです。特にform_withはRailsアプリのviewを作成するときに必ずと言っていいほどでてきます。
ではこれら３つのヘルパーの違いは？というと、

 - __form_tagはモデルと関係しないフォームの生成。__
 - __form_forはモデルのオブジェクトなどに送信したりするフォームの生成。__
 - __form_withは上記２つの機能を統合したもの。__

となります。form_tag、form_forはRails5.1以降非推奨となっており、form_withが推奨となっています。
なのでここではform_withについて書いていこうと思います。

#2. form_withの使い方
form_withの使い方は

```

<%= form_with(モデル or スコープ or URL [, オプション]) do |f| %>
  <%= f.label :name, '名前' %>
  <%= f.text_field :name %>
  <%= f.submit "送信" %>
<% end %>

```

となります。


__参考：__[form_with | Railsドキュメント](https://railsdoc.com/page/form_with)


#3. URL指定の場合
URLを指定したい場合は、pathを指定してあげます。

```

<%= form_with url: users_path do |form| %>
  <%= form.label :email %>
  <%= form.text_field :email %>
  <%= form.submit %>
<% end %>

```

デフォルトではPOSTメソッドで入力された値が送られます。GETメソッドを使用したい場合はオプションでmethod:を:getに指定すればできます。特に検索フォームを生成する場合にGETメソッドを使用します。

#4. モデル指定の場合
モデルを指定したい場合は

```

<%= form_with model: @user do |form| %>
  <%= form.label :email %>
  <%= form.text_field :email %>
  <%= form.submit %>
<% end %>

```

のように受け渡したいインスタンスを指定します。
例えば、newアクションでsubmit（登録のボタンをクリック）されるとcreateアクションが呼び出されます。editアクションでsubmitされるとupdateアクションが呼び出されます。

#5. まとめ
form_withの代表的な使い方についてまとめました。

- __form_withはフォーム要素を生成するヘルパー。__
- __URLを指定したい場合はpathを指定することで、デフォルトではPOSTメソッドが実行される。__
- __モデルを指定したい場合はコントローラーで生成したインスタンスを指定する。__

以上になります。お役に立てれば幸いです。
[rails]突然自動デプロイが反映されなくなった




#何が起きたのか


よくわかりませんが、調べたところEC2に問題があった
自動デプロイしてたら突然変更が反映されなくなった



#解決方法

よくわかりませんが突如起こった出来事ですので
とりあえずAWSのマネジメントコンソールにログインしてEC2インスタンスを再起動
再起動後は以下のコマンドでNginxとdbを起動。

```
$ sudo service nginx start　
$ sudo systemctl restart mariadb 

```

その後 自動デプロイする　完　（勝手にunicornは起動されるであろう )

```
bundle exec cap production deploy
```


#補足
###EC2に問題がある場合の確認すべきところ


基本的に以下のどれかがどうにかこうにかなっていることが多い説
( unicorn,db,nginx...)

なのでエラーログみてもよくわからなかったらコマンドでいろいろ確認してみよう


```
データーベースの状態を確認
sudo systemctl status mariadb 
```
```
データーベースの起動
 sudo systemctl restart mariadb 
```


```
nginxの再起動
sudo systemctl restart nginx
```


```
unicornの状態確認
ps aux | grep unicorn
```


```
unicornの起動
RAILS_SERVE_STATIC_FILES=1 unicorn_rails -c config/unicorn.rb -E production -D
```
webkitSpeechRecognition の型定義の書き方

keyword: vendor prefix, ベンダープレフィックス

型定義ファイル書くの慣れてなくてちょっと迷ったので記録。
webkit接頭辞がないと使えないが、webkit付きだと型定義が存在しないようなSpeechRecognitionなどは以下を書くことで型が通る。

```typescript
declare const webkitSpeechRecognition: typeof SpeechRecognition
declare const webkitSpeechGrammarList: typeof SpeechGrammarList
```
【Swift】varとletの違い

# Swiftにおける var と let の違い。

var と let の違いについてご存知でしょうか？
プログラミングを始めたばかりの時に違いがよくわからなかったのでメモとして共有します。

まず始めに、var は**変数**、let は**定数**と呼ばれているので覚えてください。

変数はその名の通り、変化する数です。
定数もその名の通り、定まっている数です。

これを頭に入れておけばもう var と let のどちらを使えばいいの？と悩むことはありません。

##変数(var) と 定数(let) 

変数と定数は、値の**一時保存**に使います。
ある処理の結果を変数や定数に保存すると、後続の処理でその結果を再利用できます。

一時保存ということは、
**アプリをタスクキルすると変数や定数の中身の情報が失われるということです。**

もちろん永久保存する方法もありますが、
それに関しては発信できるほどの知識がついたら共有します。

では、一時保存で役に立つのかというと、
簡単なコードですが下記のような使用方法などがございます。

```swift

var a: Int
a = 1 + 1    // a の中には 1 + 1 の結果が"代入"されている

var b: Int
b = a + 10   // b の中には a + 10 の結果が"代入"されている
```

一時保存することにより、別のところで変数を使用することができるようになります。

また、上記のコードで強調したのですが、変数や定数に値を入れることを**代入**と言います。

変数と定数の違いは代入できる回数にあり、
変数には何度も代入できますが、定数には一度しか代入することができません。

定数に二度目の代入を行うとコンパイルエラーが発生します。

```swift

var a: Int    //変数なので何度も代入できる
a = 1
a = 2
a = 100

let b: Int    //定数なので一度しか代入できない
b = 10        //1回目
b = 100       //2回目 コンパイルエラー発生！
```

名前やメールアドレスなどは、
不用意な変更はされたくないので定数に入れる方がいいかもしれませんね！

この様に、変数と定数を使い分けることが
安全で可読性の高いプログラムの実現に繋がります。

##変数や定数に対する代入

変数や定数に代入可能な値は、変数や定数の型と一致しているもののみになります。

Int型の変数に対してはInt型、つまり整数しか代入することはできませんし、
String型の変数に対してはString型、つまり文字列しか代入することができません。

型以外の値を代入しようとするとコンパイルエラーになります。

```swift

var a: Int   //Int型
a = 100      //エラーなし

var b: Int   //Int型
b = "Hello"  //Int型にString型を代入しようとしているのでコンパイルエラーが発生
```

このように、変数や定数に対する代入は値の型に注意してください。

また、変数 a を宣言し a に100を代入しましたが、これを一度に済ませることもできます。
さらには、前回の記事に記載した、型推論による簡潔な記述も可能です。

```swift

var a: Int = 100
let b: String = "Hello"

var c = 10       //変数cの値が10なのでInt型だと推論してくれる
let d = "World"  //変数dの値がWorldなのでString型だと推論してくれる
```

##変数・定数の型の確認方法

変数や定数に代入する際のルールや型推論については理解できましたが、
肝心の型がわからなくなった場合にどうすればいいのだろうかと当時は疑問に思ったので、
それに関しても記載しておきます。

まず、前提として、
**型が分かりにくくなるような変数名はつけないようにする。**というのが大事かと思います。

例：name
-> name は名前とかだからString型かな？ となんとなく分かる
例：book
-> book は本だからString型？ でも本のページ数とか、本の重さもある・・・。

というふうになるので、
bookName(本の名前)、bookWeight(本の重さ)など分かる変数名にする方がいい。

では、他人が書いたコードでよくわからない場合はどうすればいいか
方法としては、
1. エラーコードを読んで判断する
2. type(of:)関数を利用する
のどちらかだと思います。

エラーコードは、Google翻訳などで読み解いてください・・・。

type(of:)関数は下記のように使用します

```swift

let a = 100   
type(of: a)  // Int

print(type(of: a))  //ログに出力したい場合
```
型が分かってしまえば、こちらのものですね！
スラスラとコードを書いていきましょう。

ですが、何よりも大事なのは、
誰が見ても分かるようなコードを書くようにすることだなと、この記事を書いていて思いました。

以上、ありがとうございました。
マルチブートUSBの作成方法

##前提
UEFIによるブートです。レガシーBIOSには対応しません。
すべてのディスクボリュームのフォーマットはFAT32です。

##準備
各種isoファイルを用意します。
最近のisoイメージはUEFIに対応していることが多い。
isoイメージに次のディレクトリとファイルがあることを確認すれば良い。

/EFI/BOOT
・x86 (32bit)
 BOOTx86.efi または BOOTia32.efi

・x86_64 (64bit)
 BOOTx64.efi

###確認済みのOSのiso
・Windows10
・Ubuntu18.04, Ubuntu20.04
・CentOS8

##作成方法
###1.USBメディアのフォーマット
・対象のUSBメディアをPCにセットする
・一度、すべてのボリュームを削除してから、それぞれのisoイメージに必要なサイズで、ボリュームを作成していく。
・フォーマットは必ずFAT32で行う。（EFIの要件）
・パーティション構成はMBRでもGPTでも問題なし。
(５つ以上のパーティションにはGPTが必要)

###2.isoイメージの書き込み
・isoをマウントする。
・マウントされたドライブを開き、中身をすべてコピーしてUSBメディアへとコピーする。
・必要なiso分を順番にコピーすれば良い。
・ここで単純にファイルコピーすることがポイント。ddコマンドなどを使ってはいけない。
・注意！隠しフォルダ、ファイルもコピーすること。
・既知の懸念：シンボリックリンクはコピーできない(FAT32が対応していない)。
　そのため、これが原因で不具合が発生する恐れがある。（2020/11/30現在は未確認）

###3.起動について
・UEFIブートのためにPC起動時に「F12」や「F11」を連打して、BIOSのブートマネージャを起動する。
・ブートマネージャで、起動したいパーティションを選択すれば良い。

##補足
###Windowsの場合の補足
####USBのフォーマット
・ディスクの管理(diskmgmt.msc)でUSBメディアのフォーマットを行う
・ボリュームの削除と作成ができる。
・パーティションの種類(MBR/GPT)の変更は、別途アプリが要る。

####isoのマウント
・エクスプローラーからisoファイルを右クリックして「マウント」ができる。
・マウントしたドライブから中身をコピーすれば良い。

###Linux(Ubuntu)の場合の補足
・USBメディアのフォーマットは、GPartedかディスクの管理で行う。
・LinuxならGPT/MBRのパーティション作成が可能。

##補足2
###32bitについて
・上記の方法では32bit版のインストールメディアは作成できない。
これはUEFIの場合、64bitのみ起動できると考えて良い。→厳密には異なる。（一部の例外があるみたい）
・32bitの起動には、BIOSの設定を変更しレガシーBIOS(MBR)での起動が必要。
HTML・ブラウザとはなにか

# はじめに
今回は前回の記事[Webの概要について丁寧に](https://qiita.com/anago1030/items/0e2ab1c9af29615a3881)の続きでWeb技術の基本について更に知識を深めたいと思います。

今回の内容は

* HTMLとWebブラウザ

以上のキーワードについて説明したいと思います。

## この記事のゴール

* HTML、ブラウザの言葉の意味を理解する

## 目次
[1.世界共通言語のHTMLと人に優しいWebブラウザ](#1-世界共通言語のHTMLと人に優しいWebブラウザ)
[2.まとめ](#2-まとめ)

## 1. 世界共通言語のHTMLと人に優しいWebブラウザ
前回の記事でWebページは**ハイパーテキスト**という言語で作られているというお話をしました。
このハイパーテキストの正体が実は**HTML(Hyper Text Markup Language)**なのです。

HTMLでは**タグ**というマークを使って文章に意味づけをしていきます。
具体的には下記の通りに記述します。
↓
ルール：「〈開始タグ〉文章〈/終了タグ〉」
具体例：「〈title〉Web技術の基本〈/title〉」

上のルールのように開始タグと終了タグで文章をはさむと意味づけをすることができます具体例では、このページのタイトルは「Web技術の基本」であることを意味します。
もちろんこれだけではイメージがつかないと思いますので、ここでは他に見出しタグの紹介をしてきたいと思います！

### 1-1. 見出しタグの紹介
文章には必ずある大見出しは**h1**というタグで表します。
下の例でも、開始タグと終了タグで文章をはさんでいますね！

```sample.html
<h1>これは大見出しです</h1>
```

また、見出しの大きさを段階的に変えることもできます。
現在のHTMLの仕様では6段階まで設定可能です！

```sample.html
<h1>これは大見出しです</h1>
<h2>これは見出しです</h2>
<h3>これは見出しです</h3>
<h4>これは見出しです</h4>
<h5>これは見出しです</h5>
<h6>これは見出しです</h6>
```

実際には下のように画面に表示されます
# これは大見出しです
## これは見出しです
### これは見出しです
#### これは見出しです
##### これは見出しです
###### これは見出しです

他にも画像を表示させる**imgタグ**やリンクを貼るための**aタグ**など種類がたくさんあります。
このようにタグによって文章に意味づけをしながら記述をしていくのがHTMLです。

### 1-2. 人に優しいWebブラウザ
HTMLつまり、ハイパーテキストで書かれた文章は先程説明した通り、タグによって意味づけされている独自のものなので人間が読むにはあまりにも読みづらいです。

フランス語を知らない日本人がフランス人に話しかられても意味が理解できない状況と同じです
そこで登場するのが**Webブラウザ**という翻訳家です。
Webブラウザは人間が理解しやすいようにハイパーテキストを翻訳してくれるプログラムのことなんです！

Webブラウザには種類がいくつかあって、一般に使われているものだと
**Google Chrome**や**Safari**、**Internet Explorer**、**Firefox**などが挙げられます。

Webブラウザの種類によって情報の表示の方法に多少の違いがあるのですが
HTMLは世界共通言語なので、基本的にはどのブラウザでも同じように情報を表示させる事ができるというわけです。

## 2. まとめ
Webページを構成するHTMLとそれを人間が理解できるように解釈してくれるWebブラウザについて理解が深められたでしょうか。
次回はWebページがどのようにして表示されるかその一連の流れについてまとめたいと思います！

* Webページは**HTML**で記述される
* HTMLは**タグ**によって文章に意味づけをしていく
* HTMLを人間にわかりやすいよに翻訳してくれるプログラムが**Webブラウザ**である

以上です！最後まで読んでいただきありがとうございます。
お疲れ様でした。。

## 参考文献
[Web技術の基本](https://www.amazon.co.jp/%E3%82%A4%E3%83%A9%E3%82%B9%E3%83%88%E5%9B%B3%E8%A7%A3%E5%BC%8F-%E3%81%93%E3%81%AE%E4%B8%80%E5%86%8A%E3%81%A7%E5%85%A8%E9%83%A8%E3%82%8F%E3%81%8B%E3%82%8BWeb%E6%8A%80%E8%A1%93%E3%81%AE%E5%9F%BA%E6%9C%AC-%E5%B0%8F%E6%9E%97-%E6%81%AD%E5%B9%B3-ebook/dp/B06XNMMC9S/ref=sr_1_1?adgrpid=81750527692&dchild=1&gclid=Cj0KCQiAh4j-BRCsARIsAGeV12AQKCnmQPR0NDvYlyM_lvHA8CvoeNVHelAAgZFeerL4p4N-od6fYNEaAtOIEALw_wcB&hvadid=367948451666&hvdev=c&hvlocphy=1009332&hvnetw=g&hvqmt=e&hvrand=1747466046873707566&hvtargid=kwd-811307210612&hydadcr=2964_10317926&jp-ad-ap=0&keywords=web%E6%8A%80%E8%A1%93%E3%81%AE%E5%9F%BA%E6%9C%AC&qid=1606559011&sr=8-1&tag=googhydr-22)
curlの"-u"オプションで引き渡される認証情報をヘッダーに直接設定したい

先日プロダクトのアップデートを管理しているJenkinsサーバに対して新たにAPIを送るよう実装する機会があり、その際にインフラチームから共有いただいたAPIの呼び出し方法が下記のようなものでした。  

```
curl -k -X GET "https://hogehoge.jp/job
?token=${api_job_token}" -u ${api_user_name}:${api_user_token}
```  
  
#### "-u"オプションって？  
> Specify the user name and password to use for server authentication. Overrides -n, --netrc and --netrc-optional.
If you simply specify the user name, curl will prompt for a password.  
  
参照：https://curl.se/docs/manpage.html#-u  
  
curl先のサーバーで行われる認証に対し、ユーザ名とパスワードを引き渡しているオプションが`-u`オプションになります。  
  
  
#### "curl"経由じゃなくて直接ヘッダーに認証情報を設定したい。。。  
今回のケースでは`curl`からではなくて、ヘッダーなどのリクエスト内容を直接規定する方法でJenkinsAPIへリクエストを送る必要がありました。下記のようにすることで、`-u`オプションを利用して設定されるBasic認証情報をヘッダに設定することができます。(利用言語はPHP7.3)  

```php
private static function createHttpRequestForJenkins(): HttpRequest {
    // Basic認証情報を設定
    $encoded_user_info = base64_encode('user_name:password');
    $request_header = [
        'Content-type'  => 'application/json',
        'Authorization' => "Basic $encoded_user_info",
    ];
    ......
}
```
 
Basic認証では引き渡すユーザ名とパスワードはbase64形式でエンコードされる必要があるため、`base64_encode`を使って認証情報を設定します。
エンコード済みの認証情報をヘッダーの`Authorization`要素として指定をすることで、リクエスト先サーバにBasic認証情報を送信することができます。その際、エンコードされた情報は`Basic+半角空白`を接頭辞として持つ必要があります。
参照：https://ja.wikipedia.org/wiki/Basic%E8%AA%8D%E8%A8%BC

上記のままでもリクエストを送る上では問題ないのですが、`createHttpRequestForJenkins`ではリクエストを送ることだけ知っていて欲しかったので、最終的には下記のようにして実装を行いました（メソッドの実装内容は割愛します）。

```php
private static function createHttpRequestForJenkins(): HttpRequest {
    $request_header = ApiRequestHeader::createContentTypeApplicationJsonHeader()
    // basic認証情報を設定
    ->withBasicAuth('user_name', 'password');
    ......
}
```

#### まとめ
`curl -u`はシンプルに認証情報をヘッダーに設定できる便利なオプションですが、いざ自分で同様の情報をヘッダーに設定する際に"?"となってしまったのでまとめてみました。どなたかのお役に立てば幸いです。
コードレビューで指摘された点( ※随時更新)

現場の先輩にて、指摘された点をまとめていく

##目的
- 同じことをくりかえさない → 先輩もタスクを持っていてる。毎回同じことを指摘していては双方にメリットがない
- 技術力向上のため → 私自身の仕事をすすめるスピードを上げることで、会社にとっても利益をもたらす
- 後輩等ができた際に、実際に教えることができる

##実際に指摘された点
- テスト(Rspec)にて、必要なデータが作成されていない
- テストにて、使用されていないデータが作成されている → DRYなコードではない
タグ振り分け機能の実装

# はじめに

今回は、zipang（漢字、ひらがな、カタカナをローマ字に変換するもの）というgemを用いてタグを頭文字ごとに0~9、A~Zに振り分けて索引のようなものになるよう実装いたしました。その際、予め ancestry を用いて親カテゴリーとして0～9、A～Zをデータに保存するseedを作成しております。
<img width="239" alt="スクリーンショット 2020-06-24 20.57.21.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/616088/15342804-efff-6c56-d1eb-feb188e8c44d.png">

# 機能の実行順序

大まかな流れといたしましては、

#### ① タグを入力する

#### ②　入力されたタグをzipangでローマ字に変換
#### ③　変換した文字の頭文字を取得し、その頭文字を親としてタグをその子要素に保存する。（タグのテーブルにはancestryを用いているので、知らない方は検索してみてください）
#### ②③の流れをメソッドでまとめると以下の通りになります。（このメソッドはbefore_saveにて実行しております。）
```ruby
  def find_or_create_tag
    self.tags = self.tags.map do |tag|
      word = Zipang.to_slug tag[:name]
      parent = Tag.find_by( ancestry: nil, name: word[0].upcase )
      parent.children.find_or_create_by(name: tag.name)
    end
  end
```

#### ④　表示する際は、頭文字の子要素として出力する。

以上のことを応用すると、あいうえお順に振り分けることもできるかと思います。
ECSコンテナに接続する方法

#意外と忘れるコンテナ接続
本番環境のコンテナに入ってDB操作したりデバッグしたり...

久しぶりにやろうとしたらど忘れしていたのでこの記事を書くに至りました。

#接続までの手順

- セキュリティーグループの**インバウンドルール**変更
- EC2インスタンスの**Public IP** / **Public DNS**を確認
- ```ssh -i /path/to/my-key-pair.pem ec2-user@ec2-198-51-100-1.compute-1.amazonaws.com```コマンドでECSコンテナにssh接続

#それでは始めます
##インバウンドルールの変更

```EC2``` > ```セキュリティーグループ``` > ```該当のセキュリティーグループ``` > ```インバウンドルールを編集```


```ssh```タイプの```ソース```を「 マイIP 」に変更する

この変更をしていないと後でssh接続したとき以下のエラーが出るため必要な手順です

```
ssh: connect to host [自分のPublic IP] port 22: Connection refused
```

##Public IP / Public DNSを確認

```Elastic Container Service``` > ```クラスター``` > ```ECSインスタンス```
```コンテナインスタンス``` > 該当のインスタンスを選択

```詳細``` > 「 Public DNS 」をコピーする

##ECSコンテナにssh接続

以下のコマンドを使用します

```
$ ssh -i /path/to/my-key-pair.pem ec2-user@ec2-198-51-100-1.compute-1.amazonaws.com
```

**キーペア**はパスを指定する必要があります。
例えば私は```~/.ssh```下に配置しているので下記のように指定します

```
$ ssh -i ~/.ssh/my-key-pair.pem
```
次に前の手順でコピーしていた**Public DNS**をその後に書いてあげましょう

##接続するとき
以下のような表示が出ますが落ち着いて読みましょう

```
Are you sure you want to continue connecting (yes/no/[fingerprint])?
```

「 yes 」で大丈夫です。

その後はこのような表示が出ましたでしょうか。

```

   __|  __|  __|
   _|  (   \__ \   Amazon Linux 2 (ECS Optimized)
 ____|\___|____/
```

#お疲れさまでした
ここまで読んでいただきありがとうございました。

簡単な手順ではありますが、久しぶりにやると忘れているものです。

#参考

[https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/instance-connect.html](公式)
NimでSDL2 ② 画像を表示

#はじめに
① [NimでSDL2 ① 準備とウィンドウ表示](https://qiita.com/bucho666/items/afa37af16744a99b199e)

前回ウィンドウを表示したので、今回は画像を読み込んで表示してみる。

#概要

1. sdl2/imageをimportする。
2. SDL2初期化時にINIT_VIDEOフラグを立てて初期化する。
1. image.initに資料する画像タイプを指定して初期化する(今回はpngを使用する)
1. [createRenderer](# http://sdl2referencejp.osdn.jp/SDL_CreateRenderer.html)関数でWindowからレンダリングコンテキストを作成する。
1. レンダリングコンテキストで背景色を設定
2. レンダリングコンテキストで画像を読み込んでテクスチャを作成する。
3. レンダリングコンテキストでテクスチャの一部、または全体を指定箇所にレンダリングする。
4. レンダリングコンテキストのレンダリング結果をがめんに反映する。

# コード

```nim
import sdl2, sdl2/image, os
const
  WINDOW_W = 640
  WINDOW_H = 480

proc main() =
  if not sdl2.init(INIT_VIDEO): # 画像を扱うのでINIT_VIDEOフラグを立てて初期化
    raise Exception.newException("[ERROR] SDL2 init: " & $getError())
  defer: sdl2.quit()
  let window = createWindow(title = "SDL2 Image Sample",
                            x = SDL_WINDOWPOS_CENTERED,
                            y = SDL_WINDOWPOS_CENTERED,
                            w = 640,
                            h = 480,
                            flags = SDL_WINDOW_SHOWN)
  if window.isNil:
    raise Exception.newException("[ERROR] createWindow: " & $getError())
  defer: window.destroy
  # image初期化
  if image.init(IMG_INIT_PNG) != IMG_INIT_PNG:
    raise Exception.newException("[ERROR] image init: " & $getError())
  # imageクリーンアップ処理
  defer: image.quit()
  # windowからrenderer作成
  let renderer = window.createRenderer(
    index = -1,
    flags = Renderer_Accelerated or Renderer_PresentVsync)
  # renderer作成エラーチェック
  if renderer.isNil:
    raise Exception.newException("[ERROR] createRenderer: " & $getError())
  # rendererクリーンアップ
  defer: renderer.destroy
  # 背景色を設定
  renderer.setDrawColor(r=0, g=128, b=128)
  # rendererを使って画像を読み込んでテクスチャにする
  let neko = renderer.loadTexture("genbaneko.png")
  # 画像読み込みエラーチェック
  if neko.isNil:
    raise Exception.newException("[ERROR] loadTexture: " & $getError())
  # 画面初期化
  renderer.clear
  # 描画するサイズ
  let
    w: cint = 256 # 描画する画像の幅
    h: cint = 256 # 描画する画像の高さ
  # 描画先のRectを作成（画面の真ん中に描画）
  var dst = rect(cint(WINDOW_W/2 - w/2), cint(WINDOW_H/2 - h/2), w, h)
  # レンダリング(描画元はnilを指定しているので画像全体を描画)
  renderer.copyEx(neko, nil, dst.addr, 0.0, nil, SDL_FLIP_NONE)
  # レンダリング結果を画面に反映
  renderer.present
  var done = false
  while not done:
    var event = defaultEvent
    while pollEvent(event):
      case event.kind:
      of QuitEvent:
        done = true
      else:
        discard
    sleep(100)

main()
```

# 結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268503/9ba6d825-204b-74d0-fcf0-5e9898dd2f39.png)

# 次は？
キーボード入力とかしてみたいですね。

以上〜。
初学者が「とりあえずturbolinks消す」に抗ってみた

PF作成において、これまでJS関連でエラーが起きたらとりあえず消してきた
「turbolinks」と何とか仲良くなりたいと思い、実装した内容を備忘録として記述します。

#概要

そもそも、turbolinksとは何なのか？

https://coffeecups.blue/turbolinks/

こちらの記事が参考になりますが、本当に簡潔に言ってしまえば、
ページ推移を高速にする機能、と言えます。rails4以降は標準装備されているようです。

一方で、使うことによるデメリットも多く、私が勉強した教材の中でもとりあえず作動しないようにしておくという冷待遇を受けていた悲しい機能です。それでも、PF作成において画像が重いページ等もあり、全体的な動作は早い方がよくね？って思ったのでこの度何とか消さずに実装できないか抗ってみました。実際1秒ぐらい違います。

※大前提として、勉強まだ10週間の初学者が作っているPF内でのことなので、動的な機能がてんこ盛りの複雑なアプリではもっと色々設定しなきゃならないと思われます。

#実装

まず、rails6においてturbolinksは

```app/javascript/application.js　

require("turbolinks").start()
```

と記載されています。消したい場合はこれをコメントアウトするわけです。


turbolinksが作動することで起こるデメリット

①JSのイベントハンドラーに修正を加えないと動作しなくなってしまう。
通常使われるload、DOMContentloaded、window.onLoad、等の記述では動作しない。

②戻るボタンでページを戻ろうとすると不具合が生じる。

#解決方法

①イベントハンドラーをturbolinks仕様に変更する。
`
・turbolinks:load　ページの読み込み時
・turbolinks:click　turbolinksが有効なaタグのクリック`

等になります。また、自身の実装では特にライブラリを使用している部分において一部うまく起動しない場合もありました。やむなく、そのページだけturbolinksを作動させない設定をしました。指定したいページのリンク下にdata: {"turbolinks" => false}を記載します。

```<%= link_to '表示名', パス, data: {"turbolinks" => false}%>'
<a data-turbolinks="false" href=""></a>```

②ブラウザバックやプレビュー用のキャッシュを止める
turbolinksで戻るボタンでページ推移すると、描画したものがページ遷移直前にキャッシュされる仕様で二重キャッシュになり動作を妨げます。

`<meta name="turbolinks-cache-control" content="no-cache">`

これでOKです。より詳細に設定するのであれば、turbolinks:before-cacheなどのイベントハンドラーを使いこなし、設定することができるようですが、私の作成しているような静的アプリでは上記で問題ありませんでした。

まだまだ奥が深いturbolinksですが、今後もなるべく冷遇しないように仲良くやっていきたいと思います。
jetson xavier agx セットアップ備忘録


gpu + python + tensorflow
https://qiita.com/yamamo-to/items/51bfb92a00033257f02a


gpu + cuda
https://github.com/NVIDIA/nvidia-docker/wiki/NVIDIA-Container-Runtime-on-Jetson


specify user when docker run
https://qiita.com/comefigo/items/fb435c8c886b470ec07c

cuda test hello world
https://symfoware.blog.fc2.com/blog-entry-2395.html


errors I encountered
ubuntu 18.04 : 'xlocale.h' file not found
https://github.com/carla-simulator/carla/issues/503


python setup.py failed
https://ja.stackoverflow.com/questions/46978/pip-%E3%81%A7%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%82%A8%E3%83%A9%E3%83%BC-command-python-setup-py-egg-info-failed



https://qiita.com/Shunmo17/items/3bfd45ecb5c460bc4bc9#docker%E3%81%AE%E3%83%93%E3%83%AB%E3%83%89

この記事のdockerのビルドの際に

https://proc-cpuinfo.fixstars.com/2019/06/nvidia-sdk-manager-on-docker/

ここにある通りにコンテナを立てようとすると、

xauth not creating .Xauthority file

というエラー。


https://superuser.com/questions/806637/xauth-not-creating-xauthority-file

>X11Forwarding yes
X11DisplayOffset 10
X11UseLocalhost yes


これに従ったのと、
https://stackoverflow.com/questions/37826094/xt-error-cant-open-display-if-using-default-display

これに従った。
VScodeでPHPを書こうとすると右下に表示されるエラーを解消したい

## 環境
* OS 
    * Windous10 Home x64
    
* VScode
    * Version 1.51.1

## 表示されたエラーメッセージ
【 phpcs: Request workspace/configuration failed with message: Unable to locate phpcs. Please add phpcs to your global path or use composer dependency manager to install it in your project locally. 】

## ざっくりした意味
「phpcs」を見つけることができなくて、ワークスペースの構成ができていないよ！
phpcsを自力でインストールするか、「Composer」を利用してインストールしてください。

## 解決するためにやったこと
1. Composer をインストールする
[➤Composerインストール先](https://getcomposer.org/download/)

2. コマンドプロンプトを起動して以下の呪文を入力する

```
composer global require squizlabs/php_codesniffer
```
3.VScodeを再起動する

## 結果
ちゃんとエラーが消えました。

## 参考サイト
[Cocotiie「Visual Studio CodeでPHPエラー」](https://cocotiie.com/visual-studio-error/#Composer)
Rubyで2進数を計算する方法はとても簡単

ruby 2.7.0の記事です

# １０進数を２進数に変換する方法
以下、私の試行錯誤の結果です

- 演算子については、公式リファレンスを参照<br>
- ** で乗じる<br>
<a href="https://docs.ruby-lang.org/ja/latest/class/Numeric.html">公式ドキュメント（Numericクラス）</a>

```ruby
def Binary(num)
 array1 = [] #１になる桁を左から数えた数が入ります　４４の場合（6,4,3） つまり（101100）
  while num > 0
    array2 = [] #2で割った数が入ります
    n_i = num
    while n_i > 0 #整数型は小数点を含まない。1/2=０と出力される（0.5にはならない）
      n_i = n_i / 2
      array2 << n_i
    end
    num = num - (2 ** (array2.length - 1)) #array2.lengthで桁を出します　１０進数に戻して、最初の数から引きます
    array1 << array2.length #1になる桁数を加えます
  end

  i = 1
  b_a = []
  array1[0].times do #array1[0]に桁が入ります。１か０を配列b_aに入力します
    if array1.include?(i)
      b_a << 1
    else
      b_a << 0
    end
    i += 1
  end

  b_a.reverse.each do |s| #配列をprintで連続して表示します
    print s
  end
  print "\n" #printの改行コードを入力
end

puts "２進数にしたい値を入力してください"
num = gets.to_i
Binary(num)
```

以下@kts_hさんのコメントを元に追加

- 整数を進数で出したければ、すごく簡単にできる
- num.to_s(2-36の数値が入る) <br><a href="https://docs.ruby-lang.org/ja/latest/method/Integer/i/inspect.html">公式ドキュメント（Integerクラスinspect)</a>

```ruby
num = 44
num.to_s(2) #=> "101100"

puts "２進数にしたい値を入力してください"
num = gets.to_i # 整数にする 仮に４４と入力した場合
puts Binary = num.to_s(2) #=>101100 文字列として出力

puts "取り出したい桁を入力してください"
n = gets.to_i #例えば６桁目”６”と入力
puts Binary.slice(-n) #今回はn=6となり、”１”が表示される

#メソッドとして定義したい場合
def Binary(num)
 puts num.to_s(2)
end
```

- inspectメソッドを使わず計算式で定義したい場合

- divmodメソッド

divmod(other) -> [Numeric]
self == other * q + r
other > 0 のとき: 0 <= r < other,
other < 0 のとき: other < r <= 0,
q は整数 <br><a href="https://docs.ruby-lang.org/ja/latest/method/Numeric/i/divmod.html">公式ドキュメント（Numericクラスdivmod)</a>

```ruby
11.divmod(3) #=> [3, 2] 公式リファレンスより
```

- reverse!<br>
<a href="https://docs.ruby-lang.org/ja/latest/method/String/i/reverse=21.html">公式ドキュメント（Stringクラスreverse!)</a>
- join<br>
<a href="https://docs.ruby-lang.org/ja/latest/method/Array/i/join.html">公式ドキュメント（Arrayクラスjoin)</a>

```ruby

def Binary(num)
  acc = []
  while num > 0
    num, mod = num.divmod(2) #numには２で割った数が入ります
    acc << mod #2で割った余りを配列に加えます  つまり１or0です
  end
  answer = acc.reverse!.join #accの値をreverse!で逆にする  joinで値を続けて表示する
  puts answer
end
```
REST APIについて

#REST APIとは
Webシステムを外部から利用するためのプログラムの呼び出し規約(API)の種類の一つで、RESTの原則に則って構築されたWebシステムのHTTPでの呼び出しインターフェースのこと。

#RESTとは
REpresentational State Transferの略で、分散型システムにおける複数のソフトウェアを連携させるのに適した設計原則の集合、考え方のこと。

#RESTの原則
主に以下の４つの原則である。

###1.アドレス可能性(Addressability)
提供する情報がURIを通して表現できること。全ての情報はURIで表現される一意なアドレスを持っていること。

###2.ステートレス性(Stateless)
HTTPをベースにしたステートレスなクライアント/サーバプロトコルであること。セッション等の状態管理はせず、やり取りされる情報はそれ自体で完結して解釈できること。

###3.接続性(Connectability)
情報の内部に、別の情報や(その情報の別の)状態へのリンクを含めることができること。

###4.統一インターフェース(Uniform Interface)
情報の操作(取得、作成、更新、削除)は全てHTTPメソッド(GET、POST、PUT、DELETE)を利用すること。

これらの原則はROAの特性と同様である。ROAについては[リソース指向アーキテクチャ(ROA)について](https://qiita.com/KOME_engineer/items/e7c4e4aaae4cc167d002)を参照。

#REST APIのメリット

1. URIに規律が生まれることで、APIを利用するサービス開発者が楽になる
2. URIに規律が生まれることで、API開発者もURIからソースのどの部分なのかが容易にわかる
3. ブラウザのアドレスバーにURIを入力すればリソースが参照できる
4. サーバ、クライアント間で何も共有しないことにより、負荷に応じたスケーラビリティが向上する。ステートレス性に値するもので、一番のメリットされている。
5. GET、POST、PUT、DELETE等のHTTP標準のメソッドを使うことで、シンプルで一貫性のあるリクエスト標準化が円滑に行える。統一インターフェースに値する。
.NET5の簡単なまとめ .NET5リリース記念オンラインイベントに参加しました

# はじめに
[Announcing .NET 5.0 | .NET Blog](https://devblogs.microsoft.com/dotnet/announcing-net-5-0/?WT.mc_id=DT-MVP-5002209)にあるように、.NET5が正式にリリースされました。  

オンラインイベントに参加して.NET5面白いと思ったので、簡単にまとめてみました。
詳しくは公開資料を見た方が良いです！
[【オンライン/開催日決定】.NET 5 リリース記念 C# Tokyo イベント - connpass](https://csharp-tokyo.connpass.com/event/189415/)  

# .NET5 について
- [.NET Core + .NET Framework + XAMARIN/MONO](https://github.com/dotnet/designs/blob/main/accepted/2020/net5/pic01.png)  
.NET5でもWPF, Windows Formsでの開発は引き続き可能。  
.NET Framework 4.8が最終メジャーリリース。それ以降はサポートメインに。  
共通言語ランタイムが異なる。  
.NET Framework: CLR 4.0  
.NET 5: CLR 5.0  
=>C++アプリから呼び出す必要がある場合は.NET Frameworkに残す必要あり。  
- GA(Current)なので、LTSと異なりサポート期間は短い  
GA: GA/LTSがリリースされてから3ヶ月  
LST: 最低3年  
- C#9 F#5へアップデート  
C# 9.0については以下を参照。  
[What's new in C# 9.0 - C# Guide | Microsoft Docs](https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-9)  
[C# 小ネタ：.NET 5.0 で使える C# 9.0 で気に入ってる機能紹介 - Qiita](https://qiita.com/okazuki/items/8043ea6f0095b3019cdf)  
=>Recode typesでimmutableクラスを明示しやすいのはいいかも。  
- null許容参照型のアノテーションを.NETライブラリに導入。  
null許容参照型のアノテーション`string?` でnullを許容する型だと示す。  
- TFMがプラットフォーム共通とOS固有と大きく2つになった  
>ターゲット フレームワーク モニカー (Target Framework Moniker)。  
.NET アプリまたはライブラリのターゲット フレームワークを指定するための標準化されたトークン形式のこと。   
[.NET 用語集 | Microsoft Docs](https://docs.microsoft.com/ja-jp/dotnet/standard/glossary)  
- パフォーマンス改善  
- ARM64対応  
- Windows 10 APIが使いやすくなった  
カメラ、センサー、Windows ML、BLEなどが簡単に使える。  
.NET 5からはTFMの指定のみで呼び出し可能。  
DesktopのアプリやライブラリはUWPのAPIを簡単に参照できるようになった。  

__その他今後注目したいライブラリやツール__
Windows UI Library 3.0 (Preview)
Windows 10のネイティブUIがOS組み込みからOSS＋Nugetパッケージにする。
https://github.com/microsoft/microsoft-ui-xaml

Project Tye
.NETアプリケーションのKubernetesへのデプロイを自動化などマイクロサービス開発が楽になるツール。Preview前。
https://devblogs.microsoft.com/aspnet/introducing-project-tye/

# まとめ
.NET Core と .NET Framework, XMARINが一つになって共通のAPIになって試しやすくなって来るのかなと感じました。
Windows UI Library 3.0は、UIの部品化するということで、Atomic Designの考えを取り入れて部品として使いまわせるようになるのかなと思いましたがどうなんでしょう。
ちょっと試したくなったら以下を参考にDocker環境作ってみようかなと思いました！
[Docker 上でお手軽にC#9（.NET 5）を試す - Qiita](https://qiita.com/Nossa/items/e7a2a380c24c0c92192c)
goの超初心者向けのチュートリアル

近々go言語に触れるかもしれないので、無知の状態からやってみたことの備忘録です。

###前提
・Mac
・とりあえず手っ取り早く動かせる状態にしたい
・go触ったことない

###インストール
公式ページからパッケージをインストールするだけ。
https://golang.org/dl/

Homebrewなどでインストールする方法もあるようですがcliに苦手意識あるので簡単なやり方で。。。
###開発ツール
とりあえずVisualStudioCode
(vscode最強だと思ってる)

以下の拡張機能を追加。
・Go(https://marketplace.visualstudio.com/items?itemName=golang.Go)
※Go Nightlyという拡張機能は入れないほうがいい(goのプレビュー版で併用して動かせないため)

###とりあえずHelloWorld
####公式ページのチュートリアルをやってみる

適当な.goファイルを作って以下の内容を記載

```main.go
package main

import "fmt"

func main()  {
	fmt.Println("Hello,World!")
}
```

ターミナルでファイル実行するとHelloWorld表示される

```
go run main.go
Hello,World!
```

###パッケージの追加
node.jsでいうnode_module的なもの？

```main.go
package main

import "fmt"
import "rsc.io/quote" //追加

func main()  {
	fmt.Println("Hello,World!")
	fmt.Println(quote.Go()) //追加

}

```

ターミナルで以下のコマンドを実行するとgo.modファイル(パッケージ管理ファイル?)とgo.sumファイル(インストール済みのパッケージを記載?)が作られてquoteパッケージの読み込み設定が記載される
(node.jsでいうpackage.jsonですね)

```
go mod init main 
```

```go.mod
module main

go 1.15

require rsc.io/quote v1.5.2

```

再度runコマンドを実行すると追加したquoteがインストールされたっぽい。
npm install を自動で実施してくれた感じですね。

ひとまず初めの一歩を踏み出せるところまでです。
公式チュートリアルはまだ続きがあるので、後日追記する。

###その他やりたいこと
・自動ビルド?のパッケージがあるっぽいのでそいつを導入してみる
・web画面表示したい
vagrant up エラー対処方　備忘録

エラー文：

```
The box 'bento/cento-6.8' could not be found or
could not be accessed in the remote catalog. If this is a private
box on HashiCorp's Vagrant Cloud, please verify you're logged in via
`vagrant login`. Also, please double-check the name. The expanded
URL and error message are shown below:

URL: ["https://vagrantcloud.com/bento/cento-6.8"]
Error: The requested URL returned error: 404 Not Found
```

解消法：
vagrantのバージョンを新しいの（-1.9.6）を利用する
着目ポイント：
**error**という文言のある部分
`The expanded URL and error message are shown below:`である。

意味：
**以下にエラーメッセージとURLを提示するので見てください**という意味です。

よって`The expanded URL and error message are shown below:`の下のURLとメッセージを読む必要があります。
↓↓↓↓

```
URL: ["https://vagrantcloud.com/bento/cento-6.8"]
Error: The requested URL returned error: 404 Not Found

```

意味：
ここのURLのページを見せてとリクエストしたけど、そのURLのページは存在しません

というニュアンスです。
Webエンジニアを目指す初学者が2.5hでWebサイトを公開してみた

【思いつきから始まった】
つい先日、那覇市のオープンデータがある事を知りました。なんとなくサイトを覗いてみた
<a href="https://www.city.naha.okinawa.jp/online/opendata/">オープンデータ | 那覇市公式ホームページ</a>


いくつかあるオープンデータの中から <a href="https://www.city.naha.okinawa.jp/online/opendata/kosodate/472018_preschool.html">子育て施設一覧</a> というデータを見つけて「このデータを活用して人の役に立てないかな？」とふと思いました。

SNSで「那覇の子育て施設一覧が分かるWebサイトあったらどうかな？」みたいな投稿をしたら、子供がいる友達（特に女性）からの反応が思ったよりあって、これだけ反応があるなら作ってみようと思いました。


衝動発生から約2.5hでWebサイトを公開しました
->2021年7月現在、サイトをクローズしました。


以下に流れを記載したいと思います
注：技術的な事は書いていません




  【手順】
1.オープンデータの入手
CSV形式なのでGoogleスプレッドシートに保存

2.GoogleマイマップにGoogleスプレッドシートの情報をインポート
<a href="https://www.google.co.jp/intl/ja/maps/about/mymaps/">マイマップ </a>

インポート後は以下の様な状態。この状態でSNSに投稿（良い反応）
![スクリーンショット 2020-11-28 9.19.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/377988/4ed94506-6785-eec0-096f-d5ac741d92b3.png)


3.VS Codeでコーディング（HTML・CSS・Bootstrap）

赤ちゃんの画像が欲しかったのでFont Awesomeでアイコンを検索
<a href="https://fontawesome.com/start">Font Awesome</a>

4.ローカル環境で最低限の装飾が出来ているか確認
今回はWeb上に公開するスピードを最優先にしたので、ソースコードの綺麗さ・表示されるページの綺麗さに課題が残っています

5.ドメイン取得
過去に利用した事があるムームードメインから取得。77円（税込）で取得する事が出来ました。
<a href="https://muumuu-domain.com/">ムームードメイン</a>

6.レンタルサーバー契約（10日間無料）
ドメインを取得した流れで、レンタルサーバー10日間無料を利用。
身近な人のサイトに対する反応が良かったのでサーバー契約して10日後以降も公開しようと思っています。
<a href="https://lolipop.jp/?utm_source=lolipop&utm_medium=referral&utm_campaign=hosting_header_lolipop">ロリポップ！レンタルサーバー</a>

7.サーバーへデータをアップ
ロリポップ！FTPを使ってサーバーへデータをアップ
<a href="https://lolipop.jp/manual/user/ftp2-01/">ロリポップ！FTP</a>


8.ライセンスの最終確認
![スクリーンショット 2020-11-28 18.14.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/377988/25480a42-da65-e79e-b85a-c7dac1541e0a.png)

<a href="https://creativecommons.jp/licenses/">クリエイティブ・コモンズ・ライセンス</a>にはいくつかのライセンスの種類があるようなので、何を行ったらいいのかしっかり確認しました。
ちなみに那覇市のオープンデータは一番自由度が高いライセンスでした。

9.公開
Twitterで公開を呟く
![スクリーンショット 2020-11-28 18.18.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/377988/0923b2a1-694f-881a-c93c-e8da6b4a4445.png)

10.公開後
事前の反応通り、子供がいる友達からの反応は良かったです！


【感想】
１番の感想は「自分が作ったWebサイトに良い反応があって嬉しかった！」
初学者なので技術的な部分で課題が多く残っているけど、今まで勉強してきた知識を活用して誰かの為になれた経験はとても貴重だと思いました。この経験は学習教材をやるだけでは得られない経験だと思います。


【今後】
私はエンジニアのスキルを活用して世の中を便利にしたり、不便な事・問題になっている事の解決をお手伝い出来る様なエンジニアになりたいと思っています。

これから先、色々な技術を身につけてエンジニアとしてレベルアップして行きたいと思います！
まずは異業種からの転職を成功させる事だ〜汗



初学者や駆け出しエンジニアと繋がって切磋琢磨したいです！
<a href="https://twitter.com/SK_Okinawa098">私のTwitterアカウント</a>
配列の重複するオブジェクトを取り除きつつ数えたい

配列に重複するオブジェクトがある場合に、重複するオブジェクトを取り除きつつも、オブジェクト毎にいくつ重複するオブジェクトがあったか知りたいことがあります。

重複するオブジェクトの数を `count` プロパティに代入したい場合は以下のように書けます。`condition` はオブジェクトが重複する条件を定義します。

```javascript
Array.protptype.reduce((a, b) => {
    const duplicated = a.find(/* condition */)
    duplicated ? duplicated.count += 1 : a.push({...b, count: 1})
    return a
}, [])
```

また、特に連続する重複するオブジェクトのみを対象とする場合は以下のように書けます。
予め重複するオブジェクトが連続することが分かっている場合は、こちらの方が計算量が線形なのでよいと思います。

```javascript
Array.protptype.reduce((a, b) => {
    const last = a[a.length - 1]  // a が [] の場合は last は undefined になります。
    last && (/* condition... */) ? last.count += 1 : a.push({...b, count: 1})
    return a
}, [])
```

具体的な使い方をみていきます。例えば、以下のようなデータがある場合を想定します。

```typescript
type person = {
    name: string,
    age: number
}

const data: person[] = [
    {name: "aaa", age: 18,},
    {name: "bbb", age: 20,},
    {name: "bbb", age: 21,},
    {name: "ccc", age: 21,},
    {name: "bbb", age: 20,},
]
```

`name` と `age` のいずれも重複するオブジェクトを取り除きつつ数えたい場合

```typescript
data.reduce((a: (person & {count: number})[], b) => {
    const duplicated = a.find(e => e.name == b.name && e.age == b.age)
    duplicated ? duplicated.count += 1 : a.push({...b, count: 1})
    return a
}, [])

/*
[
  {name: "aaa", age: 18, count: 1},
  {name: "bbb", age: 20, count: 2},
  {name: "bbb", age: 21, count: 1},
  {name: "ccc", age: 21, count: 1},
]
*/
```

`name` が重複する連続するオブジェクトを取り除きつつ数えたい場合

```typescript
data.reduce((a: (person & {count: number})[], b) => {
    const last = a[a.length - 1]
    last && b.name === last.name ? last.count += 1 : a.push({...b, count: 1})
    return a
}, [])

/*
[
  {name: "aaa", age: 18, count: 1},
  {name: "bbb", age: 20, count: 2},
  {name: "ccc", age: 21, count: 1},
  {name: "bbb", age: 20, count: 1},
]
*/
```

他の書き方もあればフィードバックしてください。

そういえば、`a` に `(person & {count: number}[])`型を与えない場合、`a` は `never[]`型と推論されました。処理の内容から推論できると思ったのですが、どういうわけなんでしょう。
エンジニア転職に向けて~職種の確認~

2020/11/27までテックキャンプで学び卒業しました。
これからエンジニアへの転職活動が本格化するのですが、エンジニアにはどういった種類があるのか、自分がどんな仕事をしたいのかを明確にすることを目的に、各エンジニアの特徴をメモとしてまとめてみました。
``※私の主観が混ざっている場合があります。ご了承ください・・・。``

## エンジニア職一覧
- web/オープン系
- モバイル系
- 汎用系
- 制御・組み込み系
- パッケージソフト・ミドルウェア開発
- 社内SE
- データサイエンティスト
もっと細分化できるかもしれませんが、ざっと様々な求人サイトで選択できる項目を洗い出しました。

### web/オープン系
「エンジニアと言えば！」に一番近いのではないでしょうか。大きく以下の2つに分類されるようです。
- 受託開発
- 自社のWebサービス開発

いずれもWebブラウザを中心としたシステム開発をしており、例えばyoutubeとAPI連携したアプリを開発し、キーワードに紐づく直近のランキングをスプレッドシートに落とし込む、といったようなものです。
形は様々ですので困ったらこの職業で検索してみると自分のやりたいこととマッチする可能性があるかと思われます。
使用言語も多種多様。javascriptは必修でReactやVueといったフレームワークの理解があるほど良いと思います。

### モバイル系
web/オープン系と非常に近しいもので、メインはスマホアプリの開発になります。
最近の流行りで言えば、マッチングアプリやマンガアプリなどが挙げられるかと思います。
また、昨今ではWebで開発していたものをモバイルアプリに移植するといった流れも往々にしてあるので、一般消費者を対象とした仕事をしたい際は適しているかと思います。
特にフィードバックを受けやすい職業だと私は感じました。

### 汎用系
金融企業に多い、いわゆる基幹システムの開発・保守をするものです。
私も前職は金融企業で従事しており、開発言語は主にCOBOLを使用していました。
誰かのお金を預かって運用などをしていることから、間違いや動作不具合を起こしてはいけないという責任を強く感じる職業だと思います。

### 制御・組み込み系
いわゆるロボットを開発するものです。
例えば掃除機、ボタンを押したら吸い込みが始まって、もう一度押すと吸い込みが終了する。こうした何かを機転にハードの動きを制御するような職業です。家電量販店で並べられている家電を作る、と考えると想像がつきやすいのかなと思いました。

### パッケージソフト・ミドルウェア開発
「○○奉行にお任せ」の会計ソフトのような、一連の処理をパッケージ化して主に法人に販売していくものです。
個人的な感覚として、「導入することでこういった効果がある」といったコンサルタント的、営業的なスキルも必要になる職業だと思います。

### 社内SE
私の前職です。
社内のITに関する総務というのが想像しやすいのかなと思います。
もちろん業界によってその立場は様々で、例えば前職の金融企業では社内の従業員向けのシステム開発・保守を行っていましたし、IT設備などの発注なども企業によっては含まれてくるものと思います。後者についてはエンジニアとしてもそうですがハードやIT業界といった広い知識を持っていることが大切な職業だと思います。

### データサイエンティスト
ここ数年でよく耳にするようになった職業です。
多くのデータの中から関連性を導き出して新しいサービスの改善策に利用する、といったことがまず考えられます。使用言語はpythonが多いのかな。エーアイエーアイ言われますが、ビッグデータを解析したからAIが生まれる訳でもないので、しっかり吟味した方が良いと思います。

## まとめ
大枠からどういった仕事をしたいのか消去法で探していこうと思っています。
さて、私は数ヶ月後どの職業に就いているのか・・・
リソース指向アーキテクチャ(ROA)について

#リソース指向アーキテクチャ(ROA)とは
リソース指向アーキテクチャ(Resource Oriented Architecture、以下ROA)とは、それ自体を参照するに値するものを「リソース」として定義し、リソースを中心に考えるアーキテクチャのこと。また、ROAはREST APIを実装するうえで問題を解決してくれるアーキテクチャでもある。言い換えるとREST APIはROAの実装ということである。

##ROAの概念
ROAには以下の概念が存在する。

###1.リソース
Web上に存在する情報、データのこと。
ドキュメントやデータベースの行など、それ自体を参照するに値するほどの重要性を持っている。

###2.名前(URI)
リソースの名前とアドレスである。
リソースは少なくとも1つのURIを持っていなければならない。

###3.表現
Webサーバはリソースを特定の言語(英語、日本語等)、フォーマット(XML、JSON等)で送信しなければならない。
こういったリソースの形式をリソースの表現と呼ぶ。

###4.リソース間のリンク(リンクと接続性)
リソースには別のリソースへのリンクを含めることができる。リンクを含めることで別のリソースに接続することができる。
このように、リソースに含まれるリンクをもとに別のリソースに接続可能となる(遷移可能となる)性質のことを「接続性」と呼ぶ。

##ROAの特性
ROAには以下の特性が存在する。

###1.アドレス可能性
URIを通じてリソースを簡単に指し示せる性質のことを「アドレス可能性」と呼ぶ。

###2.ステートレス性
全てのHTTPリクエストが完全に分離している性質のことを「ステートレス性」と呼ぶ。セッション等の状態管理はせず、やり取りされる情報はそれ自体で完結して解釈できること。

###3.リンクと接続性
リソースには別のリソースへのリンクを含めることができる。リンクを含めることで別のリソースに接続することができる。このように、リソースに含まれるリンクをもとに別のリソースに接続可能となる(遷移可能となる)性質のことを「接続性」と呼ぶ。

###4.統一インターフェース
リソースの操作をする時に、全てHTTPメソッドが定義通りに使われることを「統一インターフェース」と呼ぶ。
vagrantfileエラー対処法　備忘録


エラー文:
``Vagrantfile` already exists in this directory. Remove it before
running `vagrant init`.``

行ったこと:
`vagrant init bento/centos-6.8`
をコマンドで打った

解消法：
vagrantを再インストール　⇨　PCを再起動　⇨　再度コマンドを打つ

こうする事で解消できました。
AccessのVBAでDir関数使ってファイル一覧ループする時はDir関数の再使用に注意！

# バグる例

例えば、Accessと同フォルダにいるCSVファイルに対して、サブフォルダ『backup』に同名ファイルが存在するかチェックする機能です。

```vb
Private Function dir_test_1()
    
    Dim buf_ As String
    
    'Accessと同フォルダにいるCSVを全部チェックするぞい
    buf_ = Dir(CurrentProject.Path & "\*.csv")
    
    Do While buf_ <> ""
        
        '★ここの判定でDirを再使用しているのがヤバい！
        If Dir(CurrentProject.Path & "\backup\" & buf_) <> "" Then
            Debug.Print "バックアップ先フォルダに" & buf_ & "いるよ！"
        End If

        '最初に処理するCSVと同名ファイルがバックアップフォルダにいる？
        'いる ⇒ 1ファイル目だけで Do While ループ抜けちゃう
        'いない ⇒ 後述の buf_ = Dir() で例外発生
        
        buf_ = Dir()
        
    Loop
    
End Function
```

Accessと同フォルダにいるCSVファイルが1つだけで、 ```If Dir(……``` がTrueになる条件だと正常終了してしまうん。


# 別関数でDir関数を使ったらどうなる？

例えばこんな感じ。
ファイル存在チェックを別関数に切り分けしてみました。


```vb
'Accessと同フォルダに居るCSVに対してbackupフォルダに居たらなんかする
Private Function dir_test_2()
    
    Dim buf_ As String
    
    'Accessと同フォルダにいるCSVを全部チェックするぞい
    buf_ = Dir(CurrentProject.Path & "\*.csv")
    
    Do While buf_ <> ""
   
        'ファイルの存在チェックは別関数にやらせるよ
        If is_file_exist(CurrentProject.Path & "\backup\" & buf_) <> "" Then
            Debug.Print "バックアップ先フォルダに" & buf_ & "いるよ！"
        End If
        
        buf_ = Dir()
        
    Loop
    
End Function


'ファイルパスをもらってファイルが存在するか返すよ
Private Function is_file_exist(ByVal file_path As String)
    is_file_exist = Dir(file_path) <> ""
End Function
```

結果は『バグる例』と同じ。
Dirを呼び出すのが、別関数であろうと（スコープが変わろうと）同じです(´・ω・`)


# つまり、こういう使い方はバグを生み出しやすいので注意

下記のようなコードはDo While内でDir関数を再使用していないか **人が気を付けて** 作る必要があります。

```vb
Dim buf_ As String
    
buf_ = Dir("ファイル一覧を取得するワイルドカード的な文字列")

Do While buf_ <> ""

    'buf_ = Dir()に到達するまでにDir()を再使用していないか『人が』注意して作る必要がある。

    buf_ = Dir()
    
Loop
```

Do While内（浅い階層）でDir関数の再使用を発見できればいんですが……。
**Do While内で呼び出した関数内で呼び出した関数内** でDir関数を使ってたりなんかして……。
うーん、バグの香りがプンプンします(´・ω・`)


# 蛇足

個人的にDir関数は使わないようにしています。
Dir関数の仕様を知らない人がシステム改修するかもしれないから…。

代わりに FileSystemObject クラスを使っています。使用例は下記。
[AccessのVBAでフォルダー内ハウスキープ（古いファイルを自動削除）関数](https://qiita.com/waokitsune/items/ff3db68a00db871d85f7)

あと、複数ファイルを処理する機能はテストもちゃんと複数ファイル用意しましょう。
（そのへん横着しちゃダメね）


# バージョン

Windows10 Pro バージョン1909 OSビルド19042.630
Access for Microsoft 365 MSO（16.0.13328.20334）32ビット
CentOS8.xでのJavaサーバーサイド構築

|[../](https://qiita.com/taconana/items/d382d08a83a2a67f3b6a) |
|---|

VPSサーバー（CentOS8.x）にJavaサーバーサイド構築を行っている。Java11 + MySQL8 + Tomcat9 で構成する予定である。作業手順をメモとして残しておきたい。構築の開始時にはCentOS8.1であったが、updateを重ねて、現在CentOS8.3に上がっている。
## CentOS8.xでのJavaサーバーサイド構築
- [yum update後に起動できなくなる現象の回避策](https://qiita.com/taconana/items/dd36e372be0cde6ab642) (※CentOS8.2に上げるとGrub2の構成が壊れる？)
- [VNCサーバーをセットアップする手順(CentOS8.2)](https://qiita.com/taconana/items/c1c32a20f13783933739)
- [VNCサーバーをセットアップする手順(CentOS8.3)](https://qiita.com/taconana/items/8a9b07ea686d68587281)（※手順が変わっている！)
- [httpdをセットアップする手順](https://qiita.com/taconana/items/b45ea7f86b0c7be38d5a)
- [MySQL8.0をセットアップする手順](https://qiita.com/taconana/items/08e0f3eb5b72fea11584)
- [MySQL8.0コンソールから日本語入力できない問題の回避策](https://qiita.com/taconana/items/4d75888c613237dc5ed7) (※utf8では日本語入力できない？)
- [MySQL8.0ユーザーにGRANT設定する手順](https://qiita.com/taconana/items/b5a7018e4f7904790843)
- [SCPを利用する手順](https://qiita.com/taconana/items/9fa17a7ec9e75239c401)
- [MySQL8.0の定期的なバックアップを行う手順](https://qiita.com/taconana/items/ae88e370b4abc1a3e0fc)
- [MySQL8.0でlower_case_table_names=1に変更する手順](https://qiita.com/taconana/items/5a5b0f46620ae1b27b10)（※手順が面倒になった！)
- [Java11とTomcat9をセットアップする手順](https://qiita.com/taconana/items/27fa0de7099ce359ddf1)
- [SSL証明書（Let's Encrypt）をセットアップする手順](https://qiita.com/taconana/items/a9e197e80b8c20c7d5ac)
- [SSL証明書（Let's Encrypt）の有効期限が切れた場合](https://qiita.com/taconana/items/d5072c68ab4d8844a93b)
- [SSL証明書（プライベート認証局）をセットアップする手順](https://qiita.com/taconana/items/863f50c7ba13d29cc6a7)
- [httpdとTomcat9を連携させる手順](https://qiita.com/taconana/items/2100bb0a4b27a8d3a1e7)（※secretRequired に注意！)
- [httpdとTomcat9を連携させる手順（複数のProxyPass）](https://qiita.com/taconana/items/36855776d4ed6a0d5ba5)
- [rpm実行時に「依存性の欠如」のエラーが起きた場合の対処](https://qiita.com/taconana/items/7cc36527231d49d40f3e)（※CentOS8.3に上がった！)
- [PostfixとDovecotをセットアップする手順](https://qiita.com/taconana/items/6c1813355fb788c27cb6)

## その他の投稿：
- [CentOS Stream 8でのPHP7.4の動作環境構築](https://qiita.com/taconana/items/d382d08a83a2a67f3b6a)
- [PHPの学習メモ](https://qiita.com/taconana/items/3f5424f9abfc755772c2)
- [その他](https://qiita.com/taconana/items/55e4ea3283f2fa82a670)

|[../](https://qiita.com/taconana/items/d382d08a83a2a67f3b6a) |
|---|