カテゴリー: テクノロジー

誰でもできるプログラミング

こんにちは。開発担当のマットです。

以前も言ったことがありますが、開発はとても楽しい仕事です。
PCに文字を打ち込むだけで、コンピュータがその指示を従って、面白いものを生み出せます。

でも、一度もプログラムを書いたことがない人は、どこから始まればいいかわからないでしょう。私も長いこと、プログラムの書き方を一切わからなくて、不思議な魔法のようでした。

それで、誰でもすぐに作れるプログラムを紹介したいと思います。

必要な準備

多くのプログラミング・プロジェクトに特殊な言語やコンパイラーのインストールが必要です。今回は、めっちゃ簡単に、ブラウザーとテキスト・エディター(メモ帳など)さえあれば、動くJavaScriptのプログラムを作ろうと思っています。

つまり、特に必要な準備はありません。

始めましょう〜

まずは、テキストエディターを開いて、「Hello」を書きましょう!
終わったら、program.html として保存しましょう!
保存先はどこでもいいです。デスクトップでも問題ありません。

HTMLファイルなので、ダブルクリックすると規定のブラウザーで開かれるでしょう。私の場合、Chromeで「Hello」が表示されます。

これはプログラム?

いや、今やったことは(とても簡単な)ウェブページの作成です。
動的な内容を出力する何かを開発しないと、「プログラム」と呼べないでしょう。

では、それを作りましょう!
現代のブラウザーは JavaScript という言語を解釈する能力を持っています。
Helloの後ろに、Javascriptのコードを書く部分を定義しましょう!これはHTMLタグというものでできます。

書き方は簡単です。
Javascriptのコード部分の開始は <script> で定義する。
Javascriptのコード部分の終了は </script> で定義する。

なお、コード部分にアラートを出す処理を入れましょう!
Javascriptでは、 alert(‘ホゲホゲ’); でできます。 

先程のファイルに以下を書きましょう〜

Hello
<script>
    alert('こんにちは!');
</script>

保存して、ブラウザーをリロードすると、アラートが表示されます!

やった!なんか動き出しましたよ!

基礎の準備ができ、初めてのスクリプトを書きましたので、面白いものを作りましょう!

スプラウティモン

せっかく、スプラウト株式会社のブログなので、スプラウティモンという、モンスター・ゲームを作りましょう!
150匹のモンスターがいて、全部集めることが目標!

150匹のモンスターの名前を決めなければならないことが面倒ので、プログラムで自動にやりましょう。こうやってします。

  1. スプラウティモンの名前のパーツを手動で決める。
  2. 名前のパーツを適当に組み合わせて、名前を作り出す。
  3. その名前をページに出力
  4. それを150回繰り返します。

よっし!目標を設定しました。まずは名前のパーツを手動で決めましょう。
プログラミングで、何かのコレクションを「配列」といいます。
名前のパーツのコレクションが必要ので、まずはpartsという配列を作りましょう。
言語によって、やり方が違いますが、Javascriptの場合は以下です。

Hello
<script>
	var parts = ['ほげ', 'ホゲ'];
</script>

「ほげ」と「ホゲ」で、あまりいい名前作れないので、「ファイヤ」とか「アイス」とかを勝手に決めて、面白さそうなリストを作りましょう。

Hello
<script>
	var parts = ['ファイヤ','アイス','ウィング','ライオン','イシ','デビル','ウルトラ','スーパー','デンキ','パワー','ブリザード','フラワー','ドラゴン','ロック','メガ','ワニ','ドロ','クマ','ヘビ','サメ'];
</script>

これでパーツを定義しましたが、プログラムで3つをランダムに組み合わせて、スプラウティモンの名前を決めましょう。

では、ランダムなパーツを選択する方法はちょっとややこしいですが、以下となります。

parts[Math.floor(Math.random() * parts.length)];

 これを完全に理解しなくてもいいですが、「parts配列の中から、最初から、最後までの中、どれかランダムなものを返す」という意味です。

alertで出してみましょう!

Hello
<script>
	var parts = ['ファイヤ','アイス','ウィング','ライオン','イシ','デビル','ウルトラ','スーパー','デンキ','パワー','ブリザード','フラワー','ドラゴン','ロック','メガ','ワニ','ドロ','クマ','ヘビ','サメ'];
	alert(parts[Math.floor(Math.random() * parts.length)]);
</script>

僕の場合、「メガ」が出ました。リフレッシュする度に、違う名前が出てきます。
ところで、アラートじゃなくて、直接ページに書き出す場合、「document.write」を使えます。それ使いましょう。なお、3つを組み合わせたいので、その行を3回書きましょう。

