OmniAICreator/Qiita-1.07M huggingface dataset:
Flutter for webでFlashプロダクトを置き換えた話

# はじめに

Flashのサポートが2020年12月31日で終わってしまいます。
私が所属する企業のアプリはマルチデバイス対応がウリで、Web版はFlashで作られていました。
もともとのチームは10名（パートナー含めると倍近く）くらいいましたが、今は私とパートナーさんの2名。
少ないリソースでやりきらないといけない。
というところで、白羽の矢が立ったのがFlutter for Webでした。

## どんなプロダクト？

電子書籍ビューアです。
よくある漫画ビューアのような難読化(パズルみたいに画像をバラバラにするもの)ではなく、暗号化と復号処理をするものです。これ以上は細かく言えませんが、セキュリティに少し配慮したものになってます。

# 移行開始

オリジナルのFlashのコードは存在するものの、当時流行ってたオフショア開発だったのでコメントが壊滅的でした。日本語がよくわからないのはいいとして、英語のコメントもなし。幸い、Javaのサンプルがあったのでそちらを参考にしました。

## ハマったポイント

### バイナリデータの値

復号処理をビューア側でしないといけないのですが、そもそも転送されてきたデータがなにか違う。
ここでのハマりポイントは、DartのUint8List型とJavaのbyte[]型のintの範囲が異なっていたことでした。
なので、最初は復号処理がおかしいんじゃないかとロジックを見直して無駄に時間を浪費してしまいました。
具体的にはDartは0〜255、Javaは-127〜128となっています。なので、128までは問題ないのですが130となるとJava側では-2となり意味が分かりませんでした。
その他のデータ型に関しては下記URLを参考にして実装しました。

https://flutter.dev/docs/development/platform-integration/platform-channels#codec

### HTTPリクエスト

FlutterでHTTPリクエストを実行するにはdart:ioとdart:htmlがあって、前者はモバイルなどネイティブアプリから利用できます。後者はWebで利用できます。しかしどちらか一方しか使えないという制約があるので、ラッパーライブラリのhttp.dartを利用しました。
WebサーバにはContent-Type: x-www-form-urlencodedでリクエストをPOSTすればいいのであまり気にしていなかったのですが、JSONをPOSTするとエラーになってしまいました。

~~リクエストヘッダにapplication/jsonを設定したのにおかしいなと思って調べたところ、Web版はContent-Typeを設定することができないそうです。
仕方ないのでサーバ側の受け取りをx-www-form-unlencodedに実装を変更して対応しました。
同様のdio.dartでも上手く動かないのでdart:jsで自力で実装しないといけないのかな？
まだ未検証なのでそのうち試してみます。~~

下記に同様の処理をされている人がいました。POSTするbodyをMapからエンコードしたJSONに指定するとContent-Typeがaplication/jsonに上書きできるそうです。

```Dart:動いたコード
import 'dart:convert';
import 'package:http.dart' as http;

Future<void> postData(var body) async {
    var body = {'id': 'a001', 'date': '2020/12/15 00:00:00'};
    var response = await http.post(url,
        headers: {
          HttpHeaders.contentTypeHeader: 'application/json',
          HttpHeaders.acceptHeader: 'application/json',
        },
        body: json.encode(body));
} 
```

参考
https://ttydev.com/2020/07/13/flutter-content-type-error/


```Dart:動かなかったコード
import 'package:http.dart' as http;

Future<void> postData(var body) async {
    var body = {'id': 'a001', 'date': '2020/12/15 00:00:00'};
    var headers = {'Content-Type': 'application/json'};
    var response = await http.post('https:/domain/endpoint', headers=headers, body=body);
} 
```

### 文字列定数が丸見え

DratからJavaScriptにトランスパイラされる為、文字列定数が丸見えになっていました。
URL等は見えてしまっても問題ないのですが、復号処理に使う値が見えるのは流石にまずいので、難読化することで対応しました。
パフォーマンスのこともあるのでそこまで複雑なことはしてませんが、パッと見ではわからなくなりました。

## やってよかったこと

### テストファースト

ユニットテストを積み上げて手戻りがないように最初に動けたのがよかったです。
Javaでお世話になったmockitoがDartでもそのまま使えたのが大きいと感じています。
また、ユニットテストはxUnitなのでこちらも違和感なくテストを記述できました。
テストについては下記URLを読んで取り組めばいいと思います。プロジェクトにもよりますが、ユニットテストはやっといて損はないかと思いました。
https://flutter.dev/docs/testing

### UIとビジネスロジックの分離

既存のコードはMVCパターンで書かれてましたが、名ばかりMVCでした。
今回はMVCに分離することを頑張ったおかげで責任の範囲が限定されて見通しがよくなり、カオスになることを避けれたように思います。

# おわりに

FlutterのAdvent CalendarなのにほとんどDartの話になってしまいました。私の担当範囲が通信とかデータの保持、込み入った処理が中心だったためなので仕方ないなと思う事にします。
Flutterでは描画コストの見直し以外は特に困ったことはありませんでした。それくらいサクサクとUIを構築できました。
そのおかげでFlash版で提供していたプロダクトをひとまず置き換えることに成功したと言えるかなと思います。

会社のことなので書けない事が多くなりましたが、同じように悩んでる人の助けになれば幸いです。
他にも思い出したらまた追記します。
Google Cloud アップデート (11/27-12/3 2020)

### Config Connector: [Nov 29, 2020](https://cloud.google.com/config-connector/docs/release-notes#November_29_2020)
- 1.31.1がリリースされたよ！
- バグ修正と改善

