OmniAICreator/Qiita-1.07M huggingface dataset:
Bullet Trainを始めよう🚄️

## Bullet Trainとは
[Bullet Train](https://github.com/bullet-train-co/bullet_train)とはRuby on Rails上で動くSaaSのフレームワークです([Jumpstart](https://jumpstartrails.com/)みたいなもの)。
つまり、Railsを拡張しているものなので、新規アプリを作った時点で以下の機能がもうすでについています。
1. Deviseを使ってのユーザー登録・認証
2. Sidekiq & Redisのバックエンド・ジョブの設定
3. Jbuilderを使ってのAPI自動生成
4. Webhookの自動生成

他にも機能がたくさんありますし、Pro版を買ったらStripeの決済処理の設定など、色んな便利なツールが使えます。
[公式サイト](https://bullettrain.co/)
Bullet Trainの作成者：[Andrew Culver氏](https://twitter.com/andrewculver)
[Discord](https://discord.gg/bullettrain) (英語・日本語)

## 新規アプリを立ち上げると…

![](https://storage.googleapis.com/zenn-user-upload/b87aa84e1f48-20221116.png)

見ての通り、ログイン機能やTailwindのスタイルが実装してあります。
`> rake bullet_train:themes:light:eject[任意のスタイル名]`を使って、Bullet Trainの元のビューを自由自在に編集することもできます。

## Super Scaffolding
普通のscaffoldだと、こう書きますよね：
```
> rails g scaffold Project title:string
```
これで`Project`のモデル、ビュー、そしてテストなどが全部生成されます。
ただし、ネストされるモデルに対応してくれないし、例えば`Page`というモデルをネストしたい場合は、手動でフォームを編集しないといけないのでちょっと手間がかかりますよね。スタイルもついていません。

それでBullet TrainではSuper Scaffoldingという強力なコマンドを使うと、その手間を全部省いてれます:
```
# Projectモデルの作成
> rails g model Project team:references title:string
> bin/super-scaffold crud Project Team title:text_field
> rails db:migrate

# ProjectにネストされるPageモデルの作成
> rails g model Page project:references title:string
> bin/super-scaffold crud Page Project,Team title:text_field
> rails db:migrate
```

以上！これで`Page`が`Project`にネストされ、APIを含めてテストも準備してくれます。

`Test Project`という新規`Project`を作り、showページに移った結果がこちらです。下の方を見たら、新規`Page`が作れることを確認できます：
![](https://storage.googleapis.com/zenn-user-upload/298553362113-20221116.png)

しかも、これを何層も深くネストできるのでこの辺りの開発過程が結構はやくなると思います。

## 他にも色々

Super Scaffoldingでは他の処理も実現できます：
1. `> bin/super-scaffold oauth-provider`: GitHubやGoogleなどでログインできるように、モデルやビューを自動的に生成し設定してくれるオプションです。
2. `> bin/super-scaffold crud-field`: もうすでに存在しているモデルに対して新しいカラムを追加し、ビューの中にスタイル付きの新属性を追加してくれるオプションです。

その他のオプションは何があるか公式サイトで確認できます。

## Discord
[Discord](https://discord.gg/bullettrain)(英語・日本語)もあるので気軽に入って話しましょう🎉️
ちなみに、ドキュメントやI18nの和訳がまだないので、翻訳に興味ある方はDiscordに入って伝えてくださったら、仕事があると思います✏️

## おわりに

コミュニティーもいいですし、Railsのコミッターも開発チームに入っていますので信頼できるサービスだと思います。

是非Bullet Trainで楽しい開発の旅を送ってみてください🚄️
[Xcode/SwiftUI] 複数のViewを動的に切り替える方法

# 概要
SwiftUIでpickerなどを使い複数のViewを切り替える方法です。
# 環境
Xcode: 13.4.1
Swift: 5.6.1

# 実装例
~~~Swift:ContentView.swift
import SwiftUI

struct ContentView: View {
    @State private var selection = 0
    
    let titles = [
        "いちご",
        "みかん",
        "ぶどう"
    ]
    
    var body: some View {
        VStack {
            Picker(selection: self.$selection, label: Text("")) {
                ForEach(0 ..< titles.count) {
                    Text(titles[$0])
                }
            }
            .pickerStyle(SegmentedPickerStyle())
            showView()
        }
    }
    
    private func showView() -> AnyView {
        switch selection {
        case 0:
            return AnyView(viewStrawberry())
        
        case 1:
            return AnyView(viewOrange())
        
        case 2:
            return AnyView(viewGrape())
        
        default:
            return AnyView(viewStrawverry())
        }
    }
}

struct viewStrawverry: View {
    var body: some View {
        Text("いちご")
    }
}

struct viewOrange: View {
    var body: some View {
        Text("みかん")
    }
}
struct viewGrape: View {
    var body: some View {
        Text("ぶどう")
    }
}

~~~
# 補足
pickerを用いない場合でも実装は特に変わりません。
viewの切り替えは3個程度の場合はifをVStack内に直接書けますが、切り替えるviewが5個とか多くなってくると
`The compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expression`
というエラー(ifの条件分岐多すぎてコンパイル遅いよ！と怒られる)が出るため、今後要素数が増えることを考慮して初めからswitch文で記述することを推奨します。
Docker コンテナの日本語化

Moodle の bitnami Docker コンテナを立ち上げたのですが、英語のままなので、日本語化してみました。

```bash
$ cd <docker-compose.ymlのあるディレクトリ>
$ docker containter exec -it  <container-name> /bin/bash

root@<container-id>:/# sed -i -E 's/# (ja_JP.UTF-8)/\1/' /etc/locale.gen
root@<container-id>:/# cat /etc/locale.gen | grep ja_JP
root@<container-id>:/# apt-get update && apt-get install -y locales && locale-gen ja_JP.UTF-8 && echo "export LANG=ja_JP.UTF-8" >> ~/.bashrc
root@<container-id>:/# exit
$ docker compose restart
```

コンテナ内で日本語が使えるようになりました。
あとは、Moodle に入って、言語パックをインストールするだけです。
discord.errors.HTTPException: 429 Too Many Requests (error code: 0)対策法

# 0.前回のあらすじと今回の処理内容
## 0-1.前回のあらすじと対策法
[前回記事](https://qiita.com/DoNotPrayDebug/items/cc1a3ef73d2c91e19fa6)で解決できたと思ったのですが…
デバッグ中に **429 Too Many Requests (error code: 0)** を吐きました。

このエラーは **リクエストを投げすぎると発生するエラーです。**
（よくある例：デバッグ中に何度もrun(TOKEN)を実行する）

コレの対処法は**os.system("kill 1")** を実行すれば解決できます。
（少し時間をおいてからrun(TOKEN)を実行すること）

前回記事ではログアウト処理を実装し、その際にos.system("kill 1")を実行してました。
ですが、完全対策には至らなかったようです。
（エラー出した後にos.system("kill 1")を実行させるのが正解）

なので今回は例外処理を走らせて対策していきます。
## 0-2.処理内容について
* run(TOKEN)内でエラーが発生
    1. エラー内容をコンソールログに出力
    1. エラー内容をファイル出力
    1. os.system("kill 1")を実行してシステムを落とす

2.の処理は運用を考えて、実装することにしました。
ちょっと特殊なことをしますのでログ吐かせる方は、ぜひ参考にしてください。

# 1.コード解説
## 1-1.今回のコード
```.py
import discord
import os, datetime, time

class MyClient(discord.Client):
  #botクラスの処理内容

def main():
  #タイムゾーン調整
  tz_jst = datetime.timezone(datetime.timedelta(hours=9))

  #すべての機能を使えるようにする
  intents = discord.Intents.all()
  #クラス生成、intentsは必須パラメータ
  client = MyClient(intents=intents)

  try:
    #Discord接続(エラー発生用)
    client.run("ABC")

    if (client.is_closed()):
      #discord.errors.HTTPException: 429 Too Many Requests対策
      SysClose()
    
  except discord.DiscordException as e:
    errorTime = str(datetime.datetime.now(tz_jst))
    errorText = "エラー発生:" + errorTime + "\n"
    errorText += str(e) + "\n"

    print("\n" + errorText)
    #エラーログを保存
    LogWrite(errorText)
    #discord.errors.HTTPException: 429 Too Many Requests対策
    SysClose()

#discord.errors.HTTPException: 429 Too Many Requests対策
def SysClose():
  print("osを切ります")
  os.system("kill 1")

#エラーログを保存する
def LogWrite(logText):
  sleepTime = 12
  textFile = open('log.txt', 'a')
  textFile.write(logText)
  textFile.close()
  print("処理が終わるまで待ちます:" + str(sleepTime) + "秒")
  #更新が終わるまで待たせる(早いと更新が正常に終わらない)
  time.sleep(sleepTime)

if __name__ == "__main__":
  main()
```
では、それぞれの処理について解説します。
## 1-2.try-except discord.DiscordException as e
例外処理判定をしている箇所です。
エラーが発生するとexcept内の処理を実行します。

変数eにエラー内容が入っています。
あとは、テキストを生成して、ぞれぞれの処理を呼び出しているだけですね。

## 1-3.LogWrite(logText)
エラーログを書き込んでる場所です。
ファイルを指定して末尾にエラーログを書き込んでます。

ココで大事な箇所は**time.sleep(sleepTime)**

この処理は指定した時間内、処理を停止させる処理です。
コレを組み込まないとログがうまく保存されませんでした。
※os.system("kill 1")が悪さしています。

# 2.実際に動かしてみた
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2870946/15db6d36-1f8e-a844-193f-16c1a249e047.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2870946/fbf7e170-0915-e9ad-c1e2-ce78e7d22190.png)
トークンが不適切だというエラーが出てますので成功です。
（時間表記が気になる方はフォーマットいじるなり、splitで区切るなりしてください）

無論、429 Too Many Requests (error code: 0)の対策もできています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2870946/763230ea-216f-bfeb-ae6b-f88d95f70c86.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2870946/6dc94b3f-04d2-ab54-adab-4a365ac711cd.png)

ココまでお付き合いいただきありがとうございました。

※何か連絡や依頼がありましたらDMをお願いします。
[Twitter: Don't Pray Debug](https://twitter.com/DebugDon)
VSCodeでのリモート開発でPDFが読み込めないときの対処法

「LaTeX Workshop」拡張機能をリモートサーバにインストールする。
![スクリーンショット 2022-11-17 4.42.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/546645/74905a48-6544-3bb3-e6da-3ed8afae5530.png)

PDFをクリックすると、「LaTeX Workshop」のPDF閲覧機能でPDFを閲覧できるようになる。
![スクリーンショット 2022-11-17 4.45.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/546645/32dd00cc-2839-0896-94c4-f0a964844186.png)
Swiper.jsの自動再生のバグ対策


備忘録です。スライダーを逆方向に自動で流れるように動作させた時、別のタブに移動したり、ウィンドウサイズを変更したりすると、スライドが表示されなくなるバグがあります。解決策を見つけるまでに時間がかかりましたので、忘れないように書きます。

解決策
~~~js
  autoplay: {
    delay: 0,
    disableOnInteraction: false,
    reverseDirection: true,
    pauseOnMouseEnter: false,
},
~~~

`reverseDirection`で逆再生する場合はセットで`pauseOnMouseEnter`を無効にしましょう。

### 参考記事
https://github.com/nolimits4web/swiper/issues/5029
2022/11/17主にITとかセキュリティの記事

Twitterアカウント狙うフィッシング攻撃が増加 - 「Twitter Blue」に便乗
https://www.security-next.com/141455

NEC製HAクラスタリングソフトに深刻な脆弱性 - パッチの適用を
https://www.security-next.com/141461

Acronisの小規模環境向けバックアップ製品に複数の脆弱性
https://www.security-next.com/141458

請求案内に見せかけた「So-net」を装うフィッシング
https://www.security-next.com/141452

警察庁が解説するフィッシング詐欺の事例と対策、民間企業には「DMARC」での対応と被害相談・報告をお願い
「フィッシング対策セミナー 2022」開催(11/15)
https://internet.watch.impress.co.jp/docs/news/1454486.html

先週のサイバー事件簿 - 日本気象協会の偽サイト・不正販売サイトに注意を(11/15)
https://news.mynavi.jp/article/20221115-security/

組織のCyber IQを高め、サイバーレジリエンスを向上(11/16)
https://special.nikkeibp.co.jp/atclh/ONB/22/pwc1116/

パスワードハッキング攻撃は増加の一途--マイクロソフト調査(11/15)
https://japan.cnet.com/article/35196060/

サイバー攻撃は「精神攻撃」だった(11/15)
https://kn.itmedia.co.jp/kn/articles/2211/15/news028.html

【レポート】国内791大学、アカウント漏洩累計173万件に。2022年は歴代最高の漏洩頻度・被害規模に到達見込み。
～対面授業再開によるオンライン環境放置で、不正アクセスにつながらぬよう注意が必要～(11/15)
https://prtimes.jp/main/html/rd/p/000000135.000000809.html

FTX破綻後の暗号資産業界の自浄作用は期待できるか：分散型金融（DeFi）のイノベーションを最大限活用(11/15)
https://news.yahoo.co.jp/articles/a9b21d755de447cfa55282272894c4e1aec18816

So-netを偽るフィッシング確認、注意を(11/15)
https://news.mynavi.jp/techplus/article/20221115-2513475/

FTX、ハッキングは内部関係者か──ハッカーが残した「愚かな失敗」とは？(11/15)
https://www.coindeskjapan.com/165569/

FTXのハッカーはパニック？ 計画性は見られない：アーカム・インテリジェンス(11/15)
https://www.coindeskjapan.com/165612/

Arkham IntelligenceがFTXハッカーの関連するウォレットに3億3900万ドル相当のトークンが保有されていることを明らかにした(11/15)
https://nextmoney.jp/?p=54480

暗号資産保護のカギは「コールドウォレット」…大手が経営破綻で日本法人“顧客資産は法令にのっとり管理”(11/15)
https://news.yahoo.co.jp/articles/ea14e363e9b1ecabcc96449c54061caec2fc137b

2022年第3四半期に悪意のある仮想通貨マイニングが急増(11/15)
https://nextmoney.jp/?p=54477

個人情報ダダ漏れ時代…どう身を守るのか？(11/15)
https://news.mynavi.jp/article/20221115-2513026/

フィッシングメールは前四半期比31％増、マルウェア攻撃は前年の年間数をすでに上回る
2022年7月～9月のフィッシングとマルウェアに関するレポートを発表(11/15)
https://prtimes.jp/main/html/rd/p/000000032.000061783.html

Coinbase Japanで取扱い開始されたチェーンリンク（LINK）とは？(11/15)
https://hedge.guide/feature/coinbase-link-bc202211.html

改正個人情報保護法の施行で注意すべき点は？　個人情報データ保護とログ監視を軸に実効性の高い管理を実現
インシデント時だけでなく、平時から把握しておくべき3つのポイント(11/15)
https://enterprisezine.jp/article/detail/16691

ウェブサイトの脆弱性を突く攻撃手法のひとつ「クロスサイトスクリプティング」とは(11/15)
https://news.nicovideo.jp/watch/nw11695600

わずか3分でクルマが盗まれる!? 車両盗難の手口が巧妙化！ 愛車を守る効果的な対策はある？(11/15)
https://kuruma-news.jp/post/578079

Microsoft、2023年の月例セキュリティ更新プログラムのリリーススケジュールを公開
来年も「パッチチューズデー」は継続、日本向け配信は第2水曜日または第3水曜日(11/15)
https://forest.watch.impress.co.jp/docs/news/1455656.html

BinanceのCEOがAPIリークに関する噂を明らかに(11/15)
https://nextmoney.jp/?p=54464

鹿児島県大島支庁で個人情報流出　特設サイトで設定ミス　アンケート回答者１８人のメアドなど外部閲覧可能に(11/15)
https://newsdig.tbs.co.jp/articles/-/204298

不正アクセスの実情と、2段階認証が必要なワケ(11/16)
https://xtech.nikkei.com/atcl/nxt/column/18/02229/102700010/

社員の前に上司を巻き込め　リスキリングで管理職の能力開発(11/16)
https://xtech.nikkei.com/atcl/nxt/mag/nc/18/091600313/111100003/

日本企業でDXが進まない原因は社員の意識にあり(11/16)
https://xtech.nikkei.com/atcl/nxt/mag/nc/18/111100323/111100001/
plotlyで複数のグラフに同じ図形を重ね書きする

# 概要
plotly expressで描画した複数の散布図に、一括で境界線を重ね書きプロットする。

# やりたいこと
こういうのをお手軽にプロットしたい
![newplot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/527090/1aa11bdf-fd22-3a4d-0ef6-3ed13453e549.png)

# 元のグラフ
plotly expressのサンプルデータをplotly expressのfacet_colで横方向にプロットするだけ。
こんなグラフを描くと、両方のグラフにいわゆる欲しいデータの境界線を重ね書きしたくなってくる。


```python
import plotly.graph_objects as go
import plotly.express as px

df = px.data.experiment()
fig = px.scatter(df, x="experiment_1", y="experiment_2",
                 facet_col='gender', color='group')
fig.show()
```
![newplot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/527090/52882e03-b659-2a20-6341-d90f4028d8be.png)

# 一括重ね書きするには
内部的には左右のグラフを描き分けるのに、rowとcolの指定が必要になる。
一々、rowとcolを調べて指定したくないので描画範囲を指定するだけで済むように関数化した。
rowとcolの上下限値を_get_subplot_rows_columns()で取得してforループでrowとcolを指定している。

```python
import plotly.graph_objects as go
import plotly.express as px

df = px.data.experiment()
fig = px.scatter(df, x="experiment_1", y="experiment_2",
                 facet_col='gender', color='group')


def AddPlotRect(fig: go.Figure,
                x_low: float, x_high: float,
                y_low: float, y_high: float):
    # _get_subplot_rows_columns()でrowとcolの範囲をタプルで取得
    row_range, col_range = fig._get_subplot_rows_columns()
    for row_index in row_range:
        for col_index in col_range:
            fig.add_shape(type="rect",
                          xref="x", yref="y",
                          x0=x_low, y0=y_low,
                          x1=x_high, y1=y_high,
                          line=dict(
                              dash='dash',
                              color='rgba(255,0, 0, 0.6)',
                              width=3,
                          ),
                          fillcolor='rgba(255,128, 128, 0.1)',
                          row=row_index,
                          col=col_index
                          )

# figに重ね書きしたい矩形のxy座標２点を指定
AddPlotRect(fig, 90, 110, 100, 130)
fig.show()
```
![newplot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/527090/1aa11bdf-fd22-3a4d-0ef6-3ed13453e549.png)

# 最後に
多分一年後くらいにグラフを描く自分へ。
AddPlotRect()を適当にコピペして色味だけ調整すれば、自分が必要なことはできるはず。
Node.js/Prisma(ORM)/SQLite コネクションエラー、タイムアウトする問題の対策

## この記事の概要

Node.js CLIプログラム 開発中に遭遇した問題とその対応内容を記録する。
DBレイヤーに使用した Prisma と SQLite3 の組み合わせで発生。

開発元のIssuesでは、ざっくり昨年10月頃以降に同様の項目がある。
ワークアラウンドは判ったが、現時点までに本質的な修正はないように見えた。

## 何が起きた？

よくわからないが、処理がエラーで中断する。
コンソールのメッセージを頼りに、調査した。

### エラー発生時のコンソール出力（抜粋）

```bash
PrismaClientUnknownRequestError:
Invalid `prisma.images.update()` invocation:

Error occurred during query execution:
ConnectorError(ConnectorError { user_facing_error: None, kind: ConnectionError(Timed out during query execution.) })
  clientVersion: '4.6.1'
}
```

ここでimagesは、テーブル名。簡単に言うと、SQLクエリーがタイムアウトにより失敗したということ。

### 実行時の環境

- @prisma/client@4.6.1
- prisma@4.6.1
- Node.js v18.10.0
- Ubuntu 22.10
- sqlite3(cli) 3.37.2 2022-01-06 13:25:41

## Issues

https://github.com/prisma/prisma/issues?q=is%3Aissue+is%3Aopen+label%3A%22topic%3A+Timed+out+during+query+execution%22

PrismaClientとSQLite3の組み合わせに限って起きている。
現時点で最新のバージョンにて発生している。

「CLIプログラム」だけに限るわけでもない。

いくつか、Promise.allでSQLクエリを並列していると起こるなどといったことが書かれているが、実際にはこれに限らない。
とにかくSQLへのクエリが一定以上に重複すると起きるようだが、閾値など詳しい条件は（私は）調べていない。

## 解決方法 ソース

Issueのひとつにあったワークアラウンド（以下に示す）では、コネクションプールを減らすことで解決できたとのこと。

要点の抜粋
>adding ?connection_limit=1 to the connection string ...

https://github.com/prisma/prisma/issues/9562#issuecomment-1242491767

さて「?connection_limit=1」は、どこに書くのか？
以下で順に追っていく。

### (Sample) ./prisma/schema.prisma

DB接続文字列なので、まずschema.prismaを確認する。

```shell
datasource db {
  provider = "sqlite"
  url      = env("DATABASE_URL")
}
```
→.envを調べよう

### (Sample) ./.env

結論としては、このファイルに書く。
↓変更後。

```bash
DATABASE_URL="file:./dev.db?connection_limit=1"
```

## Model

（参考）
Prismaからのコンソール出力を設定している。
以下に Model の冒頭を抜粋。

```js
import { PrismaClient, Prisma } from '@prisma/client';

// (snip)

export default class Model {
  constructor() {
    this.prisma = new PrismaClient({
      log: ['info', 'warn', 'error'],
    });
  }

  // (snip)
}
```

## 再試行

解決策を導入したあとに、試行したときのコンソール出力を見ると、`prisma:info Starting a sqlite pool with 1 connections.`
とある。
コネクションプールが1本になっているように見える。
デフォルトは、ホストの『CPUスレッド数＋1』

発生時のような処理の中断は回避できている。
ただし開発途中のため、本件と関係ない別の問題がまだあるが、ここでは省略する。

## おわりに

これにて本件の問題を解決したので、記事を締めとする。
PostgreSQLでSQL実行するECPGプログラムの簡単な例

PostgreSQLに対して以下のDB操作・SQL実行を行うECPGの簡単なプログラム例を示します。
* ローカルで稼働中のPostgreSQLに対して、DBユーザtestuserでデータベースtestdbに接続する。
* (もし未作成であれば) テーブルtesttblを作成する。テーブルtesttblは、主キーであるinteger型の1カラムnumだけを持つ。
* プログラムの引数で指定された整数値をテーブルtesttblにINSERTする。
* テーブルtesttblの全レコードについて、numカラムでソートした結果を順番に標準出力に出力する。
* SQL実行がエラーになった場合は、エラーの理由とSQLをエラーメッセージとして標準エラー出力に出力する。

これらを実現するECPGプログラムの簡単な例は下記です。

```c:test.pgc
#include <stdio.h>
#include <stdlib.h>

/*
 * SQL実行でエラーが発生したら、エラー処理のための関数として
 * elog()を呼び出すようにグローバルに宣言する。
 */
static void elog(void);
EXEC SQL WHENEVER SQLERROR CALL elog();

/*
 * 現在実行中または直前に実行済のSQL文字列を保存する
 * グローバル変数sqlを宣言する。
 */
EXEC SQL BEGIN DECLARE SECTION;
char *sql;
EXEC SQL END DECLARE SECTION;

/*
 * このプログラムのメイン関数。
 * テーブルtesttblにINSERTするレコードの整数値を第1引数で指定できる。
 */
int
main(int argc, char *argv[])
{
	/*
	 * ECPGで使うローカル変数を宣言する。
	 */
	EXEC SQL BEGIN DECLARE SECTION;
	const char *target = "testdb@localhost:5432";
	const char *user = "testuser";
	int num = 0;
	int res = 0;
	EXEC SQL END DECLARE SECTION;

	/*
	 * 第1引数が指定された場合は、引数の整数値をINSERTする。
	 */
	if (argc > 1)
		num = atoi(argv[1]);

	/*
	 * ローカル内で稼働中のPostgreSQLに対して、DBユーザtestuserで
	 * データベースtestdbに接続する。
	 */
	EXEC SQL CONNECT TO :target USER :user;

	/*
	 * もし未作成であれば、テーブルtesttblを作成する。
	 */
	sql = "CREATE TABLE IF NOT EXISTS testtbl (num integer primary key)";
	EXEC SQL EXECUTE IMMEDIATE :sql;

	/*
	 * 動的SQLを使って、テーブルtesttblにレコードを1件INSERTする。
	 */
	sql = "INSERT INTO testtbl VALUES (?)";
	EXEC SQL PREPARE teststmt FROM :sql;
	EXEC SQL EXECUTE teststmt USING :num;

	/*
	 * テーブルtesttblの全レコードを表示するために、全レコードを取得する
	 * SQLに対してカーソルを定義する。
	 */
	sql = "SELECT num FROM testtbl ORDER BY num";
	EXEC SQL PREPARE teststmt FROM :sql;
	EXEC SQL DECLARE testcur CURSOR FOR teststmt;
	EXEC SQL OPEN testcur;

	/*
	 * カーソルからレコードを1件ずつ取得して標準出力する。
	 * 全レコードを取得したらwhile()ループから抜けられるように
	 * 一時的に宣言する。
	 */
	EXEC SQL WHENEVER NOT FOUND DO BREAK;
	while (1)
	{
		EXEC SQL FETCH testcur INTO :res;
		printf("%d\n", res);
	}
	EXEC SQL WHENEVER NOT FOUND CONTINUE;
	EXEC SQL CLOSE testcur;

	/*
	 * トランザクションを完了する。
	 */
	sql = "COMMIT";
	EXEC SQL EXECUTE IMMEDIATE :sql;

	/*
	 * PostgreSQLへの接続をクローズする。
	 */
	EXEC SQL DISCONNECT;

	return 0;
}

/*
 * SQL実行でエラーが発生したときに呼び出される、エラー処理のための関数。
 */
static void
elog(void)
{
	/*
	 * sqlcaからエラー理由のメッセージを取得して、標準エラー出力に出す。
	 * また、現在実行中または直前に実行済のSQLでエラーとなったものも
	 * 標準エラー出力に出す。
	 */
	fprintf(stderr, "ERROR: %s\n", sqlca.sqlerrm.sqlerrmc);
	fprintf(stderr, "STATEMENT: %s\n", sql);

	exit(1);
}

```

このECPGプログラムは以下のとおりコンパイルします。以下では、PostgreSQLのインストール先を/opt/pgsqlディレクトリとします。

```bash
$ ecpg test.pgc
$ gcc -o test test.c -I/opt/pgsql/include -L/opt/pgsql/lib -lecpg
```

プログラムの実行例は以下のとおりです。

```bash
$ ./test 1
1
$ ./test 2
1
2
$ ./test 0
0
1
2
$ ./test 0
ERROR: duplicate key value violates unique constraint "testtbl_pkey" on line 59
STATEMENT: INSERT INTO testtbl VALUES (?)
```
DDDがわからない～みんなで仲良くしよう～

# 結局、ズレてしまう
やりたい事について詳しい人(主に顧客)、設計に詳しい人、プログラムに詳しい人、デザインに詳しい人など様々な人がシステム開発には関わってきます。
いかに最初にみんなで示し合わせたとしても**ズレ**はまた、すぐに発生してしまいます。
複数の人間がかかわっている以上、様々なものの考え方が違うのでそれは当たり前のことです。
これを放置してしまうと崩壊へと進んでしまいます。

# **ズレ**はどうやったら見つけられるのか？
**ズレ**は自分だけでは自分側の視点からしか物が見えないため、**ズレ**を認識することができません。**ズレ**は相手側がいて初めて認識することができるのです。なので定期的に認識のすり合わせを行う場を用意しましょう。その際には、名前やシステムの細かい構成まで可能な限りすり合わせしましょう。

# 改善の恐怖と戦う
もし、このすり合わせの中でズレを見つけたらすぐにズレの修復を行いましょう。
**ズレ**というのはどんどん広がっていきます。最小限で被害をとどめるためにも早急な修正が必要です。
一度できたプログラムに修正を加えることは、難色が示されるかもしれません。しかし、ここで発生する**ズレ**というのは、全員が認識できる**ズレ**となるので。プログラム的に治したいといった話よりは比較的話がしやすくなるのでないでしょうか。

**あらかじめ、そういった時間を見積もりに設けておくのも大切かもしれません。**
WordPress Plugin WPFormsのCSSのいじり方


全セレクターのリスト
ここ↓

https://twpforms.com/docs/how-to-customize-the-style-of-individual-form-fields/

英語の翻訳は
ここ↓

https://www.deepl.com/translator

ページまるっと翻訳は
ここ↓

https://www.asobou.co.jp/blog/bussiness/google-translate
ストレージサービスの種類

●ストレージサービスの概要
・冗長性及び高可用性
・セキュリティ保護
・スケーラブル
・マネージド
・広い範囲のアクセス

●ストレージサービスの種類
■Azure Blob Storage
テキストデータやバイナリデータなどの大量の日構造化データを格納するために最適化されたサービス。
Azure Blob Storageには、Azure Data Lake Storage Gen2のサポートも含まれている。これはAzure Blob Storageをもとにしたビッグデータ分析専用の機能のセット。

■Azure Files
クラウド上にSMBファイル共有またはNFSファイル共有を作成するサービス。
マネージドサービスでありSMBプロトコルまたはNFSプロトコルを介してアクセス可能な高可用性ネットワークファイル共有を作成して使用できる。
SMBファイル共有はWindows、macOS、Linuxクライアントから、NFSファイル教諭はmacOS、Linuxクライアントからアクセスできる。

■Azure Queue Storage
異なるアプリケーション間のデータ交換場所である、キューを提供するサービス。
非同期通信を行うのが一般的。

■Azure Table Storage
テーブルデータを格納するサービス。一般的にNoSQLデータと呼ばれる、日リレーショナル構造化データをクラウド内に格納するサービスとして機能し、スキーマ設計不要でキーと属性によるデータを保存できる
Pythonを管理者権限で実行するためのスクリプトを作成した。

pythonを管理者権限で実行するにはショートカットを作成して、管理者権限で実行すればいい。
そのため、pythonのスクリプトのショートカットを作成するスクリプトを作成した。

# 実行環境
 * windows 10 home
 * python 3.9
 * pip 22.0.4

# スクリプト
```python3
pip install pywin32
pip install winshell
```

```python3:make_shortcut.py
import os, sys, winshell
from win32com.client import Dispatch

def main():
    if len(sys.argv) != 2:
        return

    # スクリプトの存在確認をする
    target_path = sys.argv[1]
    if os.path.isfile(target_path) is False:
        return 

    save_path = target_path + ' - shortcut.lnk'

    # python の場所を探す
    python_work = None
    paths = os.environ["PATH"].split(os.pathsep)
    for path in paths:
        if path.split(os.path.sep)[-2][:6] == 'Python':
            python_work = path
            python_path = path + 'python.exe'
            break
    
    # python_workの存在確認をする
    if python_work is None:
        return 

    # ショートカットを作成
    shell = Dispatch('WScript.Shell')
    shortcut = shell.CreateShortCut(save_path)
    shortcut.Targetpath = python_path
    shortcut.WorkingDirectory = python_work
    shortcut.Arguments = target_path
    shortcut.save()

if __name__ == '__main__':
    main()
```

# ハマったこと
参考文献にはmklnkとpylnkで作成する方法があったが、パスに日本語があると文字化けして正しいショートカットが作成できなかった。

# 参考文献
 * [python - PythonでWindowsのショートカットを作成したい - スタック・オーバーフロー](https://ja.stackoverflow.com/questions/69212/python%E3%81%A7windows%E3%81%AE%E3%82%B7%E3%83%A7%E3%83%BC%E3%83%88%E3%82%AB%E3%83%83%E3%83%88%E3%82%92%E4%BD%9C%E6%88%90%E3%81%97%E3%81%9F%E3%81%84)
 * [python - create a shortcut(.lnk) of file in windows with python3 - Stack Overflow](https://stackoverflow.com/questions/60943757/create-a-shortcut-lnk-of-file-in-windows-with-python3)
 * [pythonスクリプトを管理者権限で実行する方法ありませんか？ -exeファ- その他（プログラミング・Web制作） | 教えて!goo](https://oshiete.goo.ne.jp/qa/8937160.html)
スクリプトでモディファイアを適用したメッシュを作成する

チャットでBlenderのモディファイアを付けた状態のメッシュを作成する話題があったのでメモ

因みに単純にモディファイアを適用したメッシュを取得したいだけなら
オブジェクトメニューの変換＞メッシュで　「オリジナルを保持」をチェックして変換するのが楽
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151493/199ec6ea-8469-6a7f-6261-5728e33c244b.png)

アクティブオブジェクトのモディファイアを適用したオブジェクトを作成したい場合

```py
import bpy
obj = bpy.context.active_object
depsgraph = bpy.context.evaluated_depsgraph_get()
modified = obj.evaluated_get(depsgraph)
mesh = bpy.data.meshes.new_from_object(modified)
new_obj = bpy.data.objects.new( "new_obj", mesh)
bpy.context.scene.collection.objects.link(new_obj)
```


スクリプト内で変換した頂点データ等を取得する場合のコード
（modifiedはMeshのデータなもののデータブロックは作成されない）
```py
import bpy
def getModifiedMesh28(obj):
    depsgraph = bpy.context.evaluated_depsgraph_get()
    modified = obj.evaluated_get(depsgraph).to_mesh
    return(modified)
obj = bpy.context.active_object
modified = getModifiedMesh28(obj)
```
Blender2.8以降で変更になった部分で
他サイトを参考に以前のコードと挙動を揃えるために使ったことがあるだけなので
細かいことはちょっとわかってない・・・ので単なるメモ
Intellijでwsl2上のdockerコンテナ内のgradleプロジェクトの同期に失敗した際の解決法

<h1>経緯</h1>
IntelliJでwsl2上のdockerコンテナ内のgradleプロジェクトを開いた際、Gradleの同期失敗でビルドが通らなかった為。<br>
根気強く試行錯誤した結果環境構築が成功しましたが、同様の情報がネット上に確認できなかったので、<br>
同じ不具合で悩む人の為に記事にしたいと思います。

<h1>使用環境</h1>
Windows 10 Pro<br>
wsl 2<br>
Ubuntu 20.04.4 LTS<br>
Docker<br>
IntelliJ IDEA 2022.2.1(Community Edition)

<h1>出ていたエラー</h1>
特になく、同期失敗としかでていない　←ここで一番詰まりました<br>
<img src = https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2629102/eff1c940-7c4c-09d2-a097-5e52b54d53ac.png>

<h1>根本原因</h1>
IntelliJでGradleの同期をする前にwsl2上のdockerコンテナ内のgradleを実行したため
<h1>解決方法</h1>
1.docker を一度停止させます<br>
<img src = https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2629102/3a0a693d-513d-327c-f6a4-055c86232c1f.png><br>
2.gradleプロジェクト内の buildディレクトリ .gradle ディレクトリを完全に削除します。<br>
<img src = https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2629102/6bde7540-ffa1-775a-d637-b8754af54eb2.png><br>
<img src = https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2629102/ce79b1d5-ea31-d800-3294-5b6cfb5d83b0.png><br>
3.Intellijでgradleプロジェクトを再度同期します。<br>
<img src = https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2629102/f2131afd-145d-2eaf-4794-1cba838fef72.png><br>
以上になります。
<h1>所感</h1>
初投稿です。<br>
頑張ってそれっぽく書きました！<br>
以上です。
[SDK46] hermesをオンにするとAndroidのreleaseビルドでクラッシュする

## 発生した問題
- Androidのreleaseビルドでのみクラッシュする
  - 実機でアプリを起動直後にクラッシュする
- debugビルドでは問題ない。エラーもなくエミュレータで立ち上がる
- 実機をMacに有線で繋ぎAndroid StudioのLogcatを開くと以下のエラーを確認できる（本当はもっとたくさん出てる）

```
java. lang. Exception: No launchable update was found. If this is a bare workflow app, make sure you have configured expo-updates correctly in android/app/build.gradle.
```
```
com.facebook.jni.CppException: Compiling JS failed: Wrong bytecode version. Expected 85 but got 84 Buffer size
```

## 環境
- expo: 46.0.16
- react: 18.0.0
- react-native: 0.69.6

## 経緯

- SDK44 -> SDK46へアップグレード完了
- 実機でreleaseビルドが問題なく動くことを確認する
- Upgrade Helperに沿って修正したタイミングでAndroidのhermesをオフにしてしまったことに気づく
- `app/build.gradle`で`enableHermes: true`とする
- **releaseビルドでクラッシュする問題が発生**

## 解決策
https://github.com/facebook/react-native/issues/34114
このissueに記載されている解決策に沿って`hermesCommand`の一文を消す
```app/build.gradle
project.ext.react = [
    enableHermes: true,
    cliPath: new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim()).getParentFile().getAbsolutePath() + "/cli.js",
    // ここの一文を消す→ hermesCommand: new File(["node", "--print", "require.resolve('hermes-engine/package.json')"].execute(null, rootDir).text.trim()).getParentFile().getAbsolutePath() + "/%OS-BIN%/hermesc",
    composeSourceMapsPath: new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim()).getParentFile().getAbsolutePath() + "/scripts/compose-source-maps.js",
]
```

これで問題が解決しました。
ちょっともう記憶にないのですが、以前expo-modulesに移行したときに移行ドキュメントに従って追加した`hermesCommand`が原因だったようです。

## 振り返り
エラー文で検索すると`expo-update`や、依存している`sentry-expo`を疑う投稿が複数あり、Androidのreleaseビルドのみクラッシュするという症状も同じだったので、その方向で調査を続けてだいぶ時間を溶かしてしまいました。
今回の自分の問題はhermesをオフにすれば消えるので、hermesの設定周りからもう少し早く見直すべきでした。
AWSハンズオン_４_IAMの４_Organization_1_マスタアカウントやメンバーアカウントを作って、組織単位を作っていく

AWSの初心者のさとしです
ハンズオンで勉強メモとして投稿いたします。
ご覧になったみんなさんにお役に立てればうれしいです
※：間違ったところがあれば、ご指摘していただければ幸いです
#本文
本日のハンズオンはOrganizationのマスタアカウントやメンバーアカウントを作って、組織単位を作っていく練習です
ーーーーーーーーーーーーーーーーーーーーーーーー
下記の応用場面を考えると
一つの部署で複数のアカウントが存在していて、部署の組織を作って、階層することで管理することができます。
今回のハンズオンは
　　この組織の階層構造を作るOUといって組織単位を作って、その組織単位でメンバーアカウントをグループすることができます。

手順：
１，マスタアカウントを作る（必ずルートアカウント）
    
２，メンバーアカウントを追加
３，別のアカウントのメールを招待して、送信する
　招待メールを受けて、Acceptをクリック前に招待されたメールのアカウントでAWSのコンソール画面にアクセス必要があります
４，元のアカウントに戻って、招待画面で確認できます

５，元のアカウントに戻って、新しいアカウントが参加することがわかります。
６，組織単位を作ります
#ハンズオン
ーーーーーーーーーーーーーーーーーーーーーーーー
１，マスタアカウントを作る（必ずルートアカウント）
ルートアカウントでアクセスして
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488091/c755cb03-4099-cc92-a744-3b13692c56c6.png)
自動的にルートアカウントの管理アカウントが作成できました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488091/c5befa5c-6251-8969-90fb-20e6f20cd206.png)
２，メンバーアカウントを追加します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488091/f446e6ef-9d8d-2cd4-8a0d-aabf8653a412.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488091/472eabd3-9303-c14c-6ab4-11cbe50c7a62.png)

３，別のアカウントのメールを招待して、送信する
※ここで注意※
招待されたメールのAccectを受ける前に
そのメールでAWSへアクセスする必要があります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488091/89de451e-2f5f-6f0e-5394-b8524f536823.png)

４，元のアカウントに戻って、招待画面で確認できます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488091/acf259de-1000-20ec-1e6f-ef750d43808e.png)
招待を承認されました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488091/fa0b27b6-66fb-8b9f-5e66-22e9d62a6b80.png)
５，元のアカウントに戻って、新しいアカウントが参加することがわかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488091/2db27dce-0c6d-c5c3-93e3-e32ca496207c.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488091/a34b1f52-67ff-b5f8-070f-5a1b31f872ef.png)

６，組織単位を作ります
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488091/5ed1da26-cff1-5c45-0e19-9a8937241c68.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488091/7441428f-9f80-b392-d717-cd38da21d69e.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488091/acc9ac4d-abf8-7ce9-f735-42ea65e72561.png)
広報部へメンバーを追加する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488091/4ec3fe03-aa31-07ac-f45b-f021e56bdd1d.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488091/69319996-b9e2-24ba-e6a1-ef2ad1c24385.png)
移動できました

