値と変数、型推論

昨日、Scala のインストールが終わったので、今日から使ってみよう。

適当なフォルダに移動して sbt console コマンドで REPL を起動する。そして “Hello, World!” と入力してみる。

scala> "Hello, World!"
res0: String = Hello, World!

1行目が REPL のプロンプトと入力、2行目がそのレスポンスだ。ここでは入力された値が String 型で Hello, World! という値を持つことが表示されている。res0 ってのは REPL が勝手につけた名前らしい。これは後から使うこともできる。

scala> res0
res1: String = Hello, World!

いくつか値を入力してみよう。

scala> 123
res2: Int = 123

scala> 12345L
res3: Long = 12345

scala> 1.23
res4: Double = 1.23

scala> 1.23e4
res5: Double = 12300.0

scala> 1.0 == 1
res6: Boolean = true

それぞれ Int とか Double とかの型に解釈されている。Scala には型推論の機能が備わっているので、型を宣言しなくても適当な型に解釈してくれる。

次、変数。Scala では変数は宣言してからでないと使えない。変数の宣言には var と val の2つがあって、前者は再代入が可能だけど、後者は再代入できない。試してみよう。

scala> var x = 3
x: Int = 3

scala> x = 5
x: Int = 5

scala> x
res7: Int = 5

scala> val y = 2
y: Int = 2

scala> y = 7
<console>:12: error: reassignment to val
y = 7
^

var で宣言した x には再代入できているけど、val で宣言した y に再代入したらエラーになっているのがわかる。

Scala では基本的に再代入できない val で宣言した変数を使い、var はあまり使わないとのこと。このへんは関数型プログラミングらしいところかな。

ちなみに、var で宣言した x に再代入することはできるけど、宣言の時に型推論が働いて x の型は Int になっている。なので Int 以外の型を代入することはできない。

scala> x = "hello"
<console>:12: error: type mismatch;
found : String("hello")
required: Int
x = "hello"
^

さて、ここまでは変数の型は型推論に任せてきたけど、明示的に宣言することもできる。次のようにする。

scala> val z: Int = 3 * 3
z: Int = 9

型を変数名の後につけるのは Go に似てるな。

以上、とりあえずここまで。

sbtとScalaのインストール

昨日は JDK のインストールをしたので、今日は Scala をインストールする。

といっても、通常は Scala を直接インストールするのではなく、sbt というツールを使うのが普通のようだ。そこで、まずは sbt をインストールする。

 cf. sbt – Download

上のダウンロードページから、最新版(1.2.8)の msi インストーラをダウンロード。ダブルクリックするとインストールが始まる。基本的に [Next] ボタンをクリックしていけば完了する。

sbt のインストールが完了したら、適当なフォルダを掘ってコマンドラインで sbt console コマンドを起動してみよう。こんなメッセージが出て入力待ちの状態になる。

^o^ > sbt console
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=256m; support was removed in 8.0
[info] Updated file C:\Users\takatoh\Documents\sandbox\scala\project\build.properties: set sbt.version to 1.2.8
[info] Loading project definition from C:\Users\takatoh\Documents\sandbox\scala\project
[info] Updating ProjectRef(uri("file:/C:/Users/takatoh/Documents/sandbox/scala/project/"), "scala-build")…
[info] Done updating.
[info] Set current project to scala (in build file:/C:/Users/takatoh/Documents/sandbox/scala/)
[info] Updating …
[info] Done updating.
[info] Non-compiled module 'compiler-bridge_2.12' for Scala 2.12.7. Compiling…
[info] Compilation completed in 6.282s.
[info] Starting scala interpreter…
Welcome to Scala 2.12.7 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_201).
Type in expressions for evaluation. Or try :help.
scala>

これは Scala の REPL で、対話的に実行できる環境。Ruby の irb みたいなものだ。「Welcome to Scala 2.12.7」と出ているので、Scala 2.12.7 がインストールされたことがわかる。

REPL を終了するには次のようにする。

scala> :quit

次回からはこの REPL を使って、Scala を触ってみることにする。

JDKをWindowsにインストール

Scala は JavaVM 上で動作する言語なので、まずは JDK(Java Development Kit)をインストールする。

