Re: Storing filehandles(for writing) in hashes doesn't work (Re: whilereach my $variable (FILEHANDLE) )

2007-01-16 Thread Mumia W.

On 01/15/2007 11:21 PM, Michael Alipio wrote:

Hi,

Ok, seems like a pet logs is not a good example.:-)

Let me revise my story:

I have a logfile which contains different clients firewall's logs.

Let's say the log file is: firewall.log

Now each line in the logfile has a $deviceid string that identifies where or which client it came from. 
What I did was to list down all of these clients in a file named deviceid.conf. 
Let's say it  contains: ('client_name'  dash  'device_id')


client1 - 293u0sdfj
client2 - 8325kjsdf
client3 - kjldas8282
.
clientn - sdkfj28350


Having said that, my goals are:

1. read the firewall.log line by line.
if it see a particular device_id in $_, and it knows that that deviceid is for this 
particular client (using the information found at deviceid.conf) it will 
write that line into /client1/$date.log or /client2/$date.log etc.

By the way, our logs are being rotated  such that it contains logs from 6:26 yesterday, to 6:25 
today, so $date on the above was obtained by let's say getting the /date=(\S+)/ on the first line 
entry of the log, let's say it reads 2007-01-10, so our $date will be 2007-01-10_11, so 
the logfile for a particular client will be /client1/2007-01-10_11.log


Here is an example of a line in the logfile:

Jan 10 06:26:17 210.23.194.86 date=2007-01-10 
time=06:30:14,devname=sccp_firewall,device_id=FWF60A1234566,log_id=00210100
01,type=traffic,subtype=allowed,pri=notice,vd=root;SN=14435461,duration=139,user=N/A,group=N/A,policyid=11,proto=6,service=7
500/tcp,status=accept,src=192.169.1.70,srcname=192.168.1.3,dst=192.169.1.17,dstname=192.169.1.17,src_int=internal,dst_int
=wan2,sent=144,rcvd=0,sent_pkt=3,rcvd_pkt=0,src_port=2354,dst_port=7500,vpn=N/A,tran_ip=0.0.0.0,tran_port=0,dir_disp=org,tra
n_disp=noop



The device_id in this log entry does not appear in the device id file 
you showed above.





So far, I've been trying to use the code that was given to me but I'm still far 
from my goal:


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

my $logfile='firewall.log';
my $devices='deviceid.conf';
our %log;


##
# 1ST PART
open DEVICES, '', $devices or die Can't open $devices $!;

while ( my $device = DEVICES){
  chomp $device;
  ($device) = $device =~ /(\S+)$/;
  open( my $fh, '', $device.log) or die Can't open $device.log: $!;
  $log{$device} = $fh;
}
close DEVICES;
#

So far I can understand that in the first part, the code will read the 
deviceid.conf and create a file handle for writing for each device id, and 
store these filehandles inside %log. But that is what I wanted to do, I want 
to, as I wanted to write my logs into /clientN/date.log instead of 
client's_deviceid.log. So I'm still trying to figure out this one.


/(\S+)$/ only matches the device-id; the client-id is thrown away. Don't 
throw it away. Create a regular expression that captures the client id 
and use the client-id to create the log file name.





Next:



# 2nd PART

my $re = '^\S+\s+(' . join( '|', keys %log ). ')';

open( IN, '', $logfile ) or die Can't open $logfile: $!;

while( my $line = IN ){
  if( $line =~ m/$re/ ){
print $log{$1} $line;
  }
}


###


The second part is what confuses me, especially the line with my $re, and also the 
if($line =~ m/$re/)

As far as I can understand, the $re will contain a regexp with ('device_id1 | 
device_id2 | device_id3 | device_idN'), so that whenever it sees any pattern 
that match either of those device_ids, it will print it to say $log{device_idN} 
which points to the file handle that writes to device_idN.log.

But this is not the case.
The line print $log{$1} $line; doesn't even work as if it cannot decode the 
$log{$1}



You are correct, my $re creates a regular expression with all of the 
device ids, and you are also correct that print $log{$1} $line does 
not work. You must use print { $log{$1} } $line.




Useless use of a constant in void context at extractdevice.pl line 30.
Scalar found where operator expected at extractdevice.pl line 35, near } $line
(Missing operator before  $line?)
syntax error at extractdevice.pl line 35, near } $line