以上、今回のハンズオンでした。
Javaで何か作ってみる(2022/11/16 Day27)

## 今日やった事
- Javaの動画教材の演習問題である、ケーキ屋プログラムの作成を行った。  
&rarr;コミットした内容は[こちら](https://github.com/takamatsuryota3/Java/commit/1acea849a55c752fdd48b639000dfad668cbd367)
## 参考にしたもの
- [【超絶丁寧解説】Javaプログラミングをゼロから学ぶ！絶対挫折させない「基礎入門」講座【講師評価4.3】](https://www.udemy.com/course/uz-java-kiso/)  
&rarr;今回取り組んだのは、この動画教材の中の、**J1-EX1_総合演習（アルゴリズム）** の**総合演習（ケーキ屋プログラムの作成）** になる。
## 所感
- 大方ケーキ屋プログラムを完成させる事が出来た。
- Integer.parseIntの例外処理等、一部出来ていないところがある。
## 明日の予定
- 明日は、ケーキ屋プログラムの残りをやり切る。
- その後は、動画教材の続きから進めていく。
- （これは余談だが）明日、Amazonで頼んだ、モニターアームが届くので設置したい。
androidスマホでpython開発環境構築

# 今回はTermuxを利用してAndroidでPythonを活用する方法を紹介しよう。
# 1. Termuxのインストール方法
  androidのPlayStoreからTermuxをインストールする。
 - android
 https://play.google.com/store/apps/details?id=com.termux&hl=ja&gl=US&pli=1

![andorid-termux.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2981486/11a40a01-3485-8615-d49b-24bf7aa0425e.png)

# 2. Python開発環境構築

- Pythonをインストールしよう
 Termuxのアプリを開いて、以下のコマンドを実行します。
 `pkg install python`
![Screenshot_2022-11-16-23-21-13-83_84d3000e3f4017145260f7618db1d683.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2981486/bccc655f-4165-80e2-ef92-5e6d32a88e5e.jpeg)

- pythonコンソールでテストコード検証
 コマンドラインで`python`を入力し、Enterを押して、pythonコンソールを開く
コンソールにprint("hello world")を入力、１Enterを押して、実行結果を確認する。
![Screenshot_2022-11-16-23-23-28-28_84d3000e3f4017145260f7618db1d683.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2981486/33b18e4c-414b-0eed-9a90-f242b0324040.jpeg)

- pythonのソースコードファイル作成＆実行
  - pyファイル作成のため、内部のストレージをアクセス必要です。まず【Termux】内部ストレージ・SDカードへアクセスの設定をします。
  コマンドラインに`termux-setup-storage`を入力し、内部のストレージアクセスできるように設定する。
  ```
  $ cd ~storage　　　　　　　　　　　　　　　　　　　  　　　　　　　　　　　　　
  $ pwd　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　
  $ /data/data/com.termux/files/home/storage
  ```

  - pyファイル作成
  ```
  $ vim test.py
  vimで下記ソースコード入力し、test.pyで保存します。　　　　　　　　　　　　　　  　　　
  test_str = "hello world"
  print(test_str)
  ```
  - pyファイル実行
  　`python pyファイル名`で実行します
  ```
  $ python test.py
  hello world　
  ```

以上です。androidスマホでpython開発環境の構築手順です。
ご参考出来れば嬉しいです。ありがとうございました。
DDDがわからない～役割分担を楽にする～

# カレーかシチューかハヤシか。。。
前回は、みんなでやることで楽をすることを考えました。今回は分け方のコツについて考えてみたいと思います。
そんなわけで、夕飯のメニューが決まらずにみんなで手分けして作ることにしました。
~~~text:それぞれ作る方式
カレー担当
1. 野菜の皮を剥く
2. 野菜を切る
3. 肉を切る
4. カレーのルーを入れる
5. 煮込む

シチュー担当
1. 野菜の皮を剥く
2. 野菜を切る
3. 肉を切る
4. シチューのルーを入れる
5. 煮込む

ハヤシ担当
1. 野菜の皮を剥く
2. 野菜を切る
3. 肉を切る
4. ハヤシのルーを入れる
5. 煮込む
~~~
これで、みんな好きなものをご飯にかけて食べれるようになりました。
ですが、役割分担では担当者全員が皮を剥く、切る、煮込むの３つの動作をそれぞれが覚える必要が出来てしまいました。
ですので、役割分担を変えてみましょう。
~~~text:みんなで作る方式
皮むき担当
1. 野菜の皮を剥く

切る担当
1. 皮を剥いた野菜を切る
2. 肉を切る

煮込む担当
1. ハヤシのルーを入れる
2. 煮込む
~~~

これで、それぞれ一つの動作を覚えればよくなりました。

これにはもう一つメリットがあります。例えば新たにビーフシチューも増やそうとした場合、それぞれ**作る方式**では新たに皮を剥く、切る、煮込むをすべて覚えた人間を用意する必要が出てきます。
しかし、**みんなで作る方式**であれば、各担当者にちょとづつお願いすれば済むので人を増やす必要もなく、ひとりひとりの負荷も少なくて済みます。

**皮むき担当が一番めんどくさいだろうというのは気にしないでください。**
【SwiftUI】ボタンアクションの共通化

結論から書くとこちら。

    struct CustomButton: View {
    
        let function: () -> Void
    
        var body: some View{
    
            Button(action: {
                function()
                
            }) {
                Text("テキスト")
    
            }
    
        }
    }

呼び出し方はこんな感じ。

    CustomButton(function: {
        print("11111")
    })

ボタンアクションをまた別の関数化したいなんて方はこんな感じ。

    func sample(){
        print("あああああ")
    }

    //Viewの中で呼ぶ
    var body: some View{
        
        CustomButton(function: {
            sample()
            
        })
    }

Flutterの仕事をずっとしてて次はSwiftUIの仕事ねと言われたのはいいものの、Buttonを共通化しようとしたときにあれ？swiftUIってボタンアクションの型なんだ？ってなり調べたけど、あまり記事がありませんでした。

なので、自身の忘備録も兼ねて投稿です。

どなたかの参考になれば幸いです。

ではまた。
Linux-Windowsファイル転送（ssh）

# Linux-Windowsファイル転送（ssh）について
簡単に接続できますよ。

# Linuxの設定
Linuxはsshをインストールする

* ssh インストール
```
sudo apt -y install openssh-server
```

* sshを起動
```
sudo systemctl restart ssh
```

* OS起動時からsshを起動
```
sudo systemctl enable ssh
```

* net-toolsインストール
```
sudo apt -y install openssh-server
```

* ip確認
```
ifconfig
```

# Windowsから接続
Linuxの調べたIPに接続してファイル転送を行います。

* SSHで接続
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2729656/f6b7410d-bbbc-6ded-d45f-907503963755.png)

* パスワード認証で接続
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2729656/436a0fab-834d-3936-3fbf-299a111ab34f.png)

