OmniAICreator/Qiita-1.07M huggingface dataset:
LeetCode挑戦日記：Day36

# はじめに

最近、業務で実装する時間よりも資料作成やレビューをする時間が多くなってきました。
このままでは自身のコーディング能力が落ちそうで怖いので、LeetCodeを始めてみました。

自身の学習の記録 & LeetCodeに興味のある人が挑戦しやすいように、記事に残していきます。
このような競技プログラミングをした経験がないので、ひよってEasyからやっていきます...

# [Medium] 437. Path Sum III

二分木の根と整数`targetSum`が与えられたとき、経路に沿った値の合計が`targetSum`に等しい経路の数を返します。
経路は根や葉で始まる必要はありませんが、下方向（すなわち、親ノードから子ノードへのみ移動）でなければなりません。

## 素直に解いてみる

### 考え方

1. それぞれのパスの合計値を求める
1. `targetSum`となる個数を数える

### コーディング

```typescript
function pathSum(root: TreeNode | null, targetSum: number): number {
    const func = (root: TreeNode | null, targetSum: number, sums: number[]): number => {
        if (!root) { return 0; }

        let match = 0;
        const newSums = [...sums, 0].map((sum) => {
            const newSum = sum + root.val;
            if (newSum === targetSum) { match++; }
            return newSum;
        });

        return func(root.left, targetSum, newSums) + func(root.right, targetSum, newSums) + match;
    }
    return func(root, targetSum, []);
};
```

### 結果

Runtime：119ms
Beats 17.96%

Memory：66.45MB
Beats 16.02%
【iOS 15】SwiftUIで共有画面の作成法

# はじめに
ここでは SwiftUI で共有画面を作成する方法を解説します。

SwiftUI では、iOS16 から [ShareLink 構造体](https://developer.apple.com/documentation/SwiftUI/ShareLink)がありますが、iOS15 以前は SwiftUI のネイティブサポートはありませんでした。そのため、開発者は代替アプローチを使用する必要があります。
ここでは、iOS16 と 1OS15 以前の2通りで共有画面を作成する方法を解説します。

# 開発環境
- Xcode15
- Swift 5.10

# iOS 16以降
iOS16 から、Apple は ShareLink という新しい View を導入しました。これにより、共有画面のプレセンテーションを簡単に作成するようになりました。
body 内に、`ShareLink` を使い、引数に共有したい任意の item を入れてあげれば完成します。

```diff_swift: ContentView.swift
import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack {
            // iOS 16
            let shareText = "iOS 16 or later shareItem"
+            ShareLink(item: shareText) {
                HStack {
                    Image(systemName: "square.and.arrow.up")
                    Text("iOS 16 or later")
                }
            }
        }
        .padding()
    }
}

#Preview {
    ContentView()
}
```

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/707293/62444a47-1b77-ddb0-d77e-1ff08b3fd3a7.png" width=300>

ShareLink については以下の記事がとてもわかりやすく書かれているので、詳細はこちらの記事を参考にすると良いと思います。

https://blog.code-candy.com/swiftui_sharelink_ios16/

# iOS 15 以前
iOS 15 以前の SwiftUI では、ShareLink のような簡単に共有シートを作成する API はありません。そのため、UIKit の `UIActivityViewController` を使って作成します。

```swift: 共有画面のコンポーネント
import UIKit

struct ShareView {
    static func showShareScreen(item: [Any]) {
        let activityVC = UIActivityViewController(
            activityItems: item,
            applicationActivities: nil
        )
        let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene
        windowScene?.windows.first?.rootViewController?.present(activityVC, animated: true)
    }
}
```

上記のコードは、item という `[Any]` 型を引数として取り扱います。これにより、任意のタイテム(URL, テキスト、画像など)を共有することを目的にしています。

`UIActivityViewController` は iOS の共有画面を表示する ViewController です。これは引数を元に作成されます。

`windowScene` では、iOS のメインウィンドを取得しています。`UIApplication.shared.connectedScenes` で現在、接続されているすべてのシーンを取得し、`first` プロパティで最初のシーンを取得します。これを `UIWindowScene` にキャストしています。

次に、取得した WindowScene の最初の　Window　の rootViewController を通じて、`UIActivityViewController` をモーダルとして表示します。

これは以下のようにして使うことができます。

```diff_swift: ContentView.swift
import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack {
            Button {
+                let shareText = "iOS 15 or earlier shareItem"
+                ShareView.showShareScreen(item: [shareText])
            } label: {
                Image(systemName: "square.and.arrow.up")
            }
        }
        .padding()
    }
}

#Preview {
    ContentView()
}
```

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/707293/d995b2ef-cd0b-2409-6ad9-40c9563ebe66.png" width=300>

# 最後に

サンプルコードを使ったリポジトリを公開しているので、よかったらスターください。

https://github.com/KaitoMuraoka/SampleShareProject

# 参考

https://medium.com/@sghanshyampadnekar/sharelink-using-swiftui-29467c17349d
【Go】依存性の注入をやってみる

## はじめに
PHPやLaravelで依存性の注入は書いたことがあるのでイメージできますが、Goでは書いたことがないので、書いてみました。

## コード
Loggerインターフェイスで持たせたいメソッドを定義しています。
そして、そのインターフェイスを満たす実装をしているのが、ConsoleLoggerとFileLogger構造体です。

ConsoleLoggerはコンソールに出力するだけ。
FileLoggerは指定ファイルにログを書き込みます。

Service構造体にはLoggerインターフェイスを持たせて、ConsoleLoggerとFileLoggerのどちらでも入れられるようにしています。
実際にはコンストラクタとしてNewServiceメソッドで注入しています。

こうすることで、Loggerインターフェイスを実装しているものなら好きなようにコンストラクタで差し替えることができます。
インターフェイスを満たすモックを作ることで簡単にテストすることも可能になります。

```go
package main

import (
	"fmt"
	"os"
)

type Logger interface {
	Info(message string)
	Warn(message string)
	Error(message string)
	Debug(message string)
	Fatal(message string)
}

type ConsoleLogger struct{}

func (c *ConsoleLogger) Info(message string) {
	fmt.Println("Info: " + message)
}

func (c *ConsoleLogger) Warn(message string) {
	fmt.Println("Warn: " + message)
}

func (c *ConsoleLogger) Error(message string) {
	fmt.Println("Error: " + message)
}

func (c *ConsoleLogger) Debug(message string) {
	fmt.Println("Debug: " + message)
}

func (c *ConsoleLogger) Fatal(message string) {
	fmt.Println("Fatal: " + message)
}

type FileLogger struct {
	filename string
}

func (f *FileLogger) Info(message string) {
	f.Log("Info: " + message)
}

func (f *FileLogger) Warn(message string) {
	f.Log("Warn: " + message)
}

func (f *FileLogger) Error(message string) {
	f.Log("Error: " + message)
}

func (f *FileLogger) Debug(message string) {
	f.Log("Debug: " + message)
}

func (f *FileLogger) Fatal(message string) {
	f.Log("Fatal: " + message)
}

func (f *FileLogger) Log(message string) {
	file, err := os.OpenFile(f.filename, os.O_RDWR|os.O_APPEND, 0644)
	if err != nil {
		file, err = os.Create(f.filename)
		if err != nil {
			fmt.Println(err)
			return
		}
	}
	defer file.Close()

	_, err = file.WriteString(message + "\n")
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Printf("Logging to file %s: %s\n", f.filename, message)
}

type Service struct {
	logger Logger
}

func NewService(logger Logger) *Service {
	return &Service{logger: logger}
}

func (s Service) LoggingAll() {
	s.logger.Info("Info message")
	s.logger.Warn("Warn message")
	s.logger.Error("Error message")
	s.logger.Debug("Debug message")
	s.logger.Fatal("Fatal message")
}

func main() {
	// ConsoleLoggerを使用
	consoleLogger := &ConsoleLogger{}
	service1 := NewService(consoleLogger)
	service1.LoggingAll()

	// FileLoggerを使用
	fileLogger := &FileLogger{filename: "log.txt"}
	service2 := NewService(fileLogger)
	service2.LoggingAll()
}
```

## 動かしてみる

```zsh
go run main.go

Info: Info message
Warn: Warn message
Error: Error message
Debug: Debug message
Fatal: Fatal message

Logging to file log.txt: Info: Info message
Logging to file log.txt: Warn: Warn message
Logging to file log.txt: Error: Error message
Logging to file log.txt: Debug: Debug message
Logging to file log.txt: Fatal: Fatal message
```
【Spring Boot】thymeleaf + ajaxで非同期処理

## やりたいこと
SNSのようなアプリケーションでユーザーが投稿からコメント削除をした場合に、ajaxでページ遷移や更新を行わず非同期で反映させたい

## Thymeleafの記述
* `meta`タグにCSRF対策トークン埋め込み
    * Spring Security使用している場合は設定しないと動かない
```html
<meta name="_csrf" th:content="${_csrf.token}"/>
<meta name="_csrf_header" th:content="${_csrf.headerName}"/>
```
* 必要なjsファイルとjQuery読み込み
```html
<script th:src="@{/webjars/jquery/3.4.1/jquery.min.js}"></script>
<script th:src="@{/js/sample.js}"></script>
```

## コメント一覧表示部分
```show.html
  <th:block th:each="comment : ${todo.comments}">
    <div class="card my-3 w-50" th:data-id="${comment.id}">
      <div class="card-body">
        <p th:text="${comment.comment}"></p>
        <div class="d-grid gap-2 d-md-flex justify-content-md-end">
          <p class="my-auto" th:text="${#dates.format(comment.updatedDate,'yyyy/MM/dd HH:mm')}"></p>
          <button type="button" class="btn btn-outline-primary edit-comment" th:data-comment="${comment.comment}" th:data-id="${comment.id}" th:data-todo="${todo.id}" data-bs-toggle="modal" data-bs-target="#commentEditModal">Edit</button>
          <button type="button" class="btn btn-secondary delete-comment" th:data-id="${comment.id}">Delete</button>
        </div>
      </div>
    </div>
  </th:block>
```

## ajax処理記述

```resources/static/js/comment-delete.js
$(function (){
    // CSRF tokenをリクエストヘッダにセット
    let token = $("meta[name='_csrf']").attr("content");
    let header = $("meta[name='_csrf_header']").attr("content");
    $(document).ajaxSend(function(e, xhr, options) {
        xhr.setRequestHeader(header, token);
    });
    // コメント削除ボタンを押した場合の処理
    $('.delete-comment').on('click', function(e){
        // idの取得
        const commentId = $(e.currentTarget).data('id');
        // POSTでjson形式のデータを送信
        $.ajax({
            url: '/comment/delete',
            method: 'POST',
            data: {
                'commentId' : commentId,
            },
            dataType: 'json',
            // 削除に成功したら画面からもコメント削除
            success: function(data){
                $('.card[data-id="'+data+'"]').remove();
            },
            error: function(){ alert("コメントの削除に失敗しました"); },
        })
    });
}); 
```

## Controller
```CommentController.java
@RequestMapping(value = "/comment/delete",method = RequestMethod.POST)
@ResponseBody
public Long delete(@RequestParam("commentId") Long commentId){
    commentService.deleteComment(commentId);
    return commentId;
}
```
* `POST`で`commentId`削除対象のコメントID受け取り
* `@ResponseBody`で削除した`commentId`をjsonで返却
Winter '21 Release Highlights - No-Code/Low-Code

https://trailhead.salesforce.com/content/learn/modules/winter-21-release-highlights-no-code


:::note alert
We could not find an active flow with the name 'Email Account Owner'. Make sure you have only one active flow created with that name.
:::

あああ、間違った

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/cc9a4548-0792-9688-e25c-efae8f8054c5.png)

