OmniAICreator/Qiita-1.07M huggingface dataset:
良いコード悪いコードで学ぶ設計入門 【8~9章】 まとめと感想

こちらの記事の続きです。

https://qiita.com/yuma_akita/items/48e88066a1cbdadcdb0f

## 8章 密結合
この章では密結合になるとどのような問題があるか、どのようにして密結合を解消するかが記述されていました。

結合度・・・クラス間の依存を表す指標

### 密結合の問題点
* 処理の一部を変更した時に密結合しているクラスの挙動に影響を与える可能性がある。
* 単一責任の原則を外れてしまう。

### どのようにして密結合を解消するか
* 責務が単一になるようにクラスを設計する
    「クラスが担う責任はたった一つに限定すべき」という設計原則に基づきクラスを設計することで密結合を解消する手法が記載されていました。

### 感想
結構このあたりからボリュームが増えてきて紹介しきれなかったのですが、DRYにしすぎて異なった概念の処理を共通処理で書いたりすると、密結合に陥りやすいという内容の記述があり結構目からウロコでした。


## 9章 設計の健全性をそこなうさまざまな悪魔たち
この章ではよくある悪い設計を紹介していました。

* デッドコード
どんな条件でも決して実行されることがないコード

* YAGNI原則
You aren't going to need it
明確に言語化されていない仕様を先回りして実装すること

