OmniAICreator/Qiita-1.07M huggingface dataset:
最近学んだGitコマンドオプション

# Gitコマンドオプション
最近学んだgitコマンドについてです。
チームで開発する上でGitは避けては通れません。
そんな中で、学んだGitの便利なオプションについて書いてみました。
### git fetch -p
リモートに存在しなくなったリモート追跡参照を削除します。
例えば、リモートリポジトリの __branch1__ が削除され
新たにbranch2が作成されていた場合には、
```

git fetch -p

 - [deleted]             (none)     -> origin/branch1
 * [new branch]          branch2 -> origin/branch2


```

ローカルリポジトリの __origin/branch1__ が削除され
 __branch2__ が新しいブランチとして作成されます。
### git merge --no-ff ブランチ名 
__--no-ff__ とは __Non Fast-Forward__ の略です。
gitではmergeをした際にコミットをしない __fast-forward__ がデフォルトのため、
```
git merge --no-ff
```
をつけることで、コミットをすることができます。なぜこれが便利なのかというと、誤ってmergeしたときや取り消たいときに、merge自体を取り消すことが簡単にできるからです。
## 終わりに
最後まで読んでいただきありがとうございました。
間違っている箇所などありましたら教えていただきますとありがたいです。
## 参考
https://qiita.com/nog/items/c79469afbf3e632f10a1
【UiPath】モダンデザインでのExcel操作系のアクティビティを使ってみた⑤


# はじめに

:::note info

この投稿はモダンデザインで使用可能なパッケージExcel ModernのアクティビティをStudioで使用してみた第5弾となります。
今回は「範囲を自動調整」アクティビティを使用してみたいと思います

実行環境は以下の環境で行っております
UiPath Studio 2022.10.3 (Community License、UIAモード：モダンデザイン）
:::

# ■範囲を自動調整
<font color=blue>(UiPath.Excel.Activities.Business.AutoFitX)</font>
指定した範囲や表・シートなどの行の高さや列幅を調整してくれるアクティビティです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482005/ba10e6fa-00f8-710c-b66b-a8e22697a906.png)


# ■アクティビティの設定
今回は下記画像の様な行・列幅が調整されておらず見辛いレイアウトになっているシートの調整を行ってみたいと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482005/70e15e29-29bb-d21a-feb7-0bd293bdc572.png)


①まずは「<b><font color="blue">Excelファイルを使用</b></font>」アクティビティを設置してファイルのパス(画像赤枠)を設定します。
※今回はこの部分の詳細設定方法については省略します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482005/074ea00a-b044-0ddf-b4d7-a577a63d9dfd.png)

②①で設置したExcelファイルを使用の中に「<b><font color="blue">範囲を自動調整</b></font>」アクティビティを設置します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482005/f0029846-4b06-de0a-3da1-c61277d0d4a7.png)



③ここから「<B>範囲を自動調整</b>」のプロパティ設定を行っていきます。
まず、ソースの選択を行っていきます。
今回は調整したい範囲をシート名で設定を行います。
ブックの右端の＋マーク⇒Excel⇒シート名の順に設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482005/9b7499e4-bf42-e170-75cf-83b09ffd1a74.png)

<b><font color="red">※ここで設定した「Excel」はExcelファイルを使用で設定されている「参照名」です。</b></font>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482005/1d9f9bae-abfb-e732-5b25-069e56eda71b.png)

今回はシート名を設定しましたが、カスタム入力でシート名を直接入力することも可能です。
また、シート以外に表やピボットテーブルの指定などもできます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482005/82294068-4d59-62d5-b456-970252d362fe.png)


④次に調整を行うのは行なのか列なのか、若しくは両方なのか選択します。
ソースを選択の下にそれぞれチェックボックスがありますので、調整を行いたい項目にチェックを付けて下さい。
<b><font color="red">※初期値では両方にチェックがついています。</b></font>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482005/da761ed5-4ebe-a2b3-aa03-bfa2fbaa3d18.png)



⑤設定は以上となりますので、実行を行ってみましょう。
実行後のファイルを確認してみると列・行がそれぞれ調整されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482005/f03027da-7853-98ab-05b0-c6fe23cb6bff.png)




# おわりに

今回は「範囲を自動調整」について触れましたがいかがでしたでしょうか。
Excel操作系の便利なアクティビティが増えてきて凄く嬉しい今日この頃です。
他にも便利なアクティビティに順次触れていこうと思います。
閲覧いただき有難うございました。
Docker イメージ、コンテナ、キャッシュの削除まとめ

## はじめに
現代の開発現場では必要不可欠なdockerですが時々、関連ファイルをいじってないのに突然upできなくなったりbuildが失敗するようになったり言うことを聞いてくれないことがあります。
エラー文を読んで色々調べてもなかなか解決できない時の対処としてイメージなりコンテナなりを削除しようということになるのでそれ関係のコマンドをまとめました。
本家はこちら　→ https://docs.docker.jp/config/pruning.html#id3

## コマンド一覧

### 容量の確認
```
$ docker system df
TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
Images          5         0         3.864GB   3.864GB (100%)
Containers      0         0         0B        0B
Local Volumes   0         0         0B        0B
Build Cache     0         0         0B        0B
```

### イメージの削除
```
# 現在使用されていないイメージの削除
$ docker image prune

# すべてのイメージを抹消
$ docker image prune -a
```

### コンテナの削除
```
# 現在使用されていないコンテナの削除
$ docker container prune -f

# すべてのコンテナを抹消
$ docker image prune -a
```
ちなみに`-f`は「本当に削除して良いですか？」的な確認をスキップしてます。

### ボリュームの削除
```
# 確認
$ docker volume ls

# 個別に削除
$ docker volume rm volume_name

# 使用していないものすべて
$ docker volume prune -f

# 全て削除
$ docker volume rm $(docker volume ls -qf dangling=true)
```

### ネットワークの削除
```
$ docker network prune -f
```

### 全てを一括削除
これまでの奴らを一気に削除するコマンドになります。
```
# イメージ、コンテナ、ネットワーク
$ docker system prune

# volumeも含める場合
$ docker system prune --volumes
```

### キャッシュの削除
```
$ docker builder prune -f
```

## 最後に
何か間違っている箇所があればご指摘ください。
負荷テストする時大量データ作成プロシージャ

DROP PROCEDURE `proc_test01`
/
CREATE DEFINER=`homestead`@`%` PROCEDURE `proc_test01`(IN input int(1))
BEGIN
SET @start_idx = 0;
SET @customers_info_id  = 100000;
SET @point_card  = 7130010000 ;
loop1: LOOP
    SET @start_idx = @start_idx + 1;
    SET @customers_info_id  = @customers_info_id  + 1;
    SET @point_card = @point_card + 1;
    IF @start_idx > input THEN LEAVE loop1; 
    END IF;
    
    # カード会員情報の登録
    insert into DB.table1(card_info_id,customers_info_id,asp_card_main_id,asp_card_sub_id,asp_card_pin_code,my_shop_id,status,disable_flag,created_at,updated_at,last_modifier_id) values (26, CONCAT('90',@customers_info_id  ) , concat(@point_card, @customers_info_id  ) , concat(@point_card, @customers_info_id  ) ,null,0,'1','0',sysdate(),sysdate(),null);
    # カード会員情報の登録
    insert into DB.table2(customers_info_id ,stamp_id ,disable_flag ,created_at ,updated_at ,last_modifier_id) values (CONCAT('90',@customers_info_id  ) ,1 ,0,sysdate(),sysdate(),null);
END LOOP loop1;
END
An unexpected error は "happened" より "occurred" だとレビューした、あの時の私は正しかったのか

# TL;DR

正しいとも言えるし、正しくないとも言えます。
"happened" と "occurred" はエラーを **誰目線で解釈するか** によって変わり、

- プログラム目線で解釈すると "happened"
- 我々開発者目線で解釈すると "occurred"

になるのではないかと考えます。

# 本編

プログラム内で外部サービスを利用するとき、そこで想定外のエラーが起こるのはつきものです。
try-catch などを用いた例外処理はよく見かけますね。
その処理に関してコードレビューをしたことがあったのですが、今回はそのレビューについて振り返りたいと思います。

## 背景

これは今から 2 年くらい前、私が新卒で入った会社でコードレビューをしていた時のことです。
チームメンバーが実装したコードを見たところ、想定外のエラーを捕捉するところで次のようにログ出力していました。

```text
An unexpected error happened.
```

Google 翻訳に入れると「予期しないエラーが発生しました。」となります（記事執筆時点）。

それを見て、当時の私はプルリクに

> An unexpected error は起こるべくして起こるものなので happened よりも occurred がいいと思います。

というコメントを書きました。

## 単語の意味

