OmniAICreator/Qiita-1.07M huggingface dataset:
Unityで出力したXcodeプロジェクトがiOS11の実機デバッグで起動直後にクラッシュする件の対応

# 環境
macOS Sierra バージョン 10.12.6
Unity 5.4.3f1
Xcode Version 9.0 (9A235)
iOS 11.0.3（iPhone 7 Plus）

# 現象
表題のとおり、iOS11の実機デバッグで起動直後に以下エラーが出て落ちる。

`UnityGfxDeviceWorker (19): signal SIGABRT`

iOS10では発生せず、iOS11でもUnity Cloud Buildやアプリインストール後にXcodeを介さず起動した際は問題なく動作する。XcodeでRunした時だけ落ちるのでコンソールでのログ出力確認等が出来ない。

クラッシュ時のコンソールには「テクスチャには指定されていない使用法があります」的なことが書かれていた。

```
validateRenderPassDescriptor:487: failed assertion `Texture at colorAttachment[0] has usage (0x01) which doesn't specify MTLTextureUsageRenderTarget (0x04)'
```
Unity初心者なのでちょっとよくわからなかった。

# 対応
ググってみるとUnityのiOS Player Settingsで「Auto Graphics API」を切って、MetalのかわりにOpenGLES2の優先度を上げれば回避できるとの情報を見かけた。

http://m.manew.com/thread-108510-1-1.html

> Automatic Graphics API	どのグラフィック API を使用するか選択するためのオプションです。チェックを付けた場合、Unity は Metal の使用を試み、デバイスが Metal に対応していない場合は GLES2 を使用します。チェックを付けていない場合、手動でグラフィック API の選択や使用優先度の変更ができます。手動でAPIを1つ選択するとアプリの info.plist の内容は変更され、App Store の規約に適切なものになります。
> 
> [Unity - マニュアル: iOS Player Settings](https://docs.unity3d.com/jp/540/Manual/class-PlayerSettingsiOS.html)

グラフィック設定が変わるためエフェクト表示などに影響が出る可能性もあるので、そのあたりは別途検証の必要がありそう。

今回はAPIレスポンスの速度計測のため起動時のログを出したいだけだったので、暫定対応としてこの方法で解決した。
![スクリーンショット 2017-10-19 13.11.36.png](https://qiita-image-store.s3.amazonaws.com/0/6380/17b94167-d18c-8688-3004-ceed1ed88572.png)


Xcode上でも Product -> Scheme -> Edit Scheme... から、RunのOptionsで Metal API Validation を Disable にできる模様。
![スクリーンショット 2017-10-19 13.21.33.png](https://qiita-image-store.s3.amazonaws.com/0/6380/90c50812-c111-fd75-8b34-d7899c314786.png)


根本的にはコンソールログにあるとおりテクスチャ設定をしくていく必要ありそうだけど、アプリ内で使用している画像があまりにも多過ぎるので、ひとつひとつ設定していくのは現実的ではない。

使用しているUnityのバージョンが古いのでバージョンを上げれば解消されるのかな？
Unity 2017.1.1f1でも発生しているとの情報もあったので、バージョンアップ後にまた見てみる予定。
http://forum.china.unity3d.com/thread-28258-1-1.html

色々調べてみたけどXcodeのバグなのかiOSのバグなのかUnityのバグなのか俺のバグなのか、具体的な原因がわからなかった。

本件に関して正しい対応方法があればご教示いただきたいです。
計算量とP≠NP予想

一旦メモ

# 用語の整理

|       |概要|
|:------|:---|
|多項式時間アルゴリズム|時間計算量がnの多項式関数であるアルゴリズム O(1), O(N),O(N^2),...|
|指数時間アルゴリズム|時間計算量がnの指数関数 O(2^n), O(n!),....|
|複雑性クラス||
|P問題  |複雑性クラス[(wikipedia)](https://ja.wikipedia.org/wiki/%E8%A4%87%E9%9B%91%E6%80%A7%E3%82%AF%E3%83%A9%E3%82%B9)の一つ。多項式時間で解を求めることが出来る問題|
|NP問題 |複雑性クラスの一つ。解の正当性を多項式時間的に確かめることが出来る問題|
|NP完全問題| 指数時間アルゴリズムは存在するが、取って代わる多項式時間アルゴリズムは存在しないと予想されている問題 (ex 巡回セールスマン問題)<br> ここでいう完全とは「そこで閉じている」という意味。|
|P≠NP予想|NP完全問題として考えられている問題は、P問題になりえないという予想|


# NP完全問題

P問題になりえないと予想されているNP問題

* 巡回セールスマン問題
* ハミルトン路

上記それぞれ解の正当性は直ぐに判別することが出来るが、
その解を導出するアルゴリズムは、指数時間となるアルゴリズムしか見つかっていない。
typescript(javascript)でarrayかhashかを判定する

## ネットで拾ってきたコードをtypescript用に修正したメモ

- hashはピンポイントで特定できない
- `typeof`を地道に使う


```js
judgeArrOrHash(obj) {
    if((typeof obj) === 'object'){
      if(obj.length != undefined){
        console.log('array');
        return 'array'
      } else{
        for(let t in obj) {
          if(obj[t] != undefined) {
            console.log('hash');
            return 'hash'
          }
          else {
            console.log('object');
            return 'object';
          }
        }
      }
    } else {
      console.log('not array nor hash');
      return (typeof obj)
    };
  }
```

### 使ってみる

```js
  let arrdata = [1,2,3];
  let hashdadta = { key1: 2, key2: 3};
    
  this.judgeArrOrHash(arrdata);
  // => array
  this.judgeArrOrHash(hashdadta);
  // => hash
```
【SQL Server】まだ追加されてい場合のみ、列の追加を行う

追加したい列が、既に存在する場合でもエラーにならない方法を調べたのでメモ

```:SQL
/* まだ追加されてい場合のみ、列の追加を行う */
IF COL_LENGTH('table_name','column_name') IS NULL
    BEGIN
        ALTER TABLE table_name ADD column_name INT
    END;
```
文字列置換方法の違いによるスピードの比較

* 文字列置換の方法によってどれくらいスピードに違いがあるのか確認してみました。
* 今回のサンプルは単純な文字列置換ですが、結果はsedコマンドがawkコマンドの70%ほどの時間で完了することがわかりました。
* bashのwhileの中で置換する方法も2つ確認しましたが、bash変数の文字列置換とsedコマンドを使う方法では750倍以上の差が出ました。

ソースコード

```bash:q_01_gorilla.sh
#!/bin/bash

FileFrom="Gorilla.tmp"
FileTo="Gallus.tmp"

StringFrom="Gorilla gorilla"
# StringTo "Gallus gallus"

# 100万行のファイルを準備します
rm -f "${FileFrom}"
for (( i = 0; i < 1000000; i++ )); do
  echo "${StringFrom}" >> "${FileFrom}"
done

# sedコマンドで置換します
echo -e "\n### sed ###"
rm -f "${FileTo}"
cat "${FileFrom}" > /dev/null
time sed 's/orilla/allus/g' "${FileFrom}" > "${FileTo}"
cat -n "${FileTo}" | tail -n 2

# awkコマンドで置換します
echo -e "\n### awk ###"
rm -f "${FileTo}"
cat "${FileFrom}" > /dev/null
time awk '{gsub("orilla","allus",$0) ; print $0}' "${FileFrom}" > "${FileTo}"
cat -n "${FileTo}" | tail -n 2

# whileの中でbashの変数置換機能を使用します
echo -e "\n### bash ###"
rm -f "${FileTo}"
cat "${FileFrom}" > /dev/null
time cat "${FileFrom}" | while read line; do
  StringTo="${line//orilla/allus}"
  echo "${StringTo}"
done > "${FileTo}"
cat -n "${FileTo}" | tail -n 2

# whileの中でsedコマンドで置換します
echo -e "\n### sed-2 ###"
rm -f "${FileTo}"
cat "${FileFrom}" > /dev/null
time cat "${FileFrom}" | while read line; do
  echo "${StringFrom}" | sed 's/orilla/allus/g'
done > "${FileTo}"
cat -n "${FileTo}" | tail -n 2

```


実行結果

```
$ ./q_01_gorilla.sh

### sed ###

real	0m0.121s
user	0m0.092s
sys	0m0.012s
 99999	Gallus gallus
100000	Gallus gallus

### awk ###

real	0m0.171s
user	0m0.144s
sys	0m0.004s
 99999	Gallus gallus