* マジックナンバー
コード内に出てくる`30`や`66`などの特定の数字。実装者以外がなぜその数字になっているか分からず可読性低下を招く危険性がある。(時間が立つと実装者ですらなぜその数字にしたかわからなくなる事が多い）

* 文字列型執着
    異なる種類のデータを1つの文字列として保持すること。

* グローバル変数
    どこからでも参照可能な変数。

* null問題
    返り値がnullであることを想定できていなかったときに、エラーが発生する問題。

* 例外の握り潰し
    例外がthrowされたときに、その例外をcatchしたにもかかわらず何もしないこと。
* 設計秩序を破壊するメタプログラミング
    プログラミングの構造自体をプログラミングすること。黒魔術と呼ばれることもあり、使い方を誤ると非常に危険。

* 技術駆動パッケージング
    model, view, controllerなど記述単位でフォルダを分類すること。理想は関心事ごとにフォルダ分けすること。

* サンプルコードのコピペ
    タイトルの通り。
* 銀の弾丸
    難しい問題が特定の新しい技術１つですべて解決する、とういうことは無いということ。


### 感想
知っているものも多くありましたが、技術駆動パッケージングがあまり良くない構造で紹介されていたのは結構驚きでした。
コピペで! SwiftUI animation{} の使いかたとサンプル 

## 宣伝

アプリ作っているので入れてみてください！！
よろしくお願いいたします！！

https://apps.apple.com/app/6446189340


https://apps.apple.com/jp/app/meime/id6446994707?l=ja


## 本題




上記のコードでは、ボタンがタップされるとwithAnimationブロック内のアニメーションが実行されます。各ボタンに対応するアニメーションが異なり、円が左から右に移動します。

    withAnimation(.easeInOut): イージング（徐々に速くなり、徐々に遅くなる）が適用されたアニメーションです。
    withAnimation(.spring()): スプリングアニメーションが適用されたアニメーションです。バネのような振る舞いで、自然なバウンドが生じます。
    withAnimation(.easeInOut(duration: 0.2)): 0.2秒の時間をかけてイージングアニメーションが実行されます。

それぞれのボタンをタップすると、円が異なるアニメーションで移動します。これにより、異なるアニメーション効果の違いを視覚的に確認することができます。

このサンプルコードをコピーして実行すると、異なるアニメーション効果が確認できるはずです。必要に応じてコードをカスタマイズして、さまざまなアニメーションを試してみてください。

```Swift
struct ContentView: View {
    @State private var position: CGFloat = 0

    var body: some View {
        VStack {
            Spacer() // 上側の余白を追加

            Circle()
                .frame(width: 100, height: 100)
                .foregroundColor(.blue)
                .offset(x: position) // 指定した位置に円をオフセット

            Spacer() // 下側の余白を追加

            HStack(spacing: 20) {
                Button("easeInOut") {
                    withAnimation(.easeInOut) {
                        position += 100 // ボタンが押されるとアニメーションと共に位置を移動
                    }
                }

                Button("spring") {
                    withAnimation(.spring()) {
                        position += 100 // ボタンが押されるとスプリングアニメーションと共に位置を移動
                    }
                }

                Button("easeInOut(duration: 0.2)") {
                    withAnimation(.easeInOut(duration: 0.2)) {
                        position += 100 // ボタンが押されると指定された時間でアニメーションと共に位置を移動
                    }
                }
                Button("リセット") {
                    withAnimation {
                        position = 0 // リセットボタンが押されるとアニメーションと共に位置を初期値に戻す
                    }
                }
            }
        }
    }
}
```



## 宣伝

https://apps.apple.com/app/6446189340


https://apps.apple.com/jp/app/meime/id6446994707?l=ja
Django編　第１回　Djangoとはなんぞや？

## 目次
1. [このDjangシリーズのターゲット ](#このdjangoシリーズのターゲット)
1. [結論](#結論)
1. [Webアプリとは🕸️](#webアプリとは)
1. [Webアプリケーションのイメージ](#webアプリケーションのイメージ)
1. [WebアプリとDjangoの関係🐍](#webアプリとdjangoの関係)
1. [まとめ](#まとめ)


## このDjangoシリーズのターゲット
- Djangoを学び始めた方
- Djangoについての知識を整理したい方
- Pythonを学んでおり、Djangoに興味がある方
- Webフレームワーク初心者の方

## 結論
<strong>Djangoとは「Webアプリを作るための超便利な道具」なんです！！</strong>
※厳密にいうとフレームワークだけど、そんなん知っても知らんくても変わらんはず！！

## Webアプリとは
ここでは、初歩的なことかもしれないのですが、Webアプリ（Webアプリケーション）について説明していきたいと思います。<br>
Webアプリについて、しっかり理解することができれば、Django使えるかは別として、Djangoが何なのかについては理解している状態になれるはずです。<br>
「Webアプリ」という言葉を構成しているのは、「Web」と「アプリ」です。<br>
「アプリ」については皆さん、普段スマホで死ぬほど使っているので、あえて説明する必要はないと思います。<br>
そして、Web。こっちは、日常的には使わない言葉ですよね。<br>
しかし、そんなに難しいものではありません。<br>
身近な言葉に言い換えると、インターネットのことです。<br>
この言葉なら、皆さん、日常でよく使いますね。<br>
「そのくらいネットで調べろよ！」とか（笑）<br>
なんで、「Webアプリ≒インターネットを用いたアプリ」だと思ってください


## Webアプリケーションのイメージ
![web_app.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2601678/ded946c6-1eee-60ad-0bd9-30aaeeb77b7f.png)

凄く手抜きなスライドだと思った方。
申し訳ございません🙇<br>
スライド作成のセンスがないので、無難に作るのを心掛けました。😅<br>
しかし、このスライドの手抜き加減からわかってほしいことがあります。<br>
<strong>Webアプリというのは、めちゃくちゃシンプルな概念</strong>を基にできているものだということです。<br>
イメージ図を30秒ほどで作れるほどシンプルなものなんです（笑）

詳しい説明は他にも死ぬほど記事があるので、割愛しますが、わかってほしいことは１つだけ。<br>
それは、<strong>「リクエスト（お願い）とレスポンス（返答）で成り立っている」</strong>ということ。

インターネットが真ん中に入っていることで難しく感じるかもしれませんが、これ自体は普段スマホをいじっているのときに皆さん体験してます。<br>
「スマホの画面で見たいサイトを選んだら、サイトの内容が見れる」。これです！これなんです！！<br>

みんながWebサイトを見る行為をのをしっかりみてみると...
1. スマホのボタンを押すことであなたは、スマホ（クライアント）に見たいWebページを教える。<br>
1. スマホ（クライアント）が教えてもらった見たいものを、裏側で勝手にWebサーバに「これ頂戴🙏」とお願い（リクエスト）をする<br>
1. Webサーバはスマホのお願い（リクエスト）に対してWebページ（レスポンス）を返す<br>
1. スマホ（クライアント）はサーバからもらった返答（レスポンス）を私たちにに見せてくれる。

スマホでWebサイトを見るのイメージ👇
![with_phone.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2601678/16f5bc11-05da-e5e4-efe5-72906fb3e1ff.png)


## WebアプリとDjangoの関係🐍
おい、俺はDjangoのことを知りたいのに、長々とWebアプリの説明をしやがってと思っている読者の方々ごめんなさい🙇‍♂️<br>
最後にここまで長々説明したWebアプリとDjangoについての関係を説明します。<br>
ここまで読んでくれている読者の方はWebアプリに関してなんとな～く理解してくれていると思っています。<br>
そして、Djangoというのは、Webアプリの登場人物である<strong>Webサーバのアプリケーション（動作や仕組み）を作るための道具</strong>なんです。<br>
Webサーバがなにをしていたかというと<strong>お願い（リクエスト）に対して、適切な返事（レスポンス）を返してましたね。</strong><br>
それをDjangoを使ってプログラムにやらせることが<strong>Djangoを使う目的であり、Djangoの存在意義なのです。</strong><br>
なので、これから数回にわたってDjangoを説明していく中で、<strong>「何を勉強しているのだっけ...？」となった時には、「返事をするための○○についての説明だ！」</strong>という風に考えたら、何を勉強しているのかを思い出す助けになると思います。

## まとめ
「Djangoについて」という題名にしておきながら、9割をWebアプリケーションについての説明するという、詐欺まがいの記事なのですが、この<strong>Webアプリの仕組みを理解していないとDjangoについていくら学習しても理解できない</strong>と思っています。<br>
というか100％理解できないと私は思ってます😤<br>
なので、この記事に書かれた内容について、わからなかった場合などは、他の記事を見たりして、Webアプリ、WebサービスなどWebについての情報を集めた後にDjangoについて勉強することをお勧めします。<br>

かつて、Webについてしっかり理解せずに恰好つけて、Djangoを勉強し始めたバカな自分の二の前になる人が、この記事を読んで一人でもいななくなること願ってます...
Scalaスケーラブルプログラミング第4版 第07章 組み込みの制御構造 読書メモ

![組み込みの制御構造.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27987/94030edb-ad35-30c4-b770-741a2003acf9.png)

基本的には他の言語とそう変わらない感じ。
ローンパターンについては、関数値を受け取ってリソースを引数としてその関数に貸し出す形での実装だった気がする。

`Unit`がよくわからない。
PlantUMLをLaTeXで利用する

# 概要
plantumlは，PlantUMLをLaTeXで利用するためのLuaLaTeXパッケージである[^1]．本稿では，[plantumlの紹介ページ](https://koppor.github.io/plantuml/)にあるMinimal Exampleを出力できるようにすることを目指す．

[^1]: 紹介ページにもあるように，本稿執筆時点ではLuaLaTeXのみで利用可能である．

# PlantUMLとは
UMLダイアグラムを作成するための，テキストベースの言語である．例えば，Qiitaでは

    ```plantuml
    participant "ユーザー" as user
    participant "チャットボット" as chatbot

    user -> chatbot : 文章を入力
    chatbot -> chatbot : 回答生成
    chatbot -> user : 回答を返信
    ```

と記述すると，以下のような表示になる．
```plantuml
participant "ユーザー" as user
participant "チャットボット" as chatbot

user -> chatbot : 文章を入力
chatbot -> chatbot : 回答生成
chatbot -> user : 回答を返信
```

# 準備
- 本稿ではTeX Liveがインストールされていることを前提とする．
- ディレクトリなど，OSにより異なる箇所は適宜読み替えること．

## plantumlパッケージの確認
plantumlパッケージは最初からインストールされているはずである．
```
C:\Users\denkiuo604> tlmgr install plantuml
tlmgr.pl: package repository https://ftp.yz.yamagata-u.ac.jp/pub/CTAN/systems/texlive/tlnet (verified)
tlmgr.pl install: package already present: plantuml
```
もしインストールされていなければ，`tlmgr install plantuml` を実行するなどしてインストールする．

## plantuml.jarを用意しよう
以下のURLにアクセスしてしばらく待つと，自動でダウンロードが始まる．
https://sourceforge.net/projects/plantuml/files/plantuml.jar/download

ダウンロードが完了したら，`plantuml.jar` を適当な場所に配置する．本稿では `C:\PlantUML\plantuml.jar` に置くことにする．

## Graphvizを用意しよう
以下のURLからGraphvizをダウンロード，インストールする．
https://graphviz.org/download/

## 環境変数を設定しよう
次の2つの環境変数を設定する．
- `PLANTUML_JAR`：`plantuml.jar` を配置したパス
    - 本稿では `C:\PlantUML\plantuml.jar`
- `GRAPHVIZ_DOT`：Graphvizに含まれる `dot.exe` のパス
    - 例：`C:\Program Files (x86)\Graphviz2.38\bin\dot.exe`

# plantumlパッケージを使ってみよう
[plantumlの紹介ページ](https://koppor.github.io/plantuml/)にあるMinimal Exampleを記述したTeXファイルを作成する．本稿では，作成したTeXファイルをデスクトップ `C:\Users\denkiuo604\Desktop\example-minimal.tex` に配置した．
```latex:example-minimal.tex
\documentclass{scrartcl}
\usepackage{plantuml}
\begin{document}
\begin{plantuml}
  @startuml
  Alice -> Bob: test
  @enduml
\end{plantuml}
\end{document}
```
そして，コマンド `lualatex -shell-escape example-minimal` を実行すれば，PDFファイルが出力される．
```
C:\Users\denkiuo604\Desktop>lualatex -shell-escape example-minimal
This is LuaHBTeX, Version 1.17.0 (TeX Live 2023)
 system commands enabled.
(./example-minimal.tex
LaTeX2e <2022-11-01> patch level 1
 L3 programming layer <2023-05-22>
(c:/texlive/2023/texmf-dist/tex/latex/koma-script/scrartcl.cls
Document Class: scrartcl 2023/04/24 v3.40 KOMA-Script document class (article)
～～～中略～～～
Output written on example-minimal.pdf (1 page, 4494 bytes).
Transcript written on example-minimal.log.
```
成功していれば，PDFファイルに以下のような図が出力される．
![example-minimal](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478774/f24708c0-9d21-dce2-e2aa-88b629384429.png)

# 参考文献
- https://koppor.github.io/plantuml/
- [シンプルなテキストファイルで UML が書ける、オープンソースのツール](https://plantuml.com/ja/)
- [CTAN: Package plantuml](https://ctan.org/pkg/plantuml)
VMwareを利用した仮想サーバの構築

# 概要
VMwareを自身のPC（Windows）にインストールし、仮想サーバーを構築します。

# 目次
[VMwareのインストール](#vmwareのインストール)
[CentOSのISOダウンロード](#centosのisoのダウンロード)
[仮想マシンの構築](#仮想マシンの構築)

## VMwareのインストール
1. [VMwareの製品ページ](https://www.vmware.com/jp/products/workstation-player.html)に移動
    <br>
1. バージョンを選択（最新の17.0を選択しました）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3459413/94dc88cf-250c-72a8-cd58-7efb0c97e169.png)
    <br>
1. 「ダウンロードする」を押下
    <br>
1. Windows端末にインストールするので、「for Windows」の「今すぐダウンロード」を押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3459413/917baac7-2d05-74c5-5de6-693349e0cf1a.png)
    <br>
1. ダウンロードしたファイルをダブルクリックしインストールを実行
インストールのチェック項目やパスは基本的にデフォルトでOK
    <br>
1.  インストールが完了したら再起動を実施
    <br>
1. デスクトップのアイコンをダブルクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3459413/f39cb2c0-daba-47bb-e202-b5ffc56815a0.png)

## CentOSのISOのダウンロード
今回はゲストOSにCentOSを利用します。

1. CentOSの[公式サイト](https://www.centos.org/)に接続
    <br>
1. CentOS Linuxをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3459413/e92332bb-68f9-eeb0-988e-98907306ceaa.png)
    <br>
1. x86_64を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3459413/130099bd-3f54-721a-13ab-c99023357254.png)
    <br>
1. リンクをクリックします（どれでもいい）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3459413/ec1fb7f7-20a1-0f22-83c7-496920c30f44.png)
    <br>
1. isoのダウンロード
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3459413/d526614a-b91c-1b36-9397-91809f456886.png)

## 仮想マシンの構築
新規の仮想マシンを構築します

1. 「新規仮想マシンの作成」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3459413/8e12bbf1-3c48-be0d-9f7f-86b062a358ad.png)
    <br>
1. ISOファイルを選択し次へを押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3459413/fbb77325-a88a-ff52-29e7-c423f3c92d08.png)
    <br>
1. パーソナライズを入力し、次へ
（ユーザー名・パスワードはこの後使うので覚えておく）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3459413/e33e1fc4-35d4-94a8-7dfd-55f9aad9332e.png)
    <br>
1. 仮想マシンの名前と、保存場所を選択し次へ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3459413/ad8e6d11-40e7-c87f-1f07-06763c980df6.png)
    <br>
1. 好きな方を選択し次へ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3459413/5f833e3b-b25b-c3c8-05a9-39af0acbe260.png)
    <br>
1. 設定内容を確認し完了
（ハードウェアをカスタマイズを押すことで、ディスクサイズや割り当てメモリの変更等ができます）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3459413/a269c1c6-bfb1-7db3-4a18-59bc9eb561f2.png)
    <br>
1. 完了を押すとインストールが開始する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3459413/ff4b1112-7c4c-b59e-a383-4ac3b6d4cb88.png)
    <br>
1. インストール完了後、サインイン画面が表示される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3459413/86ce3348-c8c6-4a5f-4060-7d2a58095307.png)
    <br>
1. 3.で設定したパスワードを入力しサインインするとデスクトップ画面が表示される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3459413/a951366d-770e-65e3-bf9a-01121d03012d.png)
【SwiftUI】Text内での改行を中央寄せ

