OmniAICreator/Qiita-1.07M huggingface dataset:
NCBIのAPI(E-Utils)を使ってPMIDからDOIを取得(Python編)

NCBIの論文情報をAPI(E-Utils)を用いて取得し、ローカル環境でPythonで解析しましたので、その方法について記録します。

記載時：2021/9/10
環境：macOS Catalina(10.15.7)、Python 3.8.5


#1.E-Utilsについて

E-Utilsを用いたGEOへのアクセスについては下記に概要が説明されています。

https://www.ncbi.nlm.nih.gov/geo/info/geo_paccess.html?fbclid=IwAR1DVyyt7XdftfKU_7r8YAuwZPZGgpWtOCXR6mRPQrV1xr0QLk-t0f2KAEQ

簡単に説明すると、例えばPMIDを引数として、論文タイトルやDOIを返り値として取得という作業をCUIで行うことができます。

#2.PUbMedから論文情報を取得してみる。

E-UtilsにはeSearch、eSummary、eFetch、ePost、eLink、eInfoなどのプログラムがあります。
今回は試しにeSummaryを使用して、引数として渡したPubMed IDからDOIを返すプログラムを作成してみます。
まず、Webブラウザでアクセスして概要を把握します。今回はXML形式でデータを取得します。実際に(PMID) 33294783の論文(私の学位論文 笑)の情報を取得してみます。

URLは{使用するプログラムのURL}?{クエリパラメータ}となります。

例：`https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=pubmed&id=33294783&retmode=xml`

![eSearch結果画面](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/590859/b222c4ea-6b28-4cc2-c1cf-bdad683c93da.png)

このように表示されます。
PythonでこのXMLデータをローカル取得し、必要な情報を抽出したいと思います。

#3.PythonでAPIからアクセス

```Python3:pmid_doi.py
# pubmed idを入力してDOIを返すプログラム

import sys
import urllib.parse as parse
import urllib.request as req
from bs4 import BeautifulSoup

# 基礎の指定
API = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi"

# 引数を取得
if len(sys.argv) <= 1:
    print("USAGE: pmid_doi.py (PMID)")
    sys.exit()
pmid = sys.argv[1]

# パラメータをURLエンコード
query = {
    "db": "pubmed",
    "id": pmid,
    "retmode" : "xml",
}
params = parse.urlencode(query)

# HTMLを取得
url = API + "?" + params
print(url)
res = req.urlopen(url)

# Beautifulsoupで解析
soup = BeautifulSoup(res, "html.parser")
# セレクタの結果はリストになるので抽出
DOI = soup.select("Item[Name='DOI']")[0]
# 文字列のみ抽出
DOI = DOI.string

# 結果表示
print(DOI)
```

解説；APIへのアクセスのためにurllibモジュールのparseパッケージとrequestパッケージをインポートします。取得したXMLデータの解析のため、BeautifulSoupをインポートしておきます。

まず、基礎となるプログラムのURLを指定します(eSummaryを使用するのであれば
`https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi`
を指定します)。

続いて、URLクエリパラメータをdictionary形式で指定します。
今回はデータベースとしてpubmed、データ形式はxmlとします。
辞書データをparseしてURLとして渡せる形式にします。

urlopenで取得した結果をBeautifulSoupで解析。"html.parser"を使用します。
属性と名前を指定し、情報を取得します(リスト形式になっているため0で抽出します)。
文字列のみsrtingで取得すると完成です。

```Bash
$ python3 pmid_doi.py 33294783

https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=pubmed&id=33294783&retmode=xml
10.1016/j.isci.2020.101774
```

うまくいっているようです。

同様に様々な情報を取得することができます。

##参考：rettype、retmodeなどのパラメータの組み合わせについてはlinkのtableを参考に。

https://www.ncbi.nlm.nih.gov/books/NBK25499/table/chapter4.T._valid_values_of__retmode_and/
【超初心者用】PaizaCloud✖Djangoでwebアプリを作る

#何の記事？
YouTubeの動画を見ながらDjangoでwebアプリを構築しました。
手順の備忘録です。使用するプログラムはpythonです。
https://www.youtube.com/watch?v=nS41IkL13QE&t=1057s

#手順
1. PaizaCloudにログインして新規サーバを作成。言語はDjangoにする

2. ターミナルから、```django-admin startproject django_website```と入力(django_websiteはプロジェクト名）

3. ```pwd```➡```cd django_website```でフォルダを移動

4. ```python manage.py runserver```で開発用サーバーの立ち上げ

5. django_website/pycache/settings.pyの28行目、```ALLOWED_HOSTS = []```となっているところを、```ALLOWED_HOSTS = [*]```に書き換える

6. 左の8000をクリックすると、サイトが表示される

7. ターミナルで```python manage.py startapp website```と入力してwebsiteというアプリを作成

8. django_website/pycache/settings.pyのINSTALLED_APPSに新しく追加したアプリ('website')を追加登録

9. websiteフォルダを右クリックして```"templates"```フォルダを作り、その中に```"index.html"```というファイルを作る。

```index.html
<h1>Hello, django!</h1>

```


10: websiteフォルダ内のviews.pyを以下のように書き換える

```views.py
from django.views.generic import TemplateView

class IndexView(TemplateView):
    template_name = "index.html"
```

11: websiteフォルダ内にurls.pyを作成し、以下のように記載

```urls.py
from django.urls import path
from .views import IndexView

urlpatterns = [
    path('', IndexView.as_view()),
]
```

12: django_website>pycache>urls.pyを以下に書き換える

```
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('website.urls'))
]

```

これで晴れて、"Hello, django!"を表示できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620139/8fe899da-1461-dd46-346c-b260049ee9ce.png)

フォルダ構成は以下の通りです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620139/d773a25c-d561-108e-bdef-a686dbfa1979.png)
Dokku日本語ドキュメント