100000	Gallus gallus

### bash ###

real	0m2.861s
user	0m2.012s
sys	0m0.724s
 99999	Gallus gallus
100000	Gallus gallus

### sed-2 ###

real	3m4.987s
user	0m6.748s
sys	0m25.956s
 99999	Gallus gallus
100000	Gallus gallus

```
Firebase Realtime Databaseはもう改善されて行かないかもしれない。

# GoogleさんのFirebase iOS SDKにFeature Requestを送っておいた

https://github.com/firebase/firebase-ios-sdk/issues/257

この機能のは、値のインクリメントをバックエンドでやって欲しいというもの。
データベースで数値をインクリメントする場合、トランザクションをして数値を変更する必要があります。Firebaseはせっかくの強力キューを持っているので`+1` `-1`を渡してあげればFirebase側でどうにかして欲しいと考えたわけです。


> We are planning to add this as a feature to Firestore, but are not intending to backport this feature to the RTDB.

**🎉 Firestoreでは導入されるようです**

**😥 FirebaseRealtimeDatabaseではサポートなし**

二つのDBに対しての対応の差が意味するものはなんなんでしょうか。
FirebaseRealtimeDatabaseも素晴らしいDBなので拡張は期待したいところです。
Slackの環境設定を変更して気分転換

slackの配色変更、絵文字変更等やろうとした時に手順をいつも失念しているので備忘として記載する。


# １．環境面の設定
### １．１．配色の変更
Menu→Preferences→sidebarからslackの配色設定が可能。
複数のワークスペースに参加している場合、ワークスペースごとに色の設定が可能なので色による使い分けをすると良いかもしれない。

**Sidebar Theme**
slackがデフォルトで用意している配色テーマ。
ラジオボタンで簡単に配色の変更が出来る。
>![image.png](https://qiita-image-store.s3.amazonaws.com/0/174609/f82e90b8-fb7c-10b9-f580-309da7e9165c.png)

**Custom Theme**
色コードが分れば、配色を自由に設定できる。

配色なんて考えられないよって人におすすめしたいのが下記サイト。
ポケモンの配色を元にslack用の配色を自動生成してくれるサイトがある。
自動生成された配色をslackに貼り付けるだけで簡単に変更する事ができる。

[Pokémon Slack theme generator](http://pokeslack.xyz/)
ポケモンを指定する事もできるし、ランダムで選ぶ事も可能という優しさ。
※ポケモンの指定をする場合、使用ブラウザによっては上手く動作しない事がある模様。

### １．２． 絵文字の変更
**絵文字フォーマットの変更**
SlackのTeam名→Preferences→Messages&Mediaからslackの絵文字のフォーマットが変更可能。

>![image.png](https://qiita-image-store.s3.amazonaws.com/0/174609/fcfcdd8c-c821-e3fc-ba88-fdc92d300e42.png)

ラジオボタンで気軽に絵文字のフォーマットを変更する事ができる。
Emoji Styleを変更すると同じ絵文字でも違って見えるので色々と試してみるのも楽しい。


**絵文字の追加**
Menu→Customize Slack→Emojiから、好きな画像をEmojiとして追加する事ができる。
追加したEmojiはEmoji選択ウィンドウの#タブ(Custom)に表示されるようになる。

>![image.png](https://qiita-image-store.s3.amazonaws.com/0/174609/29821a62-ad95-d91b-875d-abcb48a143be.png)

あまり細かい画像はおすすめしないが、「了解」等の画像を追加しておくと汎用性が高い。



# ２．その他設定
### ２．１．特定の言葉にslackbotを反応させる。
Menu→Customize Slack→Slackbotから特定の言葉に反応するように変更できる。
>![image.png](https://qiita-image-store.s3.amazonaws.com/0/174609/d6c2f1ee-0e3d-933a-a222-7686c16efa75.png)

上記のように設定し、各チャンネルで特定の言葉を投稿した場合、slackbotが指定した反応をするようになる。

>![image.png](https://qiita-image-store.s3.amazonaws.com/0/174609/ecff40b7-dba5-812e-b6c8-4638a23abb54.png)


### ２．２．botツール
紹介しているサイトを記載しておく。

[意外に知らない、Slackのbotサービス5選を紹介します！](https://seleck.cc/967)
matplotlib グラフ作成Tips (2) 上と右の軸を描画しない

まずは作例を．

![fig_mesh.png](https://qiita-image-store.s3.amazonaws.com/0/129300/0590c2d4-368f-4902-863f-90472cfdab38.png)

この手の図を描く時，以下のようにしたいという希望があります．

+ 上と右の軸を消したい
+ 縦横比を1:1にしたい

これを実現するコード例を以下に示します．


```python:
fsz=10
ixx=20
fig = plt.figure(figsize=(ixx,int(ixx/aa*bb)),facecolor='w')
plt.rcParams['font.family'] = 'sans-serif'
plt.rcParams["font.size"] = fsz
plt.xlim([xmin,xmax])
plt.ylim([ymin,ymax])
plt.xlabel('x-direction (m)')
plt.ylabel('y-direction (m)')
plt.gca().spines['right'].set_visible(False)
plt.gca().spines['top'].set_visible(False)
plt.gca().yaxis.set_ticks_position('left')
plt.gca().xaxis.set_ticks_position('bottom')
plt.axes().set_aspect('equal', 'datalim')
#plt.gca().set_aspect('equal', adjustable='box')
```

これをaxesクラスで書くと．．．

```python:
fsz=10
ixx=10
fig = plt.figure(figsize=(ixx,int(ixx/aa*bb)),facecolor='w')
plt.rcParams['font.family'] = 'sans-serif'
plt.rcParams["font.size"] = fsz
ax1=plt.subplot(111)
ax1.set_xlim([xmin,xmax])
ax1.set_ylim([ymin,ymax])
ax1.set_xlabel('x-direction (m)')
ax1.set_ylabel('y-direction (m)')
ax1.spines['right'].set_visible(False)
ax1.spines['top'].set_visible(False)
ax1.yaxis.set_ticks_position('left')
ax1.xaxis.set_ticks_position('bottom')
ax1.set_aspect('equal', 'datalim')
```

以　上
Xperia Companionのアンインストール

# Xperia Z5には、Android Oreoが来ない！
Xperia Z5を使っていますが、Android Oreoのリリースがなくなりました。
と言うわけで捨ててしまおうと思い、Xperia Companionをアンインストールしました。
その手順をメモ。

ちなみに、同じCPU、RAM搭載のNexus 6PにはOreoが配信されていますので、SONY Mobileの怠慢と映っても仕方ないと思います。
今後Androidの機種を使うならGoogle様純正のPixelにするしかないのかもしれませんが、なんと売ってません:frowning2:
やはり「iPhoneにしなさい」って事なのかもしれません:neutral_face:

# アンインストール
Xperiaと名前が付いているものを探して削除しました。

```
sudo rm -rf ~/Library/Application\ Support/com.sonymobile.Xperia-Companion
sudo rm -rf ~/Library/Application\ Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.sonymobile.xperia-companion.sfl
sudo rm -rf ~/Library/Application\ Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.sonymobile.xperia-companion-updater.xperia-companion-updater.sfl
sudo rm -rf ~/Library/Application\ Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.sonymobile.xperia-companion-agent.sfl
sudo rm -rf ~/Library/Saved\ Application\ State/com.sonymobile.Xperia-Companion.savedState
sudo rm -rf ~/Library/Preferences/com.sonymobile.Xperia-Companion-Helper.plist
sudo rm -rf ~/Library/Preferences/com.sonymobile.Xperia-Companion-Agent.plist
sudo rm -rf ~/Library/Preferences/com.sonymobile.Xperia-Companion.plist
sudo rm -rf ~/Library/Caches/com.sonymobile.Xperia-Companion
sudo rm -rf ~/Library/Caches/com.plausiblelabs.crashreporter.data/com.sonymobile.Xperia-Companion
sudo rm -rf ~/Documents/Sony/Xperia\ Companion
sudo rm -rf /Applications/Xperia\ Companion.app
```

# 余談
SONY MobileのブログでもZ5非対応の批判は多いんだけど、考え直してくれないかな:unamused:

* SONY MobileのOreoアップデート機種
 * https://blogs.sonymobile.com/2017/08/31/xperia-android-8-0-oreo/
特定の2つの日付の間から、ランダムに1日を取得


```php
// 特定の2つの日付の例
$start = Carbon::create("2015", "1", "1");
$end = Carbon::create("2020", "12", "31");
    
