OmniAICreator/Qiita-1.07M huggingface dataset:
M1 MacでDockerを使用する際の「no matching manifest for linux/arm64/v8 in the manifest list entries」エラーへの対応方法


M1 MacでDockerを使用していて遭遇する可能性のあるエラー、「no matching manifest for linux/arm64/v8 in the manifest list entries」について対応策をお伝えします。このエラーメッセージは、DockerイメージがあなたのCPUアーキテクチャに対応していないときに表示されます。

## エラー発生の状況

まずはじめに、私が遭遇した状況を共有します。以下のような`docker-compose.yml`ファイルを用意し、`docker-compose up --build`コマンドを実行しました。

```yaml
version: "3"
services:
    ...
    db-service:
        image: mysql:8.0.28
        ...
```

しかし、上記のコマンドを実行すると、以下のようなエラーメッセージが表示されました。

```
no matching manifest for linux/arm64/v8 in the manifest list entries
```

このエラーメッセージが表示される原因とその対処法について次のセクションで解説します。

## エラーメッセージの原因とその対処法

このエラーメッセージは、「指定されたDockerイメージが現在使用しているCPUアーキテクチャに対応していない」という意味を持ちます。具体的には、M1 MacのCPUはARMアーキテクチャを採用していますが、ここで指定した`mysql:8.0.28`イメージはARM版が存在しないためにこのエラーが発生しました。

この問題に対する一つの解決策は、`platform`オプションを使用して明示的にイメージのアーキテクチャを指定することです。以下のように`docker-compose.yml`ファイルを編集します。

```yaml
version: "3"
services:
    ...
    db-service:
        image: mysql:8.0.28
        platform: linux/amd64
        ...
```

もう一つの解決策として、ARMアーキテクチャに対応した別のDockerイメージを使用する方法があります。例えば、`mysql/mysql-server:latest`イメージはARMアーキテクチャに対応していますので、以下のようにイメージ名を変更することでこのエラーを解消できます。

```yaml
version: "3"
services:
    ...
    db-service:
        image: mysql/mysql-server:latest
        ...
```

以上、M1 MacでDockerを使う際に遭遇する可能性のある「no matching manifest for linux/arm64/v8 in the manifest list entries」エラーの対処法をご紹介しました。Dockerを使う上で、自身の環境とイメージのアーキテクチャが一致していることを確認することは重要なポイントです。
【翻訳】《Swift and Cocoa Essentials》What Is Asynchronous Programming

非同期という言葉に出くわすと、多くの開発者はいまだに混乱します。非同期とはどういう意味なのか？非同期プログラミングとは何か？非同期プログラミングとは何かを理解するためには、まずその対極にある同期プログラミングを理解する必要があります。 playground を使ってその違いを説明しましょう。

## 同期プログラミング

Foundation フレームワークの import ステートメント を追加し、リモートリソースの URL を定義します。
URL を使用して Data オブジェクトを作成し、 Data オブジェクト のバイト数を表示します。 FINISHED という文字列が、 playground の最後にコンソールに出力されます。

```swift
import Foundation

let url = URL(string: "https://cdn.cocoacasts.com/7ba5c3e7df669703cd7f0f0d4cefa5e5947126a8/2.jpg")!

let data = try! Data(contentsOf: url)

print(data.count)

print("FINISHED")
```

playground の内容を実行し、コンソールの出力を検査します。文字列 FINISHED が出力される前に、 Data オブジェクト のバイト数が出力されています。 playground のステートメントは同期的に実行されるので、これは驚くべきことではありません。 playground は一度に1つのステートメントを実行します。前のステートメントの実行が終わると、次のステートメントが実行されます。これが同期プログラミングを理解しやすくしています。

```swift
597628
FINISHED
```

## 非同期プログラミング

非同期プログラミングを見てみましょう。もはや Data オブジェクト を同期的に生成することはありません。 Apple の並行処理ライブラリである Grand Central Dispatch を使って、 Data オブジェクト を非同期に生成します。

```swift
import Foundation

let url = URL(string: "https://cdn.cocoacasts.com/7ba5c3e7df669703cd7f0f0d4cefa5e5947126a8/2.jpg")!

DispatchQueue.global().async {
    let data = try! Data(contentsOf: url)

    print(data.count)
}

print("FINISHED")
```

playground の内容を実行します。コンソールの出力は、同期プログラミングと非同期プログラミングの違いを示しています。 文字列 FINISHED を表示する print 文 は、 Data オブジェクト のバイト数を表示するprint文に先行しています。

```
FINISHED
597628
```

playground のステートメントは、1つの例外を除いて、依然として同期的に実行されます。グローバルディスパッチキューの async(_:) メソッド に渡されたクロージャは非同期に実行されます。これは単に、クロージャがメインの playground のフローとは無関係に実行されることを意味します。

Grand Central Dispatch はクロージャをグローバルディスパッチキューに送信し、 playground の次のステートメントを続行します。クロージャ内のステートメントの実行が終了するのを待つことはありません。ある時点でクロージャが実行され、 Data オブジェクト のバイト数を表示する print 文 が実行されます。 文字列 FINISHED を表示する print 文 が最初に来るのはそのためです。

## 長所と短所

非同期プログラミングは複雑さをもたらしますが、ソフトウェア開発において一般的であるのにはそれなりの理由があります。例えを用いて、同期プログラミングと非同期プログラミングの長所と短所を探ってみましょう。

あなたは数人の友人に夕食を作る約束をしました。あなたはシンプルに、メインディッシュとデザートのケーキを用意します。ケーキの生地を作り、オーブンにセットします。ケーキを焼くのに約1時間かかります。選択肢は2つあります。１つ目は、ケーキが焼き上がるのを待つこと。待っている間、他にできることは何もありません。２つ目の選択肢は、ケーキをオーブンで焼いている間にメインディッシュの準備をすることです。

最初の選択肢は同期プログラミングに似ています。利点はシンプルであることです。一度に一つの作業に集中できるので、夕食の計画が立てやすくなります。２つ目の選択肢は、非同期プログラミングに似ています。この選択肢は、同時に複数のことが起こるため、より複雑です。利点はスピードです。メインディッシュに集中し、同時にケーキを焼くことができます。

## 次は？

