OmniAICreator/Qiita-1.07M huggingface dataset:
機械学習で人とゴリラを見分ける

最近、怠惰なせいでqiitaを書いておりませんでした。
どうも、山田永昌です。

みなさん、ゴリラってあだ名がついている友達っていませんでしたか？
例えば、当方しがない中学生なのですが、学校で何故かゴリラと呼ばれている、もしくは喩えられているのが数人おります。
嫌がってるのか面白がってるのかは詳細はあまり詳しくないので不明です、その様な事実があることは確かでございます。

と言うわけで、今回はゴリラか人か見分けるAIを作り、果たしてゴリラと呼ばれる人はゴリラであるのか客観的に証明してみたいと思います。

まず、機械学習では当たり前ですが、学習させるデータが必要です。
今回はkaggleと言う、機械学習などを嗜んでる方には周知であろうサイトから、ゴリラと人のデータセットを探し、拝借させていただきました。
以下のURLに記載いたします。
https://www.kaggle.com/datasets/ashwingupta3012/human-faces
https://www.kaggle.com/datasets/smiles28/gorillas

今回はgoogle colab上で学習させました。
下は学習曲線です。
![スクリーンショット 2022-09-05 19.06.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/795753/59f9ba83-e2db-1f37-bab4-7d0d3263bf38.png)


と言うわけで機械に学習させ終わりました。

テストとして、以下の画像判別させてみたいと思います。
![スクリーンショット 2022-09-07 0.22.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/795753/05648585-aef4-ee38-1908-f3d699eb2ce3.png)
ダンディなゴリラとhe-manです。

![スクリーンショット 2022-09-07 0.31.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/795753/dc89eec4-77c8-0fed-0230-5ba13f6f3544.png)
ちゃんと、判別できていますね。
では、明日、学校で試してみます。

追記:ちゃんとみんな人でした。
【Go/Gin】ちゃんとセッションを消すログアウト

この記事はGo言語、Ginフレームワークの、とくに<strong>gin-contrib sessionのログアウト</strong>について、しっかりセッションを消す方法について書いています。

# 通説
gin-contrib sessionの扱い方を紹介している記事で、よくログアウト機能をこのように組み立てているものが主流になっています。

```go
func Logout(ctx *gin.Context) {
	session := sessions.Default(ctx)
	session.Clear()
	session.Save()
}
```
しかし、この方法ではブラウザ側ではセッションが残ったままになってしまいます。
セッションの内容がnilになっているかでセッションチェックを行っている場合はちゃんとログアウトできているような挙動をしますが、ブラウザの開発ツールでcookieのセッションが残っていることが確認できることかと思います。

筆者はこれを悪用したログアウト状態のPOSTを受けました(笑)

# 解決法
[GitHubのissue](https://github.com/gin-contrib/sessions/issues/89)に解決策がありました。
ログアウト関数を以下の通りに書き換えます。
```go
func Logout(ctx *gin.Context) {
	session := sessions.Default(ctx)
	session.Clear()
    session.Options(sessions.Options{Path: "/", MaxAge: -1})
	session.Save()
}
```
これで、セッションがちゃんと消えていることがブラウザの開発ツールで確認できるかと思います。
ブロック同期遅延（Final停滞）の際の復旧手順

![スクリーンショット 2022-09-06 233514.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1185246/9e1749f1-9c4b-284c-6b3f-1499afbaac14.png)

何らかの理由によりSymbolノードのFinalブロック同期に遅延が生じ、ブロックHeightは正常なのにFinalブロックだけ更新されなくなってしまった場合、何度「resetData」を実施しても、そのまま放置していても、永遠に修復されないケースがあります。

原因の一つとして、preset.ymlの「blockDisruptorMaxMemorySize」の初期設定値が低いため、その値を超すブロックのFinalizeをSymbolノードがDisrupt（中断）してしまうことが挙げられます。

そのため、復旧にはpreset.ymlの「blockDisruptorMaxMemorySize」の値を変えてやる必要があります。

＜手順＞

（１）symbol-bootstrapの停止

```cd ****（targetフォルダのある階層へ）```
```
symbol-bootstrap stop
```

（２）preset.ymlの書き換え

preset.ymlのあるtargetフォルダ内へ移動
```
cd target
```
preset.ymlの編集
```
vi preset.yml
```

「blockDisruptorMaxMemorySize: 300MB」
を
「blockDisruptorMaxMemorySize: 1000MB」
に変更


（３）symbol-bootstrapの再起動

```
symbol-bootstrap config -p mainnet -a dual -c <カスタムプリセットYMLファイル名> --upgrade
symbol-bootstrap compose --upgrade
symbol-bootstrap run -d
```

（４）HeightとFinalが正常に更新されているか確認


#＜　宣　伝　＞

デリゲートハーベスティングには、是非とも以下のノードのご利用を❣

　```0-0-0-high-performance.harvest-node.com```
　```0-0-1-high-performance.harvest-node.com```
GitHub Actions から AWS へアクセスする

AWS にアップロードしたりデプロイしたりするには、IAM の認証情報が必要になります。GitHub Actions のワークフローで認証情報を設定する方法です。

## 固定キーを使う

参照) [Deploying using GitHub Actions](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/deploying-using-github.html)

IAM ユーザーを作成し、アクセスキーを Action secrets の AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY に設定しておきます。ワークフローからは [Configure AWS Credentials](https://github.com/aws-actions/configure-aws-credentials) アクションを使用して、この認証情報を使用します。

```yaml
steps:
  - uses: aws-actions/configure-aws-credentials@v4
    with:
      aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
      aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
      aws-region: ap-northeast-1
```

## IAM Roles for Service Accounts

固定のアクセスキーではなく IAM ロールによる一時的な認証情報を使用したい場合、GitHub を IdP プロバイダとして連携します。

参考) https://dev.classmethod.jp/articles/github-actions-aws-sts-credentials-iamrole/

 1. [IAM](https://us-east-1.console.aws.amazon.com/iam/home) > Identity providers > Add provider
 2. 以下指定して Add provider
    - Provider type: OpenID Connect
    - Provider URL: `https://token.actions.githubusercontent.com` (*1)  ※入力して Get thumbprint を押す
    - Audience: `sts.amazonaws.com`

(*1) GitHub Enterprise Server の場合は、`https://HOSTNAME/_services/token` と入力します。

![Identity providers 一覧](https://hirose-public.s3-ap-northeast-1.amazonaws.com/qiita/2023/10/06/c7f73ba0-135b-4c5b-aff7-3dcd8fa8a0a8.png)

Actions から使用したい IAM ロールには、Trusted entities (信頼関係) を以下のように指定しておきます。(管理コンソールから IAM ロール作成する場合は「Trusted entity type」に「Web identity」を選択して必要な項目を入力すれば、下記のように初期設定されます。)

⚠︎Condition ステートメントに記述したリポジトリからのみ、この IAM ロールを使用できます。関係ないリポジトリから使われないよう、注意しましょう。

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Federated": "arn:aws:iam::(アカウントID):oidc-provider/token.actions.githubusercontent.com"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringEquals": {
                    "token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
                },
                "StringLike": {
                    "token.actions.githubusercontent.com:sub": "repo:yh1224/*"
                }
            }
        }
    ]
}
```

ワークフローから [Configure AWS Credentials](https://github.com/aws-actions/configure-aws-credentials) アクションを使用して、以下の記述でこの IAM ロールから認証情報を取得することができます。

```yaml
permissions:
  id-token: write
  contents: read

steps:
  - uses: aws-actions/configure-aws-credentials@v4
    with:
      role-to-assume: (ロールの ARN)
      aws-region: ap-northeast-1
```
Herokuのstackアップグレードの進め方

Herokuのstackをアップグレードする際にエラーが出て詰まったので備忘録として残します。

基本的な進め方としては
1. Heroku管理画面で対象のアプリを選択し、「Settings」選択。
1. 「Upgrade Stack」押下。
1. 次回Deploy時に自動でアップグレード

となります。

無事アップグレードできればこれで終了です。

Deploy時にエラーが出る場合は以降の内容を参考にしてください。

## エラー内容

```
 !     For reference, the following runtimes are currently available:
 !     
 !     PHP:  8.1.10, 8.1.9, 8.1.8, 8.1.7, 8.1.6
 !     
 !     Please verify that all requirements for runtime versions in
 !     'composer.lock' are compatible with the list above, and ensure
 !     all required extensions are available for the desired runtimes.
```

どうやら

1. PHPのバージョンを指定する必要がありそう。
1. その後、`composer.lock` を更新する必要がある。

ということなので一つずつ潰していきました。

## PHPのバージョンを指定する

phpのバージョンを指定するには`composer.json`に記述する必要があります。

``` json
{
  "require": {
    "php": "^8.1.0"
  }
}

