OmniAICreator/Qiita-1.07M huggingface dataset:
インターネットが遅いという既に自己解決した質問を書いてみる

# なんだかもったいないので、そのまま投稿してみます

質問としてはまだ完了形ではありません

## 解決方法

1.1.1.1 のDNSのレスポンス速度が異常に低下していることが判明したので
とりあえず、8.8.8.8 に変更


# 以下本文


## このような質問で大変申し訳ありません。

とりわけインターネットが遅くなりました。
しかし、これに回答できるのは技術者系でなければできないと思いますので、
こちらで質問させていただきます。

利用環境がすごいことになっていますので確認していただければ。。。。

## 利用環境

- 1本の光ファイバー（フレッツ光 PPPoE）で2つのISPに加入（V4接続のみ）
- fast.comの調査によれば十分に400Mbps以上出ている（サブISPは安価なので70Mbpsぐらい）
- 明らかに自作DNSがおかしい？

### 症状

構築当初は十分すぎるレスポンス速度であったが
定期的に手動で pkg update&upgradeや apt update&upgradeを手動で行っているが、いつしかから徐々にDNSの応答が遅くなった

ルーターマシン自体、rpi、ただのONUと化したNTTのルーターを再起動しても症状が改善されない

該当する重いサイトはDNS解決だけでなくSSL確立も遅くなっている

#### 一例として重いサイト
- *.yahoo.co.jp
- www.topvalu.net、www.aeon.info （www.aeon.co.jp、shop.aeon.comは重くないです）
- www.shufoo.net (応答は早いがチラシの表示が遅くなった）

### 自作DNSの仕様

ルーターのDHCP、DNSが低機能すぎてルーターのDHCP、DNSを停止し、下記に置き換えています

#### LAN1-ルーター (ISP1)
- Aterm WX3600HP (※注：2.5GBE搭載していますが、家庭内乱速度向上用に利用）
- ISP Interlink (PPPOE IPV4)

#### LAN1-rpi4（プライマリ）
- OS FreeBSD
- Gigabit LANポート2つ（USB-LAN増設）
- 上記のLANポート2つ用にunboundをrunitで多重起動
- nsdをLAN1用のみ起動
- その他 nginx、Apache

#### LAN2-ルーター (ISP2)
- ELECOM WRC-1167GEBK-S
- ISP excite ワンコイン(PPPOE IPV4)

#### rpi2（セカンダリ）
- OS raspi-os
- 100M LANポート2つ（USB-LAN増設）
- 上記のLANポート2つ用にunboundをrunitで多重起動
- nsdをLAN1用のみ起動
- その他 isc-dhcpd、ntpd

#### unbound.conf

必要と思われそうな部分のみ抜粋しました

```unbound.conf
forward-zone:
        name: "."
        forward-addr: 1.1.1.1
        forward-addr: 9.9.9.9
        forward-addr: 8.8.8.8

stub-zone:
        name: "example.com"
        stub-addr: 192.168.0.201

stub-zone:
        name: "example.com"
        stub-addr: 192.168.0.201

forward-zone:
        name: "flets-east.jp"
        forward-addr: 192.168.0.253
        forward-addr: 2408:211:83ac:4a00:124b:46ff:fee6:b10

/*
 * 注：
 * プライマリDNSの末尾IPは1
 * セカンダリDNSの末尾IPは2
 * プライマリDNSのstub IPの末尾IPは201
 * ONUの末尾IPは254
 * ルーターの末尾IPは253
*/
```

家庭内乱としては特殊な事例だと思います。
このようなサポートをみかかに投げてもやここのルーターを使ってください、とか
プロバイダーに投げてもサポート済のルーターを使ってくださいって
終わりだと思います
【Laravel8】view composerを活用して、HeaderやSidenaviにデータを渡そう

## やりたいこと

HeaderやSidenaviのような共通レイアウトに、
データを渡したい時ってありますよね。

そんな時に使えるのが「View Composer」です。
今回は、View Composerを使って、Headerに現在の会員登録数を表示してみましょう。

## View Composerとは

ビューコンポーザは、ビューをレンダーするときに呼び出すコールバックまたはクラスメソッドです。ビューをレンダーするたびにビューへ結合するデータがある場合、ビューコンポーザを使用すると、そのロジックを１つの場所に集約できます。ビューコンポーザは、アプリケーション内の複数のルートかコントローラが同じビューを返し、常に特定のデータが必要な場合にきわめて役立ちます。
（参照：https://readouble.com/laravel/8.x/ja/views.html?header=%25E3%2583%2593%25E3%2583%25A5%25E3%2583%25BC%25E3%2582%25B3%25E3%2583%25B3%25E3%2583%259D%25E3%2583%25BC%25E3%2582%25B6）

## View Composerの作り方

### 1. ServiceProviderを作る

```
php artisan make:provider ViewServiceProvider
```
artisanコマンドを叩いて、ServiceProviderを作りましょう。

```
<?php

namespace App\Providers;

use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;

class ViewServiceProvider extends ServiceProvider
{
    public function boot()
    {
        //
    }

    public function register()
    {
        //
    }
}
```

### 2. config/app.php に追加する

```
'providers' => [
    ...
    App\Providers\ViewServiceProvider::class,
    ],
```

### 3. Composer を作る

手動でファイルを作ります。
`App\Http\View\Composers\ViewComposer.php`

```
<?php

namespace App\Http\View\Composers;

use App\Models\User;
use Illuminate\View\View;

class ViewComposer
{
    protected $users;

    public function __construct()
    {
        $this->users = User::all();
    }

    public function compose(View $view)
    {
        $view->with('total_users', $this->users->count());
    }
}
```

### 4. ViewComposerに追記する

```
public function boot()
{
    public function boot()
    {
        View::composers([
            ViewComposer::class    => 'layouts.*',
        ]);

        View::composer(
            ['layouts.header'],
            'App\Http\View\Composers\ViewComposer'
        );
    }
}
```

`View::composers`で、layoutsに表示させられるように宣言します。
`View::composer`には、表示させたいファイル名を指定します。

### 5. headerに記載する

`app\resources\views\layouts\header.blade.php`
```
<p>{{ $total_users }}</p>
```

Header内に、3で指定した`total_users`を記載すると、データが反映されます。

## 備考：ログイン済みユーザーのみ表示させたい時

`Auth::user()`を使って、ログイン有無を確認してデータを渡しましょう。
`use Illuminate\Support\Facades\Auth;`の指定を忘れずに。

```
<?php

namespace App\Http\View\Composers;

use App\Models\User;
use Illuminate\View\View;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;

class ViewComposer
{
  protected $users;

  public function __construct()
  {

    if (Auth::user()) {
      $this->users = User::all();
    }
  }

  public function compose(View $view)
  {
    if (Auth::user()) {
      $view->with('total_users', $this->users->count());
    }
  }
}

```

以上、ViewComposerを使った、共通レイアウトにデータを渡す方法でした。
【WWDC22】SKAdNetwork 4.0での変更点について


## いつリリース？

- 2022年後半

## 変更ポイント

## **Hierarchical source identifiers**
- 階層化ソースID
- 閾値以上のインストールボリュームがあれば、2桁 → **4桁に拡張**されるようになった
- 旧Campaign ID
- つまり、より多くの情報を送ることが出来る
    
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681323/53ce8ffe-d795-b646-9b2c-5368cec15a18.png)
    

## 2種のConversion値
- 「細かい粒度」 と 「荒い粒度」
    - 「細かい粒度」
        - 現在と同じ
        - 0から64
    - 「荒い粒度」
        - ３つの段階がある（heigh / mid? / low?）
        → Lowであれば、少ないインストール数でもポストバックを受け取れる？

広告主アプリでの実装例
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681323/d16bede3-7411-6cc6-e656-5a6b3151cae3.png)


## **Multiple conversions（マルチコンバージョン）**

- 最大**3つのポストバックを受信**できるようになる
- ３つのウィンドウ
    1. 0日から2日
    2. 3日から7日
    3. 8日から35日
    
    ※ ただし**2番と3番目は閾値を超えた場合のみ送信される**

![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681323/6b4773ee-dc4c-a7f5-f0e1-ca933b9b9aba.png)

- 考慮ポイント
    - 最初のポストバックのみが、完全なCV値を取得可能
    - 追加のポストバックは、粒度の粗いCV値
    - 追加のポストバックは、ラストタッチのADNWと開発者のみ

## **Web広告対応**
- SKAがウェブ広告に対応（Safariのみ？）
- フロー
    1. ユーザーは「Safari」で広告のリンクをタップ
    2. SafariがAppStoreを起動
    3. アプリのストアページにアクセス
    4. App Storeは、ADNWから広告インプレッションを取得
    5. ユーザーがアプリをインストール
    6. SKAdNetworkがADNWにポストバックを送信

