~ubuntu-branches/ubuntu/oneiric/latexml/oneiric

« back to all changes in this revision

Viewing changes to lib/LaTeXML/Global.pm

  • Committer: Bazaar Package Importer
  • Author(s): Atsuhito KOHDA
  • Date: 2010-06-09 08:15:06 UTC
  • Revision ID: james.westby@ubuntu.com-20100609081506-1asj0n4u3w4q6jem
Tags: upstream-0.7.0
ImportĀ upstreamĀ versionĀ 0.7.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# /=====================================================================\ #
 
2
# |  LaTeXML::Global                                                    | #
 
3
# | Global constants, accessors and constructors                        | #
 
4
# |=====================================================================| #
 
5
# | Part of LaTeXML:                                                    | #
 
6
# |  Public domain software, produced as part of work done by the       | #
 
7
# |  United States Government & not subject to copyright in the US.     | #
 
8
# |---------------------------------------------------------------------| #
 
9
# | Bruce Miller <bruce.miller@nist.gov>                        #_#     | #
 
10
# | http://dlmf.nist.gov/LaTeXML/                              (o o)    | #
 
11
# \=========================================================ooo==U==ooo=/ #
 
12
 
 
13
#======================================================================
 
14
#  This module collects all the commonly useful constants and constructors
 
15
# that other modules and package implementations are likely to need.
 
16
# This should be used in a context where presumably all the required
 
17
# LaTeXML modules that implement the various classes have already been loaded.
 
18
#
 
19
# Yes, a lot of stuff is exported, polluting your namespace.
 
20
# Thus, you use this module only if you _need_ the functionality!
 
21
#======================================================================
 
22
package LaTeXML::Global;
 
23
use strict;
 
24
use LaTeXML::Common::XML;
 
25
use Time::HiRes;
 
26
 
 
27
use base qw(Exporter);
 
28
our  @EXPORT = ( 
 
29
               # Global STATE; This gets bound by LaTeXML.pm
 
30
               qw( *STATE),
 
31
               # Catcode constants
 
32
               qw( CC_ESCAPE  CC_BEGIN  CC_END     CC_MATH
 
33
                   CC_ALIGN   CC_EOL    CC_PARAM   CC_SUPER
 
34
                   CC_SUB     CC_IGNORE CC_SPACE   CC_LETTER
 
35
                   CC_OTHER   CC_ACTIVE CC_COMMENT CC_INVALID
 
36
                   CC_CS      CC_NOTEXPANDED ),
 
37
               # Token constructors
 
38
               qw( &T_BEGIN &T_END &T_MATH &T_ALIGN &T_PARAM &T_SUB &T_SUPER &T_SPACE 
 
39
                   &T_LETTER &T_OTHER &T_ACTIVE &T_COMMENT &T_CS
 
40
                   &T_CR
 
41
                   &Token &Tokens
 
42
                   &Tokenize &TokenizeInternal &Explode &UnTeX
 
43
                   &StartSemiverbatim &EndSemiverbatim),
 
44
               # Number & Dimension constructors
 
45
               qw( &Number &Float &Dimension &MuDimension &Glue &MuGlue &Pair &PairList),
 
46
               # Error & Progress reporting
 
47
               qw( &NoteProgress &NoteBegin &NoteEnd &Fatal &Error &Warn &Info),
 
48
               # And some generics
 
49
               qw(&Stringify &ToString  &Equals),
 
50
               # And, anything exported from LaTeXML::Common::XML
 
51
               @LaTeXML::Common::XML::EXPORT
 
52
);
 
53
 
 
54
#======================================================================
 
55
# Catcodes & Standard Token constructors.
 
56
#  CC_whatever names the catcode numbers
 
57
#  T_whatever creates a token with the corresponding catcode, 
 
58
#   some take a string argument, if they don't have a `standard' character.
 
59
 
 
60
use constant CC_ESCAPE  =>  0;
 
61
use constant CC_BEGIN   =>  1;
 
62
use constant CC_END     =>  2;
 
63
use constant CC_MATH    =>  3;
 
64
use constant CC_ALIGN   =>  4;
 
65
use constant CC_EOL     =>  5;
 
66
use constant CC_PARAM   =>  6;
 
67
use constant CC_SUPER   =>  7;
 
68
use constant CC_SUB     =>  8;
 
