OmniAICreator/Qiita-1.07M huggingface dataset:
【jQuery】子要素から親要素を指定＆同一class名を持つ要素を個別に書き換える

こんにちは。E-kan株式会社の岡田です。

既存ページのABテストのため、外部ツールにjQueryでテストしたい要素を書き込んでページを上書きするという業務をよくやるのですが、この間地味に苦労したので備忘録。
ざっくり必要なところだけ抜き出すとこんな感じです。


## 変更前html
```html
<section>
  <img class="pic" src="pic01.jpg">
  <div class="child">
    <h2>タイトル01</h2>
    <p>本文01</p>
  </div>
  <ul class="list">
    <li><img src="list01.jpg"></li>
    <li><img src="list02.jpg"></li>
    <li><img src="list03.jpg"></li>
  </ul>
</secton>

<section>
  <img class="pic" src="pic02.jpg">
  <div class="child">
    <h2>タイトル02</h2>
    <p>本文02</p>
  </div>
  <ul class="list">
    <li><img src="list04.jpg"></li>
    <li><img src="list05.jpg"></li>
    <li><img src="list06.jpg"></li>
  </ul>
</secton>
```

このように、内容はユニークだけど外側の要素は全て同一の構成を、以下の要望通りに書き換える。

- 子要素「child」を持つ親要素にclass名「parent」をつけたい
- 子要素内にいるh2を親要素の直下に移動させたい
- img.picをライトボックス表示にしたい
- ul.listをスライダー表示にしたい

出来上がりは、こう。


## 変更後html
```html
<section class="parent">
  <h2>タイトル01</h2>
  <a class="lightbox" href="pic01.jpg">
    <i class="icon"></i>
    <img class="pic" src="pic01.jpg">
  </a>
  <div class="child">
    <p>本文01</p>
  </div>
  <ul class="list slider">
    <li><img src="list01.jpg"></li>
    <li><img src="list02.jpg"></li>
    <li><img src="list03.jpg"></li>
  </ul>
</secton>

<section class="parent">
  <h2>タイトル02</h2>
  <a class="lightbox" href="pic02.jpg">
    <i class="icon"></i>
    <img class="pic" src="pic02.jpg">
  </a>
  <div class="child">
    <p>本文02</p>
  </div>
  <ul class="list slider">
    <li><img src="list04.jpg"></li>
    <li><img src="list05.jpg"></li>
    <li><img src="list06.jpg"></li>
  </ul>
</secton>
```


## jQuery
```javascript
//ライトボックスとカルーセル用の外部jsを読み込む
$.getScript('script.js', function() {

  //ページ内の要素が全て読み込まれてから実行する
  $(window).on('load',function(){
  
    //子要素「child」を持つ親要素にclass名「parent」を付与
    $('div.child').parent('section').addClass('parent');

    //ul.listにスライダー用のclassを付与
    $('ul.list').addClass('slider');

    //ライトボックス用のhtmlを作成
    var lightboxArea = (function () {/*
      <a class="lightbox" href="src">
        <i class="icon"></i>
      </a>
    */}).toString().match(/[^]*\/\*([^]*)\*\/\}$/)[1];
    
    //作ったhtmlを親要素直下配置
    $('section.parent').prepend(lightboxArea);

    //各親要素内の子要素のみを選択する
    $('section.parent').each(function(){
    
      //h2を、自分を内包する親要素内の一番上に移動
      $(this).find('h2').prependTo($(this));

      //画像のsrcを取得して変数に格納
      var src = $(this).find('img.pic').attr('src');

      //格納したsrcをリンク要素のurlに代入
      $(this).find('a.lightbox').attr('href',src);

      //自分を内包する親要素内の、特定のclass名を持つ要素下に移動
      $(this).find('img.pic').insertAfter($(this).find('i.icon'));
      
    });

  });

//ライトボックスとスライダーのプラグイン用コードを以下に書き込む（省略）
  
});
```
案件が来るたびに「あー、この間やったあれと同じだ」と思うのだけど、いざ作業を始めると何をどうやったのか思い出せない鳥頭なので、備忘録はとても大事。
Pythonでポケモン御三家の種族値をソートする

初投稿 & タイトルの通りです。

大学院の研究でグラフを描くために最近Pythonを使っているのですが「どうせなら言語丸ごと習得してしまうか～」と思い立ち、着想から約2~3時間ほどで書きました。

ご指摘やアドバイスの他、「こういう機能作ったらいいんじゃない？」などありましたら是非コメントいただけますと大変有り難いです。

```python
import pprint

    #御三家の種族値のタプルリスト
pokemon_data = [
    ("フシギバナ", 80, 82, 83, 100, 100, 80, 525),
    ("メガニウム", 80, 82, 100, 83, 100, 80, 525),
    ("ジュカイン", 70, 85, 65, 105, 85, 120, 530),
    ("ドダイトス", 95, 109, 105, 75, 85, 56, 525),
    ("ジャローダ", 75, 75, 95, 75, 95, 113, 528),
    ("ブリガロン", 88, 107, 122, 74, 75, 64, 530),
    ("ジュナイパー", 78, 107, 75, 100, 100, 70, 530),
    ("ゴリランダー", 100, 125, 90, 60, 70, 85, 530),
    ("リザードン", 78, 84, 78, 109, 85, 100, 534),
    ("バクフーン", 78, 84, 78, 109, 85, 100, 534),
    ("バシャーモ", 80, 120, 70, 110, 70, 80, 530),
    ("ゴウカザル", 76, 104, 71, 104, 71, 108, 534),
    ("エンブオー", 110, 123, 65, 100, 65, 65, 528),
    ("マフォクシー", 75, 69, 72, 114, 100, 104, 534),
    ("ガオガエン", 95, 115, 90, 80, 90, 60, 530),
    ("エースバーン", 80, 116, 75, 65, 75, 119, 530),
    ("カメックス", 79, 83, 100, 85, 105, 78, 530),
    ("オーダイル", 85, 105, 100, 79, 83, 78, 530),
    ("ラグラージ", 100, 110, 90, 85, 90, 60, 535),
    ("エンペルト", 84, 86, 88, 111, 101, 60, 530),
    ("ダイケンキ", 95, 100, 85, 108, 70, 70, 528),
    ("ゲッコウガ", 72, 95, 67, 103, 71, 122, 530),
    ("アシレーヌ", 80, 74, 74, 126, 116, 60, 530),
    ("インテレオン", 70, 85, 65, 125, 65, 120, 530),
]

def hyouzi(a):
    print("('ポケモン', HP, こうげき, ぼうぎょ, とくこう, とくぼう, すばやさ)")
    pprint.pprint(a)
    print("ソートが完了しました。")
    
while True:
    num_str = input("ソートする種族値を入力して下さい。(0:HP 1:こうげき 2:ぼうぎょ 3:とくこう 4:とくぼう 5:すばやさ 6:合計種族値)")
    num = int(num_str)

    if num == 0:
        pokemon_data.sort(key=lambda tup: tup[1], reverse=True)
        print("HPの高い順に並び替えます。")
        hyouzi(pokemon_data)
    elif num == 1:
        pokemon_data.sort(key=lambda tup: tup[2], reverse=True)
        print("こうげきの高い順に並び替えます。")
        hyouzi(pokemon_data)
    elif num == 2:
        pokemon_data.sort(key=lambda tup: tup[3], reverse=True)
        print("ぼうぎょの高い順に並び替えます。")
        hyouzi(pokemon_data)
    elif num == 3:
        pokemon_data.sort(key=lambda tup: tup[4], reverse=True)
        print("とくこうの高い順に並び替えます。")
        hyouzi(pokemon_data)
    elif num == 4:
        pokemon_data.sort(key=lambda tup: tup[5], reverse=True)
        print("とくぼうの高い順に並び替えます。")
        hyouzi(pokemon_data)
    elif num == 5:
        pokemon_data.sort(key=lambda tup: tup[6], reverse=True)
        print("すばやさの高い順に並び替えます。")
        hyouzi(pokemon_data)
    elif num == 6:
        pokemon_data.sort(key=lambda tup: sum(tup[1:7]), reverse=True)
        print("合計種族値の高い順に並び替えます。")
        hyouzi(pokemon_data)
    else:
        print("ソートできませんでした。")
    
    num2_str=input("ソートを終了しますか？(0:はい それ以外の数字:いいえ)")
    num2 = int(num2_str)
    if num2 == 0:
        break
    else:
        continue
```
Route53ヘルスチェックを使用しリカバリサーバーを用意する方法

# 完成図
プライマリサーバが正常に動作しなくなった時、検知してリカバリサーバにルーティングを変更する構成。

:::note info
リージョンを分けることで冗長化
:::