If I comment those codes inside the while in that second part, the program will 
successfully create emtpy device_id1.log, device_id2.log, etc. etc.)

Any idea what's wrong with this one?




My comments are above.

I wrote the program a completely different way. I think you should read 
'deviceid.conf' and place the device-ids and client-ids into a hash 
($clientids). Then open and start reading the logfile. Whenever you are 
able to capture a device-id that is in the %clientids hash, construct a 
filename to the desired output log file and append the input logfile 
line to that output log file.




--
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
http://learn.perl.org/




Re: Storing filehandles(for writing) in hashes doesn't work (Re: whilereach my $variable (FILEHANDLE) )

2007-01-16 Thread Michael Alipio
Hi,


Ok, here's my code:


my $logfile='firewalllog';
my $devicefile='deviceid';

our %log;

open DEVICES, '', $devicefile or die Can't open $devicefile $!;

while (my $device DEVICES){
  ($device) = $device =~ /(\S+)$/;
  open (my $fh, '', $device..log) or die Can't write to $device..log: $!;
  $log{device} = $fh;
}
close DEVICES;

So I should be able to print to at least {$log{any_device_id}} right??

But using this:

print {$log{FWF60A1234566}} testing;


gives me:

Use of uninitialized value in ref-to-glob cast at extractdevice.pl line 20.
Can't use string () as a symbol ref while strict refs in use at 
extractdevice.pl line 20.

Any idea what does the above means? 




- Original Message 
From: Mumia W. [EMAIL PROTECTED]
To: Beginners List beginners@perl.org
Sent: Tuesday, January 16, 2007 3:13:38 PM
Subject: Re: Storing filehandles(for writing) in hashes doesn't work (Re: 
whilereach my $variable (FILEHANDLE) )

On 01/15/2007 11:21 PM, Michael Alipio wrote:
 Hi,
 
 Ok, seems like a pet logs is not a good example.:-)
 
 Let me revise my story:
 
 I have a logfile which contains different clients firewall's logs.
 
 Let's say the log file is: firewall.log
 
 Now each line in the logfile has a $deviceid string that identifies where or 
 which client it came from. 
 What I did was to list down all of these clients in a file named 
 deviceid.conf. 
 Let's say it  contains: ('client_name'  dash  'device_id')
 
 client1 - 293u0sdfj
 client2 - 8325kjsdf
 client3 - kjldas8282
 .
 clientn - sdkfj28350
 
 
 Having said that, my goals are:
 
 1. read the firewall.log line by line.
 if it see a particular device_id in $_, and it knows that that deviceid 
 is for this particular client (using the information found at 
 deviceid.conf) it will write that line into /client1/$date.log or 
 /client2/$date.log etc.
 
 By the way, our logs are being rotated  such that it contains logs from 6:26 
 yesterday, to 6:25 today, so $date on the above was obtained by let's say 
 getting the /date=(\S+)/ on the first line entry of the log, let's say it 
 reads 2007-01-10, so our $date will be 2007-01-10_11, so the logfile for a 
 particular client will be /client1/2007-01-10_11.log
 
 
 Here is an example of a line in the logfile:
 
 Jan 10 06:26:17 210.23.194.86 date=2007-01-10 
 time=06:30:14,devname=sccp_firewall,device_id=FWF60A1234566,log_id=00210100
 01,type=traffic,subtype=allowed,pri=notice,vd=root;SN=14435461,duration=139,user=N/A,group=N/A,policyid=11,proto=6,service=7
 500/tcp,status=accept,src=192.169.1.70,srcname=192.168.1.3,dst=192.169.1.17,dstname=192.169.1.17,src_int=internal,dst_int
 =wan2,sent=144,rcvd=0,sent_pkt=3,rcvd_pkt=0,src_port=2354,dst_port=7500,vpn=N/A,tran_ip=0.0.0.0,tran_port=0,dir_disp=org,tra
 n_disp=noop
 

