OmniAICreator/Qiita-1.07M huggingface dataset:
【Ruby】is_a? と instance_of? の違い

## Mac で試せる

``` ruby
irb
```

## 前提
``` ruby
module ParentModule; end
module ChildModule; end

class ParentClass
  include ParentModule
end

class ChildClass < ParentClass
  include ChildModule
end

child_instance = ChildClass.new
```

## is_a?メソッド

``` ruby
child_instance.is_a? ChildClass #=> true
child_instance.is_a? ParentClass #=> true
child_instance.is_a? Object #=> true
child_instance.is_a? String #=> false
child_instance.is_a? ParentModule #=> true
child_instance.is_a? ChildModule #=> true
``` 

* is_a?メソッドがTrueを返す場合
レシーバが引数の

  - クラスの直接のインスタンス、もしくは、
  - そのサブクラスのインスタンス、もしくは、
  - モジュールをインクルードしたクラス、もしくは、
  - そのサブクラスのインスタンスであれば、trueを返す
(is_a の意味は、is one of ~ の意味なのかもしれない)

## instance_of? メソッド

``` ruby
child_instance.instance_of? ChildClass #=> true
child_instance.instance_of? ParentClass #=> false
child_instance.instance_of? Object #=> false
child_instance.instance_of? String #=> false
child_instance.instance_of? ParentModule #=> false
child_instance.instance_of? ChildModule #=> false
```

* instance_of?メソッドがTrueを返す場合
  - レシーバが引数で指定されたクラスの直接のインスタンスの場合、trueを返す
node-gyp rebuild 中に gyp ERR! stack Error: 403 status code downloading arm64 iojs.libが起きる



https://github.com/nodejs/node-gyp/issues/1933

にて報告されているが、node-gypのバージョンが5.0.5または、6.0.0のさいに起きるエラーのようである。

対策としては、node-gypのバージョンを5.0.6または6.0.1に上げることである。

## 解決方法

バージョンを上げよう。

```bash
npm install node-gyp@6.0.1
```

## GitHubActions内でこのエラーが起きた

ただ自分の場合、GitHubActions内で仮想環境を作って、このエラーが起こってしまったため、GithubActions内で参照しているnode-gypのバージョンを変える必要が生じていたのだが、前述したコマンドでは参照バージョンを変更することができなかった。

とりあえず、グローバルにnode-gypを落としてみたものの…

```bash
npm install -g node-gyp@6.0.1
```

ダメ…！

```bash
Error output:
gyp WARN install got an error, rolling back install
gyp ERR! configure error 
gyp ERR! stack Error: 403 status code downloading arm64 iojs.lib
gyp ERR! stack     at Request.<anonymous> (C:\hostedtoolcache\windows\node\12.16.1\x64\node_modules\npm\node_modules\node-gyp\lib\install.js:335:22)
gyp ERR! stack     at Request.emit (events.js:323:22)

gyp ERR! stack     at Request.onRequestResponse (C:\hostedtoolcache\windows\node\12.16.1\x64\node_modules\npm\node_modules\request\request.js:1066:10)
gyp ERR! stack     at ClientRequest.emit (events.js:311:20)
gyp ERR! stack     at HTTPParser.parserOnIncomingClient [as onIncoming] (_http_client.js:603:27)
gyp ERR! stack     at HTTPParser.parserOnHeadersComplete (_http_common.js:119:17)
gyp ERR! stack     at TLSSocket.socketOnData (_http_client.js:476:22)
gyp ERR! stack     at TLSSocket.emit (events.js:311:20)
gyp ERR! stack     at addChunk (_stream_readable.js:294:12)
gyp ERR! stack     at readableAddChunk (_stream_readable.js:275:11)
gyp ERR! System Windows_NT 10.0.17763
gyp ERR! command "C:\\hostedtoolcache\\windows\\node\\12.16.1\\x64\\node.exe" "C:\\hostedtoolcache\\windows\\node\\12.16.1\\x64\\node_modules\\npm\\node_modules\\node-gyp\\bin\\node-gyp.js" "rebuild"
gyp ERR! cwd D:\a\project\project\node_modules\sse4_crc32
gyp ERR! node -v v12.16.1
gyp ERR! node-gyp -v v5.0.5
gyp ERR! not ok 
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! sse4_crc32@6.0.1 install: `node-gyp rebuild`
npm ERR! Exit status 1
npm ERR! 
```

エラー文をよく見たらまだ5.0.5を参照しているようだ。

```bash
gyp ERR! node-gyp -v v5.0.5
```


### 結局

参照先を動的に変更しました。

```bash
run: |
  npm install -g node-gyp@6.1.0
  npm prefix -g | % {npm config set node_gyp "$_\node_modules\node-gyp\bin\node-gyp.js"}
```

### 参考記事

https://docs.npmjs.com/cli/prefix.html
Laplacian Filterの実験

<h1>概要</h1>
エッジ検出(実際はエッジというよりただの色の違いなのだけど)しようと思って4方向と8方向のLaplacian Filterどっちが良いのか気になったから実験してみた。


<h2>入力画像</h2>
![gray.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/2b678c00-02d5-185b-3ff9-eb5614a0e74b.png)


<h2>4方向Laplacian Filter</h2>
![img_lap.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/3748afe0-b3dc-dfcb-dfe5-ece09439f834.png)


<h2>8方向Laplacian Filter</h2>
![img_lap copy.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/7a69082e-6639-cb43-596d-2f3ed706d6ee.png)



<h2>結論</h2>
ほとんど同じやないかい！
結果が同じなので、とりあえず回転にも影響が少なさそうな8方向のFilterの方がを使って行きたいと思う

<h2>コード</h2>
8方向4方向お好きな方をどうぞ

```
   def LaplacianLayer(self, img):
        # 4 direction Laplacian
        laplacian_filter = torch.cuda.FloatTensor(
            [[0, 1, 0], [1, -4, 1], [0, 1, 0]]).view(1, 1, 3, 3)
        # 8 direction Laplacian
        # laplacian_filter = torch.cuda.FloatTensor(
        #     [[1, 1, 1], [1, -8, 1], [1, 1, 1]]).view(1, 1, 3, 3)

        gray = self.getGrayImage(img)

        img_lap = torch.nn.functional.conv2d(input=gray,
                                            weight=Variable(laplacian_filter),
                                            stride=1,
                                            padding=0)

        img_lap = torch.abs(img_lap)

        return img_lap

    def getGrayImage(self,rgbImg):
        gray = 0.114*rgbImg[:,0,:,:] + 0.587*rgbImg[:,1,:,:] + 0.299*rgbImg[:,2,:,:]
        gray = torch.unsqueeze(gray,1)
        return gray
```

<h1>参考文献</h1>
【画像処理】ラプラシアンフィルタの原理・特徴・計算式
https://algorithm.joho.info/image-processing/laplacian-filter/
[対処療法] aタグ内にimgタグを配置すると、imgタグのsrcがリンク先となってしまう問題 

# 問題

以下のように、aタグ内にimgタグを書くのはとても一般的かと思いますが、
Android端末でのWebViewでimgタグをタップした場合のみ、imgタグ内のsrcに飛んでしまう問題がありました。

```
        <ul class="categories">
            <li class="category">
                <a href="https://hogefuga.com/category1" target="_blank">
                    <img src="/img/category1.png" alt="" class="category-icon">
                    <p class="category-name">カテゴリー1</p>
                </a>
            </li>
            <li class="category">
                <a href="https://hogefuga.com/category2" target="_blank">
                    <img src="/img/category2.png" alt="" class="category-icon">
                    <p class="category-name">カテゴリー2</p>
                </a>
            </li>
        </ul>
```

![スクリーンショット 2020-11-01 11_opt.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317515/c2c3c837-d76e-3440-5661-f71c0631b253.png)



# 解決策 (2020/11/05修正)

~~imgタグに`pointer-events:none;`を設定~~

とりあえずaタグ以下にimgタグを配置するのを止めて、aタグと同改装に配置し直す。
さらに`pointer-events: none;` を設定することをで解決した。
なぜ上記の様な問題が起こるのかは不明。謎です。

```
        <ul class="categories">
            <li class="category">
                <img src="/img/category1.png" alt="" class="category-icon" style="pointer-events: none;">
                <a href="https://hogefuga.com/category1" target="_blank">
                    <p class="category-name">カテゴリー1</p>
                </a>
            </li>
            <li class="category">
                <img src="/img/category2.png" alt="" class="category-icon" style="pointer-events: none;">
                <a href="https://hogefuga.com/category2" target="_blank">
                    <p class="category-name">カテゴリー2</p>
                </a>
            </li>
        </ul>
```

## 2020/11/05追記
解決策に誤りがありました...実際に行った修正と別の修正を書いてしまっていました。
結局aタグ内に配置した場合は前述の挙動となってしまうため、stylingでの解決になります。
zipとgzipの違い

Adminerをいじっていてこれなんだ？と疑問に思ったので、さくっとメモしておきます。

#zipとは
圧縮ファイルの形式で現在一番ポピュラーなもの