![Untitled (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1488939/cb1febe6-e097-6a78-5c6e-b7d4d702449a.png)
やってないけど、Route 53 のヘルスチェック先とレコードを変更すれば S3 静的ホスティングとかでもいける、たぶん...

# 必要リソース
- EC2インスタンス x2 
    - プライマリインスタンス
    - セカンダリインスタンス（プライマリとは別のリージョンに作成）

- Route53 ヘルスチェック x2
    - プライマリ用
    - セカンダリ用

- Route53 レコード x2
    - プライマリ用
    - セカンダリ用

:::note warn
ホストゾーンの作成は割愛
:::

- CloudWatch アラーム x2
    - プライマリ用（ヘルスチェック作成で自動作成）
    - セカンダリ用（ヘルスチェック作成で自動作成）

- SNS トピック x1
    - プライマリ用（ヘルスチェック作成で自動作成）

# 構築手順
## 1. オリジンの作成
EC2インスタンス x2 を別々のリージョンに作成
（S3 静的ホスティングの場合は S3 x2）

## 2. ヘルスチェックの作成
Route53 ヘルスチェックをプライマリ用、セカンダリ用それぞれ作成

:::note info
ヘルスチェック作成時に CloudWatch アラーム、SNS トピックが自動的に作成される
:::

:::note warn
作成された段階で SNS トピックから登録したメールアドレスに認証メールが来る、認証を完了しないと通知が来ないので注意
:::

- 名前 : 適当
- モニタリング対象 : エンドポイント
- エンドポイント : ドメイン名
- プロトコル : HTTP
- ドメイン名 : EC2のパブリック IPv4 DNS
- ポート : 80
- アラームの作成 : はい
- 通知の送信先 : 新しいSNSトピック
- トピック名 : 適当
- Eメール受け取りのアドレス : 適当

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1488939/7fe4330f-83da-ed6b-9be7-07e2ff05cb2f.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1488939/a58d9497-cc1f-7e1f-c934-2359a0e19ee6.png)

## 3. Route 53 レコードの作成
ホストゾーンの作成は割愛
Route53 レコードをプライマリ用、セカンダリ用それぞれ作成
- レコード名 : ドメイン
- レコードタイプ : AかAAAA
- 値 : EC2インスタンスを指定
- エイリアス : いいえ
- TTL : 用途に応じて
- ルーティングポリシー : Failover
- フェイルオーバーレコードタイプ : プライマリ、セカンダリ
- ヘルスチェックID : Route53 ヘルスチェック
- レコードID : プライマリとセカンダリで別のID

![スクリーンショット 2022-06-23 17.20.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1488939/ff50f5f9-148f-d1cc-4aac-b767b4b0359c.png)

## 4. CloudWatch アラームの設定変更
Route 53 ヘルスチェック時に自動的に CloudWatch アラームが作成される。
このままだとヘルスチェックのエラーは設定したメールに通知してくれるが、エラーが解除され正常に戻ったことは通知してくれない。
エラー状態の解除も通知するように設定を追加する。

1. 作成された CloudWatch アラームを Route 53 ヘルスチェクから確認
2. アクションのプルダウンから編集を選択
2. アクションの設定で通知の追加をクリック、以下のようにOKを選択

![スクリーンショット 2022-06-23 17.52.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1488939/1ea29dd0-2d71-e5b4-0763-02dc00919408.png)

# 動作テスト
プライマリを手動で停止しセカンダリに切り替わること、再び起動したらプライマリに戻ることを確認する

:::note info
動作テスト中は一時的にTTLを短くすると、プライマリを停止してからセカンダリ切り替わるまでが早い
:::

:::note info
参考までに TTL 10sec でのプライマリ停止後に切り替わるまでの時間は3分弱ほどだった
:::

```cl:ターミナルで実行
>dig [レコード名] @1.1.1.1
~
;; ANSWER SECTION:
[レコード名]. 60 IN	A	[primary Elastic IP]
~

プライマリ停止

>dig [レコード名] @1.1.1.1
~
;; ANSWER SECTION:
[レコード名]. 60 IN	A	[secondary Elastic IP]
~

プライマリ起動

>dig [レコード名] @1.1.1.1
~
;; ANSWER SECTION:
[レコード名]. 60 IN	A	[primary Elastic IP]
```

# 参考文献
https://qiita.com/kooohei/items/c24dd3bab57552127886
ログインせずにローカルのファイルをAzureのStorage accountsにアップロードする

「バッチ処理でローカルのファイルをAzureのStorage accountsに上げたい」となったので、その時に使うPowershellスクリプトを作ろうとしたのですが、ログインしてする方法ばかりで困ったので記録用に。
「ログインせずに」したかった理由としては、ログインに使ったアカウントは2段階認証が必要で<code>az login -u $username -p $password</code>が使えなかったからです。

## 環境

* OS: Windows

## 1. Azure CLIをインストール

https://docs.microsoft.com/ja-jp/cli/azure/install-azure-cli-windows?tabs=azure-cli


## 2. Powershellスクリプトの作成

### 2-1. Storage accountsにつなげる

「Windows PowerShell ISE」というアプリを開き、「ファイル>新規作成」をします。
開けたら以下のコードを貼り付けます。

```powershell
$account_name = ''
$account_key = ''
$container_name = ''
```

これらの変数に値を入れていくために、Storage accountsからkeyとaccount nameを取ってきます。
account_nameには「ストレージアカウント名」の値を、
account_keyには「キー」の値を入れます。
![portal-connection-string.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/495159/09dba9c6-46be-6d83-1bdb-97d6983e8ca3.png)
conainer_nameには「Name」の文字列を入れます。
画像だと「$logs」しかないので、新しく作ってもらうのがいいと思います。
![create-container-lrg[1].png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/495159/ac556291-a3dc-7fe8-9272-e95438cbb953.png)

では接続できるかどうかを試してみます。
ファイルの一番最後にコマンドを追加し、上の緑の三角マークをクリックして実行します。

```powershell
$account_name = ''
$account_key = ''
$container_name = ''

az storage blob list --account-key $account_key --account-name $account_name -c $container_name
```

空っぽのコンテナであれば空配列が、ファイルが入っていればいろいろ表示されると思います。
表示されれば次へ。

### 2-2. ファイルをアップロードする

次はファイルをアップロードします。
アップロードするファイルを用意し、以下の変数名に値を入れてください。
file_nameは拡張子さえ同じであればなんでも大丈夫です。

```powershell
$file_name = ''
$file_path = ''
```

「C:\Images\Image001.png」に画像ファイルがあるとすると、こんな感じになります。

```powershell
$file_name = 'Image001.png'
$file_path = 'C:\Images\Image001.png'
```

ではアップロードするコマンドを貼り付けて実行してみます。

```powershell
$account_name = ''
$account_key = ''
$container_name = ''

$file_name = ''
$file_path = ''

az storage blob upload --account-key $account_key --account-name $account_name -c $container_name --name $file_name --file $file_path
```

私の場合は赤い文字で何やら表示されましたが、Account Storageを確認したところ、ちゃんとアップロードできてました。

### 参考
https://www.se-from30.com/azure/azurecli-az-storage-blob-01/
Zoom Meeting SDK と Zoom Video SDK の違いついて

# 概要