The device_id in this log entry does not appear in the device id file 
you showed above.


 
 So far, I've been trying to use the code that was given to me but I'm still 
 far from my goal:
 
 
 #!/usr/bin/perl
 use warnings;
 use strict;
 
 my $logfile='firewall.log';
 my $devices='deviceid.conf';
 our %log;
 
 
 ##
 # 1ST PART
 open DEVICES, '', $devices or die Can't open $devices $!;
 
 while ( my $device = DEVICES){
   chomp $device;
   ($device) = $device =~ /(\S+)$/;
   open( my $fh, '', $device.log) or die Can't open $device.log: $!;
   $log{$device} = $fh;
 }
 close DEVICES;
 #
 
 So far I can understand that in the first part, the code will read the 
 deviceid.conf and create a file handle for writing for each device id, and 
 store these filehandles inside %log. But that is what I wanted to do, I want 
 to, as I wanted to write my logs into /clientN/date.log instead of 
 client's_deviceid.log. So I'm still trying to figure out this one.

/(\S+)$/ only matches the device-id; the client-id is thrown away. Don't 
throw it away. Create a regular expression that captures the client id 
and use the client-id to create the log file name.


 
 Next:
 
 
 
 # 2nd PART
 
 my $re = '^\S+\s+(' . join( '|', keys %log ). ')';
 
 open( IN, '', $logfile ) or die Can't open $logfile: $!;
 
 while( my $line = IN ){
   if( $line =~ m/$re/ ){
 print $log{$1} $line;
   }
 }
 
 
 ###
 
 
 The second part is what confuses me, especially the line with my $re, and 
 also the if($line =~ m/$re/)
 
 As far as I can understand, the $re will contain a regexp with ('device_id1 | 
 device_id2 | device_id3 | device_idN'), so that whenever it sees any pattern 
 that match either of those device_ids, it will print it to say 
 $log{device_idN} which points to the file handle that writes to 
 device_idN.log.
 
 But this is not the case.
 The line print $log{$1} $line; doesn't even work as if it cannot decode the 
 $log{$1}
 

You are correct, my $re creates a regular expression with all of the 
device ids, and you are also correct that print $log{$1} $line does 
not work. You must use print { $log{$1} } $line.


 Useless use of a constant in void

Re: Storing filehandles(for writing) in hashes doesn't work (Re: whilereach my $variable (FILEHANDLE) )

2007-01-16 Thread Mumia W.

On 01/16/2007 04:02 AM, Michael Alipio wrote:

- Original Message 
From: Mumia W. [EMAIL PROTECTED]
To: Beginners List beginners@perl.org
Sent: Tuesday, January 16, 2007 3:13:38 PM
Subject: Re: Storing filehandles(for writing) in hashes doesn't work (Re: whilereach 
my $variable (FILEHANDLE) )

On 01/15/2007 11:21 PM, Michael Alipio wrote:

Hi,

Ok, seems like a pet logs is not a good example.:-)

Let me revise my story:

I have a logfile which contains different clients firewall's logs.

Let's say the log file is: firewall.log

Now each line in the logfile has a $deviceid string that identifies where or which client it came from. 
What I did was to list down all of these clients in a file named deviceid.conf. 
Let's say it  contains: ('client_name'  dash  'device_id')


client1 - 293u0sdfj
client2 - 8325kjsdf
client3 - kjldas8282
.
clientn - sdkfj28350


Having said that, my goals are:

1. read the firewall.log line by line.
if it see a particular device_id in $_, and it knows that that deviceid is for this 
particular client (using the information found at deviceid.conf) it will 
write that line into /client1/$date.log or /client2/$date.log etc.

By the way, our logs are being rotated  such that it contains logs from 6:26 yesterday, to 6:25 
today, so $date on the above was obtained by let's say getting the /date=(\S+)/ on the first line 
entry of the log, let's say it reads 2007-01-10, so our $date will be 2007-01-10_11, so 
the logfile for a particular client will be /client1/2007-01-10_11.log


Here is an example of a line in the logfile:

Jan 10 06:26:17 210.23.194.86 date=2007-01-10 
time=06:30:14,devname=sccp_firewall,device_id=FWF60A1234566,log_id=00210100
01,type=traffic,subtype=allowed,pri=notice,vd=root;SN=14435461,duration=139,user=N/A,group=N/A,policyid=11,proto=6,service=7
500/tcp,status=accept,src=192.169.1.70,srcname=192.168.1.3,dst=192.169.1.17,dstname=192.169.1.17,src_int=internal,dst_int
=wan2,sent=144,rcvd=0,sent_pkt=3,rcvd_pkt=0,src_port=2354,dst_port=7500,vpn=N/A,tran_ip=0.0.0.0,tran_port=0,dir_disp=org,tra
n_disp=noop



