OmniAICreator/Qiita-1.07M huggingface dataset:
[C#/UWP] WriteableBitmapで点を打って、テレビの放送終了後の砂嵐をつくる(UWP版)

**もくじ**
→https://qiita.com/tera1707/items/4fda73d86eded283ec4f

# やりたいこと
以前、WPFで同じことを試したが、そのままのコードをWPFにもっていっても動かなった。
`WriteableBitmap`クラスはUWPにもあるが、仕様が異なっているからと思われる。
また、別スレッド中に、UIスレッドで処理をしてもらうための書き方(`Dispatcher.Invoke()`)も、WPFとUWPで異なっている。

UWPでも画面に点を打つことがあるので、やり方を知りたい。

# サンプル
下記のようにすると動いた。

```MainPage.xaml.cs
using System;
using System.Threading.Tasks;
using Windows.Graphics.Imaging;
using Windows.Storage.Streams;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media.Imaging;

namespace SandStormUWP
{
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();

            Task.Run(() =>
            {
                while (true)
                {
                    const int width = 256;
                    const int height = 256;

                    byte[] data = new byte[width * height * 4];

                    Random rnd = new System.Random();    // インスタンスを生成
                    int rndMax = 256;                    // 0～256の乱数を取得

                    // バイト列に色情報を入れる
                    for (int i = 0; i < width; i++)
                    {
                        for (int j = 0; j < height; j++)
                        {
                            data[4 * (i + j * width)] = (byte)rnd.Next(rndMax);
                            data[4 * (i + j * width) + 1] = (byte)rnd.Next(rndMax);
                            data[4 * (i + j * width) + 2] = (byte)rnd.Next(rndMax);
                            data[4 * (i + j * width) + 3] = (byte)rnd.Next(rndMax);
                        }
                    }

                    var task = this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>
                    {
                        WriteableBitmap bitmap = new WriteableBitmap(width, height);

                        InMemoryRandomAccessStream inMRAS = new InMemoryRandomAccessStream();
                        BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, inMRAS);
                        encoder.SetPixelData(BitmapPixelFormat.Rgba8, BitmapAlphaMode.Ignore, (uint)bitmap.PixelWidth, (uint)bitmap.PixelHeight, 96.0, 96.0, data);
                        await encoder.FlushAsync();
                        BitmapImage bitmapImage = new BitmapImage();
                        bitmapImage.SetSource(inMRAS);
                        MyImage.Source = bitmapImage;   // 「MyImage」は、xamlの<Image Name="MyImage"/>より。砂嵐を張り付けるImageの名前。
                    });
                }
            });
        }
    }
}

```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352601/2f315d5c-8900-bb91-b064-2ee75dc06b27.png)


# 参考
UWPでバイト配列を画像として表示する
https://jprogramer.com/uwp/3926
Wagtailチュートリアル 15 adminページにSUBSCRIBERを追加