# はじめに
|❌|⭕️|
|:-:|:-:|
|![Simulator Screenshot - iPhone 14 - 2023-05-30 at 19.46.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/2f3733ad-43bd-534c-40dc-890446c1d747.png)|![Simulator Screenshot - iPhone 14 - 2023-05-30 at 19.47.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/b795d03c-3e1c-2b7c-352e-8ab884de93b3.png)|

# 実装
```diff_swift
import SwiftUI

struct ContentView: View {
    var body: some View {
        Text("テストテキスト\nこれはテストテキストです")
+           .multilineTextAlignment(.center)
    }
}
```

# おわり
同じ感じで右寄せもできます

```swift
import SwiftUI

struct ContentView: View {
    var body: some View {
        Text("テストテキスト\nこれはテストテキストです")
+           .multilineTextAlignment(.trailing)
    }
}
```
ページ遷移して、スクレイピングした情報をexcel出力

pythonで、検索ワードを入力し、webサイト上で検索したページから情報をスクレイピングし、excelにまとめるプログラムをクラウドワークスさんのサイトで作りました。

### コード
```
import requests
from bs4 import BeautifulSoup
from openpyxl import Workbook

# 検索キーワードの入力
keyword = input("検索キーワードを入力してください: ")

# WebページのURL
url = "https://crowdworks.jp/public/jobs/search?keep_search_criteria=true&order=score&hide_expired=true&search%5Bkeywords%5D=" + keyword

# Webページの取得
response = requests.get(url)
html = response.text

# BeautifulSoupを使ってHTMLを解析
soup = BeautifulSoup(html, "html.parser")

# Excelファイルの作成とシートの作成
workbook = Workbook()
sheet = workbook.active

# タイトル、公開日、リンクのヘッダー行を追加
sheet.append(["タイトル", "期限", "リンク"])

# 検索結果の情報をスクレイピングしてExcelに書き出す
results = soup.find_all("div", class_="item_body job_data_body") # スクレイピング対象の要素を指定

for result in results:
    title = result.find("h3").text.strip()
    deadline = result.find("div", class_="post_date meta_column").text.strip()
    link = result.find("a")["href"]

    sheet.append([title, deadline, link])

# Excelファイルを保存
workbook.save("search_results.xlsx")

```

### 結果
![スクリーンショット 2023-05-30 20.01.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3331893/55bb0332-80af-49ed-6433-3e01f889aff8.png)
【Paiza問題集】算術・代入演算メニュー/累乗2

# Paiza問題集
Pythonで回答

## 算術・代入演算メニュー/累乗2

### Step01 足し算
```Python:Step01
"""
足し算
https://paiza.jp/works/mondai/arithmetic_substitution_op/arithmetic_substitution_op__arithmetic_step1

問題
1,231 と 5,178 の和を出力してください
"""

print(1231 + 5178)
```

### Step02 引き算・掛け算
```Python:Step02
"""
引き算・掛け算
https://paiza.jp/works/mondai/arithmetic_substitution_op/arithmetic_substitution_op__arithmetic_step2

問題
AとBが与えられるので
AとBの差Dと積Pを半角スペース区切りで出力してください
"""

# 数字を受け取る
A, B = map(int, (input().split()))

# 差と積を出力する
print(f"{A - B} {A * B}")
```

### Step03 割り算
```Python:Step03
"""
割り算
https://paiza.jp/works/mondai/arithmetic_substitution_op/arithmetic_substitution_op__arithmetic_step3

問題
整数A=437,326 B=9,085 として
1. A を B で割った商
2. A を B で割った余り
を半角スペース区切りで出力してください
"""

A = 437326
B = 9085

print(F"{A // B} {A % B}")
```

### Step04 掛け算2
```Python:Step04
"""
掛け算2
https://paiza.jp/works/mondai/arithmetic_substitution_op/arithmetic_substitution_op__arithmetic_step4

問題
整数A,B,Cが与えられる
A*Aの計算結果X
B*B+C*Cの計算結果Y
を半角スペース区切りで表示してください
"""

# 数字を受け取る
A, B, C = map(int, input().split())

# 結果を表示する
print(f"{A * A} {B * B + C * C}")
```

### Step05 累乗
```Python:Step05
"""
累乗
https://paiza.jp/works/mondai/arithmetic_substitution_op/arithmetic_substitution_op__arithmetic_step5

問題
A=202 B=134 C=107
((A+B)*C)^2を計算してください
"""

A = 202
B = 134
C = 107

# 計算結果を表示する
print(((A + B)* C)**2)
```

### Final問題 累乗2
```Python:Final問題
"""
累乗2
https://paiza.jp/works/mondai/arithmetic_substitution_op/arithmetic_substitution_op__arithmetic_step6

問題
整数A,B,C,Dが与えられるので
((A+B)*2)^2 mod D
を計算してください
"""

# 数字を受け取る
A, B, C, D = map(int, input().split())

print(((A + B)* C)**2 % D)
```
paramsについて

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457284/fadbbe05-e705-72d2-c4f9-ac6de296fe75.png)
１：paramsとは
　クライアントからURLやフォームで送信された値（パラメータ）を取得するメソッドです。

２：パラメータの送り方
　ルートパラメータはURLの中にパラメータを入れ込む方法です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457284/ae87c355-bab5-3cc4-631f-71fa5e1bcd14.png)
ルーティングの中にあるURIPattern内の/:idといった部分がパラメータです。このようにURLの文字列内にコロンがついた部分は文字として扱われず、一種の変数として扱われます。

３：パラメータはコントローラーでparams[:id]といった形で受け取ります。
記述例として、
　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457284/07c2cf17-fcab-c43d-a513-2b708dcf7867.png)
※コードの意味：itemモデルのレコードのidを指定して、idに対応したレコードの情報をfindメソッドで取得します。取得したレコードの情報を@item（インスタンス変数）に代入していますという意味です。

４：パラメータはハッシュの要素を持っているため、シンボル記載で:idとなっています。

５：paramsはparams[:id]となっていて、配列の要素を持っています。

６：シークウェル・プロで確認すると一番左にカラムの一番最初にidがあります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457284/20b335bc-6417-2c7e-cdc6-cc6efd46c94d.png)
【ChatGPT無】長いChatをまとめよう


　どうも、カーブミラーです。

　今回は、Chatでのやり取りをまとめる方法です。
　まぁ、方法というか文章なんですけどね。


　Chatを続けていると、長くなり、
　　それをまとめる必要が出てきます。

　その方法を紹介します。
　確実かと問われると、
　　今のところはうまくいっているです。


　ではでは
***
1.Chatで質問を繰り返してきた場合
「**これまで質問してきたことをリストアップしてください。**」
「これまでの質問を以下にまとめます：」
***
2.Chatで処理を少しずつ指示していた場合
「**ここまでの指示をまとめてください。**」
「承知しました。以下に、要件をまとめた指示を示します。」
***
　とChatGPTは答えて、番号付きで、ズラズラ書いてくれます。

　処理の場合は、その指示を編集して、プロンプトにすることができます。

　その場合は
「**以下の指示で、[プログラミング言語名]のコード作成をお願いします。**」と書いて、編集した指示をペーストすれば、OKです。

　[プログラミング言語名]は、
　　各自で書き換えてくださいね。
　別に言語にこだわらなくてもOKですよ。

　ただし、確実に意図したコードになるかは、微妙です。
　そこは各自で、修整は必要でしょう。

　また、“コード作成”ではなく、
　　“メール作成”でもいけると思います。

　“[プログラミング言語名]のコード作成”の部分をカットして、“メール作成”とすれば、OKかな。

　ほかの指示にも活かせると思います。
　そこはお任せいたします（他力本願）

***
　ちなみに、私が書いた記事を読んでくれた方が、たくさんいらっしゃることに、驚いております。
　最初の記事は、2023/05/25にアップしたのに、今日（2023/05/30）の時点で、500回も見てもらって（ありがとう！）。

　ほかの記事もそれぞれ200回を越えていて、驚くばかりです。

　とにかく、ありがとうございます。
　これからも書いていきます、ネタある限り！
Javascript tutorial 　Array編

![download.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654025/29f1d6f3-72c5-99fe-d550-c16536a05ba9.png)



# JavaScript Arrayオブジェクトが持つmethod
下記のコードを実行すると、methodの一覧を確認することができます。