* SSHでファイル転送メニュー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2729656/2c5b0cdb-9066-b3f7-2bda-3c95348e7fe6.png)

* 転送
上側は、WindowsのファイルをLinuxに転送
下側は、LinuxのファイルをWindowsから取得
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2729656/351ddace-d6d6-a6a1-6ee5-c595fb8cf1aa.png)
dockerでファイルサーバー構築

### 環境
ubuntu 22.04LTS
docker 20.10.12-0ubuntu4

## dockerインストール
```
sudo snap install docker
```

linux mint ではsnapがデフォルトで無効になっているので以下のURLを参照。

http://baker-street.jugem.jp/?eid=116

その後、`snap refresh`を叩いてdockerをインストール実行するとまた`snap refresh`を実行しろと促す場合があるので、以下のコマンドを叩くと
```
$ sudo snap list
No snaps are installed yet. Try 'snap install hello-world'.
```

言われた通りに実行してみる。
以下のような結果が出力されれば、snapを使ったインストールが可能になる。
```
$ sudo snap install hello-world
Setup snap "core" (16202) security profiles                                                                         
2024-01-16T14:32:05+09:00 INFO Waiting for automatic snapd restart...
hello-world 6.4 from Canonical✓ installed
```


## 権限変更
```
sudo groupadd docker && sudo usermod -aG docker hoge && reboot
```