The device_id in this log entry does not appear in the device id file 
you showed above.




So far, I've been trying to use the code that was given to me but I'm still far 
from my goal:


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

my $logfile='firewall.log';
my $devices='deviceid.conf';
our %log;


##
# 1ST PART
open DEVICES, '', $devices or die Can't open $devices $!;

while ( my $device = DEVICES){
  chomp $device;
  ($device) = $device =~ /(\S+)$/;
  open( my $fh, '', $device.log) or die Can't open $device.log: $!;
  $log{$device} = $fh;
}
close DEVICES;
#

So far I can understand that in the first part, the code will read the 
deviceid.conf and create a file handle for writing for each device id, and 
store these filehandles inside %log. But that is what I wanted to do, I want 
to, as I wanted to write my logs into /clientN/date.log instead of 
client's_deviceid.log. So I'm still trying to figure out this one.


/(\S+)$/ only matches the device-id; the client-id is thrown away. Don't 
throw it away. Create a regular expression that captures the client id 
and use the client-id to create the log file name.




Next:



# 2nd PART

my $re = '^\S+\s+(' . join( '|', keys %log ). ')';

open( IN, '', $logfile ) or die Can't open $logfile: $!;

while( my $line = IN ){
  if( $line =~ m/$re/ ){
print $log{$1} $line;
  }
}


###


The second part is what confuses me, especially the line with my $re, and also the 
if($line =~ m/$re/)

As far as I can understand, the $re will contain a regexp with ('device_id1 | 
device_id2 | device_id3 | device_idN'), so that whenever it sees any pattern 
that match either of those device_ids, it will print it to say $log{device_idN} 
which points to the file handle that writes to device_idN.log.

But this is not the case.
The line print $log{$1} $line; doesn't even work as if it cannot decode the 
$log{$1}



You are correct, my $re creates a regular expression with all of the 
device ids, and you are also correct that print $log{$1} $line does 
not work. You must use print { $log{$1} } $line.




Useless use of a constant in void context at extractdevice.pl line 30.
Scalar found where operator expected at extractdevice.pl line 35, near } $line
(Missing operator before  $line?)
syntax error at extractdevice.pl line 35, near } $line

If I comment those codes inside the while in that second part, the program will 
successfully create emtpy device_id1.log, device_id2.log, etc. etc.)

Any idea what's wrong with this one?




My comments are above.

I wrote the program a completely different way. I think you should read 
'deviceid.conf' and place the device-ids and client-ids into a hash 
($clientids). Then open and start reading the logfile. Whenever you are 
able to capture a device-id that is in the %clientids hash, construct a 
filename to the desired output

Storing filehandles(for writing) in hashes doesn't work (Re: whilereach my $variable (FILEHANDLE) )

2007-01-15 Thread Michael Alipio
Hi,

Ok, seems like a pet logs is not a good example.:-)

Let me revise my story:

I have a logfile which contains different clients firewall's logs.

Let's say the log file is: firewall.log

Now each line in the logfile has a $deviceid string that identifies where or 
which client it came from.
What I did was to list down all of these clients in a file named 
deviceid.conf.
Let's say it  contains: ('client_name'  dash  'device_id')

client1 - 293u0sdfj
client2 - 8325kjsdf
client3 - kjldas8282
.
clientn - sdkfj28350


Having said that, my goals are:

1. read the firewall.log line by line.
if it see a particular device_id in $_, and it knows that that deviceid is 
for this particular client (using the information found at deviceid.conf) it 
will write that line into /client1/$date.log or /client2/$date.log etc.

By the way, our logs are being rotated  such that it contains logs from 6:26 
yesterday, to 6:25 today, so $date on the above was obtained by let's say 
getting the /date=(\S+)/ on the first line entry of the log, let's say it reads 
2007-01-10, so our $date will be 2007-01-10_11, so the logfile for a 
particular client will be /client1/2007-01-10_11.log


