this looks pretty good, but we cannot still enable the check :-(

-- Modeling Opetopes
-- here is Eric's editor: http://sma.epfl.ch/~finster/opetope/opetope.html
--
-- Note: Kock et al. use a similar scheme, where
--          - dots    <-->   lines
--          - spheres <-->   dots
--          - lines disappear
--          -                spheres appear

-- Note: In Eric's new work (at IAS) there are no
--       dots any more, instead he uses 'external cards', so
--          - (external) cards   <-->  lines
--          - space between stacked cards <--> external cards
--          - lines disappear
--          -                (regular) cards appear

import "../tests/Nat.prg"

-- GLOBAL TODOs
----------------

-- Naming: Seems essential for identifying things Hor(Name), Ver(Tree)
--         Name can be Label, then Niches (= sequences of opetope names).
--         the latter arise from the composition rule.
--         Note: don't store names in Stacks, that kills alpha
--               conversion. Instead names should be pushed into nodes
--               'singleton style' from outside: (node :: Tree (Hor `g))

-- Morphisms: given an opetope and a pointer to one of its cards
--            extract the opetope of that face (do we need a label
--            space to reliably find it?). This must be a type
--            function, with an algorithm accompanying it to extract
--            the face proper.

-- Composition: grafting of trees to external cards, but only if the
--              morphisms (faces) match. lower-dim stuff is unaffected.

-- Swapping: given a proof of equality between two niches, provide an
--           operation to swap them, replacing old faces by new ones,
--           FGL-style (functional graph library), just note that
--           certain morphisms are gone, others appeared.

-- References: a disciplined way of saying "I am an identical node to that guy",
--             by corollary these always obtain the same names.
--             a topologist would say 'surgery' (http://en.wikipedia.org/wiki/Surgery_theory)
--             We get a new Tree flavour, Ref, at least one up, followed by
--             naturals to index a node in a subtree.
--             At this point we are doing algebraic topology, and dealing with
--             closed manifolds, so that we can do homology etc. on them.
--             In logic this corresponds to relations, satisfiability.

-- Quoting: So far we have only dealt with data, i.e. quoted (inert) syntax.
--          we need a way to convert this syntax to code (e.g. at some stage),
--          to obtain semantics. We can have the usual splicing game.
--          Lisp does this with sexprs and macros.
--          The code needs then be executed (run, decreasing stage), when
--          it becomes active, and we can observe the manifestation of its
--          semantics. The reduction system could go along the lines of the
--          (typed) LambdaGraph.

-- NbE: I fully believe we can use this technique to reduce opetopic terms
--      to normal form. ('many syntax', 'one semantics' adjunction:
--                       http://www.logicmatters.net/resources/pdfs/Galois.pdf)

-- TODO: these three must be LeftLists
--
kind Trees = NoTree | Pre (Tree d) Trees deriving syntax (ts) List(NoTree, Pre)

data ZoomCompley :: Tree e ~> Tree f ~> * where
  Nily :: ZoomCompley a a
  Consy :: Stack a b -> ZoomCompley b c -> ZoomCompley a c
 deriving List(cply)

data ZoomComplex :: Trees ~> * where
  Nilx :: ZoomComplex [()tr]ts
  Endx :: Stack a b -> ZoomComplex [a, b]ts
  Consx :: Stack a b -> ZoomComplex [b; c]ts -> ZoomComplex [a, b; c]ts
 deriving syntax (cplx) List(Nilx, Consx) Item(Endx)

data Dir :: *2 where
  Hor :: Dir
  Ver :: Dir

-- define the Tree kind, a rose tree
-- note: we may need a two-level kind, since we need to track disjointness
--       of subtrees
-- todo: later we may want to have a label kind parameter too

data Tree :: Dir ~> *1 where
  Unit :: Tree Ver
  Ni :: Tree Hor
  Fork :: Tree d ~> Tree Hor ~> Tree Hor
 deriving syntax (tr) List(Ni, Fork) Unit(Unit)

-- make it singleton

data Tree' :: Tree d ~> * where
  In :: Tree' ()tr
  Fork :: treelike head -> Tree' tail -> Tree' [head; tail]tr
  Done :: Tree' []tr
 deriving syntax (ar) List(Done, Fork) Unit(In) -- "arbre"
-- http://www.papoulipoesique.com/wp-content/uploads/2013/06/arbre.jpg

-- define a proposition for subtrees
-- to be checked: TakeHead must ensure that all the node is consumed

prop Subtree :: Tree d ~> Tree e ~> * where
  UnitSub :: Subtree ()tr tr
  BothNil :: Subtree []tr []tr
  TakeHead :: Subtree head head' -> Subtree tail tail' -> Subtree [head; tail]tr [head'; tail']tr

-- TODO: separate the notions of Niche / Frame / Cell
kind Volume = FramedHollow | FilledCell
kind Diagram = Closed Volume | OpenNiche
-- should be a parameter to Stack

-- now we can stack cards (these are zooms in Kock et al. parlance)

data Stack :: Tree d ~> Tree e ~> * where
  Corolla :: Corolla tr => Tree' tr -> Stack tr ()tr

  -- TODO: needed?
  --Expand :: (Subtree consumed tr, {nodeValence consumed} `Equal` {nodeValence tr}) => Stack consumed prod -> Stack tr prod

  -- add another target face to a web
  Target :: ({nodes tr} `Equal` {nodeValence out}) => Stack tr out -> Stack tr out

  -- the following three grab a node (and possibly its offsprings) and incorporate it into a single card
  NodeDone :: Stack []tr [()tr]tr
  Pick :: {- EntireNode => -} Stack head prodhead -> Stack tail prodtail -> Stack [head; tail]tr [prodhead; prodtail]tr
  Exclude :: {- EntireNode => -} Stack tail prod -> Stack [()tr; tail]tr prod
  -- TODO: maybe just specify a subtree (Tree') and that's it

  On :: (Subtree tr' tr, Pointers 1t at out) => Stack tr' out' -> Stack tr out -> Tree' at -> Stack tr {graft out' at out}

  -- building niches (pasting diagrams)
  -- TODO: these must produce a composite labelled Hor
  NicheDone :: Stack ()tr []tr
  Niche :: Stack tr out -> Stack tr [out]tr
  Also :: Pointers 1t at tr
       => Tree' at -> Stack tr' out' -> Stack tr out -> Stack {extgraft tr' at tr} [out'; out]tr

  -- put a frame around a niche
  Frame :: (Corolla out, {nodes tr}  `Equal` {nodeValence out}) => Stack tr out -> Stack tr out

 deriving syntax(z) Record(NicheDone, Also) Item(Target)

stop = ({}z)z

-- this is bogus, just make it compile again...
up :: Reference tr => Stack ()tr tr -> Stack ()tr [tr]tr
up inner = ({()ar=inner}z)z

-- it remains to define corollas

-- TODO: one could say {nodes tr} == 1
prop Corolla :: Tree d ~> * where
  None' :: Corolla []tr
  One' :: Corolla tail -> Corolla [()tr; tail]tr

--  o   --->  |
--  |         |

lolliCell :: Stack []tr ()tr
lolliCell = Corolla Done

--  |         |
--  o   --->  |
--  |         |

dolliCell :: Stack [()tr]tr ()tr
dolliCell = Corolla $ Fork In Done

--              |
--  [o]   --->  o
--   |          |

lolliFrame :: Stack []tr [()tr]tr
lolliFrame = Target NodeDone

--   |          |
--  [o]   --->  o
--   |          |

dolliFrame :: Stack [()tr]tr [()tr]tr
dolliFrame = Target (Exclude NodeDone)

--   |          |
--   |          o
-- [[o]]  --->  |
--   |          o
--   |          |

stacked :: Stack [()tr]tr [[()tr]tr]tr
stacked = (dolliFrame `On` dolliFrame) (In `Fork` Done)

--   |
--  [|]   --->  o
--   |          |

crossed :: Stack ()tr []tr
crossed = stop

-- we can now join things
--
dolliForever = [dolliFrame; dolliForever]cply
nopetope = [crossed, lolliFrame; dolliForever]cply

-- back to unit as fast as possible...
--
stopetope = [crossed, lolliFrame, dolliCell]cply
neverstopetope = [crossed, lolliFrame, dolliCell; neverstopetope]cply
stopetope' = [crossed, lolliFrame; (dolliCell)cplx]cplx
stopetope'' = [crossed, lolliFrame, dolliCell]cplx

--   |          o
-- [[|]]  --->  |
--   |          o
--   |          |

drossed :: Stack ()tr [[]tr]tr
drossed = up stop

-- ################################
-- ############  Niches ###########
-- ################################

--  |          +
--  |          |

-- this is a niche, but assume to be a frame
niche0 :: Stack ()tr []tr
niche0 = {}z

--  |           |
-- [|]          +
--  |           |

-- this is a niche, but assume to be a frame
niche1 :: Stack ()tr [[]tr]tr
niche1 = {()ar=stop; {}z}z

--  |         o   o
-- [|]  --->   \ /
-- [|]          +
--  |           |

-- this is a niche, but assume to be a frame
niche2 :: Stack ()tr [[]tr, []tr]tr
niche2 = {()ar=stop; niche1}z

--                |
--  |         o   o
-- [o]  --->   \ /
-- [|]          +
--  |           |

niche10 :: Stack [()tr]tr [[()tr]tr, []tr]tr
niche10 = {()ar=Exclude NodeDone; Niche stop}z

-- ################################
-- ############  Frames ###########
-- ################################

--   |              |
--  /|\         o   o
-- |[o]|  --->   \ /
-- |[|]|          o
--  \|/           |
--   |

cyclops :: Stack [()tr]tr [[()tr]tr, []tr]tr
cyclops = (niche10)z

-- Stacking, Valence, Affine subtree, Substitute at an affine position

-- counting Units in a tree

valence :: Tree d ~> Nat
{valence []tr} = 0t
{valence [head; tail]tr} = {plus {valence head} {valence tail}}
{valence ()tr} = 1t

-- counting siblings of a tree

nodeValence :: Tree d ~> Nat
{nodeValence []tr} = 0t
{nodeValence [head; tail]tr} = (1+{nodeValence tail})t

-- counting nodes in a tree

nodes :: Tree d ~> Nat
{nodes ()tr} = t
{nodes []tr} = 1t
{nodes [head; tail]tr} = {plus {nodes head} {nodes tail}}

-- nodeValenceAt: given a (multi)pointer, determine the node valences at those positions
--               WHERE     IN
nodeValenceAt :: Tree d ~> Tree e ~> Nat
{nodeValenceAt ()tr tree} = {nodeValence tree}
{nodeValenceAt []tr []tr} = 0t
{nodeValenceAt [head'; tail']tr [head; tail]tr} = {plus {nodeValenceAt head' head} {nodeValenceAt tail' tail}}

-- a pointer is a valence-1 subtree of a tree
-- it is used to mark a unit in a tree where substitution will occur
--
prop Pointers :: Nat ~> Tree d ~> Tree e ~> * where
  Finger :: Pointers 1t ()tr ()tr
  Finished :: Pointers 0t []tr []tr
  ThisWay :: Pointers 1t head' head -> Pointers n tail' tail -> Pointers (1+n)t [head'; tail']tr [head; tail]tr
  ElseWhere :: Pointers n tail' tail -> Pointers n [[]tr; tail']tr [head; tail]tr

-- http://en.wikipedia.org/wiki/Grafting
--
-- graft WHAT      WHERE     IN
graft :: Tree d ~> Tree e ~> Tree f ~> Tree f
{graft what ()tr ()tr} = what
{graft what []tr tr} = tr
{graft what [head'; tail']tr [head; tail]tr} = [{graft what head' head}; {graft what tail' tail}]tr

-- extgraft: extend and graft
--
extgraft :: Tree what ~> Tree wher ~> Tree tree ~> Tree tree'
{extgraft what ()tr ()tr} = what
{extgraft what []tr ()tr} = ()tr
{extgraft what [head; tail]tr ()tr} = {extgrafthor what [head; tail]tr}
{extgraft what []tr []tr} = []tr
{extgraft what []tr [head; tail]tr} = [head; tail]tr
{extgraft what [head'; tail']tr [head; tail]tr} = [{extgraft what head' head}; {extgraft what tail' tail}]tr

-- helper:
extgrafthor :: Tree what ~> Tree Hor ~> Tree Hor
{extgrafthor what []tr} = []tr
{extgrafthor what [head; tail]tr} = [{extgraft what head ()tr}; {extgrafthor what tail}]tr

{- NOTE: we have an Omega bug here:

prompt> :norm {graft []tr ()tr ()tr}
Normalizes to:
  []tr

prompt> :kind []tr
[]tr :: Tree Hor  = []tr

prompt> :kind {graft []tr ()tr ()tr}
{graft []tr ()tr ()tr} :: Tree Ver  = {graft []tr ()tr ()tr}

... BUT: Hor /= Ver :-(
-}

-- substitution: replace a pointed node (of valence n) in a tree with an
-- other tree of (valence n) -- TODO

-- HERE IS A NICE RESEARCH QUESTION:
-- is it possible to "proof search" a Zoom?
-- i.e.
{-

class ZoomLike (int :: Tree) (out :: Tree) where
  zoom :: (Nodes int ~ Valence out) => Zoom int out

-}

prop Reference :: Tree Hor ~> * where
  Stop :: Reference []tr
  Up :: Reference tr -> Reference [tr]tr
 deriving Nat(d) -- de Bruijn index

prop Teleport :: Tree Hor ~> * where
  Gate :: Teleport [()tr]tr
  Tele :: Teleport tr -> Teleport [tr]tr
 deriving Nat(sk) -- skips

{-

0
|   |
1   L  (lambda node)
|   |
2   1  (how many skips)
 \ /
  o
  |
  B  (binds here)
  |

Encodes \x.xx

-}

r2 = 2d
t1 = 1sk

lamX_XX = addBinder $ [r2, t1]ar

prop BindsUp :: Nat ~> Tree Hor ~> * where
  LastSkip :: BindsUp 1t [()tr]tr
  MoreSkip :: Teleport tr -> BindsUp n tr -> BindsUp (1+n)t [tr]tr
  -- prove Application node
  HeadBindsUp :: Nat' n -> BindsUp (1+n)t head -> BindsUp n [head; tail]tr
  TailBindsUp :: Nat' n -> BindsUp n [head; tail]tr -> BindsUp n [nonempty, head; tail]tr

-- TODO: make sure that something teleports here
addBinder :: {-BindsUp 1t tr =>-} Tree' tr -> Tree' [tr]tr
addBinder term = [term]ar

testB :: BindsUp 0t [[[[]tr]tr]tr,[()tr]tr]tr -> Tree' [[[[]tr]tr]tr,[()tr]tr]tr
testB ev = [r2, 0sk]ar
testB' = testB (TailBindsUp 0v (HeadBindsUp 0v (LastSkip)))

testC :: BindsUp 0t [[[[[]tr]tr]tr,[[()tr]tr]tr]tr]tr -> Tree' [[[[[]tr]tr]tr,[[()tr]tr]tr]tr]tr
testC ev = lamX_XX
testC' = testC (HeadBindsUp 0v (TailBindsUp 1v (HeadBindsUp 1v (MoreSkip 0sk LastSkip))))

--TODO: prop Lambda :: Tree Hor ~> * where

{-
The slogan is: binder nodes do not count as result nodes:
 - just consider the next node upstream
 - incoming (external) cards, when identified to a binder do not count as inputs to application
 - incoming (external) cards, when identified to an (iterated) application become pattern matching (sigma).

In the end all identifications have a semantics (hopefully!), when the counting rules are ensured.

-}

-- Modeling Opetopes
-- here is Eric's editor: http://sma.epfl.ch/~finster/opetope/opetope.html
--
-- Note: Kock et al. use a similar scheme, where
--          - dots    <-->   lines
--          - spheres <-->   dots
--          - lines disappear
--          -                spheres appear

-- Note: In Eric's new work (at IAS) there are no
--       dots any more, instead he uses 'external cards', so
--          - (external) cards   <-->  lines
--          - space between stacked cards <--> external cards
--          - lines disappear
--          -                (regular) cards appear

import "../tests/Nat.prg"

-- GLOBAL TODOs
----------------

-- Naming: Seems essential for identifying things Hor(Name), Ver(Tree)
--         Name can be Label, then Niches (= sequences of opetope names).
--         the latter arise from the composition rule.
--         Note: don't store names in Stacks, that kills alpha
--               conversion. Instead names should be pushed into nodes
--               'singleton style' from outside: (node :: Tree (Hor `g))

-- Morphisms: given an opetope and a pointer to one of its cards
--            extract the opetope of that face (do we need a label
--            space to reliably find it?). This must be a type
--            function, with an algorithm accompanying it to extract
--            the face proper.

-- Composition: grafting of trees to external cards, but only if the
--              morphisms (faces) match. lower-dim stuff is unaffected.

-- Swapping: given a proof of equality between two niches, provide an
--           operation to swap them, replacing old faces by new ones,
--           FGL-style (functional graph library), just note that
--           certain morphisms are gone, others appeared.

-- References: a disciplined way of saying "I am an identical node to that guy",
--             by corollary these always obtain the same names.
--             a topologist would say 'surgery' (http://en.wikipedia.org/wiki/Surgery_theory)
--             We get a new Tree flavour, Ref, at least one up, followed by
--             naturals to index a node in a subtree.
--             At this point we are doing algebraic topology, and dealing with
--             closed manifolds, so that we can do homology etc. on them.
--             In logic this corresponds to relations, satisfiability.

-- Quoting: So far we have only dealt with data, i.e. quoted (inert) syntax.
--          we need a way to convert this syntax to code (e.g. at some stage),
--          to obtain semantics. We can have the usual splicing game.
--          Lisp does this with sexprs and macros.
--          The code needs then be executed (run, decreasing stage), when
--          it becomes active, and we can observe the manifestation of its
--          semantics. The reduction system could go along the lines of the
--          (typed) LambdaGraph.

-- NbE: I fully believe we can use this technique to reduce opetopic terms
--      to normal form. ('many syntax', 'one semantics' adjunction:
--                       http://www.logicmatters.net/resources/pdfs/Galois.pdf)

-- TODO: these three must be LeftLists
--
kind Trees = NoTree | Pre (Tree d) Trees deriving syntax (ts) List(NoTree, Pre)

data ZoomCompley :: Tree e ~> Tree f ~> * where
  Nily :: ZoomCompley a a
  Consy :: Stack a b -> ZoomCompley b c -> ZoomCompley a c
 deriving List(cply)

data ZoomComplex :: Trees ~> * where
  Nilx :: ZoomComplex [()tr]ts
  Endx :: Stack a b -> ZoomComplex [a, b]ts
  Consx :: Stack a b -> ZoomComplex [b; c]ts -> ZoomComplex [a, b; c]ts
 deriving syntax (cplx) List(Nilx, Consx) Item(Endx)

data Dir :: *2 where
  Hor :: Dir
  Ver :: Dir

-- define the Tree kind, a rose tree
-- note: we may need a two-level kind, since we need to track disjointness
--       of subtrees
-- todo: later we may want to have a label kind parameter too

data Tree :: Dir ~> *1 where
  Unit :: Tree Ver
  Ni :: Tree Hor
  Fork :: Tree d ~> Tree Hor ~> Tree Hor
 deriving syntax (tr) List(Ni, Fork) Unit(Unit)

-- make it singleton

data Tree' :: Tree d ~> * where
  In :: Tree' ()tr
  Fork :: treelike head -> Tree' tail -> Tree' [head; tail]tr
  Done :: Tree' []tr
 deriving syntax (ar) List(Done, Fork) Unit(In) -- "arbre"
-- http://www.papoulipoesique.com/wp-content/uploads/2013/06/arbre.jpg

-- define a proposition for subtrees
-- to be checked: TakeHead must ensure that all the node is consumed

prop Subtree :: Tree d ~> Tree e ~> * where
  UnitSub :: Subtree ()tr tr
  BothNil :: Subtree []tr []tr
  TakeHead :: Subtree head head' -> Subtree tail tail' -> Subtree [head; tail]tr [head'; tail']tr

-- TODO: separate the notions of Niche / Frame / Cell
kind Volume = FramedHollow | FilledCell
kind Diagram = Closed Volume | OpenNiche
-- should be a parameter to Stack

-- now we can stack cards (these are zooms in Kock et al. parlance)

data Stack :: Tree d ~> Tree e ~> * where
  Corolla :: Corolla tr => Tree' tr -> Stack tr ()tr

  -- TODO: needed?
  --Expand :: (Subtree consumed tr, {nodeValence consumed} `Equal` {nodeValence tr}) => Stack consumed prod -> Stack tr prod

  -- add another target face to a web
  Target :: ({nodes tr} `Equal` {nodeValence out}) => Stack tr out -> Stack tr out

  -- the following three grab a node (and possibly its offsprings) and incorporate it into a single card
  NodeDone :: Stack []tr [()tr]tr
  Pick :: {- EntireNode => -} Stack head prodhead -> Stack tail prodtail -> Stack [head; tail]tr [prodhead; prodtail]tr
  Exclude :: {- EntireNode => -} Stack tail prod -> Stack [()tr; tail]tr prod
  -- TODO: maybe just specify a subtree (Tree') and that's it

  On :: (Subtree tr' tr, Pointers 1t at out) => Stack tr' out' -> Stack tr out -> Tree' at -> Stack tr {graft out' at out}

  -- building niches (pasting diagrams)
  -- TODO: these must produce a composite labelled Hor
  NicheDone :: Stack ()tr []tr
  Niche :: Stack tr out -> Stack tr [out]tr
  Also :: Pointers 1t at tr
       => Tree' at -> Stack tr' out' -> Stack tr out -> Stack {extgraft tr' at tr} [out'; out]tr

  -- put a frame around a niche
  Frame :: (Corolla out, {nodes tr}  `Equal` {nodeValence out}) => Stack tr out -> Stack tr out

 deriving syntax(z) Record(NicheDone, Also) Item(Target)

stop = ({}z)z

-- this is bogus, just make it compile again...
up :: Reference tr => Stack ()tr tr -> Stack ()tr [tr]tr
up inner = ({()ar=inner}z)z

-- it remains to define corollas

-- TODO: one could say {nodes tr} == 1
prop Corolla :: Tree d ~> * where
  None' :: Corolla []tr
  One' :: Corolla tail -> Corolla [()tr; tail]tr

--  o   --->  |
--  |         |

lolliCell :: Stack []tr ()tr
lolliCell = Corolla Done

--  |         |
--  o   --->  |
--  |         |

dolliCell :: Stack [()tr]tr ()tr
dolliCell = Corolla $ Fork In Done

--              |
--  [o]   --->  o
--   |          |

lolliFrame :: Stack []tr [()tr]tr
lolliFrame = Target NodeDone

--   |          |
--  [o]   --->  o
--   |          |

dolliFrame :: Stack [()tr]tr [()tr]tr
dolliFrame = Target (Exclude NodeDone)

--   |          |
--   |          o
-- [[o]]  --->  |
--   |          o
--   |          |

stacked :: Stack [()tr]tr [[()tr]tr]tr
stacked = (dolliFrame `On` dolliFrame) (In `Fork` Done)

--   |
--  [|]   --->  o
--   |          |

crossed :: Stack ()tr []tr
crossed = stop

-- we can now join things
--
dolliForever = [dolliFrame; dolliForever]cply
nopetope = [crossed, lolliFrame; dolliForever]cply

-- back to unit as fast as possible...
--
stopetope = [crossed, lolliFrame, dolliCell]cply
neverstopetope = [crossed, lolliFrame, dolliCell; neverstopetope]cply
stopetope' = [crossed, lolliFrame; (dolliCell)cplx]cplx
stopetope'' = [crossed, lolliFrame, dolliCell]cplx

--   |          o
-- [[|]]  --->  |
--   |          o
--   |          |

drossed :: Stack ()tr [[]tr]tr
drossed = up stop

-- ################################
-- ############  Niches ###########
-- ################################

--  |          +
--  |          |

-- this is a niche, but assume to be a frame
niche0 :: Stack ()tr []tr
niche0 = {}z

--  |           |
-- [|]          +
--  |           |

-- this is a niche, but assume to be a frame
niche1 :: Stack ()tr [[]tr]tr
niche1 = {()ar=stop; {}z}z

--  |         o   o
-- [|]  --->   \ /
-- [|]          +
--  |           |

-- this is a niche, but assume to be a frame
niche2 :: Stack ()tr [[]tr, []tr]tr
niche2 = {()ar=stop; niche1}z

--                |
--  |         o   o
-- [o]  --->   \ /
-- [|]          +
--  |           |

niche10 :: Stack [()tr]tr [[()tr]tr, []tr]tr
niche10 = {()ar=Exclude NodeDone; Niche stop}z

-- ################################
-- ############  Frames ###########
-- ################################

--   |              |
--  /|\         o   o
-- |[o]|  --->   \ /
-- |[|]|          o
--  \|/           |
--   |

cyclops :: Stack [()tr]tr [[()tr]tr, []tr]tr
cyclops = (niche10)z

-- Stacking, Valence, Affine subtree, Substitute at an affine position

-- counting Units in a tree

valence :: Tree d ~> Nat
{valence []tr} = 0t
{valence [head; tail]tr} = {plus {valence head} {valence tail}}
{valence ()tr} = 1t

-- counting siblings of a tree

nodeValence :: Tree d ~> Nat
{nodeValence []tr} = 0t
{nodeValence [head; tail]tr} = (1+{nodeValence tail})t

-- counting nodes in a tree

nodes :: Tree d ~> Nat
{nodes ()tr} = t
{nodes []tr} = 1t
{nodes [head; tail]tr} = {plus {nodes head} {nodes tail}}

-- nodeValenceAt: given a (multi)pointer, determine the node valences at those positions
--               WHERE     IN
nodeValenceAt :: Tree d ~> Tree e ~> Nat
{nodeValenceAt ()tr tree} = {nodeValence tree}
{nodeValenceAt []tr []tr} = 0t
{nodeValenceAt [head'; tail']tr [head; tail]tr} = {plus {nodeValenceAt head' head} {nodeValenceAt tail' tail}}

-- a pointer is a valence-1 subtree of a tree
-- it is used to mark a unit in a tree where substitution will occur
--
prop Pointers :: Nat ~> Tree d ~> Tree e ~> * where
  Finger :: Pointers 1t ()tr ()tr
  Finished :: Pointers 0t []tr []tr
  ThisWay :: Pointers 1t head' head -> Pointers n tail' tail -> Pointers (1+n)t [head'; tail']tr [head; tail]tr
  ElseWhere :: Pointers n tail' tail -> Pointers n [[]tr; tail']tr [head; tail]tr

-- http://en.wikipedia.org/wiki/Grafting
--
-- graft WHAT      WHERE     IN
graft :: Tree d ~> Tree e ~> Tree f ~> Tree f
{graft what ()tr ()tr} = what
{graft what []tr tr} = tr
{graft what [head'; tail']tr [head; tail]tr} = [{graft what head' head}; {graft what tail' tail}]tr

-- extgraft: extend and graft
--
extgraft :: Tree what ~> Tree wher ~> Tree tree ~> Tree tree'
{extgraft what ()tr ()tr} = what
{extgraft what []tr ()tr} = ()tr
{extgraft what [head; tail]tr ()tr} = {extgrafthor what [head; tail]tr}
{extgraft what []tr []tr} = []tr
{extgraft what []tr [head; tail]tr} = [head; tail]tr
{extgraft what [head'; tail']tr [head; tail]tr} = [{extgraft what head' head}; {extgraft what tail' tail}]tr

-- helper:
extgrafthor :: Tree what ~> Tree Hor ~> Tree Hor
{extgrafthor what []tr} = []tr
{extgrafthor what [head; tail]tr} = [{extgraft what head ()tr}; {extgrafthor what tail}]tr

{- NOTE: we have an Omega bug here:

prompt> :norm {graft []tr ()tr ()tr}
Normalizes to:
  []tr

prompt> :kind []tr
[]tr :: Tree Hor  = []tr

prompt> :kind {graft []tr ()tr ()tr}
{graft []tr ()tr ()tr} :: Tree Ver  = {graft []tr ()tr ()tr}

... BUT: Hor /= Ver :-(
-}

-- substitution: replace a pointed node (of valence n) in a tree with an
-- other tree of (valence n) -- TODO

-- HERE IS A NICE RESEARCH QUESTION:
-- is it possible to "proof search" a Zoom?
-- i.e.
{-

class ZoomLike (int :: Tree) (out :: Tree) where
  zoom :: (Nodes int ~ Valence out) => Zoom int out

-}

prop Reference :: Tree Hor ~> * where
  Stop :: Reference []tr
  Up :: Reference tr -> Reference [tr]tr
 deriving Nat(d) -- de Bruijn index

prop Teleport :: Tree Hor ~> * where
  Gate :: Teleport [()tr]tr
  Tele :: Teleport tr -> Teleport [tr]tr
 deriving Nat(sk) -- skips

{-

0
|   |
1   L  (lambda node)
|   |
2   1  (how many skips)
 \ /
  o
  |
  B  (binds here)
  |

Encodes \x.xx

-}

r2 = 2d
t1 = 1sk

lamX_XX = addBinder $ [r2, t1]ar

prop BindsUp :: Nat ~> Tree Hor ~> * where
  LastSkip :: BindsUp 1t [()tr]tr
  MoreSkip :: Teleport tr -> BindsUp n tr -> BindsUp (1+n)t [tr]tr
  -- prove Application node
  HeadBindsUp :: Nat' n -> BindsUp (1+n)t head -> BindsUp n [head; tail]tr
  TailBindsUp :: Nat' n -> BindsUp n [head; tail]tr -> BindsUp n [nonempty, head; tail]tr

-- TODO: make sure that something teleports here
addBinder :: {-BindsUp 1t tr =>-} Tree' tr -> Tree' [tr]tr
addBinder term = [term]ar

testB :: BindsUp 0t [[[[]tr]tr]tr,[()tr]tr]tr -> Tree' [[[[]tr]tr]tr,[()tr]tr]tr
testB ev = [r2, 0sk]ar
testB' = testB (TailBindsUp 0v (HeadBindsUp 0v (LastSkip)))

--TODO: prop Lambda :: Tree Hor ~> * where

{-
The slogan is: binder nodes do not count as result nodes:
 - just consider the next node upstream
 - incoming (external) cards, when identified to a binder do not count as inputs to application
 - incoming (external) cards, when identified to an (iterated) application become pattern matching (sigma).

In the end all identifications have a semantics (hopefully!), when the counting rules are ensured.

-}


QtDBus: module updated to use ISOPTQOBJECT

/*

  Qt5xHb - bibliotecas de ligao entre Harbour/xHarbour e Qt Framework 5

  Copyright (C) 2012-2017 Marcos Antonio Gambeta <marcosgambeta@uol.com.br>

*/

#include "hbclass.ch"
#include "qt5xhb_clsid.ch"

#ifndef QT5XHB_NO_REQUESTS
REQUEST WATCHMODE
REQUEST QDBUSCONNECTION
#endif

CLASS QDBusServiceWatcher INHERIT QObject

   DATA class_id INIT Class_Id_QDBusServiceWatcher
   DATA class_flags INIT 0
   DATA self_destruction INIT .F.

   METHOD new1
   METHOD new2
   METHOD new
   METHOD delete
   METHOD watchedServices
   METHOD setWatchedServices
   METHOD addWatchedService
   METHOD removeWatchedService
   METHOD watchMode
   METHOD setWatchMode
   METHOD connection
   METHOD setConnection

   METHOD onServiceRegistered
   METHOD onServiceUnregistered
   METHOD onServiceOwnerChanged

   DESTRUCTOR destroyObject

END CLASS

PROCEDURE destroyObject () CLASS QDBusServiceWatcher
   IF ::self_destruction
      ::delete()
   ENDIF
RETURN

#pragma BEGINDUMP

#include <Qt>

#ifndef __XHARBOUR__
#include <QDBusServiceWatcher>
#endif

#include "qt5xhb_common.h"
#include "qt5xhb_clsid.h"
#include "qt5xhb_utils.h"

#ifdef __XHARBOUR__
#include <QDBusServiceWatcher>
#endif

/*
explicit QDBusServiceWatcher(QObject *parent = 0)
*/
HB_FUNC_STATIC( QDBUSSERVICEWATCHER_NEW1 )
{
  QObject * par1 = ISNIL(1)? 0 : (QObject *) _qt5xhb_itemGetPtr(1);
  QDBusServiceWatcher * o = new QDBusServiceWatcher ( par1 );
  _qt5xhb_storePointerAndFlag( o, false );
}

/*
QDBusServiceWatcher(const QString &service, const QDBusConnection &connection, WatchMode watchMode = WatchForOwnerChange, QObject *parent = 0)
*/
HB_FUNC_STATIC( QDBUSSERVICEWATCHER_NEW2 )
{
  QString par1 = QLatin1String( hb_parc(1) );
  int par3 = ISNIL(3)? (int) QDBusServiceWatcher::WatchForOwnerChange : hb_parni(3);
  QObject * par4 = ISNIL(4)? 0 : (QObject *) _qt5xhb_itemGetPtr(4);
  QDBusServiceWatcher * o = new QDBusServiceWatcher ( par1,  (QDBusServiceWatcher::WatchMode) par3, par4 );
  _qt5xhb_storePointerAndFlag( o, false );
}

//[1]explicit QDBusServiceWatcher(QObject *parent = 0)
//[2]QDBusServiceWatcher(const QString &service, const QDBusConnection &connection, WatchMode watchMode = WatchForOwnerChange, QObject *parent = 0)

HB_FUNC( QDBUSSERVICEWATCHER_NEW )
{
  if( ISBETWEEN(0,1) && ISOPTQOBJECT(1) )
  {
    HB_FUNC_EXEC( QDBUSSERVICEWATCHER_NEW1 );
  }
  else if( ISBETWEEN(2,4) && ISCHAR(1) && ISQDBUSCONNECTION(2) && ISOPTNUM(3) && ISOPTQOBJECT(4) )
  {
    HB_FUNC_EXEC( QDBUSSERVICEWATCHER_NEW2 );
  }
  else
  {
    hb_errRT_BASE( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
  }
}

HB_FUNC_STATIC( QDBUSSERVICEWATCHER_DELETE )
{
  QDBusServiceWatcher * obj = (QDBusServiceWatcher *) hb_itemGetPtr( hb_objSendMsg( hb_stackSelfItem(), "POINTER", 0 ) );
  if( obj )
  {
    delete obj;
    obj = NULL;
    PHB_ITEM self = hb_stackSelfItem();
    PHB_ITEM ptr = hb_itemPutPtr( NULL, NULL );
    hb_objSendMsg( self, "_pointer", 1, ptr );
    hb_itemRelease( ptr );
  }
  hb_itemReturn( hb_stackSelfItem() );
}

/*
QStringList watchedServices() const
*/
HB_FUNC_STATIC( QDBUSSERVICEWATCHER_WATCHEDSERVICES )
{
  QDBusServiceWatcher * obj = (QDBusServiceWatcher *) _qt5xhb_itemGetPtrStackSelfItem();
  if( obj )
  {
    QStringList strl = obj->watchedServices (  );
    _qt5xhb_convert_qstringlist_to_array ( strl );
  }
}

/*
void setWatchedServices(const QStringList &services)
*/
HB_FUNC_STATIC( QDBUSSERVICEWATCHER_SETWATCHEDSERVICES )
{
  QDBusServiceWatcher * obj = (QDBusServiceWatcher *) _qt5xhb_itemGetPtrStackSelfItem();
  if( obj )
  {
    QStringList par1 = _qt5xhb_convert_array_parameter_to_qstringlist(1);
    //PHB_ITEM aStrings1 = hb_param(1, HB_IT_ARRAY);
    //int i1;
    //int nLen1 = hb_arrayLen(aStrings1);
    //for (i1=0;i1<nLen1;i1++)
    //{
    //  QString temp = QLatin1String( hb_arrayGetCPtr(aStrings1, i1+1) );
    //  par1 << temp;
    //}
    obj->setWatchedServices ( par1 );
  }
  hb_itemReturn( hb_stackSelfItem() );
}

/*
void addWatchedService(const QString &newService)
*/
HB_FUNC_STATIC( QDBUSSERVICEWATCHER_ADDWATCHEDSERVICE )
{
  QDBusServiceWatcher * obj = (QDBusServiceWatcher *) _qt5xhb_itemGetPtrStackSelfItem();
  if( obj )
  {
    QString par1 = QLatin1String( hb_parc(1) );
    obj->addWatchedService ( par1 );
  }
  hb_itemReturn( hb_stackSelfItem() );
}

/*
bool removeWatchedService(const QString &service)
*/
HB_FUNC_STATIC( QDBUSSERVICEWATCHER_REMOVEWATCHEDSERVICE )
{
  QDBusServiceWatcher * obj = (QDBusServiceWatcher *) _qt5xhb_itemGetPtrStackSelfItem();
  if( obj )
  {
    QString par1 = QLatin1String( hb_parc(1) );
    hb_retl( obj->removeWatchedService ( par1 ) );
  }
}

/*
WatchMode watchMode() const
*/
HB_FUNC_STATIC( QDBUSSERVICEWATCHER_WATCHMODE )
{
  QDBusServiceWatcher * obj = (QDBusServiceWatcher *) _qt5xhb_itemGetPtrStackSelfItem();
  if( obj )
  {
    WatchMode * ptr = new WatchMode( obj->watchMode (  ) );
    _qt5xhb_createReturnClass ( ptr, "WATCHMODE" );
  }
}

/*
void setWatchMode(WatchMode mode)
*/
HB_FUNC_STATIC( QDBUSSERVICEWATCHER_SETWATCHMODE )
{
  QDBusServiceWatcher * obj = (QDBusServiceWatcher *) _qt5xhb_itemGetPtrStackSelfItem();
  if( obj )
  {
    obj->setWatchMode (  );
  }
  hb_itemReturn( hb_stackSelfItem() );
}

/*
QDBusConnection connection() const
*/
HB_FUNC_STATIC( QDBUSSERVICEWATCHER_CONNECTION )
{
  QDBusServiceWatcher * obj = (QDBusServiceWatcher *) _qt5xhb_itemGetPtrStackSelfItem();
  if( obj )
  {
    QDBusConnection * ptr = new QDBusConnection( obj->connection (  ) );
    _qt5xhb_createReturnClass ( ptr, "QDBUSCONNECTION" );
  }
}

/*
void setConnection(const QDBusConnection &connection)
*/
HB_FUNC_STATIC( QDBUSSERVICEWATCHER_SETCONNECTION )
{
  QDBusServiceWatcher * obj = (QDBusServiceWatcher *) _qt5xhb_itemGetPtrStackSelfItem();
  if( obj )
  {
    obj->setConnection (  );
  }
  hb_itemReturn( hb_stackSelfItem() );
}

#pragma ENDDUMP

/*

  Qt5xHb - bibliotecas de ligao entre Harbour/xHarbour e Qt Framework 5

  Copyright (C) 2012-2017 Marcos Antonio Gambeta <marcosgambeta@uol.com.br>

*/

#include "hbclass.ch"
#include "qt5xhb_clsid.ch"

#ifndef QT5XHB_NO_REQUESTS
REQUEST WATCHMODE
REQUEST QDBUSCONNECTION
#endif

CLASS QDBusServiceWatcher INHERIT QObject

   DATA class_id INIT Class_Id_QDBusServiceWatcher
   DATA class_flags INIT 0
   DATA self_destruction INIT .F.

   METHOD new1
   METHOD new2
   METHOD new
   METHOD delete
   METHOD watchedServices
   METHOD setWatchedServices
   METHOD addWatchedService
   METHOD removeWatchedService
   METHOD watchMode
   METHOD setWatchMode
   METHOD connection
   METHOD setConnection

   METHOD onServiceRegistered
   METHOD onServiceUnregistered
   METHOD onServiceOwnerChanged

   DESTRUCTOR destroyObject

END CLASS

PROCEDURE destroyObject () CLASS QDBusServiceWatcher
   IF ::self_destruction
      ::delete()
   ENDIF
RETURN

#pragma BEGINDUMP

#include <Qt>

#ifndef __XHARBOUR__
#include <QDBusServiceWatcher>
#endif

#include "qt5xhb_common.h"
#include "qt5xhb_clsid.h"
#include "qt5xhb_utils.h"

#ifdef __XHARBOUR__
#include <QDBusServiceWatcher>
#endif

/*
explicit QDBusServiceWatcher(QObject *parent = 0)
*/
HB_FUNC_STATIC( QDBUSSERVICEWATCHER_NEW1 )
{
  QObject * par1 = ISNIL(1)? 0 : (QObject *) _qt5xhb_itemGetPtr(1);
  QDBusServiceWatcher * o = new QDBusServiceWatcher ( par1 );
  _qt5xhb_storePointerAndFlag( o, false );
}

/*
QDBusServiceWatcher(const QString &service, const QDBusConnection &connection, WatchMode watchMode = WatchForOwnerChange, QObject *parent = 0)
*/
HB_FUNC_STATIC( QDBUSSERVICEWATCHER_NEW2 )
{
  QString par1 = QLatin1String( hb_parc(1) );
  int par3 = ISNIL(3)? (int) QDBusServiceWatcher::WatchForOwnerChange : hb_parni(3);
  QObject * par4 = ISNIL(4)? 0 : (QObject *) _qt5xhb_itemGetPtr(4);
  QDBusServiceWatcher * o = new QDBusServiceWatcher ( par1,  (QDBusServiceWatcher::WatchMode) par3, par4 );
  _qt5xhb_storePointerAndFlag( o, false );
}

//[1]explicit QDBusServiceWatcher(QObject *parent = 0)
//[2]QDBusServiceWatcher(const QString &service, const QDBusConnection &connection, WatchMode watchMode = WatchForOwnerChange, QObject *parent = 0)

HB_FUNC( QDBUSSERVICEWATCHER_NEW )
{
  if( ISBETWEEN(0,1) && (ISQOBJECT(1)||ISNIL(1)) )
  {
    HB_FUNC_EXEC( QDBUSSERVICEWATCHER_NEW1 );
  }
  else if( ISBETWEEN(2,4) && ISCHAR(1) && ISQDBUSCONNECTION(2) && ISOPTNUM(3) && (ISQOBJECT(4)||ISNIL(4)) )
  {
    HB_FUNC_EXEC( QDBUSSERVICEWATCHER_NEW2 );
  }
  else
  {
    hb_errRT_BASE( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
  }
}

HB_FUNC_STATIC( QDBUSSERVICEWATCHER_DELETE )
{
  QDBusServiceWatcher * obj = (QDBusServiceWatcher *) hb_itemGetPtr( hb_objSendMsg( hb_stackSelfItem(), "POINTER", 0 ) );
  if( obj )
  {
    delete obj;
    obj = NULL;
    PHB_ITEM self = hb_stackSelfItem();
    PHB_ITEM ptr = hb_itemPutPtr( NULL, NULL );
    hb_objSendMsg( self, "_pointer", 1, ptr );
    hb_itemRelease( ptr );
  }
  hb_itemReturn( hb_stackSelfItem() );
}

/*
QStringList watchedServices() const
*/
HB_FUNC_STATIC( QDBUSSERVICEWATCHER_WATCHEDSERVICES )
{
  QDBusServiceWatcher * obj = (QDBusServiceWatcher *) _qt5xhb_itemGetPtrStackSelfItem();
  if( obj )
  {
    QStringList strl = obj->watchedServices (  );
    _qt5xhb_convert_qstringlist_to_array ( strl );
  }
}

/*
void setWatchedServices(const QStringList &services)
*/
HB_FUNC_STATIC( QDBUSSERVICEWATCHER_SETWATCHEDSERVICES )
{
  QDBusServiceWatcher * obj = (QDBusServiceWatcher *) _qt5xhb_itemGetPtrStackSelfItem();
  if( obj )
  {
    QStringList par1 = _qt5xhb_convert_array_parameter_to_qstringlist(1);
    //PHB_ITEM aStrings1 = hb_param(1, HB_IT_ARRAY);
    //int i1;
    //int nLen1 = hb_arrayLen(aStrings1);
    //for (i1=0;i1<nLen1;i1++)
    //{
    //  QString temp = QLatin1String( hb_arrayGetCPtr(aStrings1, i1+1) );
    //  par1 << temp;
    //}
    obj->setWatchedServices ( par1 );
  }
  hb_itemReturn( hb_stackSelfItem() );
}

/*
void addWatchedService(const QString &newService)
*/
HB_FUNC_STATIC( QDBUSSERVICEWATCHER_ADDWATCHEDSERVICE )
{
  QDBusServiceWatcher * obj = (QDBusServiceWatcher *) _qt5xhb_itemGetPtrStackSelfItem();
  if( obj )
  {
    QString par1 = QLatin1String( hb_parc(1) );
    obj->addWatchedService ( par1 );
  }
  hb_itemReturn( hb_stackSelfItem() );
}

/*
bool removeWatchedService(const QString &service)
*/
HB_FUNC_STATIC( QDBUSSERVICEWATCHER_REMOVEWATCHEDSERVICE )
{
  QDBusServiceWatcher * obj = (QDBusServiceWatcher *) _qt5xhb_itemGetPtrStackSelfItem();
  if( obj )
  {
    QString par1 = QLatin1String( hb_parc(1) );
    hb_retl( obj->removeWatchedService ( par1 ) );
  }
}

/*
WatchMode watchMode() const
*/
HB_FUNC_STATIC( QDBUSSERVICEWATCHER_WATCHMODE )
{
  QDBusServiceWatcher * obj = (QDBusServiceWatcher *) _qt5xhb_itemGetPtrStackSelfItem();
  if( obj )
  {
    WatchMode * ptr = new WatchMode( obj->watchMode (  ) );
    _qt5xhb_createReturnClass ( ptr, "WATCHMODE" );
  }
}

/*
void setWatchMode(WatchMode mode)
*/
HB_FUNC_STATIC( QDBUSSERVICEWATCHER_SETWATCHMODE )
{
  QDBusServiceWatcher * obj = (QDBusServiceWatcher *) _qt5xhb_itemGetPtrStackSelfItem();
  if( obj )
  {
    obj->setWatchMode (  );
  }
  hb_itemReturn( hb_stackSelfItem() );
}

/*
QDBusConnection connection() const
*/
HB_FUNC_STATIC( QDBUSSERVICEWATCHER_CONNECTION )
{
  QDBusServiceWatcher * obj = (QDBusServiceWatcher *) _qt5xhb_itemGetPtrStackSelfItem();
  if( obj )
  {
    QDBusConnection * ptr = new QDBusConnection( obj->connection (  ) );
    _qt5xhb_createReturnClass ( ptr, "QDBUSCONNECTION" );
  }
}

/*
void setConnection(const QDBusConnection &connection)
*/
HB_FUNC_STATIC( QDBUSSERVICEWATCHER_SETCONNECTION )
{
  QDBusServiceWatcher * obj = (QDBusServiceWatcher *) _qt5xhb_itemGetPtrStackSelfItem();
  if( obj )
  {
    obj->setConnection (  );
  }
  hb_itemReturn( hb_stackSelfItem() );
}

#pragma ENDDUMP


Update chipdisk binary

Update chipdisk binary

2061!xoLoNl!O	;5euGu&#
BF
lS%X@%FBF[GUxP2NO|dwΔ+)?!b[C	-ښS {ܠK`iJ{v3rX"KԬw	 rk8f
&94S8'{)[@J5c
8jʬ(	ґ5R!*M&Joa52](W	֬$</	xK%k@5X/	xKJk\5t/	xKueRxJ5ސK%z2`ۥ?mm֍HF

0Is)	-ɩIɷKTt(omk5U-2TɻKN4`TM0
7z`{e&{4tvSL ^ɀC*d
PtMﺳm8M`DEFMH3IJL1[,V`%Oy;aYYY%$i/WPya
7'˽c*M`ʒ0!x\.4=頢XHzr2GFn*h@٢*)-*VkL6n/ .BnfCGp		?P0[YY]Kh1K% %-P"XA 8.`xHZ[q #?޽XlfƬuM 7eIeIY橁
X҆^3O5R
N3u1
HnPQ0D	`aؠG (K4	0b*`Zg6i΢SL(pq4ߓ`tK37ZJ4QH%LFɏߔc(ηp4`6![QnC|퉮`u搕0蓘)mJؒ,H45,F5
H sjh*&`ʀƯۈͱ|** 3?
Jآ	'
AIHVˠ7
\IXڹ +
//\UUWyBeh8LT
0 \ѬR0l	eH*(0VװYlJa\W%\cA*P#@A+
.y$Tlm ^KFL(g"
f9j㌑q\lVTz\zYY7LmġĳqE$ʬYlD#Q,PYlDf֚TI+/%r% $N`~rDioHBUUH"V,-+ಔkrXs%+V9J#7I,Vi^L,yjC	HaK@J`肝(+DaXGf}7K2eE%v!`]n~L͌깂(\8=^Q?3xB
ikٽC7(a1,_)	ec78s!7827ML829C8s!9{829ȳ8s!9͇eCPvT;*ʇeCPvT;*AQ0RTX+TW@U
PVСbWbY f\9s!:T92:!9̲:29ȹ:s!94MLǄlML:6ʇeCPvT;*ʇeCPTWXU
PVӡbWbY#\XZ5KB[jsq:]<2
;d<sE!;k<2};r<s!;y<2;ȀML%ȇ<saPvT;*ʇeCPvT;*ʐW
Wb8\'+xpOw¸\jp8e<2><s!><2$>6=s+!>n=22>Ȧ=s9!>=2@>B'cGXF;1ְv5cݬ#.䰌v'5c#_aivÔv4dJ;Z]2DGVnψb(bXXJ#sPYpG*6>Z	FR'1[J5z6_L]K	Fe	7P^6Т?c`-ü,4^,,HXdbԋ5(D6~CӔJ)pblǍL&pD)B1 ̂rDRQ
x,SDldYN-CL,]3QcMK˭0Tai	iQvH]NmEkR	M@n,93CM'.N9%U
&	 0hPEh"Q$>{@r
`xVS+<.# co2cAZl[b<3h0O_pv`xr3r<ta<P#
}v!BC
	xA<0`exC@)Tx4%3? ~3fLOؠ T b
ӀΰTr\yFa8:H\y\jhۃ5Q)tgƘϰ#ѴC%+ENɨtevkJ(-MK)FcW	P&
s߿_!:1d+FyD8pžo\W>(q;	GM,u^pZdY>WEØR8tfy@0Bg&?3`f6[YZ8BY-t#O2)Ve/ACy@;'@`A1A3@
*'`;@p&Yw.<<c\#b#"`a4I$EK9FfdͿ	데Lo/_@
8lh		fd`a@,c͐
c[/܈V@x|zFǈ'|>GA
!79 	hm_BgPk<x7o!Ɛq
+	iETlpq
hͥ:00 2@8́(L-r:#}Ȳ :uFd8nCg&3)IdAIj?3|0h|pmH?7Mӏhe."?Lh 8<GpC.3Eplx7I0#h@<гn7cڂS<SѕWIhI cL4M5u~eF>: 3xт%{<7p3̒$H0UР@~mP=9Fa*:-&1}Ց"'("
*mP/>`HeJ?*q08$Pd@6T`s@t~8>#"2>|<)0zČ<,78;<
	A`M6c?kf	aH	\(,0Yσ>qN<YL
H#- =3.zG@͐a; n\8Tr<u0I$'?m<'99 G`>LZ ZBN8ujH>MA #BtEjc$|yø|Pt#㽜'.p7v`Tkg=19dFΌ=`.%	Çb@Pl
4xŒ	F.G$I!ā?8pɨ(߶`9dx)3ޮ`0o[1
?gw羁Y:>|GCnuā%QǱgPDm6$Qe
Bd8q@
PqRnzpqH`:22qc鍕*<xq##_y+5A/FUN]HH`
z kfcy86a ̸84*q8Bo,Ig&R(8
N߁ưq1Fof9ڎ("}ЀgDFWd3|?*2H hB?Bq$A8P	yT̏J{<$	t@Q9!Ɇ?ވ<W`.,4՗eLJYcAYp&$V\	@QY0(38rUd
qu2L
$)1sUQ:gq7bg|"G,L0֪`IHLڱ"āUbDɀ\DP
YL `B!P3v+8@٭Y+&D@ŰQj0$+
c1XPL0c0;LVTbbF*$3s*c`,$
lL³H gFsDL11
΂s-3r3'a	Qs7@#q!@LQ[)dVIE(VYJ ǭEnc`J+ z	"`WEnZޠTV0$P-@ I-`lK8%Ut~	DgV0uًpYؘoU,?6$.
_`p v4A DπA4<|pxm\FNAX
,4`Qzh$?E*Ji4<hF~k\(DUQm?4mF>mA6|fjM4 Ds689warsa1 f2t.YFscק6tܫ4[Dl%s!L"22SР%PD(`Xf,C"ne&4@qDfF@@OkDfF0C `li3Aګ78Y`#gUlpn&LJDJQM0Fv sq06"PcX60(IRO%z P
ٲLDĘ@4H/!p.ܥ:P&`Ks֙$},ԿۤW]Gw=ӗSzT)1uݭ6;k;M.pj@qQV_M`o%dסc<jy;̢W	7Z5'L-3W8zǯEӏfկ@>$ޝ';ߩ/\Dt<E3cry[L|A:ϸ(yRZӻ<^-es.=;ؽ>-n=+cG?>vzY5ɿOD):"+	RU@kC
'L1E3 as'by!x) /&%6wŗ6n _${M|ơ.@Ȳ.;2X-?ArU%6C(+e$_ e|L	I͐72V11)	7|(An@Wd3MS",fv<4<A4;OByBCLe"պdF|7yu*qLű)eLsIluqi[
[
OvMbqW0iUR%LLCX}@i,0
JL7:Rͥ[e)F8jk)I778~]7S4LjVu?l	8ޝ+M7~ߴ剧mMz1e4k0z@wo1
!{_4ӽ.2)TZLpҵ=sfȯ7R}!H
ՔҒ ᲖGK#WHLOpOPy,"!:^R
',9?PZ{XG!2~ם){j	!Gz-*/dR?Y4J
T
'JK(%"(+=Խ̙[Ё;w+@OCiG[?jL8DnO汚O'Eר--yY?ON-Z?ɉKi)gbzDYITۛ.ÛwOA{%ZQfmzsJ	Qi
EVY!4|\/̋bSn'ȶ"/\/
gZ3#ڢԬߏ0؎Ȣ7I~_$!
*(A!}y	BP^RO#	o]Wh0϶M	&y<WRGXN%Y6TJ<P@.!aÁ]&	Lp@In@#	?brE
@J{
4Xjt%<^?z,4O׀ 0!Ƣ/"

%&'(),/2#*-03 T$	+.1!'b=zPJ ! +Tb֚`HɊ2eƫ^xUT	ߜmF_؝r!i#(񭫏%xg\BK+
-lܯK>1A?F1:@X]dKU+]5e7i@<}m"e%DHHx֞O@.H1Cb047
PWcIv:1eĕ.Q${lm>vڤ?Yn#-n󪆹1<972(3Msu"A2u3T9A942H<뮜>CApʢCELH7J
OML4;'Ƴz|Yac̔."KINOLQPRMVV̴a3O(9=:>?b<K@>gDFlG_K\Дŗs$3n%4Ua6%:;\!uhJX],kAf-lH72p?`VN+AΊ9r4;+yD5<5O]pb4Y0[9	:N$l>u9g$dC@
}\VFREmCaA8[A>'QZ_a<@CHLOTXP9΄5$iu@ntZP(5ʀI2gHip/$eߍ
&@k_&18R75i_1x;SsXJ1$F} ~,
zjښ0
oLv@EB$IMz!_ f`u\r zzP@
ɽB׹(1H!WWˏ3q}"2hEuoF=okjh};nW6V`ӲqU֒n`~?R͢k;O}XL8/5W85qz(Y|=v頝H11$aڅh)}n
wzeޙs̼>}0pz&=ݾA;uIfn[~a~O+Ec+BӖN=Hy+kﴖd|UbbLH~<'zO,) ;g/#>Pt1MܾeMc9;z{rU6Ԛxu=&k{[йUB
KZK#ˢaN5R	N|ht0޸@Nuf1{̙Ay젼)\AZ'"y_}LCiޗz*ۧ`wݗ!*;Wd%LK);
,e2Lh1l5g;0ӆiߐ8ݒt+8߅P5%L]}0
yLGXe漥8EL[.<s޻]
3MJN;	-7;ܗ U~ze3Azӻ.]*0۹ @	;- -3r)څL[E}w-}7ѷ	#mѐi,@Z`ŀ3!a=B䠰)[&
j
7X)1ӌ)uѰ(-*d7nR5[JT=S[(l>t3jjjjjjjjjhZ=ԽYyޜ#vtsY['}Z04lqB̿0LhnR_܃?cW
)pը+)vda`@6y?feyڧI6iL׷^egiLHrX|J֋Z
_յ斗ha NG?wB	lMEZ	pEJ~߿ȢLM!ERHHD%0(qA v/Tm+HtP^Q.V
jLՒ5%vzh"6vxl,j@H/2X$Lh	(WD$@
 4,XRmG4!CC@^PMq^boX

kC"a
x,9-x"׈yah`Eqy>CU 1h©bx01bŦ/n?-Y:8
7&5,v$i})63i,3M$0!.9Lp) !CL"t,Hma*vbgqoŮQfIN<j;$φ_50+n-_3\~hL
0{GO݄Expk
/v*Ɓk{[;5H,@l:vm&ը<
ۀ>c{oէ8;hm;a#L/	eRȯbaf"#te{2CDvl}Q*zz20(sڣ8t%ZJ	Lq욬{&2a׬>2?2]>zNКa7*U:<dfCNA_?`apJ֢x"Xd,]2adva˃CD{lvQ*yN!x7sˣv|{w
	,UY"=H
Y*M`~cYL>?=n;n,,Aݢˏk6N=kmU1-No{+*4Rо0ˇ`-%)m_|ą{Ʌԗ㙢_iAiW<L-ΛW8oި^]Z頝ɵ^Jڹh)}oݭ`ԩS"-IF9׏=
q)_`nH||{zhv[L0	3鿝>LJ_Ƚ2ɿfzc)u"=lwszL1$>\G
'D0) \ymfxlb9x|]+E6<y;Dte9
s<x}^9d~=Z]kj\m}_ހk0T.L]pl@<¥n3ӔMgd^	9Wx3;Ǽ!o@Mf2s9qY%NSk	o'J<Ϲ0iyVl}Le[SVYmz%GHJqvfr*'BOLe')}
ɬPeLꬎ*Y#xG
iDސW>;"^gffNphIQ$sv%L3>zR>}!w0
LQn/eӝʼ}8j69]̱n]n kӃF	Yvb.~.q<wszhkpo0l@	wm%Ye~)n!=L9Pt5N!ah}u8qӼ@`
PSk@4#)
&qذ
C6X:Rz_t)Y%*T7+#JGDHо==,|DJ;B5A~>Q/efx!M$MM_MM\MMVMMYMs\b=ԽdV$klw	VVKyMmi}'ijT0(j^iwe*yu0L5_lF6y}k
)p{5	)9ʮɀj8?[J	i
}Lͽ7˗uL9>X)m8M3:j4k
38P@XbAkDrs A.A1FȢj+~a0Є2EK,A7hl{^P^QnQgI[[.rk"
s525Փ;؈%
k)
	F_xl;ZZJj:z$hQE
H		6	!vS@l#& !@@a	SG
4}-a_RFv7x	UNQ
?co8gqp
A H !"#	$%1
k`PFxseK) #1|
O0-2_47(*0$'x
f!.0&5+g"A%(	>,/ab36?l+]#f#H3tC]MEo0ap;&["6MuKALxZbiy8d&0cn25x<8)Ɏ+C.!#&N#M̟@#E6}ġ	8Q2?919"K6/^#cJ9C9#yRlGSVd`e
̘Nj(DsC(MYkU8M%`F8Es%1/%14$˕%>@Z2Ba?;G=e>si86#ȅ&S-I[|򫝁P(gȻSܳKCaГ6ϖ
&§|I{iHv05w+`~r~i΍m9:q).;N6p!2#`ܳ{gP5ƽ3r=sx,5͛WGjKsbIS4h]Ne8&."{XӃ'Řv%5.ȟmxs"/#"jN,LXݑK7bz̄v;vс匂:]>3M;z.a/	ເdӪ=Ht=:Gj15-/2ǹ{BQ5Ft$S68drkn,AҞTE%a'D
#amuS-Uۦ1yÿB00
DsWƽMYK߇jƓZ6Z8;--NP_S/T5}T2Zdi:e6WE"$p=ؐ#;Ń?BDBHD?=a? &."DFmwΑ*DHڷIŚY
.YT%Z ~30pX˩W*1Z1%׵ŉ ʅ%-ryg eNA_BYUjG`_FE$XF(4I*`Nlrٍjurwx{-,	_
!%<ՕE"HQPX&uRyd-w~[h^=I	nH}@4:]U{'.{!@ C]Z
Tt~}ٻGy]-LcNש6/hs9l~q`%\=g}W>D:81<0Q~
鸺,Xbŉ[?2І	mٮ/;7i.4q`ux.>)}ozo\~2ߞ $rWs14vG[.UQ0{^|#Eltx_;~4$kae~jiV9s)_N#dS~IWNMя_uȫ!6r?Hbh_1L(Pj9|,VsPR6L73Cm<v+ *1˻k<
JY|V6{\/.Hd5W6Ls%y"0IH<&Kg|o]5`v1,rrHf9jgclœm]Kܤ_EY=.:W|~omrt%'妩OQ.2e]9
Ɗg<O*x#{.LG1=ZGˣ@<OkBlJ>&W`[ݨ꫰}bCJ{`c0Ig:^dF(Щtt[az}Bި]Gʘ?s^)pq53g?=[ckT
MIQOgb(mƻW}D[	~p-h_SWx%,cWP:8g'X9ж"n5^0R_(-k!R Vff8$u+OEt}!r sRts2t\?ʼAKԐ0}Rߙ,Xtޗ+l^A||Ղl4PQ,\LG^vA5<)r%o4nUbwR.6
i< GA.9=ý]%|5FȞ-ߪ|tbhP`twǊJ5]0=ʿ,_^(++WuO_`!H$zScr~R^KnkۡӴ/x~>1]t?c [sO}
K.Z_vM_-`h	t:t~#=~c78C~Ʋ+ۯqKi}3hMy_
?lN|xwL|OEih_#YKG]hXv=L#BiȠwe~6~Ξ0Tv3c6"w4{ba[Jlɰ]EtUBL&})
KbuyB[!X*5οD[u+b߂)OH}i7{%C8п޲碮F3q57lzryIaAh-t_ƙ%rsH!h+˯{5+WPWOydޢ`I}?HGTV`N0p

A8L,\"D4C@A A#&'(!B!Wa%u
Ք@dt!Qͥ#Ih=if?Ed/j&1bNtY">Ъ	pBPPR3Er}v,GSe?do,
<("
\7g>NdyM@с	`-`fX$ Z3
eF%p0XPMpcPqn`yp1	2A C̝"F3D$Fp#=F2"rIt>¿F?'*H?@Jxp!8N:F;=?CǙti*wrc*b8	p+br}DՄ=BFL0`1i#wsF&rr~r;@68%pf- lОPdPsU
9DID#0I:-HQ:&y
C'00Ïp҃^
D1$z -xQbPc~h*@X%SKPh$F%!!KAMh,HX&	о!%&
\YQhLECG"/H	(
#9j_p!Df,:Ehx$NBJ~#*1HOV]dk`@@0A Ą,DBՏjp̢@ĿH*"S|St-IZARD.7;pSWM1( &d#HOR0AMi:oU
N-ITLE.B )jCٕ}FG]scxhs?tϛ&Wl5r-px8c&xGofm8999999999d͋r{Y	[
w Bii#^5ؑ`UHl|T :>0kuθ<)@k&x4<>48"Prsb"[ܲǇ-`%B\`MT llw8px
m32($ax"!)44NtSX?It`l7qhZ\c?0H"h1u(^@d|QKas
>Ha#86pS3C.<Y*'޳Y
JuxĨLH596sï0
m\wKfK	.>?OfMٛIeR`0 >l	qc|nN>}6?[Kr_4􃊊y?6,=)U,x*"4Nt'(p
z0,%}
n/cBP
h;܉?c$L`"O&OB͂l]&t
װ2ғ}&C, .3Jɖ006LĶ`*tjo8f
aP;L
e,^*e}_5u8C%0@6|i9(	ILPmM/)7L(mzL3IB+2M-pkhź<qPxɐcYcND0==8',Nޏt͈570I(8F>*blK7 CdkL8#?$Ou
v}! fUkt?s*?3LUr:0Q}=#S%*ȩd~jȘ5esAP_=7Vvi]~iiL+
v|wz)g!S4Pu}\i&\?,B# i<jvx;
JwBȵwYF#չ/Q`utόO7
]
0{Xyb9O
}JZukwP.yr^f_B/A|xEx	x~,< YxQ68YN	Тmgp:Ddu8&@"ȴqLh8Eh$Ĳ:tgnc\+x> A~ՠn rݟ	c)̴2
&#=V'L
1&gX8K@03M B
g%^ZNb
f~6c&wf	Z)}i
'1<NSZbkqx,#Gl+3`FX##"A`-ըv`7"w> L˾)0,ǝaS[b&]t|9LBc" ?!d;
bXu,y!,*5@DJN˙we$Yˁt]}ONHhL[2i7|
j>8 q!g&qdhDzāryr}LhdU}5"rT,sHJ Gh	g{:"Ls)މ`'}4LHT6h)oV`(
E4.='%d+)#$Qcz,,93	='`ā`2-THNT0.	A`1S	xbbV(	q`$
@<
?R~u$˖\3L2;YW3"QbP
~#	^`rvF)vOZ2HuNՊ?8~3s[tk[

DhjIJI/t,3D/<@b®8ʻw~9'LFh\i6i@zȟ0F8:;|<Apj5	l$11110843z=;Yvt;=e'D8ē,B?t,`rK*~R8wq .#A')ٿsc5Q"րd-/
@dP'e
όJ М2@Dܢăa^$O$8E"d}Jev!PxC0+Ypϙ/2)-^K̫ĉV 1W@0g W$D
\UJ	q^W1A(e<[ٿ N|!!"5oTj&Ha+Iu|$+29@GNU\cjqx!T4 !TE=YHXH#L&9wS4@ӢhԜӔ>$&zL>}0	5	`Nt-5kUEn;Q(?KaebѶ*m76RnͶ*RWr{)ӋnQtd-dy͠ʜƊwuOvw;d$w`.𯕢Nz	nue?eyͧʜƑw|O}w;e$wRVTXKsn~$0>y[JE)U@ۖ[_ՄfɮX۽*TގuUΪDzfL`lXoНS/; 	m"S@nJT)?1xky1h)/ieEmLMR`z͢ LK $.(Pf7V*aO.7]pԊ	`S#ۯ
ЦD$!Y>(	}09$ɰ01d\ܨ)Lttuˆ`]9wthu׮vq)[
/tɹ#D;LmNpDjNҧ+(M+&N
H2<]/Jq}Ίի9j*=]=8}abOXFt+bؾN}mDf6iZZM$J4ZLyvFȘd=i=fL*JD*jyyIcmՙϵ}(>
ަoF9^P[HJi.y#L'8(rs5itRG0]޴U4RrC<!8m2<4ĖL.O&ǝhm{'XT0q+d
{i-L7rgVT.1*jтJYYyT2k~Wk6lTXIk4Yw	4^pmLYG8i)vjnż/e
<jLqo;*W<hP:ЮNҴ&&KX~ƒk%<;fݳ\%Yn֤Ǵo}+E˨%so wq+j`t=sussvssrssssspsJq`bܩpcdej)fSbeMa3U_VR	pumC!UIj*:[+Z}dMtٝ1$3kAͧA}
ہD"0Ƅ+
Y(&\Y`	^2`*E0]zl
(@$`0E$[_fI.-QNX+MJT$A,BE3'"..C9$] #%)EA@0

%)-K\U'f%$5;A	^`g&H_FD8α7f	#BL$+H#2iB#IPLI,%}28KP#a
:I*FrBA#HBBD'FQH	J֦muX:WE7I*	Sd2&⛧3DaB0+m.3"2JCb54<0HFC}bCS1t5c@BP@L}`
1_
Ԡ_@(#;!Fs=@zZ<@B l %U^s}T
yFUuQϧU8YO
FqGj#f<)C}Ti'ͺxSqBmt33 D`¶BA hX	(Tgxq  ,^l_L w2UVd"D(a&@TPAb$D LJny#fY<;])]ƹ=}50W9{Z]mȭ6tvw#ʶ9NJEYE/{ӯWv`)v1*DLxmW8񬵲
ۀڼI$u0P=#Yhm)}&𞙁QAL Q?9<uKPw;ܫ)_?`,HȎThTHv0	}<+13{L(0-xܱ׿~,<Z?I)"^~Kì<mLc>f s?܂'}vX) Ϟ$w;++˼T"noG"]O`NBdN׈-f2W=+]E7#`\wo:xd{ȹg<6
3;1+ЉWR]@_	99EBrޭ@޴˜yCdv~	+ޏAY0ys4s}NwȌ*7\%LKA)Me	ebL5ܙ\f
WKfri~{Ɂ#a
(G葫CDJU%cLȶ5}ƒ0+)L
#:>ee>Kۖ
85QclFfq9wWw?缭M6*s#	ޝ:~ȿܽ}v\'D?)tLKQm|ig}AZ6Z@R`()>ppаG
	=)3꺈K֌[JU؉R5iu5l555555554Z-=KԽ-<ɈBHڞLQWl6TTHAYK+Լ0Moc)feN=식rkxHLcJ}^_]~r
)p{Y*})j	_viKvLZL;'mf)Zm&ZU5|4[ѭ/
{xnX.u2[ybC	#w̤
@BȢG	n~iF]K!~IBIA
\+)p1GQ2D5!l\<L_bBS)b1D 6@		&3B`!&2MYt'3YuFt'BZ3Nfw	'-0D
!!B! mԮ?d
W9Ѕr&%-92):<a
|,(P$'X?5*:o8=	 !#"(+,3/0.41?67>;8VǇ`")$1^ƺ{`@|_`[`&0
9MDI2!FQ`}xD/Gs.2&6
@)&}Łu*ʼS]
`*YԚ{zj,+&_V;AوdZ͓b=بb^Ex|[/*Ac6z+tX4jaf' τRc$h,~b\\<6Ae,F[V*D)b9BB2t
'+R"$В4TL𦆰qVb(!N'%9v])/H`t1nll8t9&!Nۧ@7a1j-D1(.N&s+yk,zCdsF&/4s,ibPqb3}1H655b8"-`2A7G5*>`fbXkbcXlɔ,ƺ3i._0wJp(YXCR+&28Fu)#``o?MI5:b<dp𕎓)Q"S {Kk#&4m/'+\:!y$y
D5QbD@ Hu5Qbb 5`$b"$_ QLJyè@Ekƹl=2.ѧӉgaW2%6;mȌn}b25c+@uYw`FV.yGurtL⼛W8~t3:Hi<.ݝɀ{肝O @bh)}CS	:R=\N<S
S.)_`eHwTSqh`^հv3Y:cu+PL(oMhaձɿWI6Y\w<l	p'b*0/`) /o=7S#,:<v}a\dGz5p\}wZ3$ɇ~	Ƀtlz}Nn<L@=Aw_LP)EccM%:be|	V5bx2p@vu?k?3ͥ;=H̸=@n`o
o=0.yELq8->R޾kҢO}iP{r!	OՋ!*8]TLX))+eL8e}*eiݷKcVOf][O4λ	>qޝv~Ȳ#&Nb☝0~@	~Gbֹ"˽ʒ)L8oٽnuE~!}dﰮN+S)iw@ʼ` ;*\lG)#`*dXа
A!N8Z:B$)FԳ["H.G{H{DV1:Dc"U]]kXJsd=-7ކ͉ͻ;VQ=iwub_nНnZ6q'}hj*0m
cuk4_e0L}QT1k_Y455*Ն
)pʢ˖)+ki	j-	aiLTkڜ,LLX^t-)em̭75ZҭL
`'8K_s-NqBtZ,{'Q77WN	Уnhn9F^r8&B pLp@p@xX0 .` "D

 "$')+.147:>AEINRW\bhnu|8&x @9~!ȋH~iKLݻlɀR
K+Wm!K]A
0 `IN5%G$BDB/,<L6*\DP27Z 4@	9"cg$MW}0<j;i	7N\Ak"`koDeq-4`nuR!@B@ !A"1D@
UsZn!

!q=@CF:-aHB
	d"m$	%&'58;>A/DG7, ./Y&#o ()*+9<?BE_H643210
p(h+b}?L4fx+_.\#bb-3&Մ19*aC|^0X|&2vo^Iz&&"s/|;8"F]x/|7'R1W/a9ord8쎌t"DMOfmQtt47v.󊂯S1'9]<~Zrj-ʐ?4;5	t;&&v	ҁ/Nr4P6+4QWi9A]鹌4?vqHӈS@wfsnlneY?X
<
z8Ԫ._/H<vqQ
 phds)\~Em $.	VAGqN͗Sw	;pQ=$.qs.9ѵ_7._^a5dh8B;A8~//!ȬbGINhS%Ɋ*SB{uT(UL¤ַE{+p[0AT%E}.9d.#`7Cf|UŤ˺]6yx~Ƙ^９Rķ(|CDw3lkv7Wx^2sm
~ۂSY쒪H-t뿚6J{Ǡ_|i}Θx4jmE|ޞ7-l8N+K8Qr.iv1j6p3/&`?(~tL,
tP|!xMUŒP?Hθ(*G,p-1&8_6+J1p|LڬGM8b_
TuVl*xw984%,ka<\=_";_@`*|#~ʿ..*$
B3QDHuUb"T`&"D#	@EݢDjBTPp)J3*&ygyh 44ҠL>qɩ&FH  ! ojh*&`Ưֱ  JȐe '3 ygyH yI4 yheyeh8L;XL
0 2?06L51% %
pa2

2061!xoLooNl!O	;5tbGu&#
BF
lS%X@%FBF[GUxP2MN|dwΔ˺)?!b[C	r-ښS
 пܠq4	8&Jc7%$Ԭp Ȍ&Ȼ8n
kK0;8'w)@JuF08jʬ(	&
)"R1&Joa52](K4L	f$<	xK^%Y@X	xK^EY\t	xK^k*xQސ_+ݥ?mm֍HF

0IR=])u	5-VɺT^KUYnm2RҐi%`n0
`A{fniDɀ*ww2񕽰
PVm8ؽq`DEFFMHIJL1[,V`@%Oya++%d6%ꢠwBo,&
'нc`ʒF_x\sz~,H^G+.FըEh@4YFFL0n/ ӏ.#r2̈B?[0Ԭ.JEK%1-X 8.`xH D&[Weedi +I*M%̷7
X2bDNUmM55k
HvOWP0DgxI_^`7HؠG (J4	0aR_6;wSL(oPp4`ҏRX<Fɕߐc(o4`_!oEA
'X`K_BL)OIJbH ªI"DRvTKm4,Fl
H djh*&`^Ưo5XD

Jآ&f'd
#IHVˠ7ҭ
\IX ,
yeh8L+
0 xѬR0l	eH*(0VװYlJa\W%\cA*P#@A+
.y$Tlm ^KFL(g"
f9j㌑q\lVTz\zYY7LmġĳqE$ʬYlD#Q,PYlDf֚TI+/%r% $N`~rDioHBUUH",-+ಔkrXs%+V9J#7I,Vi^L,yjC	HaK@J`肝(+DaXGf}7K2eE%v!`]n~L͌깂(\8=^Q?3xB
ikٽC7(a1,_)	ec78s!7827ML829C8s!9{829ȳ8s!9͇eCPvT;*ʇeCPvT;*AQ0RTX+TW@U
PVСbWbY f\9s!:T92:!9̲:29ȹ:s!94MLǄlML:6ʇeCPvT;*ʇeCPTWXU
PVӡbWbY#\XZ5KB[jsq:]<2
;d<sE!;k<2};r<s!;y<2;ȀML%ȇ<saPvT;*ʇeCPvT;*ʐW
Wb8\'+xpOw¸\jp8e<2><s!><2$>6=s+!>n=22>Ȧ=s9!>=2@>B'cGXF;1ְv5cݬ#.䰌v'5c#_aivÔv4dJ;Z]2DGVnψb(bXXJ#sPYpG*6>Z	FR'1[J5z6_L]K	Fe	7P^6Т?c~b4+bGc,^5'b6~CӔJΫ)pb6FL&pBlfA]"R(
)DJi2Y\bV^N!L.3A(K	eT0p	|Q;H.6E^Y5	&7CM'NU
&	 04
(
DH=9<+ZJb`rKӐ12cA	R-bGOhEU/;<9}n`xr:0@o>;!!` Csb_<@	AL@a<p|]	? U3f'LR*s1
Oig*9y@.nS<Fa8shK:`$.Uy.h
E5PMEnq}mЃGH:3cLL簑!"NE:2H%m&܀F+r(&
?URx9ľF߿/ҲH	ApiEoBH	d+R8#ȦG:/8-2K^X,
+q)Qќ:3<t
!i{g}E3E[}-I-L8!,V'ЙK2Ѕs@`3T 	@o]&,ŗpPld<Gyh1`vtknvN$	`Nv"gdrl#sfFf߀e7/_@|Q64	^fd`tᰠ1Ȁ1RnV\E@Xy]>`#cx
xy>^sNȐhqq6_!35`Dx7H8Yv
RMN4AX688sAx0W2 u@M@z&OgbpȲ~c u:n28n3C o$c?3>I0Ǵ>CF67MiǋM2?z~q`a4C 8<xBop!ـ<0XPV4 <hYȈ1A)egʫI$ 1vGx&&~2l>|ik B<xu{<73̒_$H0Р@I]	M	aN{x}Ȉ"N
C*6FGV@0tB2?J8Vgmr(2W~n*f09 N
8L@#"2><=H\bFq[8x`&6cb3q	0rsd0],\σj8<o,&o~ؐ=c# fa{Q}Ǉِ7b.Nhb9Qev`'9|ri #0tft>&- w-f'PYj纀ٵ֤&:"1Rk>MaC:ތ'p;@T{0*C51Ҳ#`}gFoc	㇅ܱR xM	du^<mqb	FUrG$wI!@?8pd
L(02<xDрWn`0-?gs@PKFhd>|#!:āƒǱqD6{$Qe
B?d^w8@(87=88I0N8ˊAtʎZ<x`n8#ɯҏ{[UAFU]*NHG`
Qw=h 5fux8d f\loVp8Y7,IyEM)s8ۆoX
V|q7DHmGRa>@3Xr#`23|WL?~`2}$G J
!@?ơ`APT^y*tu
fG=$	x(@9bdRLF?DA<KIW`b@@IL	jˁ2&%fmG1T.YѠ(ZXHJ`qB&DVa19bq`*(YC3q7a13@ã&b0kUrlg	$`$&mXJL	qYeb@"lk|."RPYAƉA`[Z
Pҙfb@l֬"
@bW(b	gJұ@m(&01L+*11S	`cs10Qf&aYV$3sS"
E`gABser'0pP(	s7q!h&(Y2+iЁYv"
+hXr%s tVǢAJcA`% ͑Z`+AJ-o*+0t^Pm@Pz$`kl%8MlFZ~PaHM3juFOMBl,lL7*m?F/i@pHl _;V[ "jpIπf |hpx6\NOi,h(4?N"%4<4bMh~5.@"*6?qh6h>6Ij FvA~35p&B"Mrл9I I
t:m,QxXickӛ:nU-6iƦmiР^PV`@
3Q!72v 	"3#@ '3#0! 64 YUiJ,Mrbb`Gb3F*FBpe``&%d"%jq(\d0g#;
 98P(1EFb`JČȈ\D׃jf$ͩ@İŽ wPj&"BbL@Hp\nRPJʓR`K]ps֙$},_+]Gw=ӗSzT)1uݭ6;k;M.pj@qQV_M`o%dסc<jy;̢W	7Z5'L-3W8zǯEӏfկ
@ h$Go'{;^ߗ\ytEK3cryL|AZ:ϸ(RZ<es.>n_ñ+ZF#hvzY5ɿOD):"+	RU@kC
'L1E3 as'by!x) /&%6wŗ6n _${M|ơ.@Ȳ.;2X-?ArU%6C(+e$_ e|L	I͐72V11)	7|(An@Wd3MS",fv<4<A4;OByBCLe"պdF|7yu*qLű)eLsIluqi[
[
OvMbqW0iUR%LLCX}@i,0
JL7:Rͥ[e)F8jk)I778~]7S4LjVu?l	8ޝ+M7~ߴ剧mMz1e4k0z@wo1
!{_4ӽ.2)TZLpҵ=sfȯ7R}!H
ՔIHK#ԥWH'pPy"G!:^RY~
',9P-{XG!2?kםʋ){j	!zdRw,4J
T
'JK(%"(+=Խ̙[Ё;w+ v'{4byjL8Dcvzv'汚[Eר-yYONqZɥ3=",OT͗MOnA%-Q3m_=sJK
ĢV!Z^4}g\EE/Ekm)'{Od[®Ņ
g-3#ڢԬߏ0؎Ȣ7I~_$!
*(A!}y	BP^RO#	o]Wh0϶M	&y<WRGXN%Y6TJ<P@.!aÁ]&	Lp@In@#	?brE
@J{
4Xjt%<^?z,4O׀ 0!Ƣ/"

%&'(),/2#*-03 T$	+.1!'b=zPJ ! +Tb֚`HɊ2eƫ^xUT	ߜmF_؝r!i#(񭫏%xg\BK+
-lܯK>1A?F1:@X]dKU+]5e7i@<}m"e%DHHx֞O@.H1Cb047
PWcIv:1eĕ.Q${lm>vڤ?Yn#-n󪆹1<972(3Msu"A2u3T9A942H<뮜>CApʢCELH7J
OML4;'Ƴz|Yac̔."KINOLQPRMVV̴a3O(9=:>?b<K@>gDFlG_K\Дŗs$3n%4Ua6%:;\!uhJX],kAf-lH72p?`VN+AΊ9r4;+yD5<5O]pb4Y0[9	:N$l>u9g$dC@
}\VFREmCaA8[A>'QZ_a<@CHLOTXP9΄5$iu@ntZP(5ʀI2gHip/$eߍ
&@k_&18R75i_1x;SsXJ1$F} ~,
zjښ0
oLv@EB$IMz!_ f`u\r z=( dޡkJ1{TH+!+Gq}"2hEuoF=okjh};nW6V`ӲqU֒n`~?R͢k;O}XL8/5W85qz(Y|=v頝H11$aڅh)}n
wzeޙs̼>}Wz=n^A;uKn-¿aGY~"cin!ӖN=HykK2|UbbLH~<'zO,) ;g/#>Pt1MܾeMc9;z{rU6Ԛxu=&k{[йUB
KZK#ˢaN5R	N|ht0޸@Nuf1{̙Ay젼)\AZ'"y_}LCiޗz*ۧ`wݗ!*;Wd%LK);
,e2Lh1l5g;0ӆiߐ8ݒt+8߅P5%L]}0
yLGXe漥8EL[.<s޻]
3MJN;	-7;ܗ U~ze3Azӻ.]*0۹ @	;- -3r)څL[E}w-}7ѷ	#mѐi,@Z`ŀ3!a=B䠰)[&
j
7X)1ӌ)uѰ(-*d7nR5[JT=S[(l>t3jjjjjjjjjhZ=ԽYyޜ#vtsY['}Z04lqB̿0LhnR_܃?cW
)pը+)vd0 <?felyI4L^߹eɳ4L$o}^X>	{J֋}Zү
KKhaE N#?B	6w&EZ	pEJ~߿ȢLM!ERHHD%0(qA v/Tm+HtP^Q.V
jLՒ5%vzh"6vxl,j@H/2X$Lh	(WD$@
 4,XRmG4!CC@^PMq^boX

kC"a
x,9-x"׈yah`Eqy>CU 1h©bx01bŦ/n?-Y:8
7&5,v$i})63i,3M$0!.9Lp) !CL"t,Hma*vbgqoŮQfIN<j;$φ_50+n-_3\~hL
0{GO݄Expk
/v*Ɓk{[;5H,@l:vm&ը<
ۀ>c{oէ8;hm;a#L/	eRȯbaf"#te{2CDvl}Q*zz20(sڣ8t%ZJ	Lq욬{&2a׬>2?2]>zNКa7*U:<dfCNA_?`apJ֢x"Xd,]2adva˃CD{lvQ*yN!x7sˣv|{w
	,UY"=H
Y*wEMx~cYL>?=n;n,,Aݢˏk6N=kmU1-No{+*4Rо0ˇ`-%)m_|ą{Ʌԗ㙢_iAiW<L-ΛW8oި^]Z頝ɵ^Jڹh)}oݭ`ԩS"-IF9׏=
q)_`nH||{zhv[L0	3鿝>LJ_Ƚ2ɿfzc)u"=lwszL1$>\G
'D0) \ymfxlb9x|]+E6<y;Dte9
s<x}^9d~=Z]kj\m}_ހk0T.L]pl@<¥n3ӔMgd^	9Wx3;Ǽ!o@Mf2s9qY%NSk	o'J<Ϲ0iyVl}Le[SVYmz%GHJqvfr*'BOLe')}
ɬPeLꬎ*Y#xG
iDސW>;"^gffNphIQ$sv%L3>zR>}!w0
LQn/eӝʼ}8j69]̱n]n kӃF	Yvb.~.q<wszhkpo0l@	wm%Ye~)n!=L9Pt5N!ah}u8qӼ@`
PSk@4#)
&qذ
C6X:Rz_t)Y%*T7+#JGDHо==,|DJ;B5A~>Q/efx!M$MM_MM\MMVMMYMs\b=ԽdV$klw	VVKyMmi}'ijT0(j^iwe*yu0L5_lF6y}k
)p{5	)9ʮɀj8?[J	i
}Lͽ7˗uL9>X)m8M3:j4k
3( D@X1AAm5Drs A.A1FȢj+~a0Є2EK,A7hl{^P^QnQgI[[.rk"
s525Փ;؈%
k)
	F_xl;ZZJj:z$hQE
H		6	!vS@l#& !@@a	SG
4}-a_RFv7x	UNQ
?co8gqp
A H !"#	$%1
k`PFxseK) #1|
O0-2_47(*0$'x
f!.0&5+g"A%(	>,/ab36?l+]#f#H3tC]MEo0ap;&["6MuKALxZbiy8d&0cn25x<8)Ɏ+C.!#&N#M̟@#E6}ġ	8Q2?919"K6/^#cJ9C9#yRlGSVd`e
̘Nj(DsC(MYkU8M%`F8Es%1/%14$˕%>@Z2Ba?;G=e>si86#ȅ&S-I[|򫝁P(gȻSܳKCaГ6ϖ
&§|I{iHv05w+`~r~i΍m9:q).;N6p!2#`ܳ{gP5ƽ3r=sx,5͛WGjKsbIS4h]Ne8&."{XӃ'Řv%5.ȟmxs"/#"jN,LXݑK7bz̄v;vс匂:]>3M;z.a/	ເdӪ=Ht=:Gj15-/2ǹ{BQ5Ft$S68drkn,AҞTE%a'D
#amuS-Uۦ1yÿB00
DsWƽMYK߇jƓZ6Z8;--NP_S/T5}T2Zdi:e6WE"$p=ؐ#;Ń?BDBHD?=a? &."DFmwΑ*DHڷIŚY
.YT%Z ~30pX˩W*1Z1%׵ŉ ʅ%-ryg eNA_BYUjG`_FE$XF(4I*`Nlrٍjurwx{-,	_
!%<ՕE"HQPX&:)|y[d-Rw?O[h/G	߈nHԠw4:]U.!@ C.Z
T]?W}]G<]LcNjhs9l8`m%\}=gW>D:81՛<0Q?
JD],Xb[tІ	m;i]4qO`ux.>)po>ʷzo\~2Ş Y$eCrWs14vG-MQ0^|lx{/蝙4j$kaeejiV9s/)N#dS?OIWwNWMя/Џuȫ!6߹|?Hbh_1L(Pj9|,VsPR6L73Cm<v+ *1˻k<
JYjwV6Ͻ\HOd56Ls%y"0K$rKgv]|7.Ț`{v1,rHfjegclœߌKܤk_E[~=:WN|Yr7mrt%'妩Qο.{2}.
Ɗ޿g<'_x#L#1=ZGe@<OkBlkJ>&W`[ݨuU}bkCJ{`c0Igƿ^dnF(Щt[oaz}BިGʘs^)pq5t3g?=-c굋T
MIQɧgb(m}D[	٢~p-}h_WuWx%y|F,cW~Ps:8g'X9"n5^0R(ak!R VfS8$uu}!r sR92t\?ʼAKԐ0}R,Xrޗ+l^Ab|Ղl4~(WQ,\LGvGA5<)r%4nUbߕ;R.6
i< GA.9=ý5sFȞ-bbhP`twǊ\J]0=k,__/{(++u_Q}`!H$g=Sc9g?)`/KnLkWӴ<~>1}.?Oc s}
NZ/_v-{U0h{	캮:t~#=co8CYtqKi^3hMy[/
lN|;L|OEih#YKG]hXĞvL#Bi;e~Ξ0Tv3c6"w4{ba[Jlɰ]EtUWBLO&})
buyB_[!X*5_Duڱb)OtH~}i7=%C8AF3q5{7lzryIaAh-ƙ%rsxH!\WhOL=5+P+dޢ`I}W?HT_V`N0p

A8L,\"D4C@A A#&'(!B!Wa%u
Ք@dt!Qͥ#Ih=if?Ed/j&1bNtY">Ъ	pBPPR3Er}v,GSe?do,
<("
\7g>NdyM@с	`-`fX$ Z3
eF%p0XPMpcPqn`yp1	2A C̝"F3D$Fp#=F2"rIt>¿F?'*H?@Jxp!8N:F;=?CǙti*wrc*b8	p+br}DՄ=BFL0`1i#wsF&rr~r;@68%pf- lОPdPsU
9DID#0I:-HQ:&y
C'00Ïp҃^
D1$z -xQbPc~h*@X%SKPh$F%!!KAMh,HX&	о!%&
\YQhLECG"/H	(
#9j_p!Df,:Ehx$NBJ~#*1HOV]dk0 p@Y0lA Ŀ,rDjjQ@_HY"St-IZARD.7;pSWM1( &d#HOR0AMi:oU
N-ITLE.B )jCٕ}FG]scxhs?tϛ&Wl5r-px8c&xGofm8999999999d͋r{Y	[
w Bii#^5ؑ`UHl|T :>0kuθ<)@k&x4<>48"Prsb"[ܲǇ-`%B\`MT llw8px
m32($ax"!)44NtSX?It`l7qhZ\c?0H"h1u(^@d|QKas
>Ha#86pS3C.<Y*'޳Y
JuxĨLH596sï0
m\wKfK	.>?OfMٛIeR`0 >l	qc|nN>}6?[Kr_4􃊊y?6,=)U,x*"4Nt'(p
z0,%}
n/cBP
h;܉?c$L`"O&OB͂l]&t
װ2ғ}&C, .3Jɖ006LĶ`*tjo8f
aP;L
e,^*e}_5u8C%0@6|i9(	ILPmM/)7L(mzL3IB+2M-pkhź<qPxɐcYcND0==8',Nޏt͈570I(8F>*blK7 CdkL8#?$Ou
v}! fUkt?s*?3LUr:0Q}=#S%*ȩd~jȘ5esAP_=7Vvi]~iiL+
v|wz)g!S4Pu}\i&\?,B# i<jvx;
JwBȵwYF#չ/Q`utόO7
]
0{Xyb9O
}JZukwP.yr^f_B/A|xExP@<p?\C,
Y}yQ68YN	Тmgp:Ddu8&@"ȴqLh8Eh$Ĳ:tgnc\+x> A~ՠn rݟ	c)̴2
&#=V'L
1&gX8K@03M B
g%^ZNb
f~6c&wf	Z)}i
'1<NSZbkqx,#Gl+3`FX##"A`-ըv`7"w> L˾)0,ǝaS[b&]t|9LBc" ?!d;
bXu,y!,*5@DJN˙we$Yˁt]}ONHhL[2i7|
j>8 q!g&qdhDzāryr}LhdU}5"rT,sHJ Gh	g{:"Ls)މ`'}4LHT6h)oV`(
E4.='%d+)#$Qcz,,93	='`ā`2-THNT0.	A`1S	xbbV(	q`$
@<
?R~u$˖\3L2;YW3"QbP
~#	^`rvF)vOZ2HuNՊ?8~3s[tk[

DhjIJI/t,3D/<@b®8ʻw~9'LFh\i6i@zȟ0F8:;|<Apj5	l$11110843z=;Yvt;=e'D8ē,B?t,`rK*~R8wq .#A')ٿsc5Q"րd-/
@dP'e
όJ М2@Dܢăa^$O$8E"d}Jev!PxC0+Ypϙ/2)-^K̫ĉV 1W@0g W$D
\UJ	q^W1A(e<[ٿ N|!!"5oTj&Ha+Iu|$+29@GNU\cjqx!T4 !TE=YHXH#L&9wS4@ӢhԜӔ>$&zL>}0	5	`Nt-5kUEn;Q(?KaebѶ*m76RnͶ*RWr{)ӋnQtd-dy͠ʜƊwuOvw;d$w`.𯕢Nz	nue?eyͧʜƑw|O}w;e$wRVTXKsn~$0>y[JE)U@ۖ[_ՄfɮX۽*TގuUΪDzfL`lXoНS/; 	m"S@nJT)?1xky1h)/ieEmLMR`z͢ LK $.(Pf7V*aO.7]pԊ	`S#ۯ
ЦD$!Y>(	}09$ɰ01d\ܨ)Lttuˆ`]9wthu׮vq)[
/tɹ#D;LmNpDjNҧ+(M+&N
H2<]/Jq}Ίի9j*=]=8}abOXFt+bؾN}mDf6iZZM$J4ZLyvFȘd=i=fL*JD*jyyIcmՙϵ}(>
ަoF9^P[HJi.y#L'8(rs5itRG0]޴U4RrC<!8m2<4ĖL.O&ǝhm{'XT0q+d
{i-L7rgVT.1*jтJYYyT2k~Wk6lTXIk4Yw	4^pmLYG8i)vjnż/e
<jLqo;*W<hP:ЮNҴ&&KX~ƒk%<;fݳ\%Yn֤Ǵo}+E˨%so wq+j`t=sussvssrssssspsJq`bܩpcdej)fSbeMa3U_VR	pumC!UIj*:[+Z}dMtٝ1$3kAͧA}
ہD"0Ƅ+
Y(&\Y`	^2`*E0]zl
(@$`0E$[_fI.-QNX+MJT$A,BE3'"..C9$] #%)EA@0

%)-K\U'f%$5;A	^`g&H_FD8α7f	#BL$+H#2iB#IPLI,%}28KP#a
:I*FrBA#HBBD'FQH	J֦muX:WE7I*	Sd2&⛧3DaB0+m.3"2JCb54<0HFC}bCS1t5c@BP@L}`
1_
Ԡ_@(#;!Fs=@zZ<@B 6܂^s><
꣨C:Ӫ8YOu
q#wQf<)C4'ͺxSqB֛t3 U[!{A h,	(^3x*q  ,^l_L w2UVd"D(a&@TPAb$D LJny#fY<;])]ƹ=}50W9{Z]mȭ6tvw#ʶ9NJEYE/{ӯWv`)v1*DLxmW8񬵲
ۀڼI$u0P=#Yhm)}&𞙁QAL Q?9<uKPw;ܫ)_?`,HȎThTHv0	}<+13{L(0-xܱ׿~,<Z?I)"^~Kì<mLc>f s?܂'}vX) Ϟ$w;++˼T"noG"]O`NBdN׈-f2W=+]E7#`\wo:xd{ȹg<6
3;1+ЉWR]@_	99EBrޭ@޴˜yCdv~	+ޏAY0ys4s}NwȌ*7\%LKA)Me	ebL5ܙ\f
WKfri~{Ɂ#a
(G葫CDJU%cLȶ5}ƒ0+)L
#:>ee>Kۖ
85QclFfq9wWw?缭M6*s#	ޝ:~ȿܽ}v\'D?)tLKQm|ig}AZ6Z@R`()>ppаG
	=)3꺈K֌[JU؉R5iu5l555555554Z-=KԽ-<ɈBHڞLQWl6T$ ƕKԼ0oc)feN=ErxHLcJ}^_]~r
)p{Y*})j	_viKvLZL;'mf)Zm&ZU5|4[ѭ/
{y<7Y.~-Ch	;R
@BȢG	n~iF]K!~IBIA
\+)p1GQ2D5!l\<L_bBS)b1D 6@		&3B`!&2MYt'3YuFt'BZ3Nfw	'-0D
!!B! mԮ?d
W9Ѕr&%-92):<a
|,(P$'X?5*:o8=	 !#"(+,3/0.41?67>;8VǇ`")$1^ƺ{`@|_`[`&0
9MDI2!FQ`}xD/Gs.2&6
@)&}Łu*ʼS]
`*YԚ{zj,+&_V;AوdZ͓b=بb^Ex|[/*Ac6z+tX4jaf' τRc$h,~b\\<6Ae,F[V*D)b9BB2t
'+R"$В4TL𦆰qVb(!N'%9v])/H`t1nll8t9&!Nۧ@7a1j-D1(.N&s+yk,zCdsF&/4s,ibPqb3}1H655b8"-`2A7G5*>`fbXkbcXlɔ,ƺ3i._0wJp(YXCR+&28Fu)#``o?MI5:b<dp𕎓)Q"S {Kk#&4m/'+\:!y$y
D5QbD@ Hu5Qbb 5`$b"$_ QLJyè@Ekƹl=2.ѧӉgaW2%6;mȌn}b25c+@uYw`FV.yGurtL⼛W8~t3:Hi<.ݝɀ{肝O @bh)}CS	:R=\N<S
S.)_`eHwTSqh`^հv3Y:cu+PL(oMhaձɿWI6Y\w<l	p'b*0/`) /o=7S#,:<v}a\dGz5p\}wZ3$ɇ~	Ƀtlz}Nn<L@=Aw_LP)EccM%:be|	V5bx2p@vu?k?3ͥ;=H̸=@n`o
o=0.yELq8->R޾kҢO}iP{r!	OՋ!*8]TLX))+eL8e}*eiݷKcVOf][O4λ	>qޝv~Ȳ#&Nb☝0~@	~Gbֹ"˽ʒ)L8oٽnuE~!}dﰮN+S)iw@ʼ` ;*\lG)#`*dXа
A!N8Z:B$)FԳ["H.G{H{DV1:Dc"U]]kXJsd=-7ކ͉ͻ;VQ=iwub_nНnZ6q'}hj*0m
cuk4_e0L}QT1k_Y455*Ն
)pʢ˖)+ki	j-	aiLTkڜ,LLX^t-)em̭75ZҭL
`'8K_s-NqBtZ,{'Q77WN	Уnhn9F^r8&B pLp@p@xX0 .` "D

 "$')+.147:>AEINRW\bhnu|8&x @9~!ȋH~iKLݻlɀR
K+Wm!K]A
0 `IN5%G$BDB/,<L6*\DP27Z 4@	9"cg$MW}0<j;i	7N\Ak"`koDeq-4`nuR!@B@ !A"1D@
UsZn!

!q=@CF:-aHB
	d"m$	%&'58;>A/DG7, ./Y&#o ()*+9<?BE_H643210
p(h+b}?L4fx+_.\#bb-3&Մ19*aC|^0X|&2vo^Iz&&"s/|;8"F]x/|7'R1W/a9ord8쎌t"DMOfmQtt47v.󊂯S1'9]<~Zrj-ʐ?4;5	t;&&v	ҁ/Nr4P6+4QWi9A]鹌4?vqHӈS@wfsnlneY?X
<
z8Ԫ._/H<vqQ
 phds)\~Em $.	VAGqN͗Sw	;pQ=$.qs.9ѵ_7._^a5dh8B;A8~//!ȬbGINhS%Ɋ*SB{uT(UL¤ַE{+p[0AT%E}.9d.#`7Cf|UŤ˺]6yx~Ƙ^９Rķ(|CDw3lkv7Wx^2sm
~ۂSY쒪H-t뿚6J{Ǡ_|i}Θx4jmE|ޞ7-l8N+K8Qr.iv1j6p3/&`?(~tL,
tP|!xMUŒP?Hθ(*G,p-1&8_6+J1p|LڬGM8b_
TuVl*xw984%,ka<\=_";_@`*|#~ʿ..*$
B3QDHuUb"T`&"D#@@DY jnN"D5b(Htp)J3*&ygyh 44ҠL>qɩ&FH  ! oojh*&`Ưֱ  JȐe '3 ygyH yI4 yheyeh8L;XL
0 2?06L51% %
pa2


added original 'lam' from paper

added original 'lam' from paper

-- "Names Free For Polymorphic Views of Names and Binders"
-- by Jean-Philippe Bernardy, Nicolas Pouillard
-- http://www.cse.chalmers.se/~bernardy/NamesForFree.pdf

-- originally
--
type Succ a = a `Trunce` ()

data Trunce :: * ~> * ~> * where
  Old :: a -> Trunce a v
  New :: v -> Trunce a v

data Tm :: * ~> * where
  Var :: a -> Tm a
  App :: Tm a -> Tm a -> Tm a
  Lam :: Tm (Succ a) -> Tm a

lam :: (forall v . v -> Tm (a `Trunce` v)) -> Tm a
lam f = Lam (f ())

-- My way??
--
data Tri :: Nat ~> * ~> * where
  Born :: a -> Tri 0t a
  Reach :: Tri n a -> Tri (1+n)t a

-- "Names Free For Polymorphic Views of Names and Binders"
-- by Jean-Philippe Bernardy, Nicolas Pouillard
-- http://www.cse.chalmers.se/~bernardy/NamesForFree.pdf

-- originally
--
type Succ a = a `Trunce` ()

data Trunce :: * ~> * ~> * where
  Old :: a -> Trunce a b
  New :: b -> Trunce a b

data Tri :: Nat ~> * ~> * where
  Born :: a -> Tri 0t a
  Reach :: Tri n a -> Tri (1+n)t a


[Runtime] ShowFoxArray() now uses Parens when the CompilerOptionFox2 is set in the runtimestate. Also switched to use an interpolated expression.

//
// Copyright (c) XSharp B.V.  All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
// See License.txt in the project root for license information.
//

USING XSharp.Internal

/// <include file="VfpRuntimeDocs.xml" path="Runtimefunctions/alen/*" />
FUNCTION ALen(a AS __FoxArray) AS DWORD
    RETURN ALen(a, 0)

/// <include file="VfpRuntimeDocs.xml" path="Runtimefunctions/alen/*" />
FUNCTION ALen(a AS __FoxArray, nArrayAttribute AS LONG) AS DWORD
    SWITCH nArrayAttribute
    CASE 1
        RETURN (DWORD) a:Rows
    CASE 2
        IF a:MultiDimensional
            RETURN (DWORD) a:Columns
        ELSE
            RETURN 0
        ENDIF
    CASE 0
            RETURN (DWORD) a:Count
    OTHERWISE
        var cMessage := __VfpStr(VFPErrors.ATTRIBUTE_OUT_OF_RANGE, nameof(nArrayAttribute))
        THROW ArgumentOutOfRangeException { nameof(nArrayAttribute),nArrayAttribute, cMessage}
    END SWITCH

/// <exclude/>
FUNCTION __FoxALen(a AS __FoxArray) AS DWORD
    RETURN ALen(a, 0)

/// <include file="VfpRuntimeDocs.xml" path="Runtimefunctions/aelement/*" />
FUNCTION AElement(ArrayName AS __FoxArray, nRowSubscript AS DWORD) AS USUAL
   IF ( nRowSubscript > 0 .AND. nRowSubscript <= ArrayName:Rows )
      RETURN nRowSubscript
   ENDIF
   var cMessage := __VfpStr(VFPErrors.ATTRIBUTE_OUT_OF_RANGE, nameof(nRowSubscript))
   THROW ArgumentOutOfRangeException { nameof(nRowSubscript),nRowSubscript, cMessage}

/// <include file="VfpRuntimeDocs.xml" path="Runtimefunctions/aelement/*" />
FUNCTION AElement(ArrayName AS __FoxArray, nRowSubscript AS DWORD, nColumnSubscript AS DWORD) AS USUAL
    IF ArrayName:MultiDimensional
        IF nRowSubscript == 0 .OR. nRowSubscript >  ArrayName:Rows
           var cMessage := __VfpStr(VFPErrors.ATTRIBUTE_OUT_OF_RANGE,nameof(nRowSubscript))
           THROW ArgumentOutOfRangeException { nameof(nRowSubscript), nRowSubscript, cMessage}
        ELSEIF nColumnSubscript == 0 .OR. nColumnSubscript > ArrayName:Columns
           var cMessage := __VfpStr(VFPErrors.ATTRIBUTE_OUT_OF_RANGE,nameof(nColumnSubscript))
           THROW ArgumentOutOfRangeException { nameof(nColumnSubscript), nColumnSubscript, cMessage }
        ENDIF
        nRowSubscript --
        RETURN ( nRowSubscript * ArrayName:Columns ) + nColumnSubscript
    ENDIF
    THROW ArgumentException { __VfpStr(VFPErrors.ONE_DIM_NO_COLUMNS)}

/// <exclude/>
FUNCTION __FoxADel(foxArray AS __FoxArray, nElementNumber AS LONG, nDeleteType := 2 AS LONG)
    IF ! foxArray:MultiDimensional
        foxArray:Delete((LONG) nElementNumber)
    ELSE
        IF nDeleteType == 2
            foxArray:DeleteColumn( (LONG) nElementNumber)
        ELSE
            foxArray:DeleteRow((LONG) nElementNumber)
        ENDIF
    ENDIF
    RETURN 1

/// <include file="VfpRuntimeDocs.xml" path="Runtimefunctions/adel/*" />
FUNCTION ADel(foxArray AS __FoxArray, nElementNumber AS LONG, nDeleteType := 2 AS LONG) AS DWORD
    RETURN __FoxADel(foxArray, nElementNumber, nDeleteType)

/// <include file="VfpRuntimeDocs.xml" path="Runtimefunctions/adel/*" />
/// <remarks>The parameter to this function is a 'General Array'. The function decides at runtime if the array is a FoxPro array or a 'General' Array</remarks>
FUNCTION ADel(ArrayName AS ARRAY, nElementNumber AS LONG, nDeleteType AS LONG) AS DWORD
    IF ! ArrayName IS __FoxArray VAR foxArray
        XSharp.RT.Functions.ADel(ArrayName, (DWORD) nElementNumber )
        RETURN 1
    ENDIF
    RETURN __FoxADel(foxArray, nElementNumber, nDeleteType)

/// <include file="VfpRuntimeDocs.xml" path="Runtimefunctions/asubscript/*" />
FUNCTION ASubScript(ArrayName AS __FoxArray, nElementNumber AS DWORD, nSubscript := 1 AS DWORD) AS DWORD
    IF nSubscript == 0 .OR. nSubscript > 2
        var cMessage := __VfpStr(VFPErrors.ATTRIBUTE_OUT_OF_RANGE, nameof(nSubscript))
        THROW ArgumentOutOfRangeException { nameof(nSubscript), nSubscript, cMessage }
    ELSEIF nElementNumber == 0 .OR. nElementNumber >  ArrayName:Count
        var cMessage := __VfpStr(VFPErrors.ATTRIBUTE_OUT_OF_RANGE, nameof(nElementNumber))
        THROW ArgumentOutOfRangeException { nameof(nElementNumber), nElementNumber, cMessage }
    ENDIF

    IF ArrayName:MultiDimensional

        IF nSubscript == 1

            // calculate the row

            // doesn't compile because GetRow() is a internal method
            RETURN (DWORD) ArrayName:GetRow((LONG) nElementNumber)

        ELSE
            // calculate the column
            RETURN (DWORD) ArrayName:GetColumn((LONG) nElementNumber)

        ENDIF

    ELSE

        IF nSubscript == 2
            THROW ArgumentException { __VfpStr(VFPErrors.ONE_DIM_NO_COLUMNS)}
        ENDIF

        RETURN nElementNumber

    ENDIF

/// <exclude/>
FUNCTION __FoxAIns(foxArray AS __FoxArray, nElementNumber AS DWORD, nInsertType := 1 AS DWORD) AS DWORD
    IF !foxArray:MultiDimensional
        IF nInsertType > 1
            THROW ArgumentException { __VfpStr(VFPErrors.ONE_DIM_NO_COLUMNS)}
        ELSEIF nElementNumber == 0 .OR. nElementNumber > (DWORD) foxArray:Count
            THROW ArgumentOutOfRangeException { nameof(nElementNumber), nElementNumber, __VfpStr(VFPErrors.ATTRIBUTE_OUT_OF_RANGE, nameof(nElementNumber)) }
        ENDIF

        foxArray:Insert((LONG) nElementNumber)
    ELSE
        IF nInsertType > 2
            THROW ArgumentOutOfRangeException { nameof(nInsertType), nInsertType, __VfpStr(VFPErrors.ATTRIBUTE_OUT_OF_RANGE, nameof(nInsertType)) }
        ENDIF
        IF nInsertType == 2
            IF nElementNumber == 0 .OR. nElementNumber > (DWORD) foxArray:Columns
                THROW ArgumentOutOfRangeException { nameof(nElementNumber), nElementNumber, __VfpStr(VFPErrors.ATTRIBUTE_OUT_OF_RANGE, nameof(nElementNumber)) }
            ENDIF

            foxArray:InsertColumn( (LONG) nElementNumber)
        ELSE
            IF nElementNumber == 0 .OR. nElementNumber > (DWORD) foxArray:Rows
                THROW ArgumentOutOfRangeException { nameof(nElementNumber), nElementNumber, __VfpStr(VFPErrors.ATTRIBUTE_OUT_OF_RANGE, nameof(nElementNumber))}
            ENDIF

            foxArray:InsertRow((LONG) nElementNumber)
        ENDIF
    ENDIF
    RETURN 1

/// <include file="VfpRuntimeDocs.xml" path="Runtimefunctions/ains/*" />
FUNCTION AIns(ArrayName AS __FoxArray, nElementNumber AS DWORD, nInsertType := 1 AS DWORD) AS DWORD
    RETURN __FoxAIns(ArrayName, nElementNumber, nInsertType)

/// <include file="VfpRuntimeDocs.xml" path="Runtimefunctions/ains/*" />
/// <remarks>The parameter to this function is a 'General Array'. The function decides at runtime if the array is a FoxPro array or a 'General' Array</remarks>
FUNCTION AIns(ArrayName AS ARRAY, nElementNumber AS DWORD, nInsertType AS DWORD) AS DWORD
    IF ! ArrayName IS __FoxArray VAR foxArray
        XSharp.RT.Functions.AIns(ArrayName, nElementNumber)
        RETURN 1
    ENDIF
    RETURN __FoxAIns(foxArray, nElementNumber, nInsertType)

/// <include file="VfpRuntimeDocs.xml" path="Runtimefunctions/asize/*" />
/// <remarks>The parameter to this function is a 'General Array'. The function decides at runtime if the array is a FoxPro array or a 'General' Array</remarks>
FUNCTION ASize(ArrayName AS ARRAY, nSize AS DWORD) AS ARRAY
    IF ! ArrayName IS __FoxArray VAR foxArray
        RETURN XSharp.RT.Functions.ASize(ArrayName, nSize)
    ENDIF
    foxArray:Resize((LONG) nSize)
    RETURN foxArray

/// <inheritdoc cref="ShowArray" />
FUNCTION ShowFoxArray ( aTest AS __FoxArray , cPrefix := "" AS STRING ) AS VOID
    LOCAL i, j AS DWORD
    LOCAL cLDelim as STRING
    LOCAL cRDelim as STRING
    IF cPrefix:Length == 0
        cPrefix := "a"
    ENDIF
    IF XSharp.RuntimeState.CompilerOptionFox2
        cLDelim := "("
        cRDelim := ")"
    ELSE
        cLDelim := "["
        cRDelim := "]"
    ENDIF

    IF aTest:MultiDimensional
        FOR i := 1 TO ALen ( aTest , 1 )
            FOR j := 1 TO ALen ( aTest , 2 )
                 //var line := i"{cPrefix}{cLDelim}{AElement ( aTest , i , j )}{cRDelim} {cLDelim}{i},{j}{cRDelim} {aTest[i,j]} {GetElementValueType ( aTest[i,j] )}"
                 var line := i"{cPrefix}{cLDelim}{i},{j}{cRDelim} = {aTest[i,j]} {GetElementValueType ( aTest[i,j] )}"
                 QOut(line)
            NEXT
        NEXT
    ELSE
        FOR i := 1 TO ALen ( aTest , 0 )
            var line := i"{cPrefix}{cLDelim}{i}{cRDelim} = {aTest[i]}  {GetElementValueType ( aTest[i] )}"
            QOut(line)
        NEXT
    ENDIF

    LOCAL FUNCTION GetElementValueType( uValue AS USUAL ) AS STRING
        IF IsNil ( uValue )
            RETURN "(Nil)"
        ELSE
            RETURN "(" + ValType ( uValue ) + ")"
        ENDIF

        END FUNCTION

RETURN

END FUNCTION

//
// Copyright (c) XSharp B.V.  All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
// See License.txt in the project root for license information.
//

USING XSharp.Internal

/// <include file="VfpRuntimeDocs.xml" path="Runtimefunctions/alen/*" />
FUNCTION ALen(a AS __FoxArray) AS DWORD
    RETURN ALen(a, 0)

/// <include file="VfpRuntimeDocs.xml" path="Runtimefunctions/alen/*" />
FUNCTION ALen(a AS __FoxArray, nArrayAttribute AS LONG) AS DWORD
    SWITCH nArrayAttribute
    CASE 1
        RETURN (DWORD) a:Rows
    CASE 2
        IF a:MultiDimensional
            RETURN (DWORD) a:Columns
        ELSE
            RETURN 0
        ENDIF
    CASE 0
            RETURN (DWORD) a:Count
    OTHERWISE
        var cMessage := __VfpStr(VFPErrors.ATTRIBUTE_OUT_OF_RANGE, nameof(nArrayAttribute))
        THROW ArgumentOutOfRangeException { nameof(nArrayAttribute),nArrayAttribute, cMessage}
    END SWITCH

/// <exclude/>
FUNCTION __FoxALen(a AS __FoxArray) AS DWORD
    RETURN ALen(a, 0)

/// <include file="VfpRuntimeDocs.xml" path="Runtimefunctions/aelement/*" />
FUNCTION AElement(ArrayName AS __FoxArray, nRowSubscript AS DWORD) AS USUAL
   IF ( nRowSubscript > 0 .AND. nRowSubscript <= ArrayName:Rows )
      RETURN nRowSubscript
   ENDIF
   var cMessage := __VfpStr(VFPErrors.ATTRIBUTE_OUT_OF_RANGE, nameof(nRowSubscript))
   THROW ArgumentOutOfRangeException { nameof(nRowSubscript),nRowSubscript, cMessage}

/// <include file="VfpRuntimeDocs.xml" path="Runtimefunctions/aelement/*" />
FUNCTION AElement(ArrayName AS __FoxArray, nRowSubscript AS DWORD, nColumnSubscript AS DWORD) AS USUAL
    IF ArrayName:MultiDimensional
        IF nRowSubscript == 0 .OR. nRowSubscript >  ArrayName:Rows
           var cMessage := __VfpStr(VFPErrors.ATTRIBUTE_OUT_OF_RANGE,nameof(nRowSubscript))
           THROW ArgumentOutOfRangeException { nameof(nRowSubscript), nRowSubscript, cMessage}
        ELSEIF nColumnSubscript == 0 .OR. nColumnSubscript > ArrayName:Columns
           var cMessage := __VfpStr(VFPErrors.ATTRIBUTE_OUT_OF_RANGE,nameof(nColumnSubscript))
           THROW ArgumentOutOfRangeException { nameof(nColumnSubscript), nColumnSubscript, cMessage }
        ENDIF
        nRowSubscript --
        RETURN ( nRowSubscript * ArrayName:Columns ) + nColumnSubscript
    ENDIF
    THROW ArgumentException { __VfpStr(VFPErrors.ONE_DIM_NO_COLUMNS)}

/// <exclude/>
FUNCTION __FoxADel(foxArray AS __FoxArray, nElementNumber AS LONG, nDeleteType := 2 AS LONG)
    IF ! foxArray:MultiDimensional
        foxArray:Delete((LONG) nElementNumber)
    ELSE
        IF nDeleteType == 2
            foxArray:DeleteColumn( (LONG) nElementNumber)
        ELSE
            foxArray:DeleteRow((LONG) nElementNumber)
        ENDIF
    ENDIF
    RETURN 1

/// <include file="VfpRuntimeDocs.xml" path="Runtimefunctions/adel/*" />
FUNCTION ADel(foxArray AS __FoxArray, nElementNumber AS LONG, nDeleteType := 2 AS LONG) AS DWORD
    RETURN __FoxADel(foxArray, nElementNumber, nDeleteType)

/// <include file="VfpRuntimeDocs.xml" path="Runtimefunctions/adel/*" />
/// <remarks>The parameter to this function is a 'General Array'. The function decides at runtime if the array is a FoxPro array or a 'General' Array</remarks>
FUNCTION ADel(ArrayName AS ARRAY, nElementNumber AS LONG, nDeleteType AS LONG) AS DWORD
    IF ! ArrayName IS __FoxArray VAR foxArray
        XSharp.RT.Functions.ADel(ArrayName, (DWORD) nElementNumber )
        RETURN 1
    ENDIF
    RETURN __FoxADel(foxArray, nElementNumber, nDeleteType)

/// <include file="VfpRuntimeDocs.xml" path="Runtimefunctions/asubscript/*" />
FUNCTION ASubScript(ArrayName AS __FoxArray, nElementNumber AS DWORD, nSubscript := 1 AS DWORD) AS DWORD
    IF nSubscript == 0 .OR. nSubscript > 2
        var cMessage := __VfpStr(VFPErrors.ATTRIBUTE_OUT_OF_RANGE, nameof(nSubscript))
        THROW ArgumentOutOfRangeException { nameof(nSubscript), nSubscript, cMessage }
    ELSEIF nElementNumber == 0 .OR. nElementNumber >  ArrayName:Count
        var cMessage := __VfpStr(VFPErrors.ATTRIBUTE_OUT_OF_RANGE, nameof(nElementNumber))
        THROW ArgumentOutOfRangeException { nameof(nElementNumber), nElementNumber, cMessage }
    ENDIF

    IF ArrayName:MultiDimensional

        IF nSubscript == 1

            // calculate the row

            // doesn't compile because GetRow() is a internal method
            RETURN (DWORD) ArrayName:GetRow((LONG) nElementNumber)

        ELSE
            // calculate the column
            RETURN (DWORD) ArrayName:GetColumn((LONG) nElementNumber)

        ENDIF

    ELSE

        IF nSubscript == 2
            THROW ArgumentException { __VfpStr(VFPErrors.ONE_DIM_NO_COLUMNS)}
        ENDIF

        RETURN nElementNumber

    ENDIF

/// <exclude/>
FUNCTION __FoxAIns(foxArray AS __FoxArray, nElementNumber AS DWORD, nInsertType := 1 AS DWORD) AS DWORD
    IF !foxArray:MultiDimensional
        IF nInsertType > 1
            THROW ArgumentException { __VfpStr(VFPErrors.ONE_DIM_NO_COLUMNS)}
        ELSEIF nElementNumber == 0 .OR. nElementNumber > (DWORD) foxArray:Count
            THROW ArgumentOutOfRangeException { nameof(nElementNumber), nElementNumber, __VfpStr(VFPErrors.ATTRIBUTE_OUT_OF_RANGE, nameof(nElementNumber)) }
        ENDIF

        foxArray:Insert((LONG) nElementNumber)
    ELSE
        IF nInsertType > 2
            THROW ArgumentOutOfRangeException { nameof(nInsertType), nInsertType, __VfpStr(VFPErrors.ATTRIBUTE_OUT_OF_RANGE, nameof(nInsertType)) }
        ENDIF
        IF nInsertType == 2
            IF nElementNumber == 0 .OR. nElementNumber > (DWORD) foxArray:Columns
                THROW ArgumentOutOfRangeException { nameof(nElementNumber), nElementNumber, __VfpStr(VFPErrors.ATTRIBUTE_OUT_OF_RANGE, nameof(nElementNumber)) }
            ENDIF

            foxArray:InsertColumn( (LONG) nElementNumber)
        ELSE
            IF nElementNumber == 0 .OR. nElementNumber > (DWORD) foxArray:Rows
                THROW ArgumentOutOfRangeException { nameof(nElementNumber), nElementNumber, __VfpStr(VFPErrors.ATTRIBUTE_OUT_OF_RANGE, nameof(nElementNumber))}
            ENDIF

            foxArray:InsertRow((LONG) nElementNumber)
        ENDIF
    ENDIF
    RETURN 1

/// <include file="VfpRuntimeDocs.xml" path="Runtimefunctions/ains/*" />
FUNCTION AIns(ArrayName AS __FoxArray, nElementNumber AS DWORD, nInsertType := 1 AS DWORD) AS DWORD
    RETURN __FoxAIns(ArrayName, nElementNumber, nInsertType)

/// <include file="VfpRuntimeDocs.xml" path="Runtimefunctions/ains/*" />
/// <remarks>The parameter to this function is a 'General Array'. The function decides at runtime if the array is a FoxPro array or a 'General' Array</remarks>
FUNCTION AIns(ArrayName AS ARRAY, nElementNumber AS DWORD, nInsertType AS DWORD) AS DWORD
    IF ! ArrayName IS __FoxArray VAR foxArray
        XSharp.RT.Functions.AIns(ArrayName, nElementNumber)
        RETURN 1
    ENDIF
    RETURN __FoxAIns(foxArray, nElementNumber, nInsertType)

/// <include file="VfpRuntimeDocs.xml" path="Runtimefunctions/asize/*" />
/// <remarks>The parameter to this function is a 'General Array'. The function decides at runtime if the array is a FoxPro array or a 'General' Array</remarks>
FUNCTION ASize(ArrayName AS ARRAY, nSize AS DWORD) AS ARRAY
    IF ! ArrayName IS __FoxArray VAR foxArray
        RETURN XSharp.RT.Functions.ASize(ArrayName, nSize)
    ENDIF
    foxArray:Resize((LONG) nSize)
    RETURN foxArray

/// <inheritdoc cref="ShowArray" />
FUNCTION ShowFoxArray ( aTest AS __FoxArray , cPrefix := "" AS STRING ) AS VOID
    LOCAL i, j AS DWORD

    IF cPrefix:Length == 0
        cPrefix := "a"
    ENDIF

    IF aTest:MultiDimensional
        FOR i := 1 TO ALen ( aTest , 1 )
            FOR j := 1 TO ALen ( aTest , 2 )
                 QOut(cPrefix + "[" + AsString(AElement ( aTest , i , j )) + "] [" + i:ToString() + "," + j:ToString() + "] = " + AsString ( aTest [i,j] ) + ;
                     " " + GetElementValueType ( aTest[i,j] ))
            NEXT
        NEXT
    ELSE
        FOR i := 1 TO ALen ( aTest , 0 )
            QOut( cPrefix + "[" + i:ToString() + "] = " + AsString ( aTest [i] ) + " " + GetElementValueType ( aTest[i] ))
        NEXT
    ENDIF

    LOCAL FUNCTION GetElementValueType( uValue AS USUAL ) AS STRING
        IF IsNil ( uValue )
            RETURN "(Nil)"
        ELSE
            RETURN "(" + ValType ( uValue ) + ")"
        ENDIF

        END FUNCTION

RETURN

END FUNCTION