From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Original-To: caml-list@sympa.inria.fr Delivered-To: caml-list@sympa.inria.fr Received: from mail2-relais-roc.national.inria.fr (mail2-relais-roc.national.inria.fr [192.134.164.83]) by sympa.inria.fr (Postfix) with ESMTPS id 09D777FE44 for ; Wed, 6 Jul 2016 14:59:37 +0200 (CEST) IronPort-PHdr: 9a23:bry9XxQKJB7IFyG1zsMX3xwuBNpsv+yvbD5Q0YIujvd0So/mwa64bRyN2/xhgRfzUJnB7Loc0qyN4vimAzJLvM7JmUtBWaQEbwUCh8QSkl5oK+++Imq/EsTXaTcnFt9JTl5v8iLzG0FUHMHjew+a+SXqvnYsExnyfTB4Ov7yUtaLyZ/mj6bopdaOO01hv3mUWftKNhK4rAHc5IE9oLBJDeIP8CbPuWZCYO9MxGlldhq5lhf44dqsrtY4q3wD89pozcNLUL37cqIkVvQYSW1+ayFmrPHs4BLKSA/K4noHTk0XlABJCk7L9lWycZrrvmPBqu15wCyTO8u+GbEyVzOK4KpxRFrzlCADLzsw9meRhsEm34xBpxf0gh18w4fVZMmwPfxyZLLefNVSEW9IWMpLRi9ABKu9dJMVBvFHJ/sO/Nq1nEcHsRbrXVrkP+jo0DIdwyauhaA= Authentication-Results: mail2-smtp-roc.national.inria.fr; spf=None smtp.pra=mandrykin@ispras.ru; spf=None smtp.mailfrom=mandrykin@ispras.ru; spf=None smtp.helo=postmaster@smtp.ispras.ru Received-SPF: None (mail2-smtp-roc.national.inria.fr: no sender authenticity information available from domain of mandrykin@ispras.ru) identity=pra; client-ip=83.149.199.79; receiver=mail2-smtp-roc.national.inria.fr; envelope-from="mandrykin@ispras.ru"; x-sender="mandrykin@ispras.ru"; x-conformance=sidf_compatible Received-SPF: None (mail2-smtp-roc.national.inria.fr: no sender authenticity information available from domain of mandrykin@ispras.ru) identity=mailfrom; client-ip=83.149.199.79; receiver=mail2-smtp-roc.national.inria.fr; envelope-from="mandrykin@ispras.ru"; x-sender="mandrykin@ispras.ru"; x-conformance=sidf_compatible Received-SPF: None (mail2-smtp-roc.national.inria.fr: no sender authenticity information available from domain of postmaster@smtp.ispras.ru) identity=helo; client-ip=83.149.199.79; receiver=mail2-smtp-roc.national.inria.fr; envelope-from="mandrykin@ispras.ru"; x-sender="postmaster@smtp.ispras.ru"; x-conformance=sidf_compatible X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: A0BRBQAFAH1X/0/HlVNdgz5WfLEcgw+GfSKFdgKBKTwQAQEBAQEBAQFkJ4IyghoBAQQBIwRSBQsJAhgCAgUhAgIPAUcGARKIKAwKjn+dHY93AQEBAQYBAQEBAQEhgQGJc4RAgwGCWgWOBHCKH4YJgTGJRYcFhW2IGYdxNR+CCByBT2sBiHEBAQE X-IPAS-Result: A0BRBQAFAH1X/0/HlVNdgz5WfLEcgw+GfSKFdgKBKTwQAQEBAQEBAQFkJ4IyghoBAQQBIwRSBQsJAhgCAgUhAgIPAUcGARKIKAwKjn+dHY93AQEBAQYBAQEBAQEhgQGJc4RAgwGCWgWOBHCKH4YJgTGJRYcFhW2IGYdxNR+CCByBT2sBiHEBAQE X-IronPort-AV: E=Sophos;i="5.28,318,1464645600"; d="scan'208";a="225800336" Received: from smtp.ispras.ru ([83.149.199.79]) by mail2-smtp-roc.national.inria.fr with ESMTP; 06 Jul 2016 14:59:35 +0200 Received: from molnar.localnet (unknown [83.149.199.91]) by smtp.ispras.ru (Postfix) with ESMTP id 2AA51203D1; Wed, 6 Jul 2016 15:59:34 +0300 (MSK) From: Mikhail Mandrykin To: caml-list@inria.fr, Gerd Stolpmann Cc: Jocelyn =?ISO-8859-1?Q?S=E9rot?= Date: Wed, 06 Jul 2016 15:59:34 +0300 Message-ID: <44481375.r3GYhIioXc@molnar> User-Agent: KMail/5.1.3 (Linux/4.4.0-24-generic; KDE/5.18.0; x86_64; ; ) In-Reply-To: <1467798868.25014.8.camel@e130.lan.sumadev.de> References: <64440D5D-1FC8-4C53-9520-D9D3D21F8FE5@univ-bpclermont.fr> <44623127-96C5-43FB-828D-0F42DCCBA36B@univ-bpclermont.fr> <1467798868.25014.8.camel@e130.lan.sumadev.de> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="UTF-8" Subject: Re: [Caml-list] Q: functors and "has a" inheritance Hello, On =D1=81=D1=80=D0=B5=D0=B4=D0=B0, 6 =D0=B8=D1=8E=D0=BB=D1=8F 2016 =D0=B3. = 11:54:28 MSK Gerd Stolpmann wrote: > Am Mittwoch, den 06.07.2016, 10:44 +0200 schrieb Jocelyn S=C3=A9rot: > > Hi Nicolas, > Your design might work when you change Product: >=20 > module Product (S1: T) (S2: T) > (P : T with type elt =3D S1.elt * S2.elt > and type attr =3D S1.attr * S2.attr) > sig > val product: S1.t -> S2.t -> P.t > end >=20 > i.e. the "real" product module is the argument P, and this functor only > defines the product function. This way you can instantiate it for any P. It's also possible to explicitly name the anonymous module "struct type t = =3D=20 S1.elt * S2.elt let compare =3D compare end" e.g. by exposing it in the out= put=20 signature of Product: module E : Set.OrderedType with type t =3D S1.elt * S2.elt include T with type elt =3D E.t and type t =3D Make(E).t instead of=20 include T with type elt =3D S1.elt * S2.elt in myset.mli (module Product) Then if Product implementation is changed appropriately i.e. module E =3D (struct type t =3D S1.elt * S2.elt let compare =3D compare end) module R =3D Make (E) instead of module R =3D Make (struct type t =3D S1.elt * S2.elt let compare =3D compare end) include R in myset.ml (module Product), the anonymous module can be named and shared explicitly: module P =3D Myset.Product(S1.S)(S2.S) module R =3D Make (P.E) (struct type t =3D S1.attr * S2.attr let compare =3D compare end) include R instead of module R =3D Make (struct type t =3D S1.elt * S2.elt let compare =3D compare end) (struct type t =3D S1.attr * S2.attr let compare =3D compare end) include R module P =3D Myset.Product(S1.S)(S2.S) in myset.ml (module Product) The only remaining problem then is missing equality between elt and S.elt i= n=20 the signature Myseta.T: module S: Myset.T --> module S: Myset.T with type elt =3D elt This makes it work with elems =3D P.product ... Then the additional constraint ... and type S.t =3D Myset.Product(S1.S)(S2.S).t in myset.mli can be turned into module P : sig module E : Set.OrderedType end ... and type S.t =3D Myset.Make(P.E).t Regards, Mikhail >=20 > Gerd >=20 > > I guess it is because re-use the [Myseta.Product] functor only views > > the abstract types exposed by the [Myset.Make] and [Myset.Product] > > output signatures. > >=20 > >=20 > > Seems therefore i am really stuck :( > >=20 > >=20 > > Jocelyn > >=20 > >=20 > > Le 6 juil. 2016 =C3=A0 09:49, Nicolas Ojeda Bar > >=20 > > a =C3=A9crit : > > > Hi Jocelyn > > >=20 > > >=20 > > > One issue is that you have two modules, P and R.S, of the form > > > Set.Make(X), Set.Make (X') for modules X and X' which are > > > structurally equal. Unfortunately this is not enough for the OCaml > > > module system to deduce that P.t and R.S.t are compatible. In > > > general if F is a functor with output signature S and t is abstract > > > type in S, then F(X).t and F(X').t will be compatible exactly when X > > > and X' are literally the same module. I don't think you will be > > > able to fix this by adding type sharing constrains. > > >=20 > > >=20 > > > Cheers > > > Nicolas > > >=20 > > >=20 > > >=20 > > > On Tue, Jul 5, 2016 at 5:25 PM, Jocelyn S=C3=A9rot > > >=20 > > > wrote: > > > Dear all, > > >=20=20=20=20=20=20=20=20=20 > > >=20=20=20=20=20=20=20=20=20 > > > I=E2=80=99m stuck with a problem related with the use of func= tors > > > for implementing a library. > > > The library concerns Labeled Transition Systems but i=E2=80= =99ll > > > present it in a simplified version using sets. > > >=20=20=20=20=20=20=20=20=20 > > >=20=20=20=20=20=20=20=20=20 > > > Suppose i have a (very simplified !) Set module, which i > > > will call Myset to distinguish from that of the standard > > > library : > > >=20=20=20=20=20=20=20=20=20 > > >=20=20=20=20=20=20=20=20=20 > > > =E2=80=94=E2=80=94=E2=80=94=E2=80=94 myset.mli > > > module type T =3D sig > > >=20=20=20=20=20=20=20=20=20 > > > type elt > > > type t > > > val empty: t > > > val add: elt -> t -> t > > > val elems: t -> elt list > > > val fold: (elt -> 'a -> 'a) -> t -> 'a -> 'a > > >=20=20=20=20=20=20=20=20=20 > > > end > > >=20=20=20=20=20=20=20=20=20 > > >=20=20=20=20=20=20=20=20=20 > > > module Make (E : Set.OrderedType) : T with type elt =3D E.t > > > =E2=80=94=E2=80=94=E2=80=94 > > >=20=20=20=20=20=20=20=20=20 > > >=20=20=20=20=20=20=20=20=20 > > > =E2=80=94=E2=80=94=E2=80=94=E2=80=94 myset.ml > > > module type T =3D sig =E2=80=A6 (* idem myset.mli *) end > > >=20=20=20=20=20=20=20=20=20 > > >=20=20=20=20=20=20=20=20=20 > > > module Make (E : Set.OrderedType) =3D struct > > >=20=20=20=20=20=20=20=20=20 > > > module Elt =3D E > > > type elt =3D E.t > > > type t =3D { elems: elt list; } > > > let empty =3D { elems =3D [] } > > > let add q s =3D { elems =3D q :: s.elems } (* obviously > > >=20=20=20=20=20=20=20=20=20 > > > wrong, but does not matter here ! *) > > >=20=20=20=20=20=20=20=20=20 > > > let elems s =3D s.elems > > > let fold f s z =3D List.fold_left (fun z e -> f e z) z > > >=20=20=20=20=20=20=20=20=20 > > > s.elems > > > end > > > =E2=80=94=E2=80=94=E2=80=94 > > >=20=20=20=20=20=20=20=20=20 > > >=20=20=20=20=20=20=20=20=20 > > > First, i add a functor for computing the product of two > > > sets : > > >=20=20=20=20=20=20=20=20=20 > > >=20=20=20=20=20=20=20=20=20 > > > =E2=80=94=E2=80=94=E2=80=94=E2=80=94 myset.mli (cont=E2=80=99= d) > > > module Product (S1: T) (S2: T) : > > > sig > > >=20=20=20=20=20=20=20=20=20 > > > include T with type elt =3D S1.elt * S2.elt > > > val product: S1.t -> S2.t -> t > > >=20=20=20=20=20=20=20=20=20 > > > end > > > =E2=80=94=E2=80=94=E2=80=94 > > >=20=20=20=20=20=20=20=20=20 > > >=20=20=20=20=20=20=20=20=20 > > > =E2=80=94=E2=80=94=E2=80=94=E2=80=94 myset.ml (cont=E2=80=99d) > > > module Product > > >=20=20=20=20=20=20=20=20=20 > > > (S1: T) > > > (S2: T) =3D > > >=20=20=20=20=20=20=20=20=20 > > > struct > > >=20=20=20=20=20=20=20=20=20 > > > module R =3D > > >=20=20=20=20=20=20=20=20=20=20=20 > > > Make (struct type t =3D S1.elt * S2.elt let compare =3D > > >=20=20=20=20=20=20=20=20=20 > > > compare end) > > >=20=20=20=20=20=20=20=20=20 > > > include R > > > let product s1 s2 =3D > > >=20=20=20=20=20=20=20=20=20=20=20=20=20 > > > S1.fold > > >=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20 > > > (fun q1 z -> > > >=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20 > > > S2.fold > > >=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20 > > > (fun q2 z -> R.add (q1,q2) z) > > > s2 > > > z) > > >=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20 > > > s1 > > > R.empty > > >=20=20=20=20=20=20=20=20=20 > > > end > > > =E2=80=94=E2=80=94=E2=80=94 > > >=20=20=20=20=20=20=20=20=20 > > >=20=20=20=20=20=20=20=20=20 > > > Here=E2=80=99s a typical usage of the Myset module : > > >=20=20=20=20=20=20=20=20=20 > > >=20=20=20=20=20=20=20=20=20 > > > =E2=80=94=E2=80=94 ex1.ml > > > module IntSet =3D Myset.Make (struct type t =3D int let compa= re > > > =3D compare end) > > > module StringSet =3D Myset.Make (struct type t =3D string let > > > compare =3D compare end) > > >=20=20=20=20=20=20=20=20=20 > > >=20=20=20=20=20=20=20=20=20 > > > let s1 =3D IntSet.add 1 (IntSet.add 2 IntSet.empty) > > > let s2 =3D StringSet.add "a" (StringSet.add "b" > > > StringSet.empty) > > >=20=20=20=20=20=20=20=20=20 > > >=20=20=20=20=20=20=20=20=20 > > > module IntStringSet =3D Myset.Product (IntSet) (StringSet) > > >=20=20=20=20=20=20=20=20=20 > > >=20=20=20=20=20=20=20=20=20 > > > let s3 =3D IntStringSet.product s1 s2 > > > =E2=80=94=E2=80=94 > > >=20=20=20=20=20=20=20=20=20 > > >=20=20=20=20=20=20=20=20=20 > > > So far, so good. > > >=20=20=20=20=20=20=20=20=20 > > >=20=20=20=20=20=20=20=20=20 > > > Now suppose i want to =C2=AB augment =C2=BB the Myset module = so that > > > some kind of attribute is attached to each set element. I > > > could of course just modify the definition of type [t] and > > > the related functions in the files [myset.ml] and > > > [myset.mli]. But suppose i want to reuse as much as possible > > > the code already written. My idea is define a new module - > > > let=E2=80=99s call it [myseta] (=C2=AB a =C2=BB for attribute= s) - in which the > > > type [t] will include a type [Myset.t] and the definitions > > > of this module will make use, as much as possible, of those > > > defined in [Myset]. > > >=20=20=20=20=20=20=20=20=20 > > >=20=20=20=20=20=20=20=20=20 > > > Here=E2=80=99s a first proposal (excluding the Product functo= r for > > > the moment) : > > >=20=20=20=20=20=20=20=20=20 > > >=20=20=20=20=20=20=20=20=20 > > > =E2=80=94=E2=80=94=E2=80=94=E2=80=94 myseta.mli > > > module type Attr =3D sig type t end > > >=20=20=20=20=20=20=20=20=20 > > >=20=20=20=20=20=20=20=20=20 > > > module type T =3D sig > > >=20=20=20=20=20=20=20=20=20 > > > type elt > > > type attr > > > type t > > > module S: Myset.T > > > val empty: t > > > val add: elt * attr -> t -> t > > > val elems: t -> elt list > > > val attrs: t -> (elt * attr) list > > > val set_of: t -> S.t > > > val fold: (elt * attr -> 'a -> 'a) -> t -> 'a -> 'a > > >=20=20=20=20=20=20=20=20=20 > > > end > > >=20=20=20=20=20=20=20=20=20 > > >=20=20=20=20=20=20=20=20=20 > > > module Make (E : Set.OrderedType) (A: Attr) : T with type > > > elt =3D E.t and type attr =3D A.t > > > =E2=80=94=E2=80=94=E2=80=94 > > >=20=20=20=20=20=20=20=20=20 > > >=20=20=20=20=20=20=20=20=20 > > > =E2=80=94=E2=80=94=E2=80=94=E2=80=94 myseta.ml > > > module type Attr =3D sig type t end > > >=20=20=20=20=20=20=20=20=20 > > >=20=20=20=20=20=20=20=20=20 > > > module type T =3D sig (* idem myseta.mli *) end > > >=20=20=20=20=20=20=20=20=20 > > >=20=20=20=20=20=20=20=20=20 > > > module Make (E : Set.OrderedType) (A : Attr) =3D struct > > >=20=20=20=20=20=20=20=20=20 > > > module Elt =3D E > > > type elt =3D E.t > > > type attr =3D A.t > > > module S =3D Myset.Make(E) > > > type t =3D { elems: S.t; attrs: (elt * attr) list } > > > let empty =3D { elems =3D S.empty; attrs =3D [] } > > > let add (e,a) s =3D { elems =3D S.add e s.elems; attrs =3D > > >=20=20=20=20=20=20=20=20=20 > > > (e,a) :: s.attrs } > > >=20=20=20=20=20=20=20=20=20 > > > let elems s =3D S.elems s.elems > > > let attrs s =3D s.attrs > > > let set_of s =3D s.elems > > > let fold f s z =3D List.fold_left (fun z e -> f e z) z > > >=20=20=20=20=20=20=20=20=20 > > > s.attrs > > > end > > > =E2=80=94=E2=80=94=E2=80=94 > > >=20=20=20=20=20=20=20=20=20 > > >=20=20=20=20=20=20=20=20=20 > > > In practice, of course the [Attr] signature will include > > > other specifications. > > > In a sense, this is a =C2=AB has a =C2=BB inheritance : whene= ver i > > > build a [Myseta] module, i actually build a [Myset] > > > sub-module and this module is used to implement all the > > > set-related operations. > > > Again, so far, so good. > > > The problem shows when i try to define the [Product] functor > > > for the [Myseta] module : > > > It=E2=80=99s signature is similar to that of the [Myset.Produ= ct] > > > functor, with an added sharing constraint for attributes (in > > > fact, we could imagine a more sophisticated scheme for > > > merging attributes but cartesian product is here) : > > >=20=20=20=20=20=20=20=20=20 > > >=20=20=20=20=20=20=20=20=20 > > > =E2=80=94=E2=80=94=E2=80=94=E2=80=94 myset.mli (cont=E2=80=99= d) > > > module Product (S1: T) (S2: T) : > > > sig > > >=20=20=20=20=20=20=20=20=20 > > > include T with type elt =3D S1.elt * S2.elt > > >=20=20=20=20=20=20=20=20=20=20=20 > > > and type attr =3D S1.attr * S2.attr > > >=20=20=20=20=20=20=20=20=20=20=20 > > > val product: S1.t -> S2.t -> t > > >=20=20=20=20=20=20=20=20=20 > > > end > > > =E2=80=94=E2=80=94=E2=80=94 > > >=20=20=20=20=20=20=20=20=20 > > >=20=20=20=20=20=20=20=20=20 > > > Now, here=E2=80=99s my current implementation > > >=20=20=20=20=20=20=20=20=20 > > >=20=20=20=20=20=20=20=20=20 > > > =E2=80=94=E2=80=94=E2=80=94=E2=80=94 myset.ml (cont=E2=80=99d) > > > module Product > > >=20=20=20=20=20=20=20=20=20 > > > (S1: T) > > > (S2: T) =3D > > >=20=20=20=20=20=20=20=20=20 > > > struct > > >=20=20=20=20=20=20=20=20=20 > > > module R =3D > > >=20=20=20=20=20=20=20=20=20=20=20 > > > Make > > >=20=20=20=20=20=20=20=20=20=20=20=20=20 > > > (struct type t =3D S1.elt * S2.elt let compare =3D comp= are > > >=20=20=20=20=20=20=20=20=20 > > > end) > > >=20=20=20=20=20=20=20=20=20 > > > (struct type t =3D S1.attr * S2.attr let compare =3D > > >=20=20=20=20=20=20=20=20=20 > > > compare end) > > >=20=20=20=20=20=20=20=20=20 > > > include R > > > module P =3D Myset.Product(S1.S)(S2.S) > > > let product s1 s2 =3D > > >=20=20=20=20=20=20=20=20=20=20=20 > > > { elems =3D P.product (S1.set_of s1) (S2.set_of s2); > > >=20=20=20=20=20=20=20=20=20=20=20=20=20 > > > attrs =3D > > >=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20 > > > List.fold_left > > >=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20 > > > (fun acc (e1,a1) -> > > >=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20 > > > List.fold_left (fun acc (e2,a2) -> > > >=20=20=20=20=20=20=20=20=20 > > > ((e1,e2),(a1,a2))::acc) acc (S2.attrs s2)) > > >=20=20=20=20=20=20=20=20=20 > > > [] > > > (S1.attrs s1) } > > >=20=20=20=20=20=20=20=20=20 > > > end > > > =E2=80=94=E2=80=94=E2=80=94 > > >=20=20=20=20=20=20=20=20=20 > > >=20=20=20=20=20=20=20=20=20 > > > I use the [Myseta.Make] functor for building the resulting > > > module [named R here]. For defining the [product] function, > > > i first use the [Myset.Product] functor applied on the two > > > related sub-modules [S1] and [S2] to build the product > > > module (named P here) and re-use the [product] function of > > > this module to compute the [elems] component of the result. > > > The other component is computed directly. > > > The problem is that when i try to compile this i get this > > > message : > > >=20=20=20=20=20=20=20=20=20 > > >=20=20=20=20=20=20=20=20=20 > > > File "myseta.ml", line 44, characters 14-53: > > > Error: This expression has type P.t =3D > > > Myset.Product(S1.S)(S2.S).t > > >=20=20=20=20=20=20=20=20=20 > > > but an expression was expected of type S.t =3D R.S.t > > >=20=20=20=20=20=20=20=20=20 > > > My intuition is that a sharing constraint is missing > > > somewhere but i just cannot figure out where to add it. > > > I tried to rewrite the signature of the [Myseta.Product] > > > functor (in [myseta.mli]) as : > > >=20=20=20=20=20=20=20=20=20 > > >=20=20=20=20=20=20=20=20=20 > > > module Product (S1: T) (S2: T) : > > > sig > > >=20=20=20=20=20=20=20=20=20 > > > include T with type elt =3D S1.elt * S2.elt > > >=20=20=20=20=20=20=20=20=20=20=20 > > > and type attr =3D S1.attr * S2.attr > > > and type S.t =3D Myset.Product(S1.S)(S2.S).t (* > > >=20=20=20=20=20=20=20=20=20 > > > added constraint *) > > >=20=20=20=20=20=20=20=20=20 > > > val product: S1.t -> S2.t -> t > > >=20=20=20=20=20=20=20=20=20 > > > end > > >=20=20=20=20=20=20=20=20=20 > > >=20=20=20=20=20=20=20=20=20 > > > but it did not change anything.. > > >=20=20=20=20=20=20=20=20=20 > > >=20=20=20=20=20=20=20=20=20 > > > So my question is : is my diagnostic correct and, if yes, > > > which constraint(s) are missing and where; or, conversely, > > > am i completely =C2=AB misusing =C2=BB the functor mechanisms= for > > > implementing this kind of =C2=AB reuse by inclusion =C2=BB ? > > >=20=20=20=20=20=20=20=20=20 > > >=20=20=20=20=20=20=20=20=20 > > > Any help will be grealy appreciated : i=E2=80=99ve been readi= ng and > > > re-reading about functors for the last two days but have the > > > impression that at this step, things get more and more > > > opaque.. :-S > > >=20=20=20=20=20=20=20=20=20 > > >=20=20=20=20=20=20=20=20=20 > > > In anycase, the source code is > > > here : http://filez.univ-bpclermont.fr/lamuemlqpm > > >=20=20=20=20=20=20=20=20=20 > > >=20=20=20=20=20=20=20=20=20 > > > Jocelyn --=20 Mikhail Mandrykin Linux Verification Center, ISPRAS web: http://linuxtesting.org e-mail: mandrykin@ispras.ru