```javascript:index.js
    console.log(Array.prototype);
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654025/68b9b0c6-9fd1-cb84-d6ae-f7b8208e3e51.png)

この中から、いくつかピックアップして紹介します。

```javascript:index.js
    const shopping = ["bread", "milk", "cheese", "hummus", "noodles"];
    
    // Accessing and modifying array items
    console.log(shopping[0]);
    // Modify an item in an array
    shopping[0] = "tahini";
    
    // Note that an array inside an array
    const random = ["tree", 759, [0, 1, 2]];
    console.log(random[2][2]);
    
    // Finding the index of items in array
    const birds = ["Parrot", "Falcom", "Owl"];
    console.log(birds.indexOf("Owl"));
    console.log(birds.indexOf("Rabbit"));
    
    // Adding items
    const cities = ["Manchester", "Liverpool"];
    cities.push("Cardiff");
    console.log(cities);
    cities.push("Bradford", "Brighton");
    console.log(cities);
    const newLength = cities.push("Bristol");
    console.log(newLength);
    
    // To add an item to the start of the array
    cities.unshift("Edinburgh");
    console.log(cities);
    
    // Removing items
    // To remove the last item from the array
    cities.pop();
    console.log(cities);
    
    // To remove the first item from an array
    cities.shift();
    console.log(cities);
    
    // To remove an item you know the index
    const index = cities.indexOf("Liverpool");
    if (index !== -1) {
      cities.splice(index, 2);
    }
    console.log(cities);
    
    // Accessing every item
    for (const city of cities) {
      console.log(city);
    }
    
    function double(number) {
      return number * 2;
    }
    const numbers = [5, 2, 7, 6];
    const doubled = numbers.map(double);
    console.log(doubled);
    
    // To create a new array containing only the items in the original array that match some test
    function isLong(citi) {
      return citi.length > 8;
    }
    const longer = cities.filter(isLong);
    console.log(longer);
    
    // Converting between strings and arrays
    const data = "Manchester,London,Liverpool,Birmingham,Leeds,Carlisle";
    
    // Split it at each comma
    const newCities = data.split(",");
    console.log("Length:" + newCities.length, newCities);
    
    // The opposite way
    const oppositeCityes = newCities.join(",");
    console.log(oppositeCityes);
    
    // Another way of converting an array to a string
    const dogNames = ["Rocket", "Flash", "Bella", "Slugger"];
    console.log(dogNames.toString());
    
    // A valid array index
    console.log(Object.keys(cities));    
```

# 参考資料

https://developer.mozilla.org/en-US/docs/Learn/JavaScript/First_steps/Arrays
[python-oracledb入門](第3回) Thin ModeとThick Modeの違い


# 連載目次
[連載：python-oracledb入門　目次](https://qiita.com/nakaie/items/c373cff694cb23a8568c)


# はじめに 
[第1回](https://qiita.com/nakaie/items/851e7d5812da96a19ef8)でも簡単に触れていますが、本記事ではpython-oracledbで新たに追加されたThin Modeと、従来型(python-oracledbの前身のCx_Oracle)と同様のThick Modeの違いと使い分けについて解説します。


# Thin ModeとThick Modeの位置づけ
Thin ModeはCx_Oracleからpython-oracledbにリニューアルした際の最大の目玉機能で、Oracle JDBC Thin Driverのように、Oracle Databaseの接続のためにOracle Clientが不要になりました。この対応により、従来のようにOracle Istant/Thick Clientを用意せずともpython-oracledbのみで接続できるようになりました。ただし、Thick Modeと呼称していますが、従来通りOracle Clientを必要とする接続も可能です。インストール要件に関しては[第二回](https://qiita.com/nakaie/items/db41034b50ade06f306d)を参照してください。

# Thin ModeとThick Modeのコーディング上の違い
両モードともインポートするモジュール名も基本的なコーディングも同じです。python-oracledbは新機能とインポートするモジュール名を除けば前身のCx_Oracleとコーディングは同じです。どちらのドライバもPython Database API v2.0に準拠しています。ただし、これらの対応プラス、ドライバの変更のみの対応が可能なのはThin Modeになります。実質的にThin Modeがデフォルトのモードとなります。
Thick Modeを利用したい場合、コーディングの追加が必要です。この対応がないとOracle ClientがインストールされていてもThin Modeで動きます。
Thick Modeで稼働させたい場合、以下のように接続の処理よりも前にinit_oracle_client()を呼び出す必要があります。
```
import oracledb

oracledb.init_oracle_client()
# この後にDB接続やSQLの処理を記述
```
上記の記述はOracle Instant Clientがpython-oracledb実行アプリケーションが配置されているディレクトリに存在しているか、LinuxやMacの場合、LD_LIBRARY_PATHやDYLD_LIBRARY_PATHなどに記述されているディレクトリに存在していることが前提となります。この前提から外れる場合は、`oracledb.init_oracle_client(lib_dir=r"C:\instantclient_19_18")`といったように、lib_dirオプションにOracle Clientのインストールディレクトリを指定する必要があります。

# どのような場合にThick Modeを使用するか
Cx_Oracleベースのアプリケーションをpython-oracledb上で動かした場合はThin Modeで動きます。この仕様もあり、基本的にはThick Modeは使用しません。Thick Modeが必要なのは、Oracle Clientがないと利用できない機能を利用するためとなります。大きくは以下の3つの場面となります。

1. Oracle Client向けの環境変数を使用したい
特にCx_Oracleで作成されたアプリケーションを移行する場合、特定のOracle Client向けの環境変数を参照している場合もあるかと思われます。Thin ModeではTNS_ADMINとORA_SDTZ以外の環境変数はサポートされていません。ただ、Thin Modeでは上記以外の環境変数を使用する意味はあまりないので、あまり問題にならない可能性も考えられます。
2. TAF(Transparent Application Failover)
TAFは、tnsnames.oraに設定するだけで、RAC環境において接続先ノードダウン時に自動で生存ノードに接続を切らずに切り替え、設定次第ではSELECT処理を自動継続してくれる機能です。この機能はOracle Clientがないと利用できません。しかし、今ではTransparent Application Continuity(TAC)という、サーバー側の設定だけで利用でき、更新系SQLの自動再実行も可能な、より上位の機能が存在します。python-oracledbでもTACは利用可能なため、むしろThin ModeでTACを利用しましょう。
3. oraaccess.xml
oraaccess.xmlはクライアントサイドの結果セットキャッシュやフェッチサイズなど、本来はコーディングで行うOracle Databaseの一部の機能の設定をXMLファイルに定義することで、コーディングを伴わずにこれらの機能の利用を可能にするものです。このファイルを利用するためにはOracle Clientが必要です。現状、Thick Modeを使用する価値があるのはこのファイルを使用したい場合くらいですが、Thin Modeで類似機能を作りこむことも可能かと思われます。
ST7735(パラレル)をフラットケーブルで接続したい。1(ATM0177B5)(STM32G071)

目的
配線の簡素化の為にマイコンとの接続をフラットケーブル化したい


完成図

![o_cop553.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/f110ffea-0d69-1a86-4d76-3bdef69915d6.jpeg)

![o_cop554.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/869f6d4c-d50e-01a1-d33d-6491fb6648f6.jpeg)

![o_cop555.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/61c063f1-accb-0cbe-5e23-01d51edeb5f7.jpeg)

![o_cop556.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/643953a2-0ff8-7ffe-1cf5-54c6ee6ee299.jpeg)

![o_cop557.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/7fd283a7-2cb9-8ac8-44d2-43ba63ba0bef.jpeg)

![o_cop525.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/233e368c-e82d-8103-0b02-f8dd1e108109.jpeg)


![o_cop559.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/5aa9a20a-c778-f9ab-9770-c962d1d6d973.jpeg)
人に「センスない」って言っているやつが一番センスない

# はじめに

きっかけは、以下のツイートです。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">「配列のすべての要素が条件を満たすならtrueを返す」関数を定義するとき、空の配列を渡したらfalseを返すかtrueを返すかが、良いプログラマかどうかの一つの境目だ</p>&mdash; ふみ a.k.a.DJ Monad (@fumieval) <a href="https://twitter.com/fumieval/status/1663161595009314819?ref_src=twsrc%5Etfw">May 29, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


このリプライや引用リツイート欄では、Trueを返すべき、Falseかな、例外を返すべき、要件による、といった意見がありました。

建設的な議論ができるコミュニティは素晴らしいと思う反面、同じコミュニティに属するエンジニアに対して「センスがない」「プログラマを辞めてほしい」と言っている人がいて非常に残念です。

そのように敢えて煽り**他人へのリスペクトが欠如している人が一番センスがない**という話です。

# 元ネタと反応

「「配列のすべての要素が条件を満たすならtrueを返す」関数を定義するとき、空の配列を渡したらfalseを返すかtrueを返すか」(https://twitter.com/fumieval/status/1663161595009314819?s=20)

反応を以下のようにまとめてみました。
どれも根拠がしっかりあって良い意見ですね。

## True派の意見

* 論理積の[単位元](https://ja.wikipedia.org/wiki/%E5%8D%98%E4%BD%8D%E5%85%83)が真（True）であるから
* [Vacuous Truth](https://en.wikipedia.org/wiki/Vacuous_truth)から
    * [Vacuous Truth という概念を知っておくとプログラミングに（ちょっとだけ）役に立ちそう](https://summertree.hatenablog.com/entry/2022/04/16/132359)もわかりやすい
* 自分の知っているライブラリがTrueを返すから
* 再帰関数を考えるとTrueを返すのが妥当だから

## False派の意見

* 直感的にFalseを返してほしいから
* 実務的にはFalseを返すケースが考えられるから
* Trueを返すとバグを誘発するケースを経験したから

## 例外派の意見

* 仕様として読み取れない（未定義）だから

## 要件による派の意見

* 要件によって関数名の名付け方も変わり、True/Falseのどちらも返しうるから

# 「センスない」と言っている人が一番センスない

タイトルのとおりです。

理由は次の通りで、

* プログラミング言語は全て数学や論理学で成り立っていると思い込んでいる
  * そもそも論理学を理解していない
* 自身の世界と知識を前提として話を進めている
* （これが最も重要ですが）自身が優秀であると勘違いし人を煽り、**リスペクトが欠如**している

があげられます。

とりわけ人に「センスがない」と言っている人は、そもそも論理学をしっかり理解できていないのです！！

## 「センスがない」と言っている人自身がそれらの学問を理解していない

特に「センスがない」と言っている方は、そもそもそれらの学問を理解していない可能性があります。

これは、

* 自然言語で表現されたものに対して、Vacuous truth の理論を（勝手に）持ち込んでいる
* そもそも自然言語と論理学の間にあるギャップを埋めることができていない
* （そもそもギャップがあることを認識できていない可能性もある）

点にあります。

命題に何らかの条件（例えば「論理学において」）があれば、「True以外ありえない」は通りそうですが、
そのような条件はありません。

また、命題をPとすると「True以外ありえない（Trueだ）」と主張する方々を論理式にしてみると、

All.x(P(x)) -> True

ですが、彼らの主張は「この時P(x)というのは All.x(A(x) -> B(x)) の形であり、A(x)には空配列を取りうるからVacuous truthによってTrueを返すべき」というものです。

しかし、命題にはP(x)に対する前提が隠蔽されており、この「P(x)なものが存在する」という隠れた前提（これを**存在措定**と言います）を勝手に補って読んでいるのです。

例えば、「True以外ありえない」と主張する人々は「論理学において～という状況がある」という存在措定を補い、
「Falseかな」と主張する人々は「〇〇業務において～という状況がある」という存在措定を補っています。

数学や論理学を背景とした主張をしておいて、これを無視することはナンセンスでしょう。
つまり**前提を整理せず**他の主張であるFalse、例外、要件によるを**否定することはできません**。

今回は論理学を背景に主張する方の中に他人の意見を否定する方がいたためこの記事を書いていますが、人間的に見ても「前提を共有せずに相手の意見を否定することはできない」という感覚は納得いただけるはずです。

リスペクトのない方々におかれましては、**存在措定を明示せずに論証を行うこと及びその論証は妥当ではない**ことを肝に銘じて頂きたいと思います。

# さいごに

**「あまり強い言葉を遣うなよ…弱く見えるぞ」**

# P.S

多くの方々にご覧いただき、とても有り難く思います。

さて、すでに何人かはお気づきかと思いますが、
このようなタイトルを付けている私も漏れなく「センスのない」人間です。

ほんとうにありがとうございました。
STM32G071でKnight Rider(ナイトライダー)で遊ぶ(その3)


x 過去ログを見よ

A0からA5まで


![o_cop552.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/a7bdaddc-2a97-49f2-0f6e-6b285d7c5a10.jpeg)



```c++



