OmniAICreator/Qiita-1.07M huggingface dataset:
静電容量式レインセンサを自作した

静電容量式のレインセンサを自作しました。
以前に使っていた電極式のレインセンサは、電極が腐食するデメリットがありました。1年も経たないうちに電極が導通してしまい、常に検出状態になっていました。
どうしても水に電気を流すと電極が腐食されるのは避けられないため、電極が露出していない静電容量方式のレインセンサを作りました。

以下のスイッチサイエンスのページで購入できます。
[スイッチサイエンス - 静電容量式レインセンサ基板](https://www.switch-science.com/catalog/8202/)

![雨センサー表.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/445338/7a08c2d1-9fa6-aa36-9183-abefd5b78e4c.jpeg)


# 基板を設計
基板はKiCadで設計しました。
回路構成としては、2端子あるためこの様にしました。
![2022-06-19 (4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/445338/e22a5d83-1d6e-96dc-c86d-e28fa7a900fa.png)

PCBのデザインはこんな感じです。
![2022-06-19 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/445338/f4f665a9-16eb-9979-ecfc-3638cc58cf7f.png)

KiCadでガーバーデータを出力し、Fusion PCBに発注しました。
基板は発注から2週間程度で送られてきました。
![DSC_0201 (2).JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/445338/232e134e-bec8-bed7-e41a-876c8971d8fc.jpeg)
プリント基板の発注方法は、以下のサイトが参考になります。
[KiCADからガーバーファイルを出力する方法](https://www.fusionpcb.jp/blog/?p=1178)
[プリント基板の自作！簡単にできる格安オーダーメイド法](https://xn--p8jqu4215bemxd.com/archives/18938)

# 静電容量検出回路の設計
センサの静電容量値を測定するための検出回路は以下になります。センサーをSensor Inに接続し、Pulse Outをマイコンなどの入力に接続します。LOWパルスの長さを測定することで、現在の静電容量値を読み取ることができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/445338/658d7a97-51e0-89d3-b843-adeb772058ab.png)

# 静電容量パルス測定用プログラム
Arduino UNO 用のサンプルスケッチです。
2番ピンにパルス出力を接続します。雨を検出すると13番のLEDが光ります。
```RAIN_THR```の値がしきい値になっています。この値を変更することで、感度を調節できます。範囲は```0~255```で、```0```に近づけるほど感度が良くなり、```255```に近づけるほど感度が悪くなります。このプログラムは雨が落ちたかどうかを検出します。雨が降るとセンサが反応しますが、雨粒が落ちないと反応しないようになっています。雨粒が落ちると再度反応します。
```c:rain.ino
#define RAIN_IN_PIN 2
#define RAIN_OUT_PIN 13

#define TIMEOUT_US 100000
#define R_K_OHM 100.0
#define SAMPLES 100

#define LOWPASS_CAP 0.995
#define LOWPASS_RAIN 0.9
#define LOWPASS_MAX 1.0
#define CAP_AMP 0.2
#define CAP_MAX 255.0
#define RAIN_AMP 100.0
#define RAIN_MAX 255.0
#define RAIN_THR 20.0

float rain;
float cap;
float cap_before;

void setup(){
  rain = 0;
  cap = 0;
  cap_before = 0;
  pinMode(RAIN_OUT_PIN, OUTPUT);
}

float get_cap(){
  return (float)pulseIn(RAIN_IN_PIN, LOW, TIMEOUT_US) * (1000.0 / R_K_OHM) / log(2);
}

void loop(){
  cap_before = cap;
  cap = 0;
  for(int i = 0; i < SAMPLES; i++){
    cap += get_cap();
    delayMicroseconds(100);
  }
  cap = constrain(cap_before * LOWPASS_CAP + cap * CAP_AMP * (LOWPASS_MAX - LOWPASS_CAP) / SAMPLES, 0, CAP_MAX);
  rain = constrain(rain * LOWPASS_RAIN + max(cap - cap_before, 0) * RAIN_AMP * (LOWPASS_MAX - LOWPASS_RAIN), 0, RAIN_MAX);
  if(rain > RAIN_THR){
    digitalWrite(RAIN_OUT_PIN, HIGH);
  }
  else{
    digitalWrite(RAIN_OUT_PIN, LOW);
  }
}
```
React 18 にアップグレードする

# React 18 にアップグレードする

仕事で、React 16 or 17 -> React 18 にアップグレードするお祭りがあったので、備忘録です。
公式で、["How to Upgrade to React 18"](https://reactjs.org/blog/2022/03/08/react-18-upgrade-guide.html) というドキュメントが公開されているので参考にしてください。

## 1. React 18 にアップグレード

方法は、三つくらいあります。(たぶんもっとあると思います。)

1. `npm install react react-dom`
1. `yarn add react react-dom`
1. `yarn upgrade react react-dom @types/react @types/react-dom --latest`

[公式の記事](https://reactjs.org/blog/2022/03/08/react-18-upgrade-guide.html)は、1,2 が紹介されています。

## 2. index.tsxの書き換え

React 18 では、Client Rendering APIs のアップデートが必要です。
具体的には、`ReactDom.reder` は React 18 ではサポートされていません。

```typescript
// React 17以前
import ReactDom from "react-dom";
import App from "./App";

ReactDom.render(<App />, document.getElementById("app"));
```

```typescript
// React 18以降
import ReactDOM from "react-dom/client";
import App from "./App";

const container = document.getElementById("app");
if (container) {
  root.render(<App />);
}
```

もしくは、

```typescript
import { createRoot } from 'react-dom/client';
const container = document.getElementById('app');
const root = createRoot(container); // createRoot(container!) if you use TypeScript
root.render(<App tab="home" />);
```

のように書き直す必要があります。
二つ目のは、公式のものです。
TypeScriptのnon-null warning が出力されるので、`container!` と書く必要があるみたいです。

## 3. React.FC の書き換え

>If your project uses TypeScript, you will need to update your @types/react and @types/react-dom dependencies to the latest versions. The new types are safer and catch issues that used to be ignored by the type checker. The most notable change is that the children prop now needs to be listed explicitly when defining props, for example:

[公式の記事](https://reactjs.org/blog/2022/03/08/react-18-upgrade-guide.html)

上のように、children propsは明示的に渡す必要があります。

```typescript
// React 18以前
const HogeComponent: React.FC = () => {}
return (
   <HogeComponent>
     <div> hoge </div>
   </HogeComponent>
)
```

```typescript
// React 18以降
interface HogeProps {
    children: React.ReactNode
}
const HogeComponent = (props:  HogeProps) => {}
return (
   <HogeComponent>
     <div> hoge </div>
   </HogeComponent>
)
```


## 4. TypeScript の型エラー修正

TypeScriptのバージョンを上げたので、Class を使用している場合は型エラーが起きる場合があります。
スミルノフ・グラブス検定

# grubbs検定

標本が正規分布に従うとき外れ値判定する方法にスミルノフ・グラブス検定がある。

今、正規分布に従う標本$X_1, X_2, \dots, X_n$がある。このなかの最大値$X_n$が外れ値であるか検定する。

```math 
T = { X_n  - \bar X \over \sqrt{ \text{Var}(X) } } \\
s_0 = (N-1) \sqrt{ t_0^2 \over  N(N-2)+N t_0^2 }
```

このとき$ s_0 > T $であれば外れ値である。

ここで$t_0$は両側検定の場合、自由度$N-2$の$t$分布の$\alpha/2N\times100$パーセンタイル点である。片側検定の場合には、$\alpha/N\times100$パーセンタイル点とする。

$\text{Var}(X)$は不偏分散である。

以下のmatlabスクリプトは以上の計算を行う。matlabのisoutlier関数で同じ計算を行えるのであわせて結果を示す。なおここでは$s_0$をデータと同じスケールに変換し結果を示している。

計算の一例を下記にしめす。標本を正規分布からサンプルしているが、$N=8$, $\alpha=0.05$の両側検定の場合、わりと頻繁に外れ値と検定される(5%の確率で第一種の過誤となるはずであるから当然である)。

```terminal 
 データ  0.03  -0.80  -2.15  1.84  -2.75  -0.93  0.45  0.00 
 この値以上であれば外れ値: 2.571601 ( matlabのgrubbs検定の値 2.571601 )
```

```matlab 
N = 8;
X = randn( N-1, 1 );
X(end+1) = 0;
[TF, Lo, Up, C] = isoutlier(X,'grubbs' );
Xbar = sum(X)/N;
U = var(X);
maxX = max(X);
T = (maxX-Xbar)/( sqrt( U ) );

t0 = tinv(0.05/(2*N), N-2); % 両側検定  
s0 = (N-1)*sqrt( t0^2/(  N*(N-2)+N*t0^2 ) );

fprintf( ' データ ' );
fprintf( ' %4.2f ', X );
fprintf( '\n' );
fprintf( ' この値以上であれば外れ値: %f ( matlabのgrubbs検定の値 %f )\n', s0*(sqrt(U))+Xbar, Up );
```

以上
LANケーブルについて

LANケーブルについて改めて調べると、「より対線」などあまり理解していなかったことに気づいた。
なので、ここでは簡単に規格などについてまとめることにした。

より対線とは
---
より"たいせん"ではなくより"ついせん"と読む。
これは一対（2本）の銅線をより合わせて作るから。ツイスト・ペアケーブルとも呼ぶ。
よく使われるUTPケーブルは「非シールドより対（Unshielded Twisted Pair）」のこと。

ここで疑問なのは、なぜより合わせる必要があるのかということ。
それは外部からのノイズの影響を打ち消す為。

詳細は参照ページを見て欲しい。

[参照]https://xtech.nikkei.com/it/article/COLUMN/20060530/239398/

外部からのノイズを防ぐ手段は他にもシールドで覆ってしまう方法もあるのだが、
こちらだとケーブルが太くなり扱いにくくなる上にコストも高くなる。
安くノイズの影響を抑えるにはより合わせるのがピッタリという訳だ。

LANケーブルのカテゴリー
--
より対線の意味が分かったところで、LANケーブルのカテゴリーを見てみる。
カテゴリーは規格のことであり、数字が大きいほど高性能になる。
伝送速度が高くなり、帯域も広くなっていく。

|  | IEEE規格 | 伝送速度（ビット/秒） | 対応ケーブル |
|:-:|:-:|:-:|:-:|
|100BASE-TX|IEE 802.3u|100M|カテゴリー5以上|
|1000BASE-T|IEEE 802.3ab|1G|カテゴリー5e以上|
|2.5GBASE-T|IEEE 802.3bz|2.5G|カテゴリー5以上|
|5GBASE-T|IEEE 802.3bz|5G|カテゴリー6以上|
|10GBASE-T|IEEE 802.3an|10G|カテゴリー6A以上|

実はカテゴリーは性能だけで決まり、構造については規定されていない。
そのためメーカー毎に構造に違いがあることもある。
だが、実際には定められた性能を満たすように各メーカーで似た構成になることが多いようだ。

例えば、カテゴリー6Aのケーブルの場合では10Gの速度を出すためにより合わせに
加えてシールドで覆うSTP（Shielded Twisted Pair）タイプになることが多い。

> 参考 日経NETWORK 2022年6月号

まとめ
--
LANケーブルについて簡単にまとめてみた。
物品を用意する際は、求める伝送速度・帯域に合ったケーブルを選定することが必要になる。
後から要件を満たしていないことが発覚する、なんてことを避けるためにしっかり要件にあった
ケーブルを選びたい。
【#7 エンジニア転職学習】Linux基礎　パーミッション, su/sudo

# はじめに
富山県に住んでいるChikaといいます。
毎日投稿を目標に、バックエンドエンジニア転職に向けた学習内容をアウトプットします。

昨日に引き続き、Linuxの基礎を進めましたので自分なりに気になったポイント等をまとめていきます。

バックエンドエンジニアになるまでの学習内容は以前投稿した以下の記事を基にしています。


https://qiita.com/Chika110/items/ef54dddd565a0193ef44

# 本日の学習内容
本日はパーミッション、su/sudo、プロセス・ジョブ、標準入出力・パイプラインの範囲をやりました。

* **ファイル・ディレクトリのパーミッション　←Topic!!**
* **su/sudo　←Topic!!**
* プロセス・ジョブ
* 標準入出力・パイプライン

# パーミッション、スーパーユーザ
権限付与関連でチーム開発をしているわけでもないので、今は関係ないかなとサラっと流していたので初めて知った情報もありました。

## パーミッション
ファイル・ディレクトリそれぞれにr,w,xの記号が用意されているが、意味が微妙に違う。
注意すべき点として**ファイルが削除できるかどうかは、そのファイルがあるディレクトリのパーミッションwが付与されているかどうか**で決まる。
**※ファイルでwを設定しても関係なし**

## スーパーユーザ
* 環境変数を持ち込まないように`su -`コマンドを使用する
* /etc/sudoersファイルを編集するときは`visudo`で編集する（編集ミスを防ぐため）

使用している書籍はこちら↓

https://www.amazon.co.jp/%E6%96%B0%E3%81%97%E3%81%84Linux%E3%81%AE%E6%95%99%E7%A7%91%E6%9B%B8-%E4%B8%89%E5%AE%85-%E8%8B%B1%E6%98%8E-ebook/dp/B072K1NH76/ref=sr_1_1?adgrpid=113196705062&gclid=Cj0KCQjwzLCVBhD3ARIsAPKYTcR4WAb_4QVrwuBM_1mIPMFsQ6kNDJ-o4yIofVSAI7_eHpWCeva8kKwaAstgEALw_wcB&hvadid=489559881279&hvdev=c&hvlocphy=1009363&hvnetw=g&hvqmt=e&hvrand=10125867468998217428&hvtargid=kwd-1152146940662&hydadcr=21814_10996132&jp-ad-ap=0&keywords=%E6%96%B0%E3%81%97%E3%81%84+linux+%E3%81%AE+%E6%95%99%E7%A7%91%E6%9B%B8&qid=1655473534&sr=8-1




# おわりに
最後までお読みいただきありがとうございました。
明日も引き続きLinuxの基本を進めていこうと思います。
アドバイス・応援コメント等いただけますと幸いです。
【知的生産力が劇的に高まる最強フレームワーク】ビジネス技術書紹介①

# 買ってよかった技術書の紹介１
## 知的生産力が劇的に高まる最強フレームワーク
著者：永田　豊志さん

ビジネスにおけるフレームワークが100個載ってます。
紹介の仕方が、2ページに見開きで1個、もしくは4ページで1個を
概要レベルとどのような仕組みなのかを紹介しています。

仕事の順位の付け方やマーケティングの方法や
企業の分析（4C分析、4P分析等）、アイデアの整理の仕方等。

何かの仕事をしている上では、何か利用できるセンテンスが引っかかる
そんな本です。
どこかで1冊なくしてしまいましたが、もう一度買ってしまいました。
ほんとに何か悩んだらとりあえず読んで何か利用できるものがないかと探す本です。

コンサルタントであれば、持っていて損はない本です。
プロジェクトに係る人であれば、お客さんがどんなものを重視しているかなどが分かってくる。
そんな本です。

アマゾンはこちら。
https://www.amazon.co.jp/%E7%9F%A5%E7%9A%84%E7%94%9F%E7%94%A3%E5%8A%9B%E3%81%8C%E5%8A%87%E7%9A%84%E3%81%AB%E9%AB%98%E3%81%BE%E3%82%8B%E6%9C%80%E5%BC%B7%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E3%83%AF%E3%83%BC%E3%82%AF100-%E6%B0%B8%E7%94%B0-%E8%B1%8A%E5%BF%97-ebook/dp/B00GJGOEXI

イベント参加中
https://qiita.com/official-campaigns/engineer-festa/2022
星評価実装で役に立つサイト

★jQuery Raty - A Star Rating Plugin (current version: 1.4.3)

https://www.alpinestyle.co.il/media/vendor/jquery.raty-1.4.3/

★星評価実装

https://kodocode.net/design-js-raty/

★【Rails】raty.jsを使った評価機能を作る

https://qiita.com/d0ne1s/items/10c2c2c05449b73b099d

★【Rails】raty.jsを用いた星5レビュー機能の実装

https://qiita.com/kcl215/items/e226ac58d14360fd1b8e


 <div id="star-rate<%= book.id%>"></td>
          
          <script>
            $('#star-rate<%= book.id %>').empty();
            $('#star-rate<%= book.id%>').raty({        // ('div').data.('raty').score/half/etc...();という意味で定義していると思われる
              size      : 36,
              starOff   : '<%= asset_path('star-off.png') %>',
              starOn    : '<%= asset_path('star-on.png') %>',
              half      : false,
              readOnly: true,
              score: '<%= book.star %>',//この部分は 「' '」これが抜けてる記事が多かった。 エラーになる可能性有り
            });
          </script>
          </div>
フォールスポジティブ と フォールスネガティブ

## 勉強前イメージ

ポジティブ？いいこと？

## 調査

### フォールスポジティブ とは

セキュリティ製品のfirewallやIPSなどは、怪しい通信があるとブロックしてくれたりします。
自動で実施してくれることが多いですが、たまに正しい通信でも間違って不正な通信と判断してブロックしてしまうことがあります。
これを `フォールスポジティブ` といいます。

セキュリティ製品の誤検知についてですが、フォールスポジティブの他にフォールスネガティブというのもあります。

### フォールスネガティブ とは

セキュリティ製品の誤検知で
不正な通信を正常と判断して通してしまうことを `フォールスネガティブ` と言います。
不正な通信を通してしまうので、フォールスポジティブより影響が大きくなってしまい
セキュリティとしてはネガティブな方に傾くのでこの名前がついています。

セキュリティの基準は1か0ではなく
基準を厳しくすれば安全性を高めることができる反面、正しい通信をブロックするフォールスポジティブが増え
基準をゆるくすれば正しい通信を通すことができる確率は高くなる反面、不正な通信を通してしまうフォールスネガティブが増え
トレードオフの関係にあります。

## 勉強後イメージ

セキュリティ観点でポジティブなのかネガティブなのかっていうこと考えれば
確かに・・・ってなる。

## 参考

- [フォールスポジティブとフォールスネガティブの違いは？](https://itmanabi.com/false-positive-negative/)
- [フォールスネガティブ 【false negative】 偽陰性](https://e-words.jp/w/%E3%83%95%E3%82%A9%E3%83%BC%E3%83%AB%E3%82%B9%E3%83%8D%E3%82%AC%E3%83%86%E3%82%A3%E3%83%96.html)
【Git】.gitignoreって難しい Part3 - .gitignoreの作成未経験者が、ある程度の理解できるまで -

# .DS_Storeについて
Macのシステムが各ディレクトリ（Finder）に勝手に生成する隠しファイルです。
こちらのファイルは、gitで管理しないのが一般的です。
## 補足
上記の通り、<b>Macのみ</b>で起きる現象のため、プロジェクトの<code>.gitignore</code>ではなく、<code>.gitignore_global</code>で設定をしてください。
<code>.gitignore_global</code>は<b>PCに存在するGitリポジトリの設定</b>が行えます。
# 設定方法
## .gitignore_global ファイルを作成
viコマンドで編集していきます。
```
$ vi ~/.gitignore_global
```
## .gitignore_globalファイルに.DS_Storeを追加
```
.DS_Store
```
## Gitの設定を追加
```
$ git config --global core.excludesfile ~/.gitignore_global
```
### 設定を確認
```
$ git config --global -l
```
<code>core.excludesfile=/Users/hoge/.gitignore_global</code>と表示出来ていれば完成です。
[shell script]ファイル一覧と行数をCSVファイルに出力する

標題の通りに、指定されたフォルダからファイルの一覧を取得する。
```shell:「ShellScript」と記述
#!/usr/bin/bash

#ファイルパスを指定する
filePath=$'H:/GitLab/fukushisource/fukushisource/SourceFiles/QAA/WebUI'
#行数を定義する（数値）
declare -i filelines=0
#出力結果を格納する変数を定義する
declare output=""
#改行を定義
LF=$'\n'
#フォルダを定義
folder=""
#ファイル名を定義
fileName=""
#拡張子を定義
expand=""

#フォルダ・ファイルごとに処理する
while read -r strpath; do

  #パスがファイルであるかを判定する
  if test -f $strpath;then
     #ファイル名を取得する
     fileName=`basename $strpath`
     #拡張子を取得する
     expand=${strpath##*.}
     #CS・ASPX・XMLファイルの場合のみ後続の処理を行う
     case "$expand" in 
        "cs" | "aspx" | "xml" |"CS" | "ASPX" | "XML" )
          #対象ファイルの行数を数える
          filelines=`sed -n '$=' $strpath`
          #count=$(wc -l $strpath)
          #1回目の場合
          if [ -z "$output" ];then
             output="$strpath,$folder,$fileName,$filelines"
          #2回目以降の場合
          else 
             output="$output$LF$strpath,$folder,$fileName,$filelines"
          fi
     esac
  else
     #パスの最後のディレクトリ名を抽出する
     #folder=`echo ${f} | awk -F "/" '{ print $NF }'`
     folder=`basename $strpath`
  fi
  

#サブディレクトリを見ない
#done < <(find ./hoge -mindepth 1 -maxdepth 1)
#サブディレクトリを見る
done < <(find $filePath -mindepth 1)

#出力結果をcsvファイルに書き込み
echo "$output" > output.csv
```
【PHP基礎⑭】ループ処理-4.カウントダウン

［問題］　　(参照：http://www.cc.kyoto-su.ac.jp/~mmina/bp1/hundredKnocksBasic.html)
整数値を入力させ、入力値から0まで数を1ずつ減らして表示するプログラムを作成しなさい。
なお、入力値に0以下の値を入力した場合は考慮しなくてもよい。


# コード
```php
$a = intval(fgets(STDIN));
for($m = $a; $m >= 0; $m--){
    echo "$m \n";
}
```

↓「7」と入力

# 結果
```
7 
6 
5 
4 
3 
2 
1 
0 
```

☆1ずつ減らす→　＄m--
Migrationファイルなどを作成中！

## さて、環境構築できたから次へ
昨日作成できたLaravelにマイグレーションファイルを作成していきます。
`$ ./vendor/bin/sail artisan make:migration create_テーブル名_table`
これを打つことにより、作成ができる。必要なテーブル数分ファイルも作成されるということになりますね！
早速作成してみると・・・![6e8de5be078feba4e3a201a911e81014.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2712684/56a63f92-f8ac-a43c-3729-6f793e7ba14f.png)
現状では色々記述を変更したりしているので少し違いますけど、大体に多様な記述がされています。
ここで1番びっくりしたのは、SQLの形式を指定しておかないと日本語対応してくれないので変なものが挿入されてしまう・・・
慌ててリファレンスなどを参考に書き直し・・・
そして、もう一つ気づいたのは、
` $table->id()`の状態のままだとbigIntとなってしまう。
記述を`increments('id')`へと変更。
ここで、癖でやってしまったことがあります。
stringの指定しかないのに記述をvarcharとしていたところ・・・エラー吐きますよね・・・
これも注意点の一つだと思いました。
### rollbackやりすぎ
色んなところを間違えたり、テーブル名を入れるところがそもそも間違っている・・・
そんなことを繰り返しやっていたので、rollbackを何度もやっていました。
Laravelリファレンスを見ていたところ
`./vender/bin/sail artisan migrate:refresh`を使用すると今まで作成してあったテーブルを削除して、もう一度テーブルを作り直してくれるというもの。
詳しくは[リファレンスを参照](https://readouble.com/laravel/8.x/ja/migrations.html)した方が良いかと思われます。
簡単に解説しておくと
- freshはテーブルを削除して、migrateを実行
- refreshはロールバックを実行して、migrateを実行

どちらがいいのか実際は触りきってはませんが、refreshがいいのかな〜？と感じて実行をしました。
## 続けてModelクラスも作成！
`./vendor/bin/sail artisan make:model モデル名`
こちらのモデル名というところには、テーブル名と結びついた名前を定義すると・・・
Laravelが自動で判断してくれるという素晴らしい機能！！！
- テーブル名には複数系の名前を定義
- モデル名には単数系の名前を定義

明日も開発に取り組んでいく予定です！
間違いなことがあれば、Twitterなどでお話をしてくれると幸いです！！！
JibのDockerベースイメージのバージョンを固定してみた

# はじめに

こんにちは！毎日あれこれくだらないことを思い巡らすシステムエンジニアのfengdidiです。
本日はJibのDockerベースイメージのバージョンを固定する方法をご紹介させていただきます。

# Dockerベースイメージのバージョンを固定する理由

先日、Google Jibを使ってSpringbootのプロジェクトをデプロイしていました。

> Jibは、Javaアプリケーションの構成を読み取り、ビルドプロセスの中でJDKが入っているベースイメージにJavaアプリケーションを加えてコンテナイメージを生成し、Dockerコンテナのレジストリへの登録まで自動的に行ってくれるビルドツールです。

Jibは非常に便利ですが、JibはデフォルトでDockerベースイメージを固定しないので、Jibのバージョンにより、ビルドする時に使うDockerベースイメージは違う可能性があります。


Jibの公式ドキュメントによりますと、

> Starting from version 3.2, the default base image is the official eclipse-temurin image on Docker Hub. Note that Eclipse Temurin by Adoptium is the successor of AdoptOpenJDK. (For versions 3.0 and 3.1, the default is the official adoptopenjdk image.) For WAR projects, the default is the official jetty image on Docker Hub.

要するに、Jib3.2以上の場合はeclipse-temurinというOpenJDKが入っているベースイメージは使われているのですが、3.0及び3.1の場合はadoptopenjdkが使われているようです。

ここで仮にJibのバージョンをアップグレードすると、ビルドする際に使うベースのDockerイメージも勝手にバージョン変更されます。開発環境だと別に気にならないとは思いますが、本番環境の場合は嫌だと思われる方が多いのではないでしょうか。本番環境は安定性が一番大事なので、やはり皆さんはできるだけ本番環境に安定させたいですよね。

それでは、Dockerベースイメージのバージョンの固定方法を見てみましょう。

# Dockerベースイメージのバージョンを固定する

※今回の開発環境はSpringboot、Gradle、Jibになります。

手順は3つあります。

1. GradleでJavaのバージョンを指定する
1. ベースイメージのイメージ名とタグを固定する
1. ベースイメージのハッシュまで固定する

## 1. GradleでJavaのバージョンを指定する

まずは、下記のようにJavaのバージョンを指定しましょう。

build.gradleファイルに下記のソースコードを追加します。
```
sourceCompatibility = 11
targetCompatibility = 11
```
こうすると、Javaのバージョンを11に固定できます。Jibはビルドする時にこの設定を見て、とりあえずJavaメジャーバージョン11のベースイメージを使うようにします。

## 2. ベースイメージのイメージ名とタグを固定する

Javaのベースイメージは色んな種類があるので、Javaメジャーバージョンを固定することだけでは勿論足りないと思いますので、次はベースイメージのイメージ名とタグを固定してみましょう。

まずは、固定するイメージ名とタグを決めなければなりません。私の場合はJibの公式ドキュメントが推奨するイメージ名とタグを使用しようと思いますので、イメージ名はeclipse-temurinにします。次はイメージのタブを決めます。

ちなみに私は、以下の3つの条件があるので、Dockerhubにあるeclipse-temurinの公式サイトに訪問して、11-jre-alpineを選びました。
1. LinuxベースのDockerイメージを使いたい
2. JDKではなく、より軽量なJREを使いたい
3. Java11を使いたい

そして、このイメージ名とタグを設定します。

build.gradleファイルのビルドの部分に下記のような設定を加えます。

```

jib {
  from.image = 'eclipse-temurin:11-jre-alpine' // こちらはイメージ名とタグです。
  ...
}
```

## 3. ベースイメージのハッシュまで固定する
ベースイメージのイメージ名とタグを固定すれば、Dockerイメージの出品先及びJavaのメジャーバージョンは固定されます。
但し、それでも足りないと思う方はいらっしゃるでしょう.
例えば、Javaメジャーバージョンを11に固定しても、細かいバージョン番号（小数点以下の数字）を固定していないので（時間によって変わる）、昨日検証環境にリリースした時に、Java11の最新バージョン番号は11.0.9であったので、検証環境のJavaバージョンは11.0.9になりました。そして、ちょうど本日はJavaバージョン11.0.10が出ました。そして明日、本番環境にリリースすれば、本番環境のJavaバージョンは11.0.10になるわけです。

そうなると、検証環境のJavaバージョンと本番環境のバージョンは一致しなくなってしまいます。場合によっては、それは危険な可能性があるので、次は細かいバージョンまで固定してみましょう。

Dockerのイメージは、SHA Digestという唯一無二の識別子であるので、SHA DigestをさらにGradleの設定ファイルに設定すると、Dockerのイメージのバージョンを確実に固定できます。
ソースで言うと、下記のようなイメージです。

```
jib {
  from.image = 'eclipse-temurin:11-jre-alpine@sha256:5fa1c745e68287a0f6fdd68aefbb89f139bd6a028007a22c6ed8e8b6be00457f' // こちらはイメージ名とタグとダイジェストです。
  ...
}
```

ここまでにすれば、Jibビルドする時に必ず同じベースイメージ、OS及びJavaバージョンを使えるようになります。

# 最後に

以上です～！最後までご覧頂きありがとうございます！
記事内容への意見などがあれば是非コメント欄にお願いします！
なお、Qiitaへの投稿は初めてなので色々な齟齬があるかもしれませんが、お手柔らかにお願い致します〜！
【PHP基礎⑬】ループ処理-3.カウントアップ

［問題］　　(参照：http://www.cc.kyoto-su.ac.jp/~mmina/bp1/hundredKnocksBasic.html)
整数値を入力させ、0から入力値まで数を1ずつ増やして表示するプログラムを作成しなさい。
なお、入力値に0以下の値を入力した場合は考慮しなくてもよい。


# コード
```php
$a = intval(fgets(STDIN));
for($m = 0; $m <= $a; $m++){
    echo "$m \n";
}
```

↓「7」と入力

# 結果
```
0 
1 
2 
3 
4 
5 
6 
7
```
@AuraEnabled(cacheable=true)

エラーメッセージ：LWC LimitException: Too many DML statements: 1
number of DML statements:1 out of 0 ******* close to limit.

正常：number of DML statements:1 out of 150.

■実行時のパフォーマンスを改善するには、@AuraEnabled(cacheable=true) を設定してクライアントにメソッドの結果をキャッシュします。cacheable=true を設定するには、メソッドがデータの取得のみを行う必要があります。メソッドでデータを変更することはできません。

Link：
https://developer.salesforce.com/docs/atlas.ja-jp.234.0.lightning.meta/lightning/controllers_server_apex_auraenabled_annotation.htm

■LWCで呼び出すApexメソッドを作成します。
@Wireサービスで使用するApexには下記が必要です。

static
publicまたはglobal
@AuraEnabled(cacheable=true)

Link:https://qiita.com/TaaaZyyy/items/51908546c423661ff033
M1 macでAWS session managerを使っていてunknown error number 86というエラーが出たら

## TLDR
- xcodeをインストール、または最新にアップデートしましょう。

## 概要
AWS SSOを使ってEC2にsshしていたのですが突然 `ssh_exchange_identification: Connection closed by remote host`というエラーが出て接続できなくなってしまいました。

一見`ssh`コマンドでエラーが出ていたのでssh関連かな？と`~/.ssh/config` やpermission周りを疑っていたのですが `session-manager-plugin` コマンドを入力すると `exec: Failed to execute process '/usr/local/sessionmanagerplugin/bin/session-manager-plugin', unknown error number 86` というエラーが出るようになっていることに気づきました。

少しネットで調べてみるとsession-manager-pluginのissueに 


>After running the following command, session-manager-plugin works:
softwareupdate --install-rosetta --agree-to-license

https://github.com/aws/session-manager-plugin/issues/26#issuecomment-1146688835

のように書いてあったのでXcodeをアップデートしたら無事なおりました。
この手のエラーは地味ハマりますね。。
【PHP基礎⑫】ループ処理-2

［問題］　　(参照：http://www.cc.kyoto-su.ac.jp/~mmina/bp1/hundredKnocksBasic.html)
整数値を入力させ、その値の回数だけHello Ruki!を繰り返して表示するプログラムを作成しなさい。


# コード
```php
$a = intval(fgets(STDIN));
for($m = 1; $m <= $a; $m++){
    echo 'Hello Ruki!',PHP_EOL;
}
```

↓「5」と入力

# 結果
```
Hello Ruki!
Hello Ruki!
Hello Ruki!
Hello Ruki!
Hello Ruki!
```


☆＄m++は＄m=＄m+1と同じなので、
　2ずつ増やしたい時は＄m = ＄m+2とする。
　または、＄m+=2 でもOK。

↓　2ずつ増やした場合(入力値は「5」）

```php
$a = intval(fgets(STDIN));
for($m = 1; $m <= $a; $m = $m+2){
    echo 'Hello Ruki!',PHP_EOL;
}
```


結果
```
Hello Ruki!
Hello Ruki!
Hello Ruki!
```
逆sshfs

<h2>はじめに</h2>
sshfsでローカルのディレクトリをサーバーにマウントします。　

<h2>注意点</h2>
ローカルのディレクトリをマウントしているのでネットワークの環境によっては遅いかもしれません。

<h2>環境</h2>
<h3>Server</h3>
Amazon Lightsailを使用

|項目|内容|
|:---|:---|
|OS|Amazon Linux2|

<h3>Local</h3>
Macを使用

|項目|内容|バージョン|
|:---|:---|:---|
|OS|MacOS Big Sur|11.2.3|

<h2>Server設定</h2>
Macのターミナルを使って、sshでサーバー入り作業します。
<br>
<br>
<br>
EPEL レポジトリをインストール

```
sudo amazon-linux-extras install -y epel
```
<br>
<br>
fuse-sshfsパッケージをインストール

```
sudo yum install -y fuse-sshfs
```
<br>
<br>
マウント先のディレクトリを作成

```
mkdir /home/ec2-user/test-server
```

<h2>Local設定</h2>
システム環境設定 > 共有 > リモートログインを許可（オン）します。

![img1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1572/412dad7f-fe2c-1d65-d5a6-06e20e7825ed.png)


SSH接続情報を用意
```
vi ~/.ssh/config

Host sshfs-test-server
        HostName {ServerのIP}
        User ec2-user
        IdentityFile ~/.ssh/{ServerのSSHキー}
```
<br>
<br>
マウント元のディレクトリとテスト用のファイルを用意

```
mkdir /Users/{Macのログインユーザー名}/test-local
cd /Users/{Macのログインユーザー名}/test-local
date >test.txt
```

<h2>確認</h2>
sshでサーバーに入ります。

```
ssh sshfs-test-server -R 10022:localhost:22
```
<br>
<br>
サーバーで下記コマンドを実行して、ローカルのディレクトリをマウント

```
sudo sshfs -p 10022 -o idmap=user,nonempty,allow_other,uid=1000,gid=1000 {Macのログインユーザー名}@127.0.0.1:/Users/{Macのログインユーザー名}/test-local /home/ec2-user/test-server
```
<br>
<br>
パスワードを聞かれるので、<font color="red">Macのログイン時に入力したパスワード</font>を入力します。

```
Password: {Macのログイン時に入力したパスワード}
```
<br>
<br>
/home/ec2-user/test-server 内に Mac側で作成した test.txt がマウントされてます。
<br>
Server側で編集しても、Mac側で編集しても、編集内容が反映されます。

<h2>マウント解除</h2>
Server側で下記コマンドを実行するとマウントが解除できます。

```
sudo umount sshfs-test-server /home/ec2-user/test-server/
```

<h2>最後に</h2>
私はdockerの経験が浅かったので、問題が起きた時にdocker以外なら動くのかの確認をする為に使用してました。　サーバーは構築できるので準備しておき、マウントする際はnginxが指してるディレクトリにマウントして確認をしてました。
AmazonHttpClientにて、プロキシが自動で設定されてしまうことにハマった


## 背景
ある日、DynamoDBをローカルで動かすようなプログラムをいつものように実行したら、プロキシ関係のエラーではまった。
結局は単純だったが、かなり時間かけてしまったので、ほかに自分みたいな人間が生まれないように、記録。

## 起きたこと

JavaプログラムからAWS SDkを使用して、Awsのサービスにアクセスしようとした。
これまでは、問題なくアクセスできていたが、サービスにアクセスできない事態が発生。

スタックトレースには、以下のエラーが発生。
```console
com.amazonaws.services.dynamodbv2.model.AmazonDynamoDBException: null (Service: AmazonDynamoDBv2; Status Code: 502; Error Code: null; Request ID: null; Proxy: proxy.*****)
	at com.amazonaws.http.AmazonHttpClient$RequestExecutor.handleErrorResponse(AmazonHttpClient.java:1862)
	at com.amazonaws.http.AmazonHttpClient$RequestExecutor.handleServiceErrorResponse(AmazonHttpClient.java:1415)
	at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeOneRequest(AmazonHttpClient.java:1384)
	at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeHelper(AmazonHttpClient.java:1154)
```

## 原因
少し前にAWS CLIからインスタンスの起動と停止をできるように、システム環境変数に
- HTTPS_PROXY
- HTPP_PROXY

を追加した。


以下に記載があるが、AmazonHttpClientは、システムプロパティと、システム環境変数を見にいくような実装になっている。


https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/ClientConfiguration.html


そのため、意図しない形で、プロキシ設定が対象のアプリケーションに設定されてしまっていた。



AmazonDynamoDB のクライアント作成メソッド内で、
引数のclientConfigurationは特に何も指定せずデフォルトでクライアントビルダーを生成している。
そしてAmazonDynamoDBClient.build()を実行すると、内部的に、SystemのProperty("http.proxyHost")と同期され、
設定されていなければ、SystemのEnv(HTTP(S)_PROXY)と同期しに行くようになっている。
私達はすでにDDDを実践している、かもしれないという話（Spring編）

表題の一解釈について発表させていただきます。

先日、Wikiでドメイン駆動設計（DDD）の記事を目にしました。
https://ja.wikipedia.org/wiki/%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E9%A7%86%E5%8B%95%E8%A8%AD%E8%A8%88

その冒頭に、次の要約が載っていました。

>ドメイン駆動設計（英: domain-driven design, DDD）とはソフトウェアの設計手法であり、「複雑なドメインの設計は、モデルベースで行うべき」であり、また「大半のソフトウェアプロジェクトでは、システムを実装するための特定の技術ではなく、ドメインそのものとドメインのロジックに焦点を置くべき」であるとする。

とりあえず、"モデルベースで行うべき"という点には賛成です。実際、ビジネスサイドの人と話をする時は、四角と線でできた簡単な図を、ホワイトボードに書いたりして打ち合わせします。

・・・この時点でもう、私達はすでにDDDを実践しているような気がします。


さて、焦点を置くべきところは"システムを実装するための特定の技術"ではないとのことなので、表題に含まれる"Spring"などの特定の技術に拘泥していてはいけないようです。耳が痛いです。

そうではなく、焦点を置くべきところは"ドメインそのものとドメインのロジック"とのことです。それをモデル化したものに"ドメインモデル"があり、それは以下の"ドメインモデルを表現する要素"によって表現できるようです。

>エンティティ (参照オブジェクト): ドメインモデル内のオブジェクトであり、その属性によってではなく、連続性と識別性によって定義される。

>値オブジェクト: 事物の特性を記述するオブジェクトである。特に識別する情報はなく、通例、読み出し専用のオブジェクトであり、Flyweight パターンを用いて共有できる。

>サービス: 操作がオブジェクトに属さない場合に、問題の自然な解決策として、操作をサービスとして実現することができる。サービスの概念は、GRASPにおいて"純粋人工物"と呼ばれるものである。

>リポジトリ:ドメインオブジェクトを取得するメソッドは、記憶域の実装を簡単に切り替えられるようにするため、専門のリポジトリオブジェクトに処理を委譲するべきである。

>ファクトリー : ドメインオブジェクトを生成するメソッドは、実装を簡単に切り替えられるようにするため、専門のファクトリーオブジェクトに処理を委譲するべきである。


これらを見て、「これ全部、Springの用語で書き換えられるのでは？」と思ったことが、本稿起草の契機です。実際にやってみたものが下記になります。

- エンティティ
テーブルに格納されたレコードの入れ物。テーブルのカラムと同じフィールドを持つ。Repositoryの引数であり、戻り値でもある。テーブルのIDがAuto Incrementしている場合、IDフィールドにユニークな値が入る。

- 値オブジェクト
Enum。大抵、コード値とかはEnumにされる。

- サービス
Controller-Service-Repositoryの3層構造におけるServiceのこと。色々複雑なことをすることもあるようだけど、[ControllerのModel※] ⇔ [RepositoryのEntity] の詰め替え作業をしているだけのこともある。（※MVCにおけるModelのことっぽいけど、実際はただのデータの入れ物）

- リポジトリ
Controller-Service-Repositoryの3層構造におけるRepositoryのこと。要するに、DBに関わる処理をするところ。どんなORマッパーでも、内部ではSQLを実行している。あと、外部APIを読み出す箇所としても使われていたりする。

- ファクトリー：
DI。Controller-Service-Repositoryの3層構造は、DIで構築されている。@Autowiredを使うスタイルも、いまや古くなってしまったかも。


こんな感じで、概ね書き換えることが出来てしまいました。

ドメイン駆動開発は、そのアンチテーゼがトランザクションスクリプト（if-elseによる長大なメソッド群）らしいです。

トランザクションスクリプトにならないよう、上述の「ドメインモデルを表現する要素」を意識してリファクタリングに勤しめば、ボトムアップ式とはいえ、ドメイン駆動開発をしていることになりそうです。

それなら、"特定の技術"ということにはなりますが、Springを使って開発していたら、「ドメインモデルを表現する要素」を意識することになるので、自然とドメイン駆動開発をしていることになると言えそうです。

とはいえ、ドメインモデル欠乏症という言葉があって、setterとgetter以外に、なんの振る舞いもしないDTOを良しとしているとダメなようです。


実際の開発では、"ドメインそのものとドメインのロジック" を "ドメインモデル" に書き出す、なんて面倒なことはせず、よくある設計パターンを再利用する感じで進めている気がします。Springなら、Controller-Service-Repositoryの3層構造を守っていれば、そんなに困ることはないように思います。

しかし、Wiki冒頭の要約にあった"複雑なドメインの設計"においては、既存の設計パターンを簡単には適用できないのだと思います。

そうしたケースでは、適切なドメインモデルを構築すべく、ビジネスと開発の人の双方が分かるユビキタス言語を発見・発明したり、何度もER図とクラス図を書き直したり、ホワイトボードを前に喧々諤々したりする必要があるのだと思います。

いつか、"複雑なドメインの設計"をすることになっても大丈夫なように、普段から、"ドメインそのものとドメインのロジック"を意識しておくことが大切なのだと思います。

決して、「普段はそんなに意識する必要ないのでは？」なんて不遜なことを思ったりしていないです。
Javaの入出力処理の仕組み「ストリーム」について


### Streamとは
Javaの入出力処理の仕組みのこと。ストリームとは、直訳で「小さな川」という意味で、Javaでは、「データの流れとその通り道」を意味する。


### 入力ストリーム
ファイルやネットワークなどの「アプリケーションの外」から、Javaアプリケーションへデータを受け取る。



### 出力ストリーム
Javaアプリケーションから、ファイルやネットワークなどの「アプリケーションの外」へデータを送り出す。




↓参考記事

https://codezine.jp/article/detail/6299
FileMakerServer にホストされている共有ファイルで fmp プロトコルリンクを生成

# はじめに
## 対象読者
* [Claris FileMaker](https://www.claris.com/ja/filemaker/) ユーザ
* fmp プロトコルリンクを生成したい人
* ちょっとした手間をかけるのも嫌というめんどくさがりやな人

## fmp プロトコルとは
* [Claris FileMaker Pro 19 ヘルプ - URL を使用してファイルを開く](https://help.claris.com/ja/pro-help/content/opening-files-url.html)

> URL を使用して、共有ファイルまたはローカルファイルを開く、またはファイル内のスクリプトを実行することができます。FileMaker Pro または FileMaker Go をインストールすると、次の URL スキーマがオペレーティングシステムに登録されます。これにより、これらのスキーマを使用する URL は FileMaker Pro または FileMaker Go により処理されます:
> 
> fmp – 最後にインストールされたアプリケーションバージョンがこのスキーマの URL を処理します。



## 対応したいこと
* ファイル名に日本語等のマルチバイト文字が含まれていても問題ないようにする

# 本題
## 計算式
* 以下のような計算式を書くことで、生成できる
* Let で上書きしていくことで可読性が高くなるが、ワンライナー的に書いても構わない

```java
Let (
  [
    filepath = Get ( ファイルパス );
    filepath = GetAsURLEncoded ( filepath );
    filepath = Substitute ( filepath ; "fmnet:%2F" ; "fmp://" );
    filepath = Substitute ( filepath ; "%2F" ; "/" )
  ];

  filepath
)
```


## クリップボードへ格納
* レイアウト上へグローバルフィールドを設置しておいて、一度そこへ変数を格納し、コピーさせることで、手軽にクリップボードへ格納できる
  * `コピー` というステップが、以下の条件でないと正しく動作しないので要注意
    * レイアウト上にフィールドが存在している
    * そのフィールドにはカーソルが入る状態である
* たとえば以下は `トップ` というテーブルに `gtmptxt1` というグローバルフィールドが存在している状況で、そのフィールドが設置されているレイアウトで動作されることが前提となる
  * なので、より確実丁寧にするには、以下のようにやっておくとヨシ
    * 手前でレイアウトを切り替えるとか、
    * あるいは一時的にウインドウを開いて閉じるようにするとか、
    * 格納し終わったらグローバルフィールドの中身を空にする処理を入れるとか……

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37739/7fac2e1d-03bb-a3e4-7bba-b68f9235d442.png)


## 応用
### Slack のブックマークへ登録
* Slack の各 channel には `Add a bookmark` がある（日本語環境だと `関連ページを追加する` というらしい ）
* ここには `http/https://` だけでなく `fmp://` も登録できるので、ワンクリックで FileMaker ファイルを開くことができるようになる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37739/d38ba8f5-e632-632b-41b4-69b922dced60.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37739/2f3ab647-d36d-31e6-d691-82cce980cbf7.png)


https://twitter.com/Hi_Noguchi/status/1539192827522916353?s=20&t=a1w1IudgFY7SCrKJQUeALg

### スクリプトの実行
* URL に引数をつけるとスクリプトを実行したり、さらにそのスクリプトへ引数を渡したりすることもできる

```java
"?script=display_opts_id" & "&param=" & users::id
```

* この場合、 `options` という変数を別途定義して、グローバルフィールドに値を格納する際に、`$filepath & $options` を含めてあげるなどすればよい
* なお、実行するスクリプトへ引数を複数渡したい時は `param` だと一つきりしか渡せないので `&$変数=値` を複数渡してあげるとよい


# おわりに
## 感想
* Slack のブックマークに追加できることを知った嬉しさのノリで、つい、前提となるところからの記事を書いてしまったが、勢いってだいじだと思います。
Could not create yum cacheエラー対応

# エラー内容
AWS ElasticBeanstalkでのデプロイ時、エラーが発生しアプリケーションをデプロイできなかった。
```
Command failed on instance. Return code: 1 Output: Could not create yum cache (return code 1). Package listed in EBExtension failed to install. For more detail, check /var/log/eb-activity.log using console or EB CLI.
```

# 調査
インスタンスに乗り込み、activity.logを確認したところ、`yum install yarn`ができなかった様子。

その直前のコマンドが下記。おそらくこれがコケたから、上記yarnのinstallができなかったのだろうと推測。
```
curl -sL https://dl.yarnpkg.com/rpm/yarn.repo | sudo tee /etc/yum.repos.d/yarn.repo
```

上記curlを叩いたところ、調査時点では正しく返ってくる。
ただし、その時点での`/etc/yum.repos.d/yarn.repo`の中身を見ると500エラーが返っている内容であったため、デプロイ失敗時にはyarnレポからうまく取得できなかったのだろう。

# 対応
上記のコマンドをインスタンス内で実行し、再度デプロイすることで問題は解消した。

# 原因
おそらく、Cloudflareでの障害が起因している。

https://forest.watch.impress.co.jp/docs/news/1418927.html

以上
Swiftとは？

プログラミング言語のswiftとは何か、初心者が学んだことをまとめます。

## Swiftとは
・Apple社が2014年に発表したiOS,macOS向けアプリケーション開発で使用するプログラミング言語。
・2015年にオープンソース化され、Linuxでの実行環境も提供されました。

### 特徴
* モダン
プログラミング言語でいう「モダン」とは、”コードが読みやすくて書きやすい”ということです。
Ruby,Python,C#など、近年のプログラム言語を研究して設計されているので、使いやすい機能や文法などが取り入れられています。

* 安全性が高い
安全性が高いとは、プログラムの実行を邪魔する「バグ」が発生しにくいということです。
Swiftはコンパイル言語（静的型付き言語）と言って、あらかじめ決めた変数や定数の型（type）に間違った値を入れると、コンパイルエラーを起こします。コンパイルエラーが出ている間は、プログラムを実行できないので、実行時に起こるバグを未然に防ぐよう教えてくれます。

* 高速
処理の高速化を目的に作られた言語なので、アプリを作った場合に他のどの言語よりも高速で処理されます。
Objective-Cの最大2.6倍、Python2.7の最大8.4倍も速いスピードで完了できることもあるそうです。

* インタラクティブ
インタラクティブとは、ITの分野では情報の送り手と受け手がその場で互いにやり取りできる状態を指します。で
SwiftでもXcodeのplaygroundsやターミナルにて、すぐに動作確認ができ、バグの原因を探して取り除く作業(デバック)ができます。

## 環境構築
書いたプログラム言語を実行できるようにするための環境を作ります。
Swiftでは、開発ツールであるXcodeというアプリケーションを使います。
#### Xcodeのインストール
1. 比較的新しいMacのパソコンを用意します。
2. パソコンのOSが最新のバージョンになっているか確認します。
　 最新の状態にアップデートしていないと、インストールできないことがあります。
3. AppStoreから「Xcode」を検索し、インストールします。
　 インストールにはかなりの時間がかかりますのでご注意を。（私は４時間くらいかかりました）

## さいごに
整備品MacBookを買った私は、OSのバージョンが古くインストールまでにかなりの時間がかかりました。
Swiftの特徴や環境構築は、まだま勉強することが多そうです。
追記か、新しい記事で今後もアウトプットしていきたいと思います。
conda installしたcuda-toolkitとcuDNNでTensorFlowを動かす

# この記事を閲覧する前に
この記事よりも簡単にTensorFlowとCUDA・cuDNNの環境を構築する手段を別の記事（[conda install のみでTensorFlowとGPU環境（CUDA、cuDNN）を構築する](https://qiita.com/ktokey/items/7ee9c112198a6b0b5709)）に記載しています。
上記記事は本記事を閲覧して頂いた@hatsuyuki396様からのコメントを受け、作成いたしました。コメントありがとうございました。

# はじめに
私が利用していたLinuxサーバには元々、古いバージョンのCUDAとcuDNNがインストールされていました。しかし、TensorFlowの新バージョンを利用するためには、それらをアップグレードする必要がありました。しかしながら、sudo権限を持っていないため、「/usr/local/」下にある各種ディレクトリに対して操作することができません。そこで、Anacondaを利用して必要なCUDAとcuDNNをインストールしていきます。OSはUbuntu18.04を利用しています。

今回はTensorFlow2.9.1を利用するため、以下のバージョンをインストールします。
・cuda-toolkit == 11.7.0
・cudnn == 8.4.1

何かあったときに取り返しのつく仮想環境で作業を行いました。Anacondaの仮想環境を作るコマンドは以下の通りです。

```bash
conda create -n tf291 python=3.9
# tensorflowもインストールするなら、以下も実行
pip install tensorflow==2.9.1
```

※「conda install tensorflow=2.9.1」では、GPUを扱うことはできません。詳しくは[コチラ](https://qiita.com/ktokey/items/f46b7a97b08c060f077c)

# インストール
Anacondaのデフォルト参照先では、cudatoolkit==11.3.1、cudnn==8.2.1が最新のバージョンになるため、今回は以下の参照先からそれぞれをインストールします。もしかすると、何やら競合しているとの警告メッセージが表示されるかもしれません。その場合には、Anacondaの指示に従い、各種ライブラリのダウングレードなどを行ってください。

```bash
conda install -c nvidia cuda-toolkit=11.7.0
conda install -c conda-forge cudnn=8.4.1
```

ここで、CUDAなどの確認を行っても、デフォルトの環境が読み込まれているはずです。例えば、以下のコマンドでCUDAのバージョンを確認すると、以前のバージョンが表示されるはずです。また、プログラムを実行しても、デフォルトのCUDAやcuDNNが読み込まれていると思います。

```bash
nvcc -V
```

# PATHの設定
先ほどインストールしたCUDAとcuDNNのPATHを確認します。基本は、「/home/（ユーザ名）/anaconda3/envs/（仮想環境名、今回は tf291）/bin」などで確認できるかと思います。condaでインストールしたCUDAとcuDNNを利用するために、.bashrc内に以下を追記します。

```bash:.bashrc
export PATH="/home/（ユーザ名）/anaconda3/envs/tf291/bin:$PATH"
export LD_LIBRARY_PATH="/home/（ユーザ名）/anaconda3/envs/tf291/lib:$LD_LIBRARY_PATH"
```

追記して保存したら、それを適用します。
```bash
source .bashrc
```

これで、希望のバージョンを利用することができます。ただ、このようにすると、Anacondaの仮想環境に入っていなくても、今回インストールしたCUDAとcuDNNのバージョンが適用されるため、注意が必要かも（複数のCUDAがインストールされている場合、TensorFlowは自動的にマッチするCUDAとcuDNNのバージョンを選択してくれるらしいが）。もっと良い方法があれば、教えてください。。。管理者権限が無い中、お疲れさまでした。

# 参考
https://anaconda.org/nvidia/cuda-toolkit
https://anaconda.org/conda-forge/cudnn
Ubuntuがディスクの容量不足で起動しなくなった際の対処法

# ことの発端
研究室の PC には Ubuntu がインストールされており，家から SSH をつないで使うことが多いので普段からシャットダウンはしていない．
ある日，研究室で Ubuntu にログインすると，画面に `/root の容量がいっぱいです．ゴミ箱を空にしますか？` というような表示が出ていた．（正確な文言は覚えていないです．すみません．）
とりあえずゴミ箱を空にし，検索をするため Chrome を起動しようとしたが，起動しない．
shell から google-chrome を実行すると，socket 関連のエラーを吐いていた．
安直な気持ちで再起動すれば治るだろうと思い，再起動したら grub shell しか起動しなくなるという状況に...

# Ubuntu が起動しなくなった原因
Ubuntu がインストールされている `/dev/sda5` の容量がいっぱい (100%) になったことによる boot の失敗

# 対処法
なんとかして `/dev/sda5` にあるファイルを削除し，boot に必要な空き容量を確保します．
※環境が限定的，スクリーンショット無し，筆者のカーネル周りの知識が乏しいため以下の例は参考にならないかもしれません．
まずは PC の電源を入れ，F2 や del キーを長押しすることで UEFI を起動します．
Ubuntu を起動しようとするとフリーズするので，ブートの選択から GRUB を指定します．
起動すると下記のようなプロンプトが表示されるはずです．（GRUB メニューが起動し，Ubuntuのリカバリーモードが選択できる場合はリカバリーモードで起動してみてください）
```
GNU GRUB version 2.02
grub>
```
下記のフォーラムを参考に手動で Ubuntu を boot します．
https://unix.stackexchange.com/questions/418401/grub-error-you-need-to-load-kernel-first
https://askubuntu.com/questions/883992/stuck-at-grub-command-line
```
grub> insmod linux
grub> linux (hd0,msdos5)/boot/vmlinuz root=/dev/sda2
grub> initrd (hd0,msdos5)/boot/initrd.img
grub> boot
```
`(hd0,msdos5)` というのは Ubuntu がインストールされているパーティションです．
`root=/dev/sda2` とありますが，トラブルシューティングしている時は Ubuntu がインストールされているデバイス名を覚えていなかったので `/dev/sda5` とするところを間違えて `/dev/sda2` としています．追記： `root=(hd0,msdos5)` と指定しても良さそうです．

`boot` が始まりますが，途中でエラーを吐いて Ubuntu の代わりに `ash` が起動しました．
```ash
> ls
bin    dev   lib    libx32      root  snap  sys       var
boot   etc   lib32  lost+found  opt   run   srv       tmp
cdrom  home  lib64  media       proc  sbin  swapfile  usr
> ls /home
Ubuntu       BOOT
```
間違えて `/dev/sda2` を指定したせいか，まっさらなルートディレクトリが表示され，`/home` の中には `Ubuntu`, `BOOT` というディレクトリがありました．
`help` コマンドを実行すると，`mount`, `rm` が使えるようなので `/dev/sda5` をマウントしてファイルを削除します．
```ash
> mkdir /sda5
> mount /dev/sda5 /sda5
> cd /sda5
<不要なファイルを削除する>
> df
Filesystem     1K-blocks      Used Available Use% Mounted on
/dev/sda5      959862832 696352476 214682196  77% /sda5
```
とりあえず 100% から 77% までファイルを削除し，`reboot` コマンドが機能しなかったので電源ボタンから再起動します．（UEFI でブートの順番を変更した場合は元に戻すのを忘れずに．）
これで正常に起動するようになりました．

# おわりに
SSH で PC を使っていると，知らないうちにディスクが容量不足になっていたりします．
大きなファイルをダウンロードしたり，プログラムの出力で大きなファイルを出力する場合は，`df` コマンドを叩いて容量を確認する癖を付けると良いかもしれません．
プロキシ、リバースプロキシってなんだろう

# はじめに
通信障害に関する事がTwitterで盛り上がっていたが、「リバースプロキシサーバの〜」という様な聞いたことはあるけれど、実際何してるサーバなのかわからない話題だったので調べて備忘録としてまとめる。

# プロキシ
名前はproxyから来ており日本語では「代理」という意味で、内部ネットワークからインターネットへ接続する中継に用いられる。
![プロキシ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/790862/237ecf62-4069-d369-3f09-5b6e332c2b26.png)
機能として
* キャッシュの保存による通信高速化
* ユーザー認証による外部通信の限定化
* フィルタリングによる特定サイトの閲覧制限
* ③で帰ってきたコンテンツのウィルスチェック
* プロキシサーバが外部との接続を行うことで社内PCの情報が公開されない
などがあるらしい

# リバースプロキシ
こちらは外部からサーバへの通信を中継する役割をもっている
![リバースプロキシ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/790862/7923a2fd-dbbd-f438-79b3-53f30d89b4dd.png)
こちらの機能は
* キャッシュ保存による高速化、又静的コンテンツの際はWebサーバへの接続がないためWebサーバへの負荷が減少
* 複数サーバを用いることによる負荷分散
* SSL通信での認証をリバースプロキシサーバで行うことでWebサーバの負荷を軽減
* Webサーバへの直接アクセスではないためセキュリティリスクの低減が見込める

# まとめ
なるほど、かなり重要なポジションのサーバである事が分かった。
参考サイトにもあったが担っている役割が重要な分、攻撃対象にもされやすいとのこと。
今回の通信障害が何から発生したものかはまだ分からないが、一つ勉強になりました。
cookie の取得方法と curl で cookie を送信する方法

# はじめに
curl で cookie を送信する方法についてです。
example.jp への接続を想定してますが、各々の環境に合わせて変更してください。

# cookie の取得
開発者ツール > Application > Cookies を展開して取得できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/477044/93c53fd7-70dd-f08a-a113-215ad869b678.png)

# curl
## -b オプションで cookie を送信する方法
```
curl -b "id=<cookie>; quiita=<cookie>;" "http://example.jp"
```

## ヘッダーで cookie を指定して送信する方法
```
curl -H "Cookie: id=<cookie>; quiita=<cookie>;" "http://example.jp"
```
jq コマンドで curl の json レスポンスを見やすく表示する方法

# はじめに
jq コマンドを利用して curl の json レスポンスを見やすく表示する方法です。

# 内容
## jq のインストール
```
$ brew install jq
```

## jq コマンド実行
楽天 API で実行します。
※ 楽天 API の利用方法、APP_ID の取得方法は[こちら](https://qiita.com/fmyuk/items/2067bad47904fcfeeb60)
```
curl "https://app.rakuten.co.jp/services/api/Travel/KeywordHotelSearch/20170426?format=json&applicationId=<APP_ID>&keyword=ハワイ" | jq
```
取得結果
```
{
  "pagingInfo": {
    "recordCount": 152,
    "pageCount": 6,
    "page": 1,
    "first": 1,
    "last": 30
  },
  "hotels": [
    {
      "hotel": [
        {
          "hotelBasicInfo": {
            "hotelNo": 8070,
            "hotelName": "スパリゾートハワイアンズ　ホテルハワイアンズ",
            "hotelInformationUrl": "https://img.travel.rakuten.co.jp/image/tr/api/kw/JBe8h/?f_no=8070",
            "planListUrl": "https://img.travel.rakuten.co.jp/image/tr/api/kw/3VTwt/?f_no=8070&f_flg=PLAN",
            "dpPlanListUrl": "https://img.travel.rakuten.co.jp/image/tr/api/kw/IWrzP/?noTomariHotel=8070",
            "reviewUrl": "https://img.travel.rakuten.co.jp/image/tr/api/kw/HTX0u/?f_hotel_no=8070",
            "hotelKanaName": "すぱりぞーとはわいあんず　ほてるはわいあんず",
            "hotelSpecial": "スパリゾートハワイアンズ【オフィシャルホテル】東京・新宿・横浜などから宿泊者専用無料送迎バス運行中！",
            "hotelMinCharge": 10875,
            "latitude": 133166.3,
            "longitude": 506953.02,
            "postalCode": "972-8326",
            "address1": "福島県",
            "address2": "いわき市常磐藤原町蕨平50",
            "telephoneNo": "0570-550-550",
            "faxNo": "0246-44-6220",
            "access": "常磐自動車道 いわき湯本ＩＣより車で３分。ＪＲ湯本駅よりバスにて１５分。",
            "parkingInformation": "有り：３，５００台（無料：フロントで手続き必要）",
            "nearestStation": "湯本",
            "hotelImageUrl": "https://img.travel.rakuten.co.jp/share/HOTEL/8070/8070.jpg",
            "hotelThumbnailUrl": "https://img.travel.rakuten.co.jp/HIMG/90/8070.jpg",
            "roomImageUrl": "https://img.travel.rakuten.co.jp/share/HOTEL/8070/8070_furo.jpg",
            "roomThumbnailUrl": "https://img.travel.rakuten.co.jp/HIMG/INTERIOR/8070.jpg",
            "hotelMapImageUrl": "https://img.travel.rakuten.co.jp/share/HOTEL/8070/8070map.gif",
            "reviewCount": 2021,
            "reviewAverage": 3.79,
            "userReview": "部屋のトイレ使えないことをチェックインに言って欲しかったです。鍵閉まってていいと思わないでください。せめて、張り紙など貼ってもらった方がこちらもわかりやすいです。　2022-06-15 16:42:08投稿"
          }
        },
        {
          "hotelRatingInfo": {
            "serviceAverage": 3.94,
            "locationAverage": 3.94,
            "roomAverage": 3.51,
            "equipmentAverage": 3.57,
            "bathAverage": 3.94,
            "mealAverage": 3.62
          }
        }
      ]
    },
    {
      "hotel": [
... すごい量なので省略
```
【Ruby】ハッシュとシンボルについて学んだこと

# はじめに
チェリー本を読んで、ハッシュとシンボルについて学んだので簡単にまとめました！

# 参考
プロを目指す人のためのRuby入門 言語仕様からテスト駆動開発・デバッグ技法まで

# ハッシュとは
キーと値の組み合わせでデータを管理するオブジェクトのこと

# ハッシュの書き方
キーが文字列かシンボルによって、書き方が変わります。

## キーをシンボルにする場合（一般的）
{キー:値}でハッシュを生成します。
```ruby:キーをシンボルにした場合のハッシュの書き方
profile = {name:'太郎'}
```
## キーを文字列にする場合
{キー=>値}でハッシュを生成します。
ただし、あまり一般的な方法ではないようです。
```ruby:キーを文字列にした場合のハッシュの書き方
profile = {'name' => '太郎'}
```
# 要素の追加・変更
追加・変更ともに、「ハッシュ[キー] = 値」で記述します。
上記で指定したキーが、
+ 存在しない場合は：追加
+ 存在する場合は：変更
と、挙動が変わります。

```ruby:要素の追加
profile = {名前:'太郎'}

# 追加
profile[:姓] = '田中'
p profile #=>{:名前=>"太郎", :姓=>"田中"}

# 変更
profile[:姓] = '佐藤'
p profile #=>{:名前=>"太郎", :姓=>"田中"}
```

# 値の取得
ハッシュ[:シンボル名]で値を取得します。
```ruby:キーをシンボルにした場合の値の取得方法
profile = {name:'太郎'}
p profile[:name] #=>"太郎"
```
# 要素の削除
「ハッシュ.delete（キー）」で削除ができます。
```ruby:要素の削除
profile = {
    name:'太郎',
    family_name:'佐藤',
}
profile.delete(:family_name)
p profile #=>{:name=>"太郎"}
```
# ハッシュを使った繰り返し
ブロックパラメーターを2つ用意することで、キーと値がブロックに渡されます。

```ruby:ハッシュを使った繰り返し
members = {
    1=>"太郎",
    2=>"佐藤",
    3=>"次郎",
}

members.each do |num,name|
    puts "#{num}番は#{name}です"
end

#=>1番は太郎です
# 2番は佐藤です
# 3番は次郎です
```
# シンボルと文字列の違い
比較対象とされるシンボルと文字列ですが、下記のような違いがあります。

## ①オブジェクトが一緒か異なるかの違い
例えば下記のコードのように、「太郎」という文字を,
+ シンボルで3つ生成した場合：3つともobuject_idが一緒
+ 文字列で3つ生成した場合：3つともobuject_idが異なる
という違いがあります。
つまり、シンボルと文字列では、同じ文字でも生成されるオブジェクトの数が変わります。
文字列のように、オブジェクトが生成されればされるほど、占有するメモリも増えてしまうため、同じ用途なのであれば、シンボルを使用した方が、メモリの使用効率が良くなります！

```ruby:シンボルと文字列のobject_idの違い
#シンボルの場合、object_idが一緒
p :太郎.object_id #=> 1056668
p :太郎.object_id #=> 1056668
p :太郎.object_id #=> 1056668

#文字列の場合、object_idが異なる
p '太郎'.object_id #=>70212967994280
p '太郎'.object_id #=>70212967994200
p '太郎'.object_id #=>70212967994120
```
## ②ミュータブルかイミュータブルの違い
+ 文字列はミュータブル（値の変更が可能）ですが、
+ シンボルはイミュータブル（値の変更が不可）になります。
そのため、名前やIDなどのように、「一度定めたら変えることがない」ケースにシンボルが使われます。
```ruby:ミュータブルかイミュータブルの違い
#文字列の場合、値の変更が可能（ミュータブル）
name = 'taro'
p name.upcase! #=>"TARO"

#シンボルの場合、値の変更が不可（イミュータブル）
name = :taro
p name.upcase! #=>NoMethodError
```

# シンボルの特徴
シンボルの特徴は、
1. ソースコード上は、文字列に見えるため人が識別しやすい
1. 一方、内部的には整数のため、文字列を比較するよりも処理が早い
1. 同じシンボルは同じオブジェクトのため、メモリの使用効率が文字列を使うより高い
1. イミュータブルなので、破壊的メソッド防止になる(勝手に値が変わる心配がない)

# ハッシュの展開
**をハッシュの前につけることで、ハッシュの中身が展開されます。

```ruby:ハッシュ展開の例
a = { depth:1 }
size = {
    width:2,
    height:3,
    **a
}
p size #=>{:width=>2, :height=>3, :depth=>1}
```
# シンボルを文字列に変換する方法
to_symメソッドを使用します。
```ruby
'name'.to_sym #=>:name
```

# まとめ
ハッシュのキーに文字列ではなく、シンボルを使う理由は勉強になりました！
間違いやアドバイスがあればご教授いただけますと幸いです。
【Xcode】アプリ名を変更する

# iOS
①プロジェクトを選択
②ターゲットを選択
③「General」を選択
④「Display Name」を好きなアプリ名に変更する
![スクリーンショット 2022-06-21 18.56.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/ecca4da0-f4c9-68e1-ea98-c58d8cb5c629.png)

# macOS
①プロジェクトを選択
②ターゲットを選択
③「Build Settings」を選択
④`product name`と検索
⑤緑の枠をダブルタップ
⑥好きなアプリ名に変更する
![スクリーンショット 2022-06-21 19.02.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/b19091d2-eeea-8d1c-8c5a-d92311b16419.png)

# おわり
iOSのアプリ名の変更はわかりやすかったのですが、
macOSには少し手こずったので違いをまとめておきました
基本情報（CPUの性能指標）

CPUの性能は高速であればあるほど。コンピュータの処理性能は高くなります。
ただ、性能を比較しようとすると統一された基準がないと比較できません。

CPUの性能を表す指標値があり、クロック周波数やCPI(Clock cycles Per Instruction),MIPS(Million Instructions Per Second)といった数値です。

簡単に書くと

クロック周波数：周期信号の繰り返し数
CPI：周期信号が何周期分で１つの命令を実行できるか
MIPS：１秒間に実行できる命令の数

よくわからないので細かく見ていきます。

## クロック周波数
コンピュータには色んな装置が入っており、バラバラに動いてはまともに動作がしないので「クロック」と呼ばれる周期的な信号に合わせて動きます。
CPUもクロックという周期信号に合わせて動作を行います。

クロックの周期が短いほど、より多くの処理ができます。

クロックが１秒間に繰り返される回数のことを**クロック周波数**と呼びます。
単位はHz。

「クロック周波数1GHzのCPU」といった場合は、１秒間に10億回(1Gは10⁹=1,000,000,000回)振動していることになります。

## 1クロックに要する時間
「クロック周波数4HzのCPU」があったとします。
このCPUが１クロックに要する時間は何秒になるか。

１秒間にクロックが4回繰り返されることになります。
1/4のため0.25秒かかります。

クロック周波数の秒数1を割ると１クロックに要する時間が求められます。
この時間を**クロックサイクル時間**と呼びます。

```
クロック数 / 1秒　
// クロック周波数
1秒 / クロック数
// クロックサイクル時間
```

## CPI(Clock cycles Per Instruction)
１命令あたり何クロックサイクル必要かを表すものです。

```
Clock cycles Per Instruction
クロックサイクル  /   命令

命令の実行に2クロックサイクル必要なら2CPI
４クロックサイクルなら4CPI
```
このCPIとクロックサイクル時間を使うと、命令の実行時間を求めることができます。

1GHzのCPUで実行に3クロックを要する命令(3CPI)だった場合

1秒間で1,000,000,000（10億回）の計算ができます。
1/1,000,000,000で0.000000001秒/クロック

です。
１ナノは10⁻⁹倍です。
十億分の一、0.000 000 001 です。

クロックサイクル時間は１ナノです。

1ナノ秒　※ ３クロックで3ナノ秒です。
0.000000003ですね。

こちらは命令実行時間です。
ﾅﾉﾅﾉ

## まとめ
長くなりそうなので今日はここまでにします。
小数点見たらすぐに友達になれるか考える必要がありますね。
go genericsメモ

go 1.18でchunk?が書きやすくなったのでメモ。

```
import (
	"fmt"
)

func chunks[T any](l []T, n int) chan []T {
	ch := make(chan []T)
	go func() {
		for i := 0; i < len(l); i += n {
			fromIdx := i
			toIdx := i + n
			if toIdx > len(l) {
				toIdx = len(l)
			}
			ch <- l[fromIdx:toIdx]
		}
		close(ch)
	}()
	return ch
}

func main() {
	mm := []map[string]interface{}{
		{"a": 1, "b": 2},
		{"a": 3, "b": 4},
		{"a": 5, "b": 6},
		{"a": 7, "b": 8},
		{"a": 9, "b": 10},
	}

	for m := range chunks(mm, 3) {
		log.Printf("m %v", m)
	}

	nums := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
	for n := range chunks(nums, 3) {
		log.Printf("n %v", n)
	}
}
```
Postmanでapi確認をする際、tokenをどこに入れればよいか分からなかった

# 背景
drfを使用してapiを作成中。
ログインしたユーザのイベントリストをgetしたかったのですが、viewでModelViewSetを使用していると
全ユーザのイベントリストをgetしてしまうのでviewでListCreateAPIViewを使用してfilterを使用しました。
```python:views.py
class UserEventListView(generics.ListCreateAPIView):
    serializer_class=EventSerializer
    def get_queryset(self):
        username=self.request.user
        return Event_Table.objects.filter(username=username)
```
apiが正常に動作しているか確認のためにPostmanで確認を取ろうとしたら、どこにログイン情報を入れたらよいのか分かりませんでした。
認可にはsimpleJWTを使用しています。
ちなみにPostmanは初心者です。

# Postmanでtokenを入れたい
私は初めに以下のようにAuthorizationタグにtokenを入れていました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2082391/ad35c8bb-9756-e828-287b-da124c1c408b.png)

しかし、イベントリストを取得できませんでした。
それもそのはずでTypeがBearer Tokenだからです、、、、
Headerを見てみると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2082391/def14976-fff3-d3d6-da75-12b1b9d9654c.png)
Bearer JWT ～～～～ となっています。
完璧アホ丸出しです。

直接HeaderにキーをAuthorizationとしてtokenをバリューで記入するか、
もしくは、AuthorizationタブでOAuth 2.0を選択して下さい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2082391/75594508-1147-a3af-4936-7010286565af.png)
Header PrefixをJWTにするとBearer JWT みたいなことにはなりません。
Tokenについてよくわかっていないと感じました。
Bearerは認証の方式、OAuthは認可の方式でJWTはその手段の一つ、みたいな感じかなと思っていました。

ネットの記事を読むとBearerは認証認可の方式とかOAuthの一部とか色々と分からないことが増えました。
年内にTokenと認証認可についてまとめたいです。

# 最後に
PostmanでTokenを入れようとしてこんなミスをする人はいないかもしれませんが、僕は間違ったので記事を投稿しました。
Postmanに慣れていきたい、、、
BigQueryのバックアップ(復旧可能)について調べたのでメモ

# 前提
BigQueryていつまで復旧可能なんだっけ？
復旧期間伸ばしたい場合はどうすればいいんだっけ？
みたいな時に見るメモ。

# まとめ
- デフォルトで7日分はタイムトラベル機能で復旧可能
- 7日以上復旧可能にしたい場合は、スナップショット機能を使う

# メモ

### タイムトラベル機能
  
https://cloud.google.com/bigquery/docs/time-travel?hl=ja

https://cloud.google.com/bigquery/docs/managing-tables?hl=ja#undeletetable

タイムトラベル機能で、データが削除された場合も過去7日間は復旧可能です

### スナップショット機能

https://cloud.google.com/bigquery/docs/table-snapshots-intro?hl=ja

さらに、スナップショット機能を使えば、7日以上も復旧可能にできます。
スナップショットはベーステーブルの差分を保持するため、データまるごとバックアップ取るよりもストレージ費用が安くすみます。

### テーブルクローン機能

https://cloud.google.com/bigquery/docs/table-clones-intro?hl=ja

最近テーブルクローンなる機能が出たようですが、あまり使い所はわかりません。
スナップショットのように復元しなくても更新できるところが嬉しいみたいです。
tfnotifyの一括実行を可能にするtfwapperを仕込んだ話

こんにちは、anoneです。
今回は`tfwapper.sh`を用いて`tfnotify`の処理を一括実行するよう仕込んだ話をします。

## terragruntって何？
terragruntを使ってterraformのバックエンド周りをまとめてる方の記事が参考になりました。
[TerragruntでTerraformのbackend周りのコードをDRYにする](https://dev.classmethod.jp/articles/terragrunt-makes-your-terraform-backend-code-dry/)

## どうやったの？
以下記事を大変参考にしました。
[terragrunt(xxx-all系)でtfnotifyを使う方法](https://qiita.com/hiko1129/items/4f4699a170f69c4582ba)

### ディレクトリ構成
使用していた`tfnotify.yml`も使えるようにした状態でterragruntを使えるように改修する為には参考資料のようなtfwapper.shが必要でした。
そこで、同じディレクトリにtfwapperを配置します。

```
.
├── tfnotify.yml
└── tfwapper.sh
```

### tfwapper.shの中身

```scripts/tfwapper.sh
#!/bin/bash

set -eu

terraform "$@" 2>&1 | tee ./terraform.log

type=$(echo "$@" |  awk '{print $1}')

if [ "$type" != "plan" ] && [ "$type" != "apply" ]; then
  exit 0
fi

current_directory=$(pwd)

tfnotify --config "/scripts/tfnotify.yml" "$type" --message "$current_directory" < ./terraform.log
```

### 実行
codebuildのコンソール上から実行しました。
参考資料にもあったコマンドでの実行があります。（どちらを採用しても良い）

## 後日談
上記スクリプトのままだとcurrent_directoryにログメッセージが出力されますが、
他のディレクトリに対してログを吐きたい場合は、`log_directory`といった風に宣言して指定するとそこに吐き出されます

## 参考文献
[terragrunt(xxx-all系)でtfnotifyを使う方法](https://qiita.com/hiko1129/items/4f4699a170f69c4582ba)
Rails2系？ pagenateでdistinctしたかった

誰が今更こんなことを調べようか。

## 開発環境

* Ruby 1.8.7
* Rails 2.1.0
* SQLServer2008

~~なんだこの化石のような環境は~~

## 問題

pagenateでDISTINCTが使えない。

```ruby
    @data = VData.pagenate(:all,
        :select   =>'DISTINCT *', # <= こういうのはNG
        :distinct => true, # <= こんなものはない
        :page => 1,
        :per_page => 20
    ).distinct # <= できません
```


## 調査

調べても新しいのしかでないよね。そりゃ。

と思ったらこんな記事が。

https://rubricks.hatenadiary.org/entry/20070419/1176957966

> paginateの中で
(1):distinctオプションがなぜか不正としてはじかれてしまう

> (2)paginateからcountに:distinctが渡されない

だめみたいですね。


結論としてはそのままではできない、ということ。
独自に実装するか、別の方法を考えようね･･･。

### そもそも

古いシステムなのでしょうがないと思われるが、
一度しか登録されないのでキーが重複するはずがない、
しかしキーが重複してはいけないテーブルに、
一意制約がなく、何かの偶然で重複して登録されてしまった。

ので、･･･一意制約をつけるでもなく、DISTINCTをつけることに ~~（なんで？）~~

データ設計からやりなおして･･･？

## 解決？

ビューを作ってそちらでDISTINCTするようにしました
（元々ビューを使っていたので新たに作った）

･･･と思ったら別の場所でLEFT JOIN 重複したテーブルしてた。
そっちはfindなのでDISTINCTつけようね･･･。同じような取得なのに対処違うの困るなぁ。