OmniAICreator/Qiita-1.07M huggingface dataset:
PlantUMLの導入

# 環境情報

* Ubuntu 16.04.3
* Docker CE 19.03.12
* Docker Compose 1.26.2
* PlantUML Server v1.2021.7 

# 前提条件

* 以下ソフトウェアがインストールされていること
    * Docker CE
    * Docker Compose

# 作業ログ

`docker-compose.yml`の作成

以下を少し編集して使用する。
https://github.com/plantuml/plantuml-server/blob/v1.2021.7/docker-compose.yml

```yaml
version: '3.3'

services:
  plantuml-server:
    image: plantuml/plantuml-server:jetty-v1.2021.7
    container_name: plantuml-server
    ports:
      - 18080:8080
```

```
$ wget https://raw.githubusercontent.com/plantuml/plantuml-server/v1.2021.7/docker-compose.yml

... snip ...

2021-08-06 06:54:54 (29.5 MB/s) - ‘docker-compose.yml’ saved [253/253]

$ vim docker-compose.yml 
$ docker-compose up -d
Pulling plantuml-server (plantuml/plantuml-server:jetty-v1.2021.7)...
jetty-v1.2021.7: Pulling from plantuml/plantuml-server

... snip ...

Creating plantuml-server ... done
$ docker-compose ps
     Name                    Command               State            Ports         
----------------------------------------------------------------------------------
plantuml-server   /docker-entrypoint.sh java ...   Up      0.0.0.0:18080->8080/tcp
```

ブラウザから`http://<ホストのIPアドレス>:18080/`にアクセス

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350260/35b3205b-87ed-85f4-ca5b-2a96058f24ac.png)

PlantUMLのUIにアクセスできた！
【ParticleSystem】RateOverTimeの罠

ParticleSystemを使って間隔の長いエフェクトを作ろうとしたらハマったので残しておきます。

波紋のようなエフェクトを0.5秒ごとに発生させたかったので、 `[Emmision]-[Rate over Time]` に2を設定しました。
すると、ParticleSystemのGameObjectを活性にした約0.5秒後からエフェクトが発生しました。

どうやら0秒の時点ではパーティクルは発生しないらしい…？？

