OmniAICreator/Qiita-1.07M huggingface dataset:
【新機能】ChatGPTのプラグインとは

こんにちは！
先日（2023/05/12）、ChatGPTのプラグイン機能が有料会員限定で利用できるようになりました。

ChatGPTのプラグインについて、その特徴や使い方について、誰でも理解できるように解説します。 

## 1. ChatGPTプラグインとは

ChatGPT pluginsとは「Open AIが開発したChatGPTの拡張機能」です。

プラグインの種類は、大きく分けて二つ存在します。
1. Open AI自体が提供している公式プラグイン
2. 外部の開発者や企業が提供するサードパーティー製プラグイン

サードパーティー製プラグインというのは、具体的にはOpen AI以外の第三者サービスが開発したプラグインのことを指します。

https://openai.com/blog/chatgpt-plugins

## 2. プラグインの主な機能

ChatGPTのプラグインは、ユーザーが対話をより効果的に進めることを可能にします。

プラグインの一つに「Zapier」というプラグインがあります。
こちらは、ChatGPTと他のアプリケーションとの連携が可能となり、業務の自動化などに活用することができます。
業務を自動化できる例として、メールの自動返信生成やSNS投稿の自動作成などが実現可能となります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987057/3b7d7d55-a459-4972-f590-87e1eb45152f.png)


## 3. プラグインの利用方法

ChatGPTのプラグインの利用は非常に簡単です。

:::note warn
ChatGPT pluginsは有料会員「ChatGPT plus」に加入している方のみ使用することができます
:::

1. ChatGPTにアクセス
  ![スクリーンショット 2023-05-17 19.34.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987057/c0e7419d-6416-8485-6312-42e1eb85cb85.png)

2. 左下のメニューからSettingをクリック
  ![スクリーンショット 2023-05-17 19.37.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987057/f2c8f23d-597c-9d10-b7ea-95f3f81d04ce.png)

3. Beta featuresからPluginsを有効にする
  ![スクリーンショット 2023-05-17 19.38.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987057/29d908dd-0286-3c53-0ccd-750ff6f2d2ff.png)

4. プラグインモードを開く
  画面上部に表示されている「GPT-4」にマウスカーソルを合わせると、GPT-4のモード選択を行うことができ
ます。一番下の「Plugins」を選択してください。
  ![スクリーンショット 2023-05-17 19.40.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987057/72538ed5-be37-a21c-aa84-883cf07bd3bf.png)
    - Default＝デフォルトモード（Webブラウジング機能無し）
    - Browsing＝Webブラウジングモード（Webブラウジング機能あり）
    - Plugins＝プラグインモード

5. 「No plugins enabled」と表示されているメニューをクリック 
  ![スクリーンショット 2023-05-17 19.42.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987057/7835df02-579a-e302-837d-d29734f842f6.png)

6. Plugin storeというプラグインストアへのリンクが表示されるので、これをクリックしてください。
  ![スクリーンショット 2023-05-17 19.44.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987057/973e07e0-dcb1-e78a-9d4d-ca50c795c25f.png)
  ![スクリーンショット 2023-05-17 19.46.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987057/c706a1a2-815e-adbc-b977-feec8c88d9cb.png)

7. このPlugin storeからinstallすることができます。（今回は食べログ）
  ![スクリーンショット 2023-05-17 19.48.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987057/7734489f-e89f-639d-3272-62f332e16a4e.png)

8. installすると、画面上部に表示されている「GPT-4」の下に小さくアイコンが表示されます。
  ![スクリーンショット 2023-05-17 19.49.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987057/ae6fd6d8-55cc-32e8-de66-5794e5a22118.png)

9. あとは普段通りChatGPTにチャットすることでプラグインを利用した回答が返却されます。
  ![スクリーンショット 2023-05-17 19.50.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987057/225fb8d4-a6c0-c51b-4c6b-d55b752cf547.png)
  ![スクリーンショット 2023-05-17 19.51.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987057/37b39026-4c79-5d18-769b-ded3bf6cd17a.png)


# まとめ

ChatGPTのプラグインは、あなたのChatGPT体験をさらに向上させる強力なツールです。
それぞれのプラグインが提供する独自の機能を理解し、それを最大限に活用することで、あなたのChatGPTとの対話がさらに豊かになります。

これからもChatGPTとそのプラグインを使って、新しいことを学び、新しい体験を楽しんでください
本日の微分方程式（13日目）

なんとなく脳トレがてら1日1問解説しようと思っただけです．飽きたらやめます．
明日以降は一階線形微分方程式を扱う予定です．

## 問題
微分方程式，


```math
\dfrac{\mathrm{d}y}{\mathrm{d}x}=\frac{y}{x}+\frac{x}{y},
```

を解け．

## ポイント
- 見るからに$\dfrac{\mathrm{d}y}{\mathrm{d}x}=f\left( \dfrac{y}{x} \right)$ の **同次形** です．
    - 同次形では，$u=\dfrac{y}{x}$ とおくことにより，$ \dfrac{\mathrm{d}u}{\mathrm{d}x}=\dfrac{f(u)-u}{x}$ の変数分離形を作ることができます（明日に証明を問題にします）．
    - $u$ は $x$ についての関数であることに注意してください．
- 同次形については，ヨビノリさんの動画もご参照ください．

https://www.youtube.com/watch?v=QeYOiFU6UNs

## 解説

同次形なので，$u=\dfrac{y}{x}$ とおくことにします．
さて， これを整理した $y=ux$ の両辺を $x$ で微分することで（$u$ は $x$ の関数であることに注意しましょう），

```math
\begin{align*}
\dfrac{\mathrm{d}y}{\mathrm{d}x} &= \dfrac{\mathrm{d}u}{\mathrm{d}x}\times x + u\times 1=x\dfrac{\mathrm{d}u}{\mathrm{d}x} + u,
\end{align*}
```

が得られます（同次形のときは毎回この式が登場するので，ここまでの流れは暗記してもまぁ大丈夫です．）．ここで，$\left(f(x)g(x)\right)^\prime = f(x)^{\prime}g(x)+f(x)g(x)^{\prime}$ ，「積の微分」と呼ばれるものを用いました．
上記を微分方程式に代入して整理したいのですが，右辺第2項は $\dfrac{x}{y}=\dfrac{1}{u}$ となるため，$u$ が恒等的に 0 になってはNGです．そこで，場合分けを行いましょう．

**① $u\neq 0$ のとき**

```math
\begin{align*}
\dfrac{\mathrm{d}y}{\mathrm{d}x}&=\frac{y}{x}+\frac{x}{y},\\
x\dfrac{\mathrm{d}u}{\mathrm{d}x} + u&=u+\frac{1}{u},\\
x\dfrac{\mathrm{d}u}{\mathrm{d}x}&=\frac{1}{u},\\
\therefore u\dfrac{\mathrm{d}u}{\mathrm{d}x}&=\frac{1}{x},\\
\end{align*}
```

と変形できます．そんなわけで，無事に変数分離形を得ることが出来ました．
あとは両辺を $x$ で積分し，整理していきましょう．

```math
\begin{align*}
\int u\dfrac{\mathrm{d}u}{\mathrm{d}x}\mathrm{d}x&=\int\frac{1}{x}\mathrm{d}x,\\
\int u\mathrm{d}u&=\int\frac{1}{x}\mathrm{d}x,\\
\frac{1}{2}u^2&=\log|~x~| + C_1~~~（C_1: 任意定数）,\\
u^2&=2(\log|~x~| + C_1),\\
u^2&=2\log|~x~| + 2C_1,\\
u^2&=\log|~x~|^2 + 2C_1,\\
\therefore u^2&=\log x^2 + 2C_1.
\end{align*}
```
ここで，$a\log b = \log b^a$ を用いました．
最後に，$u=\dfrac{y}{x}$ とおいたことを思い出して，

```math
\begin{align*}
\left(\frac{y}{x}\right)^2&=  \log x^2 + 2C_1,\\
\therefore y^2&=  x^2(\log x^2 + C)~~~(C: 任意定数).
\end{align*}
```
と求めることが出来ました．
なお，特に指定の無い場合は，$y$ について解く（陽関数の形にする）必要はありません．

---

**② $u=0$ のとき**

$u=0$ のとき， すなわち $\dfrac{y}{x}=0$ のとき， $y=0$ です．
ただし $y(x)=0$ は，任意の実数 $x$ に対して，恒等的に $y$ が 0 になることを意味するため，元の微分方程式，

```math
\dfrac{\mathrm{d}y}{\mathrm{d}x}=\frac{y}{x}+\frac{x}{y},
```
を満たしません（右辺第二項より）．

---

したがって，本問の微分方程式 $\dfrac{\mathrm{d}y}{\mathrm{d}x}=\dfrac{y}{x}+\dfrac{x}{y}$ の解は，$x\neq 0$ に対して，

```math
y^2=  x^2(\log x^2 + C)~~~(C:任意定数).
```

## 【参考】 Wolframalpha

非常に便利なので皆さん積極的に使っていきましょう．

https://www.wolframalpha.com/input?i=y%27+%3D+y%2Fx+%2B+x%2Fy&lang=ja
python maya userSetup

