OmniAICreator/Qiita-1.07M huggingface dataset:
Metrics Serverを導入しKubernetesクラスター環境リソース情報の収集/監視

[以前の記事](https://qiita.com/rui-watanabe/items/0299e4e063e6f871e40e)では、Centos7でKubernetes環境を構築しました。

今回は各リソースのCPUやメモリー情報の収集/監視を行える**Metrics Serverの導入**を行っていきたいと思います。

 
## Metrics Serverリソースの設定

まずgit cloneでMetrics Serverのリソースファイルを取得し、deploymentを一部編集します。
 
```
# git clone https://github.com/kubernetes-sigs/metrics-server
# vi ./metrics-server/manifests/base/deployment.yaml

 containers:

      - name: metrics-server

        image: gcr.io/k8s-staging-metrics-server/metrics-server:master

        imagePullPolicy: IfNotPresent

        #  ここから追記

        command:

        - /metrics-server

        - --kubelet-insecure-tls

        - --kubelet-preferred-address-types=InternalIP

        #  ここまで追記

        args:

          - --cert-dir=/tmp

          - --secure-port=4443

          - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname

          - --kubelet-use-node-status-port
```

## Metrics Serverリソースの作成

リソースの設定が完了したら、applyでリソースの作成を行います。

```
# kubectl apply -k ./metrics-server/manifests/base/
```

以下のコマンドで、NAMEがmetrics-serverから始まるリソースが作成されていること確認。
 
```
# kubectl get pods -n kube-system
metrics-server-xxxxxxxxxx-xxxxx   1/1     Running   2 (5d21h ago)    8d
```

## Metrics Serverの動作確認
 

リソースの作成が確認出来たら、コマンドで各ノードと各Podの情報が取得できるようになります。
 
podのコマンドについては、適宜namespaceを指定してください。

```
# kubectl top node
NAME           CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%
k8s-master     333m         22%    1111Mi          40%
k8s-worker1    333m         44%    1777Mi          60%
k8s-worker2    333m         66%    1888Mi          50%

# kubectl top pod
NAME                                                           CPU(cores)   MEMORY(bytes)   
nginx-deployment-xxxxxxxxx-xxxxx                               0m           1Mi             
nginx-deployment-xxxxxxxxx-xxxxx                               0m           1Mi             
original-covid-app-container-deployment-xxxxxxxxxx-xxxxx       0m           2Mi 
```



以上のような表示がされたらMetrics Serverの導入は完了し、各リソース情報の収集や監視を行えます。


## 参考URL
https://github.com/kubernetes-sigs/metrics-server
https://www.server-world.info/query?os=Ubuntu_20.04&p=kubernetes&f=9
https://qiita.com/dingtianhongjie/items/a8ddc2d7f7b57291a13e
コードレスで５分でGoogle Homeに「うんち」と言ったら「うんち」と言わせる

みなさん、Google Homeに向かって「うんち」、言ってますか？
もちろん言ってますよね（圧）
でも、Homeくんは清楚キャラで居たいらしく、「うんち」と言っても「うんち」と返してくれません。
ということで、今回はHomeくんに頑張ってもらって（？）、「うんち」といってもらいましょう。

## その１、IFTTTというサービスを登録する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480613/8db2c776-fb3f-1f14-4d83-8c45f632d111.png)
上にある`Get started`を選択し、お好きな連携方法で登録をしてください。メアドがいい！という方は下の`sign up`からすることができますよ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480613/a41bc348-5405-e485-7c0a-aeea36a50b70.png)
これで、あとは指示通りに設定するだけ！

## その２、実際に「うんち」と喋らせる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480613/61399d84-d00d-89b9-181f-d856af584d5f.png)
登録が終わったら、上に`Create`というボタンが出現するのでそれをクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480613/6063ef39-57d5-5fdf-a79b-66af5d5fc285.png)
`If This`をクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480613/ed6de8d9-10bb-926f-d7e2-15350102a09b.png)
検索窓に`google assistant`と入力し、`google assistant`を選択する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480613/cdb58d4f-e43b-0571-2579-782cc179b6c4.png)
色々書いてあるが、今回は一番左の`Say a simple phrase`を選択する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480613/408200d1-fc55-3390-0691-2eb1f9af9492.png)
画像のように、まずトリガーとなる文章を入れていきます。（最大３つまで）
今回は、「うんち」と言ったときに喋って欲しいので一番上だけに「うんち」と入れます。
次に、言わせたい文章を入力します。
今回は、「うんち」と喋って欲しいので「うんち」と入れます。
完成図はこんな感じ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480613/dcf86dea-6fdb-b62f-97fd-cf154cd55a25.png)
最後に`Language`欄を`English`から`Japanese`にして下の`Create trigger`ボタンをポチ！

### ここで一つ問題が...
IFTTTというサービス、なにかトリガーになるものがあったら何かをするというサービスなんですが、今回の場合If(トリガー)の部分で完結してしまっています。
しかし、これだけではサービスは作れない...
ということで何かしらのAction(行動)を作らなくてはいけません。
ここをどうしたいかは皆さん次第ですが、今回は空メールを送ることにします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480613/65a1dc38-8673-26cf-410b-3b2a2d113cc7.png)
さっきの画面に戻るので、`Then That`を選択。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480613/314b4a6c-ef61-3772-fcbf-eec89148bf51.png)
`gmail`といれて、`Gmail`を選択。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480613/ce1ea426-042d-9a2d-d914-ebde5adc17f6.png)
今回は`To address`に自分のアドレス、`Subject`に`うんちと言いました`、`Body`に`ぶりぶり`とします。

できたら、下の`Create action`をポチ！
さっきの画面に戻るので下の`Continue`を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480613/dde5feaf-5ca7-d6da-935f-d55a37c6daad.png)
Titleを適当に考えて入力、下の`Finish`ボタンを選択

これで完成！
「うんち」と喋ったら「うんち」と言ってくれます。やったね✌

## 最後に
今回はIFTTTというサービスを使いましたが、このサービスをもっと知りたい方は各自お調べくだせぇ（結構便利）

また、Actionの部分、もっといい方法がありましたら有識者さん教えてくだせぇ
それではさようなら～
【SwiftUI】Navigationlinkで遷移した先で値を更新すると、勝手に画面が戻る件

#何をするのか？
@ObservedObject監視対象の値を使って描画している画面からNavigationlinkで遷移して、遷移先で監視対象の値を更新すると前画面に勝手に戻ってしまいます。
上記のような事象が発生する理由は監視対象の値を更新すると、前画面が再レンダリングされ、そしてNavigationLinkでDestination指定している画面（遷移先）が破棄されるためだと思われます。
上記の事象に対しての解決策を備忘録として残しておきます。

#対応前の処理
対応前は以下のようにForEachでcellModelsの配列の要素を順番に抜き出して、NavigationLinkを並べています。
この処理で画面遷移すると、遷移先で監視対象の値を更新すると、強制的に画面が戻されます。

```swift
@ObservedObject var viewModel = ViewModel()

/////////////////////////////////////////////////////////////

ForEach(viewModel.cellModels, id: \.self) { cell in
    NavigationLink(destination: MemoView(folderViewCellModel: cell),
        label: {
             Text(cell.name)
        }
    )
}
```

#対応後の処理
ForEachでindex番号を回して、NavigationLinkやlabelへの値の指定は配列にindexをしてNavigationLinkを並べていきます。
以下の処理だと遷移先で監視対象の値を更新しても、画面が強制的に戻ることはありませんでしが。
原因は正確にはわからないのですが、ForEachで使用している値が監視対象の値だと、変化するたびに再レンダリングされるけど、index番号だったら配列の要素が増えたり減ったりしない限り、値は変わらないので再レンダリングが発生しないのかなと一つ考察を残しておきます。

```swift
@ObservedObject var viewModel = ViewModel()

/////////////////////////////////////////////////////////////

ForEach(0..<viewModel.cellModels.count, id: \.self) { index in
    NavigationLink(destination: MemoView(folderViewCellModel: viewModel.cellModels[index]),
        label: {
             Text(viewModel.cellModels[index].name)
        }
    )
}
```
wsadminで設定し、設定できたことを確認する（webcontainer編）

webcontainerの場合の設定方法と設定確認方法

wsadminの問題なのか知らないが、AdminConfig.list()で取得するID後に
改行コードがあったりなかったりしてIDとして使用できるまでに色々設定がいる。
※うまい日本語化できなくてごめんなさい。

今回はwebthread数を設定する場合
参考サイト
https://stackoverflow.com/questions/30603818/modify-the-thread-pool-in-websphere-8-5-using-wsadmin-script


```jvminfo.txt
yyy1Node01,server1
yyy1Node01,server2
yyy2Node01,server1
```
設定方法

/opt/IBM/WebSphere/AppServer/profiles/Dmgr01/bin/wsadmin.sh -lang jython -user wasadmin -password wasadmin -f Webthread_set.py

