OmniAICreator/Qiita-1.07M huggingface dataset:
Ubuntu18.04のDockerイメージを起動する

# 目的
[Ubuntu 18.04 LTS にdockerをインストールする](https://qiita.com/seigot/items/fe9825735be4f062052a)の続き〜Ubuntu18.04のDockerイメージを起動するまでの備忘録です

# 準備

Dockerfile、docker-compose.yml、起動時に実行するスクリプト(start.sh)を準備する

```dockerfile:Dockerfile
FROM ubuntu:18.04

# コンテナ起動時に実行する
ADD  start.sh  /
RUN  chmod +x /start.sh
CMD  ["/start.sh"]
```

```docker:docker-compose.yml
version: '2.0'

services:
  myproject:
     image: mycontainer:latest
     container_name: mycontainer
```

```sh:start.sh
#!/bin/bash
echo "test" > test.txt

#コンテナを起動し続ける
tail -f /dev/null
```

# コンテナ起動

以下を実行してコンテナ起動すればOK

```
# build
docker build -t mycontainer .
# run
docker-compose up -d
# exec
docker exec -it mycontainer /bin/bash
```

# docker composeのインストール

[Install Docker Compose](https://docs.docker.com/compose/install/)を参照

```
# sudo curl -L "https://github.com/docker/compose/releases/download/1.26.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
# chmod +x /usr/local/bin/docker-compose
# docker-compose -v
docker-compose version 1.26.2, build eefe0d31
```

# docker-compose up 後に、コンテナが(container name) exited with code 0 となる場合

```
$ docker-compose up
Creating ubuntu-container ... done
Attaching to ubuntu-container
ubuntu-container exited with code 0
```

正常終了しているので、コンテナ起動後に以下を実行できるようにする。

```
#コンテナを起動し続ける
tail -f /dev/null
```

# 参考
[Ubuntu 18.04 の Docker イメージの作成（Ubuntu 上）](https://www.kkaneko.jp/tools/ubuntu/dockerimage.html)
[【Linux入門】DockerでUbuntu18.04を構築する方法](https://www.sejuku.net/blog/82240)
[Install Docker Compose](https://docs.docker.com/compose/install/)
[docker run -it の「-it」とはなにか](https://qiita.com/k_uchida_____/items/8ca31226bd6d10850791)
[docker-compose upするとコンテナが一瞬でexited with code 1する話](https://qiita.com/nrk_baby/items/d872e8f051a96a313601)
[docker コンテナ起動時のシェル実行について](http://blog.queth.net/docker-cotainer-start-shell-exec.html)
[dockerコンテナ起動時にシェルを実行する](https://qiita.com/ken992/items/872a90736e6af26ef4ab)
IAMで副作用なくリージョン縛りをする方法

## やりたいこと
IAMでリージョン縛りをする（特定のリージョンから来たリクエスト以外は弾く）ポリシーを書く方法を確認する。
素でやるとCloudFrontやIAM自身のようなグローバルサービスも「東京以外」扱いで弾かれてしまうので、それを回避する必要がある。

## NGパターン
- 以下のようなポリシーを書きたくなるが、これは失敗する（正確には、リージョン制限は利くのだがIAM、CloudFront、Route53といったグローバルサービスも共倒れになる）。グローバルサービスのエンドポイントが北バージニア（us-east-1）に存在することが原因。

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "DenyAllActionsNotFromTokyo",
            "Effect": "Deny",
            "Action": "*",
            "Resource": "*",
            "Condition": {
                "StringNotEquals": {
                    "aws:RequestedRegion": [
                        "ap-norhteast-1"
                    ]
                }
            }
        },
        {
            "Sid": "AllowAllActios",
            "Effect": "Allow",
            "Action": "*",
            "Resource": "*"
        }
    ]
}

```

## OKパターン

- 以下のように改修すればOK。
  - ここではS3、CloudFront、IAM、Route53、サポートの5つのサービスを"東京縛り"の除外対象としている。
  - `NotAction`がポイント。「以下のアクションはコンディション句を経た結果としての明示的なDenyから除外する」という意味となり、これによって後続の明示的なAllowで許可される余地が生まれる（明示的なDenyはそれ以外の全てに優先するので、これをしてしまうと、どう頑張ってもAllowはできなくなる点に注意）。

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "DenyAllActionsNotFromTokyo",
            "Effect": "Deny",
            "NotAction": [
                "s3:*",
                "cloudfront:*",
                "iam:*",
                "route53:*",
                "support:*"
            ],
            "Resource": "*",
            "Condition": {
                "StringNotEquals": {
                    "aws:RequestedRegion": [
                        "ap-northeast-1"
                    ]
                }
            }
        },
        {
            "Sid": "AllowAllActios",
            "Effect": "Allow",
            "Action": "*",
            "Resource": "*"
        }
    ]
}
```

## 裏技パターン
- グローバルサービスのエンドポイントが北バージニア（us-east-1）にあることを逆手に取ると、最初のポリシーでも動くようになる。
  - グローバルサービス触るときは北バージニア用のIAMユーザーないしIAMロールでやる、というルール決めができるなら、多分これでも運用に乗る。

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "DenyAllActionsNotFromTokyo",
            "Effect": "Deny",
            "Action": "*",
            "Resource": "*",
            "Condition": {
                "StringNotEquals": {
                    "aws:RequestedRegion": [
                        "us-east-1"
                    ]
                }
            }
        },
        {
            "Sid": "AllowAllActios",
            "Effect": "Allow",
            "Action": "*",
            "Resource": "*"
        }
    ]
}
```

## おまけ

S3はグローバルサービスだと思っていたが、バケットごとにエンドポイントが分かれる（言われてみれば・・・）ので、最初のポリシーで試すと以下のような状態になる（北米のバケットが「エラー」として表示される。バケットの中身も勿論閲覧不可）。
![1-s3-ng-from-tokyo.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/609876/4ae1e269-e9b2-f3e6-cbd5-8c274820e3bd.png)
Nuxt.js: middlewareを使って特定のページ以外からのアクセスをリダイレクトする

# 成り行き

Nuxtを使用しているアプリを作成中、ログイン後の二段階認証ページなどログインした後にアクセスしてほしくないページにアドレス直打ちで入れることに気づきました。

Nuxtには`middleware`というページレンダリングを行う前に設定されたメソッドを実行してくれるAPIがあります。今回はmiddlewareを用いて、特定のページ以外からのアクセスを行なった場合リダイレクトするようにしました。

# コード

```js:auth.js
export default function({ from, redirect }) {
  if (!from || from.path !== '/login') { // 利用される場合、/loginには任意のパスを入れてください
    redirect('/');
  }
}
```

あとはこれをページのmiddlewareプロパティに設定するだけです。

## 解説

`from`は遷移元のrouteデータが入っています。
今回の場合ログイン後に表示される二段階認証ページへのアクセスを制限したかったので、fromに入っている`path`が`/login`以外だった場合リダイレクトが実行されるようにしました。
またアドレス直打ちの場合、fromは`undefined`になっていたのでその場合も含めました。（個人的にはこちらがメイン）

[Nuxt - API: コンテキスト](https://ja.nuxtjs.org/api/context/#-code-from-code-a-href-https-router-vuejs-org-ja-api-e3-83-ab-e3-83-bc-e3-83-88-e3-82-aa-e3-83-96-e3-82-b8-e3-82-a7-e3-82-af-e3-83-88-em-vue-router-route-em-a-)
【AWS】 CircleCI/CD 自動デプロイでハマったエラーの解消【Capistrano 】

Railsで作成したポートフォリオをAWS EC2にデプロイし、最終段階でCicleCIによるCD(自動デプロイ)を導入していて、大きくハマった点があった為、備忘録かつ誰かの一助になればと思い、記します(理解が誤っている場合がありますので、修正があれば都度修正します)。

自動デプロイの記事について、先人の記事を見ながら実装を進めていたのですが、ssh keysのインストールはできており、最終段階の「Capistrano deploy」で以下のようなエラーがおき、長らくハマっていました。

<img width="1173" alt="スクリーンショット 2020-07-04 18.48.16.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620533/69cbf052-ba93-2b6e-7cd5-7e3124fffd46.png">


##Net::SSH::AuthenticationFailed: Authentication failed for user エラー

文面からSSH key関連のエラーであることはわかります。しかし、前タスクでInstalling additional ssh keysはSuccessしているしなぜ？と思っていました。ググっているとここでハマる方が多いようでした。

結論としては、

* CircleCIに登録したKeyが間違っていた
* その結果、Fingerprintとしてconfig.ymlに記載していた値が違う為、デプロイできなかった

```ruby:config.yml
   - add_ssh_keys:
          fingerprints:
            - "XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX" # こちらの値
```

ということです。

最初にCircleCIに登録していた鍵は、AWS EC2を構築しているときにダウンロードした、「hoge.pem」でした。

先人の記事を参考に進めていて、書いてあるとおり何も疑わずにEC2からダウンロードしていたhoge.pemをcatしてコピーし、CircleCIに登録していました。

最終的に、自分のケースでは「pem形式の鍵をCircleCIに登録する」という点はあっていたのですが、catする鍵が違っていたようです。

####CircleCIに登録すべき鍵は、ssh-keygenして作成した「~rsa」(公開鍵ではない)で、ローカルからEC2にログインする際に使用する秘密鍵でした。

EC2にSSH接続する際、初期の方で、EC2にログイン→.sshに移動→authorized_keys(中身はssh-keygenして作成した~rsa.pub)に対応する秘密鍵を、 ローカルの.sshに置いて~rsaでログインしていると思うのですが、CircleCIに登録すべきSSH keyはそちらでした。

しかし、ssh-keygenして生成した~rsaは、OPENSSH形式であり、そのままではCircleCIに登録できません。実際に登録しようとすると怒られて登録できませんでした。
※CircleCIはOPENSSH形式の鍵に現時点では対応していないとメンターさんから伺いました。

登録できない？じゃあ結局どの鍵を登録すればいいんじゃ！とそこでもハマっていたのですが、
結果的にどうするのかというと、
#####rsa鍵（OPENSSH形式）をpem形式(catするとBEGIN RSA PRIVATE KEY---で始まる)の鍵に変換する」というシンプルな解決方法でした。

こちらの記事を参考に、
[SSH KeyをOpenSSH形式化からPEM形式に変換](https://scrapbox.io/hibi/SSH_Key%E3%82%92OpenSSH%E5%BD%A2%E5%BC%8F%E5%8C%96%E3%81%8B%E3%82%89PEM%E5%BD%A2%E5%BC%8F%E3%81%AB%E5%A4%89%E6%8F%9B)

```ruby:local
ssh-keygen -p -m PEM -f hoge_key_rsa

```
こちらのコマンドで、rsaをpem形式に変換できると思います。
OPENSSH形式ではなくなっていますが、今までのように

```ruby:local
$ ssh hoge_key_rsa
Last login: ------- 2020 from ec2-xx-xx-xx-xx.compute-1.amazonaws.com

       __|  __|_  )
       _|  (     /   Amazon Linux 2 AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-2/
```
EC2にSSH接続は可能です。

pem形式に変換されたhoge_key_rsaをcatすると、

```ruby:hoge_key_rsa

-----BEGIN RSA PRIVATE KEY-----
省略
==
-----END RSA PRIVATE KEY-----
```
と出てくると思います。こうなっていればOKで、ハイフンを含めてBEGINからENDまで全てをコピーし、CircleCIに追加します。

ちなみにOPENSSH形式のままの鍵(rsa)を開くと、

```ruby:local
-----BEGIN OPENSSH PRIVATE KEY-----
...
```

と出てきますが、このままではCIrcleCIに登録できないとういう訳です。

先ほどのcatしてコピーしたコードを、CircleCIに登録します。
そして生成されたFingerprintを、localのCircleCIの設定ファイルであるconfig.ymlに記載することで、エラーが解消し、無事デプロイが完了しました。

随時加筆・修正していきたいと思います！
GitHubにファイル上げるために必要なコマンド

# Gitとは
簡単に言うと、バージョンを管理するアプリです。
なにかのソフトのバージョンを1.0から1.1にアップデートしたときに、なんか重たいなとか思ったときにすぐに1.0に戻すことができるものというふうに理解していればいいかなと思います。

バージョンを管理するものなんだと、現状で理解していればいいかと。

# 必要なコマンド

はじめは、Githubにプッシュするまでに必要なコマンドについて話します。

- 必要なコマンド
    - git add
    - git commit
    - git push

基本的にこの３つのコマンドがあれば、GitHubにファイルをプッシュすることができます。

##　実際に具体的な使い方について

###　git add 
git add は名前の通り追加すること

##　git commit

セーブみたいなものとおぼえていたらいいでしょう。
よく例に挙げられるのはRPGゲームのセーブという例を上げる人が多いかと感じます。
なので今回もRPGのゲームのようなものという認識で捉えれてもられば良いでしょう。

##　git push 

このコマンドを打って初めて、GitHubの保存先に自分が作ったファイルが保存されます。

簡単な説明でしたが実際にコマンドを打つのが一番理解できるので、やって見ましょう。

##　手順

前提条件

- ファイル名
   - sample.html
- gitバージョン
    - git version 2.21.1 (Apple Git-122.3)
- OS
    - iOS

では早速やって行きましょう

まずはじめに、addして追加

```
git add sample.html
```

次にコミットします。

```
git commit -m "first commit"
//これは一番はじめにコミットするときのおまじないのようなもの

git commit -m 変更内容
// 二回目以降は変更内容を記入するのが一般的
// " "はなくてもしっかりコミットできるので、自分は省略する。
```

```
git push origin master
// これでGitHubにファイルが送られる
```

以上のような流れで、GitHubにファイルを保存することができます。

私も駆け出しエンジニアですが、これからエンジニアになる方は
GitHub、Gitを使えるようになっておいたほうがいいかと思います！

最後までありがとうございました。
【javascript】計算されたプロパティ名

書籍のアウトプット

#計算されたプロパティ名

現在使用している状態マネージャを別のライブラリに対応させる必要があるとする。

このライブラリは状態に格納する必要があるいくつかの値を渡す。
問題はこのライブラリが渡すキーとペアが状態マネージャのメソッドに渡せるオブジェクトではなく、配列形式であるということ

そこで状態マネージャをうまくライブラリに渡すために仲介関数を作成する。

```javascript
function setValue(name, value) {
  const changes = {}
  changes[name] = value
  stateManager.update(changes);
}

const [name, value] = otherLibrary.operate()
setValue(name, value)
```

ポイントはsetValue関数でプロパティを定義する前にからのオブジェクトを作成しなくていけないこと。
これはプロパティ名は動的に設定されるため。

{name:value}というものを定義していたとすれば、プロパティ名はname変数に含まれる値ではなく、"name"という値になっていた。
つまり`changes.name=value`とおなじこと

"changes[name]=value"とすることでnameの値を使用する事ができる。
（Laravel）変更はマッピングに追加するだけのSingleton登録サービスプロバイダの実装

## 希望：複数クラスで依存されるクラスのSingleton化を楽に管理したい
複数のクラスで依存されるSingletonにしても問題がいないクラスだけを、ServiceProviderで同じインスタンスが取得されるよう実装しようと思いました。
数が多かったのでマッピングを編集すればSingletonに登録するクラスが追加できるように実装してみました。


```app/Providers/SingletonServiceClassRegisterProvider.php
<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class SingletonServiceClassRegisterProvider extends ServiceProvider
{
    protected function singletonTargetServiceClassNamesMap():array
    {
        return [
            \App\Service\PlanService::class,
        ];
    }

    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        $this->registerAllClassInstanceInClassNamesMap($this->singletonTargetServiceClassNamesMap());
    }

    protected function registerAllClassInstanceInClassNamesMap(array $classNamesMap):void
    {
        foreach($classNamesMap as $key=>$className){
            $instance = $this->app->make($className);
            $this->app->instance(
                is_numeric($key) ? $className : $key,
                $instance
            );
        }
    }

}

```

これで、マッピングにSignletonで登録したいクラスを追加、外したいクラスを削除することで管理できるサービスプロバイダになりました。
以上です。
Vue.jsで超簡易的な映画検索アプリを作ってみた

# はじめに

この記事は『[2020年のフロントエンドマスターになりたければこの9プロジェクトを作れ](https://qiita.com/rana_kualu/items/915345b8f3f870cfe2aa) 』で紹介されていた  

最初の
「Build a movie search app using React (with hooks)」 = Reactを使って映画検索アプリを作成する
というものをVue.js（Vue CLI）で簡易的に作ってみたものです。

# 完成したもの

![search-movie.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/462329/e8c43ac9-ac55-0772-4dac-dc5d011b25e2.gif)

この8ビット風のcssは[NES.css](https://nostalgic-css.github.io/NES.css/)を利用させていただきました！

![スクリーンショット 2020-07-09 22.28.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/462329/4b6dbfeb-2d7b-3c90-cb33-dcf00c9b1873.png)


# APIについて

[OMDb API](https://www.omdbapi.com/)という映画検索APIを用いました。
 
```
https://www.omdbapi.com/?apikey=[yourkey]&s=hero
```

s=[検索したい文字列]で下記のようなjsonが返ってきます。

![スクリーンショット 2020-07-09 22.22.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/462329/b75c42d9-bd52-f99b-ea96-b0bb62cfce4b.png)

※映画のポスター画像も取得できるのが便利です！


# コード

## Vue.js

[vue-magic-grid](https://github.com/e-oj/vue-magic-grid)と呼ばれる簡単にタイル状に並べてくれるライブラリを用います。  


```Movie.js
import MagicGrid from 'vue-magic-grid'
import Vue from 'vue'

let baseUrl = 'https://www.omdbapi.com/?apikey=[yourkey]'
export default {
  name: 'movie',
  data () {
    return {
      searchStr: '',
      results: []
    }
  },
  methods: {
    // クリック時発火
    onClick: function() {
      // 何も入力されていない場合はAPI叩かない
      if (this.searchStr === '') {
          return
      }
      // 検索用のURL作成
      baseUrl = baseUrl + '&s=' + this.searchStr
      // axiosで非同期通信
      this.axios.get(baseUrl)
      .then(response => {
          this.results = response.data.Search
          Vue.use(MagicGrid)
      })
    }
  }
}
```


## HTML&CSS

`v-model`を用いてテキストボックスの値（searchStr）を双方向データバインディングします。
ボタンでAPIを叩いて結果を表示してます。

```HTML
<div class="movie">
  <!-- 検索ボックス -->
  <div class="nes-field search-box">
      <input type="text" id="name_field" class="nes-input search-box__input" v-model="searchStr" placeholder="enter movie title" />
      <button type="button" class="nes-btn search-box__btn" @click="onClick">Search</button>
  </div>

  <magic-grid class="posts-list">
    <!-- 単体 -->
    <div class="posts-item nes-container with-title is-centered" v-for="(post, index) in results" :key="index">
      <p class="title">{{post.Title}}</p>
      <p>{{post.Year}}</p>
      <img :src="post.Poster" :alt="post.Title">
    </div>
  </magic-grid>
</div>
```

```scss
.search-box {
  display: flex;
  &__input {
    width: 80%;
  }
  &__btn {
    width: 20%;
  }
}
.posts-list {
  margin-top: 2.5rem;
}
.posts-item {
  img {
    width: 100%;
  }
}
```

# 終わり

こんな感じで映画のポスター付きで表示することができます！
[コードはこちら](https://github.com/p-t-a-p-1/vue-tools/blob/master/src/views/Movie.vue)

![screencapture-localhost-8080-movie-2020-07-09-23_05_52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/462329/2559a30f-b92d-4444-ac62-4783d539f773.png)
デバッグを表示する

何度も忘れるのでメモ。

デバッグを使う事でより開発がスムーズになる。
現在表示されているページのcontroller,view,actionなどが確認できる。
注意点として本番環境ではデバッグ情報は表示するべきではありません。

そのため、次のように記述することで開発環境のみデバッグ情報を表示されるよう対策しています。


まずはgem 'byebug'をbundle installする。
その際development、test環境で使用するのでgroup :development, :test do~end内に書き込む。

```
group :development, :test do
  gem 'sqlite3'
  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
end
```

```
$ bundle install
```

下記コードをapp/views/layouts/application.html.erbに書き込む。

```
<%= debug(params) if Rails.env.development? %>
```

```
<html>
  <head>
    <title><%= full_title(yield(:title)) %></title>
    <%= csrf_meta_tags %>
    <%= stylesheet_link_tag    'application', media: 'all',
                               'data-turbolinks-track': 'reload' %>
    <%= javascript_include_tag 'application',
                               'data-turbolinks-track': 'reload' %>
    <%= render 'layouts/shim' %>
  </head>
  <body>
    <%= render 'layouts/header' %>
    <div class="container">
      <%= yield %>
      <%= debug(params) if Rails.env.development? %>
    </div>
  </body>
</html>
```

これで表示、使用可能になります。
コマンドラインでUSBデバイスを再接続する

USBで接続しているデバイスが調子悪くなったときに、デバイスマネージャーを開いてデバイスを再インストールしたりするアレをコマンドラインでやる手順です。

**※ Windows 10 バージョン2004以降でのみ使用可能**

## 目次

1\. [デバイスのインスタンスIDを探す](#1-%E3%83%87%E3%83%90%E3%82%A4%E3%82%B9%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%82%BF%E3%83%B3%E3%82%B9id%E3%82%92%E6%8E%A2%E3%81%99)
2-1. [デバイスをリスタートする](#2-1-%E3%83%87%E3%83%90%E3%82%A4%E3%82%B9%E3%82%92%E3%83%AA%E3%82%B9%E3%82%BF%E3%83%BC%E3%83%88%E3%81%99%E3%82%8B)
2-2. [デバイスを削除してから再読み込み](#2-2-%E3%83%87%E3%83%90%E3%82%A4%E3%82%B9%E3%82%92%E5%89%8A%E9%99%A4%E3%81%97%E3%81%A6%E3%81%8B%E3%82%89%E5%86%8D%E8%AA%AD%E3%81%BF%E8%BE%BC%E3%81%BF)

## 1. デバイスのインスタンスIDを探す
```powershell
pnputil /enum-devices /connected
```
このコマンドで接続中であるデバイスの情報一覧が取得できます。
対象のデバイスを探し、インスタンスIDをコピーしましょう。

```powershell
pnputil /enum-devices /connected /class Mouse
```
この様に`/class`パラメータを使用することで、指定したクラスのデバイスのみを取得できます。

**主要なクラス名**

- USB
- Bluetooh
- Monitor
- Mouse
- Keyboard
- AudioEndpoint

## 2-1. デバイスをリスタートする
```powershell
# 管理者モード
pnputil /restart-device "<インスタンス ID>"
```
```powershell:例
# 管理者モード
pnputil /restart-device "USB\VID_045E&PID_00DB\6&870CE29&0&1" 
```
こちらはデバイスの再起動を使用した方法です。

## 2-2. デバイスを削除してから再読み込み
```powershell
# 管理者モード
pnputil /remove-device "<インスタンス ID>"
pnputil /scan-devices
```
```powershell:例
# 管理者モード
pnputil /remove-device "USB\VID_045E&PID_00DB\6&870CE29&0&1"
pnputil /scan-devices
```
こちらはデバイスを削除し、再読み込みする方法です。

## 参考
- [PnPUtil のコマンド構文 - Windows drivers | Microsoft Docs](https://docs.microsoft.com/ja-jp/windows-hardware/drivers/devtest/pnputil-command-syntax)
【TypeScript】仕様変更に強いFizzBuzz

ネタ元：[「fizzbuzzについて思うこと」](https://qiita.com/jamashita/items/d07e8dd6fd53a6e15c07)
Kotlin版：[【Kotlin】仕様変更に強い FizzBuzz](https://qiita.com/sdkei/items/55c6cc20c49f6838d66b)

FizzBuzz の、割る数、出力する文字列、変換規則の数や順番が変わっても
最小限のコード変更で済むようにする。

```TypeScript
/**
 * FizzBuzz の変換規則を表す型。
 * 入力された数値を割る数と、
 * 割り切れたときに出力に追加する文字列との組の列。
 */
type FizzBuzzMap = Iterable<
    Readonly<[number, string]>
>;

/**
 * FizzBuzz で入力された1つの数値を
 * 変換規則に従って文字列に変換する
 * 関数を返す。
 * 
 * @param map 変換規則。
 * @returns 数値を文字列に変換する関数。
 */
function fizzBuzzFunctionCreator(
    map: FizzBuzzMap
): (num: number) => string {
    return (num: number) => {
        const strs: string[] = [];
        for (const entry of map) {
            if (num % entry[0] == 0) {
                strs.push(entry[1]);
            }
        }
        return strs.length > 0 ? strs.join("") : `${num}`;
    };
}
```

## 使用例

### 普通の FizzBuzz

```TypeScript
/** 変換規則の定義。 */
const FIZZ_BUZZ_MAP: FizzBuzzMap = [
    [3, "Fizz"],
    [5, "Buzz"],
];

/** 数値を変換規則に従って変換する関数。 */
const fizzBuzzFunction: (num: number) => string
    = fizzBuzzFunctionCreator(FIZZ_BUZZ_MAP);

for (let i = 1; i <= 15; ++i) {
    console.log(
        fizzBuzzFunction(i)
    );
}
```

出力

```plaintext
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
```

### Fizz と Buzz の優先順を入れ替える

```TypeScript
const FIZZ_BUZZ_MAP: FizzBuzzMap = [
    [5, "Buzz"],
    [3, "Fizz"],
];

// 他は同じなので省略
```

出力

```plaintext
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
BuzzFizz
```

### こんなことも

```TypeScript
const FIZZ_BUZZ_MAP: FizzBuzzMap = [
    [1, "<"],
    [3, "Fizz"],
    [5, "Buzz"],
    [1, ">"],
];

// 他は同じなので省略
```

出力

```plaintext
<>
<Fizz>
<>
<Buzz>
<Fizz>
<>
<Fizz>
<Buzz>
<>
<Fizz>
<>
<FizzBuzz>
```

／以上
人工衛星の速度



# はじめに

簡単な高校数学を用いて人工衛星の周期や速度を求めてみます．

# 等速円運動する物体の運動

一定の速度$~v~$で，円運動（半径$~r~$）する物体の加速度$~a~$は次式で表現できます．
$$
a=r \omega^2=\frac{v^2}{r}~~\left(\because \omega=\frac{v}{r}\right) \tag{1}
$$
ここで，$~\omega~$は物体の角速度を表します．

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/290566/e2860ea9-1381-3357-dab9-209c6b496ddf.jpeg" width="250.0">

# ニュートンの運動方程式

ニュートンの運動方程式によると，加速度$a$で運動する質力$m$の物体に働く力は以下のように与えられます．
$$
F=ma \tag{2}
$$

# 衛星の速度・周期

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/290566/13820cb7-c522-a987-2f66-01b5f55f1a7c.jpeg" width="300.0">

式(2)の運動方程式を用いて衛星の運動を表現します．まず，高度$h$で地球を周回する人工衛星の加速度は，式(1)を参考に次式で表現できます．
$$
a=\frac{v^2}{R+H} \tag{3}
$$

一方，万有引力の法則によると，質力$~m~$の人工衛星と，質量$~M~$の地球の間には以下の力$~F~$が働きます．
$$
F=G\frac{Mm}{(R+H)^2} \tag{4}
$$
ここで，$~G~$は万有引力定数を表します．式(2)の運動方程式に上の式(3)と(4)を代入します．
$$
\begin{align}
F &=ma \\\
G\frac{Mm}{(R+H)^2} &=m\frac{v^2}{R+H} \tag{5}\\\
\end{align}
$$

式(5)を衛星の速度$~v~$について変形すると次式が得られます．
$$
v=\sqrt{\frac{MG}{R+H}} \tag{6}
$$

また，衛星が地球を1周回する時間(周期)$~T~$は，衛星の角速度$~\omega~$を用いると次式で表現できます．
$$
T=\frac{2\pi}{\omega}=\frac{2\pi}{v}(R+H)~~~~\left(\because \omega=\frac{衛星速度}{半径}=\frac{v}{R+H}\right)
$$
ソリッドステートリレーを利用したスイッチコンセントの実験動画

##ポートフォリオ
[ソリッドステートリレーを利用したスイッチコンセントの実験](https://www.youtube.com/watch?v=UoD5s3KlQkI&feature=youtu.be)

使用したもの
・ソリッド・ステート・リレー（ＳＳＲ）キット　２５Ａ（２０Ａ）タイプ
・ミゼットヒューズ
・ACインレット
・コンセント
練習のためにSwiftをUdemyで勉強してみた(2日目)

#2日目にやったことの概要

- JSONのデータを取得してくる日の出時間表示アプリの制作(後述だが、没)
- Covid-19の感染者数を表示するアプリの制作

#なぜ、日の出時間表示アプリの制作をやめたのか
Yahoo Weather apiを使う内容になっていたのだが、すでにAPIが使えなくなっていたため。
更新してほしかった。。。
https://akkiesoft.hatenablog.jp/entry/20190120/1547972476

今回はAPIを使い、JSONデータを取得して、結果を表示する、ことがメインとなるので、自分で他のAPIを探すことにした
で、選んだのがCovid-19の感染者数だった

#Rakuten Rapid APIを使い始めた
シンプルそうな「COVID-19」を選んだ。日毎の感染者数・死者などを取得できるらしい。
https://api.rakuten.net/api-sports/api/covid-193/

実験してみて死んだ。
Udemyの教材は、APIのURLを叩けば、JSONデータを取得できたが、Covid-19はユーザーごとの利用状況を確認する必要からヘッダーにユーザー情報の入力が必要になっていた。
流石に、素人にこの応用はできない。

試行錯誤してみたが、別の簡単そうなAPIに変更して実験する必要がある、というところで本日は終了。

#今回出くわした問題
憧れのAPIをいじることを始めてみたが、難しい、と直感的に思った。
しかし、色々とやってみるとできることも格段に増えるだろうし、ちょっと寄り道してAPIについて調べてみよう。
【数学】(-1) * (-1) = 1 の証明

# 概要
Twitter で話題になっていたやつ。たぶんみんな `(左辺) = ... (変形していく) ... = (右辺)` の形で証明したいのだと思うので、その一例。オリジナルであるとは主張しないです。検索すると、どこかにたぶんあります。

# 前提など

ここでは、自然数が環であることを前提とする。すると 0 は加法単位元、1 は乗法単位元である。
加法および乗法の結合則と交換則が成り立つことは暗黙的に使っている。括弧も適当に省略している。
なお、「`a=b ならば a+c=b+c`」 などの等号に関する公理と推論も暗黙に使っている。
なお、(-x) は x の加法逆元とする、つまり任意の x に対して `x + (-x) = 0` を公理であるとする。

# 証明

```
(左辺)
= (-1) * (-1)
= (-1) * (-1) + 0
= (-1) * (-1) + (-1) + 1
= (-1) * (-1) + (-1) * 1 + 1 
= (-1) * { (-1) + 1 } + 1
= (-1) * 0 + 1
= (-1) * 0 + 0 + 1
= (-1) * 0 + (-1) * 0 + {- (-1) * 0} + 1
= (-1) * ( 0 + 0 ) + {- (-1) * 0} + 1
= (-1) * 0 + {- (-1) * 0} + 1
= 0 + 1
= 1
= (右辺)
```

# 解説

## 本体 (前半部分)

基本的には

```(左辺) - (右辺) = 0```

の証明はシンプルであることを使う。なお、この命題は、より正確には

```(左辺) + {-(右辺)} = 0```

つまり、**(左辺)** と **(右辺)の加法逆元** との和が0であることを意味している。
これに対して、(右辺) を移項し戻した命題、つまり、

```(左辺) + (右辺) + {-(右辺)} = (右辺)```

の証明を作ってやればいい。これが前半にあたる。

## a * 0 = 0 (後半部分)

証明の途中である値 a に対して `a * 0 = 0` の証明が必要になる。0 はあくまでも加法の単位元であって、乗法の零元ではないので、これは明示的に証明する必要がある。これは `a * 0 = a * (0 + 0) = a * 0 + a * 0` から `a * 0` が加法単位元つまり 0 であることがわかるので、この証明を適切に変形して上記本体の証明に埋め込めばいい。これが後半部分で行っている証明である。

有用な気がするので、この部分だけ書き下しておく (乗法記号省略):

```
a0
= a0 + 0               //  0 は加法単位元
= a0 + { a0 + (-a0) }  //  逆元の存在
= { a0 + a0 } + (-a0)  //  加法の結合則
= a(0+0) + (-a0)       //  分配法則の逆
= a0 + (-a0)           //  0 は加法単位元
= 0  (Q.E.D.)          //  逆元との和
```
GitHubのProjectボードに新規作成したIssuesを自動追加する

#はじめに
今回、GitHubのProjectボードを使ってステータス管理をしようという話になり、
Projectボードに必要なGitHubの権限周りでまとまった情報が見つからなかったので書きます。

この記事を読めば少しはGitHubの権限まわりに関して理解が進むかもしれません。

#目次
* はじめに
* 目次
* 今回やりたかったこと
* 必要な権限と設定<br>
　・IssueをProjectボードへ自動追加したい場合<br>
　・（おまけ）Issueへlabelを付与させたいとき
* 権限の変え方<br>
　・Organizationの基本権限を変えたいとき<br>
　・チームで権限を管理するとき<br>
　・個人単位で権限を与えるとき
* さいごに

#今回やりたかったこと
今回やりたかったことは以下である。

* Organizationの複数のメンバーがIssueを作成する
* Organizationの任意のリポジトリのProjectボード上でIssueを動かしながら進捗を管理する（以下画像参照）
* Projectボードがあるリポジトリ以外への権限はReadに留めたい<br>（なるべくできることが少ない権限が良い）

<img width="895" alt="gitpicture.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/600297/96272a13-6d83-49b0-4d74-c3f6d0f13cb7.png">

#必要な権限と設定
GitのOrganizationのリポジトリにどのような権限があるかについては以下の公式ドキュメントを参照してほしい

* [Organization のリポジトリ権限レベル](https://help.github.com/ja/github/setting-up-and-managing-organizations-and-teams/repository-permission-levels-for-an-organization)

上記内容をもとに必要な権限範囲を考える。

## IssueをProjectボードへ自動追加したい場合
以下の作業が必要である

###1.OrganizationのProjectボードのリポジトリへの権限を変更する。

権限をWrite以上にする必要がある。

`Write: プロジェクトに積極的にプッシュしたいコントリビューターにおすすめします`

この作業によって、Issueの画面右側のメニューからProjectを選択できる。

###2.Projectボードのcolumnの設定をする。
Issueが作成されたときに自動で追加されてほしいcolomunに対して自動追加設定をする。
設定方法に関しては以下の公式ドキュメントを参照してほしい。

* [プロジェクトボードの自動化を設定する](https://help.github.com/ja/github/managing-your-work-on-github/configuring-automation-for-project-boards)

この作業をすることでIssuesが自動でProjectボードのcolomunに現れる。

##（おまけ）Issueへlabelを付与させたいとき
labelを付与する権限だけを付けたい場合は以下の権限をつければよい。

`Triage: 書き込みアクセスなしに、Issue やプルリクエストを積極的に管理したいコントリビューターにおすすめします`

Triage権限にすれば、書き込みの権限はなくても、labelを付与することはできる。
ただし、Triage権限の場合は前述の内容からProjectボードにIssueを追加するための権限が足りないので注意が必要である。

#権限の変え方
権限の変え方がわからない方のために参照すべきドキュメントを紹介する。

GitHubでは以下のそれぞれに対してOrganization が所有するリポジトリへの異なるアクセスレベルを付与できる。

* Organization のメンバー
* 外部のコラボレータ
* Team

また、Organization のリポジトリに対する管理者権限があるユーザが、リポジトリに対してそれより高いレベルの権限を付与すると、基本レベルの権限は、付与された高い権限によってオーバーライドされます。
例：
OrganizationAのメンバーとしてWrite権限を持っていて、OrganizationAのリポジトリBに対してチームメンバとしてRead権限を割り振られている場合、OrganizationAのリポジトリBに対してWrite権限を持つ。

必要な権限範囲を考慮したうえで、以降の作業を実施してください。

## Organizationのメンバーの基本権限を変えたいとき
基本権限はOrganizationの全メンバーに対して適用される、Organization内のすべてのものに対するアクセス権限です。（デフォルトは最低のRead権限）

Organizationの管理者メンバーが以下を実行できます。

* [Organization の基本レベルの権限の設定](https://help.github.com/ja/github/setting-up-and-managing-organizations-and-teams/setting-base-permissions-for-an-organization#setting-base-permissions)

## チーム単位で権限を変えるとき
チーム単位で権限を変えるときは以下の公式ドキュメントを参照してください。
チームメンバーのうち、Maintainer権限を持つメンバーが実行できます。

* [Organization のプロジェクトボードに対するチームのアクセスを管理する](https://help.github.com/ja/github/setting-up-and-managing-organizations-and-teams/managing-team-access-to-an-organization-project-board)

## 個人単位で権限を与えるとき
この作業は一度に多くの人の権限を変える場合には向いていません。

以下の作業はOrganizationの管理者権限を持つメンバーが実行できます。

* [Organization のプロジェクトボードに対する個々のアクセスを管理する](https://help.github.com/ja/github/setting-up-and-managing-organizations-and-teams/managing-an-individuals-access-to-an-organization-project-board)

# 最後に
Issueについて書かれている記事がなかったので書いてみました。
誰かの助けになれば幸いです。
AWSをゼロから勉強する。vol.0

7/9 
これから1日10分でも毎日勉強して
AWSについての理解を深めていく様をメモとして残していきます。
同じ境遇の人は、気軽に声かけてもらえると嬉しいです。
お互いに情報共有しあえたら最高です。

勉強に使う参考書
「Amazon Web Service クラウドサーバ構築ガイド ~コストを削減する導入・実装・運用ノウハウ~」
nodenv環境下でwebstormではyarnが使えない

# nodenv環境下でwebstormではyarnが使えない

## 問題
jetbrains製品でnodenvを利用する時、jetbrains-npmを利用しなければpath解決がされず、jetbrains側でnpmの機能が一切使えない問題があります。

ただjetbrains-npmという名前から察するように、jetbrains-npmはnpmをベースに操作され、少し違った挙動をしてしまいます。
具体的にはyarn.lockファイルを参照してほしいのに、参照されなかったり、package-lock.jsonが生成されてしまいます。

## 解決策
jetbrains-npmのyarnバージョンを探しましたが無かった為、今回forkし作成しました。
手前味噌のようで恐縮ですが、yarnを使いたい場合は以下を利用すれば解決します。

https://github.com/tanmen/jetbrains-yarn
Macにnode.js,npmのインストール方法


# node.js,npmのインストールの流れ
①　Homebrewのインストール
②　nodebrewのインストール
③　node.jsのインストール
上記の手順で行います。
node.jsがインストールされれば、同時にnpmもインストールされます。

# Homebrewのインストール

```:terminalコマンド
$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
```
### ＜Homebrewのバージョンの確認＞
以下のコマンドを入力してHomebrewのバージョンを確認することで、インストールがうまく行ったかどうか確認することができます。

```:terminalコマンド
$ brew -v
```

# nodebrewのインストール

```:terminalコマンド
$ brew install nodebrew
```
### ＜nodebrewのバージョンの確認＞
Homebrewと同様に、nobebrewのバージョンを確認することで、インストールがうまく行っているのかを確認できる。

```:terminalコマンド
$ nodebrew -v
```

# node.jsのインストール
以下のコマンドを入力することで、最新版のnode.jsがインストールされます。

```:terminalコマンド
$ nodebrew install-binary latest
```
### ＜インストールされたnode.jsのバージョンを確認＞

```:terminalコマンド
$ nodebrew list
```
上記を入力すると、下記のようなログが出力されます。

```:出力ログ
v12.14.1

current: v12.14.1
```
currentの部分が、現在動いているnode.jsです。
次のように出力された場合には、node.jsが有効になっていません。

```:出力ログ
current: none
```
有効化するためには、インストール済みのバージョンをuseコマンドで有効化します。

```:terminalコマンド
$ nodebrew use  v１２.１４.１
```

node.jsがインストールされれば、npmも同時にインストールされます。
これで開発環境が整いました。
Swiftで有効桁数

Swiftで有効桁数を表現するにはどうすればいいのだろう？と調べたのでメモ

```Swift
import UIKit
let a = 3.000
let b = 2.000
let c = Double(a)/Double(b)
let d = String(format: "%.3f", c)
print(c,d)
=> 1.5 1.500
```

他にも方法はあると思います。ぜひコメントしてください。
railsのbelongs_toに指定できるoptional: true

```ruby:

class Task < ApplicationRecord
  has_many :user
end


class User < ApplicationRecord
  belongs_to :task, optional: true
end
```

このoptional: trueとは何なのか？

これはbelongs_toの外部キーのnilを許可するというもの！

上記のコードであれば、User.task_idが外部キーとなり、値がセットされていない場合はバリデーションで弾かれるが、optional: trueを設定しておくと、外部キーがnilであってもDBに保存できる！
PythonでFizz Buzz

#Fizz Buzzとは
Fizz Buzzとはプログラミング初学者が最もはじめに解く問題のうちの１つです。
具体的には$1\sim100$までの数字を順に出力し、$3$の倍数の時にFizz、$5$の倍数の時にBuzz、両方で割り切れる時にFizzBuzzと出力するプログラムのことです。

さっそく書いていきます。

#コード

```Python
for i in range(1, 101):
    if i % 15 == 0:
        print('Fizz Buzz')
    elif i % 3 == 0:
        print('Fizz')
    elif i % 5 == 0:
        print('Buzz')
    else:
        print(i)
```

#出力
```
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
Fizz Buzz
16
17
Fizz
19
Buzz
Fizz
22
23
Fizz
Buzz
26
Fizz
28
29
Fizz Buzz
31
32
Fizz
34
Buzz
Fizz
37
38
Fizz
Buzz
41
Fizz
43
44
Fizz Buzz
46
47
Fizz
49
Buzz
Fizz
52
53
Fizz
Buzz
56
Fizz
58
59
Fizz Buzz
61
62
Fizz
64
Buzz
Fizz
67
68
Fizz
Buzz
71
Fizz
73
74
Fizz Buzz
76
77
Fizz
79
Buzz
Fizz
82
83
Fizz
Buzz
86
Fizz
88
89
Fizz Buzz
91
92
Fizz
94
Buzz
Fizz
97
98
Fizz
Buzz
​

```

以上です。
Macにnodebrewでnodeをインストールするまでにしたこと

Macに__nodebrew__で__node__をインストールしようとおもったところ、__nodebrew__でインストールした__node__のバージョンと`node -v`のバージョンが合っていなかったので、解決した方法を備忘録として残します。

#npm、node、nodebrewをアンインストールする
まずは__npm__、__node__、__nodebrew__をインストールしているかを確認します。

```:ターミナル
$ npm -v
$ node -v
$ nodebrew -v
```

コマンドでバージョンが確認できない場合はインストールの段階に進みましょう。

バージョンが確認できた場合はアンインストールします。

##npmをアンインストールする

まず__npm__をアンインストールします。

次のコマンドを順番に実行してください。

```:ターミナル
$ npm uninstall -f npm
$ rm -rf .npm \
> node_modules
```

`npm -v`で確認してバージョンが表示されなければ成功です。

##nodeをアンインストールする

__node__をアンインストールします。
__node__をインストールした方法でアンインストールの方法が違います。

よくわからない場合は全て実行してください。

###パッケージ版
####homebrewでインストールした場合のアンインストール方法

```:ターミナル
$ brew uninstall node
```

####その他でインストールした場合のアンインストール方法
次のコマンドを順番に実行してください。

```:ターミナル
$ lsbom -f -l -s -pf /var/db/receipts/org.nodejs.node.pkg.bom \
> | while read i; do
> sudo rm /usr/local/${i}
> done
$ sudo rm -rf /usr/local/lib/node \
>     /usr/local/lib/node_modules \
>     /var/db/receipts/org.nodejs.*
```

###ソース版

`which node`で確認したコードを`rm -rf`で削除してください。
必ずしも`/usr/local/bin/node`とは限りません。

```:ターミナル
$ which node
/usr/local/bin/node
$ rm -rf /usr/local/bin/node \
> node_modules
```

###アンインストール後

アンインストール後に`node -v`で確認して、バージョンが表示されなければ成功です。

##nodebrewをアンインストールする

__nodebrew__をアンインストールする方法は二つあります。
最初の方法でアンインストールできると思いますが、できなかった場合は次の方法も実行してみてください。

以下が__nodebrew__をアンインストールするコマンドです。

```:ターミナル
$ brew uninstall nodebrew
```

このコマンドを実行した後`nodebrew -v`でバージョン確認をしましょう。
バージョンが表示されなければ成功です。

この方法でアンインストールができなかった場合は次の方法を試してみてください。

```:ターミナル
$ brew search nodebrew
```

このコマンドで`nodebrew`というディレクトリがあるかを確認します。
あった場合は次を実行して`nodebrew`のある場所を確認します。

```:ターミナル
$ brew info nodebrew
```

場所が確認できた場合は`Finder`からそこの場所に移動して、`nodebrew`を直接ゴミ箱に捨ててください。

これで__npm__、__node__、__nodebrew__のアンインストールが終了しました。

#nodeのインストール

アンインストールが終了したら、__node__をインストールしていきます。

##nodebrewのインストール、環境変数の設定

次のコマンドを順番に実行してください。

```:ターミナル
$ curl -L git.io/nodebrew | perl - setup
$ export PATH=$HOME/.nodebrew/current/bin:$PATH
```

##nodeのインストール

次に__node__のインストールをします。
インストールするバージョンは最新版にします。

```:ターミナル
$ nodebrew install-binary latest
```

##インストールしたバージョンの確認

インストールしたバージョンを確認します。

```:ターミナル
$ nodebrew ls
v14.5.0

current: node
```

`current: node`とありますが、ここには現在使用しているバージョンが表示されます。
この状態だとまだ使用することができないのでバージョンを設定します。

##バージョンの設定

使用するバージョンを設定します。
今回は`v14.5.0`というバージョンを設定します。

```:ターミナル
$ nodebrew use v14.5.0
```

これでバージョンが設定できました。

```:ターミナル
$ nodebrew ls
v14.5.0

current: v14.5.0
```

確認すると設定できています。

##動作確認

最後に__node__が動作しているか確認しましょう。

```:ターミナル
$ node -v
v14.5.0
```

設定したバージョンが表示されれば成功です。

#参考サイト
外部サイト

+ [MacにNode.jsをインストールしてnpmを使えるようにする(Nodebrew利用)](https://hirooooo-lab.com/development/nstall-node/)

Qiita

+ [【Mac版】node.jsのアンインストールと再インストール手順メモ](https://qiita.com/wagi0716/items/94193a80502f9d81a9e0)

+ [MacにpkgでインストールしたNode.jsをアンインストールする手順](https://qiita.com/yoshikoba/items/4906829faaaae8c73e56)


+ [MacにNode.jsをインストール](https://qiita.com/kyosuke5_20/items/c5f68fc9d89b84c0df09)

+ [Nodebrew本体を削除する方法](https://qiita.com/tonkotsuboy_com/items/f5d17f0b9698554a7716)

+ [macOS Catalinaでnode.jsをインストール](https://qiita.com/kakuta_yu/items/a61e2b6a6e8a82dbbd96)
サクラエディタのGrep複数検索を自動化してみた

ソースの詰まったフォルダから特定の文字列(クラスとか条件とか)を拾ってくるのにGrepの自動化が便利すぎたので備忘録。これで既存プログラムのマッピングとかが楽になるぞー。
((꜆꜄ ˙ω˙ )꜆꜄꜆ｼｭｯｼｭｯｼｭｼｭｼｭｼｭｼｭｯ

```
cd /d C:\hogehoge\sakura
sakura -GREPMODE -GKEY=KeyWord1 -GFILE=*.* -GFOLDER=C:\hogehoge\src -GCODE=99 -GOPT:SPU1 >> C:\work\test.txt
sakura -GREPMODE -GKEY=KeyWord2 -GFILE=*.* -GFOLDER=C:\hogehoge\src -GCODE=99 -GOPT:SPU1 >> C:\work\test.txt
sakura -GREPMODE -GKEY=KeyWord3 -GFILE=*.* -GFOLDER=C:\hogehoge\src -GCODE=99 -GOPT:SPU1 >> C:\work\test.txt
```
↑これをエディタにコピッて.batで保存すればOK

1行目でサクラエディタを呼び出して(C:\hogehoge\sakuraはサクラエディタ保存場所)、2から4行目で検索かつtextに保存。

|項目|説明|
|:---|:---|
|-GKEY|検索したい単語|
|-GFOLDER|C:\hogehoge\srcは検索先のディレクトリ|
|-GFILE|拡張子の設定。言語がjavaなら*.javaとかにしておけばOK|
|-GOPT|検索オプション。なぜかここだけ「＝」じゃなくて「：」。|
|>> C:\work\test.txt|検索結果の出力先。>>で追記保存に。|
このGOPTの：のせいで標準出力できなくてめちゃくちゃ困った。
ちなみにGOPTは、

|記号|オプション詳細|
|:---|:---|
|S|サブフォルダからも検索|
|P|該当行を出力／未指定時は該当部分だけ出力|
|U|標準出力に出力し、Grep画面にデータを表示しない|
|1|結果出力形式。1か2か3のどれかを指定します。(1=ノーマル、2=ファイル毎、3=結果のみ)|

どれがどう効いたかはあまり検証してないので分からんのですが、とりあえずUはTextに書き出すうえで大事。Sは、全ソース調べるうえで下位フォルダも検索しないと意味がないので。残りは出力結果がCSV加工しやすいような感じにしました。
【jQuery】特定の要素までスクロールしたときに要素を表示

#はじめに
Webサイトのホームページでよくあるスクロールしたときに要素がフワッと表示されるアニメーションをjQueryで実装するにはどうしたら良いかを復習。

#アニメーションのロジック
実際にスクロールした量と画面のトップから特定要素までのオフセットをjQueryで取得。
「スクロールした量 > 特定の要素までのオフセット」のときにaddClassやfadeInなどでアニメーションを実行。
最後にブラウザの高さを取得すればアニメーション完成です。

#ソースコード
```index.js
$(function(){
 var offset = $('特定の要素').offset().top;
 var height = $(window).height();

 $(window).scroll(function () {
   if ($(this).scrollTop() > offset - height) {
      // アニメーションを実行
    } 
 });
}
```

#感想
何度もググるくらいなら自分で記事を書いて忘れたときに読み直せるようにしたほうが良いと思い、まとめました。
明日も記事更新頑張ります。
ゼロから始めるLeetCode Day81 「347. Top K Frequent Elements」

# 概要

海外ではエンジニアの面接においてコーディングテストというものが行われるらしく、多くの場合、特定の関数やクラスをお題に沿って実装するという物がメインである。

どうやら多くのエンジニアはその対策としてLeetCodeなるサイトで対策を行うようだ。

早い話が本場でも行われているようなコーディングテストに耐えうるようなアルゴリズム力を鍛えるサイトであり、海外のテックカンパニーでのキャリアを積みたい方にとっては避けては通れない道である。

と、仰々しく書いてみましたが、私は今のところそういった面接を受ける予定はありません。

ただ、ITエンジニアとして人並みのアルゴリズム力くらいは持っておいた方がいいだろうということで不定期に問題を解いてその時に考えたやり方をメモ的に書いていこうかと思います。

[Leetcode](https://leetcode.com/)

Python3で解いています。

[ゼロから始めるLeetCode 目次](https://qiita.com/KueharX/items/6ee2502c3b620c795b70)

前回
[ゼロから始めるLeetCode Day80「703. Kth Largest Element in a Stream」](https://qiita.com/KueharX/items/8999b2b903596639fbfa)


[Twitter](https://twitter.com/kueharx)やってます。

**[技術ブログ](https://kueharx.blogspot.com/)始めました！！**
技術はLeetCode、Django、Nuxt、あたりについて書くと思います。**こちらの方が更新は早いので**、よければブクマよろしくお願いいたします！


# 問題
[347. Top K Frequent Elements](https://leetcode.com/problems/top-k-frequent-elements/)
難易度はMedium。
前回の問題同様Heapを使った問題です。

問題としては、数字が格納された空ではない配列が与えられます。その配列の中から`K`番目まで頻出の要素を返すようなアルゴリズムを設計してください、というものです。

>Example 1:

>Input: nums = [1,1,1,2,2,3], k = 2
Output: [1,2]

>Example 2:

>Input: nums = [1], k = 1
Output: [1]

# 解法

`Counter`を使ってリストの要素を調べ、keyを取得、そしてheapの[nlargest](https://docs.python.org/ja/3/library/heapq.html)を使って書きました。


```python
import heapq
import collections

class Solution:
    def topKFrequent(self, nums: List[int], k: int) -> List[int]:
        count = collections.Counter(nums)
        key = count.get
        return heapq.nlargest(k,count.keys(),key)
# Runtime: 108 ms, faster than 66.40% of Python3 online submissions for Top K Frequent Elements.
# Memory Usage: 18.2 MB, less than 79.07% of Python3 online submissions for Top K Frequent Elements.
```

なお、`nlargest`の引数は`n, iterable, key=None`という順番です。

では今回はここまで。
お疲れ様でした。
SASテクニック 並び替え sortプロシジャ、SQL、Hash

hashの練習というか、自分用memo

# sortプロシジャ
```sas
%macro M_Sort(In = , Out = , Key = );
proc sort data = &In. out = &Out.;
  by &Key.;
run;
%mend;
```

In:入力データ
Out:出力データ(Inと同じでも可)
Key:ソートの変数(逆順にしたいならdescending 変数名)

ソートの基本形

proc sortのステートメントにnodupkey追加で重複削除
よく使うやり方

```sas
proc sort data = DATA1;
  by A B;
run;
proc sort data = DATA1 out = DATA2 nodupkey;
  by A;
run;
```
で、A,Bでソートして、Aごとに重複削除


# SQLでソート

```sas
%macro M_SqlSort(In = , Out = , Key = );
proc Sql;
  create table &Out. as
    select *
    from &In.
    order by &Key.;
quit;
%mend;
```
Key = %str(A , B , C)のように、「,」区切りでソートの変数を指定
逆順はdescを後ろにつける
select distinct AでAごとに重複削除(上のマクロは未対応)
InとOutは同じだとerror


# Hashでソート

```sas
%macro M_HashSort(In = , Out = , Key = , Ordered = A);
data _NULL_;
  if 0 then set &In.;
  declare hash hs1( dataset: "&In.", ordered: "&Ordered.", multidata: "Y" );
  hs1.definekey( &key. );
  hs1.definedata( ALL: "Y" );
  hs1.definedone();
  hs1.output( dataset: "&Out." );
  stop;
run;
%mend;
```
Key = %str( "KEY1" , "KEY2" . "KEY3" )って感じでソートの変数を指定
大きいデータの場合、hashはメモリ不足で動かないことも(じゃあ益々使わない...)

https://documentation.sas.com/?docsetId=lecompobjref&docsetTarget=n0idnipdo4awyun1q8zv7427r23f.htm&docsetVersion=3.1&locale=ja
Firebase SDKをJestでMockしてテストする

## やりたいこと
Firebase SDKを利用した関数のテストをしたいと思い立ちました。実際にAPIにアクセスせずにテストを実行したいので、Firebase SDKをMockしてテストを行うこととしました。テストはJestを使います。

## テスト対象のコード
例としてCloud Firestoreを利用する際の手順を記載します。
なお、以下には記載していませんが、環境構築は終わっているものとすします。（手順は[こちら](https://firebase.google.com/docs/firestore/quickstart?hl=ja)の通り！）

以下のようなFirestoreのドキュメントを監視して更新があったときにsomethingをする関数をテストすることにしてみます。

```javascript:target.js

  async watchDoc({ commit }) {
    await firebase
      .firestore()
      .collection('users')
      .onSnapshot((snapshot) => {
        snapshot.forEach((doc) => {
          doSomething(doc)
        })
      })
  }

```

Colud Firestoreは以下のように初期化されていることとします。

```javascript:initFirebase.js

import firebase from 'firebase'

// Initialize Cloud Firestore through Firebase
firebase.initializeApp({
  apiKey: process.env.API_KEY,
  authDomain: process.env.AUTH_DOMAIN,
  databaseURL: process.env.DATABASE_URL,
  projectId: process.env.PROJECT_ID,
  storageBucket: process.env.STORAGE_BUCKET,
  messagingSenderId: process.env.MESSAGING_SENDER_ID
});

export default firebase
```


## テストコード
以下のようにMockを作成し、振る舞いを定義することで、実際にAPIを叩かずにdoSomething関数を動作させてテストを行うことができます。


```javascript:firestore.spec.js

import * as firebase from 'initFirebase'
import * as firestore from 'target.js'

// firebase.firestore()のMockを作成する
jest.mock('initFirebase', () => ({
  firestore: jest.fn()
}))

// firebase.firestore()の振る舞いを定義する
const firebaseMock = firebase.firestore.mockImplementation(() => {
     return {
        collection: jest.fn(() => ({
          onSnapshot: jest.fn((func) => {
            func(doc) // docにはAPIから返ってくるDocument相当のデータを入れる
          })
        }))
      }
   })

// テストを記述していく

```

Mock方法のみ記載しています。テスト部分ややFirestoreの構築方法などは別の記事などを参考にしてください。。
AIZU ONLINE JUDGE の問題をSwiftでやってみた(プログラミング入門 繰り返し処理編)

##トピック #1　繰り返し処理
[AIZU ONLINE JUDGE](https://onlinejudge.u-aizu.ac.jp/courses/lesson/2/ITP1/3)の問題にSwiftで解答したものになります。競技プログラミングは普段やりませんので、こうしたほうが簡単！などがあればコメントで教えて下さい。
[テスト入力](https://paiza.io/projects/g8pB6rEnJeIh4YLStunrNg)はこちらのPaisa.IOで行っています。
###3_A 複数のHelloWorldの出力
**問題**
1000 個の "Hello World" を出力するプログラムを作成して下さい。
**解答**

```Swift
for _ in 0 ..< 1000 {
    print("Hello World")
}
```
###3_B テストケースの出力

**問題**
入力は複数のデータセットから構成されています。各データセットは１つの整数 x を含む１行から構成されています。xが0のとき入力の終わりを示し、このデータセットに対する出力を行ってはいけません。
各データセットごとに、以下の形式で x を出力して下さい
3
5
11
7
8
19
0

Case 1: 3
Case 2: 5
Case 3: 11
Case 4: 7
Case 5: 8
Case 6: 19

```Swift
var count = 1
while(true) {
    let a = Int(readLine()!)!
    if a == 0 {
        break
    }
    print("case \(count): \(a)")
    count += 1
}
```

###3_C 2つの数の交換
**問題**
入力は複数のデータセットから構成されています。各データセットは空白で区切られた２つの整数 x, y を含む１行から構成されています。x と y がともに 0 のとき入力の終わりを示し、このデータセットに対する出力を行ってはいけません。
入力
3 2
2 2
5 3
0 0
出力
2 3
2 2
3 5


```Swift
while(true){
    let a = readLine()!.split(separator: " ").map({Int($0)!})
    let first = a[0]
    let second = a[1]
    if first == 0 && second == 0{
        break
    }
    print(a[1],a[0])
}
```

###3_D約数の数

**入力**
３つの整数a、b、cを読み込み、aからbまでの整数の中にcの約数がいくつあるのかを求めるプロフラムを作成して下さい。
**解答**

```Swift
let a = readLine()!.split(separator: " ").map({Int($0)!})
var multipleArr: [Int] = []
var count = 0
for i in 0 ..< a[2] {
    if a[2].isMultiple(of: i) {
        multipleArr.append(i)
    }
}

for i in a[0] ..< a[1] {
    if multipleArr.contains(i) {
        count += 1
    }
}

print(count)
```
[django]データベースcreate!

#Djangoでデータベースに保存

##model作成

```python

from django.db import models

class Person(models.Model):
    name = models.CharField(max_length=100)
    age = models.IntegerField(default=0)

    def __str__(self):
        return '<Person:id=' + str(self.id) + ','+\
            self.name + '(' + str(self.age) + ')>'
```
モデルを作成したら、setting.pyのinstalled_apps = []のなかにアプリ名を追加
その後

```shell
python manage.py makemigrations "アプリ名"
```
その後

```shell

python manage.py migrate
```

これで使えるようになりました。

##shellでデータ保存

```shell
python manage.py shell
↓
from "アプリ名".models import Person
p = Person.objects.create(name="takuya",age="18")
p.save()
```
これで簡単なデータ保存ができます。
【cygwin】cronで実行されないスクリプト

タイトルの現象について一応は解決しました。解決したのですが、うまく行かなかった原因も、うまく行った理由もよく分かっていません。
確認したことを簡単にまとめておきます。

# スクリプトの内容

- テキストデータを処理するスクリプト
- 中間ファイル、実行の様子を確認できるログファイルを書き出す

# 動かない状況

- 他のスクリプト（同じものを３個登録）の実行実績がある環境
- コマンドラインから「./script.sh」だと動く
- コマンドラインから「/path/to/script.sh」だと動く
- cronだと動かない
- 登録当初は「chmod 744」だったのを「755」に変更。
- コマンドラインでbashのパス補完で確認した「/path/to/script.sh」のコピペもダメ

# 確認したこと

- croneventsでは実行した様子がログとして出力されない
- /var/log/cron.logで見ると「/path/to/script.sh」があることは認識している
    - 起動時に「-x ext,sch,proc,pars,load,misc」を指定しています

# 解決した方法

- 最終行にあった「/path/to/script.sh」を先頭行に移動したら動いた

# 備考

なんで、この方法で動いたのか不明。途中で「chmod 755」に変更したのがポイントで、この変更状況がcronに認識されていなかったのかもしれない。しばらく様子見。

# 後日談

再現してみようとしたけどうまくいきません。

## 1.簡単なスクリプトを作成

```
#!/usr/bin/bash

LOG_FILE=/home/USERNAME/logs/debug_cron.log

date '+%Y/%m/%d %H:%M:%S' 2>&1 >> $LOG_FILE
```
権限は「chmod 700」にしました。

## 2. CRONに登録

* ```crontab -e```でcronに登録
* croneventsを実行し「RELOAD」の表示を確認

## 3. そして再現せず…

* ```/home/USERNAME/logs/debug_cron.log```への書き込みを確認…
* croneventsで```RELOAD```を確認できれば実行は確実かもしれない。
[3] : C#(ASP.NET core)でWeb APIを作って(以下略)[EntityFrameworkCore#INSERT/UPDATE編]

# 概要
前回は、EntityFramework_Coreで「SELECT」してみました
今回は、「INSERT/UPDATE」を実装してみます

## 準備

[前回の検証はこちら](https://qiita.com/myantyuWorld/private/35c9ccc293a5c5af0493)

## 今回のキモ

EntityFrameworkのアノテーションと、ModelBindingのアノテーションは「同時」に設定できる
以下、同時設定例

```c#
{
    [Table("m_memotype")] // ★EntityFrameworkの設定
    [System.Xml.Serialization.XmlRoot("memo")] // ※ ModelBinding[FromBodyにより自動でxml　→　オブジェクト化]
    public class MemoTypeEntity
    {
        [Key] // ★EntityFrameworkの設定
        [Column("mmsb")] // ★EntityFrameworkの設定
        [System.Xml.Serialization.XmlElement("mmsb")] // ※ ModelBinding[FromBodyにより自動でxml　→　オブジェクト化]
        public int Mmsb { get; set; }

        [Required] // ★EntityFrameworkの設定
        [Column("mmsn")] // ★EntityFrameworkの設定
        [System.Xml.Serialization.XmlElement("mmnm")] // ※ ModelBinding[FromBodyにより自動でxml　→　オブジェクト化]
        public string Mmsn { get; set; }
    }
}
```

## 以下のコードについて解説

```c#
1: // POST: api/MemoTypeEntities
2: [HttpPost]
3: public async Task<IActionResult> PostMemoTypeEntity([FromBody] MemoTypeEntity memoTypeEntity)
4: {
5:     if (!ModelState.IsValid)
6:     {
7:         return BadRequest(ModelState);
8:     }
9: 
10:     _context.MemoTypes.Add(memoTypeEntity);
11:     await _context.SaveChangesAsync();
12: 
13:     return CreatedAtAction("GetMemoTypeEntity", new { id = memoTypeEntity.Mmsb }, memoTypeEntity);
14: }
```

### [5行目]ModelState.IsValidってなに？
⇒ バリデーションの実装[https://www.atmarkit.co.jp/fdotnet/aspnetmvc3/aspnetmvc3_04/aspnetmvc3_04_02.html]

```c#
実装例 上記と組み合わせての使用もできると思われる
{
  public class Book
  {
    [Key]
    [DisplayName("ISBNコード")]
    [Required(ErrorMessage = "{0}は必須です。")]
    [RegularExpression("[0-9]{3}-[0-9]{1}-[0-9]{3,5}-[0-9]{3,5}-[0-9A-Z]{1}", ErrorMessage = "{0}はISBNの形式で入力してください。")]
    public string Isbn { get; set; }

    [DisplayName("書名")]
    [Required(ErrorMessage="{0}は必須です。")]
    [StringLength(100, ErrorMessage="{0}は{1}文字以内で入力してください。")]
    public string Title { get; set; }

    public virtual ICollection<Review> Reviews { get; set; }
  }
}
```

### [11行目]await _context.SaveChangesAsync()ってなに？
⇒非同期保存[https://docs.microsoft.com/ja-jp/ef/core/saving/async]

### 上記でのcatchの仕方・例外処理
⇒EntityFramework SaveChange()時の例外発生時にSQLのエラーを表示させる[https://qiita.com/yahweh/items/1f1f1bf8b09c7d60cfbd]
AWSコンソールにログインするためのMFA（多要素認証）をAWS CLIで無効化する

MFAデバイスを失ってAWSコンソールにログインできなくなってしまった！そんなとき、AWS CLIが使えて権限さえついていれば自分自身でMFAを無効化できる。

```
aws iam list-mfa-devices --user-name {ユーザー名}
```

ここで表示される`SerialNumber`（`arn:aws:iam::***:mfa/***`）を控えておいて、

```
aws iam deactivate-mfa-device --user-name {ユーザー名} --serial-number {シリアルナンバー}
```

以上でもうログインできるようになっている。
GCPのネットワーク接続系のサービス

# 最初に
## 概要
GCPとオンプレミス or GCPと別クラウド のネットワーク接続方法の選択のまとめ。

## なんでこの記事を書いたか
GCPの[公式ページ](https://cloud.google.com/hybrid-connectivity?hl=ja)を見て、分かりにくかったのでまとめてみた。公式ページの一番下の「最適な GCP 接続を選ぶ」の項目は分かりやすかった。GCP資格（Cloud Architect）取得の対策。
ネットワーク系は良く分からない・・・

# GCPネットワーク接続系
## Cloud VPN
- 簡単で安い。ただし、回線は小さめ。
- **インターネット経由**で**安全**に**低コスト**で Google VPC に接続。**最大 3.0 Gbps**のデータ帯域幅。高可用性 VPN は業界トップクラスの SLA を提供し、99.99% の稼働時間を保証。
- Google Cloud へのトラフィックを暗号化する必要がある場合、低スループット ソリューションが必要な場合、ワークロードを Google Cloud に移行してテストを実施する場合
- トラフィックに 10 Gbps や 100 Gbps の回線が必要ない場合
- SLAは VPNサービスの可用性を対象としており、 公共インターネットの可用性は 対象としていない。ISPが提供する企業向けインターネットの サービスレベル契約（SLA）は 通常 専用回線で99%から99.5%の間。 したがって Cloud VPNサービスが 99.9%の時間利用可能でも その基盤となる通信は 0.5%から1%の時間停止。**可用性×**。

## Cloud Interconnect
エンタープライズ向け。
[構成図：レイヤ 3 のみのトポロジ（推奨）](https://cloud.google.com/network-connectivity/docs/interconnect/how-to/dedicated/configuring-onprem-routers?hl=ja)。

### Partner Interconnect（サービス プロバイダ）
- **サポートされているサービス プロバイダを通じて**、より多くの接続ポイントを提供。 ネットワーク間のトラフィックは、公共のインターネットではなく、サービス プロバイダを介して流れる。**50 Mbps～50 Gbps** の可変容量。
- スループットが高い Google Cloud へのエンタープライズ クラスの接続が必要な場合
- Google のロケーションに接続できない場合(Dedicated Interconnect のロケーションで接続できない場合)や、それほど大きな帯域幅を必要としない場合、あるいは接続ニーズへの対処にパートナーとの連携を希望の場合
- トラフィックに 10 Gbps や 100 Gbps の回線が必要ない場合（最大50 Gbpsに対応）
- お客様ネットワークと Google ネットワークの間の接続は暗号化されない

### Dedicated Interconnect（専用接続）
- Google への直接接続（オンプレミス ネットワークと Google のネットワークを物理的に直接接続）。トラフィックは、公共のインターネットではなく、ネットワーク間で直接流れる。50 Mbps～50 Gbps の可変 VLAN 容量を持つ **10 Gbps または 100 Gbps** の回線。
- スループットが高い Google Cloud へのエンタープライズ クラスの接続が必要な場合
- 高い帯域幅が必要な場合
- **最も要求の厳しいデータニーズを満たすため**にスケーリング（ただし、高コスト）
- お客様ネットワークと Google のネットワークの間の接続は暗号化されない。

## ピアリング
**G Suite アプリケーションにアクセスする必要がある場合**。G Suite アプリケーションにアクセスする必要がない限り、Google Cloud への推奨のアクセス方法は、**Dedicated Interconnect** または **Partner Interconnect**。
### キャリア ピアリング
- **サービス プロバイダを使用**して G Suite などの Google アプリケーションにアクセス。

### ダイレクト ピアリング
- **お客様のオンプレミス ネットワーク**から G Suite などの Google アプリケーションにアクセス。

# 参考
- [Google Cloud ハイブリッド接続](https://cloud.google.com/hybrid-connectivity?hl=ja)
- [Dedicated Interconnect と Partner Interconnectの比較](https://cloud.google.com/network-connectivity/docs/how-to/how-to-choose?hl=ja#compare_solutions)
- [キャリア ピアリングと Cloud Interconnectの比較](https://cloud.google.com/network-connectivity/docs/how-to/how-to-choose?hl=ja#cp-compare)
- [ダイレクト ピアリングと Cloud Interconnectの比較](https://cloud.google.com/network-connectivity/docs/how-to/how-to-choose?hl=ja#dp-compare)
パソコンのブラウザ（Chrome、Safari、Firefox、Edge）で閉じてしまったタブを簡単に復活させる方法（Windows、Macとも）

<p>パソコンのブラウザ（Chrome、Safari、Firefox、Edge）で閉じてしまったタブを簡単に復活させる方法の紹介です。（Windows、Macとも）</p><p>間違ってタブを閉じてしまうのはよくあることでしょう。次の方法で簡単に復活させることができます。</p><h1>方法</h1><p>ブラウザ（Chrome、Firefox、Safari、Edge）で共通の方法です。&nbsp;</p>&nbsp;<p>ブラウザ上で</p><blockquote><p>Windowsでは［Ctrl］＋［Shift］＋［T］キー</p><p>Macでは［command］＋［Shift］＋［T］キー</blockquote><p>を押します。</p></div><p>&nbsp;</p><p>すると閉じたタブが復活します！！</p><p>&nbsp;</p><p>押す前<BR><a href="https://blog-imgs-115.fc2.com/t/e/a/teapipin/up_180602-0001.png"><img title="180602 0001" src="https://blog-imgs-115.fc2.com/t/e/a/teapipin/up_180602-0001.png" alt="180602 0001" width="598" height="372" border="0"></a></p><p>　↓</p><p>押した後<BR><a href="https://blog-imgs-115.fc2.com/t/e/a/teapipin/up_180602-00041.png"><img title="180602 00041" src="https://blog-imgs-115.fc2.com/t/e/a/teapipin/up_180602-00041.png" alt="180602 00041" width="598" height="372" border="0"></a></p><p>&nbsp;</p><p><span style="color:#ff2600;">続けて同じことをすると、それまでに閉じたタブが閉じた順に復活します！</span></p><p>簡単ですね！</p><p>便利なので覚えておきましょう～♪</p>