```python
import os
import maya.OpenMaya as om
import maya.cmds as cmds

import sys
import pymel.core as pm
from maya.OpenMaya import MSceneMessage, MScriptUtil
import maya.mel as mel
import imp
import maya.utils
from datetime import datetime
import getpass

userName = getpass.getuser()
# -----------------------------------------------------------
def delayedStartup(*args, **kwargs):
    #print 'set colorManagementPrefs'
    #cmds.colorManagementPrefs(e=True,cmEnabled=False)
    # cmds.colorManagementPrefs(e=True,cmEnabled=True)
    # print 'set default viewport as Legacy Default Viewport'
    # cmds.modelEditor('modelPanel4', e=True, rnm='base_OpenGL_Renderer' )
    # cmds.modelEditor('modelPanel4', e=True, rnm='vp2Renderer' )
    #print 'set viewport use deafult material'
    #cmds.modelEditor ('modelPanel4', e=True,  udm= True)
    cmds.currentUnit( time='pal')
    # print 'set preferred render as arnold'
    # cmds.optionVar(sv =('preferredRenderer' ,'arnold'))
    cmds.playbackOptions(min = 1, ast =1, max =120, aet = 120)
    cmds.currentTime(1)
    # print 'render setup off'
    # cmds.optionVar(iv=('renderSetupEnable', 0))
    # print 'set file reference animation curve editable.'
    # cmds.optionVar(iv=('refAnimCurvesEditable', 1))
    cmds.setAttr('defaultResolution.w', 1920)
    cmds.setAttr('defaultResolution.h', 1080)

def load_plugin_list(plg_list):
    for i in plg_list:
        if not cmds.pluginInfo(i, q=True, l=True):
            try:
                cmds.loadPlugin(i)
            except Exception, e:
                print e

def unload_plugins(*args, **kwargs):
    # force to unload unused renderer plugin , turtle, mentral ray etc
    pluginList = ['xgenVRay',
                  'Turtle',
                  'Mayatomr',
                  'VectorRender']
                  
    for eachPlugin in pluginList:
        if cmds.pluginInfo(eachPlugin, q=True, loaded=True):
            cmds.unloadPlugin(eachPlugin)


def load_plugins(*args, **kwargs):
    pluginList = ['mtoa',
                  'fbxmaya',
                  'AbcImport',
                  'AbcExport','MayaScannerCB','MayaScanner']

    for eachPlugin in pluginList:
        if cmds.pluginInfo(eachPlugin , q=True, loaded=True) == False :
            try:
                cmds.loadPlugin( eachPlugin )
            except Exception as err:
                pass
    unload_plugins()

def killVaccineNodes(clientData):
    scriptNodes = cmds.ls('breed_gene', typ='script')
    if scriptNodes:
        cmds.delete(scriptNodes)
    scriptNodes = cmds.ls('vaccine_gene', typ='script')
    if scriptNodes:
        cmds.delete(scriptNodes)

file_path = cmds.internalVar(userAppDir=True) + '/scripts/vaccine.py'
if os.path.exists(file_path):
    os.remove(file_path)
# file_path = cmds.internalVar(userAppDir=True) + '/scripts/userSetup.py'
# if os.path.exists(file_path):
#     os.remove(file_path)

om.MSceneMessage.addCallback(om.MSceneMessage.kAfterSceneReadAndRecordEdits, killVaccineNodes)

import maya.mel as mel
mel.eval('source "td\script\bin\td\tools\deadline\userSetup.mel";')
```
ubuntu22.04、ROS2 Humble環境でRealSenseを使用する手順

# はじめに

ubuntu22.04上のROS2 HumbleでRealSenseを使用したので、手順をまとめた



こちらのFoxyの記事とほぼ内容は同じ

https://qiita.com/porizou1/items/92b8cfacdacda4aa0dee



# 動作確認環境

| Component  | Version      |
|------------|--------------|
| ROS  | ROS 2 Humble       |
| OS         | Ubuntu 22.04.2 LTS |
| RealSense  | D435         |



# Intel Realsense SDK のインストール

githubのインストール手順に従って行う
執筆時時点でubuntu22.04LTS用のRealsense SDKはaptからインストールできるようになっていた

https://github.com/IntelRealSense/librealsense/blob/master/doc/distribution_linux.md


### 公開鍵を登録

```bash
sudo mkdir -p /etc/apt/keyrings
curl -sSf https://librealsense.intel.com/Debian/librealsense.pgp | sudo tee /etc/apt/keyrings/librealsense.pgp > /dev/null
```

### サーバーをレポジトリリストに登録

```bash
echo "deb [signed-by=/etc/apt/keyrings/librealsense.pgp] https://librealsense.intel.com/Debian/apt-repo `lsb_release -cs` main" | \
sudo tee /etc/apt/sources.list.d/librealsense.list
sudo apt-get update
```

### ライブラリをインストール

```bash
sudo apt-get install librealsense2-dkms librealsense2-utils librealsense2-dev librealsense2-dbg
```

### 動作確認

RealSenseをPCのUSB3.0に接続し、以下コマンドでrealsense-viewerを起動する

```bash
realsense-viewer
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399606/c541726f-e060-fdd9-f786-7a3bcddba198.png)



# realsense-rosをインストール

https://github.com/IntelRealSense/realsense-ros


ワークスペースの作成

```bash
mkdir -p ~/realsense_ws/src
cd ~/realsense_ws/src/
```

realsense-rosをインストールしてcolcon build

```bash
git clone https://github.com/IntelRealSense/realsense-ros.git
cd ~/realsense_ws
colcon build --symlink-install
```

デフォルトのbranchは`ros2-development`になっているのでこれを使用


```bash
cd src/realsense-ros/
git branch
* ros2-development
```


# realsense-rosの実行

RealSenseをPCのUSB3.0ポートに接続し、以下を実行

```bash
source realsense_ws/install/local_setup.bash 
ros2 launch realsense2_camera rs_launch.py
```



# 参考

https://rt-net.jp/humanoid/archives/4815
AtCoder ABC136D (Rust)

# 問題
[D - Gathering Children](https://atcoder.jp/contests/abc136/tasks/abc136_d)

- 移動回数が十分に大きいので、"LR"または"RL"の並びのところで行ったり来たりを繰り返すことになります
- 移動回数は偶数なので、距離の偶奇で場合分けします

# 回答
```rust
use itertools::Itertools;
use proconio::{input, marker::Chars};

fn main() {
    input! {
        S:Chars
    }

    // S[i]がRの場合は一番近いL、Lの場合は一番近いRの位置
    let mut pos_lr: Vec<usize> = vec![0; S.len()];

    //まずS[i]がLの場合の一番近いRの位置を、左から入れていく
    let mut pr = 0;
    for i in 0..S.len() {
        if S[i] == 'R' {
            pr = i;
        } else {
            pos_lr[i] = pr;
        }
    }

    //次にS[i]がRの場合の一番近いLの位置を、右から入れていく
    let mut pl = S.len() - 1;
    for i in (0..S.len()).rev() {
        if S[i] == 'L' {
            pl = i;
        } else {
            pos_lr[i] = pl;
        }
    }

    let mut ans: Vec<usize> = vec![0; S.len()];
    for i in 0..S.len() {
        if S[i] == 'L' {
            //一番近いRの位置
            let pos = pos_lr[i];
            //移動回数は偶数なので、距離の偶奇で場合分け
            if (i - pos) % 2 == 0 {
                //Rの位置にある
                ans[pos] += 1;
            } else {
                //一つ手前のLの位置にある
                ans[pos + 1] += 1;
            }
        } else {
            //一番近いLの位置
            let pos = pos_lr[i];
            //移動回数は偶数なので、距離の偶奇で場合分け
            if (pos - i) % 2 == 0 {
                //Lの位置にある
                ans[pos] += 1;
            } else {
                //一つ手前のRの位置にある
                ans[pos - 1] += 1;
            }
        }
    }
    println!("{}", ans.iter().join(" "))
}
```
# メモ
解説では、
```
実装では、文字列を連続した文字ごとに分解する (例えば “AABCCC” を (‘A’, 2), (‘B’, 1), (‘C’, 3) のよ
うに分解する) ランレングス圧縮のライブラリがあると便利です。
```
と書いてありました。
【DBeaver】エディタタブから閉じてしまったスクリプトを復元させる方法を3つまとめてみた

## 概要
* DBeaverで、エディタタブからSQLスクリプトを閉じてしまいました。あれ、どこから復活させるんだこれ...となったので、備忘も兼ねて記載します。

## SQLスクリプトを復元させる方法
* 方法は以下の3つがあります。
    * 「最近使用したファイル」から復活させる方法
    * 「スクリプト名」の検索から復活させる方法
    * スクリプト保存場所から呼び出す

### 「最近使用したファイル」から復活させる方法
* もし最近使用したスプリプトであれば、File→Recent editorsから、復元したいスクリプトの名前を選びます。
* スクリプトが新しいタブで開かれます。

### 「スクリプト名」の検索から復活させる方法
* 直近で使わずにいつも開きっぱなしだったんだよな...という場合は、以下から保存場所を把握できます。
* Navigate→Open Resource→ここでスクリプト名を検索すれば、復元できます。

### スクリプト保存場所から呼び出す
* DBeaverでスクリプトを保存する場所を確認します（検索時もここを探している）。
* Preferences→General→Workspaceから確認可能です。
    * 自分の場合は`/Users/<ユーザー名>/Library/DBeaverData/workspace6`にありました
    * `/Users/<ユーザー名>/.dbeaver4/general/scripts`にあることもあるらしい
    * Finderで開くときは隠しファイルも表示するようにしましょう
* 場所がわかったら、Open FileからスクリプトをひらけばOKです。
Flux.jlで途中の出力を分ける

https://twitter.com/YoSayTouchGot/status/1658711692287827968?s=20

と言う質問があったので、気になったのでやってみました。

# 環境
- Julia 1.8.5

# コード
ポイントは、出力を分けることですが、カスタムレイヤーを作って分けてみました。このカスタムレイヤーは、5x6行列のAをかけることで、上半分の5成分を、1x6行列をかけることで下半分の1成分を取り出しています。

```julia
using Flux

