OmniAICreator/Qiita-1.07M huggingface dataset:
Chrome 66でUnity WebGLビルドの音が鳴らなくなった問題とその対策

## 現象
Chrome 66で音声が鳴らなくなった。

## 原因
原因は、GoogleがChromeに導入したMEIという仕組みにあった。

## 対策
以下のような対策を行い、何らかのユーザーアクションがあった場合に音が鳴るようにする。

```csharp
using System.Runtime.InteropServices;

[DllImport("__Internal")]
public static extern void resumeAudioByNextUserAction();

resumeAudioByNextUserAction();
```

```js:webAudio.jslib
mergeInto(LibraryManager.library, {
  resumeAudioByNextUserAction: function() {
    var wakeupWebAudio = function() {
      if (WEBAudio && WEBAudio.audioContext && WEBAudio.audioContext.state === "suspended") {
        WEBAudio.audioContext.resume();
      }
      document.removeEventListener("click", wakeupWebAudio);
      document.removeEventListener("touchend", wakeupWebAudio);
      document.removeEventListener("keydown", wakeupWebAudio);
    };
    document.addEventListener("click", wakeupWebAudio);
    document.addEventListener("touchend", wakeupWebAudio);
    document.addEventListener("keydown", wakeupWebAudio);
  }
});
```

## MEIとは何か
**Media Engagement Index**と言う。
これは、サイトを閲覧した際に自動的に音声を流し始めるサイトに対して、独自のレーティングに従って音声をブロックするものだ。
音声を再生するためには、クリック等なんらかのユーザーのアクションが必要になる。
対象となるのは、`<audio>`や`<video>`、そしてWeb Audio API。

現在のレーティングは`chrome://media-engagement`から確認できる。
この値がある閾値を上回ると自動再生されなくなる。

## MEIの何が問題になったか
一見すると良いことに聞こえるこの仕組みだが、例え自分が意図して開始したゲームであっても、レーディングに基づいて音声がブロックされてしまう。
更に厄介なのは、ユーザーに依存していてユーザー毎にレーティングの状況が異なるという点だ。
Google曰く「最初から止めるのではなく、止まっていたら再生するように」という事なので、ユーザーによって音声の開始位置がズレることを考慮しなければならない。

## そして延期、しかし延期
この実装は説明不足のままChrome 66で実装された。
そしてブラウザ上で動くゲームサービスやオーディオサービス提供者の反感を買った。

