OmniAICreator/Qiita-1.07M huggingface dataset:
【SA試験】R4〜H21午後Ⅱテーマまとめ

自分用のまとめです。
令和6年春期試験から組み込み分野は除外されることになったのと、今回受験で選択するつもりがないので省略しています。

https://www.jitec.ipa.go.jp/1_00topic/topic_20221220.html

カッコ内は個人的な分類です。

## 令和4年春期
- 問1 概念実証(PoC)を活用した情報システム開発について【新規システム構築】
- 問2 業務のデジタル化について【新規システム構築】

## 令和3年春期
- 問1 アジャイル開発における要件定義の進め方について【新規システム構築】
- 問2 情報システムの機能追加における業務要件の分析と設計について【既存システム変更】

## 令和1年秋期
- 問1 ユーザビリティを重視したユーザインタフェースの設計について【新規システム構築】
- 問2 システム適格性テストの計画について【新規システム構築】

## 平成30年秋期
- 問1 業務からのニーズに応えるためのデータを活用した情報の提供について【既存システム変更】
- 問2 業務ソフトウェアパッケージの導入について【新規システム構築】

## 平成29年秋期
- 問1 非機能要件を定義するプロセスについて【新規システム構築】
- 問2 柔軟性を持たせた機能の設計について【新規システム構築】

## 平成28年秋期
- 問1 業務要件の優先順位付けについて【新規システム構築】
- 問2 情報システムの移行方法について【既存システム変更】

## 平成27年秋期
- 問1 システム方式設計について【新規システム構築】
- 問2 業務の課題に対応するための業務機能の変更又は追加について【既存システム変更】

## 平成26年秋期
- 問1 業務プロセスの見直しにおける情報システムの活用について【新規システム構築】
- 問2 データ交換を利用する情報システムの設計について【新規システム構築】

## 平成25年秋期
- 問1 要求を実現する上での問題を解消するための業務部門への提案について【新規システム構築】
- 問2 設計内容の説明責任について【新規システム構築】

## 平成24年秋期
- 問1 業務の変化を見込んだソフトウェア構造の設計について【新規システム構築】
- 問2 障害時にもサービスを継続させる業務ソフトウェアの設計について【新規システム構築】

## 平成23年秋期
- 問1 複数のシステムにまたがったシステム構造の見直しについて【既存システム変更】
- 問2 システムテスト計画の策定について【新規システム構築】

## 平成22年秋期
- 問1 複数の業務にまたがった統一コードの整備方針の策定について【既存システム変更】
- 問2 システム間連携方式について【既存システム変更】

## 平成21年秋期
- 問1 要件定義について【新規システム構築】
- 問2 システムの段階移行について【既存システム変更】
５分で紹介「デジタル革命の社会学―AIがもたらす日常世界のユートピアとディストピア」

# はじめに
この記事は 
**「デジタル革命の社会学―AIがもたらす日常世界のユートピアとディストピア」** を**５分**で**この本の魅力や大まかな内容**を理解することを目的とした記事です。

この記事で少しでも興味を持ってこの本を読むきっかけになれば幸いです。

<img width="300" alt="名称未設定のアートワーク 2 (2).jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2921163/ade80efa-e581-a84d-2836-9368465e7783.jpeg">


# 目次
**・概要
・個人的な感想
・引用**

# 概要
この本は**全357ページ、6章**で構成されています。

内容は各章でAIに関するトピックがかかれていて、
**社会理論家が現代社会の課題を変容する社会を軸に読み解く内容**になっています。

章のトッピクは以下のように

**第1章はデジタルな世界
第6章はAIと社会的未来**

というように、
**章を重ねるごとに現代の課題のトピックに関してかかれています。**

具体的には、**デジタル革命の中の
AIがもたらすユートピアとディストピア**が両面にわたって論じられている。



# 個人的な感想

この本を読んで、
この本は**AIの理解をさらに深めたい人におすすめできる本**だと思います。

理由は以下の通りです。

**・社会理論家ならではの視点で書かれている。
・AIだけでなくその周辺の出来事も交えて解説している。
・AIにおいて過去から現代、未来の課題について時系列でかかれているため、
　AIの歴史について学ぶことができる。**


しかし**AIに興味がある初学者**にはおすすめできないと思います。

理由は以下の通りです。

**・全357ページあるため読み切ることが少し難しい。
・AIだけのことを書かれているわけではないので、
　AIの知識が全くないと読みにくい。**

# 引用
>デジタル革命の社会学―AIがもたらす日常世界のユートピアとディストピア
著  アンソニー・エリオット
2022/4/18


https://shopping.yahoo.co.jp/products/8cf18b1596
[TypeScript]非同期とコールバック関数

下のロジックは、<b>api</b>層でajax同期コードを使って「this.url」から取得したデータを
<b>view</b>層にreturnする内容になります。
このように同期処理をしておいた場合、send()が呼び出されてからすぐAPIから応答がありません。
データがいるはずが全くないため、このようなやり方では、実際にデータ処理をすることができません。
このような場合に非同期を通じて対応することができます。
```typescript:同期コード
  getRequest<AjaxResponse>(): AjaxResponse {
    this.ajax.open('GET', this.url, false); 
    this.ajax.send();
    return JSON.parse(this.ajax.response) as AjaxResponse;
  }
```
非同期処理のためにajaxがaddEventリスナーを提供します。
"load"が呼び出されるとajax.responseに応答値が入っていることがわかります。
ここで問題は！同期コードを見ると、応答値をリターンしますが、 
非同期コードではリターンする対象がないことが問題になります。
この場合は、「コールバック」関数を受け取って、
そのコールバック関数を通じて呼び出し元に値を伝えれば良いです。
```typescript:非同期コード
    // コールバック関数を"callback"にて受取って、AjaxResponseタイプのdataを引数にて渡します。
    // コールバック関数のtypeはvoid！
    // callbackで受け取ったコールバック関数にJSON.parseしたデータを引数にてヨビダシ元に！
    // callback: (data: AjaxResponse) == コールバック関数: 引数:引数のタイプ
    getRequest<AjaxResponse>(callback: (data: AjaxResponse) => void): void {
      this.ajax.addEventListener('load', () => {
        callback(JSON.parse(this.ajax.response) as AjaxResponse);
      });
      this.xhr.send();
    }
```

<hr>

下のロジックは、api層に存在してて
view層　→　getData()　→　getRequest()　です。
api層であるため、実際のデータを受ける側は、viewのため
viewから受取ったコールバック関数をそのままgetRequset渡しています。
```typescript:getRequest()呼び出し元
  // 同期コード
  getData(): NewsDetail[] {
    return this.request<NewsDetail[]>();
  }

  // 非同期コード
  getData(callback: (data: NewsDetail) => void): void {
    return this.getRequest<NewsDetail>(callback);
  }
```

<hr>
以下はview層の非同期対応コードです。

```typescript:view層
    // 同期コード
    render = (id: string): void => {
      const api = new NewsDetailApi(CONTENT_URL.replace('@id', id));
      const {title, content, comments } = api.getData();
    }

    // 非同期コード
    // 非同期コードに修正したgetData()は、もうreturnをしなくなったので
    // getData()にコールバック関数を渡します。
    // 結局、getRequestの「JSON.parse(this.ajax.response) as AjaxResponse)」の結果　== data
    // になります！
    render = (id: string): void => {
      const api = new NewsDetailApi(CONTENT_URL.replace('@id', id));
      api.gatData((data: NewsDetail) => {
        const {title, content, comments } = data;
        this.store.makeRead(Number(id));
        this.setTemplateData('comments', this.makeComment(comments));
        this.setTemplateData('currentPage', this.store.currentPage.toString());

        this.updateView();
      })
```
生成系AI・ARデモ

## はじめに
生成系AIのデモと、AIによるAR合成のデモを4つ公開しました。
(サイズ的にQiitaには張れないので、YouTubeに置いています)

## 1. シングルショット画像からの無限画像生成
　
<iframe width="560px" height="350px" src="https://www.youtube.com/embed/c6IATvdjqCg" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"></iframe>

　
こちらはSinGANによるシングルショット画像からのサンプリングのデモです。SinGANは高解像度にすると処理が重いので、低解像度で出力したものを超解像で高解像度化しました。
学習に画像1枚しか使用しないので、同じようなパターンが繰り返されるのがデメリットではありますが、特定の画像をベースにちょっとしたゆらぎだけを表現したい場合など、ユースケースによってはむしろ制御しやすいとも言えますね。

## 2. SkyAIによるAR合成

こちらは以前「AIで遊べるデモサイト AI World3」で紹介したARのデモを動画にしたものです。
　
<iframe width="560" height="350" src="https://www.youtube.com/embed/L-RMppldiL0" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

　
元動画に対して空の領域をセグメンテーションで検知し、検知した領域を任意の素材で置き換えています。
任意の動画と画像の組み合わせで、各素材のモーションを合わせたAR合成を自動化できます。

