MarpaX-Hoonlint

 view release on metacpan or  search on metacpan

hoons/arvo/gen/brass.hoon  view on Meta::CPAN

/?    310
::
::::
  !:
:-  %say
|=  $:  {now/@da * bec/beak}
        {$~ try/_| $~}
    ==
::
::  we're creating an event series E whose lifecycle can be computed
::  with the urbit lifecycle formula L, `[2 [0 3] [0 2]]`.  that is:
::  if E is the list of events processed by a computer in its life,
::  its final state is S, where S is nock(E L).
::
::  in practice, the first five nouns in E are: two boot formulas,
::  a hoon compiler as a nock formula, the same compiler as source,
::  and the arvo kernel as source.
::
::  after the first five special events, we enter an iterative
::  sequence of regular events which continues for the rest of the
::  computer's life.  during this sequence, each state is a function
::  that, passed the next event, produces the next state.
::
::  a regular event is a `[date wire type data]` tuple, where `date` is a
::  128-bit Urbit date; `wire` is an opaque path which output can
::  match to track causality; `type` is a symbol describing the type

hoons/arvo/gen/brass.hoon  view on Meta::CPAN

::  function (see its public interface in `sys/arvo`), gives us
::  extra features, like output, which are relevant to running
::  a real-life urbit vm, but don't affect the formal definition.
::
::  so a real-life urbit interpreter is coupled to the shape of
::  the arvo core.  it becomes very hard to change this shape.
::  fortunately, it is not a very complex interface.
::
:-  %noun
::
::  boot-one: lifecycle formula
::
=+  ^=  boot-one
    ::
    ::  event 1 is the lifecycle formula which computes the final
    ::  state from the full event sequence.
    ::
    ::  the formal urbit state is always just a gate (function)
    ::  which, passed the next event, produces the next state.
    ::
    =>  [boot-formula=* full-sequence=*]
    !=  ::
        ::  first we use the boot formula (event 1) to set up
        ::  the pair of state function and main sequence.  the boot
        ::  formula peels off the first 5 events
        ::  to set up the lifecycle loop.
        ::
        =+  [state-gate main-sequence]=.*(full-sequence boot-formula)
        ::
        ::  in this lifecycle loop, we replace the state function
        ::  with its product, called on the next event, until
        ::  we run out of events.
        ::
        |-  ?@  main-sequence
              state-gate
            %=  $
              main-sequence  +.main-sequence
              state-gate     .*(state-gate(+< -.main-sequence) -.state-gate)
            ==
::
::  boot-two: startup formula
::
=+  ^=  boot-two
    ::
    ::  event 2 is the startup formula, which verifies the compiler
    ::  and starts the main lifecycle.
    ::
    =>  :*  ::  event 3: a formula producing the hoon compiler
            ::
            compiler-formula=**
            ::
            ::  event 4: hoon compiler source, compiling to event 2
            ::
            compiler-source=*@t
            ::
            ::  event 5: arvo kernel source
            ::
            arvo-source=*@t
            ::
            ::  events 6..n: main sequence with normal semantics
            ::
            main-sequence=**
        ==
    !=  :_  main-sequence
        ::
        ::  activate the compiler gate.  the product of this formula
        ::  is smaller than the formula.  so you might think we should
        ::  save the gate itself rather than the formula producing it.
        ::  but we have to run the formula at runtime, to register jets.
        ::
        ::  as always, we have to use raw nock as we have no type.
        ::  the gate is in fact ++ride.
        ::
        ~>  %slog.[0 leaf+"1-b"]
        =+  ^=  compiler-gate
            .*(0 compiler-formula)
        ::
        ::  compile the compiler source, producing (pair span nock).
        ::  the compiler ignores its input so we use a trivial span.
        ::
        ~>  %slog.[0 leaf+"1-c (compiling compiler, wait a few minutes)"]
        =+  ^=  compiler-tool
            .*(compiler-gate(+< [%noun compiler-source]) -.compiler-gate)
        ::
        ::  switch to the second-generation compiler.  we want to be
        ::  able to generate matching reflection nouns even if the
        ::  language changes -- the first-generation formula will 
        ::  generate last-generation spans for `!>`, etc.
        ::
        ~>  %slog.[0 leaf+"1-d"]
        =.  compiler-gate  .*(0 +:compiler-tool)
        ::
        ::  get the span (type) of the kernel core, which is the context
        ::  of the compiler gate.  we just compiled the compiler,
        ::  so we know the span (type) of the compiler gate.  its
        ::  context is at tree address `+>` (ie, `+7` or Lisp `cddr`).
        ::  we use the compiler again to infer this trivial program.

