OmniAICreator/Qiita-1.07M huggingface dataset:
DotNetBarcodeライブラリを用いてQRコードを書き出すCsharpの単体アプリを作る


DotNetBarcodeライブラリ(DotNetBarcode.dll)
を用いて、QRコードを書き出すCsharpの単体アプリを作る

※DotNetBarcodeは、以下参照
http://www.geocities.jp/japan_inf/DotNetBarcode/


```csharp:sample_qr_out.cs
//c:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe /reference:DotNetBarcode.dll /target:winexe sample_qr_out.cs

using System;

public class sample_qr_out
{
 public static void Main(string[] args)
 {
    string str1;
    str1 = @"" + args[0];
    DotNetBarcode bc1=new DotNetBarcode();
    bc1.Type = DotNetBarcode.Types.QRCode;
    bc1.PrintCheckDigitChar = true;
    bc1.SaveFileType = DotNetBarcode.SaveFileTypes.Png;
    bc1.QRSave(str1,"./sample_out.png",4);
 }

}
```

コンパイル（csc.exeのパスは、適宜修正。DLLは、ソースと同階層に置いてある前提。）

```
c:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe /reference:DotNetBarcode.dll /target:winexe sample_qr_out.cs
```

実行

```
C:\QR>sample_qr_out.exe "あいうえお"
```

