OmniAICreator/Qiita-1.07M huggingface dataset:
C#で外部ライブラリを使用せずにJSON文字列を整形する





# サンプルコード

```csharp:indentJson.cs
using System.IO;
using System.Text;
using System.Runtime.Serialization.Json;
using System.Xml;

class Example
{
    public static void Main(string[] args)
    {
        string json = "[{\"color\":\"red\",\"value\":\"#f00\"}," +
                       "{\"color\":\"green\",\"value\":\"#0f0\"}," +
                       "{\"color\":\"blue\",\"value\":\"#00f\"}," +
                       "{\"color\":\"cyan\",\"value\":\"#0ff\"}," +
                       "{\"color\":\"magenta\",\"value\":\"#f0f\"}," +
                       "{\"color\":\"yellow\",\"value\":\"#ff0\"}," +
                       "{\"color\":\"black\",\"value\":\"#000\"}]";
        string indented = convertToIndentedJson(json);
        System.Console.WriteLine("in:");
        System.Console.WriteLine(json);
        System.Console.WriteLine();
        System.Console.WriteLine("out:");
        System.Console.WriteLine(indented);
    }

    private static string convertToIndentedJson(string json)
    {
        byte[] buffer = Encoding.UTF8.GetBytes(json);
        using (MemoryStream stream = new MemoryStream())
        using (XmlDictionaryWriter writer = JsonReaderWriterFactory.CreateJsonWriter(stream, Encoding.UTF8, true, true))
        using (XmlDictionaryReader reader = JsonReaderWriterFactory.CreateJsonReader(buffer, XmlDictionaryReaderQuotas.Max))
        {
            writer.WriteNode(reader, true);
            writer.Flush();
            return Encoding.UTF8.GetString(stream.ToArray());
        }
    }
}
```

# コンパイル用のバッチファイル

```indentJson.cs.bat
@setlocal
@pushd "%~dp0"
@for %%1 in ("%~n0") do @set "BASENAME=%%~n1"
@for /d %%1 in (%SystemRoot%\Microsoft.NET\Framework\v*)   do @if exist "%%~1\csc.exe" set "CSC=%%~1\csc.exe"
@for /d %%1 in (%SystemRoot%\Microsoft.NET\Framework64\v*) do @if exist "%%~1\csc.exe" set "CSC64=%%~1\csc.exe"
"%CSC%"   /target:exe /platform:x86 /optimize+ /warnaserror+ /out:"%BASENAME%.exe"   "%~n0"
"%CSC64%" /target:exe /platform:x64 /optimize+ /warnaserror+ /out:"%BASENAME%64.exe" "%~n0"
@popd
@endlocal
```

# 実行結果

```コマンドプロンプト
>indentJson.exe
in:
[{"color":"red","value":"#f00"},{"color":"green","value":"#0f0"},{"color":"blue","value":"#00f"},{"color":"cyan","value":"#0ff"},{"color":"magenta","value":"#f0f"},{"color":"yellow","value":"#ff0"},{"color":"black","value":"#000"}]

out:
[
  {
    "color": "red",
    "value": "#f00"
  },
  {
    "color": "green",
    "value": "#0f0"
  },
  {
    "color": "blue",
    "value": "#00f"
  },
  {
    "color": "cyan",
    "value": "#0ff"
  },
  {
    "color": "magenta",
    "value": "#f0f"
  },
  {
    "color": "yellow",
    "value": "#ff0"
  },
  {
    "color": "black",
    "value": "#000"
  }
]
```

# ポイント
* `CreateJsonWriter()`の第4引数が`indent`なので、こいつへ`true`を指定すること
Hexabase Dart/Flutter SDK向けドキュメントを公開しました