hoons/arvo/gen/brass.hoon  view on Meta::CPAN

::  compiler-source: hoon source file producing compiler, `sys/hoon`
::
=+  compiler-source=.^(@t %cx (welp sys /hoon/hoon))
::
::  compiler-twig: compiler as hoon expression
::
~&  %metal-parsing
=+  compiler-twig=(ream compiler-source)
~&  %metal-parsed
::
::  compiler-formula: compiler as nock formula
::
~&  %metal-compiling
=+  compiler-formula=q:(~(mint ut %noun) %noun compiler-twig)
~&  %metal-compiled
::
::  arvo-source: hoon source file producing arvo kernel, `sys/arvo`
::
=+  arvo-source=.^(@t %cx (welp sys /arvo/hoon))
::
::  boot-ova: startup events
::
=+  ^=  boot-ova  ^-  (list *)
    :~  boot-one
        boot-two
        compiler-formula
        compiler-source
        arvo-source
    ==
::
::  module-ova: vane load operations.
::
=+  ^=  module-ova  ^-  (list ovum)
    |^  :~  ::
            ::  sys/zuse: standard library
            ::

hoons/arvo/gen/ivory.hoon  view on Meta::CPAN

::
=+  arvo-source=.^(@t %cx (welp sys /arvo/hoon))
::
::  whole-hoon: arvo within compiler
::
=+  whole-hoon=`hoon`[%tsgr compiler-hoon [%tsgr [%$ 7] (ream arvo-source)]]
::
::  compile the whole schmeer
::
~&  %ivory-compiling
=+  whole-formula=q:(~(mint ut %noun) %noun whole-hoon)
~&  %ivory-compiled
::
whole-formula

hoons/arvo/gen/metal.hoon  view on Meta::CPAN

=,  old-zuse
::
::::
  !:
:-  %say
|=  $:  {now/@da * bec/beak}
        {{who/@p $~} try/_| $~}
    ==
::
::  we're creating an event series E whose lifecycle can be computed
::  with the urbit lifecycle formula L, `[2 [0 3] [0 2]]`.  that is:
::  if E is the list of events processed by a computer in its life,
::  its final state is S, where S is nock(E L).
::
::  in practice, the first five nouns in E are: two boot formulas,
::  a hoon compiler as a nock formula, the same compiler as source,
::  and the arvo kernel as source.
::
::  after the first five special events, we enter an iterative
::  sequence of regular events which continues for the rest of the
::  computer's life.  during this sequence, each state is a function
::  that, passed the next event, produces the next state.
::
::  each event is a `[date wire type data]` tuple, where `date` is a
::  128-bit Urbit date; `wire` is an opaque path which output can
::  match to track causality; `type` is a symbol describing the type

hoons/arvo/gen/metal.hoon  view on Meta::CPAN

::  function (see its public interface in `sys/arvo`), gives us
::  extra features, like output, which are relevant to running
::  a real-life urbit vm, but don't affect the formal definition.
::
::  so a real-life urbit interpreter is coupled to the shape of
::  the arvo core.  it becomes very hard to change this shape.
::  fortunately, it is not a very complex interface.
::
:-  %noun
::
::  boot-one: lifecycle formula
::
=+  ^=  boot-one
    ::
    ::  event 1 is the lifecycle formula which computes the final
    ::  state from the full event sequence.
    ::
    ::  the formal urbit state is always just a gate (function)
    ::  which, passed the next event, produces the next state.
    ::
    =>  [boot-formula=* full-sequence=*]
    !=  ::
        ::  first we use the boot formula (event 1) to set up
        ::  the pair of state function and main sequence.  the boot
        ::  formula peels off the first n (currently 3) events
        ::  to set up the lifecycle loop.
        ::
        =+  [state-gate main-sequence]=.*(full-sequence boot-formula)
        ::
        ::  in this lifecycle loop, we replace the state function
        ::  with its product, called on the next event, until
        ::  we run out of events.
        ::
        |-  ?@  main-sequence
              state-gate
            %=  $
              main-sequence  +.main-sequence
              state-gate     .*(state-gate(+< -.main-sequence) -.state-gate)
            ==