#Wagtailチュートリアル 15
<=[14 SNSをうめこもう](https://qiita.com/tagawahirotaka/items/3908dc5ffea6e02f6049)
=>[16 親ページと子ページ](https://qiita.com/tagawahirotaka/items/19dd84a26d34df33b813)

##adminページにSUBSCRIBERを追加

34

```python3 startapp subscribers```

```python:wagtailtutrial/settings/base.py

INSTALLED_APPS = [
    "home",
    "search",
    # 16 flexを追加
    "flex",
    # 18 streamsを追加
    "streams",
    # 32 追加
    "site_settings",
    "subscribers",  # 34 追加
    "wagtail.contrib.modeladmin",  # 34 追加
    "wagtail.contrib.forms",
    "wagtail.contrib.redirects",
    "wagtail.contrib.settings",  # 32 追加
    "wagtail.embeds",
    "wagtail.sites",
........
```

```python:subscribers/models.py

from django.db import models

# 34 Djangoの感じで定義
class Subscribers(models.Model):

    email = models.CharField(
        max_length=100, blank=False, null=False, help_text="Email address"
    )
    full_name = models.CharField(
        max_length=100, blank=False, null=False, help_text="First and last name"
    )


def __str__(self):
    return self.full_name

    class Meta:
        verbose_name = "Susbcriber"
        verbose_name_plural = "Subscribers"
```

```python:subscribers/admin.py

# 34 定義
from wagtail.contrib.modeladmin.options import ModelAdmin, modeladmin_register
from .models import Subscribers


class SubscriberAdmin(ModelAdmin):
    """Subscriber admin."""

    model = Subscribers
    menu_label = "Susbcribers"
    menu_icon = "placeholder"
    menu_order = 290
    add_to_settings_menu = False
    exclude_from_explorer = False
    list_display = ("email", "full_name")
    search_fields = ("email", "full_name")


modeladmin_register(SubscriberAdmin)
```

34
<img width="1440" alt="スクリーンショット 2019-08-30 14.10.33.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402245/b7f6216e-8f4e-f048-bd0d-915283d71b40.png">
STSを使いやすくカスタマイズ・・・

# 追記
2019.11.28 Limyにもう少し内容付けました。

#背景
pleiadesのAll in Oneでぬくぬく開発から、STSでの開発に変えた途端。
めちゃくちゃ使いにくくなったので、使いやすくカスタマイズしてみました。

# 前提
pleiades All in One があること。(;^ω^)
(私は バージョンMarsでやりました。)
#やったこと

### 日本語化
[Spring Tool Suiteのインストールと日本語化](https://qiita.com/kxn4t/items/2f86c57956fa052d9236)

### Limyの追加　(setter/getterを自動生成用)
[SpringToolSuite(STS)で使用するプロパティエディタの検討](https://qiita.com/hnkyi/items/3e881e2a994658a6c5f8) 

#### 追記
ここで言っている、setter/getterの自動生成は[ソース]タグからではなく[編集]タグで実行する自動生成のことを言っています。
その場合、Limyはeclipse Mars(4.5)より最新ではできないのでご注意・・・。
これが使えると、フィールドのJavadocコメントをもとにsetter/getterのコメント作ってくれるので楽ちんです。

### 保管順序
Ctrl + Spaceで出てくる候補がいつもならJava候補なのに、4回くらいCtrl+Spaceしないと出なかったので追加。

1. [ウィンドウ]→[設定]→[Java]→[エディタ]→[コンテンツ・アシスト]→[拡張]
2. コンテンツアシストの循環　で順番を変更

(でもなぜかデフォルト候補が一番上にくる・・・)
↑
デフォルト候補に何もでてこなかったので、よくよく確認してみると
デフォルトコンテンツアシストのチェックから`Java`関連がチェックOFFに・・・チェックONにすると
うまく表示されました(＾ω＾)

### フォントの設定 (日本語コメント文字化け対応用)
なぜかコメントの日本語が化ける・・・。
[Eclipseでコメントの前の方だけ文字化けする](https://qiita.com/segur/items/60b3711c0c9207d23b2f)
#余談
皆さんの記事を参考にしてせっせとカスタマイズ。
メモなので記事は追加していく～
#Ruby 初心者向け問題 | クラスメソッドとインタンスメソッドを組み合わせてメソッドチェーンして遊ぶ

#Ruby for beginners | Playing a method chain combining class methods and instance methods


次のクラスを使って OK!  と表示させてください

```rb
class Story
 def initialize(to: false)
   @to = to
 end

 def be
   @be = true
   self
 end

 def continued
   puts 'OK!' if @to && @be
 end

 def self.to
   new(to: true)
 end
end
```



# Original by Github issue

https://github.com/YumaInaura/YumaInaura/issues/2366








<!-- Update From Qiita API -->

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
57日目 Javascriptでファイルは読めるが書き出せなさそう。

Javascriptで作ったサイトにCSVを読み書きする機能を追加したいと思ったらどハマりしてしまいました。

###まずは読み込み
```
function getCsv(url){
  //CSVファイルを文字列で取得。
  var txt = new XMLHttpRequest();
  txt.open('get', url, false);
  txt.send();

  //改行ごとに配列化
  var arr = txt.responseText.split('\n');

  //1次元配列を2次元配列に変換
  var res = [];
  for(var i = 0; i < arr.length; i++){
    //空白行が出てきた時点で終了
    if(arr[i] == '') break;

    //","ごとに配列化
    res[i] = arr[i].split(',');
  }
  return res;
}
getCsv("test.csv");
```

これでイケると思ったら全然読まない。コンソールにはこんなエラーが出ていました。

```
 from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https.
```

セキュリティ上の理由でローカルファイルへのアクセスをブロックしているようです。
このブロックを許可するオプション付きでChromeを起動して読ませるとできるらしい。

[Start Google Chrome on Mac with command line switches](https://superuser.com/questions/157484/start-google-chrome-on-mac-with-command-line-switches)

```
sudo /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --args -allow-file-access-from-files
```

できました！
てすが、いつもこのオプション付きでChromeを立ち上げてくださいっていうの、あんまり現実的ではない感じです。

#書き込み
これが大変でした。
Javascriptからファイルを書き出す方法がみつからず。

①ダウンロード
できそう。だけどできればバックグラウンドで動かしたい。

②Node.jsで書き込む
サーバー側で上げられればありかも。

③FilesystemAPI
任意のファイルの編集は無理。サンドボックス内のみ可能。

いろいろ調べたのですがJavascriptだけでファイルの書き込みは難しそうです。

(所要時間２時間)
Azure で使えるkubernetes-version

## Kubernetes Version調べ方

「[しくみがわかるKubernetes Azureで動かしながら学ぶコンセプトと実践知識](https://www.amazon.co.jp/dp/4798157848/)」を読みながら実践していってp.39のAKS Kubernetesクラスターを作るところで次のエラーとなる。

```text
Operation failed with status: 'Bad Request'. Details: Version 1.11.4 is not supported in this region. Please use [az aks get-versions] command to get the supported version list in this region. For more information, please check https://aka.ms/supported-version-list
```

メッセージにあるリンクにアクセスすると使用可能なkubernetes versionの調べ方が載っている。
次のコマンドでバージョンリストを取得できます。

```shell-session
$ az aks get-versions --location japaneast 
{
  "id": "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/providers/Microsoft.ContainerService/locations/japaneast/orchestrators",
  "name": "default",
  "orchestrators": [
                                                                                                                                           
....

    {
      "default": null,
      "isPreview": null,
      "orchestratorType": "Kubernetes",
      "orchestratorVersion": "1.14.6",
      "upgrades": null
    }
  ],
  "type": "Microsoft.ContainerService/locations/orchestrators"
}
```
【C#】文字列→数値変換の色々

文字列を数値に変換することは
割と良くあるけど微妙に忘れがちなので備忘の意味も込めて。
＃16進数文字列の変換とか使うたびに調べているような…

#2進数／8進数／16進数の変換
個人的にはこれを良く使っている。

```C#
var binary = Convert.ToInt32("11", 2); // 2進数
var octal = Convert.ToInt32("11", 8); // 8進数
var hex = Convert.ToInt32("1a", 16); // 16進数

// 上から3, 9, 26になる
```
他にもNumberStylesを使う方法もあるのでそちらも記載。

```C#
var hex = int.Parse("1a", NumberStyles.HexNumber);
```
NumberStyles.HexNumberの部分は
AllowHexSpecifierを指定すれば16進数として扱ってくれるけど
前後に余分な空白があるとNGなので素直にHexNumberとしておくのが無難。

どちらの方法を使っても良いと思うけど
TryParseしたい時はNumberStylesを使う。

```C#
int hex;

if(false == int.TryParse( "xyz", System.Globalization.NumberStyles.HexNumber, null, out hex )
{
	MessageBox.Show( "16進数に変換できないよ" );
}
```

#その他の変換
NumberStylesは指数とか3桁区切りになっている場合に変換出来るので知っておくと便利。

```C#
vat str = "123,456,789";
var num = int.Parse(str, System.Globalization.NumberStyles.AllowThousands);
// 123456789に変換される

str = "123e4";
num = int.Parse(str, System.Globalization.NumberStyles.AllowExponent);
// 1230000に変換される
```
但し桁区切り文字に関しては実行環境の設定に依存するので注意。
![setting.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373724/654bbde8-76be-558e-35d3-0b9853428439.png)
※[コントロールパネル]-[地域と言語]から『追加の設定』ボタンを押下すると表示される
【備忘録】prettierの実行が遅い時の対処法

そこまでファイルがないはずなのに、prettierの実行が以上に遅かった。
もとのpackage.jsonはこんな感じ。

```json:package.json
"scripts": {
  "format": "prettier --write ./**/*.{js,jsx,ts,tsx,md,html}"
}
```

デバッグモードで実行してみる.

```console
$ yarn format --loglevel debug
yarn run v1.13.0
$ prettier --write **/*.{js,jsx,ts,tsx,md,html} --loglevel debug
[debug] normalized argv: {"_":["client/next.config.js","**/*.jsx","client/firebase.ts","client/next-env.d.ts","client/useAuthEffect.ts","gateway/index.ts","server/index.ts","server/schema.ts","server/typegen.ts","server/types.ts","**/*.tsx","**/*.md","**/*.html"],"color":true,"editorconfig":true,"write":true,"loglevel":"debug","plugin-search-dir":[],"plugin":[],"ignore-path":".prettierignore","debug-repeat":0,"config-precedence":"cli-override"}
...

```

normalized argvのところをみるとglobパターンが部分的に展開されちゃっている。
これをみてそういえば、OSやシェルによってはglobパターンを展開しちゃうものもあるというのを思い出したので、globパターンをシングルクオートで囲んでみた。

```json:package.json
"scripts": {
  "format": "prettier --write './**/*.{js,jsx,ts,tsx,md,html}'"
}
```

で、もう一回デバッグモードで実行したら、実行にものすごく時間がかかる。
しかもログをみると、node_modulesの中身を見にいっている様子。

```console
...
[debug] loaded options `null`
[debug] applied config-precedence (cli-override): {}
[debug] resolve config from 'client/node_modules/fbjs/node_modules/core-js/library/modules/$.defined.js'
[debug] loaded options `null`
[debug] applied config-precedence (cli-override): {}
[debug] resolve config from 'client/node_modules/fbjs/node_modules/core-js/library/modules/$.descriptors.js'
[debug] loaded options `null`
[debug] applied config-precedence (cli-override): {}
[debug] resolve config from 'client/node_modules/fbjs/node_modules/core-js/library/modules/$.dom-create.js'
...
```

有名どころのprettierはどうなってるんかと思って、[gatsby.js](https://github.com/gatsbyjs/gatsby/blob/master/package.json#L97の設定)をみたら、
`./**/*`の先頭の`./`が不要なことに気づく。
最終的には下のような形になって、実行も爆速で終わるようになった。

```json:package.json
"scripts": {
  "format": "prettier --write '**/*.{js,jsx,ts,tsx,md,html}"
}
```

`./`がなぜ変な挙動に繋がったかはよく分かってない。

# 参考

https://medium.com/@jakubsynowiec/you-should-always-quote-your-globs-in-npm-scripts-621887a2a784
[Chrome] フリップボードでfilterを使うと1度目の裏面の表示が遅くなる

CSSでフリップボードを作成した際に発見したので、記事にしておきます。

確認できたChromeのバージョン: 76.0.3809.100
※FireFox, Safariでは確認できませんでした。

Chromeで以下HTMLの`back`, `front`に対して`filter`を使うと、`flipBoard`を

```css
transform: rotateY(180deg);
```

で回転させた際に、1度目の回転中、裏面は表示されず回転が終わってからの表示になります。
`drop-shadow`以外でもバグります。

```html:flipBoard.html
<div id="flipBoard">
  <div id="back">
    <img src="back.png">
  </div>
  <div id="front">
    <img src="front.png">
  </div>
</div>
```
```css:style.css
div#flipBoard {
  width: 100px;
  height: 100px;
  position: relative;
  transition: all 1s;
  transform-style: preserve-3d;
}

div#back {
  transform: rotateY(180deg);
}

div#back, div#front {
  width: 100%;
  height: 100%;
  position: absolute;
  backface-visibility: hidden;
  filter: drop-shadow(0px -5px 8px rgba(0, 0, 0, 0.4)); /* <= バグの原因 */
}
```
【Git】gitコマンドを省略  〜エイリアス設定〜

## エイリアスとは

別名、通称...

## 何が出来る？

gitコマンドに別名をつけて、省略することが出来る

以下例

```bash
git checkout master
git log --oneline
git status
git commit -m 'update: ~~~~~'
```

↓

```bash
git co master
git lgone
git st
git cm -m 'update: ~~~~~'
```

## 設定方法

```bash
git config --global alias.[略称] '[gitコマンド]'
git config --global alias.co 'commit'
git config --global alias.logone 'log --oneline'
```

## 例

- cm : commit -m
- co : checkout
- logone : log --oneline
- st : status
- fe : fetch
- me : merge
- br : branch

## 終わりに

何か間違っていることがあればご指摘お願い致します
Cloud Functionの開発（gulp使用）

最近JavaScript（ES6）にもハマっております。
nodeのデプロイ先としてCloud Functionを利用していますが、機能も多く、1人だと割とつまづきながらの開発だったので、メモがてら~~たくさんのタグと共に~~私の知見をまとめました。
ソースはGitHubに[firebase-gulp-sample](https://github.com/bvlion/firebase-gulp-sample)をアップしてあります。
中身などはREADMEを確認していただくとして、今回ハマったりポイントとした点を挙げたいと思います。

## uglifyでES6が圧縮できない

いつも通り「.pipe(uglify())」と書いただけでは以下のようなエラーが発生します。

```
Caused by: SyntaxError: Unexpected token: keyword «const»
```

調べてみると、ES6には対応していないようです。
なので、[こちらの記事](https://qiita.com/zackey2/items/621f0ed94154af439143)を参考にbabel7を使って対応しました。
（ありがとうございました！）

## Circle CIでfirebaseコマンドが見当たらない

そりゃそうです。。。
なのでfirebase-toolsをインストール後、node_modules/.bin/以下から呼び出してデプロイしました。
（.circleci/config.ymlを見ていただければ…）

## 開発中はfirebase serveとgulp watchを同時に使いたい

別にターミナルを2つ立ち上げて対応してもいいのですが、せっかくツールを導入しているので、1コマンドで対応したいところです。
expressであればgulp-live-serverなどがあるようですが、似たようなライブラリは私が探した限りなさそうでした。
なので、原始的にchild_processで立ち上げるようにしました。

``` Javascript
  exec('firebase serve', { cwd: '.' }, (error, stdout, stderr) => {
    if (error) console.log("error: " + error)
    if (stdout) console.log("stdout: " + stdout)
    if (stderr) console.log("stderr: " + stderr)
  })
```

ただ、これだとfirebase serveのログが出力されないので、何かしらtailができるものがあると、よりよいかもしれません。
（ログファイルをwatchかけるとか…）

## functionsのURLをhostingと同じにしたい

あるあるですよね？（ないですか？）
プロジェクト直下のfirebase.jsonにrewriteを追記することで対応できました。

``` json
"rewrites": [{
  "source": "**",
  "function": "app"
}]
```

## Cloud Functionでセッションを使いたい

Expressと連携すればexpress-sessionが使えると思ったのですが、どうも上手くセッションが保持できません。
（インメモリを使わせないようにするとかあるのかな？）
なのでFirebaseStoreを使い、RealtimeDatabase側で管理するようにしました。

## 最後に

どなたかの参考になれば幸いです。
Nuxt.jsでプラグインを入れたらエラーが... Nuxt.js 2.9.0から<no-ssr>の代わりに<client-only>を使おう

Nuxt.jsのバージョンは2.9.2
templateはpugで書いています。

スライダーを使いたくて`vue-awesome-swiper`をインストールして、nuxt.config.jsでプラグインを使えるように修正をして、いざスライダーを書いたんですよ。。（vue-awesome-swiperの使い方は>>[こちら](https://qiita.com/IKEMAKI/items/c68e094f412b04b1afc2)<<を）

```index.vue
<template lang="pug">
        section.section.feature
            swiper(:options="swiperOption")
                swiper-slide スライド１
                swiper-slide スライド２
                swiper-slide スライド３
                swiper-slide スライド4
                swiper-slide スライド5
                swiper-slide スライド6
</template>
```
したら、以下のようなエラーが出てしまいました。

```
[error] [Vue warn]: The client-side rendered virtual DOM tree is not matching server-rendered content. This is likely caused by incorrect HTML markup, for example nesting block-level elements inside <p>, or missing <tbody>. Bailing hydration and performing full client-side render.
(訳）
クライアント側でレンダリングされた仮想DOMツリーがサーバーでレンダリングされたコンテンツと一致しません。
これは、<p>内にブロックレベルの要素をネストしたり、<tbody>が欠落しているなど、
不適切なHTMLマークアップが原因である可能性があります。
ハイドレーションをベイルするか、完全なクライアント側レンダリングを実行してね。
```

## 解決しよう1 ssrをtrueにしたら？
プラグインを設定する時に書いた`ssr: false`が気になったので

``` nuxt.config.js
plugins: [{ src: '~plugins/vue-awesome-swiper', ssr: false }],
```
もしやと取ってみたり`true`にしてみたら

```
window is not defined
```
と怒られたので、一旦`ssr: false`は戻します。

## 解決しよう2 問題の部分をno-ssrで囲んだら？
`<no-ssr>`を使ってサーバーサイドレンダリングの対象からコンポーネントを除外してみました。

```index.vue
<template lang="pug">
        section.section.feature
            no-ssr
                swiper(:options="swiperOption")
                    swiper-slide スライド１
                    swiper-slide スライド２
                    swiper-slide スライド３
                    swiper-slide スライド4
                    swiper-slide スライド5
                    swiper-slide スライド6
</template>
```

エラーが消えた！！

ただし、代わりに以下のような注意文言が現れました。

``` 
[warn] <no-ssr> has been deprecated and will be removed in Nuxt 3, please use <client-only> instead
(訳）
<no-ssr>はNuxt 3で廃止され、削除されます。代わりに<client-only>を使用してください
```
↓↓↓Nuxt.js v2.9.0で追加されたようですね。↓↓↓
- https://github.com/nuxt/nuxt.js/releases/tag/v2.9.0
- [feat(vue-app): add ＜client-only＞ alias for ＜no-ssr＞#5941 · nuxt/nuxt.js · GitHub](https://github.com/nuxt/nuxt.js/pull/5941)

わかりました。私は先生の言うことをよく聞くいい子なので

## 解決しよう３ no-ssrのかわりにclient-onlyを使おう

```index.vue
<template lang="pug">
        section.section.feature
            client-only
                swiper(:options="swiperOption")
                    swiper-slide スライド１
                    swiper-slide スライド２
                    swiper-slide スライド３
                    swiper-slide スライド4
                    swiper-slide スライド5
                    swiper-slide スライド6
</template>
```

これで無事エラーを解消出来ました。
めでたしめでたし。
多段sshを一発で

~.ssh/configを編集

```sh

Host host1
        hostname humidai1
        User root
        Port 443
Host host2
        hostname testdomain.com
        Port 8080
        User root
        ProxyCommand ssh -CW %h:%p host1
        localForward 13389 192.168.0.1:3389
```

host2を指定してssh

```sh

$ ssh host2
```
Visual Studio でASP.NET MVCを使ってみた


###
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346533/fc7c15b3-e862-b5c8-4e72-13586febf518.png)

フレームワークはサーバーに合わせましょう！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346533/24d9936e-f38b-cd47-eaee-8ef86e692ee8.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346533/55f0d5ef-5424-72a3-9782-a5b1a683dbeb.png)

###接続先の変更

####サーバーエクスプローラーから接続変更
[サーバーエクスプローラー]-[データ接続]-[(右クリック)接続の変更]

####Web.configの変更
[接続先のプロパティ]-[接続文字列] をコピー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346533/32ae2cbc-8dde-5b3e-d64a-471a5134597d.png)

[Web.config]-[connectionStrings]を書き換える
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346533/67011bd8-c7db-391a-c1ed-9ade3bde5549.png)


####コントローラー追加

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346533/488ee9a7-deac-cf0f-e3e3-13724b3a004d.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346533/05ff0590-ec19-00d3-3cd3-6299ae108c7e.png)

コントローラーとビュー（フォルダ）が作成される


####View(xxx.cshtml)を追加する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346533/6796b948-db94-90a5-4b27-805a87f10141.png)

####ビューに対応するコントローラーの記述

```Controllers/BooksController.cs
  // GET: Books/Create
        public ActionResult Create()
        {
            return View();
        }
```

####ルーティング
ルーティングはApp_Start/RouteConfig.csによって制御されているが、
基本的な使い方においては特に触る必要なし

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346533/e75cd17d-ac4e-d0b8-7aba-a673a72bf83f.png)

``` App_Start/RouteConfig.cs     
  public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );
        }
```

httｐ://localhost:29400/controller(books)/action(index)/id(オプション)

####スタートアップの設定
スタートページにしたViewの[cshtlmlファイル]-[右クリック]-[スタートページに設定]

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346533/334924a4-1a6d-27c7-fc0f-e97ff1d7d190.png)


[プロジェクト名]-[プロパティ]-[Web]-[(開始動作)ページを指定する]
※デフォルトでは間違っていたので修正した
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346533/d0d75485-22a9-f076-d289-a207f753e9a9.png)

###起動させてみる

####開始ボタンをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346533/4b991e1f-6413-6158-96e9-b92b3f7d7ff3.png)

####表示させたいURLを入力

http://ローカルアドレス/階層/ページ

```
http://localhost:29400/Books/index
```
####テーブルが作成される

この段階ではBooksテーブルは作成されていないが、「Create New」をクリックすることで作成される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346533/f4e20be2-2ae2-3c2b-ec3a-dc8b0141ef18.png)
SafariでjQueryのAjaxでファイルをUploadできない。

#概要
Ajax経由でファイルをUploadしている部分が、MacのSafariブラウザでだけうまくUploadできない現象があった。
safariのバージョンは2019年8月現在の最新版で、確認に使ったバージョンは12.1.1でした。

#結論
SafariでForm要素をclone()で複製した際に、Safariではファイルオブジェクトは空要素としてCloneされるため、挙動が異なります。その結果Safariではファイル要素がアップロードされているようでいて、中身が空になってしまいます。

#詳細
不具合が起きたソースの概略は下記の通り。フォームでファイルを選択すると、Submitボタンを押すことなく、Ajaxで送信し、プレビューに表示するような動作となっています。アップロード中を示す動作や、サーバからのエラー処理などは省いています。

###HTML部分

```html
<img src="/imgages/default.png" id="preview" alt="アップロード画像">
<form action="/fileupload.php" id="fileupload">
    <input type="file" name="upload" id="upload">
</form>
```

### JS部分

```javascript
$('#upload').on('change', function(e){
    e.preventDefault();
    // 下記の部分でコピーされるデータがSafariと他のブラウザで異なります。
    let cloneFormData = $('#fileupload').clone(); 
    let fd = new FormData(cloneFormData.get(0));
    let url = '/uploader.php';

    $.ajax({
        url: url,
        type: 'post',
        contentType: false,
        processData: false,
        cache: false,
        data: fd
    }).done(function (e) {
        $('#preview').attr('src', e.file.uploaded_url); // プレビュー用の画像を表示
    });
});
```

jQueryオブジェクトをcloneしている箇所は下記の部分です。
`let cloneFormData = $('#form_input_file').clone(); `

「ネットワーク」タブから送信しているPOSTデータを見てみると、clone()をした場合、下記のようにfilename が取れていません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102740/4306529c-5d40-fb0d-247e-d8373c0640da.png)
clone()しないで、フォームオブジェクトを直接POSTした場合は下記のようにfilenameが取れています。
（データ本体はSafariでは見えないようで）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102740/edc302b5-cba1-4476-f55c-41b5ae43a8fc.png)
あとは、HTMLプロトコルのヘッダ部分Content-lengthを見ても、何らか大きめのデータをアップしていることが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102740/1a075d12-311e-e6d4-a500-2b1e8178a951.png)