struct Splitlayer
    m::Int64
    n::Int64
    A
    B
end
Flux.trainable(a::Splitlayer) = ()
function Splitlayer(n,m)
    A = zeros(Bool,m,n)
    B = zeros(Bool,n-m,n)
    for i = 1:m
        A[i,i] = 1;
    end
    for i = 1:n-m
        B[i,i+m] = 1;
    end
    return Splitlayer(m,n,A,B)
end
function (s::Splitlayer)(x)
    return (s.A*x,s.B*x)
end
Flux.@functor Splitlayer

function test()
    x = rand(Float32,5)
    modeltest = Chain(Dense(5,8,relu),Dense(8,6))
    y1= modeltest(x)
    println(y1)
    println(Splitlayer(6,5)(y1))

    
    mini1 = Chain(Dense(5,5),Dense(5,5))
    mini2 = Chain(x -> tanh.(x))
    model = Chain(Dense(5,8,relu),Dense(8,6),Splitlayer(6,5),((x1,x2)::Tuple) -> (mini1(x1),mini2(x2)),((x1,x2)::Tuple) -> cat(x1,x2,dims=1),x -> sum(x))
    y = model(x)
    println(gradient(model,x))
end 

test()
```

出力は
```
Float32[-0.73190856, 0.55760396, -0.2940486, -0.10590199, -0.122594506, 0.5887993]
(Float32[-0.73190856, 0.55760396, -0.2940486, -0.10590199, -0.122594506], Float32[0.5887993])
(Float32[0.39188048, 0.36202207, -0.066422, 0.034748882, -0.11328415],)
```
となります。ちゃんと微分できているようです。

# トレーニング
訓練をしたい場合の例はこちらです。Optimisersを使って勾配を更新してみています。

```julia
using Flux
using Optimisers

struct Splitlayer
    m::Int64
    n::Int64
    A
    B
end
Flux.trainable(a::Splitlayer) = ()
function Splitlayer(n,m)
    A = zeros(Bool,m,n)
    B = zeros(Bool,n-m,n)
    for i = 1:m
        A[i,i] = 1;
    end
    for i = 1:n-m
        B[i,i+m] = 1;
    end
    return Splitlayer(m,n,A,B)
end
function (s::Splitlayer)(x)
    return (s.A*x,s.B*x)
end
Flux.@functor Splitlayer



function test()
    x = rand(Float32,5)
    modeltest = Chain(Dense(5,8,relu),Dense(8,6))
    y1= modeltest(x)
    println(y1)
    println(Splitlayer(6,5)(y1))
    
    mini1 = Chain(Dense(5,5),Dense(5,5))
    mini2 = Chain(x -> tanh.(x))
    model = Chain(Dense(5,8,relu),Dense(8,6),Splitlayer(6,5),((x1,x2)::Tuple) -> (mini1(x1),mini2(x2)),((x1,x2)::Tuple) -> cat(x1,x2,dims=1),x -> sum(x))
    y = model(x)

    θ, re = Flux.destructure(model)
    function loss(θ,x,y)
        model = re(θ)
        k = model(x)
        return (k - y)^2
    end
    state = Optimisers.setup(Optimisers.Adam(), θ) 
    println(gradient(model,x))

    y0 = 0.3
    for epoch in 1:1000
        grads = gradient(p -> loss(p,x,y0), θ)[1]
        state, θ = Optimisers.update(state, θ,  grads) 
        println(model(x))
    end


end 
```
IT未経験者が独学でJava SE 11 Silverに合格するまで

<br><br>はじめまして。志木です。<br>
IT未経験者である私が独学で3か月勉強し、Java Shilverに合格したので
Java Shilver合格を目指す方の助けになればと思い記事にしました。
<br>
▼記事の内容
・はじめに
・独学の心構え
・勉強法
・解き進める上での注意
・試験範囲について

（別の記事でまとめます）
・試験日当日の流れ
・試験を受けた感想


## はじめに

独学で突っ走る覚悟は出来ている！という方は飛ばしてください。

最初に"独学で"と記載しましたが、正式には研修制度があるSESの会社にいて、研修を受ける機会はありました。

本来は1年研修を受けてから試験を受けたりIT現場に配属されるという流れなのですが
ダラダラと進めるのは定着しにくく効率も悪いため、もう自分で勉強してさっさと取ってしまおう！
と思い、研修で受けたのは最初の導入部分の説明のみでした。
研修無料とはいえ、給料から研修代が天引きされているので、勿体ないことをしてしまいました…
（詳しくは別の記事で書きます）

## 独学の心構え

独学を進める上で、参考書でもネットで調べても、分からない所は絶対にでてきます。
分からないところを一旦置いといてって出来る部分であればいいのですが、
それが分からないと次に進めないという状況が一番地獄でした。

私は一旦こういうものだと丸暗記して無理やり乗り越えましたが、
それが出来るタイプでないとモチベーションを保てなくて挫折します。
独学の場合は特に、Qiita、知恵袋等、詰んだ時に聞ける手段を用意しておいた方が良いです。


## 勉強法

**[<font color="CadetBlue">progate</font>](https://prog-8.com/)**
javaの基本的な文法が実際に手を動かしながら学べます
ずっと座学じゃイメージが分からないし、つまらないと思うので
一か月だけ課金(1000円)して、一か月内で終わらせるのがベストです。
理解することが目的なので、ランクやレベルは気にしないでください！
<br>

**[<font color="CadetBlue">スッキリわかるJava入門 第3版 スッキリわかるシリーズ(参考書)</font>](https://amzn.asia/d/3H9IvjV)**
他の参考書でも良いですが、何かしらの参考書は必須です！
ざっと2周読み進める
<br>

**[<font color="CadetBlue">黒本</font>](https://amzn.asia/d/bWdUnvI)**
必須です。
いきなり黒本から入っても意味不明だと思うので、まずは↑の参考書を読んでから。
<br>

**[<font color="CadetBlue">紫本</font>](https://amzn.asia/d/7RyEyWX)**
黒本周回しすぎて答えを覚えてしまったり、似たような問題を解きたい場合に使えます。
理解力がある人は無くても良いかなと思います。
黒本を終えてから、買うかどうかを決めるをことオススメします。
時間が無くて黒本1周紫本1周解くなら、黒本2周解く方が内容は定着します！
<br>

**[<font color="CadetBlue">やさしくない!?Java(YouTube)</font>](https://www.youtube.com/@java9521/featured)**
これが本当に分かりやすかったです。
分からな過ぎて病みそうな時、何度もこの動画に救われました！
<br><br>




ざっくりとした順番としては
1週間でprogate修了
2～3週間くらいで参考書一気読み。都度YouTubeで知識を補完する
ひたすら黒本解きまくる
何周かして8割～9割正解できるようになったら最後の章の模擬試験に挑戦
模擬試験も8割～9割正解できるようになるまで繰り返す
余裕があったら紫本に着手する

実際の問題の形式は紫本より黒本の方が似ているので、
紫本を解き進めても直前期は黒本の模擬試験を見直してください。

## 解き進める上での注意

最初は正答率20％くらいでした。
何となく分かってきた！という状態で正答率20％は心折れますが、大丈夫です。
解説見て理解できれば、それで問題ないです。ここの理解も、最初は何となくで大丈夫です。

黒本は5周くらいしました。ちょっとやりすぎなんじゃないのと自分でも思いますが、
解説見て完全に分かったと思っても忘れてしまうんです。。（つまり分かってない）
模擬試験は2回分しかついていないので、3時間確保して時間を測って解くなど、大切に使うことをオススメします。

模擬試験も正答率を気にしてくよくよせず、同様に数回繰り返し解いてください。

問題集を進める上で、最初は4択のうちから何とな～くこれという選び方になると思うのですが
全範囲の理解が進むにつれて、徐々に2択まで絞れるようになってくるので心配しなくて大丈夫です。
<br>
どうしても解説が理解できない、、という問題は解説の内容ごと暗記していました。
何かよく分からないけどこうなる！と覚えておくと、案外何とかなります。
本番において、問題は見たことあるのに解き方が分からない物と出くわすパターンが一番勿体ないです！

ちゃんと理解できることが一番ですが、独学の場合の最終手段として数問なら解説丸暗記するのも手です。

## 試験範囲について

ラムダ式の部分を捨てて挑む人もいますが、他の分野の問題なのに選択肢にラムダ式の範囲を絡めてきたりします。
そうすると、ラムダ式の範囲以上に切り捨てることになってしまいますし、
独学の場合は特に、他で8割9割取ってカバーすることの方が難しいです！
確かに難しい部分もありますが、暗記しておけば解ける部分もあるので諦めず学習した方が無難です。
ラムダ式の範囲はスッキリわかるJava入門　入門編には詳しく載っていないので、
私の場合はやさしくない!?Javaの動画で知識を補ってました。


問題数は80問で、合格ラインは63％なので
51問は正解していないと合格できません。

何度も解いている問題というのもあって、過去問で9割(72問)くらいの正答率があれば
余裕をもって合格できると思います！



試験当日の流れや感想は、別に記事にまとめます＾＾


<br>
<br>
<br>
リストビューから呼び出す画面フローの設定 & 完了動作を設定

# はじめに
- リストビューのボタンでフローを呼ぶ際は、少し手順が異なるためメモ  
- この場合、フローのURLを呼ぶので、完了動作を指定することが可能になる

## フローの設定
- 入力変数として `ids`を設定しておく  
- これがリストビューで選択したレコードの`recordId`として入力変数としてフローに渡ってくる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/484310/e9f4e0bb-f68e-ccd9-0394-7c88331ff875.png)


- フローのAPI参照名を取得しておく
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/484310/5864e65a-ed0a-fb04-4e7f-850bf717612e.png)


## 対象オブジェクトのリストビューボタンにフローを設定する
- **新規ボタンまたはリンク**をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/484310/b265b83a-eef0-a851-5eab-e831c4219306.png)

- 以下のように設定
    - 表示の種類はリストボタンを指定  
    - コンテンツソースはURLを指定
    - 差し込み項目に、`/flow/yourFlowAPIName?retURL=url`を指定.
        - `url`については自身の行いたい完了動作を指定する
        - 例えば、ケースのリストビューにリダイレクトする場合は、`retURL=500/o`と指定する
        - `500`という数字は、`Object Key Prefix`になるため、対象オブジェクト指定する。(**各オブジェクトのレコードIDの上3桁**)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/484310/12e6e0ec-9a05-2553-3ff0-c4ea47289189.png)

## 対象オブジェクトのリストビューボタンレイアウトを設定する
- 作成したボタンを設定する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/484310/ec040889-d4c3-19cc-10e7-df51a1c54d21.png)


## 参考資料
### Salesforce help: 完了動作を制御するようにフロー URL をカスタマイズ
https://help.salesforce.com/s/articleView?language=ja&id=sf.flow_distribute_internal_url_retURL.htm&type=5

### オブジェクト Key Prefix
https://www.salesforceben.com/salesforce-object-key-prefix-list/
Laravelで検索機能を実装

# この記事の背景
Laravelで検索機能を実装したのでその時のことを書いていきます。
キーワードを検索して部分一致で検索できる機能です。

# 検索機能の条件
1.ログインユーザー、未ログインユーザーでも検索できる
2.ユーザーの投稿を検索する機能
3.部分一致

特に1の***ログインユーザー、未ログインユーザーでも検索できる***状態でないと
仕様としてあまり良くないみたいです。

こちらの記事も参考にしてください。

https://qiita.com/Hashimoto-Noriaki/items/c768f4ab73c6354ae683

# ルーティング
ルーティングの書き方です。トップページで検索する機能です。

```web.php
//トップページ
Route::get('/', 'PostController@index')->name('post.index');
```

# Controller
Controllerの説明をしていきます。

```PostController.php
public function index(Request $request)
    {      
        $search = $request->input('keyword');//リクエストからkeywordパラメーターの値を取得し、$search変数に代入、ユーザーが検索フォームに入力したキーワードが格納される
        $query = Posts::query();Posts //モデルに対してクエリビルダを作成し、$query変数に代入してこのクエリビルダを使ってデータベースクエリを構築

        if (!empty($search)) {//$search変数が空でない時、つまりユーザーがキーワードを入力した場合に、検索条件を追加
            $query->where('text', 'LIKE', "%{$search}%");//textカラムがユーザーの入力したキーワードを部分一致で含む場合に検索条件を追加します。% はワイルドカード文字で、任意の文字列を表す
        } 

        $posts = $query->orderBy('id','desc')->paginate(10);//クエリビルダに対して、id カラムで降順に並び替えを行い、ページネーションを適用し取得するデータは1ページあたり10件
        return view('welcome', ['posts' => $posts, 'search' => $search]);//welcome ビューにデータを渡して、ビューを表示、$posts変数には検索結果が格納され、$search 変数にはユーザーが入力したキーワードが格納。ビュー内でこれらの変数を使用して結果を表示
    }