今、Oracle のサイトを見たら最新版が JDK12 になってるけど、Scalaの公式サイトのこのページによると、JDK12 は出たばかりで十分にテストされていないようなので、以前にダウンロードした JDK8 を使うことにする。

インストーラは Windows の実行形式(exe)になっているので、ダブルクリックして実行すれば、あとはほぼ自動で完了する。ただし環境変数を設定してくれないので、これは自分で設定する必要がある。

必要な環境変数は2つ、PATH と JAVA_HOME だ。PATH は実行ファイルの検索パスで、Java の実行ファイルがあるフォルダを指定(というか追加)する。一方、JAVA_HOME には Java をインストールしたフォルダを設定する。

それぞれ次のようにした。

  • PATH には C:\Program Files\Java\jdk1.8.0_201\bin を追加
  • JAVA_HOME には C:\Program Files\Java\jdk1.8.0_201 を指定

これでOKのはず。コマンドプロンプトで確認してみる。

^o^ > java -version
java version "1.8.0_201"
Java(TM) SE Runtime Environment (build 1.8.0_201-b09)
Java HotSpot(TM) 64-Bit Server VM (build 25.201-b09, mixed mode)

大丈夫のようだ。

明日は Scala をインストールする(予定)。

Scalaを始めようと思う

新しい年には新しい言語を、ということで Scala を始めようと思う。

「新しい年」っていってももう3分の1も過ぎようとしてるけど、今からでも遅くはない、とにかくやってみようってことだ。

そもそも年のはじめから始めるつもりで去年の年末に「実践Scala入門」という本を読んだ。それが今頃になってしまったのは、俺の怠惰のせいなんだけど、とにかく今はドワンゴの新卒エンジニア向け研修資料というのを読んでいる。とりあえずはこれを読んでやってみて、「実践Scala入門」も読みなおしてみるつもり。

Scala は JavaVM 上で動作する、オブジェクト指向プログラミングと関数型プログラミングのハイブリッド言語だ。オブジェクト指向(Ruby,Python)も関数型(Haskell,OCaml)もやったことがあるけど、そのハイブリッドというのはなかなかに興味をそそる。

JavaVM 上で動作をする言語といえば、Java と Clojure をちょっと触ったことがある程度で、Java の知識もないに等しいようなもんだけど、まぁなんとかなるだろう。とにかくはじめてみる。

ついでにコップ本も買った。

rsyncで別のマシンにファイルをバックアップする

ファイルのバックアップというと、今までは同じマシンの外付けハードディスクに rsync でコピーしていた。こんな感じ。

rsync -av --delete /home/takatoh/sulaiman/ /media/opabinia/backup/sulaiman

これをスクリプトにして cron で自動的にバックアップしていたわけだ。

さて、先日、PC が1台余ったってことを書いた。何に使おうか考えていたんだけどファイルのバックアップサーバにしようと思う。

そこで今日はその前段階として、コピー元のマシン(wplj)から別のマシン(apostrophe)に rsync でファイルをバックアップすることを試してみる。↓このページが参考になった。

 cf. いますぐ実践! Linux システム管理 / Vol.009

前提条件

  • バックアップ元マシン:wplj、ユーザ:takatoh、ディレクトリ:~/sulaiman
  • バックアップ先マシン:apostrophe、ユーザ:sulaiman、ディレクトリ:~/backup/sulaiman

バックアップの方法

別のマシンにバックアップをするのは難しいかと思ったけど、大したことはない。ユーザ名とホスト名を指定してやればいいだけだ。

takatoh@wplj $ rsync -azv -e ssh --delete ~/sulaiman/ sulaiman@apostrophe:~/backup/sulaiman

-z は転送時にファイルを圧縮するオプション。-e ssh は ssh を利用するオプションだ。これで無事にバックアップできる。

ただし、このままでは実行するたびにパスワードを入力しなきゃならない。cron を使って自動でバックアップするには使えない。

sshの鍵を利用

パスワードを入力しないで済むようにするには、あらかじめ両方のマシンに ssh の鍵を仕込んでおけばいい。今回は新たにバップアップ用の鍵を作ることにしよう。

takatoh@wplj $ ssh-keygen -f ~/.ssh/synckey -N ""

