OmniAICreator/Qiita-1.07M huggingface dataset:
64bit版ExcelでVBA⇔SAP連携を行う方法（特殊な環境で業務している人向け）

# まず初めに
この記事に記載している方法は一部を除き**非推奨**な方法となります。
そのため、何らかの問題が発生しても**すべて自己責任**でお願いします。

# 正攻法でのSAP連携方法
+ [SAP JCO(Java Connector)を使用する](https://support.sap.com/ja/product/connectors/jco.html)
+ [SAP NCO(.NET Connector)を使用する](https://support.sap.com/ja/product/connectors/msnet.html)

いずれもSAP公式が提供しているミドルウェアとなります。
使用方法について、Qiitaでもいくつか記事がありますので、詳しく知りたい方はそちらを参照してみてください。(丸投げ)
どちらの手段にしても、JCO(NCO)を使用して作成されたアプリをVBAから呼び出す形で連携を行うことになります。

もちろんVBA以外での連携方法(PowerShellなど)もありますが、ここでは割愛します。

# この記事の想定読者
さて、JCOやNCOは大変便利ですが、ミドルウェア(ライブラリ)のダウンロードにはS-Userが必要です。
…そう、S-Userが必要なんです。
この記事は、何らかの理由 ~~(主に職場の環境面)~~ でS-Userの利用ができない、でも64bit版のExcel(VBA)でSAP連携を行いたい人を対象としています。
~~そんな人どれだけいるんだ…？~~

# 解決方法
私の知る限りでは、以下3つの方法があります。
(他にもあるかもしれません)

## 方法①　32bit版Excelを使用する
一番お手軽な解決方法です。
しかし、64bit版を使用している状態から都度32bit版に切り替えるというのは現実的ではありません。
そのため、SAP連携用に32bit版Excelをインストールしている端末を用意するのが良いでしょう。
~~気軽に専用端末用意できるのであればS-Userくーださい~~

## 方法②　レジストリを編集する　※非推奨
[SAP Communityの記事を参照ください。](https://answers.sap.com/questions/12721599/sap-gui-scripting-in-64-bit-excel.html)
レジストリを編集することで、64bit版Excel(VBA)からでもSAP連携可能になるそうです。
が、当然敷居が高くなりますので、最終手段として考えておくのが良いでしょう。
私としても、これについては実践できていませんので、本当にSAP連携可能になるかどうかも保証できません。
~~そもそもレジストリ編集を許可する前にS-UserとVisual Studioくーださい~~

## 方法③　64bit版Excel(VBA)から32bit版VBSを実行する
なんてことはありません。
64bit版で動かないなら、無理やり32bit版で動かせば良いのです。
この方法③について実装例を記載します。

# 実装例：VBAのコード
VBA側の実装は以下になります。
```VBA:Sample
Dim WshShell as WshShell
Dim VBSReturnCode as Integer

Set WshShell = new WshShell
VBSReturnCode = WshShell.Run("cmd.exe /c C:\Windows\SysWOW64\cscript.exe [vbsの配置ディレクトリ]\SAPQueryRFCModule.vbs")
```
VBSをSysWOW64のcscriptで実行する。ただそれだけのコードとなります。
SAPログインユーザーや実行クライアントを固定値以外にする(入力させる)場合は、VBSの引数にそれを追加し、上記コードの実行引数に追加してください。

# 実装例：VBSのコード
VBS側の実装は以下になります。(ログインクライアントなどはすべて固定としています)
```VBS:SAPQueryRFCModule.vbs
Option Explicit

Dim FunctionControl
Dim SapConnection

Set FunctionControl = CreateObject("SAP.Functions")
Set SapConnection = FunctionControl.Connection

SapConnection.Client = "xxx"
SapConnection.HostName = "hostname"
SapConnection.SystemNumber = "sysnum"
SapConnection.Language = "ja"
SapConnection.User = "user"
SapConnection.Password = "password"

If SapConnection.Logon(0, True) = False Then
  Wscript.Quit(-1)
End If

do something...

FunctionControl.Connection.Logoff
Wscript.Quit(0)
```
処理の本体となる部分は省略しています。
よくあるVBA⇔SAP連携のコードとほぼ同じですので、VBAで実装してあったものがほぼそのまま移植できます。

# おわりに
方法③について、考え方はJCO(NCO)による連携と同じですね。
(SAP連携可能な外部実行ファイル(スクリプト)を呼び出す)

解決方法を難易度順にすると　①＞③＞②　になります。
~~諸々を考慮すると　③＞①＞②　になりそう~~

以上です。
ここまでお読みいただき、ありがとうございました。
TypeScript勉強会 第6回補足 ~非同期処理で気をつけること~

## 宙に浮いたPromiseを作らない

宙に浮いたPromiseというのは、`await`のつけれられていない非同期処理の呼び出しがある関数(もしくは`Promise`を`retuｒｎ`していない関数)です。

具体的には以下のようなものです

```.ts
async function sendRequest(){
  await postA()
  postB()
}
```

この`sendRequest()` 関数をawaitして呼び出してみると、`postA()`関数はきちんと処理完了まで待ってくれますが、`postB()`は待ってくれなくなります。

```.ts
await sendRequest() // => postAの完了を待機するが、postB()の完了は待機してくれない
// 本当はpostB()の実行を待って実行したかった処理
doSomething()
```

このような関数を作ってしまうと、非同期処理のハンドリングが非常に困難になってしまうので、基本的には`await`をつけるなり、returnで返すなりして、きちんと呼び出し元からハンドリングできるようにしましょう。

## 並列実行しつつPromiseを制御する

Promiseを並列実行しつつ、きちんと制御するには`Promise.all`や`Promise.allSettled`を使います。
これらの機能を使うことで、宙に浮いたPromise関数の呼び出しを作らずに、複数の非同期処理を非同期に実行することができます。

```.ts

await Promise.all([
 postA(),
 postB()
])

// postAとpostBが並列に実行され、両方が正常終了する、もしくは、どちらかがエラーになったら処理が終了し、ここが実行される
doSomething()

```

`Promise.allSettled`は割と最近の構文なので使えないプロジェクトもあることに注意

```.ts

await Promise.allSettled([
 postA(),
 postB()
])

// postAとpostBが並列に実行され、両方の処理が正常に終了するかエラーになるかし、すべての結果が決まったあと、ここが実行される
doSomething()

```

## 非同期処理の繰り返し処理

非同期処理の繰り返す処理は少し注意が必要です。よくある悪い例は以下です。

```悪い例.ts
[user1,user2].forEach(async (user) => {
  await sendUser(user)
})
```

上記のように`forEach`や`map`を使ってPromise関数を引数に指定した場合、JSは引数に指定された関数を**awaitをつけずに**実行します。

なので上記は以下と等価です。Promiseが宙に浮いてしまっている悪い例ですね

```.ts
 (() => await sendUser(user1))()
 (() => await sendUser(user2))()

 // 少しわかりにくいが以下とだいたい同じ
 sendUser(user1)
 sendUser(user2)
```

一方for文を使って以下のように書くこともできます。

```悪い例2.ts
for (const user of [user1,user2]) {
 await sendUser(user)
}
```

for文はforEachと違い、関数の呼び出しを行うわけではないので、上記は以下と等価です。

```.ts
await sendUser(user1)
await sendUser(user2)
```

間違っているわけではないのですが、この書き方だとすべてのループが直列に実行されるので、ループの回数が多い場合は性能に悪影響が出る可能性があります。このため、ESLintでは[no-await-in-loop](https://eslint.org/docs/rules/no-await-in-loop)というルールで禁止されていることが多いです。

すべてのループの非同期処理を並列に実行して、すべての実行結果の完了を待つことを考えるのであれば、以下のようなコードを書くのが良いと思います。forEachではなくmapを使っているところがポイントです。

```良い例.ts
// ここではallSettledを使っているが、環境や目的によってはallでもほぼ同じ使い方ができる
await Promise.allSettled(
 [user1,user2].map((user) => {
   return sendUser(user) // returnでPromiseを返しているが、`await sendUser(user)`のようにしても良い
 })
)

```

これは以下のコードと等価です

```.ts
await Promise.allSettled([
 sendUser(user1),
 sendUser(user2) 
])
```
効率的なseedの書き方

# seeds.rb
Railsで初期データを格納する場合、あらかじめseeds.rbでデータをcreateしておくという手法が一般的だと思われます。
ただ、モデルが増えていくと自ずと投入したいデータは肥大化していき、seedで管理するのが面倒になりませんか？？

## 管理の方法
ある種思想の話になりますが、私はdevelop/test/productionでそれぞれseedデータは分けるべきだと考えています。
従って下記のようにseedを管理しています。

### 格納フォルダ作成
```bash:
$　mkdir -p db/seeds/development
$　mkdir -p db/seeds/test
$　mkdir -p db/seeds/production
```
seedデータを格納するseedsフォルダを作成しました。
さらに実行環境毎にフォルダを分けています。

### データを投入
```bash:
$　touch db/seeds/development/users.rb
$　touch db/seeds/test/users.rb
$　touch db/seeds/production/users.rb
```

```ruby: db/seeds/development/users.rb
User.create!(
  email: test@example.com
  password: password
  name: nara
)
```
各フォルダにデータ投入用のファイルを作成します。
また、必要なファイルに初期データを投入します。

### seed.rbで環境毎に読み込むフォルダを変更
```ruby: db/seed.rb
tables = %w(users) #読み込むseedデータのファイル名

tables.each do |table|
  path = Rails.root.join("db", "seeds", Rails.env, "{table}.rb" #環境毎のpathの指定
  if File.exist?(path)
    puts "Creating #{table}..."
    require(path)
  end
end
```

tablesという変数に配列で読み込むファイル名を指定します。（複数ある場合でも、付け加えていけば大丈夫です。）
そして、それらをeachで回した上で、環境毎にpathを発行し読み込むseedの分岐を行なってあげます。

これにより、環境毎に読み込む先のフォルダを変更でき、かつseed.rbに全ての初期データを書く必要がなくなるため肥大化を抑えつつ効率よく初期データを作成することが可能になります。

# まとめ
seedは肥大化するとイライラの原因になるのでできるだけ避けましょう。
PostgreSQLのJSONデータを扱う


## 配列要素からオブジェクトを取得

```json:データ
'[{"name":"apple"},{"name":"banana"},{"name":"orange"}]'::json->1
```

```json:結果
{"name":"banana"}
```

## 該当キーのオブジェクトを取得

```json:データ
'{"first":{"name":"apple"},"second":{"name":"banana"},"third":{"name":"orange"}]'::json->'first'
```

```json:結果
{"name":"apple"}
```

# 参考

https://www.postgresql.jp/document/9.5/html/functions-json.html
PHPのreadfile()でファイルサイズが大きいzipファイルをダウンロードできなかったためfopen()-fread()にした話

PHPのreadfile()でファイルサイズが大きいzipファイルをダウンロードできなかったためfopen()-fread()にした話

#修正前
```php
readfile($zip_name);
```

#修正後
```php
$handle = fopen($zip_name, 'rb');
while (!feof($handle)){
    echo fread($handle, 4096);
    ob_flush();
    flush();
}
fclose($handle);
```
React.jsのPropTypes.array の役割

配列を受け付ける

```js
PropTypes.array

// 受け付けるもの
[33, 'こんにちわ', true]
[{ name: '山田'}, { fruit: 'りんご' }]
```

配列であれば中身は気にしない。
そのため`非推奨`となっている。


配列の値の型もすべてチェックするなら、 `arrayOf`を使用する必要がある。

```js
PropTypes.arrayOf(PropTypes.string) 

// 受け付けるもの
['1','あいうえお']
```

参考
[React.jsでPropTypesを利用した時の話](https://qiita.com/sfatsfc/items/d32b28ccd10e04bc87ae)
Oracle Analytics Cloud：各ダッシュボードへのメニュー風のリンクを作ってみる

# はじめに
Oracle Analytics Cloud（**OAC**）を利用をすすめていくと、どうしてもダッシュボードが多くなってしまうことがあります。
そんなとき、目的のダッシュボードに素早くたどり着くための方法のひとつとして、カスタムメニューの作成があります。
ここでは、ダッシュボードにメニューを作って他のダッシュボードへの起点にしたいと思います。

# やりたいこと

- メニュー用のダッシュボードを新規に作る
- そこに他のダッシュボードへのリンクを作る
- リンクにはカスタム画像を使ってメニュー風にする

# メニュー用のダッシュボードを新規に作る
クラシックホームに移動し、「新規」から「ダッシュボード」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/83111a8c-6acf-575d-d5a0-5be5d4372e6f.png)

ダッシュボード名は「メニュー」とします（作成先は任意）。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/b2e2e6f2-0d63-f4b4-2f26-5ea476bc6792.png)

# 他のダッシュボードへのリンクを作る
ダッシュボード編集画面で、「リンクまたはイメージ」をドラッグ＆ドロップで選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/5755ee94-1896-48a0-6726-e54c2655233b.png)
セクションの「プロパティ」を表示させます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/c917ce39-cfb3-c8b5-a686-85b060b798cd.png)
「参照」をクリックしてリンクしたいダッシュボードを選択後、「イメージの選択」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/b928f8f8-36ed-2866-a42c-f48f94e28875.png)
メニュー用のカスタム画像をアップロードし、アップロードした画像を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/a3267049-6009-407f-7f7c-725fe357b78f.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/08bd5fc3-a351-6512-594f-4bff79c05f1b.png)
保存した後、実行します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/e45128ad-4f27-846c-c02d-388d53ecc72e.png)
動作確認できたら、もう一度「ダッシュボードの編集」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/d622f3e5-300d-b76d-2e54-783f79c34e09.png)