有効化は必須？

:::note
We could not find an active flow with the name 'Email Account Owner'. Make sure you have only one active flow created with that name.
:::

:::note
We could not find a flow that sends an email successfully when the Opportunity is deleted with the StageName of 'Closed Lost'.
:::

何で＞デバックすると

:::note alert

おそらく制限を超えたか、受信者が 0 人です。無効な電子メール アドレスの可能性があります: 005GB00000a80JfYAI

Probably Limit Exceeded or 0 recipients. Possible invalid email addresses: 005GB00000a80JfYAI
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/b8fc34ab-714e-f526-bd48-d553a191b2bd.png)

何でだろうなぁ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/4e842b78-e85a-d6de-9e31-cdb9ae5e7c1b.png)

間違えてidを設定してたけど owner:userがない。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/bf2c503e-f5cf-a3be-a111-7ee6447d13d7.png)

しかたない。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/34982e18-1192-c93e-23f8-d8ed6062683f.png)

よくわからんけど、これで合格
Reminder record 1: AWS

Amplify Gen 2 ( Amplify ) でアプリを構築中に学んだことを残す。

## RDS の Credentials の取得

- 原因
    - Database の Credentials を動的に生成する場合、Secret Manager から取得して、Database URL を生成する必要がある。
- 対処
    - ECS のタスク実行ロールで、自前で生成した SecretsManager を読み取る。 [^4]

## `The maximum number of VPCs has been reached.`

- 原因
    - quota [^1]
    - Google Cloud にもあると思うが、警告された記憶がない。
```bash
CloudFormationDeploymentError: The CloudFormation deployment has failed.
Resolution: Find more information in the CloudFormation AWS Console for this stack.
Cause: ❌ Deployment failed: Error: The stack named amplify-zzzzzzzzzzzzzzz-hoge464-branch-9999999999 failed creation, it may need to be manually deleted from the AWS console: ROLLBACK_COMPLETE: Resource handler returned message: "The maximum number of VPCs has been reached. (Service: Ec2, Status Code: 400, Request ID: 9e18c0c5-4744-46de-b19f-42eacc4d74f5)" (RequestToken: b6f61210-ecc2-54d7-fba1-1c23284f4608, HandlerErrorCode: GeneralServiceException), Embedded stack arn:aws:cloudformation:ap-northeast-1:000000000000:stack/amplify-zzzzzzzzzzzzzzz-hoge464-branch-9999999999-fugaCustomResourcesF3BA9C19-1UGIK5IOKLCC6/0f57f6d0-3e7a-11ef-bfcf-066d2b45ed53 was not successfully created: The following resource(s) failed to create: [fugaAmpxVPCC6A56BA2]. 
```

## `exec /usr/local/bin/docker-entrypoint.sh: exec format error`

- 原因
    - ローカルで sandbox を起動した。 `npx ampx sandbox --profile ${MY_PROFILE_NAME} --identifier xxxx` [^2] [^3]
    - Mac で `docker build` を行ったため。
- 対処
    - CPU Architecture、OS を定義する。

```typescript
const taskDefinition = new ecs.FargateTaskDefinition(
  customResourceStack,
  'FargateTaskDefinition',
  {
    memoryLimitMiB: 512,
    cpu: 256,
    runtimePlatform: {
      cpuArchitecture: ecs.CpuArchitecture.X86_64,              // add
      operatingSystemFamily: ecs.OperatingSystemFamily.LINUX,   // add
    },
  },
);
```

## Conclusion

悩みが尽きることはない。

[^1]: https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/amazon-vpc-limits.html
[^2]: https://entreprogrammer.jp/exec-format-error-m1-mac/
[^3]: https://zenn.dev/fdnsy/articles/a7be6e205a39d0#platform
[^4]: https://zenn.dev/akira_abe/articles/20220220-aws-cdk-fargate#%E8%AA%B2%E9%A1%8C2.%E3%81%AE%E8%A7%A3%E6%B1%BA
Pandas: csv のコラムの文字列長さを制限する方法

csv の2列目のコラムの長さ10以上を削除して、長さを10以下にする方法

## プログラム

```py:csv_modify.py
#! /usr/bin/python
#
#	csv_modify.py
#
#						Jul/13/2024
# ------------------------------------------------------------------
import pandas as pd
import csv
import sys

# ------------------------------------------------------------------
sys.stderr.write("*** 開始 ***\n")

csv_file_in = sys.argv[1]
csv_file_out = sys.argv[2]
ll_limit = 10
df = pd.read_csv(csv_file_in,dtype=str)
print(df.shape)
column_index = 1
max_length = df.iloc[:,column_index].apply(len).max()
print("max_length =",max_length)
#
df.iloc[:, column_index] = df.iloc[:, column_index].str.slice(stop=ll_limit)

df.to_csv(csv_file_out,index=False,quoting=csv.QUOTE_ALL)
#
sys.stderr.write("*** 終了 ***\n")
# ------------------------------------------------------------------
```

## 実行

スクリプト

```bash
./csv_modify.py in01.csv out01.csv
```

入力 csv ファイル

```text:in01.csv
"市区町村コード","宛名番号","抑止事由"
"131016","a1234","01"
"131016","a12345678912","01"
"131016","a123456789123","01"
"131016","a12345678912345","01"
"131016","a12345678912567","01"
"131016","a123456789","01"
"131016","a123","01"
"131016","a12345","01"
```

出力 csv ファイル

