OmniAICreator/Qiita-1.07M huggingface dataset:
kintoneで別アプリからGET（取得）したフィールドをPUT（更新）する

今回は、別アプリからGETした値でPUTする仕組みについて書きたかったので、
商品マスタの金額を外から更新するアプリを作成してみました。

# アプリの準備

2つのアプリを作成します。

* 商品マスタ（更新される方）
* 商品の金額変更（更新する方）

## 商品マスタアプリ

| フィールド種類 | フィールドコード |備考 |
|:-:|:-:|:-:|
| 文字列(1行)  | 商品ID  |重複禁止   |
| 文字列(1行)  |   商品名|   |
|  数値 |  金額 |   |
|関連レコード|関連レコード|商品マスタ.商品ID = 商品の金額変更.ルックアップ<br>※商品の金額変更アプリ作成後に作る|

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/d6e097c6-acda-8af8-4928-6c8c270919f4.png)


## 商品の金額変更アプリ

| フィールド種類 | フィールドコード |備考 |
|:-:|:-:|:-:|
|ルックアップ|ルックアップ|設定は後述|
| 文字列(1行)  |   商品名| ルックアップから取得  |
|  数値 |  商品のレコード番号|ルックアップから取得   |
|  数値 |  変更後の金額 |  手入力 |
|  数値 |  変更前の金額 |  ルックアップから取得しない |

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/62786872-185e-2787-57fd-fd8d28ab0c35.png)



👀ルックアップフィールドの設定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/e4eca3e6-f596-d0e8-48bf-dd08bcbf8732.png)

# 仕様

今回は「商品の金額変更」アプリの
「レコード追加画面の保存実行前イベント」のみカスタマイズします。
（フィールド値変更時イベントやレコード編集時のマスタ側もいじりたいところではありますが、カスタマイズ量が増えちゃうので）
↓アプリ内操作の流れイメージ

* 「ルックアップ」で、商品の情報を取得する
* 「変更後の金額」を入力する
* 「保存ボタン」で商品マスタの金額を「変更後の金額」で更新する

# JavaScriptを書く

今回は**生のkintone REST API**を使いたいと思います。
GETとPUTを使用します。
ドキュメントはコチラ↓