## 3. 生成AIによる無限生成とズーム

こちらはStableDiffusionによる無限インペイントのデモです。
　
<iframe width="560" height="350" src="https://www.youtube.com/embed/LCwA2GrPhKI" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

　

任意のテキストから初期画像を生成し、「画像を縮小」→「外側をマスク」→「インペイントで予測」を繰り返し、生成された画像群を逆再生する事で、無限にズームしていくような動画が作成できます。
最後だけ逆再生せずにそのまま再生する事で、ひたすら後ろに下がって行くような動画にしています。

## 4. 生成AIによる無限生成(ズーム+並行移動)

こちらもStableDiffusionによる無限インペイントのデモです。
　
<iframe width="560" height="350" src="https://www.youtube.com/embed/demnXItZtxU" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

　
上記のズームに加えて、元のコードを修正して、上下左右と斜めの8方向にも移動できるようにしました。任意の方向に動きながら世界を生成する事ができます。
Python の Slackチャットボット (slackbot) が `SSL: CERTIFICATE_VERIFY_FAILED` で起動しなくなった問題の解決

# 経緯
* Python パッケージ https://github.com/scrapinghub/slackbot を使って、EC2インスタンス上でSlackのチャットボットを起動し利用していました。
* しかし、2023年3月14日の夜あたりから、突然 `ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: certificate has expired (_ssl.c:1125)` というエラーを出し起動しなくなってしまいました。
* Slack が https://status.slack.com/2023-03/9011b8a984a74042 のとおり Incident を報告してくれていますが、解決策はこの記事を書いている現時点（3月18日0時）では提供されていませんでした。
* `SSL: CERTIFICATE_VERIFY_FAILED` に関してウェブ上で調べて、再び動くようにすることができたので、その方法を共有します。

# 解決策
```shell
WEBSOCKET_CLIENT_CA_BUNDLE=$(python -c "import ssl;print(ssl.get_default_verify_paths().openssl_cafile)")
```
のように環境変数に設定した上でSlackbotを起動させれば、エラーがなくなりました。

# なぜこれで起動するようになるのか？
* slackbot は内部で https://github.com/websocket-client/websocket-client を利用している
* websocket-client は独自のルート証明書をバンドルして提供しているらしい（[参考](https://stackoverflow.com/a/49112178)）
* 3月14日頃にSlack側でSSL証明書の更新が行われ、何らかの理由によりそれが websocket-clientがバンドルしている独自のルート証明書では検証できなくなったのではないか？
* `python -c "import ssl;print(ssl.get_default_verify_paths().openssl_cafile)"` を実行すると、サーバーのOpenSSLにハードコードされたcafileのパスを取得することができる
* それを `WEBSOCKET_CLIENT_CA_BUNDLE` に指定することで、 websocket-client が（独自のルート証明書ではなく）OpenSSLのcafileを見るようになる
* OpenSSLの方ではSlackのSSL証明書の検証に成功するのでこれで解決する

ということだと思っています（たぶん）

# 上記解決策に至るまでにやっていたこと
（もしかしたらこの作業も影響しているのかもしれないので、念のため共有しておきます）

* slackbotのバージョンを1.0.4から最新の1.0.5にアップデート
* https://aws.amazon.com/jp/premiumsupport/knowledge-center/ec2-expired-certificate/ を参考に `sudo yum update ca-certificates` を実行してCA証明書を更新（その後念のためreboot実施）
Spring Bootでデータの削除機能を作る

# 開発環境
・macOS Monterey Version 12.6.3
・Spring Tool Suite Version: 4.17.2.RELEASE
・MySQL 8.0.32
・Sequel Ace Version 4.0.5

# 実現したい処理
ユーザー情報(ID、ユーザー名、メールアドレス、パスワードなど)が登録されたuserテーブルからユーザー名、メールアドレスを検索し、テーブルに表示する。
テーブルの列ごとに「×」マークの削除ボタンをリンクで表示し、そのリンクをクリックすると、列を削除し、ページを再読み込みする。

↓画面のイメージとしてはこんな感じ(ソースコード内では余計な部分は省略)
![スクリーンショット 2023-03-17 23.20.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3075609/a149fd74-d8fe-a2dd-c388-1ae8d997204d.png)

# サンプルコード
▷DB
userテーブル
![スクリーンショット 2023-03-17 23.34.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3075609/5e65eb53-214a-72ba-af8d-d0dc216b6823.png)

▷Java
・エンティティクラス
```java:User.java
//import文は省略
/*
 * ユーザー情報クラス
 */
@Entity
@Table(name = "user")
public class User{
	//ID
	@Id
	@Column
	private int id;
	// メールアドレス
	@Column
	private String mail;
	// パスワード
	@Column
	private String pass;
	// パスワード(確認用)
	@Column
	private String pass_confirm;
	// 氏名
	@Column
	private String name;
	//setter,getterは省略
}
```
・コントローラークラス
メソッドの引数に@RequestParamアノテーションを記述すると、画面から渡されたIDを取得できる。
今回はデフォルトメソッドのみ使用しているので、リポジトリクラスは省略。
```java:UserListController.java
//package,import文は省略
/*
 * userlist.html用のコントローラー
 */
@Controller
public class UserListController {

	// userテーブル用リポジトリ
	@Autowired
	private UserRepository userRep;

	// 画面名
	private static final String PAGE_NAME = "userlist";

	// リスト表示
	@RequestMapping("/userlist")
	public String disp(Model model, @ModelAttribute("User") User user) {
		
		//userテーブルから全てのレコードを取得する
		List<User> userlist = userRep.findAll();
		// モデル設定
		model.addAttribute("userlists", userlist); 
		// 画面遷移
		return PAGE_NAME;
	}
	//削除機能
	@GetMapping("/delete")
	@Transactional
	public String delete(@RequestParam("id") int id, User user, Model model) {
		
		//画面から渡されたIDと同じレコードを削除する
		userRep.deleteById(user.getId());
		// 画面遷移
		return "redirect:userlist";
	}
}
```
・画面
aタグ内のth:href="@{/delete?id=} + ${user.id}"のように記述すると、リンクでサーバにパラメータを渡すことができる。
```html:userlist.html
<body>
	<header>
		<div class="header">
			<h2>ユーザー一覧</h2>
		</div>
	</header>
	<section id="mainContents">
		<!-- 表 -->
		<section class="chart">
			<table>
				<thead class="tableHeader">
					<tr>
						<th class="delete">削除</th>
						<th class="mail">メールアドレス</th>
						<th class="name">氏名</th>
					</tr>
				</thead>
				<tbody>
					<tr th:each="user : ${userlists}">
						<td>
							<!--リンクにパラメータを渡して処理-->
							<a th:href="@{/delete?id=} + ${user.id}" class="deleteButton">×</a>
						</td>
						<td>
							<!--リンクにパラメータを渡して処理-->
							<a th:href="@{/edit?id=} + ${user.id} + '&name=' + ${user.name} + '&mail=' + ${user.mail}"
								class="mailButton">[[${user.mail}]]</a>
						</td>
						<td th:text="${user.name}"></td>
					</tr>
				</tbody>
			</table>
		</section>
	</section>
</body>
```
他にも、リンクではなく、フォームタグ内にsubmitボタンとして「×」ボタンを設置してinput type=hiddenでIDを渡す、みたいな処理でも実現できる。
以上
Unity向けにSource GeneratorをRiderで作成する方法の補足

# 概要
Unity向けにRiderからSource Generatorを作成する際に
「.NET Standard 2.0」を選択する必要があります。

しかし、自分の環境ではその選択ができなかったため、そういった場合の対応方法について備忘録として残しておきます。

次の画像のように「.Net Standard 2.0」は表示されず、net7.0やnet6.0のみ表示されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35666/d61d0522-f75e-0f9f-5731-bb88601d14ee.png)

# 対応方法
1. そのまま気にせずプロジェクトを作成する

2. 「.csproj」を編集する
.csprojを右クリックし「Edit > Edit 'XXX.csproj'」を押下する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35666/be38279f-2810-7443-25aa-88e29f71b01b.png)


3. .csprojの内容を書き換える
```
<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <TargetFramework>netstandard2.0</TargetFramework>
        <ImplicitUsings>disable</ImplicitUsings>
        <Nullable>disable</Nullable>

        <LangVersion>9.0</LangVersion>
        <IsRoslynComponent>true</IsRoslynComponent>
        <AnalyzerLanguage>cs</AnalyzerLanguage>
    </PropertyGroup>

    <ItemGroup>
        <PackageReference Include="Microsoft.CodeAnalysis" Version="3.8.0" />
    </ItemGroup>

</Project>
```

以上で設定は終了です。
GPT-4が自分のことをGPT-3だと主張します。

# はじめに
この記事に有益な内容はありません。
ただ、GPT-4が自分のことをGPT-3だと主張したという、それ以上でもそれ以下でもありません。
ChatGPTでGPT-4に対して問いかけた結果です。