```text:out01.csv
"市区町村コード","宛名番号","抑止事由"
"131016","a1234","01"
"131016","a123456789","01"
"131016","a123456789","01"
"131016","a123456789","01"
"131016","a123456789","01"
"131016","a123456789","01"
"131016","a123","01"
"131016","a12345","01"
```
Docker: dind

Docker について。

Docker-in-Docker ( dind ) の container 内から Host への接続について残す。毎回、何だっけ？となるため。

泥水をすするような仕事を繰り返すのは避けたい。

```mermaid
graph TD
subgraph docker_desktop["Docker Desktop"]
    subgraph A["app (Docker)"]
        D["src"]
        B["dind
        app"]
    end
    C["db (Docker)"]
end
D -->|docker run| B
B -->|connects to| C
```

## tl;dr
- `--network="host"` コンテナ内でホスト側ネットワーク・スタックを使用する。 [^1]

## Create a dind
```bash
# example
docker run --name mysql-container-4 --network="host" -e MYSQL_ROOT_PASSWORD=rootpassword -d mysql:latest
```

## Connect from app to db
```bash
docker exec -it mysql-container-4 bash
mysql -h db -u mysql -p
```

```bash
node ➜ /workspaces/kbp-bpaas-fdby-1/api (main) $ docker exec -it mysql-container-4 bash
bash-5.1# mysql -h db -u mysql -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 19
Server version: 8.4.0 MySQL Community Server - GPL

Copyright (c) 2000, 2024, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> USE mysql-db;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> SELECT * FROM users;
+----+----------+------------------+
| id | name     | email            |
+----+----------+------------------+
|  1 | John Doe | john@example.com |
+----+----------+------------------+
1 row in set (0.00 sec)

mysql>
```

## Conclusion
アドラーの言葉

https://d21.co.jp/book/detail/978-4-7993-3010-4

「課題の分離」は有名で、要するに自分に集中すること。

一方で、「課題の分離」で解決できない問題もあります。例えば、親子。

私は、これは子供を持ち改めて実感した。勉強してほしい。時間を守ってほしい。片付けをしてほしい。

どれも子供の課題です。しかし、「好きにしろ」と突き放したところで、一緒に生活する以上考えないことは不可能です。

これを「共同の課題」と捉えて、どうしたら解決できるかを話し合いするめることが必要になる。

「勉強しろ」「片付けろ」と一方的に一方的に指示する事は、子供の課題に土足で踏み込むことになる。

これはチーム開発にも言えることで、共同の課題として提案するスタンスが重要。

お互いのベースラインを合わせること。

そして、課題感を伝えること。

本全般は、技術書だけでは得られない社会で生きていくために必要なものを与えてくれる。

「速く学び、 変わり続けよう」


[^1]: https://docs.docker.jp/v1.11/engine/reference/run.html#network-settings
Deploy Amplify Gen 2 with npm workspaces

雨の Tokyo

Amplify Gen 2 ( Amplify ) の deploy について。

この文章を書くにあたり前提は以下の通り。
- Amplify である。
- Monorepo である。
- `npm workspaces` を採用している。
- Backend は Amazon ECS である。

## tl;dr
- `npm-scripts` で `npx ampx pipeline-deploy` を実行できる。`-w` option を指定する。

## Case1: `cd` コマンドで対象のディレクトリに遷移し実行する
- FAILED
- `package-lock.json` が見つからないため。
```bash: CodeBuild
[Container] 2024/06/26 09:13:10.885476 Running command npx ampx pipeline-deploy --branch $BRANCH_NAME --app-id $AMPLIFY_APP_ID --debug
npm ERR! could not determine executable to run

npm ERR! A complete log of this run can be found in: /root/.npm/_logs/2024-06-26T09_13_11_097Z-debug-0.log

[Container] 2024/06/26 09:13:12.185043 Command did not exit successfully npx ampx pipeline-deploy --branch $BRANCH_NAME --app-id $AMPLIFY_APP_ID --debug exit status 1
[Container] 2024/06/26 09:13:12.190205 Phase complete: BUILD State: FAILED
[Container] 2024/06/26 09:13:12.190234 Phase context status code: COMMAND_EXECUTION_ERROR Message: Error while executing command: npx ampx pipeline-deploy --branch $BRANCH_NAME --app-id $AMPLIFY_APP_ID --debug. Reason: exit status 1
[Container] 2024/06/26 09:13:12.229527 Entering phase POST_BUILD
```

## Case2: `npm-scripts` で実行する
- SUCCEEDED
- アドバイスをいただいた同僚に感謝。
```bash: CodeBuild
[Container] 2024/06/27 04:19:45.254696 Running command npm run amplify:deploy -w api

> api@0.0.1 amplify:deploy
> npx ampx pipeline-deploy --branch $BRANCH_NAME --app-id $AMPLIFY_APP_ID --debug true

[DEBUG] 2024-06-27T04:19:56.991Z: Bundling asset amplify-yyyy-BPD168-branch-xxxx/AmplifyBranchLinker/CustomResourceLambda/Code/Stage...

[DEBUG] 2024-06-27T04:19:57.571Z: 
  ...xxxxx/index.js  1002.4kb

⚡ Done in 143ms

[DEBUG] 2024-06-27T04:19:58.125Z: 


[DEBUG] 2024-06-27T04:19:58.762Z: error TS5057: Cannot find a tsconfig.json file at the specified directory: 'amplify'.

[DEBUG] 2024-06-27T04:19:59.775Z: 
✨  Synthesis time: 0.03s



✨  Synthesis time: 0.03s
```

```json: api/package.json
{
  "name": "api",
  "version": "0.0.1",
  "description": "",
  "private": true,
  "scripts": {
    "amplify:deploy": "npx ampx pipeline-deploy --branch $BRANCH_NAME --app-id $AMPLIFY_APP_ID --debug true"
  },
  "dependencies": {
  },
  "devDependencies": {
  }
}
```

```yml: buildspec.yml
version: 0.2

phases:
  build:
    commands:
      - echo Build started on `date`
      - echo set up the build-spec when using CodeBuild...
      - export CI=1
      - npm ci
      - npm run amplify:deploy -w api
```

## Conclusion
やりたいことをやれているか。

https://x.com/KenTana2020/status/1803714681078710664

わたしは、やりたいことはやれているが、自分のスキルと時間が足りない。
Nerves LivebookでBinary clockを動かす

# 前提
イメージを焼く為のOS Ubuntu 22.04
ハード　RPI 2とBinary clock
 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295814/77afe315-fbf1-df66-bd46-3fae07e3fd17.png)

# 環境作成

### Nerves Livebookをイメージをダウンロード

https://github.com/nerves-livebook/nerves_livebook/releases

rpi2の為、「nerves_livebook_rpi2.zip」を使いました

### イメージをSDに焼く
* 空のSDを用意します
* 「nerves_livebook_rpi2.zip」を解凍すると「nerves_livebook.img」
* 「nerves_livebook.img」をダブルクリックするとディスクが起動します
* 「転送先」をSDに指定します
*  「リストアを開始」をクリック
* 出来上がったらrpi2にSDをセットして電源を入れる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295814/3474042f-572f-0354-061f-0d760e55b20f.png)

# 実行する

https://github.com/fhunleth/binary_clock/blob/main/binary_clock.md

↑からサンプルソールをダウンロードする

RPI2のIPを調べる
ルーターで調べことが可能な機種もあります
DHCPの割当とか参考になる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295814/38771aa6-7dea-29c6-60d8-9c3914dea81c.png)

調べたIPを元にブラウザーでアクセス

初期パスワードは「nerves」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295814/005f22d7-dd8c-60fc-fe0c-6fe0aed30e6a.png)


Openをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295814/a4273675-7edb-5b2e-3631-a991a8a5276b.png)


「File upload」をクリック
ファイルを選択またファイルをドラッグ
　└binary_clock.livemdを指定
「Import」をクリック


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295814/55f2c7fc-a00b-62b7-cf51-ae7ac4574c9d.png)

Setupをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295814/e5715226-ea72-bea2-336c-824cf3114261.png)

スクロールして一番下にある「Evaluate」をクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295814/fc928424-c6c2-9070-6fc2-f87c7b9527ce.png)

これで動作します

# 動作動画

<iframe width="560" height="315" src="https://www.youtube.com/embed/Z_ryM_lWoAw?si=qgQ2SAzeDFzvyvWI" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
【2024マラソン27】毎週イベントの感想ペーパーを1ヶ月間描いたら、描きたいものを効率よく描く力が鍛えられた

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/964152/b5bd40f4-34aa-f6f8-5e51-328ff0d7acd5.jpeg" width=300>

