OmniAICreator/Qiita-1.07M huggingface dataset:
CORSとは何ですか？

#CORS (Cross-Origin Resource Sharing) 
- HTTP ヘッダーの転送で構成されるシステムであり、
ブラウザーがオリジンをまたいだリクエストのレスポンスに、フロントエンドの JavaScript コードがアクセスすることをブロックするかどうかを決めるものです。

- CORS はウェブサーバーに、リソースへのオリジンをまたいだアクセスを許可すると言うことができるようにします。

- 他のオリジンから私のリソースに勝手にアクセスができないようにするため使います。

#### リクエストヘッダーには以下のようなものがあります。  

- Origin
    - どのオリジンからアクセスしているかを示します。
- Access-Control-Request-Method
    - プリフライトリクエストを発行する際に、実際のリクエストを行う際に使用される HTTP メソッドをサーバーに知らせるために使用します。
- Access-Control-Request-Headers
    - プリフライトリクエストを発行する際に、実際のリクエストを行う際に使用される HTTP ヘッダーをサーバーに知らせるために使用します。  

#### レスポンスヘッダーには以下のようなものがあります。 
- Access-Control-Allow-Origin
    - レスポンスを共有してよいかどうかを示します。
    - ブラウザが該当オリジン資源にアクセスできるように許可します。もしくは「*」はcredentialsがないリクエストに限ってすべてのオリジンにアクセスできるように許可します。
- Access-Control-Expose-Headers
    - レスポンスの一部としてどのヘッダーを公開してよいかを、ヘッダー名を列挙することで示します。
    - ラウザがアクセスできるサーバーのホワイトリストヘッダーを許可します。
- Access-Control-Max-Age
    - プリフライトリクエストの結果をキャッシュできる時間を示します。
- Access-Control-Allow-Credentials
    - 簡単なGETリクエストはpreflightされないので認証があるリソースをアクセスした場合、ヘッダーがリソースとともに返却されなければブラウザから応答を無視し、コンテンツで返却しません。
    - 認証情報フラグ（Credentials）が true の場合、リクエストに対するレスポンスを公開してよいかどうかを示します。
- Access-Control-Allow-Methods
    - プリフライトリクエストへのレスポンスで、リソースにアクセスするときに使用してよいメソッドを指定します。
- Access-Control-Allow-Headers
    - プリフライトリクエストへのレスポンスで使用され、実際のリクエストを行う際に使用してよい HTTP ヘッダーを示します。

#CORSはなぜ必要なのか
もし私がサービスしていないサイトからセッションのリクエストがあり、取得できるとしたらそのサイトは
私のセッション奪取したらそのセッションで悪いことをするかもしれません。
なので、ブラウザではこうしたリクエストを防いてくれています。
フィッシングサイトが代表的な攻撃の事例でこういう攻撃は止めて私が許可したオリジンだけがリクエストできるようにするため、必要です。

#CORSはどのように動くのか
ブラウザがリクエストをするとき、ヘッダーに追加情報を含めます。
私のオリジンは何があってどのメソッドを使ってリクエストをし、どのヘッダーが含まれているかをいれてサーバーにリクエストを投げます。
サーバーはサーバーが応答できるオリジンをヘッダーに入れてブラウザに送ります。
ブラウザがこのヘッダーを確認し該当オリジンからリクエストができるのであればリソースのリクエストを許可し、できないのであればエラーが発生します。

