OmniAICreator/Qiita-1.07M huggingface dataset:
SwiftUI & Combine オススメライブラリ3選！

# はじめに
想定読者： SwiftUI / Combine を **メイン** にしたネイティブアプリ開発を行っている（予定な）方
執筆環境：Xcode 12.4 / macOS Big Sur 11.2.3

この記事は **寄付を身近にする dim.** の開発を行う中での学びを共有する目的で執筆しております。
TechCrunch さんにも取り上げていただきましたので御覧ください。

https://jp.techcrunch.com/2021/03/18/dim/

# 前提
- SwiftUI がメインで UIKit は極力使わない
- デザイナーさんのデザインが実現できていること
- Combine を利用し、 RxSwift などは利用しない

# 1. FirebaseSDK を Combine で制御

https://github.com/rever-ai/CombineFirebase

[rever-ai/CombineFirebase](https://github.com/rever-ai/CombineFirebase) が非常に参考になります。
主観にはなりますが、 **非常にシンプルなライブラリ** になっておりますので、ライブラリとして導入するのではなく必要な部分を参考に **独自実装** する方法でも良いかと思います。

https://github.com/alickbass/CodableFirebase

Combine とは直接的な関係のないものになりますが、追加でご紹介するのが [alickbass/CodableFirebase](https://github.com/alickbass/CodableFirebase) です。
レスポンスを Codable で扱いたい場合に便利です。

# 2. UIKit の要素にアクセスしたいと思ったら

https://github.com/siteline/SwiftUI-Introspect

SwiftUI はこの記事執筆段階でまだ未熟です。
例えば「UIKit.UITableView.separatorStyle を .none にするみたいなことが SwiftUI.List でもしたいなぁ」などと1度は思って検索したことがあるはずです。そんな希望を叶えてくれるのが [SwiftUI-Introspect/SwiftUI-Introspect](https://github.com/siteline/SwiftUI-Introspect) です。

先程の例であれば以下のように実装可能になります。

```swift
List {
    Text("Item 1")
    Text("Item 2")
}
.introspectTableView { tableView in
    tableView.separatorStyle = .none
}
```

SwiftUI から利用できる UIKit 風 UI ライブラリなどを都度導入するよりも汎用的な SwiftUI-Introspect を利用するほうが **依存が1つで済む** ので **外部依存の最小化** の点でもオススメできるのではと考えています。
また、処理が分散しにくいので、将来的に **SwiftUI が成長したとき** にも対応スピードが高まるのではないかと考えています。

# 3. Alamofire を Combine で制御（近い未来）

https://github.com/Moya/Moya/releases/tag/15.0.0-alpha.1

Alamofire に依存する形で作成された [Moya](https://github.com/Moya/Moya) をご存知でしょうか。
このライブラリが遂に Combine に対応しようとしています。 Combine 発表後、 issue で多くの議論がされていましたが、 Alpha 段階まで来ているようです。正式リリースが楽しみですね！

# さいごに
最後までご覧いただきありがとうございます。
外部ライブラリとの依存は最小限にするためにも **慎重な判断** が必要です。参考にしていただけますと幸いです。

SwiftUI で FirebaseSDK を利用する場合、まだ未対応な機能も多く存在します。
こちらも参考にどうぞ
[SwiftUI ベースのプロジェクトでの FCM 実装注意点](https://qiita.com/AkkeyLab/items/2c093909f94ca7aa5f3c)
AWSソリューションアーキテクトアソシエイト受験記

2021年4月中旬にAWSソリューションアーキテクトアソシエイトを受験してきたので、
備忘録の意味も込めて、やってきたことをまとめます。

# AWSソリューションアーキテクトアソシエイトとは

![aws-certified-solutions-architect-associate.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329544/16dc878c-e945-84c9-d0ea-51b35c765bd8.png)


AWS認定の資格試験です。
ソリューションアーキテクトアソシエイトは1年間の業務経験を積んだ中級者向けの試験です。
気になる方は、以下URLから詳細をご確認ください。  
  
[AWS 認定 ソリューションアーキテクト – アソシエイト](https://aws.amazon.com/jp/certification/certified-solutions-architect-associate/)

# 受験の背景

この資格試験を受験しようと思った背景は以下です。

- 日頃業務でクラウドサービスを利用している
  - 内訳としては AWSを1年程度(2年前)、Azureを2年半程度
- しかし資格を何一つ持ってない
- 自分の実力を測ってみたかった
- 自社でAWS資格試験取得を推進している
- クラウドサービスの最新動向が知りたい

経歴としてはAzureの方が長く触っていましたが、クラウドサービスの考え方を学んだのはAWSで、個人的にAWSの方が好きだったため、先にAWSの資格試験を受験しました。
5〜6月にAzureの資格試験も受験しようと思ってるので、そちらも受験後に記事を書こうと思ってます。  

# 受験前にやったこと

![study_night_boy.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329544/180bbc17-d3b7-7efd-01fb-20cbcd31226a.png)

私が受験前にやったことは、オンライン問題集を使っての勉強がメインでした。
問題を解いてわからないことがあったらひたすらドキュメントを読み、理解を深めていきました。
勉強期間としては2週間程度です。

使用教材としては以下2つです。  

1. [udemyの問題集](https://www.udemy.com/course/aws-knan/)  
【SAA-C02版】AWS 認定ソリューションアーキテクト アソシエイト模擬試験問題集（6回分390問）
1. [koiwaclubの問題集](https://aws.koiwaclub.com/)

それぞれの解いてみた感想を次に書きます。

## udemyの問題集

[この問題集]((https://www.udemy.com/course/aws-knan/))は、難易度の高い問題を集めたものということもあって、かなり難しかったです。
そして何より、AWSにほとんど触れていなかった期間が2年ほどあり、その間でサービスがどんどん新しくなっていたため、空白期間を埋めるのに一苦労しました。  

初回に解いた際のスコアは以下でした。(合格は72%です)  

| 試験番号 | 正答率 |
|--:|--:|
|       1 |  75% |
|       2 |  56% |
|       3 |  52% |
|       4 |  70% |
|       5 |  61% |
|       6 |  56% |

各回解いてから、わからなかった問題や気になった問題を中心にドキュメントを読みました。
そして自分なりの解釈をひたすらノートに書き起こし、読み上げ、耳で聞くという五感をフル活用した覚え方をしてました。
(高校・大学受験をちょっと思い出しました)

## koiwaclubの問題集

[有料会員登録](https://aws.koiwaclub.com/paid-membership-registration/)するとソリューションアーキテクトアソシエイト対策の問題を約1000問見ることができます。
一問ずつ短時間で解けるので、隙間時間に問題が解けるというのがとてもよかったです。  

私の場合、勉強期間を短く設定してしまったため、全ての問題をゆっくり勉強する余裕がなかったので、降順に解いてわからない問題を重点的に振り返る方針で進めました。  

# 結果

結果として、ギリギリのスコアで合格できました。

![受験結果.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329544/a2781a88-7194-c131-ac05-8c5649742e39.png)

今回この資格試験を通して学んだこととしては、AWSの最新情報は常にキャッチアップしていかなければ取り残されるということです。
「別のクラウドサービスを使ってるから大丈夫だろう」という気持ちは取っ払い、常に最新情報をキャッチアップしていこうと思います。
まずはRSSを使って自分のスマホに通知する仕組みづくりからやっていこうと思います。  

これから受験を考えられている方の参考になれば幸いです。
MySQLのLOAD DATA INFLEコマンドでファイルをインポートする

## はじめに

担当している案件でMySQLで大量（10万件規模）のデータをinsertする必要があったため、
[LOAD DATA INFILE コマンド](https://dev.mysql.com/doc/refman/5.6/ja/load-data.html)でデータをインポートした際のナレッジや調査過程をまとめました。

案件で使用していたフレームワークがLaravelだったため、Laravel寄りのリンクが多くなっていますが、
他の言語/フレームワークでも、SQLを直接発行出来る機能があれば、代用は可能かと思います。

またMySQL以外でもOracleでも同様のコマンドがあるので、DBをOracleに変えた場合でも同じ実装は可能かと思います。

## 注意点
### MySQLの起動オプションにlocal_infileを追加
MySQLの起動オプションにlocal_infileの設定を追加します。
以下のファイルに下記のように設定を追加してください。
```/etc/mysql/conf.d/my.cnf
local_infile=true
```
`mysql`コマンドの場合は上記のオプションを引数に追加して起動しましょう。
configファイルに追記した場合は、MySQLのサービスの再起動も忘れずに！

### デバッグ/エラー解析
LOAD DATA INFILE コマンドは、MySQL側のインポート機能を直接呼び出す仕組みのため、
SELECT文やINSERT文のSQLの発行時のようにアプリケーション側のログにエラー内容が出力されることがありません。
そのため、デバッグやエラー解析は困難を極めます。
インポート先のテーブル名やカラム定義、インポートするファイル名やファイルパス等は念入りに確認しておいた方が良さそうです。
意外にtypoしていたりすると、気付かずハマります（苦笑）

## 参考
* [LaravelでデータをDBに保存したいときのメモリ不足をなんとかする](https://kyamashiro.hateblo.jp/entry/2019/09/16/102743)
* [LaravelでLOAD DATA LOCAL INFILEできない](https://qiita.com/hondy12345/items/ca5fdc4573292f3fcf5d)
* [Laravel ExcelパッケージでCSVデータをDBへ一括登録する方法](https://minory.org/laravel-excel-csv.html)
* [REPLACEとAUTO_INCREMENTを使用してLOADDATAINFILEを実行しようとしています](https://www.it-swarm-ja.tech/ja/mysql/replace%E3%81%A8autoincrement%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%A6loaddatainfile%E3%82%92%E5%AE%9F%E8%A1%8C%E3%81%97%E3%82%88%E3%81%86%E3%81%A8%E3%81%97%E3%81%A6%E3%81%84%E3%81%BE%E3%81%99/1066963350/)
* [【MySQL】LOAD DATA INFILE でCSVデータをインポートしたい](https://teratail.com/questions/12977)
* [MySQLの「load data LOCAL infile」の「LOCAL」って何？どこ？](https://www.ipvx.info/everyones-db/mysql/what-local-load-data-local-infile/)
* [MySQL LOAD DATA LOCAL INFILE で特定列を指定してインポートする](https://saoline.co/wordpress/?p=1479)
JavaScriptで巨大な配列処理を行う時はジェネレーターが便利

JavaScriptで配列から指定した数の組合せを作る関数を作ったところ、組合せの数が数千万になるケースがあり、Node.js(v14.16.0)で実行したら使用できるメモリの上限に達したというエラーが出てしまいました。

```
FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
```

以下のように[--max-old-space-size](https://nodejs.org/api/cli.html#cli_max_old_space_size_size_in_megabytes)オプションを指定してNode.jsで使用できるメモリを増やせば動くようになったのですが、

```terminal
$ node --max-old-space-size=8192 index.js
```

ES2015で追加された[ジェネレーター(Generator)](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Generator)を教えてもらったので書き直してみました。

**差分**

```diff_javascript
- function combine(list, n) {
+ function* combine(list, n) {
      const len = list.length;
-     const result = [];
      const indexes = [];
      for (let i = 0; i < n; i++) {
          indexes.push(i);
      }
      const lastPos = n - 1;

      while (indexes[0] + n <= len) {
          while (indexes[lastPos] < len) {
-             result.push(indexes.map(i => list[i]));
+             yield indexes.map(i => list[i]);
              indexes[lastPos]++;
          }

          for (let pos = lastPos - 1; pos >= 0; pos--) {
              indexes[pos]++;
              const lastIdx = indexes[pos] + (lastPos - pos);
              if (lastIdx < len) {
                  for (; pos + 1 < n; pos++) {
                      indexes[pos + 1] = indexes[pos] + 1;
                  }
                  break;
              }
          }
      }
-
-     return result;
  }

  const list = ['a', 'b', 'c', 'd', 'e'];
  const n = 3;
- const result = combine(list, n);
- console.log(result);
+ for (const combi of combine(list, n)) {
+     console.log(combi);
  }
  /*
- [
-   [ 'a', 'b', 'c' ],
-   [ 'a', 'b', 'd' ],
-   [ 'a', 'b', 'e' ],
-   [ 'a', 'c', 'd' ],
-   [ 'a', 'c', 'e' ],
-   [ 'a', 'd', 'e' ],
-   [ 'b', 'c', 'd' ],
-   [ 'b', 'c', 'e' ],
-   [ 'b', 'd', 'e' ],
-   [ 'c', 'd', 'e' ]
- ]
+ [ 'a', 'b', 'c' ]
+ [ 'a', 'b', 'd' ]
+ [ 'a', 'b', 'e' ]
+ [ 'a', 'c', 'd' ]
+ [ 'a', 'c', 'e' ]
+ [ 'a', 'd', 'e' ]
+ [ 'b', 'c', 'd' ]
+ [ 'b', 'c', 'e' ]
+ [ 'b', 'd', 'e' ]
+ [ 'c', 'd', 'e' ]
  */
```

修正前のコードは、組合せの配列を作り、その配列を返していたのですが、修正した方はループしつつも値を一つずつ返すようになります。

何を言っているのかわからないと思うのですが、ジェネレーターはyieldで値を返し、そこで処理を一時停止します。

そして次呼ばれた時に続きから実行し、またyieldに到達したら値を返して一時停止します。
一時停止するってすごいですよね。

値を順番に一つずつ返す考え方はイテレーターと同じで、ジェネレーターはイテレーターを書きやすくしたものだそうです。

以下のようなジェネレーターの使用例を見てもメリットがよくわからなかったのですが、こういう風に使うとメモリへの負担を少なくできる:point_up:ということがわかりました:grinning:

```javascript
function* generator() {
    yield 1;
    yield 2;
    yield 3;
}

const gen = generator(); // "Generator { }"
for (const v of gen) {
    console.log(v);
}
/*
1
2
3
*/
```

```javascript
function* infinite() {
    let index = 0;

    while (true) {
        yield index++;
    }
}

const generator = infinite(); // "Generator { }"

console.log(generator.next().value); // 0
console.log(generator.next().value); // 1
console.log(generator.next().value); // 2
```
明日の予定をGASで毎日自分のメアドに送信させる。

# え、この予定明日じゃん。ってことは今は...
「明後日の予定を明日の予定と間違える」というなんともあほらしいことを二回もやってしまった。Googleカレンダーのアプリを週で表示していて、1列違うところを見てしまっていた。
ならばということで、テキスト情報で自分のメールに飛ばすように設定した。だいたい夜の21時くらいに送ってもらえば寝る前かつ明日の準備もできるかつ覚えてられるかなということで、21時から22時の間に毎日定期実行されるようにした。

**注意！以下のコードは最後のhoge@example.comを自分の受信したいメアドに変更してください**
これはコピペで使われるのが一番多いと思うので、一応注意書き。

```js
const main = () => {
  const tomorrow = new Date()
  tomorrow.setDate(tomorrow.getDate() + 1)
  const tomorrowEventsOnDefaultCal = CalendarApp.getDefaultCalendar().getEventsForDay(tomorrow)
  const msg = tomorrowEventsOnDefaultCal.reduce((previousMsg, event) => {
    const start = event.getStartTime()
    const end = event.getEndTime()
    const result = `${formatTime(start)} - ${formatTime(end)} ${event.getTitle()}\n`
    return previousMsg + result
  }, '');
  GmailApp.sendEmail('hoge@example.com', '明日の予定', msg)
}

const formatTime = (date) => {
  const hours = date.getHours() > 9 ? date.getHours() : '0' + date.getHours()
  const minutes = date.getMinutes() > 9 ? date.getMinutes() : '0' + date.getMinutes()
  const formatted = `${hours}:${minutes}`
  return formatted
}
```

## 軽く機能紹介

 - 時間を簡単にフォーマットした。
    - フォーマットする関数にまとめときました。
 - Array.prototype.reduceを使ってスマートに見せてる。
    - ひっさびさにjs書いたので、もっとスマートなのがあった気がしてならない。
    - 最初はforeachで書いて、あれ？と思って調べたらreduceが出てきた。
 - 定期実行は何時にしてもたぶん明日の予定を表示してくれる。自分の場合は21時から22時にしたけど、別に何時でもよい。

## 最後に
GASってコピペで動いてほしいですよね。
もしコピペ(+メアド編集)で動かなかったら教えてください。
LoadAverage(ロードアベレージ)とは一体何者？

## はじめに
運用保守の業務に携わっていて、CPU、Memory、Diskのリソース監視の項目の並びにLoadAverageなるものが存在します。『サーバー負荷の状況を判断する項目』くらいの浅い認識しか持っていなかったので、これの正体について調べてみました。

## LoadAverageとは？
LoadAverageとは、『１CPUに対して、平均的にどれだけプロセスが実行待ちになっているか』を示す指標で、この数値が高いとLinuxのシステムが高負荷の状況であることを意味します。
そして、Linuxプロセスの状態について、以下の表が示すように複数の状態が存在します。この中で、LoadAverageの数値に影響するのが、**`TASK_RUNNING`**と**`TASK_UNINTERRUPTIBLE`**となります。この2つのプロセス数が多いと、色んなプロセスがCPUに対して処理を求めているけど、サーバが捌き切れないため、そのプロセスが後ろに待ち行列を作っている状態を意味しています。そのため、LoadAverageの数値が高いほど、そのサーバの負荷は高い状態ということになります。

| プロセス | 状態 |
|---|---|
| TASK_RUNNING  | CPU上で実行中、あるいは実行可能で CPUの割り当てを待っている状態  |
| TASK_INTERRUPTIBLE  | 割り込みが可能だけど、ユーザの入力待ちなどで、いつ復帰するかわからない状態  |
| TASK_UNINTERRUPTIBLE  |  サーバの負荷が高く、ディスクI/Oなどで割り込み不可の待ち状態 |
| TASK_STOPPED  | プロセス停止状態  |
| TASK_ZOMBIE  | ゾンビ化状態。いわゆるゾンビプロセス  |

## LoadAverageを炙り出すには？
LoadAverageの正体がわかったので、次は実際にこの数値を炙り出します。

- uptimeコマンド

```
[hoge@test ~]$ uptime
 16:06:08 up 248 days,  5:56,  1 user,  load average: 0.54, 0.57, 0.35
[hoge@test ~]$
```

- topコマンド

```
[hoge@test ~]$ top
top - 16:05:35 up 248 days,  5:55,  1 user,  load average: 0.47, 0.57, 0.34
Tasks: 135 total,   1 running, 105 sleeping,   0 stopped,   0 zombie
Cpu(s):  4.8%us,  0.7%sy,  0.0%ni, 94.3%id,  0.2%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:   7953580k total,  6483128k used,  1470452k free,   215532k buffers
Swap:  7953576k total,    28672k used,  7924904k free,  1781460k cached
  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
17164 jetty     20   0 5913m 2.4g  19m S  7.3 31.4   9:23.61 java
 3827 rundeck   20   0 3802m 1.3g  17m S  3.3 17.7 168:27.61 java
 2382 root      20   0  574m  59m 3860 S  0.3  0.8  34:22.45 ruby
    1 root      20   0 19692 1668 1408 S  0.0  0.0   0:04.29 init
[hoge@test ~]$ top
```
他にも確認方法ありますが、代表的な2つのコマンドで試しました。実行結果の以下部分がLoadAverageの数値となります。

```
load average: 0.54, 0.57, 0.35
```
数値が3つ並んでおり、左から順に、**`1分前の数値(0.54)`、`5分前の数値(0.57)`、`15分前の数値(0.35)`**
となります。

## LoadAverageの正常値は？
先ほど、LoadAverageの数値を確認しましたが、正常値かどうかの判断はCPUのコア数で判断します。かつてシングルコアが主流の時代は、LoadAverageは1以下であれば無条件で正常値と判断されていたようですが、現在はマルチコアも存在するため、コア数によって正常値が異なる点は注意が必要です。
そのため、コア数が1つであれば、正常値は１以下になり、コア数が２つであれば、正常値は２以下になります。では、先程のサーバーのコア数を確認してみましょう。

- コア数確認のコマンド

```
[hoge@test ~]$ grep cpu.cores /proc/cpuinfo | sort -u
cpu cores	: 1
[hoge@test ~]$
```
このサーバーはコア数１と分かりましたので、正常値は１以下となり、今回炙り出したLoadAverageは正常値と判断されます。

## 最後に
今回、Linuxのシステム限定の話でしたが、Windowsの場合はLoadAverageを確認できるコマンドやツールがないらしく、CPUやMemoryの使用率から判断したり、タスクマネージャから負荷状況を確認するそうです。私の浅いリサーチによる情報ですので、もし認識違ってましたら、ご指摘いただけますと幸いです。

##参考
[「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典](https://wa3.i-3-i.info/word11699.html)
[マルチコア時代のロードアベレージの見方](https://naoya-2.hatenadiary.org/entry/20070518/1179492085)
[ロードアベレージでサーバの負荷を確認する](https://beyondjapan.com/blog/2016/02/stress_check/)
[【CPUの基本】図解でよくわかる「マルチコア / スレッド」の意味](https://chimolog.co/bto-cpu-core-thread/)
CSRF(クロスサイト・リクエスト・フォージェリ)の危険性とその対策について

<h2>CSRF(クロスサイト・リクエスト・フォージェリ)とは</h2>
CSRFを一言で表すと<b>『Webサイトにログインしたユーザが悪意ある人間によってあらかじめ用意された罠によって、意図しないリクエストを送信されてしまう脆弱性』</b>です。
被害者は脆弱性のあるWebサービスにログイン状態を保持したまま他サイトの掲示板等で悪意ある人によって投稿されたURLをクリックすると被害者が意図しない形で情報やリクエストが送信されてしまいます。
具体的な被害としてはログインしているWebサービスでの設定の変更(パスワードの変更など)、掲示板への不適切な内容の書き込みが気づかないうちに実行されてしまいます。
過去にCSRFの被害者が自分のIDで掲示板に殺害予告が書き込まれ誤認逮捕されてしまったケースもあるので恐ろしい脆弱性です…

<h2>CSRFの対策</h2>
CSRFが起こってしまう原因は脆弱性のあるサイト(以後脆弱性サイトと呼ぶ)のリクエストが<b>内部からなのか外部からなのかが判別されていないからです。</b>


例えば脆弱サイトで名前を変更するために以下のようなHTMLが用意されていたとします。

```html
<form action="change-name.php" method="get">
    <label>新しい名前</label>
    <input type="text" name="name" value="">

    <input type="submit" value="送信">
</form>
```

名前の変更処理はformタグのactionにあるようにchange-name.phpで行われるとします。
getで送信しているので名前に田中と入力して送信ボタンを押すとこのようなurlが生成され送信されます。
``http://zeizyaku-site/change-name.php?name=田中``
この脆弱サイトのchange-name.phpではユーザがログインしていたらこの``name=田中``をPOSTで受け取り名前を変更します。

しかし、問題なのはこのurlはサイトの外部からでも送信できてしまいます。
例えばある掲示板サイトに悪い人がこのようなURLを投稿したとします。
``http://zeizyaku-site/change-name.php?name=バカ``

この``name=バカ``とあることから、仮に掲示板のこのURLをクリックしたユーザが脆弱サイトにログインしていたら勝手に名前をバカに変更されてしまいます。
これは外部からのリクエストなのにかかわらず、脆弱サイトはその見分けがつかないためこの内容で実行されてしまいます。

<b>なので対策としてはWebサイトがリクエストを内部からなのか外部からなのかをきちんと見分けをつけれるようにすることです。</b>

そのためには<b>トークン</b>というものを使用します。
トークンというのは簡単に言うとコンピュータ側が使用するパスワードみたいなもので「ワンタイムパスワード」と言うとイメージしやすいと思います。

このトークンはPHPならば``session_id()``のような関数を使用します。自作でトークンを作成すると推測される恐れがあるので提供されている関数を使ったほうが安全です。

```php
<?php
// トークンを生成するコード
session_start(); // セッションを開始すると自動でセッションIDが発行される
$session_id = session_id(); // 現在のセッションIDを取得

echo $session_id; // 予測不能なランダムな値が表示される。　例：k12hc94du3tfubihqhip9leupl
?>
```
session_id関数は引数を渡さずに呼び出すと現在設定されているセッションIDを取得できます。

トークンは予測不可能な値をサーバーサイドで生成して、それをHTMLフォームにhiddenで持たせておきます。

```php
<form action="change-name.php" method="get">
    <label>新しい名前</label>
    <input type="text" name="name" value="">
    <input type="hidden" name="token" value="<?php echo session_id()?>"> <!--トークンを持たせておく-->

    <input type="submit" value="送信">
</form>
```


トークン情報を一緒に送信して、サーバーサイドで名前の変更を行う前に設定されているセッションIDと送信されたトークンが一致するかを調べます。

```php
<?php
//change-name.phpでの処理
session_start();
// トークンのチェック
if(session_id() === $_GET["token"]){
    $name = $_GET["name"];
    // 以下名前の変更処理をする
}
?>
```

このトークンは他の人間には知られることはまず無いため、外部からのリクエストで名前を変更することは不可能になります。
仮に先程の掲示板に貼られたURLの
``http://zeizyaku-site/change-name.php?name=バカ``
をクリックしてもトークン情報がないためこのリクエストは処理されません。

<b>CSRFを防止するためにも必ずトークンを使用して、内部からのリクエストからしか受け付けないようにするようにしましょう。</b>
CPUの性能指数

基本情報の1項目であるCPU性能指数について理解する。

## クロック周波数
- コンピュータは「クロック」と呼ばれる周期的な信号に合わせて動くのが決まりになっている。
- CPUもこの「クロック」と呼ばれる周期信号に合わせて動作を行なっている。
- 1周期の時間が短ければ短いほど、より多くの処理ができる(すなわち性能が高い)。

![クロック周波数.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1247585/81f93457-b9ea-68e5-7675-a5917f612ca1.png)


### クロック周波数
クロックが1秒間に繰り返される回数のことをクロック周波数と呼ぶ。
例えば「クロック周波数1GHzのCPU」といった場合、１秒間に10億回(1Gは10^9回)振動していることになる。

### 1クロックに要する時間

```
１クロックに要する時間　　=  1秒　÷　クロック周波数
```

##CPI
- CPI(Clock cycles Per Instruction)とは、1命令あたり何クロックサイクル必要かを表すもの。

例：　実行に2クロック必要なら２CPIと表記。


### 命令実行時間

```
命令実行時間　= １クロックに要する時間　× CPI
```

例：　1GHzのCPUで3CPIにかかる時間は
1 / 10^9Hz × 3CPI = 3ナノ秒


##MIPS
MIPS(Million Instructions Per Second)とは「１秒間に実行できる命令の数」を表したもの
- 数字か大きくなりがちなので、命令の数は100万単位で表す。

MIPS値

```
MIPS = 1秒　÷ 命令実行時間
```

例：　1つの命令を実行するの平均2ナノ秒かかるCPUの場合のMIPS
１秒　➗　2ナノ秒　
= 1 / 2×10^9
= 0.5 × 10^9秒
= 500,000,000個
= 500MIPS

## 命令ミックス

- 命令ミックスとはよく使われる命令を一つのセットにしたもの。
- 出現頻度を%で表す。


### 命令ミックスの計算方法
例：　1GHzのCPUが次の命令セットでできていた場合のMIPS
  　命令① 実行時間 10クロック  出現頻度60%
    命令② 実行時間　５クロック　　出現頻度40%

- クロックサイクル時間　1秒　/ 1GHz = 1ナノ秒

命令① 命令実行に要する時間　＝　10クロック　×　１ナノ秒 = 10ナノ秒
命令② 命令実行に要する時間　＝　5クロック　×　１ナノ秒　= 5ナノ秒


- CPUの平均命令実行時間
１０ナノ秒　× 0.6 ＋　5ナノ秒　× 0.4秒　= 8ナノ秒

１秒に何百万回実行できるか(MIPS)
1秒　/ 8ナノ秒　
= 0.125 × 10^9秒
= 125000000
= 125MIPS


### 基本情報の過去問題①
動作クロック周波数が700MHzのCPUで、命令実行に必要なクロック数及びその命令の出現率が表に示す値である場合、このCPUの性能は約何MIPSか。


|命令の種別 |命令実行に必要なクロック数  |出現率(%)|
|---|---|---|
|レジスタ間演算|4|30|
|メモリ・レジスタ間演算|8 |60  |
|無条件分岐|10 |10 |

ア.10
イ.50 
ウ.70
エ.100

解説
①1命令ぞ実行するのに必要な平均クロック数は
(4×0.3)＋(8×0.6)+(10×0.1) = 7.0

②動作クロック周波数が700MHZのCPUが１秒間に実行できるクロック数は、以下のように表現できる。
１/ 700MHZ = 700百万クロック

③このCPUのMIPS値は
700百万クロック　÷ 7.0 = 100百万命令/ 秒　＝ 100MIPS

解答：エ

### 基本情報過去問題②

1GHzのクロックで動作するCPUがある。このCPUは、機械語の１命令を平均0.8クロックで実行できることが
わかっている。このCPUは１秒間に平均何万命令できるか。

ア.125
イ.250
ウ.80,000
エ.125,000

解説
1GHzのクロックで動作するCPUは、１秒間に１G回のクロックを発生させる。
「1命令を平均0.8回クロックで実行できる」ということは、
「1クロックで平均1÷0.8=1.25命令を実行できる」と言い換えられる。
したがって、１秒間に１G回のクロックを発生させるCPUでは
1G×1.25= 1.25G命令=125,000万命令を実行できる。

解答：エ


参考
令和02年　キタミ式イラストIT塾　基本情報技術者　きたみりゅうじ
令和03年【上半期】基本情報技術者 パーフェクトラーニング過去問題集
React + Material-UI: 無効化(disabled)したButtonにTooltipを表示・非表示する

Material-UIの`Tooltip`コンポーネントを`Button`に使ったとき、`disabled`との兼ね合わせで少し戸惑ったことについて書き留めます。


# Material-UIとTooltipコンポーネント
[Material-UI](https://material-ui.com/ja/)は、Googleが提唱する[Material Design](https://material.io/design)に則った、ユーザーインタフェースを提供するReactコンポーネントライブラリです(Material Designについては、「[Googleが推奨する『マテリアルデザイン』とは？5つの特徴と、メリット・デメリット・作り方について解説](https://tayori.com/blog/material-design/)」参照)。豊富なコンポーネントとシンプルで直感的なデザイン・操作感に定評があります。

`Tooltip`コンポーネントの使い方は、マウスが重なったたとき表示したい部品を包むだけです。`title`に与えたテキストがツールチップとして表れます。

```react
<Tooltip title="tooltip" arrow>
	<Button variant="contained" color="primary">
		button
	</Button>
</Tooltip>
```


# 無効化(`disabled`)した`Button`に`Tooltip`を出す
問題は、無効化(`disabled`)した`Button`を`Tooltip`コンポーネントで包んだ場合です。以下のようなメッセージが示されてしまいます。無効化された`Button`からはユーザー操作のイベントが送られないので、`Tooltip`が働かないということです。

```react
<Tooltip title="disabled" arrow>
	// 変数disabledの値はtrue
	<Button variant="contained" color="primary" disabled={disabled}>
		disabled button
	</Button>
</Tooltip>
```

> Material-UI: You are providing a disabled `button` child to the Tooltip component.
A disabled element does not fire events.
Tooltip needs to listen to the child element's events to display the title.

でも、この問題については公式サイトの「[無効な要素](https://material-ui.com/ja/components/tooltips/#disabled-elements)」(原文「[Disabled Elements](https://material-ui.com/components/tooltips/#disabled-elements)」)できちんと説明されています。`Button`を別の要素、たとえば`<span>`でつぎのようにくるんでしまえばいいのです。

```react
<Tooltip title="disabled" arrow>
	<span>
		<Button variant="contained" color="primary" disabled={disabled}>
			disabled button
		</Button>
	</span>
</Tooltip>
```

実は、メッセージにもそのヒントが示されていました。

> Add a simple wrapper element, such as a `span`.


# 動的に変わるButtonの有効・無効に応じてTooltipの表示・非表示を切り替える
筆者が困ったのは、無効化した`Button`には`Tooltip`を出したくないという場合でした。それなら、`Tooltip`を外せばいいと思われるかもしれません。でも、やりたかったのは、有効・無効は動的に切り替えて`Tooltip`を表示・非表示したいということです。

そこで、無効のときは包んだ要素の`style`に、`pointer-events: "none"`を加えることで対応しました。以下にCodePenのサンプルも添えます。`Button`の有効・無効は、`Checkbox`で切り替えてください。

```react
<Tooltip title="enabled" arrow>
	<span style={disabled ? { pointerEvents: "none" } : {}}>
		<Button variant="contained" color="primary" disabled={disabled}>
			button
		</Button>
	</span>
</Tooltip>
```

<p class="codepen" data-height="265" data-theme-id="light" data-default-tab="js,result" data-user="FumioNonaka" data-slug-hash="MWJZrLd" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="React + Material-UI: Tooltip issue">
  <span>See the Pen <a href="https://codepen.io/FumioNonaka/pen/MWJZrLd">
  React + Material-UI: Tooltip issue</a> by Fumio Nonaka (<a href="https://codepen.io/FumioNonaka">@FumioNonaka</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>
"Docker needs privileged access"が無限に出てくる

# 現象
Dockerを一度アンインストールし、再度インストールすると、"Docker needs privileged access"というダイアログが無限に出てきて、先に進めなくなる

# 環境
macOS Big Sur バージョン11.2.3

# 原因
詳しくはわからないが、Dockerを使うとあるファイルが作成されるのだが、そのファイルが再インストールの前後で整合性が取れなくなる

# 解決策
うろ覚えなので正確ではないです。すみません。

```
$ sudo chmod o-w /Library/LaunchDaemons/*
$ sudo chown root:wheel /Library/LaunchDaemons/myfile.plist
$ chmod 600 XXXXX.plist
```

# 参考記事
https://github.com/Homebrew/legacy-homebrew/issues/43855#issuecomment-141193186

https://stackoverflow.com/questions/40523307/brew-install-docker-does-not-include-docker-engine/43365425#43365425

https://github.com/docker/for-mac/issues/2687
【連載:Vue CLIのインストール】SAPを作成 = Django × RestFramework × Vue.cli 　


# 今回はDjangoプロジェクトにVueプロジェクトをインストールします。

[前回の記事](https://qiita.com/kiyokiyo1165/items/1371e32319370ecd89a5)

### Vue CLIのインストール

```sh
npm install -g @vue/cli
```
※ `-g`オプションは全体に適用するという意味。

### インストールの確認

```sh
vue --version
# @vue/cli 4.5.12
```

### Vue プロジェクトの作成

```sh
vue create <プロジェクト名>

```
以下の選択が必要

![スクリーンショット 2021-04-26 10.57.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/378066/26b3a52b-dd3d-3dfd-2084-50bc8789a2b4.png)

* Default
    * 自動で設定ファイルをcreateしてくれる。
* Manually
    * 手動で設定ファイルをcreateする。

### 起動する
defaultで作成するとvueプロジェクトが作成されるので、そのディレクトリに移動して以下コマンドで、サーバーを立ち上げる。

```sh
npm run serve
```

今回はここまで。

次回はvue routerをインストールして、url毎に表示内容を変更できるようにします。

ありがとうございました。
Heroku Postgresを触る（・接続・取得・追加・削除・更新・終了）

# データベースに接続
```
$ heroku pg:psql
```

# テーブルの一覧表示

```
> \d
 Schema |    Name     | Type  |     Owner      
--------+-------------+-------+----------------
 public |   querys    | table |     *****
```
以下、querysというテーブルがある前提で記述する

# データの取得
```
> SELECT * FROM querys;
 query  | qty |
--------+-----------
 qiita  |  2  |
 heroku |  1  |
```
querysというテーブルに、queryとqtyというカラムがあり、2つのレコードがある

# データの削除
```
> DELETE FROM querys WHERE query='qiita';
DELETE 1
```

複数レコードの削除

```
> DELETE FROM querys WHERE query='qiita' OR query='heroku';
DELETE 2
```

# データの追加
```
> INSERT INTO querys (query, qty) VALUES ('qiita', 2);
INSERT 0 1
```

# データの更新
```
> UPDATE querys SET query='github' WHERE query='qiita';
UPDATE 1
```

複数カラムの更新

```
> UPDATE querys SET query='github' qty=3 WHERE query='qiita';
UPDATE 1
```

# 接続の解除
```
> \q
```
オリジナルアプリ開発#1【ユーザー視点で考える】

エンジニア転職をするにあたって、転職先の企業へのアピールポイントになるポートフォリオ作成（オリジナルアプリ開発）をしていきます。

##ペルソナを考える
ペルソナとはマーケティングの用語で、「サービスを使用するユーザー」のことです。
似た言葉に「ターゲット」などがありますが、ペルソナはそれらよりも詳細に「サービスを使用するユーザー」を決めます。

年齢層や、職業。性別や、現在の境遇などまで決めることで、よりリアルに使用者の目線でサービスを考案できます。

###設定方法
- 性別・年齢
- 職業
- 趣味
- 日頃の生活

##ユーザーストーリー
ユーザーストーリーとは、「ペルソナの課題に対して、どのような機能で解決していくのか」を明確にしたものです。

ペルソナが感じるであろう課題を、以下のようにテーブル形式で洗い出します。
この作業を行わないと、「思いついた機能をとりあえず実装する」という開発になり非効率です。

| 解決したい課題 | なぜその課題解決が必要なのか | 課題を解決する実装の内容 |
|:-:|:-:|:-:|
|   |   |   |
|   |   |   |
|   |   |   |



##まとめ
ペルソナとユーザーストーリーを詳細に考えることで、後々に非効率な開発にならなくて済みますが、
最初はざっくりと考え作っていくうちに修正を加えていく感じでいいと思います！
じゃないと、明確に『こんなアプリを作りたい！！』というイメージがない人は、ペルソナとユーザーストーリーを考える時点で、
時間が掛かり過ぎてしまい早々に挫折なんてこともあるかもしれないので、、、😓

次回は、『要件定義』について書きたいと思います。
ではでは！
PurgeCSS で使われていない CSS を削除しよう

この記事は使われていない CSS を削除するデモです。

PurgeCSS を PostCSS のプラグインとして npm scripts で 使います。

# 環境
``` shell
$ node -v
v12.14.1
```

# プロジェクトの作成とプロジェクトルートディレクトリへの移動
``` shell
$ mkdir test-purgecss && cd test-purgecss
```

# npm パッケージを新規でセットアップする
今回はオプション ``` -y ``` で質問を省略しています。

``` shell
$ npm init -y
```

# インストール
purgecss、postcss と postcss-cliをインストールします。

``` shell
$ npm i -D @fullhuman/postcss-purgecss postcss postcss-cli
```

# postcss の設定ファイルを作成します
``` shell
$ touch postcss.config.js
```

# postcss の設定ファイルの中身
``` js:postcss.config.js
const purgecss = require('@fullhuman/postcss-purgecss')

module.exports = {
  plugins: [
    purgecss({
      content: ['./**/*.html']
    })
  ]
}
```

# package.json にコマンドを記述します。
```js:package.json
{
  "scripts": {
    "postcss": "postcss src/**/*.css --dir css"
  }
}

```

# 作業ファイルの作成
ここまででセットアップは完了しました。
作業ファイル index.html と src/style.css を作成します。

``` shell
$ mkdir src && touch index.html src/style.css
```

### HTMLファイルの中身
``` html:index.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body class="a">
  
</body>
</html>
```
``` <body> ``` 要素に ``` class="a" ``` を記述します。
### CSSファイルの中身
``` css:src/style.css
.a {
  color: aqua;
}
.b {
  color: blue;
}
.c {
  color: cyan;
}

```

# purgecss の実行
``` shell
$ npm run postcss
```

# 結果
``` css:css/style.css
.a {
  color: aqua;
}
```

# ディレクトリ構成
``` shell
.
├── css
│   └── style.css
├── index.html
├── node_modules
├── package-lock.json
├── package.json
├── postcss.config.js
└── src
    └── style.css
```


# 参考
> - [scripts | npm Docs](https://docs.npmjs.com/cli/v7/using-npm/scripts)
- [PostCSS | PurgeCSS](https://purgecss.com/plugins/postcss.html#usage)
- [postcss/postcss-cli: CLI for postcss](https://github.com/postcss/postcss-cli)
M1 MacでPHP開発環境をDockerで構築する

M1チップ搭載のMacを使ってPHP開発環境をDockerで構築してみたいと思います。

やりたいこと
・ CentOS7のイメージからコンテナ作成
・ Apache + PHPのWeb環境
・ Macのローカルフォルダと、Dockerコンテナのフォルダ共有
・ SSL通信ができること（httpsでアクセスできる）

# Docker インストール

まずは「Docker Desktop for Mac」をインストールします。

こちらのページの「Mac with Apple Chip」からダウンロードできます。
https://docs.docker.com/docker-for-mac/install/

Rosetta 2も必要になるので、手順を参考にしてインストールしてください。

# MacとDockerの共有フォルダ作成

Macのターミナルを起動して、Dockerコンテナと共有するフォルダを作ります。ACCOUNT_NAMEはご自身のMacアカウントと置き換えてください。

```
# Mac
mkdir /Users/ACCOUNT_NAME/webroot
```

# Docker コンテナ作成

CeontOS 7のイメージからコンテナを作成します。ACCOUNT_NAMEはご自身のMacアカウントと置き換えてください。

```
# Mac
docker run --privileged -it -p 80:80 -p 443:443 -v "/Users/ACCOUNT_NAME/webroot:/var/www/html" --name webserver centos:centos7 /sbin/init
```

起動の途中で下のエラーが出ますが、起動には影響ないので無視します。

[ TIME ] Timed out waiting for device dev-ttyAMA0.device.
[DEPEND] Dependency failed for Serial Getty on ttyAMA0.

# CentOS 時刻設定

「Docker Desktop for Mac」からコンテナのCLIボタンを押して、CentOSのコンソールを立ち上げます。
![スクリーンショット 2021-04-26 9.40.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278715/d3962f84-85c1-9b0d-f792-3760ed8eba48.png)

時刻を設定します。

```
# CentOS
timedatectl set-timezone Asia/Tokyo
```

# Apache インストール

Apacheをインストールします。

```
# CentOS
yum install -y httpd
```

Apacheを起動します。

```
# CentOS
systemctl start httpd
```

Macのブラウザからアクセスして、Apacheの画面が表示されればOKです。
http://localhost/

![スクリーンショット 2021-04-26 9.44.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278715/91bc86ef-ad4b-3119-d396-8f0acfd735d3.png)

# PHP インストール

PHPをインストールします。標準では5.4のバージョンがインストールされるので、必要であれば他のバージョンをインストールします。

```
# CentOS
yum install -y php
```

インストール後はApacheを再起動します。

```
# CentOS
systemctl restart httpd
```

Macで作った共有フォルダにPHPの動作確認用ファイルを作成します。ACCOUNT_NAMEはご自身のMacアカウントと置き換えてください。

```
# Mac
vi /Users/ACCOUNT_NAME/webroot/info.php
```

下記の内容を入力して保存します。

```php
<?php
phpinfo();
?>
```


PHPの動作確認用ファイルにアクセスします。
http://localhost/info.php

PHPの設定が表示されればOKです。

![スクリーンショット 2021-04-26 9.45.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278715/6a960a8b-f47f-b85b-2cd5-3befcdc91add.png)


# SSL設定

httpsでアクセスできるようにcertbotをインストールします。インストールするだけで自己署名証明書が設定されます。

```
# CentOS
yum install -y epel-release
yum install -y certbot
yum install -y certbot-apache
```

インストール後はApacheを再起動します。

```
# CentOS
systemctl restart httpd
```

MacのSafariからhttpsでアクセスします。Chromeではキーチェーンの設定をしないとページが見れないので、Safariからアクセスします。
https://localhost/

警告が表示されますので「このWebサイトを閲覧」から証明書を許可します。
ページが表示されればOKです。

![スクリーンショット 2021-04-26 9.48.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278715/90479e46-1d7f-03f5-ea18-073d1ee196a6.png)


# 補足

コンテナ起動時にApacheを自動起動する

```
# CentOS
systemctl enable httpd
```

Apacheの設定ファイルの場所

```
# CentOS
vi /etc/httpd/conf/httpd.conf
```

PHPの設定ファイルの場所

```
# CentOS
vi /etc/php.ini
```

# 最後に

最小限ですがPHPの開発環境を構築できました。あとはDBをインストールなど色々とカスタマイズしていきたいと思います。
TypeScriptで画像が読み込めない、importできない。

##はじめに

Reactで画像を読み込みたい時は以下のようにするが、TypescriptでReactを書いている場合、画像を読み込まなかった。

```
import Image from './images/image.svg'
const ImageComponent = () =>{
  return <img src={Image}  alt="アイコン" />
}
export default ImageComponent
```
相対パス、なんか間違っているのか？といじってみたけど違うみたいだ。
##解決方法

頭にurl:をつける。

```
import Image from 'url:./images/image.svg'
```

以上です。
UWPのAppWindowを試してみた感想


2021/04/26 時点での AppWindowを試してみた感想です。

https://docs.microsoft.com/ja-jp/windows/uwp/design/layout/app-window

## 良いところ

* メインウィンドウとUIスレッドが同じなのでコンテキストスイッチ、排他制御を意識しなくてもよい

## 難しいところ

* スレッド分離していないので今の処理コンテキストがメインウィンドウなのかサブウィンドウなのか判定するのが難しい
  * UIContextってどうやったらウィンドウ判別に使えるんですか…？（AppWindow.Content.UIContextとサブウィンドウ内UIElement.UIContextを参照やGetHashCodeで同値とってもイコールにならなかった）
* Window.Current.PointerPressed 等から入力を処理するようなケースに対応できない
  * AppWindowの場合は Window.Current は常にメインウィンドウに紐づく
  * マウスのマニピュレーションを処理する際にウィンドウ範囲外へのマウス移動をカバーするシナリオに対応できないので、そういった場合はCoreApplication.CreateNewView()を使ってウィンドウ作成する 
* 内部的なエラーが発生した場合に例外をスローせずにウィンドウ表示が壊れる（CloseやShowのタイミングはUIスレッドを空けるといい？）
* AppWindow上にダイアログを表示したい場合はAppWindow内のUIElement.XamlRootを引っ張ってくる必要がある
  * 依存性の逆転でDialogServiceみたいなレイヤーを経由してダイアログの利用する場合にXamlRootどうやって取ってこようってなる
* ShareUIがサブウィンドウに表示できない
  * ShareUI表示実行後にメインウィンドウに表示を切り替えればいいが
  * ShareUIの呼び出し先UIを閉じた後がフックできないのでサブウィンドウにアクティブを復帰させるにも重めのワークアラウンドが必要そう

## 個人的な感想

難しい点が多くて良くない印象を感じるかもしれませんが、あくまで個人的に動画プレイヤーアプリという重いユースケースを試してみて問題点を洗い出しただけですから、私としてもネガティブな印象はありません。ほとんどのケースではAppWindowを優先して検討したほうが工数的にも開発UX的にも良いと思います。

ApplicationViewよりもAppWindowの方が軽量な作りですし、ウィンドウのClosed等が素直に扱える[^1]ところは魅力です。マウス入力をWindowレベルでカスタマイズしなければならないとか、メイン/サブウィンドウを識別した動的な表示変化が必要とか、といった重いケースを除けば、ダイアログ的な利用にはAppWindowが適した選択になると思います。

[^1]: ApplicationView.Consolidateイベント（Window.Closedに相当）ではメインウィンドウとサブウィンドウのクローズがごっちゃで送られてくる、みたいな難解な挙動に悩まされた
市販のセンサで水素・一酸化炭素・酸素濃度の値を取得する

##Grove Multi Channel Gas sensor (v1) 
[Grove - Multichannel Gas Sensor](https://wiki.seeedstudio.com/Grove-Multichannel_Gas_Sensor/)
・Cで書かれたサンプルコードをAdruinoに流し込んだ時はうまく動くもののPythonで書かれたサンプルコードをRaspberryPi3Bで動かすと認識しない
・Cのコードを読んでPythonに書き直そうと頑張ってみるも無理
・I2Cアドレス初期値は0x04、接続に使った[Grove Base Hat for Raspberry Pi Zero](https://www.switch-science.com/catalog/5443/)も初期値は0x04らしいことがadc.pyに書いてあった（さっき気づいた）
・いろいろ測定できるように見えてセンサはCO(とその他諸々)、NOx、NH3の３つしかない(自動車の排ガス用センサかな？)
・結局諦めて他のセンサを買った

##MQシリーズとADコンバータ
・ガスセンサでぐぐると一番最初にヒットするMQシリーズを買ってみた
・ADコンバータが必要になるようなのでADS1015を買った
・ADS1015はサンプルコードがgitにあるので簡単に動いた
・MQ用のブレークアウト基盤はあった方がいい
・12bit(1024)はちょっと解像度が物足りないけどゲインを上げると壊しそうで怖い
・CO2センサーと違って校正済みではないのでガス校正が必要
・ゼロ(N2)とスパン(最大値)でいいかな…
・この辺までは先月にやったことなので詳細を忘れた(思い出したら書く)

##Grove O2 sensor (MIX8410)
・センサー関係の実装を後回しにしているうちに酸素センサーも発売されていたので買ってみた
・公式のサンプルコードだとBase HatのADコンバータを介して値を取得する仕様のよう
・モジュールとしてインポートしてそのまま使えるのでは？→だめでした
・・値を取得するMix8410()が@propertyで守られていて使えないしコメントアウトしても動かない→なぜ？？？そもそもプログラミングの基本を習っていないので全然わからん。
・サンプルコードの中でBaseHatのADコンバータの値を取得するモジュールが使用されていたので[adc.pyの中身](https://github.com/Seeed-Studio/grove.py/blob/master/grove/adc.py)を読んでみるとコメント内にサンプルコードが書かれていたのでそれを参考にした
・・このときBase HutのADCのアドレスの初期設定は0x04と書かれていた（んんん？？？Multi Channel Gas Sensorの時に出てきた謎の0x04はこれじゃ…）
・Base HutのADCから直接値を取得できたので公式のサンプルコードを見ながら適当に数値の換算→公式サンプルコードを直接動かしたときとほぼ同じ動作を確認
・MQ用のADCのチャンネルまだ余ってるしこっちでいいよね…
・2個買ってしばらく動かして様子を見ると23とか28あたりで数値が安定しているのでこちらも自前でガス校正が必要っぽい
・ゼロ(N2)とスパン(大気)でいいかな

・プロトコルは以下
・[Getting Started with Raspberry Pi](https://wiki.seeedstudio.com/Grove-Gas_Sensor-O2-MIX8410/#getting-started-with-raspberry-piwith-grove-base-hat-for-raspberry-pi)を参考に進めた
・センサのチュートリアルにある[Setting Software](https://wiki.seeedstudio.com/Grove_Base_Hat_for_Raspberry_Pi/#installation)に従ってGrove Base Hat関係のモジュールが入ったライブラリをインストール
・チュートリアルの手順に従ってサンプルコードで動作確認
・公式のサンプルコードをモジュールとして使うことができなかったので自分で書き直したコードが以下

```python:Python
import time
from grove.adc import ADC

adc = ADC()
while True:
	value = adc.read(0)
	voltage = value*3.3/1024.0
	Mix8410Value = Voltage*0.21*100/2.0
	print(Mix8410Value)
	time.sleep(10)
```
とりあえずこれでしばらく動かしてセンサが公式のサンプルコードと同じように動作するか確認した。
けど値を取得するだけなら

```python
from grove.adc import ADC
adc = ADC()
value = adc.read(0) #今回はBaseHatのA0チャンネルを読み取っている
```
で十分だと思う。
２つ買って値がずれていた上に20.9%前後ではないことからセンサに個体差がありかつ公式の換算式はあてにならないと考えられるためガス校正が必要

##結論
・ADS1015にMQ-7, MQ-8, Mix8410を接続して値を取得する(Base Hatは使わない)
・全てのセンサーでガス校正必要
・・ゼロガス(N2)とスパンガス(1%添加or大気)で校正をすればいけるかなぁ
・アナログセンサとADCの間ははんだ付けが必要だよねやっぱり
・・ユニバーサル基盤と3Dプリンタでセンサユニット作らなきゃ…
・センサをブレークアウト基盤に刺すところは導電グリスで誤魔化せないかな…
PHP5上級試験/準上級試験の上級合格に挑戦(22) 上級落ちました その２

# 結果は

先日が試験。
結果はタイトルの通り。

前が825点で、今回が875点。
うん、50点はあがってる。爆上げといかないのがきつい。

もちろん受かるまでチャレンジし続けるので、続ける。
ここまできたらもう受からないとお金がもったいない。（落ちるのももったいないんだけど）
ただ、次で最後にしたいところ。お金もけっこうかかっているし。
今から申し込んでおく。

ひとまず、結果を見比べてみようと思う。


# 結果内訳

↑が６個、→が8個、↓が5個と、↓が１つ多くなった。

３章〜１３章で点が取れるようになっている。
ただ、問題集やマニュアルに解答がない、本質を聞く難しい問題もあるが、
それ以外でも取りこぼしが多かったので、やはり黒本を完全に暗記するということに尽きる。
たとえば、問題集の解答だけでなくて、選択肢のところを言い換えた問題というのはほぼ確実に出ている。

難しい問題はとにかくおいといて、取りこぼしのないように読み込みと暗記と理解をしっかり。
弱いところはしっかり集中して暗記をしていく。
とくに正解でない、選択肢のところも。


| 目次| 出題割合     |前回|今回|判定|
|:----|:------------|:--|:--|:--|
| １章 PHPについて |0 |-|-|-|
| ２章 PHP言語の基本 |0 |-|-|-|
| ３章 関数|0.02|50%|50%|→|
| ４章 文字列|0.02 |50%|50%|→|
| ５章 配列|0.04 |33%|67%|↑|
| ６章 オブジェクト|0.1 |33%|50%|↑|
| ７章 ウェブに関するテクニック|0.12 |63%|88%|↑|
| ８章 データベース|0.08 |40%|100%|↑|
| ９章 グラフィック|0.04|50%|50%|→|
|10章 PDF|0.04|100%|100%|→|
|11章 XML（＆XML系で追加された関数） |0.06|100%|75%|↓|
|12章 セキュリティ|0.12|43%|57%|↑|
|13章 アプリケーションに関するテクニック|0.08|80%|40%|↓|
|14章 PHPの拡張|0.04|0%|0%|→|
|15章 WindowsでのPHP|0.02|50%|0%|↓|
|予備 SPL（Standard PHP Library）/日付クラス/PEAR（管理系のコマンドなど） |0.04|50%|50%|→|
|予備 名前空間/クロージャー/リフレクション/Late Static Binding|0.04|100%|0%|↓|
|予備 JSON|0.02|100%|100%|→|
|予備 PDOとネイティブモジュールの違い/mysqlndドライバについて|0.04|0%|0%|→|
|予備 正規表現（pcre, posix, mbstring）|0.02|100%|0%|↓|
|予備 APD/Xdebug/memcache|0.04|50%|100%|↑|
|予備 フィルター|0.02|0%|0%|→|

# というわけで

+ 今後の方針として、全体を復習しつつ、弱いところ、DB,ウェブに関するテクニック、セキュリティ、アプリケーションに関するテクニック、PHPの拡張、WindowsのPHP，SPL、名前空間、リフレクション、mysqlnd、正規表現、APD、フィルターについて頑張っていく
+ PHP３版も確認したが、トレイトなど、載ってない問題はほぼ出ず、どっちかというと黒本の応用が多かったので、今後は黒本を中心に、取りこぼしのないようにしていく
ターミナルを複製して、デフォルトディレクトリを設定できるか検証

M1Mac でターミナルを複製して、ロゼッタ版とM1版のターミナルを用意する機会があり、もしや、ターミナルを複製したら、それぞれのターミナルでデフォルトディレクトリを設定できるのではないかと思い検証してみた。
→結論としては出来ない。


# 確認手順

1. ターミナルを「複製」
	* 参考) [M1版Macでのコマンドライン開発環境の雑多なこと - Qiita](https://qiita.com/STDNUL/items/7f9036a9911107143ca1)
1. 複製したターミナルの名前を変更（ex)"ターミナル_ProjectB"）
	* オリジナルのターミナルの名前はそのまま（アプリ名を変更できなかった）
1. オリジナルのターミナルにデフォルトディレクトリを設定する
	* ターミナル/環境設定.../プロファイル/シェル/コマンドを実行に cd コマンドを入力
		* cd /Users/[USER_NAME]/MyApps/ProjectA
	* 参考) [ターミナル起動時に、ホームディレクトリではなく任意のディレクトリをデフォルトに設定する - Qiita](https://qiita.com/kimizuy/items/edd8db367748c89b079b)
1. オリジナルのターミナルを再起動して、デフォルトディレクトリが ProjectA になることを確認
	* →OK
1. 複製したターミナルに別のデフォルトディレクトリを設定する
	* cd /Users/[USER_NAME]/MyApps/ProjectB
1. 複製したターミナルを再起動して、デフォルトディレクトリが ProjectB になることを確認
	* →OK
1. 再度オリジナルのターミナルを再起動して、デフォルトディレクトリが ProjectA になることを確認
	* →残念、NG。どちらのターミナルを開いても、最後に設定したデフォルトディレクトリが有効になってしまう


# SourceTree の「端末」

デフォルトディレクトリを設定しても SourceTree の「端末」からターミナルを起動すると、きちんと（デフォルトディレクトリは無視されて）SourceTree で開いているリポジトリがデフォルトディレクトリとして表示される。さすが SourceTree は優秀だな。


# [注意]コンテキストメニューの「フォルダに新規ターミナル」

デフォルトディレクトリを設定すると、コンテキストメニューの「フォルダに新規ターミナル」からターミナルを起動しても、デフォルトディレクトリの設定が有効になってしまう。

[MacのFinderで開いているフォルダをターミナルでカレント・ディレクトリとして開く方法＆アプリまとめ。 | AAPL Ch.](https://applech2.com/archives/38328374.html)


# おわりに

普段ターミナルを使うのは殆どが Git 操作なので、デフォルトディレクトリを Git リポジトリに設定したら、Git を使うのがとても楽になったが、たまーに違うプロジェクトで Git を使う時に、コンテキストメニューの「フォルダに新規ターミナル」が使えなくなってしまった。
仕方がないので、その時は SourceTree の「端末」を使ってターミナルを起動しているが、これがなんとかならないかなぁとたまーに思っている私。
やはり、今後も優秀な SourceTree に頼ることになりそうだな。

そもそも SourceTree はどうやってデフォルトディレクトリを調整しているのかを軽く調べてみたが、ちょっとよく分からなかった。
DXライブラリでエフェクシアを使う

ダウンロードは以下のページから
https://effekseer.github.io/jp/

下準備

`WinMain.cpp`に`"EffekseerForDXLib.h"`をインクルードする
DXライブラリと一緒にエフェクシアを初期化

```c++
// DXライブラリの初期化処理
	if (DxLib_Init() == -1)
	{
		return -1;    // エラーが起きたら直ちに終了
	}

	// Effekseerを初期化する。
	// 引数には画面に表示する最大パーティクル数を設定する。
	if (Effekseer_Init(8000) == -1)
	{
		DxLib_End();
		return -1;
	}
```

初期化後にエフェクシアの設定を行う

```
// DXライブラリのデバイスロストした時のコールバックを設定する。
	// ウインドウとフルスクリーンの切り替えが発生する場合は必ず実行する。
	// ただし、DirectX11を使用する場合は実行する必要はない。
	Effekseer_SetGraphicsDeviceLostCallbackFunctions();

	// Effekseerに2D描画の設定をする。
	Effekseer_Set2DSetting(SCREEN_WIDTH, SCREEN_HEIGHT);
```

エフェクシアの終了処理を行う

```
Effkseer_End();
```

使い方

`"EffekseerForDXLib.h"`をインクルードする

初期化時に以下を記入

```
// Zバッファを有効にする。
	// Effekseerを使用する場合、2DゲームでもZバッファを使用する。
	SetUseZBuffer3D(TRUE);

	// Zバッファへの書き込みを有効にする。
	// Effekseerを使用する場合、2DゲームでもZバッファを使用する。
	SetWriteZBuffer3D(TRUE);
```

エフェクトのハンドルを入手

```
mEffectHndle="Resources/Effect/Effect.efk";
```

Updateに以下を記入

```
mEffect = PlayEffekseer2DEffect(mEffectHndle);

SetPosPlayingEffekseer2DEffect(mEffect, PosX, PosY, 0);

UpdateEffekseer2D();

```

DrawDrawに以下を記入

```
//描画処理に記入
DrawEffekseer2D();
```

Finalizeに以下を記入

```
//終了処理に記入
DeleteEffekseerEffect(mEffectHndle);
```



これで使えるはず
正直処理が重くてあんまり使う機会はないかも
React Nativeでページ内遷移を実現する

# はじめに

React Nativeの開発をしているときに、ページ内遷移の実装を調べていたらReactのページ内リンクの記事ばかり上位に出てきたのでReact Nativeでの実装方法を記載します。

# バージョン

```json
"dependencies": {
    "react": "16.13.1",
    "react-native": "0.63.4",
}
```

# 実装方法
関数コンポーネントで定義しています。TypeScriptで書いてます。

```react
import React, { useRef } from 'react';
import { View, ScrollView, Dimensions } from 'react-native';

const Index = () => {
  const scrollViewRef = useRef<ScrollView>(null);
  const [listPosition, setListPosition] = useState({} as Record<string, number>) // 要素のy座標
  // ページ内遷移
  const goToSection = (category: string) => {
    // スクロール後の位置の補正値
    const CORRECTION = 110
    // 指定のカテゴリのy座標を取得
    let height = listPosition[category] ?? 0
    height += CORRECTION
    if (scrollViewRef.current) {
      scrollViewRef.current.scrollTo({ x: 0, y: height, animated: true })
    }
  }
  return (
    <ScrollView ref={scrollViewRef}>
      {/* ページ内遷移ボタン */}
      <View>
        <TouchableWithoutFeedback onPress={() => goToSection('hoge')}>
          <Text>hoge</Text>
        </TouchableWithoutFeedback>
        <TouchableWithoutFeedback onPress={() => goToSection('fuga')}>
          <Text>fuga</Text>
        </TouchableWithoutFeedback>
        <TouchableWithoutFeedback onPress={() => goToSection('buzz')}>
          <Text>buzz</Text>
        </TouchableWithoutFeedback>
      </View>
      {/* コンテンツ */}
      <View
        key="hoge"
        onLayout={(e: any) => setMovieListHeight(e, "hoge")}>
      </View>
      <View
        key="fuga"
        onLayout={(e: any) => setMovieListHeight(e, "fuga")}>
      </View>
      <View
        key="buzz"
        onLayout={(e: any) => setMovieListHeight(e, "buzz")}>
      </View>
    </ScrollView>
  )
};
```

他にも実装方法がありましたらコメントください！:relaxed:
React(Next.js)でTopへ戻るボタンを実装する方法【ライブラリ使用無し】

React(Next.js)でTopへ戻るボタンを実装する方法になります。
ライブラリ等は使用しないので、導入もしやすいかと思います。

## クリックイベントを設定する

```tsx:ReturnTopButton.tsx
const ReturnTopButton = () => {
  return <button onClick={returnTop}>ボタン</button>
}

export default ReturnTopButton
```

まずは、コンポーネントを作り、クリックイベントを設定します。

## Topへ戻るイベントを追加する

```tsx:ReturnTopButton.tsx
const ReturnTopButton = () => {

  const returnTop = () => {
    window.scrollTo({
      top: 0,
      behavior: 'smooth'
    })
  }

  return <button onClick={returnTop}>ボタン</button>
}

export default ReturnTopButton

```

`window.scrollTo`メソッドを使用して、Topへ戻す処理をしています。
`behavior: smooth`とオプションを指定することで、スムーズスクロールさせることができます。
`behavior: auto `だと一瞬で移動します。

## スクロールしたらTopへ戻るボタンが表示するようにする

初期表示ではTopへ戻るボタンを表示させずに、ある程度スクロールしたら表示させる方法です。

```tsx:ReturnTopButton.tsx
import { useEffect, useState } from 'react'

const ReturnTopButton = () => {
  const [isButtonActive, setIsButtonActive] = useState(false)

  const returnTop = () => {
    window.scrollTo({
      top: 0,
      behavior: 'smooth'
    })
  }

  useEffect(() => {
    window.addEventListener('scroll', scrollWindow)
    return () => {
      window.removeEventListener('scroll', scrollWindow)
    }
  }, [])

  const scrollWindow = () => {
    const top = 100  //ボタンを表示させたい位置
    let scroll = 0
    scroll = window.scrollY
    if (top <= scroll) {
      setIsButtonActive(true)
    } else {
      setIsButtonActive(false)
    }
  }

  const normalStyle = {
    opacity: 0,
    transition: '0.5s',
    pointerEvents: 'none'
  }
  const activeStyle = {
    opacity: 1,
    transition: '0.5s'
  }
  const style = isButtonActive ? activeStyle : normalStyle

  return (
    <button style={style} onClick={returnTop}>
      ボタン
    </button>
  )
}

export default ReturnTopButton

```
`useEffect`でwindowイベントを設定します。
`useState`の真偽値によってスタイルを変えることで、ボタンを表示を変えています。


## iosではbehavior: 'smooth'が効かない時の対処
iosでは、スムーススクロールが効かないことがあります。
その場合は、Polyfillで対処できます。

```
yarn add scroll-behavior-polyfill
```

```js
import 'scroll-behavior-polyfill'
```
RaspberryPi3 の初期セットアップ回

# はじめに

利用していたRaspberryPi3が壊れました…。
Node-RedやPWA化したサイトを稼働させていたのですが、
当時、どんなふうに設定をしていたのか備忘録をあまり残していなかったため、
今回再設定を行うに当たって記載していきたいと思います。

今回はRaspberryPiを使えるようにするまで、初期セットアップ(初期設定)を行います。

# 利用機材

**ラズパイ環境**
Raspberry Pi3 Model B+
Raspberry Pi　７インチ公式タッチディスプレイ
Raspberry Pi ディスプレイケース
microSD
USBキーボード

**その他環境**
ネット環境
PC
microSDカードリーダー

# 手順

0：Raspberry Pi3にタッチディスプレイ・ディスプレイケースを取り付けます。
　取り付け方法については下記サイトを確認してください。

https://raspberry-pi.ksyic.com/page/page/pgp.id/4

　 詳細な手順については下記サイトをご確認ください。

https://studio.beatnix.co.jp/kids-it/hardware/raspberry_pi/7inch-touch-screen-display/

1：PCにRaspberry Piの公式サイトからSDカードにOSを書き込むための専用ソフト(Imager)をダウンロードします。

https://www.raspberrypi.org/software/

2：RaspberryPiのOSを書き込むため、microSDカードリーダーにmicroSDをセットしPCに接続します。

3：ダウンロードしたソフトを立ち上げ、
　　「CHOOSE OS」にダウンロードするOSを選択、
　　「CHOOSE STORAGE」にてmicroSDを指定、
　　「WRITE」を押下し、microSDにOSが書き込まれるのを待機します。

4：書き込み完了後、microSDカードリーダーからmicroSDを外し、RaspberryPiに取り付けます。

5：RaspberryPiの電源を繋ぎ、初期(初回)セットアップ設定を行います。
　　下記サイトを参考に初期(初回)セットアップ設定を完了してください。

https://minipc.just4fun.biz/?Pi/OS/Raspbian%E3%83%BBStretch%E3%81%AE%E5%88%9D%E6%9C%9F%E3%82%BB%E3%83%83%E3%83%88%E3%82%A2%E3%83%83%E3%83%97%E6%89%8B%E9%A0%86

　　※「Hide characters」についているチェックボックスは外すことで伏せ字になっている文字を確認することが出来ます。

再起動を行うことで、設定が反映され、初期設定が完了となります。

#公式タッチディスプレイが逆さまの場合

下記記事を参考に修正してください。

https://raspberry-pi.ksyic.com/page/page/pgp.id/5

#最後に
次回はSSHの接続等を行いたいと思います。

この記事を書き上げるまでの間に
ネット回線が悪くなり、ルーターの買い替え×2、
家の冷蔵庫が壊れ、急遽買い換える→大掃除等、
まとまった時間をあまり取ることが出来ませんでした。。


GWに入りますが、皆さま身の回りの機器にお気をつけください。。
chrome拡張機能を作成するときのメモ

こんにちは、シロウです。

最近、JavaScriptの勉強がてら、chromeの拡張機能を開発して遊んでいるのですが、公式ドキュメントを読んだことを毎回忘れてまうので、ちょこちょこっとメモしておきます。

マニフェストV3について調べていきます。（たぶん、今ある記事の多くはV2のはず。）

ちなみに、Qiitaに拡張機能から投稿できるようにするところまではうまく行きました。w

## マニフェストV2からV3へ移行された

まずはじめに、割と最近、マニフェスト V3に進化したらしいです。

とりあえず、[この辺のドキュメント記事](https://developer.chrome.com/docs/extensions/mv3/intro/)を読んでみるのがおすすめ。

結構変更点が多いので、注意が必要。

### 「browserAction」と「pageAction」は「Action API」に統合された

変更点の一つとして、「browserAction」と「pageAction」は「Action API」に統合されたということが挙げられます。

V3バージョンの書き方

```JavaScript
{
  "name": "My extension",
  ...
  "action": {
    "default_icon": {                // optional
      "16": "images/icon16.png",     // optional
      "24": "images/icon24.png",     // optional
      "32": "images/icon32.png"      // optional
    },
    "default_title": "Google Mail",  // optional, shown in tooltip
    "default_popup": "popup.html"    // optional
  },
  "page_action": {
    "default_icon": {                    // optional
      "16": "images/icon16.png",           // optional
      "24": "images/icon24.png",           // optional
      "32": "images/icon32.png"            // optional
    },
    "default_title": "Google Mail",      // optional; shown in tooltip
    "default_popup": "popup.html"        // optional
  },
  ...
}
```

V2の書き方

```JavaScript
{
  "name": "My extension",
  ...
  "browser_action": {
    ...
    "default_icon": "images/icon32.png"  // optional
    // equivalent to "default_icon": { "32": "images/icon32.png" }
  },
  "page_action": {
    ...
    "default_icon": "images/icon32.png"  // optional
    // equivalent to "default_icon": { "32": "images/icon32.png" }
  },
  ...
}
```

### backgroundがサービスワーカーに移行された

表現が合っているのかわかりませんが、まぁ、下記みたいな感じになったみたいです。


```JavaScript:v3の書き方
{
  "name": "Awesome Test Extension",
  ...
  "background": {
    "service_worker": "background.js"
  },
  ...
}
```

```JavaScript:v2の書き方
{
  "name": "Awesome Test Extension",
  ...
  "background": {
    "scripts": ["event.js"],
    "persistent": false
  },
  ...
}
```
継承機能を組み込んでみた。

<!-- タイトル：継承機能を組み込んでみた。 -->

# 問題
### ログイン情報取得のコードを各コントローラーで読み込む必要があるが、コードが冗長化してしまう。
```java
@Controller
public class TestController{
  @GetMapping("/index")
  public String index(Model model) {
    Authentication auth = SecurityContextHolder.getContext().getAuthentication();
    if (auth.getPrincipal() instanceof DbUserDetails) {
      int loginUserId = ((DbUserDetails) auth.getPrincipal()).getDbaccount().getID();
      String userNickname = ((DbUserDetails) auth.getPrincipal()).getDbaccount().getNICKNAME();
      String mainImage = ((DbUserDetails) auth.getPrincipal()).getDbaccount().getMAIN_IMAGE();
      model.addAttribute("loginUserId", loginUserId);
      model.addAttribute("loginUserNickname", userNickname);
      model.addAttribute("loginUserMainImage", mainImage);
    }
  }
}
```
<br>

# 仮説
### ログイン情報取得のコードをモジュール化し、継承することでコード量を減らすことができるのではないか。
<br>

# 実装①
### ログイン情報取得コードをCommonクラスとしてモジュール化する。
```java
public class Common {
  protected int loginProcessing(Model model) {
      Authentication auth = SecurityContextHolder.getContext().getAuthentication();
      if (auth.getPrincipal() instanceof DbUserDetails) {
          int loginUserId = ((DbUserDetails) auth.getPrincipal()).getDbaccount().getID();
          String userNickname = ((DbUserDetails) auth.getPrincipal()).getDbaccount().getNICKNAME();
          String mainImage = ((DbUserDetails) auth.getPrincipal()).getDbaccount().getMAIN_IMAGE();
          model.addAttribute("loginUserId", loginUserId);
          model.addAttribute("loginUserNickname", userNickname);
          model.addAttribute("loginUserMainImage", mainImage);
          return loginUserId;
      }
      return 0;
  }
}
```
<br>

# 実装②
```java
@Controller
public class TestController extends Common {
  @GetMapping("/index")
  public String index(Model model) {
      /* 認証したログインユーザー情報を取得するメソッドを実行(Common.javaのloginProcessingメソッド) */
      loginUserId = loginProcessing(model);
  }
}
```


# 結果
### モジュール化したCommonクラスを継承することで、各コントローラーに記載するコード量を減らすことができた。他の箇所でも継承を活用すれば、記述量を減らすことが実現できる。
テーブルタグ~HTML~

#テーブルタグ

①　tableタグ
１つのテーブル全体をまとめるタグ

②trタグ
table  rowの略です。テーブルの横の列を作ります。

③thタグ
見出しタグセルを作るタグを作るタグです。

④tdタグ
通常セルを作るタグです。

#コード

```index.html
<table>
    <caption>登場人物</caption>
    <tr>
      <th class="col-1">&nbsp;</th>
      <th class="col-2">年齢</th>
      <th class="col-3">性別</th>
      <th class="col-4">性格</th>
    </tr>
    <tr>
      <th>太郎</th>
      <td>22</td>
      <td>男</td>
      <td>優しい</td>
    </tr>
    <tr>
      <th>花子</th>
      <td>18</td>
      <td>女</td>
      <td>お人好し</td>
    </tr>
    <tr>
      <th>一郎</th>
      <td>24</td>
      <td>男</td>
      <td>ロールキャベツ系男子</td>
    </tr>
  </table>
  
```

①:nbsp
セルが空の場合に入れます。

trタグが横列になります。trタグに挟まれる形で、太郎君、22,男、優しいが１行になります。

HTMLでの実装は以上になりますが、このままでは表のようにボーダーが無いのでCSSで整えていきます。

#CSS

```style.css
 table,th,td {
   border: 3px solid gray;
   border-spacing: 0;
   border-collapse: collapse;
   margin: auto;
 }

 .col-1,.col-2,.col-3 {
   width: 20%;
 }
 
 th{
   background-color: pink;
 }

```

デフォルトでは、ボーダーがつかないためcssで指定します。

①border-spacingでは、ボーダー同士の隙間をなくします。
②border-collapaseでは、ボーダー同士を重ねます。

③セル同士の幅設定
それぞれのthタグに幅を設定することでより見やすくなります。

#完成


![スクリーンショット 2021-04-26 7.57.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1033397/51f09b82-d356-87f4-30a3-78ccb467c4f1.png)
sketchupでruby その16

# 概要

sketchupでrubyやってみた。
rotation使ってみた。


# 写真

![kai.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/002c0bf3-ba7c-ddad-b1ac-e4a6e20e34e2.png)


# サンプルコード


```
def kai
   model = Sketchup.active_model
   entities = model.active_entities
   unit = 10
   p = Array.new
   p[0] = ORIGIN
   p[1] = [unit, 0, 0]
   p[2] = [unit, unit, 0]
   p[3] = [0, unit, 0]
   group = entities.add_group
   face = group.entities.add_face p
   face.reverse! if face.normal.z < 0
   face.pushpull unit * 2
   rot = Geom::Transformation.rotation [0, 0, 0], [0, 1, 0], 45.degrees
   group.transform! rot
end

```

以上。