個人開発をしていて運用環境をかんたんに構築できるツール[Dokku](https://dokku.com)の日本語ドキュメントがありましたので、共有させていただきます。

↓↓↓
[Dokku日本語ドキュメント](https://dokku.docu.jp/0.24/)
↑↑↑
【Golang】構造体の並び順を自動で整える（govet の fieldalignment エラーの自動修正）

## <ruby>Struct<rt>構造体</rt></ruby> の <ruby>Field Alignment<rt>フィールドの並び</rt></ruby> で叱られる

> Go 言語の総合 lint ツールの [golangci-lint](https://golangci-lint.run/) で、`govet` の linter が「構造体の並び順にメモリの無駄がある」と指摘してきます。
>
> ```go:ほらgolang叱られた
> fieldalignment: struct with N pointer bytes could be M (govet)
> ```

この、`govet` の `fieldalignment` エラーが出るたび、構造体のフィールドの並びを<ruby>コピペピピックする<rt>トライ＆エラーでわけわかめになる</rt></ruby>のが面倒なのです。[「"go" golang fieldalignment govet フィールド 並び順 修正」でググって](https://www.google.com/search?q=%22go%22+golang+fieldalignment+govet+%E3%83%95%E3%82%A3%E3%83%BC%E3%83%AB%E3%83%89+%E4%B8%A6%E3%81%B3%E9%A0%86+%E4%BF%AE%E6%AD%A3)も出てこなかったので、自分のググラビリティとして。

## TL; DR <sub><sup><sub><sup>（今北産業）</sup></sub></sup></sub>

1. `fieldalignment` には `-fix` オプションがあるので、それ（自動修復）を使うと便利。
    - `golangci-lint run --fix` すると、他の linter の自動修正も適用されてしまうので注意。`fieldalignment` コマンドを別途入れておくと勝手が良い。
1. 単体コマンドとしてもインストールできる。
    - `golang.org/x/tools/go/analysis/passes/fieldalignment/cmd/fieldalignment@latest`

    ```bash
    go install golang.org/x/tools/go/analysis/passes/fieldalignment/cmd/fieldalignment@latest
    ```
    ```bash
    fieldalignment -fix ./lib/mypackage
    ```

1. 当然ですがフィールドの並び順が変わるので、既存のオブジェクト作成箇所に注意。
    - テストなど、構造体の新規オブジェクトを `a := &myStruct{"foo","bar", 123}` のように「フィールド名指定なし」で指定しているとエラーになるので、並びを合わせます。

## 動作確認

- `go version go1.17 linux/amd64` @ golang:1.17-alpine Docker image

## 参考文献

- [github.com/mdempsky/maligned](https://github.com/mdempsky/maligned) (`fieldalignment` のオリジナル） @ GitHub 
- [fieldalignment package](https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/fieldalignment) @ pkg.go.dev
- [x/tools/go/analysis/passes/fieldalignment: add a command?](https://github.com/golang/go/issues/43446) | #43446 | go | golang @ github.com
STM32L010を使た、MbedでHALのLチカ (約5Kバイト)


目的
最軽量化

PA4(10ピン)をLチカする。

x Mbedのリビジョンは、143


![h_con56.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/5d6e1460-6a9f-bfdb-9a89-3c984ba03df3.jpeg)



![h_con55.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/6129a7c6-432f-ad61-bf35-363227a6ff86.jpeg)



```c++


#include "mbed.h"

//DigitalOut myled(PA_4);

int main() {

  __HAL_RCC_GPIOA_CLK_ENABLE();
    
  GPIO_InitTypeDef GPIO_InitStruct = {0};
    
  GPIO_InitStruct.Pin = GPIO_PIN_4;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    
    
    while(1) {
        //myled = 1;
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
        wait(0.2);
        //myled = 0;
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
        wait(0.2);
    }
}




```
無料の勉強教材一覧　laravel編

現在絶賛勉強中のPHPフレームワークlaravelが無料で学べるサイトを集めました。(随時更新していきます)


##環境構築編
MAMPを使ってlaravel6の環境構築がローカル上でできます
https://youtu.be/yaitzPzBzuI

cloud9を使ってlaravel6の環境構築ができます
https://youtu.be/XGDS6TRWDLU

cloud9を使ってlaravel8の環境構築ができます
https://youtu.be/XXXQOYnsCBk

##基本的なCRUD機能実装

##参考サイト
storyboardをなしで画面を呼び出す方法

今回のゴールはこちら。
![スクリーンショット 2021-09-10 16.34.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494487/d64e7b3f-b26c-0f9e-ce35-dbc7547d7520.png)

プロジェクトを一から立ち上げてビルドした時に、Main.storyboardで白い画面が表示されると思うんですが、それをstoryboardなしで表示します。

やることはこちらの通り。

1.Main.Storyboardの削除
2.SceneDelegateを全てコメントアウト
3.AppDelegateの一部コメントアウト & 修正
4.Info.plistの一部分削除
5.PROJECTのGeneralの修正


それぞれ解説します。


1.Main.Storyboardの削除(画面を削除するだけなので、省きます)

2.SceneDelegateを全てコメントアウト(コメントアウトするだけなので、ここも省きます)

　
3.AppDelegateの一部コメントアウト & 修正
ソースはこちら。そのままコピー&ペーストでOKです。

    import UIKit

    @main
    class AppDelegate: UIResponder, UIApplicationDelegate {

        var window: UIWindow?

        func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
            // Override point for customization after application launch.
            
            window = UIWindow(frame: UIScreen.main.bounds)
            window?.makeKeyAndVisible()
            
            window?.rootViewController = ViewController()
            
            return true
        }

        // MARK: UISceneSession Lifecycle

    //    func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
    //        // Called when a new scene session is being created.
    //        // Use this method to select a configuration to create the new scene with.
    //        return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
    //    }
    //
    //    func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
    //        // Called when the user discards a scene session.
    //        // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
    //        // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
    //    }


    }

　
4.Info.plistの一部分削除
Application Scene Manifestの項目を全て削除してください。
![スクリーンショット 2021-09-10 16.21.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494487/551aa219-38fc-0c4a-d678-ebcd7fd3c992.png)

5.PROJECTのGeneralの修正

正確には、PROJECT　→　General　→　Deployment Info　→　MainInterFaceの削除

小さくてわかりづらいんですが、Mainとなっている部分を削除します。
![スクリーンショット 2021-09-10 16.24.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494487/867be2ac-0c72-3e7e-53cc-cba1e92555b7.png)
下記のように空白にします。
![スクリーンショット 2021-09-10 16.31.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494487/6ac459f1-5377-f3d4-218e-ef5933088735.png)

そして最後にViewControllerのソースはこちら。

    import UIKit

    class ViewController: UIViewController {

        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
            view.backgroundColor = .white
        }
    }
Android Studio Arctic FoxでOpenCVを導入する際に躓いたこと

# 躓いたポイント
File → New → Import Module...
でOpenCVをインポートしようとしたところ、Finishボタンがクリックできなかったので、その解決法。

![import_module.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/694762/d10b3d50-f1fd-230a-f4d9-c1e5314d53d8.png)


# 解決方法
どうやらバグらしい([参照](https://stackoverflow.com/questions/68649524/opencv-android-studio-module-importing-issue))。以下の手順を行うことで解決。

1． [ここからAndroid版OpenCVをダウンロード。](https://opencv.org/releases/)
2． プロジェクトフォルダ直下に先ほどダウンロードしたOpenCV-android-sdkの中にあるsdkフォルダをコピー
3． `settings.gradle`ファイルの一番下に下記内容を追加。

```settings.gradle
//(省略)
include ':sdk'
```
4． `sync now`をクリックし、終わるまで待つ。
5．  File → Project Structureでウィンドウを開く
6． 左側のDependenciesから、appを選択し、DeclaredDependenciesの下にある＋ボタンで3: Module dependencyを選択し、先ほどコピーしたsdkを選択。
![ProjectStructure.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/694762/40bc8080-2bfe-8cdc-d6a7-eb697f033745.png)
7． onCreate当たりに`OpenCVLoader.OPENCV_VERSION`と記述してエラーが出なければ導入成功してるはず。
Amazon GuardDutyでTrojan:EC2/DGADomainRequest.Bが発生したが、そこまで驚異ではなかった話。

### 結論
GuardDutyがトロイと認定しているドメインをforwardさせるSSH接続の総当たり攻撃があり、SSHDが気を利かせてドメインの情報を照会した為に起きていた。実際にトロイの木馬に感染しているわけでは無かった。


###SlackにGuardDutyからヤバい通知がきた

![Screenshot from 2021-09-10 16-14-46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293892/7f61e17d-fb14-6481-27e3-9efb050bf4d0.png)
EC2 instance i-xxxxxxxxxxxx is querying algorithmically generated domains. Such domains are commonly used by malware and could be an indication of a compromised EC2 instance.
![Screenshot from 2021-09-10 16-15-57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293892/9a0f6d05-4ada-069a-5fda-1e1c1e6b36e1.png)

アルゴリズム的に作られたドメインにクエリを送ったから、トロイ感染しているんじゃね？という通知だ。しかも重要度(Severity)は高いと。

###一次対策に失敗?

該当のインスタンスを終了、再度立ち上げた。しかし、数時間後にまた別のインスタンスで同じ通知が来るの繰り返し。

グローバルIPV4割当をしていないサブネット内のインスタンス(ElasticIPでグローバルIPは持つ)でも起きていた。
また、サブネットを跨いで起きている。
いったいどうなっているのかと。VPC単位で全てが感染した可能性すら考えられて、戦々恐々。
とはいえ、回数は1〜2回が数時間に1回と、それ程多くない。ガチでトロイに感染していたら、これが数百、数千のオーダーで発生するはずだ。

一体何が起きているのか、我々はその答えを探しにAmazon(Web Services)の奥地まで飛んだ。

###ログの中から手がかりになるものを探してみた

GuardDutyのログの最後を見ると、何れも特定のドメインへのアクセスがあった。

![Screenshot from 2021-09-10 16-18-54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293892/0e2a2be9-0b7f-7709-6443-5914aa0484f8.png)

このドメインを該当インスタンスにSSH接続して`/var/log/secure`からgrepしてみた

```
$ cat /var/log/secure |grep hitquckbulck.live
Sep  x xx:xx:xx ip-xxx-xxx-xxx-xxx sshd[16860]: reverse mapping checking getaddrinfo for hitquckbulck.live [xxx.xxx.xxx.xxx] failed - POSSIBLE BREAK-IN ATTEMPT!
```

と該当ログがあり、最初に書いた結論に至った。
GuardDutyのログを見ても、ここ数日の間、UnauthorizedAccess:EC2/SSHBruteForceが増えており、その中のfowardのドメインの1つに、トロイとして検出されるドメインが含まれていたようだ。

ドメイン名は違うが、同様の事象がこちらの記事にもあった。
下記記事と同様に、我々も該当のドメインをdigしたら、GuardDutyに検出され、問題ないとの確信に至った。
https://vamdemicsystem.black/aws/%E3%80%90aws%E3%80%91garudduty%E3%81%A7%E3%80%8Cfinding-type-trojanec2-dgadomainrequest-b%E3%80%8D%E3%81%8C%E5%87%BA%E3%81%9F
aws cliでcloudfrontのオブジェクトの無効化

## 参考

https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/Invalidation.html

（今後変わるかもしれないので参考程度に：）一ヶ月に無効化の回数が1000件超えると支払いが発生し始めるようなので注意しましょう。

## 手順

以下のコマンドで invalidationを作成できます。

```
$ aws cloudfront create-invalidation --distribution-id xxxxx --paths /past-payments/index.
html
```

このようなレスポンスが返ってきます。

```
{
    "Location": "https://cloudfront.amazonaws.com/2020-05-31/distribution/xxx/invalidation/xxxx",
    "Invalidation": {
        "Id": "xxxxx",
        "Status": "InProgress",
        "CreateTime": "2021-09-10T07:08:03.775000+00:00",
        "InvalidationBatch": {
            "Paths": {
                "Quantity": 1,
                "Items": [
                    "/past-payments/index.html"
                ]
            },
            "CallerReference": "cli-xxx-139143"
        }
    }
}
```

すべて無効化したい場合は以下を使うといいです。

```
aws cloudfront create-invalidation --distribution-id xxxxxx --paths "/*"
```
Trible R10 GNSS rtkファイルから測点と座標情報の行だけを抽出する

Trible R10 GNSS 専用のアプリを持ってないので，rtkファイルから測点と座標情報の行だけを抽出するプログラムをつくりました．
以下は，Pycharmのjupyter notebookから持ってきたので，ちょっとおかしな記載がありますが，pyファイルで保存すれば，pythonで動くと思います．

```python
#%% md

# trimble用

#when calculate again, you need
#if you want


#define working directroy
%cd C:\GNSS\data\vrs

#%% md

# まずは，入力ファイルを設定します.

#%%

# inp_file="2021-07-05_10.nmea"
# inp_file="VRS直_2021-07-05-12-48-07.rtk"
inp_file="VRS直_2021-09-10-15-37-24.rtk"

#%% md
# ひとまず，上のところ（ファイルが入っているディレクリトリとファイル名）を入力すれば，
# あとは全実行で進みます（抽出したテキストファイルが出力される．）．

#%%
import pandas as pd
import numpy as np
import csv
#%%

#if you want
#check current directory
%pwd

#%%

#check files
%ls


#%% md

# base_nameを取得しておきます．
# 出力ファイル名を自動で作成するため

#%%

type(inp_file)
base_name=inp_file.split('.',1)[0]
base_name
# inp_file="VRS直_2021-07-05-12-48-07_get.rtk"

#%%

# make output filename from input file automatically

# out_file="2021-07-05_10_GNRMC_out_test.csv"
# out_file="VRS直_2021-07-05-12-48-07_get.rtk"
out_file=base_name+"_get.rtk"
out_file
# out_file="VRS直_2021-07-05-12-48-07_get.rtk"

#%% md

# encodeを指定します．
## nmeaはUTF-8か
## trimbleはshift_jisか


#%%

# enc_sty="UTF-8"
enc_sty="shift_jis"

#%%

# with open("2021-07-05_10.nmea", "r", encoding="UTF-8", errors="", newline="" ) as f:
# with open(inp_file, "r", encoding="UTF-8", errors="", newline="" ) as f:
with open(inp_file, "r", encoding=enc_sty, errors="", newline="" ) as f:
    lst = csv.reader(f, delimiter=",")
    df = pd.DataFrame(lst).rename(columns={0:'ID'})
    # df = pd.DataFrame(lst)

#%%

# df.query('cols in ["GG1","GG2"]')
df.query('ID in ["GG1","GG2"]').to_csv(out_file,header=False, index=False)
# df[df[0].str.contains(id)].to_csv(out_file,header=False, index=False)

#%%
df.query('ID in ["GG1","GG2"]')


# !!!!FIN


```
[WIP]【社内向け】curlコマンドの作り方 初級編

### curlコマンドとは
client for URL の略で、 
様々なプロトコル（通信手順）を用いてURLで示されるネットワーク上の場所との間でデータの送受信を行うものです。

一番短い例で言えば
`curl http://localhost:8080/` 
コマンドプロンプト上で、 `http://localhost:8080/` の内容を取得して表示しています。
この際、APIの実装が以下であれば、

```kotlin
// serverは kotlin で実装。
// routing はURLを決める親となるもの
routing {
    // ローカルで動かす際は http://localhost:8080 までが親で、
    // URL の後ろに付く文字列が / と言うことになる
    route("/") {
        // httpメソッドの指定。同じURLでもhttpメソッド毎に別々に扱える
        get {
            // プレーンテキストで HELLO WORLD! と表示する
            call.respondText("HELLO WORLD!", contentType = ContentType.Text.Plain)
        }
    }
}
```

```
% curl http://localhost:8080/               
HELLO WORLD!
```
のように、 `HELLO WORLD!` の文字列が返されます。

さて、ではcurlコマンドの内容を見ていきましょう。
基本的な構成は `curl [options] [URL]` のようになっていて、
一切 `options` を付与しないのが上の状態。

そして今回のTODOアプリで使用するのは以下の4通り

*TODO一覧取得API*

```
curl -X GET http://localhost:8080/todos
```

*TODO登録API*

```
curl -X POST http://localhost:8080/todos \
-H "Content-Type: application/json" \
-d '{ "title": "タイトル", "detail": "内容", "date": "2022-12-21" }'
```

*TODO更新API*

```
curl -X PUT http://localhost:8080/todos/1 \
-H "Content-Type: application/json" \
-d '{ "title": "更新後のタイトル", "detail": "更新後の内容", "date": "2023-12-12" }'
```

*TODO削除API*

```
curl -X DELETE http://localhost:8080/todos/1
```

#### URL に関して

##### `http://localhost:8080` 
ローカルで起動させているとこのようになります。 `8080` はポート番号です。
一般的なURLで言うと `https://qiita.com` のような箇所ですね。

##### `/todos`
例で `route("/")` と書いていた箇所が `route("/todos")` と言う指定になっています。
TODOに関するAPIなのでこのような指定となり、ユーザーに関するAPIであれば `/users` などが一般的でしょう。

##### `/1`
`PUT` や `DELETE` にのみ存在するこの値ですが、 API仕様書で言う `/:id` のことです。
更新・削除対象となる TODO の ID番号 を入れています。
APIの内部処理として、該当IDのレコードをDBから取得しますが、
そのレコードに対して操作することを示しています。

#### options に関して

##### `-X`
これはHTTPメソッドの指定。
代表的なものが今回使用している GET/POST/PUT/DELETE 辺りです。
API仕様書にある通りのものを付与してあげましょう。
なお、特に付与しない場合のデフォルト値は `GET` になります。

##### `-H` 
これはヘッダーですね。リクエストの中身には ヘッダー と ボディ が存在します。
リクエストヘッダー や HTTPヘッダー などで検索すれば詳細内容はわかるかと思います。
今回必要なのは Content-Type で、リクエストボディ の内容がどのような形式で送られてくるのかを明記しています。
API仕様書に書いてある通り JSON形式なので、 `application/json` です。
参考 HTTPヘッダ一覧: http://www.cresc.co.jp/tech/java/Servlet_Tutorial/Att_03.htm

##### `-d` 
こちらは先ほども名前が出ましたが、リクエストボディの中身です。 
主に POST や PUT で、serverに送りたいデータを書いていきます。
こちらも仕様書に沿った内容ですが、ヘッダーで指定したようにjson形式で書きましょう。
見やすく改行すると以下のようになります

```json
{ 
  "title": "タイトル",
  "detail": "内容",
  "date": "2021-12-12" 
}
```


まずはここまで。
今後追記・修正していきます。
.NETCoreでアクション別のバージョン管理

# アクション別のバージョン管理

「[Microsoft.AspNetCore.Mvc.Versioning](https://www.nuget.org/packages/Microsoft.AspNetCore.Mvc.Versioning/)」を使用したバージョン管理方法

- [参考](https://dotnetcoretutorials.com/2017/01/17/api-versioning-asp-net-core/)

## 手順

1. バージョン管理を行いたいプロジェクトに Microsoft.AspNetCore.Mvc.Versioning を追加
> Install-Package Microsoft.AspNetCore.Mvc.Versioning

2. Startup.cs の ConfigureServices()に以下を追加

```C#:Startup.cs
public void ConfigureServices(IServiceCollection services)
{
  // ApiVersioningを追加
  services.AddApiVersioning(options =>
  {
      // クライアントにApiバージョンを通知
      options.ReportApiVersions = true;
      // これがないとクライアント側でエラーが出る
      options.AssumeDefaultVersionWhenUnspecified = true;
      // Apiのデフォルトバージョンを1.0に設定
      options.DefaultApiVersion = new ApiVersion(1, 0);
  });

  services.AddControllers();
}
```

3.Controllerの名前空間及び関数に属性を追加

```C#:HomeController.cs
// サポートしているバージョンを追加
[ApiVersion("1.0")]
[ApiVersion("2.0")]
[Route("v{version:apiVersion}/[controller]")]
public class HomeController : Controller
{
  [HttpGet]
  public string Get() => "v1";

  // Apiバージョンを上書き
  [HttpGet, MapToApiVersion("2.0")]
  public string GetV2() => "v2";
}
```

- /v1/Home
  - **v1**が表示
- /v2/Home
  - **v2**が表示
ubuntu20.04 (amd64)のMPLAB X IDEでmpasmを使う

2021年時点、最新版では、昔から使えていたmpasmが使えなくなって、代わりに入ったアセンブラには互換性が無い。
アセンブラ移行のドキュメントは有るが、時間も無いし、簡単に行かなそうなので、Archiveから5.35を取り出してインストールした際のメモ。

MPLABX-v5.35-linux-installer.sh は、64bitライブラリと32bitライブラリを両方要求するようである。
64bitの方は、普通にデスクトップ使っていればそのまま行けると思う。

32bitライブラリは入ってないので、チェックで引っかかる。
以下、32bitライブラリを入れた手順。

```
 sudo bash
 dpkg --add-architecture i386
 apt update
 apt install libstdc6:i386
 apt install libstdc++6:i386
 apt install libxpat1:i386
 apt install libexpat1:i386
 apt install libx11-6:i386
 apt install libxext6:i386
```

私の手元のubuntuはこれでMPLAB X 5.35がインストールできたが、環境によっては違うかもしれないので、参考まで。
jupyter notebookクラシングの解決策

jupyter　notebookを大容量なデータをprintしパナしすると、メモリオーバになって、Webページがクラッシュする問題について

IOPub data rate exceeded.
    The notebook server will temporarily stop sending output
    to the client in order to avoid crashing it.
    To change this limit, set the config variable
    `--NotebookApp.iopub_data_rate_limit`.

解決策１　
jupyter notebook --NotebookApp.iopub_data_rate_limit=1e10

jupyter-lab --NotebookApp.iopub_data_rate_limit=1e10

解決策２
vi /root/.jupyter/jupyter_notebook_config.py　を開いて、以下の設定を変更
c.NotebookApp.iopub_data_rate_limit = 100000000


＊＊一番重要なポイント
大きいサイズの行列をprintしパナっしないこと
プログラミングでスプレッドシート編集するためのGCP側の設定

プログラミングでgoogleのスプレッドシートやGoogleドライブなどを編集する為の設定。
Google Cloud Platform(以下、GCP)側の設定手順です。

## プロジェクト作成
[ここからプロジェクト作成](https://console.developers.google.com/)
![67ee6f34ab55325f271730f0e92e5844.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399745/f325f1ed-4649-8768-75a8-86b4c0d7ba48.png)
![76b2d924965d60b259f6e7047be202db.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399745/a9988005-2c92-7e8e-ece5-0fc0c2afb584.png)
ハイフンのみOK
![f487655e22a17545c3be366507f5861a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399745/259f09b5-ab22-8fe2-aefd-8fca06d664af.png)

作成ボタン押下。

## ライブラリ追加

![784ddf18ae916ce238e08f8bdd24cb76.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399745/8cc4d279-3f04-ebd0-c72e-caa503424ed5.png)

**drive**で検索
![37b0dbceee696cc6182b49ec730e4b84.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399745/c3c8a433-9ece-c989-de8e-1dd64ccc26fe.png)
有効にする。
次に**sheet**で検索
![95fb9808f17379d3db62bbd79576e9cc.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399745/7986ca3a-4415-8fb5-608d-86bab1b087fd.png)
有効にする。

## 認証情報作成

![121a8b56e575dc67da21985137d5e38c.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399745/4187d6a6-c99d-76db-5a1f-194e37f2c353.png)
プロジェクトの名前と同じでもよい。
![f48e428741d69910960aecef61217bc0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399745/5de6eb8d-cd10-d14e-2f27-64501b06669c.png)
作成ボタン押下。
![610afc02589ecd9c59a88afc357a0fdc.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399745/cf280a62-01b5-0613-0d79-2ed134dd04dd.png)
↑の通りに選択して完了ボタン押下。

## 秘密鍵作成

![e75b1b1168bf893036c1a0580767b8d4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399745/071626d5-4a9f-9a08-720a-49de5a7a061a.png)


jsonを選択して、jsonファイルをダウンロードする。

**ダウンロードしたjsonファイルをpythonのプロジェクトフォルダー直下に置く**

### このjsonファイルはGithubには上げないように必ず除外しておきましょう！

## 終わり

GCP側の設定は終わり。
[Rails]本番環境(CentOS)でエラーログを見る方法

#はじめに
CentOS上でrailsアプリを動かした際、エラーログの確認方法をまとめた。
#環境
CentOS7
rails 6.1.4
capistrano 3.16.0
puma 4.3.8

#本番エラーログ確認方法
```
#logディレクトリへ移動
$ cd /var/www/html/<アプリ名>/current/log
```
```
#lsコマンド入力
$ ls
capistrano.log  production.log  puma_access.log  puma_error.log
```
①capistrano.log → capistrano実行時のログやエラーログ
②production.log → アプリ実行時のログやエラーログ
③puma_access.log → pumaを起動した際のログ
④puma_error.log → puma実行時のエラーログ

```
#production.logの最新ログ２０行分出力
$ tail -n 20 /var/www/html/<アプリ名>/current/log/production.log
```

#まとめ
何かエラーが発生した場合は、まずはproduction.logを確認する。


#参照
https://qiita.com/nkekisasa222/items/d4ef64a5e6b539ed3c37

https://qiita.com/sobameshi0901/items/b963e7046e2ae8b8e813
'name' は非推奨です。ts(6385)

某UdemyでJavaScriptの講座を見ていて、初歩的コードをVSCodeで入力していた。

```
let name = 'Tim';
function hello(name){
  console.log('HELLO' + name);
}

hello(name);
```
☝エディタの画面上では、最後のhello()の引数に取り消し線が表示されている。そして下のような注意書きが表示された。

```
'name' は非推奨です。ts(6385)
lib.dom.d.ts(18305, 5): この宣言はここで非推奨とマークされました。
const name: void
@deprecated
利用できるクイックフィックスはありません
```

動作自体は問題ないが非推奨だと怒られている。
JavaScriptについて、仕事で使っているのに体系的な知識がない私は、なんです……？これ…と同じ言葉で検索をかけた。下記の英語サイトと同じ現象の模様。
https://www.reddit.com/r/vscode/comments/ltonp7/name_is_deprecated_ts6385/

windowオブジェクトにすでにある変数nameをグローバルスコープで新たに定義しているので怒られているらしい。
回避方法としてはnameのスコープを限定するかnameをもっと固有の名称に変更するか、TypeScriptで記述する、など。

実務ではまず起きない現象だが気になったのでメモ。
Rでクリップボードからペースト・クリップボードにコピー

OSによって違って意外と面倒だったりする。
下にある「もっと簡単に」の方がオススメ

# ペースト
たとえばExcelでタイトル付きの表を作ってRに入れたい場合

```R:Windowsの場合
x <- read.table("clipboard", header = T, sep = "\t")
```

```R:Macの場合
x <- read.table(pipe("pbpaste")), header = T, sep = "\t")
```


# コピー
たとえば何かの表や変数をクリップボードに出したい場合
Macでやる方法はわからない

```R:Windowsの場合
x <- write.table(y, "clipboard")
```


# もっと簡単に
`clipr`パッケージを使う

```R:OS問わず
library(clipr)
# Paste from clipboard
x <- read_clip_tbl(header = T)
# 表でない場合はread_clip()もある

# Copy to clipboard
write_clip(y)
```

なんと簡単
Github Actions(CI)でjest使ったらno such file or directory package.jsonエラーが出た

jestでテストコードを書いて、githubにプッシュした時にテストが実行されるようにしたかったのですが、備忘録として書いておきます
#何が起きたか
ディレクトリはこんな感じです

```yml:ディレクトリ構成
root/
├── github/workfrow/next.yml
├── app
│   ├── package.json
│   └── tests(ここの中身の関数をテスト)
```

next.ymlの記述はこうです

```yml:next.yml
name: jest

on: [push]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v1
    - name: Setup Node.js
      uses: actions/setup-node@v1
      with:
        node-version: '11.12.x'
    - name: yarn install
      run: yarn install --ignore-engines
    - name: Run jest test
      run: npm test
```
このままテストをしてしまうと問題が発生しました。
yarn installにて、
>no such file or directory package.json

とエラーが出て止まってしまいました。
エラー文から察するに、「package.jsonなんてどこにもないよ」ということみたいです。
なので、カレントディレクトリがrootディレクトリ上にあるから、appに移動する必要があるという仮説を立てました。
#やったこと
next.ymlにworking-directoryを追加し、カレントディレクトリを指定しました。

```yml:next.yml
name: jest

on: [push]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v1
    - name: Setup Node.js
      uses: actions/setup-node@v1
      with:
        node-version: '11.12.x'
    - name: yarn install
      run: yarn install --ignore-engines
    - name: Run jest test
      run: npm test
```
これでエラーが出ることなくテストが通りました！
【コピペ】Railsで選択肢を追加していく方法

#Ruby on Railsで選択肢を追加していく方法

実装後参考サイト　https://vlogmatome.herokuapp.com/posts/new

##目次
###1.コントローラーを準備する
###2.モデル・データベース周り
###3.viewのコード
###4.ルートをかく

##実装
###1.コントローラーを準備する
まずはコントローラーを準備します。
今回はブランドを投稿していくWebサイトを作成します。
ブランドの選択肢を投稿ごとに追加していきます。

ブランドの投稿はpostsコントローラー。選択肢の追加はbrandsコントローラーで行っていくこととします。
それでは早速コードを書いてみましょう。

```ruby:posts_controller.rb
class PostsController < ApplicationController
  def index
    @posts = Post.all
    @brands = Brand.all
    @brand = Brand.where(brand:"")
  end

  def new
    @post = Post.new
    @brand = Brand.new
  end

  def create
    post = Post.new(post_params)

    if post.save
      redirect_to :action => "index"
    else
      redirect_to :action => "new"
    end
  end

  private
  def post_params
    params.require(:post).permit(:brand, :brand_id)
  end
end
```

```ruby:brands_controller.rb
class BrandsController < ApplicationController
  def index
    @brands = Brand.all
  end

  def create
    brand = Brand.new(brand_params)
    if brand.save
        redirect_to action: "index"
    else
        redirect_to action: "new"
    end
  end

  private
  def brand_params
    params.require(:brand).permit(:brand, :brand)
  end
end
```

###2.モデル・データベース周り
まずはpostsテーブルにinteger型でbrandというカラムとbrand_idというカラムを作成します。
次にbrandsテーブルにstring型でbrandをいうカラムを作成してください。
準備ができてらそれぞれのモデルに以下のコードを書いてみましょう。
モデルの関連づけを行います。

```ruby:posr.rb
class Post < ApplicationRecord
    belongs_to :brand
end
```

```ruby:brand.rb
class Brand < ApplicationRecord
    has_many :posts
end
```

###3.viewのコード
続いてはveiwページです。

```ruby:posts/index.html.erb
<div class="posts-container">
  <% @posts.each do |t| %>
    <br>
    <% t.brand %>
  <% end %>

  <h2>Brand別一覧</h2>  
      <% @size = @brands.length - 1 %>
      <% for b in 0..@size do %>
        <%= @brands[b].brand %>

        <% @brands[b].posts.compact.each do |t| %>
         <% t.brand %>
        <% end %>
      <% end %>
</div>
```

```ruby:posts/new.html.erb
<%= form_for @brand do |brand| %>
    <div class="field">
      <%= brand.label :brand %>
      <%= brand.text_field :brand, :size => 10 %>
    </div>
    <%= brand.submit "追加する" %>
<% end %>

<%= form_for @post do |f| %>
    
    <div class="field">
      <%= f.label :brand %>
      <%= f.collection_select(:brand_id, Brand.all, :id, :brand) %>
    </div>

    <%= f.submit "投稿する" %>
<% end %>
```

###4.ルートをかく
最後にルートを書いていきます。

```ruby:routes.rb
Rails.application.routes.draw do
  resources :posts
  resources :brands
end
```

以上です！
Reactメモ　ルーティングの設定　＊個人メモ用

Reactの勉強をしている私の個人メモなので、 
記事としてはわかりづらくなっています。 
FBは歓迎しておりますが、温かい目で見守って頂けると幸いです。  

#react-routerとreact-router-domの違い
とりあえずreact-router-domを使えばOK

#基本的な遷移
```sample.jsx
import { BrowserRouter, Link, Switch, Route } from "react-router-dom";

    <BrowserRouter>
      <div className="App">
        <Link to="/">HOME</Link>
      </div>
      <Switch>
        <Route exact path="/">
          <Home />
        </Route>
      </Switch>
    </BrowserRouter>
```

①全てをBrowserRouterで囲む
②Linkで遷移させるためのボタンやlinkを作る
③遷移先をSwitchで囲む
④RouteのpathにLinkのパスを指定
⑤Routeで指定したパスに合う遷移先を囲む
⑥遷移先の元にはexactを指定

#ネストされた遷移先
```sample.jsx
        <Route
          path="/"
          render={({ match: { url } }) => (
            <Switch>
              <Route exact path={url}>
                <Home />
              </Route>
              <Route path={`${url}/sample1`}>
                <HomeSample1 />
              </Route>
              <Route path={`${url}/sample2`}>
                <HomeSample2 />
              </Route>
            </Switch>
          )}
        ></Route>
```

①1つのRouteの中でrenderを行う
②render内で同じことを行う
③確実にネストされた場所を指定するため
renderは関数を受け取りデフォルトの引数でpropsを持っているので
その中のmatchの中のurlを引数に指定

以上
AWSLambdaのようなFaaS「PyFuncApi」を作った話

# なぜ作ったのか
下記記事を書いていて、保存機能さえあれば
AWSLambdaやAzureFunctionsのようなFaaS(Function as a Service)と
同じようなものが出来そうだと思ったからです

https://qiita.com/HawkClaws/items/159b2630ed5fdf2107c4


# 技術スタック
- 言語
python

- フレームワーク
django

- データベース
Firebase RealtimeDatabase

# コード
https://github.com/HawkClaws/PyFuncApi/tree/master

# 使い方

#### コードを登録

Bodyにコード（Python）を書いて、下記URLにPOSTします
同URLのGETで登録した値を取得できます

実行してからの登録になるので
構文エラーが無ければ登録できます

また、上書きされないように現状UPDATEは実装していません
/v1 など付けてバージョンを管理したほうが良いかもしれません

※こういうのが出来ますよ！という紹介なので
機密なコードやパスワードなどは入力しないでくださいね！

`https://pyfuncapi.herokuapp.com/admin/api/{一意のURL}`

「exec_input」変数が外部からの値入力
「exec_result」変数がWebApi実行時の戻り値
となります

例：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/911989/d9a9d9ea-8ef7-27ce-78d9-a750271fc03e.png)


#### WebApiを実行

`https://pyfuncapi.herokuapp.com/api/exec/{登録したURL}`

bodyに入力した値がexec_inputに入ります
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/911989/43ee6542-64c2-2bb1-a14e-6b61fc8fb2ef.png)


# サンプルコード/サンプルAPI

####フィボナッチ数列かどうかを判定するWebApi
bodyに数値を入力してPOSTします
`https://pyfuncapi.herokuapp.com/api/exec/is-fibonacci`

コード

``` python:is-fibonacci.py
def fib(n):
    if n > 1:
        return fib(n-1) + fib(n-2)
    return n

def main(exec_input):
    if exec_input == '':
        return
    num = int(exec_input)
    i = 0
    while True:
        i +=1
        fib_num = fib(i)
        if fib_num == num:
            return True
        if fib_num > num:
            return False


exec_result = main(exec_input)
```

 * * *  

####人口動態調査 / 人口動態統計 月報（概数）WebApi
政府が公開しているオープンデータ（CSVファイル）をjsonに変換して返すWebApiです
`https://pyfuncapi.herokuapp.com/api/exec/vital-statistics-survey-monthly`

コード

``` python:monthly-traffic-accident.py
import csv
import json
import requests
import numpy

# https://www.e-stat.go.jp/stat-search/files?page=1&layout=dataset&toukei=00450011&cycle=1&stat_infid=000032115375&file_type=1&metadata=1&data=1
# 人口動態調査 / 人口動態統計 月報（概数）
# 

def main():
    datas = requests.get(
        "https://www.e-stat.go.jp/stat-search/file-download?statInfId=000032115375&fileKind=1")
    datas.encoding = "shift-jis"

    text = ""
    for line in numpy.array([s.split(',') for s in datas.text.splitlines()]).T:
        text += ",".join(line) + "\n"

    rows = []
    lines = text.splitlines()
    reader = csv.DictReader(lines[1:len(lines)], delimiter=',')
    for row in reader:
        rows.append(row)

    return ''.join(json.dumps(rows, ensure_ascii=False).split())

exec_result = main()

```

# この記事を書いていて思ったこと
Knativeという超強いものがあったのを知りました・・・。

# 課題
セキュリティーがガバガバです
URLさえ知っていればコードが取得できてしまいます
（認証作れば良いんでしょうけど、今回はそこまで作り込みません・・・。）

あと、HeaderやステータスコードなどResponse自体を戻り値設定できるようにしたほうが良いなぁと思いつつ
レスポンスの値を作るのがめんどくさくなるのでBodyのみ指定できるようにしてあります
SageMaker同じロールを被る場合CloudTrailにインスタンス名を残す方法

タイトルの件はAWSオフィシャルQAには記載されています。

#解決案

[すべてのインスタンスが同じ IAM ロールを使用する場合、どの SageMaker ノートブックインスタンスが特定の API 呼び出しを行ったかを判断するにはどうすればよいですか?](https://aws.amazon.com/jp/premiumsupport/knowledge-center/sagemaker-instance-api-iam/)

#注意点

上記の記事は解決案になっていますが、幾つの注意点があります。
１、コピペーは`#!/bin/bash`から始めてください。
２、改行コードはCRLFからLFに変換してください。
３、インスタンスはPrivateSubnetにいる場合、STSのVPCエンドポイントを設定すること。
４、デフォールトJupyterユーザーは`sudo`権限を持っているためスクリプトの改ざんは可能。

##４番の補足
SageMakerでノートブックインスタンスを作成するときに「ルートアクセスー無効化」を設定しすれば改ざんできなくなりますが、コンソールで`yum`コマンドは使えなくなります。システムにライブラリをインストールできないけれど、`pip`は正常に使えます。
Rails6でajaxを使う jQuery3.0

rails6のバージョンだとうまく動かなかったので。
元記事
https://qiita.com/moriwm77/items/ea54c0f34da073801bf1

バージョン
ruby-2.7.4
Rails 6.1.4.1
jquery 3.6.0


とりあえずscaffoldを導入

scaffoldについて
https://qiita.com/tsubasaozawa/items/98f3e64a450d4304fc84

文章を投稿するのでカラムにtitleを使います。

```
rails g scaffold task title:string
rails db:create # データベース作成
rails db:migrate # マイグレーション実行
```

```
yarn add jquery
```
ここからは下記ページのJqueryの設定を行います

https://ymiyashitablog.com/rails-jquery/


config/webpack/environment.js

下記コードをコピペして`config/webpack/environment.js`に貼り付ける

```
const webpack = require('webpack')
environment.plugins.prepend('Provide',
  new webpack.ProvidePlugin({
    $: 'jquery/src/jquery',
    jQuery: 'jquery/src/jquery'
  })
)
```



下記のように貼る


```
const { environment } = require('@rails/webpacker')
//ここから
const webpack = require('webpack')
environment.plugins.prepend('Provide',
  new webpack.ProvidePlugin({
    $: 'jquery/src/jquery',
    jQuery: 'jquery/src/jquery'
  })
)
//ここまで
module.exports = environment
```

次に

`app/javascript/packs/application.js`


ここへ下記コードを追加する
```
require("jquery")
```

あとは

`app/javascript`直下にjsファイルを作成すればOKです




※
tasks.jsで
`$(document).ready(function() {`とあるが
ここは下記に変更する

```
$(function() {
```


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987832/450dd65a-114b-a2b7-c9b6-894f248bdebb.png)
Vue.js 値の変更がビューに検知されない問題

Vue.jsでの実務が多くなってきて、ビュー側が変更されない問題が多すぎたので、解消方法一旦まとめました。

公式ドキュメントにもVue２で検知されない変更のパターンはまとめられています
参考リンク → [Vue 2 での変更検出の注意事項](https://v3.ja.vuejs.org/guide/change-detection.html#%E3%83%AA%E3%82%A2%E3%82%AF%E3%83%86%E3%82%A3%E3%83%95%E3%82%99%E3%83%95%E3%82%9A%E3%83%AD%E3%83%8F%E3%82%9A%E3%83%86%E3%82%A3%E3%81%AE%E5%AE%A3%E8%A8%80)

## オブジェクトの場合
公式ドキュメント
>Vue では、すでに作成されたインスタンスに対して新しいルートレベルのリアクティブなプロパティを動的に追加することはできません。

```js
data: {
    user: {
      name: "taro",
      age: 52,
    },
},
methods: {
    changeAge: function(age){
        this.user.age = age; // これだと検知されない
    },
}
```
### 解決方法
- `Vue.set`使う

Vue.setを使用するとネストされたプロパティに対して、リアクティブな変更が可能になる

```js
methods: {
    changeAge: function(age){
        this.$set(this.user, 'age', age);
    },
}
```

- `Object.assign()`でオブジェクトごとマージしてしまう

[MDN Web Docs](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)

> Object.assign() メソッドは、すべての列挙可能な自身のプロパティの値を、 1 つ以上のコピー元オブジェクトからコピー先オブジェクトにコピーするために使用されます。変更されたコピー先オブジェクトを返します。

```js
methods: {
    changeAge: function(age){
        const newUser = {...this.user};
        newUser.age = age;
        this.user = Object.assign({}, this.user, newUser);
    },
}
```

## 配列の場合
公式ドキュメント

> Vue は、配列における次の変更は検知できません:
1. インデックスと一緒にアイテムを直接セットする場合、例えば vm.items[indexOfItem] = newValue
2. 配列の長さを変更する場合、例えば vm.items.length = newLength

```js
data: {
    numbers: [1, 2, 3, 4, 5],
},
methods: {
    changeNumbers: function(number, index){
        this.numbers[index] = number; // これだと検知されない
    },
}
```

### 解決方法

- 要素を追加する場合
  - オブジェクトに関しては、`Vue.set`で変更しましたが、追加する要素を追加する場合は通常通り、`push`で良いらしいです

         破壊的メソッド↓であれば、Vueが監視してくれます
         
         >sort()
         splice()
         push()
         shift() 
         unshift()
         reverse() 

```js
methods: {
    changeNumbers: function(number){
        this.numbers.push(number);
    },
}
```

- 要素の値を置き換える場合
  - `splice`使って置き換えてあげるとリアクティブな変更になります。

    >splice(変更したいindex, 変更する要素数, 変更後の要素)；

```js
methods: {
    changeNumbers: function(number){
        this.numbers.splice(index, 1, number);
    },
}
```

## まとめ
オブジェクト・配列のリアクティブな変更の加え方をまとめてみました
この辺の問題もVue3では解決されているらしいので、あまり需要な情報だったかもしれないですね、、
lambdaでレイヤーを使用し、アップロードしたファイルのコードを表示させてみた。

ローカルで作成したファイルを、lambdaにアップロードした際に「Lambda 関数「layer-test」のデプロイパッケージが大きすぎて、インラインコード編集を有効にできません。ただし、関数を呼び出すことはできます。」
と表示されたのでレイヤーを活用して表示させました。

初めての作成に時間がかかってしまったので、手順を詳しく説明して行きたいと思います。
![スクリーンショット 2021-09-10 13.55.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1129553/e1d501c0-b3a0-077c-76a9-e4ea31496205.png)
レイヤーを使用せずにzipファイルをアップロードした時、このようにコードが表示されずlambda内で作業ができませんでした。

パッケージングした元のファイル構造はこのようになっています。

```
file
 |
 |-node_modules
 |-index.js
 |-package-lock.json
 |-package.json
```

このファイルのままではコードは表示されないままなので、まず、コードの表示に向けて二つのファイルに分けました。
lambdaで表示させたいjsファイルと、あまり動かさないnode_modulesやjsonファイルで分けます。

```
lambdaファイル
file
 |
 |-index.js
```
zip -r function.zip .　でパッケージングします。

```
レイヤーファイル
nodejs
 |
 |-node_modules
 |-package-lock.json
 |-package.json
```
desktop % zip -r function.zip nodejs でパッケージングします。


まず、fileをlambda関数にアップロード
![スクリーンショット 2021-09-10 14.15.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1129553/a62c0364-d070-55ec-8390-9d745e0fd0ee.png)

次はレイヤーを作成します。
その他のリソースのレイヤーを押します。
![スクリーンショット 2021-09-10 14.16.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1129553/df98e94b-e82a-d0ec-763c-4bc096c18e6f.png)
レイヤーの作成
![スクリーンショット 2021-09-10 14.17.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1129553/cf70c330-e306-4b4b-0dde-8e224b016a23.png)
名前の入力と.zipファイルのアップロード
![スクリーンショット 2021-09-10 14.17.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1129553/fc9ac693-feab-15f9-a95f-d5d8642b3652.png)
このように表示されると作成されています。
バージョンARNをメモしておいてください。
![スクリーンショット 2021-09-10 14.19.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1129553/173b530b-3f77-c213-788e-c2e970697f9d.png)


次に作成したレイヤーを関数に追加していきます。
追加するlambda関数のページに行き、一番下までスクロールします。
![スクリーンショット 2021-09-10 14.20.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1129553/6f63dcf4-6e92-c5e4-16bb-cd3db32526dc.png)
レイヤーの追加を押します。
先ほどメモしたARNを指定に記入し追加ボタンを押すと追加されます。
![スクリーンショット 2021-09-10 14.20.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1129553/b4c5a107-6bdf-3af9-b203-737916f0a673.png)
![スクリーンショット 2021-09-10 14.57.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1129553/cd60e43a-a66b-550e-6e7b-ea6eed475ca5.png)
このようにレイヤーが追加できていたら完成です。

もし、レイヤーに変更があれば、レイヤーのバージョンの作成で新しいzipファイルをアップロードしてください、また、レイヤーの追加ボタンの横にある編集ボタンでバージョンのみを編集すると変更後のレイヤーで動かせます。

最後までご高覧いただきましてありがとうございました。
Tweet Web IntentでAndroidから投稿画面を呼び出す

アプリから簡単にTwitterに投稿できる方法はないかなーと？とググってあったのでメモついでに。
参照したサイトはこちら
[イクログ - [Twitter] Tweet Web Intentを使ったツイートボタンの作り方・パラメータ一覧](https://blog.ikunaga.net/entry/twitter-com-intent-tweet/)

知ってる人にはなんてことない方法ですが、やることは簡単で、URLのインテントを作って呼び出すだけ。
URLでできることなので、Androidじゃなくても、いろいろなところで使えますね。

```kotlin
val uri: Uri = Uri.parse("https://twitter.com/intent/tweet?text=hello world%0D%0A&hashtags=test")
val intent = Intent(Intent.ACTION_VIEW, uri)
if (intent.resolveActivity(packageManager) != null) {
    startActivity(intent)
}
```

ちなみに、Twitterのアプリが入っていると、Twitterのアプリの投稿画面が出てきます。

試してないけど、画像なんかを添付したい場合は、どこかにアップロードして、画像のURLをtextかurlに指定すればイケるんじゃないかと思います。
【JavaScript】ホイスティング（巻き上げ）について

# はじめに
アウトプットが苦手な自分が練習の一環として記事を書いてみる。

第六回目です。

今回はJavaScript独特の挙動であるホイスティング（巻き上げ）について書いていきます。

# ホイスティング（巻き上げ）とは？
ホイスティングとは **変数や関数の宣言は常にコードの先頭で行われたことにする** という挙動のことです。

以下を例に見ていきます。

```javascript
function a() {
    console.log('aが実行されました')
}
a();

// 実行結果
aが実行されました
```
上記は「関数を定義」しその後「関数の実行」を行っているので結果は`aが実行されました`が出力されました。
ここまでは問題ないと思います。

では次は「関数を定義」と「関数の実行」の順番を入れ替えるとどうなるでしょうか。

```javascript
a();
function a() {
    console.log('aが実行されました')
}

// 実行結果
aが実行されました
```

結果は順番を入れ替えても`aが実行されました`が出力されました。

プログラムは基本的に上から順に処理が行われるためエラーになりそうですが、問題なく動作しています。

これがホイスティングによる**変数や関数の宣言は常にコードの先頭で行われたことにする**挙動です。

# 変数を使ったホイスティング
ホイスティングにはもう一つ特徴があります。
それは**定義のみが巻き上げられ、初期化は巻き上げられない**というものです。

次の例を見ていきます。

```javascript
function a() {
    console.log(x);
    var x = 0;
}
a();

// 実行結果
undefined
```
一見「0」が出力されそうですが、結果は`undefined`となりました。
これは宣言のみが巻き上げられ、コンソールログ出力時の段階では初期化が行われないため結果「undefined」が出力されました。

以下のように初期化処理の後にコンソールログを出力をすることで「0」が出力されます。

```javascript
function a() {
    console.log(x); // undefined
    var x = 0;
    console.log(x); // 0
}
a();
```

# よくありそうなミス
最後にグローバル変数を出力しようとしたが、意図せずブロックスコープ内に同名の変数を宣言してしまった場合、以下のようになります。

```javascript
var x = 0;
function a() {
    console.log(x);
    var x = 10;
}
a();

// 実行結果
undefined
```
結果は`undefined`になりました。
これはブロックスコープ内の宣言が巻き上げられたことで参照する変数がブロックスコープ内の変数「x」となってしまいました。
そして「x」は初期化されていないため、0を出力するつもりが結果undefinedが出力されてしまったのです。

# まとめ
以上になります。

ホイスティングはJavaScript特有の挙動なので意識していないと予期せぬ挙動になってしまいます。
対策としては変数の宣言はなるべく先頭に行うのが良いと思います。

参考になれば幸いです。

参考サイト
https://developer.mozilla.org/ja/docs/Glossary/Hoisting
【勉強記録】Pythonのif文で「あなたへのオススメ」を表示する

##目次
- 概要
- 成果
- 作成したコード
- 振り返り

2021/9/10:
コメント欄にてリファクタリングの例示を2件も頂いております。
ぜひご覧ください。

## 概要
本記事はPython学習のアウトプットです。
GitHubでリポジトリを作るほどのものでもなかったのでこちらをお借りして記録に残そうと思います。
質問に対してYesかNoで答えていき、「あなたへのオススメを表示する」という簡単なプログラムを組んでみました。
題材はミュージカルですが、作品名は記載しておりません。


## 成果
![if文1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1518966/34ccac47-4674-f1d5-ca7c-ab4d3c398c9e.gif)

## 作成したコード
同じ形式が続きます

```if.py
musical1 = "snow"
musical2 = "ramp"
musical3 = "king"
musical4 = "opera"
musical5 = "robot"
musical6 = "friends"
musical7 = "tree"
recommend_word = "オススメは…… "
my_name = "my_name"
print("オススメのミュージカルを紹介します。質問にyかnでお答えください。")
answer = input("初めての観劇だ y/n")
if answer == "y":
    answer = input("ディズニーと聞いたらヨダレが出る y/n")
    if answer == "y":
        answer = input("流行りにはのっておきたい y/n")
        if answer == "y":
            print(f"{recommend_word}{musical1}")
        else:
            answer = input("ドラマチックな人生に憧れる y/n")
            if answer == "y":
                print(f"{recommend_word}{musical2}")
            else:
                print(f"{recommend_word}{musical3}")
    else:
        answer = input("ちょっぴり怖くても大丈夫 y/n")
        if answer == "y":
            print(f"{recommend_word}{musical4}")
        else:
            answer = input(f"{my_name}のイチオシが気になる y/n")
            if answer == "y":
                print(f"{recommend_word}{musical5}")
            else:
                print(f"{recommend_word}{musical6}")
else:
# 以下省略

```

## 振り返り
※
何かアウトプットしたいなと思っていたところif文の勉強をしましたので作ってみました。
今まで保守性の高いコードを書けていなかったという自覚があるので、少しでも意識できたコードが書けていればと思います。
単純なコードではありますが、

- musical1、musical2…より良い命名
- yかn以外を入力した場合の処理の記述
- それを毎回差し込むのか
- 分岐した先が重なるような記述が書けないか

など、課題がいくつも出てきました。
追記できるものがあれば追記していきたいと思います。
図解 JWS/JWE/JWT/IDトークン/アクセストークンの包含関係

# JWS/JWE/JWT/IDトークンの包含関係

![Inclusion_Relation_JWS_JWE_JWT_IDToken.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106044/90874ea1-2363-b283-f137-44c751e3e17a.png)

- **JWS** (JSON Web Signature) と **JWE** (JSON Web Encryption) の直列化方法には、それぞれ JSON 形式とコンパクト形式がある。
- **JWT** (JSON Web Token) は JWS か JWE だが、いずれにしてもコンパクト形式である。仕様でそう決まっている。
- 仕様により、**ID トークン**には署名が必要なので、ID トークンは JWS もしくは「JWS を含む JWE」という形式をとる。
- ID トークンは「JWE を含む JWS」という形式はとらない。なぜなら、仕様により、ID トークンを暗号化する際は「署名してから暗号化」という順番と決まっているため。

# アクセストークン/JWT/IDトークンの包含関係

![Inclusion_Relation_AccessToken_JWT_IDToken.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106044/f958dd9e-2bd1-c3e9-3110-264bf2a33dd2.png)

- アクセストークンの実装が JWT だとは限らない。
- 仕様により、ID トークンは必ず JWT である。
- ID トークンを何らかのアクセス制御に用いたとしても、ID トークンのことをアクセストークンとは呼ばない。

# 参考

- [RFC 7515 JSON Web Signature (JWS)](https://www.rfc-editor.org/rfc/rfc7515.html)
- [RFC 7516 JSON Web Encryption (JWE)](https://www.rfc-editor.org/rfc/rfc7516.html)
- [RFC 7519 JSON Web Token (JWT)](https://www.rfc-editor.org/rfc/rfc7519.html)
- [OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html), [2. ID Token](https://openid.net/specs/openid-connect-core-1_0.html#IDToken)
- [IDトークンが分かれば OpenID Connect が分かる](https://qiita.com/TakahikoKawasaki/items/8f0e422c7edd2d220e06)
- [OAuth アクセストークンの実装に関する考察](https://qiita.com/TakahikoKawasaki/items/970548727761f9e02bcd)
- [Software Design 2021 年 10 月号](https://gihyo.jp/magazine/SD/archive/2021/202110)、第 2 特集『挫折しない OAuth/OpenID Connect 入門』 (執筆させていただきました)
EC2にアタッチしたIAMロールが変更できない場合の対処法

# はじめに
ある検証のために特定のEC2に対してIAMロールのつけ外しを行っていたのですが、急にIAMロールのアタッチができなくなったので、解決までの手順を書いておきます。

# 事象
元々アタッチしていたIAMロールを一旦外そうとした際、以下のようにエラーが出力されて、IAMロールのつけ外しができなくなりました。
尚、これが表示される直前に1度違うIAMロールから変更しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440403/9304ff5d-9b27-4b68-e889-8a667095948f.png)

# 調査
調べてみると以下のページを見つけました。
https://www.fixes.pub/program/207318.html

このページを見る限りだと、IAMロールを付け替えした際にEC2に紐づくインスタンスプロファイルも当然変更されますが、その関連付けが中途半端に設定された状態であることが原因のようです。

# 対応方法
参考ページの内容から
１．"aws ec2 describe-iam-instance-profile-associations"コマンドでプロファイルとインスタンスの関連付けを確認
２．インスタンスが複数のプロファイルと関連付けられている場合、"aws ec2 disassociate-iam-instance-profile --association-id [ASSOCIATION ID]"コマンドで関連付けを解除
３．EC2コンソールからIAMロールを変更
という手順で解決しそうですので、試してみます。

# 実施
以下のコマンドを実行してみると確かに関連付けが複数ありました。

```
aws ec2 describe-iam-instance-profile-associations
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440403/d184fafa-9f7b-c88c-76f3-c6511fedea8b.png)

以下のコマンドでIAMロールの関連付けを削除します。

```
aws ec2 disassociate-iam-instance-profile --association-id [ASSOCIATION ID]
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440403/b833378d-7239-0a59-07b8-495ee733523d.png)

再度関連付けを確認してみるとちゃんと解除されているようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440403/5ec411ff-7918-9f78-2ad7-ae6529afb442.png)

IAMロールを解除してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440403/9851d857-8269-b93c-e739-2dd44aaf42b4.png)

まだダメでした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440403/c33048ee-3b71-038c-d3f1-c08c166a23da.png)

同じ手順でもう一つの関連付けを解除するとデタッチができました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440403/5e37de9d-2d3e-4cad-03c5-0c6aa5c041ff.png)

恐らくですが、最初に設定したロール名がxxx_role、次に設定したロール名がxxx_s3_roleだったのですが、EC2には最初のロールが関連付けられていたのが原因だと思います。

# 最後に
無事IAMロールをデタッチできたので、この記事が同じ原因で詰まっている方の助けになれば幸いです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440403/49ee7b0a-a562-2245-ab71-5d99e499140c.png)
[Java] Long型とlong型の比較メモ

Javaで社内システムを作ってるときに、Long型の値とlong型の値を「==」で一致判定しようとしたら一致しなくて詰まったのでメモ。まだまだ未熟なエンジニアなので許してください\_m(-_-)m\_

#プリミティブ型の数値と参照型の数値をそのまま比較したいときは？
参照型のequalsメソッドを使いましょう。

```java:compare.java
   Long num1 = 1L;
   long num2 = 1l;
   if(num1==num2) { //1
       System.out.println("true");
   } else {
       System.out.println("false");
   }

   if(num1.equals(num2)) { //2
       System.out.println("true");
   } else {
       System.out.println("false");
   }
```

「1」のような比較を行うと、必ず**false**になりますが、「2」のような比較を行えば、数値が合っていれば**true**になります。


#後書き
記念すべきQiita初投稿記事でした。
プリミティブ型と参照型はスクリプト言語しかやったことない人には馴染みがない概念だと思いますが（僕も最初そうでした）、しっかり理解しておくべきことなので、Java初心者の方は頑張って理解しましょう（何様）。
僕も初心者赤ちゃんエンジニアなので頑張ります。
Gravio 4でSlackにホスト名を埋め込んだメッセージを送信する

GravioでSlackにメッセージを送信するときなどにHubKitの入っているホスト名を埋め込みたいことがある。
そういうときは環境変数を取得する関数 `Env()` をマッピングで使うとよい。

# 使用環境
**Windows HubKit**
* Windows 10 21H1
* Gravio HubKit v4.3.0-5831

**Linux HubKit**
* Raspberry Pi 4 Model B w/8GB RAM
* Ubuntu Server 20.04.2 LTS
* Gravio HubKit v4.3.0-6807

**Gravio Studio**
* Gravio Studio v4.3.4198.0

# Windowsの場合
Slackに"COMPUTERNAME"の値を埋め込んでメッセージを送信。

```
cp.Text = "このメッセージは " + Env("COMPUTERNAME") + " から送信されています"
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41603/8780a623-2afb-e68f-849f-2ea4809fc715.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41603/70df7a61-e363-1b98-307f-ea3a5ff4abd5.png)



# Linux、Gravio Hubの場合
Slackに"HOSTNAME"の値を埋め込んでメッセージを送信。

```
cp.Text = "このメッセージは " + Env("HOSTNAME") + " から送信されています"
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41603/0de4d3d1-d5b9-e298-fa79-7fc06d9b6689.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41603/ba0e2e66-22b3-4976-557f-d726315a7f14.png)
# 参考
* [Gravio][]
* [Gravio関数/環境変数][Gravio-Env]
* [Pre Mappings / Post Mappingsでの式の記述の仕方][Gravio-Mappings]

[Gravio]:https://www.gravio.com/jp
[Gravio-Env]:https://doc.gravio.com/manuals/gravio4/1/ja/topic/env-functions
[Gravio-Mappings]:https://doc.gravio.com/manuals/gravio4/1/ja/topic/premappings-postmappings