これで ~/.ssh ディレクトリに synckey と synckey.pub というファイルができる。前者が秘密鍵、後者が公開鍵だ。この公開鍵をバックアップ先のマシン(apostrophe)にコピーする。

takatoh@wplj $ scp ~/.ssh/synckey.pub sulaiman@apostrophe:~/.ssh/

そして、バップアップ先のマシンで、コピーされた公開鍵(~/.ssh/synckey.pub)を ~/.ssh/authorized_key ファイルに追加する。

sulaiman@apostrophe:~$ cd .ssh
sulaiman@apostrophe:~/.ssh$ cat synckey.pub >> authorized_keys
sulaiman@apostrophe:~/.ssh$ chmod 600 authorized_keys
sulaiman@apostrophe:~/.ssh$ rm synckey.pub

これでパスワードなしでバックアップできるようになったはずだ。つぎのようにする。

takatoh@wplj $ rsync -azv -e "ssh -i ~/.ssh/synckey" --delete ~/sulaiman/ sulaiman@apostrophe:~/backup/sulaiman

OK、うまくいった。これをスクリプトにしてやれば cron で自動化することができる。

修理に出していたPCが戻ってきた

先月末にダメになってしまった PC、修理に出していたのが戻ってきた。メモを見ると DELL のサポートに電話して修理依頼をしたのが4月9日なので、1週間かからずに戻ってきたわけだ。

故障個所は CPU ファンだった。どうやらファンを交換して修理完了したようだ。ハードディスクのデータは保証しない、といわれていたけど、起動してみたら元のまま CentOS7 が立ち上がった。データも大丈夫のようだ。

先日のエントリに書いた通り、この PC(ホスト名は nightschool)はインターネットに公開していたサーバで、web アプリを2つ動かしていた。両方とも新しいサーバ(unclemeat)に引き継いでいるので、余った形になる。

さて、何に使おうか。

Windows10+Tomcat上でGitBucketを動かす

GitBucket という GitHub のクローンを見つけた。GitHub クローンといえば GitLab が有名だけど、web の情報を見ていると構築するのが結構面倒そうで、試したことがなかった。その点、GiuBucket は war ファイルを Java で実行するだけ、という簡単さ。早速試してみよう。

前提条件

  • windows10
  • Java はインストール済み

まずは簡単に

GitBucket は たけぞうさんという方が Scala で書いた GitHub クローンだ。war ファイルで配布されているので、ダウンロードしたらすぐに実行できる。

 cf. GitBucket 4.31.0、4.31.1をリリースしました – たけぞう瀕死ブログ

4.31.1 が最新バージョンのようなので、上のページからリンク先にとんで、gitbucket.war ファイルをダウンロードする。あとは実行するだけだ。

^o^ > java -jar gitbucket.war

これだけで OK。http://localhost:8080/ にブラウザでアクセスするとアプリが動作している。

使い方も簡単

デフォルトで root ユーザーが用意されている。まずはこの root でサインイン(パスワードも root)して、右上のプルダウンメニューから System Administration を選び、ユーザーを追加する。今回は takatoh を追加した。ユーザー名とパスワード、フルネーム、メールアドレスが必須みたいだ。

あとは、作ったユーザーでサインインしなおせば、自由にリポジトリを作ったりできる。GitHub を使い慣れていれば迷うこともなさそうだ。

Tomcatをインストール

さて、うまく動いたわけだけど、いちいちコマンドラインから実行するのでは面倒で仕方がない。というわけで、Apache Tomcat の出番だ。

Tomcat は↓ここから最新版(9.0.17)をダウンロードした。

 cf. Tomcat 9 Software Downloads – Apache Tomcat

32-bit/64-bit Windows Service Installer ってやつね。ファイル名は apache-tomcat-9.0.17.exe だった。このファイルを実行すればインストールされる。

インストール自体は、途中の Tomcat Administrator Login のユーザー名とパスワードを入力した以外はすべてデフォルトにした。ただし、最後の Run Apache Tomcat のチェック外してすぐに実行しないようにする。

GitBucketをインストール

インストールといっても、Tomcat のインストールフォルダにある webapps フォルダに gitbucket.war ファイルをコピーするだけだ。