* [レコードの取得（GET）](https://developer.cybozu.io/hc/ja/articles/202331474)
* [レコードの更新（PUT）](https://developer.cybozu.io/hc/ja/articles/201941784)

## 保存前に商品マスタから現在の金額の取得する

今回、GETを使いたいので「変更前の金額」はルックアップでもってきません。
ルックアップ時ではなくて、保存前に現在の金額の取得をするようにしたいと思います。
また、今回、レコード編集時の事は考えません。

というわけで、まずは「レコード追加画面の保存実行前イベント」で「変更前の金額」をGETしてくるというコードを書きましょう。

取得したいレコードは1件なのでレコード番号から取ってくるようにしましょう。

[kintoneにおけるPromiseの書き方の基本](https://developer.cybozu.io/hc/ja/articles/360023047852)
の、**Column1: async/awaitで直感的に同期的処理を書く**を参考に、コードを書くとこんな感じになります。

```js
// レコード追加画面の保存実行前イベント await 使うので、コールバックには async つけましょう。
kintone.events.on(["app.record.create.submit"], async (event) => {
  const record = event.record;

  // 商品マスタからデータを取得する（ await つけると取ってくるまで待機する）
  const resp1 = await kintone.api(
    kintone.api.url("/k/v1/record", true),
    "GET",
    { app: 【商品マスタのアプリID】, id: record.商品のレコード番号.value }
  );
  // 商品マスタから取得した金額を「変更前の金額」フィールドに入れる
  record.変更前の金額.value = resp1.record.金額.value;

  // ここにPUTするコード書く

  return event;
});
```

## 商品マスタからの金額を更新する

変更前の金額を取得した後はPUTで商品マスタの金額を更新します。

```js
kintone.events.on(["app.record.create.submit"], async (event) => {
  ～省略～

  record.変更前の金額.value = resp1.record.金額.value;

  // 商品マスタの金額を更新する
  await kintone.api(kintone.api.url("/k/v1/record", true), "PUT", {
    app: 【商品マスタのアプリID】,
    id: record.商品のレコード番号.value,
    record: { 金額: { value: record.変更後の金額.value } },
  });

  return event;
});

```

# こんな動作するよ

変更前の金額を取得しつつ、商品マスタの金額を変更します。

<iframe width="400" height="360" src="https://www.youtube.com/embed/f51XoRRjkxs" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

# まとめ
更新される側の「商品マスタアプリ」側で金額を変更した場合はどうなるんだー！とか、「商品の金額変更アプリ」を修正したらどうなるんだー！とか、
死角はたくさんあるので、ここから死角の少ないアプリを作ってみてもらえると楽しいかと思います～👀✨✨
データサイエンス・プラットフォームとは？

「データサイエンス・プラットフォーム」は、2017年からバズワードになっていますが、高度な分析が企業を牽引する時代になった今日、この人気のある考え方が標準になりつつあります。このブログ記事では、データサイエンス・プラットフォームの定義を確認します。強力なデータサイエンス・プラットフォームを構成する特徴と、多くの企業がデータサイエンス・プラットフォームを必要とする理由を説明します。
 
 
##データサイエンス・プラットフォームの定義
データサイエンス・プラットフォームとは、簡単に言えば、データサイエンス・プロジェクトのライフサイクル全体が行われる構造のことです。このプラットフォームには、[データサイエンスプロジェクトのライフサイクル](https://blog.dataiku.com/ai-projects-lifecycle-key-steps-and-considerations)における、各フェーズに必要なツールやリソースが含まれます。開発からデプロイまで、データサイエンスのライフサイクル全体で[使用される人材](https://blog.dataiku.com/data-science-is-a-team-sport-enabling-team-success-on-shared-ai-projects)、ツール、リソース、その他の必要な製品をまとめています。
 
![ifographic-The Data Science Lifecycle-01 (1).jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1196881/046a50ce-d8ac-11f4-21b8-9f03d2a19053.jpeg)

データサイエンス・プラットフォームは、プロセスのスピードを早める強力なツールを使用して、モデルの実行、追跡、再現、共有、展開を、迅速かつ効率的に行い、データサイエンティストの分析を支援します。これらのプラットフォームを通じて、データサイエンスは単なるスキルから、組織的な能力へと進化していきます。


##優れたデータサイエンス・プラットフォームの価値
- 一元化：データサイエンスのプロジェクトには、さまざまなツールやデータソースが関わっています。これらのリソースを[1つの場所に集中させる](https://blog.dataiku.com/building-a-modern-ai-strategy-for-data-platforms)ことで、データサイエンティストやチームは、モデルをデプロイするプロセスを早めることができます。これにより、チーム間のコラボレーションが促進されるだけでなく、必要なものがどこにあるか直接わかるため、新入社員の教育も加速されます。
- 柔軟性：オンデマンドのコンピューティングリソース管理と、それらのリソース上で誰もがデータを扱える柔軟性という意味での[弾力性](https://www.dataiku.com/stories/building-an-elastic-ai-strategy/)は、エンタープライズAIの未来です。したがって、優れたデータサイエンス・プラットフォームは、既存のインフラ投資を活用するために必要な柔軟性を提供しつつ、特定のチームだけでなく組織全体に利益をもたらすことを保証する必要があります。
- セルフサービス機能：データを活用する組織であるということは、役割やチームに関係なく、誰もが自分の仕事に必要なデータに適切にアクセスし、そのデータに基づいて意思決定を行うことができることを意味します。コラボレーションやデータの民主化を組織に取り入れるためには、[セルフサービスによる、データやリソースへのアクセスが](https://www.dataiku.com/stories/self-service-data/)必要です。
 
![pexels-fauxels-3184325.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1196881/8ede17a2-48a3-da35-3bb9-5e927367c51d.jpeg)

 

##すべての企業にデータサイエンス・プラットフォームが必要な理由
Analytics Insight社の調査によると、データサイエンス・プラットフォーム市場は、2025年には3,850億ドルに達すると予想されています。それはなぜでしょうか？ここでは、データサイエンス・プラットフォームを利用することで生じる主なメリットをご紹介します。
 
- [コラボレーション](https://blog.dataiku.com/the-art-of-collaborative-data-science-at-scale)の拡大：データサイエンスプラットフォームは、異なる役割の個人が共同で作業することを可能にし、個人では取り組めない大きな問題にチームで取り組むことを可能にします。コラボレーションは、データの[再利用やアセット化](https://pages.dataiku.com/economics-of-ai)により、データをより活用し、効率的にすることで、[ガバナンスの実践](https://pages.dataiku.com/data-governance-to-ai-governance-capgemini)や会社全体を豊かにします。
- より速く、より効率的なインサイト：データサイエンス・プラットフォームは、より多くのモデルを素早くデプロイするとともに、不整合やエラー率を低減します。APIや簡単な統合プロセスにより、モデルのデプロイがより簡単かつ効率的になります。
- データ量の拡大：これらのプラットフォームでは、様々な種類のデータに簡単、迅速、かつ安全にアクセスできるため、チームは大量のデータを扱うことができます。これにより、より信頼性の高いデータ駆動型のインサイトを生み出すことができます。
- より安全なガバナンス：データサイエンス・プラットフォームは、一貫性、集中性、透明性のあるプロセスにより、信頼性と監査性のある結果を保証します。
 
データサイエンス・プラットフォームは、企業が多くのメリットを認識するにつれ、その重要性を増しています。問題はもはや、"我々の会社にデータサイエンス・プラットフォームは必要か？"ではなく、"我々の会社に必要なのはどのデータサイエンス・プラットフォームか？"ということです。

<br>
<font color="LightSeaGreen">**さらにご関心のある方は、ぜひこちらをご覧ください。**
[**「なぜ企業にデータサイエンス、機械学習、AIのプラットフォームが必要か」**](https://pages.dataiku.com/why-enterprises-need-ml-ai-platforms-j)</font>



原文：[*What Is a Data Science Platform?*](https://blog.dataiku.com/what-is-a-data-science-platform)
（お知らせ）アマゾンKindle電子書籍として『シアトルで実践する「プログラミング的思考」』を出版しました

すでにNoteに無料で公開されている内容ですが、Kindle電子書籍としてまとめて販売します。（Noteは日本国内の銀行口座が無いので収益化が出来ません。）

https://www.amazon.co.jp/dp/B09LM24XBK

読み放題の Kindle Unlimited なら興味のある個所だけ読めます。
PHPのswitchで複数条件分岐をしてみましょう！

複数条件がある時はswitchを使ってコードを書いていきます！

```php:index.php
<?php

$bread = 'クロワッサン';  

switch ($bread) {
  case 'メロンパン':
    echo '美味しい!' . PHP_EOL;
    break;
  case 'クロワッサン';
    echo 'サクサク！' . PHP_EOL;
    break;
  case '食パン':
    echo 'ふわふわ！' . PHP_EOL;
    break;
}
```
ターミナルに以下を実行します！

```
~$ php index.php
```
このように表示されました！

```
~ $ php main.php
サクサク!
~ $ 
```


$bread = 'クロワッサン'; の条件を変えてみます！

```php:index.php
<?php

$bread = '食パン';  //　← 食パンに変えてみます！  

switch ($bread) {
  case 'メロンパン':
    echo '美味しい!' . PHP_EOL;
    break;
  case 'クロワッサン';
    echo 'サクサク！' . PHP_EOL;
    break;
  case '食パン':
    echo 'ふわふわ！' . PHP_EOL;
    break;
}
```

先程と同じくターミナルで以下を実行します！

```
~$ php index.php
```

条件を変えると、
以下のように違う出力結果になりました！

```
~ $ php main.php
ふわふわ!
~ $ 
```
Githubでコメントを書くときに, リストのインデントをサクッと入れる

まずはインデント入れたいところで文字選択をします

![スクリーンショット 2021-11-12 102840.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1765956/008dc123-04f4-5b30-cb95-07d8908c8685.png)

Tabキーを押します

![スクリーンショット 2021-11-12 102851.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1765956/f490cc88-20c9-967f-d093-5876730960a7.png)

おわり

## いろいろ

* Shift+Tabだと普通にインデントが減ります
* インデントは2スペースです
* VSCode上だと, 何も文字を選択しなくてもTabでインデントが下がるので地味に気が付かなかったです
* ![スクリーンショット 2021-11-12 103245.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1765956/383b7da2-622c-07da-c3b7-0d7e86ebd3ad.png) の選択の仕方でももちろんインデント下がります

## 終わりに

頑張ってスペースポチポチしていた時間は一体何だったのだろうか…
2021.11.12現在 → nRF9160 feather と J-Link あれこれ


（nRF9160-DKには J-Link の機能が搭載されているので 別途 J-Linkを入手する必要はない）


J-Link は、プログラムの書き込み装置 ＆ デバッグ用装置。

nRF1960 feather で DFU モードから開放されたいと思ったら、↓これ↓ が必要になる。

https://www.segger.com/products/debug-probes/j-link/

ただし、J-Link EDU や J-Link EDU Mini なら安めだが、基本的に結構お高い。

格安のクローン製品なども流通しているが、ちょっと心配なきもする。

そんなときに使えるのが、J-link 代わりに使える開発ボード。

https://docs.jaredwolff.com/nrf9160-programming-and-debugging.html

上記サイトでは、

Requirements for external programming and debugging
You can also use external programmers with the nRF9160 Feather. Here are the current supported external programmers:

・nRF5340-DK
・nRF9160-DK

Note: Most commercial J-Link programmers *should* work with the nRF9160 Feather. In particular the J-Link EDU Mini is a great choice if you're building non-commercial products. (Supports Cortex M33 processors. Untested at this time.)

🚨Important: the nRF52 and nRF51 based development kits do not work with the nRF9160 Feather!

👉Additionally, you'll also need a Tag-Connect cable. The nRF9160 Feather was designed to use the TC2030-CTX-NL. For more information check out Tag-Connect's product page.


とある。

　nRF5340-DK や nRF9160-DK があれば J-Link の代わりになるよ。
　非商用もくてきなら J-Link EDU Mini でも大丈夫だよ。
　でも、ニードルタイプのコネクタケーブルも入手しないと feather では使えないよ。

そんな感じ。

とはいえ ニードルタイプのコネクタケーブル も結構お高い。
試しに格安品を入手してみたが、数回使ったら断線した……。
都度修理すれば使えるが、面倒なのでちゃんとしたのを入手したほうが良いと思われる。


nRF9160 feather、ケチらずにピンコネクタをつけてくれればよかったのにと思う今日この頃。


* * *

以上。

* * *
PHPの論理演算子を使ってみよう！

PHPの論理演算子で条件をまとめてみましょう！

```php:index.php
<?php
$score = 30;
$name = 'kana';
if ($score >=20) {
  if($name === 'kana') {
    echo '素晴らしい！' . PHP_EOL;
  }
}
```

ターミナルで以下を実行すると...

```
~ $ php index.php
```
このように表示されました！


```
~ $ php index.php
素晴らしい！
~ $ 
```

ではこちらの処理をもっと見やすく、

「&&」と言う論理演算子でまとめて書いていきます。

「&&」は、なおかつやandという意味です！

```php:index.php
$score = 30;
$name = 'kana';
if ($score >=20 && $name === 'kana') {
   echo '素晴らしい！' . PHP_EOL;
}
```
先程と同じようにターミナルに以下を入力します！


```
~$ php index.php
```
先程と同じ結果が出力されました！

```
~ $ php index.php
素晴らしい！
~ $ 
```

同じコードでも、論理演算子を使うと見やすくなりました　☆

```php:index.php                          
index.php
<?php
$score = 30;
$name = 'kana';
if ($score >=20) {
  if($name === 'kana') {
    echo '素晴らしい！' . PHP_EOL;
  }
}
```
```php:index.php
$score = 30;
$name = 'kana';
if ($score >=20 && $name === 'kana') {
   echo '素晴らしい！' . PHP_EOL;
}
```
Python Enum ベストプラクティス

PythonのEnumについての一番シンプルな方法を紹介します。
（他のどの記事よりも実用的で分かりやすいはず・・・）
これだけ理解すれば困ることはほとんどありません！

## Enumとは

定数を列挙して、ステータス管理などに便利です。
C#などを経験している方はPythonでもEnumを使いたくなりますよね。

## 公式ドキュメント

公式ドキュメントでは、
Enum, IntEnum, Flag, IntFlag, FlagBoundaryなどありますが、基本の「**Enum**」だけで十分だと思います。
（コードのシンプルさを考慮してもEnumだけが良いです）

> [Enum 公式ドキュメント](https://docs.python.org/ja/3/library/enum.html)

## ソースコード

Enumは説明よりコードを見る方が手っ取り早いので、さっそく紹介します。

Enumの名前と値の一覧を取得したいときもたまにあるので、
Classmethodとして実装しています。

### Case1 ソースコード

```python
from enum import Enum

class EnumColor(Enum):
    RED = 1
    GREEN = 2
    BLUE = 3
    YELLOW = 4
    
    @classmethod
    def get_names(cls) -> list:
        # Enum定義が増えても対応可能
        return [i.name for i in cls]
    
    @classmethod
    def get_values(cls) -> list:
        # Enum定義が増えても対応可能
        return [i.value for i in cls]

if __name__ == "__main__":

    print(EnumColor.RED)
    print(EnumColor.RED.name)
    print(EnumColor.RED.value)

    # 全ての名前を取得
    print(EnumColor.get_names())

    # 全ての値を取得
    print(EnumColor.get_values())

    yourColor = EnumColor.RED
    if(yourColor == EnumColor.RED):
        print("your color is red")

    print("--- for loop ---")
    for x in EnumColor:
        print(x)
        print(x.name)
        print(x.value)
    print("--- for loop end---")

    # 値からEnum要素を取得
    print(EnumColor(2))

    # 値からEnum要素の名前を取得
    print(EnumColor(2).name)
```

### Case1 出力結果

```
EnumColor.RED
RED
1
['RED', 'GREEN', 'BLUE', 'YELLOW']
[1, 2, 3, 4]
your color is red
--- for loop ---
EnumColor.RED
RED
1
EnumColor.GREEN
GREEN
2
EnumColor.BLUE
BLUE
3
EnumColor.YELLOW
YELLOW
4
--- for loop end---
EnumColor.GREEN
GREEN
```

### Case2 Enumの値に文字列含む

Enumの値には文字列を含めることが可能ですので簡単に紹介します。
使い方はCase1と全く同じです。

```python
class EnumColorStr(Enum):
    RED = "red"
    GREEN = "green"
    BLUE = "blue"
    YELLOW = "yellow"
    
    @classmethod
    def get_names_all(cls):
        return [i.name for i in cls]
    
    @classmethod
    def get_vals_all(cls):
        return [i.value for i in cls]

print(EnumColorStr.get_names_all()) # 出力：['RED', 'GREEN', 'BLUE', 'YELLOW']
print(EnumColorStr.get_vals_all()) # 出力：['red', 'green', 'blue', 'yellow']
```

以上、Enumのベストプラクティスでした。
これさえ知っていれば何にでも活用できます！

## 更新履歴

* 2021/11/12 初版
メモ〜djangoのmodel, queryset, get_querysetについてまとめる

今回のお題
-
今回はdjangoアプリの`model`, `qeuryset`, `get_queryset`についてまとめます。

これらは全て`ListView`においてレコードを取得する際に用いられ、どれか一つが指定されていればテンプレートにインスタンスが渡ります(modelに関しては他のテンプレートニューでも利用可能）が、この3つの関係性が自分の中で今ひとつ整理できていなかったのでメモとして残しておきます。

ビューからテンプレートにインスタンスのリストが渡る仕組み
-
`ListView`の継承元の一つである`MultipleObjectMixin`には、`model`, `queryset`という二つの属性値と`get_querysetメソッド`が定義されている(属性値ふたつの初期値は`None`)。

テンプレートにcontextが渡る際には参照されるのは`queryset`の値であり、最終的にはここに目的のリストが入っていれば良い。

`queryset`をテンプレートに渡すための方法は3つあり、

- ビューの初期値として設定する
- modelを指定してquerysetに変換する
- get_querysetメソッドの中でquerysetを取得できるようにする

のいずれかをとることになる。

```python:get_querysetの中身
class MultipleObjectMixin(ContextMixin):
    """A mixin for views manipulating multiple objects."""
    allow_empty = True
    queryset = None
    model = None
    paginate_by = None
    paginate_orphans = 0
    context_object_name = None
    paginator_class = Paginator
    page_kwarg = 'page'
    ordering = None

    def get_queryset(self):
        """
        Return the list of items for this view.

        The return value must be an iterable and may be an instance of
        `QuerySet` in which case `QuerySet` specific behavior will be enabled.
        """
        # querysetがあればそこからインスタンスを取得
        if self.queryset is not None:
            queryset = self.queryset
            if isinstance(queryset, QuerySet):
                queryset = queryset.all()
        # querysetがなくてもmodelがあればそこからインスタンスを取得可能
        elif self.model is not None:
            queryset = self.model._default_manager.all()
        else:
            raise ImproperlyConfigured(
                "%(cls)s is missing a QuerySet. Define "
                "%(cls)s.model, %(cls)s.queryset, or override "
                "%(cls)s.get_queryset()." % {
                    'cls': self.__class__.__name__
                }
            )
        ordering = self.get_ordering()
        if ordering:
            if isinstance(ordering, str):
                ordering = (ordering,)
            queryset = queryset.order_by(*ordering)

        return queryset
```

get_querysetメソッドの中でqeuryセットを取得する場合には、querysetを取得した後に継承元のget_querysetを呼び出す形になる（以下参照）。

```python
def get_queryset(self):
  keyword = self.request.GET.get("keyword")
  if keyword:
    self.queryset = Menu.objects.filter(name__contains=keyword).all()
  else:
    self.queryset = Menu.objects.all()
return super().get_queryset()
```

以下のようにただ単に`self.queryset`を返して終わっている例も見かけるが、大元のget_querysetメソッドには`ordering`の処理などもあるので`super().get_qeuryset()`も呼び出しておいた方が無難かなと個人的には思った（検証はしていないです）。

```python
def get_queryset(self):
  keyword = self.request.GET.get("keyword")
  if keyword:
    self.queryset = Menu.objects.filter(name__contains=keyword).all()
  else:
    self.queryset = Menu.objects.all()
return self.queryset
```
Scala for式

## for式
ループを処理する式。
ジェネレーター、定義、フィルターで構成される。

## Sample
```Scala
    for (p <- persons; n = p.name; if n startsWith "C")
        yield print(n + ", ")
        
    for {
        p <- persons          // Generator
        n = p.name            // Definition
        if n startsWith "C"   // Filter
    } yield print(n + ", ")
```

## GitHub
https://github.com/GL-Kageyama/Scala_ForExpression
Scala 暗黙の型変換&暗黙のパラメーター

## 暗黙の型変換
暗黙的な型変換は、一方の肩からもう一方の肩への明示的な型変換の宣言を減らすことが出来る。

## 暗黙のパラメーター
Scalaコンパイラーは暗黙的にパラメーターを補足し、関数呼び出しを完了出来る。

## 要求された型への変換
```Scala
    // A function that implicitly converts Double to Int
    implicit def doubleToInt(x: Double): Int = { 
        x.toInt 
    }
    val i: Int = 3.5
    println(i) // 3
```

## レシーバーの変換
```Scala
    // Function to implicitly convert from Int to Rational
    implicit def intToRational(x: Int): Rational = {
        new Rational(x, 1)
    }

    val oneHalf = new Rational(1, 2)
    val intOne = 1

    // intOne implicitly converted to Rational type
    val rationalPlusInt = oneHalf + intOne
    println(rationalPlusInt) // 3/2
    println(rationalPlusInt.isInstanceOf[Rational]) // true
```

## 暗黙のパラメーター
```Scala
    val animal = new Animal

    // Argument is implicit parameter list 
    animal.bark(dogBark, catBark) // Dog barks is Bow-wow. Cat barks is Mew-mew.

    // Possible to omit implicit parameters
    animal.bark // Dog barks is Bow-wow. Cat barks is Mew-mew.
```

## GitHub
https://github.com/GL-Kageyama/Scala_Implicit
2021.09.02現在 → nRF9160 用ライブラリの脆弱性


https://jvn.jp/vu/JVNVU90467655/

上記URLに、

・Zephyr Project RTOS 2.5 より前のバージョン 

とある。

nRF connect SDK では、ncs v1.6.0 から Zephyrのバージョンが2.6に上がる。
（それ以前は、2.4.99）

念の為、代理店の担当者に問い合わせてみたところ、v1.6.0 より前のバージョンは
上記、脆弱性に該当するという回答をもらった。


* * *

以上、ご参考まで。

* * *
Android 11 API30 以降に対応したアプリ開発用メモ

2021年11月からプレイストアの要件でターゲットAPIバージョンが30以降になったことに伴い、作業で躓いたポイントのメモです。

-------

## 前提
Android API30 の要件により、端末内へのアクセスなどをする場合は以降に記載する作業が必要になっています。
私の場合はアプリからブラウザを呼び出すために作業が必要でした。
[Android でのパッケージの公開設定のフィルタリング  |  Android デベロッパー  |  Android Developers](https://developer.android.com/training/package-visibility)


## AndroidManifest.xml への追記
プロジェクト名/android/app/src/main/__AndroidManifest.xml__
に必要な情報を追記します。
私の場合は以下を記載しました。
```
<queries>
        <intent>
        <action android:name="android.support.customtabs.action.CustomTabsService"/>
    </intent>
    </queries>
```

[Android 11のPackage visibilityへの対応 - Qiita](https://qiita.com/ryo_mm2d/items/18739c30cd251192ad8a)


## build.gradle の編集
通常は上記までで対応が完了するようなのですが、
デバッグおよびビルドに失敗したため追加の作業が必要でした。
[error: unexpected element <queries> found in <manifest>の解決方法【Unity】 - なえ箱](https://nae3na.hatenablog.com/entry/gradle-error-queries)
および
[Android Gradle プラグインのリリースノート  |  Android デベロッパー  |  Android Developers](https://developer.android.com/studio/releases/gradle-plugin?hl=ja)
を参考に
プロジェクト名/android/app
/__build.gradle__
内の
__classpath 'com.android.tools.build:gradle:3.5.0'__
の後半のバージョン番号を変更します。
使用しているパッケージなどで適切な番号が変わるようで1つのプロジェクトは__3.4.3__で一方は__4.1.0__でした。


## まとめ
新しいバージョンのFlutterを使っている場合はAndroidManifest.xmlの編集だけでいいのかもしれません。
私の場合はアクセシビリティの問題があり、__2.1.0-12.2.pre__を使っている関係で追加の作業が必要だったようです。
早く修正されて余分な作業をせずに済むようになってほしい物です。
こちらの問題については下記に記載しています。

[1年間Flutterで開発をしていてわかったアクセシビリティの問題(Android編) - Qiita](https://qiita.com/yama_1983/items/6c51e83b980c512019ab)
Scala Sealed

## Sealed
Sealedクラス/トレイトは、同じファイル内でのみ継承出来る。

## Sealed class sample
```Scala
sealed abstract class Animal

case class BirdAnimal() extends Animal
case class CatAnimal() extends Animal
case class DogAnimal() extends Animal
```

## Sealed trait sample
```Scala
sealed trait Animal

case class BirdAnimal() extends Animal
case class CatAnimal() extends Animal
case class DogAnimal() extends Animal
```

## GitHub
https://github.com/GL-Kageyama/Scala_Sealed
Scala List : 高階演算子

## 高階演算子
別の関数をパラメーターとして受け取る関数。

## Sample
```Scala
    val words = List("We", "are", "Scala", "!")
    val oneToFile = List(1, 2, 3, 4, 5)
    val minusFiveToFive = List(-5, -4, -3, -2, 1, 0, 1, 2, 3, 4, 5)
    val zeroList = List(0, 0, 0, 0, 0)
    var value = 0

    // map
    val m = words map (_.toList)
    println(m) // List(List(W, e), List(a, r, e), List(S, c, a, l, a), List(!))

    // flatMap
    val fMap = words flatMap (_.toList)
    println(fMap) // List(W, e, a, r, e, S, c, a, l, a, !)

    // foreach
    oneToFile foreach (value += _)
    println(value) // 15

    // filter
    val fil = oneToFile filter (_ % 2 == 0)
    println(fil) // List(2, 4)

    // partition
    val par = oneToFile partition (_ % 2 == 0)
    println(par) // (List(2, 4),List(1, 3, 5))

    // find
    val fin = oneToFile find (_ % 2 == 0)
    println(fin) // Some(2)

    // takeWhile
    val tWhile = minusFiveToFive takeWhile (_ < 0)
    println(tWhile) // List(-5, -4, -3, -2)

    // dropWhile
    val dWhile = minusFiveToFive dropWhile (_ < 0)
    println(dWhile) // List(1, 0, 1, 2, 3, 4, 5)

    // span
    val spa = minusFiveToFive span (_ < 0)
    println(spa) // (List(-5, -4, -3, -2),List(1, 0, 1, 2, 3, 4, 5))

    // forall
    val fAll = List(0, 0, 0, 0, 0) forall (_ == 0)
    println(fAll) // true

    // exists
    val exi = List(1, 1, 0, 1, 1) exists (_ == 0)
    println(exi) // true

    // foldLeft
    val fLeft = oneToFile.foldLeft(0)((x, y) => x + y)
    println(fLeft) // 15

    // foldRight
    val fRight = oneToFile.foldRight(0)((x, y) => x + y)
    println(fRight) // 15

    // sortWith
    val sWith = words sortWith (_.length > _.length)
    println(sWith) // List(Scala, are, We, !)
```

## GitHub
https://github.com/GL-Kageyama/Scala_List_HigherOrderOperators
【Kotlin】KTypeとKClassのちがいが知りたい

# クラス ≠ 型

**KClass**は、クラス定義そのものの情報。
**KType**は、変数の型情報。

「クラス」は「型」の情報の一部。「クラス」＝「型」**ではない**。

たとえば、変数の型は`Nullable`で宣言できる。

```kotlin
class Something(
  val str: String?
)
```
Nullabilityは変数の**型としての情報**であって、クラス自体の定義にはふくまれない。

このように「型」は「クラス」が含まない情報を持つことがあるので、
Kotlinはこれらを区別し、それぞれ**KType**と**KClass**というクラスを与えている。


# 実用面
リフレクションでクラスのフィールドの型情報を取得するようなケースだと、**KType**で扱ったほうが都合がよさそうだ。

たとえば、クラスにジェネリクス変数(*type parameter*)を持ったフィールド、典型的には`List型`があるとする。

```kotlin
class Something2(
  val list: List<String>
)
```
リフレクションでフィールドの型情報を収集したいとき、**KClass**からは型のジェネリクス変数のクラス情報(List\<String\>でいう`String`)までは取得できない[^1]。
**KClass**は単なるクラス定義で、クラス定義上ではジェネリクス変数は具体的な型情報を持たないからだ。
この点**KType**はジェネリクス変数のクラス情報まで取得できる[^2]。ありがたい。

このほか、`Nullablility`だとかの型としての情報が欲しければ、`KType`。
クラスのコンストラクタ情報が欲しいだとかは、`KClass`をつかう。ちがいが分かれば、使い分けはそこまで難しくない。


# むすびと参考
リフレクションでフィールドのList\<String\>でいうString相当の情報がとれず時間を使ったので、**屍**として置いておきます。
JavaにはKTypeに相当するものがあった記憶がありません。あったのかな…

参考サイト
https://discuss.kotlinlang.org/t/why-is-kclass-not-a-ktype/3341

[^1]: [KClass#typeParameters](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.reflect/-k-class/type-parameters.html)というそれっぽいAPIはありますが、こいつは型パラメータそのもの("out T"とか)を返す模様です
[^2]: 型のクラスが持つジェネリクス変数のクラス情報は[KType#arguments](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.reflect/-k-type/arguments.html)でとれます。「型のクラスが持つジェネリクス変数のクラス情報」:thinking_face:
続EPM7032

せっかく[いろいろ調べた](https://qiita.com/yamori813/items/208ea6d9b25a2c38bb73)ので、MAX7000でJTAGが使えるEPM7032SLCをAmazonの中国発送物資で3つ入手してみました。

もちろん3つで送料込みで1000円くらいでした。今調べたらもうないです。

ポチッたのが10/27で11/10着でした。4PX->シノトランス・エア・ジャパン->佐川できました。

![4px.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/421114be-2164-7554-6e05-d2671cd9d962.png)

![saga.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/e37eb9c6-0cbb-b89a-340d-30723ea0029d.png)

製造年週が9907,9919,9931なので中古品から回収したものではないかと思われます。

とりあえずFT2232でurjtagでみてみたのですが、3つとも認識できません。

Quatus II 13.0sp1のUSB Blasterでも認識できません。

中古品なのでJTAGがディセーブルになってるようです。

いろいろ調べてみると高電圧(12V)で初期状態に戻せるという情報があります。たまたま手元にEX-80用に40年前にかった電源があったので5Vを加えてVPP(OE1:44)に12Vをつんつんしてみました。本来はなんらかのパルスのようなのですが、回路などの情報がまったく見当たらなかったので、職人の感で手動でやってみました。

見えました。正しい方法か分からないのでよい子のみなさんは真似しないでくださいね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/5f06571a-7062-10cb-9a4c-15b7305ccb9e.png)

めでたしめでたし。

MAX IIと同じLチカしてみたのですが、使用率が78%になりました。最小のMAX7000なのでそんなもんなのかもしれません。ちなみにMAX II(EPM240T100C5)では10%でした。

7474で2分周できるので24Bit分であれば12個(7474は2回路入り)で出来るはずです。CPLDでビットカウンターは効率が悪いような気がします。

EPM7032の書き込み保証回数は100回程度ですが、製品で使われていたのであれば1度しか書き込まれていないと思われ、問題ないと思います。

FT2232でurjtagでは認識できませんでした。pull up,downの抵抗値の調整が必要なのかもしれません。

EPM7000Sシリーズは5Vですが、これ以降は3.3Vなどになっています。EPM7000SシリーズはZ80などの昔の8Bit CPUでそのまま使えるので貴重かもしれません。
PowerShellのスクリプトにTimeoutを設定する

<h3>PowerShell内の処理せず残り続けることを避けるためにTimeoutを設定し、一定時間経過後に終了させる方法です。</h3>

####外部から受け取った引数を変数に設定
　Param(\$Arg1, \$Arg2)
####処理したい内容をfunctionとして記述
　\$function_hogehoge = {
    　Param(\$Arg1, \$Arg2)
    　　　処理の内容を記載する
　} 
#### タイムアウトの設定(秒)
　\$timeOut = 30

#### Jobの実行、引数を設定
　\$job = Start-Job -ScriptBlock \$function_hogehoge -ArgumentList \$Arg1, \$Arg2


#### timeOutで指定した時間の経過後は、Jobを終了する。

　Wait-Job -Job \$job -Timeout $timeoutSeconds | Out-Null

　if(\$job.State -eq "Completed"){
    　　"正常終了"
　}elseif(\$job.State -eq "Running"){
    　　"まだ実行中"
　}elseif(\$job.State -eq "Failed"){
     　　"失敗"
　}

#### 状態に関係なく強制終了
　Remove-Job -Force \$job
【SwiftUI】CoreDataでUnexpected found nil~ のエラー

#何の記事？

Swiftでスマホ内にデータを保存させたいときに用いるのがCoreDataです。
CoreDataって何？という方はこちらをご参照ください。

https://capibara1969.com/3178/

今回仕様変更のため新しい項目（Attribute)を追加したのですが、
データを呼び出す際に下記のエラーが出て新しい項目のみ保存できず、
数日ハマりまし。解決策のメモです。

```
Fatal error: Unexpectedly found nil while unwrapping an Optional value
```

#解決策
テスト実機内に保存されている以前のデータを全て削除したところ、
エラーが消え、読み込めるようになりました。
以上です。
2021.11.11現在 → nRF9160 と 技適

nRF9160 は Nordic Semiconductor ASA にて技適が取得されている。

005-102122
D19-0085005

Revision 1（B0）
https://www.nordicsemi.com/Products/Low-power-cellular-IoT/nRF9160-Revision-1-global-and-regulatory-certifications

Revision 2（B1）
https://www.nordicsemi.com/Products/Low-power-cellular-IoT/nRF9160-Certifications

総務省のサイトでの検索結果
https://www.tele.soumu.go.jp/giteki/SearchServlet?pageID=jk01&NUM=&NAM=&FOM=nRF9160&PC=&YAR_FROM=&MON_FROM=&DAY_FROM=&YAR_TO=&MON_TO=&DAY_TO=&RAD=00-00-00-00&TEC=1&TEC=2&TEC=3&TEC=4&TEC=5&TEC=6&TEC=7&SK=0&DC=0&SC=1&as_fid=36c52bded77802d6f8d9f7510011b4687b98115e#searchlist



# 技適マーク付きの開発基板

　・ PASSY-NRF9160-FEATHER　nRF9160 Feather (Circuit Dojo)

　　v1.3（黄色い基板）で確認。
　　（古いバージョンの nRF9160 Feather（黒い基板）には技適マークの刻印がない）

　　　![IMG_0839.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/190537/99c4a332-3a73-d5c9-eeda-cf9c3d04fea4.jpeg)



　・ SCO-M5SNR9160-B,SCM-LTEM1NRF0B モノプラットホームβ (さくらインターネット)　　
　　　![IMG_0973.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/190537/14bdda5d-d506-150f-f180-de272ec950f4.jpeg)




# 技適マークが無い開発基板（パッケージにもマークなし）

　技適を取得した Nordic Semiconductor が提供している評価基板には、技適マークがない。

　・ nRF9160DK (Nordic Semiconductor) https://www.nordicsemi.com/start9160dk
　・ Thingy:91 (Nordic Semiconductor) https://www.nordicsemi.com/thingy91

　ただし、箱に製品の公式ページへのURLが記載されており、
　そこで Certification ページへのリンクがはられており技適の詳細が確認できる。

　総務省のサイトで技適マークの表示について確認すると、
　https://www.tele.soumu.go.jp/j/sys/equ/tech/gitekimark/index.htm
　”表示方法を記載した取扱説明書を添付する等、技適マークを表示する方法を明らかにする必要があります。” 
　とある。

　どこまで緩和されているのか判断できなかったので、
　関東総合通信局の技適マークのＱ＆Ａ に問い合わせてみたところ、ノルディックの開発基板はやはり NG らしい。
　
# 未確認の基板

　・WRL-17354　SPARKFUN THING PLUS - NRF9160　（SparkFun）
　・NL-SWNDK　（NimbeLink）


# アンテナ

　技適にはアンテナも含まれるので、対象外のアンテナを使用すると技適マーク付きでもＮＧとなる。

　下記URLに、

https://www.nordicsemi.com/Products/Low-power-cellular-IoT/nRF9160-Revision-1-global-and-regulatory-certifications


　Japan’s TELEC regulatory approval requires the use of antennas with less than 3 dBi gain in any direction. This is a non-exhaustive list of antennas we expect to meet that requirement. Please follow the reference design from the antenna vendor.
　（日本のTELEC規制当局の承認では、どの方向でも3dBi未満のゲインを持つアンテナを使用する必要があります。 これは、その要件を満たすことが期待されるアンテナの網羅的ではないリストです。 アンテナベンダーのリファレンスデザインに従ってください。）

　との記載がある。

　アンテナの一覧があるが”網羅的ではない”という点が気になった。

　実際、

　featherには、UnictronのWC12H0
　さくらのSCM-LTEM1NRF0Bには、TAOGLASのFXP40

　という上記URLに記載のない型番の外部アンテナが付属している。


　このあたりもよくわからなかったので、関東総合通信局の技適マークのＱ＆Ａ に問い合わせてみた。

　技適を取得したメーカー（nRF9160の場合は、Nordic Semiconductor ASA）にて承認されたものなら大丈夫らしい。


　よくわからないときは、技適を取得したメーカー、該当製品のメーカー、技適マークＱ＆Ａ 等に確認すれば確実だと思われる。


* * *
間違えや補足があればご一報ください。
以上、ご参考まで。
* * *
goenvで最新のGoをインストールできない時にやったこと

## はじめに
Goのバージョン管理をgoenvを使ってやっているのですが、goenvを使って最新のGoがインストールできなかったので、その対処方法をまとめました。

## goenvでのバージョン管理
goenvを使っている場合、指定のバージョンのGoをインストールするために以下のコマンドを使います。

### インストールできるバージョンの確認
```shell
$ goenv install -l
Available versions:
  1.2.2
  1.3.0
  1.3.1
  1.3.2
  1.3.3
　　　　.
  .
  .
  1.11.1
  1.11.2
  1.11.3
  1.11.4
  1.12beta1
```

ここで新しいバージョンのGoをインストールできないことに気がつきました。

### 指定のバージョンをインストール
```shell
$ goenv install 1.11.4
```

## 解決方法
自分はgoenvをHomebrewで管理していて、Homebrewを使ってgoenvをアンインストール、そして再インストールしてもうまく行きませんでした。

今回はHomebrew経由ではなく、git経由でgoenvをインストールすることで解決することができました。

```shell
$ git clone https://github.com/syndbg/goenv.git ~/.goenv
```

git経由でgoenvをインストールし、Goのバージョンを確認してみると

```shell
$ goenv install -l
Available versions:
  1.2.2
  1.3.0
  1.3.1
  1.3.2
  1.3.3
　　　　.
  .
  .
  1.17beta1
  1.17rc1
  1.17rc2
  1.17.1
  1.17.2
```

増えていました。

後は指定のバージョンのGoをインストールして完了です。

```shell
$ goenv install 1.17.2
$ goenv global 1.17.2
$ goenv rehash
```


## 参考資料
今回はこちらの記事を参考にしました

https://qiita.com/yut-kt/items/9f5ac1e788df61f64290
Azure CLI : Error converting Authorization Token to an ADAL Token

ある日、AzureのCloud Shellからterraformを実行すると、パースエラーが発生しました。

```
$ terraform apply
...
| Error: Error converting Authorization Token to an ADAL Token: Error parsing Token Expiration Date "":Error parsing expiration date "".
| 
| CloudShell Error:
| parsing time "" as "2006-01-02T15:04:05Z07:00": cannot parse "" as "2006"
|
| CLI Error:
| parsing time "" as "2006-01-02 15:04:05.999999": cannot parse "" as "2006"
|
```

コマンド`az login`により、再ログインすることで解消しました。

エラーメッセージ内の`Token Expiration Date`が空であることから、トークンの有効期限が切れていたために発生したエラーかと推測しています。
パースに失敗したと言っていることから、バージョン差異を疑ったりして、解消までに時間をかけてしまったため、備忘録として記録しておきます。。。

**備考：環境情報**

* azure-cli 2.30.0
* Terraform v1.0.10
Gatsbyでのリンクの付け方


```hello.jsx
import React from 'react';
import { Link } from "gatsby";

const HelloPage = () => {
  return (
    <Link to="/note">noteページへGo!</Link>
  )
}

export default HelloPage
```

# 参考サイト
* [Gatsby Link API](https://www.gatsbyjs.com/docs/reference/built-in-components/gatsby-link/)
【GAS】noteの記事一覧のデータを取得

## note の記事をWPへ移管

結論から言うと移管は難しくて無理でした。
なので今回はnoteの記事一覧から取得してきたタイトル、投稿日時、抜粋、アイキャッチを、WP記事一覧ページ上に並べ、クリックするとnoteの記事詳細ページに飛ぶと言う仕組みにしました。今後はWPで投稿する予定なので一覧ページをシームレスにするために、noteから取得したデータをcontentのない記事としてWP投稿し並べたいと思います。

## noteの記事一覧APIをGASで叩く

noteのクリエイター記事一覧ページのjsonデータは
https://note.com/api/v2/creators/${username}/contents?kind=note&page=1
で取得(usernameにクリエイターIDを入れる)。

```JavaScript

function myFunction() {
  const sheet = SpreadsheetApp.getActiveSheet();
  const userName = 'hoge'; // クリエイターID
  const maxPage = 15; // あらかじめ確認
  const baseUrl = 'https://note.com/api/v2/creators/' + userName + '/contents?kind=note&page=';

  let count = 2;

  for( let i = 1; i <= maxPage; i++ ) {
    const url = baseUrl + i;
    const jsonData = UrlFetchApp.fetch(url);
    const dataObject = JSON.parse(jsonData);
    const contents = dataObject.data.contents;
    const contentsLength = contents.length;
    const keys = Object.keys(contents[0]);
    const keysLength = keys.length;

    if( i == 1 ) { // テーブルのヘッドをセット
        for( let i = 0; i < keysLength; i++) {
        let cell = sheet.getRange(1, 1 + i);
        cell.setValue(keys[i]);
      }
    }

    for( let i = 0; i < contentsLength; i++ ) { // コンテンツの塊を回す
      let content = contents[i];
      for( let j = 0; j < keysLength; j++) {　 // 1コンテンツの中身を回す
        const range = sheet.getRange( i + count, 1 + j);
        const key = keys[j];
        range.setValue(content[key]);
      }
    }
    count = count + contentsLength;
  }
}


````

1つの記事には以下52の情報入ってました。

id
type
status
name
description
likeCount
price
key
slug
publishAt
thumbnailExternalUrl
eyecatch
user
canRead
isAuthor
externalUrl
customDomain
body
separator
isLimited
isTrial
canUpdate
tweetText
isRefund
commentCount
likes
anonymousLikeCount
isLiked
disableComment
hashtags
twitterShareUrl
facebookShareUrl
lineShareUrl
audio
pictures
limitedMessage
labels
priorSale
canMultipleLimitedNote
isPinned
pinnedUserNoteId
spEyecatch
enableBacktoDraft
notificationMessages
isProfiled
isForWork
isCircleDescription
noteDraft
noteUrl
imageCount
format		

## WordPressへ一括アップロード
今回はこのデータから「タイトル」「抜粋」「投稿日時」「アイキャッチ画像URL」だけを取り出して、WPのカスタム投稿「note記事」として一括アップロードします。

#### 使用したプラグイン
https://ja.wordpress.org/plugins/wp-all-import/

GASでセットした表データをそのままCSVとして出力し、WP All Import > New import からアップロード。
どのフィールドに、CSVデータのどの項目を使うかを問われるので、ドラッグ&ドロップで指定。
カスタムフィールドと画像は、課金してProにしないと使えないらしく。
無理矢理contentのフィールドに、noteアイキャッチ画像URLを入れ、あとはtitle, excerpt, date, slug をその通りにセット。

インポートは10秒くらいで完了しました。

今回は記事をクリックしたらnoteの記事詳細に飛べばいいので、

新着記事一覧ページのループで、post type が note の時という条件分岐で、煮たり焼いたりしてうまく表示させました。

終わり。
技術にもっと自由な解釈を

![ 2021-11-12 6.24.07.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102082/51479e1a-46e1-af03-0e26-9cc6d05433d3.jpeg)

私の暮らし方を突き放して分析してみると、たぶんこのようになります。同じ道を進むことに興味のある方はおられますか。技術そのものをより自由に解釈できるスキルのある人間が、世界にはもっと必要な気がします。

元々私はスケールする技術を使う人間ですが、スケールさせることを本気で考えるのは、ブランドに乗せた時です。ブランドから自由にソロで動けば、小さく、自由に、イテレーティブに回せる。技術を自家薬籠に入れてしまえば、ブランドに乗せても確実に回せる。

技術にもっと自由な解釈を与えること、それそのものがオープンソースという手段の本質ですね。

整理された正統教義どおりに日々の儀式を遂行するカセドラルではなく、技術からあらゆる価値を汲み尽くすバザールである、ということですね。カセドラルとバザールを自在に行き来する「人間」ということが、「カセドラル」や「バザール」という個別の場所（手法）ということよりも重要で魅力的である、という状態を作り出す。それが我々がすでに行っており、また我々がこれから行わなければならないことであるように思います。

最後に、今手がけている作業結果の例を置いておきます。サーバが動いていれば、画像をクリックすると実際のサイトにつながるかもしれません。

[![ 2021-11-12 6.21.44.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102082/5900fd96-f32e-4ad4-e734-5d30fc5b6f95.jpeg)](https://x.optgeo.org/kid-c/#18.03/35.100966/138.862883/128.8/60)

# 2021-11-13 追記：本当は怖い伽藍とバザール
このエントリをご覧いただきありがとうございます。このエントリを出してから、[本当は怖い伽藍とバザール](https://qiita.com/hfu/items/e43f87a97ccf788ac2db)への LGTM を複数いただきました。確かに、深く関係ある話だと思いますし、こちらのエントリは本当の「伽藍とバザール」からの抜き書きですので、より重みがあります。

![ 2021-11-13 7.54.12.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102082/649edb70-7c74-1955-16f5-2d38a4dd9d13.jpeg)

「楽しみが能率をあげる」ということであり、また「伝統的なソフトウェアプロジェクトの60%から75%は、結局完成せずに終わるか、あるいはその予定顧客に拒絶される」という現実の傾向の中で、いかに「限られている唯一のリソースである、才能ある人々の関心」を糾合していくか、ということなのではないかと思っています。

# 2011-11-13 追記:イテレーティブということ
イテレーティブとは何でしょう。「解決策を実装してみるまでは、問題を完全には理解しきれない」という状況の中で、まずは「実装してみることで理解をする」ということをします。これが、ラフを何度か描く、ということに似ているかもしれません。イテレーティブということに関する私の理解はおおよそこういうところです。プロトタイプは3つ目からまともに評価可能になる、という感覚があります。

行政のシステムでは、使用する技術を教本レベルでも理解せずに発注するということがあると聞きますが、本来は「2回は失敗して3回目を作っているところ」辺りからではないと、集団を統率してプロジェクトを動かすことはできない、という技術分野もあるように思います。

私が関わっているウェブ地図の分野は、おそらくそういった技術分野です。レイヤとして薄い・浅いからこそイテレーティブに回せる、という側面もあるかもしれません。ウェブ地図というのは、薄くて浅いからこそ、高いクオリティとパフォーマンスを求められる技術分野です。だからこそ、どれだけ反復をして改善ができたか、という世界になります。

ウェブ地図は薄くて浅い。地図ですから。だから何度でも繰り返す。

あるいは、イテレーティブとは、「最適化をする、しかし早すぎる最適化は行わない」という意味であるように思いました。あるいは、イテレーティブとは、「適切な最適化を実施するのに最短のやり方」なのかもしれません。
Danger Zone「押すなよ押すなよ」の解決策

https://togetter.com/li/1480818

https://twitter.com/warpbtn/status/1237924624442068993?s=20

よくある「本当によろしいですか？」的UIの議論。

> システム: 「この操作は元に戻すことはできません。よろしいですね？」
> システム: 「よろしいですね？」

結果、脳死で**「押す」**ユーザー。押すなよ押すなよ問題とでも言いたい。押した結果、やはり押してはいけなかったことが発覚し結果インシデントが発生する...

GitHubとかでリポジトリ削除する周りはこんな感じになっていますよね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93824/a58908e2-735e-0251-b4e6-a1b02e2c5eb0.png)
で、ちょっと手間かけないと本当には消せない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93824/1743922f-6e23-a16e-90e0-7d1e301f8d4f.png)
これはまあ親切なほうの設計... でもUIの世界ムズカシイ。

https://www.reddit.com/r/UI_Design/comments/llxuh3/danger_zone_we_need_more_of_this/


## 対策

自分の周りでも、と身近なプロダクトの話を書きたいところだが省略。

https://note.com/flyaway/n/n7e446a4fd8e8

> 誤操作は個人の問題ではないと捉え、総合的な対策を立てる

しかないのかなあと思いつつ。かろうじて思い出したのは以下です。例えばこの音楽が流れる社の給湯器。

<iframe width="962" height="541" src="https://www.youtube.com/embed/rrNLJcWClS8" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

お風呂を沸かすボタンを押す時に、「お湯はりをします　**お風呂の栓の閉め忘れに　注意してください**」と言いますね。
<iframe width="962" height="541" src="https://www.youtube.com/embed/hxYL8_8oC6I" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

警告はされている。が、それでも人は栓を閉め忘れるし、「お風呂の栓が抜けてるかも」も機械に教えてほしいと言う。

[「お風呂の栓が抜けてるかも」も機械に教えてほしい？　メーカーの回答は… (2019年11月23日) - エキサイトニュース](https://www.excite.co.jp/news/article/Sirabee_20162203832/)

> 担当者は、「エラーメッセージが流れるまで、冬場だと約10～15分かかる。これ以上時間を短くすることは**今の技術では不可能。**一般的にお湯の量を160リットルと設定すると、その量がたまっていないということを、お湯が出ている場所で感知している。つまり、お湯が出ている場所まで届くと、その吹き出し口でお湯を循環させる。お湯が設定量排出されているのに、吹き出し口に届いていなければ、音声とエラー番号が出る仕組みとなっている。最新の機種では、水圧でお湯の量を感知しているが、警告までの時間は変わらない



## 結論

15分で被害がおさまっているなら御の字ではとシステム目線では言いたいような、またここまでしているのだからお風呂の栓で失った水道代くらい、とも思うが、「栓を閉めないとお風呂沸かしボタンを押せない」ような画期的なUIをつくるかとか。

[風呂の栓の忘れ対策は、何かありますか？ - ウチはオール電化で、... - Yahoo!知恵袋](https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q12167726922)
> 機械が質問をしているのですから、愚直に確認して答えてやる。
> しかも声に出して言うのは、良いとおもいます。

なんていうユーザー側でのトレーニングも解決策かもしれない。風呂の栓を締めることを身体で覚える。あるいは担当者固定とか...。

結局「総合的な対策を立てる」式の話をしてしまいそうだが、押すなよ押すなよ、難しいんだよなあと思った。ポエムとして以上です。
styled-components の基本的な書き方

# `styled-components`をインストール
```bash
$ npm add styled-components
```

# 書き方

```ListStyleComponent.jsx
import styled from 'styled-components';

export const Li = styled.li`
  border-left: 4px solid lightgray;
  margin-top: 12px;
  padding-left: 12px;
    &:hover {
      border-left: 4px solid orange;
    }
  line-height: 1.8;
`;

export const DateStyle = styled.span`
  font-size: small;
  color: gray;
`;

export const ListTitle = styled.div`
  line-height: 1.5;
`;
```

```NoteArticlesComponent.jsx
import React from 'react';
import {Li, DateStyle, ListTitle} from './ListStyleComponent';

const articleLists = [
  {
    id: 1,
    date: "YYYY/MM/DD",
    title: "aaa",
    url: "https://xxx..."
  },
  {
    id: 2,
    date: "YYYY/MM/DD",
    title: "bbb",
    url: "https://xxx..."
  },
  {
    id: 3,
    date: "YYYY/MM/DD",
    title: "ccc",
    url: "https://xxx..."
  },
];

const NoteArticlesComponent = () => (
  <>
    {articleLists.map((list) => (
      <ul>
        <Li key={list.id}>
          <a href={list.url}>
            <DateStyle>{list.date}</DateStyle>
            <br />
            <ListTitle>{list.title}</ListTitle>
          </a>
        </Li>
      </ul>
    ))}
  </>
);

export default NoteArticlesComponent
```

# 参考サイト
* [styled-component Getting Started](https://styled-components.com/docs/basics)
【備忘録】Linuxパーミッションのメモ

パーミッション周りの操作を忘れやすいため、備忘録として残しておきます。

##パーミッションの確認
``` 
ls -l 対象ファイル名
drwxrwxrw- 3 taro users 0 11月 22 16:28 hoge.txt
#縦棒で区切る： drwxrwxrw-|3|tarousers|0|11月 22 16:28|hoge.txt
```
### 1カラム目：パーミッション情報(先頭の10文字)
1文字目: ファイルの種別
	-: ファイル
	d: ディレクトリ
	|: シンボリック
2文字目: ファイルの所有者の権限(r)
3文字目: ファイルの所有者の権限(w)
4文字目: ファイルの所有者の権限(x)
5文字目: ファイルの所有グループの権限(r)
6文字目: ファイルの所有グループの権限(w)
7文字目: ファイルの所有グループの権限(x)
8文字目: その他のユーザーの権限(r)(所有者出ないかつグループにも属さないユーザー)
9文字目: その他のユーザーの権限(w)(所有者出ないかつグループにも属さないユーザー)
10文字目:その他のユーザーの権限(x)(所有者出ないかつグループにも属さないユーザー)
※-の場合は権限なし

### 2カラム目：リンクされている数/サブディレクトリ数(3)
ファイルの場合：ハードリンク数
ディレクトリの場合：サブディレクトリ数
### 3カラム目：ファイルの所有者 ファイルの所有グループ(taro users)
ファイルの所有者：2文字目~4文字目
ファイルの所有グループ：5文字目~7文字目
### 4カラム目：ファイルサイズ(0)
### 5カラム目：日時(11月 22 16:28)
### 6カラム目：ファイル名(hoge.txt)


## アクセス権限の変更
♦︎数字で権限を変更する

``` 
$ chmod モード(3桁)　対象ファイル名
$ chmod 764 hoge.txt 
```

1桁目: 所有者
2桁目: 所有グループ
3桁目: その他
※モード(数字)の合計値を桁ごとに入力する

```
権限: モード(アルファベット): モード(数字)
読み取り:  r: 4
書き込み: w: 2
実行: x: 1
```
上記コマンドの「764」は下記のように設定していると読み取れます。
・所有者：読み取り/書き込み/実行
・所有グループ：読み取り/書き込み
・その他：読み取り






--------------------------
♦︎アルファベットで権限を変更する

```
$ chmod g+w hoge.txt
$ chmod モード(アルファベット) 対象ファイル名
```

カテゴリー
u: ユーザー(所有者)
g: グループ
o: その他のユーザー
a: すべてのユーザー

定義
=: 指定した権限にする(指定)
+: 指定した権限を追加する
-: 指定した権限を削除する

権限
r: 読み取り
w: 書き込み
x: 実行
s: SUID/SGID
t: スティッキーピット
Laravel SailでXdebugを有効化する

Laravel SailとXdebugにDockerfileのカスタマイズが必要な記事が多く出てきましたが、
2021/8/04にでた、Laravel Sail v1.9.0から公式でサポートしているので、そちらですすめていきます。


1.9.0未満の場合はアップグレードが必要です。

# 前提
- Laravel Sailインストール済み
- Sailのdocker-compose.ymlファイルがプロジェクトに存在している
- composer.jsonの`"laravel/sail"`が**1.9.0以上**

# 1.Laravel Sailの停止

Laravel Sailが起動していたら停止します。

```
sail down
```

# 2.`.env`の編集

下記をLaravelの`.env`に追加します
(MacとWindows(WSL2)用)

```
SAIL_XDEBUG_MODE=develop,debug
```

※Linuxの場合は[LinuxホストIP設定](https://readouble.com/laravel/8.x/ja/sail.html?header=Linux%E3%83%9B%E3%82%B9%E3%83%88IP%E8%A8%AD%E5%AE%9A)でIPの設定が必要です

#3.docker-compose.ymlの確認

デフォルトのままだとありますが、1.9.0未満だとなかったので確認します。
Sailのdocker-compose.yml内の`laravel.test`の`environment`に下記があることを確認します。

```
XDEBUG_MODE: '${SAIL_XDEBUG_MODE:-off}'
XDEBUG_CONFIG: '${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}'
```

例: 

```yml
laravel.test:
        build:
            context: ./vendor/laravel/sail/runtimes/7.4
            dockerfile: Dockerfile
            args:
                WWWGROUP: '${WWWGROUP}'
        image: sail-7.4/app
        extra_hosts:
            - 'host.docker.internal:host-gateway'
        ports:
            - '${APP_PORT:-80}:80'
        environment:
            WWWUSER: '${WWWUSER}'
            LARAVEL_SAIL: 1
            XDEBUG_MODE: '${SAIL_XDEBUG_MODE:-off}'
            XDEBUG_CONFIG: '${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}'
        volumes:
            - '.:/var/www/html'
        networks:
            - sail
        depends_on:
            - mariadb
            - redis
```

※アップグレードした場合一度` sail build --no-cache`で再ビルドが必要です

#5.確認

起動して確認します

```
sail up -d
sail php --version

PHP 7.4.25 (cli) (built: Oct 22 2021 12:34:59) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
    with Zend OPcache v7.4.25, Copyright (c), by Zend Technologies
    with Xdebug v3.1.1, Copyright (c) 2002-2021, by Derick Rethans
```

ブラウザでの使用法は[こちら](https://readouble.com/laravel/8.x/ja/sail.html?header=Xdebug%20%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6%E4%BD%BF%E7%94%A8%E6%B3%95)
Auto Hot Keyのコメントの書き方

# はじめに
Windowsを使う上で超絶便利なAuto Hot Keyですがコメントの書き方に謎の制約があったのでメモ書きです。

https://www.autohotkey.com/

# コメントの書き方
AHKでは`/* */`で囲うことでコメントが書けますが，コメントであることを表すこのコメントシンボルは必ず<font color='red'>行頭に書かれていなければいけない</font>という決まりがあります。

C言語とか書いたことある人は逆にハマりそうな仕様。私も2分くらい困りました。


具体的には，下記はコメントになりますが

```
/*
Alt+Kでカタカナに変換する。
*/
!k::Send,{F7}
```

下記はコメント終了のシンボル（`*/`）が行頭にないためコメントになりません。
(正確にはコメントの終了記号がないため2行目のキーコードもコメントの一部と見なされてしまい動作しません。)

```
/* Alt+Kでカタカナに変換する。*/
!k::Send,{F7}
```

下の例のパターンではコンパイルエラーも出ないので，なぜか`Alt+K`を押してもカタカナにならないという挙動になります。

余談ですが`Alt+K`でカタカナに変換するというのはOSXの`Ctrl+K`によるカタカナ変換のリスペクトです。F7キーは遠くて押しづらいので変えています。

また，セミコロンで行末にコメントを書くこともできます。

```
!k::Send,{F7} ; Alt+Kでカタカナに変換する。
```

# おわりに
私は普段MacBookをよく使うのでそれに合わせたウィンドウ操作やVim風のカーソル移動のキーバインドを設定するなどAHKは大変重宝しています。
LoLのチート対策ツールにBANされたりと色々悩みもありますが快適なキーバインドで快いインターネット生活をしましょう。
Laravel 多重クエリを濫用してしまってパフォーマンスを落とさない為のtips

以下のモデルがあったとする。

```php
<?php

namespace App\Http\Models;

use App\Core\Models\Bases\BaseModel;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;

class Car extends BaseModel
{
    /**
     * 現在、車がある店舗
     *
     * @return Store|BelongsTo
     */
    public function store(): BelongsTo
    {
        return $this->belongsTo(Store::class);
    }
}

```

そして以下のように使ってみる。

```php
Route::get('/guest', function () {

    $car = \App\Http\Models\Car::find(1); // １クエリ目
    dump($car->store->id);                // 2クエリ目
    dump($car->store->id);
    dump($car->store()->first()->id);     // 3クエリ目
    dump($car->store()->first()->id);     // 4クエリ目
    dump($car->store()->first()->id);     // 5クエリ目

    return view('welcome_guest');
});
```

全部で５クエリ発行されている。

![スクリーンショット 2021-11-12 1.36.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125469/2ca48b9a-6c6a-19b8-5cb1-99cfd0c9f47e.png)

`$car->store()`はModelに定義しているリレーションメソッドの戻り値であるBelongsToであるのに対し
`$car->store`はModelに定義しているリレーションメソッドではない。

テーブル名をリレーション名にするのが通なので気づきにくいが以下でもOK。

```php
<?php

namespace App\Http\Models;

use App\Core\Models\Bases\BaseModel;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;

class Car extends BaseModel
{
    /**
     * 現在、車がある店舗
     *
     * @return Store|BelongsTo
     */
    public function aaa(): BelongsTo
    {
        return $this->belongsTo(Store::class);
    }
}

```

```php
Route::get('/guest', function () {

    $car = \App\Http\Models\Car::find(1); // １クエリ目
    dump($car->store->id);                // 2クエリ目
    dump($car->store->id);
    dump($car->aaa()->first()->id);       // 3クエリ目
    dump($car->aaa()->first()->id);       // 4クエリ目
    dump($car->aaa()->first()->id);       // 5クエリ目

    // NGな書き方
    dump($car->store()->id); // そんなメソッドない。
    dump($car->aaa->id);     // そんなリレーションないので$car->aaaの時点でnull

    return view('welcome_guest');
});
```

という予備知識を踏まえた上で、クエリビルダーの状態（`$car->store()`）からfirstやgetなどすればその分クエリーが発行される。
`$car->store`ならクエリは発行されない。ただし、
`$car = \App\Http\Models\Car::find(1)`を行った時点でのstoreの情報しか取れないので、
`$car = \App\Http\Models\Car::find(1)`を行った後にどこか別のところでcar_id1に紐づくstoreの情報を更新されていたら時系列的にその情報は取得できないというズレが発生することがある。

例えば、ユーザーサイトと運営側による管理画面があるとして、CS業務によってユーザー情報を更新しつつもユーザーもサイトを利用していることを想定すればどちを使えば良いのかは分かってくるだろう。

このことを覚えておけば、無駄なクエリ発行を行うような記述はなくなるがたまに忘れるので残しておく。

この処理はクエリ発行数が少ないから２つぐらいクエリ増えたところで問題ないからfirstで取っとけば良い、という考え方もあるが個人的にお勧めはしない。ちゃんと要件に合わせて取捨選択すべき。
HomebrewでPython3を入れたときにpip3が入らなかったら

Homebrewでpython3を入れようとした

```shell
$ brew install python3
　（中略）
==> /usr/local/Cellar/python@3.9/3.9.7_1/bin/python3 -m ensurepip
Last 15 lines from /Users/*/Library/Logs/Homebrew/python@3.9/post_install.01.python3:
　（中略）
subprocess.CalledProcessError: Command '['/usr/local/opt/python@3.9/bin/python3.9', '-c', '\nimport runpy\nimport sys\nsys.path = [\'/private/tmp/tmp7r1s7_i7/setuptools-57.4.0-py3-none-any.whl\', \'/private/tmp/tmp7r1s7_i7/pip-21.2.4-py3-none-any.whl\'] + sys.path\nsys.argv[1:] = [\'install\', \'--no-cache-dir\', \'--no-index\', \'--find-links\', \'/private/tmp/tmp7r1s7_i7\', \'setuptools\', \'pip\']\nrunpy.run_module("pip", run_name="__main__", alter_sys=True)\n']' returned non-zero exit status 1.
Warning: The post-install step did not complete successfully
You can try again using:
  brew postinstall python@3.9
```
python自体は使えるが、正常に完了しない

そして、pipを使おうとすると

```shell
$ pip3 -V
pip 19.0.3 from /Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.7/lib/python3.7/site-packages/pip (python 3.7)
```

思ってたのと違う……

#結論
https://pip.pypa.io/en/stable/installation/
ここに書いてあった

```shell
$ python3 -m ensurepip
```
これで`~/Library/Python/3.9/bin`にpipがインストールされる

再度pythonインストール

```shell
$ brew reinstall python3
```
こんどは正常にインストール完了し、`/usr/local/bin/`にもシンボリックリンクが作成される
（再インストールしないでも普通に`$ brew postinstall python@3.9`でよかったかもしれない）

```shell
$ pip3 -V
pip 21.2.4 from /Users/*/Library/Python/3.9/lib/python/site-packages/pip (python 3.9)
```
pipのアップデートもしておきましょう

```shell
$ pip3 install --upgrade pip
Defaulting to user installation because normal site-packages is not writeable
Requirement already satisfied: pip in ./Library/Python/3.9/lib/python/site-packages (21.2.4)
Collecting pip
  Using cached pip-21.3.1-py3-none-any.whl (1.7 MB)
Installing collected packages: pip
  Attempting uninstall: pip
    Found existing installation: pip 21.2.4
    Uninstalling pip-21.2.4:
      Successfully uninstalled pip-21.2.4
Successfully installed pip-21.3.1
```

参考になったが今回の解決法とは違っていた情報たち
https://ja.stackoverflow.com/questions/44308/homebrewでpython3をインストールするとpipが使えない
https://stackoverflow.com/questions/47255517/brew-install-python3-didnt-install-pip3