# 何の記事？
Clusterのイベントに参加した感想ペーパーを書いた話をします


# 誰向け？ どんな役にたつ？
- イベントの感想をイラストにしてみたい人
- 感想、ペーパーを書くことによって、何が得られるのかが気になる人

# あらすじ
Clusterで毎週月曜日に開催されているイベントに通っているのですが、そのイベントが楽しかったよーと言う感想を何か自分の得意分野で伝えられればなぁと思い、今回感想ペーパーを書いてみることにしました。

# 感想ペーパーの要件
- 接したキャストさんを全員かく
- 話したキャストさんが、自分視点から映る姿でかく
    - その日に来ていた衣装でかく
- どんなことが面白かったかいや、キャストさんの素敵なところをかく
- イベントが楽しかったことが伝わるように意識してかく
- 来週のイベントが始まるまでの1週間でかく

# 難しかったこと
- 毎週描く
- 他の人のアバターを雑には描けないので、プレッシャーになった
- quest単機のイベント写真では衣装の細部がわからず、調べたりした
- イベントの暗さと実際のアバター色が違うため、参考写真から色をそのまま流用できなかった
- その人らしさが出るように描くのが大変だった

# 工夫したこと
- アバターのポーズはトレス素材からとった
- 色塗りは影色自動設定を使った
- 感想の中でも印象深かったことだけに絞って文字で追加した

# よかったこと
- 他の人のアバターを描くことで丁寧に描こうと思えた
- 定期的に同程度のクオリティを保った絵を描くことができるようになった
- その人を描くことで、とても喜んでもらえた

イラストレーターさんが好きな作品の感想をイラストにして、他の人にも布教するのを見ていて、すごく素敵だなぁとみていました。
この素敵なことを自分もできたらいいのになぁ。やってみたいなーと言う野望があったので、今回できてよかったです。
今月は子供のことでバタバタしていたり、Qiitaのイベント優先でやりませんでしたが、また書きたいなと思いました。

# 実際の感想ペーパーツイート

https://x.com/c9h11o2/status/1792523558754914350?s=61&t=gxD7gnDC7wtnx8y6znBMyA

https://x.com/c9h11o2/status/1795064353290342599?s=61&t=gxD7gnDC7wtnx8y6znBMyA

https://x.com/c9h11o2/status/1797597297569853463?s=61&t=gxD7gnDC7wtnx8y6znBMyA

https://x.com/c9h11o2/status/1799278341947818473?s=61&t=gxD7gnDC7wtnx8y6znBMyA
ターミナル開始時に特定のディレクトリをデフォルトに設定する方法

# 概要
Linuxでターミナルを開いた際
自動的に特定のディレクトリに移動するよう設定する方法を紹介します。

# 環境
エディタ：nano
シェル：Bash

# 手順
### 1. `.bashrc` ファイルを開く

ターミナルを開き、以下のコマンドを入力して .bashrc ファイルを編集モードで開きます。
```bash:Bash
nano ~/.bashrc
```
---
### 2. ファイルの末尾に移動コマンドを追加

.bashrc ファイルの最後に、`cd パス名`を追加します。
※ご自身の設定したいパス名
```shell:Bash
# 例
cd /home/yourname/vscode/runteq/basic_step/yourproject
```
![screenshot_11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711935/3d74e526-b7eb-9762-226a-40e2f4ef6805.png)

---

### 3. ファイルを保存して閉じる

①Ctrl+O を押して保存
②エンター
③Ctrl+X を押してエディタを閉じます。

---

### 4. 再読み込みして反映

```shell:Bash
source ~/.bashrc
```
---

### 5. 元に戻したい場合


①.bashrc ファイルを開く
②.bashrc ファイルの最後に記述したパスを削除
③ファイルを保存して閉じる
④再読み込みして反映
Git でファイル名の大文字小文字の変更が検知されない問題

## 概要

Git 使用時に、ファイル名の大文字小文字のみを変更した場合、その変更は検知されないことがあります。これは主に、OS のファイルシステムがケースインセンシティブ（大文字小文字を区別しない）であることが原因です。

## 問題の発生

Windows や macOS のデフォルト設定では、`file.txt` を `File.txt` に変更しても、`Git` がこの変更を検知しない場合があります。

## 対処法

### 手動での変更検知（全OS共通）
以下の手順で、確実に変更を検知させることができます。

1. ファイルをステージングから削除

```git rm --cached file.txt```

2\. ファイル名を変更

```mv file.txt File.txt```

3\. 新しいファイル名でステージングに追加

```git add File.txt```

4\. 変更をコミット

```git commit -m "Changed file name from file.txt to File.txt"```

### Git の設定変更

Git に大文字小文字の違いを意識させるための設定。

```git config core.ignorecase false```

※この設定はリポジトリごとに適用され、ファイルシステムの動作自体は変更しません。

## まとめ

ファイル名の大文字小文字の変更を Git で扱う際は、必要に応じて手動で変更を検知させるか、Git の設定を変更することが重要です。
🔰「10倍速で成果が出る！ChatGPTスゴ技大全」を読む（ChatGPT部 LT資料）#46


---
# ChatGPTスゴ技大全を読む

---
## 対象者
- 🔰AIは知ってるし、なんとなく使ったことはある
- ちょっと触ったけどよくわからなかったので、もう使ってない
- AIを使って試行錯誤しようとしているが、どうやって使えばいいかわからない

こういった方にとっては最適な本だといえます。

---
## 本の概要
「仕事のタイパを高める最強の武器を使いこなす」ということで

- 300ページを超える内容盛りだくさんの一冊
- ChatGPTの基本から応用まで幅広くカバー
- 初心者向けからビジネス利用まで想定

が主張できそうなポイントです。

---
## 1. ChatGPTが仕事を変える！

- AIブームの歴史
- テキスト生成系AIの解説
- AIを使う時の心構え
- プロンプトエンジニアリングの重要性

---
## 2. ChatGPT入門

- 実際に質問してみる
- 質問を変えて解答の変化を観察
- 翻訳など基本的なタスクを試す

---
## 3. 欲しい回答を生み出す超テクニック

- プロンプトエンジニアリングの具体例
- 「あなたは◯◯のプロです」というアプローチ
- アウトプットのフォーマット指定
- チャットボット作成

---
## 4~6. 分野別ChatGPT活用法

- 文書作成：出力内容別のプロンプト紹介
- プログラミング：実際にサイトを作成
- Excel：Googleサービスでの活用方法

---
## 7. リスキリングに活用する

- 英会話
- プログラミング（資格）
- 趣味（料理など）

---
## 8. もっと便利なChatGPTの使い方

- ChatGPT向け拡張機能
- プラグインの紹介
- ※有料サービスも含む

---
## 9. 生成AIの使い方と応用

- ChatGPT、BingAI、Bardの比較
- Text2Image技術の紹介
  - DALL-E
  - Stable Diffusion
  - CanvaAI

---
## 所感

- 内容は多岐にわたるが、一つ一つは深掘りされていない
- AIに関心を持ち始めた人向け
- 図書館で借りて読むのがおすすめ

---
## 不満点

- 生成結果の質に関する議論が少ない
- ビジネス利用を想定すると物足りない
- 「できるよ」は示されるが「できたよ」までは至らない

---
## 最後に

このスライドは本書を参考に、ChatGPTを使ってQiitaスライド用のmarkdownを生成し、
手直しする方針で進めたものです。
原稿は以下

https://qiita.com/nomurasan/items/4c8d8c3369ce4b0a3e79

---
## 書籍紹介
https://www.amazon.co.jp/10%E5%80%8D%E9%80%9F%E3%81%A7%E6%88%90%E6%9E%9C%E3%81%8C%E5%87%BA%E3%82%8B%EF%BC%81ChatGPT%E3%82%B9%E3%82%B4%E6%8A%80%E5%A4%A7%E5%85%A8-%E6%AD%A6%E4%BA%95-%E4%B8%80%E5%B7%B3/dp/4798183342

※アフィリエイトコードは貼ってません

---
## 

---
## 特になんでもない話
このスライドのQiitaIDがfc2〜になってる事に気付いて思わず噴きました（笑いを）
🔰ChatGPTスゴ技大全を読む


:::note warn
LT用の原稿的な使い方してます
:::

## 雑感
各章をまとめてバッサリいきます

### 1. ChatGPTが仕事を変える！
AIブームの歴史からテキスト生成系の解説へ、そしてAIを使う時の心構えまで。
プロンプトエンジニアリングの重要性を理解するところまでが本章のゴール、という印象

