all-exports.php

<?php
array (
  'About.Scanner' => 
  array (
    'key' => 'About.Scanner',
    'exportline' => '@export(About.Scanner)',
    'comment' => '`Scanner` trait helps find (non-standard) magic methods in your classes, in order to automatically register events (and probably routes, views, global functions, and more).  
See `Actions` documentation for more information.',
  ),
  'TODO.Scanner' => 
  array (
    'key' => 'TODO.Scanner',
    'exportline' => '@export(TODO.Scanner)',
    'comment' => '- allow configuration of the prefix regex   
- Class property to auto-merge with built-in prefixes   
    - As an alternative to actionPrefixes() method  
- Document how to use prefixFor()',
  ),
  'Usage.Scanner.ScanFor' => 
  array (
    'key' => 'Usage.Scanner.ScanFor',
    'exportline' => '@export(Usage.Scanner.ScanFor)',
    'comment' => 'Call $scannerClass->scanFor($prefix) to get an array of all methods using that prefix.   
Your functions can bedfined as:  
- `prefix_methodName()` - prefix followed by `_` then upper or lower case  
- prefixMethodName - prefix followed by upper case  
  
Example:  
```php  
class Scannable {  
    use \\Liaison\\Scanner;  
    public function on_abigthing(){}  
    public function onSmallThing  
}  
$get = \\Scannable::scanFor(\'on\');  
print_r($get);  
/ will print, in no particular order:  
[ \'abigthing\' => \'on_abigthing\',  
  \'SmallThing\' => \'onSmallThing\'  
];  
```',
  ),
  'Usage.Scanner.ActionFor' => 
  array (
    'key' => 'Usage.Scanner.ActionFor',
    'exportline' => '@export(Usage.Scanner.ActionFor)',
    'comment' => 'Get the action for a given prefix. This lets prefixes be automatically scanned for & mapped to global functions through `Actions`. See `Actions` documentation for more information.  
  
To add more actions than what\'s built-in, override `actionFor` in your scannable class, then to fallback to the built-ins call `$this->Scanner_actionFor($prefix)`',
  ),
  'Usage.Scanner.ActionMap.Override' => 
  array (
    'key' => 'Usage.Scanner.ActionMap.Override',
    'exportline' => '@export(Usage.Scanner.ActionMap.Override)',
    'comment' => 'Call `$this->actionPrefixes()` to get a map of `prefix=>action`s that will be used for automatic scanning and for `actionFor()` method. Override it to provide your own map of prefixes to actions  
  
pass liaison to actionPrefixes() as the only paramater, or by declaring on your class a property `$liaison`, or property `$lia`, or exclude it if you don\'t need global prefixes via Liaison  
  
  
Return an array like `[\'prefix1\'=>\'action1\', \'prefix2\'=>\'action2\']`.   
To merge custom prefixes with built-in prefixes, call `$this->Scanner_actionPrefixes()`.   
  
Example: (in your class that uses the `Scanner` trait)  
```php  
protected function actionPrefixes(){  
    $builtIn = $this->Scanner_actionPrefixes();  
    $custom = [\'prefix1\'=>\'action1\', \'prefix2\'=>\'action2\'];  
    $all = array_merge($builtIn, $custom);  
    return $all;  
}  
```',
  ),
  'Usage.Scanner.AutoRegister' => 
  array (
    'key' => 'Usage.Scanner.AutoRegister',
    'exportline' => '@export(Usage.Scanner.AutoRegister)',
    'comment' => 'Call `$this->autoRegisterScannedPrefixes($liaison)` to automatically scan for prefixes defined in `actionPrefixes()` and register them to actions.   ',
  ),
  'old.About.Liaison' => 
  array (
    'key' => 'old.About.Liaison',
    'exportline' => '@export(old.About.Liaison)',
    'comment' => '# Liaison  
Liaison ties everything together. Packages & their components, view lookups, config values, routing, events, and more??  
  
## Basic Usage  
```php  
$lia = new \\Liaison();  
$lia->addPackage(  
    [\'dir\'=>__DIR__.\'/my-package/\',  
     \'name\'=>\'MyPackage\'  
     ]  
);  
$lia->deliver();  
```  
This will load files from your package and route appropriately.  
  
### $lia, Methods to know  
- deliver($url=null)  
    - uses the requested url by default, but you can pass in a url, which may include a get string like `?cats=cute`  
- addPackage($options): $options is an array  
    - dir: The root directory of your package  
    - name: The name to be used for retrieving your package.   
        -Each package must have a unique name  
- package($name): retrieve a package by name  
- packages(): A list of packages  
- compo($name): For each package, get any components named `$name`.   
    - 0 components found, return null, 1 component found, return the component, 2+ components found, throw an exception  
- set($key, $value) & get($key,$valueIfNotFound): Store & retrieve values across the $lia instance  
- view($name, $passthru): Get a view (from any package) by $name, passing $passthru to the view.  
    - See [Views](0-docs/Views.md) for more information  
- register($eventName, $object, $method=null): Register the event to be executed  
- send($eventName,$arg1, $arg2, $arg3, ....): Execute the given event, passing the list of args along.  
    - See [Events](0-docs/Events.md)',
  ),
  'About.Globals.Actions' => 
  array (
    'key' => 'About.Globals.Actions',
    'exportline' => '@export(About.Globals.Actions)',
    'comment' => 'Actions tie string keys to global functions. This allows global function (`$lia->sendEvent(\'EventName\')`) names to change (`$lia->emit(\'EventName\')`) while maintaining the same central key identifier (`event`).  
  
This is primarily to make the `Scanner` work in a robust & reliable way. Components declare actions to map to instead of global functions, and hopefully this is good future-proofing.',
  ),
  'TODO.Globals.Actions' => 
  array (
    'key' => 'TODO.Globals.Actions',
    'exportline' => '@export(TODO.Globals.Actions)',
    'comment' => '- Improve documentation  
- Improve performance of addGlobal() function...  
- in the derive method, $deriver is a string representing the global function. Need to check if this global function has been set before trying to call it.  
- in the invoke method, $invoker is a string representing the global function. Need to check if this global function has been set before trying to call it.  
    - Might not care for this, since my exceptions are nice now... (Though this doesn\'t throw an exception, does it? )  
    - Maybe I just need to check to make sure it is a string?',
  ),
  'Usage.Globals.addGlobal' => 
  array (
    'key' => 'Usage.Globals.addGlobal',
    'exportline' => '@export(Usage.Globals.addGlobal)',
    'comment' => 'Adding a global action / prefix / function is basically the core of Liaison. It\'s what makes everything work. This is not very performant right now, due to many if statements  
This is the example usage with all the options.  
```php  
$lia->addGlobal([  
    \'action\'=>\'route\',  
    \'prefix\'=>\'rte\', // (optional) declare functions as rte_RouteName(){} or rteRouteName(){} in your components  
                 // a `rte_Blog(){}` method in a `$component` will ultimately call:  
                     // $routerObject->setupRoute(\'Blog\', [$component,\'rte_Blog\'])  
    //\'strict\'=>false, // to disable most errors. Don\'t use this (normally). Strict is \'true\' by default.  
    \\Liaison::DERIVER=>[ // $liaison->derive(\'route\',$RouteName, $callback) will call the callable  
        \'name\'=>\'addRoute\', // $liaison->addRoute() will call the \'callable\'.  
        \'callable\'=>[$routerObject,\'setupRoute\'],   
        //\'strict\'=>false //If \'addRoute\' has already been set globally, strict=false will overwrite  
    ],  
    \\Liaison::INVOKER=>[ //$liaison->invoke(\'route\', $url) will call $liaison->deliverRoute($url);  
        \'name\'=>\'deliverRoute\', //$liaison->deliverRoute() will call $routerObject->deliver()  
        \'callable\'=>[$routerObject,\'deliver\'],  
        //\'strict\'=>true //the default, will throw if global function \'deliverRoute\' already exists  
    ]  
    \\Liaison::ADDER=>[  
         THIS NEEDS TO BE FILLED OUT & DOCUMENTED  
    ]  
]);  
```',
  ),
  'Usage.Globals.mapActionToFunction' => 
  array (
    'key' => 'Usage.Globals.mapActionToFunction',
    'exportline' => '@export(Usage.Globals.mapActionToFunction)',
    'comment' => 'Call `$lia->mapActionToFunction($actionKey, \'register\' or \'invoke\', $globalFunctionName)` so that scannable components can automatically register methods to your global function.  
Generally, you will call this immediately after `register`ing a function.  
Simple `events` example:  
```php  
$action = \'event\';  
$liaison->addGlobalFunction(\'schedule\',  
    //we\'d reference this class method like: [$eventClass, \'schedule\']  
    public function schedule($eventName, $callback) use (&$events){  
        $this->events[$eventName] = $callback;  
    }  
);  
$liaison->mapActionToFunction(\'event\', \'register\', \'schedule\');  
```  
Using it:  
```php  
/now, calling:  
$liaison->addGlobalFunction(\'event\', \'Request.Started\', $setupUserFunction);  
/will call $eventClass->schedule(\'Request.Started\', $setupUserFunction);  
```  
Without the action mapping, you could only call it through liaison with:  
```php  
$liaison->schedule(\'EventName\', $setupUserFunction);  
```  
which would be fine normally, but what if `$eventClass` decides to change it\'s global function to `scheduleEvent` instead of `schedule`? The action mapping allows that to happen, without breaking anything.',
  ),
  'Usage.Globals.derive' => 
  array (
    'key' => 'Usage.Globals.derive',
    'exportline' => '@export(Usage.Globals.derive)',
    'comment' => 'Call `$lia->derive($actionName, ...$args)` to derive to a global action.   
Usually, this will be done by the component class & Scanner trait automatically. Thus it is unlikely you will ever need to call `derive()`  
  
To utilize with a global Scanner prefix, the global function must accept a `function($key, $callback)`... (Sorry, I know this isn\'t clear...)',
  ),
  'Usage.Globals.invoke' => 
  array (
    'key' => 'Usage.Globals.invoke',
    'exportline' => '@export(Usage.Globals.invoke)',
    'comment' => 'Call `$lia->invoke($actionName, ...$arguments)` to call a global function via it\'s action name.  
  
Internal Liaison components will likely use `invoke`, as these need to be robust & survive changes caused by extensions & future changes.  
If you\'re developing a Liaison extension, it might be good to use `invoke` as well, for more robust...ness  
If you\'re using Liaison for a website & you\'re in control of the extensions, it\'s probably easier (& less confusing) to just call the global function directly.',
  ),
  'Usage.Globals.add' => 
  array (
    'key' => 'Usage.Globals.add',
    'exportline' => '@export(Usage.Globals.add)',
    'comment' => 'Call `$lia->add($actionName, ...$arguments)` to... essentially load `...$arguments` into the `$actionName`   
         which will likely be used by the invoker of that action. (Sorry, I know this is poorly documented)',
  ),
  'TODO.Debug' => 
  array (
    'key' => 'TODO.Debug',
    'exportline' => '@export(TODO.Debug)',
    'comment' => '- Add `$lia->enableDebugging()` if I think it\'s a good idea.  
- make `debug` a read-only public property  
- consider just returning when debug is disabled, instead of throwing.  
- Document buffering the stack  
- Document examples of debugging   
- Document using the debugger inside an extensions, with examples  
- Review the documentation for accuracy',
  ),
  'Usage.Debug.subStack' => 
  array (
    'key' => 'Usage.Debug.subStack',
    'exportline' => '@export(Usage.Debug.subStack)',
    'comment' => 'Substacks can help make a debug entry easier to understand. This needs better documentation',
  ),
  'Usage.Debug.debug' => 
  array (
    'key' => 'Usage.Debug.debug',
    'exportline' => '@export(Usage.Debug.debug)',
    'comment' => 'To enable debugging: `$lia = new \\Liaison([\'debug\'=>true]);`  
Call `debug($debugGroup)` to get the stack of items in the debug group. Call `inspect(\\Liaison::STACK)` to get a list of debugable groups currently in the stack.  
  
So far, it\'s \\Liaison::FUNCTIONS & \\Liaison::MEDIATORS, but this could change. The code will be consistent, these docs may not be.',
  ),
  'Usage.Debug.add' => 
  array (
    'key' => 'Usage.Debug.add',
    'exportline' => '@export(Usage.Debug.add)',
    'comment' => 'To add a debug item to the stack, if `$lia->debug` is true, call `$lia->addDebug(string $debugGroup, string $action, array $extraArgs)`.    
Example:    
```php  
if ($this->debug){  
    $this->addDebug(\\Liaison::FUNCTIONS, \'register\', [\'function\'=>$functionName]);  
}  
```',
  ),
  'Usage.Debug.inspect' => 
  array (
    'key' => 'Usage.Debug.inspect',
    'exportline' => '@export(Usage.Debug.inspect)',
    'comment' => 'To find out what all has been registered to liaison, call `$lia->inspect()`. With no paramaters (or an invalid paramater), you\'ll receive a list of items that can be inspect.    
Then call `$lia->inspect(\\Liaison::THE_ITEM)` to inspect the specific thing you\'re interested in, such as FUNCTIONS, MEDIATORS, CONFIG, etc.     
You can also pass THE_ITEM as a string.  
  
Returned is an array w/ \'message\' (string), and \'items\' (array)',
  ),
  'TODO.Filters' => 
  array (
    'key' => 'TODO.Filters',
    'exportline' => '@export(TODO.Filters)',
    'comment' => '- declare and document more filters (Should I document them here or in the place where they\'re declared? Yes.)  
- Document examples',
  ),
  'Usage.Filters.Execute' => 
  array (
    'key' => 'Usage.Filters.Execute',
    'exportline' => '@export(Usage.Filters.Execute)',
    'comment' => 'Remove unwanted array items with custom filter functions.    
To execute the filter do `$filteredItems = $lia->filter($filterName, array $itemsToFilter, ...$extraParamaters);`  
  
  
See the [Filters Test](/test/Filters.php) for a thorough example.',
  ),
  'Usage.Filters.Add' => 
  array (
    'key' => 'Usage.Filters.Add',
    'exportline' => '@export(Usage.Filters.Add)',
    'comment' => 'Routes might frequently need some filtering that can\'t be reliably provided by liaison, such as if you declare dynamic routes that sometimes conflict with static routes.  
  
Your filter function can accept bound arguments prior to the filterable array of items. See the [Filters Test](8-build/test/Filters.php) for a full example.  
Example:    
```php  
$priorityBaseUrl = \'/blog/\';  
$lia->addFilter(Router.routes, [$yourObject, \'removeDynamicRoutes\'], $priorityBaseUrl);  
/any args after the callable will be passed to your callback before the filterable array of items and subsequent paramaters that are passed when filter() is called  
```  
Then `removeDynamicRoutes` would be:  
```php  
public function removeDynamicRoutes($priorityBaseUrl, array $routes, $url){  
    if ($url does-not-start-with $priorityBaseUrl)return $routes; //We will only filter for \'/blog/\' urls  
    $ret = [];  
    foreach ($routes as $r){  
        if ($r is-a-dynamic-route)continue;  
        $ret[] = $r;  
    }  
    if (count($ret)>0)return $ret;  
    else return $routes;  
}  
```',
  ),
  'Usage.Filters.Sort' => 
  array (
    'key' => 'Usage.Filters.Sort',
    'exportline' => '@export(Usage.Filters.Sort)',
    'comment' => 'In case you have added multiple filters for the same name, you can sort the order in which they execute.    
Your callback will be like `function(...$boundArgs, array $filterObjects)`    
- The $filterObjects will be an array of `\\Lia\\Utility\\FancyClosure` objects  
And you add the filter with `$lia->sortFilter($name, $callback, ...$boundArgs)`    
You don\'t have to pass bound args.  
  
See the [Filters Test](8-build/test/Filters.php) for an example.',
  ),
  'About.Functions' => 
  array (
    'key' => 'About.Functions',
    'exportline' => '@export(About.Functions)',
    'comment' => 'Functions can be registered to Liaison, to share functionality across a set of packages. The core components like `Router` and `Events` do this to make functions like `$lia->addRoute()` and `$lia->emit()` available everywhere.',
  ),
  'TODO.Functions' => 
  array (
    'key' => 'TODO.Functions',
    'exportline' => '@export(TODO.Functions)',
    'comment' => '- Consider removing action-function mapping when unRegistering global function  
    - Consider removing global prefix as well  
- Add conflict resolution for duplicate global prefixes  
- Add error handling or conflict resolution when there is a duplicate mediator',
  ),
  'Usage.Functions.mediate' => 
  array (
    'key' => 'Usage.Functions.mediate',
    'exportline' => '@export(Usage.Functions.mediate)',
    'comment' => 'If `register` is called for the same name twice, you can either modify your code to use reRegister/unRegister or you can add a mediator function.    
You can either mediate by the exact function name or use `*` (wildcard) as the function name to handle all function registrations that don\'t have a named mediator.    
You call `$lia->mediate($functionName, function($functionName,$oldCallback, $newCallback){return oneCallback;}`  
  
Example:    
```php  
$helloMediator =   
function($functionName, $oldCallback, $newCallback){  
    if ($newCallback[1]==\'hola\')return $newCallback;  
    return $oldCallback;  
}  
$lia->mediate(\'*\', $functionThatAlwaysReturnsTheNewCallback); //this only gets called if there is not a named mediator, so it won\'t be used in this example.  
$lia->mediate(\'hello\',$someRandomFunction); //this is replaced by the next call, with no errors  
$lia->mediate(\'hello\',$helloMediator);   
  
$lia->addGlobalFunction(\'hello\',[$this,\'hello\']); // echo "hello {$name}"  
$lia->addGlobalFunction(\'hello\',[$this,\'hola\']);   
$lia->addGlobalFunction(\'hello\',[$this,\'hallo\']);  
  
$lia->hello("Friend");  
/echos `¡Hola Friend!`  
```  
calling mediate twice with the same function name will replace the existing mediate function. No errors.',
  ),
  'Usage.Functions.register' => 
  array (
    'key' => 'Usage.Functions.register',
    'exportline' => '@export(Usage.Functions.register)',
    'comment' => 'Register a global function by calling `$lia->addGlobalFunction($functionName, $callback, $options)`. Your function can then be called with $lia->$functionName().   
- call addGlobalFunction(\'name\') twice throws an error  
- call removeGlobalFunction(\'name\') to safely call addGlobalFunction() again  
- call reRegister(\'name\', $function) to safely register $function without exceptions  
- Use a mediator to fine-tune duplicate register(\'name\') calls  
  
Example:    
```php  
$lia->addGlobalFunction(\'schedule\',   
    function($eventName, $callback){  
        echo "We scheduled {$eventName}!";  
        $this->events[$eventName][] = $callback;  
    },  
     //options array is optional  
    [ \'action\'=>\'event\', //if action is added, \'type\' is required  
      \'type\'  =>\\Liaison::DERIVER, //DERIVER, ADDER, or INVOKER. The invoker will handle an event being emitted  
      \'prefix\'=>\'on\' //Prefix is optional, but requires \'action\' be set. components declaring onSetup() will automatically register to the \'Setup\' event  
    ]  
)  
$lia->schedule("Setup", $userSigninHandler); // when $lia->emit("Setup") is called, the user sign-in handler will be called  
/ \'emit\' would also be registered in the same way \'schedule\' is above.  
$lia->addGlobalFunction(\'schedule\', function(){}) //throws a \\Lia\\Exception\\Duplicate  
```  
  
You may pass a `function(){}`, a `string $functionName`, a `$callable == [\'className\', \'staticFunctionName\']`, a `$callable == [$object, \'methodName\']`, or any object that implements `__invoke`.  
  
See Utility documentation for `FancyClosure` if you need to bind additional paramaters to your callable.',
  ),
  'Usage.Functions.reRegister' => 
  array (
    'key' => 'Usage.Functions.reRegister',
    'exportline' => '@export(Usage.Functions.reRegister)',
    'comment' => 'Reregister simply calls `$lia->removeGlobalFunction($functionName); $lia->addGlobalFunction($functionName, $callable)`.    
Example:  
```php  
$lia->addGlobalFunction(\'hello\', function($name){echo "Hello {$name}!";});  
$lia->replaceGlobalFunction(\'hello\', function($name){echo "¡Hola {$name}!";});  
$lia->hello(\'Reed\');  
/echos `¡Hola Reed!`  
```  
Don\'t worry, if you use `reRegister` when nothing has been registered to that name, the `unRegister` call won\'t hurt anything.',
  ),
  'Usage.Functions.unRegister' => 
  array (
    'key' => 'Usage.Functions.unRegister',
    'exportline' => '@export(Usage.Functions.unRegister)',
    'comment' => 'Unregister a previously registered function with `$lia->removeGlobalFunction($functionName)`. You can then call `$lia->addGlobalFunction()` for the same function name.',
  ),
  'TODO.RouteObject' => 
  array (
    'key' => 'TODO.RouteObject',
    'exportline' => '@export(TODO.RouteObject)',
    'comment' => '- Document the route object',
  ),
  'TODO.View' => 
  array (
    'key' => 'TODO.View',
    'exportline' => '@export(TODO.View)',
    'comment' => '- Config to set a namespace for all views of a given package  
- perhaps $lia should be a required paramater, not hidden in an array  
- Add an init + template approach like `view/Blog/template.php` and `view/Blog/init.php`  
- Add automatic routing via the view system (which is more robust and neat than simple public-files), such as with a `public-view` dir   
    - a `<lia-route pattern="/"> might be a valid option, but that seems more like an extension feature than a core feature  
- Document what paramaters are always available to views  
- Implement a way to pass certain paramaters to every view of a package. $lia & $package are already passed, always, but this should be extensible to allow views to automatically have access to paramaters  
- Document an example of a view file\'s code (such as the example blog.php view)  
- For sibling resource files (view/blog.php, view/blog.css, view/blog.js), resources() returns \'.js\' and \'.css\' for the resource files.   
    - Maybe they should have real names? But the current setup prevents conflicts between view/blog.css and view/blog/blog.css  
- Document resources() function & returned array',
  ),
  'Usage.View.Packaged' => 
  array (
    'key' => 'Usage.View.Packaged',
    'exportline' => '@export(Usage.View.Packaged)',
    'comment' => 'Views are defined in your package and can follow one of two different structures  
```  
public/ ... public files  
view/  
    - Blog.php  
    - Blog.js  
    - Blog.css  
    - Theme.php  
    - Theme/  
        - main.js  
        - main.css  
        - extra/ ... contains a bunch more css & js files  
```  
- Calling `$view = $lia->view(\'Theme\', $args)` will encompass `Theme.php` and load every single `.js` and `.css` file in the `Theme` directory  
- Calling `$view = $lia->view(\'Blog\', $args)` will encompass `Blog.php` for the view and load `Blog.js` and `Blog.css`  
    - @TODO implement these sibling-resource files (currnetly, only the sub-dir resource files work)  
- `$args` are `extract`ed so your `Theme.php` & `Blog.php` files receive the array keys as paramaters.  
- Resource files are loaded when you call `$view->resources()`, `$content = $view->content()`, or `$content = "".$view;` (tostring)  
- Place your view in a subdirectory like `view/Theme/Light.php` for a view named `Theme/Light`',
  ),
  'Old.View.Base' => 
  array (
    'key' => 'Old.View.Base',
    'exportline' => '@export(Old.View.Base)',
    'comment' => '## The View Object  
- Each package can implement their own view object and method of handling data. The following docs regard \\Lia\\View, used in the base package.  
- Generally, retrieve a view through liaison or the ViewHandler component.    
   - You may also do `new \\Lia\\View($viewPath,$data,$liaisonObject,$viewName=null)`, such as if you\'re creating your own package implementation.  
- Data passed in (through lia OR the constructor) will be `extract()`ed  
- The content is loaded in the constructor  
- Resources are loaded into liaison during the constructor. So you just call $lia->view($viewName), if all you want is to use the associated css & javascript resources.  
Display your view with `echo $view`  
  
### View Structure  
We have a view named "Form/Blog" at `view/Form/Blog/`. All your views go in the `view` directory and the path to the relative path to the view is it\'s name.  
```  
view/Form/Blog/  
 - init.php: (optional) code to run before the template  
 - template.php: (recommended) The PHP file to load, this is your html layout for the most part  
     - template.php & init.php are in the scope of the \\Lia\\View object that loads the files. Therefore, `$this` refers to the view object  
     - $lia, the Liaison object, is also available  
     - Uninentionally, $viewPath, $data, $viewName, & $path are available, but you should not rely on them. They will likely be removed.  
 - template.html: If a template.php file is not present, then template.html will be used.  
 - css/ (optional)  
     - BlogEditorStyle.css  
 - js/ (optional)  
     - BlogAutosaver.js  
```  
You don\'t actually have to have a template. css & js resources will still load  
  
Every css file in the css dir will be found and added to liaison through the `Red_AddStyleFile` event, which passes the absolute file path along to the event.  
Same for js, but `Res_AddScriptFile`.  ',
  ),
  'Utility.FancyClosure.TODO' => 
  array (
    'key' => 'Utility.FancyClosure.TODO',
    'exportline' => '@export(Utility.FancyClosure.TODO)',
    'comment' => '@TODO add check to see if a callable is actually callable  
@TODO setup read-only properties',
  ),
  'Utility.FancyClosure' => 
  array (
    'key' => 'Utility.FancyClosure',
    'exportline' => '@export(Utility.FancyClosure)',
    'comment' => 'Fancy closures enable binding of paramaters to a callable and inspection of callables, whether as `[\'\\\\StaticClass\',\'functionName\']`, `[$object, \'methodName\']`, or `$anonymousFunction = function(){}`.  
Example:    
```php  
$cat = new \\Funny\\Cat();  
$loudness = 7;  
$closure = new \\Lia\\Utility\\FancyClosure([$cat, \'purr\'], [$loudness]);  
$closure->funcName === \'purr\';  
$closure->object === $cat;  
$closure->class === \'Funny\\\\Cat\'; //it prints with a single slash, but backslashes are generally better off being escaped in my experience  
$closure->isStatic === false; // would be true for [\'Funny\\Cat\', \'purr\']  
$closure->isAnonymous === false; // would be true for function(){echo \'Kindness can be anonymous too.\';}  
$closure->function === null; // would be the anonymous function, if you had passed a function instead of a `[$obj, \'funcName\']` callable  
  
$closure->origCallable === [$cat, \'purr\']; //just the first arg you pass to the constructor  
$closure->bound === [$loudness]; // and this is the 2nd arg  
```',
  ),
  'TODO.Package' => 
  array (
    'key' => 'TODO.Package',
    'exportline' => '@export(TODO.Package)',
    'comment' => '- document the public dir  
- document the file-to-pattern conversion  
- document url normalization  
- Document changing the view class  
- Enable configs  
- autoloader is not necessarily available when package is costructed... Need to setup autoloading, though. Probably need package lifecycle methods or some kind of queuing system  
- Document general package usage  
- Document creating a custom package',
  ),
  'Usage.Router.publicDir' => 
  array (
    'key' => 'Usage.Router.publicDir',
    'exportline' => '@export(Usage.Router.publicDir)',
    'comment' => 'Files in the `public` dir of your package will be automatically routed to.  
- `public/index.php` files will be delivered without the file name or extension  
- `public/dir/file.php` files will be delivered at `/dir/file/`  
- `public/resource.js` and other non `.php` files will be delivered at `/resource.ext`  
  
There\'s much more to document and features to set up with routing, still. ',
  ),
  'Usage.Package.DefaultConfigs' => 
  array (
    'key' => 'Usage.Package.DefaultConfigs',
    'exportline' => '@export_end(Usage.Package.DefaultConfigs)',
    'comment' => 'protected $config = [  
    \'dir\'=>  
        [  
            \'component\' => \'core\',  
            // \'public\' => \'public\',  
            \'autoload\'=> \'class\',  
            \'view\' => \'view\',  
            \'cache\' => \'cache\',  
  
            \'public\'=>[  
                \'dir\' => \'public\',  
                \'baseUrl\'=> \'\',  
            ]  
        ],  
      
    \'route\'=>  
        [  
            \'force_trail_slash\'=>true,  
            \'index_names\'=>  
            [  
                \'index\'  
            ],  
            \'hidden_extensions\'=>  
            [  
                \'php\'  
            ],  
        ],  
    \'class\'=>  
        [  
            \'view\' => \'\\\\Lia\\\\Obj\\\\View\'  
        ],  
    \'views\'=>  
        [  
            \'conflict\' => \'throw\'  
        ]  
];',
  ),
  'Usage.View.AddView' => 
  array (
    'key' => 'Usage.View.AddView',
    'exportline' => '@export_end(Usage.View.AddView)',
    'comment' => '$lia = $this->lia;  
$dir = $this->dir(\'view\');  
$files = \\Lia\\Utility\\Files::all($dir,$dir, \'.php\');  
//set view conflict mode  
$lia->setViewConflictMode($this->config[\'views\'][\'conflict\'] ?? $lia->get(\'views.conflict\'));  
foreach ($files as $f){  
    $viewName = pathinfo($f,PATHINFO_FILENAME);  
    $class = $this->class(\'view\');  
    $dir = $dir;  
    $args =   
        [  
            \'lia\'=>$lia,  
            \'package\'=>$this  
        ];  
    $lia->addView($class, $dir, $viewName, $args);  
}',
  ),
  'TODO.Autoload' => 
  array (
    'key' => 'TODO.Autoload',
    'exportline' => '@export(TODO.Autoload)',
    'comment' => '- Add classmap-autoloading method (currently only PSR4 is supported, I think)  
- Cache autoloader classmap to disk  
- Document using autoloader component directly w/ addDir() & loadClass()',
  ),
  'Usage.Autoloader.Invoker' => 
  array (
    'key' => 'Usage.Autoloader.Invoker',
    'exportline' => '@export(Usage.Autoloader.Invoker)',
    'comment' => 'Use the built-in autoloader to load classes with the following structure:  
```  
hierarchy  
    - Contact/  
         - Submitter.php: namespace Contact, class Submitter  
    - Customer/  
         - Order.php, namespace Customer, class Order  
         - Person.php, ns Customer, cls Person  
flat  
    - Visa.php: ns Payment\\Processor, cls Visa  
    - Bitcoin.php: ns Payment\\Processor, cls Bitcoin  
    - Oauth.php: ns User\\Auth, cls Oauth  
```  
  
Load all of the above with the following:  
```php  
$dir = __DIR__;  
$lia->autoload($dir.\'/hierarchy\');  
$lia->autoload($dir.\'/flat\',[\'Payment\\\\Processor\', \'User\\\\Auth\'])  
```',
  ),
  'Usage.Autoloader.Adder' => 
  array (
    'key' => 'Usage.Autoloader.Adder',
    'exportline' => '@export(Usage.Autoloader.Adder)',
    'comment' => 'Call `$lia->addAutoloader($callback)` to add a custom autoloader. Example:  
```php  
$autoloader =   
     function($class) use ($customClassMap) {  
         $file = $customClassMap[$class] ?? null;  
         if ($file==null)return;  
         require_once($file);  
     };  
$lia->addAutoloader($autoloader);  
```  
Added autoloaders will be called in no particulary order. You can also just use `spl_autoload_register`, the built-in php function.',
  ),
  'Usage.Autoloader.Deriver' => 
  array (
    'key' => 'Usage.Autoloader.Deriver',
    'exportline' => '@export(Usage.Autoloader.Deriver)',
    'comment' => 'Add an autoloader in your component by declaring `autoloadFunctionName($class){}`. Example:  
  
```php  
class Blog extends \\Lia\\Compo {  
    $classMap = [\'Namespace\\\\ClassName\'=>\'/file/path\'];  
    public function autoloadBlogClasses($class){  
        if (isset($this->classMap[$class]))require_once($classMap[$class]);  
    }  
}  
```',
  ),
  'TODO.Error' => 
  array (
    'key' => 'TODO.Error',
    'exportline' => '@export(TODO.Error)',
    'comment' => '- Figure out how to do error handling...',
  ),
  'old.Event.Class' => 
  array (
    'key' => 'old.Event.Class',
    'exportline' => '@export(old.Event.Class)',
    'comment' => 'Events are the primary way that different packages and different parts of a package communicate with one another.    
Any component (using the base package) may declare `onNamespace_EventName($event,$arg1,$arg2,....)` to automatically have the event registered when the package is added.    
Namespaces aren\'t entirely required, but it\'s better that way.    
  
Each Event callable will receive an `$event` object. This object is always the same \\Lia\\Event component object. This needs to be improved.',
  ),
  'TODO.Events' => 
  array (
    'key' => 'TODO.Events',
    'exportline' => '@export(TODO.Events)',
    'comment' => '- Figure out how events are going to work  
- Implement an events directory, possibly  
- Rename register & send to schedule & emit  
- Should events offer return values? No, I don\'t think so',
  ),
  'old.Event.register' => 
  array (
    'key' => 'old.Event.register',
    'exportline' => '@export(old.Event.register)',
    'comment' => '- register($eventName, $object, $method=null): Register the event to be executed  
   - if `$method` is `null`, `$object` MUST have a method \'on$eventName\'  
   - if `$method` is a string, the a callable will be stored as [$object, $method]  
   - Uses the Event component of the base package  
   - The first paramater of your callback must take an `$event` object (which is poorly implemented)  
   - It may accept any paramaters after that, as specified by the registered event  
   - This might be renamed soon  
- send($eventName,$arg1, $arg2, $arg3, ....): Execute the given event, passing the list of args along.  
- has($eventName): check if event has been registered.',
  ),
  'old.Event.Events_Sort' => 
  array (
    'key' => 'old.Event.Events_Sort',
    'exportline' => '@export(old.Event.Events_Sort)',
    'comment' => 'When an event has multiple methods registered to it, the Events_Sort event is called, to allow you to filter which methods to execute.    
If you implement the Events_Sort event, you must return an array of all the events that should be executed.    
Your method should be like:  
```php  
onEvents_Sort($event,$EventName,$argsArray,$arrayOfEvents){  
    //unset one of the events because... the dog barked  
    return $arrayOfEvents;  
}  
```  
  
If there are multiple methods registered to Events_Sort... that\'s bad. It\'ll break stuff',
  ),
  'old.Events.ReturnValue' => 
  array (
    'key' => 'old.Events.ReturnValue',
    'exportline' => '@export(old.Events.ReturnValue)',
    'comment' => 'Return values from an event call depend upon how many events are registered and what they return.  
- 0 registered events: Return null  
- 1 registered event: Return the exact value returned by that event  
- 2+ registered events: Any return value === null will be discarded  
     - all other return values will be added to an array  
     - That null-filtered array will then be re-checked for 0 or 1 values  
     - If the null-filtered array has more than 1 value, an array of return values will be returned, in no intentional order.  
  
You may further refine this by registering to the event "Resolve{$EventName}".    
The resolve event will also follow the return value rules as listed here, so you could potentionally have an event like \'ResolveResolveResolveTooManyRegistered\'.    
Like, please don\'t do that? Lol. But you caaannn... I think.',
  ),
  'TODO.Resources' => 
  array (
    'key' => 'TODO.Resources',
    'exportline' => '@export(TODO.Resources)',
    'comment' => '- set page meta data like title, og:image, description, etc  
- Handle script & stylesheet URLs  
- Handle script & stylesheet code  
- Consider using custom routes instead of storing files in a cache-public dir  
- jsFiles & cssFiles arrays have the full file path as their key & value. Add ability to name the paths. This will improve dev experience when sorting a list of scripts/stylesheets  
- Improve sorting  
    - add sort preference to `addResourceFile($file)`. A Liaison extension that adds a JS framework would use this to ensure it\'s framework file is always the first thing.  
        - Without this, the sort burden is on the developer who is integrating the Liaison extension.  
- Document Resources...  
- Consider other methods of routing that might improve performance...  
- Remove duplication of code between CSS & JS compilation  
- Add url prefix for compiled files as a config option  
- move SEO code into it\'s own component  
- Use config for default site title  
- add all meta properties that are available...  
- Auto-add charset=utf8 & viewport meta tags (with config to disable)  
- Separate large files from the block of compiled code.   
     - If i\'m using a, say, 50KB or larger JS file on 10 different pages, but each of those pages has a couple different small JS files for their individual components, it\'s probably better to cache the 50KB file on its own  
- Minify js & css',
  ),
  'old.Resources.Events' => 
  array (
    'key' => 'old.Resources.Events',
    'exportline' => '@export(old.Resources.Events)',
    'comment' => 'Resources are stored through events & subsequently printed through them.    
   - You must do $lia->set(\'Resource.tempDir\',$tempDir) and $lia->set(\'Resource.pubDir\', $pubDir).    
       - The tempdir stores meta information about files (to prevent unnecessary recompilation)  
       - The pubdir is where your compiled files saved (and subsequently loaded from during the request)  
   - Script (and style) files are output in the order they\'re received. This is bad, but it\'s how things are right now.  
   - You MAY set `$lia->set(\'css.forceRecompile\',true)` and/or `$lia->set(\'js.forceRecompile\',true)` to force a recompile.  
       - file mod times are used to check if files need to be recompiled... but that can be finicky. This is also pretty inefficient.  
   - Nothing is minified, and file paths are put in comments in your compiled sheets... for debug reasons... another thing to fix.  
  
The Resource-related events are:    
- Meta Info:  
   - Res_SetPageTitle($title): Set the title for a given page  
- Styles:  
   - Res_AddStyleFile($filePath)  
   - Res_AddStyleCode($cssCode)  
   - Res_AddStyleURL($url)  
- Scripts:  
   - Res_AddScriptFile($filePath)  
   - Res_AddScriptCode($jsCode)  
   - Res_AddScriptURL($url)  
- Output:  
   - Res_PrintHeadResources: This compiles the resources and prints them out. Generally this event call would go in your <head> section  
  
Remember that Each event handler receives `$event` as the first paramater',
  ),
  'TODO.ViewComponent' => 
  array (
    'key' => 'TODO.ViewComponent',
    'exportline' => '@export(TODO.ViewComponent)',
    'comment' => '- document the use of a view that does NOT implement Lia\\IView  
- implement & document adding a view by simple file path',
  ),
  'TODO.Cache' => 
  array (
    'key' => 'TODO.Cache',
    'exportline' => '@export(TODO.Cache)',
    'comment' => '- Auto-delete expired cache-files  
    - Probably use a post-response hook (after content has been sent to the browser)  
    - And probably auto-delete if an expired file is requested  
- Possibly add `lia.cacheDir.public` & `lia.cacheDir.public.baseUrl` to assist in routing  
- Consider adding defaultExpiry as a config, rather than a default paramater in the cacheFile() function call  
- Are these the same thing?  
    - Consider function to return file content, not just file path. Consider additional decoding like parsing json or yaml.  
    - Consider adding type-based processing (PHP, JSON, DOMDocument??)  
    - Consider extensible features (such as auto en/decoding additional types not supported by Liaison)  
- cache response of getCacheFile() so files don\'t have to be loaded more than once',
  ),
  'Internals.Cache' => 
  array (
    'key' => 'Internals.Cache',
    'exportline' => '@export(Internals.Cache)',
    'comment' => 'Cache files can be used for whatever you like and are stored by key without file extensions, unless you give one to them. Namespaces are recommended.  
Two files are created when you cache a file: `file-ns.thekey` and `meta-ns.thekey`. The `meta-` file stores the expiry and may hold more information in the future. The `file-` stores the content.',
  ),
  'Usage.Cache.dir' => 
  array (
    'key' => 'Usage.Cache.dir',
    'exportline' => '@export(Usage.Cache.dir)',
    'comment' => 'There is both a public and private cache dir. Both of which are in Liaison\'s directory by default.  
- The cache is used by the Resources class to handle your compiled css and js files.   
  
To change the cachedir do:  
```php  
$lia->set(\'lia.cacheDir\', $yourPackage->dir(\'cache\'));  
```  
- You MAY use an explicit path instead of using your `$package->dir()` lookup  
- `lia.cacheDir` may be anywhere you like.',
  ),
  'Usage.Cache' => 
  array (
    'key' => 'Usage.Cache',
    'exportline' => '@export(Usage.Cache)',
    'comment' => 'Call `$lia->cacheFile($key, $content, $maxAgeInSeconds)` to store a file in the cache.  
   - You may leave off `$maxAgeInSeconds` to use the default, which is five days  
   - Cache files cannot be loaded after they expire and will be automatically cleaned up at some point.    
  
Call `$lia->getCacheFile($key)` to get the contetns of a cached file  
   - returns `false` if the cache file does not exist or has expired  
   - Files are returned as a string. JSON is not decoded. PHP files are not processed.',
  ),
  'TODO.Router' => 
  array (
    'key' => 'TODO.Router',
    'exportline' => '@export(TODO.Router)',
    'comment' => '- Document the paramaters that are passed to a public file  
- add a globalDeriver for object-oriented routing  
- add a built-in filter-routes method that prefers the least-dynamic route (no vars, or least number of vars)  
- improve \'Pattern Rules\' documentation  
- figure out sitemaps... Though that may not be part of router??  
  
- document examples of routing  
- caching of urls & routes  
- write up documentation into an MD file  
  
- auto-add `public` dir for each package  
- add a function to convert a file path to a pattern (aka, remove extensions like \'.md\' and \'.php\', per a configuration)  
- add a normalizeUrl function (add trailing slash, remove .php / .html / .md, all lowercase?)  
    
- Option to return both perfect-match routes AND routes that match with the normalized url, aka: /some/url && /some/url/ would return the same route(s)  
- add... something to help convert pattern-based routes to sitemap representations  
- create \'prefer-static\' feature that would only do regex-checks if a static match is NOT found.  
- add a mediator function to handle multiple global routers, possibly??  
- document how to use the Route object',
  ),
  'Usage.Router.addRoute' => 
  array (
    'key' => 'Usage.Router.addRoute',
    'exportline' => '@export(Usage.Router.addRoute)',
    'comment' => 'Call `$lia->addRoute($pattern, $callbackOrFile,$package=null)` to add a route to the built-in router  
  
```  
@param $pattern A pattern. See [the pattern matching rules](@link(Rules.Router.pattern))  
@param $callbackOrFile a callback or a file path  
@param $package (optional) A liaison package  
```',
  ),
  'Usage.Router.getRoute' => 
  array (
    'key' => 'Usage.Router.getRoute',
    'exportline' => '@export(Usage.Router.getRoute)',
    'comment' => 'Get a Route to work with as you please by calling `$lia->route($url, $method=\'GET\');`',
  ),
  'Rules.Router.pattern' => 
  array (
    'key' => 'Rules.Router.pattern',
    'exportline' => '@export(Rules.Router.pattern)',
    'comment' => '```  
rules:  
    .php will generally be removed & replaced with a trailing slash, but that is NOT part of parsePattern()  
    That will be a pattern-normalization step that happens prior to parsePattern() and is extensible/configurable  
  
    Methods: @POST, @GET, @PUT, @DELETE, @OPTIONS, @TRACE, @HEAD, @CONNECT  
        - We do not currently check the name of the method, just @ABCDEF for length 3-7  
        - These must appear after a `/` or after another \'@METHOD.\' or they will be taken literally  
        - lower case is not valid  
        - Each method MUST be followed by a period (.)  
        - example: /@POST.dir/sub/@GET.file/ is valid for both POST /dir/sub/file/ and GET /dir/sub/file   
  
  Paramaters:  
      - {under_scoreCamel} specifies a named, dynamic paramater  
      - {param} must be surrounded by path delimiters (/) OR periods (.) which will be literal characters in the url  
      - {param} MAY be at the end of a pattern with no trailing delimiter  
      - {paramName:regex} would specify a dynamic portion of a url that MUST match the given regex.   
          - Not currently implemented  
    examples:   
        /blog/{category}/{post} is valid for url /blog/black-lives/matter  
        /blog/{category}.{post}/ is valid for url /blog/environment.zero-waste/  
        /blog/{category}{post}/ is valid for url /blog/{category}{post}/ and has NO dynamic paramaters  
```',
  ),
  'TODO.Server' => 
  array (
    'key' => 'TODO.Server',
    'exportline' => '@export(TODO.Server)',
    'comment' => '- idk... finish building the class??  
- Graceful fallback for when view() is not available  
- Graceful fallback for when \'theme\' view is not available  
- When route is a callable, should the callable output content or should it return content that is echo\'d by Server?',
  ),
  'old.Route.rawFile' => 
  array (
    'key' => 'old.Route.rawFile',
    'exportline' => '@export(old.Route.rawFile)',
    'comment' => 'Routed files not otherwise handled will be sent, with the correct headers, including browser caching headers.    
Example: For file `public/funny/kitty.png`, url `/funny/kitty.png` will deliver the image file, as you would expect.    
Mimetypes (for headers) are derived from a PHP file internal to Liaison. It\'s not particularly efficient.  ',
  ),
  'Usage.Config.notes' => 
  array (
    'key' => 'Usage.Config.notes',
    'exportline' => '@export(Usage.Config.notes)',
    'comment' => '- `set($key, $val)` will override any previously set `$key`  
- `default($key, $val)` will never override `set()` or previous `default()` calls  
- `get($key)` will throw an exception if the `$key` has not been set',
  ),
  'TODO.Config' => 
  array (
    'key' => 'TODO.Config',
    'exportline' => '@export(TODO.Config)',
    'comment' => '- config file loading... set() should generally be able to override configs from the file  
- per-component &/or per-package configs (unless those aren\'t handled by this compo)  
- Do config file contents automatically get loaded into Liaison? Maybe, if they\'re namespaced, at least?  
- Does a package have it\'s own configs that are NOT Liaised? YES, or it could anyway  
    - Directories are one example of per-package configs  
- Should I limit access to set() & get(). NOT EARLY ON  
    - maybe in the future? I\'m concerned about performance, the time to implement, and how much it\'s actually needed (assuming you only run code you trust)  
- What happens if a config value is overridden? Error? Let it happen? Fail silently? Log?  
- add conflict resolution for duplicate config keys  
- consider a non-exception approach to a not-set config key',
  ),
  'Usage.Router.PatternCallback' => 
  array (
    'key' => 'Usage.Router.PatternCallback',
    'exportline' => '@export_end(Usage.Router.PatternCallback)',
    'comment' => '// Declare functions inside your component with the \'routePattern\' prefix, followed by an uppercase letter or underscore  
// I believe this implementation is going to change.  
public function routePatternBlog($route) {  
    if ($route===false)return [  
        \'/blog/{article}/\',  
        \'/blog/{article}\',  
        \'/about/{page}/\'  
    ];  
    $blogs = [  
        \'black-lives-matter\'=> \'Have you looked at traffic data in your home town? Is there a racial disparity?\',  
        \'toxic-pollution\' => \'The US EPA, under Trump, has rolled back many protections for U.S. citizens\',  
        \'us-voter-suppression\' => \'Why are mailboxes and mail-sorting machines being removed from cities? Why isn\\\'t the post office tax-payer funded?\',  
    ];  
    $abouts = [  
        \'me\'=>"Hi, I\'m Reed. I\'m an indie developer. I\'m very opinionated and wish the world were a better place."  
    ];  
    $var = $route->var(0);  
    if ($route->part(0)==\'about\'  
        &&isset($abouts[$var]))return $abouts[$var];  
    else if ($route->part(0)==\'blog\'  
        &&isset($blogs[$var]))return $blogs[$var];  
    else return "A blog was not found for \'{$var}\'";  
}',
  ),
  'Usage.View.AddViewCallable' => 
  array (
    'key' => 'Usage.View.AddViewCallable',
    'exportline' => '@export_end(Usage.View.AddViewCallable)',
    'comment' => '// This approach is extremely rudimentary and not recommended.  
$phrase = "Fight for your right to vote.";  
$lia->addViewCallable(\'theme\',  
    function($name, $args) use ($phrase){  
        return $phrase;  
    }  
);  
$content = $lia->view(\'theme\').\'\';',
  ),
  'Usage.Seo' => 
  array (
    'key' => 'Usage.Seo',
    'exportline' => '@export_end(Usage.Seo)',
    'comment' => '$lia->seoTitle(\'Test Page\');  
$lia->seoDescription(\'Test description\');  
$lia->seoImage(\'/path/to/image.jpg\', \'alt text for image\');  
$lia->seoUrl(\'/canonical/url/\');  
$lia->seoSiteName(\'Liaison test\');  
$html = $lia->getHeadHtml(); //includes script & stylesheet tags  
//You can alternatively use $lia->getSeoHtml(); ',
  ),
  'Usage.Seo.Output' => 
  array (
    'key' => 'Usage.Seo.Output',
    'exportline' => '@export_end(Usage.Seo.Output)',
    'comment' => '<title>Test Page</title>  
<meta property="og:title" content="Test Page" />  
  
<meta name="description" content="Test description" />  
<meta property="og:description" content="Test description" />  
  
<meta property="og:image" content="/path/to/image.jpg" />  
  
<meta property="og:image:alt" content="alt text for image" />  
  
<link rel="canonical" href="/canonical/url/" />  
<meta name="og:url" content="/canonical/url/" />  
  
<meta name="og:site_name" content="Liaison test" />',
  ),
  'Example.View.display' => 
  array (
    'key' => 'Example.View.display',
    'exportline' => '@export_end(Example.View.display)',
    'comment' => '//\'blog\' is the name of the view. The array is paramaters to pass to the view  
echo $lia->view(\'blog\',  
    [\'title\'=>\'About Liaison\',  
    \'summary\'=> \'Create full-GUI, packaged webapps that work with any PHP server\',  
    \'body\'=> "Liaison is it\'s own framework. You can use it for full websites or for GUI libraries.\\nIt\'s pre-alpha at time of writing this.\\n\\n-Sept 8, 2020"  
    ]  
);',
  ),
)
?>