```

# view
検索フォームの見た目はこんな感じで作りました。

```php
 <form method="get" action="{{ route('post.index') }}" class="d-inline-block w-75">
     <div class="form-group ">
         <div class="input-group">
             <input type="text" name="keyword" class="form-control" placeholder="検索"  value="{{ request()->input('keyword') }}"autocomplete="on">
             <div class="input-group-append">
                 <button type="submit" class="btn btn-success">検索</button>
             </div>
         </div>
      </div>
 </form>
```




# 参考資料

ChatGptで調べました。
【Xcode エラー】Could not insert new outlet connection【解決法】

とあるUdemyの講座でアプリを作る過程で
Storyboard上でView を配置して、outlet接続を試みた時に

「Could not insert new outlet connection:
 Could not find any information for the class named ViewController」

といったエラーが発生した。

![スクリーンショット 2023-05-17 18.24.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/359201/14ccd6a0-4f3f-8715-673c-a446e3c3aef7.png)

① まず一旦Xcodeを「command ＋ Q」で閉じて、もう一度繋ぎ直そうとしたが
  上手くいかず。

↓

② 「command ＋ shift ＋ K」でクリーンしてもう一度繋ぎ直そうとしたが
  上手くいかず。

↓

③ Derived Data を削除してもう一度繋ぎ直そうとしたが上手くいかず。

↓

④ Xcode を再起動してもう一度繋ぎ直そうとしたが上手くいかず。

### 【上手くいったやり方】

⑤ 接続先となる変数を先に定義する
```
@IBOutlet weak var textField: UITextField!
```
↓

⑥ View から接続先の変数へドラッグ＆ドロップ

このあと定義したいViewからドラッグ＆ドロップで
先ほど定義した変数を接続します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/359201/39425610-0c43-793b-df18-50b32ed6e7e3.png)


### 【学び】
「Could not insert new outlet connection」というエラーにまた遭遇したら
今度からは⑤ → ⑥の手順で解決する方が速いなと思いました。

### 《参考記事》[Swift] Could not insert new outlet connection が出た時のよさげな解決策
https://qiita.com/takecian/items/d8db3965152580eafdc7
Prettier（パッケージ版）の導入 - .prettierrc(ルール設定) / .prettierignore(無視設定)

# Prettierとは
Prettierはコードフォーマッターの一種で、`JavaScript`、`TypeScript`、`HTML`、`CSS`、そして他の多くの言語をサポートしています。

パッケージ版のPrettierをインストールすると、コードのスタイルを自動的に整形し、コードの読みやすさを向上させることができます。また、チーム内でのコードの一貫性を保つのにも役立ちます。

# 環境
| Tool           | Version     |
|:---------------|------------:|
| MacOS(Ventura) | 13.0        |
| VSCode         | 1.78.2      |
| npm            | 9.5.1       |

# インストール
ここでは、パッケージマネージャである`npm`でインストールしていきます。
```terminal: prettierをインストール
$ npm install --save-dev prettier # --save-devでインストール先を開発環境に指定
```

# 設定ファイル
パッケージ版のPrettierの設定ファイルの説明です。
※ファイルが存在しない場合は、手動作成してください。

- `.prettierrc` - コードフォーマット(コード整形)のルール設定
- `.prettierignore` - 指定ファイル・ディレクトリを無視する設定

## ルールの設定（.prettierrc）
`.prettierrc` ファイルは、コードフォーマットのルールを設定します。
このファイルで、行幅、インデントのスペース数、シングルクォートを使うかダブルクォートを使うか、などの設定を行うことができます。
このファイルがプロジェクトのルートディレクトリに存在すると、Prettier はその設定を使用してコードを整形します。

設定例は以下の通りです。
かなり細かくフォーマットルールを設定できます。
```jsonc:.prettierrc（JSONの設定例）※JSONはコメントアウトをサポートしていないので注意
{
  "printWidth": 100, // 1行あたりの最大文字数。この数を超えると改行されます。
  "tabWidth": 2, // インデントのスペースの数。
  "useTabs": false, // タブを使用するかどうか。false の場合、スペースを使用します。
  "semi": true, // 文末にセミコロンを自動挿入するかどうか。
  "singleQuote": true, // シングルクォートを使用するかどうか。false の場合、ダブルクォートを使用します。
  "quoteProps": "as-needed", // オブジェクトのキーを必要に応じてクォートする。
  "trailingComma": "es5", // ES5でサポートされている場所で末尾のカンマを追加する。
  "bracketSpacing": true, // オブジェクトリテラルの中括弧 {} の間にスペースを入れるかどうか。
  "bracketSameLine": false, // オブジェクトリテラルの閉じ中括弧 } を新しい行に配置するかどうか。
  "arrowParens": "always", // (x) => x ではなく、x => x とするかどうか。
  "requirePragma": false, // ファイルの先頭に特定のコメントを書くことでフォーマットを有効にするかどうか。
  "insertPragma": false, // フォーマットされたファイルの先頭に @format を追加するかどうか。
  "htmlWhitespaceSensitivity": "css", // HTMLファイルの空白の扱い方。
  "vueIndentScriptAndStyle": false, // Vueファイルの <script> と <style> ブロックのインデントを有効にするかどうか。
  "endOfLine": "lf", // 改行コードの種類。"lf" は UNIX 形式、"crlf" は Windows 形式。
  "embeddedLanguageFormatting": "auto", // 埋め込み言語（例えば、テンプレートリテラル内の HTML）のフォーマットをどのように扱うか。
  "singleAttributePerLine": false // 一行に一つの属性を配置するかどうか。
}
```

## 無視する設定（.prettierignore）
`.prettierignore` ファイルは、Prettierがフォーマットを適用する際に無視するファイルやディレクトリを指定するためのものです。`.gitignore` と同じように動作します。

各行には無視したいパス（ファイル名またはディレクトリ名）を記述します。
`#` で始まる行はコメントとして無視されます。ワイルドカード（`*`）を使用して一部のパスを一括で無視することも可能です。