[Hexabase（ヘキサベース）](https://www.hexabase.com/)は企業向けのBaaS（Backend as a Service）を提供しています。認証やデータストア、ファイルストレージ、リアルタイム通知などの機能があり、企業向けのシステム開発に必要な機能をまるっと提供しています。

APIはREST APIとGraphQLを提供しています。そのAPIをラップしたSDKも開発を進めています。SDKは現在、TypeScriptとDart向けに開発しています。Dart向けのSDKは、もちろんFlutterでも利用できます。

この記事では新しく公開したDart/Flutter SDK用のドキュメントについて紹介します。

## ドキュメントのURL

ドキュメントは下記URLにて公開しています。[Docusaurus](https://docusaurus.io/)を使って構築しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/7d1dee69-7d8b-22ef-7b4b-9ca66b2a1890.png)


[Hello from Hexabase SDK | Hexabase SDK](https://hexabase.github.io/hexabase-dart-sdk-docs/)

## 現状サポートしている機能について

執筆時点（2022年11月現在）でDart/Flutter SDKがサポートしている機能は以下の通りです。

- 認証
	- ID/パスワード認証
- ワークスペース
	- 一覧取得
	- 更新
- プロジェクト
	- 一覧取得
	- 作成
	- 更新
	- 削除
- データストア
	- 一覧取得
	- 検索
- データストアアイテム
	- 作成
	- 更新
	- 削除
	- ステータス変更
	- ファイルアップロード
	- ファイルダウンロード
	- ファイル削除

これらの機能について、SDKドキュメントにまとめて記述しています。

## デモアプリについて

Dart/Flutter SDKを使ったデモとして、現時点では2つ掲載しています。今後、追加予定です。

- [Todoアプリ](https://zapp.run/edit/flutter-z4606ru4706?entry=lib%2Fmain.dart&file=lib%2Fmain.dart)
- [写真メモアプリ](https://zapp.run/edit/flutter-ze0062ke106?entry=lib%2Fmain.dart&file=lib%2Fmain.dart)

## 他の機能について

Hexabaseでは他にもSSE（Server Sent Events）やAuth0を用いた認証、細かなロール管理などの機能があります。これらも随時SDKに追加予定です。ご期待ください。

## まとめ

Hexabase Dart/Flutter SDKはまだ0.5ですが、日々機能追加と改善を行っています。SDKへの開発コントリビューション、フィードバックを大歓迎していますので、ぜひお試しください！

[hexabase | Dart Package](https://pub.dev/packages/hexabase)

[hexabase/hexabase-dart: Hexabase SDK for Dart & Flutter](https://github.com/hexabase/hexabase-dart)
エンジニアの転職　年収を上げたければTOEIC

# わたしの自己紹介
1社目：テストをする人　350万円
2社目：SE　430万円
3社目：AWSに関わる人　600万円

:::note info
3社目で大きく**年収**が上がりました。
:::
趣味：節約（風呂なし4万5000円、半額弁当生活）
資格：AWS SAA、TOEIC 700点オーバー

# 仕事の評価よりもTOEIC
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2959011/a550788e-72fc-b115-5d31-0489942f142a.png)
[IIBC引用](https://www.iibc-global.org/iibc/press/2019/p128.html "IIBC")

英語は今後社会人として仕事をしていく上で間違いなく必要
▶️**もちろん収入が高い案件が揃う**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2959011/e3618ad2-4287-9d57-cab9-bf77924cf273.png)
[ベネッセ引用](https://www.benesse.co.jp/brand/category/education/20200903_1/ "ベネッセ")

勉強を定期的にするだけで半分以上の人間に差をつけることが出来る
▶️**成長し続けるエンジニア**

:::note info
勉強しない人は本当にテコでも勉強しない
わたしがいくら言っても~~煽っても~~残念ながら彼は最後まで勉強しなかった
もし、勉強されていなければ**本日を機に勉強しましょう**
:::

## TOEICの汎用性
20-30代の転職において大切なことは
**1番：実績**
※が、これはすぐにはどうすることも出来ないので無視します。
**2番：自分自身のプレゼン**
※この話は一旦今回はスキップします。
**3番：資格**
資格って何を勉強すればいいのって意見あると思います。

### 強い資格
私の観点(新卒・第二新卒・30代転職活動）でおすすめ度を発表します。
①情報処理試験　☆（おすすめ度1)
<理由>
・1年に2回もしくは1回しかない
・汎用的な知識しか身につけることができない

:::note warn
IoTの意味を理解していることが大事なのではなく、IoTを使って何かビジネスに使えることが大事なので、汎用的な知識しか持っていないのはあまり武器にならないのではと考察しました。
:::

:::note alert
資格取得を批判するつもりは一切ございません。
:::

・合格をするための努力と年収アップの効果が割に合わない。

②各種ベンダー試験☆☆☆（おすすめ度3)
<理由>
・情報処理試験よりも知識のその先を求められる。
・AWSやAzureやGCPなど会社で利用する環境の資格はモロ刺さる

:::note info
資格を取得している≠仕事が出来る
資格を取得している＝**最低限の能力**を第三者が保証している
:::

③TOEIC☆☆☆☆☆（おすすめ度5)
<理由>
・高収入を狙うならば確実に必要な資格になる
・勉強時間と年収アップの割が合いすぎる。

:::note info
私の場合
300時間（4ヶ月間　毎日2-3時間）
合計3万円（スマホアプリ1万5000円＋試験料2回）
:::
現職で150万円を上げる場合、10年以上働く必要がある。
150万円アップを即座にアップすることが出来た＝10年後にタイムスリップしたこととイコール

日本の優秀なエンジニアは海外や外資系企業に就職・転職をする世の中です。
優秀なエンジニア＝英語が出来る
はいずれマスト条件になります。

:::note alert
700点オーバーの実体験談
第一目標の600点をとったからと言って話せるようにもなりませんし、聞けるようにもなりません。
はっきり言って飾りであるということは常に意識して研鑽に努めましょう。
:::

大学時代400点からどうやって4ヶ月で700点取れたかは
この投稿が好評ならば書きます！！
Deta.shにPythonアプリをデプロイする

:::note warn
2023.03現在、サービスのメジャーアップデートにより、従来の方法（以下記載のもの）での新規アプリ作成はおそらく不可能となりました。
:::

# はじめに

Herokuの無料プランの廃止に伴い、flaskで作成したアプリのデプロイ先として新たに開拓する。
deta.shにデプロイが出来たので、その手順を紹介する。

※注意
ファイル構成に関してさらっと書いておく。

Herokuにデプロイできる状態であれば、まず以下の手順を行います。
生成される`main.py`を削除し、`app.py`や`run.py`などのメイン実行ファイルのファイル名を`main.py`に変えます。
基本はこの状態でデプロイできるはずです。

インストールが必要なライブラリに関しては`requirements.txt`に記載します。


<!-- ========== next article block ========== -->


# CLIのインストール

CLIをインストールするために以下のコマンドを実行する。
Windowsは、コマンドプロンプトでは動かない動かないのでPowerShellを使用する。

```:windows
iwr https://get.deta.dev/cli.ps1 -useb | iex
```

```:mac/linux
curl -fsSL https://get.deta.dev/cli.sh | sh
```

これを実行すると、`deta`コマンドが使えるようになる。


<!-- ========== next article block ========== -->


# ログインする

[deta.sh](https://www.deta.sh/) の`Join Deta` からアカウントの作成アカウントの作成とメールアドレスの認証を行う。

完了したら以下のコマンドを実行する。

```
deta login
```

実行するとブラウザが開き、`Logged in successfully.` と表示されればログイン完了。


<!-- ========== next article block ========== -->


# アプリを作成する

アプリを作成するために適当なディレクトリに移動し、以下のコマンドを実行する。

`app_test` の部分には、作成するアプリを識別するための名前を付ける。

```
deta new --python app_test
```

実行すると以下のようにURLなどが表示される。`endpoint`がアプリのURLとなる。

```
Successfully created a new micro
{
        "name": "app_test",
        "id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
        "project": "xxxxxxxx",
        "runtime": "python3.9",
        "endpoint": "https://xxxxxx.deta.dev",
        "region": "us-east-1",
        "visor": "disabled",
        "http_auth": "disabled"
}
```

実行したディレクトリ直下に、アプリのディレクトリ `/app_test` が作成され、その中に`main.py`が作成される。これが実行ファイルとなる。

また必要なライブラリ等の情報は`requiremente.txt`に記入し、同じディレクトリに設置する。

ここまで出来たら、`cd`コマンドでアプリのディレクトリに移動し、デプロイを実行する。

```
deta deploy
```

以下の表示が出たら完了。先ほどの`endpoint`に記載のURLにアクセスすることでアプリを使用できる。

```
Deploying...
Successfully deployed changes
```

pythonのバージョンバージョンを最新以外に指定するときは以下のように`deta new`を実行する。

```
deta new --runtime pytyhon3.7
```


<!-- ========== next article block ========== -->


# デプロイ時の注意点（実際に引っかかったところ）

私がHerokuのアプリをdetaにデプロイしなおした際に、`Bad Gateway`エラーで表示できないページがあった。調べてみたところ、URLにマルチバイト文字を含む際にエラーとなることが分かったので、注意。

https://qiita.com/dagamun/items/6e2407b8028b6c6b9997


<!-- ========== next article block ========== -->


# 参考

https://qiita.com/namachan/items/b8c1ee89dc091d656d4f


<!-- ========== next article block ========== -->
【Linux】cpコマンドなどの対象にドットファイルを含める

## はじめに

`cp`などで特定のディレクトリ内のすべてのファイルを対象にする際、以下のように指定してもドットファイルは対象になりません。

```zsh
$ tree -a
.
└── test
    ├── example
    └── sample
        ├── .test
        └── test.txt

$ cp -v test/sample/* test/example
test/sample/test.txt -> test/example/test.txt

$ tree -a
.
└── test
    ├── example
    │   └── test.txt
    └── sample
        ├── .test
        └── test.txt

```

`cp`の対象にドットファイルを含める方法について記載します。  

## ドットファイルを含める方法

以下のように記述することでドットファイルを対象に含められます。  

```zsh
$ cp -v test/sample/*  test/sample/.[^\.]* test/example
test/sample/test.txt -> test/example/test.txt
test/sample/.test -> test/example/.test

$ tree -a
.
└── test
    ├── example
    │   ├── .test
    │   └── test.txt
    └── sample
        ├── .test
        └── test.txt
```
YouTubeサーチ拡張プラグインの作成とリバースエンジニアリングについての検証

# 概要
[YouTubeサーチ拡張プラグイン](https://chrome.google.com/webstore/search/YouTube%E9%80%A3%E5%8B%95%E6%A4%9C%E7%B4%A2%E5%86%8D%E7%94%9F%E3%83%97%E3%83%A9%E3%82%B0%E3%82%A4%E3%83%B3?hl=ja)を作成する場合、YouTubeサーチ結果をリバースエンジニアリングして検索結果を解析する必要があります。
[リバースエンジニアリング(https://digitalrisk-lab.com/trend/156/)](https://digitalrisk-lab.com/trend/156/)については、セキュリティ対策上は禁止されなくなったようです。(著作権法の改正で)
今回のケースは検索結果を解析して、その一部データを使って別の形式の再生リストを作成します。動画自体の改変ではなく、検索結果の動画情報の一部利用になります。
つまり、動画を再生するためのオリジナル形式の再生リストを作成するプラグインを作成します。このようなケースのリバースエンジニアリングの是非について検討してみたいと思います。
# 検索結果の著作権は
著作権法では、ソースコードに著作権が発生するとされていますが、その実行結果のデータ(DOM形式)についてどうなのかはグレーゾーンだと思います。DOM形式の検索結果も一つの著作物に相当するかもしれませんが、YouTubeの利用規約を見ても、動画に関するリバースエンジニアリングは禁止とあるが、再生リストについてはその規約が見当たりません。まさにグレーゾーンです。
# オリジナルの再生リストの場合は
YouTubeには再生リストが用意されていますが、その形式の再生リストではなく、ここでの再生リストは拡張プラグインで作成したオリジナル形式の再生リストを指します。この再生リストにも作成者の著作権が発生するのかもしれません。再生リストも一種のソースコードになると思います。
# 拡張プラグインの開発上
拡張プラグインを開発するうえで、このリバースエンジニアリングは避けて通れない手法です。Chromeブラウザーでサイトを開くとこのプラグインも実行します。大抵の場合、プラグインはDOMドキュメントを参照します。これがリバースエンジニアリングに相当すると思います。
DOMの解析に必要不可欠です。この結果、拡張プラグインを作る上ではリバースエンジニアリングは暗黙的に許可されていると思われます。
# Webページと著作権
Webページを作成していて、常に思うことは、これは著作権に引っ掛からないのだろうかと言うことです。現代はオープンソースの時代です。無料で使えるコードやライブラリーがたくさんあります。jqueryも重宝しています。無料のAPIもたくさん使っています。無職のリタイヤ組としては有料のソフトは使えません。それでも多くの人に利用してもらいたいWebサイトは作りたいです。自己満足かもしれませんが。ネットで無料のイラストや音源なども利用しています。一から作っていては寿命も体力も持ちません。独創性には欠けるかもしれませんが、デザインに凝っている余裕はありません。著作権には抵触しないように慎重に制作をしてゆきたいです。
# データの引用
このプラグインはデータを引用していることになります。youtubeサーチの検索結果から、一部のデータを取り出して、利用しています。そのような場合は、データの引用元を記載すればよいのか迷います。検索結果はクェリーにヒットした動画になりますが、動画の数が多いと個々の引用元を記述すると大変な量になってしまいます。そこで、まとめて、引用元:「youtubeの検索結果より」としてよいのかが明記されていません。これもグレーゾーンです。
# デバッガーでソースコードを解読
ブラウザーのデバッガーを起動すると、確かにソースコードは見ることができます。但し、それはブラウザーが読み込んだクライアント側のソースファイルだけで、サーバー側のソースファイルまでは見ることはできません。ハッキングでもしない限りサーバの中には入り込めないので、セキュリティ面では安心です。秘密のコードはサーバに置き、見られても仕方がないコード(javascript等)はクライアント側に置きます。
このため、リバースエンジニアリングと言っても、見られても仕方がないクライアント側のコードなので、ソースコードの解読と言っても決して怪しい行為をしているわけではないと思います。
# あとがき
YouTubeサーチ拡張プラグインを作成していて、常にこのリバースエンジニアリングの問題がありました。最近では、徐々に特にセキュリティ対策上では許可されているようです。安心してプラグインを作成したいものです。
結論としては、YouTubeサーチ拡張プラグインで作成した独自形式の再生
リストはたとえリバースエンジニアリングで作成したとしても、それは著作権法に違反してはいないのではと言うことです。
ご参考:
[このプラグインを使用しているサイト(https://favorite.tecoyan.net/#btn_cntrl)](https://favorite.tecoyan.net/#btn_cntrl)
Dockerの環境構築とマウントのやり方

# はじめに
Dockerを初めて使った際の、環境構築～マウントまでのやり方を簡単にまとめました。
今回はDockerfileを用いて進めていきます。
※環境：Windows

# Dockerfileを用意
今回はSampleというディレクトリを用意し、そこにDockerfileを作成していきます。

Dockerfile記述内容
```
FROM httpd

RUN apt-get update
RUN apt-get install -y vim
```
今回はApache httpdを使用し、vimもインストールします。

# Dockerfileからイメージを作成
作成したDockerfileを元にイメージを作成します。
```
docker build -t sample-image .
```
今回はsample-imageというイメージ名にしています。

# ソースのマウント
ローカルソースのマウントを行います。
まず、srcディレクトリを作成し、その中にindex.htmlを配置します(htmlの中身は任意)。
```
Sample/
　　　├─ Dockerfile
　　　└─ src/
　　　　　　└─ index.html
```
　
次に以下コマンドを実行します。
```
docker run --name sample-container -p 80:80 -v %CD%/src:/usr/local/apache2/htdocs sample-image
```
各設定値の内容は以下です。
docker run --name {コンテナ名} -p {ホスト側ポート}:{コンテナ側ポート} -v {ホスト側ディレクトリ}:{コンテナ側ディレクトリ} {イメージ名}
今回はwindows環境で行っているので%CD%を使っていますが、
macやlinux環境で行う場合は、$PWDを使います。
　
これで http://localhost にアクセスしhtmlの中身が表示されれば成功です。

# コンテナ作成後の操作
一度コンテナを作成してからは、以下コマンドで起動/停止が行えます。
起動コマンド　docker start コンテナ名
```
docker start sample-container
```
停止コマンド　docker stop コンテナ名
```
docker stop sample-container
```

# 参考サイト
https://qiita.com/minato-naka/items/e1f91e1df2c4fe7411dc
SAA-C03にリベンジを果たした話

# 目次
* はじめに
* 前回の反省
* 勉強で工夫した点
* 今後の抱負

# はじめに
こんにちは、中学校の先生です。
[前回](https://qiita.com/Daha/items/9c169c02a4912f0a86b3 "前回")から約1か月経ち、ついにSAA-C03へリベンジを果たしました。
そこで反省した点、工夫した点、今後の抱負などを記録していきたいと思います。

# 前回の反省
前回は問題演習偏重型で、ひたすら数をこなすことに躍起になっていました。
教材は本がメインで、インターネットでは演習問題を探し回りながら取り組んでいました。
そこで細かい操作やサービスの組み合わせ、ネットワークの仕組みなどを突かれると弱いな、と感じました。
また、実際に触ったことが無い分ネットワークインフラのイメージが立てづらいことも感じていました。

# 勉強で工夫した点
* お金を惜しまない
Udemyでコースを買い、ハンズオンに取り組みました。そこでEC2の立ち上げやS3バケットのライフサイクル設定、アクセスのコントロールなど基本的であろう操作を練習しました。楽しいのはもちろん、これが試験中の選択肢を理解するのに繋がった、と感じています。

* 時間を惜しまない
前回は「○○までに勉強を終わらせる！」ということに注力しすぎて、知識が穴だらけでした。試験日を決めて、そこに向けて集中して勉強することも大事だとは思いますが、今回は逆に納得いくまで勉強し、自信をつけてから挑んでみました。

* 場所によって適切な勉強方法を用意しておく
プライベートで色々と移動することが多かったので、
移動中はスマホで問題演習
自宅で時間がある時はPCでハンズオン
隙間時間は本で復習、本が終わったらiPadで新規書籍購入
テスト前は様々な媒体で問題演習
というプランで行きました。
前回は手持無沙汰な時間もあったので、今回は隙間なく勉強できたと自負しています。

# 今後の抱負
ハンズオンをすると、意外と穴だらけな知識で勉強していたことに気づかされました。
しばらくは様々なハンズオンに取り組み、サーバーレスアーキテクチャでも組んでみようかと思っています。
落ち着いたらDVAやSOAも目指してみる予定です。
指定された名前付き接続は、構成内に見つからないか、EntityClient プロバイダーと併用することを意図していないか、または無効です

`.NET Framework4.0`のテストプロジェクトに、テストコードを実装しようとしてエラーが発生

```
テスト メソッド SampleProject.Tests.UnitTest1.TestMethod1 が例外をスローしました:
System.ArgumentException: 指定された名前付き接続は、構成内に見つからないか、EntityClient プロバイダーと併用することを意図していないか、または無効です。

  スタック トレース: 
EntityConnection.ChangeConnectionString(String newConnectionString)
EntityConnection.ctor(String connectionString)
ObjectContext.CreateEntityConnection(String connectionString)
ObjectContext.ctor(String connectionString, String defaultContainerName)
SampleProject.ctor() 行 34
UnitTest1.TestMethod1() 行 18
```

テストプロジェクトに対してテスト対象のプロジェクトを参照するだけでなく、データベース接続先の設定を持つ必要があるようだ

![Untitled (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482880/fd11bfdc-34e3-7972-6f1d-d6989bfa394e.png)

`App.config`を作成して、テスト対象のプロジェクトの`web.config`にある接続文字列を記述するとビルドが通った

```xml
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
	<connectionStrings>
		<add name="sampleEntities" connectionString="metadata=res://*/Models.sample.csdl|res://*/Models.sample.ssdl|res://*/Models.sample.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=DESKTOP-123HITE\SQLEXPRESS;initial catalog=sample_table;user id=sa;password=pass123;multipleactiveresultsets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient" />
	</connectionStrings>
</configuration>
```

リンクか何かで参照できれば良いのだが、方法は調査中...
ファイル名が固定じゃないデータをBOXDriveからS3へアップロードする

# はじめに
BOXDrive (エクスプローラー) からS3へコマンドでデータをアップロードする際、
ファイル名・S3パスともに可変にさせたかったのでコードを書きました。
cmdは初めて書く初心者です。

# 使用コード
```bat:cmd
REM 月次でフォルダを分けたいため今日の日付-1月のyyyymmを作成
set dt=%date%
set yy=%dt:~-10,4%
set mm=%dt:~-5,2%
if %mm% == 01 (
 set /a x= %yy%%mm%-89
 ) else (
 set /a x= %yy%%mm%-1
)

REM S3側処理
REM 月次フォルダを作る
set s3=[転送先S3pass]
set fullpath=%s3%%x%/

REM BOXDrive側処理
REM dir設定
set dir=[転送元BOXDrivepass]
set dir=%dir%\%x%

aws s3 cp --recursive --exclude "*" --include "*.csv" %dir% %fullpath% --profile [S3folderのprofile]
```

# コード説明
・日付作成ブロック
　今日の日付からsubstringを駆使してyyyyとmmを作成しており、
　作りたいのは前月のデータなので、monthは-1、
　各年1月の前月は「前年の12月」なので、-89しています。
　　例 : 2022年1月の前月値 (2021年12月) を作る場合は、2201-2112 = 89
　[こちら](https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q14250112349)を流用させていただきました。ありがとうございます。

・S3側処理ブロック / BOXDrive側処理
　それぞれのパスの一番後ろに前月フォルダ名 (yyyymm) を文字列結合しています。

・S3へコピー
　基本構文は`aws s3 cp [転送元ファイル名] [転送先S3バケットパス] [s3のプロファイル名]`ですが、
　`転送元ファイル名`については月によってファイル名が異なるため、ここを可変にするために
　オプションの`--recursive` `--exclude` `--include`を使用しました。
　オプションの詳細については[こちら](https://docs.aws.amazon.com/cli/latest/reference/s3/cp.html) を参照ください。

　この3オプションを利用した理由は **[aws s3 cp]の引数にはワイルドカードをそのまま使用できないため** になります。
　※正確にはUNIX スタイルのワイルドカードが使えないです。
　　UNIXスタイルのワイルドカードの説明については[こちら](http://www.edu.tuis.ac.jp/~mackin/java/2008/linux/wildcard.html)を参照ください。
　　用はexcelの置換等でやる[＊.csv]の[＊]ような形です。

# オプションの使い方
複数のオプションを指定する場合は**1番最後のオプションが優先**になります。
　`--recursive` : 指定ディレクトリ・プレフィックス内のすべてのファイル・オブジェクトに対して実行指示を出す
　`--exclude` : 指定パターンに合致するファイル・フォルダを除く
　`--include` : 指定パターンに合致するファイル・フォルダのみ残す

:::note info
exclude / includeはワイルドカード使用可です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752246/1850171d-5080-0e28-36bb-0fe3cda8e17d.png)
:::
　
# 注意点
やりながら`--include`だけでcsvファイルを選べるのでは？と思ったのですが、
[公式](https://docs.aws.amazon.com/cli/latest/reference/s3/index.html#use-of-exclude-and-include-filters)によるとデフォルトは「該当フォルダ内のオブジェクトすべて」なので、
特定のものを残したいときは最初に`--include`で欲しいオブジェクトを選び、
そのあとに`--exclude`で最初に選ばれたオブジェクト以外を除かないと思い通りのものが選ばれない状況になります。
また、`--include`のみだとエラーが出るらしいです ([参考 ポイント2部分](https://blog.serverworks.co.jp/tech/2018/02/05/point-of-aws-cli-cp-to-s3/))。

# エラーで苦労したところ
引数を変数にし、さらにファイル名をワイルドカードにしたかっただけなのですが
フォルダの引数が先なのか、オプションが先なのかが検索しても出てこずエラーと戦いました。。。

いろんな順でやってみましたが、順番はオプション→フォルダ名 でした。
オプションだけでなく転送したいファイルの指定等も後ろに書かれたものから実行なのかもしれません。

# おわりに
同じファイル名で上げられれば良かったのですが、その後の処理都合上やりたくなかったのでいろいろチャレンジしました。
参考になれば幸いです。
Fortniteで改行できないことから一転して実はレアケースだったというお話

# はじめに

本記事では、Fortniteのクリエイティブで島を作り直すぞー！　と意気込んでみたらえらい方向に行ってしまった話です。

# 背景

Fortniteのクリエイティブの島を持っているのですが、今の島では不便なことといったらならないので大改修をすることにしました。

# 発端

大改修の一環として、ビルボードにある文章を書き換えることにしました。
このビルボードで曲者なのは**改行ができない**こと。
CRやLFを打ち込んでも画面表示は改行されないまま。
Markupでも使うのかと思って調べてみたらそんなものは見つからず。
スペースをたくさん挟めばそれらしきことはできるのですが、なんというかスマートじゃない。
改行の方法が無いことはないのでは、ということで調査することに。

# 調査

ググってみると、こんなブログ記事を発見。

https://www.kagua.biz/playgame/fortnite/20220121a1.html

ここで紹介されているPastebinのページでコピペすれば改行できるよ！　と書かれていて実際に改行できました。
…はて、どうして改行できるんだ？？？
何か文字を挿入しているのか！？　Unicodeの特別な文字なのか？？？

と疑問が増えたところで、Redditの記事へのリンクも。

https://www.reddit.com/r/FortniteCreative/comments/kguiv6/how_do_you_make_multiple_lines_of_text/

すると、リプライの一つにそのものズバリな答えが。

```text
U+0085を入れればいいぜ
```

これではっきりしました。

# U+0085とは？

U+0085は「NEL(Next Line)」という、Unicode独自の改行文字です。

参考：[Wikipediaの「改行コード」の記事](https://ja.wikipedia.org/wiki/%E6%94%B9%E8%A1%8C%E3%82%B3%E3%83%BC%E3%83%89)

基本的にUTF-8でコードや文章を書くときでも改行はCRLFやLFを使うのが専らですし、NELを使う時があるのは…記憶にない(汗)

ほとんど使うことが無いNELを使う機会がまさかのFortniteのクリエイティブというのは本当にレアケースだなぁと。

# テキストエディタで挿入するぞ！

フォートナイトでの文字列を挿入したいときは、テキストエディタで編集してコピペしたほうが楽です（PC版の場合）。

## 秀丸の場合

コードを直接挿入するのも面倒くさいので、カーソル位置にU+0085を挿入するマクロを作りました。

https://gist.github.com/cyross/3bc50630bda193b89f0a08c5745e4494.js

```
insert "\u0085";
```

あとは適当なキーバインドにこのマクロを紐づければ楽に挿入できます。

## VSCodeの場合

VSCodeではちょっと導入が手間ですが、比較的ラクな方法で。

### Insert Unicode 拡張機能をインストール

「Unicode」で検索すれば引っかかりますので、選択してインストールします。

![スクリーンショット 2022-11-10 195824.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101034/ec20e102-dee2-0a00-cac7-22d33c2f433c.jpeg)

### コマンドパレットを開いて、Insert Unicodeの機能を実行

「Insert Unicode: Insert from Hex Code」を選びます。

### コードの入力ボックスに"0085"と入力してEnter

?文字ですが、これでU+0085が入力されています。

## さて、検証

テキストファイルの中身はこうなっています。
空白部分にU+0085が挿入されています。

![スクリーンショット 2022-11-10 194819.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101034/a1de734f-fed1-3dbe-c9ec-a3bbcb7eb58e.jpeg)

以下のサイトにも書かれていますが、UTF-8では0xC285がNELですので、文書中に0xC285が埋め込まれていれば成功です。

http://www.unicode-symbol.com/u/0085.html

バイナリエディタ(VSCodeのHEX Editor)で確認してみると、たしかに0xC285が埋め込まれています。

![スクリーンショット 2022-11-10 194710.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101034/46036ed6-ef40-14c9-83ec-411979d248b8.jpeg)

試しに、このファイルの内容をFortniteにコピペしてみると、ビルボードの文字列が改行されていました。

![スクリーンショット 2022-11-10 202114.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101034/30de18c3-61ea-1f20-96eb-e1138f8968f0.jpeg)

# さいごに

技術ブログの集まりであるQiitaですが、文字コードの話でもOKのようですので、この記事を執筆いたしました。
アウトプットしてみると、結構濃いことしてるなぁと思ってしまいました…。
Ubuntu 20.04　VSCodeをコマンドからインストール

snapを使わずに、公式からダウンロードしてVSCodeをインストールする方法です。

```
wget -O code.deb "https://code.visualstudio.com/sha/download?build=stable&os=linux-deb-x64"
sudo dpkg -i code.deb
```

こんな感じでインストールスクリプト作りました。

https://github.com/t-yamanashi/install/blob/main/vscode.sh
PyTorch-geometricでOSError: /lib64/libm.so.6: version `GLIBC_2.27' not foundとなったとき

PyTorch-geometricのインストールに成功したが、モデルを実行したときに
OSError: /lib64/libm.so.6: version `GLIBC_2.27' not found
というエラーがでたときに行ったこと

https://github.com/pyg-team/pytorch_geometric/issues/3593
を参考にして対処した。

# 環境
OS: Linux
Python version: 3.10
PyTorch version: 1.12.1
CUDA version: 11.4

# PyTorch、PyTorch-geometricのインストール
PyTorchのversionが1.13だとPyTorch-geometricのインストールが失敗するので1.12をインストールした。（2022年11月10日現在）
https://pytorch.org/get-started/previous-versions/
```PyTorchのinstall
conda install pytorch==1.12.1 torchvision==0.13.1 torchaudio==0.12.1 cudatoolkit=11.3 -c pytorch
```

PyTorch-geometricは対応しているものをインストールした。
https://pytorch-geometric.readthedocs.io/en/latest/notes/installation.html
```PyTorch-geometricのinstall
pip install torch-scatter torch-sparse torch-cluster torch-spline-conv torch-geometric -f https://data.pyg.org/whl/torch-1.12.0+cu113.html
```

# エラーはどこで出ているか
torch_geometric.nnをimportしようとするとエラーが出てくる。
```
$ import torch_geometric.nn
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/x/anaconda3/envs/rd-torch3/lib/python3.10/site-packages/torch_geometric/nn/__init__.py", line 3, in <module>
    from .sequential import Sequential
  File "/home/x/anaconda3/envs/rd-torch3/lib/python3.10/site-packages/torch_geometric/nn/sequential.py", line 8, in <module>
    from torch_geometric.nn.conv.utils.jit import class_from_module_repr
  File "/home/x/anaconda3/envs/rd-torch3/lib/python3.10/site-packages/torch_geometric/nn/conv/__init__.py", line 25, in <module>
    from .spline_conv import SplineConv
  File "/home/x/anaconda3/envs/rd-torch3/lib/python3.10/site-packages/torch_geometric/nn/conv/spline_conv.py", line 16, in <module>
    from torch_spline_conv import spline_basis, spline_weighting
  File "/home/x/anaconda3/envs/rd-torch3/lib/python3.10/site-packages/torch_spline_conv/__init__.py", line 15, in <module>
    torch.ops.load_library(spec.origin)
  File "/home/x/anaconda3/envs/rd-torch3/lib/python3.10/site-packages/torch/_ops.py", line 255, in load_library
    ctypes.CDLL(path)
  File "/home/x/anaconda3/envs/rd-torch3/lib/python3.10/ctypes/__init__.py", line 374, in __init__
    self._handle = _dlopen(self._name, mode)
OSError: /lib64/libm.so.6: version `GLIBC_2.27' not found (required by /home/x/anaconda3/envs/rd-torch3/lib/python3.10/site-packages/torch_spline_conv/_basis_cuda.so)
```

torch-spline-convの中のSplineConvが原因でエラーが出るらしい。
# やったこと
torch-spline-convをアンインストールする。

```
pip uninstall torch-spline-conv
```
#
Ubuntu 20.04でKVMでブリッジを使う方法

ホスト⇔ゲスト
ゲスト⇔他のPC
で通信したい時に使います。


## デバイス名を調べる
```
nmcli con show
```

表示れい
```
NAME                 UUID                                  TYPE      DEVICE  
xxxxxxxxxxxx         xxxx-xxxx-xxxx-xxx-xxxxx              ethernet  enp4s0 
```
LANカードの物理デバイスは「enp4s0」と仮定します。
この部分は調べた結果に書き変えます。

## ブリッジ作成
```
sudo nmcli con add type bridge ifname br0
sudo nmcli con add type bridge-slave ifname enp4s0 master br0
```

## KVM  ネットワークインターフェースの設定
「ブリッジ br0：ホストデバイス enp4s0」に設定します。
![Screenshot from 2022-11-10 20-15-14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295814/f0eeb36e-2bf0-4a09-30c3-d905fd11331c.png)

これで通信ができるようになりました。
[Python] PyAutoGUIをimportした時にtkinterの見た目が変わる事

### 問題
PyAutoGUIをimportした時にtkinterの見た目が変わった。
importすると、しない時と比べてくっきり(小さく)みえるようになる。
### 解決
PyAutoGUIに含まれる
```Python
try:
   ctypes.windll.user32.SetProcessDPIAware()
except AttributeError:
    pass
```
が問題。
逆に、くっきり(小さく)したかったら上記のコードを追加すればよい。
Laravelの暗号化・復号化で注意すること！

Laravelには暗号化する機能があります。

先日、API連携時に以下のようなエラーが出ました。

```
ERROR: The MAC is invalid. {"exception":"[object] (Illuminate\\Contracts\\Encryption\\DecryptException(code: 0): The MAC is invalid. at
```

やろうとしていたこととしては２つの異なるLaravelで、アプリケーションAがアプリケーションBのAPIを叩いた時に認証情報を暗号化して送ろうとしました。
ただその場合、エラーとなります。

## 原因
結論、.envのAPP_KEYが異なるから！

どうやら暗号化にはAPP_KEYが関与しているようです。

Crypt::encryptStringで暗号化して、そのLaravel環境とは異なるAPP_KEYのアプリケーションで復号化(Crypt::decryptString)しようとすると上記のエラーになります。

逆に、APP_KEYが同一であれば異なるLaravel環境でも復号することができます。

## 解決手段
上機能ようにAPI連携の認証に利用する場合は、連携先のアプリケーションで暗号化し、その文字列を送信元のアプリケーションから送ってあげると復号することができます。
HTMLでinputのrequired属性を無視する

### HTMLでinputのrequired属性を無視する
複数のsubmitがあって、その中でただ単にPOST送信したい(例えば取り消しとか)時だった。
```HTML
<input type="submit" class="..." name="..." value="..." formnovalidate>
```
`formnovalidate`を入れればよい。
10進数を2進数に変更して指定の桁数で0埋めにする処理

```TypeScript
// 10 進数
const state1 = 2;

// 2 進数で変換
const num = state1.toString(2);

// 文字列にして0埋めする
var ret = ( '000' + num ).slice( -3 );

console.log(ret); // "010"がかえる
```
Pythonの出力結果をLinuxコマンドで変数に格納する

# Pythonの出力結果をLinuxコマンドで変数に格納する

以下のコマンドですることが可能です．`./sample.py`を実行したいスクリプトに変更してください．

```shell
result=`./sample.py`
echo ${result}
```

なお，以下のように引数を与えることも可能．

```shell
result=`./sample.py 1 2`
echo ${result}
```
[Django] 検索フォーム・仕組みの作り方

### Djangoで検索機能を追加する
Djangoで検索機能を追加するために入力された内容でURLにクエリを追加してリダイレクトする。
昔[teratailで回答](https://teratail.com/questions/rnmd0yb40w4di6)したやつを備忘録として残す。
```Python
def search(request):
	search_word = request.GET.get("q")
	# search_wordで検索
	return render(...)
```
```HTML
<input type="search" id="search-form">
<button onclick="clickSearch()">検索</button>
<script>
function clickSearch() {
	var search_catch = document.getElementById("search-form").value;
	if (search_catch) {
		window.location.href = "{{request.scheme}}://{{request.get_host}}/?q=" + search_catch;
	}
}
</script>
```
PythonとYouTubeAPIで急上昇の動画のデータを取ってくる

### やること
YouTubeAPIで急上昇動画のURLを取ってくる。

まず、GoogleCloudPlatformに行き、プロジェクトを作成して、YouTube Data v3というAPIを有効化します。「認証情報」をクリックして「認証情報」を作成を選び、「APIキー」を選択します。出てきたキーはコピーして取っておきます。
```Python
import googleapiclient.discovery

def getYouTubeTop10():
    API_KEY = "あなたのAPIキー"
    youtube = googleapiclient.discovery.build(
        "youtube", "v3", developerKey=API_KEY)
    request = youtube.videos().list(
        part="snippet,contentDetails,statistics",
        chart="mostPopular",
        maxResults=10, # ここで個数を指定する
        regionCode="JP" # ここで場所(国)の指定
    )
    response = request.execute()
    return response

def writeData(json_file, data_dict):
    # 辞書型をjsonに変換して保存
    with open(json_file, "w", encoding="utf-8") as f:
        json.dump(data_dict, f, indent="\t", ensure_ascii=False)

writeData("youtubetop10.json", getYouTubeTop10())
```
youtubetop10.jsonに、データが保存されます。
実行ファイルEXEのiconがちゃんと表示されない場合

### 問題
Pythonで、Pyinstallerを使ってEXEファイルを作ってたら、iconで画像を指定しているのにちゃんと表示されていないことがあった。
### 解決
キャッシュが原因らしい。
windows10の場合、`Windows + R` でファイル名を指定して実行を表示して、
`ie4uinit.exe -show`と入力してOKを押すと、指定した画像がアイコンとしてちゃんと表示された。
その他のバージョンの場合は、`ie4uinit.exe -ClearIconCache`と入力すればOK

[このサイト](https://novnote.com/pysimplegui-exe-icon-tips/638/)より
多言語FizzBuzzチャレンジ21日目:OCaml

## これまでのまとめ
https://qiita.com/tenteko/private/fc52f7aec63ba5f67854

https://qiita.com/tenteko/private/ca9813f0982370d0c901

https://qiita.com/tenteko/private/bc808ba59f6993019045

https://qiita.com/tenteko/private/74aa4c422196cb5cdeac

https://qiita.com/tenteko/private/ea22bd19360333f9ca85

https://qiita.com/tenteko/private/ec2f7c2f99229a55a7aa

https://qiita.com/tenteko/private/237556777f5c5546af6e

https://qiita.com/tenteko/private/264e4aca8a2ee6761a6c

https://qiita.com/tenteko/private/6e86fa0eeed9d24805ab

https://qiita.com/tenteko/private/f32baaf43fe0217b7fc7

https://qiita.com/tenteko/private/b44e1e5bfc91f6f3a52f

https://qiita.com/tenteko/private/333b9697c03561fb6158

https://qiita.com/tenteko/private/667f5f69eda60f221912

https://qiita.com/tenteko/private/eff296000ecbc7b43f07

https://qiita.com/tenteko/private/f5ea89c185b14a5952f3

https://qiita.com/tenteko/private/64a5814d35f73972bde9

https://qiita.com/tenteko/private/7981389372c7f6bdc073

https://qiita.com/tenteko/private/f6814b2e192e23298da8

https://qiita.com/tenteko/private/e3e498be93b847139a7d

https://qiita.com/tenteko/private/70f6a6588bc72acf27cf

## 本日のお品書き
なんだか一瞬Twitterで話題になったOCamlさん。

## FizzBuzz
- 関数型言語（だと思うん）だけど`for`もあることがわかったOCamlさん
- いや、意地でもパターンマッチと再帰でやりくりしてみます
    - パターンマッチ`h::rest`でリストの先頭とそれ以外をデコンストラクションしている

```ocaml:fizzbuzz.ml
let rec fizzbuzz x =
    match x with
    | [] -> print_string ""
    | h::rest ->
        if h mod 15 = 0 then print_endline "FizzBuzz"
        else if h mod 3 = 0 then print_endline "Fizz"
        else if h mod 5 = 0 then print_endline "Buzz"
        else print_endline (string_of_int h);
        fizzbuzz(rest);;

(* Erlangのlists:seq(1,100)相当　↓ *)
fizzbuzz (list.init 100 (fun x -> x+1));;
```

## おまけ：実行方法
```shell
docker run --rm --mount type=bind,source=$(pwd),target=/app -w /app ocaml/opam ocaml fizzbuzz.ml
```
【Ruby】変数が定義されているかを確認

# defined?を使用する

Rubyでは変数が定義されているかを確認するために`defined?`を使用できます。
`defined?`は変数やメソッドが定義済みの場合、式の種類を表す文字列を戻り値として返します。
未定義の場合、`nil`を戻り値として返します。

- 変数に値が代入されていると`"local-variable"`が返ってきます。
```ruby
> test = 111
=> 111
> defined? test
=> "local-variable"
```

- nilが代入されていても`"local-variable"`が返ってきます。
```ruby
> hoge = nil
=> nil
> defined? hoge
=> "local-variable"
```

- 変数に値が代入されていないと`nil`が返ってきます。
```ruby
> defined? foo
=> nil
```

- グローバル変数に値が代入されていると`"global-variable"`が返ってきます。
```ruby
> $global = 111
=> 111
> defined? $global
=> "global-variable"
```

- 以下の場合は`"assignment"`が返ってきます。変数に値は代入されていません。
```ruby
> defined? bar = 111
=> "assignment"
> p bar
nil
=> nil
```

- メソッドの場合は`"method"`が返ってきます。
```ruby
> defined? puts
=> "method"
```

- `defined?`の場合はエラーが返ってきます。
```ruby
> defined? defined?
Traceback (most recent call last):
        3: from /usr/bin/irb:23:in `<main>'
        2: from /usr/bin/irb:23:in `load'
        1: from /Library/Ruby/Gems/2.6.0/gems/irb-1.0.0/exe/irb:11:in `<top (required)>'
SyntaxError ((irb):7: syntax error, unexpected end-of-input)
```

# 参考

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

https://stackoverflow.com/questions/12110235/how-to-check-if-a-variable-exists-with-a-value-without-undefined-local-variable

https://medium.com/rubycademy/the-defined-keyword-in-ruby-b7a5a5a48e1e
kintone　CSSカスタマイズ


kintoneでCSSカスタマイズをした。

具体的には、ルックアップでグレーアウトしている部分の文字列が見辛かったので、
グレーアウトを白地にし、文字色をグレーから青にした。

上手く動作してよかった！
まずは字を他の色に変えたりして少しずつ応用できるように練習する。

▼参考
https://qiita.com/will-yama/items/1dccd51a01f679e22448
[C#] 文字リテラルに文字が多すぎます　←いや多くないが？

## 状況
```C#
string hoge = "<title>hoge"
string huga = Regex.Replace(hoge,'<Title>',"");
```
※Qiitaだと赤く注意してくれますが、Visual Studio 2022だと何も表示してくれません…

出力結果
```
error CS1012: 文字リテラルに文字が多すぎます
```
別に文字数多くないのに何故文字が多すぎるとか出るんすか…と思ってたら

## 「文字」と「文字列」って違うよね
C#では文字と文字列の扱いが明確に異なります

char型は「文字」を扱う
string型は「文字列」を扱う

文字（char型）はシングルクォーテーション「’’」
文字列（string型）はダブルクォーテーション「””」で囲うという決まりがあります

なので今回は
「「文字」リテラルに「文字」が多すぎます」
つまりシングルクォーテーションで文字の型なのに文字列じゃねーかっておっしゃっているんですね

基本中の基本っぽいのに他の言語と同じノリで使うとこうなります
文字と文字列の違いを意識しながら開発していかないといけないですね

## 余談1
```C#
var hoge = "a";
```
一文字でもダブルクォーテーションで囲えば文字列になります（当たり前ですが）
## 余談2

```C#
char huga = '𣖔';
```
このような漢字一文字でも冒頭の
「リテラルに文字が多すぎます」
というエラーが出る場合もあります
（他にも𧾷（足へん）、𩸽（ほっけ）など）
これはchar型が2バイトであり、2バイト以上の複雑な漢字は収まらないのでエラーになるようです
（これはchar型がunicodeをベースに作成されていることから起因しているそうです、詳しく調べねば）
vender/bundleにgemが入ってしまってどうしようもなくなったとき

タイトルの通りなんですが、
```ruby
budle install
```
するときに、オプションで
```ruby
 bundle install --path vendor/bundle
```
とつけると、何やら見慣れないファイルが・・・
そしてその中にはgemファイルがたくさん詰まっていて、Gitにプッシュするたびに大量のデータがいってしまい（私の時は6000個くらいありました）、Gitが止まって本当に困っていました。
そのときに見つけたのがこちらのサイトです。
https://techtechmedia.com/vender-bundle-solution/
本当にわかりやすく一発で解決したので、同じような事象でお困りの方はぜひ見てみてください。
スマート（かもしれない）ジュークボックスサーバーを作る

# １．はじめに
　googleAssistantにある`SOUNDBAR`デバイスとして振る舞うサービスを作り、音声指示によって送られてくる具体的なコマンドもだいたい把握できました。他にも操作指示はあると思うのですが、喋りつかれるので最低限の「再生」「停止」「セットリストの変更」ができれば個人的には十分です。それぞれの指示で送られてくるコマンドについては「[ＯＫ、グーグル。ジュークボックス、プレイ](https://qiita.com/SSaitou/items/7da8ead299fad0f002fb)」にまとめています。
　あとはそれらのコマンドに応じた振る舞いをするサーバーを作成するのみとなります。また、今回は全体の概要説明に留めて個々の具体的な作りは稿を改めようと考えています。
# ２．全体の造り
　簡単に全体の造りを説明しておきます。
![googleAssistantButlerSystem.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2696131/2471efd3-3617-2dfc-bbd6-d216b84d5046.png)

　google Homeへの音声指示はgoogleAssistantから「[フルフィルメント](https://developers.google.com/assistant/smarthome/concepts/fulfillment-authentication?hl=en)」(図中では'smart device butler')と呼ばれるAPIに対して「[インテント](https://developers.google.com/assistant/smarthome/concepts/intents?hl=en)」というJSON形式の送信データに変換されます（①）。フルフィルメントは送られてきたインテントの内容に応じてジュークボックスサーバーに再生や停止、セットリスト変更などの指示を送ります（②）。再生・停止のためにGoogleHomePlayerを実行したり、停止したりします（③）。
　また、ジュークボックスサーバーは動作状態情報やセットリスト情報をフルフィルメントへ戻します（④）。フルフィルメントはgoogleAssistantにジュークボックスサーバーの状態やセットリストの情報を返します（⑤）。
　そしてまた、動作確認やセットリスト作成を容易にするため、コマンドラインからジュークボックスサーバーへコマンドを送れるようにしました（⑥）。
# ３．プロセスとプロセスの間には
　システム（と呼んで構わないと思うのですが）全体は登場人物が多いのですが、ジュークボックスとしての機能に絞ると下図のような造りにしています。
![JukeboxServer_Structure.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2696131/dcc3f0b7-ed67-ab0a-44bd-16a1860b35a6.png)
　作り方としてシンプルなモックアップを作って思いつくままに欲しい機能を拡張していくというノンプランアプローチを採用しました。
　だいたい次のような段階を経ています。
1. ジュークボックスサーバーがGoogle Home Playerをexecで実行できるようにする。
2. CLIから再生指示や再生リストの送信をできるようにする。
3. フルフィルメントから再生指示や再生リストの切り替え指示をできるようにする。
4. ジュークボックスサーバーがGoogle Home Playerをfork&execで実行できるようにする。

　面倒なのはプロセス間通信（ＩＰＣ）とGoogle Home Playerの非同期実行でした。以下簡単に説明します。
## ３．１．ＩＰＣクラス
　図中では`Class IPC`が担当します。ジュークボックスサーバーに再生リストを作らせるためにCLIからmp3ファイルのパスを連続して送ったりしますが、こういう処理ではサーバー側の処理がちょっと遅れると拾いこぼしがおきたりするのでバッファ（というかキュー）を持たせるのが安全です。あんまり大仰な仕掛けを持たせるのも避けたかったので、ここではPHPのセマフォ関数にある共有メモリ系の機能を使いました。セマフォ関数にはもっとキュー向けのメッセージキュー機能があるのですが、メッセージキューにはメッセージキュー全体のメモリ割り当てがあり、mp3ファイルのパス情報のような比較的長い文字列を扱うとちょいちょいメモリ制約に当たりがちだったりするので（もちろん割り当てサイズを増やせば回避できるのですが）そちらは使いませんでした。
　やりとりのキューにはリングバッファとして使える配列構造を作成して、その配列を丸ごと共有メモリに押し込むというやり方をしています。サイズが大きくなるとコスト的にどうなのという気がしなくもないのですが、今回のようなかわいらしいサイズなら問題にはならないようです。
## ３．２．非同期実行クラス
　非同期実行はフルフィルメントが再生要求後の制限時間内に応答を返すために必要でした。ジュークボックスサーバーがGoogle Home Playerを同期実行（exec関数とかsystem関数とか）させるとフルフィルメントからの要求にジュークボックスサーバーが（再生終了するまで）応答を返せないのでフルフィルメントが待ってしまいます。
　Google Home Notifierのように即座に終了するものを使うと待ち時間は小さくなりますが、今度は曲の再生終了が拾えなくなり、リストに沿って順番に再生することができなくなります。
　非同期実行はよくあるfork&execをpcntl_fork()、pcntl_exec()で実現するだけですが、ジュークボックスサーバーの子プロセスとなるGoogle Home PLayerの動作状態を拾うのが面倒でした。PCNTL関数には[pcntl_waitpid()](https://www.php.net/manual/ja/function.pcntl-waitpid.php)があって、これを使えば子プロセスの状態を拾えそうですが、使い方にクセがありました（使い方を間違えているだけかもしれないのですが）。
# ４．ジュークボックスの造り
　ジュークボックスそのものは送られてきたコマンドを解釈してそれぞれのロジックに分岐実行させるswitch～caseの塊になっています。
　主な機能は再生、停止、再生リストの作成と再生リストをセットリストとして読み書きする機能、セットリストの切り替えといったものがあります。それらのロジックそのものは別に面白いものではないのですが、Google Home Playerはプロセスをkillしても再生が止まらないので、どうやって止めるかというのが多少の工夫どころでしょうか（単に無音のmp3を再生させれば良い）。
# ５．おわりに
　ジュークボックスのシステムはGoogle Home Player以外はPHP(PHP8.1.10)で作成しました。ボリューム的にソースコードなど出していませんが、（参考になるのかどうかわかりませんが）部分的なものについては稿を改めて出そうと思っています。
備忘録　selenium.common.exceptions.StaleElementReferenceException: Message: stale element reference: element is not attached to the page document　の解決法

seleniumで画像を一斉に取得してくるプログラムを使用していました。しかし、ある日急にタイトルにもある
```
selenium.common.exceptions.StaleElementReferenceException: Message: stale element reference: element is not attached to the page document
```
のエラーが表示されました。

ページドキュメントが添付されていない？昨日まで動いていたのに、、、と思いエラーでググっていたところ以下の記事を見つけました。
https://blog.ikappio.com/wait-for-elements-to-display-in-selenium-python3/

これによるとsleepの時間で要素が読み込めなかった可能性があるみたい。早速time.sleepの時間を１秒から３秒にしてみたところ解決しました。
【Twitter, Facebook】Web IntentでSNSへのシェア機能を実装する

# Web Intentとは？

簡単に言えば、特定のURLを踏むと各SNSの投稿画面へ遷移し、投稿したいテキストやURLが自動入力される、という機能が実現できます。

（例）下のリンク先に移動するとTwitterのツイート画面になる
https://www.twitter.com/share?text=%E3%83%86%E3%82%B9%E3%83%88%E3%81%A0%E3%82%88%E3%80%9C&url=https%3A%2F%2Fqiita.com%2F

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440643/f3f2d190-5fe3-cde3-bddc-215c5a4e7e05.png)


今回はSNSとしてTwitterとFacebookのふたつに関してまとめます

# Twitter

公式のDocsがあるので読みましょう

https://developer.twitter.com/en/docs/twitter-for-websites/web-intents/overview#tweet-or-reply

**エンドポイント**
`https://twitter.com/intent/tweet`

**クエリ**

詳細は[Tweet button - Tweet text components](https://developer.twitter.com/en/docs/twitter-for-websites/tweet-button/overview)を参照してください

|key|value|
|:--:|:--|
|text|本文|
|url|URLを共有するときに使います|
|hashtags|"#"記号なしで","区切り|
|via|twitterアカウント名を指定する|

**サンプル**

https://twitter.com/intent/tweet?text=%E5%85%AC%E5%BC%8F%E3%82%A2%E3%82%AB%E3%82%A6%E3%83%B3%E3%83%88%E3%81%A0%E3%82%88&url=https%3A%2F%2Fqiita.com%2F&via=Qiita&hashtags=Qiita%2Cqiita

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440643/3d141b4e-92da-41ce-7225-7ab350d59b2b.png)

### モバイルのネイティブアプリ
AndroidやiOSの場合、ネイティブのTwitterアプリがインストールされている端末でURLを開くと、アプリが自動で起動してくれます

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440643/1b25f7a6-df3d-e78a-4da8-2d45c7c00e4c.gif" width="300">

### 他のエンドポイント
Twitterへ投稿するURLとして `https://www.twitter.com/share`を紹介する記事が調べると結構見つかります。実際にアクセスしてみると確かに投稿画面が開き、クエリも同じように処理してくれます。 301リダイレクトも含めると、

- `https://twitter.com/intent/tweet`
- `https://www.twitter.com/intent/tweet`
- `https://twitter.com/share`
- `https://www.twitter.com/share`

あたりが使えるようです（執筆時点）。

# Facebook

主に二種類あるので分けます

### アプリIDが必要

公式のDocsがあるので読みましょう

https://developers.facebook.com/docs/sharing/reference/share-dialog

以下のMeta開発者ページで自身のFacebookアカウントを登録し、アプリIDを取得する必要があります

https://developers.facebook.com/

**エンドポイント**

`https://www.facebook.com/dialog/share`

**クエリ**
|key|value|
|:--:|:--|
|app_id|登録したアプリID（必須）|
|href|シェアするURL|
|hashtag|"#"記号をつけてひとつのみ|
|redirect_uri|シェアボタン押下した後にリダイレクトされるURL. 開発者ページで登録した自身のサイトでないとエラー|


**サンプル**
`https://www.facebook.com/dialog/share?app_id=${your_app_id}&href=https%3A%2F%2Fqiita.com%2F&hashtag=%23Qiita`

![スクリーンショット 2022-11-10 18.55.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440643/8147bb00-8e4b-ddc2-da4c-e0c8630b1dee.png)



### アプリID不要

太古から存在するエンドポイントのよう。ただ公式のDocsには記載がなく、一時期は非推奨になったものの利用するサイトの多さから復活したとか言われている（要出典）

https://stackoverflow.com/questions/27973009/is-facebook-sharer-php-endpoint-not-deprecated-anymore

**エンドポイント**

`https://www.facebook.com/sharer/sharer.php`

**クエリ**
|key|value|
|:--:|:--|
|app_id|登録したアプリID（任意：シェアした後の表示が少し変わる）|
|u|シェアするURL|
|hashtag|"#"記号をつけてひとつのみ|


**サンプル**
https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fqiita.com%2F&hashtag=%23Qiita

### モバイルのネイティブアプリ
Twitterとは異なり、Facebookのネイティブアプリがインストール済みでも自動では起動してくれません。各プラットフォーム専用のFacebook SDKを利用する必要があります

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440643/4c540359-c395-06ed-f54b-5ac306df7607.gif" width="300">
【CSS】colorの指定方法

# キーワード

「red」や「black」等のキーワードを指定する方法。

一目で指定した色がイメージできるのが特徴。

```css
/* 例　*/
p{
  color:white; /* 白 */
  color:black; /* 黒 */
  color:red; /* 赤 */
}
```

# カラーコード

「# + 16進数のカラーコード(6桁又は3桁)」で指定する方法。

カラーコードは2桁毎にそれぞれ「赤(R)、緑(G)、青(B)」の数値を表している。

3桁の場合は連続する数値の指定となる。（「#ff0」は「#ffff00」となる）

```css
/* 例　*/
p{
  color:#ffffff; /* 白 */
  color:#000000; /* 黒 */
  color:#ff0000; /* 赤 */
  color:#f00; /* 赤 */
}
```

# RGB()、RGBA()

三原色である「赤(R)、緑(G)、青(B)」の数値で指定する方法。

「rgb(0,255,122)」の様に0〜255の数値で指定する。

透過度を指定することもでき、その場合はRGBにA(Alpha)を加えた「rgba( 255, 0, 0, 0.5)」のように指定する。(0〜1の数値)

```css
/* 例　*/
p{
  color:rgb(255,255,255); /* 白 */
  color:rgb(0,0,0); /* 黒 */
  color:rgb(255,0,0); /* 赤 */
  color:rgba(255,0,0,0.9); /* ほぼ透明な赤 */
  color:rgba(255,0,0,0.5); /* 半透明な赤 */
  color:rgba(255,0,0,0); /* 赤 */
}
```

# HSL()、HSLA()

色相(Hue)、彩度(Saturation)、輝度(Lightness)を指定する方法。

「hsl(328,100%,50%)」の様に、色相は0〜360度、彩度、輝度は0〜100%で指定する。

RGBと同様に透過度を指定することができ、その場合は「hsla()」となる。

```css
/* 例　*/
p{
  color:hsl(360,100%,100%); /* 白 */
  color:hsl(360,100%,0%); /* 黒 */
  color:hsl(360,100%,50%); /* 赤 */
  color:hsla(360,100%,50%,0.9); /* ほぼ透明な赤 */
  color:hsla(360,100%,50%,0.5); /* 半透明な赤 */
  color:hsla(360,100%,50%,0); /* 赤 */
}
```
エンジニア向け：CTO目線のこんな企業に転職しては駄目だTOP５ その５　管理者（CTO、VPoE、EM）が忙しすぎる

CTOとして20年、CTO10社、技術顧問20社以上の森川目線でのこんな企業に転職しては駄目ランキングをまとめてみました！

もちろんエンジニア向けです。

その５です。

# ５．管理者（CTO、VPoE、EM）が忙しすぎる

　通常、管理者は忙しいというのが当たり前です。と思ってる方多いと思いますが、実は忙しい管理者って仕事出来ない管理者なんです。

　何故なら、管理者は裁量を持ってます。自分の裁量の中で人を採用できたり、人を育てたり、人を配置する事が出来ます。

　それでも忙しいという事は理由が２つ。

　・適切に裁量を発揮できないので忙しくて、しかたない管理者

　・仕事が忙しいのが好きなので忙しくしている管理者

　（管理者のエンジニアの方々ごめんなさい。。）

　僕が見てきた中で言うと両方多いですが、後者の方が多い感じがします。

　どちらにしても、こういう管理者がいるという事は、会社にとってボトルネックです。癌です。

　管理者が忙しいと
　・ジャッジが遅い
　・フォローしてくれない
　・新しい事が始まらない
　・相談に乗ってくれない
　・言ったことを忘れられる

　等など、こんな会社に転職して良いわけがありません。

　面談の時間に遅刻するCTOもたまにいます。これなんかは最悪な状態で、会社にとって人財は最も優先すべきタスクなのに、日々の業務に追われて優先すべきタスクを見失ってる状態です。

　優秀なCTOは、暇ではないですが、突発の物事に対応できる様に融通がきく働き方をしてます。優先順位付けが正しく出来ているので、ジャッジのタイミング・内容でブレる事もありません。相談にものってくれるし、言った事を忘れたりしません。自身をコントロール出来ている状態です。

　是非、面談の際に忙しさを聞いてみて下さい。業務の優先順位を聞いてみても良いかも知れません。人財と答えた会社は良い会社としての要素を持ってると思います。

　面談に遅刻された場合は絶対にやめた方が良いでしょう。

[CTO目線のこんな企業に転職しては駄目だTOP５ その１　CTOが居ない](https://qiita.com/k1morikawa@github/items/eb6ae4e10883b5203be4)
[CTO目線のこんな企業に転職しては駄目だTOP５ その２ CTOがエンジニア出身でない](https://qiita.com/k1morikawa@github/items/4f6ae4f94bdfa543b256)
[CTO目線のこんな企業に転職しては駄目だTOP５ その3　新卒エンジニアを取ってない](https://qiita.com/k1morikawa@github/items/65b2c2b40cb973945d7a)
[CTO目線のこんな企業に転職しては駄目だTOP５ その４　副業を許してない](https://qiita.com/k1morikawa@github/items/3cc4036ec600e1ad0cc8)
[CTO目線のこんな企業に転職しては駄目だTOP５ その５　管理者（CTO、VPoE、EM）が忙しすぎる](https://qiita.com/k1morikawa@github/items/c57ea172001705304264)
エンジニア向け：CTO目線のこんな企業に転職しては駄目だTOP５ その４　副業を許してない

CTOとして20年、CTO10社、技術顧問20社以上の森川目線でのこんな企業に転職しては駄目ランキングをまとめてみました！

もちろんエンジニア向けです。

その４です。
# ４．副業を許してない

　エンジニアにとって副業は、成長へ必要なエッセンスです。業務上だけのプロジェクトだけだと成長の範囲が限られてきますし、速度が遅くなっていしまいます。

　なにしろエンジニアは、覚える事が山程あります。

　・プログラミング

　・OS

　・ネットワーク

　・ミドルウェア

　・サーバー

　・ネットワーク

　・etc

　しかも、それぞれに複数個。プログラミングであれば、Java,PHP,GO,Python等。OSだとLinux,Mac,Windows。

　これらの事を本やネットで勉強する事も出来ますが、やっぱり業務で一度経験すると深みが全く変わってきます。

　それを自社の業務だけで与えるなんて事は不可能に近いです。

　なので、副業で経験していくのが成長のために必要だと思います。

　別の会社で別のプロジェクトで別の人たちと別の環境の開発をやる。しかもその社員個人のやる気の範囲で勉強し成長出来ます。

　最終的に個人のプライベートの状況によって副業が出来ない時期だったり、気持ちが乗らない時期、良い副業が見つからない時期も出てくるとは思います。

　しかし、それはこちらの選択であって、可能性減る様な会社への転職はやめた方が良いです。

　会社的に副業を禁止にしてる会社の言い分としては

　・忙しくなり業務に支障がでる

　・他社へ転職してしまうリスクがある

　・自社の悪い部分が目立ってしまう（隣の芝は青く見える）

　とかあると思いますが、

　現在、リモートワークの中で空き時間の中で勉強（副業）する事で成長するのは喜ばしい事だし、副業で収入が上がることで、給与不満は解消され、やり甲斐にフォーカスする様になるでしょう。

　本来の良い会社のみ選択されるという事です。

転職の際には、副業についての考え方を是非聞いてみて下さい。

[CTO目線のこんな企業に転職しては駄目だTOP５ その１　CTOが居ない](https://qiita.com/k1morikawa@github/items/eb6ae4e10883b5203be4)
[CTO目線のこんな企業に転職しては駄目だTOP５ その２ CTOがエンジニア出身でない](https://qiita.com/k1morikawa@github/items/4f6ae4f94bdfa543b256)
[CTO目線のこんな企業に転職しては駄目だTOP５ その3　新卒エンジニアを取ってない](https://qiita.com/k1morikawa@github/items/65b2c2b40cb973945d7a)
[CTO目線のこんな企業に転職しては駄目だTOP５ その４　副業を許してない](https://qiita.com/k1morikawa@github/items/3cc4036ec600e1ad0cc8)
[CTO目線のこんな企業に転職しては駄目だTOP５ その５　管理者（CTO、VPoE、EM）が忙しすぎる](https://qiita.com/k1morikawa@github/items/c57ea172001705304264)
エンジニア向け：CTO目線のこんな企業に転職しては駄目だTOP５ その3　新卒エンジニアを取ってない

CTOとして20年、CTO10社、技術顧問20社以上の森川目線でのこんな企業に転職しては駄目ランキングをまとめてみました！
もちろんエンジニア向けです。

その３です。

# ３．新卒エンジニアを取ってない

　新卒エンジニアを取ってない会社というのは、

　・育てるリソースがない

　・利益がすくないので、即戦力しか無理

　等の理由があると思います。

　＊もちろん、立上げベンチャーに創業メンバーやそれに近いメンバーとして参画する場合は、この状態は受け入れるしか無いと思います。

　実は、この新卒エンジニアを取ってない状態は、非常に勿体無いんです。

　エンジニアという職種は、若くてもあっという間に成長していきます。１年目で１０年レベルのエンジニアを超えていく事もよくあります。

　これは、業務自体がノウハウの領域よりも自己学習で解決できる部分が多いためです。業務経験に依存されない職種なんです。

　例えば、コミュニケーション力等は、沢山の人と話したり、色んな種類の人と喋ったりして、話題の作り方、リアクションの仕方等を習得していきますが、プログラミングに関しては、ネット上に様々な情報が転がっており、自分ひとりで意欲さえあればドンドン成長していく事が出来ます。新規で作ったり、生産性の部分では、経験はあまり必要ありません。そして保守性や再利用性等の部分もオープンソースを読んだりすると他人のソースコードから適切なソースコードの書き方をマスターする事が出来ます。

　経験はあまり必要ないのでドンドン新卒エンジニアを取るべきなのです。

　当然、教育が必要なので既存の社員とのバランスも重要だし、新卒エンジニアを採用するのはリスクが大きいとも思えますが、優秀な新卒エンジニアを採用できれば１年くらいでリーダークラスのエンジニアになるでしょうし、３年もすれば中核メンバーとなるでしょう。若いエンジニアのパフォーマンスはリミットレスです。

　この価値ある新卒エンジニアを取ってない企業は成長力が弱いし、そこに経営者が気付いてないという事は、エンジニアが分かってない経営者の会社です。　

　新卒エンジニアを取ってない会社に関しては十分注意して転職判断が必要です。

　ちなみに下記は、新卒エンジニアを取るコツです（企業向け）
新卒エンジニアを取るコツとしては、

　１．他職種とまとめてとらない
　　営業、プロディーサー、ディレクター、エンジニア等一緒に総合職で採用する会社もありますが、これでは優秀なエンジニアを見つける事はできません。エンジニアはエンジニアで新卒採用に動いて下さい

　２．コミュニケーションを重視しない
エンジニアに必要なのは、論理的思考力や思考速度等の地頭力と柔軟性、努力できる力、興味を持つ力等の人間力です。
　　ここをコミュニケーションが下手だからと言って切り捨てないで引き出すための面談が必要となります。
　　例えば、ギフテッドで特徴として、
　　・学習能力が高い
　　・思考能力が高い
　　・好奇心旺盛
　　・完璧主義
　　等があります。
　　正にこれです。
　　Gifted childの様な将来の天才プログラマーを見つける様な面談を検討して下さい

[CTO目線のこんな企業に転職しては駄目だTOP５ その１　CTOが居ない](https://qiita.com/k1morikawa@github/items/eb6ae4e10883b5203be4)
[CTO目線のこんな企業に転職しては駄目だTOP５ その２ CTOがエンジニア出身でない](https://qiita.com/k1morikawa@github/items/4f6ae4f94bdfa543b256)
[CTO目線のこんな企業に転職しては駄目だTOP５ その3　新卒エンジニアを取ってない](https://qiita.com/k1morikawa@github/items/65b2c2b40cb973945d7a)
[CTO目線のこんな企業に転職しては駄目だTOP５ その４　副業を許してない](https://qiita.com/k1morikawa@github/items/3cc4036ec600e1ad0cc8)
[CTO目線のこんな企業に転職しては駄目だTOP５ その５　管理者（CTO、VPoE、EM）が忙しすぎる](https://qiita.com/k1morikawa@github/items/c57ea172001705304264)
エンジニア向け：CTO目線のこんな企業に転職しては駄目だTOP５ その２ CTOがエンジニア出身でない

CTOとして20年、CTO10社、技術顧問20社以上の森川目線でのこんな企業に転職しては駄目ランキングをまとめてみました！

もちろんエンジニア向けです。

# ２．CTOがエンジニア出身でない

　これが結構、罠です。

　CTOって経営者でもあり社長や他の役員とも話す必要があります。

　なので、コミュニケーション能力も求められます。

　そのためコミュニケーション力が高く、開発について少し分かってる人がCTOと名乗ってるパターンが結構あります。

　会話すると良いテンポでこちらの話もよく聞いてくれるので思わず魅力を感じてしまうエンジニアもいるでしょう。

　しかし、プログラミングをした事のないCTOというのは、エンジニアの気持ちが正直わかりません。エンジニアにとっての価値がわかりません。

　エンジニアにとっての価値等指標化するのはとても難しいです。プログラミングを沢山やって、色々な開発をやって苦労したり喜びや達成感を感じたりする事で生まれてくる大事な価値観は、指標化出来ないので、プログラミングした事がない人には伝える事が非常に難しいです。出来るのかもしれませんが、僕は諦めてますｗ

　わからないので、何がものさしになるかと言うと、売上・利益等のPLでしかエンジニア、開発組織を図ることができません。これは仕方のないことです。

　仕方のない事だから困るんです。

　全てをわかり易くエンジニアから説明しなければなりません。

　例えば、アクセス集中でサーバー負荷でサイトダウンが起きた時に、エンジニア同士であれば、2,3会話をすれば状況が伝わるし、今後どうすれば良いか決まります。

　しかし、プログラミングをやった事の無い人にこれを説明するには、1から10まで全てを説明しなければなりません。これは時間も掛かるし、ストレスも掛かります。

　プロジェクト進捗でも同様です。何故遅れているのかを説明するのに、ライブラリーの問題で動作が不安定でちょっと先が見えませんと報告しても理解してもらえません。

　先が見えないという報告では受け入れてもらえません。これに対して、先が見える形で説明する必要があります。

　時間が掛かってでも伝われば良いですが、伝わらない事の方が多いです。

　その結果、エンジニアは会話を諦めます。言っても仕方ないと思うようになります。

　そして優秀なエンジニアは辞めていきます。

　これがエンジニア出身でないCTOがいる会社の現実です。

　＊もちろん、頑張ってらっしゃる会社も存在はすると思います。

　転職する前にCTOの経歴についてチェックをしてみて下さい。

[CTO目線のこんな企業に転職しては駄目だTOP５ その１　CTOが居ない](https://qiita.com/k1morikawa@github/items/eb6ae4e10883b5203be4)
[CTO目線のこんな企業に転職しては駄目だTOP５ その２ CTOがエンジニア出身でない](https://qiita.com/k1morikawa@github/items/4f6ae4f94bdfa543b256)
[CTO目線のこんな企業に転職しては駄目だTOP５ その3　新卒エンジニアを取ってない](https://qiita.com/k1morikawa@github/items/65b2c2b40cb973945d7a)
[CTO目線のこんな企業に転職しては駄目だTOP５ その４　副業を許してない](https://qiita.com/k1morikawa@github/items/3cc4036ec600e1ad0cc8)
[CTO目線のこんな企業に転職しては駄目だTOP５ その５　管理者（CTO、VPoE、EM）が忙しすぎる](https://qiita.com/k1morikawa@github/items/c57ea172001705304264)
URQL の devtool を Chrome で動かす

# 概要

GraphQL クライアントライブラリの一種である [URQL](https://formidable.com/open-source/urql/) でも　devtool を導入し、クエリ結果及びキャッシュの状態を確認できるようにする。

# バージョン情報

- urql 3.0.3
- urql-devtools 2.6.3
- @urql/devtools 2.0.3
- Google Chrome 106

# 前提

`urql` はインストール済みで既に使用中であることを前提とする。

# 手順

Chrome 拡張をインストール

https://chrome.google.com/webstore/detail/urql-devtools/mcfphkbpmkbeofnkjehahlmidmceblmm

devtool 用の　exchange (urql におけるミドルウェアやプラグインのようなもの) をインストール

```bash
# npm
npm i @urql/devtools

# yarn
yarn add @urql/devtools
```

クライアントセットアップ時に exchange をインストール。　(デフォルトの exchange を上書きしないようにする)

```ts
import { createClient, defaultExchanges } from 'urql'
import { devtoolsExchange } from '@urql/devtools'

const urqlClient = createClient({
  url: '/api/graphql',
  exchanges: [devtoolsExchange, ...defaultExchanges]
})
```

Chrome を開いて、 Urql タブを開くと devtool が動いてるのが確認できる。

![スクリーンショット 2022-11-10 18.55.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/914610/bfb7b224-19cd-5c81-ce70-83711beda710.png)