OmniAICreator/Qiita-1.07M huggingface dataset:
Arch LinuxにJupyterLab Appをインストールする方法

# 概要

JupyterLab Appとは、Jupyter Notebookをデスクトップアプリとして利用できるようにしたアプリケーションです。

[jupyterlab/jupyterlab_app: A desktop application for JupyterLab, based on Electron.](https://github.com/jupyterlab/jupyterlab_app)


![1*ZbqjB3evW_yB_SKFjqliWA.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7565/59fd5cc1-bcad-2656-7dd6-41b8b52cbb5d.png)

このアプリケーションはLinuxにも対応していますが、現在はDebian系とRedHat系しかパッケージが提供されていません。

https://github.com/jupyterlab/jupyterlab_app/releases/tag/v3.1.13-1

この記事ではdebパッケージをArch Linuxで利用できる形式に変換する方法を説明します。

## 変換方法

変換には`debtap`が必要なのでインストールします。

```bash
yay -S debtap
```

次に`deb`パッケージを変換します。

```bash
debtap JupyterLab-Setup-Debian.deb
```

変換すると、zstファイルが作成されますので、これをpacmanコマンドでインストールします。

```bash
sudo pacman -U jupyterlab-app-3.1.13-1-x86_64.pkg.tar.zst
```

## 起動

正常にインストールされていれば、`JupyterLab`というアプリケーションがあるはずです。これを起動します。

起動すると下記のようなアプリが立ち上がれば成功です。この方法でdebパッケージしか提供されていないものでもArch Linuxで使えるようにできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7565/a998a17c-b05a-96d1-3730-3be1ae9c6c84.png)
C言語のgdbで苦戦した話

先日初めて、C言語でgdbを用いてデバッグしたのですが、少々苦戦したのです。

####やりたいこと####
gdbを用いてちゃんとHelloWorldを出力させる。

####ディレクトリ構成####
```
drwxrwxr-x 2 zombiest zombiest 4096  9月 29 22:34 c_file
drwxrwxr-x 2 zombiest zombiest 4096  9月 29 22:43 gdb_file
```
下で説明しますが、カレントディレクトリより<font color="Red">gccコマンド</font>を打ち込みます。

####ソースコード####
```
#include <stdio.h>

int main(void)
{
    char* str = "Hello World";
    printf("%s\n", str);
    return 0;
}
```

#####次にコマンドを打ち込んでファイルを出力させます。
```
gcc コンパイルするファイル -o 出力先ファイル
```
```
gcc ./c_file/HelloWorld.c -o ./gdb_file/HelloWorld.out
```

#####ファイルが出力されたか確認しましょう。
```
ls -l ./gdb_file/
-rw-rw-r--  1 zombiest zombiest 19232  9月 29 23:11 HelloWorld.out
```
じゃあ、最後にgdbコマンド叩いてデバッグしてみましょう！と言いたいのですが
###<font color="Red">ここで注意です！</font>
気づいた方もいらっしゃるかもしれませんが、今のファイル権限は"664"です。
ここでは詳しくは解説しませんが、実行権限がない状態になります。

実行権限を変えてあげる必要があります。
```chmod 755 ./gdb_file/HelloWorld.out```
###気を取り直してgdbコマンド投入
```
gdb ./gdb_file/HelloWorld.out
(以下、抜粋)
Reading symbols from ./gdb_file/HelloWorld.out...
(gdb) run
Starting program: /home/zombiest/working/gdb_file/HelloWorld.out 
Hello World
[Inferior 1 (process 20417) exited normally]
(gdb) 
```
できました〜
ちなみに、実行権限664の状態でやると
```/gdb_file/HelloWorld.out: 実行できません: 許可がありません```
って怒られます。いわゆる”Permission Denied”ってやつですね！気をつけましょう。
ここまで読んで頂き、ありがとうございました！
Windows回復環境をIntuneから有効にする

#はじめに
Windows 10 build 1709 から Autopilot Rest を使用して管理者が Windows 10 デバイスを再初期化して個人的なファイルや設定を削除し、デバイスの登録を維持したままデバイスをもとの状態に戻すことができるようになりました。
Autopilot Reset を使用するには Windows 回復環境 (WinRE) をデバイスで有効にする必要があります。このポリシーを有効にするには MEM (Microsoft Endpoint Manager) または Windows Configuration Designer パッケージを使用して行うことができます。
ここでは、MEM を使用して Windows 回復環境 (WinRE) を有効にする手順を示します。

#Windows 回復環境 (WinRE) の有効化する
- Microsoft Endpoint Manager admin center (<https://endpoint.microsoft.com>/)にアクセスします。
- **[デバイス]** をクリックする。
- **[構成プロファイル]** をクリックする。
- **[プロファイル作成]** をクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78535/6ab8de89-259d-3a8b-3578-e8aefa8852b4.png)
- **「プラットフォーム** は **[Windows 10 以降]** を選択。
- **「プロファイルの種類** は **[テンプレート]** を選択。
- **「テンプレート名」** は **[カスタム]** を選択。
- **[作成]** をクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78535/6d94b03a-664b-c8ff-9495-cd78632d1203.png)
- **「名前」**に **[Enabled WinRE]** と入力し、**「説明」** に **[Windows 回復環境 (WinRE) を有効にします]** と入力し、**[次へ]** をクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78535/b9040e07-f772-ea27-a289-45326d552bbe.png)
- **[追加]**をクリックする。
- **「名前」** に **[Enabled WinRE]** と入力する。
- **「説明」** に **[Windows 回復環境 (WinRE) を有効にする]** と入力する。
- **「OMA-URI」** に **[./Vendor/MSFT/Policy/Config/CredentialProviders/DisableAutomaticReDeploymentCredentials}** と入力する。
- **「データ型」** は **[整数]** を選択する。
- **「値」** に **[0]** を入力する。
- **[保存]** をクリックする。
- **[次へ]** をクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78535/572edda9-3213-3363-61c2-8f8f79aa16a0.png)
- **[すべてのデバイスを追加]** をクリックする。
- **[次へ]** をクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78535/108cc944-9695-0d3a-f4e1-3bce5a94ab94.png)
- **「ルール」** で **[プロファイルを割り当てる条件]** を選択する。
- **「プロパティ」** で **[OSのエディション]** を選択する。
- **「値」** で **[Windows 10/11 Education]** を選択する。
- **[次へ]** をクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78535/d2bcce00-967f-767b-f3cc-749508400967.png)
- **[作成]** をクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78535/85ad95b6-8f6f-7050-851e-930935488e1b.png)
- Windows 回復環境 (WinRE) を有効にするプロファイルが作成されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78535/fa56cd64-1c0f-5cdb-2d8d-73daaa1ca7ce.png)
e-statの研究 その5

#概要

官製lodのe-statを研究してみる。
resasで、都道府県コードを取得。
e-statで、都道府県の総人口を取得。
leafletで、ヒートマップを表示する。

#サンプルコード

```

var pref = [
    "01.json",
    "02.json",
    "03.json",
    "04.json",
    "05.json",
    "06.json",
    "07.json",
    "08.json",
    "09.json",
    "10.json",
    "11.json",
    "12.json",
    "13.json",
    "14.json",
    "15.json",
    "16.json",
    "17.json",
    "18.json",
    "19.json",
    "20.json",
    "21.json",
    "22.json",
    "23.json",
    "24.json",
    "25.json",
    "26.json",
    "27.json",
    "28.json",
    "29.json",
    "30.json",
    "31.json",
    "32.json",
    "33.json",
    "34.json",
    "35.json",
    "36.json",
    "37.json",
    "38.json",
    "39.json",
    "40.json",
    "41.json",
    "42.json",
    "43.json",
    "44.json",
    "45.json",
    "46.json",
    "47.json",
];

var population = [
    5381733, 
    1308265, 
    1279594, 
    2333899,
    1023119,
    1123891,
    1914039,
    2916976,
    1974255,
    1973115,
    7266534,
    6222666,
    13515271,
    9126214,
    2304264,
    1066328,
    1154008,
    786740,
    834930,
    2098804,
    2031903,
    3700305,
    7483128,
    1815865,
    1412916,
    2610353,
    8839469,
    5534800,
    1364316,
    963579,
    573441,
    694352,
    1921525,
    2843990,
    1404729,
    755733,
    976263,
    1385262,
    728276,
    5101556,
    832832,
    1377187,
    1786170,
    1166338,
    1104069,
    1648177,
    1433566
]

var map = L.map('map').setView([39.5, 139.5], 6);
var mapLink = '<a href="http://openstreetmap.org">OpenStreetMap</a>';
L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
  attribution: '&copy; ' + mapLink + ' Contributors',
  maxZoom: 18,
}).addTo(map);

for(var i = 0; i < 3; i++)
{
    var url = 'https://ohiapp0.herokuapp.com/pxy?url=github.com/niiyz/JapanCityGeoJson/raw/master/geojson/prefectures/' + pref[i];
    if (population[i] < 2000000)
    {
        d3.json(url, function(err, geojson) {
            L.geoJson(geojson, {
                style: {
                    weight: 1,
	    		    color: "#ccc",
		    	    opacity: 1,
			        fillColor: "#cccccc",
			        fillOpacity: 0.8
                }
            }).addTo(map);
        });
    }
    else if (population[i] > 2000000)
    {
        d3.json(url, function(err, geojson) {
            L.geoJson(geojson, {
                style: {
                    weight: 1,
	    	    	color: "#ccc",
		    	    opacity: 1,
		    	    fillColor: "#B05555",
			        fillOpacity: 0.8
                }
            }).addTo(map);
        });
    }
}




```