非同期プログラミングは、レスポンスとパフォーマンスに優れたアプリケーションを構築するためには不可欠です。しかし、先に述べたように、非同期プログラミングは複雑さをもたらします。注意しなければならないリスクもいくつかあります。これらについては、 Mastering Grand Central Dispatch (https://cocoacasts.com/series/mastering-grand-central-dispatch) で詳しく説明します。

# 【翻訳元の記事】
Swift and Cocoa Essentials
What Is Asynchronous Programming
https://cocoacasts.com/swift-and-cocoa-fundamentals-what-is-asynchronous-programming
【2023年】新しいPCがほしい（その２）

前回に引き続き半分コラムです。
今は時期が良いので新しいPCがほしい！！！

多分新しいPC買うので、
その選択をメモ形式で更新していきます。
PC選び初心者の人はこんな選び方してもいいかも。

# 仮パーツ選び

[前回は用途とスペックの検討](https://qiita.com/kit/items/001c19068f33357a358f)をしました。
今回は仮パーツ選びをします。

# PCワンズさんを使った仮パーツ選び

自作PCを選ぶときは
[PCワンズさんの「自作一式見積もり」](https://www.1-s.jp/cart/index.php?type=oneset)を使うと便利です。
細かいことは後で修正するとして、
だいたいの組み立てと費用感を知るために
必要なパーツを入力していきます。

## パーツ仮選び

ざっくりと構成してみました。

- 合計：201,230円
- CPU：46,300円
    - Core i5-13600K
        - 3.5(5.1)/2.6(3.9)GHz / 14(6+8)コア 20スレッド / スマートキャッシュ24M / Intel UHD Graphics 770 / TDP125W
        - 20スレッドほしいのでこの辺。ただ、もう少し電力低くてもいいかも。
- CPUクーラー：3,980円
    - SE-224-XTS
        - とりあえず仮置き。
- マザーボード：26,980円
    - PRIME B760-PLUS
        - Z系がいいけど高かったのでBを仮置き。要検討。
- SATAケーブル：1,000円
    - SATA-IICA40/V 70049 ✕ 4
        - 複数ハイパーバイザー用にSATAケーブルほしい。ただ、2本で良いかも。
- ケース：13,800円
    - Antec P10C
        - 後できちんと選ぶので仮置き。
- 電源：13,690円
    - TOUGHPOWER GF 850W -GOLD- PS-TPD-0850FNFAGJ-2
        - 仮置き。ちょっとオーバースペック感。
- メモリー：	34,920円
    - F5-6000J3040G32GX2-TZ5RW by リンクスインターナショナル
        - 高かったので仮置き。
- SSD：15,760円
    - WDS100T3B0C ✕ 2
        - やすかったので2つ仮置き。2TB 1個でもいいかも。
- ビデオカード：44,800円
    - GG-RTX3060-E12GB/OC/DF
        - 仮置き。コスパ重視だと3060になってくる。

## 所感
何も考えずに組んでも予算内に収まりそう。（予算：25万円）
そいえばNVMeがないな。

## 次回以降
・他社のBTOでよい構成がないか調べる
・自作が良さそうなら
    ・パーツ詳細検討（パーツレベルで評判調べて変更していく）
・購入レポ
・制作（自作なら）
・ベンチマークれぽ
座標の値から角度を求める(SPSS Modeler データ加工逆引き3-22)

## 座標の値から角度を求める

![スクリーンショット 2023-07-19 10.03.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/ab0aae6d-066d-e639-3712-58593dc4f45d.png)

## 1.想定される利用目的

・設備異常を検知する特徴量の作成
・顧客満足度向上のための改善度指数を求める

## 2.サンプルストリームのダウンロード

https://github.com/yoichiro0903n/blue/raw/main/angle.str

## 3.サンプルストリームの説明

![スクリーンショット 2023-07-19 10.28.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/a755c727-72c6-ee9c-087e-ae64eed3c69c.png)


a.入力するデータは以下の通りです。
![スクリーンショット 2023-07-19 10.30.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/b2a5dc1d-53d0-b2e9-27d2-e25bc654e82e.png)

b.[フィールド作成]ノードを編集します。 式は次の通りです。(arctan(Y / X)/pi) * 180
![スクリーンショット 2023-07-19 10.30.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/71ddd8b8-4cfb-908b-abbd-3a66683153ee.png)

式ビルダーを利用すると便利に入力できます。[三角関数]でリストから　arctan を選択します。
![スクリーンショット 2023-07-19 10.32.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/f5906838-e761-c7aa-e7d5-1efb303293c4.png)

[プレビュー]します。完成しました。
![スクリーンショット 2023-07-19 10.33.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/889b91a0-bf85-a4f4-1cce-ed0f73d65ce6.png)

#### 注意点

小数点の桁数表示はストリームのプロパティで設定できます。

## 4.参考情報

#### 波形を扱った記事

https://qiita.com/416nishimaki/items/c5ccad804d6278561fa2

https://qiita.com/416nishimaki/items/ce1497a009648eb7a3cf

#### SPSS Modeler ノードリファレンス目次

https://qiita.com/416nishimaki/private/503037195081d3323eee

#### SPSS Modeler 逆引きストリーム集（データ加工）

https://qiita.com/416nishimaki/private/4bf813e6cba84b2a1008
複数列を縦に並べる関数

~~~java
Sub CombineColumnsVertically()
    Dim ws As Worksheet
    Dim sourceRange As Range, targetRange As Range
    Dim col As Integer, targetRow As Long
    
    Set ws = ThisWorkbook.Sheets("Sheet2") ' シート名を適宜変更
    Set sourceRange = ws.Range("A1:C9") ' 取得したいデータの範囲を設定
    
    Set targetRange = ws.Range("D1") ' 結果を縦に並べる開始セルを指定
    
    targetRow = 0
    
    For col = 1 To sourceRange.Columns.Count
        targetRange.Offset(targetRow, 0).Resize(sourceRange.Rows.Count, 1).Value = sourceRange.Columns(col).Value
        targetRow = targetRow + sourceRange.Rows.Count
    Next col
End Sub
~~~
リクエストURLをすべてコンソールに表示するスクリプト【備忘録】

# 開発者ツールでリクエストURLの一覧を表示させるスクリプト

備忘録として
開発者ツールで表示されるネットワークの項目のリクエストURLをすべてコンソールに表示するためのJavaScriptスクリプト

```Javascript
// 開発者ツールの Network タブに表示されるリクエストURLを取得する
var requests = performance.getEntriesByType('resource').map(entry => entry.name);

// コンソールにリクエストURLを表示する
console.log('リクエストURL一覧:');
requests.forEach((url, index) => console.log(`${index + 1}. ${url}`));
```

このスクリプトは、performance.getEntriesByType('resource') を使用して、開発者ツールの Network タブに表示されるリソース（リクエストURL）を取得します。それらのURLを console.log を使って順番に表示します。
## キーワードで絞って表示させる
上記のコードではすべてのリクエストに対して一覧にするのでキーワードで絞って表示させる場合は以下のコードを使います。
```Javascript
// 開発者ツールの Network タブに表示されるリクエストURLを取得する
var requests = performance.getEntriesByType('resource').map(entry => entry.name);

// 絞り込むキーワード
var keyword = '特定のキーワード'; // ここを変更して絞り込みたいキーワードに置き換える

// コンソールにキーワードに一致するリクエストURLを表示する
console.log(`"${keyword}" に一致するリクエストURL一覧:`);
requests.forEach((url, index) => {
  if (url.includes(keyword)) {
    console.log(`${index + 1}. ${url}`);
  }
});
```
これで、キーワードで絞ってリスト化することができます。

使い方は、ページを開いた後、開発者ツールのコンソールに上記のスクリプトを貼り付けて実行してください。
[ERC5313] ERC173をシンプルにした提案を理解しよう！

# はじめに

初めまして。
**CryptoGames**というブロックチェーンゲーム企業でエンジニアをしている **cardene（かるでね）** です！
スマートコントラクトを書いたり、フロントエンド・バックエンド・インフラと幅広く触れています。

https://cryptogames.co.jp/

代表的なゲームは**クリプトスペルズ**というブロックチェーンゲームです。

https://cryptospells.jp/

今回は、コントラクトの所有権を制御できる**ERC173**をよりコンパクトにした**ERC5313**についてまとめていきます！

:::note info
以下にまとめられているものを翻訳・要約・補足しながらまとめていきます。
:::

https://eips.ethereum.org/EIPS/eip-5313

:::note info
**ERC173**については以下にまとめられています。
:::

https://qiita.com/cardene/items/0b8cdc156404920a8cbd

# 要約
この提案では、コントラクトを制御するアカウントを特定するために必要な最小限のインターフェースを定義しています。

:::note info
「**そもそもインターフェースって何？**」という方は以下の記事を参考にしてください！
:::

https://chaldene.net/erc721#st-toc-h-5

# 仕様

このEIPに準拠するすべてのコントラクトは、**EIP5313**インターフェースを実装しなければなりません。

```javascript
// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.15;

interface EIP5313 {
    function owner() view external returns(address);
}
```
## owner

コントラクトの所有者のアドレスを取得する関数。

コントラクトに所有権の概念を実装するための最小限のメソッドを定義しています。

![ブログERC & EIP (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/e14761c8-133a-0ec2-4b57-900f4e2bb95b.png)


# 補足
この標準の提案にあたり、以下を意識しています。

- インターフェース内の関数の数を最小限に抑えること。
- 既存のコントラクトとの後方互換性を保つこと。


この標準は、他の標準によって拡張することができ、コントラクトの所有機能を追加できます。
インターフェース内の関数の数を減らすことで、より簡単な所有権の実装が可能となります。

:::note info
詳細は以下の**ERC173**を参照してください。
:::

https://qiita.com/cardene/items/0b8cdc156404920a8cbd#%E8%A3%9C%E8%B6%B3

# 後方互換性
**ERC173**を実装しているすべてのコントラクトは、すでにこの仕様を実装しています。

# セキュリティ上の考慮事項
この仕様書は**EIP165**を拡張しないため、この提案の`owner`関数を呼び出しても、その結果が本当にコントラクトの所有アドレスであることを完全に保証できません。
例えば、同じ関数シグネチャを持つ別の関数が、コントラクトの所有者アドレスではないアドレスを返す可能性があります。
あるアドレスがコントラクトの所有者どうかを判別するためにのみこの実装を使用する場合、上記のリスクの影響は最小限に抑えられます。
ただし、例えば貴重なNFTをコントラクトの所有者アドレスに送る場合は、リスクが高まります。

![ブログERC & EIP (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/88288a48-a8b3-3979-b263-57df596e0c13.png)

:::note warn
コントラクトの所有者アドレスだと思って送ったアドレスが、実はコントラクトの所有者アドレスではない可能性がある。
:::

# 考察

この**ERC5313**として、提案されているインターフェースを使用する場面はあまりないのかなと思いました。
つまり、**ERC173**などを参考にして**ERC5313**で提案されている実装が既にされていると思っています。
この提案はざっくりまとめると、「**コントラクトの所有権を持つアドレスの確認**」となり、**ERC173**の確認部分のみを切り出したものになります。

**セキュリティ上の考慮事項**で述べられているような、「**コントラクトの所有者か判定してなんらかの処理を実行する**」は既に以下で実装されています。

https://docs.openzeppelin.com/contracts/4.x/api/access#Ownable

そのため、最初に述べたように**ERC5313**として実装することはないのではないかと思った次第です。
もしかしたら上記実装にあたり**ERC5313**を参考にしているのかもしれないですが...。

また、補足としてコントラクト内での権限管理は以下のような**Access Control**があります。

https://docs.openzeppelin.com/contracts/2.x/access-control

# 最後に

今回は「コントラクトの所有権を制御できる**ERC173**をよりコンパクトにした**ERC5313**」についてまとめてきました！
いかがだったでしょうか？

実装については今後追記していきます。

質問などがある方は以下のTwitterのDMなどからお気軽に質問してください！

[Twitter @cardene777](https://twitter.com/cardene777)

# 採用強化中！

CryptoGamesでは一緒に働く仲間を大募集中です。

https://www.wantedly.com/companies/cryptogames

この記事で書いた自分の経験からもわかるように、裁量権を持って働くことができて一気に成長できる環境です。
「ブロックチェーンやWeb3、NFTに興味がある」、「スマートコントラクトの開発に携わりたい」など、少しでも興味を持っている方はまずはお話ししましょう！
【アラサーIT資格最強勉強法】勉強から逃げてきたあなたへ、超現実的！7STEP勉強法

アラサーになるまで勉強してこなかった高卒の人はこれを読むこと。（単なる私の勉強法備忘録と反省点w）

CCNAやLPIC、AWSの試験に落ちてはまた再チャレンジしてきた僕が1年前の自分に勉強方法を教えるならこの方法だなと思い書きました。

勉強猛者の人がたくさんいるIT界隈、Quiitaを投稿している人たちからするとバカにされる内容かもしれませんが・・笑

私と同じく勉強を続けていても身についているかわからない・・周りの人に追い抜かれていく悔しさを感じている人の役に立てればと思い書きました。

# ステップ1：問題集選びを間違えるな 
勉強は努力量ではない。努力する方向がすべてだ。たった少しでも間違った方向へ向かってしまったら2ヶ月後、ゴールとは全く違う方向へ向かってしまう・・

資格合格者達の合格体験記を調べよう。最新版でかつ試験のバージョンと合っているのか確認して選ぼう。もちろん１冊だけでは足りない。有力な問題集、過去問集を２つほど用意しよう。

## ここで問題集を選ぶポイントとしては3つある。

１つは口コミ評価が高いということ。どの合格体験記にも載っているくらい。２つは解説がビッチリ書かれていて図解があること。やはり絵を見てイメージしながら理解する方が良い。３つ目は最新のものを購入すること。試験は随時アップデートしている。新しい試験に対応した問題集、テキストを購入しよう。

# ステップ2：土台を固めろ
有力な問題集を購入したら問題を解かない。サーっと読んでみてわからない基礎・基本用語をリストアップしてみよう。

わからないまま問題集を解いてもどうせまた調べるハメになる。まずは土台を固めて勝負に挑むこと。

おそらく初見者なら基本用語、概念などは100個、もしかしたら200個くらいあるかもしれない。でもこれらを理解していないと問題では何を聞かれているのかさっぱりわからない・・

できれば入門書を買っておくと良い。入門書は意外とバカにならない。難しい用語をわかりやすく説明してくれて暗記にも特化している。

リストアップが終わったらそれを3周〜5周くらいやり込むこと。ちなみにここで言っている1周は、3秒で答えがパッと頭に思い浮かぶレベルだ。もしパッと思い浮かばないのならそれは覚えていない。すぐに答えを見て覚えよう。

# ステップ3：勉強での間違い！問題集を舐めろ
誰もがやってしまう勉強法の３つある、、まず１つめ、、
それは一問ずつ丁寧にやること。日本人は完璧主義で一問ずつ完璧に理解してから次に進もうとする。

## これは大きな間違いだ。１周目の理解度は10％〜20％程度でいい。
3周〜4周目で理解度80、100％にすればいいのだ。

問題は大問1を理解するのに大問5に出てくる用語や概念を理解しないといけなかったり、参考書にある第１章を理解するには第3章と第５章に出てくる概念を知らないと理解するのが難しかったりする。

全体を通して俯瞰してみないとわからないことが多すぎる。

1周目の理解度は20％程度でいい。2周目は50％程度でいい。3周目は80％でいい。そもそも試験範囲の構造上、1周目で100理解することは難しいのだ。だからこそ最初の1周目は舐めるかのように問題集を読んでいく。

# ステップ4：２つ目の間違い、解くのに時間をかけるな。3秒でいい
結論からいうと問題は解かなくていい。細かいことをいうと3秒でわからないなら答えと解説を読んでしまえ。

問題は解かなくていい？それはおかしい！思った人もいると思う。問題を解こうと考えていると悩んでしまう。はっきり言ってこれは無駄だ。

問題文を読んで3秒考えてパッと出てこないのはそれは覚えていないってこと。絶対に解いてやる！と意気込んで5分以上、考えてみても答えが出なかったことが大半だろう。だったら答えと解説を見てしまえ。

人の記憶が定着するのは思い出そうとしている瞬間、想起して思い出した瞬間に記憶が定着するのだという。であればこのアクションに何分もかけていられない。10分悩んで答えが出ないなら1分思い出すアクションを10回した方がマシだろう。

だから真剣に解かなくていい。リズムだ。3秒だ。問題を読んで１、２、３、ハイ！答えがパッと頭に思い浮かばないならすぐに答えを見ていい。解説をみていい。

# ステップ5：３つ目の間違い、勉強の基準が低すぎる！
結論、最低でも7周反復しろ
そもそも高卒は勉強に対する基準が低すぎる。これは僕もそうだがほとんどの人が過去問、問題集を１周やるだけで満足してしまう。3周やればドヤ顔だ。

これは傲慢すぎる。最低でも７周くらいやる必要がある。多すぎだって？

## 資格試験はゲームで言うところのラスボスに挑むときと同じだ。
ラスボスがレベル80。つまり合格点。1周でレベルが10上がったと換算すると3周や4周では足りない。レベル40でレベル80のラスボスを倒すのはあまりにも無理がある。

ラッキーパンチが当たってもレベル70まであげなくてはならないだろう。（ビギナー向けの資格なら3周〜4周で十分だと思うが。）

ちなみに東大生や医学生は受験時に１つの問題集、参考書を10周するのは当たり前だという。まずは勉強の基準が低すぎるという点だ。

しかもやってみるとわかるが人は忘れる。人は一度勉強したことを1時間で56％忘れ1日後には77％と忘れるというエビングハウスの忘却曲線の話は有名だ。

100％理解したとしても4周目になって忘れている自分にガッカリとする。だから反復復讐は必要なのだ。

# ステップ6：解説のセンターピンを押えろ
センターピンというのは、ボウリングの一番先頭にあり、中央にあるピンのことを指す。センターピンが倒れれば他のピンも倒れるのでコスパの良いアクションをセンターピンという。

解説にもセンターピンがある。長い長い解説を全て読んでていて「要するにこれさえわかっていればいいよね」というところがある。そこを押さえよう。

実際に7周もやっていると解説を全て読み込むのは、はっきり言ってしんどい。といっても3周目までは解説を読まないとセンターピンがあるのがわからない。

これがわかるようになると問題文を読まずに選択肢が間違いなのかがすぐわかるようになる。

補足だが答えの選択肢を丸暗記はよくないが解説の丸暗記はしたほうがOK。答えよりも大切なのはその選択肢が正解で、なぜその選択肢が間違いなのかを解説できるのかが重要だ。

# ステップ7：スケジューリング
これまでの反省点を踏まえるとスケジュールとしてはこんな感じ。

1日〜10日：基礎・基本用語の土台固め
10日〜30日：問題集を1周〜2周
30日〜40日：問題集を3周〜4周
40日〜50日：問題集を5周〜7周
50日〜60日：バッファ

ぜひ皆の勉強法にお役立てれば光栄です。
【React + Vite + TypeScript】ビルド時に'vite/client'が見つからない問題の解決策



### 1.問題の発生

私たちのプロジェクトではReactとViteを一緒に使用しており、TypeScriptを採用しています。ところが、最近ビルドプロセスに問題が生じました。具体的には、以下のコマンドを実行したところ、エラーが発生しました。

```bash
npm run build
```

エラーメッセージは次のようなものでした。

```
Cannot find type definition file for 'vite/client'. The file is in the program because: Entry point of type library 'vite/client' specified in compilerOptions
```

このエラーメッセージによると、`vite/client`の型定義ファイルが見つからないという問題が発生しているようです。

### 2.設定の見直し

原因を探るために、まずはTypeScriptの設定ファイル(`tsconfig.json`)を見直してみました。設定ファイルは以下のようになっていました。

```json
{
    "compilerOptions": {
      "types": [ "vite/client","node"],
      "typeRoots": ["./node_modules/@types/", "./types"],
  }
}
```

ここで、問題の箇所が見つかりました。`typeRoots`の設定で、`vite/client.d.ts`が格納されているであろうディレクトリ`node_modules/vite/`が含まれていないのです。

### 3.問題の解決

問題の解決策は、`typeRoots`に`"./node_modules"`を追加することでした。以下が修正後の`tsconfig.json`です。

```json
{
    "compilerOptions": {
      "types": [ "vite/client","node"],
      "typeRoots": ["./types", "./node_modules"],
  }
}
```

これで、TypeScriptは`vite/client.d.ts`を見つけることができ、ビルドも正常に完了します。

### 4.まとめ

ここでは、React + Vite + TypeScriptの環境でビルド時に'vite/client'が見つからないという問題とその解決策について説明しました。設定を見直すだけで解決できたこの問題は、開発中にしばしば遭遇するような典型的なケースかもしれません。

設定ファイルは我々の指示通りに動作するため、不具合が発生した場合にはその設定を再確認することが重要です。思わぬ箇所に問題の原因と解決策が隠されていることがあります。

今回のケースが、同様の問題に直面した他の開発者の参考になれば幸いです。
初学者のオタクが、推しの出演情報を管理するLINEbotを作ってみた。【Python+LINEMessagingAPI+スプレッドシート】

# まえがき
私事なのですが、今年某アイドルのファンクラブに入会しました。
アイドルのファンクラブに入るのは人生初の出来事です。

そこで思ったこと…
**メンバーのTV出演情報、見逃しがち！！！！**

メンバー多め＆私箱推しなのに…
会報(メール)の下の方にしれっと書いてあるだけで終わり。
~~だいたいメールなんていちいちチェックしてない…令和よ？~~

そこでオタクは考えました。
**(´-`).｡oO(LINEでちゃちゃっと登録できて、今日の出演情報を返してくれるbotを作れないだろうか。)**


# 目次
3部構成でお送りします。
下記リンクから飛んでみてください↓

[①勤怠管理botの作成](https://qiita.com/unmochan/items/e68e615a257f4e8f90b4)　※Youtubeにアップされている講座の写経

[②推しの出演情報の登録を行うbotにリメイクする](https://qiita.com/unmochan/items/ebf09e4c4913f12a9d17)

[③本日の出演情報を取得し、返してくれる機能を追加](https://qiita.com/unmochan/items/f2fbce64d4ff2232622f)



# 感想
普段使っているスプレッドシートをDB代わりにbotが動くなんて驚きました。
ちょうどいい難易度なのに分かりやすい成果が得られて、学習とは思えないくらい楽しかったです。(自分のスマホから送信した文字列が、正しく変換されてスプシ上に登録される瞬間は快感です…)
後半自分で考えた仕様を実装する時、Pythonの基礎知識の良い復習になりました。特にNumpyで使いやすいように配列を加工した後、Pandasで表形式に変換する流れは、[Python3エンジニア認定データ分析試験](https://qiita.com/unmochan/items/75f6a19548600d03fbfd)のもろ試験範囲で、点で存在していた知識が線で繋がったのが嬉しかったです。
最初は「LINEbot開発はいろいろなAPIやツールが出てくるので複雑で難しそう…」と思っていましたが、連携の部分は意外と定型文が多めで、先人達の知恵を借りれば何とかなることが分かりました。結局大事なのはPythonで値の受け渡しをしたり欲しいデータに変換する基本のキのところなので、そこの理解に注力できました。
認定基礎試験、データ分析試験は合格したけど次は何をしたら、、、、と迷える私のような方におすすめです！！


# 今後追加してみたい機能
・登録内容のバリデーション(フォーマットと異なる入力をはじく機能)
・(あれば)放送日をカレンダーから入力できる機能
・設定した時間になると、自動的に本日の出演情報を配信してくれる機能
・最推し登録機能と、最推しの週間出演スケジュール取得
本日の出演予定をお知らせする機能を追加してみる。[Python+スプシでLINEbot作成その③]

※この投稿は、
[初学者のオタクが、推しの出演情報を管理するLINEbotを作ってみた。【Python+LINEMessagingAPI+スプレッドシート】](https://qiita.com/unmochan/items/68a24cdf9f35327071e1)
のその３です。

その１は[こちら](https://qiita.com/unmochan/items/e68e615a257f4e8f90b4)
その２は[こちら](https://qiita.com/unmochan/items/ebf09e4c4913f12a9d17)

# やったこと
その２で登録した推しの出演情報の中から、本日放送予定のものをメッセージとして送信する処理を追加しました。

# 仕様
①本日の出演情報を知りたい場合、「本日」と入力し送信する。
②今日の日付を取得し、Str型に変換。
③スプレッドシートの"日付"列が今日の日付になっているものを抽出し、リスト化する。
④取得したリストをループ処理で回し、送信用文言に加工して文字列として戻す。
⑤該当データがなかった場合、「今日の出演情報はありません。」メッセージを返す。
　該当データがある場合、「今日は
　　　　　　　　　　　　　(名前)さんが(番組名)に出演予定です。」メッセージを返す。
　※複数データの場合は複数行になる。
⑥「本日」以外の文字が入力された場合は、情報登録処理に移る。

# 実装
下記の通り、登録処理を定義しました。
```py:app.py
import numpy as np
import pandas as pd

# 今日の出演確認
def check_today():
    worksheet = auth()
    #スプレッドシートから全データを取得
    df = pd.DataFrame(worksheet.get_all_records())
    #今日の日付をStr型に変換
    timestamp = datetime.now()
    today = timestamp.strftime('%Y/%m/%d')
    #1列目が今日の日付となるレコードを抽出し、numpy配列に変換→リストに変換
    today_data = df[df['日付'] == today].to_numpy().tolist()

    #ループ処理で出力メッセージをリストに格納
    messages = []
    for date, name, info in today_data:
        messages.append(name + 'さんが' + info + 'に出演予定です。')
    #１つに結合
    message = '\n'.join(messages[:])
    #戻り値
    return message
```
その２の時と同じく、メッセージの受信・送信に関わる部分を修正。
```py:app.py
@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
    if event.message.text == '今日':
        message = check_today()

        if message == '':
            line_bot_api.reply_message(
                event.reply_token,
                TextSendMessage(text='今日の出演情報はありません。'))

        else:
            line_bot_api.reply_message(
                event.reply_token,
                TextSendMessage(text='今日は\n' + message))

    else:
        registration(event.message.text)
        line_bot_api.reply_message(
            event.reply_token,
            TextSendMessage(text='登録完了しました！'))
```
変数messageにcheck_today()の戻り値を格納し、空文字かそうでないかに応じて条件分岐する。

# 動作確認
①「今日」と送信する。
![スクリーンショット 2023-07-26 034831.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2697150/eaf652ea-4c45-f008-fa04-5f8c0014cd32.png)

②今日(2023/07/26)が放送日のデータがなかった場合、「今日の出演情報はありません。」のメッセージが返ってくる。
![スクリーンショット 2023-07-26 035022.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2697150/e0ad965c-84ca-041d-3ff7-fc3b3b348364.png)

③その２で実装した登録処理も問題なく使える。
![スクリーンショット 2023-07-26 035601.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2697150/b64b4ba0-abb4-d844-e96b-480f8c868d85.png)

④該当データがある場合は、「今日は
　　　　　　　　　　　　　(名前)さんが(番組名)に出演予定です。」のメッセージが返ってくる。
![スクリーンショット 2023-07-26 035741.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2697150/39d66fd3-3348-5a39-85d7-8a21ff218e70.png)

⑤該当データが複数ある場合も、全てのデータが返信に記載されている。
![スクリーンショット 2023-07-26 040054.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2697150/034e27ed-d733-86e6-6e1c-58443deebd1c.png)
![スクリーンショット 2023-07-26 040233.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2697150/4429b850-26a5-82c3-2bd3-5255541e1f01.png)
2023/7/26主にITとかセキュリティの記事

サポート詐欺で市内20校の校務システム停止、通知票配れず - 日置市
https://www.security-next.com/147999

人間ドック対象者情報、テストサーバで閲覧可能に - 公立学校共済組合
https://www.security-next.com/148084

学内関係者のユーザー名やメアドが外部サイトで流通 - 近畿大
https://www.security-next.com/147855

アルプスアルパイングループ会社にサイバー攻撃、社員の個人情報が漏えい(7/24)
https://scan.netsecurity.ne.jp/article/2023/07/24/49708.html

大阪教育大学職員が誤って「＠gmeil」を転送先メールアドレスに設定(7/24)
https://scan.netsecurity.ne.jp/article/2023/07/24/49709.html

大阪教育大学で情報流出、5年近く転送していた「gmeil.com」からエラーが届く(7/25)
https://xtech.nikkei.com/atcl/nxt/column/18/00598/021300226/

"シャドーAI"リスク未管理の企業が8割、オンライン旅行詐欺にご用心、IT部門とサステナビリティ
https://news.nicovideo.jp/watch/nw13036583

サイバー攻撃の標的、3割がIoT機器　NICT調べ(7/24)
https://www.nikkei.com/article/DGXZQOUC20DBG0Q3A620C2000000/

コロナ禍を経てPCの利用が大幅減少、パスワード使い回しが増加(7/24)
https://news.mynavi.jp/techplus/article/20230724-2733160/

デジタル化著しいフィジカルセキュリティ市場　IT商材としてのビジネスチャンス広がる(7/24)
https://www.weeklybcn.com/journal/feature/detail/20230724_199355.html

「Microsoft Edge 115」が公開 ～「Edge」固有の問題2件を含む13件の脆弱性を修正(7/24)
https://forest.watch.impress.co.jp/docs/news/1518283.html

GitHubリポジトリへの招待悪用してマルウェアに感染させる攻撃に注意、北朝鮮支援か(7/24)
https://news.mynavi.jp/techplus/article/20230724-2732335/

金融庁提供の報告書（XBRL）作成ツールに XML 外部実体参照 (XXE) に関する脆弱性(7/24)
https://scan.netsecurity.ne.jp/article/2023/07/24/49703.html

大阪急性期・総合医療センターのランサムウェア被害、当事者が語る復旧の道のりと教訓(7/24)
https://atmarkit.itmedia.co.jp/ait/articles/2307/24/news013.html

オンラインストレージアプリ Proself にリモートコード実行のゼロデイ脆弱性(7/24)
https://scan.netsecurity.ne.jp/article/2023/07/24/49704.html

ハッキング警戒、パスワード設定で韓国企業がノウハウ伝授(7/24)
https://www.afpbb.com/articles/-/3473842?cx_part=top_category&cx_position=2

基幹システムのクラウドシフトが本格化、成否を分ける要因とは(7/24)
https://japan.zdnet.com/article/35206682/

Oracle Java に攻撃された場合の影響が大きい脆弱性(7/24)
https://scan.netsecurity.ne.jp/article/2023/07/24/49702.html

産総研の元研究職員 秘密情報持ち出し 逮捕 起訴(7/24)
https://scan.netsecurity.ne.jp/article/2023/07/24/49707.html

【社説】生成AIと教育　「考える力」伸ばす工夫を(7/24)
https://news.yahoo.co.jp/articles/bba39a58c4d570ce031f9002c6755c535238630d

Citrix ADCおよびCitrix Gatewayに複数の脆弱性、悪用した攻撃も確認(7/24)
https://scan.netsecurity.ne.jp/article/2023/07/24/49705.html

山積する重要課題(7/24)
https://www.the-miyanichi.co.jp/shasetsu/_72453.html

ディープマインド創業者、「ＡＩが１００万ドル稼ぐ時代に備えよ」(7/24)
https://www.technologyreview.jp/s/312515/mustafa-suleyman-my-new-turing-test-would-see-if-ai-can-make-1-million/

アップルギフトカード100万円分詐欺被害　四日市の60代男性　三重(7/24)
https://news.yahoo.co.jp/articles/ee7afb6344e74181d837fc19f432334b66143c29?source=rss

身に覚えのないメールが金銭被害のきっかけに…なりすましで電話番号を乗っ取る「SIMスワップ」その手口は(7/24)
https://www.tokyo-np.co.jp/article/264942

どうなる政府のWeb3施策、「骨太の方針」から2024年を占ってみる(7/25)
https://xtech.nikkei.com/atcl/nxt/column/18/00138/072001336/

ソニーGが医療で攻勢、データ収集システムを国内でも展開(7/25)
https://xtech.nikkei.com/atcl/nxt/column/18/00001/08218/

「閉域網神話」が被害を深刻に、日本のセキュリティー対策の弱点はここだ(7/25)
https://xtech.nikkei.com/atcl/nxt/column/18/02532/072400002/

ぴあがチケット基幹系をフルクラウド化、年7500万枚処理のDBをどう移行？(7/25)
https://xtech.nikkei.com/atcl/nxt/column/18/00678/071000108/

「システムトラブルに不運が重なったとき、リーダーは知らねーよって思っている？」(7/25)
https://xtech.nikkei.com/atcl/nxt/column/18/02518/00009/

サーバー運用で消費電力抑制、不要なサービス停止以外に何ができる？(7/25)
https://xtech.nikkei.com/atcl/nxt/column/18/02500/062800002/
Cloud Run IAP の嵌り

Cloud Run を公開したり、非公開にしてみます。

https://codelabs.developers.google.com/codelabs/cloud-run-deploy#0

```
$ gcloud run services list
$ gcloud run services describe helloworld --platform managed
```

IAM の orgpoloicy で、当該プロジェクトにおいて、「Domain restricted sharing のポリシー」を、すべて許可にする必要があります。

https://cloud.google.com/blog/topics/developers-practitioners/how-create-public-cloud-run-services-when-domain-restricted-sharing-enforced?hl=en

Cloud Run で、「未認証の呼び出しを許可」する必要があります。

公開の方法は以上です。

では、この Cloud Run サービスを、IAP で守り、非公開にするにはどうしたらよいのか。
https://cloud.google.com/blog/ja/products/gcp/control-access-your-web-sites-identity-aware-proxy

Cloud Run に行きます。
ネットワーキングの「Ingress の制御」を「すべて」に変更します。
「グローバル外部アプリケーション ロードバランサからのトラフィックを許可する」にチェックを入れます。
セキュリティ、認証で、「認証が必要です」に変更します。

ロードバランサーを作成します。

ネットワークサービス > ロードバランシング
アプリケーション ロードバランサ（HTTP/S） > 構成を開始
「インターネットから VM またはサーバーレス サービスへ」
「グローバル外部アプリケーション ロードバランサ」
「続行」をクリック
名前を「for-cloudrun」「HTTPS（HTTP/2 を含む」
https://cloud.google.com/iap/docs/concepts-overview?authuser=1&hl=ja
ここで、リンクをクリックすると、403 となりました。
IPアドレスを直接入れても、403となります。
どうやら、証明書を作ったのですが、24時間待て、となっています。
待ってみます。

https://www.google.com/search?client=firefox-b-d&q=gcp+cloudrun+iap#fpstate=ive&vld=cid:488597d0,vid:LGobxFyu3zw

バックエンドサービス > cloudrun-helloworld の、左の四角に、チェックを入れます。
右側にペインが出現します。cloudrun-helloworld となっているのを確認します。
「プリンシパルを追加」をクリックします。
メールアドレスを入れます。

403 となり、Your client does not have permission to get URL from this server.と出ています。
ここに関連しているようです。
https://cloud.google.com/run/docs/troubleshooting?hl=ja#unauthorized-client

ここに書いてあることをやってみます。
https://cloud.google.com/iap/docs/enabling-cloud-run?hl=ja#troubleshooting_errors

```
    IAP は、IAP サービス アカウントの権限を使用して、Cloud Run サービスを呼び出します。Cloud Run 起動元権限が次のサービス アカウントに付与されていることを確認します。 service-[PROJECT-NUMBER]@gcp-sa-iap.iam.gserviceaccount.com

    上記のサービス アカウントに Cloud Run 起動元権限を付与しても問題が解決しない場合は、Cloud Run サービスを再デプロイします。
```

いや、ここをよく読む必要がありそうだ。
https://cloud.google.com/iap/docs/enabling-cloud-run?hl=ja

結局、以下のようにして出来ました。

IAM に行って、service-[PROJECT-NUMBER]@gcp-sa-iap.iam.gserviceaccount.com　を作成する。
その際、Cloud Run 起動元 ロールを付与する。

以上です。
推しのTV出演情報を登録するLINEbotを作ってみる。[Python+スプシでLINEbot作成その②]

※この投稿は、
[初学者のオタクが、推しの出演情報を管理するLINEbotを作ってみた。【Python+LINEMessagingAPI+スプレッドシート】](https://qiita.com/unmochan/items/68a24cdf9f35327071e1)
のその２です。

その１は[こちら](https://qiita.com/unmochan/items/e68e615a257f4e8f90b4)
その３は[こちら](https://qiita.com/unmochan/items/f2fbce64d4ff2232622f)

# やったこと
その１で写経して作成した勤怠管理LINEbotの処理を修正し、TV出演情報を登録するLINEbotにリメイクしました。

# 仕様
①放送日、出演者、番組名のデータをカンマ区切り1行で記載する。
②Pythonのsplit関数を用いてデータをカンマごとに分割後、1レコードとしてテーブルに保存。
③登録が成功したら、「登録完了しました！」メッセージを返す。

# 実装
下記の通り、登録処理を定義しました。
```py:app.py
import numpy as np
import pandas as pd

# 登録
def registration(data):
    #カンマ区切りでNumpyの配列にした後、np.newaxisで次元追加(DataFrameに変換した際に1行になるように)
    #array([['日付', '出演者', '番組情報']])
    new_record = np.array(data.split(','))[np.newaxis, :]
    
    worksheet = auth()
    #スプレッドシートから全データを取得
    df1 = pd.DataFrame(worksheet.get_all_records())
    #new_recordをDataFrameに変換
    df2 = pd.DataFrame(new_record)
    df2.columns = ['日付', '出演者', '番組情報']
    #元データと新データの結合
    df = pd.concat([df1, df2], ignore_index=True)
    
    worksheet.update([df.columns.values.tolist()] + df.values.tolist())
    print('登録完了しました')
```
Flaskを用いて書かれている下記の箇所(メッセージの受信・送信に関わる部分)を、推しTV出演情報bot用に修正。
```py:app.py
@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
    registration(event.message.text)
    line_bot_api.reply_message(
        event.reply_token,
        TextSendMessage(text='登録完了しました！'))
```
event.message.textには、「ユーザがLINEで送信してきた文字列」が格納されている。
登録処理の為の関数に、送信されてきた文字を渡している。

# 動作確認
①放送日、出演者、番組名をカンマ区切りで記載し、送信する。
![スクリーンショット 2023-07-26 030136.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2697150/6d7a6334-f974-ea27-1588-e8587f535528.png)

②送信した情報がスプレッドシートに保存され、「登録完了しました！」のメッセージが返ってくる。
![スクリーンショット 2023-07-26 030220.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2697150/d255cb05-b749-420f-790f-3243250fe08c.png)
操車場アルゴリズムを Java で実装してみた

# 操車場アルゴリズムとは
　我々人間に分かりやすいように書かれた数式(中置記法)を、プログラムで処理しやすい数式の形(後置記法)へ変換するアルゴリズム。
ダイクストラ法でお馴染みのエドガー・ダイクストラが考案したもの。

例として中置記法で `3 + 4` と示される式は、後置記法で `34 +` と表記することが出来る。

# 実装例
```java
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Scanner;

class ShuntingYard {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String input = scanner.nextLine();
        if (input == null || input.length() == 0) return;

        List<String> outQueue = new ArrayList<>();
        List<String> stack = new ArrayList<>();
        for (int i=0;i<input.length();i++) {
            String s = String.valueOf(input.charAt(i));

            System.out.println("queue: "+outQueue+" / stack: "+stack);

            if (s.matches("\\d")) outQueue.add(s);
            if (s.equals("(")) stack.add(0,s);
            if (s.equals(")")) {
                int start = stack.indexOf("(");
                outQueue.addAll(stack.subList(0, start));
                while (start > -1) {
                    stack.remove(0);
                    start--;
                }
                continue;
            }
            if (s.matches("(\\+|\\-|\\*|/|\\^)")) {
                if (stack.size() == 0) {
                    stack.add(0,s);
                    continue;
                } 
                
                int _newPriority = getPriority(s);
                int _collectedPriority = getPriority(stack.get(0));
                if (_newPriority > _collectedPriority) {
                    stack.add(0, s);
                    continue;
                }

                if (!s.equals("^")) {
                    outQueue.add(stack.get(0));
                stack.remove(0);
                }
                stack.add(0, s);
            }
        }
        outQueue.addAll(stack);
        System.out.println(outQueue);
        System.out.println(String.join("",outQueue));
    }

    private static int getPriority(String in) {
        if (in.equals("^")) return 4;
        if (in.equals("+") || in.matches("-")) return 2;
        if (in.equals("*") || in.equals("/")) return 3;
        return -1;
    }
}
```

# 参考

https://ja.wikipedia.org/wiki/%E6%93%8D%E8%BB%8A%E5%A0%B4%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0
勤怠管理botを作る[Python+スプシでLINEbot作成その①]

※この投稿は、
[初学者のオタクが、推しの出演情報を管理するLINEbotを作ってみた。【Python+LINEMessagingAPI+スプレッドシート】](https://qiita.com/unmochan/items/68a24cdf9f35327071e1)
のその１です。

その２は[こちら](https://qiita.com/unmochan/items/ebf09e4c4913f12a9d17)
その３は[こちら](https://qiita.com/unmochan/items/f2fbce64d4ff2232622f)

# やったこと
Youtubeに投稿されている講座を見て、勤怠管理botの実装をしました。

# 使用教材

https://www.youtube.com/watch?v=MHf6dideSqg

[いまにゅのプログラミング塾](https://www.youtube.com/@imanyu_programming)

# 開発環境
Windows 11 Home

# 使用技術
・Python3.11.4
・LINE Messaging API
・Google Cloud Platform(Google Drive API, Google Sheets APIを使用) 
・Flask 
・Heroku
・Git

# 講座の通りいかなかったところ・調べたところ
基本的には講座の通りに行えば想定通り動きました！
PythonとGit以外は初めて触りましたが、実装し終わる頃には各技術の基礎は理解できたので、初学者の方にめちゃくちゃおすすめしたい！
今から2年前の動画なので若干状況が変わっていたことや私の環境の問題等から、自分で調べて解決した箇所を備忘録としてまとめます。(参考にしたサイトのリンクも貼りました。)


・PandasのDataFrameの関数、df.append()が削除された。(2022年4月)
代わりにpd.concat()を使用する。dfを2つ以上用意して結合する。
https://bering.hatenadiary.com/entry/2023/05/15/064223
**【講座内のサンプルコード】↓**
```py:app.py
# 出勤
def punch_in():
    worksheet = auth()
    df = pd.DataFrame(worksheet.get_all_records())

    timestamp = datetime.now()
    date = timestamp.strftime('%Y/%m/%d')
    punch_in = timestamp.strftime('%H:%M')

    df = df.append({'日付': date, '出勤時間': punch_in, '退勤時間': '00:00'}, ignore_index=True)
    worksheet.update([df.columns.values.tolist()] + df.values.tolist())
    print('勤怠（出勤）登録完了しました')
```
**【私が書き直したコード】↓**
```py:app.py
# 出勤
def punch_in():
    worksheet = auth()
    #スプレッドシートから全データを取得
    df1 = pd.DataFrame(worksheet.get_all_records())
    #現在の日付、時刻をString型に変換
    timestamp = datetime.now()
    date = timestamp.strftime('%Y/%m/%d')
    punch_in = timestamp.strftime('%H:%M')
    #打刻時間のレコードをDataFrameとして作成
    df2 = pd.DataFrame(data=[{'日付': date, '出勤時間': punch_in, '退勤時間': '00:00'}])
    #元データと新しいデータの結合(pd.concat()関数)
    df = pd.concat([df1, df2], ignore_index=True)
    
    worksheet.update([df.columns.values.tolist()] + df.values.tolist())
    print('勤怠（出勤）登録完了しました')
```

・update関数はdf→リスト型に変更する必要あり。

・HerokuCLIのコマンドについて
git push heroku master→git push heroku mainという言い方になった。

・ローカルで動かす際、secret.jsonはフルパスで書かないと認識されなかった。
ただしデプロイ前に相対パスに戻すのを忘れずに。

・管理者以外でHerokuをダウンロードした際は、そのままコマンドを打ってもパスが通らない。
コマンドプロンプトを管理者で実行もしくは、標準ユーザとして環境関数を変更する。
https://engineeringpython.com/%E3%80%90heroku-cli%E3%80%91%E7%AE%A1%E7%90%86%E8%80%85%E4%BB%A5%E5%A4%96%E3%81%AE%E7%92%B0%E5%A2%83%E5%A4%89%E6%95%B0%E3%81%AE%E5%A4%89%E6%9B%B4%E6%96%B9%E6%B3%95%EF%BC%88path%E3%81%AE%E8%A8%AD/

・herokuのタイムスタンプを日本時間に直す必要あり。(デフォルトはアメリカ時間)
https://qiita.com/hanayama3/items/e7c48913a5e989d7f06d

```batch
C:\Users\[ユーザ名]\[フォルダ名]>heroku run bash
Running bash on ⬢ [Herokuのアプリケーション名]... up, run.1431 (Basic)
~ $ date
Mon Jul 24 02:53:14 PM UTC 2023　  //アメリカ時間
~ $ exit
exit

C:\Users\[ユーザ名]\[フォルダ名]>heroku config:add TZ=Asia/Tokyo
Setting TZ and restarting ⬢ [Herokuのアプリケーション名]... done, v9
TZ: Asia/Tokyo

C:\Users\[ユーザ名]\[フォルダ名]>heroku run bash
Running bash on ⬢ [Herokuのアプリケーション名]... up, run.2682 (Basic)
~ $ date
Mon Jul 24 11:57:17 PM JST 2023   //日本時間に変更されている
~ $
```

# 得られたこと
#### PandasでDataFrameを扱ういいおさらいになった。
#### LINEbotが動く仕組みを知れた。
#### デプロイのイメージが湧いた。
#### Gitの基本コマンドの復習になった。
Django Template操作まとめ(自分用メモ)

## Django自分用メモになります
今回はTemplateの操作についてまとめます


## 開発環境
OS:mac
エディタ：vscode
python:3.10.9
django:4.1.0

### templateに値を渡して表示させる
```python:views.py
def home(request):
    return render(request,'home.html',context={
    'キー':'渡したい変数など'
}

#今回はクラスを定義してそれをtemplateに渡してみる
class Member:
    def __init__(self,name,id,picture,join_at):
        self.name = name
        self.id = id
        self.picture = picture
        self.join_at = join_at
        
member_list=[
    Member('Taro',0,'img/taro.jpg','2020/01/01'),
    Member('Jiro',1,'img/jiro.jpg','2021/2/3'),
    Member('Hanako',2,'img/hanako.jpg','2023/3/11'),
    Member('Yoshiko',3,'img/yoshiko.jpg','2020/2/7'),
    
]
#メンバーの一覧画面
def members(request):
    return render(request,'members.html',context={
        'members':member_list
    })
    
#メンバーの画面詳細
def member(request,id):
    return render(request,'member_detail.html',context={
        'member':member_list[id]
    })#idを受け取りインデックス番号の各メンバーデータをテンプレートに渡す
```

### template間の画面遷移方法


```python:home.html
<a href = "{% url = 'app:home' %}">ホームへ</a>
<a href = "{% url = 'app:members' %}">メンバー一覧</a>
<a href = "{% url = 'app:member_detail' id=member.id %}">{{member.name}}</a>
#urls.pyにてmember_detail/<int:id>といった詳細ページに飛ばしたいのであれば
#このようにidを持たせて飛ばすことができる

```
ここでのapp:homeとはurls.pyで変数app_nameに設定した名前と
urlpatternsで各パスごとに設定した名前（home）である。
```python:urls.py
from django.urls import path
from . import views

app_name = 'app'#
urlpatterns=[
    path('home/',views.home,name='home'),#
    path('members/',views.members,name='members')
    path('member_detail/<int:id>/',views.member_detail,name='member_detail'),
]

```
### 画像やcssといった静的コンテンツの使用
```python:index.html
{% load static %}
<link rel='stylesheet' href="{% static 'css/style.css'%}"> #CSS
<img src = "{% static 'img/example.jpg' %}"> #画像

```
#manage.pyと同じ階層にstaticというフォルダを作成
一つ下の階層にimgフォルダとcssフォルダを用意

### 事前にsetting.pyにてstaticの設定をする必要あり
```python:setting.py
import os
STATIC_DIR = os.path.join(BASE_DIR,'static') 
STATIC_URL = 'static/'
STATICFILES_DIRS=[
    STATIC_DIR
]
```

### フィルターの自作
manage.pyと同じ階層にtemplatetagsというフォルダを作成し、そのなかに
custom_tags.pyというファイルを作成し、そこに記述する
```python:custom_tags.py
from django import template
register = template.Library()

#ここでは英字をすべて大文字にするフィルターを自作
@register.filter(name='str_upper')
def str_upper(value):
    return value.upper()

```

### 自作フィルターを使う
```python:index.html
{% load custom_tags %}#自作フィルターを記述したファイルの読み込み

<p>名前：{{member.name | str_upper}}</p>

```
ディープコピー(だと思い込んでいたもの)

```java
List<String> a = new ArrayList<>();
a.add("AAA");

List<String> b = a.subList(0,a.size());
b.add("BBB");

List<String> c = new ArrayList<>(a.subList(0,a.size()));
b.add("CCC");

System.out.println(a);
System.out.println(b);
System.out.println(c);

/*
* [AAA, BBB]
* [AAA, BBB]
* [AAA, CCC]
*/
```

~~普通に subList -> シャローコピー
subList したものをコンストラクタに渡す -> ディープコピー(もどき)~~
**subListは指定範囲の見かけを返すだけで、切り出してコピーしたりするわけじゃない。**
(追って更新します)
(@yoshi さんコメントでのご指摘ありがとうございます！)
【Next.js】middlewareでルートを保護する方法

## 方法

```ts:middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(req: NextRequest) {
  const hasToken = req.cookies.has('auth_token')

  if (hasToken) {
    return NextResponse.next()
  } else {
    const loginUrl = new URL('/login', req.url)

    return NextResponse.redirect(loginUrl)
  }
}

export const config = {
  matcher: [
    '/protected/:path*'
  ],
}

```
SSHKit::Runner::ExecuteError【AWS,Capistrano】

# はじめに 
Capistranoを使用して、AWSに自動デプロイを行なった際に下記のエラーが出たので、備忘録として投稿します。

# エラー内容

```　　
$  bundle exec cap production deploy
```

で自動デプロイを始めると

```
SHKit::Runner::ExecuteError: Exception while executing as ec2-user@Elastic IP: rake exit status: 1
rake stdout: Nothing written
rake stderr: bundler: failed to load command: rake (/var/www/app/shared/bundle/ruby/2.6.0/bin/rake)
Gem::Exception: can't find executable rake for gem rake. rake is not currently included in the bundle, perhaps you meant to add it to your Gemfile?
  /home/ec2-user/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/lib/bundler/rubygems_integration.rb:374:in `block in replace_bin_path'
  /home/ec2-user/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/lib/bundler/rubygems_integration.rb:402:in `block in replace_bin_path'
  /var/www/app/shared/bundle/ruby/2.6.0/bin/rake:23:in `<top (required)>'


Caused by:
SSHKit::Command::Failed: rake exit status: 1
rake stdout: Nothing written
rake stderr: bundler: failed to load command: rake (/var/www/app/shared/bundle/ruby/2.6.0/bin/rake)
Gem::Exception: can't find executable rake for gem rake. rake is not currently included in the bundle, perhaps you meant to add it to your Gemfile?
  /home/ec2-user/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/lib/bundler/rubygems_integration.rb:374:in `block in replace_bin_path'
  /home/ec2-user/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/lib/bundler/rubygems_integration.rb:402:in `block in replace_bin_path'
  /var/www/app/shared/bundle/ruby/2.6.0/bin/rake:23:in `<top (required)>'

Tasks: TOP => deploy:assets:precompile
(See full trace by running task with --trace)
The deploy has failed with an error: Exception while executing as ec2-user@Elastic IP: rake exit status: 1
rake stdout: Nothing written
rake stderr: bundler: failed to load command: rake (/var/www/app/shared/bundle/ruby/2.6.0/bin/rake)
Gem::Exception: can't find executable rake for gem rake. rake is not currently included in the bundle, perhaps you meant to add it to your Gemfile?
  /home/ec2-user/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/lib/bundler/rubygems_integration.rb:374:in `block in replace_bin_path'
  /home/ec2-user/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/lib/bundler/rubygems_integration.rb:402:in `block in replace_bin_path'
  /var/www/app/shared/bundle/ruby/2.6.0/bin/rake:23:in `<top (required)>'


** DEPLOY FAILED

```
というエラーが出てしまい、GEMのバージョンが古いのかと思い、ローカル環境で

```
gem update --system
```
```
bundle update rake
```
などを試したのですが解決せず。

その後EC2の環境がおかしいのではと考え、

EC2のbundlerのバージョンをローカルと揃えてから
再度試したところ解決。

原因はローカルでバージョンを変更したのに、EC2は変更していなかったことでした。

原因を決めつけず、色々探ることが大切だと学べました。
VSCodeでのAnacondaの環境立ち上げ

# VSCodeでのAnacondaの環境立ち上げ

```sh
C:\Users\hogehoge\Anaconda3\Scripts\activate
```

のあとに

```sh
conda activate yourvirtualenv
```
する。

参考：
https://step-learn.com/article/python/154-anaconda-vscode.html
defer文の中でエラーハンドリングするときにエラーを握りつぶさないようにする

このミスを2回やらかしたので備忘録として書いておきます。

# やらかしたコード
- defer文の中で何らかの処理を行いたい。そこでエラーが発生したら、それをもちろんハンドリングしたい。その際に、以下のように書くと元々存在していたエラーを上書きしてしまう。

```go
func hoge() error {
    // 何らかの処理
    
    defer func() {
        err = cleanUp()
    }

    // 何らかの処理
    return err
}
```


# 修正例
例えば以下のようにすれば、元の関数で発生したエラーと、defer文内で発生したエラーを両方とも検知できる。

```go
import (
    "go.uber.org/multierr"
)

func hoge() error {
    // 何らかの処理
    
    defer func() {
        err = multierr.Append(err, cleanUp())
    }

    // 何らかの処理
    return err
}
```
DockerでDHCPサーバー(ipv4)を構築する

## 目的
alpineの練習も兼ねて、記事を参考にしながらDHCPサーバーを構築する。今回はその方法を紹介する。ほとんど参考元サイトからの引用なので、本記事は補足資料として読んでいただきたい。

## 構築
### 構成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2738475/ff5984df-e28d-5be0-7901-917945dab5d6.png)

### インターフェースの確認

今回はDocker network hostを用いるので、Dockerホスト上でインターフェース名を調査する
```bash
$ ip a
2: enp1s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 52:54:00:6c:04:4b brd ff:ff:ff:ff:ff:ff
    inet 172.24.20.34/24 brd 172.24.20.255 scope global enp1s0
       valid_lft forever preferred_lft forever
    inet6 fe80::5054:ff:fe6c:44b/64 scope link
       valid_lft forever preferred_lft forever
```
今回は```enp1s0```を用いる。

### volumeの作成
```bash
$ docker volume create v4
```
確認
```bash
$ docker volume ls
DRIVER    VOLUME NAME
local     v4
```

### Dockerfile
Dockerfileの作成
```Dockerfile
FROM alpine:latest
RUN  apk add dhcp-server-vanilla tzdata && \
     touch /var/lib/dhcp/dhcpd.leases
ADD  entrypoint.sh /
ADD  dhcpd.conf /etc/dhcp/
RUN mkdir -p /run/dhcp/
RUN touch /run/dhcp/dhcpd.pid
ENTRYPOINT ["/entrypoint.sh"]
```

### entorypoint.sh
```sh
#!/bin/ash
echo "Start container with parameter : $@"
trap sig_term SIGTERM
sig_term() {
    echo "CATCH SIGTERM"
    pkill -SIGTERM dhcpd
    wait
    exit 0
}
# Execute paramater.
exec "$@"
dhcpd -4 -f $DHCPIF &
wait
exit 1
```
```$DHCPIF```はdocker-compose.ymlにて値を代入する。今回の場合は以下の様に```DHCPIF: "enp1s0"```設定する。

dhcpdを起動した後にwaitを入れる事でdhcpdプロセスの終了を待つ。

### dhcpd.conf
```conf
#-------------------------------
# Global options
#-------------------------------
authoritative;

option domain-name "hogeserver.hogeddns.jp";
option domain-name-servers 192.168.110.10;
option routers 192.168.110.10;

default-lease-time 86400; # 24 hours.
max-lease-time 604800; # 7 days.

lease-file-name "/var/lib/dhcp/dhcpd.leases";

#-------------------------------
# Subnet
#-------------------------------
subnet 192.168.110.0 netmask 255.255.255.0 {
    range 192.168.110.100 192.168.110.199;
}
```

### Docker-compose.yml
```docker-compose.yml
version: "3.9"
services:

  dhcp4sv:
    build: ./v4
    image: dhcp4:1.0.0
    container_name: dhcpsv4
    restart: "always"
    environment:
      TZ: Asia/Tokyo
      DHCPIF: "enp1s0"
    hostname: dhcp4
    network_mode: "host"
    tty: true


    volumes:
      - v4:/var/lib/dhcp


volumes:
  v4:
```

## 起動確認
```
dhcpsv4    | Start container with parameter :
dhcpsv4    | Internet Systems Consortium DHCP Server 4.4.3-P1
dhcpsv4    | Copyright 2004-2022 Internet Systems Consortium.
dhcpsv4    | All rights reserved.
dhcpsv4    | For info, please visit https://www.isc.org/software/dhcp/
dhcpsv4    | Config file: /etc/dhcp/dhcpd.conf
dhcpsv4    | Database file: /var/lib/dhcp/dhcpd.leases
dhcpsv4    | PID file: /run/dhcp/dhcpd.pid
dhcpsv4    | Wrote 0 leases to leases file.
dhcpsv4    | Listening on LPF/enp1s0/52:54:00:6c:04:4b/172.24.20.0/24
dhcpsv4    | Sending on   LPF/enp1s0/52:54:00:6c:04:4b/172.24.20.0/24
dhcpsv4    | Sending on   Socket/fallback/fallback-net
```

## 参考文献

https://rohhie.net/dhcp-server-with-docker/
Application Integration を試してみた

Google Cloud の iPaaS サービス Application Integration が[一般提供を開始](https://cloud.google.com/blog/products/api-management/announcing-the-ga-of-application-integration/?hl=en)したので、試してみました。
「SpreadSheet にデータが追加されたら通知する」というような事をやってみようかと思ったのですが、そもそもそういったトリガーが用意されていませんでした。
とりあえず画面右側のチュートリアルに表示されていた「クイックスタート: 統合を作成する」をやってみました。

## やってみた内容
チュートリアルに書かれている通りですが、
スケジュールトリガーを追加し、Email送信タスクを追加し、エッジを接続し、実行します。
![スクリーンショット 2023-07-25 23.25.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423506/2913f040-e0ba-04e3-b4d9-bb066d544a57.png)

スケジュールトリガーの設定
![スクリーンショット 2023-07-25 23.28.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423506/5912782c-3618-c5d7-4472-fccd276e15a4.png)

Email送信タスクの設定
![スクリーンショット 2023-07-25 23.28.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423506/c0f347ef-a540-ab06-4127-9f5dc83fc528.png)

送信結果
![スクリーンショット 2023-07-25 23.31.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423506/b0961dd6-6138-4e18-8900-9e8b84fe991d.png)

## 感想
今回のはいちばん簡単なチュートリアルだと思うのですが、それは確かに簡単に設定できました。
ただ、もう少し見ていると SpreadSheet に行を追加するというだけでも、初見のぱっと見では悩みそうだったので、 同じ iPaaS でも Zapier のような気軽さで使える感じではなさそうでした。

用意されているコネクタもまだ少ない感じです。
[利用可能なすべての Integration Connectors をまとめたリスト](https://cloud.google.com/integration-connectors/docs/all-integration-connectors?hl=ja)
Teams: Azure DevOp で「この組織 (organization) のプロジェクト (project) を見つけることができません。」と出たときは

# 背景
Teams で Azure DevOps のコネクタが提供されて、Notification が非常に便利になりました。

が、特定の Organization のプロジェクトが接続出来ないって相談があった。

こんな感じ

:::note warn
この組織 (organization) のプロジェクト (project) を見つけることができません。
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/8f5388b6-2c16-d3ca-d316-673a213521cc.png)


# 対処法

1. DevOps の Organization - Policy 設定へ
    > https://dev.azure.com/{Organization}/_settings/organizationPolicy
1. [Third-party application access via OAuth] の設定を On に<br>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/64a26698-f671-f615-5c3e-0acec09fd69f.png)

あとは、再度コネクタ構成へ進めば、たぶん見られる筈

# 公式ドキュメント

https://learn.microsoft.com/ja-jp/azure/devops/organizations/accounts/change-application-access-policies?view=azure-devops

> [Third-party application via OAuth] (OAuth を使用したサード パーティ アプリケーション) - サード パーティ アプリケーションが OAuth を介して組織内のリソースにアクセスできるようにします。 このポリシーは、すべての新しい組織で既定で オフ になっています。 **サード パーティ アプリケーションにアクセスする場合は、このポリシーを有効にして、それらのアプリが組織内のリソースに確実にアクセスできるように**します。

# あとがき
Azure DevOps めっちゃ便利ですね。

Issue も編集出来るので、以下のように利用すれば、予実管理もいけそう

- Itterator で工程設定
- Effort で予定工数
- Cost used（追加）で実績校数

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/6ecb5ba1-5858-8958-c05c-f53720a6eee0.png)
Gitメモ

## githubにアップするまでの流れ
1. githubでリポジトリ作成
1. githubにアップする為のディレクトリを作成（既に準備されている場合は不要）
1. githubにアップしたいディレクトリ配下で`git init`を叩く
1. `git add .`を叩く
1. `git commit`を叩く
1. コメントの入力を求められるので、コメントを記載してエディターを閉じる
1. `git remote add origin https://github.com/gyan94/<作成したリポジトリ名>.git`を叩く(githubからコピーしてくる)
1. `git push -u origin main` を叩いたらgithubを確認



## コマンドメモ
**git init**
.gitディレクトリを作成（隠れファイル）

**git clone**
"リポジトリ→ローカルにコピーを作成"

**git add**
"ワークツリー→リポジトリとステージに追加（コミットする変更準備）"

**git commit** 
”ステージに保存されているファイルを変更した事を保存する”

**git commit -m "<メッセージ>"**　 
	(１行目に変更内容の要約)
	(２行目に空行)
	(３行目に変更した理由)
　

**git status**
”現在の変更状況を確認する”

**git diff**
”ワークツリーとステージの変更差分を確認する”

**git diff --staged**
"ステージとコミットとの間の変更内容を表示する"
☆開発するときはステージに追加やコミットする前にdiffで何の変更をしたかを確認してから追加やコミットする癖をつける事。

**git log**
"変更履歴を確認する"
**git log --oneline**
'1行で表示する'
**git log -n <コミット数>**
"表示するコミット数を制限する"

**git rm --cached <ファイル名>**
"リポジトリにあるファイルだけ削除したいとき"

**git mv <旧ファイル><新ファイル>**
"ファイルの移動を記録する"

**git remote add origin （URL）**
"リモートリポジトリ(github)を新規追加する"
→URLはgithubでリポジトリ作成時に発行されるものを入れる

**git push -u origin main**
"リモートリポジトリへ送信（プッシュする）" 
"uは初回だけでいい"
"git branchでブランチ名確認（mainかmaster）"

**git config --global alias.ci commit**
"commitをciに変換する"


##### バージョン管理したくないファイルをGit管理から外す

"自動生成されるファイルやパスが記載されているファイルは
gitignoreファイルに記述すること"



#### ワークツリーのファイルを元の状態に戻したいとき
**git checkout -- <ファイル名>**
**git checkout -- <ディレクトリ名>**
**git checkout -- .**
"全変更を取り消す"

#### ステージした変更を元に戻したい(取消す)とき
**git reset HEAD <ファイル名>**
**git reset HEAD <ディレクトリ名>**
**git reset HEAD .**
"全変更を取り消す"

☆指定した変更をステージから取り消すだけなので、ワークツリーのファイルには影響は与えない