### 2. ChatGPT入門
このあたりはハンズオン。質問してみるところから、質問を変えて解答が変わるのを見たり、実際に翻訳させてみたり。

### 3. 欲しい回答を生み出す超テクニック
プロンプトエンジニアリングの具体例
よく使われている「あなたは◯◯のプロです」からアウトプットのフォーマットを指定するとか、チャットbotへ

### 4~6. 分野別ChatGPT活用法
- 文書作成
  - 出力してほしい内容別のプロンプト紹介
- プログラミング
  - 実際にサイトを作るまで
- Excel
  - Googleサービスで活用できるまで

### 7. リスキリングに活用する
英会話とプログラミング（資格）、また趣味の例として料理が挙げられている

### 8. もっと便利なChatGPTの使い方
いくつかあるChatGPT向けの拡張機能やプラグインの話。当然有料

### 9. 生成AIの使い方と応用
ChatGPTとBingAI、Bardのほか、Text2Imageまで。
DALLEからStable Diffusion、CanvaAIなど。

## 所感
内容盛り盛りで300ページを超えているが、一つ一つの内容は多くない（あまり解説するようなものではないから？）
この勉強会に参加している、しようと思ったレベルの人なら調べれば出てくるような情報がまとまってる程度でしかないので新しく得られる知識はないかも…
とはいえ、ChatGPTに関心を持っている人は多いので、図書館で借りて読むぐらいならいい感じ。立ち読み向けかな
「AIいいよ！」とはよく聞くけど、具体的にどうやって使えばいいか？という段階の人におすすめしましょう。

### 不満
やり方を教えてくれるのですが、生成した結果使えるものになっているか？の観点について一切議論されないので、ビジネス利用まで想定するとうーむ、というのが正直なところ
あくまで「できるよ」であって「できたよ」ではないのがポイント。たとえば、このLT用のスライドを生成してもらうために本を読みながらできるか？というとスライド自体を生成させることは書いていません。
とはいえ、プレゼンスライドを生成する話を4章で触れており、目次だけを見ると期待してしまいます。

アプローチの仕方としては、markdownは作れるのでQiitaスライド用に書いてもらって、細かいことを手直しすると言う方針で進めることにした方が良いです。
【2024マラソン26】Figmaで作ったフォントデータをクリスタに綺麗に持っていく方法

# 何の記事？
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/964152/771bf0c2-c118-ea54-0b68-134bb5203e89.jpeg" width=300>

figmaで作ったテキストデータを、svgファイルで出力すると白抜き文字になるため、対策方法がないか調べました。

# 誰向け？ どんな役にたつ？
- figmaでテキストを含むデータを作成後、綺麗な状態で他ファイルに持っていきたい人

# あらすじ
クリスタもベクターファイルが扱えるし、figmaからもベクター書き出しして入れればそのまま使えるやろ……と思っていたら、白抜きベクターになってしまうため、対策を考えることにしました。

# そもそもの仕様
- テキストは白抜きでエクスポートされる

> 注: SVGにエクスポートするときには以下の点に注意してください。
円錐形またはひし形グラデーション: これらは放射状グラデーションとしてエクスポートされます
背景ぼかし範囲: 直接レイヤーをぼかす必要があります
テキスト: **テキストはデフォルトでグリフとしてエクスポートされます。** つまり、テキストレイヤーをエクスポートした後に編集することはできません。テキストの編集を保存するには、をクリックして、[テキストをアウトライン化する]をオフにします
線: 線は塗りとしてエクスポートされます

https://help.figma.com/hc/ja/articles/13402894554519-エクスポート形式および設定

- jpg、png、PDFなどは72dpiなどの低画質でエクスポートされる

> **Figmaから画像としてエクスポートしたアセットはDPIがデフォルトで72です。** 規模に応じてエクスポートした画像のDPIを計算するには、選択したスケールに72を掛け合わせます。たとえば、2倍でエクスポートした画像のDPIは144です。3倍でエクスポートした画像のDPIは216です。

# 方法
## 大きいjpg、pngで書き出す
72dpiでも、大きなデータで吐き出してしまえば、クリスタのデータが高解像度でも問題なく使うことができます。
Figmaではエクスポート時にx4など倍率を選択できるので、欲しいサイズに対して倍率を上げてエクスポートしましょう。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/964152/9c9110dc-691d-a5e0-be2a-c19ad004943d.jpeg" width=300>


## PDFで書き出した後、クリスタでベクター化する
低解像度のPDFでも、意外とベクター化してそれなりの解像度で使うことができました。
ベクター化する際の設定に気をつけて変換しましょう。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/964152/06f1bff0-8cae-7e23-cef9-58b379465da3.jpeg" width=300>

### 気をつける設定
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/964152/e9eb4659-91f4-d6f6-39b5-7b4a24745fc9.jpeg" width=300>

- ベクター変換後も白抜きが残る場合は、最大線幅を大きく
- 白も変換のチェックを外す

# 感想
テキストデータをエクスポートした時も綺麗に書き出せてしまうと、他ソフトでもフォントのように使えてしまう=流用できてしまうため、あえてこういった仕様にしているところもあるのかなと思いました。
現状、PCでしか使えないフォントデータがあるのと、Figmaで作ったスタンプのような物をクリスタに付け加えたかった為、どうにかできないか……と調べましたが、クリスタで文字入れをしたいデータを先に作ってしまって、クリスタからFigmaへ持っていく方が正解なのかもしれません。
会社の先輩にVScodeかCursorを使ってMacのローカルでPythonのスクリプトをデバッグ実行する方法を教わった体験記

## 概要

会社の先輩にVScodeかCursorのエディタを使ってMacのローカルにあるPythonのスクリプトをデバッグ実行する方法を教わったので体験記としてまとめる。

## 前提

- 下記の内容が完了していること

https://qiita.com/miriwo/items/3f515e378d517cd7d5b7

- デバッグ実行は上記の記事で定義しているtest.pyを用いる

## 方法

