OmniAICreator/Qiita-1.07M huggingface dataset:
静的サイトでサイトマップ/RSSを生成する

[あおやぎのさいと2.0](https://www.saoyagi2.net/)という個人サイトを HTML 手打ちの静的サイトで運営しています。静的サイトであってもサイトマップとか RSS とかは出力したいのですが、さすがにそれらまで手打ちで作っていたら面倒でしょうがない。ということで、こんな簡単スクリプトを作って生成しています。

```Perl:mksitemap.pl
#!/usr/bin/env perl

use strict;
use warnings;

use POSIX 'strftime';

print <<'XML';
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
XML

foreach my $file (`find . -name "*.html"`) {
  chomp $file;
  $file =~ s!^\./!!;
  my @stat = stat($file);
  my $lastmod = strftime( "%Y-%m-%d", localtime($stat[9]));
  print <<"XML";
<url>
  <loc>https://www.saoyagi2.net/${file}</loc>
  <lastmod>${lastmod}</lastmod>
</url>
XML
}

print <<'XML';
</urlset>
XML
```

```perl:mkrss.pl
#!/usr/bin/env perl

use strict;
use warnings;

use Encode;
use utf8;

print encode('utf-8', <<"RSS"
<?xml version="1.0" encoding="UTF-8"?>
<rss version='2.0'>
<channel>
<title>あおやぎのさいと2.0</title>
<link>https://www.saoyagi2.net/</link>
<description>あおやぎ(saoyagi2)の個人サイトです。</description>
RSS
);

my @items;
foreach my $file (`find . -name "*.html"`) {
  chomp $file;
  $file =~ s!^\./!!;

  my $buffer = decode('utf-8', `cat $file`);

  next if(!($buffer =~ /<meta name="date" content="(.*)">/));
  my $date = $1;
  next if(!($buffer =~ /<title>(.*)<\/title>/));
  my $title = $1;
  next if(!($buffer =~ /<article>(.+?)<nav>.+?<\/nav>.+?<\/article>/s));
  my $description = $1;
  $description =~ s/<.+?>//sg;
  $description = substr($description, 0, 100);

  push(@items, [$file, $title, $description, $date]);
}
@items = (reverse sort {$a->[3] cmp $b->[3]} @items);
splice @items, 10;

foreach my $item (@items) {
  print encode('utf-8', <<"RSS"
<item>
<title>${$item}[1]<\/title>
<link>https://www.saoyagi2.net/${$item}[0]<\/link>
<description>${$item}[2]<\/description>
<pubDate>${$item}[3]<\/pubDate>
<\/item>
RSS
);
}

print encode('utf-8', <<"RSS"
</channel>
</rss>
RSS
);
```

文字列連結で XML 組み立てたりしてるいい加減なものですがね。

RSS 生成時の記事作成年月日は各記事に `<meta name="date" content="YYYY-MM-DD">` と入れておいて、それを拾うようにしています。

最終的には AWS S3 + AWS CloudFront 環境へ以下のスクリプトでデプロイ。

```shell
#!/bin/sh
./mksitemap.pl > sitemap.xml
./mkrss.pl > rss.xml
aws s3 sync . s3://www.saoyagi2.net/ --delete
aws cloudfront create-invalidation --distribution-id xxx --paths '/*'
```
＜スプレ＞GASでAPI（json）を送受信する(GAS)


あるツールに対してデータを送信した時に使ったコードをメモとして残します。

結論(jsonを分解)
--------------
JSON.parseを使用する。

    JSON.parse( "取得したjson" );

結論(jsonを分解：URLでリクエストした場合)
--------------
JSON.parseに加えて、UrlFetchApp.fetch、getContentText()を使用する。

    JSON.parse(UrlFetchApp.fetch("リクエストURL").getContentText()); 

結論(jsonを分解：keyやvalueをそれぞれ取得したい場合)
--------------
     Object.entries


結論(jsonを作る)
--------------


    JSON.stringify( data );



具体例
--------------
```
function test() {
  
  //jsonを分解する  
  var jget ='{"a":"アイウエオ","b":"カキクケコ"}';
  var jarr = JSON.parse(jget); 
  Logger.log(jarr) //{a=アイウエオ, b=カキクケコ}
  Logger.log(jarr.a) //アイウエオ
  Logger.log(jarr.b) //カキクケコ
  
  //値を変更することも可能
  jarr.b = "XXX";
  Logger.log(object);//XXX
  
  //キー自体がわからない時は、parseではなくObject.entriesで分解がわかりやすい。
  for (var [key, value] of Object.entries(jarr)) {
    Logger.log(`${key}`);//"a" "b"
  }

  
  //jsonを分解する(URLでリクエストした場合)
  var url = 'リクエストURL';
  var res = UrlFetchApp.fetch(url);
  var object = JSON.parse(res.getContentText()); 
  Logger.log(object);

  //jsonを作る
  var obj = {
    name: '太郎',
    age: 30,
    area: 'Tokyo'
  } 
  var json = JSON.stringify( obj );
  Logger.log( json ); // { "name": '太郎',"age": "30","area": 'Tokyo'} 
  
  //jsonを作る前の辞書型の作り方
  
  var keys = ["name", "address", "tell" ],
      values = ["東京都庁舎", "東京都新宿区歌舞伎町1-7-1", "03-5321-1111"],  
      for (var i = 0, l = keys.length, obj = Object.create(null); i < l; ++i) {
        if (values.hasOwnProperty(i)) {
          obj[keys[i]] = values[i];
        }
      }
  console.log(JSON.stringify(obj)); // [{"name":"東京都庁舎","address":"東京都新宿区歌舞伎町1-7-1","tell":"03-5321-1111"}]

```


参考
・[GASでTwitterAPIを叩いてみる](https://tech-cci.io/archives/4228)
・[JSON.stringifyを改めて調べる。](https://qiita.com/qoAop/items/57d35a41ef9629351c3c)
・[【JavaScript入門】JSONの作成とparse() / stringify()の使い方！](https://www.sejuku.net/blog/47716)
・[【JavaScript入門】連想配列(Dictionary)の取得/追加/ソートまとめ
](https://www.sejuku.net/blog/27965)
・[スプレッドシートのデータからオブジェクトを作成](https://moripro.net/gas-object-key/#i)
・[二つの配列をそれぞれkeyとvalueにして一つの連想配列にする方法](https://teratail.com/questions/54502)
Podデザインパターン

# 概要
KubernetesではPod内の各コンテナのネットワークが共有されておりローカルホスト（127.0.0.1）上のポート番号で相互にアクセス可能で、以下のようなパターンを実現できる

- Sidecar（サイドカーパターン)
- Ambassador（アンバサダーパターン）
- Adapter（アダプターパターン）

# 各パターンの解説
### サイドカーパターン
Pod内の機能を独立して用意できる
ログの出力はメインのアプリ、ログの転送部分はサイドカーとして共通の機能をコンテナで用意
そのほかに、同期サービスやプロセスのウォッチャーなど

### アンバサダーパターン
外部プロセスとの接続をプロキシする構造のこと。例えば本番と開発環境で異なるDBへ接続する必要があるときに、アプリ側はローカルホストを参照するようにしておき、データベースへの接続をアンバサダーコンテナが行う
### アダプターパターン
Podに接続するインターフェイスをアダプターパターンで共通化する考え方。例えばアプリケーションのモニタリングを行う際に、アダプターコンテナが一貫したAPIを提供することによって監視システムからの要求にこたえる。とくにモニタリングにおいては、異なる環境下に配置されているアプリケーションを動的に検出して監視に必要なシステムを一環して提供できることが重要なため、これが利用される。ただし、多くの場合DaemonSetによって、ワーカーノードごとに配置される。

# 気づいたことなど
- コンテナ単位ではなくPod単位で管理する意味を感じた
- いわゆるxxxagentのようなものはアダプターパターンということになりそう
- ネットワークの共有はPodが提供する基本機能なのか確認したい
  → [Kubernetesのネットワークモデル](https://kubernetes.io/ja/docs/concepts/cluster-administration/networking/#kubernetes%E3%81%AE%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AF%E3%83%A2%E3%83%87%E3%83%AB)のIP-per-podの説明を見ると基本機能でよさそう

# その他
調べてる最中に見かけたのでついでにメモ

- Serviceについて
Loadbalancerタイプの場合、外部のロードバランサーを使用することになるとのこと、それで、いずれかのノードで起動しているサービスに接続し、そこからまたどこかのノードにあるPodにルーティングされる模様（そのノードのPodに限らないという意味）
Rails 環境構築　railsコマンドでのエラー


railsで環境構築をしている際に`rails server`コマンドを打ってもrailsコマンドが使えない、バージョン管理でのエラーがいくつか発生した。各エラー内容と解決した方法をまとめておく。

#実行環境
OS: MacOS
rubyバージョン管理：rbenv
railsバージョン:6.0.3.2
シェル:zsh

#エラー内容

```
$ rails server
```
とうつと

```ruby

Rails is not currently installed on this system. To get the latest version, simply type:

    $ sudo gem install rails

You can then rerun your "rails" command.
```

Railsは現在このシステムにはインストールされていません。
`sudo gem install rails` というコマンドで最新版のRailsをインストールすることができます。とのエラーが発生した。

#やったこと
ここはエラーで指摘された通り

```
$ sudo gem install rails
```
を実行した。とりあえずこれでrailsコマンドを使うことはできた。

```
$ rails -v
Rails 6.0.3.2
```
と打ってもバージョンがちゃんと表示され、railsコマンドが使えるようになった。
他の記事などをみているとこれを行なってもエラーが解消されないことが発生している。
調べた範囲ではrbenvでrubyのバージョン管理を行っているとgemの参照先によるエラーもあるそうで、これはPATHを指定してやることで解決するそう。
rbenv自体がデフォでrubyとgemを持っているので、gemを使ってもデフォルトのrubyが起動してしまうためだそうだ。

#エラー内容2

```
$ rails server
```
を打つと

```
warn_for_outdated_bundler_version': You must use Bundler 2 or greater with this lockfile. (Bundler::LockfileError)
```
という違うエラーが発生した。このロックファイルでは、Bundler 2 以上を使用する必要があります。とのことでbundlerのバージョンが適正でない?という内容。

#やったこと2
```
$　gem update --system
```
RubyGemsのバージョンアップを実行。そして

```
$ bundle update --bundler
```
bundlerのアップグレートを実行。



最後に`rails server`を実行したら

```
Please run rails webpacker:install
```
と出たので

```
$ bundle exec rails webpacker:install
```
を実行することでサーバーの起動が確認できた。

<img width="1440" alt="スクリーンショット 2020-07-26 15.35.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640758/721def05-fa2f-2b5e-2203-184ca0471f15.png">
[Ruby] 標準入力を受け付ける際に ^H などの ASCII 制御文字を意図した通りに認識させる

# 結論
**`STDIN.gets` ではなく `Readline.readline` を使おう**

# STDIN.gets
Ruby で標準入力を受け取る方法を調べると、多くの場合、以下の実装方法が出てきます。

```ruby:stdin.rb
print '> '
text = STDIN.gets.strip
puts "You said #{text}!"
```

```bash
$ ruby stdin.rb
> hello
You said hello!
```

`gets` の他にも `read` や `readline`、`readlines` があるようです。
[Ruby 標準入力から複数行読み取りたい](https://nnnamani.hateblo.jp/entry/2016/08/14/150900)

## 欠点
しかし、上記の方法だと ASCII 制御文字を意図した挙動で認識させることができません。

```bash
$ ruby stdin.rb
> hello^H^H^H
You said he!lo
```

上記の例では、`hello` と入力したあとに、ASCII 制御文字の backspace (`ctrl` + `H` で入力可能) を 3 回入力しています。

本当は `hello` と入力したあとに 3 回 backspace の制御文字を入力しているので `he` となってほしいのですが、`hello^H^H^H` となってしまい、標準入力の受け付けを終了したあとに backspace が適用されています。

# 解決方法
これを意図した通りにするためには以下のように実装します。

```ruby:readline.rb
require 'readline'

print '> '
text = Readline.readline
puts "You said #{text}!"
```

```bash
$ ruby readline.rb
> he # "hello" と入力したあとに ctrl + H を 3 回押した
You said he!
```

# その他
`Readline.readline` は、他にもヒストリを使うことができたりして便利です。カーソルの上キーや `ctrl` + `P` を押すと、前に入力した文字列を表示することができます。詳しくは [module Readline のリファレンスマニュアル](https://docs.ruby-lang.org/ja/latest/class/Readline.html) を参照ください。

ASCII 制御文字については [Wikipedia](https://ja.wikipedia.org/wiki/%E5%88%B6%E5%BE%A1%E6%96%87%E5%AD%97) をご覧ください。
重なった汎化関係はこれでいいの？

次のようなクラス図を書くとします。

1. インクジェットプリンタ，レーザープリンタは，プリンタの一種である
2. PIXUS，カラリオは，インクジェットプリンタの一種である
3. DocuPrint，Satera は，レーザープリンタの一種である


このような記述をもとに，次のようなクラス図を書きました。このモデルに何か違和感を感じませんか？

<img width="379" alt="Screen Shot 2020-07-26 at 14.59.34.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55223/2e9aa1cd-0d6c-3005-838a-6a5b83fbccad.png">

違和感の元は，1の汎化関係と，2,3の汎化関係で，微妙に意味が異なるからです。1の汎化関係は，プリンタの実現方式の違いを表しています。それに対し2の汎化関係は，ブランド名の違いを表しています。この2つは，意味が違いますよね？

こういう時には，関連と合わせて使って，意味の違いを明確にモデリングすると良いです。

<img width="681" alt="Screen Shot 2020-07-26 at 15.10.59.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55223/1c0277e6-2f41-7cc1-6fa5-44d13e93d93c.png">

その上で，次のようにOCLを使って制約関係を表します。

```
context: プリンタ inv:
  self.印刷方式.oclAsType(インクジェットプリンタ) implies (self.ブランド.oclAsType(PIXUS) or self.ブランド.oclAsType(カラリオ))
  and self.印刷方式.oclAsType(レーザープリンタ) implies (self.ブランド.oclAsType(DocuPrint) or self.ブランド.oclAsType(Satera))
```

これの意味するところを日本語で書くと次のようになります。

* 次の条件のどちらも成立する
  * 印刷方式がインクジェットプリンタクラスだったならば，ブランドのクラスはPIXUSかカラリオである
  * 印刷方式がレーザープリンタクラスだったならば，ブランドのクラスはDocuPrintかSateraである

なお，印刷方式がインクジェットプリンタクラスでなかった場合， `self.印刷方式.oclAsType(インクジェットプリンタ)` は偽になるので，`self.印刷方式.oclAsType(インクジェットプリンタ) implies (self.ブランド.oclAsType(PIXUS) or self.ブランド.oclAsType(カラリオ))` は前提条件を満たさず真になることに注意してください。(「AならばB」という命題がある時，Aが偽だった時にはBが真でも偽でも「AならばB」は真になる)
MongoDB 基礎



##Collection
RDBのテーブルに該当するようなもの

##Document
RDBのレコードのようなもの
JavaScriptのオブジェクトの形式でデータを入れていく

例)
{
  name: "taguchi",
  score: 30
}

キーのことをフィールドと読んだりする

mongoDBはスキーマレスの為、Documentに入るデータの構造を予め決めておく必要がない

#コマンド

###show dbs;
データベースの表示

###show collections;
コレクションの表示


###use test;
testデータベースへの切り替え、存在しない場合、testデータベースの作成
test箇所は任意で指定可能

※データベースの中にコレクションとドキュメントが作られていない場合、存在しないことになっている。

###db.createCollection("testCollection");
コレクションの作成

###db.stats();
現在のデータベースに関する情報を表示

###db.dropDatabase();
現在のデータベースの削除

###db.dataBaseName.renameCollection("changeName");
コレクション名の変更

###db.colelctionName.drop();
コレクションの削除

###db.documentName.insert({ name: "k47", age: 26 });
ドキュメント挿入
コレクションは、ドキュメントを作成すると自動的に作成される

###db.collectionName.find();
指定したコレクション内のドキュメントを全て表示

※"_id"はmongoDBが自動で作成するもの(データをユニーク(一意)にする為のもの)

&条件の場合は、引数にカンマ区切りで条件を追加していく

###db.collectionName.find({$or: [{条件1}, {条件2}...]});
or条件の場合

###db.collectionName.find({feeldName: {$in: [値1, 値2]}});
フィールド内が同じ中でのor条件の場合


###db.collectionName.remove({});
指定したコレクション内のドキュメントを全て削除

###db.collectionName.remove({抽出条件});
抽出条件に合致したドキュメントの削除

###$gte
grater than or equal

{$gte: 10}
10以上

###$gt
grater than

{$gt: 10}
10より大きい

###$lte
less than or equal

{$lte: 10}
10以下

###$lt
less than

{$lt: 10}
10より小さい

###$eq
equal

###$ne
not equal

###db.collectionName.distinct( "feeldName" );
フィールドの値を出力

###db.collectionName.find({ feeldName: { $exists: 真偽値});
指定したフィールドが存在するドキュメントを出力

###db.collectionName.find({}, { feeldName1:真偽値, feeldName2:真偽値 });
指定したフィールドを出力する
※trueならtrueのみ、falseならfalseのみ。真偽値の混在は不可
("_id"に関しては、非表示(false)が可能)

###db.collectionName.find({},{}).sort({feeldName: 1});
検索結果のソート
1  昇順
-1 降順

###db.collectionName.find({},{}).limit(num);
検索結果の件数を引数の数だけ出力する

###db.collectionName.findOne({},{});
該当する1件目だけを出力

###db.collectionName.find().skip(num);
引数の数だけ出力を飛ばせる
numが3であれば、検索結果の4件目から出力される

###db.collectionName.update({抽出条件},{feeldName:値});
抽出条件のdocumentを丸ごと上書き

###db.collectionName.update({抽出条件},{#set: {feeldName: 値});
フィールドの値の更新

.update()は該当した最初の1件を更新する

###db.collectionName.update({抽出条件},{更新する値},{multi:true})
該当する全件を更新する

###db.collectionName.update({抽出条件},{更新する値},{upsert:true});
抽出条件に合致するドキュメントがなければ作成
Tech企業の技術Blogなど

個人開発や企業探しをする過程で見つけた技術ブログを自分用に残しています。


#[SmartNews Engineering Blog](https://developer.smartnews.com/blog/)
あまり更新数は多く無い

##[マネーフォワード](https://bit.ly/33FCEIx)

バックエンドメインでRails・JavaScriptを使用している。
当たり前だが社員さんのGitHubを覗いても草がみっしり生えていて、活発度が高い。
技術的な記事のみでなく、社員間のコミュニケーションに関することなども書かれている。
マネーフォワードなどの会計系のサービスがRailsで開発されているのは意外でした。

・[Railsでリファクタリングにオススメな gem 5選]
(https://bit.ly/3kq7wCV)
・[マネーフォワードCTOが考えていること（2020年3月）]
(https://bit.ly/3fJE2MC)



##[Eyes, JAPAN Blog](bit.ly/2WYLmxj)

RailsによるPDF出力の方法を調べていた時に発見した開発企業の技術ブログ。
業務上で使った技術などを社員さんが都度発信してくれている。

["脱Google map API"の記事](https://bit.ly/2WUiLcE)


##[GA TECH BLOG](https://tech.ga-tech.co.jp/)
不動産業界の業務効率化を実現するB2Bサービスを複数リリースしているGA Technologiesが発信している技術ブログ。
使用技術はRails, React, Dockerなど。

slim導入後に参考にした記事↓
・[Railsのテンプレートエンジンを、slimやhamlから、erbに戻して乗り換えた話](https://bit.ly/3if1fYT)

・展開しているサービスの公式HP↓
 [「nomad cloud」](https://nomad-cloud.jp/follow_up_client)

##[SELECK]()

読む、真似る、仕事に役立つ。
現場の事例から学べるビジネスメディア「SELECK」

技術特化のサイトではないが、マネジメントについてなどビジネス系のコンテンツもとても面白いです。


知ったきっかけの記事↓
・[チーム開発を変える「GitHub」とは？〜Pull Requestの使い方〜【連載第2回】](https://bit.ly/39VlrMq)

・[3年で270名に拡大！全社フルリモートでも「情報格差」を生まない組織の運営法](https://seleck.cc/1399)

運営会社はデザインがすごく綺麗。社員さんがnoteでメディア発信もしてくれています↓
・[ 運営会社RELATIONSのHP ](https://bit.ly/33l1YDq)

社員のいけだだいきさんのnote↓
・[ 未経験から3ヶ月でエンジニアになった時の話](https://bit.ly/2BSuzEL)

##[WIRED](https://wired.jp/)

技術ブログではないが、米国発のテクノロジー系メディアなので参考になる。

・[シリコンヴァレーに蔓延するセクハラと差別という“病”](https://bit.ly/3fF4BT6)


##[TechRacho](https://techracho.bpsinc.jp/)

新宿の受託開発会社が運営している技術ブログ。


##[SEゼミをやったら♥OSSになった](https://bityl.co/4SDu)

技術Blogのカテゴリーに入れていいのか微妙なラインですが、[GitHubでライブラリを公開したら★300以上がついて海外からも注目された学生にインタビューしてみた!](https://bityl.co/4SER)など、面白くて勉強になる記事がたくさんあります。
2018年で更新が止まってしまっているのが残念。

#[DeNAのエンジニアブログ](https://engineer.dena.com/)
・[Fi](https://engineer.dena.com/posts/2020.12/lp-generator/)
Cookieについて

#Cookieについて
・正確には、HTTP Cookie
・Webブラウザに保存された情報
・セッションのIDはCookieに保存される
・ユーザー識別やセッション管理を実現する目的で利用される
・グーグルの広告は、Cookieにそのデータ（閲覧データ）を保存して、広告を動的に出している。
・3つの用途で使用（1.セッション管理、2.パーソナライゼーション（テーマなど）、3.トラッキング（利用履歴など））

###メリット
・ユーザーの情報をブラウザに保存ができる。⇨一度のログインでそのサイトを回れる（Cookieがない場合、毎回本人確認をしなければならない。）
・ログイン状態を維持できる。

###デメリット
・知識のある人なら、その内容を覗くことが可能


##Cookieの使用ルール
・１つのドメインに対して、20個までのCookieの保存が可能
・１つのCookieは名前と値を合わせて4kバイトまで設定可能
・クライアントが保存できるCookieの数は全体で300まで。

###Cookieとセッションの違い
・データの保存場所が違う
　　セッション　 ⇨　サーバー側
　　Cookie　　 ⇨　ブラウザ側
・保存期間の違い
　　セッション　 ⇨　ブラウザを閉じるか、サイトを離れる
　　Cookie　　 ⇨　永続クッキーだと保持し続ける
・サイズ制限
　　セッション　 ⇨　制限なし
　　Cookie　　 ⇨　制限あり

####セッションとは
・一連の処理の最初から最後までを表す概念

###まとめ
・役所で発行される整理番号と似ているなと感じました。
・現在では、新しいストレージAPIを利用することが推奨されている。(Web Storage API, IndexedDB API)


###参考
書籍
・プロになるためのWeb技術入門
・Webを支える技術

ネット
・https://developer.mozilla.org/ja/docs/Web/HTTP/Cookies
・https://www.ipa.go.jp/security/ciadr/20030808cookie-secure.html
https://qiita.com/hththt/items/07136ad74127999df271
・https://qiita.com/7968/items/ce03feb17c8eaa6e4672
・https://ja.wikipedia.org/wiki/HTTP_cookie
・https://umaroidblog.com/webtechnology1
・https://ssaits.jp/promapedia/technology/cookie-session-cache.html#:~:text=%E3%82%AF%E3%83%83%E3%82%AD%E3%83%BC%E3%81%AF%E3%82%AF%E3%83%A9%E3%82%A4%E3%82%A2%E3%83%B3%E3%83%88%E5%81%B4%E3%81%AE,%E3%82%92%E4%BF%9D%E6%8C%81%E3%81%97%E7%B6%9A%E3%81%91%E3%81%BE%E3%81%99%E3%80%82
【PHP】素数の計算

素数計算を高速化する。
[こちら](https://tsg.ne.jp/TT/tsg/c/mansaku/P01.html)の記事を自分なりに備忘録としてまとめました。

#1万以下の素数のコード
##最初に書いたコード
```php5
$start = microtime(true);
play();
$end = microtime(true);
print "\n".'処理時間 = ' . ($end - $start) . '秒'."\n" ;

function play()
{  
    for ($i=max($prime)+1;$i<100000; $i++) {
        if (checkPrime($i)) {
          print $i."\n";
        }
    }
}

function checkPrime($num)
{
    $count=0;
    for ($i=2; $i <$num ; $i++) {
        if ($num%$i==0) {
            return false;
        }
    }
    return true;
}
```
2つの関数で生成する方法しか思いつかなかった
##処理時間
```
処理時間 = 19.969306945801秒
```
約20秒かかった。

#最初から考えて作り直す
##素数は約数が1と自分自身のみ
その数が1と自分自身の2回だけ割り切れたならそれは素数

```php5  
    for ($i=1; $i <10000 ; $i++) {
      // print $i."\n";
      $yakusuu=0;
        for ($j=1; $j <=$i ; $j++) {
            if ($i%$j==0) {
                $yakusuu++;
            }
        }
        if ($yakusuu==2) {
            print $i."\n";
            // break;
        }
    }
```
##処理時間
```
処理時間 = 1.4896070957184秒
```
#高速化
##素数の約数は1と自分自身のみ
ということは奇数のみをループにかければいい
もちろん2は除く。

```php5
    printf('%5d',2);
    for ($i=3; $i <10000 ; $i+=2) {
      // print $i."\n";
      $yakusuu=0;
        for ($j=3; $j <=$i ; $j+=2) {
            if ($i%$j==0) {
                $yakusuu++;
            }
        }
        if ($yakusuu==1) {
            printf('%5d',$i);
            // break;
        }
    }
            print "\n";


##処理時間
```
処理時間 = 0.39670991897583秒
```
AWS WAFv2 を Terraform で扱うときの注意点

# 概要
* マネジメントコンソール（手動）で CloudFront 用に作成した AWS WAFv2 を terraform import したときにハマったこと。
* 最初から terraform で AWS WAFv2 を作成するときも同様にハマったと思う。

# ハマったこと
## AWS provider のバージョンが古かった
* エラー
 * AWS provider 2.48.0 で terraform import すると、次のようなエラーが出る

```
Error: unknown resource type: aws_wafv2_web_acl
```

* 原因
 * aws_wafv2_web_acl は、AWS provider 2.67.0 から使えるようになった<br />https://github.com/terraform-providers/terraform-provider-aws/pull/12688

* 対処
 * AWS provider を 2.67.0 へ上げた
 * AWS provider を上げた後は、terrafrom init を実行 


## terraform import を実行するリージョンが違っていた
* エラー
 * 東京リージョンから terraform import すると、次のようなエラーが出る

```
Error: WAFInvalidParameterException: Error reason: The scope is not valid., field: SCOPE_VALUE, parameter: CLOUDFRONT
{
  RespMetadata: {
    StatusCode: 400,
    RequestID: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
  },
  Field: "SCOPE_VALUE",
  Message_: "Error reason: The scope is not valid., field: SCOPE_VALUE, parameter: CLOUDFRONT",
  Parameter: "CLOUDFRONT",
  1 resource "aws_wafv2_web_acl" "example" {
  Reason: "The scope is not valid."
}
```

* 原因
 * AWS WAFv2 の terraform 実行は、us-east-1 (バージニア北部)で実行する必要があるらしい。
 * ここが参考になった<br />https://dev.classmethod.jp/articles/cloudformation-webacl-cloudfront-error/

* 対処
 * us-east-1 から terraform import を実行する

```
$ terraform import -provider="aws.virginia" aws_wafv2_web_acl.example xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/example/CLOUDFRONT
```

# terraform 設定例

* 構成
<pre>
└── wafv2
　　　├── backend.tf
　　　├── example.tf
　　　└── provider.tf
</pre>

* provider.tf 抜粋

<pre>
provider "aws" {
  version                 = "2.67.0"
  shared_credentials_file = "credentials"
  profile                 = "terraform"
  region                  = "ap-northeast-1"
}
provider "aws" {
  version                 = "2.67.0"
  shared_credentials_file = "credentials"
  profile                 = "terraform"
  alias                   = "virginia"
  region                  = "us-east-1"
}
</pre>
Python パッケージとモジュールの呼び出しについて

# 概要
- パッケージとモジュールの呼び出し方について記述方法を忘れないように残しておく

# 前提
- 下記のようなディレクトリ構成で各ファイルを配置

```python
lesson
|- lesson.py *実施のコードを記載するファイル
|- utils.py  *モジュールの内容を記載しておくファイル 
|- __init.py__
```
- utils.py中身

```python
def f(word):
    return(word) * 2
```

# 記述方法
## フルパスで指定する場合
- lesson.pyは下記のように記載する

```
import lesson.utils
r = lesson.utils.f('hello')
print(r)

※hellohelloと表示
```

## モジュールから呼び出す場合
- lesson.pyは下記のように記載する

```
from lesson import utils
r = utils.f('hello')
print(r)

※hellohelloと表示
```

## 関数から呼び出す場合
- lesson.pyは下記のように記載する

```
from lesson.utils import f
r = f('hello')
print(r)

※hellohelloと表示
```

# その他
- 上記の「関数から呼び出す場合」は使用しない方がいいらしい
- 理由としてはコードが長くなって、最後の方で関数: fを呼び出した際にどこのモジュールから引っ張ってきたか分からなくなる為。したがって「フルパスで指定する場合」か「モジュールから呼び出す場合」で呼び出す
APIをデバックエリアに表示させる〜Swiftで楽天レシピAPIを表示させてみた①〜

##やること
Swiftで楽天APIをデバッグエリア表示させる。

##APIからデータを取得する
今回使ったAPI
<a href="https://webservice.rakuten.co.jp/explorer/api/Recipe/CategoryRanking/" target="_blank">楽天レシピカテゴリ別ランキングAPI</a>
（楽天IDが必須になります）

```
{
 result: [
  {
   foodImageUrl:
  "https://image.space.rakuten.co.jp/d/strg/ctrl/3/34d4ce95b8674c8fb6c8f08b5115464a9f180c31.17.2.3.2.jpg",
   recipeDescription: "小鉢がもう1品ほしいなっていう時に簡単でオススメです。",
   recipePublishday: "2011/08/22 19:04:07",
   shop: 0,
   pickup: 1,
   recipeId: 1200002403,
   nickname: "JIMA88",
   smallImageUrl: 
  "https://image.space.rakuten.co.jp/d/strg/ctrl/3/34d4ce95b8674c8fb6c8f08b5115464a9 f180c31.17.2.3.2.jpg?thum=55",
  recipeMaterial: [
    "きゅうり",
    "ごま油",
    "すりごま",
    "鶏ガラスープのもと",
    "ビニール袋"
   ],
   recipeIndication: "5分以内",
   recipeCost: "100円以下",
   rank: "1",
   recipeUrl: "https://recipe.rakuten.co.jp/recipe/1200002403/",
   mediumImageUrl: 
  "https://image.space.rakuten.co.jp/d/strg/ctrl/3/34d4ce95b8674c8fb6c8f08b5115464a9f180c31.17.2.3.2.jpg?thum=54",
   recipeTitle: "1分で！うまうま胡麻キュウリ"
 }
```
##Codableを使ってJSONを変換させる
<a href="https://www.amazon.co.jp/%E6%94%B9%E8%A8%82%E6%96%B0%E7%89%88-Swift%E3%83%9D%E3%82%B1%E3%83%83%E3%83%88%E3%83%AA%E3%83%95%E3%82%A1%E3%83%AC%E3%83%B3%E3%82%B9-POCKET-REFERENCE/dp/4774196177/ref=sr_1_37?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=EB68JOSYXBCN&dchild=1&keywords=swift+%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0&qid=1595740539&s=books&sprefix=swift%2Cstripbooks%2C254&sr=1-37">参考にした本</a>
<a href="https://www.youtube.com/watch?v=sOcZnbKKt9A">参考にした動画</a>
<a href="https://qiita.com/UJIPOID/items/2c436a80f1167f7bcac0">参考にした記事</a>



今回は上記の楽天レシピAPIから記事のフードイメージurlとレシピタイトルを取得しました。

```
struct ResultList: Codable {
    
    let result: [User]
 
struct User: Codable {
    let foodImageUrl :String
    let recipeTitle  :String
}
}
```

##APIをURLSessionを使って叩く

```
class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
      getRApi()
    }
    
     private func getRApi(){
            guard let url = URL(string: "ここに楽天APIのURLを") else {return}
            
            let task = URLSession.shared.dataTask(with: url) { (data, response, err)in
                if let err = err {
                    print("情報の取得に失敗しました。:", err)
                    return
                }
                if let data = data{
                    do{
                        let resultList = try JSONDecoder().decode(ResultList.self, from: data)
                        print("json: ", resultList)
                    }catch(let err){
                         print("情報の取得に失敗しました。:", err)
                    }
                }
            }
            task.resume()
        }
    }

```

##実際にデバッグエリア
<img width="869" alt="スクリーンショット 2020-07-26 14.34.38.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/627010/5b1cc93f-6b6e-61c0-5faa-057680f676b9.png">

無事表示されました。
次はtableviewを作っていきたいと思います！

<a href="https://qiita.com/aa2302/items/52c76b33ceea5ed36aba">次の記事</a>
【爆速】VueCLI × netlify でWebアプリを公開する

### この記事について
この４連休、自粛生活で暇を持て余しているエンジニアマンです。
暇すぎてブログを立ち上げてみようと思いました。

ブログを立ち上げようとするのはこれで２回目です。
１回目はWordPressで立ち上げました。
でも個人的にWordPressの立ち上げは面倒くさい！
レンタルサーバを借りるのにお金かかるし、もっと楽にお金かけずに自分だけのサイトを立ち上げる方法ないかなー。

そこで見つけたのが、netlifyというホスティングサービスです。

netlifyを使えば、爆速でブログのようなwebページを立ち上げることができます。

WordPressとちがってフロントを自分から作っていく必要はありますが、何より無料で立ち上げられるというのが気軽でいい！！
今回はVueCLIで立ち上げたサンプルページをnetlifyで爆速公開させていきたいと思います。

### VueCLIでプロジェクトを立ち上げる
vueCLIでプロジェクト立ち上げまでの流れです

##### VueCLIインストール

割愛
##### プロジェクト作成
```.js
vue create [プロジェクト名]
```
##### ローカルで立ち上げてみる
```.js
yarn serve
```
すると次の[デモページ](http://localhost:8081/)が表示されるはずです。
今回はこちらのページをnetlifyで公開させてみます。

<img width="1391" alt="スクリーンショット 2020-07-26 14.03.23.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642420/16d8c698-2d03-b9a4-639c-505eaf590052.png">

### netlifyでアプリを公開

##### githubにローカルリポジトリをプッシュしておく
Githubに連携することで、リモートへのプッシュと同時に勝手にサイトを更新してくれるようになります！（便利すぎる）

ついでに連携させてしまいましょう

##### netlifyサービスに登録
[netlify](https://app.netlify.com/)の公式ページでgithub連携を選びアカウント登録します。

##### 新しいサイトを作成
画像の赤枠ボタンを押して、ホスティングさせるリポジトリを選択しましょう。

<img width="1236" alt="スクリーンショット 2020-07-26 14.15.56.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642420/2ac75400-2d4e-4d50-ff72-828bd4534f23.png">

##### デプロイ設定
github連携を選択肢し、
画像の設定画面で、
・ブランチ(branch to deploy)
・ビルドコマンド(build command)
・公開するディレクトリ(publish directory)
を設定します。

ビルドコマンドは yarn buildに
公開するディレクトリはdistに設定します。

<img width="760" alt="スクリーンショット 2020-07-26 14.19.21.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642420/40c29427-f442-dc62-9dd9-73f3a86182f9.png">

#### 公開完了
するとデプロイ作業が自動で始まります。

完了するまで少しだけ時間がかかるので待機しましょう。

デプロイ作業が完了すると、サイトのURLが生成されるのでそちらへアクセスするとVueのデモページが表示されます。

これでブログ作成のスタート地点に立てました！！
技術基準適合証明として用いられる技適マークの説明

応用情報技術者令和元年秋期 午前問80

技術基準適合証明として用いられる技適マークの説明として，適切なものはどれか。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591618/283bbb9b-4ee6-488b-052c-ffdeac5c10f7.png)


**技適マーク**は、電波法令で定めている技術基準に適合している無線機であることを証明するマークで、一般に使用できる無線機(小型トランシーバー、無線LAN機器、携帯電話、コードレス電話など)のほとんどのものに付けられています。技適マークが付いてない無線機を使用すると電波法違反になる場合があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591618/d71ef189-6a54-c745-dab2-3a99b136c251.png)

**CEマーク**
EU加盟国で販売する製品が，EUの安全規制に適合していることを証明する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591618/5712e6e2-1053-0288-b279-8fd25fe71374.png)

**PSEマーク**
日本国内で販売する電気用品が，日本の電気用品安全法の基準に適合していることを証明する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591618/39cc8d33-61ac-58ae-35cc-3e7aff8e600e.png)

**FCCマーク**
米国で設置する通信機器が，米国の規則に適合していることを証明する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591618/6f46154a-2880-0275-cafd-674801151e02.png)


参考：
https://www.ap-siken.com/kakomon/01_aki/q80.html
https://www.tele.soumu.go.jp/j/adm/monitoring/summary/qa/giteki_mark/
SplunkでOPPAI

https://qiita.com/samuragouchi-monzaemon/items/aa0f42301733c8bd68aa
を見て作りたくなった

```sql:oppai.spl
| makeresults count=2 
| streamstats count as x 
| eval x=if(x=1,0.00000,1.80000) 
| makecontinuous x span=0.001 
| eval tmp=mvrange(0,2) 
| mvexpand tmp 
| fields - _time tmp 
| streamstats count by x 
| eval x=if(count=2,-1 * x,x) 
| eval x_1=(1.5*exp(-0.62*pow(x-0.16,2)))/(1+exp(-20*(5*x-1))) 
| eval x_2 = (1.5+0.8*pow(x-0.2,3))*pow(1+exp(20*(5*x-1)),-1) 
| eval x_3 = (1+exp(-(100*(x+1)-16))) 
| eval x_4 = (0.2*(exp(pow(-(x+1),2))+1))/(1+exp(100*(x+1)-16)) 
| eval x_5 = (0.1/exp(pow(2*(10*x-1.2),4))) 
| eval y = round(x_1+(x_2/x_3)+x_4+x_5,4)
| sort 0 x
| table x y
```

![OPPAI](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130729/b5dbb7ef-1884-09cb-e4e5-558b9813965e.png)

[小島 功さん風](https://www.pinterest.jp/pin/568086940497179838/)
どうしても縦にできなかった・・・・

```sql:cannot_duplecate_y_axis.spl
| makeresults count=2 
| streamstats count as x 
| eval x=if(x=1,0.000,1.800) 
| makecontinuous x span=0.001 
| eval tmp=mvrange(0,2) 
| mvexpand tmp 
| fields - _time tmp 
| streamstats count by x 
| eval y=if(count=2,-1 * x,x)
| eval x=0.000
| sort 0 y
| table x y
```
調べてみると、Line ChartはY軸で重ねられないらしい・・・🙇

scatter plotでできたけど、縦横比が切なくなった。

```sql:scatter.spl
| makeresults count=2 
| streamstats count as x 
| eval x=if(x=1,0.00000,1.80000) 
| makecontinuous x span=0.001 
| eval tmp=mvrange(0,2) 
| mvexpand tmp 
| fields - _time tmp 
| streamstats count by x 
| eval x=if(count=2,-1 * x,x) 
| eval x_1=(1.5*exp(-0.62*pow(x-0.16,2)))/(1+exp(-20*(5*x-1))) 
| eval x_2 = (1.5+0.8*pow(x-0.2,3))*pow(1+exp(20*(5*x-1)),-1) 
| eval x_3 = (1+exp(-(100*(x+1)-16))) 
| eval x_4 = (0.2*(exp(pow(-(x+1),2))+1))/(1+exp(100*(x+1)-16)) 
| eval x_5 = (0.1/exp(pow(2*(10*x-1.2),4))) 
| eval y = round(x_1+(x_2/x_3)+x_4+x_5,4)
| sort 0 x
| table x y
| eval y_dash=exact(x), x_dash=exact(y)
| table x_dash y_dash
| sort 0 x_dash
```
OPPAI感がなくなったので、画像省略。(まんぼう　にみえるらしい)
OPPAIへの道は長い・・・
メモ(SQL実行順)

#SQLの実行順
初心者がよく使うものだけ

from → **where** → **group by** → **having** → select → order by

・書いた理由
現在「SQL 第2版 ゼロからはじめるデータベース操作」でSQLを勉強している。
サブクエリのSQLは見ただけでは理解することができずに、紙に書いて構造を学んでいる。
そのときに、どこから実行されているかを把握できずに、何度も実行順のページまで遡ってしまうので記載。

#ACID特性
〇ACID特性とは？
DBMSがトランザクションを実行する際に、守るべき制約のこと
①原子性：トランザクションを実行した際に、そこに属するSQLは実行されるかされないかのどちらかしかない
②一貫性、整合性：事前にテーブルに対して設定した制約を守ること
例 NOT NULL制約、主キー制約
③独立性：トランザクション実行中は他のトランザクションから干渉されない
④永続性、耐久性：トランザクションが完了したもの（コミットやロールバック）はその時点でのデータが保存される

・書いた理由
SQLを学ぶ前はACID特性を何回唱えても覚えられなかった。今は空で書けるが念のため記載。
下請代金支払遅延等防止法ー違法となる行為

応用情報技術者令和元年秋期 午前問79

下請代金支払遅延等防止法において，下請業者から受領したプログラムの返品を禁止しているのは，どの場合か。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591618/7982c4fc-4bc1-118d-d26a-d39d7d3e87fb.png)


下請代金支払遅延等防止法(下請法)は、親事業者による下請け業者に対する優越的地位の乱用行為を取り締まるために制定された法律です。法律には、"下請け代金の支払い確保"のほかにも親事業者の義務や禁止事項などが条文化されており、親事業者の下請事業者に対する取引を公正に行わせることで、下請け業者の利益を保護することを目的としています。

親事業者が下請事業者から納品を受けた際に、下請事業者に責任がないにもかかわらず、給付の受領を拒むことは禁止されています。受領を拒むことができるのは、
  **①契約書面に明記された委託内容と異なる場合**、
  **②納品物に瑕疵等がある場合**、
  **③契約書面に明記された納期までに納品されない**
場合に限られます。

なお、
・**支払い期日**は、受領日から起算して60日以内、かつ、できる限り短い期間内に定めること
・親事業者には委託等をしたら直ちに所定の事項を記載した書面(3条書面)を交付する義務があり、メールでもOK


基本は、下請け業者の責ではないと、受領拒否することは禁止されています。

下請け業者の責とは、
１、要員不足が原因で開発が遅れている
２、ソフトウェアに不具合がある
３、開発途上で発生した仕様変更の内容，対価などを下請業者と合意していたが，受領したプログラムには仕様変更が反映されていなかった
４、一般にソフトウェアの瑕疵担保責任期間は商法第525条に記されている**6カ月～民法637条の1年程度**である以内に、バグ発見した。
５、など。


下請け業者の責ではないの例とは、
１、親事業者と顧客との間の委託内容が変更になる
２、親事業者がソフトウェアの仕様を変更したい
３、など

参考：
https://www.ap-siken.com/kakomon/01_aki/q79.html
https://www.ap-siken.com/kakomon/23_aki/q79.html
Firebase App named '[DEFAULT]' already existsというエラーの解決方法

nuxt.jsでfirebaseと連携したら表題のエラーが出ました。

##①firebase.jsフォルダを開きます
多分こんな感じファイルになってるかと。

```firebase.js
import Vue from "vue"

import { firestorePlugin } from "vuefire"
import firebase from "firebase"
import "firebase/firestore"

Vue.use(firestorePlugin)

  firebase.initializeApp({
    apiKey: "うんたら",
    authDomain: "うんたら.firebaseapp.com",
    databaseURL: "https://うんたら.firebaseio.com",
    projectId: "うんたら",
    storageBucket: "うんたら.appspot.com",
    messagingSenderId: "123456789",
    appId: "1:123456789:web:123456789",
    measurementId: "うんたら",
  })

export const db = firebase.firestore()
export const auth = firebase.auth()
```

##②データを囲む

上記のfirebase.initializeApp({})をif(!firebase.apps.length){}で囲みます。

以下のようになります。


```firebase.js
import Vue from "vue"

import { firestorePlugin } from "vuefire"
import firebase from "firebase"
import "firebase/firestore"

Vue.use(firestorePlugin)

if (!firebase.apps.length) {
  firebase.initializeApp({
    apiKey: "うんたら",
    authDomain: "うんたら.firebaseapp.com",
    databaseURL: "https://うんたら.firebaseio.com",
    projectId: "うんたら",
    storageBucket: "うんたら.appspot.com",
    messagingSenderId: "123456789",
    appId: "1:123456789:web:123456789",
    measurementId: "うんたら",
  })
}

export const db = firebase.firestore()
export const auth = firebase.auth()
```

これでエラーが解決してるはずです。

##その他
↓参考URL↓
Nuxt + Firebase: Firebase App named '[DEFAULT]' already exists (app/duplicate-app)
https://stackoverflow.com/questions/53887447/nuxt-firebase-firebase-app-named-default-already-exists-app-duplicate-ap
github入門（仮）



##githubの環境構築
リポジトリ初期化のメモです

Cloud9コンソールにログインします。

Cloud9でgitのバージョンを確認します。
```
ユーザ名:~/environment $ git --version
git version 2.14.5
```

```
git config --global user.name " "任意のユーザ名"
```
```
git config --global user.email "XXXXXXX@gmail.com"
```

エディターをvimに変更する。

```
git config --global core.editor 'vim -c "set fenc=utf-8"'
```

上記コマンドで.git config に設定が書かれる。
以下確認したら　qエンターで終了します。

```
less ~/.gitconfig
[credential]
        helper = !aws codecommit credential-helper $@
        UseHttpPath = true
[core]
        editor = vim -c \"set fenc=utf-8\"
[user]
        name = ユーザ名
        email = XXXXXXXXX@gmail.com
/home/ec2-user/.gitconfig (END) 
```
練習用ディレクトリを作成
```
mkdir git_repositories
```
練習用ディレクトリに移動します

```
cd git_repositories
```

チュートリアルディクレトリを作成します

```
mkdir tutorial
```
ls エンターでディレクトリ作成済みを確認します
ç
ユーザ名:~/environment/git_repositories $ ls
tutorial
```

ディレクトリ移動します
```
cd tutorial/
```

初期化します

```
git init
Initialized empty Git repository in /home/ec2-user/environment/git_repositories/tutorial/.git/

```
以上で完了。
この場合　tutorialフォルダ直下のフォルダファイルが、gitのバージョン管理の対象になります

gitディレクトリ作成を作成を確認リポジトリ作成済みになります
ls -a
Python + Selenium Chromedirverとserverless-chromeの相性問題

# 環境
AWS SAM + Python 3.7
AWS LambdaのAmazon Linuxコンテナ上で動作。

# 動作を確認できた組み合わせ
```
serverless-chrome 1.0.0.37 + Chromedriver 2.37 + Selenium 3.141.0
```

`chrome_options` ではなく `oputions` にセット。

```python:
from selenium import webdriver
from datetime import datetime

CHROME_DRIVER_PATH = "/opt/python/bin/chromedriver"
HEADLESS_CHROMIUM_PATH = "/opt/python/bin/headless-chromium"

def lambda_handler(event, context):
    options = webdriver.ChromeOptions()
    options.binary_location = HEADLESS_CHROMIUM_PATH
    options.add_argument("--headless")
    options.add_argument("--disable-gpu")
    options.add_argument("--window-size=1280x1696")
    options.add_argument("--disable-application-cache")
    options.add_argument("--disable-infobars")
    options.add_argument("--no-sandbox")
    options.add_argument("--hide-scrollbars")
    options.add_argument("--enable-logging")
    options.add_argument("--log-level=0")
    options.add_argument("--single-process")
    options.add_argument("--ignore-certificate-errors")
    options.add_argument("--homedir=/tmp")

    driver = webdriver.Chrome(
        executable_path = CHROME_DRIVER_PATH,
        options = options
    )

    # 以下ブラウザ操作の処理 #
```

あとAWS SAMはLambdaのメモリーを指定なしにデプロイするとデフォルトで256MBです。
確実に処理がつまってタイムアウトしてしまうので、512MBくらい指定しておきましょう。

## 参考
https://github.com/adieuadieu/serverless-chrome/issues/133
Chromium 版 Edge を使った system test（2020/7/26 時点）

# はじめに

macOS で Chromium 版 Edge を利用するようになったけど、そういえば Rails の system test で使えるのかな？ と思ったのでやってみました。2020/7/26 時点の話です。

# Edge 用 WebDriver の準備

Chromium 版・旧版の両方の WebDriver を [WebDriver - Microsoft Edge Developer](https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/) からダウンロードします。zip ファイルを解凍し、自身の PATH 環境変数が通ったところに配置しましょう。

```bash
$ cd ~/Downloads
$ ls
msedgedriver*
$ cd ~/bin/
$ mv ~/Downloads/msedgedriver .
```

# selenium-webdriver gem alpha版

調べてみたところ [selenium-webdriver gem の CHANGES] (https://github.com/SeleniumHQ/selenium/blob/trunk/rb/CHANGES) に Chromium 版 Edge に対応した旨の記載がありました。

```
4.0.0.alpha3 (2019-07-08)
=========================
（省略）
Edge:
  * Add support for Chromium based implementation
```

ということなので ```Gemfile``` に以下のように記載します。現時点では alpha6 が最新版です。

```ruby:Gemfile
# テスト環境 限定
group :test do
（省略）
  # gem 'selenium-webdriver'
  # NOTE: Edge Chromium 版利用時は 4.0.0 系が必要
  gem 'selenium-webdriver', '~> 4.0.0.alpha6'
end
```
また ```test/application_system_test_case.rb``` にも以下のように記載します。

```ruby:test/application_system_test_case.rb
  # driven_by :selenium, using: :headless_chrome, screen_size: [1150, 950]
  # driven_by :selenium, using: :chrome, screen_size: [1150, 950]
  # driven_by :selenium, using: :firefox, screen_size: [1150, 950]
  # driven_by :selenium, using: :headless_firefox, screen_size: [1150, 950]
  # driven_by :selenium, using: :safari, screen_size: [1150, 950]
  # Chromium 版 Edge 利用時は selenium-webdriver 4.0.0.alpha3 以上が必要
  driven_by :selenium, using: :edge_chrome, screen_size: [1150, 950]
```

これで ```bin/bundle update && bin/rails test:system``` すれば Chromium 版 Edge が起動して system test が走ります。めでたしめでたし :) 

# 宿題

headless モードでは未だ動かせてません。 ```selenium-webdriver``` の対応待ちなのかな…
【Amazon Aurora（MySQL互換）】テーブルの最大行サイズと最大キー長について

Amazon Aurora（MySQL互換）のテーブルの最大行サイズと最大キー長に関するまとめです。
内容的にはほぼMySQLと共通。

## 環境
- Amazon Aurora：2.08.1（MySQL5.7と互換性のあるもの）
    - 「開発/テスト」用
    - DBインスタンスサイズ：db.r5.large
    - ストレージエンジン：InnoDB
   
- クライアントOS：Windows10
- DB接続ツール：A5SQL:Mk2


## 1. テーブルの最大行サイズについて

- 最大行サイズ：65535バイト（InnoDBのページサイズ16Kバイト（デフォルト）の場合）
<br>→ 文字コード：utf8mb4の場合、16383文字が最大
- BLOB型、TEXT型は上記の限りではない（別領域にデータを格納するため）
<br>→ 例えば、一部のカラムをTEXT型で定義して50,000文字格納することも可能

## 2. 最大キー長について

- 最大キー長（インデックスを構成するカラムサイズの合計の最大）はInnoDBのページサイズ
- BLOB型、TEXT型はINDEXに指定できない（以下のようなエラーになる）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356958/753c9a8a-57c3-1e9a-1ad1-7ac450945fde.png)


## 注意事項と対処法
Amazon Aurora（MySQL互換）では、対象DBに割り当てられている「DBのパラメータグループ」の「sql_mode」は「0（設定値なし）」になっています。
このままだと、テーブル定義、インデックス定義する際などに、暗黙的にデータ型が変更されてしまう場合があります。
デフォルトで割り当てられている「default.aurora-mysql5.7」は編集できないので、「DBのパラメータグループ」を新規作成して「sql_mode」を「STRICT_TRANS_TABLES」に変更→対象DBに割り当てます。
その後、対象のDBインスタンスを再起動して適用します。

## 参考

- [第44回　MySQLで扱える文字列型の種類を理解する | gihyo.jp](https://gihyo.jp/dev/serial/01/mysql-road-construction-news/0044)
- [CLOB  【 Character Large Object 】  CLOB型 / キャラクタラージオブジェクト | IT用語辞典 e-Words](http://e-words.jp/w/CLOB.html)
- [5.1.10 Server SQL Modes | MySQL 5.7 Reference Manual](https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html)
- [varcharとtextの違い(mysql innodb) | lxyuma BLOG](http://lxyuma.hatenablog.com/entry/2015/08/15/131309)
- [8.4.7 Limits on Table Column Count and Row Size | MySQL 5.7 Reference Manual](https://dev.mysql.com/doc/refman/5.7/en/column-count-limit.html)
- [14.23 InnoDB Limits | MySQL 5.7 Reference Manual](https://dev.mysql.com/doc/refman/5.7/en/innodb-limits.html)
- [1.8.3.3 Constraints on Invalid Data | MySQL 5.7 Reference Manual](https://dev.mysql.com/doc/refman/5.7/en/constraint-invalid-data.html)
- [13.1.18.6 Silent Column Specification Changes | MySQL 5.7 Reference Manual](https://dev.mysql.com/doc/refman/5.7/en/silent-column-changes.html)
LaravelでAPIを作成

# 背景  
Unityで使用するAPIをPHPで作成した時のまとめ  

# 開発環境  
* PHP v7.3.20  
* Laravel v7.20.0  
* Apache 2.4.43  
  
# 手順  
* コントローラ作成  
  
```  
php artisan make:controller API/APIController  
```  
コントローラにindexメソッドを作成する  

* route設定  
  
```  
api.php  
Route::match(['get', 'post'], '/path', 'API\APIController@index')  
```  

* ローカルサーバを立ち上げる  
  
```  
php artisan serve  
```  
  
* http://127.0.0.1:8000/api/pathにアクセスしてindexメソッドの内容が実行されていれば成功
Rigging the Lottery: Making All Tickets Winners【Abstract】【論文 DeepL 翻訳】

この記事は自分用のメモみたいなものです.
ほぼ [DeepL](https://www.deepl.com/home) 翻訳でお送りします.
間違いがあれば指摘していだだけると嬉しいです.

翻訳元
[Rigging the Lottery: Making All Tickets Winners](https://arxiv.org/abs/1911.11134)

前: ないよ
次: [【1 Introduction】](https://qiita.com/tomato_/items/eb46d3c59fa0a91fe46b)

# Abstract

### 訳文

スパースなニューラルネットワークは密なネットワークに比べてパラメータや計算効率が高く, 場合によっては実時間の推論時間を短縮するために使用できることが示されている. 密なネットワークを訓練して, 推論のためのスパースなネットワークを得ることについては, 多くの研究が行われている. これは, 最大の訓練可能なスパースなモデルのサイズを, 最大の訓練可能な密なモデルのサイズに制限している. 本論文では, 既存の密対スパースの学習法と比較して精度を犠牲にすることなく, 学習中に固定のパラメータ数と固定の計算コストでスパースなニューラルネットワークを学習する方法を紹介する. 我々の手法は, パラメータの大きさと頻度の低い勾配計算を用いて, 訓練中にネットワークのトポロジーを更新する. この手法は, 従来の手法と比較して, 所定のレベルの精度を達成するために必要な浮動小数点演算 (FLOP) が少ないことを示している. 重要なことは, トポロジーを調整することで, "ラッキー" なものだけでなく, どのような初期化からでも始めることができるということである. 我々は, ImageNet-2012データセット上のResNet-50, MobileNet v1 および MobileNet v2, CIFAR-10 データセット上の WideResNets, および WikiText-103 データセット上の RNN を用いて, 最先端のスパーストレーニングの結果を実証している. 最後に, 最適化中にトポロジーを変化させることで, トポロジーが静的なままの場合に発生する局所的な最小値を克服できる理由について, いくつかの洞察を提供する.


### 原文

Sparse neural networks have been shown to be more parameter and compute efficient compared to dense networks and in some cases are used to decrease wall clock inference times. There is a large body of work on training dense networks to yield sparse networks for inference. This limits the size of the largest trainable sparse model to that of the largest trainable dense model. In this paper we introduce a method to train sparse neural networks with a fixed parameter count and a fixed computational cost throughout training, without sacrificing accuracy relative to existing dense-to-sparse training methods. Our method updates the topology of the network during training by using parameter magnitudes and infrequent gradient calculations. We show that this approach requires fewer floating-point operations (FLOPs) to achieve a given level of accuracy compared to prior techniques. Importantly, by adjusting the topology it can start from any initialization - not just "lucky" ones. We demonstrate state-of-the-art sparse training results with ResNet-50, MobileNet v1 and MobileNet v2 on the ImageNet-2012 dataset, WideResNets on the CIFAR-10 dataset and RNNs on the WikiText-103 dataset. Finally, we provide some insights into why allowing the topology to change during the optimization can overcome local minima encountered when the topology remains static.
HerokuにデプロイしたLaravelアプリのURLを正規化する

# はじめに
HerokuにデプロイしたLaravelのURLを正規化しようとしましたが、
.htaccessのリダイレクトが有効にならずにハマったのでMiddlewareでリダイレクトしました。

## やりたいこと
- 「/index.php」を「/」にリダイレクトしたい
- Herokuドメイン「\*\*\*.herokuapp.com」を独自ドメイン「\*\*\*.com」にリダイレクトしたい

## この記事で説明しないこと
- Herokuの独自ドメイン設定
- 独自ドメインSSL化

# 環境
## Laravel
```shell
$ php artisan --version
Laravel Framework 7.19.0
```

# 作業内容
## URL正規化用のMiddleware登録
### GithubからMiddlewareをダウンロード
GithubにLaravelでURL正規化する為のMiddlewareを公開されている方がいたので使用させて頂きました。
- 参考：[Laravel Middleware で URL を正規化する例です。](https://gist.github.com/hata6502/b603129ada69a28b0990cd3b78a199f5)

ダウンロードしたファイルを以下フォルダへコピーします。

```
.
├── app
│   └── Http
│       └── Middleware
│           └── Normalize.php
```


### Normalize.phpを変更

#### handle()
先頭に独自ドメインへのリダイレクトを追加します。
※ドメインの\*\*\*の部分は読み替えてください。

```php:/app/Http/Middleware/Normalize.php
/**
 * Handle an incoming request.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \Closure  $next
 * @return mixed
 */
public function handle($request, Closure $next)
{
    // ここから
    if ($_SERVER['HTTP_HOST'] == '***.herokuapp.com') {
        return redirect()->to('https://***.com' . $request->getRequestUri(), 301, [], $secure = true);
    }
    // ここまで

    $url = $_SERVER['REQUEST_URI']; // PHP 標準のリクエストを使用
    $normalized = $this->normalize($url);
    if ($url != $normalized) {
        header('Location: ' . $normalized, true, 301); // PHP 標準のリダイレクトを使用
        exit();
    }

    ....
```

#### normalize()
今回はパスの末尾をスラッシュで置き換える必要が無かったためスラッシュ追加部分をコメントアウトしました。
また、ローカルではlocalhost:8080ポートで動かしているためhostとportを追加しました。

```php:/app/Http/Middleware/Normalize.php
/**
 * @param $url
 * @return string
 */
private function normalize($url)
{
    // 'host'、'port'を追加
    $elements = ['scheme', 'host', 'port', 'path', 'query', 'fragment'];

    $isHtmlEncoded = $url !== ($decoded = htmlspecialchars_decode($url));
    $url = $decoded;
    $parsed = parse_url($url);
    foreach ($elements as $element) {
        $parsed[$element] = $parsed[$element] ?? '';
    }
    parse_str($parsed['query'], $params);
    preg_match('/(.*)\/(.*)/', $parsed['path'], $matches);
    $dirname = $matches[1] ?? '';
    $dirname .= '/';
    $basename = $matches[2] ?? '';

    /* 今回不要のためコメントアウト
    // パス末尾に / を追加
    if ($basename !== '' && mb_strpos($basename, '.') === false) {
        $dirname .= $basename . '/';
        $basename = '';
    }
    */

    // index.* を削除
    $basename = preg_replace('/^index\.(.*)/', '', $basename);
    // パスの // -> / 置き換え
    $dirname = preg_replace('/\/\/+/', '/', $dirname);
    // クエリ並び替え
    ksort($params);

    $parsed['scheme'] .= empty($parsed['scheme']) ? '' : '://';
    // 'port'を追加
    $parsed['port'] = empty($parsed['port']) ? '' : ':'.$parsed['port'];
    ....
```

### Middlewareを登録

Normalizeをグローバルミドルウェアとして登録します。

```php:/app/Http/Kernel.php
protected $middleware = [
    ....

    \App\Http\Middleware\Normalize::class, // <= 追記
    ];
```

## 確認
あとはHerokuへデプロイしリダイレクトが確認できれば完了です。

# 参考にしたサイト
- [Laravel Middleware で URL を正規化する例です。](https://gist.github.com/hata6502/b603129ada69a28b0990cd3b78a199f5)
Lambdaを使ってTwitter定期投稿botを作ろう

# 1.基本構成
- ツイートデータはAmazon S3に格納
- Lambda→S3へのアクセス権限はIAMで設定
- Cloud Watch Eventsで1時間ごとにLambda Functionを発火
- Lambdaを使ってS3のテキストを検索し、内容をTwitter REST APIへ連携
![kousei.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/585576/dd008e24-ec3b-afb6-f13b-c6ca1ba15b4c.png)


# 2.S3に格納するデータ様式
csv形式でツイートする時間とツイート内容を記載する。
即席なのでテキストファイル使ったけど、ここはNoSQL使ったりしてもよいかも……。
Example)
[ツイート時間],[ツイート内容]

# 3.IAM Roleの設定
下記の通りに,S3アクセスを許可するIAMポリシーを作成し、IAM Roleにアタッチする。

```json

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": "s3:*",
            "Resource": "*"
        }
    ]
}
```
# 4.Lambda Function の作成
Lambda Functionを作成し、トリガー(一時間ごとにテキストファイルを検索)は
Cloud Watchを使用する。
![lambda.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/585576/dbbf85f2-945f-013c-7a63-38a3a436165a.png)

作成するLambda関数のプログラムは下記の通り。
仕組みとしては、「テキストファイルに記載されている時間」と「現在時刻」が合致したら
Twitter REST APIにツイート情報を連携するというもの。

```python

import json
import boto3
import re
import datetime
from requests_oauthlib import OAuth1Session
S3 = boto3.client('s3')

def lambda_handler(event, context):
    # TODO implement
    #バケットファイルからテキスト一覧を取得
    BUCKET = S3.list_objects_v2(Bucket="daily-tweets",Prefix="DAILY_TWEETS")
    for content in BUCKET['Contents']:
    #~~.txtファイルを検索
        if re.match(r'^[^\.]+\.txt',content['Key']):
            obj=S3.get_object(Bucket="daily-tweets",Key=content['Key'])
            l=obj['Body'].read().decode('utf-8').split(",")
            time=datetime.datetime.utcnow() + datetime.timedelta(hours=9)
            print (time.strftime("%H") )
            #時間データと照合して合致したらツイート
            if time.strftime("%H") == l[0]:
                print (l[1])
                CK = '＊＊＊＊' # * enter your Consumer Key *
                CS = '＊＊＊＊' # * enter your Consumer Secret *
                AT = '＊＊＊＊' # * enter your Access Token *
                AS = '＊＊＊＊' # * enter your Accesss Token Secert *
                UPDATE_URL = 'https://api.twitter.com/1.1/statuses/update.json'
                twitter = OAuth1Session(CK, CS, AT, AS)
                req = twitter.post(UPDATE_URL,params={"status":l[1]})
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }

```
これだけでは、「一回だけ」起動するプログラムなので、定期実行のためにCloud Watch Eventsにcronを設定する。
設定値は下記にすると、1時間ごとにツイートされる。(cronを変えれば10分毎・この曜日だけ、とかも可能です。)
cron(0 * * * ? *)

注)
from requests_oauthlib import OAuth1Session →こちらはAWSの標準では使えないのでlayerを作る必要があります。詳しくは
下記記事が参考になります。
https://www.yamamanx.com/aws-lambdapython-twitter-post/

# 5.イカしてないところ
- APIのキーを直接書くな！
  →secret managerとかで何とかできるかも…
- S3である必要なくない？　→簡単さを重視してS3使ったけどNoSQLとか使えるかもね…？
- API Gateway使ってtweet登録できるようにしたほうよいかも…（ただWEBに晒すサービスとなるとセキュリティ面少し心配…)

# 6.おわりに
ものすごくザックリ、作成したツイートボットの解説していきました。なので「こっちの構成の方がいいよ！」とか
あったらどしどしツッコミ入れてください。
macOS アプリの申請して却下されたときの対処

# dark mode の時に文字が見えないよと言われたとき

dark mode のことを考えていないと

```swift
.background(Color.white)
```

などと書いて背景が白くなり、dark mode のときに白文字テキストが読めなくなりました。

なので、以下を使ってなんとか乗り越えました

```swift
.background(Color(NSColor.controlBackgroundColor))
```


# window close したときちゃんとしてと言われたとき

Alternatively, if the application is a single-window app, it might be appropriate to save data and quit the app when the main window is closed.

single-window アプリの場合は、メインウインドウ閉じたらアプリも閉じるようにしてということですので。

こんなのが来た場合は。

```swift:AppDelegate.swift
    func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
        return true
    }
```

これでなんとかなるはず。
gem 'kaminari' でページネーション実装

# 準備
* Gemfileに'kaminari'追加  

```  
gem 'kaminari'
```  

* bundle install  

# 実装例  
* Itemモデルから1回の検索で50レコード取得する

```
Item.all.page(1).per(50)
```  
  
* 配列に対して実装する場合  
  
```  
1ページに対して10レコードずつ表示する  
Kaminari.paginate_array(array).page(1).per(10)  
```