OmniAICreator/Qiita-1.07M huggingface dataset:
moduleでのclass provide

モジュールでinterfaceへのclass provide
app sideのmodule-info.javaでuse app.SampleInterfaceでinterface宣言
provide sideのmodule-info.javaでprovides app.SampleInterface with lib.SampleImplでprovide

```app\module-info.java
module App {
    exports app;
    uses app.SampleInterface;
}
```
```app\app.App.java
package app;

import java.util.Iterator;
import java.util.ServiceLoader;

/**
 *
 * @author java
 */
public class App {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        Iterator<SampleInterface> i = ServiceLoader.load(SampleInterface.class).iterator();
        while(i.hasNext()) {
            SampleInterface s = i.next();
            System.out.println(s.method());
        }
    }
    
}
```
```app\app.SampleInterface.java
package app;

/**
 *
 * @author java
 */
public interface SampleInterface {
    public String method();
}
```
```lib\module-info.java
module Lib {
    exports lib;
    requires App;
    provides app.SampleInterface with lib.SampleImpl;
}
```
```lib\lib.SampleImpl.java
package lib;

import app.SampleInterface;

/**
 *
 * @author java
 */
public class SampleImpl implements SampleInterface{
    @Override
    public String method() {
        return "i am SampleImpl";
    }
}
```
実行結果
```
i am SampleImpl
```
Python3: MariaDB のバージョンを表示

## プログラム

フォルダー構造

```text
$ tree -a
.
├── .env
├── config_mariadb.py
└── server_version.py
```

```py:server_version.py
#! /usr/bin/python
#
#	server_version.py
#
#					Feb/22/2023
# --------------------------------------------------------
import	mariadb
import	sys
#
from config_mariadb import config_mariadb_proc
# --------------------------------------------------------
sys.stderr.write("*** 開始 ***\n")
#
host,user,password,data_base = config_mariadb_proc()
conn = mariadb.connect(user=user, password=password, \
                              host=host,database=data_base)
#
cursor = conn.cursor ()
#
cursor.execute ("SELECT VERSION ()")
#
row = cursor.fetchone ()
print (row[0])
#
cursor.close ()
conn.close ()
#
sys.stderr.write("*** 終了 ***\n")
#
# --------------------------------------------------------
```

```py:config_mariadb.py
#! /usr/bin/python
#
#	config_mariadb.py
#
#					Feb/22/2023
# --------------------------------------------------------
import os
from dotenv import load_dotenv
#
# --------------------------------------------------------
def config_mariadb_proc():
	dotenv_path = '.env'
	load_dotenv(dotenv_path)
	host = os.environ.get("host")
	user = os.environ.get("user")
	password = os.environ.get("password")
	data_base = os.environ.get("data_base")
#
	return	host,user,password,data_base
# --------------------------------------------------------
```

```text:.env
host = 'localhost'
user = 'scott'
password = 'tiger123'
data_base = 'city'
```

## 実行結果

```text
$ ./server_version.py 
*** 開始 ***
10.11.2-MariaDB
*** 終了 ***
```

## 参考ページ

