mercurialのデフォルトdiffマネージャーが使いづらい時

mercurialでmergeを行いconflictが発生するときがあります (そういうOSの講義の課題もある)

macの場合FileManage.appが起動しますがわりと使いづらいのでその場合の解決方法です

stackoverflow.com

~/hgrcを次のように変更する

[ui]
merge=internal:merge

この後は hg mergehg resolve --mark などを使って解決しましょう この場合gitのデフォルトで出てくる

>>>> hoge
====
<<<< hey

の表示になるのでvimエディタなどで編集すると良いです.

mac osでfreemind1.0.1を使っていて書き込もうとした瞬間固まる状況の対策

主に学内ではMindMap toolとしてFreeMindを使っています. まぁ使う文には良いんですが最近は状況に応じてfreemindの動きが固まるという状況が発生するようです.

原因

FreeMindは内部的に Java Runtime Environment 7を使用しています. これはFreemindの内部に入っているためFreeMindはこれを参照するようです. 何かしらの原因で固まっている場合,このJava7が上手く動いていない/正常に機能していない可能性があります. 実験した所Java9以上では正常にFreeMindが動かない為Java8をローカルにダウンロードし,これをFreeMindが利用するようにすれば解決します.(おそらく)

環境

修正方法

  • まずJava SE8をダウンロードします

  • installしたらターミナルで /usr/libexec/java_home -V を実行します.

Matching Java Virtual Machines (3):
    11.0.1, x86_64: "Java SE 11.0.1"    /Library/Java/JavaVirtualMachines/jdk-11.0.1.jdk/Contents/Home
    10.0.1, x86_64: "Java SE 10.0.1"    /Library/Java/JavaVirtualMachines/jdk-10.0.1.jdk/Contents/Home
    1.8.0_181, x86_64:  "Java SE 8" /Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home

/Library/Java/JavaVirtualMachines/jdk-11.0.1.jdk/Contents/Home

ここでJavaSE 8のinstall pathを確認します,上の例では /Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk です.

  • 次にFreeMindの設定を行うために cd /Applications/FreeMind.app/Contents/ します

  • ここで 簡単の為に cd PlugIns します.lsすると jdk1.7.0_45.jdkが入っている事がわかります.

  • このディレクトリにあるJavaFreemindが利用するのでここにシンボリックリンク/ハードリンクを起きます

ln -s /Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk

  • ls -l し正常に /Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk にjdk1.8.0_181.jdkからリンクが貼られている事を確認します
  • 続いて cd ../ し,一つ前に戻った後 vimemacsなどでInfo.plistを開きます

この中の

 27 <key>JVMRuntime</key>
 28 <string>jdk1.7.0_45.jdk</string>

このjdkの部分を jdk1.8.0_181.jdk (先ほど置いたjdkの名前)に変更すれば大丈夫です.

Roppongi.pm #1 でトークしてきました

こんにちは! id:anatofuz です.今日はid:codehexさんとid:magnoliakさんにお誘いいただいてRoppongi.pm#1に参加してきました.

以前オープンソースカンファレンス沖縄でもトークをした事はあったのですが,あの時は河野先生と共同だったので一人でのトークは初めてでした いつもはLT芸人なので5分以上のトークはいつもの癖で5,6分で終わらせてしまうような気がしており尺が持つか心配でした.

当日のトーク

speakerdeck.com

当日のトークなのですが「あれ...これはYAPC::Tokyoなのでは....!?」と錯覚するような濃いトークで非常にあぁ来てよかったなと感じました. 今回のRoppongi.pmのテーマが「振り返れば、遠くへやってきた」だったので,近藤さんのラクダ本の歴史や制作秘話,DQNEOさんのAmazon::S3::Thinを設計するまでのhistoryPerlコミュニティの関わり,tokuhiromさんの今までのPerlとの関わりなど,明日でPerlが終わると言っても問題ないような(?)歴史散策なトークを聞けました.

そんな中初めての20分トーク+Perlの5に至るまでのversionの話をしたのは緊張と「場にあってるかな…」という不安が直前までありましたが無事トークをする事ができて良かったです.

僕のトークについて