RateOverTimeの説明は[こちら](https://docs.unity3d.com/ja/current/Manual/PartSysEmissionModule.html)。

> **Rate over Time** : ユニットタイム毎に放出されるパーティクルの数

一応英語版も見てみる。（英語版にしか情報ないこと結構ある）

> **Rate over Time** : The number of particles emitted per unit of time.

どちらも条件を満たす中で一体どのタイミングでパーティクルが放出されるのかは書いてない。

どこかに情報はないかと探していたらForum内に[こんな公式コメント](https://forum.unity.com/threads/particle-systems-intentional-delay-of-0-02.1072895/#post-6923570)がありました。

> Assuming you are using Rate over Time emission? In which case, particles are spawned at the end of the emission interval.
> Eg, rate over time of 10, will emit a particle at 0.1, 0.2 etc.
> So there will never be an emission exactly at time 0 with this mode.
> You can get an emission event exactly at time 0 with a burst.

Forumでコメントするだけじゃなくてマニュアルにも書いてー！

# まとめ
- RateOverTimeの割合を満たす中で一番遅いタイミングでパーティクルは放出される。
- つまりParticleSystemを開始した瞬間にはパーティクルは放出されない。
- ParticleSystemを開始した瞬間に出したい場合はBurstsのTime=0に設定すれば実現可能。
[Docker_02]ハンズオン

##環境
AWS
Docker
Python
django

##EC2構築
1. AWSにログイン
1. `EC2 ＞ インスタンスを起動`をクリックする。
1. 以下を選択する。
    * OS:`Amazon Linux 2 AMI (HVM), SSD Volume Type`
    * インスタンスタイプ:`t2.micro`
    * ネットワーク:`デフォルトVPC`<br>
      デフォルトVPCを使うのはベターではないが、とりあえずインターネットに繋がっていれば良いので使用する。
    * 自動割り当てパブリック IP ：`有効`
    * ストレージ:`8GiB`
    * キー:`Name`,値:`Docker-demo`
    * セキュリティグループ名：`DockerDemo-EC2-SG`,説明：`DockerDemo-EC2-SG`

|タイプ|プロトコル|ポート範囲|ソース|説明|
|---|---|---|---|---
|SSH|TCP|22|カスタム 0.0.0.0/0|-|
【設定概要】
![スクリーンショット 2021-08-06 17.53.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/758644/60e556cd-2089-d4f0-f7cc-87848f8e7bb3.png)

##VSCodeのRemote-sshでEC2へ接続する...ための事前設定
VSCodeだとフォルダツリーとかグラフィカルで直感的に操作できる。

1. VSCodeの拡張機能でRemote-SSHをインストール
1. (Macの場合)ターミナルで以下のディレクトリに設定内容を記載する。<br>
ディレクトリ：/Users/(ユーザのホームディレクトリ)/.ssh/config
<br>
設定内容：

```
Host Test-EC2
  HostName (EC2インスタンスのパブリックIP)
  IdentityFile (秘密鍵の場所)
  User ec2-user
```
以下、設定ログ。

```terminal
$ cd
$ ls -la
~省略~
drwx------   3 xxxxxx  staff     96  1 19  2018 .ssh
$ cd .ssh
$ touch config
$ vi　←ここで設定内容を記載
$ ls -l
-rw-r--r--  1 masudayoshiki  staff   117  8  6 18:17 config
-rw-r--r--  1 masudayoshiki  staff  2764  5 28 15:59 known_hosts
$ cat config
Host Test-EC2
  HostName (EC2インスタンスのパブリックIP)
  IdentityFile (秘密鍵の場所)
  User ec2-user
```

##VSCodeのRemote-sshでEC2へ接続する
1. 左下の緑色の`SSH:...`をクリックする。<br>これは事前設定で作成したconfigのHost
1. 検索窓が出たら、`Connect to Host ＞　Test-EC2`をクリックする。
1. これでSSH接続は完了するので、あとはフォルダを開いたり、ターミナルを開いてコマンドを実行する。
![スクリーンショット 2021-08-06 18.47.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/758644/2f064826-e9e2-a7b6-4c9b-71632d170ec3.png)

##いろいろとインストールする前の準備
```
sudo yum update -y
```

##Dockerのインストール&セットアップ
```
sudo amazon-linux-extras install  -y docker
sudo usermod -a -G docker ec2-user
sudo systemctl start docker.service
sudo systemctl status docker.service
sudo systemctl enable docker.service
```

##Docker-composeのインストール&セットアップ
```
sudo curl -L https://github.com/docker/compose/releases/download/1.21.0/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
```

##アプリに必要なツールのインストール
Pythonやそのパッケージをインストールする。

```
sudo yum install -y python37 python3-devel gcc jq tree git
git clone https://github.com/AWSCLOUDTECH/tutorial.git
cd tutorial/todobackend
cd src
pip3 install -r requirements.txt --user
python3 manage.py migrate
python3 manage.py runserver 0.0.0.0:8000
```

##djangoやPythonのセットアップ
##アプリのダウンロード＆起動
configure: error: cannot run /bin/bash tool/config.sub, 今日のdocker error(16)

実は、エラー出たの今日じゃないんです。
約１週間前です。

技術書「Rubyソースコード完全解説」 と 「docker で ruby」構築
https://qiita.com/kaizen_nagoya/items/a00fec16fb43e6e9071d

```ubuntu:bash
checking for ruby... false
configure: error: cannot run /bin/bash tool/config.sub
```

configure: error: cannot run /bin/bash tool/config.sub on ubuntu:trusty #22
https://github.com/rubyomr-preview/rubyomr-preview/issues/22

wuzzzzaah/rubyインストール
https://gist.github.com/wuzzzzaah/0a7835a1182c3c23124a

```ubuntu:bash
# apt update; apt -y upgrade;
# apt -y install build-essential git curl zlib1g-dev libssl-dev libreadline-dev libyaml-dev libxml2-dev libxslt-dev sqlite3 libsqlite3-dev nodejs 
# git clone git://github.com/sstephenson/rbenv.git .rbenv

# echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
# echo 'eval "$(rbenv init -)"' >> ~/.bashrc
# exec $SHELL
bash: rbenv: command not found
# mkdir -p ~/.rbenv/plugins
```
# Reference
今日のDocker error:docker: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?.
https://qiita.com/kaizen_nagoya/items/bea99f4c1c0cb746029d

Error一覧 error(0)
https://qiita.com/kaizen_nagoya/items/48b6cbc8d68eae2c42b8

＜この記事は個人の過去の経験に基づく個人の感想です。現在所属する組織、業務とは関係がありません。＞
This article is an individual impression based on the individual's experience. It has nothing to do with the organization or business to which I currently belong.
### 文書履歴(document history)
ver. 0.01 初稿 　20240504
### 最後までおよみいただきありがとうございました。
いいね　💚、フォローをお願いします。
#### Thank you very much for reading to the last sentence.
Please press the like icon 💚　and follow me for your happy life.
Pyinstallerでexe化した時のPydriveのエラー対処

PyinstallerでWindowsで実行可能なexe化を行った際にPydriveがインポートされず、
GoogleDriveへのファイルのアップロードが失敗してしまったので、そのエラーの対処方法の覚書です。

#環境
・OS: Windows 10 64bit
・Python 3.8.10
・PyInstaller 4.3

#エラー箇所
エラーの原因となっていたのは、下記のライブラリをインポートした部分です。
やりたかったこととしては、ローカルファイルを共有ドライブにアップロードするでしたが、Uploadの際に、Anaconda上では問題なく動作していましたが、Pyinstallerでexe化するとアップロードの際にエラーが発生して、GoogleAPIErrorが発生してしまった。

```py:GoogleDriveup.py
from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive
```
ローカルファイルを共有ドライブにアップロードする方法は以下の記事を参照しました。
[pydrive を使って 共有ドライブにアップロードする方法](https://qiita.com/zomaphone/items/d8c2beddb8114915d7c1)

#エラー内容
コンソール上で確認できたエラーはgoogleapiclient.errors.UnknownApiNameOrVersionというものでした。もう一つのモジュールでGoogleDrive上のspreadsheetの書き込みが成功していたので、PyDriveの問題ということが分かりました。

#対処方法
現状のPyinstallerはexe化実行時に、PyDriveを読み込み出来てずそのせいでエラーが起きていました。
対処方法としては、Pyinstaller実行後に出力されるspecファイルの中身を書き換える必要があります。

1.ファイルの先頭に__from PyInstaller.utils.hooks import collect_data_files__を追加する。
2.data=[],の部分を__datas=collect_data_files("googleapiclient"),__に書き換える。

```spec:GoogleDriveup.spec
# -*- mode: python ; coding: utf-8 -*-
from PyInstaller.utils.hooks import collect_data_files

block_cipher = None


a = Analysis(['EXE化したいファイル名'],
             pathex=['ファイルへのパス'],
             binaries=[],
             datas=collect_data_files("googleapiclient"),
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher,
             noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          [],
          exclude_binaries=True,
          name='Enabler_registor',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          console=False )
coll = COLLECT(exe,
               a.binaries,
               a.zipfiles,
               a.datas,
               strip=False,
               upx=True,
               upx_exclude=[],
               name='EXE化したいファイル')
```
これで問題なくファイルのアップロードが出来ました。
Linuxでswapを無効化・有効化する

スワップ領域が必要か不要かはたまに議論されているのを見ます。
が、要不要はさておき、スワップ領域を操作したい場合もあります。
その時の設定メモ。環境はUbuntu 20.04 LTSで行っています。

# スワップ領域を確認する。

```bash
$ sudo swapon --show

NAME      TYPE SIZE USED PRIO
/swap.img file   8G   0B   -2
```

スワップ領域 `/swap.img` が8GBあることが分かる。表示されない場合、スワップに使える領域がないことを意味します。

# スワップ領域を削除する

```bash
$ sudo swapoff -a
```

これだけ。スワップを使わないようになります。
ただしスワップ領域自体は残るので、rmコマンドで削除してしまいましょう。

```bash
$ sudo swapon -s
（何も表示されない）

$ ls /
bin    dev   lib    libx32      mnt   root  snap      sys  var
boot   etc   lib32  lost+found  opt   run   srv       tmp
cdrom  home  lib64  media       proc  sbin  swap.img  usr

$ sudo rm /swap.img
```

# スワップ領域を作成する

swap.imgという名前で2GBのスワップを作ってみる。

```bash
$ sudo fallocate -l 2G /swap.img
$ ls -lh /swap.img 
-rw-r--r-- 1 root root 2.0G  8月  6 16:14 /swap.img
```

きちんと2GBの領域が確保された。

```bash
$ sudo chmod 600 /swap.img 
$ sudo mkswap /swap.img 
スワップ空間バージョン 1 を設定します。サイズ = 2 GiB (2147479552 バイト)
ラベルはありません, UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
$ sudo swapon /swap.img
```

これで完了。確認すると2GBの領域が取られているのが分かります。

```bash
$ sudo swapon --show

NAME      TYPE SIZE USED PRIO
/swap.img file   2G   0B   -2
```

この削除->作成の流れは、当然、スワップ領域を変更したい際も有効です。

# 参考

-[How To Add Swap Space on Ubuntu 20.04](https://www.digitalocean.com/community/tutorials/how-to-add-swap-space-on-ubuntu-20-04)
CentOS8 を AlmaLinux に移行

## まえがき
CentOS8 から AlmaLinux へ移行が簡単にできると聞いたので
試してみた所、本当に簡単でした。スクリプトを実行するだけ！

## 準備
・一応バックアップ
・パッケージを色々入れるのでドライブに空きを作っておく
・CentOS8 も最新にしておく (古いバージョンでは未検証)

```bash
dnf update
```

・再起動

```bash
reboot
```

## AlmaLinux 移行用スクリプトを適用
https://github.com/AlmaLinux/almalinux-deploy

・移行スクリプトをダウンロード

```bash
curl -O https://raw.githubusercontent.com/AlmaLinux/almalinux-deploy/master/almalinux-deploy.sh
```
・実行

```bash
bash almalinux-deploy.sh
...
Migration to AlmaLinux is completed
```
・確認

```bash
# check release file
$ cat /etc/redhat-release 
AlmaLinux release 8.4 (Electric Cheetah)

# check that the system boots AlmaLinux kernel by default
$ sudo grubby --info DEFAULT | grep AlmaLinux
title="AlmaLinux (4.18.0-305.10.2.el8_4.x86_64) 8.4 (Electric Cheetah)"
```
・再起動

```bash
reboot
```

## 完了
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108113/f45c1bd9-17d3-0b99-a369-d742e1e470c7.png)

以上、お疲れさまでした！
ScheduledFutureのgetの使い道


定期実行し続ける```ScheduledFuture```の```Future#get```てどのように使うのだろうか？　という疑問が生じた。なので試してみた。

```java
    ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
    
    AtomicInteger c = new AtomicInteger(0);
    ScheduledFuture<?> future = scheduler.scheduleAtFixedRate(() -> {
      System.out.println(c);
      if (c.get() > 3) {
        throw new RuntimeException();
      }
      c.incrementAndGet();
    }, 0, 500, TimeUnit.MILLISECONDS);
    
    try {
      future.get();
    } catch (ExecutionException ex) {
      System.out.println("finished.");
    }
```

これを実行すると下記のような実行結果になる。

```
0
1
2
3
4
finished.
```

定期実行サービスのスレッドで例外をスローすると、```future#get```は```ExecutionException```スローする。なのでこれをcatchしてメッセージを出力している。 

というわけで、定期実行サービスをwatchして失敗したら何らかの後処理を行いたい、という場合に使える。とはいっても、定期実行でそういうユースケースはあまり思いつかない。```Future#cancel``` で停止したいことはあるだろうけど。



参考 : https://stackoverflow.com/questions/25049021/what-is-the-purpose-of-scheduledfuture-get-method-if-is-retrieved-from-the-sch
JUCEでのprintfデバッグ、およびログへの出力

# XCodeなどのConsoleへの出力

DBG("TEST")
などで、出力できる。

DBGはsystemに定義されているマクロ
https://docs.juce.com/master/group__juce__core-system.html

# ログの出力

juce::Logger
で出力できる。

ここで使われているので参考に
https://docs.juce.com/master/tutorial_simple_synth_noise.html

## How to use the FileLogger

https://forum.juce.com/t/how-to-use-the-filelogger/8539

FileLoggerの使い方

## ログ出力サンプル

ログ出力するプロジェクトをgithubにあげました。
https://github.com/uchidama/SimpleSynthNoiseTutorialMod/

```C++
#pragma once

//==============================================================================
class MainContentComponent   : public juce::AudioAppComponent
{
public:
    MainContentComponent() : m_log_file("~/log_test.txt"), m_logger(m_log_file,"Welcome to the log",0)
    {
        juce::Logger::setCurrentLogger(&m_logger);

        setSize (800, 600);
        setAudioChannels (0, 2); // no inputs, two outputs
        
    }

    ~MainContentComponent() override
    {
        shutdownAudio();
    }

    void prepareToPlay (int samplesPerBlockExpected, double sampleRate) override
    {
        juce::String message;
        message << "Preparing to play audio...\n";
        message << " samplesPerBlockExpected = " << samplesPerBlockExpected << "\n";
        message << " sampleRate = " << sampleRate;
        juce::Logger::getCurrentLogger()->writeToLog (message);
    }

    void releaseResources() override
    {
        juce::Logger::getCurrentLogger()->writeToLog ("Releasing audio resources");
    }

    void getNextAudioBlock (const juce::AudioSourceChannelInfo& bufferToFill) override
    {
        for (auto channel = 0; channel < bufferToFill.buffer->getNumChannels(); ++channel)
        {
            // Get a pointer to the start sample in the buffer for this audio output channel
            auto* buffer = bufferToFill.buffer->getWritePointer (channel, bufferToFill.startSample);

            // Fill the required number of samples with noise between -0.125 and +0.125
            for (auto sample = 0; sample < bufferToFill.numSamples; ++sample)
                buffer[sample] = random.nextFloat() * 0.25f - 0.125f;
        }
    }

private:
    juce::Random random;
    juce::File m_log_file;
    juce::FileLogger m_logger;

    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainContentComponent)
};
```

https://github.com/uchidama/SimpleSynthNoiseTutorialMod/blob/main/Source/SimpleSynthNoiseTutorial_01.h

使ってるコア部分。  
こんな感じ。

# ログを見る

Mac OS Xで見るなら、ターミナルから

```
tail -n 100 -f ~/log_test.txt
```

で見ると便利。
VSCodeで多段SSH接続

# はじめに
会社や大学などでサーバにSSH接続する際に、社内ネットワークサーバをいくつか経由しなければならないことがたまにあります。毎度毎度、手動で接続することは面倒なので、一度に接続できるように設定をし、さらにVSCode環境で作業できるように整えていきたいと思います。
※SSH接続の初期設定やVSCodeのインストールは既にできていると仮定して、話を進めていきます。
※多段SSH接続の設定はMACやLinux環境（コマンドなど）を想定していますが、Windows環境でもコマンドなどを適宜変更することにより設定可能です。
※VSCodeの設定については共通です。

# 多段SSH接続
多段SSH接続では毎回のログイン時に結構な手間が生じ、またSFTPを使用してファイルを送受信する際に少々手間が掛かってしまいます。
sshディレクトリ下でconfigを設定することにより、その手間を解消する方法を紹介します。
※MACやLinux環境を想定しているため、Windows環境では適宜GUIや適切なコマンドを用いてください。
※接続先の環境に応じて適宜変更してください。

1. まず.sshディレクトリに移動します。コマンド「cd .ssh」
2. 移動した.sshディレクトリ下に「config」ファイルを作成します。コマンド「touch config」
3. vimなどでconfigを以下のように書き換えます。コマンド「vim config」

※（）は適宜消してください
※以下は「hoge@hogehoge.hoge.jp」→「foo@foofoo.foo.jp」→「bar@barbar.bar.jp」としてSSH接続すると仮定

```ssh:config
Host HogeServer（←任意のホスト名1）
        HostName hogehoge.hoge.jp（←接続先アドレス）
        port 22（←既定のポート番号を指定してください）
        User hoge（←ユーザ名を指定）
        IdentityFile ~/.ssh/id_hoge_com（←共通鍵のPATHを指定）
Host FooServer（←任意のホスト名2）
        HostName foofoo.foo.jp（←接続先アドレス）
        port 22（←既定のポート番号を指定してください）
        User foo（←ユーザ名を指定）
        ProxyCommand  ssh -W %h:%p HogeServer
Host BarServer（←任意のホスト名3）
        HostName barbar.bar.jp（←接続先アドレス）
        port 22（←既定のポート番号を指定してください）
        User bar（←ユーザ名を指定）
        ProxyCommand  ssh -W %h:%p FooServer
```

※Hostの名前（上記ならHogeServerなど）を変更したら、ProxyCommand内のホスト名も変更してください。

4.保存して終了。(:wq)
5.ディレクトリを一つ戻る。コマンド「cd ..」
6.コマンド「ssh (任意のホスト名３)」を実行する。（それぞれ適当なパスワードを入力する）

これで、二つのサーバをジャンプして目的サーバに接続することができると思います。以降はコマンド「ssh (任意のホスト名３)」を実行するだけで（パスワードは毎回必要ですが）サーバに接続することができます。
嬉しいことに、SFTPも簡単に行うことができます。コマンド「sftp (任意のホスト名３)」を実行するだけです。後は「put」や「get」でファイルを送受信することが可能です。
ただし、今回はMacで環境構築を行いましたので、Windowsでは若干異なる部分も生じる可能性があります。

# VSCodeでSSH接続
ここでは、VSCodeでSSH接続する方法を簡単に説明します。
まず、VSCodeでMarketを開きます。「View」→「Extensions」または「左の四角マークが４つあるところ」をクリックするとマーケットを開くことができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300353/1b143894-6854-8085-878f-eccd251c70c1.png)
ここの検索フォームで「Remote-SSH」と「Remote Development」を検索して、インストールします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300353/767447bb-483a-8887-b373-0c83d2dbc453.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300353/b00b0dd1-9a24-121c-7fb9-f2210abf6d05.png)
インストール後に、左下に緑色の「><」マークが出ていればOK！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300353/93914927-8755-6965-20d3-553c755f9aa2.png)

