OmniAICreator/Qiita-1.07M huggingface dataset:
Redux Toolkit導入メモ

#### reduxで使われるワードの意味
<b>State</b>：アプリケーションの状態
<b>Store</b>：アプリケーション内の全てのstateを保持している場所
<b>Action</b>：アプリケーションのstateをどのように変更するかの注文表みたいな役割
<b>Action creator</b>: Actionのtype(注文表)を生成する関数
<b>Reducer</b>：Actionのtype(注文表)に応じてstateを変化させる関数

#### reduxルール
* Storeはアプリケーションに1つのみ存在する。
* Stateを変更できるのは、Reducerのみ。// storeのstateはグローバル変数なので、どこの処理でデータが描き変わったか
* ReducerはStore内のStateを、action typeに応じて新しいStateに更新する
* Reducerは常に同じ結果を返す

## 手順
#### step1 Redux ToolkitとReact-Reduxをインストール  
```
npm install @reduxjs/toolkit react-redux
```

#### step2 storeを作成
自動的に、Redux DevTools extensionと連携してくれます。

https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd?hl=ja

app/store.js

```
import { configureStore } from '@reduxjs/toolkit'

export default configureStore({
  reducer: {}
})
```

#### step3 ReactのRootコンポーネントをProviderコンポーネントでラップする
step2で定義したstoreをProviderコンポーネントのstoreにpropsで渡すと、storeにreduxが用意しているAPIを使うとstoreの要素にアクセスすることができます。

```
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'
import store from './app/store'
import { Provider } from 'react-redux'

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
)
```

#### step4 createSliceでreducer関数と、action creator関数を定義
 
features/counter/counterSlice.js

```
import { createSlice } from '@reduxjs/toolkit'

export const counterSlice = createSlice({
  // action typeのprefix
  //　一意である必要があるため名前がぶつかることを防ぐ
  name: 'counter',
  // 初期値
  initialState: {
    value: 0
  },
  // reducer
  // dispatchで送られてきたaction creatorをもとに下記に定義されているreducerが実行され、storeのstateを書き換える
  reducers: {
    increment: state => {
      state.value += 1
    },
    decrement: state => {
      state.value -= 1
    },
    incrementByAmount: (state, action) => {
      state.value += action.payload
    }
  }
})

// action creator
export const { increment, decrement, incrementByAmount } = counterSlice.actions

export default counterSlice.reducer
```

#### step5 storeにstep4で生成したreducerを追加する

app/store.js

```
import { configureStore } from '@reduxjs/toolkit'
import counterReducer from '../features/counter/counterSlice'

export default configureStore({
  reducer: {
    counter: counterReducer
  }
})
```

#### step6 コンポーネントで呼び出してみる

features/counter/Counter.js

```
import React from 'react'
import { useSelector, useDispatch } from 'react-redux'
import { decrement, increment } from './counterSlice'
import styles from './Counter.module.css'

export function Counter() {
  // stateは、storeのstateでcounterは、storeのreducerのkeyが入って、valueは、createSliceのinitialValueが参照されます。
  const count = useSelector(state => state.counter.value)
  const dispatch = useDispatch()

  return (
    <div>
      <div>
        <button
          aria-label="Increment value"
          onClick={() => dispatch(increment())}
        >
          Increment
        </button>
        <span>{count}</span>
        <button
          aria-label="Decrement value"
          onClick={() => dispatch(decrement())}
        >
          Decrement
        </button>
      </div>
    </div>
  )
}
```

以上
【Laravel】EloquentでOR検索する方法

# 環境
Laravel: 8.82.0
PHP: 8.1.2

# OR検索
文字列で検索ができるようにOR検索を導入しようとしたときでした。
とりあえず少し調べて、以下のコードで実行しました。

```php:失敗パターン
$keyword = $request->keyword;

$user = Auth::user();
$items = $user->items()->where("name", "like", "%".$keyword."%")
            ->orWhere("text", "like", "%".$keyword."%")->get();
```

これで OR 検索をしようとすると、
`->where("name", $keyword)`は、ログインしている User の結果だけを返すのですが、
`->orWhere("text", $keyword)`は、<font color="#f00">__全ての User__</font>の結果を返すのです。

__なんでやねん！__

とツッコミを入れながらも、改善案を探すことにしました。

## ダメな理由

ダメな理由は条件の書き方にありました。

`$user`の`item`に対して`name`または`text`がキーワードを含んでいたら、というつもりで書いていました。
つまり、`item`に対しての条件で考えていたのです。

しかし、先程の記述では
`$user`の`item`に対して`name`がキーワードを含む
または、`$user`に対して`text`がキーワードを含んでいたらになっていたのです。

その際に、`$user`に`text`というカラムが存在しないため、
全件一致という扱いを受けて、実質`$user->all()`（<font color="#f00">__全ての User__</font>）と同義になってしまったという訳です。

これでは想定している動作とは異なるので、
条件の書き方を修正する必要があります。

## `where`でまとめる

検索してみると、`where`をまとめることができるようです！
早速まとめてみます！

```php:失敗パターン
$keyword = $request->keyword;

$user = Auth::user();
$items = $user->items()->where(function ($query) {
            $query->where("name", "like", "%".$keyword."%")
                ->orWhere("text", "like", "%".$keyword."%");
            })->get();
```

これで大丈夫と思ったのですが、エラーが出ます。
スコープの問題で、「`$keyword`なんて知らない」といわれます。

これでも悩みました。。。

## `use`で変数を渡す
そうしていると、先輩が解決方法を教えてくださり、

```php:成功パターン
$keyword = $request->keyword;

$user = Auth::user();
$items = $user->items()->where(function ($query) use ($keyword) {
            $query->where("name", "like", "%".$keyword."%")
                ->orWhere("text", "like", "%".$keyword."%");
            })->get();
```

`use`を使って解決できたのでした。
DynamoDBの問題と解消法を端的にまとめてみた



###GSIをすごく多くしないと要件を満たせない
→　行と列を入れ替えたテーブルを作成してGSIを定義する
下の例だと３つの列の情報が一つのカラムにまとまっているため検索条件を複数指定できる（多重定義）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/969819/e43456c7-2183-c71e-d1dc-ae80cc4f4d39.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/969819/ae27bb09-6c56-5a25-33bf-3e0d350d9b66.png)

###3つ以上の条件でレコードをフィルターしたい
→　３つ目以降の条件はクエリフィルターで絞り込みを行う
→　（３つだった場合）２つ目と３つ目のキーを結合してしまう（Composite key）

###アイテムのデータの大小が混在している（メールで言うと本文のサイズの大小）
→　（メールを例に考えると）本文が必要なければそれ以外の要素を抽出したGSIを定義する

###時系列でデータをコントロールしたい（ホットデータとコールドデータを分けたい）
→　lambdaとdynamostreamsを組みわわせてTTLに基づいてアーカイブする（アーカイブ用のテーブルを作成する）

###特定のパーティションに読み込みが集中するのを避けたい
→　キャッシュで対処（DAXやElasticacheなど）

###特定のパーティションに書き込みが集中するのを避けたい
→　キューやストリームを活用（SQSやKinesis）
→　ランダムにパーティションに配置されるようなクエリを作成する（Insert: “~~” + rand(0, 10) 




https://d1.awsstatic.com/webinars/jp/pdf/services/20181225_AWS-BlackBelt_DynamoDB.pdf
MacPorts で GrADS をインストールして起動しない時 (Monterey)

MacPortsにてGrADS 2.2.1をダウンロードして，起動すると下記のエラーが出た．

```
GX Package Error: dlopen failed to get a handle on gxprint plug-in named "Cairo"
   dlopen(/opt/local/lib/grads/libgxpCairo.dylib, 0x0001): symbol not found in flat namespace '_gxdXflush'
GX Package Terminated
```