僕のトークですが,個人的にPerlの昔のバージョンを何故か動かしたくなってしまい以前のOkinawa.pmではcharstaiさんのリポジトリを使ってPerl1.0を動かした話をLTしていました.

今回は現在ではメンテされてないPerl2.0~Perl4.0な話を中心に折込,現在のPerl5.28に至るまでの簡単な歴史としてまとめてみました. 技術的な内容や実際の言語実装の話などには今回はあまり踏み込めなかったのでYAPCは何かの.pmで話す際はそのあたりを今度は話そうかと思っております.

調査の方法ですが,トークの序盤でも書いたとおりPerlのVersionリリースの際のtagにつけられたcommitメッセージやmanの記述 後は実際にPerlのCコードのdiffやテストコードを参照してまとめています.

コンパイルの方法自体にはあまりフォーカスしていませんが,これは直前にid:magnoliakさんに,どういう内容をトークしたほうが盛り上がりそうかと相談した際に 「Cコードの変更点はgistに貼るくらいでも良いじゃないか」とアドバイスを頂いたためです.結果的に内容の遍歴を扱う流れができた為良かったと思っています.

このあたりはまたブログなどにまとめたいと思っていますが,それぞれbuildしたPerlがテスト100%通ってないのでそのあたりも調整したいですね.

懇親会では様々な方とお話する事ができましたが,僕がPerlを勉強する時に使ったラクダ本の作者の近藤さんに「良かった」と言っていただけたのが個人的にはすごい嬉しかったです.

またインターネットで良くしていただいている@monamomiさんと初めてお会いすることもできました.

懇親会の後は id:papixさんとid:sironekotoro さんとカレーラーメンを食べるなどしました.

最後に初めてOkinawa.pmではないpmに参加しましたが非常に楽しかったです. 誘っていただいた id:codehex さん id:magnoliakさん ありがとうございました!!

Perl6と多言語の起動時間の比較(Perl5,Ruby,Python,Java,Perl6 on MoarVM,Perl6 on JVM)

追記(2018/07/19)

処理速度ではなくてプログラムの起動時間というご指摘を受けたのでタイトルを修正しました🙏🙏 純粋な処理時間の測定は別途行おうと思います.後半の感想の部分は読み流して頂けると 🙇 🙇

目的

今回は以前のエントリで書いたようなPerl6の正規表現などを使い同じ処理をするプログラムが,各言語でどういったパフォーマンスの差が出るかの検証を行います.

題材

題材としてはmac os X/var/log/system.logのデーモンの回数を数え上げるというプログラムです. 処理の流れとしてはまずコマンドライン引数を確認し,それに応じてファイルを開きます. 開くことが想定されている/var/log/system.logファイルは次のような形式になっています.

Jul 18 01:31:55 anatofuzMBP Dropbox[96084]: [0718/013155:WARNING:dns_config_service_posix.cc(306)] Failed to read DnsCo>
Jul 18 16:57:52 anatofuz-15 idea[66753]: BUG in libdispatch client: kevent[mach_recv] monitored resource vanished befor>

ここから正規表現でデーモンの名前をキャプチャし,一度連想配列を利用してそれぞれのデーモンの出現回数を数え上げます. 最終的に連想配列のkeyをfor文でループさせながら,それぞれの合計を計算するという流れです.

実験

今回はPerl6(MoarVM)とPerl6(JVM)の速度比較を中心に行いました. 解説するとPerl6はベースとなるVMが現在MoarVMかJVMか選択出来るようになっている為,この2つの速度差を図ります. またライバルとなるRuby,Python,Perl5らスクリプト言語や,JVM自体の速度の測定のためにjavaでも実験しました.

  • perl v5.26.2
  • ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-darwin17]
  • Python 3.7.0
  • java 10.0.1 2018-04-17
  • Rakudo version 2018.04.1 built on MoarVM version 2018.04.1 (debugオプション付き)
  • Rakudo Star version 2018.04.1 built on MoarVM version 2018.04.1
  • Rakudo version 2018.06-163-g612d071b8 built on JVM

実験コード

今回使用したコードは次のリポジトリのpushしています.

github.com