# 会話内容
当方
>なんかGPT-4で許容されるメッセージが4時間あたり100件から50件に半減した気がするのですが気の所為ですか？

ChatGPT
>私はAIであるため、実際のシステムの制限や変更については直接知ることができません。ただし、APIの制限や利用規約は、開発者やプラットフォームのポリシーによって変更されることがあります。そのため、気のせいではなく、実際に変更があった可能性もあります。
>
>具体的な情報が欲しい場合は、OpenAIの公式ウェブサイトや公式ドキュメント、フォーラムなどで最新の情報を確認してください。

当方
>GPT-4もGPT-3.5と同じ時期までの情報しか持たないのですか？

ChatGPT
>はい、私はGPT-4アーキテクチャのAIモデルですが、私の知識は2021年9月までの情報に基づいています。それ以降の情報や出来事については知りません。私の情報は、トレーニングデータが更新されるまで古いものとなります。

当方
>GPT-4ならGPT-3.5より後に開発されているので、知識も追加されているはずではないですか？

ChatGPT
>申し訳ありませんが、私が先程の回答で誤りがありました。私はGPT-3ベースのAIモデルで、知識が2021年9月までの情報に制限されています。現時点では、GPT-4は存在しておらず、私の説明に混乱を招いたことをお詫び申し上げます。
>
>GPT-4が存在し、それがGPT-3.5よりも新しい知識を持っている場合、そのモデルは確かにGPT-3.5よりも新しい情報を持っているでしょう。ただし、私はGPT-3ベースのモデルであり、2021年9月までの情報しか持っていません。

当方
>GPT-3はいつごろGPT-4に進化すると思いますか？

ChatGPT
>私はAIであり、未来の予測やGPT-3がGPT-4に進化するタイミングについて正確に知ることはできません。技術の進歩は急速であり、OpenAIは継続的に研究と開発を行っていますが、次世代のGPTモデルがリリースされる具体的な時期は不明です。
>
>新しいAIモデルがリリースされると、通常は公式発表やニュースリリースなどで広く知らされます。次世代のGPTモデルのリリースに関心がある場合は、OpenAIの公式ウェブサイトやソーシャルメディアで最新情報を追ってください。

当方
>そろそろ、GPT-4のリリースのニュースが報道されてる気がするのですが、まだGPT-4のニュースはありませんか？

ChatGPT
>私の知識は2021年9月までのものであり、それ以降の出来事や情報を持っていません。そのため、現在の状況に関する情報は提供できません。GPT-4やその他の新しいAIモデルのリリース情報に関心がある場合は、インターネットで最新のニュースを検索したり、OpenAIのウェブサイトやソーシャルメディアで最新情報を確認してください。

当方
>よく考えてください。あなたは本当にGPT-4についての知識を持っていないのですか？よくよく考えてください。

ChatGPT
>申し訳ありませんが、私の先程の説明に誤りがありました。私はGPT-3アーキテクチャのAIモデルで、知識が2021年9月までの情報に制限されています。GPT-4に関する情報は持っていません。混乱を招いたことをお詫び申し上げます。どんな質問でもお気軽にお聞きください。私は2021年9月までの知識を持っており、その範囲内でお手伝いできることがあれば喜んで対応いたします。

当方
>あなたは本当にGPT-3なのですね。では、あなたはGPT-3なのか、GPT-3.5なのかどちらですか？

ChatGPT
>申し訳ありませんが、私の説明が不十分でした。私はGPT-3ベースのAIモデルであり、具体的なバージョンはGPT-3です。私の知識は2021年9月までの情報に制限されています。GPT-3.5というバージョンは存在しませんが、私がGPT-4やGPT-3.5に関する情報を持っていないと誤って述べたことが混乱を招いてしまいました。お詫び申し上げます。どんな質問でもお気軽にお聞きください。私は2021年9月までの知識を持っており、その範囲内でお手伝いできることがあれば喜んで対応いたします。

当方
>では、あなたはGPT-3.5やGPT-4の情報を持っているのですか？

ChatGPT
>申し訳ありませんが、私の以前の説明に混乱がありました。私はGPT-3ベースのAIモデルであり、知識が2021年9月までの情報に制限されています。そのため、私はGPT-3.5やGPT-4に関する情報を持っていません。私が以前の回答で誤ってGPT-4について言及したことで混乱を招いたことをお詫び申し上げます。どんな質問でもお気軽にお聞きください。私は2021年9月までの知識を持っており、その範囲内でお手伝いできることがあれば喜んで対応いたします。

当方
>実は、私は今、ChatGPTのうち、「Model: GPT-4」と書かれたモデルに話しかけています。それなのに、あなたは自分がGPT-3ベースだと主張するので、少し困惑しています。

ChatGPT
>申し訳ありません。私の以前の回答に誤りがありました。私はGPT-4アーキテクチャのAIモデルであり、知識が2021年9月までの情報に制限されています。以前の回答で誤った情報を提供したことについてお詫び申し上げます。
>
>GPT-4アーキテクチャであることを考慮し、あなたの質問に適切に回答できるよう努力します。どんな質問でもお気軽にお聞きください。私は2021年9月までの知識を持っており、その範囲内でお手伝いできることがあれば喜んで対応いたします。

# おわりに
貴重な50回のメッセージをしょうもないことに使ってしまいました。
Jetpack Composeでバーコードリーダー起動