1. VScode もしくは　Cursorにて「[Python Debugger](https://marketplace.visualstudio.com/items?itemName=ms-python.debugpy)」という拡張パッケージをインストール（おそらくPython Debuggerを入れるとPythonの拡張機能も勝手に入るはず。）

    ![CleanShot 2024-07-13 at 09.34.20@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/12217eb5-2f3e-0c11-79ea-ad6e9897fa04.png)

1. エディタでtest.pyのファイルを展開しておく

    ![CleanShot 2024-07-13 at 09.36.20@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/9412d4e7-b94f-8a83-fede-e1536fa9512f.png)

1. サイドバーで「実行とデバッグ」をクリック

    ![CleanShot 2024-07-13 at 09.36.54@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/d68403af-c8c7-eb2c-89a0-5636ba510b9f.png)

1. 「実行とデバッグ」をクリック

    ![CleanShot 2024-07-13 at 09.38.20@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/e0c4cae6-a796-9415-c29b-be42cc195bd7.png)

1. デバッガーの選択で「Python Debugger」を選択

    ![CleanShot 2024-07-13 at 09.40.25@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/8cb51421-6e6b-d1ba-f651-5461d91424a3.png)

1. 「Python ファイル 現在アクティブなPythonファイルをでバッグする」をクリック

    ![CleanShot 2024-07-13 at 09.41.27@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/263c5f22-88e8-bdd3-4aae-50898b7be731.png)

1. 4行目にブレークポイントを設定

    ![CleanShot 2024-07-13 at 09.49.10@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/958076b6-b00e-f80a-918c-8a35969bad7a.png)

1. 「実行とデバッグ」をクリック

    ![CleanShot 2024-07-13 at 09.51.01@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/53e0baf7-6a27-f686-3323-5cd01a13daad.png)

1. 下記の様にブレークポイントで処理が停止すれば設定は成功

    ![CleanShot 2024-07-13 at 09.52.13@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/1e3b8ed6-a49c-f088-afdd-78b4182b3fa8.png)
Studio OneでUSBキーボードが使えるようにする

DAWソフト、Studio One でUSBキーボードを使用したいときの設定方法

　追加したいキーボードが、すでに選択肢にあれば何も問題はありませんが、私の場合は選択肢に使用しているキーボードがありませんでした。
 　コテコテしていたら、DAWから音が出るようになったので、記録します。

１　デバイスを追加を押したのち、製造元とデバイス名は自分で入力します。
２　MIDIチャンネル以下の設定は１か所を除いて変更しないようにします。
３　変更する箇所は、受信元という部分です。
４　ここをクリックすると、様々な選択肢が出てきます。ここがポイント！
５　自分が設定したデバイスを選択したら、音が出るようになりました。

 設定した時のスクリーンショットを添付しますので参考にしてください。
　
![usb key.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3832918/d33373f1-3ca5-2d4b-ac44-22dc170f490f.png)
paiza.ioでelixir その301

# 概要
paiza.ioでelixirやってみた。
String.codepoints使ってみた。

# サンプルコード

```

String.codepoints("hello")
|> IO.inspect
|> Enum.map(fn n ->
	n
	|> IO.puts
end)


String.codepoints("hello")
|> Enum.with_index()
|> IO.inspect

String.codepoints("hello")
|> Enum.with_index(fn (k, i) ->
	"i: #{i}, k: #{k}"
	|> IO.inspect
end)

vv = String.codepoints("hello")
    |> Enum.with_index(fn (k, i) ->
	    "i: #{i}, k: #{k}"
    end)
    |> Enum.join("\n")
IO.inspect vv



```

# 実行結果

```
["h", "e", "l", "l", "o"]
h
e
l
l
o
[{"h", 0}, {"e", 1}, {"l", 2}, {"l", 3}, {"o", 4}]
"i: 0, k: h"
"i: 1, k: e"
"i: 2, k: l"
"i: 3, k: l"
"i: 4, k: o"
"i: 0, k: h\ni: 1, k: e\ni: 2, k: l\ni: 3, k: l\ni: 4, k: o"
```

# 成果物

https://paiza.io/projects/bQR3pCu_QcmIgK4StJypFg


以上。
SwiftLint Error：The file ".swift.yml" couldn't be opened ... の対処法

# 概要
新しい iOS プロジェクトを作成中に SwiftLint で、以下のような WARNING が発生した。

> SwiftLint Error: The file “.swiftlint.yml” couldn’t be opened because you don’t have permission to view it. – Falling back to default configuration

簡単に説明すると、「`.swift.yml` を開くことができないよ」って話。
Xcode の Build Phases が Lint ファイルを見つけることができないので、WARNING を出している。

## 開発環境
- Xcode15
- swiftlint 0.55.1

# 原因の解説
Xcode14 ではビルドシステムに `ENABLE_USER_SCRIPT_SANDBOXING` を追加しました。これは、script phases がソースファイルまたは中間ビルドオブジェクトにアクセスするのをブロックするかどうかをビルドシステムに指示する新しいフラグです。
Xcode14 ではこのフラグは **NO** に設定されていました。しかし、Xcode15 からこのフラグは **YES** に設定され、スクリプトファイルにアクセスできません。

# この問題の解決方法
[`ENABLE_USER_SCRIPT_SANDBOXING`](https://developer.apple.com/documentation/xcode/build-settings-reference#User-Script-Sandboxing) を **YES** にするとこの問題は解決します。

1. プロジェクトの設定を開く
1. ターゲットを開く
1. `Build Settings` を選択
1. `ENABLE_USER_SCRIPT_SANDBOXING` を検索
1. `User Script Sandboxing` を **NO** に変更

これで問題を解決することができます。

しかし、`User Script Sandboxing` の値を変更するのは回避策であり、Apple 的には推奨されていません。

## 補足
SwiftLint の README にもこの内容は記述されています。
詳細や最新情報はこちらを読むことをオススメします。

https://github.com/realm/SwiftLint?tab=readme-ov-file#consideration-for-xcode-150

# 参考文献
https://thisdevbrain.com/swiftlint-permission-issue/
MacのローカルでPythonのスクリプトを実行する

## 概要

MacのローカルにてPythonのスクリプトファイルを実行してみる。

## 前提

- 下記の方法でPythonの3.10.0がMacに入っており、実行できること

https://qiita.com/miriwo/items/3f515e378d517cd7d5b7

- 実行するPythonのコードは下記で、test.pyというファイルで任意のディレクトリに設置されているものとする（10回ループを繰り返し、インデックスが奇数か偶数かを出力するコード）

    ```test.py
    def loop_and_print():
        for i in range(10):
            if i % 2 == 0:
                print(f"{i}は偶数です")
            else:
                print(f"{i}は奇数です")
        print("ループが完了しました")
    
    loop_and_print()
    ```

## 方法

1. 「前提」で上げたtest.pyのカレントディレクトリにターミナルで移動
1. ターミナルで下記を実行してtest.pyを実行

    ```sh
    python test.py
    ```

1. 下記の様に出力されたら完了

    ```
    $ python test.py
    0は偶数です
    1は奇数です
    2は偶数です
    3は奇数です
    4は偶数です
    5は奇数です
    6は偶数です
    7は奇数です
    8は偶数です
    9は奇数です
    ループが完了しました
    ```
非エンジニア（営業）がアプリ開発をやってみた

# はじめに
初めての投稿になります。
AWS CIerでカスタマーサクセスセールスをしている宇都といいます。

以前はFuji◯eroxで新規開拓の営業をしていましたが、約2年半ほど前に今の業界に転職しました。
当時から複合機を販売するよりもソフトウェアだったり、AWSを提案するほうが楽しかったのですが、今はその好きなものだけをひたすら提案できるのですごく楽しいです。

**人間、興味があるというのはすごいエネルギーがあるもの**で、気づけばAWSの認定試験を5つ（CLF→SAA→SOA→SAP→SCS）も取っていました。

こうなると目指すは**全冠セールス**だなと思っているのですが、これまでの資格は正直、テスト勉強ができれば取れちゃうものばかりだったりします（良くないですけど）

ただDevOps Professionalに関しては開発サービスを触っていないとわからないものが正直多く、資格だけ持っている頭でっかちな人間というのも面白くないので、自分で開発してみようとなりました。
生成AIの技術進歩があって開発に対するハードルも下がっているので、元々個人開発してみたかったというのもあります。

VSCODE、Githubすら触ったことが無かった人間のただの成長記録でございます。

## 開発環境を整える
### VSCODEを触る
最初に開いた時、どこがどうなっていて、何を見て、どうしたらいいのか、全くわかりませんでした…
説明書とか、チュートリアルとか見ない性格なので、何でもとりあえず触りながら覚える精神でしたが、これは本当にわからなかった…ということで生成AIに聞いてみました

フムフム、こんな画面構成になっているのだな…
![スクリーンショット 2024-07-12 9.25.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3636130/400d30fb-48c0-496d-79f1-8db9c5493373.png)

**一番驚きだったのはVSCODEの中でターミナル実行ができることでした笑**
というのも今までMACに標準でついているターミナルを利用していて、なんとなく使いにくいなと思っていました。
VSCODEであればディレクトリ構造も見ながら移動できるので、「あのフォルダどこの配下にあったっけ？」みたいなのが一画面で完結できることに感動しました。

ちなみにプラグインでTerraformが入っていますが、個人的にロゴが好きというのと「Terraformで構築してます」っていつかいってみたいなというカッコつけ要素だけです。
触れないです、ロゴ見てなんかいい〜って思いながら触ってます。

### Githubのリポジトリを用意する
Github自体がどんな役割を持っているかはなんとなく理解していました。
ただ、**非エンジニアはファイルを「ドラッグ・アンド・ドロップ」しかしたこと無いのです。**
ここでもまた生成AIに聞いてみました。

ふむふむ…VSCODEからコマンドで直接Pushできるのか…
なんなら新規でリポジトリを作成すら出来のか、ブラウザ操作しなくていいの楽じゃんとシンプルに思いました。
Githubの操作についてはこちらの記事も参考にさせていただきました。


https://qiita.com/Futo_Horio/items/4d669f695680bc13d5fa


これまで 「メインブランチに変更をステージして、コミットしといて」と会議の中で言っているのを聞き流していましたが、何をやっているのか業務の解像度が上がって嬉しかったです。

（それからというものの、プライベートで常に「メインブランチに変更をステージして、コミットしといて」と言える場面がないか密かに探っているのは内緒です。）


## サンプルアプリ（Todoアプリ）を作成してみる
サンプルコードは生成AIに作成してもらいましたが、技術要素は下記で構成しました。

**Frontend**
‐ HTML
‐ CSS
‐ Javascript

**Backend**
‐ NodeJS
‐ MongoDB

その結果がこちら

![画面収録 2024-07-04 18.21.24-2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3636130/7474a228-4521-e5ab-0990-b9ab4c675726.gif)


とても普段使いできるような代物では有りませんが、初回にしてはなかなか良かったと思っています。

# まとめ

非エンジニアでも実際に自分で触ってみるのは大事だなと思いました。
アプリを構築してみて、初めて利用するツールのことが理解でき、
アプリケーションの構造がどのように動いているのかについて理解出来ます。

アプリケーションもディレクトリの中でそれぞれ目的に応じたコードを格納していたり、
FrontendとBackendそれぞれをコマンド起動しないといけないというのも知ることが出来て良かったです。

なにより自分がサービス提供する側の営業として、そのサービス（AWS各種サービス）の良さを知らないというのは良くないと思うんです。
AWSのCodePipelineなどCI/CDの仕組みを提案することがあるのですが、正直自分自身でもなぜ必要なのかよくわかっていなかったんです…
でも今回のハンズオンを通して、アプリを起動するには多くのステップがあることを理解できたので、CI/CD環境が必要なんだなと

今後の抱負としては、もっと普段使えそうなものも本格的に作っていきたいなと思っているので、構成を固めています！乞うご期待！

ここまで見てくれている方がいたら、ありがとうございました:pray:
Github ActionsでアップロードしたartifactsのDLリンクをslackに通知する

## はじめに
2023年12月にGitHub ActionsでArtifacts v4が一般利用可能となりました。v4の変更によって、artifactsアップロード後にartifact-idが付与されるようになりました。
https://github.blog/changelog/2023-12-14-github-actions-artifacts-v4-is-now-generally-available/

付与されたartifact-idを使うことでアップロードしたartifactのDLリンクが作れるようになります。

## サマリ
次のように書くことでダウンロードリンクが作れます
```
${{github.server_url}}/${{ github.repository }}/actions/runs/${{ github.run_id }}/artifacts/${{ steps.＊＊actions/upload-artifact@v4で指定したid名＊＊.outputs.artifact-id }}
```

## サンプル
プロジェクトルートフォルダにあるhoge.txtをアップロードしてslackにDLリンクを通知する例を示します。

### yaml
```
jobs: 
  upload-artifacts: 
    *中略*
    steps: 
      - name: Upload artifacts 
        uses: actions/upload-artifact@v4
        id: artifact-upload-step
        with:
          path: hoge.txt

      - name: Send to slack
        if: success()
        uses: slackapi/slack-github-action@v1.26.0
        with:
          payload: |
            {
              "text": "Github Actions実行結果: ${{ job.status }}\nダウンロードリンク: ${{github.server_url}}/${{ github.repository }}/actions/runs/${{ github.run_id }}/artifacts/${{ steps.artifact-upload-step.outputs.artifact-id }}",
              "blocks": [
                {
                  "type": "section",
                  "text": {
                    "type": "mrkdwn",
                    "text": "Github Actions実行結果: ${{ job.status }}\nダウンロードリンク: ${{github.server_url}}/${{ github.repository }}/actions/runs/${{ github.run_id }}/artifacts/${{ steps.artifact-upload-step.outputs.artifact-id }}"
                  }
                }
              ]
            }
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} 
          SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
```
### 実行結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3510732/d4b66a9a-4a58-f5a7-3bcc-ba97e5408ace.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3510732/b2d8abe7-a914-f33c-52bb-0e9761f50c84.png)
知財のあれこれをPythonで何とかする

１．ファミリを何とかする(その２）

特許の「ファミリ」、すなわち最初の出願を基礎出願とした外国出願や分割出願をまとめたもの、の取り扱いに関して、評価等何らか作業を行おうとするのであれば、まずはどの特許がファミリに含まれるか？を把握しないといけません。
ファミリの情報は日本特許のファミリであれば日本特許庁の運営している「J-platpat」外国特許のファミリであれば欧州特許庁の「Espacenet」をアクセスして取得できます。
しかしながら特許の件数が増えるとファミリを把握するだけで結構手間がかかってしまいます。今回は日本特許のファミリを把握する作業を少しでも容易にできるような処理方法を紹介したいと思います。

２．今回やろうとしていること
２－１．今回やろうとしていることは「J-platpatで表示させた分割出願のページの、登録番号の情報だけを抜き出す」ことになります。
手作業としては「J-platpatをアクセスして出願番号、公開番号、登録番号のいずれかを入力、分割出願のページを表示させ、登録番号を含むテキストデータをコピペする」ここまでは手作業です（ロボットアクセスは禁止されているため）。
プログラムでは、コピペしたテキストデータから登録番号（「登録」の文字列以降の7桁の数値）を抽出する処理をします。
J-platpatをアクセスして番号入力すると、分割出願があれば、分割出願のページを表示させる以下のようなボタンが表示されるはずです。
![1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3831931/1b56cef8-4a29-4050-7132-6359d2ec32b9.jpeg)

「分割」ボタンをクリックすると分割出願の情報が表示されますので、表示されたページのテキストデータを以下のプログラムの「特許情報うんたら・・・」の行にペーストしてください。
正確には単にペーストすると改行コードを含むのでエラーになりますので、ExcelでClean関数をかける等改行コードを除いてペーストしてください。

```python:qiita1.py
import re
jplt =["特許情報うんたら登録 7654321かんたら登録 7776665うんたら登録 7654321"]
index =0 

for item in jplt: #リストjpltの要素の個数だけループする
    patinf = jplt[index]
    reglist =[]
    patinf_mod = patinf.split('登録')#文字列を「登録」で分割しリストpatinf_modに代入 
    for smpl in patinf_mod:
        smpl = smpl.replace(' ', '')#空白削除
        regno = re.search('[0-9]{7}', smpl)#登録番号（7桁の数値（0～9））を抽出
        if regno is not None:
            reglist.append(str(regno.group()))
            fm_mbr='\r\n'.join(reglist)#改行を入れて登録番号を結合
    print(fm_mbr)
    index += 1
```
上記プログラムを実行すると変数「fm_mbr」にファミリの登録番号だけを抜き出すことができます。
（複数の登録番号が改行コードで区切られて結合した状態でfm_mbrに格納される)
![3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3831931/f2ce40da-9592-7e01-1c8a-69e4b1823cdc.jpeg)

リストjpltの行（「"・・・",」）を増やせば何件でも一度に変換できます。

```python:qiita2.py
jplt =["特許情報うんたら登録 7654321かんたら登録 7776665うんたら登録 7654321",
       "特許情報うんたら登録 6665554かんたら登録 5554443うんたら登録 6665554"]
```
２－２．ちょっと困ったこと
上記のプログラムで特許番号の抽出はできるのですが、分割出願のテキストデータで最初に挙げられている登録番号がテキストデータの中でもう１回出てくるのでだぶりが発生します。
だぶったままでは具合が悪いので、だぶり解消のため最初に挙げられた登録番号は代表登録番号として別の変数(fmly_1)に収めて、残りを変数fm_mbrに収めるようにしました。
```python:qiita3.py
import re
jplt =["特許情報うんたら登録 7654321かんたら登録 7776665うんたら登録 7654321"]
index =0 

for item in jplt: #リストjpltの要素の個数だけループする
    patinf = jplt[index]
    reglist =[]
    patinf_mod = patinf.split('登録')#文字列を「登録」で分割しリストpatinf_modに代入 
    for smpl in patinf_mod:
        smpl = smpl.replace(' ', '')#空白削除
        regno = re.search('[0-9]{7}', smpl)#登録番号（7桁の数値（0～9））を抽出
        if regno is not None:
            reglist.append(str(regno.group()))
    fm_1    = reglist[0]
    fm_mbr  =""
    row = 0
    for reg in reglist:
        if row > 0:
            fm_mbr= fm_mbr + reglist[row] +'\r\n'#改行を入れて登録番号を結合
        row += 1
    print("fm_1",fm_1)
    print("fm_mbr",fm_mbr)
    index += 1
```
以下のように抽出できました。
![4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3831931/385319ac-de2d-9271-54f6-53ee66322447.jpeg)
変数fm_mbr内でのだぶりが解消されました。

３．最後に
特許庁ではJ-platpatのアクセスを効率よくするためのAPIを提供していますので、大量に作業するのであればそれを使う方法もあるのですが、ユーザ登録が必要だったりしますので、手早く作業したいときには今回のようなやり方でも良いのかなと思っております。
以上何かのご参考になれば幸いです。
Parrot OS VirtualBox版の日本語化

# はじめに

Parrot OSをちょっと触ってみたかったので仮想環境(VirtualBox)用イメージをダウンロードしたのだが、仮想環境用イメージは英語環境になっていて日本語化するのに手間取ったのでまとめた。

# 環境

+ Parrot OS home Edition 6.1 (VirutalBox用イメージ)
+ VirtualBox 7.0

::: note info
Home EditionはParrot OSの中では`普段使い用(daily use)`として位置づけられている。
:::

# 日本語化

この記事で「日本語化」とは日本にいる日本語を使用するユーザーが使いやすい環境に設定することと定義する。具体的には以下の内容。

+ 日本語表示（日本語フォント含む）
+ 日本語キーボート
+ 日本語入力
+ 日本のタイムゾーン設定（日本標準時での時刻表示）

::: note warn
Parrot OSは「セキュアなOS」の一種で日本語化はその安全性をそこなう（らしい）。日本語化せず英語キーボードを使用したほうがより安全と思われる。（よりセキュアな環境が必要であればHome EditionではなくSecurity Editionを使えばいい、という考えもある）
:::

# 初期設定

VirtualBox用Home Editionを最初に起動するとユーザー名/パスワードの入力をスキップしてそのままMATEデスクトップ環境が表示される。少し時間がたつとインストール済みパッケージの更新を要求されるので初期パスワード`parrot`を入力すればパッケージが更新される。

::: note info
ユーザー名(`user`)、初期パスワード(`parrot`)はParrot OSのダウンロードページや、デスクトップ上の`passowrd.txt`ファイルに記載されている
:::

::: note warn
デスクトップ上の`passowrd.txt`ファイルは、再起動すると削除されてしまう（ゴミ箱にも残らない）ようなので注意
:::


当たり前だが、この時点で初期パスワードは変更すべきだろう。

::: note info
単純に`passwd`コマンドでパスワードを変更しようとすると失敗することがあった。原因はいろいろあるらしいが、今のところ以下のコマンドだとパスワードの変更に成功している。
```shell-session
$sudo passwd user
```
:::


# 設定方法

## 1. 日本語キーボードの設定

### 1.1. GUIツールを使用する方法（おすすめ）

次のコマンドでコマンドライン版GUIツールを起動し、2画面目「Keyboard layout」で[Other]→[Japanese]→(もう一度)[Japanese]を選択する。それ以外は変更なしですべて`<OK>`を選択する

```shell-session
$sudo dpkg-reconfigure keyboard-configuration
```
いったんログアウトか再起動するとキーボードの設定が変更される


## 1.2. 設定ファイルを直接変更する方法

`/etc/default/keyboard`を直接編集して、ログアウトか再起動するとキーボードの設定が変更される
```diff_shell:/etc/default/keyboard
# KEYBOARD CONFIGURATION FILE

# Consult the keyboard(5) manual page.

XKBMODEL="pc105"
- XKBLAYOUT="us"
+ XKBLAYOUT="jp"
XKBVARIANT=""
XKBOPTIONS=""

BACKSPACE="guess"
```

::: note info
エディタとしてvimを使う場合`:`を入力しやすいように、[Control Center]→[Keyboard]→[Layout]タブで[Japanese]を追加してからのほうが作業はやりやすいかもしれない。(エディタとして`nano`を使用する場合は特に不要)
:::

::: note warn
[Control Center]→[Keyboard]→[Layout]タブから[Japanese]を追加するだけだとユーザーレベルの設定になり、ログイン前のキーボード設定に反映されないなどの問題がある。
:::


## 2. 日本時間

次のコマンドでタイムゾーンを変更すると日本時間での表示になる（初期状態は`Etc/UTC`）

```shell-session
$sudo timedatectl set-timezone Asia/Tokyo
```

::: note info
デスクトップの時刻（右上）がなかなか変わらない場合は、いったんログアウトか再起動すれば変わる
:::

::: note info
Parrot OS Home EditionではNTPの設定はされていないので必要があれば設定する（パッケージの追加が必要）
:::

## 3. 日本語表示

次のコマンドでロケールを変更し、ログアウトか再起動するとMATEデスクトップ環境が日本語化される（メニューが日本語になる）

```shell-session
$sudo localectl set-locale ja_JP.UTF-8
```

::: note info
日本語用のロケールは最初から生成済みのため`dpkg-reconfigure locales`や`locale-gen`は不要
:::


## 4. 日本語入力

次のコマンドで日本語入力（並びに日本語環境周り）で必要なパッケージをインストールし、ログアウトか再起動すると日本語入力が可能になる

```shell-session
$sudo apt install task-japanese task-japanese-desktop
```
::: note info
日本語入力の設定は[コントロールセンター]→[Mozcのプロパティ]で変更できる
:::



# 最後に

ここまで記事を書いておいてなんだが、この記事に記載した日本語化をすべて実施するのであれば最初からLive環境(isoイメージ)を使用してインストールしたほうが簡単確実で柔軟性は高いような気もする。

また、Parrot OSは初めて触ったので推測だが、debian（Parrot OSはdebianベース）＋MATEデスクトップ環境の日本語化とほぼ同じな気もする。




 # 参考情報

+ [Parrot OS](https://www.parrotsec.org/)
+ [Qiita記事「ParrotOS 5.2 でハッキングラボをつくってみる ２ 設定編（パッケージのアップデート、日本語化など」）](https://qiita.com/kagirohi/items/632e46ed3484f3693e03)
ShitSaaS 最悪のスタートアップのアイデアを共有し、投票するサービス

## はじめに
スタートアップの世界は、野心と希望で満ち溢れています。しかし、その光輝く舞台から少し視線を逸らすと、多くの夢が影に消えています。

新興企業の大半が失敗という名の厳しい現実に直面しますが、その数々の挫折と失敗は静かに闇の中に隠れ、知る手段は限られています。ですがその不可視の部分にこそ多くの教訓や物語が潜んでいます。

そんな失敗したスタートアップを紹介・共有・投票してランキング表示することができるサービスこそが[ShitSaaS](https://www.shitsaas.com/)です! 

正直ベースな話、この記事誰得？　みたいな運営のテーマを見て、ニッチな技術ではなく、ニッチなサービスで書こうと思いたって気の迷いで書いた記事なので、優しいお気持ちで御覧ください。~~実際にはRank(投票された結果による順位)と、STARTUP(Startup名)、REVENUE(収益)、CREATOR(作者)くらいしか確認できません。~~

## 実際に使ってみる。

１. [ShitSaaS](https://www.shitsaas.com/) にアクセスすると下記の画面になるので、 `Get ShitSaaS` を押下します。
![スクリーンショット 2024-06-25 3.00.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/210923/a0c0e95e-a211-ffb5-7d75-8ae465bea3df.png)

２. 現在は Google のOAuth2(OpenIDConnect)連携でしかログインできなさそうなので、 `Sign In With Google` を押下します。
![スクリーンショット 2024-06-25 3.29.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/210923/5dec7532-9fda-5958-bcc7-f6e276d938c9.png)

３. 下記のリクエストが飛び、認証用のページにリダイレクト(HTTP Status code 302)します。

- https://accounts.google.com/o/oauth2/v2/auth?client_id=696422298108-tjdgotspvhnkkedbdc88q3ca58sj66sl.apps.googleusercontent.com&scope=openid%20email%20profile&response_type=code&redirect_uri=https%3A%2F%2Fwww.shitsaas.com%2Fapi%2Fauth%2Fcallback%2Fgoogle&state=FyWmz2YeYV0lwN7UPXq8U83Y-o7v97GTiQDH3pI-pIs&code_challenge=PkFW367JV0eGVcKMhSXNaOAD-f0_rGoAICyt89E90t0&code_challenge_method=S256

余談ですが、パラメーターの redirect_uri を見る限り、他の IDプロバイダーとの連携も想定していそうに見えます。

４. Googleのログイン画面につくのでログインします。
![スクリーンショット 2024-06-28 0.11.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/210923/b726306b-ffb3-d1cc-3e05-5bf0b606fdbd.png)

５. ログイン及び許可を行うと下記の画面に移動します。この画面は自分のSaaSを登録できる画面のようですが、一旦右上の Leaderboard から他SaaSの情報を見てみます。
![スクリーンショット 2024-06-28 23.57.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/210923/40e7b553-b8d3-4b06-1032-229e1315b2a8.png)

６. 下記のようなリーダーボードが表示され、下記の画像のようにRank(投票された結果による順位)と、STARTUP(Startup名)、REVENUE(収益)、CREATOR(作者)が確認できます。
![スクリーンショット 2024-07-13 0.12.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/210923/99b3c448-da72-061f-bd35-31255059c5ea.png)

皆さんもお気づきだと思いますが、まだ圧倒的にデータが少ないです。
登録されたスタートアップ数は９つしかありません。
また、９件のうち２件しか儲かっておらず７件赤字です…世の中厳しい。

## 後書き
今はまだ９つしかスタートアップが登録されていませんし、情報がかなり少ないです。

ですが閲覧用途かもしれませんが、Creator登録は380人を超えていそうなので、
面白いサービスの発見のためにもこのサービスの発展と成長を見守っていこうかと思います。