Hello
<script>
	var parts = ['ファイヤ','アイス','ウィング','ライオン','イシ','デビル','ウルトラ','スーパー','デンキ','パワー','ブリザード','フラワー','ドラゴン','ロック','メガ','ワニ','ドロ','クマ','ヘビ','サメ'];
	document.write(parts[Math.floor(Math.random() * parts.length)]);
	document.write(parts[Math.floor(Math.random() * parts.length)]);
	document.write(parts[Math.floor(Math.random() * parts.length)]);
</script>

すると、

なんか面白いですね。
7才の息子に聞いたら、100点満点で「100点」の名前だそうです!(笑)

どうやって150回?

プログラミング言語でループを書く事ができます。
ループとは、何かの作業を繰り返す時に使うものです。
Javascript では、以下のように書きます。

for (i = 0; i < 150; i++) {
    //150回実行したいコード
}

「Hello」をもっと適切な言葉に変えて、
各スプラウティモンの名前の前に改行(HTMLで「<br />」と書く)も入れましょう!

名前のパーツを150回も定義する必要はないので、ループの外で問題ありません。

すプラウティモンのリスト!
<script>
	var parts = ['ファイヤ','アイス','ウィング','ライオン','イシ','デビル','ウルトラ','スーパー','デンキ','パワー','ブリザード','フラワー','ドラゴン','ロック','メガ','ワニ','ドロ','クマ','ヘビ','サメ'];
	for (i = 0; i < 150; i++) {
		document.write('<br />');
		document.write(parts[Math.floor(Math.random() * parts.length)]);
		document.write(parts[Math.floor(Math.random() * parts.length)]);
		document.write(parts[Math.floor(Math.random() * parts.length)]);
	}
</script>

こうすると・・・・

できました!おめでとうございます!
プログラムを書くことに成功しました。

まとめ

今回、とても簡単なプログラムを紹介しました。
よく考えたら、重複の名前がでてくる可能性もあり、「ドロドロドロ」のような変わった名前も出力されるかもしれません(確率が低くても)。
プログラマはこういうことを考慮して、プログラムを柔軟に作らなければなりません。

とても楽しい仕事で、今後も多くのプログラムを作るチャンスを楽しみにしています。


【Solr】Date Mathによる日付表現

はじめに

Solr では、pdate 等の時刻を扱うフィールドに対するクエリで使用できる Date Math という表現が用意されています。「今日からN日前」のような表現を使いたいときに便利です。 この記事ではDate Mathについてまとめました。

通常の日付表現

Solr では日付のフィールドは以下の形式で表現します。

2020-03-22T14:55:29Z

ミリ秒までの精度があるので、小数点表記も有効です。

2020-03-22T14:55:29.123Z

時刻は秒まできちんと表記しなければエラーになります。

ミリ秒よりも小さい桁が書いてあっても受付けますが、無視されます。

エラーになる例

2020-03-22
2020-03-22T14:55Z

Date Math

Date Mathは、特定の時点からの相対的な時刻を指定しやすくするための表記法です。
起点として良く使用される「今現在」を指定するために NOW という Date Math が用意されています。

Date Mathではまず起点となる日付を書き、それプラスN日という形で表記します。
「2ヶ月後」

NOW+2MONTH

「10日前」

NOW-10DAY

「1年後」

NOW-1YEAR

プラス/マイナスの部分は連続して書くことができます。

NOW+1YEAR+3MONTH+5DAY

起点として通常の日付を指定することもできます。

2020-03-22T10:15:18Z+7DAY

丸め表記

スラッシュ(‘/’)を併用することで、「〜の最初」を表現できます。
たとえば現在時刻が2020年3月22日11時22分33秒だとします。

NOW/HOUR

→2020年3月22日11時00分00秒

NOW/DAY

→2020年3月22日00時00分00秒

Date Math と組み合わせて使えるリクエストパラメータ

NOW

NOW パラメータにより、Date Math で記述した “NOW” を特定の日付に設定することができます。 NOW パラメータには、いわゆる UNIX TIME の Long 値を指定します。
NOW パラメータを指定することで、複数のノードにまたがる分散検索での NOW の値を揃えることができます。テストのときにも役に立ちそうです。

TZ

TZ パラメータを指定することで、デフォルト UTC である Date Math の日付計算を別のタイムゾーンとして扱うことができます。


【家で遊ぶ】Javascript で簡易サンプラー

Photo by Kofi Nuamah Barden on Unsplash

Javascript を使ってブラウザの Chrome で鳴らせる簡易サンプラーを作ってみます。