```


## `composer.lock` を更新する

そもそも更新の仕方もわからないので結構詰まりました。。

調べたところ更新するには`composer update` をする必要があるということですが、そんなコマンドがないと怒られてしまいました。

```
bash: composer: command not found
```

composerを使うにはphpが必要で、phpをインストールするにはHomebrewが必要。
ということで以下の手順で進めていきます。

1. HomeBrewインストール
1. PHPインストール
1. Composerインストール

心折れそうになりますがいくつかコマンド叩けば大丈夫！

### HomeBrewインストール

以下にアクセスし、インストール用のコマンドをそのままコピペして実行。

https://brew.sh/index_ja

インストールしたらバージョン確認して出てきたらOK。

``` bash
brew -v
```

### PHPインストール

HomeBrewを使ってPHPをインストールします。

```bash
brew install php
```

エラーでた。。

```bash
Error: 
  homebrew-core is a shallow clone.
To `brew update`, first run:
  git -C /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core fetch --unshallow
```

エラーに出てるコマンドをそのまま使います。

```bash
git -C /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core fetch --unshallow
```

次は成功しました！
（インストール少し時間かかります）

```bash
brew install php
```

終わったのでバージョン確認してみます。
バージョンが表示されたらOK。

```bash
php -v
```

### Composerインストール

ここまできたら後少し！

```bash
curl -sS https://getcomposer.org/installer | php
```
`composer.phar`が作成されるはずです。
バージョン確認してみます。

```bash
php composer.phar -v
```

ようやくcomposerアップデートできる！

```bash
php composer.phar update
```

## デプロイ

これで`composer.lock`が更新されたはずですので、そのままプッシュすればOK!
お疲れ様でした！

### 参考サイト

こういったサイトにいつも助けられています。

https://www.wakuwakubank.com/posts/415-php-composer/

https://tech.amefure.com/php-homebrew

https://gotohayato.com/content/528/
CakePHPのサブクエリでunionAll()を実行するとSyntax Errorになる

# 事象
サブクエリにてunionAll()を使用するとSyntax Erorになる。

元になったORM
```
$query->where(['id in' => TableRegistry::getTableLocator()
				->get('テーブル2')
				->find()
                ->select('id')
                ->unionAll(
                    TableRegistry::getTableLocator()
                        ->get('テーブル3')
        				->find()
                        ->select('id')
                )
```
生成されたクエリ
```
SELECT * FROM テーブル 
WHERE id in ((SELECT id FROM テーブル2 )
UNION ALL (SELECT id FROM テーブル3);
```

```
(SELECT id FROM テーブル2 )
```
この()がなくなるとSyntax Errorではなくなる

# 対策
OR句を使用すること。
パフォーマンスもそんなに変わらんし、その方が素直な実装になるでしょう。
それにしてもORMとの格闘は大変だ。
ラズパイ / Ubuntu でファイル共有（1分で）

# ラズパイでSambaファイル共有

１分でいきましょう♪

# 環境

Raspberry Pi 4　/　Ubuntu 20.04　（PC や他のラズパイ、Raspian OS でも同じ）


# コマンド

```
sudo apt install samba
sudo gedit /etc/samba/smb.conf      # 後述のように設定ファイルを変更する

sudo pdbedit -a ユーザ名             # samba 用のパスワードを設定
sudo service smbd restart
sudo service nmbd restart
```

Windows 等からアクセスしてみましょう。（ \\\ラズパイのPC名 ）
ラズパイのPC名は、pdbedit の実行結果画面、あるいはUbuntu 設定→共有　の所に書いてあります。

アクセスできない時は、再起動や設定ファイルを見直し

### 設定ファイル (/etc/samba/smb.conf)

```
（行数は、記事投稿時点のもの）

-> 6個の変更

29行目
   workgroup = ワークグループ       # Windows 等に設定してるワークグループ（端末で統一する）

85行目
   unix password sync = no         # yes -> no に変更

100行目
#   map to guest = bad user        # 先頭に #をつけてコメントアウト

175-177行目
[homes]
   comment = Home Directories
   browseable = yes                # 先頭の ; を外し、 yes に変更

181行目
   read only = no                  # 先頭の ; を外し、 no に変更

219-235行目
   プリンター共有関連は、全て先頭に # をつけてコメントアウト
```



以上です。

PCからファイル共有できて便利！
Google Calendar APIを使うときにサービスアカウントでカレンダーを作る方法

こんにちは。
Google Calendar APIを使うときにサービスアカウントをオーナーにしてカレンダーを作るといい感じだったので共有です。

# よくあるフロー
ネットでよく見るやり方は主にこんな流れかと思います。
ここではカレンダーの更新権限が必要なアプリを想定しています。

1. サービスアカウントを作成
2. 自分のアカウントでカレンダーを作成
3. 2で作ったカレンダーについて、1のサービスアカウントへ必要な権限付与
3. カレンダーのAPIを使ってイベントを自動登録

これで問題ない場合はOKなんですが、会社なんかだとGoogle Workspace(旧 G Suite)の全体設定などでカレンダーの編集権限は社内のユーザーアカウントのみに制限、みたいなセキュリティポリシーにしている時があって、そのときは上記のやり方だとうまくいきません。

かといって、アプリのためにポリシー変える？みたいな話になって困っちゃいますよね。

# もうひとつのフロー
ミソはサービスアカウントがオーナーのカレンダーを作ってしまうことです。

1. サービスアカウントを作成
2. サービスアカウントでCalendar APIを実行してカレンダーを作成
3. 2で作ったカレンダーについて、共有が必要なユーザーをCalendar APIを使って追加
3. カレンダーのAPIを使ってイベントを自動登録

この方法だと、アプリのために会社全体のセキュリティポリシーを変更しなくてすみます。
さらに、誰か人が作成したカレンダーに依存しないので、属人性が排除されるのもいいところですね。

# サンプルコード
では、具体的なコードを見ていきましょう。
サンプルはRubyですが、他の言語でも同様にできると思います。

前提として、サービスアカウントを作成し、認証ファイル(json)は取得済みの状態から始めます。

APIの仕様は以下になります。
https://googleapis.dev/ruby/google-api-client/latest/Google/Apis/CalendarV3/CalendarService.html

## 初期化
このインスタンスから各種APIを実行していきます。

```ruby
require 'google/apis/calendar_v3'
require 'googleauth'
require 'googleauth/stores/file_token_store'

# どこかクラスに以下のメソッドを書いている想定

def google_service
  @google_service ||= Google::Apis::CalendarV3::CalendarService.new.tap do |service|
    service.client_options.application_name = '素敵なアプリケーション'
    sio = StringIO.new({client_email: ENV['GOOGLE_CALENDAR_CLIENT_ID'], private_key: ENV['GOOGLE_CALENDAR_CLIENT_PRIVATE_KEY'].gsub(/\\n/, "\n")}.to_json)
    service.authorization = Google::Auth::ServiceAccountCredentials.make_creds(json_key_io: sio, scope: Google::Apis::CalendarV3::AUTH_CALENDAR)
  end
end

```

## サービスアカウントでCalendar APIを実行してカレンダーを作成
最初にこれをバッチかなんかで実行してカレンダーを作ります。カレンダーのIDは後々使うので控えておきましょう。

```ruby
calendar = Google::Apis::CalendarV3::Calendar.new(summary: 'カレンダーのタイトル', description: 'カレンダーの詳細')
result = google_service.insert_calendar(calendar)
result.id

```

## 共有が必要なユーザーをCalendar APIを使って追加
これをしないと、誰もサービスアカウントが作ったカレンダーを見ることができません。

権限付与したいユーザーを指定してあげましょう。
これも最初はバッチでやるとかになると思います。

これを実行すると、登録したメールアドレス宛に確認のメールが届きます。
その中にある「カレンダーを追加」を押すと、該当ユーザーはカレンダーを見ることが可能です。

```ruby
scope = Google::Apis::CalendarV3::AclRule::Scope.new(type: 'user', value: 'account@example.com')
acl = Google::Apis::CalendarV3::AclRule.new(role: 'writer', scope: scope)
google_service.insert_acl(@calendar_id, acl)
```

## Calendar APIを使ってイベントを登録
あとはイベントなどお好きなものをカレンダーに登録すれば、OKですね。


```ruby
calendar_object = Google::Apis::CalendarV3::Event.new(
        start: Google::Apis::CalendarV3::EventDateTime.new(date_time: @start_at.rfc3339),
        end: Google::Apis::CalendarV3::EventDateTime.new(date_time: @end_at.rfc3339),
        summary: 'イベントタイトル',
        description: '詳細事項'
      )

event = google_service.insert_event(@calendar_id, calendar_object)
event.html_link # ここにカレンダーのイベントごとのURLが入っている。(参考)
```

個人的には少しの違いですが、だいぶ楽になると思います。
Google Workspaceの設定の影響を受けないのがとてもよいと思いました。

サービスアカウントのこうした使い方については、プロジェクトや社内で相談した上で使っていくとよいでしょう。


# 参考文献
https://qiita.com/ikamirin/items/75446b64e2f58ea7e0f1
LazyVGridとかLazyVStackのカラムにアニメーションをつける時の注意点

## はじめに
最近はSwiftUIを触る機会が多いのですが、Table形式やCollection形式のViewを作るときは、Lazy〇〇を使うようにしています。
そんなこんなやっていた時に、LazyVGridをスクロールした時にバグが発生する問題に直面し、若干ハマったので解決方法を記事にしてみました。
ちなみにですが、iOS15のみ対応のアプリだと`warning`が出るので、このバグに直面することは少ないんじゃないかと思います！

## バグの正体
スクロールした時にセルの描画が遅れたような感じになってしまいます。
![バグ.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580445/718783e7-5013-93f4-e4d1-72a0947a1960.gif)
この時のコードは下記です。
このViewでは、各Cellをタップした時に、青からオレンジに背景色を変えるところをアニメーションにしています。

```swift
import SwiftUI

struct ContentView: View {
    
    @State private var selectedColumns = Set<Int>()
    
    let columns: [GridItem] = Array(
        repeating: .init(.flexible()),
        count: 5
    )
    
    var body: some View {
        ScrollView {
            LazyVGrid(columns: columns) {
                ForEach((1...100), id: \.self) { index in
                    Rectangle()
                        .frame(width: 60, height: 60)
                        .foregroundColor(selectedColumns.contains(index) ? .orange : .blue)
                        .animation(.easeInOut(duration: 0.3))
                        .onTapGesture {
                            switchSelected(index: index)
                        }
                }
            }
        }
    }
    
    func switchSelected(index: Int) {
        if selectedColumns.contains(index) {
            selectedColumns.remove(index)
        } else {
            selectedColumns.insert(index)
        }
    }
}

```

## 原因
結論から書くと、どのプロパティ状態によってアニメーションが行われるかが明確化されていないためにこの問題が起こります。
iOS15からは非推奨になっているメソッド`animation(_:value:)`は、どのプロパティの変化によってアニメーションが起きるかが明確になっていません。

上記のコードで言うと`.animation(.easeInOut(duration: 0.3))`が該当します。

## 解決
iOS15から非推奨になった上記のメソッドの代わりに、`animation(_:value:)`を利用することです。（推奨になっただけで以前のOSでも使える）
先ほどのメソッドとの違いは、`value`という第2引数が必要になったことです。

こちらのメソッドは、`value`に入れたプロパティが変更されたときのみViewのanimationが走るという効果があります。
なので、`value`には、animationと紐づけたい処理を入れるのが正しいということになります。

今回の場合、`selectedColumns`にタップされたGridのIndexが追加された時にanimationをキックしたいので、
上記コードを
`.animation(.easeInOut(duration: 0.3))` -> `.animation(.easeInOut(duration: 0.3), value: selectedColumns)`
というように変更してあげればOKです。

ちゃんと動くようになりました！
![正常.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580445/e6d80303-bf73-4cc5-39fb-d98a4af2d983.gif)

## FYI
解決方法は実はもう1つあります。

`withAnimation(_:_:)`を利用する方法です。
利用方法はanimationをキックしたい処理のところを`withAnimation(_:_:)`のブロックの中に書いてあげる感じです。

```swift
.onTapGesture {
    withAnimation(.easeInOut(duration: 0.3)) {
        switchSelected(index: index)
    }
}
```
UIKitのアニメーションっぽい感じなので、UIKitに慣れている場合はこちらの方が直感的な気がします。

## おわりに
最初にお伝えした通り、今回のバグの原因となるコードはiOS15〜は非推奨なのでそもそも使わないのが理想ですね。
ただ、iOS14などをサポートしている場合、`warning`が出ないので気づかないうちに使っているということもあるあるです。

そう言ったケースでは「アニメーションを明示的に指定する」ことでこのような問題が解決できることがわかりました！
読んでいただきありがとうございました🙏
BertとWord2vecを組み合わせて謎かけAIを作ってみた。

お遊びアプリとして
BertとWord2vecを組み合わせて謎かけAIを作ってみた。


https://github.com/yasuhirotakao/nazokake

## どんなアプリ
お題を入れると、謎かけを回答してくれるアプリ

```bash
> python .\nazokake.py

Please input odai : 利根川
2022-09-06 22:49:41.121694
「利根川」とかけて「出産」と説く　その心は!
どちらも「用水/羊水(ヨウスイ)」がつきものです
2022-09-06 22:49:44.241902

Please input odai : 野球
2022-09-06 22:51:30.649636
「野球」とかけて「システム」と説く　その心は!
どちらも「捕手/保守(ホシュ)」がつきものです
2022-09-06 22:51:33.327652

Please input odai : 銀行
2022-09-06 22:52:44.977923
「銀行」とかけて「禁止」と説く　その心は!
どちらも「現金/厳禁(ゲンキン)」が欠かせません
2022-09-06 22:52:45.417922
Please input odai :
```
## アルゴリズム

1. 何個かの定型文を用意する。
```
XXXにYYYは必要です
XXXはYYYが課題です
```
2.定型文のXXX(例：利根川)の部分にお題をいれる。YYYをマスクする。
```
利根川に[MASK]は必要です
```
3.上記をBERTを使って、複数の[MASK]の候補リスト（100個ほど）する。

4.上記だけだと、お題と無関係な単語も出てきやすいので、
　word2vec.most_similarを使って、候補リストで、お題と関係性の強い単語に
　絞り込む
（今回は用水（ようすい）が候補の一つ）

5.上記で絞り込んだ候補リストのうち、**同音異義語のDB** に該当する単語があるか
　求めて、同音異義語の候補リストを求める（今回は羊水（ようすい）が候補の一つ）。

6.候補リストを定型文のYYYにおいてXXXをマスクする。
```
[MASK]に羊水は必要です
```
7.上記をさらにBERTを使って、複数の[MASK]の候補リストを求める（100個ほど）。
8.上記だけだと、候補と無関係な単語も出てきやすいので、
　word2vec.most_similarを使って、候補と関係性の強い単語に
　絞り込む(この場合：出産)

9.上記で複数候補がでてくるので，ランダムに並べ替えて早く答えが出てきたものを
解答する。


## 同音異義語のDB

こちらのVocabulary Database for Reading Japanese (VDRJ) Ver. 1.1
重要度順語彙データベース (Top 60894)　重要度順位　00001-60894 (42MB)
から作成
http://tatsuma2010.web.fc2.com/VDRJ_Ver1_1_Research_Top60894.xlsx
感謝です。

# ソースコード
https://github.com/yasuhirotakao/nazokake

# 今後の課題
 * 時事問題に弱い。BERTや同音異義語の辞書を改める。
 * いくつかの候補の中から、何が最適解かを判断するのが難しい。
 * WEBサイトとかで公開したい。でも８GB以上のRAMが必要。ラニングが心配
【Java】Json文字列をオブジェクトに変換

# はじめに
jsonをjavaクラスに変換する方法をまとめました。
以下のエラーに悩んだので原因と解決方法も書いています。
```com.fasterxml.jackson.databind.exc.InvalidDefinitionException```

## Json⇒javaクラス変換

mainクラス
```java
    	String sjson = "{\"id\": 1, \"name\": \"Tanaka Taro\", \"gender\": \"Man\", \"age\": 23}";

    	ObjectMapper  mapper = new ObjectMapper();
    	BaseballPlayer player = mapper.readValue(sjson, BaseballPlayer.class);
    	System.err.println(player.getName());
```
BaseballPlayerクラス
```java
public class BaseballPlayer {
	private int id;
	private String name;
	private String gender;
	private int age;

	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getGender() {
		return gender;
	}
	public void setGender(String gender) {
		this.gender = gender;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
}
```
結果
```
Tanaka Taro
```

## InvalidDefinitionExceptionが発生する場合
原因はjsonのプロパティ名が大文字始まりの場合に、発生します。
解決方法としてはおとなしく小文字のプロパティ名にするか、大文字小文字を区別しない設定をいれてください。

```java
    	String sjson = "{\"id\": 1, \"name\": \"Tanaka Taro\", \"gender\": \"Man\", \"age\": 23}";

    	ObjectMapper  mapper = new ObjectMapper();
        mapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true); // ←これです
    	BaseballPlayer player = mapper.readValue(sjson, BaseballPlayer.class);
    	System.err.println(player.getName());
```
【PHP】URLパス部分に特定の文字列が含まれるかどうかの条件分岐【str_contains()】

## パスを取得
```
$path = $_SERVER['REQUEST_URI']
```
PHPが提供するスーパーグローバル変数$_SERVERを利用する。
'REQUEST_URI'に現在アクセスされているパスが格納されている。
因みに「プロトコル（httpsか？） + ホスト名（localhostなど） + パス（/index.phpなど） = 現在のURL」となる。

## PHP 8以上では`str_contains()`を使用
:::note
`strpos()`をメインで説明していましたが、コメントにて「文字列が含まれるかどうかをチェックするには `str_contains()`を使うとよいのではないでしょうか」といただいたので`str_contains()`の内容を追加しました。ありがとうございます！
:::
### 条件分岐
```
if( str_contains( $path, 'hogehoge' ) {
// $pathにhogehogeが含まれる場合

} else{
// $pathにhogehogeが含まれない場合

}
```
PHP 8で追加された関数`str_contains()`を使用すると、特定の文字列が含まれるかどうかの真偽値true/falseが返されるので、上記のように条件分岐できる。



## PHP 7系以下では`strpos()`を使用
### 条件分岐
```
if( false === strpos( $path, 'hogehoge' ) {
// $pathにhogehogeが含まれない場合

} else{
// $pathにhogehogeが含まれる場合

}
```
`strpos()`は文字列が見つかった位置を整数で返すので上記で判定できる。
※類似の関数`strstr()`は最初に現れる場所を含めてそこから文字列の終わりまでを返す。
※`strpos()`の方がメモリ消費が少ないので、PHP 7.4以下では文字列が含まれるかどうかの判定であれば`strpos()`を使うのがよい。

### strpos()の注意点
検索対象が先頭に見つかる場合は`strpos()`で0が返されるので注意。
```
if( strpos( 'apple', 'a' ) ) {
    // 'a' が 0 番目にあるので、boolean変換で偽になる
}
```
`str_contains()`と同じ感覚で使うとハマる可能性あり。

https://www.php.net/manual/ja/function.strpos.php
Rails入門 | エラー時の戻り値を理解して適切に使い分けるfindとfind_byとwhere

## findメソッドの概要
- 各モデルのidを検索キーとしてデータを取得するメソッド
- id以外の条件で検索不可
- 戻り値は検索対象のクラスのインスタンス
- 取得したいデータのidが特定されている場合

### findの記述方法
```ruby
# 単一のIDを指定
Customer.find(1)
Customer Load (0.4ms)  SELECT "customers".* FROM "customers" WHERE "customers"."id" = $1 LIMIT $2  [["id", 1], ["LIMIT", 1]]

# 複数のIDを指定
Customer.find(1, 2, 3)
Customer Load (8.7ms)  SELECT "customers".* FROM "customers" WHERE "customers"."id" IN ($1, $2, $3)  [["id", 1], ["id", 2], ["id", 3]]

# 配列で複数のIDを指定
Customer.find([1, 2, 3])
Customer Load (3.5ms)  SELECT "customers".* FROM "customers" WHERE "customers"."id" IN ($1, $2, $3)  [["id", 1], ["id", 2], ["id", 3]]
```

### エラー時の戻り値
検索対象が存在しなかった場合は**例外を返す**

```ruby
Customer.find(189879)
Customer Load (1.5ms)  SELECT "customers".* FROM "customers" WHERE "customers"."id" = $1 LIMIT $2  [["id", 189879], ["LIMIT", 1]]
ActiveRecord::RecordNotFound: Couldn't find Customer with 'id'=189879
```

## find_byの概要
- 各モデルをid以外の条件で検索するメソッド(idでも検索可能)
- 複数の検索条件を指定可能
- 戻り値は検索対象のクラスのインスタンス
- 返ってくる結果は、最初にヒットした1件のみ
- id以外のプロパティでデータを特定したい時

### find_byの記述方法
```ruby
Customer.find_by(name: "株式会社カンパニー")
Customer Load (7.2ms)  SELECT "customers".* FROM "customers" WHERE "customers"."name" = $1 LIMIT $2  [["name", "株式会社カンパニー"], ["LIMIT", 1]]
```

### エラー時の戻り値
検索対象が存在しなかった場合は**nilを返す**

```ruby
Customer.find_by(name: "株式会社カンパニー")
Customer Load (34.7ms)  SELECT "customers".* FROM "customers" WHERE "customers"."name" = $1 LIMIT $2  [["name", "株式会社カンパニー"], ["LIMIT", 1]]
=> nil
```

## whereの概要
- 各モデルをid以外の条件で検索するメソッド
- 該当するデータ全てが返ってくる
- 戻り値はActiveRecord::Relationオブジェクト
- id以外のプロパティでデータを特定したい時

### whereの記述方法
```ruby
# 前方一致
Customer.where('address like ?', '東京都')
Customer Load (41.9ms)  SELECT "customers".* FROM "customers" WHERE (address like '東京都')

# 後方一致
Customer.where('name like ?', '株式会社%')
Customer Load (71.4ms)  SELECT "customers".* FROM "customers" WHERE (name like '株式会社%')

# 部分一致
Customer.where('name like ?', '%カンパニー%')
Customer Load (34.8ms)  SELECT "customers".* FROM "customers" WHERE (name like '%カンパニー%')

# and検索
Customer.where('name like ?', '%カンパニー%').where('address like ?', '東京都')
Customer Load (34.8ms)  SELECT "customers".* FROM "customers" WHERE (name like '%カンパニー%')
```

### エラー時の戻り値
検索対象が存在しなかった場合**空のActiveRecord::Relationオブジェクトを返す**

```ruby
Customer.where('name like ?', '%カンパニー%')
Customer Load (92.5ms)  SELECT "customers".* FROM "customers" WHERE (name like '%カンパニー%')
[]
```
静的コンテンツ公開時のCloud Storageのキャッシュについて

# はじめに
Cloud Storage(以降GCSと記載)経由で静的Webサイトとして公開してる場合に最新の状態が表示されないことがあり、それの原因について調査した。

# 構成
- LB → GCS、GCF
    - 静的コンテンツはGCSへ
    - 動的コンテンツはGCFへ

# 発生してしまった事象及びその原因
GCSではデフォルトで以下の機能があり、まるでCDNを介しているかのようにキャッシュする機能がある。
特に設定せずとも、このメタデータはデフォルトで利用される。
```
一般公開オブジェクトの Cache-Control メタデータにより、オブジェクトがブラウザと
インターネット キャッシュに保存される期間が決まります。デフォルトでは、一般公開オブジェクトの max-age 設定は 
3,600 秒（1 時間）です。max-age には任意の長さの時間を設定できます。
```
参照
https://cloud.google.com/storage/docs/caching?hl=ja#built-in_caching_for

# 回避策
- 公開した場合GCSバケットのオブジェクトキャッシュのデフォルト設定が3600秒でありそれを変更する
    - メタデータで「no-cache, max-age=0」を設定し、キャッシュが効かないように設定する
    - メタデータで「max-age」を「15-60」に設定し、キャッシュが効くものの、オブジェクトが数秒間古い状態になることを許容する
https://cloud.google.com/storage/docs/caching?hl=ja#performance_considerations
```
public, max-age=3600
```
※上記はデフォルト値

# 対応
コンテンツ更新後も含めてどうしても最新情報を常に表示させたい、という場合、
オブジェクト配置に伴い自動でmax-ageを設定するFunctionsを設置する。

## Functions設定
### トリガー
ファイナライズ / 作成
対象バケットを選択
### ソース(以下サンプル)
```
from google.cloud import storage
import traceback

def cachenone(event, context):
    client = storage.Client()
    #バケット及びファイル情報を取得
    bucket_name = format(event['bucket'])
    bucket_object = format(event['name'])

    #バケットの存在確認
    try:
        #バケット情報取得
        bucket = client.get_bucket(bucket_name)
        print(bucket)
    except:
        print(traceback.format_exc())
        print("イベント取得失敗")
        print("status:ERROR")
        raise

    #blob情報取得
    blob_object = bucket.blob(bucket_object)
    print(blob_object)

    #キャッシュ設定を無効化
    try:
        blob_object.cache_control = 'no-cache, max-age=0'
        blob_object.patch()
    except:
        print(traceback.format_exc())
        print("cache設定失敗")
        print("status:ERROR")
        raise

    print("cache設定成功")
    print("status:info")

```
参照
https://googleapis.dev/python/storage/latest/blobs.html

# 結果
オブジェクト新規設置、更新後、Functionsが稼働しキャッシュがかからないことを確認した

# 設定に伴注意事項
CloudStorageのキャッシュ自体はこれで無効化できるが、Cloud CDNを利用する場合、max-ageの値を利用します。
そのため、この機能を有効化したままの状態でキャッシュはCDNでおまかせ、という構成をイメージしている場合、
不可となりますので、注意が必要です。
https://cloud.google.com/storage/docs/caching?hl=ja
また、デフォルトとCDNを利用した場合の違いもあるので、要件や状態に応じて検討頂いたほうが良いと思います。個人的に特筆すべき事項だと思った部分記載します。
- キャッシュ可能な最大サイズがCDNだと5TiB
- キャッシュの無効化を記載したFunctionsなどを利用せずともCDN側で無効化設定が可能
- あとは料金面でCDNとCloudStorageでそれぞれメリットがある
https://cloud.google.com/storage/docs/caching?hl=ja#pricing_considerations
```
Cloud Storage
1 か月間に処理するキャッシュ可能なデータ量が数 GiB 未満の場合は、Cloud Storage の組み込みキャッシュを使用するほうが、全体的な費用が抑えられると考えられます。
CDN
1 か月あたり 100 GiB 以上のキャッシュ可能なデータを常時配信している場合、またはリクエストごとにロギングとカスタム ヘッダーを使用する必要がある場合は、Cloud CDN を使用するほうが料金を抑えられると考えられます。
```
javacをtomcatで使う

https://atmarkit.itmedia.co.jp/ait/articles/0710/11/news121_3.html

tomcatコンテナ内に上のリンクを参考にhelloworldのサンプルファイル作ろうとしたときにjavacというコンパイルに必要なコマンド必要だとわかったのでメモ


結論：
JDK（Javaの開発キット）にそのコマンドが含まれている&tomcatにapt系コマンドがもともと入っていたので以下のコマンドでインストール
```
apt-get install default-jdk
```
aptでインストール：https://www.linuxmania.jp/apt-install-java.html
JDKは開発キット：https://techacademy.jp/magazine/22220
【LINE Bot】あれ、明日の勤怠なんだっけ？自分の携帯で確認できるLINE Bot作成してみた！！　【 GoogleSpreadSheetAPI 】


**はじめに**
*******
こんにちは！初めて投稿致します！
普段はRPA等の業務を担当しています。

今回は、Make(旧integromat)を用いて勤怠情報を返すLINE Botを作成してみました！
紙のスケジュール見れば解決？

私は、会社のツールにスケジュールを管理していまして、それを確認するとなると社用携帯からVPNをつないで、
自社システムサイトを開いてとめんどくさい…。

自分の携帯でも簡単に確認したい！！
ということで作ってみました。

**使用ツール**
****
・Make(旧integromat)
・google sheets
・各LINEモジュール



**実際の動き**
******

https://twitter.com/i/status/1567131609903812608

シートに対応する日付を入れると、その日の勤怠（予定）を返してくれます。

シートに対応する情報がない場合、正しい記入法を教えてくれます！


**Makeの流れ**
**********
![スクリーンショット (269).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2806030/8336adc2-8d60-d771-dcd3-3cd1aafd3e9c.png)

![スクリーンショット (270).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2806030/9779dc2b-ee96-1c68-7148-553043810e93.png)

![スクリーンショット (271).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2806030/c701bcfd-d7d4-ef6e-8728-66067bec9da6.png)
![スクリーンショット (272).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2806030/779922db-820e-955d-73e1-f9c923675f9e.png)


LINEモジュールとGoogle Sheets をくっつけました。

このGoogle Sheetsには自部署でスケジュール管理に使用しているTeamsのシートを元に指定しています。 
そのシートがこちらです。
![スクリーンショット (277).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2806030/4d9c2b40-01d6-e58e-bb1a-83e5e393d71a.png)
A列（日付）で認識し、一致した場合にそれと対応するB列（勤怠情報）を返します。

自分だけ使うのは何だがずるいような気が…。

そこで！

自部署の皆さんにも対応するように、元々Teamsで使用していたシートを活用！
Teams上ではなくこちらのシートに予定を記入するようにしました！
自部署の皆さんからも

**・出先でも簡単に確認できて助かる**
**・自分の携帯で気軽に勤怠を確認できる**


とご意見頂きました！！

共同編集ってすごい、、、


ちなみに、投稿にもある通り、作成する際に試行錯誤しすぎて**Makeのフリープラン上限を超えるという事件が起きました…。**

トライアンドエラー大事ですが、オペレーション数等**フリープランの上限超えないよう**にみなさんお気を付けください…！！！


**最後に**
******
Make自体使うのが初めてだったので、どういったものなのか知りたかった（慣れたかった）ので最初ジブリAPIを元に作ったLINE Botもご紹介します。

フリープラン上限超えた理由の一つ…。

引用：https://ghibliapi.herokuapp.com

中身はこんな感じでシンプルです。

ジブリ作品をLINEで送れば、その作品名やイメージ画像が返ってくるというもの




![スクリーンショット (253).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2806030/3f76de2d-2fdf-ccaa-37d5-f0b1307ffec9.png)

リプライトークンが無効ですのエラー情報にずっと唸っていたとはいえない…。

動いているものがこれです

https://twitter.com/i/status/1567143700190625793

業務でUIPATHを用いてRPAをしているため、調べ物には慣れていたつもりですが

正直Makeを理解するのに、かなり時間かかりました…。

**まだまだ学ぶことがあり楽しいばかりです！！！**

とにかく自部署の皆さんに感謝されてとてもうれしかったです！

まだまだ業務の課題を解決するために考えて作成していこうと思います！！！
ssh 接続で no matching host key type found エラー

ずっと昔の Linux マシンに ssh しようとしたらエラー。

```
$ ssh 192.168.0.5
Unable to negotiate with 192.168.0.5 port 22: no matching host key type found. Their offer: ssh-rsa,ssh-dss
```

# 環境

接続元は Ubuntu 22.04 LTS Ja 版 で

```
$  ssh -V
OpenSSH_8.9p1 Ubuntu-3, OpenSSL 3.0.2 15 Mar 2022
```

でした。

# 背景

https://www.openssh.com/txt/release-8.8
によると、
> Potentially-incompatible changes
> ================================
> 
> This release disables RSA signatures using the SHA-1 hash algorithm
> by default. This change has been made as the SHA-1 hash algorithm is
> cryptographically broken, and it is possible to create chosen-prefix
> hash collisions for <USD$50K [1]
> 
> For most users, this change should be invisible and there is
> no need to replace ssh-rsa keys. OpenSSH has supported RFC8332
> RSA/SHA-256/512 signatures since release 7.2 and existing ssh-rsa keys
> will automatically use the stronger algorithm where possible.
> 
> Incompatibility is more likely when connecting to older SSH
> implementations that have not been upgraded or have not closely tracked
> improvements in the SSH protocol. For these cases, it may be necessary
> to selectively re-enable RSA/SHA1 to allow connection and/or user
> authentication via the HostkeyAlgorithms and PubkeyAcceptedAlgorithms
> options. For example, the following stanza in ~/.ssh/config will enable
> RSA/SHA1 for host and user authentication for a single destination host:
> 
>     Host old-host
>         HostkeyAlgorithms +ssh-rsa
> 		  PubkeyAcceptedAlgorithms +ssh-rsa
> 
> We recommend enabling RSA/SHA1 only as a stopgap measure until legacy
> implementations can be upgraded or reconfigured with another key type
> (such as ECDSA or Ed25519).
> 
> [1] "SHA-1 is a Shambles: First Chosen-Prefix Collision on SHA-1 and
>     Application to the PGP Web of Trust" Leurent, G and Peyrin, T
>     (2020) https://eprint.iacr.org/2020/014.pdf

とあります。


# 一時的な対応
```
$ ssh -oHostKeyAlgorithms=+ssh-dss 192.168.0.5
```
または
```
$ ssh -oHostKeyAlgorithms=+ssh-rsa 192.168.0.5
```
で接続する。

(2023/04/17 追記)

@mizuhof さんよりコメントをいただきました。 @mizuhof 
さんの環境では以下のようにする必要があったそうです 

```
$ ssh -oHostKeyAlgorithms=+ssh-rsa -oPubkeyAcceptedAlgorithms=ssh-dss,ssh-rsa 192.168.0.5
```

@mizuhof さん、ありがとうございました。

(2023/04/07 追記 ここまで)


もし
```
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the DSA key sent by the remote host is
.
.
.
```

というメッセージが出てきた場合は以下のようにして known_hosts から削除します。


```
$ ssh-keygen -R 192.168.0.5
```


# config での対応

リリースノートにあるように ~/.ssh/config 内に
```
Host 192.168.0.5
    HostKeyAlgorithms ssh-dss,ssh-rsa
    PubkeyAcceptedAlgorithms +ssh-rsa
```

と書けば接続できるようになります。
macOS Big Sur：VirtualBoxのホストオンリーアダプタの設定方法

### 環境

- macOS Big Sur 11.6.1
- VirtualBox 6.1.36

### 概要

macOS Big SurでVirtualBoxのホストオンリーアダプタを設定する方法

### 結論

`/etc/vbox/networks.conf` を作成して使用するアドレス範囲を設定する

### 詳細

- VirtualBoxメニューの「ファイル」 > 「ホストネットワークマネージャー」からアダプターを作成
    - アダプターを手動で設定
        - IPv4アドレス：10.0.0.1
        - IPv4ネットマスク：255.255.255.0
    - DHCPサーバー
        - サーバーを有効化にチェック
        - サーバーアドレス：10.0.0.100
        - サーバーマスク：255.255.255.0
        - アドレス下限：10.0.0.101
        - アドレス上限：10.0.0.254
    - 上記設定後に適用ボタン押下

以下のダイアログが表示された

> ホストネットワークインターフェースのパラメーターの保存に失敗しました。
呼び出し先 RC: E_ACCESSDENIED (0x80070005)

### 原因

192.168.56.0/21以外のアドレスを使用するには `/etc/vbox/networks.conf` ファイルを作成し、設定する必要があるらしい

> On Linux, Mac OS X and Solaris Oracle VM VirtualBox will only allow IP addresses in 192.168.56.0/21 range to be assigned to host-only adapters. For IPv6 only link-local addresses are allowed. If other ranges are desired, they can be enabled by creating /etc/vbox/networks.conf and specifying allowed ranges there. For example, to allow 10.0.0.0/8 and 192.168.0.0/16 IPv4 ranges as well as 2001::/64 range put the following lines into /etc/vbox/networks.conf:
https://www.virtualbox.org/manual/UserManual.html#network_hostonly

### 設定方法

```zsh
# ディレクトリの存在チェック
$ sudo ls -la /etc/vbox
ls: /etc/vbox: No such file or directory
# ないので作成する
$ sudo mkdir /etc/vbox
# ファイル作成
$ sudo vi /etc/vbox/networks.conf
# 内容確認
# 頭に "*"をつける
$ sudo cat /etc/vbox/networks.conf 
* 10.0.0.0/8
```

上記実行後、ホストオンリーアダプタの設定ができるようになった

参考

[魴鮄のブログ - VirtualBoxのホストオンリーアダプタの設定方法が変わっていた](https://blog.karky7.com/entry/2021/12/10/virtualbox-hostonly)

[Virtualbox Host-only Adapter 使えるIPレンジが制限されるようになっていてハマった話 - Qiita](https://qiita.com/nfwork01/items/023e0379343a3ce85a34)
【PHP基礎復習9】掛け算と割り算

[問題]
モモさんは毎朝、近所にあるお城のお堀の周りをジョギングしています。
1周Aメートルのお堀をB周した場合、合計何キロメートルになるか求めなさい。

# コード
```PHP
$input_1 = fgets(STDIN);
$input_2 = fgets(STDIN);
echo $input_1 * $input_2 /1000, PHP_EOL;
```

↓　1000、3と入力
# 結果
```
3
```


★何キロメートルかと聞かれているので、1000で割る。
三項演算子で変数を定義する

## はじめに
三項演算子で変数を扱う機会があったので、記事にしました。
サンプルコードでは、admin権限の有無でメッセージ内容を変更させます。

## 三項演算子とは
三項演算子を使うことで、if文のコード量を減らすことができます。
```rb:if文
if user.admin?
  "Hello"
else
  "Hi!"
end
```

```rb:三項演算子
user.admin? ? "Hello" : "Hi!"
```
複雑すぎるif文は三項演算子に向いていません。かえって可読性が低くなります。

## 変数ver

一応、if文も記述しておきます。

```rb
if user.admin?
  message = "Hello"
else
  message = "Hi!"
end
```
<br>

最初に試した三項演算子。
```rb
user.admin? ? message = "Hello" : message = "Hi!"
```
<br>

変数の重複が気になるので以下のように修正しました。
```rb
message = user.admin? ? "Hello" : "Hi!"
```

## あとがき
三項演算子に限った話ではありませんが、リファクタリングの目的は、便利メソッドを使うことではありません。可読性の高いコードを実現させることが目的です。便利メソッドを使うだけで満足するのは注意が必要です。
外部設計書作成時に気をつけてほしいこと。（設計はプロ・ユーザー視点の評価を踏まえたもの）

# 外部設計（基本設計）時に気をつけてほしいこと

外部設計、すなわち、ユーザー視点の設計。
端的にいえば、画面レイアウトであったり、ユーザーがわかるデータ処理定義。

このときに、いちいち言わなくても盛り込んでほしいことがある。
というか、「設計」というのは、ただ端的に分かっている決まり事をドキュメントに記載するだけでなく、
その決められたことが本当に使いやすいものなのか「技術者・ユーザーとして評価」することも含まれると思う。

その「評価」ができる尺度をもっているのが「プロとしての技術者」だと思う。

たとえば、画面レイアウトなんかでも、画面がやたらと長くならないように、できるだけ空白を埋めるとか、そういう配慮が必要だと思う。
とりあえず作ったレイアウトをみて、「これ使った場合、スクロールしないと使えなくて、使いにくいなあ」とか「評価」をすれば、設計をブラッシュアップするはずだと思う。


ということを設計書レビューをしていてつらつらと思いました。
メモ: Java 11でのHTTP(GET)リクエスト


超簡易にHTTPGETリクエストを投げるコードを書き、動作確認したのでメモ。

```
import java.net.http.*;
import java.net.URI;
import java.io.IOException;

class Main {
    public static void main(String[] args) {
       // HttpClient生成
      HttpClient cli = HttpClient.newHttpClient();
      // HttpRequest生成
      HttpRequest req = HttpRequest.newBuilder()
      .uri(URI.create("http://www.google.com"))
      .GET()
      .build();
      // リクエスト送信
      try {
        HttpResponse<String> ress = cli.send(req, HttpResponse.BodyHandlers.ofString());
        System.out.println("ステータスコード: " + ress.statusCode());
        System.out.println(ress.body());
      } catch(Exception e) {
        System.out.println(e);
      }

    }
  }
```

## ステータスコード301について

リクエストURLを"http://google.com" (wwwなし)でリクエストを投げた場合、ステータスコード: 301　が返ってきた。　　

https://developer.mozilla.org/ja/docs/Web/HTTP/Status/301

によると、  
> リクエストされたリソースが Location ヘッダーで示された URL へ完全に移動したことを示します。
プログラミングは人間的な行為


- プログラミングは極めて人間的な行為だ。あなたもプログラミングをしていると何らかの形で感情が波立つのが分かるだろう。
- システム開発は極めて人間的な行為だ。あなたもシステム開発をしていると何らかの形で感情が波立つのが分かるだろう。
- コードがよく分からない時はテストを読もう。もしくはアプリケーションを動かして動作確認をしよう。単純だが効果的な手法だ。
- オライリーの書籍はKindleでは売っていない。オライリー公式サイトから電気書籍を購入することが出来る。まさかこの時代にKindleを選ばない出版社があるなんて。
- MENTAで「スクレイピングを覚えたい」「プログラミング未経験」という単発相談で3000円の募集が出ていた。それにメンターの応募がもう4件もついていた。その値段でよく頑張るなと思った。1時間でプログラミングが覚えられるんだろうか。
- 座禅を組むのは人間の大いなるベースに投資をしていることになる。
- たまに心身が「傷つき疲れてる」って感じになる。
- 実用書では邦書を読まない自分だが、仏教に関しては読む。なぜなら日本人は仏教のプロフェッショナルだからだ。
- スターバックスの隣の席でスーツを着たおじさんがモゴモゴと独り言をいいながらPCのキーボードを叩いている。「あうお、うおーあお、うおおい、あーう」のように聞こえる。彼の会社での立場を知りたい。意外と上役だったりするんだろうか。もしそうだとしたらその会社は終わってると思う。
- スターバックスで若いカップルがその友達とスピーカーホンで話し始めたが。音は大きかったがあまり嫌な感じはしなかった。
- もし子供が生まれたらこう教えて育てよう。「約束は極力守りなさい。もしどうしても守れなければてきとうに理由をでっち上げなさい。もし他人に同じことをされたら叩き殺しなさい」。そんな妄想。
- 新しいジャンルの読書には冊数がかかる。たとえば組織論やマネージメントについて新しく知ろうと思ったら何冊も本を読むことになるかもしれない。
- すべての方法は機能する場合と機能しない場合がある。
- 読書は認知のスポーツだ。
- ブッダは快楽を否定していた(？)にも関わらず座禅が心地よいのはいかがなものだろうか。座禅はブッダにとってのセックスだったのではないだろうか。
- 書籍代の50%はドブに捨てたようなもの。これが投資だ。
- 人類はひっきりなしに問題を起こすことで人生の中身が空洞であることを忘れさせてくれる。


# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ


# Twitter

https://twitter.com/YumaInaura
json_decodeに特定の文字列を入れるとINF（無限）になる

毎週火曜のラブライブだけを生きがいにしてたのに今週は休みと知ってとてつもなく絶望している今日

## 前提

phpにはjson形式の文字列を配列やオブジェクトなどに変換してくれる`json_decode`という関数が存在します。

関数についての細かいことは[省略](https://www.php.net/manual/ja/function.json-decode.php)

このjson_decodeは基本的に非json形式の文字列を入れるとnullを返します。
```php
// NULL
json_decode( 'abcdefg' );
```

また、入力値が整数の場合はint、少数の場合はfloatとして数値が返ってきます。
```php
// int(123456)
json_decode( '123456' );

// int(123456)
json_decode( 123456 );

// float(123.456)
json_decode( 123.456 );
```
ここまでは問題なし。

## 本題
問題なのは入力された文字列が、指数表記として解釈できるとき。（指数表記：`1.0E+10`みたいなやつ）
**json_decodeは指数表記の文字列を受け取った際に自動的にfloatへ変換してしまいます**。
詳しく調べてないけど多分こんな感じ。
- 文字列中にeが1つのみ含まれていて、それ以外の文字が数字のもの
- eの位置が最初または最後ではないもの

例えば、下記の場合は全て問題なく（？）NULLが返りますが、
```php
// 全部NULL
json_decode( 'e1234' );
json_decode( '1234e' );
json_decode( '1e23e4' );
```

下記は指数表記の条件を満たすためfloatに変換された値が出力されます。
```php
// float(1000)
json_decode( '10e2' );

// float(1.0E+308)
json_decode( '1e308' );

// float(INF)
json_decode( '123e456' );
```

面白い挙動なので何故そうなるのか調べようかとも思ったのですが、面倒なので辞めました。
**誰か教えてください。**

## まとめ
json_decodeにわざわざそんな値を入れることはないって？
いやいや、あるかも知れないじゃないですか。
知らんけど
【Java基礎】オブジェクト指向とクラス

# はじめに
最近Java基礎の研修を受けました。学生時代にJavaを授業で習って基礎は身につけていたのですが、忘れていた内容もあったので備忘録として書き残してみます。

この記事では、**Javaの基礎的な内容に関してまとめていきます**。
今回は**オブジェクト指向**と**クラス**です。



# オブジェクト指向
Javaはオブジェクト指向言語と呼ばれるプログラミング言語の1つです。


## オブジェクト指向とは
オブジェクト指向は、「**物（オブジェクト）**」と「**動作（メソッド）**」で表現する手法です。

オブジェクト指向で「車を運転する」ということを表現することを考えてみましょう。
オブジェクトとメソッドは以下のように分けることができます。
| オブフェクト | メソッド |
|:-:|:-:|
| 車、人（運転手） |  前進、後退、ブレーキをかける、クラクションを鳴らす、... |

人オブジェクトが車オブジェクトのメソッドを実行することで車を運転することができます。
このとき、**人オブジェクトは車オブジェクトの中の仕組みを知っている必要はありません。**



## オブジェクト指向のメリット
オブジェクト指向では、人オブジェクトが車オブジェクトの中身を知る必要がないように、**あるオブジェクトは他のオブジェクトの仕組みを知る必要はありません**。これによって、以下のようなメリットがあります。
* 考える範囲が限定できる
* 並行して作業ができる
* 修正による影響範囲が限定できる



# クラスとインスタンス
Javaでは、オブジェクトを**クラス**と**インスタンス**で表します。
* **クラス**：オブジェクトの設計図。オブジェクトが持つ動作（メソッド）を定義する。
* **インスタンス**：クラス（設計図）から作成したオブジェクト。オブジェクトとインスタンスはほぼ同じ意味。

1つのクラス（設計図）から、複数のインスタンスを作成することができます。


## クラスの使い方
クラスを利用するには、以下の手順で利用します。
1. インスタンスを生成する
1. メソッドを呼び出す

1つずつ見ていきます。

### インスタンスを生成する
インスタンスを生成する時は、**コンストラクタ**を呼び出します。
```java:コンストラクタ
new クラス名(引数);
```
コンストラクタを呼び出すことでインスタンスを生成できます。

このインスタンスを利用する時には、クラスの型を持つ変数にインスタンスを代入して利用します。
```java:インスタンスの代入
型名 変数名 = new クラス名(引数);
```

```java:コンストラクタを呼び出す例
// 引数がないコンストラクタを呼び出す
Car audy = new audy();

// 引きすがあるコンストラクタ呼び出す
Person driver = new Person("佐藤");
```

### メソッドを呼び出す
インスタンスを利用してメソッドを呼び出します。
```java:メソッドの呼び出し方
インスタンス.メソッド名(引数);
```

```java:メソッドを呼び出す例
audy.move();
```





# まとめ
オブジェクト指向はどんなものなのかを意識し、イメージを持つことでjavaの書き方やメリットが意識しやすくなると思います。それぞれの言葉の意味は正確に覚えていきましょう。
[Unity]3Dアセットからfbxファイルを取り出してBlenderで開く

# 概要
Unityのアセットにある３DオブジェクトはBlenderで編集することもできます。形を変えたり、色を変えたり。
本格的に修正するにはBlenderの知識が必要になりますが、少しの修正なら意外と手軽にできると思います。
# 本文
このバルーンをBlenderで編集したいと思います。Prefabを画面上に配置して
![スクリーンショット 2022-09-06 20.46.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/d4eb7266-5e8a-73e8-4dc0-b6d724b7fe79.png)
Inspectorを確認します。Meshからfbxファイル、Materialsから色情報ファイルが辿れます。
![スクリーンショット 2022-09-06 20.48.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/81a85065-cb85-5103-b87b-c4d5a386bd9d.png)
## FBXファイル
Meshをクリックしたらfbxファイルの保存ディレクトリが確認できます。
![スクリーンショット 2022-09-06 20.49.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/0f8d72a4-7617-4458-d452-ba8e44b7338d.png)

## 色情報ファイル
Materialsをクリックして表示されたマテリアルファイルをさらにクリックします。
![スクリーンショット 2022-09-06 20.49.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/b9e9fed4-c9e8-179b-b938-1267b21a22a3.png)
InspectorからBaseMapをクリック
![スクリーンショット 2022-09-06 20.49.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/ab848821-579e-947b-dbc7-91d6eef6221b.png)
画像ファイルの保存ディレクトリが確認できます。
![スクリーンショット 2022-09-06 20.55.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/542be92d-2f36-158d-a28b-ba4154c8a944.png)


# Blender
次はBlenderを開いてFile > Import > FBX(.fbx)
![スクリーンショット 2022-09-06 21.19.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/0ef78935-eaa5-ce5e-b31f-e80f53b508dd.png)
先程のディレクトリを辿るとオブジェクトをインポートできます。
![スクリーンショット 2022-09-06 21.22.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/536f7cce-96db-ad42-fd21-adc361b13aa3.png)
Shadingタブを選んだらAdd > Texture > ImageTextureとたどります。
Textureに先程のディレクトリを辿り色情報ファイルを選択すると
![スクリーンショット 2022-09-06 21.25.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/78ac13a5-5e8d-34dd-766b-0b5b7148df7b.png)

色が適用されます（画面右上Viewportの切り替えをお忘れなく）
![スクリーンショット 2022-09-06 21.31.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/ff60e753-f2f1-7140-64ad-4108b2fb80af.png)

# 補足
Blenderで色や形を変更してUnityに戻すこともできます。
![スクリーンショット 2022-09-06 21.53.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/fe30da3a-3c42-5ff0-d731-d85949ac234d.png)

この記事は[この動画](https://www.youtube.com/watch?v=PcmQhqZC_Oo)を参考にして書きました。
鋭角三角形「2022年 近畿大学・医学部(前期) 数学 ［１］」をsympyでやってみた。 

中学生でも解ける大学入試問題？だそうです。

鋭角三角形ABCがあり,AB=13,BC=15...

オリジナル
ますいしい様

https://ameblo.jp/mathisii/entry-12753146729.html

大学入試数学問題集成＞大阪府＞未掲載

https://mathexamtest.web.fc2.com/daigakubetumj/index.html#osaka

# sympyで(ますいしい様の手順で)
```python
from sympy import *
AB=13
BC=15
ADB=CEB=90         #????
BD=Rational(1,3)*BC
CD=Rational(2,3)*BC
AD=sqrt(AB**2-BD**2)
print("#(1)ア",AD)
AC=sqrt(AD**2+CD**2)
print("#(1)イ",AC)
CH=Rational(13,12)*CD
print("#(2)ウ",CH)
BE=Rational(5,13)*BC
AE=AB-BE
print("#(2)エ",BE/AE)
DH=Rational(5,12)*CD
AH=AD-DH
print("#(2)オ",AH/DH)
print("#(2)カ",Rational(1,2)*sqrt(BD**2+DH**2))
#(1)ア 12
#(1)イ 2*sqrt(61)
#(2)ウ 65/6
#(2)エ 75/94
#(2)オ 47/25
#(2)カ 5*sqrt(61)/12
```

# sympyで(Point2Dで)
```python
from sympy import *
var('t')
A=Point(13.0*cos(t),13.0*sin(t))
B=Point( 0.0,0.0)
C=Point(15.0,0.0)
D=B+Rational(1,3)*(C-B)
ans=solve(Eq((B+Rational(1,3)*(C-B)).x,(Line(B,C).projection(A)).x),t)[1]
A=A.subs({t:ans})
print("#(1)ア",A.distance(D))
print("#(1)イ",A.distance(C))
E=Line(A,B).perpendicular_line(C).intersection(Line(A,B))[0]
H=Line(A,D).intersection(Line(C,E))[0]
print("#(2)ウ",C.distance(H))
print("#(2)エ",B.distance(E)/A.distance(E))
print("#(2)オ",A.distance(H)/D.distance(H))
Ci=Circle(B,D,H)
if Ci.args[0].distance(H)==Ci.args[1]:
   print("#(2)カ",Ci.args[1],"同一円周上にある。")
else:
    print("#(2)カ","同一円周上にない。")
#(1)ア 12
#(1)イ 2*sqrt(61)
#(2)ウ 65/6
#(2)エ 75/94
#(2)オ 47/25
#(2)カ 5*sqrt(61)/12 同一円周上にある。
```

# 参考
英進館メビオ様

https://www.mebio.co.jp/files/answer/2022/M_kindai_2022A.pdf
Railsのクラスメソッドについて考える

# 本題
- Railsで書いてるとクラスメソッドでいろいろやりがちにならない？と思ったので解決策を考える。

### ファーストクラスコレクション　
[良いコード、悪いコードで学ぶ設計入門](https://www.amazon.co.jp/%E8%89%AF%E3%81%84%E3%82%B3%E3%83%BC%E3%83%89%EF%BC%8F%E6%82%AA%E3%81%84%E3%82%B3%E3%83%BC%E3%83%89%E3%81%A7%E5%AD%A6%E3%81%B6%E8%A8%AD%E8%A8%88%E5%85%A5%E9%96%80%E2%80%95%E4%BF%9D%E5%AE%88%E3%81%97%E3%82%84%E3%81%99%E3%81%84-%E6%88%90%E9%95%B7%E3%81%97%E7%B6%9A%E3%81%91%E3%82%8B%E3%82%B3%E3%83%BC%E3%83%89%E3%81%AE%E6%9B%B8%E3%81%8D%E6%96%B9-%E4%BB%99%E5%A1%B2-%E5%A4%A7%E4%B9%9F-ebook/dp/B09Y1MWK9N/ref=sr_1_1?crid=YW033JRN5MR&keywords=%E8%89%AF%E3%81%84%E3%82%B3%E3%83%BC%E3%83%89%2F%E6%82%AA%E3%81%84%E3%82%B3%E3%83%BC%E3%83%89%E3%81%A7%E5%AD%A6%E3%81%B6%E8%A8%AD%E8%A8%88%E5%85%A5%E9%96%80&qid=1662465642&sprefix=%E8%89%AF%E3%81%84%E3%82%B3%E3%83%BC%E3%83%89%2Caps%2C228&sr=8-1)という本を最近読んで、ファーストクラスコレクションという物があることを知りました。
今までrailsのみで開発をしてきたので、こんな書き方があるんだなーと思いました。
それと同時に **Railsのクラスメソッドでいろいろやりすぎ??**　という疑問が浮かびました。

#### 原因
`ActiveRecord::Relation` がクラスメソッドを実行できるのでそうなりがちなのでは？と思いました。
User modelが存在すると仮定して、APIでユーザーの名前、年齢を返すAPIを想定します。

```ruby
# app/models/user.rb
class User < ActiveRecord::Base
  scope: otona, -> { where('age >= 18') }

  def self.name_and_age
    all.each_with_object([]) { |user, result|
      result << { name: user.name, age: user.age }
    }
  end
end

# app/controllers/api/users_controller.rb
class UsersController < ApplicationController
  def index
    render json: { users: User.otona.name_and_age }
  end
end
```

ここで違和感が発生します。
`User#name_and_age` がUserクラスに存在する違和感、つまり、これってUsersクラスで良くない？ってことです。
Userクラスはあくまでそのクラスのインスタンスである1ユーザーのことに集中すべきで、そうすることで責務も適切に分けることができそうな気がします。
以下のように変更してみます。
```ruby
# app/models/users.rb
class Users
  def initialize(users)
    @users = users
  end
  
  def name_and_age
    @users.each_with_object([]) { |user, result|
      result << { name: user.name, age: user.age }
    }
  end
end

# app/controllers/api/users_controller.rb
class Userscontroller < ApplicationController
  def index
    render json: { users: Users.new(User.otona).name_and_age }
  end
end
```

パッと見た感じ良い感じに責務を分けれたように思えます。
ただ、こんな単純な場合ではなく、Usersクラスの中で `@users.includes(....)` などすることは考えられるため、ActiveRecord::Relationをnewする時に渡す、という使い方になりそうな気がします。そうなると、ただクラスメソッドを別のクラスに移しただけでは？というような気もしてきますよね。

## 最後に
Railsで開発しているとオブジェクト指向を意識する機会が少ないのかもしれないと思ってきました。有識者の皆さんの意見をお待ちしてます！
人事のおじさんプログラミングを学ぶ Day12「オブジェクトとCSSを使ってアイテム情報をテーブルで表示」

書籍『確かな力が身につくJavaScript「超」入門 第2版』に沿って、
オブジェクトとCSSを使って、アイテムの在庫をテーブルで表示してみた。
学習過程で書いたコードはコメントアウトして残した（コメントアウトの練習のため）。
![2022-09-06 (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2783084/ae660ade-127f-4f15-84dc-97898756cb31.png)
![2022-09-06 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2783084/dd230684-35bb-338b-a944-25c8ffad67cf.png)
![2022-09-06 (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2783084/947eef57-60ee-8775-4a02-a4cc49b1e395.png)
【VSCode】latexmkrcのラクダアイコンを出す方法

# 環境について

この記事は、筆者が mac ユーザーのため mac の VSCode を前提として書いています。windows では仕様が異なる可能性があります。

# ラクダを出す
VSCode で latexmkrc ファイルを作ると、同じ latexmkrc でも「アイコンがラクダになる + syntax highlight が効く」ものとそうでないものがありました。上がラクダアイコン、下がノーマルなファイルのアイコンです。

![SS_2022-09-05_20-49-20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823185/3f9fffd5-2b29-8801-fdae-1f2c069cf640.png)
![SS_2022-09-05_20-48-54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823185/4218c4b5-963f-ed48-88d6-cff4f373b561.png)

この違いは長らく謎でしたが、ラクダアイコンがなくても`latexmkrc`としてコンパイルには問題なく使えるので放置していました。

それが最近事情あって`latexmkrc`をいじりまくっているときにようやく判明しました。どうやら先頭にマジックコメントとして`#!/usr/bin/env perl`というのをつけた後、一回`latexmkrc`を閉じてまた開くと`perl`のファイルと判断されることによってラクダアイコンと syntax highlight がつくようです。

![SS_26.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823185/1088daaa-5299-974d-15d4-b492ea41aea1.gif)

ちなみに先頭に`.`をつけてもつけなくても構いません。逆にラクダにしようとするあまりファイル名を`latexmkrc.pl`などとするとラクダになる代わりにコンパイルで使えなくなるようです。

ラクダマークが無事についたので幸せになれました。

# もっと手っ取り早い方法（追記）

記事を書いた後、もっと簡単な方法があることに気づきました。要するに`perl`のファイルと認識してもらえばよいので、`settings.json`で以下のようにします。

```json:settings.json
{
    "files.associations": {
    		"latexmkrc": "perl"
    	},
}
```
すると`latexmkrc`を閉じたり開いたりしなくても、最初からラクダアイコンが表示されて syntax highlight が効くようになります。


# さらに追記

ホームディレクトリに入れるlatexmkrcについてはドットをつけないといけないようです。
【Live2D】パラメータのつまみをキーに合わせる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2704221/a6b78da7-5989-88e3-f79a-35a3c2a83383.png)

「キーの近くで右クリック」をすることで、一番近いキーにつまみが移動する。
キーとキーの中間で行った場合は、真ん中より近い方のキーに移動する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2704221/3cc5ca79-23bf-dce6-09df-1d000849f3b1.png)


動きの確認をするときなどでパラメータをいじり、それから調整に戻る場面は多いはず。
しかし、つまみをドラッグしてパラメータを動かした後、キーにぴったり合わせるために値を入力を都度行うのも地味に面倒なので、これに気付いてからは作業がちょっと楽になりました。
（ズレを無視してデフォーマなどの操作を行えば勝手にキーの位置まで戻る動作もあるが、複数のパラメータを絡めた動作が完璧とは限らないし意図していない状態での操作もあり得るなど、やはり事故の元なのでよろしくない気がする）
【PHP基礎復習8】絶対値

[問題]
次の入力値の絶対値を求めよ。

# コード
```PHP
$input = fgets(STDIN);
echo abs($input),PHP_EOL;
```

↓　－4と入力

# 結果
```
4
```


☆絶対値を求める
→　abs(　)