69
use constant CC_IGNORE  =>  9;
 
70
use constant CC_SPACE   => 10;
 
71
use constant CC_LETTER  => 11;
 
72
use constant CC_OTHER   => 12;
 
73
use constant CC_ACTIVE  => 13;
 
74
use constant CC_COMMENT => 14;
 
75
use constant CC_INVALID => 15;  
 
76
# Extended Catcodes for expanded output.
 
77
use constant CC_CS      => 16;
 
78
use constant CC_NOTEXPANDED => 17;
 
79
# Can use constants here; they should never be modified.
 
80
our $CONSTANT_T_BEGIN = bless ['{',   1], 'LaTeXML::Token';
 
81
our $CONSTANT_T_END   = bless ['}',   2], 'LaTeXML::Token';
 
82
our $CONSTANT_T_MATH  = bless ['$',   3], 'LaTeXML::Token';
 
83
our $CONSTANT_T_ALIGN = bless ['&',   4], 'LaTeXML::Token';
 
84
our $CONSTANT_T_PARAM = bless ['#',   6], 'LaTeXML::Token';
 
85
our $CONSTANT_T_SUPER = bless ['^',   7], 'LaTeXML::Token';
 
86
our $CONSTANT_T_SUB   = bless ['_',   8], 'LaTeXML::Token';
 
87
our $CONSTANT_T_SPACE = bless [' ',  10], 'LaTeXML::Token';
 
88
our $CONSTANT_T_CR    = bless ["\n", 10], 'LaTeXML::Token';
 
89
 
 
90
# Too bad we can't REALLY get inlining here...
 
91
sub T_BEGIN() { $CONSTANT_T_BEGIN; }
 
92
sub T_END()   { $CONSTANT_T_END; }
 
93
sub T_MATH()  { $CONSTANT_T_MATH; }
 
94
sub T_ALIGN() { $CONSTANT_T_ALIGN; }
 
95
sub T_PARAM() { $CONSTANT_T_PARAM; }
 
96
sub T_SUPER() { $CONSTANT_T_SUPER; }
 
97
sub T_SUB()   { $CONSTANT_T_SUB; }
 
98
sub T_SPACE() { $CONSTANT_T_SPACE; }
 
99
sub T_CR()    { $CONSTANT_T_CR; }
 
100
sub T_LETTER  { bless [$_[0],11], 'LaTeXML::Token'; }
 
101
sub T_OTHER   { bless [$_[0],12], 'LaTeXML::Token'; }
 
102
sub T_ACTIVE  { bless [$_[0],13], 'LaTeXML::Token'; }
 
103
sub T_COMMENT { bless ['%'.($_[0]||''),14], 'LaTeXML::Token'; }
 
104
sub T_CS      { bless [$_[0],16], 'LaTeXML::Token'; }
 
105
 
 
106
sub Token {
 
107
  my($string,$cc)=@_;
 
108
  bless [$string,(defined $cc ? $cc : CC_OTHER)], 'LaTeXML::Token'; }
 
109
 
 
110
#======================================================================
 
111
# These belong to Mouth, but make more sense here.
 
112
 
 
113
# WARNING: These two utilities bind $STATE to simple State objects with known fixed catcodes.
 
114
# The State normally contains ALL the bindings, etc and links to other important objects.
 
115
# We CAN do that here, since we are ONLY tokenizing from a new Mouth, bypassing stomach & gullet.
 
116
# However, be careful with any changes.
 
117
 
 
118
our $STD_CATTABLE;
 
119
our $STY_CATTABLE;
 
120
 
 
121
# Tokenize($string); Tokenizes the string using the standard cattable, returning a LaTeXML::Tokens
 
122
sub Tokenize         {
 
123
  my($string)=@_;
 
124
  $STD_CATTABLE = LaTeXML::State->new(catcodes=>'standard') unless $STD_CATTABLE;
 
125
  local $LaTeXML::STATE = $STD_CATTABLE;
 
126
  LaTeXML::Mouth->new($string)->readTokens; }
 
127
 
 
128
# TokenizeInternal($string); Tokenizes the string using the internal cattable, returning a LaTeXML::Tokens
 
