OmniAICreator/Qiita-1.07M huggingface dataset:
論理演算 研修 備忘録

テーブル

|項目|権限1|権限2|
|----|----|----|
|英語|１|00001|
|国語|２|00010|
|数学|４|00100|
|理科|８|01000|
|社会|１６|10000|

|項目|権限|
|----|----|----|
|池田|１||
|加藤|２||
|坂口|４||
|田中|８||
|中原|１６||
|浜口|６|


##各先生が持っている教科
|名前|教科|SQL|
|----|----|----|
|池田|英語|1|
|加藤|国語|2|
|浜口|英語・数学|SELECT 2 ｜4 → 6| 

論理演算
真（true）と偽（false）の二通りの状態を取る真偽値（真理値/ブール値）の間で行われる演算。

|項目|説明|例|考え方|
|----|----|----|----|
|論理和|どちらかが真(1)なら真|select 2 OR 8 → 10|0010<br>1000<br>------<br>1010|
|論理積|どちらも真(1)なら真|select 2 AND 8 →0|0010<br>1000<br>------<br>0000|

```
SELECT 2 | 8 , 2 & 8;
```
https://e-words.jp/w/%E8%AB%96%E7%90%86%E6%BC%94%E7%AE%97.html


##国語をもっている先生を抽出するには （WHERE句で）
* 先生の権限 AND 国語 → 2（0010） → 国語を持っている
* 先生の権限 AND 国語 → 0（0000） → 国語を持っていない

|名前|先生の権限|国語|論理積|
|----|----|----|----|
|池田|0001|0010|0000|
|加藤|0010|0010|0010|
|浜口|0110|0010|0010|

```先生の権限と国語の権限を論理積
WHERE 1 & 2 ,2 & 2, 6 & 2
```

##国語と数学をもっている先生を調に抽出するには （WHERE句で）
* 先生の権限 AND （国語 OR 数学） → 0110 → true 国語と英語を持っている
* 先生の権限 AND （国語 OR 数学） → 0000 → false 国語と英語を持っていない

|名前|先生の権限|国語と数学|論理演算|
|----|----|----|----|
|池田|0001|0010 OR 0100|false|
|加藤|0010|0010 OR 0100|false|
|浜口|0110|0010 OR 0100|true|

```
SELECT
    t.*
FROM
    d_teacher AS t
WHERE
    t.authority & 3 = 3; 
```
POINT

|項目|説明|備考|
|----|----|----|
|=3|1と2のビットが立っている事を表現している||


##国語か数学をもっているか先生を抽出するには （WHERE句で）
```
SELECT
    t.*
FROM
    d_teacher AS t
WHERE
    t.authority & 3 <> 0 ; 
```
ポイント

|項目|説明|備考|
|----|----|----|
|<>0|0とは1も2もビットが立っていない状態。つまりどちらか一方でもビットがたつと、0にはならない||

##英語は持っているが国語は持っていない先生を抽出するには（WHERE句で）
```
SELECT
    t.*
FROM
    d_teacher AS t
WHERE
    t.authority & 3 = 1 ; 
```
POINT

|項目|説明|備考|
|----|----|----|
|3=1|1のビットが立っているが2のビットは立っていない事を表現している|||
|t.authority & 1 = 1 と t.authority & 2 = 0　|これら両方の条件みたすことを表現している|||
GASでGoogle Calendarの予定をGmailで送ってみる

## はじめに
最近GASでできることを記事にまとめているのですが、GASを使ってGmailを操作する方法をまとめていなかったので、Gmailの使い方を簡単にまとめてみようと思います。ただGmailの使い方をまとめると味気ないかなと思ったので、Google　Calendarの予定を送るスクリプトを作成してみようと思います。

## GASでGoogle Calendarの予定をGmailで送ってみる
### メールを送る
メールは以下のやり方で送ることができる

```javascript
GmailApp.sendEmail(宛先,件名,本文[,オプション])
```

#### 具体的なスクリプト

```javascript
function myFunction () {
    var subject = 'テストの件名';
    var text = 'テストのテキスト';
    
    var to = ['zumi0@example.com', // 宛先は、配列等で決められる
              'test@example.com' ];
    
    GmailApp.sendEmail(
        to,
        subject,
        text,
        {
        name: 'zumi0' // 送信者名
        }
    );
}

```

### 実際にGoogle Calendarの予定を取得してGmailを使ってメールを送信してみる
今回かいたスクリプトの概要は以下です。

- スクリプト実行時の日付を取得する
    - 今回は`Moment`ライブラリを使っています
- カレンダーの予定を取得する
    - カレンダーの予定の取得の方法は以下の記事に記載してます
        - https://qiita.com/zumi0/items/87c248bdd68c3983ed81
- メールを作成して送信する


```javascript
function myFunction() {
    // 本日の日時を取得
    var today = Moment.moment().format('YYYY/MM/DD');
    
    // デフォルトのカレンダーを取得する
    var calendar = CalendarApp.getDefaultCalendar();
    
    // 本日の予定を取得する
    var events = calendar.getEventsForDay(new Date(today));
    
    // メールの本文を作成する
    var text = today + "の予定です\n" +
               "\n" +
               "---------------------------" +
               "\n";
                    
    events.forEach(function (event, index, array) {
        var event_text = "時間 : " + event.getStartTime() + "\n" +
                         "名前 : " + event.getTitle() + "\n" +
                         "\n" +
                         "---------------------------" +
                         "\n";

        // ベースの文と結合
        text = text + event_text;
    });
                    
    // 件名を作成
    var subject =  today + "の予定";

    // メールを送信する
    GmailApp.sendEmail(
        ['YOUR_MAIL_ADDRESS'],
        subject,
        text
    );
}
```

## さいごに
今回はGmailでメールを送信する方法と、実際にそれを使ってGoogle　Calendarの予定を取得してその内容をメールで送信できるスクリプトを作成してみました！
Pythonを使って周囲の Wi-Fi 情報(SSID・BSSID・電波強度)を取得する

# モチベーション