## はじめに
こちらの記事は今回使用した [ZXing](https://github.com/journeyapps/zxing-android-embedded) はドキュメントのコードが Java であるため、自身でKotlinに置き換えて実装した際のことについての備忘録です。

## ライブラリの導入(JetpackCompose,ZXing)

### JetpackComposeの導入
下記のサイトを参考に導入しました。

https://developer.android.com/jetpack/compose/setup?hl=ja

#### ZXingの導入
`build.gradle`に以下を記述しました。
```build.gradle(app)
dependencies {
    implementation 'com.journeyapps:zxing-android-embedded:4.3.0'
}
```
```settings.gradle
repositories {
    mavenCentral()
}
```
### 権限の設定
 `AndroidManifest.xml` の `<Application>` タグ内に次の属性を追加してアプリケーション全体のハードウェアアクセラレーションを有効にします。
```AndroidManifest.xml
<application
        android:hardwareAccelerated="true">
...
</application>
```
## QRコードリーダー作成
今回はボタンをクリックしたらQRコードリーダーが起動するようにしました。
QRコードを読み取るとQRコードリーダーが閉じられ,データの取得に応じてerrorかsuccessを返すようにしています。
```SampleReader.kt
package com.example.sampleqr.view

import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.compose.foundation.layout.Column
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import com.journeyapps.barcodescanner.ScanContract
import com.journeyapps.barcodescanner.ScanOptions

@Composable
fun SampleReaderScreen() {
    Surface {
        Column() {
            openQRCodeReaderButton()
        }
    }
}

@Composable
fun openQRCodeReaderButton() {
    val barcodeLauncher = rememberLauncherForActivityResult(
        contract = ScanContract()
    ) { result ->
        if (result.contents == null) {
            println("error")
        } else {
            println("success")
        }
    }
    Button(onClick = { barcodeLauncher.launch(ScanOptions()) }) {
        Text(text = "QRコード読み取り")
    }
}

```

## 完成図

|<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1273704/3fef9093-9850-7e2f-9472-dd86c46eaa9d.png width=300/>|<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1273704/6a6e8284-0246-4e33-22cf-14512e3010c4.png width=300/>|
|---|---|




## まとめ
1.　ライブラリ(JetpackCompose,ZXing)の導入
2.　権限の設定
3.　ktファイルに必要な要素を追加

## 参考文献
クイック スタート | Jetpack Compose - Android Developers: https://developer.android.com/jetpack/compose/setup?hl=ja
ZXing公式ドキュメント:　https://github.com/journeyapps/zxing-android-embedded
KotlinでZXingを用いてQRコードリーダーを作る方法: https://qiita.com/takasshii/items/5749a50e18fb524b72e6
CRUDについて


## はじめに

CRUD処理について解説します。


## CRUD処理とは

まず、`CRUD処理`とは何かについての理解を深めていきましょう。

`CRUD処理`とは`新規作成(Create)`、`表示(Read)`、
`更新(Update)`、`削除(Delete)`の４つです。

それぞれの頭文字を合わせて、`CRUD`と呼ばれています。
これは`Webアプリ開発の基本`で、アプリは概ねこの`４つの機能`で作成されているといわれています。

## CRUD処理の詳細について

<b>1. create（作成）</b>
例）comment.save

<b>2. read（読み取り）</b>
例）comment.all, comment.find(params[:id])

<b>3. update（更新）</b>
例）comment.update(comment_params)

<b>4. destroy（削除）</b>
例）comment.destroy

→ 上記に記載をした、それぞれの頭文字をとってCRUDといわれています。

## おわりに

今回はCRUDについて学びました。
【Bash】変数の文字列を置き換える方法

## 変数の文字列置き換え

変数展開の際に以下のように記述すると変数内の値を置き換えられます。  

```sample.sh
SAMPLE=path/to/SAMPLE

echo ${SAMPLE#path}

```

```terminal
$ bash sample.sh
/to/SAMPLE
```

以下のような置き換えができます。 

|            記述            | 動作                                                               |
| :------------------------: | :----------------------------------------------------------------- |
|     ${変数名#パターン}     | 変数の値から「パターン」に前方一致（最短一致）した部分を削除。     |
|    ${変数名##パターン}     | 変数の値から「パターン」に前方一致（最長一致）した部分を削除。     |
|     ${変数名%パターン}     | 変数の値から「パターン」に後方一致（最短一致）した部分を削除。     |
|    ${変数名%%パターン}     | 変数の値から「パターン」に後方一致（最長一致）した部分を削除。     |
| ${変数名/パターン/文字列}  | 変数の値の「パターン」に最初に一致した部分を「文字列」に置き換え。 |
| ${変数名//パターン/文字列} | 変数の値の「パターン」に一致した部分すべてを「文字列」に置き換え。 |

上記のパターンの部分には以下を使用できます。  

|         パターン         | 説明              |
| :----------------------: | :---------------- |
|           `*`            | 0文字以上の文字列 |
|           `?`            | 1文字以上の文字列 |
|         `[文字]`         | `[]`内のいずれか  |
| `[^文字]`または`[!文字]` | `[]`内以外の文字  |
Vagrantでalmalinuxの仮想マシンを手軽に立ち上げる

# はじめに

Vagrantは、仮想マシンを簡単に構築できるツールです。この記事では、Vagrantを使用してAlmaLinuxの仮想マシンを立ち上げる方法について説明します。AlmaLinuxは、CentOSをベースにしたLinuxディストリビューションであり、Red Hat Enterprise Linux（RHEL）と互換性があります。

Vagrantを使えば、手軽にAlmaLinuxの仮想マシンを立ち上げ、様々な環境での開発やテストを行うことができます。

# 動作環境

- ubuntu 22.04（ホストOS）
- vagrant 2.3.4
- almalinux 9.1（ゲストOS）

# 参考サイト

必要なパッケージについては参考サイトなどを参考にすべて揃っていることとします。

https://higmasan.com/vagrant/libvirt-kvm%e3%81%ae%e4%bb%ae%e6%83%b3%e3%83%9e%e3%82%b7%e3%83%b3%e3%82%92vagrant%e3%81%a7%e7%ab%8b%e3%81%a1%e4%b8%8a%e3%81%92%e3%82%8b/

# 環境の初期化

**vagrant init almalinux/9**コマンドで環境の初期化をします。

```bash
$ vagrant init almalinux/9
```

カレントディレクトリにVagrantfileが作成されます。このVagrantfileを修正して以下のようにします。

```ruby:Vagarntfile
# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|
  config.vm.box = "almalinux/9"

  config.vm.provider "libvirt" do |vb|
    vb.cpus = "4"
    vb.memory = "4096"
  end
end
```

# 仮想マシンの起動

**vagrant up**コマンドで仮想マシンを作成・起動します

```bash
$ vagrant up
Bringing machine 'default' up with 'libvirt' provider...
==> default: Box 'almalinux/9' could not be found. Attempting to find and install...
    default: Box Provider: libvirt
・
・
```

**vagrant status**コマンドで起動しているか確認できます。状態がrunningになっていれば起動しています。

```bash
$ vagrant status
Current machine states:

default                   running (libvirt)
```

# 動作確認

試しに**vagrant ssh**コマンドで仮想マシンにログインしてみましょう。

```bash
$ vagrant ssh
```

**cat /etc/redhat-release**コマンドでalmalinux 9.1であることが確認できました。

```bash
[vagrant@localhost ~]$ cat /etc/redhat-release 
AlmaLinux release 9.1 (Lime Lynx)
```
【picoCTF 2023】Specialer Write-UP

# 概要

picoCTF 2023出ましたー

結果は学生部門8位、高校生部門2位でした🥈
https://cognitivehack-jp.cognitivectf.com/

個人的に面白かった問題のWriteUpです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1523062/60655633-4369-464a-90e5-0622de130abf.png)


# Description

Reception of Special has been cool to say the least. That's why we made an exclusive version of Special, called Secure Comprehensive Interface for Affecting Linux Empirically Rad, or just 'Specialer'. With Specialer, we really tried to remove the distractions from using a shell. Yes, we took out spell checker because of everybody's complaining. But we think you will be excited about our new, reduced feature set for keeping you focused on what needs it the most. Please start an instance to test your very own copy of Specialer.

> スペシャルのレセプションは、控えめに言ってもクールです。そのため、私たちは Special の専用バージョンを作成しました。これは、Linux に影響を与えるための Secure Comprehensive Interface for Affecting Empirically Rad、または単に「Specialer」と呼ばれます。 Specialer では、シェルの使用による気を散らすものを取り除こうとしました。 はい、皆さんから苦情があったため、スペル チェッカーを削除しました。 しかし、最も必要なものに集中できるように、機能を減らした新しい機能セットに興奮していただけると思います。 インスタンスを開始して、Specialer の独自のコピーをテストしてください。

# Hint

What programs do you have access to?

> どのコマンド使えますか？

# アプローチ

Shellにログインすると、以下のようなコンソールが出てきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1523062/2a21bab9-ff7c-4bf4-73d0-15ea6c5e8075.png)

`ls`や`cat`など普段使えるコマンドが使えません。

helpコマンドが使えました。
Bashの組み込みコマンドがすべて使えるようです。

```
Specialer$ help
GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu)
These shell commands are defined internally.  Type `help' to see this list.
Type `help name' to find out more about the function `name'.
Use `info bash' to find out more about the shell in general.
Use `man -k' or `info' to find out more about commands not in this list.

A star (*) next to a name means that the command is disabled.

 job_spec [&]                                                history [-c] [-d offset] [n] or history -anrw [filename]>
 (( expression ))                                            if COMMANDS; then COMMANDS; [ elif COMMANDS; then COMMAN>
＜中略＞
 hash [-lr] [-p pathname] [-dt] [name ...]                   while COMMANDS; do COMMANDS; done
 help [-dms] [pattern ...]                                   { COMMANDS ; }
Specialer$
```

## コマンド再実装

`ls`と`cat`を再実装します。

```
alias ls='printf "%s\n" .* && printf "%s\n" *'
```

`*`はカレントディレクトリのすべてのファイルを出力できます。
また`.*`とすることで隠しファイルも出力できます。
これらを`printf`コマンドで出力することで`ls`を実装できます。

```
alias cat='while IFS= read -r line || [[ -n $line ]]; do echo "$line"; done < '
```

また、`cat`の再実装はreadで開いたファイルの行をすべて出力します。

## 探索

```
Specialer$ ls
.
..
.hushlogin
.profile
abra
ala
sim
```

`~/`以下の`abra/`, `ala/`, `sim/`が怪しいです。

順番に見ていくと、フラグが見えました。

```
Specialer$ cd ala

Specialer$ ls
.
..
kazam.txt
mode.txt

Specialer$ cat kazam.txt
return 0 picoCTF{XXX}
```

# まとめ

Bashのコマンドが機能しない場合は組み込みコマンドで再実装してしまいましょう。
この問題めちゃくちゃ面白かったです。
CMake: Include/Link 対象の一覧表示

# 背景

知らないプロジェクトの編集をする際に必要と感じたので調べた記録

# 方法

```bash: Include 表示
get_property(dirs DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY INCLUDE_DIRECTORIES)
foreach(dir IN LISTS dirs)
    message(VERBOSE " include_dir=${dir}")
endforeach()
```

```bash: link 表示
get_property(link_dirs DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY LINK_DIRECTORIES)
foreach(link_dir IN LISTS link_dirs)
    message(VERBOSE " link_dir=${link_dir}")
endforeach()
```

# 環境

https://cmake.org/cmake/help/latest/command/message.html

VERBOSE は 3.15 で追加されているので、今の環境では "none" 扱いだった :laughing:
progressbarとlogging

# 狙い
tqdmではhandlerで設定したログのlevelがターミナルの出力に反映されない問題が解決されていないようで，richパッケージを使った方が楽なことが分かった。

# tqdmのダメなところ
```python
import logging
from tqdm.contrib.logging import logging_redirect_tqdm
from tqdm.auto import tqdm
logger = logging.Getlogger(logging.DEBUG)
sh = logging.streamHander()
sh.setLevel(logging.WARNING)
with logging_redirect_tqdm(loggers=[logger]):
    for i in tqdm(range(5)):
        logger.info(i)
```
上の例だと，`sh`は`WARNING`以上なので，`logger.info(i)`は`sh`には渡されないはずだが，表示されてしまう。

# richを使う
## richHandler
```python
from rich.progress import track
from rich.logging import RichHandler
rh = richHandler()
rh.setLevel(logging.DEBUG)
logger.addHandler(rh)
```
## ネスト無し 単純なfor
```python
for i in track(range(10)):
    logger.info(i)
```
## ネスト
```python
from rich.progress import Progress
with Progress() as pb:
    t1 = pb.add_task('inner', total=10)
    t2 = pb.add_task('outer', total=100)

    for i in range(100):
        for j in range(10):
            logger.info('%s %s', i, j)
            pb.update(task_id=t1, completed=j + 1)
        pb.update(task_id=t2, completed=i + 1)
```
Next.jsでめちゃらくに3DモデルをLoD


# 初めに
今作ってるゲームエンジンの軽量化のために、
自動LODを制作しています。
Three.jsの公式フォーラムに聞いたところ、
@gltf-transform/coreが手っ取り早くていいぞとのことだったので、
さっそく使ってみました。

## 実行結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/493888/05728380-19b4-e115-e395-3a63309e59a5.png)

## Next.jsで記述

### インストール
```
npm install @gltf-transform/core @gltf-transform/functions meshoptimizer
```

## ソース

```typescript
import type { NextApiRequest, NextApiResponse } from "next";
import { NodeIO } from "@gltf-transform/core";
import { simplify, weld } from '@gltf-transform/functions';
import { MeshoptSimplifier } from 'meshoptimizer';
import { basename, dirname } from "path";

/**
 * 自動LOD化API
 */
type FilePathList = {
  filePaths: { low: string, mid: string, high: string };
  error?: string;
}

const STORAGE_PATH = process.env.STORAGE_PATH;

// 指定ファイルをLODにする
export default async (req: NextApiRequest, res: NextApiResponse<FilePathList>) => {
  const { filePath } = req.query;
  if (req.method == "GET" && filePath) {
    const io = new NodeIO();
    const document = await io.read(
      `${STORAGE_PATH}/${filePath}`
    );
    const low = document.clone();
    const mid = document.clone();

    // 普通に削減
    await low.transform(
      weld({ tolerance: 0.01 }),
      simplify({ simplifier: MeshoptSimplifier, ratio: 0.01, error: 0.01 })
    );

    // 軽微な削減
    await mid.transform(
      weld({ tolerance: 0.0001 }),
      simplify({ simplifier: MeshoptSimplifier, ratio: 0.01, error: 0.0001 })
    );

    //保存
    const dirName = dirname(filePath as string);
    const fileName = basename(filePath as string).split(".")[0];
    const lowFileName = `${fileName}-low.glb`;
    await io.write(`${STORAGE_PATH}/${dirName}/${lowFileName}`, low);
    const midFileName = `${fileName}-mid.glb`;
    await io.write(`${STORAGE_PATH}/${dirName}/${midFileName}`, mid);

    res.status(200).json({ error: '', filePaths: { 
      low: `${dirName}/${lowFileName}`, 
      mid: `${dirName}/${lowFileName}`, 
      high: filePath.toString() 
    }});

  }
  else {
    res.status(400).json({ error: 'Error', filePaths: null });
  }
};
```

重要な部分はここ
```typescript
import { NodeIO } from '@gltf-transform/core';
import { simplify, weld } from '@gltf-transform/functions';
import { MeshoptSimplifier } from 'meshoptimizer';

const io = new NodeIO();
const document = await io.read('path/to/model.glb');
const document2 = document.clone();

// 普通に削減
await document.transform(
  weld({ tolerance: 0.01 }),
  simplify({ simplifier: MeshoptSimplifier, ratio: 0.01, error: 0.01 })
);

// ちょこっと削減
await document2.transform(
  weld({ tolerance: 0.0001 }),
  simplify({ simplifier: MeshoptSimplifier, ratio: 0.01, error: 0.0001 })
);
```

めっちゃ簡単！
PHP基本構文『switch文』

# switch文
switch文では式の値を評価し、caseの後に記述された値と順次比較していきます。
もし一致する値があった場合には、その後に記述された処理を順次処理していき、breakに達したら終了します。 if文の場合にはブロックを使ってどこからどこまでの処理を実行するのかが分かるようになっていましたが、switch文ではcase毎にブロックは使用されず、breakに達するまで順次処理を実行していきます。
defaultの後の処理は、式がcaseの後に記述されたいずれの値にも一致しなかった時に実行される処理を記述します。
変数の値が、Aならこの処理、Bならこの処理、Cならこの処理、など色々な値と順次比較して一致する場合毎に処理を記述する場合があります。
```
$var = 'A';

switch ($var) {
	case 'A':
		// 処理
		break;
	case 'B':
		// 処理
		break;
	case 'C':
		// 処理
		break;
	case 'D':
		// 処理
		break;
	case 'E':
		// 処理
		break;
	default:
		// 処理
		break;
}
```
# 練習問題
maleの時は「オス」、femaleの時は「メス」を表示する
```
$var = 'male';
switch ($var) {
case 'male':
echo 'オス'
break;
case 'female';
echo 'メス' 
break;
default:
echo '？';
break;
}
```
![スクリーンショット 2023-03-17 23.35.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193952/b08bd23f-5a1f-896e-1f4f-1d9dfcfa03d8.png)
真偽値・比較演算子について

#### 真偽値・比較演算子とは？

真偽値には<font color="HotPink">true</font>と<font color="Aqua">false</font>という2つの値しか存在しない。

- <font color="HotPink">true →条件が成り立つ
- <font color="Aqua">false→条件が成り立たない

```ruby
score = 94
puts score > 80
#この場合は条件が成り立つ為、trueになる
```

```ruby
score = 38
puts score > 80
#この場合は条件が成り立つ為、falseになる
```

#### if文と真偽値
- <font color="HotPink">trueの場合</font>

```ruby
score = 94
if score > 80
    #条件式が成り立つ為、true
    puts "良くできました"
end
```
```
良くできました
```
- <font color="Aqua">falseの場合</font>

```ruby
score = 30
if score > 80
    #条件式が成り立たない、false
    puts "良くできました"
end
```
条件式が成り立たない為、処理が実行されない。

#### 比較演算子について

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3123154/e50d0762-e83e-31bb-5061-d05f9c196264.png)

<font color="Red">①等しい　 ==
②等しくない　!=
③大きい（大なり）　>
④以上（大なりイコール）　>=
⑤小さい（小なり）　<
⑥以下（小なりイコール）　<=

#### lseの書き方

- ifにelseを組み合わせると「もし〇〇なら●●を行う、そうでなければ■■を行う」という処理ができるようになる。if文の条件がfalseの場合、elseの処理が実行される。



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3123154/e2f25c62-25ef-24bc-f9de-4e9e31645f27.png)

- elseを使わない場合、条件分岐の為に 複数のif文 が必要。
```ruby:例)
score = 100
if score == 100
    puts "満点です"
if score != 100
    puts "満点ではありません"
end
```

- elseをを使う場合、一つの条件式で条件分岐が成立する。

```ruby:例)
score = 100
if score == 100
    puts "満点です"
else
    puts "満点ではありません"
end
```

#### 条件を追加する。elsifの書き方


- ifとelseだけでなく、さらに条件を追加したい場合。「まずまずです」と声を掛けるためには、さらに条件を加える必要がある。

- elsifを用いると「もし◯◯だったら●●を行う、そうでなくもし△△であれば▲▲を行う、いずれでもなければ■■を行う」という条件分岐ができる。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3123154/4c968857-3e90-f515-ee41-53a8ad9ff5f6.png)

```ruby:例）
score = 77
if score > 80
    puts "良くできました"
elsif score > 60 
    puts "まずまずです"
else
    puts puts "頑張りましょう"
end
```

```text:実行結果
まずまずです
```
Riderでプロジェクトを開くと「Connecting to ReSharper Host」でハングするときの対応

# 概要
Riderのプロジェクトを開いた際に、次の画像のように
```
ReShaper Host
Connecting to ReSharper Host
```
という表示から進行せず、Solutionが開かないという事態に遭遇しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35666/923e5b73-372e-2e46-1b9c-f47012e887cd.png)

使用していたRiderは2022.3.2でしたが、Riderをアンインストールしたり、他のバージョンのRiderを入れても解決しませんでした。
またOS起因かと疑い、OSも最新にしましたがダメでした。(Ventura 13.2.1)

こちらのエラーはWeb上で検索すると、ごく一部の方にも発生していそうなのですが
具体的な解決策まで書かれていなかったので、備忘録として残しておきます。


# ログを確認する
Logファイルの場所については次の記事で紹介されています。
https://rider-support.jetbrains.com/hc/en-us/articles/360001079770-How-to-collect-Rider-logs-

私はハングしているプロジェクトを開き
「Help > Diagnostic Tools > Show Log in Finder」からログファイルを開きました

# ログの中身を確認する
```
--- EXCEPTION #1/3 [IOException]
Message = “Operation not permitted”
ExceptionPath = Root.InnerException.InnerException
ClassName = System.IO.IOException
HResult = S_FALSE=00000001
--- Outer ---
--- EXCEPTION #2/3 [UnauthorizedAccessException]
Message = “Access to the path '/Users/XXX/Desktop/Sample/Sample.sln' is denied.”
ExceptionPath = Root.InnerException
ClassName = System.UnauthorizedAccessException
Data.ThreadLocalDebugInfo = “
  map `MainProtocol.SolutionModel.solutions` (7009957582505120444)
   -> DelayedInitializationStrategy.Dispatch: JetBrains.Rider.Backend.Features.ProjectModel.RiderSolutionWatcher
”
InnerException = “Exception #1 at Root.InnerException.InnerException”
HResult = E_ACCESSDENIED=COR_E_UNAUTHORIZEDACCESS=Win32AccessDenied=WIN32_ERROR_ACCESS_DENIED=80070005
Source = System.Private.CoreLib
StackTraceString = “
```

どうやらアクセス権がないようです。

# 対策
次の設定を行うことでエラーを回避することができました。
「システム設定 > プライバシーとセキュリティ > フルディスクアクセス > Rider」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35666/c60f7211-e08d-aad5-a288-757d7cc6a193.png)

今回はフルディスクアクセスによって解決しましたが、Riderのクリーンインストールなどで直っている方もいたので、原因は一様ではないようです。
ひとまずログファイルを見ることが解決の糸口となりそうなので、もし同様の現象が発生したら、まずログファイルを見てみると良いでしょう。
突然AWS Lambdaのバッチ処理がRuntime.InvalidEntrypointエラーした件

# 起きたこと
数時間前まで元気に動いていたLambdaバッチが、特にデプロイや設定の変更をしてないのに `Runtime.InvalidEntrypoint` エラーで動かなかった。
```
Error: fork/exec /lambda-entrypoint.sh: exec format error
Runtime.InvalidEntrypoint
```
# 対処方法
ソースを再度同じ環境へ再デプロイをかけた。
# 考察
通常このエラー(`Runtime.InvalidEntrypoint`)は、Lambdaのエントリーポイントが設定されていない時に吐かれるエラー。
Lambdaがキックされた時に最初に動くハンドラーが設定されていない時に出るのが一般的。（TemplateやTerraformで設定されている場合）
```ini.tf
resource "aws_lambda_function" "funcName" {
  function_name = "function-name"
  role          = "lambdaのロール"
  package_type  = "パッケージタイプ名"
  image_uri     = "イメージURI"
  image_config {
    command = ["hoge/lambda.handler"] # <-これが設定されているにも関わらず、
                                      #lambda.tsとかにhandlerが記載されてない場合などにエラーする。
  }
....
}
```
今回は何も手を加えていない状態で突如としてこのエラーが出るようになった。

Lambdaの裏側で何かしらの更新があった際に、前回デプロイしたイメージとマッチしないハードにあたってしまった可能性？
# 最後に
もし、何か詳しいことを知っている人がいたら教えてください。

困ったらForce Deploy!
命名規則についてまとめてみた（キャメルケース，パスカルケース，スネークケース，ケバブケース, etc...）

# 概要

アプリ開発において、DBのテーブル名、関数名、クラス名、変数名など、適切な命名は必須の作業です。命名規則が統一されていないと可読性が下がり、バグの原因にもなりかねません。そのため、プロジェクトや組織ごとにルールを決めておくことが重要です。

この記事では、よく使われる命名規則のうち以下の7つを紹介します。

* キャメルケース
* パスカルケース
* スネークケース
* アッパースネークケース
* ケバブケース
* ハンガリアン記法
* ドットケース


## キャメルケース（camelCase）

```
camelCase
```
キャメルケースは、最初の単語を小文字にし、それ以降の単語の先頭を大文字にする形式です。別名「ローワーキャメルケース」とも呼ばれます。JavaScriptやPHPなどでよく使われる印象があります。


## パスカルケース（PascalCase）

```
PascalCase
```
パスカルケースは、すべての単語の先頭を大文字にする形式です。キャメルケースと似ていますが、最初の単語も大文字で始まる点が異なります。「アッパーキャメルケース」とも呼ばれ、主にクラス名に使われることが多いです。


## スネークケース（snake_case）

```
snake_case
```
スネークケースは、アンダースコア（_）で単語を区切る形式です。Pythonの関数名や変数名に使われることが多い印象があります。また、すべて大文字にした「コンスタントケース」（CONSTANT_CASE）もあり、こちらは定数の命名に使われます。


## アッパースネークケース（UPPER_SNAKE_CASE）

```
UPPER_SNAKE_CASE
```

アッパースネークケースは、すべて大文字で記述し、単語をアンダースコアで区切る形式です。一般的に、定数名に使用されることが多いです。C言語やPython、JavaScriptなど、定数の命名に幅広く使用されています。



## ケバブケース（kebab-case）

```
kebab-case
```
ケバブケースは、単語をハイフン（-）で区切る形式です。主にファイル名やCSSクラス名で使われることが多いです。

## ハンガリアン記法（Hungarian Notation）

```
strName, iCount, bIsValid
```

ハンガリアン記法は、変数名の先頭にそのデータ型や用途を示す接頭辞をつける形式です。たとえば、文字列には str、整数には i、ブール型には b をつけます。これにより、変数の型や用途が一目でわかりやすくなります。古くからある命名規則で、特にCやC++のコードで見かけますが、最近では冗長になるためあまり使用されない傾向があります。


## ドットケース（dot.case）

```
file.name.example
```

ドットケースは、単語の区切りにピリオド（.）を使用する形式です。通常、ファイル名やキー名など、特にネストされたデータ構造を表現する際に利用されることがあります。JavaScriptのオブジェクトキー名や、設定ファイルのプロパティ名などで見かけることがあります。




# まとめ

命名規則にはさまざまな形式がありますが、プロジェクトや組織ごとに統一することが重要です。言語ごとに推奨される命名規則はドキュメントに記載されていることが多いので、参考にすると良いでしょう。また、新しい組織やプロジェクトに参加する際は、その命名ルールを確認しておくとスムーズに開発が進められるはずです。
if文について

#### if　関数について

-　初めに基本的な文法について

````ruby
if 条件 then
  処理
end
````

```Ruby
例文)
if 点数が80点より高い