#ソース
- [Preflighted_requests](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Preflighted_requests)
- [Server-Side_Access_Control](https://developer.mozilla.org/en-US/docs/Web/HTTP/Server-Side_Access_Control)


#### 参考
- https://hannut91.github.io/blogs/infra/cors
- https://developer.mozilla.org/ja/docs/Glossary/CORS
【Effective Javaを読む】　第３章　項目１０　『toStringを常にオーバーライドする』

#toStringを常にオーバーライドする

新しいクラスを作ってtoStringしてみても`"PhoneNumber@163b91"`のような別にもらっても嬉しくない文字列がかえってきます。
toStringに関する一般契約は「簡潔だが、人が読みやすくなっている有益な表現」です。

##サンプルコード
```java
/**
 * この電話番号の文字列表現を返します
 * 文字列は14文字で構成されていて、その形式は、"(XXX) YYY-ZZZZ"です。
 * XXXは市外局番で、　YYY-ZZZZは市内局番です。
 * （各大文字は、1桁の数字を表しています。）
 * 
 * この電話番号の3つの部分のどれかが、そのフィールドを埋めるには
 * 桁が少ない場合には、そのフィールドの先頭が0で埋められます。
 * たとえば、最後の4桁部分の番号が"123"だとしたら、文字列表現の最後の
 * 4文字は"0123"となります。
 * 
 * 市外局番のカッコの後に、市内局番と区切るための空白が一つあることに注意してください。
 */
@Override public String toString(){
    return String.format("(%03d) %03d-%04d", 
                         areaCode, prefix, lineNumber); 
}
```
これで`"{Jenny=(707) 867-5309}"`が返ってきますね！
toStringをきっちりオーバーライドすることは、このクラスを使う別な人のプログラムの解析をする時間を省略してあげることにつながります。

#続く
【Effective Javaを読む】　第３章　項目１２　『Comparableの実装を検討する』
https://qiita.com/Natsukii/items/1942f7f41ac39b914591
EC2をリバースプロキシサーバ化してElasticSearchServiceのAPIを外部から叩けるようにする

#経緯

Amazon Elasticsearch Serviceを使用してELasticSearchの検証環境を用意したが
Globalに公開できず検証しづらかったので、EC2をプロキシサーバにして外部からAPIを叩けるようにした。
セキュリティ的な問題はあるが検証環境であるということと自宅IPに絞ったので今回は甘めに

## ざっくり構成
![構成図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/273496/5d652ffd-c9d7-bf64-b9fc-3e5f8f9708e6.png)


## EC2を作成

EC2を作成し、PublicSubnetを紐づけます。

## EC2用のセキュリティーグループを作成し、EC2に紐づける

今回EC2はHTTPでAPIを叩くようとSSHでリバースプロキシの設定をするために
インバウンドルールで80ポートと22ポートを解放するようにセキュリティーグループを設定します。

![スクリーンショット 2020-07-10 19.06.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/273496/31fe444e-f2c2-4764-ff4f-72f856ae0360.png)

## ElasticSearchを作成

ElasticSearchを作成し、PrivateSubnetを紐づけます。

## ElasticSearch用のセキュリティーグループを作成し、ElasticSearchに紐づける
ElasticSearchはEC2からのみのアクセスを受け付けたいので、
インバウンドルールにポート443 ソースにEC2のセキュリティーグループを設定します。
![スクリーンショット 2020-07-10 19.16.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/273496/9261c5b2-b7bd-c2f1-8821-f5a91a0415fd.png)

## EC2をリバースプロキシ化

今回はnginxで設定していきます。

```bash
sudo yum update -y
# nginxのインストール
sudo amazon-linux-extras install nginx1.12 -y
sudo vim /etc/nginx/nginx.conf
```
/etc/nginx/nginx.conf内に
locationの記述があると思うのでそちらにElasticSearchのVPCエンドポイントを記載します

```conf:/etc/nginx/nginx.conf
location / {
    proxy_pass ElasticSearchのVPCエンドポイントを記載;
}
```

```bash
# nginxの起動
sudo systemctl start nginx
# EC2起動時に動くように
sudo systemctl enable nginx
```

## EC2のpublic IPをブラウザ等で叩く
```
{
  "name" : "hogehoge",
  "cluster_name" : "hoge",
  "cluster_uuid" : "hogeid",
  "version" : {
    "number" : "7.4.2",
    "build_flavor" : "oss",
    "build_type" : "tar",
    "build_hash" : "unknown",
    "build_date" : "2020-05-05T04:47:06.936807Z",
    "build_snapshot" : false,
    "lucene_version" : "8.2.0",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}
```

成功🎉
初心者によるプログラミング学習ログ 387日目

#100日チャレンジの387日目
twitterの100日チャレンジ#タグ、#100DaysOfCode実施中です。
すでに100日超えましたが、継続。
100日チャレンジは、ぱぺまぺの中ではプログラミングに限らず継続学習のために使っています。
387日目は、
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">おはようございます<br>昨日の作業⇩<br><br>●キンドル読書 10分<br>●プログラミング学習387日目 2h<br>・メンターの課題<br>・背景画像の位置調整<a href="https://twitter.com/hashtag/%E9%A7%86%E3%81%91%E5%87%BA%E3%81%97%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%A8%E3%81%A4%E3%81%AA%E3%81%8C%E3%82%8A%E3%81%9F%E3%81%84?src=hash&amp;ref_src=twsrc%5Etfw">#駆け出しエンジニアとつながりたい</a><a href="https://twitter.com/hashtag/100DaysOfCode?src=hash&amp;ref_src=twsrc%5Etfw">#100DaysOfCode</a><a href="https://twitter.com/hashtag/%E6%97%A9%E8%B5%B7%E3%81%8D%E3%83%81%E3%83%A3%E3%83%AC%E3%83%B3%E3%82%B8?src=hash&amp;ref_src=twsrc%5Etfw">#早起きチャレンジ</a></p>&mdash; ぱぺまぺ@社畜✕投資✕ブロガー (@ppmp65) <a href="https://twitter.com/ppmp65/status/1288931749729247232?ref_src=twsrc%5Etfw">July 30, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
【Effective Javaを読む】　第３章　項目９　『equalsをオーバーライドする時は、常にhashCodeをオーバーライドする』

#equalsをオーバーライドする時は、常にhashCodeをオーバーライドする

equalsをオーバーライドしているすべてのクラスは、一緒にhashCodeもオーバーライドしなければObject.hashCodeの一般契約を破ってしまうよ、というお話

##サンプルコード

以下のコードはequalsはオーバーライドしていますが
hashCodeはオーバーライドしていません

```java:例１
public final class PhoneNumber {
    private final short areaCode;
    private final short prefix;
    private final short lineNumber;

    public PhoneNumber(int areaCode, int prefix,
                       int lineNumber){
        rangeCheck(areaCode, 999, "area code");
        rangeCheck(prefix, 999, "prefix");
        rangeCheck(lineNumber, 9999, "line number");
        this.areaCode = (short)areaCode;
        this.prefix = (short)prefix;
        this.lineNumber = (short)lineNumber;
    }

    private static void rangeCheck(int arg, int max, 
                                   String name){
        if (arg < 0 || arg > max)
            throw new IllegalArgumentException(name +": " + arg);
    }

    @Override public boolean equals(Object o){
        if (o == this)
            return true;
        if (!(o instanceof PhoneNumber))
            return false;
        PhoneNumber pn = (PhoneNumber)o;
        return pn.lineNumber == lineNumber
            && pn.prefix == prefix
            && pn.areaCode == areaCode;
    }

    // 不完全 - hashCodeメソッドがない！
    
    ... // 残りは省略
}
```
例１をHashMapで使用することを想定してみる。
例２で`m.get(new PhoneNumber(707, 867, 5309))`は`"Jenny"`を返すと期待されるけれども、帰ってくるのは`null`です。
hashCodeをオーバーライドしていないので、putしたPhoneNumberとgetしているPhoneNumberはハッシュ値が別物だからです。

```java:例２
Map<PhoneNumber, String> m = new HashMap<PhoneNumber, String>();
m.put(new PhoneNumber(707, 867, 5309), "Jenny");
```
以下はあくまで例ですがhashCodeをオーバーライドしてあげましょう。

```java:例３

@Override public int hashCode(){
    int result = hashCode;
    if (result == 0){
        result = 17;
        result = 31 * result + areaCode;
        result = 31 * result + prefix;
        result = 31 * result + lineNumber;
        hashCode = result;
    }
    return result;
}
```
#続く
【Effective Javaを読む】　第３章　項目１０　『toStringを常にオーバーライドする』
https://qiita.com/Natsukii/items/6e2cd2e77e144048819d
Railsアプリで日時の取得にはどのクラスを使うべきか(Time, DateTime, TimeWithZone)


## 日時の取得はどのクラスを使うべきか

- Timeクラス
- DateTimeクラス
- TimeWithZoneクラス

Railsでは、特別な理由がない限り、
TimeクラスやDateTimeクラスより、TimeWithZoneクラスで統一した方が良い。

## タイムゾーンについて

タイムゾーンを設定する場所は３箇所あります。

- システム
- 環境変数 `ENV['TZ'] `
- application.rb 

application.rbにどのタイムゾーンが設定してあるか確認するには、`Time.zone.name`を使います。

```ruby
# application.rb
config.time_zone = 'Tokyo'

Time.zone.name
=> "Tokyo"
```

## どのタイムゾーンが使われるのか
ややこしいことに、クラスやそのクラスに関連するメソッドによってどのタイムゾーンが使われるか変わります。
例えば、
Timeクラスに関連するメソッド`now`を使った`Time.now`は環境変数のタイムゾーンを使い、
Timeクラスに関連するメソッド`current`を使った`Time.current`はapplication.rbのタイムゾーンを使います。

```ruby
#環境変数が使われ、classはTimeになる
[1] pry(main)> Time.now
=> 2020-07-31 19:39:18 +0900
[2] pry(main)> Time.now.class
=> Time

#application.rbが使われ、classはTimeWithZoneになる
[3] pry(main)> Time.current
=> Fri, 31 Jul 2020 19:39:35 JST +09:00
[4] pry(main)> Time.current.class
=> ActiveSupport::TimeWithZone
```


## 現在の日時の取得にはTime.currentかTime.zone.nowを使おう
現在の日時を取得する場合、以下の方法があります。

1. Time.now (環境変数のタイムゾーンを使う)
2. DateTime.now (環境変数のタイムゾーンを使う)
3. Time.current (application.rbのタイムゾーンを使う)
4. Time.zone.now (application.rbのタイムゾーンを使う)

結論としては、TimeWithZoneクラスである3または4を使っておいた方が良いです(もし国際的なアプリケーションにしようと思ったら色々と器用に扱える為)。

```ruby
# 環境変数のタイムゾーンが使われる
[1] pry(main)> Time.now
=> 2020-07-31 19:43:14 +0900 #Timeクラス
[2] pry(main)> DateTime.now
=> Fri, 31 Jul 2020 19:43:21 +0900 #DateTimeクラス

# application.rbのタイムゾーンが使われる
[3] pry(main)> Time.current
=> Fri, 31 Jul 2020 19:43:26 JST +09:00 #ActiveSupport::TimeWithZoneクラス
[4] pry(main)> Time.zone.now
=> Fri, 31 Jul 2020 19:43:32 JST +09:00 #ActiveSupport::TimeWithZoneクラス
```
## 参考記事
以下の記事を参考にしました。記事ではとても詳しく説明してあります。
https://qiita.com/jnchito/items/cae89ee43c30f5d6fa2c
Visual Studio Codeから EMRを使う

# 目的

EMRをリモートサーバーとして手元のVisualStudioCodeからコードをsubmitしたい。

# モチベーション

* Sparkを手元で簡単に検証してからクラスタにSubmitしたい。 (ex. デバッグにクラスタ使うのはもったいない）
* Jupyter より VSCodeを使いたい（ex. ブラウザの調子が悪い）
* Notebook より pythonファイルベタ打ちしたい (ex. コードセントリックに書きたい）
* gitでの管理を入念に行いたい（ex. Juypter notebookの差分は見ずらい）
* AzureよりAWSが好き（ex. 〇〇が好きだからAWS）

# やり方

* EMR側でクラスタを立ち上げる

　詳細設定でLivyを立ち上げること。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146939/6c43b926-9034-794f-d848-1256e73d2ac3.png)
 
 適切なセキュリティ設定を行う（Livyポート 8998 を開ける）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146939/03903c23-af54-244d-b17b-c2450aa719e2.png)

　「アプリケーションの履歴」タブからLivyのエンドポイントを確認する。（タブの名前、変ね）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146939/b25fc5be-4559-7635-8b63-b2349cecc2fc.png)

 ご利用は計画的に。


* Microsoft謹製の[Spark & Hive Tools Extension](https://marketplace.visualstudio.com/items?itemName=mshdinsight.azure-hdinsight)を使う。
  
　(おい、それはHDInsight用だろ、と諦めない。)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146939/18f7c9f5-5325-4d2b-5589-e89c670648fb.png)

* 上記を少しトリックする

　トリックするといっても、VSCodeのAzure ExtensionにてAzureにログインするだけ。HDInsightのリソースを作る必要はない。Azure側はゼロコスト。ごめんなさいM$様。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146939/d12dbe33-7786-5efc-8821-9c0592806cc1.png)

* Generic Livy Endpointを指定する

　Link a Clusterする。　

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146939/c5a436e3-7ed9-7369-1eb1-700d223fa843.png)

　Generic Livy Endpointを選び、EMRのEndpointを指定する。

　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146939/342f724b-05e7-e906-bede-b27d1e7524dd.png)
　
  ExtensionのOutputにこういうメッセージが出れば、ひとまずOK。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146939/ce134f8f-ec28-25ec-18a9-ccc8866abab5.png)

もう少しトリックが必要かと思ったけど、HDInsightしばりが緩いようなので、楽々でした。
その５「Rails初心者」が5回連続で発生したエラーをなんとか切り抜けた話。「NameError」

前回の「その４」の続きです

前回の記事☞https://qiita.com/Shota_U/items/f41a2e0f2a1e24f98fc9


ついにこれが最後のエラーです。

今回発生したエラーは、

`NameError (uninitialized constant)`

というエラーです。

このエラーの

`uninitialized constant`　は、
定義したクラスを読み取ることができない。



という意味だそうです。


そこで、まずファイル名とファイルパス、ファイルの中のクラス名を確認。

すると一か所、
単数形でないといけないファイル名をと複数形にしていたことが判明。


すぐ直してエラーが消えました！
これは割とうっかりミス、という感じです。

