[30955] in Perl-Users-Digest

home help back first fref pref prev next nref lref last post

Perl-Users Digest, Issue: 2200 Volume: 11

daemon@ATHENA.MIT.EDU (Perl-Users Digest)
Tue Feb 10 18:09:41 2009

Date: Tue, 10 Feb 2009 15:09:08 -0800 (PST)
From: Perl-Users Digest <Perl-Users-Request@ruby.OCE.ORST.EDU>
To: Perl-Users@ruby.OCE.ORST.EDU (Perl-Users Digest)

Perl-Users Digest           Tue, 10 Feb 2009     Volume: 11 Number: 2200

Today's topics:
    Re: A good data structure to store INI files. <perl@marc-s.de>
    Re: A good data structure to store INI files. sln@netherlands.com
    Re: A good data structure to store INI files. <perl@marc-s.de>
    Re: A good data structure to store INI files. sln@netherlands.com
    Re: A good data structure to store INI files. sln@netherlands.com
    Re: A good data structure to store INI files. <perl@marc-s.de>
    Re: A good data structure to store INI files. <tzz@lifelogs.com>
    Re: A good data structure to store INI files. sln@netherlands.com
    Re: A good data structure to store INI files. sln@netherlands.com
        A problem with TIEHASH [was: A good data structure to s <perl@marc-s.de>
    Re: A problem with TIEHASH [was: A good data structure  sln@netherlands.com
    Re: good email parser ?? <hansmu@xs4all.nl>
        Renaming file - Permission Denied <a_person@anyolddomain.fake>
        Digest Administrivia (Last modified: 6 Apr 01) (Perl-Users-Digest Admin)

----------------------------------------------------------------------

Date: Tue, 10 Feb 2009 20:12:07 +0100
From: Marc Lucksch <perl@marc-s.de>
Subject: Re: A good data structure to store INI files.
Message-Id: <gmsji3$1hvs$1@ariadne.rz.tu-clausthal.de>

Marc Lucksch schrieb:
> Maybe I'm an idiot here, but I can't figure this one out even if my life 
> would depend on it:
Maybe I posted the question wrong, it is not about the INI parsers, I 
just didn't want to release another one...

Lets say I have this data structure, from an ini file, it cares for all 
the conditions that can happen (multiple sections, keys and values)

my $ini={
     Ship=>[
         {#First Ship
             nickname=>[ #A key
                 ['li_elite'] # value
             ],
             fuse=>[ #multikey with multivalue
                 ['intermed_damage_smallship01','0.000000','400'],
                 ['intermed_damage_smallship02','0.000000','200'],

             ], #....
         },{#Second Ship
             nickname=>[
                 ['li_elite2']
             ],fuse=>[
                 ['intermed_damage_smallship01','0.000000','400'],
                 ['intermed_damage_smallship02','0.000000','200'],

             ], #....
         }, #A lot more 'Ships'
     ],Simple=>[
         #A lot of Simples
     ],ship=>[
         # 3 or 4 ships, sometime they are lowercase...
         # That's a problem with this data model,
         # Can't use Hash::Case::Preserve either,
         # cause I would loose which ship's which.
     ],Pilot=>[
         {
             name=>[['pilot_corsair']],
         }#Just one pilot entry
     ],
     # lot more sections....
}

1. Problem:

I can't save the order the sections or keys came in, nor the names of 
them so I can't write an unmodified file out again. I would have to tie 
that structure.
I want to make is easily accessable:

$ini->{Pilot}->{name} instead of:
$ini->{Pilot}->[0]->{name}->[0]->[0].

for (@$ini) {
     #in the order they came in, because a section can affect the
     #following one. As seen in weapon_equip.ini, where [LODsomething.]
     #before [Gun] affects the Gun LODs, I can't mix those up.
}
for (@{$ini->{Ships}}) {
     #Return ships in order of appearance.
}

But I would need overload for that, and I could save it into an array 
for the order and a hash for quick lookup.

But I can't just return a hash with overload, because it wouldn't change 
my array on operations like

delete $ini->{newvalue}; (Change in array missing.
for (0 .. $#{$ini}) {
	delete $ini->[$_] if something($_); #Change in Hash missing.
}
Which one do I trust now, hash or array?

or even

delete $ini->{Pilot};
$ini->{Pilot}=$otherpilot. #Order destroyed.

So I would have to return a tied hash, which gives me a lot of trouble 
with overload again. (See perldoc overload, last section or so)


 ... No solution :( ...

Either I need a better way to save it, or I'm missing something here?

Marc "Maluku" Lucksch


------------------------------

Date: Tue, 10 Feb 2009 19:42:57 GMT
From: sln@netherlands.com
Subject: Re: A good data structure to store INI files.
Message-Id: <eal3p41svouo94qo4m132p07811bmsoh3r@4ax.com>

On Tue, 10 Feb 2009 20:12:07 +0100, Marc Lucksch <perl@marc-s.de> wrote:

>Marc Lucksch schrieb:
>> Maybe I'm an idiot here, but I can't figure this one out even if my life 
>> would depend on it:
>Maybe I posted the question wrong, it is not about the INI parsers, I 
>just didn't want to release another one...
>
>Lets say I have this data structure, from an ini file, it cares for all 
>the conditions that can happen (multiple sections, keys and values)
>
>my $ini={
>     Ship=>[
>         {#First Ship
>             nickname=>[ #A key
>                 ['li_elite'] # value
>             ],
>             fuse=>[ #multikey with multivalue
>                 ['intermed_damage_smallship01','0.000000','400'],
>                 ['intermed_damage_smallship02','0.000000','200'],
>
>             ], #....
>         },{#Second Ship
>             nickname=>[
>                 ['li_elite2']
>             ],fuse=>[
>                 ['intermed_damage_smallship01','0.000000','400'],
>                 ['intermed_damage_smallship02','0.000000','200'],
>
>             ], #....
>         }, #A lot more 'Ships'
>     ],Simple=>[
>         #A lot of Simples
>     ],ship=>[
        ^^^^
Whats this amother ship in the hash?? This won't work, you already have a
ship.
>
>1. Problem:
>
>I can't save the order the sections or keys came in, nor the names of 
>them so I can't write an unmodified file out again. I would have to tie 
>that structure.
>I want to make is easily accessable:
>
Utterly absurd, of course you can. If you want to save the order in
which it exists in the ini file, dups an all, you have to break it up
into compound arrays, this way dup's are irrelavent.

Array's of references of references.
Traversing the array, its up to you to know, based on the tag
when to increment index+=2;

There is no magic bullet, you have a crap structure in an ini file,
deal with it.

my @ini = (

     Ship=>[
         [#First Ship
             nickname=>[ #A key
                 ['li_elite'] # value
             ],
             fuse=>[ #multikey with multivalue
                 ['intermed_damage_smallship01','0.000000','400'],
                 ['intermed_damage_smallship02','0.000000','200'],

             ], #....
         ],
         [#Second Ship
             nickname=>[
                 ['li_elite2']
             ],fuse=>[
                 ['intermed_damage_smallship01','0.000000','400'],
                 ['intermed_damage_smallship02','0.000000','200'],

             ], #....
         ], #A lot more 'Ships'
     ],
     Simple=>[
         #A lot of Simples
     ],
     ship=>[
         # 3 or 4 ships, sometime they are lowercase...
         # That's a problem with this data model,
         # Can't use Hash::Case::Preserve either,
         # cause I would loose which ship's which.
     ],
     Pilot=>[
             name=>[['pilot_corsair']],
         }#Just one pilot entry
     ],
     # lot more sections....
);

-sln



------------------------------

Date: Tue, 10 Feb 2009 20:52:22 +0100
From: Marc Lucksch <perl@marc-s.de>
Subject: Re: A good data structure to store INI files.
Message-Id: <gmslth$1jg4$1@ariadne.rz.tu-clausthal.de>

sln@netherlands.com schrieb:
> On Tue, 10 Feb 2009 20:12:07 +0100, Marc Lucksch <perl@marc-s.de> wrote:
>> 1. Problem:
>>
>> I can't save the order the sections or keys came in, nor the names of 
>> them so I can't write an unmodified file out again. I would have to tie 
>> that structure.
>> I want to make is easily accessable:
>>
> Utterly absurd, of course you can. If you want to save the order in
> which it exists in the ini file, dups an all, you have to break it up
> into compound arrays, this way dup's are irrelavent.
> 
> Array's of references of references.
> Traversing the array, its up to you to know, based on the tag
> when to increment index+=2;
It certainly is the most stable (stable like in sort routines) 
structure, but see below for the problems with it.

> 
> There is no magic bullet, you have a crap structure in an ini file,
> deal with it.

perls carefully designed datastructures of hash, arrays, ties defeated 
by a simple ini file?

> my @ini = (
> 
>      Ship=>[
>          [#First Ship
>              nickname=>[ #A key
>                  ['li_elite'] # value
>              ],
>              fuse=>[ #multikey with multivalue
>                  ['intermed_damage_smallship01','0.000000','400'],
>                  ['intermed_damage_smallship02','0.000000','200'],
> 
>              ], #....
>          ],
>          [#Second Ship
>              nickname=>[
>                  ['li_elite2']
>              ],fuse=>[
>                  ['intermed_damage_smallship01','0.000000','400'],
>                  ['intermed_damage_smallship02','0.000000','200'],
> 
>              ], #....
>          ], #A lot more 'Ships'
>      ],
>      Simple=>[
>          #A lot of Simples
>      ],
>      ship=>[
>          # 3 or 4 ships, sometime they are lowercase...
>          # That's a problem with this data model,
>          # Can't use Hash::Case::Preserve either,
>          # cause I would loose which ship's which.
>      ],
>      Pilot=>[
>              name=>[['pilot_corsair']],
>          }#Just one pilot entry
>      ],
>      # lot more sections....
> );
That's excatly like how I have it now (See last entry in the original 
post), but to access an SHIP section in @ini, I can't just go 
$ini->{Ship}->[1]->{nickname}, I have to do a full scan of the array and 
their keys and some files have about 1000 sections, and that is slow.

Marc "Maluku" Lucksch


------------------------------

Date: Tue, 10 Feb 2009 19:53:51 GMT
From: sln@netherlands.com
Subject: Re: A good data structure to store INI files.
Message-Id: <ecm3p49dnjupg8rfn66mu94qdedv1fp1be@4ax.com>

On Tue, 10 Feb 2009 19:42:57 GMT, sln@netherlands.com wrote:

>On Tue, 10 Feb 2009 20:12:07 +0100, Marc Lucksch <perl@marc-s.de> wrote:
>
>>Marc Lucksch schrieb:
>>> Maybe I'm an idiot here, but I can't figure this one out even if my life 
>>> would depend on it:
>>Maybe I posted the question wrong, it is not about the INI parsers, I 
>>just didn't want to release another one...
>>
>>Lets say I have this data structure, from an ini file, it cares for all 
>>the conditions that can happen (multiple sections, keys and values)
>>
>>my $ini={
>>     Ship=>[
>>         {#First Ship
>>             nickname=>[ #A key
>>                 ['li_elite'] # value
>>             ],
>>             fuse=>[ #multikey with multivalue
>>                 ['intermed_damage_smallship01','0.000000','400'],
>>                 ['intermed_damage_smallship02','0.000000','200'],
>>
>>             ], #....
>>         },{#Second Ship
>>             nickname=>[
>>                 ['li_elite2']
>>             ],fuse=>[
>>                 ['intermed_damage_smallship01','0.000000','400'],
>>                 ['intermed_damage_smallship02','0.000000','200'],
>>
>>             ], #....
>>         }, #A lot more 'Ships'
>>     ],Simple=>[
>>         #A lot of Simples
>>     ],ship=>[
>        ^^^^
>Whats this amother ship in the hash?? This won't work, you already have a
>ship.
>>
>>1. Problem:
>>
>>I can't save the order the sections or keys came in, nor the names of 
>>them so I can't write an unmodified file out again. I would have to tie 
>>that structure.
>>I want to make is easily accessable:
>>
>Utterly absurd, of course you can. If you want to save the order in
>which it exists in the ini file, dups an all, you have to break it up
>into compound arrays, this way dup's are irrelavent.
>
>Array's of references of references.
>Traversing the array, its up to you to know, based on the tag
>when to increment index+=2;
>
>There is no magic bullet, you have a crap structure in an ini file,
>deal with it.
>
>my @ini = (
>
>     Ship=>[
>         [#First Ship
>             nickname=>[ #A key
>                 ['li_elite'] # value
>             ],
>             fuse=>[ #multikey with multivalue
>                 ['intermed_damage_smallship01','0.000000','400'],
>                 ['intermed_damage_smallship02','0.000000','200'],
>
>             ], #....
>         ],
>         [#Second Ship
>             nickname=>[
>                 ['li_elite2']
>             ],fuse=>[
>                 ['intermed_damage_smallship01','0.000000','400'],
>                 ['intermed_damage_smallship02','0.000000','200'],
>
>             ], #....
>         ], #A lot more 'Ships'
>     ],
>     Simple=>[
>         #A lot of Simples
>     ],
>     ship=>[
>         # 3 or 4 ships, sometime they are lowercase...
>         # That's a problem with this data model,
>         # Can't use Hash::Case::Preserve either,
>         # cause I would loose which ship's which.
>     ],
>     Pilot=>[
>             name=>[['pilot_corsair']],
>         }#Just one pilot entry
>     ],
>     # lot more sections....
>);
>
>-sln

The other alternative is where each section and key a hash key
that is an array reference consisting of the order obtained, type and
a value array reference (undef on sections). Sort the orer and print
out the section/key/value.

-sln



------------------------------

Date: Tue, 10 Feb 2009 20:03:01 GMT
From: sln@netherlands.com
Subject: Re: A good data structure to store INI files.
Message-Id: <7an3p4hhdp54vmif3g2gpdd7152isfqle8@4ax.com>

On Tue, 10 Feb 2009 19:53:51 GMT, sln@netherlands.com wrote:

>On Tue, 10 Feb 2009 19:42:57 GMT, sln@netherlands.com wrote:
>
>>On Tue, 10 Feb 2009 20:12:07 +0100, Marc Lucksch <perl@marc-s.de> wrote:
>>
>>>Marc Lucksch schrieb:
>>>> Maybe I'm an idiot here, but I can't figure this one out even if my life 
>>>> would depend on it:
>>>Maybe I posted the question wrong, it is not about the INI parsers, I 
>>>just didn't want to release another one...
>>>
>>>Lets say I have this data structure, from an ini file, it cares for all 
>>>the conditions that can happen (multiple sections, keys and values)
>>>
>>>my $ini={
>>>     Ship=>[
>>>         {#First Ship
>>>             nickname=>[ #A key
>>>                 ['li_elite'] # value
>>>             ],
>>>             fuse=>[ #multikey with multivalue
>>>                 ['intermed_damage_smallship01','0.000000','400'],
>>>                 ['intermed_damage_smallship02','0.000000','200'],
>>>
>>>             ], #....
>>>         },{#Second Ship
>>>             nickname=>[
>>>                 ['li_elite2']
>>>             ],fuse=>[
>>>                 ['intermed_damage_smallship01','0.000000','400'],
>>>                 ['intermed_damage_smallship02','0.000000','200'],
>>>
>>>             ], #....
>>>         }, #A lot more 'Ships'
>>>     ],Simple=>[
>>>         #A lot of Simples
>>>     ],ship=>[
>>        ^^^^
>>Whats this amother ship in the hash?? This won't work, you already have a
>>ship.
>>>
>>>1. Problem:
>>>
>>>I can't save the order the sections or keys came in, nor the names of 
>>>them so I can't write an unmodified file out again. I would have to tie 
>>>that structure.
>>>I want to make is easily accessable:
>>>
>>Utterly absurd, of course you can. If you want to save the order in
>>which it exists in the ini file, dups an all, you have to break it up
>>into compound arrays, this way dup's are irrelavent.
>>
>>Array's of references of references.
>>Traversing the array, its up to you to know, based on the tag
>>when to increment index+=2;
>>
>>There is no magic bullet, you have a crap structure in an ini file,
>>deal with it.
>>
>>my @ini = (
>>
>>     Ship=>[
>>         [#First Ship
>>             nickname=>[ #A key
>>                 ['li_elite'] # value
>>             ],
>>             fuse=>[ #multikey with multivalue
>>                 ['intermed_damage_smallship01','0.000000','400'],
>>                 ['intermed_damage_smallship02','0.000000','200'],
>>
>>             ], #....
>>         ],
>>         [#Second Ship
>>             nickname=>[
>>                 ['li_elite2']
>>             ],fuse=>[
>>                 ['intermed_damage_smallship01','0.000000','400'],
>>                 ['intermed_damage_smallship02','0.000000','200'],
>>
>>             ], #....
>>         ], #A lot more 'Ships'
>>     ],
>>     Simple=>[
>>         #A lot of Simples
>>     ],
>>     ship=>[
>>         # 3 or 4 ships, sometime they are lowercase...
>>         # That's a problem with this data model,
>>         # Can't use Hash::Case::Preserve either,
>>         # cause I would loose which ship's which.
>>     ],
>>     Pilot=>[
>>             name=>[['pilot_corsair']],
>>         }#Just one pilot entry
>>     ],
>>     # lot more sections....
>>);
>>
>>-sln
>
>The other alternative is where each section and key a hash key
>that is an array reference consisting of the order obtained, type and
>a value array reference (undef on sections). Sort the orer and print
>out the section/key/value.
>
>-sln

%ini = {
	section=>[[order,name,key_index],..],
	key=>[[order,name,value_index],..],
	value=>[,,,,]
}

I think this will work.
-sln


------------------------------

Date: Tue, 10 Feb 2009 21:34:36 +0100
From: Marc Lucksch <perl@marc-s.de>
Subject: Re: A good data structure to store INI files.
Message-Id: <gmsoco$1l4u$1@ariadne.rz.tu-clausthal.de>

sln@netherlands.com schrieb:
> On Tue, 10 Feb 2009 19:53:51 GMT, sln@netherlands.com wrote:
> 
>> On Tue, 10 Feb 2009 19:42:57 GMT, sln@netherlands.com wrote:
>> The other alternative is where each section and key a hash key
>> that is an array reference consisting of the order obtained, type and
>> a value array reference (undef on sections). Sort the orer and print
>> out the section/key/value.
>>
>> -sln
> 
> %ini = {
> 	section=>[[order,name,key_index],..],
> 	key=>[[order,name,value_index],..],
> 	value=>[,,,,]
> }
> 
> I think this will work.

Well it is a good idea, but explaining that to potential users might be 
difficult.
The other way includes a lot of objects, saving it as an array and an 
hash for lookup.

while(my ($section,$data)=$ini->each()) {
	while (my ($key,$value)=$data->each()) {
		for my $entr (@$value) {
			...
		}
	}
}
$ini->section("Ship")->key("fuse")->[0]; #First ship, first fuse

$ini->section("Ship",7)->key("fuse",1)->[0];

foreach my $section (@{$ini->sections("Ship"}) {
	$section->setkey("nickname",$section->key("nickname")."_v2");
}

This would work, but it is hard to explain to any users and will scare 
them (like POE does to me). Who wants to read 3 pages of POD just to 
change a single value. :(

foreach my $section (@{$ini->{Ship}}) {
	$section->{nickname}.="_v2";
}

This is shorter but I can't find any way to do it.

Well, I'm going to bed, gotta go to the dentist tomorrow, where there 
will be joy and nice things will happen to me.  Happy thoughts, Happy 
thoughts. No pain. Happy thoughts

Marc "Maluku" Lucksch


------------------------------

Date: Tue, 10 Feb 2009 15:24:48 -0600
From: Ted Zlatanov <tzz@lifelogs.com>
Subject: Re: A good data structure to store INI files.
Message-Id: <86ab8uj87z.fsf@lifelogs.com>

On Tue, 10 Feb 2009 19:40:31 +0100 Marc Lucksch <perl@marc-s.de> wrote: 

ML> Still leaves the problem on how the represent the data, the file is
ML> not only littered with 277 [Ship] entries, but also [collision
ML> group]'s, one [Pilot] and lots of [Simple]'s... The file I put was
ML> just an example. :(

Instead of splitting on [Ship], look for [\w+] and capture that word.

ML> I want for example access the pilot this way: (Nice and easy for any
ML> user of this theoretical module)

ML> print $ini->{Pilot}->{nickname}; #Only one pilot.

Look at how I flatten an array into the first element of the array if
the array has a size of 1.  Same idea at the top level.

ML> + I want to keep the order or otherwise it will confuse diff a lot.

The CPAN IxHash module will do ordered keys IIRC.

ML> The module should help people write scripts to easily extract and
ML> modify data in those files, without exporting them to .inis first.

ML> That might be a problem, since this is neither thats not the only ini
ML> file in there.

ML> There are shiparchs (this one), loadouts, equipments, universes,
ML> systems, bases, markets, asteroids, asteroid_fielf and a lot more
ML> files of those or similiar formats. (A quick search gave me 1000+ ini
ML> files)

ML> And I don't know the keys, lately someone discovered that you can add
ML> an spin = 0.1, 0, 0 to a planet in a system.ini file and the planet
ML> rotates. This was never seen before, maybe because they probably
ML> removed it in the final version. Who knows how many of those are still
ML> in there.

ML> But I need to save them all and store them into a database, to run
ML> queries on it. Well that is working nicely currently as well, but I
ML> was wondering for a better solution to my problem too.

Sound like the format is changing quickly and it's not a standard INI
format.  You should keep your working module as it stands, instead of
trying to squeeze existing modules into something they can't do.  If the
configuration is very flexible and you're feeling adventurous, consider
writing a small data-based DSL to describe your configuration structure,
and make the main parser the interpreter of that DSL.  For example:

my $syntax = [
              Ship  => { multiple => 1, comma_keys => [qw/fuse LODranges/] ... },
              Pilot => { multiple => 0, comma_keys => [] ... }
             ];

my $data = parse($file, $syntax);

This approach works well for parsing structures that mutate quickly.
Perl 6 grammars will actually make this sort of work easier, but in Perl
5 you'd have to use Parse::RecDescent which IMO will not work well for
you.

Ted


------------------------------

Date: Tue, 10 Feb 2009 21:28:11 GMT
From: sln@netherlands.com
Subject: Re: A good data structure to store INI files.
Message-Id: <68r3p4l298sa3h9aheue3h9b5006oao3q4@4ax.com>

On Tue, 10 Feb 2009 21:34:36 +0100, Marc Lucksch <perl@marc-s.de> wrote:

>sln@netherlands.com schrieb:
>> On Tue, 10 Feb 2009 19:53:51 GMT, sln@netherlands.com wrote:
>> 
>>> On Tue, 10 Feb 2009 19:42:57 GMT, sln@netherlands.com wrote:
>>> The other alternative is where each section and key a hash key
>>> that is an array reference consisting of the order obtained, type and
>>> a value array reference (undef on sections). Sort the orer and print
>>> out the section/key/value.
>>>
>>> -sln
>> 
>> %ini = {
>> 	section=>[[order,name,key_index],..],
                   ^^^^
       order is not needed in this case
[snip]
>
>Well it is a good idea, but explaining that to potential users might be 
>difficult.
>The other way includes a lot of objects, saving it as an array and an 
>hash for lookup.
>
>while(my ($section,$data)=$ini->each()) {
>	while (my ($key,$value)=$data->each()) {
>		for my $entr (@$value) {
>			...
>		}
>	}
>}
>$ini->section("Ship")->key("fuse")->[0]; #First ship, first fuse
>
>$ini->section("Ship",7)->key("fuse",1)->[0];
>
>foreach my $section (@{$ini->sections("Ship"}) {
>	$section->setkey("nickname",$section->key("nickname")."_v2");
>}
>
>This would work, but it is hard to explain to any users and will scare 
>them (like POE does to me). Who wants to read 3 pages of POD just to 
>change a single value. :(
>
>foreach my $section (@{$ini->{Ship}}) {
>	$section->{nickname}.="_v2";
>}
>
>This is shorter but I can't find any way to do it.
>
>Well, I'm going to bed, gotta go to the dentist tomorrow, where there 
>will be joy and nice things will happen to me.  Happy thoughts, Happy 
>thoughts. No pain. Happy thoughts
>
>Marc "Maluku" Lucksch

Excuse the below verbosity. There is one other way, a single linked list.
Clean and simple. Below is a generalized double linked list schema based
on a Node, with lots of maybe 'bloated' utility functions you could trim
down.

In your case the Node would contain a single point of Section/Key/Value
but within a linked list, so order is clear and duplictes are no problem.
Access is simple.

See below, its easy to add or insert a node. Its easy to traverse the list.
And the good part is you can rename the functions for the user AND you can
even generate an ini file after the list is edited, ie: insert/remove, clear,
add head tail, etc ...

The Node structure for your ini usage would be of this form. You will have to
adjust the exapmles before "Node Functions" in examples, for data hash change,
not sure, check it out.

I highly recommend this method.
-sln

*******************************************************

sub new_node  # modified (correct below)
{
	my $node = {
		# Node Header
		prev => undef,
		next => undef,
		# Node Data
		data => { section => '',
			  key     => '',
			  value   => ''
		}
	};
	return $node;
}

So, traversal is something like this:
# Traverse the list from the Head, print data
#-
    print "\nTraverse list from Head -\n";
    $curnode = $ListHead;
    while (defined $curnode)
    {
	if (defined $curnode->{data}->{val}) {

		### Use Data Dumper on $curnode->{data}->{val}
	}
	$curnode = $curnode->{next};
    }
    print "sleeping 2 seconds\n";
    sleep(2);



----------------------------
----------------------------
## nodes.pl
## -sln

use strict;
use warnings;

### Exercise List Creation and Destruction,
### the bare minimum.
### ---------------------------------------


# Create a new List with 1,000,000 nodes
#-
    my $ListHead = CreateList();
    my $ListTail = $ListHead;
    my $curnode  = $ListTail;
    $curnode->{data}->{val} = 0;

    print "\nAdding 1,000,000 nodes\n";
    for (my $i=1; $i<1000000; $i++)
    {
	$curnode = CreateTail( $curnode );
	$curnode->{data}->{val} = $i;
	$ListTail = $curnode;
    }
    print "Done, sleeping 5 seconds\n";
    sleep(5);

# Destroy it
#-
    print "\nDestroying List\n";
    DestroyList( $ListHead );
    print "Done\n";


# Create a different List with 1,500,000 nodes
#-
    $ListHead = CreateList();
    $ListTail = $ListHead;
    $curnode  = $ListTail;
    $curnode->{data}->{val} = 0;

    print "\nAdding 1,500,000 nodes\n";
    for (my $i=1; $i<1500000; $i++)
    {
	$curnode = CreateTail( $curnode );
	$curnode->{data}->{val} = $i;
	$ListTail = $curnode;
    }
    print "Done, sleeping 5 seconds\n";
    sleep(5);

# Destroy it
#-
    print "\nDestroying List\n";
    DestroyList( $ListHead );
    print "Done\n";


# Traverse the list from the Head, print data
#-
    print "\nTraverse list from Head -\n";
    $curnode = $ListHead;
    while (defined $curnode)
    {
	if (defined $curnode->{data}->{val}) {
		print "data is: val = $curnode->{data}->{val}\n";
	}
	$curnode = $curnode->{next};
    }
    print "sleeping 2 seconds\n";
    sleep(2);

# Traverse the list from the Tail, print data
#-
    print "\nTraverse list from Tail -\n";
    $curnode = $ListTail;
    while (defined $curnode)
    {
	if (defined $curnode->{data}->{val}) {
		print "data is: val = $curnode->{data}->{val}\n";
	}
	$curnode = $curnode->{prev};
    }

## =================================
## Node Functions
## =================================

# Make a new node
# Parameters- none
# Return    - ref to a new node
# -
sub new_node
{
	my $node = {
		# Node Header
		prev => undef,
		next => undef,
		# Node Data
		data => {val => undef}
	};
	return $node;
}

# Create a new List
# Parameters - None
# Return     - ref to a created List (ListHead)
# -
sub CreateList
{
	return new_node();
}

# Destroy the List given any Node
# Parameters - $Node = any node in the List
# Return     - None
# Notes      - Destructive on all List node's
# -
sub DestroyList
{
	my $Node = shift;
	if (defined $Node)
	{
		TruncateListAfter( $Node );
		TruncateListBefore( $Node );
		undef (%{$Node});
	}
}

# Create a new List Head from the given Node
# Parameters - $Node = find the head from this node, prepend new created head,
#              creates new List if undef
# Return     - ref to a created node (ListHead)
# -
sub CreateHead
{
	my $Node = shift;
	if (defined $Node)
	{
		while (defined $Node->{prev}) {
			$Node = $Node->{prev};
		}
	}
	return CreateHeadAtNode( $Node );
}

# Create a new List Tail from the given Node
# Parameters - $Node = find the tail from this node, append new created tail,
#              creates new List if undef
# Return     - ref to a created node (ListTail)
# Notes      - Destructive on truncated node's
# -
sub CreateTail
{
	my $Node = shift;
	if (defined $Node)
	{
		while (defined $Node->{next}) {
			$Node = $Node->{next};
		}
	}
	return CreateTailAtNode( $Node );
}

# Create a new Head before Node, removes leading node's
# Parameters - $Node = node to prepend new head,
#              creates new List if undef
# Return     - ref to a created node (ListHead)
# -
sub CreateHeadAtNode
{
	my $Node = shift;
	my $ret = undef;
	if (defined $Node)
	{
		my $newnode = new_node();
		if (defined $Node->{prev}) {
			TruncateListBefore( $Node );
		}
		$newnode->{next} = $Node;
		$Node->{prev}    = $newnode;
		$ret = $newnode;
	} else {
		$ret = new_node();
	}
	return $ret;
}

# Create a new Tail after Node, removes trailing node's
# Parameters - $Node = node to append new tail,
#              creates new List if undef
# Return     - ref to a created node (ListTail)
# Notes      - Destructive on truncated node's
# -
sub CreateTailAtNode
{
	my $Node = shift;
	my $ret = undef;
	if (defined $Node)
	{
		my $newnode = new_node();
		if (defined $Node->{next}) {
			TruncateListAfter( $Node );
		}
		$newnode->{prev} = $Node;
		$Node->{next}    = $newnode;
		$ret = $newnode;
	} else {
		$ret = new_node();
	}
	return $ret;
}

# Add the passed in Node to the List as its new Head
# Parameters - $Node = find the head from this node, prepend new head
#            - $NewNode = the new node
# Return     - ref to the added node (ListHead)
# -
sub AddHead
{
	my ($Node, $NewNode) = @_;
	my $ret = undef;
	if (defined $Node && defined $NewNode)
	{
		while (defined $Node->{prev}) {
			$Node = $Node->{prev};
		}
		$ret = AddHeadAtNode( $Node, $NewNode );
	}
	return $ret;
}

# Add the passed in Node to the List as its new Tail
# Parameters - $Node = find the tail from this node, append new tail
#            - $NewNode = the new node
# Return     - ref to the added node (ListTail)
# -
sub AddTail
{
	my ($Node, $NewNode) = @_;
	my $ret = undef;
	if (defined $Node && defined $NewNode)
	{
		while (defined $Node->{next}) {
			$Node = $Node->{next};
		}
		$ret = AddTailAtNode( $Node, $NewNode );
	}
	return $ret;
}

# Add a new Head before Node, removes leading nodes
# Parameters - $Node = node to prepend new head
#            - $NewNode = the new node
# Return     - ref to the added node (ListHead)
# Notes      - Destructive on truncated node's
# -
sub AddHeadAtNode
{
	my ($Node, $NewNode) = @_;
	my $ret = undef;
	if (defined $Node && defined $NewNode)
	{
		my $newnode = $NewNode;
		if (defined $Node->{prev}) {
			TruncateListBefore( $Node );
		}
		$newnode->{next} = $Node;
		$Node->{prev}    = $newnode;
		$ret = $newnode;
	}
	return $ret;
}

# Add a new Tail after Node, removes trailing nodes
# Parameters - $Node = node to append new tail
#            - $NewNode = the new node
# Return     - ref to the added node (ListTail)
# Notes      - Destructive on truncated node's
# -
sub AddTailAtNode
{
	my ($Node, $NewNode) = @_;
	my $ret = undef;
	if (defined $Node && defined $NewNode)
	{
		my $newnode = $NewNode;
		if (defined $Node->{next}) {
			TruncateListAfter( $Node );
		}
		$newnode->{prev} = $Node;
		$Node->{next}    = $newnode;
		$ret = $newnode;
	}
	return $ret;
}

# Truncate a List after a Node (Node is intact)
# Parameters - $Node = node to disconnect from
# Return     - None
# Notes      - Destructive on truncated node's
# -
sub TruncateListAfter
{
	my $Node = shift;
	if (defined $Node)
	{
		my $curnode = $Node->{next};
		while (defined $curnode)
		{
			my $nextnode = $curnode->{next};
			undef (%{$curnode});
			$curnode = $nextnode;
		}
		$Node->{next} = undef;
	}
}

# Truncate a List before a Node (Node is intact)
# Parameters - $Node = node to disconnect from
# Return     - None
# Notes      - Destructive on truncated node's
# -
sub TruncateListBefore
{
	my $Node = shift;
	if (defined $Node)
	{
		my $curnode = $Node->{prev};
		while (defined $curnode)
		{
			my $prevnode = $curnode->{prev};
			undef (%{$curnode});
			$curnode = $prevnode;
		}
		$Node->{prev} = undef;
	}
}

# Create a new node after a node
# Parameters - $Node = node to append to
# Return     - ref to a created node
# -
sub CreateNextNode
{
	my $Node = shift;
	return InsertNextNode( $Node, new_node() );
}

# Create a new node before a node
# Parameters - $Node = node to prepend to
# Return     - ref to a created node
# -
sub CreatePrevNode
{
	my $Node = shift;
	return InsertPrevNode( $Node, new_node() );
}


# Insert a passed in node after a node
# Parameters - $Node = node to append to
#            - $NewNode = the new node
# Return     - ref to the inserted node
# -
sub InsertNextNode
{
	my ($Node, $NewNode) = @_;
	my $ret = undef;
	if (defined $Node && defined $NewNode)
	{
		my $newnode = $NewNode;
		my $nextnode = $Node->{next};

		if (defined $nextnode) {
			$nextnode->{prev} = $newnode;
			$newnode->{next}  = $nextnode;
		}
		$newnode->{prev} = $Node;
		$Node->{next}    = $newnode;
		$ret = $newnode;
	}
	return $ret;
}

# Insert a passed in node before a node
# Parameters - $Node = node to prepend to
#            - $NewNode = the new node
# Return     - ref to the inserted node
# -
sub InsertPrevNode
{
	my ($Node, $NewNode) = @_;
	my $ret = undef;
	if (defined $Node && defined $NewNode)
	{
		my $newnode = $NewNode;
		my $prevnode = $Node->{prev};

		if (defined $prevnode) {
			$prevnode->{next} = $newnode;
			$newnode->{prev}  = $prevnode;
		}
		$newnode->{next} = $Node;
		$Node->{prev}    = $newnode;
		$ret = $newnode;
	}
	return $ret;
}

# Remove node from list
# Parameters - $Node = node ref
# Return     - ref to next node
# Notes      - Destructive on Node
# -
sub RemoveNodeRetNext
{
	my $Node = shift;
	my $ret = undef;
	if (defined $Node)
	{
		my $nextnode = $Node->{next};
		my $prevnode = $Node->{prev};
		undef (%{$Node});

		if (defined $nextnode && defined $prevnode) {
			$nextnode->{prev} = $prevnode;
			$prevnode->{next} = $nextnode;
			$ret = $nextnode;
		} elsif (defined $nextnode) {
			$nextnode->{prev} = undef;
			$ret = $nextnode;
		} elsif (defined $prevnode) {
			$prevnode->{next} = undef;
		}
	}
	return $ret;
}

# Remove node from list
# Parameters - $Node = node ref
# Return     - ref to prev node
# Notes      - Destructive on Node
# -
sub RemoveNodeRetPrev
{
	my $Node = shift;
	my $ret = undef;
	if (defined $Node)
	{
		my $nextnode = $Node->{next};
		my $prevnode = $Node->{prev};
		undef (%{$Node});

		if (defined $nextnode && defined $prevnode) {
			$nextnode->{prev} = $prevnode;
			$prevnode->{next} = $nextnode;
			$ret = $prevnode;
		} elsif (defined $prevnode) {
			$prevnode->{next} = undef;
			$ret = $prevnode;
		} elsif (defined $nextnode) {
			$nextnode->{prev} = undef;
		}
	}
	return $ret;
}
__END__






------------------------------

Date: Tue, 10 Feb 2009 21:40:17 GMT
From: sln@netherlands.com
Subject: Re: A good data structure to store INI files.
Message-Id: <uks3p414bh9g4kko9tgkqipud2auhfk6po@4ax.com>

On Tue, 10 Feb 2009 21:28:11 GMT, sln@netherlands.com wrote:

>On Tue, 10 Feb 2009 21:34:36 +0100, Marc Lucksch <perl@marc-s.de> wrote:
>
>>sln@netherlands.com schrieb:
>>> On Tue, 10 Feb 2009 19:53:51 GMT, sln@netherlands.com wrote:
>>> 
>>>> On Tue, 10 Feb 2009 19:42:57 GMT, sln@netherlands.com wrote:
>>>> The other alternative is where each section and key a hash key
>>>> that is an array reference consisting of the order obtained, type and
>>>> a value array reference (undef on sections). Sort the orer and print
>>>> out the section/key/value.
>>>>
>>>> -sln
>>> 
[snip]
>
>I highly recommend this method.
>-sln
>
>*******************************************************
>
>sub new_node  # modified (correct below)
>{
>	my $node = {
>		# Node Header
>		prev => undef,
>		next => undef,
>		# Node Data
>		data => { section => '',
>			  key     => '',
>			  value   => ''
>		}
>	};
>	return $node;
>}
>

This would be better for you, get rid of 'data' altogether.
You will have to adjust a couple of undef's for the 'data' 
hash in the clear methods in the core though.

sub new_node  # modified ( need to correct below)
{
	my $node = {
		# Node Header
		prev => undef,
		next => undef,
		# Node Data
		section => '',
		key     => '',
		value   => ''
	};
	return $node;
}
To traverse:

# Traverse the list from the Head, print data
#-
    print "\nTraverse list from Head -\n";
    $curnode = $ListHead;
    while (defined $curnode)
    {
	if (defined $curnode->{section}) {
		print "section = ".$curnode->{section}."\n";
		print "key     = ".$curnode->{key}."\n";
		print "value   = ".$curnode->{value}."\n";
	}
	$curnode = $curnode->{next};
    }

-sln



------------------------------

Date: Tue, 10 Feb 2009 20:45:25 +0100
From: Marc Lucksch <perl@marc-s.de>
Subject: A problem with TIEHASH [was: A good data structure to store INI files.]
Message-Id: <gmslgh$1j6u$1@ariadne.rz.tu-clausthal.de>



A little addition why just TIE alone is also a no-go:

Marc Lucksch schrieb:
> $ini->{Pilot}->{name} instead of:
> $ini->{Pilot}->[0]->{name}->[0]->[0].
> 
> for (@$ini) {
>     #in the order they came in, because a section can affect the
>     #following one. As seen in weapon_equip.ini, where [LODsomething.]
>     #before [Gun] affects the Gun LODs, I can't mix those up.
> }

I could just say: Don't care about the shorter $ini->{Pilot}->{name} 
syntax, just let it be $ini->{Pilot}->[0]->{name}->[0]->[0].

And just Tie the first hash into something like Tie::DxHash

But I need the order of keys and sections while I write the file, or 
there the 'user' might need it (reasons above), there are two ways to do 
this (which I see:)

FETCH returns an arrayref of all sections with that name, then you can 
do $ini->{Pilot}->[0]->{name}->[0]->[0].
but:

foreach my $key (%{$ini}) {
	# Now $key can be the same one over and over again.
	# Ship/Ship/Pilot/Ship/ship
	my $value=$ini->{$key}; #arrayref of all sections. But which one
	# did I want, the first? the seventh? I have to count the keys
	# myself.
}
Same with:

while (my ($key,$value) = each(%$ini)) {
}

This is because FETCH gets called with the returnvalue of 
FIRSTKEY/NEXTKEY, there is no way to find out if it was values(), each() 
or $ini->{key}.
And you can't just assume FIRSTKEY/NEXTKEY is followed by FETCH, because 
of keys().

values() is the worst anyway: Data::Dumper would put it this way: 
$VAR1=[[],$VAR1->[0],$VAR1->[0],[name=>['foo']],$VAR1->[0],$VAR1->[0],....]; 


You would need something like this, but it won't work.

sub NEXTKEY {
	my $self=shift;
	$next=$self->get_next($_[0]); # Generate it,
	if (wantarray) { #Called by each()
		$value=$self->get($next)->[self->{count}->{$next}];
		return ($key,$value);
	}
	else { #Called from keys();
		return $next;
	}
}

Second way: FETCH keeps the keycounters inside, for stuff works, but 
that messes up $ini->{Pilot}->[7]->{name}->[0]->[0], because it look 
like this:
$ini->{Pilot} for 1 .. 6;
$ini->{Pilot}->{name}->[0]; #I would use the same tie thing for the keys
			    #as well

You would again need overload for this:

$ini->{Pilot}->[1]->{name}
$ini->{Pilot}->{name} (returns $ini->{Pilot}->[6]->{name}).

But that again won't work because $ini->{Pilot}->[6]->{name} is again a 
tied object and there is that overload bug.

Maybe someone can fix this, at least the wantarray for FISTKEY/NEXTKEY 
on each and values().

Marc "Maluku" Lucksch


------------------------------

Date: Tue, 10 Feb 2009 21:54:52 GMT
From: sln@netherlands.com
Subject: Re: A problem with TIEHASH [was: A good data structure to store INI files.]
Message-Id: <vrt3p4lpo1oppldh633g7ttusehpjq28oq@4ax.com>

On Tue, 10 Feb 2009 20:45:25 +0100, Marc Lucksch <perl@marc-s.de> wrote:

>
>
>A little addition why just TIE alone is also a no-go:
>
[snip]

Holy crap, a nightmare.
-sln


------------------------------

Date: Tue, 10 Feb 2009 23:38:09 +0100
From: Hans Mulder <hansmu@xs4all.nl>
Subject: Re: good email parser ??
Message-Id: <49920318$0$199$e4fe514c@news.xs4all.nl>

Jack wrote:
> On Feb 8, 12:08 pm, "Peter J. Holzer" <hjp-usen...@hjp.at> wrote:
>> On 2009-02-07 23:59, Jack <jack_posem...@yahoo.com> wrote:
>>
>>> Hi I havent had any luck with the CPAN email modules, I just want to
>>> parse multipart and mime and base64, with all the varieties of email
>>> files out there, these modules just dont work...
>> MIME::Parser works for me. It is a bit slow and tends to use ridiculuous
>> amounts of memory if you want to avoid temporary files, but I have yet
>> to find a (syntactically correct) email which can't parse.
>>
>>         hp
> 
> Thanks Peter for the posting.. can you provide some guidance then.. I
> tried the below code and figured the skeleton would report the base64
> image attachments in a MIME message, but isnt picking it up.

The parse() method takes a file handle argument.  So you'll have to
open the file yourself and pass the resulting handle to parse():

use warnings;
use strict;

use MIME::Parser;

my $dir = "e:\\tmp";

if (not -d $dir) {
     mkdir $dir or die "Can't create directory $dir: $!\n";
}

my $filename1 = $ARGV[0] || "no input filename";

### Create a new parser object:
my $parser = new MIME::Parser;

### Tell it where to put things:
$parser->output_under($dir);

### Open the file:
open my $fh, '<', $filename1 or die "Can't read $filename1: $!\n";

### Parse an input filehandle:
my $entity = $parser->parse($fh);

### Congratulations: you now have a (possibly multipart) MIME entity!
$entity->dump_skeleton;
__END__

This prints:

Content-type: multipart/mixed
Effective-type: multipart/mixed
Body-file: NONE
Subject: car for sale two images
Num-parts: 2
--
     Content-type: multipart/alternative
     Effective-type: multipart/alternative
     Body-file: NONE
     Num-parts: 2
     --
         Content-type: text/plain
         Effective-type: text/plain
         Body-file: e:\tmp/msg-1234304022-16083-0/msg-16083-1.txt
         --
         Content-type: text/html
         Effective-type: text/html
         Body-file: e:\tmp/msg-1234304022-16083-0/msg-16083-2.html
         --
     Content-type: image/jpeg
     Effective-type: image/jpeg
     Body-file: e:\tmp/msg-1234304022-16083-0/masertione.jpg
     Recommended-filename: masertione.jpg
     --

> I need
> to be able to deal with text body, base64 body, and image attachments,
> and want to parse them out correctly.  I can do the base64 decoding,
> etc. - 

MIME::Parser will do the base64 decoding for you.

> how do I accomplish this with MIME::Parser ??

Read the documentation carefully:

parse INSTREAM
    Instance method.  Takes a MIME-stream and splits it into its compo-
    nent entities.

    The INSTREAM can be given as a readable FileHandle, an IO::File, a
    globref filehandle (like "\*STDIN"), or as any blessed object con-
    forming to the IO:: interface (which minimally implements getline()
    and read()).

It does not mention the possibility of passing a filename and parse()
opening it on your behalf.  This suggest that this feature does not
exist in this version of MIME::Parser.

Hope this helps,

-- HansM



------------------------------

Date: Tue, 10 Feb 2009 22:32:49 -0000
From: "Bigus" <a_person@anyolddomain.fake>
Subject: Renaming file - Permission Denied
Message-Id: <49920094$0$25635$8d2e0cab@news.newsgroup-binaries.com>

Hi.

I have a script that recurses through a directory tree looking for OTF
fonts. When it finds one it extracts the postscript name and if the filename
is different then it attempts to rename the font file. However, it doesn't
rename the file and returns permission denied.

Strangely though, if I try the rename command stand-alone, ie: outside of
the loop where it runs through the files in the directory, it works. I'm
clutching at straws a bit here but is there some issue with renaming files
in a directory which is currently subject to the opendir command, or is it
something else entirely?

Here's the code:

----------------------------------------------

use strict;
use File::Copy;
use Font::TTF::Font;

recurser();

# -- recurse through 3 levels of folders -- #
sub recurser {

my $fromdir = "e:/software/fonts/";
my $fontext = "otf";

# level 1
opendir D1, $fromdir;
while( my $font1 = readdir(D1) ){
     next if $font1 =~ /^\.+$/;
     if(-d $fromdir.$font1){
         # level 2
         opendir D2, $fromdir.$font1;
         while( my $font2 = readdir(D2) ){
                next if $font2 =~ /^\.+$/;
                # level 3
                if(-d $fromdir.$font1.'/'.$font2){
                     opendir D3, $fromdir.$font1.'/'.$font2;
                     while( my $font3 = readdir(D3) ){
                           next if $font3 !~ /$fontext$/i;
                           renamefont
($fromdir.$font1.'/'.$font2.'/',$font3,$fontext);
                     }
                     closedir D3;
                 }
                 next if $font2 !~ /$fontext$/i;
                 renamefont ($fromdir.$font1.'/',$font2,$fontext);
           }
           closedir D2;
      }
      next if $font1 !~ /$fontext$/i;
      renamefont ($fromdir,$font1,$fontext);
}
closedir D1;

}

# -- rename font -- ##

sub renamefont {

my($fontdir,$font,$ext) = @_;

my $f = Font::TTF::Font->open($fontdir.$font);
my $t = $f->{name}->read;
my $psname = $t->{strings}[6][1][0]{0};

if($psname =~ /\w+/ and $psname !~ /\s+/){
      my $newfontname = $psname.'.'.$ext;
      if($newfontname ne $font){
           rename $fontdir.$font, $fontdir.$newfontname or
                   print 'rename '.$fontdir.$font.',
'.$fontdir.$newfontname.' failed<br>';
      }
}

}

----------------------------------------------

As mentioned above if I just take the output from the failed rename command
in the above loop and run that on it's own, eg:

use strict;
rename "e:/software/fonts/M/MyriadPro-BlackSemiExt_____.otf",
"e:/software/fonts/M/MyriadPro-BlackSemiExt.otf";

it works.

Could someone tell me what's going wrong?

Thanks
Bigus



-----------------
www.Newsgroup-Binaries.com - *Completion*Retention*Speed*
Access your favorite newsgroups from home or on the road
-----------------


------------------------------

Date: 6 Apr 2001 21:33:47 GMT (Last modified)
From: Perl-Users-Request@ruby.oce.orst.edu (Perl-Users-Digest Admin) 
Subject: Digest Administrivia (Last modified: 6 Apr 01)
Message-Id: <null>


Administrivia:

#The Perl-Users Digest is a retransmission of the USENET newsgroup
#comp.lang.perl.misc.  For subscription or unsubscription requests, send
#the single line:
#
#	subscribe perl-users
#or:
#	unsubscribe perl-users
#
#to almanac@ruby.oce.orst.edu.  

NOTE: due to the current flood of worm email banging on ruby, the smtp
server on ruby has been shut off until further notice. 

To submit articles to comp.lang.perl.announce, send your article to
clpa@perl.com.

#To request back copies (available for a week or so), send your request
#to almanac@ruby.oce.orst.edu with the command "send perl-users x.y",
#where x is the volume number and y is the issue number.

#For other requests pertaining to the digest, send mail to
#perl-users-request@ruby.oce.orst.edu. Do not waste your time or mine
#sending perl questions to the -request address, I don't have time to
#answer them even if I did know the answer.


------------------------------
End of Perl-Users Digest V11 Issue 2200
***************************************


home help back first fref pref prev next nref lref last post