OmniAICreator/Qiita-1.07M huggingface dataset:
flask + plotly + javascript csvグラフ化ツール　概要編

収集した**時系列データ**をwebブラウザ上で簡単に**グラフ化**できるツールです。完成したグラフは**html形式で保存**することができます。
職場ではネットワークアクセスが可能な共有PCにこちらのツールを搭載して業務効率化を図っています。

内容が長くなってしまったため、**[flask + plotly + javascript csvグラフ化ツール　プログラミング編](https://qiita.com/takenoko300/items/c6a599dd07015b10c9b1)**でプログラミングを掲載しています。
まずは**全体の動作イメージ**を伝える**概要編**です。

↓は動作イメージ。
![localhost_8880 および他 6 ページ - 個人 - Microsoft​ Edge 2021-08-11 16-38-49_3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1873853/8e4a1110-7d71-5f04-1561-486ad50baf8d.gif)

# 動作環境
Windows10　（Linuxでも動作確認済み。ただしcsvの文字コードに注意）
python3.7以降

# フォルダ構成

```
$ tree

├── main.py
├── static
|   ├── css
|   |   └── app.css
|   └── js
|       ├── app.js
|       └── main.js
├── temp
└── templates
    └── index.html
```

# 動作
大まかな動作フローは以下のようになっています。
![csvグラフ化ツール.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1873853/11e0356f-e3a7-f544-e5ee-2e888b34868b.png)

### Python実行(Flask起動)
エラーなどがなく実行できたことを確認します。

```
* Serving Flask app 'appold20201218' (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on all addresses.
   WARNING: This is a development server. Do not use it in a production deployment.
 * Running on http://***.***.**.**:8880/ (Press CTRL+C to quit)
```

**ポート番号**はpython文中で指定することができます。

```python:main.py
# port=****の部分でポート番号を変更できる。
if __name__ == '__main__':
    app.run(debug=False, host='0.0.0.0', port=8880)
```

### webブラウザで開く
pythonを実行したPCでwebブラウザを開く場合は
http://localhost:8880
ネットワークアクセス可能なPCでpythonを実行して別PCでアクセスする場合は
http://〇〇〇〇.〇〇.〇.〇:8880　（←PCにネットワークアクセスできるurl）

以下のような画面が表示されればOKです。cssフレームワークはfoundationを用いています。

![スクリーンショット 2021-08-11 154826.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1873853/01ffc9c7-8db5-febe-d7bd-f17b2cada595.png)

### csvファイルをアップロード
csvファイルをアップロードします。ただし、**csvファイルの形式・データに注意してください。**
csvファイルの文字コードは**UTF-8**で、csvファイルのデータは**1列目が時間(シリアル値)**、**2列目以降が時系列データ**、**1行目はデータラベル**としてください。
データラベルが同じであれば**複数ファイルのアップロードも可能**です。
![スクリーンショット 2021-08-11 165549.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1873853/28bafb8b-5775-85a6-c440-d4d54e02c2c6.png)

### グラフ化したい項目を選択
**csvファイルの1行目にあるデータラベル**を抽出するので、そこからグラフ化したい項目を選択します。
「グラフ作成」をクリックすれば、グラフが表示されます。
![スクリーンショット 2021-08-11 170604.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1873853/cba41624-b642-0076-be02-835981ee31e5.png)

### ステータスを編集してグラフ完成
![スクリーンショット 2021-08-11 170930.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1873853/cb70d6c0-044d-2a82-ebbc-2f73f70dfee3.png)

編集できるステータスは以下の通りです。
* グラフタイトル
* x軸のタイトル
* y軸のタイトル
* 第2y軸のタイトル
* x軸の範囲
* y軸の範囲
* 第2y軸の範囲
* 第2y軸に追加するデータ系列（選択したデータ項目から選べます。）

### グラフをhtml形式でダウンロード
作成したグラフは**html形式で保存**することができます。
NULLと '\0' の違い

Q.	`a[i] = NULL` 
	   `a[i] = \0`
上記のどちらが正解だろうか？


`NULL` も`'\0'`もいずれも`0`をあらわしている。

`NULL` はアドレスが `0`
`NULL` はマクロ定義 `#define NULL ((void *)0)`としている。

`'\0'`   は文字コード（ASCIIコード表）が `0` である
文字の`'\0'`：文字コード(ASCII)の番号が `0`

A. `a[i] = '\0'` が正解である。
　 `a[i] = NULL` これは値がポインタと数値を比較してしまっている為である。

まとめ　

`0`	整数の `0`。
`NULL`	どこも参照していないことを表すポインター（マクロ）。
　　　　　値はアドレスの0番（値0）。
空文字（`'\0'`）	ASCIIコード（文字コード）値0（NULL文字）を指す。
空文字列（`""`）	文字'\0'の配列（文字配列）。値はこの配列の先頭アドレスとなる。

整数の`0`，`NULL`，空文字（`'\0'`）は値がともに`0`であるため，結果としては混同して使っても問題ないことが多い。

ただし，空文字列は大きく意味が異なる。空文字列は空文字（`'\0'`）を要素として持つ要素数1の配列である。そのため，単独の空文字列の値は配列の先頭アドレスとなる。空文字列の先頭要素`[0]`は空文字（`'\0'`）であるため値は`0`である。
エイリアス（alias）の設定方法

#エイリアスとは？
エイリアス 【alias】：偽名、別名、通称などの意味を持つ英単語。


つまり、コマンドの別名を設定します。
いくつかのコマンドをまとめて別の名前に設定することが出来ます。

例えば、ls -al と打っていたのを ll と打つだけで実行出来るようにする事が出来ます。

```
$ ll
```
↑ls -lと同じ


# 設定方法
```
$ vim ~/.zshrc
```
でファイルを開き

```
Set up aliases
alias dc='docker-compose'
alias ll='ls -alF'
```
と書き換える。

```
$ source ~/.zshrc　
```
で実行

#よく設定されているもの



```
$ dc up -d　　　　　　　　　　#docker 立ち上げ
```
JS NumberFormat().format 相当のカスタマイズメソッド（js中将string类型转换成currency）



new Intl.NumberFormat().format(this.summary_annualBasisPrem__c);

js中将string类型转换成currency
如果长度在15位以下，就使用NumberFormat().format 
如果长度在15位以上，就是用下面的方法

上記のメソッドはIE１１の場合、１５桁の最大有効数字の制限があるから、１５桁以上の場合は、自動的に四捨五入します。
その故、私が下記のメソッドを書きました。ほぼ同じ作用で、桁数の制限を避けた。
为了解决上面js的方法在ie中自动截取15位有效数字。
我自己写了下面的js 方法，这样的话可以有效避免任何四舍五入的发生

    formatTocurrency(valueFormat){
        let my_summary_PremiumAmount = String(valueFormat);
        let summary_PremiumAmount_list = my_summary_PremiumAmount.split( /(?=(?:...)*$)/ );
        let temp ='';
        for(let i=0;i<summary_PremiumAmount_list.length;i++){
            temp = temp+summary_PremiumAmount_list[i]+',';
        }
        temp = '￥' + temp;
        return temp.slice(0, -1);
    }
GASでkintoneのレコードを条件付きで取得する


kintone運用する中で、GASを使って電話番号が一致するレコードを取得したくなったので書いてみました。

```js
function getCustomer(phone){
    const apiToken = ""; // kintoneで作成したAPIトークン
    const subdomain = ""; // kintone URLの https://***.cybozu.com における"***"の部分
    const appId = ""; //kintoneアプリの https://***.cybozu.com/k/xx/ における"xx"の部分

    const url = "https://" + subdomain + ".cybozu.com/k/v1/records.json?"
                + "app=" + appId
                + "&query=" + encodeURIComponent('phone = "080-1234-5678"'); //"phone"というフィールドコードで作成しカラムを検索条件にする場合

    const formHeader = {
        'X-Cybozu-API-Token': apiToken
    };
    const options = {
        'method': 'get',
        'headers': formHeader,
    };

    var res = UrlFetchApp.fetch(url, options);
    var json = JSON.parse(res.getContentText());
    console.log("length: " + json["records"].length); //該当データの件数
    console.log("response: "+ res); //該当データ内容
    return res;
}
```

複数条件指定したい場合は、`encodeURIComponent(phone="hoge" and email="fuga")`みたいな感じにしておく。

KintoneManager使った方が楽かもしれませんが、参考になれば。
レビューを受けた後のgit管理　メモ


作業中のものをとりあえずコミット

```
$ git commit -m ‘作業中 — 〇〇までの作業完了’
```

```
$ git checkout レビューしてもらったbranch名
```

```
$ git fetch
```

```
$ git merge origin/レビューもらったブランチ名
```
/に気をつける

```
$ dc exec web php artisan config;cache
```

```
$ git checkout 作業ブランチ名
```

```
$ git log
```

```
$ git reset --soft コミットした一個前のcommit. # 
```

```
$ git checkout vendor/*
```

```
$ git checkout .
```

```
$ git add app/Http/Controllers/PostController.php app/Post.php
```

checkoutをしたらlogで確認とfetchでremoteの変更点をとってくる
mergeするときは、自分がいるブランチのリモートブランチをmergeしてからmasterをマージする
Windows 10 WSL2 手動インストール

# Windows 10 WSL2 手動インストール

公式サイトリンク
https://docs.microsoft.com/ja-jp/windows/wsl/install-win10#manual-installation-steps

## 手動インストール手順
### 1. Linux 用 Windows サブシステムを有効にする

管理者権限で PowerShell を起動し、以下を実行します。

```PowerShell
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
```


### 2. WSL 2 の実行に関する要件を確認する

* x64 システムの場合:バージョン 1903 以降、ビルド 18362 以上。
* ARM64 システムの場合:バージョン 2004 以降、ビルド 19041 以上。
* 18362 より前のビルドは WSL 2 をサポートしていません。   
  Windows 更新アシスタントを使用して、お使いのバージョンの Windows を更新します。

バージョンとビルド番号を確認するには、Windows ロゴ キー + R キー を押して、「winver」と入力し、 [OK] を選択します。 

### 3. 仮想マシンの機能を有効にする

```PowerShell
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
```

お使いのマシンを 再起動 して WSL のインストールを完了し、WSL 2 に更新します。

### 4. Linux カーネル更新プログラム パッケージをダウンロードする

1. 最新のパッケージをダウンロードします。  
   * [x64 マシン用 WSL2 Linux カーネル更新プログラム パッケージ](https://wslstorestorage.blob.core.windows.net/wslblob/wsl_update_x64.msi)
   
1. ダウンロードした更新プログラム パッケージを実行します。

### 5. WSL 2 を既定のバージョンとして設定する
PowerShell を開いて次のコマンドを実行し、新しい Linux ディストリビューションをインストールする際の既定のバージョンとして WSL 2 を設定します。

```PowerShell
wsl --set-default-version 2
```

### 5. 選択した Linux ディストリビューションをインストールする
1. [Microsoft Store](https://aka.ms/wslstore) からLinux ディストリビューションを選択する
1. ディストリビューションのページで、[入手] を選択します。
1. 新しくインストールした Linux ディストリビューションを初めて起動すると、コンソール ウィンドウが開き、ファイルが圧縮解除されて PC に格納されるまで 1、2 分待つように求められます。 
1. 新しい Linux ディストリビューションのユーザー アカウントとパスワードを作成する必要があります。
tiktok scroller

たいくつなお仕事のおともに、tiktokスクローラー。
カーソルがwindowにあるときは止まります。

```js:consoleにはっつける
var flag = true
document.body.onmouseover = () => {flag = false}
document.body.onmouseout = () => {flag = true}
setInterval(()=>{
  if (flag) window.scrollBy(0, 300)
}, 3000);
```
raspberry pi とsynologyの連携


#つづき
https://qiita.com/im02kai/items/d4469190cb23a092a141


synologyと連携することで、
DSfileで家の外からインスタに投稿したり
複数のカメラを設置し、同時で早く、動画を作成できます

https://www.synology.com/ja-jp

synologyは、かなり大好きな製品で
今回の使い方以外に、webサーバーにしたり、写真整理のためのiCloudの代わりになったりすごく良いです。
aptができないので、入れられるパッケージは制限されますが、その辺はraspberry piと
連携すれば、解決できます


#役割分担
Raspi
撮影しzip圧縮しFTPで送り,SSHで動画作成をトリガーする

Sinology
トリガーきたら、解凍して動画作成


#raspberry pi
###インストール
sudo apt-get install ncftp
sudo apt-get install sshpass


###スクリプト

前回のffmpeg部分を消して
Cオプションがないと、解凍先でフォルダの多重階層となりました

```shellscript:timelapse.sh


tar -vczf  /home/pi/Desktop/photo.tar.gz -C /home/pi/ Pictures
ncftpput -u synology-user -p password 192.168.100.2 ./tmp/ /home/pi/Desktop/photo.tar.gz

EXIT_V="$?"
if [ "$EXIT_V" = 0 ]; 
    then
        sshpass -p password ssh synology-user@192.168.100.2 /var/services/photo/video.sh

    else
        echo "error" 
fi

```


#synology

###設定　
ssh
https://kb.synology.com/ja-jp/DSM/tutorial/How_to_login_to_DSM_with_root_permission_via_SSH_Telnet

ftp設定
https://kb.synology.com/ja-jp/DSM/tutorial/How_to_access_files_on_Synology_NAS_via_FTP

ffmpeg
最初から入ってます


###ディレクトリ作成
/var/services/photo/tmp/　　#FTP保存先
/var/services/photo/data/　#動画保存先


###スクリプト
```shellscript:video.sh

FILENAME=$(date +"%Y-%m-%d_%H%M")
DATANAME="/var/services/photo/data/"$FILENAME".mp4"

rm -rf /var/services/photo/tmp/Pictures/ &> /dev/null
sleep 1

tar -xvzf /var/services/photo/tmp/photo.tar.gz -C /var/services/photo/tmp/
ffmpeg -f image2 -r 12 -i /var/services/photo/tmp/Pictures/%08d.jpg -r 12 -an -vcodec libx264 $DATANAME


```

#DSfile(iPhone)から確認
ここからダウンロードしてインスタグラムに投稿できます

![IMG_F8BA8B90B8E6-1.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/514937/a6025dbe-5719-0259-142c-1d26b1e191c7.jpeg)
M1 Mac でRailsコマンドが使えなくなった時のメモ

M1 Mac で rbenv 経由で Ruby3.0.2 を入れたらrailsコマンドが以下のエラーで打てなくなった

```terminal:terminal
$ rails s
-bash: /usr/local/bin/rails:/System/Library/Frameworks/Ruby.framework/Versions/2.3/usr/bin/ruby bad interpreter: No such file or directory

$ rails -v
-bash: /usr/local/bin/rails:/System/Library/Frameworks/Ruby.framework/Versions/2.3/usr/bin/ruby bad interpreter: No such file or directory
```

```
$ which rails
/usr/local/bin/rails

# 現状の環境確認
$ which ruby
/Users/takuya/.rbenv/shims/ruby
$ which gem
/Users/takuya/.rbenv/shims/gem
$ which rails
/usr/local/bin/rails
```

## .bash_profileのPATHを消したら治った？

```bash:.bash_profile
export PATH="/usr/local/bin:$PATH" # これを消した
```

よくわからないが.bash_profileの上記PATHを消して`source ~/.bash_profile`し`gem install rails`したら治った。この状態では

```
$ which rails
/Users/takuya/.rbenv/shims/rails
```

となってくれるが`/usr/local/bin/rails`自体も存在する。ただrbenvを入れてる場合、SystemにインストールされたRubyはもちろんのことRailsも無視していいっぽい（rbenvで管理しているRailsの方が優先的に使われる？）

https://stackoverflow.com/questions/58736558/how-to-remove-rails-installation-from-usr-bin-rails

## M1 Mac で node-sass が未対応問題
しかし`rails s`すると`yarn install --check-files`と言われ、実行するとnode-sass関係のエラーがでる。ググると[node-sassがM1 Macに対応していない](https://github.com/sass/node-sass/issues/3033)らしい。

```
error /Users/takuya/my-project/node_modules/node-sass: Command failed.
```

代わりに`yarn remove node-sass`して`yarn add sass sass-loader`して代用しろとの声もあったが、removeの時点で下記エラー。

```
error No lockfile in this directory. Run `yarn install` to generate one.
info Visit https://yarnpkg.com/en/docs/cli/remove for documentation about this command.
```

`npm install sass sass-loader`しても、`rails s`したときに`localhost:3000`のブラウザ側に下記エラー。

```
Node Sass does not yet support your current environment: OS X Unsupported architecture (arm64) 
```

## 応急処置

もうググり倒せど解決しそうにないので、nodebrewで元々入っていたNode.jsのv11.12.0に切り替えてることで解決させた。

```terminal
$ nodebrew use v11.12.0
$ yarn intall --check-files
$ rails s # success
```

ただNode.jsのARM64（M1)対応はv16からなので、nodebrewを使ったとは言え旧バージョンを新しくインストール方法は謎（現に`nodebrew install v14`してもダメだった）。

## 余談

### yarnについて
npmとyarnがともにパッケージ管理マネージャーで、yarnはFacebookが開発したものとは知っていたが、yarnはnpmの上位互換的なソフトらしく、yarn自体はnpmで管理されるらしい。上位互換なのでpackage.jsonもnpmと共用できるようだ。

### nodebrew
nodebrewはNode.jsのパッケージ管理ソフト。他にnvm, nodenvがある。紛らわしいがhomebrewはMacOSのパッケージ管理マネージャー。Node.jsをnodebrew経由で入れたつもりでも、homebrewでyarnを入れると自動的にNode.jsも入ってしまうらしい。こわい。

https://hisa-tech.site/yarn-install-stumble/

> どうやらyarnをhomebrewでインストールのした際にnodeをインストールしてしまうみたい。
その際にnodeのPATHをyarnが使うnodeのPATHにしてしまうので、nodebrew側のnodeが使われなくなってしまう模様。

## 関連コマンド一覧

```terminal:terminal
# rbenv入れ直し
$ brew uninstall rbenv
$ brew uninstall ruby-build

$ brew install rbenv
$ brew install ruby-build

# rbenvの状況確認
$ rbenv install --list
$ rbenv versions

# rails入れ直し
$ gem uninstall rails
$ gem install rails
```

## 参考になりそうな記事

https://teratail.com/questions/346138
【Rails】LINEのように送ったメッセージがチャット画面の一番下に表示される方法

# はじめに
今回はLINEのように最新アイテムが一番下に追加されていくチャットのような画面で、
メッセージが追加されたら画面を自動で下までスクロールする方法について記述します。

記事をコピペしても使えるかと思います！

※前提でjQueryを使用しますので、そちらの導入をお願いいたします。
jQueryの導入：https://qiita.com/shunichfukui/items/d79f38a3af2715ffd218

# 開発環境
Ruby on Rails バージョン2.6.5

<!-- 各チャプター -->

#実装方法
①メッセージを表示させたいビューにidとCSSにoverflow: scroll;（スクロールさせるCSS）を記述
（※私の場合はBootstrapを導入しているので、classでスクロール指定）

``` HTML:
<div class="overflow-auto" id="area">
　　メッセージが表示されるエリア
</div>
```

②jQueryを使用し、自動スクロールを設定（jsファイルに下記を記述）

```JavaScript:
window.onload = function() {
// ↪︎ windowがロードされた時にアクションを実行するように設定
  if (document.getElementById("area")) {
    // ↪︎ areaのIDがある場合に処理を実行させる（これがないとチャット画面がなくても常にJavaScriptが動いてしまいます）
    var scrollPosition = document.getElementById("area").scrollTop;
    // ↪︎ area要素のスクロールされた時の最も高い場所を取得
    var scrollHeight = document.getElementById("area").scrollHeight;
    // ↪︎ area要素自体の最も高い場所を取得
    document.getElementById("area").scrollTop = scrollHeight;
    // ↪︎ area要素のスクロールされた時の最も高い場所をarea要素自体の最も高い場所として指定してあげる
  }
}
```

# 終わりに／完成形
以上でLINEのように送信されたメッセージが要素の下に追加されても、
画面を自動スクロールしてくれます！

チャット画面の自動スクロールについては他にも様々な記述の方法がありますが、
自分としてはこの方法が最もシンプルでわかりやすかったため記述させていただきました！

皆様のご参考になれば幸いです。
クライアントサイド、サーバーサイドでのJavaScriptについて

##JavaScriptの特徴
JavaScriptは環境（実行環境のこと、ランタイムとも言う）によって特徴が変化します。

###ランタイム(run time)
開発したコンピュータプログラムを実行する時のこと。
また言語やOSによっては実行時に特定のソフトウェアが必要になることがあり、
これらはランタイムライブラリ、ランタイムパッケージ、ランタイムモジュール、ランタイムエンジンなどに細かく分けて呼ぶことがあるが、それらを略してランタイムと呼ぶことが多い

####ランタイムライブラリ
ライブラリは便利なプログラムのコードを集めたファイルのことを指します。
なのでランタイムライブラリはランタイムを行うためのプログラムのコードを集めたファイルという意味になります。

####ランタイムパッケージ
ランタイムパッケージとは
プログラムを動かす際に関連する様々な要素を一つにまとめたもののことを指します。


####ランタイムモジュール
モジュールとは内部がより単純な複数の要素で構成され、それ自体がある程度まとまった何らかの意味のある機能を有するようなものを指します。
そのためランタイムモジュールはプログラムを実行するための部品のようなものにあたります。

####ランタイムエンジン
エンジンとは何かに特化したプログラムや機械のことを指します。
例えば検索エンジンは検索に特化したプログラムのことを指します
そのためランタイムエンジンはプログラムの実行に特化したプログラムのことを指します。

###パッケージとライブラリとモジュールの違いは？
違いについてはこちらの記事を参考にさせていただきました。

https://qiita.com/yutaro50/items/f93893a2d7b23cb05461

それぞれの部品のまとまりや規模で用語が変わってきます。
モジュールが部品にあたり、モジュールの集まったものがパッケージ、
パッケージをいくつかまとめてインストールできるようにしたものが
ライブラリ＞パッケージ＞モジュールのようになています。

###変化のパターン
####クライアントサイド
ブラウザ上（ブラウザ上で動く唯一のプログラミング言語）でのJavaScript
→スマホやパソコンのスペックが向上したことで利点が大いに生かされるようになった
**CSR**（Client Side Rendering）が可能になった。

####サーバーサイド
→Node.jsを使用したサーバーサイド側でのJavaScript。
**SSR**（Sever Side Rendering）で利用されることがある。
※ Node.js上で動かすものとして、、SEO対策でクローラーに向けてデータを返したり、スクレイピング(データを収集した上で利用しやすく加工すること)などで使われるpuppeteerが有名である。


つまりクライアント側で動作するJavaScriptとサーバーサイド側で動作するJavaScriptに分かれており、それぞれの特徴を持っています。

###ブラウザ上（ブラウザ上で動く唯一のプログラミング言語）について
JavaScriptは定義した変数や関数を読み取ることのできる範囲が定められている
→ スコープという

大きく分けて
１、グローバルスコープ
２、ローカルスコープ
の２つに分けることができる。

####グローバルスコープ
グローバルスコープには変数のvarやlet,constが存在するが、厳密にはvarは違う部類に入る。
変数としてvarが存在するが、varはwindowオブジェクト（グローバルスコープ）を通して他のファイルからもアクセスできてしまうため、非推奨となった。
その代わりとしてES6から登場したのがletとcoustであり、これらは厳密にはグローバルスコープではなく、スクリプトスコープに分類される。

####ローカルスコープ
ローカルスコープはブロックスコープと関数スコープがあり、{}の中の変数のことを示す。

また、ある関数スコープが他の関数スコープを含んだ状態のことを**スコープチェーン**という。

####関数と無名関数との違い
・関数→**ホイスティング**が発生することにより、後から変数を定義しても呼べちゃう
・無名関数→ホイスティングが発生しない→先に定義付けを行う必要がある

後から定義づけを行う→コードが汚くなり、可読性が下がる

Javascriptはhtmlを直接的に操作することができない
→htmlを**DOM**（Document Object Model）に変換することで操作可能となる。

##jQuery
・ライブラリ（引用しやすい便利ツールが集まったもの）の一種
・DOM操作を$()で行うことでコードが見やすくなる
・JavaScriptに比べコードが簡潔なので書き手も読み手も見やすいコードを書くことができる

##Vue
・フレームワーク（ライブラリーの一種だが→拘束力が強く主導権をガッツリ握ることが多い）
の一種だが公式は、
「Vueは**プログレッシブフレームワーク**であり、フレームワークではあるがライブラリーのように少しだけ使うこともできる」と言っている。



##jQueryとVueの違い
大きな違いはDOM操作を自動（リアクティブシステム）で行なってくれるか自分で行なう必要があるかどうか
→大規模になるほどVueで書いた方が綺麗で整ったコードになる。
CocoaPodsで登録されているレポジトリが消えてる！

Swift初心者です。
[Realmを使用した日記アプリ](https://qiita.com/shxun6934/items/e4e6e81cecf68b22bdc3)の記事を参考に、アプリを作ろう！と思い立った際にCocoaPods内のJBDatePickerを入れようとした際に起きた問題への解決法をまとめておきます。

## pod install→JBDataPickerが入らない

```
Diary % pod install
```
を実行しても、
![スクリーンショット 2021-08-12 15.51.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/984400/bf207015-6048-cd45-6c44-28741110bf2c.png)
ののち、giuhubのログインを求められた後、
![スクリーンショット 2021-08-12 15.49.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/984400/71d7ca23-500d-a9a3-32b6-8f1f87828f6d.png)
が表示され、困ってしまいました。

##原因
[cocapodsのJBDatePicker](https://cocoapods.org/pods/JBDatePicker)を見に行くと、指定されているレポジトリが
> https://github.com/Tuslareb/JBDatePicker

となっており、すでに存在しておらず、参照できなくてエラーが吐かれていた様子

##解決法
代わりに、
[https://github.com/carabina/JBDatePicker](https://github.com/carabina/JBDatePicker)か、
[https://github.com/myfitnesspal/JBDatePicker](https://github.com/myfitnesspal/JBDatePicker)を指定する。
今回はmyfitnesspal/JBDatePickerを使用。(こちらはcarabinaをフォークしたもの)

pod installをする前に、pod initコマンドで作成したPodfile内にて

```rb
# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'

target 'Diary' do
  # Comment the next line if you don't want to use dynamic frameworks
  use_frameworks!

  pod 'JBDatePicker', :git => 'https://github.com/myfitnesspal/JBDatePicker'
  pod 'RealmSwift'

  # Pods for Diary

end
```
のように取り込みたい外部ライブラリを指定する。

- 単に取り込みたい時は
`pod 'RealmSwift'`
のようにpodの後に''で囲んで指定するだけでよいが
- 今回は、gitを指定するため
`pod 'JBDatePicker', :git => 'https://github.com/myfitnesspal/JBDatePicker'`
のようにgitリンクを追記してあげれば、正しく読み込める。(masterの時)
- もし、特定のブランチを指定したいときは
`pod 'JBDatePicker', :git => 'https://github.com/myfitnesspal/JBDatePicker', :branch => 'hoge'`のように指定可能。

##参考
https://teratail.com/questions/318501
https://dev.classmethod.jp/articles/cocoapods/
[Azure] App Serviceをスワップした時に、再起動しないケースがあった

## はじめに

Azure App Serviceでは２つのスロットをスワップすることで、ダウンタイム無しでリリースすることが出来ます。

そのスワップ中に「インスタンスが再起動する」と説明にあるのですが、実際は再起動しないケースがありました。

## 結論

マイクロソフト サポートに問い合わせた結果、
**スロット間でアプリケーション設定に差異がない場合は再起動しない**
ということが分かりました。

これは不具合などではなく**正しい動作**、とのことです。

## 何が起こったのか

運用中のアプリケーションではWinCacheを使用したキャッシュ戦略を構成しています。
アプリケーションをリリースする時は、スワップ時の再起動によりキャッシュデータがクリアされることを想定していました。

しかし、このキャッシュデータに変更が生じるアップデートをリリースした時、**キャッシュデータが更新されていないと思われる現象**が発生し、アプリケーションエラーによりサービスがダウンしました。

## 原因が判明するまでの経緯

> スワップ時の再起動によりキャッシュデータがクリアされることを想定していました。

これは動作確認した結果を踏まえて手順を構成したのですが、実際に運用していて、スワップ時の挙動に疑問を感じることがありました。

そこで、そもそも「スワップ時にインスタンスが再起動する」という認識は正しいのか、という点から調べることにしました。

その結果、これらのことが判明しました。

- スロット間でアプリケーション設定に差異がない場合は再起動しない
- 当時のログから、再起動はされなかった
- アプリケーション設定に差異は無かった

よって問題が起こった原因は「アプリケーション設定に差異は無かったのでスワップ中に再起動せず、キャッシュデータがクリアされなかった」という結論に至りました。

## 解決方法について

これから上記の事実を踏まえて「リリース時にキャッシュデータをクリアする方法」を改めて考えることになります。

現状の手順で考えるなら、適当な設定（バージョン番号やリリース日時）などで差異を作って再起動を強制する方法があると思います。
また再起動は手段でしかないので、カスタムウォームアップを利用するのも良さそうです。

ちなみに、**スワップ中の再起動を強制するオプションのようなものは無い**、とのことです。

## おわりに

Webアプリケーションに関する情報はLAMP環境が多いので、AzureやIISに関する調査は苦労します。
何かの参考になれば幸いです。
【3章】Javaを学ぼう

#小数について

##double型
Javaでは整数を扱う際に用いられるデータ型の**int型**と、小数を扱う際に用いられるデータ型の**double型**があります。よく用いられるというだけで、あくまでも整数や小数を扱う上での型のひとつとして捉えてください。

```java:数値のデータ型
  5  ・・・・ int型
(整数)

 1.28  ・・・・ double型
(小数)
```

##double型の変数について
整数とは小数点以下を持たない数です。一方小数とは「1.28」「-3.7」のように小数点以下を持つ数になります。
例えば、1はint型ですが、1.0はdouble型になります。

```java:Main.java
double number = 5.14;
System.out.println(number);
```

出力結果↓

```java:コンソール
5.14
```

double型も数値ですので、計算が可能です。

```java:Main.java
double number1 = 5.1;
double number2 = 2.9;

System.out.println(number1 + number2);
System.out.println(number1 - number2);
```

出力結果↓

```java:コンソール
8.0
2.2
```

##計算時の自動型変換について
int型とdouble型の計算では結果はdouble型になります。これは計算の過程でint型がdouble型に変換されるためです。よって「5 / 2.0」もしくは「5.0 / 2」の結果は2.5になります。5を5.0にするように、整数は必ず小数でも表せるため、Javaが自動で型変換を行ってくれます。
それでは、例えばint型の変数同士の割り算で、正確な値を出したいときはどうすればよいでしょうか。
結論から言うとint型の変数同士を割り算した際、もし割り切れない数が出た場合は正確な値までは表示されません。

```java:Main.java
double number1 = 17;
double number2 = 3;

System.out.println(number1 / number2);
```

出力結果↓

```java:コンソール
5
```

int型同士の割り算では、上記の出力結果のように「5」となり、「5.67」とはなりません。
このような場合には強制的に型変換を行います。

##（強制型変換）キャストについて
強制的に型変換を行うことをキャストと呼び、**(変換したいデータ型)値**とすることで強制的にデータ型を変更できます。上記のint型同士の値から、最終的にdouble型の計算結果を得たい場合、どちらか1つをキャストしてあげれば、出力結果はdouble型になります。

```java:Main.java
double number1 = 17;
double number2 = 3;

System.out.println((double)number1 / number2);
      //number1の値がdouble型に変換される 17.0 / number2
```

出力結果↓

```java:コンソール
5.67
```

以上が今回の記事の内容になります。
次章に続きますので、もしよろしければ是非ご覧ください！
最後までご覧いただきまして、ありがとうございました！
投稿にユーザーIDを紐づけたい


# 投稿時に下記のエラーが出る
## laravel sql エラー: SQLSTATE[HY000]: General error: 1364 Field 'user_id' doesn't have a default value
user_idは初期値をもっていないとあるが、つまりはuser_idが入力できていない（空っぽ）ということ。

 ![スクリーンショット 2021-08-12 15.43.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1880772/b7176577-3484-77c3-b119-95e211090f7d.png)

エラーが出たときのコントローラーの記述。

```php:BlogController.php
    public function store(Request $request){
        // ブログのデータ（BlogPostRequest）を$requestで受け取る
        $inputs = $request->all();

        DB::beginTransaction();
        try{
            // ブログを登録
            Blog::create($inputs);
            DB::commit();
        } catch(\Thorwable $e){
            DB::rollback();
            abort(500);
        }


        \Session::flash('err_msg2','ブログを登録しました');
        return redirect(route('blogs'));
    }
```

モデルのfillableにuser_idを追記することも忘れてない。

```php:Blog.php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Blog extends Model
{
    use HasFactory;
    
    // テーブル名を明示
    protected $table = 'blogs';

    //可変項目（Modelを継承したBlogクラスを扱えば、以下のカラムを操作できる）
    protected $fillable = 
    [
        'title',
        'content',
        'user_id'
    ];

    public function user()
    {
        return $this->belongsTo(User::class);
    }

}
```




下記のように改めることで解決した。


```BlogController.php
    public function store(BlogPostRequest $request){
        // ブログのデータ（BlogPostRequest）を$requestで受け取る
        $user = Auth::user(); //追記
        $id = Auth::id(); //追記
        $inputs = ['user_id'=>$user->id,'title'=>$request->title, 'content'=>$request->content]; //変更

        DB::beginTransaction();
        try{
            // ブログを登録
            Blog::create($inputs);
            DB::commit();
        } catch(\Thorwable $e){
            DB::rollback();
            abort(500);
        }


        \Session::flash('err_msg2','ブログを登録しました');
        return redirect(route('blogs'));
    }
```

Auth::userでログイン済みのユーザー情報を取得。
$inputsの中身を配列にして、user_idも入力内容に含めた。
use文でAuthファサードやUserモデルを使えるようにしておくことも忘れてはいけない。


```php:BlogController.php
namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Models\User; //追記
use Illuminate\Support\Facades\Auth; //追記
use App\Http\Requests\BlogPostRequest; //フォームリクエストでバリデーションを行う場合に追記
use Illuminate\Support\Facades\DB;
指定した距離よりも近づかないように、ランダムに点を平面に並べる

###はじめに
blenderのテクスチャマップで、模様の並びがランダムで、お互いに重ならないようにする必要があったので、指定した距離よりも近づかないように、ランダムに点を平面に並べるリストを作るスクリプトを書いてみた。

ランダムに点を取って、それと、既存の点の距離を計算して、距離が十分なら新たな点として採用、という仕組みなので、効率は悪い。

並べる模様が、指定した面積からはみ出さないように、変数出力をする際に、yohaku = round(distance/2)、を設定してある。

```python
import random

dot_list = [] #点を入れるリスト。入っているのは、２次元のタプル。

distance = 70 #これ以上離れていれば良い距離。並べるものを円形としたら、その直径より大きな値にする

point_num = 20 #模様の個数

size_x = 1024 #下地の横のサイズ
size_y = 1024 #下地の縦のサイズ

#与えられた既存の点のリストと、新たに作った点に対して、新たな点が、既存の点の一覧と、離れているかの確認。
#近ければ、flagに１を足す。戻り値であるflagが０なら、離れているのでヨシ。メインプログラムで、点をリストに追加。
def dis_check(point_list,new_point):
  flag = 0
  for i in point_list:
    if ((i[0] - new_point[0])**2 + (i[1] - new_point[1])**2) < distance**2:
      flag = flag + 1
  return flag

#point_numで指定された個数分のｘｙ座標を作って、リストに追加
point_current_num = 0 #何個まで作ったか記録用
yohaku = round(distance/2) #並べるものが平面からはみ出さないよう、ランダム生成する整数の範囲を調整。
while point_current_num < point_num:
  new_point = random.randint(yohaku,size_x - yohaku),random.randint(yohaku,size_y - yohaku)
  if dis_check(dot_list,new_point) == 0:
    dot_list.append(new_point)
    point_current_num = point_current_num + 1
```

##作ったリストを元に図を描いて、散らばり具合を確認するスクリプト。実行フォルダに、texture.jpgを作る

```python
from PIL import Image, ImageDraw
img = Image.new("RGB",(size_x,size_y),(255,255,255)) #下地
draw = ImageDraw.Draw(img)

for i in dot_list:
  draw.ellipse((i[0] - yohaku, i[1] - yohaku, i[0] + yohaku, i[1] + yohaku),fill=(0,0,0))
img.save('texture.jpg')
img.show()
```

##出力画像サンプル
![20210812_03_kansei.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684864/9aa68518-4bbd-5260-0ca8-7340aa41b6b3.jpeg)

##模様を、外部ファイルから読み込む場合には、さきほどのスクリプトを以下のように変える

```python
from PIL import Image

mark = Image.open('mark.jpg') #張り付ける画像。同じディレクトリに置いておく 

img = Image.new("RGB",(size_x,size_y),(255,255,255)) 

for i in dot_list:
  img.paste(mark,i)
img.save('texture_mark.jpg')
img
```
エラーメッセージを日本語にする方法

##環境
・Rails 6.1.3
##エラーメッセージを日本語にする方法
###1日本語に設定

```config/application.rb
class Application < Rails::Application
   config.load_defaults 6.1
   config.time_zone = 'Tokyo'
    config.active_record.default_timezone = :local
    config.i18n.default_locale = :ja
    config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}').to_s]
 end
```
###2　rails-i18nのインストール

```Gemfile
gem 'rails-i18n'
```
###3config/localesの下にja.ymlを設置
###4ja.ymlに日本語を設定するためのコードを書く

```config/locales/ja.yml
ja:
  activerecord:
    models:
      user: ユーザー
      post: 投稿
    attributes:
      user:
        name: ユーザー名
        email: メールアドレス
        password: パスワード
        blank: が空になっています
      post:
        content: 投稿
        blank: が空になっています
```
config/locales/ja.ymlのコードに"blank: が空になっています"を記述したのは

```
translation missing: ja.activerecord.errors.models.post.attributes.user.required
```
や

```
translation missing: ja.activerecord.errors.models.user.attributes.password.blank
```
などのエラーが起こるのを防ぐためです（実際自分が下記記事と同じエラーに遭遇しました。）
[translation missing〜　エラーについて](https://qiita.com/mikd/items/eda6a5c8e9571034a850)
##参考記事
[translation missing〜　エラーについて](https://qiita.com/mikd/items/eda6a5c8e9571034a850)
[translation missing: ja.activerecord〜のエラー対応]
(https://qiita.com/nkekisasa222/items/0c566ced53f7ee47d67d)
[[初学者]Railsのi18nによる日本語化対応]
(https://qiita.com/shimadama/items/7e5c3d75c9a9f51abdd5)
Couchbase Server機能解説：スコープとコレクション

## スコープとコレクションの概要

Couchbase Serverは、ドキュメント管理のために、スコープとコレクションを提供します。これらを用いて、バケット内でドキュメントを分類・整理できます。

- コレクションは、複数のドキュメントをグループ化するための機構です。
- スコープは、複数のコレクションをグループ化するための機構です。

#### コレクションの存在意義

ドキュメントをコレクションによってグループ化することによって、ドキュメントの種類（ビジネスエンティティ）の違いを、コレクションによって表現することができます。
標準SQLをJSONデータへのアクセスのために拡張したクエリ言語であるN1QLクエリでは、コレクションは、リレーショナルデータベースにおけるテーブル相当の位置を占めることになります（具体的にいえば、FROM句で用いられます）。これによって、リレーショナルデータベースからCouchbase Serverへの移行が容易に実現されます（端的にいえば、データ構造を変更しない限り、同じクエリを用いることができます）。
念のため付け加えると、コレクションによって、その中に含まれるドキュメントの構造が一律のものとして規定されるわけではないため、JSONフォーマットの持つ柔軟性が損なわれることはありません。

#### スコープの存在意義

スコープによって、コレクションをグループ化することによって、ビジネスエンティティのグループを管理することができます。これによって、マルチテナンシーを実現することができます。Couchbase Serverは、スコープとコレクションによってアクセス権限を管理する機能を提供しています。

## スコープとコレクションの機能

### スコープとコレクションの適用範囲

スコープとコレクションによるデータ管理によって、Couchbase Serverの様々な機能において、以下が可能になります。

- スコープとコレクションごとのアクセス権を割り当てることができます。これによって、各ユーザー/アプリケーションが必要なコレクションのみにアクセスできるようにできます。
- コレクションにインデックスを付けるができます（スコープにインデックスを付けることはできません）。

また、Couchbase Serverの以下の機能において、スコープとコレクションが利用可能です。

- N1QLクエリ
- XDCR
- バックアップ
- 統計情報（cbstatsコマンド）


### スコープとコレクションの基本仕様

- クラスタごとに最大1000個のスコープを作成できます。
- コレクション名は、スコープ内で一意である必要があります。
- クラスタごとに最大1000のコレクションを作成できます。
- アイテム名(ドキュメントのキー)は、コレクション内で一意である必要があります。


### スコープとコレクションの作成・管理

スコープとコレクションは、以下を使用して作成・管理できます。

- Web管理コンソール
- CLI
- REST API
- N1QL
- SDK

### デフォルトのスコープとコレクション

すべてのバケットには、デフォルトのスコープが自動的に与えられ、その中にはデフォルトのコレクションが与えられます。それぞれには、`_default`という名前が付けられています。

特定のスコープまたはコレクションを指定せずに作成されたドキュメントは、デフォルトのスコープ内のデフォルトのコレクションに保存されます。
また、以下に注意する必要があります。

- デフォルトのスコープは削除できません
- デフォルトのコレクションは、CLIまたはREST APIのいずれかを使用して削除できます。 ただし、一旦削除すると、再作成できなくなります。

#### バージョン間の整合性
（スコープとコレクションが初めて導入された）7.0より前のバージョンのCouchbase Serverからアップグレードすると、既存のすべてのデータ（ドキュメント）がデフォルトのスコープとデフォルトのコレクションに自動的に配置されます。

### ユーザー定義のスコープとコレクションの命名
ユーザー定義のスコープとコレクションには、ユーザー定義の名前を割り当てますが、以下を満たす必要があります。

- 長さは1〜30文字
- 大文字と小文字が区別されます
- アルファベット(A-Z、a-z)、と数字(0-9)、記号として、`_`, `-`と`%`のみを含めることができます（ただし、`_`または`%`で始めることはできません）

スコープ内の名前空間は、他のスコープの名前空間から独立しています。同一バケット内の複数のスコープに同じコレクション名が存在することができます。同様に、コレクション内の名前空間は、他のコレクションの名前空間から独立しています。その結果、あるバケット内の同じ(または、異なる)スコープの複数のコレクションに、同じドキュメントキーが存在することができます。


### スコープとコレクションのアクセス管理
スコープとコレクションへのアクセスは、ロール（役割）ベースのアクセス制御（RBAC）によって管理されます。


### コレクションとドキュメント有効期限管理
コレクションに対して有効期限を設定することができます。これは、コレクション内のドキュメントの最大有効期限を決定します。
Couchbase Serverにおける有効期限の詳細については、ここでは触れません。



### 関連情報

[Couchbase公式ドキュメント Scope and Collection](https://docs.couchbase.com/server/current/learn/data/scopes-and-collections.html)
Pyhtonのエラーコードを投げると解説してくれるWebアプリを作った

#はじめに
前回"Pythonのエラーコードを投げると解説してくれるSlackBotを作った話"という記事を投稿しました。
当初は学部内での使用を想定していたのですが、思ったより外から使ってみたいとの声があり、Webアプリ化しました。

https://qiita.com/ituyama/items/3b7d6e6ecb7717568be0

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/509235/14ff0b12-4227-06af-7014-9836e3b5e5d8.png)


#完成したもの

http://ituyama.com/errorsearch/

#使ったもの
・GithubPages
・Bootstrap4
#画面

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/509235/902aa16e-f307-a293-5e76-7da17137043a.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/509235/3bf1728d-c69a-b052-a669-016a9c498fd8.png)

このような感じで、エラーコードを投げると画像とともにエラーを解説します。

#構造
Formに入れられたエラーコードをJSで正規表現でエラーを分け、該当エラー解説文と画像を表示します。
#あとがき
今回はSlackBotをWebアプリに作り替えるお話でした。
まだ全てのエラーコードを収録しているわけではないので、もし乗ってないエラーコードを見つけたらGitHubのIssueで教えてくれると嬉しいです。

https://github.com/ituyama/errorsearch
M5StickC PlusでGrove温湿度センサ(DHT11)を試す

#1. 外観

温度と湿度を表示するだけ。

![DSC_0230_2.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/68547/746af5ee-902f-b3d6-32fb-4a58a60cd275.jpeg)

#2. 環境

* [M5StickC Plus](https://www.switch-science.com/catalog/6470/)
* [Grove温湿度センサ 101020011 (SEN11301P)](https://www.seeedstudio.com/Grove-Temperature-Humidity-Sensor-DHT11.html)
* Arduino IDE 1.8.15

#3. 接続

Groveの4ピンケーブルで接続するだけ。

| M5StickC Plus | Grove 温湿度センサ | Memo |
|:-:|:-:|:-:|
| G (GND) | GND | - |
| V OUT (5V) | VCC | + |
| G32 | NC | 接続なし |
| G33 | SIG | 信号 |

#4. ライブラリのインストール

Arduino IDEのライブラリマネージャで **Grove Temperature And humidity Sensor** を検索し、インストールしておきます。

#5. スケッチ

```cpp:Temp_Humi_DHT11.ino
#include <M5StickCPlus.h>
#include <DHT.h>

DHT dht(33, DHT11);     // センサ初期化(G33使用, センサータイプはDHT11)

void setup() {
  M5.begin();
  M5.Axp.ScreenBreath(9);     // 7(2.5V) -> 12(3.0V)
  M5.Lcd.setRotation(1);      // 画面の向き
  M5.Lcd.fillScreen(BLACK);   // 黒で塗りつぶし
  M5.Lcd.setTextSize(2);      // テキストサイズを指定
  
  dht.begin();
}

void loop() {
  delay(5000);
  float tmp = dht.readTemperature();    // 温度Cの読み取り
  float hum = dht.readHumidity();       // 湿度%の読み取り

  M5.Lcd.setCursor(0, 0);               // 基本位置決め
  M5.Lcd.printf("\n");
  M5.Lcd.printf(" Temperature:\n");
  M5.Lcd.printf("  %4.1f 'C\n", tmp);    // 温度を表示
  M5.Lcd.printf(" Humidity:\n");
  M5.Lcd.printf("  %4.1f %%\n", hum);   // 湿度を表示
}
```
以上です。
ASP.NET MVCで生クエリではなくLINQ to entitiesを使用したほうがよいと言われて(自分用)


マークダウン記法になれていないので上手く記事を書けない点についてはご了承🙏

ASP.NET MVCで生クエリではなくLINQ to entitiesを使用したほうがよいと言われて
自分で調べてみたところ、文字列ではなくコードを書くようにSQL文を書く感じだとわかった。(理解が甘いのはわかっている)

ゴールはDBから情報を取得し、Viewに渡してHTMLのテーブルに表示させること。
View側の<span>@</span>modelは使用できないとする。
ここではViewにforeachで回せる形(ienumerable)で渡すことだけを考える。

自分なりに書いてみた。

```C#:Controller_文字列Ver
var model = this.db.Database.SqlQuery<ビューモデル名>(@"
    select
        a.id
        ,p.name
        ,p.kana
        ,p.gender
        ,p.birthday
        ,a.code
    from
        person p
    left outer join app a
    on
    p.personid = a.personid
    where
    a.code = 'コード名' ").ToList();

this.ViewBag.data = model;
```

```C#:Controller_変更後
var query =
    (from p in db.person
    join a in db.app
    on p.personid equals a.personid
    where a.code == 'コード名'
    select new
    {
        id = a.id,
        name = p.name,
        kana = p.kana,
        gender = p.gender,
        birthday = p.birthday,
        code = a.code
    }).ToList();

var VMs = new List<ビューモデル名>();

foreach (var i in query){
    ビューモデル名 VM = new ビューモデル名();
    VM.id = i.id;
    VM.name = i.name;
    VM.kana = i.kana;
    VM.gender = i.gender;
    VM.birthday = i.birthday;
    VM.code = i.code;
    VMs.Add(VM);
}

this.ViewBag.data = VMs;
```

変更後で困った点はqueryで取得できたものをそのままViewBagに渡しても、ienumerableではなく、Objectとなってしまっていた。
無理やりListの中に入れて渡したが、改善(Linq自体の機能の理解)の余地がありそう。
AWS VPC周りのネットワーク要素のER図解


```plantuml

hide empty fields
hide empty methods

class Region
class "AZ\n(AvailabilityZone)" as AZ

class "IGW\n(InternetGateway)" as InternetGateway 
class NATGateway

class VPC
interface Subnet

class RouteTable

class NetworkACL

Region ||..|{ AZ
AZ ||..|{ VPC: /16, /28, AZはVPC作成時に指定（変更不可）。
VPC ||..|{ Subnet: Subnet最大数は、200
Subnet }|..|| RouteTable
Subnet ||..|| NetworkACL

InternetGateway |o...|| VPC
NATGateway --> AZ
Subnet |o..o| NATGateway
VPC ||..|| VGW
VPC ||..o| VPCEndpoint
VPC |o..o| VPC: VPC peering
```

```plantuml
hide empty fields
hide empty methods
namespace ClassDiagram {
interface Gateway
class InternetGateway implements Gateway
class NatGateway implements Gateway
class VGW implements Gateway
class "Egress-Only InternetGateway" implements Gateway
class "Carrier Gateway" implements Gateway

interface Subnet
class PublicSubnet implements Subnet
class PrivateSubnet implements Subnet

abstract Instance {
    GroupSecurity
}
class EC2 implements Instance {
    GroupSecurity
}
```

# 略語
| 略称 | 名称 |
|:--|:--|
| AZ | Availability Zone | 
| VPC | Virtual Private Cloud  |
| IGW  | Internet Gateway  |
| ACL  | Access Control List  |
| VGW  | Virtual Private Gateway  |
| NAT  | Network Address Translation  |

# ネットワーク
## VPC
AWSにおけるトップレベルのネットワーク定義単位。
CIDRを指定し、プライベートIPアドレス範囲（数）を決定する。

## サブネット
### プライベートサブネット
サブネット作成時のデフォルト。
インターネットに接続しないリソースに設定する。

### パブリックサブネット
インターネットに接続するリソースに設定する。

# Gateway
## Internet Gateway
IPv4専用のAWS内からインターネットへのアクセスゲートウェイ。

## Transit Gateway
Hub。
VPC間、DirectConnect、オンプレミスなどの通信をルーティングできる。

## Egress-Only インターネットゲートウェイ
IPv6専用のInternet Gateway

# Elastic IP
IPとサービスを紐づける。
サービス障害時に、IPに紐づくサービスを切り替えることで迅速な対処が可能。

# 何と何をつなげる？
## VPC と AWSサービス
### VPCエンドポイント（Gateway型）
AWSサービスがVPCエンドポイントに対応している場合に利用可能。
無料。グローバルIPが用いられるが、AWS間通信は閉域（[FAQ参照](https://aws.amazon.com/jp/vpc/faqs/)で完結。

### VPCエンドポイント（PrivateLink型）
EC2などはこちら。AWS内で通信成立。
有料。

## VPC と VPC
### VPC Peering
https://docs.aws.amazon.com/ja_jp/vpc/latest/peering/what-is-vpc-peering.html
有料。

## VPC と インターネット
### AWS Internet Gateway
用意するもの
* VPC
* VPCにアタッチされたパブリックサブネット
* パプリックサブネットに属しているインスタンス
* `0.0.0.0`を割り当てられたパブリックサブネット
* `::/0`を割り当てられたパブリックサブネット（IPv6通信するなら）

### AWS NAT Gateway
**用途**
インターネットへのアクセスは必要とするが、インターネットからのアクセスは必要としない場合。つまりアウトバウンド通信のみを行いたい場合。
Privateサブネットからのインターネットアクセスに重宝。
実際には、Privateサブネット→Publicサブネット（NAT Gateway）→インターネット。

[ユースケース](https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/nat-gateway-scenarios.html)
#### Public NAT Gateway

#### Private NAT Gateway
特定のIPへの通信のみ行いたい場合。

### インターネット -> VPC by IPv4
* AWS Internet Gatewayの要件
* Elastic IPの設定


## オンプレミス と VPC
* Internet Gateway
* Private NAT Gateway + Transit Gateway
* Public NAT Gateway
* AWS Site-to-Site VPN	
* AWS Client VPN
* AWSVPN CloudHub
AWS : ssh接続で手こずった(scpコマンド、iオプション)

## はじめに

railsアプリのインフラをAWS化させようと学習中。

教材に従ってssh接続（WEBサーバーからDBサーバーに）にする際に
linuxコマンドのscpが上手く使いこなせなかったので、メモに残す。



## 学習教材
`・さわって学ぶクラウドインフラAmazonWebServices基礎からのネットワーク&サーバー構築改訂3版`

ハマった章：`6-4 踏み台サーバーを経由してSSHで接続する`



## やりたい事

`DBサーバー（プライベートサブネット）へのssh接続を可能にするために`
`WEBサーバー（パブリックサブネット）`に`秘密鍵を格納しておく`必要がある。

必要手順

１、前章（6-3）以前で作成された秘密鍵をscpコマンドを使用して、
　　WEBサーバーにコピーする。

２、コピーできたら、WEBサーバーにssh接続をして
　　ファイル権限を所有者が読み取りだけできるよう設定する。

３、WEBサーバーに置いている秘密鍵を使って
　　DBサーバーにssh接続する。



## ハマった部分

上記の１で、scpコマンドの文法が曖昧なまま実行してしまい
思うように挙動せず、迷走してしまった。




## １、いざscpコマンドでコピー

scpは、Secure Copyの略称という事で
具体的には、ssh通信でcpコマンドが使えるみたいです。
（`ローカルからリモートに対象ファイルをコピーできる。`）


秘密鍵をコピーする際の文法としては、下記コードの通り、
`・オプション(-i)を使用して認証させる秘密鍵ファイルを設定`
`・コピー元ファイルのパス`
`・コピー先のパス`
の順番で記述したら良い。

```:ターミナル

% scp -i <認証させる秘密鍵ファイル> <コピー元ファイル> <コピー先>

```

今回は
・-iで認証させる秘密鍵ファイルと
・コピー元ファイル
が`同一のため、`個人的にコードが読み解きにくかった…

```:ターミナル（ローカル）

% scp -i ~/.ssh/my-key.pem ~/.ssh/my-key.pem ec2-user@パブリックアドレス(DNSアドレス):~/

```

私はMacユーザーで、下記記事を参考に.sshディレクトリに
秘密鍵を格納していたので、パスは下記記述としている。

https://qiita.com/3naU/items/b5c5875b557bc55f96df

コピー先のパス指定で、EC2のパブリックアドレスの後に
`:~/`としているのでEC2のルートディレクトリに格納される。

## ダメな例

これは自分の例で、`オプションiを書けば`
`コピー元の秘密鍵ファイルが読み取られる`　かつ　`コピー元ファイルとして設定される`
と誤認してしまっていた。

面倒ではあるけど、オプションiの認証ファイルは
別で指定してあげないといけないらしい。

```:ターミナル

% scp -i ~/.ssh/my-key.pem ec2-user@パブリックアドレス(DNSアドレス):~/

```

## ２、ファイル権限の変更

手順は以下の通り。

・WEBサーバー（パブリックサブネット）にssh接続する。
・ファイルがコピーできているか確認する。
・コピーできていれば、chmodで所有者だけ読取可能に変更する。

コードで表すと…


```shell:ターミナル（ローカル）

# EC2へssh接続
% ssh -i ~/.ssh/my-key.pem ec2-user@パブリックアドレス(DNSアドレス)

# EC2内でファイル確認
% ls

# 同ファイルの権限を変更
% chmod 400 my-key.pem

# 変更後のチェック
% ls -l

```


## ３、ファイル権限の変更

教材の通り、秘密鍵を使用して
EC2(パブリックサブネット)からDBサーバー（プライベートサブネット）にssh接続する。


```shell:ターミナル（EC2）

% ssh -i my-key.pem ec2-user@10.0.2.10

```


## その他の参考記事

https://qiita.com/amakawa_/items/ab7d284566b5fd51d9ca

https://dev.classmethod.jp/articles/scp-for-bigginer/



## 終わりに

当問題の解決のために、ググったら
linuxコマンドの復習の機会にもなって良かった。

落ち着いて見直すと、ほぼ教材通りのコードで
お恥ずかしい。笑

最後までお読み頂き、ありがとうございました。
世界184ヶ国のFacebookユーザーから予算5万で最大値の反応を得たカラクリと雑感

##はじめに
時期外れとなってしまいましたが、クスノキでは、今年4月1日にエイプリルフール向けのネタサービスをローンチしました。

せっかくのネタなら実験しないともったいないので、思い切って海外ユーザーからの最大値の反応を得る反応をあつめてみたらどうかとFacebookから広告配信したところ、期待値以上の反応を得られたので、そのときの結果などを共有します。

最初にお断りしますが、本記事での内容は「販促現場でいますぐ実践できるノウハウ」ではありません。どちらかといえば、グローバルでの反応調査や、思考実験、承認欲求の矛先だったり、はたまた販促資料の数値根拠の捏造のような、アイデア次第でどのようにも使えるWeb広告のスキマみたいなお話です。きちんとしたSNS広告運用の作法が知りたい方は、無用な知識であることをご承知ください。


##だいぶマッチョな配信結果が出ました

広告予算：**5万円**
配信期間：**3月31日〜4月2日**
いいね！数：**1,101人**
コメント数：**8件**
シェア数：**35件**
クリック数（≒PV数／サイト流入数）：**38,375件**
インプレッション数：**1,217,621imp**

:::note info
※日本時間（GMT+9）4月1日 0時0分〜23時59分を基準時間とした関係で、国によっては配信されたタイミングが2日ズレてます。
:::

**配信したクリエイティブのスクリーンショット**
![speedpizza.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1327017/060d452a-ed11-aed5-20ca-1f2735937148.png)

***

某アッ○プル社に啓発されたサムネ画像のキャッチーさなども幾分影響したかと思いますが、結果として**高校生アルバイトの月給くらいのコストで自分たちのサービスを184ヶ国のユーザーへ露出**することができました。ソーシャルでの拡散を目的としたWeb広告案件で、2,000万近い予算を投入するクライアントがザラにいるご時世を踏まえても、かなりマッチョな成績です。


##広告効率のよい国だけに配信されるようベース設定を行っていた

Facebook広告は、設定した広告の配信されるかどうかがオークション形式でシステム処理されています。入札単価よりも競合の提示する単価が高ければそちらが優先して配信されるし、逆も然りです。配信国が複数にまたがる場合は物価の要素が絡むので、同じ金額でも新興国やいわゆる後進国に対しとても安価に配信することができます。

実際の配信結果がこちら。5万と書きましたが予算消化しきれず、実際には4万3千円くらいでした。
![スクリーンショット 2021-08-11 20.58.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1327017/f0caff79-2c3a-c921-4762-4d33d09d0b8e.png)

上記のような結果が期待できるターゲット設定画面がこちら。Facebook広告では、配信地域、年齢、興味関心などを指定する箇所ですね。配信地域は、いちいち個別の国名を指定しなくてもWorldwideと入れておけばシステム側でパフォーマンスのよい国を選んでくれちゃうあたりが罪深いです。興味は日本っぽいワードを最初に入れて、あとはリコメンドで出てきた候補をポチポチして適当にいれてます。

![スクリーンショット 2021-08-11 12.46.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1327017/931b0967-2978-73fc-4cb5-558aa3484b01.png)

つまり、配信先地域をまったく決めないことを決めたことで、結果として著しく物価差の国へ優先的に配信され、配信数、反応が最大化した、というカラクリですね。当たり前なようで、これはこれで面白い結果です。


##クスノキではどのように活用したか（雑感）
ターゲット層ではないユーザーのアクション取りに行っても営業的にはなんの役にも立ちません。参考までに、この数字をクスノキではこの結果をどのように振り返ったかを共有します。

##新興国ユーザーのデバイス環境は、中国製だらけ。
クスノキでは海外ユーザーの利用を見越したサービスを複数開発しているため、できるだけ利用者のリアルな通信環境を知っておく必要があります。無作為に配信した広告へのアクセスデータは最適です。

例えば、全体でのアクセスデータを見ると、1位にiPhoneが来ているものの、それ以外はほぼAndroidなため、全体の1割強しか存在しないことがわかります。日本ではスマートフォンといえばiPhoneと思っているユーザーも多いですが、海外、特に新興国ではiPhoneはひとつの端末に過ぎず、iOSアプリの開発は効率が悪い、iOS対応の優先度が低いことがはっきりと、数字でわかります。

![スクリーンショット 2021-08-11 21.21.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1327017/67d001bf-bc7b-3365-09cc-3664fce779bb.png)

見慣れない端末名は、ほぼOppo、Huawei、Xiaomi、Vivo製。広告の配信先は新興国が中心となっているため、勢いを増している国々ではほぼ中華製のスマートフォンの影響力が強く、XperiaやAQUOS、arrowsのような日本製はほぼ使われていないこともわかります。

中華製のスマートフォンは、Androidをベースとした独自OS（ColorOS、FuntouchOSなど）を利用しており、現状はAndroid 6をベースにスキンをかぶせただけくらいの仕様ですが、今後は個別対応が必要になってくると予想されます。


色々書きましたが、アイデア次第でいつでも安価に試せるのがFacebook広告の良いところです。他におもしろそうなアイデアなどありましたら、コメント等で教えてください。一緒に実験しましょう。


クスノキでは、システム開発やWebサイト、Androidアプリなどの開発案件から、広告運用など幅広くお仕事募集しています。企画のアイデア出しから実装まで対応していますので、お気軽にご相談ください。

株式会社クスノキ
https://www.kusunoki.ltd/
wordpress https (secure backend)

# https://wordpress

## wordpress が https のバックエンドに対応していないので対応してみた。

### 成果物

- [GitHub](https://github.com/jobscale/wordpress)

### 手順

#### どっかに `http://` って書いてあるのが原因なので全置換

> `http://`
> → `//`

- コミットハッシュ: 963dec59

#### ドメインの先頭が削られるので `substr 7` を見つけ出す

> `substr($uri, 0, 7)`
> → `substr($uri, 0, strlen($protocol))`

- コミットハッシュ: afb37416

### 成功した

- [WordPress](https://cms.jsx.jp)

### その他

`$_SERVER['X-FORWARDED-PROTO']` とか使ってもできそう
[C言語] leaksコマンドを使った簡単なメモリリークの確認方法

C言語でプログラムを書いているとメモリリークがよく発生します。
そのため、なるべく簡単にメモリリークを確認する方法を調べてみました。
方法として2つ紹介させて頂きます。

## 1. デストラクターを設定する
コマンドを設定することでプロセスが終了時に自動的に実行されます。

```c
#include <libc.h>

__attribute__((destructor))
static void destructor() {
	system("leaks -q a.out");
}

int main()
{
	char *s = malloc(100);

	s = "hello world";
	puts(s);
	return (0);
}
```
実行結果

```bash
$ gcc test.c
$ ./a.out 
hello world
leaks Report Version: 4.0
Process 47921: 170 nodes malloced for 13 KB
Process 47921: 1 leak for 112 total leaked bytes.

    1 (112 bytes) ROOT LEAK: 0x7ff7f7c05af0 [112]
```

`leaks`コマンドが実行されていますね。
ちなみに `-q` オプションを付けることでヘッダとフッタを非表示にしています。

## 2. 実行時に`-atExit`オプションを付ける

```c
#include <libc.h>

int main()
{
	char *s = malloc(100);

	s = "hello world";
	puts(s);
	return (0);
}
```
実行結果

```bash
$ gcc test.c
$ leaks -q -atExit -- ./a.out
hello world
leaks Report Version: 4.0
Process 48537: 170 nodes malloced for 13 KB
Process 48537: 1 leak for 112 total leaked bytes.

    1 (112 bytes) ROOT LEAK: 0x7fcba3c05af0 [112]
```
`leaks`コマンドが`atExit`として設定されてプロセスが終了時に実行されています。
`alias`に設定しておけば手っ取り早く確認できるので便利ですね。

## まとめ
メモリリークは避けては通れないので、逐一確認していくと良さそうですね。
`man leaks`で他にも便利なオプションが見られるので興味ある方は是非試してみてください。
【Swift】WebViewで "NSURLErrorDomain, code = -1022" のエラーが出てページが表示されない問題

# どういうことか

iOSアプリを開発している。
他所が作ったWebページと連携するためWebViewで表示しようと思ったら真っ白なページが表示され、Xcodeのコンソールに掲題のエラーが表示される。
Webインスペクタで確認するとどうやらリダイレクトする処理が書かれており、遷移する先がhttpでは？と疑ってみたもののhttpsになっている。

## 検証

対象のページがATS (App Transport Security) に対応しているか、ターミナルでコマンドを叩いて検証してみる。

```terminal
$ nscurl --ats-diagnostics --verbose https://[URL]
```

↓

```terminal
Error : Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made.
```

ダメだったらしい。
『**エラーが発生しました。Error Domain=NSURLErrorDomain Code=1200 "SSLエラーが発生したため、サーバーへの安全な接続ができません**』と書いてある。

## 解決策

上記のコマンドに `--verbose` のオプションを付けたことで、いろんなパターンの結果と解決策がいくつか出てくる。
`PASS` がOKだったパターン、`FAIL` がダメだったパターン。

```terminal
Disabling Perfect Forward Secrecy
ATS Dictionary:
{
    NSExceptionDomains =     {
        "対象のドメイン" =         {
            NSExceptionRequiresForwardSecrecy = false;
        };
    };
}
Result : PASS
```

このパターンを使う。

## 解消する

info.plistに追記する

1. どこかで +ボタンを押して `App Transport Security Settings` を追加
1. 1の中に `Exception Domains` を追加
1. 2の中に対象のドメインを追加。Typeを **Dictionary** に変更
1. 3の中に `NSExceptionRequiresForwardSecrecy` を追加。Typeを **Boolean** にし、Valueを `0`（falseを表す）に設定

これで表示されるようになった。

## おわりに

そもそもWebページの方を見直すべきかもしれないし、この設定が企業のセキュリティ要件などに引っかかるかもしれないので、そのあたりはきちんとすり合わせを行う。
Android Studioで初めてのビルドがうまくいかない時にしたこと。(Mac)

Flutter大学のこの動画を観ながら環境構築していましたが、Android Studioの最初のビルドがうまくいかず、困っていましたが、解決できたので、記事にしておきます。

# 前提

- MacOS Big Sur バージョン 11.5
- Android Studio 2020.3.1.22

# 出てきたエラーメッセージ

```
FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:compileDebugKotlin'.
> Kotlin could not find the required JDK tools in the Java installation '/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home' used by Gradle. Make sure Gradle is running on a JDK, not JRE.

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 1s
Exception: Gradle task assembleDebug failed with exit code 1
```

どうやら、JDKにパスが通っていないということらしいので、こちらの記事にしたがって、JDKをインストールしたらうまくいきました。

https://qiita.com/suke_masa/items/f9af0fb84ad9447ae961

[1] https://adoptopenjdk.net にアクセス

[2] [OpenJDK 11]・[HotSpot]を選択したあと、[Latest Release]をクリック

[3] インストール

[4] ターミナルで下記コマンドを実行

```
cd ~
echo JAVA_HOME=/Library/Java/JavaVirtualMachines/adoptopenjdk-11.jdk/Contents/Home >> .zshrc
source .zshrc
echo $JAVA_HOME
```

```
cd ~
echo PATH=$PATH:$JAVA_HOME/bin >> .zshrc
source .zshrc
echo $PATH
```
【Houdini】アトリビュートが読み取れない

ジオメトリスプレッドシートを見ると確かに存在しているはずのアトリビュートをVEXやエクスプレッションなどで、`prim`関数や`@変数名`の形式で取得しようとしてもなぜか取得できずハマりました

具体的には、 SideFX Labs の osm import SOP によって生成されたアトリビュートのみなぜか読み取れず、自分で作成したアトリビュートはいつも通り読み込めるという摩訶不思議な状況

原因は数値だと思っていた**アトリビュートが実は文字列**だったことでした

ジオメトリスプレッドシートを一見するだけでは数値と文字列は見分けられないので少々厄介でした…

文字列のアトリビュートを読み取る場合は、
`prim`エクスプレッション関数の代わりに`prims`エクスプレッション関数を使用します
また、VEXでは`@変数名`の形式の代わりに`s@変数名`と文字列の型指定が必要です
`prim`VEX関数では数値も文字列も読み込めますが`float`や`int`の変数に格納しようとすると値が 0 になってしまいますので、一度`string`の変数に読み込んだ後に`atof`関数や`atoi`関数で文字列に変換するなどという処理が必要です
javascriptで文字列の間に記号を入れたい

```js
function addSignToString(number){
  const numArray = String(number).match(/.{2}/g);
  const reducer = (accumulator, currentValue) => accumulator +  ' > ' + currentValue;
  signIncludedString = numArray.reduce(reducer);
  return signIncludedString;
}

console.log(addSignToString(121212));
// 12 > 12 > 12
```


修正案_1

@e92gr sann
@hxiqz sann
コメントありがとうございます。

```js
function addSignToString(number){
  const stringNum = String(number);

  if (isNullOrUndefined(number)) {
      return '';
  } else if (stringNum.length < 2 ) {
      return number;
  } else if (stringNum.length % 2 === 1) {
      const last = stringNum.substring(stringNum.length - 1, stringNum.length);
      return addSign(stringNum) + ' > ' + last;
  } else {
     return addSign(stringNum);
  }
}

function addSign(number) {
  if(!['string', 'number', 'bigint'].includes(typeof number)) return '';
  const numArray = String(number).match(/.{2}/g);
  return numArray !== null ? numArray.join(' > ') : '';
}

function isNullOrUndefined(number) {
    if (number === null | number === undefined | number === '' | !number) {
        console.log('入力がありません');
        return true;
    }
}
console.log(addSignToString(121212));
// 12 > 12 > 12
console.log(addSignToString(122));
// 12 > 2
console.log(addSignToString());
// 入力がありません
```
Laravelでテーブルをロックする


```php
DB::unprepared( 'LOCK TABLES tmp_1 WRITE, tmp_2 WRITE;' );

// something want to do

DB::unprepared( 'UNLOCK TABLES' );
```

`DB::statement()` や `DB::raw()` では動きませんでした。

トランザクション化のケース。

```php
 DB::transaction(function (){
    DB::unprepared( 'LOCK TABLES tmp_1 WRITE, tmp_2 WRITE;' );
    // something want to do
    DB::unprepared( 'UNLOCK TABLES' );
  });
```

## 参考


https://stackoverflow.com/questions/53522444/how-to-lock-table-with-laravel/53523102#53523102


https://qiita.com/zackey2/items/079128df6567091b8a1c
[Flutter]DynamicライブラリをiOS/Releaseで利用する

#現象
pub.devのopus_flutterを利用して開発していた。
iOSのDebugモードだと動作したが、Releaseモードでは動作しなかった。


#解決方法
Xcodeから読み込み設定をしてやるとReleaseモードでも動作した。


https://flutter.dev/docs/development/platform-integration/c-interop

```
Compiled (dynamic) library

To link to a compiled dynamic library, use the following instructions:

    If a properly signed Framework file is present, open Runner.xcworkspace.
    Add the framework file to the Embedded Binaries section.
    Also add it to the Linked Frameworks & Libraries section of the target in Xcode.
```

![unnamed.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233237/3e76655c-8b6d-cf34-8472-7de597cdc36d.png)
[Terraform] Error: project: required field is not set の対処法

google-terraform-provider利用時に以下のエラーが出力。

```terraform	
Error: project: required field is not set

  on ../../../modules/memory-store/main.tf line 50, in resource "google_redis_instance" "redis_group":
  50: resource "google_redis_instance" "redis_group" {
```

## 解決策

```sh
❯ gcloud config set project YOUR_PROJECT_NAME
❯ export GOOGLE_PROJECT=YOUR_PROJECT_NAME
```

[Error: project: required field is not set on google_compute_network · Issue #4856 · hashicorp/terraform-provider-google](https://github.com/hashicorp/terraform-provider-google/issues/4856)