"happen" と "occur" を 英英辞典で調べてみましょう。
今回は [Oxford Learner's Dictionaries](https://www.oxfordlearnersdictionaries.com/) を使用します。

### happen

> to take place, especially without being planned (起こること、特に計画されていないことが)

https://www.oxfordlearnersdictionaries.com/definition/english/happen?q=happen

この解釈を見るに、 **何かが偶然起こる** という意味合いが強そうです。
今回取り上げている「想定外のエラー」は予定されていないこととも取れますので、 "happen" は適切に見えます。

### occur

> to happen (起こること)

https://www.oxfordlearnersdictionaries.com/definition/english/occur?q=occur

to happen って・・・基本同じってことですか？？

## もうちょっと詳しく

同じ、では納得がいかないので、もう少し調べてみます。
Google 検索で「happen vs occur[^1]」と検索します。

こちらの記事では・・・

https://www.differencebetween.com/difference-between-happen-and-vs-occur/

> What is the difference between Happen and Occur?
> 
> • The word happen is used to convey the sense of ‘take place.’
> • The word occur is used in the sense of ‘come into being as an event or a process’.

- happen: 「起こる」ということを伝えるために使われる
- occur: 「出来事または過程として発生する」という意味で使われる

こちらでは・・・

https://peraperabu.com/happen-occur-chigai/

> happenとoccurの違いは、「起こっている」物事が明確にわかっているかそうでないかです。

「過程」というと、物事の進行にすでに組み込まれているような意味合いが出てきますし、起こっている物事が明確なときに "occur" を使うとすると、「プログラムでエラーが起こった」というのはある意味明確です。そうすると "occur" の方が適切にも見えます。

## 私なりの解釈とまとめ

### `An unexpected error happened.`

プログラム内部で外部サービスを利用する関数があった場合、「接続できなかった」や「リクエストの内容が不正だった」などのように原因がはっきりしているエラーもあるし、「なぜかダメだった」のように原因不明なエラーもあります。
**関数さんにとっては** 、原因不明なエラー (想定外のエラー) が起こったときに「一体何があったんだ？」 "What's happened?" となるんだと思います。で、「んー、よう分からん」ということをログに出力したり、例外を投げ直したりするということですね。

### `An unexpected error occurred.`

原因がわかっていようがわかっていまいが、「プログラム内部でエラーが起こる」という事象は **開発者から見ても他部署の人から見ても明らか** です。
このログが出たときは「エラーが起こっている」という明確な事実がそこにあるのだから、開発者が一体となって復旧および原因の解明に努めなければならないと思います。

## ちなみに

レビュー文で「起こるべくして起こる」という表現を使いましたが、"occur" にそのような意味を書いている辞書や記事は見つからなかったので、理由としては適切ではないかもです。

[^1]: 何か 2 つのものを比較する際に `vs` を間に入れるのはエンジニアにとって必須スキルの一つです。こちらに [記事](https://qiita.com/dodonki1223/items/955819806297ee554b31#%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%82%84%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA%E3%81%AE%E6%AF%94%E8%BC%83%E3%81%AB%E3%81%AF-vs-%E3%82%AD%E3%83%BC%E3%83%AF%E3%83%BC%E3%83%89%E3%82%92%E4%BD%BF%E3%81%88) を書いてくださった方もいらっしゃいます。ぜひ身につけましょう。
HTMLだけでアコーディオンが作れるらしい【検証】

どうやら `details` と `summary` を使うことで、HTML完結でアコーディオンが作れるらしいので検証。

モダンブラウザにもしっかり対応しているみたい。

![スクリーンショット 2023-01-20 9.00.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2949803/ce6dbb88-11f9-679a-1b4d-1d883eb703bf.png)


## HTMLとスタイル

```html
<details>
  <summary>概要</summary>
  <div class="inner">
    コンテンツ詳細
  </div>
</details>
```

```css
details {
  border: 1px solid #ccc;
  padding: 20px;
  cursor: pointer;
}

.inner {
  margin-top: 20px;
}

```

## 動作

![c06fea84eb711dbc29b1a1b96bb45130.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2949803/d1beba63-187c-3602-3219-db1c1dcc0bdc.gif)

cssやjsをうまく使って、簡単にアニメーションだけを追加すれば良さげです。

## アクセシビリティ面で最適化されている

> ・JavaScriptでキーボードイベントを登録することなく、タブフォーカスとエンターキー・スペースキーでの開閉操作ができます。

> ・スクリーンリーダーが開閉状態について適切に読み上げてくれます。たとえばmacOSのVoiceOverを使ってGoogle Chromeを読み上げさせてみましょう。アコーディオンが閉じている状態では「（概要文）下位項目が折りたたまれました、三角形の展開ボタン、グループ」、開いている状態では「（概要文）字間広く、三角形の展開ボタン、グループ」のように開閉状態を判断した内容が読まれます。

> ・サイト内で単語検索を行うと、検索した単語の含まれるアコーディオンが開き、中身の単語に直接移動できます。

参考: https://ics.media/entry/220901/
Yarnの使い方

パッケージマネージャー Yarn の使い方をまとめます。


nodeパッケージなので、npm経由でインストールできます。

npm install -g yarn

パッケージインストール

npm の場合
npm install

Yarnの場合
yarn

dockerのnodeイメージには既にyarnコマンドがインストールされています。

docker run --rm -w "/usr/app" -v "${PWD}:/usr/app" node:lts yarn -y
ServiceNow - 別モジュールへのリンクボタン作成

### 1.遷移先URLを取得する
今回はCallerに設定されたユーザーの会社のフォームへのリンクボタンを作成するため、会社フォームのURLを取得します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2843998/414216b8-d7ec-9449-0013-aab3e1d1dfc9.png)

### 2.UI Actionを作成する
「gs.setRedirect()」を使用することで遷移することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2843998/e9c24eb0-29ff-2398-4656-4167504ab873.png)

### 3.確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2843998/927de159-cf42-07c7-e9e1-20fc71082e56.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2843998/75984d7d-43c7-dca2-3181-33ba5b9da8dd.png)
GitHub Packages で作ったライブラリを使う💪

# やりたいこと

以下で作ったライブラリを実際に使いたい😃

https://qiita.com/miyuc/items/469275fb3b114cddcd99 

# やること一覧

1. Personal Access Token を作成する
1. 環境変数の設定する
1. .npmrc を作成する
1. パッケージのインストールする
1. プロジェクトで使う

# Personal Access Token を作成する

詳しい説明は以下をご参照ください。

https://docs.github.com/ja/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token

スコープは read:packages のみで大丈夫です。
Note は READ_PACKAGES などにするとわかりやすいと思います。

# 環境変数の設定する

Macの場合は .zshrc に以下を追加します。
source で読み込み直すのをお忘れなく。

```.zshrc
export NPM_TOKEN={personal access token}
```

# .npmrc を作成する

プロジェクトのルートディレクトリに .npmrc を作成します。

```.npmrc
@{GitHubのOrganization名}:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${NPM_TOKEN}
```

# パッケージのインストールする

```
$ npm install @{GitHubのOrganization名}/{リポジトリ名}
```

# プロジェクトで使う

```
import { func } from '@{GitHubのOrganization名}/{リポジトリ名}';
```

# 感想

これで使えるようになります！
簡単🤗

# 参考

https://engineer-first.net/create-github-packages
GitHub Packages で社内向けライブラリを作る💪

# やりたいこと

GitHub Packages を使って社内向けのライブラリを作成して、npm のパッケージとして公開する💪
TypeScriptを使用しています。

この記事ではnpmに公開するまでを対象としています。
ライブラリを使う方法は以下記事で書いているのでよかったら見てみてください🤗

https://qiita.com/miyuc/items/071098eb7d463348244d

# やること一覧

1. package.json を設定する
1. tsconfig.json を設定する
1. 関数を作成する
1. GitHub Actions を設定する
1. リリースを作成する


# Package.json を設定する

今回やりたいことと関係ない部分は省略しています。

```package.json
{
  "name": "@{GitHubのOrganization名}/{リポジトリ名}",
  "version": "1.0.0",
  "description": "自作ライブラリ",
  "main": "dist/index.js",
  "types": "dist/index.d.ts",
  "publishConfig": {
    "access": "restricted",
    "registry": "https://npm.pkg.github.com/"
  },
  "repository": {
    "type": "git",
    "url": "git://github.com/{@GitHubのOrganization名}/{リポジトリ名.git}"
  },
  "author": "",
  "license": "UNLICENSED",
  "devDependencies": {
   "typescript": "^4.9.4"
 }
}
```

重要な箇所だけ説明します。

**name**
`@{GitHubのOrganization名}/{リポジトリ名}` のように設定します。
ライブラリをインストールする際に以下のように使用します。
```
$ npm install @{GitHubのOrganization名}/{リポジトリ名}
```

**types**

ライブラリに型定義ファイルを含める場合は types を設定します。

**publishConfig**

パッケージを公開するレジストリを指定できます。
`"access": "restricted"` で private なパッケージになります。

**repository**

GitHub リポジトリの URL と一致している必要があります。


# tsconfig.json を設定する

```
{
  "compilerOptions": {
    "target": "es5",
    "module": "esnext",
    "declaration": true,
    "sourceMap": false,
    "outDir": "./dist/",
    "strict": true,
    "moduleResolution": "node",
    "esModuleInterop": true
  },
  "exclude": ["node_modules", "dist"],
  "include": ["src"]
}
```