### 接続してみよう！
左下の緑色のボタンを押してSSH接続します。緑色のボタンを押してみると以下のようなポップが出ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300353/83e59f0d-0b23-1a09-0718-c527ba4486ce.png)
ここで、「Connect to Host」を選択すると、先ほど設定した任意のホスト名が表示されると思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300353/89b76632-e4de-fcbe-0646-37313af49d60.png)
最終的に接続したいサーバ（BarServer）を選択すると、それぞれのパスワード入力が求められるので、適宜入力してください。すると、まるでローカルのように快適に作業することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300353/16c7e257-303f-03fe-e2d4-c844962e1612.png)

### リモートでコードもターミナルも出力結果も同時に見ることができる！なんて素晴らしいのでしょうか！

# 最後に
上記設定はMACやLinux環境を想定していましたが、Windows環境でも設定可能です。（VSCodeの画像はWindows環境でスクショしているぐらいなので。）
どこかのタイミングでWindows環境の設定も掲載できればと思います。
【sapui5】SelectとInputで同一の色付けができない問題を解消

##はじめに
sap.m.Select（またはsap.m.ComboBox）とsap.m.Inputに
同じカラーで色付けを行おうとした際に、
「色が異なる」や「sap.m.Inputの方に色付けできない」等の事象が発生したため、
解決策をここに記載する。

####間違ったソースコード

```ruby:view.xml
<VBox>
	<Label id="inputLabel" text="{i18n>sap.m.Input}" wrapping="false"/>
</VBox>
<VBox>
	<Input id="input" width="15rem" class="changed"/>
</VBox>
<VBox>
	<Label id="selectLabel" text="{i18n>sap.m.Select}" wrapping="false"/>
</VBox>
<VBox>
	<Select id="select" width="15rem" class="changed"/>
</VBox>
```

```ruby:style.css
.changed {
    background-color: #fff56d !important;
}
```

上記のコードで実装すると、
下記の画像のようにsap.m.Inputの方に色付けできなくなる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1855659/3172042b-756c-4be6-14fb-50ee9ce5df0c.png)


####原因
sap.m.Selectの場合、
下記の画像の青枠< input >の上にある赤枠< div id="__select0"... >に
class="changed"を指定すると色付けができるが、

![select.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1855659/0fc91be0-b5dd-f450-2ba2-29743e9da4d7.png)

sap.m.Inputの場合、
下記の画像の青枠< input >の上にある赤枠< div id="__input0-content"... >の上の
< div id="＿input0"... >にclass="changed"を指定しているため、
色付けの処理が正常に行われていないのである。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1855659/b575ba61-3294-95a7-aa1a-47babaa2b99d.png)

↓ということは...

青枠< input >の上にある赤枠< div id="__input0-content"... >に
class="changed"を指定できるようにstyle.cssに記載すればいい！


####解決策

