diff --git a/doc/dist/etemplate2-rng.php b/doc/dist/etemplate2-rng.php deleted file mode 100644 index 5cb119b7c9..0000000000 --- a/doc/dist/etemplate2-rng.php +++ /dev/null @@ -1,238 +0,0 @@ -element->zeroOrMore->ref->attributes()['name'] = 'template'; - -$classes = []; -foreach($data['modules'] as $module) -{ - if (empty($module['exports'])) continue; - foreach($module['exports'] as $export) - { - if ($export['kind'] !== 'custom-element-definition' || preg_match('/_(ro|mobile)$/', $export['name'])) - { - $last_export = $export['name']; - continue; - } - foreach($module['declarations'] as $declaration) - { - if ($declaration['kind'] === 'class') - { - foreach(['members', 'attributes'] as $collection) - { - foreach($declaration[$collection] ?? [] as $key => $element) - { - $declaration[$collection][$element['name']] = $element; - unset($declaration[$collection][$key]); - } - } - $classes[$declaration['name']] = $declaration; - } - } - // some widgets use: customElements.defines(, as any, ...) - if ($export['declaration']['name'] === "anonymous_0") - { - $export['declaration']['name'] = $last_export; - } - /*echo $export['name'].'('.$export['declaration']['name'].'): '. - implode(', ', attributes($classes[$export['declaration']['name']]))."\n";*/ -/* - - - - - - - - - - - - - - - */ - if (in_array($export['name'], ['et2-tab', 'et2-tab-panel'])) - { - continue; // we use the legacy tabs and tabpanels - } - // add the element - $define = $grammar->addChild('define'); - $define->addAttribute('name', $export['name']); - $element = $define->addChild('element'); - $element->addAttribute('name', $export['name']); - $attrs = $element->addChild('ref'); - $attrs->addAttribute('name', 'attlist.'.$export['name']); - // add to widgets - $widgets->choice->addChild('ref')->addAttribute('name', $export['name']); - - // add the element-attributes - $attrs = $grammar->addChild('define'); - $attrs->addAttribute('name', 'attlist.'.$export['name']); - $attrs->addAttribute('combine', 'interleave'); - attributes($classes[$export['declaration']['name']], $attrs); - - // widget specific fixes - switch($export['name']) - { - case 'et2-tabbox': - // add legacy children tabs and tabpanels - $element->addChild('ref')->addAttribute('name', 'tabs'); - $element->addChild('ref')->addAttribute('name', 'tabpanels'); - break; - - default: - // dont allow children - $element->addChild('empty'); - break; - } - // remove corresponding legacy widget - removeWidget(str_replace('et2-', '', $export['name'])); - } -} - -$remove = []; -foreach($widgets->choice->children() as $widget) -{ - if (preg_match('/^(button|dropdown_button|int|float|menu|select|taglist|tree|passwd|date|time|ajax_select|vfs-(select|path))/', $name=(string)$widget->attributes()['name'])) - { - $remove[] = $name; // removing direct disturbs the foreach! - } -} -foreach($remove as $name) -{ - removeWidget($name); -} - -$dom = new DOMDocument("1.0"); -$dom->preserveWhiteSpace = false; -$dom->formatOutput = true; -$dom->loadXML($grammar->asXML()); -if (php_sapi_name() !== "cli") -{ - header('Content-Type: application/xml; charset=utf-8'); -} -echo $dom->saveXML(); - -/** - * Remove (legacy-)widget with given name from schema - * - * @param string $name - * @return void - */ -function removeWidget(string $name) -{ - global $grammar, $widgets; - if (removeByName($widgets->choice, $name)) - { - removeByName($grammar, $name); - removeByName($grammar, 'attlist.'.$name); - - } -} - -function removeByName(SimpleXMLElement $parent, string $name) : bool -{ - foreach($parent->children() as $child) - { - if ((string)$child->attributes()['name'] === $name) - { - $dom=dom_import_simplexml($child); - $dom->parentNode->removeChild($dom); - return true; - } - } - return false; -} - -function getByName(SimpleXMLElement $parent, string $name) : ?SimpleXMLElement -{ - foreach($parent as $element) - { - if ((string)$element->attributes()['name'] === $name) - { - return $element; - } - } - return null; -} - -/** - * Generate attribute list for an element - * - * @param array $class class defining the element - * @param SimpleXMLElement|null $attrs attribute list element: - * @return string[]|void - */ -function attributes(array $class, ?SimpleXMLElement $attrs=null) -{ - static $default_attributes = [ - 'id' => ['name' => 'id', 'type' => ['text' => 'string']], // commented out with some reasoning in Et2Widget - ]; - $attributes = $default_attributes+array_filter($class['attributes'] ?? [], static function ($attr) - { - return ($attr['name'] ?? null) && $attr['name'][0] !== '_'; // ignore attributes with empty name or name starting with understore - }); - - if (!isset($attrs)) - { - return array_map(static function($attr) use ($class) - { - return $attr['name'].'('.($attr['type']['text']??'any'). - (isset($attr['fieldName']) && isset($class['members'][$attr['fieldName']]['default']) ? - ':'.$class['members'][$attr['fieldName']]['default'] : '').')'; - }, $attributes); - } - foreach($attributes as $attr) - { - // todo: are all attributes optional - $optional = $attrs->addChild('optional'); - $attribute = $optional->addChild('attribute'); - $attribute->addAttribute('name', $attr['name']); - if (isset($attr['fieldName']) && isset($class['members'][$attr['fieldName']]['default'])) - { - $default = $class['members'][$attr['fieldName']]['default']; - if (in_array($default[0], ['"', "'"]) && $default[0] === substr($default, -1)) - { - $default = substr($default, 1, -1); - } - $attribute->addAttribute('a:defaultValue', $default, 'http://relaxng.org/ns/compatibility/annotations/1.0'); - } - switch ($attr['type']['text'] ?? 'any') - { - case 'boolean': - $choice = $attribute->addChild('choice'); - $choice->addChild('value', 'false'); - $choice->addChild('value', 'true'); - break; - } - } -} \ No newline at end of file diff --git a/doc/etemplate2-rng.php b/doc/etemplate2-rng.php new file mode 100644 index 0000000000..1864ad5a0a --- /dev/null +++ b/doc/etemplate2-rng.php @@ -0,0 +1,419 @@ + XML Actions > Convert Schema) to Relax NG with an XML parser + * 2. remove the obsolete widgets + * 3. add new widgets from custom-elements.json file generated by our documentation build + * 4. apply overwrites below + * 5. output it again as new eTemplate2 Relax NG schema + * 6. convert it again via PHPStorm (Tools > XML Actions > Convert Schema) to etemplate2.0.dtd referenced in our xet files + * (until we figure out how to use RELAX NG direct) + * + * Open problems: + * - custom-elements.json has no information about element hierarchy: not all elements are allowed be contained by an arbitrary element + * - Relax NG can define attribute types, need to check how with match our internal types to the xet attributes + * + * @link https://en.wikipedia.org/wiki/RELAX_NG RELAX NG (REgular LAnguage for XML Next Generation) + * @link https://relaxng.org/tutorial-20011203.html RELAX NG Tutorial + * @link https://github.com/EGroupware/etemplate/blob/6767672516524444847207d50b21ba59ff7f1540/js/widget_browser.js old widget-browser dtd generation + * @link https://www.jetbrains.com/help/phpstorm/validating-web-content-files.html JetBrains DTD, XML-Schema or RelaxNG support + */ +if (!file_exists($file=__DIR__."/dist/custom-elements.json")) +{ + die("Missing '$file file!"); +} +if (!($data=json_decode(file_get_contents($file), true))) +{ + die("Could not load '$file'!"); +} +if (!file_exists(($file = __DIR__."/etemplate2/etemplate2.rng"))) +{ + die("Missing file '$file', you need to generate it from 'etemplate2.dtd' e.g. with PHPStorm!"); +} +$grammar = new SimpleXMLElement(file_get_contents($file)); +$widgets = getByName($grammar, 'Widgets'); +/** + * Manually overwriting problems / errors in what we automatically generate + * @todo fix in TS sources + */ +$overwrites = [ + // RE to remove no longer used legacy widgets not matching "et2-" + '.remove' => '/^(button|dropdown_button|int|float|menu|select|taglist|tree|passwd|date|time|ajax_select|vfs-(select|path))/', + '*' => [ // all widgets + '.attrs' => [ + 'id' => 'string', // commented out with some reasoning in Et2Widget + //'data' => null, // ToDo: not sure, but AFAIK this is no attribute, but somehow listed in each widget + 'width' => 'string', + 'span' => 'string', // actually int|"all" + ], + ], + 'Et2InputWidget' => [ + '.attrs' => [ + 'tabindex' => 'int', + ], + ], + 'Et2Textbox' => [ + '.attrs' => [ + 'placeholder' => 'string', + 'maxlength' => 'int', + ], + ], + 'Et2InvokerMixin' => 'Et2TextBox', + 'et2-description' => [ + '.attrs' => [ + 'for' => 'string', + ], + ], + 'et2-textarea' => [ + '.attrs' => [ + 'maxlength' => 'int', + 'rows' => 'int', + 'resizeRatio' => 'number', // is this correct + ], + ], + 'et2-date' => [ + '.attrs' => [ + 'yearRange' => 'string', + 'dataFormat' => 'string', + ], + ], + 'et2-hbox' => [ + '.children' => 'Widgets', + ], + 'et2-vbox' => [ + '.children' => 'Widgets', + ], + 'et2-box' => [ + '.children' => 'Widgets', + ], + 'Et2Box' => [ // inherited by et2-(v|h)box too + '.attrs' => [ + 'overflow' => 'string', + ], + ], + 'et2-tabbox' => [ + '.children' => ['tabs','tabpanels'], // add legacy children tabs and tabpanels + '.attrs' => [ + 'cfDisabled' => 'boolean', // implemented on server-side + 'cfTypeFilter' => 'string', + 'cfPrivateTab' => 'boolean', + 'cfPrepend' => 'string', + 'cfExclude' => 'string', + ], + ], + 'et2-tab' => null, // remove/skip, as we currently use legacy tabs and tabpanels + 'et2-tab-panel' => null, + 'et2-details' => [ + '.children' => 'Widgets', + ], + 'et2-split' => [ + '.children' => 'Widgets', + ], + 'et2-select-*' => 'et2-select', // seems like et2-select-* widgets are NOT parsed +]; + +/** + * Fixes on the existing legacy DTD + */ +// make overlay the only allowed start element +removeNode($grammar->start->choice); +$grammar->start->addChild('ref')->addAttribute('name', 'overlay'); +// overlay can only container template, not all widgets +getByName($grammar, 'overlay')->element->zeroOrMore->ref->attributes()['name'] = 'template'; +getByName($grammar, 'attlist.vfs-upload')->addChild('optional') + ->addChild('attribute')->addAttribute('name', 'callback'); +// add statustext to tab +getByName($grammar, 'attlist.tab')->addChild('optional') + ->addChild('attribute')->addAttribute('name', 'statustext'); + +// build a hashed version of all classes, members and attributes to e.g. find ancestors +$classes = []; +foreach($data['modules'] as $module) +{ + foreach ($module['declarations'] as $declaration) + { + if ($declaration['kind'] === 'class') + { + foreach (['members', 'attributes'] as $collection) + { + foreach ($declaration[$collection] ?? [] as $key => $element) + { + $declaration[$collection][$element['name']] = $element; + unset($declaration[$collection][$key]); + } + } + $classes[$declaration['name']] = $declaration; + } + } +} + +// iterate of custom-elements to define in the schema +foreach($data['modules'] as $module) +{ + foreach($module['exports'] ?? [] as $export) + { + // some widgets use: customElements.defines(, as any, ...) --> use previous export + if (!empty($export['declaration']['name']) && $export['declaration']['name'] === "anonymous_0") + { + $export['declaration']['name'] = $last_export; + } + $last_export = $export['name']; + + // ignore / skip none-widgets and some of the widgets e.g. r/o versions + if ($export['kind'] !== 'custom-element-definition' || + preg_match('/_(ro|mobile)$/', $export['name']) || + array_key_exists($export['name'], $overwrites) && !isset($overwrites[$export['name']])) + { + continue; + } + + // add the element + $define = $grammar->addChild('define'); + $define->addAttribute('name', $export['name']); + $element = $define->addChild('element'); + $element->addAttribute('name', $export['name']); + $attrs = $element->addChild('ref'); + $attrs->addAttribute('name', 'attlist.'.$export['name']); + // add to widgets + $widgets->choice->addChild('ref')->addAttribute('name', $export['name']); + + // add the element-attributes + $attrs = $grammar->addChild('define'); + $attrs->addAttribute('name', 'attlist.'.$export['name']); + $attrs->addAttribute('combine', 'interleave'); + if (empty($classes[$export['declaration']['name']]['tagName'])) $classes[$export['declaration']['name']]['tagName'] = $export['name']; + attributes($classes[$export['declaration']['name']], $attrs); + + // add or disallow children depending on overwrites (not available from the TS sources) + // ToDo: this ignores the use in slots! + if (empty($overwrites[$export['name']]['.children'])) + { + // don't allow children + $element->addChild('empty'); + } + else + { + // add allowed children + foreach((array)$overwrites[$export['name']]['.children'] as $child) + { + $element->addChild('ref')->addAttribute('name', $child); + } + } + + // remove corresponding legacy widget + removeWidget(str_replace('et2-', '', $export['name'])); + } +} + +$remove = []; +foreach($widgets->choice->children() as $widget) +{ + if (preg_match($overwrites['.remove'], $name=(string)$widget->attributes()['name'])) + { + $remove[] = $name; // removing direct disturbs the foreach! + } +} +foreach($remove as $name) +{ + removeWidget($name); +} + +$dom = new DOMDocument("1.0"); +$dom->preserveWhiteSpace = false; +$dom->formatOutput = true; +$dom->loadXML($grammar->asXML()); +if (php_sapi_name() !== "cli") +{ + header('Content-Type: application/xml; charset=utf-8'); +} +// add 1 to legacy widget boolean attributes +echo preg_replace('# +(\s+)true +(\s+)false +(\s+)#', "\n\$1false\n\$1true\n\$11\n\$3", + // update the header + preg_replace('##s', '', $dom->saveXML())); + +/** + * Remove (legacy-)widget with given name from schema + * + * @param string $name + * @return void + */ +function removeWidget(string $name) +{ + global $grammar, $widgets; + if (removeByName($widgets->choice, $name)) + { + removeByName($grammar, $name); + removeByName($grammar, 'attlist.'.$name); + + } +} + +function removeByName(SimpleXMLElement $parent, string $name) : bool +{ + foreach($parent->children() as $child) + { + if ((string)$child->attributes()['name'] === $name) + { + removeNode($child); + return true; + } + } + return false; +} + +function removeNode(SimpleXMLElement $node) +{ + $dom=dom_import_simplexml($node); + $dom->parentNode->removeChild($dom); +} + +function getByName(SimpleXMLElement $parent, string $name) : ?SimpleXMLElement +{ + foreach($parent as $element) + { + if ((string)$element->attributes()['name'] === $name) + { + return $element; + } + } + return null; +} + +/** + * Overwrite attributes in given element / class + * @param array& $element + * @param string|null $name overwrites to use e.g. "*", default use $element['name'] + * @return void + */ +function overwriteAttributes(array& $element, string $name=null) +{ + global $overwrites; + + if (!isset($name)) $name = $element['tagName']; + + // forward just to another widget, class or mixin + if (isset($overwrites[$name]) && is_string($overwrites[$name])) + { + $name = $overwrites[$name]; + } + if (empty($overwrites[$name]['.attrs'])) + { + return; // nothing to do + } + foreach($overwrites[$name]['.attrs'] as $attr => $type) + { + if (isset($type)) + { + $element['attributes'][$attr] = ['name' => $attr, 'type' => ['text' => $type]]; + } + else + { + unset($element['attributes'][$attr]); + } + } +} + +/** + * Generate attribute list for an element + * + * @param array $class class defining the element + * @param SimpleXMLElement|null $attrs attribute list element: + * @return string[]|void + */ +function attributes(array $class, ?SimpleXMLElement $attrs=null) +{ + overwriteAttributes($class, '*'); + overwriteAttributes($class); + // also apply overwrites of own class, direct parent and mixins + foreach(getAncestors($class) as $parent) + { + if ($parent && !empty($parent['name']) && preg_match('/^Et2/', $parent['name'])) // can also be Lit or Sl* + { + overwriteAttributes($class, $parent['name']); + } + } + $attributes = array_filter($class['attributes'] ?? [], static function ($attr) + { + return ($attr['name'] ?? null) && $attr['name'][0] !== '_'; // ignore attributes with empty name or name starting with underscore + }); + + if (!isset($attrs)) + { + return array_map(static function($attr) use ($class) + { + return $attr['name'].'('.($attr['type']['text']??'any'). + (isset($attr['fieldName']) && isset($class['members'][$attr['fieldName']]['default']) ? + ':'.$class['members'][$attr['fieldName']]['default'] : '').')'; + }, $attributes); + } + foreach($attributes as $attr) + { + // todo: are all attributes optional, probably + $optional = $attrs->addChild('optional'); + $attribute = $optional->addChild('attribute'); + $attribute->addAttribute('name', $attr['name']); + if (isset($attr['fieldName']) && isset($class['members'][$attr['fieldName']]['default'])) + { + $default = $class['members'][$attr['fieldName']]['default']; + if (in_array($default[0], ['"', "'"]) && $default[0] === substr($default, -1)) + { + $default = substr($default, 1, -1); + } + $attribute->addAttribute('a:defaultValue', $default, 'http://relaxng.org/ns/compatibility/annotations/1.0'); + } + switch ($attr['type']['text'] ?? 'any') + { + case 'boolean': + $choice = $attribute->addChild('choice'); + $choice->addChild('value', 'false'); + $choice->addChild('value', 'true'); + $choice->addChild('value', '1'); // often used in our templates + // not understood by DTD :( + //$choice->addChild('text'); // as we allow "@" or "$cont[name]" + break; + // todo: other types are understood by RELAX NG, but not by DTD + } + } +} + +/** + * Get ancestors: superclass(es) and mixins of the current class/element + * + * @param array|null $class + * @return array[] of array with name attribute + */ +function getAncestors(?array $class=null) +{ + if (!isset($class) || empty($class['name']) || !preg_match('/^Et2/', $class['name'])) + { + return []; + } + if (!isset($class['kind'])) + { + global $classes; + $class = $classes[$class['name']] ?? null; + } + return $class ? array_filter([$class, ...getAncestors($class['superclass']??null), ...$class['mixins']??[]]) : []; +} \ No newline at end of file diff --git a/doc/etemplate2/etemplate2.0.dtd b/doc/etemplate2/etemplate2.0.dtd new file mode 100644 index 0000000000..1046fca92c --- /dev/null +++ b/doc/etemplate2/etemplate2.0.dtd @@ -0,0 +1,2954 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/etemplate2/etemplate2.0.rng b/doc/etemplate2/etemplate2.0.rng new file mode 100644 index 0000000000..bf2dda39d2 --- /dev/null +++ b/doc/etemplate2/etemplate2.0.rng @@ -0,0 +1,11625 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + false + true + 1 + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + + + + + + + + + + false + true + 1 + + + + + + + + + + false + true + 1 + + + + + + + + + + + + + +