## 共有ディレクトリ作成
```
mkdir /home/hoge/share
```

## コンテナ作成
出力された値の一番最後の英数字乱列がコンテナidを表す。
```
sudo docker create -it -p 139:139 -p 445:445 --name smbsrv -v /home/hoge/share:/path1 dperson/samba \-p -r -u "hoge;パスワード" -s "share;/path1;yes;no;no;hoge"
```

## コンテナ起動、確認
```
docker restart コンテナid && docker ps
```

## iphoneからアクセス
ファイルからブラウズ画面を表示。右上の･･･からサーバ接続
欄にはpcのipアドレス 
分からなければサーバの端末で`hostname -i`を叩く。
<img width="300" alt="IMG_7868.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2929519/96328897-5407-d023-7f20-c934ba6503dc.jpeg">
登録ユーザを選択して先程コンテナ作成した時に指定した名前hoge、パスワードを入力
<img width="300" alt="IMG_7869.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2929519/2b8a1397-aaa0-fde3-88f5-4249a8a7d00d.jpeg">

## ターミナルからアクセス
```
smbclient //サーバーipアドレス/share -U hoge
```
AmplifyでDynamoDBにTTL設定してみる

# 概要
Amplifyで有効期限付きのデータを扱いたくなったので、DynamoDBのTTL設定ができないか調べたところ設定方法があるようなのでメモを。