# 仕上げ
「セクション1」のプロパティを変更します。
名前を「セクション1」から「営業支援システム」に変更してみました。
「折りたたみ可能」はオフにし、「セクション・ヘッダーの表示」と「セクション・タイトルの表示」をオンにします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/3f9894ab-ad1f-c778-f47a-8790bcf44099.png)
ダッシュボードを保存して、もう一度実行してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/249cfa77-d55f-bc57-5f50-06e7394a7329.png)
いい感じになったので、再度ダッシュボードの編集に戻り、他のダッシュボードへのリンクも作ってみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/9fdd6cfd-813c-0234-04df-336699d56067.png)
実行結果です。
良いんじゃないでしょうか？
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/2d42695f-ebdb-4fcb-246c-803706f0d667.png)

# アップロードしたカスタム画像がいらなくなったら
[カタログメニューから削除できます](https://qiita.com/tyo38/items/154d6f43bd923c424d08#%E3%82%A2%E3%83%83%E3%83%97%E3%83%AD%E3%83%BC%E3%83%89%E3%81%97%E3%81%9F%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%A0%E7%94%BB%E5%83%8F%E3%82%92%E5%89%8A%E9%99%A4%E3%81%99%E3%82%8B%E3%81%AB%E3%81%AF)
[CentOS] dm-cacheを使用してHDDのキャッシュにしたSSDを削除する

[かつて設定したSSDキャッシュ](https://qiita.com/sengoku/items/e85526bb7d578aee295a)を削除します。

# 環境

* CentOS Linux release 7.7.1908
* Linux 3.10.0-1062.18.1.el7.x86_64

```
  LV              VG  Attr       LSize    Pool     Origin         Data%  Meta%  Move Log Cpy%Sync Convert
  [cache0]        vg0 Cwi---C--- <362.79g                         99.99  3.10            0.00            
  [cache0_cdata]  vg0 Cwi-ao---- <362.79g                                                                
  [cache0_cmeta]  vg0 ewi-ao----  372.00m                                                                
  export          vg0 Cwi-aoC---   <1.82t [cache0] [export_corig] 99.99  3.10            0.00            
  [export_corig]  vg0 owi-aoC---   <1.82t                                                                
  [lvol0_pmspare] vg0 ewi-------  372.00m         
```

ボリュームグループ **vg0** に、ロジカルボリューム **export** があります。
キャッシュプール **cache0** があります。

まとめると、このようになっています。

| 役割 | LV |
|:--|:--|
| キャッシュLV  | vg0/export  |
| キャッシュプールLV  | vg0/cache0  |
| キャッシュメタデータLV  | vg0/cache0_cmeta  |
| キャッシュデータLV  | vg0/cache0_cdata  |
| オリジンLV  | vg0/export_corig  |


# 作業手順

lvmcache(7)のマニュアルに従って作業します。

2通りあります。

* キャッシュLVから、キャッシュプールLVを切り離すだけ
    * `lvconvert --splitcache VG/CacheLV`
* キャッシュLVから、キャッシュプールLVを切り離して、キャッシュプールLVを削除
    * `lvconvert --uncache VG/CacheLV`


# 作業記録

キャッシュLVから、キャッシュプールLVを切り離してみました。

## 作業前

```console
# lvdisplay vg0/export
  --- Logical volume ---
  LV Path                /dev/vg0/export
  LV Name                export
  VG Name                vg0
(snip)
  LV Cache pool name     cache0
  LV Cache origin name   export_corig
(snip)
```

## キャッシュプールLVを切り離し

```console
# lvconvert --splitcache vg0/export
  Flushing 0 blocks for cache vg0/export.
  Logical volume vg0/export is not cached and cache pool vg0/cache0 is unused.
```

## 作業後

```console
# lvdisplay vg0/export
  --- Logical volume ---
  LV Path                /dev/vg0/export
  LV Name                export
  VG Name                vg0
(snip)
  LV Status              available
(snip)
```

キャッシュプールの情報が消えました。

## キャッシュプールLVを削除

```console
# lvremove vg0/cache0
  Logical volume "cache0" successfully removed
```

## ボリュームグループから物理ボリュームを解放

キャッシュ用に使っていた物理ボリュームを解放しました。

```console
# vgreduce vg0 /dev/sda4
  Removed "/dev/sda4" from volume group "vg0"
```
ポッポッポー♪♪♪ 懐かしのSL機関車をAmazon Linux2で走らせてみよう！

# はじめに
某ベンダで、クラウドの人材育成企画と研修トレーニングのデリバリを担当しています。
今回は、懐かしいネタで記事を書いてみようと思います。**slコマンド**を使って、Amazon Linux 2のターミナルにSL機関車を走らせてみたいと思います。

slについては、詳細がwikiに記載されています。ぜひこちらを参考をください。

>　[sl (UNIX) - Wikipedia](https://ja.wikipedia.org/wiki/Sl_(UNIX))

Debian/Ubuntuだとdebパッケージが提供されているので、apt-getで簡単にインストールできます。Amazon Linux 2のyum リポジトリではRPMパッケージが提供されていないようなので、今回はUbuntuのDEBパッケージをalienコマンドでRPMパッケージに変換してみようと思います。

# alienを利用したslパッケージ(.rpm)の作成
UbuntuのEC2を立ち上げて、以下の手順でパッケージを作成します。手順は、全て**root**権限で実施します。

## 1. slパッケージ(.deb)のダウンロード
```
# apt-get -d install sl
```
/var/cache/apt/archives以下にパッケージ(.deb)がダウンロードされます。

## 2. alienのインストール
```
# apt-get install alien
```

## 3. .debから.rpmへの変換
```
# alien  -r /var/cache/apt/archives/sl_5.02-1_amd64.deb 
sl-5.02-2.x86_64.rpm generated
```

## 4. 変換したパッケージ(.deb)の詳細確認
```
# rpm -qpi sl-5.02-2.x86_64.rpm 
Name        : sl
Version     : 5.02
Release     : 2
Architecture: x86_64
Install Date: (not installed)
Group       : Converted/games
Size        : 35525
License     : see /usr/share/doc/sl/copyright
Signature   : (none)
Source RPM  : sl-5.02-2.src.rpm
Build Date  : Fri Mar 18 05:55:34 2022
Build Host  : ip-172-31-34-123.ap-southeast-2.compute.internal
Relocations : (not relocatable)
Summary     : Correct you if you type `sl' by mistake
Description :
Sl is a program that can display animations aimed to correct you
if you type 'sl' by mistake.
SL stands for Steam Locomotive.
(Converted from a deb package by alien version 8.95.)
```

alienで変換したエビデンスが残っています。

>(Converted from a deb package by alien version 8.95.)


## 5. Amazon Linux 2へのインストール
```
# rpm -Uvh sl-5.02-2.x86_64.rpm
error: Failed dependencies:
libncurses.so.6(NCURSES6_5.0.19991023)(64bit) is needed by sl-5.02-2.x86_64
libtinfo.so.6(NCURSES6_TINFO_5.0.19991023)(64bit) is needed by sl-5.02-2.x86_64
```
ライブラリの依存関係でエラーが出てます。単純にパッケージ変換で移植できると思ったのですが、失敗。。。ソースファイルからコンパイルする方針に変更して、再トライしてみます。

# [再トライ] ソースファイルからコンパイルする
## 1. slコマンドのソース入手
Ubuntuからソースファイルを取得しようと思いましたが、GitHubに最新のソースコードが公開されています。最新のversion 5.03を入手します。

https://github.com/mtoyoda/sl

## 2. 必要ライブラリの追加
ヘッダファイルを確認するとcurses.hが必要になりそうです。EPEL(Extra Packages for Enterprise Linux)を有効にして、必要なライブラリを追加します。

```
# yum install epel-release
# yum install ncurses-devel
```

## 3. コンパイル
```
# make
```

## 4. 実行
```
# ./sl
```

Amazon Linux 2 のターミナルにSL機関車が走ります。ポッポッポー♪♪♪ポッポッポー♪♪♪懐かしい〜。

![Screen Shot 2022-03-18 at 17.19.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/625920/38b749c3-acbc-6867-71c4-ee7b1785b6ba.png)

# おわりに
パッケージ形式の移植で簡単に出来るかなーと思ったのが大きな見込違いで、３時間近く試行錯誤してしまいました。家の環境もMacになって久しく、自前でコンパイルしてPPをインストールする機会もなくなりました。でも、たまにはこういう作業も懐かしくていいですね。
Gatsby.js 使い方メモ（つまづいた点と解消法）

Gatsby.jsのLP実装で制作とは異なる点があったのでメモ
※今後も追加予定。

# 背景
初めてGatsby.jsをさわってみて、WEB制作とは異なる点があり、その仕様を理解するのに時間がかかったので、理解用にメモ。

# 注意
- aタグは使用せず、Linkタグを使用
ブラウザでは、「ページ遷移」ではなく、「同じページで描画を書き換えている」
DOM描画時に、aタグに変換される

- pタグでは画像を囲えない
↓以下だと、``<p class="img_box"></>``が認識されない。
```
<p class="img_box">
  <Staticimage
    alt=""
    src=""
  />
</p>
```
## パッケージのインストールで役立った記事
npmは使用したことがあったが、yarnは今回が初めて。
下記記事が両者のコマンドを比較しており、役立った。

・npmとyarnのコマンド早見表
https://qiita.com/rubytomato@github/items/1696530bb9fd59aa28d8

インストール、アンインストールコマンドをよく使った。

# gatsby-config.jsは編集しない方が良さげ → そんなことはなかった
ファイルを見ると、google fontsが読み込まれており、font-weight 700のみ指定されていた。
```
{
  resolve: `gatsby-plugin-webfonts`,
  options: {
    fonts: {
      google: [
        {
          family: `Noto Sans JP`,
          variants: [`700`]
        },
        {
          family: `Roboto`,
          variants: [`400`]
        },
      ],
    },
  },
},
```
他のweightも追加したかったので、（下記ドキュメントを参考に）400, 500を追加したところ・・・

https://www.gatsbyjs.com/plugins/gatsby-plugin-webfonts/
```
variants: [`400`, `500`, `700`]
```
ブラウザ側では以下のようなアラートが・・・
![スクリーンショット 2022-03-26 午後10.20.44.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2333112/3d141daf-b8c3-6c0b-a85b-15ff6120c72f.jpeg)

直訳すると
> gatsby-config.jsへの変更を適用するには、開発プログラムを再起動する必要があります。
> 今すぐ開発プロセスを再開しますか？

その後エラーが出て、変更を戻してもエラーが直らなくなった。
``yarn develop``して再度サーバーを立ち上げてもエラーが直らず。

結局、リポジトリを別フォルダにcloneし直して、ファイルを上書きして対応して元に戻すことに。

### 今の仮説
~~gatsby-cofig.jsは編集しないようにした方が良さそう。
・・・しかしドキュメントには``Edit gatsby-config.js``と記載されているのが謎。~~

↓

他のパッケージをインストールしたが、その際はgatsby-cofig.jsを編集してもエラーにならなかった。
この仮説は間違っていた。
編集しても良いし、``gatsby-plugin-webfonts``パッケージに問題がありそう。

## webfontsの実装【結局``gatsby-plugin-webfonts``でうまくいった】
前述の通り、``gatsby-plugin-webfonts``が使われていたものの、新たなfont-weightを追加しようと思うとエラーが出る。

そこで、新しいパッケージをインストールして対応することにした。

↓

いくつか試してみるも500が適用されない

↓

そこでその後、もう一度``gatsby-plugin-webfonts``の設定を追加してみると
```variants: [`400`, `500`, `700`]```

うまく適用された。
以前はなぜエラーが出たか、原因は分からないが結果的にうまくいった。

### 



## スムーススクロール実装
### 【先に結論】↓↓gatsby-plugin-smoothscrollパッケージでは実装できなかった
下記記事を参考に実装
・公式ドキュメント
https://www.gatsbyjs.com/plugins/gatsby-plugin-smoothscroll/

・Gatsby.jsのおすすめプラグインをまとめてみた
https://webcraftlog.net/best-gatsbyjs-plugins/

①``yarn add gatsby-plugin-smoothscroll``でインストール
②gatsby-config.jsに以下を追記
```
plugins: [
  `gatsby-plugin-smoothscroll`
]
```
※ここでローカル環境でアラートが出てヒヤッとしたが、フォントの時とは違いエラーにはならなかった。
しかし、LinkタグでonClick実装ができず断念（アンインストール）
別のパッケージで試してみる
### 【これでも無理だった】react-scrollパッケージ
次にこちらで試してみる。

・react-scroll を導入し超簡単に画面内のスクロールを実装しよう
https://fwywd.com/tech/install-react-scroll

ページ内リンクでのスムーススクロールは実装できた。
だが、他のページからの遷移ができない。
アンインストール。

### 【これで実装できた】react-anchor-link-smooth-scroll
ここで紹介されているプラグインで実装できた。
https://qiita.com/kume_krowl/items/607516e8878ac0653425

ただし、今回の仕様として、「別ページから遷移」 &&　「ページ内遷移」 なので
headerを分ける必要がありそう。
- ページ遷移とページ内遷移を併せ持たせることは出来なさそう
- headerを出し分けする
- 読み込むlayoutを分ける

この通りに進めたら実装できた。
headerの出し分けをしないと、↓この両立は出来なさそう。
> 「別ページから遷移」 &&　「ページ内遷移」

## モーダル実装
■以下の流れで実装
・クリックしたらクラスを追加、削除（つまりtoggle）

Reactの場合、どう書いたら良いか、どこに書いたら良いか全く分からなかったが記事を見て、実装できた。
・【React】onClickでclassNameをつけたり外したりする方法
https://ralacode.com/blog/post/react-toggle-classname/
【UE4】CommandletでTextureのSizeなどのMeta情報を取得出来ない場合の解決策とその原因

# 開発環境
UE4.26.2
Windows10
Visual Studio 2019

# はじめに
この記事の内容はとてもシンプルだが、いざCommandletでAssetの詳細データを取得しようとすると上手くいかず、解決策を探すのに手間取ったので備忘録として記録する
おそらく同じような同士がいると思うので誰かの助けになれば幸い

# 発生した現象
参考先(※1)を元に以下のようなCommandletを追加し

```c++:MyCommandlet.cpp

int32 UMyCommandlet::Main(const FString& CmdLineParams)
{
    TArray<FAssetData>  _AssetList;
    GetAssetList(_AssetList);

    for (auto Asset : _AssetList)
    {
        if (UTexture2D* TmpTexture = Cast<UTexture2D>(Asset.GetAsset())) {
            
            UE_LOG(LogSandbox, Log, TEXT("Texture Size x:%d y:%d"), TmpTexture->GetSizeX(), TmpTexture->GetSizeY());
        }
    }

	return(1);
}
```

そして※1を参考に以下のコマンドで実行してみる
```
{EnginePath}\Engine\Binaries\Win64\UE4Editor-Cmd.exe {Pj Path}Sandbox.uproject -run=My -param=2.0 -stdout -UTF8Output
pause
```

実行した際のLogである"\Saved\Logs\{PJ Name}.log"を開いてみると以下のように、テクスチャサイズが取れないことがわかる

```
[2022.03.21-21.51.02:162][  0]LogSandbox: Texture Size x:0 y:0
[2022.03.21-21.51.02:163][  0]LogSandbox: Texture Size x:0 y:0
[2022.03.21-21.51.02:165][  0]LogSandbox: Texture Size x:0 y:0
[2022.03.21-21.51.02:167][  0]LogSandbox: Texture Size x:0 y:0
[2022.03.21-21.51.02:168][  0]LogSandbox: Texture Size x:0 y:0
[2022.03.21-21.51.02:170][  0]LogSandbox: Texture Size x:0 y:0
...

```

# 発生原因
GetSizeXの中身を確認するとEngineのソースでは以下のようになっており、このPlatformDataがNullであることがわかる


```c++:Texure2D.h
	FORCEINLINE int32 GetSizeX() const
	{
		if (PlatformData)
		{
			return PlatformData->SizeX;
		}
		return 0;
	}
```

### PlatformDataの生成場所
ではなぜNullか？通常のエディタ実行時ではこのPlatformDataが生成されるのはどこなのかをブレイクポイントで追ってみると以下の処理順でCallされるCreateTransient関数内で生成されることが分かった

```
UThumbnailManager::SetupCheckerboardTexture > FImageUtils::CreateCheckerboardTexture > UTexture2D::CreateTransient
```

Commandletではサムネイルを必要としないのでこのままでは生成する大本であるUThumbnailManagerがCallされず、各テクスチャのPlatformDataも生成されないことがわかった

# 解決方法
Commandlet実行時に引数「-allowcommandletrendering」を追加する
以上

### 補足
解決策はとてもシンプル
ヒストリア様の参考リンク(※2)ではデフォルトで記述されているのでそのままコピペして使っていると気づかないが、このallowcommandletrenderingはあらゆるレンダリング系の情報を取得する際に必須になる引数なので常につけておいて良いことがわかった

### 動作確認
前述したコマンドの最後に引数として「-allowcommandletrendering」を追加して実行してみると、以下のLogのようにテクスチャサイズが取得できることが分かった

```
{EnginePath}\Engine\Binaries\Win64\UE4Editor-Cmd.exe {Pj Path}Sandbox.uproject -run=My -param=2.0 -stdout -UTF8Output -allowcommandletrendering
pause
```

```
[2022.03.21-21.54.13:272][  0]LogSandbox: Texture Size x:2048 y:2048
[2022.03.21-21.54.14:390][  0]LogTexture: Display: テクスチャをビルドしています:T_Brick_Clay_Beveled_M (AutoDXT、2048X2048)
[2022.03.21-21.54.14:390][  0]LogSandbox: Texture Size x:2048 y:2048
[2022.03.21-21.54.14:616][  0]LogTexture: Display: テクスチャをビルドしています:T_Brick_Clay_Beveled_N (BC5、2048X2048)
[2022.03.21-21.54.14:616][  0]LogSandbox: Texture Size x:2048 y:2048
[2022.03.21-21.54.15:732][  0]LogTexture: Display: テクスチャをビルドしています:T_Brick_Clay_New_D (AutoDXT、2048X2048)
```


# 参考リンク
(※1) https://qiita.com/unknown_ds/items/e49aa05e142a04a1ee59
(※2) https://historia.co.jp/archives/7343/
「メンタリング入門」を読んだので、その要点

[メンタリング入門 (日経文庫) | 三枝子, 渡辺, 史昭, 平田 |本 | 通販 | Amazon](https://www.amazon.co.jp/dp/4532110939)

<img src="https://images-na.ssl-images-amazon.com/images/I/41SN9sN8ocL._SX283_BO1,204,203,200_.jpg" width=30% />

> メンタリング入門
> 個人的な相談に乗ったり、仕事を上手に進める秘けつを教えたりして、後輩のキャリア形成を支援する「メンタリング」。本書は、メンタリングを実行する「メンター」に対して、その方法論を解説する。メンタリングを受ける人(メンティ)の年齢や性別ごとの接し方から、メンターが陥りやすいジレンマの対処法、企業がメンター制度を導入する際の注意点まで詳しく記述してある。IT業界に特化した内容はないが、若手を育成する立場の人や、後輩との接し方で悩んでいる人には役立つ。

という本。新入社員を迎える季節の足音を聞きながら読む...読書感想文です。


## 感想
- Twitterで良いぞと言われているのを見つけて読みました。
- 2006年の本なのだが、入門書として十分だった。
- リモートワークには触れられていないが、リモートワークにおいて余計メンタリングは大事だと思う。
- メンタリングを受ける側だけでなく、する側にとってのメリットも明文化しているのが良い。メンタリングという活動実績に対する評価の考えなども。


## 要点

### メンター度チェック
- 人の成長を見るのは楽しい
- 人が成長するためには周囲のサポートが大切だと思う
- 会社に誇りを持っている
- 様々な年齢の人と働くのは面白い
- 挫折経験がある
- 相談には親身に乗る
- 若い人の考え方は理解できる
- ビジネス書も読む
- 上司運がよい
- 好奇心が旺盛

### メンタリングとは

- メンターとは、職業という世界において、仕事上の秘訣を教え、コーチし、役割（ロール）モデルとなり、重要な人物への紹介役を果たすなどによって、メンタリングの受け手のキャリア発達を援助する存在
- メンタリング行動とは、その職場での職業経験のある社員のとれる行動のひとつ
- メンタリングは必要な栄養補給
- メンターとは
    - 直接の上司ではない
    - 期間限定
    - いわゆる良い先輩
    - しかし職務の一環
    - 斜め上の上司
    - 少し離れた部署の先輩
    - 管理監督下ではないが、日ごろ接触しやすい場所にいる
- コミュニケーションのひとつ
- 人間は一人ひとり異なり、独自性を持つからこそ協働する
- 組織の人間関係が難しくなっている。世代間など
    - この本は2006年の本で、リモートワークには触れられていないが、リモートワークにおいて余計この要素は強くなっているだろう
- 職場を人の集まりに戻せる

### メンターになるメリット

- 一方、メンターをするメリットもある。
    - 教え方を工夫するようになった
    - 自分の考え方の癖や価値観がわかるようになった
    - 会社や仕事の意義を考えるようになった
    - 言いたいことがどうすれば伝わるか考えるようになった
    - 人の価値観は様々だと理解するようになった
- こんな質問を受けることになる
    - なぜこの会社に入ったか
    - どんなことをやりたいか。なぜやりたいか
    - これまで印象に残っている仕事は
    - 大事にしていることは
    - 目標、理想の人は
    - 会社の良いところ、悪いところは
    - 自分のやりたいことができなければやめてもいいか
    - 仕事に向いていないのだろうか
    - 上司が自分の気持ちを聞いてくれない
    - 何故このような無駄なやり方をしているのか
    - 何故虫のすかない人とも付き合わなければならないのか
    - 上が言っていることと実際の現場は違うようだ
    - 上司は私のことを評価してくれているのだろうか
        - 等など...

### よいメンターになるには

- 良いメンターになるための条件
    - メンターの役割についての正確な理解
    - 他者への関心
    - 人間関係を構築する能力
    - 人と組織についての知識
        - 中途採用や初めて管理職になる人のためにもメンターは必要
    - 他人に関心を持つ
    - 他者のことを思いやる
        - メンタリングのときだけではない
        - 人は皆異なり、ユニークな存在である
    - 放任することを誤解しない
    - メンティーに合った指導ができる
    - 自分の経験や価値観を押しつけない
    - 自分の限界を知って他者に援助をもとめる
    - 聞くは一時の恥聞かぬは一生の恥 を知っている
    - 個人の秘密を守れるということは個人の尊厳を大切にする姿勢、個人の私生活を尊重する態度
        - メンティとの間に人間関係を築くのはメンターである。
        - メンティがより自立してメンターから離れていける関係を目指すこと
    - 対話と観察する力
    - 広く社会にも積極的に自分を開いていくこと。


### メンター自身がキャリアの棚卸しをする。
- ノートなどに自分年表をつくる
- 具体的に思い出してあらためて経験を整理する
- 学生時代に熱中したこと、学んだこと
- 会社へ入社した同期
- 新入社員時代の思い出の出来事
- その経験で得られたこと
- 印象に残っている仕事と理由
- 節目
- 強み、弱み

### 組織がメンター制度を導入するとき

- 組織がメンター制度を導入するときの究極の制度の目的
- 制度としてのメンタリング関係が、いつしか当事者の主体的な意思によって、良好なメンタリング関係として長続きしていく、という状況を作り上げる
- メンタリングという活動実績に対する評価
    - 内的報酬: 満足感、達成感
        - 長期的視点からはこちら
    - 外的報酬: 報奨 


## 参考記事

https://kinokeno.hatenablog.com/entry/2019/07/29/134346

http://hurec.bz/mt/archives/2006/08/187_200601.html


以上です～
【Docker】DBの起動完了を待ってから他のサービスを起動する方法

## はじめに
　本記事は、プログラミング初学者、学習を進めていて疑問に思った点について調べた結果を備忘録も兼ねてまとめたものです。
　そのため、記事の内容に誤りが含まれている可能性があります。ご容赦ください。
　間違いを見つけた方は、お手数ですが、ご指摘いただけますと幸いです。

## DBの起動完了を待ってから他のサービスを起動する方法
### docker-compose.ymlのdepends_on/conditonを設定する方法
以下のように`depends_on`に`condition`service_healthyを設定し、dbの`healthcheck`に`test`を設定することでDBの起動完了後に他のサービスを起動させることができます。
`test`のインターバルがデフォルトでは30秒ほどのようでヘルスチェックに時間がかかるため、`intarval`を`1s`に設定しています。

```docker-compose.yml
version: '${COMPOSE_VER}'
services:
  db:
    platform: linux/x86_64
    image: mysql:${DB_IMAGE_TAG}
    command: --default-authentication-plugin=mysql_native_password && bash -c "chmod +x /docker-entrypoint-initdb.d/00_grant.sh"
    healthcheck:
      test: mysqladmin ping -h db -u$${MYSQL_USER} -p$${MYSQL_PASSWORD}
      interval: 1s
    volumes:
      - mysql_data:/var/lib/mysql
      - ${MY_CNF_PATH}:/etc/mysql/conf.d/my.cnf
      - ${INITDB_PATH}:/docker-entrypoint-initdb.d
    env_file:
      - ${DB_ENV_FILE_PATH}
    ports:
      - "${DB_PORT}:3306"
  api:
    build:
      context: .
      dockerfile: ./docker/api/Dockerfile
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/myapp
    environment:
      RAILS_ENV: ${APP_ENV}
    ports:
      - "${API_PORT}:3000"
    depends_on:
      db:
        condition: service_healthy
volumes:
  mysql_data:

```
2022/3/22主にITとかセキュリティの記事

不正メール８０万件送信か　４県システムに不正アクセス(3/20)
https://www.jiji.com/sp/article?k=2022032000438&g=pol

秋田県情報セキュリティクラウドからの不正メール転送について(3/20)
https://www.city.akita.lg.jp/bosai-kinkyu/1034080.html

2、3月企業へサイバー攻撃急増　ウクライナ侵攻後(3/20)
https://news.goo.ne.jp/article/kyodo_nor/business/kyodo_nor-2022032001000402.html

ＨＰ改ざん被害相次ぐ　企業など情報流出恐れも(3/20)
https://www.yomiuri.co.jp/local/toyama/news/20220319-OYTNT50108/

「iPhone」はウイルスに感染する？ 危険な症状と対策まとめ(3/20)
https://www.lifehacker.jp/article/2203how-to-check-iphone-for-virus-or-malware/

JR西日本偽装したフィッシング確認、注意を - えきねっと装う偽サイトも(3/20)
https://news.mynavi.jp/techplus/article/20220320-2297982/

ロシア当局、ユーチューブも遮断へ　グーグルの広告販売停止に報復か(3/19)
https://news.yahoo.co.jp/articles/2289a067d20a3b44bab5623686d60ba8088626c4

転入届のオンライン化、位置情報や水道料金票を活用へ(3/19)
https://www.nikkei.com/article/DGXZQOUA162YA0W2A210C2000000/

車検証をICカード化　2023年1月1日から(3/20)
https://e-nenpi.com/article/detail/355378

オープンデータとは　無償で利用可能、機械の判読性に差(3/20)
https://www.nikkei.com/article/DGXZQOCA1867Q0Y2A310C2000000/

八戸市役所から25万件スパムメール　青森県「クリックしないで」(3/20)
https://news.goo.ne.jp/article/asahi/region/ASQ3N624QQ3NULUC00P.html

LINE、同意のないデータ利用し広告配信　約1000件で(3/18)
https://www.nikkei.com/article/DGXZQOUC18DEN0Y2A310C2000000/
Proxmox VEで発生した仮想マシンのロックを解除

# 状態

Proxmoxのトラブル（バックアップやマイグレーションの失敗など）時に以下の写真のようにVMやコンテナがロックされることがあります。
![スクリーンショット (439).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1081654/40526bfe-b002-370d-1a84-8af8710494e0.png)

仮想マシンロック時には起動はシャットダウン、削除などの操作ができなくなるためロックを解除する必要があります。

![スクリーンショット (440).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1081654/a98422ba-9eb2-9871-7558-526b62dacde3.png)

## ロックを解除

``` :VMの場合
# qm unlock <VM ID>
```

``` :CTの場合
# pct unlock <CT ID>
```

これで今まで通り利用できるはずです。

# 参考

https://serverfault.com/questions/846356/proxmox-error-backup-of-vm-failed-ct-is-locked-backup
【NestJS】Responseデータの形式をInterceptorでいい感じに変換する方法

# 概要

`APIエンドポイント`から返却されるレスポンスデータの形式を`Interceptor`で変換した

```json
{
  "message": "success",
  "statusCode": 200,
  "errors": ""
}
```

https://docs.nestjs.com/interceptors

# `Interceptor`を定義する

```ts:transform.interceptor.ts
import {Injectable, NestInterceptor, ExecutionContext, CallHandler} from '@nestjs/common';
import {Observable} from 'rxjs';
import {map} from 'rxjs/operators';

// オブジェクトのexport
export const Info = {
    statusCode: 200,
    message: 'success'
}

/**
 * export type 型エイリアスのexport
 * オブジェクトの値のユニオン型を作成
 * typeof xxx &  型定義をマージして返却
 */
export type Response<T> = typeof Info & {
    data: T
}

/**
 * Object.assign で空オブジェクトに指定した形式で代入
 */
@Injectable()
export class TransformInterceptor<T> implements NestInterceptor<T, Response<T>> {
    intercept(context: ExecutionContext, next: CallHandler): Observable<Response<T>> {
        return next.handle().pipe(map(data => Object.assign({}, Info, {data})));
    }
}
```

# 定義した`Interceptor`を`main.ts`で読み込む

> コア関数NestFactoryを使用してNestアプリケーションのインスタンスを生成するアプリケーションのエントリファイルです。

The entry file of the application which uses the core function NestFactory to create a Nest application instance.

https://docs.nestjs.com/first-steps

```ts:main.ts
async function bootstrap() {
    const app = await NestFactory.create(AppModule, {
        logger: loggerFactory.useFactory('warn'),
    })
    app.useGlobalInterceptors(new TransformInterceptor())
}
```
ノーコードでUIButtonを丸くする!!

# はじめに

ある日、Storyboardをイジイジしていたら、ノーコードでUIButtonが丸く出来たので、そのやり方を紹介します。
他のネット記事だと、ほぼ
```swift
layer.cornerRadius
```
で調整するものがほとんどなので、これを機に知って頂ければと思います。
### 1.UIButtonの設置
⌘ + shift + L でショーライブラリを起動、UIButtonを任意の位置に設置します。

![ezgif.com-gif-maker.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2428088/c5282eaa-bd33-9df0-9f5e-eb1447dee08d.gif)

### 2.Autolayoutの設定

任意の位置にconstrainsします。

![ezgif.com-gif-maker (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2428088/ab632c5c-d7a5-3627-e2b1-3abe28062d78.gif)

### 3.Attributes inspectorをイジイジする!!
![スクリーンショット 2022-03-22 2.22.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2428088/5ef0d505-fb39-6838-f8f1-27cf24ae9d0d.png)

ポイントはBackground Configuration内のCorner Styleを[Capsule]にします!!

ただそれだけです!!笑

### 3.さいごに
ビルドしなくてもしっかりUIButtonが丸く表現されているので見た目もイメージしやすいのがメリットだと思います。
以上です。
Jiraで、自分宛のメンションのみをSlackで通知させる(Jira+Slack+Gmail)

## 概要
JiraにはSlack連携機能があり、プロジェクト単位でのチケット変更をチャンネルで通知させることが出来ますが、自分宛のメンションのみをソートしてdmにて通知を飛ばすことが出来ません。

今回はGmailの転送設定をしてSlackでJiraから来たメールを転送することでdmで通知を受け取れるように設定します。

GmailのSlack転送は、Jiraのメンション以外にも重要メールのリマインド等汎用的に使えます。

## 前提
* Slackの有料プランを使用しており、権限が通常メンバー以上(ゲストは不可)

## 手順
1. Jiraのアカウントの通知設定を確認
2. Slackのインテグレーション設定で自分宛のdmのメールアドレスを取得
3. GmailにてJiraから受信したメールを2で取得したメールアドレスに転送させるよう設定

## 1. Jiraのアカウントの通知設定を確認
1. ダッシュボード右上の歯車アイコンから「Jiraの個人設定」をクリック
![スクリーンショット 2022-03-22 1.39.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/899206/bfc67d49-ca1a-7388-dc3b-1839e87522d1.png)

2. 「個人設定」画面から「課題アクティビティのメール通知」が「受け取る」になっていること、「自分がメンションされている」にチェックが入っていることを確認して、保存します。
![スクリーンショット 2022-03-22 1.48.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/899206/ded5f6dd-6693-c268-518b-db964a1e0818.png)
これで、全プロジェクトの自分宛のメンションはメールにて受信できるようになりました。

## 2. Slackのインテグレーション設定で自分宛のdmのメールアドレスを取得
1. 自分のdmのスペース左上のチャンネル名(自分の名前)をクリック
2. 「インテグレーション」タブから「この会話にメールを送信する」をクリック
![スクリーンショット 2022-03-22 2.08.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/899206/4a3b89cb-c7ea-9275-1b5c-1ab58db8f74e.png)

3. 表示されるメールアドレス(ドメインは${SLACK_WORKSPACE_NAME}.slack.com)をコピーする

## 3. GmailにてJiraから受信したメールを2で取得したメールアドレスに転送させるよう設定
1. Gmailのダッシュボード右上の歯車アイコンをクリック=>「全ての設定を表示」をクリックし、設定画面に遷移
2. 「メール転送と POP/IMAP」タブから「転送先アドレスを追加」クリック
3. 　Gmailの転送先アドレスに、先ほどコピーしたSlack通知用メールアドレスを追加
4. 「フィルタとブロック中のアドレス」タブから「新しいフィルタを作成」をクリック
5. from欄に jira@XXX.atlassian.net（JIRAから通知が届くアドレス）を入力し「フィルタを作成」or「続行」クリック
6. 「次のアドレスに転送する」にチェックを入れてSlack通知用のアドレスを選択し、「フィルタを作成」or「フィルタを更新」クリック
【Flutter】Container Widgetまとめ


### 基本的なプロパティ
- margin ：外側の余白
- padding ：内側の余白
- color ：背景色
- width ：横幅(EdgeInsets.only(top:10, left:5)のように個別設定も可能）
- height ：縦幅(〃)
- alignment ：子Widgetの配置場所
- child ：子Widget

```dart
return Container(
      margin: const EdgeInsets.all(10.0), // 外側余白
      padding: const EdgeInsets.all(10.0), // 内側余白
      color: Colors.cyan[500],
      width: double.infinity, // 画面サイズいっぱいまで広げる
      height: 50.0,
      alignment: Alignment.center, // 子Widgetの配置
      child: const Text('Container'),
    );
```

<img　align="center" width="250" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2552610/d2902408-b6bf-99f1-f9c4-bce08a4a95cb.png">

### 枠線（角丸）、角度の変更
- transform ：Containerの角度を変更X,Y,Z軸方向を選択（今回はZ）
- decoration :装飾を行う。colorの指定はここで行う（さっきまで書いていた箇所は削除）
    - border ：枠線の指定
    - borderRadius ：枠線の角丸設定

```dart
return Center(
  child: Container(
    alignment: Alignment.center,
    margin: const EdgeInsets.all(10.0),
    padding: const EdgeInsets.all(10.0),
    width: 100.0,
    height: 50.0,
    child: const Text('Container'),
    transform: Matrix4.rotationZ(0.5), // 角度 　rotationXやrotationYもある
    decoration: BoxDecoration( // Containerの見た目を変える
      color: Colors.cyan[500], // ContainerのColorプロパティと重複できない
      border: Border.all( // 枠線
        color: Colors.red,
        width: 5, // 枠線の太さ
      ),
      borderRadius: BorderRadius.circular(20) // 枠線の角丸
    ),
  ),
);
```
<img　align="center" width="250" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2552610/aaf87366-71cb-58e2-0980-80e8041e8e62.png">

### 完全なる丸
- shape ：BoxShape.circleにすることで完全な丸に
```dart
return Center(
  child: Container(
    alignment: Alignment.center,
    margin: const EdgeInsets.all(10.0),
    padding: const EdgeInsets.all(10.0),
    width: 100.0,
    height: 100.0,
    child: const Text('Container'),
    decoration: BoxDecoration( // Containerの見た目を変える
      color: Colors.cyan[500],
      shape: BoxShape.circle,
    ),
  ),
);
```

<img　align="center" width="250" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2552610/2d51a455-c84f-1102-269e-25386be8e861.png">

### 影をつけて立体感を出す
- boxShadow ：影をつける
   - color:  影の色
   - spreadRadius: 影の大きさ
   - blurRadius: 影の不透明度
   - offset:x軸、y軸をどれだけずらすか

```dart
return Center(
  child: Container(
    alignment: Alignment.center,
    margin: const EdgeInsets.all(10.0),
    padding: const EdgeInsets.all(10.0),
    width: 100.0,
    height: 100.0,
    child: const Text('Container'),
    decoration: BoxDecoration( // Containerの見た目を変える
        color: Colors.cyan[500],
        shape: BoxShape.circle,
        boxShadow: const [
          BoxShadow(
            color: Colors.black26, // 影の色
            spreadRadius: 1.0, // 影の大きさ
            blurRadius: 10.0, // 影の不透明度
            offset: Offset(10, 10), // x軸、y軸をどれだけずらすか
          ),
        ]
    ),
  ),
);
```

<img　align="center" width="250" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2552610/180ce1dc-bb87-24ae-2389-9a8a5cbce93b.png">
PyMuPDF を用いて印刷用の PDF を作成

[PyMuPDF](https://pymupdf.readthedocs.io/en/latest/module.html) を用いて PDF の並びを変更して仕上がり A5 版の自作本を印刷するための PDF を作成した。

### A5 縦で元の PDF を作成

LaTeX で組版する場合は以下のように記述。

```TeX
\documentclass{jsarticle}

\usepackage{geometry}
\pdfpageheight=210mm
\pdfpagewidth=148mm
    ：
\begin{document}
    ：
    ：
\end{document}
```

### 印刷用の PDF を作成

以下を実行すると **imposition.pdf** が作成される。サイズが大きくなるので印刷後は削除した方が良い。**blankA5.pdf** は「A5 縦」の空白ページでこのスクリプトと同じディレクトリに配置する。
「A6 縦」の原稿にも対応させた。

```python
# -*- coding: utf-8 -*-

import os, sys
import fitz

def imposit_A5(infile):

    blank  = fitz.open(os.path.join(os.path.dirname(__file__), 'blankA5.pdf'))
    page_count = infile.page_count
    page_max   = int((page_count + 3) / 4) * 4

    doc = fitz.open()
    j = 0
    for i in range(page_max):
        mod = i % 4
        if   mod == 0: k = j
        elif mod == 1: k = j + 2
        elif mod == 2: k = j + 3
        elif mod == 3: k = j + 1; j += 4
        if k >= page_count:
            doc.insert_pdf(blank)
        else:
            doc.insert_pdf(infile, from_page = k, to_page = k)

    doc.save('imposition.pdf')

def imposit_A6(infile):

    blank  = fitz.open(os.path.join(os.path.dirname(__file__), 'blankA6.pdf'))
    page_count = infile.page_count
    page_max   = int((page_count + 7) / 8) * 8

    doc = fitz.open()
    j = 0
    for i in range(page_max):
        mod = i % 8
        if   mod == 0: k = j
        elif mod == 1: k = j + 2
        elif mod == 2: k = j + 4
        elif mod == 3: k = j + 6
        elif mod == 4: k = j + 5
        elif mod == 5: k = j + 7
        elif mod == 6: k = j + 1
        elif mod == 7: k = j + 3; j += 8
        if k >= page_count:
            doc.insert_pdf(blank)
        elif mod < 4:
            doc.insert_pdf(infile, from_page = k, to_page = k)
        else:
            doc.insert_pdf(infile, from_page = k, to_page = k, rotate = 180)

    doc.save('imposition.pdf')

def main(src):

    infile = fitz.open(src)
    width = int(infile[0].rect.width * 25.4 / 72)
    if width == 105:
        imposit_A6(infile)
    elif width == 148:
        imposit_A5(infile)
    else:
        sys.exit(f'{src} is A5 nor A6.')    

if __name__ == "__main__":

    main(sys.argv[1])
```

### 印刷・裁断・製本

~~Adbe Acrobat Reader の印刷用のフォームで以下のように設定。~~
両面印刷して中央で裁断して並べ替える。製本は例えば[この動画](https://www.youtube.com/watch?v=MzBXhUXfiXQ)を参考に行う。
![prn_acrobat.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233450/1f4b5751-a691-4aa4-996d-3a5d6ee89a89.png)

#### 訂　正
Adbe Acrobat Reader の面付けではマージン（上図の「ページ境界線」）が加わり原稿の版面が維持されないことが分かった。そこで、一手間増えるが、次の [PDFMate Free PDF Merger](https://www.pdfmate.com/free-pdf-merger.html) を用いて A4 サイズの PDF に集約することにした。
![PDFMate.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233450/e2006d96-6169-72c9-28ae-0b3f16304fd1.png)
curlコマンド備忘録 ※随時更新

# 1. はじめに
本記事では、Linuxの標準コマンドでもある『curl』コマンドのチートシート（と言う名の個人的備忘録）を記載します。

# 2. curlコマンドとは
## 2.1 curlコマンドの概要
curl は URL 指定でデータを受信（もしくは送信）するためのコマンドラインツールです。

Linuxでよく使用されるコマンドで、組み込みコマンドでもあります。
また、最近になって Windows 10 でも標準で組み込まれるようになりました。
最新版のWindows10であればコマンドプロンプトに「curl」と打ち込むことで利用できます。

## 2.2 基本書式
curlコマンドの基本書式は以下の通りとなります。

```
curl [オプション] [URL]
```

## 2.3 オプション一覧
curlコマンドで良く使用されるオプションを以下に記載します。

| オプション | 説明 |
| -- | -- |
|-d, –data PARAM|POSTリクエストとしてフォームを送信する|
|-i, –include|出力結果にHTTPヘッダーを含める|
|-s, –silent|進捗情報やエラーを出力しない|
|-u USER[:PASS]|プロキシ認証等に用いるユーザー名USER, パスワードPASSを指定する|
|-x HOST[:PORT]|プロキシサーバでのホストHOSTおよびポートPORTを指定|
|-I, –head|ヘッダーを取得する|
|-v, –verbose|処理の細かい情報(進捗情報等..)を出力する|
|-L, –location|リクエスト先にリダイレクト設定がある場合に追従する|

- 詳細なオプション
http://www.mit.edu/afs.new/sipb/user/ssen/src/curl-7.11.1/docs/curl.htm

# 3. 利用ケース
実務でよく使われるcurlコマンドの利用パターンを下記に記載します。

## 3.1 基本パターン
```
# オプション無し
$ curl https://<URL>

# URLをファイル名としてダウンロード
$ curl -O https://<URL>

# 実行結果をファイルへ出力
$ curl https://<URL> > <出力先ファイル>
$ curl -o <出力先ファイル> https://<URL>

# ファイル出力時の進捗状況を非表示にする(エラーも非表示)
$ curl -s -o 出力先PATH http://対象のURL
```

## 3.2 出力を指定する
```
# HTTPメソッドを指定
# HTTPメソッドについて → https://masa-enjoy.com/http-method-postput#toc6
$ curl -X PUT https://<URL>

# HTTPレスポンスヘッダーを取得
$ curl -I https://<URL>

# リクエストヘッダやレスポンスヘッダを表示する
# 「>」= リクエストヘッダ, 「<」= レスポンスヘッダ
$ curl -v https://<URL>
> GET /foo/ HTTP/1.1
～～略～～
< HTTP/1.1 302 Found
```

## 3.3 経路操作
```
# プロキシを経由する
$ curl -x <プロキシサーバ>:<ポート番号> --proxy-user <ユーザ名>:<パスワード> https://<URL>

# リダイレクトを有効にする
$ curl -L https://<URL>

# SSLのエラーを無視して処理を実行する
$ curl -k https://<URL>
```

## 3.4 認証操作
```
# basic認証
$ curl -user <USERID>:<PASSWORD> https://<URL>

# NTLM認証またはDigest認証
$ curl --anyauth --user <USERID>:<PASSWORD> https://<URL>
```

## 3.5 小技
```
# F5アタック
$ while :; do curl -s 'http://<URL>' >/dev/null; done

# 404や200などHTTPステータスコードだけを取得する
$ curl -Ss -w '%{http_code}\n' 'https://<URL>' -o /dev/null

# REST API を叩いて結果だけを確認する
$ curl -fsL https://<URL>
```

# 4. 参考
- [Qiita - よく使うcurlコマンドのオプション](https://qiita.com/ryuichi1208/items/e4e1b27ff7d54a66dcd9)
- [Qiita - よく使うcurlコマンドのオプションまとめ（14個）](https://qiita.com/shtnkgm/items/45b4cd274fa813d29539)
- [curl コマンド](https://hydrocul.github.io/wiki/commands/curl.html)
- [逆引きcurlコマンドのオプション一覧](https://www.setouchino.cloud/blogs/99#post-x-post-d)
[Python] delikaにアクセスしてデータをPandas DataFrameにするまで。

# はじめに

なにやらキャンペーンを行っているみたいなので、まずはPythonでデータを取り出すところまでを調べてみた。

https://qiita.com/official-events/30be12dd14c0aad2c1c2

## delika?

公式にはこのように書かれています。

"delika" is a data sharing and analysis platform for people involved in data. You can host your data and leverage your analysis with any data shared on the platform.

>"delika "は、データに関わる人々のためのデータ共有・分析プラットフォームです。プラットフォーム上で共有されているあらゆるデータをホスティングし、分析を活用することができます。

https://delika.io/welcome

データのGithubを目指す！ということなので、応援したいと思います。

## 対象のデータはこちら。

https://delika.io/connecto-data/ds-skills

データサイエンティスト スキルチェックリスト ver3.01

一般社団法人データサイエンティスト協会 スキルチェックリストより引用

**データ出典**

https://github.com/The-Japan-DataScientist-Society/skills-checklist

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80467/9096962e-1261-c6ed-af62-c3bd7c0f47af.png)

## Requirements

**Python 3.7+**

[ライブラリのドキュメントはこちら。](https://docs.delika.io/python/)

https://docs.delika.io/python/

## 作業開始

Pythonのライブラリが用意してあるので、取得したいデータセットが決まったら簡単に取得できます。

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

まずはライブラリをインストールします。

環境に応じてどちらかを実行してください。私は新しい環境を作成して、下のコードを実行してみました。

```python
# delikaのclientのみ
pip install --extra-index-url=https://docs.delika.io/python/ delika

# delikaのclientとPandas他、必要なパッケージ
pip install --extra-index-url=https://docs.delika.io/python/ delika[DataFrame]
```

### JWTの取得

```python
token = delika.new_token(host= "https://api.delika.io/v1", open_browser = "true")
```

実行すると、ログイン画面になり、ログインに成功するとJWTの取得ができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80467/cc6f39f4-f2bc-1fec-629e-3527c2c30b29.png)

一度`save`メソッドを実行しておくと、しばらくJWTの取得は不要です。
保存したJWTをロードして`client`変数にいれます。
```python
token.save()
client = delika.load_client()
```

### DataFrameで取得

`delika.pandas.read_delika_data`メソッドを使用して、データを`Dataframe`として取得します。

```python
# データフレームで取得
df1 = delika.pandas.read_delika_data(account_name="connecto-data", dataset_name="ds-skills", data_name="biz.csv", client= client)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80467/673d03c0-028b-63a5-a521-b601880b1e0d.png)

### 結果

無事取得できています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80467/4d486de8-2ed4-8ab8-230e-38ef5fdf6c28.png)

## まとめ

簡単にPythonで取得ができました。自分の手元のデータをアップするモジュールも用意されていて、オープンデータと掛け合わせて新しい発見をする・・ということが増えてきたら嬉しい。次回はこのデータを使用してテキストアナリティクスにチャレンジしてみようと思います。
がんばってEventBusがイベントを複数回発火させてしまうのを食い止める

### どうしてこの記事を書くことになったのか

ページ送り機能があるアプリの中で、共通ヘッダーのコンポーネントにあるページ送りボタンから、コンテンツ部分のコンポーネントにあるページ送り+APIを呼ぶメソッドを叩く実装がありました。
そこで、以下のような事象が発生しました

- APIが複数回飛んでいる
- ページも二つ先、三つ先のページに飛んでしまう

なんでこうなっちゃうの！　というのを解消した記録です。
なお、ここで触れているEventBusはVue3.x系では消滅しました。

### 前提
- node.js v14.15.5
- vue.js v2.6.12
- vue/cli 4.5.7

<details><summary>コード（ざっくり）</summary>

```vue:app.vue
<template>
  <Header />
  <Content />
</template>

<script>
  import Header ...
  import Content ...
```

```vue:header.vue
<template>
  <button @click="prev"></button>
  <button @click="next"></button>
</template>

<script>
  method: {
    prev():{ EventBus.$emit('prev'); }
    next():{ EventBus.$emit('next'); }
</script>

```

```javascript:content.vue
method: {
  created() {
    EventBus.$on('prev'); // 前のページへ行くイベントのリスナー
    EventBus.$on('next'); // 次のページへ行くイベントのリスナー
    this.getData();
  },
  prev(): {
    // postAPIを叩く処理
    this.$router.push(prev);
  },
  next(): { 
    // postAPIを叩く処理
    this.$router.push(next);
    
  },
  getData(): { // getAPIを叩く処理 },
},
watch: {
  $route: { this.getDate(); },
}

```

</details>

## 原因調査
日本語で検索しても情報が少なそうだったので、`EventBus dupulicate`とかで検索してました。
引っかかったのがこのStack Overflow。

https://stackoverflow.com/questions/41879836/vue-js-method-called-multiple-times-using-emit-and-on-when-it-should-only-be-c

他にも似たような質問はいくつかあり、EventBusを使うとまあまあ起こる現象のようです。
こちらをもとに検証してみたところ、今回私が直面した事象は、**前のページのコンポーネントのイベントリスナーが生きていて、そちらでもメソッドが実行されている**ということのようでした。


## 解消方法

結論としては、以下の4行をコンテンツ部分のコンポーネントに入れて解消しました。
コンポーネントが破棄される直前にEventBusのイベントリッスンを止めるようにする、ということですね。

```javascript
  beforeDestroy() {
    EventBus.$off('prev'); // 前のページへ行くイベントのリスナー
    EventBus.$off('next'); // 次のページへ行くイベントのリスナー
  },
```

## 原因の原因調査

というわけで解消はしたわけですが、疑問は残ります。
コンポーネントってページ送りごとに破棄されてるんじゃないの…？（実装上は画面パスが変わったときにgetAPIを叩いて表示データを上書きしている状態だが、beforeDestroyの時に`$off`して解決しておりページ送りをした際にdestroyとcreatedはされている）

という疑問に解消してくれるのが以下の記事でした。（上記StackOverflowのコメントの中に紹介がありましたが、元のリンクは切れているようなので、Internet Archiveに残っていたものへのリンクを貼ります。）

https://web.archive.org/web/20201126101113/https://charlietheprogrammer.com/duplicate-vue-event-listeners-and-how-i-solved-them

こちらの記事によれば、
- イベントバスのリスナーはグローバルに管理されているので、コンポーネントが作成されるたびに新しいリスナーが増えてしまう
- それぞれのリスナーはイベントが発火したときに、元のコンポーネントを再生成する。（読解に自信なし…状況的には合ってると思いますが）
- 複数回実行を避けるためには、コンポーネントが破棄されるときに手動でイベントリスナーも破棄する必要がある
- Vueの設計上、他のコンポーネントの状態は知ることができないのが基本なので、それを無理やりどうにかするような実装はやめよう

とのことです。
コンポーネントが破棄されたときにイベントリスナーが破棄されない疑問が解消されました。
ちょっとEventBusの使い方を学んだだけでこの仕様を理解するのは無理があるように思いますが、そもそもEventBusを使うこと自体がVueの設計思想上のイレギュラーであると思うとやむなしのように思います。
（Vue3.x系で消されたのも納得…）

## まとめ

- EventBusのリスナーはグローバルに管理されているので、コンポーネントを破棄しただけでは破棄されず、手動で破棄する必要がある
- 忘れずに`EventBus.$off('hoge')`
- 賢い人「最初からVuexを使って実装すればよかったのでは？」　その通りだと思います…
JavaScript環境構築まわりの用語

## Node.js

**Node.jsは、JavaScriptの実行環境のこと。**


Node.jsはサーバーサイドのプログラミング言語だと思われることが有るが、これは間違い。
プログラミング言語であるJavaScriptを、サーバーサイドでも実行できるようにするのがNode.js。
そして現在では、フロントエンドの開発環境としても広く使われている。
詳しくは↓の記事様がわかりやすい。

https://qiita.com/non_cal/items/a8fee0b7ad96e67713eb

　

## npm

**npmは、Node.jsのパッケージ管理ツールのこと。**
phpで言うところのcomposer、Pythonで言うところのpip。

npmにおけるパッケージとは、JavaScript のライブラリやフレームワークのこと。
ReactやVue.jsもnpmを利用してインストールできる。
詳しくは↓の記事がわかりやすい

https://reffect.co.jp/html/npm-package-manager-basic-for-beginner

　


## nvm、nodebrew、nodist...

**nvm、nodebrew、nodistは、いずれもNode.jsのバージョン管理ツールのこと。**

バージョン管理ツールを使用することで、Node.jsのバージョンを新しくしたり、過去のバージョンに戻したり、プロジェクトごとにバージョンを切り替えたり、といったことが可能になる。

nodebrewはMac用。nodistはwindows用。nvmはMac用とWindows用（nvm for windows）。
上記３つの他にも沢山ある。
※なお、nodistは更新が止まっており不具合が出やすいらしいので、他を使用したほうがよさそう。
そのあたりも含めて詳しくは↓の記事様がわかりやすい。

https://qiita.com/heppokofrontend/items/5c4cc738c5239f4afe02

　

## webpack

**webpackは、モジュールをまとめるためのツールのこと。**

ここで言うモジュールとは、jsファイルやhtmlファイル、sass(css)ファイル、画像などのこと。
webpackを使うことで複雑なプロジェクトの管理・保守・分担などがしやすくなり効率が上がる。

なぜwebpackを使うのかの具体的な話は↓の記事様がわかりやすい。

https://crudzoo.com/blog/js-dev
macOS Big Surで「その他」のストレージを減らしたい時

# 環境
- M1 macbook Air
- Big Sur(後述しますが、Montereyにアプデしたため、バージョンは正確に覚えていません)

# 要約
- 「その他」のデータが非常に大きい人は、Dockerのリソース設定を見直すと解決するかもしれません。Preferences->Resources->Disk image sizeを減らすと良いです。

# はじめに
ストレージが逼迫してきたので、必要ないデータを削除しようとした。「その他」のデータがおよそ100GBほど存在しているが、容量が大きいデータがどこにあるかがよくわからなかった。
ググると、`~/Library/Caches/`にあるキャッシュを減らすと解決する場合があるようだが、私の環境だと数GBしかなかった。

# やったこと
別件でMontereyに更新する必要があったので、更新した。すると、「その他」のデータのうち、数十GBが「書類」に分別されており、調べるとDockerのrawファイルサイズが非常に大きいことがわかった。
ググると、Docker for Macでよくある問題らしい。[参考](https://www.kageori.com/2020/01/docker-for-mac.html)
Dockerで使用するディスクサイズを減らすと、ストレージの空き容量を増やすことができた。

# まとめ
「その他」のデータがストレージを多く占める場合、OSをアップデートしてみると、解決の糸口が見つかるかもしれません。今回だと、Docker周りの設定が原因でした。
また、よく使うソフトウェアの設定は定期的に見直すべきだと思いました。
おしまい
TermuxでC言語を書く 2022

AndroidでC言語書きたいですよね．
やりましょう．

:::note warn
注意
この記事は**Termux**と呼ばれる環境でどうしてもC言語を書きたい~~変態の~~方向けの記事です．
AndroidでC言語を書くだけであれば，[Mobile C](https://play.google.com/store/apps/details?id=com.dztall.ccr.android.admob&hl=en&gl=US)などを使う方が良いと思います．
:::

# Termuxのインストール
まず，**Playストアのものは選ばないようにしましょう**．Playストアにあるものは更新がされていません[^1]．

インストールは，F-Droid経由か，直接APKを用いて行います．

F-Droid:

https://f-droid.org/en/packages/com.termux/

直接APKから

https://github.com/termux/termux-app/releases/tag/v0.118.0

# Repositoryの変更
このあと直接`pkg install gcc clang`してもよいのですが，初期状態ではいろいろ足りずに(実行に)失敗します．Grimler repoへ変更し，必要なパッケージを入れます．
しかし，2022年3月現在，GrimlerさんがGPGキーを変更した関係で，素直に`termux-change-repo`しても失敗する現状にあります．失敗せずにGrimler repoへ変更する方法は下記をご覧ください．

https://qiita.com/BonyChops/items/3951a122c6190f400d90

# 開発環境を入れる
あとは好きなコンパイラ・エディタを入れましょう．エディタに関してはPlayストアから適当なエディタを選ぶという手もありますし，おなじみのVim，Emacs，Nano等を入れることもできます．よくわからない方は，下記を実行してください．

```
pkg install nano clang
```

# 実際に書いてみる
ここからはnanoとclangの環境である前提で進めていきます．

```
nano hello.c
```

そしたら，下記を書きます．

```hello.c
#include <stdio.h>

int main(){
    puts("Hello C on Termux!");

    return 0;
}
```

`Ctrl + X` → `Y` → `Enter` で保存．

次に，コンパイルの実行．

```
clang hello.c
```

そして実行．
```
./a.out
```

```結果.
Hello C on Termux!
```


[^1]: https://wiki.termux.com/wiki/Termux_Google_Play
Tomcat8.5以上へバージョンアップ

1年前ほどに、Tomcatを8.0.Xから9.Xへバージョンアップした。
その際に、困った点を記載しておく。

# UMASKのデフォルト設定変更
## 内容
8.5.XからUMASKの設定値が0027となっている。
そのため、アプリから作成したファイルが他ユーザから見えなくなった。

## 原因
catalina.shにてUMASK設定をするようになっている。
以下抜粋

```sh
# Set UMASK unless it has been overridden
if [ -z "$UMASK" ]; then
    UMASK="0027"
fi
umask $UMASK

# Java 9 no longer supports the java.endorsed.dirs
# system property. Only try to use it if
# JAVA_ENDORSED_DIRS was explicitly set
# or CATALINA_HOME/endorsed exists.
ENDORSED_PROP=ignore.endorsed.dirs
if [ -n "$JAVA_ENDORSED_DIRS" ]; then
    ENDORSED_PROP=java.endorsed.dirs
fi
if [ -d "$CATALINA_HOME/endorsed" ]; then
    ENDORSED_PROP=java.endorsed.dirs
fi

# Make the umask available when using the org.apache.catalina.security.SecurityListener
JAVA_OPTS="$JAVA_OPTS -Dorg.apache.catalina.security.SecurityListener.UMASK=`umask`"
```

## 対応
シェルをいると、UMASKが設定されている場合、その値を利用するとあるので、UMASKを設定するとよい。
```sh
export  UMASK="0022"
```