129
sub TokenizeInternal { 
 
130
  my($string)=@_;
 
131
  $STY_CATTABLE = LaTeXML::State->new(catcodes=>'style') unless  $STY_CATTABLE;
 
132
  local $LaTeXML::STATE = $STY_CATTABLE;
 
133
  LaTeXML::Mouth->new($string)->readTokens; }
 
134
 
 
135
sub StartSemiverbatim() {
 
136
  $LaTeXML::STATE->pushFrame;
 
137
  # include space!
 
138
  map($LaTeXML::STATE->assignCatcode($_=>CC_OTHER,'local'),'^','_','@','~','&','$','#','%',"'",' ');
 
139
  $LaTeXML::STATE->assignCatcode('math:\''=>0,'local');
 
140
  return; }
 
141
 
 
142
sub EndSemiverbatim() {  $LaTeXML::STATE->popFrame; }
 
143
 
 
144
#======================================================================
 
145
# Token List constructors.
 
146
 
 
147
# Return a LaTeXML::Tokens made from the arguments (tokens)
 
148
sub Tokens {
 
149
  my(@tokens)=@_;
 
150
  # Flatten any Tokens to Token's
 
151
  @tokens = map( ( (((ref $_)||'') eq 'LaTeXML::Tokens') ? $_->unlist : $_), @tokens);
 
152
  # And complain about any remaining Non-Token's
 
153
  map( ((ref $_) && $_->isaToken)|| Fatal(":misdefined:<unknown> Expected Token, got ".Stringify($_)), @tokens);
 
154
  LaTeXML::Tokens->new(@tokens); }
 
155
 
 
156
# Explode a string into a list of tokens w/catcode OTHER (except space).
 
157
sub Explode {
 
158
  my($string)=@_;
 
159
  map(($_ eq ' ' ? T_SPACE() : T_OTHER($_)),split('',$string)); }
 
160
 
 
161
sub UnTeX {
 
162
  my($thing)=@_;
 
163
  (defined $thing ? ToString(Tokens(ref $thing ? $thing->revert : Explode($thing))) : undef); }
 
164
 
 
165
#======================================================================
 
166
# Constructors for number and dimension types.
 
167
 
 
168
sub Number      { LaTeXML::Number->new(@_); }
 
169
sub Float       { LaTeXML::Float->new(@_); }
 
170
sub Dimension   { LaTeXML::Dimension->new(@_); }
 
171
sub MuDimension { LaTeXML::MuDimension->new(@_); }
 
172
sub Glue        { LaTeXML::Glue->new(@_); }
 
173
sub MuGlue      { LaTeXML::MuGlue->new(@_); }
 
174
sub Pair        { LaTeXML::Pair->new(@_); }
 
175
sub PairList    { LaTeXML::PairList->new(@_); }
 
176
#**********************************************************************
 
177
# Error & Progress reporting.
 
178
 
 
179
 
 
180
sub NoteProgress { 
 
181
  print STDERR @_ if $LaTeXML::Global::STATE->lookupValue('VERBOSITY') >= 0;
 
182
  return; }
 
183
 
 
184
our %note_timers=();
 
185
sub NoteBegin {
 
186
  my($state)=@_;
 
187
  $note_timers{$state}=[Time::HiRes::gettimeofday];
 
188
  print STDERR "\n($state..." if $LaTeXML::Global::STATE->lookupValue('VERBOSITY') >= 0; }
 
189
 
 
190
sub NoteEnd {
 
191
  my($state)=@_;
 
192
  if(my $start = $note_timers{$state}){
 
193
    my $elapsed = Time::HiRes::tv_interval($start,[Time::HiRes::gettimeofday]);
 
194
    undef $note_timers{$state};
 
195
    print STDERR sprintf(" %.2f sec)",$elapsed) if $LaTeXML::Global::STATE->lookupValue('VERBOSITY') >= 0; }}
 
196
 
 
197
sub Fatal { 
 
198
  my($message)=@_;
 
199
  if(!$LaTeXML::Error::InHandler && defined($^S)){
 
200
    $LaTeXML::Global::STATE->noteStatus('fatal');
 
201
    $message
 
202
      = LaTeXML::Error::generateMessage("Fatal",$message,1,
 
203
                       ($LaTeXML::Global::STATE->lookupValue('VERBOSITY') > 0
 
204
                        ? ("Stack Trace:",LaTeXML::Error::stacktrace()):()));
 
205
  }
 
206
  local $LaTeXML::Error::InHandler=1;
 
207
  die $message; 
 
208
  return; }
 