Members/anatofuz/Perl6_log_analyze_example: 4f7103163762 /

書き方をある程度統一し,純粋な言語機能の測定を行います.

Perl5

#!/usr/bin/env perl
use strict;
use warnings;

my $file = "/var/log/system.log";

if(@ARGV == 2){
    if ( $ARGV[0] eq "-f"){
        $file = $ARGV[1];
    }
}

my $user_name = qr/anatofuzMBP|anatofuz-15/;
open my $fh, "<",$file;
my $count = {};

while (my $line = <$fh>) {
    if ( $line =~ /\w \d{0,2} (?:\d{2}:?){3} $user_name ([\w.]+)\[\d+\]/){
        $count->{$1}++;
    }
}

my $sum = 0;

for my $key (keys %$count){
    $sum += $count->{$key};
}

print "$sum\n";

素朴にハッシュリファレンスに加算しています

Ruby

#!/usr/bin/env ruby

file = "/var/log/system.log"

user_name = Regexp.new("anatofuzMBP|anatofuz-15")
count = Hash.new(0)

File.open(file,'r') do |f|
    f.each_line do |line|
        if line =~ /\w+ \d{0,2} (?:\d{2}:?){3} #{user_name} ([\w.]+)\[\d+\]/
            count[$1] += 1
        end
    end
end


sum = 0

for key in count.keys
    sum += count[key]
end

p sum

書き方を統一するためにあえて最後はfor文でLoopをさせています. Rubyでforとか数百年ぶりに書いたかも知れない

Python

#!/usr/bin/env python
import re
import sys
from collections import defaultdict

file_path = "/var/log/system.log"
args = sys.argv

if args == 3:
    if args[1] == "-f":
        file_path = args[2]

count = defaultdict(int)

with open(file_path) as f:
    for line in f:
        match = re.search(r'\w+ \d{0,2} (?:\d{2}:?){3} (?:anatofuzMBP|anatofuz-15) ([\w.]+)\[\d+\]',line)
        if match:
            count[match.group(1)]+=1

total = 0

for key in count.keys():
    total +=count[key]

print(total)

Perl6

#!/usr/bin/env perl
use v6;

unit sub MAIN(:f($file) where { .IO.f } = '/var/log/system.log');

my $user_name = /'anatofuzMBP'|'anatofuz-15'/;
my $fh = open $file,:r;
my %count =();

for $fh.lines -> $line {
     if ( $line ~~ /\w+ \s \d**0..3 \s [\d**2\:?]**3 \s $user_name \s (<[\w.]>+)\[\d+\]/) {
         %count{$0}++;
    }
}
$fh.close;
my $sum = 0;

for %count.keys -> $key {
    $sum += %count{$key};
}

$sum.say;

ちなみになんですがPerl6の正規表現リテラル上の空白を無視する為,明示的に空白があると書かないといけません. また範囲演算子**をつけるルールとなっています.

java

package com.google.anatofuz;

import java.io.File;
import java.io.FileReader;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.*;
import java.util.regex.Pattern;
import java.util.regex.Matcher;

public class LogAnalyzer {

    public static void main(String args[]) {

        File file = new File("/var/log/system.log");

        if (args.length != 0) {
            if (args[0].equals("-f")) {
                file = new File(args[1]);
            }
        }

        try {
            FileReader filereader = new FileReader(file);
            BufferedReader bufferedReader = new BufferedReader(filereader);

            String line;
            Map<String,Integer>  map = new HashMap<String,Integer>(0);
            Pattern p = Pattern.compile("\\w+ \\d{0,2} (?:\\d{2}:?){3} (?:anatofuzMBP|anatofuz-15) ([\\w.]+)\\[\\d+\\]");


            while ((line = bufferedReader.readLine()) != null) {
                Matcher matcher = p.matcher(line);
                if (matcher.find()) {
                    map.merge(matcher.group(1),1,Integer::sum);
                }
            }

            int sum = 0;

            for (String key :map.keySet()){
                sum += map.get(key);
            }

            System.out.println(sum);


        } catch (FileNotFoundException ex){
            System.out.println(ex);
        } catch (IOException ex){
            System.out.println(ex);
        }
    }
}