![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681323/5a19b70c-ec08-1cd6-a50d-50f386138dff.png)
    
- リンクタグ
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681323/30ef3f20-a049-b2c9-2d3e-806ca1516d4e.png)
        
    - `href`
        - 広告主アプリのストアリンク
    - `attributeDestination`
        - 広告インプレッションを取得するURL（Apple→ADNW）
        ![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681323/8dd410bc-afea-f0df-22ec-567eb585c840.png)        
    - `attributionSourceNonce`
        - ADNW側で広告インプレッションを特定するために使う？
    
- ADNW側での応答
    - POST Body
    ![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681323/2eeadf5a-e3f8-f756-f0f3-327d4de06c76.png)    
    - Response
    ![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681323/3a334af8-329a-8eb3-699f-4bf29d7723d9.png)


## 参考
- [What's new with SKAdNetwork - WWDC22 - Videos - Apple Developer](https://developer.apple.com/wwdc22/10038)
金食い虫のglueエンドポイントの監視の仕組みを作った話 

### AWS Glueを使う理由
Glueとは、ETLジョブの開発を行うための仕組みのことです。

大規模なデータ処理や抽出を行いたい時に使うのがSparkというフレームワーク。
弊社では過去取引の動向を分析するデータセットを作るときによく利用します。

Spark実行時には、Glueの開発エンドポイントを立ち上げる必要があります。

### AWS Glueは金食い虫
Sparkの実行終了時には、Glueの開発エンドポイントを切る必要があります。
使わなくなったら自動で消してくれるわけではありません。（SageMakerのNotebook Instanceと同じ）

もし停止し忘れると、1日で約7,000円かかります....！
（5個のDPUを24時間利用した場合。5 * 0.44 * 24 * 130（円））
[AWS Glueの料金](https://aws.amazon.com/jp/glue/pricing/)
> 開発エンドポイントのプロビジョニング時には、5 個の DPU が割り当てられます。開発エンドポイントを 24 分 (5 分の 2 時間) 実行すると、DPU 時間あたり 0.44 USD で 5 DPU * 2/5 時間、つまり 0.88 USD が請求されます。

### ミスを見越して、監視・停止できる機能を作った
毎回ちゃんと停止することを覚えよう！と思うのは得策ではありません。
lambdaを活用して、開発エンドポイントの消し忘れを防げるようにしました。

監視機能の概要
* 環境内のGlue開発エンドポイントと起動時間を定期的にチェックする
* 指定した時間以上起動していた場合、停止する

＜簡易なアーキテクチャー図＞
![architecture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405031/d3e23d82-c128-4f02-edc4-cad30e74969c.png)

### 実装内容
Boto3というライブラリを使って、Glueの開発エンドポイントを取得・停止できるようにしました。

```python:.py
import json
import boto3
from logging import getLogger
import datetime

MAX_TIME = 60 * 60 * 2

def lambda_handler(event, context):
    logger = getLogger(__name__)
    endpoints = get_glue_endpoints()
    now_datetime = datetime.datetime.now(datetime.timezone.utc)
    logger.info("endpoints exists -> {}".format(len(endpoints)))
    longtime_endpoints = [e for e in endpoints if (now_datetime - e['CreatedTimestamp']).total_seconds() > MAX_TIME]
    if longtime_endpoints:
        logger.info("longtime endpoints -> {}".format(longtime_endpoints))
        for e in longtime_endpoints:
            logger.info(delete_glue_endpoints(e['EndpointName']))
        return "{} Endpoints deleted".format(len(longtime_endpoints))
    return "No Endpoints detected"
    
def get_glue_endpoints():
    logger = getLogger(__name__)
    logger.info("get glue client")
    cli = boto3.client('glue')
    endpoints = cli.get_dev_endpoints()['DevEndpoints']
    logger.info("Glue Endpoint -> {}".format(endpoints))
    return endpoints
    
def delete_glue_endpoints(name):
    cli = boto3.client('glue')
    response = cli.delete_dev_endpoint(EndpointName=name)
    return response
```
Rustの数値型一覧

Rustで扱う数値には、大きく分けて
「符号あり整数」「符号なし整数」「浮動小数点数」
があります。
## 符号あり整数型

| 型    | 説明                                                      |
| ----- | --------------------------------------------------------- |
| i8    | 8ビット整数 (-128 ~ 127)                                  |
| i16   | 16ビット整数 (-32768 ~ 32767)                             |
| i32   | 32ビット整数 (-2147483648 ~ 2147483647)                   |
| i64   | 64ビット整数 (-9223372036854775808 ~ 9223372036854775807) |
| i128  | 128ビット整数 (- 2^127 ~ 2^127 -1)                        |
| isize | ポインタと同じサイズの整数 (64bit環境ならi64と同じ)       |

## 符号なし整数型

| 型    | 説明                                                        |
| ----- | ----------------------------------------------------------- |
| u8    | 8ビット符号なし整数 (0 ~ 255)                               |
| u16   | 16ビット符号なし整数 (0 ~ 65535)                            |
| u32   | 32ビット符号なし整数 (0 ~ 4294967295)                       |
| u64   | 64ビット符号なし整数 (0 ~ 18446744073709551615)             |
| u128  | 128ビット符号なし整数 (0 ~ 2^128 -1)                        |
| usize | ポインタと同じサイズの符号なし整数 (64bit環境ならu64と同じ) |

## 浮動小数点数

| 型   | 説明                 |
| ---- | -------------------- |
| f32  | 32ビット浮動小数点数 |
| f64  | 64ビット浮動小数点数 |

----

## とりあえず適当なの使おうかな......の時は

Q. 迷ったらどれを使うべきか？
A. 整数型ならi32, 浮動小数点数ならf64.
> 整数型の基準はi32型です: 64ビットシステム上でも、 この型が普通最速になります。

> 基準型はf64です。 なぜなら、現代のCPUでは、f32とほぼ同スピードにもかかわらず、より精度が高くなるからです。

The Rust Programming Language 日本語版 より引用  
https://doc.rust-jp.rs/book-ja/ch03-02-data-types.html
技術力のあるエンジニアをマネしてみたら自分の技術力も上がった話

最近Youtubeでプログラミングの動画をよく見ます。
検索してヒットしたチャンネルの中から、自分に合っているなと思った人の動画を参考にしてます。
英語になってしまいますが、[この人](https://www.youtube.com/watch?v=EzNcBhSv1Wo)とかいつも楽しそうにコード書いてておすすめです。

いろんな人を見てると、技術力が高い人にはいくつかの共通点を持つ傾向にあると思ったのでまとめてみました。

## 極力手で書く。
補完機能は使いますが、コードを手で書く人が圧倒的に多いです。
使用するライブラリのスペルチェックや、後述のドキュメントに載ってるコードとかはそのまま引用したりしますが、検索してヒットしたページ（Stack OverFlowとか）に載ってたコードを何も考えずにとりあえずコピペして・・・といった事はほとんどしません。
反面タイプミスは良くしてます。

## 実際にコードを書く前にこれからどういうコードを書くかの具体的なイメージができている。
技術力のある人ほどコードを書き始めてからビルドを実行するまでの時間が長い傾向にあります。
「こういうコードを書いたらこういう処理が実行されるはず！」といった感じである程度書いてからビルド実行している印象です。
ちょっとコード書いてみてデバッグしてみてまたまた修正して・・・といった事が殆どありません。引用した動画では空いてるポート番号を調べるためにビルド実行を繰り返しているシーンがありますが、こういったケースは稀です。

## 理解が早い
エラーメッセージの内容を理解したり、ドキュメントを見て内容を理解するスピードが早いです。
「どういうコードを書けば良いのか？」というよりは「どういう仕組で動いているのか？」を意識している事が多いです。

## ショートカットを使いこなしている
マウスを動かす時間よりもキーボードを叩いてる時間の方が圧倒的に長いです。ショートカットもそうですがツールを使いこなしている印象があります。

## 調べ物はする
変に自力で解決しようとせず、わからないところは素直に調べます。公式のドキュメントにかかれているコードは素直に参考にします。

## 最後にこの記事を書いた目的について
最近私は「動画主になったつもりで同じコードを写経する」「慣れてきたら動画主になったつもりで仕事してみる」という事をしているのですが、これがかなりおすすめです。作業進捗率がかなり上がったと自分でも感じています。
また、技術力のある人と同じように書いてもスピードについていけない場合、そこが自分の短所を示していると思います。

私の場合はコードを書く前に全体像が掴めていないケースが多かったですね。設計の重要さを痛感しました。
仕事で設計をした事はもちろんありますが、力不足を感じました。今後より勉強しようと思います。
フレックスレイアウト(display: flex)の配置に困ったら

## 背景
- フレックスレイアウト(`display: flex`)を利用するときに配置の設定(`flex-direction` , `align-items` , `justify-content` など)が難しかった．

## フレックスレイアウトで押さえるべきコツ
1. フレックスコンテナとフレックスアイテムの区別
2. 主軸と交差軸の理解

## 1. フレックスコンテナとフレックスアイテムの区別
- フレックスコンテナ: `display: flex;` を持つ要素
- フレックスアイテム: フレックスコンテナ直下の子ども要素
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300696/e76e386b-92f8-4af8-757d-43fde9981aa1.png)

- **両者で利用可能なプロパティが違うので注意**
  - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300696/5ca32cc2-a710-987a-032a-dc4b6e26699c.png)

  - 名前が似てるのがややこしいところ...
  - ある要素がフレックスコンテナかつフレックスアイテムの場合に混乱しやすい． どちらにつけるべきプロパティかを意識しましょう．

---
今回は最もよく使う `flex-direction` ， `align-items` , `justify-content` について説明します．
これらは親要素(フレックスコンテナ)に適用できるプロパティです．

## 2. 主軸と交差軸
- 主軸: 子供(フレックスアイテム)が並ぶ方向
- 交差軸: 主軸に垂直な方向

### `flex-direction` で主軸の方向を決める
- `row`: 左→右 (`row-reverse` は右→左)
  - ![row.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300696/5e1851f5-b94f-e3dc-1660-f9dd8d03b4ef.png)

- `column`: 上→下 (`column-reverse` は下→上)
  - ![column.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300696/8e69dfb1-c402-9575-5e21-fe9a3824271b.png)

### `justify-content`で主軸方向の配置を決める
- `flex-direction: row`の場合の例
  - 主軸は左→右の報告
  - ![row-justify.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300696/bede59a1-74f8-7e26-0a93-7ee87a5af714.png)

### `align-items`で交差軸方向の配置を決める
- `flex-direction: row`の場合の例
  - 交差軸は上→下の方向
  - ![row-align.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300696/89192c88-c7ca-9fdc-ed53-2f9efd704c64.png)

## まとめ
- 親要素(フレックスコンテナ)と子要素(フレックスアイテム)で使えるプロパティが異なるので注意
- 主軸と交差軸を意識できると配置もしやすくなります!
ACF Pro 複数の繰り返しフィールド内でそれぞれのギャラリーの画像が出力されない

ACF Pro
ギャラリーのフィールド名に
数字や_を複数使うと画像が出力されなかったので注意
途中に数字が入っててもダメだった
他のフィールド名は大丈夫だったので見つけるのに苦労したのでメモメモ

× item1_slider
× item2_slider

○ slider_design
○ slider_illustration
技術開発戦略

## 技術開発戦略
企業を接続的に発展させていくために、技術と市場のニーズを結びつける戦略
### MOT
<b>技術革新を効果的にビジネスに結びつけていこうとする経営の考え方
### イノベーション
<b>今までにない、画期的な新しいものを作り出すこと
・プロダクトイノベーション
・プロセスイノベーション
・インクリメンタルイノベーション
・ラディカルイノベーション
### イノベーションのジレンマ
<b>大企業が既存製品の改良を進めた結果、顧客が求める以上に高機能化してしまい、別の基準で評価される新技術を用いた新製品に敗北してしまうこと
### APIエコノミー
<b>アプリケーションの機能を外部から利用できる様にする仕組み。企業同士がAPIを使ってサービスを連携させることで生まれる新しい経済権を<font color = blue>APIエコノミー</font>
### オープンイノベーション
<b>違いの知識を生かしてイノベーションを起こそうという考え
### 魔の川・死の谷・ダーウィンの海
<b>技術経営における課題を表す言葉
<font color = blue>魔の川</font> - 基礎研究が製品開発に結びつかないこと
<font color = blue>死の谷</font> - 製品開発が事業に結びつかない事
<font color = blue>ダーウィンの海</font> - 事業化できても市場に浸透できないこと
### 技術のSカーブ
<b>技術の進歩の過程を示した曲線
### デザイン思考
<b>「顧客の立場で観察する」・「潜在的な問題点を抽出する」・「問題解決のためにより多くのアイディアを出す」・「すぐにプロトタイプを作る」・「評価・改善する」というプロセスを繰り返し、イノベーションを生み出すこと。
### ハッカソン
<b>開発者やデザイナーなどが集まってチームを組み、数時間や数日間の日程で、与えられた課題にチャレンジするイベントのこと。
### 技術ロードマップ
<b>将来の技術動向を予測して進展の道筋を時間軸上に表したもの
### デルファイ法
<b>「複数の専門家からの意見を収集」・「収集した意見を集約」・「集約された意見をフィードバック」というプロセスを繰り返す事で意見を収束させていく手法
[C#] テキスト内のリンクを置換する

あるテキストからリンクのみ検索して置換するというものを作ります。利用シーンとしてはリンクをトラッキングリンクに貼り替えるときなど。

```csharp

// Capture URL
Regex regex = new Regex("href\\s*=\\s*(?:\"(?<1>[^\"]*)\"|(?<1>\\S+))", RegexOptions.IgnoreCase);

var originalText = content;

for (var match = regex.Match(originalText); match.Success; match = match.NextMatch())
{
  if (match.Groups[1] != null)
  {
    content = content.Replace(match.Groups[1].Value, "{REPLACE URL}");
  }
}
```
【初心者】docker-compose file 書き方

# 目的
docker-compose ファイルの書き方を勉強します。

# 手段
- [公式ドキュメント](https://docs.docker.jp/compose/toc.html)参照しながら手を動かす

# 目次を眺めてみる
- 取り急ぎ、"Docker Compose 概要" から "Compose を始めましょう" までを読めば一通り動作確認できそうです

# さっそく始める
#### Docker Compose
- Compose は複数コンテナを定義/実行する Docker アプリケーションのためのツール
- 複数コンテナを一度で UP や DOWN できるツール

#### Docker Compose 概要
- Compose は yaml ファイルを使用
- 流れは、docker-compose.yml ファイル作成後、docker-compose up で起動

```yaml:samlple
version: '3' // バージョン
services: // アプリケーション内のコンピューティングリソースを定義
  web: // サービス単位
    build: . // コンテナイメージを作成するためのビルド設定を指定
    ports: // 公開するポートを指定
    - "5000:5000" // ホスト:コンテナ
    volumes: // コンテナがマウントするディレクトリのパスを指定
    - .:/code // ホスト:コンテナ
    - logvolume01:/var/log // ホスト:コンテナ
    links: // 他サービス内コンテナへのネットワークリンクを指定
    - redis
  redis: // サービス単位
    image: redis
volumes:
  logvolume01: {}
```

##### 単一ホスト上で複数環境を分離
- プロジェクト名を用いて各実行環境を分離可能
- これにより、複数の実行環境を持てる

##### 変更のあったコンテナのみ再作成
- コンテナ生成時に設定情報をキャッシュ保存する
- docker build と同じキャッシュのイメージ。変更あればその部分から再作成


#### Docker Compose インストール
- curl でバイナリ入手→ chmod で実行権限付与 → インストール


#### Compose を始めましょう
1. プロジェクト用のディレクトリ作成(ex: composetest)
1. Dockerfile 作成(Dockerfile)
1. Compose ファイル作成(docker-compose.yml)
1. 起動・停止等のコマンド実行

```docker
docker-compose up // 起動
docker-compose down // 停止
docker-compose up -d // デタッチモード用フラグ
docker-compose stop // デタッチモード時の停止
```


##### 環境ファイル
- Compose はファイル名 . env(環境ファイル)を通して、デフォルト環境変数を定義可能
- フォーマットは 変数=値、 # で始まる行はコメント


# 参考資料
[compose コマンドリファレンス](https://docs.docker.com/compose/compose-file/#links)
　→これに全て書かれている
# Ruby on Rails(ruby3.0系) の環境構築 ※Windows

この記事ではdockerでの仮想環境で構築するわけではなくCドライブにそのままrubyをインストールして環境構築をします。今からrubyやrailsを始めるという方向けです。
### バージョン
ruby 3.0.4p208 (2022-04-12 revision 3fa771dded) [x64-mingw32]
Rails 7.0.3
***
### rubyのインストール
[ruby公式](https://rubyinstaller.org/downloads/) から __Ruby+Devkit 3.0.4-1 (x64)__  をクリックしてダウンロードして下さい。
※バージョン確認コマンド
`ruby -v`
※rubyのバージョンが3.1系だと`rails new プロジェクト名`でrailsのプロジェクトを立ち上げる時に以下のエラーが発生してプロジェクトが上手く作られず、`rails s`で始めることが出来なくなります。
```
Errno::ENOENT: No such file or directory - bs_fetch:open_current_file:open 
bin/rails:4:in `<main>'
~~~
省略
~~~
Bundle complete! 15 Gemfile dependencies, 71 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.
         run  bundle binstubs bundler
       rails  webpacker:install
rails aborted!
Errno::ENOENT: No such file or directory - bs_fetch:open_current_file:open
bin/rails:4:in `<main>'
(See full trace by running task with --trace)
```
### 対処方
- rubyのバージョンを3.0系に下げる
- linux環境で構築する
***
### railsのインストール
```
C:\Usersユーザー名> gem install rails 
```
※バージョン確認コマンド
`rails -v`
***
### railsプロジェクトの作成
rubyとrailsのインストールを終えたら以下のコマンドでrailsのプロジェクトを作成します。
※OneDriveの配下で作成するとエラーになりました。
```
C:Users\ユーザー名\任意のフォルダ>rails new プロジェクト名
```
***
### サーバを起動する
```
C:\Users\ユーザー名\任意のフォルダ>cd プロジェクト名
C:\Users\ユーザー名\任意のフォルダ/プロジェクト名>rails s
```
(http://127.0.0.1:3000/)
(http://localhost:3000/)
上のリンク(どちらでもよい)を開いて下の画面が開けば成功です。
![スクリーンショット 2022-06-09 141256.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2706288/b6d74ecf-99a9-56ec-5bf7-2f3626e9ff62.png)

***
今回はネットにrubyの3系のrailsの立ち上げが無かったのでQiitaに始めて書いてみました。
データベースとの連携は他の方が色々とあげていらっしゃるのでここでは省きたいと思います。
【GitHub Desktop】簡単！ドラッグ&ドロップでcherry-pick

## 想定読者
- Git・GitHub初心者
- GitHubの操作でGUIツールの利用を検討している方
- GitHub Desktopを使い始めた方

## はじめに
GitHub Desktopは、GitHub公式が提供しているクライアントツールです。（以下、公式ダウンロードリンク）

https://desktop.github.com/

GUIツールで視覚的・直感的な操作が可能であり、コマンド入力の手間を省くことができます。

ところで、Git・GitHubを使って開発をしている途中で、「別のブランチのこのコミットだけ、自分の作業ブランチに反映させたいな…」と思ったことはないでしょうか？
そのような状況を解決してくれるのが、今回触れるcherry-pickという機能です。

cherry-pickは、別のブランチにある指定のコミットを現在のブランチに反映させてくれます。

今回は、コマンド・GitHub Desktopのそれぞれを用いたcherry-pick方法を紹介します。

## 前提
- OS：Windows10 21H2
- GitHub Desktopのバージョン：3.0.1 (x64)
（macOS版もあります）

### 準備物・実現内容
- 作成したレポジトリ：cherry-pick
- 元のブランチ：main
- 別のブランチ：another
- 自分の作業ブランチ：mine

anotherの指定のコミットEの内容をmineに反映させる。

- before
![スクリーンショット 2022-06-10 163630.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2512880/b9a90846-ec07-c76b-8a10-00ab0cfb8d94.png)
- after
![スクリーンショット 2022-06-10 163646.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2512880/db906e11-50a8-331f-40f9-5f5d1977d484.png)

E'になっているのは、コミットのハッシュ値が元のEと異なるからです。
EとE'は別物だけど、内容は同じというイメージです。

## コマンドでのcherry-pick実行手順
mineに移動の上、以下のコマンドを実行するとcherry-pick完了です。

```cli:コマンドライン
$ git cherry-pick 指定のコミットID
```

ちなみにコミットIDは、次のコマンドで調べることができます。

```cli:コマンドライン
$ git log
```
表示される内容のうち、「commit」の文字の横に記載されている長い数字・英字の羅列がコミットIDです。
![スクリーンショット 2022-06-10 154758.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2512880/d4affc46-9be9-f196-d180-6e7fbbf4ae24.png)


## GitHub Desktopを用いたcherry-pick実行手順

ここからが本題です。

以下の画像のようにGitHub DesktopでCurrent branchをanotherにし、Historyタブを押下します。
指定のコミットEを選択し、そのまま赤矢印の通りにCurrent branchの欄までドラッグします。
この時、まだドラッグ状態は維持したままにしてください。

（なお、複数のコミットを選択することも可能なので、まとめてcherry-pickしたい場合は[shift]キーを押しながら、対象のコミットを範囲選択します。）

![スクリーンショット 2022-06-10 170144.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2512880/3b612925-9f4e-5713-6729-e3c8f7b9796a.png)

すると、次の画像のように各ブランチが表示されるので、mineまでドラッグ&ドロップしてください。

![スクリーンショット 2022-06-10 170818.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2512880/13cc5004-a249-259a-73a1-e92b654e68cf.png)

その後、Current branchがmineに自動で切り替わり、cherry-pickしたコミットが反映されていることを確認することができます。
（cherry-pickした内容によってはコンフリクトが発生するので、発生した場合はコンフリクト箇所の修正が必要です。）

問題なければプッシュし、元に戻したい場合は上部に表示されているメッセージ横の「Undo」を押下してください。

これでcherry-pick完了です。

![スクリーンショット 2022-06-10 171022.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2512880/46753578-5cdd-7c1e-1d93-ffa459f6e1bb.png)

## おわりに
ドラッグ&ドロップで直感的にcherry-pickができるのは、すごく便利ですよね！
実は、この機能は1年以上前から備わっていたのですが、恥ずかしながらつい最近になって知りました…

このように、GitHub Desktopはコマンドなしで様々な操作を行うことができるので、実際の開発現場でもとても重宝しています！

しかし、頼りすぎるとコマンドでの操作に慣れることができず、ツールだけでは実行できない操作もあるので、早いうちにコマンド操作にも慣れておくことをおすすめします！

それでは、良き開発ライフを！

## 参考情報
https://github.blog/jp/2021-04-09-github-desktop-now-supports-cherry-picking/
Pythonの例外エラーログ、もうちょっと詳しく見たくない？

ある日の某Pythonアプリケーションのエラーログを眺めていると謎のエラーが...!

```sh
Traceback (most recent call last):
  File "/sandbox/app.py", line 22, in <module>
    main()
  File "/sandbox/app.py", line 17, in main
    sub()
  File "/sandbox/app.py", line 10, in sub
    raise Exception("sub error!")
Exception: sub error!
```

例外が起きたときのTracebackですね。
Exceptionに詳細が記録されていればわかりやすいのですが、上記のようになぜエラーが起きたのかわからないと困りますよね。

そんなとき、Tracebackのstackを追いかける事でそのときのローカル変数を取得できます。


こんなアプリケーションがあるとして
```py
def sub():
    d = 4
    e = 5
    raise Exception("sub error!")

def main():
    a = 1
    b = 2
    c = 3
    sub()
```

例外キャッチハンドラをこのように
```py
import sys
import traceback
from pprint import pprint

if __name__ == "__main__":
    try:
        main()
    except Exception:
        (_, _, tb) = sys.exc_info()
        for (frame, _) in traceback.walk_tb(tb):
            pprint(frame)
            pprint(frame.f_locals)
        raise
```

するとあら不思議
```sh
<frame at 0x7feb8b610240, file '/sandbox/app.py', line 26, code <module>>
{'_': 22,
 '__annotations__': {},
 '__builtins__': <module 'builtins' (built-in)>,
 '__cached__': None,
 '__doc__': None,
 '__file__': '/sandbox/app.py',
 '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x106dbaca0>,
 '__name__': '__main__',
 '__package__': None,
 '__spec__': None,
 'frame': <frame at 0x7feb8b610240, file '/sandbox/app.py', line 27, code <module>>,
 'logging': <module 'logging' from '/usr/local/Cellar/python@3.9/3.9.13/Frameworks/Python.framework/Versions/3.9/lib/python3.9/logging/__init__.py'>,
 'main': <function main at 0x107007d30>,
 'pprint': <function pprint at 0x107007dc0>,
 'sub': <function sub at 0x106e06160>,
 'sys': <module 'sys' (built-in)>,
 'tb': <traceback object at 0x10700db00>,
 'traceback': <module 'traceback' from '/usr/local/Cellar/python@3.9/3.9.13/Frameworks/Python.framework/Versions/3.9/lib/python3.9/traceback.py'>}
<frame at 0x106ee6200, file '/sandbox/app.py', line 17, code main>
{'a': 1, 'b': 2, 'c': 3}
<frame at 0x106f46900, file '/sandbox/app.py', line 10, code sub>
{'d': 4, 'e': 5}
Traceback (most recent call last):
  File "/sandbox/app.py", line 22, in <module>
    main()
  File "/sandbox/app.py", line 17, in main
    sub()
  File "/sandbox/app.py", line 10, in sub
    raise Exception("sub error!")
Exception: sub error!
```

StackのFrameごとにローカル変数が出力されました。
Webアプリケーションだと例外ハンドリング層に組み込むと便利ですね。
PHPでAPCuを使って共有メモリにキャッシュを実現する方法


| [../](https://qiita.com/taconana/items/3f5424f9abfc755772c2) |
| :--: |

PHPの`APCu`というライブラリを利用してみた。標準のPHPには同梱されていないので、ダウンロードしてDLLを追加した。APCuは「APC User Cache」の略である。APCは「Alternative PHP Cache」の略である。（ちなみに、PHPは「PHP Hypertext Preprocessor」の略である。再帰的な略になっている。GNUの「GNU's Not Unix!」を真似たのかな。）

JavaとTomcatでは、高速化のため、またDBやファイルへのアクセス負荷を軽減するために、メモリ上にキャッシュを作成して利用することがたびたびある。探索時にはメモリ上のキャッシュから探し、なければDBやファイルから検索したり、読み込んだりする。PHPでは、ブラウザで画面が遷移するごと(redirectするごと)に新たなプロセスが生成されるので、メモリ上に生成したオブジェクトを単純には共有できない。APCuを使って、プロセス間で共有メモリ上にオブジェクトを保持させ、取り出すことが可能になる。

## APCuの使い方

APCuの使い方は、単純明快である。`apcu_store()`で格納し、`apcu_fetch()`で取得する。格納されているデータをキャッシュから取り除くための`apcu_delete()`もある。
```php
<?php 
  apcu_store('foo', $bar); 
  var_dump(apcu_fetch('foo')); 
?>
```
もっと具体的な例だと次の感じである。ユーザー一覧をDBやファイルなどから取得する場合、高速化のためにメモリ上にキャッシュしておく例である。キャッシュにあれば、それを返す。なければ、検索に行き、検索結果はキャッシュに保持しておく。
```php
<?php 
  public function getUsers(): array {
    $users = apcu_fetch('users');
    if (!empty($users)){
      return $users;
    }
    $accessor = new UserDataAccessor(); // DBやファイルにあるユーザー情報にアクセスするためのDAO
    $users = $accessor->getUsers(); // ユーザー一覧を取得する。
    apcu_store('users', $users);
    return $users;
  }
?>
```
ユーザー情報に変更があれば、キャッシュをクリアしておく必要があり、そのときはapcu_delete()を使うといいだろう。
apcu_store()では、引数で与えられたオブジェクトはその時点のスナップショットとしてコピーされて保持される。参照渡しの場合も同様である。「[PHP7.4で、$_SESSIONとACPuはどのようにキャッシュされるのか](https://qiita.com/taconana/items/506480ab3af77a3d824a)」を参照のこと。

## APCuのダウンロードとセットアップ

APCuは、https://windows.php.net/downloads/pecl/releases/apcu/5.1.18/ から `php_apcu-5.1.18-7.4-ts-vc15-x64.zip` をダウンロードしてきた。x86版も並んでいるので間違えないこと。最新版は5.1.21のようだったが、私のEclipseの環境は PHP 7.4 なので、それに合わせたバージョンを選んでいる。

zipを展開して、`php_apcu.dll` をPHPのインストール先の`ext`ディレクトリ配下に置く。私の場合 C:\pleiades-xxx\xampp\php\ext である。

そして、`php.ini` に以下の4行を追記する。php.ini は、私の場合 C:\pleiades-xxx\xampp\php\php.iniである。
```bash
extension=php_apcu.dll
apc.enabled=1
apc.enable_cli=1
apc.shm_size=64M
```
Eclipseをcleanモードで再起動して試してみよう。

ちなみに、x86版やバージョンの異なるDLLをコピーすると、以下のようなランタイムエラーが起きた。php_apcu.dll が不適切だったら、php_php_apcu.dll.dll を探しにいくみたい。
```
PHP Warning:  PHP Startup: Unable to load dynamic library 'php_apcu.dll'
 (tried: C:\pleiades-php2\xampp\php\ext\php_apcu.dll 
(%1 は有効な Win32 アプリケーションではありません。), 
 C:\pleiades-php2\xampp\php\ext\php_php_apcu.dll.dll 
(指定されたモジュールが見つかりません。)) in Unknown on line 0
```
| [../](https://qiita.com/taconana/items/3f5424f9abfc755772c2) |
| :--: |
Kubernetes環境におけるCouchbase: Helmチャート


Couchbase公式のHelmチャートを使用して、CouchbaseデータベースをKubernetes環境にデプロイすることができます。

## Helm概要

Helmは、Kubernetesのパッケージマネージャーとして知られています。

Helmは、Helmチャートと呼ばれるメカニズムを提供します。
Helmチャートによって、Kubernetesクラスター内で、 様々なパッケージをインストール、アップグレード、そしてロールバックすることができます。
Helmは完全なライフサイクル管理を提供するわけではありませんが、多くのタスクの自動化を簡素化します。

Helmチャートは、コンポーネントのセットを表現します。また、それらのコンポーネントの構成情報についても規定します。
構成情報については、デフォルト値を規定することに加え、オプションまたはオーバーライド可能な設定を提供することができます。



カスタマイズされた構成を含む、インストールされたHelmチャートの特定のインスタンスを「リリース」と呼びます。
単一のKubernetesクラスター内で、Kubernetes名前空間内で一意に名前が付けられている限り、チャートの構成またはバージョンが異なる複数のリリースをインストールできます。

他のパッケージマネージャーでも見られるように、リポジトリまたはローカルアーカイブとディレクトリからチャートをプルすることができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176567/4fe07f9d-b8d0-7a7a-c56c-49d9ef6d74a0.png)


## CouchbaseのHelmサポート

Couchbaseは、公式のHelmチャートを提供します。
Couchbaseチャートは、 Couchbase Autonomous Operatorを、Couchbase Serverクラスターとともにインストールするために使用されます。
また、オプションでCouchbase Sync Gatewayを構成に含めることが可能です。


## 利用方法


以下のように、チャートリポジトリを追加することから始めます。


```
$ helm repo add couchbase https://couchbase-partners.github.io/helm-charts/
```

```
$ helm repo update
```

次に、チャートをインストールします。

```
$ helm update install my-release couchbase/couchbase-operator
```

デフォルトのチャートを利用して、Kubernetesプラットフォームで、Autonomous Operatorを使用したCouchbase Serverの管理を簡単に試すことができます。


最小限の労力でクラスターを稼働させるために、デフォルトのセットが提供されていますが、Couchbase チャートは、Autonomous Operatorのすべてのパラメーターのカスタマイズをサポートしています。

Couchbaseチャートは、セキュリティ機能の構成をサポートしており、デプロイをセキュアに管理する手段を提供します。最初にシークレットを作成してからCouchbaseクラスターをデプロイする代わりに、チャートを使用してこのプロセスを自動化できます。同様に、TLSやレプリケーションなどの他の機能も簡単に管理できます。

### 関連情報

https://docs.couchbase.com/cloud-native-database/helm-overview.html
GitLabサーバのアカウント操作の種類

# はじめに

チームで使用しているGitLabでアカウント棚卸を実施した際に調べた内容のメモです。

環境は次の通りです。
- オンプレミスのSelf-Managed型
- GitLab Ver.15.0.1

ちなみに所属チームでは離任者のアカウントは`Delete`ではなく`Block`する方針になっています。
アカウントをDeleteにすると、issue作成者などの表示が`Ghost User`に変わってしまい、
後で経緯などを追跡する際にわかりにくくなるためです。

# GitLabサーバでのアカウント操作の種類

GitLabでのアカウント操作は次の種類があります。
1. Block
2. Deactivate
3. Ban
4. Delete
   - Delete User
   - Delete User and Contributions

## Block
- ログイン不可
- リポジトリとAPI使用不可
- GitLabからの通知がこない

## Deactivate
- リポジトリとAPI使用不可
- GitLabからの通知がこない

:information_source: 
- この操作は`直近90日活動のない`アカウントに対して可能になります
- Blockとの異なり、UIへのログインは可能です
- UIにログインすることで自身のアカウントをActivateすることができます

## Ban
- ログイン不可
- リポジトリとAPI使用不可
- GitLabからの通知がこない
- Banしたアカウントが作成したissueが非表示になる
- 他のアカウントが作成したissueなどでのコメントは引き続き表示される

## Delete

### Delete User
- 削除するアカウントが作成した各種記録(issue, Merge request,…)は `Ghost User` へと変更になる
- 削除するアカウントで行われたコミットでの表示はそのまま

### Delete User and Contributions
- 削除したアカウントが作成した各種記録(issue, Merge request,…)も一緒に削除される

# 参考情報
- [Moderate users](https://docs.gitlab.com/ee/user/admin_area/moderate_users.html)
- [Deleting a User account ](https://gitlab-docs.creationline.com/ee/user/profile/account/delete_account.html)
【dbt Cloud】target.name 変数を使って動的にモデルを処理してみる

# この記事はなに？

dbt Cloud でモデルからテーブルを生成する際に、`target.name`変数を使って参照するデータセットや生成先のデータセットを動的に切り替える方法を解説した記事になります。

今回は、BigQuery に本番環境用の`lake_prod`、開発環境用の`lake_dev`というデータセットがあり、その中に各環境下で発生したデータが存在しているという前提のもと、各データセットから、`warehouse_prod`、`warehouse_dev`のデータセットに新しくテーブルを作る場合の手順をまとめております。

# dbt Cloud における target について

target は、`Job`及び`Project の Development Credential`で設定でき、`target.name`変数を宣言することで値を呼び出すことができます。
[公式ヘルプ](https://docs.getdbt.com/docs/dbt-cloud/using-dbt-cloud/cloud-setting-a-custom-target-name)


# 参照するデータセットを動的に切り替えてみる

例えば、下記のようなモデルがあるとします。
 
```sql:sample_model.sql
SELECT
  id
  , name
FROM
  `sample_project.lake_{{target.name}}.sample_table`
```

データセットの宣言部分に`target.name`変数を入れているため、target に `prod` という文字列が設定された Job で`dbt run`コマンドを実行した場合、FROM 句の部分は`sample_project.lake_prod.sample_table`という文字列になります。

同様に、他の Job で target に `dev`という文字列を設定して`dbt run`を実行した場合は、`sample_project.lake_dev.sample_table`という文字列になります。

このように`target.name`をモデル内で宣言することで、同じようなモデルを量産せずに1つのモデルで動的に処理を切り替えることができます。

# 生成先のデータセットを動的に切り替えてみる

前提として、[こちらの記事](https://docs.getdbt.com/docs/building-a-dbt-project/building-models/using-custom-schemas)を参考に、下記 macro を実装し、`dbt_project.yml`内で`schema`の宣言がされていた場合は、宣言された値を参照するようにしています。

```sql:generate_schema_name_for_env.sql
{% macro generate_schema_name_for_env(custom_schema_name, node) -%}

    {%- set default_schema = target.schema -%}
    {%- if (target.name == 'prod' or target.name == 'dev') and custom_schema_name is not none -%}

        {{ custom_schema_name | trim }}

    {%- else -%}

        {{ default_schema }}

    {%- endif -%}

{%- endmacro %}
```

```sql:get_custom_schema.sql
{% macro generate_schema_name(custom_schema_name, node) -%}
  {{ generate_schema_name_for_env(custom_schema_name, node) }}
{%- endmacro %}
```

上記 macro が組まれている前提で、下記のような`dbt_project.yml`があるとします。(models 部分のみ抜粋)

```yml:dbt_project.yml
models:
  project_name:
    warehouses:
      +materialized: table
      +schema: |
        {%- if  target.name == "prod" -%} warehouse_prod
        {%- elif target.name == "dev"  -%} warehouse_dev
        {%- else -%} invalid_database
        {%- endif -%}
```

Jinja の if ステートメントを用いて`target.name`の値を比較することで、動的に schema が参照する文字列を切り替えています。

これにより、`lake_prod`のデータは`warehouse_prod`に、`lake_dev`のデータは`warehouse_dev`にテーブルを生成させることができます。

# おわりに

今回の動作検証を通して、dbt Cloud における target の役割を理解することができました。
扱うデータが増えれば増えるほど、dbt のモデルファイルも増えていき、処理も複雑化していくため、こういった仕組みを使って最適化していきたいですね。
ここまで読んでくださりありがとうございました！
コードベースで封筒の宛名とかをPDF出力できるツールを作った

コードベースで封筒の宛名とかをPDF出力できるツールを作った

JSONで宛名テンプレートと封筒のレイアウト指定してで印刷用のPDF吐く｡

https://github.com/gretchi/envelope-maker


# 封筒作るん

JSON テンプレートから封筒に宛名とかの PDF 作るやつ

## Usage

```shell
$ ./main.py -t [TEMPLATE_PATH] -p [LAYOUT_PATH] -o [OUTPUT] --a4
```

`-t`: 宛先 JSON
`-p`: 封筒レイアウト JSON
`-o`: 出力先
`--a4` A4 互換モード(option)

宛名のサンプル: template.json
長形 3 号のサンプル: naga_3go.json

サイズ･位置パラメータは `mm` ミリメートル単位

### Dockerを使用したサンプル

```shell
# Using docker
$ docker build -t envelope-maker .
$ docker run \
-v $PWD/dist:/var/dist \
envelope-maker \
./main.py -t ./template/template.json -p ./layout/naga_3go.json -o /var/dist/sample.pdf --a4
```


## 上手く動かなかったらすまん

うちのプリンターでしか動かんかもしれん

動作確認済み: ブラザー HL-L2365DW

## サンプル

![A4モード](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149815/7b8ca469-4113-6570-8dab-6abfe0372fea.png)

![ネイティブモード](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149815/b1c433f5-c6b9-be98-c40e-6c728233ad31.png)

![印刷結果](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149815/97cc8b75-1b87-73a6-eac7-6efac6e21a9f.png)



## ＩＰＡフォント

ＩＰＡフォントをバンドルしてるよ

[IPA_Font_License_Agreement_v1.0.txt](https://github.com/gretchi/envelope-maker/blob/main/fonts/IPA_Font_License_Agreement_v1.0.txt) 読んでね
PHP8.0のUNION型で型指定の幅が広がった

## UNION型とは
型を`union`として宣言すると、ひとつではなく
**複数の異なる型を値として受け入れる**ことができます。
union型は、`T1|T2|...`という文法を使って指定します。

## 今までのコード
PHP8以前はプロパティ、パラメーター、および戻り値の型に対して**単一の型しか宣言**できず
PHPDocで補完することしかできませんでした。

```php5
class Foo {
	/**  
	* @var int|float $num
	*/  
	private $num;

	/**  
	* @var int|float $a
	* @var int|float $b
	* @return void
	*/  
	public function test($a, $b): void
	{
		$this->num = $a * $b;
	}
}
```

## UNION型を使用
PHP8.0からはこのように書くことができます。
```php5
class Foo {
	private int|float $num;
 
	public function test(int|float $a, int|float $b): void
	{
		$this->num = $a * $b;
	}
}
```

## 注意点
#### void型
`void`はUnionTypesでは使用できません。

#### false疑似型
PHPでの多くはエラーを吐くときはfalseで返すことが多く、
失敗時には`null`ではなく`false`を返すように実装されています。
型指定はfalseでしましょう。
（例）`int|false` `string|false`

#### null許容型
`T1|T2|null`としてnullを指定できます。
null宣言には`?T1|T2`などはできないので注意しましょう。

## メリット
- **すべてのパターンで型指定が可能**となり、プログラムの品質が向上する。
- PHPStanなど**静的解析でおこるエラー**が解消しやすい。
- **PHPDocの分量を減らす**ことができる。


## デメリット
- あまり型に精通していない人が記載した場合、誤った型のケースを想定する場合がある。

## 参考
https://php.watch/versions/8.0/union-types
Sql学習メモ-inner join

```sql
select e.emp_no, dm.emp_no
from employees as e
         inner join dept_manager as dm;
-- 10003,10002
-- 10002,10002
-- 10001,10002
-- 10003,10003
-- 10002,10003
-- 10001,10003
-- 10002,10003はdept_managerにある。10001,10002,10003はemployeesにある
```

inner joinの本質はCartesian productです
Railsで"Failed to build gem native extension"のエラーが出る原因と解決法

# 1. 背景
Rails 5.2.6から5.2.8へアップデートするためにGemfileを修正し、`bundle update`した時に事態は発生した。

# 2. エラーログ
~~~
(前略)
Fetching unf_ext 0.0.8.2 (was 0.0.8)
Installing unf_ext 0.0.8.2 (was 0.0.8) with native extensions
Gem::Ext::BuildError: ERROR: Failed to build gem native extension.

    current directory: /opt/bundle/ruby/2.7.0/gems/unf_ext-0.0.8.2/ext/unf_ext
/usr/bin/ruby2.7 -I /usr/lib/ruby/2.7.0 -r ./siteconf20220609-1597-ncuewr.rb extconf.rb
checking for -lstdc++... *** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of necessary
libraries and/or headers.  Check the mkmf.log file for more details.  You may
need configuration options.
(後略)
~~~

# 3. 原因
依存関係の問題かと思ったが、rubygems.orgを参照しても問題なさそうだった。
注目すべきポイントは以下の二つ。
~~~
Installing unf_ext 0.0.8.2 (was 0.0.8) with native extensions
Gem::Ext::BuildError: ERROR: Failed to build gem native extension.
~~~
要約：ネイティブ拡張のgemである'unf_ext'をでインストールするのに失敗した。
~~~
checking for -lstdc++... *** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of necessary
libraries and/or headers.  Check the mkmf.log file for more details.  You may
need configuration options.
~~~
要約：おそらくc++関連のライブラリが不足していてMakefileが作れない。

ネイティブ拡張とはCやC++などの言語で書かれたライブラリをRubyから使用できる機能である。
unf_extのgithubを参照したところ、このgemはHackというプログラミング言語で書かれており、インストールにはC++のコンパイラが必要とのこと。
https://github.com/knu/ruby-unf_ext

# 4. 対処法
以下の記事を参照しつつ、C++のコンパイラとmakeをインストールした。
https://azechi-n.hatenadiary.com/entry/2020/04/11/084307

~~~
apt update
apt install g++ make
~~~

上記を実行し再度`bundle update`したところ、全て上手く行った。

# 5. 参考サイト
[knu/ruby-unf_ext](https://github.com/knu/ruby-unf_ext)
[Ruby:slimにdiscordrbをインストールできた](https://azechi-n.hatenadiary.com/entry/2020/04/11/084307)
Ruby-FFIでは関数はクラス変数に登録されていたが、今ではFiddleと同じくクラスインスタンス変数に登録されている

:::note alert
この記事は情報が古いです。
現在ではRuby-FFIもクラスインスタンス変数 `@ffi_functions` に関数は登録されています
:::

## モチベーション

コールバックとして、attach_function した関数を利用したい

## はじめに

Ruby-FFI と Fiddle はRubyからC言語の関数を呼び出せる便利なライブラリです。

* Ruby-FFIでは、`attach_function` メソッドを利用して、関数を登録します。
* Fiddleでは、`extern` メソッドを利用して、関数を登録します。

それぞれ `Function` クラスが存在します。しかし何もしなければRubyではガベージコレクションが働いて関数を表現しているオブジェクトを開放してしまいます。開放された関数オブジェクトを呼び出そうとするとセグフォが発生してしまうはずです。ですから関数オブジェクトは、どこかのオブジェクトから参照されてGCから保護されているはずです。では `attach_function` や `extern` で作成した関数オブジェクトはどこに登録されているのでしょうか？

## Ruby-FFIではクラス変数

Ruby-FFIでは、関数はクラス変数に退避されています。クラス変数の一覧は、`class_variable` メソッドで閲覧できます。

```ruby
HogeLib::FFI.class_variables
```

たとえば、こんな感じで、一つの関数が、同名の一つのクラス変数に保存されています。

```ruby
(略)
 :@@sam_hdr_init,
 :@@bam_hdr_read,
 :@@bam_hdr_write,
 :@@sam_hdr_destroy,
 :@@sam_hdr_dup,
 :@@sam_hdr_parse,
 :@@sam_hdr_read,
(略)
```

## Fiddleでは、クラスインスタンス変数

Fiddleでは、関数は、`@func_map` というクラスインスタンス変数に登録されています。

```ruby
HogeLib::FFI.instance_variable_get(:@func_map)
```

とすれば見ることができます。ただし、`@func_map` は内部のAPIだと思います。この先とくに予告なく変更される可能性があります。そのため特に必要なとき以外は、安易にアクセスしない方が良いとは思いますが、とにかく現状ではこのような実装になっています。


この記事は以上です。
Atomが開発終了…→同作者の「Zed Editor」がよさそう

 # Atom開発終了！！！

Atom Editorの開発終了がアナウンスされました。

https://github.blog/2022-06-08-sunsetting-atom/

> Atom has not had significant feature development for the past several years, though we’ve conducted maintenance and security updates during this period to ensure we’re being good stewards of the project and product. As new cloud-based tools have emerged and evolved over the years, Atom community involvement has declined significantly. As a result, we’ve decided to sunset Atom so we can focus on enhancing the developer experience in the cloud with GitHub Codespaces.
https://github.blog/2022-06-08-sunsetting-atom/

> (翻訳)
Atomは、過去数年間、重要な機能開発を行っていませんが、この期間中に、プロジェクトと製品の優れた管理者であることを確認するために、メンテナンスとセキュリティの更新を実施しました。新しいクラウドベースのツールが何年にもわたって出現し進化してきたため、Atomコミュニティの関与は大幅に減少しました。その結果、GitHubコードスペースを使用してクラウドでの開発者エクスペリエンスの向上に集中できるように、Atomを廃止することにしました。

…と書かれていますが、Micr○softがGitHubを買収して以来Atomの開発が止まり気味になったのを考えると~~どの口が言ってるのか~~と思います。

# Atomの作者が新しいエディタを作っている

Atom作者のnathansobo氏が新しいエディタを作っているようです。

https://twitter.com/nathansobo/status/1534565356131393537

その名も「Zed Editor」です。ホームページには「Rustで記述された超高速のコラボレーションコードエディタ」と書かれています。

https://zed.dev/

Atomの起動速度が遅かったのを気にかけているのか、パフォーマンスにかなり気を使っているようです。

まだ開発中ということですが、作者がツイートしている動画を見るにもう完成間近のようですね。

https://www.loom.com/share/1a07df9440fe4d198b1a4df134401a1d

「[今週アルファ版をリリースする](https://twitter.com/nathansobo/status/1534587172669603844)」と言っているので、気になる方は[waitlist](https://zed.dev/waitlist)に登録してみましょう！

Atomは開発終了しましたが、その基盤技術であるElectronは様々なソフトウェアのプラットフォームに利用されています。ZedのRust製GUIのしくみもそのような革新的技術だと嬉しいですね。
pandasのread_tableとread_csvの違い（初心者による初心者向けの説明）

# レコード形式のテキストファイルを読み込もうとしてread_csvを使ったらエラーが出た話

- 24列からなるデータを読み込もうとしたら...
```python
df = pd.read_csv('test.txt')

# エラーメッセージ
ParserError: Error tokenizing data. C error: Expected 1 fields in line 18, saw 3
```


# 原因

- read_csvは引数を指定しなければ、","カンマ区切りのファイルしか受け付けない。
- このテキストファイルの場合は区切り文字が”\t”(タブ文字)だった。


# 解決法
- read_csvの代わりにread_tableを使えばよい。read_tableはデフォルトで区切り文字が"\t"(タブ文字）になっているので、このファイルを扱うのに適している。

# 大事な知識
- csv　の正称は　comma-separated value　で、名前にある通り区切り文字が "," (コンマ)のファイルを指す。
- 可変長レコードなる概念が存在する。[わかりやすいサイト](https://wa3.i-3-i.info/word12937.html)
- [タブについてちゃんと理解しよう](https://wa3.i-3-i.info/word11700.html)
- 区切り文字が "," だけでなく "\t"（タブ）　の場合もある。
【PHP】西暦から和暦を返す関数

調べれば山ほど出てくる日本人御用達関数です。
どっかで拾った関数を魔改造したものなので似たものがある場合はご了承ください。

```php
function get_wareki($year, $format = false, $gannen = false) {
  $gengoList = [
    ['name' => '令和', 'name_short' => 'R', 'year' => 2019],  // 2019-05-01,
    ['name' => '平成', 'name_short' => 'H', 'year' => 1989],  // 1989-01-08,
    ['name' => '昭和', 'name_short' => 'S', 'year' => 1926], // 1926-12-25'
    ['name' => '大正', 'name_short' => 'T', 'year' => 1912], // 1912-07-30
    ['name' => '明治', 'name_short' => 'M', 'year' => 1868], // 1868-01-25
  ];

  $gengo = array();
  foreach ($gengoList as $g) {
    if ($g['year'] <= $year) {
      $gengo = $g;
      break;
    }
  }

  $year = ($year - $gengo['year']) + 1;
  if ($year == 1 && $gannen) {
    $year = '元';
  }

  $out = $gengo['name'] . $year . '年';
  if ($format) {
    $out = $gengo['name_short'] . $year . '年';
  }
  return $out;
}
```
## 使い方

関数の第一引数に西暦を入れれば和暦が返ってきます。

```php
echo get_wareki(2022)
// 令和4年
```

第二引数移行は任意ですが、第二引数をtrueにすると元号はアルファベットになります。
```php
echo get_wareki(2022, true)
// R4年
```

第三引数は、1年の場合は元年に変更するオプションです。
```php
echo get_wareki(2022, false, ture)
// 令和4年

echo get_wareki(2019, false, ture)
// 令和元年
```
iOS16端末でDeveloper Modeを有効にする方法

ぱっと見で分からなかったのでメモしておきます。

[設定]>[プライバシーとセキュリティ] からDeveloper Modeを有効に出来ます。

ドキュメント
[Enabling Developer Mode on a device | Apple Developer Documentation](https://developer.apple.com/documentation/xcode/enabling-developer-mode-on-a-device)

> デベロッパモードを有効にするには、iOSデバイスの[設定]>[プライバシーとセキュリティ]に移動します。デベロッパモードのリスト項目までスクロールして、その中に移動します。デベロッパモードを切り替えるには、「デベロッパモード」スイッチを使用します。

ビデオはこちら
[Get to know Developer Mode - WWDC22 - Videos - Apple Developer](https://developer.apple.com/videos/play/wwdc2022/110344/)

開発者モードの設定を自動化する必要がある場合は、macOS Venturaに搭載されるdevmodectlを使用できるらしい。
devmodectl もいつか見ておこう。


ドキュメントを読むとTestFlightには影響ないみたいだけど、DeployGateはどうなるんだろう？
M5Paper: fillCenterSquare の挙動がおかしい

```text:draw_square.ino
// ---------------------------------------------------------------
//	draw_square.ino
//
//						Jun/09/2022
// ---------------------------------------------------------------
#include <M5EPD.h>

M5EPD_Canvas canvas(&M5.EPD);

// ---------------------------------------------------------------
void setup() {
  // put your setup code here, to run once:
	M5.begin();
	M5.EPD.SetRotation(90);
	M5.TP.SetRotation(90);
	M5.EPD.Clear(true);
	canvas.createCanvas(540, 960);
	canvas.setTextSize(5);

	canvas.fillCenterSquare(100, 100, 50, WHITE);
	canvas.fillCenterSquare(200, 100, 40, WHITE);
	canvas.fillCenterSquare(300, 100, 30, WHITE);

	canvas.fillRect(200, 200, 50, 30, WHITE);
	canvas.drawRect(200, 300, 50, 30, WHITE);

	canvas.fillRoundRect(300, 200, 50, 30, 10, WHITE);
	canvas.drawRoundRect(300, 300, 50, 30, 10, WHITE);

	canvas.fillCircle(200, 400, 30, WHITE);
	canvas.drawCircle(200, 500, 30, WHITE);

	canvas.fillCircle(300, 400, 15, WHITE);
	canvas.drawCircle(300, 500, 15, WHITE);

	canvas.fillEllipse(200, 600, 30,15, WHITE);
	canvas.drawEllipse(200, 700, 30, 15, WHITE);
	
	canvas.fillTriangle(200, 800, 300,800, 250,750, WHITE);
	canvas.drawTriangle(200, 900, 300,900, 250,850, WHITE);
	
	canvas.fillTriangle(400, 800, 500,800, 450,775, WHITE);
	canvas.drawTriangle(400, 900, 500,900, 450,875, WHITE);
	
	canvas.pushCanvas(0,0,UPDATE_MODE_DU4);
}

// ---------------------------------------------------------------
void loop() {
  // put your main code here, to run repeatedly:

}

// ---------------------------------------------------------------
```

Arduino IDE
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/5b88e36c-c06e-9853-2f66-207b8dc90927.png)

実行結果
![IMG_20220609_125723.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/c7ad70a9-da4d-1d96-8f5c-b57bde7a51a5.jpeg)
Java SE8 Gold -概要-

## はじめに
2022年4月にJava SE8 Silverに合格したため、上位のJava SE8 Goldの概要をまとめる。

**そもそもなぜJavaGoldを取得したいのか**
常駐先がJava案件であることがほとんどのため、Javaの知識を身につけたい。
また、エンジニアとしての力量をわかりやすく提示するためにも取得したい。
## Java SE8 Goldとはどういうもの
>Oracle Certified Java Programmer, Gold SE 8 認定資格は、設計者の意図を正しく理解して独力で機能実装が行える中上級者向け資格です。
Javaアプリケーション開発に必要とされる汎用的なプログラミング知識を有し、設計者の意図を正しく理解して独力で機能実装が行える能力評価することを目的としています。
Oracle Certified Java Programmer, Gold SE 8 認定資格を取得するためには、Java SE 8 Programmer II (1Z0-809-JPN) 試験の合格が必要です(認定パス)。
[Java SE 8 認定資格 - Oracle](https://www.oracle.com/jp/education/certification/jse8-2489021-ja.html)

**試験概要**
* 前提資格： Java Silver
* 出題形式： 選択問題
* 試験時間： 150分
* 出題数： 85問
* 合格ライン: 65%
* 受験料： ３万円前後


## Java SE8 Goldの出題範囲
**Java SE8 Gold 出題範囲**
* Java クラスの設計
* 高度な Java クラスの設計
* ジェネリクスとコレクション
* コレクション、ストリームおよびフィルタ
* ラムダ組込み関数型インタフェース
* Java ストリーム API
* 例外とアサーション
* Java SE 8 の日付/時刻 API
* Java の I/O の基本
* Java のファイル I/O（NIO.2）
* Java の同時実行性
* JDBC によるデータベース・アプリケーションの作成
* ローカライズ

## 学習方法（予定）
いわゆる黒本を中心に進めていく予定
各章を２〜３回確認してから、巻末の練習問題をこなして、足りなようなら他の問題集を検討する。
[amazon -黒本-](https://www.amazon.co.jp/dp/B01LXSG1G9/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1)
ざっくりと中身を確認した感じとしてはJavaSilverよりかなり難易度が上がっており、しっかりと理解、また、暗記を求められる試験となっている様子。
AWS CLIでDynamoDBのtransact-write-itemsとConditionCheckを試した時にハマったこと


## 概要
AWS CLIでDynamoDBのトランザクション機能を検証していますが、ConditionCheckの使い所でハマったので、簡単にまとめます。


## ハマったことを時系列に書いてみる

以下のコマンドを実行

```bash
aws dynamodb transact-write-items --transact-items '[
{
    "Put": {
        "TableName" : "tableA",
        "Item" : {
            "ID" : {"S": "001"},
            "Attribute" : {"N": "1"}
        }
    },
    "ConditionCheck": {
        "TableName" : "tableA",
        "Key" : {
            "ID" : {"S": "001"}
        },
        "ConditionExpression" : "Attribute > :limit",
        "ExpressionAttributeValues" : {
            ":limit" : {"N": "0"}
        }        
    }
}
]'
```

すると、以下エラーが発生

```
An error occurred (ValidationException) when calling the TransactWriteItems operation: TransactItems can only contain one of Check, Put, Update or Delete
```

以下を参考にコマンドを修正し、上記エラーはなくなる
https://stackoverflow.com/questions/57685182/using-dynamodb-transact-write-items-how-to-do-a-conditioncheck-for-an-existing-i


```bash
aws dynamodb transact-write-items --transact-items '[
{
    "Put": {
        "TableName" : "tableA",
        "Item" : {
            "ID" : {"S": "001"},
            "Attribute" : {"N": "1"}
        }
    }
},
{
    "ConditionCheck": {
        "TableName" : "tableA",
        "Key" : {
            "ID" : {"S": "001"}
        },
        "ConditionExpression" : "Attribute > :limit",
        "ExpressionAttributeValues" : {
            ":limit" : {"N": "0"}
        }        
    }
}
]'
```

しかし、以下のエラーが発生

```bash
An error occurred (ValidationException) when calling the TransactWriteItems operation: Transaction request cannot include multiple operations on one item
```

Putなどのコマンド内でConditionExpressionやExpressionAttributeValuesを入れる必要があった。
(参考に記載の公式ドキュメントを見る限り、このようになっていないが、、)

以下コマンドで解決

```bash
aws dynamodb transact-write-items --profile sandbox --transact-items '[
{
    "Put": {
        "TableName" : "tableA",
        "Item" : {
            "ID" : {"S": "001"},
            "Attribute" : {"N": "1"}
        },
        "ConditionExpression" : "Attribute > :limit",
        "ExpressionAttributeValues" : {
            ":limit" : {"N": "0"}
        }
    }
}
]'
```

## 参考
https://stackoverflow.com/questions/57685182/using-dynamodb-transact-write-items-how-to-do-a-conditioncheck-for-an-existing-i

https://docs.aws.amazon.com/cli/latest/reference/dynamodb/transact-write-items.html