//GPIO_Knight_Rider3_test_767_1


void GPIO_A0(int s)
{

  digitalWrite(A0,s);

} //GPIO_A0

void GPIO_A1(int s)
{

  digitalWrite(A1,s);

} //GPIO_A1


void GPIO_A2(int s)
{

  digitalWrite(A2,s);

} //GPIO_A2


void GPIO_A3(int s)
{

  digitalWrite(A3,s);

} //GPIO_A3


void GPIO_A4(int s)
{

  digitalWrite(A4,s);

} //GPIO_A4


void GPIO_A5(int s)
{

  digitalWrite(A5,s);

} //GPIO_A5


void GPIO_A0_A5_cls()
{

  digitalWrite(A0,0);
  digitalWrite(A1,0);
  digitalWrite(A2,0);

  digitalWrite(A3,0);
  digitalWrite(A4,0);
  digitalWrite(A5,0);

} //GPIO_D8_D13_cls()

void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(PB7, OUTPUT);
  pinMode(A0, OUTPUT);
  pinMode(A1, OUTPUT);
  pinMode(A2, OUTPUT);
  pinMode(A3, OUTPUT);
  pinMode(A4, OUTPUT);
  pinMode(A5, OUTPUT);

} //setup


void loop() {

  digitalWrite(PB7, HIGH);
  
  GPIO_A0_A5_cls();
  GPIO_A0(1);

  delay(1000);

  digitalWrite(PB7, LOW);
  
  GPIO_A0_A5_cls();
  GPIO_A1(1);

  delay(1000);

  digitalWrite(PB7, HIGH);
  
  GPIO_A0_A5_cls();
  GPIO_A2(1);

  delay(1000);

  digitalWrite(PB7, LOW);
  
  GPIO_A0_A5_cls();
  GPIO_A3(1);

  delay(1000);

  digitalWrite(PB7, HIGH);
  
  GPIO_A0_A5_cls();
  GPIO_A4(1);

  delay(1000);

  digitalWrite(PB7, LOW);
  
  GPIO_A0_A5_cls();
  GPIO_A5(1);

  delay(1000);

} //loop




```
Kompira EnterpriseからSlackにアラート通知を投稿する

Kompira Enterpriseを用いて運用作業の自動化を行う際、障害発生や処理終了などの通知は mailto関数を用いて電子メールで送ることが一般的ですが、API を持ったメッセージアプリケーションに送信することも可能です。今回は Slack に通知を行ってみましょう。

手順に関しては、他の多くのツールからのSlack連携と同様に、Slack APIを用います。また各種権限が制限されている場合には管理者と相談して進めてください。

# Slack側の設定
お使いになっている Slackのアカウントにメッセージ受信用のチャネルを作成します。今回は #kompira を作ります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94326/86c66aa3-e60c-ff4f-9db8-b271542cff97.png)

次に Slack に外部からメッセージを送信できるように、”Incoming WebHooks” の設定をします。
「[Slack API](https://api.slack.com/apps "Slack API")」にアクセスし、”Creare New App” をクリックします。

“Create an app” が表示されますので、”From scratch” を選択します。

その後、
”App Name” に “Kompira2Slack” 、
”Pick a workspace to develop your app in:” にご利用の Slack のチームを指定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94326/88a9d2fb-4485-4841-c16f-bf0b51acb4a0.png)

“Add features and functionality” が表示されますので、”Incomming Webhooks” を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94326/0a4790fb-0c6d-1f4a-c5a7-ad0e661e6cb5.png)

“Activate Incoming Webhooks” を以下のように有効化し、その後 “Add New Webhook to Workspace” をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94326/ccbb1111-f7fc-d568-04e5-930f97dba67e.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94326/b480d6b2-c674-0bf5-1afd-073c5cb35887.png)

すると、以下のような画面に切り替わりますので、投稿したいチャンネルを選択し、”許可する” を押します。

今回は、”#kompira” を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94326/de5fa907-f64c-a21e-4269-df678d59f8dd.png)

画面が切り替わり、”Webhook URL” が表示されます。こちらの内容をコピーしておいてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94326/74956c83-d286-72e7-0f37-92e2c573f3c6.png)

# ジョブフローの作成

続いて、Kompira Enterprise 上でジョブフロー「Slackへ通知」を次のように作成します。

```
| message = "This is a sample line of text. Does it work?" |
# Webhook URL
| url = "https://hooks.slack.com/services/xxxx/xxxxx/xxxxxxxx" | 
urlopen(
    url=url,
    data={"text": message},
    http_method="POST",
    encode="json",
    quiet=true
) ->
print("Slack へ通知しました。")
```

ここでパラメータ “url” には、Slack のセットアップ画面で表示された “Webhooks URL” を記載してください。

このジョブフローを実行すると、Slackに次のように投稿されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94326/aaf7da96-d31a-eb20-f7a5-e3c0e5e8b190.png)


このように、Kompira Enterprise から Slack のチャンネルへの投稿は容易に可能です。
また、これを他のジョブフローから利用する場合には、例えば以下のように呼び出します。

```
[./Slackへ通知: message="緊急事態： 至急対応してください"]
```
単純なメッセージ送信以外にもリンク URL の送信やアイコン・色の変更なども行えます。リッチなメッセージ作成の詳細は Slack API の「[Messaging for Slack apps](https://api.slack.com/messaging)」をご参照ください。

# Kompira Enterpriseの製品情報
https://www.kompira.jp/
サーバーやネットワーク機器などの運用を自動化するための連携処理基盤ソフトウェアです。
運用手順書の操作作業の自動化、監視ツールやメールなどをトリガーにした保守作業の自動実行など、独自のKompiraジョブフロー言語を用いたスクリプトを用意する事で、個々の機器やワークフローにきめ細かく対応する事が可能です。
Windows,WSL環境でのpbpaste代替決定版

Windows上のWSLで困るのがクリップボードとのやりとり。クリップボードに送る方はclip.exeに渡せばいいけど、とりだしが大変。

以下、WSL2からWindows上のクリップボードからテキストを取り出す時の決定版。

これ
```/usr/lob
powershell.exe -command "[Console]::OutputEncoding = [System.Text.Encoding]::GetEncoding('utf-8');Get-Clipboard"
```

めちゃくちゃ長い。馬鹿っぽいけどこれにエイリアスでもはるしかない。

別解として以下のコマンドでもうまくいくケースはある。

```
powershell.exe -command "Get-Clipboard"
```

ただし、これをスクリプト経由で呼び出そうとすると、powershell自体のコンソールがデフォルトのSJISで吐き出そうとして実行結果を受け取る際にUTF8ベースの環境で化ける。

以下irbの中でpowershell経由でクリップボードを呼び出すサンプル。クリップボードには🐏の絵文字が入っている。

```
irb(main):005:0> `powershell.exe -command "Get-Clipboard"`
=> "??\r\n"
irb(main):006:0> `powershell.exe -command "[Console]::OutputEncoding = [System.Text.Encoding]::GetEncoding('utf-8');Get
Clipboard"`
=> "🐏\r\n"
```
エンコード指定をしないとSJISベースで吐き出そうとするので化ける。

### 上記方式の特徴

- PowerShell5系でも7系でも機能する
- WSL上からでも直接使える
- WSL上のrubyでもWindows上のjrubyからも外部コマンド呼び出しで機能する
- 何もインストールしないでいい

クリップボードアクセスの際にはPythonからWin32APIを呼び出してる例もあるんだけど、その方式だとWSLからは使えない。
Amazon Linux 2023 にcertbotを入れる(2023年5月時点)

# はじめに
Amazon Linux 2023 ではEPELがサポートされていません。
Amazon Linux 2 でEPELからCertbotを入れていた場合、移行時の問題になります。
現時点では、Cerbotの公式ドキュメントに記載されている[pipを利用した導入](https://certbot.eff.org/instructions?ws=nginx&os=pip)を行うことになります。

※説明例は、nginxでの利用の場合です。

# 手順

```shell
# 必要パッケージインストール
dnf install python3 augeas-libs cronie

