OmniAICreator/Qiita-1.07M huggingface dataset:
DjangoでWebアプリを作ってみる。【vol. 03 DBをPostgreSQLに変更する。】

※[こちら](https://qiita.com/TsJazz27Sumin/items/e91f61364366aa341bf4)の記事の続きです。
## DBをPostgreSQLに変更する。

こちらの記事を参考にさせていただきました。

 - [DjangoにPostgreSQLを適用する](https://qiita.com/shigechioyo/items/9b5a03ceead6e5ec87ec)
 - [Windows環境でPython + DjangoにPostgresqlへ接続する方法](http://www.sassy-blog.com/entry/2017/04/11/000646)

元々Sqliteが入っているのですが、普段使っているのがPostgreSQLなので変更したいと思います。
※すでにPostgreSQLのインストールは終わっている前提です。

### psycopgのインストール

[こちら](http://initd.org/psycopg/download/)が管理サイトになっています。
現在の最新は、

>The current stable Psycopg release is 2.8.3:

となっています。

コマンドラインからインストール可能だったので、pipを使って実行しました。

```
pip install psycopg2
Collecting psycopg2
  Downloading https://files.pythonhosted.org/packages/3b/b4/b6db75663e1c73bb6190cbcbb02f94a36c574b813a353446087cbdf43712/psycopg2-2.8.3-cp37-cp37m-win_amd64.whl (1.1MB)
     |████████████████████████████████| 1.1MB 501kB/s
Installing collected packages: psycopg2
Successfully installed psycopg2-2.8.3
```

### DB接続定義の修正

「settings.py」内に76行目あたりにDB接続定義の記載があったので以下修正しました。

```
DATABASES = {
    # 'default': {
        # 'ENGINE': 'django.db.backends.sqlite3',
        # 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    # }
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'postgres',
        'USER': 'postgres',
        'PASSWORD': 'postgres',
        'HOST': '127.0.0.1',
        'POST': '5432'
    }
}
```

### マイグレーションの実行

マイグレーションを実行します。

```
python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying sessions.0001_initial... OK
```

pgAdmin4で確認してみたところ、

<img width="291" alt="pgadmin.JPG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280384/00836a5d-f47f-12b0-2d58-245a152326ad.jpeg">

確かにDjango関連のテーブルが作成されています。
MVVM雑感

Windows Formから、WPFのコードビハインド。次に、MVVMを学んでコードを書いています。
MVVMについての感想を、つらつら書きます。


#MVVMで苦労している点
- 例えると、コードビハインドでは、（右利きの場合）右手にペンをもって、左から右に文字を書いていたけれども、MVVMでは、左手にペンをもって右から左の逆の順に文字を書いているようなものになった。
- 例えると、コードビハインドでは、図と解説を、1枚の書類に収めれば良かったが、MVVMでは、図と、解説と、図と解説との間を繋げる書類の、3枚の書類が必要になった。
- コードビハインドは、データの流れが一方通行でデバッグ時追跡しやすかったが、MVVMでは、データがどこに流れているのか追跡しにくい。
- コードビハインドでは1行で済むのを、MVVMの方法に合わせるために5行も10行もそれ以上にコードを書かないといけない場合がある。

と、ここまで、デメリットを書きましたが、メリットも実感しています。

#MVVMで感じるメリット
- WPFでは、データバインディングを利用するため（しなくてもいいが、した方が楽）、Viewで表示するためのプロパティを1カ所に集めるのは合理的。従って、Viewで利用するプロパティを、1つのViewModelに集約して、1対1の関係にしてしまう、のは分かりやすくなる。特に、ListViewやDataGirdで表示するデータを1行ずつ、VMにしてからListViewやDataGridにバインドする場合は、都合が良い。
- Viewと、ViewModelはパターン化できる。従って、後で見返したときも、理解しやすい。

#その他
- View, ViewModel, Modelの役割を明確に分けることで、パターン化できるが、ViewModelの役割をよく考えてコードを書かないと、Modelの領分を侵してしまう。どこまで、ViewModelの役割にするのか、考える必要がある。
- ListViewの1行ずつを、ViewModelにする方法は、よくあるMVVMの関係を示す図からは、想定できない。
- MVVMを実現するためのコードの書き方が、考え方の差によるバラツキが大きい。
例えば、Viewのコードビハインドで、イベントをキャッチして、それを、VMに渡す、というのでも、VMからはVは疎結合のままなので、良いという考え方もある。

#現時点
- 学習コストが高い
- MVVMを実現するためのフレームワークもツールもまだまだ足りない、不便。
- ネットのMVVMのサンプルや解説はどれがお手本として適切なのか見極めるのが難しい
- 大規模なアプリなら、MVVMで構築した方が、その後の機能追加や、修正を行いやすくなると思う。
- 小規模なアプリなら、開発効率は低下する。


## MVVMの記事
* [MVVM Show View パターン1 Viewのコードビハインド](https://qiita.com/hiro_t/items/967146f2ccb79318397c)
* [MVVM Show View パターン2 Commandパラメータ](https://qiita.com/hiro_t/items/b177c40e03d22ef24068)
* [MVVM Show View パターン3 Prism の Dialog Service](https://qiita.com/hiro_t/items/61a50d9f6308195c3536)
* [MVVM List Detail パターン](https://qiita.com/hiro_t/items/2c843a8b2117573d9bfa)
PythonというかDjangoで Markdownの表

Djangoを使っていて，Markdownで表を書くときのメモ．

要は，```extensions=['tables']```を指定するということ．
これを指定しないと，Markdownで表を書いても```<p>....</p> ```でレンダリングされる．

```python:markdown.py
from markdown import Markdown
from django.utils.html import mark_safe

class MarkDownView(TemplateView):                                                            
    template_name = 'myapp/markdown.html'

    def get(self,request,*args,**kwargs):
        mdsrc = '.....some mark down text including a table.....'

        md = Markdown(extensions=['tables'])
        md_html = mark_safe(md.convert(mdsrc))

        self.extra_context = { 'md_html': md_html , }
    return super().get(request,*args,**kwargs)
```

テンプレート側では，お約束でsafeを指定します．

```python:myapp/markdown.html
         :
    {{ md_html|safe }}
         :
```

他のextensionsについては下記．

https://python-markdown.github.io/extensions/
python起動時のエラーメッセージ①

# エラーメッセージ 
```python

Failed calling sys.__interactivehook__
Traceback (most recent call last):
  File "C:\Users\username\Anaconda3\lib\site.py", line 439, in register_readline
    readline.read_history_file(history)
  File "C:\Users\username\Anaconda3\lib\site-packages\pyreadline\rlmain.py", line 165, in read_history_file
    self.mode._history.read_history_file(filename)
  File "C:\Users\username\Anaconda3\lib\site-packages\pyreadline\lineeditor\history.py", line 82, in read_history_file
    for line in open(filename, 'r'):
```

python起動時にこのようなエラーメッセージが出るようになったので、それを解消した。

C:\Users\username

にあるpython_historyというファイルを消すことで解決した。
[JS]console.log(2==1==0)←これがtrueの件

# はじめに
先日Twitterで、@TaneoKoyamaさんが面白いツイートをしていたので、今回はこれを一歩深入りして調べてみます。
# 今日のコード
```javascript
console.log(2==1==0); // => true
```
これ、実際にやってみると本当にtrueになります。
面白い。
# 解説
1つずつ分解して、調べていきましょう。

```javascript
console.log(2==1); // => false
```
↑この段階では、falseになりますが…

```javascript
console.log(false==0); // => true
```
↑これがtrueになるのが、このコードのキモですね。
JavaScriptの仕様では、「数字の0」はfalseになります。
その結果、`2==1==0`がtrueになるという事態がおきます。
# 順番を変えて、0==1==2にしたら？
```javascript
console.log(0==1==2); // => false
```
結果はfalseです。
分解してみると…

```javascript
console.log(0==1); // => false
```

```javascript
console.log(false==2); // => false
```
という処理を行なっています。処理が左から行われていることが、確認できますね。
# 厳密等価演算子で、2===1===0にしたら？
```javascript
console.log(2===1===0); // => false
```
はい、無事falseになってくれました。
## 等価演算子（==）と厳密等価演算子（===）の違い
普段、何気なく使っている等価演算子「==」ですが、型変換をして判断してくれる特性がありました。
これにより、false（ブーリアン型）は「0」に型変換されるので、`0=0`という判断になってしまうんですね。

一方、厳密等価演算子（===）は、型変換を行いません。
なので、falseはfalse、0は0なのです。
つまり判断しても、これは等価にはなりません。

## よく似た例
```javascript
console.log(null == undefined); // => true
console.log(null === undefined); // => false
```

```javascript
console.log(0 == ''); // => true
console.log(0 === ''); // => false
```
# 結論
 - `x==y==z`といった形の場合、左から潤に処理される
 - 「==」と「===」は明確に違う演算子である
 - 「==」の型変換に注意する
 - JSでは、0（数値）やnull、undefined、''(空文字)はfalseとして扱われる

以上です。
最後までありがとうございました。

[参考にしたページ①](https://qiita.com/PianoScoreJP/items/e43d70ec188c6fed73ed)
[参考にしたページ②](https://qiita.com/katsuo5/items/ffb8b83c6b8a6dcbd9d6)
Selenium ActionChainsでStaleElementReferenceExceptionが発生する原因と対策 要検証

# はじめに

Seleniumを使っていると、StaleElementReferenceExceptionが発生しました。
だたし、操作対象のelementは直前に取得しており、なおかつ表示されているので存在していないとは考えられませんでした。
そこで、自分が変更した個所と動作を検証した結果、原因らしきものが分かりました。
もっとも、原因に関しては個人の予想の範疇なので間違っているかもしれません。

# 例外が発生する記述

単純化すると以下のような記述の場合に発生します。

```python:python
actions = ActionChains(driver)

element = driver.find_element(By.ID, "1")
actions.move_to_element(element).perform()

# 何かの処理
# その結果、IDが"1"のelementの参照が切れる

element = driver.find_element(By.ID, "2")
actions.move_to_element(element).perform()
```

この記述だと、2度目のactions.move_to_element(element).perform()でStaleElementReferenceExceptionが発生するはずです。
なぜならば、move_to_elementの出発点がidが"1"のelementのためにその参照が必要なためと思われます。

もしくは、以下のようにしても例外が発生すると思います。
actions.click(element)は、内部でactions.move_to_element(element)を呼んでいるからです。

```python:python
actions = ActionChains(driver)

element = driver.find_element(By.ID, "1")
actions.click(element).perform()

# 何かの処理
# その結果、IDが"1"のelementの参照が切れる

element = driver.find_element(By.ID, "2")
actions.click(element).perform()
```

# 修正方法

上記の記述で問題だったのは、ActionChainsのインスタンスを使いまわしてしまったことです。
これを避けるためには、インスタンスを作り直せば良いだけです。

```python:python
actions = ActionChains(driver)
element = driver.find_element(By.ID, "1")
actions.move_to_element(element).perform()

# 何かの処理
# その結果、IDが"1"のelementの参照が切れる

actions = ActionChains(driver)
element = driver.find_element(By.ID, "2")
actions.move_to_element(element).perform()
```

# 最後に

わざわざインスタンス作り直す必要ないだろうと横着しようとしたら思わぬエラーにぶつかりました。
適当な事をしては駄目という事でしょうか。
とりあえず対策できて一安心です。
C系言語のforeach

C言語族の言語はif～else、forといった基本制御構文はほぼ同じ書き方ができることが多いけど、foreach(ループで配列などのコレクションを回す構文)はベースになったC言語には存在しなかったため言語ごとに違いが出て面白いなぁと思い、まとめてみた。
## for
```php
//C++
for(auto i=0;i<size(collect);i++)
//C#
for(var i=0;i<collect.Length;i++)
//D
for(auto i=0;i<collect.length;i++)
//Go
for i:=0;i<len(collect);i++
//Java
for(var i=0;i<collect.length;i++)
//JavaScript
for(var i=0;i<collect.length;i++)
#Perl
for(my $i=0;$i<scalar(@collect);$i++)
//PHP
for($i=0;$i<count($collect);$i++)
```
まずはfor文。
配列の長さを表す構文に個性があることを除けば大体一緒。

## foreach
```php
//C++(C++11以降)
for(auto v:collect)
//C#
foreach(var v in collect)
//D
foreach(v;collect)
//Go
for _,v:=range collect
//Java(Java 1.5(J2SE 5.0)以降)
for(var v:collect)
//JavaScript(ES6(ES2015)以降)
for(var v of collect)
//PHP(PHP4以降)
foreach($collect as $v)
#Perl
foreach my $v(@collect)
```
見事にバラバラで後天的にforにforeachの機能を備えさせる言語も多い(C++,Java,JavaScript)。
個人的にas句でループ変数とコレクションの順序が入れ替わってるPHPがややこしく感じる。

以上、内容はこれだけです。
言語によっては参照の設定の有無もあったり、イテレータ回したり、連想配列に対するものとか細かい挙動は異なるよね。

## 実行環境
[C++](https://paiza.io/projects/caQeLBy3fYsakAmGUuii2A)、[C#](https://paiza.io/projects/_pQLzRpV_z06WR4Z6n36IQ)、[D](https://paiza.io/projects/wlKg3SCdDr81EJk4oeWYnQ)、[Go](https://paiza.io/projects/hR7kTIZxN0Kt5iSlG1KE4g)、[Java](https://paiza.io/projects/3igJ0Rt7Rnjng23jw18_eQ)、[JavaScript](https://paiza.io/projects/pnSWHqE6hnXXoSMqsec14Q)、[Perl](https://paiza.io/projects/Mvdr7gAXVg-qB_p3OW92rQ)、[PHP](https://paiza.io/projects/Pl2tLocA-T6WCmnI13V3tA)
android(java)でluaJを使った電卓を作る

#前書き
hotmanです
通常電卓やプログラミング言語を処理するには構文解析する必要がありますが、luaJ等のインタプリタのライブラリを使えば、そいつが勝手に構文解析&実行してくれます
つまりは大幅な作業コストのカットになります
ではやり方の説明
#luaJの導入
[luaJダウンロードページ](http://www.luaj.org/luaj/3.0/README.html#8)からluaJを落としてきまして、解凍すると中にあるluaj-jse-3.0.1.jarを(プロジェクトフォルダー)/libsにぶちこんでやるぜ

#activity_main.xml
今回作るのは電卓なので入力スペースと出力スペースを用意します

```xml:activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">


    <EditText
        android:id="@+id/editText"
        android:layout_width="match_parent"
        android:layout_height="70dp"
        android:inputType="text"
        android:text=""
        android:textSize="50sp" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:text=""
        android:textSize="100sp" />
</LinearLayout>
```

#MainActivity.java
luaJ使うだけ、
ちなみに
```globals.load(text).call()```
textをluaコードとして実行
```globals.set(text,val)```
textの変数名にvalを代入
```globals.gat(text)```
textの変数名に入っている値を取得
です

```java:MainActivity.java
package com.test.gameeditor;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import org.luaj.vm2.*;
import org.luaj.vm2.lib.jse.*;
import android.widget.*;
import android.view.*;
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final Globals globals = JsePlatform.standardGlobals();
        final EditText et=findViewById(R.id.editText);
        final TextView tv=findViewById(R.id.textView);
        tv.setText("0");
        globals.set("x",0);
        et.setOnEditorActionListener(new TextView.OnEditorActionListener() {
            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                LuaValue chunk = globals.load("x="+et.getText().toString()).call();
                tv.setText(Integer.toString(globals.get("x").toint()));
                return false;
            }
        });
    }
}
```

むしろ前回のandoridでアニメーションより簡単まである

#以上
#あとがき
lua+javaは最高
エラーハンドリングがないのは仕様です
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">luaJを使ってandroidで電卓作った〜<br>これもQiitaに纏めるので特にScriptEditorチームの方は確認お願いしま〜す <a href="https://t.co/o8w8dN7iTO">pic.twitter.com/o8w8dN7iTO</a></p>&mdash; hotman (@hotmanww) <a href="https://twitter.com/hotmanww/status/1142354468089896962?ref_src=twsrc%5Etfw">2019年6月22日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
Scrapboxのuserscriptを使ってリンク先をプレビューする

# Demo

[![Image from Gyazo](https://i.gyazo.com/907c8c828d662bd987e15d3d0de2c3c4.gif)](https://gyazo.com/907c8c828d662bd987e15d3d0de2c3c4)

# Userscriptの使いかた

については下記のサイトなどを参照してほしい。
https://qiita.com/beeeyan/items/0d04b1859943a9a1e92c

# ライブプレビューのjQueryプラグイン

[http://www.ampedupdesigns.com/blog/show?bid=49](A LIVE link preview window for links on hover over using Jquery and CSS3)を採用。コードをここからダウンロード > [https://github.com/alanphoon/jquery-live-preview](https://github.com/alanphoon/jquery-live-preview)

# userscriptは以下を参照

[https://scrapbox.io/wordbook/yamato](https://scrapbox.io/wordbook/yamato)

### ポイント：jquery-live-preview.js をそのままコピペしても動かないです。
```jquery-live-preview.js
//(function($) {

(省略)

//})(jQuery);
```

という感じでコメントアウトしてください。

# CSS

livepreview-demo.css を usercss として settings にコピペ。
例：[https://scrapbox.io/wordbook/settings](https://scrapbox.io/wordbook/settings)

# ローディングアイコン

上記のSettingsの中でどこか参照できるところにこれを置く。

 ![icon_loading.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18839/5d8154ec-88d8-5ce6-24a2-57f44c20a0ce.gif)

というかこれで置かれているので、settingsの中のlivepreview-demo.cssをコピペした内容の下記のところを書きかえる。

```livepreview-demo.css
//background-image:url('/images/icon_loading.gif');
     background-image:url('https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18839/5d8154ec-88d8-5ce6-24a2-57f44c20a0ce.gif');
```

# 課題

現状はリロードしないとaタグのclassが書き変わらないときがある。どうしたものだろう。

以上です。これで英語の勉強が益々捗る。
Railsのフォームの確認画面でアップロードする画像のファイル名を表示する

開発しているサービスで確認画面にてアップロードするファイル名を表示するのに少しハマったので共有します。

こちらのブログを参考にフォームを作成します。
http://rakio1234.hatenablog.com/entry/2017/01/09/234744

##まずはフォームを作成
確認画面であるurlオプションでconfirm.html.erbに飛ばします。

```erb:new.html.erb
<div class="form">
  <%= form_with model: @hoge, url: {action: 'confirm'} do |f| %>
      <div>
        <%= f.label :image, "画像ファイル" %>
        <%= f.file_field :image %>
        <%= f.hidden_field :image_cache %>
      </div>
      <div>
        <%= f.submit "確認画面へ進む" %>
      </div>
  <% end %>
</div>
```

コントローラーはこちら


```ruby:hoge_controller.rb
  def confirm
    @hoge =  Hoge.new(hoge_params)

    return if @hoge.valid?(:hoge_validation) #validateチェック
    flash.now[:alert] = "入力内容にエラーがあります。"
    render :new 
  end

  private

    def hoge_params
      params.require(:hoge).permit(:image, :image_cache)
    end
```

##フォームの確認画面

```erb:confirm.html.erb
<div class="container">

  <div>
    <!-- 三項演算子 -->
    <p><%= @hoge.image.present? ? @hoge.image.filename : "添付ファイルなし" %></p>
  </div>

  <div>
    <%= form_with model: @hoge, url: hoges_path do |f| %>
      <%= f.hidden_field :image, value: @hoge.image %>
      <%= f.hidden_field :image_cache, value: @hoge.image_cache %>
      <%= f.submit '投稿する' %>
    <% end %>

    <%= form_with model: @hoge, url: new_hoge_path do |f| %>
      <%= f.hidden_field :image, value: @hoge.image %>
      <%= f.hidden_field :image_cache, value: @hoge.image_cache %>
      <%= f.submit '入力画面へ戻る' %>
    <% end %>
  </div>
</div>
```
@hoge.imageにfilenameをつけることによってファイル名を取得できる！
これだけのことにだいぶハマりました。
入力画面へ戻るときはbackアクションへ、そのまま投稿する場合はcreateアクションへ

```ruby:hoge_controller.rb
  def back
    @hoge = Hoge.new(hoge_params)
    render :new
  end

  def create
    Hoge.create!(hoge_params)
    flash[:success] = "保存に成功しました！"
    redirect_to  complete_hoge_path
  end
```
「入力画面へ戻る」ボタンを押したら、backアクションが呼ばれるようroutingを設定

```ruby:routes.rb
   resources :hoge do
     collection do
        post :new, path: :new, as: :new, action: :back
     end
   end
```
これでbackアクションが呼ばれた際、routingで戻った先のURLはhoge/newになる。

##ちなみに

ファイル名だけ、拡張子だけをそれぞれ取得する場合は下記の通り。
拡張子を含むファイル名がsample.rbだとすると

```ruby:
File.basename("sample.rb", ".*")
#=> "sample"

File.extname("sample.rb")
#=> ".rb"
```

ファイルの名前や拡張子も簡単に取得できますね！
CP/Mいろいろ

中学校の頃に憧れだったCP/Mがフリーで手に入る時代になったので、いろいろ調べてみました。

CP/Mは8080向けに開発されたOSで、デジタルリサーチ (Digital Research Inc.)という会社の製品でした。8080の互換のZ80でも使うことができました。しかし16Bitの8086になったときにMS-DOSにシェアーを奪われ衰退し、会社は売却されました。現在もCP/Mの権利はあるのですが、保持している会社が[フリーでの使用](http://www.cpm.z80.de/)を容認している様です。

![写真（2019-06-23 9.04）.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/09fc0de5-b8c3-990e-93d1-48c7ab6fc101.jpeg)

8080やZ80はリセット後0番地から命令を実行し始めます。CP/Mではなんらかの方法でディスクの最初のセクターを0番地からのメモリに貼り付け実行して、この処理がBIOSやBDOSなどをメモリの最後の方に読み込み、実行を渡します。

0番地への読み込みは、スイッチでの手打やDMAやROMで起動してメモリに貼り付けそのメモリが0番地に変わるようなロジックで処理されていたと思われます。

今から考えると不思議な仕様なのですが、Altairが0番地からメモリが実装されていて、そこにスイッチの手打ちでバイナリをセットする仕様だった事から来ているような気がします。

# 本物系

* SDを使ったモジュール

http://star.gmobb.jp/koji/cgi/wiki.cgi?page=AVR%A4%C8Z80%A4%C7CP%A1%BFM

* CFを使ったモジュール

http://yuuyuusyumi.blogspot.com/2019/04/aki-80-cpm-box.html

ROMを使うものと使わずAVRやPICマイコンを使うものがあります。またCPLDやGALを使ったものもあるようです。リンクは目に付いたもので、他にもいろいろあります。

PC-8001などの国産のパソコンでもCP/Mは動いていましたが、それぞれのメーカーがポートした部分はオープンにはなっていないので、現在これらを使うことはほぼ不可能だと思います。

# エミュレーター系(マイコン) 

* AVRにDRAMを使ったもの

多分これが、最初に出てきたマイコンを使ったエミュレーター系。オリジナルはATMEGA88でした。DRAMとSDカードを使います。

http://spritesmods.com/?art=avrcpm&page=2

* AVRにSRAMを使ったもの

上のDRAMをSRAMに変更したもの。SDカードを使います。

https://github.com/toyoshim/cp-mega88

* RunCPM

複数のプラットフォームに対応していて、SDカードを使います。GPIOのサポートがあるようです。

https://github.com/MockbaTheBorg/RunCPM

VGAをサポートしたforkもあるようです。

https://github.com/guidol70/RunCPM_VGA32

* cpm8266

ESP8266をターゲットにした実装で、SPI Flashにドライブを置いて、SDなどが必要ありません。Flashの容量は4M必要です。nosdkというコードを使ってメモリを広く(62K)使えるようにしているようです。ESP-01のような小さなモジュールでも動き、オススメです。

https://github.com/SmallRoomLabs/cpm8266

* CP/M on FPGA

FPGAで作ってるのもありました。

http://searle.x10host.com/Multicomp/cpm/fpgaCPM.html

# エミュレーター系(PC)

MacやFreeBSD上で動く処理系

* SIMH

https://schorn.ch/altair.html

VAXなどのエミュレーターのSIMHに8080とZ80のエミュレーターが入っていて、それを使ってCP/Mを動かすことができます。[日本語の解説のページ](http://okgnz.web.fc2.com/zbrd/zbrd21.htm)

CP/M以外にも4K BASICなども動きます。

* YAZE-AG

https://www.mathematik.uni-ulm.de/users/ag/yaze/

CP/MのエミュレーターではなくZ80のエミュレーターとのこと。Windowsではcygwinが必要。

CP/Mはマイコンがセルフ開発できるようになった初めての環境だったと思います。これ以前の開発はPDP11などの高価な環境が必要でCP/Mは画期的だったとおもいます。マイクロソフトのBasicもビルゲイツが大学のPDP11を使って作ったと言われています。

とはいえ、1980年くらいには64KのメモリとフロッピードライブまたCP/M本体と各種ソフトで100万円くらいしていたと思います。さすがに中学生の自分には手が出せませんでした。
Azure DevOps のリポジトリをSourcetreeで管理する

# やりたいこと
* Azure DevOps のリポジトリを Sourcetree で管理させる

# 環境
* Azure DevOps
* Sourcetree Ver 3.1.2

# Azure DevOps側の設定
\[Repos\](左側のメニュー)-\[Clone\](右上)-[Generate Git credentials]を選択
**Clone repository**より、パスワードを設定します。Aliasは任意です。
[Save Git Credentials]で保存します。
次の項目をコピーしておきます。

* HTTPS
* User name(or Alias)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443524/152ecbe0-7b85-f8c3-8788-1198221bb767.png)


# Soucetree側の設定
[アカウントの追加]より、
**Azure DevOps**を選択します。
ホストURLに先ほどコピーしたHTTPSを貼り付け、内容を下のように変更します。
https://\*\*\*\*@dev.azure.com/\*\*\*\*/xxxx/_git/xxxx
↓
https://****.visualstudio.com
[Credentials]-[Personal Access Token を再読み込み]より
ユーザ名とパスワードが要求されます。
ユーザ名：コピーしたUser name(or Alias)
パスワード：設定したパスワード
これでアカウントが設定され、Azure DevOpsからCloneできるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443524/11145a52-beba-70b6-5d9c-852218cba988.png)
Google Apps Scriptでログが表示されない2019年4月9日以降

Google Apps Scriptを使って、LINE Botを作ろうとした際にログが吐き出されずハマりまくったので、後続の方の参考になればと思います。

##Google Apps Scriptの仕様が2019年4月8日以降に変わった
プログラミング初心者なので表現が間違っているかもしれませんが、デフォルトでstackdriverを開くと下記のようなポップアップが出ます。エンジニアの方々からすると楽勝なのかもしれませんが、4月9日以降の記事がほとんどなく、これに対する対応が全くわからなかった。

<img width="739" alt="スクリーンショット 2019-06-23 8.55.49.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/444878/d515d618-1aef-63ce-3f05-2e6c5d87d722.png">


##Google Cloud Platformに紐付ける
対応としてはGCP(Google Cloud Platform)に紐付けるだけなのだが、説明ページが素人にはなかなか読み解けず時間を浪費した。
###紐づけ方法
やり方はGCPのホーム画面にプロジェクト情報があるので、そこに記載されているプロジェクト番号をコピー、GASのリソース>Cloud Platoform プロジェクト を選択しそこに、コピーしたプロジェクト番号を貼り付けるだけ。
<img width="464" alt="スクリーンショット 2019-06-23 9.02.29.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/444878/a3ed6fb9-caac-3db5-d691-6903f3f2c38e.png">

#####※プロジェクトがない場合は新たに作成する必要があります。

##ログが表示された！
上記処理を行うと、めでたくログが表示されました！
<img width="866" alt="スクリーンショット 2019-06-23 8.30.16.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/444878/c8d5de6a-2e41-5e83-5809-95fe9f096b62.png">

##余談
ただ、この表示を探していた原因である文字おこしくんというLINE BOTのチュートリアルに表示されているコードのエラーはいっこうに改善されず、遅々として進まないことに身悶えしていますが、それはまた別のお話。

このコードだけで、LINEからメッセージを送ると、
```
function doPost(e) {
 const lineJson = JSON.parse(e.postData.contents);
 console.log(lineJson);
}
```
下記のようなログが返ってくるということなんですが、全く返ってきません。。。わかる方おられましたら教えてくださいませ〜


![picture_pc_2bd1f129a39f5e566b8c8522977ef81d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/444878/8b5fadda-8be1-ba7c-83b5-e5d095d90276.png)
ipynbやmdファイルをnbconvertやpandocを使ってpdfに変換する方法

# 背景
jupyter notebook上でmarkdownで書いた数式が，github上では正しく表示されない現象が発生したため，ipynbやmdファイルをpdfにする方法を調べたときのまとめです:muscle:
（※もし，もっと簡単な方法をご存知であれば是非教えてください:blush:）
# 動作環境
Windowns10
jupyter notebook: 5.7.4
pandoc: 1.19.2.1
chocolatey: 0.10.13

# 必要な物
pandoc，TexLive，jupyter notebookなど
インストール方法は，色々あると思いますが自分はpandocはchocolateyで入れました
`choco install pandoc`

また，pandocはtex環境を用いるのでそちらも別で用意する必要があります．自分は，TexLiveを使っています．

# 結論
ipynbファイルは，
`jupyter nbconvert hoge.ipynb --to latex`で，texファイルに変換して
`platex hoge.tex`
` dvipdfmx hoge.dvi`
で，pdfにできます

mdファイルは，
`pandoc hoge.md -o hoge.pdf --latex-engine=lualatex -V documentclass=ltjsarticle -V luatexjapresetoptions=hiragino-pron`

で，pdfに変換できます
（※hogeはファイルの名前で置き換えてください）

# 補足
pandocは，様々なフォーマット形式を別のフォーマット形式にすることができるドキュメント変換ツールです．自分の環境では，pandocが「LuaLaTeX」と「XeLaTeX」しかサポートしていないようなので，「LuaLaTex」で実行しました．

# 参考文献
https://pandoc.org/
https://cartman0.hatenablog.com/entry/2016/03/29/131903
composer global require ほげほげで失敗しまくった話

## 結論
global で色々やるのはやめたほうがいい。

### だがしかし現実
とはいえその道の玄人じゃないので、公式の通りやっちゃうんですよね。

### 解決策 (全消し脳筋パターン)
1. ターミナルで global のディレクトリ `/Users/[あなたのユーザ名]/.composer/` に移動する
2. composer.json を削除
3. `vender` ディレクトリの中身を全て削除
4. `composer clear-cache` を実行
5. `composer.lock` を削除

### 注意
* 実行環境は macOS
* *入れたもの全部消えます (他のプロダクトに影響する可能性大)*
* composer コマンドはパスを通してある前提

## 失敗したこと
次のコマンドを発行したところ、
`composer global require "laravel/homestead=~2.0`
以下の結果になった。
`Installation failed, reverting ./composer.json to its original content.`

ログを見ると `conflicts with` とか `Installation request for ほげほげ (locked at v4.3.1) -> satisfiable by ほげほげ[v4.3.1].` といったものがみえる。
インストール済みのライブラリと、これから入れたいものが使うライブラリでバージョンが食い違っているよという話のようだ。
node とか他のパッケージマネージャを見習ってほしい。

### トライアンドエラー
#### composer.json の削除
まずやって見たのが `composer.json` の削除。

```console
rm composer.json
```
当然のごとく改善せず。

`composer.json` は npm で言うところの `package.json` みたいなもので、このライブラリ使いますと言う宣言ファイルに過ぎない。
なのでこれを消したところで実態は消えないので何の解決にもならない。

#### `vendar` ディレクトリの中身を削除
じゃぁ、実態を消してみよう。

```console
rm -rf vendar/*
```
はい、だめでした。

なぜかと言うと、実態は消えてもインストールした実績が残っているからだ。
実績は `composer.lock` というファイルで管理されており、これは npm で言うところの `package-lock.json` に当たる。

#### キャッシュをクリアして見る
`composer.lock` に気づく前に、キャッシュクリアを試してみた。

```console
composer clear-cache
```
だめでした。

理由は前述のとおり。

#### composer.lock の削除
```console
rm composer.lock
```
これでやっとインストールできるようになりましたとさ。

git でこいつらを管理するかどうか論争があるのはこう言う不幸があるからなのだろう。
もちろん管理する意義はあるとは思う。
この辺りは宗教とか政治に通ずるものがあるので深入りはしない。

## composer
便利なので用法用量を守って使用してね！
良き composer life を！
Railsチュートリアルのログイン処理(8~9章)を図解でしっかり理解する。

会社の研修でRailsチュートリアルを実施しましたが、8~9章のログイン周りがややこしく、ふわっとした理解しか得られませんでした。しっかり理解したいなとー思っていたので、ログイン時の流れをフローにして整理したところ、意外とスッキリ理解できたので、記事にしてみました。

*図が小さく見辛いですが、ご容赦下さい。

## 押さえておかないと、こんがらがる点
前提として、認識しておいた方が良いと思う点です。
個人的には、この辺りを把握できたことで理解の大きな助けになりました。

  - **セッションはサーバーで管理されていない<br>**
    セッション情報はサーバー側で保持されていると思うかもしれないが、Railsのデフォルトでは**クッキーに保存されている。**<br>
参考：[Railsのセッション管理には何が最適か - Qita](https://qiita.com/shota_matsukawa_ga/items/a21c5cf49a1de6c9561a)
<br>
  　 <br>
  - **一時ログインと永続ログイン、結局どちらもクッキーを使っている<br>**
     上記のようにセッションをクッキーで管理しているので、一時ログインには有効期限が一時的なクッキー(=セッションを保持するクッキー)を使い、永続ログインには有効期限が２０年のクッキーを別で発行して利用している。<br>
　<br>
  - **セッション用のクッキーはログインする前から作られている<br>**
    ログイン後にセッション用クッキーが作られると思って検証ツールを眺めていたが、新しくクッキーは作られていなかった。どうやら、デフォルトで生成されている"_アプリ名_session"という名前のクッキーがセッション情報を保持しており、そこにログインに必要な情報が追記される形のようだ。
    
## (図解)ログインするときの流れ
コードの一行一行が、何をしているかを書きました。
これを読めば、ログイン処理の裏で何をしているか理解する助けになると思います。

![Rails_Tutorial_Chap9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283137/cfdc02a9-1f2f-167e-ce08-314f80d4205f.png)

## ログイン後に再度サイトにアクセスする時の流れ
追記予定です。

## 参考文献
[Quora | セッションを暗号化することになんの意味がありますか？...](
https://jp.quora.com/%E3%82%BB%E3%83%83%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%92%E6%9A%97%E5%8F%B7%E5%8C%96%E3%81%99%E3%82%8B%E3%81%93%E3%81%A8%E3%81%AB%E3%81%AA%E3%82%93%E3%81%AE%E6%84%8F%E5%91%B3%E3%81%8C%E3%81%82%E3%82%8A%E3%81%BE)
[Railsチュートリアル | 8,9章](
https://railstutorial.jp/chapters/basic_login?version=5.1#cha-basic_login)
Oculus Integrationを用いたVive開発時のコントローラー対応について

# TL;DR

- 概ね直感的な対応付けがされている(Thumbstick->タッチパッド、など)
- 物理的に対応していないキーがある(A,X,Start,Back)
- クロスプラットフォーム対応するなら事前に使うボタンの選別をしておくとよさそう

# 初めに

Oculus Integrationは`1.31`からクロスプラットフォームに対応しており、そのままSteamVRなどで動作させることが出来ます。

基本的にはマジでそのまま動くのですが、コントローラーに関しては物理的に形状やボタンの有無等が異なるため対応が必要になります。今回はその辺りの対応についてまとめたいと思います。主にQuest->Viveを想定した書き方になっています。

参考: [Oculus Unity Integrationクロスプラットフォーム開発ドキュメンテーション 私家訳版 | heistak]( morning https://www.heistak.com/2018/12/04/oculus-unity-crossplatfom-jp-translation/)

# 環境

- Unity 2018.3.14f1
- Oculus Integration for Unity - 1.37
  - Oculus Utilities Plugin 1.32.0
- Windows 10 Home 1809

# Viveで動作させるまで

Oculus Integrationを使って開発したプロジェクトをViveで動かす際に必要だった手順です。

[Player Settings]-[XR Settings]-[Virtual Reality SDKs]にて`OpenVR`の追加だけ必要になると思います(デフォで入ってるかも)。それに伴い、[Window]-[Package Manager]より[OpenVR (Desktop)]もInstallsいてください。記事執筆時は`1.0.5`でした。

以上で、SteamVR Pluginのインポート等は必要ないです。

# コントローラー対応

Oculus Integrationのコントローラー機能については以下の記事で詳しく紹介しています。以下の内容を前提として紹介していきたいと思います。

Oculus Questコントローラーが持つ複数のキーマッピングについて - Qiita
https://qiita.com/nkjzm/items/96cd9cddc645c45dd5e5


以下が対応しているキーです。

- `Button.PrimaryIndexTrigger`
- `Button.SecondaryIndexTrigger`
- `Button.PrimaryHandTrigger`
- `Button.SecondaryHandTrigger`
- `Button.PrimaryThumbstick`
- `Button.SecondaryThumbstick`
- `Button.Two`
- `Button.Four`
- `Axis1D.PrimaryIndexTrigger`
- `Axis1D.PrimaryHandTrigger`
- `Axis1D.SecondaryIndexTrigger`
- `Axis1D.SecondaryHandTrigger`
- `Axis2D.PrimaryThumbstick`
- `Axis2D.SecondaryThumbstick`

`Button`で書いていますが、`Touch`(触れているかどうか)も対応していました。

<img width="518" alt="vive_controllers2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55365/016abefa-1132-3830-8967-75c8eee5744f.png">
([Unityマニュアル](https://developer.oculus.com/documentation/unity/latest/concepts/unity-cross-platform-dev/)内の画像を元に、文字を付け加えたもの)

Viveのメニューボタンは`Button.Two`,`Button.Four`に対応付されていました。

OculusでいうThumbstickはViveのタッチパッドに相当しており、座標と押し込みの取得が可能です。Oculus Integrationで定義されている`Up`,`Right`,`Down`,`Left`に関しては、OculusではThumbstickを「その方向に倒した時」に判定されますが、Viveでは「その方向の位置で押し込みをした時」に判定されていました。

コントローラーの思想に関しても、上記の記事で説明しているように、第二引数に渡すコントローラーの種別によってキーマッピングが変化する仕様になっていました。

逆に対応していないキー次のようになります。

- `Button.Start`
- `Button.Back`
- `Button.One`
- `Button.Three`

物理的に対応付けがされていないキーです。`Button.Back`はOculusでアプリ開発をする際はメニュー呼び出しボタンとしてよく利用されるキーなので、結構困りそうですね。

# 最後に

個人的なベストプラクティスとして以下のような形にしておくのが良い気がしました。

- そもそもOculusのA,B,X,Yボタンを使わない(`Button.One`などのこと)
- Viveのメニューボタンは`Button.Back`に対応させる

物理的に難しいとはいえ、ほとんどの機能がそのまま動くクロスプラットフォームはかなり強力だと感じました。予め知っておくとゲームデザインで解決できることでもあるので、うまく対処していきたいと思います。
rails g devise モデル名


※gemのdeviseをインストールする事で使用可能

●用途
・ログイン紐付いたモデルの生成
・ルーティングの追加

●新規作成されるファイル
app/models/user.rb
db/migrate/201xxxxxxxxx_devise_create_users.rb
test/fixtures/users.yml
test/models/user_test.rb

●更新されるファイル
config/routes.rb
以下のコードがroutes.rbに自動で追記される

devise_for :users
Firebase Authentication のGoogleログインで 403 Error: restricted_client になった時は。。

久しぶりにFirebase Authentication触ったらGoogle認証で403エラーになったので、その対処法をメモ。

# Error画面・文言

<img width="1000" alt="スクリーンショット 2019-06-23 7.16.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114396/2d7677ac-d908-f2c2-03a5-7a12f0db902f.png">


```
403.That’s an error.

Error: restricted_client
Application:*project-xxxxxxxxxxxxxx*
You can email the developer of this application at: [unconfiguredapp@google.com](mailto:unconfiguredapp@google.com) 
This app is not yet configured to make OAuth requests. To do that, set up the app’s OAuth consent screen in the Google Cloud Console.
 [Learn more](https://console.developers.google.com/apis/credentials/consent?project=xxxxxxxxxxxxx) 
Request Details
```

# 対処法

Error文言の通り、GCP側のOAuthの設定が完了出来ていないのでGCPのAPIsで`OAuth同意画面`の設定を行いましょう。
Error画面の`Learn more`のリンクで設定画面に行くので、そちらで必須の設定項目を入力します。
保存できたら完了です

<img width="1138" alt="スクリーンショット 2019-06-23 7.23.01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114396/632c33be-fa18-1415-6d6c-5ae52291ff13.png">

これでGoogle認証が動作するはず！
Amazon QuickSightのデータセットでカテゴリ変数を変換する(数値⇒文字列)

# はじめに
Amazon QuickSightのデータセットでカテゴリ変数を変換する方法を記載します。
カテゴリ変数の例としては、性別(1=男性、2=女性)などです。
データベースには数値で保存されているが、QuickSightで可視化するときに文字列で表示したい時に使ってください。

# カテゴリ変数を変換
今回は下記のデータを使用します。
1は男性、2は女性を表しています。
![1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270692/370b692e-3deb-1f4b-54b2-e2189236b22e.png)

データセットの編集ページを開いて、左にある計算フィールドの追加をクリックしてください。
計算フィールド名にはカテゴリ変数の変換後の新しいカラム名を記入してください。
今回、計算式には下記を記入します。

```
ifelse({gender} = 1,'男性',ifelse({gender} = 2,'女性','その他'))
```

ifelse関数は以下のような書き方になっています。

```
ifelse(条件式, true時の値, else時の値)
```
ifelse関数には else ifの機能がないため、elseの部分にカテゴリの数だけif文をネストして書いていきます。
ifelse関数に関する詳細は下記を参照してください。
https://docs.aws.amazon.com/ja_jp/quicksight/latest/user/ifelse-function.html
もっとスマートなやり方があれば教えてください!

![2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270692/adfb31d5-bbed-953e-fc5d-87381cf5db6f.png)

作成ボタンを押すと、新しいカラムが追加されます。
![3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270692/01d2d376-1e84-c46b-99c7-d2b00bcd1bec.png)

# 可視化
カテゴリ変数を文字列に変換することで、グラフが見やすくなりました！
![4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270692/7b68412a-38dc-29fb-9866-6e6fc4dade42.png)
nslcd メモ

nslcd のマニュアルしっかり読めばいい話ですが、log オプション理解に時間食ったので書いときます。
<pre>
% man nslcd.conf 
... snip ...


    log SCHEME [level]
</pre>

<h2>SCHEME って何でしょう。</h2>


例によって syslog 経由で吐き出しそうだなと思います。まぁ log.c 読み込むと、関数内では 普通に FILE* 型変数扱ってます。つまり 単なる File を 書き出し で開けたり出来るので あえていうなら SCHEMA とは絶対パスで書いたログファイルのコトです。
指定しないなら syslog 使うようなのですが、null なら、続けて level が書けるのか、怪しいですね。
マニュアル記述は 具体的にログをファイルに書けるよとか書いてないのでアタマワルイネコにはソース読む必要がありました。

例) log /var/log/nslcd.log debug

デバッグ有効だと、uid の解決処理にフックされた様子が手に取るように分かります。
JavaScriptでもnumpyみたいなことがしたい！

# JavaScriptでも行列の計算がしたい
Pythonにはnumpyなどのライブラリがあり, 行列計算を簡単に行うことができます。
では, JavaScriptではどうでしょうか？
実は, [numjs](https://github.com/nicolaspanel/numjs)というライブラリが用意されています。
この[numjs](https://github.com/nicolaspanel/numjs)ですが, numpyライクなインタフェースを持っておりとても使いやすいです。

# インストール方法
npm installで一発です。

```
npm install numjs
```

ただ、Pythonをインストールしておく必要であり, しかもPython3系ではなくPython2系でなければいけません。
pyenvを使われている方は、2系と3系の両方をglobalにすることでエラーを回避することができます。
例えば私の環境であれば以下のようにしました。

```
pyenv global 3.7.2 2.7.5
```

# 使い方
詳しい使い方は[本家](https://github.com/nicolaspanel/numjs)をご覧ください。
ここでは私がよく使うものをメモ書きしておきます。

## 行列の和

行列の和には`add`を使います。

```js:addMatrix.js
const nj = require('numjs')

let a = nj.array([[0, 1, 1],
                  [1, 0, 1],
                  [1, 1, 0]])
let b = nj.array([[1, 0, 0],
                  [0, 1, 0],
                  [0, 0, 1]])

let c = nj.add(a, b)
// let c = a.add(b)でも可能

console.log(c)
/* 出力結果
array([[ 1, 1, 1],
       [ 1, 1, 1],
       [ 1, 1, 1]])
*/
```
## 行列の積

行列の積には`dot`を使います。

```js:dotMatrix.js
const nj = require('numjs')

let a = nj.array([[1, 2, 3],
                  [4, 5, 6],
                  [7, 8, 9]])
let b = nj.array([[1, 0, 0],
                  [0, 0, 1],
                  [0, 1, 0]])

let c = nj.dot(a, b)
// let c = a.dot(b)でも可能

console.log(c)
/* 出力結果
array([[ 1, 3, 2],
       [ 4, 6, 5],
       [ 7, 9, 8]])
*/

```

## 行列の転置
行列の転置には`.T`を使います。

```js:transposeMatrix.js
const nj = require('numjs')

let a = nj.array([[1, 2, 3],
                  [4, 5, 6],
                  [7, 8, 9]])

console.log(a.T)
/* 出力結果
array([[ 1, 4, 7],
       [ 2, 5, 8],
       [ 3, 6, 9]])
*/
```

## ベクトルの結合
ベクトルを結合して行列を生成する場合には`stack`が便利です。

```js:jointVector1.js
const nj = require('numjs')

let a = nj.array([1, 2, 3])
let b = nj.array([4, 5, 6])
let c = nj.array([7, 8, 9])

let d = nj.stack([a, b, c], axis = 0)

console.log(d)
/* 出力結果
array([[ 1, 2, 3],
       [ 4, 5, 6],
       [ 7, 8, 9]])
*/
```

なお, axisは結合方向を表す省略可能な引数であり, デフォルトでは0が指定されています。
axisに1を指定すると転置された行列を得ることができます。

```js:jointVector2.js
const nj = require('numjs')

let a = nj.array([1, 2, 3])
let b = nj.array([4, 5, 6])
let c = nj.array([7, 8, 9])

let d = nj.stack([a, b, c], axis = 1)

console.log(d)
/* 出力結果
array([[ 1, 4, 7],
       [ 2, 5, 8],
       [ 3, 6, 9]])
*/
```

# まとめ
JavaScriptでnumpyライクに行列計算ができるライブラリ[numjs](https://github.com/nicolaspanel/numjs)を紹介しました。
この他にも行列のreshapeやFFT (高速フーリエ変換) など便利な機能がたくさんありますので, 是非試してみてくださいね。
PythonのWordCloudで遊んでみた【題材 : 吾輩は猫である】

# きっかけ
　イベントに参加した際にの隣の席の方が使っていたのをみて将来的に役に立つ技術が学べそうだと思い、やり方を調べつつ[WordCloud](https://sugiyamatatsuya.com/python%E3%81%A7wordcloud%E3%82%92%E4%BD%9C%E3%81%A3%E3%81%A6%E3%81%BF%E3%82%8B/)を使ってみた。ドキュメントは [→こちら](https://amueller.github.io/word_cloud/)

# WordCloudとは
　文章中で出現頻度が高い単語を選んで、その頻度に応じた大きさで図示する手法のことである。[参照](https://www.pc-koubou.jp/magazine/2646)

# やったこと
　今回は吾輩は猫であるの小説を元にWordCloudを使い、簡単な画像の作成を行った。（以下参照）

　

※画像
![我が輩は猫である.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323243/7fe186f4-9386-4ab7-62e2-545352c16057.png)


小説については青空文庫のもの（前処理実施）を使用した。以下、コードと備忘録である。

　

* ライブラリのインストールとマスク画像（猫の画像）の準備

```python

from wordcloud import WordCloud
import MeCab
import re
from PIL import Image
import numpy as np

mask = np.array(Image.open('イメージ画像のパスを入力'))
mask = np.where(mask == 0, 255, 0)
```
 
　

* 形態素解析で単語の抜き出しを行い、小説のデータを整形

```python

with open("./前処理済/wagahaiwa_nekodearu.txt", mode='r', encoding='utf-8') as f:
    text_list = [i.strip() for i in f]
text = "".join(text_list)

stop_words = ['する', 'せる', 'られる', 'あの', 'する', 'ある', 'とこ', 'なる', 'ない', 'ああ', 'れる', 'さん', 'やる', 'この', 'どう', 'そう']
font_path = "/Library/Fonts/BIZ-UDGothicR.ttc"

mecab = MeCab.Tagger("-Ochasen")
mecab_str =  mecab.parse(text)
mecab_list = mecab_str.replace('\t', 't').split('\n')
lang_meta_list = [re.split('[t-]' ,lang_meta_str) for lang_meta_str in mecab_list]

for lang_meta in lang_meta_list : 
    if "助詞" in lang_meta :
        continue
    if "助動詞" in lang_meta :
        continue
    if "非自立" in lang_meta :
        continue  
    if "サ変・スル" in lang_meta :
        continue
    if "サ変接続" in lang_meta :
        continue
    #if "一般" in lang_meta :
        #continue
    if "数" in lang_meta :
        continue
    if "記号" in lang_meta :
        continue    
    else :
        try:
            lang = lang_meta[2]
            print(lang_meta)
            text_list.append("{}\t".format(lang))
        except:
            pass
        
text = ("").join(text_list)
```
　

* WordCloudの実装

```python

wordcloud = WordCloud(font_path=font_path, font_step=1, mask=mask, background_color="white", contour_width=1, repeat=1, contour_color='purple', colormap='Praples', stopwords=set(stop_words)).generate(text)
wordcloud.to_file("./吾輩は猫である.png")    
```
　

吾輩は猫である.png を開くと先ほどの
　

※画像
![吾輩は猫である.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323243/dc34803a-5b9d-d68e-3e75-91e430fb7454.png)

が出力される


　

完了

# まとめ
* 少ないコードで作成可能。
* 見栄えが面白いのでプレゼンに使える。（※個人的意見）
* wordcloudのパラメータがもう少し欲しい。（別のwordcloudの埋め込み等...）
* Mecabのライブラリを楽しく学べるきっかけになる。
* ドキュメントが多く存在するので扱いやすい。

　



以上
wiresharkのプラグイン開発まとめ

# はじめに
WiresharkはLua言語で独自プロトコルを解析するプラグインを作成できるため、とても便利です。が、馴染みのないLua言語でのプラグイン開発は苦労も多いため、いろいろとQiitaにまとめることにしました。

# プラグインのインストール
.luaファイルをロードすることで、プラグインが有効になります。
読み込ませる方法は複数あり、いずれも一長一短があるようです。

|読み込ませ方  |メリット／デメリット  |
|---|---|
|init.luaからdofile関数を実行する  |【メリット】dofile関数が使用できる。<br>【デメリット】再インストールで設定が消える。 |
|pluginsフォルダに配置する  |【メリット】公式のプラグイン利用方法である。<br>【デメリット】dofile関数が使えない。  |

###### init.luaからdofile関数を実行する
インストール先フォルダにあるinit.luaファイルは、最初にロードされる.luaファイルのようです。init.luaファイルの末尾にdofile関数を用いたコードを記載することで.luaファイルをロードすることができます。但し、アップデート等で再インストールされると、同時にinit.luaファイルが初期化されてしまうようです。dofile関数を用いたコードの記載例は以下の通りです。

```lua
-- init.luaの末尾
DATA_DIR = Dir.global_config_path()..package.config:sub(1,1) -- init.luaがあるフォルダ
dofile(DATA_DIR.."sample_plugin.lua")
```

###### pluginsフォルダに配置する
指定の場所にpluginsフォルダを作成し、その中に配置した.luaファイル（サブフォルダ以下もロードされる）はプラグインとして読み込まれます。但し、dofile関数が無効化されているため、共通のロジックを１ファイルにまとめておいて、各プロトコルでコードを再利用するといったテクニックは使えません。pluginsフォルダの場所は以下の通りです。（[Wireshark Developer’s Guide Appendix B.4.](https://www.wireshark.org/docs/wsug_html_chunked/ChPluginFolders.html)）

|OS  |Path  |
|---|---|
|Windows  |%APPDATA%/Wireshark/plugins  |
|Linux |~/.local/lib/wireshark/plugins |

# デバッグの方法
###### プラグインのリロード
.luaファイルは起動時に読み込まれますが、再起動をしなくても「Ctrl+Shift+L」でプラグインがリロードされます。
###### コンソールの利用
起動後に「ツール」→「Lua」から「console」と「evaluate」を起動することで、ちょっとしたコードを試しに実行することができます。[Wireshark’s Lua API Reference Manual](https://www.wireshark.org/docs/wsdg_html_chunked/wsluarm_modules.html)にある関数を試してみたい時に便利です。

evaluateウィンドウに以下のコードを記載し、Evaluateボタンを押すと、

```lua
-- wiresharkに登録されているDissectorの一覧を表示するプログラム
-- ref) https://www.wireshark.org/docs/wsdg_html_chunked/lua_module_Proto.html
for key, val in pairs(Dissector.list()) do
	print(key,val)
end
```

以下の結果がConsoleウィンドウに表示されます。

```
2019/06/22 17:40:46 1	6lowpan
2019/06/22 17:40:46 2	CI+ SAC message
2019/06/22 17:40:46 3	DOF Object Identifier
2019/06/22 17:40:46 4	DOF Tunnel Protocol
2019/06/22 17:40:46 5	DOF Tunnel Protocol Stack
```

# サンプルスクリプトの応用
プラグインを作成する上では、サンプルスクリプトを真似るのが最も近道です。有用なサンプルスクリプトの一覧は以下の通りです。

|リンク |備考 |
|---|---|
|[10.2. Example: Creating a Menu with Lua](https://www.wireshark.org/docs/wsdg_html_chunked/wslua_menu_example.html) |GUI |
|[10.3. Example: Dissector written in Lua](https://www.wireshark.org/docs/wsdg_html_chunked/wslua_dissector_example.html) |プロトコル解析 |
|[10.4. Example: Listener written in Lua](https://www.wireshark.org/docs/wsdg_html_chunked/wslua_tap_example.html) |統計解析 |
|[Wireshark Wiki / Lua Example](https://wiki.wireshark.org/Lua/Examples)||
|[【GitHub】Wireshark/src/test/lua](https://github.com/wireshark/wireshark/tree/3a514caaf1e3b36eb284c3a566d489aba6df5392/test/lua)| テスト |



# 参考文献
* [Wireshark Developer’s Guide](https://www.wireshark.org/docs/wsdg_html_chunked/)
* [Creating a Wireshark dissector in Lua - part 2 (debugging and a more advanced dissector)](https://mika-s.github.io/wireshark/lua/dissector/2017/11/06/creating-a-wireshark-dissector-in-lua-2.html)
* [【Qiita】Wireshark で独自プロトコルを解析 (dissector with Lua)](https://qiita.com/castaneai/items/734fbe2fbdd66f226d50)
* [【SlideShare】Wiresharkの解析プラグインを作る ssmjp 201409](https://www.slideshare.net/mnrkbys/wireshark-ssmjp-201409)
エンベデッドシステムスペシャリスト合格までの道のり

今春に受験した[エンベデッドシステムスペシャリスト試験](https://www.jitec.ipa.go.jp/1_11seido/es.html)に無事合格していたので、昨年受験した応用情報技術者試験も含めて受験の記録を記事にしたいと思います。

# 受験の目的
* 自分は自社製品の制御用ソフトを作っていましたが、結構いい加減な開発プロセスだったため、一般的な開発手法を知りたかった。
* 残念ながら試験に合格しても報奨や給与アップなどは勤め先にはありませんでした。ものづくりをするメーカーなので仕方ないですね。
* 正直な所、転職時に役に立つかも…という淡い期待もありました。

### なぜ応用情報から受験したか
* エンベデッドスペシャリストを含む高度区分は応用情報を合格してから２年間は午前1試験を免除されます。午前1の試験範囲は広いため、受験する場合は別途対策が必要なります。
* 組み込み以外の分野(ネットワーク、データベース、セキュリティなど)に関する知識が浅かったので、免除を狙うついでに幅広く学んでおこうと思い、まずはこちらから受験することにしました(特に自分は基本情報を受験していなかったので)。試験範囲だけなら応用情報の方が広いため、レベルが高いからといって高度区分が上位互換というわけではないです。(シラバスは[こちら](https://www.jitec.ipa.go.jp/1_04hanni_sukiru/_index_hanni_skill.html))

# 応用情報技術者試験記
* 応用情報は４択問題の午前試験と、11問から５問を選択する記述式の午後試験があります。
* とにかく最小限の労力で試験に合格したい人と、しっかり知識を身に着けたいという人で勉強の仕方が変わると思います。私は後者でした。

### 自分の勉強法
* 勉強は試験の１ヶ月半前から開始しました。まずは２週間程度でテキストをさくっと読みながら[応用情報技術者試験ドットコム](https://www.ap-siken.com/)の過去問道場で知識の定着を図りました。分野を指定して問題を解くことができるので便利です。
* テキストは[ニュースペックテキスト](http://urx3.nu/QO9R)を購入しました。書店で類書を確認して、自分に合う本を選べば良いと思います。
* テキストを一巡した後に過去問道場で１年分を解いてみた所、合格ラインの60%を十分上回ることができたので、午後試験の勉強に移りました。
* 午後試験には定番の[午後問題の重点対策](http://urx3.nu/7vXC)を使いました。選択する問題に絞って勉強するのが定石ですが、自分は興味ある分野を全て勉強しました。その後は試験日までにひたすら過去問道場と午後勉強を続けました。

### 結果
* 1年前のことなので細かい点数は残っていませんが、午前9割・午後8割程度で余裕をもって合格しました。
* 特に午後試験は試験終了時間の1時間前に退室できた覚えがあります。

# エンベデッドスペシャリスト試験記
午前2は4択問題、午後1,2は記述問題で共にソフトウェアかハードウェアの問題から選択する必要があります。自分は1,2共にソフトウェアを選択しました。
### 自分の勉強法
* 勉強は試験日の2ヶ月ほど前から始めました。使用したテキストは[「専門知識+午後問題」の重点対策](http://urx3.nu/kw1s)。残念ながら不人気なエンベデッドスペシャリスト試験はいい感じの学習サイトもアプリもないようです。
* 午前、午後共に過去問を解いて、知らないことがあれば検索するということを繰り返しました。この時自分は試験に合格することが目標になっていたので、午後はソフトウェアに絞って勉強していました。
* 午後問題は専門的な知識よりも読解力を問われる問題という印象で、わかりにくい問題文に慣れるためにとにかく数をこなしました。

### 結果
結構ぎりぎりでした…
![スクリーンショット 2019-06-23 1.31.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157423/c4bbfde2-1f7c-dd71-2519-e830429795e1.png)


# 受験を終えての感想
* 応用情報はそれなりに楽しみながら勉強できましたが、肝心のエンベデッドスペシャリストは完全に惰性で受験してしまいました…
* エンベデッドスペシャリストを受験する頃には自分は何を学びたいかがはっきりしてきていたので、試験勉強に身が入らなかったのだと思います。何を勉強すれば良いかわからない場合は、情報処理技術者試験は方向性を見出すための一つのきっかけになるかもしれません。
* 今は資格を取るよりもgithubやqiitaなので個人の成果を公開した方が評価される時代だと思いますので、資格試験を受けるのは8月に受けるディープラーニングE検定を最後にしようかと思います。
MacにPyTorchをインストール

# 概要

Mac OS X 10.14.4にPyTorchをインストールして動作確認する

---

# 環境

- Mac OS X 10.14.4 Mojave
- [oh-my-zsh使用](https://dev.to/berry_clione/switch-from-bash-to-zsh-and-install-oh-my-zsh-on-iterm2-18d9)
- [Homebrew 2.1.6 (git revision 0d363)](https://dev.to/berry_clione/install-homebrew-on-macos-mojave-4m3m)
- Python 3.7.2
- [anaconda3-5.3.1](https://qiita.com/berry-clione/items/24fb5d97e4c458c0fc28)
- pip 19.1.1

---

# PyTorchのインストール方法

- [PyTorch公式](https://pytorch.org/get-started/locally/)には、Anacondaがある場合にはcondaを使ってインストールできると書いてあるが、[諸事情](https://qiita.com/berry-clione/items/619d64d646d0385a7e01)によりなんとなく心配なので、pipを使ってインストールすることにする

```sh
$ pip3 install torch torchvision
Collecting torch
  Downloading https://files.pythonhosted.org/packages/95/80/0851d6088bb054be3ddf47bfde1aedb4e1cbd170cf8e1c60cad321b97162/torch-1.1.0.post2-cp37-none-macosx_10_7_x86_64.whl (88.1MB)
     |████████████████████████████████| 88.1MB 604kB/s
Collecting torchvision
  Downloading https://files.pythonhosted.org/packages/af/7c/247d46a1f76dee688636d4d5394e440bb32c4e251ea8afe4442c91296830/torchvision-0.3.0-cp37-cp37m-macosx_10_7_x86_64.whl (231kB)
     |████████████████████████████████| 235kB 894kB/s
Requirement already satisfied: numpy in /Users/hoge/.pyenv/versions/anaconda3-5.3.1/lib/python3.7/site-packages (from torch) (1.15.1)
Requirement already satisfied: pillow>=4.1.1 in /Users/hoge/.pyenv/versions/anaconda3-5.3.1/lib/python3.7/site-packages (from torchvision) (5.2.0)
Requirement already satisfied: six in /Users/hoge/.pyenv/versions/anaconda3-5.3.1/lib/python3.7/site-packages (from torchvision) (1.11.0)
Installing collected packages: torch, torchvision
Successfully installed torch-1.1.0.post2 torchvision-0.3.0
```

- [PyTorch公式](https://pytorch.org/get-started/locally/)に沿って、以下のpythonコードを作成してpytorchの動作確認

```python
from __future__ import print_function
import torch
x = torch.rand(5, 3)
print(x)
```

- 実行結果

```py
tensor([[0.7747, 0.9627, 0.1806],
        [0.9219, 0.1319, 0.9026],
        [0.6719, 0.6495, 0.5341],
        [0.6629, 0.4546, 0.7309],
        [0.3577, 0.8918, 0.8544]])
```

- GPUが使えるか確認

```py
import torch
print(torch.cuda.is_available())
```

- GPUが使えない場合

```sh
False
```
AngularDartで作ったWebをGithub Pagesで公開する

# はじめに
### ！AnuglarDartとは
マテリアルデザインの動的Webページを作成することができます。
Angularのアーキテクチャについては触れませんが、
資料は結構あると思いますので お初の方はぜひ調べてみてください。

# GitHub Pagesで公開する
GitHub PagesについてはGitHub利用者は理解していると思うので特に書くことはないですね。
もちろん、GitHub PagesはDartには対応していないので、
そのままリポジトリを作成したところで、正常に動くことはありません。

ですが、**peanut**パッケージを使用することでこれが可能になります。

手順について説明していきます。

## 0. DartSDKの更新
これは必要な方のみです。
要求されるバージョンに合うように最新版に更新しておきましょう。

## 1. peanutをインストールする
ターミナルで
**``pub global activate peanut``** を実行します。
実行すると必要なものがダウンロードされます。

```bash
Installed executable peanut.
Activated peanut 3.2.1.
```
この表示が出れば成功です。
(僕はwindowsなのでそれ以外の場合はわかりませんが)パスが表示されると思うので
環境変数に追加しておきます。
追加後、後述の作業ができない際はマシンの再起動などを試みましょう。

## 2. リポジトリのクローン
リポジトリをローカルにクローンしておきましょう。
そして、ローカルリポジトリのディレクトリまで**``cd``**コマンド等で移動しておきます。

## 3. 実行する
まずは、**``pub get``** を実行して
依存関係をダウンロードします。

次に、**``peanut``** を実行します。
これを行うとプロジェクトが構築され、
**gh-pages**ブランチに対してコミットが行われます。

### エラーで先に進めない場合
僕の実行した環境でもエラーが起きてしまいました。
次のように pubspec.yamlを編集し、改善できるか試してみてください。
※ 投稿した時点の情報なので、内容が変わる可能性があります。コメントいただけると修正いたします

```yaml:pubspec.yaml
#該当項目のバージョンを以下のように変更してください

build_runner: '>=1.3.0 <2.0.0' 
build_web_compilers: ' >=1.2.0 <3.0.0'
```

##4. commitをpushする
pushを行う際に気を付けるべきことは、
特に理由のない場合は masterブランチにpushしないことを推奨します。
理由は、本来書いたソースと見た目が違うものがコミットされているからです。

現存のソースを維持しつつページを公開したい場合は
``gh-pages``ブランチにpushを行います。
(gh-pagesブランチにコミットが行われているので手順を間違えなければ大丈夫だと思いますが)

コマンドはこちら

```bash
git push origin --set-upstream gh-pages
```
GitHubのリポジトリへ行き、ブランチができていることを確認してください。

## 5. GitHub Pagesで公開設定を行う
リポジトリのページへ行き、上部の項目から、
歯車マークの付いた Settingsと書かれた項目をクリックします。

下へスクロールすると、GitHub Pages の項目があります。
以下の画像のように選択してください。
![コメント 2019-06-23 013152.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/334791/4549961d-039c-f35e-97ca-7b3470649258.png)

これで設定は完了です。

## 6. 動作確認
あとは、表示される ``https://○○.github.io/リポジトリ名``へアクセスし、
ページが表示されることを確認しましょう。

README.mdの内容が表示される方は、
ページのファイルを指定してあげるとOKです。
(例) ``https://○○.github.io/リポジトリ名/index.html``

正常に動くことが確認出来たら、これにて完了となります。
お疲れさまでした。

# サンプル
デザインとか手抜きまくってますが、こんな感じで公開できます。

↓ MCBEのサーバーのステータスを検索して表示するだけ
**https://mydeacy.github.io/Test-AngularDart/index.html**

## おわりに
Flutterが流行りだしてDartがアツくなっている(?)今、
なんとなくAngularDartに触れたけど、こりゃいいなって感じ。

リポジトリの内容として公開するものについては特に料金も発生しないこの方法が手軽でいいと思います。
もちろん、本番環境ではお勧めできるかというとできません。

天下のIntellij IDEAのDartプラグインにおいてもAngularDartのサポートがされているので
ぜひ試してみてください。

----
**参考・一部引用の資料**
https://angulardart-org-dev.firebaseapp.com/angular/guide/deployment

**パッケージ**
https://dart.dev/tools/pub/cmd/pub-get
numpy配列とctypes配列の相互変換

multiprocessingで生成したプロセス同士でndarray配列を共有する必要があったのでメモ

ctypesの変数については以下の記事を参照
https://qiita.com/maiueo/items/b2093ba78cde988bb111

# ライブラリの読み込み
```python
import ctypes
import numpy as np
```

# ndarray -> ctypes
```python
n = np.zeros((3, 4)).astype(np.uint8)  # ndarray型の3x4の配列を生成
n_h, n_w = n.shape  # nのサイズを取得
c = n.ctypes.data_as(ctypes.POINTER((ctypes.c_uint8 * n_w) * n_h)).contents  # ctypesの3x4の配列へと変換
```
**np.uint8, ctypes.c_uint8の部分は配列に用いる型の指定**
`n`と`c`はともに同じアドレスを参照しているので、片方を書き換えるともう片方にも書き換えが反映されます。
`n.ctypes.data_as`は`n`の配列の先頭ポインタを引数で指定したctypesのポインタにキャストしたものを返します。

# ctypes -> ndarray
```python
c = ((ctypes.c_uint8 * 4) * 3)()  # ctypesの3x4の配列を生成
n = np.ctypeslib.as_array(c)  # ndarray型の3x4の配列へと変換
```
**ctypes.c_uint8の部分は配列に用いる型の指定**
こちらも、`c`と`n`はともに同じアドレスを参照しているので、片方を書き換えるともう片方にも書き換えが反映されます。

# サンプルプログラム
cv2で読み込んだ画像(ndarray型)をctypes型に変換し、それをまたndarray型に戻すプログラムです。
`画像ファイルのパス`の箇所を適宜変更してください。

```python
import ctypes
import numpy as np
import cv2

if __name__ == '__main__':
	# 適当な画像からndarrayの生成
	input_img = cv2.imread("画像ファイルのパス")

	# uint8に変換
	input_img = input_img.astype(np.uint8)

	# input_imgのサイズ、チャンネル数を取得
	img_h, img_w, img_ch = input_img.shape

	# input_imgをctypesの配列に変換
	input_img_c = input_img.ctypes.data_as(ctypes.POINTER(((ctypes.c_uint8 * img_ch) * img_w) * img_h)).contents

	# ctypesの配列からndarrayを生成
	output_img = np.ctypeslib.as_array(input_img_c)

	# プレビュー
	cv2.imshow("input", input_img)
	cv2.imshow("output", output_img)
	cv2.waitKey(0)
```

# 参考
https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.ctypes.html
https://docs.scipy.org/doc/numpy-1.15.1/reference/routines.ctypeslib.html
https://stackoverflow.com/questions/3195660/how-to-use-numpy-array-with-ctypes
https://stackoverflow.com/questions/4355524/getting-data-from-ctypes-array-into-numpy
sbtで関節依存しているライブラリのバージョンを強制固定する

# 背景

- 依存に加えたライブラリが依存しているライブラリがバージョンconfilictを起こしている場合がある

- 競合を解決するバージョンに固定したいが、libraryDependenciesでは関節依存のバージョン固定ができない

- 他の方法が必要

# force()を使う

```scala
libraryDependencies += "fi.jumi" % "jumi-launcher" % "0.4.350" force()  
```
  

# dependencyOverridesを使う

```scala
dependencyOverrides += "fi.jumi" % "jumi-launcher" % "0.4.350"  
```

# 2つの違い

### プロジェクトをモジュールに直接依存させるかどうか

- forceは直接依存を加える

- dependencyOverridesは直接依存を加えない

どうも直接依存させるかどうかはどうでもいいような気がする。
なんか違いがあるのかしら。

## 参考

https://www.scala-sbt.org/1.x/docs/Library-Management.html#Overriding+a+version

https://stackoverflow.com/a/18109214