OmniAICreator/Qiita-1.07M huggingface dataset:
私の考えるエンジニアの習得スキルのサンクコストとか要求難易度ふり幅が大きい案件（エンジニアスキルの振り方）

----------------------
# 1. webフレームワークを用いた開発案件
難易度ふり幅：★★★★★

## 要求スキル

- 基本的に[UI][API][DB]の知見がある程度ないとすぐに詰まる。
- 共同開発ならgitの知識も最低限必要
- 案件によってフォルダ・ファイルが無限に増える。
- 人の作ったソースコードバグを数分で治すスキルを求めてくる客もいる。
- デバッグ方法のスキルも暗黙的に実用スキルを求められる。
- テストコードの知識も幅広さを求められる。
- webフレームワークが多すぎる。案件毎にそのwebFWと相性のいいORMやDBの知識もさらに求められる。
- 頻繁にwebFWがバージョンアップデートし、バージョン上げると今までのライブラリと相性悪くなるとかよく起きる。
- 頻繁なバージョンアップによる機能追加とそれに適応するためのライブラリ管理方式の最新知識が常に求められる。
- バージョンバグを防ぐためdockerなどの仮想化技術を用いた開発知識が必須になる。
- インフラをAWS等のクラウドで開発するとき、疎結合化するため各種サービスの知見が必要になる。

## 個人的考察：
- webフレームワークを用いた開発案件はITエンジニアの案件母数を占めているので、使えるようになると仕事に困ることはなくなる。
- webフレームワーク習得は、メジャーなものを１つ習得してから、node.js系しかやらないとか、python系しかやらないとか好きなほうにスキルを割り振っていきたい。
- （当方はrails/flask/django/reactを嗜んでいるが、難しすぎるやつは三か月位でおさらばする）
- webフレームワークは覚えておいて損はないが、求められる知識が広いが故に「出来て当然だろう？」と理不尽なことも結構起こる。
- インフラとかに自信があったら得意分野を伸ばすためにあえてwebフレームワークに関わる案件を避けても良いかも。


----------------------
# 2. DPETL・MLOPS・インフラ設計でOSSやクラウドサービスでのソリューション提案力の使用を求められる案件
難易度ふり幅：★★★☆☆

## 要求スキル
- アプリパフォーマンスを最適化するために、アプリの知見も必要
- インフラ最適化のためのセキュリティ、ネットワークの知見は必要
- 要件定義では咀嚼力・設計段階では知識の幅広さを求められる
- 提案力はどんな技術を使ってもOKな所ほどOSSやクラウド等知識の幅広さが求められる。
- レガシー環境の移行案件だとレガシー技術を学ぶ必要が出てくる


## 個人的考察：
- 知識の広さがものをいう案件なので、資格試験の学習で得られる知識も役立つ
- 頻繁にバージョンアップするFWよりは求められるスキルにムラがなく、学習にやりがいを感じれる


----------------------
# 3. SRE的な働きが求められる案件

難易度ふり幅：★★★☆☆

## 要求スキル

- 基本的にインフラコード化（IAC）のterraformのスキルを求められる
- リポジトリからのCICD自動化処理コードを書くスキル（github actions）（cloudbuild）等を求められる
- アプリパフォーマンスを最適化するために、アプリの知見も必要
- インフラ最適化のためのセキュリティ、ネットワークの知見は必要
- 一番詰まったり、設計開発で時間を使わせるのはIAMロール等の権限設計だったりする


## 個人的考察：
- インフラやデプロイの知見は求められつつも、慣れるとアプリ開発よりポジション的に求められるスキルが限定される所が楽。
- webフレームワーク以外の部分を担当する場合、要求難易度ふり幅が小さい印象。
- （AWSだったらIAMロール）など権限部分さえ理解できれば怖くない。
Google カレンダーの変更通知を Slack に飛ばす Google Apps Script

家族で使っている共有 Google カレンダーの変更通知を家族 Slack に飛ばす Google Apps Script を書いた。

https://github.com/hoto17296/google-calendar-event-notificator

動いている様子はこんな感じ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16369/11fc4366-34b5-2280-35e7-7e0a239c4c21.png)

細かい実装はリポジトリを見てもらうとして、大まかな仕組みといくつかハマったポイントについて書いていく。

## 動作する仕組み
1. カレンダー予定が変更される (予定の作成,更新,削除)
2. Google Apps Script (以下 GAS) が起動する
    - GAS のトリガー設定で「イベントソース: カレンダー」を設定するだけでできる
3. GAS 内で Slack Incoming Webhook を使って Slack にメッセージを飛ばす

簡単！

## 開発環境
GAS は Web 上のエディタで直接書くこともできるが、コードを Git で管理したいし TypeScript 使いたいので、Google 公式の GAS CLI である clasp を使って開発環境を作った。

https://github.com/google/clasp

`clasp login` して `clasp create ...` して適当に TypeScript 書いて `clasp push` したらもう動かせるようになるので本当に簡単で、「うひょーーー GAS 開発ぜんぜん楽勝じゃねえか」と思われた。しかし...。

## カレンダーの変更内容を簡単に取得できない
前述の通り GAS ではカレンダーの変更時にトリガーすることができる。

**しかしイベントとして取得できるのが「カレンダー ID のみ」である。**

つまり「このカレンダーで何らかの変更があったよ」まではわかるが「どの予定が変更されたか」まではわからない。これは公式ドキュメントにも記載されており、「変更内容が知りたければ nextSyncToken を保持しておいて増分同期してね」的なことが書かれている。

https://developers.google.com/apps-script/guides/triggers/events?hl=ja#google_calendar_events

**何故こんな仕様に？？？**

言っていることはわかるがとにかくめんどくさい。

仕方ないのでこのような実装を書いた。

- User Properties に syncToken を保持するようにする
- GAS 実行時に前回分の syncToken が存在しない場合、現在時刻からの予定のフルスキャンを行い、syncToken を入手して User Properties に保存する
- GAS 実行時に前回分の syncToken が取得できる場合、それを使って予定の差分を入手する

(コードの詳細は冒頭に貼ったリポジトリを参照)

## 予定の新規作成と更新の区別がつかない
今回は「新規作成」か「更新」か「削除」かによって Slack メッセージの色を変えたかったので、それらを区別する必要があった。

しかし前述の増分更新で得られる Event オブジェクトはあくまで「(変更があった) 予定の詳細」を返してくれるのみで、「どのような変更があったか」は得られない。

「削除」だけは簡単に識別できて、予定の `status` というプロパティが `cancelled` になっていれば「予定が削除されている」=「キャンセルされた」と判断できる。

https://developers.google.com/calendar/api/v3/reference/events?hl=ja

問題は「新規作成」と「更新」の区別で、これはもうどうやっても無理な気がしたので、 **「予定の作成時刻が10秒以上前であったら更新」** という方法で識別することにした。10秒のラグを設定したのは、カレンダーの予定変更タイミングと GAS 発火タイミングで若干遅延がある可能性を考慮したため。(実際はかなり速く GAS が起動するので、ここは3秒とかでもいいかもしれない)

## ES Modules (import/export) が使えない
コードを書いていたらボリュームが大きくなってきたので、普通の TypeScript のノリでファイルを分割したところ、うまく動かなくなってしまった。

GAS は ES Modules (import/export) をサポートしておらず、そもそもモジュールという概念がなく (？)、ファイルを分割しても名前空間が共有されるという仕様らしい。

例えば `utils.gs` 内で `foo()` という関数を定義した場合、別ファイルの `main.gs` 内からは特に import などを明示しなくても `foo()` という関数が使える。

楽といえば楽だが、今回は TypeScript で書いているので相性が悪い。

TypeScript で

``` ts:main.ts
import { foo } from 'utils'

function main() {
    foo()
}
```

こんなコードを書いていると、clasp でトランスパイルしたときに

``` js:main.gs
// import { foo } from 'utils'

function main() {
    _module1.foo()
}
```

こんな感じになる。

import 文は勝手にコメントアウトされるくせに、 `foo()` の呼び出しはどこかにあるモジュールを参照している風になり、「_module1 など無い」とエラーが出る。めんどくさい。

clasp 公式では「いくつかの workaround があるよ」と紹介しているが、どれも一長一短ありケースバイケースな感じがする。

https://github.com/google/clasp/blob/master/docs/typescript.md#modules-exports-and-imports

<del>Webpack 使うのが一番良さそうではあるが、設定ファイルを書くのがめんどくさかったのでやめた。</del>

parcel や ncc も使ってみたが、別の理由でうまくいかなかった。(詳細は割愛)

最終的にどうしたかというと、ビルド時に「import 文は消して全 ts ファイルを結合する」という原始的な方法で解決した。だって TypeScript のトランスパイルは clasp がやってくれるのだし...。

``` console
$ cat src/*.ts | grep -Ev '^import' > dist/bundle.ts
```

この方法だと npm モジュールを使うことなどができないので注意が必要だが、シンプルだし別の bundler を入れなくてもよいので、場合によってはかなりいいのではないかと思う。
JSONオブジェクトをBeanに変換する