```ruby:style.css
.changed {
    background-color: #fff56d !important;
}
.changed > div{
    background-color: #fff56d !important;
}
```

上記のコードで実装すると、同じカラーで色付け可能となった。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1855659/cbbd58b7-182a-6dbc-d78d-8578aa9c4189.png)
リクエストヘッダーに付与されたBearer Tokenを解析して情報を取得する


備忘録として後世の自分に残す。

## 概要

APIにリクエストされた情報(Bearer Token)を取得 → Tokenの情報を解析してほしい情報を持ってこれるようにする

## まずはリクエストヘッダーのToken情報を取得する

リクエスト情報の取得はHttpContextAccesorを使う。  
DIして👇みたいに使ってみる。  
Headers[""]の中身にKeyを指定すれば他のヘッダー情報もひっこぬける。

```C#
private readonly IHttpContextAccessor _httpContextAccessor;

public hogeController(IHttpContextAccessor httpContextAccessor)
{
  // DIする
  _httpContextAccessor = httpContextAccessor;
}

[HttpGet]
public Task<ActionResult> GetHoge()
{
  var request = _httpContextAccessor.HttpContext.Request;
  string token = req.Headers["Authorization"] // Authorizationヘッダーにセットされてる値を取得する
}
```

## 取得したTokenを解析


取得したtokenにBearerついてる場合はReplaceメソッドなりで置き換えておきましょう。

```C#
token = token.Replace("Bearer", "").Trim();
```

Token解析には
JwtSecurityTokenHandler()使います。
System.IdentityModel.Tokens.Jwtをパッケージに追加しておく。

```C#
var handler = new JwtSecurityTokenHandler();
var ArrayToken = token.Split("&");
var result = "";
var target = "name";
```