これまでのエラーよりは解決しやすかったかなと思います。
これで、5つすべてのエラーを解消することができました！

一応、ほかの4つの記事も載せておきます

その１　https://qiita.com/Shota_U/items/1f91709704476618aa0d
その２　https://qiita.com/Shota_U/items/c93eb669b3f8078785eb
その３　https://qiita.com/Shota_U/items/a589a080815032a24092
その４　https://qiita.com/Shota_U/items/f41a2e0f2a1e24f98fc9

これらのエラーと戦い、どうにか解決したうえで
改めて気づいたことが３つありました。（どれも初心者向けですが。。。）

ですので、ここで学んだことをまた次の記事で書こうと思います！

※その記事はこちら👇https://qiita.com/Shota_U/items/73b16eec4753b35d0ed0


読んでくださり、ありがとうございました！
Pythonの無限スクロールスクレイピングの終わらせ方

Pythonで無限スクロールがあるWebページのスクレイピングを実装中、終わらせ方がわからなくてつまづいたのでメモ

## サンプル

```py3
>>> t = 0
>>> start_at = time.time()
>>> t = time.time() - start_at
>>> t == 5
>>> break
```

## 解説

`start_at`は、実行してから経過している時間
`t`は、その差
`t`が5（5秒経過）になると、処理を終了する

参考
https://note.nkmk.me/python-datetime-timedelta-measure-time/
https://ai-inter1.com/python-selenium/#st-toc-h-14
その4「Rails初心者」が5回連続で発生したエラーをなんとか切り抜けた話。「ArgumentError in income_Values#index」

前回の「その３」の続きです

前回の記事☞https://qiita.com/Shota_U/items/a589a080815032a24092


今回発生した新たなエラーは、

`ArgumentError in income_Values#index`

です

※すみません！エラーのスクショは撮っておりません

こちらのエラーは、

「引数の数があっていないときや、数は合っていて、期待される振る舞いを持ってはいるが、期待される値ではないときに発生する」

みたいです。


エラー文をよく見たところ、

`wrong number of arguments (given 1, expected 0)`
とありました。

これは、
「引数の数がちがうよー」
「正常な引数の数は０のはずなのに1個入ってるよ」

ってことらしいです


そこで引数を正しく直したところ、
やっと、一覧画面を表示することができました！！！
（正確には、&をつかった「ぼっち演算子」で解決）



エラー文を知るって大事だなぁ。。。


しかし、今度は新規投稿ができなくなっていました。

今度は`NameError`です。

せっかく実装できた！と思ったのに、、、


その５に続く👇
https://qiita.com/Shota_U/items/7f5c60e95e9b95b55d8e
その３「Rails初心者」が5回連続で発生したエラーをなんとか切り抜けた話。「NoMethodError in IncomeValues#index」

前回の「その２」の続きです

前回の記事☞https://qiita.com/Shota_U/items/c93eb669b3f8078785eb

３つ目のエラーです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674052/e04f710b-fa9d-9f0b-d019-428be1f94f1b.png)


「NoMethodError in IncomeValues#index」

というのがでてきました。

これは、「NillClassにstrftimeなんていうメソッドはないよ」

ということみたいです

そこで、


```
income_value.year_month.strftime('%Y年%m月')
```

を


```
income_value.year_month&.strftime('%Y年%m月')
```

としたところ、無事解決できました。


しかし、
また次のエラー「ArgumentError」がでてきてしまいました。。。

これは、正直心折れそうでした（笑）。



その４へ続く👇
https://qiita.com/Shota_U/items/f41a2e0f2a1e24f98fc9
【VSCode】ES6記法スニペットのEmmet展開方法まとめ

#React学習中の自分のための、ES6記法スニペットのEmmet展開方法メモ

Reactの学習を始めたのですが、アロー関数やらimportとかexportとか何度も繰り返し登場する記述を毎回書くのが面倒で、スニペットのVSCode拡張機能ないかな？と思ったら案の定ありました。


[VSCodeの拡張機能 : JavaScript (ES6) code snippets](https://marketplace.visualstudio.com/items?itemName=xabikos.JavaScriptSnippets)

ただこいつを使いこなすにもEmmetのキーを覚えないといけなくて、なかなか覚えられないので自分のためのメモ帳代わりにしようと記事投稿しています。

最初はとりあえず少数しかない状態で公開しちゃいますが、React含めES6記法のEmmetをこれからどんどん追加していきます。
なんならこの記事をご覧のみなさんからも**「こんなのあるよ！」****「こっちの方がもっと便利だよ！」**等ありましたらコメント頂けますと幸いです！（他力本願）

みなさんのお力を借りてブラッシュアップしていきたい！そんな心つもりでございます！

みなさま、どうぞよろしくお願いいたします。

## アロー関数 系

####nfn

```javascript
//nfn
const name = (params) => {
    
}
```

####anfn

```javascript
//anfn
(params) => {
    
}
```

## import 系

#### imr

```javascript
//imr
import React from 'react'
```

#### imrd

```javascript
//imrd
import ReactDOM from 'react-dom'
```

#### imd

```javascript
//imd
import {  } from 'module'
```

#### imp

```javascript
//imp
import moduleName from 'module'
```

## export 系

#### exp

```javascript
//exp
export default 
```

## React Hooks 系

#### useState

```javascript
//useState
const [state, setstate] = useState(initialState)
```

#### useEffect

```javascript
//useEffect
useEffect(() => {
    effect
    return () => {
        cleanup
    }
}, [input])
```

#### useReducer

```javascript
//useReducer
const [state, dispatch] = useReducer(reducer, initialState, init)
```

#### useContext

```javascript
//useContext
const context = useContext(contextValue)
```



## おわりに
もっともっとあるはず。これからどんどん追加していきます。
その２「Rails初心者」が5回連続で発生したエラーをなんとか切り抜けた話。「ActiveRecord::StatementInvalid in IncomeValues#index」

前回の「その１」の続きです

前回の記事はこちら☞https://qiita.com/Shota_U/items/1f91709704476618aa0d


２つ目のエラーは

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674052/b83ff65a-7425-96ed-d70d-d8089469de3a.png)

ということで、

「ActiveRecord::StatementInvalid in IncomeValues#index」

「データベースがおかしいよ」

ってことみたいです。



色々調べてみましたが、全く解決できませんでした。。
そこでQiitaで質問しました。

すると、ありがたいことに回答をいくつかいただきました。

どうやら、controllerの

```
IncomeValue.order("year_month asc")
```
が怪しいみたく、orderの指定の仕方がおかしいようです。


そこで、

```
IncomeValue.order(year_month: :asc)
```
としたところ、
このエラーがなくなりました！


君には苦戦したよ。。。って感じで
エラーが解消されたのはよいものの、、、



また次に
「NoMethodError in IncomeValues#index」
がでてきてしまったのです。。。



その３に続く👇
https://qiita.com/Shota_U/items/a589a080815032a24092
その１「Rails初心者」が5回連続で発生したエラーをなんとか切り抜けた話。「index (投稿一覧) が表示できない」

ポートフォリオの家計簿アプリ作成中、非常に躓いた箇所がありましたので備忘録として書いていきます。

何に躓いたかというと、同じところで5回連続エラーが起こったのです。

※３～４日ほどでやっと解消できました😊


今回はエラーの内容と、それを解決した方法をそれぞれ書いていきます。


苦悩の連続の全てはここから始まりました。


まず、エラー画面はでていないのですが、
投稿一覧が表示されないという事態が起こりました。

関係のあるコードはこちら

```index.html.erb
<% require 'active_support/core_ext/numeric/conversions' %>
<h2>収入科目の新規データ登録</h2>
<p>登録年月を設定してください</p>
<%= form_tag({controller: :income_values, action: :new}, {method: :post}) do %>
    <input type="month" name="year_month">
    <input type="submit">
<% end %>

<h2>収入科目 データ一覧 </h2>
<% if @income_value.present? %>
<table>
  <tr>
    <th>登録年月</th>
    <th>名称</th>
    <th>値</th>
    <th>備考</th>
    <th>操作</th>
  </tr>
    <% @income_values.each do |income_value| %>
  <tr>
        <td><%= income_value.year_month.strftime('%Y年%m月') %></td>
        <td><%= @incomes.find(income_value.income_id).name %></td>
        <td><%= income_value.value.to_s(:delimited) %> 円</td>
        <td><%= income_value.description %></td>
        <td><%= link_to "編集", [:edit, income_value] %> | <%= link_to "削除", income_value, method: :delete, data: { confirm: "本当に削除しますか？"} %></td>
  </tr>
  <% end %>
</table>
<% else %>
    <p>登録されているデータがありません。</p>
<% end %>

```

