OmniAICreator/Qiita-1.07M huggingface dataset:
Active Hash で作ったカテゴリーの中身を一覧表示する

# はじめに
## やりたいこと
- Active Hash で作ったカテゴリー毎に紐付くコンテンツを一覧表示する

# 手順
- ルーティングを設定する
- リンクを作る
- コントローラーにアクションを記述する
- 対応するビューを作る

前提としてActive Hashの導入とモデル/DBまわりの設定は完了しているものとします。


## ルーティングを設定する
Itemモデルにcategory_idを持たせているので次のようにルーティングを設定

```ruby:routes.rb
get '/items/category/:id', to: "items#category"
```

## リンクを作る
リンクを作ります。

```ruby:html.erb
link_to 'hoge', '/items/category/1'
link_to 'fuga', '/items/category/2'
link_to 'piyo', '/items/category/3'

```

ちなみにCategoryモデルはこんな感じの設定

```ruby:models/category.rb
class Category < ActiveHash::Base
  self.data = [
    { id: 1, name: 'hoge' },
    { id: 2, name: 'fuga' },
    { id: 3, name: 'piyo' }
  ]
end
```

## コントローラーにアクションを記述する
categoryアクションを定義します。

```ruby:items_controller.rb
def category
  @item = Item.find_by(category_id: params[:id])
  @items = Item.where(category_id: params[:id]).order('created_at DESC')
end
```

カテゴリーの一覧ページでカテゴリー名を表示するために@itemを定義、eachで展開するために@itemsを定義しています。

## 対応するビューを作る
items配下にcategory.html.erbを作成します。

```ruby:items/category.html.erb
#カテゴリー名の表示
  @item.category.name
#カテゴリーの中身を展開
  @items.each do |item|
    〜中略〜
  end
```

# おわりに

link_toでそれぞれidを渡すことでだいぶ楽に書けたかなと思います。
もしもっと良い方法がありましたら教えてください！

✔︎
axiosのパラメータに配列を指定する方法

##概要
axiosを使用してフロントからAPIコネクタを実装する際、配列(string)をURLのパラメータに追加する方法をまとめました。

https://example.com?id=1 に"name=サンプル&name=なまえ"を追加してAPIに接続する場合について記載します。

#####URLSearchParamsを使用する
```typescript:axios
//URLSearchParamsインスタンス化
const params = new URLSearchParams();

//パラメータを追加
params.append("name", "サンプル");
params.append("name", "なまえ");

axios.get('https://example.com', params);
```
IfcOpenShell python でIFCファイルに壁を追加してみる 

## はじめに
### IFCファイルとは
Industry Foundation Classesの仕様に基づき作成されたファイルのことです。
建設業界にて、建設に使用される要素(壁・窓・ドア・建物設備など)が含まれます。そのためIFCファイルがあれば、ビジュアライズアプリなどを用い3Dでビルを再現することも可能です。

### スコープ
・環境構築
・既存のIFCファイルを読み込む
・サンプルの壁を追加する
・新しいIFCファイルとして出力する

## 環境構築
### IfcOpenShellのダウンロード
```shell
conda install -c conda-forge -c oce -c dlr-sc -c ifcopenshell ifcopenshell
```
### pythonocc-coreのインストール
```shell
conda install -c conda-forge -c dlr-sc -c pythonocc -c oce pythonocc-core
```

## IFCファイルに壁を追加する
```py
import ifcopenshell
from ifcopenshell import geom

settings = ifcopenshell.geom.settings()
settings.set(settings.USE_PYTHON_OPENCASCADE, True)

# 既存のIFCファイルを読み込む
ifc_file = ifcopenshell.open("sample.ifc")

# 新規作成する壁のテンプレートを読み込む
sample_wall = ifc_file.createIfcWall()

# 座標を設定する
context = ifc_file.by_type("IfcGeometricRepresentationContext")[0]
point1 = ifc_file.createIfcCartesianPoint((0.0, 0.0, 0.0))
point2 = ifc_file.createIfcCartesianPoint((5.0, 0.0, 0.0))
ifcpts = []
ifcpts.append(point1)
ifcpts.append(point2)
polyline = ifc_file.createIfcPolyLine(ifcpts)

# 形状を設定する
axis_representation = ifc_file.createIfcShapeRepresentation(context, "Axis", "Curve2D", [polyline])
product_shape = ifc_file.createIfcProductDefinitionShape(None, None, [axis_representation])

# 新規壁を追加する
sample_wall.Representation = product_shape
ifc_file.add(sample_wall.Representation)

# 別ファイルとして書き出す
ifc_file.write("sample_new.ifc")
```