上記だと ES Modules にしか対応していないので、CommonJS にも対応したい場合は以下の記事を参考にしていただければと思います。

https://qiita.com/miyuc/items/57e8670b3263da732147

# 関数を作成する

index.ts は関数をエクスポートするだけにしました。

```index.ts
export { func } from './features/filename';
```

# GitHub Actions を設定する

リリース作成時に自動でトランスパイルして、Packageとして公開するようにします。
`.github/workflows/publish.yml` を作成します。

```publish.yml
name: npm publish
on:
  release:
    types: [published]
jobs:
  publish-gpr:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: 16
          registry-url: 'https://npm.pkg.github.com'
          scope: '@{GitHubのOrganization名}'
      - run: |
          npm ci
          npm run build
          npm publish
        env:
          NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```

`secrets.GITHUB_TOKEN` はリポジトリに元々備わっているものなので設定は必要ありません。

# リリースを作成する

GitHub でリリースを作成して、パッケージが npm に公開されるか確認しましょう。
リリースの作成方法は以下をご参照ください。

https://docs.github.com/ja/repositories/releasing-projects-on-github/managing-releases-in-a-repository

# 感想

GitHub Packages は導入コストが低いので便利だなと感じました。
これまで複数箇所に同じ処理が書かれていてヤキモキしていたので、ライブラリとして管理できるのがとっても楽しみです🤗


# 参考
https://docs.github.com/ja/packages/working-with-a-github-packages-registry/working-with-the-npm-registry

https://engineer-first.net/create-github-packages

https://zenn.dev/keitakn/articles/github-packages-private-react-npm
ServiceNow - URLパラメータを取得する

### 1.クライアントサイドのScriptで実施する
今回はClident Scriptで実施します。
URLパラメータを「URLSearchParams」を使用して取得します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2843998/d30c1f8a-2707-9d3b-d7a3-e99f0c197e98.png)

### 2.確認
URLパラメータを取得することができました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2843998/cd8479d0-d85d-bac2-3f15-065fe0192ca5.png)
【TypeScript】parameter implicitly has an 'any' type

# エラー内容
JavaScriptコードをTypeScript化しようとしていた時、
```typescript
function titleCheck(title){
        if(jsonData[title] != undefined){
            return jsonData[title];
        }else{
            message.channel.send("そのゲームは登録されていません");
            return null;
        }
    }
```
という関数がもともとあったんですが、
![スクリーンショット 2023-01-17 142103.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2665102/92a28001-2f01-e738-cb9a-4f6da09f4448.png)
というエラー発生。
# 解決策
## 1. 引数の型を明記する
``any``型を持たないように、きちんと型を明記しておくというシンプルな解決法。
```typescript
function titleCheck(title: string){
     //略
    }
```
## 2. tsconfig.jsonを書き換える
80行目くらいにある
```typescript
// "noImplicitAny": true,                            /* Enable error reporting for expressions and declarations with an implied 'any' type. */
```
の部分を
```typescript
"noImplicitAny": false
```
に書き換えるとエラー消えました。
ServiceNow - 印刷画面へのリンクボタン作成

### 1.UI Actionを作成する
* クライアントで動作させるため、Clientにチェックを入れます。
* Onclickに適当な関数名を設定します。
* Onclickに設定した関数名でScriptを記載します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2843998/aebf3a82-22d6-927c-70fb-1828843ba956.png)

### 2.印刷画面を実際に開き、URLを取得する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2843998/1d451791-a421-32b1-a9cc-a40c86618007.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2843998/57e4a0a7-a238-cf51-cf32-f5e4ff32c327.png)

### 3.取得したURLを開くScriptをUI Actionに記載する
現在開いているレコードの印刷画面を開くため、「sysparm_record_list」のパラメータ情報をSysIDに変更します。
今回は、Taskテーブルを継承しているテーブルで使用できるようにするため、「sysparm_record_target」パラメータも変更しています。
ポップアップ画面で開きたいため「g_navigation.openPopup()」を使用し、返ってきたWindow変数で印刷を実行します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2843998/34721d1c-1735-435b-24a1-2558b7d26eb7.png)

### 4.確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2843998/c67eec72-cf6e-825f-92e2-3497293d9b0b.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2843998/32483ad8-0818-3a58-260c-243480c8982d.png)
ワンボタンで印刷実行画面まで表示することができました。
ServiceNow - 更新前の項目値をメールに記載する

### 1.特定の項目が変更された場合にイベントを発生させる
イベント起動時に、パラメータ1に更新前項目値を設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2843998/e80d2efb-5c73-8739-fc26-254be0c6afcb.png)
イベントの作成方法は[こちら](https://qiita.com/K-Shingo/items/d1121c6967cec1394e9a)の記事を参考にしてください。

### 2.Notificationを作成する
起動方法を「Event is fired」に、イベント名を発生させたイベントに設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2843998/2be1114a-7b5a-04f1-61ef-1296636bd84a.png)

### 3.Email Scriptを作成する
[System Notification] > [Email] > [Notification Email Scripts]
「event」変数にイベント起動時の引数情報を持っています。
「template.print()」で設定した値がメールに記載されるため、以下のようにScript記載します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2843998/40001a9d-1ff0-a654-c363-af960b2932b2.png)

### 4.メール本文でEmail Scriptを呼び出す
${mail_script:[Script Name]}で変数と同様にEmail Scriptを使用できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2843998/d7dbf0bb-772f-dca9-3c37-b78b8983703b.png)
エンジニアが知らないとおわり：ブラウザの違いを知ろう

未経験からエンジニアになりたい人は、プログラミングから始める人が多いと思いますが、
エンジニアの仕事は、プログラミングだけではありません。そして、プログラミングだけでは、エンジニアになれません。同時にプログラミングが苦手でも、システム構成や開発の流れを理解するとエンジニアに近づきます！
今回はブラウザの違いの影響について調べてみましょう！

![インスタスライド_202301041.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23130/e7ce0c1f-335c-3a60-e4dc-47a4252d60fa.gif)

# ブラウザとは
ブラウザとは、WEBサイトを閲覧するためのソフトのこと。
WEBブラウザと言います。
英語では、browserから来てます

# ブラウザの種類
１．IE Internet Explorer
　Microsoftが作っているブラウザです。　Windwosにデフォルトで入ってます。
　最近では、Microsoft Edgeに切り替わってます。

２．Safari 
　Appleが作っているブラウザです。　MacやiPhoneにデフォルトで入っています。

３．Chrome 
　Googleが作っているブラウザです。　Androidにデフォルトで入ってます。

# ブラウザのシェア
PC+モバイル全体　2022年7月時点のデータ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23130/19bff5c4-6c31-3777-5973-88ab319cd8b2.png)

# ブラウザのイメージ図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23130/fd6d09bc-46eb-23c8-8449-c151e4a5abe0.png)

# ブラウザの役割
ブラウザは、
・入力されたURLに従ってサイトから情報を取得する役割を持っている
・HTML,CSS等の情報を解釈して画面にレンダリングする役割を持っている
・JavaScriptを解釈して実行する役割を持っている

# まとめ
ー　Webサイトを見るには、Webブラウザが必要です

ー　ブラウザは色々な種類があります。

ー　ブラウザのお陰でサイト側では、HTML,CSS,JavaScript等を置いておけば、ブラウザが解釈して画面を表示してくれる役割をもっている

# 最後に
未経験の皆さん、若手エンジニアの皆さん、勉強方法について悩みがあればなんでも気軽に質問して下さい！
これからも記事を書いていきますので、モチベーションアップのためフォロー、イイねお願いします。
ServiceNow - Scriptでイベントを発生させる

### 1.イベントを作成する
[System Policy] > [Events] > [Registry]
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2843998/0276ce32-3592-20e4-eab6-ba9cf413b9be.png)

### 2.適当なビジネスルールを作成し、イベントを発生させる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2843998/d6614e6a-50b7-165a-4712-3df7ccfdf38c.png)
XAMPP と PowerCMS と

だれかに深く刺さるんじゃないかな

XAMPP は「その他のバージョンについてはこちらをクリックしてください」から
古いのを入れるのだけどリンクと気づかないようになってる。

さらに飛んだ先の
「More Downloads »」
へ飛ぶ

Linux Mac ユーザーは別に困る人は居ないと思うので
「XAMPP Windows」へ進む

結構下の方に「5.6.40」へのリンクがあるはず
ダウンロードしてとりあえず C:\xampp を作ろう

XAMPP 触ったこと無い方は「XAMPP 使い方」で検索して軽く触ってみて
軽くといいながら phpMyAdmin のログイン方法とかあるけど頑張って

CGI が動くことくらいまで確認できたら

いったん XAMPP は忘れよう

おもむろに「strawberryperl」で検索しよう