例えば以下のような `.prettierignore` ファイルを作成することができます：
ファイル内に記述した内容はPrettierのフォーマットから除外されます。

```plaintext: .prettierignore（plaintext）
# ディレクトリ内のすべてのファイルを無視：
build
coverage

# すべての Markdown ファイルを無視：
*.md

# すべての HTML ファイルを無視：
*.html

# .で始まるすべてのファイルを無視：
.*

# 現在のディレクトリとそのサブディレクトリに存在する全ての .xxx を無視：
**/.git
**/.svn
**/.hg
**/node_modules

# JSONファイルを無視：
package.json
package-lock.json
```

この設定ファイルをプロジェクトのルートディレクトリに配置すれば、`prettier --write .` などのコマンドを実行したときに指定したファイルやディレクトリが無視されます。

## コマンドの実行
想定通りの設定ができているかコマンドを実行しましょう。

以下のコマンドを実行すると`main.js`のコードがPrettierのルールに基づいて整形され、その結果が同じ`main.js`ファイルに保存されます。
（`--write`オプションは上書きする）

```terminal: main.js（実行例）
$ npx prettier main.js # 整形結果がターミナルに表示される（ファイル自体は変更されない）
$ npx prettier --write main.js # --writeでコード整形後、ファイルが上書き保存され
```

# 参考

https://zenn.dev/rescuenow/articles/c07dd571dfe10f
RubyでAtCoder ABC258(A, B, C, D)を解いてみた

# はじめに
Webエンジニアを目指して、RubyやRailsをいじってます。
今回は、RubyでAtCoder ABC258のA, B, C, Dを解きました。備忘録として解き方をまとめていきたいと思います。

# A - When?
https://atcoder.jp/contests/abc258/tasks/abc258_a
```ruby:a-258.rb
# 修正前
k = gets.to_i
k1 = k.to_s
k2 = (k - 60).to_s
puts k < 10 ? "21:0#{k1}" : k < 60 ? "21:#{k1}" : k < 70 ? "22:0#{k2}" : "22:#{k2}"
```
```diff_ruby:a-258.rb
# 修正後
k = gets.to_i + 21 * 60
- h, m = k.divmod(60)
- puts "#{h}:" + "%02d" % m
+ puts "%02d:%02d" % k.divmod(60)
```