次に、環境変数 GITBUCKET_HOME を設定する。これは データベースや各リポジトリを格納するフォルダを指定する。これを指定しておかないと、データがどこにあるのかわからない。今回は C:\GitBucket に設定した。

Tomcatを起動

スタートメニューから、Apache Tomcat 9.0 Tomcat9 → Configure Tomcat を選択。開いたウィンドウで、Startup type を Automatic にして Start ボタンをクリック。これで Tomcat が起動する。Startup type を Automatic にしたのは、Windows 起動時に自動で Tomcat も起動させるため。

GitBucketにアクセス

Tomcat はポート8080で待ち受けているので、http://localhost:8080/githubucket/ にアクセスする。コマンドラインから立ち上げたときとパスが違うので注意。だけど、これで無事アクセスできた。

さいごに

プライベートでは GitHub なり BitBucket なりに自由にアクセスできるので、わざわざ構築する必要もないのだけど、会社の PC からはアクセスできない(制限されている)ので、そういう環境では役に立つだろう。週が明けたらやってみよう。

DELL製PCにCentOS7をインストールしてもブートできない

昨日の話。サーバにしていた PC がダメになった。しばらく前から異音がしていて、これはもうヤバげだな、という感じではあったんだけど、昨日リブートしてみようと思い立ってそうしてみたら、ダメになった。余計なことはするもんじゃない。

もう少し正確に言うと、OS (CentOS7だ)は起動する。Nginx も起動する。けど、肝心の web アプリが起動しない、という状態。リブートしただけなので、何も変わっていないはずなんだけど、起動しないものは起動しない。そもそも上に書いたとおりハード的にもヤバそうだったので、早々に諦めて、新しいPCに移行することにした。実は、しばらく前から異音が発生していたので新しい PC を買ってあったのだ。

新しい PC は、DELL 製の OptiPlex 3060 Micro という機種。これに CentOS7 をインストールしようというわけだ。BIOS (というか最近のは UEFI というらしい)の設定を変更して外付け DVD ドライブからブートするようにしてインストール。インストール自体は特につまづくこともなく終了(過去記事を見てほしい)。

ところが、DVD を抜いてリブートしてもできない。ブータブルなメディアが見つからない、とかなんとかそんなことを言われる。そんなこと言われても、インストールできたんだからなんとかなるだろう、と思って UEFI の設定を変更しようと試みるも、UEFI というのは Windows 向けの設定になっているし(変更しようにもファイルシステムが見つからないと言われる)、レガシーな BIOS (インストール時にはこちらに設定した)には内部のハードディスクからブートするという選択肢がない。ように見える。

BIOS に内部ハートディスクからブートする機能がないとすると、UEFI を使うしか無いんだけど、どうもググった限りで分かったのは CentOS7 は UEFI に対応していないらしいということと、Ubuntu は対応しているらしい、ということ。

そこで、Ubuntu (18.04 の日本語REMIX版)をインストールしてみた。結果、今度はちゃんとブートするようになった。まだ OS をインストールしただけで、web アプリの構築とかしてないんだけど、今のところ大丈夫そうだ。

というところまでが、昨日の話。今日は web アプリを構築して早くサーバとして復帰させたい……んだけど、今日は時間がないんだよなぁ。

[追記]

何とか、最低限の復旧は果たした。

あと、ホスト名は unclemeat にした。

webフォントを使ってみた

さくらインターネットでは、無料でモリサワのwebフォントが使える(30書体)というので、使ってみた。このブログじゃなくて、ホームページ(PanicBlanket)のほうだ。

 cf. レンタルサーバ Webフォント機能 – さくらのサポート情報

利用するには、まずサーバコントロールパネルにログインして、利用するドメインを登録する。登録できるドメインはメニューから選べばいい。今回は panicblanket.com を登録した。

次に、html ファイルに JavaScript のファイルを読み込む設定をする。なんでフォントを使うのに JavaScript が要るのかわかんないんだけど。まぁ、そういう説明になってるので素直に従う。

html といっても、ホームページは静的サイトジェネレータの Middleman で作っているので、layouts/laytout.erb ファイルにつぎの行を追加した。

    <script type="text/javascript" src="//webfonts.sakura.ne.jp/js/sakura.js"></script>

次にスタイルシートで適当にフォントを設定してやる。ここは書くのがめんどくさいので割愛。そんでもってサイトのビルド。

