OmniAICreator/Qiita-1.07M huggingface dataset:
さくらVPSにSSH接続する方法

部品メーカで働くかたわらでプログラミングの修行をしております。
今回はLinux環境を構築するために　さくらVPSを契約してそこにssh接続する　という作業を備忘録として残しておきたいと思います。



## PC環境
- PC: MacBookAir
- Chip: M1
- OS: Bigsur 11.5.1

## サーバ
- さくらVPS（一番安いやつ）
- OS: Debian10

## 環境構築
### 1. さくらVPSにOSのインストール
さくらVPSにログインし、サーバ設定画面からOS再インストールを選択。
カスタムOSでDebian10を選択する。
![名称未設定_-_OS再インストール_-_さくらのVPS_-_コントロールパネル.png](https://bootcamp.fjord.jp/rails/active_storage/blobs/redirect/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBd1JUQWc9PSIsImV4cCI6bnVsbCwicHVyIjoiYmxvYl9pZCJ9fQ==--676b5f8bd8ea57590b4a4b76647a186f5e1b42af/%E5%90%8D%E7%A7%B0%E6%9C%AA%E8%A8%AD%E5%AE%9A_-_OS%E5%86%8D%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB_-_%E3%81%95%E3%81%8F%E3%82%89%E3%81%AEVPS_-_%E3%82%B3%E3%83%B3%E3%83%88%E3%83%AD%E3%83%BC%E3%83%AB%E3%83%8F%E3%82%9A%E3%83%8D%E3%83%AB.png)

下記参考URL通りにDebianのインストールを進める
[Debian 9 / Debian 10 \| さくらの VPS マニュアル](https://manual.sakura.ad.jp/vps/os-reinstall/custom/de9-10.html)


### 2.各種設定、アプリケーションのインストール
#### 2-1.システムの最新化
root権限で、`apt update`、`apt -y upgrade`を実施し、ファイルを最新化しとく。

#### 2-2vimインストール
`apt install vim`
.vimrcの設定も忘れずに

#### 2-3.bashrcの設定
コマンドのエイリアスの設定などをする。

#### 2-4sudoインストール
`apt install sudo`
インストールしただけでは、root以外のユーザでうまくsudoを使えないので下記URLを参考にユーザにsudo権限を与える。
[Debian GNU/Linux Lennyでsudoを使えるようにする](https://www.garunimo.com/program/linux/column-linux7.php)


### 3. 公開鍵認証によるssh接続の設定
下記URLを参考にキーの作成と登録を進める。
http://www.tooyama.org/ssh-key.html
キー登録後は、ssh接続の設定ファイル`/etc/ssh/sshd_config`の以下構文を変更する。
Port 22⇨ウェルノウン番号を避け、できるだけ大きい任意の番号に）
PasswordAuthentication  yes⇨ no
ChallengeResponseAuthentication  yes ⇨no
UsePAM  yes

sshd.config変更後はファイルを再読み込みする必要があるので、
`sudo /etc/init.d/ssh restart`を実施

その後、ターミナルからsshコマンドでVPSに接続し、接続が確認できました。🥺
<br>
VPSへSSH接続したときにPermission denied (publickey)が出た時の対処

VPSへのSSH接続、Permission denied (publickey)たまに出ますよね。。
久々VPSへの接続するぞって時にこのエラーが出て結構ストレスになっています。
最近、以下の方法でエラーが解消できたので参考程度に見ていただければと思います。

### 自分の環境
PC：MacBookAir （M1チップ、Bigsur)
VPS：さくらVPS
接続方法：SSH接続（ノーパスワード）

### 方法1.パーミッションの確認
これはエラー名でググるとだいたい出てくる対処法のため、試していると思いますが念のため。。
キーとキーが保存されているディレクトリの権限確認です。
参考URL：[ssh接続でPermission deniedと表示されたときの対処法](https://note.mokuzine.net/ssh-permission-denied/)

### 方法2.SSH AGENTへの秘密鍵の登録
僕は上記方法でダメだったので、秘密鍵の発行と登録はできているけど、接続時に秘密鍵がうまくサーバに渡せていないのではないか？ということを疑いました。
そこで登録した秘密鍵を必要な時に取り出してくれるSSH AGENTで秘密鍵の登録状況を調べ、秘密鍵を登録しました。僕はこれでVPSへのSSH接続がなおりました。

まず、以下コマンドで情報を確認します。
(以下はMacターミナルで実行します）

```
ssh-add -l
#=> コマンドの結果として僕の場合は以下が表示されました
The agent has no identities.
```

特に何も登録がされていないようなので、登録を実行

```
ssh-add ~/.ssh/client_rsa
#=> client_rsaは、rsa鍵ファイルでrsa鍵に別名をつけている場合はこのファイル名に限りません
```

以下コマンドで登録状態を再確認。

```
ssh-add -l
#=> コマンドの結果として僕の場合は以下が表示されました
2048 ****（文字列が続く）
```

登録ができていることを確認できたので、VPSへSSH接続を試す。
⇨接続できた

### 方法3.秘密鍵の再発行
一番確実な方法かもしれません。。（僕も何回もお世話になりました）
参考にしているURLを貼ります。
[ssh\-add ~/\.ssh/client\_rsa](http://www.tooyama.org/ssh-key.html)

### 番外編　Connection refused(接続拒否） エラーが発生した場合の対処法
これは今回のとは別エラーですが、もし出た時に解消する参考になるかもと思い、蛇足ですが載せておきます。
（ただ、根本的な解決にはいたっていません。。）
・確認
サーバーに対してネットワーク経路が確保できているか確認する。

```
ping サーバIPアドレス
#=> 自分の場合はtimeoutが発生
```

・解決方法
別のネットワークで接続してみる。
⇨自分の場合はスマホのデザリングからポケットwifiに切り替えることで解消

以上です。

何かのお役に立てれば幸いです。
jsxでの条件分岐の書き方

* `<>` から`</>`の中は`jsx`の適用範囲だから、if文は使えない。
* `{}`の中に三項演算子の形で書く。
* セミコロン不要。

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

const ArticlesComponent = ({title, size, articleLists, linkUrl}) => (
  <>
    <h1 className="title is-1">{title}</h1>
    {articleLists.slice(0, size).map((list) => (
      <ul>
        <Li key={list.id}>
          <a href={list.url}>
            <DateStyle>{list.date}</DateStyle>
            <br />
            <ListTitle>{list.title}</ListTitle>
          </a>
        </Li>
      </ul>
    ))}
    {
      linkUrl ? <Link to={linkUrl}>and more...</Link> : null
    }
  </>
);

export default ArticlesComponent
```
lint-stagedでeslintのwarnを許容しなくしたら何故かprettierが終わらなくなったので直した

`@typescript/use-unused-vars` を error にはしたくないけど、コミットには含めたくなかったので、これをやった 

https://qiita.com/kondei/items/fbad4b746836383c6481#%E8%BF%BD%E8%A8%98

https://github.com/okonet/lint-staged#how-can-i-ignore-files-from-eslintignore

そうしたら何故か `prettier --write` が永遠に終わらなくなったので直した話。

# 結論

`files` を `prettier --write` にも渡す

```js:.lintstagedrc.js
// @see https://github.com/okonet/lint-staged/issues/1017

module.exports = {
  '**/*.{ts,tsx,js,jsx}': async files => {
    const filesToLint = await removeIgnoredFiles(files);
    return [`prettier --write ${filesToLint}`, `eslint --max-warning=0 ${filesToLint}`]
  }
}
```

https://github.com/okonet/lint-staged/issues/1017

# 詳細

もともとの設定がこんな感じだった

```json:package.json
{
  "lint-staged": {
    "**/*.{ts,tsx,js,jsx}": ["prettier --write", "eslint"]
  }
}
```

これをwarnを許容しないようにするために設定を書き換えた。書く場所も `package.json` ではなく `.lintstagedrc.js` に変更。

```js:.lintstagedrc.js
// @see https://github.com/okonet/lint-staged/issues/1017

module.exports = {
  '**/*.{ts,tsx,js,jsx}': async files => {
    const filesToLint = await removeIgnoredFiles(files);
    return ['prettier --write', `eslint --max-warning=0 ${filesToLint}`]
  }
}
```

これで動かしたら `prettier --write` が永遠に終わらなくなったので、色々調べてたら上にあげたissueにたどり着いた。

> Since you are using the function syntax, it's assumed to pass the files yourself:
>
> https://github.com/okonet/lint-staged/issues/1017#issuecomment-924312570

とのこと ほえ〜
Scala クロージャー

## クロージャー
内部でその状態を保持する関数。
保持する状態は、関数宣言と関数実行後の状態。 

## Sample
```Scala
    var counter = 0

    def countUpClosure(): Int = {
        counter += 1
        counter
    }
    
    // The output of countUpClosure method changes
    for (i <- 1 to 10) print(countUpClosure().toString + ", ") // 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 
```

## GitHub
https://github.com/GL-Kageyama/Scala_Closure
Mac から git clone を ssh で行うときに ~/.ssh/github という秘密鍵を読み込もうとするときの対処方

#経緯
先日、新しく与えられたMacを基に開発環境を構築しようと思い、すでにあるレポジトリから ssh で git clone を行ったが、 ~/.ssh/github という秘密鍵を読み込もうとした。

#対処方法
ターミナルより下記コマンドを実行

```
$ ssh-add ~/.ssh/id_rsa
```

登録されていることを確認するときは -L

```
ssh-add -L
```

削除するには -D をつければよい

```
$ ssh-add -D
```

#あとがき
~/.ssh/config を編集する方法もあったのかもしれないが、そもそも git clone コマンドで実行するため、 config が関係していないと考えたため上記の方法で秘密鍵を読み込ませた。
他にも良い方法があれば是非ご教示頂きたい。
Android studio　初回起動時にビルドエラーが起きた時

環境：android studio 4.2.1

#記事を書こうと思った訳
エラー内容でググっても中々対処法が見つからないので備忘録として残す。

#背景
案件の途中から参画。
gitからソース取得。
android studioをダウンロード＆インストール。
android studioでプロジェクト開く。
初回起動でビルドエラーが発生。

ビルドエラー内容
`〜略
Warning: License for package Android SDK Build-Tools XX.XX.XX.XX not accepted.
〜略`

#原因
書いてある通り、SDKのライセンス承認してない。

#対処法
適当にSDKを追加して、ライセンス認証を行う。
再度プロジェクトを開く。

Android Studioを起動
Configure　→ SDK Manager　→　適当なSDKを選択してOK → ライセンス表示画面で、acceptにチェックをつけてOK
→完了後、再度プロジェクトを開く。

#etc
これでうまくいかなかった場合は他の原因なので、エラー内容をよく見ること。
EclipseでのPHP開発環境を構築する【Windows10】

#環境
Windows10 Pro 21H1 64bit

#統合開発環境Eclipseのダウンロード

https://mergedoc.osdn.jp/

1.「Pleiades All in One ダウンロード」から最新版を選択
2.開発言語毎のダウンロードリンクが表示されるので、**PHP**の**Full Edition**を選択しダウンロード

:::note info
Full Edition には各言語の処理系も含まれており、自動デフォルト設定機能により既存環境に依存することなく、コンパイラなどのパスが自動でセットされます。特に理由が無ければ、すでにコンパイラなどがインストールされている環境でも Full Edition をお勧めします。
:::

#ダウンロードファイルの展開
上記ダウンロードファイルを展開すると、以下のフォルダ、ファイルが配置されます。
（2021/11/01時点）

<dl>
  <dt>pleiades フォルダ</dt>
  <dd>┣ .metadata.default フォルダ</dd>
  <dd>┣ eclipse フォルダ</dd>
  <dd>┣ xampp フォルダ</dd>
  <dd>┗ pleiades-2021-09-php-win-64bit-jre_20210919 ファイル</dd>
</dl>
※本記事では「C:\work」へ展開しています。異なる場所へ展開する場合は、適宜読み替えてください。

#xamppの実行（Eclipseの起動テスト準備）
1. C:\work\pleiades\xampp フォルダの xampp-control.exe をダブルクリックして起動します。
1. 言語選択の画面が表示されるので、選択する。
（今回は、左の**英語**を選択します）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2277098/e4864002-e6fa-583d-cc80-87eeaca07a2b.png)

1. XAMPPが起動する。
Apache、MySQLの**Start**ボタンをクリックし実行状態にしておく。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2277098/f9136fb7-8bb6-0a56-7e58-65d5f2703455.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2277098/80b00a7a-0b73-bbe5-fd1a-2871a38d44ed.png)

#Eclipseの起動テスト

1. Eclipseの起動
C:\work\pleiades\eclipse フォルダの eclipse.exe をダブルクリックして起動します。
※Eclipseの初回起動時、コマンドプロンプトが自動で起動し、キャッシュのクリーンアップを実行しますが、何も操作しなくて良い。

1. ワークスペース選択
Eclipseプラットフォームランチャーが表示され、ワークスペースを選択する。
（EclipseのFull Editionをダウンロードした場合、自動で「..\pleiades\eclipse\xampp\htdocs」が選択されている。）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2277098/21c8051b-1ad3-3f50-4957-dbcdee53274f.png)

1. デバッグ設定の変更
　・「ウインドウ」→「設定」を選択し、設定ウインドウを表示する。
　・設定ウインドウの「PHP」→「デバッグ」を選択し、**最初の行でブレークする**チェックを外す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2277098/03c18f03-a6bd-5e8d-b18a-61cad6ec672c.png)
>デフォルトの設定では、「処理実行時に最初の行でブレークする」設定になっているため、その設定を外す。

1. PHPプロジェクトの作成
「ファイル」→「新規」→「PHPプロジェクト」を選択し、PHPプロジェクトを作成
（ここではプロジェクト名を**HelloWorld**としています）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2277098/85e4b494-8e1f-947b-a4c7-b174c4461ba9.png)

1. PHPファイルの作成
作成された「HelloWorld」プロジェクトを右クリックし、コンテキストメニューから「新規」→「PHPファイル」を選択。
（ここではファイル名を**HelloWorld.php**としています）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2277098/be4e55da-c0ce-e472-5c33-052a40c4f1b7.png)

1. テスト用処理の記述
作成されたPHPファイルに以下の処理を記述する。

```ruby:HelloWorld.php
<?php
    print("Hello World!!!");
```
#実行テスト
1. HelloWorld.phpを右クリックし、コンテキストメニューから「実行」→「PHP Webアプリケーション」を選択。
1. 「PHP Web アプリケーションの実行」ダイアログが表示されるので、**OK**ボタンをクリック。
1. ブラウザで「Hello World」が表示されればOK。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2277098/55bcad8e-5c7c-4282-3cb9-6e561f329d3f.png)
windowsでiverilog その114

#概要　

windowsでiverilogやってみた。
再帰やってみた。

#参考にしたページ。

https://qiita.com/IchiroKawashima/items/35f7f1319f87c8594c34

#サンプルコード

```
module test();
	reg [63:0] idata = 64'hfff0e08060302010;
	wire [7:0] odata;
	Max u(.idata(idata), .odata(odata));
	initial
	begin
		$monitor("%h %h", idata, odata);
	end
endmodule



```

#結果

```
fff0e08060302010 60

```

以上。
Couchbase Lite機能解説：ローカルデータ同期

## 概要

Couchbase Liteは、ローカルにあるふたつのデータベース間のレプリケーションをサポートしています。これにより、Couchbase Liteデータベースのデータをセカンダリストレージに保存することできます。

以下は、ローカルデータ同期のコーディング例です。

```JAVA
DatabaseEndpoint targetDatabase = new DatabaseEndpoint(database2);
ReplicatorConfiguration replicatorConfig = new ReplicatorConfiguration(database1, targetDatabase);
replicatorConfig.setReplicatorType(ReplicatorConfiguration.ReplicatorType.PUSH);

// レプリケーターを作成します（レプリケーターがGCされるのを防ぐために、参照が保持されている必要があります）
replicator = new Replicator(replicatorConfig);
replicator.start();
```

## 関連情報

https://docs.couchbase.com/couchbase-lite/3.0/android/dbreplica.html
Cisco Packet Tracerを使用してネットワークを構築する

## ユースケース
資格勉強でネットワークの勉強でよく使われる
視覚的にネットワークの動きを確認することができるので、頭に入りやすい

## 手順
パケットトレーサーにログインする

![スクリーンショット 2021-11-12 14.49.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1603537/59955237-9e82-965b-69fb-b2fd785de57f.png)

![スクリーンショット 2021-11-12 15.29.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1603537/ce9f92ce-82c7-4cd6-fd4f-e0f4a28f5e13.png)

![スクリーンショット 2021-11-12 15.29.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1603537/ccce405d-34ae-1047-5eb7-3ce79b95d0d0.png)

![スクリーンショット 2021-11-12 15.33.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1603537/833e4ebb-5268-fc31-7e7a-34e8e927f9c5.png)

要するに普段OS上でやっているネットワーク設定をパケットトレーサー上でGUIで操作して設定ができる
接続した時点で特にファイアウォールなどは設定されていないので、すぐに疎通確認ができる

シミュレーションを使うと、視覚的にパケットの動きを確認することができる
![スクリーンショット 2021-11-12 15.35.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1603537/65cc8244-db6b-72aa-aefc-2541f40a9ad9.png)

データの中身も確認することができる
各レイヤーの通信内容も確認できる
![スクリーンショット 2021-11-12 15.38.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1603537/991bb3d1-32b9-b094-4744-bc53b02e17ec.png)
STM32L010F4P6と液晶、ACM1602K-NLW-BBWでHello Worldを表示3(DigitalOut)



x 原因は、わからないが液晶がちらつく場合は、ウェートを調整してね!!


STM32L010F4P6でmbedを使い16文字2行液晶に
Hello Worldを表示するプログラム

74hc164シフトレジスターを使用した。
液晶とのピン数を節約した。信号線10本から
信号線3本に減らした。

1 CLK クロック端子(緑)
2 RSDATA RS端子とデータの共有端子(黄)
3 E 読み込み書き込み同期信号(青)

![h_con39.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/e03d3033-c7f3-ff02-c298-7ef1a3cd91b5.jpeg)


![o_con87.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/ea906315-4aae-9419-098c-2d976ddf0c0b.jpeg)



いろいろキレイにした。



```c++




#include "mbed.h"

DigitalOut swdclk(PA_5);
DigitalOut swdio(PA_7);
DigitalOut en(PA_4);

//液晶に一文字送信する
void seg1(int v,int rs)
{
    for(int jj=0;jj<8;jj++){
        if( (v<<jj) & 0x80 ){      
                swdio=1; //ビットが1 
        } else {
                swdio=0; //ビットが0
        }//endif
        swdclk=1;
        swdclk=0; //clk
    }//for
    swdio=rs;
    en=1;wait_ms(1);
    en=0;
}//seg1

//文字列の表示 nana_seg
int ns_printf(char *str1) {
    //文字の中身がゼロか
    while(*str1){
        //一文字出力
        seg1( *str1 ++ , 1  );
    } //while
    //戻り値
    return(0);
}//ns_printf

//液晶の初期化コード
int lcd_int[]={
  0x30,0x30,0x30,0x38,0x08,0x01,0x06,0x08+0x04
};//lcd_init

//メイン関数
int main() {

    //GPIOの初期化
    en=0;

    //液晶の初期化
    for(int ii=0;ii<8;ii++){ 
        seg1( lcd_int[ii] , 0);wait_ms(2);
    }//for

    //seg1(   0x01  , 0  ); wait_ms(1000); //画面クリア

    seg1( 0x80+0x00 , 0  ); //1ライン目にカーソルを移動

    ns_printf("Hello World !"); //表示

    while(1) {} //無限ループ

}//main

//容量削減
void error(const char* format, ...){}



```
Sync Gatewayセキュリティ：認証と承認のためのOAuth 2.0とOIDCの基礎

## はじめに
OAuth 2.0 は、「委任された承認」の業界標準です。
OAuth 2.0は承認に重点を置いており、認証について規定していません。 OpenID Connect（OIDC）は、OAuth2.0の上に認証レイヤーを追加します。

ここでは、OAuth2.0とOIDCの基本について説明します。

## Sync GatewayとOIDC
Sync Gatewayはさまざまな形式のクライアント認証をサポートしています。
Sync Gatewayは、Couchbase Liteとのレプリケーション機能だけでなく、パブリックRESTエンドポイントを提供します。
つまり、クライアントは、Couchbase Liteアプリケーションの場合もあれば、パブリックRESTエンドポイントを介してSync GatewayにアクセスするWebフロントエンドまたは、(Couchbase Liteを使っていない)モバイルアプリの場合もあります。


最もよく使われているCouchbaseSync Gatewayクライアント認証メカニズムの1つが、OIDCです。


## OAuth 2.0


OAuth 2.0は委任認証の業界標準であり、市場には多数のOAuthプロバイダーがあります。

たとえば、多くのWebアプリやモバイルアプリで見かける「Facebookでログイン」ボタンを思い出すことができます。これは、OAuth2.0を使用して実装されます。


## OpenID Connect（OIDC）


OIDCは、OAuth 2.0の上に標準ベースの認証レイヤーを追加します。

OIDCには、2つの一般的なOIDCフローがあります。暗黙フローと認証コードフローです。

## 暗黙フローと認証コードフローのどちらが良いか？

暗黙のフローは単純であり、一般的にほとんどのユーザーに好まれています。モバイルアプリには安全なストアがあるため、IDとアクセストークンをデバイスのローカルキーストアに安全に保存できます。

認証コードフローの利点は、セキュリティがわずかに向上することです。これは、OIDCプロバイダーに有効な`client_id`と`client_secret`が提示された場合にのみ、認証コードと引き換えにトークンがSync Gatewayに付与されるためです。これにより、認証されたクライアントのみがトークンを取得できるようになります。また、更新トークンを使用すると、エンドユーザーが毎回資格情報を入力しなくても認証セッションを更新できます。




## JSON Web Token（JWT）
 
Identity Server（OIDCプロバイダー）は、IDトークン（IDトークン）を要求元のアプリに配信します。

IDトークンは、ユーザーの認証に関する「クレーム」をエンコードする標準的な方法です。「クレーム」は、ユーザーに関するアサーションです。

OIDCの重要な要素は、JSON Web Token（JWT）と呼ばれる標準形式でエンコードされたセキュリティトークンであるIDトークンです。JWTはデジタル署名されています。

以下は、典型的なクレームのセットを持つJWTの例です。

```json
{
  "sub": "AItOawmwtWwcT0k51BayewNvutrJUqsvl6qs7A4",
  "name": "Priya Rajagopal",
  "email": "priya.rajagopal@example.com",
  "iss": "https://pk-demo.okta.com/OAuth 2.0/default",
  "aud": "WuRuBAgABMP7_w4K9L-40Jhh",
  "iat": 1622246311,
  "exp": 1624838311,
  "amr": [
    "pwd"
  ]
}
```

- `sub`: JWTが参照するユーザー
- `iss`: JWTに署名するJWTの発行者
- `aud`: トークンの対象者
- `iat`: 発行されたタイムスタンプ
- `exp`: 有効期限のタイムスタンプ
- `amr`: トークンの発行に使用される認証方法
 
 

jwt.ioは、JWTのデコードと検証に役立ちます。

https://jwt.io/



## 参考情報

https://blog.couchbase.com/oauth-2-oidc-fundamentals-authentication-authorization/


OAuth 2.0 Playgroundは、OAuth認証フローの理解を助けてくれます。

https://www.oauth.com/playground/index.html


https://blog.couchbase.com/oidc-implicit-flow-client-authentication-couchbase-sync-gateway/?ref=blog

https://blog.couchbase.com/oidc-authorization-code-flow-client-authentication-couchbase-sync-gateway/?ref=blog
AWS Organizationsを使って複数のAWSアカウントの管理を行う

AWSには複数のAWSアカウントを管理する機能として AWS Organizationsがあります。
今までは複数のAWSアカウントがある場合、それぞれに個別でログインするかクロスアカウントを使ってログインを柔軟にコントロールすることができます。
具体的には複数のAWSアカウントを同じIAMユーザーのアカウントでログインできるようにしたり、請求を一つにまとめたりすることができます。

受託案件など複数の案件を管理する場合、AWSアカウントから切り分けをしておくことで開発・運用でのアクセスコントロールが強く行うことができたり、ユーザーが混在する状況を解決することができます。


## 要点

- AWSアカウントの作成は簡単（ただしrootアカウントの[パスワードリセット](https://qiita.com/ai-2723/items/d82d072debdbf6d15b34)が必要）
  - クレジットカード、電話認証がなくすぐに作成できました
- Organizationsの単位はOU（組織）
  - OUは社内の組織を表すイメージ
- SCP（サービスコントロールポリシー）によってメンバーアカウント側の操作権限を付与する
  - SCPのポリシをグループに付与しておき、グループメンバーをOUに紐付ける？
  - 基本的にはメンバーアカウントのAdministratorの全権を渡すことになる？
- 組織に参加させてたり、脱退したりということが可能（未検証）
  - 例として、初期開発時はOrganizationsで作成して途中からOrganizationsを脱退してお客さんに渡す、と言ったことが可能（だと思います）


- 費用
  - まとめて請求
  - ボリュームディスカウントがあれば全適用
  - リザーブドインスタンスやセービングプランズの共用
    - これは結構便利そうですが、代理請求の場合には計算が複雑になりそうです
  - デメリットとして[無料枠がなくなります](https://www.slideshare.net/tsukamoto/aws-organizations-249878141)（管理アカウントの作成から12ヶ月）
    - おそらく[3万円クレジット](https://qiita.com/anmorenight/items/b6ddd6edb89a39b008eb)もなくなります
- サポートの費用は組織毎
  - 通常、メンバーアカウントに対する AWS Support のサブスクリプションは、組織全体には適用されません
- 既存のAWSアカウントがある場合、そこからメンバーアカウントを作るのではなく、別途新規で作ることが[ベストプラクティス](https://tech.nri-net.com/entry/2021/04/05/091532)となるようです

## 懸念点
- OUの単位が組織のため、自分たちのようにプロジェクトごとに分ける用途とは違うかもしれない？
  - SCPの付与がグループ毎のため、複数グループ（OU、プロジェクト）に属したモデルを再現できる？
- SCPでメンバーアカウントの全権が渡るため、パートナーさんで権限を制約することができない？
  - 本番、開発でアカウントを分けて開発アカウントに全権などで分けると良いのではないか
- 本番、開発で分けるとき、途中から増やしたい時の階層構造はどうなる？

## ログインの方法



## Organizations経験者から
知り合いのOrganizationsに話を聞きました。

- 管理用アカウントは人の管理だけを行い、そこでリソースの利用はしないほうが良い
- PoC案件等もメンバーアカウントを作成し、そちらで行う。
- 管理用アカウントは人の管理に集中する。


## 参考

https://dev.classmethod.jp/articles/aws-organizations-best-practice/


https://docs.aws.amazon.com/ja_jp/organizations/latest/userguide/orgs_manage_accounts_access.html
unittestとは

Pythonでのunittestの使い方についてまとめる。

# unittestとは

***unittest***とは、Pythonの標準モジュールとして提供されているテストフレームワーク。
***unittest***を利用することで、複数のテストを同時にできることや、同条件で何度も行えるなどのメリットがある。

# unittestの使い方
unittestのテストプログラムの基本的な書き方は以下となる。まず、ファイル名については、「```test_<テスト対象モジュール>.py```」とする。
1.  ```unittest```モジュールをインポートする。
2. テストクラスは、クラス名を「```Test<テスト対象クラス名>```」とし、```unittest.TestCase```を継承して作成する。
3. テストメソッドは、メソッド名を「```test_<テスト対象メソッド名>```」とし、テストケースを記述する。テストは unittestで提供されているメソッド(assertEqual()やassertTrue()など)を使用して判定を行う。　　
   提供されているassertメソッドについては、公式ドキュメントを参照（[公式ドキュメント](https://docs.python.org/ja/3/library/unittest.html#unittest.TestCase.debug)）
4．```unittest.main()```でテストを実行する。

例として、```calculator.py```のメソッドをテストするテストプログラム```test_calculator.py```は以下のように書くことができる。

```python:calculator.py
class Calculator:
    def multiply(self,a,b):
        return a * b
```
   
```python:test_calculator.py
# 1. unittestをインポート
import unittest
from calculator import Calculator

# 2. クラス名を「Test<テスト対象クラス名>」とし、unittest.TestCaseを継承
class TestCalculator(unittest.TestCase):

    calculator = Calculator()
    # 3. メソッド名を「test_<テスト対象メソッド名>」とし、テストケースを記述
    def test_multiply(self):
        calculator = Calculator()
        # テストコードの記述
        self.assertEqual(6, calculator.multiply(2,3))

# 4．unittest.main()で実行
if __name__ == "__main__":
    unittest.main()
```

```python:実行結果
$ python test_calculator.py
.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK
```
UbuntuにMySQLをインストールして、ApacheのPHPからアクセスするまで

#環境
Ubuntu 20.04.3
Apache 2.4.41
PHP 7.4.3

#MySQLのインストール
https://qiita.com/houtarou/items/a44ce783d09201fc28f5

こちらを参考にしました。
こちらのコマンドを入力します

```shell-session
 $ sudo apt install mysql-server mysql-client
```
##Rootユーザーの設定
```shell-session
 $ sudo mysql_secure_installation
```

|質問|答え|
|--|--|
|Press y&#124;Y for Yes, any other key for No:|y|
|Please enter 0 = LOW, 1 = MEDIUM and 2 = STRONG: 2|後述※１|
|Do you wish to continue with the password provided?(Press y&#124;Y for Yes, any other key for No) :|y|
|Remove anonymous users? (Press y&#124;Y for Yes, any other key for No) :|y|
|Disallow root login remotely? (Press y&#124;Y for Yes, any other key for No) :|y|
|Remove test database and access to it? (Press y&#124;Y for Yes, any other key for No) :|y|

※１
パスワードの強度についてです。0が一番弱く、2が強いです。
パスワードマネージャー等で強固なパスワードを管理できる方は2で大丈夫ですが、自信のない方は0にしましょう(とはいっても、2にするのが推奨です)

##テスト用ユーザーの作成
次のように入力してMySQLを起動します

```shell-session
 $ sudo mysql -u root
```

###ユーザー作成
MySQL内でユーザーを作成します

```sql
mysql> CREATE USER 'ユーザー名'@'localhost' IDENTIFIED BY 'パスワード';
```
###権限付与
ここでは分かりやすく全権限を付与していますが、通常は必要な物のみ与えるようにしましょう。

https://www.dbonline.jp/mysql/user/index6.html

```sql
mysql> GRANT all on *.* to 'ユーザー名'@'localhost';
```
###テスト用テーブルの作成
mysqlの画面で次の文を実行してください。

```sql
create database test;
use test;
create table students(id int,name varchar(20));
insert into students (id,name) values (1,'Taro'),(2,'Hanako');
```
###PHPの環境
PHPのライブラリをダウンロードします

```shell-session
 $ sudo apt install php7.4-mysql
 $ sudo systemctl restart apache2
```

###ファイルの作成
次の内容を適宜変更し、アップロードします

```php
<?php

$link = mysqli_connect('localhost', 'ユーザー名', 'パスワード', 'test');

$query = "SELECT id, name FROM students;";

if ($result = mysqli_query($link, $query)) {
    foreach ($result as $row) {
        echo($row['id'].$row['name']);
    }
}
mysqli_close($link);
```

アクセスして、1Taro2Hanakoと表示されたら成功です。お疲れ様でした。
タブの作り方

今回のお題
-
今回はBootstrapを用いたタブの作り方を取り上げます。

完全に自分用のメモです。

タブとは
-
[![Image from Gyazo](https://i.gyazo.com/9185d0b7045aa7913388c6e45b7fc5a5.gif)](https://gyazo.com/9185d0b7045aa7913388c6e45b7fc5a5)
こういうやつです。

　スマホのような小さい画面であっても複数の情報を無理なく載せることができるので便利ですよね。

タブの基本骨格
-
タブの上の方にあるクリックする部分（`店舗紹介`とか`キャンペーン一覧`とかの部分)を`ナビアイテム`、ナビアイテムをクリックすると表示される部分を`タブパネル`といいます。

```html
<!-- ナビアイテム定義部分 -->
  <ul class="nav nav-tabs mb-3" id="myTab" role="tablist">
    <li class="nav-item" role="presentation">
      <!-- ページを開いた時に表示されている部分に関してはclass="active"とaria-selected="true"が必要 -->
      <a href="#detail" class="nav-link active text-secondary" id="detail-tab" data-bs-toggle="tab" role="tab" aria-controls="detail" aria-selected="true">
        店舗紹介 <!-- ここに書いたものがナビアイテムとして表示される -->
      </a>
    </li>
    <li class="nav-item" role="presentation">
      <a href="#menu" class="nav-link text-secondary" id="menu-tab" data-bs-toggle="tab" role="tab" aria-controls="menu" aria-selected="false">
        取扱商品一覧
      </a>
    </li>
    <li class="nav-item" role="presentation">
      <a href="#campaign" class="nav-link text-secondary" id="campaign-tab" data-bs-toggle="tab" role="tab" aria-controls="campaign" aria-selected="false">
        キャンペーン一覧
      </a>
    </li>
    <li class="nav-item" role="presentation">
      <a href="#member" class="nav-link text-secondary" id="member-tab" data-bs-toggle="tab" role="tab" aria-controls="member" aria-selected="false">
        スタッフ一覧
      </a>
    </li>     
  </ul>
<div class="tab-content" id="myTabContent">
    <div class="tab-pane fade show active" id="detail" role="tabpanel" aria-labelledby="detail-tab">
      <!-- タブパネルの中身を書く -->
    </div>
    <div class="tab-pane fade" id="menu" role="tabpanel" aria-labelledby="menu-tab">
      <!-- タブパネルの中身を書く -->
    </div>
    <div class="tab-pane fade" id="campaign" role="tabpanel" aria-labelledby="campaign-tab">
      <!-- タブパネルの中身を書く -->
    </div>
    <div class="tab-pane fade" id="member" role="tabpanel" aria-labelledby="member-tab">
      <!-- タブパネルの中身を書く -->
    </div>
```
`ナビアイテム`の`href`属性および`aria-controls属性`と`タブパネル`の`id属性`、`ナビアイテム`の`id属性`とタブパネルの`aria-labelledby属性`を対応させる必要があります。
WPで定期実行させる｜wp-cronの使い方


wpで定期実行したい時、「wp-cron」を使うことで実現します。

例えば、毎日午前6時にデータ集計したり、30日経過後の論理削除データをけしたりしたい時ってありますよね。


それでは、これからwpで定期実行するやり方を解説していきます。

## 1.設定

まずfunctions.phpに以下を追記します。


```php:functions.php

function auto_func()
{
    //定期実行させる処理が書いたphpファイル
    $return_url = dirname(__FILE__) . '定期実行させたいphpファイル'; 
    require $return_url;
}

add_action('auto_func_cron', 'auto_func');
if (!wp_next_scheduled('rss_check_cron')) {// 何度も同じcronが登録されないようにするため
    //スケジュールを組み立て
    $difference = (current_time('timestamp') - time()) / 3600;
    $my_time = wp_date('Y-m-d 09:00:00', current_time('timestamp'));
    $task_time = strtotime(-1 * $difference . " hour", strtotime($my_time));
    //スケジュール登録する（毎日）
    wp_schedule_event($task_time, 'daily', 'auto_func_cron');
}

```


## 2.確認

プラグイン「WP Crontrol」をインストールする.
「WP Crontrol」を使えば、視覚的にいつ実行されるのか（されたのか）わかる。


## 3.おことわり

「WP-Cron」はOSのcronとは違います。

webサイトにアクセスがあったときに実行される「擬似」的なcronです。

なので逆にアクセス数の少ないwebサイトですと、cron実行に若干のタイムラグがあります。
【SwiftUI】View上のテキストをクリップボードに直接コピーする

####ボタンを使用する
クリック時に、ios端末のクリップボードに直接コピーが可能。

```swift
Button(action:{
    UIPasteboard.general.string = "コピーしたい文字列"
}){
    Text("コピーしたい文字列")
}
```
window.open()の「アクセスが拒否されました」のエラーに対処する

先日遭遇した問題として、
JavaScriptを利用してブラウザのタブを開く場合、「アクセスが拒否されました」と表示されてうまくいかないことがあった。

原因はwindow.open()の引数として、
windowNameを’blank’固定で渡していたため、既に同じものが存在する場合に開けなくなったようだった。
Electron + Angular は、こうしたらいいんじゃないかなプラクティス

# はじめに

Electron + React は、よい感じのものが用意されていますが、Electron + Angular はまだのようです。

少しノウハウたまったので書いてみます。

# 環境

* Electron 15.3.0
* Angular 12.2.0


# ディレクトリ/ファイル構成

projectsディレクトリを作り、メインプロセスとレンダラープロセス(Angular)を分けました。

```
├── angular.json
├── karma.conf.js
├── package.json
├── package-lock.json
├── projects
│   ├── main                  # メインプロセス
│   │   ├── src
│   │   │   ├── main.ts
│   │   │   └── preload.ts
│   │   └── tsconfig.json     # メインプロセス用tsconfig
│   ├── renderer              # レンダラープロセス(Angular)
│   │   ├── src
│   │   ├── tsconfig.app.json
│   │   └── tsconfig.spec.json
│   └── types                 # 共通型定義
└── tsconfig.json
```

## なぜこうしたか

メインプロセスとAngularのtsconfigは内容が異なる。
↓
別々のファイルにしたい。
↓
別々のファイルにしてtscへコンパイルオプションを渡すだけだと、vscodeが期待するtsconfigを見つけられない。
↓
:point_right: tsconfigをディレクトリごとに配置


## ちなみに

ngcliで新規に始めるときは、以下のようにしてアプリケーションをあとから作成するとよいです。

```console
ng new --no-create-application MyApplication
cd MyApplication
ng generate application
```


# メインプロセス用tsconfig

```json
{
  "extends": "../../tsconfig.json",
  "compilerOptions": {
    "target": "es2020",
    "module": "commonjs",
    "lib": ["ES2020", "DOM"],
    "outDir": "../../dist",
    "types": [],
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "resolveJsonModule": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["../projects/types/**/*.d.ts", "src/**/*.ts"]
}
```

## なぜこうしたか

メインプロセスとAngularのビルド結果が同じディレクトリに存在しないといけない。
↓
:point_right: compilerOptions > outDir をAngularに合わせる。

`tsc --build --watch`で全部見るようにする。
↓
:point_right: includeに全部書く。


# package.jsonのscripts

```json
  "scripts": {
    "start:el": "electron .",
    "build:el": "tsc --build projects/main/tsconfig.json",
    "watch:el": "tsc --build --watch projects/main/tsconfig.json",
    "ng": "ng",
    "start:ng": "ng serve",
    "build:ng": "ng build",
    "watch:ng": "ng build --watch --configuration development",
    "test:ng": "ng test",
    "build": "run-p build:*",
    "watch": "run-p watch:*"
  },
```

普段は`npm run watch`でビルドしながら、適宜`npm run start:el`で起動させてます。

## なぜこうしているのか

ホットリロードしたいなぁ。
↓
Electron自体にはそういったものは用意されていない。
↓
Webpackのdev serverみたいなもの作らないとだめか。。。つらいな。。。
↓
:point_right: とりあえずビルドだけ自動にしておくか。。。


良い方法ないでしょうか？ :pensive:
文字列の日付を降順にソートする方法

```src/data/note.json
[
  {
    "id": "1",
    "title": "【参加メモ】 『SCRUM BOOT CAMP THE BOOK 増補改訂版』読書会 第1回目",
    "date": "2021/10/25",
    "url": "https://note.com/maiamea/n/n5cd7a8c0cbf7"
  },
  {
    "id": "2",
    "title": "【参加メモ】 『SCRUM BOOT CAMP THE BOOK 増補改訂版』読書会 第2回目",
    "date": "2021/10/27",
    "url": "https://note.com/maiamea/n/n792779910e0b"
  },
  {
    "id": "3",
    "title": "【参加メモ】 『SCRUM BOOT CAMP THE BOOK 増補改訂版』読書会 第3回目",
    "date": "2021/10/29",
    "url": "https://note.com/maiamea/n/n21e44fdb4f10"
  },
  {
    "id": "4",
    "date": "2021/10/01",
    "title": "はじめてカンファレンスのセッション公募に応募したよ！",
    "url": "https://note.com/maiamea/n/n165d9f8199fa"
  }
]
```

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

// 文字列の日付をDate型に変換してsortする
const DescArticleLists = articleLists.sort((a, b) => Date.parse(b.date) - Date.parse(a.date));

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

export default NoteArticlesComponent
```

# 結果
仮に日付の順序をバラバラに登録してしまっても、ちゃんと降順にソートされる。
![スクリーンショット 2021-11-12 14.25.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/384836/a6712127-fbfe-4e20-74d0-7251878ae71e.png)


# 参考サイト
* [MDN - Array.prototype.sort()
](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/sort)
* [MDN - Date.parse()](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Date/parse)
DjangoでPostgreSQLと接続(Windows環境)

普段、macを使っていてwindowsでDATABASEをsettingした際に詰まったことを個人メモとして書き残します。
初心者向けの記事になります。


## 1. setting.pyのDATABASEを以下に変更

```
DATABASES = {
    'default':{
        'ENGINE':'django.db.backends.postgresql',
        'NAME':'データベース名',
        'USER':'ユーザー名',
        'PASSWORD':'パスワード',
        'HOST':'ホスト名',
        'PORT':'5432',
    }
}
```

## 2.環境変数の設定(これをしてなくてなかなか接続できませんでした)

この部分に関しては1どやれば大丈夫です。

・windows10の場合
「スタート」 → 「設定」 → 「バージョン情報」 → 「システム情報」 
→ 「システムの詳細設定」　→　「環境変数」 → 「Pathをクリックして編集」
→ 「```C:\Program Files\PostgreSQL\12\bin``` を追加してOKする」

※最後のパスは大抵の方はこちらでいけると思いますが、違うところに保存した方は変える必要があります。

<B>終わり次第、IDEとターミナルは再起動してください</B>

### 参考にしたサイト
https://stackoverflow.com/questions/47124297/commanderror-you-appear-not-to-have-the-psql-program-installed-or-on-your-pat
C#でlineプリプロセッサディレクティブのhiddenを使うと、usingディレクティブの追加が提案されない

C#で、`#line hidden`を使うと、usingの追加（等々）の提案がされなくなる。

↓通常時
![2021111212392500.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223441/aba5cc4f-28ec-db98-61f5-96496528a51c.png)

↓`#line hidden`を使ってるとき
![2021111212383357.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223441/b39864fd-f1ec-9c93-c31b-db0ccc0a7a76.png)

仕様だろうか？

usingの提案がされなくなった！と思った場合は、オプションを開く前に`#line hidden`使ってないか確認の必要あり。

# 対策

そもそも`#line hidden`を使おうと思ったのは、デバッグ時にステップ実行をスキップしたいコードがあったから。

これは、`DebuggerStepThroughAttribute`を使えば解決。
スキップしたいクラスやらメソッドやらに`[DebuggerStepThrough]`を付ければ、ステップ実行はスキップされる。
Unityパフォーマンス最適化シリーズ――アセットのメモリリーク

4年前、Unityの各主要なモジュールのパフォーマンス最適化知識（初心者向け版）を1つずつ説明しました。近年、エンジン自体、ハードウェアデバイス、製作基準などのアップグレードに伴って、UWAは引き続き規則や方法を更新して、各開発者に提供しつつあります。「アップグレード版」のパフォーマンス最適化マニュアルとして、【Unityパフォーマンス最適化シリーズ】はより多くの開発者が利用できるように、シンプルでわかりやすい表現を心がけています。今回、アセットのメモリリークに関連する知識を共有します。

メモリリークは一番出やすい問題ですけど、出たのは一番怖いとも思われませんか。それはなぜでしょう？

考えたら、リークボトルネックを特定するまでに、リークの程度はどうだろうと全く予想できない、オンラインのある時刻で集中的に爆発するかなと心配しているからかもしれません。「こっちのユーザーは、三時間続けて流暢にゲームをやっていたのに、３～４時間になったら、ますます動かなくなってしまいました。それは全く予想出来ていませんね。」というフィードバックにあたって、今回はそういう疑問を解決しましょう。

UWAの実機テストレポートにもUWAレポートにも、アセット使用のトレンド図があります。もし下図のような絶えずに上昇するトレンドが出たら、十分な注意が必要です。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/3394bb4a-70dd-4947-eada-a4166d8f27d0.png)

またこういうように、節ごとに上昇します。

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/ffd6f849-99b9-6e6f-f214-3a85647e448b.png)
このような状況になっていたのは、開発チームはローディング完了のアセットに対してキャッシュしておいたが（例えばContainerの中に入れるとか）、シーンを切替る際に、それをRemoveしたりまたはClearしたりしていません。したがって、エンジン自体でも、手動的にResources.UnloadUnusedAssetsなどの関連するAPIを呼び出しても、それをアンインストールできません。そして、アセットのリークが引き起こされました。

それでは、常用のアセットメモリリークをチェックする論理を紹介します。

---
##１．アセットのライフサイクルに注目する
すなわち、各アセットがプロジェクトの実行中での使用範囲を知ることです。レポートの「アセット詳細」パージには、実行中に現れたアセットの情報が見えます。指定されたアセットを選択すると、生命トレンド図にローディングやアンインストールされたシーンが見えます。
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/37c9ebb6-14f3-44c2-b751-7818583738bb.png)
この機能は、主にどのようなアセットはメモリに常駐するかを素早くチェックし、さらにそのアセットはプリロードなのかリークアセットなのかを判定することに用いられます。よく見られるLoading図、Login図は、（下図のように）、メモリの使用が大きいから、常駐メモリにする必要がありません。

![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/d0f7e54d-635b-3528-41a3-3e91ea08243b.png)
---
##２．リークをチェックする具体法>>シーン・フレーム　アセットの比較
通常、プロジェクトのアセット数は数千で、どのようにリークを科学的にチャックしますか？もっと早くリークがあるアセットを探し出し、以下のようないくつかの方法でアセットの対照を行います。
###１）同類のシーン・同じシーンの比較：相違アセットを注目する

同類のシーン・同じシーンのアセットは一般的に固定的で、違った時刻の同じ種類・同じシーンの相違アセットを比較し、それらの存在は合理的かどうかを判断するだけで、リークアセットがあるか、あったら具体的にどのアセットなのかを判定できます。
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/71095eb6-9cba-18cf-7d64-c4ea46b9f860.png)
###２）異類シーンの比較：共有アセットを注目する
常駐アセット以外、異類のシーンが使用しているアセットは完全に違っています。両類型のシーンの共有アセットを比較して、それは常駐アセットであるかどうかを判断します。常駐アセットでないと、リークアセットであるかもしれません。
![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/fb423cd7-f40d-7fa7-cd6f-65f105c54f13.png)
###３）相違フレーム間の比較
他に、相違フレーム間の共有アセットや専有アセットを比較して、共有項・相違項は合理的であるかどうかをチャックできます。
![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/34ea3ebd-124b-b88e-a8f5-b845f9413074.png)

方法が適切で、特定が正確なら、修正はかなり早いですよ。

同時に、平常に長時間のテスト例を用意しおきれば、りーっくを問題を避けることができます。多くの開発チームは便宜のために、ただ10～15分に実行すると済みます。実は、これらのテストサンプルはとても十分ではありません。こちらの方はできるだけゲーマーのリアルなシーンを復元して、最適化の階段ではできるだけ十分なテストを行います。

もちろん、もっといい方法として、自動化スクリプトによって回帰テストをします。例えば、初心者の最初の３０分、コピーの長時間オンフックなどのようなものは自動化スクリプトによって代替されます。それに、UWAのPipelineサービスは、多端末の自動化テストをサポートし、長時間テストのニーズにも十分に満たします。

 
---
UWA Technologyは、モバイル/VRなど様々なゲーム開発者向け、**パフォーマンス分析**と**最適化ソリューション**及び**コンサルティングサービス**を提供している会社でございます。

今なら、UWA GOTローカルツールが**15日間に無償試用**できます！！
よければ、ぜひ！

UWA公式サイト：https://jp.uwa4d.com
UWA GOT OnlineレポートDemo：https://jp.uwa4d.com/u/got/demo.html
UWA公式ブログ：https://blog.jp.uwa4d.com
PHPのwhileでループ処理を行いましょう☆

whileを使って条件が満たされている間、

繰返しができるループ処理をしていきましょう！

50点を持っていて、-10ずつ減らしていきます。

```php:index.php
<?php

$score = 50;

while ($score > 0) {
   echo "あなたの点数は $score です!" . PHP_EOL;
   $score -= 10;
}
```

ターミナルに以下を入力します！

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

このように出力されます！

```
~ $ php index.php
あなたの点数は 50 です!  // -10ずつ減っていきます
あなたの点数は 40 です!
あなたの点数は 30 です!
あなたの点数は 20 です!
あなたの点数は 10 です!
~ $ 
```
メモ〜cleanメソッドの注意点

今回のお題
-
今回はdjangoの`clean`メソッドを使う上での注意点として、自分が引っかかった点を挙げておきます。

一つのフォームに`clean`メソッドと`clean_xxx`メソッドが両方あって、cleanメソッドの方でも`xxx`フィールドを参照している場合に起こりがちなエラーになります。

エラーが起きた時の状況
-

モデルとフォームについては以下の通りで、開始日と終了日を選択してキャンペーン情報を登録するという機能を実装していました（関係のない部分については省略しています）。

```python:models.py
from django.db import models

# Create your models here.
class Campaign(models.Model):
  start = models.DateField(
    verbose_name="開始日"
  )
  end = models.DateField(
    verbose_name="終了日"
  )

```
```python:forms.py
from django.core.exceptions import ValidationError
from .models import Campaign
from django.forms import ModelForm, SelectDateWidget
import datetime
class CampaignForm(ModelForm):
  
  class Meta:
    model = Campaign
    fields = ["menu","campaign_type", "value", "start", "end"]
    widgets = {
      "start": SelectDateWidget,
      "end": SelectDateWidget,
    }

  def clean_start(self):
    start = self.cleaned_data.get("start")
    if start <= datetime.date.today():
      raise ValidationError("開始日は本日以降の日付で入力してください")
    return start

  def clean(self):
    cleaned_data = super().clean()
    start = cleaned_data.get("start")
    end = cleaned_data.get("end")

    if end <= start:
      raise ValidationError("終了日は開始日よりも後の日付で入力してください")
    return cleaned_data
```

まず`clean_start`で開始日が今日よりも前になっていないかどうかを確認した後で、`clean`メソッドで終了日が開始日以前でないかどうかを確認しています。

発生したエラー
-
上記のコードを書いた上で、`clean_start`のテストのために`開始日=昨日の日付', `終了日=翌日の日付`と入力したところ以下のエラーが。

```shell
TypeError at /campaign/create/
'<=' not supported between instances of 'datetime.date' and 'NoneType'
# 中略
Exception Location:	/Users/hashimotokeishi/cakeshop/cakeshop/campaign/forms.py, line 40, in clean
```

>'<='を用いてdatetimeオブジェクトとNoneTypeを比較することはできないよ。
該当箇所はforms.pyの40行目だよ。

とのこと。

で、該当箇所を見てみると

```python
  def clean(self):
    cleaned_data = super().clean()
    start = cleaned_data.get("start")
    end = cleaned_data.get("end")

    if end <= start: # ここが40行目
      raise ValidationError("終了日は開始日よりも後の日付で入力してください")
    return cleaned_data
```
の一文がありました。

そもそも`clean`メソッドは`clean_xxx（今回であればclean_start)`の後に呼ばれます。

今回の入力内容であれば`clean_start`でキャンペーン開始日時が弾かれてしまうので、そもそも`cleaned_data.get("start")`の戻り値は`None`です。

なのでキャンペーン終了日時と`None`を比較することになり、上記のようなエラーが発生してしまったのでした。

解決策
-

以下のように、startの値が存在しているかどかの確認をしましょう。

```python
if start and start >= end:
```
Ubuntu20.04上のApacheにPHPをインストールする

###環境
Ubuntu 20.04.3 LTS
Apache 2.4.41

#インストール
```shell-session
 $ sudo apt-install php libapache2-mod-php
```

#動作確認
```shell-session
 $ vi /var/www/html/test.php
```
次の内容を書き込みます。
保存できない場合はこちらの記事を参考に権限設定をしてみてください。

https://qiita.com/yuu1111main/items/77976d7ece0ecfb35157

```php
<?php phpinfo();
```
保存したら、test.phpにアクセスし、次のように表示されれば成功。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362835/729d986e-242a-7fd9-3ff6-1f9d40961155.png)
Ubuntu上のApacheにて権限が無い問題を解決する

#環境
Ubuntu 20.04.3
Apache 2.4.41

#現在の権限を確認
```shell-session
 $ cd /var/www
 $ ls -l
 drwxr-xr-x 2 root root 4096 Nov  1  2020 html
```
__r-x__となっているため、読み込みと実行はできるが書き込みができない状態になっている。
権限関係についてはこちらが分かりやすかった。

https://qiita.com/shisama/items/5f4c4fa768642aad9e06

#権限の設定
まず、Ubuntu上のApacheはwww-dataというユーザーによって実行されているため、このユーザーに所有権を移動する。

```shell-session
 $ sudo chown -R www-data:www-data /var/www/html
```
そしたら、www-dataグループにユーザーを追加する

```shell-session
 $ sudo usermod -aG www-data 追加したいユーザー名
```

次に、所有者とグループに入っている人に書込実行読込の権限を与え、それ以外のユーザーには読込と実行のみできるようにする。

```shell-session
 $ sudo chmod 775 -R /var/www/html
```
一度SSHを切断し、ログインし直す。これによって、ユーザーが書き込み出来るようになった。
自サイトがiframeで第三者のサイトへ埋め込まれることへの対策（X-Frame-OptionsもCSPも使えない場合）

# はじめに

自サイトがiframeで第三者のサイトへ埋め込まれることを避ける方法として本来あるべき姿は、 HTTPレスポンスヘッダーに `X-Frame-Options: SAMEORIGIN` あるいは `X-Frame-Options: DENY` を追加することです。

https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/X-Frame-Options


しかし、そのサイトがiframeで埋め込んで利用することを前提としていて、かつ埋め込み元のドメインが異なる場合、`X-Frame-Options` で対応することはできません。 （ `X-Frame-Options: ALLOW-FROM` というものも存在していたようですが、最近のブラウザでは廃止されていますので利用できません ）

代替方法として、CSP(Content-Security-Policy)の `frame-ancestors` で指定する方法はありますので、HTTPレスポンスヘッダーの追加が可能であれば、その方法で対応する方法はありますが、HTTPレスポンスヘッダーが追加できなければこの方法で対応することはできません（metaタグでのCSPの設定も行えますが、frame-ancestorsはmetaタグでの設定に対応していません）。

以上のような、条件のあまり宜しくない（制限の厳しい）環境における対策について考えてみました。

# 考えられる対策

このような場合において、iframeが自サイト外で埋め込まれる問題への簡単な対策として、次の方法が挙げられます。

- ページ読み込み時において、コンテンツをCSSで不可視 ( `display:none` ）とする。（JavaSciptが無効化されている状態においては、コンテンツの不可視で対応する）
- JavaScriptで埋め込み元サイトのドメインをチェックする（`parent.location.href` で埋め込み元サイトのURLが取得可能）。
- 埋め込み元サイトのドメインが自サイトに関連する場合は、コンテンツの不可視を解除 ( `display:block` ）とする。
- 埋め込み元サイトのドメインが自サイトに関連しない場合は、不可視のままとし、かつコンテンツを削除する。

サイトの環境（条件）によっては対応可能な事項は他にもあるかもしれませんが、自サイト（オリジナルサイト）が第三者のサイトにiframeで埋め込まれることを避けることだけを目的とし（それ以外のことは考えず）、かつ閲覧環境は最近のWebブラウザのみを対象とするのであれば、シンプルに対応できるものであろうと思います。もし、より高いセキュリティを求める場合は、追加でその要件に合わせた実装等の検討を進めれば良いでしょう。（悪意を持った第三者向けには追加の対策が必要となるかもしれませんが、カジュアルにiframeで自サイトを埋め込む第三者への対策としては、これで十分であろうと思います）

# サンプルコード

以下では処理が把握しやすいよう、便宜的にインラインでJavaScriptを記述していますが、別ファイルにして難読化した方が良いでしょう。

```html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="notify">
        <p>NG:不正なドメインからリクエストが行われました</p>
    </div>
    <div id="main" style="display:none !important;">
        <p>正規のドメインで表示されるコンテンツ</p>
    </div>
    <script>
        const elemMain = document.getElementById('main');
        const elemNotify = document.getElementById('notify');
        try {
                if (parent.location.href.match(/^https:\/\/www\.example\.com/)){
                        elemNotify.innerHTML = 'OK:正規のドメインからリクエストが行われました';
                        elemMain.style.display = 'block';
                } else {
                        throw new Error();
                }
        } catch(e) {
                elemMain.innerHTML = '';
        }
    </script>
</body>

```

## 実行結果
### 正規のドメインからのリクエスト
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64876/cf96bd55-0ba1-e7b7-20b5-5e50fd26965d.png)

### 不正なドメインからのリクエスト（JavaScriptが無効化されている場合を含む）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64876/fb6b8c5b-085a-42bc-3c56-ca952eefc273.png)
PHPのforを使ってループ処理をしましょう★


処理の回数が決まっている場合や、
特定の処理を行う時にfor文を使ってループ処理をしていきます！

「わーーーぃ!」を7回表示させてみます。

```php:index.php
<?php

for ($i = 1; $i <= 7; $i++) {
   echo 'わーーーぃ!' . PHP_EOL;
}
```

ターミナルで以下を実行します！

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

このように表示されました！

```
~ $ php index.php
わーーーぃ!
わーーーぃ!
わーーーぃ!
わーーーぃ!
わーーーぃ!
わーーーぃ!
わーーーぃ!
~ $
```

次はこちらにカウントをつけて表示させてみます！

先程のコードに変数を追加して

「''」シングルクオーテーションを「""」ダブルクオーテーションに変えます！


```php:index.php
<?php

for ($i = 1; $i <= 7; $i++) {
   echo "$i ・ わーーーぃ!" . PHP_EOL;
}
```

ターミナルに以下を入力します！

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

以下のようにカウンターが表示されました！

```
~ $ php main.php
1 ・ わーーーぃ!
2 ・ わーーーぃ!
3 ・ わーーーぃ!
4 ・ わーーーぃ!
5 ・ わーーーぃ!
6 ・ わーーーぃ!
7 ・ わーーーぃ!
~ $
```
windowsでiverilog その113

#概要　

windowsでiverilogやってみた。
練習問題やってみた。

#練習問題

フィボナッチ数を、求めよ。

#サンプルコード

```

module lut(input wire [3:0] n, output reg [7:0] val);
	always @(n)
	begin
		case(n)
		4'h0:
			val = 8'd1;
		4'h1:
			val = 8'd1;
		4'h2:
			val = 8'd2;
		4'h3:
			val = 8'd3;
		4'h4:
			val = 8'd5;
		4'h5:
			val = 8'd8;
		4'h6:
			val = 8'd13;
		4'h7:
			val = 8'd21;
		4'h8:
			val = 8'd34;
		4'h9:
			val = 8'd55;
		4'ha:
			val = 8'd89;
		endcase
	end
endmodule

module testbench;
	reg [3:0] n;
	wire [7:0] val;
	lut u(.n(n), .val(val));
	initial
	begin
		$display("n val");
		$monitor("%d  %d", n, val);
		n = 4'h0; #10;
		n = 4'h1; #10;
		n = 4'h2; #10;
		n = 4'h3; #10;
		n = 4'h4; #10;
		n = 4'h5; #10;
		n = 4'h6; #10;
		n = 4'h7; #10;
		n = 4'h8; #10;
		n = 4'h9; #10;
		n = 4'ha; #10;
		$finish;
	end
endmodule




```

#結果


```
n val
 0    1
 1    1
 2    2
 3    3
 4    5
 5    8
 6   13
 7   21
 8   34
 9   55
10   89

```

以上。
windowsでiverilog その112

#概要　

windowsでiverilogやってみた。
練習問題やってみた。

#練習問題

1から10までの和を、求めよ。8も9も

#サンプルコード

```
module lut(input wire [3:0] n, output reg [7:0] val);
	always @(n)
	begin
		case(n)
		4'h0:
			val = 8'd0;
		4'h1:
			val = 8'd1;
		4'h2:
			val = 8'd3;
		4'h3:
			val = 8'd6;
		4'h4:
			val = 8'd10;
		4'h5:
			val = 8'd15;
		4'h6:
			val = 8'd21;
		4'h7:
			val = 8'd28;
		4'h8:
			val = 8'd36;
		4'h9:
			val = 8'd45;
		4'ha:
			val = 8'd55;
		endcase
	end
endmodule

module testbench;
	reg [3:0] n;
	wire [7:0] val;
	lut u(.n(n), .val(val));
	initial
	begin
		$display("n val");
		$monitor("%d  %d", n, val);
		n = 4'h0; #10;
		n = 4'h1; #10;
		n = 4'h2; #10;
		n = 4'h3; #10;
		n = 4'h4; #10;
		n = 4'h5; #10;
		n = 4'h6; #10;
		n = 4'h7; #10;
		n = 4'h8; #10;
		n = 4'h9; #10;
		n = 4'ha; #10;
		$finish;
	end
endmodule




```

#結果

```
n val
 0    0
 1    1
 2    3
 3    6
 4   10
 5   15
 6   21
 7   28
 8   36
 9   45
10   55

```
以上。
HomebrewでインストールしたVagrantが動かなくなったときにバージョンを落としたい

なんにも考えずにbrew upgradeってやったらVagrantが動かなくなっていつものバージョン上がったら死ぬやつだったときの対処法メモ。

# Vagrant編

指定したいバージョンのハッシュ値探し

```
cd /usr/local/Homebrew/Library/Taps/homebrew/homebrew-cask/Casks
git log vagrant.rd
```

みつかったらそのハッシュ値でチェックアウト

```
git checkout [hash] vagrant.rd
```

からの再インストール

```
brew reinstall vagrant
vagrant -v
```

バージョン確認して変わってることを確認します。

大丈夫そうならもとに戻しておきます。

```
git reset --hard
```

ヨシ！


# VirtualBox編

vagrantがダメなときだいたいこっちもダメなので一緒に。
やることは一緒だけど一応メモ。

指定したいバージョンのハッシュ値探し

```
cd /usr/local/Homebrew/Library/Taps/homebrew/homebrew-cask/Casks
git log virtualbox.rd
```

みつかったらそのハッシュ値でチェックアウト

```
git checkout [hash] virtualbox.rd
```

からの再インストール

```
brew reinstall virtualbox
virtualbox -v
```

バージョン確認して変わってることを確認します。

大丈夫そうならもとに戻しておきます。

```
git reset --hard
```

ヨシ！
【備忘録】LPIC1レベル1の学習環境を構築する2


####[前回](https://qiita.com/hiro_h/items/080103ce7f997ca56222)の続き

Windows上でUbuntuが動作したわけですが、LPICではRedHat系のコマンドも習得が必要ですのでCentOSを動作させないことには、話しが終わってしまいます。

Microsoft Storeでは提供されていませんので、ググってみると先人の方々が書いている記事に辿り着きました。

####参考にしたサイト
・[「WSLでCentOS7をインストールする」](https://qiita.com/ShikiSouma/items/8a47082e0067e102c5c4)
・[「CentOS7格納先」](https://github.com/wsldl-pg/CentWSL/releases)

####動作しました
CentOS7.zipをDL、解凍後に任意の保存先にフォルダごと保存します。
CentOS7.exeを実行、rootユーザーのパスワードやsshの設定などを施し、通常ログインする一般ユーザーを作成します。
Windows terminalにリンクされていました、これは便利ですね！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/115027/2ae0d3ae-90aa-48a8-0355-26c995a5042d.png)

####ついでに
ssh設定を施しホストPCのTeraTermでSSH接続できました。
これで、出先などでオフライン環境だったとしても使えますね。
![teraOK.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/115027/58f1e34e-edcc-7559-e696-ba921f93a088.png)


これで環境は揃いました！
あずき本の第1章第3部（103）から実習です。

以上です。
[vuetify]v-data-tableのヘッダーのvalueにidを設定してはいけない

# TL;DR
- ソート機能に不具合がでます
- ソート機能を使わないケースでは不具合でなさそうですが、再レンダリングがあるときには不具合ありそう

# はじめに
Vuetifyのv-data-tableを使っていたときにハマりました。

誇張したタイトルなのはお許しください。

表でIDを表示する必要があり、ヘッダーにvalueがidの項目を設定してソートをしていると、`Duplicate keys detected`のwarningが出てソートができなくなってしまいました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191958/395259f7-4cdb-8c78-c128-5cef07c006af.png)

表示しようとしていた表のデータはこのようなものです。

```javascript
header = [
  { text: "ID", value: "id" },
  { text: "text", value: "text" }
]

// idは整数で1始まり
items = [
  { id: 1, text: "text" },
  { id: 2, text: "text" },
  { id: 3, text: "text" }
]
```

# 原因
（多分ですが）

- itemsの`id`とv-data-tableの中でユニークキーとして使われるプロパティの`id`が競合していた

[v-data-table API](https://vuetifyjs.com/ja/api/v-data-table/#links) のitems-key項目に下記の記述がありました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191958/9b5d5dd6-2d39-af12-b604-f19a2ffa308a.png)

# 対応策
いくつか対応策あると思います。

- itemsのkey名`id`を別の名前に変更する（動作確認済み）
    - こだわりなければ、`recordId`など、`xxxId`と変更するのが手っ取り早いと思います
- itemsのidに整数ではない値を設定する（**動作未確認**）
    - そもそも、idに整数が設定されていなければidの重複は起きないはずです
    - しかし、v-data-tableのitemごとのkeyはデフォルトで`id`なので、同じkey名をitemsに設定するのはよくない気がします
- v-data-tableのpropsでitem-keyで`id`以外のユニークなkey名を指定する
    - vuetify側から提供されている方法です
    - 表示させるデータの持っている項目次第では使えないです

おわりです
Step Functions のパラメータで配列を扱いたい

## 組み込み関数の States.Array を使う
https://docs.aws.amazon.com/step-functions/latest/dg/amazon-states-language-intrinsic-functions.html

> **States.Array**
> This intrinsic takes zero or more arguments. The interpreter returns a JSON array containing the Values of the arguments, in the order provided. For example, given the following input:

>```
{
  "Id": 123456
}
```

> You could use

>```
"BuildId.$": "States.Array($.Id)"
```                
Which would return “BuildId”: [123456]

## Example
AWS SDK 統合で EC2 の StartInstances を call する場合場合、API パラメータは以下のような形式です。

```json
{
  "InstanceIds": [
    "MyData"
  ]
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125105/00a8b382-0177-348a-88af-2c34a75cc1f7.png)

ステートマシン実行時の Input で以下の入力を受け取る前提を考えたとき、

```json
{
    "InstanceId": "i-xxxxxxxxxxxxxxxxxxx"
}
```

API パラメータで以下のような設定でステートマシンを保存しようとするとエラーになります。

```json
{
  "InstanceIds.$": [
    "$.InstanceId"
  ]
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125105/722c73e9-de28-3996-a898-1dea72a8cfba.png)

```
The value for the field 'InstanceIds.$' must be a STRING that contains a JSONPath but was an ARRAY
```

このようなケースで組み込み関数の States.Array を使用できます。

```json
{
  "InstanceIds.$": "States.Array($.InstanceId)"
}
```

結果として以下が返されるため、StartInsntaces を正常に実行できます。

```json
{
  "InstanceIds":[
    "i-xxxxxxxxxxxxxxxxxxx"
  ]
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125105/10a8d7ee-82a4-5d42-a6ba-5d56b7bc23ee.png)


簡単ですが、以上です。
【Google Apps Script/Spreadsheet/Gmail】includes()で日付を比較する時に沼に陥ったので解決した方法をまとめておく。

Google Apps Scriptで条件を指定してメールを取得しSpreadsheetに記述するという時に新しいメールかどうかを日付で判断しようと思ってSpreadsheetにある日付を取得してリストにし、includesで比較したら何故か別のSpreadsheetではうまくいったのに、うまくいかな行ことがありその際に解決した方法をまとめておきます。

簡潔解決法をにいうと、

`Date.parse()`

を使って、リスト・Gmailから取得する日付ともに

`Thu Nov 11 2021 21:51:35 GMT+0900 (Japan Standard Time)`

上記形式から以下のように変換して比較しました。

`1636635095000`

その結果、includesでリストを比較できるようになりました。
オンラインIDEのRepl.itでGoogleニュース検索を作りました

## ０．はじめに

Google ニュースを簡単に検索したくなったので、オンラインIDEの[Repl.it](https://replit.com/)でPHPで検索画面を作ってみました。

Repl.itの説明は、以下の記事あたりに紹介されてます。

[60以上の言語が使用可能なブラウザ実行型IDE - Repl.it - ばいばいバイオ](https://www.kimoton.com/entry/20201115/1605449573)

## １．実際の画面やコード

Repl.itで実際に動いているので、そちらをご覧ください。

https://replit.com/@basictomonokai1/Google-News-Search

## ２．参考にした記事

ほぼ丸パクリです…

* [google NewsをRSSで取得してjsonで返却するPHPプログラム](https://www.zip358.com/2018/12/22/google-news%E3%82%92rss%E3%81%A7%E5%8F%96%E5%BE%97%E3%81%97%E3%81%A6json%E3%81%A7%E8%BF%94%E5%8D%B4%E3%81%99%E3%82%8Bphp%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0.html)
* [Google News Rss(API) - Qiita](https://qiita.com/KMD/items/872d8f4eed5d6ebf5df1)

以上