// タイムスタンプに変換
$min = strtotime($start);
$max = strtotime($end);

// タイムスタンプにした2つの日付の中からランダムに1つタイムスタンプを取得
$date = rand($min, $max);

// タイムスタンプ => Y-m-d に変換    
$date = date('Y-m-d', $date)
```
Unity複数起動するときにどれかわからなくなった人のためのEditorスクリプト

複数Unity起動していると、どれがどのプロジェクトか忘れちゃうので、
メニューに表示するスクリプト作成。
ゴリゴリで書いているので、汚いソースには目をつぶってください。

Assetsの親の親の名前を取ってきているのは、
git管理とかだと、Assetsの親を
「Project」とか「Unity」とか「UnityScript」とか統一していて、
同階層にドキュメントとかツールをおいている人も多いかなぁと思ってそうしております。

```cs:ProjectUtil.cs
using UnityEngine;
using UnityEditor;
using System.IO;
using System.Collections;
using System.Collections.Generic;

namespace yyama2.Editor {

    public partial class ProjectUtil : AssetPostprocessor {
        private const string THIS_FILE_NAME = "ProjectUtil.cs";
        private const string PROJECT_NAME = ""; // ここが勝手に書き換わる。
        private const string PROJECT_NAME_REPLACE_FORMAT = "private const string PROJECT_NAME = \"{0}\";";
        private const string MENU_ITEM_ROOT = "【" + PROJECT_NAME + "】" + ":ProjectUtil/";
        public static void OnPostprocessAllAssets (string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromPath)
        {
            // コンストラクタ起動用に定義
        }
        private const string PROJECT_DIR_NAME = "Project";

        static ProjectUtil()
        {
            var path = Application.dataPath;
            var projName = path.Substring( 0, path.Length - path.Substring( path.LastIndexOf( PROJECT_DIR_NAME ) ).Length );

            var temp = Path.GetDirectoryName( projName ).Split( "/"[0] );
            projName = temp[temp.Length-1];

            if( projName != PROJECT_NAME)
            {
                var thisFilePath = CombineAll( Application.dataPath,"Editor",THIS_FILE_NAME);
                string text = "";
                using ( StreamReader reader = new StreamReader( thisFilePath, System.Text.Encoding.UTF8 ) )
                {
                    text = reader.ReadToEnd();
                }
                text = text.Replace( string.Format( PROJECT_NAME_REPLACE_FORMAT, PROJECT_NAME ), string.Format( PROJECT_NAME_REPLACE_FORMAT, projName ) );

                using ( StreamWriter writer = new StreamWriter( thisFilePath, false, System.Text.Encoding.UTF8 ) )
                {
                    writer.Write( text );
                }
                AssetDatabase.Refresh();
            }
        }

        private static string CombineAll( string root, params string[] stringArray )
        {
            if( stringArray == null || stringArray.Length == 0 ) return stringArray[0];

            string path = null;
            path = Path.Combine( root, stringArray[0] );

            if (stringArray.Length == 1)
            {
                return path;
            }
            else
            {
                var stringList = new List<string>( stringArray );
                stringList.RemoveAt(0);
                return CombineAll( path, stringList.ToArray() );
            }
        }

        [MenuItem( MENU_ITEM_ROOT + "Hello" )]
        public static void ShowCurrentProjectDir()
        {
            // 
        }
    }
}
```
gRPCでユーザ/パスワード認証をする

# 環境

 | Client | Server
-----|-----|-----
言語  | Ruby | Go

# 参考にしたコード


https://github.com/grpc/grpc-go/issues/106#issuecomment-246978683
(clientとserverを両方goで実装した例)

# ソースコード

gRPCリクエストのメタデータで`username`と`password`を渡し、認証をします。

## Client

```client.rb
stub = HogeServer::Stub.new("localhost:99999", :this_channel_is_insecure)
request = HogeRequest.new(hoge: 'fuga')
metadata = { username: 'admin', password: 'admin123' }
stub.hoge(request, metadata: metadata)
```

## Server

```server.go
import (
	grpc "google.golang.org/grpc"
	metadata "google.golang.org/grpc/metadata"
)

grpcServer := grpc.NewServer(
	grpc.StreamInterceptor(streamInterceptor),
	grpc.UnaryInterceptor(unaryInterceptor),
)

func streamInterceptor(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
	if err := authorize(stream.Context()); err != nil {
		return err
	}
	return handler(srv, stream)
}

func unaryInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
	if err := authorize(ctx); err != nil {
		return nil, err
	}
	return handler(ctx, req)
}