### Anthos on bare metal: [Nov 30, 2020](https://cloud.google.com/release-notes#November_30_2020)
- GAに！
    - OSは自分で用意する。CentOS8.1/8.2, RHEL8.1/8.2, Ubuntu18.04/20.04が対応
    - サブスクかPAYG[プライシング](https://cloud.google.com/anthos/pricing)
    - デプロイがスタンドアローンとマルチクラスタが存在。(前者はエッジ向き、後者はこれまでのAnthosと似た感じ?)

### Security Command Center: [Dec 1, 2020](https://cloud.google.com/security-command-center/docs/release-notes#December_01_2020)
- プレミアムに含まれる、GKE上のコンテナの脆弱性スキャンをしてくれる[Container Threat Detection](https://cloud.google.com/security-command-center/docs/concepts-container-threat-detection-overview)がGAになったよ！
    - GKEのStableチャネルをサポート
    - 新しいクラスタ追加時のレイテンシが改善
    - その他修正

### Config Connector: [Dec 1, 2020](https://cloud.google.com/config-connector/docs/release-notes#December_01_2020)
- 1.32.0リリース！
- 複数の修正と改善。

### ディスクレーマ
- アップデートの内容はあくまでも個人の理解していることを書いています。正しい内容はリリースノート等を確認下さい。
- リリース内容できるだけ拾うようにしているのですが、抜けていそうなリリースノートが追加するのでぜひ教えて下さい！(一覧[ここ](https://qiita.com/kenzkenz/items/ac18a359b803dbb6b490)で更新してます。)
【GAS】メールに含まれるURL先の更新を自動で確認

#モチベーション
2020年一番お世話になったGASを利用したWebモニター・Webチェッカーです．
Webページの更新を毎週見に行くのが苦痛だったので作りました．
同様のサービスは色々ありますが，広告が入ってたり，PCしか対応していなかったり，追加削除にはホームページに行く必要があったり，だったらGoogle Apps Script(GAS)で作ろうということにしました．
GASなら数十行でGmailをUIとしたWebチェッカーが作れます！
###仕様
このプログラムはスターされたメールに含まれるURLの更新を定期的に確認します．
Gmail側のスターを解除すると更新確認もやめます．

UIはGmail．Gmailが使えればURLの追加や削除ができるのでPC,スマホ，iPhoneでも使えます．
自分自身ににURLの入ったをメールしてスターしておくことで特定のURLに対してもWebチェッカーとして利用できます．


#プログラム

```javascript
//プログラムを動作させるために15分に1回実行などの設定を行ってください

var myEmailAddress = 'メール@address.com'
//本体　
function webMonitor() {
//メールから検索,メールの文書をすべて結合，そこから正規表現でURLを配列で取得
  const Emails = getEmailsBySearch('is:starred');
  const concatedMail = Emails.reduce(function(pre, cur) {
    return pre + ' ' + cur.getPlainBody() 
  },'');
  const urls = concatedMail.match(/(http(s)?:\/\/[-_.!~*\'()a-zA-Z0-9;\/?:\@&=+\$,%#]+)/gi);

//URLのアップデート確認，更新されたものはメールで知らせる．
  urls.map(isUpdatedURL).removeNull().map(sendURLByEmail);
}

//更新確認関数,入力はURL，返り値は更新された場合URL，されてない場合null
function isUpdatedURL(url) {
  const html = fetchHtmlByUrl(url);
  //文字列変換後，ヘッダなどの見えない部分の削除
  const htmlBody = JSON.stringify(html)
  .replace(/<head>[\S|\s]*?<\/head>/gi,'')
  .replace(/<script[^>]+?\/>|<script(.|\s)*?\/script>/gi, '')
  .replace(/(<|{)("[^"]*"|'[^']*'|[^'">])*(>|})/g,'')
  .replace(/\s|\\r|\\n|\\t/g, "");
 
  //HTML文字列の保存．GASのキャッシュ機能．3600秒間保存する．
  const catche = CacheService.getScriptCache();
  const beforeHtmlBody = catche.get(url);
  catche.put(url, htmlBody, 3600);
  //前と変わってないまたは初めての確認時はNULLを返す．更新されてたらURLを返す.
  return (beforeHtmlBody == htmlBody || beforeHtmlBody == null) ? null : url;
}

function sendURLByEmail(url) {
  return GmailApp.sendEmail(myEmailAddress, '【update】' + getDomainByURL(url), url);
}

//プロトタイプに直接書くのは行儀が悪いかもしれない．
Array.prototype.removeNull = function(){
  return this.filter(function(x) {
    return x != null;
  });
}

function getDomainByURL(url) {
  return url.match(/^https?:\/{2,}(.*?)(?:\/|\?|#|$)/)[1];
}
```
＊注意事項
プログラムはHTMLを見てるだけなのでJavascriptで描画される部分やユーザ認証が必要なところでは機能しません．
Webページの応答が長すぎる，HTMLに現在時刻が埋め込まれているなどのエラー処理，例外処理は面倒なのでやってません．
文字列にしてからHTMLのタグを消してる都合上<このような文字列>は消されてしまいます．

#最後に
GoogleフォームをUIにしたり，Chrome拡張機能で部分的に選択してAPIで動作させてみたかったですがそこまでできませんでした．（Chrome拡張機能からGASのAPIにあくせすできるのかな？）できるみたいですね．
https://qiita.com/sakaimo/items/3ee8feaf692d5e7455bb
強制ダークモード

画面を強制的にダークモードにしたい場合
iOS13以降のみ ViewController 内でこうする

```swift
    override func viewDidLoad() {
        super.viewDidLoad()
        if #available(iOS 13.0, *) {
            overrideUserInterfaceStyle = .dark
        } else {
            // Fallback on earlier versions
        }
    }
```
ssh接続するための準備 公開鍵 秘密鍵

## 必要な手順

クライアント側

- 公開鍵と秘密鍵の作成

リモート側

- クライアントから指定してくるユーザの**~/.ssh/authorized_keys**に、ssh接続するユーザの**公開鍵を登録**
- devサーバのsampleユーザからprdサーバのrootユーザでsshする場合、sampleユーザの公開鍵をrootユーザのauthorized_keysに登録

両方にやること

- 適切なパーミッションの設定
- 適切な所有者、グループの設定


あいまいな点
・~/.ssh/known_hostsの設定
・~/.ssh/configの設定
まだDrawerのハンバーガーメニュー自分で書いてんの？

# お断り

煽り気味なタイトルは嫌いなのですが本日とてもおもしろいことを知ったので勢いのままに書きます。

# まえがき

React Nativeで画面遷移を行う際にデファクトスタンダードとして使われるReact Navigation。その中のDrawer navigationを使う場合、ハンバーガーメニューはStack Navigationと組み合わせて実装するというのが常識で**した**。

React Navigation自体最近v5が出て書き方ががっつり変わっているのですが、[先人が書かれたv4までの知見](https://qiita.com/zaburo/items/aaf198c79520dbaa48e2)を参考に「えー、こんな典型的な機能用意しといてよー」とぶーたれながら「引数のコンポーネント（画面）をハンバーガーメニュー付きStackNavigatorでラップしたコンポーネントを返す関数」を書き、さてこの高階関数どう説明しようかと悩んでいたところ、

# 本題

ちょっと改めて本家のAPIドキュメントを見てみました。
https://reactnavigation.org/docs/drawer-navigator#options

> title
Generic title that can be used as a fallback for headerTitle and drawerLabel

あれ？headerTitleってどういうこと(。´･ω･)?

> headerShown
Whether to show or hide the header for the screen. The header is not shown by default. Setting this to true shows the header.

え？まさか

```js
// https://reactnavigation.org/docs/drawer-based-navigationのサンプルコードです
export default function App() {
  return (
    <NavigationContainer>
      <Drawer.Navigator initialRouteName="Home"
        // ↓これだけ追加
        screenOptions={{
          headerShown: true
        }}
      >
        <Drawer.Screen name="Home" component={HomeScreen} />
        <Drawer.Screen name="Notifications" component={NotificationsScreen} />
      </Drawer.Navigator>
    </NavigationContainer>
  );
}
```

![react-navigation-drawer-header.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141091/f88525d4-162d-2e9a-f80d-db2e0e359ab1.jpeg)

( ﾟДﾟ)
ハンバーガーメニュー！お前ハンバーガーメニューじゃないか！元気だったか？少し痩せたか？（錯乱）

# 説明

`headerShown`についての説明記事がないのも無理はない。
`headerShown`は[2020/11/10に実装された](https://github.com/react-navigation/react-navigation/commit/dbe961ba5bb243e8da4d889c3c7dd6ed1de287c4)ばかりなのだ。

超意訳：StackNavigator使えって言ってたけどまあいろいろ問題あるしヘッダ実装したわ。

# まとめ

`headerShown`は`@react-navigation/drawer@5.11.0`から使えるようになっています。最新のバージョンに上げられる人は`headerShown`を使いましょう。StackNavigatorと同じヘッダのカスタマイズもできるよ。試してないけど。
Strapiの環境設定

こんにちは。株式会社dottの齊藤です。

Strapi Advent Calenderの4日目の本日は、Strapiの環境設定についてお話します。

Strapiの概要やクイックスタートはとは前日の記事をどうぞ。
[HeadlessCMS Strapiの使いどころ](https://bit.ly/2L24urc)
[Strapi Quick Start Guide 日本語訳](https://bit.ly/3qmX7uq)


StrapiをCloud SQLに接続する場合、デプロイ時とローカル起動時とで設定値が異なるため、先に環境設定をしておくと楽になります。
ちなみに、Cloud SQLを利用するのであれば、Cloud Runを使って運用するのがおすすめです。
[StrapiをCloud Runで運用している話](https://bit.ly/37yZRMI)



# 環境設定の手順
StrapiはNODE_ENVという環境変数によって環境ごとの設定を読み込むことができます。

1. Strapiプロジェクトの./configにenvフォルダを作成

2. envの中にdevelopフォルダを作成
    StrapiのNODE_ENVのデフォルト値がdevelopなので、この中にはローカル起動用のDBやプラグインの設定を入れていきます。

3. 場合に応じてenvの中にdevelop、staging、productionなどのフォルダを作成し、それぞれの環境用の設定ファイルを入れる

4. app.yamlファイルでNODE_ENVを指定してデプロイ

ex) stagingにデプロイするとき

```yaml:app.yaml
runtime: nodejs10

instance_class: F2

env_variables:
  HOST: "0.0.0.0"
  NODE_ENV: "staging" <= ここ変える
  DATABASE_USERNAME: "<DATABASE_USERNAME>"
  DATABASE_PASSWORD: "<DATABASE_PASSWORD>"
  INSTANCE_CONNECTION_NAME: "<INSTANCE_CONNECTION_NAME>"
```
スナック「Flash」

　……あら、嬉しいわね。来てくれたのね。
　……そうなのよ。この店も、今年いっぱいで閉める事になってね。もう20年以上も続いてたんだけどねえ。その間、ずっとひいきにしてくれたわねえ。ありがとうね。
　さあ、入って入って。今日は他にお客さんもいないし、あたしの昔話に付き合ってくれるかしら？
　あ、入る時はそこの「許可」ボタンを押して入ってきてね。ごめんね。面倒な世の中になっちゃったけど、これも時代の流れなのよねえ。

## 1996 - 1999

　さて……この店が生まれたのが、えーと、1996年か。もう前世紀の話になるのね。
　当時のインターネット環境って、もちろんブロードバンド回線なんて普及してなかった頃だから、今では考えられないくらい通信速度が遅かったんだよねえ。当然サイトのコンテンツはテキストが中心で。画像を使う時はとても気を使ってねえ。極限までサイズを小さくなるようにとか、同じ素材を使いまわしてとか、涙ぐましい努力をしてたわけ。
　そんな時代だから、動画をページに埋め込むなんてほぼ不可能だったんだよね。何時間もかけてダウンロードしたものをあとで見るとか、そういう時代だったわけ。

　そんな頃に颯爽とオープンしたのが、この店ってわけ。
　ウチの店の一番の特長は、ベクター形式のアニメーションを採用したことだよね。
　アニメーションって、言ってみれば、画像を連続で表示するパラパラ漫画なわけよ。だから、一枚一枚の画像がキレイになればなるほど、枚数が増えれば増えるほど、ファイルサイズが膨れ上がるんだよね。
　だけど、ベクター形式の画像って、線や図形の座標とか、そういう数値だけで表現できるわけ。だから、ファイルサイズも小さいし、拡大してもキレイなままなの。当時のネット環境にピッタリだったんだよね。
　それから、忘れちゃいけないのが『モーショントゥイーン』っていう機能よね。知ってる？
　たとえば、こうやってカウンターの端っこにグラスを置くじゃない？　で、1秒後のフレームに、あなたの前にグラスを置くわけよ。これをムービーにすると、こうサーっと、グラスが滑っていくように見えるわけ。途中のフレームを自動で補完してくれるんだよね。この手軽さがウケて、じわじわと人気が出ていったの。

## 2000 - 2003

　2000年くらいになると、この業界の第一人者だと自信持って言えるようになったわねえ。Webアニメーションといえばウチだ、って。
　この店も一気に賑やかになったよねえ。覚えてる？　「職人」と呼ばれる人たちが夜な夜な集まってさ、パーティーなんて開いたりしてね。懐かしいわねえ。
　今思い出すと、あの頃が一番輝いてたかもね。華やかなステージの上で、いろんな人にモーションかけられたりしてね。目を閉じると、たくさんのムービークリップが浮かんでくるわ。

## 2004 - 2009

　さて……今になって振り返ると、2004年の思い切った業務拡大がさ、一番のターニングポイントだったわよねえ。良くも悪くも。

　一つ目が、本格的なオブジェクト指向言語を搭載したこと。
　元々「ActionScript」っていう簡易的なスクリプト言語を搭載してて、フレームを進めたり、キャラクターを動かしたりっていう簡単な操作はスクリプトから実行できたんだけどね。それを、ECMAScript準拠の、本格的なクラスベースのオブジェクト指向言語へと進化させたんだよね。……急に難しい話になったけど、大丈夫？　あたしもよくわかってないけど。
　これによって、多くのプログラマー達を取り込むことに成功した。アニメーションを再生するだけでなく、ネットゲームといったWebアプリケーションのプラットフォームへと変革を遂げたんだよねえ。

　もう一つが、動画配信への参入だよね。
　当時の動画配信のプラットフォームって、Windows Media PlayerさんやQuickTimeさん、あとはRealPlayerさんとかがしのぎを削ってたのよね。
　そこに、うちの店がどーんと参入した。プラグインの普及度を生かしてさ。YouTubeさんとかニコニコ動画さんとも提携して、一気にシェアを占めたんだよね。
　
　こんな感じでさ、いろんな分野に手を広げてさ。そのおかげで店は一気に大きくなったけど、同時にいろんな物を背負い込んじゃった。簡単にアニメーションを表示できるっていう、最初のころの思想をさ。ひょっとしたら、どこかに置き去りにしちゃったのかもしれないね。

　……あ、水割り、おかわりする？　じゃあ、一緒にMcAfee Security Scanはどう？　……いらない？　ああ、そう。

## 2010 - 2019

　この頃から、世間の風当たりが強くなってきたのよねえ……
　まずね、一番の繁華街で営業が出来なくなっちゃってね。そう、あのシンクディファレントなところ。やれ電力消費が激しいだの、ブラウザがクラッシュするだの、色々言われてね。追い出されちゃった。
　続けざまに、セキュリティ上の問題点が次から次へと見つかってねえ……ひたすら対応に追われてばかりだった。そうこうしているうちに、バッシングの声がどんどん強くなってきてね。あれだけ各所に出してた店が、バタバタと閉まっていったよね。あの時は、本当淋しかったわ。

　あとは、HTML5が登場し、JavaScriptも大幅に進化して、動画やゲームがWebブラウザだけで実行できるようになった。そう、あたしがいなくても十分素敵なものが作れるようになったんだよね。ああ、あたしの役目は終わったんだな、そろそろ潮時なのかな……なんて、あなたに愚痴ったりもしてたよね。

　でもさ、あたしたちのやってきた事は、今のWeb業界に確実に受け継がれてるって思うんだよね。より楽しい、より便利なコンテンツ。目指す方向は、同じところにあると思ってる。……あなたもそう思う？　そう言ってくれると嬉しいわ。

## 2020

　ま、そんなこんなでさ、最後に残ったこの店も、今年いっぱいでおしまい。良いことも悪いこともたくさんあったけど、全部が楽しい思い出ね。
　……あたしね、引退したら、最初の頃のような簡単なアニメーション、もう一度作ってみたいんだよね。簡単な図形が右や左に動くだけで、とってもワクワクしたあの気持ち。それを、もう一度思い出してみたいな、って。……あら、あなたも付き合ってくれるの？　ふふ、ありがと。

　この店は、これで終わっちゃうかもしれないけど。Flashは、いつまでも終わらないよ。
　Flashは、何度だって再生できるんだから。
パッカーいろいろ

これは[マルウェア解析・検知・分類 Advent Calendar 2020](https://qiita.com/advent-calendar/2020/malware-analysis)の第1日目の記事です．

ゆるく書いていきます．

マルウェアの多くはパッカーと呼ばれるツールによってパックという処理を施されています．パックはプログラムを，挙動や機能をそのままに保ちながら，暗号化や圧縮して別のプログラムに変換する処理です．パックによって，静的解析が難しくなったり，プログラムイメージのシグネチャマッチングによってマルウェアと認識することが難しくなったりします．

マルウェア解析，特に静的解析では，まず，そのマルウェアがパックされているかどうかを正しく判定し，可能ならパッカーの種類を推定するなどの処理を通じてアンパックすることが重要になります．

パッカーいろいろ．ていうかリンク集．

- 無料かつオープンソースのパッカー
-- [UPX](https://upx.github.io/) おそらくマルウェア界でのシェアNo. 1
-- [UPack](https://inedo.com/upack)
-- [Yoda's Protector](http://yodap.sourceforge.net/)
-- NSPack ミラーサイトはあるが公式サイトがない？

- 無料かつ，おそらくクローズドソースのパッカー
-- [Crinkler](http://crinkler.net/)
-- [PECompact](https://bitsum.com/portfolio/pecompact/)
-- [PEtite](https://www.un4seen.com/petite/)

- 有料
-- [Themida](https://www.oreans.com/Themida.php)
-- [VMProtect](https://vmpsoft.com/products/vmprotect/)
-- [ASPack](http://www.aspack.com/)
-- [The Enigma Protector](https://enigmaprotector.com/)
-- [Obsidium](https://www.obsidium.de/)
-- [PELock](https://www.pelock.com/)

パッカーを扱った研究の論文もたくさん出ています．
- パックされているかどうか，どのパッカーでパックされているかを認識する方法
- 未知のパッカーでパックされたバイナリを自動的にアンパックする方法
- 世の中のマルウェアがどんなパッカーでパックされているかの実態についての調査結果
などなど．具体的な論文へのリンクは，そのうち，ここに加筆するかもしれません（しないかもしれません）．

あくまで気が向いたらですが，随時更新していきます．
Dockerだけでnpm initやnpm installをする方法

npmをローカルにインストールせずに、Dockerだけで`npm init`や`npm install`をする方法を解説します。

## npm init

まずは、ディレクトリを作成して中に移動します。

```sh
mkdir app && cd app
```

次に、dockerを使って`npm init`します。以下のコマンドを実行してください。実行すると`package.json`が生成されます。

```sh
docker run --rm -w "/usr/app" -v "${PWD}:/usr/app" node:15.3-alpine npm init -y
```

コマンドの解説をします。

`docker run <IMAGE>`は、イメージをコンテナ化するコマンドです。今回は`node:15.3-alpine`を指定しています。これは、[公式](https://hub.docker.com/_/node)のイメージで、ローカルになければコマンドを実行したときにインストールされます。

`--rm`オプションは、コンテナの終了時に自動的にそのコンテナを削除します。詳しくは[こちら](https://docs.docker.jp/engine/reference/run.html#rm)に書いてあります。

`-w`オプションでワーキングディレクトリを指定しています。システムの邪魔にならなければどこでもいいですが、今回は`/usr/app`としました。

`-v`オプションは、マウントをします。今回は、`${PWD}:/usr/app`としているので、現在のディレクトリを`/usr/app`にマウントすることになります。こうすることで、`npm init -y`を実行して、`/usr/app`内に生成される`package.json`を現在のディレクトリに反映させることができます。

最後の引数は、実行したいコマンドです。

## npm install

上記と同じように以下のコマンドを実行します。例としてexpressをインストールしてみました。実行すると`package-lock.json`や`node_modules`が生成されます。

```sh
docker run --rm -w "/usr/app" -v "${PWD}:/usr/app" node:15.3-alpine npm install express
```

Dockerを使うことで、npmをインストールせずに使うことができました。
「Svelte日本」のご紹介

先月中旬に、東北に住むカナダ人のウェブ開発者による Discord コミュニティ「Svelte日本」が開設されました。

<blockquote class="twitter-tweet" data-theme="dark"><p lang="ja" dir="ltr">東北に住むカナダ人のウェブ開発者で、日本で素敵なSvelteコミュニティを育てたいと思っています。​​アイデアやプロジェクトについて話し合いましょう!<a href="https://twitter.com/hashtag/discord?src=hash&amp;ref_src=twsrc%5Etfw">#discord</a> <a href="https://twitter.com/hashtag/svelte?src=hash&amp;ref_src=twsrc%5Etfw">#svelte</a> <a href="https://twitter.com/hashtag/%E3%82%B3%E3%83%9F%E3%83%A5%E3%83%8B%E3%83%86%E3%82%A3?src=hash&amp;ref_src=twsrc%5Etfw">#コミュニティ</a> <a href="https://twitter.com/hashtag/%E6%9D%B1%E5%8C%97?src=hash&amp;ref_src=twsrc%5Etfw">#東北</a> <a href="https://twitter.com/hashtag/%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0?src=hash&amp;ref_src=twsrc%5Etfw">#プログラミング</a><a href="https://t.co/fnJ8uO7xd0">https://t.co/fnJ8uO7xd0</a></p>&mdash; Jimmy (@MonsieurTako) <a href="https://twitter.com/MonsieurTako/status/1327770264919105538?ref_src=twsrc%5Etfw">November 15, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> 

---

現在は１３名ほどで、一週間に２～３回ほど Svelte に関するチャットがあるといった感じの、落ち着いたコミュニティとなっています。

先週は `#rss日本語` というチャンネルが開設され、 Qiita と Zenn の Svelte に関する記事が流れるようになり、 `#rss英語` というチャンネルでは dev.to の Svelte 記事が流れるようになりました。記事を全部読むとそれなりのボリュームがあり、情報収集にも使えるコミュニティになってきたと思います。

他にも質問が出来る `#help` や、雑談が出来る `#svelte雑談`、 作ったものを公開し合える `#ショーケース` 等といったチャンネルが用意されています。

Svelte を使ってみたい方、使ってみて楽しいと思った方、盛り上げていきたい方などには是非お勧めのオープンソースコミュニティとなっています。


興味がある方がいましたら、以下の招待リンクよりご参加ください。
https://discord.com/invite/YTXq3ZtBbx

※この記事は開設者の許諾を得て公開しています。
※自分の discord での名前は `am-researcher` です。
そんなの関係ねぇ、はいっ、OCP

# OCPとは

Open Closed Principle.

オープン・クローズドの原則

# 拡張に対して開いていて、修正に対して閉じている

オープン・クローズドの原則とは、**コードは拡張に対して開いていて、修正に対して閉じている**べきという考え方です。
つまり**機能を追加しても、それを使っているいずれの処理も影響を受けない**というような設計のことになります。

JavaでいうところのInterfaceがその役割に近いでしょうか。中身の実装が変わっても、引数や戻り地はInterfaceが保証してくれるので、その部分でのデグレは起きません。

こういう設計にしていると後の仕様変更に対応しやすかったりします。

# つまり

先に書いた[コピペ駆動開発](https://qiita.com/tosiooooooo/items/5bbd63b967897b753a32)なんてまさに理想のOCPなんですが、コードが冗長になって別な部分で不都合を生むので、プロジェクトの状況に応じてバランスよく取り入れる必要があります。
開発者ごとでなく、プロジェクトごとにFlutterのバージョンを管理する

Flutterのアップデート、まだまだ激しいですよね。
以前チーム開発していた時も、

- **他の開発者とのFlutterのバージョン違いによりAPI定義が異なりエラーの嵐→無駄なコミュニケーションの発生**
- **自分のPCのFlutterのバージョンを上げてしまったところ、ビルドできなくなったといった報告の対応**

など、プロジェクトごとでなく開発者ごとにFlutterのバージョンを管理しているために起きてしまう問題がいくつかありました。また、OSSや個人開発などでも使用するFlutter SDKのバージョンを固定したいこともあるかと思われます。

**本記事では、開発者ごとでなく、プロジェクトごとにFlutterのバージョンを管理する方法を紹介します。**

# FVMを用いる場合

FVMはFlutter SDKバージョン管理ツールです。

https://github.com/leoafarias/fvm

導入についてはこちらの記事が日本語で分かりやすいので、説明は割愛します。

https://qiita.com/Kurusu_ima/items/2dfd067f6e79f520198f

## バージョンをプロジェクトごとに固定する方法

ターミナルを開いてプロジェクトのルートに移動しておいてください。

インストール可能なリリース済みのバージョン一覧を確認しましょう。

```
$ fvm releases
```

次に現在インストールされているバージョンの一覧を確認してみましょう。

```
$ fvm list
```

お目当てのバージョンがなければ、以下のコマンドでバージョン名またはチャンネル名からFlutter SDKが手に入ります。

```
$ fvm install <バージョン名またはチャンネル名>
```

例えばstableを使いたい人は以下のコマンドです。

```
$ fvm install stable
```

最後に、以下のコマンドで、プロジェクトのFlutter SDKのバージョンを固定することができます。

```
$ fvm use <バージョン名またはチャンネル名>
```

そうすると、プロジェクト内に`.fvm`が作成されます。`.fvm`内には以下が入っています。

- プロジェクトで固定されるFlutter SDKバージョン情報が記載された`.fvm/fvm_config.json`
- `~/fvm/versions/<バージョン名>`のシンボリックリンクとなっている`.fvm/flutter_sdk`

## すでにFVMによりバージョン固定されているプロジェクトで開発する時

バージョンを指定せず以下のコマンドを実行すると、`.fvm/fvm_config.json`のバージョンをインストールできます。

```
$ fvm install
```

## 固定されたバージョンのFlutter SDKを使用する

`flutter`コマンドの前に`fvm`をつけるだけです。例として`flutter run`したい場合は以下のようになります。

```
$ fvm flutter run
```

## IDEの設定
IDEの操作でも固定したFlutter SDK下で実行できるようにします。デバッガーなどIDEの機能を使いたい時のために必要です。

### Android Studioの場合

`Preferences > Languages & Frameworks > Flutter`のFlutter SDK pathを`{対象プロジェクトのルート}/.fvm/flutter_sdk`に変更してください。

### VSCodeの場合

`{対象プロジェクトのルート}/.vscode/settings.json`に以下を追加してください。

```
{
    "dart.flutterSdkPath": [".fvm/flutter_sdk"],
}
```

VSCodeを再起動し、コマンドパレットで`Flutter: Change SDK`と入力してバージョンを選んでください。

# Flutter Wrapperを用いる場合

更新が一年以上止まっているのですが、特定のバージョンのFlutter SDKをダウンロード&実行するシェルスクリプトによってFlutterのバージョンをプロジェクトで固定できるFlutter Wrapperを用いる方法もあります。

https://github.com/passsy/flutter_wrapper

## 導入
ターミナルでバージョンを固定したいプロジェクトのルートに移動した後、以下を実行するだけです。

```
$ sh -c "$(curl -fsSL https://raw.githubusercontent.com/passsy/flutter_wrapper/master/install.sh)"
```

以降は`flutter`の代わりに`./flutterw`のコマンドを用いることで、固定されたFlutter SDK下でコマンドを実行することができます。

## アップグレード

特に新しいコマンドを覚える必要はありません。これも`flutter`の代わりに`./flutterw`になるだけで、いつものFlutterのアップグレードと同じです。

## IDEの設定
各IDEで設定されているFlutter SDKのパスを変更しておくことで、FVMの時と同様、IDEの操作でも固定したFlutter SDK下で実行できるようにします。

### Android Studioの場合
`Preferences > Languages & Frameworks > Flutter`のFlutter SDK pathを`{対象プロジェクトのルート}/.flutter`に変更してください。

### VSCodeの場合
`{対象プロジェクトのルート}/.vscode/settings.json`に以下を追加してください。

```
{
    "dart.flutterSdkPath": ".flutter",
}
```

# まとめ
Flutter Wrapperは更新があまりされていないので、**現在のところFVMがスタンダードなのかなという感じです。**FVMの方がバージョン切り替えもスムーズかと思います。強いて言うなら、Flutter WrapperはFVMのインストールを必要としないので、コマンド一発で使えるというところがメリットでしょうか。

## 参考
https://qiita.com/tetsufe/items/8ffa296c22a2dc8b9b51
https://qiita.com/Slowhand0309/items/0767abee120fcb3ba0b4
GASとNuxt.js、スプレッドシートで簡易顧客リスト検索アプリを作る(Part1)

# はじめに
こんにちは！株式会社Re:Buildの鈴木です！
弊社、<a href='https://re-build.company/'>株式会社Re:Build</a>は現在、沖縄拠点で9人のメンバーで活動してます！
今回は個人開発した内容を書いていきます！

# 開発するアプリのざっくり仕様
- スプレッドシートの顧客リストと連携して、Webアプリの画面で簡易的に検索できるアプリ。
- スプレッドシートの情報を直接は見れないようにしたい。
- 検索条件は複数持ちたい。

# こんな人にオススメ
- データベースを使わずに既存の使用しているスプレッドシートを使いたい。
- 現状のスプレッドシートを更新する運用フローは変更したくない。

# 使用した技術
- GAS
- Nuxt.js
- Vuetify

# 全体構成
![スクリーンショット 2020-12-01 19.50.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85181/0e7f5d9a-e77c-9eb1-c207-8c0b43c081ba.png)


# 開発手順
## 1.事前準備
### STEP1.シート作成
![スクリーンショット 2020-12-01 19.19.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85181/918a96b6-7652-ef2c-220b-d39d9a7cfd13.png)

### STEP2.シート準備
Google スプレッドシートで新しいシートを作成して、「ツール」タブ→「スクリプトエディタ」をクリックします。
![スクリーンショット 2020-12-01 19.19.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85181/67fe5371-533d-3de3-83cd-ba145f0432b2.png)

### STEP3.GASのコードを準備
```js
function doGet(e) {
  const params = e.parameter

  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('会社');
  sheetData = sheet.getDataRange().getValues();

  const output = ContentService.createTextOutput();
  output.setMimeType(ContentService.MimeType.JSON);
  output.setContent(JSON.stringify({"data": sheetData }));

  return output;
}
```

### STEP4.API URL の発行
「公開」タブ→「ウェブ アプリケーションとして導入」をクリックします。
![スクリーンショット 2020-12-01 19.27.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85181/29cecb40-a29d-1b47-43ef-a59a8388d990.png)
「Project version」は「New」、
「Execute the app as」は「Me (自分のメールアドレス)」、
「Who has access to the app」は「Anyone, even anonymous」
で「Deploy」ボタンをクリックします。
![スクリーンショット 2020-12-01 19.31.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85181/110d845d-20e1-85e6-7b83-f7d9b2f1790e.png)


### STEP5. authTokenの設定(任意)
このURLは誰でもアクセスができてしまうので、authToken を設定することもできます。

※この設定は任意です
「ファイル」タブ→「プロジェクトのプロパティ」→「スクリプトのプロパティ」を開きます。
authToken という行を追加して、任意の値を設定します。

# 最後に
次回はNuxt.js側の実装の文章を書いていきます！

あと、少し告知ですが、弊社では沖縄で<a href='https://rebuild-bootcamp.jp/'>Re:Build Boot Camp</a>という、エンジニアとして即戦力となる人材の育成を目的としたスクールも運営しております。
弊社で実際に働くエンジニアや関わりの深いエンジニアが講師やPMとなって個人開発やチーム開発を行っていただく内容です。

受講終了後には、複数のプログラミングスクールによる合同コンテスト「<a href='https://editch.org/'>editch(エディッチ)</a>」にもご参加いただけます。
各プログラミングスクール卒業生が作成した成果物を発表し、エンジニア出身経営者やCTOの方々が、ビジネスとエンジニアの両方の視点で審査。「実用性」、「技術力」、「アイデア」の評価ポイントにより、総合的に作品を評価します。


# 参考にした記事
【GAS x Vue.js】JavaScript のみで今、家計簿をつくるとしたら【ハンズオン付き！】
https://qiita.com/matsu7089/items/6ea7931e97ae703f6607
文化祭1週間前に配信担当になってやったこと

#はじめに
N高3年の_tomoiです。
1、2年と文化祭の実行委員はやっていて疲れたので今年は参加しないで終わりにしようと決めていたのです。が、今年の実行委員が崩壊し始めていてこのまま最後の文化祭を放置するのはちょっと違うなと空いている席に座る感じに参加しました。
今回は最初で最大のミスをやらかしたのでそこの設定を残しておきたいと思います。

#環境
- mac book pro
- obs
- webカメラ
- オーディオミキサー
- マイク

など

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">配信準備終わり<br>寝る <a href="https://t.co/UaDbYJncks">pic.twitter.com/UaDbYJncks</a></p>&mdash; tomoi🌕 (@_tomoi) <a href="https://twitter.com/_tomoi/status/1332868197960192001?ref_src=twsrc%5Etfw">November 29, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

↓かんたんに説明するとこんな感じ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374827/54a0e44c-0395-7bfe-2372-d5843e7acf1a.png)


#不具合
映像がカクカクになった。
おそらくキャンパスの回線が悪いのが原因のため以降解像度を1980x1080で設定していくが、テスト配信をし、その際にカクついた場合1536x864や1440x810など解像度を下げて対応してください。

#OBSの設定
##出力の配信ビットレートを4,500～9,000に設定する
![スクリーンショット 2020-12-01 18.55.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374827/dd2290bc-3bd6-1dde-049d-27323b1a6d6d.png)

##映像の基本解像度と出力解像度を 1920x1080 に設定する

![スクリーンショット 2020-12-01 19.02.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374827/fe4379f1-db46-1bcc-e8bf-4deb8538f8b2.png)

##配信のサービスを以下のように設定する

※ストリーミングキーは後述するものを使用
![スクリーンショット 2020-12-01 19.04.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374827/16a09d74-7067-d849-e181-047b78f97b9c.png)

#youtube live
[配信準備画面](https://www.youtube.com/livestreaming/)に行く

- ライブ配信をスケジュール設定を押す
![スクリーンショット 2020-12-01 19.10.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374827/fa742be8-4385-6b72-7677-fa080f0e010b.png)

- 新しいエンコーダー配信を押し適当に設定し、エンコーダー配信を作成を押す

- ライブ配信の設定 → ストリームキー → ストリームキーを設定から新しいストリームキーを作成を押し以下のように設定する

![スクリーンショット 2020-12-01 19.00.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374827/6d16e1cb-c9e9-cd8f-99d8-55ebea25461a.png)

- ストリームキーを選択から先ほど作成したストリームキーを選択し、ストリームキーをコピーし[ここ](##配信のサービスを以下のように設定する)のストリーミングキーに貼り付ける

#おわりに
来年は誰が機材担当するのかな
正直今のままだと来年以降誰も配信できない気がするのでこの記事をとりあえず書いておきました
(全然情報足りないけど)
連絡くれれば詳しい設定とか相談乗るので気軽に連絡してね

#追記 他のやらかしたこと集
- 配信中のハウリング
- 配信画質の劣化
- 司会が見えない(端だったしwebカメラ1つしかなかったからしょうがないようなところはある)
- 当日のスケジュール変更(結局もとに戻した)
- マジックのときの急なBGMの追加(これはあり)
- 待機画面のワンパターン化
- スケジュールを概要欄に書いて置かなかったこと

など
来年は改善しておいてくれるとありがたい
Macで標準出力から改行コードを削除してクリップボードにコピーする

# これはなに


VS Codeで作業していて、ファイル名のパスの指定を行う際に、

1. マウスで選択
2. コピー
3. コードに貼り付け

という手順で行っていましたが、少し面倒に感じていました。
ということでシェルの標準出力からクリップボードにコピーする方法を調べた結果です。

状況は、こんな感じです。
![no_pbcopy.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191337/31d6306c-5aa3-27bc-8bb6-084d5111afaa.gif)


# 改善後のフロー

VS Codeのターミナルから、pbcopyを使用しました。

```ｓｈ
$ ls hogehoge.csv | tr -d '\n' | pbcopy
```

改行を削除しないと行末の改行コードもコピーされます。sedは大げさに感じましたのでtrを使用しました。。

## pbcopy使用

![pbcopy.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191337/e609ed0d-6ae6-3f22-f66c-3bfa60545f20.gif)

# 参考にしたページ

[ねこの足跡R](https://blog.katsubemakito.net/macos/pasteboard-on-terminal)
AndroidStudioメソッドのパラメータを確認する方法

#動機
プログラミング学習していて、ふと気になったことが。
メソッドを入力した時に表示されるこれ。何をパラメータとして持つのか、ぱっと見で分かるので便利。
![2020-12-01 (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599059/960122a5-4b55-e487-1471-b8643f928220.png)
しかし、入力し終えると直ぐに消えてしまう。
どうにかしたいものだ。調べると、解決策は見つかった。
![2020-12-01 (4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599059/4977c662-45df-ce29-a604-91d8199fefcb.png)
#解決策

調べたいメソッドにカーソルを合わせて「Ctrl + p」以上。※Macの方は、「Cmd + p」
また、他にもViewタブから「Parameter Info]によっても可能だ。ちなみに、その横にショートカットキーも表示されていて、ここでも「Ctrl + p」であることが確認できるはずだ。
![2020-12-01 (9).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599059/ffc8e780-b825-b657-76cf-0ff918ab1802.png)
![2020-12-01 (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599059/5f8db937-16e7-cadc-0fab-8f5e189bde86.png)
RaspberryPi 4BでAI、RaspberryPi 4BでIoT（まえがき）

#はじめに
プログラミングの学習を始めてから4ヶ月。pythonを使い、ラズベリーパイで高齢者見守りシステムを作ってみました。
制作の過程を、数回に分けてまとめていきます。
#システム機能

* 対象者の起床を見守ります。予定の時刻までに起床が確認できないときは、あらかじめ登録している家族にLINEで連絡します。
* 対象者の活動量を見守ります。対象者が動かない状態が長く続いたときは、声をかけてみます。それでも反応がない場合、あらかじめ登録している家族にLINEで連絡します。
* 対象者の所在が確認できない状態が長く続いたときは、あらかじめ登録している家族にLINEで連絡します。ただし、googleカレンダーに登録されている外出予定期間は、装置が見守り対象者を認識できなくても、所在が確認できていると見做します。
* 複数台の装置が連携することで、広い範囲をカバーして対象者を見守ります。

#記事内容

* システム概要

 <dd><details><summary>記事へのリンク</summary><div>
    [RaspberryPi 4BでAI、RaspberryPi 4BでIoT（システム概要）](https://qiita.com/Jin_Kubota/items/1f225e7813ba0b281923)
</div></details></dd>

* 環境構築 （投稿予定）

 * 開発環境
 * RaspberryPi OSインストール
 * RaspberryPi初期設定

 <dd><details><summary>記事へのリンク</summary><div>
    [RaspberryPi 4BでAI、RaspberryPi 4BでIoT（開発環境）](https://qiita.com/Jin_Kubota/items/6a63c6ea4e621427a541)
    [RaspberryPi 4BでAI、RaspberryPi 4BでIoT（RaspberryPi初期設定：OSインストール編）](https://qiita.com/Jin_Kubota/items/319319a026256595c45f)

</div></details></dd>



* ソフトウエア制作 （投稿予定）

 * マルチプロセッシング・マルチスレッディング
 * スレッド間同期
 * 顔認識
 * 物体認識
 * 物体追跡
 * google calendarスケジュール取得
 * LINE通知
 * 音声合成
 * 装置間通信（FireStore）

* ハードウエア制作 （投稿予定）

#おわりに
プログラミング初心者のため、誤りが多々あると思います。アドバイス、励ましのコメントなどいただけると嬉しいです。
PC-98 MASM32でGRCGを使ってみた

#環境
- Windows 10 Home (64bit)
- MASM32
- Neko Project Ⅱ x64
- DiskExplorer

#ソース

```nasm:gcls.asm
comment *
ml /c /AT /Fl gcls.asm
link16 /t gcls;
*
	.model	tiny

	.code
	org	100h
start:
	mov	al, 01h
	out	6ah, al		; 16色モード

	mov	al, 80h		; GRCG=ON TDW(Tile Direct Write)
	out	7ch, al		; GRCGモードレジスタの書き込み

	mov	al, 00h
	out	7eh, al		; GRCGタイルレジスタの書き込み(BRGI)
	out	7eh, al
	out	7eh, al
	out	7eh, al

	mov	ax, 0a800h
	mov	es, ax
	mov	di, 0
	mov	cx, 40 * 400
	rep stosw

	mov	al, 00h		; GRCG=OFF
	out	7ch, al		; GRCGモードレジスタの書き込み

	mov	ax, 4c00h
	int	21h

	end	start
```

#応用編

QuickC 2.0
`qcl /c gcls2.c`
`link gcls2;`

```gcls2.c
#include <conio.h>

void gcls2(char b, char r, char g, unsigned short step)
{
	unsigned short offset;
	char far* lp;
	unsigned int i;

	outp(0x7c, 0x80);	// GRCG=ON TDW(Tile Direct Write)
	outp(0x7e, b);		// GRCG tile
	outp(0x7e, r);
	outp(0x7e, g);
	offset = 0;
	for (i = 0; i < 32768; i++) {
		lp = (char far*)(0xa8000000 + offset);
		*lp = 0;
		offset += step;
	}
	outp(0x7c, 0x00);	// GRCG=OFF
}

int main()
{
	outp(0x68, 0x08);	// 400 line
	outp(0x6a, 0x00);	// 8 color
	outp(0xa2, 0x4b);	// G-GDC CSRFORM
	outp(0xa0, 0x00);	// line scale
	outp(0xa2, 0x0d);	// G-GDC START

	gcls2(0xff, 0x00, 0xff, 1);
	gcls2(0x00, 0x00, 0x00, 3);

	return 0;
}
```
C++20便利機能の紹介：同期出力ストリーム std::osyncstream

C++20標準ライブラリでは「同期出力ストリーム(synchronized output stream)」が追加されました。これによって並行実行される複数スレッドから **行単位のストリーム同時出力** を、安全かつ手軽に行えるようになります。[^1]

[^1]: そのまま`std::cout`出力すればいいんじゃね？何がダメなの？という方は記事「[スレッドセーフという幻想と現実](https://yohhoy.hatenablog.jp/entry/2013/12/15/204116)」や「[C++11のcoutとスレッド安全性](https://yohhoy.hatenadiary.jp/entry/20120127/p1)」をご一読ください。

```c++:C++17
#include <iostream>
#include <mutex>

// std::cout出力を保護するミューテックスを用意...
std::mutex g_cout_mutex;

// 複数スレッドからworker_thread関数が同時に呼び出されると仮定
void worker_thread(int id)
{
  {
    // 文字列"Worker#<N>"が1行で出力されることを保障するため
    // ミューテックスg_cout_mutexによる排他制御が必須！！
    std::lock_guard lk{g_cout_mutex};
    std::cout << "Worker#" << id << std::endl;
  }
  // ...
}
```

# std::osyncstreamクラス

下記の例示ソースコードでは新ヘッダ`<syncstream>`をincludeし、標準出力ストリーム`std::cout`を`std::osyncstream`でラップしています。

```c++:C++20
#include <iostream>
#include <syncstream>  // NEW

// 複数スレッドからworker_thread関数が同時に呼び出されると仮定
void worker_thread(int id)
{
  // 文字列"Worker#<N>"は他スレッド出力と混じることなく1行で出力される
  std::osyncstream{std::cout} << "Worker#" << id << std::endl;

  {
    // syncoutへのストリーム出力は一旦バッファリングされ...
    std::osyncstream syncout{std::cout};
    syncout << "Worker#" << id << " ";
    for (int n = 0; n < id; n++) {      
      syncout << (n ? "," : "[") << n;
    }
    syncout << "]" << std::endl;
  } // syncoutオブジェクト破棄時にstd::coutへアトミックに送出(emit)される
}
```

`std::osyncstream`クラスでは、スレッド間の排他制御は「ラップ対象の出力ストリーム（先例では`std::cout`）」に対して行われます。つまりストリーム出力操作(`operetor<<`)を行う **`std::osyncstream`オブジェクト自体は異なっていてもよく**、実際にストリーム出力を行う箇所で一時オブジェクトの生成／破棄を行えば十分です。

合わせて関連するマニピューレータ(`emit_on_flush`,`noemit_on_flush`,`flush_emit`)も追加され、より細かい制御も可能となっています。これらの機能詳細は記事「[C++ Synchronized Buffered Ostream](https://yohhoy.hatenadiary.jp/entry/20171121/p1)」でも紹介しています。


## 利用上の注意（2020/12/1現在）
2020/12/1現在、主要C++コンパイラGCC／Clang／MSVCいずれにおいても [標準ヘッダ`<syncstream>`は未実装](https://cppmap.github.io/standardization/header/) です。この便利機能を試すことはできません。どうして…

先行して試したい方向けに、提案時の参照実装を紹介しておきます。
https://github.com/PeterSommerlad/SC22WG21_Papers/tree/master/workspace/p0053_basic_osyncstreambuf


## 参考ページ
* https://timsong-cpp.github.io/cppwp/n4861/syncstream
* http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0053r6.pdf
* http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0753r2.pdf
マンガでわかるアンチパターン序文

![8D13BC59-03C5-45A6-B88D-079E0495DEFC.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/11525/a1957eb2-e6af-c5fd-3b1a-8047f7552b38.png)

アンチパターンの名を冠した本が出版されたのは、今を遡ること 18 年前の 2002 年のことです。当時の文化的状況はたしかに今とは違いますが、これもまた、多くのソフトウェアに関する知見に共通して、現代でも通用する、いやそれどころか、現代だからこそようやく、一般的な理解を得はじめた教示にあふれていると思います。

じっさい、現在のソフトウェア開発の現場において、このアンチパターン本のパターン名は、もしかしたらデザインパターンより広く知られているかもしれません。今はもう絶版となってしまったこの本を再度読み解いて、名前は知ってたけど元はそういう意味だったのか、と、1日1パターンのペースで再認識していこうと思います。

まずは前置き。アンチパターンがデザインパターンよりも価値があるひとつの理由として、その発生率が挙げられます。というのも、[パターンとは、盲目的にそれを使えば無条件に良くなるものではなく、あくまで、よくできた典型的な状況に見い出し、名前を付けて認識を共有するもの](https://qiita.com/tanakahisateru/items/df03d2558f9499d1a64a) という前提に立てば、デザインパターンを認識できるような美しい設計の有様は、スキルの高い人からしか生まれない、珍しいものであるのに対して、アンチパターンは、特別できる人材のいない凡庸なチームからでも発生する (もちろん技術スキルが高くもその偏りからも生まれる) ので、ソフトウェア開発のあらゆる場面で見られます。

普通の人がやらかしてきたありがちな失敗を知り、自分たちの失敗の兆候にいち早く気づくための目を養うのは、おそらく、デザインパターンにぴったりマッチするまれな状況を待つよりも、広く適用でき、早く役に立つと思います。
Vue3 コンポーネントをグローバルで使用できるように登録する

@takayuki-miura0203 さんが書いてくださったこちらの記事 [Vue.js + Typescript のディレクトリ構造一例](https://qiita.com/takayuki-miura0203/items/75a1b6d118613ff97dbc) を参考にVue3プロジェクトを作成していました。

plugins/materials のセクションで紹介されている、atoms、molecules 粒度のコンポーネントを

```
createApp(App)
  .use(XXXX)
```

を使用してまるっとグローバルで使用できるように登録するコードが便利そうで組み込もうとしましたが、Vue3では以下のエラーが発生、解決のため調査をした。

```
ERROR in src/plugins/materials/index.ts:1:32
TS2307: Cannot find module 'vue/types/umd' or its corresponding type declarations.
  > 1 | import { VueConstructor } from 'vue/types/umd'
      |                                ^^^^^^^^^^^^^^^
    2 |
    3 | // @/plugins/materials 配下の全vueファイルを取得
    4 | const context = require.context('.', true, /.vue$/)
```

結論として、以下の通り修正を行った。

```typescript
import { App } from 'vue'

// @/plugins/materials 配下の全vueファイルを取得
const context = require.context('.', true, /.vue$/)
// eslint-disable-next-line
const components: { [key: string]: any } = {}

// 取得したコンポーネント一覧を、ファイル名がキーのオブジェクトに変換
context.keys().forEach(contextKey => {
  const keys = contextKey.match(/.+\/(.+)\.vue/)
  if (keys) {
    const key = keys[1]
    components[key] = context(contextKey).default
  }
})

// ファイル名をキーとしたコンポーネントとしてグローバル登録
export default {
  install(app: App) {
    Object.keys(components).forEach(key => {
      app.component(key, components[key])
    })
  },
}
```

## 修正した内容

1. 呼び出されるinstallメソッドの引数は、VueConstructorから、Appに変わったので、その箇所とimportを修正。
2. 
```typescript
const components: { [key: string]: any } = {}
```
の箇所が以下、lintエラーになってしまった

```
/Users/quqjp/Documents/works/ymorimo/lounge-m/vq-frontend/src/plugins/materials/index.ts
  9:36  warning  Unexpected any. Specify a different type  @typescript-eslint/no-explicit-any
```

解決方法が不明だったので、

```
// eslint-disable-next-line
```
で逃げています。。。

## 単体のコンポーネント登録
記事のタイトルと内容があまりマッチしていなそうなので、念の為単体のコンポーネント登録について書いておきます。

```typescript
const app = createApp(App)
app.component('PopupWindow', PopupWindow)
```
main.ts に、createAppのコードがありますが、
componentメソッドで、コンポーネント名、コンポーネント実態を渡すことで、
vueファイルのscriptのcomponents でコンポーネントをいちいち登録せずともtemplate内で使用できるようになる。

# 参考ページ
How to Register a Vue3 Global Component
https://learnvue.co/2020/08/how-to-register-a-vue3-global-component/
ご注文はPyTorchですか？　～Tensorを知っTensor～

# はじめに
皆さん、ディープラーニングしてますか？私はテスト勉強で過学習をして死にました。
それはともかく、最近はディープラーニング初心者でも耳にするPyTorch。同じディープラーニング用のフレームワークKerasと比べると難しく感じるものの、慣れてしまえばKerasの方が難しく感じてくる場面に出くわします。

#目次
1. [PyTorch #とは](#pytorchとは)
2. [PyTorchのインストール](#pytorchのインストール)
3. [PyTorchのインポート](#pytorchのインポート)


# PyTorchとは
PyTorch は、Facebookが開発・公開するディープラーニング用ライブラリです。
筆者はFacebookアカウントが大統領選のBAN祭りでやられたので、いろいろな連携サービスが使えなくなってしまいました。
[PyTorchの公式ページ](https://pytorch.org/)ではドキュメントが英語で書かれています。英語ツヨツヨになりたい。
ドキュメントの中では見やすい部類なので、Google翻訳レベルでも見ることができるのではないでしょうか。DeepL使いましょう。

# PyTorchのインストール
PyTorchのインストール方法は、[公式サイト](https://pytorch.org/)に実行すべきコマンドが載っています。
下の画像のように、自分が使う環境をクリックしたら、その下に実行するコマンドが出てくるので、これをコピーしてターミナルやプロンプトにペーストして実行します。
CUDAを使用したい場合は、別途CUDAをインストールする必要があるかもしれません。(あんまりよく覚えていない)
![スクリーンショット (29).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/338279/f3bc2957-e211-3fca-cf79-5405554d5948.png)
筆者はWindows10にPython3.8をインストールして、venvからpipでインストールしています。
そもそもPythonをインストールしていない人は、Pythonインストールに関する記事を探してください。
できればMatplotlibやJupyterをインストールしておくといいでしょう。

# PyTorchのインポート
PyTorchがインストールできたらPyTorchをインポートして使ってみましょう。
ターミナルからPythonを起動して、以下を実行してみてください。

```python
import torch
print(torch.device('cuda' if torch.cuda.is_available() else 'cpu'))
```

NVIDIA製グラフィックボードを利用していて、CUDAがきちんと利用できていれば`cuda`と表示されます。
NVIDIA製グラフィックを利用していなかったり、CUDAが利用できていない場合は`cpu`と表示されます。
インストールできていない場合はエラーが出ます。

# まとめ
今回はPyTorchの紹介からインポートまでを行いました。
次回は線形代数に少し触れながらPyTorchを使っていきたいと思います。
愛 LOVE SLAP

# SLAPとは

Single Level of Abstrustion Principle.

抽象化レベルの統一

# 書籍のように構成する

文書を書くとき、大見出し、中見出し、小見出しみたいに構成してわかりやすくすると思いますが、それと同じようにクラス・関数を構成すると可読性が上がります。


＃＃ 例

```example.rb
class 会員管理クラス

  def 会員登録関数
    会員登録のデータを操作する関数
    ......
  end

  def 会員登録のデータを操作する関数
    会員登録のデータをDBに保存する関数
    ......
  end

  private

  def 会員登録のデータをDBに保存する関数
    ...
  end
end
```
 　1 classに詰め込んだ場合の例です。実際にはclassも分かれることが多いと思いますが。

このように3段なら3段ですべてのコードを構成しておくと、「このプロジェクトはこういう構成なんだ」と読む側も意識できると可読性があがってGoodです。

# つまり

書籍の目次をイメージするといい感じになるんじゃないかな。
まとめて文字列を変換する

#translate()を使う
文字列をまとめて変換するにはtranslate()メゾットを使います。

例えば'タマゴ'を'たまご'に変換したいときは下記の通り入力します。

```python
text = 'タマゴ'
#何を何に変換するか
m = str.maketrans({'タ':'た','マ':'ま','ゴ':'ご'})
#実行
t = text.translate(m)
print(t)
```
PIEの実

# PIEとは

Program Intently and Expressivery.

ひたすら意図を表現するプラグラミングをせよ

# 設計書はコード

あるあるですね。
設計書はない、OR 、メンテしてないから情報が正しいかわからない。
結局コードが一番の設計書になりがちです（たまに本番で動いているのとgitに上がっているのが違うコードで、コードすら正しくないパターンもありますが）。
なので、設計書のつもりで、誰かに読ませるつもりでコードを書くのが一番ですね。

# コードは読みやすさが最優先

可読性とか言ったりしますが、書くことよりも読まれることのほうが圧倒的に多いので、読み物としてコーディングする必要があります。
コメントを書くのも、ネストしすぎないのも、一つのクラスや関数で長々と書かないのもそのためですね。

クラスや関数の役割を明確にしておくと、読みやすくなります。私の場合はクラスや関数を**部署**と思って設計しますが、「データを取得するだけの部署」、「データをチェックするだけの部署」、「データを整形するだけの部署」などと役割を明確にしておくと、あとから改修するときに「この関数だけを気にすれば良い」と最初に割り切れるので、対応しやすかったりします。

# 他の人のコードを直すのも大事

他の人が作ったシステムを改修するタイミングでついでに見やすくリファクタリングするのも大事です。
もともと美しいコードであれば良いですが、そうではない場合こういうタイミングで直していかないといつまでも負の遺産が残されていくので、勇気を持ってこれも運命だと思って読みやすく正していくことで、プロジェクト全体の生産性が上がっていきます。

# つまり

コーディングルール作って、メンバー全員で意識してプログラミングしようぜ
JavascriptのforEachでindexの使用例

# forEachのindexとかarrayの使いどころがわからなかった

forEachでコールバック関数を利用するのみでindex,arrayを使ったことがなかった。
face-api.jsの中身を見ていてああ、なるほどと思ったのでまとめます。

# 例

face-api.jsの中で使われていたコードの雰囲気

```test.js

array.slice(1).forEach(({ x, y }, index) =>
            {
                const from = array[index];
                ctx.moveTo(from.x, from.y);
                ctx.lineTo(x, y);
            })
ctx.stroke();
//~~~
```
これは顔の特徴点と特徴点同士を線でつなぎ、canvas上に描画する処理の一部。↓の青線を引く。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482410/bb30db0a-b603-b2ec-a099-352fabe4d4af.png)

slice関数で1番目以外の点を取得し、それぞれについて一つ前の点から次の点へ直線を引くという流れです。

# あとがき
いままで使える機会があったが、わざわざ別で変数を用意して繰り返しインクリメントさせる
という非常にスマートでない方法でやっていた。。。
apiの中身を見てみるといろいろと発見がある！
【JS】オブジェクトから要素を削除する方法。filterとfindの活用

オブジェクトから該当する要素を削除する方法について。

例えば、以下のようなオブジェクトがあった場合に、指定した要素を削除する場合を考える。

```js:
obj = [{a:1, b:2}, {a:1, b:3}, {a:2, b:3}, {a:3, b:4}]
```

##目次

1. [元のオブジェクトを利用する場合](#元のオブジェクトを利用する場合) 
    2. [要素が１つの場合](#要素が１つの場合)
    3. [要素が２つ以上の場合](#要素が２つ以上の場合)
4. [元のオブジェクトを利用しない場合](#元のオブジェクトを利用しない場合)
5. [どれか一つのプロパティが一致する要素を削除する場合](#どれか一つのプロパティが一致する要素を削除する場合)




<br>
##元のオブジェクトを利用する場合
元のオブジェクトを使って除外する要素を指定する場合は判定式が使える。

###要素が１つの場合
要素が一つの場合は、filterを使えば実現可能。例えば、配列番号3の`{a:3, b:4}`を削除する場合は以下のような式になる。

```js:
obj = [{a:1, b:2}, {a:1, b:3}, {a:2, b:3}, {a:3, b:4}]
removeObj = obj[3]

res = obj.filter( elem => elem != removeObj)

console.log(res)
//[{a:1, b:2}, {a:1, b:3}, {a:2, b:3}]
```

`obj.filter( elem => elem != removeObj)`

- objの要素を一つづつ抜き出し、elemという変数に代入する
- `=> `以降の処理がtrueの場合のみ要素を抜き出す。
- つまり、要素がremoveObjと一致する場合は抜き出さない（削除）する処理となる。

 <br>
`removeObj = obj[3]`のように、**元のオブジェクトを使って要素を指定しているため、要素どうしの比較が可能**。



<br>
###要素が２つ以上の場合
要素が２つ以上の場合はfilterとfindを使う必要がある。配列番号0と１の要素を排除する場合は以下のようになる。

```js:
obj = [{a:1, b:2}, {a:1, b:3}, {a:2, b:3}, {a:3, b:4}]
removeObj2 = [obj[0], obj[1]]

res2 = obj.filter( elem => !removeObj2.find( x => x == elem ))

console.log(res2)
//[{a:2, b:3}, {a:3, b:4}]
```

`obj.filter( elem => 処理)`

- filterを使ってobjの要素を一つ一つ抜き出す。（変数elemに代入）


`!removeObj2.find( x => x == elem )`

- findは処理結果がtrueになった要素を返す処理。
- `!`をつけ、排除したい要素とobjの要素が一致した場合はfalseを返す。
- filterはtrueの場合は要素を抽出するが、falseの場合は抽出しない（除外する）



<br>
##元のオブジェクトを利用しない場合
元のオブジェクトを利用しない場合は、filterとfindを使うことで、指定した要素を排除できる。

```js:
obj = [{a:1, b:2}, {a:1, b:3}, {a:2, b:3}, {a:3, b:4}]
removeObj = [{a:1, b:2}, {a:3, b:4}]

res = obj.filter( elem => !removeObj
    .find( x => x.a == elem.a && x.b == elem.b )
    )

console.log(res)
//[{a:1, b:3}, {a:2, b:3}]
```

元のオブジェクトからfilterを使って要素を一つづつ取り出し、中のプロパティを一つ一つ比較していく必要がある。

`removeObj.find( 変数 => 処理 )`

- 処理結果がtrueになった最初の要素を返す。
- `x => x.a == elem.a && x.b == elem.b` removeObjのプロパティaとbが元のオブジェクトの要素と一致した場合にその値を返す。（xはremoveObjの要素を一つ一つ取り出した変数）
- `!`をつけ、排除したい要素とobjの要素が一致した場合はfalseを返す。



<br>
##どれか一つのプロパティが一致する要素を削除する場合

複数あるプロパティの中で、a:1となっている要素を全て除外する場合はfilterのみで実現可能。

```js:
obj = [{a:1, b:2}, {a:1, b:3}, {a:2, b:3}, {a:3, b:4}]

res = obj.filter( elem => !(elem.a == 1) )

console.log(res)
//[{a:2, b:3}, {a:3, b:4}]
```

`!(elem.a == 1)`
filterで抜き出した要素（elem）のプロパティaが1となる場合はfalseを返し除外する。




<br>
###（補足）filterのみで記述する場合
要素が１つの場合は、findを使わずfilterのみで記述することも可能だが汎用性がないため特に不要。

記述は以下のようになる。

```js:
obj = [{a:1, b:2}, {a:1, b:3}, {a:2, b:3}, {a:3, b:4}]
removeObj3 = [{a:3, b:4}]

res3 = obj.filter( elem => !(removeObj3[0].a == elem.a && removeObj3[0].b == elem.b )
    )
console.log(res3)
//[{a:1, b:2}, {a:1, b:3}, {a:2, b:3}]
```

`removeObj3[0].a`のようにプロパティの値を直接指定し、比較している。
Kotlin どうでしょう

Kotlin コトリン
----------------------
Kotlin は JET BRAINS社が開発したオブジェクト型指向言語。
2017年に Google がAndroid開発言語として正式サポート。
元々、Android開発環境である「Android Studio」は、JET BRAINS社の IntelliJ ベース。
開発環境の言語サポートが充実している！

言語仕様について
-------------------------------------
![kotoli.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/518262/119d377b-db42-1a31-d1e5-df2baaf6e401.png)

Javaと相互運用可能！
------------------------------------------------------
JavaからKotlin のクラス使える。
逆に、KotlinからJavaのクラスも使用可能。
(Kotlin が JVM上で動作する言語のため。)

JavaコードをAndroid Studio上で 貼り付けすると、
Kotlinコードに変換できる。
(ただし、完璧ではない。ビルドが通らないことも有。)


・総評
-----------------------------------------
記述が簡潔にできるので、積極的に使用したい。
　
Swiftの文法に近いため、
iOS - Android 開発者のスキルトランスファーの敷居は下がると思われる。
(設計の思想は違う。)

Android開発には、Javaを知った上でのKotlin知識が必要なため、
Javaを捨てることはまだできない。
Android開発者向けオプションを使ったチート対策

[PONOS Advent Calendar 2020](https://qiita.com/advent-calendar/2020/ponos) 5日目の記事です。

##はじめに:eyeglasses:

Androidチート対策の一つとして
開発者向けオプションを使用した対策を紹介します

##この記事の対象者:eyeglasses:
・アプリ開発者
・Android開発者

##開発者向けオプションが有効かの判定
チート端末では開発者向けオプションが有効になっていることが多いです。
アプリ側で開発者向けオプションが有効か無効か判定してみましょう。

[android.provider.Settings.System](https://developer.android.com/reference/android/provider/Settings.System)クラスを使用します。
システム環境設定関連の値を取得するなど便利な機能があります。

 `Settings.Secure.getInt() `メソッド
 `Settings.Global.DEVELOPMENT_SETTINGS_ENABLED `フィールド
を使用します。

```
boolean isEnable = Settings.Secure.getInt(this.getContentResolver(),
 Settings.Global.DEVELOPMENT_SETTINGS_ENABLED , 0) == 1;
        if(isEnable){
            //開発者向けオプション　有効時の処理
            //例：タイトル画面でロックして、開発者向けオプションをOFFにするように促すポップアップ表示
        }else{
            //開発者向けオプション　無効時の処理
        }
```
**メリット**
アプリのセキュリティーレベルを上げることができる。
実装コストが軽い

**デメリット**
主に開発者など日常的に開発者向けオプション有効にしているユーザーにとっては迷惑

**導入する場合**
端末操作で開発者向けオプション有効にする方法は
「設定」アプリ内で「ビルド番号」を7回連続してタップ
と一般ユーザーはやらない操作だと思われるが、トレードオフが必要です


####USBデバッグモードの判定
フィールド名だけを変えた同様の方法で[adb](https://developer.android.com/studio/command-line/adb?hl=ja)のチェックも可能です。
USB経由の[adb](https://developer.android.com/studio/command-line/adb?hl=ja)が有効かどうか判定できます。

```
boolean isAdb = Settings.Secure.getInt(this.getContentResolver(),
 Settings.Global.ADB_ENABLED , 0) == 1;

```

チート対策としては有効ですが
こちらも導入する場合は、トレードオフが必要です。

##まとめ
今回紹介した方法は「小を捨てて大に就く」手法で完璧なものではありません。
他にも有効なチート対策があるので合わせて検討するのがお勧めです。
**チート対策**
・メモリシャッフル（メモリハック対応）
・root権限チェック
・不正端末名、不正エンジン名のチェック（エミュレーター対策）
・ソースコード難読化
・リソースなどの暗号化
・サーバー側でのバリデーションチェック
・サーバー通信時の内容を暗号化
・SafetyNetの導入
などなど

今回の手法の最大のメリットは実装コストが軽いことなのですぐ実装して
・複数端末テストの結果をみて導入を検討する
・得られた情報をユーザーデータとして保存してデータ分析してから検討する
などのやり方がベターかなと考えております。


明日は、[@nissy_gp](https://qiita.com/nissy_gp)さんの記事です。
お楽しみに！！
【備忘録】tapについて少し調べてみた。

# 環境
Ruby 2.6
Rails 5.1.7

# 背景
機能実装中、似たような処理を探していたら「tap」を見つけてなんだこれ、と思い調べた。これは初めて遭遇したので備忘録として。

# tapとは
```ruby:
"foo".tap {|str| puts str.reverse}
# oof
# => "foo"
```

メソッドの返り値は変わっておらず小文字のままだけれど、tap自体は動いていて文字列が反対になっている。
調べたところによると、tapはメソッドの中で何かしたいけど、メソッド自体の評価は変えたくない時に使うみたい。

# 実際に見たコード
こんな使い方もある(らしい)。

```ruby:
...
User.new.tap do |item|
  item.name = "Taro"
  item.address = "test@gmail.com"
  --- 中略 ---
  item.tel_num = "09012345678"
end.save!
...
```
`end`の後にsave!ってなんやねんと思ったけど大分スッキリ書けますね。
tapを応用していって可読性の高いコーディングしていきたいと思います。
YOUは何処から日本へ？（ページにアクセスしたユーザーがどこから来たか調べる）

# アクセスしたユーザーの国や地域、IPアドレス取得
案件で多言語サイトのデフォルト言語をユーザーごとに出し分けたいという要望があったため
フロント、サーバー側で国や地域、IPアドレスを取得する方法を調査した

## JavaScripts で対応
JS単体では端末のIPを取得することはできないがAPIを利用することで取得できる
以下は中でもフリーのサービスを抜粋したもの

### 1. ipinfo.io
　アクセスするとIPを取得して表示してくれるサービス。
　JSON形式で情報が返却される。
　アカウント作成とアクセス回数に上限がある
　[ipinfo.io](https://ipinfo.io/ "ipinfo.ioの公式")

### 2. Geolocation API
　WiFi、GPS、IPアドレスなどから位置情報を取得するAPI。
　JSON形式で情報が返却される。
　位置情報の取得にはユーザーの許可が必要なため拒否されれば当然取得できない。
　WiFiや緯度経度からの取得はGoogleが提供していることが多いため中国などでは利用できないことがある。
　[Geolocation API](https://developer.mozilla.org/ja/docs/Web/API/Geolocation_API "Geolocation APIのドキュメント")
### 3. ipify
　フリーのIP取得サービス。
　JSON形式で情報が返却出来る。
　上限は無し。
　[ipify](https://www.ipify.org/ "ipifyの公式")
　[API](https://api.ipify.org/?format=json "API単体")

### 4. jsonip.com
　無料無制限のIP取得サービス。
　JSON形式でIPを取得できるがおまけに広告とドキュメントのURLが含まれている。
　以前は政治的メッセージも含まれていたがなくなったらしい。
　上限なし。
　[jsonip.com](https://getjsonip.com/ "jsonip.comの公式")
　[API](https://jsonip.com/ "API単体")

### 5. JSON Test
　フリーのIP等取得サービス。
　IPアドレス単体やリクエストヘッダー情報をJSON形式で取得できる。
　名前のせいで情報が見つけにくい。
　[JSON Test](http://www.jsontest.com/ "JSON Testの公式")
　[API](http://ip.jsontest.com/ "API単体")

### 6. ipapi.co
　フリーと商用ライセンスのあるIP等取得サービス。
　アカウント登録が必要。
　IPだけでなく国や地域、緯度経度など詳細なデータをJSON形式で取得できる。
　珍しくドキュメントもそろっているので親切。
　[ipapi.co] (https://ipapi.com/ "ipapi.coの公式")

## PHP で対応
PHPはIPアドレスを取得できるが国や地域を取得するにはライブラリかAPIが必要になる（一部有料）

### 1. IPinfoAPI
　IPアドレスを渡すと国や地域のコードをJSON形式で取得できるサービス
　上限が毎秒２回まで。

### 2. Geo IP2
　MaxMind社から提供されたデータベースファイルをサーバー側に設置しアクセスしたIPで検索してどの国や地域からアクセスがあったかを調べる。
　無償版ライセンスでは国まで、有償版では地域まで取得できるので用途によって使い分け可能。
　[Geo IP](https://www.php.net/manual/ja/book.geoip.php "PHPのドキュメント")

## AWS で対応
AWSのCloudFront-Viewer-Country はIPアドレスから判断したアクセス元の国コードを返却するためAWSを利用していれば対応可能。
　[AWS] (https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/using-cloudfront-headers.html "AWSのドキュメント")
## まとめ

- JavaScriptsは単体ではIPを取得できないがAPIを使用すればIPもしくは国コードなどのアクセス元情報が取得できる。<br>ただしIPアドレスの取得方法によっては対象外の国や地域があるため注意が必要。

- PHPはIPアドレスは単体で取得可能だがアクセス元の国や地域のコードを取得するにはライブラリ、APIが必要。
ライブラリのライセンスは詳細な情報が必要であれば有償版、国コードが必要なだけであれば無償版でよい。

- その案件がAWSを利用しているのであればCloudFront-Viewer-Country で対応可能