strawberry-perl-5.32.1.1-64bit.msi (202301 現在) をダウンロードして
インストールしよう
インストール先はデフォルトのまま「C:\Strawberry」がいい
それ以外だと無駄に思考回路を焼くけどお好みで焼いて

strawberryperl を入れたら「mklink strawberry」を検索しよう
「シンボリックリンク + Windows10」とか見えたら参考にして
何とかして C:\usr <<===>> C:\Strawberry\perl を繋ごう
黒い画面は管理者で起こそう
「C:\usr」フォルダーは勝手にできるから、というか作ってるとつながらないので注意しよう

あとは所定の場所に必要ファイルを入れて localhost/cgi-bin/mt/mt.cgi とかしよう

細かいことは置いておいた武運を
【React Native】Expoでapkファイルを作ろうとしたけどダメだった

# Expoでapkファイルを作って実機にインストールしたい

以下のサイトを参考に`npx expo build:android`を実行

https://zenn.dev/knaka0209/books/cd1518009314d2/viewer/038613

`apk`か`apk-bundle`を問われるので`apk`を選択
（※初回はExpoアカウントのログインを要求されました）

処理が進んで完了
表示されたURLを踏んだ先でapkファイルがダウンロードできるはず、と思ったらapkファイルがなかった。

以下のようなページが表示された
![1674153235396.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603894/f325f1ba-5ba6-49d3-fef2-cc92f6a23a4b.png)

要はExpo GoのアプリでQRコードを読み取れってこと
読み取ったらアプリのデータをExpoのサーバーからダウンロードしてアプリを起動するっぽい

# Classic Build service is no longer available. Migrate to EAS Build.

処理が終わった後にこのメッセージが表示された

調べてみると以下の情報が見つかった。

https://blog.expo.dev/classic-build-service-no-longer-supported-73c82b500f56

「クラシックビルドはサポートされなくなりました」

apkファイルを作るビルド方法でなく、Expo Goのアプリを通したEASビルドでしかビルドできないようになったらしい

EASビルドによってアプリのサイズが小さくなるんだとか

つまり最初に見たサイトの情報は古かった。

どうしてもapkファイルを作りたいなら、脱ExpoしてReact Nativeだけでアプリ作るか、Java/Kotlinでネイティブアプリを作るしかないのか

そもそもReact Native自体情報が少ない
useEffectを画面表示時（マウント時）のみ発火させる方法

まぁ何番煎じだよって気もしますが復習用

useEffectの第二引数に空配列を指定することで画面表示時に発火するようになります。
```
useEffect(() => { 
    console.log(test)
}, []);
```


useStateの値を指定した場合はstateが更新されたとき（setTest()呼ばれたとき）に発火するようになります。
```
const [test, setTest] = useState('');

useEffect(() => { 
    console.log(test);
}, [test]);
```

useStateの第一引数にはstateが更新されたときの関数を渡しますが、非同期関数は渡せません、内部で非同期関数を呼ぶようにしましょう。
NG
```
useEffect(async () => {
    console.log(test);
  }, [test]);
```
OK
```
useEffect(() => {
    async function test() {
      console.log(test);
    }
  }, [test]);
```
[Laravel] --env=testing が効かない時の解決例

## 何が起きた？
下記のコマンドを使った時に`.env.testing`ではなく`.env`を読みにいってしまった。
```
php artisan migrate --seed --env=testing
```

## 原因

```
php artisan config:cache
```
のコマンドで`.env`で環境ファイルが固定されてしまっていた。


## 解決例

```
php artisan config:clear 
```
を実行し`php artisan migrate --seed --env=testing`を実行することで、`.env.testing`を読ませることができることを確認した。


## 余談
下記でも同様の結果を得られることを確認できた。
```
php artisan config:cache --env=testing 
```
AWS Lightsail の wordpress で使っていた Let's Encrypt が自動更新できてなかったので対応した

AWS のマニュアルに Really Simple SSL というプラグインを使えというドキュメントがあるから、妄信していれていたんですが、ある日期限が切れるよメールが Let's Encrypt から送られてきた。

プラグインで更新かけると以下のような表示

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366986/0e845a83-abac-c72b-aaa6-99cd7b933af4.png)

どうやら、何かが更新されて、AWS-Lightsail （bitnami）　が対応できなくなったようだ。

ということで、SSHから手動で更新してみる。

結論、

`sudo /opt/bitnami/bncert-tool` を実行して対話的に進めたらあっけなく終了
【Smarty】 template_dirとcompile_dir

# template_dirとcompile_dirのパス
```php
<?php
// Smarty
define('SMARTY_DIR', '/usr/local/lib/smarty-3.1.35/libs/');
require_once(SMARTY_DIR . 'Smarty.class.php');
$smarty = new Smarty();
$smarty->template_dir = "../layout/";
$smarty->compile_dir = "../template_c/";

$smarty->display("layout.tpl");
```

* ディレクトリ構造
```
test--
    |-layout
    |   |_layout.tpl
    |
    |-module
    |   |_module.php
    |
    |-template_c
```

* この場合module.phpからlayout.tplを表示するため一階層上のlayoutの中の...と記述する
```php
template_dir = "../layout/";
compile_dir = "../template_c/";
```

* displayについてはtemplate_dirの続きからファイルを指定
```php
display("layout.tpl");
```
KISS原則を深堀してみる

# KISS原則って？
「Keep It Simple, Stupid」 or 「Keep It Short and Simple」の略

**何事もシンプルにしてね。** という意味

# 複雑とは何か

そもそも複雑とはなんでしょう。
国語辞書を引いたところ、以下のように記載されていました。

- 物事の事情や関係がこみいっていること。
- 入り組んでいて、簡単に理解・説明できないこと。

エンジニアの世界で言うと、
コードやコンポーネントが互いに絡みあったり、依存している状態と言えそうですね。

# なぜ複雑がダメで、シンプルさが必要なのか

アプリケーションは**常に変更されるもの**だからです。
仮に一生変更されないアプリに携わっているなら、KISS原則も他の全ての原則も覚える必要はないです。

変更するためには、人がそこに手を加わえなければいけません。
手を加えるためにはコードを読まなければいけません。
そして、その時のためにコードをシンプルにしておかなければいけません。

普段あまり意識しませんが、コードは人間のために書かれるべきだと思っています。
機械のために書かれているわけではないと思います。（もちろん機械に命令するためにも書いていますが）
爆速アルゴリズムや、ワンラインのコンパクトなコードや書いたとして、それを他の人が読んで何を意味しているのか理解ができなかった場合、負債でありコストにしかなりません。

人間が理解しやすいようにわかりやすくシンプルに書くのが、我々エンジニアの使命だと思っています。


# 「短い = シンプル」は常に成り立たない

なるほど、シンプルさがエンジニアにも求められるのは理解できたと。
じゃあなんでも短くしようとするアプローチはちょっと待ったです。

「短い = シンプル」は時に成り立ちますが、時に成り立ちません。

```js
// 短い
f = lambda x: 1 if x <= 1 else x * f(x - 1)
```
```js
// 短くない
def faculty(number: int) -> int:
    if number <= 1:
        return 1
    else:
        return number * faculty(number - 1)
```

# どのように"シンプル"を実現するのか

DRY原則やYAGNI原則を筆頭にいろんな原則/原理/パターンなどを用いて、シンプルにしていけいばいいと思います。それぞれの説明はここでは割愛させてもらいます。

原則などとは別に、”不要な使われていないものを削除する”というアプローチをここで簡単に紹介します。

コードの量が少なければ少ないほど、シンプルに向かっていきます。
サン・テグジュペリに以下のような名言があります。
```
追加するものがなくなったときでなく、
取り除くものがなくなったとき、それが完璧になるということである。

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away.
```
いやあ〜、かっこいいですね..。

コードの中に眠っている、デッドコードと向きあう事は”シンプル”に向けて大きな前進になるはずです。

# まとめ

**コードは人間のために、何事もシンプルに！！！** 

# 参照
https://code-specialist.com/code-principles/kiss#what-does%C2%A0kiss%C2%A0stand-for

https://thevaluable.dev/kiss-principle-explained/


https://medium.com/sliitwif/keep-it-simple-stupid-the-kiss-principle-guide-to-developers-d6ad83145955
Goを使ってDynamoDBに一括書き込み

