24時間制、0~23時のHH:mm:ss の正規表現
^(0[0-9]|1[0-9]|2[0-3]):(0[0-9]|[0-5][0-9]):(0[0-9]|[0-5][0-9])$
Wicket で、IModel インスタンスを書く時 、コーディングの癖で、 new 演算子による
new Model<>() を書くことが多い。
Model.of があるのは知ってはいたけど、なぜかあまり書かなかった。
https://issues.apache.org/jira/browse/WICKET-6412
Model.orElse を書いてフォームの submit でも、結局は問題は起きるようで、
String の TextField を使うときに、使うのが良いかも。
それよりも、Java8 ラムダになって、Model クラスでも、
IModel<T> orElseGet(SerializableSupplier<? extends T> other)
を書けることの方が魅力的です。
他人が構築したDBを引き継ぐのは、嫌なもので状況を把握しないまま、
MySQL ストアドファンクションを追加したら、
Error Code: 1419. You do not have the SUPER privilege and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)
マニュアルには、こう書いてある。
「バイナリロギングを有効にしているサーバーに対するこの危険から保護するために、
ストアドファンクションの作成者は、必要な通常の CREATE ROUTINE 権限に加え、SUPER 権限も持つ必要があります。
同様に、ALTER FUNCTION を使用するには、ユーザーは ALTER ROUTINE 権限に加え、SUPER 権限を持つ必要があります。
SUPER 権限がないと、エラーが発生します。」
しかたないので、権限のある root で入り、log_bin_trust_function_creators を調べる。
mysql> SHOW VARIABLES LIKE 'log_bin_trust_function_creators'; +---------------------------------+-------+ | Variable_name | Value | +---------------------------------+-------+ | log_bin_trust_function_creators | OFF | +---------------------------------+-------+
なので、ONにするために、
mysql> set global log_bin_trust_function_creators=1; Query OK, 0 rows affected (0.00 sec)
確認、
mysql> SHOW VARIABLES LIKE 'log_bin_trust_function_creators'; +---------------------------------+-------+ | Variable_name | Value | +---------------------------------+-------+ | log_bin_trust_function_creators | ON | +---------------------------------+-------+ 1 row in set (0.00 sec)
これで、無事、ストアドファンクション生成できるようになる。
先日のグルーピング&ソートに続いて、、、
グルーピングした時にソートもする。 - Oboe吹きプログラマの黙示録
同じく Foo なるクラスオブジェクトのリストで、グルーピングして並べた時に、先頭だけキーをそのままで
他をキーが表示されないように置き換えなどの細工をする。
key : value ------------- A : 1 : 2 : 3 B : 11 : 12 C : 31
のように表示できるようにリストを変更したいする。すぐに思いつくのが、groupingBy して作った Map の
entrySet() ストリームを流して、flatMap で、変更する方法、、
List<Foo> results = list.stream().collect(Collectors.groupingBy(t->t.key, Collectors.mapping(u->u, Collectors.toList()))) .entrySet().stream().flatMap(e->{ AtomicInteger i = new AtomicInteger(0); return e.getValue().stream().sorted((o1, o2)->new Integer(o1.value).compareTo(new Integer(o2.value))).map(t->{ if (i.getAndIncrement() > 0) t.key = " "; return t; }); } ).collect(Collectors.toList());
でも、AtomicInteger生成文が入って気持ち悪い。
遅くて効率が悪いかもしれなけど、Stream.concat を使ってみる。
List<Foo> results = list.stream().collect(Collectors.groupingBy(t->t.key, Collectors.mapping(u->u, Collectors.toList()))) .entrySet().stream().flatMap(e->{ List<Foo> _list = e.getValue().stream() .sorted((o1, o2)->new Integer(o1.value).compareTo(new Integer(o2.value))).collect(Collectors.toList()); return Stream.concat(_list.stream().limit(1) , _list.stream().skip(1).map(t->{ t.key = " "; return t; })); }).collect(Collectors.toList());
キーそのものもソートまで実施するなら、こんなんじゃダメなので、
Map<String, List<Foo>> map = list.stream().collect(Collectors.groupingBy(e->e.key, Collectors.mapping(t->t, Collectors.collectingAndThen(Collectors.toCollection(ArrayList::new) , t->{ List<Foo> _list = t.stream().sorted((o1, o2)->new Integer(o1.value) .compareTo(new Integer(o2.value))).collect(Collectors.toList()); return Stream.concat(_list.stream().limit(1), _list.stream().skip(1).map(u->{ u.key = " "; return u; })).collect(Collectors.toList()); }) )));
ソートもされるけど、何だか遅そう。。
グルーピングしながら、ソートした結果リストを求めることを
いざコーディングしようとすると、即時、思いつかないのが残念でメモ。
Collectors.collectingAndThen を使うのが重要
サンプル、以下、文字列の key と value があるクラスオブジェクト
public class Foo{ public String key; public String value; public Foo(String key, String value){ this.key = key; this.value = value; } }
あえて、value には、数値の文字列が入る約束として、この value で、グルーピング結果のコレクションがソート
されるようにする。
List の Map を生成
Map<String, List<Foo>> map = list.stream().collect(Collectors.groupingBy(e->e.key, Collectors.mapping(t->t, Collectors.collectingAndThen(Collectors.toCollection(ArrayList::new) , t->t.stream().sorted((o1, o2)->new Integer(o1.value).compareTo(new Integer(o2.value))) .collect(Collectors.toList()) ) )));
Set の Map を生成、 toList() を toSet() に返るだけですが。
Map<String, Set<Foo>> map = list.stream().collect(Collectors.groupingBy(e->e.key, Collectors.mapping(t->t, Collectors.collectingAndThen(Collectors.toCollection(ArrayList::new) , t->t.stream().sorted((o1, o2)->new Integer(o1.value).compareTo(new Integer(o2.value))) .collect(Collectors.toSet()) ) )));
方法があった。
stackoverflow で見つけました。
$(function(){ $("body").on('mouseover', 'a', function(e){ var $link = $(this), href = $link.attr('href') || $link.data("href"); $link.off('click.chrome'); $link.on('click.chrome', function(){ /* window.location.href = href; */ this.location.href = href; }) .attr('data-href', href) .css({ cursor: 'pointer' }) .removeAttr('href'); }); });
注意しなければならないのは、必ず、<a> タグの href属性を書いておくこと。
mouseover のイベントで、href 属性を data属性である data-href に置き換えて書込み
ブラウザ左下に URLが出るのを抑止、
再びマウスが上にきてクリックされても、data-hrefの残されてた URLを
location.href へのセットでページ遷移させる方法だ。
2年近く前、Wicket6 → 7 になった時、DropDownChoice の為の IChoiceRenderer が、
public T getObject(String id, IModel> choices)
が増えて、choices のgetModelObject() で取ってくるものをこのメソッドで返さなくてはならなくなり、
当時、以下のように、optionタグの value属性値を返せるようにするインターフェースを用意して
更に、IChoiceRenderer継承と、DropDownChoice がそれを使うように継承したものを作った。。
IChoiceRenderer ラムダ化 - Oboe吹きプログラマの黙示録
でも、やはりDropDownChoice の継承と、選択要素にoptionタグの value属性値を返せるようにするインターフェース
を付けるなんて方法は、選択要素の構造に手を加えるので良くない。
かと言って、IChoiceRenderer の無名インナークラスのコーディングは、長くなって嫌だ。
option タグの value を返すもの。bodyを返すもの。選択されたものを判断して返すもの。
これらの処理関数を埋め込めるラムダ式になっていれば良い。
import java.util.List; import org.apache.wicket.markup.html.form.IChoiceRenderer; import org.apache.wicket.model.IModel; import org.danekja.java.util.function.serializable.SerializableBiPredicate; import org.danekja.java.util.function.serializable.SerializableFunction; /** * IChoiceRenderer を提供 */ public class ChoiceRender{ private ChoiceRender(){} public static <T> IChoiceRenderer<T> of(SerializableFunction<T, String> idfunction , SerializableFunction<T, String> displayfunction , SerializableBiPredicate<T, String> bipredicate ){ return new IChoiceRenderer<T>(){ @Override public Object getDisplayValue(T t){ return displayfunction.apply(t); } @Override public String getIdValue(T t, int index){ return idfunction.apply(t); } @Override public T getObject(String id, IModel<? extends List<? extends T>> choices){ return choices.getObject().stream().filter(e->bipredicate.test(e, id)).findFirst().orElse(null); } }; } }
例)
以下のような対象クラスがあったとする。
public class Foo implements Serializable{ public int val; public String name; public Foo(int val, String name){ this.val = val; this.name = name; } }
final DropDownChoice<Foo> selectFoo = new DropDownChoice<Foo>("select1", new Model<>(), Arrays.asList(new Foo(1,"A"), new Foo(2,"B"), new Foo(3,"C") ) , ChoiceRender.of(t->Integer.toString(t.val), t->t.name, (t,u)->Integer.toString(t.val).equals(u)) ) ; queue(selectFoo);
そして、optionタグの value も body も同じものとして生成することも簡単に書ける。
例えば、"a","b","c"
final DropDownChoice<String> selectChar = new DropDownChoice<String>("select2", new Model<>(), Arrays.asList("a","b","c") , ChoiceRender.of(t->t, t->t, (t,u)->t.equals(u)) ) ; queue(selectChar);
フォーム送信されて受け取るところ。。
Optional.ofNullable(selectChar.getModelObject()).ifPresent(s->{ // });