OmniAICreator/Qiita-1.07M huggingface dataset:
CI/CDやってみた③ Serverless FrameworkとCodeBuildを使ってS3 bucketにlambdaにfileをuploadする

前回、前々回でlambda functionとS3 bucketを作成しました。
今回はそれらを組み合わせて、lambda functionを使ってファイルをS3にアップロードしてみます。


# 今回の目的
lambdaを使って、以下のtxtファイルを、S3 bucketにアップロードします。
```txt:hello.txt
lambda to s3 !
```
以下がアーキテクチャです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2950855/495ca1b6-102f-e1ba-8532-11048875b08c.png)



# buildspec.ymlの作成
GitHubレポジトリのrootに作成します。
前回と同じものを使います。

```yml:buildspec.yml
#buildspecのバージョンを指定する
version: 0.2 

#ビルドの各段階で実行するコマンドを書いていく
phases: 
  install:
    commands:
      - npm install -g serverless #serverlessをインストールする
  build:
    commands:
      - sls deploy               #serverless.ymlの内容をdeployする
      - echo 'deploy finished!'
```

# serverless.ymlの作成
GitHubレポジトリのrootに作成します。

以下を参考に作成しました。


```yml:serverless.yml
service: serverless-lambda-s3-test

provider:
  name: aws
  runtime: python3.9
  stage: dev
  region: ap-northeast-1


functions:
  uploads3:
    handler: handler.upload_file
    role: lambdaS3RoleResource

resources:
  Resources:
    s3hello:
      Type: AWS::S3::Bucket
      Properties:
        BucketName: serverless-s3-bucket-hello-txt
    lambdaS3RoleResource:
      Type: AWS::IAM::Role
      Properties:
        AssumeRolePolicyDocument:
          Version: "2012-10-17"
          Statement:
            - Effect: Allow
              Principal:
                Service:
                  - lambda.amazonaws.com
              Action:
                - 'sts:AssumeRole'
        Policies:
          - PolicyName: lambdaS3Policy
            PolicyDocument:
              Version: "2012-10-17"
              Statement:
                - Effect: Allow
                  Action: 
                    - 'logs:CreateLogGroup'
                    - 'logs:CreateLogStream'
                    - 'logs:PutLogEvents'
                    - 's3:PutObject'
                  Resource: '*'
```

今回はS3にfileをuploadするためにIAM RoleとIAM Policyを設定する必要があります。

私は以下の2つを参考にしました。
[【初心者必見】Serverless FrameworkでAWS環境作りたいやつはこれを参考にしろ！ - サーバーワークスエンジニアブログ](https://blog.serverworks.co.jp/2021/03/23/182829)
[Serverless Framework - IAM Permissions For Functions](https://www.serverless.com/framework/docs/providers/aws/guide/iam)



# handler.pyの作成
lambda functionの設定を書きます。
```python:handler.py
import boto3

# s3 constant
S3_BUCKET = "serverless-s3-bucket-hello-txt"

def upload_file(event, context):
    # client
    s3 = boto3.resource('s3')
    # s3 upload
    bucket = s3.Bucket(S3_BUCKET)
    bucket.upload_file('./hello.txt', 'hello.txt')

    return None
```



# buildを実行する
マネコンから実行します。
先ほど作成したCode Buildの画面から`start build`をクリックすると実行されます。



# S3 bucketを確認する
S3から確認すると，作成したBucketの中にtxtファイルがアップロードされているのが確認できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2950855/6ee5b7bc-5c34-b632-81bb-751d147a847d.png)
ローカルにダウンロードして開いてみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2950855/a1d1ce54-2582-edd5-0816-a6ea6ab8aeda.png)
アップロードできてますね。成功です！
RubyでPythonのgeneratorのようなことをするには

Rubyで実装する案件で、Pythonのgeneratorのような形で遅延読み込みをしようと思い、どんなふうに実現したかという話です。

# Pythonのgenerator
Pythonのgeneratorは遅延読み込みなどを行う際に便利です。
例えば大きいjsonlファイルを扱う場合だと、以下のような感じに、データを取り出す処理と加工する処理を分けて書くことができつつ、データを1行ずつ取り出して変換することができます。
（jsonlについては https://qiita.com/yasubei/items/95e6a742c24189ded3d6 あたりを参照してください）

```python
import json

def jsonl_generator(jsonl_path):
    with open(jsonl_path) as f:
        for l in f:
            yield json.loads(l)

def main()
    gen = jsonl_generator('大きい.jsonl')
    for dict in gen:
        print(dict['name'])

main()
```

