webgen 0.5.17 → 1.0.0.beta1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/API.rdoc +143 -0
- data/AUTHORS +0 -1
- data/COPYING +17 -8
- data/ChangeLog +4456 -0
- data/GPL +623 -289
- data/README.md +71 -0
- data/Rakefile +87 -99
- data/VERSION +1 -1
- data/bin/webgen +1 -7
- data/data/webgen/basic_website_template/ext/init.rb +15 -0
- data/data/webgen/basic_website_template/webgen.config +18 -0
- data/data/webgen/bundle_template_files/README.md.erb +24 -0
- data/data/webgen/bundle_template_files/Rakefile.erb +36 -0
- data/data/webgen/bundle_template_files/info.yaml.erb +16 -0
- data/data/webgen/bundle_template_files/init.rb.erb +1 -0
- data/data/webgen/passive_sources/default.metainfo +32 -0
- data/data/webgen/passive_sources/stylesheets/coderay-default.css +109 -118
- data/data/webgen/passive_sources/templates/feed.template +62 -0
- data/data/webgen/passive_sources/templates/sitemap.template +3 -6
- data/data/webgen/passive_sources/templates/tag.template +42 -0
- data/data/webgen/website_bundles/default/README +2 -2
- data/lib/webgen/blackboard.rb +15 -51
- data/lib/webgen/bundle/built-in-show-changes/init.rb +54 -0
- data/lib/webgen/bundle/built-in/init.rb +366 -0
- data/lib/webgen/bundle_loader.rb +126 -0
- data/lib/webgen/cache.rb +9 -18
- data/lib/webgen/cli.rb +131 -58
- data/lib/webgen/cli/bundle_command.rb +30 -0
- data/lib/webgen/cli/create_bundle_command.rb +46 -0
- data/lib/webgen/cli/create_command.rb +48 -60
- data/lib/webgen/cli/generate_command.rb +25 -0
- data/lib/webgen/cli/install_bundle_command.rb +34 -0
- data/lib/webgen/cli/list_bundle_command.rb +108 -0
- data/lib/webgen/cli/logger.rb +45 -0
- data/lib/webgen/cli/show_command.rb +30 -0
- data/lib/webgen/cli/show_config_command.rb +63 -0
- data/lib/webgen/cli/show_dependencies_command.rb +103 -0
- data/lib/webgen/cli/show_extensions_command.rb +74 -0
- data/lib/webgen/cli/utils.rb +68 -95
- data/lib/webgen/configuration.rb +143 -105
- data/lib/webgen/content_processor.rb +160 -0
- data/lib/webgen/content_processor/blocks.rb +96 -0
- data/lib/webgen/content_processor/builder.rb +25 -0
- data/lib/webgen/content_processor/erb.rb +25 -0
- data/lib/webgen/content_processor/erubis.rb +31 -0
- data/lib/webgen/content_processor/fragments.rb +82 -0
- data/lib/webgen/content_processor/haml.rb +25 -0
- data/lib/webgen/content_processor/html_head.rb +157 -0
- data/lib/webgen/content_processor/kramdown.rb +49 -0
- data/lib/webgen/content_processor/maruku.rb +39 -0
- data/lib/webgen/content_processor/r_discount.rb +21 -0
- data/lib/webgen/content_processor/rdoc.rb +22 -0
- data/lib/webgen/content_processor/redcloth.rb +23 -0
- data/lib/webgen/content_processor/ruby.rb +20 -0
- data/lib/webgen/content_processor/sass.rb +145 -0
- data/lib/webgen/content_processor/scss.rb +23 -0
- data/lib/webgen/content_processor/tags.rb +30 -0
- data/lib/webgen/content_processor/tidy.rb +32 -0
- data/lib/webgen/content_processor/tikz.rb +116 -0
- data/lib/webgen/content_processor/xmllint.rb +31 -0
- data/lib/webgen/context.rb +57 -29
- data/lib/webgen/context/html_head.rb +60 -0
- data/lib/webgen/context/nodes.rb +32 -27
- data/lib/webgen/context/rendering.rb +39 -0
- data/lib/webgen/context/webgen_tags.rb +25 -0
- data/lib/webgen/core_ext.rb +25 -0
- data/lib/webgen/destination.rb +151 -0
- data/lib/webgen/destination/file_system.rb +62 -0
- data/lib/webgen/error.rb +59 -49
- data/lib/webgen/extension_manager.rb +121 -0
- data/lib/webgen/item_tracker.rb +237 -0
- data/lib/webgen/item_tracker/file.rb +39 -0
- data/lib/webgen/item_tracker/missing_node.rb +61 -0
- data/lib/webgen/item_tracker/node_content.rb +40 -0
- data/lib/webgen/item_tracker/node_meta_info.rb +53 -0
- data/lib/webgen/item_tracker/nodes.rb +92 -0
- data/lib/webgen/logger.rb +26 -82
- data/lib/webgen/node.rb +122 -367
- data/lib/webgen/node_finder.rb +336 -0
- data/lib/webgen/page.rb +48 -85
- data/lib/webgen/path.rb +218 -156
- data/lib/webgen/path_handler.rb +400 -0
- data/lib/webgen/path_handler/base.rb +220 -0
- data/lib/webgen/path_handler/copy.rb +78 -0
- data/lib/webgen/path_handler/directory.rb +21 -0
- data/lib/webgen/path_handler/feed.rb +82 -0
- data/lib/webgen/path_handler/meta_info.rb +84 -0
- data/lib/webgen/path_handler/page.rb +38 -0
- data/lib/webgen/path_handler/page_utils.rb +79 -0
- data/lib/webgen/path_handler/sitemap.rb +52 -0
- data/lib/webgen/path_handler/template.rb +96 -0
- data/lib/webgen/path_handler/virtual.rb +85 -0
- data/lib/webgen/{webgentask.rb → rake_task.rb} +31 -27
- data/lib/webgen/source.rb +106 -24
- data/lib/webgen/source/file_system.rb +41 -0
- data/lib/webgen/source/stacked.rb +49 -53
- data/lib/webgen/source/tar_archive.rb +59 -0
- data/lib/webgen/tag.rb +250 -19
- data/lib/webgen/tag/breadcrumb_trail.rb +65 -0
- data/lib/webgen/tag/coderay.rb +32 -35
- data/lib/webgen/tag/date.rb +9 -9
- data/lib/webgen/tag/execute_command.rb +31 -0
- data/lib/webgen/tag/include_file.rb +32 -0
- data/lib/webgen/tag/langbar.rb +31 -47
- data/lib/webgen/tag/link.rb +17 -18
- data/lib/webgen/tag/menu.rb +27 -189
- data/lib/webgen/tag/meta_info.rb +31 -0
- data/lib/webgen/tag/relocatable.rb +48 -39
- data/lib/webgen/tag/tikz.rb +24 -100
- data/lib/webgen/task.rb +99 -0
- data/lib/webgen/task/create_bundle.rb +73 -0
- data/lib/webgen/task/create_website.rb +94 -0
- data/lib/webgen/task/generate_website.rb +47 -0
- data/lib/webgen/test_helper.rb +183 -0
- data/lib/webgen/tree.rb +95 -46
- data/lib/webgen/utils.rb +39 -0
- data/lib/webgen/utils/external_command.rb +27 -0
- data/lib/webgen/utils/tag_parser.rb +124 -0
- data/lib/webgen/version.rb +1 -1
- data/lib/webgen/website.rb +134 -296
- data/setup.rb +1 -1
- data/test/test_documentation.rb +43 -0
- data/test/webgen/cli/test_logger.rb +41 -0
- data/test/{test_contentprocessor_blocks.rb → webgen/content_processor/test_blocks.rb} +30 -28
- data/test/webgen/content_processor/test_builder.rb +25 -0
- data/test/webgen/content_processor/test_erb.rb +21 -0
- data/test/webgen/content_processor/test_erubis.rb +33 -0
- data/test/webgen/content_processor/test_fragments.rb +96 -0
- data/test/webgen/content_processor/test_haml.rb +24 -0
- data/test/webgen/content_processor/test_html_head.rb +78 -0
- data/test/webgen/content_processor/test_kramdown.rb +49 -0
- data/test/webgen/content_processor/test_maruku.rb +30 -0
- data/test/webgen/content_processor/test_r_discount.rb +18 -0
- data/test/webgen/content_processor/test_rdoc.rb +18 -0
- data/test/webgen/content_processor/test_redcloth.rb +23 -0
- data/test/webgen/content_processor/test_ruby.rb +24 -0
- data/test/webgen/content_processor/test_sass.rb +44 -0
- data/test/webgen/content_processor/test_scss.rb +23 -0
- data/test/webgen/content_processor/test_tags.rb +44 -0
- data/test/webgen/content_processor/test_tidy.rb +31 -0
- data/test/webgen/content_processor/test_tikz.rb +33 -0
- data/test/webgen/content_processor/test_xmllint.rb +32 -0
- data/test/webgen/destination/test_file_system.rb +54 -0
- data/test/webgen/item_tracker/test_file.rb +31 -0
- data/test/webgen/item_tracker/test_missing_node.rb +70 -0
- data/test/webgen/item_tracker/test_node_content.rb +42 -0
- data/test/webgen/item_tracker/test_node_meta_info.rb +44 -0
- data/test/webgen/item_tracker/test_nodes.rb +61 -0
- data/test/webgen/path_handler/test_base.rb +153 -0
- data/test/webgen/path_handler/test_copy.rb +56 -0
- data/test/webgen/path_handler/test_feed.rb +85 -0
- data/test/webgen/path_handler/test_meta_info.rb +98 -0
- data/test/webgen/path_handler/test_page.rb +25 -0
- data/test/webgen/path_handler/test_page_utils.rb +59 -0
- data/test/webgen/path_handler/test_sitemap.rb +95 -0
- data/test/webgen/path_handler/test_template.rb +64 -0
- data/test/webgen/path_handler/test_virtual.rb +87 -0
- data/test/webgen/source/test_file_system.rb +51 -0
- data/test/webgen/source/test_stacked.rb +35 -0
- data/test/{test_source_tararchive.rb → webgen/source/test_tar_archive.rb} +10 -25
- data/test/webgen/tag/test_breadcrumb_trail.rb +66 -0
- data/test/webgen/tag/test_coderay.rb +34 -0
- data/test/webgen/tag/test_date.rb +18 -0
- data/test/webgen/tag/test_execute_command.rb +36 -0
- data/test/webgen/tag/test_include_file.rb +35 -0
- data/test/webgen/tag/test_langbar.rb +50 -0
- data/test/webgen/tag/test_link.rb +40 -0
- data/test/webgen/tag/test_menu.rb +61 -0
- data/test/webgen/tag/test_meta_info.rb +25 -0
- data/test/webgen/tag/test_relocatable.rb +50 -0
- data/test/webgen/tag/test_tikz.rb +41 -0
- data/test/webgen/task/test_create_website.rb +46 -0
- data/test/webgen/test_blackboard.rb +31 -0
- data/test/webgen/test_bundle_loader.rb +55 -0
- data/test/{test_cache.rb → webgen/test_cache.rb} +3 -15
- data/test/webgen/test_cli.rb +41 -0
- data/test/webgen/test_configuration.rb +131 -0
- data/test/webgen/test_content_processor.rb +86 -0
- data/test/webgen/test_context.rb +73 -0
- data/test/webgen/test_core_ext.rb +20 -0
- data/test/webgen/test_destination.rb +48 -0
- data/test/webgen/test_error.rb +121 -0
- data/test/webgen/test_extension_manager.rb +70 -0
- data/test/webgen/test_item_tracker.rb +106 -0
- data/test/{test_languages.rb → webgen/test_languages.rb} +4 -4
- data/test/webgen/test_logger.rb +46 -0
- data/test/webgen/test_node.rb +178 -0
- data/test/webgen/test_node_finder.rb +127 -0
- data/test/{test_page.rb → webgen/test_page.rb} +44 -48
- data/test/webgen/test_path.rb +271 -0
- data/test/{test_webgentask.rb → webgen/test_rake_task.rb} +4 -4
- data/test/webgen/test_source.rb +59 -0
- data/test/webgen/test_tag.rb +137 -0
- data/test/webgen/test_task.rb +40 -0
- data/test/webgen/test_tree.rb +147 -0
- data/test/webgen/test_utils.rb +16 -0
- data/test/webgen/test_website.rb +45 -0
- data/test/webgen/utils/test_tag_parser.rb +99 -0
- metadata +292 -344
- data/data/webgen/passive_sources/templates/atom_feed.template +0 -39
- data/data/webgen/passive_sources/templates/rss_feed.template +0 -28
- data/data/webgen/resources.yaml +0 -4
- data/data/webgen/webgui/app.rb +0 -11
- data/data/webgen/webgui/controller/main.rb +0 -135
- data/data/webgen/webgui/layout/default.xhtml +0 -40
- data/data/webgen/webgui/overrides/win32console.rb +0 -0
- data/data/webgen/webgui/public/css/jquery.autocomplete.css +0 -50
- data/data/webgen/webgui/public/css/ramaze_error.css +0 -90
- data/data/webgen/webgui/public/css/style.css +0 -55
- data/data/webgen/webgui/public/img/headerbg.jpg +0 -0
- data/data/webgen/webgui/public/img/webgen_logo.png +0 -0
- data/data/webgen/webgui/public/js/jquery.autocomplete.js +0 -15
- data/data/webgen/webgui/public/js/jquery.js +0 -32
- data/data/webgen/webgui/start.rb +0 -9
- data/data/webgen/webgui/view/create_website.xhtml +0 -14
- data/data/webgen/webgui/view/error.xhtml +0 -64
- data/data/webgen/webgui/view/index.xhtml +0 -22
- data/data/webgen/webgui/view/manage_website.xhtml +0 -18
- data/data/webgen/website_skeleton/README +0 -10
- data/data/webgen/website_skeleton/Rakefile +0 -69
- data/data/webgen/website_skeleton/config.yaml +0 -35
- data/data/webgen/website_skeleton/ext/init.rb +0 -10
- data/doc/contentprocessor.template +0 -11
- data/doc/contentprocessor/blocks.page +0 -129
- data/doc/contentprocessor/builder.page +0 -79
- data/doc/contentprocessor/erb.page +0 -60
- data/doc/contentprocessor/erubis.page +0 -46
- data/doc/contentprocessor/fragments.page +0 -26
- data/doc/contentprocessor/haml.page +0 -46
- data/doc/contentprocessor/head.page +0 -31
- data/doc/contentprocessor/kramdown.page +0 -49
- data/doc/contentprocessor/less.page +0 -34
- data/doc/contentprocessor/maruku.page +0 -44
- data/doc/contentprocessor/rdiscount.page +0 -37
- data/doc/contentprocessor/rdoc.page +0 -36
- data/doc/contentprocessor/redcloth.page +0 -41
- data/doc/contentprocessor/sass.page +0 -31
- data/doc/contentprocessor/scss.page +0 -39
- data/doc/contentprocessor/tags.page +0 -73
- data/doc/contentprocessor/tidy.page +0 -14
- data/doc/contentprocessor/xmllint.page +0 -14
- data/doc/extensions.metainfo +0 -29
- data/doc/extensions.page +0 -15
- data/doc/extensions.template +0 -17
- data/doc/faq.page +0 -222
- data/doc/getting_started.page +0 -135
- data/doc/index.page +0 -71
- data/doc/manual.page +0 -727
- data/doc/reference_configuration.page +0 -1254
- data/doc/reference_metainfo.page +0 -265
- data/doc/reference_website_styles.page +0 -32
- data/doc/source/filesystem.page +0 -41
- data/doc/source/tararchive.page +0 -40
- data/doc/sourcehandler.template +0 -23
- data/doc/sourcehandler/copy.page +0 -19
- data/doc/sourcehandler/directory.page +0 -27
- data/doc/sourcehandler/feed.page +0 -102
- data/doc/sourcehandler/metainfo.page +0 -48
- data/doc/sourcehandler/page.page +0 -14
- data/doc/sourcehandler/sitemap.page +0 -46
- data/doc/sourcehandler/template.page +0 -45
- data/doc/sourcehandler/virtual.page +0 -49
- data/doc/tag.template +0 -25
- data/doc/tag/breadcrumbtrail.page +0 -40
- data/doc/tag/coderay.page +0 -53
- data/doc/tag/date.page +0 -31
- data/doc/tag/executecommand.page +0 -26
- data/doc/tag/includefile.page +0 -32
- data/doc/tag/langbar.page +0 -47
- data/doc/tag/link.page +0 -44
- data/doc/tag/menu.page +0 -109
- data/doc/tag/metainfo.page +0 -29
- data/doc/tag/relocatable.page +0 -38
- data/doc/tag/sitemap.page +0 -31
- data/doc/tag/tikz.page +0 -159
- data/doc/upgrading.page +0 -138
- data/doc/webgen_page_format.page +0 -129
- data/doc/website_styles.metainfo +0 -8
- data/lib/webgen/cli/apply_command.rb +0 -66
- data/lib/webgen/cli/run_command.rb +0 -22
- data/lib/webgen/cli/webgui_command.rb +0 -68
- data/lib/webgen/common.rb +0 -27
- data/lib/webgen/common/sitemap.rb +0 -83
- data/lib/webgen/contentprocessor.rb +0 -117
- data/lib/webgen/contentprocessor/blocks.rb +0 -92
- data/lib/webgen/contentprocessor/builder.rb +0 -29
- data/lib/webgen/contentprocessor/erb.rb +0 -26
- data/lib/webgen/contentprocessor/erubis.rb +0 -39
- data/lib/webgen/contentprocessor/fragments.rb +0 -25
- data/lib/webgen/contentprocessor/haml.rb +0 -34
- data/lib/webgen/contentprocessor/head.rb +0 -128
- data/lib/webgen/contentprocessor/kramdown.rb +0 -27
- data/lib/webgen/contentprocessor/kramdown/html.rb +0 -36
- data/lib/webgen/contentprocessor/less.rb +0 -35
- data/lib/webgen/contentprocessor/maruku.rb +0 -36
- data/lib/webgen/contentprocessor/rdiscount.rb +0 -19
- data/lib/webgen/contentprocessor/rdoc.rb +0 -20
- data/lib/webgen/contentprocessor/redcloth.rb +0 -21
- data/lib/webgen/contentprocessor/sass.rb +0 -22
- data/lib/webgen/contentprocessor/scss.rb +0 -22
- data/lib/webgen/contentprocessor/tags.rb +0 -170
- data/lib/webgen/contentprocessor/tidy.rb +0 -38
- data/lib/webgen/contentprocessor/xmllint.rb +0 -37
- data/lib/webgen/context/render.rb +0 -32
- data/lib/webgen/context/tags.rb +0 -20
- data/lib/webgen/coreext.rb +0 -13
- data/lib/webgen/default_config.rb +0 -240
- data/lib/webgen/loggable.rb +0 -25
- data/lib/webgen/output.rb +0 -86
- data/lib/webgen/output/filesystem.rb +0 -69
- data/lib/webgen/source/filesystem.rb +0 -61
- data/lib/webgen/source/resource.rb +0 -45
- data/lib/webgen/source/tararchive.rb +0 -78
- data/lib/webgen/sourcehandler.rb +0 -275
- data/lib/webgen/sourcehandler/base.rb +0 -281
- data/lib/webgen/sourcehandler/copy.rb +0 -44
- data/lib/webgen/sourcehandler/directory.rb +0 -30
- data/lib/webgen/sourcehandler/feed.rb +0 -92
- data/lib/webgen/sourcehandler/fragment.rb +0 -70
- data/lib/webgen/sourcehandler/memory.rb +0 -42
- data/lib/webgen/sourcehandler/metainfo.rb +0 -128
- data/lib/webgen/sourcehandler/page.rb +0 -64
- data/lib/webgen/sourcehandler/sitemap.rb +0 -60
- data/lib/webgen/sourcehandler/template.rb +0 -66
- data/lib/webgen/sourcehandler/virtual.rb +0 -117
- data/lib/webgen/tag/base.rb +0 -170
- data/lib/webgen/tag/breadcrumbtrail.rb +0 -70
- data/lib/webgen/tag/executecommand.rb +0 -31
- data/lib/webgen/tag/includefile.rb +0 -42
- data/lib/webgen/tag/metainfo.rb +0 -27
- data/lib/webgen/tag/sitemap.rb +0 -41
- data/lib/webgen/websiteaccess.rb +0 -31
- data/lib/webgen/websitemanager.rb +0 -125
- data/misc/default.css +0 -403
- data/misc/default.template +0 -76
- data/misc/htmldoc.metainfo +0 -26
- data/misc/htmldoc.virtual +0 -17
- data/misc/images/arrow.gif +0 -0
- data/misc/images/error.png +0 -0
- data/misc/images/headerbg.jpg +0 -0
- data/misc/images/important.png +0 -0
- data/misc/images/information.png +0 -0
- data/misc/images/quote.gif +0 -0
- data/misc/images/warning.png +0 -0
- data/misc/logo.svg +0 -313
- data/misc/style.page +0 -33
- data/test/helper.rb +0 -61
- data/test/test_blackboard.rb +0 -60
- data/test/test_cli.rb +0 -119
- data/test/test_common_sitemap.rb +0 -58
- data/test/test_configuration.rb +0 -68
- data/test/test_contentprocessor.rb +0 -39
- data/test/test_contentprocessor_builder.rb +0 -41
- data/test/test_contentprocessor_erb.rb +0 -33
- data/test/test_contentprocessor_erubis.rb +0 -62
- data/test/test_contentprocessor_fragments.rb +0 -43
- data/test/test_contentprocessor_haml.rb +0 -39
- data/test/test_contentprocessor_head.rb +0 -96
- data/test/test_contentprocessor_kramdown.rb +0 -56
- data/test/test_contentprocessor_less.rb +0 -40
- data/test/test_contentprocessor_maruku.rb +0 -33
- data/test/test_contentprocessor_rdiscount.rb +0 -21
- data/test/test_contentprocessor_rdoc.rb +0 -22
- data/test/test_contentprocessor_redcloth.rb +0 -26
- data/test/test_contentprocessor_sass.rb +0 -28
- data/test/test_contentprocessor_scss.rb +0 -28
- data/test/test_contentprocessor_tags.rb +0 -122
- data/test/test_contentprocessor_tidy.rb +0 -34
- data/test/test_contentprocessor_xmllint.rb +0 -38
- data/test/test_context.rb +0 -81
- data/test/test_error.rb +0 -93
- data/test/test_loggable.rb +0 -32
- data/test/test_logger.rb +0 -94
- data/test/test_node.rb +0 -469
- data/test/test_output_filesystem.rb +0 -60
- data/test/test_path.rb +0 -241
- data/test/test_source_filesystem.rb +0 -76
- data/test/test_source_resource.rb +0 -28
- data/test/test_source_stacked.rb +0 -49
- data/test/test_sourcehandler_base.rb +0 -136
- data/test/test_sourcehandler_copy.rb +0 -47
- data/test/test_sourcehandler_directory.rb +0 -38
- data/test/test_sourcehandler_feed.rb +0 -88
- data/test/test_sourcehandler_fragment.rb +0 -70
- data/test/test_sourcehandler_main.rb +0 -39
- data/test/test_sourcehandler_memory.rb +0 -44
- data/test/test_sourcehandler_metainfo.rb +0 -127
- data/test/test_sourcehandler_page.rb +0 -73
- data/test/test_sourcehandler_sitemap.rb +0 -68
- data/test/test_sourcehandler_template.rb +0 -68
- data/test/test_sourcehandler_virtual.rb +0 -106
- data/test/test_tag_base.rb +0 -62
- data/test/test_tag_breadcrumbtrail.rb +0 -91
- data/test/test_tag_coderay.rb +0 -45
- data/test/test_tag_date.rb +0 -18
- data/test/test_tag_executecommand.rb +0 -41
- data/test/test_tag_includefile.rb +0 -50
- data/test/test_tag_langbar.rb +0 -71
- data/test/test_tag_link.rb +0 -70
- data/test/test_tag_menu.rb +0 -207
- data/test/test_tag_metainfo.rb +0 -26
- data/test/test_tag_relocatable.rb +0 -60
- data/test/test_tag_sitemap.rb +0 -47
- data/test/test_tag_tikz.rb +0 -69
- data/test/test_tree.rb +0 -70
- data/test/test_website.rb +0 -130
- data/test/test_websiteaccess.rb +0 -25
- data/test/test_websitemanager.rb +0 -65
data/lib/webgen/path.rb
CHANGED
|
@@ -1,218 +1,252 @@
|
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
|
2
2
|
|
|
3
|
-
require '
|
|
3
|
+
require 'uri'
|
|
4
4
|
require 'webgen/languages'
|
|
5
5
|
|
|
6
6
|
module Webgen
|
|
7
7
|
|
|
8
|
-
# ==
|
|
8
|
+
# == About
|
|
9
9
|
#
|
|
10
10
|
# A Path object provides information about a path that is used to create one or more nodes as well
|
|
11
|
-
# as methods for accessing the path's content.
|
|
12
|
-
#
|
|
13
|
-
#
|
|
11
|
+
# as methods for accessing/modifying the path's content. Path objects are created by Source
|
|
12
|
+
# classes but can also be created during the rendering phase (see
|
|
13
|
+
# PathHandler#create_secondary_nodes).
|
|
14
14
|
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
# Path object must have such a valid source path sothat webgen can infer the Path the lead to
|
|
19
|
-
# the creation of a Node object later.
|
|
20
|
-
#
|
|
21
|
-
# * In contrast, the +path+ attribute specifies the path that is used to create the canonical name
|
|
22
|
-
# (and by default the output path) of a Node object. Normally it is the same as the
|
|
23
|
-
# +source_path+ but can differ (e.g. when fragment nodes are created for page file nodes).
|
|
15
|
+
# So a Path object always refers to a path from which nodes are created! In contrast, destination
|
|
16
|
+
# paths are just strings and specify the location where a specific node should be written to (see
|
|
17
|
+
# Node#destination_path).
|
|
24
18
|
#
|
|
25
19
|
# A Path object can represent one of three different things: a directory, a file or a fragment. If
|
|
26
20
|
# the +path+ ends with a slash character, then the path object represents a directory, if the path
|
|
27
21
|
# contains a hash character anywhere, then the path object represents a fragment and else it
|
|
28
|
-
# represents a file. Have a look at the
|
|
22
|
+
# represents a file. Have a look at the user documentation to see the exact format that can be
|
|
23
|
+
# used for a path string!
|
|
24
|
+
#
|
|
25
|
+
# == Utility methods
|
|
29
26
|
#
|
|
30
|
-
#
|
|
27
|
+
# The Path class also provides some general methods for working with path strings which are also
|
|
28
|
+
# used, for example, by the Node class:
|
|
29
|
+
#
|
|
30
|
+
# * Path.url
|
|
31
|
+
# * Path.append
|
|
32
|
+
# * Path.matches_pattern
|
|
33
|
+
# * Path.lcn
|
|
31
34
|
#
|
|
32
|
-
# A webgen source class needs to derive a specialized path class from this class and implement an
|
|
33
|
-
# approriate #changed? method that returns +true+ if the path's content has changed since the last
|
|
34
|
-
# webgen run.
|
|
35
35
|
class Path
|
|
36
36
|
|
|
37
|
-
#
|
|
38
|
-
#
|
|
39
|
-
|
|
40
|
-
# it is actually needed. This is done by not directly requiring the user of this class to supply
|
|
41
|
-
# the IO object, but by requiring a block that creates the real IO object.
|
|
42
|
-
class SourceIO
|
|
43
|
-
|
|
44
|
-
# Create a new SourceIO object. A block has to be specified that returns the to-be-wrapped IO
|
|
45
|
-
# object.
|
|
46
|
-
def initialize(&block)
|
|
47
|
-
@block = block
|
|
48
|
-
raise ArgumentError, 'You need to provide a block which returns an IO object' if @block.nil?
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
# Provide direct access to the wrapped IO object by yielding it. After the method block
|
|
52
|
-
# returns the IO object is automatically closed.
|
|
53
|
-
#
|
|
54
|
-
# The parameter +mode+ specifies the mode in which the wrapped IO object should be opened.
|
|
55
|
-
# This can be used, for example, to open a file in binary mode (or specify a certain input
|
|
56
|
-
# encoding under Ruby 1.9).
|
|
57
|
-
def stream(mode = 'r')
|
|
58
|
-
io = @block.call(mode)
|
|
59
|
-
yield(io)
|
|
60
|
-
ensure
|
|
61
|
-
io.close
|
|
62
|
-
end
|
|
37
|
+
# This pattern is the the same as URI::UNSAFE except that the hash character (#) is also
|
|
38
|
+
# not escaped. This is needed so that paths with fragments work correctly.
|
|
39
|
+
URL_UNSAFE_PATTERN = Regexp.new("[^#{URI::PATTERN::UNRESERVED}#{URI::PATTERN::RESERVED}#]") # :nodoc:
|
|
63
40
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
def data(mode = 'r')
|
|
67
|
-
stream(mode) {|io| io.read}
|
|
68
|
-
end
|
|
41
|
+
# Base URI prepended to all internal URLs.
|
|
42
|
+
WEBGEN_BASE_URI = URI.parse('webgen://webgen.localhost/') # :nodoc:
|
|
69
43
|
|
|
44
|
+
# Construct an internal URL for the given +path+ which can be an acn/alcn/absolute path.
|
|
45
|
+
#
|
|
46
|
+
# If the parameter +make_absolute+ is +true+, then a relative URL will be made absolute by
|
|
47
|
+
# prepending the special URL 'webgen:://webgen.localhost/'.
|
|
48
|
+
def self.url(path, make_absolute = true)
|
|
49
|
+
url = URI.parse(URI::DEFAULT_PARSER.escape(path, URL_UNSAFE_PATTERN))
|
|
50
|
+
url = WEBGEN_BASE_URI + url unless url.absolute? || !make_absolute
|
|
51
|
+
url
|
|
70
52
|
end
|
|
71
53
|
|
|
72
|
-
|
|
73
|
-
#
|
|
74
|
-
#
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
54
|
+
# Append the +path+ to the +base+ path.
|
|
55
|
+
#
|
|
56
|
+
# The +base+ parameter has to be an acn/alcn/absolute path. If it represents a directory, it
|
|
57
|
+
# needs to have a trailing slash! The +path+ parameter doesn't need to be absolute and may
|
|
58
|
+
# contain path patterns.
|
|
59
|
+
def self.append(base, path)
|
|
60
|
+
raise(ArgumentError, 'base needs to start with a slash (i.e. be an absolute path)') unless base =~ /^\//
|
|
61
|
+
url = url(base) + url(path, false)
|
|
62
|
+
url.path + (url.fragment.nil? ? '' : '#' + url.fragment)
|
|
78
63
|
end
|
|
79
64
|
|
|
80
|
-
# Return +true+ if the given
|
|
81
|
-
#
|
|
82
|
-
|
|
65
|
+
# Return +true+ if the given path string matches the given path pattern.
|
|
66
|
+
#
|
|
67
|
+
# For information on which patterns are supported, have a look at the API documentation of
|
|
68
|
+
# File.fnmatch.
|
|
69
|
+
def self.matches_pattern?(path, pattern, options = File::FNM_DOTMATCH|File::FNM_CASEFOLD|File::FNM_PATHNAME)
|
|
83
70
|
pattern += '/' if path.to_s =~ /\/$/ && pattern !~ /\/$|^$/
|
|
84
|
-
File.fnmatch(pattern, path
|
|
71
|
+
File.fnmatch(pattern, path, options)
|
|
85
72
|
end
|
|
86
73
|
|
|
74
|
+
# Construct a localized canonical name from a given canonical name and a language.
|
|
75
|
+
def self.lcn(cn, lang)
|
|
76
|
+
if lang.nil?
|
|
77
|
+
cn
|
|
78
|
+
else
|
|
79
|
+
cn.split('.').insert((cn =~ /^\./ ? 2 : 1), lang.to_s).join('.')
|
|
80
|
+
end
|
|
81
|
+
end
|
|
87
82
|
|
|
88
|
-
include Comparable
|
|
89
|
-
|
|
90
|
-
# The full path for which this Path object was created.
|
|
91
|
-
attr_reader :path
|
|
92
|
-
|
|
93
|
-
# A string specifying the path that lead to the creation of this path.
|
|
94
|
-
attr_reader :source_path
|
|
95
|
-
|
|
96
|
-
# The string specifying the parent path
|
|
97
|
-
attr_reader :parent_path
|
|
98
|
-
|
|
99
|
-
# The canonical name of the path without the extension.
|
|
100
|
-
attr_accessor :basename
|
|
101
|
-
|
|
102
|
-
# The extension of the +path+.
|
|
103
|
-
attr_accessor :ext
|
|
104
83
|
|
|
105
|
-
|
|
106
|
-
attr_accessor :meta_info
|
|
84
|
+
include Comparable
|
|
107
85
|
|
|
108
|
-
#
|
|
109
|
-
#
|
|
110
|
-
|
|
86
|
+
# Create a new Path object for +path+ (a string).
|
|
87
|
+
#
|
|
88
|
+
# The optional block needs to return an IO object for getting the content of the path (see #io
|
|
89
|
+
# and #data).
|
|
90
|
+
#
|
|
91
|
+
# The +path+ string needs to be in a well defined format which can be looked up in the webgen
|
|
92
|
+
# user documentation.
|
|
93
|
+
def initialize(path, meta_info = {}, &ioblock)
|
|
94
|
+
@path = path.freeze
|
|
95
|
+
@meta_info = meta_info.dup
|
|
96
|
+
@ioblock = block_given? ? ioblock : nil
|
|
97
|
+
end
|
|
111
98
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
99
|
+
def initialize_copy(orig) #:nodoc:
|
|
100
|
+
super
|
|
101
|
+
@meta_info = orig.instance_variable_get(:@meta_info).dup
|
|
102
|
+
end
|
|
115
103
|
|
|
104
|
+
# The original path string from which this Path object was created.
|
|
105
|
+
attr_reader :path
|
|
116
106
|
|
|
117
|
-
#
|
|
118
|
-
# string that lead to the creation of this path. The optional block needs to return an IO object
|
|
119
|
-
# for getting the content of the path.
|
|
107
|
+
# Meta information about the path.
|
|
120
108
|
#
|
|
121
|
-
#
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
@
|
|
125
|
-
@source_path = source_path
|
|
126
|
-
@passive = false
|
|
127
|
-
analyse(path)
|
|
109
|
+
# Triggers analyzation of the path if invoked. See #[]= to setting meta information without
|
|
110
|
+
# triggering analyzation.
|
|
111
|
+
def meta_info
|
|
112
|
+
defined?(@basename) ? @meta_info : (analyse; @meta_info)
|
|
128
113
|
end
|
|
129
114
|
|
|
130
|
-
#
|
|
131
|
-
# and return the new path object.
|
|
115
|
+
# Get the value of the meta information key.
|
|
132
116
|
#
|
|
133
|
-
#
|
|
134
|
-
#
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
#++
|
|
139
|
-
def mount_at(mp, prefix = nil)
|
|
140
|
-
raise(ArgumentError, "The mount point (#{mp}) must be a valid directory path") if mp =~ /^[^\/]|#|[^\/]$/
|
|
141
|
-
raise(ArgumentError, "The strip prefix (#{prefix}) must be a valid directory path") if !prefix.nil? && prefix =~ /^[^\/]|#|[^\/]$/
|
|
117
|
+
# This method has to be used to get meta information without triggering analyzation of the path
|
|
118
|
+
# string!
|
|
119
|
+
def [](key)
|
|
120
|
+
@meta_info[key]
|
|
121
|
+
end
|
|
142
122
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
if reanalyse
|
|
150
|
-
temp.send(:analyse, temp.path)
|
|
151
|
-
else
|
|
152
|
-
temp.instance_variable_set(:@parent_path, File.join(mp, temp.parent_path.sub(strip_re, '')))
|
|
153
|
-
end
|
|
154
|
-
temp
|
|
123
|
+
# Set the meta information +key+ to +value+.
|
|
124
|
+
#
|
|
125
|
+
# This method has to be used to set meta information without triggering analyzation of the path
|
|
126
|
+
# string!
|
|
127
|
+
def []=(key, value)
|
|
128
|
+
@meta_info[key] = value
|
|
155
129
|
end
|
|
156
130
|
|
|
157
|
-
#
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
131
|
+
# The string specifying the parent path.
|
|
132
|
+
#
|
|
133
|
+
# Triggers analyzation of the path if invoked.
|
|
134
|
+
def parent_path
|
|
135
|
+
defined?(@parent_path) ? @parent_path : (analyse; @parent_path)
|
|
162
136
|
end
|
|
163
137
|
|
|
164
|
-
#
|
|
165
|
-
#
|
|
166
|
-
|
|
167
|
-
|
|
138
|
+
# The canonical name of the path without the extension.
|
|
139
|
+
#
|
|
140
|
+
# Triggers analyzation of the path if invoked.
|
|
141
|
+
def basename
|
|
142
|
+
defined?(@basename) ? @basename : (analyse; @basename)
|
|
168
143
|
end
|
|
169
144
|
|
|
170
|
-
# The
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
raise "No IO object defined for the path #{self}"
|
|
176
|
-
end
|
|
145
|
+
# The extension of the path.
|
|
146
|
+
#
|
|
147
|
+
# Triggers analyzation of the path if invoked.
|
|
148
|
+
def ext
|
|
149
|
+
defined?(@ext) ? @ext : (analyse; @ext)
|
|
177
150
|
end
|
|
178
151
|
|
|
179
|
-
#
|
|
180
|
-
|
|
181
|
-
|
|
152
|
+
# Set the extension of the path.
|
|
153
|
+
#
|
|
154
|
+
# Triggers analyzation of the path if invoked.
|
|
155
|
+
def ext=(value)
|
|
156
|
+
defined?(@ext) || analyse
|
|
157
|
+
@ext = value
|
|
182
158
|
end
|
|
183
159
|
|
|
184
|
-
#
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
160
|
+
# The canonical name created from the +path+ (namely from the parts +basename+ and +extension+
|
|
161
|
+
# as well as the meta information +version+).
|
|
162
|
+
#
|
|
163
|
+
# Triggers analyzation of the path if invoked.
|
|
164
|
+
def cn
|
|
165
|
+
if meta_info['cn'].kind_of?(String)
|
|
166
|
+
tmp_cn = custom_cn
|
|
188
167
|
else
|
|
189
|
-
|
|
168
|
+
tmp_cn = basename + (use_version_for_cn? ? "-#{meta_info['version']}" : '') +
|
|
169
|
+
(ext.length > 0 ? '.' + ext : '')
|
|
190
170
|
end
|
|
171
|
+
tmp_cn + (@path =~ /.\/$/ ? '/' : '')
|
|
191
172
|
end
|
|
192
173
|
|
|
193
174
|
# The localized canonical name created from the +path+.
|
|
175
|
+
#
|
|
176
|
+
# Triggers analyzation of the path if invoked.
|
|
194
177
|
def lcn
|
|
195
|
-
self.class.lcn(cn,
|
|
178
|
+
self.class.lcn(cn, meta_info['lang'])
|
|
196
179
|
end
|
|
197
180
|
|
|
198
181
|
# The absolute canonical name of this path.
|
|
182
|
+
#
|
|
183
|
+
# Triggers analyzation of the path if invoked.
|
|
199
184
|
def acn
|
|
200
185
|
if @path =~ /#/
|
|
201
|
-
self.class.new(
|
|
186
|
+
self.class.new(parent_path).acn + cn
|
|
202
187
|
else
|
|
203
|
-
|
|
188
|
+
parent_path + cn
|
|
204
189
|
end
|
|
205
190
|
end
|
|
206
191
|
|
|
207
192
|
# The absolute localized canonical name of this path.
|
|
193
|
+
#
|
|
194
|
+
# Triggers analyzation of the path if invoked.
|
|
208
195
|
def alcn
|
|
209
196
|
if @path =~ /#/
|
|
210
|
-
self.class.new(
|
|
197
|
+
self.class.new(parent_path).alcn + lcn
|
|
211
198
|
else
|
|
212
|
-
|
|
199
|
+
parent_path + lcn
|
|
213
200
|
end
|
|
214
201
|
end
|
|
215
202
|
|
|
203
|
+
|
|
204
|
+
# Mount this path at the mount point +mp+, optionally stripping +prefix+ from the parent path,
|
|
205
|
+
# and return the new Path object.
|
|
206
|
+
#
|
|
207
|
+
# The parameters +mp+ and +prefix+ have to be absolute directory paths, ie. they have to start
|
|
208
|
+
# and end with a slash and must not contain any hash characters!
|
|
209
|
+
#
|
|
210
|
+
# Also note that mounting a path is not possible once it is fully initialized, i.e. once some
|
|
211
|
+
# information extracted from the path string is accessed.
|
|
212
|
+
def mount_at(mp, prefix = nil)
|
|
213
|
+
raise(ArgumentError, "Can't mount a fully initialized path") if defined?(@basename)
|
|
214
|
+
raise(ArgumentError, "The mount point (#{mp}) must be a valid directory path") if mp =~ /^[^\/]|#|[^\/]$/
|
|
215
|
+
raise(ArgumentError, "The strip prefix (#{prefix}) must be a valid directory path") if !prefix.nil? && prefix =~ /^[^\/]|#|[^\/]$/
|
|
216
|
+
|
|
217
|
+
temp = self.class.new(File.join(mp, @path.sub(/^#{Regexp.escape(prefix.to_s)}/, '')), @meta_info, &@ioblock)
|
|
218
|
+
temp
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
# Provide access to the IO object of the path by yielding it.
|
|
222
|
+
#
|
|
223
|
+
# After the method block returns, the IO object is automatically closed. An error is raised, if
|
|
224
|
+
# no IO object is associated with the Path instance.
|
|
225
|
+
#
|
|
226
|
+
# The parameter +mode+ specifies the mode in which the IO object should be opened. This can be
|
|
227
|
+
# used, for example, to specify a certain input encoding or to use binary mode.
|
|
228
|
+
def io(mode = 'r') # :yields: io
|
|
229
|
+
raise "No IO object defined for the path #{self}" if @ioblock.nil?
|
|
230
|
+
io = @ioblock.call(mode)
|
|
231
|
+
yield(io)
|
|
232
|
+
ensure
|
|
233
|
+
io.close if io
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
# Return the content of the IO object of the path as string.
|
|
237
|
+
#
|
|
238
|
+
# For a description of the parameter +mode+ see #io.
|
|
239
|
+
#
|
|
240
|
+
# An error is raised, if no IO object is associated with the Path instance.
|
|
241
|
+
def data(mode = 'r')
|
|
242
|
+
io(mode) {|io| io.read}
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
# Set the IO block to the provided block.
|
|
246
|
+
def set_io(&block)
|
|
247
|
+
@ioblock = block
|
|
248
|
+
end
|
|
249
|
+
|
|
216
250
|
# Equality -- Return +true+ if +other+ is a Path object with the same #path or if +other+ is a
|
|
217
251
|
# String equal to the #path. Else return +false+.
|
|
218
252
|
def ==(other)
|
|
@@ -226,9 +260,9 @@ module Webgen
|
|
|
226
260
|
end
|
|
227
261
|
alias_method(:eql?, :==)
|
|
228
262
|
|
|
229
|
-
# Compare the #path of this object to
|
|
263
|
+
# Compare the #path of this object to 'other.path'.
|
|
230
264
|
def <=>(other)
|
|
231
|
-
@path <=> other.
|
|
265
|
+
@path <=> other.to_str
|
|
232
266
|
end
|
|
233
267
|
|
|
234
268
|
def hash #:nodoc:
|
|
@@ -248,9 +282,8 @@ module Webgen
|
|
|
248
282
|
private
|
|
249
283
|
#######
|
|
250
284
|
|
|
251
|
-
# Analyse the
|
|
252
|
-
def analyse
|
|
253
|
-
@path = path
|
|
285
|
+
# Analyse the path and extract the needed information.
|
|
286
|
+
def analyse
|
|
254
287
|
if @path =~ /#/
|
|
255
288
|
analyse_fragment
|
|
256
289
|
elsif @path =~ /\/$/
|
|
@@ -258,10 +291,10 @@ module Webgen
|
|
|
258
291
|
else
|
|
259
292
|
analyse_file
|
|
260
293
|
end
|
|
261
|
-
@meta_info['title']
|
|
294
|
+
@meta_info['title'] ||= @basename.tr('_-', ' ').capitalize
|
|
262
295
|
@ext ||= ''
|
|
263
296
|
raise "The basename of a path may not be empty: #{@path}" if @basename.empty? || @basename == '#'
|
|
264
|
-
raise "The parent path must start with a slash: #{@path}" if @path !~ /^\//
|
|
297
|
+
raise "The parent path must start with a slash: #{@path}" if @path !~ /^\//
|
|
265
298
|
end
|
|
266
299
|
|
|
267
300
|
# Analyse the path assuming it is a directory.
|
|
@@ -270,7 +303,7 @@ module Webgen
|
|
|
270
303
|
@basename = File.basename(@path)
|
|
271
304
|
end
|
|
272
305
|
|
|
273
|
-
FILENAME_RE = /^(?:(\d+)\.)?(\.?[^.]*?)(?:\.(\w\w\w?)(?=\.))?(?:\.(.*))?$/
|
|
306
|
+
FILENAME_RE = /^(?:(\d+)\.)?(\.?[^.]*?)(?:\.(\w\w\w?)(?=\.))?(?:\.(.*))?$/ #:nodoc:
|
|
274
307
|
|
|
275
308
|
# Analyse the path assuming it is a file.
|
|
276
309
|
def analyse_file
|
|
@@ -281,9 +314,9 @@ module Webgen
|
|
|
281
314
|
@basename = match_data[1]
|
|
282
315
|
@ext = match_data[2]
|
|
283
316
|
else
|
|
284
|
-
@meta_info['sort_info']
|
|
317
|
+
@meta_info['sort_info'] ||= (match_data[1].nil? ? nil : match_data[1].to_i)
|
|
285
318
|
@basename = match_data[2]
|
|
286
|
-
@meta_info['lang']
|
|
319
|
+
@meta_info['lang'] ||= Webgen::LanguageManager.language_for_code(match_data[3])
|
|
287
320
|
@ext = (@meta_info['lang'].nil? && !match_data[3].nil? ? match_data[3].to_s + '.' : '') + match_data[4].to_s
|
|
288
321
|
end
|
|
289
322
|
end
|
|
@@ -295,6 +328,35 @@ module Webgen
|
|
|
295
328
|
raise "A fragment path must only contain one hash character: #{path}" if @path.count("#") > 1
|
|
296
329
|
end
|
|
297
330
|
|
|
331
|
+
# Whether the version information should be added to the cn?
|
|
332
|
+
def use_version_for_cn?
|
|
333
|
+
meta_info['version'] && meta_info['version'] != 'default'
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
CN_SEGMENTS = /<.*?>|\(.*?\)/ # :nodoc:
|
|
337
|
+
|
|
338
|
+
# Construct a custom canonical name given by the 'cn' meta information.
|
|
339
|
+
def custom_cn
|
|
340
|
+
replace_segment = lambda do |match|
|
|
341
|
+
case match
|
|
342
|
+
when "<basename>"
|
|
343
|
+
basename
|
|
344
|
+
when "<ext>"
|
|
345
|
+
ext.empty? ? '' : '.' << ext
|
|
346
|
+
when "<version>"
|
|
347
|
+
use_version_for_cn? ? meta_info['version'] : ''
|
|
348
|
+
when /\((.*)\)/
|
|
349
|
+
inner = $1
|
|
350
|
+
replaced = inner.gsub(CN_SEGMENTS, &replace_segment)
|
|
351
|
+
removed = inner.gsub(CN_SEGMENTS, "")
|
|
352
|
+
replaced == removed ? '' : replaced
|
|
353
|
+
else
|
|
354
|
+
''
|
|
355
|
+
end
|
|
356
|
+
end
|
|
357
|
+
self.meta_info['cn'].gsub(CN_SEGMENTS, &replace_segment).gsub(/\/+$/, '')
|
|
358
|
+
end
|
|
359
|
+
|
|
298
360
|
end
|
|
299
361
|
|
|
300
362
|
end
|