Windows で Wi-Fi の SSID と BSSID を取得したいと思ったのがきっかけ。
はじめはコマンドラインで `netsh wlan show networks mode=bssid` で Wi-Fi の一覧を取得しようかと考えていたのですが、[参考資料](# 参考資料)にある通り、何度実行しても同一のSSID/BSSIDになってしまったり、複数あるはずのSSIDが接続中のSSID1つだけになってしまったりしました。

[解決方法](https://teratail.com/questions/174005#reply-295932)を以下に引用します。

> C#を使ってWindowsAPIを呼び出すことでWifiの電波強度一覧を取得することができました。
> 使用したAPIはWlanScan()です。NativeWifiというオープンソースのライブラリを使って使用することができました。

上記を Python でもできないか調べたところ、`win32wifi` を見つけました。



# 環境
- Windows 10
- Python 3.6 
- 追加ライブラリ
    - `win32wifi`

※ 3.7 以上で実行しようとすると import comtypes でエラーが生じます。[参考資料](# 参考資料)の方法で回避できるかもしれません。


# プログラム

実行をする場合は中身を確認しながら自己責任でお願いします。

`WlanRegisterNotification` にて通知がきても Wi-Fi 情報が空の場合があるため3回実行しています。
(何か使い方が間違っているのでしょうか...)


```python
from win32wifi import Win32Wifi as ww
import threading


def get_ssid(trial=3):
    ## Wlanが変更を登録するEvent
    th_ev = threading.Event()
    def callback(wnd, p):
        th_ev.set()

    interfaces = ww.getWirelessInterfaces()
    handle = ww.WlanOpenHandle()


    ## 試行回数
    for i in range(trial):
            
        ssid_dict = {}
        for interface in interfaces:
            ## 検索
            ws = ww.WlanScan(handle, interface.guid)
            ## 登録完了を最大10秒待機する。
            cb = ww.WlanRegisterNotification(handle, callback)
            th_ev.wait(10)
            th_ev.clear()

            networks = ww.getWirelessNetworkBssList(interface)
            for network in networks:
                ssid = network.ssid.decode()
                bssid = network.bssid
                quality = network.link_quality

                ## ssid がなければリストを追加
                if ssid not in ssid_dict.keys():
                    ssid_dict[ssid] = []

                ## bssid と電波強度を追加
                ssid_dict[ssid].append((bssid, quality))

        ## 空でなければ break
        if ssid_dict != {}:
            break

    ww.WlanCloseHandle(handle)

    return ssid_dict


if __name__ == "__main__":
    print(get_ssid())
```

# 実行結果(例)

実行毎に更新し、周囲の SSID と BSSID、電波強度を取得できました。
`win32wifi` のソースコードを確認するとより多くの情報を取得できると思います。

```
{'SampleSSID1': [('XX:XX:XX:XX:XX:XX', 100)], 'SampleSSID2': [('YY:YY:YY:YY:YY:YY',80)], ..... }
```

# 参考資料
- [「netsh wlan show networks mode=bssid」コマンドで表示される同一SSIDのBSSIDの情報が省略される。](https://teratail.com/questions/174005)
- [Syntax error when trying to import comtypes on Python 3.6.7](https://github.com/enthought/comtypes/issues/180#issuecomment-1009675303)
- [win32wifi (Python Windows Wifi)](https://github.com/kedos/win32wifi)
【Unity】Android実機のログを確認する方法

Unityで開発をしていて、Androidの実機を動かしている時のログを確認したい時があると思います。

今回はそのログを簡単に確認する方法についてです。

# 環境
- Windows10
- Unity Hub 2.4.5
- Unity 2020.3.25f1
- Android Studio 2020.3.1

# Android Logcatをインストール
Unity2019からPackage Managerに公式のツールが加わっています。

Windows > Package Manager へ移動して、
左上のPackagesを「Unity Registry」にします。

すると「Android Logcat」という項目があるので、
それをインストールするだけです。

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399610/53fe9645-8e04-2ac7-44f0-a093ed1a80f1.png)


あとはPCと実機を繋いで「Build And Run」をするとAndroid Logcatが起動して以下のようにログが出力されます。

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399610/56209e67-52a8-5071-623f-0f13d18eb7b9.png)

ログの出力を止めたい時は、「Disconnect」をクリックするだけです。

以上、ご拝読有難うございました。
Emacs26が入っているUbuntuにEmacs27をインストールする

# やりたいこと
UbuntuでEmacs26をEmacs27にアップデートしたい

# やったこと
```
#リポジトリ追加
sudo add-apt-repository ppa:kelleyk/emacs
sudo apt update
# 以前のものを削除
sudo dpkg –remove –force-remove-reinstreq emacs27
sudo apt remove emacs26-common emacs26 emacs-common emacs apel flim w3m-el emacs-el emacs-bin-common
# インストール
sudo apt install emacs27
```

# 参考
- UbuntuにEmacs27をインストール  
https://ubuntuhandbook.org/index.php/2020/09/install-emacs-27-1-ppa-ubuntu-20-04/?unapproved=3718240&moderation-hash=a2b3e95faf6442b03a231b82d41a2ee3#comment-3718240
- 依存関係の削除  
https://marmooo.blogspot.com/2018/11/dpkgapt-get.html
【Vue.js】privateな変数の双方向バインディング方法

# はじめに
JavaScriptでprivateな変数やメソッドが作れるようになったようです。
私は業務でVue.jsを触っているため、「双方向バインディングする場合はどのように書くんだろう？」
と気になったので試してみました。

# 結果
getterとsetterを用意して、**「v-model="クラス名.変数名"」**で良いみたいでした。

# 検証
変数に「#」を付けることでprivateになるようです。
一旦setterは用意せず、以下のようなクラスを作成しました。

```Javascript
module.exports = class Test{
  #detail;
  #tag;

  constructor() {
    this.#detail = null;
    this.#tag = null;
  }

  get detail() {
    return this.#detail;
  }
  get tag() {
    return this.#tag;
  }
};
```

画面側は以下のように実装しました。

```Javascript
<template>
  <div>
    <div class="control column">
      <base-select v-model="test.tag" :options="testTags"></base-select>
    </div>
    <div class="control column">
      <base-input
        v-model="test.detail"
      ></base-input>
    </div>
  </div>
</template>

<script>
import BaseSelect from "~/components/BaseSelect.vue";
import BaseInput from "~/components/BaseInput.vue";

export default {
  components: {
    BaseSelect,
    BaseInput
  },
  data() {
    const Test= require("~/server/api/models/test");
    return {
      testTags: require("~/assets/testTags.json"),
      test: new Test(),
    };
  }
};
</script>
```

この状態で画面上で値を変更してみると以下のようなエラーが発生します。

```
TypeError: Cannot set property tag of #<Test> which has only a getter
```

「setterを用意しないと値がセットできないぞ」ということです。
ということでsetterを用意したところ、想定通りに値を変更することができました。

結果に書いている通り「v-model="クラス名.変数名"」で良いみたいでした。


# 追加検証
次に「#」を外して同様に実行してみます。
getterもsetterも無い以下のようなクラスを用意します。

```Javascript
module.exports = class Test{
  constructor() {
    this.detail = null;
    this.tag = null;
  }
};
```

画面のコードは同じもので、再度画面から値を変更してみるとエラーも何も発生せず変更することができます。
しかし、クラス内の変数をgetterとsetterを介さず直接操作をすることになってしまいます。(と思っています。)

# おわりに
親側にsetterを呼ぶメソッドを書いて、子側でそのメソッドを呼ぶことで値が変更できる、
そんな実装になるのかと思ったのですが、その必要はなくシンプルでよさそうでした。

参考になりましたら幸いです。
エンジニアの3大原則

## 投稿の経緯
そろそろエンジニアになってから一年程度経過するので、原点回帰の意味を込めて自社内でLT会で発表しました。
その内容をQiita上でもまとめようと思いました。

3大原則
・DRY
・KISS
・YAGNI
に関してまとめました。

## DRY
### DRY
DRY　＝　Don’t Repeat Yourself　＝　「重複させるな」
コードやなんらかの設定値や設定ファイル、データベースやスキーマファイル*などを重複定義したり多重管理せずに、どこか一箇所だけに定義して管理するようにする。

スキーマファイル: 現在のデータベースの構造を記録したファイル。
### なぜDRY化が必要なのか
後でコードや設定値などを変更する時に複数の箇所を同時に改修しないといけなくなり、変更漏れが高い確率で起きるようになり、不具合が発生してしまう。

仮に定数化したURLをたくさん使う場所があっても、一箇所を変更することで終わる
⇨保守性の向上

次に見た人がわかりやすい
⇨’https:login.yahoo.co.jp/config/login’はYahooにログインするために必要なんだな〜


## KISS

KISS　＝　Keep it simple, stupid!　＝　「シンプルにしろ、ばかやろう！」

もともと航空機(パイロットなど)の格言が、ITエンジニアでも広まったもの。
プログラミングは自由度が高いので基本やろうと思えば、複雑なコードもかけるがシンプルなコードを書くようにする。
興味本位や自慢のため無駄に高度なコードを書かないように。
新しく入った人が見づらく、改修や新規開発がしづらくなる。

## YAGNI
YAGNI　＝　You ain’t(aren’t) gonna need it　＝　「それは必要にならないよ？」
　　　　　　　　　　　　　　　　　　　　　　　「どうせ使わないよ」
「今の段階で必要ではないが、あとで必要になるかもしれない」と思って書いたコードや機能はほとんどの場合使われない。

### YAGNIの具体例
例えば、二種類のデータベースの方式があります。

1、規模に応じてよしなに調節してくれるデータベース
	(NoSQL系、DynamoDBなど)
2、大量アクセスを捌くには特別な処理をさせないといけないデータベース。
o	(RDB)　(みんせつはこちら)

一見1のデータベースの方が良さそうに見えますが、
：大量のデータを捌くようになって初めてメリットが得られる。
：トランザクション機能*が使えなかったり、複雑なクエリを実行できなかったりめんどくさい。



トランザクション機能: 複数のテーブルに処理を行うクエリを投げた時、もしどこかでエラーが出てしまってもクエリを投げる前の状態に戻してくれる

将来的な規模拡大を考慮して、メインのデータベースに1を採用したことにより、改修したり新規開発する時間が長くなってしまうため、
他の競合サービスに敗れて大量アクセスが来る前にサービスが倒産してしまう。

最初から1を使うのではなく、2を使って、もしユーザー数の規模が大きくなって処理が大変になったら、部分的に1を使うようにする。

## しめ
以上3大原則をまとめた元です。

参考(というかほぼパクリです。)
DRY原則/KISS原則/YAGNI原則について説明します。
https://www.youtube.com/watch?v=nE-AiOkzY70&t=60s
formatメソッド(Ruby)

Ruby3.1 <a href = "https://docs.ruby-lang.org/ja/latest/class/Kernel.html#M_FORMAT">Kernelモジュールformat</a>
#sprintf(string print formatted)フォーマット
formatの記述は『%指示子』が基本
指示子は、引数の型の解釈を示し、省略できない
・文字列を表す指示子：c,s,p
・整数を表す指示子：d,i,u,b,B,o,x,X
・浮動小数点数を表す指示子:f,g,e,E,G

```ruby
#『%d又は%i』引数の数値を10進表現の整数として出力する
#整数でない場合はto_iと同規則で整数に変換する
format("%d",3.5)
#=> "3"
format("%d","0b1010") #0b(2進数)
#=> "10"

#『%s』は文字列を出力する
v = "moji"
5.times do |i|
  if i % 2 == 0
    puts format("文字列%d(%s)", i, v)
  end
end
#=>
"文字列0(moji)"
"文字列2(moji)"
"文字列4(moji)"
```
GASでスクリプトを定期実行させてみる

## はじめに
GASを使う大きなメリットの一つに定期実行が容易にできるということがあります。この記事では、その定期実行をどのようにやるかまとめてみました。

## GASでスクリプトを定期実行させてみる
1. エディタ画面右側のサイドバーから、時計のようなアイコンをクリックする
    - ![スクリーンショット 2022-01-16 21.45.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/581736/2c7c6adc-e660-36c2-681f-760707beb43f.png)

1. 右下の「トリガーを追加」をクリック
    - ![スクリーンショット 2022-01-16 21.46.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/581736/a52b8919-7adf-14a4-026e-1ef0d71ed91a.png)

1. 定期実行する関数や間隔を選択して保存する
    - メモ
        - 定期実行したい関数を選択する
        - 定期実行するためには、「イベントのソースを選択」の欄から「時間主導型」を選択する
        - 定期実行したい間隔を選択するには「時間ベースのトリガーのタイプを選択」から選択できる
            - 時間や曜日、週などから選択できる
    - ![スクリーンショット 2022-01-16 21.49.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/581736/17b80f61-55fd-955d-48fa-c1777de48290.png)

## さいごに
今回はGASのスクリプトを定期実行させる方法をまとめてみました。
Wikipedia上から話の小ネタを探してくれるLINEBotを作ってみた。

LINE上でWikipediaのトップページにある「今日は何の日」を取得するbotを作成しました。

#作った理由
現在、小売業の企業で社内教育や採用を担当しています。
初対面の方への面接・研修などの機会が多く、自己紹介や会話のきっかけになる「話のネタ」をサクッと調べられたらといいなと思ったのがきっかけです。
昭和の企業戦士（父）はネタ帳に「分厚い革の手帳」を持っていましたが、令和のサラリーマン（私）はネタ帳を「スマートフォン」に収めたいと思います。

　
#完成品
「同じテーマ」で「毎回違う情報」が見たかったので、<a href"https://ja.wikipedia.org/wiki/%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%9A%E3%83%BC%E3%82%B8">Wikipedia</a>のメインページにある情報を使うことにしました。
![追加完成.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2490846/67498907-1e5f-19c8-b45d-7d677e9ac165.png)
「LINE上で文字を入力→文字に該当するページを取得して返す」が大まかな流れとなります。

　
#使用したもの
- Node-RED
- LINE Developer
- node-red-contrib-wikipedia

　
#作業過程
![ノードの追加.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2490846/3674c499-9ac1-596a-8c26-e5b56081207c.png)
<a href="https://www.mediawiki.org/wiki/API:Main_page/ja">MediaWiki API</a>を見て試行錯誤をしましたがAPIに上手くアクセス出来ず、Node-REDの「ノードの追加」を検索したところWikipediaの名称を見つけたので、そちらで作成することにしました。
![初回完成.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2490846/ae232945-5081-6558-68d0-899f0ce3bbd5.png)
![1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2490846/87de8d2e-888e-a312-4d82-86d1f1a0731b.jpeg)
LINE上に表示出来ました。
ついでなので、よく使うキーワードを調べやすくしつつ、ブラウザを開かずともLINE上で任意のワードも検索出るようにしました。
検索したい文字を全て打つのは大変なので、よく使いそうな「今日は何の日」と「季節の話題」のページは覚えやすい最小文字数の入力で表示出来るようにしています。
　1.【今日】と入力→「今日は何の日」と置き換えてページを取得
　2.【季節】と入力→「季節の話題」と置き換えてページを取得
　3.【その他（テストでは【猫】）】→入力内容をそのままWikipediaで検索・取得
![2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2490846/7adcd38b-0710-1004-740c-2f66991f20ae.jpeg)

　
#本当はやりたかったこと
- ページ内の該当文字情報（画像の藪入り～イラン革命まで）だけをLINEに送りたかった。
![テンプレート.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2490846/85798cd6-a4f7-399e-7e6e-972607c24e43.png)
今回のBotだとWikipediaのページへのアクセスが発生するため、本当は画像にある文字情報だけをLINE上に取得出来ればベストだと思って試しましたが実装出来ませんでした。
Qiitaを始めるにあたって

# 免責事項
著者は本記事を掲載するにあたって、その内容、機能等について細心の注意を払っておりますが、内容が正確であるかどうか、安全なものであるか等について保証をするものではなく、何らの責任を負うものではありません。
本記事内容のご利用により、万一、ご利用者様に何らかの不都合や損害が発生したとしても、著者や著者の所属組織は何らの責任を負うものではありません。

# わたしがQiitaを通して実現したいこと

* ある分野のカリスマとして、尊敬されるエンジニアになること。
* 素晴らしい仲間と仕事ができるような機会をつくること。
* 世の中にインパクトを残せるような仕事ができること。

# エンジニアとしての将来像

* OSからサーバー、開発ツールまで多種多様な製品やプログラミング技術を駆使し、課題解決できる
* プログラミングで手を動かせるだけでなく、英語も喋れて、経営的視点も持っているエンジニア
* 海外で働けて、グローバルに情報発信ができること
* イノベーティブなプロダクトを開発し、企業価値を高められる。
* 仲間が自然発生的に集まるカリスマ的な魅力を持ったエンジニア

# エンジニアとして意識したいこと

* Qiita上に仕事で感じたことをまとめて、それを客観的に振り返って、自身の価値観や特徴について理解する。
* どんな人が周囲にいれば自身のパフォーマンスを発揮できるかを考える。
* 「労働市場で自分の市場価値を高めること」を常に意識する。
* 最新技術やツールに対する有意義なディスカッションを起こす。

# 不安なこと

* エンジニアリングは基本的にマネジメントに対して格下に位置付けされており、評価されにくい。
* 見てきた開発が、エンジニアとしてのセンスに疑問。
* レガシーな開発(ウォータフォール、ドキュメントがExcel、人力のテスト、デプロイなど)がまかり通っていたり、業務時間が足りないからコードレビューもろくにできない。
* 時間がないからプライベートで勉強しないなど、そんなエンジニアを市場は評価するだろうか？という疑問が拭えない。
* 業務に忙殺されている間に、世界のエンジニアは勉強して、技術力を高めているのかと思うと、相対的に自分の市場価値は劣化していく。
composer self-updateできない


##はじめに
環境変数の設定中に、phpdotenvというライブラリを導入する際に、複数のエラーにハマったので、備忘録として残します。

##現状①

- phpdotenv導入のために、下記コマンド入力後に、Composer2へアップデートして下さいとのエラーが出ている状況。

```
docker-compose exec app composer require vlucas/phpdotenv
```
```
Warning from https://repo.packagist.org: You are using an outdated version of Composer. Composer 2 is now available and you should upgrade. See　https://blog.packagist.com/deprecating-composer-1-support/
```

- [https://blog.packagist.com/deprecating-composer-1-support/](https://blog.packagist.com/deprecating-composer-1-support/)を参照


##対応①

- 素直にcomposerをアップデートするコマンドを入力

```
$ sudo composer self-update
```

##現状②

- composerコマンドが使用できない現状。

```
composer: command not found
```

##対応②

- `/usr/local/bin/`を確認。composerあるのにな・・・と思い、バージョンを確認してみるが、`not found`・・・。

```
$ composer --version
zsh: command not found: composer
```
- composerを削除して、composerを再インストールしてみる。

```
$ sudo rm -rf /usr/local/bin/composer
```

- composer.pharを落としてくる

```
$ sudo curl -s https://getcomposer.org/installer | php
```

- Password聞かれるので、入力する

```
Password:
All settings correct for using Composer
Downloading...

Composer (version 2.2.4) successfully installed to: /Users/〇〇/composer.phar
Use it: php composer.phar

```

- composer.pharを移動する

```
$ sudo mv composer.phar /usr/local/bin/composer
```

- composerのバージョンを確認してみる

```
$ composer --version
Composer version 2.2.4 2022-01-08 12:30:42
```

これでコマンドが使用できていますし、バージョンUPもできました！

##まとめ

1日に2回も`command not found`を見るなんて・・・・と思い、備忘録として残しました。少しでも参考になると幸いです。


##参考記事

- [PHP | Composer のバージョンを 2.x にバージョンアップする](https://al-batross.net/2020/11/02/composer-update-veron-2x/)
- [「composer self-update」を実行するとエラー](https://exiz.org/posts/composer-self-update-error/)
- [[Mac]composer: command not found 対処法](https://yrfreelance.com/2020/09/10/composer-command-not-found/)
GASでGoogle Calendarの予定を取得する

## はじめに
GASではGoogleが提供されるサービスと連携することができるのですが、今回はGoogle Calendarの予定を取得する方法を備忘録として記載しておこうと思います。

## GASでGoogle Calendarの予定を取得する

### カレンダーの取得の方法
- IDやメールアドレスを使ってカレンダーを取得する
- デフォルトカレンダーを取得する
- 所有・閲覧しているカレンダーの中から取得する

#### 実際のスクリプト

```javascript
function myFunction() {
    // デフォルトのカレンダーを取得する
    var calendar1 = CalendarApp.getDefaultCalendar();
    
    // IDで取得する
    var calendar2 = CalendarApp.getCalendarById('YOUR_CALENDER_ID');
    
    // 所有しているカレンダー一覧を取得する
    var calendars1 = CalendarApp.getAllOwnedCaledars();
    
    // アクセス可能なカレンダー一覧を取得する
    var calendars2 = CalendarApp.getAllCalendars();
    
    // カレンダーのタイトルを表示する
    Logger.log(calendar1.getName());
}
```

### カレンダーに登録している予定を取得する
- 日程の期間を指定して、その期間内の予定を取得する
- ある特定の日を指定して、その日の予定を取得する

#### 実際のスクリプト

```javascript
function myFunction() {
    // デフォルトのカレンダーを取得
    var calendar = CalenderApp.getDefaultCalender();
    
    // 今日の予定を取得
    var events1 = calendar.getEventsForDay(new Date('2022/01/16')); 

    // 期間を指定して予定を取得する
    var events2 = calendar.getEvents(
                       new Date('2022/01/17'),  // start day
                       new Date('2022/01/21'))  // end day
    
    // イベントのタイトルと開始時間を表示する
    // forEach 構文
    // 配列に使える
    // 使うには、値とインデックス、元の配列といった3つの仮引数が必要
    events1.forEach(function (event, index, array) {
        // タイトルを表示
        Logger.log(event.getTitle());
        // 開始時間を表示
        Logger.log(event.getStartTime());
    });
}
```

## おわりに
今回は簡単ではありますが、GASでGoogle Calendarの予定を取得する方法を記載しました。
AWS 【セキュリティグループで解決】ELBが応答しない（HTTP 504: Gateway Timeout）

#前提条件

**OS**
 MacOS Monterey 12.0.1
**CPU**
 Apple M1(arm64) 

**AMI(アマゾンマシンイメージ)**
Amazon Linux 2 AMI (HVM) - Kernel 5.10, SSD Volume Type - ami-02d03ce209db75523 (64 ビット x86) / ami-00ad846222db698f3 (64 ビット Arm)
**インスタンスタイプ**
t2.micro

※練習用の低スペックなインスタンスです

#はじめに

今回はハマった内容を解決した備忘録的に書いているので、内容はエラー箇所とその解決過程にフォーカスし、各リソースの設計手順等はほとんど割愛しています。
ご容赦ください。

#アーキテクチャ

・１つのVPCに２つのAZ(１b、１cとします)を配置

・それぞれのAZにパブリックサブネットを１つずつ設置（１b、１c）

・それぞれのパブリックサブネットにEC2インスタンスをWEBサーバとして起動
　　※ほぼ同じ内容でインスタンスを起動しています
　　※サブネット１bに作ったEC2インスタンスをAMIとしてイメージ保存し、そこからもう１台を立ち上げるとスムーズです。

・起動したインスタンス計２台にELBを紐づける

※EC2インスタンスにアパッチサーバをインストールし、WEBサーバとして起動する手順を記しています。ご参考までに。
↓

https://qiita.com/Ryo-hey/items/cb42d713d881814acb42


#やりたいこと

ELBで２台のWEBサーバ（EC2インスタンス）に負荷分散する
（ELBのDNSにアクセスした際、２台のWEBサーバの内容が均等に表示されることを確認する）

#つまづいた話

ELBのDNSにアクセスすると、「HTTP 504: Gateway Timeout」のエラーが発生する

![スクリーンショット 2022-01-16 17.44.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1068535/44b8ace2-6387-3c8c-5f4e-4391b2852c60.png)


#切り分け

・各EC2インスタンスのグローバルIPには正常にアクセスできる
　　　→インスタンスの異常ではない

![スクリーンショット 2022-01-16 18.03.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1068535/992a3f88-bf18-c2b9-e411-5ec6d8693d23.png)

![スクリーンショット 2022-01-16 18.06.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1068535/10bb6959-7b09-aa7a-68db-633103ed2e8a.png)

※どちらのインスタンスにアクセスできているかがすぐ分かるよう、それぞれに置くhtmlファイルの内容はAZ名で書き分けています。

・サブネットのネットワークACLはデフォのまま、IN,OUT共に全トラフィックを許可することになっている

・ELBのターゲットグループやELB自体は正常に動作している

#原因

`EC2に設定したセキュリティグループ`のインバウンドルールで、**`ELBからのトラフィックを許可`していなかった。**

ELBは配下のEC2に負荷分散を行うに当たってEC2にリクエストを送りますが、そのトラフィックがインスタンスに届かなかったことが原因でした。

#解決策

セキュリティグループの見直し

修正前）EC２、ELBとも同じセキュリティグループを設定
↓
修正後）

①ELBのセキュリティグループを設定
　　IN)クライアントからのトラフィックを許可
　　OUT)全て許可

②各EC2のセキュリティグループのインバウンドで、**①のセキュリティグループを許可**

セキュリティグループは、`許可するソースとして別のセキュリティグループも設定できる`
という点がポイントだったんですね。
ここがネットワークACLと異なる点であり、見落としがちな点なんだとか。

※自分も勉強したばかりの内容でしたが、気づくまでずいぶん時間がかかりました。。。

#手順

###1　ELBにセキュリティグループを設定

分かりやすいよう、「ELB-SG」という名前にしました。

![スクリーンショット 2022-01-16 18.24.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1068535/3e1de09a-8a9a-19f4-8587-ec1b99fa79a0.png)

※セキュアな状態となるよう、インバウンドはクライアントPC（自分）からのアクセスのみ許可するようソースを設定しました。
（セキュリティグループ編集の「ソース」から「カスタム」→「マイIP」で設定可能）
※アウトバウンドはデフォのまま、全て許可としています。

###2　EC２にセキュリティグループを設定

「Webserver-SG」という名前にしました。
![スクリーンショット 2022-01-16 18.29.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1068535/d5fdcfe1-3ac6-52ed-fc22-5bc256b49175.png)



※ELBからのトラフィックが届くようにします。
※**上記１で設定したELBのセキュリティグループを、インバウンドで許可するソースとして設定します。**
※`タイプ「HTTP」　ソース「カスタム」`とすると、選択肢から他のセキュリティグループを指定できます。

###3　ELBのDNSをブラウザURL欄に貼り付け、アクセスしてみる

無事にページが表示されました。

繰り返しアクセスすると、アクセスのたびに各インスタンスにトラフィックが分散されていることがわかります。
（各インスタンスに置いた別々のhtmlファイルの内容が、交互に表示されているため。）
正常に動作しているようです。



#参考サイト

↓Udemy

https://www.udemy.com/course/aws-associate/


↓公式ドキュメント

https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-security-groups.html#elb-vpc-nacl
command not found:phpを解消する

##はじめに

phpのバージョンを確認するコマンドを入力した際にエラーにハマったので、備忘録として残します。

##現状

- `php -v`入力後に下記エラーが出ている現状。

```
$ php -v
zsh: command not found: php
```

##原因

- パスの通し方が間違っていたのが原因でした。

##対応

- まずは、phpのパスを調べる。

```
brew --prefix php@7.4
```
- 私の環境では、`usr/〇〇/opt/php@7.4`なので`/Users/ユーザー名/.zshrc`を編集します。`cat`コマンドを使用して、現在の設定を確認します。

```
cat ~/.zshrc
```

- `vi`コマンドでパスを編集します。編集方法は、`i`を押して、インサートモードに入る。`esc`を押して戻る。`:w`で書き込みをして、`:q`で終了する

```
vi ~/.zshrc
```

```
export PATH=(brew --prefix php@7.4で返ってきたパス)bin:$PATH
```
- 下記コマンドで、変更を反映させます。

```
source ~/.zshrc
```

- `php -v`コマンドを実行する。

```
PHP 7.4.27 (cli) (built: Dec 16 2021 18:14:46) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
    with Zend OPcache v7.4.27, Copyright (c), by Zend Technologies
```

phpのコマンドが使用できるようになりました！

##まとめ

`command not found`ってよくみるエラーなので、備忘録として残しました。
少しでも参考になると幸いです。

##参考記事

- [sourceコマンドを誤って使ってしまいゾッとした話](https://qiita.com/stilo/items/90f6c6e308c85a4a9460)
- [bash: : command not found　〜どんなコマンドを打っても抜け出せない地獄〜](https://qiita.com/baby-0105/items/dedfe3a4eb52d9b7f7d3)
League of Legendsの高ランクプレイヤーの試合情報を取得する (2022年版)

2022年からRiot Games APIから高ランクプレイヤーの試合情報を取得する方法が変わった為、備忘録として残す。

# 全体の手順
1. 高ランクのプレイヤーのsummoerIdを取得する
1. 各プレイヤーのpuuidを取得する
1. puuidに紐づくmatchIdを取得する
1. matchIdに紐づく試合情報を取得する
1. matchIdに紐づくタイムラインを取得する  
※ タイムライン: いつ、どんなアイテムを購入したか？ どのようなオブジェクトを破壊したか？など
  
2021年からの大きな変更点  
日本サーバーの場合、エンドポイントは`https://jp1.api.riotgames.com/lol`が決め打ちだったが、2022年から、3のmatchId取得から`https://asia.api.riotgames.com/lol`に変更。


## 1. 高ランクのプレイヤーの情報を取得

手順： 取得したJSONの['entries']の中にある人数分のsummoerIdを抽出する
チャレンジャー帯
`https://jp1.api.riotgames.com/lol/league/v4/challengerleagues/by-queue/RANKED_SOLO_5x5?api_key=[APIKEY]`  
  
グランドマスター帯
`https://jp1.api.riotgames.com/lol/league/v4/grandmasterleagues/by-queue/RANKED_SOLO_5x5?api_key=[APIKEY]`

マスター帯
`https://jp1.api.riotgames.com/lol/league/v4/masterleagues/by-queue/RANKED_SOLO_5x5?api_key=[APIKEY]`


## 2. 各プレイヤーのpuuidを取得
手順： 取得したJSONの中にあるpuuidを抽出する
`https://jp1.api.riotgames.com/lol/summoner/v4/summoners/[SUMMONER_ID]?api_key=[APIKEY]`

## 3. puuidに紐づくmatchIdを取得する
手順： 取得したJSONからmatchIdのリストを取得する  
`https://asia.api.riotgames.com/lol/match/v5/matches/by-puuid/[PUUID]/ids?queue=420&type=ranked&start=0&count=100&api_key=[APIKEY]`


## 4. matchIdに紐づく試合情報を取得する
手順： 取得したJSONから必要な試合情報を取得する
`https://asia.api.riotgames.com/lol/match/v5/matches/[MATCH_ID]?api_key=[APIKEY]`


## 5. matchIdに紐づくタイムラインを取得する
手順： 取得したJSONから試合のタイムラインを取得する
`https://asia.api.riotgames.com/lol/match/v5/matches/[MATCH_ID]?api_key=[APIKEY]`



## 参考サイト
Riot Games API
https://developer.riotgames.com/apis


APIを利用する開発者用ドキュメント
https://developer.riotgames.com/docs/lol


## メモ
1. 各サーバーのエンドポイント
APIを利用する開発者用ドキュメントのPlatform Routing Valuesを参照

2. 各サーバーのエンドポイント
APIを利用する開発者用ドキュメントのRegional Routing Valuesを参照

3. queueのパラメータについて
下記を参照
`https://static.developer.riotgames.com/docs/lol/queues.json`
PostgreSQLでcreateuserコマンドによるユーザ作成時にエラーが出た際の対応ログ

# 現象
以下のメッセージが表示される
`error: could not connect to database template1: could not connect to server: No such file or directory
        Is the server running locally and accepting
        connections on Unix domain socket "/var/run/postgresql/.s.PGSQL.5432"?`


# 対策
PostgreSQLサーバ上の既存アカウントにて以下のコマンドを実行し、サーバを起動する
`pg_ctlcluster 12 main start`

PostgreSQLインストール時、以下のメッセージが表示されている場合、本対策で対応可能です。
`Success. You can now start the database server using:
pg_ctlcluster 12 main start`

要するに、インストール時のメッセージをしっかり読みなさい、ということでした。。。

#PostgreSQLインストール方法について参考にしたサイト
https://www.digitalocean.com/community/tutorials/how-to-install-postgresql-on-ubuntu-20-04-quickstart-ja
Windows のタスクトレイに Python アプリを常駐させ定期的にプログラムを実行する


# 常駐アプリを作ってみたい

お手軽にタイトルみたいな事ができないかと調べていたときに `pystray` というライブラリを知ったので[参考資料](# 参考資料)を見ながら作成してみました。
ご指摘やアドバイス等あればコメント頂きたいです。

# 環境

- Windows 10
- Python 3.9
- 追加ライブラリ
    - `pystray`
    - `schedule`


# プログラム

中身を確認しながら自己責任で実行してください。
アイコン (`sample.jpeg`) は ICOON MONO さんのフリー素材を使用しました。

```python:tray.py
from pystray import Icon, MenuItem, Menu
from PIL import Image
import time
import threading
import schedule

class taskTray:
    def __init__(self, image):
        self.status = False

        ## アイコンの画像
        image = Image.open(image)
        ## 右クリックで表示されるメニュー
        menu = Menu(
                    MenuItem('Task', self.doTask),
                    MenuItem('Exit', self.stopProgram),
                )

        self.icon = Icon(name='nameTray', title='titleTray', icon=image, menu=menu)


    def doTask(self):
        print('実行しました。')

    def runSchedule(self):
        ## 5秒毎にタスクを実行する。
        schedule.every(5).seconds.do(self.doTask)
        ## status が True である間実行する。
        while self.status:
            schedule.run_pending()
            time.sleep(1)

    def stopProgram(self, icon):
        self.status = False

        ## 停止
        self.icon.stop()

    def runProgram(self):
        self.status = True

        ## スケジュールの実行
        task_thread = threading.Thread(target=self.runSchedule)
        task_thread.start()

        ## 実行
        self.icon.run()


if __name__ == '__main__':
    system_tray = taskTray(image="sample.jpeg")
    system_tray.runProgram()

```

# 実行結果

プログラムを実行すると5秒毎に print します。右クリックで Task をクリックしても実行します。
Exit をクリックすればプログラムを終了します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/174323/b94a2bc8-93d6-1dbf-4683-daf1c3d11e21.png" width="500">


# 参考資料
[github: OtagoPolytechnic/CommandLineSpeechControl/Developers/systray.py](https://github.com/OtagoPolytechnic/CommandLineSpeechControl/blob/master/Developers/systray.py)
return/break/nextの使い方(Ruby)

Ruby3.1
<a href = "https://docs.ruby-lang.org/ja/latest/doc/spec=2fcontrol.html#return">制御構造return</a>
<a href = "https://docs.ruby-lang.org/ja/latest/doc/spec=2fcontrol.html#break">制御構造break</a>
<a href = "https://docs.ruby-lang.org/ja/latest/doc/spec=2fcontrol.html#next">制御構造next</a>

#return
Rubyのようなオブジェクト指向の言語の関数をメソッドと呼ぶ
breakは式の値を戻り値としてメソッドを終了する

```ruby
def ex
  10.times do |i|
    if i == 7
      return i
    end
  end
end
#メソッドexを実行します(戻り値はi)
ex 
#=> 7

#戻り値を省略するとnilが返る
def ex
  10.times do |i|
    if i == 7
      return
    end
  end
end
ex
#=> nil
```
#break
breakは一番内側のループを脱出する

```ruby
10.times do |i|
  if i == 3
    break
  end
  puts i
end
0
1
2
```
#next
一番内側のループの繰り返しにジャンプする

```ruby
5.times do |i|
  if i % 2 == 0
    next
  end
  puts i
end
1
3
```
【LINE BOT】で店舗情報を教えて！・・・を作成しようとしたけど未完

LINE BOTってなに？という私が作ろうとチャレンジしてみました

仕事上、出張に行くことが多く事前に店舗情報を確認することが多くあります。
住所は？店長誰だった？最寄り駅はどこ？ついでにランチするなら？と調べることが多いのでLINE BOTで教えて貰えたらいいなあと作成してみました。

##イメージ
欲しい情報をまとめるために一旦エクセルシートに作成してみました。
![リスト.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2495084/3c57ae38-d495-269f-66ab-015134af1b81.jpeg)
店舗名を入力したら、下のようなLINEで返信が返ってくるイメージをして・・・
![完成予想.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2495084/4447602d-cacb-80bd-4ccf-0856bb2d5fe2.jpeg)


##使用したもの
・Node-Red
・LINE Developers
・Googleスプレッドシート

##Node-Redでの作成
GSheetのノードが無かったため、右上「三本線」から「パレットの管理」→「ノードを追加」で「GSheet」と入力し検索、追加しました。

##構成
![NODE.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2495084/085da39a-ab60-7c1a-2b54-fc2da0962f61.jpeg)

①ノード「http in」:ラインサーバーからのメッセージ受信
![①.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2495084/48853025-e116-133c-17a4-eb5e3c5f0f8b.jpeg)
②ノード「function]:①からのメッセージを受け取る
![②.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2495084/8a2a7916-0bcc-060a-908b-d6c62f5f6abe.jpeg)
③ノード「Gsheet」Googleスプレッドシートからデータを読み取る。
![Gsheet.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2495084/c4d4e9fd-da68-3e89-8975-bed05fe8bcd1.jpeg)
ここでGoogle スプレッドシートからAPI化した時のAPIキーやスプレッドシートIDを入力するものの、無効に。

API化が作成できていないのか？と思いながら試行錯誤しておりましたが、一旦タイムオーバーの為、終了。

##そして続く
この続きは何が問題か確認してから、チャレンジしてみたいと思います。
実際に使いたい！と思っていただけに「これを作り上げたい！」という気持ちが大きいです。
Python仮想環境 venv

##venv
https://docs.python.org/ja/3/library/venv.html
##使い方
###環境の作成
```
$ python -m venv [環境名]
```
###環境の有効化
```
$ .\[環境名]\Scripts\activate
```
###環境の無効化
```
$ deactivate
```
Rails × Vue で vue Router を使用する

rails アプリの中でVueを使用する場合にVue Routerを使ったページの切り替えができるまでの過程を書いていきます。

## Vue Routerとは

Vue Routerとは、Vue.jsを使ったアプリケーションでルーティング制御をするためのプラグインのことです。これを利用することでリクエストされたURLごとに表示するページを切り替えることができるようになります。

## Vue Routerを使いページの切り替えができるようになるまで

Vue Routerでページの切り替えをするには

- Vue Routerのインストール
- Vue Routerの設定
- application.jsファイルでVue Router の設定をimportする
- 表示したいページ（コンポーネントの用意）
- rails側のルーティングの設定

が必要となるので順番に進めていきます。

## Vue routerのインストール

まずは Vue Routerをインストールしていきます。インストールの仕方は様々だと思いますが自分の環境では以下のコマンドでインストールを行いました。

```markdown
yarn add vue-router
```

これだけでインストールは完了です。次のステップに進みます。

## Vue Routeの設定

インストールしたVue Routerで実際のルーティングを制御するファイルを作成していきます。まだ作成していないコンポーネントをインポートしますがこちらは後で作成します。

app/javascript/router.js

というファイルを作成し、中身を

```jsx
import Vue from 'vue'
import Router from 'vue-router'
import Top from "../pages/top"
import Test from '../pages/test'

Vue.use(Router)

export default new Router({
  name: "Router",
  mode: 'history',
  routes: [
    {
      path: '/',
      name: "top",
      component: Top,
    },
    {
      path: '/test',
      name: "test",
      component: Test,
    },
  ]
})
```

とします。

## application.jsファイルに Vue Router の設定をimportする

先ほど設定したURLごとのコンポーネントの切り替えを反映するためのコードを

app/javascript/application.js

に追加します。

```javascript
import Vue from 'vue'
import App from '../app.vue'
import Router from'../router.js' // 追加 router.jsファイルのimport
import 'bootstrap/dist/css/bootstrap.css'

Vue.config.productionTip = false

document.addEventListener('DOMContentLoaded', () => {
  const app = new Vue({
    render: h => h(App),
    router: Router // 追加 router.jsに書いたルーティングごとに切り替えを使用できるようになる
  }).$mount()
  document.body.appendChild(app.$el)
})
```

## 表示したいページの準備

 URLごとに表示するページ（コンポーネント）を作成していきます。

- トップページの作成

ますはトップページを作成していきます。

app/javascript/pages/top.vue

というファイルを作成し、中身を

```vue
<template>
  <p>topページです</p>
</template>

<script>
export default {
  name: "Top",
}
```

とします。

- 切り替え先ページの作成

app/javascript/pages/test.vue

というファイルを作成し、中身を

```vue
<template>
  <p>testページです</p>
</template>

<script>
export default {
  name: "Test",
}
```

とします。

最後にHTMLファイルに実際に読み込まれる

app/javascript/app.vue

ファイルの変更を行います。（上で用意した二つのコンポーネントはこのファイルの中に埋め込まれる）

```vue
<template>
  <div>
    <router-view /> // この部分にURLごとのファイルが埋め込まれる
  </div>
</template>

<script>
export default {
  name: "App"
}
</script>
```

Vue Routerを使用すると各コンポーネントは```<div>```タグの中に記述されている```<router-view />```の中に埋め込まれるようになるなります。これでページの準備は完了です。

## rails側のルーティングを設定する

rails側ではどんなURLにリクエストが来たとしても表示するページはひとつとなります。その中で埋め込むページを切り替えるのはVue側の役目となります。なのでrouter.rbの中身を以下とします。

```ruby
Rails.application.routes.draw do
  root to: 'home#index'
  get '*path', to: 'home#index' # どのURLにリクエストが来たとしてもhome#indexアクションを使用する
end
```

これで全ての設定が完了です。

サーバーを起動し、```http://localhost:3000```、```http://localhost:3000/test``` にアクセスすると表示が切り替わるようになります。
[Heroku] code=H12 desc="Request timeout"の解決

# 設定
- Heroku
- Heroku Postgres
- Node.js


# 問題

- Herokuサーバーに対するHTTPリクエストがタイムアウトする

```
2022-01-16T08:05:42.762559+00:00 heroku[router]: at=error code=H12
desc="Request timeout" method=POST path="/sample" host=[host_name]
request_id=[request_id] fwd=[ip_address] dyno=web.1 connect=0ms
service=30000ms status=503 bytes=0 protocol=https
```

# 原因
- レスポンスに30秒以上かかっているため
    - Herokuの問題ではなく、コードの問題
    - 自分の場合は、DBのconnection周りの問題でした
    - timeoutの原因は人それぞれだと思います


> これらのエラーは、HTTP リクエストの完了に 30 秒以上かかる場合に発生します。多くの場合、次の原因で発生します。

[H12 エラーへの対処 \(リクエストタイムアウト\) \| Heroku Dev Center](https://devcenter.heroku.com/ja/articles/addressing-h12-errors-request-timeouts)

# 解決
- 自分の場合は以下
    - connectionが溜まっていることが原因なのでreleaseする
    - [\[Node\.js\]\[PostgreSQL\] too many connections for role の解決 \- Qiita](https://qiita.com/wadayamada/items/ab8fc1c33208472756d9)
排他制御_悲観的排他制御(悲観ロック)と楽観的排他制御(楽観ロック)

#■排他制御
複数の人やプログラムが同じ資源(データ)を同時に利用すると競合状態が生じる場合に、ある主体が資源(データ)を利用している間は別の主体による資源(データ)の利用を制限もしくは禁止する制御のこと。
排他制御の考慮がないと、下記のような事象が発生したりする。

≪排他制御がないと、、≫
①人物A、人物Bが同時にWebサイトである商品の購入ページを開く。その時のその商品の在庫数1。
&emsp;(人物A、人物Bが同時にテーブルからデータを取得。そのデータの在庫数は1。)
②人物Aが先に購入処理を実施し、正常に完了。在庫数0。
&emsp;(人物Aが在庫数を取得時からマイナス1した在庫数0でテーブルのデータを更新。)
③次に人物Bが購入処理を実施し、正常に完了。在庫数0。
&emsp;(人物Bが在庫数を取得時からマイナス1した在庫数0でテーブルのデータを更新。)
④在庫数1しかなかった商品を2人の人物が購入できてしまう事態が発生。困る。

上記の状態を防ぐために排他的制御は必要不可欠となる。
また排他制御には、以下の悲観的排他制御(悲観ロック)と楽観的排他制御(楽観ロック)という方法がある。

#■悲観的排他制御(悲観ロック)
ある人がある商品の情報編集ページを開いた際に、その商品情報が記録されているデータをロックし、その情報編集が完了する(か編集をやめる)までその人以外の人はそのデータを参照することすらできなくなるようにする制御。
頻繁にデータの参照や更新が行われる前提のロック方式。

≪悲観的排他制御の例≫
①人物Aが情報編集ページで編集開始&emsp;(対象情報のデータをロック(人物A))
②人物Bが情報編集ページで編集しようとするが、人物Aがデータをロックしているため
&emsp;データを読み取れないので編集不可★悲観的排他制御★&emsp;(対象情報のデータをロック(人物A))
③人物Aが編集完了しデータを更新&emsp;(対象情報のデータはフリー)

#■楽観的排他制御(楽観ロック)
ある人がある商品の情報編集ページを開いた際に、その商品情報が記録されているデータのバージョンを取得し、編集完了した情報をデータに反映させるために更新処理を実施した際に編集開始時のデータのバージョンと更新処理実施時のデータのバージョンを比較し、バージョン異なっていたら更新不可とする制御。もし、バージョンが同じであれば(変わっていなければ)データを更新しバージョンも更新する。
処理中に参照しているデータが書き換わってしまうことが滅多に起こらない前提のロック方式。
(※データのバージョンはタイムスタンプを利用したり、専用のカラムで管理する。)

≪楽観的排他制御の例≫
①人物Aが情報編集ページで編集開始&emsp;(対象データバージョン：1)
②人物Bが情報編集ページで編集開始&emsp;(対象データバージョン：1)
③人物Bが編集完了しデータを更新処理実施→更新OK&emsp;(対象データバージョン：1→2)
&emsp;(人物B編集開始時に取得した対象データバージョンは1で更新時も1なので更新できる)
④人物Aが編集完了しデータを更新処理実施→更新NG★楽観的排他制御★&emsp;(対象データバージョン：2)
&emsp;(人物A編集開始時に取得した対象データバージョンは1だが、
&emsp;更新時の対象データバージョンが人物Bの更新により2になっていたので更新できない)
[Node.js][PostgreSQL] too many connections for role の解決

# 設定

- PostgreSQL 13.5
- Node.js 14.16.1
- pg(node-postgres) 8.7.1


# 問題

- Node.jsからDBに対するクエリのレスポンスが返ってこない
    - 以下のコードの`results`が返らない

```javascript:model.js
exports.getUserByUserId = async function (user_id) {
  var query = {
    text: "select * from users where user_id = $1;",
    values: [user_id],
  };
  await pool.connect();
  try {
    results = await pool.query(query);
    return results.rows[0];
  } catch (e) {
    console.log(e);
  }
};
```

- psqlでCUIから接続しようとすると以下のエラーで接続できない

```
psql: error: connection to server at [name] ([ip_address]), port [port_number] 
failed: FATAL:  too many connections for role [name]
 ▸    psql exited with code 2
```

# 先行事例の調査
- 以下では解決できなかった
  - [FATAL: too many connections for role \.\.\."に対して、自分がとった対策（Django/Heroku） \- otkken2のプログラミング備忘録](https://otkken2.hateblo.jp/entry/2020/03/28/142830)

# 原因
- connectionが溜まっている

# 解決
- connectionをreleaseする

```javascript:model.js
exports.getGroupByGroupId = async function (group_id) {
  var query = {
    text: "select * from groups where group_id = $1;",
    values: [group_id],
  };
  client = await pool.connect();
  try {
    results = await client.query(query);
    client.release();
    return results.rows[0];
  } catch (e) {
    console.log(e);
  }
};
```


# 参考文献
- [pool\.connect\(\) => Promise<pg\.Client>](https://node-postgres.com/api/pool)
React チュートリアル　パート8　（Crudシステム）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654025/c234af03-5cdb-eee9-e654-c9d5b79baf67.png)

#目標:military_medal:
アプリケーションに追加と削除の機能を作りましょう:bangbang:
この機能をマスターすれば、アプリケーションでできることが増えますね:blush:

#App.jsを作成
前回作成した、List.jsは削除しています:bangbang:

![code.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654025/d8deabfc-511b-361d-48b4-bb2e100d9a51.png)

>【3行目】 まず、ターミナルで"npm install nanoid"をインストールします。

>【11行目】 コンポーネント何で配列を作成しました。

>【25行目】ここから追加機能になります。

>【26行目】"e.preventDefault();は、ボタンをクリックされない限りこの機能が動かないようにしています。

>【36行目】ここで、nanoid()が登場しています。自動性IDを生成します。

>【47行目】ここからが削除機能になります。filter()を使って、渡されたid以外の要素をフィルターにかけています。

#ブラウザで確認:fire::fire:

![2022-01-16_19h05_36.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654025/e2a78c60-6449-0063-344b-6d21999a6570.gif)

#次回:bell:
今回のアプリケーションは、ページをリロードするとリセットさせるので次回は、JSON-Serverを使って外部からデータを取得したり削除したりする機能を追加したいと思います！

#参考:ledger:

https://youtu.be/w7ejDZ8SWv8
CCENTが無くなってるみたいだからCCNA取るよ('ω')#0

#勉強方法
今回勉強を進める方法を考えましたが、

今回は、勉強用のテキストを使用して、勉強しようと思います。
使うテキストはまだいまいち考えてませんがとりあえず３冊購入しました。

・いわゆる黒本
・いわゆる白本
・１週間でCCNAの基礎が学べる本

過去問とか解いていって問題なさそうだったら、これだけで勉強します。

勉強が落ち着てきたら、みんな大好きping-tの問題集を解いていこうかと考えてます。

#時間作り
前回の勉強では時間が上手く作れなかったので挫折しまし、
どうすれば時間を上手く作れるのか考え、頭のよくない私は力業で時間を作ることにしました。

それは...**仕事を最速で終わらす!!**

そして...**仕事を通して勉強をする!!**

この２つです...(;´･ω･)

一つ目は言わずもがな仕事が忙しいから時間が作れない?
それなら、仕事をとっとと終わらせればいいじゃないか。

二つ目に関してはせっかくNWに関わる仕事をしてるなら、
仕事しながら勉強すれば良いじゃないか。

具体的にはテキストで見た内容を実機を使って検証したり、
お客様の設定などを確認した時にもっと設定を理解していけば、
体で覚えやすいと考えてます。

#ちなみに...
最初に読みやすそうな１週間でCCNAの基礎が学べる本を読みましたが、
初歩的な内容が多くて全くの未経験でもわかりやすく基礎の部分が書いてある感じがしました。

ただ、仕事をしてて全然使わない知識だなぁってのも同時に感じました...

#最後に
今回は、勉強の方針を考えてみました。

次回からは勉強の内容をアウトプットしていこうと思います。
Rails 7でTailwind CSSを使ってみた

Rails 7の新機能を触ってみたいと思い、今回はその中でもTailwind CSS for Railsというgemを使ってNode.jsやWebpack無しでモダンなフロントエンド開発環境をお試しで作ってみたいと思います。

# 脱モジュールバンドラー
Rails 7では、[cssbundling-rails](https://github.com/rails/cssbundling-rails)というGemをインストールすることで、 Tailwind CSS、 Bootstrap、 Bulma、PostCSS、 Dart Sassを使用してCSSを結合・最適化し、Railsのアセットパイプラインで配信ができるようになったそうです。Webpackerなどのバンドラーを使わなくとも良くなったということですね。
その中でも今回はTailwind CSSを使ってみました。

ちなみにバンドラーを使わないメリット等含め、Rails 7におけるフロントエンド周りの刷新についてDHH氏のブログ記事をまとめた以下記事が参考になりました。

https://www.publickey1.jp/blog/21/rails_70nodejs.html


# Tailwind CSS is 何？

https://fixel.co.jp/blog/tailwindcss/

本筋から逸れてしまうため、簡単に自分なりにまとめると

- あらゆるスタイリングに対応したクラスをまとめたライブラリ
- クラス名には`h-12 w-12` `p-6 max-w-sm mx-auto`のように適用したいスタイルの名前を指定をする
  - BEMのようなレイアウト上意味のある命名をするやり方とは真逆のアプローチ
- メリットは命名に悩む時間が減る、CSSファイルが無闇に増えない、安全な変更が可能。レスポンシブデザインにも対応
- 保守性はコンポーネント化することでカバーする。つまり、ReactやVue.jsなどのライブラリ使用が前提

といった内容のようです。

# Tailwind CSS、使ってみた

## インストール

新規アプリケーション作成の場合、rails newにオプションを付けるだけです。

```zsh
$ rails new myapp --css tailwind
```

既存アプリケーションの場合はGemをインストールした上でTailwind CSSを入れましょう。

```ruby:Gemfile
gem 'cssbundling-rails'
```

```zsh
$ bin/bundle install
$ bin/rails css:install:tailwind
```

## サンプルTodoモデル作成

scaffoldで`Todo`モデルを作成してみます。

```zsh
$ rails g scaffold todo name:string limit:date

# Tailwind CSSのビルドが必要
$ rails tailwindcss:build
```

`rails s`でサービスを起動している場合、手動でCSSをビルドする必要があります。
上記ビルドコマンドを実行することで`app/assets/builds/tailwind.css`がビルドされます。

CSSを修正する度に手動で再ビルドが必要なのはイケてないのですが、`rails s`ではなく`bin/dev`でサービスを起動することにより、Tailwindのスタイル修正の都度、自動でビルドが走るようになるみたいです。

・・・が、私のDocker環境で`rails s`の代わりに`bin/dev`で起動すると、起動と同時にサービスが落ちてしまい上手く動作しませんでした。エラーログも出ないため、一旦手動でビルドします。~~これが解消できないと実用は厳しいかな。。~~
**→2022/4/5追記**
`docker-compose.yml`でRailsアプリのコンテナに`tty: true`オプションを追加することで解消できました！
コメントで教えてくださった @hazm さん、ありがとうございます。


### 動作確認
<img width="400" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/505169/9b52248d-46dc-a357-cffb-4836325b62d2.png">


これは驚いたんですが、scaffoldで自動作成されたviewの各DOMのクラス名にTailwind CSSを適用するクラス名が自動で設定されています。すごい！
これで無事Tailswind CSSが適用されていることを確認できました。

```erb:index.html.erb
<div class="flex justify-between items-center">
  <h1 class="font-bold text-4xl">Todos</h1>
  <%= link_to 'New todo', new_todo_path, class: "rounded-lg py-3 px-5 bg-blue-600 text-white block font-medium" %>
</div>

<div id="todos" class="min-w-full">
  <%= render @todos %>
</div>
```

# 使ってみた所感
- 導入だけは何とかできたがTailwind CSSを使いこなすには学習コストが多くかかりそう
- 当たり前だがサンプルアプリ程度の規模ではバンドラーを使わないメリットは享受しにくい
- リリース間もない機能を使ってみたのが初めてで、情報を集めることの難しさを知った
- 本当はHotwireやTurboを使って簡単なSPAを作るところまでやりたかった…

まだ使用例も少ない中、自分の力では導入して動作を試すところが精一杯でした。
次はもう少し突っ込んだところまでやれたらいいなと思います。

# 参考記事

https://nothing-behind.com/2021/12/21/docker-compose%E3%81%A7ruby3rails7-mysql%E3%81%AE%E7%92%B0%E5%A2%83%E6%A7%8B%E7%AF%89%E3%82%92%E8%A1%8C%E3%81%86%E6%96%B9%E6%B3%95%E3%81%BE%E3%81%A8%E3%82%81/

https://fixel.co.jp/blog/tailwindcss/

https://zenn.dev/seuyu_bin/articles/bfdcdc46b36a42

https://qiita.com/ryohashimoto/items/f5382478c78f296d8291
M5Paperで日本語Webサイトの内容を表示する

自分でやってて色々詰まったところのメモ。

#httpsでWebサイトにアクセスする
iOSやMacだったらOSのAPIを使用すればデフォルトでインストールされているルート証明書を使ってうまいことしてくれるけれど、Arduino互換機にそういうのはないので、自分でWebサイトのルート証明書をAPIに渡さなければならない。
https://qiita.com/suin/items/59491e44f3e73a1984ff
こちらを参考にしてFireFoxで.pemファイルを取ってきた。
コードに直打ちしてもいいんだけど、後で変えたくなるかもしれないのでSDカードに入れることにした。その場合はこんな感じ。

```C++
// Load PEM file in SD card
String root_ca;
File pemFile = SD.open("/root_ca.pem");
if (pemFile)
{
  root_ca = pemFile.readString();
  pemFile.close();
}

// Load URL via https
String urlString = "https://somewhere/"
HTTPClient httpClient;
httpClient.begin(urlString, root_ca.c_str()));
```

#Chunkを結合しながらパースする
これであとはhttpClient.getStreamPtr()からstream->readStringUntil('\n')で一行ずつパースすればいいと思っていた。ところが実際にやってみたら、日本語が途中で切れたり16進数のようなものが混じったりした。ターミナルをよく見るとこういうメッセージが出ていた。

```
[D][HTTPClient.cpp:1264] handleHeaderResponse(): Transfer-Encoding: chunked
```

Transfer-Encoding: chunkedって何？これだった。
https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Transfer-Encoding

つまりレスポンスヘッダにこれが返ってきたら最初の行はサイズを表す16進数になっていて…CR+LFの次からそのサイズだけ読んだらCR+LFでぶった斬られ、またサイズを表す16進数が入り…の繰り返しになっている。ウワーッめんどくさい！でもでかいStringを作るのも嫌だしやるしかないか…

```C++
String firstLine = stream->readStringUntil('\n');
if (!firstLine.startsWith("<"))
{ // Chunk size line
  useChunk = true;
  chunkSize = strtol(firstLine(), NULL, 16);
}
```
HTTPClientってレスポンスヘッダ読めないのかな？方法が見つからなかったのでHTMLなら<!DOCTYPE html>から始まるだろうと思って、そうじゃなかったらチャンクを使用しているだろうという乱暴なことをした。まあ特定のサイトのみ見るならいいか…
ところでArduinoのStringはUTF-8が入っているので、日本語のようなマルチバイト言語では日本語で言う1文字を構成する複数のバイトの間でチャンクが切れている可能性がある。けど、UTF-8の2バイト目から始まっているStringがあったところで別にそこはチェックされないらしいので、そのまま繋げてしまえば大丈夫だった。
#日本語フォントを読み込む
こちらを参考にさせていただいたけど、フォントは普通にSDカードに置いた。
https://neocat.hatenablog.com/entry/2021/04/10/073043

```C++
M5EPD_Canvas canvas(&M5.EPD);
```

```C++
// load font
canvas.loadFont("/font.ttf", SD);
canvas.createRender(36, 256);
canvas.setTextSize(36);
```

フォントはIPAフォントとか…M+フォントとかが使いやすそう。
https://moji.or.jp/ipafont/
https://mplus-fonts.osdn.jp

#行の折り返しとかを計算する
Canvasに文字列を折り返しながら描画すると高さがどうなるか返す関数とか無いのかなと思ったら無かった。
https://docs.m5stack.com/en/api/m5paper/epd_canvas
文字列の幅を返す関数ならあるように見えるじゃんか。これ、TTFフォントを読み込ませた状態だと0を返すらしい。

```C++
int16_t textWidth(const String& string)
```

じゃあ等幅フォントを使って（英数字部分は過大に計算されるとしても）文字数から幅を計算して…それを指定の幅で折り返すと何行になるという計算をするしかないか…でも思い出してほしい。StringはUTF-8なので、length()はバイト数しか返ってこない。
結局こちらを参考にして、日本語の文字数を計算するコードを書いた。サロゲートペアはどうなんのかな
https://yama-3.net/c/str-count3

#指定エリアに描画する
まあ書いてあるけど、setTextWrapで折り返しをオンにして、setTextAreaでさっき計算した高さとかを指定して、printすればいいらしい（drawStringではない）。折り返しにxとyがあるんだけどxはfalseでもいいのかな…
https://docs.m5stack.com/en/api/m5paper/epd_canvas

```C++
canvas.setTextWrap(true, true);
canvas.setTextArea(x, y, width, height);
canvas.println(text);
```

できた。
![IMG_0919.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37794/bfa4fccc-1579-9948-a4f2-fbfa5814bdfb.jpeg)
Chatwork独自のMarkdown記法　チートシート

# はじめに
業務でChatworkを使用する機会があり、独自の記法ルールを自分用にまとめました。
記載漏れ等ありましたら、コメントにて教えていただけますと助かります！

Slackの記法ルールは以前にこちらでまとめております。
>[Slack独自のMarkdown記法　チートシート](https://qiita.com/tamakiiii/items/ef91f18f9d22ed863950)

# 装飾用ショートコード一覧
* 罫線
* 囲み枠
* 囲み枠のタイトル
* 絵文字の自動変換を無効化

## 罫線
記法方法：罫線を挿入したい箇所に**[hr]**を入力
![スクリーンショット 2022-01-16 17.44.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554111/4c76bfc5-85d7-b4d1-2494-a46383455383.png)
↓結果
![スクリーンショット 2022-01-16 18.22.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554111/70bf69fa-b249-1f62-3810-3300b53c54d8.png)


## 囲み枠
記載方法：囲み枠を付けたいメッセージを**[info][/info]**で囲む
![スクリーンショット 2022-01-16 18.12.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554111/13798ec1-df2e-74ec-8821-02e4a9a0bd69.png)
↓結果
![スクリーンショット 2022-01-16 18.21.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554111/d2600ae9-e0fe-c210-18f3-9be8e91feb67.png)

## 囲み枠のタイトル
記載方法：囲み枠を作成した上で、見出しにしたい文字列を**[title][/title]**で囲む
![スクリーンショット 2022-01-16 18.29.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554111/1701534f-f31e-0287-73de-380a0056d1e6.png)
↓結果
![スクリーンショット 2022-01-16 18.31.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554111/7da88be6-61ab-5ad7-d9cf-e7a2237c916c.png)
※タイトル（[title][/title]）は囲み枠（[info][/info]）と併用せず、単体でも使用可能。

## 絵文字の自動変換を無効化
記載方法：変換したくない文字列を**[code][/code]**で囲む
![スクリーンショット 2022-01-16 18.35.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554111/b059ba31-fd8f-a0dd-0d65-52b8ebbc930a.png)
↓結果
![スクリーンショット 2022-01-16 18.35.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554111/f54effe0-49e0-7c0d-a361-29fc12ff0ae7.png)


# 参考
* [Chatwork（チャットワーク）の装飾タグの種類と装飾する方法](https://go.chatwork.com/ja/column/usage/usage-010.html)
* [チャットワークでショートコードを使いメッセージを装飾しよう](https://ishikawa-blog.com/chatwork-short-code-message/)
PHPで発生したエラーを画面に出力する方法



PHPのエラーをブラウザに表示させる方法

```
sudo vi /etc/php.ini
```

「/display」で検索

「エラーをHTML出力の一部として画面に出力するかどうか」の設定。OffをOnに変更。

```
display_errors = Off → display_errors = On
```

「display_errorsをOnにしても、自分で書いた<??>内のプログラムエラーしか表示しませんよ」という設定。OffをOnに変更。

```
display_startup_errors = Off →　display_startup_errors = On

```
続 FreeDOSでpccard

以前ハムフェアで100円で入手したENEのCB-1410があったのでAprivaに入れてみました。

いろいろ探してみたところDOS(16Bit)でPCI BIOSをアクセスするサンプルコードがありました。watcomのコンパイラーとnasmでビルドできるようなので、環境はすでに構築済みです。

ENEはデーターシートを公開していないようなのですが、FreeBSDのコードを見ているとTIの製品と同じように処理できるようなので、TIのPCI1410のデータシートを参考にすることにします。型番からして、コンパチ製品なのかもしれません。

ENEはかなり後になってから製品を出していて、DOSのサポートはまったく無かったようです。

とりあえずcardbusは後にしてPCMCIAをいじってみます。

レジスタの44HにIOアドレスを設定してそこを使って処理できるようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/943b2d78-108f-ea03-7423-d131ed860e4f.png)

その処理内容はここに書かれてありました。すごいです。

http://oswiki.osask.jp/?PCIC

コードはここでいじります。

https://github.com/yamori813/dos_pccard

とりあえずPCMCIAカードをISA空間に貼り付けることを目標にします。

こういうのって、物理マシンじゃないと楽しめないですね。

FreeBSDの上でビルドして自分で作ったmTCPのtftpでexeをコピーして試しています。

DOSのメモリやIOはこのようになっていました。

![DOS_MEM_IO.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/50269f8c-abf8-c441-7b39-8b4e9363ff33.png)

8086は8080由来のメモリとIOが別々のアドレス空間で使えました。

メモリ空間は20bitで1Mバイトで前半はプログラムの実行などに利用するRAMですが後半はVGAなどのデバイスで使われていました。

IO空間は8080は8bitで256でしたが8086では16bitになり、64kになりました。

デバイスは以下のパターンがありました。

* IO空間だけ利用
* メモリ空間だけ利用
* IO空間と割り込みを利用
* メモリ空間と割り込みを利用
* IO空間とメモリ空間と割り込みを利用

PCMCIAの場合アドレス空間はメモリー空間が2つとIO空間が1つあります。メモリー空間の一つは属性やコンフィグレーションを行う空間で、もう一つは実際のメモリー空間です。カード情報(CIS)は属性空間にあり、これを読む必要があります。もし事前にCISを読んでindexやCCORのアドレスを決め打ちで設定するにしても、属性空間にあるCCORへの書き込みは必須になります。

初期のISAのカードはディップスイッチでIOアドレスなどを代えるようになっていました。たとえばシリアルのカードはデフォルトが0x3F8(COM1)か0x2F8(COM2)になっていたと思われます。内蔵でCOM1,COM2がある場合はこれ以外に代える必要があります。

PCMCIAのコンフィグレーション機構はISAのPnPとは違っているようです。USBのコンフィグレーションのプロトタイプのような感じもします。

DOSで常駐型のプログラムにする必要があるのはAPIを提供するか、または割り込みの処理を行う場合です。これ以外の場合は常駐型にする必要はないので、カードの抜き差しの検知をしなければ、普通のアプリでもカードの設定はできると思います。

PCMCIAカードで16Bitマイコンなどを搭載してホストからファームをダウンロードするタイプのカードもありました。おそらくこれらはメモリー空間にカードのメモリをマップして書き込んで、その後マイコンを動かすような仕組みだったのではないかと想像されます。

昔の情報を調べていると、カードサービスに対応したドライバーが一般的だが、それ以外に直接82356を叩くスタンドアローンのドライバや設定プログラムもあったよいうだ。

結局CardBus Socket/ExCA Base Address(10h)を使って0xb0000-0xb0fffに貼り付けて、メモリウインドウを0xb1000-0xb1fffにして処理するようにしました。

どうにかCISが見えるようになったのですが、CISに含まれるConfiguration map(0x1a)にCCORのオフセットがあるので、CISのConfiguration entry(0x1b)の設定するindexをそこに書き込むとそのアドレスが、有効になります。

4KのCISのメモリウインドウにCCORもあればそのままいけるが、4Kより上にある場合は貼り付けなおさなければいけない。