OmniAICreator/Qiita-1.07M huggingface dataset:
Xcodeクラッシュ時の対応備忘録

## 概要
Xcodeでビルド中していたところXcodeがクラッシュし、以降プロジェクトを立ち上げても直ぐにクラッシュしてしまい編集、ビルドができなくなってしまったため修復にあたっていくつか過去の参考事例があり試してみたのでその結果と解決策について備忘録兼ねてまとめておきます。
結論から言うと破損したファイルへのリンク情報がXcodeをアンインストールしても残り続けておりそれが悪さしておりました・・・というお話です。
基本的なXcodeの異常は確認内容1～5のどれかで解決すると思います。

検証した環境は以下の通りです。
### 動作環境
H/W：MacMini（2020 M1)
OS：MacOS Sonoma 14.5
Xcode : 14.5

## エラー内容
エラー内容ですが新規プロジェクトを立ち上げようとしても一瞬立ち上がるものの直ぐにクラッシュし、ウィンドウが閉じてしまうといった感じでした。エラーログを見たところ原因はScenekit系のレンダリング周りでアクセスエラーが原因臭い感じでした。
```
Crashed Thread: Dispatch queue:
com.apple.scenekit.renderingQueue.SKESceneView0x3207c9700

ExeptionType: EXC_BAD_ACCESS(SIGSEGV)
ExeptionCodes: KERN_INVALID_ADDRESS
```

## 確認内容
Scenekitのレンダリング系で落ちているのでクラッシュする前に開いていた3Dモデルデータの一時ファイルが何か悪さしているのか？と思いTeratailや海外サイトにいくつかXcodeがクラッシュし立ち上がらなくなった際の対応方法を確認したところいくつか解決策があったので以下の1～5をまず確認してみました。
1. Xcodeの再インストール
　→Xcodeを削除後、AppStore経由で再インストールを試みたものの症状に変化なし
1. xcrun --kill-cache
　→症状に変化なし
1. xcodebuild -alltarget clean
　→症状に変化なし
1. /Library/Developer/Xcode/DerivedDataを削除
    そもそも↑のディレクトリに該当するフォルダがない・・・と思ったらM1Macの場合、/user/${USER_NAME}/Library/Developer/DerivedDataにフォルダが生成されてました。なんじゃそりゃ・・・。で、削除してみたところ症状に変化なし。