こんなの。

DJブースの隅やイベント会場に置いてあるやつです。

爆発音を鳴らしてみたり、録音機能があったり、パターンを保存して再生する機能が付いてあったり、利用場面に合わせて様々な使われ方をされます。

ビートボックス、リズムマシンとも呼ばれたりします。

Tone.js

今回は、簡易版ということで、音が3つ鳴るだけのサンプラーです。

作成に当たっては、偉大なる Web Audio framework の Tone.js を利用します。

A Web Audio framework for making interactive music in the browser.
https://github.com/Tonejs/Tone.js/

動作デモ

まずは見ていただいた方が早いと思うので、 作ったものを netlify に上げておきました。

netlify.app

Chrome 以外では確認していません。
音が出るので注意。
PC、最近のスマートフォンなら動くと思いますが、環境によってはブラウザの「音声」を許可する必要あり。

やってること

主要部分はこんな感じになります。

!function(){
	Tone.Transport.bpm.value = 80;
	Tone.Transport.loop = false;
	const sampler = new Tone.Sampler({
		'C1' : '/bd.mp3',
		'E1' : '/sd.mp3',
		'F#1': '/hh.mp3'
	}, ()=>{
		console.log('initialized')
	}).toMaster();
	const sound = note => {
		const cell = document.querySelector('[data-note="'+note+'"]');
		sampler.triggerAttackRelease(note, .3);
		cell.style.animationName = 'fade1';
		setTimeout(()=>{
			cell.style.animationName = '';
		}, 300)
	}
	const beatbox = document.getElementById('petit-beatbox');
	beatbox.querySelectorAll('div').forEach(div=>{
		div.onclick = e => {
			sound(e.currentTarget.dataset.note)
		};
	});
	document.body.onkeypress = e => {
		if (e.code === 'KeyA') {
			sound('C1');
		} else if (e.code === 'KeyS') {
			sound('E1');
		} else if (e.code === 'KeyD') {
			sound('F#1')
		}
	}
}();

赤、黄、緑の四角をクリックするか、キーボードのASDでそれぞれ鳴らしたい音が再生されるようイベントリスナーをセットします。

ほぼこれだけです。

ボタンを追加して効果音や音色を設定していけば色々遊べます。

Javascript なので、その気になれば、その場でソースコードごと変更してしまうことも可能です。

(ラグがある場合は音自体の軽量化までやらないと駄目かも…)

家で遊ぶ

Tone.js には様々な API が用意されているので、頑張ればエフェクターやシーケンサーとしての機能も追加できます。

Tone.js っょぃ。

逆に、Tone.js のない標準の Web Audio API は、かなりしんどいです。
「シンプルなサイン波を440Hzで3秒間ほどほどの音量にして鳴らす」だけでもう再起不能に陥り寝込んでしまいます。

おうちで自家生産、サンプラーを作って遊んでみるのはいかがでしょうか。


Solr 8.4.0 で追加された”Untrusted Configsets”の制限について

Solr 8.4.0 の Changes には以下の項目があります。

SOLR-14071: Untrusted configsets (ones that are uploaded via unsecured configset API) cannot use <lib> directive. Consider enabling authentication/authorization so that the uploaded configsets are trusted. Note: If you already have a collection using untrusted configset that uses directive, it will not load after upgrading to 8.4. You can re-upload your configset using “bin/solr zk -upconfig ..” or place your libraries in the classpath and restart Solr.

「Untrusted configsets は lib ディレクティブを使えません」とあります。
configsets が trusted として扱われるためには、認証有りでアップロードしなければならないとのことです。Solr 8.4.0 では _default の solrconfig.xml から lib を使う設定が無くなったのもこの変更に合わせてのようです。

Untrusted configsets では lib ディレクティブが使えないというのが具体的にどういう意味なのかを確認してみました。

まず Solr 8.4.0 が起動した状態で sample_techproducts_configs (このサンプル設定には 8.4.0 でも lib ディレクティブが含まれます)を configsets_test という名前でアップロードします。

$ (cd solr-8.4.0/server/solr/configsets/sample_techproducts_configs/conf && zip -r - *) > configsets_test.zip
$ curl -X POST --header "Content-Type:application/octet-stream" --data-binary @configsets_test.zip "http://localhost:8983/solr/admin/configs?action=UPLOAD&name=configsets_test"

アップロードした configsets_test を使ってコレクションを作成します。