```income_values_controller.rb
class IncomeValuesController < ApplicationController

    def index
      @incomes = Income.order(created_at: :asc)
        @income_values = IncomeValue.order("year_month asc")
    end

    def show
        @income_value = IncomeValue.find(params[:id])
    end

    def new
        year_month_day = params[:year_month] + "-01"
        @year_month = year_month_day.to_date

        @incomes = Income.order(created_at: :asc)
        @form = Form::IncomeForm.new
    end

    def edit
        @income_value = IncomeValue.find(params[:id])
        @income = Income.find(@income_value.income_id)
    end

    def create
        @form = Form::IncomeForm.new(income_form_params)
        if @form.save
            redirect_to :income_values, notice: "登録しました"
        else
            redirect_to :income_values, notice: "登録に失敗しました"
        end
    end

    def income_form_params
        params
            .require(:form_income_form)
            .permit(income_values_attributes: Form::IncomeValue::REGISTRABLE_ATTRIBUTES)
    end

    def update
        @income_value = IncomeValue.find(params[:id])
        @income_value.assign_attributes(params[:income_value])
        if @income_value.save
            redirect_to :income_values, notice: "情報を更新しました"
        else

```



一覧が表示されなかった原因は、

`index.html.erb`
の

```
<% if @income_value.present? %>
```

の変数が単数形だったからでした。

```
<% if @income_values.present? %>
```

として、解決！

しっかり確認することの大切さを改めて実感しました。


原因が分かって、
「一覧が表示される！」と思いきや、

「ActiveRecord::StatementInvalid」というエラーがでてしまったのです。。。

そして僕はこのエラーにとてつもなく苦しみました。




その２に続く👇
https://qiita.com/Shota_U/items/c93eb669b3f8078785eb
Firebaseでデータの取得、追加、更新を行う

# Firebaseでデータの読み込み、書き込み、更新を行う

## 目次
### 1.目的
### 2.データ操作の基本
### 3.データ取得
### 4.データ追加
### 5.データ更新
### 6.まとめ

## 1.目的
備忘録として
[前提条件]
・Firebaseの構築に関しては、もう終わっている。
(Firestoreの設定も含めて)

## 2.データ操作の基本
FirestoreにアクセスするためのAPIは既に用意されている。

データ操作の基本として、以下の構文が基本となる。
firebase.firestore()　−　①
　.collection('[コレクション名]')　−　②
　.where('[フィールド名]' ,'[比較演算子]' ,[検索する値])　−　③
　.orderBy('オーダーをかけるフィールド名' ,'[asc or desc]')　−　④
　.limit([整数])　−　⑤

上記が基本構造となる。
必須項目は　①、②
任意項目は　③、④、⑤

また、whereはメソッドチェーンで繋げることができる。
この時、重要となるのが、「Firebaseは'AND'条件のみサポートしている」という点である。
現在は、'OR'条件は利用できない。

また、利用できる比較演算子は以下の通り。
・'=='
・'>'
・'>='
・'<'
・'<='
・'in'
・'array-contains'
・'arrat-contains-any'

上記の中で説明が必要なのは、以下だと思う。
・'array-contains'
・'arrat-contains-any'

'array-contains' は、配列形式で持っているデータの中から、完全一致する文言を探す。
　こんな書き方
　　.where('[コレクション名]' ,'array-contains' ,'りんご')

'arrat-contains-any'　は上記の拡張版で配列形式で持っているデータの中から、完全一致する文言を複数個探す。
　こんな書き方
　　.where('[コレクション名]' ,'array-contains-any' ,['りんご', 'みかん'])


## 3.データ取得
データ操作の基本を踏まえ、取得は以下の様な記載方法となる。
firebase.firestore()
　.collection('[コレクション名]')
　.where('[フィールド名]' ,'[比較演算子]' ,[検索する値])
　.orderBy('オーダーをかけるフィールド名' ,'[asc or desc]')
　.limit([整数])
　.get();

記載しているのはjsなので、結果を待たない。
上記メソッドはpromise関数なので、「then()」を使うなり、「async await」を使うなりして取得する。

## 4.データ追加
firebase.firestore()
　.collection('[コレクション名]')
　.add(
　　{
　　　'name':'フルーツ',
　　　'number':1,
　　　available:true,
　　　'fruit':[
　　　　'りんご',
　　　　'みかん'
　　　],
　　　'creater':[{
　　　　'生産者':'AA農場',
　　　　'電話番号':'080-0000-0000'
　　　}],
　　　[{
　　　　'生産者':'BB農場',
　　　　'電話番号':'0９0-1111-1111'
　　　}]
　　}
　);

こんな感じ。
色々な型を使える。
[]は配列indexが自動でインクリメントされて生成される。
{}はkeyとvalueを指定できる。

例えば「'creater'」は以下の様に保存される。
[0] => 生産者 => 'AA牧場'
　　　電話番号 => '080-0000-0000'
[1] => 生産者 => 'BB牧場'
　　　電話番号 => '090-1111-1111'

ドキュメントIDは、何も指定しなければ自動生成される。
ドキュメントIDとは、そのデータを表す一意の特定を行うために作成されるID。

実は追加のメソッドは「add()」だけでなく「set()」も使えるが、多分使わない方が無難。
この辺は説明すると長くなるので、一旦省略。

もしも、ドキュメントIDを指定したい場合は、set()を利用する必要があるが、その場合は・・・いずれ書くかもしれません。

## 5.データ更新
firebase.firestore()
　.collection('[コレクション名]')
　.doc(ドキュメントID)
　.update(
　　{
　　　available:false,
　　}
　);

上記で追加したデータを更新すると考えたときに、他のフィールドは変更なく、「available」フィールドのみ更新される。


更新でも「set()」メソッドを使えるが、使わない方が無難。理由は（ry

## 6.まとめ
まずは基本を覚えて、
.get()
.add()
.update()

を覚えれば、基本的にはfirestoreを使える。
ZabbixでWindowsのイベントログを監視する方法

# 環境
監視ツール：Zabbix 2.4.6
監視対象：Windows Server 2012 R2

# 前提条件
Zabbix サーバがインストール＆設定されていること。
監視対象のホストに Zabbix エージェントがインストール＆設定されていること。
Zabbix のホスト設定で監視対象の Windows が登録されていること。

# アイテム作成
[設定]→[ホスト]→対象ホストの[アイテム]→[アイテムの作成]

名前：任意
タイプ：Zabbixエージェント(アクティブ)
キー：eventlog[System]
データ型：ログ
更新間隔：1秒
ヒストリ保存期間：任意
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83224/d3e7f765-0917-6666-e612-a56d6a50f381.png)
※上記はシステムログの例です。アプリケーションログはSystemの部分をApplication、セキュリティログはSecurityに置き換えてください。

# トリガー作成
今回はイベントIDが16949のログを監視します。
※イベントID16949はOS標準NICチーミングのメンバー切断時に発生します。

[設定]→[ホスト]→対象ホストの[トリガー]→[トリガーの作成]

名前：任意
条件式：{ホスト名:eventlog[System].logeventid(16949)}=1
障害イベントを継続して生成：チェック外します
深刻度：軽度の障害
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83224/da7c7fab-111d-0b70-be35-17cb2bb100b7.png)

# アクション作成
[設定]→[アクション]→[アクションの作成]

名前：任意
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83224/b7c09cbe-be5d-4d26-5a48-bd473535fb6e.png)


計算のタイプ：And
アクションの実行条件：
　A　トリガー = 上で作成したトリガー名
　B　トリガーの深刻度 = 上で作成したトリガーの深刻度
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83224/ad769d56-e2ba-196d-792c-9fa7d94116f3.png)

実行内容のタイプ：メッセージの送信
ユーザーに送信：メールを送信する任意のユーザ(予めユーザーは作成しておく)
次のメディアのみ使用：Email
追加をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83224/00c91809-5715-cbbf-dda9-75d03ce4b00e.png)


追加をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83224/c27562dd-2aba-8c62-498b-78e20b3b92b4.png)


# 確認
NICチーミングした片方のLANケーブルを抜き、イベントID16949のログを発生させます。

[監視データ]→[イベント]
登録したイベントが発生したことが確認できます。
![zabbix_event.png](https://qiita-image-store.s3.amazonaws.com/0/83224/788df9bb-2463-163d-7a7f-ec9d68a82e4c.png)

メール通報確認
障害通知メールが届きます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83224/4e4310a9-32cb-d83a-2658-99e3ff5589a7.png)

# 保留にしている問題点

障害検知後にしばらく経つと、障害は続いているにもかかわらず勝手に復旧（正常）になってしまう。
障害状態を継続させるための何らかの仕組みが必要。
NestJS でエラーレスポンスをカスタマイズしてみる[Typescript]

# やりたいこと

デフォルトの Exception が返すこんな感じのレスポンスを。

```json
{
  "statusCode": 400,
  "message": "id must be number.",
  "error": "Bad Request"
}
```

例えばこんな感じに変更したい。

```json
{
  "message": "Bad Request",
  "errors": [
    {
      "resource": "Issue",
      "field": "id",
      "code": "must be number"
    }
  ]
}
```

(どちらも Status Code は 400 が返る想定)

# やること

NestJS は最後まで Catch されなかった Exception を拾ってエラーレスポンスを生成してくれるので、そこで拾ってくれる Exception を独自の形で書いてあげれば良い。

# 実装

## Exception Class

### Base