::
::  boot-two: startup formula
::
=+  ^=  boot-two
    ::
    ::  event 2 is the startup formula, which verifies the compiler
    ::  and starts the main lifecycle.
    ::
    =>  :*  ::  event 3: a formula producing the hoon compiler
            ::
            compiler-formula=**
            ::
            ::  event 4: hoon compiler source, compiling to event 2
            ::
            compiler-source=*@t
            ::
            ::  event 5: arvo kernel source
            ::
            arvo-source=*@t
            ::
            ::  events 6..n: main sequence with normal semantics
            ::
            main-sequence=**
        ==
    !=  :_  main-sequence
        ::
        ::  activate the compiler gate.  the product of this formula
        ::  is smaller than the formula.  so you might think we should
        ::  save the gate itself rather than the formula producing it.
        ::  but we have to run the formula at runtime, to register jets.
        ::
        ::  as always, we have to use raw nock as we have no type.
        ::  the gate is in fact ++ride.
        ::
        ~>  %slog.[0 leaf+"1-b"]
        =+  ^=  compiler-gate
            .*(0 compiler-formula)
        ::
        ::  compile the compiler source, producing (pair span nock).
        ::  the compiler ignores its input so we use a trivial span.
        ::
        ~>  %slog.[0 leaf+"1-c"]
        =+  ^=  compiler-tool
            .*(compiler-gate(+< [%noun compiler-source]) -.compiler-gate)
        ::
        ::  switch to the second-generation compiler.  we want to be
        ::  able to generate matching reflection nouns even if the
        ::  language changes -- the first-generation formula will 
        ::  generate last-generation spans for `!>`, etc.
        ::
        ~>  %slog.[0 leaf+"1-d"]
        =.  compiler-gate  .*(0 +:compiler-tool)
        ::
        ::  get the span (type) of the kernel core, which is the context
        ::  of the compiler gate.  we just compiled the compiler,
        ::  so we know the span (type) of the compiler gate.  its
        ::  context is at tree address `+>` (ie, `+7` or Lisp `cddr`).
        ::  we use the compiler again to infer this trivial program.

hoons/arvo/gen/metal.hoon  view on Meta::CPAN

::  compiler-source: hoon source file producing compiler, `sys/hoon`
::
=+  compiler-source=.^(@t %cx (welp sys /hoon/hoon))
::
::  compiler-twig: compiler as hoon expression
::
~&  %metal-parsing
=+  compiler-twig=(ream compiler-source)
~&  %metal-parsed
::
::  compiler-formula: compiler as nock formula
::
~&  %metal-compiling
=+  compiler-formula=q:(~(mint ut %noun) %noun compiler-twig)
~&  %metal-compiled
::
::  arvo-source: hoon source file producing arvo kernel, `sys/arvo`
::
=+  arvo-source=.^(@t %cx (welp sys /arvo/hoon))
::
::  main-moves: installation actions
::
=+  ^=  main-moves
    |^  ^-  (list ovum)

hoons/arvo/gen/metal.hoon  view on Meta::CPAN

    :-  [now i.main-moves]
    $(main-moves t.main-moves, now (add now (bex 48)))
::
~?  try
  ~&  %metal-testing
  =+  ^=  yop
      ^-  @p
      %-  mug
      .*  :*  boot-one
              boot-two
              compiler-formula
              compiler-source
              arvo-source
              main-events
          ==
      [2 [0 3] [0 2]]
  [%metal-tested yop]
::
:*  boot-one
    boot-two
    compiler-formula
    compiler-source
    arvo-source
    main-events
==