aws-sdk-goを使ってDynamoDBを操作するメモです。
こちらの[リンク](https://docs.aws.amazon.com/ja_jp/code-library/latest/ug/go_2_dynamodb_code_examples.html)を見ながら基本的なCRUDは一通りできたのですが、一括処理はうまくできませんでした。
一括書き込みの箇所についてデモを作成しようと思います。

### 環境
`go version 1.17.2`

`aws-sdk-go v1.44.180`

### 前提
DynamoDBにユーザ情報を一括登録する想定です。
ユーザ情報はHTTPリクエストボディから受け取ります。
Lambda上で受け取ったデータを構造体に変換し、DynamoDBに書き込みます。

### 構造体を定義
ユーザ情報を表現する構造体を定義します。

```go:main.go
type User struct {
	ID   string `json:"id"`
	Name string `json:"name"`
}
```

### リクエストボディからのデータを構造体に変換
APIGatewayからリクエストボディを受け取り、User構造体に変換します。

```go:main.go
func handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
  body := request.Body
  err = json.Unmarshal([]byte(body), &users)
	if err != nil {
		return events.APIGatewayProxyResponse{
			Body: err.Error(),
			StatusCode: 501,
		}, err
	}
  ...
}
```

### DynamoDBに一括書き込み
`BatchWriteItem`というメソッドを使います。
このメソッド注意点があり、一回で登録できるデータは25個までです。
今回はUserの配列を書き込みたいので、25個登録したら次に要素にアクセスするというfor文を回します。

```go:main.go
func handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
  ...
  batchSize := 25
	start := 0
	end := start + batchSize
	for start < len(users) {
		var writeReqs []*dynamodb.WriteRequest
		if end > len(users) {
			end = len(users)
		}

		for _, user := range users[start:end] {
			item, err := dynamodbattribute.MarshalMap(user)
			if err != nil {
				return events.APIGatewayProxyResponse{
					Body:       err.Error(),
					StatusCode: 501,
				}, err
			}

			writeReqs = append(
				writeReqs,
				&dynamodb.WriteRequest{
					PutRequest: &dynamodb.PutRequest{
						Item: item,
					},
				},
			)
		}

		_, err = db.BatchWriteItem(&dynamodb.BatchWriteItemInput{
			RequestItems: map[string][]*dynamodb.WriteRequest{"TABLE_NAME": writeReqs},
		})
		if err != nil {
			return events.APIGatewayProxyResponse{
				Body:       err.Error(),
				StatusCode: 501,
			}, err
		}

		start = end
		end += batchSize
	}
  ...
}
```

### レスポンス実装
登録したデータをHTTPレスポンスとして返します。
ユーザの配列を`[]byte` -> `string`と変換します。

```go:main.go
func handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
  ...
  bytes, err := json.Marshal(users)
	if err != nil {
		return events.APIGatewayProxyResponse{
			Body:       err.Error(),
			StatusCode: 501,
		}, err
	}

	return events.APIGatewayProxyResponse{
		Body:       string(bytes),
		StatusCode: 200,
	}, nil
}
```

以上です。

### 参考
https://docs.aws.amazon.com/ja_jp/code-library/latest/ug/go_2_dynamodb_code_examples.html
Typescriptにおける部分型関係

# 概要
部分型関係とは、２つの型の互換性を表す概念です。Animal型はHuman型を含んでいると言えます。Human型の田中さんはAnimal型でもあるということです。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1980538/255f9dc8-af28-2e02-ec08-b4ff47c8f8f2.png" width=50% >


そのため、以下のコードはTypescriptでコンパイルエラーになりません。

```ts
type Human = {
    name: string,
    age: number
}

type Animal = {
    name: string
}

const tanaka: Human = {name: '田中', age: 35}
const tanaka2: Animal = tanaka
```
`tanaka`という変数にHuman型の値を入れました。`tanaka2`は `age`を含まないAnimal型であるにも関わらずHuman型の値を入れることが可能です。これはHuman型はAnimal型の部分型であるからです。

しかし、だからと言って`tanaka2`は人間ではないため、ageプロパティにアクセスすることはコンパイルエラーが発生します。
```ts
console.log(tanaka2.age)

TS2339: Property 'age' does not exist on type 'Animal'.
```

## 部分型関係の成立条件

```ts
type Human = {
    name: string,
    age: number
}

type Animal = {
    name: string
}
```

1. Animal型に含まれているプロパティは全てHuman型に存在する。

これはAnimalにnameが含まれているのに対して、Humanにもnameというプロパティが存在するので満たしています

2. 条件1で該当したプロパティの型が同じ

Animalのnameプロパティがstring型なのに対して、Human型も同様にstringなのでこの条件を満たしています。

よって、Human型はAnimal型の部分型であるということがわかります。

## 注意すべきこと

以下のコードは上のコードと似ていますが、Errorが発生します。
```ts
type Human = {
    name: string,
    age: number
}

type Animal = {
    name: string
}

const tanaka: Human = {name: '田中', age: 35}
const tanaka2: Animal = {name: '田中', age: 35}

TS2322: Type '{ name: string; age: number; }' is not assignable to type 'Animal'. Object literal may only specify known properties, and 'age' does not exist in type 'Animal
```

先ほど説明した、部分型からの関係からすれば問題ないように見えるのですが型の安全性とは別にこのようなエラーが発生します。
`tanaka2`は Animal型であるため、ageプロパティは存在しません。もちろん部分型の関係から代入は可能なのですが、どうせアクセスできないプロパティは無闇に書く必要はありません。だから上記のようなErrorが発生します。


このErrorはTypescriptによって出る場合とでない場合があります。下記のように
```ts
const tanaka2: Animal = {name: '田中', age: 35}
S2322: Type '{ name: string; age: number; }' is not assignable to type 'Animal'.   Object literal may only specify known properties, and 'age' does not exist in type 'Animal'.
```

直接代入すると、ageプロパティは存在しないことが明らかであるためErrorが発生します

```
const tanaka: Human = {name: '田中', age: 35}
const tanaka2: Animal = tanaka
```

しかしこのように変数に一度おくとErrorは発生しなくなります。一旦変数に入れるとこのようなチェックは失われてしまうということです。
Open VPN Server導入メモ@ Roky Linux 9

Roky Linux 9 に Open VPN Server を立てようと思ったらつまったのでメモ

# まとめ
- 実行権周りで怒られるので `# chmod a+x /etc/rc.d/rc.local` を実行
- OpenVPN の `server.conf` 最終行の `explicit-exit-notify 1` をコメントアウト

- その他
    - `server.conf` 上の暗号化方式などもデフォルトでは問題があるので，たとえば以下などに修正・追加する
```
cipher AES-256-GCM
data-ciphers AES-256-GCM
tls-version-min 1.2
tls-cipher TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384:TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384
reneg-sec 60
```

# 本編
## 環境
- Rocky Linux release 9.1 (Blue Onyx)
- OpenVPN 2.5.8
- EasyRSA 3.0.8

## 基本的な流れ
以下の記事を参考にインストール
https://www.server-world.info/query?os=Rocky_Linux_8&p=openvpn&f=1

この辺りの流れは CentOS6,7 など，過去とほぼ同じで特に注意事項はない（のに詰まってしまった…）

## 生じたエラー
### 1点目
- `systemctl enable openvpn-server@server` 実行時に `/etc/rc.d/rc.local` の実行権がないと怒られる
    - 単に実行権を渡せば良いので素直に対応して解決．
### 2点目
- `systemctl start openvpn-server@server` が，以下のコードを吐いて止まる．
    - エラーの内容
        - `The process' exit code is 'exited' and its exit status is 1.`
        - `openvpn-server@server.service: Failed with result 'exit-code'.`
    - 原因
        - OpenVPN の設定ファイル `server.conf` に記載されていたオプション `explicit-exit-notify` が原因
        - コメントアウトして解決

## 生じた警告
- エラーを解消するためにログを見たところ，暗号方式周りの警告を発見
- 警告通りデフォルトが`AES-256-CBC`だったので，以前の設定を引っ張り出して設定
slapd-configについて

OpenLDAPの設定方法は、OpenLDAP2.3以降、テキストの設定ファイルから起動時に設定を読み込む一般的な方法から、LDAPを使った動的な設定方法に変更。


この新しい設定の方式は「slapd-config」と呼ばれ、LDAPのデータベース（ディレクトリ）に保存されている設定データを追加・変更・削除等することで、動的に設定を更新。これをディレクトリベースの設定と言い、通常は設定変更による再起動等が不要。

設定データベースのツリー構造のルートは、DN（識別名）が「cn=config」で定義され、変更できない。また、標準では「/usr/local/etc/openldap/slapd.d」以下に設定データがLDIFファイルで格納。LDIFファイル自体はテキストファイルなので編集は可能だが、直接編集は非推奨。

LDAPの作法に則った方法での更新が推奨。設定用のLDIFファイルを定義し、ldapadd、ldapdelete、ldapmodifyといったコマンドにより、データベースを更新。

ディレクティブの先頭の「olc」という文字は「OpenLDAP Configuration」の略
Laravel9でつまずいたところ

## Laravelスタートの見習いエンジニア
自分が学習していく中でつまずいたところをメモします。

まずはMVCの動き方とかを知るために職場の方から教えていただいたこちらのサイトをもとにTODOアプリを作成することにしました。
https://www.hypertextcandy.com/laravel-tutorial-introduction

### 環境
Laravel9+Docker+mysql+nginx
PHP 8.1.14
editor: PHPStorm

### 今日つまずいたところ
Routingはあっているはずなのに
```
target class [クラス名] does not exist.
```
のエラーが表示される・・・

### 解決
どうやらLaravel8とLaravel9では動作が違うという
（そりゃそうだよな・・・）

### 参考記事
https://biz.addisteria.com/laravel_route_error/
とても助かりました。
先駆者の方でこうしてまとめてくださるのは本当にうれしいこと
ありがとうございます。
【プログラミングに役立つ数学】ド・モルガンの法則を使って条件分岐の可読性をあげよう

### はじめに

プログラムを書く上で可読性は非常に重要です。

「リーダブルコード」が多くのエンジニアに支持されているように、他者と開発する上では「いかに理解しやすいコードを書くか」が求められています。

そこで、プログラミングの基本である条件分岐について高校数学で学習する「ド・モルガンの法則」を使った可読性を向上させるテクニックを紹介します。

可読性の高いプログラムを書きたい方はもちろん、「大人になってから数学なんて役に立たない」と思っている方にもぜひ一読いただけたら幸いです。

### ド・モルガンの法則とは

本題に入る前にド・モルガンの法則を初めて聞く人や忘れてしまった人のために簡単におさらいします。

ド・モルガンの法則とは、2つの集合A,Bに対して以下が成り立つことを言います。イギリスの数学者オーガスタス・ド・モルガンさんが発案したことからその名が付けられています。

```math
\overline{A \cup B} = \overline{A} \cap \overline{B}
```

```math
\overline{A \cap B} = \overline{A} \cup \overline{B}
```

この式を日本語にするとそれぞれ次のような意味になります。
- 『「A または B」でない』 は 『「A」でない かつ 「B」でない』に等しい
- 『「A かつ B」でない』 は 『「A」でない または 「B」でない』に等しい

どうでしょう、ここまでの説明で理解いただけましたでしょうか？

おそらく初めて聞く人にはまだ理解することは難しいと思うので、ぜひ次のようなベン図を書いてご自身で一度考えてみてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309621/ed302d14-8fc8-7917-5b7d-f200a75e65e5.png)

