OmniAICreator/Qiita-1.07M huggingface dataset:
Rails newが上手くいかない時の対処法

今日１時間ほどコマンドプロンプトでrails newをしても必要なファイルが作成されず、苦戦したのでその対処法を残しておきます。

誰かの参考になれば嬉しいです。

では、本題ですがコマンドプロンプトでrails newを実行するとこんな画面が表示されてばかりで、欲しいファイルが作成されませんでした。
gemfileでdeviseをインストール出来ないことからこの異変に気付いたのですが、最初はずっとgemfile側の問題だと思っていたのですが、全く改善できず。。。

そこで、最初に上手くいっていたアプリがあったのでそれを参考にしようと思ったのですが、まさか一番最初の時点でミスっているなんて思わずドツボにハマり、１時間ちょっと使いました（笑）

![スクリーンショット (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/900733/45d39485-476d-1825-1b77-0c9251e95857.png)

で、改めてこのコマンドプロンプトの表示を見てみるとgitのところで止まっていることに気づき、ググってみるとgitのコマンドがコマンドプロンプト上で使えるようになっていないからだと分かりました！！

だから、解決策としてはrails new アプリ名 -Gと後ろに-Gをつけてgitをスキップすれば解決することが判明し、無事解決することが出来ホッとしているところです。

gitをwindowsのコマンドプロンプトで使えるように設定しておけばよかった。。。
Amazon Translate で翻訳の範囲指定ができるようになりました。

#はじめに
**この記事は株式会社ナレッジコミュニケーションが運営する Amazon AI by ナレコム Advent Calendar 2020 の 7日目にあたる記事になります。**
ここでは、2020年11月5日にAWS Machine Learning Blog にて紹介されたAmazon Translate のアップデートについての紹介記事です。

#Amazon Translate とは？
Amazon Translate はディープラーニングを利用したテキスト翻訳サービスです。
Amazon Translate の主な特徴としては以下の通りです。

■ディープラーニングを利用した自然な翻訳を提供。
■複数の言語に対応(2020年12月7日時点で55の言語に対応)
■アプリやwebサイトとの連携が可能
■リアルタイム翻訳・バッチ翻訳に対応

# Amazon Translate の料金体系
Amazon Translate は従量課金制です。
課金対象の範囲は Amazon Translate が処理したテキストの文字数(空白文字も含む)になります。
料金には標準料金と無料枠があります。以下が詳細です。

■標準料金

 - 100万文字あたり15.00USD(1文字あたり0.000015USD)
 
■無料枠

- 最初に翻訳をリクエストしてから12か月間利用可能。
- 1か月200万文字の翻訳が無料
- 無料枠を超えた場合は超えた文字数分が標準料金で請求。

#今回のアップデード内容
今回のアップデートでは翻訳するテキストから翻訳しない範囲を指定できるようになりました。
以下の記事を参考に実際に試していきたいと思います。
参考記事：[Amazon Translate now enables you to mark content to not get translated](https://aws.amazon.com/jp/blogs/machine-learning/amazon-translate-now-enables-you-to-mark-content-to-not-get-translated/)

今回は以下の文章の**ニューラル機械翻訳サービス**を翻訳しない範囲においてみたいと思います。

**Amazon Translate は、高速で高品質な言語翻訳を手ごろな価格で提供するニューラル機械翻訳サービスです。**



###AWSマネジメントコンソール上で操作
![2020-12-07_16h40_36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614396/c28b7378-45dc-2b53-6a0e-c16e7b83fd62.png)
範囲指定は以下のように行います。

```
<p translate=no> 対象範囲 </p> 
```

上記の画像の赤枠の指定した範囲が翻訳されず他のは英語で翻訳されました。


###コマンドツールでの操作
![2020-12-07_16h49_18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614396/bad39c55-1509-1b2c-c5f7-f272bf5849c3.png)
コマンドプロンプトを使用してAWS CLI で行いました

結果はjson方式で出しています。
上記の画像の通り、コマンド上でも指定した範囲では翻訳されずに行えました。

※以下のようにコマンド入力の際にOSによって違いがあるのでご注意ください。
Unix,Linux,MacOS 各行の終わりの行を「\」
Windows 各行の終わりの行を「＾」
#最後に
Amazon Translate はAWS SDKでの操作可能です。
Amazon Translateではpptxなどの様々な形式での翻訳や大量のテキストを一度に翻訳できるバッチ翻訳も利用可能なので試してみたいと思います。
興味がある方は無料枠を利用して試してみてはいかがでしょうか？


#参考資料
[Amazon Translate 開発者ガイド](https://docs.aws.amazon.com/ja_jp/translate/latest/dg/translate-dg.pdf)
CakePHP CASE文をORMで表現する

こちらの記事は[ユアマイスターアドベントカレンダー2020](https://adventar.org/calendars/5455)の7日目の記事です。

# やりたいこと
- SQLのSELECT句におけるCASE文を、ORMで表現したい

# TL;DR
- queryオブジェクトを生成
- addCase()を使用してCASE文作成
    - 第一引数：条件
    - 第二引数：条件に関連した値
        - 最後の値（`new IdentifierExpression('SUM(price)')`）は、SQLのELSEの値に当たる
    - 第三引数：型
- CASE文をORMのSELECT句に指定

```php
$query = $this->Products->find();
$case  = $query->newExpr()->addCase(
    [$query->newExpr()->add(['SUM(price) IS NULL'])],
    [0, new IdentifierExpression('SUM(price)')],
    ['integer', 'integer']
);
$query->select(['price' => $case])->all();
```


# SQL
- ORMで表現したいSQL


```sql
SELECT
    CASE
        WHEN SUM(price) IS NULL THEN 0
        ELSE SUM(price)
    END
FROM products;
```

# ORM
- 上記のSQLをORMで表現

```php
$query = $this->Products->find();
$case  = $query->newExpr()->addCase(
    [$query->newExpr()->add(['SUM(price) IS NULL'])],
    [0, new IdentifierExpression('SUM(price)')],
    ['integer', 'integer']
);
$query->select(['price' => $case])->all();
```

# 解説
- queryオブジェクトを生成
- addCase()を使用してCASE文作成
    - 第一引数：条件
    - 第二引数：条件に関連した値
        - 最後の値（`new IdentifierExpression('SUM(price)')`）は、SQLのELSEの値に当たる
    - 第三引数：型
- CASE文をORMのSELECT句に指定
エンジニアにとって効率のいいおやつとは何だろう

この記事は [WESEEK Advent Calendar 2020](https://qiita.com/advent-calendar/2020/weseek) 7日目の記事です！

さっそく2回目の執筆です。  

そして結論から言うと『エンジニアにとって効率のいいおやつとは人それぞれである』という内容になるので、この解を求めている方はここで読むのをやめてもいいかもしれない…です。  
箸休め的に読んでもらえると幸いです！
  
# 筆者の前提条件  
- 以前ゲーム開発会社に在籍しており、エンジニア/プログラマと触れ合ってきた
- 現在はエンジニアに囲まれて、非エンジニアな職に就いている
- かつ、人とのコミュニケーションをとてもとても大切にしている
- スナック菓子的なものをあまり食べない

では、参ります。

# おやつバーの存在
私の在籍しているWESEEKでは、おやつバーというものが存在しています。  

```
説明しよう！
おやつバーとは、WESEEK の福利厚生の一部であり、誰もが営業日であれば自由に食べられる夢のようなバーなのである！
```
というものです。
このおやつバーを管理・運営しているのが私のいる部署なんですね。  
独断と偏見と予算を加味して選定・購入しているのですが、エンジニアがどういうものをこのおやつバーに求めているのか…はとても気になっているところです。

# 食べづらいおやつは不人気
ひとくちパイ的なものが私はわりと好きで、かつお安いこともあり常設していた時期がありました。
しかしながらあまり減らない。  

なんでだろうなぁ～と思い、社内交換日記に「ひとくちパイは不人気なのだろうか？」という趣旨の質問をしてみました。
返信があったらあったで、なかったらなかったで。という軽さです。

数日後、このような返答が書かれていたのですね。

```
「美味しいのだけれど、ポロポロこぼれて大惨事になったことがある。」
「俺のキーボードがひとくちパイ食っちまった…的な」
```

Oh...それはアカンやつですね。なるほど。  
たしかに自分も、ティッシュに広げて食べていたし、ウェットティッシュがマストだった…なるほど。
栄養補給を効率的に行いたい(であろう)エンジニアにとっては、この手間は全く持って合理的ではない。なるほどなるほど。  
と、現在はひとくちパイは1軍から外れています。
要求があればたまに登場するかもしれないですが！

# おやつバーの見直し
上記の件も含めて、7月におやつバーの見直しを行いました。  
主に予算ですね。
![5efef65a6846e2004875e7ea.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/915398/0c4ba9ba-0894-e0d2-377e-7e50d5e6c670.png)

そうですよね。
こちらのアンケートでは、**限りがないとすれば** という前提条件を設けましたが、無くても同じ結果だったと思います。  

数字からも攻めよう！となり、前回予算を決めた時からの以下の推移を見てみました。
* 稼働人数
* 稼働時間

これらを算出したところ、どちらも約2.5倍に跳ねていることがわかりました。
数値とアンケートを持って代表へ直談判し、予算を希望どおりに上げることができたのです。

それでも足りていない気がするのですが、次の予算アップは現場のエンジニア方から意見書がほしいところであります。  

# エネルギーを求めるか、楽しみたいのか
わかれるところだと思いますが、半々なのかな…？
チョコレートと飴に関しては前者のエネルギー補給が大きい部分であると感じているので、常に設置しています。  

ちなみに、チョコレートは『チョコレート効果カカオ72%』をご指名いただいているのでずっとコレです。 
声を上げることは何にしても大切なのですね。予算の4~5%はこれです。結構な割合だと思います。  

チョコレートはエネルギー効率重視だとすると、『ココアシガレット』『うまい棒』『よっちゃんイカ』などを列挙するタイプはエネルギー重視じゃないのだろうと推測されます。
自分の中でエネルギー効率が高いものは自前で用意し、それ以外の楽しみをおやつバーに求めているのかな…とかとか。
エンジニアではないながらも、意外と色々考えて運営をしています。

私はエンジニアではないのですが、前職でゲームのスクリプトを組んでいたことがあります。
その時は柿ピーとドライフルーツを無限に食べていたな…と思いだし、ドライフルーツもいいなぁ…と今、なう、考えているところです。  


ただ単価が高い！個包装め！！！

単価が高い…から派生すると、グミはとても効率的だと考えています。
顎を使うから眠気覚ましにもなるし、甘いし。  

でも！！！個包装が少ない！！！単価が高い！！！
単価が高いのを納得させるほどのプレゼンテーションをしてくれたら導入するのに！！  

という気持ちです。


# まとめと余談
エンジニアにとって効率のいいおやつとは何だろう、というタイトルの回収は残念ながらできませんでした…。  

人それぞれなところもあるので、しょっぱい系と甘い系・たまに季節ものなどを織り交ぜて、エンジョイ側に寄って運営していこうかなぁと思っています。
そもそも私がスナック菓子をあまり食べてこなかった事もあり、何が世間一般で人気なのかが不明なところもあります。
ので、年齢を感じるお菓子が出てきている気もします。エ●ーゼとか。  

それもそれで、普段自分では買わないお菓子として楽しんでもらえたらいいな。  
ですが、エンジニアにとって効率がいいもの！というのはこれからも探求していきたいと考えています。  

**余談**

別府サテライトオフィスにおやつバーを設置する際、「何が食べたいですか？」という問いに対して、「馬場で人気なもの」という回答がありました。  

微笑ましい気持ちになった。という余談。

# 最後に
※この記事は [WESEEK Tips wiki](https://tips.weseek.co.jp/) に 2020/12/7 に投稿された記事の転載です。
Tips wiki では、IT企業の技術的な情報やプロジェクトの情報を公開可能な範囲で公開しています。  

どうぞ明日もお楽しみに！
Railsについて初心者なりに調べてみた

# ドキュメント

[Ruby on Rails ガイド：体系的に Rails を学ぼう](https://railsguides.jp/)

[Railsドキュメント](https://railsdoc.com/)

# Railsとは

- Rubyにより構築されたWEBアプリケーションフレームワーク
- MVCアーキテクチャに基づいて構築されている
- 他のフレームワークより少ないコードでアプリケーション開発ができるように考慮されている
- それを実現するためにRailsには制約が多く存在し、慣れるまでは少し窮屈に感じることもあるかも？

# Rubyの他フレームワーク

###Sinatra
・軽量なフレームワークで簡潔に記述できる、最小限の労力でWebアプリケーションをすばやく作れる。
・MVCアーキテクチャに基づいた設計ではない。
小規模開発に向き
http://sinatrarb.com/

###HANAMI
・バージョン1.0が2017年4月にリリースされた比較的新しいフレームワーク。
・メモリの消費を抑えるために提供されている100以上の安定したAPIを利用できる
・応答速度などで高いパフォーマンスを発揮
長期的なメンテナンスを考え作られている
https://hanamirb.org/

###Ramaze
・Sinatraと同様にシンプルかつ軽量で柔軟性のあるフレームワーク
・Rubyの書き方をそのまま踏襲できるようになっている
http://ramaze.net/

# 他言語フレームワークとの比較

## Web開発フレームワークのシェアと推移

[Stack Overflow](https://insights.stackoverflow.com/trends?tags=laravel%2Cruby-on-rails%2Cdjango%2Cgo%2Ccodeigniter)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586262/8bfde555-9447-50ea-3d67-bd6ea9c70a8c.png)


djangoとlaravelがトレンド上昇している。

ruby on rails は2011年以降、下降している。

## Ruby on rails のトレンド下降している要因

[Twitterが、Ruby on RailsからJavaVMへ移行する理由](https://www.publickey1.jp/blog/11/twitterruby_on_railsjavavm.html)

Twitterの膨大化したアクセスを、railsで構築されたシステムよりもJavaVMの方が速やかに処理できる。

→大規模システム開発で使われるケースが世界的に減っている。

なぜ一時期、一世を風靡したRuby on railsが、「railsはもう終わった」と言われるようになったのか？

その一部の背景を上記で説明しました。以下は具体的にかかれている記事

[「Railsは終わった」と言われる理由 - Qiita](https://qiita.com/klriutsa/items/86ac5e94ec99c0d95b61)

ただ日本ではスタートアップ中心に仕事がまだまだたくさんある。

例、Cookpad, Gunosy, 食べログ, Freee, Crowdworks

# 開発環境

- ローカル
- Virtual Box
- Docker
- Cloud9(AWS)

# 開発の流れ（ローカル環境）

基本的にMVCモデルの設計に沿って、ファイルを作成する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586262/c7461ea7-3fa7-22ac-824d-7010768af899.png)
↑railsチュートリアルから抜粋


# 参考文献

[Ruby on Railsだけじゃない！Rubyフレームワーク6選](https://eng-entrance.com/ruby-framework)

[Ruby on Rails チュートリアル：プロダクト開発の０→１を学ぼう](https://railstutorial.jp/)
JUnit 基礎

> この記事の目標
JUnitの基本的な使い方とJUnit4, 5の違いをまとめる
必要になった時に目を通してわかる程度のまとめ

### 目次

1. JUnitとは
2. JUnitでのテスト対象
3. 基本的な使い方
4. アノテーションと検証メソッド
5. 実際の単体テストで注意すること

## 1. JUnitとは 
JUnitとは**Javaプログラム向けの単体テストフレームワーク**
作成したJUnitのコードからテスト対象クラスのメソッドを呼び出して動作テストが出来る
テストコードは流用が効くためテスト工数削減につながる

## 2. JUnitでのテスト対象
- publicメソッドであること(JUnit5ではpublicである必要はない)
- 引数を持たないこと
- 戻り値はvoidであること
※テスト対象メソッドがprivate,protectedの場合解決策
 → リフレクションを使うかpublicまで上がるか

## 3. 基本的な使い方
テスト対象メソッド

```java:SampleJunit.java
public class SampleJunit {

    public String sayHello() {
        return "Hello";
    }

		public int add(int x, int y) {
				return (x + y);
		}
}
```


テストコード  (JUnit4)

```java:SampleJunitTest.java
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;

import org.junit.Test;

public class SampleJunitTest {

    @Test //クラス名はテスト対象メソッド+Test
    public void sayHelloTest() {
        SampleJunit sample = new SampleJunit();
        assertThat(sample.sayHello(), is("Hello"));
    }

		@Test
		public void addTest() {
				SampleJunit sample = new SampleJunit();
				int actual = sample.add(2, 3);
				assertThat(actual, is(5));
		}
}
```

**クラス名**
テスト対象メソッド+Test

**テストメソッド**
＠Testアノテーションの付与（テスト対象メソッドとして実行される）
1ケースにつき1メソッド

**期待値と実測値の比較**
assertEquals(expected, actual)  または  assertThat(actual, is(expected))
引数がそれぞれ逆なので注意

**実行結果**
・画面右側のインジゲータがすべてグリーンになっている
・実行結果が全て完了していること
失敗した場合はインジケータがレッドになる


## 4. アノテーションと検証メソッド

アノテーションはJUnit4とJUnit5で一部違いあり

| JUnit4      | JUnit5     | 説明                       |
|:------------|:-----------|:-----------------------------|
| ＠Test        | ＠Test       | テストメソッド     |
| ＠Before      | ＠BeforeEach | 各テストメソッドの実行前に呼ばれる    |
| ＠After       | ＠AfterEach  | 各テストメソッドの実行後に呼ばれる    |
| ＠BeforeClass | ＠BeforeAll  | クラス内の全テストの実行前に呼ばれる  |
| ＠AfterClass  | ＠AfterAll   | クラス内の全テストの実行後に呼ばれる  |
| ＠Ignore      | ＠Disabled   | テストを実行しない                 |



### 検証メソッド

JUnitで多用する検証メソッドについては下記URL参考
・[HamcrestのMatchersに定義されているメソッドの使い方メモ](https://qiita.com/opengl-8080/items/e57dab6e1fa5940850a3)
・[AssertJ版：テストでよく使う検証メソッド一覧](https://qiita.com/naotawool/items/6512ecbe2fd006dacfd2)


---

## 5. 実際の単体テストで注意すること

▼現場での単体テスト実施時の注意事項
・テスト観点の優先順位を確認する
　(成果物の最低ラインをとりあえず『わかりやすく』満たすべき)
・ケース網羅出来ているかは自分で考えてしっかり確認を行う
　カバレッジ100%はあくまで目安　テスト仕様書を信用してはならない



<br>

### 単体テスト参考

・ユニットテストデザイン
[https://qiita.com/koduki/items/4fde43b68fe450c6a5d8](https://qiita.com/koduki/items/4fde43b68fe450c6a5d8) 

・カバレッジの計測 (JaCoCo/JMockit)
[https://tosi-tech.net/2020/06/coverage-report-of-jacoco/](https://tosi-tech.net/2020/06/coverage-report-of-jacoco/)
[https://atuweb.net/201606_junit-jmockit-test-and-coverage/](https://atuweb.net/201606_junit-jmockit-test-and-coverage/)
FTPサーバーとしてのS3とフォルダ振り分け

# FTPサーバーもサーバーレスに
ファイルをFTPサーバーで受信するような旧来型のあるサービスをAWSに移行したときの話です。
移行後もFTPサーバーとしての EC2 を立てて…というのはなんだかなぁということで、**S3** に配信することにしました。

このとき、まず仕組みとして考えたのが以下の構成。

- (HTTP) CloudFront → API Gateway → Lambda → S3

見様見真似で構築自体は問題なくいきましたが、配信元システムの仕様でHTTPでのファイル配信では運用できないことが分かりました。

そこでFTPで配信する仕組みを構築すべく、[AWS Transfer Family](https://aws.amazon.com/jp/aws-transfer-family/?whats-new-cards.sort-by=item.additionalFields.postDateTime&whats-new-cards.sort-order=desc) を検討しました。

## AWS Transfer Family
従来はSFTPのみサポートしていたマネージドサービスですが、今年からFTP/FTPSをサポートするようになりました。まさに僥倖。
※FTPやめようよ…

構築について詳しくはこちらを参考に。
[AWS Transfer for SFTPがFTP/FTPSをサポートしました！](https://blog.serverworks.co.jp/tech/2020/04/29/post-83641/)

Cloud Formation でテンプレートから構築されます。

- Transfer for SFTP
- API Gateway
- Lambda

FTPの場合、認証はカスタムするしかないので、[Secrets Manager](https://aws.amazon.com/jp/secrets-manager/) を利用することにして、作成された Lambda から読み込むようにしました。
（Secrets Manager の読み込みはサンプルコードが生成されるのでそれを元に）

あとは、つくられた VPC のエンドポイントにアクセス確認。

問題なければ、配信元のシステムの設定も更新します。
これで無事、S3にFTP配信される仕組みが整いました。

## 配信されたファイルをフォルダに振り分ける
あとは元々、ファイル名から適切なフォルダに振り分ける（なければつくる）という処理が入っていました。
このままだとバケットのルートにファイルが溜まり続けるので、S3トリガーで動く Lambda を作成します。

トリガーは S3 ファイル**PUT**時。
ファイルを適切なフォルダに移動（コピー＆削除）する処理を Lambda で記述します。

- Pythonでの例

```move.py
import logging
import urllib.parse
import boto3

logger = logging.getLogger()
logger.setLevel(logging.INFO)

def handler(event, context):
    try:
        client = boto3.client('s3')
        bucket_name = event['Records'][0]['s3']['bucket']['name']

        src = urllib.parse.unquote_plus(event['Records'][0]['s3']['object']['key'], encoding='utf-8')

        ## ここで対象ファイルのチェックなど

        ## 向き先のフォルダ名を決めるなど

        dst = folder_name + '/' + src

        client.copy_object(Bucket=bucket_name, Key=dst, CopySource={'Bucket': bucket_name, 'Key': src})
        client.delete_object(Bucket=bucket_name, Key=src)

        logger.info("moved file: from[" + src + "]" + ", to[" + dst + "]")

        return True

    except Exception as e:
        logger.error(e)

        return False
```

トリガーを「すべてのイベント時」ではなく PUT に限定することで、このファイル移動処理での COPY のときにも起動されないようにしています。

これで、サーバーレスなFTPサーバー(?)ができました。
Web開発の便利ツール ngrokをご紹介！ webhookを利用した開発に便利！

# はじめに
今回はWeb開発における便利ツールngrokについて紹介します！
ngrokはローカルの特定のポートをWeb上に公開できるツールです。

LINEやSlack, Salesforceなどでwebhookを使う時に大活躍します！
また、ローカルのポートを共有できるので、デモなどにも適しているかもしれません。

# YouTube動画
動画で確認したい方はこちらをどうぞ！
[【YouTube動画】 Web開発の便利ツール ngrokをご紹介！ webhookを利用した開発に便利！](https://youtu.be/9UYZf-AUXhw)
[![Web開発の便利ツール ngrokをご紹介！ webhookを利用した開発に便利！](https://img.youtube.com/vi/9UYZf-AUXhw/0.jpg)](https://youtu.be/9UYZf-AUXhw)

# インストール方法
Macの場合、brewで簡単にインストールできます。

```bash
brew install ngrok
```

# 使い方
ローカルの3000番ポートを公開したい場合は、以下のようにします。

```bash
ngrok http 3000 --region jp
```

実行すると、以下のような画面になります。
``http://xxxx.ngrok.io`` または ``https://xxxx.ngrok.io``にアクセスすると、3000番ポートに繋がります。
![スクリーンショット 2020-11-30 22.51.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/751408/90e624ed-43ce-4317-7f99-aa5e08a530c9.png)

Node.jsなどで8080番ポートを公開したい場合は、Invalid Host Headerを防ぐために、次のようにしたりします。

```bash
ngrok http 8080 --region jp -host-header="localhost:8080"
```

# 有料版
無料版の場合、ngrokを使うたびに、``http://xxxx.ngrok.io``のxxxx部分が変わります。
有料版にすると、その部分を固定することができ、サブドメインも追加することができます。

Pricingは$5からです。
Webhookの開発で大活躍するので、ぜひ活用してみてください！！
![スクリーンショット 2020-12-07 18.15.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/751408/43a54bac-e09d-2fb6-9c10-b1a4b0816141.png)
【PHP】宇宙船演算子の復習

##はじめに
https://qiita.com/Hiraku/items/62821d7d0e7af1ac211e
こちら様の記事の個人用メモになります。難しい！

###宇宙船演算子の基本
`<=>`と記載する「小なり」「イコール」「大なり」がくっついた演算子のこと。名称がわからず検索に苦労。
三方比較演算子とも表記するみたいです。基本的に`usort()`関数と併用します。

基本的に`$a <=> $b`とした場合、usortで指定した配列は昇順(0,1,2,...)でソートされます。
対して、`$b <=> $a`とした場合は指定した配列が降順(...,2,1,0)でソートされる、という特徴があるようです。

###サンプル1

```php
$array = array(1,0,3,2);

usort ($array, function ($a, $b){
    return $a <=> $b; //昇順に並び替えられる 0,1,2,3
});
print_r($array);

/* 出力結果
Array
(
    [0] => 0
    [1] => 1
    [2] => 2
    [3] => 3
)
*/
```

```php
$array = array(1,0,3,2);

usort ($array, function ($a, $b){
    return $b <=> $a; //降順に並び替えられる 3,2,1,0
});
print_r($array);

/* 出力結果
Array
(
    [0] => 3
    [1] => 2
    [2] => 1
    [3] => 0
)
*/

```

###サンプル2（2次元配列）
```php

    $array = [
        [2,2], [5,3], [3,5], [3,4], [4,2], [2,3], [2,5], [3,6], [2,4], [4,1]
    ];
    //[値x,値y]として配列に入っている。
    //今回はxの値を優先的に昇順(0,1,2,...)でソートされるように決定。
    //xの値が、比較先のxと同じである場合はyの値を確認し、yが降順(...,2,1,0)に並ぶようにする。
    
    usort ($array , function ($a, $b) {
        
        //$aのxと、$bのxが同じだった場合。
        //===は変数の型も同じである場合。(==と記載した場合も、今回のコードは動きます)。
        if ($a[0] === $b[0]) {
            
            //yの降順で並べる
            //降順の際は、比べている値を逆さに記載する
            return $b[1] <=> $a[1];
        }
        //それ以外の場合は、xの値を昇順に並べる
        return $a[0] <=> $b[0];
    });
    
    foreach ($array as $a) {
        echo implode(' ', $a). "\n";
    }

/* 出力結果
2 5
2 4
2 3
2 2
3 6
3 5
3 4
4 2
4 1
5 3
*/
    
```
###さいごに
自分以外が見ても分かるように書いたつもりですが、自分の理解していない箇所についてはうまく言語化できず・・・
記事にしてアップすると知識が定着すること以外にも、自分の弱い箇所も分かって良いですね。

自分で配列の値を弄って、実行して結果を見て様子を確認していくと結構理解が進んだ気がします。
ASM6でnesファイルを作ってみた(2)


#環境
- Windows 10 Home (64bit)
- ASM6 (v1.6)

#ソース
##原始的サウンドドライバ
VBlank割込みを使った原始的サウンドドライバ。

```nesasm:test9.asm
;asm6 test9.asm test9.nes

tick	= $00
seq	= $01

	; iNES header
	db	"NES", $1a
	db	$01	; PRG-ROM
	db	$01	; CHR-ROM
	db	$00	; mapper / mirroring
	dsb	9, $00

	base	$c000
Reset:
	lda	#$00
	sta	seq
	lda	#$01
	sta	tick

	lda	#$01
	sta	$4015	; 音声チャンネル制御レジスタ
	lda	#%10111100
	sta	$4000	; 矩形波CH1制御レジスタ1
	lda	#$00
	sta	$4001	; 矩形波CH1制御レジスタ2
	sta	$4002	; 矩形波CH1周波数値レジスタ1
	sta	$4003	; 矩形波CH1周波数値レジスタ2

	lda	#$80
	sta	$2000	; PPU制御レジスタ1
	lda	#$08
	sta	$2001	; PPU制御レジスタ2
-
	jmp	-

VBlank:
	dec	tick
	bne	++
	ldx	seq
	lda	sequence, x
	bne	+
	ldx	#$00
	stx	seq
	lda	sequence
+
	sta	$4002	; 矩形波CH1周波数値レジスタ1
	inc	seq
	lda	#30
	sta	tick
++
	rti

sequence:	; 1,790,000Hz / (1,000Hz * 16) - 1 = 110.875 = $6f
	db	$37, $6f, $00

	org	$fffa
	dw	VBlank	; NMI VBlank
	dw	Reset
	dw	0	; IRQ/BRK

	; fsutil file createNew test.chr 8192
	incbin	"test.chr"
```

##ノイズ発生
ABボタンでノイズ発生。

```nesasm:test10.asm
;asm6 test10.asm test10.nes

button_a	= $00
button_b	= $01

	; iNES header
	db	"NES", $1a
	db	$01	; PRG-ROM
	db	$01	; CHR-ROM
	db	$00	; mapper / mirroring
	dsb	9, $00

	base	$c000
Reset:
	lda	#$80
	sta	$2000	; PPU制御レジスタ1
	lda	#$08
	sta	$2001	; PPU制御レジスタ2
-
	jmp	-

VBlank:
	lda	#$01
	sta	$4016	; ジョイパッド1レジスタ
	lda	#$00
	sta	$4016

	; Aボタン
	lda	$4016
	and	#$01
	bne	+
	lda	#$00
	jmp	++
+
	lda	button_a
	bne	++
	ldx	#%10000111
	jsr	sound
	lda	#$ff
++
	sta	button_a

	; Bボタン
	lda	$4016
	and	#$01
	bne	+
	lda	#$00
	jmp	++
+
	lda	button_b
	bne	++
	ldx	#%00000111
	jsr	sound
	lda	#$ff
++
	sta	button_b

	rti

sound:
	lda	#%00001111
	sta	$400c	; ノイズ制御レジスタ
	stx	$400e	; ノイズ乱数レジスタ
	lda	#%00001000
	sta	$400f	; ノイズ時間レジスタ
	lda	#$08
	sta	$4015	; 音声チャンネル制御レジスタ
	rts

	org	$fffa
	dw	VBlank	; NMI VBlank
	dw	Reset
	dw	0	; IRQ/BRK

	incbin	"test.chr"
```
[Delphi] class constructor と initialization は違うよという話

# initialization

[initialization](http://docwiki.embarcadero.com/RADStudio/ja/%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E3%81%A8%E3%83%A6%E3%83%8B%E3%83%83%E3%83%88%EF%BC%88Delphi%EF%BC%89#initialization_.E3.82.BB.E3.82.AF.E3.82.B7.E3.83.A7.E3.83.B3) 節とは、Turbo Pascal の段階から載っていた unit の初期化節です。
ここに書くとアプリの起動時にメイン部より先に実行されます。

```pascal:初期化節の例
unit Foo;

{中略}

initialization // 初期化節
  Bar;         // アプリの起動時に実行される

finalization // 終了処理節
  Baz;       // アプリの終了時に実行される

end.
```

# class constructor
~~Delphi 2009 か 2010 のどちらか~~ Delphi 2010 から搭載されている [class constructor](http://docwiki.embarcadero.com/RADStudio/ja/%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89%EF%BC%88Delphi%EF%BC%89#.E3.82.AF.E3.83.A9.E3.82.B9_.E3.82.B3.E3.83.B3.E3.82.B9.E3.83.88.E3.83.A9.E3.82.AF.E3.82.BF)
~~(どこから載っているか特定できませんでした。恐らく 2009)~~
(コメントで Delphi 2010 からとご教授いただきました)

```pascal:クラスコンストラクタの例
type
  TFoo = class
  private
    class constructor CreateClass; // ←これ
  end;

implementation

class constructor TFoo.CreateClass;
begin
  // なにか初期化
end;
```

>クラス コンストラクタの呼び出しは、そのクラスが定義されているユニットの initialization セクションに、コンパイラが自動的に挿入します。

と DocWiki にあるように class constructor は基本的には initialization と同義です。
ある１点を除いては。

# 違い

initialization 節は必ず実行されるのに対して、class constructor は

**クラスが使用されている場合にのみ実行される**

という事です。

DocWiki にも

> コンパイラがアプリケーションのどこかで TBox が実際に使用されているかどうか確認し、使用されている場合は、クラス コンストラクタの呼び出しがユニットの initialization セクションに自動的に追加されます

とありました。

Delphi はスマートリンカが載っているので使われていないクラスは削除されてしまうという訳です。
なので、initialization と同じ感覚で使うと、あれれ！？初期化部分が動いてないぞ～！？となってしまいます。

# 問題になるコード

例えば下記のようなコードです。

```pascal:失敗
uses
  System.Classes;

type
  TFoo = class(TPersistent)
  private
    class constructor CreateClass;
  end;

implementation

class constructor TFoo.CreateClass;
begin
  RegisterClass(TFoo); // クラスを登録する処理（実行されない）
end;
```

この場合、TFoo が TFoo の外部（他のユニットやinitializationなど）から呼ばれないと TFoo は削除されリンクされません。
TFoo.CreateClass で RegisterClass に TFoo を渡していてもそれは TFoo 内部の話なので誰かが使っているとは認識されません。

この場合は

```pascal:成功
uses
  System.Classes;

type
  TFoo = class(TPersistent)
  end;

implementation

initialization
  RegisterClass(TFoo); // クラスを登録する処理（実行される）
```

と、initialization を使うのが正解です。
この場合 initialization から使われるため、TFoo もリンクされます。

# 最後に
同じような機能がある場合、きちんと差異を知っておかないとダメですね
LINE WORKS Bot 固定メニュー簡単登録

#自己紹介
今回はじめて参加します。SPALOです。
私たちは、LINE WORKSなどのチャットツールからボットと会話するだけで報告書を作成できるサービス<a href = "https://spalo.jp/" target="_blank">SPALO</a>を展開しています。

#固定メニュー使ってますか？
早速本題にはいります。
よく使う言葉や外部ページを簡単に利用できるようにしたいけどリッチメニューを使う程でもないよなって時に重宝するのが「固定メニュー」ですよね。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/913794/53275a0a-aae0-0ebe-d262-9c933065b9c0.png" width="60%">
こちらの固定メニューですが、コンソールから設定する事ができず、API経由からのみとなっています。
![固定メニュー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/913794/8f17973b-db77-e30d-675b-151646ddf10c.png)

そんな固定メニューをcurlコマンドで簡単一発登録する方法を説明します。

#準備するもの
- API ID
- Server API Consumer Key
- Token
- Bot No（固定メニューを設定したいBotのNo。）
- メニュー内容（Action Objectsのmessageとuriが利用できます。）<br>
https://developers.worksmobile.com/jp/document/1005050

#コマンドの作成
こちらの例文を元にして、準備した値を各項目に書き換えて下さい。
dオプションがメニュー内容になっています。任意の内容に変えて下さい。

```bash
curl -X PUT -H 'consumerKey:{ConsumerKey}' -H 'Authorization:Bearer {Token}' -H 'charset: UTF-8' -H 'Content-Type: application/json' -d '{"content": {"actions": [{"type": "message","label": "こんにちは","postback": "hello"},{"type": "message","label": "ありがとう","postback": "thanks"},{"type": "uri","label": "Qiita","uri":"https://qiita.com/"},{"type": "uri","label": "LINE WORKS","uri":"https://line.worksmobile.com/"}]}}' https://apis.worksmobile.com/r/{API ID}/message/v1/bot/{Bot No}/persistentmenu
```

#コマンドを実行
ターミナルを開いて作成したコマンドを貼り付けてEnterキーを押して完了です。
エラーが返ってこなければ成功です。
対象のBotを開いて確認してみて下さい。
【LaravelExcel】LaravelExcelのバージョンアップでハマったことまとめ

##経緯
Laravelをバージョンアップするに伴い、PHPやライブラリであるLaravelExcelやPHPExcelなどもバージョンアップされ、いくつかの変更点でハマった点をまとめてみた

##新旧のバージョン情報
#####Laravel
新:6.18.42
旧:5.1.46

#####PHP
新:7.4.11
旧:5.6.30

##ハマった点と解決方法
####Excel::load()の廃止
元々はこんな感じでExcelを読み込んでいました。

~~~test.php
Excel::load('file.xlsx', function ($file) {
  // PHPExcelを使った処理 など
});
~~~

→後述のPHPSpreadsheetの機能で読み込む方法に変更しました。
多分、Excelファイルを読み込んで値を返すだけならLaravelExcelの3以降だとExcel::import()を使用するのがいいと思います。
PHPExcelなどを使ってシート、列、行、セルなどを操作している場合はPHPSpreadsheetを使用する形へ変更した方がいいと思います。
    

####PHPExcelの廃止→PHPSpreadsheetへ移行
PHPExcel自体が非推奨・廃止となり、PHPSpreadsheetの使用を推奨されています。
使用するクラスなどが変更となっています。

ちなみにExcelファイルの読み込みは下記のような形で実装しました。

~~~php

namespace App\Http\Controllers;

use PhpOffice\PhpSpreadsheet\Reader\Xlsx as Reader;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;

class ImportExcelController extends Controller
{

// エクセル読み込み処理
$reader = new Reader();
$sheet = $reader->load('/test.xlsx');

}
~~~

※前述した通り、色々な操作をする場合のExcel::import()での読み込みが上手く構築出来ず…もし何か良い方法などをご存知の方がいらっしゃいましたらご教示くださいますと嬉しいです。

####セルオブジェクトの値取得時、列番号の指定が変更
PHPSpreadsheetへ移行したことでセルオブジェクトにおける列番号の指定が変更になりました。これが地味に混乱させる要因に…

旧処理

~~~test.php
$col = 0; // 列
$row = 0; // 行

// A1のセルオブジェクトを取得
$cell = $sheet->getCellByColumnAndRow($col, $row)->getValue();
~~~


新処理

~~~test.php
$col = 1; // 列
$row = 0; // 行

// A1のセルオブジェクトを取得
$cell = $sheet->getCellByColumnAndRow($col, $row)->getValue();
~~~

旧処理では列はA=0,B=1…と0始まりで指定されますが、新処理ではA=1,B=2…と1始まりに変更になっています。
普段プログラミングからもずれており、ややこしさを感じますね。

##結論
・Excelを使う処理はシンプルであるべき！
特にテンプレートに可変部分を持たせないようにした方がいいですマジで


##参考資料
[Upgrade Guide | Laravel Excel](https://docs.laravel-excel.com/3.1/getting-started/upgrade.html#upgrading-to-3-from-2-1)
[PHPExcel と PhpSpreadsheet の比較](https://knooto.info/php-phpexcel-vs-phpspreadsheet/)
早期リターンすればいいってもんじゃねーぞ！

こういうケースでは早期リターンしないほうがいいかも！って話をさせてください。

# 例

例えば自分の ~~Webサイト~~ ホームページに、アクセス時の処理として以下のような実装をしたとします。

ページ読み込み後にアクセスカウンターを加算し、キリが良ければalertを出す、というものです。

```js
const BBS_URL = 'https://..'
const accessCounter = ..

const onPageLoad = () => {
  accessCounter.increment()
  if (accessCounter.isKiriban) {
    alert('キリ番おめでとうございます！掲示板で報告お願いします！（踏み逃げ禁止）')
    if (location.href !== BBS_URL) {
      location.href = BBS_URL
      // ..
    }
  }
}

window.addEventListener('load', onPageLoad)

// ※ 例なので単純ですが、実際はもっとネストが深かったり、return後の処理が多かったりして、早期リターンしないと辛い状態だと思ってください。
```

これを作った数カ月後、早期リターン病を患った僕はこんな風にリファクタリングしてみることにしました。

```js
const onPageLoad = () => {
  accessCounter.increment()
  if (!accessCounter.isKiriban) return // キリ番じゃなければそれ以上何もしないよ
  alert('キリ番おめでとうございます！掲示板で報告お願いします！（踏み逃げ禁止）')
  if (location.href === BBS_URL) return
  location.href = BBS_URL
  // ..
}
```
大満足。

―――

さらに数カ月後、僕は`alert('相互リンク大募集！')`っていうアラートも表示したくなりました。

ただしこのアラートは、キリ番の処理よりも後に置きたいです。
キリ番が一番大事ですからね。

ではリファクタリング後のコードの、どの位置に新しいalertを記述しましょう？

キリ番のalertより下に配置しようと思いましたが、そこはキリ番だった人しか到達しません。

………。

…リファクタリング後のコードだと、どこに置いてもそれが実現できないことに気づいてしまいました。

ということは、早期リターンとは悪なのでしょうか？ 僕の病気は治るんでしょうか？

## なにが良くなかったか

今回注目するべきなのは、`onPageLoad`という関数の役割です。

これは名前の通り「ページをロードしたときにやるべきことをやる」ための関数です。

つまり、**アクセスカウンターを処理するためだけの関数ではありません**。
元々は、**偶然アクセスカウンターの処理しかやることがなかった**だけです。

にも関わらず、アクセスカウンターの条件次第でこの関数全体を終了させてしまっていたことがよろしくありませんでした。

## 解決案1

ということは、「アクセスカウンターを処理するためだけの関数」を作ってしまえば解決しそうです。

```js
const countupAndNotifyAccessCounter = accessCounter => {
  accessCounter.increment()
  if (!accessCounter.isKiriban) return
  alert('キリ番おめでとうございます！掲示板で報告お願いします！（踏み逃げ禁止）')
  if (location.href === BBS_URL) return
  location.href = BBS_URL
  // ..
}

const onPageLoad = () => {
  countupAndNotifyAccessCounter(accessCounter)

  alert('相互リンク大募集！')
}

window.addEventListener('load', onPageLoad)
```

早期リターン云々抜きにしても、タスクの切り分けができて元より良さそうです。

もしやることが

```js
const onPageLoad = () => {
  countupAndNotifyAccessCounter()
}
```

だけだった場合、不要にラッピングした関数のように見えるかもしれませんが、これはこのままで大丈夫です。

仕様上たまたまそのとき1つしかタスクがないだけですし、
文脈としてもそれぞれの役割に適した名前が付けられることは自然と言えます。

もちろん、新たに追加した2つ目のalertも関数にしてあげてもOKです。

## 解決案2

あるいは、（カウントと通知を一緒にしたくないとかで）ifが残るような場合でも、やはり関数にまとめるなどで、そもそも早期リターンしなくていいくらいに整理してもよさそうです。

```js
const onPageLoad = () => {
  accessCounter.increment()
  if (accessCounter.isKiriban) notifyKiriban()

  alert('相互リンク大募集！')
}
```

# まとめ

- 「やるタスクが多岐にわたる（可能性のある）メソッド」において、あるひとつのタスクの都合次第でreturnしてしまうと後から困るケースがあるので、気をつけましょう。
- 根本的には、そもそもタスクごとに適切に関数を分けられていれば大丈夫だと思います。

という話でした。

---

Vue.jsの`created`（コンポーネント作成時のフック）などがまさに`やるタスクが多岐にわたる`ですが、

```js
created () {
  if (!canXxx) return
  // doXxx
  // ..
}
```

みたいなコードを見て「あっ、あっ、まだ終わらせないで！」ってことがたまにあったので書いてみました。
[Swift]Mintが動かなくて困ったが`~/.git_template/hooks/`のせいでした

### 概要

```
Cloning into 'github.com_yonaskolb_xcodegen'...
Post Checkout
make: *** No rule to make target `project'.  Stop.
🌱 Encountered error during "git clone --depth 1 -b 2.18.0 https://github.com/yonaskolb/xcodegen.git github.com_yonaskolb_xcodegen". Use --verbose to see full output
🌱  Couldn't clone https://github.com/yonaskolb/xcodegen.git 2.18.0
```
というログが出てMintのコマンド(bootstrap, install)が失敗して困っていた。

### 原因

エラーを見ると、「makeコマンド実行してるけどprojectってやつないよ」とのこと。
mintってmakeつかってるんだとか思ってたんですが、
mint内でgit cloneするときに以下のtemplateを参考にしちゃってたので自動でhooksファイルが生成されていた。
`~/.git_template/hooks/`
hooks ファイルにて`make project`を実行していてエラーになり、途中で処理が止まっていた。

### 解決法
`~/.git_template/hooks/`内のファイルを全部消す

### おまけ
Mint関係なかったので調べるの大変でした
Pythonによるrandom変数と条件分岐（Ruby学習後のPython初学）

#Random数

```python:dice.py
import random
number = random.randint(1,6)
print(number)
```

**import random** にてrandomモジュールをインポートする。
そして、変数に **random.randint** か **random.random** で整数のみか少数含むのかを指定し、
()内の変数に範囲を指定する（今回の場合はサイコロと考え、1〜6の範囲の整数）。


#条件式
```python:if.py
if 条件式1:
    条件式1が成り立った時の処理
elif 条件式2:
    条件式2が成り立った時の処理
else :
    条件式が成り立たなかった時の処理 
```
#####**Rubyとの違い**
1.**インデントとして半角スペースを4つあけるのがPythonの特徴
(インデントの位置がずれただけでエラーになる。Rubyの場合は半角スペース2つが基本)**
2.endで閉じることは不要だが条件式の後に**:**をつける
3.**elif（複数条件式）**(Rubyの場合はelsif)
図形を回転する transformRotate

角度と基点を指定して図形を回転させます。

![cap.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8227/b5cc884e-6f58-820e-68c3-f8325afb4405.gif)

- [Rotate features - JSFiddle - Code Playground](https://jsfiddle.net/amay077/qkL3xruv/)

```javascript
let polygon1 = {
  "type": "Feature",
  "properties": {},
  "geometry": {
    "type": "Polygon",
    "coordinates": [
      [
        [ 137.796, 34.940 ],
        [ 137.748, 34.882 ],
        [ 137.887, 34.888 ],
        [ 137.796, 34.940 ]
      ]
    ]
  }
};

const dataSource = {
  'type': 'geojson',
  'data': {
    "type": "FeatureCollection",
    "features": [
      polygon1,
    ]    
  }
};

const bounds = turf.bbox(dataSource.data);

let anchor;

const map = new mapboxgl.Map({
  container: 'map',
  bounds: bounds,
  style: {
    version: 8,
    sources: {
      OSM: {
        type: "raster",
        tiles: [
          "https://a.tile.openstreetmap.org/{z}/{x}/{y}.png",
        ],
        tileSize: 256,
        attribution:
        "OpenStreetMap",
      },
    },
    layers: [{
      id: "BASEMAP",
      type: "raster",
      source: "OSM",
      minzoom: 0,
      maxzoom: 18,
    }],
  },      
});

map.once('load', () => {

  map.fitBounds(bounds, { padding: { bottom: 200, top: 200, right: 200, left: 200 }});

  map.addSource('polygons', dataSource);
  
  map.addLayer({
    'id': 'polygons',
    'type': 'fill',
    'source': 'polygons',
    'paint': {
      'fill-color': '#FF0000',
      'fill-opacity': 0.7
    }
  });

  const center = turf.center(polygon1);
  anchor = new mapboxgl.Marker()
    .setLngLat(center.geometry.coordinates)
    .setDraggable(true)
    .addTo(map);

});

document.getElementById('rotate').addEventListener('click', () => {
  const angle = Number(document.getElementById('dir').value);

  turf.transformRotate(polygon1, angle, { pivot: anchor.getLngLat().toArray(), mutate: true });

  const dataSource = map.getSource('polygons');
  dataSource.setData({
    "type": "FeatureCollection",
    "features": [
      polygon1,
    ]    
  });
});
```

使い方は、``turf.transformRotate(図形, 角度, { pivot: 基点 });`` です。
options に mutate: true を付けると、引数に渡した図形の座標群を入れ替えます。
mutate: false (既定値) の場合は返値に移動した図形を返します。

## 参考

- [transformRotate - Turf.js | Advanced geospatial analysis](https://turfjs.org/docs/#transformRotate)
生誕 11,111 日目を Twitter アカウントでカウントダウンするための Python スクリプト

最近 Tweepy で動かすオモチャの紹介ばかり書いている気がします。私が生誕してからそろそろ 11,111 日を迎えそう（2020/12/09、30歳半ぐらい）、ということで、そのことを忘れないように Twitter アカウント名を毎日更新するために作ったスクリプトの紹介をします。

（ちなみに、生誕 10,000 日記念のときにはこんなことやりました。[生誕1万日記念にポッキー1万本食べようとした話 - note](https://note.com/mkuriki/n/n193f9c5020fb)）

できるものはざっくりこんなイメージです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/331465/af74d744-e935-507c-ad48-12a6600ca938.png)

殆どの内容は拙記事「[Tweepy を使って月齢🌕を Twitter ユーザーネームに反映させる - Qiita](https://qiita.com/mkuriki1990/items/9c78f285a50f14f31a23)」と同じです。`Python` の `datetime` ライブラリを使って生誕日から現在年月日までの日数を計算します。

# 環境
* Python : 3.8.5
* Tweepy : 3.9.0

# 生誕からの日数の計算方法
やっていることはシンプルです。

1. 生誕日 `d_birth` の設定
2. 現在日 `d_today` の取得
3. 現在日と生誕日の差分 `d_from_birth` を計算
4. カウントダウンのための数字 `remain_days` を計算

ソースコードは以下のとおり。

```python
# 誕生日から生誕何日か調べる
# 生誕日と現在日を取得
d_birth = datetime.date(1990, 7, 9)
d_today = datetime.date.today()

# 日時の差を計算
d_from_birth = d_today - d_birth
print(d_from_birth)

# 11111 日までの残り日数
remain_days = 11111 - d_from_birth.days
```

# Twitter アカウント更新
あらかじめ取得した API キーを使って `tweepy` の `update_profile` 関数を使えるようにしておき、適当な形で先程計算した日数を入れます。API の取得、設定方法は [Tweepy を使って月齢🌕を Twitter ユーザーネームに反映させる - Qiita](https://qiita.com/mkuriki1990/items/9c78f285a50f14f31a23) を参考にしてください。

> `API.update_profile([name][, url][, location][, description])`
name – ユーザーネーム（最大 20 文字）
url – アドレス（最大 100 文字、"http://" を省略しても勝手につけられる）
location – 場所（最大 30 文字）
description – 自己紹介（最大 160 文字）

```python
# 表示名を設定
nameStr = "村橋究理基%s北大@生誕%d日目" % (moon, d_from_birth)
profileStr = "名前の%sは今夜の月を表しています。仕組みの説明→https://t.co/ACE6OhPVVz 生誕11111日まで後%d日 北大理学院宇宙理学 博士3+2年 惑星気象/火星大気シミュレーション 3Dプリンタ/恵迪寮寮歌アプリ/高校専修免許(理科)/学芸員/恵迪寮第300期寮長/恵迪寮同窓会理事/愛知県立津島高校出身" % (moon, remain_days)

api.update_profile(name = nameStr, description = profileStr)
```

# おわり
さあ、みなさんも任意の生誕記念日までの日数を意識してみましょう。結構たくさん記念日があるかもしれません。身近な人を適当な理由をつけて祝ってみたいときにぜひ！

ところでこの記事を書いている今日 2020/12/07 は私の生誕 11,109 日目なのですが、まだ 11,111 日記念日に何するか決まってません。結構悩んでいるので、だれか面白い案を教えてください→ https://twitter.com/mkuriki_ 

# 参考資料
* [Pythonのdatetimeで日付や時間と文字列を変換（strftime, strptime）- note.nkmk.me](https://note.nkmk.me/python-datetime-usage/)
WordPressのAll in One SEOパックで指定されたTDKを変更したい！

# 前提
WordPress
All in One SEOパックインストール済み

# 背景
今回関わっている案件で顧客からWordPressの記事サイトのTDKをカスタマイズしたいという要望を受けて対応をしたので、そのあたりについてメモがてらまとめておく
All in One SEOパックを利用しているので、ある程度は設定画面からカスタマイズできるのはこの記事に辿りつくかたならご存知だと思いますが、今回特定のカテゴリのみカスタマイズしたいという要望だったため、設定画面からでの対応では難しく、モジュール側に手を入れる方向で対応を行いました

# 対応内容
結論から言うと専用のfilterがあったので、`functions.php`にそのフィルターを追加する形で対応を行いました。ソースコードは以下

```php:functions.php
/**
 * 一覧のdescription制御
 * @param $description All in One SEOで設定しているdescription
 */
function archive_description_custom($description) {
	if (is_archive()) {
		// 表示中のカテゴリを取得
		$cat = get_term(get_query_var('cat'), 'category');
		// カテゴリの判定ロジック
		if ($cat->slug === 'XXXXXXXX') {
			// ここで変更したい内容のdescriptionを入れる
			$description = "";
		}
	}
	// カスタマイズ後のディスクリプションをreturnする
	return $description;
}
add_filter('aioseop_description', 'archive_description_custom');
```

**aioseop_xxxx**の部分を**title**に変更すればそのままtitleのカスタマイズができます
ネストしたデータ構造をフラットなマップに変換する

別途穴埋め記事を書こうと思いますが、[crux](ネストしたデータ構造をフラットなマップに変換する
)というClojureネイティブなdatalogデータベースシステムがあります。
この記事に関連ある点だけで言うと任意のClojureマップをシリアライズして保存して後からクエリできるのですが、
ネストされたフィールドはインデックスされないためクエリの対象にできない、という特徴があります。

つまり

```clojure
{:foo "bar"
 :bar {:baz "quz"}}
```

という者が保存されていた場合、`:foo`が`"bar"`の値の物を返してくださいというクエリはできますが、`:bar`のように値がプリミティブな値でない場合にはそれに基いたクエリができないというわけです。

ただ、何かしらの手段でネストしたフィールドをこのようにトップレベルに持ってきたマップに変換できれば`:bar.baz`が "quz"のもの、という風に書けてこの弱点を克服できそうです。

```clojure
{:foo "bar"
 :bar.baz "quz"}
```

動機はcruxの特性でしたが、只のアルゴリズムでcrux以外の文脈でも使えるかも、というわけでこれをするライブラリを作って公開しました。

https://github.com/iku000888/map-crusher

実装のつっこみやスターなどお待ちしております。
DjangoのHttp404

##この記事の内容
Djangoでよく見るHttp404を使った例外エラー処理について解説します。


```python:views.py（よく見るエラー処理）
from django.http import Http404
from django.shortcuts import render
from polls.models import Poll

def detail(request, poll_id):
    try:
        p = Poll.objects.get(pk=poll_id)
    except Poll.DoesNotExist:
        raise Http404("Poll does not exist")
    return render(request, 'polls/detail.html', {'poll': p})
```

##Http404は何がイケてるのか
そもそも、raiseは強制的に例外処理を出すためのpythonのメソッドです。
raise Http404では**実際にページが存在するかどうかに関わらず、好きな時に404のエラーを出力することができます。**
例えば以下のようなコードのときは、valueが2の時に404エラーを出し、それ以外の時には適切なルーティングを行うことができます。

```python:views.py
def example(request,value):
    if value == 2;
        raise Http404
    return HttpResponseRedirect(reverse('example'))
```


実際にはこんな使い方はしないと思いますが、

```python:views.py
def example(request,value):
    if request.method == "POST";
        raise Http404
    return HttpResponseRedirect(reverse('example'))
```

とすればPOSTの時だけ404エラーを出すこともできます。


##Http404を使ったエラーページのカスタマイズ

Http404を使ってエラーページをカスタマイズすることもできます。
自分の好きなhtmlファイルを作成し、templatesフォルダの**直下**に"404.html"を配置します。
そして、必ずsettings.pyの中でDEBUG=Falseにします。
（デフォルトではTrueになってます）

```python:settings.py
DEBUG = False
```

もし、カスタマイズしなかった場合は、以下のようにデフォルトの404エラーページを返します。
![Screenshot from 2020-12-07 17-13-57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918692/34a8404e-22f3-7a80-176d-f308cd86a557.png)

また、DEBUG=Trueになっていた場合、通常の404debugページが表示されます。




##参考サイト
Djangoドキュメント
https://docs.djangoproject.com/en/3.1/topics/http/views/
RaspberryPi4とMomoでWebRTCによる映像配信を行う

# この記事の概要

時雨堂が開発されているオープンソースのMomoというソフトウェアで、RaspberryPiからWebRTCによる映像配信をしてみました
https://momo.shiguredo.jp/

一般的なインターネット環境、カメラ・マイクがあれば、簡単にRaspberryPiでスタンドアローンなWebRTCを試すことができます。


# セットアップ

## Raspberry Pi セットアップ

RPiが始めてだったので、とりあえずGUIがほしかったため、RaspbianOSというLinuxベースのOSをインストールしてみました。
WebRTC（Momo）に必須ではありませんが、一応紹介しておきます。

[Raspberry Pi 4にRaspbianの初期設定2020年版](https://raspida.com/setup-raspbian4rpi4b-2020)

## 用意したデバイス

### USBキーボード、USBマウス

セットアップに必要となるため、ロジクールの格安USB（Bluetooh）セットを購入しました。

[ロジクールUSBキーボード＆USBマウス](https://www.amazon.co.jp/gp/product/B01LW8E866/ref=ppx_yo_dt_b_asin_title_o04_s00?ie=UTF8&psc=1)

基本的にUSBをつなぐだけで使えます。

### USBカメラ＆マイク

USBで接続できるカメラならなんでもよいと思いますが、社内にあった以下の会議用USBカメラを接続しました。
マイクもついてるタイプですが、マイクがない場合は別途必要となります。

[ロジクール BCC950](https://www.logicool.co.jp/ja-jp/product/conferencecam-bcc950)

## OSの基本設定

RaspbianOSがインストールされている前提で説明します。
まずはカメラが有効化されていることを確認します。

RaspbianOS / 設定 / Raspberry Pi の設定 / インターフェイス
カメラ：有効

設定を変更し、ターミナルを開いてsupported=1になっていれば有効化されていることが確認できます。

```
$ vcgencmd get_camera 
supported=1 detected=0 
```

## USB接続デバイスの確認

接続されているUSB接続デバイスをの種類を確認します。

```
$ lsusb
```

接続されているデバイスを確認する。

```
$ v4l2-ctl --list-devices 
```


## Momoセットアップ

参考）Momoセットアップ公式ページ
https://github.com/shiguredo/momo/blob/develop/doc/SETUP_RASPBERRY_PI.md

momoのリリースページから対象のライブラリをダウンロードします。
https://github.com/shiguredo/momo/releases

※ Raspberry Pi 4 は ```momo-2020.9_raspberry-pi-os_armv7.tar.gz``` が対象となります。

任意のディレクトリに配置し解凍します。

```
$ tar xfz momo-2020.9_raspberry-pi-os_armv7.tar.gz
```

解凍後の構成は以下の通り。

```
$ tree
.
├── html
│   ├── test.html
│   └── webrtc.js
├── LICENSE
├── momo
└── NOTICE
```

RaspberryPiにパッケージのインストールします。

```
$ sudo apt-get update  
$ sudo apt-get upgrade  
$ sudo apt-get install libnspr4 libnss3  
```

### 映像配信テスト

#### ローカル配信

参考）公式ページ：テストモードを利用して Momo を動かしてみる
https://github.com/shiguredo/momo/blob/develop/doc/USE_TEST.md

解凍後のディレクトリにmomoの実行バイナリがあるのでローカルでテストをします。
以下を実行すると、ローカルネットワークで配信します。
（音の配信はありません。後述する方法でマイクの設定が必要です）

```
$ ./momo --no-audio-device test
```

自分のIPアドレスを調べます。

```
$ ifconfig
```

仮にIPが「192.168.1.28」だった場合、同じローカルネットワーク環境にてブラウザで```http://192.168.1.28:8080/html/test.html```とアクセスし、表示されれば成功です。


#### AYAME配信

公式ドキュメント
https://github.com/shiguredo/momo/blob/develop/doc/USE_AYAME.md

ローカルネットワークではなく、インターネット環境で配信テストをしてみたい場合は、時雨堂が提供するAYAMEというサーバーがあるのでそちらで試すこともできます。

## マイク接続

RaspberryPiにはデフォルトでマイクがなく、USBマイクを接続し利用するには、初期設定する必要があります。
USBマイクをRaspberryPiに接続し、以下コマンドでマイクのUSB接続がされているか確認してください。

```
$ lsusb
```

マイクの接続優先度を確認します。

```
$ cat /proc/asound/modules
 0 snd_bcm2835
 1 snd_bcm2835
 2 snd_usb_audio
```

USBマイクの優先度が低いため、自動的に接続されません。
nano（vimのようなエディタ）を使って設定ファイルを新規作成します。

```
$ sudo nano /etc/modprobe.d/alsa-base.conf
```

以下を入力して保存します。  

```
options snd slots=snd_audio,snd_bcm2835
options snd_usb_audio index=0
options snd_bcm2835 index=1
```

設定ができたら、端末を再起動します。

```
$ reboot
```

再起動後、以下のように優先度が変われば成功です。

```
$ cat /proc/asound/modules
 0 snd_usb_audio
 1 snd_bcm2835
 2 snd_bcm2835
```

audioオフのオプションを削除してMomoを起動します。

```
$ ./momo test
```

視聴側で音が配信されていれば成功です。
LINE WORKSとfreee勤怠botをつなげてみた

# はじめに

この度はじめてAdvent Calendarにお誘いいただきました、smooth合同会社です。
早いもので今年も残すところあとわずか、リモートワークなど働き方が大きく変わった一年でした。

そんな中、どこからでも気軽に出勤と退勤の打刻ができるfreeeアプリを11月にリリースしました。
その名も「LINE WORKS ×freee 勤怠bot」です。
LINE WORKSから人事労務freeeに勤怠打刻ができます。

# 利用例

いつも使っているLINE WORKSから勤怠打刻ができるため、営業先・現場への直行直帰時でも簡単に打刻できます。

例：ゴトウ ススムさん（仮名）は、今日は勤務先に立ち寄らず営業先に直行直帰です。

### 出勤時

ゴトウ「スマホのLINEWORKSをひらいて、勤怠登録Botをえらんで、出勤をタップ！」
![syukkinn.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/913847/50c12017-73ce-ca97-a577-d124594389fc.png)
ゴトウ「打刻ヨシ！ 今日の商談の確認をしておこう」


### 退勤時

ゴトウ「スマホのLINEWORKSをひらいて、勤怠登録Botをえらんで、退勤をタップ！」
![taikinn.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/913847/4df6d799-7a44-cb55-7de7-33e81ae9a7eb.png)
ゴトウ「打刻ヨシ！  晩ご飯は何にしよう」

# 連携方法

利用例では、勤怠打刻をする様子をご説明しました。
ゴトウさんのような利用者が簡単に打刻をできるように、LINEWORKSの管理者は初期設定をする必要があります。

### 管理者の設定

1. freeeのアプリストアから、LINEWORKSとの連携を開始します。
![freee_app_store.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/913847/ae12bab4-6c9c-c4f1-b3bb-2083fc635d07.jpeg)

2. 「LINEWORKS Developer Console」から各種IDをコピーします。
![dev_console.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/913847/aa93c897-c048-8041-40c4-748ac2e19a5a.jpeg)
![dev_console2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/913847/809daeb7-6331-8ff9-7665-1a14b199ce09.jpeg)

3. 「LINEWORKS-freee連携設定」に各種IDを貼り付けます。
![rennkei.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/913847/5a72229c-7ba7-e52e-7200-e57e664e7642.jpeg)
![rennkei2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/913847/5ccbd594-25bc-afda-3c11-6cf8ecfeccbc.jpeg)

以上がLINEWORKSの管理者側の初期設定です。

### 利用者の設定

次に、利用者は勤怠登録BotをLINEWORKSに追加します。

1. トークルームを作成する画面で「勤怠登録Bot」を招待します。
![user.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/913847/1dd363b8-dc15-aaef-dfec-9b85db931a5d.jpeg)


2. 勤怠登録Botのメッセージからfreeeにログインします。
![user2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/913847/73263d2f-f206-9abd-a4d9-6aff04108d4e.jpeg)
![user3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/913847/09365fcf-de5e-7b52-a190-f3e7df08b349.jpeg)

以上がLINEWORKSの利用者側の初期設定です。


# おわりに

LINE WORKSと人事労務freeeを連携するためのアプリ「LINE WORKS ×freee勤怠bot」は、freeeアプリストアより無料でご利用いただけます。

気になった方はぜひ一度試してみてください。

[![freee_app_store link.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/913847/134f3560-4a68-195b-90c1-384dafab4a18.jpeg)
「LINE WORKS ×freee 勤怠bot」アプリ詳細ページ](https://app.secure.freee.co.jp/applications/8762)
Ruby で解く AtCoder ABC057 C 動的計画法

# はじめに
*[AtCoder Problems](https://kenkoooo.com/atcoder/#/)* の Recommendation を利用して、過去の問題を解いています。
AtCoder さん、AtCoder Problems さん、ありがとうございます。

# 今回のお題
*[AtCoder Beginner Contest C - Digits in Multiplication](https://atcoder.jp/contests/abc057/tasks/abc057_c)*
<font color="green">Difficulty: 904</font>

今回のテーマ、動的計画法

この問題は、以前に [Ruby と Python で解く AtCoder ABC057 C 素因数分解 ビット全探索](https://qiita.com/superrino130/items/10213645bb4ff63a6ac7) で解いております。

今回、動的計画法で解くことにより、実行時間が大幅に縮小したので投稿します。
# ビット全検索
```ruby.rb
require 'prime'

n = gets.to_i
h = n.prime_division
p = []
h.each do |k, v|
  v.times do
    p << k
  end
end
min = Float::INFINITY
0.upto(2**p.size - 1) do |bit|
  a = 1
  p.size.times do |i|
    a *= p[i] if bit[i].zero?
  end
  min = [a, n / a].max if min > [a, n / a].max
end
puts min.to_s.size
```
```bit.rb
0.upto(2**p.size - 1) do |bit|
  # 処理
end
```
ここが、ビット全検索の部分になります。
# 動的計画法
```ruby.rb
require 'prime'

n = gets.to_i
if n == 1
  puts 1
  exit
end
p = n.prime_division
dp = Hash.new(0)
dp[1] = 1
min = Float::INFINITY
p.each do |k, v|
  v.times do
    dp.keys.each do |u|
      dp[k * u] = 1
      tmin = [(k * u).to_s.size, (n / (k * u)).to_s.size].max
      min = tmin if min > tmin
    end
  end
end
puts min
```
動的計画法の処理内容については、[Ruby の Hash における keys.each と each_key の違い](https://qiita.com/superrino130/items/965ac708eb2d48f47952) を参照願います。

||ビット全検索|動的計画法|
|:--:|:--:|:--:|
|コード長 (Byte)|318|344|
|実行時間 (ms)|1504|69|
|メモリ (KB)|14416|14468|
実行時間が`1504`->`69`と、大幅に縮小。
# どうして早いのか
`ビット全検索`の場合、その都度計算される（上記ソースですと乗算）

|1|=|1|
|:--|:--:|--:|
|1 * 2|=|2|
|1 * 2 * 3|=|6|
|1 * 2 * 3 * 5|=|30|
`動的計画法`の場合、前回の計算結果を使用する

|1|=|1|
|:--|:--:|--:|
|1 * 2|=|2|
|2 * 3|=|6|
|6 * 5|=|30|
よって、計算コストが低くなります。
# まとめ
+ ABC 057 C を解いた
+ Ruby に詳しくなった
デフォルトブランチに main を採用していないリポジトリでも main として扱う方法

色々なリポジトリで作業していると、 main やら master とかデフォルトブランチが異なって、git コマンドが不発する場合がある. 自分はコマンドが不発することがあってボヤいていたら `git-symbolic-ref` を教えてもらった.



```sh
git symbolic-ref main master
```

上記のコマンドを実行すると `.git/main` ができて内容が `ref: master` のファイルができます.

同様に `origin` にも同じ設定をします.

```sh
git symbolic-ref refs/remotes/origin/main refs/remotes/origin/master
```


これで デフォルトブランチが `master` でも `git merge main` とか `git merge origin/main` ができます :tada: 

### 参考
- [git symbolic-ref を利用して、ブランチに対して別名をつけることができて墓ドル - ( ꒪⌓꒪) ゆるよろ日記](https://yuroyoro.hatenablog.com/entry/2013/03/08/132842)
- [Git - Gitの参照](https://git-scm.com/book/ja/v2/Git%E3%81%AE%E5%86%85%E5%81%B4-Git%E3%81%AE%E5%8F%82%E7%85%A7)
- [gitで warning: ignoring broken ref refs/remotes/origin/HEAD ってエラーが出た時の対処法 - Qiita](https://qiita.com/Kazuhiro23/items/c64e0a7b75da7767d684)
プログラミング用語辞典

##インスタンス
インスタンスという言葉と一緒に
・クラス
・オブジェクト
の二つも出てくる

それぞれの意味は
クラス・・・設計図
インスタンス・・・設計図から実際に作ったもの
オブジェクト・・・クラスとかインスタンスをふんわりさせたもの

インスタンス化＝new演算子で「newする」とも言う
インスタンス化＝実際にものをつくる

##メソッド
メソッドとはプロパティに入っている関数の事である

```js
var sumple {
  プロパティ : 値,
  プロパティ : 関数  ←これがメソッド
```

##スコープとは
スコープとは、変数の名前や関数などを参照できる範囲のこと
**JavaScriptでは、変数や関数などにアクセスできる範囲が決まっている**

```js
function fn() {
    const x = 1;
    // fn関数のスコープ内から`x`は参照できる
    console.log(x); // => 1
}
fn();
// fn関数のスコープ外から`x`は参照できないためエラー
console.log(x); // => ReferenceError: x is not defined
```
仮引数も同じで関数の中では参照可能だが関数の外からは参照できない。


このスコープという言葉は
・グローバルスコープ
・ローカルスコープ
という形でよく見かける

これらの意味は
グローバルスコープは名前の通り最も外側にあるスコープである
だから「JavaScriptのどこからでもアクセスできて全部の範囲が有効」
グローバルスコープで定義した変数はグローバル変数と呼ばれる



ローカルスコープは更に2種類あり、「関数スコープ」「ブロックスコープ」と言うモノがある。

####関数スコープ
関数スコープとは上にあげた物も関数スコープである。
```let```や```const```は同じスコープ内に同じ名前の変数を二重に出来ないが、これは各スコープで同じ名前の変数は一つしか宣言できないからである。
```js
let toaru;
let toaru;
//SyntaxErrorと表記される
```
だがスコープが異なれば同じ名前で変数を宣言できる

####ブロックスコープ
ブロックスコープとは{~~~}で囲んだ範囲の事である
関数スコープと同じようにブロック内で宣言した変数はスコープ内でしか参照できない。

if文やwhile文でもブロックスコープを作るが、これも同じように外側からは参照することは出来ないのである。

≻https://jsprimer.net/basic/function-scope/

##仮引数(別名パラメーター)

```js
function 関数名(仮引数1, 仮引数2, ...){
  実行される処理1;
  実行される処理2;
  ...
  return 戻り値;
}
```
仮引数には変数が入る
もし引数を指定せず関数が呼び出されたら```undefined```がになるが、仮引数を設定しておけば、その値を代入してくれる。
>https://www.javadrive.jp/javascript/function/index3.html
図形を移動する transformTranslate

距離と方向を指定して図形を移動します。

![cap.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8227/3e5bacea-adaf-2640-1ec7-be68719a2d6f.gif)

- [Translate features - JSFiddle - Code Playground](https://jsfiddle.net/amay077/m9arfnz8/2/)

```javascript
let polygon1 = {
  "type": "Feature",
  "properties": {},
  "geometry": {
    "type": "Polygon",
    "coordinates": [
      [
        [ 137.796, 34.940 ],
        [ 137.748, 34.882 ],
        [ 137.887, 34.888 ],
        [ 137.796, 34.940 ]
      ]
    ]
  }
};

const dataSource = {
  'type': 'geojson',
  'data': {
    "type": "FeatureCollection",
    "features": [
      polygon1,
    ]    
  }
};

const bounds = turf.bbox(dataSource.data);

const map = new mapboxgl.Map({
  container: 'map',
  bounds: bounds,
  style: {
    version: 8,
    sources: {
      OSM: {
        type: "raster",
        tiles: [
          "https://a.tile.openstreetmap.org/{z}/{x}/{y}.png",
        ],
        tileSize: 256,
        attribution:
        "OpenStreetMap",
      },
    },
    layers: [{
      id: "BASEMAP",
      type: "raster",
      source: "OSM",
      minzoom: 0,
      maxzoom: 18,
    }],
  },      
});

map.once('load', () => {

  map.fitBounds(bounds, { padding: { bottom: 200, top: 200, right: 200, left: 200 }});

  map.addSource('polygons', dataSource);
  
  map.addLayer({
    'id': 'polygons',
    'type': 'fill',
    'source': 'polygons',
    'paint': {
      'fill-color': '#088',
      'fill-opacity': 0.8      
    }
  });
  
});

document.getElementById('translate').addEventListener('click', () => {
  const distance = Number(document.getElementById('dist').value);
  const direction = Number(document.getElementById('dir').value);

  turf.transformTranslate(polygon1, distance, direction, { units: 'meters', mutate: true });

  const dataSource = map.getSource('polygons');
  dataSource.setData({
    "type": "FeatureCollection",
    "features": [
      polygon1,
    ]    
  });
});
```

使い方は ``turf.transformTranslate(図形, 距離, 方向, { 距離の単位、など })`` です。
方向は北を0として時計回りに360までの度です。
options に ``mutate: true`` を付けると、引数に渡した図形の座標群を入れ替えます。
``mutate: false`` (既定値) の場合は返値に移動した図形を返します。