hoons/arvo/gen/musk.hoon  view on Meta::CPAN

      ::
      &+data.noy
    ::  reduce block set to block list
    ::
    |+~(tap in blocks)
  ::
  ++  apex
    ::  execute nock on partial subject
    ::
    |=  $:  ::  bus: subject, a partial noun
            ::  fol: formula, a complete noun
            ::
            bus/seminoun
            fol/noun
        ==
    ^-  output
    ::  simplify result
    ::
    %-  abet
    ::  interpreter loop
    ::
    |-  ^-  result
    ::  ~&  [%apex-fol fol]
    ::  ~&  [%apex-mac mask.bus]
    ::  =-  ~&  [%apex-pro-mac ?@(foo ~ ~!(foo mask.foo))]
    ::      foo
    ::  ^=  foo
    ::  ^-  result
    ?@  fol  
      ::  bad formula, stop
      ::
      ~
    ?:  ?=(^ -.fol)  
      ::  hed: interpret head
      ::
      =+  hed=$(fol -.fol)
      ::  propagate stop
      ::
      ?~  hed  ~
      ::  tal: interpret tail
      ::
      =+  tal=$(fol +.fol)
      ::  propagate stop
      ::
      ?~  tal  ~
      ::  combine 
      ::
      (combine hed tal)
    ?+    fol  
    ::  bad formula; stop
    ::
        ~
    ::  0; fragment
    ::
        {$0 b/@}
      ::  if bad axis, stop
      ::
      ?:  =(0 b.fol)  ~
      ::  reduce to fragment
      ::