func authorize(ctx context.Context) error {
	if md, ok := metadata.FromIncomingContext(ctx); ok {
		if len(md["username"]) > 0 && md["username"][0] == "admin" &&
			len(md["password"]) > 0 && md["password"][0] == "admin123" {
			return nil
		}
		return errors.New("AccessDeniedError")
	}
	return errors.New("EmptyMetadataError")
}
```
即時関数の書き方メモ　withアロー関数　

#即時関数とセミコロン
即時関数を使う場合は一般的にこんな感じで書かれたりする

```test.js
(function(){})()
```

javascriptを書く際にセミコロンを省略する宗教に入信している場合
これではエラーが出ることがあるので

```test.js
!function(){}()
```
こんな書き方をするパターンもある

#即時関数とセミコロンとアロー関数
アロー関数を使用する場合

```test.js
(()=>{})()
```
こうなる

同じくjavascriptを書く際にセミコロンを省略する宗教に入信している場合
これではエラーが出ることがあるので

```test.js
!()=>{}()
```
こう書きたくなるが、これもエラーになる。
そこで、こういう書き方にすることで回避できる

```test.js
;(()=>{})()
```
jQueryとかの関数で先頭にセミコロンがついてるのは他の行末にセミコロンが無いことを考慮しているから
もちろんfunctionを使う場合でも

```test.js
;(function(){})()
```
という書き方も可能
ASTERIA Excelとの連携が難しい

ASTERIAとExcelとの連携をしようとしているのですが、
思いのほか難しくて悪戦苦闘ナウ.

[【つないでみた】今だからこそ「ネ申Excel」を活用してみる！](https://www.infoteria.com/jp/warp/blog/asteria-warp/24732.html)

↑の記事の
ExcelPOIInputコンポーネントを,ExcelPOIOutputコンポーネントに変えて
Excelにデータを突っ込むだけの処理がしたい。
のだが、Excelと連動できない

# 原因①Excelは64bitはダメらしい. 32bitを使え.
[Microsoft Office 2010/2013の64bit版には対応していますか？]
(https://support.asteria.com/hc/ja/articles/229292568-Microsoft-Office-2010-2013%E3%81%AE64bit%E7%89%88%E3%81%AB%E3%81%AF%E5%AF%BE%E5%BF%9C%E3%81%97%E3%81%A6%E3%81%84%E3%81%BE%E3%81%99%E3%81%8B-)
ちょっと古い記事だが,
>フローデザイナーにおいてExcelビルダーおよびPDFビルダーをExcel 2010/2013の64bit版で動作させることはできませんのでご注意ください。

>Windows 64bit版にインストールしたExcel 2010/2013の32bit版では動作させることができます。


要は,32bitなら動く.

## Excelのビットを調べる
Excelの"ファイル"タブ
->"アカウント"タブ
->"Excelのバージョン情報"ボタン
を押下すると、何bitかの情報が出てきます.

これで32bitならOKです.64bitなら残念ながら入れなおしましょ.



[Excelファイルにデータを書き込むには]
(https://support.asteria.com/hc/ja/articles/115002171967-Excel%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AB%E3%83%86-%E3%83%BC%E3%82%BF%E3%82%92%E6%9B%B8%E3%81%8D%E8%BE%BC%E3%82%80%E3%81%AB%E3%81%AF9)

この記事から
>1. 配置したExcelPOIOutputコンポーネントをダブルクリックして、マクロを有効にしてExcelを起動し、書き込み先の実データファイル、もしくはデータ領域のテンプレートとしたい任意のExcelファイルを開く


## 配置したExcelPOIOutputコンポーネントをダブルクリックして
このときに,Excelを指定すると思うのですが,
C:\Program Files (x86)\Microsoft Office\root\Office16\EXCEL.EXE
↑を指定します。

DirectoryのPATHがC:\Program Files (x86) 配下だと32bitで動くソフトウェアが入ってます。
こちらだとOKです。
C:\Program Filesだとたぶん64bitなのでダメです。


### 間違ってExcelを指定したとき
[Excelビルダー起動時に選択するExcel.exeのパスを間違えたらExcelビルダーが起動できなくなりました]
(https://support.asteria.com/hc/ja/articles/229077087-Excel%E3%83%93%E3%83%AB%E3%83%80%E3%83%BC%E8%B5%B7%E5%8B%95%E6%99%82%E3%81%AB%E9%81%B8%E6%8A%9E%E3%81%99%E3%82%8BExcel-exe%E3%81%AE%E3%83%91%E3%82%B9%E3%82%92%E9%96%93%E9%81%95%E3%81%88%E3%81%9F%E3%82%89Excel%E3%83%93%E3%83%AB%E3%83%80%E3%83%BC%E3%81%8C%E8%B5%B7%E5%8B%95%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%8F%E3%81%AA%E3%82%8A%E3%81%BE%E3%81%97%E3%81%9F)

この記事を要約すると

C:\Users\ユーザーの名前\AppData\Roaming\Infoteria\flowdesigner\4.9.1\conf\excelbuilder.properties

ファイルを一旦削除し、もう一度ExcelPOIInputコンポーネント起動時に
C:\Program Files (x86)\Microsoft Office\root\Office16\EXCEL.EXE
を指定する.


# ExcelPOIInputコンポーネントダブルクリックすると動くはずなのだが・・・動かん
ExcelPOIInputコンポーネントダブルクリックした時の
ASTERIA側では, "ExcelBuilderの実行中です..." がちゃんと出力
![ETL-2017-10-19-1.png](https://qiita-image-store.s3.amazonaws.com/0/180419/12d0e023-9dfd-b939-8e00-a9bee067ce33.png)

Excel側だと,FlowDesignerメニューが出ない.
![ETL-2017-10-18-2.png](https://qiita-image-store.s3.amazonaws.com/0/180419/54fa1120-f1c3-b1a2-29f4-3f094a5f8db2.png)

# why???Japanese people!!!
>マクロを有効にしてExcelを起動し

**ここで一回警告が出るはずなのですが、出ません。**

一応, Excel側のオプションの設定は以下のようにしています.
###アドイン
分析ツール - VBA等をアクティブにしています.

###セキュリティーセンター
#### マクロの設定
>すべてのマクロを有効にする(推奨しません。危険なコードが実行される可能性があります)

にチェック
> VBAプロジェクト オブジェクト モデルへのアクセスを信頼する

にチェック
### ActivX の設定
>先に確認メッセージを表示してから,最低限の制限を適用してすべてのコントロールを有効にする

にチェック

もうわかりません。orz
わかる方がいらっしゃりました, ご教示願います(涙)
MySQLのJSON型カラムを日本語で検索する場合

以下のように、日本語がキーに使われているJSON型カラムを持つデータベースで、

```sql
mysql> SELECT * FROM hoge;
+----+----------------------------------------+
| id | payload                                |
+----+----------------------------------------+
|  1 | {"日本語": "にほんご"}                 |
|  2 | {"英語": "えいご"}                     |
|  3 | {"フランス語": "ふらんすご"}           |
+----+----------------------------------------+
3 rows in set (0.00 sec)
```

キーを指定して検索すると、エラーになる時がある。

```sql
mysql> SELECT * FROM hoge WHERE payload->'$.日本語' = 'にほんご';
ERROR 3143 (42000): Invalid JSON path expression. The error is around character position 11.
```

キーをクオートで括ることで解決。

```sql
mysql> SELECT * FROM hoge WHERE payload->'$."日本語"' = 'にほんご';
+----+-------------------------------+
| id | payload                       |
+----+-------------------------------+
|  1 | {"日本語": "にほんご"}        |
+----+-------------------------------+
1 row in set (0.00 sec)
```
NetowrkManagerで特定のWiFiに繋がったタイミングで自動でコマンドを実行させる

あるwifiに繋がったら自動でsshトンネルを掘ってほしかったので調べました。

`/etc/NetworkManager/dispatcher.d/`以下にシェルスクリプトを置いておくと、ネットワークの状態が変化したときに実行されるらしい。第一引数には変更があった対象のNIC名、第二引数は状態のメッセージが来るみたいです。第一引数だけつかって以下のようなものを書いて配置しました。


```bash
#!/bin/bash

if [ "$1" == wlan0 ] && iwconfig wlan0|grep HogeHogeAccessPoint; then
        if ! ps ax|grep "[s]sh -fND 8080"; then
                ssh -fND 8080 user@myserver.com -i /home/onokatio/.ssh/id_rsa -o "StrictHostKeyChecking no"
        fi
fi
```

変更があったNICがwlan0であること、さらに現在繋がっているAPがHogeHogeAccessPointであることを確認した上で、既にssh -fnDが実行されていないか確認し、動いていなかったらsshを実行します。
>ちなみにgrepでsshが[s]shとなっているのは、自分自身(grep ssh)をps axの中から検出しないようにするためです。

最後にsudo chmod +xで実行属性を付けて完了。
Tomcat ログローテート設定

## 環境
OS : CentOS7

## logrotate.d 編集
```$ vi /etc/logrotate.d/tomcat```

以下を記述する

```text:tomcat
# Logrotate file for Tomcat
/opt/apache/tomcat/logs/catalina.out {
        missingok
        copytruncate
        daily
        dateext
        rotate 60
}
```

## 強制ローテートさせて様子を見る

```$ /usr/sbin/logrotate -fv /etc/logrotate.d/tomcat```
Swift4でUser Defined Runtime Attributesがうまく効かないところがあった

## 問題
### UIViewの枠線の色が変わらなくなった

Storyboardの `User Defined Runtime Attributes` でUIViewに枠線や、角丸、枠線の色を編集していたが、Swift4にあげてから枠線の色だけうまく反映されなくなった。

該当のStoryboardを見ると画像の通り。 `layer.borderUIColor` が反映されていない模様。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/122365/9e155f0c-e3ea-3783-a6aa-6e2ca386dbcd.png)

このプロパティは自分で以下のように実装していた。

```swift
import Foundation

extension CALayer {
    var borderUIColor: UIColor {
        get {
            return UIColor(cgColor: self.borderColor!)
        } set {
            self.borderColor = newValue.cgColor
        }
    }
}
```

これがSwift4から動かなくなっていた。Swift4になってからObjective-Cとの互換性が変わって `User Defined Runtime Attributes` が書き方によってはうまく読み込まれていなかったみたい。

## 解決方法

`@objc dynamic` をつけてあげる。

```swift
import Foundation

extension CALayer {
    @objc dynamic var borderUIColor: UIColor {
        get {
            return UIColor(cgColor: self.borderColor!)
        } set {
            self.borderColor = newValue.cgColor
        }
    }
}
```

とすればちゃんと動く。
シェルスクリプトで空の関数やif文を書いた際に表示されるエラーの回避方法

# はじめに
シェルスクリプトで空の関数やif文を書いた際に表示されるエラーの回避方法について。

# エラーと実装例

例えば、他の箇所の動作確認をしたい場合などに、一時的にシェルスクリプト内の関数やif文を空にしようとして、何も考えずに全部コメントアウトしてシェルを叩くと、以下のようなエラーが表示されるはずです。

```shell-session:エラーメッセージ例
./xxx.sh: 行 xx: 予期しないトークン `}' 周辺に構文エラーがあります
./xxx.sh: 行 xx: `}'
```

英語だとこんな感じ。

```shell-session:エラーメッセージ例（英語）
./xxx.sh: line xx: syntax error near unexpected token `}'
./xxx.sh: line xx: `}'
```

これを回避するには適当なecho文でも入れておけばいいのでしょうが、それすらめんどくさい（或いは元々のロジック自体がechoコマンドの出力に反応しちゃうような場合）という人にはヌルコマンド:（コロン）を入れる方法が一番シンプルだと思います。

```shell-session:修正例
function xxx() {
    # コメントアウト行1
    # コメントアウト行2
    :
}
```

# おわりに
ヌルコマンドはこういう事例以外にも色々活用するケースがあるので、覚えておくと色々便利だと思います。Qiitaでも「ヌルコマンド」で検索すると色々出てくるはずです。あと、レガシーなコードだと割と見かけるのですが、一時的な検証以外で空の関数やif文をコメントもなしに残したままにしておくのは後々手を入れる人間が頭を抱えるので、シェルじゃなくても今すぐやめましょう（血涙
イメージマップ（クリッカブルマップ）のリンク部分のラインを消す

イメージマップを使って商品ごとのリンクを貼っている店舗で、Chromeブラウザで閲覧した際に青い線が表示されることがあります。この青い線は、リンクがフォーカスされたときに表示されるデフォルトのスタイルです。これが気になるという要望を受けたので対応方法を記録しておきます。

## 解決方法
CSSでarea要素に対して、borderとoutlineをnoneに設定することで、青い線を消すことができます。以下のコードを参考にしてください。
```css:CSS
area {
  border: none;
  outline: none;
}
```
これにより、Chromeで閲覧した際の青い線が表示されなくなります。

## 具体的な使用例
以下に、具体的なHTMLとCSSの使用例を示します。イメージマップを使って特定の領域にリンクを設定し、そのリンクに青い線が表示されないようにしています。
```html:HTML
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>イメージマップの青い線を消す</title>
  <style>
    area {
      border: none;
      outline: none;
    }
  </style>
