OmniAICreator/Qiita-1.07M huggingface dataset:
Wordpressでfigureタグ+pictureタグを扱う

Wordpress(以下WP)を使用した案件で、挿入する画像にキャプションを付ける場合と付けない場合で出力されるタグに違いがあったので、どの場合でもfigureタグ+picutureタグで出力するようにする必要があった。
また画像はwebp形式で表示することを目的としています。

## figureタグとは？
一昔前まではimgタグが存在し、Googleなどの検索エンジンやブラウザはimgタグが「画像」ということが認識できました。
しかしCSSもバージョンがあがり、簡単な図形やイラストの場合はCSSで作ることができ検索エンジンは「画像」という認識ができなくなり、そこでfigureタグが生まれました。
またfigureタグにfigcaptionタグというものを含めることができ
表示しているものの説明を文字で表示することができます。

## pictureタグとは？
- 画面の幅に応じて表示する画像を出し分けることができる
（PCの場合はA画像、SPの場合はB画像のような）
- **webpを使用する際に対応していないブラウザの場合、代替画像を設定できる**

```html
<picture>
  <source srcset="***" media="(min-width: 1000px)"/> <!-- 幅1000px以上なら表示 -->
  <source srcset="***" media="(min-width: 700px)"/> <!-- 幅700px以上なら表示 -->
  <img src="***" /> <!-- 上記が当てはまらない場合に表示 -->
<picture>
```


## キャプションなしの画像を登録した場合
クラシックエディターの上部にある「メディアを追加」ボタンから画像を追加した場合
![スクリーンショット 2021-10-19 15.04.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542793/ab00b090-42df-4c6d-a368-88aba382b27d.png)

```html
<img loading="lazy" class="alignnone size-full wp-image-4632" src="http://localhost:8080/wp-content/uploads/2021/08/image1.png" alt="" width="640" height="640">
```
imgタグで挿入される

## キャプションありの画像を登録した場合
![スクリーンショット 2021-10-19 15.19.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542793/4167b6a5-a27f-e28c-9156-17627bc755c4.png)

クラシックエディター上ではWPショートコードで挿入される。

```html
[caption id="attachment_4632" align="alignnone" width="640"]<img class="wp-image-4632 size-full" src="http://localhost:8080/wp-content/uploads/2021/08/image1.png" alt="" width="640" height="640" /> これはキャプションです[/caption]
<!-- /wp:paragraph -->
```

記事を表示した場合（ショートコード変換後）

```html
<figure>
<img loading="lazy" class="wp-image-4632 size-full" src="http://localhost:8080/wp-content/uploads/2021/08/image1.png" alt="" width="640" height="640">
<figcaption>これはキャプションです</figcaption>
</figure>
```


### キャプションなしでもありでも、この形で出力したい！！！！
Q. でもなぜ？
A. webp使用する場合に、非対応ブラウザの場合は代替画像をだすことができるため

```html
<figure>
  <picture>
    <source srcset="***"/>
    <img src="***" />
  </picture>
  <figcaption>これはキャプションです</figcaption>
</figure>
```

### 解決方法
- 本文を表示する際にWPのフックを使って、画像のタグを置換する

WPのクラシックエディターで入力している場合
the_contentのフックを使うことで本文を加工することができます。

```php:functions.php
function update_content($content) {
    // imgタグからsrc width height altを取り出す
    $pattern = '/<img.*?(?=.*?src\s*=\s*[\"|\'](.*?)[\"|\'])(?=.*?width\s*=\s*[\"|\'](.*?)[\"|\'])?(?=.*?height\s*=\s*[\"|\'](.*?)[\"|\'])?(?=.*?alt\s*=\s*[\"|\'](.*?)[\"|\'])?.*?>/i';

　　　　　　　　// マッチしない場合は$contentをそのまま返す
    $update_content = preg_replace_callback($pattern, function ($matches) {

        $src = $matches[1];
        $width = $matches[2];
        $height = $matches[3];
        $alt = $matches[4];

        $format = '<picture>'
            . '<source type="image/webp" srcset="%s.webp">'
            . '<img src="%s" width="%s" height="%s" alt="%s" />'
            . '</picture>';

        return sprintf($format, $src, $src, $width, $height, $alt);

　　　　　　　　}, $content);

    return $update_content;
}
add_filter('the_content', 'update_content');
```

### 最後に
今回は画像をfigure+picture構造で出力することを目標としており
Wordpressでwebpを生成する方法は割愛しております。
"_"(アンダースコア)の使い方

プログラミングにおける```_``` (アンダースコア)の使い方について学んだのでまとめておく。

#"_"(アンダースコア)の使い方
```_``` (アンダースコア)が使われている場合は主に以下の3つがある。
### 1. 名前の前にある場合("_"が１つ)
Java、C++、JavaScriptにおいて、privateな変数やメソッドを意味する。
メソッドや変数の名前の前に```_```がついた変数やメソッドはクラスの外から直接読み書きしないようにする。ただし、これはコーディングルールの慣例にすぎず、言語仕様ではない。
【例】
```this._value```
```_func(){}```


### 2. 名前の前にある場合("_"が2つ)
Pythonでは言語仕様として、privateなメンバを意味する。
JavaScriptやC++については、予約語とされているため、使用することは推奨されていない。


### 3. 名前の途中にある場合
「スネークケース」などの命名規則によるもの。スネークケースでは、単語と単語を```_```でつないでいる。
【例】
```student_name```
```student_id```

# まとめ
```_``` (アンダースコア)の使い方についてまとめてみた。
まだ自分の知らないコーディングルールの慣例があるので徐々に身につけていきたい。
PostgreSQLで空配列を返したい

# 経緯
`json_agg関数`と`array_agg関数`を使ってSQLからJSONを返す処理を実装していたが、特定条件の場合、`CASE式`で空配列を返す処理が必要になって、試行錯誤することになった。基本使わないと思うが、なかなか苦労したのでメモとして残す。

# 結論

```sql
-- 空配列を返す。配列の型は宣言する必要がある
SELECT ARRAY[]::VARCHAR[] AS empty_array;
```

# 試行錯誤メモ

```sql
-- [null]が返ってくる。nullが入った配列であり、空配列ではない
SELECT ARRAY[NULL] AS null_array;

-- 上記からnullを削除する。空配列が返ってくるけど、処理効率は悪そう
-- ちなみにpg_typeof関数にかけたらtext[]が返ってくる
SELECT array_remove(ARRAY[NULL], NULL) AS bad_empty_array;

-- 型宣言がないとエラーになる
SELECT ARRAY[] AS error;
```
Excel関数の日付計算

###・要件
SFDCのGMT時間はJST時間のExcel計算。
###・対応案
GMT時間の形式：2021-10-04T15:00:00.000ZからDateValueとTimeValueで計算し、後Textでフォーマットする

###・例
2021-10-04T15:00:00.000Z　→2021/10/5  00:00:00
#####式



```
     =TEXT(DATEVALUE(LEFT(AM9,10))+TIMEVALUE(MID(AM9,12,8)) + TIMEVALUE("09:00:00"),"YYYY/MM/DD HH:mm:SS")

```
JSONの紹介

<H2> JSONの紹介 </H2>
<div id = "intro">
<p> <strong> JSON：<span class = "marked"> J </span> ava <span class = "marked"> S </span> cript <span class = "marked"> O </span> bject <span class = "marked"> N </span> otation（JavaScriptオブジェクト表記）。 </strong> </p>

<p> <strong> JSONは、データを保存および交換するための文法です。 </strong> </p>

<p> <strong> JSONは、JavaScriptオブジェクト表記で記述されたテキストです。 </strong> </p>
</div>

<div>
<h2>データの交換について</h2>

<p>ブラウザとサーバー間でデータを交換する場合、データはテキストのみになります。 </p>

<p> JSONはテキストであり、任意のJavaScriptオブジェクトをJSONに変換してから、サーバーに送信できます。 </p>

<p>サーバーから受信したJSONをJavaScriptオブジェクトに変換することもできます。 </p>

<p>このようにして、複雑な解析や変換を行うことなく、データをJavaScriptオブジェクトとして処理できます。 </p>
</div>

<div>
<h2>データの送信について</h2>

<p>データがJavaScriptオブジェクトに保存されている場合は、オブジェクトをJSONに変換してサーバーに送信できます。 </p>

<h3>例</h3>

<pre>var myObj = { name:"Bill Gates",  age:62, city:"Seattle" };
var myJSON = JSON.stringify(myObj);
window.location = "demo_json.php?x=" + myJSON;
</pre>
</div>

<div>
<h2>データの受信について</h2>

<p> JSON形式でデータを受け取った場合は、JavaScriptオブジェクトに変換できます：</p>

<h3>例</h3>

<pre>var myJSON = '{ "name":"Bill Gates",  "age":62, "city":"Seattle" }';
var myObj =  JSON.parse(myJSON);
document.getElementById("demo").innerHTML = myObj.name;
</pre>
</div>

<div>
<h2>データの保存について</h2>