Here is an example of a line in the logfile:

Jan 10 06:26:17 210.23.194.86 date=2007-01-10 
time=06:30:14,devname=sccp_firewall,device_id=FWF60A1234566,log_id=00210100
01,type=traffic,subtype=allowed,pri=notice,vd=root;SN=14435461,duration=139,user=N/A,group=N/A,policyid=11,proto=6,service=7
500/tcp,status=accept,src=192.169.1.70,srcname=192.168.1.3,dst=192.169.1.17,dstname=192.169.1.17,src_int=internal,dst_int
=wan2,sent=144,rcvd=0,sent_pkt=3,rcvd_pkt=0,src_port=2354,dst_port=7500,vpn=N/A,tran_ip=0.0.0.0,tran_port=0,dir_disp=org,tra
n_disp=noop


So far, I've been trying to use the code that was given to me but I'm still far 
from my goal:


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

my $logfile='firewall.log';
my $devices='deviceid.conf';
our %log;


##
# 1ST PART
open DEVICES, '', $devices or die Can't open $devices $!;

while ( my $device = DEVICES){
  chomp $device;
  ($device) = $device =~ /(\S+)$/;
  open( my $fh, '', $device.log) or die Can't open $device.log: $!;
  $log{$device} = $fh;
}
close DEVICES;
#

So far I can understand that in the first part, the code will read the 
deviceid.conf and create a file handle for writing for each device id, and 
store these filehandles inside %log. But that is what I wanted to do, I want 
to, as I wanted to write my logs into /clientN/date.log instead of 
client's_deviceid.log. So I'm still trying to figure out this one.

Next:



# 2nd PART

my $re = '^\S+\s+(' . join( '|', keys %log ). ')';

open( IN, '', $logfile ) or die Can't open $logfile: $!;

while( my $line = IN ){
  if( $line =~ m/$re/ ){
print $log{$1} $line;
  }
}


###


The second part is what confuses me, especially the line with my $re, and 
also the if($line =~ m/$re/)

As far as I can understand, the $re will contain a regexp with ('device_id1 | 
device_id2 | device_id3 | device_idN'), so that whenever it sees any pattern 
that match either of those device_ids, it will print it to say $log{device_idN} 
which points to the file handle that writes to device_idN.log.

But this is not the case.
The line print $log{$1} $line; doesn't even work as if it cannot decode the 
$log{$1}

Useless use of a constant in void context at extractdevice.pl line 30.
Scalar found where operator expected at extractdevice.pl line 35, near } $line
(Missing operator before  $line?)
syntax error at extractdevice.pl line 35, near } $line

If I comment those codes inside the while in that second part, the program will 
successfully create emtpy device_id1.log, device_id2.log, etc. etc.)

Any idea what's wrong with this one?











