OmniAICreator/Qiita-1.07M huggingface dataset:
FlutterとSkyWayでオンライン麻雀ゲーム作ってみた

# この記事について
昨年末、タイトルのようにオンライン麻雀ゲームを作成したので、振り返りを兼ねてゲームの紹介記事を作成しました。

# ゲームのURL
以下のURLで公開しています。

https://yomoyama-dev68.github.io/y2-mahjong/

# どんなゲーム？
ボイスチャット付きオンライン対戦麻雀ゲームです。
アカウントなどの登録作業不要なので気軽に遊べます。

個人開発のため機能やUIはしょぼいです。
点数計算機能がなく。また、フリテンや間違った鳴き方を防ぐ機能もありません。
やり直し機能は付けているので、ミスしてもやり直し可能です。
細かなルールはプレイヤー同士で話し合って決める必要があります。
また、プレイヤーとしてだけでなく、観戦者としても参加できます。
参加者でワイワイお喋りしながら楽しく遊んで貰えると嬉しいです。
Flutterの習作として作ったので、作りが粗い部分が多々ありますがご容赦ください。

![startgame_step2](https://user-images.githubusercontent.com/88811767/143666246-5b5e8214-ea35-4cd6-9635-f186443ebbd4.gif)



# なんで作ったの？

\<オンライン飲み会にて\>
先輩「コロナで雀荘に行けないから、いい感じのオンライン麻雀ゲーム探してきて」
私　「かしこまり」  
先輩「あ、アプリインストールとかアカウント登録とかめんどいから、そういうの無しのね」
私　「か、かしこまり」

\<一週間後\>
私　「見つかりませんでしたぁ！」
先輩「無いなら作れば良いんだよ！」
私　「」

という感じで、自作してみることにしました。
Webのフロントエンドの経験はなかったのですが、当時お仕事で使っていたFlutterがWebアプリに正式対応したこともあり、習作のつもりで作成を開始しました。
また、以前から興味のあったWebRTCの勉強にも良い機会だと思ったのもあります。

\<完成後\>
私　「どやさ！」
先輩「え？ホントに作ったん？」
後輩「ていうか、天鳳ならアプリインストールもアカウント登録も不要っｽよ」
私　「」


# 作成期間
仕事終わりや休日にほそぼそと作業して、約4ヶ月かかりました。
* SkyWay調査：2週間
* システム面：1.5ヶ月
* GUI関連：1.0ヶ月
* 不具合修正：1.0ヶ月
* 説明書作成：2週間

## SkyWayについて
WebRTCのSDKとして、SkyWayを選択しました。
選定理由としては、
* 無料枠がある。
* サンプルコードが分かりやすい。

などです。
実際に使ってみて、ボイスチャットの音質はZoomやMeetsなどに比べて、特に悪いとは感じませんでした。
5人程度で会話していましたが、ハウリングや音割れは起きませんでした。

# 工夫したこと
### ゲームサーバレス
個人開発で手数が少ないこともあり、このゲームにはゲーム管理用のサーバを構築していません。
サーバは、SkyWayのWebRTCサーバと、Githubのホスティングサーバのみです。

参加者の内、一人がゲームサーバ役を担うシステムになっています。
もしサーバ役の人が落ちても、別の人がサーバ役を引き継ぐようになっています。
全員が同時に落ちない限りはゲームの続行が可能な作りになっています。

このシステムの実現にあたって、参加者全員がゲームデータを保持しています。
そのため、頑張れば相手の牌や山牌を見ることができてしまいます。
このゲームは身内で行う想定なので、そこまでズルい行為しないと割り切って作成しました。

# 大変だったこと
### 麻雀システム
鳴きの処理など、通常のゲームでは発生しないような割り込みイベントがあり、排他処理や誰がどの操作が可能かの管理が大変でした。
中でも、加槓は牌の処理も、描画でも例外的な処理を書く必要があり一番苦戦しました。
正直、「麻雀のゲーム化なんて点数計算機能以外は楽勝でしょ」と舐めていました。

### テスト
とにかく4人分の操作を1人でするはきつかったです。1局分の操作をすると10分以上掛かっていました。
最後の方は、かなり虚無ってました。

### デバイスごとの違い
デバイスごとの挙動の違いは懸念していたほどではなかったのですが、canvasへの描画でAndroid端末のブラウザでは、画像データを半透明で描画することができないなどがありました。
それ以上に、モバイル端末とデスクトップ両対応のUI構築が大変でした。

### 操作説明
想定外に苦戦したのが操作説明の作成でした。
お仕事では１つの操作毎に機械的に説明を書いていけば良いのですが、個人開発のゲームの説明にそこまでの労力を割く気力がありませんでした。
個人開発のゲームやアプリの操作説明をちゃんと書いている人を尊敬します。

### 電気通信事業の届出
クローズド・チャットを提供する場合は、電気通信事業の届出が必要になるようです。
事業としてこのゲームを提供するつもりは無いのですが、念の為、届け出ました。
提出する書類の記述内容は簡単なのですが、事業の届出など普通の生活では行わないことをしたので提出時は緊張していました。

# 作ってみて
これまで自分で使うアプリなどは幾つか作っていましたが、他の人にも使ってもらうアプリは初めてでした。
UIの構築から操作説明の作成まで全て一人で作業していると、「使い難く無いだろうか」、「分かりにくく無いだろうか」などの不安に襲われ、何度も作成を中断しそうになりました。
普段、職場で気軽に意見を聞ける状態がどれだけありがたいか身にしみました。
コロナで他にやることもなかったので、なんとか作業を続けて身内への公開まで漕ぎ着けましたが、逆にコロナでなければモチベーションを保てなかったかもしれません。
そんなモチベーションの遷移も含めて良い経験になりました。
今後もFlutterを使ってWebアプリを作ろうと思っていますが、モチベーション維持とノウハウの蓄積のために小マメに記事を書いていこうかと思います。

なお、これまで身内で4回ほど遊びました。
ダラダラ喋りつつ、チョンボや点数計算どうやるか等でわちゃわちゃしながら遊ぶことができたので、このゲームでやりたかったことは達成できたかなぁと思います。

# あとがき
天鳳。。。
そっかぁ、アプリインストールもアカウント登録も不要なのか。
orz

以上
100日後くらいに個人開発するぞ！day059

## 今日はオーバーライドを学んでみた！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2632394/a2131416-9a1a-43d0-4d72-a88a929766ab.png)


## 今日の学び
### オーバーライド
* 親クラスにあるメソッドと同じ名前のメソッドを子クラスで定義するとメソッドを上書きすることができる
    * 例
        * `class Food < Menu`
        * :
        * ` def info→親クラスと同じメソッドを上書き`
        * :
        * ` end`
        * `end`
* 子クラスのインスタンスでは子クラスで定義したメソッドを優先して呼び出すため、親クラスに同名のメソッドがある場合は上書きされた子クラスのメソッドが優先的に呼び出される

### initializeメソッドのオーバーライド
* initializeメソッドも子クラスでオーバーライドできる
    * 例
        *` def initialize(name:,price:,calorie:)`
            * `self.name=name`
            * `self.price=price`
            * `self.calorie=calorie`
        * `end`
Ubuntuの環境でNeosVRでALVR経由でQuest2を使う方法

## 前提条件
下記がインストールされていること
・Steam
・SteamVR　（Steamからインストール）
・NeosVR（Steamからインストール）
・GPUドライバー

検証環境
・OS　Ubuntu　20.04LTS
・GPU　RTX3060
・GPUドライバー 515.48.07
・CPU　RyZen 7 5800X
・メモリ 32GB

## 参考にするサイト
ALVR
https://github.com/alvr-org/ALVR/wiki/Installation

ALVRダウンロード（検証時はV18.2.3）
https://github.com/alvr-org/ALVR/releases/tag/v18.2.3

# 必要な物をダウンロードする
・alvr_client_oculus_quest.apk
　Quest2にインストールに必要

・alvr_server_linux_portable.tar.gz
　Ubuntu側に使うソフト（Ubuntuの場合は_portableがつく方）

## Quest2にアプリをインストール
前提条件
　・開発者モードになっていること
　・接続するPCはQuest2との接続許可が完了していること
　・Ubuntuにadb がインストールが完了していること


・Quest2をUSBケーブルにつなぐ
・ `adb install alvr_client_oculus_quest.apk`

 インストールに成功するとQuest2で
 アイテムライブラリ→すべて→提供元不明→ALVR
 に表示する

## Ubuntuにalvrサーバをインストール
・ダウンロードしたalvr_server_linux_portable.tar.gzを解凍する
　`tar zxvf alvr_server_linux_portable.tar.gz`

## 接続方法
#### Quest2でALVRを起動
　Sercheing　for serverと表示されている

#### Ubuntuでalvr_serverを起動
　alvrを解凍したディレクトリで　`./bin/alvr_launcher` を実行

下記の画面が表示されたら「Trust」をクリック
![Screenshot from 2022-07-20 08-43-19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295814/b8d9c38b-2150-95e8-907b-febce856d2dd.png)

動作すると下記の画面が表示される
![Screenshot from 2022-07-20 08-44-45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295814/daf6308f-1fa8-ed99-c73e-92a9ae058644.png)
![Screenshot from 2022-07-20 08-45-43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295814/3ccd6a84-7a31-d8de-9f6a-1d6fb50a3521.png)




この後に、NeosVRを起動する。

こんな感じに動きます
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">🐧なのに手が自由に動かせる喜び <a href="https://t.co/I1X1iGQFL8">pic.twitter.com/I1X1iGQFL8</a></p>&mdash; ymn (@ymnbuild) <a href="https://twitter.com/ymnbuild/status/1549346678691352577?ref_src=twsrc%5Etfw">July 19, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

※Linuxで動かすと頭の上に🐧が表示されます

以上
AWS lightsail: Wordpress: All-in-One WP Migrationのアップロードサイズ変更方法

# まえがき
Wordpressには、[All-in-One WP Migration](https://ja.wordpress.org/plugins/all-in-one-wp-migration/)というプラグインがありますが、サーバー移行の際にとても簡単に移行を行うことができるプラグインです。
移行元Wordpressから移行ファイルをダウンロードして、移行先にアップロードするだけで完了します。

しかし、このプラグインには、デフォルトでファイルのアップロードサイズが**80MB**という制限がついています。
これは、プラグインをプレミアムプランにすれば、制限を解除できるようです。
しかし、公式のドキュメントを読むと難しいけど、自分で制限を上げることもできるよというように説明が書いてあります。
[その設定](https://help.servmask.com/2018/10/27/how-to-increase-maximum-upload-file-size-in-wordpress/)を試してみたのですが、効果がなかったです。異なる方法でできる方法を見つけたので、それを書いていきます。
設定をちょっと変えるだけなので、簡単でした。

# All-in-One WP Migrationのアップロードサイズ変更手順
1. All-in-One WP Migrationの管理画面からアップロードサイズ制限を確認
![スクリーンショット 2022-07-18 12.28.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280261/a4109dfe-40a8-de41-a5d4-f76f7eba087f.png)
Maxinum upload fie size: 80MBという記載が見て取れます。
2. lightsailからコンソールへアクセス
画像のWordPress-1の文字の横のターミナルアイコンをクリックしてください。
![スクリーンショット 2022-07-18 12.29.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280261/5ea9ef54-afbb-d007-b4dd-915f1d52cd0b.png)
すると、新しくブラウザが起動し、ターミナルへアクセスできます。
![スクリーンショット 2022-07-18 12.31.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280261/094280cf-1d69-6b6d-7bd6-46e0a7cf081f.png)
3. ターミナルを操作し、/opt/bitnami/php/etc/php.iniを次のように編集。サイズは任意で大丈夫です。
    ```ini:php.ini
    # 703行目
    post_max_size = 512M
    
    # 855行目
    upload_max_filesize = 512M
    ```
4. bitnamiを再起動する。
    ```bash:コンソール
    $ sudo /opt/bitnami/ctlscript.sh restart
    ```
5. All-in-One WP Migrationの管理画面からアップロードサイズ制限を確認
![スクリーンショット 2022-07-18 12.38.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280261/2da0473d-9d49-c3b3-67ca-29827b829b56.png)
Maxinum upload fie size: 80MBがMaxinum upload fie size: 512MBへ変わりました。
この状態であれば、80MBを超えるファイルでもアップロードできます。

# あとがき
All-in-One WP Migrationのアップロードサイズ変更方法の紹介でした。
また、lightsailは作成の手間もかからず、管理も楽になり、一番安いインスタンスなら月額$3.5と料金も安いので、とりあえず、ネット上にWordpressを作ってみたいという方は良いのではないでしょうか？
固定IP、ドメイン、SSL化など諸々を含めた場合の料金は未調査です。
Wordpressを立ち上げてくれるサービスは他にもあるので、それらとの検討も必要になるかと思います。
子の情報を親に参照させる質問


考えたら普通に分かりそうなんだけど、多い質問。　ローコードとかノーコードとかどうでもいいけど、データモデルについては学ばないと意味がないと思う。コーディング以前の問題です。

さて、私は英語が全く分からないので理論的に英語で回答することはまず不可能です。そのため回答例を集めておきたいと思います。
また長い質問はグーグルさんで訳しても理解できないので、回答できないです。

+ [Formula to connect Contact to Company](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000HEM1e)

No formula field is going to work for this scenario since Contact looks up to Account. Formula fields can only pull values from parent down to child, not the other way around. 

You could use DLRS to accomplish this. Flow can also do this.

連絡先はアカウントを検索するため、このシナリオでは数式フィールドは機能しません。数式フィールドは、親から子に値をプルすることしかできず、その逆はできません。

DLRSを使用してこれを実現できます。フローもこれを行うことができます。

-----------------------------------------------------------------

数式フィールドと同様に、行レベルの数式は、対象のデータ ソースの下にある子レコードを参照できません。取引先レポートでは、それが取引先であり、子商談は表示されません。

これを達成する唯一の方法は、取引先のカスタム フィールドを使用することです。おそらく、機会をカウントするロールアップ サマリーです。

[未処理の案件数の行レベルの式](https://trailhead.salesforce.com/en/trailblazer-community/feed/0D54S00000J6B9j)

# 自動化プロセスの実行順序を考慮した場合

これを見ると積上げ集計は入力規則の後だから使えない。　フローは前に行われるから大丈夫ですね。
DLRSはBefore　トリガー（？）だからこれも入力規則の前だから機能するということかな。

![image.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F125621%2F5dda31b7-cdc0-cafe-d672-bdce5ec36dc5.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&w=1400&fit=max&s=14964a751ec8660e2b3064802c279a37)


# アカウントの内の自己参照で子の合計金額を集計したい

[Hello, I´m trying to find the way to create a field in an account that summarize the sum of another field of the account childs. I cannot find the way to do it with rollup field, since I need to do it within the same object. Can anybody help me? Thank you](https://trailhead.salesforce.com/en/trailblazer-community/feed/0D54S00000ISwgwSAD)
VBAでプロシージャから別のプロシージャを呼ぶ

プロシージャーから別のプロシージャーを呼ぶにはCallを使います。

```
Sub S1()
    Range("A1") = 100
    Call S2
End Sub

Sub S2()
    Range("B1") = Range("A1") * 2
End Sub
```
JavaScript: Cookieから特定要素を見つけ出す際のトリム

jQuery.Cookieなどのラッピングされたものを使用する場合には、なんの考慮もいらないはずです。
裸のJavaScriptでハンドリングする場合に忘れがちなのがトリムです。
## サンプル
```JavaScript
function getCookie (key) {
  var cookies = document.cookie;
  var cookiesArray = cookies.split(';');
  for (var tuple of cookiesArray){
    var strArray = tuple.split('=');
    var str = strArray[0];
    if (str.trim() == key) {  // トリムしてあげましょう
      str = strArray[1];
      return str.trim();
    }
  }
  return '';
}
```
CやPerlなんかで書く場合には、まあ忘れることはないんですけどね。私の場合、JavaScriptの場合が特に油断しますね。
トリムのオーバーヘッドなんてわずかでしょうからね、私の場合は、要らないんじゃない？と思える場合でもとりあえずトリムしますよ。
【C++】基礎を学ぶ㉓～例外処理～

# 例外処理
**例外**（異常な事象）が発生した場合に実行するプログラムのこと

## 例外処理の使い方
例外処理は次の3つのキーワードを用いて実装します
* `try`
* `catch`
* `throw`

### `try`
**例外**が発生する**可能性のある**コードを`try{}`で囲う
各`try`ブロックには**1つ以上**の`catch`ブロックが存在する

### `catch`
**例外**を処理するコードを書きます
`catch`に続く`()`に例外の型を書きます

### `throw`
**例外**とその**値**を送るための構文

### サンプルプログラム
```cpp
#include <iostream>
using namespace std;

int main() {
  try
  {
    throw runtime_error("test");
  }
  catch(const runtime_error& e)
  {
    cout << e.what() << endl;
  }
  return 0;
}
```
```
test
```

### 例外の型
例外には様々な型が使用できる
```cpp
#include <iostream>
using namespace std;

int main() {
  try
  {
    throw 10;
  }
  catch(const int v)
  {
    cout << v << endl;
  }
  return 0;
}
```
```
10
```

### あらゆる例外を`catch`する
`catch(...)`と書くことであらゆる例外をcatchできる

```cpp
#include <iostream>
using namespace std;

int main() {
  try
  {
    throw runtime_error("test");
  }
  catch(...)
  {
    cout << "Unexpected exception was thrown." << endl;
  }
  return 0;
}
```
```
Unexpected exception was thrown.
```
TypeScript（JavaScript）のswitch文で「Unexpected lexical declaration in case block」

先日、以下のようなコード書いたところ、ESLintに「Unexpected lexical declaration in case block」と怒られました。

```ts
let input = 1

switch (input) {
  case 1:
    const message = '指定されたのは1です。'
    console.log(message)
    break;
  case 2:
    console.log('指定されたのは2です。')
    break;
  default:
    console.log('不明な数値が指定されました。')
    break;
}
```

元々は下記のようなコードだったのですが、メッセージを定数`message`に切り出したところ、エラーとなるようになってしまいました。

```ts
let input = 1

switch (input) {
  case 1:
    console.log('指定されたのは1です。')
    break;
  case 2:
    console.log('指定されたのは2です。')
    break;
  default:
    console.log('不明な数値が指定されました。')
    break;
}
```

調べてみたところ、case内で定数（const）、変数（let）、関数（function）、クラス（class）を定義する場合は、caseの中身を中括弧（{}）で囲まないといけないそうです（参考：[no-case-declarations](https://eslint.org/docs/latest/rules/no-case-declarations)）。

今回の場合だと、下記のようにすればエラーにならなくなります。

```ts
let input = 1

switch (input) {
  case 1: {
    const message = '指定されたのは1です。'
    console.log(message)
    break;
  }
  case 2:
    console.log('指定されたのは2です。')
    break;
  default:
    console.log('不明な数値が指定されました。')
    break;
}
```
forEach内でawaitはできない（JavaScript、TypeScript）

先日、TypeScriptでの実装で、すごく基本的なところでハマってしまったので、メモとして残しておきます。

TypeScript（JavaScript）で`forEach`内で`await`を記述したら、エラー（「'await' 式は、非同期関数内と、モジュールのトップレベルでのみ許可されます。」）となりました。

エラーとなったコードはこんなやつです。

```ts
const millisecs = [1000, 2000, 3000]
millisecs.forEach(millisec => {
  await sleep(millisec)
  console.log(millisec)
})
console.log('forEach完了')
```

`sleep()`関数はこんなもので、引数で指定した時刻（ミリ秒）処理を中断します。
```ts
async function sleep (millisec: number): Promise<void> {
  return new Promise(resolve => {
    setTimeout(resolve, millisec)
  })
}
```

Visual Studio Codeのクイックフィックスを利用したところ、「含まれている関数にasync修飾子を追加します」が候補にあったので、これを選択すると下記のようにコードが修正されました。

```ts
const millisecs = [1000, 2000, 3000]
millisecs.forEach(async millisec => { // クイックフィックスによってasyncが追加された
  await sleep(millisec)
  console.log(millisec)
})
console.log('forEach完了')
```

なるほど、`async`の付け忘れだったかと思い納得したのですが、実行してみると下記のような予想外の結果となりました。

```
forEach完了
1000 // 1秒後
2000 // さらに1秒後
3000 // さらに1秒後
```

予想していた結果はこうです。
```
1000 // 1秒後
2000 // さらに2秒後
3000 // さらに3秒後
forEach完了
```

調べてみたところ、mdn web docsに`forEach は同期関数を期待します。`との記載を見つけました。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach

ということで、`forEach`内に渡すコールバック関数は、同期関数でないとダメなようです。

繰り返し処理で非同期関数を扱いたい場合は、下記のように`for...of`か`Promise.all()`を使うということになります。
```ts
const millisecs = [1000, 2000, 3000]

// for...ofを使った場合
for (const millisec of millisecs) {
  await sleep(millisec)
  console.log(millisec)
}

// Promise.all()を使った場合
await Promise.all(millisecs.map(async millisec => {
  await sleep(millisec)
  console.log(millisec)
}))

console.log('forEach完了')
```

ただし、Promise.all()を使った場合はコールバック関数が並列で処理されるため、結果は以下のようになります。ご注意ください（@arimoo さんご指摘ありがとうございます）。
```
1000 // 1秒後
2000 // さらに1秒後
3000 // さらに1秒後
forEach完了
```

さらに、今回はsleepする時間に差があるためコールバック関数が順番に呼ばれているように見えますが、実際にはPromise.all()の場合、3回呼ばれるコールバック関数は並列で処理されるため、順序性は保証されない点をご注意ください（@ktz_alias さんご指摘ありがとうございます）。

# まとめ

今回の問題は非常に基本的ですが、結構ハマる人が多いようです。

`forEach`に限らず、コールバック関数が`await`されているかどうかはわからないので、コールバック関数には非同期関数を渡さないのが安全そうです。
古いPCにChromeOSFlexを入れたときの不具合

２機種に入れて、以下の不具合を確認しました。

`バージョン: 103.0.5060.132（Official Build） （64 ビット）`
で確認しています。
2022/7/20時点、Stableでの最新版です。

## Fujitsu Arrows Tab Q507/PE
### 不具合内容
音が出ない
→ Bluetoothヘッドセット等をペアリングして音が出ることは確認できました。
### 製品情報
https://jp.fujitsu.com/platform/pc/product/arrowstab/1708/q507pe/spec.html
### 補足情報
Atomプロセッサを使ったWindowsタブレットです。
音が出ない以外にも、動作が非常に遅いという難点があります。実用的には使えません。

## Fujitsu FUTRO MP702
### 不具合内容
無線LANが接続できない
→ 有線LANでは接続できます。
アクセスポイントを選んで接続する操作はできますが、接続するとエラーとなります。
### 製品情報
カタログしか見つけられませんでした。

https://jp.fujitsu.com/platform/pc/product/catalog/ctlg_futro_201206c.pdf
### 補足情報
Celeron 877 (Sandby Bridgeコア)を使ったシンクライアントです。
メモリを4GBに増強、ストレージを交換してあります。
この記事を執筆する程度には実用的に動作します。


## まとめ
インプレスに掲載されてた記事だと「2010年以降〜」の記述がありますが、当時のメインストリームだった機種での動作と捉えたほうが良さそうです。

https://forest.watch.impress.co.jp/docs/news/1425202.html

Googleで認証済みの機種リストが出ています。
Intel NUCの古いモデルでも第3世代Coreプロセッサなので、これより古い機種は諦めるということも考えたほうが良さそうです。

https://support.google.com/chromeosflex/answer/11513094

Windows 11に移行できない旧型のPCが比較的安く販売されているので、そうした機種で試すのにはちょうどいいかと思います。
ID毎に前回のフラグからの経過時間を求める(SPSS Modeler データ加工逆引き4-7)

# ID毎に前回フラグが立った時との時間差を求める（@&#xFFF0;SINCE）

![スクリーンショット 2022-07-12 15.41.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/365cb310-d8f8-708d-f1e6-6c05b48995c2.png)


## 1.想定される利用目的

・顧客の特定の行動までの間隔を特徴量にする
・設備ログから特定イベントの発生間隔を特徴量にする

## 2.サンプルストリームのダウンロード

https://github.com/yoichiro0903n/blue/blob/main/flag_interval.str?raw=true

## 3.サンプルストリームの説明

![スクリーンショット 2022-07-12 15.41.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/8f6c0c0e-bc42-ad40-20ca-04379ba652fd.png)

a.入力するデータは以下の通りです。ID(顧客/設備)が2種類存在します。
![スクリーンショット 2022-07-12 15.42.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/1a513d1c-25d5-a283-4998-7737553df64d.png)

b.[フィールド作成]ノードを編集します。[派生]モードを[条件付き]にします。[If]は自分のレコードにフラグが立っていて且つ前回フラグが立ったレコードが何行情報かを[@&#xFFF0;SINCE(ID,1)]で数えた上で、そのレコードを@&#xFFF0;OFFSETで指定してIDが一致する条件を記述しています。[Then]では前回のフラグが立っている時間と自分のレコードの差を求めています。該当しない場合はundefで欠損値にします。
![スクリーンショット 2022-07-12 15.42.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/a8cf1893-0c59-5f07-62cc-69143b08a194.png)

式ビルダーから@&#xFFF0;関数を探すと簡単に入力できます。
![スクリーンショット 2022-07-12 15.43.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/56ac9407-9829-f879-1dba-60fd8fff7608.png)

[プレビュー]します。ID毎の最初のフラグも欠損値になるのでゼロにします。
![スクリーンショット 2022-07-12 15.43.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/f295d277-e85b-be25-9d9d-f341f6c6f60a.png)

c.[置換]ノードを編集します。
![スクリーンショット 2022-07-12 15.43.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/63929582-7e7b-45d6-c0f9-3833601182e4.png)

[テーブル]ノードを実行します。完成しました。
![スクリーンショット 2022-07-12 15.44.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/a5c933f0-bc1e-c2a8-f31b-0e29d23ba9d7.png)

#### 注意点

@&#xFFF0;SINCEとの組み合わせのみで利用できる関数に@&#xFFF0;THISがあります。
同じフィールドが何行上方に存在するかを数で返します。存在しない場合には@&#xFFF0;INDEX+1になるため@&#xFFF0;OFFSET内で利用するとNullになるようになっています。

![スクリーンショット 2022-07-12 16.57.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/6bbb278c-b87f-d601-3525-9702c43bbeac.png)


7と9レコードだけ同じ時刻をもつレコードが上方にあるため、その行数を返しています。それ以外は@&#xFFF0;INDEX+1になっています。
![スクリーンショット 2022-07-12 16.56.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/4c0010b1-dcd6-44ce-dc33-279ee5327600.png)

## 4.参考情報

#### フィールド作成のカウント型を解説した記事

https://qiita.com/kawada2017/items/7b3c279963d39043214a#3m-%E3%82%AB%E3%82%A6%E3%83%B3%E3%83%88%E5%9E%8B%E3%82%B8%E3%82%B0%E3%82%B6%E3%82%B0%E3%82%92%E8%B5%B7%E3%81%93%E3%81%97%E3%81%9F%E7%B4%AF%E7%A9%8D%E5%9B%9E%E6%95%B0modeler%E7%89%88

#### SPSS Modeler ノードリファレンス目次

https://qiita.com/416nishimaki/private/503037195081d3323eee

#### SPSS Modeler 逆引きストリーム集（データ加工）

https://qiita.com/416nishimaki/private/4bf813e6cba84b2a1008
LeetCode easy: 1342. Number of Steps to Reduce a Number to Zero

LeetCodeを始めたので記録しています。

## 解いた問題

https://leetcode.com/problems/number-of-steps-to-reduce-a-number-to-zero/

>Given an integer num, return the number of steps to reduce it to zero.
>In one step, if the current number is even, you have to divide it by 2, otherwise, you have to subtract 1 from it.

## ざっくり処理の流れを考える
- while文でnumが0でない状態をtrueとして回す
- 奇数偶数判定をする
- それぞれの処理をしてnumに入れる
- numが0になったときの回数を返す

## 書いたコード
```
/**
 * @param {number} num
 * @return {number}
 */
var numberOfSteps = function(num) {
    steps = 0;
    while (num !== 0) {
        if (num%2){
            num--;
        } else {
            num/= 2;
        }
    steps ++;
    }
    steps;
};
```

>Runtime: 102 ms, faster than 22.64% of JavaScript online submissions for Number of Steps to Reduce a Number to Zero.
Memory Usage: 42 MB, less than 49.50% of JavaScript online submissions for Number of Steps to Reduce a Number to Zero.

## 調べたこと
JSの数字を真偽値として利用する際の注意点

https://kojimanotech.com/2020/09/26/253/

計算式の書き方
- プラス/マイナス１	
num++;
num--;

数字を四則演算して再代入
num[+-*/]= ２

修正はしていないけどTimeComplexityについて

https://qiita.com/cotrpepe/items/1f4c38cc9d3e3a5f5e9c

今回は繰り返しのたびに数字が小さくなる。
一番回数が増えるパターンは、/2と-1をずっと繰り返すようなもの。
`30 15 14 7 6 3 2 1`
「２で割る」と「１をひく」 がどちらも同じ回数でてくるため。
2 logn 
計算量では係数を取らないためO(logn)




## 答えを見て修正したこと
【入門】仮設検定を一枚絵で解説

最近、統計について考えることも出てきたので**仮説検定について一枚絵で整理**しました。昔、勉強したけど使っていないと忘れていますね。それにしても統計や機械学習の用語って、非常にとっつきにくいと感じるのは私だけでしょうか？

# 帰無仮説と対立仮説
## 帰無仮説(Null Hypothesis)
[帰無仮説(Null Hypothesis)](https://www.jspt.or.jp/ebpt_glossary/null-hypothesis.html)は、以下の説明がわかりやすいです。「帰無仮説」の「無」に注目して覚えれば良いでしょう。

> 帰無仮説（H0）とは，“**差がない**（差は0）”，“**関係がない**（相関が0）”などの無（＝0）を意味する仮説です．研究では通常，「運動療法前と比較して一定期間の運動療法後は，筋力が増強する」とか，「患者群の歩行速度は健常群の歩行速度よりも遅い」などの差（違い）を証明します．そのために統計的検定では“運動療法前後でも差がない”とか“患者群と健常群の歩行速度は差がない”などの帰無仮説を想定し，この仮説が成立する有意確率p値を求めます．有意確率が有意水準よりも小さければ（p<0.05のとき），対立仮説（H1）を採択する（差がある）という判断をします．

## 対立仮説(Alternative Hypothesis)
[対立仮説(Alternative Hypothesis)](https://www.jspt.or.jp/ebpt_glossary/alternative-hypothesis.html)
> 帰無仮説に対立する仮説（H1）です．反対（対立）の意味を持つ仮説なので，“**差がある**（差は0ではない）”，“**関係がある**（相関が0ではない）”などの意味を持つ仮説です．

# 一枚絵で整理
一枚絵で整理しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134273/5f4cb6b0-d29c-17e7-ada2-dc5e4d9810dc.png)

## 例
コインを投げて裏表を出した場合の例を一枚絵に書き込みました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134273/d3c53285-07a0-357b-6972-91207d3f60cd.png)

# 参考ページ
Python例もやろうと思いましたが力尽きました。リンクだけ。

https://qiita.com/g-k/items/520c236f23407fe6e767
database.ymlについて

# database.yml
データベスに接続するための設定ファイル。
YAML形式で記述されている。

#### 構成（中身）について
項目・・・	説明
adapter・・・	データベースの接続時に使用するアダプターの名前。
encoding・・・	文字コード
Pool・・・	コネクション数の上限
database・・・	データベース名
username・・・	データベースに接続するユーザー名
password・・・	データベースに接続するためのパスワード
host・・・	データベースが動作しているホスト名またはIPアドレス

### YAMLについて
構造化されたデータを表現するためのフォーマット。
ハッシュ形式（キー : 値）が利用される。
「エイリアス」と「アンカー」という機能を使い、共通化することができる。

使用方法としては、まず、共通化して使いたい箇所の親となるキーに「&エイリアス名」を書くことで、エイリアスを定義する。
次に、エイリアスを参照したいところで、「<<: *参照するエイリアス名」を書き、エイリアスの内容を使用することができる。

```
Ex.
// animal: &animal
//    cat: ‘ネコ’
//    dog: ‘イヌ’

// animal_shop_1:
//     <<: *animal
//     hamster: ‘ハムスター’

// animal_shop_2:
//     <<: *animal
//     parrot: ‘オウム’

上記のymlファイルを bin/rails c コマンドで実行すると、、、

$ bin/rails c
Running via Spring preloader in process 25096
Loading development environment (Rails 6.1.6.1)

irb(main):001:0> YAML.load_file('./example.yml')

=> {"animal"=>{"cat"=>"‘ネコ’", "dog"=>"‘イヌ’"}, "animal_shop_1"=>{"cat"=>"‘ネコ’", "dog"=>"‘イヌ’", "hamster"=>"‘ハムスター’"}, "animal_shop_2"=>{"cat"=>"‘ネコ’", "dog"=>"‘イヌ’", "parrot"=>"‘オウム’"}}

```
上記より、ymlファイルは実行することで、データをハッシュとして表示することができる。
エイリアスの設定方法【bash】【zsh】

## エイリアスの設定方法
`alias 別名= '実際に実行するコマンド'`と.zshrc`や`.bashrc`に記述することでエイリアスが設定できます。

```.zshrc:エイリアス設定例
alias g='git'
alias gst='git status'
alias gd='git diff'
alias gdc='git diff --cached'
alias gl='git pull'
alias gup='git pull --rebase'
alias gp='git push'
alias gd='git diff'

alias d=‘docker’
alias dc=‘docker-compose’
alias dcnt=‘docker container’
alias dcur=‘docker container ls -f status=running -l -q’
alias dexec=‘docker container exec -it $(dcur)’
alias dimg=‘docker image’
alias drun=‘docker container run —rm -d’
alias drunit=‘docker container run —rm -it’
alias dstop=‘docker container stop $(dcur)’

```
ModuleNotFoundError: No module named '_sysconfigdata_x86_64_conda_cos7_linux_gnu'

以下のエラーが発生したので解決策をメモ．

```shell
ModuleNotFoundError: No module named '_sysconfigdata_x86_64_conda_cos7_linux_gnu'
```

`_sysconfigdata_x86_64_conda_cos7_linux_gnu.py`という名前のファイルがどこかにあるか探す．

```shell
sudo find / -name _sysconfigdata_x86_64_conda_cos7_linux_gnu*
```

発見したら，それを `/home/anaconda3/lib/python3.8` の直下にコピーすれば解決する．
【Unity】自作リズムゲームに弐寺のようなソフランを実装してみる


## まず
Unityでリズムゲーム作っててめちゃくちゃ嫌だったこと。
それは、「ソフランなどと言ったギミックの情報が全く無いこと」でした。
色んなギミック譜面が作れるリズムゲームを作りたかったのに、一切その情報が無い。
なんでなん？みんな上から下に流れるだけで十分なん？？自作音ゲーの譜面を弐寺みたいにソフランさせたり、太鼓みたいに超高速でノーツ飛ばしたり、Ar〇aeaみたいに訳分からん動きさせたりしたくならないんか？？？

この記事は、「自作リズムゲームにギミックを搭載したい！でも何も分からん！！」な人達の助けになったら良いなという目的で作りました。悩んでる時間あったら手動かして欲しいしね。

## 目標とする挙動
↓こんな挙動を作りたい。
![testA.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2703207/743d2bc7-9b59-b62c-0d9b-b3b01cc9e897.gif)

## 作り方
下の画像で赤いノーツは等倍速度、青いノーツには0.25倍のソフランをかけたものです。
要はこういう配置になれば宜しいのです。
![202207180029.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2703207/91d0fc6b-b06c-ae4a-1e4c-0693738f6254.png)
### ノーツの座標の出し方
私がやったやり方としてはこんな感じ↓
1. ノーツがある小節を調べる。
1. 小節の座標と時間を調べる。
1. ソフランの値を取得する。
1. ノーツの時間から小節の時間を引く（これで小節内での時間になる）。
1. 4．で出た値を基準速度とソフランでかける。
1. ノーツ座標が出てくるのでそれを使用する。

                float softLanding;　　　//ソフランの値
                float baseSpeed;　　　　//基準となるスクロール速度
                float measureTiming;　　//小節の開始時刻
                float measurePos;　　　 //小節の座標
                float  noteTiming;　　　 //ノーツの判定時間
                float notePos;　　　　　//ノーツの座標
                
                var distance = (noteTiming - measureTiming);
                notePos     = measurePos + (distance * baseSpeed * softLanding);

### レーンのスクロールの仕方
小節の1拍目の座標から次の小節の座標まで、Lerpで動かしてあげるのです。
正規化の方法が地味に分からなかった。数学難しい……

                float musicTime;　　　   //曲の再生位置
                float measurePosBegin;　 //小節の座標
                float measurePosEnd;　 　//次の小節の座標
                float normalize;　 　　　//正規化


                normalize = (musicTime- measurePosBegin) / (measurePosEnd - measurePosBegin);
                Vector3.Lerp(measurePosBegin, measurePosEnd, normalize);
これらをListとかifやforを駆使して実装すれば、それっぽいものになると思います。
![testB.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2703207/c8fbef8c-4b81-12c5-dfca-8b83f0278a0c.gif)
見て、ノーツがぴょんぴょんしてるよ！かわいいね
## 終わり
書いてて思いましたけど、このコードまだまだ改装出来そうですね。
「小節とノーツの座標取得二度手間では？」とか、「baseSpeedを少し弄れば太鼓のソフランも実装出来そう」とか。
因みにスクロール方法ですが、今のままだと1/64拍子とかにしたら目に見えてカクついてしまう（処理落ちではない）ので、そこ含めて次リズムゲーム作った際には別の方法を模索してみようと思います。
もっとみんなリズムゲーム作れ、そして情報共有しろ
Flutterで天気を取得するAPI

天気を取得するAPIを発見したので紹介します。

今回使用するのはweatherというパッケージ。
早速パッケージをpubspec.ymlに追加していきます。
~~~
dependencies:
  weather: ^2.0.1
~~~

パッケージを追加したらOpenWeatherMapにサインインし、API keyを取得します。
情報を取得したい場所の緯度と経度を指定することで、結果が得られます。
緯度と経度の他にも、地名を指定する方法もあるようです。詳しくはDart公式ページにて
~~~dart:main.dart
import 'package:weather/weather.dart';
...
void getWeather() async {
  String key = "Your API key"
  double lat = 55.0111; //latitude(緯度)
  double lon = 15.0569; //longitude(経度)
  WeatherFactory wf = new WeatherFactory(key);
  
  Weather w = await wf.currentWeatherByLocation(lat, lon);
  
  print(w);
}
~~~

以下の結果が得られました。
~~~
flutter:     Place Name: Nexø [DK] (55.0111, 15.0569)
    Date: 2022-07-20 02:38:43.000
    Weather: Clouds, scattered clouds
    Temp: 21.0 Celsius, Temp (min): 21.0 Celsius, Temp (max): 21.0 Celsius,  Temp (feels like): 21.0 Celsius
    Sunrise: 2022-07-19 11:46:25.000, Sunset: 2022-07-20 04:25:18.000
    Wind: speed 0.51, degree: 260.0, gust null
    Weather Condition code: 802
~~~
Ubuntu20.04LST セットアップ備忘録

# ローカルでやること
- ipアドレスをGUIで固定しておく
- これ以降はSSH通信で操作可能
```
# パッケージのアップデート
sudo apt update && sudo apt upgrade

# SSHインストール
sudo apt install openssh-server
```

# ホームディレクトリの英語表記
- 日本語ディレクトリは色々不都合なので英語表記へ変更
- 必要がない場合はやらなくてもよい
```
# 現在の表記を確認
cat .config/user-dirs.dirs

# 英語表記へ変更
LANG=C xdg-user-dirs-update --force

# 英語表記になっていることを確認
cat .config/user-dirs.dirs

# 日本語ディレクトリが残っているので削除
rmdir デスクトップ ピクチャ ダウンロード テンプレート ドキュメント ビデオ ミュージック 公開
```

# SSHの公開鍵認証
- 接続するPCのid_rsa.pubをホームへコピー
- 新規接続にて公開鍵認証ができることを接続テストするまで、古い接続は切らないこと
```
# 鍵生成
ssh-keygen -t rsa

# 鍵の登録
cat id_rsa.pub >> ~/.ssh/authorized_keys

# 権限変更
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys

# 設定の変更
sudo vi /etc/ssh/sshd_config

# 設定内容
# ChallengeResponseAuthentication no
# PasswordAuthentication no

# デーモンの再起動
sudo /etc/init.d/ssh restart

rm id_rsa.pub
```

# Nvidia Driver
```
sudo apt install -y ubuntu-drivers-common

# インストール可能ドライバの確認
ubuntu-drivers devices

# recommendのついたバージョンをインストール (e.g. nvidia-driver-515)
sudo apt install -y --no-install-recommends {version}

# 再起動後、確認
sudo reboot now
nvidia-smi
```

# Cmake
```
# 必要パッケージのインストール
sudo apt update && sudo apt install build-essential checkinstall zlib1g-dev libssl-dev -y

# リポジトリ(https://github.com/Kitware/CMake/releases)へアクセスして、最新のものを指定することダウンロードする
# e.g. https://github.com/Kitware/CMake/releases/download/v3.24.0-rc3/cmake-3.24.0-rc3.tar.gz
mkdir cmake_install && cd cmake_install
wget {URL}

# 解凍
tar -zxvf {file_name}

# ブートストラップ
cd {dir_name}
sudo ./bootstrap

# ビルド&インストール
sudo make && sudo make install

# インストール確認
cd ~
cmake --version

# 後処理
sudo rm -rf cmake_install/
```

# Docker 
- Docker Engineのインストールは[公式ドキュメント](https://docs.docker.com/engine/install/ubuntu/)参照(すごい分かりやすい)
- Nvidia Dockerのインストールは[公式ドキュメント](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html)参照(すごい分かりやすい)

```
# Docker Engineインストール

# ユーザー権限追加
sudo groupadd docker
sudo gpasswd -a $USER docker
sudo service docker restart
sudo reboot now

# NvidiaDocker2インストール
```

# Python
```
sudo apt update && sudo apt install -y python3.8-dev python3.8-distutils python3-pip 
```

# Git
```
git config --global user.name {user_name}
git config --global user.email {user_mail}
```
覚えがき:muzikdarts.comからの見知らぬクレジットカードの請求

ふと、クレジットカードの請求を見ると、見知らぬ請求があったので、色々調べとりあえず解約してみた。
そもそも、どうやってこれに入会したのかは謎のまま。

見覚えのない請求名: 「muzikdarts.com 利用国 GBR」

muzikdarts.com にアクセスすると音楽配信サイトとなっているようで、日頃使っているメアドとパスワードでログインできた。（当然、このようなサイトに登録した覚えはないが…）

解約の画面があったので、速攻で解約を実施。
結果として、5,6,7月分の利用料が請求され、泣き寝入りの状態。
早く気づいたから、良かったがこのまま放置してたら、毎月6000強の金額が引き落とされ続けてたことに…

しばらくは様子見とします。

同様の被害を受けた方は、コメント下さい。
「オブジェクト'Left'のメソッド'_Application'が失敗しました。」の解決方法

# 結論

Applicationオブジェクトのプロパティを使ったエラーの場合、ActiveWindow等のウィンドウのオブジェクトのプロパティに対して処理する。

```vb
    Application.Left = 5
    Application.Top = 0
    Application.Width = 727.714285714286
    Application.Height = 910.857142857143
```

↓

```
    With ActiveWindow
        .Left = 20
        .Top = 0
        .Width = 727.714285714286
        .Height = 910.857142857143
    End With
```

# 経緯
macOSのExcelでウィンドウの制御をしていたところ、「オブジェクト'Left'のメソッド'_Application'が失敗しました。」というエラーが出て処理が進まなくて困っていた。
```vb
    Application.Left = 5
    Application.Top = 0
    Application.Width = 727.714285714286
    Application.Height = 910.857142857143
```

![スクリーンショット 2022-07-20 1.30.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/288/ff8149f4-919e-c186-75aa-af6c0d08a147.png)

Windowsだと何もエラーが出なかったのに、macOSだと出るエラーで困った。

ふと、なんで自分はApplicationオブジェクトのLeftプロパティに代入しているのかなと思った。ウィンドウの制御なのに、ApplicationオブジェクトのLeftプロパティを使っている。

試しに普通のウィンドウ制御を調べてみると以下のような書き方をしていた。

```
With ActiveWindow 
 .WindowState = xlNormal 
 .Top = 1 
 .Left = 1 
 .Height = Application.UsableHeight 
 .Width = Application.UsableWidth 
End With
```

こんな風に書くために以下のようにするとエラーが出なくなって処理が正常に動いた。

```
    With ActiveWindow
        .Left = 20
        .Top = 0
        .Width = 727.714285714286
        .Height = 910.857142857143
    End With
```

とりあえず閃いてよかった。

# 参考
[Application.Width プロパティ (Excel) | Microsoft Docs](https://docs.microsoft.com/ja-jp/office/vba/api/excel.application.width)
分散表現の可視化はwhatliesが楽

# はじめに
https://github.com/koaning/whatlies

BERTやWord2Vecの分散表現の可視化がインタラクティブでできるライブラリです。
transformersやgensimのimportも不要です。

バージョン：`whatlies==0.6.3`

実行ノートブック：

https://colab.research.google.com/github/sentencebird/google-colab-notebooks/blob/main/bert_whatlies.ipynb

# 分散表現空間
```python
from whatlies import EmbeddingSet
from whatlies.language import HFTransformersLanguage
from whatlies.transformers import Pca

lang = HFTransformersLanguage('cl-tohoku/bert-base-japanese-whole-word-masking')

words = ["先生", "教師", "学生", "社員", "研究者", "会社員", "医者", "銀行員"]
emb = EmbeddingSet(*[lang[w] for w in words])
emb.transform(Pca(2))
emb.plot_interactive()
"""widthとheightも設定できる
res = emb.plot_interactive()
res.config = {"view": {"continuousWidth": 1500, "continuousHeight": 1500}}
"""
```
![visualization.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638747/2bf7ca81-42d8-69c7-6929-f5fd1fc89e2f.png)

# ベクトル
```python
lang["男"].plot(kind="arrow")
lang["女"].plot(kind="arrow")
lang["王"].plot(kind="arrow")
```
![Unknown.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638747/4c641d35-bd36-b57e-dc4c-2ec2942c3b86.png)



# 参考
- https://hiromu-nlp.com/whatlies-introduction/
ConoHa WINGにEC-CUBEをサクッとインストール

# 新規ドメイン、ディレクトリ、データベース作成

ConoHa管理画面

サーバー管理＞ドメイン＞「＋ドメイン」＞　サブドメインを追加　＞　無料独自SSL利用する　＞　保存=>自動でディレクトリ作られる

サイト管理＞「切り替え」ボタン→新規ディレクトリで「切り替え」＞データベース＞「＋データベース」＞データベース名、ネームタグ入力→保存
サイト管理＞データベース＞ユーザー選択＞接続先データベース「設定」＞一番下の「＋」＞保存

サーバー管理＞ドメイン＞作成したドメイン　
ステータス：「設定中」→「稼働中」を確認する
独自SSL：[設定中」→「利用中」を確認する

# FTPファイルアップ
FTPサーバーでeccube-x.x.x.tar.gzをルートディレクトリにアップロード

# SSHでインストール
SSHでアクセス
現在位置を取得

```
$ pwd

/home/ユーザー名/public_html
```

eccube-x.x.x.tar.gzあるディレクトリまでcd

```
$ cd /home/ユーザー名/public_html/eccube-root
```
gzファイルを解凍

```
$ tar -xvf eccube-x.x.x.tar.gz
```

eccube-x.x.x内に移動

```
$ cd /home/ユーザー名/public_html/eccube-root/eccube-x.x.x
```

ファイルを隠しファイルも含めてeccube-x.x.xからeccube-rootに移動

```
mv * .[^\.]* /home/ユーザー名/public_html/eccube-root
rmdir /home/ユーザー名/public_html/eccube-root/eccube-x.x.x
rm /home/ユーザー名/public_html/eccube-root/eccube-x.x.x.tar.gz
```
# ブラウザ確認＆インストール
SSL設定が終わっていることを確認

フロントページ
`https://example.com/`
管理画面
`https://example.com/admin/login`
ログインID：`admin`
パスワード：`password`

### アクセスできなかったら
![スクリーンショット 2022-12-05 9.32.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1653133/d2e583c7-a8f5-2e7a-a20c-0cefeab24be4.png)

```:#&nbsp;/var/www/html/example.com/.env
（ドメインでアクセスの場合）
TRUSTED_HOSTS=^example\.com$

（IPアドレスでアクセスの場合）
TRUSTED_HOSTS=^xxx\.xxx\.xxx\.xxx$
```

### EC-CUBEインストール
インストールする

# WAF対策

ConoHaのIPアドレスを調べる
管理画面＞サーバー管理＞契約情報＞サーバー情報＞スペック

`.htaccess`　に以下を追記

```:vim&nbsp;root/.htaccess
RewriteRule ^(.*) - [E=HTTPS:on]

<IfModule mod_siteguard.c>
SiteGuard_User_ExcludeSig ip(1.2.3.4)
SiteGuard_User_ExcludeSig ip(xx.xx.xx.xx)
</IfModule>
```

# パーミッション設定

一般ディレクトリ　705

```
find /var/www/html/example.com -type d -exec chmod 705 {} +
```

一般ファイル 604

```
find /var/www/html/example.com -type f -exec chmod 604 {} +
```

以下ディレクトリ　707

```
chmod 707 /var/www/html/example.com/
chmod 707 /var/www/html/example.com/app/
chmod 707 /var/www/html/example.com/app/Plugin/
chmod 707 /var/www/html/example.com/app/PluginData/
chmod 707 /var/www/html/example.com/app/proxy/
chmod 707 /var/www/html/example.com/app/template/
chmod 707 /var/www/html/example.com/html/
chmod 707 /var/www/html/example.com/var/
chmod 707 /var/www/html/example.com/vendor/
```

以下ファイル 606

```
chmod 606 /var/www/html/example.com/composer.json
chmod 606 /var/www/html/example.com/composer.lock
```

以下ファイル 400

```
chmod 400 /var/www/html/example.com/.env
chmod 400 /var/www/html/example.com/.htaccess
```


# サイト設定
### ログインフォルダ名を憶測されにくいものに変更
管理画面＞設定＞システム設定＞セキュリティ管理
管理画面URL`hoge`
SSLを強制`✔︎`
管理画面URLが`https://example.com/hoge/login`に変更された

### ログイン情報を変更
管理画面＞設定＞システム設定＞メンバー管理

### 店舗設定
管理画面＞店舗設定＞基本設定


***
# 参考記事
https://xoops.ec-cube.net/modules/newbb/viewtopic.php?topic_id=25991&forum=11
python デジタルフォトフレームの作り方 -tkinter-

<H1>7秒ごとに写真を変えていく</H1>

```python
import tkinter

pnum = 0
def photograph():
  global pnum
  canvas.delete("PH")
  canvas.create_image(400,300,image=photo[pnum], tag="PH")#400 canvas内の画像の位置。x座標 300 canvas内の画像の位置。y座標。
  pnum = pnum + 1
  if pnum >= len(photo):
    pnum = 0
  root.after(7000, photograph)

root = tkinter.Tk()
root.title("デジタルフォト")
canvas = tkinter.Canvas(width=800, height=600)
canvas.pack()
photo = [
  tkinter.PhotoImage(file="cat5.png"), #pngじゃないとダメっぽい
  tkinter.PhotoImage(file="****.png"),
  tkinter.PhotoImage(file="****.png"),
  tkinter.PhotoImage(file="****.png")
]
photograph()
root.mainloop()
```
![スクリーンショット 2022-07-20 0.28.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1614609/be29cf8a-e820-57ee-1452-4f4c141c89f8.png)
HTML + JavaScript: 見出しやボタンなどの表示文字列を統一させたいとき

とあるシステムに登場する複数のWEB画面のあいだで、見出しやボタンの表示文字列を統一させたい場合に、私が使う手法のひとつがこれです。
いろんな方が、これと同じような手法をとられていると思います。かな？
## サンプル
JavaScript側からです。これを各HTMLにインクルードして使います。
```JavaScript
// JavaScript
function label_print () {
  var arrVar = {
    label_lastname: "姓",
    label_firstname: "名",
    label_birthday: "生年月日",
  };
  var arrVarButton = {
    button_save: "保存",
    button_cancel: "キャンセル",
  };
  for (let key in arrVar) {
    if(document.getElementById(key) != null) {
      $('#' + key).html(arrVar[key]);
    }
  }
  for (let key in arrVarButton) {
    if(document.getElementById(key) != null) {
      $('#' + key).val(arrVarButton[key]);
    }
  }
}
```
HTML側です。
```HTML
<!-- HTML -->
  ...
  <body class="" onload="label_print();">
  ...
    <td class="label" style="white-space: nowrap;">
      <div id="label_lastname"></div>
    </td>
  ...  
```
サーバ・サイドで、データベースなどを用いて処理する手法もあったり、いろんな手法があっていずれも賛否両論だと思います。上記はレガシーで単純、必要なパーツも少なく取り回しが楽ですね。Simple is best.
Reactのカスタムフックを定義する時には型に注意！

## 最初から結論

カスタムフック自体に型をつけてなかったから、定義したカスタムフックを別のコンポーネントでimportした時に型関連のエラーが出てた

-> カスタムフック自体に戻り値の型をつければ万事解決！！

```TS
// この部分
type funcs = {
  setTimer: () => void;
  resetTimer: () => void;
};
type Timer = [number, funcs];

export const useTimer = (): Timer => {
  const [time, setTime] = useState<number>(0);
  const setTimer = (): void => {};
  const resetTimer = (): void => {};
  // （中略）
  return [ time, { setTimer, resetTimer } ];
}
```

## まとめ
考えてみれば当然って感じですね。
コンポーネント・関数の型定義は、暗黙的な型変換に頼ることが多かったので気付くのが遅れちゃいました…

もし、僕と同じく暗黙的な型変換をよく使う人がいたらこんなエラーがあったことを頭の片隅に入れてもらえたら幸いです。
【Swift】ローカルのHTMLとCSSをWebViewに表示する

# はじめに
今回はローカルにある`index.html`と`style.css`をWKWebViewで読み込む方法を紹介します。
![スクリーンショット 2022-07-19 23.26.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/956022c2-4583-5f1c-d0ac-11ba2e815651.png)

# 実装
```index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="style.css">
    <title>Document</title>
</head>
<body>
    <div class="box26">
        <span class="box-title">POINT</span>
        <p>これはSwiftのWKWebViewでローカルにあるHTMLとCSSを読み込むテストです。</p>
    </div>
</body>
</html>
```

```style.css
.box26 {
    position: relative;
    margin: 2em 0;
    padding: 0.5em 1em;
    border: solid 3px #95ccff;
    border-radius: 8px;
}
.box26 .box-title {
    position: absolute;
    display: inline-block;
    top: -13px;
    left: 10px;
    padding: 0 9px;
    line-height: 1;
    font-size: 19px;
    background: #FFF;
    color: #95ccff;
    font-weight: bold;
}
.box26 p {
    margin: 0; 
    padding: 0;
}
```

```ViewController.swift
import UIKit
import WebKit

class ViewController: UIViewController {
    var webView: WKWebView!
    override func viewDidLoad() {
        super.viewDidLoad()

        webView = WKWebView(frame: view.frame)

        view.addSubview(webView)

        // MARK: HTML
        /// HTMLのファイルURLを取得する
        guard let html = Bundle.main.url(forResource: "index", withExtension: "html")  else { return }
        /// ファイルURLからファイルの内容をStringで取得
        guard let htmlString = try? String(contentsOf: html) else { return }

        // MARK: CSS
        /// CSSのファイルURLを取得する
        guard let css = Bundle.main.url(forResource: "style", withExtension: "css")  else { return }

        // MARK: 読み込み
        webView.loadHTMLString(htmlString, baseURL: css)

    }

}
```

||||
|-|-|-|
|❌ HTML|✅ HTML|✅ HTML|
|❌ CSS|❌ CSS|✅ CSS|
|![simulator_screenshot_46B22246-22AD-412C-9105-D7D7C035B407.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/051f0ac5-489b-8622-9326-54f2c9fe4782.png)|![simulator_screenshot_387B14DD-8747-4B23-8726-07E4BD908DDA.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/d14c3c32-0cbe-e292-62b2-a3910460f2a1.png)|![simulator_screenshot_D0F6AA31-9514-4F93-9965-9612CF73D573.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/47e94cc4-1eea-c648-4f20-abe8aac64f64.png)|

# おわり
WKWebViewでローカルファイルを表示したのは初めてだったのでまとめてみました。
STM32G031で時間関数と繰り返しタイマー割込みで遊ぶ(1秒)



x OBでPA2をGPIOがわかる人むけ

目的
簡易な時間づくり



leafonyさんのページより引用



![o_con362.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/dadeb52e-f6f4-2503-884f-cf0341955f62.jpeg)





![o_con585.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/248bf620-3c19-59dc-5875-0b0c58a87eb7.jpeg)




参考

STM32 MCU の Arduino IDE 設定


https://docs.leafony.com/docs/environment/stm32/arduino_ide/



SER_time_test2_031_1


```c++



#include <Arduino.h>
#include <time.h>

#define LOOP_INTERVAL 1000000
#define BOARD_LED_PIN PA11

HardwareTimer *timer2 = new HardwareTimer (TIM2);

//time_t seconds = 0 + (60 * 60 * 9); // JST
time_t seconds = (60*60*24*365) - (60 * 60 * 9) ; // JST

//二桁の変換
#define DIV10(n) ((n*205)>>11)
char data1[16];
char *itoa99(int n) {


  data1[0] = '0' + DIV10(n);                        // n / 10
  data1[1] = '0' + (  n - ((data1[0] - '0') * 10) ); // n % 10
  data1[2] =  0;

  return (data1);

}//itoa99

void setup() {

  delay(3000); //not delete

  //シリアルの初期化
  Serial.setTx(PA2_ALT1);
  Serial.setHalfDuplex();
  Serial.begin(9600);

  pinMode(BOARD_LED_PIN, OUTPUT);

  timer2->setOverflow(LOOP_INTERVAL, MICROSEC_FORMAT);       // 125ms
  timer2->attachInterrupt(intTimer);
  timer2->resume();

}

struct tm *t;
struct tm tm;

void loop() {

  //t = localtime(&seconds);

  int tj = seconds;

  tm.tm_hour = ( (tj / 3600 + 9) % 24);
  tm.tm_min =  (tj / 60 % 60);
  tm.tm_sec =  (tj % 60);

  t = &tm;

  //    Serial.print(         t->tm_year + 1900 );
  //    Serial.print( itoa99( t->tm_mon + 1 ) );
  //    Serial.print( itoa99( t->tm_mday    ) );
  //    Serial.print( ' ' );
  Serial.print( itoa99( t->tm_hour    ) ); Serial.print( ':' );
  Serial.print( itoa99( t->tm_min     ) ); Serial.print( ':' );
  Serial.print( itoa99( t->tm_sec     ) );

  Serial.printf("\r\n");

  delay(1000);

}

void intTimer(void) {

  static int LEDstate = 0;
  digitalWrite( BOARD_LED_PIN, LEDstate);
  if ( 0 < LEDstate )
  {
    LEDstate = 0;
  } else {
    LEDstate = 1;
  }

  seconds++;

}



```
仮想通貨 ブロックチェーン　入門 その2

## 仮想通貨における暗号技術
通常、通貨には偽造防止技術が施されています。**バイカラー・クラッド**、**異形斜めギザ**、**微細文字**、**すき入れ**、**すき入れバーパターン**、**ホログラム** etc... しかしながら、これらの技術を使っても完全に偽造不能にすることはできません。最終的には、法的な規制が必要です。
しかしながら、仮想通貨のセキュリティルールは、純粋な技術的な強制が必要で、暗号理論を多用しています。
### 暗号学的ハッシュ関数
まずハッシュ関数のポイントは以下3点
- 任意のサイズの任意の文字列を入力として使える
- 決められたサイズの出力を生成する
- 効率的に計算できる
これは、数学的に言えば、nビットの文字列のハッシュ計算にかかる時間はO(n)で表せるってこと

暗号的なハッシュ関数はこれらに以下３つの属性が必要です。
- **衝突耐性**(collision resistance) 
これは、２つの値x,yがx≠yでありながら、H(x)=H(y)であるようなものをけして見つけられない場合、ハッシュ関数は衝突耐性があるってこと。「**見つけられない**」と表現した理由は、厳密には、入力空間のほうが大きいので、衝突が存在しないわけではないためです。衝突耐性が難しい理由はこれで、この辺は別記事でまとめていきたいです。

- **秘匿性**(hiding)
ハッシュ関数の出力y=H(x)が与えられたとき、入力のxを明らかにする現実的な方法がないってこと。この秘匿性を実現するためには、xの正解候補の値が存在してはいけない訳で、ｘの集合は大きく散らばっていなければいけない。

- **パズル親和性**(puzzle friendiliness)
y = H(x)となるyが与えられたとき，xを導くのが難しいってこと。要するにハッシュ値から入力の一部を特定するために，多くの計算コストを要するという性質です。

[仮想通貨 ブロックチェーン　入門 その1](https://qiita.com/sharpman/items/aa9d184cae14733cc60b)
HaskellプロジェクトをすぐにIDE (VSCode+Haskell Language Server) 化する

# 手軽に Haskell を Visual Studio Code (w/Haskell Language Server) 環境で使いたい

昨今の Haskell 環境は [GHCup](https://www.haskell.org/ghcup/) をインストールするだけで手軽に VS Code + Haskell Language Server (Haskell LSP) 上での full-fledged なIDE/開発環境が手に入る． とはいえこれは Stack か Cabal といったツールでの最低限のセットアップが必要で，私のように偶にしか Haskell を触らない者にはそれすらも少々面倒である．

そこで，Haskell Stack や Cabal を使わない， `ghc --make` 一つでできているプロジェクトを手軽に最新の VSCode + Haskell LSP 環境でブラウズできるようにする方法を紹介する．


# hie.yaml と hie-bios と Haskell LSP

VSCode の Haskell 開発環境のバックエンドである [Haskell Language Server のドキュメントによれば](https://haskell-language-server.readthedocs.io/en/latest/configuration.html#configuring-your-project-build), プロジェクトの設定を検出するのは [hie-bios](https://github.com/haskell/hie-bios) というコンポーネントが担当している． (hie は Haskell IDE Engine の頭文字で，Haskell Language Server の前身であったようだ．)
[hie-bios](https://github.com/haskell/hie-bios) の README にあるように， hie-bios は `hie.yaml` に設定を書けば明示的にプロジェクトの設定を Haskell Language Server に知らせることができる． その設定は Stack, Cabal のほかに Bios (より詳細な設定) と Direct がある．

## hie-bios の Direct 設定

このうち [Direct](https://github.com/haskell/hie-bios#direct) を使えば，手元の非 Stack・非 Cabal のプロジェクトでも平易に Haskell LSP の恩恵を得ることができる．

例えば，次のようにコンパイルされる Haskell コードを考える：

```sh
ghc --make -package mtl -package split A.hs B.hs
```

すなわち A.hs と B.hs からなり， `mtl` パッケージと `split` パッケージに依存するプロジェクトである．
こういったコードを VS Code で編集するには，次の内容をもつ `hie.yaml` をプロジェクトルートにおいて VSCode で開けばよい：

```yaml
cradle:
  direct:
    arguments:
      - "-package"
      -  "mtl"
      - "-package"
      - "split"
      - "A.hs"
      - "B.hs"
```

必要に応じて Haskell LSP をリスタート (Ctrl-P -> Haskell と入力すれば選択肢が現れる) すれば反映される．

# 所感
自分でごく短いコードを試すほか，誰かから渡されたレガシーな Haskell コードを調べなければならない場合にもこの方法は有効だと思う．

とはいえこの方法はファイルが増えるたびに `hie.yaml` の編集が必要になる．
プロジェクトが複数のファイルから構成されるようなったら，早々に Stack か Cabal を使う方法に切り替えたほうがよさそうだ．
ローミング とは

## 勉強前イメージ

なんかで見たことある気がする・・・？

## 調査

### ローミング とは

roamingとは英語で宛もなく歩き回るという意味で、通信事業者のサービスで契約している事業者の範囲外であっても
提携している事業者の回線を利用して同じサービスを受けれるようなものを指します。
基本的には携帯電話のローミングを指している場合が多い。
機器の設定でオンオフができるが、基本的には自動的に契約している事業者の電波が使えないようになったら
提携している事業者の回線に切り替わることが多いです。

国外でも同様のローミングサービスを使えることがあり、特に国際ローミングと言われることがあります。
ローミングは契約している事業者以外の通信設備を使用するので追加料金がかかったりします。

## 勉強後イメージ

そういえばスマホとかでみたことあるかも。
通信自体は海外でもできるのか・・・
どんな仕組みかは知りたい、、、

## 参考

- [ローミング 【roaming】 ローミングサービス](https://e-words.jp/w/%E3%83%AD%E3%83%BC%E3%83%9F%E3%83%B3%E3%82%B0.html)
【Rust】Actix Webで静的ファイルを扱う

## 概要
RustのWebフレームワークActix Webでは、テンプレートエンジンはあるのですが、別途静的なファイル（HTMLファイル）を置いておきたいという場合もあると思います。
Actix Webで静的ファイルを扱う場合のメモ書きです。

## 対応
actix-webのリポジトリにあるクレートで[actix_files](https://docs.rs/actix-files/latest/actix_files/)というのがあるので、これを使うのがベターかなと思います。
actix_filesで出来ることとしては[Static Files](https://actix.rs/docs/static-files/)のページにある通り、個別に公開したいファイルを指定したりディレクトリ配下を公開できたりします。

## 実装サンプル
ディレクトリ配下のファイルを公開する、実装サンプルを紹介します。
前提として以下のようなディレクトリ構成とし、`asset`配下のファイルを公開するものとします。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32098/f63be089-2622-4b3c-e2ff-052a47192f18.png" width=250 />

以下がmainの実装です。該当箇所にコメントを入れています。
なお、公開したファイルをにアクセスするURLパスは`/contents`とします。

```rust
#[actix_web::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| {
        App::new()
            // ここが静的ファイルを設定している箇所。assetディレクトリの配下を「/contents」のURLパスで公開。
            .service(fs::Files::new("/contents", "asset/").show_files_listing())
            .service(controller::sample_controller::get_sample_info)
    })
    .bind(("0.0.0.0", 8080))?
    .run()
    .await
}
```
ReactNativeでビルド時にスクリプトを実行させる方法

## やりたいこと

- ビルド時にビルド日時やコミットハッシュなどの情報を何かしらのファイルに吐かせたい

## やり方

やり方は色々あるのだが、Xcode/AndroidStudioからのビルド・実行、コマンドラインからのビルド・実行両方で必ず実行したい場合、方法は限られると思う。

### Xcode

- Build Phasesでスクリプトを実行する方法

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213719/4b6c1f89-8eb7-329c-9684-927463624bcd.png)

上記のようにBuild Phasesで`New Run Script Phase`を行いスクリプト実行を行わせる。ここはXcode、コマンドライン共に実行される箇所なので、ビルドすれば必ず行われる。`${PROJECT_DIR}`でiosディレクトリを取得できるので、それ経由でpackage.jsonがあるディレクトリに移動し、npm scriptsを実行すると良い。

- SchemeのPre-actionsで実行させる方法

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213719/603c21ac-6332-7846-8794-09e55262d95e.png)

ビルド前に実行させるスクリプトをPre-actionsに書く事が出来る。react-native-configなんかはここでenvファイルをコピーするようにしていると思う。ここにも任意のスクリプトが書けるので方法としてはありなのだが、全てのSchemeに書かないといけないのでやや面倒くさい。

### Android Studio

- Gradleで実行させる方法

`android/app/build.gradle`に下記のような記述を追加する。

```gradle
task runAnyScript(type: Exec, description: 'Run any script') {
    workingDir "$rootDir/../"
    commandLine 'yarn', '...'
}
preBuild.dependsOn runAnyScript
```

これでビルド前に任意の処理を挟めるようになる。Gradleの処理として書く事で、AndroidStudio、コマンドライン共に実行するようにできる。