* 本記事はZoomのMeeting SDKとVideo SDKの違いについて解説します。
* そもそもZoomのSDKって何？という方はQiita Zineの[こちらの記事](https://zine.qiita.com/interview/202205-zoom/)をお読みください。
* 細かい仕様の違いについてはこちらの[Zoomサポート記事](https://support.zoom.us/hc/ja/articles/360058998832)をご確認ください。


# Meeting SDK
![Copy of Developer Platform Fundamentals - SDK Deep Dive.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2123955/9d567908-a3d3-2429-ca12-79d98269c588.jpeg)


* ZoomのMeeting SDKを用いて、アプリやウェブサービスの中にZoom Meeting(もしくはZoom Webinars)を埋め込むことができます。
* Zoom MeetingやZoom Webinarsと互換性があるので通常のZoomクライアントアプリと接続することも可能です。
* UI/UXのカスタマイズはほとんどできません、そのぶん簡単に組み込めます。
* チャット、ブレイクアウトルーム、クラウド録画など通常のZoom MeetingやZoom Webinarsで提供されている機能の大半がご利用いただけます。
* 社内利用（Zoom Meeting/Webinarsの __*参加者全員が契約企業に所属している場合*__ ）であれば有償のZoomライセンスのご契約があればご利用いただけます。無償ライセンスでの動作は保証していません。
* 第三者利用（Zoom Meeting/Webinarsの ___ホストまたは参加者が契約企業に所属していない場合___ ）になる場合、Zoom ISVパートナープラグラムに参加頂くか、Zoom App Marketplaceにご登録いただく必要があります。
* Native Meeting SDKではAndroid, iOS, Windows, MacのMeeting SDKが提供されています。
* フレームワークではElectronとIonicのWrapperを提供していますがWindows, MacのNative Meeting SDKの利用を推奨しています。
* Web Meeting SDKはChrome, Safariなどデスクトップとモバイルの主要ブラウザをサポートしてます。
* 詳細はこちらのドキュメントでご確認ください。

# Video SDK

![Copy of Developer Platform Fundamentals - SDK Deep Dive.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2123955/1f497460-0f5f-17d1-3dc6-f33e5c4a5291.png)

* Zoom Video SDKでアプリやウェブサービスにビデオ通話の機能を埋め込むことができます。
* インフラはZoomなので高品質かつ高い信頼性が担保されていますが、通常のZoom MeetingやZoom Webinarsとは互換性がありません（接続できません）。
* 標準のUI/UXが提供されません。画面レイアウトなどをゼロから設計する必要があります。ただしJumpstartでWeb SDKにはひな形を提供するするようになりました。
* チャットやブレイクアウトルームなど、ビデオ通話以外の機能は原則的に提供されません。ただしクラウド録画は提供されるようになりました。
* 社内利用／第三者利用ともにZoomのウェブサイトでサインアップしてクレジットカードをご登録いただくだけで、月に1万分までは無料でご利用いただけます。1万分以降は従量課金で有料になります。
* Native Video SDKではAndroid, iOS, Windows, MacのVideo SDKが提供されています。
* フレームワークではAndroidとiOSでReact NativeのWrapperを提供しています。
* Web Video SDKはChrome, Safariなどデスクトップとモバイルの主要ブラウザをサポートしてます。
* 詳細はこちらのドキュメントでご確認ください。

# 参考資料

* [Zoom Meeting SDK](https://marketplace.zoom.us/docs/sdk/native-sdks/introduction)（英文）
* [Zoom Video SDK](https://marketplace.zoom.us/docs/sdk/video/introduction)（英文）
* [Zoomの拡張機能！？シームレス連携が出来るAPIとSDKについて中の人に聞いてみた](https://zine.qiita.com/interview/202205-zoom/)
CSSで異なる画像サイズを同じ高さ、同じサイズでレスポンシブに表示させてみた(メディアクエリなし)

# 下記の条件で困ってる方向けに、備忘録残します。

・画像サイズが違うけど、全て同じ大きさで画像を一覧表示したい
・画像に空欄ができてしまう
・なるべくメディアクエリは使いたくないがレスポンシブにしたい

画像は、テスト用にオンラインからお借りいたしました（便利ですねコレ）
https://placehold.jp/

# ポイント
・要素はそれぞれwidth:100%; height:100%; で指定
・imgタグにaspect-radioを指定（今回は4/3としました)

# HTMLコード

```html
<div class="image-area">
  <!-- extensible !-->
  <ul>
    <li>
      <img src="https://placehold.jp/550x550.png" alt="">
    </li>
    <li>
      <img src="https://placehold.jp/1250x850.png" alt="">
    </li>
    <li>
      <img src="https://placehold.jp/2050x1450.png" alt="">
    </li>
  </ul>
</div>

```

# CSSコード
```css
body {
  margin:0;
  padding:0;
}
ul, li {
 margin:0;
  padding:0;
}
div {
  width:100%;
  height:100%;
}
ul {
  display:flex;
}
li {
  width:100%;
  max-height:100%;
  list-style:none;
}
img {
  width:100%;
  height:100%;
  aspect-radio:4/3;
  border:solid; /* borders are listed for clarity*/
}

```
CSSは簡易的なリセットCSS書いてます。

# 手っ取り早くどんな出来栄えか知りたい方

https://codepen.io/pontarou194/pen/RwQzvEW

※基本的に、画像サイズに関係なく、無理矢理サイズを統一するため、画像サイズや特定のサイトによっては、
かなり変に見えてしまう可能性もありますので、ご了承くださいませ。

また、ここはこうしたほうがいいよー！等ございましたら、ご指摘いただけますと幸いです！
努力し、精進いたします（好奇心旺盛、勉強大好きです）
【unity】キャラクターを移動させる

<h1>概要</h1>
キャラクターのアニメーションを設定した後、移動やジャンプをさせる方法がわからなかったので、メモしておく。

<h1>設定方法</h1>
<ol>
<li>スクリプトを作成し、スプライトにアタッチする。</li>
<li>スクリプトに、以下のように記述する。

```
    void Update()
    {
        float horizontalKey = Input.GetAxis("Horizontal"); 
        Vector2 position = transform.position;

        if (horizontalKey > 0) 
        {
            position.x += speed;
            transform.localScale = new Vector3(1, 1, 1);
        }
        else if (horizontalKey < 0) 
        {
            position.x -= speed;
            transform.localScale = new Vector3(-1, 1, 1);
        }

        transform.position = position;

    }
```

</li>
</ul>

`horizontalKey`にて、スプライトの水平方向の入力を取得する。`position`ではスプライトの位置を取得している。
`horizontalKey`によって分岐し、左右それぞれでスプライトの位置を変更する処理を記述する。
`transform.localScale`ではスプライトの向きを変更している。

ちなみに以下のように直接`transform.position`を変更しようとすると、エラーになってしまうので注意。

```
transformposition.x += speed;
```
初心者コンテンツ記事一覧

## 記事一覧

**1章：はじめに**
・[1から学ぶKony Mobility Platform -はじめに-](https://qiita.com/Kony_Team/items/f3b6faf8179d7ffd70b2)　
・[Kony Mobility Platformのサービス概要説明](https://qiita.com/Kony_Team/items/97f40662c36036903b85)
・[Visualizerの環境設定](https://qiita.com/Kony_Team/items/cb012a9b3eeb5832ac9d)

**2章：基本的な使い方の説明**
・[Visualizerワークスペースの基本的な使い方](https://qiita.com/Kony_Team/items/8d6afaed19229d01454e)
・[覚えておくと便利！ショートカット集](https://qiita.com/Kony_Team/items/9091cd4c6fd7e340ad4e)
・[Widgetの機能について簡単にご紹介](https://qiita.com/Kony_Team/items/85a97af217ae0d53f3bf)

**3章：Visualizerを使ったフロントアプリの作成**
・[Webアプリを作ってみよう](https://qiita.com/Kony_Team/items/80d6bbab808699ab7bef)
・[モバイルアプリ（iOS/Android）を作ってみよう](https://qiita.com/Kony_Team/items/576711d7016e2f073b8b)
・[Exercise1 デザインを元にモバイルで画面を作ってみよう](https://qiita.com/Kony_Team/items/8685b53a8878d41cdaf6)
・[Exercise2 モバイルでクーポン一覧画面を作ってみよう](https://qiita.com/Kony_Team/items/c1bf41da1df24d7608a5)
・[i18nを使って多言語対応をしてみよう](https://qiita.com/Kony_Team/items/463ecc8dd3ee313adcc2)

**4章：Faricを使ったAPIの作成**
・[Fabricの概要説明とAPIの作成方法](https://qiita.com/Kony_Team/items/540996aa24fc17fd7b2f)
・[Exercise3 Identity Serviceを使ってノンコーディングでログイン画面を作成してみよう！](https://qiita.com/Kony_Team/items/963a88c97dab99f8b583)
・[Exercise4 気象情報APIを使ってアプリを作ってみた -Integration Service編-](https://qiita.com/Kony_Team/items/7f16c91695a8e384c956)
・[Exercise5 気象情報APIを使ってアプリを作ってみた -Object Service編-](https://qiita.com/Kony_Team/items/4387cc54df3089f95e1b)
・[Exercise6 気象情報APIを使ってアプリを作ってみた -Visualizer編](https://qiita.com/Kony_Team/items/9132887be758f4739b49)
・[アプリのユーザー分析機能を使ってみよう](https://qiita.com/Kony_Team/items/1de9f5840111ab32c62c)

**5章：開発の効率化**
・[コンポーネントの概要説明](https://qiita.com/Kony_Team/items/a25b322d9524f9f1ac92)
・[コンポーネントを作ってみよう！](https://qiita.com/Kony_Team/items/1f20ddcbc4610105b97a)
・[Temenos Forge（旧Kony Marketplace）の概要と利用方法](https://qiita.com/Kony_Team/items/a2208485463ed2b25c34)

**6章：エラーが起きた時の対処法**
・[エラーが発生した時に確認する記事まとめ](https://qiita.com/Kony_Team/items/56867a7c8c977ba58e3c)
・[basecampの使い方](https://qiita.com/Kony_Team/items/3ce70aa09c78465bc448)
・[supportへの問い合わせ方法](https://qiita.com/Kony_Team/items/b09df2ef9178cbd543bc)（※2022年3月22日より新サポートポータルへ移行しました。）
辞書をpd.DataFrameに変換

#辞書をpd.DataFrameに変換

```python
dic={}
for c,Ss in C2Ss.items():   # 一度pd.Seriesに変換
    dic[c]=pd.Series(Ss)
 
df=pd.DataFrame(dic)
 
print(df.head())
df.to_csv('dic.csv')

```
Hello, hardhat! につまずいた

次のページの案内に沿って、サンプルプロジェクトを実行し、localhost にデプロイしたときにつまづいた。

https://hardhat.org/guides/deploying

```
$ npx hardhat node
$ npx hardhat run --network localhost scripts/sample-scripts.js
```

上記を実行後、node を立ち上げて、以下のように `greeter.greet()` をしたら、`CALL_EXCEPTION` が出た。

```
> const hre = require("hardhat");
> address = "0x5FbDB2315678afecb367f032d93F642f64180aa3"
'0x5FbDB2315678afecb367f032d93F642f64180aa3'
> const contract = await hre.ethers.getContractAt("Greeter", address);
> await contract.greet()
Uncaught:
Error: call revert exception [ See: https://links.ethers.org/v5-errors-CALL_EXCEPTION ] (method="greet()", data="0x", errorArgs=null, errorName=null, errorSignature=null, reason=null, code=CALL_EXCEPTION, version=abi/5.6.4)
    at Logger.makeError (/Users/ytakashina/workspace/achievement-maker/node_modules/@ethersproject/logger/lib/index.js:233:21)
    at Logger.throwError (/Users/ytakashina/workspace/achievement-maker/node_modules/@ethersproject/logger/lib/index.js:242:20)
    at Interface.decodeFunctionResult (/Users/ytakashina/workspace/achievement-maker/node_modules/@ethersproject/abi/lib/interface.js:388:23)
    at Contract.<anonymous> (/Users/ytakashina/workspace/achievement-maker/node_modules/@ethersproject/contracts/lib/index.js:395:56)
    at step (/Users/ytakashina/workspace/achievement-maker/node_modules/@ethersproject/contracts/lib/index.js:48:23) {
  reason: null,
  code: 'CALL_EXCEPTION',
  method: 'greet()',
  data: '0x',
  errorArgs: null,
  errorName: null,
  errorSignature: null,
  address: '0x5FbDB2315678afecb367f032d93F642f64180aa3',
  args: [],
  transaction: {
    data: '0xcfae3217',
    to: '0x5FbDB2315678afecb367f032d93F642f64180aa3',
    from: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
    gasLimit: BigNumber { value: "29021272" }
  }
}
```


原因を調査してみたところ、ちゃんとアドレスが指定できていなかったり、接続先のネットワークが間違っていると、このエラーが出るらしい。

https://docs.ethers.io/v5/troubleshooting/errors/#help-CALL_EXCEPTION

普通に node を立ち上げるのではなく、hardhat console を使って接続先のネットワークを指定しなければいけなかった。

```
$ npx hardhat console --network localhost
```

（多分 node で立ち上げた上で localhost 繋ぐ方法もあるだろうけど、割愛。）

無事、Hello, Hardhat! できました :blush:  

```
> await contract.greet()
'Hello, Hardhat!'
```
心理的安全のためにマネジャーがきょうからできる7つの習慣



チームが生産的・自律的であるために重要な「心理的安全」を高めるにはどうしたらいいか？
これを職場で考える機会が最近ありました。
それを踏まえ、職場のマネジャーにお勧めしたことをここでも共有してみます。

# 対等に話す

部下が上司に使うのと同じように、上司も部下も敬語を使うべきです。
「さん」づけで呼びかけるべきです。
なぜなら、常体（ため口）や「くん」づけは上下関係が前提になっているからです。
これは日本語ならではの特徴です。

問題は、本人は歩み寄っているつもりでも、部下からしたら怖いということがありえます。
もちろん雑談モードだったり、すでに双方の距離が近かったりすれば、問題にはなりません。

対等な言葉遣いをする別の利点は、
高齢化してきた組織では、ある日を境に突然、上下関係が逆転することがよくあり、
敬語や「さん」づけに慣れておけば、逆転しても自然な関係を維持できることです。
これは『会社人生を後悔しない 40代からの仕事術』という本からの引用です。


# 腕組み・足組みしない

これは説明は不要でしょう。
対面の機会は少ないので、昨今の重要性は低いですが。
腕組み・足組みは威圧感を与えます。

# 上機嫌でいる

不機嫌そう、忙しそう、いらいらしている雰囲気を漂わせている人には話しかけにくいものです。

# 失敗談を話す

会社の多くのマネジャーは武勇伝（成功談）ばかり話したがります。
距離を置くのが目的ならいいですが、
失敗談を話したほうが部下には親近感がわきます。

# 「私は聞いていない」と言わない

トヨタの「事技職場における7つのムダ」に載っているので挙げてみました。
これは「報告せよ」という威圧であり、
資料作りや根回しという面倒な仕事を部下に暗黙的に強制しています。
必要な情報は上司が自ら集めましょう。
これに限らず、暗黙的な指示は威圧感を感じさせます。
宿題があるなら会議の最後に明示してほしいものです。


# 部下の変えられない部分を受け入れる

指導して部下が改善できることと、改善できないことの違いを見極めましょう。
できないのに無理やり改善させようとしても、
だんだんと口調が厳しくなり、不機嫌になり、いらいらするでしょうし、
そうすれば部下からしたら怖いだけです。
そのような場合には、ほかの手立てを打つのがマネジャーの仕事です。

# 会議中に部下を認める

会議の他の参加者に聞こえるように、
部下の発言に賛同したり、
アイデアを褒めたり、
部下自身の有能さを褒めたり、
業績を具体的にねぎらったりする光景を、
他社で見かけます。
とてもいいなと感じます。
あまり職場ではお目にかかれない光景です。
日本人らしく褒めるのは苦手、などであれば、
会議での部下の発言を積極的に引用して自説を展開するのは比較的やりやすいでしょう。
DockerでCentos7 Python3.6の環境を構築 & Jupyter Lab

# 構築内容
```
Centos7
Python3.6
Jupyter Lab
```

# クローン
以下リポジトリをクローンする
https://github.com/yamada-ham/centos7_python3.6

# コマンド ビルドして起動 
```
$ docker-compose up -d
```

# コンテナに入る
```
$ docker-compose exec centos bash
```

# Jupyter起動
```
$ jupyter lab --ip=0.0.0.0  --port 9999 --allow-root
```
Railsのレスポンスに任意のHTTPヘッダを追加するRackミドルウェア

```ruby:config/initializers/additional_http_headers.rb
class AdditionalHTTPHeaders
  def initialize(app)
    @app = app
  end

  def call(env)
    status, headers, body = @app.call(env)
    additional_headers.each{|k, v| headers[k] = v }
    [status, headers, body]
  end

  private
    def additional_headers
      {
        'x-foo' => 'bar',
      }
    end
end

Rails.application.config.middleware.insert_before(
  ActionDispatch::Cookies, AdditionalHTTPHeaders
)

```
Orca Securityで継続的スキャン

Orca SecurityのAPIを試してみました。この記事はCI/CDパイプラインからVMやS3を継続的にスキャンして重大なCVE等の脆弱性を発見することを想定した実験メモです。
**<font color="DarkOrange">実験を実施頂く場合はOrca Securityのトライアルライセンスが必要になります。[こちら](https://orca.security/lp/cloud-security-risk-assessment/)から申請お願いします。</font>**

# 実験メモ
api.orcasecurity.io/api/assetsにGETリクエストを送信してOrca Securityがスキャンしたアセットを確認します。"asset_unique_id"のValueをメモします。
<img src="https://i.imgur.com/jQgq0qo.png" width=70%>

api.orcasecurity.io/api/assets/{{asset_unique_id}}にGETリクエストを送信してアセットの詳細を確認します。この実験ではAWS Ahtenaを対象としています。"cloud_provider_id"と"asset_unique_id"のValueをメモします。
<img src="https://i.imgur.com/hT7mwdZ.png" width=70%>

api.orcasecurity.io/api/scan/asset/{{assetType}}/{{cloudProviderID}}/{{providerAssetID}}にPOSTリクエストを送信してAthenaのスキャンを開始します。{{assetType}}には"db"を指定します。"scan_id"
をメモします。
<img src="https://i.imgur.com/4z9TyDw.png" width=70%>

api.orcasecurity.io/api/query/cves?dsl_filter={ "filter": [ {"field": "asset_unique_id", "includes": [ "scan_id" ]}]}にGETリクエストを送信して結果を確認します。この実験ではCVEの有無をチェックしています。CVEはありませんでした。Deployしても問題なさそうです。
<img src="https://i.imgur.com/hMq5Dvx.png" width=70%>

# まとめ
実験メモを拝見頂きありがとうございます。Cloud環境は従来のOn-premise環境と特性が異なるため、脆弱性や設定ミス等多くのセキュリティインシデントの温床を抱えていますね。"Shift Left"と言う言葉を聞かない日は無いくらいSDLCの初期フェーズでセキュリティをケアすることが安全なSoftwareサービスを提供するために重要な取り組みになってきました。仮想マシンやコンテナイメージのスキャンニングはCI/CDに組み込んでその筋の専門サービスに任せて開発に集中したいですよね。

# Orca Securityとは?
Gartner社が使いはじめたCNAPP(Cloud Native Application Protection Platform)にカテゴライズされるCloud Securityに特化したSolutionです。多くのお客様がAgent型のSolutionやAWS/Azure/GCPがNativeで持っているSecurity Solutionを利用しているかと思います。これらのSolutionはスケーラビリティやカバーできる範囲、Alertの重要度判別に課題を多く抱えており、実用には耐えられないものが大多数でした。Orca Securityはこれらの課題を解決すべく誕生しました。
SwiftのDictionaryについて

## Dictionary（辞書）の基本
Swiftの　Dictionary（辞書）は、「順序をもっておらず、キー(Key)と値(Value)が１セットになった複数のデータの集まり」です。

作成したキーは辞書の索引のようなイメージで、
キーを指定して、値の追加や削除、また取得することができます。
→　そのため、同じ名前のキーが複数存在すると混乱が起こってしまうので、辞書のキーは一意的ものである必要があります。

## Dictionaryの作り方
```Swift
var dict1:[String: Int] = [:]
var dict2 = [String: Int]()
var dict3: Dictionary<String, Int> = [:]
var dict4 = Dictionary<String, Int>()
```
公式ドキュメントでは１と２行目の[Key:Value]de
表記することを推奨しています。

さらに、型推論も使用できるので、データ型の省略もできます。
```swift
var dict = ["Key1": 10, "Key2": 5, "Key3": 7, "Key4": 10]
```

⚠︎値のデータ型がキーごとに違うような場合は、作る際に型の省略はできません。
```swift
var student:[String : Any] = ["Name": "Tanaka", "Age": 17, "Gender": "M"]
```

## Dictionary（辞書）の値を取得する
Dictionaryのキーに対応している値を取得するには
[ ] を使ってキーを指定します。

```swift
let dict = ["a": 1,"b": 2,"c": 3]
print(dict["a"] ?? "Not Found")  //1
```

##  Dictionary（辞書）の値を変更する
Dictionaryの値を変更するには、角括弧［ ］を使ってキーを指定し、そこに新しい値を代入します。
```swift
var dict = ["Key1": "orange", "Key2": "peach", "Key3": "banana"]
print(dict)

dict["Key1"] = "grape"
print(dict) 
```
結果は
["Key1": "orange", "Key2": "peach", "Key3": "banana"]
["Key1": "grape", "Key2": "peach", "Key3": "banana"]
となります。

## Dictionaryにキーと値のペアを追加する
Dictionary（辞書）にキーと値のペアを追加するには、［ ］を使って新しいキーを指定して値を代入します。
```swift
var dict: [String: Int] = [:]
print(dict)

dict["Key1"] = 1
print(dict)

dict["Key2"] = 2
print(dict)
```
結果は
[:]
["Key1": 1]
["Key1": 1, "Key2": 2]
となります。
Godot Engine で 作ったゲームを RasberryPie で 動かしたい！


注意事項：
この記事では、ゲームの作り方に関しては解説しません。
他にたくさん解説されている記事がありますので、Godot Engineで調べてください。

## Godot Engine とは？
OSSのゲームエンジン 2Dゲームを作るには最適。
2022/6/23 現在では3.4.4 が最新版。

Godot Engine
https://godotengine.org/

## Rasberry Pie とは？
教育用で作られた、小型パソコン
小型のゲーム機を作る みたいなことができる。
https://www.iodata.jp/product/pc/raspberrypi/ud-rp4b/index.htm
自分はここで買ってたので、RasbeanというOSが入っていました。

## どうやって動かす？
Godot Engine は、マルチプラットフォームでプロジェクトをエクスポートすることができるが
Linux(x11)のエクスポートテンプレートを使ってそのまま動作させることはできない。

非公式だが、以下のようなエクスポートテンプレートが存在するので、これを使う。
https://github.com/hiulit/Unofficial-Godot-Engine-Raspberry-Pi
1. Downloadsにある、自分の手持ちの RasberryPie のバージョンと、 GodotEngineのバージョンに合った
エクスポートテンプレートをダウンロードする。
![スクリーンショット 2022-06-30 16.58.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2724258/47e56bef-fd33-8775-d466-e8d3b7ec11c4.png)


2. GodotEngineを起動し、エクスポートしたいプロジェクトを開き、エクスポートを選択
![スクリーンショット 2022-06-28 23.23.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2724258/613f61c8-ec54-b472-d24a-7f77baab0b68.png)

3. RasbeanのOSを利用している場合は、Linuxベースになるので、
エクスポートはLinux(x11)を選ぶ。
エクスポートテンプレートファイルを選択するところがあるので、そこに1.で落としたファイルを設定する。
![スクリーンショット 2022-06-28 23.23.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2724258/f971621f-eccb-9c13-fce5-a89a04011e8b.png)

4. デバッグ情報を含めるのチェックをOFFにして、エクスポートする
![スクリーンショット 2022-06-28 23.24.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2724258/3de74056-ebc9-b7fb-eb78-14b35a56a369.png)

5. USBメモリやSSHなどでRasberryPieに出力したファイルをコピーする

6. 実行権限をつけて、起動する

7. 起動できた！

# 最後に
RasberryPieにて、OpenGLの設定を有効にしないと重くて動かなかった。
また、このエクスポートテンプレートは Godot非公式のエクスポートテンプレートです。利用は自己責任でお願いします。
機種依存文字を置換 PHP


```
<?php

namespace App\Libs;

/**
 * 文字コード
 */
class CharacterEncoding
{

    /**
     * 機種依存文字を文字化けしない文字に変換
     *
     * @param string $str
     * @return string
     */
    public function replaceMachineChar(string $str): string
    {
        // 現在の文字コードを取得
        $_encode = mb_detect_encoding($str);

        // SJIS-winに変換
        if ($_encode != "SJIS-win") {
            mb_convert_encoding($str, "SJIS-win", $_encode);
        }

        $search = array(
            'Ⅰ', 'Ⅱ', 'Ⅲ', 'Ⅳ', 'Ⅴ', 'Ⅵ', 'Ⅶ', 'Ⅷ', 'Ⅸ', 'Ⅹ',
            'ⅰ', 'ⅱ', 'ⅲ', 'ⅳ', 'ⅴ', 'ⅵ', 'ⅶ', 'ⅷ', 'ⅸ', 'ⅹ',
            '①', '②', '③', '④', '⑤', '⑥', '⑦', '⑧', '⑨', '⑩',
            '⑪', '⑫', '⑬', '⑭', '⑮', '⑯', '⑰', '⑱', '⑲', '⑳',
            '№', '㈲', '㈱', '㈹',
            '㊤', '㊦', '㊥', '㊧', '㊨',
            '髙', '﨑', '彅', '塚', '增', '寬', '敎', '晴', '朗', '﨔', '橫', '德', '瀨',
            '淸', '瀨', '凞', '猪', '益', '礼', '神', '祥', '福', '靖', '精', '濵', '琦', '昻',
            '緖', '羽', '薰', '諸', '賴', '逸', '郞', '都', '鄕', '閒', '隆', '靑', '飯', '飼', '館',
            '鶴', '黑',
            '㍉', '㌔', '㌢', '㍍', '㌘', '㌧', '㌃', '㌶', '㍑',
            '㍗', '㌍', '㌦', '㌣', '㌫', '㍊', '㌻',
            '㎜', '㎝', '㎞', '㎏', '㏄', '㎡',
            '㍻', '〝', '〟', '℡', '㍾', '㍽', '㍼', '㏍'
        );

        $replace = array(
            'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', 'X',
            'i', 'ii', 'iii', 'vi', 'v', 'vi', 'vii', 'viii', 'ix', 'x',
            '(1)', '(2)', '(3)', '(4)', '(5)', '(6)', '(7)', '(8)', '(9)', '(10)',
            '(11)', '(12)', '(13)', '(14)', '(15)', '(16)', '(17)', '(18)', '(19)', '(20)',
            'No.', '（有）', '（株）', '(代)',
            '(上)', '(下)', '(中)', '(左)', '(右)',
            '高', '崎', 'なぎ', '塚', '増', '寛', '教', '晴', '朗', '欅', '横', '徳', '瀬',
            '清', '瀬', '煕', '猪', '益', '礼', '神', '祥', '福', '靖', '精', '濱', '埼', '昂',
            '緒', '羽', '薫', '諸', '頼', '逸', '郎', '都', '郷', '間', '隆', '青', '飯', '飼', '館',
            '鶴', '黒',
            'ミリ', 'キロ', 'センチ', 'メートル', 'グラム', 'トン', 'アール', 'ヘクタール', 'リットル',
            'ワット', 'カロリー', 'ドル', 'セント', 'パーセント', 'ミリバール', 'ページ',
            'mm', 'cm', 'km', 'kg', 'cc', '平方メートル',
            '平成', '"', '"', 'TEL', '明治', '大正', '昭和', 'K.K.'
        );

        $result = str_replace($search, $replace, $str);
        // 半角カナを全角カナ 全角英字を半角英字
        // $result = mb_convert_kana($result, "KV");

        // 機種依存文字を変換
        // $ret = str_replace($search, $replace, $str);
        // UTF-8に変換
        // $result = mb_convert_encoding($ret, 'UTF-8', "SJIS-win");

        return $result;
    }
}
```

# 参考
https://gist.github.com/Yashi100/d9ef8184926b79374fedeeba52d7bd95
MQTTとAMQPの比較

本来、比較すべきものでもないのかもしれませんが、日本語の記事があまりないので、下記のページ内の表を和訳したメモ。
https://www.intuz.com/blog/mqtt-vs-amqp-iot-protocols-you-must-know

|パラメータ  |MQTT  |AMQP  |
|---|---|---|
|定義  |シンプルなメッセージキューイングサービスを提供し、主に組込みシステムで実装可能  |さまざまなメッセージング環境を提供し、セキュリティプロトコルに関してはパフォーマンスが向上します|
|背景  |MQTTは主にベンダー主導であり、IBMによって開発されました  |JPモルガンは金融アプリ向けのAMQPを開発しました  |
|アーキテクチャー  |client/broker アーキテクチャー  |client/broker、およびclient/server アーキテクチャー  |
|プロトコル設計  |TLSを使用してメッセージングを暗号化したり、OAuthなどの最新のプロトコルを使用してクライアントを認証したりするプロセスを簡素化します  |publisher/subscribeとrequest/responseの両方のタイプの通信を実行するTCPベースのプロトコルです。 |
|最適化フレームワーク  |軽量メモリデバイスのストリームライクなアプローチを採用したwireフレームワークをベースにしています  |データフレームワークのワイヤーに最適化されており、バッファリング方式を採用し、サーバーの性能を高めています。  |
|メッセージサービス  |MQTTは非常に過渡的であり、結果的にリンクされたパブリッシャーとサブスクライバーのアクティブルーティングに最も適しています。  |AMQPは、バルクメッセージングを含むあらゆる種類のメッセージングを可能にし、メタデータメッセージを実行することができます。 |
|メッセージトランザクション  |一般的なアクノリッジを比較的早くサポートすることで知られている  |様々なアクノリッジやトランザクションに対応しています。  |
|データコンテキスト  |データキャッシュとプロキシを部分的にサポートしています。  |AMQPは、データキャッシュとプロキシをフルサポートしています。  |
|実証済みのセキュリティ  |アドオンサービスを使用してセキュリティを強化することはできますが、関連するセキュリティの問題には対応していません。 |AMPはTLSとSASLのポリシーを排除し、継続的な更新のパフォーマンスを迅速に向上させます  |
|最後の値のキュー  | コマンドの保持を提供し、キューの最後の値をスムーズにサポートします。 |キュー内の最後の値に関する規定やサポートがないため、制限になることがある  |
|効率とスケーラビリティ  |ワイヤーエフィシェントであるため、AMQPよりもクライアント側の実装に手間がかからない  |メッセージストリームにサブスクリプションを作成することができないので、拡張性がない。  |
|信頼できるメッセージング |そのデータ配信は信頼性が高く、適切です  |fire-and-forgetポリシーのみ有効です。AMQQPは信頼性がない |
|ネームスペース  |MQTTはメッセージの送信に名前空間を階層的に展開する |AMQPでは、キューやノードなど、メッセージを見つけるための複数の方法が用意されている |
|追加属性  |MQTTは、DNSサーバーの基本要件を満たしています。非同期式であり、高度な機能はサポートされていない |AMQPはピアツーピア接続をサポートしており、ネットワーク全体の負荷分散や多重化を行うことができる |
|実装 |64kb以下のRAMを搭載したデバイスに実装可能です。|64kb以下の小さな要素で実装されています。 |
|拡張性 |MQTTは、プロトコルのドラフトが一新され、他のプロトコルよりもはるかに広い拡張性を持つようになった |特定の方法で拡張でき、分離してレイヤーを変更できる構造上のポイントを持つ  |

ほぼ機械翻訳なので、自分でも意味の分からない表現が。。。
気の利いた日本語があれば教えて下さい。
Laravelでテーブルのカラムを後からNULLを許可したいんですけどっ！？？

# テーブルのカラムにNULLが入ってもOKにする

カラムを**後から**`nullable`に変更する方法を紹介するZE☆

Laravelドキュメントの[マイグレーション](https://readouble.com/laravel/8.x/ja/migrations.html)内を分かりやすく噛み砕いたものやで👍

> 俺「nullableってなんやねん」

って人はこちらを参照↓

https://qiita.com/Sunasuna24/items/7751cd41accfb337a127

カラムにNULLが入ってもOKするよ🙆‍♂️

:::note
解説するLaravelドキュメントはバージョン8.xです。
:::

# めちゃ簡単なmigrationのおさらい

簡単にmigrationについておさらいするよ！

- migrationの生成コマンド

```sh
# create_flights_table部分はよしなに
php artisan make:migrate create_flights_table
```

- migrationの実行コマンド

```sh
php artisan migrate
```

簡単に言うと、既存のカラムをnullableに変更するためのmigrationファイルを生成して、nullableに変更するコードを書いたら、そのmigrationを実行するだけ👍

# テーブルの更新

`Schema`ファサードの`table`メソッドを使うことで既存のテーブルを更新できるよ！

以下がカラムの設定を更新するときのmigrationファイルの例だよ！

```PHP
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

Schema::table('users', function (Blueprint $table) { // この行の先頭がSchemaのtableメソッドになってる！
    $table->integer('votes');
});
```

テーブルを**作成**するときは`Schema`ファサードの`create`メソッドを使ってるんだよね。

テーブルを**更新**するときは`table`メソッドを使おうね👍

※以下、テーブルを作成するとき(`create`メソッドを使っているとき)の例

```PHP
// これはテーブルを新規に作成するときのメソッドやで
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

Schema::create('flights', function (Blueprint $table) { // テーブルの作成のときはSchemaのcreateメソッド
    $table->id();
    $table->strint('name');
});
```

# カラム属性の更新

すでに設定済みのカラムについて変更したいときは`change`メソッドを使おう！

例えば文字列を格納できる`string`カラムのサイズを大きくしたいとしよう。

`string`カラムは第一引数にカラム名、第二引数にサイズを指定する。

`string`でできている`name`カラムのサイズを25から50に後から変更したいときはmigrationにこんなふうに書こう！

```PHP
Schema::table('users', function (Blueprint $table) {
    $table->string('name', 50)->change(); // 最後にchange()を忘れないでね！
});
```

すでに`name`カラムがあるとき、そのサイズが50になるように`change`しているよ！

# nullableにも変更しちゃおう！

- カラムを変更する方法(=`change`メソッドを使う)を学んだ
- LaravelでカラムにNULLが入ってもOKな方法(=`nullable`メソッドを使う)も知ってる
    - (知らない方は[こちらの記事](https://qiita.com/Sunasuna24/items/7751cd41accfb337a127)を参照)

両方を同時に行うことで、カラムを後からnullableに変更できるでっ！

さっきの`name`カラムのサイズを25から50に大きくして、かつnullableに変更するのは以下。

```PHP
Schema::table('users', function (Blueprint $table) {
    $table->string('name', 50)->nullable()->change(); // nullableに後から変更してるよ！
});
```

もちろん`string`カラムのサイズ変更がないんだったら、シンプルに`$table->string('name')->nullable()->change();`とすれば`name`カラムがnullableになるだけ👍

# 最後の大仕事(doctrine/dbal)

カラムを変更するmigrationファイルを作成したので、あとは`php artisan migrate`で実行するだけです！


かと思いきや実はまだ足りない作業が1つあります。

`doctrine/dbal`というパッケージをインストールしないといけません。

過去に1度でもインストールしていればOKです！

※この記事を読んでいるということは、恐らく`doctrine/dbal`をインストール済みではないかと予想しますが(笑)。

`doctrine/dbal`のインストールするコマンドはこちらです！

これをシェル（ターミナルやコマンドプロンプトなど）で実行してみてください！

```sh
composer require doctrine/dbal
```

# やっと変更できる😉

これで`doctrine/dbal`もインストールされたので、`php artisan migrate`を実行するとカラムがnullableに後から変更できます👍

# お詫び

これまで一度作成したカラムを後から変更する方法をご紹介してきましたが、実は後から変更できるカラムは以下の種類しかできないと決まっています。

下記のカラム以外を変更しようとされていた方、全能感を演出して申し訳ないです汗

直接SQLを実行するなど、別の方法を検討しましょう。

- bigInteger
- binary
- boolean
- date
- dateTime
- dateTimeTz
- decimal
- integer
- json
- longText
- mediumText
- smallInteger
- string
- text
- time
- unsignedBigInteger
- unsignedInteger
- unsignedSmallInteger
- uuid
C++ hot-reload で GUI アプリとか開発したいメモ

## 背景

C++ での GUI アプリ開発とかだと, 毎回コンパイルめんどい...
React みたいな感じでリロードしたい..

jet-live と blink がありました!

### Linux

https://github.com/ddovod/jet-live

### Windows

https://github.com/crosire/blink
[JavaScript]map()で連想配列から特定keyの値を取得する

# はじめに
今回は、JavaScriptのmap()について学んだことをまとめておきたいと思います。

map()の基本構文の説明後、タイトルのサンプルコードを紹介します。

# 目次
[1.mapメソッドとは](#1-mapメソッドとは)
　[1-1.基本構文](#1-1-基本構文)
　[1-2.サンプルコード](#1-2-サンプルコード)
[2.本題](#2-本題)
[3.参考記事](#3-参考記事)

# 1. mapメソッドとは

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/map

map()は、元となる配列から新しく配列を作るためのメソッドです。

配列の各要素に対して与えられたコールバック関数を実行し、関数の戻り値で
新しい配列を生成します。

コールバック関数の引数には
- 第１引数：現在処理されている要素の値
- 第２引数：現在処理されている要素の配列内におけるインデックス（**省略可**）
- 第３引数：現在処理している配列（**省略可**）

の３つを渡すことができます。

## 1-1. 基本構文
```js
配列データ.map(( value, index, array ) => {
   // 新しい配列の要素を返す
})
```

## 1-2. サンプルコード
以下は、配列の要素に2を掛けて新しい配列を生成したサンプルコードです。
```js
const arr = [1, 2, 3];

const newArr = arr.map(value => {
  return value * 2;
});

console.log(arr);
// [1, 2, 3]

console.log(newArr);
// [2, 4, 6]
```
上記の結果から、元の配列には手を加えずに、**新しい配列が返り値となっている**ことが分かります。

# 2. 本題
### 連想配列から特定keyの値を取得する

`obj.name`で、オブジェクトのプロパティにアクセスします。
それをmap()と掛け合わせて、プロパティの値で配列を作成します。

```js
const objArr = [
  {id: 1, name: 'Taro'},
  {id: 2, name: 'Koki'},
  {id: 3, name: 'Hiro'}
];

const names = objArr.map(obj => obj.name);

console.log(names);
// ["Taro", "Koki", "Hiro"]
```
以上で実装完了です。

シンプルに書けるので、より可読性が上がったなと感じました。

map()は、配列の各要素に対してさまざまな処理を行うことができて便利なので、
これからもうまく活用していきたいと思います。

# 3. 参考文献

https://swallow-incubate.com/archives/blog/20191023

https://tcd-theme.com/2021/07/javascript-array-map.html
SPAにおけるGTM・GAの検討事項

## 概要

シングルページアプリケーション（SPA）のCSR（Client Side Rendering）での画面
切り替えでは、GTMのロードが発生せず、またHTMLの要素を動的に変化させない場合は思わぬログ欠落が発生することがあります。

「タグをそのまま貼った結果、フロントエンド実装後の疎通確認のタイミングで問題が起きた」というのは割とよくあるケースなので、よくある問題と対策を記しておきます。

※ここではGTM側の細かい設定方法については触れません。

## よくある問題

### 1) ページビュー
ページ遷移が発生しないため、GTMもロードされずページビューのログが飛ばない。

→ 都度グローバルのオブジェクトをリセットし、gtm.jsをロードする必要がある or dataLayerのカスタムイベント経由でページビューを発生させる。

### 2) ページタイトルディメンション
titleタグが変更されないため、ページタイトルディメンションが固定される。

→ titleタグを動的に変化させる or GTM（dataLayer）側でディメンションを上書きする必要がある。

### 3) 「前のページの遷移」ディメンション
document.referrerが変化しないため、UAにおいては「前のページの遷移」ディメンション、GA4においては「page_referrer」パラメーターが固定される。

 ----- （2022年12月編集・追記 ここから） -----

~~→ GTM（dataLayer）側でディメンションを上書きする必要がある。~~

**Universal Analyticsにおいては**referrerはトラフィックソースの算出に利用されるため、ページ遷移ごとにreferrerをセットしてしまうと 都度新規セッションとなってしまいます。（セッション数やトラフィックソースの計上が狂ってしまいます）
Universal AnalyticsではSPAでもURL自体が正しく変化していれば正しく計上できるはずです。

> ウェブサイトにトラフィックを送り込んだ参照ソースを指定します。この値はトラフィック ソースの算出にも使用され、値の形式は URL となります。このフィールドは create コマンドで初期化され、alwaysSendReferrer フィールドが true に設定されている場合を除き、現在のホスト名が参照 URL のホスト名と異なる場合にのみ設定されます。
> https://developers.google.com/analytics/devguides/collection/analyticsjs/field-reference?hl=ja

なお、GA4においてはページ遷移の度にドメイン関係なく drパラメータがセットされています。

------- （ここまで） --------

### 4) クリックイベントのページ情報
クリックイベントの関数実行より前にDOM構築が完了してしまい、「遷移先ページで発生したイベント」としてログ計測される。

※「ページAでのURLクリックでクリックイベントが発生して、ページBに遷移」の場合に、そのクリックイベントがページBで発生したように計測される。

→ クリックイベントの実行タイミングを担保する必要がある。


## 対策

### GA/GTM関連のオブジェクトのリセット

画面遷移を遷移してもグローバルオブジェクトがリフレッシュされないため、GA/GTM関連のリセット処理を都度実行します。

```javascript
google_tag_manager["GTM-${CONTAINER_ID}"].dataLayer.reset()
```

GAのトラッカー名を指定している場合は念のためトラッカーもリセットします。
```javascript
ga('${TRACKER_NAME}.remove’)
```


### カスタムイベント（dataLayer）を使ったページビューの送信

画面遷移ごとに、GTMのカスタムイベント経由でページビューを発生させます。

なお、 `pageUrl`、`pageTitle`、`previousPageUrl`もdataLayerにセットし、GTM側で設定フィールドのオーバーライドします。
これにより `ページURL`と`ページタイトル`のディメンションを動的に変化させることができます。

```javascript
dataLayer.push({
    'event': 'csr_pageview', 
    'pageUrl': '${pageUrl}',
    'pageTitle': '${pageTitle}',
    'previousPageUrl': '${previousPageUrl}',
}); 
```
※previousPageUrlはGA4のみ利用します。UAでリファラー上書きを行うとセッション数が狂います。

※「画面遷移であればCSR、直接のURLアクセスであればSSR(Server Side Rendering)」といった実装パターンもあると思いますので、カスタムイベント名は `csr_pageview` 、 `ssr_pageview`のように2つ用意し、個々のレンダリングでイベント処理を分けておくといいと思います。

#### ※dataLayerのpush()のタイミングに注意

「DOM構築の完了やURLの変更より前にdataLayer.push()をしてしまう」と、前のページの情報でページビュー送信されてしまいます。
このため実行順序の担保が必要ですが、フロントエンドのフレームワークの都合上難しい場合にはpush()のタイミングを `setTimeout(func,0)` で遅延させることで解決するかもしれません。

### クリックイベントの実行タイミングの調整

「クリックイベントの実行よりも前にDOM構築やURLの変更が完了する」場合は、クリックイベントが先に実行されるような形で順番を担保することが必要です。 

## おわりに

「SPAのページで正常にログが取れていないが、何が起きているかわからない」といったケースは散見されます。疎通確認のタイミングでの実装変更を避けるためにも、事前にSPA対応の方法を把握しておくと良いと思います。

また、ログの疎通確認も慎重に行うことをおすすめします。

## 参考URL
https://developers.google.com/analytics/devguides/collection/analyticsjs/command-queue-reference?hl=ja#remove

https://twitter.com/SimoAhava/status/823753362843770888
if文の条件式をちゃんと書くようにした話

if文の条件式を

```js
// 省略した書き方
if(a) {
  // ...
}
```

ではなく、
```js
// 省略しない書き方
if(a === true) {
  // ...
}
```
と書くようにした話です。

※ここでは主に、JavaScriptを想定して説明します。
他の言語等にも共通する話ですが、各値を条件式に入れた時にTrueとして扱われるのか、はたまたFalseなのか厳密な判定はきちんと調べていないので、その点ご了承ください。

# これまでは
もともとプログラミング初心者の頃は下側の**省略しない書き方**をしていました。
ですが、各言語の理解が深まる内に、`0`や`undefined`や`null`を条件式として評価した時に、`false`として扱われる事を知ってからは上側の**省略した書き方**を使うようになり、最近までこの書き方を多用していました。

# 省略した書き方のメリット
## コードが短くなる
条件式が短くなって、すっきりしますね。
(これくらい？)

# 省略した書き方のデメリット
## どんな値が来るか分かりづらい
**省略した書き方**をやめた理由として、正直これが大きいです。
このif文を見た時、変数`a`が論理値なのか、数値なのか、文字列なのか分からないですよね。
例として、変数`a`には文字列が入る可能性があって、何も入らなかった場合(undefined)にとあるの処理を行いたい時、以下のように書けます。
```js
if(!a) {
	// とある処理
}
```
ですが、これだけ読むと`a`には何が入り、どういった時にこの処理を通したいのか、コードを書いた人の意図が推測しづらいです。


JavaScriptの場合、上のコードのだと変数`a`が以下の値でも処理が通ります。
- false
- 0
- null
- undefined
- "" (空文字)

もちろんJava等の静的型付けの言語であれば定義を読めば型は分かりますが、それでも定義までさかのぼる必要があります。
また、JavaScript等の動的型付けの言語は型の定義が無いので、その変数に代入している箇所を探す必要があり、かなり手間です。

## 想定外の値を通してしまう
**省略した書き方**だと、仮に「変数`a`には論理値が入ると想定していたのに文字列が入っていた」場合、処理が通ってしまうことがあります。
（論理値を想定していたのに文字列が入ることは少ないかもしれませんが、`undefined`のままだったという事は多いと思います。）


# 省略しない書き方に変えた結果
上記のデメリットがだいぶん軽減されました。
たとえば以下のように、そこを読むだけで変数`a`にどんな値が入ることを想定しているのかが分かりやすい。
```js
if(a === "hoge") {
	// ...
}
// なるほど、変数aには「文字列」が入るのか...
```

```js
if(a === 1) {
	// ...
}
// なるほど、変数aには「数値」が入るのか...
```

```js
if(a === false) {
	// ...
}
// なるほど、変数aには「論理値」が入るのか...
```

当然、変数に`a`なんて分かりづらい名前を付けるから分かりづらいのであって、実際はもっと分かりやすい名前を付けると思います。
しっかり命名規則に則った[分かりやすい変数名](https://qiita.com/3087kt/items/df96c2774778ab687258)を使えば、ある程度変数の中身を推測することはできますが、それに加えて上記のように書くことで、より読みやすいコードになると思います。

# まとめ
if文には、変数をつっこむだけの雑な条件式をやめると、読みやすいコードになるかも？という話でした。

自分が書いたコードでさえ、数ヶ月経って読むと分からなくなるので、省略せずに書いてあるとだいぶラク。
この書き方にしてからコードを読んで理解するスピードが上がったと思います。

もし、「**省略しない書き方**にはこんなデメリットがあるぞ」などありましたら、コメントにて教えてください。
M5Paper: ボタン (G37,G38,G39) の操作

## プログラム ##

```text:button.ino
// ---------------------------------------------------------------
//	button.ino
//
//					Jun/23/2022
// ---------------------------------------------------------------
#include <M5EPD.h>

M5EPD_Canvas canvas(&M5.EPD);

// ---------------------------------------------------------------
void ButtonTest(char str[])
{
	canvas.fillCanvas(0);
	canvas.drawString(str, 100, 200);
	canvas.pushCanvas(0,0,UPDATE_MODE_DU4);
	delay(500);
}

// ---------------------------------------------------------------
void setup() {

	M5.begin();
	M5.EPD.SetRotation(90);
	M5.EPD.Clear(true);
	canvas.createCanvas(540, 960);
	canvas.setTextSize(3);
	const int xpos = 100;
	canvas.drawString("Push Button", xpos, 200);
	canvas.drawString("G37", xpos, 300);
	canvas.drawString("G38", xpos, 350);
	canvas.drawString("G39", xpos, 400);
	canvas.pushCanvas(0,0,UPDATE_MODE_DU4);
}

// ---------------------------------------------------------------
void loop()
{
	if( M5.BtnL.wasPressed())
		{
		ButtonTest("Btn L G37 Pressed");
		}

	if( M5.BtnP.wasPressed())
		{
		ButtonTest("Btn P G38 Pressed");
		}
	if( M5.BtnR.wasPressed())
		{
		ButtonTest("Btn R G39 Pressed");
		}

	M5.BtnL.lastChange();

	M5.update();
	delay(100);
}

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

Arduino IDE
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/7f4d323c-efd3-0639-56e3-0fb1b4e2f7b5.png)
NginxとApacheの競合を避けて、wwwユーザに統一した

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

NginxとApacheの権限が競合しているようで、以下のようなWarningが出た。
```
Warning: session_start(): open(/var/lib/php/session/sess_cgc4v1d02oej4dp08u45ud3mkf, O_RDWR) 
failed: Permission denied (13) in /opt/php74/webapps/.../xxx.php on line 40
```
また、WordPressを触っていると、以下のようなエラーも出た。wp-content/uploadsデイレクトリの権限が足らないようだ。
```
ディレクトリ wp-content/uploads/2022/06 を作成できません。
この親ディレクトリのアクセス権はサーバーによる書き込みを許可していますか ?
```
ネット情報を参考に、`www`というユーザーとグループを作成して、それを統一的に使うようにした。その方が無難と判断した。
```
$ useradd -s /sbin/nologin -M www
$ cat /etc/passwd
...
www:x:1004:1004::/home/www:/sbin/nologin
```
修正が必要な設定ファイルは、以下のとおり。ユーザがapacheやnginxになっていた箇所を`www`に置き換えた。
```
$ vi /etc/php-fpm.d/www.conf

  ;user = apache
  user = www
  ;group = apache
  group = www
  ;listen.owner = apache
  listen.owner = www
  ;listen.group = apache
  listen.group = www
  ;listen.acl_users = apache,nginx		// ここはコメントアウトしておく
  ;listen.acl_groups =

$ vi /etc/nginx/nginx.conf

  # user nginx;
  user www;

$ vi /etc/httpd/conf/httpd.conf			// httpdは現在停止中だが、念のため

  # User apache
  User www
  # Group apache
  Group www
```
該当するファイルやディレクトリの権限も変更しておく。
```
$ cd /var/lib/php			// 冒頭のWarningの元なので変更しておく
$ chown -R www:www .
$ cd /var/www/html			// 使っていないが、念のため
$ chown -R www:www .
$ cd /opt/php74/webapps		// こちらを使っている
$ chown -R www:www .
$ cd /opt/php74/webapps/wordpress/wp-content
$ chmod 775 uploads
```
サービスを再起動する。（※httpdは、現在停止中）
```
$ systemctl restart nginx
$ systemctl restart php-fpm
```
|[../](https://qiita.com/taconana/items/d382d08a83a2a67f3b6a) |
|---|
Vue3(3.2)でvue.draggable.nextを使う

なぜ改めてVueDraggableについて記事を立ち上げたのか？

ここ最近、新しく作る物には練習を兼ねてLaravel＋Vue3で作るようにしています。

で、ふと「並び替えて」保存する必要が出てきました。

まぁここはVueDraggableの出番なので、Vue3対応とか色々調べてみたところ、
パッケージが他のVue3対応と同じように「next」付きになっている事に気が付きました。

https://github.com/SortableJS/vue.draggable.next

そこで使ってみると若干書き方が変わっている。

今までのだとリンク内にもありますがめっちゃ簡略化して書くと
展開するリスト（オブジェクト配列）が「myArray」としますと
```vue2
<draggable v-model="myArray">
    <div v-for="(item , index) in myArrayt" :key="index">
        {{item.name}}
    </div>
</draggable>
```
って感じがベーシックな感じかと。

今回私が問題だったのは例のコードで言う「index」がさっとわからなかった所。

並び替えてその順番を保存したいだけならindexすら書く必要がありませんが、内容も保存して一緒に更新したいとかですとindexが無いと中身を更新するのが手間になります。
例コードを少し書き換えれば
```vue2(vue.draggable )
<draggable v-model="myArray">
    <div v-for="(element, index) in myArray" :key="index">
        もとの値：{{ element.name }}
        変更後の値：<input type="text" v-model="myArray[index].name" />
    </div>
</draggable>
```
みたいな感じでしょうか？
これで10行あったとしてそれぞれを更新するような事が可能になります。

で、結局はこれをnextで書くとしたら？？？って事だったんです。

結論はgithubにちゃんと書いてあったんですけど、かなり下の方で、私のやりたいことをみんなは違うやり方で実行しているのだろうか・・？

上記をnextで書いてみます（簡略化）
```vue3(vue.draggable.next)
<draggable :list="myArray" item-key="id">
    <template #item="{ element , index }">
        もとの値：{{element.name}}
        変更後の値：<input type="text" v-model="myArray[index].name" />
    </template>
</draggable>
```
こうなります。
ループ部分が「template」でくくる事になったところが主だった新しい書き方なんですが、gitのコードはひたすら「#item="{ element}"」としか書いてない。
かなり下の方にやっと「{element , index}」が書いてあって「あっ！！！」ってなりました。

答えがわかればv-forとの対応で「ああ、当たり前だな！」ってなるんですが、発見するまで1時間以上試行錯誤してしまいました・・

一応Vue3.2(.37)で書いてますが、多分3以上なら同じではないでしょうか。

わざわざ記事を立てるまでではないかと思いましたがちゃんと結論が出たので忘備録で残しておこうかと思いました。
コンピュータは電気でものを考える

情報という名のデータをコンピュータの力を借りて処理してる。
データをサクサク処理してくれるからコンピュータは便利なのだ。

# どうやって電気でものを考えているのか？
コンピュータに話しかけても何も起こらない。
コンピュータは独自の考え方をしている

# コンピュータは０と１で考えている
コンピュータは```オンなら１``` ```オフなら０```と２つの数字しか理解できない。
1と０の組み合わせで複雑な表現をしている。
単純だが```高速に大量の１と０を処理```することができる。
モールス信号と似ている。
オンとオフしか表せない```最小単位```をコンピュータの世界では```bit```という。

気づき
オンオフを2回すると４bitになるのか。
０と１を最初書いたけどオンオフにするには１と０がいいな。
コンピュータは```１と０しか理解```できない。
本当にモールス信号みたいだな
コンピュータは１と０を```コツコツと処理```しているのか

## よしこれから頑張ろう
ClickHouseにWindowsのODBCで接続する

ClickHouseにWindowsのODBCで接続しました。

* テスト環境
    * Windows 10
    * ClickHouse 22.6.1.1985
    * ClickHouse ODBC Driver Release 1.1.10.20210822


# 1. ODBCドライバーのダウンロード
以下からODBCドライバーをダウンロードします。

https://github.com/ClickHouse/clickhouse-odbc/releases

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/421c1212-def6-246c-fbb8-a06e76f25475.png)


# 2. ODBCドライバーの導入

clickhouse-odbc-1.1.10-win64.msiを起動します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/6137dd2f-152a-aabd-dff5-9d3aa369eb1b.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/330429c8-eb54-8203-dbd6-34530bedd894.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/de16ec76-c17c-e4da-22a5-a6098e730672.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/042357fa-71f2-5163-bf31-e7b21196c97c.png)


# 3. データソースの作成

Windowsのスタートメニューから「ODBCデータソース（64ビット）」を起動します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/a012d8b7-a223-4b74-c392-8901f42b9481.png)

データソースの追加を行います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/798d548f-5aa3-dbbf-2448-8e0f462c18ce.png)

ClickHouse ODBC Driver（Unicode）を選んで完了します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/ec8c77dc-85b8-4d53-895a-9eb198899299.png)

接続情報を入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/ad8475ca-190d-6bcc-adc9-9ffa8b03434e.png)

パラメーターの詳細は以下にあります。
ここでは非SSL接続なので8123ポートにつないでいます。SSL接続の場合は8443になります。
https://github.com/ClickHouse/clickhouse-odbc


# 4. Excelからテスト接続
Excelのデータからデータの取得で「ODBCから」を選びます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/29f02e84-a439-9294-3406-b4d61ee42a54.png)

先ほど作ったDSNを選びます。
SQLステートメントにもなにかSELECT文を書きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/22bb3759-5e93-06f4-c449-3c1e8b728a2a.png)

ユーザー名とパスワードを入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/25912e42-a743-c211-5bda-f0a828223d1a.png)

正しく読むことができました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/adc03bdb-0379-766e-3d95-571f6b954334.png)
俺「nullableってなんやねん」

# カラムにNULLが入ってもOKになるよ

まずは`nullable`の説明から。
`nullable`分かるよ！って方は「[架空のテーブルでnullableを使ってみよう！](#架空のテーブルでnullableを使ってみよう)」までスキップ！🙆‍♂️

LaravelではあるカラムにNULLが入ってもOKなときはmigrationで`nullable`を指定します。

以下は`nullable`について[日本語ドキュメント](https://readouble.com/laravel/8.x/ja/migrations.html)の引用。

> NULL値をカラムに保存可能に設定

そう言うこと👍

逆にこれがないと基本的にカラムにNULLは保存できない。

# 架空のテーブルで`nullable`を使ってみよう！

記事が投稿できるサイトを仮定して、投稿(posts)テーブルを作成するときをイメージしよう！

`nullable`自体の実装はこんな感じ↓(migrationファイルの`up`メソッドのみ)

```PHP
/**
 * Run the migrations.
 *
 * @return void
 */
public function up()
{
    Schema::create('posts', function (Blueprint $table) {
        $table->id();
        $table->string('title');
        $table->text('body');
        $table->string('category')->nullable(); // ここでnullableを使っている！
        $table->timestamps();
    });
}
```

こんな風にmigrationを書いて実行すると、categoryカラムはNULLでも保存できるようになるよ！