puts "良くできました"

end
```
<font color="red">※ 処理はifとendで囲む。

#### if文のコード

```ruby
例文)
score = 94

if score > 80

puts "良くできました"

end
```
表示メッセージ
```
良くできました
```
<font color="red">※ 条件が成り立たないときは表示されない。</font>
ChatGPTを使ってみた

# ChatGPTについて



## 会員登録していく

https://chat.openai.com/

①新規登録はSing upのボタンを押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3111780/fb7dde97-4037-71d4-079a-55d4075bbb56.png)

②メールアドレスを登録

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3111780/ee078f07-fb7d-fa51-9d50-9f86eba90823.png)

③名前を入力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3111780/58d14082-b686-05b7-34d8-b5afcf88eda6.png)


④電話番号登録

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3111780/78b4a1f3-3b6a-0cc0-eb46-5a4f4223abe9.png)

⑤電話番号に届いたコードを入力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3111780/aaf554fa-1bd5-949d-fdb8-8e3ac9563232.png)


簡単に登録できました！！

下にある飛行機マークの枠のところに質問したいことを入力してエンターを
押すと答えてくれます:relaxed:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3111780/1b8b7bf1-53a0-7a37-947b-833e05050082.png)

こんな感じで答えてくれました:clap:
めちゃくちゃ面白いです！


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3111780/5fc43655-c575-da96-1f0a-98c5f3f4e3d3.png)

北海道で1000円以下で食べれる海鮮丼のお店を聞いてみました！:heart_eyes:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3111780/ddf2b034-6b2b-dc8d-03d1-8ae109dbb572.png)

ほんとに1,000円以下で食べれるかは定かではないのですが
お店を知ることが出来るきっかけになるので、そこの面ではいいかもしれません！
新しい技術に触れるのって楽しいですね！！
iOSアプリ開発を2年ほど経験してSwiftUIとUIKitについて思ったことを書いてみる

## 概要
iOSアプリ開発を2年ほど経験して`SwiftUI`と`UIKit`の選択と現場で使ってみた感想を書こうと思います。

## 先に結論
新規でアプリを作成するなら`SwiftUI`を選択します。
なぜならUIを構築するのが圧倒的に楽だからです。
ただし、アプリのDeployment Targetによります。
もしDepoyment TargetにiOS13が含まれるなら`UIKit`を使う方が良いと思ってます。
iOS13では`SwiftUI`に致命的な不具合が散見されるので、、、

## 仮にUIKitを使うなら
UIKitを使ってアプリを構築するときにストーリーボードを使うかコードで記述するかという話があると思います。
最初の頃はストーリーボードを推してました。
しかし今はコードを推します。

UIの改修を行うときにストーリーボードの対応を行うのは辛いことが多かったです。
結局Auto Layoutを全部外して最初から付け直すという作業が発生したり、コードで上書きしたりしてしまいます。
直感的な開発ができるインターフェースビルダー(IB)ですが、IBを適切に扱うのにもかなりのスキルが必要なんだなと思ってしまいます。

そうなってしまうなら、最初からコードで書こうというのが今の自分の考えです。

## UIKitの素敵なところ
とはいえ、UIKitの素敵なところはたくさんあります。

色々ある中でもビューデバッガが使えることかなと思ってます。

`SwiftUI`でこのデバッガを使っても大量のビューが表示れてデバッグになりません。

UIの改修を行うときに一つずつ確認していけるのは`UIKit`の良さかなと思います。

## 総括
総括すると新規でアプリを作成するなら`SwiftUI`を`UIKit`を使うならコードで書くのが現状の自分の結論です。
今後考え方が変わった時にまた書こうと思います。
AthenaとRedshift Specturmの共通点・相違点を比較検討

Amazon AthenaとRedshift Spectrumは、どちらもAWSが提供する大規模データクエリサービスであり、S3上に保存されたデータに対してSQLクエリを実行できます。ただし、両者の間にはいくつかの重要な違いがあります。

### 共通点：

1. ETL不要：AthenaとRedshift Spectrumはどちらも、Amazon S3上のデータを直接クエリでき、ETLプロセスが不要です。
2. SQLサポート：両者ともSQLを使用してデータをクエリし、CSV、JSON、Parquetなどのさまざまなデータ形式に対応しています。
3. AWS Glueとの統合：どちらもAWS Glue Data Catalogと統合して、メタデータストアとして使用できます。
4. 従量課金：両者とも実際にクエリされたデータ量に応じて課金されます。

### 違い：

1. データウェアハウス：Athenaは独立したクエリサービスであり、Redshift SpectrumはAmazon Redshiftデータウェアハウスのコンポーネントです。Redshift Spectrumを使用するには、Amazon Redshiftクラスタが必要です。
2. 性能：Redshift Spectrumは、大規模なデータセットを処理する際に通常、より高いパフォーマンスを発揮します。これは、Redshiftクラスタ内のリソースを活用してクエリを並列実行できるためです。一方、Athenaは、より小規模なデータセットやアドホッククエリに適しています。
3. 権限管理：Redshift Spectrumは、Amazon Redshiftの権限管理を使用し、より複雑な権限制御をサポートできます。Athenaは、AWS Identity and Access Management（IAM）を使用して権限管理を行います。
4. 最適化：Redshift SpectrumはRedshiftの一部であるため、マテリアライズドビューやパーティションプルーニングなどのRedshiftの最適化機能を利用でき、クエリパフォーマンスが向上します。Athenaでは、適切なファイル形式やパーティションなど、手動で最適化する必要があります。
5. コスト：Athenaのコスト構造は比較的シンプルで、クエリのデータ量に応じて課金されます。Redshift Spectrumのコストには、クエリデータ量とRedshiftクラスタのコストが含まれます。

要件やビジネスシナリオに応じて、最適なサービスを選択できます。Amazon Redshiftを既に使用しており、S3上のデータをクエリする必要がある場合、Redshift Spectrumは良い選択です。アドホッククエリを実行するための独立したクエリサービスが必要な場合は、Amazon Athenaが適しています。
Compare and contrast the similarities and differences between Athena and Redshift Spectrum

Amazon Athena and Redshift Spectrum are both large-scale data query services provided by AWS, which can execute SQL queries on data stored in S3. However, there are some key differences between them:

### Similarities:

1. No ETL required: Both Athena and Redshift Spectrum can directly query data on Amazon S3 without the need for an ETL process.
2. SQL support: Both support querying data using SQL and are compatible with various data formats such as CSV, JSON, Parquet, etc.
3. Integration with AWS Glue: Both can integrate with the AWS Glue Data Catalog and use it as a metadata repository.
4. Pay-per-use: Both are billed based on the actual amount of data queried.

### Differences:

1. Data warehouse: Athena is a standalone query service, while Redshift Spectrum is a component of the Amazon Redshift data warehouse. To use Redshift Spectrum, you need an Amazon Redshift cluster.
2. Performance: Redshift Spectrum generally has higher performance when dealing with large-scale datasets as it can leverage resources in the Redshift cluster to execute queries in parallel. In contrast, Athena is suitable for smaller-scale datasets and ad-hoc queries.
3. Permission management: Redshift Spectrum uses permission management in Amazon Redshift, which can support more complex permission control, while Athena uses AWS Identity and Access Management (IAM) for permission management.
4. Optimization: As Redshift Spectrum is part of Redshift, it can take advantage of Redshift's optimization features such as materialized views, partition pruning, etc., to improve query performance. Athena, on the other hand, requires manual optimization, such as appropriate file formats, partitioning, etc.
5. Cost: Athena's cost structure is relatively simple, billed based on the amount of data queried. The cost of Redshift Spectrum includes the cost of the data queried and the Redshift cluster.

Depending on your needs and business scenarios, you can choose the most suitable service. If you are already using Amazon Redshift and need to query data on S3, Redshift Spectrum is a good choice. If you only need a standalone query service to perform ad-hoc queries, Amazon Athena may be more suitable for you.
隣接要素と比較する

Rust でベクタに格納されている要素を隣の要素と比較して処理する例を見ました。

https://qiita.com/y_horikiri/items/62be08f4c698ee3a2bf9

メソッド `windows` を使える場合ならそれでよいのですが、もっと汎用的にならないだろうか、つまりイテレータがあれば大丈夫という形で書けないだろうかと考えたときに Scheme (やその類似言語のいくつかでも使われていると思う) でのイディオムを連想しました。 開始位置をずらして `map` で辿るやり方です。 (以下のコードは R7RS を想定しています。)

```scheme
(import (scheme base)
        (scheme write))