出来上がり
sample_out.png
![sample_out.jpg](https://qiita-image-store.s3.amazonaws.com/0/107418/b34eb1da-2853-3c7d-1604-97da84bf37c7.jpeg)
Unity初心者やってみた一覧

* Unity初心者やってみた
  * その１：https://qiita.com/akagane99/items/92a1ca9bfb841d9b63a8
  * その２：https://qiita.com/akagane99/items/cd1603ef4c3bddac86ed
  * その３：https://qiita.com/akagane99/items/dc0291df28f84e192ffd
  * その４：https://qiita.com/akagane99/items/0d01e4b21919278f5469
  * その５：https://qiita.com/akagane99/items/a7c5912a7ec98da9c7b9
Node.jsでnpmを使わずにShift_JISやeuc-jpを処理する

[Node core APIのi18n](https://nodejs.org/dist/latest-v10.x/docs/api/intl.html)を活用しよう

# 用途

オフラインの時や共用サーバーで勝手に`npm install iconv-lite`などができない時、エクセルをワンライナーでサクッと処理したい時など

# 必要条件

- v8.3.0以上
  - [util.TextDecoder](https://nodejs.org/dist/latest-v10.x/docs/api/util.html#util_class_util_textdecoder)を使うため
- icudtXX[bl].datファイルが手元のマシンにある
  - XXはICUのバージョン、bかlかはendian
  - OSXなら`/usr/share/icu/`にプリインストールされてる（特定バージョンのみ）

## 確認方法

```sh
$node # REPLに入る
> process.version
'v8.3.0' # Node.jsのバージョンが満たしているか確認
> process.versions.icu
'59.1' # 必要なICUのバージョンを確認
```

上記の場合、icudt59b.datまたはicudt59l.datが必要

自分のMBPの場合、`/usr/share/icu/icudt62l.dat`があり、
手元のNode.jsのversionはv10.15.3なので利用可能（下表）

## 対応表(2019-03, v8.x/v10.x/v11.xのみ)[^1]

Node.js ver|ICU ver
---|---
v11.1.0 ~|63
v11.0.0, v10.7.0 ~|62
v10.0.0 ~|61
v8.10.0 ~|60
v8.3.0 ~|59

## ICU dataが手元にない場合

いずれもオフラインは厳しい

- `npm i full-icu` / `yarn add full-icu`
  - Node.js verに対応するICU verをビルドしてくれる
  - `node --icu-data-dir=./node_modules/full-icu`で実行可
- [nodejs/nodeをfull ICUでbuild](https://github.com/nodejs/node/blob/master/BUILDING.md#build-with-full-icu-support-all-locales-supported-by-icu)
  - ICUデータはオンラインからダウンロードしている
- [ICUのユーザーガイド](http://userguide.icu-project.org/icudata)を参考にbuildする
- etc...

# やり方

ex, euc-jp.txtというeuc-jpエンコードされたファイルを読み込みUTF8で出力

```js:no_npm.js
const {TextDecoder} = require('util');
const {readFileSync} = require('fs');
const d = new TextDecoder('euc-jp');
const s = d.decode(readFileSync(0)); // fd=0: 標準入力
console.log(s);
```

```sh
$cat ./euc-jp.txt
�ۤ�
$cat ./euc-jp.txt | node --icu-data-dir=/usr/share/icu/ no_npm.js
ほげ
```

## 解説

- encodingオプションを指定せず生のbufferで読み込む
  - ここで'euc-jp'と指定できれば楽なのだが、TextDecoderでしかi18n対応がされておらず、encodingに指定できる値はENUM値で決まってしまっている
  - ex, readFileでは第二引数のオプションで指定しなければencodeのデフォルトはnull
  - cf, Buffer.from()の第二引数のencodeのデフォルトは'utf-8'
- TextDecoderでencodingオプションを指定する
  - 'shift_jis'は'sjis'でも良い。下記公式docを参照
  - https://nodejs.org/dist/latest-v10.x/docs/api/util.html#util_encodings_requiring_full_icu_data
- `--icu-data-dir`でicudtXX[bl].datがあるディレクトリを指定して実行する
  - これが指定できないとTextDecoderはデフォルトでは`utf-8`か`utf-16le`しかサポートしていないのでできない

## できないこと

上記でUTF-8への変換はできたが、それをeuc-jpでencodeすることはできない。
同様にjsのstring(utf-16エンコードされるらしい)をeuc-jpで吐き出すことも自前で変換表を作らないと難しい。

Transcode(`require('buffer').transcode()`)でできないかと期待したけど、指定可能なencodeは決まっていた。
https://github.com/nodejs/node/blob/master/src/node_i18n.cc

# Appendix
## Node verとICU verの対応の調べ方

```
$git clone git@github.com:nodejs/node.git
$cd node
$git log -p deps/icu-small/README-SMALL-ICU.txt
# 変更差分からICU verが更新(ex, commit messageに`bump`を含む、など)されたcommit番号をコピーし、下記でその番号を含むtagを検索
$git tag -l --contain 538acead6670d711ddb71c0b852089b792c996e3
v11.0.0
v11.1.0
v11.10.0
v11.10.1
v11.11.0
v11.12.0
v11.2.0
v11.3.0
v11.4.0
v11.5.0
v11.6.0
v11.7.0
v11.8.0
v11.9.0
# ただしこれだけだとｍasterブランチ経由で変更されたものしか取得できない
# 例えばv8系の変遷を正しく知るには、v8系の最新のtagで調査する必要がある
$git checkout -b v8.15.1 refs/tags/v8.15.1
```

[^1]: 最新情報はAppendixを参考に調査ください
phpqueryでh1～h6タグのテキストを取得する

```php

<?php
    require_once("./phpQuery-onefile.php");
    $html = file_get_contents("https://ja.wikipedia.org/wiki/%E3%82%A6%E3%82%A7%E3%83%96%E3%82%B9%E3%82%AF%E3%83%AC%E3%82%A4%E3%83%94%E3%83%B3%E3%82%B0");

    #ここでhtml全文を取得している
    $phpobj = phpQuery::newDocument($html);

    #hタグを取得
    $headers = $phpobj[":header"];

    #foreachで回して、pqで囲ってtext()するとｈタグで囲まれた文字列を取得できる
    foreach ($headers as $header) {
      echo pq($header)->text()."<br>";
      echo "----------------<br>";
    }

  ?>
```
throttleやdebounceがremoveEventListenerされない件

※throttleやdebounceに限ったことではありません。

## 概要
たまたまvueを書いていて遭遇。
scrollやresizeイベントの負荷を減らす際、わりとよく使うthrottleやdebounce。

mountedでaddEventListenerして、
beforeDestroyでremoveEventListenerしているつもりが、
イベントが削除できていなかった。

## 失敗例
```javascript

import { throttle, debounce } from 'lodash'

export default {
  name: 'xxxxx',

  mounted () {
    window.addEventListener('scroll', throttle(this.handleScroll, 100))
    window.addEventListener('resize', debounce(this.handleResize, 300))
  },

  beforeDestroy () {
    window.removeEventListener('scroll', throttle(this.handleScroll, 100))
    window.removeEventListener('resize', debounce(this.handleResize, 300))
  },

  methods: {
    handleScroll: function () {
      // scrollの処理
    }
    this.handleResize: function () {
      // resizeの処理
    }
  }
}

```

## 成功例
window.removeEventListener()する際、
直接かかずに、ワンクッション置くような感じですね。

```javascript
  mounted () {
    window.addEventListener('scroll', this.handleScroll)
    window.addEventListener('resize', this.handleResize)
  },

  beforeDestroy () {
    window.removeEventListener('scroll', this.handleScroll)
    window.removeEventListener('resize', this.handleResize)
  },

  methods: {
    handleScroll: throttle(function () {
      this.scroll()
    }, 100)
    handleResize: debounce(function () {
      this.resize()
    }, 300)

    scroll: function () {
      // scrollの処理
    }
    resize: function () {
      // resizeの処理
    }
  }
```

## reactの場合
methodをbind（this）したあと、
throttleなどの関数をconstructorで登録する。

```javascript
import React from 'react';
import throttle from 'lodash.throttle';

class Scroll extends React.Component {
  constructor(props) {
    super(props);

    this.scroll = this.scroll.bind(this);
    this.trottledFunction = throttle(this.scroll, 100);
  }
  componentDidMount() {
    window.addEventListener('scroll', this.trottledFunction, false);
  }
  scroll() {
    //scrollの処理
  }
```


### 参考
https://alligator.io/vuejs/lodash-throttle-debounce/
https://stackoverflow.com/questions/47002485/removing-event-listener-in-react-lodash-throttle
mac ショートカットキー メモ

macショートカットキーの備忘録
参考：https://support.apple.com/ja-jp/HT201236
※今後safariとchromeの共通のショートカットをまとめていく予定 （ここから覚えていこう）

#safari

タブとウィンドウのショートカット

|操作|ショートカット|
|---|---|
| 新しいウィンドウを開く | ⌘+n |
| 新しいウィンドウをシークレット モードで開く | ⌘+shift+n |
| 新しいタブを開いてそのタブに移動する | ⌘+t |
| 開いている次のタブに移動する | ⌘+option+右矢印 |
| 開いている前のタブに移動する | ⌘+option+左矢印 |
| 特定のタブに移動する | ⌘+1～⌘+8 |
| 最後のタブに移動する | ⌘+9 |
| 現在のタブの閲覧履歴の中で前にあるページを開く | ⌘+[ または ⌘+左矢印 |
| 現在のタブの閲覧履歴の中で次にあるページを開く | ⌘+] または ⌘+右矢印 |
| 現在のタブまたはポップアップを閉じる | ⌘+w |
| 現在のウィンドウを閉じる | ⌘+shift+w |
| 最後に閉じたウインドウ(tab)を開く | ⌘+shift+w |
| ウィンドウを最小化する | ⌘+m |
| front appを隠す | ⌘+h |
| front app を終了する | ⌘+q |

プライベートブラウズの使いみちは、秘密の検索をするようなときだけではなく、パーソナライズされてない「純粋な検索順位を知りたい」というときにも使える便利ツールです。


#切り替え
|ショートカット|機能|
|---|---|
|cmd+tab|アプリの切替|
|cmd+` (個人設定) |ウィンドウの切り替え(同一アプリ内）|
|control+tab|タブの切り替え（同一ウィンドウ内）|


#terminal
|ショートカット|機能|
|---|---|
|cmd+t|新規タブの作成|
|cmd+n|新規ウィンドウを開く|
DevOps のための Azure Application Insights クエリ（Kustoクエリ言語 - KQL) その２

[DevOps のための Azure Application Insights クエリ（Kustoクエリ言語 - KQL)](https://qiita.com/yoshiwatanabe/items/b981773b9a5775e4a0f8) の続編です。

今回も```requests```テーブルからデータを抽出していきます。今回想定しているDevOpsシーンは、ログの特定のコラムの値を、重複なく羅列する場合です。例えば「いったいどの国からサービスへアクセスがあったのか？」といった疑問に答えたいような場合です。

## リクエスト元のクライエントのジオ情報をざっくりみたい

リクエストがどの国の、どの地域の、どの町から来ているかを知りたいとします。まずは```project```で要らない情報を切り捨てましょう。

```
requests
| where timestamp > ago(24h)
| project client_CountryOrRegion, client_StateOrProvince, client_City 
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/1eca5e8b-4d5d-ebb8-05b4-6acc94729cb2.png)

## 国のリストを見たい

重複を排除して24時間でどの国からリクエストがあったかを調べます。

```
requests
| where timestamp > ago(24h)
| summarize count() by client_CountryOrRegion 
| project client_CountryOrRegion, count_ 
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/d5c90eb4-913e-f8cc-9468-236b620c1a3a.png)

11か国ということでした。

国のリストだけでいいので、```project```から```count_```を取り除きます

```
requests
| where timestamp > ago(24h)
| summarize count() by client_CountryOrRegion 
| project client_CountryOrRegion
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/3eeef771-1aa1-4407-2e68-2dd5e485f950.png)

ところで、値は空のものがあります。データとしては無意味なので、それを```where```に```and```オペレーターを使って条件をもうひとつ付け足して、とりのぞきます。

```
requests
| where timestamp > ago(24h) and not(isempty(client_CountryOrRegion)) 
| summarize count() by client_CountryOrRegion 
| project client_CountryOrRegion
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/17640fb7-72dd-430d-fd17-09a15cdff509.png)

```isempt() ```関数で空かどうかをしらべ、```not()```関数で否定して値を逆にします。

これで、求めていた結果が出ました。

## 国のリストをJSON配列に変換したい

テーブルの状態ではなく、JSON配列の方が都合が良かったとします。

```
requests
| where timestamp > ago(24h) and not(isempty(client_CountryOrRegion)) 
| summarize count() by client_CountryOrRegion 
| summarize makelist(client_CountryOrRegion)
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/f98f7311-e209-c407-ffbc-9c4227449293.png)

再度```summarize```しますが、今回は```makelist()```関数を使ってJSON配列にしています。

## count()関数を使わずに国のリストを得る

```count() ```関数を使うとパフォーマンスが遅い可能性が高いです。数を数えるということは、O(n)の時間計算量（time complexity）になります。データが多いほど遅くなってしまいます。そこでおそらくはO(1)時間計算量（コンスタントでデータの量に影響されない）になる```any()```関数を使って以下のように最適化してみます。（実測はしていませんが、論理的には早くなるはずです）

```
requests
| where timestamp > ago(24h) and not(isempty(client_CountryOrRegion)) 
| summarize any(client_CountryOrRegion) by client_CountryOrRegion 
| summarize makelist(client_CountryOrRegion)
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/5b1dd789-a18d-6893-1532-7332e8ad702f.png)

```any()``` 関数はグループ毎にレコードをひとつランダムに選んで、指定されたカラム、この場合は```client_CountryOrRegion```を返します。```any()```関数の[ドキュメンテーション](https://docs.microsoft.com/en-us/azure/kusto/query/any-aggfunction)に記述されているとおり、どのレコードを選ぶかはランダムで、そのアルゴリズムも公開されていないので、結果は安定していません。

## まとめ
ログ解析では時々、特定のカラムの別個の値をすべて知りたい状況が出来きます。例えば：

- 先週サーバーが返した全ての Http ステータスの値
- 全てのクライエントのブラウザの種類
- アクセスがあった全ての国（地域、町）の名前

それらをキーとして、別のクエリに利用する場合などがよくあります。
180度の3D画像の作り方と360度の3D画像が難しい理由

現在、誰でもVRギャラリーを簡単に作成・シェアできるサービスを開発中です。
https://note.mu/excosarada/n/n3db1afec01e1

このサービスのなかでA-Frameで作った3D空間を3D画像にエクスポートする機能があるのですが、その中で得た知見を共有したいと思います。

※ポエム分多めです。

## 180度の3D画像の作り方(人間の目まじで単純すぎぃ〜)

3Dに興味がある方ならば立体的に物を見るには視差が必要だということを知っていると思います。人間の2つの目は４〜5cmほど離れており、物体を複数の角度から見ることで距離を認識しているのです。つまり、原理的には4〜5cmほど左右にずれたカメラから見えるビューを合成すれば3D画像が作れることになります。しかし、果たして本当にそんな単純にいくのでしょうか？現実と3D空間は違いますし4〜5cmの位置の差なんてほとんど画像の内容も変わりません。人間には個体差もあります。3D画像の作成にはたぶん色々な困難が待ち受けているはず。私にもそう思っていた時期がありました。
しかし！人間の目まじで単純すぎぃ！個体差もなんのその、だいたい4〜5cmくらい離したところから画像とって合成すれば普通に3Dに見えました！何も難しいことなかったです！逆に驚きです！

## 360度3D画像は原理的に難しい(諦めた)

開発中のサービスでは180度3D画像のエクスポートに対応します。
しかし、本当は360度(全天球)の3D画像に対応するつもりでいました。
最初は４〜5cmカメラをずらして全天球画像を２枚とって合成すれば実現できるのではないかと考えましたが、これは誤りであることが分かりました。カメラを横にずらしても、それは自分が前方を見ているときの視差を発生するだけで、横方向を見たときには視差はなくなってしまいます。つまり、この方法で単純に画像を合成しても前方だけは3Dで見ることができるが横を見ると視差がなく、さらに左右の目で別々の画像を表示しているのでおかしな見え方になってしまうのです。
しかし世の中には360度の3Dの撮影に対応している機器も存在するため、何らかの処理で実現はできるのだと思いますが、文献が少なく実装は諦めました。おそらく全天球画像の横方向に位置する部分について視差が発生するように画像を合成するアルゴリズムが存在するのではないかと思うのですが。。。
見つけられても処理が複雑でJavaScriptで処理するのが現時的ではない可能性もありますね。
この辺りは引き続き調査・勉強したいと思います。(もし、これを実現する記事や論文を知っている方がいましたら教えていただけると助かります。)
packagistで使うcomposer.jsonのlicenceに独自ライセンスを設定する

転記記事です。

こんにちは、オープンソース・ワークショップの牟田口です。
IT技術ネタです。

packagistが最近になって、composer.jsonのlicenceの書き方を厳密に見るようになったようで、
下記のエラーメールが届きました。

```
--- 注釈
・packagistは、composerでパッケージバージョン管理してるメインリポジトリです。
・composerは、phpのパッケージバージョン管理ツールです。
・composer.jsonは、composerの設定ファイルです。
---
```
 

### --- エラー内容
```
「件名」
netcommons/videos failed to update, invalid composer.json data

「本文」
The netcommons/videos package of which you are a maintainer has
failed to update due to invalid data contained in your composer.json.
Please address this as soon as possible since the package stopped updating.

It is recommended that you use `composer validate` to check for errors when you
change your composer.json.

Below is the full update log which should highlight errors as
"Skipped branch ...":

[Composer\Repository\InvalidRepositoryException]: Some branches contained invalid data and were discarded, it is advised to review the log and fix any issues present in branches

Reading composer.json of netcommons/videos (3.1.7)
Importing tag 3.1.7 (3.1.7.0)

（省略）

Reading composer.json of netcommons/videos (master)
Importing branch master (dev-master)
Skipped branch master, Invalid package information:
License "NetCommons License" is not a valid SPDX license identifier, see https://spdx.org/licenses/ if you use an open license.
If the software is closed-source, you may use "proprietary" as license.
```

なにやら、composer.jsonのLicense "NetCommons License" は、SPDX license（https://spdx.org/licenses/）に該当してないよ、との事。
NetCommons Licenseは、FreeBSD Licenseを基にした独自のOSSライセンスなんだよなぁ。
という事で、SPDXのライセンスにない場合の書き方を調べました。


### --- 対応方法
SPDXのライセンスにない場合の書き方をする。
　　（composer.jsonの修正例）

```
"license": "LicenseRef-NetCommons",
 "license-ref-net-commons": "https://raw.githubusercontent.com/NetCommons3/NetCommons3/master/license.txt",
```

### --- 情報元link
SPDXのライセンスにない場合は、こう書くらしいです。
https://spdx.org/spdx-specification-21-web-version#h.1v1yuxt

issueにもこんなのあがってました。
https://github.com/composer/composer/issues/2152

修正例
https://github.com/NetCommons3/Videos/blob/master/composer.json#L25-L26

 
### --- その他の対応方法
メールの修正方法に従う。
　1) SPDX license（https://spdx.org/licenses/）に修正する。
（composer.jsonの修正例）

```
"license": "BSD-2-Clause-FreeBSD",
```
 
　2) クローズしたソースなら、ライセンスを"proprietary"にする。
（composer.jsonの修正例）

```
"license": "proprietary",
```
 
以上、参考なればうれしい限りです。
Gitのリモート追跡ブランチ・追跡ブランチ・上流ブランチ

この投稿は、リモート追跡ブランチ・追跡ブランチ・上流ブランチのまとめです:laughing:
Gitのバージョンは、`2.21.0`。
# 何が違うのか？
## ローカルブランチ
**ローカルブランチ**とは、ローカルリポジトリにあるブランチ

```bash:ローカルブランチの確認
$ git branch
* develop
  feature/xx1
  master

# ファイルで確認
$ tree .git/refs/heads/
.git/refs/heads/
├── develop
├── feature
│   └── xx1
└── master
```

## リモートブランチ、リモート追跡ブランチ
- **リモートブランチ**とは、リモートリポジトリにあるブランチ
- **リモート追跡ブランチ**とは、前回`fetch`（や`pull`）をした時点でのリモートブランチを参照するブランチ。ローカルにある。

### もっと詳しく
- リモート追跡ブランチ名は、`origin/develop`のように`{remote}/{branch} `となる
- `fetch`（や`pull`）をすると自動的に更新される
- リモート追跡ブランチを「派生元」として、ローカルブランチを作れる:smiley:
- リモート追跡ブランチは、checkoutしない（`detached HEAD`が起きるかも:laughing:）

```bash:リモートブランチの確認
$ git branch -r
  origin/HEAD -> origin/master
  origin/develop
  origin/feature/xx1
  origin/master

# ファイルで確認(リモートリポジトリ=origin)
$ tree .git/refs/remotes/
.git/refs/remotes/
└── origin
    ├── HEAD
    ├── develop
    ├── feature
    │   └── xx1
    └── master
```

## 上流ブランチ、追跡ブランチ

- 上流ブランチが設定されたローカルブランチは、**追跡ブランチ**と呼ばれる
- 追跡ブランチの「追跡先」が**上流ブランチ** 
- リモート追跡ブランチからローカルブランチを作ると、自動的に上流ブランチが設定。
    - `リモート追跡ブランチ = 上流ブランチ`、`ローカルブランチ = 追跡ブランチ`となる
    - この動作は.git/configで変えられる[^1]
- 上流ブランチは、リモート追跡ブランチやローカルブランチを指定できる。`追跡ブランチ ≠ リモート追跡ブランチ`となる。

例えば、いま`feature/xx1`をcheckoutしているとすると

```bash:上流ブランチの場合
# 上流ブランチ = ローカルブランチ
$ git branch --set-upstream-to=develop
Branch 'feature/xx1' set up to track local branch 'develop'.

# 上流ブランチ = リモート追跡ブランチ
$ git branch --set-upstream-to=origin/develop
Branch 'feature/xx1' set up to track remote branch 'develop' from 'origin'.
```

# なぜこんなことが...
追跡ブランチ、上流ブランチがあると、` git pull`, `git push` といったコマンドを引数なしで実行可！初心者に優しくて便利＆うれしい:laughing:
Gitも進化してるんだね！[^2]

***追伸***
Gitって、バージョン管理システムなのに、**バージョン**って言葉が使われない気がする。なぜ？？セマンティックバージョニングのせいなのかな。
[Git - git-rev-parse Documentation](https://git-scm.com/docs/git-rev-parse#_specifying_revisions)


[^1]: [Git - git-config Documentation](https://git-scm.com/docs/git-config/2.21.0#Documentation/git-config.txt-branchautoSetupMerge)

[^2]: バージョンによって動作が違う。`push.default`の挙動が、バージョン2.xから`matching`→`simple`など。[とうとう Git 2.0 が現実のものに。便利な機能満載 | Atlassian Blogs](https://japan.blogs.atlassian.com/2014/06/happened-git-2-0-full-goodies/)。各バージョンでの差異は、[RelNotes\Documentation - git.git - The core git plumbing](https://git.kernel.org/pub/scm/git/git.git/tree/Documentation/RelNotes)
TypeScriptでIDに型をつけて型安全にする

## IDを型安全にするとは？

各種IDを整数型や文字列型のまま扱うと、関数の引数に複数種類のIDを指定する時などに、順番を間違えて逆にしてしまってもそのままコンパイルが通ってしまうため、テスト時や実行時に不思議な動作をして、問題に気づくということがよくあります。

そのため、JavaやKotlinだと、データクラスやLombok等を使って、IDに型をつけてコンパイル時にこのようなミスに気づけるようにします。

```kotlin
data class EntityId(val id: Int)

class Entity {
  val id: EntityId;
  /* ... */
}
```

## TypeScriptでの問題

TypeScriptでclassを使って同じようなことをしようとすると、比較の時やMapのキーとして使用した時に、同じIDを表しているオブジェクトでもオブジェクトインスタンスが違うため、比較が偽になってしまい使い物になりません。仕様でequals()やhashCode()が決められている訳でもないので、クラスでラップする方法だとやりようがありません。

## ではTypeScriptでどうするか？

色々調べて試した結果、Intersection Typesを使ってnumberやstringに型チェックを追加するのが大体のケースでうまくいき、オーバーヘッドも少なそうです。

```ts:types.ts
declare class Id<T extends string> {
  private IDENTITY: T;
}

export type EntityId = Id<'Entity'> & number;
export function EntityId(id: number): EntityId { return id as EntityId; }

export type AttributeId = Id<'Attribute'> & number;
export function AttributeId(id: number): AttributeId { return id as AttributeId; }

export type CategoryId = Id<'Category'> & number;
export function CategoryId(id: number): CategoryId { return id as CategoryId; }
```

typeとfunctionを同じ名前で定義していますが、コンパイルは通りますし、exportもちゃんと動作します。

#### トランスパイル後
```js:types.js
"use strict";
exports.__esModule = true;
function EntityId(id) { return id; }
exports.EntityId = EntityId;
function AttributeId(id) { return id; }
exports.AttributeId = AttributeId;
function CategoryId(id) { return id; }
exports.CategoryId = CategoryId;
```

`Id<T>`の型情報が完全に消えていて、普通のNumber型としてJS上では扱われるようになります。

## これを使って実際コードを書いてみると

```ts:main.ts
import { EntityId, AttributeId } from './types';

const entityId1: EntityId = EntityId(1);
const entityId1_1: EntityId = EntityId(1);
const entityId2: EntityId = EntityId(2);

const attributeId1: AttributeId = AttributeId(1);

console.log(entityId1 === entityId1_1); // output: true
console.log(entityId1 === entityId2); // output: false

console.log(entityId1 === attributeId1); // Compile error!!!

let entityIdMutable: EntityId;
entityIdMutable = entityId1; // OK
entityIdMutable = entityId2; // OK
entityIdMutable = attributeId1; // Compile error!!!
entityIdMutable = 1; // Compile error!!!

function getEntity(entityId: EntityId) { /* ... */ }
getEntity(entityId1); // OK
getEntity(EntityId(1)); // OK
getEntity(attributeId1); // Compile error!!!
getEntity(1); // Compile error!!!
```

## 追記 (2019/11/05)

`Array<number>`のようにリテラル型を型引数に指定したオブジェクトには、要素の追加ができてしまいます。`Array<EntityId>`のようにちゃんと型引数にも型を指定して使ってください。

```ts
const numbers = new Array<number>();
numbers.push(EntityId(1)); // 通っちゃう
numbers.push(AttributeId(1)); // 通っちゃう

const entityIds = new Array<EntityId>();
entityIds.push(EntityId(1)); // OK
entityIds.push(AttributeId(1)); // ERROR
entityIds.push(1); // ERROR
```

## 最後に

通常のプログラムを書く時だと、これくらいで十分かなと思っています。
IDに型をつけると、IDEやVS Codeで補完や型の表示も効くので色々と捗ります。
git-lfsがaptで更新できなくなった時の対処方法

ある日突然、git-lfsがaptで更新できなくなった。

```
#sudo apt upgrade -y

（中略）

エラー:27 https://packagecloud.io/github/git-lfs/ubuntu xenial InRelease
 クリアサインされたファイルが有効ではなく、'NOSPLIT' を得ました (認証にネットワークが必要?)
取得:28 http://security.ubuntu.com/ubuntu xenial-security/main DEP-11 64x64 Icons [67.1 kB]
取得:29 http://security.ubuntu.com/ubuntu xenial-security/universe amd64 DEP-11 Metadata [116 kB]
取得:30 http://security.ubuntu.com/ubuntu xenial-security/universe DEP-11 64x64 Icons [173 kB]
取得:31 http://security.ubuntu.com/ubuntu xenial-security/multiverse amd64 DEP-11 Metadata [2,464 B]
ヒット:32 http://ppa.launchpad.net/git-core/ppa/ubuntu xenial InRelease
5,064 kB を 3秒 で取得しました (1,326 kB/s)
パッケージリストを読み込んでいます... 完了
E: https://packagecloud.io/github/git-lfs/ubuntu/dists/xenial/InRelease の取得に失敗しました  クリアサインされたファイルが有効ではなく、'NOSPLIT' を得ました (認証にネットワークが必要?)
E: いくつかのインデックスファイルのダウンロードに失敗しました。これらは無視されるか、古いものが代わりに使われます。
```

調査したところ、aptの認証キー（公開鍵）が期限切れになっていることが原因のようだ。

```
#sudo apt-key list
/etc/apt/trusted.gpg
--------------------
pub   1024D/437D05B5 2004-09-12
uid                  Ubuntu Archive Automatic Signing Key <ftpmaster@ubuntu.com>
sub   2048g/79164387 2004-09-12

pub   4096R/C0B21F32 2012-05-11
uid                  Ubuntu Archive Automatic Signing Key (2012) <ftpmaster@ubuntu.com>

pub   4096R/EFE21092 2012-05-11
uid                  Ubuntu CD Image Automatic Signing Key (2012) <cdimage@ubuntu.com>

pub   1024D/FBB75451 2004-12-30
uid                  Ubuntu CD Image Automatic Signing Key <cdimage@ubuntu.com>

pub   1024R/3DF71FB4 2016-04-26
uid                  live-build local packages key <live-build-local-key@invalid>
sub   1024g/64E8CE16 2016-04-26

pub   1024D/0C4ECFEC 2005-05-24
uid                  Ubuntu-ja Archive Automatic Signing Key <archive@ubuntulinux.jp>
sub   2048g/40A3E9B2 2005-05-24

pub   1024R/CDC1D865 2009-04-05
uid                  Launchpad PPA for Ubuntu Japanese Team

pub   4096R/D59097AB 2014-01-13 [期限切れ: 2019-01-12]
uid                  packagecloud ops (production key) <ops@packagecloud.io>

/etc/apt/trusted.gpg.d/git-core_ubuntu_ppa.gpg
----------------------------------------------
pub   1024R/E1DF1F24 2009-01-22
uid                  Launchpad PPA for Ubuntu Git Maintainers
```

git-lfsのinstall手順に従い、再度認証キーを設定することで従来通りaptで更新できるようになった。
Laravelの概要

#Lravelの特徴

1. 容易な学習[学習コストが低い]
2. Symfonyベース [コア部分に高い信用性と実績のあるSymfony Componentsを使用]
3. 多機能
4. 積極的なバージョンアップ
5. 高い拡張性



##PHPのフレームワーク
Laravekの他には
・CakePHP
・Symfony
・CodeIgniter
・Zend Framework
などがある。

##ディレクトリ構成

```
　sampleapp
  |--app/
  |--artisan
  |--bootstrap/
  |--composer.json
  |--composer.lock
  |--config/
  |--database/
  |--package.json
  |--phpunit.xml
  |--public/
  |--readme.md
  |--resorces/
  |--routes/
  |--server.php
  |--storage
  |--tests/
  |--vendor/
  |--webpack.mix.js
```

###app/
コントローラやミドルウェア、例外クラス、コンソールサービス、プロバイダなど
アプリケーションの主要な処理クラスはappディレクトリ配下に配置します。

###bootstrap/
アプリケーションで最初に実行される処理やオートローディング設定が入っています。

###config/
アプリケーションの設定値を記載したファイルが入っています。

###database/
データベース関連のファイルが入っています。
マイグレーションファイルや初期投入データなど。

###public/
webアプリケーションとして公開する場合、このフォルダをドキュメントルートに設定します。
エントリポイントとなるindex.phpが入っている他、JavascriptやCSSなどそのまま公開できるファイルを配置するディレクトリです。

###resouces/
Viewのテンプレートファイルや、LESSや SASSなどメタ言語ファイルを配置します。

###storage/
プログラム実行時にLaravelが作成するファイルの出力先です。ログファイルやファイルキャッシュの他、コンパイルされたテンプレートファイルなども保存される。

###tests/
テストコードを記載したファイルを置きます。

###vendor/
Composerによりダウンロードされる各種のパッケージのディレクトリです。
ディレクトリ配下にある[Larvael]ディレクトリがLaravel本体のコードの配置場所です。
「承認と購入のリクエスト」で購入完了後のレシートが空

# 問題

iPhoneには、ファミリー共有による[承認と購入のリクエスト][1]を利用した課金フローがあります。
これを利用した場合、SKPaymentTransactionのstateがpurchasedの購入完了時にレシート情報がappStoreReceiptURLに含まれてない問題が発生しました。
レシートはサーバーに送信して検証を行っており、検証NGで課金失敗扱いになっていました。

```swift:レシート
Bundle.main.appStoreReceiptURL
```

# 解決

[こちら][2]を参考にappStoreReceiptURLの[解析処理][3]を仕込み、購入したtransactionIdentifierが含まれているか確認を行います。
含まれていない場合（今回の問題の事象）、[レシートの更新][4]を行うことで、該当のレシート情報が含まれるようになることを確認できました。

```objective_c:レシートの更新処理
request = [[SKReceiptRefreshRequest alloc] init];
request.delegate = self;
[request start];
```

# 参考文献

[In App Purchaseのレシートをローカルで検証できるようになった話][2]

[1]:https://support.apple.com/ja-jp/HT201089
[2]:https://qiita.com/fmtonakai/items/6d13c8e535c5d8904c60
[3]:https://github.com/rmaddy/VerifyStoreReceiptiOS
[4]:https://developer.apple.com/jp/documentation/NetworkingInternet/Conceptual/StoreKitGuide/Chapters/Restoring.html
GoogleDriveからウイルススキャンを伴うファイルをwget1回で取得する

# 概要
Google Driveからwgetでファイルを取得する際、大きいサイズのファイルだとウイルススキャンが必要となりダイアログ認証のせいでうまく取得することができません。
Google Colaboratory等の場合、ローカルにおいてあるファイルをアップロードすることは可能ですが非常に時間がかかります。1つのファイルを送るためにGoogle Driveをマウントするのも手間です。

そこで今回は、ウイルススキャンを伴うサイズのファイルをGoogle Driveから1回のwgetで取得していきます。

## サイズの小さいファイルの取得
サイズの小さいファイルをwgetで取得する方法は他の方の記事で取り上げられていますが、同じ方法でサイズの大きいファイルを取得しようとすると画像のように上手く取得できません。
画像では730MBの学習済みモデルの取得を試みましたが、実際に取得できているのは3.2KBです。

一般的なサイズの取得は下記の記述で行います。

```
wget "https://drive.google.com/uc?export=download&id=<共有リンクのファイルID>" -O <任意のファイル名.拡張子>
```


![Qiita挿入画像_wget失敗_002.png](https://qiita-image-store.s3.amazonaws.com/0/132574/a7cf6d46-9562-56eb-fac7-a6e9007824f5.png)


## サイズの大きいファイルの取得
ウイルススキャンを伴う大きいサイズの取得は以下の記述で行います。
先程と同様に730MBの学習済みモデルの取得を行います。

```
wget --load-cookies /tmp/cookies.txt "https://drive.google.com/uc?export=download&confirm=$(wget --quiet --save-cookies /tmp/cookies.txt --keep-session-cookies --no-check-certificate 'https://drive.google.com/uc?export=download&id=<共有リンクのファイルID>' -O- | sed -rn 's/.*confirm=([0-9A-Za-z_]+).*/\1\n/p')&id=<共有リンクのファイルID>" -O <任意のファイル名.拡張子> && rm -rf /tmp/cookies.txt
```
![Qiita挿入画像_wget成功_003.png](https://qiita-image-store.s3.amazonaws.com/0/132574/42a2ea98-c066-2457-23ac-991255150618.png)

1回のwgetで730MB全てを取得することができました。
今回はGoogle Colaboratory上で行いましたが、一般的なターミナル上でも取得できます。
Srrong Parametersってなんぞ

Strong Parametersがよくわからないので、アウトプットがてらここにまとめてみます。

[Railsチュートリアル第7章](https://railstutorial.jp/chapters/sign_up?version=5.1#sec-strong_parameters)でStrong Parametersは登場します。

## Strong Parametersはなぜ生まれたのか？

Strong Parametersはセキュリティを高めるために生まれたテクニックです。
具体的には、マスアサインメント脆弱性への対処のためのものです。

### マスアサインメント脆弱性とは
`@user = User.new(params[:user])`
のように、ユーザが送信したデータを丸ごとUser.newに渡しているとする。
この場合、もしUserモデルに管理者権限の属性があり、ユーザにそのデータを書き換えるコードがformを通して送られてしまうと、ユーザに管理者権限が奪われてしまう。

これをマスアサインメント脆弱性という。

## Strong Parameterはどのようにマスアサインメント脆弱性に対処するのか

Strong Parameterは必須のパラメータと許可されたパラメータを指定することでマスアサインメント脆弱性に対処します。

`params.require(:user).permit(:name, :email, :password, :password_confirmation)`
のように、許可されるパラメータを指定して対策しています。

こうすることで、もし管理者権限の属性があったとしても、ユーザからは書き換えられなく（admin属性に関するコードが送れなく）なります。
現在アクティブなワークブックの選択セルをA1に揃えるVBAマクロ

Excelを保存して閉じる際、A1セルが選択された状態にせず怒られたことがあります。
そんなわけで、すべてのシートの選択セルをA1にするVBAマクロです。
過去にも同様のテーマの記事がありますが、非表示・保護シートのスキップや固定ウィンドウのスクロールも戻すなど、豪華版となっております。

# 環境

- Windows7 64bit
- Excel 2013
- VBA 7.1

所有するWin10にはMSOfficeが入っていないため、確認したのはWin7です。
でもWin10でもおそらくそのまま動くと思います。

# ExcelVBAソース
```vb
Sub selectA1()
  Dim shItem As Worksheet
  Dim firstIndex As Long
  Dim msg As String
   
  Application.ScreenUpdating = False
  
  For Each shItem In ActiveWorkbook.Worksheets
    ' 非表示・セル選択禁止シートはスキップ
    If (shItem.visible = xlSheetVisible) And (shItem.EnableSelection = xlNoRestrictions) Then
      Application.Goto Reference:=shItem.Cells(1, 1), Scroll:=True
      If firstIndex = 0 Then
        firstIndex = shItem.Index
      End If
    Else
      If shItem.visible <> xlSheetVeryHidden Then
        msg = msg & vbCrLf & shItem.Name
      End If
    End If
  Next shItem
  
  With ActiveWorkbook
    .Worksheets(firstIndex).Select
    Application.ScreenUpdating = True
    
    If msg <> "" Then
      msg = vbCrLf & vbCrLf & "以下のシートには適用されませんでした。" & msg
    End If
    
    If vbYes = MsgBox("完了しました。" & vbCrLf & "上書き保存して終了しますか？" & msg, vbYesNo) Then
      .Save
      .Close
    End If
  End With
End Sub
```

# 利用方法
**個人用マクロブックの表示とマクロの登録方法**
[単一のブックにすべてのマクロを作成して保存する | MSOffice Support](https://support.office.com/ja-jp/article/%E5%8D%98%E4%B8%80%E3%81%AE%E3%83%96%E3%83%83%E3%82%AF%E3%81%AB%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E3%83%9E%E3%82%AF%E3%83%AD%E3%82%92%E4%BD%9C%E6%88%90%E3%81%97%E3%81%A6%E4%BF%9D%E5%AD%98%E3%81%99%E3%82%8B-aa439b90-f836-4381-97f0-6e4c3f5ee566)
**マクロへのショートカット登録などの方法**
[マクロを実行する | MSOffice Support](https://support.office.com/ja-jp/article/%E3%83%9E%E3%82%AF%E3%83%AD%E3%82%92%E5%AE%9F%E8%A1%8C%E3%81%99%E3%82%8B-5e855fd2-02d1-45f5-90a3-50e645fe3155)
XAMPPでPHPを使ってウェブスクレイピングするときの設定


[【php】webサイトから、欲しい情報を3行で取得する方法](https://qiita.com/dia/items/3cf963fa89b08b87e8ef)を真似してウェブスクレイピングをしようとしたが、failed to open stream: Invalid argument in~~とエラーが出た。
調べるとOpensslを有効化しないといけないというらしい。

XAMPPで仮想サーバーを立てていたので、XAMPPのファイルを編集しないといけない。
Cドライブ直下にxamppフォルダがあるはずなので、そのフォルダ内のphpフォルダにあるphp.iniを編集する。

```php.ini
extension=php_openssl.dll

```

この一行を追加して、xamppを再起動後にウェブスクレイピングするとできるようになった。
Rubyでnilを含む配列をソートしたいとき

# nilを含むデータでもソートがしたい！
よくあることですね。
こんなときはみなさんどうしてるんですかね？
例えば、果物を値段の高い順にソートしたいとき

```fruits.rb
fruits =  [
  {
    name: 'apple', price: 200
  },
  {
    name: 'orange', price: 400
  },
  {
    name: 'plum', price: 300
  }
]

sorted_fruits_from_price_higher = fruits.sort do |a, b|
  b[:price] <=> a[:price]
end

p sorted_fruits_from_price_higher
```
こうしますね。
出力は
`[{:name=>"orange", :price=>400}, {:name=>"plum", :price=>300}, {:name=>"apple", :price=>200}]`
ちゃんとpriceが降順に表示されるはずです。

## 蛇足
### sortモジュールについて
sortはrubyの標準のモジュールです。
ブロック要素として配列の各要素を2つ（a, b）送り出して、
戻り値が1のときはbをaの前に持ってきて、
戻り値が-1のときはaをbの前に持ってきます。
戻り値が0のときは何もしません。
「戻り値が１のときに順番を変更すると覚えておけば大丈夫です」

### <=> について
<=> はruby の比較演算子です。
a <=> b としたときに、左側の値のほうが大きかったら 1 を返し、
右側の値のほうが大きかったら -1 を、
左右の値が同じだったら 0 を、
そして、左右の型が違う場合は nil を返します。※重要!!!

# nilを含むデータをソートしたいとき
### ここからが本題です!
先程のデータの中に値段がわからない果物が入ってきたらどうしましょう！

```fruits.rb
fruits =  [
  {
    name: 'apple', price: 200
  },
  {
    name: 'orange', price: 400
  },
  {
    name: 'anonymous', price: nil
  },
  {
    name: 'plum', price: 300
  },
]
```

ソートをしてみます。。。

```fruits.rb
sorted_fruits_from_price_higher = fruits.sort do |a, b|
  b[:price] <=> a[:price]
end
```

エラーが。。。

```
fruits.rb:16:in `sort': comparison of Hash with Hash failed (ArgumentError)
```

比較演算子 <=> の戻り値を確かめてみましょう

```fruits.rb
sorted_fruits_from_price_higher = fruits.sort do |a, b|
  p b[:price] <=> a[:price]
  b[:price] <=> a[:price]
end
```

```
1
nil
```
### nil！？
先程の蛇足説明を思い出してください(読んでなくても大丈夫です)

- sortモジュールは -1 と 1 と 0 のどれかの戻り値に基づいて処理する
- <=> は型の違う値を比較するとnilを返却する


### 上の２つの規則から判断すると、nil と 数値(300)を比較した結果、nilが戻り値になり、その結果、エラーが起こっていた！？
sortの戻り値をnilにしたらだめなんですねー

# 結論: nilを含んだデータを比較するには？
ここまでくれば簡単ですね
if文を使いましょう

```fruits.rb
sorted_fruits_from_price_higher = fruits.sort do |a, b|
  if !a[:price]
    1
  elsif !b[:price]
    -1
  else
    b[:price] <=> a[:price]
  end
end
```
↑こうすればnilの入ったデータを後ろに追いやってくれます
`[{:name=>"orange", :price=>400}, {:name=>"plum", :price=>300}, {:name=>"apple", :price=>200}, {:name=>"anonymous", :price=>nil}]`

```fruits.rb
fruits.select! {|a| a[:price]}
```
↑のように比較前に取り除いても大丈夫です。
`[{:name=>"orange", :price=>400}, {:name=>"plum", :price=>300}, {:name=>"apple", :price=>200}]`

# 以上です
いかがでしたでしょうか？
【Rails】ヘッダーへの検索機能の付け方

**「検索機能をつけたい！」**
**「検索ページを作るのではなく、検索窓として常にアプリ上部に出てくるようにしたい！」**
といった時の対応方法です。

↓参考イメージ（Qiitaでいうこんな部分）
![スクリーンショット 2019-03-21 11.51.42.png](https://qiita-image-store.s3.amazonaws.com/0/356866/e0a969da-9edb-7d59-9798-e1f201ccef64.png)

#はじめに
今回の前提は、

- 検索対象モデルがある。（今回はproductモデルと仮定する）
- 検索対象モデルのindexページがある。（例：app/view/products/index.html.erb）
- indexページを再利用して検索結果を表示させる。

としたいと思います。

#元コードイメージ
## コントローラ

```ruby:app/controllers/products_controller.rb
def index
  @products = Product.all
end
```

## view

```erb:app/view/products/index.html.erb
<% render partial: 'products/product', collection: @products %>
```
collectionを使って各商品を表示させてます。

```erb:app/view/products/_product.html.erb
<%= product.name %>
<%= product.price %>
```
パーシャルを用いて各productの情報を表示させていきます。
※パーシャル名=変数名となるので注意。（例：_user.html.erbの場合は、user.nameとなる。） 


だいたいこんな感じの状態のものを想定します。


#①Gemインストール
今回はransackというgemを使用します。

```ruby:Gemfile
gem 'ransack'
```
記述したら`bundle install`する。

#②検索機能の追加（コントローラの修正）
実は今回products_controller.rbは触りません。
products_controller.rbで検索機能を追加すると、検索”窓”として、どのページからでも使用することはできなくなるからです。
そのためapplication_controller.rbに機能追加していきます。

```ruby:app/controllers/application_controller.rb
before_action :set_search

def set_search
  @search = Product.ransack(params[:q])
  @search_products = @search.result
end
```
#③検索窓の作成（viewの修正）
検索窓を作っていきます。
今回は特定のviewではなく、検索窓のような形で作成するので、application.html.erbなどに記入しましょう。

```erb:app/view/layouts/application.html.erb
<%= search_form_for @search, products_path do |f| %>
  <%= f.text_field :name_cont, placeholder: '名前を入力...' %>
  <%= f.submit ("検索する") %>
<% end %>
```
ポイントは下記の部分です。

- `search_form_for`は`form_for`のRansack版。
- `products_path`の記載によって、リダイレクト先はproductのindexページを指定している。
- 2行目に書いている`:name_cont`の記載によって、nameカラムに対して部分一致検索ができるようになる。

#④indexページでの条件分け（パーシャルへの変数の出し分け）
indexページを再利用するために、条件指定をします。

- 「検索窓→indexページ」の時には検索結果を表示させたい。（`@search_products`を表示させる。）
- 上記以外の場合には、全ての商品を表示させたい。(`@products`を表示させる。)

```erb:app/view/products/index.html.erb
<% if @search_products %>
  <% render partial: 'products/product', collection: @search_products %>
<% else %>
  <% render partial: 'products/product', collection: @products %>
<% end %>
```
これで、
`@search_products`が存在する場合には、`@search_products`がパーシャルに渡され、
`@search_products`が存在しない場合には、`@products`がパーシャルに渡されるので、indexページの再利用ができます。

# おわりに
まだまだ駆け出しエンジニアなので、変な部分ありましたらドシドシコメント欲しいです！
[イベントメモ］python入門＠コワーキングスペース秋葉原|190321

イベント内容の備忘録です。

# イベント名
[[秋葉原] 超初心者向けPython入門会 (プログラミング初心者大歓迎！)](https://weeyble-beginner.connpass.com/event/124323/?utm_campaign=event_reminder&utm_source=notifications&utm_medium=email&utm_content=detail_btn)

### 自分の参加目的
- Python入門で必要だろう知識について、先人に教えをこい、理解を深めたい！

**→期待値に見合った勉強会だった。何より、先生や他の参加者の方の雰囲気が楽して、あっという間だった！**

### 主催者様側のゴール(私解釈）
- pythonのライブラリ（pandas)でできることを見て、可能性を感じてもらう！

## 勉強会スタート！
#### pythonとは
- 汎用プラログラミング言語。組込み系と相性が良い（raspberry pi)。作業の自動化。スクレイピング。Excelに向いていない大量データを扱うのに向いている
- 初心者におすすめ書籍　[「退屈なことはPythonにやらせよう ―ノンプログラマーにもできる自動化処理プログラミング」](https://www.amazon.co.jp/%E9%80%80%E5%B1%88%E3%81%AA%E3%81%93%E3%81%A8%E3%81%AFPython%E3%81%AB%E3%82%84%E3%82%89%E3%81%9B%E3%82%88%E3%81%86-%E2%80%95%E3%83%8E%E3%83%B3%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9E%E3%83%BC%E3%81%AB%E3%82%82%E3%81%A7%E3%81%8D%E3%82%8B%E8%87%AA%E5%8B%95%E5%8C%96%E5%87%A6%E7%90%86%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-Al-Sweigart/dp/487311778X/ref=cm_cr_arp_d_product_top?ie=UTF8)
- 今回は[googole colab](https://colab.research.google.com/notebooks/welcome.ipynb#recent=true)環境でpythonを触るよ！
- google colabはgoogle社が提供しているオンライン環境。１クリックでGPUに切り替え可能なので、大量データの扱いはめっちゃ早いとのこと！
- エディタは、 **jupyter notebook** もおすすめ。実行結果やグラフが下列にすぐに出力されるのでわかりやすい！
- `print('便利でしょ'+'ね？'*10)` 　←これ好き^^
- 文字列はシングルクォーテーションまたは、ダブルクォーテーションで囲むこと。IF文、While文、関数は、タブ2回でインデント！

#### pythonのpandasライブラリとは
- pandasとは、データ解析を支援する便利なライブラリ！
- 雑多なデータをpandas（データフレーム）に入れることにより、解析がしやすくなる。データフレームとは、２次元のデータ構造を指す。縦軸はindex,横軸はcolumns。

#### jupyter notebook とgoogle colab のデータセットの読み込みの違い 
- ２つのエディタ（環境）共に、pythonを使える環境が提供されている
- google colabはファイル読み込むときは、google driveに格納されているファイルを読み込む

`from google.colab import files`
`uploaded = files.upload()`

- jupyter notebook はローカルフォルダのファイルを読み込む


#### データセットに使える政府機関のサイト（ただし手加工必要）
- [e-Stat](https://www.e-stat.go.jp/)
- 日本政府が運営する統計サイト。
- ただ、こちらの統計データは、Excel上で扱うことをイメージして作られているので、直でpandasで読み込むのはNG。 
- Excelの縦・横軸で不要な行を削除してから、pandasにInportするのが良い。
- 言いたいことは、「pandasはなんでもやってくれる銀の弾丸ではない！　e-Statは凄くいいデータを持っているので、使ってみるのが良いよ！」

# 感想
- jupyterもgoogle colabも他の勉強サイトを通して触ったことがあったが、実際に使っている人から対面で聞くのは、自分の道具の使い方のブラッシュアップになっていい（こうやって使うといいよ〜）。
- 先生も参加者の方も、いろんな職業・職種が混ざっていて、かつ和気藹々な空気感だったので、凄く楽しかったです。

#### 参加者Slackチームで共有されたサイト（面白い！）
- [アヤメデータを使った機械学習の流れを簡単にまとめてみた](https://yolo.love/scikit-learn/iris/)　←勉強会で扱ったデータ
IE11でsvgをimageタグで読み込んだ場合にサイズが適用されない

## 概要

IE11でsvgをimageタグで読み込んだ場合に、下記のような記述で、CSSのサイズが画像に適用されなかった。

```html:index.html
<div class="img"><img src="dummy.svg" alt=""></div>
```

```css:style.css
    .img img {
    	width: 300px;
    	height: auto;
    }
```

## 解決策
```css:
    .img {
    	width: 300px;
    }
    .img img[src$=".svg"] {
        width: 100%;
        height: auto;
    }
```

属性セレクタで横幅の指定する。親要素にサイズを指定するとimg要素が親要素にフィットして表示される。

svg自体にviewBoxの指定がされていないと、上記のみの記述では効かない。
その為、viewBoxの記述を追加すると動作するようになる。

```html
<svg xmlns="http://www.w3.org/2000/svg" width="640" height="480" viewBox="0 0 640 480">
```

## 参考

[https://stackoverflow.com/questions/27970520/svg-with-width-height-doesnt-scale-on-ie9-10-11](https://stackoverflow.com/questions/27970520/svg-with-width-height-doesnt-scale-on-ie9-10-11)
[https://qiita.com/Shitsu/items/4edf6fae3329c4904f29](https://qiita.com/Shitsu/items/4edf6fae3329c4904f29)
Windows PCを使ってGoogle Homeを喋らせてみた

##はじめに
Google home miniを使って、外部のアプリ等で通知した内容を喋らせることができないか試してみた。
Google home miniから、特定の文言で外部アプリに連携することは、IFTTTを使ってできる。
だが、Google Homeを喋らせるためには、google-home-notifierを使用する必要がある。

[google-home-notifier](https://github.com/noelportugal/google-home-notifier)：Googleホームに通知を送信するNode.jsライブラリ

WindowsのPCでgoogle-home-notifierを実行し、Google Homeを喋らせる方法について試してみた。

OS：Windows 10

##準備
1. Node.jsのインストール
[Node.js](https://nodejs.org/ja/) - 10.15
※推奨版と最新版があるが、今回は、推奨版を使用

2. Windows Build Toolsのインストール
コマンドプロンプト(※管理者で実行する)で以下のコマンドを実行する。
`npm install --global --production windows-build-tools`

3. node-gypのインストール
コマンドプロンプト(※管理者で実行する)で以下のコマンドを実行する。
[node-gyp](https://github.com/nodejs/node-gyp) に記載されている方法に従って実施する。
`npm install -g node-gyp`
![キャプチャ002.png](https://qiita-image-store.s3.amazonaws.com/0/190974/eaae979c-cdb5-2c6f-0e64-ef3b238ede58.png)
Pythonが複数バージョンインストールされている環境において、npm経由でnode-gypを実行する場合、Python2.7を使用する必要があるため、以下のコマンドを実行する。（※Python3.x系では、node-gypが実行できない。)
`npm config set python /path/to/executable/python2.7`

4. Bonjour SDKのインストール
[Bonjour SDK for Windows](https://developer.apple.com/download/more/?=Bonjour%20SDK%20for%20Windows)
インストーラーをダウンロードするために、Apple IDでのサインインが必要。
環境変数にBONJOUR_SDK_HOMEが設定されていることを確認する。
設定されていない場合は、「C:\Program Files\Bonjour SDK」で設定する。

5. Bonjour Print Serviceのインストール
[Bonjour Print Service(Windows)](https://support.apple.com/kb/DL999?locale=ja_JP)

6. google_home_notifierのインストール
コマンドプロンプト(※管理者で実行する)で適当な作業フォルダにcdコマンドで移動後に以下のコマンドを実行する。
`git clone https://github.com/noelportugal/google-home-notifier
cd google-home-notifier
npm install`

##プログラム
まずは、google-home-notifierないのexample.jsを用いて、google homeを喋らせることができるか試す。

IPアドレスと言語（以下の画像で黄色に色付けしている箇所）を修正し、Node.jsで実行する。
IPアドレス：GoogleHomeアプリで確認した値を設定する
言語：jaを設定
![キャプチャ003.png](https://qiita-image-store.s3.amazonaws.com/0/190974/7291277f-40cf-b4cb-3a4d-76d963e3b40e.png)

![キャプチャ004.png](https://qiita-image-store.s3.amazonaws.com/0/190974/8f8cdc0c-fe83-b2b9-fde2-1f7a61b9fc81.png)

表示されたエンドポイントに対して、リクエストを送信したところエンドポイント側で以下のエラーが表示され、Google Homeは喋ってくれない
![キャプチャ005.png](https://qiita-image-store.s3.amazonaws.com/0/190974/43e943d6-952c-7389-7040-44e158ec77ec.png)

[google-home-notifierで"Error: get key failed from google"とエラーが出る問題の対処法](https://qiita.com/ktetsuo/items/21f4f85a98145772be3d)を参考に対処を実施
Node.js内にインストールされたgoogle-home-notifierに含まれるpackage.jsonを編集する。

編集内容
node_modules\npm\node_modules\google-home-notifier\package.jsonの以下の画像の黄色で色付けしている箇所を0.0.5に変更する。
![キャプチャ006.png](https://qiita-image-store.s3.amazonaws.com/0/190974/d7b68316-5cfc-8cc0-cd75-cfa83469e594.png)

上記対応をして再度試したところ、Google Homeを喋らせることができた。

example.jsをもとに、エンドポイントを立ち上げ、IFTTTのアクションでWebhooksで立ち上げているエンドポイントにリクエストを送信すると、外部のアプリから、Google Homeを喋らせることができた。
【WPF】ItemsControlで、複数のControlを重ねて表示する

# やりたいこと
画面上に、複数の線を描きたいときに、Polylineを使おうと思ったが、画面のxamlに「Polyline・・」を何個(何十個)も書きたくないので、コレクションにPolylineをAddするだけで画面に線を追加したい。

# 結果
ItemsControl.ItemsPanelにItemsPanelTemplateを入れて、「Grid」や「Canvas」を指定するとできる。
具体的には、下記のようにする。

``` MainWindwo.xaml
<ItemsControl ItemsSource="{Binding Pl}" Width="600" Height="600">
    <ItemsControl.Template>
        <ControlTemplate TargetType="ItemsControl">
            <ItemsPresenter Margin="10" />
        </ControlTemplate>
    </ItemsControl.Template>

    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <!-- ここに、Gridを指定する。-->
            <Grid />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl>
```
バインドしたプロパティをもつViewModelは下記のようにしている。

``` ViewModel.cs
namespace WpfApp1
{
    class ViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        // ItemsControlのSourceに設定するコレクション
        public ObservableCollection<Polyline> Pl { get { return pl; } }
        public ObservableCollection<Polyline> pl = new ObservableCollection<Polyline>();
        
        // DataTemplateの中にバインドしたいプロパティ
        public Thickness MyThickness { get; } = new Thickness(20);

        public ViewModel()
        {
            Polyline pl1 = new Polyline();
            pl1.Points.Add(new Point(10, 10));
            pl1.Points.Add(new Point(200, 150));
            pl1.Stroke = new SolidColorBrush(Colors.Red);
            pl1.StrokeThickness = 5;
            pl.Add(pl1);

            Polyline pl2 = new Polyline();
            pl2.Points.Add(new Point(15, 15));
            pl2.Points.Add(new Point(250, 600));
            pl2.Points.Add(new Point(600, 400));
            pl2.Stroke = new SolidColorBrush(Colors.Yellow);
            pl2.StrokeThickness = 5;
            pl.Add(pl2);
        }
    }
}

```

上記を実行すると、下記のようになる。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/352601/bf2af260-8087-c15a-7d34-da1ec6629c9d.png)

# ItemsControlについて
ItemsControlは、ListBoxの継承元のクラス。使い方は、下記を参照。
https://qiita.com/tera1707/items/363d2a33eadcb3eb275a

# Gridでないものを指定したとき
ListBoxを使う場合など、普通は縦や横に項目を並べたいと思うので、Gridではなく、StackPanelやWrapPanelを指定すると思う。
例えばStackPanelを指定すると、こうなる。
(2つのPolylineが、縦に並んでいる)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/352601/46233e91-f791-69c8-3f5f-4670edfb9538.png)

# 参考
自分のページ(ListBox関連)
https://qiita.com/tera1707/items/363d2a33eadcb3eb275a

ItemsControl 攻略 ～ 外観のカスタマイズ
http://grabacr.net/archives/1240

# コード
https://github.com/tera1707/WPF-/tree/master/018_BindIntoDataContext_ItemsPanelTemplate
RealmのModelを独自の型に変換して使いたい

Realmでデータを取得するとResults型で返却されますが、Realmで定義された型を使いたくない時の内容になります。

## 目的
Realmで取得した内容は`RealmSwift.Results`型で返却されます。ただ、レイヤーアーキテクチャで言うとインフラ層に位置するので、個人的にView, ViewModelで扱うのは抵抗があります。そのため、View, ViewModelでは独自に定義した型に変換して使用したいです。


## 内容
データモデルは以下のように定義します。

```swift
# 独自の型
struct MyTask {
    let id: String
    let title: String
    let finished: Bool
}

# RealmのModel
final class ReMyTask: Object {
    @objc dynamic var id = UUID().uuidString
    @objc dynamic var title = ""
    @objc dynamic var finished = false

    override static func primaryKey() -> String? {
        return "id"
    }
}
```

以上の`ReMyTask`に変換する処理を追加します。

```swift
final class ReMyTask: Object {
    @objc dynamic var id = UUID().uuidString
    @objc dynamic var title = ""
    @objc dynamic var finished = false
    
    override static func primaryKey() -> String? {
        return "id"
    }

    var taskStruct: MyTask {
        get {
            return MyTask(id: self.id, title: self.title, finished: self.finished)
        }
    }
}
```

使い方は以下のように行います。

```swift
let realm = try! Realm()
let tasks = realm.objects(ReMyTask.self)

# MyTaskのstructで返却される
Array(tasks).map({ (data: ReMyTask) in data.taskStruct })
```

## まとめ
実はこの記事を書いている日に初めてRealmを使い始めたので、アンチパターンであるなら申し訳ないです。ただ、`RealmSwift.Results`が広範囲で使われることで保守しずらくなりそうだなと感じたのでこのような記事にしました。
CLIでAWSのEC2にapacheをインストールして起動するまでのコマンド

## 事前作業

マネジメントコンソールでEC2インスタンスを作成・起動し、pemファイルをダウンロードしておく。

## EC2にログインするまで(ローカルPC上)

### pemファイルの権限を操作する

`chmod 400 hogehoge.pem`

EC2にSSH接続するためのpemファイルの権限を操作する。

自分以外のユーザーがこのファイルの読み込みと書き込みをできないように、
かつ自分が読み込みだけできるように変更する。

この操作をしておかないとSSH接続時にwarningが表示されてEC2に接続できない。

### SSHでEC2に接続する

`ssh -i hogehoge.pem ec2-user@[起動中のEC2のIP address]`

## EC2にログインした後

### apacheのインストール

`sudo yum install httpd`

### apacheの起動

`sudo service httpd start`

## ブラウザでapacheの起動を確認

EC2のIPアドレスをブラウザのアドレスバーに入力・実行するとapacheが起動していることが確認できる。
[Laravel] ソフトデリートと取得、復元、完全削除

#物理削除と論理削除
データベースの削除には物理削除と論理削除があります。言葉はどうでもいいのですが、２つには大きな違いがあります。
それは、復元可能かどうかということです。
この復元可能な削除、いわゆるゴミ箱に入っている状態にする削除方法が論理削除でソフトデリートになります。
#とりあえずデータベースを作る
データベースを作っていきましょう。

```terminal
php artisan make:migration create_contents_table --create=contents
```
ここではcontentsテーブルを作成しています。

```php:create_contents_table.php
    public function up()
    {
        Schema::create('contents', function (Blueprint $table) {
            $table->increments('id');
            $table->text('body');
            $table->timestamps();

            $table->softDeletes();
        });
    }
```
textデータ型で、bodyカラムを作っている単純なデータベースです。
最後の`$table->softDeletes();`がポイントです。
このテーブルの要素に削除処理をするときはソフトデリートだよと、定義しています。
#付随したモデルを作る
次に、データベースに付随したモデルを作りましょう。

```terminal
php artisan make:model Content
```

```php:Content.php
use Illuminate\Database\Eloquent\SoftDeletes;

class Content extends Model
{
    use SoftDeletes;

    protected $dates = ['deleted_at'];

    protected $fillable = [
        'body'
    ];
}
```

モデルでは、`$fillable`でbodyをいじれるように設定しています。
`use SoftDeletes` でソフトデリートを使用できるようにしており、削除した日がわかるように`$dates`でdeleted_atカラムを作成しています。

ここまできたら`migrate`しましょう。

```terminal
php artisan migrate
```

#中身が空なのでデータを入れる
現在は中身が空なので適当にデータを３つぐらい入れてみましょう。

```php:web.php

use App\Content;

Route::get('/contents/insert', function() {
    Content::create([
        'body' => 'Laravel is PHP framework!!',
    ]);
});

Route::get('/contents/insert2', function() {
    Content::create([
        'body' => 'PHP is programming language!!',
    ]);
});

Route::get('/contents/insert3', function() {
    Content::create([
        'body' => 'programming is a lot of fun!!',
    ]);
});
```
これで指定のURLにアクセスするとデータが入ります。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/286470/f4a9bff7-41b7-90a6-d2fd-99c1da7e4448.png)

いけてますね。`deleted_at`は現在NULLになっています。

#ソフトデリートと取得
本題のソフトデリートをしてみましょう。

```php:web.php
Route::get('/contents/softdelete', function() {
    Content::find(1)->delete();
});
```
idが１の要素を削除します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/286470/5fabb2bf-ac69-dd56-f63a-39b7fc5f96d4.png)

いけましたね。削除した日が表示されておりデータベースにはあるけど取得はできません。

次は削除した要素を取得しましょう。

```php:web.php
Route::get('/contents/softdelete/get', function() {
    $content = Content::onlyTrashed()->whereNotNull('id')->get();

    dd($content);
});
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/286470/e645f5d9-622b-3fbe-154d-e4c39178adfa.png)

いけていますね。

#他のメソッドも紹介
`onlyTrashed()`は削除済みの要素のみ取得するメソッドですが他のメソッドもあります。
また完全削除や、復元のメソッドも紹介します。

```php
//削除済みのデータも含める
Content::withTrashed()->whereNotNull('id')->get();

//完全削除
Content::onlyTrashed()->whereNotNull('id')->forceDelete();

//復元
Content::onlyTrashed()->whereNotNull('id')->restore();

```
#まとめ
早くlaravelを使いこなせるようになりたいです。。。
macでnode.jsのhello world

# 前提

- ググってやってみたけどググり力が弱く、日本語記事のまま出来なかったので備忘録

# 環境

- macOS Mojave 10.14.3
- node.js 10.15.3 LTS

# やる事

以下を読んで、2ページ目までのHello Worldまで進める。以上。

https://expressjs.com/en/starter/installing.html

ちなみにexpressコマンドが入らない、、って悩んでたのは、3ページ目のExpress Navigaterまで進めばコマンド入るっぽい。

結果的には何かこんな感じの画面が出ます。

<img width="723" alt="スクリーンショット 2019-03-21 12.37.39.png" src="https://qiita-image-store.s3.amazonaws.com/0/381696/75453334-cd73-7683-ba44-9a96eacf2496.png">
Rspecでsidekiqのジョブ登録をテストしたいとき

SidekiqのテストはSidekiq::Testing.fake! を使うと便利です。
テストの前に実行するとRedisにジョブを登録するのではなく、workerオブジェクトのjobsメソッドで、登録されるjobを確認できるようになります。


https://github.com/mperham/sidekiq/wiki/Testing#testing-worker-queueing-fake

以下はjobが登録されることを確認するテストです。
`HogeWorker.jobs.size`で登録されたjobの数を取得しています。

```ruby

require ‘sidekiq/testing’
# 省略

before do
  Sidekiq::Testing.fake!
end

context ‘ワーカーのテスト’ do
  it do
      expect { HogeWorker.new.perform }.to change { HogeWorker.jobs.size }.by(1)
  end
end
```

上記でもテストできるのですが、beforeブロックでSidekiq::Testing.fake!を実行すると、
グローバルで設定が有効になり他のテストにも影響を与えてしまいました。
なので、使う時はブロックで囲って以下のようにすると、特定のテストだけでSidekiq::Testing.fake!を有効にすることができます。

```ruby

require ‘sidekiq/testing’
# 省略

context ‘ワーカーのテスト’ do
  it do
    Sidekiq::Testing.fake! do
      expect { HogeWorkernew.perform }.to change { HogeWorker.jobs.size }.by(1)
    end
  end
end
```
エンジニアの知的生産術を読んで

# いつも通り本を読んだアウトプットを挙げます
今回の本は<a hlef="https://www.amazon.co.jp/dp/B07JFRF6MW/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1">エンジニアの知的生産術</a>です

- 基本的にはポイント形式で、文章にはしません
- 既知の項目についてはメモしません

# 学習理論

- 情報収集→抽象、モデル化→応用、実践
    
# タスクの分類ポイント

- 行動を起こす必要がないものは’ゴミ’’資料’’保留’に分ける
- 次に取るべき項目が複数なら、プロジェクトととする
- 次にできるのが2分以内で出来るなら、今やる
- 不確かな時は楽観的に優先順位をつける（そこまで労力を使うべきでない）

#見積もり能力はどのように鍛えられるか？

→見積もり、実行し、記録し、振り返ることでしか鍛えられない
ここでのポイントは、分析方法。より詳細に記録しておきくことで「現状を詳細に分析」できる

# 記憶力はどのように鍛えられるのか？

- アウトプットとインプットのサイクルを如何に短くできるか。
　→プログラムの場合、読んで勉強するのではなく、作りながらわからないところを学習していくことで、
　インプット⇔アウトプットのサイクルを非常に早く回せる
- 物事を構造化すること
- 全体から、詳細の流れを作ること

# 本の読み方
- 読書ノートをつける。
　→この本から学び取りたいこと（目的）を明確に記載し、各章に対して「理解したポイント」「わからない点→なぜわからない？」「書くキーワードの構造化」を行う。
- 理解している状態を明確に定義するor完全に定義しない


# 何を勉強すべきか？
３つの方針が存在する。どの視点からついていくのから自分次第
- 興味ある事ベース
- 差別化（メンバーがまだ手を付けていない）ベース