```ts
import { HttpException, HttpStatus } from "@nestjs/common";

export class CustomHttpException extends HttpException {
  constructor(
    message: string,
    errors: Array<{
      resource: string;
      field: string;
      code: string;
    }>,
    statusCode: HttpStatus
  ) {
    const response = {
      code,
      title,
      message,
    };
    super(HttpException.createBody(response, message, statusCode), statusCode);
  }
}
```

### Bad Request 用

```ts
import { HttpStatus } from "@nestjs/common";
import { CustomHttpException } from "./CustomHttpException";

export class BadRequestException extends CustomHttpException {
  static readonly message = "Bad Request";
  constructor(
    errors: Array<{
      resource: string;
      field: string;
      code: string;
    }>
  ) {
    super(BadRequestException.message, errors, HttpStatus.BAD_REQUEST);
  }
}
```

# 使い方

こんな感じで書いてあげれば、あとは NestJS が拾って良い感じに返却してくれる。

```ts
throw new BadRequestException([
  {
    resource: "Issue",
    field: "id",
    code: "must be number",
  },
]);
```
WSL2を有効化してからカスペルスキーのファイルスキャンが度々停止する

# 先日からKaspersky Internet Security 20 でファイルスキャン(カスタム,簡易関わらず)を行おうとすると，スキャン中に勝手にスキャン停止してしまうようになった
![スキャンログ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/226891/d617232e-7b94-62d8-cadb-f2ac3a17898d.jpeg)