ちなみにデバッガで送信するフォームデータを見るとcloneしなかった場合でもした場合でも、下記のように見えるので中身がよくわかりません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102740/2a0b24a1-db42-497b-6e8a-7151471a15d5.png)

ということで、Safariで ファイルオブジェクトがあるform を clone した場合、
ファイルオブジェクトは空要素としてCloneされるようです。
S3バケットをバブリングにするが、下位フォルダの一部は制限をかけたい

#問題
アクセス制限違いでバケットを分けたくない

#こうした
 * アクセス権限→バケットポリシー

  * hoge/download
  * hoge/content
  * hoge/private <- ここはパブリックにしたくない

```bash
{
    "Version": "2008-10-17",
    "Statement": [
        {
            "Sid": "PublicReadForGetBucketObjects",
            "Effect": "Allow",
            "Principal": {
                "AWS": "*"
            },
            "Action": "s3:GetObject",
            "Resource": [
                "arn:aws:s3:::hoge/download/*",
                "arn:aws:s3:::hoge/content/*"
            ]
        }
    ]
}
```

 * hoge/private は"Resource"に記載しないこと

#メモ
パブリックにしたバケットがあると、awsから親切にお知らせが来る
```
We’re writing to notify you that your AWS account xxxxxx has one or more S3 buckets that allow read or write access from any user on the Internet. By default, S3 buckets allow only the account owner to access the contents of a bucket; however, customers can configure S3 buckets to permit public access.
```
Laravel(5.7)のDeployer利用時のログファイルの問題