curl -s "http://localhost:8983/solr/admin/collections?action=CREATE&name=configsets_test&numShards=1&replicationFactor=1&collection.configName=configsets_test&omitHeader=true"
{
  "failure":{
    "127.0.1.1:8983_solr":"org.apache.solr.client.solrj.impl.HttpSolrClient$RemoteSolrException:Error from server at http://127.0.1.1:8983/solr: Error CREATEing SolrCore 'configsets_test_shard1_replica_n1': Unable to create core [configsets_test_shard1_replica_n1] Caused by: The configset for this collection was uploaded without any authentication in place, and use of  is not available for collections with untrusted configsets. To use this component, re-upload the configset after enabling authentication and authorization."},
  "Operation create caused exception:":"org.apache.solr.common.SolrException:org.apache.solr.common.SolrException: Underlying core creation failed while creating collection: configsets_test",
  "exception":{
    "msg":"Underlying core creation failed while creating collection: configsets_test",
    "rspCode":400},
  "error":{
    "metadata":[
      "error-class","org.apache.solr.common.SolrException",
      "root-error-class","org.apache.solr.common.SolrException"],
    "msg":"Underlying core creation failed while creating collection: configsets_test",
    "code":400}}

アップロードはできましたが、その configsets を使ってコレクションを作成することろでエラーになりました。

次に BASIC 認証を設定してからコレクション作成してみます。

$ ./solr-8.4.0/server/scripts/cloud-scripts/zkcli.sh -zkhost localhost:9983 -cmd put /security.json '{
"authentication":{
   "blockUnknown": true,
   "class":"solr.BasicAuthPlugin",
   "credentials":{"solr":"IV0EHq1OnNrj6gvRCwvFwTrZ1+z1oBbnQdiVC3otuq0= Ndd7LKvVBAaZIF0QAVi1ekCfAJXr1GGfLtRUXhgrF8c="}
 }
}'

ここで Solr を再起動して BASIC 認証が有効になった状態で再度コレクション作成。

$ curl --user solr:SolrRocks -s "http://localhost:8983/solr/admin/collections?action=CREATE&name=configsets_test&numShards=1&replicationFactor=1&collection.configName=configsets_test&omitHeader=true"
{
  "failure":{
    "127.0.1.1:8983_solr":"org.apache.solr.client.solrj.impl.HttpSolrClient$RemoteSolrException:Error from server at http://127.0.1.1:8983/solr: Error CREATEing SolrCore 'configsets_test_shard1_replica_n1': Unable to create core [configsets_test_shard1_replica_n1] Caused by: The configset for this collection was uploaded without any authentication in place, and use of  is not available for collections with untrusted configsets. To use this component, re-upload the configset after enabling authentication and authorization."},
  "Operation create caused exception:":"org.apache.solr.common.SolrException:org.apache.solr.common.SolrException: Underlying core creation failed while creating collection: configsets_test",
  "exception":{
    "msg":"Underlying core creation failed while creating collection: configsets_test",
    "rspCode":400},
  "error":{
    "metadata":[
      "error-class","org.apache.solr.common.SolrException",
      "root-error-class","org.apache.solr.common.SolrException"],
    "msg":"Underlying core creation failed while creating collection: configsets_test",
    "code":400}}

やはりエラーになります。

confitsets を trusted として扱ってもらうために、認証有りの状態で再度アップロードします。UPLOAD コマンドでは上書きできないので、DELETE してから UPLOAD します。

$ curl --user solr:SolrRocks -X POST --header "Content-Type:application/octet-stream" --data-binary @configsets_test.zip "http://localhost:8983/solr/admin/configs?action=DELETE&name=configsets_test"
{
  "responseHeader":{
    "status":0,
    "QTime":220}}
$ curl --user solr:SolrRocks -X POST --header "Content-Type:application/octet-stream" --data-binary @configsets_test.zip "http://localhost:8983/solr/admin/configs?action=UPLOAD&name=configsets_test"
{
  "responseHeader":{
    "status":0,
    "QTime":292}}

認証有りでアップロードした configsets を使ってコレクションを作成してみます。

$ curl --user solr:SolrRocks -s "http://localhost:8983/solr/admin/collections?action=CREATE&name=configsets_test&numShards=1&replicationFactor=1&collection.configName=configsets_test&omitHeader=true"
{
  "success":{
    "127.0.1.1:8983_solr":{
      "responseHeader":{
        "status":0,
        "QTime":2126},
      "core":"configsets_test_shard1_replica_n1"}}}

今度はうまくいきました。

結論としては、「Untrusted configsets では lib ディレクティブが使えない」とは、libディレクティブを含む Untrusted configsets ではコレクションを生成できないという意味でした。

ところで、configsets アップロードする方法としては、Solr の Configsets API を使う方法とは別に zookeeper に直接アップロードする方法もあります。