</head>
<body>
  <img src="your-image.jpg" usemap="#image-map" alt="Sample Image">
  <map name="image-map">
    <area shape="rect" coords="34,44,270,350" alt="Example" href="https://example.com">
  </map>
</body>
</html>
```
## 補足情報
最新のブラウザでは、outlineプロパティだけで対応できる場合もあります。また、アクセシビリティの観点から、フォーカスリングを完全に削除することは推奨されていません。
```css:CSS
area {
  border: none;
  outline: none;
  outline: 2px solid transparent; /* フォーカスリングを透明にする */
}
```
このようにすることで、フォーカスリングの存在を保ちながら、視覚的に見えなくすることはできます。
【Vertica】DDL抽出方法

## 概要
現状のVerticaの環境に適応されているDDLがわからなくなってしまったが、Verticaから直接DDLを抽出する方法があったのでメモ。

## コマンド

```
$ vsql -U {ユーザ名} (-w {パスワード}) -h {ホスト名(IP等)} -c "select export_tables('','{対象のデータベース名}');"  | sed -e '1,2d' | grep -v " row" > {任意のディレクトリ}/{任意のファイル名}.sql
```
※(-w {パスワード})は任意です。history等に残るのでコマンドで指定しない方が良いと思いますが。<br>指定していない場合は、パスワードを聞かれるので入力すればOKです

### 解説

- `export_tables`: 定義をエクスポートする関数
    - `('{出力先}','{対象のデータベース名}')`: 指定したデータベースのテーブルのDDLを指定した出力先へ抽出する。
        - データベース名を指定しない場合は、`-U`で指定したユーザがアクセス権をもつ全定義をエクスポートします。
        - データベースの指定はカンマ区切りで複数行うことも可能です。`('','{対象のデータベース名_1},{対象のデータベース名_2}・・・')`
        - 出力先を指定しない場合は標準出力される(指定できるのはスーパーユーザのみ)
            - <font color="red">※今回は標準出力されたものをDDLとして抽出する為指定していない</font>
    - export_tables関数について詳しくは[こちら](http://vertica-tech.ashisuto.co.jp/ddl_export/)をご覧ください。
- sedコマンド
    - `-e`: 指定したスクリプト（条件式）で変換処理を行う
        - <font color="red">※オプションはなくても大丈夫でした。</font>
    - `'1,2d'`: 1行目と2行目を削除する
        - 無駄な1~2行目を削除しています。別に削除しなくても良いですが、下記のようにファイルサイズが変わるほど邪魔なので、ここで消しておきましょう
            
            ```
381K  sample_processed_data.sql
            1.2M  sample_raw_data.sql
            ```
- grepコマンド
    - `-v`: マッチしない行を検索結果として表示する
    - `" row"`: 最終行の`(1 row)`みたいな無駄な行を削除している

### 参考記事
[Verticaで既存環境のテーブルのDDLとデータを一括で抽出する方法](http://vertica-tech.ashisuto.co.jp/export-all-data/)
※若干のオプションの指定ミスがありました
XMLリソースファイルからHashMapを生成する


```xml:res/xml/monsters.xml
<?xml version="1.0" encoding="utf-8"?>
<map linked="true">
    <entry key="4">ゲリョス</entry>
    <entry key="1">アイルー</entry>
    <entry key="5">リオレイア</entry>
    <entry key="2">イャンクック</entry>
    <entry key="3">ドスジャギィ</entry>
    <entry key="6">リオレウス</entry>
</map>
```

```java:ResourceUtils
public class ResourceUtils {
    private static final String LOG_TAG = "ResourceUtils";

    public static Map<String, String> getHashMapSS(Context context, int resourceId) {
        Map<String, String> map = null;
        String key = null;
        String value = null;

        try {
            XmlResourceParser parser = context.getResources().getXml(resourceId);
            int eventType = parser.getEventType();

            while (eventType != XmlPullParser.END_DOCUMENT) {
                if (eventType == XmlPullParser.START_DOCUMENT) {
                    Log.d(LOG_TAG, "Start document");
                } else if (eventType == XmlPullParser.START_TAG) {
                    if (parser.getName().equals("map")) {
                        boolean isLinked = parser.getAttributeBooleanValue(null, "linked", false);
                        map = isLinked ? new LinkedHashMap<String, String>() : new HashMap<String, String>();
                    } else if (parser.getName().equals("entry")) {
                        key = parser.getAttributeValue(null, "key");
                        if (key == null) {
                            parser.close();
                            return null;
                        }
                    }
                } else if (eventType == XmlPullParser.END_TAG) {
                    if (parser.getName().equals("entry")) {
                        Log.d(LOG_TAG, "Put " + key + ":[" + value + "]");
                        map.put(key, value);
                        key = null;
                        value = null;
                    }
                } else if (eventType == XmlPullParser.TEXT) {
                    if (key != null) {
                        value = parser.getText();
                    }
                }
                eventType = parser.next();
            }
            Log.d(LOG_TAG, "End document");
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        return map;
    }
}
```

```java:usage
LinkedHashMap<String, String> monsters = (LinkedHashMap<String, String>) ResourceUtils.getHashMapSS(context, R.xml.monsters);
```
StackExchange.Redisで閲覧履歴を実装

開発メモ

StackExchange.Redisの使い方は下記参照
https://github.com/StackExchange/StackExchange.Redis

#登録
```C#
        //RedisのDBを選択
        IDatabase db = RedisRepository.SelectCache(0);

        //キーを生成
        var key = "hoge";

        // スコア算出の為、Unixtimeを取得
        var unixSeconds = DateTimeOffset.Now.ToUnixTimeSeconds();
        // 経過秒数をスコアとして保存
        var score = (double)unixSeconds;

        //閲覧履歴の情報をソート済みセット型で登録
        db.SortedSetAdd(key, "りんご", score);

        //保持期間を設定する場合は下記（例：30日）
        db.KeyExpire(key, new TimeSpan(30, 0, 0, 0));

        //最大件数を設定する場合は下記
        var current = db.SortedSetRangeByScore(key);
        var maxCnt = 10;
        if (current.Count() > maxCnt)
        {
            //最下位のデータを削除
            db.SortedSetRemoveRangeByRank(key,0,0);
        }
```

#取得
```C#
        //最新の閲覧順（スコアが高い順）に取得
        var list = db.SortedSetRangeByScore(key, order: Order.Descending);
```
SerializableとserialVersionUIDについて

# Serializable
* Javaのインタフェース
* シリアライズできることを宣言できる
* メソッドやフィールドの定義が１つもない（＝マーカインタフェース）  
宣言をしているだけで機能が追加されるわけでも何でもない

# SerialVersionUID
* シリアライズを宣言したクラスのバージョンのようなもの
* IDが同じということは構造が同じであることを保証する
* 構造が変わった時には変更するべきもの

# `@SuppressWarnings("serial")`
* 構造の保証をするためには、SerialVersionUIDのバージョンを適切に運用する必要があるが、そのコストが見合わない場合には下記のアノテーションをつけて回避する  
* `implements Serializable`だけしていると下記の警告がでる  

警告がでるサンプル

```java:Person.java
package sample;

import java.io.Serializable;

public class Person implements Serializable {
	public String name;