設定値を変数渡しをしたい場合はこちらのコードを参照してください。
※いつか直します。。。
https://qiita.com/XKYUXSOX/items/7f33c1ee19827030f0a7

```Webthread_set.py

import csv

with open('jvminfo.txt') as f:
    csvreader = csv.reader(f)
    for row in csvreader:
      nodename=row[0]
      servername=row[1]
      id=AdminConfig.getid('/Node:'+nodename+'/Server:'+servername+'/')
      ProcessID = AdminConfig.list('ThreadPool',id)
      threadPoolList=AdminUtilities.convertToList(ProcessID)
      for thd in threadPoolList:
        if AdminConfig.showAttribute(thd,'name') == 'WebContainer':
           print nodename + servername
           AdminConfig.modify(thd,'[[maximumSize "70"]]')
           AdminConfig.modify(thd,'[[minimumSize "30"]]')
           AdminConfig.save()

```

設定確認方法

/opt/IBM/WebSphere/AppServer/profiles/Dmgr01/bin/wsadmin.sh -lang jython -user wasadmin -password wasadmin -f Webthread_get.py

```Webthread_get.py
import csv

with open('jvminfo.txt') as f:
    csvreader = csv.reader(f)
    for row in csvreader:
      nodename=row[0]
      servername=row[1]
      id=AdminConfig.getid('/Node:'+nodename+'/Server:'+servername+'/')
      ProcessID = AdminConfig.list('ThreadPool',id)
      threadPoolList=AdminUtilities.convertToList(ProcessID)
      for thd in threadPoolList:
        if AdminConfig.showAttribute(thd,'name') == 'WebContainer':
           print nodename + servername
           print AdminConfig.showAttribute(thd,'name')
           print AdminConfig.showAttribute(thd,'maximumSize')
           print AdminConfig.showAttribute(thd,'maximumSize')
```
Rubyのsuperはメソッドチェインできる

# 概要

> super は現在のメソッドがオーバーライドしているメソッドを呼び出します。括弧と引数が省略された場合には現在のメソッドの引数がそのまま引き渡されます。引数を渡さずにオーバーライドしたメソッドを呼び出すには super() と括弧を明示します。

https://docs.ruby-lang.org/ja/latest/doc/spec=2fcall.html#super

この`super`ですが、以下のようにメソッドチェーンすることで続きの処理を書くことができます。

```ruby
def some_method
  super.to_s
end
```

# 詳細

例えば次のような受け取った引数を使って文字列を返すメソッドを持ったクラス`Klass`があるとします。

```sample.rb
class Klass
  def hello(arg: nil)
    "Hello #{arg}!"
  end
end

klass = Klass.new
result = klass.hello(arg: "World")

puts result
```

これを実行すると期待通り文字列が出力されます。

```bash
% ruby sample.rb
Hello World!
```

`Klass`を`SubKlass`で継承し、メソッド`hello`をオーバーライドしてみます。

```sample.rb
class Klass
  def hello(arg: nil)
    "Hello #{arg}!"
  end
end

class SubKlass < Klass
  def hello(arg: nil)
    "Hi #{arg}!"
  end
end

klass = Klass.new
result = klass.hello(arg: "World")

puts result

sub_klass = SubKlass.new
result = sub_klass.hello(arg: "World")

puts result
```

`SubKlass`でメソッド`hello`がオーバーライドできていることが確認できます。

```bash
% ruby sample.rb
Hello World!
Hi World!
```

そして、`SubKlass#hello`の中で`super`と書くと、
`SubKlass#hello`が受け取った引数をそのまま使って継承元の`Klass#hello`の結果を得ることができます。

```ruby
class SubKlass < Klass
  def hello(arg: nil)
    super
  end
end
```

```bash
% ruby sample.rb
Hello World!
Hello World!
```

ではここからが本題です。
`super`にメソッドチェーンして、文字列を操作してみます。
(冗長なので`Klass#hello`の呼び出しは削除します)

```sample.rb
class Klass
  def hello(arg: nil)
    "Hello #{arg}!"
  end
end

class SubKlass < Klass
  def hello(arg: nil)
    super.split(" ").reverse.join(" ")
  end
end

sub_klass = SubKlass.new
result = sub_klass.hello(arg: "World")

puts result
```

これを実行すると以下のような結果を得ることができます。

```bash
% ruby sample.rb
World! Hello
```

もちろん、単純に`+`で追加の文字列を連結することも可能ですし、string以外の型でも使用できます。

これは、`super`の正体が`Klass#hello`によって返された値(`"Hello World!"`)であるがゆえに、
「戻り値のクラスの組み込みメソッドをチェーンすることで処理を追加できる」ということです。
つまり`hello`が値を返すものではない(最後の行が`puts`など)場合には意図した通りにはなりません。

### 使用例

この性質が活きると思うのは実行結果がhashを返すメソッドをオーバーライドする場合かなと思います。
例えばRailsの実装で、「基底のコントローラー`TypeA`ではリファラーのURLは必要ないけど、`TypeA`を継承したコントローラー`TypeB`では使いたい」といったような状況があったとき。

```ruby
class TypeAController < ApplicationController
  def create
    ResourceA.create(params)
  end

  def params
    {
      key_1:  params[:key_1],
      key_2:  params[:key_2]
    }
  end
end

class TypeBController < TypeAController
  def create
    ResourceB.create(params)
  end

  def params
    super.merge(additional_params)
    # => {key_1=>params[:key_1], key_2=>params[:key_2], referrer=>request.referrer}
  end

  def additional_params
    { referrer: request.referrer }
  end 
end
```

このように、サブクラスで必要になった値を足す、みたいなことができたりします。

あまり見ない書き方ではあるのですが、rubyの`super`はこのような使い方もできるというお話でした。
(他の言語でもできるのでしょうか)

# 参考

- https://docs.ruby-lang.org/ja/latest/class/String.html
- https://docs.ruby-lang.org/ja/latest/class/Array.html
PostgreSQL: テーブルの所有者を変更する (Python3)

PostgreSQL で複数のテーブルの所有者を変更する方法です。
Ubuntu 21.10 で確認しました。

ライブラリーのインストール

```bash
sudo apt install python3-dotenv
```

```text:.env
user='******'
password='******'
data_base='******'
```

```py:change_owner.py
#! /usr/bin/python3
# -*- coding: utf-8 -*-
#
#	change_owner.py
#					Nov/20/2021
#
# --------------------------------------------------------
import os
import sys
import psycopg2
import psycopg2.extras
from dotenv import load_dotenv
#
# --------------------------------------------------------
def display_tables_proc(cursor):
    sql_str="select schemaname, tablename, tableowner from pg_tables where schemaname='public' order by tablename"
    cursor.execute (sql_str)
    rows = cursor.fetchall ()
    for row in rows:
        print(row['tablename'],row['tableowner'])
# 
# --------------------------------------------------------
sys.stderr.write ("*** 開始 ***\n")
dotenv_path = '.env'
load_dotenv(dotenv_path)
USER=os.environ.get("user")
PASSWORD=os.environ.get("user")
DATA_BASE=os.environ.get("data_base")
#
conn = psycopg2.connect("dbname=" + DATA_BASE + " user=" + USER + " password=" + PASSWORD)
cursor = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
#
sql_str="select schemaname, tablename, tableowner from pg_tables where schemaname='public' order by tablename"
cursor.execute (sql_str)
rows = cursor.fetchall ()
owner_new = "scott" 
for row in rows:
#    print(row)
    print(row['tablename'],row['tableowner'])
    tablename = row['tablename']
    sql_str = "alter table " + tablename + " owner to " + owner_new
    print(sql_str)
    cursor.execute (sql_str)
    conn.commit ()
#
display_tables_proc(cursor)
cursor.close()
conn.close()
#
sys.stderr.write ("*** 終了 ***\n")
#
# --------------------------------------------------------
```
mavenの依存関係ではまった話

## Missing artifact xxxのエラーが発生した
自分向け備忘録。

次の案件でspringbootを使うらしいという話を聞いたので、おべんきょのためSTSと参考図書をゲットして最初の一歩を踏み出した瞬間であった。
とりあえず本のサンプル写経→動作確認で流れを確認しようとしました。
ほんでもってjquery、bootstrap、webjars-locationをpom.xmlに追加したところで

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2305337/9c6b6b30-73e4-2dfd-1130-7e74917f6194.png)このざま

~~こんなに色々自動化が進んでる時代なのに環境構築は落とし穴だらけだし毎回しっかりはまるので泣きそう。~~

### 現状を把握
ちなみにpom.xmlに追加したのは以下の部分。
jqueryやbootstrapの箇所は問題なく動いている。

