OmniAICreator/Qiita-1.07M huggingface dataset:
@ionic/vue + Capacitorでクロスプラットフォームの未来を覗いてみる


先日行われたFrontend Conference Fukuoka 2018で [Web開発者のためのクロスプラットフォームアプリ開発] (https://speakerdeck.com/7nohe/webkai-fa-zhe-falsetamefalsekurosupuratutohuomuapurikai-fa) という内容で発表させてもらいました。

その中でも注目しているIonicですが、Vueでも使えるようになるということで、簡単ではありますが動かしてみます。

さらにそれをCapacitorでiOSアプリとして動かしてみようと思います。



## 環境

- node 8.12.0
- vue ^2.5.17 (vue cli)



## プロジェクト作成

```
$ vue create ionic-vue-app  
$ cd ionic-vue-app
$ vue serve
# またはGUIからビルド
$ vue ui
```


これで、初期画面がブラウザで表示すれば準備OKです。



## @ionic/vueの追加
```
$ npm install @ionic/vue
```


IonicのUIコンポーネントを使ってみます。

使えるコンポーネントは以下から参照できますが、@ionic/vueはまだalpha版ということもありうまく動かないものも多くあります。

https://beta.ionicframework.com/docs/components

```
// main.js
import Vue from 'vue'
import App from './App.vue'
import Ionic from '@ionic/vue';

Vue.use(Ionic);

Vue.config.productionTip = false

new Vue({
  render: h => h(App),
}).$mount('#app')

```
    
```
// App.vue
<template>
  <div id="app">
    <ion-grid>
      <ion-row>
        <ion-col>
          <ion-button>Ionic Button</ion-button>
        </ion-col>
        <ion-col>
          <ion-toggle></ion-toggle>
        </ion-col>
      </ion-row>
    </ion-grid>
  </div>
</template>

<script>
export default {
  name: 'app',
  components: {}
}
</script>

```

こんな感じでボタンを表示してみました。

<img width="375" alt="localhost_8081_(iPhone 6_7_8).png" src="https://qiita-image-store.s3.amazonaws.com/0/52622/86e73749-3e71-19c8-45d1-d9d91a68058c.png">


## Capacitorの導入


```
$ npm install @capacitor/core @capacitor/cli
$ npx cap init [appName] [appId]
```

## Vueアプリのビルド

```
$ npm run build
```

## iOSアプリの作成

```
$ mv dist www
$ npx cap add ios
$ npx cap sync
```

Capacitorはwwwを元にiOSアプリを作成します。
するとiosディレクトリができて、Xcodeを開いてビルドすることができます。

```
$ npx cap open ios
```

すると、Xcodeが立ち上がり、動かせましたが、すごい崩れました笑。

<img width="407" alt="スクリーンショット 2018-12-15 23.31.08.png" src="https://qiita-image-store.s3.amazonaws.com/0/52622/8005edb4-4e29-8aa7-f86b-7352afc8ba2d.png">

Androidも同様の流れで作成できます。

## まとめ

まだまだ使える機能は少ないですが、

Ionic + Vue + Capacitor の組み合わせで、クロスプラットフォームアプリの可能性が少し見ることができました。

CapcaitorではElectronアプリも作れるので、早く正式リリースして欲しいです！
Unityシーン切り替えとファイル読み込み高速化手法その１

# 概要
他の記事ではあまり記述されていない高速化手法を延々と並べていく
シーン切り替えやファイル読み込みが遅くて困っている人向けの記事
対象プラットフォームはiOS、Android

# 一覧

- シーン切り替えを行わずprefab読み替えをする
- GCやResources.UnloadUnusedAssetsのコールを限定する
- コルーチンリストを使って並列でコルーチンを回す
- AssetBundleを考慮したファイルパッキングと、どのパスからでもファイルを読めるLoaderを用意
- リソースのキャッシュと破棄を行う機能
- SpriteAtlasを使いまわす

# シーン切り替えを行わない
SceneManager.LoadSceneを使用したシーン切り替えは遅いので、起動シーン以外は使わないようにする
ただし、ライティングがシーンに紐づくのでライティングが異なるステージなどはマルチシーンで読み込みを行う
各画面ごとにprefabを作成して読み替える作りにすると高速に画面切り替えを行うことが出来る
この時、GCやResources.UnloadUnusedAssetsを呼ぶと遅くなってしまうので呼ばないこと

GCやResources.UnloadUnusedAssetsはバトルなど大きな括りの画面に遷移する時にメモリ使用量をみて、危険域に達していたら呼ぶようにする

# prefab読み替えと画面ごとの開発シーン
ゲーム中はシーン切り替えを基本行わないが、全くシーンを使わないと各画面の開発が面倒になってしまう。
この問題を解決するには、各画面ごとにシーンを作成してシーンにはcanvasオブジェクトを配置し、その下に画面として使うprefabを作成して画面を構築していく。

ゲームで使うシーンにも常時canvasを1つ常駐させるようにして、ゲーム中はそのcanvasの下に上記で作ったprefabを読み替えるようにする。

# コルーチンリストを使って並列でコルーチンを回す
ある画面に入るときに「通信」「画面を構築するprefabのロード」をそれぞれコルーチンで作成して同時に実行することにより、並列で処理が走りロードが高速化される。

```CoroutineList.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CoroutineList
{
	List<IEnumerator> enumerators = new List<IEnumerator>();
	List<Coroutine> coroutines = new List<Coroutine>();

	public void Add(IEnumerator co)
	{
		enumerators.Add(co);
	}

	public void AddRange(IEnumerable<IEnumerator> cos)
	{
		enumerators.AddRange(cos);
	}

	public IEnumerator WaitForCoroutine(MonoBehaviour mb)
	{
		coroutines.Clear();
		foreach (var e in enumerators)
		{
			coroutines.Add(mb.StartCoroutine(e));
		}
		enumerators.Clear();

		foreach (var co in coroutines)
		{
			yield return co;
		}
	}
}
```

```sample.cs
using UnityEngine;

public class Sample : MonoBehaviour
{
	IEnumerator Start()
	{
		// ロード処理を並列で実行する
		var cl = new CoroutineList();
		cl.Add(APIConnect());
		cl.Add(LoadPrefab());
		cl.Add(LoadExtra());
		yield return cl.WaitForCoroutine(this);
	}

	IEnumerator APIConnect()
	{
		// 通信処理をごにょごにょ
	}

	IEnumerator LoadPrefab()
	{
		// プレハブ読み込みをごにょごにょ
	}

	IEnumerator LoadExtra()
	{
		// その他並列で読み込みたいものをごにょごにょ
	}
}
```

[その２](https://qiita.com/sawasaka/items/a97f94fc33ff0d2bf29b)を書きました。
和訳:Environment Design Best Practices


# Environment Design Best Practices

この記事はUnityのml-agents [Environment Design Best Practices](https://github.com/Unity-Technologies/ml-agents/blob/master/docs/Learning-Environment-Best-Practices.md)の和訳になります.

意訳があります.

この記事は強化学習の環境を作る際に役立つ一般的なテクニックについて書かれています.

また,Brainなどのml-agents独自の用語は強化学習の一般的な用語に解釈して翻訳しています.

文末の()には補足を入れてます.
## 概略

* エージェントがタスクを学習できるかを確認できるように学習するタスクはもっとも簡単なバージョンにし,そこから時間経過に応じてタスクの複雑性を増加させる. 
 このやり方は,自分で作ることもできるし, ml-agentsに用意されているカリキュラムラーニングの仕組みを用いても作成することができる. ([カリキュラムラーニングについて](https://github.com/Unity-Technologies/ml-agents/blob/master/docs/Training-Curriculum-Learning.md)).
*  可能であれば,自分でそのタスクが達成できるかを確かめた方が良い.
* 学習させるときは複数のエージェントで学習を回した方が良い. そうすることで経験(学習時に得られる情報)が増えるので学習がより早くなる.
## 報酬(Reward)

* 学習の安定化のため与える報酬の大きさは**1以下**にすべき.
* 目的とする振る舞いを形成するためには負の値の報酬よりも正の値を与えた方が良い.
* 移動を行うタスクにおいては,  典型的に,+0.1の小さい報酬を目的地に前進した場合に与える.
* エージェントがタスクを早く終わらせたい場合,タスクが完了するまで-0.05の報酬をペナルティとして与え続けるのが良い.この報酬設定を行う場合,エピソードの終了とタスクの完了は同時に起こるべき.(1エピソードで複数タスクにはこの報酬設定は合わないって感じだと)
* 大きすぎる負の値の報酬はエージェントがより良い報酬を得るために負の報酬を生じる行動のようなことを行わないようになることもある.エージェントが負の報酬に対して過敏になってしまう.(何も行動しない方がいいと学習してしまう感じ)
## 状態値のベクトル(State)
ml-agentsではStateのことをObservatin(観察)と呼んでいます.

Vector Observations(ベクトルの状態値と訳した)はプレイヤーの速度や位置情報,敵の情報などの数値情報をStateとして渡すことができます.一方VisualObservationは画像をStateとする場合です.

* ベクトルの状態値はエージェントが最適な行動を行わせるために関係のある全ての変数を含むべきである.
* 時間をまたいで状態を記憶する必要があるか状態を時間ごとに比較する場合,`Stacked Vectors`のパラメータを増加させることで過去から現在の複数ステップ状態を持つことができる.
* (Sword, Shield, Bow)のような分類的な状態はone-hot で表現するべきである.
   (例えば, `3` > `0, 0, 1`).
* 数値ではない値を除いて, 全ての状態値は0~1(or -1~1)に正規化するべき. 
* なるべく位置情報は相対座標に変換して状態に渡すべき.
この位置情報はエージェントの位置と関係があることが多い.(エージェント（プレイヤ)との相対位置を状態として渡すといいみたい)

## 行動のベクトル(Action)

* 行動の値が連続値の時,行動値は適切な値にクリッピングするべき.
ml-agentsで実装している学習アルゴリズムPPOでは連続値である場合行動の値は自動で-1~1にクリップされている.しかし,他の学習システムを使う場合にはクリッピングを行う必要がある. 

* 出力する行動値のベクトルのサイズはエージェントが使用する行動だけにし,ベクトルのサイズが大きくなりすぎないようにする.
ベクトルのサイズが大きいと学習の効率が落ちることがある.
便利なCSSテクニック

# 要素を数えて番号をふる 
##counter()
counter関数は要素を数えることができるもので、例えばリスト要素などで効力を発揮します。

```html:html
<ol>
　　<li>池袋で山手線に乗る</li>
　　<li>渋谷で東急東横線に乗り換え</li>
　　<li>自由が丘で下車する</li>
</ol>
```
スタイルシートを指定していなければ、以下のように出力されます。

```
1. 池袋で山手線に乗る
2. 渋谷で東急東横線に乗り換え
3. 自由が丘で下車する
```
以下のようなスタイルシートを適用してみましょう。

```css:css
body {
　　counter-reset: i;
}
li:before {
　　counter-increment: i;
　　content: “手順” counter(i) “：”;
}
```
すると、以下のようになります。

```
　手順1. 池袋で山手線に乗る
　手順2. 渋谷で東急東横線に乗り換え
　手順3. 自由が丘で下車する
```

#要素内の値を展開する
##attr()

attr関数は、要素内の値を展開するための関数です。
HTML5では、「data-」で始まるカスタム属性が使用できるので、attr関数はカスタム属性と一緒に用いられることも多いようです。

```html:html
<li data-label="ToDo:">池袋で山手線に乗る</li>
```

```css:css
li:before {
　　content: attr(data-label);
}
```

```
ToDo: 池袋で山手線に乗る
```

#要素の最小値と最大値を指定
##minmax()
minmax関数は値に数字や キーワードを使って、要素の最小値と最大値を指定していきます。
CSSグリッド レイアウトと一緒に用いることで、簡単な CSSで高度なレスポンシブデザイン対応のレイアウトを作成することができます。

```
minmax(min, max)
```
```css:css
.grid {
　　display: grid;
　　grid-template-columns: minmax(100px, 200px) 1fr 1fr;
}
```
F#を横目にElixirで「こんにちは世界」


---

(この記事は[「Elixir Advent Calendar 2018」](https://qiita.com/advent-calendar/2018/Elixir)の15日目です)

---

# Summary

`F#`と`Elixir`のちょっとしたコード比較をしてみました

## Motivation

`BashScript`で書いたスクリプトの速度を改善したい
`Elixir`で書いたら早くなるかも？

問題の`BashScript`はこちら
[古い写真のアルバムをスマホで見るようにしたお話 05-05 BashScriptで連番振りスクリプト書いてみた](https://qiita.com/callmekohei/items/beba68200239c895d098#05-05-bashscript%E3%81%A7%E9%80%A3%E7%95%AA%E6%8C%AF%E3%82%8A%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88%E6%9B%B8%E3%81%84%E3%81%A6%E3%81%BF%E3%81%9F)


## Goal

`Elixir`の「こんにちは世界」レベルに最速でなる！

## Way

ちょっとだけ知ってる`F#`と比較することで
手早く`Elixir`の「こんにちは世界」レベルに行く


## 実際に書いたコード

[BashScript を Elixir で書き直してみたっ（２倍速〜)](https://qiita.com/callmekohei/items/0dee2d07d98726537943)

## F#とElixirの簡単な比較コード

F#

```fsharp
// File extension 
// foo.fsx

// binding
let foo = 123

// function in pipe
"foo" |> fun s -> stdout.WriteLine( s )
```

Elixir

```elixir
# file extension
# foo.exs

# Binding
foo = 123

# function in pipe
"foo" |> fn s -> ... end
"foo  |> &( &1  )
```

print

```fsharp
// fsharp
"hello" |> stdout.WriteLine
[1..5]  |> printfn "%A"

// hello
// [1; 2; 3; 4; 5]
```

```elixir
# elixir
"hello" |> IO.puts
1..5    |> IO.inspect

# hello
# 1..5
```

iter

```fsharp
// fsharp
["foo";"bar";"baz"]
|> List.iter stdout.WriteLine

// foo
// bar
// baz
```

```elixir
# elixir
["foo","bar","baz"]
|> Enum.with_index()
|> Enum.each(fn {e,_} -> IO.puts e end)

# foo
# bar
# baz
```

tuple

```fsharp
// fsharp
("foo","bar","baz")
|> fun (_,x,_) -> stdout.WriteLine x

// bar
```

```elixir
# elixir
{"foo","bar","baz"}
|> elem(1)
|> IO.puts

# bar
```

type cast( int -> strings )

```fsharp
// fsharp
(1).ToString().GetType()
|> stdout.WriteLine

// System.String
```

```elixir
# elixir ( typeof()がなさそう？ )
to_string(1)
|> is_bitstring
|> IO.puts

# false
```

parallel

```fsharp
// fsharp
let hello1 = async { stdout.WriteLine("hello") }
let world1 = async { stdout.WriteLine("world") }

[hello1;world1]
|> Async.Parallel
|> Async.RunSynchronously

// hello world or world hello
```

```elixir
# elixir
["hello","world"]
|> Task.async_stream( &( IO.puts &1 ) )
|> Enum.to_list()

# hello world or world hello
```

module and function ( elixir has no class )

```fsharp
// fsharp
module foo =

    let bar baz =
        stdout.WriteLine( baz )

foo.bar "aaa"

// aaa
```

```elixir
# elixir
defmodule Foo do

  def bar( baz ) do
      IO.puts( baz )
  end

end

Foo.bar "aaa"

# aaa
```


## いくよ？

ほむほむ
こんなところでしょうか？
では・・・

![foo.png](https://qiita-image-store.s3.amazonaws.com/0/149269/68edf3b8-4912-724d-7496-f33df39372c7.png)

できたーーー！
ありがとうございますっ！
当たり判定が狭い広告の判定を検証してみた


はじめまして。
Qiitaへの記事の投稿は初めてなのですが、
今日はAdvent Calendar15日目の記事として投稿させていただきます。

#絶対押してんじゃん

さて、ネットサーフィンをいていると時折遭遇するのが**✗の小さすぎる広告**。あの当たり判定の小さすぎるButtonにとって私は日々苦しめられています。あの広告によって、世界中で一体どれだけの時間が奪われているのでしょうか。
<img width="224" alt="スクリーンショット 2018-12-15 23.18.28.png" src="https://qiita-image-store.s3.amazonaws.com/0/326888/197af6e1-5bec-1bc7-28b1-f95410bb3f3a.png">

また、あのボタンの当たり判定は本当にあのButtonの大きさのとおりなのでしょうか。かなり怪しいと思います。今回は実際に検証してみました。

## 擬似的な広告で検証してみる。

広告のButtonの当たり判定が小さすぎると感じるのは気の所為で、実は自分の指のAIM力不足だった。ということも十分考えられたので
Xcodeで擬似的な広告を消すだけのiOSアプリを作成しました。わざわざ説明しなくてもいいかなとは思います。

```ViewController.swift
import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var labelA: UILabel!
    @IBOutlet weak var buttonA: UIButton!
    @IBOutlet weak var viewA: UIButton!
    
    @IBAction func tappedHide(_ sender: Any) {
        buttonA.isHidden = true
        viewA.isHidden = true
        labelA.text = "Tapped!"
    }
    override func viewDidLoad() {
        
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }


}
```
<img width="300" alt="スクリーンショット 2018-12-15 23.17.18.png" src="https://qiita-image-store.s3.amazonaws.com/0/326888/5cbf9a04-ec53-a91f-f272-ac0877662439.png">


iPhoneの実機実行してみるとびっくり。私の大きな親指でも想像よりも難無くピンポイントに✗ボタンを押せてしまいました。想像より遥かに正確に✗ボタンに指が届きます。人間の指と脳って案外正確なものですね。~~また一つ自分のiPhoneに無駄なアプリがが増えていきます~~。




## 実際の広告で✗ボタンの当たり判定を検証する

では一体あの✗ボタン激小広告の当たり判定の広さはどのようなものなのか実際に検証してみます。

iOSのTweaks(脱獄アプリ)に[AutoTouch](https://tools4hack.santalab.me/jbapp-me-autotouch-autotouch.html)というアプリが存在します。操作している指の動きを記録し、それをもとに自動操作を実行したりするアプリです。指の動きはLuaスクリプトで書かれているので、それを編集して1px単位の細かい操作を実行できます。


今回はこの大人気音楽ゲームの広告で試してみましょう。

![FullSizeRender 2.jpg](https://qiita-image-store.s3.amazonaws.com/0/326888/05564b14-788e-f666-dec3-2d3a5731065d.jpeg)

×ボタンの中心座標は**(1093,597)**で、×ボタンの直径はこの端末では**41px**でした。そこでLuaのスクリプトで遠くから×ボタンに向かって1pxずつタップする場所を変えながら×ボタンの中心へタップポイントを下の画像のように動かしていき、中心から何pxで反応するのか確かめてみます。

<img width="320" alt="IMG_3199.JPG" src="https://qiita-image-store.s3.amazonaws.com/0/326888/3012944a-a724-0479-93ac-d5c39321e23a.jpeg">


コードはとてもシンプルです。Luaは見栄えが良いですね。

``` AdsTouchTest.lua
y = 592
x = 1087


color = getColor(y,x)
centerY = y
sec = 1000000

for i = 50,0,-1 do
	tap(centerY + i, x)
	usleep(sec/2)
	if color ~= getColor(y,x) then
		alert(i)
		break
	end
end

```
#### 結果
結果は**15(px)**となりました。

![FullSizeRender 4.jpg](https://qiita-image-store.s3.amazonaws.com/0/326888/aeee3966-e8bf-ddc6-8689-5f060df81b8f.jpeg)
## 当たり判定は小さかった

xボタンの半径は21.5pxなわけですが、タッチできる範囲は中心から15px以内っぽい。この広告の×ボタンのタップ可能範囲で実際よりも小さい。
当たり判定はButtonの円に内接する正方形だったのかもしれません。21.5/√2でだいたい辻褄が合うような気もします(わからんです)

# まとめ
広告によって違いはあるとは思いますが、Buttonのタッチの判定が狭いのは気の所為ではなく本当にタッチできる範囲が狭いこともあるということがわかりました。

私の勝手な感覚では無理して指の先で狙うのではなく指の腹で全体的に押すと広告が消えてくれる気もします。神経を使うゲームですね。**これは脳トレです。**AIMの精度を上げるためにみなさん右脳と指を鍛えましょう。本当にくだらない内容でしたが、最後まで読んでいただきありがとうございました。
osmium-tool を使って日本全体の地図データをグリッド状に分割した話

# はじめに
この記事は [OpenStreetMap Advent Calendar 2018](https://qiita.com/advent-calendar/2018/osmjp) の 15日目の記事です。

こんにちは、[AROW](https://arow.world/) というプロジェクトの開発チームの広井です。
AROW では 3Dリアルマップの研究開発を行っていて、没入感のある新しいゲーム体験の実現を目指すために現在開発中です。

その中で地図データをグリッド状に分割した話を書いていきます。

# 前置き

地図データをグリッド状に分割とは、以下のイメージのようなことを指します。

<img width="500" alt="grid_1.png" src="https://qiita-image-store.s3.amazonaws.com/0/63607/50c0dc92-389b-3848-b09a-26afa5d4012d.png">

このようにデータを分割することで、例えばゲームでプレイヤーの周辺の地図データをダウンロードさせたい場合、データごとの重複がなく効率的にダウンロードすることができます。

# 方法1. Overpass API の利用

グリッド状に分割しようと考えたとき、まず利用しようとしたのは [Overpass API](https://wiki.openstreetmap.org/wiki/JA:Overpass_API) でした。

これは、Web上のOSM地図データの中から個別に選択された部分を取り出すものです。

矩形領域のダウンロードをするようなマップクエリを用意し、APIを叩くことで、1グリッド分をダウンロードすることができます。

これを必要なグリッドの数だけ繰り返すと目的は達成されます。

## 問題点

ですが、この方法だと1グリッドずつAPIを叩くので、グリッドの数が多いと問題になってきます。
Overpass API の記事に以下の記述があります。

> 1日あたり10,000クエリまたは5GBのデータ取得より少なければ、他のユーザーを邪魔しないと考えてよいでしょう。

今回自分が必要だったのは「日本全体を n [km] 四方のグリッドに分割する」であり、期待するグリッド数が数万〜数十万という数でした。
データ更新のことを考えると、Overpass API以外の方法を検討する必要がありました。

# 方法2. osmium-tool の利用

2つ目に上げるのが、タイトルにも挙げている [osmium-tool](https://osmcode.org/osmium-tool/) を利用する方法です。

これは、ローカルにあるOSM地図データに対していろいろな操作ができるコマンドラインツールです。

`osmium extract --bbox 〜` のコマンドでは矩形領域の切り出しが可能です。
地図データは [http://download.geofabrik.de/index.html](http://download.geofabrik.de/index.html) でダウンロードできます。

これを必要なグリッドの数だけ繰り返すと目的は達成されます。

## 問題点

ですが、これも一筋縄ではいかず、単純に処理時間が長いという問題がありました。
例えば一番最初は以下のコマンドを実行していました。

```
$ osmium extract --bbox 切り出したい矩形 -o grid_1.osm.pbf japan-latest.osm.pbf
```

これは、日本全体の地図データ（japan-latest.osm.pbf, 1.2[GB]）から1つのグリッド（grid_1.osm.pbf）を取り出すコマンドです。
日本全体の地図データを使っているので処理時間が長いのは当然です。1回の実行に数分かかっていました。

## 工夫

「日本全体の地図データ -> 1つずつのグリッドに分割」だったので、
「日本全体の地図データ -> ある程度小さいグリッドに分割 -> 1つずつのグリッドに分割」に変更するという工夫をしました。

イメージは以下です。

<img width="500" alt="image.png" src="https://qiita-image-store.s3.amazonaws.com/0/63607/43209527-c4e9-4397-1773-1d0146f61d98.png">

スクリプトは以下のリポジトリに上げています。使ったままのスクリプトで拡張性はないですが、実装の参考程度にお願いいたします。
https://github.com/junjanjon/osm-map-grid-separator

現在、このスクリプトを改造し並列して実行することで、大体半日という現実的な時間で日本全体の地図データをグリッド状に分割することができるようになりました。

# おわりに

OSMはいろいろなソフトウェアとの連携がされており、またwikiも日々更新されており、「エコシステム」？というのでしょうか、貢献している方たちの相互作用を感じることが多いです。

OSMを利用する開発者の1人として、OSMのコミュニティに貢献していきたいなと希望しています。
プログラミング/システム開発のパラダイムシフトという視点

この投稿は、Low-Code/No-Code Advent Calendar 2018 12月15日担当分となります。
##はじめに
いくつかのサービス/プロダクトを検証しながら、Low-Code/No-Codeという潮流について少し俯瞰的な目で考察してみたいと思います。

##とりあげるサービス/プロダクト
この記事では、以下の4つのサービス/プロダクトを見て行きます。今現在の、「Low-Code/No-Code」とはなんぞやということは置いといてｗ、従来型のコーディングスキルがないエンドユーザー層ても習得/利用ができるものという視点で選んでみました。

###サイボウズ kintone(キントーン）
![image.png](https://qiita-image-store.s3.amazonaws.com/0/60483/a52e603d-479f-9597-f094-e043a172fdbd.png)

まず日本でこれは、はずせないだろうということで、サイボウズさんのkintone(キントーン)です。最近は業務改善プラットフォームという位置づけにもなっており、エンドユーザーが自分たちのお困りごとを解決するために業務システムを自分たちで作れるのが特徴です。
ただ、問題がないわけではありません。
標準機能をかなり整理して実装されているため、ちょっと痒いところに手が届かないこともあったりします。その足りない部分をどうしたらいいんやろというのが、課題でした。
これを解決する１つの方法が、続く「gusuku CUSTOMINE」です。

###gusuku CUSTOMINE
![image.png](https://qiita-image-store.s3.amazonaws.com/0/60483/6b1742fe-81be-f077-d253-8c3291376031.png)
先に触れたkintoneの足りないところを実現しようとすると、今まではJavaScriptによる開発が避けて通れませんでした。
そういえば、前にこんな妄想を投稿していたのですが、本当にこれを作っちゃった会社がでたのです！
[kintoneのJavaScriptカスタマイズをもっと簡単に！？Blockintone(仮称)を妄想してみた](https://qiita.com/mniizuma/items/ea76d7cedfd4b0499eaa)

というわけで、紹介するのが、R3さんが開発・運営されている「gusuku CUSTOMINE（グスク カスタマイン)」です。優しい日本語のメニューから「やりたいこと」と「条件」を組み合わせてkintoneに機能を付加していくことができます。裏側ではJavaScriptのコード生成などされているそうですが、作っている側はそれを意識する必要はありません。
このgusuku CUSTOMINEについては、このAdventカレンダー12/10分の記事としても紹介されているので、詳しくはこちらを見て頂くのがよいでしょう。
[システム開発会社が行うNo-Code開発](https://blog.r3it.com/20181210-how-we-make-our-internal-systems-with-no-code-tools-5cbe5be420cf)

###Microsoft Flow
![image.png](https://qiita-image-store.s3.amazonaws.com/0/60483/60d0e616-2ff5-17fe-7547-d751247b72b9.png)
Microsoftさんもこの分野での存在感をじわじわと増してきましたね。特に個人的には、「Flow」がお気に入りです。豊富な自社サービス（まったくどんだけあるんだか）だけでなく、他社サービスとの連携が充実してくれると楽しみなんですが、はてさて。
システム間連携という小難しいところの敷居を一気に下げてくれた気はしています。日本語だし(笑）。

###Scratch 3.0
![image.png](https://qiita-image-store.s3.amazonaws.com/0/60483/f5f31c1e-8780-95e4-e9d3-82e4dffc5d71.png)
先に取り上げた3つとは少し毛色が違いますが、最後にScratchも取り上げたいと思います。ご存じない方もいるかもしれませんが、子供用のプログラミング環境として11年を超える歴史のあるものです。テキストで命令を記述するのではなくブロックを組み合わせてプログラミングをしていきます。
現行バージョンはWeb上のサービスとして提供されていて、全世界で3400万人を越える登録ユーザーがいます。国内でも毎年約1.7倍の伸び率で増えており、12月現在で34万人を越えています。
このScratchは、年明けの１月２日に新しいバージョン3.0がリリースされる予定でこの8月からパブリックベータテストが続けられています。
Scratch3.0では、機能を拡張するためのインターフェースが一新され、例えば、翻訳ブロックや音声合成ブロックといったWebサービスを組み合わせた機能や、micro:bitやLEGO MIND3などのSTEAM教材との接続が既にできるようになっています。
初心者にも親しみやすいブロック型プログラミングの世界でも、より複雑で現実世界とつながるようなプログラムが作れるようになりつつあるのです。

##Low-Code/No-Codeをどう見るか
4つのサービス/プロダクトを簡単にとりあげてみました。このように、従来の専門的なスキルが必要だった世界から、そこまでのスキルを必要とせずにプログラミングやシステム開発ができるように広がってきていることがわかります。
ここ数年、2020年度からの小学校におけるプログラミング教育必修化の話題が続いていますが、小学校だけでなく、中学・高校のプログラミング教育も新しい学習指導要領に基づいて順次強化されていく予定です。多くの子ども達が自分たちで何かを開発する経験をしていくことになるのです。そのために使われるツールは、Low-Code/No-Code的なものが多いかもしれません。

この広がりが今後どうなっていくかは、わかりません。しかし、個人的にはプログラミングやシステム開発のパラダイムシフトのはじまりと期待しています。

素晴らしいサービス/プロダクトを提供している皆さんに感謝を込めて。

##関連リンク
[kintone](https://kintone.cybozu.co.jp/jp/)
[gusuku CUSTOMINE](https://customine.gusuku.io/ja/index.html)
[Microsoft Flow](https://flow.microsoft.com/ja-jp/)
[Scratch](https://scratch.mit.edu/)
※ScratchはMITメディアラボのライフロングキンダーガーテングループのプロジェクトで、無償で提供されています。
[LIFE HACK]１カ月で人は変わることができる！その実践と反省

# Before & After
## Before
* 寝るのは夜の2時や3時は当たり前。起きたら昼前。
* 午前中がない
* 趣味程度のPythonコードしかかけない。フロントエンドまったく触れたことがない
* 惰性とコレジャナイ感で過ごす毎日
* 輝いている他人への嫉妬
* 肌荒れ

## After
* 寝るのは遅くても夜の12時。朝起きるのは5時。
* 朝学習の習慣化
* Pythonのコーディング力の向上。Vue.jsでWebサービスをリリースできるようになった
* 充実感のある毎日
* 自信がついた
* お肌が綺麗になった

# 何をしたのか
* 早寝早起き
* 朝学習あるいは朝Dev
* 共有と発信

## 早寝早起き
一ヶ月間で変わるために実践した一番重要なことは、「早寝早起き」です。ものすごく単純なことですが、僕はこれが自分を変える上で最も大事なことだったと思います。具体的には、夜は遅くとも24時までには寝て、朝は7時には起きるというのを習慣化しました。これを習慣化する前までは、夜は26時から27時くらいに寝るのが当たり前、朝起きるのも11時とか12時になりがちでした。そして、昼前に起きた日は決まって勉強や仕事のやる気が起きず、特に何もしないでダラダラと生活する日となっていました。早寝早起きの習慣をつけるために、毎朝起床したら友人に起床報告のメッセージを送ることと、スプレッドシートに就寝時間と起床時間を記録するようにしました。「早寝早起きの習慣をつける」という自分の目標に、他人も巻き込むことで、その目標に対する責任感と緊張感を持たせることができ、習慣化するまで継続できた要因だと思っています。

## 朝学習あるいは朝Dev
早寝早起きすることは大事です。しかし、早寝早起きするだけでは人は変われません。朝早く起きることで、時間を生み出しているわけですから、その時間に何をするかが大切です。僕は早起きすることで生み出した時間で朝学習あるいは朝Dev（朝にプロダクト開発を行うこと）をすることにしました。具体的には、Vue.jsをゼロから自習し、Webサービスをリリースするということをしました。フロントエンド完全初心者の僕が、独学で新たなフロントエンドの言語（正確にはjsフレームワークですが）を学習するにはかなりの時間的リソースが必要でした。朝学習の時間を生み出さなかったら、その時間的リソースを確保するのは難しかったと思います。

## 共有と発信
朝学習することは大事です。しかし、学習するだけでは人は変われません。学習したこと・作ったものを周りの人に共有することが大切だということを一ヶ月間で身にしみて感じました。内省的に一ヶ月前の自分自身とこれやあれができるようになったと比較することで実感できる変化も大事ですが、他人から変化や成長を指摘されたときに実感できる自分自身の変化はより大きいものでした。なによりも他の人に指摘されると嬉しいです。共有することのもう一つのメリットは、アドバイスやレビューを貰えることです。Vue.jsの学習は基本的には自習でしたが、どうしてもドキュメントを読んでも解決できない問題や実装方法が分からない部分は、アドバイスやレビューの際にヒントを貰っていました。また、学習したこと・作ったものを不特定多数に発信することも大事だと思いました。友人など限定的な範囲内で共有するだけでなく、不特定多数に自分のやっていることを発信することで、継続して学習しなければならない状況を自分で作り出しました。

# 反省
* 環境に恵まれていた
    * 学んだ技術を共有できる仲間が近くにいた
    * フロントエンドのメンター的存在が近くにいた
* もっと時間あたりの生産性を上げる必要あり
    * 早寝早起きと朝学習（朝Dev）によって時間を生み出すことはできたが、その生み出した時間を効率化することまでは徹底できていなかった
* 意識的に継続していることを無意識で継続できるようにする必要あり

# 最後に
2019年は僕にとって勝負の年になります。その勝負の年を迎える前に、今回の実践を通して、成長するための姿勢と土台を作ることができた思っています。一ヶ月で人が変わることができるならば、一年間ではもっと大きく変わることができるはずです。一年後の自分がなっていたい理想像を追い求めて、2019年は成長し続けます！
【Handsontable】最大文字数制限(MaxLength)

# はじめに
これは、[Handsontable Advent Calendar 2018](https://qiita.com/advent-calendar/2018/handsontable)の15日目の記事となります。

前回「[【Handsontable】変更マークの付与と必須チェック](https://qiita.com/yaju/items/900cef462f0daf69c19b)」では変更マークの付与と必須チェックを行いました、今回は最大文字数制限(MaxLength)を実装していきます。

# 最大文字数制限(MaxLength)
Handsontableのセル入力では、MaxLengthがサポートされていません。
よって、ユーザー側でカスタムエディタで対応するようにしています。
参照：[Handsontable Limit Cell Characters](https://stackoverflow.com/questions/26427150/handsontable-limit-cell-characters)

```javascript
(function (Handsontable) {

    'use strict';

    var MaxLengthEditor = Handsontable.editors.TextEditor.prototype.extend();

    MaxLengthEditor.prototype.prepare = function () {
        Handsontable.editors.TextEditor.prototype.prepare.apply(this, arguments);

        this.TEXTAREA.maxLength = this.cellProperties.maxLength;
    };

    Handsontable.editors.MaxLengthEditor = MaxLengthEditor;
    Handsontable.editors.registerEditor('maxlength', MaxLengthEditor);

})(Handsontable);

var hot = new Handsontable(grid, {
```

最大文字数の桁数とカスタムエディタ定義のオプションを追加します。
maxLength: 5, editor: 'maxlength'

```javascript
var hot = new Handsontable(grid, {
    data: [],
    colHeaders: ['編集', '選択', '商品CD', '商品名', '単価', '備考'],
    columns: [
        { data: COL_EDIT, readOnly: true, type: 'text' },
        { data: COL_SELECT, type: 'checkbox' },
        { data: COL_PRODUCTCODE, type: 'text', width: 80, validator: function (value, callback) { callback(true); }, maxLength: 5, editor: 'maxlength' },
        { data: COL_PRODUCTNAME, type: 'text', width: 200, className: "htLeft htMiddle", validator: function (value, callback) { callback(true); }, maxLength: 30, editor: 'maxlength' },
        { data: COL_UNITPRICE, type: 'numeric', numericFormat: { pattern: '0,00', culture: 'ja-JP' }, validator: function (value, callback) { callback(true); } },
        { data: COL_COMMENT, type: 'text', width: 300, className: "htLeft htMiddle", validator: function (value, callback) { callback(true); }, maxLength: 100, editor: 'maxlength' }
    ],
```

こうすることで例えば商品コードには、5桁までしか入力できなくなります。
![最大桁数制限.png](https://qiita-image-store.s3.amazonaws.com/0/14053/290ac0fc-dae3-e165-76a6-040dd7f66606.png)
Gitのsubtreeとsubmoduleを調べてみた

この記事は[谷ゼミの落書き帳 Advent Calendar 2018](https://qiita.com/advent-calendar/2018/drawing_pad_from_tani_seminar) の17日目の投稿になります。
書くネタに困ってしまったので、備忘録の意味も含めて以前調べたGitのsubtreeとsubmoduleについてまとめようと思います。

# はじめに
Gitのsubtreeとsubmoduleについてですが、どちらも外部リポジトリを自リポジトリに取り込む方法です。
多くの場合パッケージ管理システム（PHPの場合のcomposer等）が使われることが多いと思いますが、
それが使えない（それを使わない）場合の取り込み方法の選択肢としてそれぞれについて調べてみました。

# subtree
subtreeを使用するには外部リポジトリを取り込みたいリポジトリのディレクトリで以下を実行します。

```sh
git remote add 外部リポジトリ判別用の名称 URL
git subtree add --prefix=取り込むディレクトリのパス --squash 外部リポジトリ判別用の名称 ブランチ名
```

ここで気をつける必要があるのが``--squash``の指定です。
subtreeは外部リポジトリのhistoryもすべて取り込もうとしてしまうため、不要な場合は``--squash``でまとめてあげる必要があります。

``git subtree add``を実行すると、取り込んだディレクトリ(ファイル)はすべて自リポジトリの一部として扱うことができるため、変更を加えることもコミットすることも可能です。
自リポジトリへのコミット&pushを行えば、取り込んだディレクトリ(ファイル)もすべて一緒に自リポジトリのリモートに反映されます。

外部リポジトリに変更をpushすることも、外部リポジトリから変更を取り込むことも可能です。

subtreeのディレクトリを削除したい場合、他のディレクトリ同様``rm``等で削除するだけです。

**取り込んでしまえばあとは自リポジトリのものとして扱うことができる**という部分がsubtreeの特徴かと思います。

# submodule
submoduleを使用するには外部リポジトリを取り込みたいリポジトリのディレクトリで以下を実行します。

```sh
git submodule add URL 取り込むディレクトリのパス
```

取り込むディレクトリは自リポジトリで作成済みのディレクトリを選ぶことができないので注意が必要です。

``git subtree add``との違いがここから出てきますが、submoduleは外部リポジトリのソースが自リポジトリに展開されません。
submoduleは**外部リポジトリのある地点のコミットを参照する**ということだけが管理されます（コミットハッシュだけが管理されます）。
参照だけなので、変更を加えることも、ソースを自リポジトリのリモートにpushすることもできません。
※ 参照のためにローカルに展開することは可能です
※ 力技で変更することもできますが、あまりおすすめしないので方法も割愛します
※ 参照元のリポジトリが削除された場合にどうなってしまうのか等、まだまだ試せていないことも多いです

参照するコミットハッシュを変更する場合は、submoduleのディレクトリで``git pull``し、自リポジトリをpushすることで変更が反映されます。

submoduleのディレクトリを削除したい場合は、``rm``等で削除するのではなく以下のコマンドを実行する必要があります、

```sh
git submodule deinit 取り込んだディレクトリのパス
```

submoduleはsubtreeと比較するとパッケージ管理システムの考え方に近いのが特徴かと思います。


# 終わりに
今回はあまり特殊なことはせずに基本的な部分のことを確認し、まとめてみました。
まだまだ紹介していないオプション等があると思いますので、これをきっかけにいろいろ調べてみると面白い発見があるかもしれません。

Qiitaへの投稿が初ということもありうまくまとめることのできなかった記事になってしまいましたが、読んでくださりありがとうございました！
ruby on rails5開発環境　atomインストール後

progateで勉強し実際にコードを書いて習ったappを作りたいです。

atomをインストールし、railsもインストールはしたものその後何をしたら実際にappが作れるようになるのでしょうか？

windowsを使っているのでターミナルはコマンドプロントを使用すると思いますが、コマンドプロントをatomは連動してるのですか？

超初心者であり、まず何から取り掛かっていいものか苦戦しております。
アドバイス頂けたら嬉しいです。
[Go]可変長のsliceを展開、受け取る時の記述方法

## three dots

可変長引数を表す`...`という記法。展開して渡す側、受け取り側で記述方法が混乱したので書いておく

```sample.go
package main

import (
	"fmt"
)

func main() {
	holiDays("JUN")
	holiDays("MAY", 3, 4, 5)

	days := []int{1, 8}
	holiDays("JAN", days...)

}

func holiDays(month string, days ...int) {
	fmt.Println(month)
	fmt.Println(days)
}
```
上記のようなコードの場合...

- 引数として受け取る場合は`days ...int`と型名の手前にthree dotsで記述する
- sliceを展開して渡す場合は`days...`と記述する
マウスホバーで離れた位置になにか表示したいときの便利ワザ

マウスホバーで別の要素を表示することってありますよね。
（カテゴリメニューの子カテゴリとか、別のアクションをするボタンやリンクを表示したりとか）

次のGIFでは、要素の外にマウスカーソルがいったときにすぐ消えてしまっています、とても残念な感じです。
これをいい感じにする便利ワザの紹介です。
※サンプルはVue.jsですが他のライブラリでも似たような感じになるのかな、と思います。

![CodePen - Vue hover bad pattern.gif](https://qiita-image-store.s3.amazonaws.com/0/35595/937e7bf4-1d3f-1a1a-da35-b3af557a3721.gif)



## パターンA `:hover` を使う
デフォルトで `display: none;` にしといて `:hover` がついたら `display:block` に切り替えて表示しています。

<p data-height="350" data-theme-id="0" data-slug-hash="VqazqK" data-default-tab="html,result" data-user="howdy39" data-pen-title="Vue hover bad pattern" class="codepen">See the Pen <a href="https://codepen.io/howdy39/pen/VqazqK/">Vue hover bad pattern</a> by Tatsuya Nakano (<a href="https://codepen.io/howdy39">@howdy39</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

### このパターンの問題点
要素外に出た瞬間にホバーが外れます。
そのため、ホバーで出てくる要素が離れていたりするとUXがとても悪いです。

![CodePen - Vue hover bad pattern.gif](https://qiita-image-store.s3.amazonaws.com/0/35595/937e7bf4-1d3f-1a1a-da35-b3af557a3721.gif)


## パターンB `@mouseenter`, `@mouseleave` を使う
Vueの `@mouseenter`, `@mouseleave` を使ったパターンです。
これも先程の `:hover` と同じ挙動になってしまうためUXがとても悪いです。

<p data-height="350" data-theme-id="0" data-slug-hash="BvKmOj" data-default-tab="html,result" data-user="howdy39" data-pen-title="Vue hover good pattern step1" class="codepen">See the Pen <a href="https://codepen.io/howdy39/pen/BvKmOj/">Vue hover good pattern step1</a> by Tatsuya Nakano (<a href="https://codepen.io/howdy39">@howdy39</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>


## パターンC パターンBに `debounce` を組み合わせたパターン
先程の `@mouseenter`, `@mouseleave` に加えて `debounce` を組み合わせたパターンです。
ここでは debounce の実装に [Lodash](https://lodash.com/docs/4.17.10#debounce) を使いました。 

<p data-height="350" data-theme-id="0" data-slug-hash="roeYod" data-default-tab="html,result" data-user="howdy39" data-pen-title="Vue hover good pattern step2" class="codepen">See the Pen <a href="https://codepen.io/howdy39/pen/roeYod/">Vue hover good pattern step2</a> by Tatsuya Nakano (<a href="https://codepen.io/howdy39">@howdy39</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>


上記コードの場合、要素を離れて(mouseleave)してから500ms後に要素にホバーがあたっていないときだけホバーを消すという処理をしています。
「消えるんかい！！」っていうイライラがなくなりますね。

![CodePen - Vue hover good pattern step2.gif](https://qiita-image-store.s3.amazonaws.com/0/35595/520e1945-d1aa-ed0c-5bf9-5b0bc76bbfe4.gif)


## あとがき
もっといい方法あるよって人はコメントくれると嬉しいです。
[AWS]S3バケットに対して大量の読み取り/書き込みトラフィックが発生する場合の対処

# はじめに
EBSに対するアクセス増加に対してはIOPSやスループット重視のストレージタイプにするのでしょうが、S3に対するアクセスが増える場合の対処について、知らなかったのでメモ書き。

# 対処
ワークロードが急増したときに S3 バケットのパフォーマンスを向上させるには、どうすればよいですか?
https://aws.amazon.com/jp/premiumsupport/knowledge-center/s3-bucket-performance-improve/

平たく言うと、オブジェクト名にランダムな文字列（プレフィックス）を含めることで、書き込まれるパーティションを分散できる、というものらしいです。

# 参考ページ
リクエスト率およびパフォーマンスのガイドライン
https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/request-rate-perf-considerations.html

ここに書かれているワークロードを超えたら先述の対処を考えなさい、という一つの基準。

- 3,500回以上のPUT/POST/DELETEリクエスト（秒・プレフィックス毎）
- 5,500回以上のGETリクエスト（秒・プレフィックス毎）

プレフィックスが無くてもそこそこの性能が出るようになったのはどうも割と最近みたいです。

https://dev.classmethod.jp/cloud/aws/amazon-s3-announces-increased-request-rate-performance/
締切りまでの時間をカウントダウンしてくれる zsh プロンプト 君

# はじめに
学生や社会人の皆様は，

- 20xx 年 x 月 x 日の xx 時 xx 分 までに締切りが
- 締切り間近だけど，やる気が．．

なんてこともあるはずです．

そんなときに，ターミナルのどこかに締切りまでの時間をカウントダウンしてくれる人がいれば，
少しはやる気がでるのでは無いでしょうか？

今回は，zle の機能を使用し，zsh ターミナルに 締切りまでの時間をカウントダウンしてくれるスクリプトを書きました．

# 実装

- 基本， $DEADLINE を変更すれば，締切りまでをカウントダウンしてくれる
- PROMPTの部分の $TIMEREMAIN にカウントダウンの日数が格納され，ターミナルに表示される
- 締切り後は，その部分がジョブ数 %j に変わる
- 締切りの 1,2,3,4,5 週間前には，表示の色が変わり，警告してくれる
 - 好きな日にち，好きな色に変えてお楽しみください

```zsh:.zshTimeRemain
function getTimeRemain(){
  DEADLINE="2018/12/16 00:00:00" # 締切り日
  ALL=$(expr \( `date --date $DEADLINE +%s` - `date +%s` \)) # 合計秒数
  DAY=$(expr $ALL / 86400)
  HOR=$(expr $ALL % 86400 / 3600)
  MIN=$(expr $ALL % 86400 % 3600 / 60)
  SEC=$(expr $ALL % 86400 % 3600 % 60)
  # 残りの日数に応じて，色を変更
  if   [ $DAY -le  7 ]; then COLOR="%F{1}" # red
  elif [ $DAY -le 14 ]; then COLOR="%F{5}" # magenta
  elif [ $DAY -le 21 ]; then COLOR="%F{3}" # yellow
  elif [ $DAY -le 28 ]; then COLOR="%F{2}" # green
  elif [ $DAY -le 35 ]; then COLOR="%F{6}" # cyan
  elif [ $DAY -le 42 ]; then COLOR="%F{4}" # blue
  else                       COLOR="%F{7}" # white
  fi
  if [ $ALL -le 0 ]; then
      TIMEREMAIN="%j"
  else
      TIMEREMAIN=$COLOR$(printf "%d %.2d:%.2d:%.2d" $DAY $HOR $MIN $SEC)"%f"
  fi
}

setopt PROMPT_SUBST

PROMPT='%U%B$promptname%b [ %m : $TIMEREMAIN : %~ ] %u
'
getTimeRemain

TRAPALRM () {
  getTimeRemain
  zle reset-prompt
}
TMOUT=1 # 1s
```

```zsh:.zshrc
if [ -f ~/.zshTimeRemain ]; then
  source ~/.zshTimeRemain
fi
```

```zsh:結果
user_name [ host_name : 3 14:15:26 : ~ ] # 締切りまで 3日と 14時間 15分 26秒 
```

# 最後に

正直，普段は bash を使っているので， zsh について詳しく分からないため，

- 正しい動作か
- ターミナル処理への弊害の有無

については分かりません．

あと，bash でも同じことがしたいんですが，そんな機能が bash にあるのだろうか？
知ってる人がいたら教えてください．
俺のNuxtがこんなところで躓くはずがない

## 概要

こんにちは、アジアクエスト株式会社でフロントエンドエンジニアをやってます、「結局最後はエモさの」
[かめぽん](https://twitter.com/kamepon_fe)です。
Nuxt.jsで開発することが多くてQiita記事で盛大にNuxtをもてはやしてますが、僕も無駄に詰んだり変なところで時間食ったりなど、ありますのでそれらを供養できればと思い書かせていただきました。
皆様の大切な時間を守る記事に少しでもなっていただければ嬉しいなと思ってます。

##　本題
### その１：エラーページ実は１撃で終わる問題
問題というかこれはNuxtの良い点の一つなんですが、404や500番代エラーのページなどを実装しようと思ってて、自前でページのエラー処理を書こうと意気込んでた矢先のこと、いつもお世話になってる`layouts/default.vue`と同じディレクトリ内に`error.vue`を置くだけ。
これだけで、ページ周りのエラー時に自動でerror.vueが表示されます。
errorページにはいくつか特殊な項目があるので、以下に記載します。

- page周りでエラーが起こると`error.vue`に飛ぶ
- エラーページには`<nuxt/>`タグを含めてはならない
- `props:['error']`で取得後、`error.statusCode`で404か500系なのか条件分岐することができます

単一ファイルコンポーネントを読んだ時点で、popsに値が入りその中のstatusCodeによってメッセージによって表示内容を変えるだけで、簡単にエラーページを実装することが出来ます。
<img width="405" alt="スクリーンショット 2018-12-15 21.20.51.png" src="https://qiita-image-store.s3.amazonaws.com/0/105049/76053a70-cc90-4e2b-a928-fe6a79dca4ec.png">


### その２ sketchアニメーションが死ぬ問題

processingでアニメーションを実装するために以下のコードを書きました。

```html

<div class="visual">
  <canvas data-processing-sources="pde/sketch.pde"></canvas>
</div>

<script>
export default {
  head() {
    return {
      script: [{ src: "script/processing.min.js" }]
    };
  },
...
}
</script>

```

これ自体ページは表示時にアニメーションがしっかりと表示されます。
以下が、表示された際のDOMの状況です。
<img width="451" alt="スクリーンショット 2018-12-15 20.47.06.png" src="https://qiita-image-store.s3.amazonaws.com/0/105049/e843a13e-6c91-d973-cd96-b5d14e6163f4.png">


しかし、別ページからnuxt-linkでやってくると、なんとアニメーションが動かないんですよね〜
そしてその時のDOMの状況です。アニメーションが表示されていた時とは違って、widthとheightの設定がなく実態がない状態になってますね。

<img width="444" alt="スクリーンショット 2018-12-15 20.47.36.png" src="https://qiita-image-store.s3.amazonaws.com/0/105049/554ef64c-131f-11cb-2625-b1c8878d8a2c.png">



ページリロードがかからないといけないので、nuxt-linkではなくaタグを用いて画面遷移することで解決します。

### その３　nuxt generateで動的ルーティングが効かなくて焦った話
Nuxtには静的サイトジェネレータという最終的な成果物をHTML/CSS/jsの静的なページとして出力してくれる機能があります。
pages配下にファイルと置くだけで、ジェネレート時にも勝手にファイルを生成してくれるのですが、これには一つ落とし穴があって、`/user/:id`のように、`/user/10`とか/hoge/foo/3など動的ルーティングの場合は反映されません。
ですので、nuxt.config.jsのgenerate設定で、動的ルーティングにおける**全てのパターン**のを記述しなければいけません。

```js

module.exports = {
  generate: {
    routes: [
      '/foo/1',
      '/foo/2',
      '/foo/3',
      ...
    ]
  }
}
```

しかしながら、ヘッドレスCMSなど外部APIなどによってページ毎に内容が変わる場合はその全パターンもgenerateで設定する必要があります。


```js
export default {
  generate: {
    routes() {
      return axios.get('[apiのurl]')
      .then((res) => {
        return res.data.map((v) => {
          return '/foo/' + v.id
        })
      })
    }
  }
}
```

ここでお分かりだとは思うのですが、動的な内容のジェネレートはAPIで受け取る内容の量がかなり多い場合に非常に時間がかかってしまいます。また、コンテンツの使用頻度がかなり頻繁だとジェネレートがそもそもその運用方法に敵視しているのかなど出てくるので、ジェネレートが良いのかSSRが良いのか適切に判断していきましょう。

## まとめ
ここまで、僕がNuxtの開発で若干積んだ部分をご紹介しました。
Nuxt.jsは非常に融通がきくFWですが、普通のHTKML/CSSコーディングと同じ感覚で行くと若干やけどしちゃうので、公式リファレンス片手に（ここ大事）ガンガン開発していきましょう！
では、エモくいきましょう！
ビルドマシンでビルドしたAndroidイメージをシームレスにローカルでエミュレートしたかった

# ビルドマシンでビルドしたAndroidイメージをシームレスにローカルでエミュレートしたかった
最近Androidのビルドをしているのですが、手元のPCではビルドに時間がかかりすぎてしまい、なんとか高速化できないか試行錯誤してみたので、記事にしてみます。

## 発端
Androidのビルドは並列化することによって高速化できるのですが、そもそも手元のPC(2コア4スレッド)では4並列が限界で、1回のフルビルドに2時間近くかかっていました。

そこで、処理性能の高い(CPUコア数の多い)ビルドマシンを用意して、Androidのビルドはビルドマシンの方でおこない、ビルド成果物を用いて手元のPCでビルドしたイメージをエミュレートしたいと考えました。

## 試したこと
1. `ramdisk.img、system.img、userdata.img ` をダウンロード
2. `/out` をダウンロード
3. `sshfs` でビルドマシンの `/out` をローカルにマウント
4. `sshfs` でローカルの `/out` をビルドマシンにマウント
5. lsyncdで `/out` を同期する

## 1. `system.img` をダウンロード
ビルドマシンでビルドして生成した `ramdisk.img、system.img、userdata.img ` をダウンロードして、手元のビルド環境の `ramdisk.img、system.img、userdata.img ` と置き換えてエミュレータ起動

結果: これだと上手くいかなかった。(エミュレートはできるが、古いイメージをエミュレートしている?)

## 2. `/out` をダウンロード
ビルドマシンでビルドして生成した `/out` をダウンロードして、手元のビルド環境の `/out` と置き換えてエミュレータ起動

結果: 上手くいったが、 `/out` をダウンロードするのに1時間以上かかってしまい、ビルドマシンで高速化した意味があまりなかった

## 3. `sshfs` でビルドマシンの `/out` をローカルにマウント
sshfsを用いて、ビルドマシンの `/out` をローカルにマウントして、ビルドマシンでビルド後、ローカルで `emulator`を起動

結果: エミュレータが立ち上がらなかった

## 4. `sshfs` でローカルの `/out` をビルドマシンにマウント
sshfsを用いて、ローカルの `/out` をビルドマシンにマウントして、ビルドマシンでビルド後、ローカルで `emulator`を起動

結果: ビルドマシンのビルド途中で、コネクションが切れてしまった

---

ここまで試して、「起動しない」か「起動しても遅すぎてビルドマシンを使う意味が無い」という結果になってしまいました。

## 6. lsyncdで `/out` を同期する
[Ubuntu: lsyncd によるディレクトリのリアルタイム同期（追記あり）](http://tkrd.hatenablog.com/entry/2018/01/13/205730)

ビルドマシンにlsyncdをインストールして、下のような設定ファイルを用意して、ビルドマシンの `/out` を手元PCの `/out` に同期するようにしました。

```lsyncd.conf.lua
settings {
        logfile    = "/var/log/lsyncd.log",
        statusFile = "/tmp/lsyncd.stat",
        delay        = 1
}

sync {
        default.rsync,
        source="/home/build-machine/AOSP-9.0.0/out/",
        target="local-user@xxx.xxx.xxx.xxx:/home/local-user/AOSP-9.0.0/out/",
		delete=running,
        rsync = {
          rsh = "/usr/bin/ssh -i /home/build-machine/.ssh/id_rsa.rsync -o UserKnownHostsFile=/home/build-machine/.ssh/known_hosts"
        }
}
```

ビルドマシン側で `make clean` をした際に、手元のビルド成果物も消すために、 `delete=running` にしています。

結果: 今の所いい感じ。 `system.img` のrsyncに少し時間がかかるものの、ビルドマシンでのビルド後にほぼシームレスにローカルでエミュレートできている。


## まとめ
lsyncdを使うことで、処理能力の高いビルドマシンでAndroidを高速ビルドしつつ、手元でエミュレートできるようになりました。
いろいろ試行錯誤の結果なのですが、もっと良い方法があれば試してみたいです。
cordova-plugin-crypt-fileを使用した時に起こるアレコレのメモ

まず、始めに、[cordova-plugin-crypt-file](https://github.com/tkyaji/cordova-plugin-crypt-file)は素晴らしいプラグインです。
本当にありがたいプラグインです。
tkyaji さん、ありがとうございます。
[ここにtkyajiさんが書かれた記事があります。](https://qiita.com/tkyaji/items/084d063a9585b50b7d01)

ただ、何故か色々干渉することがある。
今回の開発ではcordova-plugin-crypt-fileは絶対に使いたいプラグインだったので、他を消してでも使う勢いです。
私がつまづいた部分と解決したものは解決法をいくつか書いていきます。
自分用のメモ程度です。
# 画面が真っ白。そこにhtmlの暗号化された文が表示される。（iOS）
結論から言うと、cordova-plugin-ionic-webviewと干渉していました。
cordova-plugin-ionic-webviewを消して解決。
でも消したくない場合もあるので、その場合の事も考えてみました。
## 原因
調べたところ、cordova-plugin-ionic-webviewを入れる事により、UIWebViewがWKWebViewに変更されていると、NSURLProtcolが...と言う事らしいです。
なので、同じくWKWebViewを使うcordova-plugin-wkwebview-engineでも同じ症状が出ます。
## 思いついた解決法 「iOSだけ暗号化を諦める」
iOSの暗号化を諦めるようにするには、plugins/cordova-plugin-crypt-file/plugin.xmlの

```
<platform name="ios">
            ・・・
</platform>
```
を

```
<!--
<platform name="ios">
            ・・・
</platform>
-->
```
丸ごとコメントアウト。

次にplugins/cordova-plugin-crypt-file/hooks/after_prepare.jsの

```
if (platform == 'ios') {
            ・・・
} else if (platform == 'android') {
            ・・・
```
を

```
if (platform == 'ios') {
/*
            ・・・
*/
} else if (platform == 'android') {
            ・・・
```
コメントアウト。
これでAndroidだけ暗号化されるようになりました。

# 画面が真っ白。そこにhtmlの暗号化された文が表示され、「net::ERR_FILE_NOT_FOUND (file:///android_asset/www/+++/index.html)」と言うエラーが出る。（Android）
結論から言うと、cordova-plugin-ionic-webviewと干渉していました。
またか。
cordova-plugin-ionic-webviewを消して解決。
でも消したくない場合もあるので、その場合の事も考えてみました。
## 原因
いまいちよくわからない。
## 思いついた解決法 「cordova-plugin-ionic-webviewを諦める」
cordovaでWKWebViewを使う方法は、cordova-plugin-ionic-webview以外にもcordova-plugin-wkwebview-engineなどがあります。
とりあえず、そちらを入れてみました。
そうすると、何と言うことでしょう、iOSが動かない。
なので次はcordova-plugin-wkwebview-file-xhrを入れます。
動くようになりました。
でもなんか、パフォーマンスが微妙なような気がします...。
もっといい方法あったら教えてください、

# Androidでrun時にエラー。
エラーメッセージを忘れてしまいましたが、、、
plugins/cordova-plugin-crypt-file/hooks/after_prepare.js内の

```
} else if (platform == 'android') {
     var pluginDir = path.join(platformPath, 'src');
            ・・・
}
```
を

```
} else if (platform == 'android') {
     var pluginDir = path.join(platformPath, 'app/src/main/java');
            ・・・
}
```
に変更。（'src'を'app/src/main/java'に変更しているだけ。）

# 他のプラグインと干渉
その他のプラグインでのことは今の所よくわかりませんが、試す価値がありそうなのが、
plugins/cordova-plugin-crypt-file/plugin.xml内の

```
<exclude>
</exclude>
```
の部分で

```
<exclude>
    <file regex="cordova\.js" />
    <file regex="plugins" />
</exclude>
```
暗号化しなくても良いファイルを暗号化しない設定をします。

# たまにAndroidがどうしようもなくなる。
詳しい状況まで覚えていませんが、Androidの開発時にcordova run時などにエラーが出てきた場合は、platformをrmしてaddすることで解決したことがありました。

```
$ cordova platform rm android
$ cordova platform add android
```

# 本当に素晴らしいプラグインです。
何度も言います。
tkyajiさん、本当にありがとうございました。
Karabiner-ElementsのComplex Modificationsが動かないエラーの解決策

# はじめに

Karabiner-Elements、便利ですよね。
ただ、Simple Modificationsの方は普通に動いたのですが、Complex Modificationsがなぜか動かなくて数時間ハマってしまったので解決策をメモしておきます。
ただ、一応解決策は分かりましたが、詳しい原因はよく分かってないです。。
:warning:(2018.12.17追記）原因判明したので一番最後に追記してます。

# 環境
macOS Mojave 10.14.2
Karabiner-Elements 12.1.0

# エラー内容
Complex Modificationsを使ってやりたいことは「option+Tabでタブ遷移が出来るようになる」です。
Windowsの時のように左手だけでタブ遷移がしたいのです。
まず01_hoge.jsonファイルを以下の用に作成して、

```01_hoge.json
{
  "title": "タブ遷移（右へ）",
  "rules": [
    {
      "description": "タブ遷移（右へ）"
    }
  ],
  "manipulators": [
    {
      "type": "basic",
      "from": {
        "key_code": "tab",
        "modifiers": {
          "mandatory": ["left_option"]
        }
      },
      "to": [
        {
          "key_code": "right_arrow",
          "modifiers": ["left_command", "left_option"]
        }
      ]
    }
  ]
}
```

以下のディレクトリに置いたところ、
`~/.config/karabiner/assets/complex_modifications/01_hoge.json`

以下の通り表示はされるのですが、
![image.png](https://qiita-image-store.s3.amazonaws.com/0/230651/e4f28ec0-8f85-d49d-ac8e-e01210d7c08f.png)

enableにしても動かないのです。

# 解決策

:warning:(2018.12.17追記）この解決策は古いです。一番下に最新の解決策を追記してますのでそちらを参照お願いします。

以下のファイルを確認すると、以下の画像の通りdescriptionの設定しか反映されていないことに気づきました。
`~/.config/karabiner/karabiner.json`

<img width="615" alt="スクリーンショット 2018-12-15 22.36.34.png" src="https://qiita-image-store.s3.amazonaws.com/0/230651/3c079a20-de4a-ec2b-dd89-20263041f68a.png">

なのでここに01_hoge.jsonの内容をコピペすると動くようになりました。

<img width="562" alt="スクリーンショット 2018-12-15 22.40.20.png" src="https://qiita-image-store.s3.amazonaws.com/0/230651/56253b12-3024-fa2d-0ece-40fd7144a6a9.png">

# おわりに
動いたものの、なんかスッキリしない解決策ですよね。。
原因が果たしてバグなのか自分の環境？設定？なのかよく分かってない。。
詳しい人いたら教えてくだせえ

ではでは。

# :warning:2018.12.17 追記
原因分かりました。
自分がアホなだけでした。
manipulatorsをrulesの中に入れないといけなかったのに並列に記載してしまってました。
なので、以下のように書くと普通に動きました。
しょーもな。。

```01_hoge.json
{
  "title": "タブ遷移（右へ）",
  "rules": [
    {
      "description": "タブ遷移（右へ）",
      "manipulators": [
        {
          "type": "basic",
          "from": {
            "key_code": "tab",
            "modifiers": {
              "mandatory": ["left_option"]
            }
          },
          "to": [
            {
              "key_code": "right_arrow",
              "modifiers": ["left_command", "left_option"]
            }
          ]
        }
      ]
    }
  ]
}

```

お騒がせしました。。
画面付きデバイス対応Alexaスキルを、実機なしでテストする

タッチイベントのテストについて検索しても具体的なやり方が見つからなくて、諦めかけていた1ヶ月前の自分に向けた記事です。
もしもっと簡単な方法が常識みたいに存在してたら教えてください。

# 問題

Echo Spot、Echo Showの画面に選択肢を表示して、ユーザーのタッチを処理して進行するスキルを作りたい。
でも、実機は持ってません。

- [日本語版 Echo Spot に対応したスキルの作り方](https://developer.amazon.com/ja/blogs/alexa/post/7989cf68-e611-4d88-9ffb-3fca677214bf/building-skills-for-echo-spot-customers-in-japan1)
- [[日本語Alexa] Alexa-SDK Ver2(その7) ディスプレイ表示](https://dev.classmethod.jp/cloud/alexa-sdk-v2-seventh/)
- [[Alexa] 動画を再生するスキルを作ってみました](https://dev.classmethod.jp/cloud/alexa-video-skill/)

以上の記事を参考にして、画面に選択肢を表示させる方法はわかりました。
また、Display.ElementSelectedというイベントを処理すればいいらしいこともわかりました。
選択肢にはtokenという、どれを選んだか識別するための文字列を仕込んでおいて、タッチされたときにtokenを取り出して処理を分岐させるということですね。

しかし、開発者コンソールのテスト画面で、シミュレーターに表示されている選択肢をクリックしても何も起こりません。
タッチイベントのシミュレートはしてくれないようです。
どうすればいいんだろう…

# 答え
[Displayインターフェースのリファレンス](https://developer.amazon.com/ja/docs/custom-skills/display-interface-reference.html)によると、

>スキルでは任意の選択可能要素にtokenフィールドを設定でき、設定したトークンは要素が選択されるとDisplay.ElementSelectedリクエストで送信されます。このようなイベントの例を次に示します。
>>```json
"request": {
    "type": "Display.ElementSelected",
    "requestId": "amzn1.echo-api.request.7zzzzzzzzz",
    "timestamp": "2018-06-06T20:05:04Z",
    "locale": "ja-JP",
    "token": "getTopicName-Cookie-Contest"
}
```

これか。

1. Alexaシミュレーターでスキルを起動して、選択肢が提示されるところで、音声で選択をした体で入力のシミュレートを行います。（例えば番号で選択する場面なら「3番」とかを入力する）
2. そのとき表示されるJSON入力をコピーします。
3. lambdaのテストイベント設定画面を開き、コピーしたJSONを貼り付けます。
その中には、以下のようなリクエストデータが含まれていますので、

```diff
"request": {
		"type": "IntentRequest",
		"requestId": "amzn1.echo-api.request.7zzzzzzzzz",
		"timestamp": "2018-12-15T11:33:22Z",
		"locale": "ja-JP",
		"intent": {省略}
}
```

Display.ElementSelectedリクエストに書き換えます。

```diff
"request": {
-		"type": "IntentRequest",
+		"type": "Display.ElementSelected",
		"requestId": "amzn1.echo-api.request.7zzzzzzzzz",
		"timestamp": "2018-12-15T11:33:22Z",
		"locale": "ja-JP",
-		"intent": {省略}
+		"token": "その選択肢に設定したtoken"
}
```

これで、そのテストを実行すれば、lambda上で結果の出力を得られます。
Display.ElementSelectedのハンドラで処理され、音声での入力と同じ結果が得られれば問題ないでしょう。
実機での動作が確認できないので不安でしたが、審査は通りました。

### 余談

ディスプレイインターフェースを有効にしたときに自動的に追加されるインテントのうち、NextIntentとPreviousIntentは処理が必須です（審査されます）。が、スキルで「前」とか「次」を使わない場合はわざわざ個別に対応しなくても、ErrorHandler（どのハンドラにも引っかからなかったイベントをまとめて処理するハンドラ）に任せて「すみません、わかりませんでした」みたいな答えを返せば大丈夫だと思います。
私はErrorHandlerをコピペしたきりで返答が英語だったため、一度審査に落ちました。

なお、当該スキルは[こちら](https://www.amazon.co.jp/Poncot-%E6%9A%97%E9%97%87%E3%81%AE%E3%82%B5%E3%83%B3%E3%82%BF%E3%82%AF%E3%83%AD%E3%83%BC%E3%82%B9/dp/B07L57GHBG/ref=sr_1_1?s=digital-skills&ie=UTF8&qid=1544876762&sr=1-1&keywords=%E6%9A%97%E9%97%87%E3%81%AE%E3%82%B5%E3%83%B3%E3%82%BF%E3%82%AF%E3%83%AD%E3%83%BC%E3%82%B9)です。クソゲーかな？ でもキャンペーンでEcho Showがもらえる条件はクリアしたはず！
Firestoreセキュリティルールで存在するドキュメントの上書き作成を防ぐ

今回は、すでに存在するドキュメントの作成を禁止する方法を紹介します。
なぜUpdateでなく**「すでに存在するドキュメントの上書き作成」**なんて回りくどい言い方をするかというと、

- クライアントサイドのsetメソッドでの同一パスへの書き込みはUpdate扱いとなる
- 部分的なフィールドのUpdateは許可したい

といった背景があります。



## セキュリティルールで意図しない書込みを防ぐ

Firebase Firestoreの**セキュリティルール**では、match文でドキュメントパスを指定し、
allow式でドキュメントの**read**、**create** 、**update**、**delete**権限を指定することができます。
※以下、権限に関する**create**等は太字で表現します。

参考：[【改訂版】 Firebase Cloud Firestore rules tips](https://tech-blog.sgr-ksmt.org/2018/12/11/194022/)



## setメソッドでの同一パスへの書き込みはUpdate扱いとなる

クライアントからのFirestoreドキュメントの指定パスへの書込み方法の代表的なものとして、`set`メソッドがあります。
**参考**：[Firebase firestore：Writing Data](https://firebase.google.com/docs/reference/swift/firebasefirestore/api/reference/Classes/DocumentReference?hl=ja#/Writing%20Data)

これは、従来のデータベースの**insert**に近いイメージですが、`merge`オプションをセットすることで**upsert**のような、`update、もしなければinsert`といった挙動をさせることができます。

よって、Firestoreドキュメントの指定パスへの書込み方法の分類は`merge`オプションを区別すると
`set without merge`、`set with merge`、`update`の3種類となります。
(今回は[mergeFields](https://firebase.google.com/docs/reference/swift/firebasefirestore/api/reference/Classes/DocumentReference?hl=ja#/c:objc(cs)FIRDocumentReference(im)setData:mergeFields:)オプションについてはmergeとして扱います)

この3つには下記のような違いがあります。

- `set without merge`： ドキュメントそのものを**update**、もし存在しないようなら**create**
- `set with merge`： ドキュメントのフィールドの**update**、 もし存在しないようなら**create**
- `update`： ドキュメントのフィールドの**update**、 もし存在しないようなら失敗する


```サンプルコード.swift
//すべて同期的に動作するものと仮定したコードです

let firestore = Firestore.firestore()

//新規documentIDでReferensePathを作成
let userRef = firestore.collection("users").document()
let data1 = ["name":"userA"]

//ドキュメントが存在しないため失敗する
userRef.updateData(data1)

//ドキュメントが存在しないのでcreateされる
userRef.setData(data1, merge: true)
/*
user > {documentID} > ["name":"userA"]
*/

//ドキュメントそのものがupdateされるためnameフィールドは消える
let data2 = ["age": 21]
userRef.setData(data2)
/*
user > {documentID} > ["age": 21]
*/

//ドキュメントが存在するためフィールドがupdateされる。ageフィールドは消えない
//userRef.updateData(data1, merge: true)と同じ挙動
userRef.setData(data1, merge: true)
/*
user > {documentID} > ["name":"userA", "age": 21]
*/
```

## set without mergeはすでに存在するドキュメントを無視する
**まだ登録されてないuserIDのprofileだけ登録したい**等の目的で**create**を目的とした`set`メソッドを使用して書き込み処理を行なっても、すでに存在するdocumentPathに対しては**update**の挙動となってしまいます。
なので、

- **すでに存在するドキュメントの上書き作成を防ぎたい**
- **通常の部分的なフィールドの更新は許可したい**

といった意図をセキュリティルールで実現するには、*update*権限のルールを工夫する必要があります。

## 1度しかデータを作成できないようにする
方法としては、初回作成時にしか書き込まない`createdAt`のようなフィールドを利用します。
具体的には

- **データ作成時は必ず`createdAt`を書き込むこと**
- **下記のようなルールで`createdAt`の更新のみを禁止すること**

によって、すでに存在するドキュメントに`create`しようとした処理を失敗させることができます。

```
match /users/{userID} {
      allow read: if request.auth.uid != null;
      allow create: if request.auth.uid == userID
                    && request.resource.data.createdAt != null
      allow update: if request.auth.uid == userID
      	            && request.resource.data.createdAt == resource.data.createdAt;
```

ちなみに
`request.resource.data.createdAt == resource.data.createdAt`
のようなルールをallow文に記述することで、フィールドの変更を制限することができます。
Adobe Illustrator オブジェクトの重ね順の取得

## はじめに

Adobe Illustratorにて、JavaScript経由で取得したオブジェクトの

1. 重ね順の確認
1. ソート方法

の2点について詰まったのでメモを残しておきます。

## 結論

document.pageItemsなどの*Itemsコレクションとselection配列は、重ね順でソート済みです。
ユーザーが後からソートする必要はありません。

## 問題の詳細

### Adobe Illustrator Extend Scriptとは

Adobe IllustratorにはJavaScriptによる操作が可能です。

[公式リファレンス](https://www.adobe.com/devnet/illustrator/scripting.html)

定型処理をスクリプト化しておくことで、作業効率を向上させることができます。

### ドキュメント上のオブジェクトの取得

このスクリプト上では、さまざまなIllustrator上の情報の確認と操作ができます。

たとえば

```js
activeDocument.selection
```

で現在選択しているオブジェクトの配列を取得できます。

```js
activeDocument.pageItems
```

ならばドキュメント上のすべてのアートアイテム（レイヤーを除くテキスト、シェイプ、画像など）を取得できます。

selection以外の〇〇Itemsクラスは、コレクションであり**配列ではありません**。
そのためfor文で中身を取得することはできますが

1. ReadOnlyであり、代入できない。
2. sort, reverseなどのArray.prototype関数が使えない。

という違いがあります。

コレクションに対してArray.prototype関数を利用したい場合は、要素をforループで取り出し新規の配列にpushで詰め直すなどの処理が必要になります。

### 重ね順の取得

これらの配列およびコレクションは取得した段階で、重ね順の最前面から順にソートされています。
ユーザー側が明示的にソートする必要はありません。
最前面からの処理が必要な場合はforループで、最背面からの処理が必要な場合はデクリメントのforループで処理ができます。

### zOrderPositionについて

アートアイテムのインスタンスには、``zOrderPosition``という変数が設定されていることがあります。これは同一のグループ / レイヤー内での重ね順を示すものです。
最背面にあるアートアイテムにはzOrderPosition自体がありません。undefinedではなくプロパティ自体が存在しないため、アクセスするとエラーでスクリプトが停止します。zOrderPositionにアクセスする場合はtry構文でエラーを避けるか、プロパティ自体にはアクセスせずにzOrder関数を経由して操作することをオススメします。

配列およびコレクションの順序がオブジェクトの重ね順であるということがリファレンスに明示されていないため、しばらく詰まりましたが処理は不要でした。

以上、ありがとうございました。