$ ./solr-8.4.0/server/scripts/cloud-scripts/zkcli.sh -zkhost localhost:9983 -cmd upconfig -confdir solr-8.4.0/server/solr/configsets/sample_techproducts_configs/conf -confname configsets_test2
INFO  - 2020-02-23 22:52:50.804; org.apache.solr.common.cloud.ConnectionManager; Waiting for client to connect to ZooKeeper
INFO  - 2020-02-23 22:52:50.821; org.apache.solr.common.cloud.ConnectionManager; zkClient has connected
INFO  - 2020-02-23 22:52:50.821; org.apache.solr.common.cloud.ConnectionManager; Client is connected to ZooKeeper
$ curl --user solr:SolrRocks -s "http://localhost:8983/solr/admin/collections?action=CREATE&name=configsets_test2&numShards=1&replicationFactor=1&collection.configName=configsets_test2&omitHeader=true"
{
  "success":{
    "127.0.1.1:8983_solr":{
      "responseHeader":{
        "status":0,
        "QTime":1361},
      "core":"configsets_test2_shard1_replica_n1"}}}

なんとコレクション生成できてしまいました。

現時点では Untrusted Configsets の制限はまだ不十分なようで、今後の進展に注意する必要がありそうです。


SolrにBasic認証を設定する

Solrの管理画面やAPIへのアクセスに認証を掛けることができます。この記事ではBASIC認証を設定してみます。

SolrCloudの環境では Zookeeper の /security.json に設定ファイルを置きます。 Solrリファレンス にはユーザ:solr パスワード:SolrRocks で設定する例が載っています。

$ ./zkcli.sh -zkhost localhost:9983 -cmd put /security.json '{
"authentication":{
   "blockUnknown": true,
   "class":"solr.BasicAuthPlugin",
   "credentials":{"solr":"IV0EHq1OnNrj6gvRCwvFwTrZ1+z1oBbnQdiVC3otuq0= Ndd7LKvVBAaZIF0QAVi1ekCfAJXr1GGfLtRUXhgrF8c="}
 }
}'

この後Solrの再起動でBASIC認証が有効になり、管理画面にブラウザでアクセスすると、ユーザ名とパスワードの入力を促されます。ここで solr と SolrRocks で確かにログインできます。

このままリファレンスに載っているユーザとパスワードを使い続ける訳にはいかないので、別のユーザを追加することを考えます。初めは security.json に追加の設定を記載するのかと思いましたが、パスワードをSolrが期待する形式でハッシュ化する方法が分かりませんでした。結局のところ、リファレンスに書いてある通り、APIで設定変更するしかなさそうです。

ここで、APIへのHTTPアクセスにも認証が必要となります。

新しいユーザの追加

curl --user solr:SolrRocks http://localhost:8983/solr/admin/authentication -H 'Content-type:application/json' -d '{"set-user": {"solradmin":"solrpass"}}'

最初に設定した solr ユーザの削除

curl --user solr:SolrRocks http://localhost:8983/solr/admin/authentication -H 'Content-type:application/json' -d  '{"delete-user": ["solr"]}'

追加と削除の後の security.json の内容を確認

$ server/scripts/cloud-scripts/zkcli.sh -zkhost localhost:9983 -cmd get /security.json
{"authentication":{
    "blockUnknown":true,
    "class":"solr.BasicAuthPlugin",
    "credentials":{"solradmin":"AkZTG0uVSAgfzB/OC+kI1tqw9aeR8pP05tpNdcnnfN8= wRKTRwEcTX5eiCgEmCfIRXdRf9zIq2/Aef/LP6ZzdIQ="},
    "":{"v":13}}}

確かに変わっています。パスワードもハッシュ化されています。

管理画面だけではなく、コマンドラインツールも認証が必要になります。

bin/post -c mycollection data.json
POSTing file data4.json (application/json) to [base]/json/docs
SimplePostTool: WARNING: Solr returned an error #401 (require authentication) for url: http://localhost:8983/solr/mycollection/update/json/docs
SimplePostTool: FATAL: Looks like Solr is secured and would not let us in. Try with another user in '-u' parameter

オプションで指定するだけなので簡単。

bin/post -u solradmin:solrpass -c mycollection data.json

昔は認証が必要な場合は Jetty 側でなんとかしていたようですが、今は Solr 側で設定できるようになっています。Solr 8.4 からは認証が設定されていない場合にはAPI経由での設定ファイルのアップロード(というかアップロードする設定の内容)に制限が付くこともあるので、この辺の設定もきちんと押さえておきたいところです。