# venv作成・pipからcertbotをインストール
python3 -m venv /opt/certbot/
/opt/certbot/bin/pip install --upgrade pip
/opt/certbot/bin/pip install certbot certbot-nginx
ln -s /opt/certbot/bin/certbot /usr/bin/certbot

# 証明書取得
certbot certonly --nginx -d example.com --dry-run
certbot certonly --nginx -d example.com

# 自動更新の登録
crontab -e
```

```text:crontabで追記する内容
0 0,12 * * * root /opt/certbot/bin/python -c 'import random; import time; time.sleep(random.random() * 3600)' && sudo certbot renew -q
```

# さいごに
cronも標準で入ってなくておどろき。
RubyでAtCoder ABC253(A, B, C)を解いてみた

# はじめに
Webエンジニアを目指して、RubyやRailsをいじってます。
今回は、RubyでAtCoder ABC253のA, B, Cを解きました。備忘録として解き方をまとめていきたいと思います。

# A - Median?
https://atcoder.jp/contests/abc253/tasks/abc253_a
```ruby:a-253.rb
a = gets.split
puts a[1] == a.sort[1] ? "Yes" : "No"
```

# B - Distance Between Tokens
https://atcoder.jp/contests/abc253/tasks/abc253_b
```ruby:b-253.rb
h, _ = gets.split

x = y = 0
h.to_i.times do |i|
  gets.chomp.chars.each_with_index do |char, j|
    if char == "o"
      y = i - y
      x = j - x
    end
  end
end
puts x.abs + y
```

# C - Max - Min Query
https://atcoder.jp/contests/abc253/tasks/abc253_c
```ruby:c-253.rb
q = gets.to_i

hash = Hash.new(0)
max = -1
min = Float::INFINITY
q.times do
  t, x, c = gets.split.map(&:to_i)
  case t
  when 1
    hash[x] += 1
    max = [max, x].max
    min = [min, x].min
  when 2
    hash[x] = [0, hash[x] - c].max
    if hash[x] == 0
      hash.delete(x)
      if hash.empty?
        max = -1
        min = Float::INFINITY
      else
        max = hash.keys.max if max == x
        min = hash.keys.min if min == x
      end
    end
  when 3
    puts max - min if max != -1
  end
end
```
## 解説
集合に含まれる要素xの個数を連想配列hashに保持させます。
1) t = 1のとき
連想配列のxの値をインクリメントします。また、集合に含まれる最大値と最小値を更新します。
2) t = 2のとき
集合に含まれるxの個数がcよりも大きければ、xの値からcを引き、c以下であれば0とします。このとき、要素数が0なら連想配列からxを削除し、最大値と最小値を更新します。
3) t = 3のとき
連想配列が空でなければ、最大値から最小値を引いた値を出力します。

https://qiita.com/shoya15/items/50fd17e37d7c64f2b166
Kompira Enterpriseを使って、簡単な死活監視を行う。

本記事は「運用自動化プラットフォーム Kompira Enterprise」で、簡単なサーバーの死活監視を行うジョブフロー（スクリプト）を作成していきます。

# 「ジョブフロー」とは
Kompira Enterpriseでサーバー機やネットワーク機器の操作を行う手順を記載したプログラムです。いわゆる”バッチ処理”をイメージしていただいても良いかと思います。
Kompira Enterpriseでは、専用のジョブフロー言語を用いてジョブフローを記載していきます。

# 「ジョブフロー」の作成
ここでは、指定したアドレスに対して定期的にPing送信を行い、応答が無い場合にはメールで通知する想定です。ジョブフローでは実行したいコマンドを[ ]で囲んで記載します。コマンドが続く場合には矢印でつなげていきます。 

一番シンプルなジョブフローは次のようになります。
```
| target = "192.168.1.1" |