なおjavaはbuildツールのgradleを利用してjarに固めています

計測

素朴にzshのtimeを使って計測しました. 簡単な次のようなスクリプトを作成しています.

#!/bin/zsh
#

echo 'perl5'
time perl log_analyze.pl
echo '====='

echo 'ruby'
time ruby log_analyze.rb
echo '====='

echo 'python'
time python log_analyze.py
echo '====='

echo 'java'
time java -jar java/build/libs/anatofuz-1.0-SNAPSHOT.jar
echo '====='

echo 'perl6'
time perl6 log_analyze.p6
echo '====='

echo 'perl6 (debug)'
time /Users/anatofuz/workspace/cr/Basic/build_perl6/bin/perl6 log_analyze.p6
echo '====='

echo 'perl6(jvm)'
cd  /Users/anatofuz/workspace/cr/Basic/jvm/rakudo/
time /Users/anatofuz/workspace/cr/Basic/jvm/rakudo/perl6 /Users/anatofuz/workspace/cr/Basic/perl6/sandbox/log/log_analyze.p6

実行結果

perl5
524
perl log_analyze.pl  0.04s user 0.03s system 84% cpu 0.090 total
=====
ruby
524
ruby log_analyze.rb  0.12s user 0.05s system 81% cpu 0.220 total
=====
python
524
python log_analyze.py  0.06s user 0.05s system 79% cpu 0.137 total
=====
java
524
java -jar java/build/libs/anatofuz-1.0-SNAPSHOT.jar  0.24s user 0.05s system 140% cpu 0.203 total
=====
perl6
524
perl6 log_analyze.p6  0.37s user 0.03s system 137% cpu 0.294 total
=====
perl6 (debug)
524
/Users/anatofuz/workspace/cr/Basic/build_perl6/bin/perl6 log_analyze.p6  0.78s user 0.07s system 112% cpu 0.752 total
=====
perl6(jvm)
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by org.perl6.nqp.runtime.Ops (file:/Users/anatofuz/workspace/cr/Basic/jvm/nqp/install/share/nqp/runtime/nqp-runtime.jar) to field sun.management.RuntimeImpl.jvm
WARNING: Please consider reporting this to the maintainers of org.perl6.nqp.runtime.Ops
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
524
/Users/anatofuz/workspace/cr/Basic/jvm/rakudo/perl6   21.26s user 0.67s system 439% cpu 4.983 total

トップはPerl5で0.04秒です.かなり早いですね. 続いて処理として早いのはPythonです.正規表現などがモジュール化されていましたが高速ですね. Rubyはeach文を使ってないためか0.12と比較的LLの中では低速です.

JavaはPerl5の6倍,Rubyの2倍ですが,JVMが苦手な正規表現を行っているにもかかわらずそこそこの速度が出ています. またこれでJVM自体が遅いわけではない事が分かります.

さてPerl6ですが,MoarVMの場合0.37とPerl5の10倍遅くなっています. debug optionをつけた場合は速度が0.78sとPerl5の19.5倍の速度となっています.1.0s内に収まっていますがやはりちょっと遅いですね.

一番の問題はJVMに乗ったPerl6で,何かしら厳しいエラーがひとしきり出ている上に21.26s掛かっております. 単純計算でPerl5の531.5倍となっています.Javaと比較しても88倍とJVMが悪いわけではないことが分かります.一体どこが原因なんだろう...

感想

やはりなんというかPerl6全体的に遅く,このPerl6を高速化するというのは非常にロマンがある世界かと思われます. 時間はかかりますが,使えないことはないので皆さん試してみたらどうでしょうか.

Perl6のif文は空白が重要

Perl6でこういったコードを書くと

#!/usr/bin/env perl6
use v6;

if ( 1 ){
    say "goe";
}
perl6 if.p6
===SORRY!=== Error while compiling /Users/anatofuz/workspace/cr/Basic/perl6/sandbox/log/if.p6
Missing block (whitespace needed before curlies taken as a hash subscript?)
at /Users/anatofuz/workspace/cr/Basic/perl6/sandbox/log/if.p6:8
------> <BOL>⏏<EOL>
    expecting any of:
        block or pointy block