#成果物

https://embed.plnkr.co/plunk/2fEva4pQcoaRb9tu

以上。
e-statの研究 その4

#概要

官製lodのe-statを研究してみる。
都道府県の総人口をsparqlしてみた。
一回の問い合わせで、一県しか取れない。

#サンプルコード

```

var pref = [
  '01000',
  '02000',
  '03000',
  '04000',
  '05000',
  '06000',
  '07000',
  '08000',
  '09000',
  '10000',
  '11000',
  '12000',
  '13000',
  '14000',
  '15000',
  '16000',
  '17000',
  '18000',
  '19000',
  '20000',
  '21000',
  '22000',
  '23000',
  '24000',
  '25000',
  '26000',
  '27000',
  '28000',
  '29000',
  '30000',
  '31000',
  '32000',
  '33000',
  '34000',
  '35000',
  '36000',
  '37000',
  '38000',
  '39000',
  '40000',
  '41000',
  '42000',
  '43000',
  '44000',
  '45000',
  '46000',
  '47000',
];

var src = document.getElementById('src');
var out = document.getElementById('out');
var endpoint = "https://data.e-stat.go.jp/lod/sparql/alldata/query";
function run() {
	var sparql = src.value;
  var res = [];
  for(var i = 0; i < pref.length; i++)
  {
    var query = sparql.replace("06000", pref[i]);
		var xhr = new XMLHttpRequest();
		xhr.onreadystatechange = function() {
			if (xhr.readyState == 4 && xhr.status == 200)
			{
				var data = JSON.parse(xhr.responseText);
	      res.push(data.results.bindings[0].o.value);
			}
		};
		xhr.open("POST", endpoint, false);
		xhr.setRequestHeader("Accept", "application/sparql-results+json");
		xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
		xhr.send("query=" + encodeURIComponent(query));
	}
  out.value = JSON.stringify(res);
}

```

#成果物

https://embed.plnkr.co/plunk/0SPceypfF0nHXpW0

以上。
保存済みのマイグレーションファイル削除してしまったときの解決法

こんにちは！テックアカデミーのWebアプリコースでプログラミングを学んでいる駆け出し高校生エンジニアの安田駿介です。

今回は「Railsで保存済みのマイグレーションファイル削除してしまったときの解決法」について紹介します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1903726/fb68c064-13db-b148-764e-53678586aa1e.png)

このように、保存(up)しているファイルを削除してしまったときの解決法を書いていきます。

ちなみに、マイグレファイルの確認するには、rials db:migrate:statusを実行します。

# マイグレーションファイルを削除してしまったときの解決法

rails db:migrate:reset

をターミナルで実行してください。

# 実行結果

すると、先程のマイグレファイルがこのようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1903726/82ca3383-4e71-48fb-5153-8e0455056481.png)

保存済みのマイグレファイルを削除してしまったファイルを正常に削除することができました。

それと同時に、保存していなかっったマイグレファイルを一気に保存することもできました。

# 保存済みのマイグレーションファイルを編集する方法は？
その場合は、こちらをお読みください。

https://qiita.com/yasshun1229/items/d0cf5bb1c7a78d5582d8

# 開発環境
Ruby 3.0.0
Rails 6.1.3.1
lsコマンドで特定の名前、拡張子を持つファイルだけを表示

# lsコマンドだけで実行すると...
```
$ ls
feed.txt        inu.py          keep.sh         like
list.txt        neko            neko.py         neko.txt
pet.py
```
こんな感じで一覧を見せてくれるんだけど、例えばnekoって名前がついているファイルって何があったかな？ってみたい時、これだと必要のないものまで表示されてわかりづらい...

# ls <ファイル名>
このコマンドを打つと、そのファイル名のファイルのみが表示されるみたい

```
$ ls neko.py
neko.py
```
でも、これだけだと、そのファイルが存在しているかどうかを確認することができるだけ。
そこでワイルドカード(*)を使えば...

```
$ ls neko*
neko            neko.py         neko.txt
```
うまく、nekoが含まれるファイル名のみを表示することができました！

これを使えば、ファイル名だけでなく、特定の拡張子のみを表示させることもできます。

```
$ ls *.py
inu.py  neko.py pet.py
```

# 参考
https://www.sejuku.net/blog/49057
VS Codeで、Python Extension Loading... が終わらない...

## Phthonが実行できない？？

* VisualStudio Codeを使っていると、なぜかPython 機能拡張がいつまで経っても読み込めないときがありました。