takatoh@apostrophe $ bundle exec middleman build

あとは、新しくなったファイルを FTP でサーバにアップしてやればOK。


3本のひもで作る四角形

3月も下旬になってしまった。

今回もたまたま見つけたネタ。前回と同じブログから。

 cf. 3本のひもで作る四角形 – utthi_fumiの日記

同じ長さの3本のひもを折り曲げて3つの四角形を作ります。 そのうち2本でそれぞれ長方形を作り、残りの1本は正方形を作ります。 このとき、作った2つの長方形の面積の和が、正方形の面積と同じになることがあります。 (ただし、いずれの長方形、正方形も辺の長さは整数)

例)紐の長さが20の時

1本目 縦1×横9の長方形→面積=9

2本目 縦2×横8の長方形→面積=16

3本目 縦5×横5の正方形→面積=25

さらに、ひもの長さを変えてできる長方形と正方形の組をカウントします。 ただし、同じ比で整数倍のものは1つとしてカウント

例)紐の長さが40の時

1本目 縦2×横18の長方形→面積=36

2本目 縦4×横16の長方形→面積=64

3本目 縦10×横10の正方形→面積=100

紐の長さが60の時

1本目 縦3×横27の長方形→面積=81

2本目 縦6×横24の長方形→面積=114

3本目 縦15×横15の正方形→面積=225

紐の長さを1から500まで変化させる時、2つの長方形の面積の和と 正方形の面積が同じなる組が何通りあるか?


Python でやってみる。

import math
from functools import reduce


def main():
    s = set()
    for l in range(1, 501):
        for c in height_of_rectangles(l):
            s.add(reduction(c))
    for c in s:
        print(format_rect(c))
    print(len(s))

def combi(l):
    if l % 4 == 0:
        h3 = int(l / 4)
        return [(h1, h2, h3) for h2 in range(1, h3) for h1 in range(1, h2)]
    else:
        return []

def area(h, l):
    w = int(l / 2) - h
    return h * w

def height_of_rectangles(l):
    hor = []
    for c in combi(l):
        (h1, h2, h3) = c
        if area(h1, l) + area(h2, l) == area(h3, l):
            hor.append(c)
    return hor

def format_rect(c):
    (h1, h2, h3) = c
    l = h3 * 4
    w1 = h3 * 2 - h1
    w2 = h3 * 2 - h2
    return "{l}: {h1} * {w1} + {h2} * {w2} = {h3} * {h3}".format(l=l, h1=h1, w1=w1, h2=h2, w2=w2, h3=h3)

def reduction(c):
    r = reduce(math.gcd, c)
    return tuple(map(lambda x: int(x / r), c))


if __name__ == '__main__':
    main()

実行結果:

116: 8 * 50 + 9 * 49 = 29 * 29
260: 9 * 121 + 32 * 98 = 65 * 65
100: 1 * 49 + 18 * 32 = 25 * 25
340: 8 * 162 + 49 * 121 = 85 * 85
388: 25 * 169 + 32 * 162 = 97 * 97
164: 1 * 81 + 32 * 50 = 41 * 41
404: 2 * 200 + 81 * 121 = 101 * 101
68: 2 * 32 + 9 * 25 = 17 * 17
52: 1 * 25 + 8 * 18 = 13 * 13
260: 2 * 128 + 49 * 81 = 65 * 65
212: 8 * 98 + 25 * 81 = 53 * 53
500: 8 * 242 + 81 * 169 = 125 * 125
436: 18 * 200 + 49 * 169 = 109 * 109
20: 1 * 9 + 2 * 8 = 5 * 5
340: 1 * 169 + 72 * 98 = 85 * 85
244: 1 * 121 + 50 * 72 = 61 * 61
148: 2 * 72 + 25 * 49 = 37 * 37
292: 18 * 128 + 25 * 121 = 73 * 73
356: 9 * 169 + 50 * 128 = 89 * 89
452: 1 * 225 + 98 * 128 = 113 * 113
20

いちばん最後に出力されている 20 が答え。20 通りあるってこと。

整数の割り算の結果が小数になることとか、map の結果が map object とかいうものになるとことかでちょってハマった。map object ってなにさ。