## 参考
・[Creating a simple wall with property set and quantity information](http://academy.ifcopenshell.org/creating-a-simple-wall-with-property-set-and-quantity-information/)
・[Try to create the Wall by myself](https://sourceforge.net/p/ifcopenshell/discussion/1782717/thread/9c6995ab/)
Docker HubのPull制限が順次開始！AWS Nitro Enclaves リリース！Ruby Conference 2020もうすぐ開催！【やっすんのエンジニアNews】【11月2週目】

# はじめに
11月2週目のニュースを独断と偏見で紹介していきます。
3分程度の動画でまとめているので、興味のある方はこちらもどうぞ！

[【YouTube動画】 やっすんのエンジニアNews 11月2週目](https://youtu.be/aoJdMG0uNmM)
[![やっすんのエンジニアNews 11月2週目](https://img.youtube.com/vi/aoJdMG0uNmM/0.jpg)](https://youtu.be/aoJdMG0uNmM)

# Docker Hub Pull回数制限スタート
11/2からDocker HubのPull回数制限が順次スタートしました。

Pull回数制限は未認証ユーザーで100回/6h, 無料アカウントで200回/6hです。
有料アカウントにアップグレードすれば、無制限になります。

<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/751408/aca5cefd-3170-0c5f-6758-ea8b3bcf0641.png' width='650'>

ただ、いくつか条件がありますが、OSSのプロジェクトは適用対象外のようです。

## CircleCIはどうなる？
結論として、CircleCIのDocker Imageを利用している場合と[Executorタイプ](https://circleci.com/docs/ja/2.0/executor-types/)をDockerにしている場合、**しばらくの間** 制限を受けません。

ただ、将来的にどうなるかは不明のため、Dockerの認証はしておいた方が良いかもしれません。

公式ではこちらで紹介しています。
[Docker の認証付きプルの使用](https://circleci.com/docs/ja/2.0/private-images/)

CircleCIのContextと合わせて利用したい場合はこちらの記事も参考になります。
[CircleCIでDocker Hubの制限を回避するための設定](https://qiita.com/sot528/items/30a9728973b3dbca3f76)


また、本件に関する内容はこちらで、以下のサブタイトル部分が回答に相当します。
[Docker Hub rate limiting FAQ](https://support.circleci.com/hc/en-us/articles/360050623311-Docker-Hub-rate-limiting-FAQ)
**I use CircleCI convenience images, does this affect me?**
**I use custom Docker images, does this affect me?**
**I use CircleCI Enterprise (Server), does this affect me?**


# AWS Nitro Enclaves 一般提供開始！
この新サービスはEC2上で金融情報や個人情報などの機密性の高い情報の処理で使うと良いそうです。

<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/751408/9fe26b4c-3b31-287d-d844-f3a5961290a2.png' width='700'>

使うときは、EC2内でnitro-cliをインストールして、Docker ImageをEnclave Image File (.eif) に変換して使うようです。

# Ruby Conference 2020もうすぐ開催！
今回のRuby Conferenceはオンラインで実施されるそうです！
https://rubyconf.org
<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/751408/a37e7401-4199-db51-ca8c-7396a63a07e4.png' width='350'>
Shell scriptで湯婆婆を実装してみた

# はじめに
原作：[Javaで湯婆婆を実装してみる](https://qiita.com/Nemesis/items/c7192a7c510788d2cba2)

世の中では湯婆婆プログラムが大流行中らしい。
このビックウェーブに乗るっきゃないということで
初めてQiitaを書いてみました。

# 実際のコード

```shell:yubaba
set -eu #エラー時に停止するように

echo "契約書だよ。そこに名前を書きな。"
read name
echo "フン。${name}というのかい。贅沢な名だねぇ。"

random=$[RANDOM % ${#name}]
newName=${name:random:1}

echo "今からお前の名前は${newName}だ。いいかい、${newName}だよ。分かったら返事をするんだ、${newName}!!"
```

# 実行例

```
$ bash yubaba
> 契約書だよ。そこに名前を書きな。
> 山田太郎
> フン。山田太郎というのかい。贅沢な名だねぇ。
> 今からお前の名前は郎だ。いいかい、郎だよ。分かったら返事をするんだ、郎!!
```

# コマンド化
ちなみに、下記のようにPATHが通ったところに置き、権限を渡せば
いつでもどこでも湯婆婆を召喚できます。
（/usr/local/bin/に置くのはあんまりいい気持ちはしませんが・・・

```
$ chmod a+x yubaba #権限を付与
$ cp yubaba /usr/local/bin/ #PATHが通った場所へコピー
$ yubaba
> 契約書だよ。そこに名前を書きな。
> 山田太郎
> フン。山田太郎というのかい。贅沢な名だねぇ。
> 今からお前の名前は太だ。いいかい、太だよ。分かったら返事をするんだ、太!!
```

# クラッシュ
何も入力しないと、しっかりエラーを吐いて停止します（原作リスペクト大事
Shell scriptはデフォルトだとエラーを吐いた後も実行されてしまうので、
最初に``set -eu``を指定しています。

```
$ bash yubaba
> 契約書だよ。そこに名前を書きな。
> 
> フン。というのかい。贅沢な名だねぇ。
> yubaba: line 7: RANDOM % 0: division by 0 (error token is "0")
> yubaba: line 8: random: unbound variable
```

# 終わりに

初Qiita投稿でしたが如何だったでしょうか。

一応、Shell scriptで書かれたものが無いか確認しましたが
もし私が気づかず、丸被りしてしまってたらごめんなさい。

私としてはShell scriptも触れられて、記事にも挑戦できて良い経験になりました。
みなさんも湯婆婆・Shell scriptを楽しんでみてください！ｗ
【JavaScript】時間を１２時間表記で表す。

#プログラミング勉強日記
2020年11月9日
時間の表記を24時間表記から12時間表記で表すコードを作成する。

#コード

```index.html
   <p>現在は<span id="ampm"></span><span id="hh"></span>:<span id="mm"></span>です。</p>

```
```script.js

//Date()関数をインスタンス化
const now = new Date();

//現在の時間を取得
let hh = now.getHours();

//現在の分を取得
let mm = now.getMinutes();

//時刻が12以上のとき
if(hh >= 12) {

    //id属性ampmのコンテンツを『午後』に書き換える
    document.getElementById('ampm').textContent = '午後';

    //id属性がhhのコンテンツを現在時間に書き換える(13時の場合、13-12=1となり午後1時と表示される)
    document.getElementById('hh').textContent = hh - 12;//hh % 12でもOK

} else {
    //時刻が0~11のとき!

    //id属性ampmのコンテンツを『午前』に書き換える
    document.getElementById('ampm').textContent = '午前';

    //id属性がhhのコンテンツを現在時間に書き換える
    document.getElementById('hh').textContent = hh;
}

//id属性mmのコンテンツを現在の分に書き換える
document.getElementById('mm').textContent = mm;


```
#出力結果
![スクリーンショット 2020-11-09 19.34.17.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/854121/647dbd08-fefe-6f17-63d1-48ccda88a737.jpeg)


#参考資料
* [確かな力が身につくJavaScript「超」入門 第2版](https://www.amazon.co.jp/s?k=javascript&__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=I8ER3WML3XL5&sprefix=java%2Caps%2C312&ref=nb_sb_ss_ts-apa-p_1_4)
* [【Javascript】時刻を12時間表記にしてみる【ifの使い方】](https://sunsukeblog.com/javascript_ampm)
備忘録：AWS S3活用による画像保存

#はじめに
Railsでオリジナルアプリを制作しています。このアプリに画像投稿機能を実装しました。しかしHerokuでデプロイしたところ、24時間後には画像は表示されなくなりました(仕様です)。この問題を解決するため、AWS(Amazon Web Service)のS3(Simple Storage Service)を活用しました。今後も使用する機会がありそうなので、備忘録として書き記します。なお、AWS上のアカウント作成やセキュリティ対策方法は割愛します(別記事でまとめます)。

#手順
1.S3でバケット(データ格納場所)の準備
2.データ(今回は画像)保存先の設定

#1.S3でバケット(データ格納場所)の準備
バケット準備は大きく分けて下記2つの手順が必要です。

**1-1.バケットの作成**
AWSの公式サイトのサービスタブをクリックし、S3を選択します。その後「バケットを作成」をクリック。バケット名は誰かが既に使用していると、保存できないので注意。

[AWS公式サイト](https://aws.amazon.com/jp/console/)

**1-2.バケットポリシーの設定**
どのようなアクセスに対してS3への保存やデータの読み取りを許可するか決めます。
(今回はIAMユーザーで設定します。)

・サービスタグから検索窓にIAMを入力し、表示されたメニューをクリックする。
・左端のユーザーをクリックし、表示されたユーザー名をクリックする。
・ARNをコピーする。
・再びサービスタブからS3を選択し、対象のバケットを選択する。
・アクセス許可タブ、バケットポリシーの項目の編集するをクリックする。
 (下記参照)

```bash
{
    "Version": "2012-10-17",
    "Id": "Policy1544152951996",
    "Statement": [
        {
            "Sid": "Stmt1544152948221",
            "Effect": "Allow",
            "Principal": {
                "AWS": "先ほどコピーしたARNを貼り付ける"
            },
            "Action": "s3:*",
            "Resource": "arn:aws:s3:::対象のバケット"
        }
    ]
}
```

#2.データ(今回は画像)保存先の設定
こちらも下記4つの手順が必要です。

**2-1.必要なGemのインストール**
Gemファイルに下記Gemを追加して、ターミナル上でインストールします。

```Ruby:Gemfile
gem "aws-sdk-s3", require: false
```

```bash:ターミナル
bundle install
```
**2-2.保存先を指定**
通常は保存先がlocalになっています。これをamazonに書き換えます。またローカル環境と本番環境では記述するファイルが異なるので注意する。

```Ruby:config/environments/development.rb(ローカル環境)
config.active_storage.service = :amazon
```
```Ruby:config/environments/production.rb(本番環境)
config.active_storage.service = :amazon
```

**2-3.環境変数を設定**

```Ruby:config/storage.yml
local:
 service: Disk
 root: <%= Rails.root.join("storage") %>
-------------------------------下記を追記----------------------------------
amazon:
 service: S3
 access_key_id: <%= ENV['AWS_ACCESS_KEY_ID'] %>
 secret_access_key: <%= ENV['AWS_SECRET_ACCESS_KEY'] %>
 region: ap-northeast-1
 bucket: 対象のバケット名
```

ターミナル上で環境変数を設定する。

```bash:ターミナル
vim ~/.zshrc
```

```bash:ターミナル
export AWS_ACCESS_KEY_ID="Access key IDの値をコピー"
export AWS_SECRET_ACCESS_KEY="Secret access keyの値をコピー"
```

設定できたら再びターミナルで設定を適用する。

```bash:ターミナル
source ~/.zshrc
```

**2-4.動作確認**
実際に保存してみて、AWS S3のページ対象のバケットにオブジェクトが追加されればOK

以上
【python】正規表現で出会い系を駆逐

#ことの発端
Twitterのデータ収集はしていましたが、その後はほったらかしにしていました。
で、久しくデータを見たらfav0の出会い系の謎の市町村ツイートがわんさかわんさか……。
実際にTwitter検索かけてもばりばり見つかりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412138/8ad09e49-ddd7-0627-e8bc-ade2b4e48944.png)

ユーザ名はさすがに卑猥すぎて隠しました……。
なんだこの謎の単語は……前までもうすこし文章だったろ……？
そして以前まで特定の単語を指定して、それがヒットしたらサヨナラとしてたんですけど、この文字数だと指定できる共通単語もありません。

ので正規表現でどかんと削除します。


#ソース

動作確認のサンプルごとドカン。土管。

ざっと見たところ呟きのパターンとしては
①「平仮名1文字」「平仮名もしくは句読点」「市町村名」
②「平仮名3文字」「記号」「市町村名」
この2つなので、該当するものを空白に置換してから空白行を削除します。

データはデータフレームに入ってるのでそこでなんとか、えんやこらします。
地味に久しぶりのpythonタイム。すぐ終わりましたが。

```python
import pandas as pd
import re
DF_samp=pd.DataFrame({'col_0': {'row_0': "おー大阪市", 'row_1': "おっ、大阪市aaa", 'row_2': "おっ、大阪市"},'col_1': {'row_0': 3, 'row_2': 4, 'row_3': 5},})
cols=DF_samp.col_0
cols0=cols.str.replace("[ぁ-ゟ][ぁ-ゟ][!-/:-@?[-`{-~。、～ー…＼].+[町|村|市]$|[ぁ-ゟ][ぁ-ゟ!-/:-@?[-`{-~。、～ー…＼].+[町|村|市]$", '')
DF_samp.col_0=cols0
DF_samp.dropna(subset=['col_0'])
```

これで該当する謎文章だけ駆逐出来ました。
ヤッタネ。
そこの代入いるんですかって声が聞こえる気がしますが長いの嫌なので……。

#そして今
これBOT担当者に見られたら新たなパターンが来るのかもしれないと気づいてしまった……。
その時はその時ですが。

なにはともあれ効率よくブロックできる世の中になりた～い！
まあツイート収集してるのはAPIなので今回のこれはブロック関係ないんですけどネ。
BigQueryでなんか知らんけどクエリが走らんと言われた


こんにちは。バンです。

皆さん BigQuery 使ってますか？？僕は使ってますよ

BigQuery 使う上での小ネタシリーズです

まあBigQueryに限った話ではないのですが。。

## 問題

`sample.dataset.table` というテーブルがあったときに、下記のクエリを走らせると

```sql
SELECT following
from `sample.dataset.table`
```

こんなエラーが出ます

```
Syntax error: Expected end of input but got keyword FOLLOWING at [xxxx]
```

何が悪いかわかりますか？というやつです。

## 答え

小ネタはあっさりが信条ですのであっさり答えを言うと、

`FOLLOWING` が BigQuery においては **予約語** です。

### 予約語とは

`AND` とか、 `SELECT` のように予め特殊な意味を持つ言葉として定められているものです。python なら if とか。

ちなみに BigQuery の予約語一覧は下記で確認できます！
[BigQuery の予約語リスト](https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#reserved_keywords)

## でも予約語をカラム名にしちゃった…

困りますね。こういうときは `(Backtick) で囲えばOKです。(ちなみにLegacyのときは[]でした。)

なので、修正するなら下記のように。

```sql
SELECT `following`
from `sample.dataset.table`
```

ただ、これで囲うとBigQueryのGUI上でシンタックスハイライトがちゃんと効いて色が変わらないのでちょっと不安になりますが、普通に動きます。

本当はそこらへんの感覚をもってカラム名を設定してほしいですがまあ、どうしようもないときもあるでしょうというところで…

いとめでたし。
Fluentd(k8s) で "hello, world" 

## 環境

```
$ kubectl version --short
Client Version: v1.19.2
Server Version: v1.18.8
```

## 初期状態の確認

```
$ kubectl get cm                     
No resources found in default namespace.
```

```
$ kubectl get deploy                 
No resources found in default namespace.
```

## 動作確認用の fluent.conf ファイルの作成

```
$ cat <<EOS > fluent.conf
<system>
  log_level debug
</system>

<source>
  @type forward
  @id input_forward
</source>

<match **>
  type stdout
</match>
EOS
```

## 上記で作成したファイルから ConfigMap のマニュフェストを作成

```
$ kubectl create configmap fluent-conf-configmap --from-file=fluent.conf --dry-run=client -o yaml > fluent-conf-configmap.yaml
```

## ConfigMap の作成

```
$ kubectl apply -f fluent-conf-configmap.yaml 
configmap/fluent-conf-configmap created
```

```
$ kubectl get cm
NAME                    DATA   AGE
fluent-conf-configmap   1      10s
```

## Deployment のマニュフェストを作成

```
$ cat <<EOS > sample-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sample-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: sample-fluentd
  template:
    metadata:
      labels:
        app: sample-fluentd
    spec:
      containers:
        - name: fluentd-container
          image: fluent/fluentd:v1.11.4-debian-1.0
          volumeMounts:
            - name: fluent-conf-config
              mountPath: /fluentd/etc/fluent.conf
              subPath: fluent.conf
      volumes:
        - name: fluent-conf-config
          configMap:
            name: fluent-conf-configmap
EOS
```

## Deployment の作成

```
$ kubectl apply -f sample-deployment.yaml 
deployment.apps/sample-deployment created
```

```
$ kubectl get deployment                 
NAME                READY   UP-TO-DATE   AVAILABLE   AGE
sample-deployment   1/1     1            1           10s
```

## 動作確認

```
$ pod=$(kubectl get po | grep ^sample-deployment | grep Running | tail -n 1 | awk '{print $1}')
```

```
$ kubectl exec -it $pod -- bash -c "cat /fluentd/etc/fluent.conf"
<system>
  log_level debug
</system>

<source>
  @type forward
  @id input_forward
</source>

<match **>
  type stdout
</match>
```

```
$ kubectl exec -it $pod -- bash -c "echo '{\"message\":\"hello, world\"}' | fluent-cat debug.test"
```

```
$ kubectl logs $pod | tail -n 1
2020-11-08 09:50:10.395839985 +0000 debug.test: {"message":"hello, world"}
```
【BigQuery】毎月1日のテーブルを抽出

GENERATE_DATE_ARRAYで毎月1日の配列をつくり、WHILE構文でそれぞれSELECTしてくる。

``` sql
DECLARE month_list ARRAY<DATE>;
DECLARE i INT64 DEFAULT 1;

SET month_list = (
  SELECT 
    GENERATE_DATE_ARRAY('2020-01-01', '2020-04-01', INTERVAL 1 MONTH)
);

WHILE i < ARRAY_LENGTH(month_list) DO

  SELECT 
    culumn1
    , culmn2
    , culmn3
  FROM
    `project_name.dataset_name.table_name_*`
  WHERE
    _TABLE_SUFFIX BETWEEN CAST(FORMAT_DATE('%Y%m%d', month_list[ORDINAL(i)]) AS STRING)
    AND CAST(FORMAT_DATE('%Y%m%d', month_list[ORDINAL(i)]) AS STRING)

  SET i = i + 1;
END WHILE;
```
jqGridでonSelectRowで設定したfunctionが実行されない原因について

# jqGridでonSelectRowで設定したfunctionが実行されない原因について

jqGridでonSelectRowでfunctionを設定しているが、該当functionが実行されない事象が発生した。
その解決方法を備忘録的に記載します。

※onSelectRow：行選択後に実行するfunctionを指定するための設定。


# 画面イメージ

![Qiita_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/701538/0dcb3cd8-40ac-754e-6438-00438f48c336.png)

# ソース
```
 1  <!DOCTYPE html>
 2  <html lang="ja">
 3  <head>
 4  <meta charset="utf-8">
 5  <title>jqGrid行選択時処理</title>
 6  <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
 7  <script src="https://code.jquery.com/ui/1.12.0/jquery-ui.min.js"></script>
 8  <script src="https://js.cybozu.com/jqgrid/v5.1.1/js/jquery.jqGrid.min.js"></script>
 9  <script src="https://js.cybozu.com/jqgrid/v5.1.1/js/i18n/grid.locale-ja.js"></script>
 0  <link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
11  <link rel="stylesheet" href="https://js.cybozu.com/jqgrid/v5.1.1/css/ui.jqgrid.css">
12  <script>
13  $(document).ready(function(){
14    //表示データ
15    var dt = [
16       {code:'ZZ001', name:'ＸＸ', price:1300}
17      ,{code:'ZZ002', name:'ＹＹ', price:1400}
18      ,{code:'ZZ003', name:'ＺＺ', price:1500}
19      ,{code:'ZZ004', name:'ＸＹ', price:1250}
20      ,{code:'ZZ005', name:'ＹＺ', price:1850}
21    ];
22  
23    //表示設定
24    $("#grid_table").jqGrid({
25       data: dt
26      ,datatype: 'local'
27      ,colNames: ['コード', '名前', '金額']
28      ,colModel: [
29          {index:'code', name:'code', width:'80px', align:'center'}
30         ,{index:'name', name:'name', width:'150px', align:'left'}
31         ,{index:'price', name:'price', width:'200px', align:'right'}
32       ]
33      ,height: 'auto'
34      ,cellEdit: true
35      ,caption: '商品一覧'
36      ,onSelectRow: function(rowid, status, e){  //行選択後に呼ばれる
37         window.confirm("行番号：" + rowid);
38       }
39    });
40  
41  });
42  </script>
43  </head>
44  <body>
45    <table id="grid_table"></table>
46    <p>※行選択するとダイアログが表示される。</p>
47  </body>
48  </html>
```

# 原因

34行目のcellEdit:trueを削除するとonSelectRowで設定したfunctionが実行されるようになった。
cellEdit:trueは編集可能なグリッドにするための設定。
一時的に編集可能なグリッドに変更していたのを戻し忘れていた！
湯婆婆をAndroidアプリで実装する

本記事は、@Nemesisさんの[Javaで湯婆婆を実装してみる](https://qiita.com/Nemesis/items/c7192a7c510788d2cba2)という記事のパロディです。
湯婆婆をAndroidアプリで実装しました。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/694762/d7fe436e-ab12-ee6d-9e80-b4c09904079e.gif" width=50%>

# 必要な機能
・コマンドプロンプト風
・名前が空白だとアプリが落ちる

# レイアウト
テキスト表示(TextView)とテキスト入力(EditText)で構成されています。

```activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/black"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/text1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="@color/white"
        android:textSize="14sp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <EditText
        android:id="@+id/name"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:background="#00000000"
        android:importantForAutofill="no"
        android:inputType="text"
        android:textColor="@color/white"
        android:textSize="14sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/text1"
        tools:ignore="LabelFor" />

    <TextView
        android:id="@+id/text2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="@color/white"
        android:textSize="14sp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/name" />

    <TextView
        android:id="@+id/text3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="@color/white"
        android:textSize="14sp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/text2" />

</androidx.constraintlayout.widget.ConstraintLayout>
```

# 内部処理部分

言語はKotlinを使用しています。
大まかに解説すると、最初のテキストを表示し、名前入力部分で入力が終わったらnewName作成＋その後のテキスト表示をしています。

```MainActivity.kt

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        text1.text = "契約書だよ。そこに名前を書きな。"
        name.requestFocus()
        name.setOnKeyListener { _, i, keyEvent ->
            if (keyEvent.action == ACTION_DOWN && i == KEYCODE_ENTER) {
                text2.text = "フン。${name.text}というのかい。贅沢な名だねぇ。"
                val newName = name.text[Random.nextInt(name.text.length)].toString()
                text3.text = "今からお前の名前は${newName}だ。いいかい、${newName}だよ。分かったら返事をするんだ、${newName}!!"
                true
            } else {
                false
            }
        }
    }
}
```
Raspberry PiでImageMagickを使う

## インストール

```sh
$ sudo apt-get update
$ sudo apt install imagemagick
```

## バージョン確認

```sh
$ convert -version
Version: ImageMagick 6.9.10-23 Q16 arm 20190101 https://imagemagick.org
Copyright: © 1999-2019 ImageMagick Studio LLC
License: https://imagemagick.org/script/license.php
Features: Cipher DPC Modules OpenMP 
Delegates (built-in): bzlib djvu fftw fontconfig freetype heic jbig jng jp2 jpeg lcms lqr ltdl lzma openexr pangocairo png tiff webp wmf x xml zlib
```
mac + homebrew + postgresSQLでバージョン違いのエラーが発生した時（database files are incompatible with server）

<h1>macでpostgresSQLのcreatedbでのエラー解決</h1>

postgresSQLで新しいデータベースを作成しようとcreatedbコマンドを打つと
以下のようなエラーが発生した。

```terminal:error_message
createdb: error: could not connect to database template1: could not connect to server: 
No such file or directory
	Is the server running locally and accepting
	connections on Unix domain socket "/tmp/.s.PGSQL.5432"?
```

テンプレート１つながらず、サーバーにもつなげない、、、
エラー文を読んでもいまいちピンと来ないのでログを確認

```terminal:ログの確認
% postgres -D /usr/local/var/postgres
FATAL:  database files are incompatible with server
DETAIL:  The data directory was initialized by PostgreSQL version 12, 
　　　　　 which is not compatible with this version 13.0.
```

どうやらデータディレクトリのバージョンが今使っているバージョンと違って
競合している為、使えないご様子。
そういうわけでデータディレクトリの方をアップグレード。

```terminal:ログの確認
% postgres -D /usr/local/var/postgres
FATAL:  database files are incompatible with server
DETAIL:  The data directory was initialized by PostgreSQL version 12, 
　　　　　 which is not compatible with this version 13.0.
```
```terminal:データベースのアップグレード
 % brew postgresql-upgrade-database
```

無事にアップグレードが完了して、問題なくcreatedbも出来ました！よかった！
【Swift】Xcode (ver 12.1) でプロジェクトを作って "Hello, World!" を表示

# ド初心者向け

今日初めてXcodeおよびSwiftに手を出したところ、検索してみると「アレコレを選んでください」が現在のバージョンとはビミョーに違っていた。

## とりあえずXcode起動

![スクリーンショット 2020-11-09 18.27.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413699/175ae0e7-6c73-3480-545a-3799033ede2c.png)

一番上の "**Create a new Xcode project**" を選択
かつてのバージョンでは上から2番目に項目があったようだ。

## フォーマットを選ぶ

![スクリーンショット 2020-11-09 18.27.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413699/7675b10f-30ef-1452-6955-bb6d4c03ed57.png)

"**App**" を選択する。
多く出てくる検索結果ではやや情報が古く "Single View App" を選択してくださいとあったため、スーパー初心者の自分は「あれ、無いじゃん」となった。

## プロジェクトの情報を入力する

![スクリーンショット 2020-11-09 18.37.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413699/bbf9385f-eb64-f882-88b3-e48cc711c06b.png)

**プロジェクト名** と "**Organization Identifier**（これに関わる組織名、あるいは個人名？）" を入力する。
今回はプロジェクト名も組織名も適当なものを入れた。
Nextを押すと「プロジェクトをどこに作るのか」という画面になるのでディレクトリを選択する（たとえば自分の場合はMacの個人フォルダ内に作った『projects』というディレクトリを選択した）。

## Hello, World!

プロジェクトを作ったらもう出力する処理が書かれていた。

![スクリーンショット 2020-11-09 19.02.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413699/fc22ca3a-21cc-2e44-4a1f-08b7a8b4ac3f.png)

どのファイルにどういう処理が書いてあるかはまだよくわからないが、とにかく左上の『▶』を押すと別ウインドウで開いたプレビュー画面で、**アイコンがまっさらのプロジェクト名のアプリ**をクリックする。

![スクリーンショット 2020-11-09 19.02.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413699/68cb7ed4-4b17-ff23-8b08-56b6fb5222ac.png)

出ましたね。
ここから何をどうすればいいのかサッパリわかりませんが続けていこうと思います。
vue.config.js/nuxt.config.jsで補完を効くようにする 


※ vscodeでの開発が前提です

## vue.config.jsの場合

- @vue/cli 4.5.8 で`vue create`した環境で確認
  - Vue2 / Vue3 どちらでもOK

```js:vue.config.js
/**
 * @typedef { import("@vue/cli-service").ProjectOptions } Options
 * @type { Options }
 */
const option = {
  // ここに補完が効くようになる
};

module.exports = option;
```

![スクリーンショット1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137148/8af90ded-4716-a2d8-4e2d-e0caddfacb9f.png)


↑こんな感じになると思います

## nuxt.config.jsの場合

- nuxt 2.14.6 と @nuxt/types 2.14.6 で確認

```js:nuxt.config.js
/**
 * @typedef { import("@nuxt/types").NuxtOptions } NuxtOptions
 * @type { NuxtOptions }
 */
const option = {
  // ここに補完が効くようになる
};

export default option;
```

![スクリーンショット2](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137148/e009bd84-dd02-6a42-9859-b1b530362b30.png)


↑こんな感じになると思います

@nuxtjs/vuetify を使ってる場合は以下のように書きます

```js:nuxt.config.js
import colors from "vuetify/es5/util/colors";

/**
 * @typedef { import("@nuxt/types").NuxtOptions } NuxtOptions
 * @typedef { import("vuetify/types/services/presets").VuetifyPreset } VuetifyPreset
 * @type { NuxtOptions & { vuetify?: Partial<VuetifyPreset> } }
 */
const option = {
  // ここに補完が効くようになる
};

export default option;
```

### nuxt.config.jsでの注意点

上記の@nuxtjs/vuetifyのように、nuxtプラグインの設定は自分で型を定義する必要があり、まあまあめんどくさいです。

## まとめ

configファイルをtsで書く選択もあるみたいですが、補完が効くなら個人的にはjsの方が気軽だなと思います。
わざわざうる覚えの設定をいちいちググるのもめんどくさいですし。

## 関連記事

- [webpack.config.jsで補完を効くようにする - Qiita](https://qiita.com/items/82e27e493a55ea5b5b17)
  - ちょっと前に書いたしたやつ　(これ書いたからすっかりvue.config.jsのも書いていたと思っていました、、)
データカタログに他ユーザ（IBMid）を招待する。

#前提事項
招待したいユーザがすでにIBMIDを取得していること。
今回は、ユーザAがユーザBを招待したい、とします。

以下画面はユーザB（招待される側）のCloud Pak for Data as a Service（CP4DaaS）管理画面です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295123/24ec8cfb-0bb5-48ce-130f-3bde5dadbd2f.png)

#操作方法
以下操作はユーザA（招待する側）のCloud Pak for Data as a Service（CP4DaaS）管理画面です。

管理画面の左上から「管理」⇨「アクセス（IAM）」をクリックして、新しいタブへ移動。
![スクリーンショット 2020-11-09 18.43.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295123/d4e40229-c308-e89b-ed87-deb12a5d9d7b.png)

「ユーザーの招待」をクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295123/2a73b311-2a36-6d42-8be1-0c9a19a5969e.png)

招待したいユーザのメールアドレス（IBMidを取得済みのもの）を入力し、
![スクリーンショット 2020-11-09 18.49.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295123/4aa65802-17f0-e8ef-0287-d81f95358f7f.png)

「ユーザへの追加のアクセス権限の割り当て」の「IAMサービス」をクリックして
![スクリーンショット 2021-07-29 16.55.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295123/971bc373-eacc-297a-ebc4-aa0c5ee36f9e.png)

「サービス・アクセス権限無し」のドロップダウンリストから「Watson Knowledge Catalog」をクリックして
「すべてのリソース」を選んで「ビューアー」を選択して「招待」をクリック。
![スクリーンショット 2021-07-29 16.59.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295123/b250a18d-8d37-2ea6-011e-524c66c86469.png)


自分自身（管理者）以外にユーザが追加されたことを確認。
ただし、この時点ではまだ「状況」は「保留中」となっています。
![スクリーンショット 2021-07-29 17.01.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295123/889de260-7cb8-c2ab-c999-bc4450faa44b.png)


招待されたユーザは、自分のメールアドレスに招待のメールが来ていることを確認し、「Join Now」をクリック。
![スクリーンショット 2021-07-29 16.43.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295123/233ddfad-7d3f-748f-891a-f505e48e2025.png)


アカウントに参加、をクリック。
![スクリーンショット 2021-07-29 16.37.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295123/e971c195-6acb-7475-4df0-c6690eca2981.png)

招待した側の画面で、当該アカウントが「保留」から「アクティブ」になっていることを確認。


CP4DaaSで作成済みのデータカタログ画面の「Access control」タブから、「コラボレーターの追加」をクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295123/59bff9df-f740-d735-f3e5-013f614c68c1.png)


「ロール」を「ビューアー」に指定して、先ほど追加したユーザのメールアドレスを指定し、
コラボレータとして追加する。
![スクリーンショット 2020-11-09 18.54.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295123/9a7144b2-0462-f106-8533-8cfb9d8540e8.png)


カタログにビューアーとしてユーザが追加されたことを確認。
![スクリーンショット 2020-11-09 18.56.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295123/f24453b1-b6e6-f45b-851c-621c86cf0f9e.png)

#確認
以下はユーザB（招待された側）の管理画面です。「カタログ」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295123/43205036-20c7-5fb6-ced5-0661998dbe46.png)


ユーザAが作成したカタログにビューアーとして参加できていることがわかります。
![スクリーンショット 2020-11-09 19.11.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295123/ad1455f4-c563-11d3-df84-6690eaf17470.png)
Permitted Cross Domain Policies

#はじめに
Permitted Cross Domain Policies
について書いていきたいと思います。
備忘録程度ですが....

#Permitted Cross Domain Policiesって？
ドキュメント
https://www.adobe.com/devnet-docs/acrobatetk/tools/AppSec/xdomain.html
Flash pLayerを使う際
他のドメインのダータファイルなどを閲覧する際に制限をかけるためのファイル
設定などはドキュメント、またはこちらを参照(http://cuaoar.jp/2008/03/-flash-player.html)

#FlashでCross Domain てどういうこと？
そもそもFlashは呼び出される側でcrossdomain.xmlのを設定してそこを制約として
クロスドメインでFlashコンテンツを呼び出せるらしい。
参考(https://gihyo.jp/dev/serial/01/web20sec/0004)
ただしCross Domainを許可した場合他のファイルまでアクセスできてしまい情報漏洩につながってしまう。
そのためCross Domainを扱う際には十分注意しなければならない。
Alloyでアナリシスパターンを表現「2章 責任関係」

Alloyでアナリシスパターンを表現する試み
## 2.1 パーティ
人あるいは組織を抽象化した概念として「パーティ」を導入する。

```
abstract sig パーティ {
	属性_電話番号: 電話番号,
	属性_住所: 住所,
	属性_Eメールアドレス: Eメールアドレス
}
fact {
	属性_電話番号 in パーティ some -> lone 電話番号
	属性_住所 in パーティ some -> lone 住所
	属性_Eメールアドレス in パーティ some -> lone Eメールアドレス
}
sig 人, 組織 extends パーティ {}
sig 電話番号 {}
sig 住所 {}
sig Eメールアドレス {}

pred show {}
run show
```

### 実行結果

![2.1_party.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53775/2f254c53-b5b2-a20c-fd26-6535c97c764c.png)


## 2.2 階層構造
階層に関する制約はalloyで素直に記述できる。

```
abstract sig 組織 {
    親:  lone 組織
}
sig 営業所 extends 組織 {} { 親 in 部門 }
sig 部門 extends 組織 {} { 親 in 地域 }
sig 地域 extends 組織 {} { 親 in 事業部 }
sig 事業部 extends 組織 {} { no 親 }

pred show(a地域: 地域, a事業部: 事業部, a部門: 部門, a営業所: 営業所) {
}
run show for 4
```

### 実行結果
![alloy2.2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53775/9209e275-e02e-4d5f-cc50-73ff1885ae11.png)


### 二つの組織階層

```
abstract sig 組織 {
	親営業:  lone 組織,
	親製品サービス: lone 組織
}
sig 営業所, 製品サービス extends 組織 {}

fact {
	all a組織: 組織 | no a組織.^(親営業 + 親製品サービス) & a組織
	親製品サービス in 組織 -> lone 製品サービス
	親営業 in 組織 -> lone 営業所
}

pred show {}
run show
```

### 実行結果
![alloy2.2.2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53775/9ab6c60e-6be5-3602-de63-b9cf9fced0ab.png)
XAMPPにCakePHP4をインストールする

躓いたところと解決法の覚書です。
※最新版では変更になっている場合があります。

XAMPP：7.4.11 (PHP7.4.11)
Composer：2.0.4
CakePHP：4.1.*

XAMPPとComposerはインストール済みです。

#XAMPPの設定
CakePHP4ではPHP拡張のintlが必要です。
php.iniを修正し、intlを有効にします。

```php.ini
extension=intl
# 先頭の;を外して有効にする
```

#インストール
##PHPのバージョン確認
PHP 7.2～が表示されればOK

```shell
php -v
```

##CakePHPのインストール
XAMPPのhtdocsに移動しインストールします。

```shell
cd c:/xampp/htdocs
composer create-project --prefer-dist cakephp/app:4.* my_app_name
# htdocs内に「my_app_name」が作成される
```

バージョン指定する場合は↓

```shell
cd c:/xampp/htdocs
composer create-project --prefer-dist cakephp/app:^4.1 my_app_name
# 4.1系の最新版がインストールされる
```

http://localhost/my_app_name にアクセス
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308640/c4a774a6-fd33-b15a-8d4c-113fad416999.png)

#DBの設定
config内のapp_local.phpもしくはapp.phpにDBの情報を設定します。
app_local.phpに設定した場合は、そちらが優先されるそうです。
https://book.cakephp.org/4/ja/quickstart.html

```php:config/app_local.php
'Datasources' => [
    'default' => [
        'host' => 'localhost',
        // 作成したDBの接続情報
        'username' => '...',
        'password' => '...',
        'database' => '...',
        ...
    ],
```

成功すると緑のコック帽のマークが表示されます。
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308640/6a6a2772-d2c6-0483-debc-3127b0e012f5.png)
truffle console

```
truffle console
```
```
truffle(development)> <コントラクト名>.deployed().then(function(instance) { app = instance })
truffle(development)> app.address
//コントラクトアドレスが返る
truffle(development)> app.<変数名>()
//変数の値が返る
//変数は自動で getter function になる
```
【単体テストコード】外部キーがあるのに「〇〇を入力してください」と言われる

## 問題
単体テストコードで「コメントが保存できる時」というテストを行った。
その際にFactoryBotで作成した外部キーであるskill_idとuser_idは存在するのになぜかその二つが空だと言われた。

```:エラー文
  1) Comment コメント投稿 コメント投稿がうまくいくとき コメントが存在すれば登録できる
     Failure/Error: expect(@comment).to be_valid
       expected #<Comment id: nil, text: "v5tycc16e03hixch09y3661diocp6t5mwqj11r26gbjnptc0ty...", skill_id: 2, user_id: 1, created_at: nil, updated_at: nil> to be valid, but got errors: Userを入力してください, Skillを入力してください
     # ./spec/models/comment_spec.rb:11:in `block (4 levels) in <top (required)>'

Finished in 0.78208 seconds (files took 6.7 seconds to load)
3 examples, 1 failure
```

## 結論
外部キーのバリデーションをチェックする時にはbuildではなくcreateでデータベースにアクセスすることで値を取得する。
見た目上ではskill_idとuser_idが存在していたが、migrationファイルで外部キー制約をかけているため、それらの値は別テーブルから持ってきた値でなければならない、ということだった。

## 構造
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693815/31e0467e-9955-dc90-59d8-69319dd92c44.png)

###before

```ruby:factorybot
FactoryBot.define do
  factory :comment do
    text { Faker::Lorem.characters(number: 100) }
    user_id { 1 }
    skill_id { 2 }
  end
end
```

```ruby:comment_spec.rb
require 'rails_helper'
RSpec.describe Comment, type: :model do
  describe 'コメント投稿' do
  before do
    @comment = FactoryBot.build(:comment)
  end

    context 'コメント投稿がうまくいくとき' do
      it 'コメントが存在すれば登録できる' do
        expect(@comment).to be_valid
      end
    end
...

```

### after

```ruby:factorybot
FactoryBot.define do
  factory :comment do
    text { Faker::Lorem.characters(number: 100) }
    association :user
    association :skill
  end
end
```

```ruby:comment_spec.rb
require 'rails_helper'
RSpec.describe Comment, type: :model do
  describe 'コメント投稿' do
  before do
    @comment = FactoryBot.create(:comment)
  end

    context 'コメント投稿がうまくいくとき' do
      it 'コメントが存在すれば登録できる' do
        expect(@comment).to be_valid
      end
    end
...

```
Microsoft365のAccessでデータベースの最適化修復のやり方と注意点（データベースへの副作用）

# 手動で最適化/修復をする方法

データベースツール ⇒ データベースの最適化/修復。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/3399b61c-3537-3999-086b-0c048c79f2e1.png)


# ファイルを閉じるときに毎回最適化を走らせる設定

ファイル。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/e2d5b1dd-2e7b-d78d-7079-11fb026b7ac7.png)
オプション。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/2fdbceb1-ba98-05a8-ae02-217d25a927c3.png)
現在のデータベース ⇒ 閉じるときに最適化する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/ed7653bd-74c3-30ce-c4b1-d0368d53688e.png)


# 注意点（最適化した時に起こるデータベースへの副作用）

**レコードが無い** テーブルの **オートナンバー型** の採番が **1からスタートにリセット** されます。

例えば下図のテーブルについて、IDがオートナンバー型で100まで採番されていたとします。
（次のレコードはID=101の状態）

この状態で最適化をすると、次にこのテーブルの入るレコードはID=1になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/ffd92de2-62be-d1c3-3dd6-53029d978443.png)

**レコードがある** 場合はリセットされません。
例えば下図の状態で最適化すると、次にテーブルに入るレコードはID=4となります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/ac4323a4-06f8-fdfd-6ac8-771a87520c33.png)


# 蛇足

最適化するとファイルサイズが格段に小さくなることがあります。
（特にCRUDする回数が多かったり、扱うレコード数が多いAccessファイル）

バックグラウンドで常に最適化を走らせればいいのに…。
なぜ任意のタイミングで実行させたり、あえて毎回やるかどうかの設定を用意しているのか…。
謎…(´・ω・`)

最近は『ファイルを閉じる時に毎回最適化する設定』にして、『オートナンバー型の値に依存しない設計』で開発をスタートしています。

# この問題に対応する為に自作ツール作った

https://qiita.com/waokitsune/items/93a87da9d7feffc74b6e

# バージョン

Access for Microsoft 365 MSO（16.0.13328.20262）32ビット
Windows10 Pro バージョン1909 OSビルド18363.1171
【Rails/ActiveRecord】最新3件のみを取得。残りはプルダウンで表示する。を実装

# 概要

* コメント投稿機能を実装したい
* コメントは全件表示したい
* けど全部表示するのは邪魔だから、最新3件だけ表示して残りは必要なときだけ表示したい



**<完成形イメージ>**
![decmo](https://gyazo.com/a36eea47d3c09639ba9fb30a09f620af/raw)

<br>

# 環境

* macOS Catalina 10.15.6
* ruby 2.6.5
* Rails 6.0.3.4

<br>

# 学んだこと
* ActiveRecord
    * **first : 引数に指定した数だけレコードを取得する**メソッド
    * **offset : 引数に指定した数だけレコードを読み飛ばす**メソッド
* HTML
    * **details : 折りたたみウィジェット** (クリックしたら開くオブジェクト) を生成するHTML要素
    * **summary : detail要素のバーの文字を指定** (上のGIFでいう「全てのコメントを表示」)

<br>

# 今回のコード

* 必要部分のみを抜粋します
* association等は省略

## 1. itemsコントローラ

1. items#show のリクエストを受け取る
2. before_action :set_item で商品情報を取得
3. before_action :set_comments で商品に紐づくコメントを全件取得 (新着順)
4. <b>全コメントにfirst(3)適用 : 上から3件を取得</b>
5. <b>全コメントにoffset(3)適用 : 上から4件目以降を全取得</b>
6. 以上のデータをshow.html.erbに渡す

```app/controllers/items_controller.rb

class ItemsController < ApplicationController
  before_action :set_item, only: [:show]
  before_action :set_comments, only: [:show]

  def show
    @comment = Comment.new
    # 新着コメントを上から3件取得
    @comments_latest3 = @item_comments.first(3)
    # 新着コメント3件を除く全コメントを取得 (3件以下の場合は空)
    @comments_offset3 = @item_comments.offset(3)
  end


  private

  def set_item
    # PATHパラメータでitemを取得
    @item = Item.find(params[:id])
  end

  def set_comments
    # itemに紐づくcommtnsを新着順で取得
    @item_comments = @item.comments.includes(:user).order('created_at DESC')
  end

end
```

<br>

## 2. show.html.erb

1. 部分テンプレートで最新3件を表示
2. **4件目以降がない場合はそのまま終了**
3. **4件目以降があった場合は、折りたたみウィジェットの中に4件目以降を全表示**

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

<%# コメント一覧を表示 %>
<div id="comment-lists">
  <%= render partial: 'shared/comment', collection: @comments_latest3 %>
  <%# コメントが4件未満の場合はここから表示しない %>
  <% if @comments_offset3.any? %>
    <details>
      <summary>全てのコメントを表示</summary>
      <%= render partial: 'shared/comment', collection: @comments_offset3 %>
    </details>
  <% end %>
</div>
```

```erb:app/views/shared/_comment.html.erb

<div class="comment-box">
  <div class="comment-info">
    <%# user名を表示 %>
    <p class="comment-user"><%= comment.user.nickname %></p>
    <%# 投稿時間を表示 %>
    <p class="comment-time"><%= l comment.created_at %></p>
  </div>
  <%# 改行が反映される形でコメントを表示 %>
  <p><%= simple_format(h(comment.text)) %></p>
</div>
```

<br>

# その他、工夫したこと
* コメントにユーザー情報を載せるときに**N+1問題を回避**したこと (includes メソッド)
* **コメント投稿時刻を日本時間にした**こと (l メソッド)
* **コメントに記入した改行が実際の表示に反映されるようにした**こと (simple_format)
* simple_format 使用時に**文字をエスケープさせた**こと (h オプション)

<br>

## 参考

* <a href="https://railsguides.jp/active_record_querying.html#limit%E3%81%A8offset">Railsガイド | Active Record クエリインターフェイス
* <a href="https://developer.mozilla.org/ja/docs/Web/HTML/Element/details">開発者向けのウェブ技術 | details: 詳細折りたたみ要素</a>
AWS Step Functions でGlueジョブを呼び出す方法

AWS Step FunctionsでGlueジョブを呼び出す方法が分かりづらかったのでメモしておきます。
ドキュメントは[このあたり](https://docs.aws.amazon.com/ja_jp/step-functions/latest/dg/connect-glue.html)です。

## Step FunctionsでGlue Stateの表現方法
Stateは以下のように表現します。

```json
States": {
  "hoge_state": {
    "Type": "Task",
    "Resource": "arn:aws:states:::glue:startJobRun.sync",
    "Parameters": {
      "JobName": "ジョブの名称をここに書きます",
      "Arguments": {
        "--hoge": "aiu",
        "--foo": "123"
      }
    },
    "Next": "foo_state"
  },
  ...
}
```

わかりづらいと感じたのは`Resource`には`arn:aws:states:::glue:startJobRun.sync`と必ず書き、どのジョブかはジョブ名称を`Parameters`の`JobName`に書く点です。arnを書くものだと思っていたのですが、どうやらGlue Jobにはarnが存在しないようです。

またGlueのジョブパラメータは`Arguments`に書くのですがこのときは各keyの先頭に`--`を付ける必要があります。
参考：[【AWS Glue】ジョブパラメータを利用する](https://qiita.com/YujiHamada3/items/780af5c7bb5b9d4fa997)
Error: Truffle is currently using solc <version>, but one or more of your contracts specify "pragma solidity <version>".

以下のエラーがでたら、

```
Error: Truffle is currently using solc <version>, but one or more of your contracts specify "pragma solidity <version>".
```

このページを参照してみてください。
https://ethereum.stackexchange.com/questions/15749/how-do-i-specify-a-different-solidity-version-in-a-truffle-contract
Gitのコミットコメントを間違ってPushした際に修正する方法

# 経緯
チームの方針でgitのコメントにEmoji Prefixをつける方針になったのだが、慣れていないためよく忘れてしまう
何回か今後もやらかしそうなのでやり方まとめておく

# 方法1
①コメントを修正する
②強制オプション付きでPushする

これが一番簡単です

## コメントを修正する

直前のコミットの場合は下記のコマンドで修正できます

```
git commit --amend "修正後のコメント"
```

それ以前のコメントを変更したい場合は、[こちら](https://saikeblog.com/2019/04/20/%E9%81%8E%E5%8E%BB%E3%81%AB%E3%83%AA%E3%83%A2%E3%83%BC%E3%83%88%E3%81%B8push%E3%81%97%E3%81%9F%E3%82%B3%E3%83%9F%E3%83%83%E3%83%88%E3%81%AE%E3%82%B3%E3%83%A1%E3%83%B3%E3%83%88%E3%82%92%E5%A4%89/)をご参考ください


## 強制オプション付きでPushする

```
git push -f
```

これで終わりです
ただ、強制的に自分の変更をリモートに反映させることになるので、実行時は細心の注意を払ってください
※共有ブランチでこの作業は絶対しないこと


# 方法2
上記が難しいケースは[こちら](https://pursue.fun/tech/how-to-comment-correction-after-push-git/)で
ガートナーの『2021年の戦略的テクノロジートレンド』を読み解く

10/19にガートナーから『[2021年の戦略的テクノロジートレンド](https://www.gartner.com/smarterwithgartner/gartner-top-strategic-technology-trends-for-2021/)』が公開されていました。
9つのテクノロジートレンドを翻訳しつつ、中身を探ってみたいと思います。

## トレンド1：行動のインターネット
> 行動のインターネット（IoB, Internet of Behaviors）は、日常生活の「デジタルダスト」（デジタルと物理の世界にまたがるデータ）を収集するテクノロジーの増加に伴い、その情報を使用したフィードバックを通じて、我々の行動に様々な影響を与えることができます。
> 
> 例えば、健康保険会社が保険料を削減するために、ウェアラブルデバイスによって食料品の購入を監視するなどにも使用できます。不健康な商品の購入が多い人には保険料を上げるなどの目的のためにも使用できます。

人間のあらゆる行動をデータ化してマーケティングや商品開発に活かしていくということでしょうか。
最近ではスマートウォッチやスマートリングなど体に身につけるものも流行ってきているので、そのうち体に埋め込むようなものも一般化されてくるのかもしれませんね。


## トレンド2：トータルエクスペリエンス
> マルチエクスペリエンス（VRやAR、MRなど）を顧客や従業員に適用させるトータルエクスペリエンスとすることで、COVID-19の中でも持続可能な競争上の優位性を生み出すことができます。
> 
> 例えば、リモートワーク、モバイル対応、仮想化、分散型の顧客対応などもトータルエクスペリエンスの向上となります。

リモートワークが増えたり、ソーシャルディスタンスによって人と人が直接触れ合う機会が減ったからこそ、必要となる技術なのでしょうね。
VRやARはこれまで流行になりそうでならない感じでしたが、一気に波が来るのかもしれません。


## トレンド3：プライバシーを強化する計算
> プライバシーやセキュリティを維持しながらデータを共有する必要性が高まっています。データを保護する3つのテクノロジーがあります。
> ・機密データを処理または分析できる信頼できる環境
> ・分散型の方法で処理と分析を実行
> ・処理または分析の前にデータとアルゴリズムを暗号化

ファイルの暗号化やデータベース自体を暗号化する技術などはありますが、ネットワークを介して共有しても暗号化し続けるようなプラットフォームということでしょうか。
プライバシーという点では、ブロックチェーンのCordaを活用してみるのも面白いかもしれません。

## トレンド4：分散クラウド
> サービスの提供を物理的に近づけることは、低遅延になることやデータコストを削減し、データを特定地域に置かなければいけない状況に対応するために役立ちます。
> 
> パブリッククラウド、プライベートクラウド、エッジコンピューティングを含む様々なプラットフォームを物理的な場所に分散したクラウドサービスが誕生し、低遅延のコンピューティングが可能になります。分散クラウドはクラウドの未来です。

パブリッククラウドをAWSやAzureで分散させるようなことはよく検討されていますが、これは物理的な距離についても分散してデータを近くに配置するような技術ということですかね。
５Gのような通信自体が高速になっても、レイテンシが大きいと恩恵が受けにくいというのはありそうな気がします。


## トレンド5：どこでもオペレーション
> COVID-19からビジネスが成功するためには、どこでもオペレーション可能なモデルが不可欠です。それは「デジタルファースト、リモートファースト」です。
> 
> 顧客、従業員、ビジネスパートナーが物理的に離れた環境でも、ビジネスにアクセスでき、情報を届けることができるようにデジタル的な強化が必要となります。

これはすべての会社が急務なテクノロジー戦略ですね。


## トレンド6：サイバーセキュリティメッシュ
> サイバーセキュリティメッシュは、スケーラブルで柔軟性があり、信頼性の高いサイバーセキュリティ制御への分散アーキテクチャアプローチです。
> 
> サイバーセキュリティメッシュを使用すると、セキュリティ境界線を人や物のアイデンティティの周りに定義することを可能にします。ポリシーのオーケストレーションを一元化し、ポリシーの実施を分散させることで、よりモジュール化された応答性の高いセキュリティアプローチを可能にします。

人や物の単位でセキュリティポリシーを設定可能にするようなイメージなのでしょうか。
分散IDとして管理するようなことかもしれませんね。

## トレンド7：インテリジェントなコンポーザブルビジネス
> 組織がデジタル・ビジネス戦略を加速させてより迅速なデジタル・トランスフォーメーションを推進するためには、俊敏性を持ち、現在入手可能なデータに基づいて迅速なビジネス上の意思決定を行う必要があります。
> 
> これを成功させるためには、組織は情報へのより良いアクセスを可能にし、その情報をより良い洞察力で補強し、その洞察力の意味合いに迅速に対応する能力を持たなければなりません。

これはDXはもはや不可欠ということでしょうか。

## トレンド8：AIエンジニアリング
> 堅牢なAIエンジニアリング戦略は、AIへの投資の価値を最大限に発揮しながら、AIモデルのパフォーマンス、スケーラビリティ、解釈可能性、信頼性を促進します。AIプロジェクトは多くの場合、保守性、スケーラビリティ、ガバナンスの問題に直面しており、ほとんどの組織で課題となっています。
> 
> AIエンジニアリングのガバナンスの側面から、信頼性、透明性、倫理、公平性、解釈可能性、コンプライアンスの問題に対処するために、責任あるAIが台頭してきています。それは、AIのアカウンタビリティの運用化である。

AIについてますます加速させる必要があり、さらにAIを管理するAIみたいなものが登場してくるということでしょうか。


## トレンド9：ハイパーオートメーション
> ハイパーオートメーションとは、組織内で自動化できるものはすべて自動化されるべきだという考え方です。
> 
> 多くの組織は、無駄がなく、最適化されておらず、接続されておらず、クリーンでもなく、明示的でもないテクノロジーの「パッチワーク」に支えられています。同時に、デジタルビジネスの加速には、効率性、スピード、民主化が求められます。効率性、効率性、ビジネスの俊敏性を重視しない組織は取り残されてしまうだろう。

DXと合わせて不可欠な戦略ですね。


## まとめ・感想
やはりCOVID-19の影響を受けた戦略が多いですね。
DX・AI・リモート（分散）というあたりが大きなポイントのようです。
エンジニアとしてもこのあたりの知識を深めたり、組織やプロジェクトへの導入を検討していくことが必要となりそうです。


以上、参考になれば幸いです。
CloudWatch Logs から Lambda を使って NewRelic にログを転送する際にカスタムタグをつける

# 概要
* 掲題の通り
* 公式のコードに変更を加えているので、自己責任で利用してください
* Lambda から NewRelic にログを転送するときに任意のタグをつけて送りたかった
  * NewRelic の Logs の画面で任意のタグでフィルタリングしたかったため
* fluentd ではできそうだった
  * http://katzchang.hatenablog.com/entry/2019/12/10/132210

# 方法
* そもそも Lambda のスクリプトは以下にある
  * https://github.com/newrelic/aws-log-ingestion.git
* 今回は、 function.py (下記リンクの箇所)に任意のタグを追加することで実現した
https://github.com/newrelic/aws-log-ingestion/blob/59665cd2951fdc7ea3e50d92d2911700f19dc97e/src/function.py#L448
* diff はこんな感じ
  * Lambda に `CUSTOM_ATTRIBUTES` という環境変数を設定することで、任意のタグを注入できる
  
```
diff --git a/src/function.py b/src/function.py
index 937c1b6..b242aba 100644
--- a/src/function.py
+++ b/src/function.py
@@ -371,6 +371,12 @@ def _reconstruct_infra_data(context, entry, logEvents):
 #  NR Logging  #
 ################
 
+def _get_custom_atrributes():
+    """
+    This functions get attribute key from env vars.
+    """
+    return os.getenv("CUSTOM_ATTRIBUTES", "{}")
+
 
 def _logging_enabled():
     """
@@ -447,6 +453,7 @@ def _package_log_payload(data):
                         "logStream": entry["logStream"],
                         "logGroup": entry["logGroup"],
                     },
+                    "custom": _get_custom_atrributes(),
                 }
             },
             "logs": log_messages,
```

# 結果
* `CUSTOM_ATTRIBUTES = "{\"group\":\"group-x\"}"` とした場合
* Logs 画面の UI にも反映されている
  * ![image (10).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521224/1eea506f-2608-233d-f407-04f2bc19ac53.png)
* ログデータの詳細は以下
  * ![image (9).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521224/4379abd1-3559-e41f-62a3-949e6d8f31ab.png)
TLSv1.2未満でのアクセスを制御するときのメモ

# 概要

いろいろあって低いSSLバージョンでのアクセスは弾くことになりました。
まぁまぁ今更感がありますが、やっといた方が良いような気はしますよね。
Apacheの設定でチョチョイのチョイなんですが、案外丁寧にやってる記事が少なかったのでメモ。

## 普通のやり方

TLSバージョンを見て、アクセスを弾く。まずはこれで行こうと考えますよね。

``` httpd.conf
SSLProtocol +TLSv1.2
```

しかし実際この対応をしてサーバーにアクセスすると下の画像のように表示され、じゃあどうすればええねんということがわかりにくい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350773/da711c1e-ba23-9e73-35fe-7ba263ae23e1.png)
今どきTLS1.2対応していないブラウザでアクセスしようとする人なんてほぼいないだろうし別に良い気もしますが、もし古代のアーティファクトを使い続けている方々がこの画面を見たときどうすれば良いかは絶対にわからんだろうと思いますね。
もしも表示された通り「Webサイトの所有者に問い合わせ」なんぞされた日にはどこから説明したらいいやらｗ

ちなみに参考にしようと思った某ヤホーや某ネズミーランドのサイトでは（おそらく）この対応がなされてます。

## 丁寧で良さげなやり方
```　.htaccess
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{SSL:SSL_PROTOCOL} !^TLSv1\.2$
RewriteRule ^(.*) 遷移させたいURL [R=301,L]
</IfModule>
```
TLSバージョンを見て、別のURLにリダイレクトさせる。
これならどうすればいいかを案内出来ますね。実際これで実装しようと思ったけどうちでは結局採用しませんでしたが。
いや普通はこの設定で良さげな気がします。

（おそらく）〇〇カードマン！のサイトではこの対応をしてそうですね。なんとなく雑な印象があったので正直見直しました。

## 今回採用したやり方

挙げた2件で全然実装出来ると思うんですが、プロキシの設定やらなんやらが競合？してうまく動かず大変に面倒だったので
今回はSSL_PROTOCOLをPHPの環境変数から取得し、そこで煮るなり焼くなり好きにすることにしました。

``` .php
<?php
    echo $_SERVER['SSL_PROTOCOL'];
?>
```
うちのサーバーは外部アクセスはHTTPSで、サーバー間の通信はHTTPで行っているため下記設定をしないとSSL環境変数が抜け落ちてしまい参照出来ませんでした。

``` プロキシ設定.conf
RequestHeader set X-Forwarded-SSL-Protocol %{SSL_PROTOCOL}s
```

これでどん詰まっていたのですが、冷静に考えたら当たり前ですね...

# まとめ

今回は導線をはっきりさせるべく丁寧にやりましたが、正直必要があるかと言われたらあんまり要らない気もします。
該当する人数ももうかなり少ないし。
実際、TLSv1.1の通信でセキュリティソフトのサイトをいくつか閲覧しましたが、弾かれるところもありましたが普通にアクセスできるところもありました。
トークン等含む個人情報さえ通信しなければ基本的には問題にならないですもんね（もしこんな危険性がありますというのがあれば教えて下さい）

もしも今更ながら対応する必要が出てきた人の参考になれば幸いです。

# 参考にしたサイト
[PHPでSSLバージョンを判別する方法](https://www.nedia.ne.jp/blog/tech/2018/06/19/11980)
[httpsで受け取ったSSLバージョンを、httpで別のサーバーに受け渡す際に引き渡したい。](https://teratail.com/questions/298393)
[Apache モジュール mod_headers](https://httpd.apache.org/docs/current/ja/mod/mod_headers.html)
[[Apache] TLSのバージョンによって処理を変更する](https://hacknote.jp/archives/27866/)
[Apache httpd で接続を許すSSL/TLSのバージョンを制限する方法](https://weblabo.oscasierra.net/apache-httpd-sslprotocol/)
【Mac/PostgreSQL】psqlコマンドが使えないときの対処法

# 概要

普段は``MySQL``を使ってアプリ開発をしていますが、諸事情で``PostgreSQL``が必要になりました。

今回、``PostgreSQL v12.4``の導入を目指したのですが、途中で``psql``コマンドが使えないという現象が起きました。

この記事では``PostgreSQL導入後にpsqlコマンドが使えなかった方``のために、備忘録として僕が行ったことを記録します。
<br>

# 環境

* macOS Catalina : 10.15.7
* Homebrew : 2.5.8

ちなみにHomebrewnのバージョンは次の手順で確認します。

```:terminal
% brew --version
=> Homebrew 2.5.8
```

<br>

# 手順

まずは、``インストールできるPostgreSQLのバージョンを確認``します。

```:terminal
% brew search postgresql

==> Formulae
postgresql             postgresql@11          postgresql@9.4         postgresql@9.6
postgresql@10          postgresql@12 #これ！    postgresql@9.5
==> Casks
homebrew/cask/navicat-for-postgresql
```

``postgresql12``をインストールします。

```:terminal
% brew install postgresql@12

# ちなみに@12をつけないと、最新版がインストールされます。
```

この状態でバージョンを確認すると…

```:terminal
% brew search postgresql

==> Formulae
postgresql             postgresql@11          postgresql@9.4         postgresql@9.6
postgresql@10          postgresql@12 ✔        postgresql@9.5
==> Casks
homebrew/cask/navicat-for-postgresql
```

``インストールされたバージョンに ✔ が入っています``。

ちなみにいろんな記事を検索したところ、バージョンは``psql --version``で見れるそうです。
なのでやってみると…

```:terminal
% psql --version
=> zsh: command not found: psql
```

できない…。
どの記事にも書いてあるのに…``みんなできてることができないのは本当に焦ります…``

とはいえ``brew search postgresql``で12のバージョンが入ったことは確認できたので、頑張ればできるはずです。

しばらく``「homebrew postgresql psql できない」などと検索``し…。
色々ググり倒した結果見つかったコマンド``brew link postgresql``を実行したとき。

```:terminal
[~] % brew link postgresql@12
Warning: postgresql@12 is keg-only and must be linked with --force

If you need to have this software first in your PATH instead consider running:
  echo 'export PATH="/usr/local/opt/postgresql@12/bin:$PATH"' >> ~/.zshrc
```

最後の行に、ヒントが出てきました。
エラー文をGoogle翻訳で和訳してみると、次のとおりです。

> (和訳)
警告：postgresql @ 12は樽のみであり、-forceとリンクする必要があります
このソフトウェアを最初にPATHに含める必要がある場合は、代わりに検討してください。

和訳して逆によくわからなくなりましたが、``どうやらPATHを通さないと、psqlコマンドが使えないようです``。

なので指示通り、.zshrcに環境変数を設定します。

```:terminal
# vim で確認
% vim ~/.zshrc

# i でインサートモードに

# 最後の行に
export PATH="/usr/local/opt/postgresql@12/bin:$PATH"

# esc => :wq で閉じる

# 更新
% source ~/.zshrc
```

これで、``psql``を使えるようになりました！

```:terminal
% psql --version
=> psql (PostgreSQL) 12.4
```

無事に``psql``コマンドを使えるようになり、``PostgreSQL v12.4``の導入を確認できました！

<br>

## 参考
* <a href="https://qiita.com/yuppymam/items/fad4eec0c5b7d6c86517">Qiita | 【Mac】Homebrew を使って PostgreSQL を動かす</a>