target変数には取得したい情報を指定します。  
何を引っこ抜きたいかは[JWT](https://jwt.io/)などのサイトで  
事前に解析したいTokenをセットしてペイロードなり確認してください。  
Tokenを「&」でSplitしてるのは解析で使うのは最初のほうの情報になってくるのでSplitしてる。  
早速解析してみる。👇

``` C#
if (handler.CanReadToken(ArrayToken[0]))
 {
  var readToken = handler.ReadToken(ArrayToken[0]) as JwtSecurityToken;
  var res = readToken.Claims.Where(w => w.Type == target);
  if (res.Any())
  {
    var prop = res.First();
    result = prop != null ? prop.Value : "";
  }
}
```

ReadToken()で読み取る。  
Claimsに情報が入ってるのでそこから欲しい情報を引っこ抜く。

## 終わり

自分はよくリクエストの情報を取得するのに毎回調べてる感じあるので今回残してみた。
大規模開発事業でのおススメ「コミュニケーションツール」10選！

こんにちは。DMM.com PF事業本部のhayashiです。
今回は、140名が在籍する大規模事業でよく使っているコミュニケーションツールを用途も交えて紹介します。

##チャットやオンライン会議ツール
* 1.slack
* 2.discord
* 3.zoom

上記を利用しています。
より高機能なものでは有償版として会社導入するものもありますが、
だいたいは無償で使えるものも多いので、用途に応じて使い分けています。

とくに最近主流のオンライン会議では以下のようなすみわけをしています。

すでに会議が決まっているものや対外との面談では、zoomやmeetsを使うことが多いです。
discordは、プロジェクトの開発過程で雑談シーンで使ったり、ちょっと今相談したいのですがなどライトなシーンでよく使われています。
私たちPF事業本部でも部屋を用意して、各チャンネルごとに入室し、「お、この人今部屋にいる！」となったら
その部屋に集合して課題解決やコミュニケーションの促進に役立てています。


Discord参考
![Frame 15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1706758/b160af82-4d4e-dc28-d7b6-cfec093f0806.png)


##タスク管理
* 4.zenhub
* 5.Googleスプレッドシート
* 6.Confluence


これはどの企業でも代表格かと思います。
私たちは、confluenceにてドキュメント類を管理して、開発途中のタスク管理はjiraやzenhubなどを使うことが多いです。
工数や調達人員管理など、計算が必要なもの　や　簡易的にロードマップ・WBSを引いてみるときにはスプレッドシートを使うシーンが多いです。
特にconfluenceは主流としており、いろんなアドオンや互換性がある機能が多いので重宝しております！

余談ですが…
筆者は特にプロジェクト管理でもデザイン性を高めたいと思ってしまうので、CSSを適用したりオリジナルバナーなどを作ったりなど、confluenceの見た目もこだわっております（笑）

##クリエイティブ作成
* 7.adobeXD
* 8.figma

最近ではこのツールが勢力を占めています。
とくにfigmaは無償でも充実した機能がある点も高評価で、デザイナーではないがクリエイティブ案を作成してみるときなどでもライトに利用している方も多いようです。
slackとも連動しているので、コメントなどの通知がされる点も便利かなと思います。


##オンラインディスカッション用
* 9.miro
* 10.Googleスライド

KPTやイメージが必要なオンラインディスカッションが必要なとき、最近はmiroもよく使われております。
付箋をぺたぺたとはったり、簡単に記号で描画できるので操作性がわかりやすいという点が評価が高いようです。
ブラウザでの同期性も非常に高くノンストレスでディスカッションができるようになったなと感じます。


##まとめ
ブラウザ1つでライトにコミュニケーションができるツールは本当に便利だなと実感させられます。
これからもDMM.PF事業本部ではいろんなツールを試し、よりよいコミュニケーションスタイルを模索していきます！
アラビア数字から漢数字変換

# アラビア数字から漢数字に変換する処理　備忘録

無量大数って有限だったんだ、、知らんかった

# 文字列処理でガンバる場合

```python
d1 = {u'1': u'一', u'2': u'二', u'3': u'三', u'4': u'四', u'5': u'五', u'6': u'六', u'7': u'七', u'8': u'八', u'9': u'九'}
d3 = {1: u'十', 2: u'百', 3: u'千'}
d4 = {4: u'万', 8: u'億', 12: u'兆', 16: u'京', 20: u'垓', 24: u'予', 28: u'穣', 32: u'溝', 36: u'潤',
      40: u'正', 44: u'載', 48: u'極', 52: u'恒河沙', 56: u'阿僧祇', 60: u'那由他', 64: u'不可思議', 68: u'無量大数'}

def int2kanji(integer):
    sio = str(integer)
    i = len(sio) - 1
    ret = u""
    for s in sio:
        mod4 = i % 4
        if (mod4 == 0):
            ret += d1.get(s, u"")
            ret += d4.get(i, u"")
        elif (s != u'0'):
            if s != u'1':
                ret += d1.get(s, s)
            ret += d3.get(mod4, u"")

        i -= 1
    return ret


int2kanji(110304567) # -> 一億千三十万四千五百六十七

In [2]: %timeit int2kanji(110304567)
2.69 µs ± 96.2 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
```

# 数値計算で頑張る場合

```python
d1 = [u'', u'一', u'二', u'三', u'四', u'五', u'六', u'七', u'八', u'九']
D3_U = [u'十', u'百', u'千']
D4_U = [u'', u'万', u'億', u'兆', u'京', u'垓', u'予', u'穣', u'溝', u'潤', u'正', u'載', u'極', u'恒河沙', u'阿僧祇', u'那由他', u'不可思議', u'無量大数']

def int2kanji(i):
    if (i == 0):
        return "零"
    mod = i % 10
    ret = ""

    for d4 in D4_U:
        ret = d4 + ret

        if (mod):
            ret = d1[mod] + ret

        i //= 10
        if (i == 0):
            break
        mod = i % 10

        for d3 in D3_U:
            if (mod):
                ret = d3 + ret
                if (mod != 1):
                    ret = d1[mod] + ret
            i //= 10
            if (i == 0):
                break
            mod = i % 10

        if (i == 0):
            break
        

    return ret

int2kanji(110304567) # -> 一億千三十万四千五百六十七

In [4]: %timeit int2kanji(110304567)
1.94 µs ± 5.78 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops 
each)

```

やっぱり数値計算で処理した方が速かった。
Python内でLogicaのプログラムをSQLに変換する

# Logicaとは

[Logica](https://logica.dev/)とはGoogleが発表した論理プログラミング言語で、BigQueryやPostgreSQLのクエリにコンパイルして実行できます。

日本語ではこれらの記事で紹介されており、だいたいの概要は分かると思います。

* [logica で readable, testable な SQL の夢を見る](https://labs.septeni.co.jp/entry/2021/05/26/110000)
* [論理プログラミング言語Logicaでデータサイエンス100本ノック](https://zenn.dev/koji_mats/scraps/81edc33b8b9e5d)

引用すると次のような特徴があり、私の所属するチームではBigQueryでそれなりに複雑な処理が実装されているので、特に「モジュール機能があること」「テストが実施できる?(ドキュメントにも明確に記載がないのでまだ詳細不明)」ことに期待しています。また、GitHubのDiscussions（[PageRank Alogrithm](https://github.com/EvgSkv/logica/discussions/106)）を見る限り再帰も（回数は限定されてそうですが）使えるらしく、もしかするとBigQuery側で柔軟にアルゴリズムを実装していくことも可能かもしれません。

> 最初に、プログラミング言語Logicaの特徴を纏めておく。
>
> * 論理型プログラミング言語: このカテゴリではPrologが有名
> * SQLにコンパイルされる: 現状BigQueryとPostgreSQLに対応
> * モジュール機構がある: SQLと比較した強み
> * コンパイラはPythonで書かれている: Jupyter NotebookやGoogle Colabですぐ始められる
> * Colabで[チュートリアル](https://colab.research.google.com/github/EvgSkv/logica/blob/main/tutorial/Logica_tutorial.ipynb)が用意されているので、まずこちらからやると良いと思う。

ただ、チュートリアルやドキュメントを見る限り`logica`のコマンドで実行するか、Collabで実行するかという方法しか紹介されていません。そのため、私は「複雑なクエリをPythonのバッチ処理で実行したい」と考え、Python自体でlogicaをimportして実行してみました。

（※ただ、後から思いついたのですが、Python内で利用できなくても、Dockerのビルド時にlogicaをSQLに変換した結果を保存して利用すればいいだけかもしれません）



# LogicaのプログラムをSQLに変換するPythonスクリプト

チュートリアルにあるこちらのLogicaプログラムをPython内で変換します。

```prolog:mentions.l
@OrderBy(Mentions, "mentions desc");
@Limit(Mentions, 10);
Mentions(person:, mentions? += 1) distinct :-
  gdelt-bq.gdeltv2.gkg(persons:, date:),
  Substr(ToString(date), 0, 4) == "2020",
  the_persons == Split(persons, ";"),
  person in the_persons;
```

以下のようなスクリプトで実行できます。[logica.py](https://github.com/EvgSkv/logica/blob/main/logica.py)の内容を追って、不要な処理を削除したものです。

```python:main.py
from logica.parser_py import parse
from logica.compiler import universe

with open("./mentions.l") as f:
    program = f.read()

# 構文木(?)に変換する
parsed_rules = parse.ParseFile(program)["rule"]
# SQLに変換する
program = universe.LogicaProgram(parsed_rules)
sql = program.FormattedPredicateSql("Mentions") # 呼び出したい変数(Mentions)を指定する

print(sql)
```

結果、以下のSQLが出力されます。このSQL文字列をBigQueryのクライアントで利用すればokです。

```sql
SELECT
  x_3 AS person,
  SUM(1) AS mentions
FROM
  gdelt-bq.gdeltv2.gkg AS gdeltbq_gdeltv2_gkg, UNNEST(SPLIT(gdeltbq_gdeltv2_gkg.persons, ";")) as x_3
WHERE
  (SUBSTR(CAST(gdeltbq_gdeltv2_gkg.date AS STRING), 0, 4) = "2020")
GROUP BY person ORDER BY mentions desc LIMIT 10;
```


# 参考資料

* [Logica Tutorial](https://colab.research.google.com/github/EvgSkv/logica/blob/main/tutorial/Logica_tutorial.ipynb)
* [GitHubリポジトリ](https://github.com/EvgSkv/logica)
[Docker_01]概要

##Dockerとは
コンテナ仮想化を用いてアプリを開発・配置・実行するためのソフトウェア。
インフラのコード化(IaC)にも役立つ。
<br><br>



##従来の仮想化との違い
一般的な仮想サーバというと、CPUやメモリなどのハードウェアリソースを分割し、複数の独立したサーバのように機能させるもの。
コンテナも、隔離されたユーザー環境(ユーザーがアプリを実行するためのリソースがセットで提供される空間)を提供する点は同じだが、1つのOSのカーネルを共有している点が仮想マシンとは大きく異なる。

しかし、DockerエンジンにもOS(Linux系)が含まれている。ややこしいが、まるまるOSが入っているわけでなく、カーネルだけをホストOSと共有している。
Dockerと検索して出てくる説明や図では、「ゲストOSがないから早い！」的な短絡的な内容が書かれているが、実際には **仮想マシンはカーネルまで仮想化しているが、コンテナはカーネルをホストOSと共有しているから、軽量・高速を実現している** ということらしい。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/758644/dce94677-bd57-1289-8f44-b9000ac4969a.png)
画像引用：さくらのナレッジ:Dockerとは何か、何が良いのか
<br><br>

##世間の注目度
AWS,GCP,AZUREなどのパブリッククラウドやプライベートクラウドが普及し始めて、アプリの実行環境の種類が増えた。それに伴い、どのような環境でも動かせるコンテナの注目度は高い。

実際、世界の開発者のトレンドの調査として「[Stack Overflow Developer Survey 2020](https://insights.stackoverflow.com/survey/2020#technology-most-loved-dreaded-and-wanted-platforms-loved5)」では、開発者が関心を示しているプラットフォームの割合として、Linuxに次いて2番目となっている。
![スクリーンショット 2021-08-06 15.42.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/758644/6c910629-9584-ca4e-e803-f0bdc91d52f3.png)
<br><br>


##用語
####Docker Daemon
Dockerエンジンの一部で、Dockerの主要機能。
コマンドの受付場所。命令をREST APIで受け付ける。
他のDockerの機能に命令を出す。

####Docker Client
コマンドの発行場所。Docker Daemonとやりとりする。

####Docker image
このファイルをもとにコンテナを起動する。
アプリやOSがひとまとめになったもの。

####Docker レジストリ
Docker imageのファイル置き場。
例：Dockerhub(パブリック)
　　AWS ECR　(プライベート)

####Docker file
Docker imageをカスタマイズする指示内容を記述したテキストファイル。これによりOS設定やインフラ構築部分をコード化出来る。
初級：Gitを活用した共同開発の方法

##Gitとは
共同開発を可能にするターミナル上で利用するツール

###共同開発のステップ
1. コードを変更する
2. 共有する準備をする（コミットと呼ばれる作業）
3. 共有する（リモート / リモートリポジトリと呼ばれる共有ファイル置き場にて共有）

###共同開発のステップはこの4コマンドのサイクル
add→commit→push→pull→　addに戻る。※以降、繰り返し。

1. add = 自分が作成したコードを選択し
2. commit = メッセージをつけて記録し
3. push = 共有リポジトリにアップロードする
4. pull = 共有リポジトリからファイルをダウンロードする

##Gitに関するターミナルコマンド
###Gitを利用するために、ターミナルにて最初に実行する

```
git init
```

###共有するためにGitに追加する

```
git add
git add index.html
```

###選択したファイルをメッセージをつけて記録する

```
git commit -m "メッセージ"
git commit -m "index.htmlを作成しました"
```
###共有で作業するリモートリポジトリに登録する

```
git remote add リモートリポジトリ名 URL
git remote add origin https://example.com/mysite.git
```

###リモートリポジトリにファイルをアップロードする（プッシュする）

```
git push origin master
```

###リモートリポジトリのファイルをダウンロードする

```
git pull origin master
```
PlantUMLを使用してテキストでディレクトリ構成図を描く

PlantUMLでは、様々な図を記載することができますが、ディレクトリ構成図も記載することができます。

書き方はシンプルで、`+`記号を増やしていけば子ディレクトリの表現になります。また、`|`を利用することで、ディレクトリの説明も記載できます。

## 記載例
```
@startuml
title ディレクトリ構成図
skinparam TitleFontSize 0

salt

{
  {T
    + ルートディレクトリ
      ++ 子ディレクトリ1     | xxxを格納する
        +++ 子ディレクトリ1  | xxxのaaaを格納する
      ++ 子ディレクトリ2
  }
}

@enduml
```
`skinparam TitleFontSize 0`はタイトルを出力しないようにしています。表示されて問題なければ不要です。

## 出力例
上記の記載例を出力すると以下のような結果になります。
![ディレクトリ構成図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365965/3bf1a136-a8eb-0f5c-b9c8-7626056ff6bb.png)
Node.js 16.6.0からArray.at()が使えるようになった

# Changelog
https://github.com/nodejs/node/blob/master/doc/changelogs/CHANGELOG_V16.md#16.6.0

# Reference
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/at

# `.at()`とは
- `-1`を渡すと末尾の要素を、`-2`を渡すと末尾から2番目の要素を返す、ブラケット`[]`の拡張。
- `Array[Array.length - 1]` が `Array.at(-1)`のように書ける。簡単。嬉しい。
- 去年の11月からTC39 Processの`Stage 3`に格上げされ、`Chrome 92` および `Firefox 90`から利用可能となっている。  
https://github.com/tc39/proposal-relative-indexing-method

# その他の提案
もっとシンプルに自由に配列にアクセスしたい、という思いから提案された仕様は他にもある。
## ブラケットのスライス表記
https://github.com/tc39/proposal-slice-notation

- 元からある`slice()`メソッドが分かりにくすぎる！という提案。
- PythonやGolang等にある`[1:3]` `[-1:]`のような書き方を追加するというもの。
- 良さそうだけどドラフトになる気配なし…

## `.lastItem` `.lastIndex`
https://github.com/tc39/proposal-array-last

- その名の通り、最後の要素を指す`lastItem`と、最後のインデックスを指す`lastIndex`を追加する というもの。
- `.at()`又はスライス表記のどちらかが`Stage 3`に進めば、提案は破棄という予定だったので消滅。
javascriptでリテラルなArrayの前はセミコロンが必要です。

表題の通りなのですが、なぜ今まで一度も引っ掛からなかったんだろう？という奇妙だけどありそうなエラーに引っかかったので共有します。まあ、セミコロン省略しないで必ず書く人は引っかからないでしょう。

一部抜粋ですがこのコードは`Uncaught TypeError: Cannot read property 'forEach' of undefined`のエラーになります。


```javascript
form.target = 'ServiceItemForm'

[
  { name: 'shop_id', value: this.props.currentShop.id },
  { name: 'category', value: category },
  { name: 'sub_category', value: sub_category },
  { name: 'name', value: name }
].forEach(item => { //ここでエラー！
  ....
})
```


どう見てもちゃんとしたArrayだしなんでだ？と思ったのですが、詳しく読み解いてみると・・・

```js
//セミコロンがないので'ServiceItemForm'のプロパティーにアクセスしようとしてる
form.target = 'ServiceItemForm'[...].forEach

//[]の中は複数のオブジェクトをカンマで列挙してるので一番最後のオブジェクトが評価される
form.target = 'ServiceItemForm'[{ name: 'name', value: name }].forEach

//{ name: 'name', value: name }が文字列に変換される
form.target = 'ServiceItemForm'['[object Object]'].forEach

//'ServiceItemForm'['[object Object]']はundefined
```

今まで鬼のようにJS書いたけどこれは初だったかも。でも割とセミコロン書かない方なので不思議だなあ。
https://stackoverflow.com/questions/38908243/cannot-read-property-foreach-of-undefined
またスタックオーバーフローに助けてもらいました。
RDSのスナップショットからDBを復元する

#はじめに
RDSのスナップショットからDBを復元する際に、少し手間取ったため、記録します。

##1.DB識別子を確認
現在使用しているDBの識別子を確認します。( RDS>データベース にて確認可能 )

##2.現在のDB識別子を変更
はじめに確認したDB識別子を適当なものに変更します。

##3.スナップショットから復元
①対象のスナップショットを選択し、アクションから「スナップショットを復元」を選択（RDS>スナップショット）
②インスタンス識別子は"元のインスタンス識別子"を指定する
③DBインスタンスクラスは無料枠の場合、以下を選択。
![スクリーンショット 2021-07-10 8.32.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1273104/62fe8c69-165b-90fd-fb4d-22a65497ef4d.png)
④「DBインスタンスを復元」をクリック

##4.復元したDBインスタンスのセキュリティグループを変更
スナップショットからの復元の場合、セキュリティグループが引き継がれないため、設定する必要があります。
元のDBインスタンスと同じ設定にすることで、アプリケーションからの接続が可能になります。

##5.まとめ
スナップショットさえあれば意外と簡単にDBの復元が可能でした。
復元するDBがすでに存在しておらず、DB識別子が不明な場合は、以下の手順で復元・設定が可能です。

・3①で新規識別子を作成　→　アプリケーションのDB設定にて、新規作成した識別子を指定

##6.参考
[DB のスナップショットからの復元](https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/USER_RestoreFromSnapshot.html)
BINDで歓迎されないクエリをIPTABLESでブロックする

###BINDで歓迎されないクエリをIPTABLESでブロックする

BINDのログの中に、以下のような不正なクエリを見つけました。

```console
client x.x.x.x query (cache) 'example.com/A/IN' denied
```

このようなエントリーが大量に頻繁に記録されています。
ログファイルのサイズが大きくなり、リソースの無駄遣いにもなります。
そこで、このクエリをブロックする必要がありますが、どうすればよいのでしょうか？
iptablesでソースIPをブロックすればよいのでしょうか。しかしながらソースIPが複数なのでこの手法は使えません。

ようやく見つけた方法は、iptablesにstringモジュールを付けてブロックする方法です。

以下のように。

```console
DOMAIN=example.com
HEX=$(perl -e 'print map {chr(length($_)).$_} split /./, "'$DOMAIN'"'. | xxd -p)
echo $HEX
076578616d706c6503636f6d
iptables -I INPUT -m string --algo bm --hex-string '|076578616d706c6503636f6d|' -j DROP
```


:::note info
man（英語版）によると、stringモジュールは2.6.14以上のカーネルバージョンから利用できるようです。
ホットペッパーのAPIで遊んでみる

###概要
ホットペッパーAPIを利用して近隣店舗の情報を取得する。

##ホットペッパーAPI
ホットペッパーAPIとはリクルートが提供するOPENAPI。ホットペッパーとホットペッパーBeautyの2種類のAPIが提供されているが、今回はホットペッパーのAPIを利用していきます。
※[ホットペッパーAPIの公式リファレンス](https://webservice.recruit.co.jp/doc/hotpepper/guideline.html)

###準備
ホットペッパーAPIを利用するには利用申請が必要となります。
[リンク](https://webservice.recruit.co.jp/register/)より新規登録し、APIキーを取得してください。申請からAPIキー取得までのリードタイムは約10分程度です。

###実装

```shell:ライブラリインストール
~/develop/study/node/hotpepper $ yarn add fs xml2json node-fetch 
```

```:ディレクトリ構造
~/develop/study/node/hotpepper $ tree -I node_modules
.
├── hotpepper.js
├── package.json
└── yarn.lock

0 directories, 3 files
```

```javascript:hotpepper.js
const fs = require('fs');
const parser = require('xml2json');
const fetch = require('node-fetch');
const API_KEY = 'HOTPEERのAPIキー'

/**APIのURL */
const URL = 'http://webservice.recruit.co.jp/hotpepper/gourmet/v1/?key=' + API_KEY + '&large_area=Z011'

/** 非同期処理 */
async function main() {
  try {
    const res = await fetch(URL);
    if (!res.ok) {
      throw new Error(`${res.status} ${res.statusText}`);
    }
    const data = await res.text();
    var json = parser.toJson(data);
    
    const obj = JSON.parse(json)
    console.log('xmlns:' +obj.results.xmlns)
    console.log('店舗名:' +obj.results.shop[0].name)
    console.log('住所:' +obj.results.shop[0].address)
  } catch (err) {
    console.error(err);
  }
}

main();
```

```:実行結果
~/develop/study/node/hotpepper $ node hotpepper.js              
xmlns:http://webservice.recruit.co.jp/HotPepper/
店舗名:さーて 四ッ谷店
住所:東京都新宿区四谷１-7-15 山田ビル2F
```
【対処法】Vue の CLI が使えない場合

##背景
```
npm install -g @vue/cli
```


```
vue -V

zsh: command not found: vue
```
コマンドが実行できないのは、どうやらPATHが通っていないため、らしい。
##.zshrcにPATHを通すよ
```
export PATH=$PATH:/Users/[username]/.npm-global/bin
```
username はご自身の環境に合わせて書き換えてください。
これを.zshrcファイルの最後行に書く。
##ターミナルに戻って
```
source .zshrc      
```
これを実行。
```
vue -V
@vue/cli 4.5.13
```
できました
Node.js 実行中のファイルの絶対パスを取得する。

相対パスで指定すると、実行するディクレトリによって結果が変わってしまう。

なので NodeJS のスクリプトの中でのパス指定は絶対パスを使う必要がある。


## 結論

`__dirname` を使う。

__dirname は実行中のファイルへの絶対パスを取得できる環境変数。

> __dirname is an environment variable that tells you the absolute path of the directory containing the currently executing file.

https://www.digitalocean.com/community/tutorials/nodejs-how-to-use__dirname



```
bin/
 |_ index.js
src/
```
のようなディレクトリ構成で、`index.js` から `src/` を指定したい場合、

```index.js
const srcPath = path.resolve(dirname, '../src')
```

と指定すると、 `node bin/index.js` でも、 `cd bin/ && node index.js` でも同じ結果になる。
Z3Py　例題　ナップサック問題

# 問題
5つの品物の価格と価値が以下の表に示されるようになっているとする． 価格の合計が 15以下で，価値の合計が 19以上になる場合はあるか?

| 品物 | 価格 | 価値 |
|:-:|:-:|:-:|
|品物0|3|4|
|品物1|4|5|
|品物2|5|6|
|品物3|7|8|
|品物4|9|10|

# 回答
```example_knapsack.py
from z3 import *

price = [3, 4, 5, 7, 9]
value = [4, 5, 6, 8, 10]

X = [Int("X%s" % i) for i in range(5)]

s = Solver()
s.add([And(0 <= X[i], X[i] <= 1) for i in range(5)])
s.add(Sum([price[i]*X[i] for i in range(5)]) <= 15)
s.add(Sum([value[i]*X[i] for i in range(5)]) >= 19)

print(s.check())
if s.check() == sat:
    print(s.model())
```
出力
価値の合計が19の場合、

```terminal
unsat
```

価値の合計を18の場合、

```terminal
sat
[X1 = 0, X0 = 1, X4 = 0, X3 = 1, X2 = 1]
```


## 解説
`s.add(Sum([value[i]*X[i] for i in range(5)]) >= 19)` の19が価値の合計に対する制約
ここを変えることで、価値の制限による違いを見ることができる。

# 他の例題
[Z3Py個人的ポータル](https://qiita.com/Ganesha/items/7a606ffc8a7c2504c143) へ
素のJavaScript（node）だけでmicroCMSのデータを全て取得してみた

例えばNextJSのビルド前だったりGatsbyJSのgatsby-node.js(nodeしか使えないページ)、ライブラリが使えない、などの何らかの形で素のJSだけでお手軽にデータを取得したい時があります。

microCMSがそのケースでした。その時に少し工夫が必要だったので知見としてコードを載せてみました。

## GETのデフォルトが10件までしか取得できない
通常は以下のようなコードで取得すると思います。

```node.js
const axios = require('axios').default;
require('dotenv').config({ path: '../../.env' }); // package.jsonから動かす場合はpathが通っていると思われるので不要。必要であれば.envのあるファイルの相対パスを記載

const getMicroCMSdata = async() => {
  const url = `https://hoge.microcms.io/api/v1/hoge`;
  const apiKeyHeaderOption = { headers : { "X-API-KEY": process.env.MICROCMS_API_KEY }};

  return await axios.get(url, apiKeyHeaderOption).then(r => r.data);
}

console.log(getMicroCMSdata().then(data => console.log(data)));
```

しかし記事データを確認すると10件しか取得できていません。
取得したJSONの中身を確認すると

```json
{
  contents: [
    {省略}...
  ],
  totalCount: 100,
  offset: 0,
  limit: 10
}
```
となるように limit: 10 が返ってきています。確認したところやはり limit: 10 が取得できる件数を示していました。
したがって、この limit の上限を自身のコンテンツの数（totalCount以上）に設定する必要があります。

ただし、面倒であれば url に ?limit=1000 のような大きめの数字でオプションをつけてあげれば済みます。
ですがそれだとちょっと気持ち悪いので先に totalCount を取得してから ?limit=${totalCount} となるようなコードを書きました。

## ２回GETさせてみた

```node.js
const axios = require('axios').default;
require('dotenv').config({ path: '../../.env' }); // package.jsonから動かす場合はpathが通っていると思われるので不要。必要であれば.envのあるファイルの相対パスを記載

const getMicroCMSdata = async() => {
  const url = `https://hoge.microcms.io/api/v1/hoge`;
  const apiKeyHeaderOption = { headers : {"X-API-KEY": process.env.MICROCMS_API_KEY }};

  const getUrlOption = (number, url) => {
    const UrlandOption = url + `?limit=${number}`;

    return String(UrlandOption);
  }

  // microCMSのコンテンツを引っ張ろうとするとデフォルトでlimit=10のオプションがついており全てのコンテンツを引っ張ってこれない。totalCountでコンテンツ総数をチェック
  const getTotalCountUrl = getUrlOption(0, url),
    totalCountUrlData = await axios.get(getTotalCountUrl, apiKeyHeaderOption).then(r => r.data),
    { totalCount } = await totalCountUrlData;

  // ２回目のGET
  const getContentUrl = getUrlOption(totalCount, url),
    contentUrlData = await axios.get(getContentUrl, apiKeyHeaderOption).then(r => r.data),
    { contents } = await contentUrlData;

  return contents;
}

console.log(getMicroCMSdata().then(data => console.log(data)));
```

getUrlOption の関数で引数に応じた ?limit=${number} のオプションをURLに追加させています。

初回のGET時は  ?limit=0 にして無駄なリソースを取得しないようにして、２回目のGET時には取得した totalCount の値を渡して実行するようにしました。
zsh で PATH を通す方法

## 手順
1. ~/.zshrc に任意の PATH を追記
2. source コマンドを実行  

##.zshrc ファイルを開く
```
open ~/.zshrc  
```
これをターミナルで実行すると、テキストファイルが開くのでそこに任意の　PATH を追記してください。
##sorceコマンドを実行
```
source ~/.bash_profile
```
これをターミナルで実行すると完了です。
【初心者】Stimulus の使い方


# 概要
Stimulus の簡単な機能を学習したので記載します。
これからStimulusを学習する方の参考になればと思います。

前提条件としてdockerとrails6で実装しています。
他の方法も一応記載しているので、参考になれば嬉しいです！

# Stimulusとは

Stimulusは、JavaScriptフレームワークです。
StimulusはHTMLを中心に考え、JavaScirptで書かれたHTMLを呼び出すことができるように設計されています。

## 基本説明
呼び出すJavaScriptオブジェクトはコントローラーと呼ばれ、StimulusはHTMLデータコントローラー属性が表示されるのを待ってページを継続的に監視します。 
Stimulusは、属性ごとに、属性の値を調べて対応するコントローラークラスを見つけ、そのクラスの新しいインスタンスを作成して、それを要素に接続します。

つまり、class属性がHTMLをCSSに接続するブリッジであるように、Stimulusのデータコントローラー属性は**HTMLをJavaScriptに接続するもの**です。

いや、どうゆことやねんって感じなので実際に使っていきます。

# 使い方

前提として
① 今回はdockerの環境で開発します。
dockerの環境構築がまだの方は
↓こちら↓を参考にして下さい。
[【Docker】Quickstart : Compose and Rails やってみた](https://qiita.com/SAPPPOROBEER/items/65e3c08bd2e59e05bba6)

②webpackerのインストールが必要な為、rails6で開発します。
rails5の方は以下の方法でwebpackerをインストールしなくても開発できます。
[【GitHub】 Stimulus-rails](https://github.com/hotwired/stimulus-rails)

では開発していきます。

### javascriptファイルに記述

javascript>controllers>hello_controller.jsファイルに
以下を記述します。




```javascript:javascript>controllers>hello_controller.js

import { Controller } from "stimulus"

export default class extends Controller {
  static targets = [ "name", "output" ]

  greet() {
    this.outputTarget.textContent = `Hello, ${this.nameTarget.value}!`
  }
}
```

### viewsファイルに記述

views>messages>index.html.erb に以下を記述します。

```html:index.html.erb
<div data-controller="hello">
  <input data-hello-target="name" type="text">

  <button data-action="click->hello#greet">
    Greet
  </button>

  <span data-hello-target="output">
  </span>
</div>
```

これで準備完了です。
dockerを動かしていきます。

```
% docker compose up
```

dockerが動いているのを確認したのでローカルで確認してみます。
[http://localhost:3000/](http://localhost:3000/)

以下のようにテキストを入力できるフォームが表示されました。
![スクリーンショット 2021-08-05 15.37.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1129869/eee4a84a-a8f5-9f6f-1c80-20d988ed091a.png)


実際に使ってみます。

![スクリーンショット 2021-08-05 15.45.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1129869/0ebb9937-c295-6d1b-432c-a13d0ec02d0d.png)


上記のように入力して**「Greet」**ボタンを押します。

![スクリーンショット 2021-08-05 15.47.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1129869/3385c767-3a2e-2221-14cf-f30abbd3ada6.png)

右側に**Qiita！**と表示されるようになりました。

これで完了です。
この機能を活用して様々なJavaScriptの動きをHTML上で表示することができます。

今後、他にも様々な機能を実装していこうと思います。

# 最後に

stimulusは最近私も知ったJavaScriptのフレームワークです。
使用方法もコントローラーで接続するので比較的簡単です。

前提条件がdocker・rails6だったので、やりづらいかも知れません。
なので、まずは公式ドキュメントを確認してみて下さい。
[「STIMULUS 公式ドキュメント」](https://stimulus.hotwired.dev/handbook/introduction)

私もこれから学習していきます。
頑張りましょう！！
[Vue.js]トランジション


```HTML
<head>
    <meta charset="utf-8">
    <title>vue</title>
    <link rel="stylesheet" href="css/styles.css">
    <!--これはアニメーションのために必要-->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/2.2.0/anime.min.js"></script>
</head>

<body>

    <script src="https://unpkg.com/vue@2.5.17"></script>

    <div id="app">
        <pull-down-menu></pull-down-menu>
    </div>

    <script src="js/main.js"></script>
</body>
```

css は好きに書いてね

```Vue.js
var fff = {
    data: function () {
      return {
        isShown: false,
        name: 'カーソル',
        items: [
          '1-1',
          '1-2',
          '1-3',
        ]
      };
    },
    template: `
      <div @mouseleave="isShown = false">
        <p @mouseover="isShown = true"><a href="#" class="menu">{{ name }}</a></p>
　　　　//イベントに対するイベントリスナーは
        <transition
          @before-enter="beforeEnter"
          @enter="enter"
          @leave="leave"
        >
          //isShownの時にリストが出現
          <ul v-if="isShown">
            <li v-for="item in items" :key="item">
              <a href="#" class="menu-item">{{ item }}</a>
            </li>
          </ul>
        </transition>
      </div>
    `,
    methods: {
    //トランジションの対象となるDOM要素:el
    //初期状態
      beforeEnter: function(el) {
        el.style.height = '0px';
        el.style.opacity = '0';
      },
      enter: function(el,done) {
        // 3秒かけて、透明度と高さを変更して出現させる
　　　　//はじめ
        anime({
          targets: el,
          opacity: 1,
          height: el.scrollHeight + 'px',
          duration: 10000,
          complete: done
        });
      },
      leave: function(el,done) {
      //終わり
        anime({
          targets: el,
          opacity: 0,
          height: '0px',
          duration: 10000,
          complete: done
        });
      }
    },
  };

  new Vue({
    el: '#app',
    components: {
      PullDownMenu: fff
    }
  });

```
Docker-compose 関連でつまづいたときに参考になった記事[M1 Mac]


### M1 Mac関連の問題

- [Dockerコンテナでyarnをインストールする](https://satoh-d.hatenablog.com/entry/2020/10/21/180000)
- [Docker に yarn を入れるための yarnpkg で no valud opengpg data found になった時の対処法](https://zenn.dev/junki555/articles/2de6024a191913)
- [M1 MacでHeroku containerにデプロイしたら `Exec format error` と出て困った話](https://zenn.dev/daku10/articles/m1-heroku-container-trouble-exec-format-error)
- [M1 MacでHerokuにデプロイする手順](https://qiita.com/nagatak/items/fc7a2cc39d8fb1826b32)

### docker-compose build
- [Dockerでコンテナ内にbundle installされない問題の解決法](https://fuqda.hatenablog.com/entry/2019/03/21/204118)
パス間違いはないが、Railsで写真が表示されない原因

##パス間違いはないが、Railsで写真が表示されない。
自分のポートフォリオを作っているときに発生した問題なのですが、パスはあっているのに写真が表示されず30分くらい手が止まってしまったので、ここで今回の解決策を共有させていただきます。

結論：ファイル名にカタカナを用いてはいけない。
例えば、マネー.jpgとかレベルアップ.pngなど。
写真の種類をわかりやすくするため自分でファイル名を変更することがあると思うのですが、まさかカタカナがダメだとは思いませんでした。なかなかの盲点だったのでみなさんも注意してみてください！
Ubuntu 20.04 LTSでリンクアグリゲーション(LACP)を組んでみた

#Ubuntu 20.04LTSの設定
既にUbuntu 20.04LTSではPC本体のLANインタフェース(enp1s0)に加え、USB接続のLANインタフェース(enx7cc2c6FFFFFF)を接続して2つのLANインタフェースが利用できる状態です。
この状態で/etc/netplan配下にあるyamlファイルに下記の「bonds:」以下の記載を追加することでLANインタフェースがまとめられて(リンクアグリゲーション)bond0というインタフェースができます。

```
$ sudo vim /etc/netplan/01-network-manager-all.yaml
# Let NetworkManager manage all devices on this system
network:
  ethernets:
    enp1s0:
      addresses:
      - 192.168.2.6/24
      gateway4: 192.168.2.1
      nameservers:
        addresses:
        - 8.8.8.8
        - 8.8.4.8
        search: []
    enx7cc2c6FFFFFF:
      addresses:
      - 192.168.2.7/24
      gateway4: 192.168.2.1
      nameservers:
        addresses:
        - 8.8.8.8
        - 8.8.4.4
        search: []
  bonds:
    bond0:
      interfaces: [enp1s0, enx7cc2c6FFFFFF]
      addresses: [192.168.2.8/24]
      gateway4: 192.168.2.1
      parameters:
        mode: 802.3ad
        transmit-hash-policy: layer3+4
        mii-monitor-interval: 1
      nameservers:
        addresses:
        - 8.8.8.8
        - 8.8.4.4
  version: 2
  renderer: NetworkManager
```
##設定の反映
ファイルを保存したら設定を反映させるため下記を実行します。

```
$ sudo netplan apply
```

##インタフェースの確認
bond0というインタフェースができていることが確認できました。
($ ip aで見ればenp1s0とenx7cc2c6FFFFFF表示されます)

```
$ ip -4 a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
4: bond0: <BROADCAST,MULTICAST,MASTER,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    inet 192.168.2.8/24 brd 192.168.2.255 scope global noprefixroute bond0
       valid_lft forever preferred_lft forever
```

#スイッチの設定
リンクアグリゲーション(LAPC)に対応しているスイッチを用意します。
ここでは[AlliedTelesisのx510-28GTX]("https://www.allied-telesis.co.jp/products/list/switch/x510/catalog.html")を利用します。
2つのLANインタフェース(enp1s0とenx7cc2c6FFFFFF)はx510-28GTXのポート番号3(port1.0.3)とポート番号4(port1.0.4)に接続しています。

```
awplus>en
awplus#conf t
Enter configuration commands, one per line.  End with CNTL/Z.
awplus(config)#int port1.0.3-port1.0.4
awplus(config-if)#channel-group 1 mode active
awplus(config-if)#
awplus#write memory
Building configuration...
[OK]
awplus#sh etherchannel
LAG Maximum        : 128
LAG Static  Maximum: 96
LAG Dynamic Maximum: 32
LAG Static  Count  : 0
LAG Dynamic Count  : 1
LAG Total   Count  : 1
Lacp Aggregator: po1
Member:
 port1.0.3
 port1.0.4
awplus#
```

##疎通確認
確認はWindows10 PC(192.168.2.3)からpingで行います。

```
C:\>ping 192.168.2.8

192.168.2.8 に ping を送信しています 32 バイトのデータ:
192.168.2.8 からの応答: バイト数 =32 時間 <1ms TTL=64
192.168.2.8 からの応答: バイト数 =32 時間 <1ms TTL=64
192.168.2.8 からの応答: バイト数 =32 時間 <1ms TTL=64
192.168.2.8 からの応答: バイト数 =32 時間 <1ms TTL=64

192.168.2.8 の ping 統計:
    パケット数: 送信 = 4、受信 = 4、損失 = 0 (0% の損失)、
ラウンド トリップの概算時間 (ミリ秒):
    最小 = 0ms、最大 = 0ms、平均 = 0ms
```


これでUbuntu 20.04LTSのPCとスイッチ間でリンクアグリゲーションによる接続と疎通確認ができました。
次回はUbuntu 20.04 LTSのPCをサーバにして2台のクライアントPCからiperf3によるスループット測定を同時に行い、各々、1Gbpsの速度がでるか試してみたいと思います。