# API作成
amplify cliのおなじみのコマンドでapiを作成します。

```
amplify add api
```

schema.graphqlは以下のような感じ。（サンプルのやつにttlを追加）
```
type Todo @model {
  id: ID!
  name: String!
  description: String
  ttl: AWSTimestamp!
}
```

# APIのカスタマイズ
[公式](https://docs.amplify.aws/cli/graphql/override/)の記事に従ってカスタマイズ設定を施す。

```
amplify override api
```
/amplify/backend/api/<api名>フォルダの下に「override.ts」というファイルが生成されるので以下のようにttl設定を行う。
（"Todo"の箇所を自分の環境に合わせて書き換える。）

```
import { AmplifyApiGraphQlResourceStackTemplate } from '@aws-amplify/cli-extensibility-helper';

export function override(resources: AmplifyApiGraphQlResourceStackTemplate) {
  resources.models["Todo"].modelDDBTable.timeToLiveSpecification = {
    attributeName: "ttl",
    enabled: true
  }
}

```

# デプロイ

エラーが起こらないことを祈りつつ、心を込めてコマンドを打つ。
```
amplify push
```

無事、デプロイが完了するとDynamodbにTodoテーブルが作成される。

# 動作を見てみる
## データ投入
確認方法は何でも良いが、手軽に試したいのでAppSyncのコンソールからmutation実行。

```
mutation MyMutation {
  createTodo(input: {id: "001", name: "hoge", description: "desc", ttl: 1668608700}) {
    id
  }
}

```

TTL属性はエポック時間形式で指定する必要がありますが、計算が面倒だったので以下のような[EpochConveter](https://www.epochconverter.com/)を利用させていだだきました。
[公式の記事](https://aws.amazon.com/jp/premiumsupport/knowledge-center/ttl-dynamodb/)にも紹介されているし、怪しいものではないはず。

## 結果の観測
無事、データ投入ができたので有効期限経過後にデータが削除されるのを待つ。

...
...
が、時間が過ぎても消される様子がない。。。

調べてみると、
「TTL タイムスタンプの有効期限が切れると、DynamoDB は書き込みスループットをまったく消費せずに 48 時間以内にテーブルから項目を削除します。」

って書いてますね。
有効期限後に即座に削除されることを保証するものではないみたい。orz

TTLは場合によっては48時間以上の時間を要する事例もあるようなので、レコードの削除が即座に行われることを期待するようなサービスでは地道にCloudWatch EventsでLambda定期実行して該当レコードを削除していく方法を取ることになりそう。

もちろん、TTL設定だけで不要なレコードが削除されるのは非常に便利なので、使い所は要件次第ですが。

# その他
ちなみに、AmplifyでTTL設定するのに[graphql-ttl-transformer](https://github.com/flogy/graphql-ttl-transformer)というライブラリがあるようですが、こちらを試したところ以下エラーでamplify pushに失敗したため断念しました。
使ったamplify cliのバージョンはv10.4.1。
```
Unable to import custom transformer module(graphql-ttl-transformer).
🛑 You may fix this error by editing transformers at graphql-ttl-transformer/transform.conf.json
```

# まとめ
AmplifyのAPIのカスタマイズ機能を使ってDynamoDBのTTL設定を試してみました。驚くほど簡単に設定ができてしまいますね。
今回調べてみたoverride apiだけでも他に色々ありそうなので、機会があれば試してみたいと思います。
IBM Cloud FunctionsのPeriodicトリガーを使ってアプリを実行する(コマンドを使って構築)

# はじめに
以前に投稿した記事「[IBM Cloud FunctionsのPeriodicトリガーを使ってアプリを実行する](https://qiita.com/kenji_kanzaki/items/454027ee258254392d9f)」ではUIのみで作業を行いました
本記事では上述の作業をコマンドを利用して行います。

# 前提
* IBM Cloudが提供している2022/11/16時点の機能を用いています。

# 準備
1. リンク先の手順に従って、[IBM Cloud コマンド・ライン・インターフェース (CLI)](https://cloud.ibm.com/docs/cli?topic=cli-getting-started) をインストールします。
1. リンク先の手順に従って、[Cloud Functions プラグイン](https://cloud.ibm.com/functions/learn/cli)をインストールします。
1. 2の手順に従い、IBM Cloudへのログインと名前空間のターゲットを指定します。


# Acionの作成
次の内容のJavascriptファイルoutputInvokedLogCmd.jsを作成します。
```javascript:outputInvokedLogCmd.js
function main(params) {
    var date = new Date();
    console.log("Invoked at: " + date.toLocaleString());
    console.log("param testKey: " +params.testKey);
    return { message: 'Invoked at: ' + date.toLocaleString() };
}
```
Javascriptファイルからアクションを作成します。
```shell:
ibmcloud fn action create outputInvokedLogCmd outputInvokedLogCmd.js
```
```
ok: created action outputInvokedLogCmd
```
アクションの一覧を表示し、アクションが作成されていることを確認します。
```shell:
ibmcloud fn action list
```
```shell:
actions
<NAMESPACE>/outputInvokedLogCmd  private nodejs:16
```

# Triggerの作成
CRON式「0/1 * * * *」を利用して、1分毎に起動されるトリガーを作成します。
```shell:
ibmcloud fn trigger create every1Minute --feed /whisk.system/alarms/alarm -p cron "0/1 * * * *"
```
~~~
ok: invoked /whisk.system/alarms/alarm with id xxxxxxxxxxxxxxxxxxxxxxx
~~~
トリガーの一覧を表示し、トリガーが作成されていることを確認します。
```shell:
ibmcloud fn trigger list
```
~~~
triggers
<NAMESPACE>/every1Minute         private
~~~

# Ruleの作成および動作確認
ActionとTriggerを紐づけるRuleを作成します。
```shell:
ibmcloud fn rule create every1MinuteRule every1Minute outputInvokedLogCmd
```
~~~
ok: created rule every1MinuteRule
~~~

Ruleの一覧を表示し、Ruleが作成されていることを確認します。
```shell:
ibmcloud fn rule list
```
~~~
rules
<NAMESPACE>/every1MinuteRule       private          active
~~~

Ruleが作成され、ActionとTriggerが紐づいたことで1分おきにActionが実行されるようになっています。
アクティベーションを確認しActionが実行されていることを確認します。（直近の4行の未出力するコマンドです）
```shell:
ibmcloud fn activation list -l 4
```
~~~
Datetime            Activation ID                    Kind      Start Duration   Status  Entity
2022-11-16 23:29:00 8f3ad4393364478dbad4393364278d02 nodejs:16 cold  43ms       success <NAMESPACE>/outputInvokedLogCmd:0.0.1
2022-11-16 23:29:00 d216187b86cb411b96187b86cbe11b97 trigger   warm  0s         success <NAMESPACE>/every1Minute:0.0.1
2022-11-16 23:28:01 6013f890b6724d0e93f890b672ed0e22 nodejs:16 warm  4ms        success <NAMESPACE>/outputInvokedLogCmd:0.0.1
2022-11-16 23:28:01 ddd190be648c48489190be648ca84859 trigger   warm  0s         success <NAMESPACE>/every1Minute:0.0.1
~~~

1分おきにActionが実行し続けるのでRuleとTriggerを削除します。
```shell:
ibmcloud fn rule delete every1MinuteRule
ok: deleted rule every1MinuteRule

ibmcloud fn trigger delete every1Minute
ok: deleted trigger every1Minute
```
文件夹名(系统时间)

文件夹名(系统时间).bat

```@ech off
set dt=%date:~0,4%%date:~5,2%%date:~8,2%
reg add "HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\NamingTemplates " /v "RenameNameTemplate" /d %dt% /f
pasue
```
AWS Cosole、ヘルプの説明がわかりずらかった話

AWSは初心者には何がどこで課金されているのかわかりずらいという話を書きましたが、AWSがわかりずらのはそれだけではありません。

1. AWS Consoleの説明、ヘルプの説明が、ほとんど英語の機械翻訳のそのまま。なので、日本語的におかしいし、(英語の原文を見ると、あーなるほどなと思うフシもある)どう見ても、不自然な文章。
1. AWS ConsoleのGUIの変更が激しい。1年〜2年前のちょっと古い記事、blogでも、もうその画面は変わっている。記事、blogで書かれている箇所が今のAWS Consoleのどこに相当するのか、考えないといけない。
1. 色々と機能が豊富すぎる。^^; もっと最低限に絞ってもいいと思う。後から、後から機能追加された新機能があっても、それでも今まで使っていた古い機能も使っているひとがいるので、無くすことはできない。そうやって、膨らんでいっている。

例えばAWS S3のアクセス制御。S3も単なるGoogleDriveやBox、OneDriveみたいなストレージかと思っていたら、いやいや、機能満載で、奥深い。

![Screenshot_20221116_221354.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933408/70969b77-bece-1baf-3ab1-32a8986343dc.png)
Bugetを作る時にまず、ACL無効か有効化で分かれ道がある。どうやら、ACL無効にできる機能が追加になったのが2021年らしい。なのでこの画面は2021から。AWSはACL無効を推奨している。(って、ことはそれまでは全部ACL有効だったってこと？)ま、だからここはACL無効でいいんじゃないか。全般的にACL無効の流れらしい。

で、次。
![Screenshot_20221116_221443.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933408/d2193d1b-e540-571f-f48a-7f10299bef67.png)
ここで面食らってしまう。この説明読んですぐわかる人いるんだろうか・・・？

AWS S3にはアクセスコントロールの種類が3つあって、
1. ACL(アクセスコントロールリスト)
1. バケットポリシー
1. IAMポリシー

IAMはIAMなんでAWS内部からのアクセス制御なんだろうな。
それに対し外からのアクセス制御がACLとバケットポリシーのふたつがあるのか。

上の図で言う1番目と2番めはACLのことを言っているのだと思う。
3番目と4番目はバケットポリシーのことを言っているのだと思う。

S3としては極力外部からアクセスを許さないように倒す(情報漏えい対策)ので、ACLやバゲットポリーで誤って外部からのアクセスを許可しても、それをブロックするのがここの機能らしい。

で、
1. 新しいACL
1. 任意のACL
1. 新しいバゲットポリシー
1. 任意のバゲットポリシー

で、新しい/任意、ACL/バゲットポリシーで、2×2になっているが、この新しい/任意って、何なの？この説明じゃ、さっぱりわからない。どうやら、この辺の解説を読むと・・・

[非凡な才能をください。 都心でサラリーマンやってます。書きます。](https://muessenwirwollen.hatenablog.com/entry/2019/10/19/203706)

「新しい」は新規にバゲット、オブジェクトが作られるときに付くACL、バゲットポリシーのことを言っているらしい。この時にパブリック・アクセスが有りでもブロックすると言っているのだと思う。
それに対し「任意の」は既にあるバゲット、オブジェクトで変更が加えられないものを指しているのか？それが、パブリック・アクセスが有りでもブロックすると言っているのだと思う。

うーん・・・「新しい/任意の」てか、「新規の/既存の」方が意味が合っているのでは？AWS Consoleのこういうところがわかりずらい。

そもそも、分ける必要あるのか？「任意の」が両方カバーすりゃいいんじゃないのか？と思うが、そこがAWS。違うらしい。

「新しい」はACLやバゲットポリシーの編集の際に、パブリック・アクセスを誤って付けてしまうのを防ごうという意図らしい。なので、今、オブジェクトが0個ならば、「新しい」だけ付けておけば、ACLやバゲットポリシーでパブリックアクセスを許可することができない。(許可したバゲット、オブジェクトが作れない)

それに対し、「任意の」はもう既にパブリックアクセスを許可してしまっているものをブロックする意図らしい。


うーむ・・・AWSのプロフェッショナルになってくれば、AWS Consoleに書いてある説明や、ヘルプは「あー、ここは、こういうことを言っているのね・・・」って雰囲気で分かるんだろうが、そこまで行くにはかなりの修行を積む必要がありそうだ。

**AWSエキスパートの方々には突っ込みどころ満載であるかもしれませんが、あくまでも初心者目線で、別な初心者がハマるであろうところに着目した記事であるということでご容赦いただきたい。**
VSCodeの拡張機能

## はじめに

Web開発の学習過程で自分が使った拡張機能のメモ👀
フロントエンド学習がメインのため、フロントエンド寄り。

## 基本機能

#### Japanese Language Pack for Visual Studio Code
https://marketplace.visualstudio.com/items?itemName=MS-CEINTL.vscode-language-pack-ja

VSCodeを日本語化してくれる

#### indent-rainbow
https://marketplace.visualstudio.com/items?itemName=oderwat.indent-rainbow

インデントを虹色で表示してくれる

#### Code Spell Checker
https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker

コードのtypoを視覚化してくれる

#### zenkaku
https://marketplace.visualstudio.com/items?itemName=mosapride.zenkaku

全角スペースを視覚化してくれる

## フロントエンド

#### Live Sass Compiler

https://marketplace.visualstudio.com/items?itemName=glenn2223.live-sass

Sassを自動でCSSにコンパイルして表示してくれる機能



## Git

#### Git History

https://marketplace.visualstudio.com/items?itemName=donjayamanne.githistory

ブランチのコミット履歴が表示され、コードの最終承認者を表示してくれる

## その他

#### Todo Tree
https://marketplace.visualstudio.com/items?itemName=Gruntfuggly.todo-tree

ソースコードにコメントで「TODO:」と書いておくと、エクスプローラーペインにツリービューとして表示してくれる

#### vscode-pets
https://marketplace.visualstudio.com/items?itemName=tonybaloney.vscode-pets

VSCode上に猫ちゃんや蛇などのペットを表示してくれる（癒し機能）
管理者と顧客を分けてDeviseを導入

## 初めに
今回は管理者と顧客を分けてDeviseを導入していきたいと思います。
※実装前提としてDeviseを導入していること


## 管理者と顧客のモデル設定

管理者側がAdmin
```
管理者用
$ rails g devise Admin
```
今回顧客側がCustomer
```
顧客用
$ rails g devise Customer
```
これをそれぞれターミナルに打ち込みます。

## 次にcontrollerを管理者、顧客で作成
```
管理者用
$ rails g devise:controllers admin
```
```
顧客用
$ rails g devise:controllers public
```
これらをそれぞれ記述するとappのcontrollerの部分がadminとpublicそれぞれ作成され２つに分かれてくれます。


## viewページの方も作成

```
管理者用
$ rails g devise:views admins
```
```
顧客用
$ rails g devise:views publics
```
これらを記述する事でviewページの方も管理者、顧客に分けて作成する事ができます。

※注意
これらを記述した後に作成されたフォルダはadmins、publicsのように複数形のままで作成されているのでadminsならadmin、publicsならpublicと単数形に改名してあげましょう。


## controllerの追加の仕方

```
$ rails g controller public/homes
```
このようにpublic/homesを付け足す事でpublicにhomes_controller.rbができます。
adminに欲しい場合はadmin/homesに変えてあげること。
【Laravel】Composerでパッケージ削除してみた

Laravelを使用している業務の中で不要になったパッケージがありまして、そちらを削除することになりました。
ちなみに私にとって初めてのパッケージ削除でして備忘録として残したいと思います。

今回はpdf機能で使用していたdompdfを削除しました。

方法は簡単です。以下のコマンド打ちました。
```
composer remove "barryvdh/laravel-dompdf"
```
composer remove コマンドでパッケージ名を指定するだけです。
```
composer remove "パッケージ名"

// パッケージ名はcomposer.jsonで確認することができます
```

このコマンド打つと、composer.jsonとcomposer.lockからdompdfに関する記述が消えていることが確認できました。

ただし、これだけでは完了とはいきませんでした。
プロジェクト内でdompdfで検索をかけると、明らかにdompdfに関するファイルが残っていました。
```
config/dompdf.php
```
このファイルを手動で削除しまして完了になります。

今回のパッケージ削除は案外サクッといきましたが、ググってみると一筋縄ではいかないものもあるようですね。
なぜRustはメモリ安全なのかをC言語のコードと考える

追記: Twitterなどでご指摘等いただいているのをコメントしてますので、ぜひそちらもご覧ください！

## これはなに

絶賛Rust勉強中の僕が、「なんでRustはメモリ安全って言われているの？」と聞かれたので、実際にメモリ安全ではない（？）C言語のコードを並べてみて考える記事です。

## C言語の場合

### メモリリーク

以下のコードはメモリリークを起こす可能性があります。

```c:memory_leak.c
#include <stdio.h>
#include <stdlib.h>

#define STR_BUF_SIZE 100000000

char *str_new() { return calloc(STR_BUF_SIZE, sizeof(char)); }

int main() {
  for (int i = 0; i < 100000000; i++) {
    char *str = str_new();
    snprintf(str, STR_BUF_SIZE, "[number: %d]", i);

    printf("%s\n", str);
  }

  return 0;
}
```

メモリリークを起こす原因としては、`calloc`によってアロケートされたメモリが不要になっているにも関わらず、開放されないためです。

### バッファオーバーラン

以下のコードは、確保したメモリの領域外にアクセスがされてしまう例です。

```c:buffer_overrun.c
#include <stdio.h>

#define BUF_SIZE 16

int main() {
  int buf[BUF_SIZE];

  for (int i = 0; i < BUF_SIZE + 2; i++) {
    buf[i] = i;
    printf("buf[%d]: %d\n", i, buf[i]);
  }

  return 0;
}
```

配列`buf`のサイズ`16`を超えて書き込みが行われてしまっており、また、エラーにならずに実行できてしまいます。

## Rustの場合

### メモリリーク

Rustには所有権・ライフタイムの仕組みがあり、スコープをでると自動的に開放（`drop`）されます。

```rust:memory_leak.rs
fn main() {
    for i in 1..10000000 {
        let str = format!("[number: {}]", i);
        println!("{}", str);
    }
}
```

そのため、C言語の例のように、動的に確保したメモリを開放し忘れる心配がいらなくなります。

また、ライフタイムの仕組みによって、ダングリングポインタなども考える必要がなくなります。

### バッファオーバーラン

Rustでは、実行時に確保されたメモリ領域内であるかのチェックが走るようになります。

```rust:buffer_overrun.rs
const BUF_SIZE: usize = 16;

fn main() {
    let mut buf = [0; BUF_SIZE];

    for i in 0..(BUF_SIZE + 2) {
        buf[i] = i;
        println!("buf[{}]: {}", i, buf[i]);
    }
}
```

なお、実行時チェックのオーバーヘッドがあるようなので、イテレータなどを使うようにするのが良い様です。

## さいごに

他にもあると思いますが、これでRustのメモリ安全のイメージが湧くと嬉しいです。
間違いなどありましたら、コメント・編集リクエストから教えていただけると勉強になります。

## Refs

- [安全と危険のご紹介 - Rust裏本](https://doc.rust-jp.rs/rust-nomicon-ja/meet-safe-and-unsafe.html)
- [なぜRustなの？と言われた時のために](https://zenn.dev/khale/articles/rust-beginners-catchup)
- [Rustのメモリ管理機能とその特徴 | 己の不学を恥じる](https://garasubo.github.io/hexo/2021/11/07/rust-memory.html)
- [Rustのメモリ管理って面白い - Qiita](https://qiita.com/ksato9700/items/312be99d8264b553b193)
- [コンセプトから理解するRust：書籍案内｜技術評論社](https://gihyo.jp/book/2022/978-4-297-12562-2)
Androidのベースプログラム作成時のリソースの使い方について

# はじめに

Android開発で毎回ベースプログラムが安定せず、自分のように毎回プログラムの記述を変えてしまう自分のような人に読んでほしい。

# 目的

Android開発は基本的にKotlin言語で開発しており、コーディング規約等は存在しているのですがリソースやメソッド等の記述についての決まり事が少なく。
毎回別人が開発したようなプログラムとなってしまうのを防止したい。

# 前提

AndroidStudioのVersionUPにより、ベースプログラムを作成して毎回同じリソースやプログラムを使い回しする事は難しいと思われるので、記述方法のみを参考にして毎回最新のAndroidStudioのVersionで新規作成するようにしましょう！！

# colors.xml

色情報を管理する為のXMLファイル。
base_** : 画面設計書等で指定されているカラーコードを記載
text_color_white : 色情報を直接使用するのではなく、base_**の色リソースを使用する

```xml:colors.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- 基本的な色情報 -->
    <color name="base_color_white">#FFFFFF</color>

    <!-- レイアウト等に仕様するリソース -->
    <color name="text_color_white">@color/base_color_white</color>
</resources>
```

上記のように直接カラーコードを記載させない事で、ある程度の決まりを維持する事が可能に・・・・なるかも。。。。

# dimens.xml

サイズ情報を管理する為のXMLファイル。
sp** : 画面設計書等で指定されているサイズを指定(リソース情報が数字で開始出来ない為、spと16を入れ替えしている。。。。)
text_size_big : サイズ情報を直接指定するのではなく、sp**のサイズリソースを使用する

```xml:dimen.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- 基本的なサイズ情報 -->
    <dimen name="sp16">16sp</color>

    <!-- レイアウト等に仕様するリソース -->
    <dimen name="text_size_big">@dimen/sp16</color>
</resources>
```

こちらに関しては、正直微妙な気がする。
サイズに関しては、dimen.xmlで指定サイズのみ利用可能にするのではなく、styleを充実させ、そちらで各サイズがボタンやテキストしか利用出来ないようにした方がいいかもしれない。。。

# styles.xml

テキストやボタン等のレイアウト情報を格納するファイル
基本ここで仕様的な共通情報を登録し、どの画面でも共通したレイアウトが作成出来るようにする。
個人的にこのファイルが一番重要だと感じてます。複数人数で開発する際には最初にほぼ全て情報を入力し、更新が無いようにすれば誰がレイアウトを作成しても同じようなレイアウトが作成出来て、尚且つ修正も簡単になるかと。

```xml:styles.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="Base.Button" parent="Widget.AppCompat.Button.Borderless">
        <item name="android:textSize">@dimen/text_size_big</item>
        <item name="android:background">@drawable/noborder_button</item>
    </style>
</resources>
```

# PR

エンジニアとして一緒に働きませんか！！
創業から3年が経ち、成長段階の弊社ですが、1人の裁量が大きいためスキルを身につけやすい環境です。
フレックス出勤やリモートワークも取り入れ、エンジニアにとって働きやすい制度も整っております。
このように、自分らしい働き方を見つけながら、さまざまなことに挑戦し、成長していきたいエンジニアを絶賛募集中です!!

https://bravestudio.co.jp/%E6%8E%A1%E7%94%A8/%E5%8B%9F%E9%9B%86%E8%A6%81%E9%A0%85/