209
 
 
210
# Note that "100" is hardwired into TeX, The Program!!!
 
211
our $MAXERRORS=100;
 
212
 
 
213
# Should be fatal if strict is set, else warn.
 
214
sub Error {
 
215
  my($msg)=@_;
 
216
  if($LaTeXML::Global::STATE->lookupValue('STRICT')){
 
217
    Fatal($msg); }
 
218
  else {
 
219
    $LaTeXML::Global::STATE->noteStatus('error');
 
220
    print STDERR LaTeXML::Error::generateMessage("Error",$msg,1,"Continuing... Expect trouble.\n")
 
221
      unless $LaTeXML::Global::STATE->lookupValue('VERBOSITY') < -2; }
 
222
  if(($LaTeXML::Global::STATE->getStatus('error')||0) > $MAXERRORS){
 
223
    Fatal(":too_many:$MAXERRORS Too many errors!"); }
 
224
  return; }
 
225
 
 
226
# Warning message; results may be OK, but somewhat unlikely
 
227
sub Warn {
 
228
  my($msg)=@_;
 
229
  $LaTeXML::Global::STATE->noteStatus('warning');
 
230
  print STDERR LaTeXML::Error::generateMessage("Warning",$msg,0)
 
231
    unless $LaTeXML::Global::STATE->lookupValue('VERBOSITY') < -1; 
 
232
  return; }
 
233
 
 
234
# Informational message; results likely unaffected
 
235
# but the message may give clues about subsequent warnings or errors
 
236
sub Info {
 
237
  my($msg)=@_;
 
238
  $LaTeXML::Global::STATE->noteStatus('info');
 
239
  print STDERR LaTeXML::Error::generateMessage("Info",$msg,0)
 
240
    unless $LaTeXML::Global::STATE->lookupValue('VERBOSITY') < -1; 
 
241
  return; }
 
242
 
 
243
#**********************************************************************
 
244
# Generic functions
 
245
our %NOBLESS= map(($_=>1), qw( SCALAR HASH ARRAY CODE REF GLOB LVALUE));
 
246
 
 
247
sub Stringify {
 
248
  my($object)=@_;
 
249
  if(!defined $object){ 'undef'; }
 
250
  elsif(!ref $object){ $object; }
 
251
  elsif($NOBLESS{ref $object}){ "$object"; }
 
252
  elsif($object->can('stringify')){ $object->stringify; }
 
253
  # Have to handle LibXML stuff explicitly (unless we want to add methods...?)
 
254
  elsif($object->isa('XML::LibXML::Node')){
 
255
    if($object->nodeType == XML_ELEMENT_NODE){ 
 
256
      my $tag = $LaTeXML::Global::STATE->getModel->getNodeQName($object);
 
257
      my $attributes ='';
 
258
      foreach my $attr ($object->attributes){
 
259
        my $name = $attr->nodeName;
 
260
        next if $name =~ /^_/;
 
261
        my $val = $attr->getData;
 
262
        $val = substr($val,0,30)."..." if length($val)>35;
 
263
        $attributes .= ' '. $name. "=\"".$val."\""; }
 
264
      "<".$tag.$attributes. ($object->hasChildNodes ? ">..." : "/>");
 
265
    }
 
266
    elsif($object->nodeType == XML_TEXT_NODE){
 
267
      "XMLText[".$object->data."]"; }
 
268
    elsif($object->nodeType == XML_DOCUMENT_NODE){
 
269
      "XMLDocument[".$$object."]"; }
 
270
    else { "$object"; }}
 
271
  else { "$object"; }}
 
272
 
 
273
sub ToString {
 
274
  my($object)=@_;
 
275
  (defined $object ? (((ref $object) && !$NOBLESS{ref $object}) ? $object->toString : "$object"):''); }
 
276
 
 
277
# Just how deep of an equality test should this be?
 