いかがでしょうか？
初見の方は理解ができなかったかもしれませんが、聞き覚えのある方はベン図を見ればすぐに思い出したかもしれませんね。

ド・モルガンの法則についてのこれ以上細かい説明はこの記事では省略するので、これでもまだわからない方は検索して調べてみてください。

### ド・モルガンの法則をプログラムに応用する

それでは実際にド・モルガンの法則を使って条件分岐の書き換えを行ってみましょう！
例えば以下のようにaとbの値によって処理を変える条件分岐について考えてみます。
※説明のため極端にわかりづらい例を挙げていますのでご容赦ください

```ruby
if !(a != 10 && b != 20)
```

上記の条件分岐を日本語にすると以下のような意味になります。

__もし「aが10でない かつ bが20でない」でない場合__

まるで「__もう恋なんてしないなんて言わない__」のように、読み手からしたら「結局どっちなの！？」と戸惑ってしまいます。

こんな分岐を見たら思わずPCを投げ出したくなる方もいるかもしれません。

「でない」という否定が多重になっていることが読み手を混乱させてしまう大きなポイントです。

それではこの式をド・モルガンの法則を使って書き換えてみましょう。
今回は先ほど紹介したド・モルガンの法則の2つの式のうち以下の式を適用します。

```math
\overline{A \cap B} = \overline{A} \cup \overline{B}
```

ぜひご自身でも先ほどの条件分岐をどのように書き換えることができるか考えてみてください。

<br/><br/><br/><br/>

↓書き換え後の結果はこちらです


<br/><br/><br/><br/>

じゃん！

```ruby
if (a == 10 || b == 20)
```

どうでしょう！先ほどよりも随分すっきりした感じはありませんか？？

先ほどとは全く同じ条件分岐の結果となりますが可読性に雲泥の差があることは一目瞭然です。

このように実際にド・モルガンの法則を使うことで条件を変えることなく読み手にとって理解しやすい分岐に書き換えることができました！

今回は解説のため極端な例を紹介しましたが、実務でも意外と同様のパターンは散見されるため実装時やコードチェック時は意識していただくと良いと思います！


### 余談

※ここからはほとんどrubyの話になります。

多くの言語では条件式を`if`と`else`で記載しますが、rubyの場合は`if`とtrue/falseが反対となる`unless`という修飾子が存在します。

例えば以下の式はaが10でない場合にtrueとなります。

```ruby
unless a == 10
```

上の例だと伝わりづらいですが`if`よりも`unless`を使った方が可読性が高くなる場面は多いです。
しかし、`unless`で複数の条件式をANDやORで繋げてしまうとさきほどの例のように可読性が低くなってしまう傾向があるので、条件式が複数になる時は素直に`if`を使う方がおすすめです。


`unless`から`if`への書き換えは本記事で紹介したド・モルガンの法則を使って考えると導きやすくなるので、特にRubyを使う方はこれらの知識を身につけておくと役に立つと思います！

unlessからifへの読み替えについてより詳しく知りたい方は以下の記事が参考になります。

https://qiita.com/jnchito/items/a24e2b188e44c0f8c2ad

また、Ruby以外の言語でも条件分岐はつきものなので、ド・モルガンの法則やベン図を活用することでより可読性の高いコードを書く意識を持っていただくと良いと思いました。
VerilogでSPI受信

# 概要

ESP32マイコンをSPIマスター，FPGAをSPIスレーブとする構成で，SPIデータの受信を行うVerilogコードを紹介します.

 
![SPI_受信ブロック図.dio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204268/f52fdc9d-4834-6260-0c57-1fdbeff038b8.png)