# RubyのFiber
Rubyで上記のようなことをするにはFiberを使うことで実現できます。
上記と同様の処理を書いてみると、以下のような感じです。
※ [追記](#%E8%BF%BD%E8%A8%98) にコメントいただいた内容を反映した改良版があります。

```ruby
require 'json'

class JsonlFiber
    def initialize(jsonl_path)
        f = File.open(jsonl_path)
        @fiber = Fiber.new do
            until f.eof? do
                Fiber.yield(JSON.parse(f.readline)
            end
        end
    end

    def each
        while @fiber.alive? do
            yield(@fiber.resume)
        end
    end
end

def main
    JsonlFiber.new('大きい.jsonl').each do |h|
        print(h['name'])
    end
end

main
```

# 感想
RubyのFiberで書くと、Pythonのgeneratorよりもやや長くなってしまいますが、要件や好み次第で、どっちで書くのもありかなと思いました。
あと、 `Fiber.yield` はPythonの `yield` と同様な感じで、 `each` で使った `yield` はブロックの実行と、ちょっとややこしいなと思いました。

# 追記
コメントをいただいたので、ちょっと改良版を書いてみました。
これで案件の方で ~~動くかはまだ試していませんが~~ 取り入れようとしたのですが、案件の方ではループで回ってくるタイミングと、 `yield` するタイミングが異なるため `Fiber` を使うことにしました。
ただしタイミングが同じなら、 `class` にして `Fiber` を使って `each` を実装するよりも、コメントいただいた `to_enum` を使う方法の方がコンパクトに実装できますし、 `Enumerator` の全メソッドが使えて汎用性が高いですね。

```ruby
def jsonl_fiber(jsonl_path)
    unless block_given?
        return to_enum(__method__, jsonl_path)
    end
    f = File.open(jsonl_path)
    until f.eof? do
        yield(JSON.parse(f.readline))
    end
end

def main
    enum = jsonl_fiber('大きい.jsonl')
    enum.each do |h|
        print(h['name'])
    end
end
```

上にも書いた通り、この案件を対応した際に扱ったファイルがGBオーダーのものでして、1行ずつではなくもっとまとめて読んで、含まれているデータによってごにょごにょしてと、もうちょっと複雑なことになっていたため `Fiber` を使った次第です。
案件ではデータの塊単位でまとめて読み込んで、`Fiber.yield` は、読み込んだ内容に応じて加工したデータを返すところで使っていました。
例を簡単にしすぎてしまって、すみません、うまく伝わらなかったかもしれません。
移動体の遷移を時間帯とメッシュで識別する(SPSS Modeler データ加工逆引き4-20)

# 移動体の遷移を時間帯とメッシュで識別する(Space-Time-BOX)

![スクリーンショット 2023-04-25 10.48.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/3322356a-3b64-ea3c-820e-401ef35c1b3a.png)

## 1.想定される利用目的

・ 座標とタイムスタンプからスマートフォンや車両などの移動体の遷移を要約する

## 2.サンプルストリームのダウンロード

https://github.com/yoichiro0903n/blue/blob/main/space_time.str?raw=true

## 3.サンプルストリームの説明

![スクリーンショット 2023-04-25 13.49.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/c45dc6c0-ca36-b031-e52e-b1d642a4fbb7.png)

a.入力するデータは以下の通りです。ある端末の9:24と9:50の二つの時間の位置情報が記述されています。
![スクリーンショット 2023-04-25 13.51.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/809c2c94-4df8-1bc5-7274-f6494f53eed9.png)

b.[レコード]ノードを編集します。ジオハッシュの粒度は2.4キロ四方に、単位時間は15分に設定しました。
![スクリーンショット 2023-04-25 13.53.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/06e782be-5956-362f-8ae0-44bd6dfb303c.png)

[テーブル]表示します。15分ごとにどのメッシュにいるかが識別されています。
![スクリーンショット 2023-04-25 13.54.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/8a2dd77b-c394-f4df-674a-4ac21d40ab93.png)


#### 注意点

時間のフィールドが文字列だとbの処理が行われないため、データ型でタイムスタンプに変更しておきます。

## 4.参考情報

#### Space-Time-BOXノードについて解説した記事

https://qiita.com/416nishimaki/items/07c77b96a860c38decf5

#### SPSS Modeler ノードリファレンス目次

https://qiita.com/416nishimaki/private/503037195081d3323eee

#### SPSS Modeler 逆引きストリーム集（データ加工）

https://qiita.com/416nishimaki/private/4bf813e6cba84b2a1008
Creatomateとは【動画自動生成】

## Creatomateとは

`Creatomate`は、ビデオと画像の自動生成に対応したクラウドベースのサービス[[1](https://creatomate.com/docs/getting-started)]

`APIを通じてビデオを生成、自動化、編集すること`ができ、これはオンラインビデオエディターやテンプレートを使用して行うことができます[[2](https://creatomate.com/)]。

またCreatomateは大量生成で、これにより数十のビデオや画像を素早く作成することができます。

このサービスは、2020年にオランダのカップルによって設立されました[[3](https://creatomate.com/about-us)]。

APIキーを使ってCreatomateに認証する必要があり、アカウント内の各プロジェクトには独自のAPIキーがあります。これにより、異なるクライアント、顧客、またはアプリケーションに対して別々の環境を作成することが可能になります[[4](https://creatomate.com/blog/get-started-with-creatomate-video-generation-api)]。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987057/d2a175a0-66f9-b885-8a26-eb4521b75a96.png)

## Creatomate APIでできること

1. `クラウド上でビデオの生成、自動化、編集`を行うことができます[[3](https://creatomate.com/)]。
2. `ビデオ、GIF、画像を完全にゼロからJSON形式でレンダリング`することができます。これにより、出力に対する完全な制御が可能になります[[5](https://creatomate.com/blog/get-started-with-creatomate-video-generation-api)]。
3. テンプレートを使用してビデオを作成したり、オンラインビデオエディタを使用したりすることができます[[6](https://creatomate.com/)]。
4. SDKやAPIを通じて任意のプログラミング言語でビデオ編集タスクを自動化することができます[[7](https://creatomate.com/)]。
5. MP4、GIF、JPEG、PNGを生成する方法をJSON形式で指定することができます。全ての処理はCreatomateのレンダーファームで行われます[[8](https://www.npmjs.com/package/creatomate)]。
6. REST APIを使用して、ソフトウェアアプリケーションとCreatomate間で最適に動作します。POSTまたはGETリクエストを介してレンダリングを作成し、リクエストのステータスを確認するか、ウェブフックを使用して完了したレンダリングを待つことができます[[9](https://creatomate.com/docs/api/introduction)]。
7. `ビデオと画像の大量生成が可能`で、数十のビデオや画像を素早く作成することができます[[10](https://creatomate.com/docs/getting-started)]。
プリザンターのクライアントスクリプトを使って、レコード取得上限を超えた件数取得の方法

# はじめに
プリザンターでは、スクリプトやAPIでレコードを取得する時、デフォルトでレコード取得上限が200件となっています。もし、レコード取得上限を200件から変更したい場合、「Api.json」の「PageSize」の値を変更してください。「Api.json」に関してのユーザーマニュアルは下記リンク先をご参照ください。今回の記事では、スクリプトでレコードを取得する場合、テーブルの条件に合致する全レコードを取得する方法を記載いたします。今回の方法はレコード数が200件以上でも取得できる方法です。

https://pleasanter.org/manual/rds-json

# ソースコード
```JavaScript
try {
    // 各変数を初期化
    // offsetは取得開始位置
    let offset = 0;
    // pageSizeは一度に取得できるレコード数
    let pageSize = 0;
    // totalCountは取得した全レコード数
    let totalCount = 0;
    // カウンタ
    let count = 0;
    do {
        let data = {
            id: $p.id(),
            data: {
                Offset: offset,
                view: {
                    ColumnFilterHash: {
                        // 棚卸チェック項目がオン、かつ該当ユーザーIDでフィルタ
                        Title: 1,
                    },
                    ColumnFilterSearchTypes: {
                        // 完全一致でフィルタ
                        Title: 'ExactMatch'
                    }
                }
            },
            done: function (data) {
                let records = data.Response.Data;
                pageSize = data.Response.PageSize;
                totalCount = data.Response.TotalCount;
                console.log(`ページサイズは${pageSize}`);
                console.log(`トータルカウントは${totalCount}`);
                console.log(`オフセットは${offset}`);
                for (let record of records){
                    count += 1;
                }
                console.log(count);
            }
        };
        await $p.apiGet(data);
        offset += pageSize;
    }
    while (offset < totalCount);
    console.log('全レコードを抽出できました');
} catch (ex) {
    console.log(ex.stack);
}
```
上記のスクリプトではタイトルに1が入力されているレコードの件数を取得します。もちろん、デフォルトの取得上限を超えて取得することが可能です。私の環境では問題なく、200件以上取得することができました。  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/659914/25375b50-b59e-3bc2-ccda-5d95ed136e63.png)

# おわりに
Podsディレクトリは、大量のファイルを含むため、Gitの管理下から除外することが推奨されている

「Pod」関連を全部コミットした後にプッシュしたら
永遠とプッシュが終わらない現象に陥ったので
ChatGPTとのやり取りを備忘録。

一般的に、プロジェクトの依存関係を管理するためにCocoaPodsを使用している場合、
以下のファイルをGitHubにプッシュすることは一般的に問題ありません。

Podfile: CocoaPodsが使用する依存関係を定義するファイル。
Podfile.lock: プロジェクトの依存関係をロックして、再現性を確保するためのファイル。
Pods/: CocoaPodsが管理するライブラリのソースコードやリソースが含まれるディレクトリ。

ただし、Podsディレクトリは、大量のファイルを含むため、
Gitの管理下から除外することが推奨されています。

Podsディレクトリを.gitignoreに追加することで、
Gitがこのディレクトリを無視するように指示することができます。

したがって、PodfileとPodfile.lockはリポジトリに含め、
Podsディレクトリは除外するようにすることが一般的に推奨されています。
CI/CDやってみた② Serverless FrameworkとCodeBuildを使ってS3 bucketを作る



前回はlambda functionを作成したので、次はS3 bucketを作成してみました。

# 今回作るもの
前回とほぼ同じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2950855/618d75e0-35c4-1998-0b09-9aa489df3118.png)

# GitHub repositoryの用意
説明は省略します。

# CodeBuildの作成
説明は省略します。


# buildspec.ymlの作成
GitHubレポジトリのrootに作成します。
前回と同じものを使います。

```yml:buildspec.yml
#buildspecのバージョンを指定する
version: 0.2 

#ビルドの各段階で実行するコマンドを書いていく
phases: 
  install:
    commands:
      - npm install -g serverless #serverlessをインストールする
  build:
    commands:
      - sls deploy               #serverless.ymlの内容をdeployする
      - echo 'deploy finished!'
```

# serverless.ymlの作成
GitHubレポジトリのrootに作成します。

以下を参考に作成しました。
```yml:serverless.yml
service: serverless-S3Bucket-test

provider:
  name: aws
  runtime: python3.9
  stage: dev
  region: ap-northeast-1

resources:
  Resources:
    s3test:
      Type: AWS::S3::Bucket
      Properties:
        BucketName: serverless-s3-bucket
```
## パラメータの説明
`service`: Serverless Frameworkのサービス名/プロジェクト名です。

`provider`:クラウドサービスの設定を行います。
- `name`:クラウドサービスを指定します。
 AWSの他にGCP,Azureなども指定できます。

- `runtime`: 言語とそのversionを指定します。
lambda functionのruntimeの設定をここで行います。

- `stage`:  stageを設定します。default値は`dev`です。

# buildを実行する
マネコンから実行します。
先ほど作成したCode Buildの画面から`start build`をクリックすると実行されます。

ログを確認したところ，Succeedが表示されていました。


# S3 bucketを確認する
S3から今回作成したbukcetを探してみます。
今回の場合「serverless-s3-bucket」という名前のbucketが作成されているはずです！




# 参考情報
[Serverless Framework - IAM Permissions For Functions](https://www.serverless.com/framework/docs/providers/aws/guide/iam)
プログラムと映像、音楽制作を様々な角度から比較してみた（使用するパソコン）

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

https://qiita.com/vram/items/c2b317a4ab84801e8c0b



# 使用するパソコンの特徴は違う

パソコンをプログラムを作って作曲して絵を描いているとよく「どれも1台のパソコンで出来るのだから安くんでいいよね」と思われる事がありますが実際はそうではありません。
現にプログラムと作曲と絵を描くパソコンはそれぞれ別々に所持しており管理が非常に面倒です。
なぜ1台のパソコンで完結させないのかを簡単に説明すると、 **それぞれに求める性能が異なる** ためです。
## プログラムを作るためのパソコン
プログラムを作る環境をよりよくするためにコンピュータを買い換えるとしたら何を重視しますか？
自分の場合は
* CPUの性能
* 静かなこと（プログラムに集中したい）
* キーボードが打ちやすいこと
価格を考えなければこんなところでしょうか？

## 絵を描くためのパソコン
絵を描くパソコンはこんなところを重視しています
* 筆圧対応タブレットPCであること
* 自分が使用する筆圧対応アプリの対応OSであること
* sRGB値が可能な限り高いこと
これも価格は考えていません

## 映像を作るためのパソコン
絵と分離させて性能を書くと
* CPU性能が良い物（エンコード時間の短縮）
* メモリ 32Gは欲しい（制作中のメモリ不足回避）
* GPU 性能が良い物でメモリ 4Gは最低欲しい
* sRGB値が高く、残像がない表示
* メディアも高速かつ大容量が理想（素材映像がたくさんある）

## 音楽を作るためのパソコン
* 静かなこと（作曲の邪魔）
* インターフェイスが充実しているもの
* 標準音源に余計な機能がないもの
家庭向けPCの多くは音を良くみせようと変な効果が標準で乗ってるのも多いですがこれが非常に邪魔です。
ただこれはスペックではわからないですし、外部音源を使うのでそこまで慎重になる心配はありません。
あくまで **最終調整を一般向けPCを想定して行う** 際に必要なだけです。

この条件を全て満たしていれば1台で全てが完結します。ですが・・・まあ価格を考えても無理でしょう。ただしそれぞれを満たす物は安く手に入るので複数台購入して制作しています。

#使用する周辺機器の違い
##プログラムを書くための周辺機器
マウス以外は意外と思いつきません。
## 絵を描くための周辺機器
* 筆圧に対応させるペン
* 左手デバイス
* スキャナとプリンタが付いた複合機
* タブレットを自分用に角度をつけるためのスタンド

## 映像を作るための周辺機器
* 左手デバイス
* ビデオキャプチャ

## 音楽を作るための周辺機器
* ASIO対応オーディオインターフェイス
* ミキサー
* ヘッドフォン
* 鍵盤（USBタイプ）
* 鍵盤（単体で発音するタイプ）

プログラムを作るためには周辺機器は不要で、意外にも音楽制作には様々な周辺機器が必要です。
左手デバイスというのはマウスを使わずにパラメータ調整や拡大縮小その他の操作が可能なデバイスです。
なくても作れますがマウス操作が複雑になります。
ペンをわざわざ書いたのはペンごとに書き心地が違うので種類を変えたりするためです。あとペン先が消耗品だったりします。
鍵盤が2種類あるのは1つは入力インターフェイスでもう1つは曲のイメージが思いついたときにさっと音を出すための鍵盤も必要なためです。

#使用するアプリの違い
##プログラムを書くためアプリ
* エディタ
* コンパイラ
* 外部ライブラリ
統合開発環境としてエディタとコンパイラが1つになったものもありますが、別々の物もありますね。価格は無料の物から20万超えのものまで様々です。

自分はDelphiとKotlinというどちらかというとマイナー系を使っています

## 絵を描くためアプリ
あまり知られていませんが実は大きく分けて「ベクター」と「ラスター」の2種類の系統があります。

### ラスター
いわゆるピクセルを単位として描くソフトです。最初に解像度を指定して、そのキャンバス上に絵を描いていきます。当たり前ですがその解像度以上のピクセルは扱えません。
なんか当たり前のことを言っていますがそうではないのがベクターです
### ベクター
解像度という指定はあくまで建前でそれ以上の解像度も扱えるのがベクターです。
割愛して説明するとピクセルではなく、直線や曲線の情報を扱って描画されるので解像度の変化に影響されません。
それならベクターで描けばいいじゃないと思いますが重いとかエフェクタとかの関係でそうはいきません。
世の中一般的にはラスターのソフトが主流です。
しかし自分はベクター派のため、ベクターで描きつつラスターに変換出来るアプリを使って描いています。

複数のソフトを使い分けるのも当たり前のため以外とアプリにお金がかかるかも知れません。

## 映像を作るためのアプリ
昔は高価なソフトが多かったのですが今や無料のでも十分すぎるぐらいの性能があります。
無料で有名どころとして
* AviUtl
* ゆっくりMovieMaker
* DaVinci Resolve 

この辺でしょうか？
映像にセリフをつけてしゃべらせるには音声合成ソフトも必要です。
有名どころとして
* VOICEROID
* AI VOICE
* VOICEVOX
* CeVIO AIトーク
最近は無料のでも性能が良くなってきています

## 音楽を作るためのアプリ
DAWソフトが必須です
有名どころとして
* Cubase Pro (付属版から50,999円ぐらい)
* Studio One （10,590円ぐらい）
* FL Studio Signature（36,720円ぐらい）

意外と財布に優しくないですね
これ以外にこの音が欲しいという場合はプラグインとして購入することになります。

そして最近はボーカルをつけることも当たり前です
有料版の有名どころとして
* ボーカロイド(VOCALOID) (20,000円前後)
* CeVIO AIソング（30,000円ぐらい）

# さいごに
結局、プログラムと画像や映像、音楽を作る環境を整えるとどれぐらいかかるの？となるのですが
* パソコン（プログラム用と映像制作） 198,000円
* パソコン（音楽制作） 128,000円
* タブレットPC（画像制作） 98,000円（中古）
パソコンで424,000円
周辺機器とソフトもこれぐらいかかっていますので全部で 80万といったところでしょうか？

さすがにここまでの事をしようとする人は居ないと思いますが同時に様々な事を手がけようとすると結構な金額になってしまいます。

ですがそれに見合うだけの成果物は出来ていますし経験値も増えましたので自分に投資したと思うことにしましょう。
p5.jsでつくる正弦波の重ね合わせ

# はじめに
p5.jsというライブラリを利用してchatGPTと共に作成したアートの紹介です。
「なんかいい」をモットーに作っています。

# 作品紹介
<iframe width="560" height="315" src="https://www.youtube.com/embed/SlUgZ_fIBoo" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
『正弦波』

# 構想
最初は海の波を表現してみようと考えていたのですが、波の表現のために正弦波を利用しているうちに重ね合わせると面白そうだと考えました。それから正弦波をひたすら重ねてみるようにして作り始めました。

# chatGPTと調整
はじめは均等にずらしていくような正弦波を生成していました。それでも十分面白かったのですが単調でした。そこでランダムにできそうな数値のところはランダムに変えてみました。すると時間が立つと雰囲気がコロコロと変わるようになり、よりダイナミックに面白い動向を生み出しました。

# 作品解説
## 下準備
必要なファイルや実行方法がわからない人は以下を参考にしてください。

https://qiita.com/keigo1110/items/543423379813b49e7415

## コード
コードはchatGPTが生成しています。数字は一部調整しています。
```javascript
let waves = [];

function setup() {
  createCanvas(2000, 1200);
  background(0);
  strokeWeight(2);
  noFill();
  stroke(255);

  // 波を10個作成
  for (let i = 0; i < 10; i++) {
    let c = color(random(100, 255), random(100, 255), random(100, 255));
    let freq = random(1, 5);
    let amp = random(20, 100); //20, 100が一番きれいだと感じた
    let phase = random(TWO_PI);
    let speed = random(0.01, 0.05);
    waves.push(new Wave(c, freq, amp, phase, speed));
  }
}

function draw() {
  // 背景色のフェード
  fill(0, 10);
  rect(0, 0, width, height);

  // 波の描画
  for (let i = 0; i < waves.length; i++) {
    waves[i].update();
    waves[i].display();
  }
}

class Wave {
  constructor(c, freq, amp, phase, speed) {
    this.c = c;
    this.freq = freq;
    this.amp = amp;
    this.phase = phase;
    this.speed = speed;
    this.offset = 0;
    this.freq_delta = random(-0.1, 0.1);
    this.amp_delta = random(-5, 5);
  }

  update() {
    // 波の速度に応じた位相の移動
    this.phase += this.speed;

    // オフセットの更新
    this.offset = map(sin(this.phase), -1, 1, 0, TWO_PI * this.freq);

    // 周期の微小な変化を加える
    this.freq += this.freq_delta;
    if (this.freq < 1 || this.freq > 5) {
      this.freq_delta *= -1;
    }

    // 振幅の微小な変化を加える
    this.amp += this.amp_delta;
    if (this.amp < 20 || this.amp > 100) {
      this.amp_delta *= -1;
    }
  }

  display() {
    // 色の設定
    stroke(this.c);
    strokeWeight(0.9); // 線の太さをランダムに変更

    // 正弦波の描画
    beginShape();
    for (let x = 0; x <= width; x += 5) {
      let y = sin(x * this.freq + this.offset) * this.amp;
      vertex(x, height / 2 + y);
    }
    endShape();
  }
}
```

# 拡張性
設定を調整することで雰囲気が一気に変わります。自分は以下のようにコメント入れている通り、振幅にこだわって数値を決めました。ほんとにちょっと変えるだけで様子が変わるので試してみて自分の好きな雰囲気を作り出してください。
```javascript
function setup() {
  createCanvas(2000, 1200);
  background(0);
  strokeWeight(2);
  noFill();
  stroke(255);

  // 波を10個作成
  for (let i = 0; i < 10; i++) {
    let c = color(random(100, 255), random(100, 255), random(100, 255));
    let freq = random(1, 5);
    let amp = random(20, 100); //20, 100が一番きれいだと感じた
    let phase = random(TWO_PI);
    let speed = random(0.01, 0.05);
    waves.push(new Wave(c, freq, amp, phase, speed));
  }
}
```

これも自分で実際につくって見てみると綺麗です。ぜひ、試してみてください！

# おわりに
今回は正弦波を重ね合わせることで移り変わる動向を楽しめる作品ができました。
[アップデート] PolarDBで1 ノードクラスターが利用できるようになった(MySQLのみ)

# 概要
もともとPolarDBのクラスターを利用するには、最低でも2つのノードが必要でした。開発環境やテスト環境、または可用性がそこまで求められていない利用シーンにおける本番環境利用する場合は、少なくとも2つのノードから構築する必要がありました。しかし、可用性がそれほど求められていない場合でも、2倍の費用を払うのはかなり痛かったです。そして、つい最近、1つのノードからでも利用可能になりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/57d45625-7763-f8fc-3e83-e68f22cc0258.png)

::: note info
もともと「単一ノード(Starter)」というエディションもありましたが、「4コア8GB」のスッベクしか使えなかったため、利用シーンはかなり限られていました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/405ef9a2-05c9-75b3-ea3a-41780735d8fe.png)
:::

# 1 ノードクラスターの制約

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/765fff6d-c893-092b-2cdd-3f316757b033.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/583726bf-f6eb-5c60-0cef-6451de09e230.png)
- クラスターにノード一つしかないため、`クラスターエンドポイント`や`カスタムクラスターエンドポイント`がありません。
- 2ノードクラスターで利用できるProxy機能が1ノードクラスターで利用できません。
  - つまりProxyに付属するconnection poolなどの機能が使えません。

 https://www.alibabacloud.com/help/en/polardb/latest/polarproxy-enterprise-edition-overview

- 可用性が重要なシステムでは、引き続き2ノード以上のクラスターを構築することが推奨されます。2ノード以上のクラスターを構築することで、1ノードに障害が発生した場合でも、他のノードでサービスを継続することができます。

# 既存の2ノードクラスターを1ノードに変更することも可能
以下の手順でいつでも自由に変更可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/aa21921f-f969-b5b3-e523-611c0f22fbf5.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/e1af2271-b3e2-a476-55f4-0c1ff1ef44c3.png)

# まとめ
- 開発環境やテスト環境、または可用性がそこまで求められていない利用シーンにおいて、本番環境で1つのノードクラスターを利用することで、コスト(ストレージを含まずに、コンピューティングの部分にかかる費用)を半分に抑えることができます。
- 可用性を求めている本番環境では引き続き2ノード以上のクラスターを推奨します。
PythonによるWebスクレイピング-入門編、その4 - 画像ファイルのスクレイピング

Webスクレイピングの学習が進みました。今回は画像ファイルをWEBサイトからスクレイピングする方法を学びました。

https://www.udemy.com/course/python-scraping-beginner/

https://scraping-for-beginner.herokuapp.com/image

# 画像のスクレイピング
まずは画像を処理するためのライブラリ：`Pillow`をインストールします。

```python
pip install Pillow
```
Pillowを使うと、`Image`形式でローカルフォルダーやカーネルに読み込んだ画像を扱えるようになります。
```python
from PIL import Image
img = Image.open("Sample.JPG")
img
```
![スクリーンショット 2023-05-09 143705.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/337578/3d22c3f8-b013-f356-4c8e-1f33e9ed5340.png)

Pillowを使えば簡単な画像の表示の他、サイズの確認・リサイズ・リネームして保存といったことができます。
```python
#画像のサイズを確認
img.size
```
```python
(1200, 798)
```

```python
画像をリサイズ・リネームして保存
img = img.resize((1024, 768))
img.save("sample_resize.jpg")
```

# Selenium・Pillowを使って画像をスクレイピング
Selenium・Pillowを使えばWEB上から画像をスクレイピングすることができます。他にも出入力・URL処理用のライブラリが必要です。
```python
#必須 - 出入力・URL処理のライブラリ、Pillow
import io
from urllib import request
from PIL import Image

#Chrome
from selenium import webdriver
browser = webdriver.Chrome()

#URLにアクセスする
browser.get("https://scraping-for-beginner.herokuapp.com/image")

#imageタグとその親要素を取得する
elem_parent = browser.find_element_by_class_name("material-placeholder")
elem_img = elem_parent.find_element_by_tag_name("img")

#srcのリンク先を取得する
url = elem_img.get_attribute("src")
print(url)

#画像データをioを使ってメモリー上に読み込む
f = io.BytesIO(request.urlopen(url).read())
print(f)

#Pillowで画像データを処理する
img = Image.open(f)
img

#画像を保存
img.save("img01.jpg")
```
![スクリーンショット 2023-05-09 150810.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/337578/4cc64655-cc6f-3546-80fe-19a77a3ecce8.png)

# すべての画像を収集
```python
#必須 - 出入力・URL処理のライブラリ、Pillow
import io
from urllib import request
from PIL import Image

#Chrome
from selenium import webdriver
browser = webdriver.Chrome()

#URLにアクセスする
browser.get("https://scraping-for-beginner.herokuapp.com/image")

#imageタグとその親要素全てを取得する
elem_parents = browser.find_elements_by_class_name("material-placeholder")

#for...in文にindexを足す→子要素のインデックスも取得できる
for index, elem_parent in enumerate(elem_parents):
    #img要素
    elem_img = elem_parent.find_element_by_tag_name("img")
    
    #srcのリンク先を取得する
    url = elem_img.get_attribute("src")
    #print(url)

    #画像データをioを使ってメモリー上に読み込む
    f = io.BytesIO(request.urlopen(url).read())
    #print(f)

    #Pillowで画像データを処理する
    img = Image.open(f)
    #img
    
    #画像を保存 - format関数を使ってファイルをindexを使った連番にする
    img.save("img/img{}.jpg".format(index))
```
![スクリーンショット 2023-05-09 150954.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/337578/27c876c3-4698-ecf0-75eb-d9eb40e3cc7b.png)

これでWebスクレイピング-入門編の学習が完了しました。次はスクレイピングを開発向けに応用するのを目指します。
超初心者向け Python PythonAnywhere を使ってみる

PythonAnywhereを使ってみたので、その使い方の解説動画と、実際にデプロイしたウェブサイトをシェアしたいと思います。15分ほどの英語の動画で、簡単な使い方が紹介されています。ぜひ使ってみてください。

# YouTube解説動画

[Deploy Python app to PythonAnywhere](https://www.youtube.com/watch?v=wbAhmGFwZ-g
)

https://www.youtube.com/watch?v=wbAhmGFwZ-g

# デプロイしたウェブサイト

[https://natsuki777.pythonanywhere.com/example](https://natsuki777.pythonanywhere.com/example)
Salesforceの用語解説～Salesforceの基本用語をエクセルで例えてみた

こんにちは
本橋孝昭です

今回の内容は動画でも解説しています

https://youtu.be/OuyAEmlehtU

<iframe width="560" height="315" src="https://www.youtube.com/embed/OuyAEmlehtU" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>


今回はSalesforceでよく聞く用語だけどいったいこれって何？ということが分かるための解説を行います

Salesforceに携わると
・オブジェクト
・レコード
・項目
・レポート

という言葉が出てきて
・これって結局なんなの？
と思うこと、あるかと思います

私もSalesforceを最初に勉強したころは結構色々調べて色々な記事を探したのですが

・オブジェクトはデータの箱？データの箱ってなんだろう

とよく分からないまま色々調べた記憶があります

おそらく、この内容がいまいち頭に入ってこない原因として
・Salesforceを身近な○○で例えてみた

というような解説がなかったからだと思います

今回はおそらくSalesforceよりも身近であろうエクセルと比較して


分かりやすいようにSalesforceの基本用語
・オブジェクト
・レコード
・項目
・レポート
について解説しようと思います

「エクセル」と聞くとなんだか複雑な集計やらで大変なイメージしかない！という人でもご安心ください。

みなさまこのようなエクセルで顧客管理をしていることもあるのではないでしょうか


![タブ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/fc29cdc7-1b9a-ce2e-38ee-2eacaaba9b51.png)

今回は例として顧客管理のエクセルで解説しますが、
成績管理やら家計簿管理やらなどで、
このようにシートタブごとにエクセルでデータ管理をしたこと、みなさんも一度はあるかと思います
今回はこのようなエクセルを用いてSalesforceを分かりやすく解説します



エクセルでいう
・１つのエクセルデータでシートタブごとに分けて情報を管理する
ということはSalesforceでいうと
・１つのSalesforce環境でデータをオブジェクトごとに分けて情報を管理する

ということになります

![セールスフォース01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/d2169eba-555c-93b3-b7c0-50553c0f1dfb.png)


次に、エクセルの中身を紹介します

エクセルで例えると、
このように１行ごとにデータを入力しているかと思います

![空欄1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/22a2454c-5997-2b0a-3054-e0f0760cc108.png)

これは、Salesforceでいうと
1行ごとのデータは「レコード」と呼びます
![レコード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/f8654550-f4ef-e9a8-ae93-8566bf349569.png)

このレコードですが、Salesforceをタブをクリックした画面だと、ちょうど
１行ごとにデータが見えるのでエクセルみたいな動きですね
このレコードですが、レコード名の青文字をクリックすると詳細なレコード画面になります

![レコード002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/c0678c89-32db-14f3-e276-38cc92037f5f.png)

このエクセルでいう行にあたるSalesforceのレコードは、Salesforceではレコード作成ボタンから追加することが可能です

次に、エクセルでは「金額」や「確度」などの列を作成し
「金額」情報や「確度」情報を入力すると思います

![金額01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/4ed45c45-2922-c1f8-34f3-0f02d2b720ef.png)


このエクセルでいう列のことをSalesforceでは「項目」と呼びます

![行とは.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/6048813f-2a9e-15c9-21fd-32ce6bd530c1.png)


項目の作成は「オブジェクトマネージャー」から作成することが可能です
また、作成した項目は削除することも可能です
そして、リストビューから項目の並び替えを行ったり、ページレイアウトから項目の並び替えや見えるor見えない　の設定を行うことが可能です


最後です
エクセルでは入力されたデータを元に合計を集計したりしてグラフを作成することができますね


![グラフ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/faeb7ac3-38bb-4d1a-75b2-d605afdb1615.png)

このようなエクセルのグラフですが、Salesfroceでも同じようにSalesforceで入力された情報からグラフを作成することが可能です
このSalesforceの機能をレポートと呼びます

![レポート001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/e17b589b-f958-c967-9fc8-ff444c888586.png)


まとめます

## Salesforceをエクセルに例えると


### 1エクセルでいう「シートタブ」はSalesforceでいう「オブジェクト」

### 2エクセルでいう「行」はSalesforceでいう「レコード」

### 3エクセルでいう「列」はSalesforceでいう「項目」

### 4エクセルでいう「グラフ」はSalesforceで「レポート」を作成すれば表示可能
ChatGPTを利用して、Youtubeの動画を要約してくれる拡張機能（Google Chrome）

# Google拡張機能をインストールする
https://chrome.google.com/webstore/detail/youtubedigest-summarize-u/agjkjablkiapmpbeglmdcmhnihlofija?hl=ja

# プロパティを設定する
設定に関しては、ケースバイケースであるため、任意で設定すればいいと思います。以下の画像では、言語を日本語、背景を暗く設定しています。
![スクリーンショット 2023-05-09 13.56.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3079289/9b4b6869-f106-62f0-4f40-a4df99524b3b.png)

# ChatGPTを確認し、音声ツールが反映されていることを確認する
**【反映前】**
![スクリーンショット 2023-05-09 13.52.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3079289/c2e46cd1-224e-51bd-8e70-55cec68c7a19.png)

**【反映後】**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3079289/4c6bf378-e519-4894-1ae2-3d2da1a2995d.png)

# 使用方法
- 要約してもらいたい動画を開き、Summarizeのボタンを押す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3079289/ffcd8eb0-feb7-c88b-3d36-ae540bea2758.png)
- 要約が開始される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3079289/2594e646-4786-09a9-f53a-d35584bad33a.png)

# 注意事項
- **使用する際は、ChatGPTへ一度、ログインしておく必要があります。**
- Youtubeのショート動画では、この拡張機能は機能しないようです。
- プロパティの設定は、以下をアドレスバーに入力することで、設定し直すことができます。
chrome-extension://agjkjablkiapmpbeglmdcmhnihlofija/options.html

# この記事は誰向けの記事か？
- YouTubeの動画を要約してほしい人
- YouTubeで動画を視聴する際に、これまでにない刺激や経験をしたい人

# 環境
- OS：macOS 13.3.1（22E261）
- ブラウザ：Google Chrome 112.0.5615.137（Official Build） （arm64）

# 本記事における注意事項
- 本記事は、備忘録としてまとめたものになります。
- 他の方の参考になる可能性も踏まえて、一般公開も行なっております。
- また記載内容はすべて、正しい内容が記載されているとは限りません。
- 誤った内容を見つけた場合は、ご指摘をお願いいたします。
トップ5%社員になりたくない？

## はじめに

「AI分析でわかった トップ5%社員の習慣」を読んだので記事にしてみました。
個人的に刺さった項目3つについてまとめてみたので、休憩時間にでも読んでもらえたら嬉しいです。
**「トップ5%社員になりたくない？」とかタイトルで言っておきながら、この記事を読んでもトップ5%の社員になれるわけではないのでその点ご容赦ください**（そんな記事がもしあれば是非コメントにお願いします）。

なおこの記事は本全体の要約ではないため全項目に対して触れることはありません。
「もっと詳しく知りたい！」となった方は是非[こちら](https://www.amazon.co.jp/dp/4799326082)から購入して読んでみてください。損はしないと思います。
ちなみにAmazonPrime会員であれば、PrimeReadingで購入することなく読むことができます（2023/05/09時点）。Amazon様様ですね。

## どんな本？

人工知能（AI）を用いて、トップパフォーマー社員の習慣を分析し、成功につながる習慣を紹介しているビジネス書です。
> トップ5%社員は、特別な能力や才能に長けているというよりは、
> 「仕事が早く終わるツボ」を心得ている人です。
> そのため、本書で紹介する仕事術は、誰でもできるもの。
> ・常に時間に追われているのに仕事が終わらず、努力だけでは限界を感じている人
> ・働き方改革やテレワーク導入を機に働き方を見直したいと思っている人
> 必読の1冊です。

## 感想

- よかった点
    - データで語られるため納得感がある
    - 筆者の主観ではなく、データとそこからの推論で基本的に展開される
    - 表現がシンプルでわかりやすい
    - 目に見える習慣や事実にフォーカスされていて、内面的な話や精神論が少なめ
    - 「あとがき」が熱い
- うーんって点
    - 単に真似るだけでは意味がなさそうな項目もある
    - 大きいテーマを序盤に扱いすぎて終盤の先細りが個人的に気になった

## 刺さった項目3選

### 「5%社員」は再現性を大切にする

> ⭕️ 成果を出し続けるルールを見つけ出すために行動実験をする
❌ 一時的な成果が出ただけで喜び、満足する

要約：
**「特定のことができる」というスキルや能力がある状態 は、「特定のことを再現できる」状態である。**
幸運に恵まれてたまたま何か成果を生み出せたとしてもそれ自体に意味はなく、それを喜ぶだけでは成長につながらない。**失敗成功問わず必ず要因があり、それをしっかり分析して把握し、手順化や習慣化することで成功の再現性を高めていくことが重要である。**

感想：
成果が出たことに満足して、そこで思考止めちゃうことって確かにあるなって感じました。「**成功を単なる偶然の産物ではなく再現できるようなものにしなければ意味がない**」って考え方は面白いし、役立ちそうだなって感じました。
成功失敗に関わらず、物事の要因を分析して手順化や習慣化することの大事さが印象に残りました。
ついでに自分の好きな漫画のセリフに似たようなものがあったので紹介しておきます。
> 「“再現性”のある成功の先にしか進化はないと思い知れ」 by 『ブルー・ロック』



### 「5%社員」はアウトプットする習慣を持っている

> ⭕️ 意見や学習成果を披露する機会を意図的に作れば、社内外でインパクトを残すことができる
❌ インプットすることに注力してしまい、その学びが活用されない

要約：
「5%社員」は自身の考えを表現することに積極的である。会議において、**思いつきベースであってもアイデアや企画を積極的に発言する。**
また学習内容のアウトプットも多い。アウトプットによって学習内容を定着させ自分のものにしている。

感想：
学習内容のアウトプットについての重要性は色んな本で見かけるし、大事なんだろうなって感じました。確かに読んだことあるけど思い出せない〜みたいなことって多いですもんね。詳しくは[こちら](https://qiita.com/Terao-Takumi/items/ddf11b32676021fd2e83)の記事の「本を読むだけで満足するのは三流」という項目が参考になるので是非見てください。

### 「95%社員」は平日も休日もこまめにメールチェックする

> ⭕️ オンとオフの切り替えをして、最高のパフォーマンスを出せるようにする
❌ 目の前のメールが気になって、返信をこなすことが目的になり疲弊する

要約：
評価されにくい社員は緊急度で仕事の優先順位を決めるが、成果を出し評価されている社員は**緊急度と重要度の2つの評価軸で仕事の優先順位を決める**。そのため評価されている社員は、緊急度は低いが重要度が高いタスクに時間を割いているという特徴がある。

感想：
ついつい簡単にわかる緊急度で判断しがちですけど、重要度で判断することってまあ大事ですよね。重要度を把握するためにも仕事の目的とかゴールをしっかり明確にして取り組むことが大事になるんだろうなって感じました。

## 終わりに

3つほど紹介しましたが、どれも形だけ真似することはあまり意味がないと思うので、**なぜその習慣になったのかみたいな観点を踏まえつつ参考にできるものは真似できたらいいなって感じました。**「5%の社員になるために休日は全くメール見ないようにしよう！」って話でもないので。
本を読んで満足するのではなく、行動まで変えることができたら最高ですね。

> この読書の目的は「知ること」ではなく、「行動すること」です。
> 
作者のあとがきにある通り「行動すること」が大事になると思います。
Atcoder典型90問 004 - Cross Sum

# Atcoder典型90問 004 - Cross Sum（★2）
▶︎https://atcoder.jp/contests/typical90/tasks/typical90_d

## 問題
H 行 W 列のマス目があります。上から i (1≤i≤H) 行目、左から j (1≤j≤W) 列目にあるマス 
(i,j) には、整数 A(i,j)が書かれています。 
すべてのマス (i,j) (1≤i≤H,1≤j≤W) について、以下の値を求めてください。

* マス (i,j) と同じ行または同じ列にあるマス（自分自身を含む）に書かれている整数をすべて合計した値

## 制約
```math
2≤H≤2000 \\
2≤W≤2000 \\
1≤A_{(i,j)}≤99 \\
```

## 試したこと
* 各マスに対して愚直に行/列の足し算を行うと、最低でもO(HW * [H + W])となりPythonには荷が重い計算量になる。
    * あとでわかったことだが、input時以外にO(N^2)の計算が入った時点でほぼ詰んでしまう。
    * その理由はPythonでは配列宣言がとくに重いから。
    * https://tech-lab.sios.jp/archives/21127#i-10
* 上のアルゴリズムでは同じ行と同じ列の足し算を重複して行っていることに気づければ、あとは計算量を乗り越える部分に入る。とはいえO(HW)がギリギリなので、かなりアルゴリズムを気をつけないと定数倍さえ響く。かなり苦労した...
* 最初はnumpyで実装したが、Pypy3とnumpyが併用できないのでnumpyを諦めた。
    * 結果的には、実行速度が早い順に
    * Pypy3 & map > numpy > Pypy3&for
    * となった(左が早い)。numpyがTLE２個、Pypy3&forがTLE4個くらい。

## 適切な方針
* 各行と各列の和を事前に計算しておく(前処理)
* 求める行列B[i][j]は、与えられた行列Aのi行目の和とj行目の和から重複部分(A[i][j]を一つ分)除いた値である。
* 行列の列和を求める際はmapを使うとよい。単に二重for文でゴリ押そうとするとTLEコース。
    * 二重for文ではなく、逆行列を作ってその行和を取ろうとしたのがミスだったのかもしれない。
    * いずれにせよmap文を使うのが大切そう。


## 解説付きコード
```py
[H, W] = list(map(int, input().split()))
ans_mat = [[0 for i in range(W)] for j in range(H)]
tar_mat = [[0 for i in range(W)] for j in range(H)]

#行和と列和の保存用配列
addH_list = [0 for i in range(H)]
addW_list = [0 for i in range(W)]

#入力受け取り
for i in range(H):
  input_list = list(map(int, input().split()))
  tar_mat[i] = input_list.copy()

#行和の保存
for i in range(H):
  addH_list[i] = sum(tar_mat[i])

#列和の保存
for j in range(W):
  addW_list[j] = sum([tar_mat[i][j] for i in range(H)])

#行和と列和の更新
for i in range(H):
  for j in range(W):
    ans_mat[i][j] = addH_list[i] + addW_list[j] - tar_mat[i][j]

#配列をスペースで結合した文字列として出力する
for i in range(H):
  print(" ".join(list(map(str, ans_mat[i]))))
```

## 付録：TLEを起こしたコード(二重for文)、
```py
# 転置行列を返す関数(戦犯)
def transpose(mat):
  H = len(mat)
  W = len(mat[0])
  new_mat = [[0 for i in range(H)] for j in range(W)]
  for i in range(H):
    for j in range(W):
      new_mat[j][i] = mat[i][j]
  return new_mat

def main():
    [H, W] = list(map(int, input().split()))
    ans_mat = [[0 for i in range(W)] for j in range(H)]
    tar_mat = [[0 for i in range(W)] for j in range(H)]
     
    addH_list = [0 for i in range(H)]
    addW_list = [0 for i in range(W)]
     
    for i in range(H):
      input_list = list(map(int, input().split()))
      tar_mat[i] = input_list.copy()
     
    for i in range(H):
      addH_list[i] = sum(tar_mat[i])
     
    for j in range(W):
    　　　　# sumは組み込み関数なので早いだろうし転置行列に対して使えばいいだろう
    　　　　# と思ったが、見通しが甘かった。
      tar_mat_t = transpose(tar_mat)
      addW_list[j] = sum(tar_mat_t[j])
        
    for i in range(H):
      for j in range(W):
        ans_mat[i][j] = addH_list[i] + addW_list[j] - tar_mat[i][j]
     
    for i in range(H):
      anslist = list(map(int, ans_mat[i]))
      for j in range(W):
        if j!= W-1:
          print(anslist[j], end=' ')
        else:
          print(anslist[j])
main()
```
仕事用PowerShellコマンド

※※ 私用メモ


フォルダー自動作成
```
for($i=1; $i -le 20; $i++) {
$N = "{0:000}" -f $i
$N2 = "ZZ" + $N
mkdir $N2 
}
```

フォルダー自動削除
```
Remove-Item -Path ./* -Recurse -Include *Thumbs.db*
Get-ChildItem -Recurse -Name -Include *要件定義*
```

コード内テキスト参照（横並びチェックに利用）
```
$infolder="C:\_ZaimApp\ローカルリポジトリ\tkz_web_source\jz\trunk\jz_server\webapps\JZWeb\WEB-INF\src_gyomu"
$keyword="JZC090R"
$outputfile=New-Object System.IO.StreamWriter("C:\log.txt",$true,[Text.Encoding]::GetEncoding("UTF-8"))
# 検索対象ディレクトリー存在チェック
if (Test-Path $infolder) {
    # 検索対象フォルダ内のファイル一覧を取得
    $infilelist=Get-ChildItem -Path $infolder -Recurse
    # 1ファイルずつ処理
    foreach ($infilename in $infilelist) {
        # ファイル存在チェック
        if (Test-Path $infilename.FullName) {
           # ファイルの中身取得
           $line=Get-Content $infilename.FullName
           # 1行ずつ処理
           foreach ($getline in $line) {
               # キーワードがある行かどうかの判定
               if ($getline -match $keyword ) {
                   # 出力ファイルに行を書きだす
                   $outputfile.WriteLine("$($infilename.Name): $($getline)")
               }
            }
        }
    }
}
$outputfile.Close()
```

カレントディレクトリーの全てのアイテムの特定の名前を置換する。
```
Get-ChildItem | Rename-Item -NewName {
	$_ -Replace ".BK",""}
```

リモートデスクトップPORT
通常 3389
ActiveDirectory 56379

リモート接続元のIPを確認する。
```
function getRemoteIpAddr(){
    $result = &"netstat" -n -p tcp
    foreach ($line in $result) {
        if ( ${line} -match "  TCP +\d+\.\d+\.\d+\.\d+:3389 +(\d+\.\d+\.\d+\.\d+):.+ESTABLISHED") {
            return $Matches[1]
        }
    }
    return ""
}
$ret = getRemoteIpAddr
```

ファイルカウント集計
```
$infolder="C:\Users\zaimu010\Documents\006.マクロ作成\CSV\00_ALL"
$outputfile=New-Object System.IO.StreamWriter("C:\Users\zaimu010\Documents\006.マクロ作成\FTRAN_Cnt_ALL.csv",$true,[Text.Encoding]::GetEncoding("UTF-8"))
if (Test-Path $infolder) {
    $infilelist=Get-ChildItem -Path $infolder -Recurse
    Write-Host $infilelist
    foreach ($infilename in $infilelist) {
        if (Test-Path $infilename.FullName) {
           $fname=$infilename.Name
           $rfname=$fname
           Write-Host $rfname
           $rcount=(Get-Content $infilename.FullName).count
           Write-Host $rcount
           $num=$fname.Length - ($fname -replace "_","").Length
           Write-Host $num
           if ($num -ge 2 ) {
               Write-Host $rfname
               $strindex=($rfname.LastIndexOf("_"))
               Write-Host $strindex
               $rfname=($fname.Substring(0,$strindex)) 
           }
           Write-Host $rfname
           $writes="01, ,$fname,$rfname,$rcount"
           
           $outputfile.WriteLine("$writes")
        }
    }
}
$outputfile.Close()
```
Open LibertyでつくるHelloWorldタイムアタック

## はじめに
Open LibertyはLightWeightなオープンフレームワークですが、準備して動かすところも軽いのでしょうか。
そこで、プログラムの第一歩である「HelloWorld」をOpen Libertyで動かすことがどれくらい簡単かを確認していきます。

## 試すこと
ゼロから環境を作成してHelloWorldが表示できるまでのステップと時間を主に確認します。手順は大きく次のステップになります。
* JDKのインストール
* Open Libertyのプロジェクト作成
* HelloWorldロジックの追加
* 起動

## 実行環境
| 種類 | スペック |
|:-:|:-:|
| OS  | Windows 11 Enterprise (21H2)  |
| メモリ  | 16GB |

## つくってみる
#### JDKのインストール
ここではIBMのJDKであるSemeruRuntimeを使用していきます。
ダウンロードサイトは[こちら](https://developer.ibm.com/languages/java/semeru-runtimes/downloads/)。

今回はWindowsのインストーラ（msi）版を選択します。
![230509a5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536604/d54223bd-aacc-7cf6-cf5c-ea17284028e0.png)
ダウンロード後、ダブルクリックでインストール開始です。特にインストール時の指定は迷わないかと思います。

インストール後の確認として、コマンドプロンプトより
```
java --version
```
と入力し、次のような結果が返ればOKです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536604/5d9a38a1-3d2d-690b-0144-7ee884349f19.png)
もし表示されない場合は、環境変数 JAVA_HOME の設定が適切かを確認してください。

#### Open Libertyのプロジェクト作成
[「Open Liberty の公式サイトを使いこなそう」](https://qiita.com/mi-ta/items/6e7bdbc31540d50f0b60)で記載しましたが、プロジェクトのひな形をサイトからダウンロードすることができます。
Get Started > Create a starter application から、JakartaEEベースでプロジェクトを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536604/d5dca15b-cd2f-fb0d-652c-3db3e9eee7f3.png)
「Generate Project」のボタンを押すことで構成済プロジェクトをまとめたzipファイルがダウンロードできます。

取得したzipファイルを任意のフォルダに展開します。今回はC:\projectsというフォルダを作成し、ここに展開します。
結果、C:\projects\app-ee フォルダができあがりました。

#### HelloWorldロジックの追加
C:\projects\app-ee\src\main\java\jp\sample\rest
フォルダの下に、HelloWorldを返却するファイルを追加します。
```java:Hello.java
package jp.sample.rest;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;

@Path("hello")
public class Hello {

    @GET
    public String helloResponse() {
        return "Hello World!!";
    }
}
```

#### 起動
コマンドプロンプトで、プロジェクトフォルダから「mvnw liberty:dev」を実行します。
```java:例
C:\projects\app-ee>mvnw liberty:dev
```

Mavenが定義に応じてライブラリを自動ダウンロードするため、初回は少し時間がかかります。2回目以降は1分程度で起動できます。

コンソールの表示が次のところまで進んだら準備完了です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536604/f8b2cc0f-f148-5eba-76ce-3a9baa067348.png)
ブラウザからlocalhostにアクセスし、次のような表示になればOKです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536604/d23e8508-abd7-e80f-2b3f-93b33f78f5b3.png)

CURLコマンドによる確認でも。
```
curl http://localhost:9080/app-ee/api/hello
```

## まとめ
* 起動まで3分10秒
* 起動に3分58秒

上記は自環境で1回試した際の記録ですので、目安レベルとご認識ください。
各プロセスはネットワーク速度によって変動があると思います。所要時間の半分くらいはダウンロードを行っています。

単なるHelloWorldですが、難しいことなく手軽に試せるというイメージは持っていただけるのではないでしょうか。
タイムアタックする必要はありませんが、ぜひ一度チャレンジしてみてください。
「デカ文字」「デジタル日日(64x128)」をST7735で作る1(仕様)

目的
温度計等で使用かる　どでか　デカ文字を作り表示する
圧縮形式または、方法は、沢山あるが上下分離のパターン式とする


完成図

![o_cop500.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/eecea205-a79e-dcc6-6df2-1b5450de08eb.jpeg)



分類

![o_cop498.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/5b698e20-c1a4-5f94-0e0e-c5dc64d005ef.jpeg)


![o_cop499.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/085e7c98-4a54-3f7a-5237-0a566f9db1f4.jpeg)


![o_cop501.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/e71a9e93-36aa-95f7-317f-0afba68ab362.jpeg)
MicroStrategyにおけるID・DESCの挙動

# はじめに
本記事ではMicroStrategyにおける
IDとDESCの設定不備によっておこる挙動についてご紹介します。

# ID・DESCとは
アトリビュートに設定できるものです。
他のカラムをキーとして名称や説明などを取得したい際にDESCに設定すると
IDをキーに、データを取得することができます。
IDにはコード、DESCには説明や名称などを設定することが多いです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2737479/180d682b-0bf8-3211-c3df-32cafe65a7a7.png)

# ケース
今回のケースではエリアの名称が定期的に変わる場合を想定します。
当時のエリア名称：エリア名称　※トランザクションから取得
最新のエリア名称：エリア名称（マスタ）※マスタから取得
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2737479/18c2b1e6-7efd-8155-43b4-5b44586fd188.png)
データベースには以下のデータが格納されているとします。
※こちらは記事用に準備したテストデータです。
AAAの名称が東京エリア→関東エリアに変わったことがわかります。
上記の通り、トランザクション当時の名称を取得するためデータベースのまま
画面上でも取得できることが正しいです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2737479/1002f344-7c2f-0203-b207-2cfde879b1bc.png)
本来であればIDにエリア名称をセットするべきですが
マスタから取得するときのようにIDとDESCにカラムをセットします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2737479/dfb0bee8-e2e7-5d41-3822-0a4b44a599b7.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2737479/57f745e6-ea43-99b4-3f3e-8f2ab00cb69f.png)
そうすると以下のように表示され、トランコード4の名称が
関東エリアではなく東京エリアで表示されてしまいます。
これはトランザクションのエリアコードをキーにエリア名称を取得するので
実行するたびに値が変わったり、maxがセットされたりなど正しい値を取得できません。
「名称や説明はDESCで設定する」という誤った理解をしたまま実装するとこのような不備が発生します。またデータが変わらないと検知できないため、初期での検知は難しくとも、のちの不具合に繋がる可能性があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2737479/a287fa47-114d-a3cb-3452-3179e74ab773.png)

# さいごに
製品仕様を理解していないと発生する事象かと思います。
また検知してから水平展開で改修するとなると相当な工数がかかります。
そのため開発からこのような細かい仕様を把握しておくことが重要となります。
以上、みなさまの業務の一助となれましたら幸いです。
GithubActions, rsyncを用いたVue.jsの自動デプロイ

本記事では、GithubActionsとrsyncを使用してVue.jsアプリケーションをAWS EC2上に自動デプロイする方法について解説します。
これにより、開発環境へのビルドが煩わしさや、リソースの限られるサーバでビルドする際のメモリ不足問題を解決できます。
## secretsにssh情報を設定
セキュリティのために、GithubのsecretsにEC2へのSSH接続に必要な情報を設定します。EC2_SSH_PRIVATE_KEY、EC2_HOST、EC2_USERの3つを登録しておきます。

## workflowファイルの作成
まず、Githubリポジトリのルートディレクトリに.github/workflowsフォルダを作成し、その中にdeploy.ymlという名前のファイルを作成します。

deploy.ymlファイルには、以下の内容を記述します。
```yml
name: Deploy to AWS EC2 staging

on:
  push:
    branches:
      - hogehoge

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout repository
      uses: actions/checkout@v3

    - name: Setup Node.js
      uses: actions/setup-node@v3
      with:
        node-version: '16'

    - name: Build
      run: |
        npm install
        npm run build --if-present

    - name: Deploy to EC2
      env:
        PRIVATE_KEY: ${{ secrets.EC2_SSH_PRIVATE_KEY }}
        HOST: ${{ secrets.EC2_HOST }}
        USERNAME: ${{ secrets.EC2_USER }}
      run: |
        echo "$PRIVATE_KEY" > private_key.pem
        chmod 600 private_key.pem
        rsync -avz -e "ssh -i private_key.pem -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" --exclude '.git/' --exclude 'node_modules/' --exclude 'private_key.pem' ./dist/ $USERNAME@$HOST:/path/to/your/vue/project/dist
        rm -f private_key.pem
```
## プログラムの解説
### トリガー
onキーで、ワークフローのトリガーを設定しています。今回は、ブランチへのプッシュをトリガーにしています。hogehogeの箇所は適宜修正してください。

### job
jobsキーでは、ワークフロー内で実行されるジョブを定義しています。今回は1つのジョブdeployがあり、以下のステップが含まれています。

- セットアップ
    リポジトリのチェックアウト: actions/checkout@v3を使用して、リポジトリのコードをチェックアウトします。
    Node.jsのセットアップ: actions/setup-node@v3を使用して、Node.jsをセットアップします。今回はバージョン16を指定しています。
- ビルド
ビルド: npm installで依存関係をインストールした後、npm run build --if-presentでビルドを実行します。--if-presentオプションは、buildスクリプトが存在しない場合にエラーを回避するために使用されます。
- rsyncによるファイル転送
EC2へのデプロイ: まず、secretsから取得したSSHの秘密鍵をprivate_key.pemという名前のファイルに保存し、パーミッションを600に設定します。その後、rsyncコマンドを使用して、ビルドされたファイルをEC2インスタンスに転送します。.git/、node_modules/、およびprivate_key.pemディレクトリは除外されます。最後に、private_key.pemファイルを削除します。
ファイルごとのMR頻度を出力するshellファイル作ったメモ

# 概要
ソースコードはファイルやClassごとに編集頻度の濃淡があります。重要な処理はやはり頻度が多くソースコードも肥大化しがち。
一方で、プロジェクト参画時はそういった濃淡が把握できずどこからインプットしたら良いかというのも判然としないことがままあります。
そういうわけで「まあこのへんから見てみたら？」程度にソースコードの重要性を図れる手段を備忘しました。

# やったこと
以下の仕様で動作するshellファイルを作成。

* 設置したディレクトリ配下のファイルの中で、gitのMR回数をカウント
* 直近半年カウント
* 上位20件を表示

# ソースコード

```shell
#!/bin/bash

# 直近半年間のマージコミットIDを取得
merge_commits=$(git log --merges --since="6 months ago" --pretty=format:"%H")

# ファイルの変更回数をカウントする連想配列を宣言
declare -A file_count

# 各マージコミットに対して実行
for commit in $merge_commits
do
  # マージコミットの親コミットIDを取得
  parent_commit=$(git log --pretty=format:"%P" -n 1 $commit)

  # マージコミットと親コミット間の差分を取得
  diff_files=$(git diff --name-only $parent_commit $commit)

  # 差分に含まれるファイルをカウント
  for file in $diff_files
  do
    file_count[$file]=$((file_count[$file] + 1))
  done
done

# カウント結果を表示
for file in "${!file_count[@]}"
do
  echo "${file_count[$file]} $file"
done | sort -rn | head -20

```

# おわり
担当者ごとのMR頻度とかを定期計測できるようにしたら生産性可視化までいけそうなのでどっかでやります。
【Wordpress】ContactFrom7でのスパムメール対策

こんにちは、新人エンジニアのやまべです。

## 背景
入社直後から運営をさせてもらっているサイトで問題発生。
お問い合わせフォーム経由でとんでもない数のスパムメールが来てしまっていた...
同じようなことが起こらないように対策方法をメモ。
（サイトを作成したての頃はほとんど来ていなかったのですが、運営している間に急に来るようになって大焦りでした...）

私の運営サイトのお問い合わせフォームは「ContactFrom7」というプラグインを使っていたのでそのプラグインをベースにスパム対策を紹介していきたいと思います。

【 紹介する内容 】
1.お問い合わせフォームプラグイン「ContactFrom7」
2.スパム対策用サービス「reCAPTCHA」

# 1. プラグイン 「ContactFrom7」 をインストール

1.プラグイン＞新規追加を押下
![スクリーンショット 2023-05-09 13.47.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2512240/8b693fab-c04a-a6e1-ba54-7f07f7bf679e.png)
2.検索窓でContactFrom7と検索
![スクリーンショット 2023-05-09 13.48.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2512240/7ae0cad7-86df-62d2-2917-d9a23bbb6dba.png)
3.今すぐインストールを押下し、有効化する
※wordpressではインストールするだけでは反映されないので、使用したいプラグインは必ず「有効化」しましょう。

これでプラグインの導入は完了！！

お問い合わせという欄が増えるのでそちらで問い合わせの設定を行いましょう。

#  2. 「reCAPTCHA」 の導入
ここからはスパムメールの対策方法になります。

・そもそもreCAPTCHAとは
reCAPTCHAとは、botによるWebサイトへのスパム攻撃を防ぐためGoogleが提供しているサービスのことです。例で言うとお問合せフォームの画面やログインするときの認証画面で「私はロボットではありません」にチェックを入れる場面。あれって実はreCAPTCHAが動いてくれているからなんです。


お問い合わせフォームなどを設置すると悪意的なbotによる攻撃を受けることが普通にあります（自戒です）reCAPTCHAはいわばそのような攻撃や怪しいものを防ぐために使われるツールと言っていいでしょう。
→お問い合わせフォームやログイン画面等を設置するときはサイトの安全性を保つために必ず入れておくことをお勧めします...！

ーーではここから手順を説明していきます。ーー
#### #01 「Google reCAPTCHA」の操作

https://www.google.com/recaptcha/intro/v3.html

1.上記のリンクに移動し、v3 Admin Consoleをクリックしてログイン
![スクリーンショット 2023-05-09 13.58.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2512240/c7d07d85-f378-18e6-18b0-b0ab9f553ecb.png)

2.「新しいサイトの登録」画面が出てくるので必要事項を記入

・ラベル
→なんでもいいので自分がわかりやすい名前にしておきましょう
・reCAPTCHAタイプ
→スコアベース（v3）を選択
・ドメイン
→設定したいサイトやブログのドメインを入力しましょう

![スクリーンショット 2023-05-09 14.02.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2512240/3241c9cb-b43f-c3e2-eeba-adb0db969208.png)
3.登録をクリックすると、サイトキーやシークレットキーが表示されるので控えておきましょう（後でwordpress側で設定します）

#### #02 「Wordpress」側の操作
1.お問い合わせ＞インテグレーション
![スクリーンショット 2023-05-09 14.04.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2512240/8bc66e1c-e95e-7dcf-2345-910eeba530f4.png)
2.reCAPTCHAの「インテグレーションをセットアップ」をクリック
![スクリーンショット 2023-05-09 14.05.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2512240/b8505bab-8d85-8d1b-7998-a511e738300e.png)
3.reCAPTCHAの登録した後に出た「サイトキー」と「シークレットキー」をコピーしてきて貼り付けましょう
![スクリーンショット 2023-05-09 14.06.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2512240/f859cf92-0bcf-3095-ad82-016bedffefa2.png)

これでreCAPTCHAの設定は完了しました！
右下あたりにreCAPTCHAのマークが出ていれば保護は完了したことになります。お疲れ様でした！！

最高のサイト、ブログ作りをしてきたのにセキュリティ対策ができていなかったせいで、乗っ取りられて改ざんされた...サイトがめちゃくちゃになってしまった...ということが起こる前に打てる対策はしっかりしておきましょう...！