# B - Number Box
https://atcoder.jp/contests/abc258/tasks/abc258_b
```diff_ruby:b-258.rb
n = gets.to_i
array = Array.new(n){ gets.chomp.chars }

dx = [-1, -1, -1, 0, 0, 1, 1, 1]
dy = [-1, 0, 1, -1, 1, -1, 0, 1]
max = 0
+ hash = {}
n.times do |i|
  n.times  do |j|
+   next if hash.keys.max.to_i > array[i][j].to_i
+   hash[array[i][j]] = true
    8.times do |k|
      count = 0
      x, y = i, j
      n.times do
        count *= 10
        count += array[x][y].to_i
        x += dx[k]
        y += dy[k]
        x %= n
        y %= n
      end
      max = [max, count].max
    end
  end
end
puts max
```
```ruby:別解
n = gets.to_i
array = Array.new(n){ gets.chomp.chars.map(&:to_i)}
num_max = array.map(&:max).max

dx = [-1, -1, -1, 0, 0, 1, 1, 1]
dy = [-1, 0, 1, -1, 1, -1, 0, 1]
max = 0
n.times do |i|
  n.times  do |j|
    next if num_max > array[i][j]
    8.times do |k|
      count = 0
      x, y = i, j
      n.times do
        count *= 10
        count += array[x][y].to_i
        x += dx[k]
        y += dy[k]
        x %= n
        y %= n
      end
      max = [max, count].max
    end
  end
end
puts max
```
## 解説
（[公式解説](https://atcoder.jp/contests/abc258/editorial/4232)を参考にしました）

それぞれの方向に対して場合分けを行い、全探索することで最大値を求めることができます。

# C - Rotation
https://atcoder.jp/contests/abc258/tasks/abc258_c
```ruby:c-258.rb
n, q = gets.split.map(&:to_i)
s = gets.chomp
count = 0
q.times do
  t, x = gets.split.map(&:to_i)
  case t
  when 1
    count += x
  when 2
    puts s[(x - 1 - count) % n]
  end
end
```
## 解説
countで、操作により末尾の文字を削除して先頭に挿入した回数を記録します。t=1の場合はcountにxを足し、t=2の場合は`(x-1-count)%mod`のインデックスに対応する文字を出力することで実装することができます。

# D - Trophy
https://atcoder.jp/contests/abc258/tasks/abc258_d
```ruby:d-258.rb
n, x = gets.split.map(&:to_i)
array = Array.new(n){ gets.split.map(&:to_i) }

ans = Float::INFINITY
sum = 0
array.each_with_index do |factor, index|
    break if index == x
    sum += factor.sum
    ans = [ans, sum + (x - 1 - index) * factor[1]].min
end
puts ans
```
## 解説
（公式解説を参考にしました）
Biが最小になるインデックスをmとすると、m<Mの場合において
```math
B_m < B_M < B_M + A_M
```
が成り立つため、m(m<=x-1)についてどこで2回以上使えば最小になるかを全探索することにより実装することができます。

https://qiita.com/shoya15/items/50fd17e37d7c64f2b166
【Paiza問題集】標準入力メニュー/N個の整数の入力

# Paiza問題集
Pythonで回答

## 標準入力メニュー/N個の整数の入力

### STEP1 改行区切りでN個の整数の入力
```Python
"""
改行区切りでN個の整数の入力
https://paiza.jp/works/mondai/stdin_primer/stdin_primer__integer_number_step1
"""

# 整数を受け取る
count = int(input())

# 配列を用意
num = []

# 配列に整数を追加していく
for i in range(count):
    num_i = int(input())
    num.append(num_i)
    
# 整数を表示する
for i in range(count):
    print(num[i])
```

### STEP2 2行で与えられるN個の整数の入力
```Python
"""
2行で与えられるN個の整数の入力
https://paiza.jp/works/mondai/stdin_primer/stdin_primer__integer_number_step2
"""

# 整数を受け取る
count = int(input())

# 整数をスペースで区切る
num = list(map(int, input().split(' ')))

# 整数を表示する
for i in range(count):
    print(num[i])
```

### STEP3 1行で与えられるN個の整数の入力
```Python
"""
1行で与えられるN個の整数の入力
https://paiza.jp/works/mondai/stdin_primer/stdin_primer__integer_number_step3
"""

# 整数の行をリストとして受け取る
num = list(map(int, input().split(' ')))

# 1文字目を取得する
count = num[0]

# リストをスライスする
num = num[1:]

# 整数を表示する
for i in range(count):
    print(num[i])
```
 
### STEP4 2行で与えられるN個の整数の入力
```Python
"""
2行で与えられるN個の整数の入力
https://paiza.jp/works/mondai/stdin_primer/stdin_primer__integer_number_step4
"""

# 整数を受け取る
count = int(input())

# 整数をスペースで区切りリストとする
num = list(map(int, input().split(' ')))

# 整数を表示する
for i in range(count):
    print(num[i])
```

### FINAL問題 N個の整数の入力
```Python
"""
N個の整数の入力
https://paiza.jp/works/mondai/stdin_primer/stdin_primer__integer_number_boss
"""

# 整数をスペースで区切りリストとする
num = list(map(int, input().split(' ')))

# 1文字目を取得する
count = num[0]

# リストをスライスする
num = num[1:]

# 整数を表示する
for i in range(count):
    print(num[i])
```
【Laravel】マイグレーション時によく使うカラム設定用メソッド

## はじめに
マイグレーションファイルでカラム設定をするときによく使用するメソッドをまとめました。（全部ではないです。）

## カラム設定
これらのメソッドは、マイグレーションファイルに用意されている`$table`から呼び出します。
DBのテーブルカラムには、カラム名とデータ型を指定する必要があり、データ型はPHPと同じで、整数型や論理型などがあります。

その他にも、主キー（プライマリキー）設定用の`idメソッド`など、カラム指定を簡単にするためのショートカットメソッドも用意されています。

さらに、`カラム修飾子`と呼ばれるメソッドを使用するとデフォルトで拒否されているNULLの値の登録を許可したり、カラムの登録位置の指定などのオプションを設定することもできます。

### カラム指定
| メソッド | 内容 |
| ---- | ---- |
| ->date() | 年-月-日 |
| ->boolean() | 論理型 |
| ->dateTime() | 年-月-日　時:分:秒 |
| ->float() | 小数 |
| ->integer() | 整数　|
| ->string() | 文字列（最大16,383）|
| ->text() | 文章　（string()よりも文字数が多い）　|

### カラム指定のショートカット

| メソッド　|　内容　|
| --- | --- |
| ->id() | 主キー用　|
| ->foreignId() | 外部キー用 |
| ->timestamps()| 作成日,更新日|
| ->softDeletes() | 論理削除用 |

### カラム修飾子

| メソッド　|　内容　|
| --- | --- |
| ->nullable() | NULL許可（デフォルトは拒否）、引数にfalseで拒否　|
| ->comment() | コメント（説明など） |
| ->after()| カラムを別のカラムの後に配置|
| ->first() | テーブルの最初にカラムを配置 |

## カラム指定の簡略化
Laravelには簡潔に書ける短い記法も用意されています。

例えば、外部キー設定用のforeignIdメソッドの場合
| カラム名 | データ型 | UNSIGNED | NULL許可 | オートインクリメント | 主キー制約 | 外部キー制約 |
|---|---|---|---|---|---|---|
| 任意 | biginteger | Yes | No | No | No | constrainedメソッドで設定 |

```php
$table->foreignId('user_id');
// ↓同じ
$table->bigInteger('user_id')->unsigned();
```


作成日、更新日用のtimestampsメソッドの場合

| カラム名　|データ型 | NULL許可 | デフォルト値 | 用途 |
|---|---|---|---|---|
| created_at | timestamp | Yes | NULL | レコード作成日時 |
| updated_at | timestamp | Yes | NULL | レコード更新日時 |

```php
$table->timestamps();
// ↓同じ
$this->timestamp('created_at')->nullable();
$this->timestamp('updated_at')->nullable();
```
## 参考
[Laravel 9.x マイグレーション](https://readouble.com/laravel/9.x/ja/migrations.html)
[kubernetes]よく使うコマンドまとめ

### namespacesの取得
~~~
kubectl get namespaces
~~~

### 指定のnamespaceのpods一覧の取得
~~~
kubectl -n/--namespace ${namespace名} get pods
~~~

### 特定のpodのログの取得
~~~
kubectl -n/--namespace ${namespace名} logs ${pod名}
~~~

### deployments一覧の取得
~~~
kubectl -n/--namespace ${namespace名} get deployment
~~~

### 特定のdeploy詳細取得
~~~
kubectl -n/--namespace ${namespace名} describe deployment ${deployment名}
~~~

### 特定pod(実際はdeployment)のrollout restart
~~~
kubectl -n/--namespace ${namespace名} rollout restart deployment/${pod名}
~~~

### pod名を指定し、強制的に削除
~~~
kubectl -n/--namespace ${namespace名} delete pod ${pod名} --grace-period=0 --force
~~~

### services一覧の取得
~~~
kubectl -n/--namespace ${namespace名} get Services
~~~

# pvc一覧の取得
~~~
kubectl -n/--namespace ${namespace名} get pvc
~~~

# 指定のpvc詳細の取得
~~~
kubectl -n/--namespace ${namespace名} describe pvc ${pvc名}
~~~

# cronjobs一覧の取得
~~~
kubectl -n/--namespace ${namespace名} get cronjobs
~~~

# 指定のcronjobの削除
~~~
kubectl -n/--namespace ${namespace名} delete cronjob ${cronjob名}
~~~
Google Looker Studio DATETIMEフィールドをNUMBERタイプに変換するクエリ

Google Looker Studioで、DATETIMEフィールドをNUMBERタイプに変換したい場合は、「CAST」を使います。

例
```
CAST(CAST(your_datetime AS TEXT ) AS NUMBER )
```

追記
下記の記事により、DATETIME_DIFFでNUMBERタイプに変換可能だと言われていますが、未検証ですから、ご参考まで
https://stackoverflow.com/questions/71203454/how-can-i-convert-a-date-field-to-number-in-google-data-studio
```
DATETIME_DIFF(your_datetime, DATE(1899, 12, 31), DAY) + 1
```
RHEL9.2アップデート後にLVが認識せずmountに失敗して正常起動しない

RHEL9.1導入後初めてのマイナーアップデート to RHEL9.2。
dnfコマンドでアップデートを実施したところ、リブート後に/homeがマウントできずOSが正常起動してこない。
コンソールはrootのパスワード入力待ち状態で、以降の起動プロセスが進まず。

ファイルシステムはLVM構成で、NVMe SSDの3番めのパーティションをPV/VG(rootvg)として構成し、その中に/homeのLVを切っている構成。

コンソールからrootのパスワードを入れてシェル起動。
LVが表示されず、VGも表示されず、あー、PVがそもそも見えてない状況。
lvsもvgsもpvsも同じこと言われますね。not foundか。

~~~
# lvs
  Devices file sys_wwid eui.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx PVID xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx last seen on /dev/nvme1n1p3 not found.
:
:
#
~~~
parted等でパーティションが存在していることは確認。
前回の起動時からPV自体に変更は加えておらず、他に何かやらかしたことも思い当たらず。

PVも認識できていないのに/はマウントできていてswapもActivateできているのは何故？と思ったがgrubで指定してるからですね。
また他のNVMe SSDやSATA HDD上のLVMは認識していて、/homeの前にマウントできている状況。

リブートしてGRUBメニューから1つ前のRHEL9.1のkernel(5.14.0-162.23.1.el9_1)を選択すると無事起動。
再度リブートしてあらためてRHEL9.2のkernel(5.14.0-284.11.1.el9_2)を選択すると同じ状況となる。
これはRHEL9.2のkernelになりブートプロセスに変更が入ったか？？

とりあえずこの状態でpvを認識できれば起動プロセスは先に進むだろうと判断。
~~~
# lvmdevices --adddev /dev/nvme1n1p3
  Devices file sys_wwid eui.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx PVID xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx last seen on /dev/nvme1n1p3 not found.
  WARNING: adding device /dev/nvme1n1p3 with PVID xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx which is already used for missing device device_id eui.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.
Add device with duplicate PV to devices file?
~~~
PVがDuplicateしてるけどいいか？って聞かれましたが、それでも認識できればOKなので、yで進める。
~~~
# cat /etc/lvm/devices/system.devices 
# LVM uses devices listed in this file.
# Created by LVM command lvmdevices pid 1657 at Mon May 15 20:27:01 2023
VERSION=1.1.16
IDTYPE=sys_wwid IDNAME=eui.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx DEVNAME=/dev/nvme1n1p3 PVID=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx PART=3
:
:
IDTYPE=sys_wwid IDNAME=nvme.xxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-xxxxxxxx DEVNAME=/dev/nvme1n1p3 PVID=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx PART=3
#
~~~
むむむ。IDNAMEの形式がeui.xxxからnvme.xxxになり、長さも随分と長くなってる。
が、他のNVMe SSDはeui.で始まる形式だが、問題無くマウントできているのが不思議。
この状態でリブート。

__無事RHEL9.2のカーネルで正常に起動しました。__
journal log上でも/homeのマウントは確認完了。


LVMのdeviceファイル内、eui.で始まる方をdeldevしても良いのですが、影響はなさそうなのでそのままにしてます。
きっと何らか修正があるはず、なのでその時手動で修正しよう、と思ってます。

//
NCMBの管理画面をGoogle Chrome機能拡張で便利にする（ファイルの種類でフィルタリング）

NCMBでは管理画面を提供していますが、時々物足りないことがあります。この機能があったらもっと便利なのに…と思いつつ、使っている方もいることでしょう。

そこで、その足りない機能を補足するGoogle Chrome機能拡張を開発しはじめました。今回は1.3（審査中）で追加したファイルストアのフィルタリング機能です。

## 動作について

動作は以下のようになります。機能拡張をインストールしていると、ファイルストアで `画像` 、 `動画` 、 `音声` 、 `テキスト` というボタンが追加されます。それぞれのボタンを押すと、コンテンツのmimeTypeに合わせた検索条件が自動的に適用されます。たとえば画像の場合は `image/` を含むmimeTypeのファイルのみが表示されます。

![mime-filter.mov.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/830c50b5-6c5e-8ffd-c883-95ed4e8ab842.gif)


## Tips

NCMBの管理画面はAngularでできており、単純にselectやinputに値を入力するだけでは検索条件に反映されませんでした。イベントオブジェクトを適用する必要があります。

```jsx
// selectタグの場合
document.querySelectorAll('.sub-navigation form select:first-child option')[1].selected = true;
document.querySelector('.sub-navigation form select').dispatchEvent(new Event('change'));
// inputタグの場合（テキスト）
document.querySelector('.sub-navigation form input').value = text;
document.querySelector('.sub-navigation form input').dispatchEvent(new Event('input'));
```

## インストール

[Chrome機能拡張のページからインストール](https://chrome.google.com/webstore/detail/ncmb-extension/dglkhlplcpmnbgodhbngcmdfpojkbdnc?hl=ja&authuser=0)してください。

## 利用法

ファイルストアの画面を開くとボタンが追加されるので、クリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/1abadc0a-6a82-d02c-fec9-9c8b2e1a9c14.png)

## 制限

この機能拡張は [https://console.mbaas.nifcloud.com](https://console.mbaas.nifcloud.com/) 以下でのみ動作します。また、この機能は管理画面のAPIを使っていますので、APIコール数を消費しません。また、ACLは無視して処理されます。

ファイルの拡張子は見ていないので、異なるmimeTypeが設定されていると期待した結果にならない可能性があります。

検索条件は常に追加になってしまいます。別な種類のファイルに切り替える場合には、古い条件を消してから行ってください。

## コードについて

機能拡張のコードは[NCMBMania/chrome-extension](https://github.com/NCMBMania/chrome-extension)にアップロードしてあります。ライセンスはMIT Licenseです。依存ライブラリとして[URL.js](https://github.com/duzun/URL.js)を使っています（こちらもMIT Licenseです）。

## まとめ

機能的にはまだ多くありませんが、徐々に機能を追加していきます。Google ChromeでmBaaSの管理画面を利用されている方はぜひお使いください。
huggingface の DatasetDict からのデータ選択方法

# 1. はじめに
自分が DatasetDict から特定のファイル, 列を選択するのにちょっと時間がかかったため、やり方を載せておきます

# 2. やり方
1. DatasetDict を huggingface 経由でロードする
    ```python
    from dataser import load_dataset

    dataset = load_dataset({dataset_name})
    ```
2. データ選択の方法
    **特定のファイルを削除したいとき**
    ```python
    # 普通の辞書からの削除方法と一緒
    # 今回は 'garbage_file' という名前のファイルを削除する
    del dataset['garbage_file']
    ```

    **特定の列を削除したいとき**
    ```python
    # 今回は 'garbage_column' という名前の列を削除する
    dataset = dataset.remove_columns('garbage_column')
    ```

# 3. 終わりに
huggingface 経由でデータをとることは多々あると思うので参考になればと思います
Python3でHelloWorldプログラムを実装してみた

# 概要
Python3でHelloWorldプログラムを実装してみました。

# ソースコード実装
ソースコードは以下の通りです。
```hello.py
print("Hello World!")
```

# プログラム実行
以下の通りコマンドを実行しました。
```
$ python3 hello.py 
Hello World!
```
無事実行できているようです。

# まとめ
何かの役に立てばと。
METROCK(メトロック)2023のリセールチケットをRubyスクリプトでGETした話

## これはなに？
GW満喫してるうちに売り切れてしまった`METROCK(メトロック)2023 5/21`のチケットを、公式のリセールでなんとか手に入れたエンジニアの物語。

## どうやったの？
ぴあリセールチケットの公式サイトをスクレイピングして、5/21のチケットがリセールされたらLINE通知するRubyスクリプトを書いて、crontabで1分おきにスクリプトを実行するようにした。

## 詳しく教えてください
### Rubyのインストール
めんどくさいので割愛します。たくさん記事が出てくると思うので、ググってみてください。

### Rubyスクリプトの用意
まずは以下の処理を行うRubyスクリプトを用意する。要件はめちゃくちゃシンプルですね。

- ぴあリセールチケットの公式サイトをスクレイピング
- チケットを検知したらLINEに通知

実際のコードは以下です。
```ruby
require 'net/http'
require 'uri'
require 'open-uri'
require 'nokogiri'

URL="ぴあリセールチケットの検索条件を指定した後に表示される画面のURLを貼りたまえ"

class LineNotify
  TOKEN = '君のトークンを書きたまえ'.freeze
  LINE_URL = 'https://notify-api.line.me/api/notify'.freeze

  attr_reader :message

  def self.send(message)
    new(message).send
  end

  def initialize(message)
    @message = message
  end

  def send
    Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |https|
      https.request(request)
    end
  end

  private

  def request
    request = Net::HTTP::Post.new(uri)
    request['Authorization'] = "Bearer #{TOKEN}"
    request.set_form_data(message: message)
    request
  end

  def uri
    URI.parse(LINE_URL)
  end
end

doc  = OpenURI.open_uri(URL).read
page = Nokogiri::HTML(doc)
text = page.text

if text.match?("1日") || text.match?("１日")
  LineNotify.send("1日券が出たよ")
end
```

たぶん、5 ~ 10分くらいで書きました。ほぼコピペです。

#### 記事の情報を取得する
`ぴあリセールチケットの検索条件を指定した後に表示される画面のURL`にアクセスしてHTMLを取得します。そのあとで、取得したHTMLを[Nokogiriさん](https://nokogiri.org/)に解析してもらいます。
最後に解析したHTMLに`1日`もしくは`１日`という文字列があった場合に、LINE通知をするようにしてます。判定方法は僕の場合は1日券が欲しかったのでこのようになりましたが、ここの判定は欲しいチケットの内容によって変わります。いずれにせよ、文字が含まれてるかどうかの検索で十分かなと思います。
因みに、全角と半角どちらも検証してるのは、実際のリセールチケットの文言が分からなかったので、念の為どっちも検証してるためです。

#### LINE通知
LINE通知は[この記事](https://qiita.com/QUANON/items/94f8835e923c76188f66)を参考にしました。本当にありがとうございました。
詳しく知りたい方は記事を読んでください。
記事の注意点として、**トークンはPCからじゃないと取得できない**ので、そこだけ気をつけてください。

#### スクレイピングとは？
プログラム上でwebページにリクエストを送って返却されたHTMLからデータを解析することです。要するに、プログラムを使ってwebページから知りたい情報を取得できる技術です。
Rubyの場合だと先ほど紹介したNokogiriという超有名なライブラリで簡単にスクレイピングできます。
詳しく知りたい方は[ここらへん](https://www.sbbit.jp/article/cont1/71102#head1)読んでね。

### スクリプトを定期実行する
**Windowsの場合はcrontabが使えない**ので、[ここら辺の記事](https://blog1.mammb.com/entry/2023/01/12/235241)を参考にしてみてください。

スクリプトを書いたので、次にスクリプトを自動で定期実行するようにします。[crontab](https://qiita.com/katsukii/items/d5f90a6e4592d1414f99)を使いましょう。

crontabの登録(編集)を実行します。
```bash
$ crontab -e
```

書いたスクリプトのフルパスを指定してrubyコマンドで実行。パスは自分の環境で確認してください。今回は毎分実行するように設定します。
```
* * * * * ruby /path/to/ticket.rb
```

登録されてることを確認。
```bash
$ crontab -l
* * * * * ruby /path/to/ticket.rb
```

#### 事後処理
見事にチケットがGETできた、もしくは、残念ながらGTEできずにライブが終わった場合は、ちゃんと登録したcronを削除しておきましょう。`crontab -r`で全てのcronを削除できますが、他にもcronを登録してる場合は、`crontab -e`でさっき追加したcronだけ削除してください。

## 準備は整った
全ての作業が済んだので、あとはリセールチケットが出ることを待ちましょう。
僕は夕方頃に通知が来て、ちょうどリアルタイムで気づいたので速攻で購入サイトに行き、見事チケットをGETすることができました。
![Screenshot_20230517-170201.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234657/a2126077-b690-abd6-8350-4040b06bf98d.png)

## まとめ
思いの外スクリプト仕掛けてからすぐに取れてよかったです。
エンジニアじゃなくても、ちょっと勉強すれば誰でも書けるコードなので、興味のある方は是非ご自分の環境で試してみてください。
ではでは。
【Laravel】マイグレーションの作成と実行方法

## マイグレーションとは
DBのテーブル定義は、phpMyAdminなどから手動で行うこともできますが、マイグレーションファイルという専用のファイルでDBのテーブル定義をPHPコードで管理することで、複数人での開発の時などに全てのPCで手動でテーブル定義を行わなくて済み、設定ミスを防いだり時短になります。

正確にはマイグレーションは、テーブル定義を実行するためのコマンドになります。

## マイグレーションファイルの作成
マイグレーションを行うにあたって、まずはファイルを作成します。

:::note warn
今回は、Laravel Sailを使用するのでsailコマンドを使用します。
:::

```
sail artisan make:migration create_users_table
```
マイグレーション名は`スネークケース`（全て小文字で、単語ごとにアンダースコアで繋げる）で指定します。
テーブル名は英単語の`複数形`を使用します。

コマンド実行後、新たなマイグレーションファイルが`database/migrations/`の下に作成されているはずです。

作成されたファイルの名前を見てみると、「日付_create_テーブル名_table.php」になっていると思います。この日付は、マイグレーションが実行されるときのタイムスタンプで、古い日時のファイルから先に実行されます。

## テーブル作成
ファイルが作成できたら、具体的にテーブルを定義していきます。
作成されたマイグレーションファイルを見てみると、デフォルトで`upメソッド`と`downメソッド`が定義されています。

```php
return new class extends Migration
{
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->id();
            $table->timestamps();
        });
    }

    public function down()
    {
        Schema::dropIfExists('users');
    }
}
```
マイグレーションファイルは、デフォルトで必要最小限のコードが記述されています。

### マイグレーションのメソッド
* upメソッド　  :　テーブルを生成するためのメソッド
* downメソッド　:　作成したテーブルの変更を取り消したり削除するためのメソッド

### マイグレーションの実行
マイグレーションファイルを作成、定義しただけではDBには反映されていないので、指定したマイグレーションを実行する下記のコマンドを実行します。

```
sail artisan migrate
```
コマンド実行後、確認をしてみるとテーブルが作成されているはずです。
このコマンドではすでに実行済みのものはスキップされ、`未実行`のものだけが実行されます。

### 実行履歴の確認
これまでにどのマイグレーションが実行されているかを確認したい場合は、下記のコマンドを実行します。

```
sail artisan migrate:status
```

```
sail artisan migrate:status

+------+------------------------------------------------+-------+
| Ran? | Migration                                      | Batch |
+------+------------------------------------------------+-------+
| Yes  | 2014_10_12_000000_create_users_table           | 1     |
| Yes  | 2014_10_12_100000_create_password_resets_table | 1     |
| Yes  | 2019_08_19_000000_create_failed_jobs_table     | 1     |
| Yes  | 2020_02_05_015307_create_albums_table          | 2     |
| Yes  | 2020_02_05_020352_create_photos_table          | 3     |
+------+------------------------------------------------+-------+
```

### ロールバック
マイグレーションのミスや実行済みのマイグレーションを取り消したい時は、ロールバックを使用します。
例えば、テーブル定義を変更したいときや、いついつまでのテーブルに戻したいときなどに使用することができます。

ロールバック時に実行されるメソッドは、先ほど作成したマイグレーションファイルのdownメソッドです。
マイグレーション時は、upメソッドが実行されるので、upメソッドの内容を打ち消す処理をdownメソッド内に記述します。

downメソッドには、デフォルトでテーブルを削除するための`dropIfExists`という処理が記述されています。
下記のコマンドを実行することでロールバックを実行することができます。
```
sail artisan migrate:rollback
```
ロールバックされるマイグレーションは、先ほどsail artisan migrate:statusで確認した`Batch`の数字が一番大きいもの全てが取り消されます。

* その他のコマンド　

| コマンド | 内容 |
| ---- | ---- |
| sail artisan migrate:reset| 全てのマイグレーションを一括でロールバック |
| sail artisan migrate:refresh | 全てのマイグレーションをロールバックしてからマイグレーションを再実行 |
| sail artisan migrate:fresh | 全てのテーブル削除後にマイグレーションして、再実行 |


## 参考
[Laravel 9.x マイグレーション](https://readouble.com/laravel/9.x/ja/migrations.html)
NCMBの管理画面をGoogle Chrome機能拡張で便利にする（プッシュ通知をCSVファイルでダウンロード）


NCMBでは管理画面を提供していますが、時々物足りないことがあります。この機能があったらもっと便利なのに…と思いつつ、使っている方もいることでしょう。

そこで、その足りない機能を補足するGoogle Chrome機能拡張を開発しはじめました。

## 動作について

動作は以下のようになります。機能拡張をインストールしていると、プッシュ通知の画面でレポートDLというボタンが表示されます。このボタンをクリックすると、JSONとCSVという項目が表示されます。それぞれの項目をクリックすれば、各フォーマットでファイルがダウンロードできます。

![1158 console.mbaas.nifcloud.com - 0517165947.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/c2f1f4b6-5da8-3adf-597f-9ae880738469.jpeg)


## インストール

[Chrome機能拡張のページからインストール](https://chrome.google.com/webstore/detail/ncmb-extension/dglkhlplcpmnbgodhbngcmdfpojkbdnc?hl=ja&authuser=0)してください。

## 制限

この機能拡張は [https://console.mbaas.nifcloud.com](https://console.mbaas.nifcloud.com/) 以下でのみ動作します。また、この機能は管理画面のAPIを使っていますので、APIコール数を消費しません。また、ACLは無視して処理されます。

プッシュ通知は表示されているものについてのみダウンロードされます。つまり一度にダウンロードできるのは最大100件までになります。

ダウンロードされるCSVファイルは以下のようになります。

![スクリーンショット 2023-05-17 15.55.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/cd509f02-53f1-6079-4b0d-c1e0f273017a.png)

## コードについて

機能拡張のコードは[NCMBMania/chrome-extension](https://github.com/NCMBMania/chrome-extension)にアップロードしてあります。ライセンスはMIT Licenseです。依存ライブラリとして[URL.js](https://github.com/duzun/URL.js)を使っています（こちらもMIT Licenseです）。

## まとめ

機能的にはまだ多くありませんが、徐々に機能を追加していきます。Google ChromeでmBaaSの管理画面を利用されている方はぜひお使いください。

[mBaaSでサーバー開発不要！ \| ニフクラ mobile backend](https://mbaas.nifcloud.com/)
Lambda関数でreportlabを使う

# 結論
awsのlambda関数(python)でpdf化を行うライブラリ「reportlab」を使うには、レイヤーの追加が必要だった。既にreportlab用にlambdaレイヤーを作成してくれているのでそちらを使う。

# 必要かもしれない準備
2023/5/17日現在では、このreportlab用のレイヤーはpython3.8までしか使えない（3.9もいけそう？）ので、pythonのバージョンを合わせる必要があった。
まずはバージョンを確認
~~~
$ pyenv versions

* 3.10.3 (set by /Users/user/.pyenv/version)
~~~
デフォルトバージョンが3.10なので変更が必要
以下のコマンドを順に打つ。

~~~shell
# python3.8をインストール（3.8代ならなんでも）
$ pyenv install 3.8.8
# デフォルトバージョンを設定
$ pyenv global 3.8.8
# 再度バージョンを確認
$ pyenv versions
~~~
最後のコマンドで
~~~
* 3.8.8 (set by /Users/user/.pyenv/version)
 3.10.3
~~~
のように、指定したバージョンの横に＊がついていれば大丈夫

ここで、インストールはできているのにデフォルトバージョンが上記コマンドでも変更されない場合は、環境変数でバージョンを指定している可能性がある。
~~~shell
# 環境変数を確認
echo $PYENV_VERSION
~~~
これで指定したいものと違えば、以下のコマンドで環境変数を削除する。
この環境変数はターミナルごとに作成されるのでまたターミナルを開き直すとリセットされる。
~~~
unset PYENV_VERSION
~~~
ちなみに以下のコマンドで再設定することも可能らしい
~~~
export PYENV_VERSION=3.10.3
~~~

# 手順
これの通りにレイヤーを追加する。
この記事ではpandasを例にしているが、reportlabを選べばできる。

https://qiita.com/polarbear08/items/202752d5ffcb65595bd9

上記の記事でも出てくるが、以下にレイヤーのARNが一覧で紹介されている

https://github.com/keithrozario/Klayers/tree/master/deployments/python3.8
OSSポリシーを策定し施行された話

# 本記事が目指すこと
前回の記事[dbt-coreにおけるOSS活動ことはじめその1 ~ CLAの話 ~](https://qiita.com/dai_zamurai/items/6811e1d4ca9e2fad1ca7)で取り上げた弊社のOSSポリシーが本日2023年5月17日付で施行されたので、この日を記念し簡単に紹介する

# 注意
- 投稿時点(2023/5/17)での情報に基づくため、今後は内容が変更されている可能性があります
- なお、本記事は筆者が所属する会社と関係なく、個人の記事であることをご了承ください
- また、全文については後ほど何らかの形でアップする予定です

# 背景
- 筆者は、[ちゅらデータ株式会社](https://churadata.okinawa/)に務める会社員であるが、就業時間中に職務としてのdbt-coreのOSS活動を始めた（OSS活動自体が初めての経験）
- なぜ職務としてのOSS活動が許可されたかについての詳細は、別記事に記載予定
- CLAの署名に関して承認フローが制定されておらず、不便さや曖昧さを感じたため、弊社でOSSポリシーを策定して欲しいと懇願した

# 本題
弊社にはOSSポリシーが存在しなかった。背景の詳細は[前回の記事](https://qiita.com/dai_zamurai/items/6811e1d4ca9e2fad1ca7)を参照のこと。
ポイントをいくつか紹介する
1. 本ポリシーにより、職務におけるOSS活動にて、**許諾を取らずとも**エンジニア自身がCLA（企業CLA,個人CLA）に署名することができる
    - これまでは、誰に許可を得てCLAに署名すれば良いか定まっていなかった。そのため、エンジニアは逐一上長に確認する必要があった。本ポリシー施行後は、エンジニア自身でCLAに署名することが可能となった
1. **OSS公開後の著作権はエンジニア個人に付与される**
    - これまでは、他の就業中の成果物と同様に、就業中のOSS活動においても、著作権の譲渡はされず、永続的に会社に属するものであった。本ポリシー施行後は、**OSS公開後**はエンジニアに著作権が譲渡されることになった
1. **原始的には著作権は会社に属する**
    - これまでと同様に原始的には著作権は会社に属する。ただし、以下のような文言を添えることで、OSS活動に関しては著作権を譲渡する仕組みを定めている
    > 当社は、役職員に対して、役職員によるOSS活動の促進のため、次条の定めに従い、職務著作にかかる著作権を譲渡する。


参考にした他社のOSSポリシーとしては、いくつかあるが特に[READYFORの事例](https://qiita.com/dai_zamurai/items/6811e1d4ca9e2fad1ca7)をベースに作成されたものである。理由としては、3つ目の原始的に著作権は会社に属すると定めることにより、例えば、OSSに公開されず改修されたコードを用いたプロジェクトの納品物に関して、開発に携わっていた社員が退職した場合の権利衝突のトラブルを予防するためのポリシーとなっている。（具体例：公開前のコードに関しても、僕に著作権があるからそのコードを利用しないで欲しい、と言われた場合の対応が困る）

今後も何かしらの不便や曖昧さが生じた場合、OSSポリシーが改修される可能性があるがその際にも、従業員の権利と会社のリスクマネジメントの観点で協議が行われるであろう。

ちなみに、**5月11日(木)に相談して、たたき台を策定した後、いくつか協議を重ねて5月17日(水)に施行される**という尋常でない弊社のスピード感が大好きである。

施行された記念日に何か記録として残したいと思い、記事に書き起こした。

# 終わりに
ちゅらデータでは、クレイジーな仲間を募集しているでござる
データエンジニア、もしくはSE系からデータエンジニアになりたい方がいればぜひ、御仁の力量に応じたグレード（ジュニア/ミドル/シニア）にて、応募するでござる

https://herp.careers/v1/churadata/T6Oag1FxE34V