# TL;DR
**[カスペルスキーのハードウェア仮想化を使用した保護](https://help.kaspersky.com/KIS/2019/ja-JP/83057.htm)とHyper-Vが干渉していた模様**
Hyper-VやVMWareなどの仮想化技術を使用する場合には，カスペルスキーのハードウェア仮想化を使用した保護を無効化しましょう

# カスペルスキーのハードウェア仮想化を使用した保護の無効化方法
可能な場合はハードウェアを仮想化するのチェックを外す
![カスペルスキーのハードウェア仮想化を使用した保護の無効化](https://support.kaspersky.co.jp/images/common_13713_0154-504013.png)
参考:
[エラー「 ハードウェアを仮想化できません。互換性のないハードウェアまたはソフトウェアが検出されました。」](https://support.kaspersky.co.jp/common/safemoney/13713)

# まとめ
Windows10でDockerを使うためにWSL2を有効化した為，仮想化技術の競合が発生してしまった?
スキャンプロセスが瞬時にKillされるのでウイルスに感染でもしたのかと焦りましたが仕様?で良かったです
【AWS×WordPress】504 Gateway Time-outが出た

#はじめに
AWS（AWS Linuxインスタンス）上でWordPressをたてて使用していたが、ある日突然504 Gateway Time-outが出た。
<img width="341" alt="スクリーンショット 2020-07-31 8.31.56.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449478/e4de8853-e3db-3e23-471e-690eb2dc01cc.png">

#504 Gateway Time-outの意味
[Wikipedia](https://ja.wikipedia.org/wiki/HTTP%E3%82%B9%E3%83%86%E3%83%BC%E3%82%BF%E3%82%B9%E3%82%B3%E3%83%BC%E3%83%89)によると、5XXはサーバエラーを指し、504は「ゲートウェイタイムアウト。ゲートウェイ・プロキシサーバはURIから推測されるサーバからの適切なレスポンスがなくタイムアウトした。」を意味する。サーバ側のエラーということでAWS上での問題っぽそう。

#色々試してみる
<h2>試したこと①</h2>
[AWS上に構築したWordPressで「504 gateway timeout」が頻発した時の対処法](https://qiita.com/kimurayut/items/566f4de4075b075d549d)
ALBのターゲットグループをhttp&https→httpに変更したということだが、もともとhttpだった。

<h2>試したこと②</h2>
[【504 Gateway Time-out】【Bad Request】でブログがつながらない！AWSのELBをチェック](https://www.keitaiplan.com/aws-elb-504-gateway-time-out-bad-request/)
DNS名・IPアドレス直打ちで入れたらアクセスできたというが、今回はできず。

<h2>試したこと③</h2>
[【WordPress】504 Gateway Time-out が出た時の対処法](https://sho-d-blog.com/tech/589/)

```
$ df -h
```

ストレージの容量を確認できるとのことだが、使用% を見ても、特に割合が高くなかった。

<h2>試したこと④</h2>
[【AWS】【WordPress】「504 Gateway Timeout Error」の原因](https://sashihara.jp/aws-wordpress-504)
Apacheが起動しているかを確認するとのこと。

```
$ sudo systemctl status httpd.service
```

この時`Active: active (running)`になっていたため、てっきりApache側での問題ではないと勘違いしていたが、これは間違いだった。


#解決策

```
$ sudo systemctl restart httpd.service
```

今回はApahceがいつの間にか落ちてしまったらしく、上記コマンドでApacheを再び起動させ、504エラーが解消されWordPressの画面が表示された。
statusで確認してもたまにうまく反映できてないことがあるらしいので、psコマンドでちゃんとプロセスが起動しているかを確認する方が確実とのこと。

#反省点
ネット記事を探して手当たり次第、試していたが下記記事のようにもう少し問題点を切り分けて行うべきだった。

[インフラ苦手な人が知っておくといい、Webサイトにつながらない障害パターンと解決方法]
(https://qiita.com/ykyk1218/items/5a541246e82678b2ece3) 

ググった方が早い場合もあるが、インフラ力を高めるためにもログなどで原因を予測した上で確認したい。
Golangで再帰関数を書く

仕事でGoで再帰関数を書いた時に苦戦したので備忘録として残しておきます。

## サンプルコード

```
func unpackStruct(data interface{}) interface{} {
	switch d := data.(type) {
	case *structpb.Struct:
		_metadata := make(map[string]interface{})
		for k, x := range d.Fields {
			_metadata[k] = unpackStruct(x.GetKind())
		}
		return _metadata
	case *structpb.Value_StructValue:
		_metadata := make(map[string]interface{})
		for k, x := range d.StructValue.Fields {
			_metadata[k] = unpackStruct(x.GetKind())
		}
		return _metadata
	case *structpb.Value_ListValue:
		_metadata := make([]interface{}, len(d.ListValue.Values))
		for i, x := range d.ListValue.Values {
			_metadata[i] = unpackStruct(x.GetKind())
		}
		return _metadata
	case *structpb.Value_StringValue:
		return d.StringValue
	case *structpb.Value_NumberValue:
		return d.NumberValue
	case *structpb.Value_BoolValue:
		return d.BoolValue
	case *structpb.Value_NullValue:
		return d.NullValue
	default:
		return d
	}
}
```

内容としては、gRPCのgoogle.protobuf.Struct型をパースする処理です。
gRPCで受け取ったデータをDBに書き込む、といった処理はよくあると思うのですが、そのまま書き込むと取り出す時に非常に読みづらい形式になってしまうため取得時にパースしてやる必要があります。

こういった処理はライブラリがあると思うのですが、ぱっと探したところ無いように見えたので自力で書きました。

## Golangで再帰関数を書く時の注意点

再帰関数を書く場合のユースケースとして引数に与えた型によって条件を分岐する場合があるかと思います。
pythonやJavascriptのような動的型付けの言語では気にする必要は無いのですが、Goのような静的型付けの言語では引数の型をしなければならず、かつ指定すると型に応じたメソッドを呼び出せない、というジレンマに陥ってしまいます。（単にGoビギナーなだけですが...）

この問題を解消する手段としてinterface型を引数に指定します（interface型は特殊な型でどのようなデータ型も許容できます）。

interface型として与えた引数を「switch d := data.(type)」のようにswitch文とキャストを組み合わせて処理することで、型に応じたメソッドが利用できるようになります。
deviseでデフォルトparameterを設定する方法

チーム開発の新規ユーザー登録を実装中に陥った事例…あまり起こることはないと思うのですが、万が一のために！

#前提として
通常であれば、deviseを使用してuser登録を実装する場合のparameterはdeviseがデフォルトを持っているためapplication.controller.rbには以下の記述をすれば良いと思います。

```application.contoller.rb
class ApplicationController < ActionController::Base
  before_action :configure_permitted_parameters, if: :devise_controller?

  protected

  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up, keys: [:nickname])
  end
end
```
しかし、今回deviseで作成はしたもののテーブル名をcreate_userにしてしまっている！
これではdeviseのデフォルト設定のままではでたを受け取ることができない為、こちらでparameterのformを修正してあげなければダメ！となりました！

[参考にさせていただいたgithub](https://github.com/heartcombo/devise#strong-parameters)

```application.controller.rb
class ApplicationController < ActionController::Base
  before_action :configure_permitted_parameters, if: :devise_controller?

  protected
  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up) do |user_params|
      user_params.permit(:nickname, :email, :password, :password_confirmation)
    end
  end
end
```
こちらで無事、保存できるようになりました！

あまり起こる事例ではないと思いますが良い経験をしたなと！
[Zabbix] Web監視の応答時間は画像ファイルなども含む？

# はじめに
 ZabbixのWeb監視は応答時間(Response time)を取得しグラフ表示できますが、画像ファイルなど全ての要素を読み込んだ時間なのか、それともHTMLファイル単体なのか検証してみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83224/b221aeac-46f3-bc3a-aa02-40e21329bdcb.png)


# 環境

* Zabbix 4.0.1
* CentOS 7.5 + Apache 2.4

# Webブラウザから
まずは普通にクライアントからWebブラウザでページ表示し、その時のWebサーバーのログを確認してみます。

```log:access_log
172.16.xx.xx - - [14/Nov/2018:13:54:52 +0900] "GET / HTTP/1.1" 200 454 "-" "Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:63.0) Gecko/20100101 Firefox/63.0"
172.16.xx.xx - - [14/Nov/2018:13:54:52 +0900] "GET /logo1.png HTTP/1.1" 200 51614 "http://172.16.yy.yy/" "Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:63.0) Gecko/20100101 Firefox/63.0"
172.16.xx.xx - - [14/Nov/2018:13:54:52 +0900] "GET /logo2.png HTTP/1.1" 200 51614 "http://172.16.yy.yy/" "Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:63.0) Gecko/20100101 Firefox/63.0"
172.16.xx.xx - - [14/Nov/2018:13:54:52 +0900] "GET /logo5.png HTTP/1.1" 200 51614 "http://172.16.yy.yy/" "Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:63.0) Gecko/20100101 Firefox/63.0"
172.16.xx.xx - - [14/Nov/2018:13:54:52 +0900] "GET /logo3.png HTTP/1.1" 200 51614 "http://172.16.yy.yy/" "Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:63.0) Gecko/20100101 Firefox/63.0"
172.16.xx.xx - - [14/Nov/2018:13:54:52 +0900] "GET /logo4.png HTTP/1.1" 200 51614 "http://172.16.yy.yy/" "Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:63.0) Gecko/20100101 Firefox/63.0"
172.16.xx.xx - - [14/Nov/2018:13:54:52 +0900] "GET /logo7.png HTTP/1.1" 200 51614 "http://172.16.yy.yy/" "Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:63.0) Gecko/20100101 Firefox/63.0"
172.16.xx.xx - - [14/Nov/2018:13:54:52 +0900] "GET /logo8.png HTTP/1.1" 200 51614 "http://172.16.yy.yy/" "Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:63.0) Gecko/20100101 Firefox/63.0"
172.16.xx.xx - - [14/Nov/2018:13:54:52 +0900] "GET /favicon.ico HTTP/1.1" 404 209 "-" "Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:63.0) Gecko/20100101 Firefox/63.0"
172.16.xx.xx - - [14/Nov/2018:13:54:53 +0900] "GET /logo6.png HTTP/1.1" 200 51614 "http://172.16.yy.yy/" "Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:63.0) Gecko/20100101 Firefox/63.0"
```
PNG形式の画像ファイルなどもログに記録されていることが分かりました。

# Zabbixから
次にZabbixのWeb監視を設定し、監視時のWebサーバーのログを確認。

```log:access_log
172.16.zz.zz - - [14/Nov/2018:13:57:38 +0900] "GET / HTTP/1.1" 200 454 "-" "Zabbix"
```
ログに記録されたのは『GET /』だけでした。
つまりHTMLファイル単体のみ読み込んでいることが分かります。

# さいごに
3秒ルールという言葉があるようにWebサイトの表示速度は重要ですが、ZabbixのWeb監視の応答時間はそのままユーザーからみた表示時間とならないので鵜呑みにしないようにしましょう。
Flutter学習2日目後編 -公式を読む 3. テストドライブ編-

**※自分の学習記録のメモとしてこの記事を書いています。**

1日目：[Flutter学習1日目 -公式を読む 1. インストール編-](https://qiita.com/umiremix/items/940f38e03be4b71dc33d)
2日目前編：[Flutter学習2日目前編 -公式を読む 2. エディターの設定編-](https://qiita.com/umiremix/items/0ff6600a6a9f996a3a74)
2日目後編：Flutter学習2日目後編 -公式を読む 3. テストドライブ編-（イマココ）

今回は公式ドキュメントの[Test drive](https://flutter.dev/docs/get-started/test-drive?tab=vscode)ページを進めて行きます！
このページではテンプレートから新しいFlutterアプリを作成→実行し、アプリに変更を加えると「ホットリロード」する体験方法が説明されています。

今回はVS Codeで進めていきます🔥

## アプリを作成する

1. View > Command Paletteを選択します（もしくは⌘+Shift+P）
2. 「flutter」と入力し、Flutter：New Projectを選択
![スクリーンショット 2020-07-31 6.11.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62182/39f43cfa-3780-4c14-6ec4-54e5b7854083.png)
3. プロジェクト名（myapp）を入力し、Enteｋrキーを押します
![スクリーンショット 2020-07-31 6.11.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62182/913ce5f6-3b08-df05-e3cd-f1e31939e72a.png)
4. 親ディレクトリを求められるので選択します（私の場合は~/works）
5. main.dartファイルが表示されるまで待って終わりです
![スクリーンショット 2020-07-31 6.13.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62182/b0ca5ffc-d2c0-9c16-6b5d-0093b5bd09f2.png)

## アプリを実行する

1. VS Codeの下部にある青いステータスバーを見つけます
![スクリーンショット 2020-07-31 7.10.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62182/b65074d5-afa9-e855-e813-14cddb19984f.png)

2. Device Selectorからデバイスを選択します（私の場合はシミュレーターを選択しました）
![スクリーンショット 2020-07-31 7.10.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62182/7dd645d9-c4c5-1561-fbd6-7f5dc82193f2.png)

3. Run > Start Debuggingを選択します
4. アプリの起動を少し待ちます。アプリのビルドが完了するとシミュレーターの画面が変わります
![スクリーンショット 2020-07-31 7.15.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62182/b5965241-3878-d139-600f-313f9e533db9.png)
![スクリーンショット 2020-07-31 7.15.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62182/5b939360-2c1b-f02a-a69a-190bee62e9e2.png)

## ホットリロードを試す

1. lib/main.dartを開きます
2. 文字を変更します

```
'You have pushed the button this many times'
```
👇👇👇

```
'You have clicked the button this many times'
```
3. 保存するとホットリロードでシミュレーターの文字が変わりました🎉
![スクリーンショット 2020-07-31 7.22.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62182/4c0e06a6-794f-22f1-8ae5-ebc9472a880e.png)

## プロファイルまたはリリースの実行

とても便利なホットリロードですが、公式で注意書きがありました。

>So far you’ve been running your app in debug mode. Debug mode trades performance for useful developer features such as hot reload and step debugging. It’s not unexpected to see slow performance and janky animations in debug mode. Once you are ready to analyze performance or release your app, you’ll want to use Flutter’s “profile” or “release” build modes. For more details, see Flutter’s build modes.

訳：
これまでは、デバッグモードでアプリを実行していました。デバッグモードは、ホット リロードやステップデバッグなどの開発者にとって便利な機能のためにパフォーマンスを犠牲にしています。デバッグモードでパフォーマンスが低下したり、ぎこちないアニメーションが表示されるのは予想外のことではありません。パフォーマンスを分析したり、アプリをリリースしたりする準備ができたら、Flutterの「profile」または「release」ビルドモードを使用することをお勧めします。詳細については、Flutterの[ビルドモード](https://flutter.dev/docs/testing/build-modes)を参照してください。

実際にリリースする際には十分気をつけたいと思います！

# 感想

iOSを開発している方が「ホットリロードは感動する」って言っていたのできっとネイティブ開発の方にとっては目玉の機能なんだろうな〜と思って今回進めていました☺️

次回（3日目）は、小さなアプリを作成して、Flutterのコアとなる概念を学びます！💡
【Java】文字の出現回数を調べる

#目次
- はじめに
- 前提
    - 実現したいこと
    - やってみたこと
    - 問題
    - 解決方法
- 実装内容
- 終わりに

##はじめに
ふと、<b>MapとかListとか勉強したい！！</b>と思ったので課題考えて作ってみましたが
MapとListの役割とか変換とかでかなり躓きました。
オンラインで検索してもあんましいいの出てこなかったので、自分なりにまとめたので記事にします。


##前提
- 実現したいこと
    - n個の任意の文字列型入力(n_1 n_2 n_3... ...n)に対し、最も多く登場した文字列の特定。
- やってみたこと
    - Map<String, Integer> map = Map<String Integer>();として、[key:入力文字列, value:登場回数]を実装。
    - mapを[value]でソートして一番最初の[key]を取り出せばいいじゃん！

- 問題
    - Map系[HashMap, LinkedHashMap, TreeMap]は、基本的には要素に順番を持たない。
    - map[0]のように、インデックスでは値を取り出せない。

- 解決方法
    - Map.Entryクラスを利用して、マップのkeyとvalueの組み合わせを取得できる。
    - List内にEntryオブジェクトを格納して、List[i]のEntryのvalueでソートができる。

##実装内容
解決方法をもとに実装した内容が以下です。

```CountMain.java

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Scanner;

public class CountMain {

	public static void main(String[] args) {

		// 入力検知
		Scanner sc = new Scanner(System.in);
		String count = sc.nextLine();
		String[] line = sc.nextLine().split(" ");

		// マップ作製
		Map<String, Integer> map = new HashMap<String, Integer>();
		for(int i=0; i<line.length; i++){
			if(!map.containsKey(line[i])){
				map.put(line[i], 1);
			} else {
				int tmp = map.get(line[i]);
				map.remove(line[i]);
				map.put(line[i], tmp+1);
			}
		}

		// mapのエントリを取得→listへ格納
		List<Entry<String, Integer>> list = new ArrayList<Entry<String, Integer>>();
		for (Map.Entry<String, Integer> entry : map.entrySet()){
				list.add(entry);
		}

		// list内entryのバリューを比較→ソート
		for (int i = 0; i < list.size(); i++){
			for (int j = list.size()-1; j > i; j--){
				if (list.get(j).getValue() > list.get(j-1).getValue()){
					Map.Entry<String, Integer> tmpEntry = list.get(j-1);
					list.set(j-1, list.get(j));
					list.set(j, tmpEntry);
				}
			}
		}
		
		System.out.print(list.get(0).getKey());
		try {
			int i = 1;
			while( list.get(i).getValue() == list.get(i-1).getValue() ){
				System.out.print(" " + list.get(i).getKey());
				i++;
			}
		} catch (IndexOutOfBoundsException e){
			return;
		} finally {
			System.out.println("");
			sc.close();
		}
	}
}
```

##終わりに
- まとめ
    - 各クラスごとの役割を意識するのが大事
        - Mapは連想配列、順序付けの配列が必要な時は機能をListに投げる
        - これができてないから最初にMapをソートしようとしてわからなくなってた
- 今後の課題
    - list内のソートは人力バブルソートでやってるけど、Collection.sort()とか使えそう。
    - Comparator<>みたいなのとかが役に立ちそう。
- 以下参考リンク
    - https://www.sejuku.net/blog/16176
    - http://lovedvoraklayout.hatenablog.com/entry/java-map-value-sort-2
    - https://teratail.com/questions/117328
Power BIでヒストグラムを描くのは簡単だったという話

##Power BIに「ヒストグラム」がない！

Power BIはデータを簡単に可視化できるBIツールです。

円グラフや棒グラフ、折れ線グラフ、ツリーマップ、などなど多種多様なグラフを自由自在に描くことができます。

ところが、不思議なことに**「ヒストグラム」がどこにもない**のです。
一体これはどうしたことか？
ヒストグラムほどポピュラーなグラフをなぜ描けないのか疑問に思っていました。

いろいろ検索してみると、「カスタムビジュアルでヒストグラムを入れる」か「Pythonビジュアルを使ってPythonでヒストグラムを描く」かどちらかしかないように見えました。

正直どちらも面倒臭く、それでも頑張ってPythonビジュアルを実装しようとしましたが、numpyのインポートエラーがどうしても解消できず、もう諦めかけていました。

ですが、実はこんな苦労をしなくてもデフォルトの機能を使って簡単にヒストグラムは作れることがわかりました。

##「新しいグループ-ビン」を使えばOK

あっけない話ですが、ヒストグラム化したいデータに対して「グループ(ビン)」を作ればいいだけの話でした。

ここでは有名なタイタニックの生存者データで「Age」(年齢)のヒストグラムを作ります。

1.ヒストグラム化したいデータに対し、「新しいグループ」を選択します。
![powerbi_hist1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634673/9c27e298-14ed-b004-8c4a-e09896907ab8.png)



2.グループの種類で「ビン」を選びます。
ビンのタイプは「ビンのサイズ」か「ビンの数」か好きな方を選びます。

例えば、年齢の階級幅を10にしたいときは、ビンのサイズ=10とします。
<img width="560" alt="powerbi_hist2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634673/f21f96c1-adde-557c-42e2-72c421c67418.png">


3.新しいグループ(「Age(ビン)」)ができます。
![powerbi_hist3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634673/b51d32f7-b5f0-9a36-b435-0fa41cdb204b.png)

4.視覚化から「集合縦棒グラフ」を選び、軸に「Age(ビン)」、値に「Age」の"カウント"を指定します。

![powerbi_hist4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634673/955245fd-c9a3-f299-3e74-7667136769aa.png)


すると、これはまさにヒストグラムですね。

「ヒストグラム」というグラフがあるわけではなく、「グループ-ビン」で度数分布を作ってそれを集合縦棒グラフでグラフにするということでした。
どんなニュース見出しでも緩やかに景気回復させてくれるプログラム


# プログラム

import feedparser

RSS_URL = 'https://news.yahoo.co.jp/pickup/rss.xml'

d = feedparser.parse(RSS_URL)
for entry in d.entries:
    print(entry.title,'だから緩やかに景気回復しています。')

# 引用元 h1

https://techacademy.jp/magazine/19148

# メモ h1

↑にprintをくっつけただけ。楽しみながらプログラムを作りたい。
https://youtu.be/DsSNpegZLoA
5分40秒〜
jsonをcsv(カンマ区切り、項目行あり)に変換する(構文破壊に対応)

以下の記事にあるJSON変換用関数、すごくわかりやすくて重宝しているのですが、
文字列をダブルクオーテーションで囲んでないので、
「あいうえお"」や「あい,うえお」のような、構文破壊系の文言が来ると死にます。

https://qiita.com/_shimizu/items/38e6d75afcacec25eb7e

ので、見出し行以外を全てダブルクォーテーションで囲んでカンマによる構文破壊を防ぎ、
ダブルクォーテーション一つだけの文字列は二つにすることで、そちらの構文破壊も防ぐようにします。

おまけで、見出し行を出力するかどうかを選択できるようにしました

### 実装

```javascript
/**
 * Convert json to csv
 * Supports syntactic destruction
 *
 * @params array-object records
 * @params boolean isHeaderDraw [default true]
 * @return string
 * @link https://qiita.com/_shimizu/items/38e6d75afcacec25eb7e
 * @link https://qiita.com/qwe001/items/60f6cb264110490d7d90
 */
function json2csv(records, isHeaderDraw)
{
  var isHeaderDraw = isHeaderDraw !== undefined && isHeaderDraw === false ? false : true;

  if(! records || records.length === 0){
    return "";
  }

  var header = Object.keys(records[0]).join(',') + "\n";

  var body = records.map(record => {
    record = Object.keys(record).map(key => {
      var field = record[key];
      if (field) {
        field = field.replace(/\"/g, "\"\"");
        //field = field.replace(/\r?\n/g, " "); // 改行を無効にしたい場合
      }
      return field;
    }).join("\",\"");

    return "\"" + record + "\"";
  }).join("\n");

  return isHeaderDraw ? header + body : body;
}
```

### 使い方

```javascript
var a = [
    {id:1, name:"test", address:"tokyo"},
    {id:2, name:"hoge", address:"構文破壊1\""},
    {id:3, name:"hello", address:"構文,破壊2"},
    {id:4, name:"world", address:"saitama"}
];

json2csv(a);

//output
id,name,address
"1","test","tokyo"
"2","hoge","構文破壊1"""
"3","hello","構文,破壊2"
"4","world","saitama"

// 見出し行が要らへんとき
json2csv(a, false);

//output
"1","test","tokyo"
"2","hoge","構文破壊1"""
"3","hello","構文,破壊2"
"4","world","saitama"
```

バグなどあったら教えてくれると助かります。
eclipseにspring bootとgradleを追加する

前回の記事はこちら
[Javaの環境構築をしてhelloworldを出力する](https://qiita.com/kty000/items/5c6519d46a9a72b33dd2)

今回はspring bootとgradleを追加してみましょう。

#spring bootってなに？
JavaによるWebアプリケーションの開発を迅速かつ効率的に行う仕組みを備えたフレームワークです。
フレームワークとはプログラミングを効率化するために用意された、プログラムのひな形のようなものです。
要はプログラムを簡単に書くためのヤツです。

#Gradleってなに？
wikiより
>GradleはApache AntやApache Mavenのコンセプトに基づくオープンソースビルド自動化システムであり、プロジェクト設定の宣言にはApache Mavenが利用するXML形式ではなくGroovyベース、もしくはKotlin Scriptベースのドメイン固有言語 (DSL) を採用している

うん。よくわからん。調べたところこちらの記事がとてもわかりやすかったです（[Gradle入門](https://qiita.com/vvakame/items/83366fbfa47562fafbf4)）

開発するうえで便利なものはいろいろあります。それを使うためのものを毎回１つづつ取ってくるのは面倒なのでGradleさんにこれよろしく～といえばGradleさんがやってくれる。みたいな感じだと思っています。



#追加する
Eclipse Marketplaceから追加します。
１．[Help] => [Eclipse Marketplace]を開く
２．serchにgradleと入力して検索し、インストールを押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550109/efb29ded-53ea-1ed5-88e2-3b0d047abe48.png)
３．ライセンスのレビューがでるのでI acceptを選択してfinish
４．インストールが完了すると再起動してねと言われるので再起動して完了です。

１～４と同じ要領でプラグインの追加ができますのでspringも追加しましょう。



次回は開発に便利なプラグインを追加します。
次 => [Eclipseにプラグインをインストールする](https://qiita.com/kty000/items/634f642a49fcb8ede40f)
Javascriptを一から勉強する（JavaScriptの基本事項編）

一時期勉強していたJavascriptを１からざっくり勉強し直すための記事です．他人に教えることが３倍ぐらい勉強したことになるという理論がモチベーションです．
自分と同じようにJavascriptを一からざっくり勉強したい人にはおすすめですが，それ以外の人は閲覧注意（間違った解釈が多いかもしれないので）．

https://www.javadrive.jp/javascript/ini/index1.html
↑を参考に勉強していきます

#JavaScriptとは？
https://techacademy.jp/magazine/8801 から引用
>JavaScriptはプログラミング言語であり、ユーザー側のWebブラウザと、Webサイトまたはウェブサービスの相互間のやりとりを、円滑にするために使われています。

>実質的に、私たちがブラウジングで体験できることのすべては、ブラウザの中で使われているJavaScriptの処理によるものです。

>Webサイトの外観のデザインや使い心地から、Netflixのサイトに表示される映画の題名のようなサイト内の情報表示に至るまで、JavaScriptが使われています。

つまりWeb系言語で，HTMLの拡張機能的な何かで，UXに重要なプログラミング言語ってことかなるほど．

#スクリプトの記述
>1. 大文字小文字は区別する（Num=num）
2. スクリプト内の空白と改行は無視される(var n=　0とvar num=0は同じ)
3. 文の区切りにはセミコロンを付ける(var num=0;)

基本的にはProcessingと一緒やな，大文字小文字の区別はコンピュータ君頭いいなと思えばいいし，改行や空白はめんどくさがりには大変うれしくてありがとうございましたやし，セミコロンは日本語の句読点と同じ役割やし簡単やな，次．


#スクリプトが実行されるタイミング
>Script要素が表れるとHTMLの記述の中にあろうが実行される

```html
<p>HTML文の解析中</p>
<p>この次にスクリプトが実行される</p>

<script type="text/javascript"</p>
document.write("<p>スクリプトが出力</p>");
</script</p>

<p>スクリプトが終了</p>
<p>HTML文の解析を続行</p> 
```
なるほど（なるほど），実行したい順番にコードを書かないといけないことね
#分散して記述されたスクリプトの扱い
>分散してても１つのスクリプトに記述されたように実行される


```html
 <p>XHTMLの文1</p>

<script type="text/javascript">
var num = 10;
</script>

<p>XHTMLの文2</p>

<script type="text/javascript">
num = num * 10;
</script>

<p>XHTMLの文3</p>

<script type="text/javascript">
document.write("<p>結果は" + num + "です</p>");
</script> 
```
だとしても

```html
<script type="text/javascript">
var num = 10;
num = num * 10;
document.write("<p>結果は" + num + "です</p>");
</script>
```
のようなスクリプトとして実行されるらしい．分散されてても変数はそのファイル内でちゃんと共有されてるのよって感じですね

#特殊な文字の入力(エスケープシーケンス)
>入力できない文字を他の文字の組み合わせで表現したものをエスケープシーケンスといいます。
（¥b＝改行，¥'=シングルクオーテーションなど）

``` 'It's a pen' ```だと意味の違うシングルクオーテーションが文の中にもあってバグるけど``` 'It¥'s a pen' ```にするとバグらなくなるらしい．時々必要になる秘密のコマンドみたいなもんだね．

ということで今日はここまで．初心者が作ったノートは果たして本当に初心者に分かりやすいものなのかは神のみそしる．
[rails]Controllerに定義するアクション一覧

#Controllerに定義するアクション一覧
RailsではWebアプリケーションの基本となる以下の7つの役割を持つアクションを用います。

| アクション名 | 役割 |
|:--|:--|
| new | データを新規作成する |
| create | データを追加（保存）する |
| index | データの一覧を表示する |
| show | データの内容（詳細）を表示する |
| edit | データを更新するためのフォームを作成する |
| update | データを更新する |
| destroy | データを削除する |
PHPでAWS CLIを用いてS3に画像をアップする

EC2環境上でPHPのexec関数とAWS CLIを用いてS3に画像をアップしようと思ったら、嵌ったので備忘録メモです。

まず、事前にEC2上で

```
$ aws configure 
```
を叩いて、アクセスキー ID、シークレットアクセスキー、AWSリージョン、出力形式を入力した後に、PHPファイルに

```php5
exec('aws s3 sync  ./upload  s3://{バケット名}/img --acl public-read --delete', $out);
```
を挿入し、実行してみましたが$outに結果が返らず、S3にもアップされませんでした。
そこで、PHPのファイル上に事前に次の形式でアクセスキー ID、シークレットアクセスキー、AWSリージョンを記述したあとにexec関数を記述すると動作しました。

```php5

$region = 'ap-northeast-1';
$key = '****';
$secret = '**********************';
putenv('AWS_DEFAULT_REGION=' . $region);
putenv('AWS_ACCESS_KEY_ID=' . $key);
putenv('AWS_SECRET_ACCESS_KEY=' . $secret);
exec('aws s3 sync  ./upload  s3://{バケット名}/img --acl public-read --delete', $out);
```

ただし、PHPファイルにキー情報を直接書いてしまうのはセキュリティ的に問題ありそうなので、APPACHと同じキーをユーザーに割り当てる方法もあるようです。
kintoneで性別判定をしてみよう

# はじめに
- ES2015以降の構文を含むため、Chromeでのみ動作確認をしています
- サンプルコードのため実際の使用は自己責任でお願いします🙇‍♂️

# 作るもの
- 名前を元に性別を自動判定する

![タイトルなし.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535789/b12882d0-62e7-1c29-d045-200f191f6089.gif)

# フォーム構成
![スクリーンショット 2020-07-31 17.31.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535789/01b2c68b-3358-e2cf-93f4-dd19c5266a53.png)

| フィールド名（フィールドコード）| 種別 |
| --- | --- |
|姓（姓） | 文字列（１行）|
|名（名） | 文字列（１行）|
|LastName（LastName） | 文字列（１行）|
|FirstName（FirstName） | 文字列（１行）|
|性別（性別） | ドロップダウン|
## API
今回は [Genderize](https://genderize.io/)というAPIを使って性別判定を行います。
使用方法は簡単で、https://api.genderize.io/?name=●● と叩くと推定性別、パーセンテージが返ってきます。
ただし、日本語には対応していませんのでアルファベットで渡してあげる必要があります。
また、国の指定もできるので今回は**country_id=JP**というパラメータを付与します。
このパラメータが結構重要で、mika（みか）という日本名は概ね女性につけられますが、
英語圏だとmichaelの略名だったりする関係で、パラメータなしだと男性判定、パラメータありだと女性判定になります。
よって外国人も含む場合は国名などのフィールドを用意してパラメータを変化させることを要件に追加するのもありでしょう。

## カスタマイズ
今回はレコード追加画面を保存したタイミングで性別判定を行い、ドロップダウンに性別を反映します。

```JavaScript:gender.js
(() => {
  'use strict';
  kintone.events.on('app.record.create.submit', event => {
    const record = event.record;
    const firstName = record.FirstName.value;
    const apiUrl = `https://api.genderize.io/?name=${firstName}&country_id=JP`;
    return kintone.proxy(apiUrl, 'GET', {}, {}).then((args) => {
      const res = JSON.parse(args[0]);
      const gender = res.gender;
      record.性別.value = gender === 'male' ? '男' : '女';
      return event;
    });
  });
})();
```

## 留意点
- Genderize APIは1日1000件までが無料範囲内です。
- 実際の運用では、Possibilityに基づき、閾値を設定する必要がありそうです。
- 今回のコードにはエラー処理を含めていません。
Fortran90覚え書き (超基本)

とても基本的なことなのだが、他の言語と混ざっていつまで経っても覚えられない（覚える気がない）のでメモ。

# 比較演算子

演算子 | 意味
-----| -----
.lt. | <
.le. | <=
.eq.  |==
.ne. | /=
.gt. | >
.ge. | >=


# 論理演算子

演算子 | 意味
-----| -----
.not.  |   ノットイコール
.and.  |  &
.or.   |    もしくは
.eqv.  |  論理値が等しい
.neqv. | 論理値が等しくない

# 引数の取得

文字列としての取得になるので、数値の場合は`read`し直す必要がある。

```fortran:sample.f90
program sample
	implicit none
	integer         :: nmax
	character(256)  :: arg

	if( iargc() == 2 ) then
  		call getarg(1,arg)
		read(arg,*) nmax
        	call getarg(2,arg)
		open(90,file=trim(arg))
	else 
		!---引数が2つでなければ、適当な値/文字列を使用
		nmax=1000
		open(90,file="tmp.dat")
	end if
end program
```