- Original Message 
From: Thomas Bätzler [EMAIL PROTECTED]
To: Perl Beginners beginners@perl.org
Sent: Monday, January 15, 2007 4:24:02 PM
Subject: RE: whilereach my $variable (FILEHANDLE)  (sort of like foreach 
my $variable (@array)

Hi, 

Michael Alipio [EMAIL PROTECTED] asked:
 I've been thinking about this for quite some time now.
 Suppose I have a text file (mypet.log that contains:
 
 dog
 pig
 cat
 
 Then I have another text file and I want to read it line by 
 line and extract each line that has those contained in the 
 first file. Sort of like running while inside while.
 
 myallpetlogs contains:
 
 blabla dog blah
 blabla cat blah
 blabla dog blah
 blabla pig blah
 blabla cat blah
 blabla pig blah
 
 
 Now, the goal is to have 3 files which contains all extracted 
 lines in myallpetlogs

Assuming that you don't have too many log extracts to create, the easy
way would be to read in mypet.log first and open a new logfile for
each entry using a scalar as the filehandle. That scalar can be stored
in a hash using the pet name as a key.

When reading the logfile you determine the pet name using a regular
expression and write the line to the pets 

RE: Storing filehandles(for writing) in hashes doesn't work (Re: whilereach my $variable (FILEHANDLE) )

2007-01-15 Thread Thomas Bätzler
Hi, 

Michael Alipio [EMAIL PROTECTED] wrote:

 Ok, seems like a pet logs is not a good example.:-)
 
 Let me revise my story:
 
 I have a logfile which contains different clients firewall's logs.
 
 Let's say the log file is: firewall.log
 
 Now each line in the logfile has a $deviceid string that 
 identifies where or which client it came from.
 What I did was to list down all of these clients in a file 
 named deviceid.conf.
 Let's say it  contains: ('client_name'  dash  'device_id')
 
 client1 - 293u0sdfj
 client2 - 8325kjsdf
 client3 - kjldas8282
 .
 clientn - sdkfj28350
 
 
 Having said that, my goals are:
 
 1. read the firewall.log line by line.
 if it see a particular device_id in $_, and it knows that 
 that deviceid is for this particular client (using the 
 information found at deviceid.conf) it will write that line 
 into /client1/$date.log or /client2/$date.log etc.
 
 By the way, our logs are being rotated  such that it contains 
 logs from 6:26 yesterday, to 6:25 today, so $date on the 
 above was obtained by let's say getting the /date=(\S+)/ on 
 the first line entry of the log, let's say it reads 
 2007-01-10, so our $date will be 2007-01-10_11, so the 
 logfile for a particular client will be /client1/2007-01-10_11.log
 
 
 Here is an example of a line in the logfile:
 
 Jan 10 06:26:17 210.23.194.86 date=2007-01-10 
 time=06:30:14,devname=sccp_firewall,device_id=FWF60A1234566,lo
 g_id=00210100
 01,type=traffic,subtype=allowed,pri=notice,vd=root;SN=14435461
 ,duration=139,user=N/A,group=N/A,policyid=11,proto=6,service=7
 500/tcp,status=accept,src=192.169.1.70,srcname=192.168.1.3,dst
 =192.169.1.17,dstname=192.169.1.17,src_int=internal,dst_int
 =wan2,sent=144,rcvd=0,sent_pkt=3,rcvd_pkt=0,src_port=2354,dst_
 port=7500,vpn=N/A,tran_ip=0.0.0.0,tran_port=0,dir_disp=org,tra
 n_disp=noop
 
 
 So far, I've been trying to use the code that was given to me 
 but I'm still far from my goal:
 
 
 #!/usr/bin/perl
 use warnings;
 use strict;
 
 my $logfile='firewall.log';
 my $devices='deviceid.conf';
 our %log;
 
 
 ##
 # 1ST PART
 open DEVICES, '', $devices or die Can't open $devices $!;
 
 while ( my $device = DEVICES){
   chomp $device;
   ($device) = $device =~ /(\S+)$/;
   open( my $fh, '', $device.log) or die Can't open 
 $device.log: $!;
   $log{$device} = $fh;
 }
 close DEVICES;
 #

OK, that is obviously too simple for what you want to do.

use strict;
use warnings;

[...]

open DEVICES, '', $devices or die Can't open $devices $!;

my %log;
my %client;
 
while ( my $line = DEVICES){
   my($clientid, $devid) = ( $line =~ m/^(\S+)\s+-\s+(\S+)/ );
   # store device-id = client-id relationship
   $client{$devid} = $clientid;
   # store device-id = logfile relationship
   # we initialize this with a bogus date and no filehandle
   @($log{$devid}){'date','fh'} = ('1970-01-01', undef);
 }

close DEVICES;

 So far I can understand that in the first part, the code will 
 read the deviceid.conf and create a file handle for writing 
 for each device id, and store these filehandles inside %log. 
 But that is what I wanted to do, I want to, as I wanted to 
 write my logs into /clientN/date.log instead of 
 client's_deviceid.log. So I'm still trying to figure out this one.

Well, you get what you ask for ;-)

The new idea works on the assumption that your logfile is
chronologically sorted. We can then look at each line in turn
and identify the log entry date and the device id for which
the event was logged.

What you then do is this:

- check $log{$devid}{'date'} if the date matches.
  - if it doesn't match, close $log{$devid}{'fh'}
  - open a new logfile named $clientid/$newdate.log;
  - store the new date and handle in $log{$devid}{'date'} and $log{$devid}{'fh'}
- write the log line to $log{$devid}{'fh'}

Writing the code is left as an exercise for the reader ;-)

HTH,
Thomas

--
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
http://learn.perl.org/