と大体調べて出てくる1～5を試しても症状が直らないので藁にも縋る気持ちで過去のプロジェクト等の展開情報を管理しているファイルが無いか探したところ・・・ありました！
/user/${USER_NAME}/Library/Autosave infomation/com.apple.dt.Xcode.plits
なるここ最近開いたプロジェクトのリンク？等を一時ファイルとして保存している上記のファイルがありこのファイルを削除することで(私はファイルそのものを削除しましたがファイル削除せずとも中の原因のファイルに関する記述を消すだけでいいと思います）で無事Xcodeが立ち上がるようになりました。
~~有難迷惑~~素敵な機能のおかげでXcodeをアンインストールしようが何しようが残り続けているので気づくまでに遅れてしまいました・・・。

もしXcodeが何してもクラッシュして立がらない＆クラッシュログの内容がファイル破損等でなければ是非最後の手段として試してみてください。
wp_optionsに相当するテーブルはdrupalにあるのか

# 説明
wp_optionsの設計ってデータベース設計の観点からするとアンチパターンだと思うのですが...
独自のプラグイン設定管理テーブルをつくらずに、ちょっとしたモジュールの設定値を記録管理する分には便利だったりします。

なので、drupalでも用意されているかなと思って調べてました。
僕の調べ方が悪いのかそれらしい記事やドキュメントが見当たりませんでした。
なので、テーブルを一つずつ見ていくと、おそらく、configテーブルがそれに該当しそうです。(値はblob型)

![test1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280639/e1c35cc4-086d-d9cb-c35b-885c8aaa2800.png)

なので、このテーブルに設定値を読み書きできれば、わざわざテーブルを作らずに、設定値の管理が行えそうです。
実際にできるか試すと、「ConfigFormBase」継承してフォームを作成すると簡単に↓モジュールの設定のフラグ管理が行えました。

![test1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280639/bd904b28-eb56-ffc8-3efe-798b5226b417.png)


https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Form%21ConfigFormBase.php/class/ConfigFormBase/8.9.x

## 実際に作成したモジュール
リキャプチャをログイン画面に設定したり、ログイン画面のルーティングを変更できたりするモジュールです。

https://github.com/teratai3/login_guard/tree/main


## 余談
他のcmsでもwp_options相当テーブルが用意されています。

・basercms
site_configテーブル
→値はtext型

・movabletype
mt_plugindataテーブル
→値は、blob型

ここに上げたcms以外でも似たようなテーブルが用意されていた気がするので、調べてみるのも面白いかもしれません
【Tauri・Rust・Vue3】ストレージの使用状況をサンバースト図により可視化するためのアプリを作成しました

# 作ったもの
https://github.com/fksms/DirWalker

![Screenshot_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846452/59730857-ee8c-07cf-7e24-d0fd22e8176f.png)

![Screenshot_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846452/be62ac0c-e633-a3fc-fed4-0a01beb8e760.png)

![Screenshot_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846452/7a20bade-c871-3a9c-dc9c-1633106ce997.png)


# アプリの特徴
- ストレージの使用状況をサンバースト図により可視化することができます。サンバースト図のアークを左クリックすると、サンバースト図やリストが自動的に更新されます。アークを右クリックすると、コンテキストメニューが開き、OSの標準ファイルマネージャーで該当のディレクトリを開いたり、該当のディレクトリ・ファイルのパスをクリップボードにコピーしたりすることが可能です。

<p></p>

- デフォルトでは、OSのルートディレクトリをスキャンする仕様になっていますが、スキャンしたいディレクトリを指定することで、より高速にスキャンすることが可能です。また、スキャンさせたくないディレクトリを複数設定することも可能です。

<p></p>

- フレームワークはTauriを利用しているためマルチプラットフォーム対応で、Linux、macOS、Windowsで動作することを確認済みです。

<p></p>

- フロントエンドの処理はVue3 + Javascript、バックエンドの処理はRustで書かれています。処理が重いスキャン部はRustで書かれており、マルチスレッドで高速にスキャン可能です。また、以下のライブラリやコードを利用しています。
  - [Dust](https://github.com/bootandy/dust)
  スキャン処理用にソースを改変して利用
  - [Tauri Plugin Context Menu](https://github.com/c2r0b/tauri-plugin-context-menu)
  Tauri v1では、OS標準のコンテキストメニューが使えないためプラグインとして利用
  - [Opener](https://github.com/Seeker14491/opener)
  ファイルマネージャーを開くために、Tauri標準のopen機能が使えなかったため利用
  - [D3.js](https://d3js.org/)
  サンバースト図描画用
  - [Vuetify](https://vuetifyjs.com/)
  V-Data-Table等UIで利用

# ビルド・インストール方法
[GitHub](https://github.com/fksms/DirWalker)をご確認ください。

# アプリを作った背景
macOS向けの[DaisyDisk](https://daisydiskapp.com/)（ストレージの使用状況をグラフィカルに可視化するためのアプリ）に感化されたのが背景です。
後はTauriやVueの勉強用。

# その他
Issueへの投稿、PullRequest大歓迎です。 バグや改善点を見つけた場合は、遠慮なくPullRequestを送ってください。 英語が苦手なので、英訳も大歓迎です。
（英訳はChatGPTに丸投げしたので。。。）
33業種×エンジニア：ガラス・土石製品

## はじめに
転職を始める際、自分ができることを加味したうえで求人情報を確認しますが、あえて33業種の側からみてみて、どのような働き方、どんな会社があるのかを知りたいと思います。
世界と日本でどんな企業が有名なのかも知りたいと思います。

## ガラス・土石製品×エンジニアの働き方の例
#### 1. システムエンジニア（SE）
製造プロセスを管理するシステムの設計・実装、各種ソフトウェアツールの統合、製造ワークフローの最適化を行う。
例：ERP（Enterprise Resource Planning）システムを開発し、在庫管理、生産スケジュール管理、品質管理プロセスを統合的に管理する。

#### 2. プログラマー
製造設備や生産ラインの制御システム、品質管理システム、データ解析ツールなどのソフトウェアの開発を担当する
例: 製造ラインの自動化を支援するソフトウェアのコーディング、製品検査データを解析するためのプログラムを作成する。

#### 3. サーバーエンジニア
製造関連システムを支えるサーバーの設計、構築、運用、保守を担当する。
例: 製造データをリアルタイムで収集し、分析するためのサーバーインフラの構築と管理。

#### 4. ネットワークエンジニア
製造工場内および企業全体のネットワークの設計、構築、管理を行います。データの安全な伝送とシステムの安定運用を確保する。
例: 工場内のIoTデバイスと中央管理システムを接続するためのネットワークインフラの設計と最適化。

#### 5. データベースエンジニア
製造プロセスや品質管理データを効率的に管理するデータベースの設計、実装、運用、保守を担当する。
例: 製造データの蓄積と解析を容易にするためのデータベースシステムの構築と最適化。

## 世界大手企業の概要
[Saint-Gobain (サンゴバン)](https://www.saint-gobain.com/en)
1665年に設立されたフランスの多国籍企業で、建設、工業、交通機関など様々な市場向けに先進材料やソリューションを提供しています。特にガラス製品で知られ、建築用ガラス、自動車ガラス、特殊ガラスなどを製造しています。

[Corning Incorporated (コーニング社)](https://www.corning.com/worldwide/en.htm.)
アメリカの多国籍企業で、1851年に設立されました。特殊ガラス、セラミックス、関連材料の製造に特化しており、ディスプレイ技術、通信、ライフサイエンス、環境技術などの分野で広く活用されています。

## 日本大手企業の概要
[AGC株式会社](https://www.agc.com/)
1907年に設立された日本の企業で、旧名は旭硝子。建築、自動車、電子機器向けのガラス、化学品、セラミックスなどを製造しています。グローバルに展開し、先進材料とソリューションを提供しています。

[日本板硝子株式会社](https://www.nsg.com/en/)
1918年に設立され、建築、自動車、電子機器向けのガラス製品を製造しています。世界中に製造拠点を持ち、先進技術と高品質な製品で市場をリードしています。

[三菱マテリアル株式会社](https://www.mmc.co.jp/corporate/ja/)
1950年に設立され、ガラス、セメント、金属、電子材料など幅広い製品を提供する総合素材メーカーです。持続可能な社会の実現に向けた技術開発と事業展開に取り組んでいます。

## さいごに、求人票を検索してみて
「AWS活用に伴う技術的支援」「IT基盤の構築」「PMO業務」「情報セキュリティ強化」「社内システムエンジニア」などの文言を確認することができました。実際の業務イメージが想像しにくいように感じました。そこは、選考に通った方や、長年似たような業務を行っていた方が強いのかな…。ガラス・土石とエンジニアって想像しにくい
Live_Portrait_Monitor　を ローカルで使う動画生成AI

動画生成AIを使ってみた

動画をアップできないので
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">静止画→動画を3秒で作ることができる。色々な女優で試したけど、すごくきれいにできる。15秒のcmなんて静止画1枚でできちゃうでしょ <a href="https://t.co/sZkH8DdlBw">pic.twitter.com/sZkH8DdlBw</a></p>&mdash; ⁂ コロまる ™ 🍼 (@ma7ma7pipipi) <a href="https://twitter.com/ma7ma7pipipi/status/1816781499624260027?ref_src=twsrc%5Etfw">July 26, 2024</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


https://github.com/Mrkomiljon/Live_Portrait_Monitor?tab=readme-ov-file#live_portrait_monitor

上記に書いてあるようにやればいいんだけど、注意点。

ファイルを指定する場合は

```
python inference_org.py -s assets/examples/source/hage.jpg -d assets/examples/driving/d3.mp4 --no_flag_pasteback
```

と、写真パスと動画パスを同時に指定すること。


```
# to use monitor
python inference_monitor.py -s assets/examples/source/MY_photo.jpg 

# or disable pasting back
python inference_monitor.py -s assets/examples/source/s9.jpg -d assets/examples/driving/d0.mp4 --no_flag_pasteback

# to use original code for inference 
python inference_org.py -s assets/examples/source/s9.jpg -d assets/examples/driving/d0.mp4 --no_flag_pasteback

# more options to see
python inference_org.py -h
```

とある中で、

```
python inference_monitor.py -s assets/examples/source/MY_photo.jpg 
```

と画像だけ指定する場合はエラーになる。

```
File "C:\Users\xxx\liveportrait\Live_Portrait_Monitor\src\live_portrait_pipeline_monitor.py", line 620, in process_frame
    frame_resized = cv2.resize(frame, (256, 256))
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
cv2.error: OpenCV(4.10.0) D:\a\opencv-python\opencv-python\opencv\modules\imgproc\src\resize.cpp:4152: error: (-215:Assertion failed) !ssize.empty() in function 'cv::resize'

```

こんな感じ
フロントエンドでのdigメソッドの使い方

## digメソッドとは
digメソッドは、Rubyのメソッドでありハッシュや配列などのデータ構造に対し、指定したキーまたはインデックスを使用して要素にアクセスできるメソッドです。

## 使い方

例えば、下記のデータへアクセスする場合には、下記のような方法でデータを取得できます。
```
data = {
  user: {
    name: "kaihatu tarou",
    address: {
      country: "Japan",
      region: "aichi"
    },
    orders: [
      { id: 1, product: "1" },
      { id: 2, product: "2" }
    ]
  }
}
```
```
name = data.dig(:user, :name)
# ＝> "kaihatu tarou"
```

下記のように、他のキーと値が含まれる場合でも、digメソッドを使用することができます。以下のコードでは、item_hash の中にある status_id キーに対応する値の "1 (0から数えた場合)" 番目の値を比較する処理が実行されます。
```
item_hash = {
  "status_id" => [10, 2, 7],
  "other_key" => "example",
  "more_keys" => [1, 2, 3]
}
```
```
item_hash.dig("status_id", 1) == 2

item_hash.dig("status_id", 1000) == 1
# ＝> nil
```

## 特徴
digメソッドの特徴としては、存在しない要素にアクセスするとnilが返されることです。
これにより、安全に要素へアクセスできます。

```
array = [A, B, C]
result = array.dig(5)
# ＝> nil
```
```
item_hash = {
  "status_id" => [10, 2, 7],
  "other_key" => "example",
  "more_keys" => [1, 2, 3]
}

item_hash.dig("status_id", 1000) == 1
# ＝> nil
```

参考サイト：
https://wingdoor.co.jp/blog/%E3%80%90ruby%E3%80%91dig%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6/
【オブジェクト型】同じ値でも比較結果がfalseになる理由

# はじめに

同じ値のオブジェクト型について、比較結果がfalseになるのはご存知でしょうか？最近動画を使って勉強をしている中で、個人的には割とびっくりした内容でした。

実際に下記のようなソースコードを書いてみると、値が同じであるにもかかわらず、falseと判定されてしまいます。

```js
// オブジェクト型
const o1 = {"age": 20};
const o2 = {"age": 20};

console.log(Object.is(o1, o2)); // 比較結果が「false」と判定される
```

そこで、本記事では同じ値のオブジェクト型での比較結果がfalseになる理由を紹介します。

# プリミティブ型とオブジェクト型の違い

前提として上記の理由を説明する前に、オブジェクト型との比較結果が異なるプリミティブ型についても併せて紹介します。

|種類|型の具体例|
|:-:|:--|
|プリミティブ型(基本型)|String型, Number型, Boolean型, undefined型, null|
|オブジェクト型|配列, オブジェクト などプリミティブ型に該当しないもの|

```js
// プリミティブ型の例
const p1 = "string"; // string型
const p2 = 1; // number型
const p3 = true; // boolean型
const p4 = null; // object型(null自体はobject型に該当)

// オブジェクト型の例
const o1 = [1, 2, 3]; // object型(配列もobject型に該当)
const o2 = {"age": 20}; // object型
```

次に、本題である「比較結果がfalseになる理由」についてプリミティブ型と比較しながら説明していきます。理由を知るには、javascriptのメモリ内部の仕組みを理解することが必要になってきます。

# メモリ内部の仕組み

比較結果がfalseになる理由を知るためには、プリミティブ型とオブジェクト型とで、メモリへデータが保存される仕組みに違いがあることを理解する必要があります。

### プリミティブ型

プリミティブ型では、下記ソースコードを記載すると、trueが返却されます。
```js
const p1 = 100;
const p2 = 100;

console.log(Object.is(p1, p2)); // true
```

下図のように、プリミティブ型は<font color="red">**直接的**</font>に値をメモリに保存し、これらの値を比較します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3661690/96aba4a5-e07e-331e-5fd1-3cab364396d2.png" width="50%">


### オブジェクト型

一方でオブジェクト型では、上記で挙げた通り、falseが返却されます。

```js
// オブジェクト型
const o1 = {"age": 20};
const o2 = {"age": 20};

console.log(Object.is(o1, o2)); // 「false」と判定される
```

下図のように、オブジェクト型は<font color="red">**間接的**</font>に値をメモリに保存し、番地同士で値を比較します。そのためオブジェクト自体は値が同じであっても、**番地が異なる**ことより、比較結果がfalseになるというわけです。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3661690/d309311e-5939-4860-5c68-51dad83e2c81.png" width="50%">


# まとめ

プリミティブ型とオブジェクト型での比較結果についてまとめると、下表の通りになります。

|種類|メモリ保存方法|同じ値での比較結果|
|:-:|:-:|:-:|
|プリミティブ型|直接的(値比較)|true|
|オブジェクト型|間接的(番地比較)|false|

最後まで目を通していただいてありがとうございました！
【Python3】【殿堂入りキャンペーン】村人の友好関係 (paizaランク S 相当)：アルゴリズム付きの解説

https://paiza.jp/works/mondai/s_rank_skillcheck_archive/group_popularity

この問題では、村人の同好会グループの管理と人気度の計算を効率的に行う必要があります。Union-Findデータ構造を用いることで、友好関係を管理し、入退会ログに基づいて人気度を計算することができます。

### アルゴリズム設計

**概要:**
- 村人間の友好度データを受け取り、Union-Findを用いて管理します。
- 各村人が同好会に入退会するたびに、同好会の人気度を計算します。

### 手順

1. **Union-Findクラスの定義**:
   - `find`メソッドでルートを探し、パス圧縮を行う。
   - `union`メソッドで2つの集合を結合する。

2. **データの読み込み**:
   - 村人の数 `N`、友好関係の数 `M`、ログの数 `Q` を読み取る。
   - 友好関係のデータをリスト `all_edges` に格納し、友好度の降順でソートする。

3. **最小全域木（MST）の構築**:
   - Union-Findを用いて友好関係をMSTに追加する。

4. **同好会の入退会の管理**:
   - 入退会ログを処理し、同好会に所属する村人の状態を管理するリスト `is_member` を更新する。
   - 入退会ごとにMSTを用いて人気度を計算する。

### 完成したコード

```python
# utf-8
class UnionFind:
    def __init__(self, size):
        self.par = [-1 for _ in range(size)]
    
    def find(self, x):
        if self.par[x] < 0:
            return x
        else:
            self.par[x] = self.find(self.par[x])
            return self.par[x]
    
    def union(self, x, y):
        x = self.find(x)
        y = self.find(y)
        
        if x == y: return False
        if self.par[x] <= self.par[y]:
            self.par[x] += self.par[y]
            self.par[y] = x
        else:
            self.par[y] += self.par[x]
            self.par[x] = y
        
        return True
        

if __name__ == "__main__":
    import sys
    input = sys.stdin.read
    data = input().split()
    
    index = 0
    N = int(data[index])
    M = int(data[index + 1])
    Q = int(data[index + 2])
    index += 3
    
    all_edges = []
    for _ in range(M):
        a = int(data[index]) - 1
        b = int(data[index + 1]) - 1
        f = int(data[index + 2])
        index += 3
        all_edges.append((f, a, b))
    
    all_edges.sort(reverse=True)
    
    uf = UnionFind(N)
    mst_edges = []
    for f, a, b in all_edges:
        if uf.union(a, b):
            mst_edges.append((a, b, f))
    
    is_member = [False] * N
    answers = []
    
    for _ in range(Q):
        op = data[index]
        member = int(data[index + 1]) - 1
        index += 2
        
        if op == "+":
            is_member[member] = True
        else:
            is_member[member] = False
        
        answer = 0
        for a, b, f in mst_edges:
            if is_member[a] != is_member[b]:
                answer = max(answer, f)
        
        answers.append(answer)
    
    sys.stdout.write("\n".join(map(str, answers)) + "\n")
```

### 説明

- **Union-Findクラス**: 
  - `__init__`メソッドで初期化し、`find`メソッドでルートを見つけ、`union`メソッドで集合を結合します。
  
- **データの読み込みとMSTの構築**:
  - 入力データを読み込み、友好関係を降順にソートします。
  - Union-Findを用いてMSTを構築します。

- **同好会の入退会の管理と人気度の計算**:
  - `is_member`リストで各村人の同好会所属状態を管理します。
  - 入退会ごとにMSTを参照し、同好会内外の最大友好度を計算します。

このアルゴリズムは、各ログエントリに対して効率的に同好会の人気度を計算することができます。
DynamoDB Local

## 概要

DynamoDB をローカル環境で利用する

[https://github.com/idenrai/templates/tree/main/dynamodb_local](https://github.com/idenrai/templates/tree/main/dynamodb_local)

## 詳細


### 準備

#### Docker

Docker Desktop インストール

[https://docs.docker.com/desktop/install/mac-install/](https://docs.docker.com/desktop/install/mac-install/)

#### AWS

##### AWS-CLI

[https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)

##### boto3

```
pip install boto3
```

[https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html)

##### Configure

円滑な利用のため、AWS Credentials 設定が必要

```
aws configure
```

以下のように設定

```
$ aws configure
AWS Access Key ID [None]: dummy
AWS Secret Access Key [None]: dummy
Default region name [None]: ap-northeast-1
Default output format [None]: json
```

手動設定の場合は以下になる

```
touch ~/.aws/credentials
vi ~/.aws/credentials
```

```
[default]
aws_access_key_id = dummy
aws_secret_access_key = dummy
```

```
touch ~/.aws/config
vi ~/.aws/config
```

```
[default]
region = ap-northeast-1
output = json
```

### Code

以下の２つを利用

[amazon/dynamodb-local](https://hub.docker.com/r/amazon/dynamodb-local)
[aaronshaf/dynamodb-admin](https://hub.docker.com/r/aaronshaf/dynamodb-admin)

docker-compose.yml

```
version: "3.8"
services:
  dynamodb-local:
    command: "-jar DynamoDBLocal.jar -sharedDb -dbPath ./data"
    image: "amazon/dynamodb-local:latest"
    container_name: dynamodb-local
    ports:
      - "8000:8000"
    volumes:
      - "./docker/dynamodb:/home/dynamodblocal/data"
    working_dir: /home/dynamodblocal

  dynamodb-admin:
    container_name: dynamodb-admin
    image: aaronshaf/dynamodb-admin:latest
    environment:
      DYNAMO_ENDPOINT: dynamodb-local:8000
    ports:
      - "8001:8001"
    depends_on:
      - dynamodb-local
```

### Run

```
docker-compose up
```

### Test

```
aws dynamodb list-tables --endpoint-url http://localhost:8000
```

以下のように出力されたら OK

```
$ aws dynamodb list-tables --endpoint-url http://localhost:8000
{
    "TableNames": []
}
```

#### GUI

8000 で DynamoDB を, 8001 で GUI を起動するので、GUI からも確認可能

[http://localhost:8001/](http://localhost:8001/)
現場で学んだ大事な事の振り返り

## はじめに
SESとしての初現場が決まり、いざ現場に出た時の緊張はいまだに忘れません。
その期間の中で私が学んだことを、初心忘るべからずと思ったので2つまとめてみます。

#### よく言われているコミュニケーションはやはり大事
チームの中で困ったらその人に聞いてと言われていたのと席が近いのもあり、いつも質問していた方が休みの日がありました。その日に不明点などあったので別の方に聞こうと思ったのですが、普段あまり接する時間がなく他の方の都合のいいタイミングが分かりづらく聞くのに躊躇してしまうこともありました。その時に思ったことはいつも特定の方に聞くのではなく内容によっては聞く人を変えたり、出勤時や退勤時に少しでも話すタイミングがあればコミュニケーションを取ればよかったということです。なので翌日から内容によっては聞く人を変えたり出社時には軽くコミュニケーションを取ることを意識して行うようにしました。現在はその経験を活かすことが出来ています。

#### 質問力もやはり大事
今回の現場で初めて使うツールがありました。エラーについて調べても出てこないので聞くしかありませんでした。使い始めのうちはエラーメッセージを読んでも解決法が分からず、そもそも設定を変えないといけない、などの内容もありました。質問をした時にも、あそこの設定はどうしてる？この手順で試してる？など聞かれても理解不足でもう一度確認してきます、などの二度手間になることもありました。その後はツールや業務にも少し慣れたこともあり、質問の質が上がり短時間で解決できるようになりました。

### さいごに
初めて現場に出て特に思ったことは、業務内容以外にも学ぶことはたくさんあるということです。
普段のコミュニケーションを取るのが上手な人、説明がとても分かりやすい人など、こういう人達で出来たチームは仕事がしやすく進捗も上がるのではないかとも考えています。なので必要とされる人になれるように今後も日々努力を惜しまず、尽力していきます！
AOSP(Android Open Source Project)をちまちま読んでいくブログ - 目次

twitter :

https://twitter.com/IKent1mm
# 目次
- Android 14 でのDozeの挙動について
  - https://qiita.com/I-Kent/items/bc1d37c7cc82b95446a4
<br>

- ドキュメントに書かれていないエラーで苦労した話
  - https://qiita.com/I-Kent/items/431275031f6f8dc821b7



# コメント
Androidのアプリケーション開発に少し関わるようになり、感じたことがあります
それは「中国語と英語で検索かけた方が情報が見つかるのが早い」ということ
いや、分かりますよ。母数の問題だったりだとは思うんです
でも、ちょっと昔のコードだと日本語でも結構見つかるんです

多分ですが、そういう記事を書いてくれていた方々は、皆つよつよエンジニアになって「そんなこと書かなくてもわかるやん」って感じになったのかなと自分は思うのです
それはそれでしゃーないと思うけど、事実自分は困ってたりして…

んで、そこで「悲しいな」で終わるとなんか生産性の終了な気がするし、自分が欲しいと思ってことはきっとニーズがあると思うわけですよ

なのでこの日記のようなブログを書いていきます
間違いだらけだったりするとは思うんですが、間違いを見つけた際は暖かく指摘いただければなと思います！
Google App ScriptとLINEbotでテキストとスタンプを同時に送りたい

Google App ScriptとLINEbotを使って旅行までのカウントダウンや旅行当日の天気予報をメッセージとして送れるようにしたが、メッセージだけではやはり寂しいのでメッセージと同時にLINEスタンプを送れるようにしました。

```
//LINEbotを作成し、APIキーを下の'YOUR_LINE_ACCESS_TOKEN'に入れてください
const LINE_ACCESS_TOKEN = 'YOUR_LINE_ACCESS_TOKEN';


// スタンプパッケージIDとスタンプIDのリスト
const STAMP_PACKAGE_ID = 1070;
const STAMP_IDS = Array.from({length: 17878 - 17839 + 1}, (v, k) => k + 17839);

/**
 * ランダムなスタンプとテキストメッセージを送信する関数
 * @param {string} text - 送信するテキストメッセージ
 */


function sendRandomStampWithText(text) {
  // スタンプIDをランダムに選択
  const randomStampId = STAMP_IDS[Math.floor(Math.random() * STAMP_IDS.length)];
  
  // LINE Messaging APIのエンドポイントURL
  const url = 'https://api.line.me/v2/bot/message/broadcast';

  // 送信するメッセージデータ
  const messageData = {
    
    messages: [
      {
        type: 'text',
        text: text
      },
      {
        type: 'sticker',
        packageId: STAMP_PACKAGE_ID.toString(),
        stickerId: randomStampId.toString()
      }
    ]
  };

  // HTTPリクエストのオプション
  const options = {
    method: 'post',
    contentType: 'application/json',
    headers: {
      'Authorization': 'Bearer ' + LINE_ACCESS_TOKEN
    },
    payload: JSON.stringify(messageData)
  };

  // HTTPリクエストを送信
  const response = UrlFetchApp.fetch(url, options);
  
  // レスポンスをログに表示
  Logger.log(response.getContentText());
}

```

ここでは、sendRandomStampWithText()を実行する際、引数に送信したいLINEのメッセージ内容をもたせることでそのLINEの内容と私の気に入ったLINEスタンプの中からスタンプが一つランダムに送られるというものになっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2971002/b1bdfd50-3015-96cb-aa53-13d3584f6de2.png)

気に入ったと言っても上記のパッケージIDが1070の中のスタンプが送られるというものです。

他のが良ければ、簡単に変えられるのでぜひ変えてみてください。

また、もっとこうしたほうがわかりやすいとか動作が早いという案があれば教えていただきたいです。

それでは、以上！
Tomcatのポート番号を環境変数で定義・変更する方法

## 1． はじめに
SpringBoot等のモダンなアプリケーションではポート番号を環境変数で容易に変更することが可能です。それに倣い、Tomcatで動作しているJavaアプリをコンテナ化するというレガシーシステムのクラウドリフト案件で起こりえるケースを前提とし、Tomcatのポート番号を外部（環境変数）から変更可能とする方法について説明したいと思います。

## 2． 検証環境・バージョン

* OS : Windows 11 Pro 23H2
* Java : Corretto-17.0.12.7.1
* Apache Tomcat : 10.1.26

## 3． 設定方法

```xml:%CATALINA_HOME%/conf/server.xml
<!-- ⭐️　ポイント1 -->
<Connector port="${server.port}" protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443"
           maxParameterCount="1000"
           />
```
⭐️　ポイント1
設定ファイル（server.xml）の設定値として環境変数を参照したい箇所を`${キー}`形式で定義します。
今回のサンプルではhttpコネクタのport属性のみですが、他のコネクタ（ajpコネクタ）や他の属性（redirectPortt等）も同様に設定可能です。

```bat:%CATALINA_HOME%/bin/setenv.bat
@echo off
rem ⭐️　ポイント2
set JAVA_OPTS=-Dserver.port=%SERVER_PORT%
```
⭐️　ポイント2
デフォルトでは`setenv.bat`ファイルは存在しないので新規に作成します。※ Linuxの場合は`setenv.sh`
設定ファイル（server.xml）で参照している`${キー}`形式の値をJAVA_OPTSにシステムプロパティとして定義します。
つまり環境変数ではなくシステムプロパティを参照しているが正しい説明になります。
システムプロパティの定義時に環境変数を参照することで、推移的に環境変数で定義できるようにしています。

## 4． 動作確認
環境変数`SERVER_PORT`にポート番号：8083を定義してTomcatを起動してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195748/240aa499-935c-8ba2-a9be-a3e99a2c9760.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195748/62e06bef-53e8-abd0-8be6-abfc724e16d1.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195748/a8901f49-278e-8474-5c57-56601f4f100a.png)

## 5． さいごに
`JAVA_OPTS`とシステムプロパティを利用し、Tomcatのポート番号を環境変数で定義する方法について説明しました。
[Twelve-Factor App](https://12factor.net/ja/) を踏まえるとアプリ単位でTomcatコンテナを立ち上げる場合、ポート番号を環境変数で変更・定義できることは重要です。
コンテナをどのような環境で動かすのかはコンテナ利用者の裁量であり、コンテナ提供者が決めるべきものではないからです。
パブリッククラウドにおけるコンテナの実行、例えばAWSのECSでは環境変数を連携（パラメータストア等）できるように最初からデザインされています。
クラウドリフトするのではあれば、できるかぎりクラウドに適した構成を心掛けましょう。
Seabornのcatplotで引数にaxを渡してグラフを並べて表示させる方法

# はじめに

データ分析する際にSeabornを使用するのですが、グラフを並べて表示したいと思いました。
`matplotlib`では`plt.subplots`を使用して1つの`fig`に複数の`ax`を入れることができ、seabornでも同様にしてできそうかと思ったのですが、`catplot`だけは簡単にできなかったので備忘録として書きます。



# まずは結論

https://seaborn.pydata.org/generated/seaborn.catplot.html

上記のリファレンスを読み`seaborn.catplot(kind="swarm")`だったら`seaborn.swarmplot(ax=ax)`にするだけ！！



# 詳しい説明

seabornでは基本的に、plotをする関数の引数の`ax`にmatplotlibで作成したaxを渡すだけで、図中にseabornで作成したグラフを入れることができます。

例えば`kdeplot`関数では、

```python
import seaborn as sns
y = "列名" 
fig, axes = plt.subplots(2, 2, figsize=(2*1.4*3.8, 2*3.8),dpi=300, tight_layout=True, )
sns.kdeplot(hue="type", x=y, data=data, shade=False, ax=axes[0,0])
```

といったように引数に`ax`を追加して渡してやるだけでpltで作成したfigureにグラフを入れることができます。

しかし、`catplot`関数に同様に引数に`ax`を追加して渡してやっても反映されないという問題に遭遇しました。

いろいろ調べた結果、


>stripplot() (with kind="strip"; the default)
swarmplot() (with kind="swarm")
boxplot() (with kind="box")
violinplot() (with kind="violin")
boxenplot() (with kind="boxen")
pointplot() (with kind="point")
barplot() (with kind="bar")
countplot() (with kind="count")
https://seaborn.pydata.org/generated/seaborn.catplot.html


上記のリファレンスのように、`catplot`関数の`kind`に与えている文字+`plot`という関数を代わりに使用して`ax`を使用すればいいということがわかりました。

なので、例えば2x2のグラフを表示させたい場合は、以下のように書くことができます。

```python
    import pandas as pd
    import seaborn as sns
    
    data = pd.DataFrame()
    y = "列名" 
    
    fig, axes = plt.subplots(2, 2, figsize=(2*1.4*3.8, 2*3.8),dpi=300, tight_layout=True, )

    #sns.catplot(x="type" ,y=y, data=data, kind="swarm", ax=axes[0,0])
    sns.swarmplot(x="type" ,hue="type", y=y, data=data, legend=False, ax=axes[0,0])
    
    #sns.catplot(x="type" ,y=y, data=data, kind="bar", ax=axes[0,1])
    sns.barplot(x="type" ,y=y, data=data, ax=axes[0,1])
    
    #sns.catplot(x="type" ,y=y, data=data, kind="violin", ax=axes[1,0])
    sns.violinplot(x="type" ,y=y, data=data, ax=axes[1,0])
    
    sns.kdeplot(hue="type", x=y, data=data, shade=False, ax=axes[1,1])

    #fig.savefig("save" + ".png", format="png", dpi=300,transparent=True)
    plt.show()
```



# 最後に

今回はSeabornのcatplotで引数にaxを渡してグラフを並べて表示させる方法を解説しました。
調べても英語の情報ばかり出てきてよくわからなかったので、参考になればと思って書きました。
それでは楽しいデータ分析ライフを！
デザイン崩れの見つけ方

多くのエンジニア案件でデザイン崩れはつきものです。しかし崩れの原因が見つけられず、作業が止まってしまいがちです。今回はそういった場合に崩れの原因を可視化する方法をまとめていきます。

# 1. CSSで見つける方法
CSSの全称セレクタを利用してoutlineを表示させる。

```
* {
	outline: 1px solid magenta;
}
```
たったこれだけで全要素のアウトラインを確認できます。

![スクリーンショット 2024-07-26 13.44.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3760862/8a93d91b-be2d-6e7e-0abb-f9fd0f4d30a7.png)

これで一目瞭然です。

# 2. JavaScriptで見つける方法
ブラウザのデベロッパーツールのConsole機能を使います。
使用するコードは以下。

```
$$("*").forEach(v => v.style.outline = '1px solid magenta');
```

![スクリーンショット 2024-07-26 13.44.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3760862/8a93d91b-be2d-6e7e-0abb-f9fd0f4d30a7.png)

結果は同じですがこちらの方が簡単ですね。

# まとめ
今回はデザイン崩れの見つけ方をCSSとJavaScriptの2通りで紹介しました。
どちらも同じ結果ですが、JavaScriptの方が使い勝手良いのでそちらをお勧めします。
座学ではなかなか教えてくれない内容ですが、現場仕事ではものすごく重宝する小技です。ぜひご活用ください。
JavaScriptもちゃんと習いたいね

**[前回の問題解決しました](https://qiita.com/suzukidog/items/3d20cbf38a1afb4f7c8e#%E8%A7%A3%E6%B1%BA20240723)**

---

問い合わせたり一から作り直したりなど、紆余曲折ありなんやかんやで解決しているデプロイ関係
めちゃくちゃ難しですが、少しずつ理解してきています。

勉強を始めた頃と比べると、プログラミングやITインフラへの理解は相当深まっています。
完全習得を100としたときに今は5くらいです。(多分)
初めは0だったので結構な進歩だと思います！！
今後のロードマップ

# 今後のロードマップ
　以下の通り行います。順不同です。
* [ ] AWA-ECS-fargate上の構成をマイクロサービス化
* [x] docker-compose.yml上の構成をマイクロサービス化
* [ ] 特定の座席を指定する機能の導入
* [ ] 席替え履歴を削除する機能の導入
* [x] セキガエマシンの使い方ページの導入
* [ ] &Xopf;上の現職教員の方々へのテスト依頼
* [ ] テストについて学習
メディアクエリをできるだけ書きたくない人へ ズボラさん向けCSS記法

Webデザインにおいてもはや必須となっているレスポンシブ対応。
しかし、メディアクエリを駆使していちいちブレイクポイントを作ってCSSを指定するのは煩雑で、つい億劫になってしまうこともありませんか？

そこで今回は、メディアクエリに頼らず、より柔軟でスマートなレスポンシブデザインを実現する方法をご紹介します。

アイテムを横並びに配置するのに、よく使われがちな**flexbox**。

要素が横並びになったときに`display: flex;`にして、スマホでは`display: block;`にして縦並びにするのが割と定番の方法かと思います。

ですが私はスマホで`display: block;`せずに`flex-direction: column;`で縦並びにする方法をここで提唱しておきます。

なんなら、PCで横並びにならないエリアさえも`flex-direction: column;`でレイアウトしちゃいます。

なぜなら、**できるだけflexboxを活用することで、要素のサイズや余白の設定などを容易にできるから**です。

実際にPC画面で要素が3つ横に並び、スマホでは縦に並ぶよくありがちなレイアウトを、従来のCSS記法と新しいCSS記法で比較してみましょう。

![flex (1).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1902958/7cedb765-0477-056b-3171-acd4a3470e0b.jpeg)

```css:従来の記法
.parent{
    display: flex;
}
.child{
    /* めんどくさポイント */
    width: calc((100% / 3 ) - 16px);
    justify-content: space-between;
}
@media (max-width: 767px){
    .parent{
        display: block;
    }
    
    /* めんどくさポイント */
    .parent:not(:last-child){
        padding-bottom: 16px;
    }
    .child{
        width: 100%;
    }
}
```
子要素のwidthをちゃっかり3等分にするために、calc(100% / 3 )とします。
さらに、子要素間に余白を空けるため、calc(100% / 3 )から余白分幅を引きます。
後々、情報が追加されて、要素が4つになってしまった場合、calc(100% / 4 )にしなければなりません。これはめんどくさいですね。

また、display: block;で縦並びにした場合、子要素間の行の余白がなくなってしまうので、`.parent:not(:last-child)`というめんどくさいセレクタ指定をして、子要素間の余白を設けなければなりません。

```css:新しい記法
/* 新しい記法 */
.parent{
    display: flex;
    /* gapは要素間のすき間を自由に定義できます。 */
    gap: 16px;
}
.child{
    /* flex:1とすることで、子要素の幅は均等に分配されます。 */
    flex: 1;
}
@media (max-width: 767px){
    .parent{
       flex-direction: column;
    }
    .child{
        width: 100%;
    }
}
```
このように`gap`や`flex`プロパティを使うことで、先ほどのめんどくさいcss記述がなくなり、シンプルになりました。

また、最近は**ノーコード**でのサイト制作がトレンドになっています。
ノーコードでWebデザインやプロトタイプが作れるツール代表格である『**Figma**』はまさにflexboxを大いに活用してレイアウトするツールです。

参考：

https://cumak.net/blog/figma-frame/

今後のノーコードとflexboxは切っても切り離せない関係になってくるでしょう。
今のうちに、flexboxに慣れていた方が良いかもしれません。
ポートフォリオ「セキガエマシン」について

# このアプリの目的
　教育現場における「席替え」は、本来、学級に３０名程度いる生徒一人一人への教育的配慮に基づいて行われるものです。しかし、一人一人の特性や人間関係を考慮しながら一人一人の座席を割り振っていくのは、大変な手間と時間のかかる作業です。これを自動化するためのWebAppは存在するのですが、毎回、生徒名や条件の設定等の手間から始まるため、より効率的に稼働するものをということで開発に着手しました。

 ## 「セキガエマシン」の特徴
 　セキガエマシンは生徒名と条件を設定しさえすれば、あとは席替えロジックのもと、自動で席替えを行うものですが、その最大の特徴は２回目以降の利用の際は生徒名と条件の設定すらいらないいうところです。ユーザーが設定した生徒名と条件はDBに保存され、次回利用時には復元できるようになっています。これにより、セキガエマシンは教員の席替えの負担を1/100にします。

## 使用した技術スタック
　このアプリに使用した技術スタックは以下の通りです。
* フロントエンド：TypeScript - Next.js - Authj.js, TailwindCSS
* バックエンド：Java - SpringBoot
* データベース：RDS - PostgreSQL
* 本番環境インフラ：AWS - ECS - fargate, EC2 - ALB
* 開発環境インフラ：Docker, Docker compose
* バージョン管理：GitHub
* CICD：GItHubActions

## リンク
宜しければ、ご覧ください→[セキガエマシン](http://www.sekigae-machine.jp/)
お
Array.mapの中でasync/awaitを使う

# はじめに
諸事情につき、`Array.map`の中でasync/awaitを利用したのですが、思った以上に詰まった・・。  
ということでメモがてら残しておきましょう。

参照（というかほとんど切り抜き元）：

https://qiita.com/kwbt/items/6c0fe424c89a9f7553c1

## やりたかったこと
Arrayに入っている値を元に非同期関数を呼び出しつつ、その結果の値を整形した配列を用意する。  
（最終的にjoinするだけで画面に表示したい）
```text:イメージ図
dataArray:['1', '2', '3']
  ↓
result:['・りんご', '・みかん', '・いちご']
  ↓
画面
・りんご
・みかん
・いちご
```

# 結論
```javascript:sample.js
const dataArray = ['1', '2', '3'];

const result = await Promise.all(dataArray.map(async (data) => 
    '・' + await sampleFunction(data)
));
```

# 説明
## dataArray.map(async (data) => await sampleFunction(data))
ここはまあ、見たまんまの動きです。  
非同期関数を同期的に呼びたいので、無名関数の頭に`async`を付け、実際に呼び出す関数には`await`を付けています。

こうすることで、dataArray.mapは無事同期的に結果を取得できる・・と思いきや、**dataArray.mapにはawaitがついていないので、この無名関数の処理終了を待ちません。**

コードを分解すると、こんな感じ。
```javascript
// この関数内ではきちんと同期処理化している
async mapFunction(data) {
    return '・' + await sampleFunction(data);
}

let result = [];
for (const data of dataArray) {
    result.push(mapFunction(data)); // こっち側が同期処理化していない
}

// そのため、Promiseの配列になってしまう
console.log(result); // [object Promise, object Promise, object Promise]
```

じゃあ`await dataArray.map`としたら良いのでは？と思ったのですが・・。  
`await`は**Promiseが返される関数にのみ適用される**ため、「Promiseの配列」だと無力です。  
※エラーにもならなかった。

## await Promise.all
ということで、`Promise.all`を使います。  
こうすることで、配列内のPromiseが全て履行されてから次へ進むようになります。

解決！！


# ちなみに・・
今回のパターンの場合、こっちでもできる。
```javascript:sample2.js
const dataArray = ['1', '2', '3'];

const promiseResult = await Promise.all(dataArray.map(data => 
    sampleFunction(data)
));
const result = promiseResult.map(elem =>
    '・' + elem
);
```

おそらく処理速度はほぼ一緒になる・・と思う・・・。  
mapを2回呼び出している分だけロスがある？？と思う？？？  
（逆に`async/await`の数が少ない分早かったりする？？多分変わらないよね・・？）

# さらにちなみに・・
```javascript
await Promise.all(...).join('\n');
```
の書き方は許されませんでした。  
多分`Promise.all(...).join('\n')`を評価した後に`await`をする流れになるから。


下記のどちらかにしましょう。
```javascript
// パターン1
(await Promise.all(...)).join('\n');

// パターン2
const promiseResult = await Promise.all(...);
const result = promiseResult.join('\n');
```

# おわりに
JavaScriptは奥が深いけど、なんとなく好きです。  
自由度が高い・・気がする・・・。
アウトソーシングとオフショアリング：現代のビジネス戦略

はじめに
現代のビジネス環境では、企業は競争力を維持し、コストを削減し、専門知識を活用するためにさまざまな戦略を採用しています。その中でも、アウトソーシングとオフショアリングは重要な戦略です。本記事では、これらの戦略がどのように企業に利益をもたらすのかを解説し、コーディングサービス、開発チームのアウトソーシング、およびアウトソーシング製品開発に焦点を当てます。
アウトソーシングとオフショアリングの概要
[アウトソーシング](https://newwave-solutions.co.jp/outsourcing-vs-offshoring/)は、企業が内部リソースを使用する代わりに外部の専門家や企業に特定の業務を委託するプロセスです。一方、オフショアリングは、業務を海外の企業やチームに委託することで、コスト削減や24時間体制の運営が可能になります。
アウトソーシングとオフショアリングの主な利点
コスト削減：人件費や運営費の削減が可能です。
専門知識の活用：外部の専門家や企業から最新の技術や知識を得られます。
業務効率の向上：企業はコア業務に集中でき、全体的な効率が向上します。
コーディングサービス
[コーディングサービス](https://newwave-solutions.co.jp/programming-outsourcing/)は、ソフトウェア開発の一環として、プログラムの作成やテストを専門とするサービスです。これにより、企業は専門的なコーディングスキルを持つ開発者に依頼し、高品質なソフトウェアを迅速に開発することができます。
![unnamed (48).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3031688/349c7a7f-a1b3-da21-597f-c4adb3f7fccd.png)
コーディングサービスは、プロフェッショナルなソフトウェア開発の鍵です。
コーディングサービスの利点
専門知識の活用：高度なプログラミングスキルを持つ専門家によるコーディング。
スピードと効率：プロジェクトの迅速な完了と品質保証。
コスト削減：内部リソースの節約と費用対効果の高いサービス。
開発チームのアウトソーシング
開発チームのアウトソーシングは、企業が特定のプロジェクトやタスクのために外部の開発チームを雇うことです。これにより、企業は必要なスキルセットを持つ専門家を迅速に集め、プロジェクトを成功させることができます。
![3 (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3031688/1397216c-5f0a-4b18-e094-0f6731113238.png)
開発チームのアウトソーシングは、迅速かつ効率的なプロジェクト管理を可能にします。
[開発チームのアウトソーシング](https://newwave-solutions.co.jp/outsourced-development-team/)の利点
フレキシビリティ：プロジェクトのニーズに応じてチームサイズやスキルセットを調整可能。
リスク管理：外部の専門家がリスク管理をサポート。
グローバルな才能の活用：世界中の優秀な開発者を活用。
アウトソーシング製品開発
[アウトソーシング製品開発](https://newwave-solutions.co.jp/outsourced-product-development/)は、製品のコンセプトからリリースまでの開発プロセスを外部の企業やチームに委託することです。これにより、企業は自社のリソースを節約しつつ、高品質な製品を市場に提供することができます。
![z5667165684514_358adb235b51ec74e81a2365620bb9f9.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3031688/0c3b3261-4ba3-c2a1-99a9-7cd5c4f1d121.jpeg)
アウトソーシング製品開発は、高品質な製品を迅速に市場に投入するための鍵です。
アウトソーシング製品開発の利点
タイムトゥマーケットの短縮：開発期間の短縮により、迅速な市場投入が可能。
コスト効果：開発費用の削減と予算内でのプロジェクト管理。
品質保証：専門家による高品質な製品開発。
結論
アウトソーシングとオフショアリングは、現代のビジネスにおいて不可欠な戦略です。特に、コーディングサービス、開発チームのアウトソーシング、およびアウトソーシング製品開発は、企業が競争力を維持し、効率を最大化するための強力な手段です。これらの戦略を適切に活用することで、企業は持続的な成長と成功を実現することができます。
iPadOS18のTabbarの仕様変更を回避する

## 概要

iPadOS18でタブバーのUIが刷新されました。

https://developer.apple.com/jp/videos/play/wwdc2024/10147/

これに伴い、これまで`UITabBarController`や`TabView`を用いて実装していたアプリはこの変更がアプリのUIに影響を与えないかのチャックや必要に応じて改修する必要があります。

この記事では、この変更を回避し、既存のタブバーのデザインを残すコードを紹介しています。

※2024/07/26現在は有効ですが、今後無効化される可能性があります


## 回避するためのコード

iOS17から追加された`UIView`の`Instance Property
`である`traitOverrides`の`horizontalSizeClass`に`.compact`を代入することで、タブバーの変更を回避することができます。



```swift
class MyTabBarController: UITabBarController {
    override func viewDidLoad() {
        super.viewDidLoad()

        traitOverrides.horizontalSizeClass = .compact // 👈 Override like this
    }
}
```

コードはこちらから引用させていただきました。

https://stackoverflow.com/questions/78631030/how-to-disable-the-new-uitabbarcontroller-view-style-in-ipados-18

## `.compact`について

`.compact`が何を意味しているかは@inuhaさんの記事が参考になりました🙏

https://qiita.com/inuha/items/145c595ec9861a39d6e2#uitraitcollection%E3%81%AE%E3%83%97%E3%83%AD%E3%83%91%E3%83%86%E3%82%A3
英語日記アプリアップデート！！

## はじめに
みなさんこんにちは。奥江です。
個人アプリをリリースしてから１年くらい経過したので現状を報告します！
それと同時にこんな機能あったらいいのにとかUI変えた方がいいよなどありましたらどしどしコメントしてくれると嬉しいです！

## どんなアプリ？
私自身英語を勉強しており、英語日記かくといいよみたいな記事を発見したのと、本で英語日記は絶対にするべきと書いてあったので、じゃ自分で作ってみよう！となり作ってみました！
日々のこんなときなんて英語で言うのかな？時ってあると思います。そんな時にメモしておいて、英文を作成し繰り返し復習することが出来るアプリです。
オンライン英会話などと一緒に使って頂けるともっと役に立つアプリかと思います。
現状App Storeで「英語日記」と検索すると上から３番目くらいに表示されているかと思います。

https://apps.apple.com/jp/app/ai%E7%BF%BB%E8%A8%B3-%E3%82%AA%E3%83%AA%E3%82%B8%E3%83%8A%E3%83%AB%E8%8B%B1%E4%BD%9C%E6%96%87-%E8%8B%B1%E8%AA%9E%E6%97%A5%E8%A8%98/id6472871867

## アップデートの内容
- 一番大きなアップデートはAIで英作文を作成出来るようにしました
日本語でメモしても英文が作れない！ことはたくさんあると思うので、それならAIに頼ろう！と思いAI機能を付けました！

- サブスクリプション
本業の業務でサブスク機能を実装することがあり、少し勉強したのでそれなら個人アプリでも導入しよう！と思い導入しました。
サブスクのプランとしては
・広告非表示プラン
・AI英文作成プラン
・AI英文作成プラン + 広告非表示プラン
上記３つを実装してみました。

- UI
やはり見た目は大事と思い、UIをアップデートしました。色んなアプリを参考にしました。

## サブスク登録者数
現状150人くらい使用して頂いて３人ほどサブスク登録してくれてます。もっと登録してくれると思っていたので少しショックです笑

## 収益
現状サブスクで月900円とadmob広告で月1000円くらいですね。
もっと伸びてくれると嬉しいです。

## UI
スクリーンショットを載せておきます！笑
ダセーUIだなとかなんでもいいのでコメントしてくれると嬉しいです笑

こちらがメイン画面です。
![スクリーンショット 2024-07-26 16.12.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2348250/92868bdd-a760-6e9c-7a1d-d5a9f6fe2f9c.png)

編集画面
「AIに英文を教えてもらう」で日本語日記から英文を作成してもらえます。
![スクリーンショット 2024-07-26 16.11.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2348250/ee791c4d-2375-9054-ef9e-f408b9208a70.png)

カテゴリー画面
こちらはカテゴリーごとに日記を分けて表示しております。
![スクリーンショット 2024-07-26 16.12.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2348250/8dac09b2-3ca2-33fe-5d8f-64917769af59.png)

設定画面
各種設定に遷移できる画面です。
![スクリーンショット 2024-07-26 16.12.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2348250/33089cc0-9afe-b0ac-daf2-7627e19e774f.png)

サブスクリプション画面です。
![スクリーンショット 2024-07-26 16.15.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2348250/a0e5e53a-85da-7364-ac7c-622c04d59782.png)


## 個人開発の難しさ
なかなかたくさんの人にアプリを知ってもらうのがやはり難しいなと感じています。
時間かけて作成しても全く使われないとモチベーションを保つのが難しいです。
コードを書くのが好きなので、全くやる気が出ないことはないですが、やっぱりせっかく作ったならたくさんの人に使って欲しい気持ちはあります！

## 最後に
ちょっと宣伝っぽくなってしまいましたが、個人アプリをアップデートしてアプリを使ってもらえるのは本当に嬉しいです。
色んなアプリを作ってこれからも色んな人の役に立ちたいと思っています。
What is SaaS CRM and how it is benefitial for business.

SaaS CRM stands for Software as a Service Customer Relationship Management. It refers to a cloud-based platform that provides tools and features to manage customer interactions, sales leads, marketing campaigns, and more. Here are some benefits of SaaS CRM for businesses,
1. Cost-Effective: SaaS CRM eliminates the need for businesses to invest in expensive hardware or software infrastructure. It operates on subscription-based pricing, making it a cost-effective solution for businesses of all sizes.

2. Easy Implementation: With SaaS CRM, businesses can get up and running quickly as there is no need for complex installations or configurations. The software is typically user-friendly and can be accessed through a web browser.

3. Scalability: SaaS CRM allows businesses to scale their operations easily as their customer base grows. They can easily add users, features, and functionalities to meet their evolving needs.

4. Accessibility: One of the key benefits of SaaS CRM is that it can be accessed from anywhere, at any time, as long as there is an internet connection. This flexibility enables remote work and enhances collaboration among teams.

5. Data Security: SaaS CRM providers invest heavily in data security measures to ensure that customer information is protected. This includes encryption, regular backups, and compliance with industry standards.

6. Integration Capabilities: SaaS CRM systems are often designed to integrate with other business tools and applications, allowing for seamless data flow between different systems.

Overall, SaaS CRM offers businesses a cost-effective, flexible, and secure solution for managing customer relationships and driving business growth.
メモ5

为了实现用户按下按钮后，由Java后台调用外部API获取一个新的URL，然后在新窗口中打开该URL，可以按照以下步骤进行：

1. **前端：JSF页面**：
   - 使用一个PrimeFaces的`p:commandButton`来触发一个后端的动作方法。
   - 使用`p:remoteCommand`来异步地从后端获取新的URL并在新窗口中打开。

2. **后端：Java后台**：
   - 创建一个Managed Bean，其中包含一个用于调用外部API的方法。
   - 该方法返回新的URL，并将其传递给前端。

### 前端：JSF页面

```xhtml
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:p="http://primefaces.org/ui">
<h:head>
    <title>Redirect Example</title>
    <h:outputScript>
        function openNewWindow(url) {
            window.open(url, '_blank');
        }
    </h:outputScript>
</h:head>
<h:body>
    <h:form>
        <!-- 按钮点击触发后端方法 -->
        <p:commandButton value="获取并打开新页面" actionListener="#{myBean.getExternalUrl}" oncomplete="openNewWindow(xhr.responseText)" />
        <!-- 隐藏的remoteCommand用于获取新的URL -->
        <p:remoteCommand name="openNewWindow" action="#{myBean.getExternalUrl}" oncomplete="openNewWindow(xhr.responseText)" />
    </h:form>
</h:body>
</html>
```

### 后端：Java后台

```java
import javax.faces.bean.ManagedBean;
import javax.faces.context.FacesContext;
import javax.faces.application.FacesMessage;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;

@ManagedBean
public class MyBean {

    // 方法用于调用外部API并返回新的URL
    public void getExternalUrl() {
        String apiUrl = "https://api.example.com/getUrl";
        String newUrl = "";

        try {
            // 创建URL对象
            URL url = new URL(apiUrl);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.connect();

            // 检查响应码
            int responseCode = conn.getResponseCode();
            if (responseCode != 200) {
                throw new RuntimeException("HTTP GET 请求不成功，响应码: " + responseCode);
            } else {
                // 读取响应
                Scanner sc = new Scanner(url.openStream());
                while (sc.hasNext()) {
                    newUrl += sc.nextLine();
                }
                sc.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 将新的URL写入响应以便前端JavaScript使用
        FacesContext.getCurrentInstance().getExternalContext().getResponseOutputWriter().write(newUrl);
        FacesContext.getCurrentInstance().responseComplete();
    }
}
```

### 解释

1. **JSF页面**：
   - `p:commandButton`：点击按钮触发后端方法`getExternalUrl`。
   - `p:remoteCommand`：隐藏的远程命令，用于从后端异步获取新的URL并在新窗口中打开。
   - `openNewWindow`：JavaScript函数，用于在新窗口中打开传递过来的URL。

2. **Java后台**：
   - `getExternalUrl`方法调用外部API获取新的URL，并将其写入响应，这样前端可以在`oncomplete`事件中获取到新的URL并在新窗口中打开。

这样，整个流程就实现了用户按下按钮后，Java后台调用外部API获取一个新的URL，并在新窗口中打开该URL。
CSR,SSR,SSG,ISRの理解を深める

## なぜ理解を深めるべきだと思ったか

現代のwebフレームワークにおいて、この理解を深めることは開発をする上での作るもののを性能を底上げするものに繋がると考えた。

## CSR（クライアントサイドレンダリング）

ブラウザ側でレンダリングする方法の事。

クライアント側で処理する量を増やしてしまうとユーザーにページを表示させるのが遅くなってしまう。（デバイスに依存してしまう）

## SSR（サーバーサイドレンダリング）

サーバー側で処理を行い、HTMLを構築してクライアント側に返す方式の事。

これはCSRのようにクライアント（デバイス）に依存しないため、ハイスペックなサーバーでHTMLを構築することができる。

しかし、サーバーで処理を行って、HTMLを構築してユーザー側に表示させるため、待たせる時間が長くなる。

## SSG（静的サイトジェネレーション）

ビルド時にすでにHTMLを構築しておくことによってユーザーからのリクエストがあっても事前に用意しているHTMLを返す。

CDNにキャッシュしておくことによって高速なページ表示が可能になる。

しかし、かなり巨大なECサイトのようなものの場合にビルド時にすべてのデータを取ってきてHTMLを構築しておくことはかなり難しい。

リソースの更新が頻繁な場合もSSGだと変化後の状態を見れない。（ビルド時にしかデータフェッチをしていないから）

## ISR（Incremental Static Regeneration）

一定期間ごとにサーバーサイドレンダリングを行うことによって、高速なページ描画を実現できるようになり、表示されるデータの更新頻度が高くても新しいデータを表示させることができる。

常に最新の情報が届けられるわけではない。
Form コントロールで「表示するアイテムがありません」と表示されてしまう

Power Apps を使用して Form を作成する際に、「表示するアイテムがありません」と表示されることがあります。
この時の確認すべきポイントを紹介します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404009/0bbd5fbc-ced9-7fb8-befb-d70b4df97677.png)

# ポイント
###  ポイント1.既定モードの設定
Form の既定モードが正しく設定されているか確認します。
編集モードになっていることを確認します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404009/c8e43291-c588-3c84-d3e3-01516980f731.png)


### ポイント2.Itemプロパティ
Item プロパティを確認し、式が設定されているか確認します。
例えば、ギャラリーやコレクションからアイテムを取得する場合、そのアイテムが存在するか確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404009/8129f723-f88d-8958-c80d-370457734f60.png)

# まとめ
私の経験上、既定モードの設定や Item プロパティの値が入ってなく表示されることが多いように思われます。これらのポイントをチェックすることで、Form が正しくデータを表示するように設定できます。
TypeScriptを基本からまとめたみた【入門】

## 1.セットアップ

①プロジェクトを作成する
```
mkdir test
cd test
npm create vite@latest
npm install
npm run dev
```
②srcにtest.tsを作成する

## 2. 基本のデータ型

①Typescriptの基本のデータ型を作成する

```test.ts

export const test = () => {
  const name: string = 'Mike'; //1. 文字列型 (string)
  const age: number = 25; //2. 数値型 (number)
  const isStudent: boolean = false; //3. ブール型 (boolean)
  const hobbies: string[] = ['reading', 'coding', 'gaming']; //4. 配列型 (Array)
  const address: object = {
    street: '123 Main St',
    city: 'Tokyo',
    state: 'CA',
  }; //5-1.オブジェクト型 (object)
  const today: Date = new Date(); // 5-2.オブジェクト型 (object) 現在の日付と時間を取得
  const none: null = null; //6. ヌル型 (null)
  const notDefined: undefined = undefined; //7. 未定義型 (undefined)
  const random: any = 'Hello Wordl'; //8. 任意型 (any)
};
```

## 3.interface/type

```test.ts

export const test = () => {
  const user = {
    useId: 1,
    name: 'Mike',
    age: 25,
    Email: 'mike@gmail.com',
    isActive: true,
  };
  //オブジェクトを定義する(interface)
  interface UserProps {
    useId: 1;
    name: 'Mike';
    age: 25;
    Email: 'mike@gmail.com';
    isActive: true;
  }

  // interfaceを拡張する場合
  interface AdminUser extends UserProps {
    role: String;
  }
  //オブジェクトを定義する(type)
  type UserProps = {
    useId: 1;
    name: 'Mike';
    age: 25;
    Email: 'mike@gmail.com';
    isActive: true;
  };
  // typeを拡張する場合
  type AdminUserProps = UserProps & {
    role: String;
  };

  const createAccount = (accountInfo: UserProps) => {};
  createAccount({
    useId: 1,
    name: 'Mike',
    age: 25,
    Email: 'mike@gmail.com',
    isActive: true,
  });
};
```
## 4.TSでクラスを書く

```test.ts
export const test3 = () => {
  class User {
    userId: number;
    name: string;
    age: number;
    Email: string;
    isActive: boolean;

    constructor(
      userId: number,
      name: string,
      age: number,
      Email: string,
      isActive: boolean
    ) {
      this.userId = userId;
      this.name = name;
      this.age = age;
      this.Email = Email;
      this.isActive = isActive;
    }

    //アクセス修飾子を使用することで、そのアクセス範囲を制御することができる

    //public: クラスの外部および内部からアクセス可能
    //private: クラスの内部からのみアクセス可能
    //protected: クラスの内部およびその派生クラスからアクセス可能

    public getProfile(): string {
      return `Name: ${this.name}, Age: ${this.age}`;
    }
    //staticメソッドはクラスレベルで共通の機能を提供するために使用され、インスタンスを生成することなく呼び出せる便利なメソッド
    static sayHelloWorld(): void {
      console.log('Hello World');
    }
  }
  const user = new User(1, 'Mike', 25, 'mike@gmail.com', true);
  user.getProfile(); //public
  User.sayHelloWorld(); //static
};
```

## 5.ジェネリクス

```test.ts
//ノーマル
export const test4 = () => {
  const foo = (arg: string): string => {
    return arg;
  };
};

//ジェネリクス
export const test5 = () => {
  const foo = <T>(arg: T): T => {
    return arg;
  };
  foo<string>('hello world');
};
```
## TSのテクニック

①Vscodeで飛ぶ

※指定した単語をコマンド押しながら、クリックすると定義された場所に移動する

②エラーをよく読む

※型のエラーが多い

③一旦型は、anyにする



## 参考サイト
[世界一わかりやすいTypeScript講座！プログラミング初心者もOK](https://www.youtube.com/watch?v=GEMtGlBiua4&list=WL&index=4&t=249s)
[セクション9: 実践：健康管理アプリはTypeScriptでこう作る！](https://www.udemy.com/course/typescript-complete/learn/lecture/17877718#overview)
【UIKIitシリーズ】目次一覧

# シリーズの目次
- [その1 - UI実装方法の選択肢
](https://qiita.com/generosity_hiroto_taniguchi/items/90f2465011dae6941cf1)
- [その2 - プロジェクトの基本的な制御フローを理解する！](https://qiita.com/generosity_hiroto_taniguchi/items/8a2b3e17a3df1902e597)
- 「UIKitシリーズ UIViewControllerについて 更新予定]
- [UIKitシリーズ UIViewについて 更新予定]
- [UIKitシリーズ] カスタムフォントを追加して使用する方法！

(記事を随時、追加・更新)

# はじめに
[UIKit](https://developer.apple.com/documentation/uikit)を利用して、iOSアプリのUIを構築することになったエンジニアです。
私自身、SwfitUIに少し触れていましたが、UIKitを利用したコードベースで実装したことがありませんでした。
なので私自身の経験踏まえて、これからiOSアプリでUIを実装するためにUIKitを選択した人の手助けとなればと思います。私の場合、UIKitの理解を促進するために、UIに関わるiOSアプリの全体像を掴んだ方が良かったので、そのことについても少し触れながら記載していきたと思います。

# 対象読者
- UIKitでUIを実装していくぞ！という初心者の人
- SwiftのUIに関する全体像を掴みたい人
Docker 備忘録

## 基本コマンド

### ログイン
```bash
# Docker Hubにログイン(imageアップロード時、pull時？に必要)
docker login

# ログアウト
docker logout
```

### image関係
```bash
# Doker Hubからimageをダウンロード
docker image pull [オプション] イメージ名[:タグ名]

# imegeの一覧を表示
docker image ls

# imageの削除
docker image rm [オプション] イメージ名(REPOSITORY or IMAGE ID)

# 使用していないimageをすべて削除
docker image prune -a

# Docker Hubへimageをアップロード
docker image push <dokerhubユーザー名>/イメージ名:[タグ名]
```

### container関係
```bash
# containerの一覧を表示
docker container ls

# 停止しているcontainerも表示
docker container ls -a

# containerの削除
docker container rm コンテナ名(CONTAINER ID)

# 停止しているcontainer全てを削除
docker container prune -a

# containerを作成&起動
docker container run -it --name "test1" hidakakombu/whisper:1.0 /bin/bash
###
-it :コンソールに結果を出すオプション(コンテナ内でbashを使って操作できる)
--name :コンテナ名(指定しないとランダムな文字列が使用される)
hidakakombu/whisper:1.0 :雛形にするimage名
/bin/bash :コンテナで実行するコマンド(bashを起動した際は、exitコマンドでシェルが終了しコンテナも停止する)

# ローカルのディレクトリにマウント(指定したディレクトリを仮想環境の/tmpとする)
docker container run -it -v /Users/hoge/Desktop/panpkin_230221:/tmp shiramaty/panpkin:0.0.3
###
```

### image作成
```bash
# Dockerfileからイメージを作成
docker build -t <dokerhubユーザー名>/[生成するイメージ名]:[タグ名] [Dockerfileの場所]
###
# 基本的にDockerfileのあるところまでcdして実行する(最後の.はカレントディレクトリを指定している)
docker build -t test:1.0 .
###
```
### その他
コンテナ起動時にbashを起動

dockerfileの最後に以下のコマンドを追加する

```bash
CMD ["/bin/bash"]
```

コンテナ停止時にコンテナを削除する

コンテナ起動時に—rmオプションをつける

```bash
docker container run -it --rm hidakakombu/whisper:1.0 /bin/bash
```

Dockerで使えるメモリを設定する

Docker Desktopを開く

Extensionsの右の：を押す

Resourceを押す

### 参考
[RNA-seqその10、Dockerで環境構築 - mecobalamin’s diary](https://mecobalamin.hatenablog.com/entry/2020/05/07/163303)

[Dockerでデータ分析環境を作る方法｜COLORS](https://colors.ambl.co.jp/docker-data-analyze/#section4)

[Dockerビルド時にプライベートリポジトリをクローンする](https://zenn.dev/ryo_f/articles/27f223203481ef)

[自宅ではじめるDocker入門[改訂版] (I/O BOOKS)](https://www.amazon.co.jp/自宅ではじめるDocker入門-改訂版-I-BOOKS-浅居/dp/4777521478/ref=sr_1_1?__mk_ja_JP=カタカナ&crid=3NOSAGDI5JQ7K&keywords=自宅ではじめるDocker入門&qid=1689949366&s=books&sprefix=自宅ではじめるdocker入門,stripbooks,177&sr=1-1)
ListBox(ListView)の複数選択をMVVMで判断する

自分向けのメモ。

WPF アプリの ListBox(ListView) を複数選択対応にする場合。XAMLとVMだけで完結する

```XML
<Window><!--名前空間などは省略-->
  <Window.DataContext>
    <ViewModel />
  </Window.DataContext>
  <ListBox ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem}"
           SelectionMode="Extended">
           <!--SelectionMode=Multipleでもよい, Singleだと単一選択になる-->
    <ListBox.ItemContainerStyle>
      <Style TargetType="ListBoxItem">
        <Setter Property="IsSelected" Value="{Binding IsSelected}" />
      </Style>
    </ListBox.ItemContainerStyle>
  </ListBox>
</Window>
```

``` C#
class Item : ObservableObject
{
  [ObservableProperty]
  bool isSelected;

  // 選択状態が変更された場合に何かしたい場合はこれをハンドリングすればよい
  //partial void OnIsSelectedChanged( bool value )
  //{
  //}
}
class ViewModel : ObservableObject
{
  // リストボックスのItemsSource にバインドする
  public ObservableCollection<Item> Items { get; set; }

  // 単一選択の場合の選択アイテム(複数選択した場合は来ない)
  [ObservableProperty]
  Item selectedItem;

  void SelectWork()
  {
   foreach( var item in Items.Where( i => i.IsSelected ) )
   {
     // 選択アイテムに対して何かやる
   }
  }
}
```