	public SerializablePerson(String name) {
		this.name = name;
	}
}
```

オプション（全ての警告を出すため）をつけてコンパイルすると

`javac -Xlint SerializablePerson.java`

警告がでる
（Eclipse上では設定によっては表示されない（環境設定->Java->コンパイラー->エラー/警告））

```text:日本語
Serializable.java:5: 警告: [serial] 直列化可能なクラスSerializableには、serialVersionUIDが定義されていません
```
```text:英語（たぶん）
The serializable class Mutter does not declare a static final serialVersionUID field of type long
```

アノテーションをつけて実行すると出ません。

```java:Person.java
package sample;

import java.io.Serializable;

@SuppressWarnings("serial")
public class Person implements Serializable {
	public String name;

	public SerializablePerson(String name) {
		this.name = name;
	}
}
```

# 参考
[難解なSerializableという仕様について俺が知っていること、というか俺の理解Add Star](http://d.hatena.ne.jp/daisuke-m/20100414/1271228333)
継承することの責任という話がとても為になった
Javaのアノテーションの名前がかぶったときの挙動

Javaを書くようになってアノテーションを使うようになりました。

ふと疑問に思ったのが、作ったアノテーションの名前が他のライブラリとかぶってしまったらどうなるの？ということです。

クラスの場合はパッケージ名を付けて明示的に示すことでクラスに同じ名前が使えますが、アノテーションにパッケージ名がつくというのがちょっと想像ができなかったので、簡単なアノテーションを作ってみました。

package名分けてさえいれば同名のクラスは作れるので作れるはずなのでaパッケージとbパッケージにそれぞれAアノテーションを作成しました。

```
package a;

public @interface A {
}
```

```
package b;

public @interface A {
}
```

何も処理がないので凄くシンプルですね。

では使ってみましょう！intelliJに身を任せてコーディングした結果下のようになりました

```
import a.A;

public class Main {
    @A //こいつはimport宣言されたAアノテーション
    // @a.A //↑と一緒じゃん！って怒られちゃうのでコメントアウトしてますが、この書き方も当然OK
    @b.A
    public static void main(String[] args){
    }
}

```

パッケージ名がそのまま入るのですね。

# まとめ
　ひょっとしたらJavaエンジニア的には有名な話だったりするかもですがアノテーション名前かぶってもクラスみたいに使い分けできるんですね。
そしてアノテーションにパッケージ名が付いてるとなんかちょっと気持ち悪いというか見慣れない感が合って慣れるまでは大変そう。
ライブラリ同士でアノテーションの名前がかぶっても問題が無いことがわかって取り敢えず安心しました。
PythonでフォルダやファイルをZIP化する方法

# はじめに
Pythonを使って、ZIP化する方法を載せておきます。
ファイルのZIP化はzipfileライブラリーでできますが、フォルダごとZIP化というのが調べた限り無いようです。

# ソースコード
```python:zip.py
import os
import zipfile

def get_file_path(file_path):
    """
    ファイルパスから指定以下のファイルの一覧を取得する
    :param file_path:ファイルパス
    :return: generator
    """
    if os.path.isfile(file_path):
        yield file_path
    else:
        for (base_dir, _ , file_name_list) in os.walk(file_path):
            for file_name in file_name_list:
                path = os.path.join(base_dir, file_name)
                path = path.replace(os.sep, '/')
                yield path


def zipping(file_path, save_dir=""):
    """
    ファイル及びフォルダごとZIP化関数
    :param file_path: 圧縮対象のファイルおよびディレクトリ
    :param save_dir: 保存先（デフォルトは圧縮対象と同じ階層）
    :return:
    """
    if file_path[-1]==os.sep or file_path[-1]=="/" :
        file_path = file_path[:-1]

    if not os.path.isdir(file_path) and not os.path.isfile(file_path):
        print("Not Found : {}".format(file_path))
        raise FileNotFoundError

    if os.path.isdir(save_dir):
        save_dir = os.path.join(save_dir, os.path.basename(file_path))
    else:
        save_dir = file_path

    zip_file_name = "{}.zip".format(save_dir)

    print('zip file : {}'.format(zip_file_name))
    with zipfile.ZipFile(zip_file_name, 'w', zipfile.ZIP_DEFLATED) as z:
        if os.path.isfile(file_path):
            print(">>zipping....   {}".format(file_path))
            file_name = os.path.basename(file_path)
            z.write(file_path, file_name)
        else:
            for file_name in get_file_path(file_path):
                head, tail = file_name.split(os.path.join(file_path,'').replace(os.sep,'/'))
                print(">>zipping....   {}".format(file_name))
                z.write(file_name, tail)

    return zip_file_name

```

# 使い方
```python:main.py
from zip import zipping

if __name__ == '__main__':
    file_path = "/sample/sample.jpg"
    file = zipping(file_path, "/tmp")
```
Google Analytics検討


# 定義

> GAとはデータを収集したり、設定したり、分析したりするツールです。

# WHY?

> どうして`GA`を使うことにしますか。

+ ユーザの使う習慣を見たい
+ ページを訪問してした人数を知りたい
+ ページのロードタイムを見たい
+ …

→ 収集したデータから総計したり、提案したりすることができるようにします。したがって、サービスの品質を上げます。

# GAの構築（Concept）

![ga](https://lh3.googleusercontent.com/3CPnVsUMt13tPhbueYnjSJQ-7DTAOT4cREjDbPAxiT-QlqqUTiGEMqJiqdSN7gJdMjckPme5NcOMLv6ZctS6QENlRvju0Z_J=s888)

> https://developers.google.com/analytics/devguides/platform/

基本的は4つに分けます。「収集」、「設定」、「処理」、「レポート」

# データの収集

> 一番大事なステップです。

このステップで、全て監視したい情報をデータ化して`GA`に送ることです。
端末によって`SDK`を使ってデータを収集することは一番簡単でオススメです。

+ Web　→　[analytics.js](https://developers.google.com/analytics/devguides/collection/analyticsjs/) [gtag.js](https://developers.google.com/analytics/devguides/collection/gtagjs/)
+ IOS　→　[IOS SDK](https://developers.google.com/analytics/devguides/collection/firebase/ios/)
+ ANDROID　→　[ANDROID SDK](https://developers.google.com/analytics/devguides/collection/firebase/android/)
+ その他　→ [Protocol](https://developers.google.com/analytics/devguides/collection/protocol/v1/)（普通のHTTPコール）


##　どんなものを監視できますか。

+ ユーザーがサイトに滞在した合計時間
+ 各ページでのユーザーの滞在時間および訪問したページの順番
+ クリックされた内部リンク（次のページビューの URL に基づく）
+ ユーザーの地域
+ 使用されているブラウザとオペレーティング システム
+ 参照元サイト
+ など

## Analytics.js

#### Trackerオブジェックトを作成

```
ga('create', 'UA-XXXXX-Y', 'auto');
```

`Tracker`オブジェックト作成際に、トラッカーID（`UA-XXXXX-Y`）やコッキードメイン（`auto`にはオススメです）指定することが必須です。

他のオプシオン：
+ `name`: トラッカー名。設定させない場合：`t0`にします。
+ `fields`:　[https://developers.google.com/analytics/devguides/collection/analyticsjs/field-reference](https://developers.google.com/analytics/devguides/collection/analyticsjs/field-reference)


#### データを`GA`まで送信する

データを送信するときに`Hit`（ヒット）と呼ばれています。ヒットごとに対してタイプが必要となります。

ヒットタイプ：
+ pageView: [doc](https://developers.google.com/analytics/devguides/collection/analyticsjs/pages)
+ screenView: [doc](https://developers.google.com/analytics/devguides/collection/analyticsjs/screens)
+ event: [doc](https://developers.google.com/analytics/devguides/collection/analyticsjs/events)
+ transaction: 
+ item: 
+ social: [doc](https://developers.google.com/analytics/devguides/collection/analyticsjs/social-interactions)
+ exception: [doc](https://developers.google.com/analytics/devguides/collection/analyticsjs/exceptions)
+ timing: [doc](https://developers.google.com/analytics/devguides/collection/analyticsjs/user-timings)

構文：
```
ga('[trackerName.]send', [hitType], [...fields], [fieldsObject]);
```

タイプによる必要なパラメーターも変わります。

#### `GA`のプラグインは何？

`GA`にデータ送信際に、プラグインを使うこともできます。プラグインは、analytics.js の機能を強化して、ユーザーの接点の測定をサポートするスクリプトです。
プラグインは通常、[e コマース](https://developers.google.com/analytics/devguides/collection/analyticsjs/enhanced-ecommerce)や[クロスドメイン トラッキング](https://developers.google.com/analytics/devguides/collection/analyticsjs/cross-domain)など、すべての Google アナリティクス ユーザーが必要とするとは限らない一連の機能を対象としています。そのため、デフォルトでは analytics.js にプラグインは含まれていません。
パラメタライズドテストと普通のテストを抱き合わせにしたクラスでPowerMockを使いたい

## TL;DR

- 外部クラスには`@Runwith(Enclosed.class)`のみ
- 内部クラスには下記をつけてやる
    - `@RunWith(PowerMockRunner.class)`
    - `@PrepareForTest({テスト対象クラス})`
    - `@PowerMockRunnerDelegate(Parameterized.class)` 
        - `@PowerMockRunnerDelegate(JUnit4.class)`は不要 

## やりたかったこと

- staticイニシャライザ実行される処理のテストが書きたかった
- テスト内にパラメタライズドテストと１回だけ流したいテストが混在していた
    - とは言え一つのクラスに対するテストコードが複数箇所に分散するのは気持ち悪い

## 調べてみた

- staticに割り込むテストはMockito + PowerMockで出来る
- パラメタライズドテストは`@RunWith(Theories.class)`か`@RunWith(Parameterized.class)`を使えば出来る
    - `Parameterized`だとパラメータ毎にアサーションしてくれたのでこっちを採用
- `@RunWith(Enclosed.class)`を使えば一つのクラスに複数のテストクラスをまとめられる

## ライブラリ構成

- junit: 4.12
- mockito-core: 1.10.19
- powermock-core: 1.7.3
- powermock-module-junit4: 1.7.3
- powermock-api-mockito: 1.7.3

## 検証コード

### テスト対象
```java
public class StaticClass {
    public static String MESSAGE;

