OmniAICreator/Qiita-1.07M huggingface dataset:
Backlog APIを使用してWikiを更新する

# 背景
[Backlog](https://backlog.com/ja/)のWikiを修正したいが、修正対象の文言が複数ページに渡って記載されている。
人力で1ページずつ更新するには量が多いため、[API](https://developer.nulab.com/ja/docs/backlog/#backlog-api-%E3%81%A8%E3%81%AF)を使用して一括で修正を適用したい。

# APIキーの発行
APIを使用するにはAPIキーの発行が必要です。
個人設定のAPIタブ(****.backlog.jp/EditApiSettings.action)から新しいAPIキーを発行します。

# 実装
Python3で実装していきます。

## 使用ライブラリ
```python
import requests
import json
import sys
```

## ある文言が含まれるWikiのページIDと本文を取得する
```python
def wiki_search():
    params = {
        "apiKey": BACKLOG_API_KEY,
        "projectIdOrKey": BACKLOG_PROJECT_KEY,
        "keyword": ORIGIN_KEYWORD
    }
    result = requests.get(BACKLOG_HOST + "/api/v2/wikis", params=params)
    if "errors" in result.json():
        print(u"ERROR: {}".format(result.json()["errors"][0]["message"]))
        sys.exit()
    if not len(result.json()):
        print(u"INFO: \"置換元のキーワードは使われていません。\"")
        sys.exit()
    return {result.json()[i]["id"]: result.json()[i]["content"] for i in range(len(result.json()))}
```

## 本文に対し、文言置換を行う
```python
def replace_contents(origin_contents):
    update_contents = {}
    for id, origin_content in origin_contents.items():
        update_content = origin_content.replace(ORIGIN_KEYWORD, UPDATE_KEYWORD)
        update_contents[id] = update_content
    return update_contents
```

## 文言置換した内容でWikiを更新する
```python
def wiki_update(update_contents):
    for id, update_content in update_contents.items():
        params = {
            "apiKey": BACKLOG_API_KEY
        }
        data = {
            "content": update_content
        }
        result = requests.patch(BACKLOG_HOST + "/api/v2/wikis/{}".format(id), params=params, data=data)
        if "errors" in result.json():
            print(u"ERROR: {}".format(result.json()["errors"][0]["message"]))
            sys.exit()
        print(u"{} を更新しました。".format(json.dumps(result.json()["name"], ensure_ascii=False)))
```

# 更新履歴
20/03/14 更新内容をparamsではなくdataに含めるよう修正
【Rails】bootstrap導入【Rails Tutorial 5章まとめ】

Gemfileにbootstrapを記述。

```Gemfile.rb
gem 'bootstrap-sass', '3.3.7'
```

$ bundle installしておく。
レイアウト用のcssを作って@importを使ってbootstrapを読み込む。

```app/assets/stylesheets/custom.scss
@import "bootstrap-sprockets";
@import "bootstrap";
```
テストコードを書くことは、ライブラリなどの動作確認にもいいぞ

# 皆が抱くであろう不安

**ライブラリのメソッドなどで挙動がわからない、どう動くか不安だ。。。** 
といったこと、ありませんか？

ドキュメントが公開されていればそれを読むのも大切ですが、多くの人はいきなりプロダクトのコードに組み込まず、挙動を試すと思います。

そういった時にただ手元で試すだけでなく、**テストコード**として残るように試すことをおすすめします。

以下、Kotlinで例を見ていきましょう。

# String.trim()のテストを書いてみる(例)

kotlin.stdlibには、`fun String.trim(): String` という、文字列の前後の空白文字を消してくれる便利なメソッドが用意されています。

[公式ドキュメント](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/trim.html) によると、以下のように書かれています。

> Returns a string having leading and trailing whitespace removed.

`whitespace` とありますが、これが「半角スペースのみならず、**全角スペース**などは対象になるのかならないのか?」わからなかったりします。
こういう時にテストコードを書いてみます。

```kotlin:TrimTest.kt
@Test
fun trim_FullWidth() {
    val actual = "　全角スペースのテスト　".trim()
    val expected = "全角スペースのテスト"
    assertThat(actual, `is`(expected))
}
```

このテストは成功します。
つまり、**全角スペースを除外対象(whitespace)に含む**ことがわかります。

他にも、「タブは空白文字として扱われるのか？」や、「複数空白文字がある場合はどうなるか？」なども、同様にテストコードを書けば挙動を確認できます。

```kotlin:TrimOthersTest.kt
@Test
fun trim_Tab() {
    val actual = "\tタブのテスト\t".trim()
    val expected = "タブのテスト"
    assertThat(actual, `is`(expected))
}

@Test
fun trim_SomeWhiteSpaces() {
    val actual = " \t　さまざまな空白文字のテスト \t\t  　".trim()
    val expected = "さまざまな空白文字のテスト"
    assertThat(actual, `is`(expected))
}
```

# まとめ

もちろんライブラリのメソッド自体のテスト[^1]（上記の例のテスト）をプロダクトコードで直接書くことは少ないかもしれませんが、trim()を内部で利用するメソッドをプロダクトコードで書いた時には、このテストケースは十分プロダクトのコードに活かせます。

また、手を動かしながら動作確認と学習ができますし、何よりコードとして残すことができ、書いたテストケースに関しては、その挙動は正しいことがわかります。


# おまけ

Javaのtrim()は全角スペースが対象外です。以下のテストを書いてみると、テストに失敗し、対象外であることがわかります。

```java:TrimTest.java
@Test
public void trim_FullWidth() {
    String actual = "　全角スペースのテスト　".trim();
    String expected = "全角スペースのテスト";
    assertThat(actual, is(expected));
}
```

[^1]: 学習用テストというものがあるようです。また、そもそもライブラリにそのメソッドのテストコードがある場合もあります。直接見に行くこともいいと思いますが、自分で書いて動作を試すという意味では意義があるかと。テストコードがない場合はOSSに貢献するチャンスです！すかさずプルリクを送りましょう！
elfutilsのaddr2lineがLDCで生成したバイナリで期待通りに動かなかった場合は `-generate-arange-section` をつけると幸せになれるかもしれない

## tldr;

elfutilsのaddr2lineがLDCで生成したバイナリで期待通りに動かなかった場合は `-generate-arange-section` をつけると幸せになれるかもしれない(タイトルママ)

## 環境

```console
$ ldc2 -version| head -1
LDC - the LLVM D compiler (1.18.0):
$ eu-addr2line --version| head -2
eu-addr2line (elfutils) 0.170
Copyright (C) 2017 The elfutils developers <http://elfutils.org/>.
```

## あらすじ

なんの変哲もないHello, World!プログラムを用意します。

```d
import std.stdio;

void main()
{
    writeln("Hello, World!");
}
```

このプログラムをデバッグ情報つきでビルドしたとき、binutilsのaddr2lineではアドレスをちゃんと `<ファイル名>:<行番号>` の形に変換できていますが、elfutilsだと正しく変換できていません。

```console
$ ldc2 -g helloworld.d
$ nm helloworld| grep _Dmain
000000000001f540 T _Dmain
$ eu-addr2line -e helloworld -f 1f540
_Dmain
??:0
```

binutilsのaddr2lineだとうまいこといきます。

```console
$ addr2line --demangle=dlang -e helloworld -f 1f540
D main
/home/kubo39/dev/dlang/helloworld.d:3
```

## どうして…どうして…

これはどうもelfutilsのaddr2lineの実装としてそうなっているようです。

直接的な原因としてはeu-addr2lineは `.debug_aranges`セクションがない場合はbinutilsと違いCompilation Unitsをフルスキャンしてテーブルを作成するようなフォールバックを行わないからですが、 [関連すると思われるIssueチケットのコメント](https://sourceware.org/bugzilla/show_bug.cgi?id=22288#c1)で

> Without .debug_aranges we would have to scan all CUs to create our own aranges table by inspecting the DW_AT_low_pc/DW_AT_high_pc or DW_AT_ranges attributes.

> In theory we could do that, but it is not immediately obvious when we should.
> If there is no .debug_aranges at all then it might be sensible to assume this does not mean there are really no CUs that cover program scope addresses. But if there are .debug_aranges then it seems bad to assume they are wrong or incomplete.

というようにこの振る舞いは意図的なもののようです。

## けっきょくどうすればいいんや

調査時点でのLDCにおいてはデバッグ情報に `.debug_aranges` を含んでいないのが問題だとわかりました。

LDCはコンパイラの引数に渡ってきたオプションでフロントエンドで解釈できないものをそのままバックエンドに流すようで、 `-generate-arange-section` を渡すことで解決できるようです。もちろんバックエンドのLLVMがそのオプションを受け取って適切に `.debug_aranges` を生成してくれる必要がありますが。

```console
$ ldc2 -g -generate-arange-section helloworld.d
$ eu-addr2line -e helloworld -f 1f540
_Dmain
/home/kubo39/dev/dlang/helloworld.d:3
```

いやこの解決方法はどうなんだ。本来はコンパイラがいい感じに生成するべきなような。
UE4というゲームエンジンの基本設計について覚書

# ことはじめ
最近UE4を勉強していて、とっかかりに基本的な考え方とか、オブジェクトの意味合いとかが気になった
とりあえず[Epicの公式ドキュメント](https://docs.unrealengine.com/ja/Programming/UnrealArchitecture/index.html?lang=ja)をかいつまんでメモっていこうと思う

## ActorとPawnとCharacterの違い
- Actor
 - UE4のワールド内に配置可能な全てのオブジェクトはActorクラスを親に持つ
 - UE4全体のオブジェクトの基本となるObjectクラスから派生したクラス 
 - コンポーネントを付与することができる(？)
 - Unityで言うところのGameObject
- Pawn
 - [Controller](#コントローラーについて)を所有することができるオブジェクト
 - [Controller](#コントローラーについて)を介して操作をすることができる
- Character
 - Pawnの上位互換(?)
 - 人の形をしたPawn
 - `CapsuleComponent`と`CharacterMovementComponent`がデフォルトでアタッチされている
 - アニメーションや、ネットワーク関係の動作に強い(?)

## コントローラーについて
- Controller
 - Pawnに指示を出すことができるアクタ
 - AIControllerとPlayerControllerの2種類が存在する
- PlayerController
 - プレイヤーの入力を仲介して対象のPawnに指示を送るオブジェクトという認識
- AIController
 - ↑のAI版　NPCの操作を仲介する 多分

コントローラー関係についてはまだ不明なことが多いが、ラジコンで言うところの人とコントローラーと車みたいな関係だと思っている

## ゲームの情報表示関連
- HUD
 - ~~普通にUIとかを管理してるやつだと思う~~ HUDはUE4以前によく使われていたそうで、現在はUIならUMGとかいうのが幅を利かせているらしい
 - `PlayerController`と関連付いてる(?)
- Camera
 - ちょっとよくわからないので別途掘り下げたほうがよさげ

### ↑の`Camera`について引用
引用 ゲームプレイのプログラミング | Unreal Engine ドキュメント
> PlayerCameraManager はプレイヤーの「眼球」で、挙動を管理します。
各 PlayerController は、通常これらのいずれかを持ちます。詳細は、 [camera workflow](https://docs.unrealengine.com/ja/Gameplay/Framework/Camera/index.html) ページをご覧ください。

### カメラについて追記
実行時にCamera Actorなるオブジェクトがレベル内に勝手に生成されていて気持ち悪かったので色々調べてみたけど、結局サンプルとかでも同じようにCameraActorが生成されており、しかも特に使われていなかったので、そういうものだと思うことにした。誰か詳しい人がいれば是非この辺りの詳細について教えていただきたい。

## ゲームのルールを設定する系オブジェクト
- GameMode
 - ゲームの定義 (勝敗条件やゲームのルールなど)
- GameState
 - ゲームの状態 (スコアやプレイヤーのリストなど)
- PlayerState
 - プレイヤー個人の状態 (プレイヤー名やHP、MPなど？)
 - AIは`PlayerState`を持たない

ここの項目には、公式ドキュメントにはネットワーク用語がちょくちょくでていたので、そういったところも意識した設計になっているのかも？

## さいごに
↑に書いたオブジェクト達を全てまとめて`GameplayFramework`という呼び方をしているように見えた
また公式ドキュメントには、`GamePlayFramework`のクラス達をわかりやすくクラス図にして説明もしているので是非読んでもらいたい

自信のないものについては文の末尾に(？)がついているので、そういうものだと思って読んでもらいたい（ていうか全体的に解釈が正しいか自信がない）

今回UE4の基本について調べておおよその流れは把握できた気がするので、これを軸に気になった箇所を掘り下げていけたらと思う

## 参考にしたサイト
ゲームプレイのプログラミング | Unreal Engine ドキュメント
https://docs.unrealengine.com/ja/Programming/UnrealArchitecture/index.html?lang=ja
アンリアル アーキテクチャー - Let's Enjoy Unreal Engine
http://unrealengine.hatenablog.com/entry/2014/04/24/221643
もんしょの巣穴blog [UE4] UE4のフレームワーク
http://monsho.blog63.fc2.com/blog-entry-119.html
【UE4】移動方向に対するキャラクターとカメラの回転
http://game-ue4.hatenablog.com/entry/2017/11/20/180426
プログラミング始めて1週間で競技プログラミング参加してみた

##プログラミングを始めたきっかけ
今までエンジニアに囲まれて働いてて「いつかプログラミングしたいなぁ」と思い続けてました。
そんな中、夫が最近毎週末競技プログラミングにはまっており、数学の思考部分を自分も一緒に手伝って解いている中で楽しくなってやりたい気持ちが高まりました。
そして夫に「AtCorderのビギナーレベルならプログラミングやったことない人でもできるよ」という甘い声にそそのかされて、足を踏み入れてみたのでした・・・。


##自己紹介
 - IT業界に5年いるけどプログラミング経験なし（なんならMarkDownも今書くのが初めて時間めっちゃかかってるw:sob:）
 - 理系出身なので数学は抵抗感なし。なんならパズルは好きだし得意
 - 触ったことのないITのツールの導入には抵抗なし
 - ググり力は高い（と思っている）
 - 夫がフルスタックのエンジニアで困ったらいつでも聞ける [^1]

 
##一週間で何をやったか
- PythonをMacにインストール
- Visual Studio CodeをMacにインストール[^2]
- [AtCorderに登録](https://atcoder.jp/?lang=ja)
- [実践力を身につける Pythonの教科書](https://www.amazon.co.jp/%E5%AE%9F%E8%B7%B5%E5%8A%9B%E3%82%92%E8%BA%AB%E3%81%AB%E3%81%A4%E3%81%91%E3%82%8B-Python%E3%81%AE%E6%95%99%E7%A7%91%E6%9B%B8-%E3%82%AF%E3%82%B8%E3%83%A9%E9%A3%9B%E8%A1%8C%E6%9C%BA/dp/4839960240/ref=tmm_pap_swatch_0?_encoding=UTF8&qid=&sr=)
 - 1章〜2章の途中くらい。とりあえず、if文をちょろっと書くくらいはできるようになった
- [Progate](https://prog-8.com/languages/python)
 - Python1章分修了

#####上記によって「プログラミングってパズルっぽいな〜おもろいな〜」くらいの印象になった


##AtCorderやってる時に考えたこと
- まず問題をよく読む[^3]
- 制約と入力例もよく読む
 - 意外と入力例の形式をちゃんと捉えるのが大事だなと思ったり
- こまめに`print`を使って、自分が意図した通りのことができているかどうかを確かめる
- エラーをよく読む。何行目か。その上でハマりやすいエラーでまずは考える
 - `==`と書くべきところで`=`と書いてしまうのは初心者あるあるな気がする
- 書き間違いを防ぐためになるべく`Tab`を使って入力
- わからなかったらググる。（「リスト 削除 python」とかでググりまくる。そしてわんさか出てくるサイトたち…。もしかしてググりだけで解けるんじゃね！？）

#####上記によってビギナーの100点問題（グレーの問題）はあっさり解けるなぁと思った
#####200点問題はまだ難しい。半分くらいしか書けない。そもそもfor文まだよくわかってない。ここはググるより、ちゃんと教科書読んだ方が良さそう


##結論
- 100点問題はググり力で結構いける
- 各構文のところはちゃんと教科書読んで体系的に学んだ方が良さそう
- AtCorderは問題がたくさんあって飽きない。楽しい。スコアもあるからそれでモチベ上がりそう
- プログラミング敬遠してたけど、結局ルールの決まってる自由な組み立て可能なパズルって感じで楽しい。思ってたよりも取っ付きやすかった。


##今後
- 開始して2週間くらい経ちましたが、100点問題は確実に解けるように。次は200点問題だー
- とりあえずAtCorderを一日1問ずつくらい解いていく
- 今やっている教科書を一通り終えて、中級クラスの教科書に行きたい。あとはpythonを使ってデータ分析の方面をやりたいので、そっちの勉強もしたい


[^1]: ラッキー
[^2]: ググったら「Atom」っていうのがおすすめって書いてあったけど、エンジニアの夫が「時代はVisual Studio Codeだ」って言ってたから入れた。のちに感動の渦に巻き込まれる
[^3]: そりゃそうだ。でも大学受験の時も先生からよく読むのが大事と言われたなぁ
[Flutter]TextFormFIeldを再初期化する方法

## 結論
```dart
TextFormField(
  key: Key(count),
  initialValue: count,
  ...
)
```

keyを変更することで、別ウィジェット扱い（差分扱い）にして再描画させている。

## 終わりに
reactにおけるredux-formのreinitializeみたいなことをしてほしいだけなんだけど、もっときれいなやり方ないのかな。

## 参考
[TextFormField not resetting its Initial Value](https://stackoverflow.com/questions/58715192/textformfield-not-resetting-its-initial-value)
node.js スクレイピング

スクレイピングとはプログラミングを使ってwebサイトから情報を取得する方法である。


スクレイピングは基本2種類あって、requestを送る方法とheadless browserを使ってbrowserを動かす方法の二つである。
requestを送る方法は処理自体は軽いが、Vue.jsやReact.jsを使ったSPAだと取得が難しい。
headless browserを使う方法は処理は重いが、SPAでも取得が可能。

テスト用途で使う時は、もう少しきちんと使うべきかもしれないが
スクレイピング用途で使う時はclickとtype以外はevaluate(javascript実行)のゴリ押しでいい。

参考URL Puppeteer.jsのgithub
https://github.com/puppeteer/puppeteer

```
npm init
npm install puppeteer
npm install cheerio
```

の3つをインストールする。
puppeteerはheadless browser
cheerioは取得したhtmlをjqueryライクで加工できるパーサーである。

###起動

下記例はgithubに載っている例を少し改良したものである。
launch関数でbrowserを作成。この時、headless:falseにしてあげることでブラウザを出しながら動かせる。
newPage関数でpageを作成。
goto関数でそのページに遷移。
close関数はbrowserを閉じるので、一旦コメントアウトしておく。

```js:index.js
const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({headless:false});
  const page = await browser.newPage();
  await page.goto('https://example.com');
  //await browser.close();
})();
```

###スクリーンショット

page.screenshot関数は現在ページのスクリーンショットを撮る。
pathのところに画像を保存。

```js:index.js
const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({headless:false});
  const page = await browser.newPage();
  await page.setViewport({width:800, height:600});
  await page.goto('https://example.com');
  await page.screenshot({path:"test.jpg"});
  
  //await browser.close();
})();
```

###htmlの取得

直接htmlを取得することができない。
セレクターで情報を取得した後、evaluateで(javascript)実行してあげないといけない。

```js:index.js
const puppeteer = require('puppeteer');
const cheerio = require('cheerio');

(async () => {
  const browser = await puppeteer.launch({headless:false});
  const page = await browser.newPage();
  await page.setViewport({width:800, height:600});
  await page.goto('https://example.com');
  const bodyHandle = await page.$('body');
  const html = await page.evaluate((body) => body.innerHTML, bodyHandle);
  const $ = cheerio.load(html);
  var h1 = $('h1');
  console.log(h1.html());
  //await browser.close();
})();
```

###クリックして遷移する。

goto時、waitUntilオプションがないとすぐセレクターを使うとエラーが起こってしまう。
クリック時はwaitForNavigationと一緒に使ってあげないとエラーが出ることもある。
クリックの中身はセレクター。

```js:index.js
const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({headless:false});
  const page = await browser.newPage();
  await page.goto('xxxxxxxx', {waitUntil:'domcontentloaded'});

  await Promise.all[
      page.waitForNavigation(),
      page.click('yyyyyy')
  ];
  //await browser.close();
})();
```

###入力

```js:index.js
const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({headless:false});
  const page = await browser.newPage();
  await page.goto('xxxxxxxxxxx', {waitUntil:'domcontentloaded'});

  await page.type('yyyyyyyyyyy', "testtest");
  //await browser.close();
})();
```

###待機

page.WaitFor関数でミリ秒待つ。

```js:index.js
const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({headless:false});
  const page = await browser.newPage();
  await page.goto('xxxxxxx', {waitUntil:'domcontentloaded'});
  await page.waitFor(3000);
  //await browser.close();
})();
```
【画像処理100本ノックに挑戦】Q.20. ヒストグラム表示

# 使用したライブラリ
[【画像処理100本ノック】独自の画像入出力クラスを作る](https://qiita.com/jajagacchi/items/834e8425b84f94df8a49)

# Q.20. ヒストグラム表示
> matplotlibを用いてimori_dark.jpgのヒストグラムを表示せよ。

簡単です。注意が必要なのは、ここでいうヒストグラムはRチャンネルのヒストグラム＋Gチャンネルのヒストグラム＋Ｂチャンネルのヒストグラムのことを想定しているらしいということです。
最初はグレースケールに対するヒストグラムかと思いました。正解出力が掲載されているので少し考えればわかりますが、少し不親切に感じました。特に言及なく、グレースケール画像が対象であることを想定した問題もありますし。

```c++
int main()
{
	PPM ppm("imori_dark.pnm");
	int width = ppm.Get_width();
	int height = ppm.Get_height();
	
	int N = 256;
	std::vector<int> hist(N);
	for (int n = 0; n < N; n++)
	{
		hist[n] = 0;
	}

	for(int j=0; j<height; j++)
		for (int i = 0; i < width; i++)
		{
			hist[ppm(i, j, 'r')]++;
			hist[ppm(i, j, 'g')]++;
			hist[ppm(i, j, 'b')]++;
		}

	for (int n = 0; n < N; n++)
	{
		std::cout << n << " " << hist[n] << std::endl;
	}


	return 0;
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520857/3b463969-06f9-9d39-5e69-b5d3f3eacd6e.png)

これで20問完了です！
CloudFrontの署名付きURLをLambda@Edgeで発行する妄想

# はじめに

こちらは[ミクシィグループアドベントカレンダー](https://qiita.com/advent-calendar/2019/mixi)17日目の記事です。

[家族アルバム みてね](https://mitene.us/)というサービスの開発・運用を行っている尾関と申します。

今回は、全世界向けのサービスをAWSの単一リージョンで運用していることによる課題と、その解決案についてお話します。
あくまでまだ案レベルで本番導入する予定もないものですが、どなたかの参考になればと思い記事に残すことにしました。

# 「家族アルバム みてね」

スマホで撮った子どもの写真や動画をかんたん共有、整理できるアプリです。
今年は[Google Playのベストアプリで2部門受賞しました。](https://prtimes.jp/main/html/rd/p/000000446.000016514.html)超おすすめです。

[みてね年賀状](https://mitene-nenga.jp/)という別アプリと連携して、年賀状もかんたんに作成できるので、まだ書いてないよ！という方にもおすすめです。


# 課題

みてねでは、ユーザーさんがアップロードした写真・動画はすべて東京リージョンのS3に保存されています。
これらはCloudFront経由で配信していますが、プライベートなコンテンツなので、家族内でしか見ることはできません。
また、家族の中でも公開範囲を分けることができ、誰が見ることができるかという情報はコンテンツ毎に違います。
通常は家族全体・夫婦のみの2種類ですが、プレミアム会員に入ると、任意のグループを作ることができます。便利ですね。[ぜひプレミアム会員になってください](https://mitene.us/premium)お願いします。


話がそれてしまいましたが、公開範囲の制限をどうやっているかというと、下記のようなシンプルな実装になっています。

1. 端末からみてねサーバのAPIにリクエスト
2. DBにある権限管理テーブルを参照し、問題なければAPIがCloudFrontの署名付きURLを返す
3. 端末から署名付きURLにリクエストを送り、写真を取得する


さて、みてねというサービスはグローバルに展開しており、海外からのアクセスだと、署名付きURLを発行するために遠く離れた日本のリージョンにアクセスしなければなりません。
こちらについてはフロントにキャッシュをOFFにしたCloudFrontを置くことで、ネットワークの最適化は図っていますが、それでもやはり物理的に遠いことは変わりありません。
[こちらの資料](https://speakerdeck.com/fanglang/the-battle-with-network-latency?slide=24)でそのあたりの話に触れていますが、今なら[GlobalAccelerator](https://aws.amazon.com/jp/global-accelerator/)がより便利に使えるかもしれません。

また、[こちらの資料にあるように](https://speakerdeck.com/_atsushisakai/workmanager)バックグラウンドで先読み＆端末にキャッシュしているため、ユーザーへのストレスはかなり軽減されているのですが、まだキャッシュされていないユーザーにとっては表示までにかなりの時間がかかってしまっているのが現状です。

また、膨大な画像・動画を扱っているため、この署名付きURLの発行処理というのがみてねのAPIの中で最も大きい処理となっており、全体の約3割を占めています。(NewRelicのMost time consumingにて計測)

# 解決案

AWSの[Lambda@Edge](https://aws.amazon.com/jp/lambda/edge/)という、CloudFrontのエッジロケーション上でLambda関数を実行するサービスがあります。
こちらで署名付きURLを発行する関数を用意すれば、ユーザーさんからのリクエストはエッジロケーションで返すことができ、ネットワークの距離の問題も解決しつつ、高負荷かつ重要な機能をより安定したインフラに移すことができ、結果的にシステム全体の安定性を上げることができそうです。

まとめると下記のメリットがあります。

* 物理的な距離が近くなることでレイテンシが下がり、ユーザーからのレスポンス時間短縮
* 高負荷な処理がスケールされやすくなり、急なアクセス集中にも耐えやすくなる
* メインのAPIがメンテナンス状態でも写真だけは閲覧可能な仕組みを構築可能

いい事尽くめではないでしょうか

# 課題


一方、課題ももちろんあります

* 認証はどうするか？
* コストが余計にかかるのでは？

認証については、署名付きURLを発行する前にメタデータをAPIから一度取得しており、その時点で権限を持っていることが保証されています。ただし、写真毎に公開範囲を変更できるので、署名付きURLを発行する時点での権限は保証されません。この時点での権限の確認をどう行うかは課題となります。
[AWS Cognito](https://aws.amazon.com/jp/cognito/)という、AWSが提供するサインアップの仕組みがその解決策になりうるかもしれません。要検証です。

次にコストについてですが、これも余分にかかることは容易に予想できます。さらに言うと、[AWS Cognito](https://aws.amazon.com/jp/cognito/)を使うならそのコストも加わってきますので、コストに見合うことを説明する必要がありそうです。やはりこれもなかなか難しい課題です。

# 実装してみる

課題はいろいろありますが、Lambda@Edgeの実装を試してみたいと思います。

・・・と言いつつ、本当は署名付きURLを発行するところまで実装して記事にするつもりでしたが、自分の努力不足により間に合いませんでした。
言い訳すると、[今週からオフィスが移転して](https://internet.watch.impress.co.jp/docs/news/1223671.html)浮かれていました。本当に申し訳ありません。

後日実装して追記します。

# 最後に

こんな中途半端な記事を読んでいただいてありがとうございました。
フリーランスSNSをツクール2.0

#はじめまして
はじめましてって書いていいのか分からないですが、初投稿になります。
多分、6年くらい前（railsを触りはじめた頃）に技術系ブログに大変お世話になって、自分も何か書きたいと思っていたんですが、qiitaは、敷居が高い（ガチエンジニアしか書けない）って思い込み？があって、はてブロに書いていました。
そんな自分が、qiitaに書く事がくるとは感無量です。（と言っても書く事がない。。

少し自己紹介させてもらうと、Sierとメーカー系の子会社に約10年くらいいて、その後ベンチャーをウロウロしていました。学んだ（気付いた）のは、自分はまともなコードが書けないという事です。

##自分の技術論？
正直、プログラミングは努力ではできるようにならないです。
正確にいうと、努力で仕事をこなせる程度には書けるようになりますが、センスがある人とない人の差はどれだけ積み上げようと埋まらないです。「エンジニア未経験から年収1000万」ってフレーズよくみますけど、ほぼ未経験から1年くらい年収700万くらいになった人なら知っていますし、あながち嘘じゃないと思います。

急成長する人は、成長する能力も含めて「持ってる」のです。（ちゃんと努力もしてると思いますが）
自分には才能はない、という事だけは誰がなんと言おうと明確に分かったので、多分アドベントなんちゃらがなかったら、自分がqiitaに投稿することもなかったと思います。

##何をやっているか
どんどん、qiitaに書くべき（書くような？）内容から遠ざかっている気がするのですが、、
フリーランスのSNSを、rails+vueで作っています。フロント＋バックエンド＋デザイン＋ライティング？＋環境構築まで自分でやっているのですが（イラストは依頼しています）、vue使うようになってから、慣れてなかった事もあってかなり開発に時間がかかるようになってしまいました。

こんな感じのやつです
https://lancepod.com/

##SPAで苦労した事
VueはNuxtを使わず、SPAで動作させているのですが、**OGP問題**で困っています。

この記事にまとめて頂いている通りで、
https://qiita.com/rotelstift/items/f7dad19177d30714dcfa

方法としては、
- [vue-head](https://github.com/ktquez/vue-head)のようなプラグインで対応する
- SSRする
- プリレンダリングする
のようなやり方があるのですが、**twitterでシェアされたい欲**があり、それだとvue-headのようなやり方だとtwitterがogpを拾ってくれないので、SSRで対応する事にしました。プリレンダリングも考えたんですが、やり方構築するのが手間だなと思ったのと、多分railsが好きなんでしょうね、第一館でrailsでrenderさせたい！と思ってしまいました。

## railsにogpをレンダリングさせる
やり方が曲芸的なので、rails好きにはたまらないかもしれませんが、通常こんなやり方しないと思います。
1. nginxに特定のURL（パス）のパターンに合致する場合、フロント（vue)ではなく、rails側に飛ばす（rewrite）
2. rails側でリライト前の当該URLの示すVueのページを取得して、そのページ独自のogp（tilte/description/image等）を埋め込む
3. そのページをrenderメソッドでレンダリングして返す

みたいな感じです。
全然技術ブログっぽくないので、nginxの設定を抜粋しておきます。。
```
     # iam and party -> backend
      rewrite ^/iam/(.+)$ /render/retell/iam/$1 last;
      rewrite ^/party/(.+)$ /render/retell/party/$1 last;
```
SPAで、ogpって皆さんどうやっているんでしょう？
Lancepodの開発を手伝ってくださる方もしいたら、お声かけ頂けたら超うれしいです。
（アイコンは推しです）
Jip-Base 障害の原因から、Design for Failure の大切さを改めて考えてみる

#はじめに
「Jip-Base」と呼ばれる自治体向けのクラウドサービス (IaaS) で障害が発生し、全国の自治体関連システムに影響が出たとのことです。

- https://www.jip.co.jp/news/pdf/20191216.pdf
- https://www.itmedia.co.jp/news/articles/1912/16/news127.html

実務を担当されているエンジニアさんは本当に大変だと思います。どのようにすれば問題を回避できたのかについて、一次情報や解説記事等から得られた情報を元に、失敗の原因と得られた教訓についてまとめていきたいと思います。

#何が根本的にまずかったのか
解説記事等では、使用していたストレージ製品(Dell EMC Unity 500)に不具合があったために、結果としてデータの欠損が発生したことが言及されておりますが、基本に立ち返って考えてみると、ソフトウェアの設計に問題があったと考えられます。
IaaS という用語自体は AWS 等の Public Cloud が普及したおかげで広く使われるようになりましたが、その根底にある設計思想については必ずしも広く共有されていないと思われます。

[前回](https://qiita.com/rev4t/items/85117669bdcdb755a1be)の記事でも、[Well-architected フレームワーク](https://d1.awsstatic.com/whitepapers/ja_JP/architecture/AWS-Reliability-Pillar.pdf?sc_icampaign=aware_well_architected_jp_reliability_pillar&sc_ichannel=ha&sc_icontent=awssm-3366&sc_iplace=content&trk=awssm-3366_aware_well_architected_jp_reliability_pillar)について言及しましたが、冗長化が必要な要件がある場合は、何を守りたいのかを明確にした上で、ソフトウェアを含めた全体のフレームワークの中で要件を実現する必要があります。

今回の事例では IaaS 上でシステムを実装しているので、次のように Design for Failure に基づいた冗長構成にする必要があります。

- 複数の Available Zone (AZ) を使用し、永続化が必要なデータについては AZ を跨いだ冗長構成を取る形で保管する
  - Database (RBDMS等)については、Multi Master 構成、または Replication を用いて Failover ができる状態にする
  - Webの静的コンテンツ等についても、必要に応じて複数の AZ に同一のデータを配置する

また、今回の事例で改めて明らかになったこととしては、どんなにお金をかけて(高いグレードのベンダ製品を買ったとして)も、機械は壊れるという点があります。
一次情報をみる限りではストレージシステムのコントローラが冗長構成になっておりますが、今回のようにファームウェアに問題があるとシステムは停止するかもしれませんし、最悪の場合はデータが欠損する可能性もありえます。
このため、あるコンポーネントが壊れても自律的にサービスが継続できるように、ソフトウェア側で適切な制御をする必要があります。また、自律的な制御を確実にするためにはデプロイをシステマチックに実施するためのツールが不可欠になってきます。

#おわりに
今回は、最近発生した失敗事例を元に Design for Failure の重要性について考えてみました。RAID や NAS 等でも言えることですが、例えばコントローラを二重化したとしても、一度ソフトウェアに問題が発生すると Failover では回復できないパターンが確実に出てきます。

これらを踏まえると、高価なベンダ製品を買って安心感を得る代わりに、そのお金をシステム設計に回して適切に冗長化を実現する方が合理的だと思えます。AWS のサービスで稼働しているハードウェアの大半が ODM 製品で構成されている理由の一つも、この点にありそうですね。
Mockito引数null想定テストで型指定してしまいdoReturnしてくれなかった




JUnitで業務中、モックオブジェクトの一種としてMockitoというフレームワークを使っていた際、思った通りにOutputを返してくれず半日溶けたので備忘録。

↓Mockito紹介サイト。
[Mockitoの飲み方](https://orizuru.io/blog/java/mockito-primer/)


###前提
例えば以下のソースにおいてControllerクラスの`getContent`メソッドの引数に<b>nullが入るパターン</b>をテストしたい場合。(コードは上記のサイトから引用・改変しています。)

`getContent`はその内部でServiceクラスの`getContentById`を使用するメソッドですが、`getContent`直下のロジックだけをテストしたい際、`getContentById`内のロジックを気にしたくありません。そこでMockitoを用いて`getContentById`内のロジックによらないI/Oを指定し、クラスごとに独立なテストを行います。



```Java:Controller.java
  public class Controller
  {
      private Service service = new Service();

      public String getContent(String id) {
          String content = service.getContentById(id);
          return content;
      }
  }
```

```Java:Service.java
  public class Service
  { 
     private Map contents = new HashMap();
  
     //コンストラクタ
     public Service(){ genContents(); }

     //key指定してvalueを返す
     public String getContentById(String id) {
          String content;
          content = contents.get(id);
          return content;
     }

     //コンテンツ作る
     public void genContents() {
          contents.put("1","Tanaka");
          contents.put("2","Saitou");
          contents.put("3","Yoshida");
          contents.put("4","Suzuki");
     }
   }
```

以下ミスコード

```Java
  public class Test{
     Controller controller = new Controller();

     //ダミーのserviceを作る、中身は知らん
     Service service = mock(Service.class);
     // I/Oだけ別途設定
     doReturn("Content1").when(service).getContentById(Mockito.anyString());
}
```

`doReturn`から始まる文は

「任意のString型を引数として呼び出されたらいつでもContent1という文字列を返せ」

という意味ですが、今回の想定だと`getContentId`の引数がnullなのでanyString()が指定されずgetContentは何も返してくれません。そこで、より広義の引数を指定してやります。

以下正しいコード

```Java
     doReturn("Content1").when(service).getContentById(Mockito.any());
```

これでgetContentByIdメソッドに

「なんでもいいから呼び出されたらContent1という文字列を返せ」

という設定を加えることが出来ます。引数がnullでも動かすことが出来ました。


実際の業務では`Mockito.Any~()`ではなくて`ArgumentMatchers.any(~~~.class)`を用いて自作の型引数を持つメソッドに対してモックしていたのですが、今回はより簡単にString型のパターンで書いてみました。

追記
※書いてたらより端的な記事を発見してしまいました。こちらもあわせてどうぞ。
[MockitoでMockする際の引数にMockito.anyStringを使う場合の注意点](https://qiita.com/supergamaspecial/items/d9dad432ff67a5d42054)
セルに設定した値をシェルスクリプトなどのファイルとして出力

作業をする際にエクセルのリストをもとにシェルスクリプトを作成することが増えたため作成してみました。
以下はサンプルなので、1文字列+1エリア分しかありません。

※このままだと改行コードがLFで出力されるので、注意してください。
CR+LFにしたい場合は別の記述を追加する必要があります。


Sub makeShell（）
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheet（1）

Dim datFile As String

datFile As String
Open datFile For Output As #1
Dim i As Long

‘エリア１
i = 0

‘エリア１開始まで　固定文字列を設定するなど
Print #1, ws.Cells（4,1）

‘エリア１
Do While ws.Cells（i ＋ 18,2）.Value<>””

 Print #1,ws.Cells（i ＋ 18,13）.Value
 i = i +i
Loop


‘以下必要に応じて記述を追加
‘たとえばエリア2として（i ＋ 18,14）を対象にするなど

Close #1

MsgBox “XXXX 作成完了”
End Sub
geopandas で 世界地図を表示

Pythonで地図にプロットしたりしたいなー、と思っていたのですが、先日、[geopandas](https://geopandas.readthedocs.io/en/latest/)というものがあるのを知りました。私のノートＰＣ(Windows10, Visual Studio Code, python3)にインストールして動いた感じなのでメモします。

![naturalearth-lowres.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294040/a08c4931-94a1-4594-19bc-1d33c62b4a87.png)

## Geopandas インストール

最初、pip3 install geopandas としましたが、エラーが出てインストールできず。

- pip3 を使う。いろいろ問題がありましたが、こちらからエラーが起きたモジュールを入れました。私は、エラーが出たモジュールについて、こちら([Unofficial Windows Binaries for Python Extension Packages](https://www.lfd.uci.edu/~gohlke/pythonlibs/))のサイトで最新のものをインストールしました。GDAL, Fiano, Shapely をインストールしました。

- 実は[geopandas のサイトでインストール方法](https://geopandas.readthedocs.io/en/latest/install.html)を調べると、conda を使うように書いてありました。conda はanaconda と関係があるようで、私は初めて知りました。pip でインストールした後、いろいろ提案されるとおりにしたところ、動きました。

```shell
$ python -m pip install conda
$ conda update -n base -c defaults conda
$ conda create -n geopandas
$ conda activate geopandas
```

## テスト

以下のプログラムで地図が出てきました。元ネタは[こちら](https://geopandas.readthedocs.io/en/latest/data_structures.html)です。


```python
import geopandas
import matplotlib.pyplot as plt

world = geopandas.read_file(geopandas.datasets.get_path('naturalearth_lowres'))
print(world.head())
world.plot()
plt.show()
```

`world.head()` で以下が出力されます。この `world` は class ` geopandas.geodataframe.GeoDataFrame` です。

```
     pop_est      continent                      name iso_a3  gdp_md_est                                           geometry
0     920938        Oceania                      Fiji    FJI      8374.0  MULTIPOLYGON (((180.00000 -16.06713, 180.00000...
1   53950935         Africa                  Tanzania    TZA    150600.0  POLYGON ((33.90371 -0.95000, 34.07262 -1.05982...
2     603253         Africa                 W. Sahara    ESH       906.5  POLYGON ((-8.66559 27.65643, -8.66512 27.58948...
3   35623680  North America                    Canada    CAN   1674000.0  MULTIPOLYGON (((-122.84000 49.00000, -122.9742...
4  326625791  North America  United States of America    USA  18560000.0  MULTIPOLYGON (((-122.84000 49.00000, -120.0000...
```

このファイル(test.py)を `python3 test.py` とすると、冒頭の画像が表示されました。
いろいろ使えそう。わくわく。(^^)/

以下を参考にさせていただきました。

- [QGISでPandasとGeoPandasを使えるようにする](https://qiita.com/ozo360/items/87334983e7e9b95d50e9)
星空が綺麗だったのでthree.jsを使って簡易宇宙を創造してみた

突然ですが、宮崎市も次第に寒くなってきましたね...
冬の夜は寒くて寒くて、外に出るのが憂鬱です。

そんな冬ですが個人的に好きな点があります。

それは、星空がとてもきれいなことです。
空気が乾燥している分、夏よりか圧倒的なスケール！

田舎の実家に戻ったときにふと空を見上げるとと、ても綺麗だったので、宇宙（星空？）をブラウザ上に再現したいと思います。
＊ぱっと作ったのでショボい宇宙になりましたが...

## 使用技術・サービス
- three.js（WebGL）
- webpack
- Netlify


## 参考
- three.js<br>
[公式ページ](https://threejs.org/)
- Netlify<br>
[超便利ホスティングサービス Netlify
](https://qiita.com/niihara_megumu/items/db8c53f0f5de9f377976)
- webpack<br>
こちらの説明については省きます。<br>
気になる方は、[GitHub](https://github.com/niiharamegumu/three-js-sample/blob/master/webpack.config.js)を御覧ください。


## 完成ページ
https://starry-sky.netlify.com

## 実装
ファイル構成等は https://github.com/niiharamegumu/three-js-sample を御覧ください。

three.jsのインストール

```shell
npm install three --save
```
たったこれだけのコードで作成することができました。

```js:index.js
import * as THREE from "three";

const generateRenderer = (width, height, selector) => {
    const renderer = new THREE.WebGLRenderer({
        canvas: document.querySelector(selector)
    });

    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(width, height);

    return renderer;
}

const init = () => {

    const
        width = window.innerWidth,
        height = window.innerHeight,
        renderer = generateRenderer(width, height, "#canvas"),
        scene = new THREE.Scene(),
        camera = new THREE.PerspectiveCamera(100, width / height, 10000, 100),
        geometry = new THREE.SphereGeometry(),
        SIZE = 2000,
        POINT_NUM = 4000;

    camera.updateProjectionMatrix();
    camera.position.set(1, 1, +1000);

    for (let i = 0; i < POINT_NUM; i++) {
        geometry.vertices.push(new THREE.Vector3(
            SIZE * (Math.random() - 0.5),
            SIZE * (Math.random() - 0.5),
            SIZE * (Math.random() - 0.5),
        ));
    }
    const material = new THREE.PointsMaterial({
        size: 3,
        color: 0xFFFFFF,
    });

    const mesh = new THREE.Points(geometry, material);
    scene.add(mesh);

    run();

    function run() {
        mesh.rotation.y += 0.0001;
        renderer.render(scene, camera);

        requestAnimationFrame(run);
    }
}

  window.addEventListener('load', init);
```

## まとめ
もう少し、ドキュメントや使い方を知ることができれば、複雑な３Dを作成することができるので、
もっと触ってみたいと思いました！
自分の好きな風景や物を再現できたら最高です！
Extemporeの楽曲サンプル。（公式のヤツ）

そもそもExtemporeのコードサンプルがろくに紹介されてないので、一度調べたので良さそうなの書いておきます。

### 公式のサンプル1

```scheme:test.xtm
(sys:load "examples/sharedsystem/audiosetup.xtm" 'quiet)
(sys:load "examples/sharedsystem/analogue_synth_basics.xtm" 'quiet)
(sys:load "examples/sharedsystem/drum_synth_basics.xtm" 'quiet)
```

これは何かというとシンセサイザーとドラムを使った楽曲のサンプルみたいです。
ステップバイステップで書かれてるので読みやすいと思ったんですが、そもそもどんな順番で起動したらいいのか書いてなかったので控えておきました。

あとは上記フォルダ内にある「pattern_basics.xtm」ってファイルにパターン制御に関して色々書いてるのでこれ追ってくだけでも作曲できると思います。

### 公式のサンプル2

「examples/sharedsystem/covers」にどっかで聞いたことがある曲が入ってます。
上記コードの1行目だけ実行して、あとはCoversの中身を実行していけば聞くことができます。

ちなみに、「audiosetup.xtm」の中に記述を短くするための定義が入ってるので、これを改造していくのもいいと思います。
（というか記述が前提になってるので、他のファイルを単体で起動しても動かない）
NotionでRDBのスキーマを設計する

[アルプ株式会社](https://thealp.co.jp/)でエンジニアをしています、集約のエンティティ@pictinyです。
これは[Notion Advent Calendar 2019](https://qiita.com/advent-calendar/2019/notion) 16日目のエントリです。
15日目は[Notionのデータベースをロックする](https://qiita.com/pictiny/items/1c86e51c9ff6ea77f31f)でした。

# RDBスキーマ設計
MySQLのようなRDBのスキーマを設計することがあります。
Notionのデータベース機能を使って書いてみましょう。

<img width="718" alt="RDBスキーマ設計" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427952/df9a305b-c8ba-f92c-00cb-67d69e9842d7.png">

ユーザテーブルを設計したサンプルです。
以下の**プロパティ**を作っています。

- カラム名
- データ型
- データ例
- カラムの説明

## プロパティタイプ

**プロパティ**には種類があります。これを**プロパティタイプ**といいます。
RDBのデータ型を表現する**プロパティ**には`Select`という**プロパティタイプ**を使っています。

<img width="364" alt="Screen Shot 2019-12-16 at 23.14.42.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427952/6b64fdd2-b8d9-502d-25a6-c7940ff81e54.png">

有限集合から1つを選択するときは`Select`を使うとよいでしょう。
有限集合から複数を選択するときは`Multi Select`があります。

# まとめ
Notionのデータベース機能の利用例を紹介しました。
**プロパティタイプ**についての公式ドキュメントは[Properties](https://www.notion.so/Intro-to-databases-fd8cd2d212f74c50954c11086d85997e#15b88f267edf4077a04753a708aec05d)にありますので、そちらもご覧ください。
REST APIのエラー設計ではまった話

こんにちはCLBです。
転職してからと言うもの、とあるシステムのバックエンドとして
ひたすらAPIを作る仕事をしています。
そんな時にエラーではまった話を書いて行きます。

# 当初の設計
こんな風にAPIのエラーを返却していました。

```JSON
{
    "error-message" : "〇〇が入力されていません"
} 
```

そして、`〇〇が入力されていません` と言う文章をそのままフロントエンドの画面に表示していました。
この時の自分にとっては、特に問題はなさそうに見えました。
「こんなもんなんだ。」程度にしか理解していませんでした。

# 問題発生
フロントエンダーの方がこんなバグを見つけます。

> エラーメッセージが正しく無い。
> 〇〇 ではなく、 △△であるべきだ。

確かに画面を見てみると `〇〇` ではなく、 `△△` と言う項目名が利用されていました。
この時自分は、「汎用のエラーメッセージを利用していたのが間違いだったなぁ」と思い、修正に取り掛かろうとしました。
しかし、フロントエンドの方はこうも付け加えました。

> このエラーメッセージの項目はフロントエンド画面の状態によって
> △△ ではなく、 ×× となる場合がある。
> フロントから現在の画面の状態を送るので、それを元にエラーメッセージの項目名を変更してほしい。

パニックが始まりました。

# どうなったか
話し合いの結果、フロントエンド画面は状態によって項目の名前が変わる仕様が無くなり、
自分は項目名の修正を行うことで落ち着きました。
これによって画面に表示される項目と、APIのエラーメッセージに差異がある問題はなくなったものの、
依然としてエラーメッセージを組み立てる際にフロントエンドの画面がどうなるかを意識する必要は残り続けました。

# どうすべきだったか
この設計の問題点はバックエンド側がエラーコード等の状態ではなく、
メッセージをそのまま返却しており、その内容は画面を考慮しないといけないと言うのが
今回の事態の原因だと感じました。

なので、今回のような事を防ぐ為には
1. バックエンドはエラーコードを返却する
2. フロントエンドはエラーコードを元に画面に表示するメッセージを組み立てる

と言った風にするのが理想だと思いました。
(もちろん、フロントエンドの方の作業が増えてしまうのですが・・・)

バックエンドとしては [GitHub API](https://qiita.com/suin/items/f7ac4de914e9f3f35884)のような以下の形がいいなぁと思いました。

```JSON
{
  "message": "Validation Failed",
  "errors": [
    {
      "resource": "Issue",
      "field": "title",
      "code": "missing_field"
    }
  ]
}
```
OutSystemsのTraditional Webで多言語化対応する

2019/10のReactive Web Appの発表に伴い、従来のWebアプリケーション開発はTraditonal Webに改称されました。

OutSystemsの従来のWebアプリケーション開発では、Reactive Web Appより使いやすい多言語化対応機能が提供されていました。その機能を試してみます。
組み込みのスクリーンテンプレートを使って、言語設定(ロケール)を変更することで、同じスクリーンを英語と日本語で表示します。

なお、Reactive Web App版は以前Qiitaに書きました。
[OutSystemsのReactive Web Appで多言語化対応する](https://qiita.com/jyunji_watanabe/items/9c666e7883fa73e0a11f)

# サンプル
Forgeコンポーネント：https://www.outsystems.com/forge/component-overview/7064/housesoftsampletraditional
Multilingual Screenを参照してください。

# 環境
Personal Environment(Version 11.0.606.0)
Service Studio(Version 11.6.14)

# 概要
Traditional Webにおける多言語機能は、

1. eSpaceにロケールを追加する
2. 翻訳可能なリソースに翻訳後の文言を設定する(ダイアログとExcelインポート/エクスポートの方法があります)
3. 実行時に使用するロケールを設定するActionを呼ぶ

で実現します。

# 事前準備
翻訳対象となる画面を用意しておきます。
新しいWeb ScreenをDirectory Listテンプレートを使って作成し、Multilingualという名前を付けました。
またスクリーンショットが見やすいように、Table Recordsの表示件数を3に減らしてあります。

![qTraditionalML0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/77c02d7f-376c-7554-6e5d-08cd007740aa.png)

赤い枠を付けた部分を翻訳対象とします。

# eSpaceのロケール
多言語の対応をしたい場合は、Service Studioで、eSpaceに翻訳先ロケール(言語と地域の組み合わせ)を追加します。

Data > Multilingual Localesを右クリックし、Add Localeを選択します。
![qTraditionalML1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/fe68a5cc-fe94-7e1c-cbdf-621ee6e7ca0c.png)

ロケールを選択するダイアログが表示されるので、「ja-JP - Japanese (Japan)」を追加します。

# 翻訳後の文言を設定
この機能で翻訳可能な要素は以下になります。Entityから取得してくる情報は対象外で別途自分で翻訳を実装することになりますね。

- テキスト
- タイトル
- ラベル(Button, Process, Process Activity)
- Instruction(Human Activity)
- リンク
- Special List(Combo Box)
- メッセージ
- リテラル(EscapeしてなければJavaScriptも)
- 画像(画像は別途用意する)
- Static Entity(設定必要)

追加した「ja - JP」のロケールを右クリックし、Edit Translations...を選択してください。
これで、指定したロケールの場合の翻訳語の文言を設定するダイアログが表示されます。

![q
TraditionalML2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/0db763c9-1700-15f3-3b9c-46d19b87e159.png)

Translation in の後のダイアログで翻訳文言を設定したいロケールが選択されていることを確認してください。

翻訳文言は、真ん中のテーブルで設定します。
Text列に表示される文言は、Service StudioでWidgetに設定したものです。実行時にロケールが設定されないときのデフォルト表示になります。
Location列で、翻訳したいテキストが実際にどこに配置されているかを確認できます(どの画面に配置されているか、画面内のWidget Treeのどこにあるかなど)。

翻訳文言を設定したい行では、Translation in の列に翻訳後の文言を設定します。このとき、Behavior列をTranslateにしないと、翻訳が機能しません。

なお、翻訳担当者が別にいる場合、Excelとして設定をエクスポートし、設定済みのExcelファイルをインポートする機能もあります。

# ロジックの設定
画面のActions Placeholder内にロケール切り替え用のボタンを配置します。

Screen Actionは以下のように実装しました。
![qTraditionalML3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/14d5563d-8e82-f3d4-fa68-031116036d00.png)

SetCurrentLocaleは今リクエストを受け付けているユーザーのセッションのロケールを切り替えるActionです。ロケールを切り替えることによって、画面上ではそのロケールに設定しておいた翻訳文言が表示される仕組み。(System)モジュールから参照を追加してください。

ボタンをクリックするたびに、デフォルトロケール(ロケール="")と日本語("ja-JP")を切り替えるようにしています。GetCurrentLocaleは現在のセッションのロケールを取得。組み込みFunctionなので参照は不要。

なお、ロケールとして設定する値は、Service StudioでMultilingual Localesに追加した設定の先頭部分(「ja-JP - Japanese (Japan)」なら「ja-JP」)です。

# 実行例
![qTraditionalML4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/af06c904-46ef-1a45-e01c-a3739464f108.png)
【画像処理100本ノックに挑戦】Q.19. LoGフィルタ

# 使用したライブラリ
[【画像処理100本ノック】独自の画像入出力クラスを作る](https://qiita.com/jajagacchi/items/834e8425b84f94df8a49)

# Q.19. LoGフィルタ
> LoGフィルタ(sigma=3、カーネルサイズ=5)を実装し、imori_noise.jpgのエッジを検出せよ。
LoGフィルタとはLaplacian of Gaussianであり、ガウシアンフィルタで画像を平滑化した後にラプラシアンフィルタで輪郭を取り出すフィルタである。
Laplcianフィルタは二次微分をとるのでノイズが強調されるのを防ぐために、予めGaussianフィルタでノイズを抑える。

畳み込みの式の微分を考えれば、この場合カーネルを二階微分してから畳み込めばよいことがわかります。

```c++
int main()
{
	PPM ppm("imori_noise.pnm");
	int width = ppm.Get_width();
	int height = ppm.Get_height();
	PPM ppm2(width, height);

	auto kernel = [&](int i, int j)
	{
		double ret = 0;
		double sigma = 3, pi = 3.141592653589793;;
		if (abs(i) <= 2 && abs(j) <= 2)
		{
			double x = i, y = j;
			ret = (x * x + y * y - sigma * sigma) / (2. * pi * sigma * sigma * sigma * sigma * sigma * sigma) * exp(-(x*x + y*y) / (2. * sigma * sigma));
		}
		return ret;
		
	};

	auto conv = [&](const std::vector<std::vector<double>>& f)
	{
		std::vector < std::vector < double >> ret(width, std::vector<double>(height));
		for (int j = 0; j < height; j++)
			for (int i = 0; i < width; i++)
			{
				ret[i][j] = 0;
			}
		for (int j = 0; j < height; j++)
			for (int i = 0; i < width; i++)
			{
				double sum = 0;
				for (int di = -2; di <= 2; di++)
					for (int dj = -2; dj <= 2; dj++)
					{
						if (i - di >= 0 && i - di < width && j - dj >= 0 && j - di < height)
						{
							ret[i][j] += kernel(di, dj) * f[i - di][j - dj];
							sum += kernel(di, dj);
						}
					}
				ret[i][j] /= sum;
				//std::cout << sum << std::endl;
			}
		return ret;
	};

	std::vector < std::vector < double >> arry(width, std::vector<double>(height));
	for (int j = 0; j < height; j++)
		for (int i = 0; i < width; i++)
		{
			int r = ppm(i, j, 'r');
			int g = ppm(i, j, 'g');
			int b = ppm(i, j, 'b');
			int y = (std::round)(0.2126 * r + 0.7152 * g + 0.0722 * b);
			arry[i][j] = y;
		}
	arry = conv(arry);

	for (int j = 0; j < height; j++)
		for (int i = 0; i < width; i++)
		{
			int val = abs(arry[i][j]);
			if (val > 255) val = 255;
			ppm2(i, j, 'r') = val;
			ppm2(i, j, 'g') = val;
			ppm2(i, j, 'b') = val;

		}
	
	ppm2.Flush("out.ppm");
	return 0;
}
```
![imori_noise.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520857/3c09d4bb-a96f-d7ab-ee9f-5a9c6e8fceaa.png) ![out.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520857/f037f889-fae1-bc6f-9da9-e3d6d6f66406.png)
ぼかしが入っているので、あまりエッジが抽出出来ていない。何に使うのだ？
とにかくこれでフィルタ地獄から抜け出しました！ここからしばらくはヒストグラム操作みたいですね。
素人が勢いだけでデルタ型３Dプリンタを作ってみる

##ことはじめ
前から３Dプリンターが欲しいと思っていましたが、実際に３Dプリンタを使ったことは一度もなく
どれを買えばいいの分からずに買おう買おうと思って時間が過ぎてました。

ようやく3Dプリンターで作りたいものがちらほら出てきて、よし買おうと踏み出した訳ですが、
奮発して10万円以上のものに手を出すのもあれだし、かといって安いのはなんか面白みもなくて、

調べてみると３Dプリンターは自作している人が結構いるようで、中でも特に目を引かれたのがデルタ型プリンタです。
かっこいいですよね。

なのでここはひとつデルタ型プリンタを作ってみましょう。
一発で成功するとは思えませんが( ;∀;)

あまりお金をかけるのもあれなので予算を決めて4万円で作りたいと思います。
(既製品は4万円くらいだせばそこそこのものは買えます。というか4万円ってそこまで切り詰めてる感じでもないよね)

私の３Dプリンターの使用用途は、仕事や趣味の電子工作に使う小さい部品や治具を作りたいってだけなので、
造形精度はそこまで求めていません。まあ自分が欲しいサイズの箱くらいは出来て欲しいかなって感じです。

早速youtubeによさそうな動画を見つけて真似します。
[リンク](https://www.youtube.com/watch?v=NEtXqRDNJMc&t=303s)

この動画ではマイコンはArduinoMEGAを使用していたので同じものを使います。

そしてAmazonで部品を購入！もう後には戻れません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/361605/a392c76b-5ca8-57b3-a0a1-5a5e809b283f.png)

この時点で予算半分以上使いました。
まだ買っていないのは、モーターとマイコン、細かい部品などが残っています。


####ざっくり設計
(googleスケッチアップを使用しています。)
![デルタ3dPrinter.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/361605/043f0c34-0905-18aa-7e5c-1e4f618260e2.png)
2本づつ立っているシャフトは内側に入れようか迷いましたが、印刷範囲は広い方がいいだろうと思って外側に付けました。

早速シャフトとホルダー、リニアスライドユニットとアルミフレーム1000Lが届いたので組み立てます。
![20191216_230426.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/361605/32888b5a-4a69-25ad-a1ba-8c3c547eec8b.jpeg)

続いてリンクロッド。タミヤのおもちゃに使われるネジシャフト150Lを使います。
シャフトがリンクのネジ山にハマらず結構無理やりねじ込みましたｗ
![20191216_230444.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/361605/18756259-6207-e6a8-39db-94bfafb8f647.jpeg)

ですが！
ここで150Lのリンクがテーブルの印刷範囲まで移動できるのか疑問に思ってざっくり設計に150Lで手を足してみると・・・

![デルタ3dPrinter2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/361605/efa29bd3-c8b2-c814-3551-e1e667a6a109.png)

#####手の長さ足りなくね？
やっぱりリニアシャフトは内側に入れるべきでした。
それでもだめなら200Lのシャフトを買い直すことにします。

また150Lと100Lのアルミフレームの間にあるブラケットは正三角形の三角柱になります。
この形状のブラケットは調べても出てこないのでホームセンターでよさそうなのを探してみようと思います。


次は残りの部品が届いたら組み立てるところまでやりたいと思います。
NginxとDjangoとuwsgiの接続と戦ってやや勝利するまでの道のり

## DjangoとNginxを本格的にやろうと思い立って早2週間、ようやくサーバー接続に成功！

私はflaskとwsgiとapache2で接続したことはありましたがDjangoはこれまで食わず嫌いでいました。しかしWebSocketとかを導入したくてDjangoとnginxを導入することにしました。

現在も**「http://example.com:9000」**のように入力しないと表示されないのですが、バックグラウンドでuwsgiを起動させるところまではたどり着きました。

以下に苦戦した部分を書きます

###環境

- Ubuntu18.x
- Python2.7.x

##まずはnginxサーバーのインストールでまごつく

nginxサーバーを起動するまではよかったのですが

``` bash
$sudo /etc/init.d/nginx restart
```
と入力すると起動に失敗することがありました。
以下のような表示が出ました

``` bash
[....] Restarting nginx (via systemctl): nginx.serviceJob for nginx.service failed because the control process exited with error code.
See "systemctl status nginx.service" and "journalctl -xe" for details.
 failed!
```

これは私のUbuntu環境だと**/etc/nginx/sites-available/**の中の設定ファイルが間違っていたことが原因でした。(ポートがほかのサーバーと重複していたなど)

## uwsgiの仕組みがわからず大混乱

ここからが苦悩の始まりでした。uwsgiに苦しめられ結構苦戦しました。何よりノリで何とかなると思ってしまったことが失敗です。

uwsgiはnginxとDjangoアプリを結びつけるための設定値を持つ仲介的な役割を担うミドルウェアだと思ってください。いかに私のへたくそなiniファイルを貼ります。ちなみにuwsgiで大変参考になったサイトも紹介します。(英語)

[これがそのサイトです](https://uwsgi-docs.readthedocs.io/en/latest/tutorials/Django_and_nginx.html)

以下が私のiniファイルとその解説のコメントです。

``` bash 
# open_dashboard_uwsgi.ini file
[uwsgi]
project = open_dashboard
base = /home/user/Python #←自分のPythonプロジェクトのパス

chdir = %(base)/%(project)
#home = %(base)/Env/%(project)
home = %(base)/env #←自分のPython仮想環境のパス
module = %(project).wsgi:application

#uid = root
uid = user #←自分のユーザー名
master = true
processes = 2

socket = %(base)/%(project)/%(project).sock #←このソケットは自分で作ろうとしないこと
chmod-socket = 666
vacuum = true #←サーバーが切れたときにソケットを自動的に削除してくれる、結構大事

```

これをもとにemperorモードというものuwsgiをバックグラウンドで動かすモード(実際は複数のアプリを起動したりできたりするすごいモード)を設定しますが大体の場合以下のエラーで躓きます。

``` bash
unix:///home/user/Python/open_dashboard/open_dashboard.sock failed (13: Permission denied)
```

これが厄介なのですがemperorモードのuidとgidを自分のユーザー名にしておくと解決できます。
あとログファイルも**sudo chown user:user /var/log/uwsgi-emperor.log**
など設定しておくのを忘れないでください。

.bashrcを以下のように設定します。(/etc/rc.localがよいらしいのですがとりあえず確実な方で)

``` .bashrc
/usr/local/bin/uwsgi --emperor /etc/uwsgi/vassals --uid www-data --gid www-data --daemonize /var/log/uwsgi-emperor.log
```

上記のコードの***--emperor /etc/uwsgi/vassals***の部分ですが以下のように設定します。

``` bash
# create a directory for the vassals
sudo mkdir /etc/uwsgi
sudo mkdir /etc/uwsgi/vassals
# symlink from the default config directory to your config file
sudo ln -s /path/to/your/mysite/mysite_uwsgi.ini /etc/uwsgi/vassals/
```

- (2020/1/1更新)ユーザーはwww-dataがよいです。ソケットが作られない場合は/tmpを指定してください
- (2020/1/1更新)Python2のuwsgiだとPython3でエラーになるのでpip3などでuwsgiを再インストールする必要があります。

駆け足になってしまいわからないこともあるかと思いますが、とりあえず
**再び自分が迷わなくてもいいように**この記事を書かせていただきました。

[この記事のように502エラーばっかりでて暗い日々を過ごしていました](https://www.linode.com/community/questions/222/how-do-i-fix-this-502-bad-gateway-error-when-setting-up-django-project-on-ubuntu)

_次はDockerに挑戦するつもりです！_

## 改訂履歴 
- 2019/12/16 新規作成
- 2020/1/1 Python3でやった時にuwsgiをもう一度Python3用にインストールして再設定する方法を追記
[Unity] Colliderのみで衝突判定を行う

こんばんは、Arumiです！

今回はRigidbodyなしで衝突判定を行ってみましょう(๑•̀ㅂ•́)و✧

#実装

```c#:collider.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;

public class PlayerCollider : MonoBehaviour
{
    // BoxCollider2D コンポーネント
    BoxCollider2D collider2d;

    // 衝突結果を格納 (最大5個まで)
    Collider2D[] results = new Collider2D[5];

    // 開始処理
    void Start ( )
    {
        // Colliderをキャッシュ
        collider2d = GetComponent<BoxCollider2D> ();
    }

    // 更新処理
    void Update ( )
    {
        if ( IsHitToEnemy ()  ) {
            Debug.Log ("衝突しています");
        }
    }

    // 敵との衝突判定
    bool IsHitToEnemy ( )
    {
        // collider2dと衝突しているcolliderの数が返ってくる
        int hitCount = collider2d.OverlapCollider(new ContactFilter2D(), results);

        if ( hitCount > 0 )
        {
            for ( int i = 0; i < hitCount; i++ )
            {
                // 衝突したオブジェクトのTagがEnemyならreturn
                if ( results [ i ].tag == "Enemy") 
                {
                    return true;
                }
            }
        }
        return false;
    }
}
```


BoxCollider2Dと先程のコンポーネントを取り付けたプレイヤー（仮）
![player.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552230/38da3174-a5e3-1199-a2ff-fb8ece1d5c2c.jpeg)

BoxCollider2DとTagをEnemyにした敵オブジェクト（仮）
![inspector.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552230/043f995b-05de-effd-9703-5e1fa2f8dc86.jpeg)

２つのオブジェクトを作り、重なるように配置したら再生してみてください

#結果
めっちゃ衝突してくれます
![result.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552230/aef3e91c-689c-9bbb-3f20-f7d267166a45.jpeg)


今回はここまで(｀･ω･´)ゞ
ありがとうございました！
pyenv+pipx+PoetryでPythonのきれいな開発環境を手に入れる

以前話題になっていたこちらの記事の通りです。…というのも無価値な記事になってしまうので、多少解説をします。

[My Python Development Environment, 2020 Edition](https://jacobian.org/2019/nov/11/python-environment-2020/)

こちらの記事の著者はWSLを使っていますが、私もOSX環境でもほぼこのまま使えています。

# pyenv

> Why? I need to run multiple Python versions, isolated from the system Python. pyenv makes it easy to install, manage, and switch between those multiple Pythons.

様々なPythonのバージョンを切り替えるツールです。ちなみにもとの記事にある通り、pyenvは開発環境用に使い、アプリケーション実行環境にはDockerを利用すべきです。

## 参考記事

* [pyenv/pyenv](https://github.com/pyenv/pyenv)


# pipx

> Why? pipx lets me install Python-based CLI stuff (youtube-dl, awscli, doc2dash, etc.) without those projects’ dependencies messing up my global Python.

Pythonはawscliなどのコマンドのインストールにも使うため、それと開発用のライブラリのバージョンが衝突したりするとけっこう大変です。

## 参考記事

日本語でざっくり使い方を知りたい方は、以下の記事を読むといいでしょう。

* [pipxの紹介 - ばいおいんふぉっぽいの！](https://www.natsukium.com/blog/2019-08-26/pipx/)
* [Docs - pipx](https://pipxproject.github.io/pipx/docs/)

# Poetry

> Why? Poetry handles dependency- and virtual-environment-management in a way that’s very intuitive (to me), and fits perfectly with my desired workflow.

似たような用途で[Pipenv](https://pipenv-ja.readthedocs.io/ja/translate-ja/)がありますが、私も最近はPoetryを使っています。最近HackerNewsでも「[Pipenvって最近ちゃんとメンテナンスされてなくない？](https://news.ycombinator.com/item?id=21781421)」という趣旨の話題が出てました。

* Pipenvは `.python-version` を読み込んでpyenvのバージョン切り替えを自動行うが、Poetryは手動で行う必要がある
* Poetryにはパッケージとしてビルドして、PyPIに公開することがコマンドがある

また、以前はPoetryには `requirements.txt` でのエクスポートコマンドがなかったのですが、[最近実装されていました](https://python-poetry.org/docs/cli/#export)。Dockerを利用する際はこのコマンドで生成した `requirements.txt` を、Dockerイメージ内で `pip install -r requirements.txt` するようDockerfileを書くのがいいでしょう。

```bash
poetry export -f requirements.txt > requirements.txt
```

## 参考記事

* [Poetryを使ったPythonパッケージ開発からPyPI公開まで](http://kk6.hateblo.jp/entry/2018/12/20/124151)
* [Poetry - Python packaging and dependency management made easy](https://python-poetry.org/)
Swiftでzipメソッドに3つ以上の引数を渡す


今年も岩手県立大学アドベントカレンダーを書きます！

Swiftでzipメソッドを使うことはあると思いますが、引数として取れる値の数は２つのみです。

今回は３つの引数をとれるzipメソッドを実装したので紹介します。

# 環境

```
$ swift --version
Apple Swift version 5.1 (swift-5.1-RELEASE)
Target: x86_64-apple-darwin19.2.0
```

# 実装

```swift
func zip<A: Sequence, B: Sequence, C: Sequence>(_ a: A, _ b: B, _ c: C) -> Zip3Sequence<A, B, C> {
    Zip3Sequence(a, b, c)
}

struct Zip3Sequence<A: Sequence, B: Sequence, C: Sequence>: Sequence, IteratorProtocol {
    private var a: A.Iterator
    private var b: B.Iterator
    private var c: C.Iterator

    init (_ a: A, _ b: B, _ c: C) {
        self.a = a.makeIterator()
        self.b = b.makeIterator()
        self.c = c.makeIterator()
    }

    mutating func next() -> (A.Element, B.Element, C.Element)? {
        guard let a = a.next(), let b = b.next(), let c = c.next() else { return nil }
        return (a, b, c)
    }
}
```

# 解説

簡単にながら解説を書きます。

Swiftのzipメソッドは二つのSequenceを引数にとり、Zip2Sequenceを返却します。[zip(_:_:) - Swift Standard Library | Apple Developer Documentation](https://developer.apple.com/documentation/swift/1541125-zip)

また、このZip2SequenceもSequenceプロトコルに準拠しています。 [Zip2Sequence - Swift Standard Library | Apple Developer Documentation](https://developer.apple.com/documentation/swift/zip2sequence)

リファレンスを参考にSequenceプロトコルに準拠した、Zip3Sequenceを作成しました。

[Sequence - Swift Standard Library | Apple Developer Documentation](https://developer.apple.com/documentation/swift/sequence) に書いていますが、Sequenceプロトコルに準拠するためには `func makeIterator() -> Self.Iterator` を実装するか、 `IteratorProtocol` に準拠する必要があるとの記載があります。

> Making your own custom types conform to Sequence enables many useful operations, like for-in looping and the contains method, without much effort. To add Sequence conformance to your own custom type, add a makeIterator() method that returns an iterator.

> Alternatively, if your type can act as its own iterator, implementing the requirements of the IteratorProtocol protocol and declaring conformance to both Sequence and IteratorProtocol are sufficient.

今回はIteratorProtocolに準拠して実装をしました。

Zip3Sequenceに渡している３つのSequenceですが、このプロトコルに準拠しているものは makeIterator() というメソッドを持っているため、作成したイテレータに対してnext()を呼ぶごとにシーケンスの次の値を参照することができます。

IteratorProtocolに準拠するためには `func next() -> Self.Element?` を実装すれば良いです。 [IteratorProtocol - Swift Standard Library | Apple Developer Documentation](https://developer.apple.com/documentation/swift/iteratorprotocol)

理解がし辛い方へ補足を入れると、Zip3Sequence自身も next()　メソッドを持っているし、 引数として渡されている３つのSequenceも next() メソッドを持っています。

next() メソッドはmutating funcであり自身に対して作用するためvarとして宣言する必要があります。


# まとめ

この記事では3つの引数を取れるzipメソッドの実装について紹介しました。

間違っている箇所やご意見があればお願いします。

ジェネリクスを用いて引数の数に限りがないメソッドを作れるのかについても調査してみます。

最後までご覧いただきありがとうございました。

# 参考文献

- https://github.com/apple/swift/blob/master/stdlib/public/core/Zip.swift
- https://developer.apple.com/documentation/swift/zip2sequence
- https://gist.github.com/kristopherjohnson/04dbc470e17f67f836a2