digitalmars.D - "Modern D Design" :))
- "Aleksey Bobnev" <uw front.ru> Dec 27 2004
- "Walter" <newshound digitalmars.com> Dec 27 2004
- "Ivan Senji" <ivan.senji public.srce.hr> Dec 30 2004
- "Walter" <newshound digitalmars.com> Jan 29 2005
- "Ivan Senji" <ivan.senji public.srce.hr> Jan 30 2005
- "Walter" <newshound digitalmars.com> Jan 30 2005
- "Zz" <Zz Zz.com> Dec 27 2004
- Norbert Nemec <Norbert Nemec-online.de> Jan 07 2005
- M <M_member pathlink.com> Dec 28 2004
Yesterday I tried to get back to idea of using D templates for
meta-programming. Last time I tried it there were some serious bugs which
made meta-programming if not impossible at all, still very hard to achieve.
This time it turned out to be a fairly easy task. Though C++ specialization
is still much more powerful than D's one. Therefore template
meta-programming code in C++ is declarative by nature, while in D it seems
to be mostly imperative. But due to unique template syntax introduced in D
and some other advantages, D code surely looks cleaner, much more compact,
and doesn't require any preprocessor macros.
At this time I have only typelists and related meta functions similar to
those from famous Loki library, but it already seems to me - D language has
a Bright(sorry for a pun) future in area of meta-programming. Possibly with
some more improvements to template facility it will beat C++ completely some
day.
I ported a simple lisp program, which finds a solution to hanoi tower
problem, both to C++ and D.
Here's an original code(slightly modified code from xlisp examples):
(defun hanoi(n)
(eval (cons 'progn (transfer "A" "B" "C" n ))))
(defun print-move ( from to )
(princ "Move Disk From ")
(princ from)
(princ " to ")
(princ to)
(princ "\n")
nil)
(defun transfer ( from to via n )
(cond ((equal n 1) (list (cons 'print-move (list from to))))
(t (append
(append (transfer from via to (- n 1)) (list (cons 'print-move
(list from to))))
(transfer via to from (- n 1))))))
Here's C++ meta-program "port"(via Loki):
#include <iostream>
#include <typeinfo>
#include "TypeList.h"
using namespace std;
struct A
{
static const char * name()
{
return "A";
}
};
struct B
{
static const char * name()
{
return "B";
}
};
struct C
{
static const char * name()
{
return "C";
}
};
template <typename From,typename To>
struct print_move
{
static void exec()
{
cout<<"Move Disk From "<<From::name()<<" to "<<To::name()<<endl;
}
};
template <typename From,typename To,typename Via, int n>
struct transfer
{
typedef typename Loki::TL::Append<typename
transfer<From,Via,To,n-1>::type,Loki::Typelist<print_move<From,To>,Loki::Nul
lType> >::Result type0;
typedef typename Loki::TL::Append<type0,typename
transfer<Via,To,From,n-1>::type>::Result type;
};
template <typename From,typename To,typename Via>
struct transfer<typename From,typename To,typename Via, 1>
{
typedef Loki::Typelist<print_move<From,To>,Loki::NullType> type;
};
template <typename FnList>
struct eval
{
};
template <typename Fn,typename Fns>
struct eval <Loki::Typelist<Fn,Fns> >
{
static void exec()
{
Fn::exec();
eval<Fns>::exec();
}
};
template <>
struct eval <Loki::NullType>
{
static void exec()
{
}
};
int main()
{
eval<typename transfer<A,B,C,3>::type>::exec();
}
And here's D port (via my crazy little library):
import Thor.typelist;
import Thor.meta;
import std.stdio;
class A{}
class B{}
class C{}
template PrintMove(From,To)
{
struct PrintMove
{
static void eval()
{
writef("Move Disk From %s to
%s\n",typeid(From).toString(),typeid(To).toString());
}
}
}
template Transfer(From,To,Via,int n : 1)
{
alias TL!(PrintMove!(From,To)) Transfer;
}
template Transfer(From,To,Via,int n)
{
alias
Append!(Append!(.Transfer!(From,Via,To,n-1),TL!(PrintMove!(From,To))),
.Transfer!(Via,To,From,n-1)) Transfer;
}
template Eval(TL_ : TypeList)
{
void Eval()
{
TL_.H.eval();
.Eval!(TL_.T)();
}
}
template Eval(T : NullT)
{
void Eval()
{
}
}
void main()
{
Eval!(Transfer!(A,B,C,3))();
}
Now to implementation details. Here is how my TypeList looks and
works(complete code may be found in attachment along with hanoi sample in
C++,
lisp and prolog):
// end of list marker type
class NullT
{
}
// common base type for all typelists
class TypeList
{
alias NullT H;
alias NullT T;
template Length()
{
const int Length = 0;
}
}
// 1-type typelist constructor
template TL(T0)
{
class TL : TypeList
{
public:
alias T0 H;
alias NullT T;
template Length()
{
const int Length = 1;
}
}
}
// 2-type length typelist
template TL(T0,T1)
{
class TL : TypeList
{
public:
alias T0 H;
alias .TL!(T1) T;
template Length()
{
const int Length = 2;
}
}
}
// generated constructors for any arbitary number of types
// ...
//
// Cons is similar to cons in lisp
/*
Construct type list from head and tail
typical use :
Cons!(A,Cons!(B,Cons!(C,NullT)))
*/
template Cons(_Head, _Tail : TypeList)
{
class Cons : TypeList
{
alias _Head H;
alias _Tail T;
template Length()
{
const int Length = 1 + .Length!(T);
}
}
}
template Cons(_Head : NullT, _Tail : TypeList)
{
class Cons : TypeList
{
alias _Tail.H H;
alias _Tail.T T;
template Length()
{
const int Length = .Length!(_Tail);
}
}
}
template Cons(_Head, _Tail : NullT)
{
class Cons : TypeList
{
alias _Head H;
alias _Tail T;
template Length()
{
const int Length = 1;
}
}
}
/*
General meta-functions
*/
template Equal(T0,T1)
{
const bool Equal = false;
}
template Equal(T0,T1 : T0)
{
const bool Equal = true;
}
template SelectType(bool c, T0,T1)
{
alias T0 SelectType;
}
template SelectType(bool c : false, T0,T1)
{
alias T1 SelectType;
}
template SelectAlias(bool c, alias T0,alias T1)
{
alias T0 SelectAlias;
}
template SelectAlias(bool c : false, alias T0, alias T1)
{
alias T1 SelectAlias;
}
/*
typelist manipulation
*/
template Length(_TL : TypeList)
{
const int Length = 1 + .Length!(_TL.T);
}
template Length(_TL : NullT)
{
const int Length = 0;
}
template RemoveAll(_TL : TypeList, T)
{
alias SelectType!(Equal!(_TL.H,T),.RemoveAll!(_TL.T,T),
.Cons!(_TL.H,.RemoveAll!(_TL.T,T))
) RemoveAll;
}
template RemoveAll(_TL : NullT, T)
{
alias NullT RemoveAll;
}
template RemoveAll(_TL, T : NullT)
{
alias _TL RemoveAll;
}
template Remove(_TL : TypeList, T)
{
alias SelectType!(Equal!(_TL.H,T),_TL.T,
.Cons!(_TL.H,.Remove!(_TL.T,T))
) Remove;
}
template Remove(_TL : NullT, T)
{
alias NullT Remove;
}
template Remove(_TL, T : NullT)
{
alias _TL Remove;
}
template IndexOf(_TL : NullT, T, int i = 0)
{
const int IndexOf = -1;
}
template IndexOf(_TL : TypeList, T, int i = 0)
{
const int IndexOf = .Equal!(_TL.H,T) ? i : .IndexOf!(_TL.T,T,i + 1);
}
template TypeAt(_TL : NullT, int i)
{
static assert(0);
}
template TypeAt(_TL : TypeList, int i : 0)
{
alias _TL.H TypeAt;
}
template TypeAt(_TL : TypeList, int i)
{
alias .TypeAt!(_TL.T,i - 1) TypeAt;
}
template TypeAtNonStrict(_TL : NullT, int i, _Default = NullT)
{
alias _Default TypeAtNonStrict;
}
template TypeAtNonStrict(_TL : TypeList, int i : 0, _Default = NullT)
{
alias _TL.H TypeAtNonStrict;
}
template TypeAtNonStrict(_TL : TypeList, int i, _Default = NullT)
{
alias .TypeAtNonStrict!(_TL.T,i - 1,_Default) TypeAtNonStrict;
}
template Append(_TL0 : TypeList, _TL1: TypeList)
{
alias Cons!(_TL0.H,.Append!(_TL0.T,_TL1)) Append;
}
template Append(T: NullT, _T : TypeList)
{
alias _T Append;
}
template Append(T: NullT, _T : NullT)
{
alias NullT Append;
}
template NoDups(_TL : TypeList)
{
alias Cons!(_TL.H,Remove!(.NoDups!(_TL.T),_TL.H)) NoDups;
}
template NoDups(_T : NullT)
{
alias NullT NoDups;
}
template TypeidPrint(_TL : TypeList)
{
void TypeidPrint()
{
typeid(_TL.H).print();
.TypeidPrint!(_TL.T)();
}
}
template TypeidPrint(_T)
{
void TypeidPrint()
{
typeid(_T).print();
}
}
template TypeidPrint(_TL : NullT)
{
void TypeidPrint()
{
}
}
/*
and finally a little sanity test
*/
alias TL!(int,float,char,double) tl0;
alias TL!(double,char,float,uint) tl1;
alias Append!(tl0,tl1) tl2;
alias NoDups!(tl2) tl3;
template TypeidPrint(_TL : TypeList)
{
void TypeidPrint()
{
typeid(_TL.H).print();
.TypeidPrint!(_TL.T)();
}
}
template TypeidPrint(_T)
{
void TypeidPrint()
{
typeid(_T).print();
}
}
template TypeidPrint(_TL : NullT)
{
void TypeidPrint()
{
}
}
void main()
{
static assert(IndexOf!(tl0,char) == 2);
static assert(IndexOf!(tl0,TypeAt!(tl0,IndexOf!(tl0,char))) == 2);
static
assert(IndexOf!(tl0,TypeAtNonStrict!(tl0,IndexOf!(tl0,uint),char)) == 2);
printf("tl0.l == %d\ntl1.l == %d\ntl2.l == %d\ntl3.l = %d\n",
tl0.Length!(),tl1.Length!(),tl2.Length!(),tl3.Length!());
printf("types in tl0\n");
TypeidPrint!(tl0)();
printf("types in tl1\n");
TypeidPrint!(tl1)();
printf("types in tl2\n");
TypeidPrint!(tl2)();
printf("types in tl3\n");
TypeidPrint!(tl3)();
}
Dec 27 2004
"Aleksey Bobnev" <uw front.ru> wrote in message news:cqp7v0$1grl$1 digitaldaemon.com...This time it turned out to be a fairly easy task. Though C++
is still much more powerful than D's one. Therefore template meta-programming code in C++ is declarative by nature, while in D it seems to be mostly imperative. But due to unique template syntax introduced in D and some other advantages, D code surely looks cleaner, much more compact, and doesn't require any preprocessor macros.
Great!At this time I have only typelists and related meta functions similar to those from famous Loki library, but it already seems to me - D language
a Bright(sorry for a pun) future in area of meta-programming. Possibly
some more improvements to template facility it will beat C++ completely
day.
What do you think it needs? Also, what in particular are you thinking of by saying that C++ specialization is much more powerful? D's is equivalent, if not more powerful.
Dec 27 2004
"Walter" <newshound digitalmars.com> wrote in message news:cqpgh1$1qrs$1 digitaldaemon.com..."Aleksey Bobnev" <uw front.ru> wrote in message news:cqp7v0$1grl$1 digitaldaemon.com...
.... Possibly withsome more improvements to template facility it will beat C++ completely
day.
What do you think it needs? Also, what in particular are you thinking of
saying that C++ specialization is much more powerful? D's is equivalent,
not more powerful.
I know there are people out there that could answer this better than i but i will try: Here is the example of C++ code: <CODE> #include <iostream> using namespace std; template<class U,class V,class X,class Y> class Four { U i; V j; X k; Y l; }; template<class U,class V,class X,class Y> int WhatFour(const Four<U,V,X,Y>& four) { cout << "general template\n"; } template<class U,class V,class X> int WhatFour(const Four<int,U,V,X>& four) { cout << "specialization:: first int\n"; } template<class U,class V> int WhatFour(const Four<U,U,V,V>& four) { cout << "specialization:: first two equal, second two equal\n"; } int main(int argc, char *argv[]) { WhatFour(Four<int,float,char,bool>()); WhatFour(Four<float,float,char,bool>()); WhatFour(Four<float,float,char,char>()); WhatFour(Four<int,int,float,char>()); /* will print: specialization:: first int general template specialization:: first two equal, second two equal specialization:: first int */ return 0; } </CODE> Is there a way to write this in D? If not (and i haven't found one) here is our problem. Specializations like this are used alot in C++.
Dec 30 2004
"Ivan Senji" <ivan.senji public.srce.hr> wrote in message news:cr0f07$2uj7$1 digitaldaemon.com...Is there a way to write this in D? If not (and i haven't found one) here
our problem. Specializations like this are used alot in C++.
Ah, I see. What you're asking for is not specialization, but implict instantiation of function templates. You can do the same sort of specialization, however, in D: class Four(U, V, X, Y) { U i; V j; X k; Y l; } template WhatFour(U,V,X,Y) { void func(Four!(U,V,X,Y) four) { printf("general template\n"); } } template WhatFour(U:int,V,X,Y) { void func(Four!(int,V,X,Y) four) { printf("specialization:: first int\n"); } } template WhatFour(U,V:U,X,Y:X) { void func(Four!(U,U,X,X) four) { printf("specialization:: first two equal, second two equal\n"); } } alias WhatFour!(int,float,char,bool).func whatfour; alias WhatFour!(float,float,char,bool).func whatfour; alias WhatFour!(float,float,char,char).func whatfour; alias WhatFour!(int,int,float,char).func whatfour; int main() { Four!(int,float,char,bool) f; Four!(float,float,char,bool) g; Four!(float,float,char,char) h; Four!(int,int,float,char) i; whatfour(f); whatfour(g); whatfour(h); whatfour(i); /* will print: specialization:: first int general template specialization:: first two equal, second two equal specialization:: first int */ return 0; }
Jan 29 2005
"Walter" <newshound digitalmars.com> wrote in message news:cti6lg$1o0q$1 digitaldaemon.com...Ah, I see. What you're asking for is not specialization, but implict instantiation of function templates. You can do the same sort of specialization, however, in D:
int main() { Four!(int,float,char,bool) f; Four!(float,float,char,bool) g; Four!(float,float,char,char) h; Four!(int,int,float,char) i; whatfour(f); whatfour(g); whatfour(h); whatfour(i); /* will print: specialization:: first int general template specialization:: first two equal, second two equal specialization:: first int */
Thanks for this example, but i get: specialization:: first int general template general template specialization:: first int ?return 0; }
Jan 30 2005
"Ivan Senji" <ivan.senji public.srce.hr> wrote in message news:ctiav5$1u2e$1 digitaldaemon.com...Thanks for this example, but i get: specialization:: first int general template general template specialization:: first int ?
So did I at first. That's a compiler bug, and I fixed it (will appear in next update). -Walter
Jan 30 2005
I could not resist.
As a person who really likes Lisp and D here is a Dylan version.
The code is from the recently released Open Dylan.
I personally used Dylan about 3 years ago for a few projects of my own while
not Lisp it has a small runtime and it statically links.
Module: hanoi
Synopsis: The classic Towers of Hanoi puzzle
Author: Andy Armstrong
Copyright: Original Code is Copyright (c) 1995-2004 Functional Objects,
Inc.
All rights reserved.
License: Functional Objects Library Public License Version 1.0
Dual-license: GNU Lesser General Public License
Warranty: Distributed WITHOUT WARRANTY OF ANY KIND
define class <disk> (<object>)
constant slot diameter :: <integer>,
required-init-keyword: diameter:;
end class <disk>;
define function make-disk
(integer :: <integer>) => (disk :: <disk>)
make(<disk>, diameter: integer)
end function make-disk;
define class <tower> (<object>)
constant slot name :: <string>,
required-init-keyword: name:;
constant slot disks :: <deque> = make(<deque>);
end class <tower>;
define method initialize
(tower :: <tower>,
#key initial-disks :: <sequence> = #[])
=> ()
next-method();
for (disk in initial-disks)
push(tower.disks, disk)
end
end method initialize;
define method height
(tower :: <tower>) => (height :: <integer>)
size(tower.disks)
end method height;
define variable *n-operations* :: <integer> = 0;
define method move-disk
(from-tower :: <tower>, to-tower :: <tower>)
*n-operations* := *n-operations* + 1;
format-out(".");
let disk = pop(from-tower.disks);
push(to-tower.disks, disk)
end method move-disk;
define method hanoi
(from-tower :: <tower>, to-tower :: <tower>, with-tower :: <tower>,
#key count :: <integer> = from-tower.height)
=> ()
if (count >= 1)
hanoi(from-tower, with-tower, to-tower, count: count - 1);
move-disk(from-tower, to-tower);
hanoi(with-tower, to-tower, from-tower, count: count - 1)
end
end method hanoi;
Dec 27 2004
Zz wrote:The code is from the recently released Open Dylan.
I know this is drifting off-topic, but still: what is "Open Dylan"? I know of Gwydion and FunctionalDeveloper. The news page of Gwydion mentiones that FD might become OpenDylan one day, but information generally seems rather confusing.
Jan 07 2005
Think the Lisp wins this on ;) In article <cqp7v0$1grl$1 digitaldaemon.com>, Aleksey Bobnev says...Yesterday I tried to get back to idea of using D templates for meta-programming. Last time I tried it there were some serious bugs which made meta-programming if not impossible at all, still very hard to achieve. This time it turned out to be a fairly easy task. Though C++ specialization is still much more powerful than D's one. Therefore template meta-programming code in C++ is declarative by nature, while in D it seems to be mostly imperative. But due to unique template syntax introduced in D and some other advantages, D code surely looks cleaner, much more compact, and doesn't require any preprocessor macros. At this time I have only typelists and related meta functions similar to those from famous Loki library, but it already seems to me - D language has a Bright(sorry for a pun) future in area of meta-programming. Possibly with some more improvements to template facility it will beat C++ completely some day. I ported a simple lisp program, which finds a solution to hanoi tower problem, both to C++ and D. Here's an original code(slightly modified code from xlisp examples): (defun hanoi(n) (eval (cons 'progn (transfer "A" "B" "C" n )))) (defun print-move ( from to ) (princ "Move Disk From ") (princ from) (princ " to ") (princ to) (princ "\n") nil) (defun transfer ( from to via n ) (cond ((equal n 1) (list (cons 'print-move (list from to)))) (t (append (append (transfer from via to (- n 1)) (list (cons 'print-move (list from to)))) (transfer via to from (- n 1)))))) Here's C++ meta-program "port"(via Loki): #include <iostream> #include <typeinfo> #include "TypeList.h" using namespace std; struct A { static const char * name() { return "A"; } }; struct B { static const char * name() { return "B"; } }; struct C { static const char * name() { return "C"; } }; template <typename From,typename To> struct print_move { static void exec() { cout<<"Move Disk From "<<From::name()<<" to "<<To::name()<<endl; } }; template <typename From,typename To,typename Via, int n> struct transfer { typedef typename Loki::TL::Append<typename transfer<From,Via,To,n-1>::type,Loki::Typelist<print_move<From,To>,Loki::Nul lType> >::Result type0; typedef typename Loki::TL::Append<type0,typename transfer<Via,To,From,n-1>::type>::Result type; }; template <typename From,typename To,typename Via> struct transfer<typename From,typename To,typename Via, 1> { typedef Loki::Typelist<print_move<From,To>,Loki::NullType> type; }; template <typename FnList> struct eval { }; template <typename Fn,typename Fns> struct eval <Loki::Typelist<Fn,Fns> > { static void exec() { Fn::exec(); eval<Fns>::exec(); } }; template <> struct eval <Loki::NullType> { static void exec() { } }; int main() { eval<typename transfer<A,B,C,3>::type>::exec(); } And here's D port (via my crazy little library): import Thor.typelist; import Thor.meta; import std.stdio; class A{} class B{} class C{} template PrintMove(From,To) { struct PrintMove { static void eval() { writef("Move Disk From %s to %s\n",typeid(From).toString(),typeid(To).toString()); } } } template Transfer(From,To,Via,int n : 1) { alias TL!(PrintMove!(From,To)) Transfer; } template Transfer(From,To,Via,int n) { alias Append!(Append!(.Transfer!(From,Via,To,n-1),TL!(PrintMove!(From,To))), .Transfer!(Via,To,From,n-1)) Transfer; } template Eval(TL_ : TypeList) { void Eval() { TL_.H.eval(); .Eval!(TL_.T)(); } } template Eval(T : NullT) { void Eval() { } } void main() { Eval!(Transfer!(A,B,C,3))(); } Now to implementation details. Here is how my TypeList looks and works(complete code may be found in attachment along with hanoi sample in C++, lisp and prolog): // end of list marker type class NullT { } // common base type for all typelists class TypeList { alias NullT H; alias NullT T; template Length() { const int Length = 0; } } // 1-type typelist constructor template TL(T0) { class TL : TypeList { public: alias T0 H; alias NullT T; template Length() { const int Length = 1; } } } // 2-type length typelist template TL(T0,T1) { class TL : TypeList { public: alias T0 H; alias .TL!(T1) T; template Length() { const int Length = 2; } } } // generated constructors for any arbitary number of types // ... // // Cons is similar to cons in lisp /* Construct type list from head and tail typical use : Cons!(A,Cons!(B,Cons!(C,NullT))) */ template Cons(_Head, _Tail : TypeList) { class Cons : TypeList { alias _Head H; alias _Tail T; template Length() { const int Length = 1 + .Length!(T); } } } template Cons(_Head : NullT, _Tail : TypeList) { class Cons : TypeList { alias _Tail.H H; alias _Tail.T T; template Length() { const int Length = .Length!(_Tail); } } } template Cons(_Head, _Tail : NullT) { class Cons : TypeList { alias _Head H; alias _Tail T; template Length() { const int Length = 1; } } } /* General meta-functions */ template Equal(T0,T1) { const bool Equal = false; } template Equal(T0,T1 : T0) { const bool Equal = true; } template SelectType(bool c, T0,T1) { alias T0 SelectType; } template SelectType(bool c : false, T0,T1) { alias T1 SelectType; } template SelectAlias(bool c, alias T0,alias T1) { alias T0 SelectAlias; } template SelectAlias(bool c : false, alias T0, alias T1) { alias T1 SelectAlias; } /* typelist manipulation */ template Length(_TL : TypeList) { const int Length = 1 + .Length!(_TL.T); } template Length(_TL : NullT) { const int Length = 0; } template RemoveAll(_TL : TypeList, T) { alias SelectType!(Equal!(_TL.H,T),.RemoveAll!(_TL.T,T), .Cons!(_TL.H,.RemoveAll!(_TL.T,T)) ) RemoveAll; } template RemoveAll(_TL : NullT, T) { alias NullT RemoveAll; } template RemoveAll(_TL, T : NullT) { alias _TL RemoveAll; } template Remove(_TL : TypeList, T) { alias SelectType!(Equal!(_TL.H,T),_TL.T, .Cons!(_TL.H,.Remove!(_TL.T,T)) ) Remove; } template Remove(_TL : NullT, T) { alias NullT Remove; } template Remove(_TL, T : NullT) { alias _TL Remove; } template IndexOf(_TL : NullT, T, int i = 0) { const int IndexOf = -1; } template IndexOf(_TL : TypeList, T, int i = 0) { const int IndexOf = .Equal!(_TL.H,T) ? i : .IndexOf!(_TL.T,T,i + 1); } template TypeAt(_TL : NullT, int i) { static assert(0); } template TypeAt(_TL : TypeList, int i : 0) { alias _TL.H TypeAt; } template TypeAt(_TL : TypeList, int i) { alias .TypeAt!(_TL.T,i - 1) TypeAt; } template TypeAtNonStrict(_TL : NullT, int i, _Default = NullT) { alias _Default TypeAtNonStrict; } template TypeAtNonStrict(_TL : TypeList, int i : 0, _Default = NullT) { alias _TL.H TypeAtNonStrict; } template TypeAtNonStrict(_TL : TypeList, int i, _Default = NullT) { alias .TypeAtNonStrict!(_TL.T,i - 1,_Default) TypeAtNonStrict; } template Append(_TL0 : TypeList, _TL1: TypeList) { alias Cons!(_TL0.H,.Append!(_TL0.T,_TL1)) Append; } template Append(T: NullT, _T : TypeList) { alias _T Append; } template Append(T: NullT, _T : NullT) { alias NullT Append; } template NoDups(_TL : TypeList) { alias Cons!(_TL.H,Remove!(.NoDups!(_TL.T),_TL.H)) NoDups; } template NoDups(_T : NullT) { alias NullT NoDups; } template TypeidPrint(_TL : TypeList) { void TypeidPrint() { typeid(_TL.H).print(); .TypeidPrint!(_TL.T)(); } } template TypeidPrint(_T) { void TypeidPrint() { typeid(_T).print(); } } template TypeidPrint(_TL : NullT) { void TypeidPrint() { } } /* and finally a little sanity test */ alias TL!(int,float,char,double) tl0; alias TL!(double,char,float,uint) tl1; alias Append!(tl0,tl1) tl2; alias NoDups!(tl2) tl3; template TypeidPrint(_TL : TypeList) { void TypeidPrint() { typeid(_TL.H).print(); .TypeidPrint!(_TL.T)(); } } template TypeidPrint(_T) { void TypeidPrint() { typeid(_T).print(); } } template TypeidPrint(_TL : NullT) { void TypeidPrint() { } } void main() { static assert(IndexOf!(tl0,char) == 2); static assert(IndexOf!(tl0,TypeAt!(tl0,IndexOf!(tl0,char))) == 2); static assert(IndexOf!(tl0,TypeAtNonStrict!(tl0,IndexOf!(tl0,uint),char)) == 2); printf("tl0.l == %d\ntl1.l == %d\ntl2.l == %d\ntl3.l = %d\n", tl0.Length!(),tl1.Length!(),tl2.Length!(),tl3.Length!()); printf("types in tl0\n"); TypeidPrint!(tl0)(); printf("types in tl1\n"); TypeidPrint!(tl1)(); printf("types in tl2\n"); TypeidPrint!(tl2)(); printf("types in tl3\n"); TypeidPrint!(tl3)(); } begin 666 Thor.zip M4$L#! H``````)V.FS$````````````````$````8W!P+U!+`P04````" ": M9IDQG N&IJ8!``"^!0``$ ```&-P<"]H86YO:5]C="YC<'"E4TU/ S 8OI/P M'][ 10T:C;?2D&PSGJ8'LW U#72N$5I"RZ(Q^^^^!=)ND#FW<5GW]/GBI;T0 M,BN:G ,52IN:LS(-`P\B).3'#F2^*R[D4 UXN5"WJVTL6B!Q+K2Y745A$ :- M1B>0K.2Z8AD'E"06QX F,S ) Y\P``#<8$9DD"FI#60K5L-U*[N\ZO8MK7]J M;II:0C2)D [<A,%FVW5ZCNMTG^OL'-?9R-7PLBJ8Z6=KY?!4JS)V_Q8J==E5 M+:1Y+]6:#TNLE<B!?_%L'(X%&T-I](PR>!3ZLPV B%+[2TA7&0E E$47RF-< MYL4)C?WZ3; 8L#1(_Q:F9E(O>>W>P;)SO 2GFJM/0<AB3LBD0BAW24Y+VTCK MCFGRYCXEQ'+B7HG+0FA#_< Z`0ZSI[PT16%I*:#TE>NF,&W^77),I[MXW*PO MU>;Y9KLIR:G#'$_QWU_A/AT-_/AI'6XO[;7W-?F:%9C[IR+>6NM=*=!!1V1; M$J1'W "T):3;2CQH[:GU<GM[#_JPTV HAZL,G.V%*)F0N&^EKLWX,$WB:3R+ M']PA\E4WOU!+`P04````" #(NM0J$QCZJF "```Y! ``# ```&-P<"].=6QL M5'EP92YHM51-;]LP#+T'R'] L\N&9F[788=EIZ ;AFY9D$.+8:="EFB;B"P) M^FAK%/WOH[340;L>&\& ;>KQZ>F1TLDKC^GDY 0N.X25W1*LJ/;"#R5X;MW MJ>TBO)7OX.ST] /4`RR-\DBPU' G\F>0:4=!`:15"$)*VSMA" -$)JZMW2XR MYDG2?,=4P>P79WD#Y\?'\!4#M68!W]& )PD;;ULO^IY,"YRYFX?"EL=&Q,BY M`9;.:4(UJUZ07<%2*0K6O/^-0>-0E?0-^IY"(&L 6D !YR Y=0Z]5=3PFU.B MISI%+$L'U!IBWF6P3;P5'J&QGJ>&O1R7O+,! 4$=>F2[6+V)J."68F=3A 9Y M'>?M#2E43"=B\4C4] 9!CM)'1F,C29YW#H4',B"TSKALKC [AMK&KGSM&<9$ MQA31>XWCOO\G#\DYZV-V6UF9>C111$968Y>(Q/OPP,_>4QUPX/8Q;2\,]&*+ M3 P>G<?P2!#R#E/9ZUY)2!1%39KB`+9YV=M'2RNXB$!A;]U,!/Z?C6RCPWB7 M%PY9(O6E*8 )<QE*X5]Y3"=%P$J$",DI$7$!/Y)!;KQY:;X,>$.-4=C ^FJU MNORS^79]L3Z_YC#'R."S,..-Z#$X(?\=RNGD_A"Z6;74 HU:)ZTO!X<E=!50 M`5LKP&D6T%FMT)=BS(R%R+#2V;-'<)-T 1M H[CX?LMP, 6I*<0`A] ^G0# M,_EP__!E.GF83 ZQ8+X..V%:!&W;<ID]K?("\KE!E6_(-<DMGY7DR\722 EG MU>=/U<<*?B9EP[P`CHZ.#J&3FPJ-H 98X+.V^ M02P,$% ```` `X+OG,#%: M4F N# ``4X(```X```!C<' O5'EP94QI<W0N:-U=;7/;-A+^W,ST/Z"^#[6G MM&O)\9N2YL:-TS9WKB\3R].YF9OI0"0D84(1.I!TXNODO]\N(!*B24007Q39 MF BAR,7NLXO=);"4H1];?GW[[,<?R7#*R)7XP,D5'TDJ[]7)UV)^+_EDFI!= M?X_T#P][9'1/+J) ,DXN0O:)XF'LI]74SY$:R<C/8A2Q\7 AB<?$%P$CU/?% M;$XCSF*2 /R1$!\&2%/ [2T$'I"=WZ&7C,CK'WX ERSFDVA ?F41D]PG[Z28 M2#J;\6A"H.?B.E'<\/6.) GTC<G%?!YR%NP<5&AW0"Z" ,<BVO^#Q2&[/U#= MWS$YXW',14020=*8><2'KAZ9B8"/X7_HDD ^2A.F1,<L#$F"6L9BG'RDDI&Q MD'#IWL"9IW(N8D: :,HD`SL!^BAA`?G(DZE($S)F(&<NQ1T/6 #L:*)L1$?B MCA$_ VXX1B+A/ER?SQF5A$>$AB'2H7%IM. P$LE4'QD.NB/2:- &H]&[Q#Q. MYW,A$[1V(/QTQJ*$)D!YD#L334$/2>"?L6D8LWOPLF RHQ&9T0\,&!/)YC#. M&8,8-4R5K 9)G/*$CGC(DWLBQM6VS4QZ0-XF8%9CNAT:P^<=PRVS,/N$ F.$ MR&?**0 PQ&%0`]_RZ]MG"L 5C1.2S .:L 'Y1QHQ<#Q/.1\2_(V/HX"-R?#? M[]Y<O;T9_OGV^O6?<!K.\8 53VOZR ]3"*6=ZS0,A_=S=C#=63Z-IWZ'")NK M\UUH!3K-J"]%;-#U/'/<]\C!P8'Y?'RHNKRA/C B_8#.2:)T-F(21Y;*B?*E MF+#_IC3$>.-)C 0JR.-T/.:?<A<SU. '":A*(CIC\9*XZVLRP0Q!$Y2D:$(> MH_N#O_$(_-?X!08,$H#OT# &;Z"Q$>&!U^O($1*2T('6XA,%QV&#)75W_2F5 M2)SLE20O2T4RC#FD[,C;2E[3VQWV]LA 'E^,! N;/%RV//RDYD;O2HP,-HA M[;!O8;(D"&FJ>1PM>,#[R,;'R--T-E[/EWC!^_D>^<^WSP A%K8& NEB8WW\ M #6\CYW8(ZIB-YN(DPH1\#YQ$H,(RUUMHDXMHN!]ZB0.T5JZ6T2>?4$DO,^< MQ")R.PN;Z/,5HN%][B0>M5C!Q *A=^B `=Z]0R< J),#+RN:GBL:;'IND%!' M5XY68/VU &'3=T77<T.'S/3+2+"A/5H?+39'KI#[=2 ;,5;<.D\VXHV-8WY% M.[4ARZ+,<4O*8'/LJM'S%C12`JUJG;2I%C8GKKH=MZ6;DFI5\+1U!;$Y==7R MI%4ME6BKJF?=J(K-F:N^I^WKJ^1;E3[O4&ELSETU/^M(\P4(R]3XL&OUD?FA MJPW.N[2!0F(U1&\CAL#&=:+2/^S<& J.U23]S9D$F[ZK77J;L8O"9#7.T8:- M \V1JX7Z&[20`F8U4UMSN+708//<U59MS/IJH+,9K-5YXEJ0L#EVM5IK,TL; MQ$)G&UJK%=N?EM:%B,V)JU7;G=,V FPU;4<3XKHXL3EUM6\'L^E&N*U&[G(J M7A<L-F>NENYJ'M\(O-7<G2\"ZB+&YMS5YIVN(!II8*VJ;V;Y41<VHCITM7[W M:Y=&:EB'8%,+GP;8L7%=-1UM8M747!?+8&QJR=54`6SZKB.RB?5:2PI9AF53 MB[U6M,#FR'5L-K%2;%,KRP!M:IG9GBK8.#_YW<0:M775+$.UJ05N(WU,YPK5 ML#EV';KM6" W4M4ZE%NVRJZK'S8GKN.Y14OT1OI:!W4;U_=UE<3FU'5DMZTX MT$AIZ_!N;66AKJ;8G+F.\5:6)1II;AWH[:YIU%47FW/7T=[> D C]:W?*WP$ MU92Z.J,ZAZ[CON6EF$8VL [^HZCC-% <&]<BT/.M+P(U-X3%#1Y%!:FI]MCT M77UAZ\M/+5G#XA"/HG;5B FP.7+UBJTO?+5I$HMK/(JJ67MVP.:YJW]L?<FM M=;M8G.2)U.MLQBAV+ML%&^<_H7D"Q;Y&=K(ZT5.J%-8U#C8GKI[T5,J,K7O2 MDRM/UO4D;$Y=W>E)U38;6<SJ6$^S,%K73-B<N7K7TZNJ-C*;U<6><$FVKJVP M.7?ULR=:SVUD.^M? C_U8G!= Z$=#ET][BE7DIL94+N=VKAB3GV]"\^WS_[J M8D\(V++"#VD<DX3-YB%-&,E&*]]38Y3R,, -*D:A\#^HW586)#%^P(U60A9- MDJGJ<1LSPG&S%BG2R13^9X6M-_3&((KR4D553."=L$ QC0?YUAN_,1J0W3&7 M<4)8R'#'#8]0$HEH/Q.ONN"&0KZ([N Z%]%>WG](>4AV8P;7`L/ IQ$9,< L M`)C,%=GKPK3*`8Q=7VH[#[V%P6]?:8(XD:F?&+.KDW_EWH,0U?XORB(O2N=O ME::+\Y]?9&*-\PRO])D-N<^5<8778C9/$[V3T\)%E,, =N-B;Z,[X5,</+([ MO,)AY?$2S9YV"<WVI2)X-1C<T3!EZH)D22HC[.&#.!ZR_83/&+I$G-"HL*U+ M$89BY8%#(4T:)4"1.P]2,MS]"/<[BF B)-G]..7^M.AMB#3;'J5#%ZIR(VV( MS'FT=5Y4D3^ >9GA77A?[FSFQ:)T1OXBRL3D)W)(/AO&A6-]Y.3D^"KB(.:N MX $9<<;3(S]D/&XS3W `L;-MC2I2Y87VXE]X%"A'UTF))H22"0<_(7"!?8)V M3;_'G8"ROB7OYE'")I*&)//8S-^S<-'(=+AXF W8ZCV+TS!9"AN#& '.1<P5 MGN]5A^_Q''#(\([)O4C51DB C8 TV1?C_9%(07$MP5/<I!)2`9I)*607`[,B M2CR21KCS&PO0;AIJ'A7:4$Y.C?DW\VO,N277SJR>>[;JH6D]<FCS<)/+D9[H M02KYLRNJA]JNB9*O1HG_X^TE8Z2E<K)/>KF/+;3XBE%Y+:*;1'*_>7C&'<0G MW6LY1#TB9'XO(GQLH&40BA&KSHXJ47CDLBF0RP*" N N?*!&`O#*OHT^C9-2 M"GHK*_Z4&]021,;)5 5- 6\Y-FKE'Z^$V 6J-3UY!2Y.N:H]38H#U*YF?#W- MC&RX7'R5!9K45Q"R%7GP+?KYO\;%_*>]WTS#:TY,AN:<SFB9M"R3#*LFZ0C M9 Z< ]OS%TI0D_,QIHV<K O3K4P?BP_9I"'3U6TJ7'+;W%29NF MY]GO?J_) M=!S]U8['S,CSV!EVNDPHYX%5-K.$N 7F7/([$#>H!(Y `'?&6,L?5JXHYNDH MY/[ B_KO:GYJA/Z.S0!7*DK*WE=:GES,(9$%ZHH^S$(68FTYH!.1%436BW_& ML4\E3T *1JS)"573B *2*572M-BQ"$/QD06XZ!ZBV#Q![&<+<Q9T8<JU$X+6 M<X7//Z VX:_4<KLW(663.<30#F*X4GIA-]>]MF[^1JP56E70$P>X%=W:0IT? MV^ [9"HWV(:H:L*:2=.83(2]*G7[LN9=A%$Y([V1-&9X01_I"8&N\0K?3R6+ M?!ANKHK*7 >3%"6U9CK*- FOPJSF,EV8<-U,I#5T306V%UCC9LY\3D/^/VWC M7LZG(& Y1ILF+]?IRPJD?0O2TN3&"3)2-J_(Y 8OPSVJAKNI[*&$.22/K[F. M41 OPG Y;] P?!B#<>>)`S TS!T(;VNS!JCWPG$=4^S59A9PR %V**YA;M+' MKP*=227UC_2>!.)CI#ZH091L)NZR1T>HP(J*00:C%%%5RK8RV2 KCITWJ'N- M? -PMSSE7(O+=!YR'XYUI?0]&F.1=X+LDE(+GWW4>J19$%+**U^CT)&E P(R MQT5-49NV%C0U5Q%E0&Y+B'+5P![K1?[(SP3[5>^%2Z)X>=7SE")+/?OELH-+ MW$''5U\S8-XS^-]GZI(^KI[<VV[-GKI#%KZ7X1))'L&'Q_EOO<08608!!%5. ML^I^C7#4$W[K]!XE2\TXT&AON["MX[W;/&'/(C#3NO$#>LW'S.VU`;L+Y<*M MW0%7Z1;O"C#O>)LE +9F]NN 1B8U )N^*VZQF4"4H 5LZ4U6`\UF]ME'?8\U ML_I'D#&* !]5L #CMY4O %7+*2,[;BUU`,1VLH<)-L.X(M[:KS8ZZ;CQ7 ,R M'T.ZN6-25Q^SX[C&Q-WTULEBS4* 5'V_RF,+$_L:0\W'E[GZ#QX';,WC`X.O MUF.#4FD=J*S^KT45I_\/YO35BF[*ZW^!-F&1NC36Q['"3Z:<22K]Z3U>4[]W MNO.'",>_X>/V';([EF)&WM]<7G?RQ=9OX-\W7_32##G8JDC[D, L-I%N,:;0 MP7*+0:+/AFG1MW+'4KP>R#'NY $!T>* ,;(,A;E%F.XF+WX)2P:EEV/IN:$R MPM4?2;PR($LVR;"!Q0<#[>6:1).]?(B]Q)ODNBSW\\K]*NE*H8$ -QD4OXLX MN62PS&=!U;<#>53.W_KR3,")0/<D&"'9UPC7F7^:$Y;)Y^IOWR&E1O:]!=B6 M%):7+%WW=F-8K/NTNJU;C$=<P+7QU912 "[Q+]>47],HX %P<:P9&;8W+&1^ M4G%GN[E]]^;]S>W/KZ\N;FYV<P'ZEK9GF0YJ?3/B[?CRV\)H0_&+%)$.I LI M:311=:G*TBV)A0JI<D!I8OU3UU ;6FNV6$2B ]P>X9()"6)!J"+LY+F\ZSRQ MB'Q%Z! WK^[>6DVXC2EB$5H7U>%2X!8GA>5 &DY9*5F6V%N*/*NXE:K,:Q>9 M'_*[<EK:?M:/F8I_BU8ZB7_=V%E:>#W%F">AF*AHU+^O?GBN?U]]`'?^3V24 M3M0WVJD$2 F3^O&7&)=^Q+Q_1!*Q]/%4<52O71]"ED/&2!G27-([4);>AT+N MY6)!9"86?RA??Z_MFOL?8+0 _K'?Q/=)_^#\^.#H /PS#43L*8+OOONN"_/ M7S8SR-EC&([R[\C_'U!+`P04````" #(NM0JF;&DA3P&``!N& ``#P```&-P M<"]4>7!E36%N:7 N:-U8;6_;-A#^'B#_X9(!K=VJ;IIA'Z:F!?+2KEF3+HAE M%,,V!+1TMHE(I$923KR _WW'%YM^B8%LK3MT1H#(Y-WQX3W'YV ]_\*?[:WG MSR$;(9S):PYGO*^8FKC!8UE/%!^.#+3R-NSO[;V _ 0.1:&0PV&)M\P^ZKP) M(;B&7!8(+,]E53/!48.AP'TIKU-KL^"4A$ =V#TG+R7 ^.E3.$'-AR*%GU" MXCE<*#E4K*JX& )YAGEPT>SG AE#OAH.Z[KD6.QV[H'= <.BX%J*9Q]1ESCI M./<+5!77FDL!1D*C,8&<7!.H9,$'])]<C.+]QJ!;6F-9 K&[U') ;IA"&$A% M4Y,(IVY4+34"&8U0(:6+T N#!=QP,Y*- 0'2.K628UY 0>&8<3EB?3E&R*?0 M8T0A#<]IOJZ1*> "6%E:.YM<)D*$OC0C]Q0C!,= P_4<QKCOE>"ZJ6NIC,UV M(?.F0F&8(<O.K$I80_M00'\QIZ7&"96/&%9,0,6ND0*#PIIXG ;0=H>-VVM$ MHAMN6)^7W$Q #M;D-J2T`Z<&N(ZIVV6:ON_&:-,,XZU=6%N(O')%`130TN"( M_\*?[2T'X(QI`TU=,(,I_-P(I,)+7/%9 ^_X0!0X .S7BS?GAQ].+ZY./QQ? MT3 -<H'+X^0A6(6Z9KD_EMM;=YM 3KCSDFD-!BE1!!U.A=G/)C6&\R_&J(P& M9/D(N#!(Q6R+3VA#V;0C$A T O_9()C 1C'&,G>DI[-X!^/7<&-/!(PMB0RL M0O 2GQE>88PX7</%.7&YT?!XS,H&'R? !*!H*E_H:$>9H7D",=Y$=K:W`""F MYH# P?BU']5&-;F)Z7*#Q!'XC\=Y!PXYO*)-?WKI)F?_-P%XE4Z+;0V?CJ]% M"A/ZJGG-B_NXC+$.LBF7F><R6$?&S A]^%](BKA I74C'T[+5JS6T&?YM>4M MVT0:EGFS2.QQ FR1/ OJ?O:LASNN"QOX3QCL8HFYL3/A48,4Z-3R1CJ -IL: M"Q(?(HG99ELB$[,SM7PD0YB#0<F&"60)]%ZGZ27JIG2FGEG?K:W)ZFF]?X7, M-9H>,(4>E1MU<9?.: 9\, M-3&#B>Y0D;VEH]1NN<4-"O5 8=B/ \Q!K9.ZY MMU O 8JUQ1)V&\MD:;D'KT'DL%)C8&?M KVPX->IRW=8UJA"Q74K5I:.MB,^ MA&<P;)B[YJ#79LW_0CEH.:LV'$R_DVU[$^C\OF/'O%!\S,SJL8Y4^$-&Z74/ MLR1'(H)6VDN2WW PB &7V<A'3/F\!!X6`[I$W7FKHJFJR6_[?[R$3RNVS/#< MV0)DJ$VKT^FT[S7R:WFCWAJ3#,[9-6:MN>G8B+:W-L'%JH+%3+K9MWS8*-0P MO0SFLVE06/J[XHC;'H'F!E%$G5M2, VM%=%I>^%B[;E5#X+&X2W7Q =1:!IE M`S SE3:PTM9V>F3UR>H0.NT3_A*9<S,/=:!DY;N7%ZX6WC(RPQ1.D*H/G9X= M,8UM9]-?#VC_(YO\(U!,H;_O1SAZ!0_EQ8_UO.1&?%P8&O*%2%:N%7N0^7T M-:O0-K\'0 R,Q,N_XYB"Q/NAOXJP,3*30C7]J0(W4EW[")%3;AM:[4\S?:'M M<\-$CC#BJ)C*1YNZT#]$+5:58JU2!T%*TV55\5F&=R_C3X2KJ_./;R[?=Z^N M5FZ3OF# U51/9TWD79H&K7TUFZ0QIPWT/XA NPV?[$)8:EP?V[6>8" */EBQ MC&5+UL'MT:/YTNDED,WJFT*MA) 655QNJ8>M86!=XBF--!D=[]9O[T6RL 'Z M/ ?FQ6<#&4M>_&LL>_-8]CX;"R7%PODJ6 ((!VDY'^M U$V?=#7]`ESYT)OK M:!7+E81N[^+-9;=W='QVV.TN7ZL79UM'"9RTPZ^D(__B*G:I#OC+L5?3F78> MN7X3TF(O]>Z:?Y* 5'XZAF$EIVE-\[,7*E%D.]^*RH:W'TNILY+8AM\]MZTT MM>\_YI7SP/WN -Z3!/Q3]H3$) I1\-Q9ZYE-/5U=/IEK<NW_9P5]VP5QU<TN M3X^SI;JXIV8>1OZ4^]Y7X?UXQ,00H91#=S-=?#.80BV5P<*^5?_ \VO(1D0G M& G#/(?]SH\_=+[OP/NFD#IQ!CL[.YO .6WU0 "7WT3^#5!+`P04````" #W MA)LQ(8\F6%$!``!"`P``!P```&AA;F]I+F2-44U+`S$0O2_L?\ 6A 1BH'BS MI[8J'JH(!D^"A&ZJP6RR)-.*E/YWDZ:[V?H]L)MA/MZ;-Z.:UCI _,4Z!N^M MU,K#I"R&X4:"R"$/-0N?LB%4%DLMO$?3[:YS9]F=1[<L0#:M%B#1G5,&;NQ& MXBMG&\HM*8MM6:! 'MQZ";DB10_)5"! +='&JAK)C="8I%Q?ENW-*9 K/(HX MZ$+Y5Q3IT(E'8,/_T8QH%*KJ_1B$ ;V'P/N,21?G=A EDXP?!!V>8VG<">-7 MTG7*Z(,2-&A!!IVC<=8IM!(>\46%>ZE5OPW2PTS^C_\9>]JVTM05[E[6M2:> MV!C[S>F8T)_F(#0KSC9 .H#$AHCTV^27\5A\\13VP,-V%\I#'CF>,U60+Q</ M/>R:I5L/+L!B>85CEI,^L_N>-I#>KK7F?S%F 'V^$<K W),8L_HIG=$Y/2.) M?O<!4$L#!!0````(`"V_F#$S#JG!S0```.,!```)````:&%N;VDN;'-PE5"[ M#L(P#-PK]1].67"'#GP"#['Q!RQ122&B."5I^_TX 39TQ%(BY>Y\/H>NIAT9 M=\W.$E<H"Y"9= =J' =L>N]N#!J\YM :#[534'LY!P5&)5469?%UZ;WEH7ZZ MR8#0>O?$X" " "+50)TC=[3A 5.DU0^9&E9BZ5XIY+WB+_QAV7:_*9:L.<-D M-3 E27M=061>H^X$W%: SH8A+YQWB/CL\5D54B1:W?=&; 3(M:#YMU*O#(\9 MJ$[3_ABWML^VLV.4+K:+=FX3)%W5&U!+`P04````" !&OI Q7]>U9P$!``#Z M`0``" ```&AA;F]I+G!L94^Q;H,P%-R1^ =GPD O5:DZM9.3 2QXRH:0925. MB H8Q5:: 8_O,T\X1?5BO[OSW;V3'4Y*>]OS^C =&Q#YQS9-&)XG<P0E< A/ M%4#M^0$1E+ZD29K\<1#TGVUFXN?6>J-ZXYR^&E[1'>U;I[K6^8C#,W#!H')7 M 7,.LU4W\ 7X)(\(DY[Z8+X=^?LK/"X/\)9 ;[F 70Q?5ZNSRMX-.[?NFUUN MMF<9",B8M_C8-63PI0?;! ]04$ M`ON?VX.$X.5RMD1)B:LRN2V YD6\1[E$ MM2OR%1-P0<S;PNAQ-,,9MX_)$[(-15$'<]<=KTNK.S:QTC7SJF&$#<Q<N1)B M\U]02P,$" ``````BXZ;,0````````````````4```!4:&]R+U!+`P04```` M" `\E9DQ=Q<&-UH!```F`P``"P```%1H;W(O;65T82YDC9#-3 (Q%(7WD\P[ MG+#B5\#H!N("15= 3)P7Z'0NT-!IQ[:#CL9WMT,#& S 9M*<GOO-=]MOQQ$` M)"MMT,,4<W*L,'II6)X+M<1,I(:9*K0V9*S0"I]D=$B:O(7KP>"FYS^WF$A: M6ZIPKU-%FS *G9<RE8)CJG,F5(AV/V5J;;'4<'H4HHG*#(D:],'JH^6EUUIX M.9;EPK!4$E*MUVC,=49&X:'3P92L6*H&_ 1F>BT _0>6>')"+*D=BR_8:'M MKM?%^TKP%1AW)9.R0N&7)#*4(2?'>K_?0RA,XZC=CZ-<9Z6D[<M=U;5QO2^7 MS%H\EU(F<?051]]UZ" O)'.$QS?/;R:#;C)L^>O Q[6RKEY*AGO<8<&DI?&9 M:8R0#,XBG"G_$EY)$G=)55!S6^9=',DP*9CUX:'Z#PI&P? 4;7B9-JF;.ZF] M13<<3 N&N<O, ^*!C9/PX3'\!U!+`P04````" `JCYLQ*%BJIX<"```8!P`` M#0```%1H;W(O=')A:71S+F255,MNVS 0O!OP/ZQS2"7'>:!H+PF"(HE;($"" M!J .`8H>*&ECL::XPI*RZQ;Y]Y*FI I.#*4ZV.3NS.QP^3 ]!<M"6 ,EY;5" MD 92IB5JR&L$2U#KI::UAHS*2BID2.O%>.1XTL*:>&E 7:!/YY[L_BN).5!M MC701> );R%9]!F0+Y+4TZ.DYH='O+)Q'D5.<CD? OJ0 AF.8PSU:43$M6)2E MU NXDRD+W 34"ME(TO ;F4(DRF)X?W;VX=C]?(0KA4N#&[BF5.-J/ J8ASI5 M,H,YE4+J$&J+"NU6LB"P=!Y"5SIGE%[HE_!#D]7.UA,QB+R4+%*%D!(MX>"> M<F0--T=',$<C%_H`' /N:"E!!=.=Y :^L$2#NM6JF"HR+6[FFBFS`D1F:Z'4 M!BI)&I$QAQ*M..[W0VJ8CT?3T_$H-'?;N9.PFQ=^Q17+E; X'OT)Y659$=L` M\VH.].QQ%LM*.2#<FBMFL8F2N.-DI(WUZU1M%B[A22B#^]EP#LGW'P,:ENO7 M)!Y(:HN\QT*7WVNB0P0;TP&9O3Z^IC\QLWMMA'3K8C_?FPC#`:'7?7Q66**V MR:;"EVT52 H#20\T(/!_U- B_%=[^H+?8H;Y;Z+ZM\A-FP>I)Y5L`WT5![TU M-Z17R-;?Q(2Z>"8T/$**D(4TYF )DD_M&]"J[ I$CW$`^!+A"YNT ^LV/<"> MAW5]\]ZL;;GNI/WKU.M:>WLFKA, P_BBG^_.=4"TLSZF.W(!TDP<HH_YALH% M_=9,HJ I%,]ZA\639SNHIE \"P/L<$D< ZG35P_)K2Z0_=Y>"X/=79G!32%5 M/G!W&BI<-N=CLA6)3W9Z.HFV8C$<'L(D(-O0+K11\"[_`E!+`P04````" #D MHIDQ#B=K`JL$``#H(P``#P```%1H;W(O='EP96QI<W0N9,U774_C.!1]1^(_ M7.:I&=*0E,\!C58=NBM6ZK"C';^/3&**11IG$Z<[[(K_OC=VTM*4?)2Z98M, MJ7WON><<1]7AZ./^'N"+/( $^C""KTS2.!&3A$ZG/)K F-\E-'G253.6I%Q$ M\ ]+A-[I^18,7/>DC[].81BRQY0]P1=Q%['9_IZN^9;=A=R'D9A2'NFM<BB- M'E.8")#B4F\-HR!A/ ?Z2?,_4S]#6O=(C 93GM"[D,&=$(_PX:L(6!+!]>$A MC%C*)]$'P X8BT<.H28]AWR"WQ+.4A:56* P%FE99\/?#]Q_`.K+C(;A$\0H MDK&$!3!%._HO_> 1C/;W/A[M[TU%D(5,.>?(IYB%/)57N>8XX3,JV?[>OYH` MG\8BD;HPQ\.B9ZS#'S^D:0H$F\?8/&^ (:<IW&9A2.#F:G6/%'N23>,0)\&8 M11/YT+/TMD+1+U]$J43.LBB!S^ 6S<\%BRK(#S*&RSDG2Y&J ?+ $!S]Z2#O M<XAUU82JZ3="NAI ">)/-A4S- S#"C<;B%7Q[#L+F2_S H/>KW_A96I>-S:Q M;&>.4Y#--[&YT\NY1JX%V*M(5 V2M:"OI#4(T_:LJM+[77&POX2JXN!I*\IF M'BLW-C*UNZ.U`MJ];$9H=[&N__<H8#__N*]0L-4CSO.G^Y5GOVS"X[[7 EC> MRCJ 3N6.X!?L0BRG*)D;;G,X!,^J4E!#AW))DYZ]F)M**KD/-$U9(GMN"T:I MHH#!';?JL2);=*T%5 5R='$IDD,?)38#WXKHNTRX_YID&WZ,V#W-0 F?:YZ. MXKP"UC:LP9O6F=HM,P/;ASD5G"5K[;+;:J4SC&,6!7FSNT0#-[S%Y^KT^3>& MFW]E:(SB,['S5LLJD.L&DO)&<1+4#L+#M7!>]4IMUN+<BE$6I_H:VO6BW/(+ MTM&=A?&6K4XMJP"LF]/"LJ9;$>/!MX1'LI;J3/! J7 UB$AUJH583JRKKA;G MSHOV4MB\X+F9U-N(%"RZ#EG$E_9IY:QEX")JJRN52>9+Q07RV CWB9C"`Z.! MRK"2\E#78 7W:0A9RD GY.*)&-KZ_4OQ?FUK<I:EPNE"!1[CW=\ =/Z (O"K M-ZB"J*I]<5SQKGQ<%!CFTNJ^1B^S:4,^K:!V"9?DY;/R7+FP5:GE71F3G*,X M-W6B'6).]ERR0EY/=B&W5/__OMX.RLBX1]R*"MQLTA"K_S4OJ^2)NZI(F63P MYAH4'1T!S:3H3UC$$L0/((M!"ABX$-.$3IED25H5;A-O>]H=,C[HX0!S\ <U M\E=5V62P=6$XPZ"VXW6TV>1X%_)PC$&%)VLJM,G)CD3B)(,Z3]?7:9/3W4G% M80;5GKU)K4W.=BH8YQG4?/Y6S38YW[5L'&E0^<4&RFUR\0[B<:I!_9\VTV^3 M3^]C`0XVZ(+G;FP#'FTQ=BDKFH>;M,,S8 >N[:>Q% (FTYHW,&8+KIWDN382 M) .?=VS4'ER[RH2M1$RF1N_$N$VX=I LV\F8#)_>Z5;LPK7;A-J!D,D4ZYUM MS39<.\^Z74B9#,3>^5;MP_4>N;D3,9/IVKO8NHVXWBF%=R-G,JQ[FZ?U+HQQ MO5^J[TC09/H?U*3__P!02P$"% `*``````"=CILQ````````````````! `` M`````````! `````````8W!P+U!+`0(4`!0````(`)IFF3&>"X:FI $``+X% M```0````````````( ```"(```!C<' O:&%N;VE?8W0N8W!P4$L!`A0`% `` M`` `R+K4*A,8^JI ` ``.08```X```````````` ````] $``&-P<"].=6QL M5'EP92YH4$L!`A0`% ```` `X+OG,#%:4F N# ``4X(```X```````````` M```` 0``&-P<"]4>7!E3&ES="YH4$L!`A0`% ```` `R+K4*IFQI(4\! `` M;A ```\```````````` ````W!(``&-P<"]4>7!E36%N:7 N:%!+`0(4`!0` M```(`/>$FS$ACR9840$``$(#```'````````````( ```$49``!H86YO:2YD M4$L!`A0`% ```` `+;^8,3,.J<'-````XP$```D```````````` ````NQH` M`&AA;F]I+FQS<%!+`0(4`!0````(`$:^F#%?U[5G`0$``/H!```(```````` M````( ```*\;``!H86YO:2YP;%!+`0(4``H``````(N.FS$````````````` M```%````````````$ ```-8<``!4:&]R+U!+`0(4`!0````(`#R5F3%W%P8W M6 $``"8#```+````````````( ```/D<``!4:&]R+VUE=&$N9%!+`0(4`!0` M```(`"J/FS$H6*JGAP(``! '```-````````````( ```'P>``!4:&]R+W1R M86ET<RYD4$L!`A0`% ```` `Y**9,0XG:P*K! ``Z",```\```````````` L````+B$``%1H;W(O='EP96QI<W0N9%!+!08`````# `,`*L"```&) `````` ` end
Dec 28 2004









"Walter" <newshound digitalmars.com> 