OmniAICreator/Qiita-1.07M huggingface dataset:
音のあるプッシュ通知を実装してみた(React.js)

## はじめに
最近、個人開発でプッシュ通知を実装して、音をつけたいなと思ったので実装してみました。プッシュ通知はNotificationAPIを使っているので、残念ながらサイトを開いてないと通知されません。ServiceWorkerとweb-push使って、バックグラウンドで実装できるようにしたいと思ってます。
React使ってます。

参考：
[通知APIの使用](https://developer.mozilla.org/ja/docs/Web/API/Notifications_API/Using_the_Notifications_API)
[Web Audio API](https://developer.mozilla.org/ja/docs/Web/API/Web_Audio_API)

効果音探しに使わせていただきました↓
[フリー音楽素材魔王魂](https://maoudamashii.jokersounds.com/list/se6.html#google_vignette)

## ソースコード

説明は簡単にコメントで記述しました！

```tsx:src/App.tsx
import { useEffect, useState } from "react";

function App() {
  const [hasSound, setHasSound] = useState(true);
  useEffect(() => {
    if ("Notification" in window) {
      // 通知が許可されていたら早期リターン
      const permission = Notification.permission;
      if (permission === "denied" || permission === "granted") {
        return;
      }
      // 通知の許可を求める
      Notification.requestPermission().then(() => new Notification("テスト"));
    }
  }, []);

  const handlePushNotif = () => {
    if ("Notification" in window) {
      const notif = new Notification("こんにちは！");
      // プッシュ通知が表示された時に起きるイベント
      notif.addEventListener("show", () => {
        // 状態によって音の有無を変える
        if (hasSound) {
          // 音再生
          new Audio("./push.wav").play();
        }
      });
    }
  };

  return (
    <div>
      <button onClick={handlePushNotif}>PUSH</button>
      <button onClick={() => setHasSound((prev) => !prev)}>
        {hasSound ? "音なしにする" : "音ありにする"}
      </button>
    </div>
  );
}

export default App;

```

初回アクセス時は下の画像のようなものが出てくるので許可するとプッシュ通知が出るようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/697143/9b2cc835-f50e-d4b8-8983-4ab123419b94.png)


`creact-react-app`で作られた`App.tsx`を変えただけの簡単なコードです。
押したらプッシュ通知を出すボタンと音の有無を切り替えるボタンが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/697143/d9b04819-3e00-f8a8-4b3b-873f1c5aee23.png)

一応完成のコード公開したので実際に試したい場合はクローンしてみてください！
https://github.com/NozomuTsuruta/simple-notification-audio

## 終わりに
ここまで読んでいただきありがとうございました！少しでもお役に立てれば嬉しいです
また、「もっといい方法あるよ」だったり、「こういう面白い技術があるよ」などなど気軽にコメントやTwitterで絡んでくれたりすると嬉しいです！
いろいろな技術を触りながら日々精進していきます！
Next.jsのプロジェクトにTypeScriptを導入する方法

[Next.jsの公式チュートリアル](https://nextjs.org/learn/excel/typescript/create-tsconfig)にそって進めます
# 導入手順

①プロジェクトルートにtsconfig.jsonを追加。

```
$ touch tsconfig.json
```
②TypeScriptのパッケージをインストール。

```
# If you’re using npm
$ npm install --save-dev typescript @types/react @types/node

# If you’re using Yarn
$ yarn add --dev typescript @types/react @types/node
```

③ローカルの開発サーバの際立ち上げ。ここで、tsconfig.jsonの中身が記述され、next-env.d.tsが追加されます。

```
$ npm run dev or yarn dev
```

④JS ファイルを TS ファイルに変換します。

```zsh
$ find pages -name "_app.js" -or -name "index.js" | sed 'p;s/.js$/.tsx/' | xargs -n2 mv & \
  find pages/api -name "*.js" | sed 'p;s/.js$/.ts/' | xargs -n2 mv
```

以上です。
Ruby On Rails でのHP作成メモ

##目的

自分用のRailsでHello Worldの表示。今回はmacでの環境設定。
Windowsは次回。。。。

##開発環境

macOS Big Sur
Visual Studio Code

##バージョン

Rails 5.2.3
Ruby 2.7.0
rbenv 1.1.2
Bundler 2.1.4

##初期設定

######1 . [Homebrew][link-1]のインストール
[link-1]:https://brew.sh/index_ja
```:terminal
$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```

######2 . rbenvのインストール
Rubyのバージョン管理ツールrbenvのダウンロード

```:terminal
$ brew install rbenv ruby-build
```

######3-1 . Rubyのインストール
最新版（2.7.0）をインストール

```:terminal
$ rbenv install --list
$ rbenv install 2.7.0
$ rbenv global 2.7.0
$ ruby -v
```
#####3-2 . PATHを通す

```:terminal
$ touch ~/.bash_profile # ホームディレクトリに.bash_profileを作成
$ touch ~/.bashrc       # ホームディレクトリに.bashrcを作成
$ echo '# rbenv' >> ~/.bash_profile
$ echo 'export PATH=~/.rbenv/bin:$PATH' >> ~/.bash_profile
$ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
$ source ~/.bash_profile
```

######4 . Bundleのインストール
Railsのバージョン管理ツールのダウンロード

```:terminal
$ gem install bundler
$ bundle -v
```
#####5 . Railsのインストール

```:terminal
$ gem install -v 5.2.3 rails
$ gem list rails

*** LOCAL GEMS ***

rails (6.0.2.1, 5.2.3)
rails-dom-testing (2.0.3)
rails-html-sanitizer (1.3.0)
sprockets-rails (3.2.1)
```
######6 . データベースのインストール

sqlite3

```:terminal
$ gem install sqlite3 @[バージョン]
```

postgresql

```:terminal
$ brew install postgresql @[バージョン]
```
MySQL

```:terminal
$ brew install mysql @[バージョン]
$ mysql.server start
```

######7 . プロジェクト作成・導入〜起動
```:workspace
$ rails _5.2.3_ new my-app
```

```:workspace/my-app
$ cd my-app
$ bundle install --path vendor/bundle
$ rails server
````

<font color="red">→ Gemfileからインストールする方法もある

##応用

#####bootstrap4の導入

```ruby:Gemfile
gem 'bootstrap', '~> 4.3.1'
gem 'jquery-rails'
```

```:my-app
$ bundle install
```

```ruby:app⁩/assets⁩/⁨javascripts/application.js⁩
//= require jquery3
//= require popper
//= require bootstrap-sprockets
```
→ 文末には記述しない

```ruby:app⁩/assets⁩/⁨stylesheets/application.css→application.scss（rename）
@import "bootstrap";
```

##ルーターとMVC開発

```:my-app
$ rails g controller users index
```
#####ルーター
```:my-app/config/routes.rb
Rails.application.routes.draw do
  get 'users/index'
  # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end
```
#####①モデル
```ruby:my-app/app/models
$ 省略
```

#####②コントローラー

```ruby:my-app/app/controllers/users_controller.rb
class UsersController < ApplicationController
  def index
    @message = 'Hello World'
  end
end
```

#####③ビュー
```ruby:my-app/app/views/users/index.html.erb
<div class="row">
<div class="col-1">
</div>
<div class="col-4">
<h1><%= @message %></h1>
</div>
</div>
```

#結果
![スクリーンショット 2021-01-30 9.51.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/522384/15e2593c-5b81-1d2c-4ef5-ca7f56895165.png)

##おまけ

#####復元するとき
```:my-app
$ bundle update
```

#####バックグランドで残っているとき

```:terminal
$ rm ./tmp/pids/server.pid //process idを消す
```
【Swift】構造体まとめ

#はじめに
この記事では、Swiftで多用する構造体についてまとめました。
⚠️当方初学のため認識違いがある可能性大です
誤りを見つけた際はコメントにて指摘していただけると幸いです🙇‍♀️🙇‍♂️


#参考
この記事は、以下の情報を参考にして執筆しました。

- [Swift実践入門](https://www.amazon.co.jp/%EF%BC%BB%E5%A2%97%E8%A3%9C%E6%94%B9%E8%A8%82%E7%AC%AC3%E7%89%88%EF%BC%BDSwift%E5%AE%9F%E8%B7%B5%E5%85%A5%E9%96%80-%E7%9B%B4%E6%84%9F%E7%9A%84%E3%81%AA%E6%96%87%E6%B3%95%E3%81%A8%E5%AE%89%E5%85%A8%E6%80%A7%E3%82%92%E5%85%BC%E3%81%AD%E5%82%99%E3%81%88%E3%81%9F%E8%A8%80%E8%AA%9E-WEB-PRESS-plus-ebook/dp/B086VVQ3DJ/ref=sr_1_1?adgrpid=56053864951&dchild=1&gclid=CjwKCAiAo5qABhBdEiwAOtGmbtEdp97n9eQCgn4VQpffZut8DhCnND9sXQBMoTecHwls0LKIy4l-cxoCCZwQAvD_BwE&hvadid=338518511220&hvdev=c&hvlocphy=1009155&hvnetw=g&hvqmt=e&hvrand=13959960213026669174&hvtargid=kwd-306987067810&hydadcr=27263_11561109&jp-ad-ap=0&keywords=swift%E5%AE%9F%E8%B7%B5%E5%85%A5%E9%96%80&qid=1611048736&sr=8-1&tag=googhydr-22)


#構造体とは
構造体とは、値型の一種であり、ストアドプロパティの組み合わせによって一つの値を表す。


#定義方法
構造体の定義にはstructキーワードを使用する。

```struct 構造体名 {
構造体の定義
}
```

プロパティやメソッド、イニシャライザなどの型を構成する要素は構造体で全て利用可能で、{}内に定義できる。


#ストアドプロパティの変更による値の変更
構造体のストアドプロパティを変更することは、構造体を別の値に変更することであり、その時は構造体が入っている変数や定数への再代入が必要となる。
ただし、定数に代入されている場合ストアドプロパティは変更できない。

###メソッド内のストアドプロパティの変更
構造体のストアドプロパティの変更は再代入を必要とするため、ストアドプロパティの変更を含むメソッドにはmutatingキーワードが必要。
ストアドプロパティの変更を含んでいるにもかかわらずmutatingキーワードがついていない場合、コンパイルエラーとなる。


#メンバーワイズイニシャライザ
型のインスタンスは初期化後にすべてのプロパティが初期化されている必要がある。
独自にイニシャライザを定義して初期化の処理を行うこともできるが、構造体では自動的に定義されるメンバーワイズイニシャライザというイニシャライザを利用できる。
メンバーワイズイニシャライザは、型が持っている各ストアドプロパティと同名の引数をとるイニシャライザ。
また、ストアドプロパティが初期化式とともに定義されている場合、そのプロパティに対応するメンバーワイズイニシャライザの引数はデフォルト引数を持ち、呼び出し時の引数の指定を省略できる。
[GitHub] 基本の使い方

#環境
macOS

Gitのインストール、
GitHubのアカウントの作成
が済んでいることが前提です。

#リモートリポジトリを作成する
GitHubにログインし、右上の `+` ボタンから `Create Repository` をクリックします。

`Repository name` にリポジトリ名を決めて入力します。
次にリポジトリの種類を `Public` か `Private` を選択します。
（ リポジトリの説明や使い方を記述するREADMEファイルを事前作成しておく場合は　`Initialize this repository with:` の `Add a README file` にチェックを入れます。）
そして、一番下の `Create repository` をクリックしてリポジトリを作成します。

#ローカルリポジトリを作成する
今回は `tweet_app` というディレクトリにローカルリポジトリを作成します。（まだGitHubにアップするファイルがない場合はディレクトリを作成し、 `cd` で作成したディレクトリに移動します。）
 `tweet_app` には既に　`index.html` などのファイルが保存されています。
 `tweet_app` ディレクトリに移動して `git init` コマンドを入力します。


```
$ cd tweet_app

$ git init
```

#gitのインデックスに追加する
`git add 移動したいファイル名` のコマンドでファイルの作成、変更、削除をインデックスに追加します。
インデックスとは、リポジトリにコミットする準備をするために変更内容を一時的に保存する場所のことです。
(`cd` で作成したディレクトリに移動してから実行します。）

```
$ git add index.html
```


#ローカルリポジトリにコミットする
`git commit -m "コミットメッセージ"` で先ほどインデックスに追加したファイルをコミットします。
`コミット（commit）` とは、ファイル追加や変更の履歴をリポジトリに記録することです。
`コミットメッセージ` には簡潔に変更内容などを書きます。

```
$ git commit -m "add new file"
```

ファイルが追加されているか確認するコマンドです。
gitの管理下にあるファイルが表示されます。

```
$ git status
```

次に、リモートリポジトリの情報を `git remote add origin リモートリポジトリのアドレス` で追加します。この情報は、GitHub上に表示されるリモートリポジトリのアドレスです。(アドレスは緑のCodeボタンを押すと表示されます）

```
$ git remote add origin https://github.com/,,,/,,,.git
```

#ローカルリポジトリをプッシュしてリモートリポジトリへ反映させる
`git push origin master` でプッシュします。

```
$ git push origin master
```

GitHubのユーザ名とパスワードを入力すると、プッシュしてリモートリポジトリへ反映させることに成功します。
PuppeteerでローカルのHTMLファイルをData URI Schemeとして読み込む

Puppeteerの`page.goto()`はhttpプロトコルやfileプロトコルなどの他、[Data URI scheme](https://ja.wikipedia.org/wiki/Data_URI_scheme)文字列も引数にできる。

下記のようなHTMLファイルを用意しておき

```html:test.html
<html>
	<head>
		<meta charset="utf-8"/>
	</head>
	<body>
		Data URI schemeを表示できます
	</body>
</html>
```

同じディレクトリのJavaScriptからこのように読み込むと、

```javascript
import fs from 'fs/promises';
import puppeteer from 'puppeteer';

const html = "./test.html"
const buffer = await fs.readFile(html)

const browser = await puppeteer.launch({ headless: false, });
const page = (await browser.pages())[0];
await page.goto(`data:text/html;base64,${buffer.toString("base64")}`);
// ...
browser.close();
```

Chromiumで開いてくれる。
実運用ではまず使わないけど、ちょっとした確認をするときに便利だったりする。

なお、日本語が含まれていると、高確率で文字化けするので、charset指定をしておくのが無難。[^why-mojibake]

[^why-mojibake]: ファイルをそのままChromiumで開いたら文字化けしなくても、なぜかData URI schemeだと化ける。なぜだ？
GitHubのWikiに画像が表示されないときに確認すること

GitHubのWiki機能、便利ですよね。でも、画像が上手く表示されないこともあります。

画像が表示されないときには以下の点を確認しましょう。

- パスが正しいか
- 画像が破損していないか
- 画像のファイル名に日本語が含まれていないか
- imgタグではなくMarkdown記法を使っているか
- 画像をGitHubにPushしているか

特に、2つ目の「画像のファイル名に日本語が含まれていないか」は重要です。画像が表示されなくて困っていて、ネットで調べて出てきたものを色々試しても効果がなかったとき、これが原因でした。画像のファイル名に日本語が含まれていると表示されません。
【JavaScript】スマホ判定する方法

#プログラミング勉強日記
2021年1月29日
JavaScriptでデバイスがスマホかどうか判定する方法について簡単にまとめる。

#UserAgentから判定する
　UserAgentがiPhoneまたはAndroidとMobileを含む場合はスマホと判定できる。接続してきたユーザー情報を知るためにnavigatorオブジェクトのUserAgentを使用する。navigatorオブジェクトはいくつもの端末やブラウザの情報が格納されていて、プロパティとして情報を取得できる。

```:userAgentに含まれている情報の例
Mozilla/5.0 (iPhone; CPU iPhone OS 6_0 like Mac OS X) AppleWebKit/577.01 
(KHTML, like Gecko) Version/6.8 Mobile/11A111 Safari/9788.91
```

```js
function isSmartPhone() {
  // UserAgentからのスマホ判定
  if (navigator.userAgent.match(/iPhone|Android.+Mobile/)) {
    return true;
  } else {
    return false;
  }
}
```

#デバイスの画面幅から判定する
　window.matchMedia()関数を使うことで、デバイス画面幅を判定できる。この方法はスマホを判断するのではなく、画面幅によってUIを変更したいときに使うのが望ましい。


```js
function isSmartPhone() {
  // デバイス幅が640px以下の場合にスマホと判定する
  if (window.matchMedia && window.matchMedia('(max-device-width: 640px)').matches) {
    return true;
  } else {
    return false;
  }
}
```

#サンプルプログラム

```html
<html>
<head>
<title>スマホ判定</title>
</head>
<body>

<p>使用中の端末：</p>
<p id="Terminal"></p>

<script type="text/javascript">
	let tarminal = document.getElementById('Terminal')
	let msg = ""
	let ut = navigator.userAgent;

	if(ut.indexOf('iPhone') > 0 || ut.indexOf('iPod') > 0 || ut.indexOf('Android') > 0 && ut.indexOf('Mobile') > 0){
		msg = "SmartPhon";
	}else if(ut.indexOf('iPad') > 0 || ut.indexOf('Android') > 0){
		msg ="Tablet";
	}else{
		msg = "Personal Computer";
	}

	tarminal.textContent = msg
</script>

</body>
</html>
```

実行結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642821/6b1613f5-55f8-bb86-2a81-85792c2b0ffe.png)


#参考文献
[JavaScriptでスマホ判定する2つの方法](https://www.site-convert.com/archives/2188)
[JavaScriptでアクセス元の端末がスマホかどうか判定する方法を現役エンジニアが解説【初心者向け】](https://techacademy.jp/magazine/24013)
React でソフトウェアキーボードを作る

react 2年目がいろいろ学んだことやハマったことの記録。
今回は、「ランダムにキー配置するソフトウェアキーボード」を作った時のお話。

## キー配列をシャッフル
キーボードは数字のみと英数字記号の２タイプ。さらにキー配置そのものを変えるものと、あるグルーピング単位で配置を変えるという仕様のキーボードを作ります。
ランダム→配列をシャッフルするから、Array.shuffle() かな？と思いましたが・・・ありませんでした。
みなさん自作なさってるようなのでそれについては真似して作りました。

続けてシャッフル対象のキー配列を作成します。まず「数字のみ」タイプから。
数字のみのほうはキー配置そのものを変える仕様のキーボードです。
もう１つのタイプでも数字は使うので、1〜9の数字と0の配列を１つ別に作っておきます。
数字タイプの、いわゆる10キーは３列４行の配置でレイアウトしたいため、ダミーの空文字を２つ加えて12個のキーを作り、シャッフルします。
シャッフルするタイミングはキーボードを開く時のみにしたいため、depsは未指定にします。

```tsx
const numbers: string[] = React.useMemo(() => {
  return [...Array.from({length: 9}, (_, i) => (i + 1).toString()), '0'];
}, []);

const tenkeys: string[] = React.useMemo(() => {
  return shuffle([...numbers, '', '']);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
```

## グループ配列をシャッフル

残りのキーボードは「英字」「数字」「記号」のグルーピング単位で配置を変えます。
例えば「数字」「英字」「記号」とか、「記号」「英字」「数字」とか、そういう配置換えです。
この場合だと、３つの数字をシャッフルすればよいだろう、ということで２次元配列を作成してみました。
こちらも10キーと同様、シャッフルするタイミングは開くときのみです。

```tsx
const alphabets: string[] = 'ABCDEF...'.split(''); // アルファベット文字列は省略してます
const symbols: string[] = '\"#$%...'.split(''); // 記号文字列も省略してます

const charkeys: stinrg[][] = React.useMemo(() => {
    return [[...numbers], [...alphabets], [...symbols]];
}, [numbers, alphabets, symbols]);

const groups: number[] = React.useMemo(() => {
  return shuffle([...Array(charKeys.length).keys()]);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
```

実際の10キーのキーボードはこんな感じで作ってみました。

```tsx
const tenKeyboard = React.useMemo(() => {
  return (
    <>
      <div className="tenkey">
        <div className="fixed">
          {tenkeys.map((key, index) => (
            <div className="keycell" key={index} onClick={() => onClick(key)}>
              {key}
            </div>
          ))}
        </div>
      </div>
    </>
  );
}, [tenkeys, onClick]);
```

英数字記号のほうも同様な感じで、ただしこちらは2次元配列のため2回ぐるぐるまわします。

```tsx
const alphanumKeybord = React.useMemo(() => {
  return groups.map((key, i) => {
    const charKey = charKeys[key];
    return (
      <React.Fragment key={i}>
        <div className="keySection">
          {charKey.map((key, index) => (
            <div className="keycell" key={index} onClick={() => onClick(key.toString())}>
              {key}
            </div>
          ))}
        </div>
      </React.Fragment>
    );
  });
}, [keyboards, charKeys, onClick]);
```

## シャッフルしまくる

今回のハマりどころは、メモ化のdeps指定でした。
初めはあまり深く考えずに、メモ化してeslintに言われるままdepsに影響する変数を書き込んでました。
すると、キーをクリックするたびにシャッフルが走ってしまうキーボードが出来上がってしまいました。

シャッフルは最初の１回だけなのだから、ということで前述した空配列指定になったわけです。ただしこのままだとeslintに怒られますので、無効化にするコメントも一緒に記載します。

メモ化はどのタイミングでメモの内容を書き換えるべきか？をよく考えて使わないといけない、と勉強した作業となりました。
Next.js + Typescript + TailwindCSSのつまずかない環境構築

# Next.jsのプロジェクトの作成
Next.jsのプロジェクトの作成

```
> npx create-next-app MyApp
```

# Typescript
## Typescriptのインスコ

```
> touch tsconfig.json 
> yarn dev
```

yarn devするとtsconfig.jsonあるのにts関連のパッケージないよ！って言われるので
言われた通りのパッケージをインスコ

_app.jsとindex.jsを_app.tsx,index.tsxに変える

```_app.tsx
import "../styles/globals.css";
import { AppProps } from "next/app";

export default function MyApp({ Component, pageProps }: AppProps) {
  return <Component {...pageProps} />;
}
```

index.tsxは自動生成されるもの消して終わり

# TailwindCSS
## TailwindCSSのインスコ

```sh
> yarn add tailwindcss@latest postcss@latest autoprefixer@latest postcss-preset-env
> touch postcss.config.js
> npx tailwindcss init --full // fullにするとstyle全部ぶっ込んでくれる
```

## 設定ファイル書き換え

tsxファイルに適用させる設定を書く

```tailwind.config.js
// eslint-disable-next-line @typescript-eslint/no-var-requires
const colors = require("tailwindcss/colors");

module.exports = {
  + purge: ["./pages/**/*.tsx", "./components/**/*.tsx", "./public/**/*.html"],
  presets: [],
  darkMode: false, // or 'media' or 'class'
  theme: {
      // 略
```

```postcss.config.js
module.exports = {
    plugins: { tailwindcss: {}, "postcss-preset-env": {} },
  };
```

## styleの適用
style/global.cssを書き換える

```style/global.css
/* ./styles/globals.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
```

# test用ボタン

これにstyleが適用されて表示できたら完了

```html
<button id="sendMoneyButton" className="px-4 py-1 text-sm text-purple-600 font-semibold rounded-full border border-purple-200 hover:text-white hover:bg-purple-600 hover:border-transparent focus:outline-none focus:ring-2 focus:ring-purple-600 focus:ring-offset-2">Send</button>
```
ActionView::Template::Error (Webpacker can't find application.css）で沼にハマった時の解決方法

##動作環境


- Ruby 2.6.6
- Rails 6.1.0
- Docker 20.10.2
- Heroku

##経緯
Railsでアプリを作っており、Herokuにデプロイしたが、その際にHerokuでエラーが発生してしまった。

##エラー内容
rails_12factorを追加して、herokuでもrailsのログが見れるようにしている。

```
ActionView::Template::Error (Webpacker can't find application.css in /myapp/public/packs/manifest.json. Possible causes:
1. You want to set webpacker.yml value of compile to true for your environment
2021-01-25T01:15:35.492764+00:00 app[web.1]: unless you are using the `webpack -w` or the webpack-dev-server.
2021-01-25T01:15:35.492765+00:00 app[web.1]: 2. webpack has not yet re-run to reflect updates.
2021-01-25T01:15:35.492765+00:00 app[web.1]: 3. You have misconfigured Webpacker's config/webpacker.yml file.
2021-01-25T01:15:35.492766+00:00 app[web.1]: 4. Your webpack configuration is not creating a manifest.
```

##解決方法
これは__application.cssをwebpackerで管理できてないことが原因__で発生したエラーであった。

試しにエラーが出ていたviewファイルを確認してみる。

```ruby:application.html.erb
<%= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
```

そういえばtailwindを導入した際に、記事の内容に従ってstylesheet_linkからpackに書き換えたような、、、

```ruby:application.html.erb
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
```
中身を書き換えたら無事に本番環境でデプロイできました！

どうやらstylesheet_pack_tagをつかうと、webpackerからスタイルシートを呼び出すみたいでした。
自分の場合はcssをsprocketsで管理していたので、stylesheet_link_tagを使う必要があったようでした。

エラー文のPossible causes以降の文章が答えだと思って、ずっと頭を悩ませていましたが全く別のところに原因が存在していました。
まずはじめに、__「webpackerでapplication.cssが見つからない」__というところに注目して取り組んでいたらもっと苦労せずに解決できていたと思います。

##最後に
今回のエラーを経て、
エラー文の怪しいところに注目して解決をするだけではなく、しっかりとエラーの本質を理解して解決に当たるということが重要であると感じました。

しかし、ローカル環境では何の問題もなかったのになぜ本番環境のみでエラーが発生したんだろう、、、？
Laravel SailでM1 MacBookのDocker開発環境構築

# 前置き
ご購入検討中のエンジニアさん
結論、“まだ”M1のMacはおすすめできません。
VagrantやVirtualBox、何を入れるにも一苦労。
導入できたとしても仮想環境は起動しない・・・。
（ARM対応してないものが多い）

私はかれこれ2週間近く試してやっとLaravelが動く方法を見つけました。
PHP + MySQL(mariaDB)使いたい方は参考になると思います。
私が実際に試して導入できた方法をご案内します。

# LaravelSail導入
Laravel公式のDocker 開発環境構築ツール使います。
ターミナルからコマンドを実行。

```
curl -s https://laravel.build/sample-app | bash
```

[sample-app]の部分はお好みで。

## 起動します

```
cd sample-app
./vendor/bin/sail up
```

### うまく行かない・・・ので

## docker-compose.ymlの1箇所修正

```
image: 'mysql:8.0'
```

の部分を↓

```
image: 'mariadb'
```

### 再トライで、無事に起動

```
./vendor/bin/sail up
```

以上です。

# まとめ
今まではHomestead使っていたので、
M1 MacではVirtualBoxとVagrantが動かないのがわかったとき、めっちゃ焦りました。

いろいろ調べてLaravelSailというのを見つけて、初めて導入しました。
かなりいいです。Laravel開発のスタンダードになりそうな予感。

よし、開発すすめるぞー

開発中のツーリングアプリ
https://touringbook.com/
俺の書いたPythonのdiscordbotのコード！

#中身
```Python:main.py
import discord
import os
import asyncio

# 接続に必要なオブジェクトを生成
client = discord.Client()

version = "1.0"
noeconsole=input

@client.event
# botが起動したときに動作する処理
async def on_ready():
    # 起動したらログイン通知が表示される
    print('ログインしました')
    print("erroがないか確認してください")
    await client.change_presence(activity=discord.Game
    (name="versionは"+(version)+"です。", ))
    await client.get_channel(782243365982175252).send("bot is online")

# botがメッセージを受信したときに動作する処理
@client.event
async def on_message(message):
    if message.author.id == 302050872383242240:
      if 'https://disboard.org' in message.embeds[0].description:
        await message.channel.send('べ、別にbumpしてくれたってうれしくねーぞ///')
      else:
      
        await message.channel.send('あれれぇ？時間わからないのかなぁ？') 
      
    # メッセージ送信者がBotだった場合は無視する
    if message.author.bot:
        return
    # ans のメッセージに対し ans と送信する
    if message.content == 'やっほー':
      await message.channel.send("あそぼ")
    if message.content == 'ねえねえ':
      await message.channel.send('どうした？')
    if message.content == 'おやすみ':
      await message.channel.send('おやすみー')
    #以下にコードを書いていく 
    if message.content.startswith("p."): #ここは自由に変えてね
        query = message.content[2:].split(" ") #空白で区切る
        if query[0] == "timerh": #ここも自由にかえてね
            await message.channel.send("timer start")#ここも自由に変えてね
            if int(query[1]) > 60:
              await message.channel.send('1時間以上は設定できません！')#ここも（ｒｙ
            else:
              await asyncio.sleep(int(query[1])*60) #分を取得&60倍
              await message.channel.send(f"{int(query[1])}分経ちました") #こ（ｒｙ
      #ここから下はおんなじ感じのコード
        if query[0] == "timer": #コマンドを判定
            await message.channel.send("timer start")
            if int(query[1]) > 3600:
              await message.channel.send('1時間以上は設定できません！')
            else:
              await asyncio.sleep(int(query[1])) #分を取得&60倍
              await message.channel.send(f"{int(query[1])}秒経ちました") #内容を変更

        elif query[0] == "say": #コマンドその2
            await message.channel.send(query[1])
        else:
            await message.channel.send(">>> 不明なコマンドです。")
    

client.run('#ここにbotのトークン入れてね')
``` 

#宣伝
「プログラミングがしたい！」「わからないところがある！」って人は
[Glanz code](https://discord.gg/c8vrrg6T8j)
に参加してね！
AWS ECRへのログイン方法

[こちら](https://www.youtube.com/watch?v=zs3tyVgiBQQ&t=110s)を参考にDockerイメージをEC2にデプロイしようと、
`aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin アカウントID.dkr.ecr.ap-northeast-1.amazonaws.com`
のコマンドをターミナルで実行
1. 以下のようなエラーがでた。

`command not found aws`    
`Cannot perform an interactive login from a non TTY device`
まずAWSのコマンドが使えるようになっていないらしい。

２. [StackOverflow](https://stackoverflow.com/questions/60583847/aws-ecr-saying-cannot-perform-an-interactive-login-from-a-non-tty-device-after)によると「AWS CLI version 2」というのをインストールしないといけないらしい。そのために、[こちらのページ](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2-mac.html#cliv2-mac-install-confirm)の指示に従って、以下のコマンドをターミナルで実行する。
`$ curl "https://awscli.amazonaws.com/AWSCLIV2.pkg" -o "AWSCLIV2.pkg"`
`$ sudo installer -pkg AWSCLIV2.pkg -target /`
`$ curl "https://awscli.amazonaws.com/AWSCLIV2.pkg" -o "AWSCLIV2.pkg"`
`$ sudo installer -pkg ./AWSCLIV2.pkg -target /`

3.AWSに認証情報を登録する
再度ターミナルで
`aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin アカウントID.dkr.ecr.ap-northeast-1.amazonaws.com`
を実行したら、
`Unable to locate credentials. You can configure credentials by running "aws configure".`
というエラーがでた。[こちら](https://aws.amazon.com/jp/premiumsupport/knowledge-center/s3-locate-credentials-error/)によると、認証情報が登録されていないため、それを登録する必要があるらしい。
このページの指示通り、`aws configure list`をターミナルで実行すると、以下のようにでて、確かに認証情報がない。
![スクリーンショット 2021-01-29 21.29.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/637360/d8394b78-4be3-7176-fad6-77a01e150daa.png)

[こちら](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html)に飛び、認証情報を登録する

この時点でAWSのIAMユーザのアカウントがなければ[こちら](https://docs.aws.amazon.com/IAM/latest/UserGuide/getting-started_create-admin-group.html)から作る。このページの「Creating an administrator IAM user and group (console)」の項目の最後までやればOK。
ここまでできたら、[このページ](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html)の「Access key ID and secret access key」項目の指示に従ってAccess key と Secret access key を作成する。作成したそれらはメモっておく。
次に、そのページにあるように、`aws configure`をターミナルで実行する
![スクリーンショット 2021-01-29 21.38.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/637360/24e861c5-71d6-7783-5f05-6499720ee3c3.png)
「Access Key Id」と「Secret Access Key」に先ほど作成したものを入れる。
「Default region name」には「ap-northeast-1」を入れる
「Default out put format」にはjsonを入れる
これで認証情報が登録完了

4.再度
`aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin アカウントID.dkr.ecr.ap-northeast-1.amazonaws.com`
を実行
`Login Succeeded`
がターミナルに表示！
Pythonにおけるリストの高速処理

pythonにおいて、リストを利用する機会は多々ありますが、
リストの生成、検索においてどのように処理するのが一番速いのかを調べました。

## 環境
Python 3.7.8

## 生成

まずはじめに、こんなプログラムを用意しました。
リストの生成にかかる平均秒数を計測する簡単なプログラムです。

```python
import random
from time import time

#### List Tests ####

# テスト回数
num_tests = 25

# テスト回数分の測定値を保存するリスト
timeList = []

for i in range(0, num_tests):

    # 10万まで要素を生成
    end = 100_000

    # 開始時刻
    startTime = time()

##### リスト生成プログラム #########################
    listComp = [i for i in range(0, end)]
##################################################

    # 終了時刻
    endTime = time()
    
    # 測定値保存
    timeList.append(endTime - startTime)

# テストの平均値[s]
avg = sum(timeList) / len(timeList)
print(avg, '[s]')
```

リスト生成プログラムの所を書き換えて計測していきましょう。

### 内包表記
まずは内包表記の場合です。

```python3
listComp = [i for i in range(0, end)]
```
結果

```shell
0.006156406402587891 [s]
```

### appendメソッド

次はappendメソッドです。リスト生成プログラムを書き換えましょう。

```python3
append_list = []
for i in range(0,end):
  append_list.append(i)
```
結果

```shell
0.01742997169494629 [s]
```

### 初期化済みリスト
最後は、指定サイズ分要素を用意しておいて、
そこに値を代入しましょう。

```python3
preAllocate = [0] * end
for i in range(0, end):
  preAllocate[i] = i
```
結果

```shell
0.014672718048095702 [s]
```

### 生成のまとめ

リスト生成の計測値

| 方法 | 時間[ms] |
|:-:|:-:|
| 内包表記 | 6.16 |
| appendメソッド | 17.42 |
| 初期化済みリスト | 14.67 |

内包表記 > 初期化済みリスト > append の順で速いのが分かると思います。
生成する要素数を変えてみても、**内包表記が一番速い**のは変わりませんでした。

## 検索

次は検索の計測をしてみます。
先ほどのプログラムを少し書き換え、
1から30000の数値がランダムに入る、30000の要素を持つ配列を2つ用意して検索してみます。

```python
import random
from time import time

# Initialize Random
random.seed(time())

#### List Tests ####

# テスト回数
num_tests = 3 

# テスト回数分の測定値を保存するリスト
timeList = []

for i in range(0, num_tests):

    # 3万まで要素を生成
    end = 30_000

    # リストの生成
    list_a = [random.randint(1, end) for i in range(0, end)]
    list_b = [random.randint(1, end) for i in range(0, end)]

    # 開始時刻
    startTime = time()

##### リスト検索プログラム #########################
    for i in list_a:
        for j in list_b:
            if i == j:
                break
###############################################

    # 終了時刻
    endTime = time()

    # 測定値保存
    timeList.append(endTime - startTime)

# テストの平均値[s]
avg = sum(timeList) / len(timeList)
print(avg, '[s]')
```

リスト検索プログラムの所を書き換えて計測していきましょう。

### ダブルループ
まずはダブルループの場合です。

```python3
for i in list_a:
    for j in list_b:
        if i == j:
            break
```
結果

```shell
34.66531833012899 [s]
```
### In検索

次はInを使って検索を行ってみましょう。

```python3
for i in list_a:
  if i in list_b:
    continue
```
結果

```shell
7.02125096321106 [s]
```

### Set集合

次は検索する対象をSet集合にして、重複を無くしてみましょう。
Set集合の場合は、ハッシュ値を利用してアクセスするので、
1回の検索に必要な計算量はO(1)。n要素だったらO(n)。

```python3
unique = set(list_b)
for i in list_a:
  if i in unique:
    continue
```
結果

```shell
0.0038799444834391275 [s]
```
爆速:laughing:

### 検索のまとめ

検索の計測値

| 方法 | 時間[s] |計算量[*O*]|
|:-:|:-:|:-:|
| ダブルループ | 34.6653 |*O*(n^2)|
| In検索 | 7.0213 |?|
| Set集合 | 0.0039 |*O*(n)|

やっぱりハッシュを使うSet集合は爆速です。ダブルループの比ではないですね。
in検索だけでもループに比べると1/5くらいになるのが分かります。

リストから値を検索したい場合は、inを使いましょう。
そして、可能な場合はハッシュが使えるSet集合に変換しましょう。

以上 :peach:
vscodeでxdebug3のdocker環境を作る

## はじめに
2020年11月25日にxdebug 3.0.0がリリースされました。
それを知らずにdockerでxdebugの環境を作って、「ブレイクポイントで止まってくれない、なんでやねん」ってなったのでまとめます。

## フォルダ構成
xdebug2からxdebug3に移行のために、編集するのはphp.iniだけですがDockerfilやvscodeのlaunch.jsonの解説もします。
docker-composeは省略。

```
php
├── Dockerfile
└── php.ini
```

## php.ini
xdebug3ではxdebug2と記述方法が異なるようです。

xdebug2のphp.iniのxdebugの設定

```ini
xdebug.remote_host = host.docker.internal
xdebug.remote_autostart = 1
xdebug.remote_connect_back = 0
xdebug.remote_enable = 1
xdebug.remote_handler = "dbgp"
xdebug.remote_port = 9000
```

xdebug3のphp.iniiのxdebugの設定

```ini
xdebug.client_host = host.docker.internal
xdebug.mode = debug
xdebug.start_with_request = yes
xdebug.discover_client_host = 0
xdebug.remote_handler = "dbgp"
xdebug.client_port = 9000
```

| xdebug2 | xdebug3の変更点 |
|:-:|:-:|
| xdebug.remote_host  | xdebug.client_host に置き換え |
| xdebug.remote_autostart  |  xdebug.mode=debug と xdebug.start_with_request=yes で設定 |
|  xdebug.remote_enable | xdebug.mode=debugで設定  |
| xdebug.remote_connect_back | xdebug.discover_client_host に置き換え |
|xdebug.remote_handler|　変更無し|
|xdebug.remote_port|xdebug.client_port に置き換え|

これら以外にも変更点があるので、詳しくはこちらを参照
https://xdebug.org/docs/upgrade_guide


## Dockerfile

```dockerfile
FROM php:7.4-fpm
SHELL ["/bin/bash","-c"]

COPY ./php.ini /usr/local/etc/php/php.ini

RUN apt-get update && \
    apt-get -y install git unzip libzip-dev libicu-dev libonig-dev && \
    pecl install xdebug && \　#xdebugのインストール
    docker-php-ext-enable xdebug  #

WORKDIR /work
```
ポイントは`pecl install xdebug`と`docker-php-ext-enable xdebug`

- 2021年1月29日、現在では`pecl install xdebug`を行うとxdebug3がインストールされます。

- xdebugを使うにはイントールされた、xdebug.soのパスをphp.iniに`zend_extension = パス`を追記して、登録しなければなりません。`docker-php-ext-enable xdebug`のコマンドを叩くと自動でこの作業を行ってくれます。

## launch.json
vscode側の設定になります。

```json
"configurations":[
 {
   "name": "XDebug on docker",
   "type": "php",
   "request": "launch",
   "port": 9000,//php.iniで設定したポート番号
   "pathMappings": {
      // {docker上のdocument root}:{ローカルのdocument root}
      "/work":"${workspaceRoot}/src"
    }
  }
]
```

これをlaungh.jsonの中に追記します。

これでxdebugを動かすための環境ができました。

## 参考にさせて頂いた記事
[Dockerで構築したPHP環境をxdebugでデバッグ（vscode）](https://qiita.com/gigosa/items/90431be7a6a79db78480)
[Xdebug3.0.0がリリースされたので、ver2からの雑な設定コンバート](https://qiita.com/naoyukik/items/ef83fd9f59228694556d)
## 最後に
`"port:9000"`のポート番号はvscodeが開いてるんですね。
xdebugが開いているものと思ってました。
AccessVBAの丸め誤差を即行で応急処置した話

だいぶ前に納品したAccessアプリケーションで、月末に動く**端数**の集計処理が正しくないのでは？とお客様のご指摘。
賃金台帳の合計と突き合わせると確かに違うようで、明細行を電卓で足し合わせた値とも違っている。
Accessのレポート（１月の出勤簿）は労基署に提出予定とのことで、即行で応急処置したので対処方法を共有する。

# デバッグ開始

```vb
total = total + Int(n)
```

において、`total`の値が途中で検算とズレている。

丸めに使っている変数`n`のデータ型を確認する。

```vb
Debug.Print VarType(n)
```

```:結果
5
```

vbDouble の値が返ってきた。Double … つまり**倍精度浮動小数点数型**である。

集計値がズレ始めたタイミングで中身を確認する。

```vb
Debug.Print n, Int(n)
```

```:結果
4      3
```

倍精度浮動小数点数の`4`を、Int関数（小数点以下の値を切り捨てるVBAの組込み関数）に通すと`3`が返ってくる。
この謎が解けた人は、この先は読まなくて良い。

見た目は`4`だが、本当に`4`なのか？を確認する。

```vb
Debug.Print 4 = n
```

```:結果
False
```

どうやら`4`では無いらしい。

`4`との差を確認する。

```vb
Debug.Print 4 - n
```

```:結果
8.88178419700125E-16
```

$ 8.88178419700125*10^{-16} $ という極めて小さな値が返ってきた。
どのくらい小さいかって言うと、地球と太陽間の距離に対して1mmも無いくらいだ。

整理すると以下のようになる。

```vb
Dim n As Double

n = 4 - 8.88178419700125E-16
Debug.Print n, Int(n), Round(n)

n = 4.99999999999999
Debug.Print n, Int(n), Round(n)
```

```:結果
 4                   3               4 
 4.99999999999999    4               5 
```

限りなく`4`に近く、見た目も`4`だが、Int関数を通すと仕様通り`3`が返ってくるので大きな誤差になる、ということのようだ。
このような場合、一般的には、Int関数をRound関数で置き替えるのがセオリーであり、VBAのRound関数は**偶数丸め**であることに留意すれば普通に使うことができる。

しかしながら、特殊な事情で、見た目上の数字（今回の場合は `4`）とその合計を一致させておく必要があれば、苦肉の策だが、組込み関数**Int**をユーザ関数**Int2**で置き替えるしかない。

```vb:Int2
Public Function Int2(n) As Long
    Dim str As String, pos As Integer
    
    str = CStr(n)
    pos = InStr(str, ".")
    If pos > 0 Then
        Int2 = CInt(Left(str, pos - 1))
    Else
        Int2 = CInt(str)
    End If
End Function
```

数値を文字列に変換し、小数点より前の数字を取り出すことで、見た目通りの数値で評価されるようになる。
その上で、集計箇所のIntをInt2に修正する。

```vb
total = total + Int2(n)
```

解決した。
応急処置的に対処してしまったが、そもそも設計レベルで見直すべき事柄である。

今までこんなことは無かったというので、稀なケースかもしれないし、Officeが64bitに変わったせいかもしれない。
定かで無いが不具合には変わりなく、修正済モジュールをBAS形式でエクスポートし、先方のアプリケーションにインポートして頂いた。
データベースとモジュールが分離されていないAccessアプリケーションでは、このようなリリース手順になる。

# 教訓
浮動小数点演算では、プログラミング言語に関係なく誤差は発生する。

かなり昔の話だが、Javaの開発案件で集計結果が合わない、と新人から相談を受けたことがある。
早速コードレビューすると原因発覚。補助通貨単位（ドルの場合はセントとかのアレだ）を小数点で表してDouble型の変数に格納していたからだった。
Double型はプリミティブ型としては極めて大きい（小さい）値を扱えたが、浮動小数点方式の性質上、2進数で完全に表せない10進数の小数では無限小数となり、データ型の精度を超える桁は丸められてしまう。
例示すると、10進数の`0.1`を2進数に変換すると`0.0001100110011…`となり、`0011`の部分を永遠に繰り返すことになり（循環小数）、Double型に格納すると切り捨てられてしまう。
多少の誤差はあっても性能を優先する科学技術計算ならともかく、金額計算に浮動小数点は不向きなのだ。
なお、Excelの計算でも**IEEE754**（浮動小数点数の標準規格）に準じて設計されているため、同じような誤差は発生しているが、それが目立たないよう巧妙に工夫されているので通常の使い方で問題になることは無い。

で、誤差を回避する方法だが、すべて整数にする（小数点以下が2桁固定なら100倍するとか）か、`java.math.BigDecimal`のような専用クラスを使うのが定石。BigDecimalは10進数値を文字列として扱うためパフォーマンスは落ちるものの、厳密に正しい数値を表現できる。
ポートフォリオつくる。【プログラミング日記~ポートフォリオ①~】#2

#ポートフォリオ作ります:fist:
最初になに作ろうかなぁと悩みググり悩んだ結果とりあえずポートフォリオを作ることとしました‼
理由はどこのサイトにもポートフォリオを作るべし！べし！べしべし！と書いてあったから（笑）
実際ポートフォリオに載せるサイトもないし仕事をするって段階じゃないけど今後のために作っちゃえってノリで作ることにしました～:v:

#～完成までの流れしらべたよ～
###①企画
(1)目的の明確化
→『将来仕事をする際に相手に自分のスキルなどを知ってもらうためのサイト』ってことで今回は設定

(2)掲載内容を考える
→いろんなポートフォリオ覗かせていただいた結果、、、
・自己紹介
・スキル/仕事内容
・作成サイト集
・連絡先
にすることにしました！

###②設計
(1)サイト全体の構造を考える
→今回は初作成なので単純な作りになるのであまりやらないかも

(2)ワイヤーフレームを作る
→ワイヤーフレームとはサイトの骨組みのようなものでどこに何が来るのかっていう設計図のようなモノ
調べた感じパワポ、エクセルその他なんでも作れるっぽいのでなんかでやります！

###③作成
(1)ひたすらコードを書く
→無心で書き続けるのみ。。。
なんかコードを書くことをコーディングって言うらしいですね、そのレベルの人間です（笑）
###④公開
progateでGithubでのサイトの公開方法を学んだのでこれを使います！
サイトURLがよく見る「https://...」ってやつじゃないんだけどあれにするにはGithubではなくほかのサービスなのかな？

#おわりに
日記書くのも結構時間かかるなぁ。。。日記は挫折しそう
って感じで明日からもポートフォリオ製作頑張りま～す:man_tone3:
IAMとは？

## 勉強前イメージ

アカウントの管理のイメージ
触れるサービスを制御したりできる

## 調査

## IAM とは

Identity and Access Management の略で
AWSアカウントに対してユーザを作成したり、そのユーザに対してリソースへのアクセス制御を行うことができるサービス
グループ・ユーザ・ロールの作成ができ、またグループやユーザごとに制御を行うことが出来ます。

## そもそもAWSアカウントってどういう感じ？

そもそもAWSのアカウントは2種類あります。

- ルートユーザ
- IAMユーザ

`ルートユーザ` はlinuxでいうとrootユーザ(管理者)のイメージ
`IAMユーザ` はlinuxでいうとuseraddコマンドで作成する、adminユーザなどのイメージです。

図解すると以下のイメージです

![IAMUntitled Diagram.drawio - diagrams.net - Google Ch.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129517/06d67193-1f5c-05fe-03fe-bf0feca8fe72.png)

※ルートアカウントは利用しない
アカウントを取得した際の最初のログインがルートユーザのログインですが、
このアカウントは上記でも記載したとおり、linuxのrootユーザ(管理者)のイメージです。
アカウントのすべてのリソースに対してフルアクセス権限がありますので、
リソースを使用する際は、基本的にはIAMユーザを作成して最小の権限で行います。

## IAMでのログイン方法

以下からログインすることが出来ます。

`https://[アカウントID].signin.aws.amazon.com/console`

## 文言の確認

### IAMユーザ

まずIAMユーザについて。
IAMユーザは個人で利用するアカウントに相当します。
IAMユーザのユーザ名は個人の名前で有ることが多く、下記のイメージで作成されます

![IAMユーザUntitled Diagram.drawio - diagrams.net - Google Ch.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129517/99d79d62-023b-0338-0eed-a8b91df76469.png)


### IAMグループ

IAMグループはIAMユーザをまとめて管理するグループになります。
運用チームグループや、開発チームグループなどで作成することが出来ます。

![IAMグループUntitled Diagram.drawio - diagrams.net - Google Ch.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129517/6b226999-0315-c351-84ab-454f795dc663.png)

### IAMポリシー

IAMポリシーはAWSリソースにアクセスするための権限設定のことで、
s3やEC2、他のAWSリソースに対する権限などを設定します。

以下のように、
開発チームのIAMグループにはs3,EC2,ACMの権限を許可するが、
運用チームのIAMグループにはs3の権限のみ許可する という設定ができます。

![IAMポリシーUntitled Diagram.drawio - diagrams.net - Google Ch.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129517/6e952d80-a91b-516e-5eb6-204bd541e633.png)

### IAMロール

IAMロールはIAMポリシーをグループ化したものです。
例えば
以下のように開発用ポリシーをグループ化して、ロールにすることでセットで適応することが出来ます

![IAMロールUntitled Diagram.drawio - diagrams.net - Google Ch.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129517/3134c9a7-f469-0e42-2d53-efd542313045.png)


## 勉強後イメージ

ふわっとわかってたけど、ちゃんと調べることで合ってたってことがわかった。
設定したこともあるし触り方とかもイメージ分かるけど、
正しく区切ってIAMは出来てないかもしれないから今度はコンソール上で確認したい

## 参考

- [AWS Identity and Access Management (IAM)](https://aws.amazon.com/jp/iam/)
- [AWS再入門 AWS IAM (Identity and Access Management) 編](https://dev.classmethod.jp/articles/cm-advent-calendar-2015-getting-started-again-aws-iam/)
- [AWSアカウントとは？IAMとは？【ビギナー向け】](https://blog.serverworks.co.jp/tech/2020/02/03/awsaccountforbeginner/)
【備忘録】同じタグ内で複数のclass名を並べる理由とCSS記述について

# 初めに
HtmlのdivタグやspanタグにCSSを適用するためには、id名もしくはclass名を付けます。特にcalssセレクタは頻繁に使われていますが、その中でも複数のクラス名を一つの要素に並べるケースについてその理由とcssの記述について纏めてみました。

# 目次
- idとclassの違い
- 同じタグ内に複数のclass名を付ける理由
- 同じタグ内に複数のclass名が並んだ場合のCSS記述
- 複数のクラス名が入れ子構造（ネスト）の場合 
- 複数のclassに同じcssを適用する場合
- まとめ

## idとclassの違い
id属性はhtml文書内でたった一つしかない要素に対してスタイルを適用する時に使います。なので同じ文書内に同じid名が複数存在することはあり得ません。これに対してclass属性の場合、複数のタグに同じclass名を付けてそれぞれ同じスタイルを適用することができます。「この部分は絶対このスタイルにしたい、他の要素タグとスタイルが被りたくない」と言う場合を除いて、class属性を使った方が無難です。

## 同じタグ内に複数のclass名を付ける理由
色んなケースがあると思いますが代表的な例としては、cssを利用したアニメーションを作る場合が挙げられます。z-indexを指定し、layer構造にしてそれぞれ違うスタイルを適用する場合に複数のclass名を並べます。cssアニメーションについては下記のサイトをご利用ください。
- https://techacademy.jp/magazine/9409

## 同じタグ内に複数のclass名が並んだ場合のCSS記述
divタグ内にapplicationとexampleと言う２つのクラス名が並んだケースを見てみると
①HTML

```html
<div class="application example">application <br>
</div>
```
②CSS

```css
.application.example {
                       color: #3f32d3;
                       }
```
ここでポイントになるのが、「.application」と「.example」の間を半角スペースなどで空けてはいけません。理由は同じタグ内にクラス名が並んでいるからです。これと似たような記述で間違えやすいのが次の様なケースです。

## 複数のクラス名が入れ子構造（ネスト）の場合
次のように適用したいクラスの要素がexampleで、example要素がapplication要素に対して親子関係にある場合は次のように
CSSを記述します。
①HTML

```html
<div class="application"> <br>
     <section class="example">example
　   </section>
</div>
```

②CSS

```css
.application .example {
                       color: #3f32d3;
}
```
この場合、「.application」と「.example」の間は半角スペース１個分を空けなければなりません。その理由はapplicationクラスとexampleクラスがネスト構造で離れているからです。
## 複数のclassに同じcssを適用する場合
最後に次の様に複数の異なるクラスに同じスタイルを適用する場合には以下の様に記述します。
①HTML

```html
<div class="kind-1">kind-1</div>
<div class="kind-2">kind-2</div>
```

②CSS

```css
.kind-1,.kind-2 {
                 color: pink;
}
```
ポイントは「.kind-1」クラスと「.kind-2」クラスの間に「,」を入れつことです。

##まとめ
以上をまとめて表示すると次のようになります。
①HTML

```html
<body>
    <div class="application example">application<br>
        <section class="example">example
        </section>
    </div>
    <div class="trip" id="helper">trip</div>

    <div class="kind-1">kind-1</div>
    <div class="kind-2">kind-2</div>
</body>
```

②CSS

```css
.application .example {
    color: #3f32d3;
}

.application.example {
    color: #f324df;
}

.trip#helper {
    color: #aafef6;
}

.kind-1,
.kind-2 {
    color: pink;
}
```

③画像
![スクリーンショット 2021-01-29 20.41.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/966135/5bf67210-0446-7e06-0c56-5db11950b780.png)
firebase deploy で詰まった時の対処法

## 簡単な自己紹介

今回が初投稿になります！現在フロントエンド を学習している就活生です。
何事もアウトプットが重要だと思うので投稿してみようと思いました！かつ自分の備忘録として記録しようと思います。

今回vueCLIとfirebaseを使用してアプケーションを作成したのですが、最後の最後デプロイするところで壁にぶつかったので記録しておきます！

## サイトが公開されていない
詳しいデプロイ方法は他の記事を参照してください。

`$ firebase deploy`


これでfirebase deployが成功した場合、最後にURLが発行されると思います。
そしてそのURLをクリックして無事公開できたと思ったらこの画面になりました、、、
<a href="https://gyazo.com/cdcefdaaa155de9e97a38e5d5a0dac48"><img src="https://i.gyazo.com/cdcefdaaa155de9e97a38e5d5a0dac48.png" alt="Image from Gyazo" width="539"/></a>


##原因
おそらく人によって様々かとは思いますが私の場合はdistディレクトリの位置がおかしかったからでした。

```
$firebase init

     ######## #### ########  ######## ########     ###     ######  ########
     ##        ##  ##     ## ##       ##     ##  ##   ##  ##       ##
     ######    ##  ########  ######   ########  #########  ######  ######
     ##        ##  ##    ##  ##       ##     ## ##     ##       ## ##
     ##       #### ##     ## ######## ########  ##     ##  ######  ########

You're about to initialize a Firebase project in this directory:

  C:\Users\username\
　　　　　　　　　　　　⬆︎ここがおかしい
```
上記のようになっている場合うまくいきません

  `C:\Users\username\desktop\app`

このようにしておかなければなりませんでした。

##解決策
私の場合すでに作成しまっていたdistディレクトリを削除し、また新しく作り直したのちに
正しいディレクトリの位置でfirebase init を行いました。

そしてもう一度firebase deploy を実行すると成功しました。


これまでターミナルなんて物を触ったこともなかったのでこんなこと当たり前だよ！と言われそうですが、
何故無知な者で。。
**これからも精進していきます！**
gitignore系メモ

# gitignore系メモ

## 配置する階層
.git以下ならどこでもいい。複数の.gitigoreファイルを配置できる。その場合、最下層のgitignoreの設定が優先される

## 書き方
### 階層

```:ファイル階層
a/-|
   |- apl/-|
           |-aplhoge.txt 
           |-hogedir/
   |- hoge.txt
   |- .gitignore

```


### 特定のファイルを対象外にしたい

```:.gitignore
/hoge.txt
/apl/hogedir
```



### 特定のファイルだけ対象にしたい


```:.gitignore
#階層関係なく全てのファイルを対象外にする
*
#apl/を対象外から外す
!/apl
#apl/以下のファイルを再帰的に対象外から外す。ワイルドカード1個だと、直下のみ対象外から外し、hogedir以下は対象外のまま。
!/apl/**
#Makefile通過
!/Makefile
```
【メール】sendmailからPostfixへの切り替え

https://qiita.com/chanP_yamazaki/items/ec3285c18578d80d6e9c
上記記事内で「yum remove -y mariadb*」したところpostfixまで一緒にアンインストールされてしまったので入れ直す

```
$ sudo su -
# yum install -y postfix
# systemctl enable postfix
# systemctl restart postfix
# postmap /etc/postfix/virtual
# alternatives --config mta
 -> 2(postfixに変更)
# ll /usr/sbin/sendmail
# ll /etc/alternatives/mta
 -> postfixになってればok

# vi mail.php
<?php
$to = "hogehoge@hoge.com";
$subject = "hoge";
$message = "hoge";
$headers = "From: hoge@hoge.com";
mail($to, $subject, $message, $headers);

# php mail.php
メールが届いていればok
```

メールが届かない場合は/var/log/httpd/error_logや、/var/spool/mail/rootにログが出る...はず
ubuntu 超初心者向け設定　VNCアクセスできるようになるまで

###################################################
ubuntu 20.04   x11vnc
###################################################

gdm3からlightdmに変更
sudo apt install lightdm

x11vnc をインストール

パスワードを設定
sudo x11vnc -storepasswd /etc/.vncpasswd

Xauthority の場所を探す
ps wwwwaux | grep auth
-auth /run/user/1000/gdm/Xauthority

コマンドを打って起動、接続確認する
sudo x11vnc -rfbauth /etc/.vncpasswd -loop  -forever -repeat -rfbport 5900 -shared -display :0 -auth /run/user/1000/gdm/Xauthority


サービスに登録する
sudo vi /etc/systemd/system/x11vnc.service

demo@demo-S2600WT2R:~$ cat /etc/systemd/system/x11vnc.service
[Unit]
Description=x11vnc (Remote access)
After=network-online.target

[Service]
Type=simple
ExecStart=/usr/bin/x11vnc -rfbauth /etc/.vncpasswd -loop -forever -repeat -rfbport 5900 -shared -display :0 -auth guess
ExecStop=/bin/kill -TERM $MAINPID
ExecReload=/bin/kill -HUP $MAINPID
KillMode=control-group
Restart=on-failure

[Install]
WantedBy=graphical.target


サービスコンフィグファイルが書き換わったので一度デーモンを再起動
systemctl daemon-reload

x11vncのサービススタート
systemctl start x11vnc

登録
systemctl enable x11vnc



###################################################
ubuntu 18 + tivervncserver
###################################################
ubuntu 18.04.x　Serverをインストールする
SSHサーバーも同時にインストール
もしくは　sudo apt-get install openssh-server

IPを設定

reboot

Ubuntuバージョン確認
cat /etc/lsb-release   or   lsb_release -a

ーーー以下すべてsudoコマンドーーー

vi /etc/ssh/sshd_config     Rootのアクセスを許可
systemctl restart ssh

ufw 
ufw allow 22

apt-get update

apt-get -y install ubuntu-desktop　昔はUnityが標準だったが今はGnomeが標準

gnome-shell --version


apt-get install tightvncserver   (もしくはtigervncserver こちらの方がtightの改良版らしい）

apt list <xxx>   or   apt search <XXX>
dpkg -l
apt remove <xxx>   or   apt remove --purge <xxx> 

vncserver でアクセス時のパスワード設定　６－８文字

うまくいかないのでtigervnc にチェンジ

apt-get install tigervnc-standalone-server tigervnc-common tigervnc-xorg-extension
vncpasswd

vncserver -localhost no -geometry 1920x1080 -depth 24

アクセスはVNCクライアントで　vncserver-IP:5901

vncserver -list
vncserver -kill :1

自動起動は以下の記事が参考になりました。
https://www.it-swarm-ja.tech/ja/ubuntu/ubuntu-1804でのtigervnc-systemdプロセスの設定/962276367/
【React】Reducerでstateを直接変更してはならないことの背景

##  Reducerのルール

Reducerにはいくつかの決まりごとがあり、よくあるミスとして「引数として渡されたstateそのものに変更を加えてはならない」ところを、直接変更を加える処理をreducerに記述してしまうというものがあります。

## ルールの背景

各reducerをまとめてexportするときにcombineReducers関数を用いますが、このcombineReducersのコード（ https://github.com/reduxjs/redux/blob/master/src/combineReducers.ts ）を確認すると、終盤辺りに以下のようなコードがあります。

```typescript:combineReducers.ts
let hasChanged = false
const nextState: StateFromReducersMapObject<typeof reducers> = {}
for (let i = 0; i < finalReducerKeys.length; i++) {
  const key = finalReducerKeys[i]
  const reducer = finalReducers[key]
  const previousStateForKey = state[key]
  const nextStateForKey = reducer(previousStateForKey, action)
  if (typeof nextStateForKey === 'undefined') {
    const errorMessage = getUndefinedStateErrorMessage(key, action)
    throw new Error(errorMessage)
  }
  nextState[key] = nextStateForKey
  hasChanged = hasChanged || nextStateForKey !== previousStateForKey
}
hasChanged = hasChanged || finalReducerKeys.length !== Object.keys(state).length
return hasChanged ? nextState : state
```

このコードは、受け取ったactionを各reducerに送り、reducerから返ってきたstateが更新されているかどうかを判断して、更新されていれば更新後のstateを、そうでなければ元々のstateを返すというものです。

forループでは、各reducerについてfor文内の処理が行われます。
for文内では、更新前のstateがpreviousStateForKeyに代入されます。
次に、reducerが実行され、reducerが返した更新後のstateがnextStateForKeyに代入されます。

そして、次の1行でstateの更新の有無が判定されます。

```javascript
hasChanged = hasChanged || nextStateForKey !== previousStateForKey
```

この行では、previousStateForKeyとnextStateForKeyの比較が行われ、両者が異なっている（previousStateForKey !== nextStateForKey がTrueである）ならば、hasChangedはTrueとなり、更新後のstateが返されることになります。Falseであれば、更新前のstateがそのまま返されます。

ここで、次のようなケースを考えます。


```javascript
const state = {name:"Taro",nationality:"USA"};
const previousState = state;
const reducer = (state) => {
    state.nationality = "Japan";
    return state;
};
const newState = reducer(state);
```

上のreducerは、stateを直接変更してしまっています。（実際のreducerではactionも引数として渡されますが、ここでは簡略化のために省いています。）

このような場合、次の真偽値はfalseとなります。これは、オブジェクトは参照渡しであるということから、newStateとpreviousStateは同じアドレスを参照しているためです。

````javascript
newState !== previousState  //false
````

この結果、先程のcombineReducersのコードにおけるhasChangedはFalseになり、stateを更新したはずなのに更新されていないというような問題が起こるという訳です。

実は、2019年頃に次の一行が加わっており（ https://github.com/reduxjs/redux/pull/3490/commits/001a1979372dbd9cf431805f439a179eb05e20be ）combineReducersの変更検知の方法も少し変わったようですが、reducerでstateを直接変更しないという習慣は今後も続けた方が間違いはないと思います。

````
hasChanged = hasChanged || finalReducerKeys.length !== Object.keys(state).length
````

## 参考文献

・Redux combineReducers.ts（ https://github.com/reduxjs/redux/blob/master/src/combineReducers.ts ）

・Udemy講座「 Modern React with Redux [2020 Update] 」（ https://www.udemy.com/course/react-redux/ ）
この講座は、Reactにおける様々な決まりごとの背景なども教えてくれます。
今回、reducerの決まりごとに関してここで学んだ内容について、備忘録を兼ねて共有させていただきました。Udemyの講座は、このような本ではなかなか学べない部分もカバーしており、Reactの新たな学びにとても役立ちます。
特定のyoutubeチャンネルの動画の評価数を監視するスクリプト

youtubeのホワイトハウスの動画を監視するスクリプトが以下のサイトで紹介されていました。作者がこのスクリプトを使ってホワイトハウスの動画を調査したところ、バイデンの動画の低評価がとても多いことと。低評価を減らす操作が行われていることがわかったそうです。
https://phzoe.com/2021/01/27/white-house-youtube-dislike-manipulation/
このスクリプトは英語圏用みたいで、日本語圏の自分の環境では以下のスクリプトで動きました。言語圏によりcurlの応答が変わるのは、curlで「私はこの言語圏にいます」という情報をyoutubeに送っているからなのか、それともyoutubeが勝手にこちらの言語圏を認識してるのかわかりません。詳しい人教えてください。

あとこのプログラムが回りすぎるとDOS攻撃になってしまうと思うので、使うときはターゲットのサイトをホワイトハウス以外に変えてみてください。

```wh.sh
# Zoe Phin, 2021/01/26
# Habu, 2021/01/29
require() { sudo apt-get install curl gnuplot; }
 
stats() {
    list=$(curl -s 'https://www.youtube.com/c/WhiteHouse/videos' | grep -o 'watch?v=[^"]*')
    for i in $list; do
        link="https://www.youtube.com/$i"
        #echo -e "\x1B[31m" $link "\x1B[0m"
	date=$(date +"%s %x,%R:%S" | tr -d '\n')
	curl -s $link | tr -d ',' | tr '}' '\n' > new 
	grep -m 1 -o '[0-9,]* 回視聴' new > .views
        grep -m 1 -o '高評価 [0-9,]* 件' new > .likes
        grep -m 1 -o '低評価 [0-9,]* 件' new > .dislikes
	paste .views .likes .dislikes | awk -v L=$link -v D="$date" '
	    NF==8{printf "%s %s %9s %9s %9s\n", L, D, $1, $4, $7}'
    done
}
 
collect() {
    while true; do
        stats; sleep 75
    done | tee -a data.csv
}
 
dislikes() {
    list=$(cut -c1-44 data.csv | sort -u)
 
    for vid in $list; do   
        echo $vid
        grep ^$vid data.csv | awk '{
            DiffD=$6-D
            if (DiffD < 0) { 
                printf "%s %+7d\n", $3, DiffD 
                DLost+=DiffD
            }
            L=$5; D=$6
        } END {
            printf "%-19s %7d\n", "Total", DLost
        }' 
        echo
    done | awk '{
        print} $1=="Total" { GT+=$2 } 
        END { printf "%-17s %9d\n", "Grant Total", GT 
    }'
}
 
plot() {
    list=$(cut -c1-44 data.csv | sort -u)
    let n=0
 
    for vid in $list; do   
        let n++
        awk -v V=$vid '$1==V {print $2" "$4" "$5" "$6}' data.csv > plot.csv
 
        echo "set term png size 740,740
        set key top left
        set grid xtics ytics
        set title '$vid'
        set timefmt '%s'
        set xdata time
        set xtics format '%Hh'
        plot 'plot.csv' u 1:2 t 'Views'    w lines lc rgb 'black' lw 2,\
                     '' u 1:3 t 'Likes'    w lines lc rgb 'green' lw 2,\
                     '' u 1:4 t 'Dislikes' w lines lc rgb 'red'   lw 2
        " | gnuplot > example${n}.png 
    done
}

```
###使い方

```shell
$source wh.sh;
```
とします。次に

```shell
$collect
```

とします。このプログラムは75秒間隔で情報をとってきます。
好きなときに`Ctrl-D`で止めます。

gnuplotが入ってたら

```shell
$plot
```
でグラフがかけます。

###中身の解説
まず

```shell
list=$(curl -s 'https://www.youtube.com/c/WhiteHouse/videos' | grep -o 'watch?v=[^"]*')
```
でホワイトハウスのyoutubeチャンネルの動画一覧のリンクを得ます。
次に`for`ループでそのリンクを巡回して

```shell
curl -s $link | tr -d ',' | tr '}' '\n' > new 
```
でそのリンクの情報をとってきます。
そして'grep'で狙っている情報を抜き取ります。

```shell
grep -m 1 -o '[0-9,]* 回視聴' new > .views
grep -m 1 -o '高評価 [0-9,]* 件' new > .likes
grep -m 1 -o '低評価 [0-9,]* 件' new > .dislikes
```

あとは表示を整えたり、ポストプロセスの情報処理の部分です。
git取り消し系メモ

# git取り消し系メモ

## 最新コミットに戻す（変更箇所全削除）
```
git reset --hard HEAD
```
HEAD…最新のエイリアス
HEAD^…最新の1個前のエイリアス

## 最新コミットに戻す（変更箇所は削除しない。）
addの取り消しにも使える

```
git reset --mixed HEAD
```


## 指定のコミット時点に戻す
```
git reset --hard 指定のハッシュ値
```
## 指定のコミット時点を上書きコミット（戻らない）
```
git revert 指定のハッシュ値
```



## コミットの上書き
コミットメッセージやり直したい時など

```
git commit --amend
```

## add(ステージング)したものを編集はそのままにaddを取り消し
```
git reset --mixed HEAD
```

## addしたものを最新コミットに戻す（編集分は消える）
```
git reset --hard HEAD
```