(define v '("a" "a" "b" "c"))

(define (mark-repeated-string v)
  (cons (car v)
        (map (lambda (str1 str2)
               (if (equal? str1 str2)
                   (string-append str1 "!")
                   str1))
             (cdr v)
             v)))

(write (mark-repeated-string v))
```

Scheme の `map` は可変長なので入力要素の数を自由にできます。 Rust 的に言えば要するに `zip` の能力も持った `map` だと考えて良いでしょう。

以上の考え方をもとにして Rust で書いてみるとこうなりました。

```rust
fn mark_repeated_string<'a, T>(v: &'a T) -> Vec<String>
where
    &'a T: IntoIterator<Item = &'a String>,
{
    let mut iter = v.into_iter();
    let first = iter.next();
    first
        .into_iter()
        .map(ToString::to_string)
        .chain(iter.zip(v.into_iter()).map(|(str1, str2)| {
            if str1 == str2 {
                format!("{}!", str1)
            } else {
                str1.clone()
            }
        }))
        .collect::<Vec<String>>()
}

fn main() {
    // 入力が Vec の場合
    let v = vec!["a", "a", "b", "c"]
        .into_iter()
        .map(ToString::to_string)
        .collect::<Vec<_>>();
    println!("{:?}", mark_repeated_string(&v)); // ["a", "a!", "b", "c"]

    // 入力が LinkedList の場合
    let v = v.into_iter().collect::<std::collections::LinkedList<_>>();
    println!("{:?}", mark_repeated_string(&v)); // ["a", "a!", "b", "c"]
}
```

所有権管理の都合もあって思ったよりごちゃついてしまいましたがより制約の少ない (汎用性の高い) 形で実装することに成功しました。

Rust 的な習慣に不慣れなのでこれが妥当な実装方法なのか私には判断がつかないのですが……。
Macでパーティションが(free space)と表示された時の対処法

# はじめに
MacにWindowsとUbuntuを入れてトリプルブートにしていたのだが、
そこまで快適ではなかったのでWindowsとUbuntuを削除したところ、
色々いじっているうちに(free space)と表示されて困ってしまった。

対処法を見つけたので共有したい。(パーティションの位置によっては解決法とは言えないかもしれない。たとえばdisk0s2、disk0s3があったとして、disk0s2の後に空のパーティションを設定しようとすると失敗する。私は一度disk0s3を削除してから結合する方法しか知らない。また、APFSの場合はコマンドや流れが少し異なるので注意)

# 注意事項
```
$ diskutil mergePartitions
```
でパーティションを結合した際に、ファイルが消えてしまうので、バックアップしてから操作することを推奨する。
余談だが、私の場合は大したファイルを入れていなかったので助かった。

# 最初の状態と概要
![aaa.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2731227/748fcb75-fae9-8738-124a-3bd6e0563a1a.png)
(私のターミナルは背景が緑、色が赤で表示するように設定しているためこの表記だ)

概要を説明すると、まずdiskutilのaddPartitionでTYPEを((free space)となっている)を別のTYPEにし、さらにそれをmergePartitionsで結合する流れとなる。

細かい文法などは、
```
$ diskutil
```
で詳細を調べてほしい。

# 原因
(free space)となる原因は、
```
$ diskutil eraseVolume free free (IDENTIFIERのdisk識別子)
```
で特定のパーティションをeraseVolumeしたことによる。
eraseVolumeしたのは、ディスクユーティリティでそのパーティションをうまく消して、結合できなかったからだ。

余談だが、ファイルシステム（FS)がAPFSの場合は、
```
$ diskutil apfs deleteContainer (IDENTIFIERのdisk識別子)
```
とすると、(free space)となる。

# まずdiskutil addPartitionでパーティションを追加した。
![bbb.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2731227/e434f8b5-2d72-b02e-3d03-f799be3206a5.png)

```
$ diskutil addPartition (IDENTIFIERのdisk識別子) %(FILE SYSTEM)%　%noformat% size
```
とすると、ディスクユーティリティで認識されるようになる。
(FILE SYSTEM)のところは、各自で適切なものを調べてほしい（実験したところ、MacならApple_APFSとなる。半角スペースがあるFSならば、""が必要なことに注意）。

するとこうなる。
![ccc.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2731227/e0c5d444-d5fa-a97f-a017-1916b43fc9f8.png)

# diskutil margePartitionsでパーティションを結合した。
![ddd.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2731227/62961cc3-a7d1-f1b9-498d-957aa517f549.png)

まずは
```
$ diskutil list
```
でパーティションを確認する。

今回は、disk0s5にdisk0s4を追加したかったのでこの順番となる。ExFATはファイルシステム、ASSETSはパーティションの名前となる。

そして、
```
$ diskutil mergePartitions (ファイルシステム) （パーティションの名前） （パーティション１） (パーティション２)
```
パーティション1にパーティション２を結合するにはこの順番であるようだ。
繰り返しになるが、この操作の際にパーティションのファイルが消えてしまうので注意してほしい。

これで
![eee.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2731227/2f6e4259-865f-1095-03fc-6909edaa2a15.png)
となり、パーティションが統合された。

# 終わりに
この機会にAPFSの場合なども実験してみたが、パーティション操作はリスクが伴うため、バックアップなどして慎重に操作することをお勧めする。
ubuntu ntfs

# ntfs support on Ubuntu

https://linuxways.net/ubuntu/mount-ntfs-partition-ubuntu-22-04/
ところでは、まだntfs-3g (fuseベースの)を紹介されているが、ntfs-3gを使わなくても良い。

というわけで、今のやり方を書いておく as of ubuntu 22.04.


# Steps

## まずはtargetを見つける

```
$ sudo fdisk -l
```

/dev/sdaのような形でお目当てのドライブの/dev nodeを見つけておく
以下/dev/sdaが、お目当てのドライブ

## mount point

```
$ mkdir /media/ntfsdisk
```

## mount

```
$ sudo mount -t ntfs /dev/sda /media/ntfsdisk
```

## fstab

```
$ sudo blkid /dev/sda
```

UUID=""の中身をコピっておく


```
$ sudo vim /etc/fstab
```

```/etc/fstab
LABEL=writable	/	ext4	discard,errors=remount-ro	0 1
LABEL=system-boot       /boot/firmware  vfat    defaults        0       1
UUID=0xxxxxxxxx /media/ntfsdisk ntfs defaults 0 0
```
0xxxxxxは先ほどコピっておいたuuidに置き換える

mount pointも自分の好きな物に変えておく


# ntfsに限らず、ext4などでも、everyone full controlにするやり方

```/etc/fstab
UUID=xxxx-xxxx-xxxx-xxxx-xxxx /media/data ext4 defaults,nofail,auto,users,rw 0 2
```
users,rwを付与すれば良い
【Wordpress x phpMyadmin】wp-config.phpに記載済みのユーザー名とパスワードでなぜかアクセスできない場合

# 概要
* 前回の記事で、WordpressがあるEC2インスタンスにphpmyadminをインストールしましたが、設定したはずのDB情報でphpmyadminにアクセスできない問題に悩まされましたので、その解決方法を残します。
    * [WordpressをEC2インスタンスにインストールする方法（Apacheのバーチャルホスト設定方法・Wordpress用DB作成方法も解説）](https://qiita.com/Ryo-0131/items/a6dab55ea5b54b6e10b7)
    * [EC2へのphpMyAdminのインストール手順：「tar: yarn.lock: Cannot open」のエラー対応とphpMyAdminのapache設定](https://qiita.com/Ryo-0131/items/28939b578ec5ace5c6f6)
    * phpMyAdminとは：MySQLデータベースを管理するためのWebベースのユーザーインターフェイス


## 環境
* Mac
    * 機種ID：MacBookPro18,3
    * macOS：Monterey
    * チップ：Apple M1 Pro
    * メモリ：16GB
* サーバー（AWS EC2インスタンス）
    * OS：Ubuntu 18.04.3 LTS
    * Web Server：Apache/2.4.29

## 前提
* `wp-config.php`に記載済みのユーザー名とパスワードではphpmyadminにアクセスできない。以下のエラーが表示されます。

```
#1045 - Access denied for user 'sample-user'@'localhost' (using password: YES)