APIを使用して取得してきたJSON形式のデータを型変換して、Beanに格納する処理についてです。
インタフェースを通して外部システムからデータを取得して、そのデータをBeanに格納するために、データをBeanの型に変換する必要があります。
![スクリーンショット 2023-02-18 8.55.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551832/89248b14-c7cf-2fd9-fe04-6344f38c24bd.png)

## 前提
外部システムから取ってきたデータは以下のJSON形式です。
```json
{"catList":[{"id":"1",name:"トラ吉","age":"3"}]}
```

クラスはAnimalBeanクラスと、その子クラスであるCatBeanクラス。AnimalBeanの中にCatBean型のListがあります。

#### AnimalBean.java
```java

public class AnimalBean {

    private List<CatBean> catList = null;

    public List<CatBean> getCatList() {
        return catList;
    }

    public void setCatList(List<CatBean> catList) {
        this.catList = catList;
    }
}
```

#### CatBean.java
便宜上全てString型で定義
```java

public class CatBean {

    private String id = null;

    private String name = null;

    private String age = null;

    public String getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public String getAge() {
        return age;
    }

    public void setId(String id) {
        this.id = id;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(String age) {
        this.age = age;
    }
}
```

JSONのデータはCatBeanクラスで定義した変数名と一致します。
CatBeanクラスの変数の中にJSONのデータが入り、AnimalBeanクラスで定義しているcatListに、id,name,ageが格納される流れです。

## JSONObject.toBean
JSONObejectクラスに用意されているJSONオブジェクトをBeanに変換してくれるメソッド。
```java
JSONObject.toBean(変換したいJSONオブジェクト,変換先クラス);
```

## JSONConfig
JSONオブジェクトをBeanに変換するときにBeanやリストの型を設定するクラス。
変換先Beanの子項目に型を設定するときに使用する。
今回はAnimalBeanのcatListにデータを格納したいので、外部システムから取得したデータをcatListの型に変換する必要がある。そのときcatListに変換先の型を指定する必要がある。
以下のように設定するだけでは中身の項目(catList)の型を指定することはできない。

```java
JSONObjectBean(前提で記述したJSONオブジェクト,AnimalBean.class);
```
そこでJSONConfigを使用する。
```java
private JsonConfig createConfig() {
    JsonConfig jsonConfig = new jsonConfig();
    jsonConfig.setRootClass(AnimalBean.class); //親クラスの指定
    Map<String,Class> classMap = new HashMap<String,Class>();
    classMap.put("catList",CatBean.class); //親クラスに格納されているcatListの型を設定
    jsonConfig.setClassMap(classMap); //jsonConfingにセット
    return jsonConfig
}

JsonConfig jsonConfig = createConfig();
AnimalBean res = (AnimalBean)JSONObject.toBean(変換したいJsonオブジェクト,jsonConfig);
```
これでcatListがCatBean型になる。

## 全体的な処理
```java

public AnimalBean getCatInfo(省略) {
    String res = APIを使用して外部システムからJSON形式のデータをString型で受け取るメソッドの呼び出し(前提で記述したデータが返ってくる)

    Map<String,Class> classMap = new HashMap<String,Class>();
    classMap.put("catList",CatBean.class); //親クラスに格納されているcatListの型を設定
    JsonConfig jsonConfig = new jsonConfig();
    jsonConfig.setRootClass(AnimalBean.class); //親クラスの指定
    jsonConfig.setClassMap(classMap); //jsonConfingにセット

    AnimalBean resBean = (AnimalBean)JSONObject.toBean(res,jsonConfig);

    return resBean
}
```
これでAnimalBeanのcatListに外部システムから取得したデータを格納することができます。

## 終わり
外部システムからデータを取得してBeanに格納する処理を簡単に書きました。
今の案件は外部システムから情報を取得する事が多いので、これからもよく使いそうです。
何かご指摘あればお願いいたします！
ServiceNowでヘッダやボディに特定の文字列を含むメールの受信拒否の設定

Version: Tokyo, Vancouber
# Email Filters
ServieNowの System Mailbox - Filters にEmail Filtersというものがあり
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193272/c2310bcf-7982-0f84-2aa6-ee9cc348fd64.png)
Ignore Headerは受信したメールのヘッダーに特定の文字列が含まれるときに受信を拒否しているようで
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193272/32ebaca6-2bfe-fa51-4fa1-b93499612de2.png)
Ignore Subjectは受信したメールのSubjectに特定の文字列が含まれるときに受信を拒否しているようです
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193272/303d459e-dc50-9c0f-76b1-4fc9cba5d814.png)

:::note info
先日見た他のインスタンスと自分のPDIで存在するFilterの種類と内容が違うような…バージョン違いかな…？
:::

同じようにボディに特定の～でも受信拒否を設定することが出来るはずです

ServiceNowのインスタンスから送信されるメールには X-ServiceNowなんちゃらというヘッダが付いてFilterで受信拒否されるようです これはServiceNowインスタンスが自動配信するメールが複数のインスタンス内でループしてしまうことを防ぐ仕組みのようです

--

2024-04 DefaultのEmail Filterはドキュメントによると

https://docs.servicenow.com/bundle/vancouver-platform-administration/page/administer/notification/concept/c_EmailFilters.html

以下のようです

| Filter | Descrioption | 
|:---:|:-----------:|
| Ignore VCAL | 	Ignores all email containing vCalendar requests. This filter prevents inbound email actions from creating unnecessary incident records when the instance receives a response to sent email. vCalendar requests in email responses are identified by the EmailUtils script include. |
| Ignore header | 	Ignores email that contains specific headers. This filter overrides the glide.pop3.ignore_headers property. |
| Ignore sender | 	Ignores email from specific senders. This filter overrides the glide.pop3.ignore_senders property. Tip: To ignore emails from untrusted domains and addresses, consider setting up a system address filter instead. For more information, see System address filters. |
| Ignore subject | 	Ignores email with specific terms or phrases in the subject line. This filter overrides the glide.pop3.ignore_subjects property. This filter might not apply to emails arriving from unknown users. Unknown users can be locked out.|
| Move spam to junk folder | 	Moves email identified as spam to the Junk folder. This filter checks for the value of the ServiceNow spam header. If the header is X-ServiceNow-Spam-Status:Yes, the filter moves the email to the Junk folder |

自分のPDIにはIgnore snderが無いようです気にしないことにします
【未解決】MAUIで作ったAndroidアプリでローカルネットワークなSQLServerとやりとりしたいけど諦めた。

<br><br><br>
# 経緯
<br>
社内に立てたMicrosoft SQLServer をAndroid端末で利用したかった。でもできなそうだった。
Windowsタブレットなら簡単だろうけど、高価なのでできれば安いAndroidで考えたかった。
こういった使い方は邪道なので、仕方ないのかもしれない。あきらめることにした。

# 環境
Windows10 pro 22H2
visual studio 2022 Community (MAUI)
SQLServer 2022 Express
Unity 2021.3.5f1

# 検討、検証したこと
<br><br><br>
 まず筆頭候補Xamarin。
 これはできる。が、来年2024年にサービスが終わるらしいので避けた。
Androidstudio。
 試してないが、知り合い曰くできないらしい。
Unity。
 試したがうまくいかなかった。AsetStoreにて「SQL for Unity Database」なるものが見受けられたのでやはり普通にはできないのだろう。
$100と高価だし、マイナーなアセットで使い方も理解できるか不安があったので避けた。

最後に希望の星MAUI。できそうでなんだかできなかった。。。。
おそらくだが、一般的にC#にてSQLを利用する際に使用される「System.Data.SqlClient」ライブラリがMAUIでは使えないことが原因に思う。

using System.Data.SqlClient

と記述すると構文エラー。調べてみると、代替で「MicroSoft.Data.SqlClient」を使おう、とおっしゃっているページをいくつか見つけた。
「MicroSoft.Data.SqlClient」をNuGetからとってきてusingするとWindowsエミュレートで動いた。しかしandroid実機では動かなかった。。。
名前通りMicroSoftのライブラリなので、Windowsでは動くけど、Androidまでカバーしてないのは仕方がないと思う。



<br><br><br>
# 所感
<br>
Unity「SQL for Unity Database」を試す気はない。<br>
MAUIのアップデートでSystem.Data.SqlClientが使えるようになればあり得るのかもしれない。<br>
MAUIはGUIをXAMLで手書きなのがストレス。こちらもアップデートを祈る。<br>
というか、Microsoft側もわざとこういう使い方(携帯情報端末をローカルに使う)を排斥しようとしているかもしれない。IP直打ちでVBAが動かないのもそう感じた。
邪道なやり方は可能な限り避けるべきで、携帯情報端末らしくWebサーバーを使うのが正解なのだろう。
WMAの調査

ネットラジオで使われるエンコードにwmaがあります。mp3やaacに比べると少ないのですが、デコーダーをちょっと調べてみました。

ffmpegにはもちろんコードがあるようです。整数演算のデコーダーがあるようです。

https://ffmpeg.org/

ここのコードを元にして固定長小数点の実装を追加したコードがここにありました。

https://www.rockbox.org/