278
sub Equals {
 
279
  my($a,$b)=@_;
 
280
  return 1 if !(defined $a) && !(defined $b); # both undefined, equal, I guess
 
281
  return 0 unless (defined $a) && (defined $b); # else both must be defined
 
282
  my $refa = (ref $a) || '_notype_';
 
283
  my $refb = (ref $b) || '_notype_';
 
284
  return 0 if $refa ne $refb;                                   # same type?
 
285
  return $a eq $b if ($refa eq '_notype_') || $NOBLESS{$refa}; # Deep comparison of builtins?
 
286
  return 1 if $a->equals($b);                                   # semi-shallow comparison?
 
287
  # Special cases? (should be methods, but that embeds State knowledge too low)
 
288
  if($refa eq 'LaTeXML::Token'){ # Check if they've been \let to the same defn.
 
289
    my $defa = $LaTeXML::Global::STATE->lookupDefinition($a);
 
290
    my $defb = $LaTeXML::Global::STATE->lookupDefinition($b);
 
291
    return $defa && $defb && ($defa eq $defb); }
 
292
  return 0; }
 
293
 
 
294
#    && ( ((ref $a) && (ref $b) && ((ref $a) eq (ref $b)) && !$NOBLESS{ref $a})
 
295
#        ? $a->equals($b) : ($a eq $b)); }
 
296
 
 
297
#**********************************************************************
 
298
1;
 
299
 
 
300
__END__
 
301
 
 
302
=pod 
 
303
 
 
304
=head1 NAME
 
305
 
 
306
C<LaTeXML::Global> - global exports used within LaTeXML, and in Packages.
 
307
 
 
308
=head1 SYNOPSIS
 
309
 
 
310
use LaTeXML::Global;
 
311
 
 
312
=head1 DESCRIPTION
 
313
 
 
314
This module exports the various constants and constructors that are useful
 
315
throughout LaTeXML, and in Package implementations.
 
316
 
 
317
=head2 Global state
 
318
 
 
319
=over 4
 
320
 
 
321
=item C<< $STATE; >>
 
322
 
 
323
This is bound to the currently active L<LaTeXML::State> by an instance
 
324
of L<LaTeXML> during processing.
 
325
 
 
326
=back 
 
327
 
 
328
=head2 Tokens
 
329
 
 
330
=over 4
 
331
 
 
332
=item C<< $catcode = CC_ESCAPE; >>
 
333
 
 
334
Constants for the category codes:
 
335
 
 
336
  CC_BEGIN, CC_END, CC_MATH, CC_ALIGN, CC_EOL,
 
337
  CC_PARAM, CC_SUPER, CC_SUB, CC_IGNORE,
 
338
  CC_SPACE, CC_LETTER, CC_OTHER, CC_ACTIVE,
 
339
  CC_COMMENT, CC_INVALID, CC_CS, CC_NOTEXPANDED.
 
340
 
 
341
[The last 2 are (apparent) extensions,
 
342
with catcodes 16 and 17, respectively].
 
343
 
 
344
=item C<< $token = Token($string,$cc); >>
 
345
 
 
346
Creates a L<LaTeXML::Token> with the given content and catcode.
 
347
The following shorthand versions are also exported for convenience:
 
348
 
 
349
  T_BEGIN, T_END, T_MATH, T_ALIGN, T_PARAM,
 
350
  T_SUB, T_SUPER, T_SPACE, T_LETTER($letter),
 
351
  T_OTHER($char), T_ACTIVE($char),
 
352
  T_COMMENT($comment), T_CS($cs)
 
353
 
 
354
=item C<< $tokens = Tokens(@token); >>
 
355
 
 
356
Creates a L<LaTeXML::Tokens> from a list of L<LaTeXML::Token>'s
 
357
 
 
358
=item C<< $tokens = Tokenize($string); >>
 
359
 
 
360
Tokenizes the C<$string> according to the standard cattable, returning a L<LaTeXML::Tokens>.
 
361
 
 
362
=item C<< $tokens = TokenizeInternal($string); >>
 
363
 
 
364
Tokenizes the C<$string> according to the internal cattable (where @ is a letter),
 
365
returning a L<LaTeXML::Tokens>.
 
366
 
 
367
=item C<< @tokens = Explode($string); >>
 
368
 
 
369
Returns a list of the tokens corresponding to the characters in C<$string>.
 
370
 
 
371
=item C<< StartSemiVerbatim(); ... ; EndSemiVerbatim(); >>
 
372
 
 
373
Desable disable most TeX catcodes.
 
374
 
 
375
=back
 
376
 
 
377
=head2 Numbers, etc.
 