hoons/arvo/gen/musk.hoon  view on Meta::CPAN

    ::  1; constant
    ::
        {$1 b/*}
      ::  constant is complete
      ::
      [&+~ b.fol]
    ::
    ::  2; recursion
    ::
        {$2 b/* c/*}
      ::  require complete formula
      ::
      %+  require
        ::  compute formula with current subject
        ::
        $(fol c.fol)
      |=  ::  ryf: next formula
          ::
          ryf/noun
      ::  lub: next subject
      ::
      =+  lub=^$(fol b.fol)
      ::  propagate stop
      ::
      ?~  lub  ~
      ::  recurse
      ::

hoons/arvo/sys/hoon.hoon  view on Meta::CPAN

      ::
      &+data.noy
    ::  reduce block set to block list
    ::
    |+~(tap in blocks)
  ::
  ++  apex
    ::  execute nock on partial subject
    ::
    |=  $:  ::  bus: subject, a partial noun
            ::  fol: formula, a complete noun
            ::
            bus/seminoun
            fol/noun
        ==
    ^-  output
    ::  simplify result
    ::
    %-  abet
    ::  interpreter loop
    ::
    |-  ^-  result
    ?@  fol  
      ::  bad formula, stop
      ::
      ~
    ?:  ?=(^ -.fol)  
      ::  hed: interpret head
      ::
      =+  hed=$(fol -.fol)
      ::  propagate stop
      ::
      ?~  hed  ~
      ::  tal: interpret tail
      ::
      =+  tal=$(fol +.fol)
      ::  propagate stop
      ::
      ?~  tal  ~
      ::  combine 
      ::
      (combine hed tal)
    ?+    fol  
    ::  bad formula; stop
    ::
        ~
    ::  0; fragment
    ::
        {$0 b/@}
      ::  if bad axis, stop
      ::
      ?:  =(0 b.fol)  ~
      ::  reduce to fragment
      ::

hoons/arvo/sys/hoon.hoon  view on Meta::CPAN

    ::  1; constant
    ::
        {$1 b/*}
      ::  constant is complete
      ::
      [&+~ b.fol]
    ::
    ::  2; recursion
    ::
        {$2 b/* c/*}
      ::  require complete formula
      ::
      %+  require
        ::  compute formula with current subject
        ::
        $(fol c.fol)
      |=  ::  ryf: next formula
          ::
          ryf/noun
      ::  lub: next subject
      ::
      =+  lub=^$(fol b.fol)
      ::  propagate stop
      ::
      ?~  lub  ~
      ::  recurse
      ::

hoons/arvo/sys/hoon.hoon  view on Meta::CPAN

    (~(put in lez) i.yed)
  ==
::
++  cove                                                ::  extract [0 *] axis
  |=  nug/nock
  ?-    nug
      {$0 *}   p.nug
      {$10 *}  $(nug q.nug)
      *        ~_(leaf+"cove" !!)
  ==
++  comb                                                ::  combine two formulas
  ~/  %comb
  |=  {mal/nock buz/nock}
  ^-  nock
  ?:  ?&(?=({$0 *} mal) !=(0 p.mal))
    ?:  ?&(?=({$0 *} buz) !=(0 p.buz))
      [%0 (peg p.mal p.buz)]
    ?:  ?=({$2 {$0 *} {$0 *}} buz)
      [%2 [%0 (peg p.mal p.p.buz)] [%0 (peg p.mal p.q.buz)]]
    [%7 mal buz]
  ?:  ?=({^ {$0 $1}} mal)

hoons/arvo/sys/hoon.hoon  view on Meta::CPAN

++  cond                                                ::  ?:  compile
  ~/  %cond
  |=  {pex/nock yom/nock woq/nock}
  ^-  nock
  ?-  pex
    {$1 $0}  yom
    {$1 $1}  woq
    *        [%6 pex yom woq]
  ==
::
++  cons                                                ::  make formula cell
  ~/  %cons
  |=  {vur/nock sed/nock}
  ^-  nock
  ?:  ?=({{$0 *} {$0 *}} +<)
    ?:  ?&(=(+(p.vur) p.sed) =((div p.vur 2) (div p.sed 2)))
      [%0 (div p.vur 2)]
    [vur sed]
  ?:  ?=({{$1 *} {$1 *}} +<)
    [%1 p.vur p.sed]
  [vur sed]

hoons/arvo/sys/hoon.hoon  view on Meta::CPAN

      =.  wat  ~
      [%wtcl [%bust %bean] $(sec p.sec) $(sec q.sec)]
    ::
        {$weed *}
      (hail (home p.sec))
    ==
  ++  clam  
    ^-  hoon
    =/  raw  [%brts [~ ~] [%base %noun] (whip(gom 7) 6)]
    ::
    ::  this performance fix should unify a bunch of trivial formulas,
    ::  but breaks on certain hacks in ++raid:zuse.
    ::
    ::  ?.  ?=(?($axil $leaf) -.sec)  raw
    ::  [%tsgr [%rock %n ~] raw]
    raw
  ::
  ++  whip
    |=  axe/axis
    =+  ^=  tun
        |=  $:  def/tile 

hoons/arvo/sys/hoon.hoon  view on Meta::CPAN

        ++  form  |*({* *} [p=+<- q=+<+])               ::
        ++  skin  |*({p/* q/*} q)                       ::  unwrap baggage
        ++  meat  |*({p/* q/*} p)                       ::  unwrap filling
        --
      --
    ++  def
      =+  deft:arc
      |%  +-  $
      =>  +<
      |%
      ++  pord  |*(* (form +< *nock))                   ::  wrap mint formula
      ++  rosh  |*(* (form +< *(list pock)))            ::  wrap mint changes
      ++  fleg  _(pord *bath)                           ::  legmatch + code
      ++  fram  _(pord *claw)                           ::  armmatch +
      ++  foat  _(rosh *bath)                           ::  leg with changes
      ++  fult  _(rosh *claw)                           ::  arm with changes
      --  --
    ::
    ++  lib
      |%
      ++  deft

hoons/arvo/sys/zuse.hoon  view on Meta::CPAN

    ::                                                  ::  ++dif:fu:number
    ++  dif                                             ::  subtract
      |=  {c/{@ @} d/{@ @}}
      [(~(dif fo p.a) -.c -.d) (~(dif fo q.a) +.c +.d)]
    ::                                                  ::  ++exp:fu:number
    ++  exp                                             ::  exponent
      |=  {c/@ d/{@ @}}
      :-  (~(exp fo p.a) (mod c (dec p.a)) -.d)
      (~(exp fo q.a) (mod c (dec q.a)) +.d)
    ::                                                  ::  ++out:fu:number
    ++  out                                             ::  garner's formula
      |=  c/{@ @}
      %+  add  +.c
      %+  mul  q.a
      %+  ~(pro fo p.a)  b
      (~(dif fo p.a) -.c (~(sit fo p.a) +.c))
    ::                                                  ::  ++pro:fu:number
    ++  pro                                             ::  multiply
      |=  {c/{@ @} d/{@ @}}
      [(~(pro fo p.a) -.c -.d) (~(pro fo q.a) +.c +.d)]
    ::                                                  ::  ++sum:fu:number

lib/MarpaX/Hoonlint/Policy/Test/Whitespace.pm  view on Meta::CPAN


    my @mistakes = ();
    push @mistakes,
      @{
        $policy->checkOneLineGap(
            $gap,
            {
                mainColumn => $anchorColumn,
                preColumn => $elementsColumn,
                runeName        => $runeName,
                subpolicy => [ $runeName, 'formulas-initial-vgap' ],
            }
        )
      };

    if ( $expectedElementsColumn != $elementsColumn ) {

        my $msg = sprintf 'formula %s; %s',
          describeLC( $elementsLine, $elementsColumn ),
          describeMisindent2( $elementsColumn, $expectedElementsColumn );
        push @mistakes,
          {
            desc         => $msg,
            subpolicy    => [ $runeName, 'formula-body-indent' ],
            parentLine   => $parentLine,
            parentColumn => $parentColumn,
            line         => $elementsLine,
            column       => $elementsColumn,
            reportLine   => $elementsLine,
            reportColumn => $elementsColumn,
          };
    }

    push @mistakes,
      @{
        $policy->checkOneLineGap(
            $tistisGap,
            {
                mainColumn => $anchorColumn,
                preColumn => $elementsColumn,
                runeName        => $runeName,
                subpolicy => [ $runeName, 'formulas-final-gap' ],
                topicLines => [$tistisLine],
            }
        )
      };

    push @mistakes,
      @{
        $policy->checkTistis(
            $finalTistis,
            {
                expectedColumn => $anchorColumn,
                tag            => $runeName,
                subpolicy => [ $runeName, 'formulas-final-tistis' ],
            }
        )
      };

  return \@mistakes;

}

# optBonzElements ::= bonzElement* separator=>GAP proper=>1
# bonzElement ::= CEN SYM4K (- GAP -) tall5d
sub checkBonzElements {
    my ( $policy, $node ) = @_;
    my $children = $node->{children};
    my @nodesToAlign = ();
    for (my $childIX = 0; $childIX <= $#$children; $childIX += 2) {
        my $element = $children->[$childIX];
        my ($cen, $sym, $gap, $body) = @{ $element->{children} };
        push @nodesToAlign, $gap, $body;
    }
    my $alignmentData = $policy->findAlignment( \@nodesToAlign );
    $policy->setInheritedAttribute($node, 'formulaAlignmentData', $alignmentData);
    return $policy->checkSeq( $node, 'sigcen-formula' );
}

sub checkBonzElement {
    my ( $policy, $node ) = @_;
    my $instance = $policy->{lint};

    # bonzElement ::= CEN SYM4K (- GAP -) tall5d
    my ( $bodyGap, $body ) = @{ $policy->gapSeq0($node) };

    my ( $parentLine, $parentColumn ) = $instance->nodeLC($node);
    my ( $bodyLine,   $bodyColumn )   = $instance->nodeLC($body);

    my $alignmentData = $policy->getInheritedAttribute($node, 'formulaAlignmentData');
    my $bodyAlignmentColumn = @{$alignmentData};

    my @mistakes = ();
    my $runeName      = 'sigcen';

  BODY_ISSUES: {
        if ( $parentLine != $bodyLine ) {
            my $msg = sprintf 'formula body %s; must be on rune line',
              describeLC( $bodyLine, $bodyColumn );
            push @mistakes,
              {
                desc         => $msg,
                subpolicy => [ $runeName, 'formula-split' ],
                parentLine   => $parentLine,
                parentColumn => $parentColumn,
                line         => $bodyLine,
                column       => $bodyColumn,
                reportLine   => $bodyLine,
                reportColumn => $bodyColumn,
              };
            last BODY_ISSUES;
        }

        # If here, bodyLine == parentLine
        last BODY_ISSUES if $bodyColumn = $bodyAlignmentColumn;
        my $gapLiteral = $instance->literalNode($bodyGap);
        my $gapLength  = $bodyGap->{length};
        last BODY_ISSUES if $gapLength == 2;
        my ( undef, $bodyGapColumn ) = $instance->nodeLC($bodyGap);

        my $msg = sprintf 'formula body %s; %s',
          describeLC( $bodyLine, $bodyColumn ),
          describeMisindent2( $gapLength, 2 );
        push @mistakes,
          {
            desc         => $msg,
            subpolicy => [ $runeName, 'formula-body-indent' ],
            parentLine   => $parentLine,
            parentColumn => $parentColumn,
            line         => $bodyLine,
            column       => $bodyColumn,
            reportLine   => $bodyLine,
            reportColumn => $bodyColumn,
          };
    }

    return \@mistakes;



( run in 0.283 second using v1.01-cache-2.11-cpan-26ccb49234f )