Deployerを利用してLaravelをデプロイするとデプロイユーザーの設定によってログファイルのPermissionエラーが発生します。

## サーバーでの対応
ユーザーのGroup設定やファイルが作成する時のディフォルトPermissionの設定を変える等で対応はできると思いますが、ユーザーの設定ができないサーバーを利用していると難しいと思います。また、設定が面倒と考える方もいると思います。

## ConsoleとHttpのログファイルを分ける
logging.phpのtapの設定を行います。

```config/logging.php
        'daily' => [
            'driver' => 'daily',
            'path' => storage_path('logs/laravel.log'),
            'level' => 'debug',
            'days' => 7,
            'tap' => [App\Logging\SapiLogTap::class],
        ],
```

ファイル名を分けるクラースを作成します。

```app/Loggin/SapiLogTab.php
<?php

namespace App\Logging;

use Monolog\Handler\RotatingFileHandler;

/**
 * ログファイルを出力する
 */
class SapiLogTap
{
    /**
     * ログファイル名にインターフェイスの型を入れる
     *
     * @param  \Illuminate\Log\Logger $logger
     * @return void
     */
    public function __invoke($logger)
    {
        foreach ($logger->getHandlers() as $handler) {
            if ($handler instanceof RotatingFileHandler) {
                // ログハンドラーがRatationFileHandlerの場合
                // PHPの間のインターフェイスの型を取得
                $sapi = php_sapi_name();
                // ファイルのフォーマットを定義
                $handler->setFilenameFormat("{filename}-$sapi-{date}", 'Y-m-d');
            }
        }
    }
}
```
## ファイルのPermissionの変更
設定ファイルの修正でできるようです（検証しておりません）。[参考](https://stackoverflow.com/a/55206727)

```config/logging.php
    'daily' => [
        'driver' => 'daily',
        'path' => storage_path('logs/laravel.log'),
        'level' => 'debug',
        'days' => 7,
        'permission' => 0664,    // this line lets the file owner to be www-data:www-data
    ],
```
rubyで継承した親クラスのメソッドを[super]以外の方法で呼び出したい

# 問題

1. 親クラスに子クラスで使う共通のメソッドがある
2. 子クラスで同名のメソッドがあるが、その場合はsuperで呼べる
3. 子クラスで全く別のメソッドから、親クラスの特定のメソッドを呼ぶ時はsuperは使えない

# 例

下の例で

```rb
  def another_method_name
    p "another_method_nameからの呼び出し"
    method_name # => これは自分自身のmethod_nameになる
  end
```

としたい所だが、`C`自身の`method_name`を呼ぶ事になり、paramsなどが違う場合などは`C#method_name`経由で`P#method_name`を呼ぶわけにはいかない。


```rb
# another_method_nameメソッドからはPのインスタンスメソッドとなる
# method_nameが直接呼べない。

class P
  def method_name
    p "from parent"
  end
end

class C < P
  def method_name(caller_name)
    p "calling from #{caller_name}"
    # => Pの同名メソッドが呼べる 
    # ()無しだとparamsも全部渡してしまうので、()付でparams無し
    super() 
  end

  def another_method_name
    p "another_method_nameからの呼び出し"

    # 単純に
    # method_name 
    # としてしまうと、自分自身(C)のmethod_nameを呼ぶ事になる
    # superでは自身のメソッドの親側のメソッドを呼ぶため、method_nameではない

    # P#method_nameは直接アクセスできない 
    # なので、Pクラスからmethod_nameメソッドを取り出して動的に呼ぶ
    P.instance_method(:method_name).bind(self).call
  end
end
```


# 解決方法

```rb
P.instance_method(:method_name).bind(self).call

# または動的にするなら
self.class.ancestors[1].instance_method(:method_name).bind(self).call

# 親のメソッドにparamsがあれば.call(...)で呼ぶ
```
php 参照渡しと値渡しの違いをまとめる

#近況報告

エンジニア転職成功しました。YouTubeでエンジニア転職したい方向けに情報発信しています。

https://www.youtube.com/channel/UCcXQG8lu_EdyP2Cbhtz1bcA



普段何気なく使っている変数への代入ですが、値渡し以外にも参照渡しという方法があるので、
参照渡しと値渡しの概念についてまとめていきます。

##変数

- 値渡し
    - 変数の中の値を渡す

```php
$x = 1; //変数$xに1を代入
$y = $x; //変数$yに$xの値を代入　値渡し
$x = 6; //変数$xに6を代入
print $y;

//結果
1 //$yは$xの値の更新の影響を受けない
```

- 参照渡し
    - 変数のメモリアドレス値を渡す
    - 参照渡しする際は、$の前に「&」を付ける

```php
$x = 1; //変数$xに1を代入
$y = &$x; //変数$yに$xのメモリアドレスを代入　参照渡し
$x = 6; //変数$xに6を代入
print $y;

//結果
6 //$yは$xと同じメモリアドレスを見ているので、$xの値の6が、$yとして出力される
```

##配列

＊後で書く
Gradle Kotlin DSLでOracleのMavenリポジトリからJDBCドライバを取得する

# Oracleアカウントの作成
ユーザー名とパスワードが必要になるので、アカウントを作成する。
[http://maven.oracle.com/](http://maven.oracle.com/)

また、下記ページにて利用規約に同意する必要がある。
[https://www.oracle.com/webapps/maven/register/license.html](https://www.oracle.com/webapps/maven/register/license.html)

# (オプション)gradle.properties作成
```build.gradle``` に直接アカウント情報を記入したくない場合は```gradle.properties```に書いておく。

```properties:~/.gradle/gradle.properties
oracleUsername=<ユーザー名>
oraclePassword=<パスワード>
```

# JDBCドライバ取得
URLに[https://maven.oracle.com](https://maven.oracle.com)ではなく[https://www.oracle.com/content/secure/maven/content](https://www.oracle.com/content/secure/maven/content)を使うところが鍵。

```gradle:build.gradle.kts
repositories {
	maven("https://www.oracle.com/content/secure/maven/content") {
		authentication {
			create<BasicAuthentication>("basic")
		}
		credentials {
			username = oracleUsername  // ユーザー名
			password = oraclePassword  // パスワード
		}
	}
}

dependencies {
	implementation("com.oracle.jdbc:ojdbc8:12.2.0.1")
}
```

# 参考
Get Oracle JDBC drivers and UCP from Oracle Maven Repository (without IDEs)
[https://blogs.oracle.com/dev2dev/get-oracle-jdbc-drivers-and-ucp-from-oracle-maven-repository-without-ides](https://blogs.oracle.com/dev2dev/get-oracle-jdbc-drivers-and-ucp-from-oracle-maven-repository-without-ides)

Can I use the Maven repo with Gradle?
[https://community.oracle.com/thread/3899544](https://community.oracle.com/thread/3899544)

Unable to activate pre-emptive authentication with Kotlin DSL
[https://github.com/gradle/kotlin-dsl/issues/1109](https://github.com/gradle/kotlin-dsl/issues/1109)
初心者でも出来るHTML,JavaScript入門5

## 1.事前知識
- [初心者でも出来るHTML入門1](https://qiita.com/ryome/items/9ec3819e5e9ab5321553)
- [初心者でも出来るHTML入門2](https://qiita.com/ryome/items/4e19c19d3166a01bc0fc)
- [初心者でも出来るHTML入門3](https://qiita.com/ryome/items/72408fb260d1576fcb25)
- [初心者でも出来るHTML,JavaScript入門4](https://qiita.com/ryome/items/152ebca06eda9fe05b39)

事前知識として、上記リンクの内容が必要です。

## 2.文字列と数値
```html:文字列と数値
<script type="text/javascript">
    alert("文字列：Hello!");
    alert("数値："+100);
</script>
```

- `JavaScript` では、`文字列` を扱う際「' '（シングルクォート）」または「" "（ダブルクォート）」で囲む必要がある。
- `JavaScript` では、全ての `数値` は、 `整数` も `浮動小数点数` も内部的に区別されない。
- `JavaScript` において、 `数値` は全て `浮動小数点数` として扱われる。

## 3.テキストの出力
```html:文字列と数値
<script type="text/javascript">
    document.open();//ドキュメントの出力を開始
    document.write('Hello');//ドキュメントに文字列を書き出す
    document.close();//ドキュメントの出力を終了
</script>
```
- `document.write()` は、 `ドキュメント` に `文字列` を書き出す。
- `文字列` として書き出すため、タグ等も書き出しが可能。

## 4.記述例

```html:js1_1.html
<!DOCTYPE html>
<html>
    <head>
        <!-- 付加情報 -->

        <!-- タイトル -->
        <title>JavaScriptの説明</title>

        <!-- 文字コードの指定 -->
        <meta charset="utf-8" />
    </head>

    <body>
        <!-- コンテンツ -->
        
        <!-- インラインスクリプト -->
        <script type="text/javascript">
            document.open();//ドキュメントの出力を開始
            document.write('<h1>h1</h1>');//ドキュメントに文字列を書き出す
            document.write('<h2>h2</h2>');//ドキュメントに文字列を書き出す
            document.write('<h3>h3</h3>');//ドキュメントに文字列を書き出す
            document.close();//ドキュメントの出力を終了
        </script>
        
    </body>
</html>

```

中身の文をコピーして、文字コードは `UTF-8` を指定し、ファイル名を `js1_1.html` でデスクトップに保存するとブラウザではこうなります↓↓

- js1_1.html
![js1_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449867/2b15f8b3-679f-d0af-68df-53bea8e770cf.png)

画像のようになれば成功です。

## 5.GitHub
GitHubにソースコードを公開しています。

https://github.com/ryomeblog/qiita/tree/master/%E5%88%9D%E5%BF%83%E8%80%85%E3%81%A7%E3%82%82%E5%87%BA%E6%9D%A5%E3%82%8BHTML%2CJavaScript%E5%85%A5%E9%96%805

## 6.関連
- [初心者でも出来るHTML,JavaScript入門6](https://qiita.com/ryome/items/4a75d5d3df0c6355accd)
- [初心者でも出来るHTML,JavaScript入門7](https://qiita.com/ryome/items/6d58c666a4b296e8cc02)
LiveDataのテストというかJUnitのRule適用するときについて躓いたところ

LiveDataを使ったViewModelのテストをしていたら、なぜかLiveDataのValueがずっとNullで更新されない問題にぶち当たった。

問題のコード簡易版. `fuga()`で"fuga"って値をPostすると思ってください

```Java

    class HogeViewModelTest {

        @get:Rule
        val rule = InstantTaskExecutorRule()

        private val target: HogeViewModel = HogeViewModel()

        @RelaxedMockK
        lateinit var observer: Observer<String>

        @Before
        fun setup() {
            MockKAnnotations.init(this)

            target.liveData.observeForever(observer)
        }

        @Test
        fun fugaTest() {

            target.fuga()
            assertEquals("fuga", target.livedata.value)
        }
    }
```

これの何が問題だったかって、targetの生成タイミング。
Testクラスインスタンス生成時にtargetもインスタンスを作っていたら、Ruleが適用されていなかった。

↓のように`@Before`の中でテスト対象はInstance生成するとうまくいくので、今後は`@Before`の中でインスタンス生成するようにしていきたいですね。

```Java

    class HogeViewModelTest {

        @get:Rule
        val rule = InstantTaskExecutorRule()

        private lateinit var target: HogeViewModel

        @RelaxedMockK
        lateinit var observer: Observer<String>

        @Before
        fun setup() {
            MockKAnnotations.init(this)
            target = HogeViewModel()

            target.liveData.observeForever(observer)
        }

        @Test
        fun fugaTest() {

            target.fuga()
            assertEquals("fuga", target.livedata.value)
        }
    }
```
「ねぇ、今から晴れるよ」を自動化する！

GAS+YOLPでSlackBotを作ったので紹介してみます。
せっかくなので時事ネタをぶっこみました。
qiitaというが技術ブログみたいなの書くの初めてなのでお手柔らかに。

#GAS？YOLP？Slack？　
**GAS**はgoogle Apps Scriptの略です。詳細はググれ。
googleが提供するJavaScriptで無料でサーバのお世話もなく動作し、
定刻起動などが出来、web公開してwebhookから叩けたりするのでとても楽しいものです。

**YOLP**はYahoo! Open Local Platformの略で、Yahoo! JAPANが提供している地図・地域情報のAPI・SDKです。
これのうち今回は気象情報APIを利用します。
気象情報という名前のくせに降水量の現在値と予報値しか返してこない。
名前負けしてません？

**Slack**に関しては説明いらないよね？

#動作イメージ
<img width="485" alt="hareruyo.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101834/b8301786-9b91-1b5f-733f-d92d5af14694.png">

こんな感じで代々木会館(原作で晴らしたとこのモデル)の雨が止むと教えてくれます。
これで何時でも晴れるよ！って言うタイミングが計れますね！


#スクリプト
スクリプトは以下のような感じです。参考urlとかから頂いたコードが9割です。

```js:imahare.gs
function imahare(){
  var ima = 0;
  var gofungo = 0;
  var message="ねぇ、今から晴れるよ:sunny:";
  //経度、緯度＠代々木会館
  var keido = "139.7016769";
  var ido   = "35.6832461";
  //yolpのAPPID
  var appId = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
  //YOLPをコールする。位置情報と降水情報の粒度を指定
  var url = "https://map.yahooapis.jp/weather/V1/place?coordinates=" + keido + "," + ido + "&output=json&appid=" + appId + "&interval=5";
  var response = UrlFetchApp.fetch(url);
  var js = JSON.parse(response.getContentText());

  //YOLPの結果から今の降水量と5分後の降水量を取得
  ima = js.Feature[0].Property.WeatherList.Weather[0].Rainfall;  
  gofungo = js.Feature[0].Property.WeatherList.Weather[1].Rainfall;
  
  //現在降水量があって5分後予報が0だったら晴れるよっていう
  if(ima > 0){
    if(gofungo == 0){
      //SlackのincomingWebhookのurl
      var postUrl = 'https://hooks.slack.com/services/XXXXXXXXX/XXXXXXXX/xxxxxxxxxxxxxxxxxxxxxxxxx';
      var jsonData =
      {
         "username" : "陽菜",
         "icon_url" : "https://xxxxxx",//適当な画像url
         "text" : message 
      };
      var payload = JSON.stringify(jsonData);

      var options =
      {
        "method" : "post",
        "contentType" : "application/json",
        "link_names": 1,
        "payload" : payload
      };
  
      UrlFetchApp.fetch(postUrl, options);
    }
  }
  
}
```

#参考URL
[SlackとGoogleAppsScript(GAS)を連携する手順・事例](https://tech.tabilabo.co.jp/598/)
[初心者がGASでSlack Botをつくってみた](https://tech.camph.net/slack-bot-with-gas/)
[Yahooが提供する気象情報API(YOLP) を使ってbotにお天気(降水情報)を教えてもらう~pythonでslack bot開発④~](https://qiita.com/takahirono7/items/01b1ef6bd364fffdb3c4)
[Google Apps Script試行錯誤Blog](http://www.pre-practice.net/p/blog-page_21.html)
#あとがき
動作イメージ後半で陽菜に呼び掛けてなんやかんや陽菜が答えてくれてるやつは、
元々こっちを先にやってて今晴れが副産物な感じです。
GAS+YOLP(気象情報)+DarkSky+YAHOO日本語形態素解析API+Googlegiocoding API+google reverse geocodingで動いてますが、気が向いたら紹介します。
ES6のimportでFirebase Admin, Cloud Storageを書く

JavaScript -> TypeScript の変換をしていく中で、なかなか見つからなかったのでメモがてら :pencil: 

```js
import * as admin from 'firebase-admin';
import * as serviceAccount from './serviceAccountKey.json';
import { Storage } from '@google-cloud/storage';

const params = {
  type: serviceAccount.type,
  projectId: serviceAccount.project_id,
  privateKeyId: serviceAccount.private_key_id,
  privateKey: serviceAccount.private_key,
  clientEmail: serviceAccount.client_email,
  clientId: serviceAccount.client_id,
  authUri: serviceAccount.auth_uri,
  tokenUri: serviceAccount.token_uri,
  authProviderX509CertUrl: serviceAccount.auth_provider_x509_cert_url,
  clientC509CertUrl: serviceAccount.client_x509_cert_url
};

// firebase admin
admin.initializeApp({ credential: admin.credential.cert(params) });

// firestore
const db = admin.firestore();
db.settings({
  timestampsInSnapshots: true
});

// cloud storage
const storage = new Storage({
  credentials: {
    client_email: serviceAccount.client_email,
    private_key: serviceAccount.private_key
  }
});
```

以上です :hugging: 

## 参考
- [TypeScriptでfirebase\-admin sdkを使う \- ロップップ](http://ropupu-ropupu.hatenablog.com/entry/2019/02/19/212426)
- [オブジェクトのアップロード  \|  Cloud Storage  \|  Google Cloud](https://cloud.google.com/storage/docs/uploading-objects)
fastlaneで最新のコミットがマージコミットであるかを判定する

リリース作業の自動化でちょこっと書いたもののメモ
(実際の自動化における利用方法はページの末尾に記載)

### 最新のコミットがマージコミットであるか判定

```rb
# 最新のコミットと最新のマージコミットのハッシュの比較により判定
last_commit_hash = Action.sh("git log -1 --pretty=format:\"%H\"")
last_merge_commit_hash = Action.sh("git log -1 --merges --pretty=format:\"%H\"")

return false if last_commit_hash != last_merge_commit_hash
```

### （Optional）予期せぬブランチからのマージでないかを判定
必須ではないが、予期せぬブランチからのマージでないかも判定したい場合は以下のコードも追加

```rb

# 所定のheadブランチ名(正規表現)
branch_regex = ... # "develop" や "release\/\\d+(\\.\\d+){2}" など

if branch_regex.nil? then
  return true
else
  # 最新のコミットメッセージ。マージコミットであるので以下のような形式(GitHubの場合)
  # "Merge pull request #{number} from {repository-name}/{branch-name}"
  last_commit_msg = Actions.last_git_commit_message()

  # 所定のheadブランチからのマージであるかを判定
  return /^Merge.*#{branch_regex}/ === last_commit_msg
end
```

コミットメッセージからheadブランチ名を判定する…とのざっくりしたやり方だが、さしあたり運用においては支障はないのでこのようにしている

### リリース作業自動化における利用
自分のチームでは、以下のような設定でリリース作業を自動化している

1. `master`へのPush時にリリース用処理を行うように設定
2. リリース用処理の一番最初に、所定のブランチからのマージコミットであるかを判定
  - 自分のチームではGitFlowを採用しているので、`release/x.x.x`または`hotfix/x.x.x`
3. ２の判定で問題なければ実際のリリース作業を開始する

GitFlowがきちんと回せていれば`master`ブランチにPushされるのは所定のブランチからのマージのみになっているはずだが、
リリース作業が予期せぬ経路から実行されないよう安全のためこのようにしている

### 補足
headブランチの判定まで含めるとそれなりに長くなるので、以下のようなCustom actionを定義し、リリース作業用のlaneから呼び出すようにしている

- [Gist](https://gist.github.com/gaussbeam/3a454d5c9f038363704ebb3d93f3293c)
expo 34.0.1で起きたエラー


久しぶりのReact Nativeで、いろんなエラーが出てきたので、自分用のメモ。

#エラー
Unable to resolve "react-native-gesture-handler" from "node_modules@react-navigation\native\src\Scrollables.js"

#解決策
react-native-gesture-handlerは、Expo 34以降ではデフォルトに含まれていないようで、
都度インストールが必要らしい。

```terminal
expo install react-native-gesture-handler
```


これで、無事動きました。

他にも今後出てきたら追記します。

##参照記事
https://github.com/expo/expo/issues/5107
IntelliJ IDEA のCSSフォーマット設定について

## 備忘録

intelli Jのフォーマットツールでは、CSSの改行がデフォルトで3行になっている。

これを1行に切り替えたいとき。
<img width="241" alt="スクリーンショット 2019-08-22 17.00.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/475739/1a251e2f-6329-7694-97a3-21449306ece2.png">
IntelliJ IDEA→Preferences
<img width="500" alt="スクリーンショット 2019-08-22 17.02.45.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/475739/d69ca9d9-ab09-f464-6bd1-f22b33f6b833.png">
Editor→CodeStyle→StyleSheet→CSS

設定を下記に変更する。

| 項目 | 初期値 | 設定値 |
|:--:|:--:|:--:|
| In code | 0 | 1 |
| Around top-level block | 0 | 1 |
| Around nested-selector | 0 | 1 |

あとは<kbd>⌘+option+L</kbd>で綺麗にフォーマットされる。
CloudWatch LogsでAWSコンソールでfilterできない量のログをCLIでなんとかする

# こんな課題を解決したい

- CloudWatch Logsでログを調査したい
- 特にログ周りの整備や連携は進んでいないので、現状CloudWatch Logsだけでなんとかしている
- 探したいおおまかな時間とキーワードはわかっている
- AWS Console上でイベントのフィルターで時間とキーワードを指定して検索しようとする
- **ログが多すぎて、いつまで経っても結果が帰ってこない**
- 基本Lambdaのログを想定（他でも使えると思います）

これを、CLIとコマンドを組み合わせて、なんとか周辺のログを取得するお話です

# モデルケース

- 今回は、例えば以下のようなLambdaのログを仮定してみます
  - Lambda関数名: `TestLambda`
  - 取得したい時間: `2019/08/20 10:00 - 10:10` `(1566262800000 - 1566263400000)`
  - 検索したいキーワード: `Error`

## その他条件
- 1日分の該当LogGroupのログがDLできる規模であること
- `AWS CLI`, `jq` が使えること

# 結論

先に利用したコマンドだけ記載するとこんな感じです。

```sh
# ログストリーム一覧取得
aws logs describe-log-streams --log-group-name '/aws/lambda/TestLambda' --log-stream-name-prefix '2019/08/20/[1234]' | jq '.logStreams | sort_by(.lastEventTimestamp)' | jq '.[] | select(.lastEventTimestamp > 1566263400000)| select(.firstEventTimestamp<1566262800000)' | grep -e logStreamName | cut -d '"' -f 4 > log-stream-list.txt

# ログストリーム一覧からログを取得
while read line; do aws logs get-log-events --log-group-name '/aws/lambda/TestLambda' --log-stream-name $line >> all.log; done < log-stream-list.txt

# ログの整形
cat all.log | jq '.events[]| select(.timestamp>1566262800000) | select(.timestamp<1566263400000)' > log_between_timestamp.log
```

# 上記コマンドの解説のようなもの
どういう経緯で上記コマンドになったのか、一応記載しておきます

## CLIでDLしてみよう

- AWSコンソールでうまくいかないなら、CLIを使おう
- AWSコンソールでやろうとしたことをコマンドにするとこんな感じ？
  - `aws logs filter-log-events --log-group-name '/aws/lambda/TestLambda' --start-time 1566262800000 --end-time 1566263400000 --filter-pattern 'Error'`
- 当たり前だがコンソールと同様のことをさせているので返ってこない・・・
- LogStreamがわかれば、Stream名を指定すればすぐに落とせるんだけど・・・
  - e.g.) `aws logs get-log-events --log-group-name '/aws/lambda/TestLambda' --log-stream-name '2019/08/20/[1234]dae4553dv12349gosjgoe2342qwahwks'`
  - [version]まではわかっても、そのあとはわからないと思います

## 該当しそうなLogStream全部とる

今回の主題です。
大抵Streamがどれかはわからないので、当てはまりそうなStreamは全部取ってこようと思います。

### Stream名の一覧を取得する

当てはまりそうなStream名がわからないと、結局`get-log-events`で取得できません。
Stream名の一覧を取得してみます。
`firstEventTimestamp`, `lastEventTimestamp` で絞り込めます。
jqの`sort_by`と`select`を使って絞ります。

```sh
aws logs describe-log-streams --log-group-name '/aws/lambda/TestLambda' --log-stream-name-prefix '2019/08/20/[1234]' | jq '.logStreams | sort_by(.lastEventTimestamp)' | jq '.[] | select(.lastEventTimestamp > 1566263400000)| select(.firstEventTimestamp<1566262800000)' | grep -e logStreamName | cut -d '"' -f 4 > log-stream-list.txt
```

### リストを元に実際にログを取得する

以下のような感じで、対象のStreamからログ取得するコマンドをぐるぐる回して1つのログファイルを作ります。
1つにするのが大きそうなら、shellなどにして適宜ファイル分けるなり、整形したりしてください。

```sh
while read line; do aws logs get-log-events --log-group-name '/aws/lambda/TestLambda' --log-stream-name $line >> all.log; done < log-stream-list.txt
```

### ログ内のメッセージを欲しい timestamp で絞る
基本的に、1つのLogStreamには、`lastEventTimestamp`までのログが入っており、開始時刻はわかりません。
目的の時刻よりはかなり多いはずなので、絞り込みます。

```sh
cat all.log | jq '.events[]| select(.timestamp>1566262800000) | select(.timestamp<1566263400000)' > log_between_timestamp.log
```

## 解析を行う

以上で目的の時刻間のログのみが取れたはずです。
あとは普通に`grep 'Error'`などで探して、Hitした部分と同じ`RequestID`で処理を抽出して、同様に`jq`などを駆使して解析できるはずです。
Ubuntu18.04にJuman++ V2をインストール

# この記事の対象者
- AI Chatbotや自然言語処理に興味がある。
- MeCabだけでなく、Juman++が使用してみたい
- Jumanはインストールでできたが、Juman++のインストール方法がよくわからない

# 環境
- OS：Ubuntu-18.04

# Juman++をインストール

今回は処理速度が大きく向上したJuman++のV2を使用していきます。
（あくまでV2は開発版なので、ご利用の際は自己責任でお願いいたします）
https://github.com/ku-nlp/jumanpp/releases

※Juman++の1.0系はこちらからインストールできます
http://nlp.ist.i.kyoto-u.ac.jp/index.php?JUMAN%2B%2B


## Juman++のソースをダウンロードして解凍

```bash
# jumanpp-2.0.0-rc3 download
wget https://github.com/ku-nlp/jumanpp/releases/download/v2.0.0-rc3/jumanpp-2.0.0-rc3.tar.xz
# unzip a file
tar xvf jumanpp-2.0.0-rc3.tar.xz
```

## GNU C コンパイラをインストール（追記：2019年9月26日）

Ubuntuの場合、```build-essential``` パッケージをインストールすることで gcc などの必要なツールがまとめてインストールされます。

```bash
sudo apt update -y
sudo apt upgrade -y
sudo apt install build-essential -y
```

## cmakeをインストール

```bash
sudo apt install cmake -y
```

## コンパイル用のフォルダを作成

```bash
cd jumanpp-2.0.0-rc3/
mkdir build
```

## juman++をコンパイル。

```bash
cd build/
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local
make
```

```-DCMAKE_INSTALL_PREFIX```には、```make install```した時のインストール先を設定できます。デフォルトは、UNIXでは```/usr/local```、Windowsでは```C://Program Files```です。

```-DCMAKE_BUILD_TYPE``` については、[こちら](https://qiita.com/shohirose/items/637f4b712893764a7ec1#%E3%83%93%E3%83%AB%E3%83%89%E3%81%AE%E7%A8%AE%E9%A1%9E%E3%81%AB%E3%82%88%E3%81%A3%E3%81%A6%E3%82%AA%E3%83%97%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%92%E5%A4%89%E3%81%88%E3%82%8B)(項：ビルドの種類によってオプションを変える)の記事が詳しいです。

## コンパイルが完了したら、インストール開始

```bash
sudo make install
```

## Juman++がインストールできたか確認

文字列を品詞分解してみる。

```bash
echo すももももももももももも | jumanpp
```

以下のように出力されれば、インストール成功です。

```bash
すもも すもも すもも 名詞 6 普通名詞 1 * 0 * 0 "自動獲得:テキスト"
@ すもも すもも すもも 名詞 6 普通名詞 1 * 0 * 0 "代表表記:酸桃/すもも 自動獲得:EN_Wiktionary"
も も も 助詞 9 副助詞 2 * 0 * 0 NIL
もも もも もも 名詞 6 普通名詞 1 * 0 * 0 "代表表記:桃/もも ドメイン:料理・食事 カテゴリ:植物;人工物-食べ物 漢字読み:訓"
@ もも もも もも 名詞 6 普通名詞 1 * 0 * 0 "代表表記:股/もも カテゴリ:動物-部位"
も も も 助詞 9 副助詞 2 * 0 * 0 NIL
もも もも もも 名詞 6 普通名詞 1 * 0 * 0 "代表表記:桃/もも ドメイン:料理・食事 カテゴリ:植物;人工物-食べ物 漢字読み:訓"
@ もも もも もも 名詞 6 普通名詞 1 * 0 * 0 "代表表記:股/もも カテゴリ:動物-部位"
も も も 助詞 9 副助詞 2 * 0 * 0 NIL
もも もも もも 名詞 6 普通名詞 1 * 0 * 0 "代表表記:桃/もも ドメイン:料理・食事 カテゴリ:植物;人工物-食べ物 漢字読み:訓"
@ もも もも もも 名詞 6 普通名詞 1 * 0 * 0 "代表表記:股/もも カテゴリ:動物-部位"
EOS
```

品詞分解したファイルを出力する場合は、こんな風に使います。

```bash
cat source.txt | jumanpp > sumomo.csv
cat sumomo.csv
```

# まとめ
以下、上記コードをバッチ処理で実行できるソースです。

```bash
# jumanpp-2.0.0-rc3 download
wget https://github.com/ku-nlp/jumanpp/releases/download/v2.0.0-rc3/jumanpp-2.0.0-rc3.tar.xz
# unzip a file
tar xvf jumanpp-2.0.0-rc3.tar.xz
# cmake install
sudo apt install cmake -y
# build jumanpp
cd jumanpp-2.0.0-rc3/
mkdir build
cd build/
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local
make
# install jumanpp
sudo make install
```

以上
【AWS】 EC2インスタンスのstop状態中でのEBSの扱いに注意 [クラウド破産注意][やらかし画像あり]

# 【AWS】 EC2インスタンスのstop状態中のEBSの扱いに注意 [クラウド破産注意] 【画像あり】


内容は表題の通りなんですが、はじめに、下記はテスト環境です。

<img width="1094" alt="スクリーンショット 2019-08-30 11.09.522.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/344266/121fcb81-a643-1d84-a3ec-2d09bc86359b.png">

## 料金体系

EC2は従量課金なので、この状態であればt3.smallのインスタンスのみの料金だけ課金される思いますよね！？

実際、AWSの公式でもこのような記載があります。

---

<img width="909" alt="スクリーンショット 2019-08-30 11.38.53.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/344266/3bf24eae-7be3-a77c-a959-d5172a11405c.png">

---

## EC2 は EBS とセット と考えて！！
でも... 違うんですよ。EC2はEBSとセットなんです(当たり前と言ったらそうですが、、、)！
1番上のEC2の状態でのこの状態のときのEBSの画面はこちら

<img width="1148" alt="スクリーンショット 2019-08-30 11.21.312.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/344266/ac8053ef-c9f6-d226-7974-ec252829a676.png">

EC2インスタンスがstop状態でもEBSはアタッチしている状態になっています。
要は使っている状態と同じです。

EBSはそこまで高額ではないので多少はいいかと思うところもありますが、
油断していると同じ失敗をしますよ。


## 失敗あるある事例がこちら

実際にやらかして、経理の人に怒られかけた事案です... w

(実際は心の中では怒っていたと思いますが) とても理解のある会社なので素直に謝ったら怒られませんでしたw

ごめんなさい m(_ _)m 


<img width="1147" alt="スクリーンショット 2019-04-26 16.31.492.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/344266/a0f27bf5-6aa3-c57a-c369-37a32be9f16d.png">

これは実際のその時の画像です。

本番環境を構築テストしている時に同様の設定で試していたんですが、
終わったあとにEC2をstop状態にして、数ヶ月放置してしまったんですね...

実際は9TBのEBSを5ヶ月放置してしましました...
(普通はこんなにつかわねーよっているツッコミはしないでくださいw)


そしたら↓のようになりました。
AWs Billing内のコストCost Explorerの画像です。


<img width="918" alt="スクリーンショット 2019-04-26 16.58.2123.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/344266/aa534a6e-e31d-e61d-a6af-8a1415676246.png">


ある時点からEC2-Otherが爆発的にあがっていますよね...
ちなみに請求は毎月10万円くらい来ました Σ(ﾟдﾟ;) ﾇｵｫ!?
全部で60万円位やらかしました。個人アカウントだったらお小遣いが半年剥奪されるレベルだと思います。


便利な世の中になり、クラウドを活用する企業が増えてきたのはいいことですが、
このような危険を潜んでいるということを心に留めておきいていただきたく記事にしました。

ちゃんと使えばこれ以上便利なものはないので、ご利用は計画的に！ってことですね。


では、よいAWSライクを！
有線LAN無線LANの通信速度

インターネットに接続する方法には有線と無線の２つの方法があります。
有線LANは速度が速い代わりにLANケーブルでルーターとPCを繋げる必要があり、無線LANは速度が有線LANより遅いですが、ケーブルを必要としないため利便性が高いです。

##有線

有線LANではLANケーブルが必要となります。

###ルーター有線LANポート

|規格              |速度                |
|:-----------------|:------------------|
|10GBASE-T         |	10Gbps|
|1000BASE-T        |	1Gbps|
|100BASE-T         |	100Mbps|
|10BASE-T          |	10Mbps|

###有線LANケーブル

|規格|対応ポート規格|
|:-----------------------|:----------------------|
|CAT5|10BASAE-T 100BASE-TX|
|CAT5e|10BASE-T 100BASE-TX 1000BASE-T|
|CAT6|10BASE-T 100BASE-TX 1000BASE-T 1000BASE-TX|
|CAT7|10BASE-T 100BASE-TX 1000BASE-T 1000BASE-TX 10GBASE-T|

##無線

無線LANでは帯域を気にする必要があります。
2.4GHzは、屋内、屋外でも使用可能ですが、他の機器の周波数に影響されやすいです。
5GHzは、他の機器からの周波数の影響は少ないですが、屋内のみでの使用になります。

###無線LAN（Wi-Fi）

|規格              |速度    |帯域         |
|:-----------------|:-------|:------------|
|IEEE802.11ad      |6.7Gbps|60GHz帯      |
|IEEE802.11ac      |6.9Gbps|5GHz帯       |
|IEEE802.11n       |300Mbps|2.4G帯/5GHz帯|
|IEEE802.11a       |54Mbps |5GHz帯       |
|IEEE802.11g       |54Mbps |2.4GHz帯     |
|IEEE802.11b       |11Mbps |2.4GHz帯     |


##その他

ルーターとの接続以外にもPCとの通信には様々な方法があります。

###bluetooth
|規格              |速度    |帯域         |
|:-----------------|:-------|:------------|
|IEEE 802.15.1|24Mbps|2.4GHz|

###USB
|規格              |速度    |
|:-----------------|:-------|
|USB 1.0|	12Mbps|
|USB 1.1|	12Mbps|
|USB 2.0|	480Mbps|
|USB 3.0| 5Gbps|
|USB 3.1| 10Gbps|
|USB 3.2| 20Gbps|
|USB 4|	40Gbps|

###ATA
|規格              |速度    |
|:-----------------|:-------|
|SATA2.0|　3Gbps|
|SATA3.0|　6Gbps|