<p>データを保存する場合、データは特定の形式である必要があり、どこに保存するかに関わらず、テキストは常に有効な形式の1つです。 </p>

<p> JSONを使用すると、JavaScriptオブジェクトをテキストとして保存できます。 </p>

<h3>例</h3>

<p>ローカルストレージにデータを保存する</p>

<pre><span class = "code_comment">//データの保存：</span>
myObj = { name:"Bill Gates",  age:62, city:"Seattle" };
myJSON =  JSON.stringify(myObj);
localStorage.setItem("testJSON", myJSON);

<span class = "code_comment">//データの受信：</span>
text = localStorage.getItem("testJSON");
obj =  JSON.parse(text);
document.getElementById("demo").innerHTML = obj.name;
</pre>
</div>

<div>
<h2> JSONとは何ですか？ </h2>

<ul>
<li> JSONはJavaScriptオブジェクト表記（<em> J </em> ava <em> S </em> cript <em> O </em> bject <em> N </em> otation）</li >
<li> JSONは軽量のデータ交換フォーマットです</li>
<li> JSONは自己記述的で、理解しやすいです</li>
<li> JSONは言語やプラットフォームに依存しません</li>
</ul>



<p> JSONはJavaScript構文を使用しますが、JSON形式はプレーンテキストです。 </p>

<p>テキストは、任意のプログラミング言語でデータとして読み取って使用できます。 </p>

<p> JSON形式は、もともとDouglasCrockfordによって提案されました。 </p>
</div>

<div>
<h2>なぜJSONを使用するのですか？ </h2>

<p> JSON形式は単なるテキストであるため、サーバーブラウザー間で簡単に転送でき、任意のプログラミング言語でデータ形式として使用できます。 </p>

<p> JavaScriptには、JSON形式で記述された文字列をネイティブJavaScriptオブジェクトに変換するための組み込み関数が用意されています。</p>

<pre> JSON.parse()</pre>

<p>したがって、サーバーからJSON形式でデータを受信する場合は、他のJavaScriptオブジェクトと同じように使用できます。 </p>
</div>
ローカルのphpバージョンを設定

### Homebrewを使ってlocalのphpバージョンを設定する場合

#### 1. Homebrewに下記をインストール

```
brew install php　# 入れておかないと怒られるので追加しておく
brew install php@7.4
```

#### 2. Homebrewにlocalのphpをphp@7.4へ切り替える

```
brew unlink php && brew link --overwrite --force php@7.4
```

#### 3. 上記のcommandで出てきた案内通りに`~/.zshrc`へechoで指定のパスを追加

#### 4.下記コマンドで、`~/.zshrc`の内容を反映

```
source ~/.zshrc
```
helmのコマンドと使い方


# install
```
brew install kubernetes-helm
helm version
```

# helm用のnamespaceの作成
```
kubectl create namespace helm-test   // 作成
kubectl get namespace    // 確認
kubectl config set-context $(kubectl config current-context) --namespace=helm-test  // 切り替え
```

# helmのprometheus chartの取得,削除
```
helm install stable/prometheus --generate-name   // 取得
helm ls
helm delete prometheus-1634786686   // 削除 lsででてきたNameを指定
```

# helm repositoryの操作

```
$ helm repo list
NAME    URL                          
stable  https://charts.helm.sh/stable

$ helm repo add incubator https://charts.helm.sh/stable  // repoの作成
"incubator" has been added to your repositories
```
【Rails】Tag機能　

#投稿にタグを紐付け〜絞り込みまで

##前提 
- 投稿機能実装済
- bootstrap使用


##実装
###多対多の関係なので中間テーブルを用意
####まず`tag`モデル作成

```:ターミナル
$ rails g model tag name:string
```

```ruby:
class CreateTags < ActiveRecord::Migration[5.0]
  def change
    create_table :tags do |t|
      t.string :name, null: false

      t.timestamps
    end
  end
end
```
`null:false`を追加,空で保存できないように修正する

####`boards`と`tag`を紐付ける中間テーブルの作成

```:ターミナル
$ rails g model board_tag_relation board:references tag:references
```


```ruby:
class CreateBoardTagRelations < ActiveRecord::Migration[5.0]
  def change
    create_table :board_tag_relations do |t|
      t.references :board, foreign_key: true
      t.references :tag, foreign_key: true

      t.timestamps
    end
  end
end
```

``` :ターミナル
rails db:migrate
```

### アソシエーション
`through`で中間テーブルを経由して掲示板との関連付け
※複数形
`dependent: :delete_all`で`board`モデルのデータの削除と共に紐付いたタグも削除されるよう記述（複雑な処理でなく、まとめて削除する際効率が良いということでdelete_all使用）

```ruby:app/models/tag.rb
class Tag < ApplicationRecord
  has_many :board_tag_relations, dependent: :delete_all
  has_many :boards, through: :board_tag_relations
end
```

```ruby:app/models/board.rb
class Board < ApplicationRecord
  has_many :comments, dependent: :delete_all
  has_many :board_tag_relations, dependent: :delete_all
  has_many :tags, through: :board_tag_relations
end
```
### ストロングパラメーターに`tag_ids`を忘れず記述
ビューのチェックボックスに指定する`tag_ids`を許可する指定 `[]`は配列で渡ってくることを意味

```ruby:app/controllers/boards/controller.erb
private

   def board_params
      params.require(:board).permit(:name, :title, :body, tag_ids: [] )
   end
```
### ビュー記述
タグフォーム
`corection_check_boxs`メソッド使用
第一引数に相手のモデル名_idで関連つける、第２引数にはtagオブジェクトのリストを取得して渡している
第三引数にはチェックボックスのバリューに設定するプロパティ第4引数には各チェックボックスのラベル名としての設定

``` erb:app/views/boards/_form.html.erb
<div class="form-group">
    <span>タグ</span>
    <%= f.collection_check_boxes(:tag_ids, Tag.all, :id, :name) do |tag| %>
      <div class="form-check">
        <%= tag.label class: 'form-check-label' do %>
          <%= tag.check_box class: 'form-check-input' %>
          <%= tag.text %>
        <% end %>
      </div>
    <% end %>
  </div>
```
`board.tags`をループしてタグの数だけタグ名を表示

```erb:app/views/boards/_board.html.erb
<% board.tags.each do |tag| %>
      <span class="badge badge-primary"><%= tag.name %></span>
    <% end %>
```
`rails c` や`seed`などを使用して、タグを作成したらブラウザに表示される

#### タグセレクトボックスを追加してタグに関連付いた投稿を絞り込みをできるようにする

```erb:app/views/boards/index.html.erb
<%= form_with url: boards_path, method: :get, class: 'boards__searchForm' do %>
      <%= select_tag :tag_id,
                      options_from_collection_for_select(Tag.all, :id, :name, params[:tag_id]),
                      {
                        prompt: 'タグで絞り込み',
                        class: 'form-control boards__select',
                        onchange: 'submit(this.form);'
                      } 
      %>
    <% end %>
```

####　コントローラ記述
タグ`id`があった場合にはタグ`id`から検索できるようにして、タグに紐付くリストを取得
タグ`id`が渡されなければ　`Board.all`で取得

```ruby:app/controllers/boards_controller.rb
def index
      @boards = params[:tag_id].present? ? Tag.find(params[:tag_id]).boards : Board.all
      @boards = @boards.page(params[:page])
   end
```

これでタグの絞り込みが可能です
C#とNode.jsを連携する  最終章


###EdgeJsは使わずにNode.jsの外部プログラム実行を利用する

前回はedgeJsには制約があり、ビルドでエラーが頻発することからコンソールアプリを使用することにしました。
**コンソールアプリを使うなら、nodejsに元々ある外部プログラム実行を使えばいいのではないか？という結論に至りました。**


####Node.jsの外部プログラムの実行

https://nodejs.org/api/child_process.html

```js
const { exec } = require('child_process');
const path = require("path");

let pathStr = path.join(__dirname, '../ConsoleApp1/bin/Debug/net5.0/ConsoleApp1')
let commendStr = pathStr + " args1 args2";

exec(commendStr, (error, stdout, stderr) => {
    if (error) {
        console.error(`[ERROR] ${error}`);
        return;
    }
    console.log(`stdout: ${stdout}`);
});
```

####NodeRedにも外部プログラム実行がある

nodeRedにも外部プログラム実行があるようなので、C#との連携ができると思います。

https://flows.nodered.org/node/node-red-contrib-func-exec

####使用用途
NodeRedからコンソールアプリにJsonを投げ実行します。C#内でSwitchやif文で分岐し、クラスや関数を呼び、結果をConsole.writelneで出力し、それをNode.js側で取得します。
NugetからDapperとDapperExtensionを使いSqliteの管理を楽にする。