調べると[このようなページ](http://gradsusr.org/pipermail/gradsusr/2017-September/041188.html)がヒットする．曰く，`-h GD`オプションをつけるとgxprit（これが何者か理解してないが）をCairoではなくGD（[本家]()ではclassicとも呼ばれてる）へ指定するそう．

```
~ % grads -h GD

Grid Analysis and Display System (GrADS) Version 2.2.1
Copyright (C) 1988-2018 by George Mason University
GrADS comes with ABSOLUTELY NO WARRANTY
See file COPYRIGHT for more information

Config: v2.2.1 little-endian readline grib2 netcdf hdf4-sds hdf5 opendap-grids geotiff shapefile
Issue 'q config' and 'q gxconfig' commands for more detailed configuration information
GX Package Initialization: Size = 11 8.5
ga->
```
無事起動しました！

ただ，これが自分の環境に固有の問題なのかどうかはよく分かっておりません．誰かの役に立てば幸いです．．

***
参考，gradsコマンドのオプションの説明
[Starting and Quitting GrADS](http://cola.gmu.edu/grads/gadoc/start.html)
rsyncのメモ 

# 要望

- rsyncでssh接続したい
- ポートの指定
- リモート　→　ローカルへのコピー
- あるディレクトリは除外したい


```
rsync -avz --rsh="ssh -p 2222" user@host:hostのディレクトリ ローカルのディレクトリ --exclude '除外ディレクトリ'
```

- ローカル　→　リモートへのコピー
- ssh接続（鍵指定）

```
rsync -avz --rsh="ssh -i ~/.ssh/鍵の名前" ローカルのディレクトリ user@host:リモートのディレクトリ
```

参考サイト
- https://www.ninton.co.jp/archives/3601
- https://www.softel.co.jp/blogs/tech/archives/5267
- https://www-creators.com/archives/1543
Xplenty中級編  Part7： パッケージのExport/Import機能

パッケージのExport/Import機能は、Xplentyのパッケージ定義をJSON形式でExportし、JSONの中身を直接変更し、再アップロードしたり、別のアカウント環境へそのままコピーするのに非常に便利です。
このブログでは、パッケージを別のアカウント環境へコピーする方法についてご紹介します。

###1. 任意のパッケージを開き、「Export　JSON」ボタンをクリックし、JSON形式のパッケージ定義ファイルをダウンロードする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65461/aa5afcd1-0df7-8336-e1ca-b64c5cd5d612.png)

###２.　パッケージをテキストエディタで開く。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65461/25384db7-6043-acd5-aa0b-64363548da26.png)

###3. コピー先のアカウント環境で新規でパッケージを作成し、「Import JSON」ボタンをクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65461/a410634c-2c8c-618b-e0f2-a35e15abc1b3.png)

###4.　手順2のテキストディタのテキストをコピーし、貼り付け「Import」ボタンをクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65461/b66438fa-f87e-5776-d9af-63d034bc7e16.png)

###5. パッケージが正しく表示され、左上のバージョンが1.1となっていれば、コピー完了です。（Saveは不要です）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65461/06ddc375-41e6-f20e-d517-acb900c32c5e.png)
GNU nanoエディタの使い方

# nanoとは
Linuxに最近インストールされているテキストエディタだ。
私はvimerですが、vimは操作を覚えるのがちょっと大変なので、
初心者はnanoを使ったほうが良い場面がありそう。
というわけで、nanoの使い方を調べていく。

# 公式ページ
https://www.nano-editor.org/
![nanotop02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6384/c6948011-5316-6b46-5cd1-ed6653e8099b.png)
なんだか分かりにくそうなページ。
Documentを読んで基本操作を調べる。

https://www.nano-editor.org/dist/latest/cheatsheet.html

![nano_doc_short_cut_05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6384/8e68b9ed-151b-9ef9-ba0a-e45ba009d78c.png)

# 基本操作

カーソルを右に動かす キーボード カーソルキー →
カーソルを左に動かす キーボード カーソルキー ←
カーソルを上に動かす キーボード カーソルキー ↑
カーソルを下に動かす キーボード カーソルキー ↓

デリートキーで文字を消して、
入力した文字がそのままテキストファイルに記入されるっぽい。

ファイルの保存が Ctrl + S
エディタの終了が Ctrl + X

ワード検索 Ctrl + W

# 使ってみる

## テスト用ファイルを用意
青空文庫夏目漱石こころのテキストファイルを用意。

操作はMacのターミナルで行います。
青空文庫のテキストファイルはデフォルトでSJISなのでUTF8に変更します。

```bash
wget https://www.aozora.gr.jp/cards/000148/files/773_ruby_5968.zip
unzip 773_ruby_5968.zip
cat kokoro.txt | nkf -w > kokoro.UTF8.txt
nano kokoro.UTF8.txt
```

![kokor1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6384/12c1691d-494e-076f-13db-8d4cb79620e0.png)

カーソルキーを↓に一回、右に数回入力してカーソルキーを移動。
This is KOKORO file.
をキーボードからタイプして入力。

![kokoro2edit.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6384/0e11a2dd-e3d5-a68f-573f-ab2ff1b9f95f.png)

入力できた。

「恋は罪悪」で検索してみる。
Ctrl + Wの後に「恋は罪悪」をキーボードから入力。コピペでも可。
検索する単語を入力したらエンターキーをぽん！ 

![kokoro3kensaku.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6384/30ca48c1-a14b-ba00-5658-2619009cf422.png)

![kokoro4kensaku.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6384/22125383-fecf-499a-4681-b2812fe88b85.png)

ヒットした。


保存してエディタを終了
Ctrl + Xを入力
エディターボトムに

```text
Save modified buffer (ANSWERING "No" WILL DESTROY CHANGES) ?
 Y Yes
 N No           ^C Cancel
```
が表示されたので、
Yキーを一回ぽん！と叩く。

次の表示に切り替わる。

```text
File Name to Write [DOS Format]: kokoro.UTF8.txt
^G Get Help                   ^T To Files                   M-M Mac Format                M-P Prepend
^C Cancel                     M-D DOS Format                M-A Append                    M-B Backup File

```

ファイル名 kokoro.UTF8.txt 、DOS Formatで保存すると聞いているので、
エンタキーを一回ぽん！と叩く。

エディタが終了してターミナルに戻る。

```bash
head -n 5 kokoro.UTF8.txt
```

![ss27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6384/30c724de-2063-3653-ba27-5d23993e6c93.png)

変更内容が保存されていることを確認。
【備忘録】Codewar(JavaScript)勉強記録 2

# Codewar を使い始めたので自分用アウトプット記録。2

# 3. Sum of positive
 
配列を受け取って、正の数だけ足して合計を返す。

```js
// [1, -4. 7, 12] => 1 + 7 + 12 = 20
// []  => 0
```

## 1-1. Brute Force

配列の中身を一つ一つループで確認して、プラスのときのみ足す。

### Time Complexity: O(N)

ループで一個ずつ確認する処理。

### Space Complexity: O(1)

```js
function positiveSum(arr) {
  // check parameter
  if (arr.length === 0) {
    return 0;
  }
  // create sum constant
  let sum = 0;
  for (let i = 0; i < arr.length; i++) {
    if (arr[i] > 0) {
      sum += arr[i];
    }
  }
  return sum;
}
```

# Best Practice 参考

```js
function positiveSum(arr) {
  // check if current is bigger than 0, then add
  return arr.reduce((a, b) => a + (b > 0 ? b : 0), 0);
}
```

reduce()メソッド：要素を一つ一つ見てって各ステップ毎に、現在の値をそれまでのステップでの合計に足してく。

戻り値:　reducerコールバック関数を実行した結果。

```js
const arr = [1, 2, 3, 4];
const reducer = (prevVal, currVal) => prevVal + currVal;

// 1 + 2 + 3 + 4
console.log(arr.reduce(reducer)); // 10
// 5 + 1 + 2 + 3 + 4
console.log(arr.reduce(reducer, 5)); // 15
```

```js
function positiveSum(arr) {
  // filterメソッドで0より大きいのだけフィルタし、reducerで足してく
  return arr.filter((num) => num >= 0).reduce((prev, curr) => prev + curr, 0);
}
```

# 4. Mubmling

以下を吐き出す関数を作る。

```js
accum("abcd") -> "A-Bb-Ccc-Dddd"
accum("RqaEzty") -> "R-Qq-Aaa-Eeee-Zzzzz-Tttttt-Yyyyyyy"
accum("cwAt") -> "C-Ww-Aaa-Tttt"

// The parameter of accum is a string which includes only letters from a..z and A..Z.

```

## 4-1. Brute Force

返す文字列を保存する変数を作る。
文字を一つずつループでチェック。
　　まず大文字にして保存
　　インデックスの数だけ小文字にして保存 (別のループ)

### Time Complexity: O(N^2)

ループで一個ずつ確認する処理。

### Space Complexity: O(1)

```js
function accum(s) {
  let str = '';
  for (let i = 0; i < s.length; i++) {
    for (let j = 0; j < i + 1; j++) {
      if (j === 0) {
        const upperS = s[i].toUpperCase();
        str += upperS;
      } else {
        const lowerS = s[i].toLowerCase();
        str += lowerS;
      }
    }
    str += '-';
  }
  str = str.substring(0, str.length - 1);
  return str;
}
```

## Best Practice 参考

Time Complexity は結局同じ？難しい...

```js
function accum(s) {
  return s.split('').map((c, index) => (c.toUpperCase() + c.toLowerCase().repeat(index))).join('-');
}

//accum("abcd") -> "A-Bb-Ccc-Dddd"
Split -> string to array
// 'abcd' -> ['a','b','c','d']
map(charとindex) -> a 0, b 1, c 2, d 3
charを大文字にする
charを小文字にしてそれをindexの回数repeatし-でarrayからStringにする

```

### メソッド

- split('') -> string to array
- repeat(num) -> num の数だけ repeat した string を返す
- join('-') -> array to string
AWS Amplify のビルドで『The input value type 'AuthRule' is not present when resolving type 'AMPLIFY'』が発生した際の対応

AWSの発表しているAmplify + Reactで簡単なアプリケーションをデプロイするというチュートリアルをやっていたところ、表題の問題に遭遇。

https://aws.amazon.com/jp/getting-started/hands-on/build-react-app-amplify-graphql/module-four/


ローカルでの動作は問題なくGraphQLを使ったデータ登録ができたものの、その変更をpushし、amplifyにデプロイしようとしたところで以下のようなエラーが出てビルドに失敗した。

![AWS_Amplify_Console.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8607/a9bad5f8-3ab4-d0c1-ea56-705d0efdf2a3.png)



CloudFormation上では以下のようなログ
![CloudFormation_-_スタック_amplify-amplifyreact-master-144648-apiamplifyreact-5V93MRL0X15Y.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8607/64a68789-1509-0a8c-18cd-c0e4e0130598.png)

### The input value type 'AuthRule' is not present when resolving type 'AMPLIFY'

`AuthRule` に問題があるとのことなので、ソースコード内を検索して引っかかったのが以下の箇所。
`amplify add api`で自動作成されるGraphQLのスキーマ定義ファイルですね。
コードの意味はよくわからないけど **FOR TESTING ONLY!** と付いているのが怪しい感じ。

**amplify/backend/api/amplifyreact/schema.graphql**

```graphql
# This "input" configures a global authorization rule to enable public access to
# all models in this schema. Learn more about authorization rules here: https://docs.amplify.aws/cli/graphql/authorization-rules
input AMPLIFY { globalAuthRule: AuthRule = { allow: public } } # FOR TESTING ONLY!

type Note @model {
  id: ID!
  name: String!
  description: String
}
```

冒頭のコメントにあるURLに詳しい説明があるとのことなので見てみると。

https://docs.amplify.aws/cli/graphql/authorization-rules/#global-authorization-rule-only-for-getting-started

```
To help you get started, there's a global authorization rule defined when you create a new GraphQL schema. 
For production environments, remove the global authorization rule and apply rules on each model instead.
```

開発用にcreate, update, delete権限を全スキーマに付与してくれる設定みたい。
まずはこの設定で開発を初めて後から権限を絞ってね的な話なのかな。

ともあれ、本番環境ではこの設定は消すようにとのことなので以下のように変更。
（このチュートリアルでは認証機能が既に実装されているので、認証されたユーザーのみ許可する、という設定のほうが正しいのだけど、まずはビルドエラーを解決したかったので `{ allow: public }`にしてます。。）

```graphql
# input AMPLIFY { globalAuthRule: AuthRule = { allow: public } } # FOR TESTING ONLY!

type Note @model @auth(rules: [{ allow: public }]) {
  id: ID!
  name: String!
  description: String
}
```

変更をGithubにpushして再度ビルドを走らせると無事ビルドが成功しました。

![AWS_Amplify_Console.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8607/3f39dcc3-8025-3c0d-c739-d8ebd4333bf1.png)

![React_App.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8607/d455f098-2880-f40d-bff7-449c65f80307.png)
QGISを使ってosmファイルをshpファイルに変換する

# やりたいこと
- GeoPandasで地図データを処理したい！
- GeoPandasで取り扱える地図データは```.shp```の拡張子のデータ
- OpenStreetMapから地図データを簡単に手に入れられる！
- OpenStreetMapから地図データを取得すると```.oms```という拡張子で保存される
- ```.oms``` を ```.shp``` に変換したい
- フリーソフトの「QGIS」を使うとよさそう

# 使用するツール・環境
- Windows 10
- QGIS (version 3.16.15)

# 説明を省略する部分
- OpenStreetMap (https://openstreetmap.org/) からomsファイルのダウンロード方法（そんなに難しくない）
- QGIS (https://qgis.org/ja/site/forusers/download.html) のインストール（たしか適当にポチポチしてインストールしただけ）

# やり方
1. QGIS Desktop 3.16.15をスタートメニューから立ち上げ
1. ツールバーのレイヤーからデータソースマネージャを起動
　　　　![スクリーンショット 2022-02-02 061037.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2510180/f0a6d138-ed65-4b96-48b3-5a1cd4c81c11.png)

1. ソースタイプを「ファイル」, 文字コードを「UTF-8」に設定し、ソースで```.oms```ファイルを選択し、追加ボタンを押す
　　　　![スクリーンショット 2022-02-02 061326.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2510180/a14e29d0-c9f1-192e-4842-fe0c736bc00e.png)


1. すべて選択してOKを押す
　　　　![スクリーンショット 2022-02-02 061946.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2510180/bf2b56d7-7246-5c94-1226-11e0df61604a.png)

1. データソースマネージャを閉じて、左下のレイヤから```.shp```にしたいレイヤを右クリックして、「エクスポート」から「地物の保存」を選択
　　　　![スクリーンショット 2022-02-02 062248.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2510180/80cb0059-b7e3-d887-fe17-f985e5212ae3.png)


1. 形式で「ESRI Shapefile」を選択し、ファイル名を入れて、OKボタンを押して完了！
　　　　![スクリーンショット 2022-02-02 062741.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2510180/062fae48-2c81-6dfc-53ce-e8b5a9c99c31.png)


# なぜこの記事を書いたか
- 地図データ周り（GIS）の取り扱いに慣れておらず、```.osm``` の取り扱いに困っていたが、調べても ```.shp``` に変換する方法がいまいちわからなかったため。
- 四苦八苦した後に「QGIS」というソフトを使えばいいことが分かった。ただ、もっといい方法があるかもしれない。
【Unity】Dropdown内のリストのテキストサイズを変更する方法

Unityでドロップダウン内のアイテムのテキストのFontSizeを変更する方法についてになります。

現在選択されているLabelのテキストサイズはすぐに変更できたのですが、ドロップダウンを選ぶ時に出てくるテキストサイズの変更方法がなかなかわからなかったため記事にいたします。

このようなイメージで、中身のテキストサイズを変更してみます。
![Screen Shot 2022-02-02 at 6.00.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399610/956d42ea-8c1f-076d-8dbc-23604c25fa20.png)

# ドロップダウン内のテキストサイズを変更する方法
Dropdownを作ったら、

Dropdown > Template > Viewport > Item > Item Label を選択

![Screen Shot 2022-02-02 at 6.03.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399610/2ed4655f-6eb0-a3d2-682c-dcb65fd8f5c7.png)

Inspectorから `Font Size` を変更すれば、中のテキストサイズが変わります。

# 選択中のLabelのFont Sizeの変更
ちなみに、選択中のLabelのFont Sizeの変更については、

Dropdown > Label から `Font Size` を変更すればよいだけです。

![Screen Shot 2022-02-02 at 6.05.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399610/a4614ab4-6498-c6ba-4a78-2ed389cafa0e.png)

今回は以上となります。
お読み頂き有難うございました。
CloudFront + videojs-vr でセキュアな360° グリグリ動画配信を実現する！

最近VR動画撮影＆配信のお仕事をいただくようになってきたので、はまったところを記事にしていきます。

全体像は追って書きます。

今日はCloudFrontの署名付きCookieを使ってセキュアな配信を実装している場合にvideojs-vrで再生がうまくいかなかったので
対処法をメモ。

#結論
videojsのwithCredentialsをtrueにしても署名cookieが送信されない場合は、videoタグのオプションに、
「crossorigin="use-credentials"」をセットすると解決できる！

```html
<video id="my_video_1" class="video-js vjs-fluid" playsinline controls crossorigin="use-credentials"> </video>
```
Objective-C のメソッドが自動的に async func に変換されるらしいので試してみた

## 概要

ScreenCaptureKit 関連のクラスの[ドキュメント](https://developer.apple.com/documentation/screencapturekit/scshareablecontent/3916730-getexcludingdesktopwindows)を眺めていたら Discussion に Concurrency Note という項目があることに気付き、特定の形式を持った Objective-C のメソッドが自動的に Swift の非同期関数に変換されることを知りました。

[Calling Objective-C APIs Asynchronously](https://developer.apple.com/documentation/swift/calling_objective-c_apis_asynchronously) に詳細が書かれています。[簡単なサンプルプロジェクト](https://github.com/naru-jpn/AsyncObjC)も作成して挙動を見てみました。

## 環境

- Swift 5.5.2

## メソッド変換の条件

[Calling Objective-C APIs Asynchronously](https://developer.apple.com/documentation/swift/calling_objective-c_apis_asynchronously) によると、変換されるメソッドとその Completion Handler は以下を満たす必要があります。

1. メソッドの返り値は void である。
1. Completion Block の返り値は void である。
1. Completion Block は全ての可能な制御フローにおいてただ一度だけ呼ばれる。

また、引数の個数によって変換されるメソッド名の規則が変わります。

引数が一つだけ、つまり引数が Completion Block のみである場合、メソッド名の末尾が

- WithCompletion
- WithCompletionHandler
- WithCompletionBlock
- WithReplyTo
- WithReply

のいずれかであるものが Swift にインポートされる。Completion Block の他に引数がある場合は、メソッド名の末尾が

- completion
- withCompletion
- completionHandler
- withCompletionHandler
- completionBlock
- withCompletionBlock
- replyTo
- withReplyTo
- reply
- replyTo

のいずれかであるものが Swift にインポートされる、という記載がありました。

## 挙動

Objctive-C で

```obj-c
- (void)handleVoidWithCompletion:(void (^)(void))completion;
```

のように定義されたメソッドは、Swift で

```swift
await objc.handleVoid()
```

のように呼び出すことができます。Objective-C 側の実装が

```obj-c
- (void)handleVoidWithCompletion:(void (^)(void))completion {
  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    sleep(3);
    completion();
  });
}
```

となっているとして、

```swift
// ここまでメインスレッドで実行されている (Thread.current.isMainThread が true)
await objc.handleVoid()
// ここもメインスレッドで実行される (Thread.current.isMainThread が true)
```

のような挙動になります。


## 注意点

### メソッド名の末尾は指定されたものでなくても呼び出しはできる

例えば

```obj-c
- (void)handleVoidWithCompletionHoge:(void (^)(void))completion;
```

は Swift 側で

```swift
await objc.handleVoidWithCompletionHoge()
```

と末尾が残ったままになるものの、呼び出しはできました。

### Objctive-C 側の定義によっては Ambiguous use of ... になる

Objective-C 側で

```obj-c
- (void)handleVoidWithCompletion:(void (^)(void))completion;
- (void)handleVoidWithCompletionHandler:(void (^)(void))completion;
```

のような2つのメソッド定義がある場合、Swift 側ではいずれも `await objc.handleVoid()` での呼び出しになるので、どちらを呼び出していいか判断が付かずに `Ambiguous use of 'handleVoid()'` となりエラーになってしまいます。

### Completion Block を複数回実行するとクラッシュする

Objective-C 側の実装を

```obj-c
- (void)handleVoidWithCompletion:(void (^)(void))completion {
  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    sleep(3);
    completion();
    completion();
  });
}
```

のようにしても、

```swift
await objc.handleVoid()
```

と Swift 側で呼び出すことはできます。しかし、実行時に `EXC_BAD_ACCESS` が発生してしまいました。ただ一度だけ実行する、という保証は Objective-C 側で担保する必要があるようです。

当然ですが、逆に Completion Block を一度も呼ばないと await から先に進まなくなってしまいます。

### まとめ

Objective-C から Swift の非同期関数への変換はよしなにやってくれるようですが、安全性は Objective-C 側の実装で担保する必要があるようです。今さら Objective-C のプログラムを書く機会はなかなかないですが、標準のフレームワークのメソッドを自前で continuation などで async func にする手間が省ける場合もあると考えるとなかなか便利機能かも知れません。
InstagramのAPIを使ってハッシュタグ検索をする

#1.前提
Instagram　APIのビジネスIDとアクセストークンを持っていること
#２.概要
GoogleAppsScriptでInstagram　APIを使い、ハッシュタグの投稿のリンクを取得すること

#3.やること１

ハッシュタグ名、取得数、最近の投稿か、人気の投稿かを決める
取り合いずハッシュタグ名は、「猫」、取得数は「１０」で最近の投稿にする

```
function sample0(){
  // 取得するハッシュタグ名
  var query = "猫";
  // 取得する数
  var count = 10;
  // 最近やつを取得なら１、トップページなら0
  var flag_m = 1;
  // 投稿IDと投稿先のリンクをコンソールに出力する
  console.log(sample1(flag_m,query,count))
}
```

#4.やること2
api_idにビジネスIDを入れる
api_tokenにアクセストークンを入れる

```
function sample1(flag_m,query,count) {

  var api_id = "";
  var api_token = "";

  // ハッシュタグ名をハッシュタグIDに変換する
  var hash_id = sample3(query,api_id,api_token);
  // ハッシュタグIDで対象の投稿を取得する
  var list_t = sample2(hash_id,api_id,api_token,flag_m,count);

  // 取得数分だけ返す
  return list_t.slice(0,count);
}
```

#4.やること３
データをスクレイピングしてjsonでハッシュタグIDを返す

```
function sample3(query,api_id,api_token) {
  var URL = "https://graph.facebook.com/ig_hashtag_search?user_id="+ api_id +"&q="+ query +"&access_token="+ api_token;
  var response = UrlFetchApp.fetch(URL);
  var json = JSON.parse(response.getContentText());
  return json["data"][0]["id"];
}
```

#4.やること４
データをスクレイピングしてjsonで取得したデータを整形する

```
function sample2(hash_id,api_id,api_token,flag_m,count) {

  var c = 0;
  var URL = "";
  var Next_URL = "";
  var response = "";
  var json = "";
  var list_re = [];

  if(flag_m < 1){
    
    URL = "https://graph.facebook.com/v12.0/"+ hash_id +"/top_media?user_id="+ api_id +"&fields=permalink,media_url&access_token="+ api_token;
  
  }else{
    
    URL = "https://graph.facebook.com/v12.0/"+ hash_id +"/recent_media?user_id="+ api_id +"&fields=permalink,media_url&access_token="+ api_token;
  
  }

  while(c < count){

    if(Next_URL == ""){

     response = UrlFetchApp.fetch(URL);         
     json = JSON.parse(response.getContentText());

    }else{

     response = UrlFetchApp.fetch(Next_URL);         
     json = JSON.parse(response.getContentText());

    }
    
    for(let i = 0; i < json["data"].length; i++){
      
      list_re.push([json["data"][i]["id"],json["data"][i]["permalink"]]);
    }

    c += json["data"].length;

    Next_URL = json["paging"]["next"];
  }

  return list_re;
}
```

上で記載したファンクションをGoogleAppsScriptのエディタ内に入れて
sample0を実行したらコンソールにURLとIDが出力される
Node.jsのバージョンアップ

Nextの新規プロジェクトを作ろうとしたとき、Nodeのversionが古い！と怒られたのでメモです。
nodebrewを利用して、Node.jsをバージョンアップします。

##現在のnodeのversion確認

```
$ node -v
v10.3.0
```

##nodebrewをインストール

```
$ brew install nodebrew
```

##インストールできたか確認

下記のように表示されればOKです

```
$ nodebrew -v
nodebrew 1.1.0
```

##セットアップ

```
$ nodebrew setup
Fetching nodebrew...
Installed nodebrew in $HOME/.nodebrew

========================================
Export a path to nodebrew:

export PATH=$HOME/.nodebrew/current/bin:$PATH
========================================
```

##bash_profileにパスを設定

```
$ vi ~/.bash_profile

export PATH=$HOME/.nodebrew/current/bin:$PATH ##追加
```

## bash_profileの変更を反映させる

```
source ~/.bash_profile
```

## nodeのインストールできるバージョンを確認

ずらーっとバージョンが表示されます
どのバーションにアップデートするか下記を見て判断してください。
https://nodejs.org/ja/

```
$ nodebrew ls-remote
```

## インストール

現時点でv16.13.2が推奨版とのことだったのでインストールします

```
$ nodebrew install v16.13.2
```

## 使用するバーションを決める

```
$ nodebrew use v16.13.2
```

##アップデートできたか確認

アップデートしたいバージョンにすることができました

```
$ node -v
v16.13.2
```

##終わり

Nextの新規プロジェクトを作成することができました。
ありがとうございました。
iOSのWebViewで任意のCookieを送信するには

iOSのWebViewで任意のCookieを送信する場合、WKHTTPCookieStoreにCookieをセットすることで実現できます。
実装パターンとしてはアプリの自動ログインなど、API経由などで取得したセッションCookieを送信するなどがあります。

結構前の話になりますが、WKHTTPCookieStoreが使えなかった時代（iOS11未満）は、WKWebViewの`evaluateJavaScript`なんかを使ってJavaScriptで`document.cookie = "foo=bar";`のようにセットしたりしていました。
この場合、初回ロード時にはタイミング的には当然このJavaScriptが実行前の状態になるので未ログイン状態の画面になってしまうため、NSMutableURLRequestでヘッダにCookieヘッダを詰め込む必要があったり、いろいろ苦労した思い出があります。

以下は、WebViewにCookieをセットする簡単な例です。

```
import WebKit

class PrivateWebViewController: UIViewController {
    var webView: WKWebView!
    var config: WKWebViewConfiguration!
    var firstLoadURL = URL(string: "https://mgre.jp")!

    override func viewDidLoad() {
        super.viewDidLoad()
        
        config = WKWebViewConfiguration()
        webView = WKWebView(frame: view.frame, configuration: config)
        view.addSubview(webView)
        
        // Cookieオブジェクトを作成
        let cookie = HTTPCookie(properties: [
                                    HTTPCookiePropertyKey.name: "foo",
                                    HTTPCookiePropertyKey.value: "var",
                                    HTTPCookiePropertyKey.domain: firstLoadURL.host!,
                                    HTTPCookiePropertyKey.path: "/"])!

        // Cookieをセット
        config.websiteDataStore.httpCookieStore.setCookie(cookie) { [weak self] in
            guard let self = self else { return }
            self.webView.load(URLRequest(url: self.firstLoadURL))
        }
    }
}
```

WKHTTPCookieStore登場後も、WebViewのインスタンス化前にCookieをセットしないと何故かCookieが送れないという問題などもあり、いろいろ苦労した記憶がありますが、シミュレータで試した限りではiOS13以降はそれを意識する必要はなくなっているように見えます。

## WebView間のCookieをリアルタイムで同期する場合
異なるWebViewインスタンスの間でCookieを同期する場合、WebViewにそれぞれWKWebsiteDataStore.defaultをセット（デフォルト状態）したうえで、同じWKProcessPoolをセットします。
同じWKWebsiteDataStoreを参照させることでおなじCookie情報を取得でき、WKProcessPoolを同じにすることでリアルタイムにCookieがWebView間で同期されるようになります。
WebView間で同じWKWebsiteDataStoreをセットしていればCookieは同期されますが、同じWKProcessPoolをセットしていないとリアルタイムにCookieが同期されず、遅延が発生します。

別のやり方としては、WKWebsiteDataStore.nonPersistentを使って同じインスタンスを複数のWebViewにセットすればWebView間でCookieを共有することは可能です。

### WKWebsiteDataStoreとは
WebViewでアクセスしたページのキャッシュ等のデータを保存します。
WebViewはデフォルトでWKWebsiteDataStore.defaultがセットされており、WKWebsiteDataStore.default を使った場合、WebViewのCookieはアプリ内に保存されて永続化されるため、WebView内でログイン状態をアプリ再起動後も維持できます。
WKWebSiteDataStore.default()で返されるのは同じインスタンスです。

### WKProcessPoolとは
Webコンテンツプロセスを共有するもので、同じWKProcessPoolをセットしたWebView間はリアルタイムにCookieが同期されます。
WKProcessPoolが同じでも、WKWebsiteDataStore.nonPersistent()のWebViewでセットしたCookieは他のWebViewには同期されないようです。

## SafariViewで任意のCookieを送信できるか
SafariViewはカスタムできないため、任意のCookieを送ることはできません。
ただ、シミュレータで確認した限りではCookieはアプリ内の「/SystemData/com.apple.SafariViewService/Library/Cookies/Cookies.binarycookies」に保存され、永続化されるため、SafariView内でログインした状態はアプリを再起動しても維持することは可能です。

ランチェスターではアプリエンジニア社員を募集しております！
まずはざっくばらんにお話しさせてください。下記からご応募お待ちしております。
▼https://herp.careers/v1/lanchester/stnR3oAOKkwJ
▼https://www.wantedly.com/companies/lanchester
▼採用動画について：https://moovy.jp/job/651
PostgreSQL データをnode.jsで挿入してみる

# 目次
* 目的
* 導入
* プログラムの作成
* つまづいた点
* 参考文献

# 1.目的
* 前回はユーザのラインでの問い合わせに対してPostgreSQLのデータを取得し、送信してくれるようなシステムがあればいいなということで作りました。
* 今回は値を挿入するプログラムを作成していきたいと思います。

* 家の温度や湿度をセンサで取得し、その値をPostgreSQLに格納する。←今回はここ
その後、家の外からでも家の中の状態をラインで把握できるといった応用例があります←前回はここ




#  2. 導入

* 前回の記事でユーザからのLINEメッセージに対して、適したデータをPostgreSQLから取得し、送信するといったことをpythonで実装しました。先に[そちらの記事](https://qiita.com/paupau/items/14c636469c81f4b4e9e7)をお読みいただいた方が理解がスムーズかと思います。herokuやPostgreSQLを初めて使うという方もお読みください。

※プログラムは一例として作っています。また、今回はプログラムの一部抜粋して掲載しております。

* データベースの要素は
  id  |            time            | temp |   hum
となっていて、idは主キーとして設定しており、テーブル名はtableです。



# 3. プログラムの作成

```node.js
require('pg').defaults.ssl = true; //SSLエラー解消のため
const { Pool } = require('pg')
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"; //証明書エラーのため

const pool = new Pool({ //herokuサイト内のPostgreSQLの情報
    user: '',
    host: '',
    database: '',
    password: '',
    port: 5432,
})


async function postgresql_connect(temp,hum){
	const sqltime="SET TIME ZONE 'Asia/Tokyo'"
	const sql = "INSERT INTO table (time,temp,hum) VALUES (current_timestamp, $1, $2)"
	const sql_count = "SELECT COUNT(*) FROM table"
	const sql_del ="DELETE FROM table"
	const values = [temp, hum]
	try {
		await pool.query(sqltime)
		const result = await pool.query(sql, values)
		const result_count = await pool.query(sql_count)
        console.log(result)
		count=result_count.rows[0].count //何行あるかの数値

		if(count>9500){ //PostgreSQLの１万行問題の対策
            await pool.query(sql_del)
        }

	}	catch (e) {
			console.error(e)
		}

}

postgresql_connect(temp,hum); //センサ情報を関数へ
```

# 4. つまづいた点
* クエリを短期間で何度も実行する場合、接続プールを使わないといけない点。
    * [公式ドキュメント](https://node-postgres.com/features/pooling)を読み、解決しました。

* SSL関連でのエラーが多かった。
    * 調べると情報が多く出てきたので解決できました。

* SELECT COUNT(*) FROM tableで得られた行数を変数に入れるのが少し時間がかかった。
    * rows[0].countで数値のみ抽出できました。




# 5. 参考文献

[参考にさせていただいたサイト]

https://stackoverflow-com.translate.goog/questions/22301722/ssl-for-postgresql-connection-nodejs?_x_tr_sl=en&_x_tr_tl=ja&_x_tr_hl=ja&_x_tr_pto=sc

https://qiita.com/masaks/items/3ee1b5a06a95315a7ae7

https://node-postgres.com/features/pooling

https://qiita.com/dkkoma/items/7f22769f3b3b69bf1d5f
本番環境でdbが反映されない件

#問題
Rails及びcloud9で開発し、ec2を用いて本番環境にデプロイしました（日本語あっているでしょうか）。デプロイはうまくいったと思いましたが、その後にデータベースに修正を加えるとエラーが発生。
#課題
##we're sorry, but something went wrong
アプリのURlにアクセスして、会員新規登録画面で情報を登録しようとした際に、上記ログでした。Rails側で何かしらのエラーが派生していると考えて、cloud9に戻り、ec2にログインして、
$ sudo tail -f log/production.log
を実行。本番環境でのRails側のログは/log/production.logファイルに格納されているが、その中身をリアルタイムで見ることが可能になるコマンドである。
##ActiveRecord::NotNullViolation (Mysql2::Error: Field 'profile' doesn't have a default value...
すると、会員新規登録画面で登録ボタンを押した後に上記エラーがあることを発見。customerテーブルにはprofileカラムがあるが、それはNotNullであり、渡された値がNullのため、怒られた様子。
profileカラムは
customerテーブル/text型/null: true/default値なし
である。
#解決
##①defaultを設定
![c61bb4261d08602c3f9d7bbfff23e39b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1923339/b9c8b3a8-58b0-8529-8bc8-79f60c6b8585.png)
default値があれば良いと考えて実行。
###結果
同様のエラーが発生。
##②null: falseを設定
![4a38315e0b9ce9fa01001ada34b700bf.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1923339/90c59bb5-6845-45da-c977-b6fb76b5a251.png)
NotNull制約をかければと考えて実行。
###結果
同様のエラーが発生。
##③mysqlについて
色々調べてみると、mysqlとRailsではdbの取り扱いが異なることが判明。
①text型はデフォルト値を設定できない。
②空文字とnullはどちらもnull判定
③mysqlにはstrictモード（厳格モード）というものがデフォルトで設定されているらしい。
とのこと。
###対応
とりあえず、
①→string型に変更
②→default値を「未登録」に変更
③database.ymlを下記のように変更
![7a816ef594d8a69e3b9d661807b11bb1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1923339/3fafdfe5-c19e-0bfd-d3c5-f803e93e9101.png)
###結果
①、②は効果なしで、③を実行すると新規登録できた！！しかし、strictモードを無効にすることは非推奨とされている様子。まだ、知識がペラペラのため不安に感じて再び試行錯誤。
###疑問
ec2にログインして、mysqlを起動して、設定を確認するも、どうやらバージョンが古いため、strictモードではないようでした。
![c15a1fdff49f956acb618886d421e6e1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1923339/16fb558c-a70d-bc85-e992-95037e38fe07.png)
SELECT @@global.sql_mode;
を打つとsql_modeについて確認できるが、strictモードについて記載がないため、設定なしと思われる。しかし、strict:falseで結果が変わったため、strictモードは設定されているはず。分からん！
#結末
①が解決策でした。というのも、db修正してたのに、本番環境に全く反映されてなかった。
mysqlにて、
SHOW COLUMNS FROM テーブル名 FROM データベース名;
で確認すると、だいぶ前の状態のまま。。。
ec2にて、
![2f8b22c7e3829975ada30f76f4fd858e.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1923339/1aa2de0d-03d9-5b17-79d6-7fde04989327.png)
でdbをリセットして作り直すと反映された。。。
その前にgithubのActionsを利用してgit push origin main　で本番環境に自動で反映されるようにしていたが、dbだけは違うらしい。
これからdbを修正したらmysqlでデータベースが反映されたか確認して、されてなかったらdbを作り直そうと思います。
とういうか、基本設計がしっかりしていればこうはならなかった。基本設計をしっかりと行いたい。
#参考
mysql関係
https://qiita.com/maruyama42/items/a692edac9f5aa4b64786
https://pentan.info/sql/mysql/strict_mode.html
https://obel.hatenablog.jp/entry/20180727/1532656800
https://teratail.com/questions/127616
https://www.wakuwakubank.com/posts/414-mysql-sqlmode/
https://qiita.com/park-jh/items/32b21d7b8d24b0ab3dba
anyenv nodenv コマンドまとめ

## 事前知識
| 単語 | 意味 |
|:-----------|:------------|
| node.js　|V8 JavaScriptエンジン上に構築されたJavaScript実行環境の1つ|
| nodenv|プロジェクト(ディレクトリ)ごとに、Node.jsのバージョンを管理することができるバージョン管理ツール|
| anyenv|**env系ツールのバージョンを管理することができるバージョン管理ツール|

これらの関係は、node.jsのハージョンを管理するためにnodenvを使って、  
そのnodenvのバージョンを管理するのにanyenvを使うという感じです。



## コマンド表
### anyenv
| コマンド | 内容 |
|:-----------|:------------|
| anyenv envs　| インストールされている**env一覧|
| anyenv version|**envごとのシェルにおける実行環境|
| anyenv version|**envごとのインストールされている実行環境一覧|
| anyenv install -l|インストールできる**envの一覧|

### nodenv

| コマンド | 内容 |
|:-----------|:------------|
|nodenv version|インストールしているノードの中で現在のバージョンを確認　|
|nodenv versions|インストールしているノードのバージョン確認　(*は現在のバージョン)|
|nodenv install --list|インストールできるnodeの一覧|
|nodenv install 10.14.1|nodeのインストール|
|nodenv rehash|npmパッケージを見えるようにする|
|nodenv install 10.14.1|グローバルで使うnodeのバージョンを指定する|
|nodenv global 16.13.1| あるプロジェクトのディレクトリでのみ使うnodeのバージョンを指定する|
|nodenv local 10.14.1| あるプロジェクトのディレクトリでのみ使うnodeのバージョンを指定する|
``nodenv local`` を実行することで、``.node-version``という名前の不可視ファイルが生成され、その中にそのディレクトリで使うnodeのバージョンが記述されます。

gitなどで``.node-version``を共有することで、プロジェクトのメンバーで使うnodeのバージョンを統一することもできます。

### node
| コマンド | 内容 |
|:-----------|:------------|
|node --version|nodeのバージョン確認|




## 参考サイト
[anyenvまとめ](https://qiita.com/SUZUKI_Masaya/items/51366be1510f7fde7cdf)
[nodenvの環境構築](https://qiita.com/282Haniwa/items/a764cf7ef03939e4cbb1)
vscode起動時に特定の処理を実行する

タイトルの通りです。vscodeでプロジェクトを開くと自動で何かしらの初期化処理を実行させたり、開発用サーバーを起動したりする方法を調べたので書き残します。


## やり方

vscodeのタスク機能を使います。今回は以前の記事で作成した[こちら](https://github.com/odayushin/plantuml_work)のリポジトリのdocker-composeを自動で起動していきます。

https://code.visualstudio.com/docs/editor/tasks

### プロジェクト直下に.vscode/tasks.jsonファイルを作成する

```json:tasks.json
{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "Launch PlantUML Server",
      "type": "docker-compose", // 他にshell, processなどが使えます
      "dockerCompose": {
        "up": {
          "detached": true,
          "build": true
        },
        "files": ["${workspaceFolder}/docker-compose.yml"]
      },
      "group": "none",
      "presentation": {
        "reveal": "always",
        "panel": "new"
      },
      "runOptions": {
        "runOn": "folderOpen"
      }
    }
  ]
}
```

### vscodeの設定で自動タスクを許可する

command+shift+p(ctrl+shift+p)でTasks: Manage Automatic Tasks in Folderを選択
![スクリーンショット 2022-02-02 0.42.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360735/83db5a1d-7286-3d58-4dd9-d4d983c7922f.png)

Allow Automatic Tasks in Folderを選択
![スクリーンショット 2022-02-02 0.44.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360735/ba57f299-fafd-ab5e-0edf-49a53e309f29.png)

### vscodeでプロジェクトを開き直す

無事自動で`docker-compose up -d`が実行されたかと思います。
以上です！
論文紹介：Accelerating Sparse Deep Neural Networks

この記事では、NVIDIAのAmpareアーキテクチャのGPUの疎行列計算に関する論文を紹介します。[^1]
[^1]: 画像や数式は論文から引用しています。

## 紹介する論文
https://arxiv.org/abs/2104.08378

タイトル：Accelerating Sparse Deep Neural Networks
研究機関：NVIDIA

## 概要
2:4 sparsity pattern。ニューラルネットワークモデルのパラメータ数を半分にし、AmpareアーキテクチャのGPUに搭載されているSparse Tensor Coreで高速処理する方法。

## 新規性
2:4の疎行列化の方法と、疎行列の積を高速（密行列の2倍）に計算するアーキテクチャを提案した。
枝刈りで疎行列化する方法を提案し、その方法で精度があまり落ちないことを実証した。

## キモ
行列の50%を0にして疎行列化することで、メモリアクセス速度を改善する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2448931/5f98d77c-c6d8-2042-2ced-4f4a6021ef6b.png)
Tensor Coreでは、疎行列に対して高速に行列積できるアーキテクチャを導入する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2448931/b65a3312-f93a-1b87-0395-82dc27e8b5bb.png)
ニューラルネットワークモデルを学習する時は、まず密行列で学習してから、疎行列にして再学習する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2448931/c8f116a1-9ad9-a81e-7e53-dd1e0d99eee9.png)
疎行列化した時に情報が落ちないようにチャンネルの順序を並び替える。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2448931/3e5e299f-1d6f-ceb0-a0a4-46a5e0b0080b.png)

## 評価
画像認識、セグメンテーション、GAN、自然言語処理タスクに適用して精度が落ちにくいことを確認した。
AI-900:Microsoft Azure AI Fundamentals試験に向けて part3

#Azure Machine Learning デザイナーを使用して分類モデルを作成する
- MSLearn
    - [リンクはコチラ](https://docs.microsoft.com/ja-jp/learn/modules/create-classification-model-azure-machine-learning-designer/introduction)

- 分類モデル
    - 前回の統計と同じ機械学習手法の1つ
    - データの特長の組み合わせをラベルに合わせて学習する、"教師あり"手法
    - トレーニング完了後、トレーニング済みモデルを使用することで、自動的に不明なアイテムをラベリングできます

- ワークスペース・コンピューティグリソースの作成
    - 特に注意点もないので省略

- パイプラインの作成
    - MLは関係ないけど、「Diabetic」は「糖尿病」列
        - 0：糖尿病ではない
        - 1：糖尿病である
    - MLや統計などの作業としてデータのバラつきを無くすため、正規化は大事
        - 例）21-77とか、0.07-2.8とかの値だと、前者の方が有利になっちゃう

- トレーニングモジュールの追加
    - 2項分類なので、Two-Class Logistic Regressionを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/219847/59949f8a-4e7a-8557-6d95-7e93047a52e0.png)

    - 実行が完了すると予想された値が表示される
        - 実際の値がDiabeticに対し、ScoredLabelsが予想値
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/219847/887cb86a-db44-a233-ffe5-efd5b3262746.png)

- 分類モデルの評価
    - 混同行列がすごい
        - 正確性　→　正しい予測の比率（糖尿病の人、そうでない人の予測が当たった）
        - 精度　→　糖尿病の人を当てた比率（実際に糖尿病の人、予測で１になっちゃった人で計算）
        - 再現率　→　糖尿病の人のみを対象とし、糖尿病と予測された人の比率
        - F1スコア　→　実質的に制度と再現率を組み合わせた全体的な指標
    - ここで閾値（もとは0.5）を調整すると、それぞれの値が変わってくる
        - もしかしたら、閾値を変えるとよりよい予測ができるということになるかもしれない
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/219847/e8b7d735-cf46-b603-f6ff-6a5f1929f64b.png)
    - （参考）閾値を「0.29」にするとF1スコアの値が変わったが、適合率は下がる。。。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/219847/87b059cc-e346-ffab-18f8-4e31492a5cf2.png)

- 後は他と同じように推論パイプラインを作って予測して完了

#お疲れ様でした
何もしないif文でネストを減らす


```javascript
if (isHoge) {
    if (isFuga) {
        なんかの処理();
    }
    else if (isPiyo) {
        また別の処理();
    }
}

共通的な処理();
```

は次のように書き換えるとネストが一段減らせる。

```javascript
if (isHoge == false) {
    // 何もしない。
}
else if (isFuga) {
    なんかの処理();
}
else if (isPiyo) {
    また別の処理();
}

共通的な処理();
```

もちろん次のようにも書けるが… 個人的に微妙

```javascript
if (isHoge == false) {
    共通的な処理();
    return;
}

if (isFuga) {
    なんかの処理();
}
else if (isPiyo) {
    また別の処理();
}

共通的な処理();
```

```javascript
if (isHoge && isFuga) {
    なんかの処理();
}
else if (isHoge && isPiyo) {
    また別の処理();
}

共通的な処理();
```

こうしてみると最初の方法が一番拡張性があるように見える。
Microsoft Intune を体験してみる

これからの時代はクラウド化は当たり前で、
リモートワーク化を進めるためにも、
BYODも必然になってきているようです。

世の中の流れに取り残されないように
MAM(Mobile Application Management) や　MDM(Mobile Device Management) 
の機能を持つ　Microsoft の　Intune　について学習してみました。

**Intuneとは**
https://docs.microsoft.com/ja-jp/mem/intune/fundamentals/what-is-intune
上のリンクを見ると、Intuneのドキュメントがあるのですが
実際にIntuneをデバイスにインストールさせるために1日,2日ではできなかったので
今回やったことを書こうと思います。

**【やりたいこと】**
自分の端末にIntuneをインストールして、
どんなふうに端末の制御や、アプリケーションの制御をするか
この目で確かめる


↓一番初めに学習するにはこのリンクからがわかりやすいです。
**Intuneの基本**
https://docs.microsoft.com/ja-jp/mem/intune/fundamentals/

![スクリーンショット 2022-02-02 1.30.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121322/2fc8d024-5145-82f7-e417-f544023cc23b.png)



基本的に、こちらのクイックスタートの手順で
進めていきます。


#無料試用版のIntuneアカウントを作成する（ブラウザでの作業）

https://docs.microsoft.com/ja-jp/mem/intune/fundamentals/free-trial-sign-up
１ヶ月の期限付きですが
無料でIntuneのアカウントを作成することができます。
この記事を書いている今がもう期限ギリギリです。:sweat_smile:

#Microsoft Endpoint Manager 管理センターで Intune にサインインする（ブラウザでの作業）

↓Endpoint Managerの様子
ダークモードにしてます:smiling_imp:

![スクリーンショット 2022-01-05 21.46.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121322/a49c89ea-7853-c79c-6ea0-8bec4c1e3476.png)


↓続けてこちらもちゃっちゃとやってしまいます。
#Endpoint Manager でユーザーの追加、グループの追加を行う（ブラウザでの作業）
https://docs.microsoft.com/ja-jp/mem/intune/fundamentals/quickstart-create-user
https://docs.microsoft.com/ja-jp/mem/intune/fundamentals/quickstart-create-group

グループの追加を行なった様子
![スクリーンショット 2022-02-03 23.00.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121322/9bdcf229-3b97-db2b-21eb-74a42b3078cf.png)

￼


#どのデバイスにIntuneをインストールするか選択する
私はiPhoneユーザーですので、まず初めに　iPhoneにインストールする方法を試しましたが
結果から言いますと、企業向けAppleIDを持っていないため 
Intuneをインストールすることは不可能でした。:cry:

https://docs.microsoft.com/ja-jp/mem/intune/enrollment/ios-enroll
丸1日中ああでもない、こうでもないとドキュメントを読みながら手順を進めましたが
企業用のAppleIDが必要です　みたいなメッセージが出て
インストールに失敗します。

手順の通りに、初めはEndpoint Managerにて
iPhoneのシリアル番号等を調べて、CSVファイルにしたものをブラウザから取り込み
デバイスの登録を行います。
（ここまではできた）:sweat_smile:

![スクリーンショット 2022-02-03 23.19.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121322/c8fac586-64dc-3421-3aa5-a5070e6e3c1e.png)


次のステップとして

iPhoneへのIntuneのインストールには
Macが必要です。
Macに、Apple Configulator2というアプリケーションをインストールし、
Apple Configulator2を介して　Intuneをインストールするようです。:thinking:　

MacとiPhoneをUSBで繋ぎ、Apple Configulator2　
からIntuneを　登録しようとする際に
さっきの悲しいメッセージが出てきて　失敗します。:expressionless:

ちなみに、企業用AppleIDは作れるかな？
と思い調べましたが　
https://support.apple.com/ja-jp/HT210737
会社を作るところからやらないといけなかったので
諦めました。　そうのうち作ります。。:smirk:
Apple製品は素人にはIntuneの検証が難しいことが分かりました。:pensive:




次に検討したのはWindowsですが、
個人用のWindows PCは持っていなかったので
こちらもパスです。:confounded:


で残るはAndroid のみ
でもAndroidは持っていません。。
諦めたく無かったので

実験用にAndroid
デバイスを用意しました。:clap:

近くのRakuten Mobile に行って
役１時間半で　端末をゲットできました。:raised_hands:

めちゃくちゃお得感がありまして、
デバイスもほぼ無料で手に入れることができ
電話もタダななので結構気に入っています。:smile:

脱線しましたが、
そんなこんなで

**デバイスは　Android  に決定しました。**

　　　　次回は
　　　　　Android端末を　デバイス登録する
JEP 421: Deprecate Finalization for Removal

動向キャッチアップ出来てなかったので纏め。

https://openjdk.java.net/jeps/421

## 概要

* タイトル通り、Finalizationを廃止する為に前準備するJEP。
  * Java 1.0から存在してるprotected void finalize()を廃止。
  * Finalizationに対する指摘自体は1998年から挙がってた、とのこと。
     * Finalizationの問題点は、JEP本文ご参照。
     * 経緯も纏まっていて非常に勉強になった。
* JDK18時点ではデフォルト有効で変わらず。
* 移行先は、try-with-resources(Java7以降)および、Cleaners(Java9以降)を想定。

## 今後(JEP421で整備する範囲)

* 以下などfinalize()メソッドをDeprecated勧告。

```java
java.lang.Object.finalize()
java.lang.Enum.finalize()

java.util.concurrent.ThreadPoolExecutor.finalize()

//GUIアプリ関連
java.awt.Graphics.finalize()
java.awt.PrintJob.finalize()

//イメージ操作関連
javax.imageio.spi.ServiceRegistry.finalize()
javax.imageio.stream.FileCacheImageInputStream.finalize()
javax.imageio.stream.FileImageInputStream.finalize()
javax.imageio.stream.FileImageOutputStream.finalize()
javax.imageio.stream.ImageInputStreamImpl.finalize()
javax.imageio.stream.MemoryCacheImageInputStream.finalize()
```

* CommandLineオプションを追加。
  * Finalization無効にする(=GCによるFinalization実行計画をスキップする)フラグ追加。
  * JDK18時点ではデフォルト有効。

## 今後(JEP421より未来の話 2022/2/1現時点)

* Finalizationをデフォルト無効にする。  
  --finalization=enabledで有効に切り替えられるように整える予定。
* 実行時には警告を出す予定。

* 更に将来では、Finalizationの機構自体を削除。

* 長めに移行期間を設けてメンテ作業できるように整える予定。
  * JDK自体がFinalization多用してるので対応。
  * 著名なライブラリ群も多用してるのでメンテ支援。Netty, Log4j, Guava, Apache Commonsなど。
  * 開発者向け移行ガイドを提供。Finalizationに依存してる箇所の確認方法などを想定。
Pythonで仮想環境を用意するときの備忘録(pipを最新化するまで)

忘れそうなためPythonの仮想環境を準備するときの備忘録。
使用する仮想環境はvenv。
VSCodeについては管理者権限で起動。


## 前提条件
Python 3.10
Visual Studio Code 1.63.2


## 仮想環境作成
プロジェクトを作りたい場所にディレクトリを作成。
(※今回はCドライブにグローバル環境のPythonが格納されていてプロジェクトはEドライブに格納されている。)

VSCodeのメニューバーのファイル→フォルダを開くでプロジェクトを選択する。
メニューのターミナル→新しいターミナルを選択。プロジェクト直下で次のコマンドを実行すると仮想環境が作成される。

```
$ python -m venv venv01
```
:::note info
memo
-m モジュールであることを示す。
:::
venv01の部分は環境名のため任意の文字列を入力。
次のような構成になっていれば成功。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/310625/28a0420a-71df-8dff-aa5b-4a562953f967.png)

仮想環境は作成されていますがまだ有効にはなっていないため有効化する。
プロジェクト直下に適当な拡張子が.pyのファイルを作成。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/310625/fa7e29e8-a554-8bef-0fb1-946f1b926814.png)
作成したファイルを開いた後ターミナルも再度開き直す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/310625/813b0c44-0279-bd31-faf7-df52b8758606.png)
ウィンドウ左下にPythonのバージョンと使用している仮想環境が表示されている。
ターミナルのコマンド入力先頭部分に環境名となっており仮想環境有効状態でコマンドが実行可能な状態になっていることが確認できる。

また、次のようなコマンドを直接入力しActivate.ps1を直接指定することでも仮想環境を有効化できる。

```
PS E:\dorayaki> venv01/Scripts/Activate.ps1
(venv01) PS E:\dorayaki>
```


スクリプトの実行が無効となっていてActivate.ps1を読み込めない場合はPowerShellにて次のコマンドを実行する。2回目以降の実行は不要。
`Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser`

仮想環境を無効化する場合はdeactivateと入力すればよい。

```
(venv01) PS E:\dorayaki> deactivate
PS E:\dorayaki> 
```


##pipを最新化
listコマンドを実行するとターミナルに次のように表示される場合がある。

```
(venv01) PS E:\dorayaki> pip list  
Package    Version
---------- -------
pip        21.2.4
setuptools 58.1.0
WARNING: You are using pip version 21.2.4; however, version 22.0.2 is available.
You should consider upgrading via the 'E:\dorayaki\venv01\Scripts\python.exe -m pip install --upgrade pip' command.
```
より新しいバージョンのpipが存在するとのこと。pipのバージョンによっては一部のモジュールが取得出来ない場合がある。


pipを最新にするには次のコマンドを実行する。

```
(venv01) PS E:\dorayaki> python -m pip install --upgrade pip
Requirement already satisfied: pip in e:\dorayaki\venv01\lib\site-packages (21.2.4)      
Collecting pip
  Downloading pip-22.0.2-py3-none-any.whl (2.1 MB)
     |████████████████████████████████| 2.1 MB 6.4 MB/s
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-22.0.2
```
正常に最新のpipにアップグレードされた。

:::note info
memo
python -m　を先頭につけないと失敗する場合がある。
:::


## 補足
どのモジュールを使用しているか次のようにwhichコマンドで確認できる。

グローバル環境

```
PS E:\dorayaki> which pip
/c/Users/hoge/AppData/Local/Programs/Python/Python310/Scripts/pip
PS E:\dorayaki> pip --version
pip 21.2.4 from C:\Users\hoge\AppData\Local\Programs\Python\Python310\lib\site-packages\pip 
(python 3.10)
```

仮想環境

```
(venv01) PS E:\dorayaki> which pip
/e/dorayaki/venv01/Scripts/pip
(venv01) PS E:\dorayaki> pip --version
pip 22.0.2 from E:\dorayaki\venv01\lib\site-packages\pip (python 3.10)
```

このように異なるバージョンのpipが適用されていることが確認できる。
Next.jsのImageコンポーネントを使って、画像がなぜか中央寄せに表示されたら　layout="fill"を疑おうという話


どう頑張っても画像が他の要素の上に配置され、「中央寄せ」が解除されなかったため、その時解決できた方法を書いてみます。

## 前提として以下のようなコンポーネントの内容になっています。
※TailwindCSSも使っていますが、TailwindCSSは特に今回、謎の画像の中央寄せに影響していません。

### 使用技術

- TypeScript
- Next.js
- TailwindCSS

### 実装例
```
main.tsx

import React from 'react';
import Image from 'next/image'
export const Main = () => {
  return (
    <main className="
        px-6
        sm:px-6
        md:px-11
        lg:px-24
        h-screen
        pt-10
        sm:pt-10
        md:pt-12
        lg:pt-16
        bg-gray-100
        ">
       <section className="flex flex-col lg:flex-row">
            <div id="wrapper-left" className='order-2 sm:order-2 lg:order-1'>
                <h2 className="
                    text-3xl
                    sm:text-3xl
                    lg:text-[40px]
                    text-gray-700
                    leading-normal
                    sm:leading-normal
                    lg:leading-loose
                    tracking-normal">
                    TEXT
                </h2>
            </div>
            <div className="
                order-1
                sm:order-1
                md:order-1
                lg:order-2
                ">
                <Image src='/images/illust1.png'
                    alt="illust"
                    width={400}
                    height={400}
                    objectFit='contain'
                    quality={50}
                    priority={true}
                    className="
                        pt-12"/>
            </div>
       </section>
   )
}
```

sectionタグにflexを指定して、その子のdivタグにorderで要素の配置される順序を指定したのに、なぜか効かず、marginも効かない・・
そんな時にNext.jsで推奨されているImageコンポーネントのプロパティ、「layout='fill'」が怪しいのでは？と疑い、それを外したところ、orderも効くようになりました！