とエラーが発生する. これは ifの後の (){ の間に空白がない為であり

#!/usr/bin/env perl6
use v6;

if ( 1 ) {
    say "goe";
}

としてあげると

perl6 if.p6
goe

と表示される

公式ドキュメントを見るとif文には ()をつけないで書いている為言語デザイナー的には

ifと評価する真偽値の間には区切りの空白があるのは当然だけれども,()はあくまで人間が見やすくしているだけなので空白入れてくれ!!という世界観だと思った.

Perl6の正規表現の世界 ~ キャプチャマーカー編 ~

こんにちは.最近Perl6に思いを馳せつつRubyソースコードを読んだりしているid:anatofuzです. ところで9月はOkinawa.pmとRoppongi.pmが開催される予定なので皆さんよろしくお願いします.

題材

さて今回ですが個人的にPerl6のスピードを他言語と比較測定しようとしています. 題材として青空文庫から正規表現で漢字とふりがなを取り出すというスクリプトを作成しています.

どういうことかというと青空文庫テキスト版は蜜蜂《みつばち》の用に漢字+<<>>の順でるびが表記されています. これを正規表現でキャプチャするには例えばPerl5の場合

#!/usr/bin/env perl
use strict;
use warnings;
use utf8;
use feature 'say';
use Encode;

my $filename = "./dogura_magura.txt";
open my $fh,'<:encoding(utf-8)',$filename or die qw/can't open/;

my @kana;

while (my $line = <$fh>) {
    chomp $line;
    while( $line =~ m![、。]?(\p{Han}+)(\p{Hiragana}+)!g){
        push @kana,[$1,$2];
    }
}

print scalar @kana;

この場合 m![、。]?(\p{Han}+)《(\p{Hiragana}+)》!unicodeプロパティを使ってキャプチャしています. ちなみにRubyで書くとこんな感じです

#!/usr/bin/env ruby

File.open("./dogura_magura.txt",'r') do |f|
    hoge = f.read.scan(/[、。]?(\p{Han}+)(\p{Hiragana}+)/)
    p hoge.count
end

Perl6で書く

ではこれをPerl6で書いてみましょう

#!/usr/bin/env perl6
use v6;

my $file = "./dogura_magura.txt";
my $fh = open $file, :r;
my $hoge;

for $fh.lines -> $line {
    if ($line ~~ m:g/<[、。]>?(<:Han>+)""(<:Hiragana>+)""/ ) {
        say $/[0];
        $hoge += $/.conj;
    }
}

say $hoge;

$fh.close;

Perl6の場合正規表現がPerl5と大分異なっており,まず文字クラスは[]ではなく<[]>と表記します. Unicodeプロパティは<:プロパティ名>と表記し,文字列はダブルクォーテーションでくくる必要があります.

実際にこれでコードを実行すると

# say $0;
「蜜蜂《みつばち》」
 0 => 「蜜蜂」
 1 => 「みつばち」

こういった具合に $0に配列としてキャプチャ結果が代入されます. なぜ配列で$0から入るかはこちらの資料を御覧ください.

qiita.com

キャプチャマーカー

さて本題です.

Perl6の正規表現にはキャプチャマーカー(Capture markers)と呼ばれる機能があります. 構文的には <()>と書くとキャプチャマーカーです.

公式ドキュメントによれば以下のように書かれています.

A <( token indicates the start of the match's overall capture, while the corresponding )> token indicates its endpoint. The <( is similar to other languages \K to discard any matches found before the \K.

 say 'abc' ~~ / a <( b )> c/;            # OUTPUT: «「b」␤» 
 say 'abc' ~~ / <(a <( b )> c)>/;        # OUTPUT: «「bc」␤» 

As the example above, you can see <( sets the start point and )> sets the endpoint; since they are actually independent each other, the inner-most start point wins (the one attache to b) and the outer-most end wins (the one attached to c).

CaptureMarkers%3E)

つまりこれはどういうことかというと 「正規表現の開始位置と終了位置を書き換えることが可能」という訳です.

二番目の例を見てみましょう

 say 'abc' ~~ / <(a <( b )> c)>/;        # OUTPUT: «「bc」␤» 

こちらはまず内部の <(b)>のキャプチャマーカーが処理され,abcという文字列の中のbがキャプチャされます. キャプチャマーカーではこの時点でキャプチャが走り,キャプチャマーカーはエンドポイントであるbcという文字列を返します. 次のキャプチャではこの末尾のcがキャプチャされるので全体的なアウトプットは bcとなります.

青空文庫の例

ではこれを応用(?)してみましょう.

先程の青空文庫正規表現で後ろのかなの部分にキャプチャマーカーを当てます

 m:g/<[、。]>?(<:Han>+)"《"<(<:Hiragana>+)>"》"/

こうするとどうなるでしょうか. 答えはこのようになります.

「みつばち」
 0 => 「蜜蜂」

挙動を確認するとまずキャプチャマーカーでかなの部分が読み込まれます. 読み込まれた場所はPerl6は利用しないで捨てられます.

続いてキャプチャする箇所が前にあるのでPerl6はキャプチャを後ろに戻し漢字の箇所をキャプチャし返却します.

なかなかの挙動でしたね.正直使いこなせるのか怪しいところがあります.

ちなみにこれは吉祥寺.pmのid:magnoliakさんと探っていました. 常日頃からコラボしている吉祥寺.pmとOkinawa.pmのコラボpm Roppongi.pmは9月開催予定なのでよろしくお願いします

Hackers-Champloo 2018 で(スタッフ|LT)してきました

こんにちは id:anatofuz です.久しくイベント参加ブログを書いていない(最悪)なのですが忘れないうちに書きます.

ハカチャンでの役割

今回のハカチャンではSNS運用おじさん+Okinawa.pmの人という感じで関わらせていただきました. SNS運用おじさんはYAPC::Okinawaでも行っていたので前回の知見を使いながら行っていました.

個人的に一番貢献できたかなというのはOkinawa.pmとしてPerl界隈の人をゲストとして打診するというフェーズで 前々から思っていた「個人的にid:motemenさん呼びたい」という案を実行委員帳の西島さんからOKをもらい,実行したところです.

motemenさんを呼びたかったのは個人的にはてなインターンでの思いがあるということと,単純に僕がお会いしたかったからという所です. 打診した所OKを頂き,無事Okinawa.pmの人として役目を果たせたと思っています.

トーク

トークハッカーズチャンプルーらしく様々な方面のトークが聞け,非常に良かったです. 今回はゲーム方面としてUnityの方もお呼びしていましたが,学生にとっては身近な話題だったので参加者層とマッチしており,運営が功を奏したと思っています.

参加者の中に僕の学科*1の1年次が多く,この時期からカンファレンスに参加できるのは良いなと感じました. そういえば僕が最初に参加したカンファレンスもハカチャンだったことを思い出し,懐かしい思いになりました.

どのトークも非常に良かったのですが,個人的な話をするとやはりお呼びしたmotemenさんのトークが聞けて良かったと思っています. 去年のインターンの後様々な思いがあり,色々と辛かったことも多かったのですが,トークを聞いてなんというか救われた感じがしました. motemenさんとは懇親会でも色々とお話する事ができて,自分としてはこの上ないほど良い体験をさせていただきました. id:motemenさんご登壇していただいてありがとうございました!

(これは余談ですがハカチャンに来ていた大学の先生が去年のインターンのブログエントリを見ることを1年時に進めていたらしい)

LT

LT芸人のようなところがあるので今回もLTしました.

ちなみにスライドのこの部分ですが

休憩時間にメルカリからきていたid:codehexさんから「遠慮せずにOkinawa.pm開催したほうが良い」と言われその場の勢いで決定したものです.

言ったからにはやろうと思っていて,確実に9月には開催する予定です.それまでの7,8月なのは短めにやると思います.

来年へ

ハッカーズチャンプルー毎年非常に良いイベントになっていて,今年は運営としてちょっとお手伝いさせていただいたので個人的には今までで一番良かったかなと思っています.来年も運営としてお手伝いさせていただこうと思っていますので皆さんよろしくお願いします.

*1:琉大情報工学