詳細はブログ **[「FPGAでシンプルSPI受信」](https://kairoyasan.com/fpga/fpga_simple_spi_receiver/)** にて紹介しておりますので,参考になれば幸いです!

## Verilogソースコード

```verilog:SPI_RECEIVER_32BIT
module SPI_RECEIVER_32BIT
  (input	wire      i_clk       
  ,input	wire      i_rst_n     
  ,input	wire      i_SPI_CLK   
  ,input	wire      i_SPI_CS_n  
  ,input	wire      i_SPI_MOSI  
  ,output	reg[31:0] o_data      
  ,output	reg       o_valid     
  );
    
  reg [2:0]	buf_clk;
  reg [2:0]	buf_ena;
  reg [2:0]	buf_dat;
  
  reg [31:0]rsv_data;
  wire      clk_rise;
  wire      ena_rise;
  wire      shift	;
    
  always@(posedge i_clk or negedge i_rst_n)begin
    if(!i_rst_n)begin
        buf_clk	<=3'b111;
        buf_ena	<=3'b111;
        buf_dat	<=3'b000;
    end else begin
        buf_clk	<={buf_clk[1:0] , i_SPI_CLK};
        buf_ena	<={buf_ena[1:0] , i_SPI_CS_n};
        buf_dat	<={buf_dat[1:0] , i_SPI_MOSI};
    end
  end
    
  assign clk_rise=( (buf_clk[2]==1'b0) && (buf_clk[1]==1'b1) ) ? 1'b1 : 1'b0;
  assign ena_rise=( (buf_ena[2]==1'b0) && (buf_ena[1]==1'b1) ) ? 1'b1 : 1'b0;
  assign shift   =( (clk_rise == 1'b1) && (buf_ena[2]==1'b0) ) ? 1'b1 : 1'b0;

  always@(posedge i_clk)begin
    if(shift)
      rsv_data <= {rsv_data[30:0],buf_dat[2]};
  end

  always@(posedge i_clk)begin
    if(!i_rst_n)begin
      o_data	<=32'd0;
      o_valid <=1'b0;
    end else if(ena_rise==1'b1)begin
      o_data	<=rsv_data;
      o_valid <=1'b1;
    end else begin
      o_data	<=o_data;
      o_valid <=1'b0;
    end
  end

endmodule
```
[Apex] Blobと文字列の変換

Blobは、バイナリデータを表すApexのプリミティブデータ型。
Base64は、データを64種類の英数字記号で表すエンコード方式。

## String → Blob
```apex
// 文字列をBlob型にキャストする。
String str = 'Blobと文字列の変換　サンプル';
Blob b = Blob.valueOf(str);

// Base64でStringに変換されたバイナリデータをBlob型に戻す。
String encoded_64 = 'QmxvYuOBqOaWh+Wtl+WIl+OBruWkieaPm+OAgOOCteODs+ODl+ODqw==';
Blob blobData1 = EncodingUtil.base64Decode(encoded_64);

// 16進数のStringに変換されたバイナリデータをBlob型に戻す。
String encoded_16 = '426c6f62e381a8e69687e5ad97e58897e381aee5a489e68f9be38080e382b5e383b3e38397e383ab';
Blob blobData2 = EncodingUtil.convertFromHex(encoded_16);
```




## Blob → String
```apex
// Blob型のデータを文字列にキャストする(文字コードがUTF-8でないとエラー)。
String str = inputBlob.toString();

// Blob型のバイナリデータをBase64でエンコードした文字列に変換する。
String encoded_64 = EncodingUtil.base64Encode(inputBlob);

// Blob型のバイナリデータを16進数にエンコードした文字列に変換する。
String encoded_16 = EncodingUtil.convertToHex(inputBlob);
```

## 参考
- [EncodingUtil クラス | Apex 開発者ガイド | Salesforce Developers](https://developer.salesforce.com/docs/atlas.ja-jp.apexcode.meta/apexcode/apex_classes_restful_encodingUtil.htm)
- [Blob クラス | Apex 開発者ガイド | Salesforce Developers](https://developer.salesforce.com/docs/atlas.ja-jp.apexcode.meta/apexcode/apex_methods_system_blob.htm)
【備忘録】Macのtarminalで~/.bash_profileを設定してもなかったことにされる件について

### Macのtarminalで~/.bash_profileを設定してもなかったことにされる件について

## 発端
* MAMPのmysqlのログインをどこからでもできるようにしようと~/.bash_profileにパスを記載したところ、source ~/.bashrcをして保存したとしても、tarminalを終了し再度開いたらパスが通ってなかったことにされていた。

## 原因
* tarminalのシェルがbashではなくzshだったため、ログイン時には~/.bash_profileではなく~/.zshrcを通っていたのが原因だった。

## 解決方法
~/.zshrcにパスを記載すればいい。

1. ~/.zshrcを開く
```
vim ~/.zshrc
```

2.パスを記載して保存(ここではMAMPのmysqlのパス)
```
export PATH=$PATH:/Applications/MAMP/Library/bin
```

３. esc → :wq でvimを保存して終了

４.  保存
```
source ~/.zshrc
```

MacのCatarinaはシェルがzshになっているみたいなのでパス系は~/.zshrcに書きましょう！！！
k8sのマスターノード、ワーカーノード、コントロールプレーン、クラスターを理解する #UserPlane説明のおまけ付き

クラスターとは、サービスを外部に公開するためのマスターノードとワーカーノード一式のことです。

コントロールプレーンを理解するには、データプレーンも理解する必要があります。

ワーカーノードと関わりが深いのは、ネットワーク屋にしてみたらデータプレーンであるものの、k8s公式では、データプレーンを処理するリソースまで範囲を拡張して"ワークロードを担当する"のがワーカーノードであると、説明されています。

次にコントロールプレーンについてです。ネットワークの世界ではデータプレーン以外のすべてがコントロールプレーンですが、k8sの世界ではミドルウェア的な動作をするソフトウェアや関連する制御信号まで解釈を広げて、コントロールプレーンと呼ばれています。

そのk8s的コントロールプレーンを担うべきノードがマスターノードです。コントロールプレーンとマスターノードがごちゃごちゃにならないように、しっかり覚えておきましょう。

【おまけ UserPlaneとは何か？】

k8sの世界も文化的ですが、3gppの世界も文化的です。

UPlaneなる言葉もあるのですが、3gppの世界では、データプレーンのうち、モバイル端末で送受信するデータプレーンをUserPlaneと呼んでいます。
kubernetesを使用するにあたってぶち当たる壁

kubernetesをGCPやAWS上で動かすとき、実務でぶち当たった壁、考えないといけないポイントをまとめていきます。

## AWSのマネージドで動かすか?　k8sの中で動かすか問題

### 証明書関連

どこでSSL終端を行うのか?k8s-cluster外でSSL終端するのか、しないのか?を考える必要がある。さらにその証明書を得るときに期間が切れたときに自動で証明書を発行するのかいなかなどもある。

https://cert-manager.io/


## シークレット関連
通常、k8sで`secrets.yaml`ファイルを定義した場合、Secretのvalueは`base64`で、エンコードされるだけで、エンコードされた文字列を知れば、簡単にデコードできてしまう。そのため、secretsを以下のサービスを使用して外部に置いておいて、必要な時に動的に取得するといったシークレット管理の仕方が存在する。

##### external-secrets-operator(ESO)
SSMパラメータストアなどに置いておいて必要な時にk8sからシークレットを呼び出す形

https://external-secrets.io/v0.7.2/

##### vault
シークレットに対してのアクセス権限を動的に発行してセキュアに保つ

https://github.com/hashicorp/vault-k8s


## 認証認可・IRSA周り

IRSA(IAM Roles for Service Accounts)：Pod単位でIAMのロールを割り当てる仕組み。AWS・GCPマネージドリソースとk8s-cluster内のリソースのアクセス許可とアクセス制御を考えるのが非常に大変。


## HPA戦略
HPAさせる時のメモリ使用率などから考える。
このpodのメモリ率はこのインスタンスタイプにおいて常時〇%を使用している。じゃあ、〇%のリクエストを受けた時に、PodをHPAさせようなどを考えること

https://speakerdeck.com/oracle4engineer/hpa-deep-dive?slide=28


## CRD(Custom Resource Definition)
kubernetesはGoでちなみに書かれている。deployment、serviceなどがリソースタイプに存在するのだが、そのdeploymentをdeploymentだと定義させるリソースが存在する。簡単にいうとサードパーティ製のリソースを定義するためのもの。先ほどのESOもその一つである。

https://www.udemy.com/course/kubernetes-operator-basics/


## EKS・GKEのアップグレードそれに対応
eksなどの特定のkubernetesバージョンに対応してる期間がかなり短い。それもkubernetesのそもそものバージョンアップデートが早いからである。

https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/kubernetes-versions.html

バージョンが上がったとき、旧バージョンで動いていたk8sリソースが新バージョンで動くかどうかをchangeing logで確認する必要がある。`kind：apps/v1beta1`とかなどは新バージョンでなかったりするケースがある。

https://aws.amazon.com/jp/blogs/news/planning-kubernetes-upgrades-with-amazon-eks/



## おまけ
### よく実務中、調査で使用するモジュール

#### k9s

この人が、使い方をまとめてくれている。

https://qiita.com/t0m0ya/items/15ee4d43dcda4701946c


https://github.com/derailed/k9s

### aliasでkubectl=kは登録する
kubectlまで打つのが本当にめんどくさい。


https://qiita.com/magisystem0408/items/c5229c7bf9221009b2c4
チャットボットのhubotをインストール時のトラブル対応


チャットボットのhubotをインストールしてみました。
インストール時にちょっとトラブったので、メモとして残しました。

## 参考になったサイトはこちらの記事
[Hubot のインストールと Hello World](https://qiita.com/suppy193/items/27ffbe932877a1d7e8ee)

## エラー発生
この手順に従って進めていくと、 $ yo code　でエラーになりました。
エラーコードは以下の通り。

```
/usr/local/lib/node_modules/yo/node_modules/npm-registry-fetch/node_modules/@npmcli/fs/lib/fs.js:6
const fsSync = Object.fromEntries(Object.entries(fs).filter(([k, v]) =>
                      ^
TypeError: Object.fromEntries is not a function
    at Object.<anonymous> (/usr/local/lib/node_modules/yo/node_modules/npm-registry-fetch/node_modules/@npmcli/fs/lib/fs.js:6:23)
    at Module._compile (internal/modules/cjs/loader.js:778:30)
(略)
```

## 原因と対策
ネットで調べてみると、githubのissuesに全く同じ事象についての記事がありました。

参考：
https://github.com/microsoft/vscode-generator-code/issues/343

原因としては、Node.jsのバージョンが古いためのようです。
さらに、yoが動くためにもnodeのバージョンの指定が必要のようです。

- The latest version of the yo package supports node >=12.10.0.

この記事には、バージョンの上げ方の情報も提示してくれていました。↓
https://computingforgeeks.com/how-to-install-nodejs-on-ubuntu-debian-linux-mint/
[ServiceNow] GlideSchedule APIで営業日計算する

# 指定日からX営業日後の日付を計算する

## きっかけ
インシデントの解決日時のX営業日後を取得する必要があった

## 方法
GlideSchedule API のaddメソッドを使えば期待するものは取れそう

### 前提条件
Tokyoで実施
営業日カレンダーはOOTBの`8-5 weekdays excluding holidays`を使用

<img width="800" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/676866/10e2e37a-a274-3019-2c8c-1b33850541b2.png">


### サンプルコード
```JavaScript
    var sch_id = "090eecae0a0a0b260077e1dfa71da828"; // 8-5 weekdays excluding holidays
    var gdt = new GlideDateTime("2023-02-09"); // 元の日付
    var duration = 5; // 営業日数
    var sched = new GlideSchedule(sch_id, "Asia/Tokyo");
    var dur = new GlideDuration(60 * 60 * 9 * 1000 * duration); // 8-5時なので1日を9時間として間隔を定義
    var result = sched.add(gdt, dur);
    gs.info(result);
```
### 実行結果
```text
*** Script: 2023-02-16 00:00:00
```

## 参考
[GlideSchedule API(ServiceNow Developer)](https://developer.servicenow.com/dev.do#!/reference/api/tokyo/server/no-namespace/c_GlideScheduleScopedAPI)
【Mac】コマンドでクリップボードを使用する方法

## クリップボードに保存

`pbcopy`を使用することでクリップボードに保存できます。

```zsh
cat sample.txt | pbcopy
```

## クリップボードからペースト

`pbpaste`を使用するとクリップボードからペーストできます。

```zsh
pbpaste > example.txt
```

## 例

`sample.txt`と`example.txt`を用意します。
それぞれ内容は以下のとおりです。

```sample.txt
これはsample.txt内の文章です。
```

```example.txt
これはexample.txt内の文章です。
```

実際に`pbcopy`と`pbpaste`を使用してみます。

````zsh
$ cat sample.txt | pbcopy

$ pbpaste >> example.txt

$ cat example.txt
これはexample.txt内の文章です。これはsample.txt内の文章です。
````

`sample.txt`の内容をクリップボード経由で`example.txt`に追加できました。
LaravelのクエリビルダにてJOINする際に複数条件でのONをしたいとき


# なにがやりたかったか
aというテーブルとbというテーブルがある。
この2つをJOINにて結合し表示をしたかったが、このとき2つの列を使用し結合しなければ行けない場合がでてきた。
実現したいクエリとしては
```sql
SELECT *
FROM a
JOIN b ON a.id = b.a_id AND a.type = b.type
```
こんな感じ。
これをLaravelのクエリビルダにて実現したかった。

# 最初に試したコード
```php
$query = DB::table('a')
    ->join('b', function ($join) {
        $join->on('a.id', '=', 'b.a_id')->where('a.type', '=', 'b.type');
    })
```
これを実行しクエリを確認したところ以下になっていた。
```sql
SELECT *
FROM a
JOIN b ON a.id = b.a_id AND a.type = 'b.type'
```
なぜかb.typeが文字列として実行されてしまう。
そしてreadoubleなどを見るとON条件が複数の場合の記述が書いていない。
orOnの記述はあるが、andOnがやりたいので、試しにandOnなどを試してみるがそんなメソッドはないと怒られる。
参考 : https://readouble.com/laravel/8.x/ja/queries.html

# 解決したコード
```php
$query = DB::table('a')
    ->join('b', function ($join) {
        $join->on('a.id', '=', 'b.a_id')->on('a.type', '=', 'b.type');
    })
```
これを使用したコードにより解決がされた。
で、これをどこから見つけたかというと
> Add an "on" clause to the join.
> On clauses can be chained, e.g.
> $join->on('contacts.user_id', '=', 'users.id') ->on('contacts.info_id', '=', 'info.id')
> will produce the following SQL:
> on contacts.user_id = users.id and contacts.info_id = info.id
参考 : https://laravel.com/api/5.5/Illuminate/Database/Query/JoinClause.html#method_on:~:text=%24join%2D%3Eon(%27contacts.user_id%27%2C%20%27%3D%27%2C%20%27users.id%27)%20%2D%3Eon(%27contacts.info_id%27%2C%20%27%3D%27%2C%20%27info.id%27)

と書いてあった。
readoubleに書いてなくてパニクったがこういうときはリファレンスがいいわね。
実行環境などはLaravel5以下で試しているがクエリビルダの話なので、多分Laravel8とかでも大丈夫ではあろう・・・
日本語トランスコンパイラ言語 Re:Mind （自作言語）と他言語との構文比較（FOR文）

# はじめに
[前回のIF文の比較](https://qiita.com/mylifewithviolin/items/579e6c9b77dcd2adda0f)で、自作の日本語トランスコンパイラ言語では、条件分岐構文のはじまりとおしまいに全角記号の◇を使うことを開示しました。今回は繰り返し構文のFOR文です。ということは、まさかのまさか！？

日本語トランスコンパイラ言語の詳しい利用シーンのイメージは[こちらへ](https://qiita.com/mylifewithviolin/items/9d58db8a101807c19bde)

## この記事内容の作業目的
[日本語トランスコンパイラ言語 Re:Mind という自作言語](https://qiita.com/mylifewithviolin/items/9d58db8a101807c19bde)の制御構文をターゲット言語のそれと比較して検討する。
if文につづいてfor文。しかもbreak条件はなしとして、あとで考えます。つまり、無限ループの書き方です。

## この記事内容の保証
※この記事には実装的な情報が含まれます。各言語で書かれた引用ソースの妥当性は保証されません。また、開発中（というよりまだ企画段階）の仕様のため、本記事に開示された自作言語の仕様は予告なく変更される場合があります。
# ターゲット言語の構文イメージ
## ターゲット言語とは
プログラミング言語としてのソース言語を日本語を母語とするテキスト(自然文ではない)として、その変換対象となるプログラミング言語のことです。
現在、下記の言語を想定しています。全機能全ライブラリのサポートは目的としておらず、基本的な制御構文のトランスコンパイルが可能なレベルとしています。（独自に対象言語のライブラリはインポートして日本語ラッパ上で使えるようにしたいとうい願望はあり）
* JAVA
* C#
* TypeScript
* Go
このあたりのグループはC言語を祖先として構文似てるかも的な思わくあり。

* VBA（Excel用）
オフィスワーカーにとってステップアップスキルとしてまだまだ需要あり。

* Mind
* DNCL
日本語プログラミング言語グループ。Mindを第1世代の日本語プログラミング言語とすると、なでしこ、ドリトルなどの後発第2世代日本語プログラミング言語のほとんどはDNCLをソース言語とする互換モードを実装されているようなので、とりあえずRe:MindとしてはDNCLをターゲット言語としておけば、第2世代各言語の処理系の実行にはつながるかなという思惑です。

## 各ターゲット言語のFOR文
では、「Re:Mind」 （自作言語リマインド）と他言語との構文比較第2弾として、各ターゲット言語のFOR文を比較して、自作言語のループ文を検討します。
最初に長くならずイメージが比較しやすいよう、breakはなしとして、あとで考えます。また、カウンタ変数を構文中に宣言して、カウントアップ・ダウンを行い、ループ終了に向かっていくような複雑な構文は、また別の機会にゆずるとします。無条件のループ文が書けない言語の場合は、最も単純な等価構文とします。
## JAVA
```java:JAVA
    for(;;){
       //todo
    }
```
## C#
```cs:C#
    for(;;)
    {
       //todo
    }
```
## TypeScript
```ts:TypeScript
    for(;;){
       //todo
    }
```
tsは自信なかったのでPlaygroundで実行してしまいました。エラーにはならずハングアップしてしまいましたので、上記構文OKです。
## Go
```go:Go
    for {
       //todo
    }
```
## VBA（Excel用）
```vb:VisualBasic for Application
    Do While 0=0
        'todo
    Loop
```
VBAにはFor文ありますが、カウンタ変数必須のためDo Whileで代替しました。
## Mind
```mind:Mind
    ここから
        ※todo
    繰り返す
```
## DNCL
```mind:DNCL
    0 ＝ 0 の間，
        //todo
    を繰り返す
```
DNCLは無条件ループ書けないようでした。Do While相当の構文で代替しました。

各言語のFOR構文、または相当構文の間に挟まれているtodoは各言語のコメントアウト符号によるコメントです。
# ソース言語の構文イメージ
## ソース言語のFOR文
## Re:Mind
```mind:Re:Mind
    〇繰り返す
        //todo
    〇ここまで
```
# おわりに
◇や〇を積極的にトークンとして活用するのが、「Re:Mind」（自作言語リマインド）の特徴です。

この企画を実現・設計・実装していくには、スキル上の課題や未獲得の知見など多数あることが予想されます。Qiita様の場をお借りして、獲得したスキルや知見の共有、いたらない点のご支援をいただければと考えています。

# 参考リンク

[Mind プログラミングマニュアル ３ 制御構文](http://www.scripts-lab.co.jp/mind/ver8/doc/03-Control-syntax.html#naraba)

[共通テスト手順記述標準言語 (DNCL) の説明](https://www.dnc.ac.jp/albums/abm.php?d=88&f=abm00001247.pdf&n=%E4%BB%A4%E5%92%8C%EF%BC%93%E5%B9%B4%E5%BA%A6%E8%A9%A6%E9%A8%93%E5%85%B1%E9%80%9A%E3%83%86%E3%82%B9%E3%83%88%E6%89%8B%E9%A0%86%E8%A8%98%E8%BF%B0%E6%A8%99%E6%BA%96%E8%A8%80%E8%AA%9E%EF%BC%88DNCL%EF%BC%89%E3%81%AE%E8%AA%AC%E6%98%8E.pdf)

https://qiita.com/mylifewithviolin/items/9d58db8a101807c19bde

https://qiita.com/mylifewithviolin/items/ebb406bf5ea7a4eea24c
コマンドラインで場所を変えずに他のディレクトリからファイルを実行する方法

下記のディレクトリ構造で、dir1にいる状態で、dir2からコマンドを実行したい時があり、調べたところ簡単に実行できることがわかった。

```
├── dir1
│   └── dir2
```
上記のdir1にいる状態で、dir2からコマンドを実行する場合。

```

user@MacBook-Pro dir1 % (cd dir2 && pwd)
/dir1/dir2
user@MacBook-Pro dir1 % pwd
/dir1

```

上記のようにコマンドに（）をつけると、コマンド実行後もdir1のままでいられる。