[How to connect Python programs to MariaDB](https://mariadb.com/ja/resources/blog/how-to-connect-python-programs-to-mariadb/)
jdeps

jdepsは、パッケージやクラスの依存関係を表示する
jdk8のjdepsはclass指定できるようだがjdk11だとエラー
オプションなしはpackageの依存？
-verbose:classはclassの依存
-profileはprofile
-jdkinternalsは内部apiの依存関係。どんなものが対象になるのか不明。カキのサンプルでも何も出なかった
-apionlyはpublic,protectedのもの

```
C:\Program Files\Java\jdk1.8.0_351\lib>"C:\Program Files\Java\jdk1.8.0_351\bin\jdeps.exe" -cp tool.jar com.sun.tools.jdeps.Main
tools.jar -> C:\Program Files\Java\jdk1.8.0_351\jre\lib\rt.jar
   com.sun.tools.jdeps (tools.jar)
      -> java.io
      -> java.lang

C:\Program Files\Java\jdk1.8.0_351\lib>"C:\Program Files\Java\jdk1.8.0_351\bin\jdeps.exe" -verbose:class -cp tool.jar com.sun.tools.jdeps.Main
tools.jar -> C:\Program Files\Java\jdk1.8.0_351\jre\lib\rt.jar
   com.sun.tools.jdeps.Main (tools.jar)
      -> java.io.PrintWriter
      -> java.lang.Exception
      -> java.lang.Object
      -> java.lang.String
      -> java.lang.System

C:\Program Files\Java\jdk1.8.0_351\lib>"C:\Program Files\Java\jdk1.8.0_351\bin\jdeps.exe" -profile -cp tool.jar com.sun.tools.jdeps.Main
tools.jar -> C:\Program Files\Java\jdk1.8.0_351\jre\lib\rt.jar (compact1)
   com.sun.tools.jdeps (tools.jar)
      -> java.io                                            compact1
      -> java.lang                                          compact1

C:\Program Files\Java\jdk1.8.0_351\lib>"C:\Program Files\Java\jdk1.8.0_351\bin\jdeps.exe" -jdkinternals -cp tool.jar com.sun.tools.jdeps.Main


C:\Program Files\Java\jdk1.8.0_351\lib>"C:\Program Files\Java\jdk1.8.0_351\bin\jdeps.exe" -apionly -cp tool.jar com.sun.tools.jdeps.Main
tools.jar -> C:\Program Files\Java\jdk1.8.0_351\jre\lib\rt.jar
   com.sun.tools.jdeps (tools.jar)
      -> java.io
      -> java.lang
```
plunkerでdeck.gl その13

# 概要
plunkerでdeck.glやってみた。
練習問題やってみた。

# 練習問題
covid-19のjsonを読んで、ヒートマップを表示せよ。

# サンプルコード

```

let scatterplotLayer = new deck.ScatterplotLayer();
let heatmapLayer = new deck.HeatmapLayer();
const tileLayer = new deck.TileLayer({
  data: "https://c.tile.openstreetmap.org/{z}/{x}/{y}.png",
  minZoom: 0,
  maxZoom: 19,
  tileSize: 256,
  renderSubLayers: props => new deck.BitmapLayer(props, {
    data: null,
    image: props.data,
    bounds: (({ west, south, east, north }) => [west, south, east, north])(props.tile.bbox),
  }),
});
const data = [];
const OPTIONS = ['intensity', 'radiusPixels', 'threshold', 'opacity'];
const deckgl = new deck.Deck({
  initialViewState: {
    longitude: 137,
    latitude: 37,
    zoom: 5,
    minZoom: 2,
    maxZoom: 8,
    pitch: 30,
    bearing: 10,
  },
  controller: true,
  layers: [tileLayer, scatterplotLayer, heatmapLayer, ]
});
const renderLayer = () => {
  const options = {};
  OPTIONS.forEach(key => {
    const value = document.getElementById(key).value;
    document.getElementById(key + '-value').innerHTML = value;
    options[key] = Number(value);
  });
  scatterplotLayer = new deck.ScatterplotLayer({
    data,
    opacity: 0.5,
    getPosition: ({p}) => p,
    getRadius: ({v}) => Math.sqrt(v) * 12,
    getFillColor: ({v}) => [Math.sqrt(v) / 10, 20, 60],
  });
  heatmapLayer = new deck.HeatmapLayer({
    data: data,
    id: 'heatmp-layer',
    pickable: false,
    getPosition: ({p}) => p,
    getWeight: 1,
    radiusPixels: 30,
    intensity: 2.5,
    threshold: 0.1,
    opacity: 0.3,
    ...options
  });
  deckgl.setProps({
    layers: [tileLayer, scatterplotLayer, heatmapLayer, ],
  });
}
OPTIONS.forEach(key => {
  document.getElementById(key).oninput = renderLayer;
});
d3.json("https://covid19-japan-web-api.now.sh/api/v1/prefectures", function(error, json) {
  var keys = ["id", "name_ja", "name_en", "lat", "lng", "cases", "deaths"];
  for (var i = 0; i < json.length; i++)
  {
    var s = {
      p: [json[i]["lng"], json[i]["lat"]], 
      v: json[i]["cases"] 
    };
    data.push(s);
  }
  renderLayer();
});





```

# 実行結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/3cb609bd-1d70-e44a-4bbf-3991838cfc97.png)


# 成果物

https://embed.plnkr.co/plunk/5n0bFUJGn9jYlgwb


以上。
FastAPIのasync def表記を深掘りしてみた

async defとは、fastapiにおける頻出表記ですね。いつもちゃんと理解ができなくて、あやふややってきました。今年2月時点で、fastapi公式ドキュメントの[並行処理とasync/await](https://fastapi.tiangolo.com/ja/async/#path-operation)がようやく日本語化され、それを読んでから記事を作成しました。（訳者さんに感謝〜）

## 結論

### APIサーバーの動き
fastapiは、クライアントサーバ（client-server, cs）システムの一つです。サーバー上では、fastapiアプリはASGIサーバー（uvicornが一般的）から起動されます。uvicorn起動オプションの一つ`--workers`でスレッド数が指定されます。デフォルトでは環境変数WEB_CONCURRENCYを参照し、ない場合は1とします。
多重化（multiplexing）技術を使って、複数のTCP接続を一つのスレッドで管理します。

### async defとdefの違い
- Path operation関数asyncで宣言すると、fastapiのメインスレッドで直接実行されます。awaitされるので、メインスレッドをブロックします。時間消費が多い場合、サーバーが新しいリクエストへ返答が遅くなる可能性があります。
- 一方で、defで宣言すると、メインスレッドじゃなくて外部スレッドプールで実行されます。メインスレッドをブロックしないが、cpuに負荷をかけます。

### 結局、どっちを使うのか
答えは公式ドキュメントにあります。
> path operation 関数を async def の代わりに通常の def で宣言すると、(サーバーをブロックするので) 直接呼び出す代わりに外部スレッドプール (awaitされる) で実行されます。
>
> 上記の方法と違った方法の別の非同期フレームワークから来ており、小さなパフォーマンス向上 (約100ナノ秒) のために通常の def を使用して些細な演算のみ行う path operation 関数 を定義するのに慣れている場合は、FastAPIではまったく逆の効果になることに注意してください。このような場合、path operation 関数 がブロッキングI/Oを実行しないのであれば、async def の使用をお勧めします。
> 参照先：https://fastapi.tiangolo.com/ja/async/#path-operation

## コードで検証

"async def"と"def"違いを検証するために、demoを用意しました。

```python
import threading
from fastapi import FastAPI
from time import sleep
from hashlib import md5
from random import randint

app = FastAPI()


def work(n):
    sleep(n)
    b = randint(602, 2021).to_bytes(4, 'big')
    return md5(b).hexdigest()


async def awork(n):
    sleep(n)
    b = randint(602, 2021).to_bytes(4, 'big')
    return md5(b).hexdigest()


@app.get('/awork')
async def awk(n: int = 7):
    res = await awork(n)
    print(123)
    return res


@app.get('/work')
def wk(n: int = 7):
    res = work(n)
    return res


@app.get('/aping')
async def aping():
    return 'APONG!'


@app.get('/ping')
def ping():
    return 'PONG!'


@app.get('/tid')
def tid():
    return threading.get_ident()

```
github:　https://github.com/tdzz1102/fastapi-async-what

![スクリーンショット 2023-02-22 16.32.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3172801/43a49211-e427-23cc-2d93-32caaa750a92.png)


localhost:8000でサーバーを立ち上げて、api docsはこうなっている。

`work(), awork()`の中ではブロッキング処理があります。唯一の違いは、`awork()`はasyncで宣言されます。それぞれにapiも作成しました。`ping(), aping()`の役割は、サーバーが今ブロックされるかの確認。`tid()`は`threading.get_ident()`、つまりスレッドidを取得する関数です。

| 操作 | 結果 | 原因 |
| --- | --- | --- |
| ブラウザの違うページから/tidを実行 | tidは同じ | fastapiはシングルスレッド |
| /workしてからすぐに/pingを実行 | /pingはすぐに結果が返される | 両方とも外部スレッドプール実行されるので、メインスレッドをブロックしない |
| /workしてからすぐに/apingを実行 | /apingはすぐに結果が返される | /workは外部スレッドプール実行されるので、メインスレッドをブロックしない |
| /aworkしてからすぐに/apingを実行 | /apingは約7秒後に結果が返される | メインスレッドは/aworkを待つ（await）ので、7秒間ブロックされる |
| /aworkしてからすぐに/pingを実行 | /pingは約7秒後に結果が返される | メインスレッドは/aworkを待つ（await）ので、7秒間ブロックされる。/pingはスレッドプールが代わりに実行するが、それにリクエストの「受け取り-スレッド作成-結果を待つ」という流れも、メインスレッドの役割だから |
【Rails】ランキング機能の実装

## 概要
ユーザー情報に紐づいた都道府県訪問数をランキング形式でビュー画面で表示する方法。

## 環境
- Rails 6.0.6.1
- ruby 2.6.5

## 前提
- ユーザーのテーブル名：users
- 都道府県のテーブル名：prefectures
  (Activehashは使用していない。)
- 中間テーブル名：user_prefectures

## コントローラー
ユーザー情報に紐づいた都道府県訪問数をランキング形式で取得し@user_prefecture_ranks変数に代入する。
```users_controller.rb
  def ranking
    @user_prefecture_ranks= User.find(UserPrefecture.group(:user_id).order('count(prefecture_id) desc').limit(10).pluck(:user_id))
  end
```

`@user_prefecture_ranks`の詳細が下記の通りになります。

```ruby:@user_prefecture_ranks詳細
UserPrefecture.group(:user_id) #ユーザー情報(:user_id)が同じものにグループ分けをする
order('count(prefecture_id) desc') #都道府県訪問数(:prefecture_id)が多い順に並べる
limit(10) #ビュー画面に表示する最大数を10と設定
pluck(:user_id) #ユーザー情報(:user_id)のみを数字で取り出す。

User.find()#上記pluckで取り出された数字をUserのidとすることで訪問数順にユーザー情報を取得する。

@user_prefecture_ranks
```

## ビュー

```ruby:ranking.html.erb
<table>
  <tr>
    <th>ランク</th>
    <th>ユーザー名</th>
    <th>訪問数</th>
  </tr>
  <% @user_prefecture_ranks.each.with_index(1) do |rank, i| %> 
  <% if i == 1 %> # iの値が1-3の時はランキング順位の横に王冠のアイコンを表示させる為、if文で条件分岐を記述。
  <tr>
    <td><%= image_tag("gold_icon.png") %><%= i %>位</td>
    <td><%= rank.name %></td>
    <td><%= rank.prefectures.count %></td> 
  </tr>
  <% elsif i == 2 %>
  <tr>
    <td><%= image_tag("silver_icon.png") %><%= i %>位</td>
    <td><%= rank.name %></td>
    <td><%= rank.prefectures.count %></td> 
  </tr>
  <% elsif i == 3 %>
  <tr>
    <td><%= image_tag("blonze_icon.png") %><%= i %>位</td>
    <td><%= rank.name %></td>
    <td><%= rank.prefectures.count %></td> 
  </tr>
  <% else %> 
  <tr>
    <td><%= i %>位</td>
    <td><%= rank.name %></td>
    <td><%= rank.prefectures.count %></td> 
  </tr>
  <% end %>
  <% end %>
</table>
```
`with_index(1)`を使うことで、ユーザー情報に紐づいた都道府県訪問数を上から順に表示するだけでなく、1位、2位、3位のようなランキング順位をビュー画面で表示することができる。

## ブラウザ例
[![Image from Gyazo](https://i.gyazo.com/af96d3373e4d9bcc49255021a9f52043.png)](https://gyazo.com/af96d3373e4d9bcc49255021a9f52043)

## 参考文献
[Railsのアソシエーションされたモデルを使ってランキングシステムを作る](https://qiita.com/Inp/items/dcd1d6103b4215859e8c)
ECS (Entity Component System) ざっくり概念解説

※某クラウドサービスのA〇SのECSとは関係ないです。

UnityではECSが1.0になりました。
Rust製ゲームエンジンのbevyではECSが根幹に据えられています。
このECSについて解説してみたいと思います。

--- 
# コンポーネント指向
---

まずECSの前のコンポーネント指向について触れたいと思います。
コンポーネント指向とは機能をコンポーネントにまとめ、そのコンポーネントをまとめたオブジェクトを作り上げることによって作り上げる設計です。

---

アクションゲームで例えるなら、キャラクターというオブジェクトは、
- ここに描画するという情報をまとめた座標(transform)のコンポーネント
- どのように描画するかのアニメーションのコンポーネント
- 物理演算用のコンポーネント
- 入力に対して動作させるためのコンポーネント
- ロジックの状態管理のコンポーネント

などに分かれることになります。

---
これらのコンポーネントが一つの物体に付与されまず。それぞれが毎フレームの処理をし、また他のコンポーネントにmessageを送ったりすることでゲームの動きとなっていきます。
例えば物理演算で座標を変更したり、ロジックによってアニメーションを変化させたりなどです。

---
このコンポーネント指向ですが機能同士の分離はしてもデータの分離はされていないです。
そのため機能の再利用するときに(悪しき)継承などを使ったりすることが多いです。
Unityではほとんどのコンポーネント`MonoBehaviour`が基底に置かれていたりします。

---
# ECS
---

ここで機能とデータも分離してしまおうとするのがデータ指向になります。
その中の一つがECSになります。
Entity Component Systemはその名の通り、
- Entity 物体
- Component 要素、属性
- System 機能、法則
に分割していく設計です。

--- 

従来のComponent指向の場合はComponentとSystemが一体と化していました。
そのためこの属性はどの機能と結びつくかに依存したものになっていました。
なので複数の機能で同じデータを使いたい場合メッセージを送りあったり別のComponentを握り続ける必要があります。

ECSにおいてはComponentはただのデータの塊です。Systemが複数のComponentを利用して処理を行いComponentを変更したりします。

---
# 概念的な例
---

ECSは次のように考えると理解しやすいと思います。

---

# Entity
まずEntityは物体です。
人だったり車だったりします。
人はプレーヤーだったりNPCだったり、キャラごとの違いがあったりしますが、ひとまず物は単なるEntityとして捨象して考えます。

---

# Component
次にComponentは属性です。
現実にあるものなら、人でも車でも座標情報(x,y,zや向いている方向)があります。
移動しているなら速度を持ちます。
プレーヤーとしての属性をもったりNPCの属性を持たせたりして物体を具象化していきます。
しかしだけではComponentはただの属性、情報です。
Componentがあるだけではなんの変化が起きません。

---

# System
ここでSystemが入ってきます。Systemとは法則です。
物理法則というSystemを定義することで「速度があれば座標が変わる」、「力が加われば加速度が働く」、「重さがあれば重力が加わる」などの動きが定義されます。
アクションゲームなら「入力でキャラクターの速度を変更する」「体力が0になれば死んだ状態にする」などの法則を設定していきます。

---

# World
そうやって一つの「世界」を定義していくのがECSになります。
ちなみにECSではこれらを`World`という単位に格納していきます。
ゲームの中で一つの世界を作り上げると考えるとロマンを感じる名前ですね。

---

# ECSの利点

---

ECSの利点としてはデータと機能が完全に分離しているのでパフォーマンス的に優れているところがあります。
SystemではあるComponent群があるEntityをQueryで取得してそれらに変更を加えていくというような形をとります。大抵のECSは要求するComponentが何かを引数で書いて登録すればライブラリ側がQueryなどをしてくれますが、並列化できるところは自動でしてくれます。またQueryを手書きすることでさらに効率よくすることができます。(なのでECSはただのバッチ処理とみることもできます。)

---

またデータが分離しているので機能間の通信とかを考えないで良くなります。
単純にSystemのレイヤーでどの機能が動くかだけ考えればいいです。
逆にECSの欠点としてSystemのスケジュールが複雑になることがあるかもしれません。

---

# まとめ

ざっくりとした概念は以上になります。
エンジンによって細かい差異はあると思いますが、考え方としては同じようになっているはずです。
StepfunctionとECSを使ったイベントドリブンな構成を作成してみた所感とつまずいた点について

こんにちは! Agoと申します｡
今回は問題が発生していたシステムをStepfunctionとECSで構成したことで問題解決できた内容及び､構成する上で詰まった点等を共有させていただきたいと思います｡


読む時間が無い方にも要約(TL;DR)を載せてありますのでそちらだけでも読んでいただけると幸いです｡
## TL;DR
- AWS Batch + EC2でZipファイルを解凍して配置するシーケンシャルな構成だった
- 旧システムの仕組み上､大容量のZipを配置しようとすると､次の定期実行までに終わらず､ファイルが配置できない問題が発生していた
- EventBridge + Stepfunctions + ECSでイベントドリブンな構成をすることで問題が解決した
- StepfunctionでECSを選択する場合､かんたんに後続処理に値を渡すことができない
- StepfunctionsでECSに渡した入力データをそのまま取得して後続処理に渡す力技で対応を行った


## 前提
旧システムはzipファイル配置バケットから対象となる30件ずつリスト化し､RDSに保存するジョブとRDSの配置リストを元に30件ずつzipを展開して指定バケットに配置するジョブが別れており､それぞれ定期実行で動くシーケンシャルな構成でした｡
下記が以前のインフラの構成図になります
![旧システム.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27126/49b3994e-331d-11f4-ad8f-1cf69f639d16.png)


以前までは1つのZipファイルの容量はおよそ50MB〜3GBが主でした
また､一日のZipの配置数は約1000件ほどありました｡


## 抱えていた問題
- Zipファイルの肥大化
	旧システムの仕組み上､Zipの解凍及び展開jobで従来のZipファイルのサイズよりも大きいZipファイルが対象となった場合､定期実行処理のシーケンスに間に合わなくなり､その定期実行処理で拾われた30件のZipファイルがいつまでも配置されない問題が度々発生する様になりました｡
つまり､今回のケースのように､シーケンシャルな構成だと､大容量のZipファイルが置かれた場合に耐えられない構成になっていました｡


## 解決方法
上記問題を解決するために下記の構成で解決を検討しました｡

- Event Bridge + Stepfunctions + lambdaを使ってS3にZipが配置されたタイミングで1件ごとにZipファイルを処理するイベントドリブンな構成

しかし､この構成だと10GB以上のZipファイルが配置された場合にlambdaの処理制限時間の15分に間に合わないことが判明したため､断念をしました｡
そこで､大容量のZipファイルを処理するために下記の構成にすることで､時間制限なく大容量のzipファイルを処理することに成功しました｡

- Event Bridge + Stepfunctions + ECSを使ってS3にzipが配置されたタイミングを検知し､1件ごとにzipファイルを処理するイベントドリブンな構成

実際のインフラ構成図が以下になります｡
![新システム構成図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27126/ece60bed-6114-753d-e4a8-458c87cdebbf.png)





## つまずいた点
StepfunctionsでECSを行う構成で作成を行った際につまずいた点があるため､共有します

-  StepfunctionsにおいてECSの結果データをアプリコード内のreturnで後続処理に渡すことができない
	lambdaだと､ 下記のように設定することで､処理結果を後続処理に渡すことができますが､
	```
	# 何らかの処理
	return { 
		"error_code": 0,
	    "zip_path": "fugafuga.zip"
	} 
	```

	 ```
	## stepfunctionの出力結果
	"Payload": {
	    "error_code": 0,
	    "zip_path": "fugafuga.zip"
	}
	
	## 下記をstepfunctionの後続jobに記述することで後続処理に結果を渡すことができる
	"Parameters": { 
		"error_code.$": "$..Payload.input.error_code",
		"zip_path.$": "$..Payload.zip_path"
	}
	```
	ECSだと､ アプリ内でreturnを記述してもoutputには出力されず､うまく後続処理に結果を渡すことができません｡
	
	今回のケースだと､ECSのあとにlambdaで処理を行う設定があったのですが､ECSに渡した入力データのまま出ていることがわかったので､その内容から必要な値をlambdaのeventに渡すという力技で対応を行いました｡

	```
	# 出力結果をそのままlambdaに渡して､ lambdaのコード内で必要な値を取得するように設定
	"Parameters": { 
		"Payload.$": "$"
	}

	```


## 終わりに
今回の改善によって得られたことは以下の通りでした｡
- stepfunctionのjobの選択肢として､lambdaの処理制限に引っかかるのであればECSを選ぶのもあり
    - ただし､lambdaのように後続処理に値を渡すことが容易ではないため､stepfunctionの定義する内容から取得する等､工夫する必要がある｡
Rails paranoia dependent 親レコード消す際 子レコードが論理削除されている場合対応

## 親レコード消す際 子レコードが論理削除されているたらdependent: :destoryがうまく動かんかった

## 最終的な対応

親レコード削除前に子レコードを削除するというパワープレイになりました。
いい方法があれば

```
class EntryLimit < ApplicationRecord
  has_many :entry_lists, dependent: :delete_all
  before_destroy :entry_lists_depend_paranoia


  def entry_lists_depend_paranoia
    entry_lists.with_deleted.map(&:really_destroy!)
  end
```


## 構成

親モデル
```
class EntryLimit < ApplicationRecord
  has_many :entry_lists, dependent: :destroy
```

子モデル
```
class EntryList < ApplicationRecord
  acts_as_paranoid

  belongs_to :entry_limit
```

削除しようとした時エラーが発生
```
entrylimit=EntryLimit
entrylimit.destroy
＝＞ActiveRecord::InvalidForeignKey: Mysql2::Error: Cannot delete or update a parent row: a foreign key constraint fails
```

## 対応１　dependentをdestroyからdelete_allにしてみよう

```
has_many :entry_lists, dependent: :delete_all
```

結論だめでした。

## 対応2 before_destroyで消す前に論理削除されたレコードを物理削除かましてみよう

```
class EntryLimit < ApplicationRecord
  has_many :entry_lists, dependent: :delete_all
  before_destroy :entry_lists_depend_paranoia

  def entry_lists_depend_paranoia
    entry_lists.with_deleted.map(&:really_destroy!)
  end
```

結果消せました

```
 entrylimit.destroy

 (2.2ms)  BEGIN
 EntryList Destroy (1.1ms)  DELETE FROM `entry_lists` WHERE `entry_lists`.`id` = 30
 EntryLimit Destroy (1.2ms)  DELETE FROM `entry_limits` WHERE `entry_limits`.`id` = 6
 (1.9ms)  COMMIT
```

## まとめ

今回はパワープレイで行きました
もっといい感じに消す方法があったら教えてほしいです。

dependentで削除する場合 paranoiaの影響で通常デリートが動くが
論理削除になってしまう　しかし親は消えるので関連キーがないよエラーがでてると認識してます。

ただparanoia使っていても
論理削除されたレコードが一件もないと特に問題なく削除はうごきました🤔
chart.jsのx軸の値がlabelsになっていないバグの対処

環境: chart.js 3.9.1、vue.js、 nuxt.js 2.13.0

```
lables: ["2021", "2022", "2023"]
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2481192/f78586db-1dae-562c-1ded-b3b4e141040e.png)

このように、x軸が0, 1, 2となっていました。

ChatGPTに聞いてみたところ・・・こういった回答が来ました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2481192/0f5cf0a6-2d32-6ad2-e889-51200e768f65.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2481192/aac7f33e-ade9-f4e3-01d5-08607e34b427.png)

それでもしこれでいけるか試して見ました。

```
chartData.labels = chartData.labels.map((label) => {
  return label + '年'
})
```

結果、x軸がlabelsの値になりました！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2481192/22ec7517-674e-d5f6-a524-d9448fec661f.png)
intelからm1に移行したmacのbundle（もしくはgem install）で make: /usr/local/bin/gmkdir: No such file or directory と出る

## できれば
Intel -> m1への移行時にはbrew関係はなくしたほうが良かった。
後々で大変。
brewfileにダンプしてからm1でその通りインストールすればたぶんこうはならなかった…（はず

## 標題

``` bash
(中略)
make DESTDIR\= install
make: /usr/local/bin/gmkdir: No such file or directory
make: *** [.sitearchdir.time] Error 1
```

こんなエラーがでる。
ぐぐると`brew install coreutils`でgmkdirとかが入るのだが、m1だと`/opt/homebrew/bin`に入る。

gemでgenerateしてるmakefileを見ると

``` makefile
(中略)
RM = rm -f
RM_RF = rm -fr 
RMDIRS = rmdir -p
MAKEDIRS = /usr/local/bin/gmkdir -p
INSTALL = /usr/local/bin/ginstall -c
INSTALL_PROG = $(INSTALL) -m 0755
INSTALL_DATA = $(INSTALL) -m 644
COPY = cp
TOUCH = exit >
```

で、どうもintel版のPATHを参照してる。
makefile作成の部分をどうにかできるかもしれないが、それは後にして、ひとまずの解決は
`ln -s /opt/homebrew/bin/gmkdir /usr/local/bin/`
でリンク貼る。（なお、ginstallも）

これでひとまずbundle install は通るようになった。

## 追記【理由がわかった】
https://qiita.com/labocho/items/c998791ab37e93ccb924
こちらの方が書かれていた。

確かにソースを追うと、`~/.rbenv/versions/2.6.7/lib/ruby/2.6.0/x86_64-darwin19/rbconfig.rb`
を参照していた。
これはIntel時のRubyのパスだった。なのでこれは再インストールしないといけない…
`rbenv install (version)`でOK
定積分1/(1+cosx)「2022信州大理(数)1(1)」をwolframalphaとsympyでやってみた。


グラフがでます。
オリジナル

https://kamelink.com/blog/2023/02/20/15-2-22-shinshudai-risuu1-1/

上と同じです。大学入試数学問題集成＞テキスト

https://mathexamtest.web.fc2.com/2022/202210421/2022104210300mj.html

# wolframで

https://www.wolframalpha.com/input?i=integrate%281%2F%281%2Bcosx%29%2C%28x%2C%CF%80%2F2%2C2%CF%80%2F3%29%29&lang=ja

参考

https://www.wolframalpha.com/input?i=1%2F%281%2Bcosx%29&lang=ja

https://www.wolframalpha.com/input?i=trigfactor++++++%281%2F%281%2Bcosx%29%29&lang=ja


https://www.wolframalpha.com/input?i=1%2F2+sec%5E2%28x%2F2%29&lang=ja

上の不定積分

https://www.wolframalpha.com/input?i=tan%28x%2F2%29+&lang=ja


# sympyで(半角の公式で)
勉強中

# sympyで(wolframと同じ)

```python
from sympy import *
var('x')
y=1/(1+cos(x))
print("#",integrate(y,(x,pi/2,2*pi/3)))
plot(y,0,(x,pi/2,2*pi/3))
# -1 + sqrt(3)
```
plotコマンドは、縦横比？異なります。

![Figure_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109698/649ec987-2bc2-0dcb-aef5-2406197a74e7.png)


# 参考


https://ja.wikipedia.org/wiki/%E4%B8%89%E8%A7%92%E9%96%A2%E6%95%B0%E3%81%AE%E5%85%AC%E5%BC%8F%E3%81%AE%E4%B8%80%E8%A6%A7#倍角・三倍角・半角の公式

https://en.wikipedia.org/wiki/List_of_trigonometric_identities#Half-angle_formulae



https://docs.sympy.org/latest/modules/simplify/fu.html
【MySQL】Windows ServerにMySQL8.0を導入してmy.iniを編集するときにハマった話

# 概要
Windows ServerにMySQL8.0を導入して、
設定を変更しようと思ったらめちゃくちゃハマった話

# 結論
- Windowsインストーラーから導入するとmy.iniの場所が固定される
- my.iniの場所がわかりにくすぎる
- メモ帳でmy.iniを編集するとMySQLが起動できなくなる

※ 環境によって現象はことなると思うので参考程度に

# インストーラーから導入するとmy.iniの場所が固定される
ここ
https://dev.mysql.com/downloads/installer/
からインストーラーをDLして導入して、
設定を変更したかったので、my.iniをインストールフォルダ直下に配置してもなぜか読み込まれない。

インストール時に自動で登録されるサービスのプロパティを確認したところ、
なんと「---default-file=」で読み込むmy.iniを指定されていた模様
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2420694/df3c3365-162d-2af8-ab01-7475c130de98.png)

# my.iniの場所がわかりにくすぎる
初期設定だと前述のとおり、
C:¥ProgramData¥MySQL...配下のmy.iniを読み込むわけだが、
この「ProgramData」フォルダがなんと隠しファイルになっている。
ので、明示的に隠しファイルを表示するようにしないとなかなか気が付かない。

# メモ帳で編集するとMySQLが起動できなくなる
やっとmy.iniを見つけたのでメモ帳から編集したところ、
なぜかMySQLが起動しなくなってしまった。
設定を間違ってるわけでもないし、もとの設定に戻しても起動しない･･･

調べてみると、どうやらメモ帳で保存したときに文字コードが勝手に変わっていたらしい。
たぶん、SJIS→UTF-8

Sakuraエディタ等で開いてSJISに設定したら問題なく起動できた

# まとめ
Windowsで開発するの大変すぎる・・・
【Swift】プッシュ通知設定を判別するコード

## 概要
Swiftでプッシュ通知設定を判別するコード

## コード

```swift

UNUserNotificationCenter.current().getNotificationSettings { settings in
    switch settings.authorizationStatus {
        case .notDetermined:
            print("許可設定を行っていない")
        case .denied:
            print("通知が拒否されている")
        case .authorized:
            print("通知が許可されている")
        case .provisional:
            print("Provisional Authorizationが有効になっている")
        case .ephemeral:
            print("限られた時間内の通知が有効")
    }
}

```

## 参考

https://developer.apple.com/documentation/usernotifications/unusernotificationcenter/1649524-getnotificationsettings

https://yamatooo.blog/entry/2021/02/10/083000

## Swiftのお役立ち情報

https://wagtechblog.com/programing/swift-iphone-application-school

https://wagtechblog.com/programing/swift-textbook.html
【JavaScript・kintone】ドロップダウンの選択肢で文字列自動入力

kintoneの記事多すぎて自分の欲しい情報だけ見つけるの大変だったので:clipboard:
ドロップダウンで選んだ項目によって文字列に指定の文字を入れるのは
プリントクリエイターを使用していると頻繁に使う…
あと、社内展開してると自由記述欄は荒れがちなのでこういうセーフティ大事ですよね:cry:

```
(function () {
    "use strict";
    
    var events = ["app.record.create.show", 
                  "app.record.edit.show", 
                  "app.record.index.edit.show",
                  "app.record.create.change.ドロップダウン名"];
    
    kintone.events.on(events, function(event) {
    var record = event.record;
    
    if (record['ドロップダウン名']['value'] === 'ドロップダウン選択肢①') {
        record['文字列①']['value'] = 'AAAAA' ;
        record['文字列②']['value'] = 'aaaaa';
    } else if (record['ドロップダウン名']['value'] === 'ドロップダウン選択肢②') {
        record['文字列①']['value'] = 'BBBBB' ;
        record['文字列②']['value'] = 'bbbbb';
    } else if (record['ドロップダウン名']['value'] === 'ドロップダウン選択肢③') {
        record['文字列①']['value'] = 'CCCCC' ;
        record['文字列②']['value'] = 'ccccc';
    } 
    return event;
    });
    })();
```
VS Codeの拡張機能REST Client

VSCodeの拡張機能[REST Client](https://github.com/Huachao/vscode-restclient)を使用してAPIを呼び出すのが簡単で使いやすかったので設定方法をご紹介します。

```html: sample setting
@username = "JohnDoe"
@password = "myPassword123"
@url = https://example.com/api/

##############################
POST {{url}}/login
Content-Type: application/json

{
    "username": "{{username}}",
    "password": "{{password}}"
}

##############################

Get {{url}}/user
Content-Type: application/json

##############################
```
ファイル名には`.http`という拡張子を使用します。
この例では、変数`@username`と`@password`にそれぞれの値を代入し、リクエストボディ内の`username`と`password`のフィールドにそれぞれの値を代入しています。

また、変数名にはアルファベットや数字、アンダースコア、ハイフンを使用できますが、先頭に数字を使用することはできません。また、変数名は大文字と小文字が区別されます。

`@url`という変数にAPIのURLを代入し、リクエスト内で`{{url}}`のように変数を参照しています。このように変数を使用することで、APIのURLを変更する場合には、`@url`変数の値を変更するだけで済みます。

また、変数を使用することで、APIのURLに含まれるパスパラメーターやクエリパラメーターの値も変数化することができます。このようにして、APIのURL内のすべてのパラメーターを一元管理し、簡単に変更できるようにすることができます。

https://github.com/Huachao/vscode-restclient
Chrome拡張機能のデプロイ / アップデート方法

## 手順
デプロイ
・ChromeWebStoreの登録
・ファイルのアップロードと必要記入事項の入力

アップデート
・``manifest.json``のバージョンを上げる
・ファイルのアップロード

## デプロイ
### ChromeWebStoreの登録
拡張機能をデプロイするためには、[ChromeWebStore](https://chrome.google.com/webstore/devconsole/register)に登録して、5ドルの登録料（初回のみ）を払わないといけない。

これらの登録が終わるとデベロッパーダッシュボードに遷移できるようになる。

### ファイルのアップロードと必要記入事項の入力
ダッシュボード画面の右上に``+ 新しいアイテム``と書かれたボタンがあるのでそれを押すと、
zipファイルをアップロードしてくださいと出るので、作成した拡張機能のzipファイルをアップロードする。

>選択したファイルに、右クリックで``〜〜ファイルを圧縮``が選択できる

#### 項目内容
ステータス：審査の状態が確認できる
パッケージ：拡張機能のパッケージ情報が確認できる
ストアの掲載情報：ここで掲載情報を入力する
プライバシーへの取り組み：用途や権限が必要な理由はここで入力する
決済と配布地域：決済方法や公開設定、販売地域を設定できる
ストアへの掲載情報の入力項目は以下の通り

商品の詳細（アイテムの説明、カテゴリ、言語）
画像アセット（ショップアイコン、プロモーション動画、スクリーンショット等）
追加フィールド（公式URL、ホームページURL、サポートURL、GoogleアナリティクスID等）
画像アセットに関しては、画像サイズが指定されているため調整する必要がある。

不足項目がある場合は、画面上部に「送信できない理由」が表示されるので、確認し不足分を入力する。

必要項目の入力が全て完了すると、右上の「審査のための送信」が押せるようになるので、そちらから送信。私の場合は２週間かかりました。人によってはもっと早かったり、遅かったりするみたいなので。大体これくらいの期間、は無さそう？

## アップデート
### ``manifest.json``のバージョンを上げる
``manifest.json``ファイルに記載されている``version``の数値を上げる。
```manifest.json
{
    "version": "1.0",//←ここを変える 2.0とか
    "manifest_version": 3,
    .
    .

}
```
ここの数字を変えないと、パッケージのアップロード時に「マニフェストのバーションが無効です」
とエラーが出る。

### ファイルのアップロード
``manifest.json``の修正が完了したら、デプロイした時と同じように、ファイルを圧縮する。
「パッケージ」へ移動し、新しいパッケージをアップロード」をクリック、ZIPファイルをアップロードすると「ストアの掲載情報」へ移動する。

あとは下書きとして保存し、「審査のため送信」ボタンをクリックしたらOK。審査結果を待ちましょう。
## 参考記事
[Chrome拡張機能の申請手順](https://qiita.com/sasao3/items/0606b67da01948ae58b7)
[公開したChrome拡張機能のアップデート手順](https://zenn.dev/eetann/articles/2021-06-11-how-to-update-chrome-extension)
【備忘録】Raincloud plot

# はじめに
<!-- 発端や概要を記載 -->
2要因2×2のデータセットでRaincloud plotを作るだけの備忘録。
完成形はこんな感じ↓

![Rplot.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2737734/575d7b6b-219b-bbb7-ef91-8f9a536304c1.jpeg)


# 目次
<!-- タイトルとアンカー名を編集 -->
1. [下準備](#下準備)
1. [グラフを描画](#グラフを描画)
1. [グラフを保存](#グラフを保存)
1. [参考](#参考)



<!-- 各チャプター -->
<a id="#下準備"></a>
# 下準備
今回使うデータ。
要因Aが2水準(a1, a2)、要因Bが2水準(b1, b2)。


```{r}
id <- rep(seq(1, 30, 1), 4)
A <- rep(c(rep('a1', 30), rep('a2', 30)), 2)
B <- c(rep('b1', 60), rep('b2', 60))

a1b1 <- c(rnorm(30, mean=15, sd=5))
a2b1 <- c(rnorm(30, mean=30, sd=5))
a1b2 <- c(rnorm(30, mean=20, sd=5))
a2b2 <- c(rnorm(30, mean=25, sd=5))

data <- data.frame(id, A, B, Value  = c(a1b1, a2b1, a1b2, a2b2))


data
```

<a id="#グラフを描画"></a>
# グラフを描画

```{r}
# install.packages("ggrain")
library(ggrain)

Graph <- ggplot(data[data$B %in% c('b1', 'b2'),], aes(B, Value, fill = A)) +
  geom_rain(alpha = .5, rain.side = 'f2x2', id.long.var = "id") +
  theme_classic() +
  facet_wrap(~A) +
  scale_fill_manual(values=c("dodgerblue", "darkorange")) +
  guides(fill = 'none', color = 'none') +
  ggtitle("Raincloud plots")

plot(Graph)

```

<a id="#グラフを保存"></a>
# グラフを保存
```{r}
ggsave(file = "名前.png", plot = Graph)
```


<a id="#参考"></a>
# 参考
- [Raincloud vignette](https://cran.r-project.org/web/packages/ggrain/vignettes/ggrain.html)
Rustのトレイトについて

# 背景、やること
最近Rustをいじっていた際トレイトという概念で扱う範囲が広くよくわからなくなってきたため、その役割についてとりあえず分かったことをまとめる。

# トレイトの役割
トレイトの役割の1つとして、「Javaのインターフェース(interface)のような機能です。共通の振る舞いを取り出して名前付けしたものをいいます。」とあった([実践Rustプログラミング入門より](https://www.amazon.co.jp/%E5%AE%9F%E8%B7%B5Rust%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E5%85%A5%E9%96%80-%E5%88%9D%E7%94%B0-%E7%9B%B4%E4%B9%9F/dp/4798061700))。

トレイトの意味を知るために、ある動物の寿命と学術名を表示するプログラムについてトレイトを使用しない場合と使用する場合(参考書記載)のプログラムを用意し、比較する。

# トレイトを使わない場合
プログラムは以下のようになる。動作としてはほぼ同じ(life_span, scientific_nameを表示する)だが、動物の数だけanimal_show_data()関数の実装をする必要が出てくる。
```main.rs
fn main() {
    let dog = Dog{};
    let cat = Cat{};
    show_animal_data_dog(dog);
    show_animal_data_cat(cat);
}

//犬の構造体。
struct Dog;
impl Dog {
    //寿命を返す。
    fn lifespan(&self) -> u32 {
        13
    }
    //学名を返す。
    fn scientific_name(&self) -> String {
        "Canis lups familiaris".to_string()
    }
}

//猫の構造体
struct Cat;
impl Cat {
    fn lifespan(&self) -> u32 {
        16
    }

    fn scientific_name(&self) -> String {
        "Felis catus".to_string()
    }
}

//犬のデータを表示する関数
fn show_animal_data_dog(d: Dog) {
    println!("life_span: {}", d.lifespan());
    println!("scientific_name: {}", d.scientific_name());
}

//猫のデータを表示する関数
fn show_animal_data_cat(c: Cat) {
    println!("life_span: {}", c.lifespan());
    println!("scientific_name: {}", c.scientific_name());
}

//...以下動物の数だけ関数を宣言する。

```
# トレイトを使う場合
以下のプログラムは書籍において紹介されていたもので、Animal型というトレイトと、その中でAnimal型を実装した型に共通する振る舞いを実装している。
具体的にはAnimal型を実装した型として構造体Dog, Catが存在しており、それらに共通する振る舞い(lifespan, scientific_name)をAnimalトレイトで実装している。
このトレイトにより、Animal型を実装した型は全てshow_animal_data()関数を通して動物のデータを表示可能となる。

```main.rs
fn main() {
    let dog = Dog{};
    let cat = Cat{};
    show_animal_data(dog);
    show_animal_data(cat);
}

trait Animal {
    fn lifespan(&self) -> u32;
    fn scientific_name(&self) -> String;
}

struct Dog;
impl Animal for Dog {
    fn lifespan(&self) -> u32 {
        13
    }

    fn scientific_name(&self) -> String {
        "Canis lups familiaris".to_string()
    }
}

struct Cat;
impl Animal for Cat {
    fn lifespan(&self) -> u32 {
        16
    }

    fn scientific_name(&self) -> String {
        "Felis catus".to_string()
    }
}

//Animal型をもつ動物のデータを表示する関数。
fn show_animal_data<T: Animal>(animal: T) {
    println!("Lifespan: {} years", animal.lifespan());
    println!("Scientific Name: {}", animal.scientific_name());
}
```
# まとめ
トレイトを使って同様の出力を行う部分を構造体ごとに実装する必要がなくなることが分かった。トレイト自体の役割は他にもいろいろあるため時間があるときにまとめていきたい。
なんかいつも忘れるクソ脳みそのためのtuple


まあチュートリアルをまとめただけ。意味がない

タプルは、複数の値を1つのまとまりでグループ化できる。
任意の順序で、異なる任意の方を組み合わせることができる。

タプルの表現方法は2種類ある。
```swift:
let http404error = (404,"Not Found")
let (statusNumber,statusMessage) = http404error
```
```swift:
let http404error = (statusNumber:404,statusMessage: "Not Found")
```
タプルの一部だけが必要な場合は、アンダースコアで無視することが可能。（おそらく外部のクラスなどを使用する際に有効的）
```swift:
let http404error = (404,"Not Found")
let (statusNumber, _) = http404error
```
各種アクセスには、インデックスを使用する例と、定義した名前を使用する2種類がある。
```swift:
let http404error = (404,"Not Found")
let (statusNumber,statusMessage) = http404error
print(The status is \(http404error.0))
// -> "The status is 404"
print(The status is \(http404error.statusNumber)
// -> "The status is 404"
```
Safari で YouTube の自動再生をトグルする AppleScript

# Safari で YouTube の自動再生をトグルする

YouTube、たくさんショートカットキーが用意されているのに、自動再生をトグルするショートカットキーは存在しないんですよね… なんでなんでしょうね…

と思ったので AppleScript を書きました。


## AppleScript

以下の通りです。シアターモードとデフォルト表示でのみ動作します（全画面時とミニプレーヤーには非対応）。設定言語に関わらず動くはずですが、拡張機能などの有無によって動かない可能性はあります（動かなかったらコメントください）。

```applescript:AppleScript
tell application "System Events" to tell process "Safari" to tell first window
	tell group 1 of (first group whose subrole is not "AXEmptyGroup") of group -3 of UI element 1 of scroll area 1 of group 1 of group 1 of tab group 1 of splitter group 1
		
		if button 1 of group -1 of group 1 exists then
			click button 1 of group -1 of group 1
		else if button 1 of group -1 exists then
			click button 1 of group -1
		end if
		
	end tell
end tell
```

この AppleScript を Apple 純正「ショートカット」アプリでショートカットキーに割り当てれば完璧ですね（割り当て方は[この記事](https://qiita.com/MANABU0SEC/items/ea74d37b421c81fbe6bf#%E3%82%B7%E3%83%A7%E3%83%BC%E3%83%88%E3%82%AB%E3%83%83%E3%83%88%E3%82%AD%E3%83%BC%E3%81%AB%E5%89%B2%E3%82%8A%E5%BD%93%E3%81%A6%E3%82%8B)を参照）。


## 簡略的な解説

この AppleScript は「YouTube の自動再生ボタンをクリック」しているだけです。

質問があればコメントにどうぞ。
Databricks SQLとは何か？

[What is Databricks SQL? \| Databricks on AWS](https://docs.databricks.com/sql/index.html) [2023/2/3時点]の翻訳です。

:::note warn
本書は抄訳であり内容の正確性を保証するものではありません。正確な内容に関しては原文を参照ください。
:::

Databricks SQLは、Databricksレイクハウスプラットフォームにビルトインされているエンタープライズデータウェアハウスです。Databricks SQLのコアの提供機能は[SQLウェアハウス](https://qiita.com/taka_yayoi/items/23d7789198c2dcd66381)と呼ばれる最適化計算リソースです。

Databricksは、SQL[クエリー](https://docs.databricks.com/sql/user/queries/index.html)、[ビジュアライゼーション](https://docs.databricks.com/sql/user/visualizations/index.html)、[ダッシュボード](https://qiita.com/taka_yayoi/items/834bef9aa784e1a045d8)を構成、実行するために**SQLペルソナ**として知られるUIツールのコレクションを提供します。

SQLウェアハウスは、[サードパーティのBI、可視化ツール](https://docs.databricks.com/partners/partners.html#bi)を含む様々な環境で実行されるSQLクエリーに対する一般的な計算資源を提供します。また、Databricks SQLは堅牢な[API](https://docs.databricks.com/sql/api/index.html)を提供しています。

Databricks SQLの最新機能に関しては、[Databricks SQL release notes](https://docs.databricks.com/sql/release-notes/index.html)をご覧ください。

# Spark SQL vs Databricks SQL

Databricks SQLは最適化された計算環境ですが、Spark SQLはApache Spark APIのコレクションを表現しています。DatabricksではSQL開発者がETLや分析のような作業を行い、ダッシュボードを作成するための様々なツールやテクノロジーを提供しています。エンタープライズデータウェアハウスに関しては、Databricks SQLをお勧めします。

# Spark SQLとは？

**Spark SQL**という用語は、技術的にはSparkデータフレームを使用するすべてのオペレーションすべてに適用されます。Spark SQLはSQLクエリーのサポートとPython、Scala、R、Java用のDataFrame APIを導入したSpark 2.xにおけるSpark RDD APIを置き換えました。

DatabricksのドキュメントではSQLのクエリーや機能を説明する際には、多くの場合Spark SQLを使用しています。Databricksランタイムの計算資源に対して実行されたSQLクエリーは、Delta Lakeに対するビルトインの拡張プロトコルと、プロプライエタリのDatabricksの機能と、オープンソースのApache Sparkの機能に密接にマッピングされます。[SQL reference](https://docs.databricks.com/sql/language-manual/index.html)で、利用可能なすべての機能と実行コンテキスト間での違いを学ぶことができます。

# DatabricksにおけるSQLはオープンソースApache Sparkとどう違うのか？

実行環境に関わらず、DatabricksにおけるSQLは他の場所で実行されるApache Spark SQLと大きな違いはありません。3つの異なる計算資源に対して、一般的なクエリーやステートメントを実行するために、DatabricksでSQLを使用することができます。これらの環境のすべては、オープンソースApache Sparkで利用できない数多くのコマンドを追加しており、Delta Lakeに関連するすべてのSQLクエリーを実行できるように事前設定されています。

Unity Catalogが有効化されたワークスペースでは、数多くの追加キーワードやコマンドを利用できます。ビルトインのHiveメタストアではなく、Unity Catalogに対して実行する際、いくつかのSQLコマンドは異なる挙動をすることに注意してください。

これらの計算資源の選択肢のそれぞれでは、若干異なるセマンティックスと文法を持っています。一般的にいうと:

- DatabricksランタイムコンピュートにおけるSQLは、オープンソースApache Sparkの処理と最も近いものになっています。
- Delta Live Tablesで実行されるSQLは、一般的にDatabricksランタイムの文法とセマンティクスを継承していますが、Delta Live Tables固有のキーワードや関数が追加されています。
- SQLウェアハウスで実行されるSQLは最もANSI標準に近いものとなっています。HiveQL、変数宣言、変数参照、DButilsウィジェットを含むDatabricksランタイムコンピュートに対してDatabricksノートブックで実行されるSQLでサポートされている多くの機能は、SQLウェアハウスでは動作しません。

# Databricks SQLにおける管理者のタスク

Databricks SQLの有効化、ユーザーとデータアクセスの管理、そのほかの管理タスクに関する情報を探しているのでしたら、[Databricks SQL administration](https://docs.databricks.com/sql/admin/index.html)をご覧ください。

# 参考資料

- [SQL language reference](https://docs.databricks.com/sql/language-manual/index.html)
- [Delta Live Tables SQL language reference](https://docs.databricks.com/workflows/delta-live-tables/delta-live-tables-sql-ref.html)

### Databricks 無料トライアル

[Databricks 無料トライアル](https://databricks.com/jp/try-databricks)
c#でgraph apiを使ってメールにファイルを添付し、メールを送信するサンプル


```
// Create the message with attachment.
byte[] contentBytes = System.IO.File.ReadAllBytes("test.xlsx");
string contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
MessageAttachmentsCollectionPage attachments = new MessageAttachmentsCollectionPage();

attachments.Add(new FileAttachment
{
    ODataType = "#microsoft.graph.fileAttachment",
    ContentBytes = contentBytes,
    ContentType = contentType,
    ContentId = "test",
    Name = "test.xlsx"
});

var message = new Message
{
    Subject = "こちらは件名です",
    Body = new ItemBody
    {
        ContentType = BodyType.Text,
        Content = "こちらは本文です。"
    },
    ToRecipients = new List<Recipient>()
    {
        new Recipient
        {
            EmailAddress = new EmailAddress
            {
                Address = "meganb@contoso.onmicrosoft.com"
            }
        }
    },
  　Attachments = attachments
};

//await graphClient.Users["test@outlook.jp"]→アプリケーション認証

//委任認証
await graphClient.Me
    .SendMail(message,true)
    .Request()
    .PostAsync();
```
# 参考サイト
https://stackoverflow.com/questions/42374501/microsoft-graph-send-mail-with-attachment

https://learn.microsoft.com/ja-jp/graph/api/user-sendmail?view=graph-rest-1.0&tabs=csharp
【Drupal】DDEVでDrupal9のローカル環境構築してみよう

DDEVと呼ばれるMacにDrupalサイトを構築するツールを使ってローカル環境を構築していきます。
Dockerと呼ばれるコンテナも使うのでPHPやMySQLなどのミドルウェアの設定をする必要がなく、簡単にローカル環境を構築できます。

# Dockerのインストール
[Install Docker Desktop on Mac](https://docs.docker.com/desktop/install/mac-install/)
上記ページよりDockerをインストールする
インストール後、ターミナルで以下のコマンドを実行する
```
docker
```

# DDEVのインストール
ターミナルで以下のコマンドを実行します
```
brew tap drud/ddev && brew install ddev
```
実行完了後にさらに以下のコマンドを実行します
```
ddev
```

# Drupalサイト構築
以下のコマンドを実行していく
```
mkdir my-drupal9-site
cd my-drupal9-site
ddev config --project-type=drupal9 --docroot=web --create-docroot
ddev start
ddev composer create "drupal/recommended-project:^9"
ddev composer require drush/drush
ddev launch
```
:::note warn
エラー「Could not connect to a docker provider.」が発生したら・・・
→　Docker Desktopを起動後に再実行してみてください。
:::
:::note warn
「ddev start」コマンド実行時に「Permission to beam up?」と表示されたら・・・
→　Yesと入力してください。
:::
上記コマンドを実行し終わるとブラウザが起動して、ローカル環境が表示されます。
その後、Drupalのインストールを進めていきます。

言語は日本語を選択します。
![4328a782fdbbf84f76c06c083d2a8b5d-1024x560.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/622183/b078cc73-5983-bb92-b9ca-9d30a5f7e25e.png)

インストールプロフィールは標準を選択します。
![dffca7dde244c27ec741f83f0379b304-1024x562.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/622183/0d615240-de6b-f70b-531e-eaef22e1744e.png)

サイトの環境設定ではサイト名や管理者アカウントを設定します。
![7686483b65420d531d6c6611748229db-1024x562.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/622183/deca830c-a73d-addd-e0ac-742cb2df3cfe.png)

保存して次へを選択してしばらく待つとトップページが表示されます。
ここまでくればとりあえずローカル環境にDrupalインストール完了です。
![fd652b8d856b6b2aa82188529b8be9f4-1024x564.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/622183/7f76d043-c6b0-4f18-4eab-31f4674d71be.png)

ただ警告が気になるので解消していきます。

# インストール後の警告の解消
ページ上部に表示されているメニューバーからレポート>サイトの状態を開きます。
2件表示されています。
![4f93dae43ff2de9056caeb4ed9b85d4b-1024x220.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/622183/dda7081b-a983-52de-9535-b318e01128df.png)

## 「更新の通知：無効」の解消
表示されている通りに、機能拡張でUpdate Managerモジュールを有効にします。

## 「Drupalコアの更新状況」の解消
再びサイトの状態にアクセスすると更新の通知は消えていますが新たに警告が表示されています。
![ee9e248e3adb4014f7450792e7d534da-1024x50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/622183/ab242c28-f2d2-2b4e-1c30-85a84796aa0b.png)
**Cronを実行**のリンクにアクセスして警告を解消します。

## 「構成ファイル：保護が無効」の解消
ターミナルでDrupalをインストールしたフォルダを開き、sites/default配下のパーミッションを確認します。
```
my-drupal9-site $ ls -l web/sites/default/
total 168
-rw-r--r--   1 kmmch211  staff   8542  1 16 12:02 default.services.yml
-rw-r--r--   1 kmmch211  staff  33395  1 16 12:02 default.settings.php
drwxr-xr-x  10 kmmch211  staff    320  1 16 12:10 files
-rw-r--r--   1 kmmch211  staff   2282  1 16 12:03 settings.ddev.php
-rwxr-xr-x   1 kmmch211  staff  31091  1 16 12:03 settings.php
my-drupal9-site $
```
settings.phpに書き込権限が与えられているため警告が発生していますが、 DDEVのローカル環境固有の現象のためsettings.ddev.phpを編集します。
```php:settings.ddev.php
$settings['skip_permissions_hardening'] = TRUE;
# 以上の設定を以下のように書き換えます。
$settings['skip_permissions_hardening'] = FALSE;
```
以上となります。
Vimで行数を表示する

Vimのデフォルトだと下記のように行数が表示されておらず、指定行への移動がしづらい。

![スクリーンショット 2023-02-22 16.09.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43800/23941533-ba1d-2f9e-ab6d-7a4b09c4ef97.png)

# 行番号の表示

`:set number` (省略形は `:set nu` )を実行すると、下記のように行数が表示されるようになります。

![スクリーンショット 2023-02-22 16.15.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43800/f30e78ec-b04b-0ffd-11f5-1b7fdf70ffa1.png)

`.vimrc` に下記を追記しておけば、標準で行数の表示がされるようになります。

```vimscript
set number
```

一方で非表示にしたい場合は `:set nonumber` (省略形は `:set nonu` )で非表示にすることができます。

# 相対行番号の表示

Vimは相対行番号での移動がサポートされているのですが、その際に便利なのが相対行番号表示です。
`:set relativenumber` を実行すると自身のカーソルを基準とした相対行番号表示になります。

![スクリーンショット 2023-02-22 16.23.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43800/0f867b82-bd72-be7d-9b42-69db521330dc.png)

例えば上記の状態で `:+4` を実行すると `//time.Sleep(1 * time.Second)` の行に移動します。

![スクリーンショット 2023-02-22 16.26.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43800/d63b2633-5583-2aee-7981-4ed15761e560.png)

さらにこの状態で `:-7` を実行すると `var c chan interface{}` の行に移動します。
![スクリーンショット 2023-02-22 16.27.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43800/6e5b3679-b711-6563-3eb5-98d87c2c0312.png)

快適な行移動の旅をお楽しみください :airplane:
chatGPTとのjavascript勉強の記録

chatGPTを使って条件分岐の問題と解答を作成してもらいました。

問題：
以下の仕様に従って、JavaScriptで条件分岐の処理を行う関数を作成してください。

仕様：

引数として渡された数値が、0以上100未満の場合は「0から100未満の数値です」と出力する。
引数として渡された数値が、100以上200未満の場合は「100以上200未満の数値です」と出力する。
引数として渡された数値が、200以上の場合は「200以上の数値です」と出力する。
引数として渡された数値が、負の数の場合は「負の数です」と出力する。
解答：
```javascript:script.js
function checkNumber(num) {
  if (num < 0) {
    console.log("負の数です");
  } else if (num < 100) {
    console.log("0から100未満の数値です");
  } else if (num < 200) {
    console.log("100以上200未満の数値です");
  } else {
    console.log("200以上の数値です");
  }
}

checkNumber(365);
//200以上の数値です
```


次は繰り返し処理の問題を作成してもらいました。

問題：
以下の仕様に従って、JavaScriptで繰り返しの処理を行う関数を作成してください。

仕様：

引数として渡された数値に対して、1からその数値までの数字を順にコンソールに出力する。
出力される数字が、3の倍数の場合は「Fizz」と出力する。
出力される数字が、5の倍数の場合は「Buzz」と出力する。
出力される数字が、3と5の両方の倍数の場合は「FizzBuzz」と出力する。
解答：

```javascript:script.js
function fizzBuzz(num) {
  for (let i = 1; i <= num; i++) {
    if (i % 3 === 0 && i % 5 === 0) {
      console.log("FizzBuzz");
    } else if (i % 3 === 0) {
      console.log("Fizz");
    } else if (i % 5 === 0) {
      console.log("Buzz");
    } else {
      console.log(i);
    }
  }
}

fizzBuzz(15);
//FizzBuzz
```

引数について改めて理解できた。
引数とは、関数が処理を行う際に必要とする情報を、外部から渡すためのもの！
C#でローカルファイルをsharepointにアップロードサンプル

```
string fileLocation = "test.xlsx";
using(Stream = new FileStream(fileLocation,FileMode.Open,FileAccess.Read)
{
    var driveItem = await graphClient
        .Sites["sharepoint ID"]
        .Drive
        .root
        .ItemWithPath("test.xlsx")
        .Content
        .Request()
        .PutAsync<DriveItem>(steam);

}
```
# 参考サイト
https://stackoverflow.com/questions/59236249/upload-a-file-in-c-sharp-asp-net-core-to-sharepoint-onedrive-using-microsoft-gra
お酒好きの健康を守りたい｜飲酒ログアプリをリリースしました【個人開発】

![top_image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982087/4901c222-09de-b7d7-2919-fe9e3ee8019b.png)

手軽に飲酒を記録し、飲酒量・アルコール摂取量を見える化する飲酒簿アプリ「**酒の記録**」を作りました。

■ **iOS**

https://apps.apple.com/jp/app/%E9%85%92%E3%81%AE%E8%A8%98%E9%8C%B2/id1661597567

■ **Android**

https://play.google.com/store/apps/details?id=com.yuyatoyoizumi.lagavulin

### こんな方におすすめ
- 「別にお酒を減らしたいとかではないんだけど、もう年齢も年齢だし健康管理のために一応毎日どれくらい飲んだかくらいは把握してみようかな。」という方
- 「節酒しようとはいつも思っているんだけど、なかなかやめられないんだよね。とりあえず記録をつけるところからはじめてみようかな。」という方
- 「自分の飲酒の傾向ってどんなんだろう。体調とか時期とかで変化あるのかちょっと気になるな。」という方

### こんなことができます
- 日々の飲酒量やアルコール摂取量を記録
- お酒の種類ごとに分類して表示
- カレンダーやグラフで飲酒傾向を見える化

## 作ろうと思ったきっかけ
- お酒が好き
- でも健康管理もしないと
- お酒の量減らした方が良いかな
- いやまだ大丈夫かな
- とりあえず飲むか

という方結構いると思っているのですが、健康は失ってからその大事さに気づく系でなかなか取り戻せないと思うので、失う前にどうにかできないかということで色々考えました。

「減酒・禁酒しましょう！」みたいなアプリだと少しハードルが高い気がしたので、とりあえず飲酒量を記録だけしてみて、徐々に意識を高めていけば良いのではということでこのアプリを作りました。

## 技術的なところ
使用している主な技術は下記です。
-  Flutter
-  Firebase

本業の方で未経験のFlutter × Firebaseで開発をすることになり、早めにキャッチアップしたいということもあったのでこの技術を使って個人開発することにしました。

結果的には、個人開発で得た知見が実案件に活きたことはもちろんなのですが、実案件で得た知見が個人開発に活きることも結構あり、実案件と個人開発の両方の開発が加速して良い感じでした。

また、Flutter × Firebaseという構成自体が素早くアプリを開発するのに向いている気がするのと、ドキュメントもそれなりにあったので基本的にはサクサク個人開発を進められた気がします。

## 開発過程
開発した期間ですが、初回リリースまでだいたい1ヶ月、もろもろの機能追加でだいたい1ヶ月の合計2ヶ月でした。
平日は業後に１〜２時間くらい、土日は２〜３時間ずつくらい開発していたと思います。

本業がフルリモートで残業もほぼなかったということもあり比較的開発の時間はとりやすかったと思っていて、特に夜遅くまでやったりとかはなく楽しく開発できていました。

## 学んだことなど
- アプリ開発は初めてだったので、iOSとAndroidのアプリのリリースを経験できてよかったです。次からはもっとスムーズにリリースできそう。もっとやるぞ！
- DBはFirestoreを使ったのですが、NoSQLも初めて使ってみて少しだけ使い勝手がわかった気がします。
- Flutter（Dart）も初めてでしたが開発経験できてよかったです。

## まとめ
ここまで読んでいただきありがとうございます。
いいね・保存・シェアなどしていただけるととても励みになります！
もっとこういう機能があったら嬉しいなどコメントもいただけると嬉しいです。

▼ ダウンロードはこちらから
■ **iOS**

https://apps.apple.com/jp/app/%E9%85%92%E3%81%AE%E8%A8%98%E9%8C%B2/id1661597567

■ **Android**

https://play.google.com/store/apps/details?id=com.yuyatoyoizumi.lagavulin

<br>
<br>

:::note info
このプロダクトは、株式会社mofmofの「水曜日の個人開発」にサポートされています。
:::

https://indie-dev.mof-mof.co.jp
【個人開発】引っ越し先の住みやすさをサクッと知れるサービスを作りたかった（Next.js, Yahoo!ローカルサーチAPI, Geocoding.jp）

こんな感じのサービスつくりました。
![service-image-fake.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255661/1269e265-8aaa-6ff8-113a-e94ee3a9ca66.png)
嘘です。ほんとはこっち 
![service-image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255661/10d1baac-375d-a7b1-37e8-399aa271a28c.png)

（事情があり、記事内でサービスURLを紹介することは控えます。理由は後述します）

## 作ったもの紹介

①調べたい駅名を入力して検索

![input.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255661/2437909b-61d9-acdb-1eaa-126e3a9b14b2.png)

②結果が表示されます

![result.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255661/655b72a9-388a-4edd-0b53-112e1e835e02.png)

③複数の結果を見比べることができます

![results.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255661/8c767c23-2e1e-2395-6db5-82d2090b39e9.png)

- 周辺の施設数に応じて、検索キーワードの表示サイズが変わるようになってます。東京駅とかヤバい。
- 色々試してみた結果、暮らし系の割合が多いほどファミリーっぽくて、グルメ系の割合が多いほど遊びに行く場所だったり一人暮らしするっぽい街な傾向があるなあというのがわかってきました。
- （上位200件を取得していますが並び順はYahooのおすすめ順なので、ちょっと恣意性があるかも？）
- Geocodingとのやりとりがうまくいかずエラーになることが多いです…。キーワード変えたりリロードしたりする必要がある。~~でもGoogleのAPIめっちゃ高くて手が出ない~~

## ちなみに

所属している株式会社mofmofの「水曜日の個人開発」ってやつで捻り出た時間で作りました。毎週水曜日の日中は個人開発しなければいけない制度です。楽しい。
[https://indie-dev.mof-mof.co.jp/](https://indie-dev.mof-mof.co.jp/)

## 技術面

- **Next.js**
  - フロントだけでやれるかなって思ってたけど素振りしたらcorsで引っ掛かったからAPI Routes使おうと思って選定。SSRとかはしない。
  - 手癖でChakraUIいれた。もう超便利。
  - グラフ描画はrecharts。
  - /api/citiesに、キーワード受け取っていい感じにするのを生やした。
- **Yahoo!ローカルサーチAPI**
  - [https://developer.yahoo.co.jp/webapi/map/openlocalplatform/v1/localsearch.html](https://developer.yahoo.co.jp/webapi/map/openlocalplatform/v1/localsearch.html)
  - 駅の周辺情報を取得するのに利用。緯度経度を受け取って調べるって役割。
  - 別途キーワード→緯度経度してくれるAPIが必要だったのでGeocoding.jpにお世話になってます。
    - yahooのジオコーダAPIはキーワードから駅をピンポイントで取ってくるというのができなかったので不採用
  - こんな感じのを使ってる。レスポンスのResultInfoに件数、Featureに各施設の詳細が入ってる。
      - `https://map.yahooapis.jp/search/local/V1/localSearch?appid=${api_key}&dist=2&output=json&lat=${lat}&lon=${lng}&sort=hybrid&results=100`
- **Geocoding.jp**
    - [https://www.geocoding.jp/](https://www.geocoding.jp/)
    - キーワードを渡すと緯度経度を返してくれる。
    - `https://www.geocoding.jp/api/?q=${pointName}`って具合でキーワードを渡すだけ。
        - xmlで返ってくるので、`xml2js`でparseして使う。
    - 検索頻度が高いとこちらのサービス様に迷惑がかかってしまうので、今回の開発物のURLは本記事には掲載しません。ご了承ください。もし触ってみたいなって方いらっしゃったらTwitterまでリプライかDMください 🙏
    - こちら [https://twitter.com/yubachiri](https://twitter.com/yubachiri)

## 以上
社内でちまちま使って遊んでワイワイするにとどまってしまっていますが、キーワード→緯度経度代を出してくれる人が出てきたら機能拡充したりUXもっと整えたりしてちゃんと公開したいなあと思ってます。