これに対してGoogleは、多くの当該サービスで利用されているWeb Audio APIに対してはポリシーをはずす事を[発表した](https://bugs.chromium.org/p/chromium/issues/detail?id=840866#c103)。
それはChrome 66の次のバージョンですぐに適用された。
なお、`<audio>`や`<video>`についてはポリシーを適用したままだ。

また、これは当該サービスの提供者に対策する猶予を与えるためのもので、2018年10月にリリース予定のバージョン70で改めて適用される。

## 参考
- [グーグル、Chrome 66の動画自動再生ポリシーを一時的に変更--ゲーム開発者などの苦情受け - CNET Japan](https://japan.cnet.com/article/35119311/)
- [「ゲームの音が出なくなった」ことからChromeに追加されたばかりの「音声の自動再生を無効化する」機能が削除へ、5カ月後には再度実装される予定 - GIGAZINE](https://gigazine.net/news/20180517-chrome-66-sound-broken-delay/)
- [Autoplay Policy Changes | Web
      | Google Developers](https://developers.google.com/web/updates/2017/09/autoplay-policy-changes)
- [Auto-Play Policy Changes for macOS | WebKit](https://webkit.org/blog/7734/auto-play-policy-changes-for-macos/)
- [Unity Issue Tracker - Chrome66: Autoplaying audio is muted](https://issuetracker.unity3d.com/issues/chrome66-no-longer-playing-integrated-audio)
Greenletを試す


[developit/greenlet: 🦎 Move an async function into its own thread.](https://github.com/developit/greenlet)

Greenletは単純に言うと、WebWorkerをシンプルに扱えるようにしたライブラリ。

[Web Workers API - Web API インターフェイス | MDN](https://developer.mozilla.org/ja/docs/Web/API/Web_Workers_API)

```index.html
<script src="https://unpkg.com/greenlet@0.1.2/dist/greenlet.umd.js"></script>
<script>
const getName = greenlet(async username => {
  const url = `https://api.github.com/users/${username}`
  const res = await fetch(url)
  const profile = await res.json()
  return profile
})

getName('akameco').then(console.log).catch(console.error);
</script>
```

面倒なので、何も考えずparcelで

```
$ parcel index.html
```

DevtoolのConsoleタブで開くと結果が得られているのがわかると思う。
また、SourcesタブのNetworkを見ると、差し込まれたWorkerがわかる。

ちなみに実装的にgreenletおよびWorkerのコードにブレークポイントを置いても、greenletの実装的にデバッグするのは不可能。

どうなっているかというと、関数を文字列としてdata URIにするという実装をしている。
ここまで書くとわかるようにスコープ外の変数はもちろん使えない。(まあWebWorkerなので当たり前だけど)
table関数で集計して結合するときの危険性 [R]

#はじめに
まずこの記事はforループでついついゴリ押ししてしまう人に向けたものです。
apply関数を使ってデータにアクセスできる方にはあまり参考にならないと思います。

主な内容はtable関数について、集計値が0になる際に扱いを間違えたら非常にまずい事態になってしまうという話です。


#サンプルデータ
以下のような仮想データを作成しました。平日の朝食におけるデザートとでもしましょう。
これを曜日ごとに集計したい。

```R
> dessert
         Mon    Tue    Wed    Thu    Fri
week1 banana  apple orange banana  apple
week2  apple orange banana orange banana
week3  apple orange orange  apple  apple
week4 orange  apple  apple orange orange
```


#個別に集計して結合する
とりあえずtable関数を用いて集計してみましょう。

```R
> table(dessert$Mon)

 apple banana orange 
     2      1      1 
```

これを各曜日で行いrbindにより結合します。

```R
cross.Mon <- table(dessert$Mon)
cross.Tue <- table(dessert$Tue)
cross.Wed <- table(dessert$Wed)
cross.Thu <- table(dessert$Thu)
cross.Fri <- table(dessert$Fri)

cross1 <- rbind(cross.Mon, cross.Tue, cross.Wed, cross.Thu, cross.Fri)
```

以上の処理を行えばこのような集計表ができます。

```R
> cross1
          apple banana orange
cross.Mon     2      1      1
cross.Tue     2      2      2
cross.Wed     1      1      2
cross.Thu     1      1      2
cross.Fri     2      1      1
```
さて、１点おかしな場所があります。
２行２列目、火曜日にbananaは一度も観測されないはずが集計値が2になっていますね。
実際この方法で結合を行なった場合errorメッセージが出てきます。

```R
> cross1 <- rbind(cross.Mon, cross.Tue, cross.Wed, cross.Thu, cross.Fri)
 警告メッセージ: 
 rbind(cross.Mon, cross.Tue, cross.Wed, cross.Thu, cross.Fri) で: 
  number of columns of result is not a multiple of vector length (arg 2)
```
実際に火曜日の集計結果はこちら

```R
> cross.Tue

 apple orange 
     2      2 
```

このように真ん中のbananaだけすっぽ抜けとるわけです。
さて問題は次のケース、forループにより一気に集計した場合です。

#forループで集計して結合する
ちょっと集計する対象が多くて困ったときついforループ使ってしまいますよね。
forループを用いて先ほどの処理を繰り返し計算させた場合、エラーメッセージが出現せずに結合された結果が返ってきます。

```R
cross2 <- data.frame(apple=0, banana=0, orange=0)
for (i in 1:ncol(dessert) {
  cr <- table(dessert[, i])
  cross2 <- rbind(cross2, cr)
}
cross2 <- cross2[-1, ]
```

ちょっと汚いですが空っぽいデータフレームを作ってからforループで順次結合しております。結果はやはり先ほどのような結果が**エラーメッセージなしで**返ってくるんですね。

```R
> cross2
          apple banana orange
cross.Mon     2      1      1
cross.Tue     2      2      2
cross.Wed     1      1      2
cross.Thu     1      1      2
cross.Fri     2      1      1
```

#解決策
このデータ構造での解決策を私は見つけられておりません(すみません…)。
集計を行うための関数としては他にxtabs関数とかがありますが、少し異なるデータ構造にあれを用いれば回避はできます。

```R
> dessert2
   week dessert
1   Mon  banana
2   Tue   apple
3   Wed  orange
4   Thu  banana
5   Fri   apple
6   Mon   apple
7   Tue  orange
8   Wed  banana
9   Thu  orange
10  Fri  banana
11  Mon   apple
12  Tue  orange
13  Wed  orange
14  Thu   apple
15  Fri   apple
16  Mon  orange
17  Tue   apple
18  Wed   apple
19  Thu  orange
20  Fri  orange
```

これに対してxtabs()により

```R
> xtabs(~week+dessert, data=dessert2)
     dessert
week  apple banana orange
  Fri     2      1      1
  Mon     2      1      1
  Thu     1      1      2
  Tue     2      0      2
  Wed     1      1      2
```

ちょっと順番は崩れますが0がしっかり入力されてます。

#終わりに
脱forループして他の方法を使いましょう。そもそもRというソフトウェアはforループ自体が苦手みたいです。
また計算しやすいデータの構成を設計することも大事そうです。
皆さんもtable関数を使うときはご注意ください。

p.s. 
さっきのやつをapply族を用いて集計できるようになりたい。
dplyrもいいらしいですね…。学びたいことたくさんだ…。
URIの不透明性

#はじめに
技術書で学んだことはどんどんアウトプットすることが大事だと感じ始めたので、少しずつ小さい単位でやっていこうと思います。
今日はこちらの書籍について。
[Webを支える技術](https://www.amazon.co.jp/dp/4774142042?tag=googhydr-22&hvadid=262938977491&hvpos=1t1&hvnetw=g&hvrand=12168620957391825091&hvpone=&hvptwo=&hvqmt=e&hvdev=c&hvdvcmdl=&hvlocint=&hvlocphy=1009318&hvtargid=kwd-333749887651&ref=pd_sl_29ampwrlju_e)
こちらの本はweb関連の技術を歴史を振り返りながら、理解を深めていける、良い本だというレビューが気になって買ってみました。
特にREST APIに関しての記述が目立ちますね。

中でも今回はURIの設計方法の一つの考え方についてまとめてみたいと思います。
URIをどのように設定して、パスをどう切るかって結構適当な人って多いと思います。自分がそうなので
、これを機に学んでいきたいと思ってます。


#URIの不透明性
URIをどのように設計するかについての考え方の一つに不透明性というものがあるみたい。
「不透明」な「性質」というくらいであるから、不透明であれば不透明であるほど良いということだ。
これが初めに「？」ってなりました。明確ではない方が良いのである。普通逆だろっておもっちゃいますけどねぇ。
ひとまず読んでみると、まずはじめの考え方として、シンプルなURIは可読性が高いため、ユーザがURIの構造を推測しやすくなるということが言える。
例えば

```プレスリリース日本語版
http://examle.jp/2018/05/05/press.ja
```

```プレスリリース英語版
http://examle.jp/2018/05/05/press.en
```

このURIは末尾に文字コードを付けているため、フランス語のURIは言わずもがな想像がつくと思う。

しかし、URIが想像がついたからといって、そこにリソースが存在するとは限らない。
URI=パス+リソース名ではないのです。

なるほど、確かに。

逆に上記の等式が成り立ってしまうと、サーバーの実装が変更になった際にURLまで変更する羽目になる。
最悪、クライアント側が下手にリソースの構造が見えてしまうことによって、想像でリソースの構造を利用したロジックを実装してしまうことにもなりかねない。

確かに、これはクライアントがサーバーサイドの実装に依存することになり、MVC的な観点から見てもありえないと思われる。

[クールなURIは変わらない](https://www.kanzaki.com/docs/Style/URI)、だそうですので、少しでもURIが変更になる可能性は減らすべきです。

他にもURIに関していろいろとあるようなので、またまとめていきたいと思います。
Phoenixで選択項目の使用（Select Box / Radio Button）


`Phoenix` でよく使うので覚え書き。


## selectタグの場合

```form.html.eex
  <div class="form-group">
    <%= label f, :gender, class: "control-label" %>
    <%= select f, :gender_cd, ["男性": "1", "女性": "2", "その他": "0"], class: "control-label" %>
  </div>
```

## radio button タグの場合
``` form.html.eex
  <div class="form-group">
    <%= label f, :gender, class: "control-label" %>
    <%= radio_button f, :gender_cd, "1", checked: true, class: "control-label" %>男性
    <%= radio_button f, :gender_cd, "2", class: "control-label" %>女性
    <%= radio_button f, :gender_cd, "0", class: "control-label" %>その他
  </div>
```

※参考URL http://www.whoocus.com/blog/?p=2639
slackbotを作成してherokuを使って定期的なメッセージを送るまで

# herokuを使ってSlackで定期的なメッセージを表示させる

## Slackで定期的なメッセージを送る処理
Rubyで書きました。

```ruby:slack.rb
require 'slack-ruby-client'

#slackの認証
Slack.configure do |config|
  config.token = "トークンを入力してください"
end

#testタグにメッセージを送りつける
def post_msg(message)
  client = Slack::Web::Client.new
  client.chat_postMessage(
    channel: '#test',
    as_user: true,
    text: "#{message}"
  )
end

#時刻を表示する処理
def test_scheduler
  post_msg("#{Time.now}")
  exit
end

test_scheduler
```

単体実行前の準備として、slack上のtestタグのメンバーにbotを追加しておいてください。
そうじゃないとエラーで弾かれてしまいます。

ご参考：

[Slack Web API であそぼ](https://doruby.jp/users/whale/entries/Slack-Web-API-%E3%81%A7%E3%81%82%E3%81%9D%E3%81%BC)

[slack-ruby/slack-ruby-client](https://github.com/slack-ruby/slack-ruby-client/blob/master/examples/hi_web/hi.rb)

## herokuで自動実行するための準備
heroku schedulerでrakeで実行したかったのでRakefileとGemfileを用意します。
Gemfileがないとherokuでgemを落としてくれないどころか、以下のエラーが出るので注意。

[herokuへのpushが[ buildpack ]の問題でエラーになる。](https://teratail.com/questions/45874)

Gemfile作ったらそのついでにHigh Sierraでbundle installコケるケースにも遭遇。対策させてもらった記事もつけておきます。Cloud9使ってて久々にHigh Sierraでbundle installしたは。

[High Sierraにしたらbundle exec pod installできなくなったよ](https://qiita.com/grnboy_qiita/items/30c5f1a0fcec5149b63d)

```ruby:Rakefile
require './slack.rb'

desc "This task is called by the Heroku scheduler add-on"
task :slack_post do
  ruby ./slack.rb
end

```

```ruby:Gemfile
source 'https://rubygems.org'

gem 'rake'
gem 'slack-api'
gem 'slack-ruby-client'
```

## heroku schedulerに登録
herokuを使うための前準備はできている前提で書きます。
まだの方はユーザー登録とクレジットカード登録をしておきましょう。超過しない限り無料です。参考にさせていただいたサイトは次の通りです。

[Herokuでrakeファイルを定期実行する](https://qiita.com/ryuchan00/items/f412e692891b046e7c93)

herokuで適当なappを作って、Resourceタグからheroku schedulerを検索してアドオンを追加しましょう。
<img width="1297" alt="スクリーンショット 2018-05-21 0.04.53.png" src="https://qiita-image-store.s3.amazonaws.com/0/17918/79ad2f00-fe99-76f5-8300-17fb4d75cac1.png">

あとはrake skack_postを登録するだけです。1日に1回。1時間に1回。10分に1回実行できます。
<img width="799" alt="スクリーンショット 2018-05-21 0.08.44.png" src="https://qiita-image-store.s3.amazonaws.com/0/17918/722129e7-e1dc-d4c8-83bb-7482d9b63c2f.png">

詳細は触れていませんでしたが、あらかじめherokuに作ったappに対してソースコードはpushしておいてくださいね。


## 結果
こんな感じで１時間に一度時報が出ます。
<img width="375" alt="IMG_4357.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/17918/dd1454ae-67b7-60d0-0758-d7c90922818a.png">
Phoenixのselectタグ


Phoenixのselectタグの使用方法が整理できてなかったので、下記に覚え書き。


## コントローラ 
コントローラにて、`selectbox` に表示する値(teams)を取得し、パラメータとしてView/Templateへ渡す。 

```member_controller.ex
def new(conn, _params) do
  changeset = Portal.change_member(%Member{})
  # チームのリストを取得する
  teams = Portal.list_teams()
  # チームのリストをパラメータとして渡す  
  render(conn, "new.html", changeset: changeset, teams: teams)
end

def edit(conn, %{"id" => id}) do
  member = Portal.get_member!(id)
  # チームのリストを取得する
  teams = Portal.list_teams()
  changeset = Portal.change_member(member)

  # チームのリストをパラメータとして渡す  
  render(conn, "edit.html", member: member, changeset: changeset, teams: teams)
end
```

## テンプレート
特に記述に変更なし。

``` new.html.eex 
<h2>New Member</h2>

<%= render "form.html", Map.put(assigns, :action, member_path(@conn, :create)) %>
```

```edit.html.eex
<h2>Edit Member</h2>

<%= render "form.html", Map.put(assigns, :action, member_path(@conn, :update, @member)) %>
```

## フォームテンプレート
`Enum.map`によって展開する。

```form.html.eex
<div class="form-group">
  <%= label f, :teams, class: "control-label" %>
  
  <%= select f, :team_id, Enum.map(@teams, &{&1.team_name, &1.id}) ,  class: "control-label" %>
  <%= error_tag f, :team %>
</div>
```

参考までに、特にDBから取得する必要のない一覧の記述方法は下記。

```
<div class="form-group">
  <%= label f, :gender, class: "control-label" %>
  <%= select f, :gender_id, ["男性": "1", "女性": "2", "その他": "0"], class: "control-label" %>
  <%= error_tag f, :team %>
</div>
```

よく使うので覚え書きまで。

※参考URL http://www.whoocus.com/blog/?p=2631
IFTTT + Google Homeを使ってMastodonに投稿する方法

先日、前から欲しかったGoogle Homeを買ってみました。

凄く便利なのでオススメです。

Google Homeを使ってMastodonに投稿する方法です。

色々手間がかかるのでPCから作業した方がいいです。

## 用意するもの
- Google Home
- IFTTTアカウント
- Mastodonアカウント

## 手順
mstdn.mimikun.jp(自分のお一人様インスタンス)で作業していますが、他のインスタンスでも似たような感じでいけると思います。

### Mastodon側でアプリケーション作成
Mastodon側でアプリケーションを作成していきます。

ログインした状態で https://インスタンスドメイン/settings/applications

にアクセスします。

新規アプリ作成 を押し、適当に名前を付けて、クライアントキーとクライアントシークレット、アクセストークンを貰ってきて、どこかにメモしておきます。

### IFTTTのアプレットを作成する
アプレット作成ボタンを押します。

するとこういうのがでてくるので、クリックします。

![image1](https://s3-ap-northeast-1.amazonaws.com/mstdn.mimikun.jp/media_attachments/files/000/092/331/original/462f3e4f192da35e.png)

この部分を作っていきます。

その後、検索窓にGoogle Assistant と入力します。

そして、これを選択します。
![image2](https://s3-ap-northeast-1.amazonaws.com/mstdn.mimikun.jp/media_attachments/files/000/092/332/original/2edb662fc33980fb.png)

そしてこのように入力します。

![image3](https://s3-ap-northeast-1.amazonaws.com/mstdn.mimikun.jp/media_attachments/files/000/092/333/original/4ef5e048a468fb74.png)

![image4](https://s3-ap-northeast-1.amazonaws.com/mstdn.mimikun.jp/media_attachments/files/000/092/334/original/fc612d2c4426a481.png)

全部入力したら Create trigger でトリガーを作成します。

![image5](https://s3-ap-northeast-1.amazonaws.com/mstdn.mimikun.jp/media_attachments/files/000/092/392/original/845a3f0bfc491238.png)

次にこの部分を作っていきます。

検索窓に Webhook と入れ、出てきたものを選びます。

![image6](https://s3-ap-northeast-1.amazonaws.com/mstdn.mimikun.jp/media_attachments/files/000/092/393/original/a0d982f2db23d50b.png)

![image7](https://s3-ap-northeast-1.amazonaws.com/mstdn.mimikun.jp/media_attachments/files/000/092/395/original/9b14669d0b36772c.png)

このように入力します。 `textfield`は、Add ingredient をクリックすれば出てきます。

投稿範囲は、public, unlisted, private, directがありますので適切に入力してください。

全部入力したら、Create action でアクションを作成します。

### 試しになにか投稿してみる
「おっけーぐーぐる、ますとどんに テスト と投稿」

![image8](https://s3-ap-northeast-1.amazonaws.com/mstdn.mimikun.jp/media_attachments/files/000/092/431/original/603cdebd41e87bf9.png)

きちんと投稿されています。

IFTTTだと、喋ったことが確認なしでそのまま投稿されるので、そこを改善できたらもっと便利だなと思いました。
SpringMVCとMyBatis2.xの連携

###pom.xmlに追加した依存

		<!-- MyBatis -->
		<dependency>
			<groupId>org.apache.ibatis</groupId>
			<artifactId>ibatis-core</artifactId>
			<version>3.0</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-ibatis</artifactId>
			<version>2.0.8</version>
		</dependency>
		<dependency>
			<groupId>org.apache.ibatis</groupId>
			<artifactId>ibatis-sqlmap</artifactId>
			<version>2.3.0</version>
		</dependency>

この記述によってibatisのライブラリが使えるようになります。


###sqlMapConfig.xml

    <sqlMapConfig>
    	<transactionManager type="JDBC">
    		<dataSource type="SIMPLE">
    			<property name="JDBC.Driver" value="org.postgresql.Driver"/>
    			<property name="JDBC.ConnectionURL" value="jdbc:postgresql://localhost:5433/spring"/>
    			<property name="JDBC.Username" value="postgres"/>
    			<property name="JDBC.Password" value="postgres"/>
    		</dataSource>
    	</transactionManager>
	
    	<sqlMap resource="sample/Friendry.xml" />
	

    </sqlMapConfig>

今回はPostgreSQLを使用しました。

###Friendly.xml

    <sqlMap namespace="Friendly">
    	<resultMap id="ownerResult" class="sample.biz.domain.Owner">
    		<result property="ownerId" column="OWNER_ID"/>
    		<result property="ownerName" column="OWNER_NAME"/>
    	</resultMap>
	
    	<!-- Owner SQL -->
    	<select id="findOwner" parameterClass="java.lang.String" resultMap="ownerResult">
    		select OWNER_ID, OWNER_NAME from OWNER
    			where OWNER_ID = #value#
    	</select>

    </sqlMap>

sqlMapConfigから参照されます。
resultMapタグで、ドメインクラスにSQLの列名を紐づけています。
この宣言をすることで、自動でドメインクラスのプロパティにselect分の結果を格納してくれます。
selectタグにはidをつけてあげます。
このselect分を呼び出すときに指定する名前になります。
parameterClassは#value#の位置に入る引数の型です。
resultMapに先ほど宣言したresultMapを参照させます。

###SampleRun

    @Controller
    public class SampleRun {
	
    	@RequestMapping("/hello")
    	public String hello(Model model) {
    		try {
    			Reader reader = Resources.getResourceAsReader("sample/sqlMapConfig.xml");
    			SqlMapClient sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);
    			reader.close();
			
    			Owner owner = (Owner)sqlMap.queryForObject("findOwner", "2");
			
    			model.addAttribute("owner", owner);
    		} catch(Exception e) {
    			e.printStackTrace();
    		}
    		return "showMessage";
    	}
    }

実行クラスになります。
/helloでアクセスした場合にhelloが呼ばれます。
Modelを引数に受け取ることで、model.addAttributeが使えます。
SqlMapClientをビルドして、先ほど作ったfindOwnerに"2"の値を渡してselect分を実行しています。
最後にmodelにOwnerをセットしてjspに遷移します。

###Owner.java

    public class Owner {
    	private int ownerId;
    	private String ownerName;
	
    	public int getOwnerId() {
    		return ownerId;
    	}
    	public void setOwnerId(int ownerId) {
    		this.ownerId = ownerId;
    	}
    	public String getOwnerName() {
    		return ownerName;
    	}
    	public void setOwnerName(String ownerName) {
    		this.ownerName = ownerName;
    	}
    }

ドメインクラスです。
こちらは普通ですね。


###まとめ
今回はSqlMapClientを使用してMyBatisを使ってみました。
Springが初めて学ぶことだったので、難しかったです。
MyBatis2.xを使用したのですが、今現場で使われているのはずっと最新のMyBatisのようです。
DockerでMySQLをインストール


# 概要

DockerでMySQLを立ち上げ、接続する。


# 環境

 * Ubuntu 16.4

# 手順
## インストール、起動
```
sudo apt install docker.io

# 実行ユーザーをdockerグループにいれて実行
docker run --name mysql -e MYSQL_ROOT_PASSWORD=mysql -d -p 3306:3306 mysql --default-authentication-plugin=mysql_native_password
```

### 補足

`--default-authentication-plugin`を指定しないと、接続時に下記のエラーが発生する。

```
ERROR 2059 (HY000): Authentication plugin 'caching_sha2_password' cannot be loaded: /usr/lib/mysql/plugin/caching_sha2_password.so: cannot open shared object file: No such file or directory
```

## 接続

```
sudo apt install mysql-client

mysql -h 127.0.0.1  -uroot -pmysql
```
【調査】WEBアプリをPWAとして起動した場合にブラウザのCookieが引き継がれるか確認する

# まとめ

OS | 動作
:--- | :---
iOS 11.3 | - ブラウザとPWAでCookieが共有されない<br><br>- PWAを再起動すると起動時に毎回初期化される
iOS 12.2 | - ブラウザとPWAでCookieが共有されない<br><br>- PWAを再起動してもCookieは保持される<br>- PWAをタスクキルしてもCookieは保持される<br><br>- 端末を再起動するとPWAのCookieは初期化される
Android 8.0 | - ブラウザとPWAでCookieが共有される<br><br>- PWAを再起動してもCookieは保持される

# 【更新履歴】

- 2019/05/11 : まとめ に iOS12.2 のiPhoneで確認した動きを追記しました。



# 【追記】調査用アプリ
調査で利用したWEBアプリは今後もiOS, Androidバージョンアップ時に利用する可能性がありそうなためHerokuで公開しておきました。（無料プランのためしばらくアクセスがなかった場合はページが表示されるまで少し時間がかかります）

https://pwa-cookie-test-app.herokuapp.com/ 
![heroku-pwa-cookie-test-app.png](https://qiita-image-store.s3.amazonaws.com/0/141934/91d85376-fbfc-9e42-28fe-582441cfe154.png)

# 調査内容
WEBアプリをPWA（プログレッシブウェブアプリ）として起動した場合にブラウザのCookieが引き継がれるか確認する。

## 調査対象

- iOS 11.3
- Android 8.0

## 確認方法
**login**リンクをクリックするとCookieに`user_id`として`1`を格納するアプリを作成。

事前にブラウザで**login**しておき、PWAとして起動した場合に、
- 「ログイン済み」と表示されたら、Cookieが引き継がれている
- 「ログイン前」と表示されたら、Cookieが引き継がれない
と判断する。

<img width="854" alt="pwa-cookie01.png" src="https://qiita-image-store.s3.amazonaws.com/0/141934/f98943f5-63f5-11ea-45db-574a11145848.png">

> 補足：調査用アプリはRailsで作成した。
>     RailsではCookieを利用してデータを保存する方法が2つ(sessionとcookie)存在するため、調査用アプリでも2つの方法で`user_id`を保存している

# 確認内容

## 詳細：iOS 11.3

- ブラウザのCookieはPWA起動時には引き継がれない
- PWAを再起動（HomeScreenから再度開く）した場合、前回PWA起動時のCookieは引き継がれない

<img width="851" alt="pwa-cookie02.png" src="https://qiita-image-store.s3.amazonaws.com/0/141934/c15a19fc-fd6e-04d0-66a2-748c36b56560.png">

## 詳細：Android 8.0

- ブラウザのCookieはPWA起動時に引き継がれる
- PWAを再起動（HomeScreenから再度開く）した場合、前回PWA起動時のCookieは引き継がれる
- PWAのCookieもブラウザに引き継がれる

<img width="856" alt="pwa-cookie03.png" src="https://qiita-image-store.s3.amazonaws.com/0/141934/a2f69516-a5c8-8538-cf5b-288c93c284de.png">

# 補足

## 調査用アプリのソースコード（Ruby on Rails）

[NaokiIshimura/Qiita\-PWA\-Cookie](https://github.com/NaokiIshimura/Qiita-PWA-Cookie)
[Xcode] ペーストボード(クリップボード)(Select Select All Paste Look Up …)を選択　全選択　ペースト　にする方法

iPhoneの言語設定を日本語にしてもアプリでは英語のペーストボードで出てきます。

今回、これを日本語にしてほしいと言われ、どうすればできるんだろうと考えてやってみたらできたのでご紹介します。

|<img width="1026" alt="スクリーンショット 2018-05-21 21.18.29.png" src="https://qiita-image-store.s3.amazonaws.com/0/133940/e6595187-155c-cfcb-b9b7-e887a9d236da.png">|
|:-:|

っと言ってもやることは単純でアプリをローカライズ対応するだけ。

[[iPhone] 多言語対応、Localizationの設定](https://i-app-tec.com/ios/localization.html)

のサイトに乗っているようにローカライズ対応すればできました。

ま、当たり前なのかもと思ったのですが、すぐに思いつかなかったのでqiitaにあげてみました。

こちらのサイトはとても見やすく、自分で説明するよりも絶対いいだろうと今回リンクを貼るだけになってしまいました。
batからPowerShell ログ内容をメールで出力　メモ

#batからPowerShell ログ内容をメールで出力　メモ

##作業
・実行結果ログファイルを出力するにバッチ処理に追記
　※ログ出力し終わった直後に下記コマンドを設置

```bash

powershell -ExecutionPolicy RemoteSigned -Command ~ (省略)
```
・powershellファイルを作成。

#bat側処理
###bat側で以下要素を指定し、PowerShellに渡す。
その後、メール結果を表示。

・PowerShell処理ファイル(絶対パス)
・FROM(差出人メールアドレス)
・TO(Toメールアドレス※複数の場合「;」で区切る)
・CC(Ccメールアドレス※複数の場合「;」で区切る)
・SUBJECT(件名)
・ログファイル配置先(絶対パス)


```bash

@echo off
SET MAIL_PS1="PowerShellファイル配置先パス"
SET from="差出人メールアドレス"
SET to="toメールアドレス"
SET cc="ccメールアドレス"
SET subject="件名"
SET logFile="ログファイル配置先パス"

rem powershell呼び出し
powershell -ExecutionPolicy RemoteSigned -Command %MAIL_PS1% %from% %to% %cc% %subject% %logFile%

rem メール配信確認
If %ERRORLEVEL% EQU 0 GOTO label_SEND_MAIL_OK
If %ERRORLEVEL% NEQ 0 GOTO label_SEND_MAIL_NG

:: =============送信OK
:label_SEND_MAIL_OK
     echo "メールが正常に送信されました"
     GOTO label_SEND_MAIL_END

:: =============送信NG
:label_SEND_MAIL_NG
     echo "メール送信時にエラーが生じ、異常終了しました"
     GOTO label_SEND_MAIL_END

:: =============処理終了
:label_SEND_MAIL_END
```

#PowerShell側処理
###bat側から受け取った値でメール作成、指定パスのログファイル内容を本文に書き出し送信する。
```powershell

Param(
     [string]$from			#差出人
     [string[]]$to			#to(複数アドレス対応)
     [string[]]$cc			#cc(複数アドレス対応)
     [string]$subject		#件名
     [string]$logFile		#ログファイル配置先パス
)

$smtp = "SMTPサーバアドレス"
$port = "SMTPポート番号"
$SmtpClient = New-Object Net.Mail.SmtpClient($smtp,$port)
$Mail = New-Object Net.Mail.MailMessage

#差出人
$Mail.From = $from

#TO
$to | foreach { $Mail.To.Add($_) }

#CC
$cc | foreach { $Mail.Cc.Add($_) }

#件名
$Mail.Subject = $subject

#本文 ログファイル内容を書き出す
body = (Get-Content $logFile) -as [string[]]
$i = 0
foreach($l in $body){
	if($i -eq 0){
		$Mail.body = $l
	}else{
		$Mail.Body = $Mail.Body += "`r`n + $l 
	}
$i++
}
$SmtpClient.Send($Mail)
```
GitHub PagesでWebサイトを公開し、Googleアナリティクスを設定するまでの流れ

#はじめに
最近Webサイトを公開しました。
https://kouuuki.github.io/index/

<img width="1261" alt="スクリーンショット 2018-05-13 19.59.38.png" src="https://qiita-image-store.s3.amazonaws.com/0/201127/92b5c91f-5819-42f3-9ca1-426dba42da1d.png">


筆者が読んでよかったと思った技術書と技術ブログを紹介するサイトです。
このサイトはGitHub Pagesで公開しており、Googleアナリティクスも導入しています。

本記事ではGitHun Pagesでのサイト公開からGoogleアナリティクスの設定までを解説していきます。

#GitHub Pagesで公開

GitHub PagesでWebサイトを公開する方法は非常に簡単です。

1, 作ったファイルをGithubにpushします。
2, リポジトリ画面のSettingsをクリック
3, GitHub Pagesの設定ができるので「master branch」を選択してSaveします。
<img width="634" alt="スクリーンショット 2018-05-21 20.08.25.png" src="https://qiita-image-store.s3.amazonaws.com/0/201127/c1e74a71-7ef2-c3bb-b215-9ae4af27046d.png">

これだけでWebサイトが公開できてしまいます。

#Googleアナリティクスの導入

coming soon....
気づけばプロ並みPHP　ショッピングカート作りにチャレンジ！＃５【日記】(2018-05-21)

前回の日記から1ヶ月以上経っている・・_:(´ཀ`」 ∠):_

簡単なデータベースに関してページ遷移の仕組みや遷移先のページのソースを一通り書き終える。参照編集追加削除機能あり。

次は掲示板を作りたいんだけどPEARのインストールは必要かな
RedHat　IP設定　自分用メモ　crossfish21

さくらVPSの、/etc/sysconfig/network-scripts/ifcfg-eth0 の内容

```
# Generated by parse-kickstart
UUID=6db26840-8daa-44d0-9197-735d4ac2a0b9
DNS2=210.188.224.11
DNS1=210.188.224.10
IPV6_AUTOCONF=no
BOOTPROTO=none
DEVICE=eth0
IPV6ADDR=2001:e42:102:1704:160:16:137:141/64
ONBOOT=yes
IPV6INIT=yes
HWADDR=9C:A3:BA:02:30:1B
TYPE=Ethernet
IPADDR0=160.16.137.141
PREFIX0=23
GATEWAY0=160.16.136.1
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
DNS3=2001:e42::1
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
NAME="System eth0"
IPV6_DEFAULTGW=fe80::1
IPV6_PRIVACY=no
ZONE=public
```

---

[Redhatドキュメントリンク](https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/7/html/networking_guide/sec-editing_network_configuration_files)
[ちょっと古いが参考になるかもリンク](http://linux.kororo.jp/cont/intro/ipadd_manual.php)
[リンク3](https://qiita.com/kmikmy/items/8e0e55aeb6c24ac2e274)
[リンク4](https://qiita.com/routerman/items/4d19b3084fa58723830c)
Win32APIコールバック関数はラムダ式でも書けるのですね！

#はじめに
タイトルのとおりです。便利ですね～
（とっくに知ってらしている方もいらっしゃると思いますが...）

#サンプル
トップレベルウインドウと、子ウインドウや孫ウインドウ...を列挙して、ハンドルとタイトルを表示します。
トップレベルウインドウの列挙 ([EnumWindows](https://msdn.microsoft.com/ja-jp/library/cc410851.aspx)) では、コールバック関数の内容をラムダ式でコーディングしました。子ウインドウの列挙 ([EnumChildWindows](https://msdn.microsoft.com/ja-jp/library/cc410802.aspx)) については、孫、ひ孫、玄孫、...と再帰させるため、名前ありのメソッドを設けました。

```C#:Program.cs

using System;
using System.Text;
using System.Runtime.InteropServices;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            // トップレベルウインドウを列挙
            NativeMethods.EnumWindows(
                (h, p) => {
                    var count = NativeMethods.GetWindowTextLength(h);
                    var sb = new StringBuilder(count + 1);
                    var ret = NativeMethods.GetWindowText(h, sb, sb.Capacity);

                    Console.WriteLine("0x{0:X8} - {1}", h.ToInt32(), sb.ToString());

                    // 子ウインドウを列挙
                    NativeMethods.EnumChildWindows(h, EnumChildWindowsProc, new IntPtr(1));

                    return true;
                },
                IntPtr.Zero);

            Console.Read();
        }

        static bool EnumChildWindowsProc(IntPtr hWnd, IntPtr lParam)
        {
            var count = NativeMethods.GetWindowTextLength(hWnd);
            var sb = new StringBuilder(count + 1);
            var ret = NativeMethods.GetWindowText(hWnd, sb, sb.Capacity);

            Console.WriteLine("{0} 0x{1:X8} - {2}", new string('+', lParam.ToInt32()), hWnd.ToInt32(), sb.ToString());

            // さらに自身の子ウインドウを列挙
            NativeMethods.EnumChildWindows(hWnd, EnumChildWindowsProc, new IntPtr(lParam.ToInt32() + 1));

            return true;
        }

        class NativeMethods
        {
            [return: MarshalAs(UnmanagedType.Bool)]
            public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);

            [DllImport("user32.dll", SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool EnumWindows(
                EnumWindowsProc lpEnumFunc,
                IntPtr lParam
            );

            [DllImport("user32.dll", SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool EnumChildWindows(
                IntPtr hWndParent,
                EnumWindowsProc lpEnumFunc,
                IntPtr lParam
            );

            [DllImport("user32.dll", SetLastError = true)]
            public static extern Int32 GetWindowTextLength(
                IntPtr hWnd
            );

            [DllImport("user32.dll", SetLastError = true)]
            public static extern Int32 GetWindowText(
                IntPtr hWnd,
                StringBuilder lpString,
                Int32 nMaxCount
            );
        }
    }
}
```


##出力結果の例
<img width="735" alt="e1.png" src="https://qiita-image-store.s3.amazonaws.com/0/100206/8c6945a5-2f10-27a1-9969-493609b4f939.png">

#おわりに
C# がさらに好きになりました！
誤字その他のご指摘、もっと頼もしい便利な使用法、などをお待ちしています！
「自作Python100本ノック」13日目（Pythonおじさんへの道：89本〜90本目）

**「自作Python100本ノック」13日目です。**

なんかC++用の良さげな問題を見つけたので、「これをPythonにちょこっと直せばいけるんじゃね？」

と思ってた時もありました。

まあ、何だかんだで解き、なんかとか２問だけgetすることが出来たのでこれで今日は乗り切ります。

さて、
「自作Python100本ノック」とはそもそも何ぞや？
どの程度のレベル感なのか？
どのように進めて行くのか？
など気になる方は詳しくは[こちら](https://qiita.com/ahpjop/items/373f807d68044cda1c9b#%E8%87%AA%E4%BD%9Cpython100%E6%9C%AC%E3%83%8E%E3%83%83%E3%82%AF1%E6%9C%AC5%E6%9C%AC%E7%9B%AE)に整理してありますのでまずはそちらを確認するようお願いします。
それでは始めていきます。

##Q89: 全て偶数だったらひたすら割るやつ
問題：
渡辺君は，黒板に書かれている整数がすべて偶数であるとき，次の操作を行います。
黒板に書かれている整数すべてを，2で割ったものに置き換える。
渡辺君は最大で何回操作を行うことができるかを求めてください。

条件：
数字はリスト型で与えられる。

例：
　count_odd([16,12,24) ==> 2
1 回操作を行うと (8, 6, 12) になります。2 回操作を行うと (4, 3, 6) になります。2 個目の 3 が奇数なため 3 回目の操作は行えません。

個人的に`while`の使い方に慣れてなく、考えるのに結構時間かかりました。。。
`map()`とか使ってリスト内の数字を同時に2で割って、あまりの合計が0でなかったらみたいな式を作りたかったのですが、作れず。
　　　
```q89.py
def count_n(n_list):
    counts = []
    for n in n_list:
        count = 0
        while n % 2 == 0:
            count += 1
            n = n / 2
        else:
            counts.append(count)
    aws = min(counts)
    print(aws)
    
count_n([16,16,4])
```
[参考][B - Shift only](https://beta.atcoder.jp/contests/abc081/tasks/abc081_b)

##Q90: 大きい数字からとるゲーム
問題：
N 枚のカードがあり、0 〜 N までの整数が被らないように書かれています。
Alice と Bob はこれらのカードを使ってゲームを行います。ゲームでは 2 人が交互に 1 枚ずつカードを取っていきます。Alice が先にカードを取ります。
2 人がすべてのカードを取ったときゲームは終了し、取ったカードの数の合計がその人の得点になります。
2 人とも自分の得点を最大化するように最適戦略をとったとき、Alice は Bob より何点多くの得点を獲得できるかを求めてください。

元の問題が解けなかったので、自分で解けるような問題に変えました。
本当は、カードの数字はランダムにしたかったのですが、うまくいかず結局カードの数字は「0 〜 N」というつまらない問題になってしまいました。
物足りたい人は、[参考]から元の問題を是非解いて見てください。（そして教えてください）
　　　　

```q90.py
from numpy import random

def num_fight(card_number):
    cards = list(range(card_number))
    count = 0
    alice_cards = []
    bob_cards = []
    while len(cards) != 0:
        taken_card = max(cards)
        cards.remove(taken_card)
        count += 1
        if count % 2 == 1:
            alice_cards.append(taken_card)
        else:
            bob_cards.append(taken_card)
    alice_score = sum(alice_cards)
    bob_score = sum(bob_cards)
    aws = alice_score - bob_score
    
    print(aws)
    
num_fight(10)
```
[参考][B - Card Game for Two](https://beta.atcoder.jp/contests/abc088/tasks/abc088_b)

##感想
早く終わらせようと１日10問やっていた時が信じられません。
問題自体は、AtCoderとかに死ぬほどあるんですがほぼほぼ競技プログラミング用の問題なので、自分としては実用性が皆無なんですよね。
それでもAtCoderから面白そうな問題を漁りまくるか、もうChekiOから問題持ってきちゃうか悩み中です。

ChekiOからラスト10問持ってくるのが現状ベストかなあ。
[Twitter](https://twitter.com/i/notifications?lang=ja)の方ではQiitaの記事に加え、エンジニア向けのニュースなどの共有といった活動もしているので、よろしければフォローお願いします（フォロバ100%）

それでは！

→ [14日目](https://qiita.com/ahpjop/items/dc68cc02bc2b2ac30669)
【Unity】MenuItemで指定したショートカットキーを無効化する

# はじめに
Unityのエディタ拡張にはMenuItemを使ってショートカットキーを登録する方法があります。
参考：http://baba-s.hatenablog.com/entry/2013/12/13/101637

この方法でだれでも手軽にショートカットキーを登録することができます。

```c#
[MenuItem("Custom/Pause _p")]
private static void Pause()
{
    if(!EditorApplication.isPlaying)
    {
        return;
    }

    EditorApplication.isPaused = true;
}
```

例えば上記のようなコードがあったとすると、これは「p」を押すだけでプレイ中に一時停止することができます。
Unityの標準のままだと「Ctrl+Shift+P」を入力しないといけないのでとても楽になったのがわかります。

# 問題点
実は先ほどのコード、少し問題点があります。
それはEditor上での「p」入力を全て受け取ってしまい、GameObjectやファイルのリネーム時に「p」が入力できなくなってしまうことです。

そこでUnityのMenuItemリファレンスを見てみました。
https://docs.unity3d.com/jp/530/ScriptReference/MenuItem.html

この中の

```c#
[MenuItem("MyMenu/Log Selected Transform Name")]
static void LogSelectedTransformName()
{
    Debug.Log("Selected Transform is on " + Selection.activeTransform.gameObject.name + ".");
}

[MenuItem("MyMenu/Log Selected Transform Name", true)]
static bool ValidateLogSelectedTransformName()
{
    // Return false if no transform is selected.
    return Selection.activeTransform != null;
}
```

この記述。
これはMenuItemの機能で、MenuItemの第二引数をtrueにしたValidateメソッドを用意してやることで、メニューを表示した際に実行可能かチェックするものです。

これを見る限り、現状の問題を解決してくれそうな気がしますが、残念ながらこれでは解決されません。
確かにメニューに表示した際は無効化され、メソッドは呼ばれなくなっていますが、しっかりとショートカットキー入力は受け取っているようです。

# 解決策
```c#
[MenuItem("Custom/Pause _p")]
private static void Pause()
{
    if (!EditorApplication.isPlaying)
    {
        var window = EditorWindow.focusedWindow;
        if (window != null)
        {
            window.SendEvent(Event.KeyboardEvent("p"));
        }

        return;
    }

    EditorApplication.isPaused = true;
}
```

ということで、MenuItemで指定したメソッドが呼ばれてしまうのは受け入れて、その中で新しくキーイベントを発光する方法をとりました。

```c#
var window = EditorWindow.focusedWindow;
if (window != null)
{
    window.SendEvent(Event.KeyboardEvent("p"));
}
```

変更点はここです。
ここでは、まず現時点でフォーカスが当てられているWindowを取得します。
そのWindowに対して、KeyboardEventを発行してSendEventにて送っています。

こうすることによって、実際にはショートカットキーで呼ばれていますが、呼ばれていないように誤魔化すことができます。

# まとめ
今回はショートカットキーを無効化にする方法を紹介しました。
ただ、この方法だと一部無効化しきれないこともあるので、ご注意ください。
ほかにいい方法があればお教えいただけると嬉しいです。

感想、意見などお待ちしております。
https://twitter.com/_ykringo
IAMポリシー (利用リージョンの制限)

例:

```json:
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Deny",
            "Action": "*",
            "Resource": "*",
            "Condition": {
                "StringNotEquals": {
                    "aws:RequestedRegion": [
                        "us-east-1",
                        "ap-northeast-1"
                    ]
                }
            }
        }
    ]
}
```
cronをランダムに実行する設定

# ランダム(乱数)で処理を実行するシェルコマンド

以下の3つはいずれも
処理`echo "hello"`を1/3の確率(33%)で実行できます。

```
[ $(($RANDOM % 3)) -eq 1 ] && echo "hello"
[ $(($RANDOM % 100)) -lt 33 ] && echo "hello"
if [ $(($RANDOM % 100)) -lt 33 ]; then echo "hello"  ; fi
```

1つずつ紐解いてみます。

## $RANDOM とは

bash、zshであらかじめ用意されている環境変数で、
`0`から`32767`までの数字をランダム(乱数)出力させることが出来るようです。

試してみる

```
$ echo $RANDOM
26634
$ echo $RANDOM
7712
$ echo $RANDOM
15559
```

## 乱数を割った余りを出力する

乱数を割った余りを出します。
`% 5`とすれば、乱数を5で割った余り、すなわち0-4までの数字がランダムに出ます。

```
$ echo $(($RANDOM % 5))
2
$ echo $(($RANDOM % 5))
4
```

なおexprを使う方法もありますが、二重括弧`((...))` の方が処理が早いようです。

```
$ echo `expr $RANDOM % 5`
3
```

## 乱数を使った様々なパターン

### eq(イコール)を用いたケース

`乱数を割った余りの数字`と`1`が`イコール(eq)`だった場合に実行されます。

```
[ $(($RANDOM % 3)) -eq 1 ] && echo "hello" // 3回に1回
[ $(($RANDOM % 5)) -eq 1 ] && echo "hello" // 5回に1回
[ $(($RANDOM % 10)) -eq 1 ] && echo "hello" //10回に1回
[ $(($RANDOM % 100)) -eq 1 ] && echo "hello" //100回に1回
```

### lt(より小さい)を用いたケース

`乱数を割った余りの数字`が`指定した数字`より`小さい(lt)`場合に実行されます。

```
[ $(($RANDOM % 100)) -lt 33 ] && echo "hello" // 33%
[ $(($RANDOM % 100)) -lt 50 ] && echo "hello" // 50%
[ $(($RANDOM % 1000)) -lt 70 ] && echo "hello" // 7%
[ $(($RANDOM % 1000)) -lt 700 ] && echo "hello" // 70%
```

### if文を用いてスクリプトも可能

```
if [ $(($RANDOM % 100)) -lt 33 ]; then echo "hello"  ; fi
```

# cronをランダム(乱数)に設定する

## 必須コマンド

### 登録

```
$ crontab -e
```

ファイルがあれば、`crontab ファイル名` でも可能です。

### 確認

```
$ crontab -l
```

## cronをランダムに実行させる設定例

`分 時 日 月 曜日`

```
# 5分おきに実行。ただし33%の確率
*/5 * * * * [ $(($RANDOM % 100)) -lt 33 ] && echo "hello"

# 1,6,11,16..5分おきに実行。ただし33%の確率
01-59/5 * * * * [ $(($RANDOM % 100)) -lt 33 ] && echo "hello"

# 2,7,12,17..5分おきに実行。ただし33%の確率
02-59/5 * * * * [ $(($RANDOM % 100)) -lt 33 ] && echo "hello"

# 8:00と16:00と20:00に実行。ただし50%の確率
0 8,16,20 * * * [ $(($RANDOM % 100)) -lt 50 ] && echo "hello"

# 12:30,13:30,14:30,16:30,,,に実行。ただし80%の確率
30 12,13,14-22/2 * * * [ $(($RANDOM % 100)) -lt 80 ] && echo "hello"
```

# Reference

今回調べるにあたり多くの記事を見ました。
特に下記の記事を参考にさせて頂きました。

・[シェルスクリプトでランダムにする方法](https://qiita.com/piroor/items/6300e665bc8ac314211b)
・[exprと二重括弧について](https://qiita.com/d_nishiyama85/items/a117d59a663cfcdea5e4)
・[cronの実行時間の微調整1](https://qiita.com/tukiyo3/items/4b3a6ed5b5bc1208bf66)
・[cronの実行時間の微調整2](https://qiita.com/yudoufu/items/2aecba975f9267af6f19)
・[cron1時間に1回をワンライナー](https://qiita.com/shimon_haga/items/42f54f0e12ced9b9117d)
・[cronの設定例](https://qiita.com/hikouki/items/e744b3a4d356d2af12cf)
・[cronの書き方](https://qiita.com/katsukii/items/d5f90a6e4592d1414f99)

いずれの記事も大変わかりやすくとても参考になる内容でした。
ありがとうございました。
【RSpec 3.1+】ひとつの expect で複数リソースの change を検証する

ひとつのアクションで、複数のリソースが作成されるときの検証方法の例。

例えば POST するエンドポイントを叩いたあとにリソースがひとつ増えることを検証するときは次のように書く。

```rb
    it do
      expect { 
        post "/api/v1/schedules/create", params: params
      }.to change { Schedule.count }.by(1)
    end 
```

このとき、`Schedule` というリソースだけでなく `Project` といったリソースも一緒に登録されることを検証したい場合は次のように書ける。

```rb
    it do
      expect { 
        post "/api/v1/schedules/create", params: params
      }.to change { Schedule.count }.by(1).and change { Project.count }.by(1)
    end 
```

RSpec 3.1 のリリースで、`change` メソッドをチェーンできるようになっている！

## 参考

[RSpec 3.1 has been released!](http://rspec.info/blog/2014/09/rspec-3-1-has-been-released/)
[expect change を複数データ同時にTESTしたいときに](https://qiita.com/hachiya/items/2831557a1dac2505ab2e#comment-a1429e9bf1c6071e4772)
【RSpec】described_classの小さなサンプルメモ

# サンプルクラス

```ruby:person.rb
class Person
  attr_accessor :name
  def initialize
    @name = "kure"
  end
end

class Person2
  attr_accessor :name
  def initialize
    @name = "kure2"
  end
end
```


# サンプルRSpec

```ruby
require 'person'

RSpec.describe Person do

  subject(:kure){ Person.new }
  # ★described_class で describeで宣言されたクラス（=Person）を取ってくる
  subject(:kure_by_described_class){ described_class.new }
  subject{ Person2.new }

  # オーソドックスな書き方
  it "name is kure" do
    person = Person.new
    expect(person.name).to eq("kure")
  end

  it "name is kure(described_class)" do
    expect(kure_by_described_class.name).to eq("kure")
  end

  it "name is kure(subject)" do
    expect(kure.name).to eq("kure")
  end

  it "name is kure2(subject)" do
    expect(subject.name).to eq("kure2")
  end
end
```
phpMyAdminをアップデートしたときの方法

![phpMyAdmin.png](https://qiita-image-store.s3.amazonaws.com/0/187963/b9aaf744-858d-8338-bfa9-a37c8007fd90.png)

ずっとこのエラーに悩まされていて、ログインしては強制的にログアウトをさせられるという非効率な感じの管理画面になってしまっていた。

知人に相談すると、以下のURLが送られてきた。https://github.com/phpmyadmin/phpmyadmin/issues/13964
どうやらバーションのエラーっぽいからアップデートしたら？って答えが返ってきたので早速着手。

こちらの記事を参考にphpmyadminをアップデートしてみた。
https://wp.bmemo.pw/556

### まずはサーバー類を止める

```
$ sudo service mysql stop
$ sudo service nginx stop
```

### 古いやつはバックアップ

```
$ cd /usr/share
$ sudo mv phpMyAdmin phpMyAdmin.old
```

### 新しいのインストール
執筆時の最新安定バージョンは「4.8.0.1」。

```
# $ sudo wget https://files.phpmyadmin.net/phpMyAdmin/｛最新のバーションを指定｝/phpMyAdmin-｛最新のバーションを指定｝-all-languages.zip
$ sudo wget https://files.phpmyadmin.net/phpMyAdmin/4.8.0.1/phpMyAdmin-4.8.0.1-all-languages.zip
$ sudo unzip phpMyAdmin-4.8.0.1-all-languages.zip
$ sudo mv phpMyAdmin-4.8.0.1-all-languages phpMyAdmin
$ sudo rm phpMyAdmin-4.8.0.1-all-languages.zip
$ sudo chmod -R 775 phpMyAdmin
```

###パスフレーズの設定

パスフレーズの設定をするみたい。バージョンによっては必須。

```
$ cd /etc/phpMyAdmin/
$ sudo vim config.inc.php
```

```
/*
 * This is needed for cookie based authentication to encrypt password in
 * cookie
 */
$cfg['blowfish_secret'] = 'ababa'; /* YOU MUST FILL IN THIS FOR COOKIE AUTH! */
```

###サーバを再起動

```
$ sudo service mysql start
$ sudo service nginx start
```


![スクリーンショット 2018-05-21 18.14.28.png](https://qiita-image-store.s3.amazonaws.com/0/187963/7ecbe0bd-f33b-84d1-3373-7d858e185b49.png)

無事に最新版へアップデートできました。
Amazon linux:2016.09にDoxygenの最新版をインストールする with Graphviz

# はじめに
PHPとかのドキュメントを作成してくれるツール　***Doxygen***　をインストールします。
最新のDoxygenのインストールにはCMake3が必要らしいのでまずこれをインストールします。

Doxygenのドキュメントは日本語に翻訳したページもあるんですが、バージョンが古いまま更新が止まっているようなので、英語で書かれている本家のドキュメントを見た方がいいかと思います。
ドキュメントに書かれている最新バージョンは1.8.14でしたが、githubから落としたものは1.8.15でした。

# 環境
- Amazon linux 2016.09

# init
最初にコンパイラとか

```bash:console
$ yum groupinstall "Development Tools"
$ yum install wget
```

# CMake3のインストール

```bash:console
$ cd /usr/local/src
$ wget https://cmake.org/files/v3.11/cmake-3.11.1.tar.gz
$ tar xvf cmake-3.11.1.tar.gz
$ cd cmake-3.11.1
$ ./bootstrap
$ make
$ make install
$ /usr/local/bin/cmake --version
cmake version 3.11.1
```
20180521現在の最新バージョンは3.11.2だったのでそっちでもいいと思います。
適宜バージョンの部分を書き換えればインストールできるかと。

# Doxygenのインストール

```bash:console
$ cd /usr/local/src
$ git clone https://github.com/doxygen/doxygen.git
$ cd doxygen/
$ mkdir build
$ cd build/
$ /usr/local/bin/cmake -G "Unix Makefiles" ..
$ make
$ make install
$ /usr/local/bin/doxygen --version
1.8.15
```

# 終わりに
あとDoxygenで図が欲しい時に必要かと思うのでGraphvizも入れとく。
これのバージョンは特に指定しないです。

```bash:console
$ yum install graphviz graphviz-gd
```

Doxygenの使い方については今後まとめようと思います。
git on Windowsで aggregateexceptionが発生する

# 概要
- WindowsからGit Bashをつかってgitコマンドをたたいていた環境で発生した問題の共有
- 英語の記事は多かったのですが日本語の記事がピンポイントで見つからなかったので備忘録
- 結論から言うとGit Bashを最新版にしたら直る問題

# 環境
- windows 7 Professional, SP1, 64bit
- Git Bash 2.16.0 よりも前のバージョン
- gitコマンド対象リポジトリ：Github

# 事象
下記のエラーメッセージが発生し、ユーザIDとPWを毎回入力しなければgitが使えない（fetch, pull, pushなどなど）。

```
fatal: AggregateException encountered. 
One or more errors occurred. 
```

gitのプロキシ設定や、credential-helperをつかっていても同事象が発生していた。原因を調べたところ、この英語の[記事](https://github.com/Microsoft/Git-Credential-Manager-for-Windows/issues/559 "記事")を発見。

```
GithubでTLS1.0が無効化されたことが原因だよ。バージョン2.16.2以降では解決しているよ。
```

よって、[ダウンロードサイト](https://git-scm.com/downloads "ダウンロードサイト")から最新版の2.17.0をインストールすることで無事、毎回ユーザIDとPWをきいてくるプロンプトが出なくなった。
【RSpec】subjectの小さなサンプルメモ

# サンプルクラス

```person.rb
class Person
  attr_accessor :name
  def initialize
    @name = "kure"
  end
end

class Person2
  attr_accessor :name
  def initialize
    @name = "kure2"
  end
end
```

# RSpecサンプルメモ

暗黙の定義（というのだろうか？）

```ruby:person_spec.rb
require 'person'

RSpec.describe Person do

  # オーソドックスな書き方
  it "name is kure" do
    person = Person.new
    expect(person.name).to eq("kure")
  end

  # Subject利用（暗黙に定義されてる）
  # describeでクラス名を指定すると、[subject]が暗黙にそのクラスのインスタンスとして定義されるみたい
  it "name is kure(subject)" do
    expect(subject.name).to eq("kure")
  end
end
```

明示的な定義

```ruby:person_spec2.rb
require 'person'

RSpec.describe Person do

  subject(:kure){ Person.new } # 「kure」でPersonインスタンスを使用できる
  subject{ Person2.new } # 「subject」でPerson2インスタンスを使用できる

  # オーソドックスな書き方
  it "name is kure" do
    person = Person.new
    expect(person.name).to eq("kure")
  end

  it "name is kure(subject)" do
    expect(kure.name).to eq("kure")
  end

  it "name is kure2(subject)" do
    expect(subject.name).to eq("kure2")
  end
end

```

# 参考リンクメモ

10 subjectを使ってみよう | RSpec入門 - プログラミングならドットインストール https://dotinstall.com/lessons/basic_rspec/27910

Explicit Subject - Subject - RSpec Core - RSpec - Relish https://relishapp.com/rspec/rspec-core/v/3-7/docs/subject/explicit-subject

implicitly defined subject - Subject - RSpec Core - RSpec - Relish https://relishapp.com/rspec/rspec-core/v/3-7/docs/subject/implicitly-defined-subject
docker run の時 volume が割り当てられない(Git For Windows使用)

# 環境

* Windows 8.1
* **Git for windows**

Docker Toolboxをインストール

* Docker version 18.03.0-ce, build 0520e24302
* docker-machine.exe version 0.14.0, build 89b8332

# 問題

docker runでvolumeをマウントしようとしたら出た問題。

```shell
docker run -v /C/Users/hoge/Logs:/logs centos:7
```

上記実行するとエラー!

```shell
Error response from daemon: invalid mode: \Program File\Git\logs.
```

`Git\logs`とおかしいでしょと思って対処方法を探してたら見つかった。
[Dockerにホストのフォルダをマウントしたい！ git-for-windows-など-bash-上での注意](https://qiita.com/dojineko/items/f623894ef2436bef890e#git-for-windows-%E3%81%AA%E3%81%A9-bash-%E4%B8%8A%E3%81%A7%E3%81%AE%E6%B3%A8%E6%84%8F)
ありがとうございます。

```shell
docker run -v //C/Users/hoge/Logs:/logs centos:7
```

`/C`の先頭にもう一個`/`を追加するとマウント出来ました。

------

WindowsのターミナルはGit For WindowsのBashを使用しているのだけど、カレントディレクトリで操作しているときは`pwd`を使うと楽。

```shell
docker run -v /$(pwd)/Logs:/logs centos:7
```
Cognos Framework Manager で自動集計後フィルターの実装

#概要
こんなTechnoteの存在を最近始めて気が付き、自分の興味と理解のために検証したので、自分で忘れないように投稿しておきます。
こちらの**Summary Query Subjects**です。

**IBM Analytics Proven Practices - What's New in Framework Manager 10.2.2**
http://www-01.ibm.com/support/docview.wss?uid=swg21902184

フィルターを自動集計前に適用するか、自動集計後に適用するか、「レポートの機能」では詳細フィルターのプロパティで指定できていましたが、Framework Managerで実装する方法になります。
![009.JPG](https://qiita-image-store.s3.amazonaws.com/0/147246/61e3843c-666b-405a-d223-103883d37e27.jpeg)

#動きと設定方法の説明
以下のように、Great Outdoors Warehouseのサンプルで、製品ライン・年・数量を集めて、「製品ライン販売数量」というクエリーサブジェクトを新規に作成してみます。
![000.JPG](https://qiita-image-store.s3.amazonaws.com/0/147246/5d94e74d-6a26-5929-ad13-40fbed55b829.jpeg)

パッケージを発行して、リストレポートに「製品ライン販売数量」クエリーサブジェクトをそのまま置いて、実行してみると、以下の結果になります。
小さいものは68万、大きいものは1000万超、という感じなので、500万個以下の製品ラインの表示は削除するフィルターをFramework Managerで作成したいなと思います。
![002.JPG](https://qiita-image-store.s3.amazonaws.com/0/147246/d8f691a1-9509-31c5-120a-1581c507e00a.jpeg)

FM上で、「製品ライン販売数量」クエリーサブジェクトに以下のようなフィルターを追加してみます。
![003.JPG](https://qiita-image-store.s3.amazonaws.com/0/147246/63bba4b7-30c4-884d-9a46-1e82403e2d38.jpeg)

再度パッケージ配布して、レポート実行すると「データなし」となります。
先ほど、500万個以上のデータは複数表示されていたのに、おかしいですね。
![004.JPG](https://qiita-image-store.s3.amazonaws.com/0/147246/cd25807d-6f75-17a5-86ff-59052b5df427.jpeg)

何故そうなるかというと、先ほどの「数量」の値は、「製品ライン」と「年」のレベルで集約された結果のデータだからですね。
実際の元の表を見てみるとわかりますが、「製品ライン」単位ではなく「製品」単位、「年」単位ではなく「日付」単位にデータを持っているので、1行1行はこの数個から数百個のレベルの「数量」なので、FMのフィルターはこの「粒度が最も小さい」データに対して適用されるため、「500万個以上」となると、全てフィルターではねられてしまいます。
![005.JPG](https://qiita-image-store.s3.amazonaws.com/0/147246/9e87aa1b-db46-f45f-56ee-e3aade66cc48.jpeg)

冒頭でお話したように、レポートの機能では、このフィルターを自動集計後に適用するように変更できますが、Framework Managerでは、Cognos BI 10.2.2から同様の事ができるようになりました。

まず、以下のようにFMでクエリーサブジェクトを選択し、プロパティから「(DQM)使用方法」を「集計クエリー」に変更します。
![006.JPG](https://qiita-image-store.s3.amazonaws.com/0/147246/556e5a68-1c34-aa17-595a-749b449a3e45.jpeg)

そして、クエリーサブジェクトを開き、「フィルター」タブでフィルターを確認すると「(DQM)アプリケーション」列が増えていますので、ここを「自動集計後」に変更します。
![007.JPG](https://qiita-image-store.s3.amazonaws.com/0/147246/9d470f77-c831-571c-cd20-c4ec7726cfc8.jpeg)

パッケージを発行後、再度レポート実行で、集計後のデータにフィルター(500万以上)が適用されている事がわかります。
![008.JPG](https://qiita-image-store.s3.amazonaws.com/0/147246/9c5043ab-8bf8-13f8-38b5-0f18a6c09d52.jpeg)

以上です。
レポートの機能では良く使う機能なので、Framework Managerでもできる事を覚えておくと便利かと思います。
単体テストでDLLロードにはまった話

# 概要

C#の単体テストでDLLのロードに失敗した。簡単に解決できると思っていたがなかなか解決できなかった。今後、同じようなミスを犯さないよう、ミスの内容を記述する。

# 環境
OS：Windows 10
IDE：Visual Studio 2010

# 現象
C#のコードから呼び出すネイティブDLLに次のようなコードがあり、ロードに失敗していた。

```c++

WCHAR* dllPath = "Hoge.dll";
::LoadLibrary(dllPath);    // ここで失敗

```

実行アプリのディレクトリには"Hoge.dll"があること、またデバッグ実行ではロードに失敗しないことから、ロードできないはずはないと思い込んでいて、解決に時間がかかった。

# 原因
分かってしまうと簡単で、カレントディレクトリが実行アプリのディレクトリでなかったため。
単体テストの時はカレントディレクトリが下記のような位置になる。
　　"D:\\Projects\\TestResults\\user_pc 2018-05-21 17_52_47\\Out"

そのため、単体テスト中はロードできなかった。
※デバッグ実行時はカレントディレクトリが実行アプリのディレクトリになっているからロードできていた。

# 対策
下記の方法が考えられるが、モジュールに手を加えられないため後者の方法を使用した。
1. ネイティブDLL内のLoadLibraryで指定するモジュールパスを、実行アプリのディレクトリを付加した形式にする
2. 単体テスト実行時に、Directory.SetCurrentDirectory()を使ってカレントディレクトリを実行アプリのディレクトリに変更する
CLI で esa.io の記事を作成するツール esautils を作りました

# 開発の動機

最近 esa.io を業務で使うようになりました。とても便利です。
ブラウザでの編集も快適なのですが、年中端末に引き篭っている身からすると、どうにか CLI でも記事を更新をしたいと思っていました。

例えば CLI で esa.io の記事更新ができるようになると、以下のようなことができるようになります。

- vi/emacs などお気に入りのエディタを使って編集できる
- screen/tmux など端末プレクサとのコピペが楽になる
- 他の CLI ツールと連携しやすくなる
- cron などで記事更新を自動化できる

# 既存の esa.io 関連ツール

公式のライブラリとして [esa-ruby](https://github.com/esaio/esa-ruby) があります。

サードパーティ製の esa.io ツールは以下のページでまとめられています。

- https://docs.esa.io/posts/158

CLI ツールとしては [esa-cli](https://github.com/ksss/esa-cli) がありますが、記事の観閲がメインです。
[esa.vim](https://github.com/upamune/esa.vim) のようなエディタのプラグインを使えばローカルでも記事作成はできますが、他の CLI ツールとの連携には使えません。

# esautils

## 概要

CLI で記事の投稿・更新をするためのコマンド群です。
記事の取得もできますが、検索のためのコマンドはありません。

言語は Go 言語を使用しました。
ライブラリとしては upamune さんの [go-esa](https://github.com/upamune/go-esa) を利用させていただきました。

## 設計思想

esautils では記事の`Number`ごとにディレクトリを作成し、その直下に JSON キーと対応するファイルを配置します。

例えば esa.io の API からの応答は以下のような JSON です。

~~~json
{
  "number": 1,
  "name": "hi!",
  "full_name": "日報/2015/05/09/hi! #api #dev",
  "wip": true,
  "body_md": "# Getting Started",
  "message": "Add Getting Started section",
  "tags": [
    "api",
    "dev"
  ],
  "category": "日報/2015/05/09",
}
~~~

これを JSON のキーごとに個別のファイルに書き出します。
`esa_new` というコマンドで記事を作成すると以下のようなファイルが作成されます。

~~~bash
$ esa_new "日報/2015/05/09" "hi!"
$ ls -F
$ 352/
$ tree 352/
352/
├── BodyMd
├── Category
├── Message
├── Name
├── Tags
└── Wip
~~~

それぞれのファイルの内容は単なるテキストファイルです。

- `BodyMd`: 記事の本文 (Markdown記法)
- `Category`: カテゴリ
- `Message`: 記事作成・更新の際のメッセージ
- `Name`: 記事タイトル
- `Tags`: タグ (改行区切り)
- `Wip`: WIPフラグ (`true` or `false`)

## 環境変数

各コマンドの使用前にいくつかの環境変数を設定する必要があります。

- `ESA_API_KEY`
    - アプリケーショントークン
- `ESA_TEAM`
    - esa.io のチーム名
- `ESA_USER`
    - ユーザ名

API KEYの取得は以下のURLから行うことができます。

- https://your_team.esa.io/user/applications

## 各コマンドの使い方

- `esa_new CATEGORY NAME`
    - 説明:
        - 新規に記事を作成する
    - 引数:
        - CATEGORY: 記事カテゴリ
        - NAME: 記事タイトル
- `esa_update NUMBER`
    - 説明:
        - 記事を更新する
    - 引数:
        - NUMBER: 記事の`Number` (`esa_new`が作成したディレクトリ名を指定)
- `esa_attach PATH`
    - 説明:
        - 添付ファイルをアップロードする
    - 引数:
        - PATH: アップロードするファイルのパスを指定
    - 返り値:
        - アップロード先のURL
- `esa_get NUMBER`
    - 説明:
        - 指定した`Number`の記事を取得する
    - 引数:
        - NUMBER: 記事の`Number`
- `esa_getall`
    - 説明:
        - 自分のユーザ名に紐付く全ての記事を取得する

`esa_new`や`esa_get`で記事の作成・取得を行い、ローカルで編集した後、`esa_update`で更新する、という流れを想定しています。

## 使用例

### (1) fswatchとの連携

`fswatch`がファイルの更新を検知する度に自動で esa.io の対応記事をアップデートします。

~~~bash
#!/bin/bash
fswatch --one-per-batch -d -0 . | while read -d "" path; do
  POST_NUM=`basename $(dirname $path)`
  PATTERN="[0-9]+"

  diff $POST_NUM/BodyMd{.draft,} && continue
  cp $POST_NUM/BodyMd{.draft,}

  if [[ $POST_NUM =~ $PATTERN ]]; then
    esa_update $POST_NUM
  fi
done
~~~
iPhone検証機のiOSを気軽にアップデートすると開発不能になる

「iOS最新」とラベルが貼られているからと言って、気軽にiOSアップデートを仕掛けたらまずい。調べて、適切なバージョンにアップデートするか、アップデートを諦めましょう。

## まずい理由
最新のXCodeが、最新のiOSに対応しきれていない場合がある。その場合、開発不能になる。

## 対処法
1. iPhoneで、iOSを最新にあげようとしたときに、どのバージョンになるのかを確認する
2. Appleのサイト( https://developer.apple.com/download/more/ ) などで、最新のXCodeのバージョンを確認する
3. 最新のXCodeがサポートしているiOSのバージョンを確認する(release_noteに書いてあることもある)
4. 「１」と「３」の情報を見比べて、アップデートしても問題なければ、アップデート

## その他、Tips
- ipswでファームウェアをフォーマットすると、ある程度任意のバージョンにできる
- ファームウェアをフォーマットすると、初回セットアップでSIMカードが必要になる(要注意)