上のコードをこちらでも使っているようです。

http://www.mplayerhq.hu/

がっつり組み込まれているので、抜き出すのは大変そうです。

MacOS Xで作れた単体デコーダーです。

https://github.com/shuice/WmaDecoder

floatを使っているので、厳しいです。

手ごろなものがありません。

以前はいくつかwmaのステーションがあったような気がするのですが、今見たらほとんど見当たりません。日本には少しまだありますが、WMAを使ったMMSは開発が終了しているのでじきに他のシステムに変更されるような気がします。
mix testでNGが発生したテストをseed値を指定して再現する方法

# はじめに

乱数を使ったテストで、同じテストを再現したい。

mix testのコマンドを紹介します。

# こんな時に役立ちました

オセロゲームの強化学習をするために、オセロの環境を作成しました。
乱数で石を置いてゲームが終了するまで行うテストを作りました。
バグがあって、白が置けるのに完了しています(failの条件を書いてないのでテストは成功の扱いですが、正しい状態ではない）。

```
   abcdef
1: ●●●●●- |FFFFF.
2: ●○○●●● |FFFFFF
3: ●●○●●● |FFFFFF
4: ○●●●●● |FFFFFF
5: ○○●●●● |FFFFFF
6: ○○○●●● |FFFFFF

.
Finished in 0.03 seconds (0.00s async, 0.03s sync)
3 tests, 0 failures, 2 excluded

Randomized with seed 482389
```

# 同じ条件でもう一度実行

テストの結果の最後の行に、seedの値が表示されています。
次のコマンドのように、`--seed`で、このseed値を指定する事で、再現できます。

```
$ mix test test/reversi_rl_test.exs:45 --seed 482389
```

# ほかの方法

毎回、固定したseed値で実行したい場合は、test コードの中でseed値を設定するのが簡単でよいとおもいます。

今回は、いろいろなseed値で確認したかったので、この方法が便利でした。
Gradle - archive contains more than 65535 entries.

# Problem
```
* What went wrong:
Execution failed for task ':JarHazardSyncWorker'.
> archive contains more than 65535 entries.
  
  To build this archive, please enable the zip64 extension.
  See: https://docs.gradle.org/7.6/dsl/org.gradle.api.tasks.bundling.Zip.html#org.gradle.api.tasks.bundling.Zip:zip64

* Try:
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.
...
...
...
...skip
Caused by: org.gradle.api.tasks.bundling.internal.Zip64RequiredException: archive contains more than 65535 entries.

To build this archive, please enable the zip64 extension.
```

# Solution
```build.gradle

task JarTestExample(type: Jar) {
    zip64 = true // <-- Add this
    duplicatesStrategy = DuplicatesStrategy.INCLUDE
    archivesBaseName = 'TestExample'
    includeEmptyDirs = false

    manifest {
        attributes 'Main-Class': 'com.johnny.TestExample'
    }

	// remove the security files (from mail.jar / activation.jar) so that the jar will be executable.
    from (configurations.implementation.collect { it.isDirectory() ? it : zipTree(it) }) {
	    exclude 'META-INF/MANIFEST.MF'
		exclude 'META-INF/*.SF'
		exclude 'META-INF/*.DSA'
		exclude 'META-INF/*.RSA'
	}

    from sourceSets.main.output
}

```
勉強の達人たちから学ぶ資格勉強の極意

# はじめに
多くの書籍や今ではYouTubeなどで資格の勉強方法について解説されています。いつも参考にさせてもらっており、**TOEICで815点と取得できたり、日商簿記3級や基本情報技術者試験に合格**出来たりしました。

でも、たくさん情報や動画があるので、少しずつ人によって言っていることが違うのでたくさん書籍や動画にあたるほど**どう資格の勉強をしたらいいのかわからなくなってくると思いました。**

そこで今回は、著名人の方が言っている**資格勉強法に共通する極意**とそこからつくった**ロードマップ**を紹介したいと思います。
**著名人：　メンタリストDaiGoさん　資格スクエア(東大卒弁護士)　銀行員うめこさん　精神科医の樺沢紫苑さん　などなど**

https://uniyt.blogspot.com/

https://uniyt.blogspot.com/2023/02/blog-post.html


# 資格勉強の極意
+ **資格勉強では、完璧を目指さなくていい**
+ **インプットよりもアウトプット（過去問を解く・問題集）の時間を多くとる**
    + インプット：アウトプット＝2：8
    + 問題を解く、内容を思い出すことが最高の勉強法である
+ **過去問が最高の教材である**
    + ITパスポートや情報技術者試験(国家資格)はほとんどが過去問から出題される（筆者まとめ）
    + 似たような問題が出ることが多い
    + 過去問を解くことで傾向をつかむことが出来る

# 資格勉強のロードマップ
+ **過去問を5年分用意する**
+ **一番新しい過去問をとりあえず解く**
+ **分からないところをテキストで調べる**
+ **もう一度、一番新しい過去問を解く**
    + これを合格点に到達するまで繰り返す
+ **次に、2番目に古い過去問を解く**
    + 以下、上記の繰り返し
+ **一番大切なのは、「やりきる」こと**


脳科学や心理学の研究で、人に話したり、テストをするというすなわちアウトプットが大切を言われています。そこら辺を踏まえて、著名人の方もそうおっしゃっているのだなと思いました。

# まとめ
今回、資格勉強法をまとめることで改めて勉強になりました。
この記事が資格勉強をしている人（自分を含む）の一助になれば幸いです。

# 参考文献
https://uniyt.blogspot.com/

https://uniyt.blogspot.com/2023/02/blog-post.html
Sassのエラー解決の道のり　’変数が引き出せない’、’コンパイル出力先’

scssで2日間迷宮に迷い込んでいたので、事態の解決までの道のりを記します。
プログラミング初学者なので考察が変だと思ったらご指摘いただけると嬉しいです。

## error01
### 問題
_base.scssに_variable.scss内にある変数を使用したところ、参照エラー

### ディレクトリ構成
![ディレクトリ構成.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2966871/f6554347-466a-9d98-a14b-126e4f237b8d.png)

### 原因
style.scssに`@use 'setting/index'`を記載していたため。
@forwordでまとめたものは、すべてstyle.scss内に@useすればいいというバイアスがかかっていました。

### 解決策
`@use 'setting/index'`を_base.scssに記載

### 理由と考察
_base.scssの中で変数を使いたいのに、base.scssと変数が入っているindex.scssが同じ階層で集合しているため、変数を見つけることができなかった。

まずは_base.scss内に@useでindex.scssを読み込む必要がある。
@useはファイルをカプセル化する性質があるため、単純に@forwardで転送しようとしてもスコープ内にいなければ読み込めないよう。

[こちら](https://zenn.dev/taketooon/articles/fa77fcbd3ba4b9)のページを参考にさせていただきました。

## error02
error01を修正してsuccessの表示が出ているのにstyle.cssに反映されない。。

### ディレクトリ構成
error01を修正したもの

### 原因
コンパイルの出力先がsrcと同じ階層に作成されて、以前に作成されたstyle.scssをずっと見ていた。。
![スクリーンショット (20).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2966871/71efd44c-14fd-e90a-9068-5325c6ade495.png)

### 解決策
setting.jsonで出力先（"savePath":）を "/css"から "~/../css"に変更
![スクリーンショット json.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2966871/e0cd423c-7cff-9685-0832-ce850fc7ecc6.png)

### 理由と考察
コンソールから直接出力先を参照することで、見ているところが違うと判明。
おそらくerror01のときに色々といじっていたときにできたstyle.scssがあったので「ここに反映されるんだ！」とバイアスがかかっていた。


## 教訓
- 「バイアスは起こりうるもの」と理解して、何にバイアスがかかっているか疑うことから始める。
- エラー文やコンソールはヒントを出してくれるので読み込もう！
ERROR: Failed to set up Chromium r1045629! Set "PUPPETEER_SKIP_DOWNLOAD" env variable to skip download. Error: connect ECONNREFUSED 2404:6800:4004:81f::2010:443

`npm install`でエラーがでるー

```bash
$ npm i
npm WARN deprecated puppeteer@18.2.1: < 19.2.0 is no longer supported
npm ERR! code 1
npm ERR! path /home/kudu/Downloads/myproj/node_modules/puppeteer
npm ERR! command failed
npm ERR! command sh -c -- node install.js
npm ERR! ERROR: Failed to set up Chromium r1045629! Set "PUPPETEER_SKIP_DOWNLOAD" env variable to skip download.
npm ERR! Error: connect ECONNREFUSED 2404:6800:4004:81f::2010:443
npm ERR!     at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1251:16) {
npm ERR!   errno: -111,
npm ERR!   code: 'ECONNREFUSED',
npm ERR!   syscall: 'connect',
npm ERR!   address: '2404:6800:4004:81f::2010',
npm ERR!   port: 443
npm ERR! }

npm ERR! A complete log of this run can be found in:
npm ERR!     /home/kudu/.npm/_logs/2023-02-18T00_05_40_109Z-debug-0.log
```

# 教えてSenapi

IPv6を使わないようにする

```bash
NODE_OPTIONS=--dns-result-order=ipv4first npm install
```
Docker の実験（その６：コンテナの自動削除）

[その５：コンテナのディスク使用率](https://qiita.com/intrajp/items/3f3416506c9a94cebaa9)のつづき。

コンテナが  exit したら、自身を自動的に削除する方法。
--rm オプションをつけることで可能。
ちなみに、--restart unless-stopped とは一緒に使えない。当たり前だけど。
実行コマンド。

```bash
$ docker container run -dt --rm -p 8080:80 --name mynginx nginx2
```

コンテナが立ち上がったことを確認する。

```bash
$ docker container ps
CONTAINER ID   IMAGE     COMMAND                  CREATED              STATUS              PORTS                                   NAMES
98c652e50bfb   nginx     "/docker-entrypoint.…"   About a minute ago   Up About a minute   0.0.0.0:8081->80/tcp, :::8081->80/tcp   mynginx2
67df4d402280   nginx     "/docker-entrypoint.…"   31 minutes ago       Up 31 minutes       0.0.0.0:8080->80/tcp, :::8080->80/tcp   mynginx
```

では、--rm オプションをつけていたコンテナを停止してみる。

```bash
$ docker container stop mynginx2
mynginx2
```

コンテナが停止したことを確認する。

```bash
$ docker container ps
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS          PORTS                                   NAMES
67df4d402280   nginx     "/docker-entrypoint.…"   33 minutes ago   Up 33 minutes   0.0.0.0:8080->80/tcp, :::8080->80/tcp   mynginx
```

コンテナが自動的に削除されていることを確認する。

```bash
$ docker container ps -a
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS          PORTS                                   NAMES
67df4d402280   nginx     "/docker-entrypoint.…"   33 minutes ago   Up 33 minutes   0.0.0.0:8080->80/tcp, :::8080->80/tcp   mynginx
```

上記のとおり、ps -a オプションで確認しても、該当するコンテナは exit となっておらず、削除されているのが確認できた。

[その7：イメージの作成](https://qiita.com/intrajp/items/9bf5e4cc5893d9c95da8)につづく。
plunkerでdeck.gl その11

# 概要
plunkerでdeck.glやってみた。
FirstPersonView、使ってみた。

# サンプルコード

```

const tileLayer = new deck.TileLayer({
  data: "https://c.tile.openstreetmap.org/{z}/{x}/{y}.png",
  minZoom: 0,
  maxZoom: 19,
  tileSize: 256,
  renderSubLayers: props => new deck.BitmapLayer(props, {
    data: null,
    image: props.data,
    bounds: (({ west, south, east, north }) => [west, south, east, north])(props.tile.bbox),
  }),
});
const tile3dLayer = new deck.Tile3DLayer({
    id: 'tile3dlayer',
    pointSize: 1,
    data: 'https://s3-ap-northeast-1.amazonaws.com/3dimension.jp/13000_tokyo-egm96/13101_chiyoda-ku_notexture/tileset.json', 
      // PLATEAU千代田区
    loader: Tiles3DLoader,
    onTilesetLoad: (tileset) => {
      const { cartographicCenter } = tileset;
      const [longitude, latitude] = cartographicCenter;
      console.log(longitude, latitude);
    },
});
const deckgl = new deck.Deck({
  views: new deck.FirstPersonView({
    far: 10000,
  }),
  initialViewState: {
    longitude: 139.749,
    latitude: 35.693,
    position: [0, 0, 25],
    bearing: 90,
    pitch: 10,
    maxPitch: 89,
    minPitch: -89
  },
  controller: true,
  layers: [tileLayer, tile3dLayer, ]
});




```

# 実行結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/4de739cd-674b-c33a-344e-d632ac3001eb.png)


# 成果物

https://embed.plnkr.co/plunk/u1wxiH8BR8Epn29T


以上。
plunkerでdeck.gl その10

# 概要
plunkerでdeck.glやってみた。
hexagonLayer、使ってみた。

# 参考にしたページ
https://qiita.com/syanseto/items/c30cd82be8df1fdc927e

# サンプルコード

```


const tileLayer = new deck.TileLayer({
  data: "https://c.tile.openstreetmap.org/{z}/{x}/{y}.png",
  minZoom: 0,
  maxZoom: 19,
  tileSize: 256,
  renderSubLayers: props => new deck.BitmapLayer(props, {
    data: null,
    image: props.data,
    bounds: (({ west, south, east, north }) => [west, south, east, north])(props.tile.bbox),
  }),
});
const data = [
  {p: [141.3521727, 43.0620842], v: 1952356}, // sapporo
  {p: [140.8677736, 38.2686018], v: 1082159}, // sendai
  {p: [139.5196066, 35.4937089], v: 3724844}, // yokohama
  {p: [136.9043778, 35.1814347], v: 2295638}, // nagoya
  {p: [135.7696242, 35.0118413], v: 1475183}, // kyouto
  {p: [135.5023064, 34.6936616], v: 2691185}, // oosaka
  {p: [135.1959010, 34.6894819], v: 1537272}, // koube
  {p: [132.4556497, 34.3849809], v: 1194034}, // hiroshima
  {p: [130.4017854, 33.5902214], v: 1538681}, // fukuoka
];
const OPTIONS = ['radius', 'elevationScale', 'coverage', 'opacity'];
const colorRange  = [
  [1, 152, 189],
  [73, 227, 206],
  [216, 254, 181],
  [216, 254, 181],
  [254, 237, 177],
  [254, 237, 177],
  [254, 237, 177],
  [254, 237, 177],
  [254, 173, 84],
  [254, 173, 84],
  [254, 173, 84],
  [254, 173, 84],
  [254, 173, 84],
  [254, 173, 84],
  [254, 173, 84],
  [254, 173, 84],
  [209, 55, 78],
  [209, 55, 78],
  [209, 55, 78],
  [209, 55, 78],
  [209, 55, 78],
  [209, 55, 78],
  [209, 55, 78],
  [209, 55, 78],
  [209, 55, 78],
  [209, 55, 78],
  [209, 55, 78],
  [209, 55, 78],
  [209, 55, 78],
  [209, 55, 78],
  [209, 55, 78],
  [209, 55, 78],
  [209, 55, 78],
  [209, 55, 78],
  [209, 55, 78],
  [209, 55, 78],
  [209, 55, 78],
  [209, 55, 78],
  [209, 55, 78],
  [209, 55, 78],
  [209, 55, 78],
  [209, 55, 78],
  [209, 55, 78],
  [209, 55, 78],
  [209, 55, 78],
  [209, 55, 78],
  [209, 55, 78],
  [209, 55, 78],
];
const options = {};
OPTIONS.forEach(key => {
  const value = document.getElementById(key).value;
  document.getElementById(key + '-value').innerHTML = value;
  options[key] = Number(value);
});
const getValue = (d) => {
  return d.v;
};
const hexagonLayer = new deck.HexagonLayer({
      id: 'hex',
      data,
      getPosition: ({p}) => p,
      colorRange,
      getColorWeight: getValue,
      getElevationWeight: getValue,
      elevationScale: 200,
      extruded: true,
      pickable: true,
      radius: 1000,
      opacity: 1,
      coverage: 1,
      upperPercentile: 100,
      ...options
});
const deckgl = new deck.Deck({
  initialViewState: {
    longitude: 137,
    latitude: 37,
    zoom: 5,
    minZoom: 2,
    maxZoom: 8,
    pitch: 30,
    bearing: 10,
  },
  controller: true,
  layers: [tileLayer, hexagonLayer, ]
});




```

# 実行結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/5c4757a8-e1c9-0c93-ecbd-c722148f8f29.png)


# 成果物

https://embed.plnkr.co/plunk/2zqyY1DqwBnZlVzT

以上。
Qiita Daily Survey memo 2023.02.18

# Qiita Daily Survey memo 2023.02.18

Qiita の記事を可能な限り毎日読むために、読んだmemoを公開することでモチベーションを維持しようという試み。（5ヶ月ぶり）

## [リモートワークで鬱になったエンジニアがwebデザイナーを目指すようになった話](https://qiita.com/four_leaf_clover/items/261d3633e646944c11fe)

four_leaf_clover 様の記事。

タイトルにはリモートワークでとありますが、様々な要因が重なって病んでしまった筆者の方が、Webデザイナーを目指すようになった経緯を共有していただいている記事です。

かく言う自分もリモートワーク開始時は調子が良かったですが、そこからしばらく経ったタイミングからはあまり調子がよくないのは事実だと思います。

そのことについて振り返りを実施しましたが、リモートワーク開始時と比べて、大きく下記のようなことが変わったかなと思いました。
- 人と会話することが少なくなった
- 通勤（運動）する機会が大幅に減った
- 小さな目標を立ててクリアする、という習慣が途切れた

幸い、最近はネットの友達が増え、毎日のように楽しく会話できています。
運動と、目標を立ててクリアしていくほうが解決すれば、調子が上向くのでは…と思い、Daily Surveyに挑戦してみました。

やはりリモートワークで人と会話する機会が減ると病みやすくなる傾向はあるようなので、皆さまもお気をつけください。

## [フロントエンドテストにおける知見の宝庫を発見！「javascript-testing-best-practices」](https://qiita.com/taisei-13046/items/662a289dc7328fb64836)

ytaisei (taisei-13046(HRBrain)) 様の記事。

フロントエンドテストにおけるとありますが、前半はフロントエンドに限らず、どのテストにも当てはまる大変勉強になる記事を共有してくださっています。

自分はテスト工程が苦手である認識があるので、「ゴールデンルール」などシンプルでわかりやすい方針があると、動きやすいと感じました。

また、いい例と悪い例を併記してくださっており、どうするべきかを直感的に理解しやすかったです。

特に「テストに脳内のスペースを使わない！」と「AAAパターンでテストする」というのが自分に刺さりました。

シンプルに、小さい規模でテストして、かつわかりやすく、テンプレートのように構造化された方法でテストすると、やりやすそうに感じました。

こういった非常に良い記事を読んでも、実践しないとどんどん忘れていくので、最近作ったコードで実践してみたいと思います。

## [新卒1年目が覚えて良かったショートカット集](https://qiita.com/taka_da/items/4a0a675a4dfa89927e02)

TKD K (taka_da) 様が共有してくださった記事。

タイトルの通り、新卒1年目の筆者の方が覚えたショートカットを共有していただいている記事になります。

共有していただいているショートカットはExcelのものになります。

私も理系大学院を卒業して就職しましたが、学生時代と社会人ではやはり大きく異なっており、就職してから非常に多くのショートカットを身に着けました。

特にセル移動系や選択系のショートカットの威力は非常に高いです。

会議で私の画面を共有して話し合っている際に、話している方の内容をガタガタと高速でExcelに反映すると、皆さま驚いてくれますし、会議が円滑に進みますし、非常に気分が良いです。

基本的なショートカットが記載されているので、Excelに慣れていない方は是非参考にして手を動かしてみることをおすすめいたします。

## [ChatGPTと15分会話して毎朝のスピーチを乗り切る](https://qiita.com/sunnku/items/579d5499293a721c192f)

sunnku 様の記事です。

タイトルの通り、今流行のChatGPTで朝のスピーチの原稿とスライドを作成される、という記事になります。

私の勤めている会社でも会議の際にChatGPTの話題を出し共有した所、いろいろな方に興味を持っていただきました。

ChatGPTの威力が高すぎて、その使い方に注目が集まっているように感じます。

今回の筆者様の記事も、単純にスピーチの記事を作成するだけでなく、その後の整形やスライド作成に向けて、ChatGPTをうまく活用されています。

また、記事の冒頭にフローも記載いただいていて、とても頭に入ってきやすかったです。

How to Use ChatGPT は、これからしばらく楽しく追いかけられるテーマだと思うので、注目していきたいと思います。
逆にStreamを使う例題を作ってみよう！

Streamを使うと、意外と簡単にできる。ということがあるのでは？
Streamですっきりと記述できる例題を書いてみます

思いついたら、増やしていきます。

# ex01 

```Elixir
  @doc """
  foo()が40を10回返すまで繰り返す

  ## 実行結果

      iex> Tutorial012.ex01
      :ok

  """

  def ex01() do
    Stream.repeatedly(fn  -> foo() end)
    |> Stream.filter(fn val -> val == 10 end)
    |> Stream.take(3)
    |> Stream.run()
  end

  defp foo() do
    Enum.take_random(0..10, 1)
    |> hd
    |> IO.inspect(label: "foo")
  end
```

# ex02

```Elixir
  @doc """
  正の整数で3,5,7の倍数ではない数を小さいものから10個

  ## 実行結果

      iex> Tutorial012.ex02
      [1, 2, 4, 8, 11, 13, 16, 17, 19, 22]

  """
  def ex02() do
    Stream.iterate(1, &(&1 + 1))
    |> Stream.reject(fn val -> Integer.mod(val,3) == 0 end)
    |> Stream.reject(fn val -> Integer.mod(val,5) == 0 end)
    |> Stream.reject(fn val -> Integer.mod(val,7) == 0 end)
    |> Stream.take(10)
    |> Enum.to_list()
  end
```
# ex03

```Elixir

  @doc """
  n回ごとにtrueを返すStreamから10個取り出す

  ## 実行結果

      iex> Tutorial012.ex03
      [false, false, true, false, false, true, false, false, true, false]

  """
  def ex03() do
    true_every(3)
    |> Stream.take(10)
    |> Enum.to_list()
  end

  defp true_every(n) when n > 0 do
    Stream.concat(Stream.duplicate(false, n-1), [true])
    |> Stream.cycle()
  end
```
Office Lists を徹底活用して個人タスクを管理する

## この記事について

これまで個人のタスクを管理する方法を数々試しました。
* redmine
* Excel
* Asana
* and more....

最近、社内で「O365を徹底活用しよう！」という号令もあって、O365で便利なアプリはないか？と探した結果、Listsがタスク管理に使えそうと思ったのでトライしました。

最初は、ただの贅沢なエクセルでしょ？！って思っていましたが、ビューを自分でイジイジできたり。ボードで見せることができるとわかったので、ビビッと来ました。

私のやり方が参考になるならばと思い記事に残します。


### 対象読者

* 個人のタスクを管理したい人
* 会社でOffice365が使える＋SharePointが使える人（個人アカウントだといろいろ機能制限があります）

## 開発環境

* Chrome

## インストール手順

* なし　ChromeがあればOK

## 参考文献

[Qiita：Asanaの活用事例　～個人タスク管理編～](https://qiita.com/ikedahideya/items/2120983a98b165b9217f)


## 使い方

### 新しい Lists を作成する
![0001.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/382325/6ccaa801-f026-0f9c-c0a4-6b6a6cb0030f.jpeg)
「新しいリストを作成する」から新しいリストを作成します。

![0002.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/382325/89ff5f12-f0b1-94a5-ea48-a43b36b041e7.jpeg)
![000 (3).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/382325/a380df26-4d71-88c3-534d-49e7bd04d033.jpeg)
もし、タスクを複数人でシェアするようならば、Sharepointを選択すればOK

### 項目を作成する!
![0006.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/382325/8ff7a16c-2159-3c40-629d-cb5f3a13cb94.jpeg)
|項目名|タイプ|説明|
|----|----|----|
|タスク名|テキスト(default)|初期値の項目で、名称を変更|
|プロジェクト名|テキスト|複数案件で同じ項目名になるので、分類のために|
|着手予定|選択肢|後述|
|内容|リッチテキスト|タスクに関するメモ書きです。Listsには別途コメント項目があるのでうまく活用します。|
|最終期日|日付|後々必要になるかと思って追記|

#### 着手予定の項目
* 0.今日
* 1.今週
* 2.来週
* 3.今月
* 4.来月
* 8.委任
* 9.完了

「8.委任」
見積依頼というタスクが頻発する仕事なのですが、依頼を出しただけでは「完了」にはならないですよね？
"委任" という選択肢を作っておけば、追跡できます。委任したタスク専用のビューがあれば管理もしやすいです。私は、委任だけで「ギャラリー」スタイルのビューを作っています。

### 「かんばん」ビューの作成
![000 (8).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/382325/503f645b-d0b9-36df-29a8-ac3803a4b0b1.jpeg)
新しいビューを作成する　から、ビューを作成します。

![000 (9).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/382325/48c25458-e403-c4ff-17de-753eaaef8777.jpeg)
* ボード：これで「かんばん」のビューを作れます。
* ボードの整理：横軸の項目です。項目の種別が「選択肢」以外選べないです。

### 「かんばん」ビューの完成
![000 (11).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/382325/8e343b2a-3725-d123-0f10-9194e6b7d1a9.jpeg)

### ビューの調整
ビューの調整をします。
なぜなら、このまま「完了」のタスクが増えれば、そこがたくさん増えて消えてくれなくなるので、着手予定＝完了のタスクを消すように設定が必要

![000 (17).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/382325/87754641-56ee-11b8-2ddf-bdf02ba4e4c0.jpeg)
1. [設定]-[リストの設定]
1. 最下部にあるビューから、調整するビューを選択
1. [フィルター]を展開
1. [次の条件に該当する場合だけアイテムを表示する]を選択
1. 列の条件：着手予定／次の値に等しくない／9.完了

[OK]で確定させます。
これで、カードを完了に移動させて、画面更新などすれば完了のタスクが消えてくれます。

## 感想

いろいろツールを試しましたが、この方法は非常にしっくり来ています。
お金不要だし、Asanaなどのツールではないのでアカウントも不要。
ビューのアイデア次第でどんな見方もできます。

同じ組織内ならば、担当者列などを作って数人ぐらいなら、一緒にタスク管理できそうです。
Docker の実験（その４：コンテナの停止および自動起動の設定）

[その３：ポート番号の設定](https://qiita.com/intrajp/items/096d357c0c3e4d3e6c55)のつづき。

存在するコンテナをいっぺんに停止する方法。

```bash
$ docker container stop $(docker container ls -aq)
a985f26967a8
fe8d52bced5e
```

コンテナが停止したことを確認する。

```bash
$ docker container ps -a
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS                      PORTS     NAMES
a985f26967a8   nginx     "/docker-entrypoint.…"   45 minutes ago   Exited (0) 4 seconds ago              mynginx
fe8d52bced5e   nginx     "/docker-entrypoint.…"   11 hours ago     Exited (0) 45 minutes ago             funny_wu
```

コンテナは、止めただけだと、ストレージとして残ってしまいリソースを圧迫する。したがって、コンテナを削除する。

```bash
$ docker container rm funny_wu
funny_wu
```

コンテナが削除されたことを確認する。

```bash
$ docker container ps -a
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS                          PORTS     NAMES
a985f26967a8   nginx     "/docker-entrypoint.…"   46 minutes ago   Exited (0) About a minute ago             mynginx
```

（参考）すべてのコンテナを削除する方法。

```bash
$ docker container rm $(docker container ls -aq)
```


コンテナのプライマリプロセス（デフォルトのコンテナコマンド）ではなくて、他のプログラムを指定することができる。

nginx イメージをつかって、 sleep コマンドを実行してみる。

```bash
$ docker container run -d nginx sleep 300
```

コンテナの中に入って確認してみる。

```bash
$ docker container exec -it <name> bash
(以下、コンテナの中)
/# apt-get update
/# apt-get install htop
/# htop
```

300秒後に、リターンしてした。

コンテナを立ち上げた状態で、Docker を再起動すると、デフォルト動作では、コンテナが停止してしまう。
この様な場合に備えて、リスタートポリシーを作ることができる。

```bash
no (デフォルト)
on-failure
unless-stopped
always
```

以下のコマンドで立ち上げておけば、Docker をリスタートしても、コンテナは、Docker の再起動時に自動的にリスタートする。

```bash
$ docker container run -dt --restart unless-stopped -p 8080:80 --name mynginx nginx
$ sudo systemctl restart docker
```

起動していた。

[その５：コンテナのディスク使用率](https://qiita.com/intrajp/items/3f3416506c9a94cebaa9)につづく。
ArcGIS Pro でスクリプトツールに自作モジュールを読ませるときは importlib.reload()

**実行環境**
Windows10
ArcGIS Pro 3.0.3
Python 3.9.11

## はじめに

タイトルにある [スクリプトツール](https://pro.arcgis.com/ja/pro-app/latest/help/analysis/geoprocessing/basics/create-a-python-script-tool.htm) というのは、ArcGIS Pro アプリケーションから python スクリプトにパラメータを渡して処理を実行する機能のことです。

このスクリプトツールに登録している python スクリプトが、**スクリプト内でインポートしている自作モジュールの更新を反映してくれない**という現象にずっと悩まされていました。

更新を反映させるにはアプリケーションを再起動させないといけないので煩わしいことこの上なかったのですが、やっと解決策を見つけました。

**標準ライブラリ importlib の reload() でモジュールをリロードする。**

これだけの話だったのですが、調べてもすぐに答えにたどり着けなかったので、ここに書き留めたいと思います。

## モジュールの更新が反映されないケース

以下の tool.py と mod.py が、同じフォルダ内にある場合です。

```python:tool.py
# スクリプトツールに登録する python スクリプトファイル
import arcpy
import mod

arcpy.AddMessage('tool')
arcpy.AddMessage(mod.get_text())
```

```python:mod.py
# インポートするモジュールファイル
def get_text():
    return 'mod'
```

[arcpy](https://www.esrij.com/gis-guide/arcgis-basic/arcpy/) というのは、ArcGIS Pro の提供するライブラリです。

[AddMessage()](https://pro.arcgis.com/ja/pro-app/latest/arcpy/functions/addmessage.htm) は、アプリケーション上に文字列を出力します。

ArcGIS Pro から tool.py を登録したスクリプトツールを実行すると、以下の結果になります。

![result01.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1409923/0342b78e-15e7-4f56-edba-4d61364af9fe.png)

tool と mod が出力されます。

ここで、tool.py と mod.py を以下のように更新し、ファイルを上書き保存します。

```diff_python:tool.py
import arcpy
import mod

- arcpy.AddMessage('tool')
+ arcpy.AddMessage('tool_changed')
arcpy.AddMessage(mod.get_text())
```

```diff_python:mod.py
def get_text():
-     return 'mod'
+     return 'mod_changed'
```

両ファイルとも、出力する文字列のみ変更し、上書き保存します。

この状態で、再度スクリプトツールを実行した結果がこちらです。

![result02.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1409923/33ee0027-76bc-b22b-e981-1ba8bebe32b7.png)

tool は tool_changed になっていますが、mod は mod のままです。

このように、読み込んでいるモジュールの変更がスクリプトツールに反映されないという現象が問題となっていました。

ArcGIS Pro を再起動するとモジュールの変更が反映されるようになりますが、面倒です。

## 解決策

tool.py で、importlib をインポートし reload() で mod モジュールをリロードするようにします。

```diff_python:tool.py
+ import importlib
import arcpy
import mod

+ importlib.reload(mod)

arcpy.AddMessage('tool_changed')
arcpy.AddMessage(mod.get_text())
```

結果は以下のとおりで、モジュールの変更が反映されるようになりました。

![result03.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1409923/140b030e-a5c6-3d07-dc1c-b759e2e85142.png)

## importlib.reload() について

importlib.reload() の説明のために、[ドキュメント](https://docs.python.org/ja/3/library/importlib.html#importlib.reload) を一部抜粋します。

> 以前にインポートされた module をリロードします。引数はモジュールオブジェクトでなければならず、したがってそれ以前に必ずインポートに成功していなければなりません。この関数は、モジュールのソースファイルを外部エディタで編集していて Python インタープリタから離れることなく新しいバージョンを試したい際に便利です。

今まで知らなかったのですが、Python インタープリタで自作モジュールを扱っている場合でも、普通にあることのようです。

## 最後に

モジュールの変更が反映されないのはアプリケーションの不具合かと思っていましたが、そうではありませんでした。

そこであらためて、アプリケーション側のリファレンスに書いてなかったものかと探してみたところ、ありました。

https://pro.arcgis.com/ja/pro-app/latest/arcpy/geoprocessing_and_python/editing-a-python-toolbox.htm

ですよね。

ともかくこれで、ArcGIS Pro のカスタムツール作成時の煩わしさから解放されました。
Docker の実験（その３：ポート番号の設定）

[その２：コンテナの調査](https://qiita.com/intrajp/items/10783090fa9b5501ec7c)のつづき。

コンテナを停止する。

```bash
$ docker container stop funny_wu
funny_wu
```

ローカルホストのポート番号を 8080、名前を mynginx にしてみる。

```bash
$ docker container run -dt -p 8080:80 --name mynginx nginx
a985f26967a89a512ec1ad9d8b6a34552800f22f1d4b220e084ef7e7dc65eaa0
```

確認する。

```bash
$ docker container ps
CONTAINER ID   IMAGE     COMMAND                  CREATED              STATUS              PORTS                                   NAMES
a985f26967a8   nginx     "/docker-entrypoint.…"   About a minute ago   Up About a minute   0.0.0.0:8080->80/tcp, :::8080->80/tcp   mynginx
```

netstat で、8080 番ポートが開いているか確認する。

```bash
$ netstat -ntlp
(No info could be read for "-p": geteuid()=20163 but you should be root.)
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN      -
tcp        0      0 127.0.0.1:33905         0.0.0.0:*               LISTEN      -
tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      -
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      -
tcp6       0      0 :::8080                 :::*                    LISTEN      -
tcp6       0      0 :::22                   :::*                    LISTEN      -

```

webからも確認する。
vm のグローバル IP の確認方法
（参考）
https://cloud.google.com/compute/docs/instances/view-ip-address?hl=ja#gcloud

```bash
$ gcloud compute instances list
$ gcloud compute instances describe <instance-name> --zone=asia-northeast1-b --format='get(networkInterfaces[0].accessConfigs[0].natIP)'
xxx.xxx.xxx.xxx
```

ちなみに、プロジェクトのデフォルトゾーンに存在しているインスタンスならば、ゾーンオプションは省略できる。

```bash
https://<IP_ADDR>:8080
```

タイムアウトする。これは、Firewall で、8080 番ポートが開いてないから。

Google Cloud で作成していた Firewall Rule で、ポートのところを修正する。

```bash
Protocols and ports:Specified protocols and ports:TCP:80,8080
```

webから再度確認する。

```bash
https://<IP_ADDR>:8080
```

確認できた。

[その４：コンテナの停止および自動起動の設定](https://qiita.com/intrajp/items/a9fcc6fe43c6dc150646)につづく。
MarkupとMarkdownの違い

# 前置き
ふとMarkypとMarkdownの違いが気になった
調べるまえの僕の認識だと、
- Markupはマークアップ言語とかで聞いたことがあるな
- HTMLがマークアップ言語だったはず
- Markdownってgithubのissueとか、pullrequestとかに書くときのやつだよな、、(qiitaも)

程度の認識だった

# 結論
Markupはマークアップ言語や、マークアップ文書のこと
HTMLやCSS,LaTeXなど

Markdownはマークダウン記法のこと
マークアップ言語を簡略化することができる書き方のこと
ejectコマンドの意外な使い方

https://ja.manpages.org/eject/1 より

## 説明
eject を用いると、リムーバブルメディア (CD-ROM、フロッピーディスク、テープ、 JAZ/ZIP ディスクなど) をソフトウェア制御によってイジェクトできる。 また eject は、連装 CD-ROM チェンジャを制御したり、 デバイスの自動イジェクト機能を制御したり、CD-ROM ドライブのディスクトレイを 閉じることもできる (製品によってはできないこともある)

## 注目すべきは CD-ROMドライブのディスクトレイを開け閉めできるかもしれないことです

## 非常に信頼する友達におすすめのパソコンはLinux (ubuntu)パソコンだよと伝える

もちろん、CDを聴けるようにしてあげないといけません

そのため、DVDドライブ付きのパソコンにします。

:::note info
DVDまで見れるようにするには、以下より
https://www.aiseesoft.jp/tutorials/play-media-files-on-ubuntu.html#part2::
:::

Linuxパソコンを買ってあげ、設定として自分のアカウントとroot権限(sudo)も設定してしまう

更に、DDNSも設定してあげる必要があるでしょう。

ルーターのsshのポートも開けないといけません。

## おうちに帰る

おうちにかえって、大切な友達のパソコンをのぞき見

## 数日立ってから

お相手が目の前に明らかにいるときに
リモートで

```
sudo eject /dev/cdrom
```

なんで突然開いたのだ？って疑問に思いいます

閉じようとするので、数回だけ
```
sudo eject /dev/cdrom
```

をします。

しかし、それ以上粘着はしないことです。

お相手からメッセージが来なければ、電話しましょう。

今僕がDVDドライブ開けたんだよって

## さいごに

どういう反応が来るかは、わずか2択です。
日時が格納されたカラムの日付のみをUPDATEする

調べても見つけられなかったので、ChatGPTさんに教えてもらいました

# 結論
DATE_FORMAT()とCONCAT()を組み合わせるといける
```SQL
UPDATE テーブル名
SET カラム名 = DATE_FORMAT(
    CONCAT('01-02-03 ', TIME (カラム名)),
    '%Y-%m-%d %H:%i:%s'
)
```
フォーマットは参考記事を見ながら、好きなように変えるとよい

## 参考記事
- https://www.javadrive.jp/mysql/function/index49.html
RuntimeError – [Xcodeproj] Unknown object version

## エラー内容
いつものようにターミナルで「**podinit**」を実行したところ、**RuntimeError – [Xcodeproj] Unknown object version**というエラーが発生

## 解決方法
**xcodeproj**というものをインストールすればいいらしいので以下のコマンドを実行してみました。
```terminal:command 
gem install xcodeproj
```
しかしまたもエラー発生、、、 :disappointed_relieved:
**FilePermissionError**だと、、、
```terminal
ERROR:  While executing gem ... (Gem::FilePermissionError)
    You don't have write permissions for the /Library/Ruby/Gems/2.6.0 directory.
```
色々調べた結果、sudoを頭につけたら無事うまくいきました！！

```terminal:command 
sudo gem install xcodeproj
```
【Solidity】(tips)定数の定義constantとimmutableとの違い

定数の定義であるconstantとimmutableとの違いについてメモします。

constant：　値の変更ができない。
immutable：　constructor内で値の設定はできるが、その後は値の変更ができない。

なのでRemix IDEだとこちらはエラーになります。
```
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

contract Sample{
    uint public constant number;

    constructor(uint _num){
        number = _num;
    }
}
```

immutableを用いた場合は、エラーはなくconstructorで値を設定できます。

```
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

contract Sample{
    uint public immutable number;

    constructor(uint _num){
        number = _num;
    }
}
```

ドキュメントには、constantの値はコンパイラ後には変更できない、immutableの値はコンパイラ後に1度だけ変更できるというニュアンスで記載されています。
コード書く→コンパイラ→デプロイ(constructor実行)　という順番なのでそうなりますね。
https://docs.soliditylang.org/en/v0.8.18/contracts.html#constant-and-immutable-state-variables
nodejsでsymbol-sdkを触ってみる（自分用の備忘録）2023/2/17

自分用の備忘録。

# 1 環境設定

### 1-1 Visual Studio Codeを使う

・インストール
・作業用フォルダを作る
・VSCodeを起動
・作業用フォルダを開く
・VSCodeでコンソールを表示

詳細はネットの海から拾ってください。

### 1-2 SDKのインストール

```
npm init
npm install symbol-sdk rxjs
```

### 1-3 テスト用ファイル作成
テキトーに symbolTest01.js とかしてみる。

### 1-4 テストノードを選択

[<<ノードリスト>>](https://symbolnodes.org/nodes_testnet/)

上記リンクから好きなノードを選ぶ。
Heightという列がリンクになっているので、httpsをなっているものをどれか選ぶ。
クリックすると「　{"scoreHigh"…　」とか訳のわからない文字が表示されるが無視。
欲しいのはノードへのリンクである。
ブラウザ上部のURLをクリックして覗くと「 https://〜〜〜:3001/chain/info」とか表示されるはず。
この「https://〜〜〜:3001」をコピーする。

### テスト用ファイルに書いてみる

```js
NODE = "https://〜.com:3001"
sym = require("./node_modules/symbol-sdk");
repo = new sym.RepositoryFactoryHttp(NODE);
txRepo = repo.createTransactionRepository();
networkType = repo.getNetworkType().toPromise();
console.log(networkType);
```
結果
```
Promise { <pending> }
```
なんだこりゃ。
こちとらVBAをちょっと触ったことしかないんですよ。
最近やっとコンソールとかシェルスクリプトとかに指一本触れた感じなんですよ。
う〜〜〜む。

どうやら非同期処理というものらしい。
Promiseとかいうのを使えばいいのか？

```js
NODE = "https://canade01t.symbol-node.com:3001"
sym = require("./node_modules/symbol-sdk");
repo = new sym.RepositoryFactoryHttp(NODE);
txRepo = repo.createTransactionRepository();
(async() =>{
    networkType = await repo.getNetworkType().toPromise();
    console.log(networkType)
})();
```
よくわからんがこんな感じで書いたら、無事

    152
と表示された。
これはテストネットを表す数字のようだ。

### 勘の良い人はお気づきだと思うが速習symbolを見させてもらっている。先人の知恵に感謝である。
javaScriptもよくわかっていないが、なんとかできた。
Remixアプリに同じネットワーク内の別の端末からアクセスする

Remixで開発したアプリケーションを起動して、同じネットワーク内の他の端末からアクセスする方法について紹介します。

通常、node.jsで起動したアプリケーションは`localhost`を表す`127.0.0.0`で起動することが多いと思います。

この値を`0.0.0.0`に変更することで外部からのアクセスが可能になるとされています。

ただ、実際に外部の端末から`0.0.0.0`でアクセスしても、Remixを起動している端末には接続できません。

外部からアクセスしてもらうために必要なIPアドレスを確認するには、アプリケーションが動く端末側のコンソールにて`Ipconfig`を実行します。

```shell
# 無線LANのIPアドレスを確認
Ipconfig getifaddr en0
# 有線LANのIPアドレスを確認
Ipconfig getifaddr en1
```

では、Remixにて起動した時のホストを指定するにはどうすればよいのでしょうか？

Remixでは、`process.env.HOST`を通してExpressの`app.listen`にホストの値を渡しています。


```cli.ts
let server = process.env.HOST
  ? app.listen(port, process.env.HOST, onListen)
  : app.listen(port, onListen);
```

なので、環境変数`HOST`を`0.0.0.0`に設定することで、外部からのアクセスが可能になります。

```shell
export HOST="0.0.0.0"
```

最後に、別の端末から、先ほど取得したIPアドレスを指定してアクセスしてみましょう。

```
192.168.xx.x:3000
```

# 参照記事

https://github.com/remix-run/remix/discussions/4621

https://stackoverflow.com/questions/30712141/connect-to-localhost3000-from-another-computer-expressjs-nodejs
Faster R-CNNの闇！4-step trainingの謎に迫る！

# この記事は？
[Faster R-CNN論文](https://proceedings.neurips.cc/paper/2015/hash/14bfa6bb14875e45bba028a21ed38046-Abstract.html)の3章，「Sharing Convolutional Features for Region Proposal and Object Detection」の節で説明されている，"a pragmatic 4-step training algorithm"について説明します．

# 結論
誰も使ってないし，気にしなくていいです．

# 詳しく
Faster R-CNNの実装が気になって調べていたところ，こんな記事を見つけました．

https://stackoverflow.com/questions/46561390/4-step-alternating-rpn-faster-r-cnn-training-tensorflow-object-detection-mo

**意訳**
> 質問者：TensorflowのFaster R-CNN実装の中に，論文に書いてある4-step trainingがないんだけど？
> 開発者：実装してません！end-to-endで学習できるのでいいです！

「オイオイオイオイ」と思い，公式実装を見に行ってみました．

https://github.com/rbgirshick/py-faster-rcnn

実はこれは公式による再実装であり，[正式な実装](https://github.com/ShaoqingRen/faster_rcnn)はMATLABによって行われています．
再実装版のgithubを見てみると，なにやら意味深な[スライド](https://www.dropbox.com/s/xtr4yd4i5e0vw8g/iccv15_tutorial_training_rbg.pdf?dl=0)が貼り付けられています．

スライド39ページには，Alternating optimization(4-step training)についての説明が書かれています．
![スクリーンショット (105).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1119776/676413fb-2214-26ee-6a58-fe6aff4ae0e9.png)
> Primarily driven by implementation issues and the NIPS deadline😊
>> 主に実装の問題とNIPSの期限によって引き起こされた😊

なるほど

スライド47ページ
![スクリーンショット (107).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1119776/99de0347-2877-b58a-6dcf-5f8be65c4b7a.png)
（注：Approximate joint training は，end-to-endでの実装）
> Approximtate joint training is faster and simpler
>> end-to-endで学習したほうが速くてシンプル

とのこと

# おわりに
難しいね
PythonのRequestsでサイズの大きいファイルをダウンロード

Pythonのrequestsモジュールでファイルをダウンロードしたいとする。素直に書くとこう。
```python
import requests
r = requests.get('https://hogehoge/')
with open('hogehoge.zip', 'wb') as f:
  f.write(r.content)
```
ただ、これではファイル全体をメモリに読み込むため、サイズの大きなファイルをダウンロードしようとしてメモリが足りなくなることがあった。
そんなときは、ストリームを使って少しずつ読み書きすればよい。次の例では1MBずつ処理する。

```python
import requests
with requests.get('https://hogehoge/', stream=True) as r:
  with open('hogehoge.zip', 'wb') as f:
    for chunk in r.iter_content(chunk_size=1024*1024):
      f.write(chunk)
```

参考: [Requests / Advanced Usage / Body Content Workflow](https://requests.readthedocs.io/en/latest/user/advanced/#body-content-workflow)
innerHTMLで要素を追加させる

通常DOMを挿入する方法は`appendChild()`や`insertAdjacentHTML()`などがあります。
`innerHTML`は現在のDOM破壊して新しいDOMを挿入します。今回は破壊せずに追加したように見せる方法のメモです。

~~~ html
<ul id="list1">
    <li>item1</li>
    <li>item2</li>
    <li>item3</li>
    <li>item4</li>
    <li>item5</li>
</ul>
~~~
上記のようなリストに`innerHTML`で`item6`を入れてみます
~~~ js
const list1 = document.getElementById('list1');
list1.innerHTML = '<li>item6</li>';
~~~
#### 結果
~~~ html
<ul id="list1">
    <li>item7</li>
</ul>
~~~
結果は`list1`の種類、状態に関係なく、新しく挿入された要素のみになります。
では、既存の要素に追加したように見せる方法です。
~~~ js
const list1 = document.getElementById('list1');
list1.innerHTML += '<li>item6</li>';
~~~
##### 結果
~~~ html
<ul id="list1">
    <li>item1</li>
    <li>item2</li>
    <li>item3</li>
    <li>item4</li>
    <li>item5</li>
    <li>item6</li>
</ul>
~~~
代入部分を加算代入に変更すれば可能です。
これは実際には前の要素は削除され、新しい要素が生成されているので、リストの中にあるイベントは機能しなくなります。
使用するケースとしては、DOM変更と同時に現在リストにあるイベントを消したい、変更したい時などに使用するかなと思いました。

#### 参考
https://into-the-program.com/javascript-add-elements-innerhtml/
エンジニアインターン16日目

今日は前回の反省を生かして作業を進めることができた。スクレイピングするURLの情報を管理画面から入力し、DBに格納した。情報があるときにはINSERT文を情報がないときにはUPDATE文を呼ぶようにした。管理画面の編集画面にURLのカラムを追加し、編集した情報を更新するボタンを押したらＤＢに格納される仕組みだ。作業を進めていく中で情報を更新したはずのデータが管理画面上では更新されない状態であった。原因ＳＱＬ文を書くときにサニタイズのため値を置き換えていたところで、呼び出すときに順番が違っていたため変更されずにそのままの状態であった。正しい順番に修正したところ正常に動くようになった。
インターンでやっていることはある程度作られている状態での作業で一から作ることがあまりない。自分一人でも自習としてコーディングする必要があると感じた。まずはweb制作を一人でしていこうと考えている。先輩エンジニアも仕事以外でもコーディングをしていると聞いた。毎日コードを書くことが大事であることも教えていただいた。自分は大学生のうちに自分一人で仕事を受けられるようになりたいと思っている。だからこそ学んだことをアウトプットしてたくさんコードを書いて一人前のエンジニアになれるように努力しよと思った。
【Git】保護ブランチをコマンドで設定する方法

## 保護ブランチをCLIで設定する

以下を実行するとCLIで保護ブランチを設定できます。

`OWNER_NAME`と`REPO_NAME`は適宜変更が必要です。

``` protect-branch.sh
owner="OWNER_NAME"
repo="REPO_NAME"
repositoryId="$(gh api graphql -f query='{repository(owner:"'$owner'",name:"'$repo'"){id}}' -q .data.repository.id)"

gh api graphql -f query='
mutation($repositoryId:ID!,$branch:String!,$requiredReviews:Int!) {
  createBranchProtectionRule(input: {
    repositoryId: $repositoryId
    pattern: $branch
    requiresApprovingReviews: true
    requiredApprovingReviewCount: $requiredReviews
    isAdminEnforced: true
  }) { clientMutationId }
}' -f repositoryId="$repositoryId" -f branch="main" -F requiredReviews=1

```

実行後は以下のように設定され`main`ブランチには直接`push`できなくなります。

![image221019_204133.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/1b99abce-e6e7-f189-b5c4-abdc02535297.png)

上記以外の設定をしたい場合には以下のページを参照して設定を追加します。

https://docs.github.com/en/graphql/reference/input-objects#createbranchprotectionruleinput
URLの構造をさらっとおさらいしつつ、部分的に抽出する方法

## はじめに
URLの構造を判定して適切な処理をする、みたいなときに役立つことを簡単にまとめる。

## URLの構造
・個人的にはこの図がわ分かりやすいと思っている。[このサイト](https://www.asobou.co.jp/blog/web/url-optimisation)を参照してみてください。
![スクリーンショット 2023-02-17 23.11.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2915639/29f7c76b-e514-fb37-43f5-ece08dea56d1.png)

## URLの構造を部分的に抽出する

```swift:Swift
//元となるURL
let url = URL(string: "https://qiita.com/search?q=swift+ios")

//プロトコル(scheme)の摘出
print("出力：\(url?.scheme ?? "")") //出力：https

//ドメイン(host)の摘出
print("出力：\(url?.host ?? "")") //出力：qiita.com

//ディレクトリ(path)の摘出
print("出力：\(url?.path ?? "")") //出力：/search

//クエリパラメーター(query)の摘出
print("出力：\(url?.query ?? "")") //出力：q=swift+ios
```

## おわりに
間違い等ありましたらコメント欄にてご指摘お願いいたします。

## 参考記事
[【Swift】URLの部分抽出
](https://qiita.com/SNQ-2001/items/a5f7bce8854a2c19bf72)

[分かりやすいURL構造を設計しよう「ディレクトリ名・ファイル名の付け方」
](https://www.asobou.co.jp/blog/web/url-optimisation)

[[増補改訂第3版]Swift実践入門 ── 直感的な文法と安全性を兼ね備えた言語 (WEB+DB PRESS plusシリーズ)　](https://www.amazon.co.jp/%E5%A2%97%E8%A3%9C%E6%94%B9%E8%A8%82%E7%AC%AC3%E7%89%88-Swift%E5%AE%9F%E8%B7%B5%E5%85%A5%E9%96%80-%E7%9B%B4%E6%84%9F%E7%9A%84%E3%81%AA%E6%96%87%E6%B3%95%E3%81%A8%E5%AE%89%E5%85%A8%E6%80%A7%E3%82%92%E5%85%BC%E3%81%AD%E5%82%99%E3%81%88%E3%81%9F%E8%A8%80%E8%AA%9E-PRESS-plus%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA/dp/4297112132)
↑引用元
石川 洋資 (著), 西山 勇世 (著)
発行者：片岡 巌
出版社：技術評論社
印刷/製本：日経印刷株式会社

## 開発環境
- Xcode-13.4.1
- Swift version 5.7
PHP：論理型：ブール変数を使いこなさないといけない

# 例えばif文等で比較する文字数が冗長な時に重宝する

```php
// それぞれの文字列が冗長だと、全体でものすごく長い比較文になってしまう。
if (A >= B && A <= B && C < D)

// そこで、二つに区切って、区切った部分の意味を表現する変数名の変数へそれぞれ代入すると、とても短い比較文になる。
if ($clear && $correct)

```