#gzipとは
GNU Zipのこと。
>GNU（グヌー、[ɡnuː] ( 音声ファイル)）とはオペレーティングシステム であり、かつコンピュータソフトウェアの広範囲に渡るコレクションである。 GNUは完全にフリーソフトウェアから構成されている。 GNUは"GNU's Not Unix! "（「GNUはUNIXではない」）の再帰的頭字語である。
wikipediaより
https://ja.wikipedia.org/wiki/GNU#:~:text=GNU%EF%BC%88%E3%82%B0%E3%83%8C%E3%83%BC%E3%80%81%5B%C9%A1n,%E7%9A%84%E9%A0%AD%E5%AD%97%E8%AA%9E%E3%81%A7%E3%81%82%E3%82%8B%E3%80%82


#それぞれの主な役割
##zip
圧縮アーカイバ。

※圧縮アーカイバ = 複数のファイルを一つのファイルにまとめる機能をもつ

##gzip
単なる圧縮機能
【Rails/simple_format】フォームで入力した改行を反映させるヘルパーメソッド

# 状況

* フォームで改行を入力

* 出力時に改行が反映されない

![demo](https://gyazo.com/8629b45baabdb38fc768268d5a525ade/raw)

<br>

# 環境

* macOS Catalina 10.15.6

* ruby 2.6.5

* Rails 6.0.3.4

* MySQL : 5.6.47

* Bootstrap : 4.3.1

<br>

# 学んだコード

* simple_format : ヘルパーメソッド。改行をpタグやbrタグで表現

* hオプション : XSS対策。simple_formatにエスケープ機能を付与

【参照】

* <a href="https://railsdoc.com/page/simple_format">simple_format | Railsドキュメント</a>

* <a href="https://qiita.com/mojihige/items/c01682774e8ef29b361f">simple_formatの使い方 | Qiita</a>

<br>

# 今回のコード

```app/controllers/tasks_controller.rb
def show
  @task = Task.find(params[:id])
  @commits = @task.commits
end
```


```erb:app/views/tasks/show.html.erb
<% @commits.each do |commit| %>
  <%= commit.content %>
<% end %>
```

<br>

この表示の仕方だと、commit.contentの改行が反映されません。

<こんな感じです>
![demo](https://gyazo.com/924063a82ce7b72aadad02f9119c8bc3/raw)

これはsimple_formatを使うことで解決できます。実際にやってみましょう。

<br>

# simple_formatを使う

```erb:app/views/tasks/show.html.erb
<!-- simple_formatを使う -->
<% @commits.each do |commit| %>
  <%= simple_format(commit.content) %>
<% end %>
```

<br>

**simple_formatは、改行をpタグやbrタグで表現してくれるヘルパーメソッド**です。
出力したいテキストをsimple_formatに入れるだけで完了します。

<結果はこんな感じ>
![demo](https://gyazo.com/4876cddd4f1ea1b982c00c2ce63bc223/raw)

さて、とりあえず目標達成です。
しかし、この実装には問題があります。それは<b>「エスケープ」ができていないということ</b>です。

詳しく見ていきましょう。

<br>

# エスケープできるようにする

エスケープは、セキュリティ対策で使われる技術です。簡単に言うと「<b>意味がある文字の意味をなくす</b>」役割があります。

具体的に見ていきます。
例えばこんな入力をしたとします。

![demo](https://gyazo.com/e6d2acf02a7fa7fb58be5c719f87c802/raw)

この値をエスケープしないまま表示すると、こんな感じで「HTMLタグ」として認識されてしまいます。

![demo](https://gyazo.com/abe7628dd5bf895875ff23c1de85b51f/raw)

HTMLでは "<" を「タグが始まりますよ！」という意味で認識します。よってエスケープしない場合はh1要素として表示してしまいます。

このエスケープ機能は、Railsのビューで用いる<%= %>を使うことで付与されます。
しかし、simple_formatを使ってしまうと、この機能が失われます。

よって、simple_formatを使う際は、hオプションを使います。これはsimple_formatにエスケープ機能を付与してくれる優れものです。

```erb:app/views/tasks/show.html.erb

<%# hオプションを使う %>
<% @commits.each do |commit| %>
  <%= simple_format(h(commit.content)) %>
<% end %>
```

<br>

こうすると、表示が下記のように変化します。

![demo](https://gyazo.com/0e648731a0a98db0d4cdf2614335345b/raw)

"<"などから意味が奪われ、ただの記号や文字として表示されています。それに伴い文字も小さくなりました！(pタグで囲まれた)

<br>

# まとめ

* formの改行を反映させたい

* simple_formatで可能！

* セキュリティ対策のため h を使うとベター

<br>

simple_formatは使う機会が多そうですが、セキュリティ対策を怠ると怖いヘルパーメソッドでもあります。使う際は頭に入れて使っていきます。

## 参照

* <a href="https://railsdoc.com/page/simple_format">simple_format | Railsドキュメント</a>

* <a href="https://qiita.com/mojihige/items/c01682774e8ef29b361f">simple_formatの使い方 | Qiita</a>
多段階ソートを書きやすい記載で動作するように実装する

やめ太郎先生のところで、lodash の多段階のソートが紹介されていました。

ワイ「なに！？ライブラリをラップするやと！？」 - Qiita
https://qiita.com/Yametaro/items/111ce26637d6a3c2e763

```js

const userList = [
  {
    name: 'c',
    age: 20,
  },
  {
    name: 'b',
    age: 20,
  },
  {
    name: 'a',
    age: 20,
  },
  {
    name: 'c',
    age: 21,
  },
];

const sortedUserList = _.orderBy(userList, ['name', 'age'], ['asc', 'desc'])
console.log(sortedUserList)

// [[object Object] {
//   age: 20,
//   name: "a"
// }, [object Object] {
//   age: 20,
//   name: "b"
// }, [object Object] {
//   age: 21,
//   name: "c"
// }, [object Object] {
//   age: 20,
//   name: "c"
// }]
```
https://jsbin.com/relafaxohi/edit?html,js,console

パラメータ指定によって項目内部のnameとageで、降順、昇順が指定できるようになっているようです。

sort関数は書いたことがあったのですが、複数条件でのソートを考慮するのを忘れていました。

partsjs/array.test.js at v9.0.0 · standard-software/partsjs
https://github.com/standard-software/partsjs/blob/v9.0.0/source/array/array.test.js#L2385

複数条件でのソートは普通、いろんな場面で使いそうなので実装してみました。

```js
const orderFuncFromName = name => {
  if (name === 'asc') {
    return (a, b) => (
      a > b ? 1
      : a < b ? -1
      : 0
    );
  } else {
    return (a, b) => (
      a > b ? -1
      : a < b ? 1
      : 0
    );
  }
}

const sort = (array, orderFuncs) => {
  const orderFuncArray = [];
  for (const [orderName, func] of orderFuncs) {
    const orderFunc = orderFuncFromName(orderName);
    orderFuncArray.push((a, b) => orderFunc(func(a), func(b)));
  }
  array.sort((a, b) => {
    for (const orderFuncItem of orderFuncArray) {
      const result = orderFuncItem(a, b);
      if (result !== 0) {
        return result;
      }
    }
    return 0;
  });
};

const sortedUserList = [...userList];
sort(sortedUserList, [
  ['asc', v => v.name],
  ['desc', v => v.age],
]);

console.log(sortedUserList)
```
https://jsbin.com/hehudeduga/edit?html,js,console

思った以上にわかりやすく短めに書けました。

これで項目内の文字列の内容や長さや数値でのソートが書きやすくなりそう。
VNRequestのメモリ使用を減らすコツ

CompletionHandlerをつかいます。
これが絶対なのかはわかりませんが、手元のDeepLabV3でCoreMLHelpersを利用した場合、３０枚画像を処理して４００MBメモリ使用量が下がりました。なのでいちおう共有するという感じで。

#Good
CompletionHandlerがあるとき😆

```swift
lazy var model:VNCoreMLModel = try! VNCoreMLModel(for: DeepLabV3(configuration: MLModelConfiguration()).model)
lazy var request:VNCoreMLRequest? = {
    let model = self.model
    let request = VNCoreMLRequest(model: model, completionHandler: completionHandler)
    request.imageCropAndScaleOption = .scaleFill
    return request
}()
```

```swift
let handler = VNImageRequestHandler(cvPixelBuffer: pixelBuffer, options: [:])
do {
    try handler.perform([request!])
   } catch let error {
    print(error)
   }
// 実行したら、後の処理は完了ハンドラに任せる。（結果が返ってくると実行される）
```

```swift
func completionHandler(_ request:VNRequest?,_ error:Error?){
    guard let result = request!.results?.first as? VNCoreMLFeatureValueObservation else { 
 return }
// 結果処理
```
#Bad
ないとき😞

```swift
lazy var model:VNCoreMLModel = try! VNCoreMLModel(for: DeepLabV3(configuration: MLModelConfiguration()).model)
lazy var request:VNCoreMLRequest? = {
    let model = self.model
    let request = VNCoreMLRequest(model: model, completionHandler: nil)
    request.imageCropAndScaleOption = .scaleFill
    return request
}()
```
```swift
let handler = VNImageRequestHandler(cvPixelBuffer: pixelBuffer, options: [:])
do {
    try handler.perform([request!])
   } catch let error {
    print(error)
   }
// ImageRequestHandler実行のすぐ下の行でObservationをとっても結果は得られるが、メモリ使用量が多い。
guard let result = request!.results?.first as? VNCoreMLFeatureValueObservation else { return }
// 結果処理
```

🐣
****
お仕事のご相談こちらまで
rockyshikoku@gmail.com

Core MLを使ったアプリを作っています。
機械学習関連の情報を発信しています。

[Twitter](https://twitter.com/JackdeS11)
[Medium](https://medium.com/@rockyshikoku)
Webサービスが提供される流れ （ブラウザとサーバー、HTTP、静的サイトと動的サイト)

全くの未経験からプログラミングを学び出して、言語の学習ばかりしていて、ふと感じた疑問。
webサービスはどんな流れでユーザーの画面に表示されてるのか？
プログラミングとは、その流れの中のどこに位置するのだろうか？
仕組みの全体像を把握して、プログラムの行き着く先が見えたらプログラミングへの理解がより深まるかと思い、web全体の基礎から学習し直すことにしました。

##■何についての記事？
下記のような疑問に対する回答を、参考書を元にまとめた記事です。
・webサービスはどんな流れで提供されてるの？
・ブラウザとサーバーの役割とは？
・静的サイトと動的サイトってどう違うの？

##■対象読者
・未経験からプログラミング学習をはじめた方
・webサービス提供の全体像を知りたい方

##■この記事のゴール
__webサービスがユーザーに提供されるまでの全体像を知る__
 ①リクエストとレスポンスについて
 ②webサーバーへのアクセス方法(URL)
 ③webブラウザの役割
 ④HTTPとは何か
 ⑤静的ページと動的ページの表示の仕組み

下記より、それぞれ解説していきます。



##webブラウザとwebサーバーの関係##
webサービスを利用する際に必要なのがブラウザとサーバーです。
ブラウザの代表例は Internet Explorer 、google chrome、Safari などがあります。
ブラウザ→サーバーに対して『このファイルを頂戴！』という要求をして、それを受けたサーバーがブラウザに対して要求されたファイルを送り返します。

この流れをリクエストとレスポンスと呼びます。これによって、私達はwebページを閲覧したり、webサービスを利用することができます。

##ブラウザの機能##
ブラウザの主な機能が下記２点です。

__①サーバーに対して指定ファイルのリクエスト__
リクエストの方法は、一般的にも聞き馴染みのあるURLを用いています。

(例)http:/naoya-net:80/index.html

例えば上記の場合だと、『naoya-net』というサーバーの『ポート番号80番』に『index.html』というファイルを要求しています。
これを受けた『naoya-net』というサーバーは、その要求をしてきたブラウザに対して『index.html』のファイルを投げ返します。かなりザックリですが、このリクエストがブラウザが持つ機能の一つです。

ちなみに、ここでの『naoya-net』の部分をドメインと呼び、サーバーを指定する際はドメインもしくはIPアドレスを指定します。
（IPアドレスとは各コンピュータ固有の住所のようなものです）
上記ではドメインを使用していますが、実際のコンピュータ同士のやりとりにはIPアドレスが必要になります。そのために、ドメインをIPアドレスに変換してくれる仕組みをDNSと呼びます。DNSは電話帳のようなもので、IPアドレスとドメイン名を紐付けて管理しています。なので、ドメイン名からIPアドレスを呼び出して変換することが可能なのですね。

ドメインの後の『：80』の部分はポート番号と言い、ポート番号によってサービスの種類を指定できます。webサーバーのポート番号は80番なので、ここでは 80番を指定しています。
住所で考えると、IPアドレスでマンションを指定し、ポート番号で部屋番号を指定するようなイメージです。

__②HTMLファイルの解釈__

サーバーからwebページが送られてきたとして、HTMLのコードがそのままブラウザ上で表示されたら見辛いですよね。それを解消してくれるのもブラウザの役割です。コードに書かれたタグの意味をブラウザが解釈して、ユーザーが見やすいように整形してwebページを表示してくれます。
(例)h1タグであれば見出しとして大きく表示する 等


##HTTP （HyperText Transfer Protocol）とは？##
URLを見ると、httpで始まる場合が殆どだと思います。
このhttpとはザックリいうと、通信時のルールのことを指します。
ブラウザ⇄サーバー間でのコンテンツの送受信の流れにおける、共通のルールや手順のことをHTTPと言い、サーバーへのコンテンツ要求はこのHTTPに基づいて行われます。
ネット回線に繋がる機器同士の共通ルールをプロトコルと言い、HTTPの場合だと、Hypertextの送受信のプロトコルなので、正式名称をHyperText Transfer Protocolと呼びます。
そうしたプロトコルの集まりをTCP/IPと言います。以前はコンピュータに搭載されているOSや機種によって異なるプロトコルが用意されていたので異なる機種間の接続ができませんでした。が、TCP/IPの浸透によりプロトコルが統一された結果、異なるOSや機種間の通信が可能になりました。
(関連用語：ステータスコード、メッセージヘッダー)


##静的サイトと動的サイト
webページは大きく分けて静的サイトと動的サイトの２つに区分されます。誰が・いつログインしても同じ表示のページを静的サイト(ホームページ等)、ログインする人や状況によって内容が変わるページを動的サイトと呼びます。(インスタ・Twitter等)
このwebページの種類によってリクエスト・レスポンスまでのサーバー側の処理内容に若干の違いがあります。

まず静的サイトについては、ブラウザからリクエストが来たら、毎回同じコンテンツをそのまま送信します。わかりやすいですね。
動的サイトの場合、リクエストが来たら、webサーバーがその時の状況に応じて毎回コンテンツを作成しています。具体的には、リクエストを受けたサーバーがサーバーサイドスクリプトと呼ばれるプログラムを実行、リクエストの内容(検索ワードなど)を加味して、データベース等と連動しながら作成されたHTMLをブラウザに返します。この仕組みをCGIと呼びます。これによって、アクセスするユーザーやその時のデータ状況によって異なるコンテンツを送信することができます。

PHPやRubyなどのいわゆるバックエンドの言語は、サーバー側で、動的サイトを作るという役割を担っている事になります。

##まとめ
webサービスは、ブラウザとサーバ間の通信によって提供されている。
コンテンツへのアクセスはブラウザ経由でのURL入力によって可能。その際の通信手順をHTTPと呼び、HTTPのようなプロトコルの集合体をTCP/IPと呼ぶ。
TCP/IPにより、様々な通信の規程が標準化された結果、異なるOSや機種間の通信が可能になった。
webページは静的サイトと動的サイトに区分される。動的サイトの場合、CGIによって毎回異なるページを生成してユーザーに返す。この生成の処理をバックエンドの言語が担っている。

##参考にした本
この一冊で全部わかる「Web技術の基本」　著：小林恭平、坂本陽

##所感
プログラム言語の学習をやってきましたが、 サービスが提供されるに到る全体像についてあまり把握してませんでした。。
今回、通信の仕組みやサーバー周りの事を学習した事で、プログラム言語の学習において、あまり腹落ちしてなかった部分がスッキリしました。
(Cookieやセッションの仕組みなど)
これからプログラミング学習を始める方は、まずwebサービスが提供されるまでの全体像を把握してから、言語学習を始める事をおすすめします！
【Rails/Heroku】push後のエラー解消手順

# 状況

* 開発環境でアプリケーションに追加実装 (コメント機能の実装)

* デプロイ先のHerokuにpush

* Heroku上アプリでコメントを投稿しようとしたところエラー

![demo](https://gyazo.com/fe06ac1a3aa02f51465eb94ee18a0310/raw)

<br>

# 環境

* macOS Catalina 10.15.6

* ruby 2.6.5

* Rails 6.0.3.4

* MySQL : 5.6.47

<br>

# 対処の手順

## 1. ターミナルでログを確認

Heroku上のアプリを操作した際は、ターミナルでコマンドを打つとログを確認できます。

```:terminal
% heroku logs --tail --app アプリ名

# --tailは最後の10行を表示するオプション
```

<br>

実行後、エラー箇所を抜粋したのがこちら。

![demo](https://gyazo.com/6db73fbc980e736c5791c9ab7959016a/raw)

<br>

続いてエラー箇所を深ぼっていきます。  

<br>
  
## 2. エラーを読み解く

先程の画像にエラーの理由が書かれています。

1. Completed 500 Internal Server Error

2. ActiveRecord::StatementInvalid (Mysql2::Error: Table 'heroku_***.comments' doesn't exist):

<br>

1ではエラーがサーバーサイドのエラーであることを示しています。  
この'500'は「HTTPステータスコード」と呼ばれ、HTTP通信でのレスポンスの意味を表現します。
一部を紹介すると…  

- 200 : 正常なレスポンス

- 302 : リダイレクトを実行

- 404 : 存在しないURLへのリクエスト

<br>  

2が今回のエラーを解決するためのヒントです。  

- ActiveRecord::StatementInvalid : Active Recordを使用した際に起きるエラー

- Table '*** .comments' doesn't exist : commentsテーブルが存在しません

<br>

開発環境ではコメント機能は正常に動作し、Heroku上ではコメントを投稿しようとしたときにエラーが出ました。
そしてこのエラー文を見るに、以下のことがエラーの原因として考えられます。  

<br>

<b>Heroku上でコメントテーブルを作成していない</b>。

<br>

では、実際に解消してみましょう。

<br>

## 3. Heroku上のアプリでテーブルを作成

ターミナルで次のコマンドを実行します。

```:terminal
(Control + C でログ画面を抜けた後)

% heroku run rails db:migrate
```

<br>

これで無事にエラーが解消しました！  

<br>

# まとめ

- Heroku上でエラーに対処するため、ターミナルでログを確認した

- エラー文を確認し、原因を特定した

- heroku run rails db:migrateでテーブルを作成した

- エラーを無事に解決できた

<br>

エラーが出ると少なからず焦ります。特に本番環境でのエラーは別格の怖さがあります。

解決できるかと不安になりますが、いつだって大事なのは冷静に状況を整理すること。そして適切な対処を淡々と実行すること。

経験値を増やして、エラー対処職人になれるように積み上げていきます！
高位合成言語アセンブラを作る。 その8

#概要

高位合成言語アセンブラを作る。
練習問題、やってみた。

#フリップフロップを作れ。


```
make 4
in 0 1
nor 3 1 2
nor 0 2 3
out 2 3
```

#コンパイル結果

```
module x(input a, input b, output c, output d);
    assign c = ~(d | b);
    assign d = ~(a | c);
endmodule

module testbench;
    reg a, b;
    x u(.a(a), .b(b), .c(c), .d(d));
    initial
    begin
        $display("a b c d ");
        $monitor("%b %b %b %b ", a, b, c, d);
        a = 0; b = 0; #10;
        a = 0; b = 1; #10;
        a = 1; b = 0; #10;
        a = 1; b = 1; #10;
        $finish;
    end
endmodule





```

#実行結果

```

a b c d
0 0 x x
0 1 0 1
1 0 1 0
1 1 0 0


```

以上。
Gray ScaleをPytorchで書いてみた

<h1>背景</h1>
PytorchでGlay Scaleしようと思ったら、Functionがなく、一度PILに変換し、Gray Scaleしてから、Torch Tensorに再変換していたので、計算コスト無駄だなって思ってた。
てかGray Scaleくらいサポートしてくれよ。。。

もしあったらゴメンナサイ

<h2>コード</h2>

ちなみにGray Scaleは色々と種類があるらしいので、自分の好きなパラメータを使えばいいと思います。


```
    def getGrayImage(self,rgbImg):
        gray = 0.114*rgbImg[:,0,:,:] + 0.587*rgbImg[:,1,:,:] + 0.299*rgbImg[:,2,:,:]
        gray = torch.unsqueeze(gray,1)
        return gray
```


<h2>結論</h2>
PytorchでGrayScaleのFunctionあったら教えてください！

<h1>参考文献</h1>
グレースケール画像のうんちく
https://qiita.com/yoya/items/96c36b069e74398796f3
バージョン情報ソートができないと面接に落ちるので解答しとく

有名なrana_kualuさんが、Zennに投稿していらっしゃる記事から。

アルゴリズムのせいで面接に落ちた
https://zenn.dev/rana_kualu/articles/efd74e8525ccab6c8474

rana_kualuさんは「不労所得で生きたい。」そうですので、Zennでは「￥サポートする」ができるみたいなので、みなさまヨロ。

そこにスタックオーバーフローの回答もリンクされています。

また、Zennで他の方の記事でもコード書いていらっしゃいました。

【Typescript】バージョン比較用関数について
https://zenn.dev/nekoniki/articles/c9c4584bc463e593cb94

私も書いておきます。
こだわってみたのは、バージョン番号にアルファベットが付属しているときにその大文字小文字も比較しているところです。これは紹介した上記の回答でも考慮されてない気がします。

動作確認はこちら。
https://jsbin.com/xofomudano/1/edit?html,js,console

コードはこれ。

```js

const versions = [
  '5.0.0.',
  '1.3.0.9',
  '0.2.0',
  '3.1.2',
  '0.1.6',
  '5.0.0',
  '3.3.3.3',
  '3.3.3.3.3',
  '3.10',
  '0.2.0',
  '0.2.0a',
  '0.2.0aa',
  '0.2.0AA',
  '0.2.0Aa',
  '0.2.0aA',
  '0.2.0c',
  '0.2.0b',
  '0.2.0A',
  '0.2.0C',
  '0.2.0B',
  '0.2.0.a',
  '0.2.0.c',
  '0.2.0.b',
  '0.2.0.A',
  '0.2.0.C',
  '0.2.0.B',
  '5.0.0.',
  '5.0.0.0',
];

const output = [
  '5.0.0.0',
  '5.0.0.',
  '5.0.0.',
  '5.0.0',
  '3.10',
  '3.3.3.3.3',
  '3.3.3.3',
  '3.1.2',
  '1.3.0.9',
  '0.2.0C',
  '0.2.0c',
  '0.2.0B',
  '0.2.0b',
  '0.2.0AA',
  '0.2.0Aa',
  '0.2.0aA',
  '0.2.0aa',
  '0.2.0A',
  '0.2.0a',
  '0.2.0.C',
  '0.2.0.c',
  '0.2.0.B',
  '0.2.0.b',
  '0.2.0.A',
  '0.2.0.a',
  '0.2.0',
  '0.2.0',
  '0.1.6',
];

const sortVersions = (unsortedVersions) => {
  const result = unsortedVersions.map(element=>element.split('.'));
  result.sort(
    (a, b) => {
      const length = Math.min(a.length, b.length);
      for (let i = 0; i < length; i += 1) {
        const valueA = parseInt(a[i], 10);
        const valueB = parseInt(b[i], 10);
        if (valueA < valueB) { return -1; }
        if (valueA > valueB) { return 1; }
        if (a[i].toLowerCase() < b[i].toLowerCase()) { return -1; }
        if (a[i].toLowerCase() > b[i].toLowerCase()) { return 1; }
        if (a[i] < b[i]) { return 1; }
        if (a[i] > b[i]) { return -1; }
      }
      if (a.length < b.length) { return -1; }
      if (a.length > b.length) { return 1; }
    return 0;
    }
  );
  return result.map(element=>element.join('.')).reverse();
};
const sortedVersions = sortVersions(versions);
console.log(versions, sortedVersions, sortedVersions.join() === output.join());
```
SSIMをPytorchで書いてみた

<h1>概要</h1>
Stereo MatchingでDisparityの精度を確かめる為にSSIMが良く用いられているのだが、gitで見つけたコードがSSIMの値が0~1に収まっていなかったから、自分で書いてみることにした。

<h2>SSMIの計算</h2>
paddingするとSSIMの結果が悪くなりそうだったので端っこをclippingした
入力のxとyは比較対象で方はTorch Tensor。

```
    def SSIM(self, x, y,window_size=3):
        C1 = 0.01 ** 2
        C2 = 0.03 ** 2
        clip_size = (window_size -1)/2

        mu_x = nn.functional.avg_pool2d(x, window_size, 1, padding=0)
        mu_y = nn.functional.avg_pool2d(y, window_size, 1, padding=0)

        x = x[:,:,clip_size:-clip_size,clip_size:-clip_size]
        y = y[:,:,clip_size:-clip_size,clip_size:-clip_size]

        sigma_x = nn.functional.avg_pool2d((x  - mu_x)**2, window_size, 1, padding=0)
        sigma_y = nn.functional.avg_pool2d((y - mu_y)** 2, window_size, 1, padding=0)
        
        sigma_xy = (
            nn.functional.avg_pool2d((x- mu_x) * (y-mu_y), window_size, 1, padding=0)
        )

        mu_x = mu_x[:,:,clip_size:-clip_size,clip_size:-clip_size]
        mu_y = mu_y[:,:,clip_size:-clip_size,clip_size:-clip_size]

        SSIM_n = (2 * mu_x * mu_y + C1) * (2 * sigma_xy + C2)
        SSIM_d = (mu_x ** 2 + mu_y ** 2 + C1) * (sigma_x + sigma_y + C2)

        SSIM = SSIM_n / SSIM_d

        loss = torch.clamp((1 - SSIM) , 0, 2)
        save_image(loss, 'SSIM_GRAY.png')

        return  torch.mean(loss)

```


<h2>Stereo Matchingの精度を計算する場合</h2>
入力の左画像
![gray_left.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/00ce76ad-0a4c-ad84-6fa2-cf75a2524f2c.png)


右の画像を推定したDisparityを使ってワープさせた画像</h2>
僕の目には全く同じように見えるけど、SSIMはどうなるのか
![gray_estLeft.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/d392b6cd-2cb2-1e5d-35cc-edd308f913fd.png)


SSIMのloss
textureが無い領域が白っぽくなってる。きっとdisparityの推定精度が低かったのだろう。
![SSIM_GRAY.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/998bd09b-84cc-f8d6-6540-4e8d1d2c391a.png)


*白い所がlossが高い。黒い所がlossが0


<h2>入力を同じ画像にした場合</h2>

もちろんlossは0！
![SSIM_GRAY.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/0b004e29-662f-1d79-3cc2-e3567ec2ee9e.png)



<h2>左の画像と右の画像を入力した場合</h2>

物体がある場所はきちんとlossがが出てますね。
車のフロントガラスは一部黒くなってるので左右の画像で同じ輝度だという事が分かる。
![SSIM_GRAY.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/50e29941-2f25-a534-89ec-f69b04552297.png)


<h2>window sizeを5にした場合</h2>

![SSIM_GRAY.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/c7e651a9-fc2f-d066-b13c-28e06b6554f9.png)

<h2>window sizeを7にした場合</h2>

![SSIM_GRAY.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/89757a47-0abf-e835-1da1-964804b513d9.png)

<h2>window sizeを9にした場合</h2>
![SSIM_GRAY.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/cc4c5689-3880-2290-1080-8715d831e1cf.png)


<h1>結論</h1>
きっと合ってると思うんですけど、間違ってたら指摘してください！

<h1>参考文献</h1>
https://github.com/mrharicot/monodepth/blob/b76bee4bd12610b482163871b7ff93e931cb5331/monodepth_model.py#L98
Structural similarity
https://en.wikipedia.org/wiki/Structural_similarity
カラムの型早見表

# 早見表

| 型 | 概要 |
|:-:|:-:|
| primary_key  | プライマリキー  |
| string  | 文字列（1〜255文字）  |
| text  | 長い文字列（1〜4294967296文字）  |
| integer  | 整数（4バイト）  |
| smallint  | 値の範囲が-32768～32767の整数を扱うデータ型  |
| bigint  | 整数（8バイト）  |
| float  | 浮動小数  |
| decimal  | 精度の高い少数  |
| numeric  | 数値  |
| datetime  | 日時  |
| timestamp  | 更新時間  |
| binary  | バイナリーデータ  |
| boolean  | 真偽値  |
| char  | 固定長文字列のこと。0~255まで  |
| vachar  | 可変長文字列のこと。0~65535まで  |
実は、Rubyは改行と空白を区別しています

「Ruby は改行と空白を区別していない」という話をちらちら見かけます[^space]。
そんなわけないのでして。

[^space]: ここでいう「空白」はいわゆる「半角スペース」（U+0020）のこと。

改行と空白が区別されないなら

```rb
x = 1 puts x
```

で `1` が表示されるはずですが，SyntaxError になります。そりゃそうだ。
また，

```rb
puts
1
```

で `1` が表示されるはずですが，改行しか出力されません。そりゃそうだ。

Ruby はむしろ改行と空白を区別する言語です。だからこそ文末のセミコロンが省略できるのですね。

# なぜ広まった？

Ruby on Rails チュートリアル 第4版の「4.3.4 CSS、再び」
https://railstutorial.jp/chapters/rails_flavored_ruby?version=5.0#sec-css_revisited
には，

> 実は、Rubyは改行と空白を区別していません

というくだりがあります[^latest]。ここが発信源かっ？！

[^latest]: 最新版でどうなっているかは（有料なので）知らない。

Ruby on Rails チュートリアルは本当に優れたチュートリアルだと思います。和訳の品質もけっこう高くて，作者と訳者の方々には感謝しています。
それだけに，どうしてこんな初歩的な誤りが書かれているのかと，残念に思います。
windowsでiverilog その79

# 概要　

windowsでiverilogやってみた。
フリップフロップ書いてみた。

# サンプルコード

```
module ff(input a, input b, output c, output d);
	assign c = ~(a | d);
	assign d = ~(b | c);
endmodule

module testbench;
	reg a,
		b;
	wire c,
		d;
	ff u(.a(a), .b(b), .c(c), .d(d));
	initial
	begin
		$display("a b c d ");
		$monitor("%b %b %b %b", a, b, c, d);
		a = 0; b = 0; #10;
		a = 1; b = 0; #10;
		a = 0; b = 0; #10;
		a = 0; b = 1; #10;
		a = 0; b = 0; #10;
		$finish;
	end
endmodule





```

# 実行結果

```

a b c d
0 0 x x
1 0 0 1
0 0 0 1
0 1 1 0
0 0 1 0


```

以上。
Winstonでログを出力する

## インストール
```
npm i winston
npm i -D @types/winston
```

## 設定ファイル
```ts:logger.ts
import * as winston from "winston";

export class Logger {
  // クラス変数(this.~)・インスタンス変数の型宣言
  private logger: winston.Logger;
  private stage: string;

  // Loggerインスタンス作成時に設定する項目(インスタンス変数)
  constructor(stage: string) {
    this.stage = stage;
  }

  public async initialize(): Promise<winston.Logger> {
    this.logger = winston.createLogger({
      level: "info",
      format: winston.format.combine(
        winston.format.timestamp({
          format: "YYYY-MM-DD HH:mm:ss"
        }),
        winston.format.errors({ stack: true }),
        winston.format.splat(),
        winston.format.json()
      ),
      // デフォルトで毎回必ず出力する項目を設定(出力時変更不可)
      defaultMeta: {
        service: "winston-lambda"/*
        *他にも
        *constuructorで設定した値(this.label = 'sample label')を
        *ここで
        *label: this.label
        *として設定してもよい
        *(つまりインスタンス作成時に値を設定してそれを毎回出力する)
        */
      },
      transports: new winston.transports.Console()
    });

    // 検証環境の場合、loggingをdebugレベルまで上げる
    if (this.stage !== "prd") {
      // clear()をする事によって、createLoggerの際に指定したtransportsの設定を消せる
      this.logger.clear();
      this.logger.add(
        new winston.transports.Console({
          level: "debug"
        })
      );
    }
    return this.logger;
  }
}

```

## 使用する
```ts:sample.ts
import Logger from './logging/logger';

// 元になるインスタンスを作成して初期化
const originalLogger = new Logger('dev').initialize();

// childメソッドを使ってインスタンスを分けることで、エラー出力時など、たまに切り替える項目の値を切り替える
// これで通常はlogger.logやlogger.infoなどと、console.log()と同じように簡易にログが出力できる
const logger = originalLogger.child({ notice: 0 });
const loggerWithNotice = originalLogger.child({ notice: 1 });

// 通常の出力方法
logger.log({
  level: "info",
  message: "SILLY message",
  additional_label: "additional_content" // オブジェクトに値を追加することで出力内容を随時追加できる
});

// logメソッドではなく、直接レベル名を繋ぐことで、level・messageラベルを省略できる
logger.info('Loading Redirect Function');
loggerWithNotice.error('error message')

// logger.error, warning, info, debug の4段階で出力が可能

```

## 参考
TypeScriptでロギングするためにwinstonを導入してみる
https://qiita.com/18kondo/items/3d5738a1c2eacd83d4f4

winston
https://openbase.io/js/winston
自己証明書のHTTPSにChromeでアクセスした時に出るERR_CERT_INVALIDへの対処

# Chromeが出す信頼できない証明書を持つサイトブロックの回避方
開発中VS CodeのLive Serverなどを使って、HTTPSローカルサーバーを立てる際に、自己証明書を使うことがあると思いますが、いつからかChromeでは警告を無視してページを開くオプションがなくなってしまいました。```ERR_CERT_INVALID```というエラーを出して強引にページ時を開くことができません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/537237/8ddf3dd4-d91b-0fbf-ea2f-3edc5589cdae.png)

# 解決策
この[Mediumの記事](https://medium.com/@dblazeski/chrome-bypass-net-err-cert-invalid-for-development-daefae43eb12)で見つけましたが、次の文字列をキーボードからタイプすると、強引に開けます。
* thisisunsafe
* badidea

## 余談
opensslを使って自己証明書と秘密鍵を作成するコマンド。

```bash
openssl req -x509 -sha256 -nodes -days 9999 -newkey rsa:2048 -keyout localhttps_key.pem -out localhttps_cert.pem
```
Amazon S3 バッチオペレーションを使って日付毎に区切られたGlacierをディレクトリごと復元する

# 背景
S3に`bucket/log/20201101`のようにdailyでログデータを保存しており、一定期間がたったログについてはS3からGlacierに移していましたが、Glacierのログデータが数ヶ月分必要になり、それを復元する必要がありました。

# 検討したこと
- [S3 Glacierアーカイブをフォルダごと復元 \- Qiita](https://qiita.com/kobake@github/items/32bfbe59da2143c5f572) 
  - インストールが割と大変で今回はこのツールは使いませんでした。

- [まとめてGlacierからS3に戻すためのワンライナー \- Qiita](https://qiita.com/fanglang/items/91770ea74dfc03beb554) 
  - データ量が少なければワンライナーでも良いと思うのですが、今回の数ヶ月分のデータの場合１日復元するのに1時間かかっていました。（非同期のオプション等があれば違うかもしれないです。）


# 対応
S3の大量のオブジェクトに対して復元という一つの操作をするということで、S3 batch operationsを使うことにしました。

S3 batch operationsは大きく以下のようなステップで実行さます。
- manifestファイルの作成
- manifestファイルのアップロード
- ジョブの作成
- ジョブの実行

## manifest ファイルの作成
- manifestファイルは`bucket, object_key` の形式で記載します。ここではバケットと復元したいログデータオブジェクトのkeyを記載したCSVを作成します。
- 作成したファイルをS3にアップロードしてください。

```ruby
target_date_range  = Date.parse(config['START_DATE'])..Date.parse(config['END_DATE'])
target_date_range.each do |date|
  # 復元対象のログデータが保存されているディレクトリのオブジェクト一覧を取得します
  s3_objects = s3_list_object_content(config['BUCKET'], "#{config['S3_KEY']}/#{date.strftime('%Y%m%d')}")
  # 取得したオブジェクト一覧をCSV形式でmanifestファイルにします
  s3_objects.each do |object|
    CSV.open(file_name, 'a') { |f| f << [config['BUCKET'], object.key] }
  end
end
```

## ジョブの作成
- `confirmation_required: false` を指定することでジョブの作成と同時に実行を行います。`true` にするとジョブが作成され、実行は別途行う必要があります。
- reportに指定bucketにジョブの結果が出力されます。復元に失敗したものなどがあればここに表示されます。

```ruby

job_id = Aws::S3Control::Client.new.create_job(
  account_id: config['AWS_ACCOUNT_ID'],
  confirmation_required: false,
  operation: {
    s3_initiate_restore_object: {
      expiration_in_days: 10,
      glacier_job_tier: config['GLACIER_JOB_TIER'],
    },
  },
  report: {
    bucket: "arn:aws:s3:::#{config['MANIFEST_BUCKET']}", 
    format: 'Report_CSV_20180820',
    enabled: true,
    prefix: 'report',
    report_scope: 'AllTasks',
  },
  client_request_token: SecureRandom.uuid,
  manifest: {
    spec: {
      format: 'S3BatchOperations_CSV_20180820',
      fields: ['Bucket', 'Key'],
    },
    location: {
      object_arn: "#{manifest_bucket_arn}/#{manifes_file_name}",
      etag: etag,
    },
  },
  description: 'restore',
  priority: 10,
  role_arn: config['ROLE_ARN'],
  tags: config['TAGS'],
)

puts job_id
```

## その他
- S3 batch operationsはジョブ単位で課金されるので、ジョブの分割には注意しましょう。
- 最終的に作成したスクリプトは https://github.com/akiraisomura/s3_utils に置いてあります。
ちゃんとその日の天気を把握しよう

# まずは動かしてみた
今回は1回だけ動かしてみましたが、毎日、6時半に動かすように設定してみようと思います。
製作時間は2時間くらいでした。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">決まった時間に天気を通知してくれる。結構簡単に作れた。<a href="https://twitter.com/hashtag/protoout?src=hash&amp;ref_src=twsrc%5Etfw">#protoout</a> <a href="https://t.co/OyQxrVV4iR">pic.twitter.com/OyQxrVV4iR</a></p>&mdash; heihei (@heihei15408697) <a href="https://twitter.com/heihei15408697/status/1322692171833638912?ref_src=twsrc%5Etfw">November 1, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# これでビニール傘が増えなくてすむかも
朝、天気予報を見ずに家を出てしまい、雨が降られて、急遽コンビニで傘を買うことが多い。
<strong><font color="MediumBlue">自宅にはいったい何本傘があるんだという状況に陥っている。</font></strong>
朝、家を出るとき時間をスマホを必ず見ているので、LINEに通知しておけば、スマホのロック画面で見るかなと思い、作ってみました。

# 何を使ったのか？
■Integromat
https://www.integromat.com/
〇Weather
　Get daily weather forecast
〇LINE
　Send a Notification

### 全体概要
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/726018/a4e306ef-c8f8-aa71-ff50-37f6dd8bd7e9.png)

### Weather側設定
いつの天気？
どこの天気？
を選択して設定しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/726018/ffe15637-7328-b922-ed48-f99a8a9d9fed.png)

### LINE側設定
LINE Notifyとの接続を作成します。
LINEに送信するメッセージについて、
　formatDate関数で日付だけに加工
　switch関数で天気に応じて合致した日本語を返却
するようにしています。
メッセージと合わせて天気に合わせたアイコンも送るようにしました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/726018/11bff103-051e-107e-467a-d6837017f592.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/726018/940141ea-6dd6-4fa3-87e3-20793108b76b.png)

### 時間設定
赤枠部分をONにしたうえで、時計マークをクリックします。
![test.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/726018/3966e77b-f441-22f7-54e4-1ada45ae14a1.png)

毎日、朝の6時30分に連絡するようにしてます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/726018/0a6038ea-5ac9-7269-b246-bccb46af6196.png)

# 最後に
天気予報を取得したりとか、LINEに通知したりとか、ハードル高いイメージがあったが、こんなに簡単にLINE通知をする仕組みがつくれるのかという驚きがいまだに勝っています。
【Rails/一意性制約】モデルのバリデーションをコンソールで確認する方法/複数カラムへの一意性制約

# 状況

* userとroomを紐付けるpermissionsテーブル(部屋に入れる許可証を管理)を作成したい

* references型でuser, taskをカラムにもつ

* 既にテーブルに存在する(user_id, task_id)のセットが入力された際、保存しない制約

* このバリデーションが正常に動作するかをコンソールで確認したい

<br>

「一意性制約」を使えば実現できるこちらのバリデーション。

今回はこれがちゃんと実装できているか、rails cで立ち上げたコンソールでの操作についての記録です。

<br>

# 環境

* macOS Catalina 10.15.6

* ruby 2.6.5

* Rails 6.0.3.4

*  MySQL : 5.6.47

<br>

# 今回のコード

```app/models/permission.rb

class Permission < ApplicationRecord
  belongs_to :user
  belongs_to :task

  validates :user_id, uniqueness: { scope: :task_id }
end
```

<br>

ちなみに、こちらはアプリ上での制約であり、正確にはDB側でも制約をかける必要があります (<a href-"https://railsguides.jp/active_record_validations.html#uniqueness:title">Railsガイド</a>より)。
しかしまだ理解できていないので今回は省略します。

<br><br>

# コンソールで入力したコマンド

一意性制約を確認したかったので、以下の流れでコードを実行していきました。

* Permission.find(数字)で既存のレコードを取得

* 適当な変数に代入する

* valid?メソッドで保存可能か確認

* "false"になると予想

<br>

ターミナルでコンソールを立ち上げて確認しました。

```:teminal
$ rails c

[1] > permission = Permission.find(1)
=> #<Permission:*** id: 1, user_id: 1, task_id: 1, ***>

[2] > new.valid?
=> true
```

<br>

trueになってしまいました…。
原因を考え、コマンドを変えてみました。

<br>

# 原因とコマンドの変更

【原因】
▶"find"は既存のレコードを探すActiveRecordメソッド
▶これを保存すると上書き保存みたいになる？

【変更】
▶user_id, task_idを直打ちする

<br>

```:terminal
$ rails c

[1] > Permission.find(1)
=> #<Permission:*** id: 1, user_id: 1, task_id: 1, ***>

[2] > permission = Permission.new(user_id: 1, task_id: 1)
=> #<Permission:*** id: nil, user_id: 1, task_id: 1, ***>

[3] > permission.valid?
=> false

[4] > permission.errors.full_messages
=> "User has already been taken"
```
<br>

これでしっかりfalseになることを確認できました。

<br>

# まとめ

* 複数キーの一意性制約はscopeオプションで指定できる

* 確認のためには、新たにレコードを生成すること

<br>

少しハマってしまいましたがなんとか乗り越えました。
本当に理解するためには、saveやvalidの裏側で何が動いているかを知る必要がありそうですね。

<br>

まだまだ勉強することがいっぱいありますが、１つずつおさえていきます。

<br>

### 参照記事

* <a href="https://railsguides.jp/active_record_validations.html#uniqueness:title">Railsガイド/バリデーション</a>

* Qiita : <a href="https://qiita.com/j-sunaga/items/d7f0e944baad6e56206c">uniqueness: scope を使ったユニーク制約方法の解説</a>

* 外部ブログ : <a href="https://310nae.com/rails-uniqueness">【Rails】複数のカラムを使ったユニーク制約の方法【uniqueness: scope】</a>

<br>
pyenvをmacにインストール

#pyenvのインストール（Mac）

pyenvはpythonの複数のバージョンを使い分けるツールです。pyenvを使ってpythonをインストールしておくと後々便利だと思います。

pyenvはPythonの複数のバージョンを使い分けるツールです。pythonを使う場合はまずはpyenvをインストールしておくと後々便利です。

##1.Homebrewのインストール
下記のコマンドをコピーしてターミナルに貼り付けEnter

```
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
```


##2.Homebrewでpyenvをインストール
ターミナルで下記のコマンドを実行

```
brew install pyenv
```


```
Error: No developer tools installed.
Install the Command Line Tools:
  xcode-select --install
```
↑のようなエラーが出たら、xcodeがインストールされていないので、指示に従って
ターミナルで下記のコマンドを実行して、もう一度brew install pyenv を実行してみる

```
xcode-select --install
```


##3.パスを通す（OSがCatalina以降）
ターミナルで下記のコマンドを１行ずつコピーして実行

```
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zshrc
echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zshrc
echo 'eval "$(pyenv init -)"' >> ~/.zshrc
```

zshrcに書き込んだ内容を適用する

```
source ~/.zshrc
```

##3.パスを通す（OSがCatalinaより前）
Catalinaより古いOSでは下記のようにします
ターミナルで下記のコマンドを１行ずつコピーして実行

```
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile
echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile
echo 'eval "$(pyenv init -)"' >> ~/.bash_profile

```
bash_profileに書き込んだ内容を適用する

```
source ~/.bash_profile
```

##4.python3.7.3をインストールしてみる
デフォルトで入っていたバージョンと同じものをインストール

```
pyenv install 3.7.3
```

##4.バーションを切り替える
なぜか、ホームディレクトリにpython-versionがある場合がある。これがあると、切り替えができないので、下記のコマンドで削除する

```
rm ~/.python-version
```
バージョンの切り替え

```
pyenv global 3.7.3
```


#pyenvのコマンド
インストールできるバージョンのリスト

```
pyenv install --list
```

インストールされているバージョンと現在使用中のバージョン（現在使用中は※印がついている）

```
pyenv versions
```
OpenJtalk で日本語の発話 (テキストファイルの読み上げ）

こちらのプログラムを改造して、テキストファイルを読み上げるようにしました。
[OpenJtalk で日本語の発話](https://qiita.com/ekzemplaro/items/8b6169de6ea8510edecd)

プログラム

```py:kusamakura01.py
#! /usr/bin/python
#
#	kusamakura01.py
#
#						Nov/01/2020
#
# --------------------------------------------------------------------
import subprocess
import sys
# --------------------------------------------------------------------
def jtalk_proc(tt):
	open_jtalk=['open_jtalk']
	mech=['-x','/var/lib/mecab/dic/open-jtalk/naist-jdic']
	htsvoice=['-m','/usr/share/hts-voice/mei/mei_normal.htsvoice']
	speed=['-r','1.0']
	outwav=['-ow','open_jtalk.wav']
	cmd=open_jtalk+mech+htsvoice+speed+outwav
	subprocess.run(cmd,input=tt.encode())
	sys.stderr.write("*** wav is created ***\n")
	args = ['aplay','-q','open_jtalk.wav']
	print(args)
	subprocess.run(args)
#
# --------------------------------------------------------------------
sys.stderr.write("*** 開始 ***\n")
file_in = sys.argv[1]
#
fp_in = open(file_in,encoding='utf-8')
lines = fp_in.readlines()
fp_in.close()
#
count = 0
line_out = ""
for line in lines:
	print(count,line)
	if 5 < count:
		break
	line_out += line[:-1]
	line_out += "  " 
	line_out += "  " 
	line_out += "  " 
	count += 1
#
print(line_out)
jtalk_proc(line_out)
#
sys.stderr.write("*** 終了 ***\n")
# --------------------------------------------------------------------
```

入力データ

```text:in01.txt
草枕
夏目漱石

やまみちを登りながら、こう考えた。
ちに働けばかどが立つ。じょうにさおさせば流される。意地をとおせばきゅうくつだ。とかくに人の世は住みにくい。
住みにくさがこうじると、安い所へ引き越したくなる。どこへ越しても住みにくいとさとった時、詩が生れて、えが出来る。
```

実行方法

```bash
./kusamakura01.py in01.txt
```

bash で同じことを行う場合

```bash
#
perl -pe 's/\n/  /g' < in01.txt > tmp01.txt
#
open_jtalk \
        -x /var/lib/mecab/dic/open-jtalk/naist-jdic \
        -m /usr/share/hts-voice/mei/mei_normal.htsvoice \
        -r 1.0 \
        -ow ./out01.wav \
        tmp01.txt
#
aplay out01.wav
#
```

wav ファイルを作成しない方法

```bash
perl -pe 's/\n/  /g' < in01.txt  \
 | open_jtalk \
	-x /var/lib/mecab/dic/open-jtalk/naist-jdic \
	-m /usr/share/hts-voice/mei/mei_normal.htsvoice \
	-r 1.0 \
	-ow /dev/stdout | aplay --quiet
```
DockerhubのイメージをGithub Container Registryに移行する

DockerhubからGithub Container Registry にイメージを移行する際の自分用メモです。

### 背景
[https://github.blog/2020-09-01-introducing-github-container-registry/](https://github.blog/2020-09-01-introducing-github-container-registry/)
9/1 に公開された GitHub Container Registry(以下、ghcr) を使用してみる。
現在(2020/09/03)ではパブリックベータ版なので、変更になる可能性がある。

[Docker Hubに保存したコンテナイメージ、無料プランでは6カ月間使われないと削除へ － Publickey](https://www.publickey1.jp/blog/20/docker_hub6.html)
また、Dockerhubの無料プランでは使用されていないコンテナが削除されてしまうように仕様が変更された。

つまり、
「Docker Hub の需要が増えて制約が多くなったので、無料プランなら Github Container Registry を使っていこう。」

### 前提条件

- Githubに登録していること
    - パーソナルアクセストークンを作成していること
        - packagesにread,write,delete権限があること

ghcrには以下のコマンドでログインする

```console
docker login ghcr.io -u $OWNER #Githubのアカウント名
Password: <パスワードはパーソナルアクセストークンを入力> 
Login Succeeded
```

以下のコマンドで、Docker Hub から移行する

```bash
docker pull $OWNER/$IMAGE_NAME:$VERSION
docker tag $OWNER/$IMAGE_NAME:$VERSION ghcr.io/$OWNER/$IMAGE_NAME:$VERSION
docker push ghcr.io/$OWNER/IMAGE_NAME:$VERSION
```

ghcrにpushしたcontaner image をPublicに設定して`docker pull`できることを確認する

```bash
docker pull ghcr.io/$OWNER/$IMAGE_NAME:$VERSION
```

### Reference
[GitHub Container Registry 入門](https://www.kaizenprogrammer.com/entry/2020/09/03/060236)<br>
[GitHub Container Registryのパブリックベータをリリース - GitHubブログ](https://github.blog/jp/2020-09-07-introducing-github-container-registry/)
プログラミング用語集　【更新版】

#はじめに

###前提

この記事は、現役でweb開発企業で働いている、私自身がエンジニアと会話をする上で分からなかったこと、理解できなかった用語をまとめる為の記事です👨‍💻
記事の内容は、更新されていきます😄

対象読者
・初学者向けにブログを書いている方
・エンジニア初学者を育成している方
・エンジニア初学者


##ネスト【nest】

ネスト　= 入れ子

for文の中にfor文を入れるなど、構造の中に別の構造を入れること。
ネストが深くなりすぎると、コードを見た時に醜いかったり、エラーの原因になることも😭


##スコープ【scope】

スコープ ＝ 影響範囲

```index.js
function number (){
  let number = 1
}
```
上記のコードですと関数の中でnumberを宣言しているので、この場合の変数numberのスコープは、number関数の中でしか使うことができません。

```index.js
let number
function number (){
 number = 1
}
```
このように、関数の外で記述することで、関数外でも、number変数を使うことができます。
レスポンシブデザイン対応（addClass, removeClass）

```
// リロード時
$(function() {
  // ウィンドウサイズ768px以下の場合、クラスを削除
  if (window.matchMedia( '(max-width: 768px)' ).matches) {
  $(function(){
    $('.tabs__content').removeClass('order-last');
  });
  //768px以上の場合なにもしない
    } else {
  };
});
```
```
// リサイズ時
$(window).resize(function(){
  let x = $(window).width();
  let y = 768;
  if (x <= y) {
    $('.tabs__content').removeClass('order-last');
  }
  else {
    $('.tabs').addClass('order-last');
  }
});
```
windowsでiverilog その78

#概要　

windowsでiverilogやってみた。
7セグメントデコーダーのテストベンチ、書いてみた。

#参考にしたページ

https://qiita.com/17ec084/items/f267d12097da62dadc83

#サンプルコード

```


module testbench;
	reg [3:0] data;
	wire [6:0] code;
	decoder7seg u(.data(data), .code(code));
	initial
	begin
		$display("data code");
		$monitor("%h  %b", data, code);
		data = 4'd0; #10;
		data = 4'd1; #10;
		data = 4'd2; #10;
		data = 4'd3; #10;
		data = 4'd4; #10;
		data = 4'd5; #10;
		data = 4'd6; #10;
		data = 4'd7; #10;
		data = 4'd8; #10;
		data = 4'd9; #10;
		data = 4'd10; #10;
		data = 4'd11; #10;
		data = 4'd12; #10;
		data = 4'd13; #10;
		data = 4'd14; #10;
		data = 4'd15; #10;
		$finish;
	end
endmodule





```

#実行結果

```



data code
0  1111110
1  0110000
2  1101101
3  1111001
4  0110011
5  1011011
6  1011111
7  1110010
8  1111111
9  1111011
a  1110111
b  0011111
c  1001110
d  0111101
e  1001111
f  1000111


```

以上。
【javascript】一行で書かないrange関数

ワンライナー以外の記述をしたかった。

###コード

```javascript:
const range = (from, to, step) => {
	if (Number.isFinite(from) === false) from = 0;
	if (Number.isFinite(to) === false) to = 0;
	if (Number.isFinite(step) === false || step < 1) step = 1;
	
	if (from === to) return [to];
	
	const result = new Array();
	if (from < to) {
		for (; from <= to; from += step) result.push(from);
	} else {
		for (; from >= to; from -= step) result.push(from);
	}
	return result;
};

console.log( range() );				//[0]
console.log( range(5, 5) );			//[5]

console.log( range(-5) );			//[-5, -4, -3, -2, -1, 0]
console.log( range(5) );			//[5, 4, 3, 2, 1, 0]

console.log( range(-5, 5) );		//[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5]
console.log( range(5, -5) );		//[5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5]

console.log( range(-5, 5, 2) );		//[-5, -3, -1, 1, 3, 5]
console.log( range(5, -5, 2) );		//[5, 3, 1, -1, -3, -5]

```

###コード（修正）
引数が空の時と、1個の時の結果が不満だったので。

```javascript:
const range = function (from, to, step) {
	const length = arguments.length;
	if (length===0) return new Array();
	
	if (Number.isFinite(from) === false) from = 0;
	if (length===1 && from > 0) to = from, from = 0;
	
	if (Number.isFinite(to) === false) to = 0;
	if (from === to) return Array.of(to);
	
	if (Number.isFinite(step) === false || step < 1) step = 1;
	
	const result = new Array();
	if (from < to) {
		for (; from <= to; from += step) result.push(from);
	} else {
		for (; from >= to; from -= step) result.push(from);
	}
	return result;
};

console.log( range() );             //（新）[]（旧）[0] 

console.log( range(-5) );           //[-5, -4, -3, -2, -1, 0]
console.log( range(5) );            //（新）[0, 1, 2, 3, 4, 5]（旧）[5, 4, 3, 2, 1, 0] 
```
##変更点
- アロー関数は`arguments`が使えないので`function`に変更
- 引数が空の時、空の配列を返す
- 引数が1個且つ0より大きい時、`from->0`ではなく`0->from`で返す
【Windows】HomesteadにphpMyAdminの最新版をインストール

# この記事の目的
Homesteadをapt-getでインストールしたところ、phpMyAdminでエラーが発生しました。
バージョンを変えてのインストールが必要になったので、この方法を覚書として掲載します。

参考記事：[http://coskx.webcrow.jp/mrr/memo/phpmyadmin.html](http://coskx.webcrow.jp/mrr/memo/phpmyadmin.html)




# インストール方法
公式からwgetでファイルをダウンロードし、配置する方法です。


## ダウンロードと展開
phpMyAdmin は /usr/share/ に置くのが標準とされているので，それに従います。

下記のダウンロードページへアクセスしてください。
[https://www.phpmyadmin.net/downloads/](https://www.phpmyadmin.net/downloads/)

「Current version」の「all-languages.zip」のURLをwgetコマンドで指定してください。

※例では「ver.5.0.4」がダウンロードされます。

```
cd /usr/share/
sudo wget https://files.phpmyadmin.net/phpMyAdmin/5.0.4/phpMyAdmin-5.0.4-all-languages.zip
sudo unzip phpMyAdmin-5.0.4-all-languages.zip
sudo mv phpMyAdmin-5.0.4-all-languages phpmyadmin
sudo chmod -R 0755 phpmyadmin
```

## hostsの変更
以下の設定を「C:\Windows\System32\drivers\etc\hosts」へ追記します。

※編集はメモ帳などを「管理者として実行」で行ってください。

```
192.168.10.10           homestead.phpmyadmin
```
ホスト名、IPは環境に合わせて変更してください。

## Homestead.yamlの変更
以下の設定をHomesteadフォルダ内のHomestead.yamlに追記します。

```
sites:
    - map: homestead.phpmyadmin
      to: /usr/share/phpmyadmin/
```

Homestead.yamlの変更を反映するため、以下のvagrantコマンドを実行します。

```
 vagrant reload --provision
```

`http://homestead.phpmyadmin`へアクセスすると、phpMyAdminのログインページが表示されます。
AWS Lamp環境構築

# やること
AWS上にLamp環境構築

## EC2(Linux)環境構築
1.AWSコンソールからEC2を選択し、インスタンスを起動を選択
2.Amazon Linux 2 AMI (HVM), SSD Volume Typeを選択し、残りの設定はお好みで設定する
3.ssh通信をするためのキーペアを作成し、ダウンロードしておく
4.作成したEC2のセキュリティタブからセキュリティグループを選択し、**インバウンド通信にsshを追加することで、外部からのssh通信を許可**する
5.ターミナル上でダウンロードしたキーペアのあるディレクトリに移動し、ssh接続を行う

```
ssh -i {ダウンロードした証明書} ec2-user@{作成したEC2のパブリック IPv4 DNS}
```

※パブリック IPv4 DNSはインスタンス概要から確認できる

## Apache環境構築

1.EC2の**インバウンド通信にhttp**を追加し、外部からのhttp接続を許可する
2.以下のコマンドでapacheをインストールし起動する

```
sudo yum -y install httpd
sudo service httpd start
```
3.インスタンス概要欄にあるパブリック IPv4 アドレスのオープンアドレスを開く（許可しているのはhttpなので、httpsからhttpに変更する）

## MySQL環境構築

1. AWSコンソールからRDSを選択し、データベースの作成を選択し、MySQLにチェックを入れ作成を行う(マスターユーザ名とパスワードはメモしておく)
2. 作成されたデータベースのセキュリティグループを選択し、**インバウンド通信にMySQLを許可**し、外部からの接続を許可する
3. ssh通信したEC2サーバに、MySQLをインストールし、データベースへの接続を行う

```
sudo yum -y install mysql

mysql -h {作成したDBのエンドポイント} -P 3306 -u {マスターユーザ名} -p
```

なお、現在の状態では、データベースは**プライベート接続のみ許可**されている状態となっているため、EC2のサーバを踏み台として利用することのみで接続できる

また、EC2はデフォルトでアウトバウンドが**全てのポート許可**となっているため、MySQLに接続できる

## PHP環境構築

1.PHPのインストールおよび設定読み込み（再起動）

```
sudo amazon-linux-extras install php7.2
sudo service httpd restart
```
2.ドキュメントルートに移動する

```
cd /var/www/html/
```

3.PHPファイルを作成する

```
sudo vi index.php
```

4.内容を記述する

```
<?php
echo "Hello World!";
```

※Vimの使い方は詳しく触れませんが、Iキーを押すことで入力モード、ESXキーを押すことでノーマルモードに戻り、ノーマルモードで:wqと入力すれば保存することができます。

5.再度パブリック IPv4 アドレスのオープンアドレスを開く

※この時、キャッシュが残っている場合に最初に開いたApacheの初期画面が表示されることがあるので、キャッシュクリアもしくは別のブラウザの使用、時間を置いてアクセスなどしてください


## 感想
初めは少しセキュリティグループの設定漏れなどで困ったが、簡易に環境構築ができると感じた。

普段はAzureユーザなので、Paas(WebApps等)でアプリケーションサーバを構築することが多いが、EC2の場合は実際にはIaasなので、少し設定が面倒だと感じたので、他に方法が無いか探る（Elastic Beanstalkがそれに該当？）
WindowsのServiceでパスワードを持たないユーザーのログオンを許可する

# はじめに

備忘録です。運用の都合上パスワードをかけていないWindowsマシンがあり、権限の関係で特定ユーザーでサービスのログオン設定をしたい場合がありました。しかしデフォルト状態では以下の事情からそのままでは実行できなかったため、その設定を変更する手順をまとめました。

> 現代のWindowsではすべて、空のパスワードを持つユーザーがローカルコンソールのみにログオンするように制限するローカルセキュリティポリシーがあります。
http://ja.voidcc.com/question/p-hjwahxks-g.html

# 手順

下記手順に従ってローカルグループポリシーエディタを開く

[グループポリシーgpedit.mscが見つからない時の対処 – Windows10 Home](https://itojisan.xyz/trouble/17155/)


`[ローカルコンピューターポリシー] -> [コンピューターの構成] -> [Windowsの設定] -> [セキュリティの設定] -> [ローカルポリシー] -> [セキュリティオプション] -> [アカウント: ローカルアカウントの空のパスワードの仕様をコンソールログオンのみに制限する]`を無効にすれば完了

# 最後に

よかったらTwitterフォローしてください～
https://twitter.com/nkjzm
高位合成言語アセンブラを作る。 その7

# 概要

高位合成言語アセンブラを作る。
ソースから、回路図、描いてみた。

# 写真

![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/d5c2feac-1aed-7446-3c86-d19f2bf37a34.jpeg)


# 成果物

https://embed.plnkr.co/plunk/Rbr1Dt2RaJwUP51n

以上。