Visual Studio | Marketplace
[Visual Studio Code > Programming Languages > Python > Changelog](https://marketplace.visualstudio.com/items/ms-python.python/changelog)

によると、2021.9.3 (20 September 2021)で、
Fix `Python extension loading...` issue for users who have disabled telemetry. (#17447)
と不具合があったが、修正されているのこと、、、

* しかし、この最新バージョンにしてもまだ発生！！

## 機能拡張の再インストール

手順

* 問題のあるPython 機能拡張を削除
* いったん少し古いバージョンのPython 機能拡張をVS Codeのターミナルからインストール

```
code --install-extension ms-python.python@2021.9.1218897484
```
* 最新バージョンにアップデート
* この手順で、無事にPython機能拡張が有効になるようになりました。
SharePoint Online の JSON書式設定で参照可能なプロパティ一覧

SharePoint Online のドキュメントライブラリおよびリストの JSON書式設定 で参照できるプロパティ（変数）の一覧です。
（独自に発見したものもあり、仕様変更などにより動作しなくなる場合もありますのでご了承ください）
一般的なプロパティは、末尾のリンクを参照ください。

### ドキュメントライブラリで参照可能な変数
|変数名|内容|
|-|-|
|[$FileRef]|パス付のファイル名|
|[$FileLeafRef]|ファイル名|
|~~[$FileDirRef]~~|パス名 ( プロパティ自体は存在するはずですが、現状は値が返ってきません​(将来対応?) )|
|[$FSObjType]|ファイルの種類　0: ファイル、1: フォルダ|
|[$File_x0020_Size]|ファイルサイズ(Byte)|
|[$File_x0020_Type]|ファイルの拡張子|
|[$ItemChildCount]|フォルダ下のドキュメントの数（フォルダの場合）|
|[$FolderChildCount]|フォルダ下のフォルダの数（フォルダの場合）|

### リストで参照可能な変数
|変数名|内容|
|-|-|
|[$Attachments]|添付ファイルがあるかどうか（ある場合は True、ない場合は False）|

### リストとドキュメントライブラリ共通で参照可能な変数
|変数名|内容|
|-|-|
|[$Link.desc]|ハイパーリンクの代替テキスト（Linkというフィールド名のハイパーリンクの列が設置されている場合）|
|[$UniqueId]|UniqueId ( b1dc3a1f-ed4e-43e9-822a-c061942dacc9 のような形式のアイテムの Id )|

<br> 
例えば、以下は、ドキュメントライブラリで、FileSize という列で、 `$File_x0020_Size` という値を参照して表示する場合の JSON書式設定の例です。

```
{
    "elmType": "div",
    "txtContent": "=[$File_x0020_Size]"
}
```

以下のようにファイルサイズを表示することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1467348/4d99b5dc-33fd-13f2-96be-afcb11b71377.png)



一般的なプロパティなどは以下を参照ください（私もいつも参考にさせていただいています）
　[SharePointリストの書式設定(JSON) チートシート (@Momomo_ai さん)](https://qiita.com/Momomo_ai/items/58bf768fb83bddfbdca1)
　[特別な文字列値 (Microsoft 公式)](https://docs.microsoft.com/ja-jp/sharepoint/dev/declarative-customization/formatting-syntax-reference#special-string-values)
[メモ] docker-compose による Bottle の構築



## 概要

通常 Bottle 自体は 1ファイルなので Docker を使う必要は無いが、
K8s や Fluentd の検証でも活用できるので Docker (docker-compose) による構築手順をメモしておく.

# 構築する環境

Python 3.9.4 ベースの Bottle 59184 の動作環境を作る.
アクセスは `http://<IP>:59184/` である.

# ファイル構成

```
.
|-- PV
|   `-- bottle
|       `-- app
|           `-- main.py .......... bottle を使って実装していくコード
|-- assets
|   `-- bottle
|       |-- Dockerfile
|       `-- requirements.txt
`-- docker-compose.yml

```

　

# ファイル詳細

## ./PV/bottle/app/main.py

```python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from bottle import route, run
 
@route("/")
def index():
  # 画面に表示したい文字
  return "<h1>Hello bottle</h1>"
 
# 59184番ポートを使用してサーバを起動する
run(host='0.0.0.0', reloader=True, port=59184)
```

## ./assets/bottle/requirements.txt

```bash
bottle
```

## ./assets/bottle/Dockerfile

```bash
FROM python:3.9.4-buster

## プロキシサーバを使う場合
# ENV http_proxy="http://proxy.co.jp:8080"  
# ENV https_proxy="http://proxy.co.jp:8080"

# コンテナ内での作業場所を /usr/src/app とする
WORKDIR /usr/src/app

# Python に関する環境変数
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

# 時刻を日本に合わせる
RUN ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
ENV LANGUAGE ja_JP.UTF-8
ENV LANG ja_JP.UTF-8

# pip を更新したうえで必要なパッケージをインストールする
RUN pip install --upgrade pip==21.0.1
COPY requirements.txt .
RUN pip install -r requirements.txt

```

## ./docker-compose.yml

```yaml
version: '3.7'

services:
  bottle:
    build: ./assets/bottle
    image: mybottle
    container_name: mybottle
    command: >
      bash -c 'python -u main.py'
    volumes:
      - ./PV/bottle/app/:/usr/src/app/
    ports:
      - 59184:59184
```

# 実行

```bash
$ docker-compose up -d --build
```

# 参考にしたサイト

・https://qiita.com/ritorut18/items/4230ec6b524be15ede01

　

以上
ラムダ式・ストリームについて自分の見解とまとめ

- ラムダ式の引数戻り値には、型の指定を行わない
- java8から「型推論」の機能が追加されたから
- 単一関数インターフェース(java.util.function)を使う実装につかえる
- 引数が一つの場合は（）を省略可能、引数がない場合は（）が必要

例

```
IntBinaryOperetor op = (x, y) -> x + y;
```

例　型を書くこともいちお可能

```
IntBinaryOperetor op = (int x, int y) -> {x + y;};
```

- **メソッド参照**について
引数に対してシンプルにメソッドを適用する場合はメソッド参照でさらに簡潔に記述することができる

```
Function<String, Integer> func = str -> str.length();
```
下のように書き換えが可能である

```
Function<String, Integer> func = str -> String::length;
```

偶数をカウントするプログラム(ラムダ式)

```
List<Integer> list = Arrays.asList(5,8,1,2,3);
long count = list.stream().filter(x -> x % 2 == 0).count();
```

## ストリームについて（java.util.stream）
- データ集合（配列やコレクションのこと）に対する処理をラムダ式で簡潔に記述する為の新しい概念

以下のようにArraysはstreamメソッドを持っているので、streamオブジェクト
を取得できる

```
List<String> list = Arrays.asList("A", "B", "C");
Stream<String> stream = list.stream();
```

- 基本的な使い方<br>
①ストリームオブジェクトの取得<br>
②中間操作メソッド（ラムダ式）<br>
③終端操作メソッド();<br>
railsのjoinsメソッドは何をやっているのか？

皆様お久しぶりです、プレイライフの熊崎です！
最近体調を崩すことが多く、アウトプットができておりませんでした。
体調を崩していた私が言うのもどうかとは思いますが、季節の変わり目ですので体調管理には気をつけましょう！

というわけで、久々のアウトプットを行っていきたいと思います。

## joinsメソッド
内部結合を行うメソッド。

## 内部結合

### 結合とは？
> SQLで、このような複数のテーブルに格納されたデータを集めた表を作る処理を「結合」と呼びます。
ref:  https://style.potepan.com/articles/17010.html

### 内部結合とは？
結合にもいくつか種類があり、その中の一部。

>INNER JOINは、結合するテーブルのデータのうち、条件に指定したカラムの値が一致するデータのみを結合します。
ref: https://style.potepan.com/articles/17010.html

例： 書籍（books）テーブルと著者（authors）テーブルを内部結合する。

#### booksテーブル
| id | title | authors_id |
|:-:|:-:|:-:|
|  1 | 猿でもわかるRuby on Rails  | 1  |
|  2 |  猿でもわかるSQL |  1 |
|  3 | 猿でもわかるRuby  |  2 |

#### authorsテーブル
| id | name |
|:-:|:-:|
|  1 | 佐藤太郎  |
|  2 | 鈴木次郎  |
|  3 |  田中三郎 |

#### 結合後のテーブル
| id | title | authors_id | id | name |
|:-:|:-:|:-:|:-:|:-:|
| 1  |  猿でもわかるRuby on Rails | 1  | 1  | 佐藤太郎  |
|  2 |  猿でもわかるSQL |  1 |  1 |  佐藤太郎 |
|   3|  猿でもわかるRuby |  2 |  2 |  鈴木次郎 |

このように、２つのテーブルが結合する。
注意点としては、田中三郎さんが書いた書籍はbooksテーブルに存在しない（→ author_id = 3のレコードが存在しない）場合は、結合後のテーブルには表示されない。

#### 内部結合のSQL文
SQL文は以下のように書く。

```SQL
SELECT * FROM books
         INNER JOIN authors
         ON books.author_id = authors.id;
```

もっと抽象的に説明すると、以下のような書き方をする。

```SQL
SELECT * FROM 結合元のテーブル
         INNER JOIN 結合したいテーブル
         ON 結合条件;
```

## railsのjoinsメソッドはどのような挙動を示すのか？
先ほどの書籍テーブル、著者テーブルの例を使用する。

```sample.rb
class Book < ApplicationRecord
  belongs_to :author
end

class Author < ApplicationRecord
  has_many :books
end

Book.joins(:author) # => ちなみに、joinsの中身は生のSQLでも可

# 以下のSQLを生成する。
# SELECT * FROM books
#          INNER JOIN authors
#          ON books.author_id = authors.id;
```

## まとめ
- 内部結合は、結合するテーブルのデータのうち、条件に指定したカラムの値が一致するデータのみを結合する。
- railsのjoinsメソッドは内部結合のSQL文を生成する。

## 参考文献

https://railsguides.jp/active_record_querying.html#joins
https://style.potepan.com/articles/17010.html


## 最後に
フレームワークはとても便利ですが、反面何をやっているか見えにくいところもあるので、今後もフレームワークの裏側ではどのような処理が行われているのかまでしっかりと理解していきたいと思います。
SSD, HDDの容量削減方法

## 大きなファイル、フォルダの調査
- [DiskInfo](https://forest.watch.impress.co.jp/library/software/diskinfo/) で大きなファイルやフォルダを調査する。
- WSL2を使っていると、ext4.vhdxがかなり大きくなっています。

## ext4.vhdxの圧縮
- WSL2でファイルを削除しても容量は開かないのでext4.vhdxを圧縮します。(Windows10 homeの場合の方法)

　1. タスクバーのDocker Desktopを右クリックし、Quit Docker Desktopで終了する。
　2. スタートメニューのWindows PowerShellを右クリックし、管理者として実行する。
　3. ext4.vhdxのある場所を調べておく(%USERPROFILE%\AppData\Local\Packages\CanonicalGroupLimited.UbuntuonWindows_79rhkp1fndgsc\LocalState\ext4.vhdx 等)
　4. 以下のコマンドを実行

```
wsl --shutdown
diskpart
DISKPART> select vdisk file="%USERPROFILE%\AppData\Local\Packages\CanonicalGroupLimited.UbuntuonWindows_79rhkp1fndgsc\LocalState\ext4.vhdx"
DISKPART> attach vdisk readonly
DISKPART> compact vdisk
DISKPART> detach vdisk
DISKPART> exit
```
　5. 13.87GB → 9.67GB になりました。もともとあまり使っていなかったのか、思ったより減りませんでした。
　6. Windows を再起動する。
Talend ジョブの重複起動をTouchファイルで管理する

# はじめに
例として5分に1回呼び出される想定のジョブをtalendで作成した場合に、5分で処理が終わらずジョブが実行された状態で再度ジョブを実行するとエラーになります。
そのため、現在ジョブが動作しているかを確認するためにTalendのtFileTouchコンポーネントを利用する例を備忘録として記載します。

# touchコマンドとは
touchはLinuxのコマンドとして用意されています。
機能として
*　ファイルのタイムスタンプ変更
*　存在しないファイル名を指定するとファイルを新規作成
があります。-tで指定のタイムスタンプに更新が可能でオプション指定がない場合は現在時刻に更新されます。

```
touch sample.bat -t 指定の時刻へ更新
```
TalandにはtFileTouchコンポーネントが用意されており機能としてファイルを作成することができるため、この機能を利用しジョブ起動中のみ既定のファイルが存在する処理をジョブに追加することで重複起動を管理します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135147/9d8ff950-92e5-bec5-7911-ad0e525d7ce5.png)

# Touchファイル確認手順
1. touchファイルがあるか確認する
2. ファイルがなければ作成しジョブの処理を継続、あればジョブを停止
3. touchファイル削除

各コンポーネントのファイル名に追加

```パラメータ.txt
ファイル名: "C:/talend/TOS_DI-Win32-20200219_1130-V7.3.1/workspace/job.touch"
```
## tFileExist_1

```条件分岐.txt
((Boolean)globalMap.get("tFileExist_1_EXISTS")) == false
((Boolean)globalMap.get("tFileExist_1_EXISTS")) == true
```
## tFileTouch_1

```オプション.txt
存在しない場合、ディレクトリを作成にチェック
```

## tFileExist_2

```パラメータ.txt
((Boolean)globalMap.get("tFileExist_1_EXISTS")) == true
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135147/c0b74665-095b-8d39-3216-458fe5e73af8.png)
CloudFront-Forwarded-Protoヘッダを使ってCloudFrontへの通信プロトコルをオリジン側で確認してみた

[参考](https://dev.classmethod.jp/articles/cloudfront-cloudfront-forwarded-proto-header/)

[mod_remoteip の設定は書く場所に注意！（なるべく最初の方に書くべし）](https://qiita.com/kawaz/items/31b604985d0866128c62)

[mod_remoteip を使って LB 配下の Apache もアクセス元 IP を正しく認識できる](https://blog.yskw.info/articles/256/)
【Androidアプリリリース】パワポでフィーチャーグラフィックを作成する方法


#背景
先日初めてAndroidアプリをリリースしようとしたときに、**フィーチャーグラフィック**が用意できていませんでした。本来であればデザイナーさんに依頼するのが一番だと思うのですが、趣味程度のアプリリリースだったのでパワポで作成することにしました。



#Androidアプリリリース時に必要な画像素材
(2021年10月現在)
- アプリのアイコン
- **フィーチャーグラフィック（Google Play ストアページの上部で使用されるんだと思います）**
- スマートフォン版のスクリーンショット
- 7インチタブレット用のスクリーンショット
- 10インチタブレット板のスクリーンショット

##パワポで作成する手順


1) パワポの 表示＞スライドマスター を選択

![スライドマスタ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/875694/bcdba880-407f-cf6e-8f05-d3d7862d6d87.png)

2) スライドのサイズ＞ユーザー設定のスライドサイズ を選択

![サイズの変更.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/875694/00e89a24-d538-1707-8bff-f802703e5912.png)

3) 1024ピクセルx500ピクセルをcmに直す必要がある。
　 デフォルトの解像度は96dpiのようなので、幅27.09cm 高さ13.23cmに設定。

※デフォルトの解像度はオプション＞詳細設定＞イメージのサイズと画質 から確認できます。
※解像度が違った場合は、ピクセルをcmに変換できるサイトがあるのでそこでdpiを変更して単位を変換してください。


![スライドサイズ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/875694/6a519cd1-343f-3018-58b5-98e921a07e09.png)

4) 最大化を選択

![最大化.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/875694/e2de2912-49bf-dc6d-841a-5a5534386a8e.png)

5) 1ページの幅と高さに合わせて画像を作成しPNGまたはJPEGとして該当ページのみ保存。

![サンプル.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/875694/e73b4828-cf4b-f163-619c-e4b6caf81a45.png)

6) 保存した画像のプロパティを開き、大きさが1024x500になっていることを確認。

![Testプロパティ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/875694/533a417f-a057-6b53-4b54-ef6e010b6a86.png)

完成！
[備忘録]Nuxt.jsでgenerateする場合はssr:falseにしないとレイアウトが正しく動作しない

ローカルでは`nuxt`で動確していて、本番環境では`nuxt generate`したものを[@nestjs/serve-static](https://docs.nestjs.com/recipes/serve-static)で配信するようにしていたんですが、ローカルと本番で挙動に違いがあったので、調べてみました。

# やりたいこと

- ログイン画面のレイアウト（layouts/no-auth.vue）
    - ヘッダはロゴのみ
- ログイン後の画面のレイアウト（layouts/default.vue）
    - ヘッダにログアウトボタン追加
    - サイドメニューを表示 

layouts/default.vueで認証されてなければログイン画面にリダイレクトする処理を入れてたのですが、本番環境だとログイン画面への無限リダイレクトが発生してしまいました。

ログイン画面で`layout: 'no-auth'`を指定しているにも関わらずlayouts/default.vueが呼ばれていました。

# 回避策

真の原因はよくわかってないですが、`ssr: false`でSSRを無効にすることで発生しなくなりました。

```nuxt.config.js
export default {
  target: 'static',
  ssr: false,
```

# 参考

https://qiita.com/Grandpa/items/cf62c60c49fe4f5df4f1#ssgstatic-site-generation%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6
ずっとFPGA初心者（その13：ボタン長押し）

# VHDLでボタンの長押しと短押しを検出
ボタンの長押しと短押しとをロジック的に実現する。深い意図はなく、何かに役に立つかどうかも考えていない。

## 環境
[その１](https://qiita.com/infinite1oop/items/4b0f03b97ed859fbd954)と同じOdyssey MAX10 FPGA Eval KitおよびQuartus利用。

## サンプル
長押しと短押しとで、異なるLEDを用いて、押下状況を把握する。ここでは、2秒以上押された時、長押しとした。

### ソースコード
```vhdl:LongPush.vhd
library ieee;
use ieee.std_logic_1164.all;

entity LongPush is
  port (
	CLK, BTN : in  std_logic;
    LED0, LED1 : out std_logic);
end;

architecture RTL of LongPush is
constant CYCLE : integer := 2*50000000;  -- 2 seconds (50MHz)  -- ①
signal CNT : integer range 0 to CYCLE-1 := 0;  -- ②
signal TWOSEC : integer := 0;  -- ③
signal BtnFlag : std_logic := '0';                -- Off  -- ④
signal LED: std_logic_vector(1 downto 0) := "11"; -- Off  -- ⑤

begin
  LED0 <= LED(0); LED1 <= LED(1);  -- ⑥

  process (BTN, TWOSEC)  -- ⑦
  begin
--    if (BTN'event and BTN='0') then -- NG  -- ⑧
    if (BTN='0') then    -- Pushed  -- ⑨
		BtnFlag <= '1';    -- On
		LED(0) <= '0';     -- On
		if (TWOSEC > 0) then  -- Over 2 sec
		  LED(1) <= '0';      -- On
		else
		  LED(1) <= '1';      -- Off
		end if;
    else                 -- Not pushed  -- ⑩
	   BtnFlag <= '0';    -- Off
	   LED(0) <= '1';     -- Off
	   LED(1) <= '1';     -- Off
    end if;
  end process;
  
  process (CLK, BtnFlag)  -- ⑪
  begin
    if (BtnFlag = '1') then  -- ⑫
      if (rising_edge(CLK)) then
        if (CNT = CYCLE-1) then
          CNT <= 0;
		  TWOSEC <= TWOSEC+1;
        else
          CNT <= CNT+1;
        end if;
      end if;
    else  -- ⑬
	   CNT <= 0;
	   TWOSEC <= 0;
	end if; 
  end process;
end RTL;
```

- ①：2秒の定義
- ②：クロック用カウンタ
- ③：2秒経過フラグ
- ④：ボタンフラグ
- ⑤：LEDフラグ（1:Off, 0:On）
- ⑥、⑦、⑪：同時処理
- ⑥：信号LEDへのLEDフラグ代入
- ⑦：ボタン押下時および2秒経過フラグ変化時の処理
- ⑧：⑨の代わりに用いると文法エラー
- ⑨：ボタン押下時、ボタンフラグOn、LED0 On、2秒経過時にはLED1 On
- ⑩：ボタン非押下時、ボタンフラグOff、LED0およびLED1はOff
- ⑪：クロック変化時およびボタンフラグ変化時の処理
- ⑫：ボタン押下時にクロック毎にカウンタインクリメントおよび2秒経過時に2秒経過フラグOn（インクリメント）
- ⑬：ボタン非押下時、カウンタおよび2秒経過フラグの初期化


### ピンアサインメント
![ピンアサイン.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/bf52693f-2cd9-e735-ca87-8de15ead4dd1.png)
コード上のLED0はボード上もLED0にアサインしているが、LED1はボード上ではLED4にアサインしている。

### 実験
#### 短押し
LED0のみ点灯。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/25715681-2235-d597-ea8d-ed8d564551a3.png", width=60%>

#### 長押し
LED0およびLED4が点灯。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/5b897c14-5a47-985e-147a-ede45c5030ff.png", width=60%>
【実践的】データベースから月間会員登録者数をSQLのSELECT文で作って抽出してみた。

##はじめに
どうも、未経験からエンジニア転職を目指しているもきおです。

おそらく自社開発企業などで自社サービスのデータ分析をするとき、「月別の月間登録者数割り出しといて」みたいな感じで頼まれる事ってありそうな気がするんですよね。

えっ、そんなことねえよって？
ある程にしてください、お願いします笑

今回はSELECT文を使用しどうやって月間登録者数をグループ化し抽出するのかをまとめていきたいと思います。

##最終目標物
最終的に作りたいSQLクエリ結果はこちら
![スクリーンショット 2021-10-02 6.17.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1089852/af714235-e13d-b380-0e57-f838120463f6.png)
こんな感じで月別に会員登録者数を集計したものを算出してます。

##まず最初にやる事
SQL文を作成するにあたってまず最初に行うことはテーブル構造の把握です。
テーブル構造を把握した上で目標結果に対しどういったSQL文を作成したら良いのかを考えていきます。

```bash:SELECT*で全体を表示
SELECT * FROM テーブル名 LIMIT 5;
```
構造だけ把握すればいいので LIMITで5件のみを抽出しております。
###結果はこちら
![スクリーンショット 2021-10-02 6.28.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1089852/018e5a6f-236d-3cc4-cd5a-d87bd61861e1.png)
月間の会員登録者数を抽出したいのでcreated_atカラムに着目すれば良さそうです。
今回は月別なので曜日と時間は必要ありません。

よってこのcreated_atのフォーマットを変更→それを月別に集計→月別にまとめて表示という流れでSQL文を作成してみました。

##最終的に作成したSQL文はこちら
```bash:SQL月間会員登録者数集計
SELECT 
  DATE_FORMAT(created_at, '%Y-%m') AS by_month, 
  COUNT(*) AS count
FROM
  テーブル名
GROUP BY
  DATE_FORMAT(created_at, '%Y-%m')
ORDER BY
  by_month
;
```
①まずDATE_FORMATというものを使用しcreated_atのフォーマットを2020-07のような感じに変更してます。
②変更したフォーマットをby_monthというカラム名にASで指定
③それを集計
④GROUP BYを使用し月別にまとめる
⑤ORDER BYで月を昇順で表示

こんな流れでしょうか。

##最終成果物
![スクリーンショット 2021-10-02 6.17.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1089852/af714235-e13d-b380-0e57-f838120463f6.png)
月別の会員登録者数を抽出できました！
ちなみに登録者数多い順とかにするなら

```bash:月間登録者多い順
SELECT
  DATE_FORMAT(created_at, '%Y-%m') AS by_month,
  COUNT(*) AS count
FROM
  テーブル名
GROUP BY 
  DATE_FORMAT(created_at, '%Y-%m')
ORDER BY 
  count DESC
;
```

このような感じでORDER BYにおいてcountをDESC(降順に並べ替える句)で指定すると以下のような感じになります。
![スクリーンショット 2021-10-02 7.04.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1089852/a208981f-2a85-ef52-2eda-0b727c6c216e.png)

##あとがき
いかがでしたでしょうか？
今回は企業でのデータ分析においてやりそうなことを勝手に想像して作成してみました笑

転職活動に励みたいと思います。

最後までご覧いただきありがとうございました！
この記事が少しでも良いと感じていただけましたらLGTMポチッとしていただけますと幸いです。

他にもSQL関連の記事書いているのでよければご覧ください！

https://qiita.com/mokio/items/6aa443de4758a774f356

https://qiita.com/mokio/items/6a4a76c7d4c962860ea4
Typescript - Hello World

Typescriptをはじめたいと思います。
Node.jsをインストールしていない場合はインストールします。

https://nodejs.org/ja/

# プロジェクト作成

Node.jsのプロジェクトを作成します。

```
npm init -y
```

続いて、typescriptパッケージをインストールします。

```
npm i -D typescript
```

# 実装

次のソースコードを作成します。

```ts:hello.ts
console.log("Hello world!");
```
コンソールにHello worldを表示せよという命令です。

# 実行

ソースコードをコンパイルします。

```
npx tsc hello.ts
```

同じディレクトリに`hello.js`が生成されているはずですので、これを実行します。

```
node hello.js
```
「Hello world!」と表示されたら成功です。

# 参考

Typescript - The Basics
https://www.typescriptlang.org/docs/handbook/2/basic-types.html
kustomization.yamlのimagesを使ってマニフェストのimageを指定する

# 目的

KubernetesやOpenShiftのマニフェスト管理にKustomizeを使っている場合、イメージの指定をdeployment等の個別YAMLに書かずにkustomization.yamlで指定することができるようになっていました。そのやり方を試してみます。

# 手順

```kustomize/base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

commonLabels:
  app: sample

resources:
- deployment.yaml

images:
- name: sample-image
  newName: nginx
  newTag: latest
```

```kustomize/base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sample-deployment
spec:
  template:
    spec:
      containers:
      - name: sample-container
        image: sample-image
```

では、kustomizeを実行してみます。

```
$ oc kustomize kustomize/base/
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: sample
  name: sample-deployment
spec:
  selector:
    matchLabels:
      app: sample
  template:
    metadata:
      labels:
        app: sample
    spec:
      containers:
      - image: nginx:latest
        name: sample-container
```

deployment.yamlでは``sample-image``で書かれていた箇所がkustomization.yamlで定義した``newName``と``newTag``に自動的に書き換わっていることがわかります。

次に、kustomization.yamlをKustomize CLIで書き換えてみます。これはocやkubetlのビルトインkustomizeではなく、Kustomize CLIを使う必要があります。下記のコマンドを実行します。

```
$ pushd kustomize/base/
$ kustomize edit set image sample-image=nginx:1
$ popd
```

kustomization.yamlが書き換わっていることがわかります。

```kustomize/base/kustomization.yaml
...
images:
- name: sample-image
  newName: nginx
  newTag: "1"
```

```
$ oc kustomize kustomize/base/
...
    spec:
      containers:
      - image: nginx:1
        name: sample-container
```

> （注）
kustomize editはカレントディレクトリのkustomization.yamlしか変更できません。

# 感想

CI/CDパイプラインでKustomizeを使ってデプロイをするとき、従来ですとdeployment.yaml等を書き換える必要がありましたが、この機能を使うことでkustomization.yamlの書き換えで済むようになりました。環境依存値はdeployment.yaml等リソースに個別に記述するべきではないので、こちらの方がしっくり来ました。
mtailで「文字列がマッチしない場合」という否定条件を作る

## 概要
golangの正規表現では文字列がマッチしない否定文(Negative look ahead and behind)がサポートされていない。

そもそも肯定でも否定でも、`(?`を使うと以下のようにエラーになる。

- error parsing regexp: invalid or unsupported Perl syntax: `(?=`
- error parsing regexp: invalid or unsupported Perl syntax: `(?!`

[mtail](https://github.com/google/mtail)というgolangで書かれたログ収集ツールを使っていて、「特定の文字列がマッチしない場合ログを収集する」という条件を付けたいのだが、当然これもサポートされていないし、mtailではgolangそのものを書けるわけではないので、正規表現以外の方法がない。
https://github.com/google/mtail/issues/18

これをどうにか解決した記録。

## 関連
https://qiita.com/Esfahan/items/7fdef62746e0c7bf16c4

## やりたいこと
文中にERRORを含むがAAAAを含まない、という条件を作りたい。

| Text | Matched |
| --- | :--: |
| This is an ERROR. | true |
| This is an ERROR and AAAA. | false |
| This is an ERROR and BBBB. | true |

## 通常の正規表現で書くと
通常の正規表現で書くとこんな感じ。

```
/^(?=.*ERROR)(?!.*AAAA).*$/
```

https://qiita.com/Esfahan/items/b8bc6504f66b3941d5f2

## mtailでの実現方法
以下のように、条件を入れ子にして、elseを使うことで実現した。

```
counter error_count

/^.*ERROR.*$/ {
  /^.*AAAA.*$/ {
  } else {
    error_count++
  }
}
```

否定条件を複数書く場合は以下。
文中にERRORを含むがAAAAもBBBBも含まない。

```
counter error_count

/^.*ERROR.*$/ {
  /^.*AAAA.*$|^.*BBBB.*$/ {
  } else {
    error_count++
  }
}
```

以上
日記；回すだけII ③GUIツールTMCM-CANopen  Profile positionと Profile Velocity Mode


###Profile position mode
　このProfile position modeは、速度（Profile Velocity）と加速度（Profile acceleration）、減速度（Profile deceleration）と目標位置（Target position）を決めたら、そこまで勝手に加速、減速して止まるという動作をします。
　TMCM-CANopen Revision V1.5.0.0の最初の画面です。
![t101.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/fad974b1-c518-b9b4-c032-71d4243a9c3e.png)
　Connectをクリックすると、左のエリアにメニューが並びます。xxxx.xxxxは読み出した型番です。本来ならPD42-1270と書かれているはずなのですが。

![t102.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/74830b52-47d9-7bcf-39d5-a00970d68b4f.png)

　NMT（Network management）のタブをクリックし、Syncにチェックを入れ、Startを押し、Pre-Opを押します。これで、CANopenが動き始めました。
　Object Browser、CiA-402 State Machine、CiA-402 Profile Position Modeの三つを立ち上げて右側のエリアに並べます。
　IXXAT connectionの画面で、Reset Applをクリックします。
　Object Browserの画面でIndex 2005を選択し、Writeのボタンの左に3を入れ、Writeボタンをクリックします。これは、リミット・スイッチを無効にする設定です。今回はリミット・スイッチを用意しているのですが、この設定をしないとうまく動きませんでした。
　Object Browserの画面でIndex 6060を選択し、Writeのボタンの左に1を入れ、Writeボタンをクリックします。これは、Profile position modeの選択です。

![t102a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/ae6136ec-873c-4359-d164-88c0012c5f8e.png)

　CiA-402 State Machineの画面で、Switch on disable、Ready to switch on、Switched on、Operation enabledを次々と押していきます。Switch on disableがグレイでReady to switch onが生きている場合は、Ready to switch onから順に押していきます。
　最終的な状態Current Stateを、Operation enabledに移行します。
![t104.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/6f5f9c6f-f72c-c4cc-a459-521cab6b864f.png)
　
　CiA-402 Profile Position Modeの画面で、Cyclic Pollingをチェックすると、表示が常に更新されます。
　607A Target positionに100000とか適当な数値を入れ、リターンを押します。最後に Move absoluteボタンを押すと、6064 Actual Positionを更新しながら回転します。
　最後は、607A Target positionに入れた数値まで回転して止まります。
![t105.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/d7163c59-52af-5e28-43a7-dd164812c604.png)

　Move relativeボタンを押すと、ここでは6064 Actual Positionが20000まで回転します。

###Profile Velocity Mode

　左のエリアにあるCiA-402 Profile Velocity Modeをクリックします。Profile Velocity Modeは、加減速を自分で設定できるモードです。Target velocityに設定する数値が大きいほど、高速に回転します。
![t300.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/fde17489-be71-2fb3-5da9-11a00345b804.png)
　前記のProfile position modeと手順は同じです。

① IXXAT connection画面のNMTタブで、Syncにチェックを入れ、Startをクリック、Pre-Opをクリック、Reset Applをクリック
② Object Browser画面でIndex 2005を選択し、Writeのボタンの左に3を入れ、Writeボタンをクリック
③ Object Browser画面でIndex 6060を選択し、Writeのボタンの左に1を入れ、Writeボタンをクリック
④ CiA-402 State Machineの画面で、Switch on disable、Ready to switch on、Switched on、Operation enabledを次々とクリックしていく。Switch on disableがグレイでReady to switch onが生きている場合は、Ready to switch onから順にクリック
⑤ CiA-402 Profile Velocity Modeの画面で、Cyclic Pollingをチェック
⑥ CiA-402 Profile Velocity Modeの画面で、60FF Target velocityの欄に60000リターン
⑦ 矢印などのボタンを押すと、606C Actual verocityの値がTarget velocityの設定値まで加速し、その後定速で回転する。絶対位置はCiA-402 Profile Position Modeの画面に表示されている

　CiA-402 Profile Position ModeとこのCiA-402 Profile Velocity Modeは、この設定で、どちらも同時に利用できます。
WSR-5400AX6SでIPv4 PPPoEとIPv6 IPoEを共存させる

## はじめに
IPv6を使いたいけどIPv4はIPoE (IPv4 over IPv6) にしたくないというニッチな向け人の備忘録です。
この方式を取ることで一定の恩恵がある人はいますが自分で何とかできない人は実施しない方が良いかも。自己責任でお願いします。

設定のバックアップをして元に戻せるようにしておくと良いかもしれません。

## なぜそうしたか
10/1に「WSR-5400AX6S」が届いたのですがそれ以前はIPv4/IPv6ともにIPoEでした。（※OCNバーチャルコネクト）  
IPv4をIPoE (IPv4 over IPv6) にすることでIPv4 PPPoEに比べてIPv4の通信が高速になるケースはあるのですが以下のデメリットがあるためです。  

- IPv4グローバルIPアドレスを複数人で共有する事になる
- IPv4グローバルIPアドレスは固定になる (MAP-Eの場合)
- ポート開放の自由度が低い

また、IPv6を引き続き使いたいのはIPv6で提供されているサービスを引き続き使いたいためです。

## 具体的な設定について
1. WSR-5400AX6Sの筐体についているモード変更のできる物理スイッチをManualにします。  (すでにManualならOK)  
1. WSR-5400AX6SのWeb管理画面にアクセスします。
1. 画面左部のメニューからPPPoEの設定画面に飛んでPPPoEの設定を入れます。 (IPv4の設定)
1. 画面左部のメニューからInternetの設定画面に飛んで「PPPoEクライアント機能を使用する」の設定を入れます。
1. 以下のIPv6の設定を反映させます。
  1. 画面左部のメニューからIPv6の設定画面に飛んで「インターネット＠スタートを行う」にチェックを入れます。
  1. IPv6ブリッジを許可するのチェックを外します。 (※必要ならチェックを入れたままで大丈夫です。)

## 最後に
IPv4 PPPoEでもISP側がキャリアグレードNATしているケースなどは大差ない可能性はあるので書いておきながら好みの問題かもしれません。

IPv4 PPPoEでまた通信速度がどうしても耐えられなくなればIPoE (IPv4 over IPv6) に戻すか、ルータをさらに増やしてIPv4 PPPoEとIPoE (IPv4 over IPv6) を共存させるという構成を取る可能性があります。そこまでするならYAMAHAルータ等一台でそれが可能な構成にしてしまうかもしれません。
devise_token_authの認証Headersのサンプルについて

# devise_token_authとは
***新規登録やログイン、ログアウトなどを実装するときに使うgem***です。
***deviseというgemを使えば上記のようなユーザーの認証機能を実装***できます。


●公式ドキュメントです。

https://devise-token-auth.gitbook.io/devise-token-auth/

# Headersとは
本題ですがdevise_token_authの中でもHeadersというものがあります。
このheaderにアプリの操作などをするときにユーザーの認証情報を送り、
アプリを動かすことができます。

Headersはpostmanの中でも確認できます。

https://www.postman.com/

# headerの認証サンプル
headersの中には認証サンプルがあります。
公式ドキュメントに載っているものを紹介します。

●***access-token***
リクエストごとに```認証パスワードとして使用```されます。
この値のハッシュなどはデータベースに保管されるみたいです。

⚫︎***client***
それぞれ違うクライアント(リクエストを送る側)が同時に
```session(通信などの処理の流れ)を管理できるもの```です。
pcと携帯で同時認証を受けたいときに使うみたいです。

⚫︎sessionのわかりやすい説明はこちら

https://wa3.i-3-i.info/word1791.html

⚫︎***expirly***
```sessionの失効日```です。
クライアントがAPIのリクエストを期限切れのトークンとして無効にするためのものです。

●***uid***
ユーザーを識別するためのものです。
なぜこの機能があるかというと```timing attack```を防止するためのものです。
timing attackとはサイドチャネル攻撃といって、暗号鍵などを推測する手法みたいです。

https://securitychecklist.net/security/cyber-attack/timing-attack.html


# まとめ
今回紹介したのはdevise_token_authの一部です。
公式ドキュメントや下の参考資料からいろいろと調べてみてください。


# 公式ドキュメントの和訳
https://sainu.hatenablog.jp/entry/2018/08/11/194319

# 参考資料
https://qiita.com/tomokazu0112/items/5fdd6a51a84c520c45b5
CoroutineScops完全に理解した。

 完全に理解したからイケてるコードを書こうと思ったら、完全に理解してない箇所が出てきた。調べてもドンピシャに解決する記事がなかったので、自分でイケてるコードを検証したみた。

## 検証で使ったコード
``` kotlin
import kotlinx.coroutines.*
import kotlin.coroutines.CoroutineContext

class Hoge(private val context: CoroutineContext) : CoroutineScope {
    override val coroutineContext: CoroutineContext
        get() = context // + Job() or + Job(context.job)

    fun start() {
        launch {
            while(true) {
                println("hoge")
                delay(1_000)
            }
        }
    }
}

suspend fun main() {
    val context = Job() as CoroutineContext
    val hoge = Hoge(context)
    hoge.start()
    val job = hoge.coroutineContext.job

    context.cancel()
    job.join()
}

```

 コメントがある行(#6)をコメント通りに変更すると、Hoge#start()で実行したlaunch()の生死が変わる。

## そのまま実行

 Hogeクラスのコンストラクタで受け取ったCoroutineContextをそのまま使うので、start()のlaunch()で元のCoroutineContextに内包されるJobから直接子Jobが生成される。
 start()では、元のCoroutineContextのJobからlaunch()したときと同じ状況であり、当然元のCoroutineContextをキャンセルすればstart()で生成されたJobは停止し、プログラムは終了する。

## `+ Job()`

 Job()の第一引数には親Jobを指定することができるが、何も指定しないと独立したJobが生成される。
 また、CoroutineContextのplus()に他のCoorutineContext(Jobもこれのサブクラス)を渡すと、元のCoroutineContextの各要素がもう一方のCoroutineContextが所持している要素によって上書きされる。
 そのため、`+ Job()`をコードに加えると、独立した新しいJobが元のCoroutineContextが持っているJobに取って代わり、よって元のCoroutineContextがキャンセルされてもHogeで開始されたJobは動き続き、コンソールには`hoge`が繰り返し表示される。

## `+ Job(context.job)`

 親Jobを指定したため、Hoge自体のJobは子Jobであり、start()で生成されたJobは孫Jobになる。
 元のCoroutineContextをキャンセルすれば、孫Jobにもキャンセルが伝播しプログラムは終了する。

## まとめ
　いつの間にかCoroutineContextとJobのお話になってしまいました。
　適切にCoroutineScopeを分割することで、なにかいいことがある気がする。

　蛇足になりますが、上記のやり方は少しだけ面倒なので、何か特別な操作を必要としない場合は`class Hoge(context: CoroutineContext) : CoroutineScope by CoroutineScope(context + Job(context.job))`に書き換えるととても便利です。
【Ruby】奇数か偶数かを判断するメソッド



- Inetger#odd?は奇数であればtrue、そうでなければfalseを返します。
- Inetger#even?は偶数であればtrue、そうでなければfalseを返します。

### 奇数かどうか
``` 
5.odd? =>  true
10.odd? => false
```

### 偶数かどうか
```
10.even? => true
5.even? => false
```
【Swift】Eurekaの画像サイズを大きくする法法

## 課題
Swiftのフォームライブラリ「Eureka」のImageRowの画像サイズが小さいと感じたが、大きくする方法がなかなか見つからず苦戦したのでメモとして残しておきます。

https://github.com/xmartlabs/Eureka


## 解決コード

```swift
    <<< ImageRow() {
        //セルの高さ
        $0.cell.height = { 120 }
        //表示させる画像のframe
        $0.cell.accessoryView?.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
        //任意で角丸を設定（無くても良い）
        $0.cell.accessoryView?.layer.cornerRadius = 2
        $0.cell.accessoryView?.clipsToBounds = true

        $0.title = "画像"
        $0.sourceTypes = [.PhotoLibrary, .SavedPhotosAlbum, .Camera]
        $0.clearAction = .yes(style: .destructive)
        $0.placeholderImage = UIImage(named: "dummy")
        $0.onChange { [unowned self] row in
            self.ImageView.image = row.value ?? UIImage(named: "dummy")
        }
    }

```
accessoryViewで設定するのがミソ。

## ビフォーアフター

標準の画像サイズと比較するとご覧のようにかなり見やすくなっている。

・ビフォー
![Simulator Screen Shot - iPhone 11 Pro - 2021-10-02 at 01.54.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/522445/d48a329f-5080-d6b6-4f9a-65e4b1931426.png)
・アフター(セル120px,画像100px)
![Simulator Screen Shot - iPhone 11 Pro - 2021-10-02 at 01.54.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/522445/517eeb8a-041c-d73e-fa9d-99fda4f6ebc7.png)

## おすすめ情報

https://wagtechblog.com/programing/swift-iphone-application-school

https://wagtechblog.com/programing/swift-textbook.html
[Go] Consume Kafka Message

A example to consume kafka message with golang and confluent.

```go
package main

import (
	"log"

	"github.com/confluentinc/confluent-kafka-go/kafka"
)

func main() {
	c, err := kafka.NewConsumer(&kafka.ConfigMap{
		"bootstrap.servers": "localhost:9092",
		"group.id":          "myGroupId",
	})

	if err != nil {
		panic(err)
	}

	c.SubscribeTopics([]string{"quick-start-event"}, nil)

	for {
		msg, err := c.ReadMessage(-1)
		if err == nil {
			log.Println(string(msg.Value))
		} else {
			log.Fatal("Can not consume message", err)
			break
		}
	}

	c.Close()
}
```

For more information about confluent kafka go please see here.
https://github.com/confluentinc/confluent-kafka-go
Quillで入力した画像をjsで取得する方法

# 結論
以下のように取得したDELTA形式のデータをJSONとして扱い、画像データ部分を取得する。

``` javascript:概念コード.js
var quill = new Quill();
var contents = quill.getContents();//エディタに入力されている全内容の取得 DELTA形式

var img = new Image();
img.src = contents["ops"]["insert"]["image"] //DELTA形式はJSONと同様に扱えばいい
```

# [Quill](https://quilljs.com/)って？
Ctrl＋Vによる画像貼り付けにも対応したWYSIWIG テキストエディタ のインターフェースです。
簡単なhtml+jsで以下のようなテキストエディタUIをWEBページに埋め込むことができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26413/31177ba8-b49e-9559-9891-828daf624729.png)

例えば以下HTMLを作成し、ブラウザで開けます。簡単！！

# 入力データの取得とDELTA形式
入力データは getContents() によりデルタ形式で取得をします。

DELTA形式のデータは JSONの厳密なサブセット と[記載があります](https://quilljs.com/docs/delta/)。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26413/3df42882-d32a-f626-0bc1-1ea6beef09d3.png)


# サンプルコード
submit ボタンを押すと、入力されている画像をページ上部に表示するサンプルページをつくりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26413/2536c661-c8ab-5e84-dd1c-b1c8402ed682.png)

```javascript:quill.html
<html>
<header>
	<link href="https://cdn.quilljs.com/1.3.6/quill.snow.css" rel="stylesheet">
</header>
<body>
<div id="editor">
	<p>Hello Quill!</p>
	<div id="imageput"></div>
</div>
<form>
	<input type="button" onclick="click_action();" value="submit" />
</form>
<div id="edit"></div>
<script src="https://cdn.quilljs.com/1.3.6/quill.js"></script>
<script>
  var quill = new Quill('#edit', {
    theme: 'snow'
  });

//=====================================================
//以下より拝借
//https://qiita.com/yasumodev/items/e1708f01ff87692185cd
// Base64形式の文字列 → <img>要素に変換
//   base64img: Base64形式の文字列
//   callback : 変換後のコールバック。引数は<img>要素
//=====================================================
function Base64ToImage(base64img, callback) {
    var img = new Image();
    img.onload = function() {
        callback(img);
    };
    img.src = base64img;
}

function click_action(){
	var content = quill.getContents();
	console.log(content);
	content["ops"].forEach((c) => {
		console.log(c);
		if('insert' in c){
			if(typeof(c["insert"]) === "string"){
			}
			else if('image' in c['insert']){
				console.log("GET IMAGE");
				Base64ToImage(c["insert"]["image"], function(img) {
				// <img>要素としてDOMに追加
				document.getElementById('imageput').appendChild(img);
				// <img>要素にすることで幅・高さがわかります
				var log = "w=" + img.width + " h=" + img.height;
				document.getElementById('log').value = log;
				});
			}
	}
	});
}
</script>
</body>



</html>
```


# 情報源
感謝！！
- [[JavaScript] 画像変換：<img>要素 ⇔ Base64（相互変換）](https://qiita.com/yasumodev/items/e1708f01ff87692185cd)
- [Quill公式 getContents](https://quilljs.com/docs/api/#getcontents)
- [DELTA形式について](https://quilljs.com/docs/delta/)
- [GitHubでスターが多いWYSIWYGエディタ（2019年11月）](https://qiita.com/mima_ita/items/bacf3ca3c078d1e6c70f)
googlemapのルートを作る

##googlemapのルートを作る



```jquery:jquery

$(function() {
    $('#inputOne,#inputTwo').on('input', function() {
        var inputOne = $('#inputOne').val();
	    var inputTwo = $('#inputTwo').val();
        $('#link').attr('href', 'https://www.google.com/maps/dir/?api=1&origin=' + inputOne + '&destination=' + inputTwo + '&travelmode=transit');
    });
});


```


ーーーーーーーーーーーーーーーーーーーーーーー

参考にしました


https://qiita.com/hiron2225/items/8d5cd1b6728b4d63434b
Wacomのペンタブをlinuxで使う方法

# 概要
WacomのペンタブをLinuxでも利用したいと思ったが、ドライバ関係でハマったので手順を記載する。

# Wacom の pentab 
[Wacomのページ](https://support.wacom.com/hc/ja/articles/1500006331202-Wacom%E3%81%AB%E3%81%AFLinux%E3%82%92%E3%82%B5%E3%83%9D%E3%83%BC%E3%83%88%E3%81%99%E3%82%8B%E3%82%BF%E3%83%96%E3%83%AC%E3%83%83%E3%83%88%E3%83%89%E3%83%A9%E3%82%A4%E3%83%90%E3%81%8C%E3%81%82%E3%82%8A%E3%81%BE%E3%81%99%E3%81%8B-)にあるように、大抵のLinuxにはWacomドライバーが標準搭載されている。また、搭載されていない場合でもyumやaptでインストールが可能となっている。

## 使用環境
- OS：RHEL8系 (Almalinux)
- デスクトップ：Gnome環境
- パッケージ管理：yum (dnf)
- ペンタブ：Wacom Intuos S (CTL-4100)

# ドライバーインストール手順

雑だが、下記のコマンドでインストールできる

```sh
$ yum install *wacom*
```

そして、ペンタブをUSB接続すると、ペンタブを認識していることがわかる。  
しかしなぜか、ペンタブの全域が認識されず、左側でしかペンが動かせない状態になってしまっていた。

そこで、ドライバ設定を以下のコマンドで確認する

```sh
$ libwacom-list-local-devices

[Device]
Name=Wacom Intuos S (Android Mode)
ModelName=CTL-4100
DeviceMatch=usb:2d1f:0374
Class=Bamboo
Width=2
Height=4
Layout=intuos-s-p3.svg
IntegratedIn=
Styli=@intuospt3;
...
```

なんと、Android Modeで認識されているではないか。  

# 設定ファイルの上書き
Wacom driverの設定ファイルは `/usr/share/libwacom/`に存在する。
中身を比較してみると、現在認識されているファイルは、`/usr/share/libwacom/intuos-s-p3-android.tablet`
が利用されているようだ。

これではなく`/usr/share/libwacom/intuos-s-p3.tablet`が認識されてほしい。

そこで、とりあえず、
`/usr/share/libwacom/intuos-s-p3.tablet` のDeviceMatchを`/usr/share/libwacom/intuos-s-p3-android.tablet`のものに書き換えてみる。

```sh
[Device]
Name=Wacom Intuos S
ModelName=CTL-4100
DeviceMatch=usb:056a:0374 # ここを書き換える
Class=Bamboo
Width=6
Height=4
Layout=intuos-s-p3.svg
IntegratedIn=
Styli=@intuospt3;
```



すると、正しく認識されるようになった。


# その他
- デバイスのボタンの一番左と一番右のボタンを押し続けてリセットをすると解決できることもあるそう。
- wacomライブラリの再インストールを行っても解決するかもしれないが、私の場合
  `yum remove *wacom*`とすると、X serverのコンポーネントまで消されてしまったので、注意して行ったほうがよい。
SSLとTLSについて

# はじめに
本記事では、`SSL`と`TSL`について記述します。

# SSL
インターネット上で`データを暗号化`し、解読が困難な状態にし、`送受信する仕組み`です。
`盗聴`、`改竄`、`なりすまし`を防止するためにあります。

例えば、旅行サイトなどで、
メールアドレスやクレジットカードを登録した場合、
`SSL化`されていれば、悪意のある第三者から見られること恐れはなくなります。

### WEBサイトでは
`http`か`https`かどうかで区別します。

`https`がSSL化されています。

`Heroku`などのプラットフォームでは、
`https://＜アプリの名前＞.heroku.com/`となっていることから、
この点においては安全と言えると思います。

独自にサーバーを契約してデプロイする場合は、自分自身で`SSL化`をする必要があるようです。
以下のようなサイト↓
[https化（常時SSL化）とは？メリットや導入方法を画像付きで詳しく紹介【Xサーバー・ロリポップ編】](https://service.plan-b.co.jp/blog/seo/22408/)

以下のサイトでは、このようなことも書かれておりました。
[SSL/TLS総合解説サイト](https://www.sslcerts.jp/)
> 多くのユーザが安全に情報を通信するために、SSL/TLSは多くのウェブサイトで採用されています。
2014年に大手検索サイトのGoogleは、ユーザが安全にサイトを閲覧できるようなユーザ保護の観点から、
SSL/TLS実装の有無を検索結果の基準の1つとすることを発表しました。
SSL/TLSを実装して安全性を考慮したウェブサイトが推奨されています。

SSL化しているサイトは、SEOで優遇されるようですね。

# TLS
大きな仕組みは、`SSL`と特に変わりはありません。
`TLS`は`SSL`次世代規格です。

SSLであった脆弱性を解決し、`TLS`へとなりました。

## 歴史
調べたところ、以下のような時系列でした。

|名前|年号|
|-|-|
|SSL1.0|リリース前に脆弱性が発見され公開できず|
|SSL2.0|1994年リリース|
|SSL3.0|1995年|
|TLS1.0|1999年|
|TLS1.1|2006年|
|TLS1.2|2008年|
|TLS1.3|2018年|

`2014年`に、
`SSL3.0`は`POODLE`という重大な脆弱性が発見されました。

```
POODLEとは
「Padding Oracle On Downgraded Legacy Encryption」の略です。
SSLのバージョン3.0に存在する脆弱性(CVE-2014-3566)のことを指します。
```

詳しい内容
[用語解説：オラクル攻撃](https://qiita.com/n-i-e/items/838df87a977fb213bedb)

`SSL3.0`に加え、POODLEにおいて、実装が不十分な`TLS1.0`、`TLS1.1`が、
サーバーとの通信に脆弱性があるとわかり、非推奨となりました。

これにより、
現在では、`TLS1.2`、`TLS1.3`が推奨されております。

以上です。

# 終わりに
SSL/TLS化は、必須ですね。
個人でWEBアプリケーションを作る上でも注意したいと思います。
(独自でサーバー契約する機会はあるのだろうか)

以下参考サイトです。
[相次ぐSSL関連の脆弱性　その2 ～POODLE脆弱性とは～](https://jp.globalsign.com/blog/articles/ssl_poodle_about.html)
[SSLとTLSの違いについて](https://jp.globalsign.com/ssl-pki-info/ssl_practices/ssltls_brittle.html)
[SSL証明書（SSL化）とSEOの効果とは](https://www.seohacks.net/blog/3198/)
[SSL/TLS総合解説サイト](https://www.sslcerts.jp/)
[SSLとTLSとは？意外に知らないSSLとTLSの違い（簡単編）](https://www.idcf.jp/rentalserver/aossl/basic/ssl-tls/)

明日も頑張ります！
【React】useRefを活用して対象要素以外のイベントを捕捉する

## 概要
例えばWeb画面上で、入力や選択操作の途中で他のところをクリックされた時に、イベント捕捉したいということがあると思います。素のJavaScriptだと[JavaScriptで特定の要素以外をクリックした時のイベント【jQuery不要】](https://hirakublog.com/outside-click-event-js/)のように、`addEventListener`を追加し、その中でidやclassで判定をする実装が考えられます。
ではReactで、例えば対象の要素以外がクリックされた時を捕捉したい、という場合はどうすれば良いか。ということで今回の記事になります。

## 対応
[Detect click outside React component](https://stackoverflow.com/questions/32553158/detect-click-outside-react-component/)の記事に色々対応方法が紹介されていますが、個人的にはuseRefを活用した方法が良いかなと感じました。リスナーの中ではrefを指定した要素を取得し、クリックされた要素がrefの要素かという判定を行います。

## 実装サンプル
サンプルで、ヘッダー要素以外がクリックされたかという判定を例にします。

```javascript:Header.js
export default function Header() {
  const headerRef = useRef();

  useEffect(() => {
    document.addEventListener("mousedown", handleClickOutside);
    return () => document.removeEventListener("mousedown", handleClickOutside);
  }, []);

  const handleClickOutside = (e) => {
    if (!headerRef.current.contains(e.target)) {
      alert("ヘッダー以外がクリックされました");
    }
  };

  return (
    <div ref={headerRef}>
     ・
     ・
    </div>
  );
}
```

ヘッダー要素以外がクリックされると、以下のイメージのようにalertが表示されます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32098/2bf8d171-04b8-67b8-e1a9-4a252380956c.png" width="500"/>
ABC81 C - Not so Diverse を解いた

https://atcoder.jp/contests/abc081/tasks/arc086_a

![abc81_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/737344/7405aa7b-807e-7030-ebc7-69245c71b096.png)
![abc81_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/737344/5c6a1ff8-be15-de12-f633-6c9bea14fbee.png)
![abc81_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/737344/3353e747-e0e2-94f3-e8da-6a6695720899.png)
![abc81_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/737344/f130eefd-6d8c-5931-c839-8e239b0bfe02.png)

各要素を数えてみる。
K 種類以下になるまで、要素数の少ない順に足し合わせたら答えになると思った。

```NotSoDiverse.py
N,K = map(int,input().split())
A = list(map(int,input().split()))

dic = {}
for n in range(N):
    if A[n] not in dic:
        dic[A[n]] = 0
    dic[A[n]] += 1

target = len(dic)-K
dic = sorted(dic.items(), key=lambda t:t[1])
#print(dic)
ans = 0
for i in range(target):
    ans += dic[i][1]
print(ans)
```

辞書の sort がいっつも忘れる。

https://www.headboost.jp/python-how-to-sort-dict/

神サイトに感謝
CSS編　CSSの書き方

<h1>CSSの書き方について</h1>
まずCSSを書く前にファイル名の後ろは.cssと書いて下ださい。これでCSSファイルが作成できました。

では本題に入ります、CSSファイルの先頭は＠charset "UTF-8"と書いてください。（書かなくても文字化けにならないかもしれないですが、
一応書いといてください。）

書き方は
Pタグにクラス名がある場合は以下のようになります

```
.Ptag {
//この中に処理を書く
}
```
IDがある場合は以下の感じです。

```
#Ptag {
//処理内容を書く
}
```

クラスもIDも指定してないときはそのままのセレクターを書くようにしましょう。

```
p {
//処理を書く
}
```