OmniAICreator/Qiita-1.07M huggingface dataset:
Nest.js で加算

こちらのプログラムと同じことを Nest.js で行いました。
[Nuxt.js で簡単な WebAPI を作成 (その 2)](https://qiita.com/ekzemplaro/items/09191b15fdc0978c4e20)
[Koa.js で加算](https://qiita.com/ekzemplaro/items/56a29a7a918084a0def2)
プロジェクトの作成

```bash
nest new -p npm sum-number; cd sum-number
```

次のプログラムを変更します。

```js:src/app.controller.ts
import { Controller, Get, Post, Req, Query, Body } from '@nestjs/common';
import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get()
  getHello(): string {
    return this.appService.getHello();
  }


  @Get('sum')
  get_sum_proc(@Query('aa') aa_str, @Query('bb') bb_str): {aa: number; bb: number;}{
	const aa = parseInt(aa_str,10)
	const bb = parseInt(bb_str,10)
	const sum = aa + bb
	console.error("aa = " + aa)
	console.error("bb = " + bb)
	console.error("sum = " + sum)
	const rvalue = {"aa": aa,"bb": bb, "sum": sum}
	return rvalue
  }



  @Post('sum')
  post_sum_proc(@Body() item: {aa: string; bb: string;}): {aa: number; bb: number;}{
	const aa = parseInt(item.aa,10)
	const bb = parseInt(item.bb,10)
	const sum = aa + bb
	console.error("aa = " + aa)
	console.error("bb = " + bb)
	console.error("sum = " + sum)
	const rvalue = {"aa": aa,"bb": bb, "sum": sum}
	return rvalue
  }
}
```

サーバーの起動

```bash
npm run start:dev
```

#テスト結果#

GET

```text
$ curl 'http://localhost:3000/sum?aa=32&bb=54' | jq .
{
  "aa": 32,
  "bb": 54,
  "sum": 86
}
```

```text
$ http 'http://localhost:3000/sum?aa=32&bb=54'
HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 26
Content-Type: application/json; charset=utf-8
Date: Tue, 11 Jan 2022 01:10:23 GMT
ETag: W/"1a-9WzAWuyXr0mWfL1ALqrsJlQGIrA"
Keep-Alive: timeout=5
X-Powered-By: Express

{
    "aa": 32,
    "bb": 54,
    "sum": 86
}
```

POST

```text
$ curl -X POST http://localhost:3000/sum -d 'aa=23' -d 'bb=49'  | jq .
{
  "aa": 23,
  "bb": 49,
  "sum": 72
}
```

```text
$ http http://localhost:3000/sum aa==23 bb==49
HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 26
Content-Type: application/json; charset=utf-8
Date: Tue, 11 Jan 2022 01:11:05 GMT
ETag: W/"1a-35DecUh+AqL9Q4ncVN6yMOB7NJM"
Keep-Alive: timeout=5
X-Powered-By: Express

{
    "aa": 23,
    "bb": 49,
    "sum": 72
}
```

次のバージョンで確認しました。

```
$ node --version
v17.3.0
$ nest --version
7.5.4
```
AWS AmplifyのAPIを修正する

一度`amplify add api`で作成したものの、**Choose the default authorization type for the API**の設定を途中で変えたくなったときの作業メモです

# amplify update apiで対応可能
ちゃんと更新用のコマンドがありました。

```console
amplify update api

? Select from the options below Update auth settings
? Choose the default authorization type for the API Amazon Cognito User Pool
Use a Cognito user pool configured as a part of this project.
? Configure additional auth types? No
(node:14112) ExperimentalWarning: The fs.promises API is experimental
```
laradock からの laravel-admin で失敗した部分のメモ

下記の記事を参考にLaravelのインストールを行っていたが、ところどころで詰まったので自分メモ的に補足です。

参考：
[laravel-adminで管理画面を速攻で構築する。](https://qiita.com/pikonori/items/a04066010e7380b3ee38)

#docker-composeの準備
laradock/下でのdocker-composeでエラーがでたので調べたところ、.envから読み出すことが多くなっているようなので、下記の通りenvの対応を行いました。

```
cp env-ecample .env
```

#パスの修正
設定通りすすめ、laravelのインストールを行うことはできたが、localhost確認すると404になってしまう現象がおきていました。
dcoker-compose.yml が当時と大きく変更されているようで、該当箇所が見つからなかった部分が原因だったようなので、代わりに下記箇所を変更しました。

```ruby:laradock/.env
### Paths #################################################

# Point to the path of your applications code on your host
#適切なパスを指定
APP_CODE_PATH_HOST=../admin/

# Point to where the `APP_CODE_PATH_HOST` should be in the container
#適切なパスを指定
APP_CODE_PATH_CONTAINER=/var/www/admin/
```

```ruby:laradock/nginx/sites/default.conf
    server_name localhost;
    #laravelのpublicの指定なので、publicの前に適切なパスを指定
    root /var/www/admin/public;
    index index.php index.html index.htm;
```

#laravel-adminのインストール
laraverl-adminをインストールするのに、admin/下のcomposer.jsonに指定通りに記述してみたところ、エラーがでているようでした。
他の記事を参考にして、下記のようにしたところすすみました。


```ruby:admin/composer.json
    "require": {
        "php": "^7.3|^8.0",
        "fideloper/proxy": "^4.4",
        "fruitcake/laravel-cors": "^2.0",
        "guzzlehttp/guzzle": "^7.0.1",
        "laravel/framework": "^8.12",
        "laravel/tinker": "^2.5",
        "encore/laravel-admin": "dev-master" #ここを追加。追加する際は、一個手前にカンマを追加。
    },
```


参考：
[Laravel 6.0 だけどLaravel-Adminを試したい](https://qiita.com/ProjectEuropa/items/122cf75a2fc2fa24ce44)


admin/service.php へのservuiceProviderを追加したところ、エラーとなるようなので、下記で対応しました。

```
$ php artisan vendor:publish --provider="Encore\Admin\AdminServiceProvider"
$ php artisan admin:install
```

上記でとりあえず、laravel-adminを画面で確認することができるようになりました。
Macの電源アダプタの充電電力をコマンドラインから確認する方法

USB Type-Cの電源アダプタは事前にネゴシエーションを行うことで適切な充電電力を確定しますが、時折ネゴシエーションが上手く行かなかったのか期待していた充電電力を下回ったままの事があります。
そうなると、Macのバッテリーがじわじわ減っていくことになり困ります。

そう言う時は、Macのシステム情報から現在の充電電力を確認できます。
![充電電力](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189239/b2cb15b8-e3aa-88d1-a78e-76e9c49a84b1.png)
ただ、こちらの情報をコマンドラインから確認できたほうが開発者的には便利なのでコマンドを探しました。

# コマンド

```bash
system_profiler SPPowerDataType | grep Wattage
```

システム情報はsystem_profilerコマンドから確認できるので、そこから電力の項目を抜き出します。

## 出力例

```bash
% system_profiler SPPowerDataType | grep Wattage
      Wattage (W): 100
```
研究データリポジトリ

以下のリポジトリは研究データをシェアするの際に便利だと思われます。
随時更新を予定しています。

### Scientific Data推奨リポジトリ
https://www.nature.com/sdata/policies/repositories
Scientific Dataで研究分野毎に推奨リポジトリが紹介されています。
物質科学分野では以下のNOMADとMaterials Cloudが推奨されています。

### Zenode
https://zenodo.org/
OpenAIREとCERNによって運営されている研究データリポジトリ
- 50 GBまでのデータセット（ファイル）をアップロード可能
- DOIの取得が可能

### figshare
https://figshare.com/
Digital Scienceによって運営されている研究リポジトリ
- 5GBまでのファイルと20GBまでのストレージが利用が可能
- DOIの取得が可能

### NOMAD repository
https://nomad-lab.eu/index.php?page=repo-arch
物質科学分野のオープンリポジトリ
- DOIの取得が可能

### Materials cloud
https://www.materialscloud.org/
物質科学分野のオープンリポジトリ
- DOIの取得が可能

### JARVIS
https://jarvis.nist.gov/
NISTが提供する物質科学分野のオープンリポジトリ。ユーザー登録が必要。

### Materials data repository
https://mdr.nims.go.jp/
物質・材料研究機構 (NIMS) が提供する物質・材料のリポジトリ。

### J-STATE data

https://jstagedata.jst.go.jp
こちらのリポジトリはデータの閲覧、ダウンロードのみで、自分でデータをアップロードはできないようです。J-STAGEを利用している（オンライン）雑誌がJ-STATE dataを利用している場合、その雑誌に論文を掲載しデータアップロードすることが可能なようです。
トップページを見ると分かると思いますが、本体はfigshareでJSTが契約して利用しているようです。
Quantum-ESPRESSO入力ファイルの作成方法

Quantum-ESPRESSOの計算を行うためには擬ポテンシャルを準備した上で入力ファイルを作成する必要があります。以下に幾つかの例を紹介します。

## 手動
[pw.x input description](https://www.quantum-espresso.org/Doc/INPUT_PW.html)を見ながら手動で作成します。結晶、電子状態計算、擬ポテンシャルに関するある程度の知識は必要です。
半導体・絶縁体の場合のSCF計算用の最小限の入力ファイルは以下のようになります（ダイアモンド構造のシリコン）。

```
&control
   calculation  = 'scf'
   restart_mode = 'from_scratch',
   pseudo_dir   = '/home/ikutaro/QE/pseudo/',
   outdir       = './tmp'
   prefix       = 'si'
/
&system
   ibrav     = 2
   celldm(1) = 10.35
   ntyp      = 1
   nat       = 2
   ecutwfc   = 35.0
/
&electrons
   diagonalization = 'david'
   conv_thr        = 1.0e-12
   mixing_beta     = 0.7
/
ATOMIC_SPECIES
 Si  0.000   Si_ONCV_PBE-1.1.upf
ATOMIC_POSITIONS (crystal)
 Si  0.0000  0.0000  0.0000
 Si  0.2500  0.2500  0.2500
K_POINTS (automatic)
 06 06 06 0 0 0
```
金属系の場合は以下のようにパラメーターが少し増えます（fcc構造のアルミニウム）。

```
&control
 calculation  = 'scf'
 restart_mode = 'from_scratch',
 pseudo_dir   =  '/home/ikutaro/QE/pseudo/'
 outdir       = './tmp'
 prefix       = 'al'
/
&system
 ibrav       = 2
 A           = 4.020
 ntyp        = 1
 nat         = 1
 ecutwfc     = 30.0
 ecutrho     = 120.0
 occupations = 'smearing'
 smearing    = 'mp'
 degauss     = 0.01
/
&electrons
 diagonalization = 'david'
 conv_thr        = 1.0e-12
 mixing_beta     = 0.5
/
ATOMIC_SPECIES
 Al 0.0000 Al.pz-vbc.UPF
ATOMIC_POSITIONS (crystal)
Al      0.000000000000      0.000000000000      0.00000000000
K_POINTS (automatic)
16 16 16 0 0 0
```

手動で作成する際には[Quantum ESPRESSO入力ファイル作成手順](https://qiita.com/xa_member/items/727c1a62930611babaf7)が参考になります。入力ファイルも含めたQuantum-ESPRESSOの使い方全般は[quantum ESPRESSO tutorial](http://www.cmpt.phys.tohoku.ac.jp/~koretsune/SATL_qe_tutorial/)がとても参考になります。

## cif2qe.shの利用

``PW/tools``以下に含まれる``cif2qe.sh``を利用することでcifファイルからpw.xの入力ファイルの雛形を作成することが可能です。GNU awkの利用が前提となっているようです (Macのnativeのawkだとうまく動作しませんでした)。

## cif2cellの利用

オリジナルの[cif2cell](https://github.com/torbjornbjorkman/cif2cell) (python 2.4対応)の利用。source forgeからgithubに移動しているようです。使用方法はサイトを参照して下さい。

Python 3対応のcif2cellは[こちら](https://github.com/kmu/cif2cell)を参照して下さい。

TBD

## Catalysis Hubの利用
https://www.catalysis-hub.org/
[apps](https://www.catalysis-hub.org/appsIndex)にある[Wyckoff Bulk Genenerator](https://www.catalysis-hub.org/bulkGenerator)を使うことで結晶の計算のための入力ファイルの作成が可能です。
典型的な結晶の表面、および限られた分子の吸着構造を計算するための入力ファイルは[CatKit Slab generator](https://www.catalysis-hub.org/catKitDemo)で作成が可能です。

## Materials Cloudの利用
https://www.materialscloud.org/
cifファイルが入手できればMaterials Cloudに含まれる[Quantum ESPRESSO input generator and structure visualizer](https://www.materialscloud.org/work/tools/qeinputgenerator)を使うことでQuantum-ESPRESSOの入力ファイルの作成が可能です。必要に応じて自分で作った入力ファイルの修正もしてくれます。
binding.pryを使用したエラー解決の例

新規投稿画面で下記のエラーが表示されました。
Title can't be blank
Content can't be blank

値が保存されていない場合binding.pryを
createアクションのdef createの直下に設置します。

```ruby
def create
  binding.pry
  @post = Post.new(post_params)
if @post.vaid?
  redirect_TOMOMITSU root_path
else
  render'new'
end
```

binding.pryでブラウザの処理を止めた後、ターミナルにparamsと入力
new.html.erbのform_withからcontrollerへ何が送られどの様に格納された状態か確認できます。

pry(#<PostsController>)params
"post" => {"title"=>"samlittle","content"=>"こんにちは！"}
 
上記よりparamsの中のpost内にtitleやcontentが格納されています。
さらにparams[:post][:totle]やparams[:post][:content]を入力すると値が取れます。
よって保存したい値は送信できていることが分かります。

送信が問題なく保存の前でエラーが起きている。
なので保存をするために許可を出すストロングパラメータの確認が必要になります。

app/controllers/posts_controller.rb
```def post_params
 　　params.permit(title,:content).merge(user_id:current_user.id)
```
ストロングパラメーラで二重ハッシュの中身を取得するにはrequireメソッドが必要です。
今回はparamsの中のpost内にデータが格納されているのでrequireメソッドが抜けています。

params.require(:post)permit.(title,:content).merge(user_id:current_user.id)

上記の様にrequireメソッドを付け加えた修正になります。
Font Awesome の導入

まずターミナルでfont awesomeを導入

``` 
yarn add @fortawesome/fontawesome-free
```


次に、app/javascript/stylesheets/application.scssにFont Awesome のCSSを読み込みます。

```
@import '~@fortawesome/fontawesome-free/scss/fontawesome';

```

次にyarnでインストールした Font Awesome のパッケージを利用できるようにimportします。
app/javascript/packs/application.js に以下のコードを追加してください。

```
 import '@fortawesome/fontawesome-free/js/all';
```

これでFont Awesome の導入完了です。
ハイブリッドソースコード（笑）

# ハイブリッドソースコード（笑）
## はじめに
まずハイブリッドソースコードという用語はないはずです。（一応記事を書く前にgoogleで検索して調べました）
追記：複数のプログラミング言語で書かれた1つのプログラムを[Polygot](https://en.wikipedia.org/wiki/Polyglot_(computing))と呼ぶそうです。（@twostarsmcoさん、教えていただきありがとうございます。）
1つのソースコードから複数のプラットフォームで動くハイブリッドアプリというのはあります。
ここでのハイブリッドソースコードとは1つのソースコードに2つのプログラミング言語を記述して、どちらのプログラムとしてでも動作させてしまうという**遊び**です。

## 原理
原理は簡単でプログラミング言語Aのコメント（もしくは実行に影響がない記述）にプログラミング言語Bのコードを記述して、プログラミング言語Bのコメントにプログラミング言語Aのコードを記述することで、お互いがコメントになるようにすることでどちらのプログラムとしても動作します。

## 実例

###C/C++ソースコード×Rubyソースコード

```test1.c
#/*
puts "Hello Ruby"
__END__
*/
#include <stdio.h>
int main()
{
  printf("Hello C/C++\n");
}
```

```
$ gcc test1.c
$ ./a.exe
Hello C/C++
$ ruby test1.c
Hello Ruby
```

Rubyからのソースコードの見え方は以下のようになっています。
![c-ruby1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252533/7eb56ab7-d510-7023-79b7-63269a84f61a.png "Rubyからのソースコードの見え方")
C/C++からのソースコードの見え方は以下のようになっています。
![c-ruby2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252533/01fe3878-b908-6088-0809-c6ef8a6cae38.png "C/C++からのソースコードの見え方")

### C/C++ソースコード×Pythonソースコード

```test2.c
#/*
print("Hello Python")
"""
*/
#include <stdio.h>
int main()
{
  printf("Hello C/C++\n");
}
/*
"""
#*/
```

```
$ gcc test2.c
$ ./a.exe
Hello C/C++
$ python test2.c
Hello Python
```

Pythonからのソースコードの見え方は以下になっています。
![c-python1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252533/89a856f0-eb10-266e-ae5f-7e75f412074e.png "Pythonからのソースコードの見え方")
C/C++からのソースコードの見え方は以下になっています。
![c-python2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252533/e5e270d0-3e2c-585a-1ec5-10ff97f342b7.png "C/C++からのソースコードの見え方")

### Rustソースコード×Pythonソースコード

```test3.rs
#[doc()]/*
print("Hello Python")
"""
*/
fn main()
{
  println!("Hello Rust");
}
/*
"""
#*/
```

```
$ rustc test3.c
$ ./test3.exe
Hello Rust
$ python test3.c
Hello Python
```

Pythonからのソースコードの見え方は以下になっています。
![rust-python1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252533/ffadef16-cb9b-c531-df67-8515b80347f1.png "Pythonからのソースコードの見え方")
Rustからのソースコードの見え方は以下になっています。
![rust-python2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252533/141a7d60-5049-8b4a-bb27-a9d0943ed36f.png "Rustからのソースコードの見え方")

おしまい。
VSCode：SonarLintでtsconfig.jsonが見つからずエラーとなる場合の対応

Visual Studio CodeでAngularのTypeScriptファイルを開いたらSonarLintのエラーが出て困っていましたが、対応方法がわかったので記録しておきます。

## 発生したエラーと原因

![Screenshot from 2021-02-10 11-24-15_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578948/e853ca9f-d8b1-1f5d-7a04-0c7df5b25e30.png)

ポップアップの表示は

```console
JS/TS analysis failed. Please check the SonarLint Output for more details.
```

で、SonarLintの出力結果を見ると、

```console
[Error - 11:23:32.979] org.sonarsource.nodejs.NodeCommandException: No tsconfig.json file found, analysis will be stopped.
```

と出力されていて、tsconfig.jsonファイルが見つからないとのこと。
Angularプロジェクトの中ではtsconfig.jsonはプロジェクトディレクトリ直下にあって、srcディレクトリ内の
.tsファイルを開いている場合にはSonarLintがtsconfig.jsonを見つけられないようです。

## とりあえずの対応方法・・・

settings.jsonに以下の設定を加えることでエラーなく動くようになりました。

```json
    "sonarlint.analyzerProperties": {
        "sonar.typescript.tsconfigPath": "../tsconfig.json"
    }
```

・・・これで一応エラーはでなくなりましたが、実態としてはsrcディレクトリ直下にあるファイルを開いた場合しかチェックされておらず、それより深い階層の.tsファイルの場合はtsconfig.jsonが見つけられずにスキップされているだけみたいでした。（プラグインのデバッグ出力からの推測ですが、指定している相対パスから考えてそりゃそうだという感じではあります）

## 恐らく正しい対応方法

Angularのプロジェクトディレクトリを「フォルダを開く」機能で開いた上で、対象の.tsファイルを開く。
・・・わかっていれば至極当たり前のようにも思えて来ますが、この対応を見つけるまでに結構な時間がかかってしまいました。

何かの参考になれば幸いです。
Yellowfinのダッシュボードを埋め込んだ外部ファイルからグラフ表の表示切り替えを行う


#概要
前回は[Yellowfinのコードモードダッシュボードでレポートのグラフ表の切り替えを一括で行う](https://qiita.com/celery/items/13afec16a618af527c94)の記事でダッシュボード上にボタンを置いてレポートの切り替えをしたのですが、EOMの場合など、自社の製品に組み込みたい場合はHTMLファイルなどにダッシュボードを埋め込んでそこからHTML上のボタンで制御していくことになります。
今回は、前回の流れを踏襲しつつ、DOMを駆使して実現していきます。
下のgifファイルでは分かりづらいですが、左上にクリックボタンがあります。
![](https://user-images.githubusercontent.com/34874755/107459964-97274180-6b9a-11eb-9805-579e73d40606.gif)

#前準備
適当なダッシュボードを用意して頂き、そのダッシュボードのUUIDを取得します。共有をクリックして埋め込みタグからdashUUID=の後の82b33f61-7ce9-4e83-b26a-425520124d49を控えておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223443/dbfb4687-c32a-883f-7d08-a2826356a1c9.png)


#アクセスするHTMLファイルの書き方
最初のscriptタグでYellowfinサーバーのJSAPIv3の読み込みを行います。適宜ドメインを下記コードから変更してください。CORSでエラーが出る場合はこちらを参照してください。[CORS設定を行いwebserver越しにRESTでYellowfinサーバーにアクセスする](https://qiita.com/celery/items/69f8da9601277807cc34)
埋め込み元のボタンを\<div id="text-button">タグ一式で作成します。
また、ダッシュボードを表示するための領域を\<div id="dashboard">\</div>で確保します。

スクリプトの流れとしてはダッシュボードをロードした後に、使われているレポートの名前を取得し、ボタンをクリックすることでDOMを利用してそれぞれのレポートのdisplay-typeを変更しています。
詳細はコードでご確認ください。

```html:enbbededDashboard.html
<html>
<head>
	<meta charset="utf-8" />
	<style type="text/css" id="style0"></style>
</head>
<script type="text/javascript" src="http://localhost:8940/JsAPI/v3"></script>
<body>
<div id="text-button">
	<button id="btn">クリック</p>
</div>
<div id="dashboard"></div>

<script>
	var reports;
	window.yellowfin.init().then(() => {
		window.yellowfin.loadDashboard({
			dashboardUUID: '82b33f61-7ce9-4e83-b26a-425520124d49',//控えたdashUUIDを指定します
			element: 'div#dashboard'
		}).then(dashboard => {

			let reportNames = [];
			reportDefinitions = dashboard.reports.reportDefinitions;
			Object.keys(reportDefinitions).forEach(key =>{
				reportNames.push(reportDefinitions[key].reportInfo.name);
			})

			let btn = document.getElementById("text-button");
			btn.addEventListener('click', () => {
				reportNames.forEach(reportName =>{
					if (document.getElementsByName(reportName)[0]) {
						let currentDisplay = document.getElementsByName(reportName)[0].getAttribute('display-type');
						if (currentDisplay === "CHART") {
							currentDisplay = "REPORT";
						} else {
							currentDisplay = "CHART";
						}
						document.getElementsByName(reportName)[0].setAttribute('display-type', currentDisplay);
					}
				});
			});
		});
	});
</script>
</body>
</html>
```

#感想
これで埋め込みダッシュボードでもよりインタラクティブな表現が可能になり、組み込みの際に役立つんじゃないかなと感じています。
SwiftUIでもprintデバッグしたい！！

**バッドノウハウです**。

通常SwiftUIでは`body`の中に`print`を書くことができません。

```Swift
var body: some View {
    let width: CGFloat = 100 + 100
    print(width)               //エラー
    Rectangle()
        .frame(width: width)
}
```
この原因は`print(width)`が実は`Void`の値`()`を返していることです。そのため、`ViewBuilder`の側が`Void`の値を`View`として解釈しようとして、エラーになります。

パッと思いつく解決策としては下のように、`body`の外で計算型プロパティを作って内部で`print`を呼ぶ方法でしょうか。もちろんクロージャを即時実行する形でもいいと思います。


```Swift
var width: CGFloat {
    let _width: CGFloat = 100 + 100
    print(_width)
    return _width
}

var body: some View {
    Rectangle()
        .frame(width: width)
}
```
あとは`onAppear`内部で


```Swift
var body: some View {
　　 let width: CGFloat = {
        let _width: CGFloat = 100 + 100
        print(_width)
        return _width
    }()
    Rectangle()
        .frame(width: width)
}
```
何にせよちょっと面倒ですね。

そこで、`let width = 100 + 100`の方に着目します。これは文だから(値を返さないので)エラーになっていません。

そこでこうするとprintデバッグできるようになります。

```Swift
var body: some View {
    let width: CGFloat = 100 + 100
    let _ = print(width)       //200
    Rectangle()
        .frame(width: width)
}
```
得られた値`()`を文の中で用いるので、何の問題もなく実行されます。コード量は1行も増えません。
これでSwiftUIでもスマートにprintデバッグできるようになりました！

---
SwiftUI3ではひっそりとデバッグ用関数が追加されたようです。以下の関数を使うとさらに幸せになれそうです。

```swift
let _ = print(Self._printChanges())
```
atom-ide-uiが非推奨になっていた

atomをIDE化するパッケージである`atom-ide-ui`は開発が止まっており、非推奨になっている。後継パッケージが出ているので、そちらを使おう。

## 経緯

`atom-ide-ui`は元々facebookによって開発されていた。しかし、2018年になってfacebookがオープンソースに関する取り組みを廃止。`atom-ide-ui`リポジトリは[アーカイブされ](https://github.com/facebookarchive/atom-ide-ui)、atom本体の変更に追随しなくなった。
atomのIDEパッケージの開発を引き継いだのが[atom-community](https://github.com/atom-community)で、そこではかつての`atom-ide-ui`にあった機能がいくつかのパッケージに分割されて提供されている。こちらは更新が続いている。

## 対策

詳しくは[atom-communityの公式サイト](https://atom-community.github.io/)を参照。

atom-communityからは`atom-ide-ui`の代替となる以下のパッケージが提供されている。

 - [Data Tip](https://atom.io/packages/atom-ide-datatip) - 変数にカーソルを合わせるとデータチップが表示される。
 - [Signature Help](https://atom.io/packages/atom-ide-signature-help) - 関数にカーソルを合わせるとヘルプが表示される。
 - [Go to Definition](https://atom.io/packages/atom-ide-definitions) - 変数や関数が定義されている場所に飛べる。
 - [linter](https://atom.io/packages/linter) - リンター。
 - [linter-ui](https://atom.io/packages/linter-ui-default) - リンターUI。
 - [Outline](https://atom.io/packages/atom-ide-outline) 変数や関数の一覧を表示するやつ



これらの基本パッケージの中から必要なものを選んでインストールする。一個ずつインストールするのが面倒だという人は、全部が入った[atom-ide-base](https://github.com/atom-community/atom-ide-base)というパッケージもある。(←後から気付いた)
なお、基本パッケージは、IDE言語パッケージ（[ide-python](https://atom.io/packages/ide-python)とか）との組み合わせで動く。言語パッケージは従来の`atom-ide-ui`に対応しているものならなんでもいいようだ。
参考までに、いくつか言語パッケージを列挙しておく。

 - [ide-python](https://atom.io/packages/ide-python)
 - [ide-typescript](https://atom.io/packages/ide-typescript)
 - [ide-css](https://atom.io/packages/ide-css)
 - [ide-html](https://atom.io/packages/ide-html)
 - [ide-rust](https://atom.io/packages/ide-rust)
 - [ide-go](https://atom.io/packages/ide-go)
 - [ide-haskell](https://atom.io/packages/ide-haskell)
 - [ide-php](https://atom.io/packages/ide-php)

他にもいっぱいある。
古い言語パッケージは依存関係として`atom-ide-ui`を導入するようサジェストしてくるが、無視してOKらしい。


`atom-ide-ui`でも部分的には動くのだが、確認できる範囲ではターミナル機能などが死んでいて不安要素があるので、新しいほうに乗り換えたほうがよさそう。

## 参考

雑にググった結果。

 - https://blog.atom.io/2018/12/12/facebook-retires-nuclide-extension.html - `atom-ide-ui`の廃止が発表された時の記事
 - https://news.ycombinator.com/item?id=18666827 - それを受けての掲示板の反応
 - https://nazimboudeffa.medium.com/atom-ide-community-to-replace-facebooks-nuclide-2c8c6aab5a32 - atom-communityの紹介記事

「atom ide」とかでググると`atom-ide-ui`の情報しか出てこない。もうちょいコミュニティ盛り上がってくれ。
新規登録後、ログイン後のリダイレクト先を変更する

#概要
新規登録後、ログイン後のリダイレクト先を変更する。

※デフォルトではリダイレクト先がroot_ptahとなっている。

#前提
deviseをインストールし、新規登録、及びログイン機能が実装済み

#バージョン
rubyのバージョン　ruby-2.6.5
Railsのバージョン Rails:6.0.0

#実装内容
app/controllers/application_controller.rbに以下を記述する。


```app/controllers/application_controller.rb

〜省略〜

#新規登録後のリダイレクト先の指定
def after_inactive_sign_up_path_for(resource)
    ※指定_path                 
end

#ログイン後のリダイレクト先の指定
def after_sign_in_path_for(resource)
    ※指定_path 
end

〜省略〜

```
*指定は、自身が指定したいパスを記述

以上です。
【初心者用】SQLまとめ

#WHY
コードが一気に出てきて、いつでも見直せるようにまとめました

#SQLとは
SQL（シークェル）とはStructured Query Languageの略で、<b>RDB（リレーショナルデータベース）の操作</b>を行うための言語。
SQLの操作は<b>ターミナル</b>と<b>Sequel Pro</b>でもできる。
SQLでできることは主に以下の３つ
<b>データを定義する「DDL（Data Definition Language）」</b>
<b>データを操作する「DML（Data Manipulation Language）」</b>
<b>データを制御する「DCL (Data Control Language)」</b>

##DDL
データの削除、作成、更新などをするSQL

###ターミナルでの操作
mysqlにログイン（rootという名前でログインしている。）

```
mysql -u root
```

<br>
###CREATE
データベースやテーブルを作成できる。
<b>「CREATE DATABASE データベース(テーブル)名」</b>を実行すると、指定した名前のデータベース（テーブル）が作成される。

```
CREATE DATABASE 《データベース名》;

CREATE TABLE テーブル名 (カラム名1 カラム名1の型, カラム名2 カラム名2の型, …);
```
カラムの型はこんなかんじ。

|型名|保存できる値|
|:--:|:--:|
|INT|数字|
|VARCHAR(M)|最大M文字の文字列|

###SHOW
データベースやテーブルを一覧表示できる。
<b>「SHOW DATABASES(TABLES)」</b>を実行すると、作成されているデータベース(テーブル)を一覧で表示できる。

```
SHOW DATABASES;

SHOW TABLES;
```

###DROP
データベースやテーブルを削除できる。
<b>「DROP DATABASE データベース名」</b>を実行すると、作成されているデータベースを削除できる。

```
DROP DATABASE 《データベース名》;
```

###USE
データベースを指定する。
<b>「USE 《database名》」</b>と指定することでデータベースを選択する。

```
USE 《データベース名》;
```
###FROM
テーブルを指定する。
<b>「USE 《table名》」</b>と指定することでテーブルを選択する。

```
 FROM 《テーブル名》
```

###ALTER
データベースやテーブルを編集できる。
<b>ADD</b>で追加、<b>CHANGE</b>で変更、<b>DROP</b>で削除できる。

```
 ALTER TABLE テーブル名 ADD (カラム名 カラムの型, ……);
 ALTER TABLE テーブル名 CHANGE 古いカラム名 新しいカラム名 新しいカラムの型;
 ALTER TABLE テーブル名 DROP カラム名;
```
<br>
<br>
##DML
データの登録/更新/削除/検索などをするSQL。

###SELECT
データを取得する。
テーブルの全てのカラムを取得する場合は「*」ワイルドカードを使う。

```
SELECT 《カラム名》 FROM 《テーブル名》

SELECT * FROM 《テーブル名》
```

###INSERT
テーブルにデータを登録する。INTOという句と組み合わせて<b>INSERT INTO</b>として使用し、値は、VALUESの後に入力する。
カラム名はなくてもいい。

```
INSERT INTO テーブル名(カラム名1, カラム名2) VALUES(値1, 値2);
```

###UPDATE
データを更新する。
<b>テーブル名</b>を指定し、<b>SET</b>のあとに変更内容、<b>WHERE</b>のあとに条件を指定する。

```
UPDATE 《テーブル名》 SET 《変更内容》 WHERE 《条件》;

(例)　UPDATE goods SET price = 100 WHERE id = 2;
```

###DELETE
データを削除する。<b>FROM</b>のあとにテーブル名を、<b>WHERE</b>のあとに条件を指定する。

```
DELETE FROM 《テーブル名》 WHERE 《条件》;
```
<br>
<br>
##データ検索
###WHERE
条件を指定し、条件にあった<b>レコード</b>を取得する。

```
WHERE 《条件》

(例) WHERE id = 1

(例) WHERE last_name = "阿部"
```

###LIKE
WHEREと併用して使うことで<b>「文字列検索」</b>ができる。

```
WHERE 《列名》 LIKE '検索文字'
```

###AND演算子
複数の条件を指定し、その<b>条件がすべて正</b>であるレコードを取得する。

```
WHERE 《a》 AND 《b》
```
###OR演算子
複数の条件を指定し、その条件のうち<b>どれか1つ以上</b>が正であるレコードを取得する。

```
WHERE 《a》 OR 《b》
```

###NOT演算子
1つの条件を指定し、その条件に<b>当てはまらないもの</b>を取得する。

```
WHERE NOT 《a》
```
###BETWEEN演算子
1つのカラムに対し<b>上限と下限を指定</b>し、カラムの値がその範囲に含まれるレコードを取得する。

```
WHERE 《カラム名》 BETWEEN 《下限》 AND 《上限》
```
###IN演算子
1つのカラムに対し値を指定し、<b>カラムの値が指定した値を含む</b>レコードを取得する。

```
WHERE 《カラム名》 IN (値1, 値2, ……)
```
###JOIN
指定したカラム同士を紐付けさせ、<b>テーブルを紐づける</b>ことができる。

```
FROM 《テーブル名1》
JOIN 《テーブル名2》 ON 《テーブル名1.カラム名1》 = 《テーブル名2.カラム名2》
```
###CONCAT
複数の<b>文字列を連結</b>できる。
(例)last_nameとfirst_nameなど

```
CONCAT(文字列1, 文字列2, ……)
```
###GROUP BY
ある特定のデータごとに、平均値や総量などを集計するときに用いる。この時に、ある特定のデータをグループ化すると言う。

```
GROUP BY カラム名
```

###COUNT
グループ化されたデータに対して使用できる、データの総量をカウントする。<br>カラムを指定することで、そのカラムのデータの行数を取得できる。

```
SELECT COUNT(カラム名)
```
--------
実際に使ってみて覚えていこうとおもいます。
CentOS8とかAlmalinuxで使うコマンドのメモ

忘れるのでメモ。
ターミナルにコマンド打ち込めば動く。
たまにShellって書いてあるの見るけど、ありゃなんだろか。


# 間違えた単語

`'` シングルクォーテーション
`"` ダブルクォーテーション(`''`これはシングル2個）
`　バッククォート

プログラム上ではバッククォートは使わないらしい。
Qiitaの上ではこれ使うと`こういう`灰色の囲いができるからシングルクォートと間違えたんだけど？？

あと0（zero）とO（large-o）も間違える。
l（エル） と 1（イチ） と |（バーティカルバー）も怪しい。



# 便利な機能
コピー：Shift + Ctrl + C
ペースト：Shift + Ctrl + V
ただしターミナルに貼り付けるとenterを押したのと同じ扱いになる？
このページを参考にした（https://websetnet.net/ja/how-to-copy-paste-in-linux-terminal-for-absolute-beginners/

実行の強制停止：Ctrl + C



# インストール関係

### インストール
`yum install サービス名`
yumはdnfでもいい？
サービス名の後に`.service`ってつけなくても動く

`yum -y install`ってすると、間の質問を全部y(es)で返す

### アンインストール
`yum remove`



# プログラムの起動関係
### systemctlでの起動
`systemctl start サービス名`
例えばhttpdならsystemctl start httpd



### 起動してるかの確認
`systemctl status サービス名`



### そもそも何のプログラムがあるねん
全部：`systemctl list-units --all  --type=service`
起動中のみ：`systemctl list-units --type=service`
こちらを参考にした（https://www.suzu6.net/posts/303-systemctl-list/
ここも参考（https://qiita.com/sinsengumi/items/24d726ec6c761fc75cc9



# ディレクトリ関係
### ファイルシステムを見る
`df -Th`
dfコマンドにオプションで-Thを入れるとファイルシステムが確認できる。
バックアップするときによく確認した。
参考サイトはこちら（https://www.t3a.jp/blog/infrastructure/check-fileformat/



### ファイルを見る
`cat /ディレクトリ名/ファイル名`
例えばhomeディレクトリのhogeって名前のファイルなら cat /home/hoge



### ファイルを探す
ディレクトリ名から探す
`ls -l`

ファイル名から探す
`find / -name hoge_fuga.txt`

ファイル名の一部で探す
`find / | grep hoge`

ファイルに書いてある何かで探す
今いるディレクトリ以下を探すならfind の後は./でいい。
home以下なら~/で、フルパスを入れても良いらしい。
`find ./ -print | xargs grep 'hoge'`

ここ（https://kojimanotech.com/2018/12/28/113/#outline__4
から丸パk...参考にしました



### リストで表示して見る
`ls /ディレクトリ（＝ファイル）名`
例えばhomeディレクトリをリストで見たいならls /home
ディレクトリを一覧で見るときに便利。
他にもlsのオプションは豊富。よく使うのはこの辺か。
`ls -l`　詳細を1行で表示
`ls -a`　隠しファイルも表示
`ls -h`　サイズをメガ、ギガバイト表示
`ls -t`　更新日時順に表示
複合して`ls -alht`とかすると↑全部のせできる。

参考サイト
（https://linux.keicode.com/commands/list-directory-contents.php
（https://webkaru.net/linux/ls-command/
（https://uxmilk.jp/51846



### ハードリンクとシンボリックリンク
lsしたときにファイル名が ->　と表示されているのはシンボリックリンク
参考サイト（https://www.wakuwakubank.com/posts/342-linux-ln-unlink/



### パーミッションの変更
`chmod アクセス権限 変えたいファイルなど`　の組み合わせ。

例えば`chmod 660 hoge`だとhogeディレクトリのパーミッションは
本人とグループにrw、他人には何もなし、となる。

参考サイト（https://eng-entrance.com/linux-command-chmod
パーミッション早見表（https://hayakawa.ddo.jp/beginner/ux/permit.html



### 所有者の変更
`ls -l`で適当なディレクトリを覗くと
```
-rw-rw----  1 root root   0 Jul 22 12:02 ファイル名
```
となっていると思う。
左から、「ファイルの種類とパーミッション属性」、「ハードリンクの数」、「所有者と所有グループ」、「ファイルサイズ」、「タイムスタンプ」、「ファイル名」となっている。
参考（https://atmarkit.itmedia.co.jp/ait/articles/1605/18/news015.html

ここでファイルの所有者や所有グループを変えたいときがある。

例えばhoge.txtの所有者をrootに変えたいときは
`chown root hoge.txt`

所有グループをrootに変えたいときは
`chgrp root hoge.txt`

である。
両方一気に変えたいときは
`chown root:root hoge.txt`
でいける。

参考サイト（https://webkaru.net/linux/chown-command/



### ファイルに書き込む
`vi /ディレクトリ名/ファイル名`
例えばhomeディレクトリのhogeって名前のファイルなら vi /home/hoge
入ってiキーを押すとinsertモードになって書き込みができる。
終わるときにはescキーを押すとinsertモードが終わる。
ファイルを上書き保存してファイルを閉じたいときは`:wq`を入力してエンター。
上書きせずに閉じたいときは`:q!`してエンター。



### ディレクトリの移動
`cd /ディレクトリ名`
例えばhomeディレクトリのhogeディレクトリなら cd /home/hoge
`cd -`とすると最初の状態に戻せる。
一階層上のディレクトリに上がるとかはわからない。



# PCの起動関係
### 再起動
`reboot`



### 電源を切る
`shutdown -h now`
コマンドでできると謎にカッコイイ
Object→Map型変換

javaのオブジェクトクラスを変換するための処理です。(自分用メモ)

→Mapクラスへの変換

		Object object = item.get("obj");
		if (object instanceof Map) {
			data = (Map<String, Object>) object;
		}

どのクラスでも変換できるので、Stringに変換したい場合はStringに書き換えて使います。
アクセスするまで初期化を遅延させるlazyプロパティとは

#はじめに
最近、開発している時に使用する部分が出てきたので備忘録としてまとめます。

#lazyプロパティ
タイトルにもあるように`アクセスするまで初期化を遅延させるプロパティ`です。

コードで表すとこんな感じ。

```swift
lazy var hoge: Hoge
```

varの前に`lazy`を付けることで初期化を遅らせることが出来ます。

どのような動きをするのか確認してみましょう。

```swift
class Hogehoge {
    var hoge: Int = {
        print("hogeの値を生成します")
        return 1
    }()
    
    lazy var fuga: Int = {
        print("fugaの値を生成します")
        return 2
    }()
}

var hogehoge = Hogehoge()
print("Hogehogeクラスをインスタンス化しました")
print("hogeの値は\(hogehoge.hoge)です")
print("fugaの値は\(hogehoge.fuga)です")

// =======実行結果========
// hogeの値を生成します
// Hogehogeクラスをインスタンス化しました
// hogeの値は1です
// fugaの値を生成します
// fugaの値は2です
```

上記のコードを実行してみると通常のストアドプロパティ( hoge )の場合
`インスタンス化した時に初期化`が行われています。

対してlazyプロパティ( fuga )の場合は`アクセス時に初期化`が行われています。

この事から、lazyプロパティは`アクセスするまで初期化を遅延させている`ことが分かりますね。

#初期化時に他のプロパティやメソッドを利用できる
通常のストアドプロパティは、初期化時に他のプロパティやメソッドを利用することが出来ませんが
lazyプロパティの場合だと利用可能です。

実際にコードで検証してみましょう。

```swift
class Hogehoge {
    var hoge: Int = {
        print("hogeの値を生成します")
        return 10
    }()
    
    lazy var fuga = getValue(value: hoge)
    
    func getValue(value: Int) -> Int {
        print("今から計算します")
        return value * 2
    }
}

var hogehoge = Hogehoge()
print("Hogehogeクラスをインスタンス化しました")
print("fugaの値は\(hogehoge.fuga)です")

// =======実行結果========
// hogeの値を生成します
// Hogehogeクラスをインスタンス化しました
// 今から計算します
// fugaの値は20です
```
まず、hogeプロパティの値が生成されます。

そして、その後にHogehogeクラスのインスタンスが生成されて
そのインスタンスの`fugaプロパティにアクセス`します。

このアクセス時にfugaプロパティの初期化が行われて
それと同時にメソッドが呼ばれるため、初期化時に`利用可能`という訳です。

結果、fugaプロパティの値は`20`になりました。

#どのような場面で使えばいいのか？
色々、調べていくと

・`初期値がインスタンス生成後の状態(他のプロパティなど)に依存している`
・`セットアップが複雑で重く、使われるまでは生成する必要がない`

この上記のような場面で使うことが推奨されていました。

こちらの記事で詳しく説明されています↓
[【Swift4.1】lazyプロパティの使い所](https://qiita.com/negi0205/items/d367395d5780c915fb1d)
[【Swift】Lazyプロパティの使い方に気をつける(ドキュメントの確認は大事)](https://qiita.com/shiz/items/782979bd8a539c9d2291)
[Swiftでlazyの使い方を復習してみる](https://note.com/tzxdtc10/n/ne8604c880ea1)

#おわりに
アクセスされるまで初期化されないので、不要なメモリの消費を防ぐことにも繋がります。

ちゃんと理解して使い分けれるようになりたいですね。
【axios】POSTで通信する時にBodyにパラメタをセットする方法

些細なつまづきでしたが自戒の念を込めてQiitaに残します。間違っているところやもっとこうしたほうがいいよなどありましたらコメントによろしくお願いします。

## 前提

POSTで通信する時にBodyにセットしたいパラメタを次のようにします。オブジェクトじゃなくても問題ないです。

```js
const param = { id: 1, title: "BLEACH", price: 440 };
```
バックエンドはBodyの値を取得したときparamsを”直接”取得したいとのことでした。（”直接”の意味は後ほど）

## 結論
axiosにオブジェクトの引数を入れるだけでした(泣)。keyが`data`のところにBodyにセットしたい値（ここでは`param`）を書いてください。

```js
const options = {
  method: "POST",
  url: URI,
  headers: { "Content-Type": "application/json" },
  data: param,
};
const res = axios(options); // 適宜awaitなどを付けてください
```



## なぜ困ったか
私にとってむしろここが本題かも。axios使うときは必ず`axios.get`や`axios.post`で実装してました。中途半端にドキュメントを読んだせいで

```js
axios.post(URI, { data: param });
```
と書けばBodyに値がセットできると思ってました。ですがバックエンドから「keyに`data`を指定しないとBodyの値が取れないよ！」と言われた（これが上で出てきた”直接”の意味です。）のでおかしいなーと思いつつ

```js
axios.post(URI, param);
```
これでその場は解決しました。後日バックエンドから「timeoutも設定してくれ！」と頼まれました。この時に困りました。

```js
axios.post(URI, { data: param, timeout: 1000 });
```

これだと、いやいやこれだとまたkeyの`data`を介してじゃないと取れへんやん、となりドキュメントをちゃんと読み今回の結論に至りました。


## 最後に
これからは`axios.get`や`axios.post`を使わずに`axios(options)`実装しようと思いました。結局ドキュメントちゃんと読めって話ですね。

## 参考
https://github.com/axios/axios
【VS Code】Spring Boot(Java 8)の開発環境を構築する

## はじめに
VSCodeの拡張機能が`Java 11(<= version)`じゃないと動作しない場面に遭遇したので、`Java 8`プロジェクトで開発されている方向けに手順を共有します。

## 検証環境
- Windows 10

## 1.  VSCodeに拡張機能をインストール
適宜インストールしてください

- [Java Extension Pack](https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-pack)

- [Spring Boot Extension Pack](https://marketplace.visualstudio.com/items?itemName=Pivotal.vscode-boot-dev-pack)

- [Lombok Annotations Support for VS Code](https://marketplace.visualstudio.com/items?itemName=GabrielBB.vscode-lombok)

## 2. OpenJDKをインストール

`OpenJDK 8`と`OpenJDK 11`を両方インストールします。

以下からインストーラーを取得できます。

https://adoptopenjdk.net/?variant=openjdk8&jvmVariant=hotspot

## 3. setting.json編集

`setting.json`に以下を追記します[^1]

``` json
"java.home": "(OpenJDK 11インストールパス)/jdk-11"
"java.configuration.runtimes": [
        {
          "name": "JavaSE-1.8",
          "path": "(OpenJDK 8インストールパス)/jdk-8",
        },
        {
          "name": "JavaSE-11",
          "path": "(OpenJDK 11インストールパス)/jdk-11",
        },
    ]
```

## 4. F5キーを押下
押下しましょう(^ ^)

## まとめ

とにかく起動速度が`Eclipse`と段違いなので、乗り換えおすすめです。

[^1]: https://github.com/redhat-developer/vscode-java/wiki/JDK-Requirements#java.configuration.runtimes
FortranでNaNを見つける方法

# はじめに
Fortranで数値計算していると、NaNがどこで発生したか見つけたいと思うことが多々あると思います。
Intel fortran (ifort)にはNaNを見つけるisnanという関数があるのですが、他のコンパイラには無いようです。

方法としては、以下のような感じになります。
# 1. 基本的な方法
NaNは何と比較してもfalseなので

```fortran
if(a/=a)then
  write(*,*) "a is NaN"
endif
```
もしくは何と掛けてもNaNなので、

```fortran
if(a*0.0/=0.0)then
  write(*,*) "a is NaN"
endif
```
とすれば良いです。

# 2. コンパイラ最適化の回避
じつは、上の２つのコードはコンパイラ最適化によってうまく動作しなくなる可能性が高いです。
a/=aや、a*0=0といった演算は分かりきっていて意味のない演算だとコンパイラが判断してしまうので、このif文自体が取り除かれてしまいます。
これを回避するためには、

```fortran
zero = 0.0
call checknan(a,zero,flag)
```

```fortran
subroutine checknan(a,zero,flag)
  implicit none
  double precision,intent(in) :: a,zero
  logical,intent(out) :: flag
  flag = .false.
  if(a*zero/=zero)then
    flag = .true.
  endif
end subroutine
```

のように外部サブルーチンに分離してやると、ifが取り除かれなくなります。
コンパイラを騙しているようなものですね…
インライン展開を行うと、これでも取り除いてしまうコンパイラがあるかもしれないので、checknanのサブルーチンは別ファイルに分離するほうが安全です。

# 3. IEEE関数を使う方法
@implicit_none さんに教えて頂きました(コメントに有ります)。

```fortran
use, intrinsic :: ieee_arithmetic

if(ieee_isnan(a))then
  write(*,*) "a is NaN"
endif
```
でいけるようです。便利ですね。
ただし、gcc 5以前ではコンパイル出来ないようです。
CentOS 7やRHEL 7 (デフォルトがgcc 4.8.5)のマシンはまだまだ多いので、可搬性を考えると要注意です。
Power Automate から Teams へ Adaptive Card を Chat bot を使って投稿する

# Power Automate で HTML が使えなくなった？
らしい。
参考：https://qiita.com/yukimatsu/items/286be09e4b80cfd20478

#代わりにAdoptive Card を使う
慣れると簡単に使えるので、HTML と JSON どちらもできるようになるのがオススメ

##Power Automate で Chat bot を設定する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573860/ce3de86d-d62d-8dd0-18a6-4d1628c5ff2c.png)

**Post your own adaptive card as the Flow bot to a user** を使うのがキモ

間違えて Message post as flow bot を使っていてハマった。

##Adaptive card のJSON を作成する
https://adaptivecards.io/designer

```json:AdoptiveCardScheme例
{
    "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
    "type": "AdaptiveCard",
    "version": "1.2",
    "body": [
        {
            "type": "TextBlock",
            "text": "Sample file was uploaded"
        }
    ],
    "actions": [
        {
            "type": "Action.OpenUrl",
            "title": "Link to Forms",
            "url": "お好きなように"
        }
    ]
}
```

##Adaptive card の参考
https://adaptivecards.io/explorer/Action.OpenUrl.html

##Adaptive card の内容をPower Automate のアクションに記入する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573860/bf1de3e1-2661-9d17-f428-a220bb46ba33.png)
【 SQLを基礎から学んでみよう！】の備忘録

# 概要
この記事は、Techpitの教材[SQLを基礎から学んでみよう！](https://www.techpit.jp/courses/58)で学習した内容の備忘録です。

## 使用するテーブル
**playersテーブル**

|id|name|age|address|
|:---|:---|:---|:---|
|1|吉川|26|岐阜県|
|2|松原|26|大阪|
|3|坂本|32|兵庫|
|4|岡本|24|奈良|
|5|丸|31|千葉|
|6|パーラ|33|ベネズエラ|
|7|大城|27|沖縄|
|8|中島|38|兵庫|
|9|菅野|31|神奈川|

※こちらのデータは架空のものです。

## SELECT文

`SELECT`文はデータを抽出するときに使用します。

### 基本構文
```SQL
SELECT 項目 FROM テーブル WHERE 条件
```

### サンプル
```SQL
SELECT age FROM players WHERE age>=27
```
### 実行結果
`age`が27以上の人が抽出されます。

|id|name|age|address|
|:---|:---|:---|:---|
|3|坂本|32|兵庫|
|5|丸|31|千葉|
|6|パーラ|33|ベネズエラ|
|7|大城|27|沖縄|
|8|中島|38|兵庫|
|9|菅野|31|神奈川|


## UPDATE文
`UPDATE文`はデータを変更するときに称します。

### 基本構文
```SQL
UPDATE テーブル名 SET 列名 = 値
```

### サンプル
```SQL
UPDATE players SET age=age+1
```

### 実行結果

全員の`age`がプラス1されます。

|id|name|age|address|
|:---|:---|:---|:---|
|1|吉川|27|岐阜県|
|2|松原|28|大阪|
|3|坂本|33|兵庫|
|4|岡本|25|奈良|
|5|丸|32|千葉|
|6|パーラ|33|ベネズエラ|
|7|大城|28|沖縄|
|8|中島|39|兵庫|
|9|菅野|32|神奈川|

## INSERT文

新しいデータを追加するときに使用します。

### 基本構文
```SQL
INSERT INTO pkayers (列名, 列名, 列名, 列名,) VALUES (値,値,値,値)
```

### サンプル
```SQL
INSERT INTO players (id, name, age, address) VALUES (10,'ウィーラー','35','アメリカ')
```

### 実行結果

|id|name|age|address|
|:---|:---|:---|:---|
|1|吉川|26|岐阜県|
|2|松原|26|大阪|
|3|坂本|32|兵庫|
|4|岡本|24|奈良|
|5|丸|31|千葉|
|6|パーラ|34|アメリカ|
|7|大城|27|沖縄|
|8|中島|38|兵庫|
|9|菅野|31|神奈川|
|10|ウィーラー|35|アメリカ|

## DELETE文

`DELETE文`はデータを削除したいときに使用します。

### 基本構文
```SQL
DELETE FROM テーブル WHERE 条件
```

### サンプル
```SQL
DELETE FROM players WHERE id=6
```

### 実行結果

|id|name|age|address|
|:---|:---|:---|:---|
|1|吉川|26|岐阜県|
|2|松原|26|大阪|
|3|坂本|32|兵庫|
|4|岡本|24|奈良|
|5|丸|31|千葉|
|7|大城|27|沖縄|
|8|中島|38|兵庫|
|9|菅野|31|神奈川|

### 参考
[SQLを基礎から学んでみよう！](https://www.techpit.jp/courses/58)
長いコマンド打つの面倒！って思ったら【alias】

# はじめに
「`$ docker-compose ...`とか長いコマンド打つの面倒だな〜」
「サクッと`$ dc ...`とかにできないかな〜」

そんな時に役立つのが【alias】（エイリアス）です。
>**エイリアス 【alias】**
エイリアスとは、偽名、別名、通称などの意味を持つ英単語。ITの分野では、ある対象や実体を、複数の異なるシンボルや識別子で同じように参照できるする仕組みを指す。別名。[（IT用語辞典）](https://e-words.jp/w/%E3%82%A8%E3%82%A4%E3%83%AA%E3%82%A2%E3%82%B9.html)

必要な設定を行うことで、長〜いコマンドをお好みで省略して利用することができます。
以下、設定手順です👇

# .bash_profile, .bashrc作成
エイリアス設定に必要なファイルは、`.bash_profile`と`.bash_rc`の二つです。

```terminal:ターミナル
# 当該ファイルが存在するか確認
$ cat ~/.bash_profile
$ cat ~/.bashrc
```

もし`No such file or directory`と表示されたら、`.bash_profile`, `.bashrc`がまだ作成されてません。下記コマンドで新しく作っちゃいましょう。

```terminal:ターミナル
# 新規作成
$ touch ~/.bash_profile
$ touch ~/.bashrc
```

#.bashrcにエイリアスを書く
エイリアスは`.bashrc`に書きます。
ターミナルから`vi ~/.bashrc`と打ち、vimを使って記述します。
（※注）`=`部分は詰めて記述してください。

```shell:~/.bashrc
alias dc='docker-compose'
```
### （参考）viエディタの使い方
・入力する：`i` （→ `-- INSERT --`が下部に表示されたら入力OK）
・変更内容を保存：`:w`
・vi閉じる：`:q`
・変更保存して終了：`:wq`
・変更保存せずに終了：`:q!`

# .bash_profileに.bashrcを読み込む設定を書く
エイリアスは`.bashrc`に書くだけでは、反映されません。
別途、`.bash_profile`に`.bashrc`を読み込む記述が必要です。

`.bash_profile`はターミナルを起動する度に読み込まれるファイルなので、
そこに記述することで`.bashrc`がいつも反映されるようになる、ということですね👍

では`vi ~/.bash_profile`と打ち、最下部に`source ~/.bashrc`と記述しましょう！

```shell:~/.bash_profile
# .bashrcを読み込む記述
source ~/.bashrc
```

# .bash_profileの変更を反映する
先ほどの変更を反映させるために、ターミナル上で

```terminal:ターミナル
$ source ~/.bash_profile
```
と打ちます。
**これでエイリアスが設定できました！**

# 正しく設定されたか確認

```terminal:ターミナル
# 元々は $ docker-compose ps ですが…
$ dc ps
Name   Command   State   Ports
------------------------------
```
正しく設定できました！
AWSのEC2利用する際忘れてしまうコマンドメモ

結構　オンプレ　と違うのでメモを表記失礼します。

```
sudo -i
でrootに移動する。
```


ec2-userでviを編集した保存する場合は
[E45: 'readonly' option is set (add ! to override) が出た場合に保存する方法] (https://qiita.com/maedatakumi/items/220f747307f773bceb02)

```
入力モードをescで抜ける

コマンドモードで下記を実行

:w !sudo tee %
強制脱出
:q!
```


私はファイル検索はlocateを多用していたので使えなくて困っていたのですが

```
$ sudo updatedb
```
とすると
locate test
が使える。



また何か思い出したらコチラに表記する予定
【Godot】サウンドを動的にロードして再生する方法

# 概要
この記事では、サウンドファイル(*.wav / *.ogg) をGDScript上で実行時にロードして再生する方法を説明します

# 通常のサウンド再生
通常、サウンドを再生する場合には、`AudioStreamPlayer2D` にサウンドファイルを割り当てて再生する、という方法を行います。
![Godot_Engine_-_TestSound_-_Main_tscn____.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/564c73e5-0fa7-7a2a-c11e-e4f92f383974.png)

ただ、この方法だと異なるサウンドファイルを追加するたびに、登録が必要となり不便です。

# GDScriptでのサウンドの読み込みと再生
例えば、以下のサウンドファイルがプロジェクトに追加されているとします。

* 1.wav
* 2.wav
* 3.wav

![Godot_Engine_-_TestSound_-_Main_tscn____.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/c4039b13-71d9-5bf9-535e-1623916ddf58.png)

まずは以下のように `AudioStreamPlayer2D` を追加して、スクリプトを追加します。

```gd:Main.gd
extends Node2D

func _ready():
	pass # Replace with function body.

func _play_sound(idx):
	# 指定したIDのサウンドを再生
	# 一旦停止する
	$AudioStreamPlayer2D.stop()
	
	# サウンドファイルのパスを作成
	var path = "res://%d.wav"%idx

	# 動的に読み込んで steam に割り当てる
	$AudioStreamPlayer2D.stream = load(path)

	# 再生
	$AudioStreamPlayer2D.play()

func _process(delta):
	if Input.is_action_just_pressed("ui_left"):
		_play_sound(1)
	if Input.is_action_just_pressed("ui_up"):
		_play_sound(2)
	if Input.is_action_just_pressed("ui_right"):
		_play_sound(3)
```

画像の動的読み込みと同様、`load()` を使うことでサウンドファイルを動的に読み込んで再生します。

もしアクションゲームなどでサウンド再生のレスポンスの速さを出すために、毎回ロード処理を行いたくない場合は、`preload()` でサウンドファイルを読み込みます。
ただしその場合、動的にパスは作れず、固定のパスとなります。

```gd:Main.gd
extends Node2D

var Snd1 = preload("res://1.wav")
var Snd2 = preload("res://2.wav")
var Snd3 = preload("res://3.wav")

func _ready():
	pass # Replace with function body.

func _play_sound(idx):
	$AudioStreamPlayer2D.stop()
	
	match idx:
		1:
			$AudioStreamPlayer2D.stream = Snd1
		2:
			$AudioStreamPlayer2D.stream = Snd2
		3:
			$AudioStreamPlayer2D.stream = Snd3
		
	$AudioStreamPlayer2D.play()

func _process(delta):
	if Input.is_action_just_pressed("ui_left"):
		_play_sound(1)
	if Input.is_action_just_pressed("ui_up"):
		_play_sound(2)
	if Input.is_action_just_pressed("ui_right"):
		_play_sound(3)
```

# 参考

* [Correct way to load and play sounds from code](https://godotengine.org/qa/88590/correct-way-to-load-and-play-sounds-from-code)
PHP 簡易掲示板作成　表示編 #2

[PHP 簡易掲示板作成　データ保存編 #1](https://qiita.com/yuyawatanabe1028/items/94f2b503cee8b0170911#comment-ac8b90a30dae1cb2284d)の続き
データの保存内容

```:test.txt
1<>yuya<>完成<>2021/2/8 10:13:16
2<>yuya<>完成<>2021/2/8 10:13:22
3<>yuya<>完成<>2021/2/8 10:13:25
```
#目標
入力フォームのすぐ下部にテキストファイルの内容を表示する
1. ファイルを1行ずつ読み込み、配列変数に代入する
2. 配列の数だけ処理をする
3. 処理内容：区切り文字「<>」で分割して、それぞれの値を取得
4. 処理内容：上記で取得した値を表示する

#入力フォームのすぐ下部にテキストファイルの内容を表示する
１. ファイルを1行ずつ読み込み、配列変数に代入する
`file`関数：ファイルを読み込み行ごとに配列にして返す

```php:PHP
$lines = file($filename,FILE_IGNORE_NEW_LINES);
```
`file関数`を使うことで以下のように配列が作れる

```php:具体例
<?php
    $filename = "test.txt";
    $lines = file($filename,FILE_IGNORE_NEW_LINES);
    print_r($lines);
?>
```
```:結果
Array ( 
[0] => 1<>yuya<>完成<>2021/2/8 10:13:16
[1] => 2<>yuya<>完成<>2021/2/8 10:13:22
[2] => 3<>yuya<>完成<>2021/2/8 10:13:25
)
```
２. 配列の数（＝行数）だけ処理をする
→`foreach文`を使う

```php:PHP
foreach($lines as $line){
      //処理
}
```
 
３.  処理内容：区切り文字「<>」で分割して、それぞれの値を取得
`explode関数`：
文字列を指定した文字列で分割する関数。分割された文字列は、配列の各要素として格納される。

```php:PHP
$elements = explode("<>",$line);
```
`explode`関数の実際の挙動

```php:具体例
$str ="1<>yuya<>完成<>2021/2/8 10:13:16";
$str = explode("<>",$str);
print_r($str);

echo $str[0];
```
```:結果
Array (
[0] => 1
[1] => yuya
[2] => 完成 
[3] => 2021/2/8 10:13:16 
)

1
```
４. ループ処理内：上記で取得した値を表示する

```php:PHP
echo $elements[0].$elements[1].$elements[2].$elements[3];
```
何回も`$elements[i]`を書くので、`for文`繰り返し処理を行う
・始めの値：`$i`をインデックス番号として扱う
　　　　　　インデックス番号[0]から順番に取得したので0→`$i = 0`
・条件式 ：インデックス番号　<　要素の数
         `count関数`を使って配列の要素の数を出す→`$i < count($elements)`
・増減式 ：処理一回ごとに、値を1ずつ増やす→`$i = $i + 1`→→`$i++`

```php:PHP
for($i = 0 ; $i < count($elements); $i++){
    echo $elements[$i];
}
```
#まとめ

```php:PHP
<?php
    $filename = "test.txt";

    //ファイルを行ごとに要素として配列に格納
    $lines = file($filename,FILE_IGNORE_NEW_LINES);
    
    //格納された要素毎の処理を行う
    foreach($lines as $line){
        
        //要素を"<>"で分割して配列に格納
        $elements = explode("<>",$line);
        
        //格納した要素を取り出し表示する
        for($i = 0 ; $i < count($elements); $i++){
            echo $elements[$i];
        }
    echo "<br>";
    }
?>
```
laravel migrateしたときのエラー対処方法

php artisan migrateコマンドを実行した際に、
SQLSTATE[HY000] [1045] Access denied for user ‘root’@’localhost’ (using password: NO)というエラーが発生。

内容としては、
ユーザー ‘root’ @ ‘localhost’のアクセスが拒否されました。という内容です。

解決した方法

```　.env
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=データベース名
DB_USERNAME=root
DB_PASSWORD=root
```
キャッシュをクリア

//下記コマンドを実行

```
$ php artisan cache:clear
```
//▼実行結果

```ターミナル
Cache cleared successfully.
```
//下記コマンドを実行

```
$ php artisan config:cache
```
//▼実行結果

```ターミナル
Configuration cache cleared!

Configuration cached successfully!
```
Windows Update 停止コマンド（手動更新へ変更）

#　Windows Update 停止コマンド

よく忘れるのでWindows Update 停止コマンドをメモ
なお動作確認をしたことがあるOSは下記の通り
>Windows 10, Windows Server 2016, Windows Server 2019

## 停止
``` powershell
reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU" /v "NoAutoUpdate" /d "1" /t REG_DWORD /f
```

## 再開
``` powershell
reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU" /v "NoAutoUpdate" /d "0" /t REG_DWORD /f
```

## Appendix
上記のコマンドはレジストリをそのまま書き換えているので
AD環境ではGPOでの適用をおすすめ致します。
だいたいわかるPHPのコールバック関数のサンプル

しょっちゅう忘れるので、だいたいわかる感じで書いた。

## array_walkのサンプル

```php:FizzBuzz.php
<?php
$arr = range(1,100);


array_walk($arr, "FizzBuzz");

function FizzBuzz($val, $index){
    echo ($index + 1)." : ";
    if($val % 15 == 0){
        echo "FizzBuzz".PHP_EOL;
    } else if ($val % 5 == 0){
        echo "Buzz".PHP_EOL;
    } else if ($val % 3 == 0){
        echo "Fizz".PHP_EOL;
    } else {
        echo $val.PHP_EOL;
    } 
}
// 出力結果（一部）
1 : 1
2 : 2
3 : Fizz
4 : 4
5 : Buzz
...
15 : FizzBuzz


```

## usortのサンプル
```php:usortSample.php
<?php
//以下の配列を末尾の数字順にソートをしたいみたいなケース
$a = ["A-1", "B-3", "C-4", "D-2", "E-5"];

usort($a, "cmp");

foreach ($a as $key => $value) {
    echo "$key: $value\n";
}

function cmp($a, $b)
{
    $numA = substr($a, -1);
    $numB = substr($b, -1);
    
    if ($numA == $numB) {
        return 0;
    }
    return ($numA < $numB) ? -1 : 1; 
    //比較関数は、最初の引数と二番目の引数の比較結果を返します。
    //最初の引数のほうが二番目の引数より大きい場合は正の数を、
    //二番目の引数と等しい場合はゼロを、
    //そして二番目の引数より小さい場合は負の数を返す必要があります。
}
?>
// 出力結果
0: A-1
1: D-2
2: B-3
3: C-4
4: E-5

```
pandasでカンマ区切りの値や正規化されたデータをダミー変数に変換を行う

ダミー変数変換（Dummy Variable Encoding)は One-Hot Encoding とも呼ばれるデータ変換手法です。
pandas では `get_dummies` メソッドを使うと、以下のようにダミー変数へ変換できます。

```python
df = pd.DataFrame({'user': [1,2,3],
                   'flag': ['a','b','a']})
pd.get_dummies(df['flag'])
```

|  | a | b |
|:-:|:-:|:-:|
| **0**  | 1  | 0  |
| **1**  | 0  | 1  |
| **2**  | 1  | 0  |

文字列の値をバイナリ値の複数列に変換します。

## カンマ区切りの値が入っている場合の変換方法

次に、以下のようなカンマ区切りで値を持っているデータフレームでダミー変数への変換を行おうとする場合、

```python
df = pd.DataFrame({'user': [1,2,3,4,5],
                   'opt1': [100,200,200,400,100],
                   'opt2': ['a', 'a,b', 'c', 'b,c', 'b']})
```

| |user|opt1|opt2|
|:-:|:-:|:-:|--:|
|**0**|	1 |100	|a|
|**1**|	2 |200	|a,b|
|**2**|	3 |200	|c|
|**3**|	4 |400	|b,c|
|**4**|	5 |100	|b|

対象のカラムをカンマ区切りで変換します。（わかりやすいように `opt2_` プレフィックスをつけてます）

```python
df2 = df['opt2'].str.get_dummies(sep=',').add_prefix('opt2_')
```

| |opt2_a|opt2_b|opt2_c|
|:-:|:-:|:-:|--:|
|**0**|	1 |0|	0|
|**1**|	1 |1|	0|
|**2**|	0 |0|	1|
|**3**|	0 |1|	1|
|**4**|	0 |1|	0|

参考: [pandas.Series.str.get_dummies](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.str.get_dummies.html)

これを元のデータフレームから必要なカラムだけ取り出してから結合して完成です。

```python
df3 = pd.concat([df[['user', 'opt1']], df2], axis=1)
```

| |user| opt1| opt2_a | opt2_b |opt2_c |
|:-:|:-:|:-:|:-:|:-:|:-:|
|**0**|	1 |100|	1 |0 | 0 |
|**1**|	2 |200|	1 |1 | 0 |
|**2**|	3 |200|	0 |0 | 1 |
|**3**|	4 |400|	0 |1 | 1 |
|**4**|	5 |100| 0 |1 | 0 |

## 正規化されたデータの場合

リレーショナルデータベースからデータを取得する場合は、正規化されていることがほとんどです。
以下のように2つのテーブルのデータに対してダミー変数への変換を行います。

```python
df1 = pd.DataFrame({'user': [1,2,3,4,5],
                   'opt1': [100,200,200,400,100]})
df2 = pd.DataFrame({'user': [1,2,2,3,4,4,5],
                    'opt2': ['a','a','b','c','b','c','b']})
display(df1, df2)
```

| |user|opt1|
|:-:|:-:|:-:|
|**0**|	1|100 |
|**1**|	2|200 |
|**2**|	3|200 |
|**3**|	4|400 |
|**4**|	5|100 |

| |user | opt2 |
|:-:|:-:|:-:|
|**0**|	1 |a |
|**1**|	2 |a |
|**2**|	2 |b |
|**3**|	3 |c |
|**4**|	4 |b |
|**5**|	4 |c |
|**6**|	5 |b |

この場合、ダミー変数へ変換を行うと `user`の`2`と`4`が重複してしまいます。

```python
pd.get_dummies(df2, columns=['opt2'], prefix='opt2')
``` 

| |user | opt2_a | opt2_b | opt2_c |
|:-:|:-:|:-:|:-:|:-:|
|**0**|	1 |1|0|0|
|**1**|	2 |1|0|0|
|**2**|	2 |0|1|0|
|**3**|	3 |0|0|1|
|**4**|	4 |0|1|0|
|**5**|	4 |0|0|1|
|**6**|	5 |0|1|0|

そのため、`groupby` して `sum` で集約します。

```python
df3 = pd.get_dummies(df2, columns=['opt2'], prefix='opt2').groupby('user').sum()
```

|user|opt2_a|opt2_b|opt2_c|
|:-:|:-:|:-:|:-:|			
|**1**|	1 | 0 |0|
|**2**|	1 | 1 |0|
|**3**|	0 | 0 |1|
|**4**|	0 | 1 |1|
|**5**|	0 | 1 |0|

最後に元のデータにマージして完成です。

```python
df4 = df1.merge(df3, on='user')
```

| |user|opt1|opt2_a|opt2_b|opt2_c|
|:-:|:-:|:-:|:-:|:-:|:-:|
|0|1|100|1|0|0|
|1|2|200|1|1|0|
|2|3|200|0|0|1|
|3|4|400|0|1|1|
|4|5|100|0|1|0|
Microsoft Teams の ID を取得する

#Teams の各種ID
1. Tenant ID
2. Group ID
2. Channel ID
3. Thread ID

##Channel のリンクを取得
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573860/e37ee3bd-efb0-96f1-c602-20b890fb91d8.png)


下記のような構成になっている。

https://teams.microsoft.com/l/channel/チャンネルのID@thread.skype/ここに該当のチームのコード?groupId=グループのID&tenantId=テナントのID

##Thread のリンクを取得
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573860/90c7f9b0-63c6-830a-174f-9d56875f1d50.png)

https://teams.microsoft.com/l/message/チャネルID@thread.skype/チームのコード?tenantId=テナントID&groupId=グループID&parentMessageId=メッセージID&teamName=チームの名前&channelName=チャネルの名前&createdTime=作成日時
ラズパイをmacで遠隔操作する際に詰まったこと（超初心者）

##はじめに

コロナが蔓延し、リモートワークが増えたので、PCを遠隔操作してみたい！！
とIT初心者がラズパイをノリとテンションで購入し、遠隔操作ができるまでに詰まったところをメモしたいと思います。
参考サイトを下に記載してありますが、そこで触れられないような初歩的なミスが多かったので、そういった点をピックアップしていきます。

##環境
・RaspberryPi4 Model4
・OS:Raspbian Gnu/Linux(buster)
・ディスプレイ:Panasonicのテレビ
・PC:macOS Big Sur 11.2
・LANへはRaspberryPi4内臓の無線接続
・VNCはRaspbianにデフォルトで入っていたものを使用
・ルーターはプロバイダから有線接続しているものを使用（APモード）

##参考サイト
今回は以下のサイトを参考にしています。
以下のサイト以外でも「ラズパイ」「SSH」「遠隔」などの検索ワードで調べれば、たくさん参考になるサイトが出てきます。

macだけでraspberry Piに接続する
https://qiita.com/murs313/items/81757bf8bc74b6b76cdf

Raspberry Pi3のLAN外からのSSH接続設定方法
https://qiita.com/3no3_tw/items/4b5975a9f3087edf4e20

※注）以下はサイトを参考に進めて行くと詰まらず進むことも十分あります

##詰まった箇所
###IPアドレスの固定
私はディスプレイがあったのでターミナルを開き、コマンドで管理者権限でファイルを開きGUIで編集しました。

```UNIX:terminal
$ sudo pcmanfm
```

/etc/dhcpcd.confのファイルを開く

```:/etc/dhcpcd.conf
interface wlan0
static ip_address=192.168.0.xxx/24        #固定するローカルIP
static routers=192.168.0.1              #デフォルトゲートウェイのIP
static domain_name_servers=192.168.0.1  #DNSサーバーのIP?
```
xxxに任意の数を設定
ここで私は一度詰まりました。
たくさんのサイトを見て、行っていたのですが、
static ip_address=192.168.<font color="Red ">xxx</font>.xxx/24
と記載があったサイトがあったので、
赤い部分まで自由に設定したところ、サブネットが変わってしまい同一ネットワークから弾かれてしまったため、ローカルでSSH接続を試す際に、

```UNIX:terminal
$ ssh pi@raspberry.local
```

では繋がるのに

```UNIX:terminal
$ ssh pi@192.168.xxx.xxx(自分で固定したIPアドレス)
```

では繋がらないない
arpコマンドにも反応しない
pingコマンドも返ってこない
という事態に陥りました。

###ポート開放
外部からのアクセスのためルーターに入り口を開けてあげる作業なのですが、
こちらもサイトを見て行えばなんら問題はないのですが、
ルータを複数個接続している場合に少しややこしくなるようで、私の場合はそうだったので詰まりました。
私は環境に記載した通りプロバイダーが有線だったので、関係ないと思っていましたが、ルーターがAP
モードだったので、プロバイダーのポートを開放しないとダメなようです。
ルーターを複数で中継している場合は、各ルーターのポートを開放するようです。
ポートの開放を確認する時には下記のサイトを使用しました。
（nmapのコマンドも使用しました）
https://www.cman.jp/network/support/port.html

##まとめ
知識量も少なく、初歩的なミスが多かったですが、初心者の私でも繋げることができました。
私と同じで、ノリとテンションでラズパイを買ってしまった人の参考になればと思います。