```xml:pom.xml（抜粋）
<dependency>
	<groupId>org.webjars</groupId>
	<artifactId>jquery</artifactId>
	<version>3.6.0</version>
</dependency>
<dependency>
	<groupId>org.webjars</groupId>
	<artifactId>bootstrap</artifactId>
	<version>5.1.3</version>
</dependency>
<dependency>
	<groupId>org.webjars</groupId>
	<artifactId>webjars-locator</artifactId>
	<version>0.4.0</version>
</dependency>
```
ユーザフォルダ配下の.m2フォルダ（maven依存関係関連のファイルが配置されてるフォルダ）を確認。
~~指定したファイル自体は落とせてました~~ 
落とせてると思ってました。
問題が解決してから落ち着いて見たら中身はjar入ってなかったです。フォルダの中まで見てください自分。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2305337/87ad2a02-531d-06f7-410c-5998e80eed3f.png)

### Mavenのセントラルリポジトリに無いバージョンはアカンらしい
[Mavenのセントラルリポジトリ](https://mvnrepository.com/)で取り扱ってるwerbjars-locatorのバージョンを確認。
pom.xmlに指定しなおして解決しました。

```xml:pom.xml(修正後）
<dependency>
	<groupId>org.webjars</groupId>
	<artifactId>jquery</artifactId>
	<version>3.6.0</version>
</dependency>
<dependency>
	<groupId>org.webjars</groupId>
	<artifactId>bootstrap</artifactId>
	<version>5.1.3</version>
</dependency>
<!-- webjars-locatorのversionを0.4.0から0.42へ修正しています-->
<dependency>
	<groupId>org.webjars</groupId>
	<artifactId>webjars-locator</artifactId>
	<version>0.42</version>
</dependency>
```

### 技術書の内容は疑え
これ毎度思うんだけど忘れたころにやってくる。
誤記だったり、記載内容が古いっていうのはよくある話なので今回もその類なんでしょう。
wsadminで設定し、設定できたことを確認する（Cookie編）

今回はwsadminで特定の設定を取得する方法
ノードとアプリケーションサーバの情報は別ファイルから呼び出す方法
まずは定義ファイル

```jvminfo.txt
yyd1Node01,server1
yyd1Node01,server2
yyd2Node01,server1
```
Cookieの設定するコード
設定値を変数渡しをしたい場合はこちらのコードを参照してください。
※いつか直します。。。
https://qiita.com/XKYUXSOX/items/7f33c1ee19827030f0a7

``` "Cookie_set.py
import csv

with open('jvminfo.txt') as f:
    csvreader = csv.reader(f)
    for row in csvreader:
      nodename=row[0]
      servername=row[1]
      id=AdminConfig.getid('/Node:'+nodename+'/Server:'+servername+'/')
      ProcessID = AdminConfig.list('Cookie',id)
      print nodename + servername
      AdminConfig.modify(ProcessID,'[[name "EEJSESSION"]]')
      AdminConfig.modify(ProcessID,'[[secure "true"]]')
      AdminConfig.modify(ProcessID,'[[httpOnly "true"]]')

AdminConfig.save()

```



Cookieの設定情報を取得するコード

``` "Cookie_get.py

import csv

with open('jvminfo.txt') as f:
    csvreader = csv.reader(f)
    for row in csvreader:
      nodename=row[0]
      servername=row[1]
      id=AdminConfig.getid('/Node:'+nodename+'/Server:'+servername+'/')
      ProcessID = AdminConfig.list('Cookie',id)
      print nodename + servername
      print AdminConfig.showAttribute(ProcessID,'name')
      print AdminConfig.showAttribute(ProcessID,'secure')
      print AdminConfig.showAttribute(ProcessID,'httpOnly')
```

設定変更していることを確認する。
[WIP] Dockerfile Tips

# Dockerfileのダウンロードからコンテナ作成までの流れ
1. Docker Desktopのインストール
1. Docker Desktopの起動
1. Dockerfileのダウンロード
1. Docker Imageの作成
1. Docker Containerの作成

# WSL上のUbuntuでdockerが使用できない
- WSL上のUbuntuで`docker build`を実行した時、下記のようなエラーが排出される。

```
The command 'docker' could not be found in this WSL 1 distro. 
We recommend to convert this distro to WSL 2 and activate
the WSL integration in Docker Desktop settings.
```
- このときは、記載の通りWSLのバージョンを1から2に上げる。

```
$ wsl --set-version Ubuntu 2
```
- その後、さらに下記のようなエラーが排出される。

```
The command 'docker' could not be found in this WSL 2 distro.
We recommend to activate the WSL integration in Docker Desktop settings.

See https://docs.docker.com/docker-for-windows/wsl/ for details.
```
- Docker Desktopを起動し、Settings > Resources > WSL INTEGRATIONでUbuntu(この画像ではUbuntu-18.04)をONにする。
![wsl2-choose-distro.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95700/f9743c3b-5d05-2f03-ff0a-2ca40942e94d.png)

- 右下のApply & Restartを押下する。
## 参考
- [wsl上のubuntuでdockerが使用できない](https://zenn.dev/kathmandu/articles/4a86c3d75b93c3)
- [Docker Desktop WSL 2 backend, Install](https://docs.docker.com/desktop/windows/wsl/#install)
【備忘録】Docker+Apache2+Laravelで404 Not Found

人からいつもDocker環境をもらってたので、今回初めて自分でDockerのapacheイメージをpullし、そこにLaravelをインストールして開発を始めたが、http://***.****.com/以外受け付けてくれない。
routeの問題かと思ったがそうでもなさそう。

[routes/web.phpの確認方法]
php artisan route:list

色々記事を検索していくと、「ルート以外にアクセスできない時は、mod_rewriteを疑え」というのを見つけたので、早速confファイルを探すが、どこにも記述がない。

これまでLINUXはCentOSばかり触ってたので、ubuntuには何か違いがあるのか探してみたら、あったあった。

[ubuntu+apache2でLoadModuleの設定方法]
(shellから)
root@-----------:/etc/apache2# a2enmod
Your choices are: access_compat actions alias allowmethods asis auth_basic auth_digest auth_form authn_anon authn_core authn_dbd authn_dbm authn_file authn_socache authnz_fcgi authnz_ldap authz_core authz_dbd authz_dbm authz_groupfile authz_host authz_owner authz_user autoindex brotli buffer cache cache_disk cache_socache cern_meta cgi cgid charset_lite data dav dav_fs dav_lock dbd deflate dialup dir dump_io echo env expires ext_filter file_cache filter headers heartbeat heartmonitor http2 ident imagemap include info lbmethod_bybusyness lbmethod_byrequests lbmethod_bytraffic lbmethod_heartbeat ldap log_debug log_forensic lua macro md mime mime_magic mpm_event mpm_prefork mpm_worker negotiation php7 proxy proxy_ajp proxy_balancer proxy_connect proxy_express proxy_fcgi proxy_fdpass proxy_ftp proxy_hcheck proxy_html proxy_http proxy_http2 proxy_scgi proxy_uwsgi proxy_wstunnel ratelimit reflector remoteip reqtimeout request rewrite sed session session_cookie session_crypto session_dbd setenvif slotmem_plain slotmem_shm socache_dbm socache_memcache socache_redis socache_shmcb speling ssl status substitute suexec unique_id userdir usertrack vhost_alias xml2enc
Which module(s) do you want to enable (wildcards ok)?

こうやってubuntuでは設定するものなのかと納得。

この設定を行った後、あっさりと追加したURLは表示されたとな。(´・ω・`)
renderingMode(_:)に.templateを設定すると何が変わる？

## 概要
SwiftUIで画像を扱うとき`renderingMode(_:)`に`.template`を設定したときに何が変化するのか気になりました。
調べてみます。

## 環境
`macOS Big Sur 11.6`
`Xcode 13.1`

## 公式の説明
意訳したものを添付します。

:::note info
.originalと.templateの二つを設定できます。
:::

:::note info
.originalを設定した場合、元画像のまま表示されます。
:::

:::note info
.templateを設定した場合、画像の色を変更できます。
:::

https://developer.apple.com/documentation/swiftui/image/renderingmode(_:)

## 使ってみる
３つのサンプルを準備して試してみます。
1. 何も設定しない
2. `.original`を設定する
3. `.template`を設定する

```swift:RenderingModePlayground.swift
struct RenderingModePlayground: View {
    var body: some View {
        HStack {
            Image(systemName: "person.crop.circle.badge.plus")
            Image(systemName: "person.crop.circle.badge.plus")
                .renderingMode(.original)
                .foregroundColor(.blue)
            Image(systemName: "person.crop.circle.badge.plus")
                .renderingMode(.template)
                .foregroundColor(.blue)
        }
        .font(.largeTitle)
    }
}
```

表示は以下のようになります。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551042/8d130812-b8dd-44c9-8db7-fad9a8bdb05a.png" width="300" />

### 公式の説明を確認してみる

##### 何も設定しない場合
ライトモードではアイコンを黒色で表示する。
ダークモードではアイコンを白色で表示する。

##### `.original`を設定する場合
以下和訳

>オリジナルのテンプレートレンダリングモードと青の前景色を使用して、マルチカラーの動作を実現しました。このモードでは、画像の特徴的な部分（ここではプラスのアイコン）の前景色がグラフィックで上書きされます。

「画像のプラスの箇所だけオリジナルの緑色が適用されて、それ以外は`foregroundColor`で設定した色で表示される」ということなのでしょう。

>画像の特徴的な部分

ただ、この判定はどのように行われているのか疑問です。

##### `.template`を設定する場合
ダークモード・ライトモード変わらず`foregroundColor`で設定した色で表示されます。
MemLabs Lab1 で Volatility3 を勉強した

Volatility3 を勉強した記録
題材 stuxnet999/MemLabs

問題配付サイト

https://github.com/stuxnet999/MemLabs/tree/master/Lab%201


# プロセス列挙

```
# python3 vol.py -f MemoryDump_Lab1.raw windows.pstree

（略）
2504	3000	explorer.exe	0xfa800104a780	34	825	2	False	2019-12-11 14:37:14.000000 	N/A
* 2304	2504	VBoxTray.exe	0xfa800104a780	14	144	2	False	2019-12-11 14:37:14.000000 	N/A
* 1512	2504	WinRAR.exe	0xfa800104a780	6	207	2	False	2019-12-11 14:37:23.000000 	N/A
```

WinRAR.exeが不審

# WinRAR.exeのコマンドラインから使っているファイルを調べる

```
# python3 vol.py -f MemoryDump_Lab1.raw windows.cmdline

（略）
1512	WinRAR.exe	"C:\Program Files\WinRAR\WinRAR.exe" "C:\Users\Alissa Simpson\Documents\Important.rar"
```

# ファイル「Important.rar」をダンプ

```
# python3 vol.py -f MemoryDump_Lab1.raw windows.filescan | grep Important.rar

0x3fa3ebc0 100.0\Users\Alissa Simpson\Documents\Important.rar	216
0x3fac3bc0	\Users\Alissa Simpson\Documents\Important.rar	216
0x3fb48bc0	\Users\Alissa Simpson\Documents\Important.rar	216
```

```
# python3 vol.py -f MemoryDump_Lab1.raw windows.dumpfiles --physaddr 0x3fa3ebc0
```

パスワードがかかってる

# プロセス「WinRAR.exe」をダンプ

```
＃python3 vol.py -f MemoryDump_Lab1.raw windows.pslist --pid 1512 --dump
```

```
# strings -a pid.1512.0x13f710000.dmp > ascii.txt
# strings -a -el pid.1512.0x13f710000.dmp > unicode.txt
```

手がかり無し。ここで終了

https://jpn.nec.com/cybersecurity/blog/200131/index.html

だと，WinRAR.exeのダンプからPassword is NTLM hash of Alissa's acount passwdと表示されるらしいが，Volatility3では何も出ない。
MemLabs Lab0 で Volatility3 を勉強した

Volatility3 を勉強した記録
題材 stuxnet999/MemLabs

問題配付サイト

https://github.com/stuxnet999/MemLabs/tree/master/Lab%200

# プロセス列挙

```
# python3 vol.py -f Challenge.raw windows.pstree

（略）
324	1876	explorer.exe	0x84d83d20	33	827	1	False	2018-10-23 08:30:04.000000 	N/A
* 1000	324	VBoxTray.exe	0x84d83d20	14	159	1	False	2018-10-23 08:30:08.000000 	N/A
* 2096	324	cmd.exe	0x84d83d20	1	22	1	False	2018-10-23 08:30:18.000000 	N/A
* 2412	324	DumpIt.exe	0x84d83d20	2	38	1	False	2018-10-23 08:30:48.000000 	N/A
```

エクスプローラでcmd.exeを表示してWクリックする等して cmd が起動されている。（デスクトップのショートカットから起動したのかも？）

とにかく PID 2096 の cmd.exe が不審。

volatility3からcmdscanがなくなっているから，cmd.exeのダンプをとってみる。

# プロセス「cmd.exe」をダンプ

```
# python3 vol.py -f Challenge.raw windows.pslist --pid 2096 --dump
```

strings (Unicode) で ￥ を検索

```
# strings -a -el pid.2096.0x4aa80000.dmp | grep -i -F \\

\XCOPY.EXE
\\.\
Software\Policies\Microsoft\Windows\System
Software\Microsoft\Command Processor
Software\Classes
\\?\
 :\*
\CMD.EXE
C:\Users\hello
Desktop\
C:\Users\hello>
C:\Python27
C:\Python27\python.exe C:\Users\hello\Desktop\demon.py.txt   <-- ★
m;C:\Windows\System32\WindowsPowerShell\v1.0\
:\Users\hello\Desktop\demon.py.txt
:\Python27\python.exe C:\Users\hello\Desktop\demon.py.txt
\Shell\Open\Command
```

pythonコードが書かれた demon.py.txt を動かしてる

# ファイル「demon.py.txt」をダンプ

filescan でアドレスを特定

```
# python3 vol.py -f Challenge.raw windows.filescan | grep -i -F "demon.py.txt"

0x3d4d1dc8 100.0\Users\hello\Desktop\demon.py.txt	128
```

アドレスが判ったので，dumpfilesでダンプ

```
# python3 vol.py -f Challenge.raw windows.dumpfiles --physaddr 0x3d4d1dc8
```

あとは見るだけ

```
# cat file.0x3d4d1dc8.0x84dde548.DataSectionObject.demon.py.txt.dat

a = "1_4m_b3tt3r}"
b = ""
for i in a:
    b = b + chr(ord(i)^2)
print b.encode("hex")
```

フラグの末尾が見えました。
Lightning レコードページでコンポーネントの表示を設定する数式項目


数式項目を使用して、Lightning レコードページでのコンポーネントの表示を制御できます。

表示フィルターで個人取引先項目にもアクセスできるはずだと思います。可能であれば、スクリーンショットを共有していただけますか? 

同じデータ型の 2 つの項目が表示されます。1 つは取引先 obj で、もう 1 つは取引先責任者項目 (個人取引先) で作成された項目です。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/9c6c4198-55d7-f492-f856-1f85f4895698.png)


大丈夫！「Is Deceased」と入力する代わりに、「Person Account」と入力してそのオプションを選択し、その Deceased__pc フィールドを表示できるかどうかを確認していただけますか?

[数式とLighrningページを使って可視性を制御するらしい](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000IRSsLSAX)
kaggle API でデータセットをアップする

# 初めに
自分の環境で学習したモデルをアップロードする際に、kaggleAPIを使わないと大変です。。。

# 1. init
kaggleの初期セットアップ完了後、下記コマンドを実行する。

```shell:command
kaggle datasets init -p hoge
```

hoge/dataset-metadata.json というファイルが生成される


# 2. metadataを編集する
metadataは下記のようになっている。
ここの、大文字部分を編集する必要がある。
SLUGはハイフンしか使えないので注意！
```
{
 "title": "INSERT_TITLE_HERE",
 "id": "<name>/INSERT_SLUG_HERE",
 "licenses": [
  {
   "name": "CCO-1.0"
  }
 ]
}
```
↓

```

{
 "title": "hogefuga", 
 "id": "<name>/hogefuga",
 "licenses": [
  {
   "name": "CCO-1.0"
  }
 ]
}
```

# 3. upload 

```shell:ファイルをuploadする場合
kaggle datasets create -p hoge
```
```shell:フォルダをアップロードする場合
kaggle datasets create -p hoge --dir-mode zip
```
こんな感じです。
OCPをアップグレードしたらOCSが動かなくなって焦った

#環境情報
- IBM Cloud Managed Openshift(ROKS)
- OCP Version 4.7 -> 4.8
- OCS Version 4.7

#やったことと、起こったこと
IBM Cloud Web UIから順にOCPをバージョンアップ。
Workerノードを順にアップグレードしている際に、OCSまわりのPodが起動しなくなった。

#解決方法
アップグレード前後のノードを比較して、ラベル情報が違うと気づいた。
その後、同じラベルを付与することで解決した。

OCSの[ノードの置き換えガイド](https://access.redhat.com/documentation/ja-jp/red_hat_openshift_container_storage/4.7/html/replacing_nodes/index)にラベルを付与する手順があったので、
間違った手順ではないと思っておこう。

```shell
$ oc label node <new_node_name> cluster.ocs.openshift.io/openshift-storage=""
```
以上、
OCS自体初めて使っていて、よく分かってなかったのでだいぶ焦った話でした。
Tableau 書式設定を理解する 番外編


## 前置き
　Tableauを使っていて毎回書式設定でどこをどう変えれば良いかよく分からず、とりあえずいじりまくって何とかしていますが、いい加減非効率なので一回書式設定をきちんと理解しておこうと思いまとめてみました。 

　これまで、[前編](https://qiita.com/zaki_001/items/c83bc2881a6b54a9f997 "Tableau 書式設定を理解する 前編")、[後編](https://qiita.com/zaki_001/items/10ce5c9155887a711f34)にわたってシート単位での書式設定について整理してきましたが、本記事ではそこでは書ききれなかった内容をTips的に紹介します。


https://qiita.com/zaki_001/items/c83bc2881a6b54a9f997

https://qiita.com/zaki_001/items/10ce5c9155887a711f34

##ワークブック/ダッシュボード一括で書式設定

###ワークブックの書式設定
 書式設定->ワークブックでワークブック共通で書式設定を変更することができます。設定できるのはフォントと線だけですがワークブック全体の設定を変えるときに便利です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307669/f995ef6a-cdbf-286c-d159-6682f49cc9e9.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307669/e32ee283-29a1-4964-744e-41d6d9ce5226.png)
　フォント->すべて ではワークブック全体の書体と文字色を変更できます。例えばTableauは初期設定では文字色がグレーに近い黒に設定されていて場合によっては見えづらい場合があるため、くっきりさせたいので黒に変更したいといったときに便利です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307669/490e0bca-0413-958f-429f-994b82b54a31.png)
　ワークシート～ストーリーのタイトルまでは、書体、文字色に加えて文字サイズ/装飾を設定可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307669/68b455b7-631b-4e39-1d88-a1a5a41572ab.png)
　線の設定に関しては、ワークブック全体の各線の線種類や太さ、色を変更可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307669/a032a107-ca40-4f18-dee3-6b4115c9d7d7.png)


###ダッシュボードの書式設定
 書式設定->ダッシュボード、またはダッシュボード->書式設定でダッシュボードの書式設定メニューが表示されます。ここでは次の4つの設定ができます。

+ ダッシュボードの網掛け：ダッシュボードの背景色を設定できます
+ ダッシュボードのタイトル：ダッシュボードのタイトルの書式を設定できます。
+ ワークシートのタイトル：ダッシュボードに含まれるワークシートのフォントと背景色を一括で変更できます。
+ テキストオブジェクト：ダッシュボードに含まれるテキストオブジェクトのフォントと配置を一括で変更できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307669/993dd1b3-8156-fe55-90d3-700ba7246ab6.png)
　実際に各設定を変更してみました。左がデフォルト状態、右が変更後です。ダッシュボードの4つの書式設定だけですが、テキストオブジェクトが2つとも書式が変わっていることがわかります。またワークシートのタイトルも2つとも書式が変わっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307669/c6b51839-534f-5bff-26cc-29afa98b6020.png)
　注意点として、個々のテキストオブジェクトで個別に書式設定している場合はそちらが優先され、ダッシュボードの書式設定での設定は反映されれなくなります。反映させたい場合はテキストオブジェクトの編集画面右端の×ボタンを押して書式設定をクリアすればOKです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307669/5f5184f7-72f7-d351-8edb-798b6ac0a10e.png)


##書式設定のコピー
　シート間で書式設定をコピーすることができます。コピー元のワークシートで書式->書式設定のコピーをクリックし、コピー先のワークシートに移動して書式->書式設定の貼り付けをクリックすればOK。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307669/7c8b9524-9ddb-4df5-2866-6ec8e78cc553.png)


## 　

https://qiita.com/zaki_001/items/f2e7087dc3b0fa2efae8
5.1 Webフレームワークの紹介


# Webフレームワークとは

ライブラリとか、フレームワークとか聞きなれない言葉かもしれません。
簡単に言うと、

<font color="red">便利なプログラムの部品をいっぱい集めて、ひとまとめにしたファイルのこと</font>

です。テンプレート群です。

世の中にはたくさんのライブラリ、フレームワークがあります。

CSSのみに特化したフレームワークもありますし、いろいろな機能をひと纏めにしたものなど様々です。

簡単に利用でき、見た目も良かったりというメリットもありますが、
デメリットとしては、bootstrapっぽいとか、使用したライブラリっぽい
似通ったものになるという点でしょうか。

# BootStrap（ブートストラップ）のサイトを見てみよう

https://getbootstrap.jp/

部品を見る
サンプルページを見る

# Matrial UI（マテリアルユーアイ）のサイトを見てみよう

# BootStrapを使ってみよう

[Bootstrapのページ](https://getbootstrap.jp/)にアクセスしダウンロードボタンをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1888749/9598ca34-1339-f54c-0204-37320c87abae.png)

コンパイルされたCSSとJSソースをダウンロードします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1888749/3ee0763c-e862-91fe-852d-c53ccd2d5884.png)

フォルダを作成し（任意）、CSSとJSのフォルダを作成フォルダに移動します。
また、index.htmlを同じ階層に作成しておきます。

以下は、VSCode作成フォルダを開いた状態です。

いつものように`!＋Tabキー`でHTMLソースを生成し、
headタグの最後の方に2行追加しCSSとJSを読み込ませます。
（link＋Tabキーでテンプレートが出ます。script＋Tabキーで同様にテンプレートが出ます。）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1888749/2ae62d1c-f4d0-4e15-9b19-e92045ddd028.png)

Bootstrapのコンポーネントはたくさんありますが、まずは一つ試してみましょう。
Bootstrapページの左側メニューのComponentsからAccordionを選択しソースをコピーして
index.htmlのbodyタグ内に貼り付けて実行してみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1888749/4ab795e4-7ed6-8d8a-a869-f6fd3f1e1565.png)

Bootstrapページ同様のコンポーネントが表示されたと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1888749/f487a170-3c85-6192-bd9c-2154d409ff10.png)

これらの部品（コンポーネント）を組み合わせて、独自のページを作成していきます。

# Material UIを使ってみよう
I2Cキーボード（FreeRTOS理解:番外編1）

# I2Cキーボードを試す
スイッチサイエンスなどで入手できる[I2Cキーボード](https://www.switch-science.com/catalog/5689/)を試した。M5Stack用、、と記載されているが、I2C制御できるものであれば、どんなものにでも接続できる。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/3d5bc47e-4f2b-b921-fd48-3b1402039b68.jpeg", width=80%>
今回は、Arduinoに接続した。

## ハードウェア
ATmega328p U-THにより制御されている。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/80dba552-e18b-7626-b4d7-68cc399aae0f.png", width=80%>
ピン配置は異なるが、Arduino搭載のマイコンと基本的には同じ。

## 参考ソースコード
Arduino IDE上で利用できるソースコードは、[ここ](https://github.com/m5stack/M5-ProductExampleCodes/tree/master/Unit/CARDKB/Arduino)に見つかる。

## テスト用ソースコード
FreeRTOSを使って、キーボード入力を行うタスクを設け、改行コードが入力されたら、それまでに入力された内容を別タスクに伝えることとした。

### 定義
```c++
#include <Arduino_FreeRTOS.h>
#include <queue.h>
#include <Wire.h>

#define CARDKB_ADDR   0x5F    // I2C slave address
#define KBD_BUF_SIZE  32
#define NL            0x0d
#define BS            0x08

TaskHandle_t xKbd, xRecv;
QueueHandle_t qMsg;
```

- ArduinoでFreeRTOSの利用
- FreeRTOSでのQueueの利用
- I2Cアドレス
- キーボードバッファサイズおよび特殊コード（改行およびバックスペース）
- タスクハンドラ及びキューの定義

### キーボード入力タスク（行入力）
```c++
void TaskOneLine(void *arg) {
  char      key[KBD_BUF_SIZE];
  uint16_t  i = 0;
  for (;;) {  
    Wire.requestFrom(CARDKB_ADDR, 1);
    while (Wire.available()) {
      char c = Wire.read();   // receive a byte
      if (c != 0) {
        if (c == BS) {        // Back space
          if (i != 0) {
            i--;
          }          
        } else {              // Store input data in buffer
          key[i++] = c;       // Not consider KBD_BUF_SIZE for input
          if (c == NL) {      // Read until new line and Send data to queue
            key[i] = 0;
            xQueueSend(qMsg, key, portMAX_DELAY);
            i = 0;
          }
        }
      }
    }
    vTaskDelay(1);
  }  
}
```
- 1バイト入力およびキーボードバッファへの格納
- バックスペース入力時にはキーボードバッファで1バイト分戻る
- 改行入力時にはQueueにキーボードバッファをつむ

### キーボードバッファを受けるタスク
ここでは、数値を受信することを想定して、数値分、LEDの点灯を繰り返すこととした。なお、数値以外のコード入力時のエラー処理は考慮していない。

```c++
void TaskDataRecv(void *arg) {
  char      buf[KBD_BUF_SIZE];
  
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);
  for (;;) {
    if (xQueueReceive(qMsg, buf, portMAX_DELAY) == pdPASS) {
      //Serial.println(buf);
      uint16_t n = atoi(buf);
      for (int i=0; i<n; i++) {
        digitalWrite(LED_BUILTIN, HIGH);
        delay(300);
        digitalWrite(LED_BUILTIN, LOW);
        delay(300);
      }
    }  
    vTaskDelay(1);
  }
}
```

実用では、バッファ受信側で、自由なコードを作ればよい。

### Arduinoお決まり部分
```c++
void setup() {
  Serial.begin(9600);
  Wire.begin();
  qMsg = xQueueCreate(1, KBD_BUF_SIZE);
  xTaskCreate(TaskOneLine, "TaskOneLine", 128, NULL, 1, &xKbd);
  xTaskCreate(TaskDataRecv, "TaskDataRecv", 128, NULL, 1, &xRecv);
  vTaskStartScheduler();
}

void loop() {
  // Nothing in Arduino
}
```

- I2C初期化
- キュー初期化
- タスク生成
- タスクスケジューリング

## 最後に
執筆時点で1111円。自明であるが、キーボードはマイコン制御に便利である。
JupyterでDockerカーネル(Python)を選択できるようにするレシピ

# はじめに

JupyterLabを使うとき、いろんな環境で使いたいなあなんて思ってました。そのために、DockerにJupyterLabを入れて起動していたのですが、そもそもJupyterのカーネルで、Dockerのカーネルを選択できれば便利ではないか？と思って、どうやればいいか調べてみました。
この設定をすることで、お好きなDockerイメージのカーネルでJupyterを起動できるようになります。自分用にまとめておこうと思ったのですがKaggleのGPUのDockerイメージのカーネルを追加してみたので、KagglerでDeepLearningをする人にもおすすめできそうだなあと思って、Qiitaに記事を書いておくことにしました。こんな感じで**Kaggleのイメージのカーネルを選べます！**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630841/a193d55f-9917-f66f-f234-76b3e0fb4874.png)

# 実行環境

* Ubuntu: 20.04
    * MacとかWindowsでも本質は同じだと思います
* Docker: 20.10.10
* JupyterLab: 3.2.3
    * 多分JupyterNotebookだけでもいいはず。
* NVIDIAドライバ: 450.156.00
    * GPUを使用しない場合は不要
* NVIDIA Container Toolkit: 1.5.1-1
    * GPUを使用しない場合は不要

# 設定手順

## Dockerのカーネルをjupyterに追加

まず、JupyterLabのインストール先を確認します。特に自分で指定していない場合は、`~/.local/`以下のはずです。

インストール先の階層を辿っていくとkernelsというディレクトリがあるので、そこに作成したいカーネルごとにディレクトリを作成します。

```shell
cd JupyterLabのインストール先/share/jupyter/kernels
mkdir kaggle_v106
cd kaggle_v106
```

これで`JupyterLabのインストール先/share/jupyter/kernels/kaggle_v106`というディレクトリが作成されて、作成した`kaggle_v106`がカレントディレクトリとなっているはずです。`kernel.json`というファイルを新規作成します。

```shell
touch kernel.json
```

そしたら、お好みのエディタでこのファイルを開いて、内容を以下の通りにしてください。

```
{
 "argv": [
  "/usr/bin/docker",
  "run",
  "--network=host",
  "--gpus",
  "all",
  "-v",
  "{connection_file}:/connection-spec",
  "gcr.io/kaggle-gpu-images/python:v106",
  "python",
  "-m",
  "ipykernel_launcher",
  "-f",
  "/connection-spec"
 ],
 "display_name": "kaggle:v106",
 "language": "python"
```

必要に応じて以下の変更を加えてください。

GPUを使用しない場合は次の記述は不要です。

```
  "--gpus",
  "all",
```

他のコンテナを使用したい場合は、次の記述を変更してください。ただしそのコンテナにはipythonとipykernelがインストールされている必要があります。

```
  "gcr.io/kaggle-gpu-images/python:v106",
```

お好きな表示名に変えてください。

```
 "display_name": "kaggle:v106",
```

# アイコンを変える

カッコよくJupyter上の表示でアイコンを表示させたい人は`logo-32x32.png`と`logo-64x64.png`というロゴ画像ファイルを用意してください。解像度はそれぞれ32x32、64x64としてください。今回の例ではKaggleのアイコンを使用しています。

以上でJupyterから使えるようになってるはずです！

# 備考

:::note warn
jupyterlabを起動するユーザはdockerコマンドを使える必要があります。従ってdockerグループに属している必要があります。
:::


# さいごに

もっと詳しく書いてほしいとか、こうするにはどうしたらいいかとか要望がありましたらコメント頂けますと幸いです。最大限対応いたします！

# 参考

## DockerでGPUを使う準備ができていない人へ

NVIDIAドライバやNVIDIA Container Toolkitをインストールしておいてください。

https://qiita.com/karaage0703/items/e79a8ad2f57abc6872aa
dockerfile で一般ユーザーを作成する

# Dockerfile

```dockerfile
ENV UNAME=docker
ENV GID=1000
ENV UID=1000

RUN groupadd -g $GID -o $UNAME
RUN useradd -m -u $UID -g $GID -G sudo -o -s /bin/bash $UNAME
RUN echo "$UNAME ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
```

こんな感じに書いてあげると、一般ユーザーを作成できる。

```
echo "$UNAME ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
```

のコマンドによって、`sudo` もパスワード無しで実行できるようになる

# docker-compose
user で id を指定してあげると、ログインユーザーを変更できる。

```yml
version: "3.7"
services:
  app:
    ...
    environment:
      GID: 1000
      UID: 1000
    user: "1000:1000"
```

# ちょっとはまったところ
node のイメージだったりだと、`UID 1000` ですでに一般ユーザーが用意されている場合がある。
この場合は `RUN echo "node ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers` としてあげることで、 `sudo` が使えるようになる。
ヤコビ行列のつくり方入門　~ヤコビ行列を次元を増やしながら理解してみる~

# ヤコビ行列とは

一言でいうと出力がベクトルの多変数関数を偏微分した結果を行列の形に整列したものです．
とても単純に言うとただの微分の集まりです．

ヤコビ行列とは？と思っている方でもなるべく理解しやすいように，単純な式からヤコビ行列を組み立てていき，自分でも作れるようにだんだんと理解を進めていきます．



# 出力が1つ，変数が1つの場合のヤコビ行列
以下の式のヤコビ行列を考えます．

$$
f(x)=ax+b
$$
の微分値が

$$
\frac{df(x)}{dx}=a
$$
となるため，式$f$のヤコビ行列$J$は1行1列となり

$$
J = (\frac{df(x)}{dx})=(a)
$$
となります．

1次元であれば偏微分を使わないので簡単ですね．
ただの微分式です．


# 出力が1つ，変数が2つの場合のヤコビ行列

関数の出力が1つで変数が2つある式，つまり<font color="red">多変数関数</font>を考えてみましょう．
多変数関数$f$を

$$
f(x_1, x_2) = ax_1 + bx_2 + c
$$


としたとき，式$f$のヤコビ行列$J$は1行2列となります．
今回は2変数を扱うため，変数ごとの微分，すなはち<font color="red">偏微分</font>が必要になります．そのためヤコビ行列$J$は

```math
\begin{align}
J &= (\frac{df}{dx_1} \ \ \frac{df}{dx_2}) \\
  &= (\frac{ax_1 + bx_2 + c}{dx_1} \ \ \frac{ax_1 + bx_2 + c}{dx_2}) \\
  &= (a \ \ b)
\end{align}
```

となります．

# 出力が2つ，変数が2つの場合のヤコビ行列

関数の出力が1つで変数が2つある式，つまり<font color="red">出力がベクトル</font>である多変数関数を考えてみましょう．
出力がベクトルの多変数関数$\boldsymbol{f}$を

$$
\boldsymbol{f}(x_1, x_2) = \left\\{ f_1, f_2 \right\\}
$$
ここで$f_1, f_2$の中身を

```math
f_1(x_1, x_2) = ax_1 + bx_2 + c \\
f_2(x_1, x_2) = dx_1 + ex_2 + f
```
としたとき，式$\boldsymbol{f}$のヤコビ行列$J$は2行2列となります．
今回は出力も2つあるため，それぞれを偏微分してやる必要があります．そのためヤコビ行列$J$は


```math
J = 
\left(
\begin{array}{ccc}
\frac{df_1}{dx_1} & \frac{df_1}{dx_2} \\
\frac{df_2}{dx_1} & \frac{df_2}{dx_2} \\
\end{array}
\right)
```

となります．


# 出力がN個，変数がM個の場合のヤコビ行列

ここまで解ければあとはどれだけ出力と変数の数が増えても同じですね．
先ほどと同様に出力がベクトルの多変数関数$\boldsymbol{f}$を考えてみましょう．

$$
\boldsymbol{f}(x_1, x_2, .... , x_M) = \left\\{ f_1, f_2, .... , f_N \right\\}
$$
ここで$f_1, f_2, .... , f_N$の中身を

```math
\begin{align}
f_1(x_1, x_2, .... , x_M) &= k_{1,1}x_1 + k_{1,2}x_2 + ..... + k_{1,M}x_M + c \\
f_2(x_1, x_2, .... , x_M) &= k_{2,1}x_1 + k_{2,2}x_2 + ..... + k_{2,M}x_M + c \\
\vdots \\
f_N(x_1, x_2, .... , x_M) &= k_{N,1}x_1 + k_{N,2}x_2 + ..... + k_{N,M}x_M + c \\
\end{align}
```

<br>
としたとき，式$\boldsymbol{f}$のヤコビ行列$J$はN行M列となります．このときヤコビ行列$J$は

```math
J = 
\left(
\begin{array}{ccc}
\frac{df_1}{dx_1} & \frac{df_1}{dx_2} & ... & \frac{df_1}{dx_M} \\
\frac{df_2}{dx_1} & \frac{df_2}{dx_2} & ... & \frac{df_2}{dx_M} \\
& & \vdots & \\
\frac{df_N}{dx_1} & \frac{df_N}{dx_2} & ... & \frac{df_N}{dx_M} \\
\end{array}
\right)
```

これでヤコビ行列が作れました．
TypeScriptでパスワードを自動生成

今回はパスワード自動生成機能を作る機会があったのでついでにメモ。
標準ライブラリのみで実装しました。

## サンプル

```typescript 
const getAutoGeneratePassword = () => {
  // パスワードの文字数を決定
  const maxLength = 20
  const minLength = 8

  // パスワードに使用可能な文字を決定（今回はアルファベットの大文字と小文字 ＋ 数字 ＋ symbolsの記号）
  const lowerCase = 'abcdefghijklmnopqrstuvwxyz'
  const upperCase = lowerCase.toLocaleUpperCase()
  const numbers = '0123456789'
  const symbols = '%&$#()'
  const chars = lowerCase + upperCase + numbers + symbols

  // パスワードが持つ文字列条件を正規表現で追加（今回はアルファベット小文字1つ以上かつ数字1つ以上）
  const lowerCaseRegex = new RegExp('[a-z]')
  const numberRegex = new RegExp('[0-9]')

  // autoGeneratedPasswordが以上の条件を満たせばvalidがtrueになる
  let valid = false
  let autoGeneratedPassword: string

  while (!valid) {
    autoGeneratedPassword = ''
    // パスワードの文字数を上で決めた範囲内（今回は8文字以上20文字以下）でランダムに決定
    const randomLength =
      Math.floor(Math.random() * (maxLength - minLength)) + minLength
    while (autoGeneratedPassword.length < randomLength) {
      // 上で決定したcharsの中からランダムに1文字ずつ追加
      const index = Math.floor(Math.random() * chars.length)
      autoGeneratedPassword += chars[index]
    }

    // パスワードが上で決定した条件をすべて満たしているかチェック
    // 条件を満たすまでループ
    valid =
      minLength <= autoGeneratedPassword.length &&
      autoGeneratedPassword.length <= maxLength &&
      lowerCaseRegex.test(autoGeneratedPassword) &&
      numberRegex.test(autoGeneratedPassword)
  }
  return autoGeneratedPassword
}

```

## ライブラリを使用したサンプル
ライブラリだと[password-generator - npm](https://www.npmjs.com/package/password-generator)などがありました。
このライブラリを使うと以下のようにかけるようです。

```javascript
var generatePassword = require("password-generator");
 
var maxLength = 18;
var minLength = 12;
var uppercaseMinCount = 3;
var lowercaseMinCount = 3;
var numberMinCount = 2;
var specialMinCount = 2;
var UPPERCASE_RE = /([A-Z])/g;
var LOWERCASE_RE = /([a-z])/g;
var NUMBER_RE = /([\d])/g;
var SPECIAL_CHAR_RE = /([\?\-])/g;
var NON_REPEATING_CHAR_RE = /([\w\d\?\-])\1{2,}/g;
 
function isStrongEnough(password) {
  var uc = password.match(UPPERCASE_RE);
  var lc = password.match(LOWERCASE_RE);
  var n = password.match(NUMBER_RE);
  var sc = password.match(SPECIAL_CHAR_RE);
  var nr = password.match(NON_REPEATING_CHAR_RE);
  return password.length >= minLength &&
    !nr &&
    uc && uc.length >= uppercaseMinCount &&
    lc && lc.length >= lowercaseMinCount &&
    n && n.length >= numberMinCount &&
    sc && sc.length >= specialMinCount;
}
 
function customPassword() {
  var password = "";
  var randomLength = Math.floor(Math.random() * (maxLength - minLength)) + minLength;
  while (!isStrongEnough(password)) {
    password = generatePassword(randomLength, false, /[\w\d\?\-]/);
  }
  return password;
}

console.log(customPassword()); // => 2hP5v?1KKNx7_a-W
```

複雑なパスワードの自動生成などではライブラリは役に立つのかもしれませんが、今回想定したパスワードくらいであればライブラリ使用せずとも大丈夫そうでした。

## 個人的ニュース
半年間インターン生としてAWSとバックエンドを担当してきたのですが、先月から自分のワガママで未経験だったフロントエンド（React）を業務でやらせてもらい、知らないことだらけで楽しいインターン生活を送ってます。

そんな優しい会社で開発してきたアプリがついにリリースされたみたいです！
[不動産売買事例を10秒で取得！「プロマトComps」のβ版 (無料版)の提供開始](https://prtimes.jp/main/html/rd/p/000000001.000083512.html)
AWS ネットワークデザインパターンDeep Diveの整理

# 背景・目的
- AWS Summit Tokyo 2019の「ネットワークデザインパターン Deep Diveの内容を整理する。

# 内容
## Overview
- 歴史を追いながら説明されている。背景などを把握しやすい。

## 歴史
- 2013/12 VPCリリース
    - セキュアな空間が利用可能になった
- 2014/3 VPC Peeringリリース
    - VPC間で通信可能
    - 同一アカウント、別アカウントのVPC間で通信可能になった。
    - 1ホップまで通信可能。（2ホップはNG)
        - VPCの数が多くなると複雑になる
- 2017/11 Inter-Region Peeringリリース
    - 海外のリージョンに接続が可能になる。(リージョン間通信）
- 2017/11 Direct Connect Gatewayをリリース
    - Private VIFとVGWが1:1だったものが、DxGWをはさむことで1:Nになり、オンプレ-AWS間のPrivate VIFが1本に集約することが可能になる。
    - 同一アカウントのみ（クロスアカウントは不可）
    - 海外リージョンに抜けられる。（オンプレミスから1ホップで接続可能）
- 2018/11 Transit GWがリリース
    - Transit Gatewayは各VPC内のENIに対して通信が可能になる。
    - 折返し通信が可能になる。これによりVPC Peeringが不要になる。
    - Transit GWはリージョンサービスである。
    - Direct Connect対応ができない。
- 2019/3 Direct Connect Gatewayのマルチアカウント対応リリース
    - DxGWが別アカウントのVGWに接続可能
    - この時点でマルチアカウント、マルチリージョン含めて完全閉域NWの通信が可能
- 2019/5 Transit GatewayがDirect Connect Gateway対応された
    - Transit GatewayようにTransit VIFを作成。
    - Dxは従来どおり、DxGWに接続。DxGWからTransit GWに接続し各VPCのENIに接続する。

## ユースケース
### オンプレミス-VPC内からVPC外サービス(S3等)にアクセスしたい

|Source |Direct Connect接続方法 |経路|Target|備考|
|:--|:--|:--|:--|:--|
|オンプレミス|Private VIF|VPC内のProxyを介してVPCe(GW型)|DDB|オンプレから直接アクセスできないので、Proxyを介する。|
|オンプレミス|Private VIF|VPCe(I/F型)| DDB以外のVPCe対応サービス|Proxyは不要。直接アクセス可能|
|オンプレミス|Private VIF|独自VPCe(PrivateLink接続)| VPCe未対応サービス|対応してないものについて、共有サービスVPCとして、NLB＋EC2+NATGWの構成でPrivateLinkでEndpointとして提供可能。<BR>※NATGWを使うのはパブリックIPが必要なため。<BR>複数のVPCに提供することも共有サービスとして提供可能。|
|オンプレミス|Public VIF|VPCは通らない| VPCe未対応サービス|パブリックIPをつかってアクセス|
|オンプレミス|Public VIF|VPCは通らない| 別リージョンサービス|同上|

### オンプレミス/AWS間のシームレスなDNS設計がしたい
- 解決したい課題
    - オンプレミスからAWS上のシステムへの名前解決はどうすればよいか？
    - その逆の名前解決は？
    - 透過的な名前解決になる名前解決にしたい

#### Route53 Resolver Endpoint
- オンプレミスからVPC内リソースへLookup(In-Bound)
    - 準備
        - Route53 ResolverのIn-Boundのエンドポイント（VPC内）を設定する。
        - オンプレミスのDNS ResolverにInbound Endpointに転送するように設定する。
    - 名前解決と通信
        1. オンプレミスのClientは、オンプレミス内のDNS Resolverに対して、VPC内のEC2のIPアドレスを問い合わせる。
        1. オンプレミスのResolverは、Route53 Resolverに問い合わせる。（InBound Endpointにアクセス）
        1. Route53 ResolverはEC2のIPアドレスを知っているので名前解決して、オンプレミスのResolverに返却する
        1. オンプレミスのResolverは、ClientにIPを返す
        1. Clinetは、EC2にトラフィックを投げる。

- VPC内リソースからオンプレミスにLookup(Out-Bound)
    - 準備
        - Route53 Resolverの転送ルールにオンプレミスのDNSを設定
    - 名前解決と通信
        1. VPC内のEC2からIn-Bound Endpointを利用してRoute53 Resolverに名前解決する。
        1. ResolverはOut−Boundの転送ルールをLookup。その結果転送ルールに該当するので、OutboundEndpointに抜ける。
        1. Out-Bound EndpointからVGW　をとおりオンプレミスのDNS ResolverにLook upする。
        1. オンプレミスのDNS ResolverはIPアドレスを返す。
        1. VGW→Outbound Endpoint→ Route53 Resolver→In-Bound Endpoint→EC2へとLookupしたIPアドレスを返す。
        1. EC2→オンプレミスのリソースへアクセスする。

### オンプレミス/AWS間接続を高信頼にしたい
1. デュアルDxロケーション
    1. Equnixとアット東京の利用など
1. 同一キャリアで異経路設計
1. 異なる通信キャリア
    1. オンプレミスとDxロケーション間の高信頼化
1. 大阪ローカルリージョン
    1. 大阪のDxロケーションを併用する。
    1. DxGWは、AWSで冗長化されている。
1. 海外リージョン
    1. 上記と同じように海外リージョンを利用する。


# 考察
TBD
# 参照
[ネットワークデザインパターン Deep Dive](https://pages.awscloud.com/rs/112-TZM-766/images/B1-04.pdf)
roswellでスクリプトを実行する方法

#はじめに
##作者のレベル
まだ、Land of Lispと実践Common Lispを読み、これからCommon Lispを始めようとしているレベルです。なので、全然詳しくないです。
##なぜこの記事を書こうと思ったか
Common Lispをいざ始めてみようとして、いきなりつまづいたのがここでした。
Common Lispにはいろんな処理系があって、参考となる情報も少なく、この通りにやればCommon Lispはできるよというような情報がなかなか見つかりません。
他のメジャーな言語では、スクリプトを実行するという当たり前のようなことすら、どういうやり方が正しいのか分からないというのが、Common Lispの楽しさなのかもしれません。。
##試している環境
macOS Mojave version 10.14.6
roswell 21.10.14.111(NO-GIT-REVISION)
処理系 sbcl
#実行方法
##buildする方法
この方法を実行すると、roswellが入っていない他の環境（同一のOSに限る）でもプログラムを実行することができます。

まずはプロジェクトのスケルトンを作成します。

```common-lisp
$ ros run
* (ql:quickload :cl-project)
To load "cl-project":
  Load 1 ASDF system:
    cl-project
; Loading "cl-project"
..
(:CL-PROJECT)
* (cl-project:make-project #P"hello" :author "aaa") 
```

次に作成されたsrcディレクトリ内にあるmain.lispにコードを書きます。

変更前

```common-lisp:src/main.lisp
(defpackage hello
  (:use :cl))
(in-package :hello)

;; blah blah blah.
```

変更後

```common-lisp:src/main.lisp
(defpackage hello
  (:use :cl)
  (:export :wow))
(in-package :hello)

(defun wow ()
  (print "hello!"))
```

次にrosファイルを作成します。
スケルトンを作成したカレントディレクトリで実行します。srcディレクトリの一つ上です。

```
$ ros init hello
Successfully generated: hello.ros
```

作成された hello.ros ファイルを編集します。

変更前

```common-lisp:hello.ros
#!/bin/sh
#|-*- mode:lisp -*-|#
#|
exec ros -Q -- $0 "$@"
|#
(progn ;;init forms
  (ros:ensure-asdf)
  #+quicklisp(ql:quickload '() :silent t)
  )

(defpackage :ros.script.hello.3846270491
  (:use :cl))
(in-package :ros.script.hello.3846270491)

(defun main (&rest argv)
  (declare (ignorable argv)))
;;; vim: set ft=lisp lisp:
```

変更後

```common-lisp:hello.ros
#!/bin/sh
#|-*- mode:lisp -*-|#
#|
exec ros -Q -S . -- $0 "$@"
|#
(progn ;;init forms
  (ros:ensure-asdf)
  #+quicklisp(ql:quickload '(:hello) :silent t)
  )

(defpackage :ros.script.hello.3846270491
  (:use :cl))
(in-package :ros.script.hello.3846270491)

(defun main (&rest argv)
  (declare (ignorable argv))
  (hello:wow)
  )
;;; vim: set ft=lisp lisp:
```
:::note info
-S . と追加しておりますが、このコマンドラインオプションは、SourceRegistryの指定となります。
~/common-lispなど、ASDFがソースを探せるディレクトリにスケルトンを作成する場合は必要ありません。
まり、~/common-lisp内にある他のプロシェクトを参照する場合は、-S . を指定しないでください。
他のプロジェクトを探せなくなります。
:::

この状態で、rosファイルをそのまま実行することもできますが、このままコンパイルします。

```
$ ros build hello.ros 
WARNING: :SB-EVAL is no longer present in *FEATURES*
compressed 0 bytes into 8 at level -1
compressed 32768 bytes into 279 at level -1
compressed 27033600 bytes into 6426090 at level -1
compressed 1998848 bytes into 569613 at level -1
compressed 11730944 bytes into 3813223 at level -1
```

これで hello という実行ファイルができていますので、実行してみます。

```
$ ./hello

"hello!"
```

##roswellからスクリプトを起動する方法
これが意外と情報がなかったんですが、main関数さえ作ってしまえば、直接roswellからスクリプトを実行できました。

```common-lisp:hello.lisp
(defun main ()
  (print "hello!"))
```

これだけです。
実行してみます。

```
$ ros hello.lisp 

"hello!" 
```

すごく簡単です。


#参考URL
https://kitemw.hateblo.jp/entry/2018/05/15/113058
https://kitemw.hateblo.jp/entry/2018/05/16/130856
https://kitemw.hateblo.jp/entry/2018/05/17/132841
https://blog.3qe.us/entry/2017/12/12/163000
[Python]データフレームに誕生日を利用して年齢を追加する



意外とてこずったので備忘録として残します。

**まずは適当にデータフレームを作成**
元のデータがなぜか日付が表記揺れしてたのでそのまま再現しています。

```
import pandas as pd

dict1=dict(entry=["20211120","20211020","20201120"], birthday=["1998/10/24","1966/8/8","1957/6/2"])
list1=pd.DataFrame(data=dict1)
list1
```

**年齢を算出**

```
list1['entry']=pd.to_datetime(list1['entry'])
list1['birthday']=pd.to_datetime(list1['birthday'])

list1["age"]=(pd.to_datetime(list1['entry'])-pd.to_datetime(list1['birthday'])).astype('timedelta64[Y]')
list1
```

`astype('timedelta64[Y]')`　こいつがミソです。

日付から「年」「月」「曜日」「曜日」を抽出して列に追加

```
list1['year']=list1['entry'].dt.year
list1['month']=list1['entry'].dt.month
list1['day']=list1['entry'].dt.day
list1['weekday']=list1['entry'].dt.weekday
```

```
#逆に「年」「月」「日」を日付に戻す
list1["date"] = pd.to_datetime(list1[["year", "month", "day"]])
```

#日付データに誤表記が含まれていた場合#

例えば1000/11/20が含まれていると

```
OutOfBoundsDatetime: Out of bounds nanosecond timestamp: 1000-12-04 00:00:00
```

とエラーが出る。
その場合はerrors = 'coerce'とすることでおかしな日付はNaTとなる

```
list1['entry']=pd.to_datetime(list1['entry'], errors = 'coerce')
```
おかしい日付を見つけて、該当の日付を修正するか削除する

```
list1[list1['entry'].isna()]
```

#別の方法で年齢を算出
```
list1['entry']=pd.to_datetime(list1['entry'])
list1['birthday']=pd.to_datetime(list1['birthday'])

age=[]

for i,u in zip(list1['entry'],list1['birthday']):
  ages=(int(i.strftime("%Y%m%d")) - int(u.strftime("%Y%m%d"))) // 10000
  age.append(ages)

list1['age']=age
```