    static {
        int i = new Random().nextInt();
        if (0 <= i && i <= 10) {
            MESSAGE = "Parameter is inside of range, 0 to 10.";
        } else {
            MESSAGE = "Nmm...?";
            method();
        }
    }

    private static void method() {
        // to do any action
    }
}
```

### テスト
```java
@RunWith(Enclosed.class)
public class StaticClassTest {

    @RunWith(PowerMockRunner.class)
    @PrepareForTest({StaticClass.class})
    @PowerMockRunnerDelegate(Parameterized.class)
    public static class ParameterizeTest {
        @Parameterized.Parameter
        public Integer parameter;

        @Parameterized.Parameters(name = "parameter is {0}")
        public static Object[][] parameterSupplier() {
            return new Object[][]{
                    {0},
                    {1},
                    {2},
                    {3},
                    {4},
                    {5},
                    {6},
                    {7},
                    {8},
                    {9},
                    {10}
            };
        }


        @Test
        public void test() throws Exception {
            // given
            Random random = PowerMockito.mock(Random.class);
            PowerMockito.whenNew(Random.class).withNoArguments().thenReturn(random);
            PowerMockito.when(random.nextInt()).thenReturn(parameter);

            // expect
            assertEquals("Parameter is inside of range, 0 to 10.",
                    Whitebox.getInternalState(StaticClass.class, "MESSAGE"));
        }
    }

    @RunWith(PowerMockRunner.class)
    @PrepareForTest({StaticClass.class})
    public static class NormalTest {
        @Test
        public void test() throws Exception {
            // given
            Random random = PowerMockito.mock(Random.class);
            PowerMockito.whenNew(Random.class).withNoArguments().thenReturn(random);
            PowerMockito.when(random.nextInt()).thenReturn(99);

            // expect
            assertEquals("Nmm...?",
                    Whitebox.getInternalState(StaticClass.class, "MESSAGE"));
        }
    }
}
```

## 参考
http://tomoyamkung.net/2013/08/28/java-junit4-enclosed/
https://stackoverflow.com/questions/28027445/powermock-access-private-members
GooglePlay定期購読状態取得時に410となる件

GooglePlay課金における[定期購読状態取得API](https://developers.google.com/android-publisher/api-ref/purchases/subscriptions/get#request)にて以下のレスポンスが返ることがある。

```json
{
  "code" : 410,
  "errors" : [ {
    "domain" : "androidpublisher",
    "message" : "The purchase token is no longer valid.",
    "reason" : "purchaseTokenNoLongerValid"
  } ],
  "message" : "The purchase token is no longer valid."
}
```
Android Publisher APIのライブラリ(google-api-client1.23.0,google-api-services-androidpublisherv2-rev46-1.23.0)を使っているが、これを使うとGoogleJsonResponseExceptionがスローされる。
また公式ドキュメントにもこのエラーについては記述がなかった。

## ユーザの状態

課金状態をコンソールで確認してみたところ、有効期限がきれたあともしばらく課金は「有効」となっている。
数日(日数はムラあり)後見ると「無効」に更新されていた。(これまで確認できたユーザすべて)
またこの状態のユーザについてGoogleに問い合わせてみたところ、Googleアカウントを削除していたということだった。

## 対処

GoogleJsonResponseExceptionでcatchし、e.getStatusCode == 410で判定し有料解除するようにした。
なにかいい方法があれば是非教えてください :bow:
Mapの使い方


Mapに突っ込んだ順に値を取り出したいならLinkedHashMap
Keyの順番に取り出したいならTreeMap
特にこだわりがないならHashMap

覚えました。

```java:MapTest
import java.util.Map;
import java.util.LinkedHashMap;
import java.util.TreeMap;
import java.util.HashMap;

public class Main {
    public static void main(String[] args) throws Exception {
        new MapTester(new LinkedHashMap<String, String>()).test();
        new MapTester(new HashMap<String, String>()).test();
        new MapTester(new TreeMap<String, String>()).test();
    }
}

class MapTester {
    private Map<String, String> map;

    public MapTester(Map<String, String> map) {
        this.map = map;
    }
    
    public void test() {
        this.putValues();
        this.dump();
    }
    
    private void putValues() {
        this.map.put("4", "ゲリョス");
        this.map.put("1", "アイルー");
        this.map.put("5", "リオレイア");
        this.map.put("2", "イャンクック");
        this.map.put("3", "ドスジャギィ");
        this.map.put("6", "リオレウス");
    }
    