[Gtk3アプリ NodeRedとC#を連携する 入門編](https://qiita.com/iota_11/items/5e33f53875b54d6058c0)に続く

[C#とNode.jsの連携例](https://qiita.com/iota_11/items/24ab2db7f2ee758f715c)
dockerを用いたgoreのinstall方法

みんなのGoという書籍を見ながら、goreをインストールしようとしたができなかったので、dokerを用いてgoreをインストールしてみた。

##公式レポジトリのREADNEに書いてあるとおり、以下を実行していく。

###1. まずはgit clone 

```
git clone https://github.com/x-motemen/gore.git
```


###2. goreのディレクトリに移動し、dockerのbuildとrunを実行
```
cd gore 
docker build -t gore .
docker run -it --rm gore
```

####追記

書籍に書いてあるgo getを用いた方法は、筆者のGo 1.17.2のバージョンでは動作しなかった。

```
go get github.com/motemen/gore/cmd/gore
```

これはGo1.16からのアップデートで、go getの代わりにgo installを使う仕様変更があったため。



####参照記事、書籍

・改訂2版 みんなのGo言語


・CloneしたRepository↓

https://github.com/x-motemen/gore

・Go 公式のサイト↓

https://go.dev/blog/go116-module-changes
document.queryCommandSupported('insertText')のfirefox暫定対応

firefoxがdocument.queryCommandSupported('insertText')に対してtrueを返してくるのに
実際には動作しない件について、
この場合はUndoは効かないもののとりあえずキャレット位置を分割して文字を挿入するようにし、
それ以外はdocument.execCommandを利用するパターン。

※そもそもexecCommandが非推奨ではあるんだけども、とりあえず。（調べたけど「navigator.clipboard.writeText」を使うしかない？ようだけどクリップボードが汚れるのが嫌）

```
$(function(){
	//ボタン.btnクリック時、入力欄#hoge に テキスト「XXX 」を挿入する
	$('.btn').on('click',function(event){
		insertText('hoge','XXX');
	});
});

function insertText(id,text){
	let userAgent = window.navigator.userAgent;
	let area = document.getElementById(id);
	let flag = true;

	event.preventDefault();
	area.focus();

	switch (true) {
		case userAgent.indexOf('Firefox') != -1:
		case document.queryCommandSupported('insertText') == false:
			flag = false;
			break;
	}

	if (flag) {
		document.execCommand('insertText', false, text);
	}else {
		let ss = area.selectionStart;
		let se = area.selectionEnd;
		area.value =	area.value.substr(0, ss) + text + area.value.substr(ss);
		area.selectionEnd = se + text.length;
	}
}
```

個人的には、.btnのdata属性で、挿入先IDとテキストを仕込む仕様が拡張性高くて好きです。

なお、document.execCommandの完全な代替を目指す場合、
valueに直接、挿入後のテキスト全体を入れる分岐をメインとして
「lastTextとして元のテキストを保持し、Undo時にそれを差し替える（Redo時も類似の処理）」実装を行なうことで
擬似的に対応可能だとは思いますが、
keydown時も含めて履歴を取らねば完全な代替とはいかず、誰かがまるっといい感じのコードを書いてくれることを期待します…
Couchbase Server機能解説：データ圧縮


## はじめに

本稿では、NoSQLドキュメント指向データベースであるCouchbase Serverがどのようにデータの圧縮を制御しているかを整理します。

## 概要

Couchbase Serverは、クライアントとの通信、および内部処理でデータ圧縮を行なっています。

データの圧縮により、RAMとディスクスペースをより効率的に使用できます。また、ネットワーク帯域幅の消費を削減する可能性があります。一方、CPUリソースの消費量が増える可能性があります。

## 仕様

Couchbase Serverは、オープンソースライブラリSnappyによって圧縮機能を実現しています。

圧縮は、様々な要因〜クライアントの特性、バケットに対してユーザーが設定した圧縮モード、圧縮前のドキュメントに必要な最小サイズと圧縮後のサイズ（圧縮率）の関係〜に基づいて、アイテムに適用されます。

圧縮は、バイナリアイテムとJSONアイテムの両方に適用されます。

圧縮は、CouchbaseおよびEphemeralバケットにのみ適用できます（Memcachedバケットには適用できません）。

圧縮はCouchbaseEnterprise Editionでのみ使用可能です。

## 圧縮が使用される箇所

下記は、Couchbase Serverで圧縮が利用される箇所を示しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176567/48d721cd-ff23-4338-6771-b66430bafba6.png)


Couchbase SDK　クライアント（1）、クラスター内レプリケーションに参加するクラスター内のノード（4）、内部Couchbaseサービス（5）、外部DCPクライアント（6）、およびクロスデータセンターレプリケーションに参加するリモートクラスター（7）、これらは、`HELO`コマンドを使用して、Snappy圧縮データタイプのサポートを確認するフラグを用いて、圧縮されたアイテムを送受信することが可能かどうかを伝達します。

Couchbase Serverは、（バケットのモードに応じて）圧縮された形式でアイテムをメモリに保存する場合があります（2）。サーバーは、アイテムをディスクに保存するときに常にアイテムを圧縮します（3）。

## 圧縮モード
バケットは、下記の3つのモードのいずれかを用いて構成されています。クライアントが圧縮データを送受信することができるかどうかを伝達した後、サーバーでの圧縮および解凍ルーチンの実行は、指定されたバケット用いられているモードによって異なります。



### パッシブ
クライアントから圧縮されたアイテムを受信すると、Couchbase　Serverはそれを圧縮された形式でメモリとディスクの両方に保存します。
Couchbase Serverは、クライアントから要求された場合、アイテムを圧縮形式でクライアントに送り返します。それ以外の場合は、アイテムを非圧縮形式で送り返します。
圧縮されていないアイテムを受信すると、Couchbase Serverはそれを非圧縮形式でメモリに保存し、圧縮形式でディスクに保存します。
アイテムを非圧縮形式でクライアントに返します。
このモードはバケット新規作成時のデフォルトです。
圧縮を処理することが可能なクライアントをサポートし、さらにCouchbase Serverがメモリリソースとネットワーク帯域幅の使用を制限できるようにします。
Couchbase Serverは、クライアントにとって必要のない、アイテムの圧縮と解凍にCPUリソースを使用することを強制しません。

### アクティブ
Couchbase Serverは、アイテムが非圧縮形式で受信された場合でも、メモリおよびディスクに保存するためにアイテムをアクティブに圧縮します。
アイテムは、圧縮データの受信をサポートしていないクライアントに送り返される前に解凍されます。
アイテムは、圧縮データの受信をサポートするクライアントに圧縮形式で送信されます。これらのクライアントは、元々非圧縮形式でサーバーにアイテムを送信した場合でも同様です。

このモードでは、サーバーはメモリリソースとネットワーク帯域幅を最大限に節約できます。その結果、より多くのアイテムを同時にメモリに保持できるため、全体的な効率が向上します（圧縮と解凍に必要な処理時間は、ディスクからデータをフェッチするために必要な処理時間よりも大幅に短いため）。それにもかかわらず、状況によっては、


### オフ

これがMemcachedバケット、が動作する（また、5.5より前のCouchbaseServerにとっても）唯一のモードです(現在、Memcachedバケットは、既に機能拡張が停止され、将来のサポート継続が行われない予定の「非推奨(deprecated)」機能です。Memcachedバケットの要件のために、Ephemeralバケットを利用することができ、推奨されます)。

圧縮されたアイテムを受信すると、CouchbaseServerはメモリに保存するときにアイテムを解凍します。ディスクに保存するときに再圧縮します。Couchbase Serverは、アイテムを非圧縮形式で送信します。

このモードでは、圧縮の恩恵を受けることができません。


## 圧縮比
圧縮比は、圧縮後のドキュメントのサイズとの関係においkて、圧縮前のドキュメントの最小の大きさを指定する、クラスターレベルのパラメータです。
ドキュメントがこの要件を満たしていない場合、非圧縮形式で保持されます。
このクラスターレベルのパラメーターの値は1.2です。

したがって、ドキュメントは、`original_size >= (1.2 * compressed_size)`の場合にのみ圧縮形式で保持されます。`original_size < (1.2 * compressed_size)`の場合、ドキュメントは非圧縮形式で保持されます。




## 参考情報

https://docs.couchbase.com/server/current/learn/buckets-memory-and-storage/compression.html
C#ネット学習で得られること（１／２）


:::note info
塾長：こんにちは、塾長です。

生徒：C#ネット学習で得られることはなんですか？

塾長：それは、『アルゴリズムを考える力が付く』です

生徒：『アルゴリズム』？？？？


塾長：ではこれからどこよりもわかりやすく、正確なアルゴリズムの解説をしていきます。
:::


アルゴリズムとは『目的を達成するためにコンピュータに手順を教えること』です。

C#ネット学習の教材を例にすると、「忍者が迷路から脱出する」という『目的』に対して、


「上に行く」、「右に行く」・・・とコンピュータに指示しないと、動かないし脱出できないです。


また、動かす前に通路なのか壁なのか判断しなければ動けませんね。

これらを『手順』といいます。まさに自分が迷路を脱出するときにどう考えるかが、アルゴリズムなんです。

 

**\アルゴリズムがわかったら、以下よりC#の学習を行っていきましょう！/** \:smile:

[≫C#の学習-特典あり！-](https://programingo.com/csharp-2/ "タイトル")

https://programingo.com/csharp-2/
パスワード変更で、そのユーザのHTTPセッションをすべて破棄する

---
### はじめに

Webアプリケーションで、**利用者が「パスワード変更」**を行ったら、**そのユーザのHTTPセッションをすべて破棄する。**
という実装を一般的なWebアプリケーション・フレームワークではどのように実装するのかという点について考察した。

---
### なぜこれが必要なのか

ユーザのHTTPセッションが、不正行為者にハイジャック(乗っ取り)されている場合、利用者はパスワード変更で不正行為者が乗っ取っているHTTPセッションを破棄することができる。

しかしながら、パスワードが漏洩している場合は、不正行為者が先にパスワード変更されると**「おしまい(パスワード変更での2要素認証は必須)」**だが、不正行為者よりも先にパスワード変更ができれば、不正行為をその時点までに止めることもできる。

(セッションハイジャックされた原因がそのままだと、再度ハイジャックされるかもしれないが・・・)

![passChg02a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/182822/845a51ca-9942-44e3-03a0-5e6d7572e517.png)

---
### 一般的なWebアプリケーションのHTTPセッション管理の仕組み

一般的には**「セッションID方式」**だと思う。
このセッションID方式によるHTTPセッション管理は、**「セッションID」**と呼ばれる一意で推測困難な値を、Webブラウザの(多くは)クッキーに埋め込み、その値を元にHTTPリクエストをどのHTTPセッションか認識する、というものである。
さらに、セッションIDごとにWebアプリケーション・サーバ側にメモリ(セッション変数/セッションオブジェクトと呼ばれる)が確保されて、データを保持することができる。
この方式の特徴としては、HTTPセッション間は独立であるので、「パスワード変更したユーザかどうか」を見極める仕組みがひつようとなる。

![passChg01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/182822/3ec65313-ab87-9d1f-055a-a3f84afbd408.png)

---
### 解決策

ログイン時にセッション変数/セッションオブジェクトに**何かを**記憶させておき、このセッションの年齢というか生存期間が判断できるようにする。
全てのHTTPアクセスのサーバ側の処理の一番最初で、この値をデータベース側の値と比較し、古ければ強制的にログアウトさせる。
(ログイン画面へリダイレクトさせる)

---
#### 具体的解決策1

セッション変数に、パスワードの更新日時を保持し、その値とデータベース側の**最新の**パスワード更新時間を比較し、
過去のものであれば、セッションを破棄(ログアウト)し、ログイン画面へリダイレクトさせる。

![passChg03a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/182822/6312f937-e5af-a5ba-393e-0bde1ed51b64.png)

---
#### 具体的解決策2

セッション変数に、ログイン日時を保持し、その値とデータベース側の**最新の**パスワード更新時間を比較し、
過去のりものであれば、セッションを破棄(ログアウト)し、ログイン画面へリダイレクトさせる。

![passChg04a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/182822/472fe3e4-d554-3e9e-74ee-3b1d8316c8d7.png)

---
### その他

他のやり方もあると思う。
そういうのはコメントに書いてほしい。

---
### 以上
Voiceのセキュリティ向上重要な3つの改善

Vonageは全てのAPIのセキュリティを常に改善しています。この記事では、Voiceにおける最近の重要な改善点について説明します。


Secure Real-Time Transfer＝SRTP
---------------------------------------
Secure Real-time Transfer Protocol（SRTP）は、Voice over IP（VoIP）通話での音声など、リアルタイムメディアを安全に送信するためのインターネット技術特別調査委員会[（IETF）](https://www.ietf.org/)の標準対応です。

SRTPを使用すると、SIPプロトコル利用時にSIPエンドポイントとVonageのプラットフォーム間で交換されるメディアを暗号化し、対象のメディアストリームを確実に保護します。 SRTPの使用は、既存のSIP over TLS機能と組み合わせて、シグナリングとメディア交換の両方でセキュリティを提供する事を前提としています。

Signed Callbacks
---------------------------------------
署名されたコールバック[（「webhook」とも呼ばれます）](https://developer.nexmo.com/voice/voice-api/guides/signed-webhooks)を使用すると、受信リクエストのJWT（JSON Web Token）署名を確認した上でVonageからアプリケーションに送信されていることを確認します。この機能は、サポートされているイベントの限定されており、開発者プレビューとして現在利用可能です。現在、AnswerURLを含むすべてのVoiceAPIWebhookが完全にサポートされています。ベータ段階では、Voiceアプリに対してApplicationsAPIへのAPIリクエストをアクティブ化する必要があります。現時点ではBeta版ですがGAでは、全てのアカウントとアプリケーションで自動的に有効になる予定です。

HTTPS Caching
---------------------------------------
Voice APIでは、ストリームアクションを使用して、通話中に事前録音されたオーディオファイルの再生をサポートします。一部のユースケースでは、同じオーディオファイルが複数回使用されている場合、ファイルをキャッシュするよう指定が可能です（標準の[HTTP Cache-Controlヘッダー](https://qiita.com/anchoor/items/2dc6ab8347c940ea4648)を使用）。 前の仕様ではHTTPでのみキャッシングが使用可能でした。現在は、HTTPSをサポートするように改善されたため、パフォーマンスとセキュリティの両面で改善されました。Vonageは、弊社で提供する全てのAPIサービスにおいて高いセキュリティのインターフェイスを提供するために継続的に取り組みます。それによりユーザーのデータを確実に保護される事を目指します。

関連記事
---------------------------------------
* [Vonage SIP Documentation](https://developer.nexmo.com/voice/sip/overview)
* [Voice API Signed Callbacks Guide](https://developer.vonage.com/voice/voice-api/guides/signed-webhooks#activation)
* [Fraud Prevention Guide](https://developer.vonage.com/voice/voice-api/guides/fraud-prevention)
* [Build High Availability Voice API Applications](https://learn.vonage.com/blog/2020/12/09/build-high-availability-voice-api-applications/)

参照記事
---------------------------------------
https://learn.vonage.com/blog/2021/06/17/voice-security-improvements/

連絡先
---------------------------------------
Vonage Japan合同会社
Mail: sales-japan@vonage.com
URL: https://www.vonagebusiness.jp/communications-apis/
Azure Databricksにおける日本語文字化けの対処

#読み込んだcsvファイルの日本語が文字化けに・・・

Azure Databricks notebook上で
以下のコードを記載してcsvを読み込みました。

```
df = spark.read\
  .format("csv")\
  .options(header="true", inferSchema="true")\
  .load(order_items_csv)
 
display(df)
```


読み込んだ結果は以下です。
![Databricks.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1514023/9a0f59d0-54a6-458a-c72c-78166f33441e.png)
見事に文字化けしてますね・・・

#文字コードの変換

どのように文字コード変換をするか調べました。
そこで、以下の1行を加えます。

```
.option('charset', 'shift-jis')\
```

全体は以下のようになります。

```
df = spark.read\
  .format("csv")\
  .options(header="true", inferSchema="true")\
　.option('charset', 'shift-jis')\
  .load(order_items_csv)
 
display(df)
```

![Databricks2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1514023/8602e952-3f74-1137-63cb-69169432bb40.png)


問題なく読めるようになりました！
Gerritの権限制御について

# 概要

Gerritの権限設定は、All-Projects レポジトリの、`project.config` に書かれている。この設定ファイルに、あるグループが何をできるかという設定が記述されている。

# 設定ファイルの保存場所

設定値はデータベースでもGerrit本体の設定でもなく、Gitレポジトリに保存されている。

# project.configの設定例

```
[project]
	description = Access inherited by all other projects.
[receive]
	requireContributorAgreement = false
	requireSignedOffBy = false
	requireChangeId = true
	enableSignedPush = false
[submit]
	mergeContent = true
[capability]
	administrateServer = group Administrators
	priority = batch group Service Users
	streamEvents = group Service Users
[access "refs/*"]
	read = group Administrators
	read = group Anonymous Users
	revert = group Registered Users
[access "refs/for/*"]
	addPatchSet = group Registered Users
[access "refs/for/refs/*"]
	push = group Registered Users
	pushMerge = group Registered Users
[access "refs/heads/*"]
	create = group Administrators
	create = group Project Owners
	editTopicName = +force group Administrators
	editTopicName = +force group Project Owners
	forgeAuthor = group Registered Users
	forgeCommitter = group Administrators
	forgeCommitter = group Project Owners
	label-Code-Review = -2..+2 group Administrators
	label-Code-Review = -2..+2 group Project Owners
	label-Code-Review = -1..+1 group Registered Users
	push = group Administrators
	push = group Project Owners
	submit = group Administrators
	submit = group Project Owners
```

# 参照

- [Gerrit Code Review - Access Controls](https://gerrit-review.googlesource.com/Documentation/access-control.html)
GCPに関する記事まとめ

# IAM(Identity and Access Management)
IAMの基本コンセプト

https://cloud.google.com/iam/docs/overview

ロールについて

https://cloud.google.com/iam/docs/understanding-roles

サービスアカウントに使用と管理のベストプラクティス

https://cloud.google.com/iam/docs/best-practices-for-using-and-managing-service-accounts
WireMockをスタンドアロンで起動してAPIをモック化する

## WireMockとは

> WireMock ** は、Webサービスをスタブ化およびモックするためのライブラリです。実際のWebサービスと同じように接続できるHTTPサーバーを構築します。

(開発者ドキュメントより引用 https://ja.getdocs.org/introduction-to-wiremock/)

## WireMockの導入

[公式サイト](http://wiremock.org/docs/running-standalone/)からスタンドアロン版のjarをダウンロードする。

ダウンロードしたらjarを起動する。

```cmd
$ java -jar wiremock-jre8-standalone-2.31.0.jar
```
*デフォルトのポートは8080なので、変更したい場合は`-port`オプションを使用する。

## モックの定義

jarと同階層にあるmappingsディレクトリ内に任意のファイル名でjsonを作成する。
下記の例では、ユーザー情報を取得するAPIのモックを設定している。

```json
{
    "request": {
        "method": "GET",
        "urlPathPattern": "/v1/users/[1-9][0-9]*"
    },
    "response": {
        "status": 200,
        "jsonBody": {
            "id": 1,
            "name": "username"
        },
        "headers": {
            "Content-Type": "application/json"
        }
    }
}
```

## 動作確認

WireMockサーバーを立ち上げて指定したパスにGETリクエストを送信すると、設定したモックの値が返却されることが確認できる。

```cmd
$ curl 'http://localhost:8080/v1/users/1'


StatusCode        : 200
StatusDescription : OK
Content           : {"id":1,"name":"username"}
RawContent        : HTTP/1.1 200 OK
                    Matched-Stub-Id: f8a952d2-9772-4a57-b067-65bbc4747719
                    Vary: Accept-Encoding, User-Agent
                    Transfer-Encoding: chunked
                    Content-Type: application/json

                    {"id":1,"name":"username"}
Forms             : {}
Headers           : {[Matched-Stub-Id, f8a952d2-9772-4a57-b067-65bbc4747719], [Vary, Accept-Encoding, User-Agent], [Transfer-Encoding, chunk 
                    ed], [Content-Type, application/json]}
Images            : {}
InputFields       : {}
Links             : {}
ParsedHtml        : mshtml.HTMLDocumentClass
RawContentLength  : 26
```

後は実際にモック化したいAPIの向き先をlocalhostに変更してWireMockに向けることでモックサーバーを利用できるようになる。
AndroidStudio2020.3.1で日本語が文字化けした時の対処法

Adnroid Studioを日本語変換しようとしたらそれは起こりました。

![スクリーンショット 2021-10-21 10.47.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494487/88cfb303-6cb7-06f7-a610-4f96cfb96a7e.png)

□□□□□□□□□□□□□□と表示されて何が書いてあるかわからない、、、

##対処法

Android Studio ⇨ Preferences...を開く


![スクリーンショット 2021-10-21 10.49.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494487/60206d23-9488-a86e-220b-53dd6f22528b.png)

赤く囲ったところをチェックつける
![スクリーンショット 2021-10-21 10.50.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494487/cc0bacc4-27ee-a929-4834-e4ae4f7bfd20.png)
チェックつけたらOK押してAndroid Studioを再起動
![スクリーンショット 2021-10-21 10.50.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494487/271347ad-c04a-898e-d9f7-ccb24e31bc45.png)


再度Android Studioを開くと直ってます。
![スクリーンショット 2021-10-21 10.54.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494487/779d37bc-7b6b-0862-0c58-ca0b4039178c.png)
react-router-dom でページ遷移できない原因

## 課題
[react-router-dom](https://www.npmjs.com/package/react-router-dom) を使ってサンプルと同じように書いたけれどページ遷移できずに詰まったことはありませんか？

初心者がハマりやすいポイントですが、[react-router-dom](https://www.npmjs.com/package/react-router-dom) のルーティングの方法は2種類あります。

## ルーターには2種類ある

それぞれの方法で**URLが変わり**ます。
`HashRouter` を使っていた場合、**URL に #(ハッシュ）** が追加されるので、 `https://example.com/about` のようにアクセスすると `/` にリダイレクトされます。

### 解決方法

まず、自分が使っているのが `HashRouter` か `BrowserRouter` を確かめて下さい。

- `HashRouter` → `https://example.com/#/about`
- `BrowserRouter` → `https://example.com/about`

正しい形式の URL でアクセスすると無事にページ遷移されるハズです。

### HashRouter

- メリットはサーバーサイドでの設定が不要。
- デメリットはURL の形式がいつもと違うので、ユーザーが使いづらいケースが出てくる？

#### URLの形式
`https://example.com/#/`
`https://example.com/#/about`

```
import { HashRouter, Route } from "react-router-dom";

return (
  <HashRouter>
    <Route exact path="/">component={HOME}</Route>
    <Route exact path="/about" component={AboutUs} />
  </HashRouter>
)
```



### BrowserRouter

- メリットはURLの形式がいつもと同じなので、ユーザーが違和感なく使える。
- デメリット
    - サーバサイドの設定が必要。（後述）
    - サーバーサイドでどの URL にアクセスされているか判別できない。

#### URLの形式

`https://example.com/`
`https://example.com/about`

```
import { BrowserRouter } from 'react-router-dom';

return (
  <BrowserRouter>
    <Route exact path="/">component={HOME}</Route>
    <Route exact path="/about" component={AboutUs} />
  </BrowserRouter>
)
```

`BrowserRouter` を使う場合は、全てのアクセスを `index.html` にリダイレクトする設定をサーバーサイドでする必要があります。

具体的には、`create-react-app`で言うと、 `public` ディレクトリに、 `_redirects` というファイルを作成し以下のように書きます。

```
/*    /index.html   200
```
UE5 で VS Code の環境設定ファイルが書き出されない

# C++クラス拡張でのインクルードファイルエラーの警告が大量発生

環境設定で、使用するエディタをVS Codeに設定し、プロジェクトの更新や作成を行なってもVS Code用の設定ファイルがうまく書き出されない

そのため、インクルードファイルエラーの警告など、正しいはずのコードがエラーを大量発生する状態になってしまう

## 環境設定のソースコードエディタを選択し直す

`{project_name}.code-workspace`と`.vsdode`を削除

Unreal Editor > 環境設定 > ソースコード > ソースコードエディタ

Visual Studio Codeを選択した後に、”デフォルトとして設定”を選択し、もう一度プロジェクトの更新を行うことで、VSCode用の設定ファイルが書き出された

## おまけ：UE4で書き出した設定ファイルからコピペ

この方法でもエラーを回避できたが、`.vscode`以下の大量ファイルが生成されないため、その場しのぎな感じの方法

以下の二つのファイルをエディタで編集

一部のパスはUEのインストール環境や、プロジェクトの保存場所などなどによって異なる可能性があるので、確認の上、適切なパスに書き換える必要あり

```diff_json:{project_name}.code-workspace
+{
+	"folders": [
+		{
+			"name": "MyProject",
+			"path": "."
+		},
+		{
+			"name": "UE5",
+			"path": "/Users/Shared/Epic Games/UE_5.0EA"
+		}
+	],
+	"settings": {
+		"typescript.tsc.autoDetect": "off"
+	},
+	"extensions": {
+		"recommendations": [
+			"ms-vscode.cpptools",
+			"ms-dotnettools.csharp",
+			"vadimcn.vscode-lldb",
+			"ms-vscode.mono-debug"
+		]
+	}
+}
```


```diff_json:.vscode/c_cpp_properties.json
{
    "configurations": [
        {
            "name": "Mac",
            "includePath": [
                "${workspaceFolder}/**"
            ],
            "defines": [
                "${default}"
            ],
            "macFrameworkPath": [
+                "/System/Library/Frameworks",
+                "/Library/Frameworks",
                "/Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk/System/Library/Frameworks"
            ],
            "compilerPath": "/usr/bin/clang",
            "cStandard": "c11",
            "cppStandard": "c++98",
            "intelliSenseMode": "macos-clang-x64"
        }
    ],
    "version": 4
}
```

## おわりに

先にXCodeで少し作業をしたために、環境移行がうまくいかなかったのか、Early Access版の不具合なのか？

以上、走り書きでした m(_ _)m
Centos8(8.4)へのDocker-composeインストール手順

特に難しいわけではないですが、知らないとできないのでメモ

1)ダウンロード
コマンドはこちら

```
 wget https://github.com/docker/compose/releases/download/1.25.5/docker-compose-Linux-x86_64
```
結果はこちら、

```
--2021-10-21 10:45:15--  https://github.com/docker/compose/releases/download/1.25.5/docker-compose-Linux-x86_64
Resolving github.com (github.com)... 52.69.186.44
Connecting to github.com (github.com)|52.69.186.44|:443... connected.
HTTP request sent, awaiting response... 302 Found
Location: https://github-releases.githubusercontent.com/15045751/6e19c880-7b13-11ea-97d7-bec401ece2d4?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20211021%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20211021T014442Z&X-Amz-Expires=300&X-Amz-Signature=fe834254e9ad05dd70a7059cbd4bbb29a171a8b9cd3910d23d396cb85dcadc59&X-Amz-SignedHeaders=host&actor_id=0&key_id=0&repo_id=15045751&response-content-disposition=attachment%3B%20filename%3Ddocker-compose-Linux-x86_64&response-content-type=application%2Foctet-stream [following]
--2021-10-21 10:45:15--  https://github-releases.githubusercontent.com/15045751/6e19c880-7b13-11ea-97d7-bec401ece2d4?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20211021%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20211021T014442Z&X-Amz-Expires=300&X-Amz-Signature=fe834254e9ad05dd70a7059cbd4bbb29a171a8b9cd3910d23d396cb85dcadc59&X-Amz-SignedHeaders=host&actor_id=0&key_id=0&repo_id=15045751&response-content-disposition=attachment%3B%20filename%3Ddocker-compose-Linux-x86_64&response-content-type=application%2Foctet-stream
Resolving github-releases.githubusercontent.com (github-releases.githubusercontent.com)... 185.199.111.154, 185.199.109.154, 185.199.108.154, ...
Connecting to github-releases.githubusercontent.com (github-releases.githubusercontent.com)|185.199.111.154|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 17586312 (17M) [application/octet-stream]
Saving to: 'docker-compose-Linux-x86_64'

docker-compose-Linux-x86_64             100%[=============================================================================>]  16.77M  25.2MB/s    in 0.7s    

2021-10-21 10:45:16 (25.2 MB/s) - 'docker-compose-Linux-x86_64' saved [17586312/17586312]
```
無事ダウンロード完了。
次に、正しい場所へ移動。

```
mv docker-compose-Linux-x86_64 /usr/local/bin/docker-compose
```
実行できるように権限変更

```
chmod +x /usr/local/bin/docker-compose
```
バージョン確認を兼ねた動作確認

```
docker-compose --version
docker-compose version 1.25.5, build 8a1c60f6
```

以上
安全なWordpressの自動更新スクリプト

###Wordpressには自動更新機能がありますが
Wordpressに搭載されている自動更新機能にはちょっと不安がございます。
ちゃんと自動更新はできるものの、自動バックアップができないところです。

何かのアップデートによるトラブルがあったら、場合によっては致命的です。

###まずはWordpress自身の自動更新をやめる

以下を追記します。

```wp-config.php
define( 'AUTOMATIC_UPDATER_DISABLED', true );
```

###wpコマンドをインストールする

https://wp-cli.org/ja/

こちらを参照してインストールします。

なお、phpにphar が対応している必要があります。

```wp-cli-install.sh
#!/bin/sh
curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
php wp-cli.phar --info
chmod +x wp-cli.phar
sudo mv wp-cli.phar /usr/local/bin/wp
```


###以下のファイルを作成します。
```wp-autoupdate.sh
#!/bin/sh

PHP="/usr/bin/php7.4"
WP="$PHP /usr/bin/wp"
DIR="/home/(username)/backup/wordpress-file"
DOCROOT=/home/(username)/public_html
export HTTP_HOST="ドメイン"
# https:// で動いてない場合は以下をコメントアウト
export HTTPS="on"

DBNAME=データベースの名前
USERNAME=データベースのユーザー名
PASSWORD=データベースのパスワード
HOST=データベースのサーバー

mkdir -p $DIR
FNAME="$DIR/$HTTP_HOST-`date +%Y%m%d`.tar"
SQLNAME="$DIR/$HTTP_HOST-`date +%Y%m%d`.sql"

cd $DOCROOT

tar cvf $FNAME *.php wp-admin wp-includes wp-content/languages wp-content/plugin
s wp-content/themes >/dev/null 2>/dev/null
rm -rf $FNAME.xz
xz -z $FNAME

mysqldump -u $USERNAME -p$PASSWORD -h $HOST --no-tablespaces $DBNAME > $SQLNAME
rm -rf $SQLNAME.xz
xz -z $SQLNAME


$WP core update
$WP plugin update --all
$WP core language update
```

###crontabに登録します

```crontab.txt
0 4 30 * * /bin/bash /home/username/bin/wp-autoupdate.sh
``
HTML & JavaScriptで複数動画を順次ループ再生する方法

[完成コード](#完成コード)
[ハマった点１）自動再生しない](#ハマった点１）自動再生しない)
[ハマった点２）ビデオがフッタの下に表示された](#ハマった点２）ビデオがフッタの下に表示された)
[参考記事](#参考記事)

#完成コード

```
<div class="top-video">
<video id='video' width="640" height="360" autoplay muted ></video>
<script type="text/javascript">
'use strict';

var playlist = [
  '＜ビデオ１URL＞.mp4',
  '＜ビデオ2URL＞.mp4',
  '＜ビデオ3URL＞.mp4'
]

var video = document.getElementById('video');
video.muted = true;
video.autoplay = true;
video.style.width = '640';
video.style.height = '360';
video.controls = false;
video.src = playlist[0];
video.play();
var index = 0;

window.addEventListener('DOMContentLoaded', function(){
const videoElement = document.querySelector("video");
videoElement.muted = true;
videoElement.autoplay = true;
});

video.addEventListener('ended', function(){
  index++;
  if (index < playlist.length) {
    video.src = playlist[index];
    video.play();
  }
  else {
    video.src = playlist[0];
    video.play();
    index = 0;
  }
});
</script>
</div>
```

#ハマった点１）自動再生しない

HTMLに`autoplay`を指定したのに自動再生しなかった

```
<video id='video' width="640" height="360" autoplay></video>
```

最近のブラウザでは、音声付き動画の自動再生が制限されているため
対策：
`muted`：無音声再生を指定すれば自動再生された

```
<video id='video' width="640" height="360" autoplay muted></video>
```

#ハマった点２）ビデオがフッターの下に表示された

```
document.body.appendChild(video);
```

このコードのために、すべての要素の最後に回されていた
削除して普通にコンテンツ領域に表示

#
#

***
#参考記事
`https://gist.github.com/yoshiiz/6134482f8fd72063e7221b7b82d27e67`
`http://lifelog.main.jp/wordpress/?p=981`
`https://se.ekaki-j.com/html5-video/`
【Google Spread Sheet】スプレッドシートでお手軽スクレイピング

グーグルスプレッドシートで簡単にスクレイピングをする方法です。


```
= IMPORTXML(URL, クエリ)
```

URL:スクレイピングしたいサイトのURLを入れます。
クエリ: デベロッパーツール上で要素を右クリック、「Copy→Copy XPath」を選び、クリップボードにコピーされたXPathをここに入れる。

——

サーバーにあげたページのタイトルなどの要素が正しく反映されているかを確認できます。
簡単にURL上の要素を取得できるのですが、動作が重いので注意が必要です。
Hugoで最初のセットアップ例

### 実行した環境

- macOS BigSur 11.6
- Macbook Air (M1, 2020)
- Hugoはすでにインストール済み

全部大文字の箇所は固有名詞が入る想定です。



### 初期ファイルの生成

```
% hugo new site PROJECT_NAME
```

このあとの操作のために中のディレクトリへ移動しておきます。

```
% cd PROJECT_NAME
```


### Gitのリポジトリを作成する

```
% git init
```

### テーマを取得する

Hugoではサブモジュールとして扱うことが推奨されているらしいです。この例ではStackというテーマを使用しています。

```
% git submodule add https://github.com/CaiJimmy/hugo-theme-stack/ themes/hugo-theme-stack
```

テーマフォルダ内の設定ファイルとコンテンツファイル一式を、サイト用にコピーします。

```
% cp -r themes/hugo-theme-stack/exampleSite/* .
```

設定ファイルはテーマに含まれているconfig.yamlを使用するため、初期ファイル生成時の設定ファイルである、config.tomlを削除しておきます。

```
% rm -rf config.toml
```

一度サーバを起動して、動作を確認します。

```
% hugo server
```

![hugo_stack.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1417/fff09db6-581b-6e03-300d-5ce640fc3bb9.png)


大丈夫そうなので、Ctrl+Cでサーバを停止。
Gitリモートレポジトリへ上げておきます。

```
% git add .
% git commit -m "my first commit"
% git remote add origin https://github.com/ACCOUNT_NAME/PROJECT_NAME.git
% git push -u origin master
```
【git】差分ファイルの抽出


業務で差分ファイルのみをzip形式でアップロードする必要があったため、エイリアスを作成しました。
（もっといろんなエイリアスを作っている人はいっぱいいると思いますが、今のところ自分はこれくらいで十分かな）
マスターとの差分を出す場合と、直前のコミットとの差分を出すときのエイリアスとその中身を見ていければと思います。

#エイリアス

```..gitconfig
[alias]
    al = !git archive HEAD `git diff --name-only master HEAD --diff-filter=ACMR` -o al.zip
	dif = !git archive HEAD `git diff --name-only HEAD~1 HEAD --diff-filter=ACMR` -o dif.zip
```

#中身の解説

>al = !git archive HEAD `git diff --name-only master HEAD --diff-filter=ACMR` -o al.zip

##"!"

"!"をつけないとエイリアスの中身に勝手に"git"が入ってしまうため、"!"をつけることで中身がそのまま展開される。

##"git archieve"

>git archive [コミットIDなど] -o [ファイル名]

上の形式で指定のコミットを指定のファイル名で出力する。

##git diff --name-only master HEAD --diff-filter=ACMR

>git diff [比較ブランチ1] [比較ブランチ2]

でブランチ間の差分を出す。 --name-onlyはファイル名だけを表示させるために必要。
--diff-filter=[]は[]に指定したものをフィルターする。

A:Add=追加
C:Copy=コピー
M:modify=修正
R:Rename=名前変更

つまり上記4つの変更があった差分をファイル名で出力するのが、

>git diff --name-only master HEAD --diff-filter=ACMR

まとめると"al"というエイリアスはmasterとHEAD間で「追加」「コピー」「修正」「名前変更」があったファイル名を出力し、git archieveでそれらのファイルをzip形式でまとめている。
Zipが吐き出されるのはそのままだとレポジトリのルート。
【git】gitのエイリアスの指定方法

windowsの場合、

C:>Users>[ユーザー名]>.gitconfig

の最後に

```
[alias]

#エイリアス
```

という形式で記述。

例：

```
[alias]
al = !git archive HEAD `git diff --name-only master HEAD --diff-filter=ACMR` -o al.zip
dif = !git archive HEAD `git diff --name-only HEAD~1 HEAD --diff-filter=ACMR` -o dif.zip
```
【git】vscode上で快適にgitを使う

Gitを使う際にsource treeを使って操作をするという方も多いのではないかと思います。
私も最初はsource treeを使っていたのですがこのソフトなかなか重たいんですよね、、
しかもコンフリクトを解決しようとすると結局vscode上で解決していたので、
これって全部vscode上でやった方が早いのではと思い、好みの問題かもしれませんがvscode上でgit操作を快適にする方法を調べました。

#git graph

そのままだとコミットツリーが見えないので、git graphという拡張機能をインストール。
これを入れるとコミットツリーが見えるようになるだけでなくチェックアウト、マージなどの操作も簡単に行えるようになります。

https://marketplace.visualstudio.com/items?itemName=mhutchie.git-graph

#ステージング・コミット・プッシュ

左側のgitのアイコンから簡単に行えます。

![63A568D8-0BBB-4BC8-9588-76196CC8509F.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/856144/59ce16f9-2ae7-338f-5ae7-7267cb254621.jpeg)

——

viscideでgit を使うとかなり快適なので試してみて下さい。
ウォーターフォールとアジャイルの違い、メリット・デメリット

仕事ではじめてアジャイルでの開発をすることになったので、改めてウォーターフォールとアジャイルのetcについて調べてみました。

## 仕様と要求

- ウォーターフォール
    - 厳密に取りまとめてから開発を進める。
    - 開発途中の仕様変更などを想定していない
- アジャイル
    - 大枠だけを決めて開発を進める
    - 開発途中での変更や追加を予め想定している

## 開発の工程

- ウォーターフォール
    - 「要件定義→設計→開発→テスト→運用」の工程を一回限り行い、後戻りを想定していない
- アジャイル
    - 「要件定義→設計→開発→テスト→運用」の工程を繰り返し行う。

## 顧客への提供タイミング

- ウォーターフォール
    - 全ての機能の開発が終了し、プロジェクトが完了した後
- アジャイル
    - 開発が終了した機能から随時提供することが可能

## メリット

- ウォーターフォール
    - プロジェクト全体のスケジュールが立てやすい
    - プロジェクトの進捗管理がしやすい
    - 人員が変更されても引継ぎが行いやすい
    - 開発費用や人数が見積もりやすい
- アジャイル
    - 仕様変更にスムーズに対応できる
    - 開発のスピードが速い
    - 仕様変更に柔軟に対応できるため、顧客の要望を満たしやすい
    - スケジュールを柔軟に組むことができる

## デメリット

- ウォーターフォール
    - 仕様変更や問題発生時などの対処に手間がかかる
    - 手戻りは各工程をさかのぼらないといけない
    - WBSの作成に時間がかかる
    - 成果物の作成に時間がかかる
- アジャイル
    - 開発の方向性や目的がぶれやすい
    - 進捗のコントロールが難しい

## 開発ケースによって使い分ける

- ウォーターフォール
    - 安定稼働しているシステムのリプレース
    - 厳密な要件定義が必要な管理系のシステム
- アジャイル
    - 技術変化の激しいモバイル業界や研究分野
    - 簡単に操作できるUIが必要なソフトフェア
    - ニーズが変化しやすいシステム
機械学習モデルの推論結果を返す Web API を FastAPI で作成

# はじめに

機械学習で作成したモデルを実用化するには、システムが必要になる。もっともシンプルなシステム実装としては、学習済みモデルが API リクエストに対して推論結果をレスポンスで返す簡単な Web API が考えられる。具体的には、推論対象の CSV データをもたせた POST リクエストに対して推論結果を返すような Web API を想定している。機械学習モデルは大半が Python で構築されているため、API も Python ベースで作成することが望ましいと考え、FastAPI を用いた Web API を段階を踏んで作成していく。
[シンプルな Web API を FastAPI で作成](https://qiita.com/honda28/items/4c6a4b7235ce43c7131e)ではまず FastAPI を使った簡単な Web API を作成した。続いて [FastAPI で作成した Web API にて、リクエストボディのデータを DataFrame に直接入れる](https://qiita.com/honda28/items/2aa04e1b4f689bd3287d)で、リクエストボディのデータを DataFrame に直接入力できるようなものに改良した。本記事では、当初の目的である機械学習モデルの推論結果を返す Web API を作成する。[FastAPI 公式ドキュメント](https://fastapi.tiangolo.com/ja/)、[機械学習システムデザインパターン](https://www.amazon.co.jp/AI%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AE%E6%A9%9F%E6%A2%B0%E5%AD%A6%E7%BF%92%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3-AI-TECHNOLOGY-%E6%BE%81%E4%BA%95-%E9%9B%84%E4%BB%8B/dp/4798169447)を参考にした。

実行環境は以下。

- Python 3.7.12
- fastapi 0.70.0

# 必要なパッケージのインストール

学習環境で使用していたパッケージ類および fastapi, uvicorn など必要なパッケージをインストールする。学習環境で使用していたパッケージを `pip freeze > requirements.txt` で出力しておく。（余分なパッケージも含まれるが、ここではとりあえずの稼働なので目をつむる。）

```bash
$ pip install --no-cache-dir -r requirements.txt
$ pip install fastapi uvicorn
$ pip install python-multipart # リクエストボディのファイル受け取りに必要なパッケージ
```

`--no-cache-dir` はキャッシュを無効に、`-r` は指定した requirements.txt からインストールする。

# ディレクトリ構成

ディレクトリ構成は以下。

```bash
.
├── __init__.py
├── models
│   ├── __init__.py
│   └── model.pickle    # ロードするモデル
├── requirements.txt    # 必要なパッケージリスト
└── src
    ├── __init__.py
    ├── app
    │   ├── __init__.py
    │   ├── app.py      # API 実行
    │   └── routers.py  # ルーティング設定
    └── ml
        ├── __init__.py
        └── predict.py  # データ読み込み・前処理・推論など詳細な処理
```

# コード例

以下はコード例のイメージ。（実行未確認）

```python:src/app/app.py
from fastapi import FastAPI
from src.app.routers import router

app = FastAPI()
app.include_router(router, prefix="", tags=[""])
```

```python:src/app/router.py
from fastapi import APIRouter, File, UploadFile
from src.ml.predict import Model

@router.get("/health")
def health():
    """
    Web API の実行確認
    """
    return {"health": "ok"}

@router.post("/predict")
async def predict(file: UploadFile = File(...)):
    """
    POST で与えられたストリームデータに対して推論
    """
    model = Model(
        data_filepath=file.file
    )
    model.predict()
    return {"result": model.result}
```

```python:src/ml/predict.py
from io import StringIO
import pandas as pd
import pickle

class Model(object):
    """
    ファイルを読み込んで推論
    """
    def __init__(self, data_filepath):
        _data = str(data_filepath.read(), 'utf-8') # ストリームデータを str に変換
        self.data = pd.read_csv(StringIO(_data))
        self.model = self.load_model()
        self.result = None

    def load_model(self):
        with open('./models/model.pickle', 'rb') as f:
            _model = pickle.load(f)
        return _model

    def predict(self):
        ...
```

`uvicorn src.app.app:app --reload` にて実行・動作確認ができる。

# おわりに

機械学習モデルの推論結果を返す Web API を FastAPI で作成した。ベースはこのような形でより高度なことができるように追加していきたい。
input要素で親子間の値を受け渡す方法（Vue.js）

inputフォームをコンポーネント分割する際、「あれ、値の受け渡しってどうしたらいいんだ？？」となったので調べたことをこちらに簡単にまとめたいと思います。

詰まった点は、これまでinput要素に入力された値を取得するときv-modelで取得してたけどコンポーネント分けたらできなくなるよね？というところでした。

# 結論： v-modelのままだと値は取得できない

通常のデータバインディングであればv-modelを使うことで実現できます。しかし、親子コンポーネント間で値を受け渡すときはそれでは動きません。

# 解決策： 取得方法

v-modelの代わりにv-bind:value（:value）とv-on:input（@input）で取得します。

### ファイル構成
MainPage.vue（親）
FormInput.vue（子）


### 子コンポーネントの作成
子コンポーネントのinput要素に@inputと:valueをセットします。
そして、@inputで受け取った入力をevent引数で受け取ると同時にgetInputDataメソッドを発火、$emitの第二引数に値をセットして親コンポーネントに送るよう記述します。

<br>

$emitは単体だと親コンポーネントのメソッドを子コンポーネントから発火したりできますが、第二引数を指定することで親にデータを受け渡す役割も担います。

```FormInput.vue
<template>
  <div>
    <input type="text" @input="getInputValue" :value="value" />
  </div>
</template>

<script>
export default {
  props: {
    value: String,
  },

  data() {
    return {
      showInputData: "",
    };
  },

  methods: {
    getInputValue($event) {
      this.$emit("inputValue", $event.target.value);
    },
  },
};
</script>
```

### 親コンポーネントの作成
親コンポーネントでは先程送られてきた値をinputDataメソッドの引数として受け取りthis.showInputDataへ代入します。

```MainPage.vue
<template>
  <div>
    <FormInput :value="data" @inputValue="inputData" />
    {{ showInputData }}
  </div>
</template>

<script>
import FormInput from "./FormInput";

export default {
  components: {
    FormInput,
  },
  data() {
    return {
      data: "",
      showInputData: "",
    };
  },
  methods: {
    inputData(value) {
      this.showInputData = value;
    },
  },
};
</script>
```

これでinputで入力された値を無事親コンポーネントで表示することができました。
WordPressの投稿機能を使うときに検討すべき事柄

株式会社ココロファン - エンジニアリング事業部所属のSassyです。

普段は業務委託で仕事をしながら、自社プロダクトの企画/開発をしています。

## 最初に

これまで弊社はSESメインでやっておりましたが、8月頃からWordPressを使ったWebサイト制作の受託業務を始めました。

そこで「ブログ」「お知らせ」「募集要項」「社員インタビュー」という要素があり、これらはお客様側で追加、削除、更新をしやすいようにするという要件がありました。

当初、WordPressの投稿機能を使って、「ブログ」「お知らせ」「募集要項」「社員インタビュー」をカテゴリとして記事作成時にカテゴリ付けを行ってもらい、WordPress上では表示したい箇所でPHPを書いて`get_posts`関数を使って引数パラメータに特定のカテゴリで絞り込むようにcategory_idを渡して取得して表示するようにしました。

しかしここでいくつかの問題が発生してしまったのです。

表示上は問題ないのですが、これらの記事ページや記事の一覧ページをそれぞれ細かくカスタマイズしようとすると問題が出てきます。

これを実際に製作序盤で気づければよかったのですが、後半になって入ってくる様々な変更により対応できなくなっていきました。

１つのテンプレート内でカテゴリ毎に出しわける分岐を入れて対応しました( ;∀;)

そもそも要件を細かく洗い出せてなかったというところもありますが、制作前に未来を見通すことは結構難しいことなので最初からある程度設計して、後々の変更にも対応できるように投稿機能を使うときはこういうことを考えておくとよいですよという内容の記事になります。


## 要素を洗い出す

要素という抽象的な表現を使わせていただきますが、今回の案件ですとお客様側で追加、削除、更新ができるようにしたい部分になります。

「ブログ」「お知らせ」「募集要項」「社員インタビュー」ですね。

他にも扱いたい要素があるかを確認します。

可能であれば、さらに細かく洗い出していきます。

例えばですが、「ブログ」には【技術情報】【広報】があるとか、「募集要項」には【正社員】【パート】【技術職】【営業職】【総合職】があるといった具合です。

こういった細かい部分まで一通り洗い出せると良いです。

洗い出したものが多い場合は投稿自体（投稿タイプ）を分けるか、またはカテゴリやタグなどで表現できないかを検討します。

お客さん側である程度決まっているなら、そのカテゴリなどを参考に整理すればよいですが、まとまっていないならこちら側で洗い出して、「ブログのカテゴリとして～で検討していますがいかがでしょうか？」、「募集要項のカテゴリとして～で検討していますがいかがでしょうか？」みたなやり取りは必要になってくるかと思うので、そこは状況を見ながら作業していけばよいと思います。

## 洗い出した要素の性質を見極める

次に要素の性質を見極めます。

この性質を見極めるというのは例えば「ブログ」「お知らせ」「募集要項」「社員インタビュー」とあった場合、「ブログ」「お知らせ」は外部に共有したいもの、「募集要項」「社員インタビュー」は特に外部に共有するほどではないといった、そのページが持つ特徴などを考えます。

ここでそれぞれが持つ特徴が異なってくるとテンプレートを分けるかどうかの判断が必要になります。

上記の４つの要素をすべて1つのテンプレートで表示する場合、例えば「ブログ」「お知らせ」にSNSボタンを表示したいのに「募集要項」「社員インタビュー」も表示されてしまって変更できないというような状況が発生します。

また、「募集要項」の一覧ページにサムネイルは不要なのにテンプレートがすべてで共有されていることでサムネイルと削除できないとか、そういったことが起こり改修にコストがかかるようになります。

これらの要件が複雑化してくると１つのテンプレートでやり過ごすのは苦しくなるのです。

最悪1つのテンプレート内に分岐がたくさん入りバグの温床になりかねません。

ただですらPHP in HTMLなので非常に可読性が低くなります。

そのためにも各要素の性質を見極めるのは重要だなと感じました。

一通り検討が済んだらテンプレートを分けるかどうかを判断します。

## 最後に

今までWordPressでサイト制作は何回か経験しましたがWordPress1本でやってきているわけではないので色々調べながらやりました。

納期も迫っている中で今の自分の持っている知識でやりきらなければならないというところと、後々制作を進めていくとその過程で調べて新しく分かったことなどがあり、そこから実装を変えたりしたいなと思ったり…笑

しかし、今回は納期に間に合わせる方が大事であったため、今回得た知見は今後の制作業務に活かせたらと思っております。


株式会社ココロファンでは自社プロダクトの開発も行なっており、やってよかったこと、やってわかったこと、便利なノウハウを皆さんに共有できるように、これからも積極的に技術記事をアップしていきたいと思います！

https://cocolofun.co.jp/
Backlogのプロジェクトを移動してみる

おはようございます、本日は課題管理で利用しているBacklogプロジェクトを移動することになったのでこちらのドキュメントを見て試してみます。

https://backlog.com/ja/backlog-migration/backlog-migration-manual-1.5.5.pdf

ここで用意されているのはAPIを使った移行用ツールになります。Javaで書かれているとのことでJavaを実装する環境が必要となります。

こちらが実装ファイルです。（最新版はbacklog.comより確認ください）

https://backlog.com/ja/backlog-migration/backlog-migration-1.5.5.jar


APIキーの取得方法はこちらを参照しました。

https://support-ja.backlog.com/hc/ja/articles/360035641754

Windows上でJavaを実装したい人はOracleのページよりJDKを先にダウロードしてインストールしてください。
https://www.oracle.com/java/technologies/downloads/#jdk17-windows

インストール後の実装方法はこちらを参照ください。
https://www.javatpoint.com/how-to-run-a-java-program-in-windows-10

# ざっくりとした流れ

1. java 実装ファイルのダウンロード
2. APIキーの取得
3. ユーザーのマッピング（元プロジェクトのユーザーと移行先プロジェクトのユーザーのマッピング）
4. 移行の実装

# 実装場所の確保

双方のAPIを取得したら次はcmdを立ち上げて作業用のフォルダーを作ります。

```
$ mkdir work
$ cd work
$ mv ダウンロードディレクトリ/backlog-migration-1.5.5.jar
```

# ユーザーマッピング用のファイル生成

下記のコマンドでにintiファイルを生成します

```
java -jar backlog-migration-1.5.5.jar init --src.key {SOURCE API KEY} --src.url {SOURCE URL} --dst.key {DESTINATION API KEY} --dst.url {DESTINATION URL} --projectKey {SOURCE PROJECT KEY}:{TARGET PROJECT KEY}
```
注意:親子課題を使用する←この設定が両プロジェクトで同じでないとエラーになります。

実行画面のスクショ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241909/4d079b6e-d573-070e-c21c-314711c8b147.png)


# ユーザーマッピング


# 実装・移行

最後に下記のコマンドで移行を実装します。

```
java -jar backlog-migration-1.5.5.jar execute --src.key {SOURCE API KEY} --src.url {SOURCE URL} --dst.key {DESTINATION API KEY} --dst.url {DESTINATION URL} --projectKey {SOURCE PROJECT KEY}:{TARGET PROJECT KEY}
```