378
 
 
379
=over 4
 
380
 
 
381
=item C<< $number = Number($num); >>
 
382
 
 
383
Creates a Number object representing C<$num>.
 
384
 
 
385
=item C<< $number = Float($num); >>
 
386
 
 
387
Creates a floating point object representing C<$num>;
 
388
This is not part of TeX, but useful.
 
389
 
 
390
=item C<< $dimension = Dimension($dim); >>
 
391
 
 
392
Creates a Dimension object.  C<$num> can be a string with the number and units
 
393
(with any of the usual TeX recognized units), or just a number standing for
 
394
scaled points (sp).
 
395
 
 
396
=item C<< $mudimension = MuDimension($dim); >>
 
397
 
 
398
Creates a MuDimension object; similar to Dimension.
 
399
 
 
400
=item C<< $glue = Glue($gluespec); >>
 
401
 
 
402
=item C<< $glue = Glue($sp,$plus,$pfill,$minus,$mfill); >>
 
403
 
 
404
Creates a Glue object.  C<$gluespec> can be a string in the
 
405
form that TeX recognizes (number units optional plus and minus parts).
 
406
Alternatively, the dimension, plus and minus parts can be given separately:
 
407
C<$pfill> and C<$mfill> are 0 (when the C<$plus> or C<$minus> part is in sp)
 
408
or 1,2,3 for fil, fill or filll.
 
409
 
 
410
=item C<< $glue = MuGlue($gluespec); >>
 
411
 
 
412
=item C<< $glue = MuGlue($sp,$plus,$pfill,$minus,$mfill); >>
 
413
 
 
414
Creates a MuGlue object, similar to Glue.
 
415
 
 
416
 
 
417
=item C<< $pair = Pair($num1,$num2); >>
 
418
 
 
419
Creates an object representing a pair of numbers;
 
420
Not a part of TeX, but useful for graphical objects.
 
421
The two components can be any numerical object.
 
422
 
 
423
=item C<< $pair = PairList(@pairs); >>
 
424
 
 
425
Creates an object representing a list of pairs of numbers;
 
426
Not a part of TeX, but useful for graphical objects.
 
427
 
 
428
=back
 
429
 
 
430
=head2 Error Reporting
 
431
 
 
432
=over 4
 
433
 
 
434
=item C<< Fatal($message); >>
 
435
 
 
436
Signals an fatal error, printing C<$message> along with some context.
 
437
In verbose mode a stack trace is printed.
 
438
 
 
439
=item C<< Error($message); >>
 
440
 
 
441
Signals an error, printing C<$message> along with some context.
 
442
If in strict mode, this is the same as Fatal().
 
443
Otherwise, it attempts to continue processing..
 
444
 
 
445
=item C<< Warn($message); >>
 
446
 
 
447
Prints a warning message along with a short indicator of
 
448
the input context, unless verbosity is quiet.
 
449
 
 
450
=item C<< NoteProgress($message); >>
 
451
 
 
452
Prints C<$message> unless the verbosity level below 0.
 
453
 
 
454
=back
 
455
 
 
456
=head2 Generic functions
 
457
 
 
458
=over 4
 
459
 
 
460
=item C<< Stringify($object); >>
 
461
 
 
462
Returns a short string identifying C<$object>, for debugging.
 
463
Works on any values and objects, but invokes the stringify method on 
 
464
blessed objects.
 
465
More informative than the default perl conversion to a string.
 
466
 
 
467
=item C<< ToString($object); >>
 
468
 
 
469
Converts C<$object> to string; most useful for Tokens or Boxes where the
 
470
string content is desired.  Works on any values and objects, but invokes 
 
471
the toString method on blessed objects.
 
472
 
 
473
=item C<< Equals($a,$b); >>
 
474
 
 
475
Compares the two objects for equality.  Works on any values and objects, 
 
476
but invokes the equals method on blessed objects, which does a
 
477
deep comparison of the two objects.
 
478
 
 
479
=back
 
480
 
 
481
=head1 AUTHOR
 
482
 
 
483
Bruce Miller <bruce.miller@nist.gov>
 
484
 
 
485
=head1 COPYRIGHT
 
486
 
 
487
Public domain software, produced as part of work done by the
 
488
United States Government & not subject to copyright in the US.
 
489
 
 
490
=cut
 
491