    private void dump() {
        System.out.println(this.map.getClass().getName() + "の中身");
        for (Map.Entry<String, String> entry : this.map.entrySet()) {
            System.out.println(entry.getKey() + ":[" + entry.getValue() + "]");
        }
        System.out.println("");
    }
}
```

```text:実行結果
java.util.LinkedHashMapの中身
4:[ゲリョス]
1:[アイルー]
5:[リオレイア]
2:[イャンクック]
3:[ドスジャギィ]
6:[リオレウス]

java.util.HashMapの中身
1:[アイルー]
2:[イャンクック]
3:[ドスジャギィ]
4:[ゲリョス]
5:[リオレイア]
6:[リオレウス]

java.util.TreeMapの中身
1:[アイルー]
2:[イャンクック]
3:[ドスジャギィ]
4:[ゲリョス]
5:[リオレイア]
6:[リオレウス]
```
Pythonista3でちょっと休憩してニュースを聞く

#はじめに
[iOS上で動作する革命的ものづくり環境「Pythonista 3」の魅力をとくと語る](http://hitoriblog.com/?p=42145)
でPythonista3が紹介されていて、おもしろそうなので私もインストールしました。
今回は学習のために簡単なスクリプトを作りました。
Pythonistaでfeedparserが使えるので、
[【データサイエンスの基礎】pythonでRSSからデータ収集](https://qiita.com/shunsuke227ono/items/da52a290f78924c1f485)
のコードに無駄にiOSっぽい処理を追加しました。
#コード

```py:news_time.py
import feedparser
import speech
import notification
import re
import ui

#ボタンをタップした時の動作
def button_tapped(sender):
	sender.title = 'Stopped'
	speech.stop()

#UIの設定
view = ui.View()                                      
view.name = 'NewsTime'                                    
view.background_color = 'white'                       
button = ui.Button(title='STOP NEWS')
#ボタンを真ん中に配置
button.center = (view.width * 0.5, view.height * 0.5)
button.flex = 'LRTB'                                  
button.action = button_tapped                         
view.add_subview(button)                              
view.present('sheet')

#RSSをParse
RSS_URL = "https://headlines.yahoo.co.jp/rss/tokyomx-dom.xml"
news_dic = feedparser.parse(RSS_URL)

#speechで読み上げる
speech.say('ニュースでも聞いてって')
for entry in news_dic.entries:
	title = re.sub('（.+）','', entry.title)
	speech.say(title)

#通知の設定:7200秒後に通知をスケジュールし、このスクリプトを呼ぶ
ret = notification.schedule("ちょっと休憩してニュースでも聞いたら", 7200, 'default','pythonista3://speech/news_time?action=run')
```
流れは次のようになっています。
(1)UIの作成。かなり適当で音声再生を止めるボタンのみ配置しています。
(2)ニュースの取得。RSSから見出しを取得しています。
(3)読み上げ。`speech.say`で読み上げてくれます。
(4)通知の設定。`notification`で7200秒(2時間)後に通知が来るようにしています。
また、`pythonista3://speech/news_time?action=run`で通知を開いた際に、
再度このスクリプトを実行するようにアクションを設定しています。
#テスト
スクリプトを実行します。初回はとりあえず、聞いておきましょう。
そして2時間後、、、
<img width="375" alt="DE40436C-AEE3-48CF-8551-8FF58CD50845.png" src="https://qiita-image-store.s3.amazonaws.com/0/140055/49342713-49b6-2c7f-0873-3193881bfaa7.png">

通知が来た！そろそろ休憩です。タップ！

<img width="375" alt="E2E999FD-59AA-4F12-B611-E71BA4A3DF67.jpeg" src="https://qiita-image-store.s3.amazonaws.com/0/140055/bc4504ba-27da-22cf-61c7-64044073ac7e.jpeg">

__ちなみにこの画面で音声が流れています。__
真ん中の「STOP NEWS」をタップすると音声が止まります。

#最後に
無限ループになるので、もういいやってなったら通知を開かずに消してください。
このスクリプトはあまり役に立ちませんが、面白いことができそうだと思いました。

#参考サイト
[ひとりぶろぐ](http://hitoriblog.com/?p=42145)
[【データサイエンスの基礎】pythonでRSSからデータ収集](https://qiita.com/shunsuke227ono/items/da52a290f78924c1f485)
[Pythonista Modules](http://omz-software.com/pythonista/docs/ios/)
【Visual Studio】Visual Studio 2017 で使用できるオススメの拡張機能の記事16選

<div align="center"><img src="https://cdn-ak2.f.st-hatena.com/images/fotolife/b/baba_s/20170924/20170924211343.png"></div>

# 備考

この投稿は自分のブログの記事の転載になります
http://baba-s.hatenablog.com/entry/2017/10/04/100000

# はじめに

Unity 2017 から Visual Studio 2017 が正式にサポートされました
今回は Visual Studio 2017 で使用できるオススメの拡張機能を<span style="color: #ff0000">16個</span>まとめました

すべて無料で、かつ Unity におけるゲーム開発でも使用できるため
興味がある拡張機能はぜひ使ってみて頂ければと思います

# 拡張機能

1. [Ctrl + クリックで変数や関数の定義にジャンプすることができる「Ctrl+Click Go To Definition」](http://baba-s.hatenablog.com/entry/2017/10/02/113000_14)
1. [キャレットの位置に存在する単語と等しいすべてのテキストを強調表示できる「Match Margin」](http://baba-s.hatenablog.com/entry/2017/10/02/113000_9)
1. [Ctrl + Alt + \] で代入文を整列できる「Align Assignments」](http://baba-s.hatenablog.com/entry/2017/10/02/113000_4)
1. [文字や数値を含まない行の縦幅を 25% 縮小できる「Shrink Empty Lines」](http://baba-s.hatenablog.com/entry/2017/10/02/113000_6)
1. [コードエディタの任意の位置に垂直線を表示できる「Editor Guidelines」](http://baba-s.hatenablog.com/entry/2017/10/02/113000_3)
1. [メインメニュー、タイトルバー、タブを非表示にできる「Hide Main Menu, Title Bar, and Tabs」](http://baba-s.hatenablog.com/entry/2017/10/02/113000_2)
1. [ウィンドウヘッダーをダブルクリックして最大化できる「Double-Click Maximize」](http://baba-s.hatenablog.com/entry/2017/10/02/113000_8)
1. [タブとスペースの混在を自動的に修正できる「Fix Mixed Tabs」](http://baba-s.hatenablog.com/entry/2017/10/02/113000_10)
1. [エラーや警告を含むファイルを強調表示できる「Solution Error Visualizer」](http://baba-s.hatenablog.com/entry/2017/10/02/113000_5)
1. [デバッグ出力ウィンドウにタイムスタンプを表示できる「Time Stamp Margin」](http://baba-s.hatenablog.com/entry/2017/10/02/113000_1)
1. [マウスの中央ボタンを押しながらスクロールできる「Middle Click Scroll」](http://baba-s.hatenablog.com/entry/2017/10/02/113000_12)
1. [Alt + F1 でヘルプをインライン表示できる「Peek Help」](http://baba-s.hatenablog.com/entry/2017/10/02/113000_13)
1. [クイック起動ツールにコマンドを追加する「Quick Launch Tasks」](http://baba-s.hatenablog.com/entry/2017/10/02/113000_7)
1. [ドキュメントタブの動作を変更できる「Custom Document Well」](http://baba-s.hatenablog.com/entry/2017/10/02/113000_11)
1. [選択したテキストを HTML 形式でクリップボードにコピーできる「Copy As Html」](http://baba-s.hatenablog.com/entry/2017/10/02/113000_15)
1. [Visual Studio IDE の便利な機能のセット「Power Commands for Visual Studio」](http://baba-s.hatenablog.com/entry/2017/10/02/113000)

# 関連記事

http://baba-s.hatenablog.com/entry/2017/10/03/100000
http://baba-s.hatenablog.com/entry/2016/06/29/100000
LaravelのEloquentでJSON型の列を取得する

LaravelのEloquentで列の型がJSON型の列を取得するときにちょっとハマったので調査しました。

```php
$post = Post::find(1);
echo $post->json_column->col1;  // エラー
echo $post->json_column['col1'] // エラーにならない
```

## TL;DR

結論からいうとJSON型の列を取得する場合は
モデルクラスの`$casts`にjsonであることを明示しておき、
`$model->json_column['property']`というように連想配列でアクセスすれば取得できます。

## 環境

|名前|バージョン|
|---| -------- |
|PHP | 7.1.6    |
|Laravel| 5.5.14 |

## 配列でのアクセスになるのはなぜか

モデルは以下のとおり。

```Models/Post.php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model as Eloquent;

class Post extends Eloquent
{
    use \Illuminate\Database\Eloquent\SoftDeletes;

    protected $casts = [
        'json_column' => 'json',  // ★これ
    ];

    protected $fillable = [
        'json_column',
    ];
}
```

`$casts`をjsonにしているのでjson_decodeされた結果が返ってくると思ったので
プロパティアクセス(`$post->json_column->col1`)でいけると思ったのですがエラーになります。
配列でアクセス(`$post->json_column['col1']`)するとエラーになりません。

ひょっとして`json_decode($string, true)`で連想配列にしてjsonをパースしてるのではと思ってソースを見てみました。

```Illuminate\Database\Eloquent\Concerns\HasAttributes.php
    /**
     * Cast an attribute to a native PHP type.
     *
     * @param  string  $key
     * @param  mixed  $value
     * @return mixed
     */
    protected function castAttribute($key, $value)
    {
        if (is_null($value)) {
            return $value;
        }

        switch ($this->getCastType($key)) {
            case 'int':
            case 'integer':
                return (int) $value;
            case 'real':
            case 'float':
            case 'double':
                return (float) $value;
            case 'string':
                return (string) $value;
            case 'bool':
            case 'boolean':
                return (bool) $value;
            case 'object':
                return $this->fromJson($value, true);
            case 'array':
            case 'json':
                return $this->fromJson($value);    // ★ここ
            case 'collection':
                return new BaseCollection($this->fromJson($value));
            case 'date':
                return $this->asDate($value);
            case 'datetime':
                return $this->asDateTime($value);
            case 'timestamp':
                return $this->asTimestamp($value);
            default:
                return $value;
        }
    }

    /**
     * Decode the given JSON back into an array or object.
     *
     * @param  string  $value
     * @param  bool  $asObject
     * @return mixed
     */
    public function fromJson($value, $asObject = false)
    {
        return json_decode($value, ! $asObject); // ★ここでjsonを連想配列にしている
    }
```

json_decodeの第２引数をtrue、つまりassocがtrueなので連想配列形式で返却されます。
モデルクラスのプロパティで`$casts`をjsonにしていた場合は連想配列でキャストされたものが返却されます。

## 参考

[PHP.net json_decode](http://php.net/manual/ja/function.json-decode.php)