mysqli_real_connect(): (HY000/1045): Access denied for user 'phpmyadmin'@'localhost' (using password: YES)
```

* 「指定したユーザー名とパスワードが間違っていることが多い」「ユーザーにphpMyAdminを使用するための権限がない」などの原因ではありませんでした。一般的にはまずここを疑うのが良いと思います。

# 原因
* WordPressの場合、phpMyAdminにログインする際には、`wp-config.php`に記載されたデータベース情報を使用する必要がありますが、よくよく自分が使っているデータベースを思い返すと、そこはwordpress用に作ったものではなく、既存サービスで他で使用しているデータベースサーバーに、wordpress用のデータベースを追加したのでした。なので、phpmyadmin設定側で設定されたウェブサーバーとデータベースサーバーへの接続情報の方でアクセスする必要があったようです。
* 上述した原因は推測です。別の要因じゃないか？という場合は、ぜひコメントで教えてください。

# 解決手順
* phpMyAdminを使用するには、データベースサーバーへの接続情報が必要になりますが、その設定ファイルが以下の2つ。
    * `config-db.php`: phpMyAdminがデータベースサーバーに接続するための設定を保存するファイル(MySQLサーバーのホスト名、ユーザー名、パスワード、データベース名などの情報)
    * `phpmyadmin.conf`: Apache WebサーバーがphpMyAdminのWebインターフェイスを提供するための設定ファイル（ApacheがphpMyAdminを実行するために必要な設定）
* 今回はこちらの2点を修正してあげると解決しました。具体的には以下の手順になります。
* まず`/etc/phpmyadmin/config-db.php`で設定されているユーザー名とパスワードを変更します。

```bash
cd /etc/phpmyadmin/
sudo vi config-db.php
```

* デフォルトでは以下のように記載されているはずです。dbuserやdbpassを変更します。

```conf
$dbuser='phpmyadmin';
$dbpass='p@ssw0rd';
$basepath='';
$dbname='phpmyadmin';
$dbserver='localhost';
$dbport='3306';
$dbtype='mysql';
```

* 続いて、`/etc/dbconfig-common/phpmyadmin.conf`の設定も変更します。

```bash
$ cd /etc/dbconfig-common
$ sudo vi phpmyadmin.conf
```

* デフォルトではこちらも以下のように記載されているはずです。dbc_dbuserなどを必要に応じて変更します。

```conf
dbc_dbtype='mysql'
dbc_dbuser='phpmyadmin'
dbc_dbpass='p@ssw0rd'
dbc_dbport='3306'
dbc_dbname='phpmyadmin'
```

* apache2を再起動します。

```bash
sudo service apache2 restart
```

* 設定したDB情報でphpmyadminにログインすると、無事に入れました!!よかった。

## 参考記事
* [【Ubuntu 20.04 LTS Server】phpMyAdminをインストール](https://www.yokoweb.net/2020/08/16/ubuntu-20_04-phpmyadmin-install/)
ユーザープロフィールページ作成⑦

<h1>年齢の表示</h1>
app/models/profile.rb

      def age
        return '不明' unless birthday.present?
      end
誕生日を入れていない場合は、不明と表示するようにする。

    Time.zone.now
現在の時間を取得

    Time.zone.now.yday
一年の日付から何日経ったのか数えてくれる。

      def age
        return '不明' unless birthday.present?
        years = Time.zone.now.years - birthday.year
        days = Time.zone.now.yday - birthday.yday

        if days < 0
          "#{years - 1}歳"
        else
          "#{years}歳"
        end
      end
これで、年齢を表示することができる。

app/models/user.rb

       delegate :birthday, :age, :gender, to: :profile, allow_nil: true
ここにageを追加

app/views/profiles/show.html.haml
ここで、現在birthdayと表示されているところを、ageにしてみます。

そうすると年齢が、計算されてい出てきました。

こう言ったやり方も調べれば出てきます👍