["ping -c1 $target] ->
print("終了します")
```
| | で挟んだ部分はパラメータで、実行時に動的に指定することができます。
= の右辺 “192.168.1.1” は初期値となります。

また、ping には “-c1” オプションをつけています。繰り返し回数を指定しないと、pingコマンドが Ctrl + C などで中断するまで継続的に実行されます。ジョブフローでは投入したコマンドの終了を待って次の処理に進みますので、ブレイクを入れないと止まらないコマンドは投入しないようにします。

続いて、pingの応答が正常の場合は"OK"、異常の場合に"NG"と表示するように条件文を追加します。
```
| target = "192.168.1.1" |

["ping -c1 $target] =>
{ if $STATUS == 0 |
  then: print("OK")
  else: print("NG")
}
```
$STATUS 変数は直前の処理の戻り値 (終了ステータス) で、この場合には ping コマンドの実行結果となります。
if 文の直前の矢印は “->” ではなくて、”=>” になることに注意してください。
”->” では処理エラーが発生した場合にジョブフローが中断されますので、ping の応答がなかった場合には if 文が実行される前にジョブフローが異常終了します。

これは通常のジョブフローでは -> で処理をつなぐだけで、さまざまな条件判断文を追加しなくても、コマンドのエラー時には処理が止まって被害が拡大しないような仕様になっているためです。

最後に pingの応答がなかった場合に、指定のメールアドレスに通知メールを送っています。
メールを送るためには mailto() 関数を利用します。ここでは簡略化のため、固定のアドレスに対して固定のメッセージを送信しています。それぞれのパラメータで送信元アドレス、送信先アドレス、表題、本文を指定します。
```
mailto(
    to="info@kompira.jp",
    from="alert@kompira.jp",
    subject="server is DEAD",
    body="サーバーの反応がありません。至急対応してください。"
)
```

これを上記のジョブフローに組み込むと以下のようになります。
```
| target = "192.168.1.1" |
["ping -c1 $target"] =>
{ if $STATUS == 0 |
  then:
    print("OK")
  else:
    print("NG") -> 
    mailto(
        to="info@kompira.jp", 
        from="alert@kompira.jp", 
        subject="server is DEAD", 
        body="サーバーの反応がありません。至急対応してください。"
    )
}
```
これを無限に繰り返して常駐プロセスのように動かします。while文などを用います。ping送信のタイミングとして60秒間隔とするため、sleep(60) を追加しています。

```
| target = "192.168.1.1" |
{ while(1) | 
  ["ping -c1 $target"] =>
  { if $STATUS == 0 |
    then:
      print("OK")
    else:
      print("NG") -> 
      mailto(
        to="info@kompira.jp", 
        from="alert@kompira.jp", 
        subject="server is DEAD", 
        body="サーバーの反応がありません。至急対応してください。"
      )
  } 
  -> sleep(60)
}
```

本稿では、簡単なジョブフローの作成例として、pingコマンドによるサーバー死活監視のジョブフローを作りました。while文を入れる前のジョブフローでしたら、Kompira Enterprise のスケジューラを利用してこのジョブフローを定期的に実行することで、サーバーがダウンした際に指定のアドレスに通知することができます。

while文を追加した後のものは、サーバー停止が継続する場合、60秒ごとにメールが送信されます。これを抑制したい場合には、送信した後はジョブフロー自体を停止する、送信後、一定回数は継続しても送信しないなどのロジックを追加するなどの改良が考えられます。

上記の例では、メールの送信先やメッセージの内容は固定ですが、これらをジョブフローとは切り離して管理したい場合には、環境変数オブジェクトやメールテンプレートオブジェクトなどを利用することができます。
また通知手段をメール以外にurlopen関数を使ってSlackなどのメッセンジャーアプリのAPIで連携することも可能です。


# Kompira Enterpriseの製品情報
https://www.kompira.jp/
サーバーやネットワーク機器などの運用を自動化するための連携処理基盤ソフトウェアです。
運用手順書の操作作業の自動化、監視ツールやメールなどをトリガーにした保守作業の自動実行など、独自のKompiraジョブフロー言語を用いたスクリプトを用意する事で、個々の機器やワークフローにきめ細かく対応する事が可能です。
Windows(AMD)+Podmanでarm用イメージを実行する話

```CMD
podman machine set --rootful
podman machine start
podman run --rm --privileged docker.io/multiarch/qemu-user-static --reset -p y
podman run -it --arch arm64 --rm <起動したいイメージ>
```
`qemu-user-static`はマルチアーテクチャをなんとかするためのものらしい。

ただ、これやったら元のイメージが全部消えたのはショックでした。。。

@tnk4on 様にコメントを頂きました。ありがとうございます！
元の方にはイメージ等が残っているそうです（明日試してみよう。。）

また、実行時に対象アーキテクチャの指定のオプションが必要とのことで`--arch arm64`を追記させていただきました！
ターミナルで動くライフゲームを作ってみた

# ライフゲームをターミナルで動かしてみた
    
    1世代
    1 1 1 0 1
    1 0 1 1 0
    0 1 0 1 1
    0 0 1 0 0
    0 0 0 0 1
    
    2世代
    1 1 0 0 0
    0 0 0 0 0
    0 0 0 1 1
    0 0 1 0 1
    0 0 0 0 0
    
    3世代
    0 0 0 0 0
    0 0 0 0 0
    0 0 0 0 1
    0 0 0 0 1
    0 0 0 0 0


# ライフゲームとは
ライフゲーム(Conway's Game of Life[1]) は1970年にイギリスの数学者ジョン・ホートン・コンウェイ (John Horton Conway) が考案した生命の誕生、進化、淘汰などのプロセスを簡易的なモデルで再現したシミュレーションゲームである。

ライフゲームでは初期状態のみでその後の状態が決定されます。碁盤のような格子があり、一つの格子はセル（細胞）と呼ばれる。各セルには8つの近傍のセルがある (ムーア近傍) 。各セルには「生」と「死」の2つの状態があり、あるセルの次のステップ（世代）の状態は周囲の8つのセルの今の世代における状態により決定される。

セルの生死は次のルールに従う。

誕生
死んでいるセルに隣接する生きたセルがちょうど3つあれば、次の世代が誕生する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3092001/c36532b0-9f47-45de-b29e-4c84edface14.png)


生存
生きているセルに隣接する生きたセルが2つか3つならば、次の世代でも生存する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3092001/7750895c-ac92-4afa-d969-5cf7d8f0123a.png)


過疎
生きているセルに隣接する生きたセルが1つ以下ならば、過疎により死滅する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3092001/48742f70-ee58-f508-a5cb-0a784ff5c98d.png)

過密
生きているセルに隣接する生きたセルが4つ以上ならば、過密により死滅する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3092001/428b4b22-b9e8-7821-67df-dbd0cd29c8b8.png)


[wikipediaより引用](https://ja.wikipedia.org/wiki/%E3%83%A9%E3%82%A4%E3%83%95%E3%82%B2%E3%83%BC%E3%83%A0)




## 実行方法

このコードを用いる。

https://github.com/mimic-asy/lifegame/blob/main/README.md

    $ git clone git@github.com:mimic-asy/lifegame.git
    $ mkdir build
    $ cmake ..
    $ make
    S lifegame_test

上記の方法で実行環境が整う。

## どのように遊ぶか

:one:　盤面の大きさを決める　（x = 列 y = 行）サイズを決めると盤面が出力される。

    盤面の大きさを決めてください x : 3
    盤面の大きさを決めてください y : 3
     0  1  2  3 
     1  0  0  0 
     2  0  0  0 
     3  0  0  0  
    




:two: 生存にするところを決める　座標で指定する（y,x）-1で終了

     開始点のX座標を入力してください(終了: -1) x: 1 
     開始点のY座標を入力してください(終了: -1) y: 1
     開始点のX座標を入力してください(終了: -1) x: 1
     開始点のY座標を入力してください(終了: -1) y: 3
     開始点のX座標を入力してください(終了: -1) x: 2
     開始点のY座標を入力してください(終了: -1) y: 3
     開始点のX座標を入力してください(終了: -1) x: 3 
     開始点のY座標を入力してください(終了: -1) y: 1
     開始点のX座標を入力してください(終了: -1) x: 3
     開始点のY座標を入力してください(終了: -1) y: 2
     開始点のX座標を入力してください(終了: -1) x: 3
     開始点のY座標を入力してください(終了: -1) y: 3
       
     0世代
     1 0 1
     0 0 1
     1 1 1


:three: 何世代まで進めるか決める
    
    何世代まで進めるか決めてください :　3
:four: 実行結果が出力される

    1世代
    0 1 0
    1 0 0
    0 0 1
    
    2世代
    0 0 0
    0 1 0
    0 0 0
    
    3世代
    0 0 0
    0 0 0
    0 0 0


## つくってみて思ったこと
最初の出力の生存の座標の入力が面倒なので、フロントエンドとつなげたい
フロントエンドはやったことがないのでいろいろ試そうと思う
おすすめ教えてください:pray:
Mulesoft AWS S3 Connectorを使ってみた

# はじめに
みんなさん こんにちは。

Mulesoftの魅力点としては、多種多様なコネクターが手に入り、さまざまなシステムへの接続が容易な点にあります。

この記事では、MulesoftのAWS S3コネクタを活用し、S3バケットからファイル内容を取得する方法と手順について、紹介していきます。

# 必要な情報

**AWS関連**
- Region Endpoint
- Access Key
- Secret Key
- Bucket name
- Object key (ファイル名)

# AWS S3モジュールの追加
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343120/ee24adbf-7b71-9955-5e14-df5234645d83.png)
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343120/f87374dd-8b42-2a35-a8a7-b09061810b70.png)
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343120/452de675-3d49-4a09-cce9-5473b7bfe4f6.png)
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343120/34c3488d-23aa-93d9-5a50-8a9039f7805a.png)
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343120/ba529c55-48c9-6174-13a1-114654acc5ea.png)


# 接続手順
## Flowイメージ
![9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343120/f969bd82-6ae5-a384-4fba-8467136c093e.png)

## Scheduler
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343120/c67b66b6-ef8e-2733-4cd4-59c7e3674438.png)


## 開始ログ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343120/4f93ac01-f979-4d3c-c6b8-32fe8585a4f8.png)

## AWS コネクター

### Configuration

![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343120/a9205663-72a1-52b2-c089-9254947bfbbd.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343120/eab28cfd-a525-f27f-c76f-670d2f0e12a0.png)

### コネクター
![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343120/9dc2f417-c1b2-ed42-2ed2-2d11abc86fd3.png)

## 終了ログ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343120/8dd7920e-61ac-9afb-8bec-c1d95fed2353.png)

## 結果確認
![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343120/85ba5fdb-2faa-960c-0653-2e5730b7f039.png)

## デモリンク
[Github: aws-demo](https://github.com/qiguang-fang/mule-demo/tree/master/aws-demo)

# 終わりに

最後までお読みいただき、本当にありがとうございました。
Mulesoftに関する、すこし理解できましたら幸いです。気になる点があったらお知らせください。
ブラウザで動かせる「Linux」の「Ubuntu 22.04」のデスクトップ版（Xfce）のDockerイメージ「docker-ubuntu-desktop」を作りました

# Ubuntu 22.04がブラウザで動く様子
![screenshot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34365/63fb770f-50ab-cf8c-7649-8def6c90061d.png)
本家Ubuntu DesktopのUIと違い、Xfceデスクトップ環境を利用しています。

<br>

・ソースコードは、以下GitHubリポジトリで公開しております。
https://github.com/takahashi-akari/docker-ubuntu-desktop

<br>

・Dockerイメージは、DockerHubで公開しております。
https://hub.docker.com/r/akarita/docker-ubuntu-desktop

# 環境
・ OS: macOS(M1)
・ メモリ: 16GB
・ その他: Dockerがインストールされていること

# 概要
macOSのM1チップがメインの開発環境なので、すぐにLinuxOS（x86_64）環境が立ち上がって、触れることを目的として、ブラウザで、Ubuntu22.04が操作できるように環境を整えました。

# 利用方法

以下のコマンドを実行します。

```bash
$ docker run -it --platform=linux/amd64 -p 6080:6080 akarita/docker-ubuntu-desktop
```

以下のURLにアクセスします。

SSLなし： http://localhost:6080/vnc.html

SSLあり： https://localhost:6080/vnc.html (証明書のエラーが出ます)

# Dockerfileに関して

```dockerfile:Dockerfile
FROM --platform=linux/amd64 ubuntu:22.04

ENV DEBIAN_FRONTEND=noninteractive
RUN apt update -y && apt install --no-install-recommends -y xfce4 xfce4-goodies tigervnc-standalone-server novnc websockify sudo xterm init systemd snapd vim net-tools curl wget git tzdata
RUN apt update -y && apt install -y dbus-x11 x11-utils x11-xserver-utils x11-apps
RUN apt install software-properties-common -y
RUN add-apt-repository ppa:mozillateam/ppa -y
RUN echo 'Package: *' >> /etc/apt/preferences.d/mozilla-firefox
RUN echo 'Pin: release o=LP-PPA-mozillateam' >> /etc/apt/preferences.d/mozilla-firefox
RUN echo 'Pin-Priority: 1001' >> /etc/apt/preferences.d/mozilla-firefox
RUN echo 'Unattended-Upgrade::Allowed-Origins:: "LP-PPA-mozillateam:jammy";' | tee /etc/apt/apt.conf.d/51unattended-upgrades-firefox
RUN apt update -y && apt install -y firefox
RUN apt update -y && apt install -y xubuntu-icon-theme
RUN touch /root/.Xauthority
EXPOSE 5901
EXPOSE 6080
CMD bash -c "vncserver -localhost no -SecurityTypes None -geometry 1024x768 --I-KNOW-THIS-IS-INSECURE && openssl req -new -subj "/C=JP" -x509 -days 365 -nodes -out self.pem -keyout self.pem && websockify -D --web=/usr/share/novnc/ --cert=self.pem 6080 localhost:5901 && tail -f /dev/null"
```

一行目の「--platform=linux/amd64」で、本来arm64アーキテクチャのOSで、amd64(x86_64）のLinuxOSを扱えるようになります。
<br>
TigerVNC（ https://tigervnc.org/ ）を利用してVNCサーバーを構築して、
noVNC(websockify: https://kanaka.github.io/noVNC/ )を利用して、ブラウザで表示できるようにします。（SSLにも対応させています）
<br>
FireFoxも最低限のデスクトップアプリケーションとして入れてあります。
<br>
その他、arm64v8、riscv64アーキテクチャにも対応予定です。
<br>
以上です。
【個人開発】GPTがLINEスタンプも送るよ　LINE BOT x GPT x Google Cloud Vision

# LINEのスタンプが送りたい

LINE messenger API　x GPT には結構可能性を感じていて、過去二つほどリリースしました

学習アプリ

https://qiita.com/bizposan/items/60f4b627b8afd71974b6

マルチキャラクターchat

https://qiita.com/bizposan/items/326b3ec9f4788d645544

LINE BOT とGPTを組み合わせていて、**「あ〜ここでGPTスタンプ送ってきたら面白いのなぁ」**　と思いました。思ったらすぐTry & BuildできるのがGPT時代の良いところです。

# スタンプ送ってみた
一部スタンプの著作権的関係の問題があるかもしれないので、あくまで個人の検証用です。

LINE messenger API では、パッケージIDと、スタンプIDを指定することで、Stiker（スタンプ）をPUSHメッセージとして送信することができます。

https://developers.line.biz/ja/docs/messaging-api/sticker-list/

MessageにパッケージIDとStickerIDを設定するだけです。

```/ スタンプメッセージを作成
  var message = {
    type: 'sticker',
    packageId: packageId,
    stickerId: stickerId
  };
```
問題は、このIDをどこから取ってくるか、です。
ランダムに設定するのが手っ取り早いですが、それでは文脈に沿ったスタンプになりません。

方法は二つ考えました。

+ Stamp に、事前的に感情のキーワードを人力で設定する
+ スタンプの解析自体をAIに行ってもらう

後者について調査するとGoogle Cloud Vision というサービスが一番良さそうです。

# Google Cloud Vision

画像を送ると、その画像を解析して以下のような情報を提供してくれます

+ 画像内のテキストを検出する
+ ファイル内のテキストを検出する（PDF / TIFF）
+ 画像内の手書き文字を検出する
+ 顔の検出
+ 画像にラベルを付与する

https://cloud.google.com/vision?hl=ja
 
この中の「画像にラベルを付与」するを使ってみました。
以下のGoigleのサイトにある例では、風景を表現するラベルを付与してくれています。なかなか面白いですね。

<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3356879/c2324516-85fd-ec75-8420-84374b4a99c6.png">

これをLINEのスタンプで実施しますと、例えば、パッケージID:446 スタンプID:1988の彼は、以下のようなラベルが付与されました
注：どうも日本語では上手くいかなかったので取り急ぎ英語のラベルです。

<img width="100" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3356879/e0e7d719-f159-f29b-c7ff-544cf9b46d39.png">
Facialexpression,Vertebrate,Smile,Cartoon,Organism,Mammal,Happy,Gesture,Art,Font,Finger,Illustration,Drawing,Fictional character,Graphics,Pleased,Line art,Child art,Logo,Rectangle

これをスプレッドシートにパッケージIDとスタンプIDとともに保存します。

# GPTとの連携

ここでGPT登場です。モデルは3.5Turboで、以下のようにPrompt打ちます。

```  var payload = {
    "prompt": `ユーザーのメッセージ: "${userMessage}"\nスプレッドシートのデータ:
\n${spreadsheetData}\n\nこの日本語のメッセージを英語で解釈してください。
そしてスプレッドシートの中のキーワードを一つだけランダムに利用してユーザーへの返信を生成してください。
その際に利用したキーワードが対応するパッケージIDとスタンプIDを必ず記載してください　
```

この後返ってきたレスポンスから正規表現で、パッケージIDとスタンプIDを取り出し、LINE messanger APに渡すという動きです。

結果こんな感じになります。
プロンプトをもっと上手く書けば、もっともっといい感じで返信してくれる気がします。


<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3356879/c35086eb-ef63-368c-8835-4fa3c50feb6c.png">


# 課題とまとめ
GPTの使い方によっては、スタンプさえ使いこなすBOTができそうです！
いろいろ課題ありますので、引き続き検証していきます。

課題
+ Google Cloud Vision API、LINE PUSHメッセージも一定量からは有償プランになってしまいます。
+ スタンプを画像解析する行為が"あり"なのか要調査です。

環境
* GAS
* Google Cloud Vision API
* LINE messenger API
演習問題100問パックつづき

前回は100問パックの50問まで終わっていたので、51問目からやっていく。
タプル型、集合型、辞書型が出題されたが、辞書型が特に難しく感じた。

前回同様有料なので問題は載せられないが、colabのやり方にはけっこう慣れてきた感ある。

今回は80問まで終了したので、残り20問集中して完走しようと思う。
そしたら2周目が待ってるZE🌟
form チェックボックス

```html
<div class="form__checkbox">
<!-- labelで囲んだ範囲を押すとボタンが反応する -->
  <label>
    <input type="checkbox">
    <span>個人情報保護方針に同意する</span>
  </label>
</div>
```

```scss
.form__checkbox {
  margin-top: 40px;
  text-align: center;
  font-weight: bold;

  [type="checkbox"] {
    // 自由度の低いデフォルトのボタンを見えなくする
    display: none;
  }

  // 擬似要素でチェックボックスを作成する
  span {
    position:  relative;
    font-weight: bold;
    margin-left: 41px;

    // 箱部分
    &::after {
      position: absolute;
      top: 0;
      left: -41px;;
      content: "";
      border: 1px solid #707070;
      width: 20px;
      height: 20px;
    }

    // チェック部分
    // 選択されていない時は見えなくする
    &::before {
      position: absolute;
      top: 0;
      left: -35px;;
      content: "";
      border: 2px solid #3B69FF;
      width: 8px;
      height: 15px;
      border-top: none;
      border-left: none;
      transform: rotate(45deg);
      display: none;
    }
  }

  // チェックされているチェックボックスの次のspan要素
  [type="checkbox"]:checked + span {
    &::before {
      display: block;
    }
  }
}

```