From 729991564ec7e1116fc023c51e73b47af8b6fce7 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Fri, 12 Sep 2014 21:23:58 +0100 Subject: [PATCH] ikiwiki (3.20140916) unstable; urgency=low MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit * Don't double-decode CGI submissions with Encode.pm >= 2.53, fixing "Error: Cannot decode string with wide characters". Thanks, Antoine Beaupré * Avoid making trails depend on everything in the wiki by giving them a better way to sort the pages * Don't let users post comments that won't be displayed * Fix encoding of Unicode strings in Python plugins. Thanks, chrysn * Improve performance and correctness of the [[!if]] directive * Let [[!inline rootpage=foo postform=no]] disable the posting form * Switch default [[!man]] shortcut to manpages.debian.org. Closes: #700322 * Add UUID and TIME variables to edittemplate. Closes: #752827 Thanks, Jonathon Anderson * Display pages in linkmaps as their pagetitle (no underscore escapes). Thanks, chrysn * Fix aspect ratio when scaling small images, and add support for converting SVG and PDF graphics to PNG. Thanks, chrysn - suggest ghostscript (required for PDF-to-PNG thumbnailing) and libmagickcore-extra (required for SVG-to-PNG thumbnailing) - build-depend on ghostscript so the test for scalable images can be run * In the CGI wrapper, incorporate $config{ENV} into the environment before executing Perl code, so that PERL5LIB can point to a non-system-wide installation of IkiWiki. Thanks, Lafayette Chamber Singers Webmaster * filecheck: accept MIME types not containing ';' * autoindex: index files in underlays if the resulting pages aren't going to be committed. Closes: #611068 * Add [[!templatebody]] directive so template pages don't have to be simultaneously a valid template and valid HTML * Add myself to Uploaders and release to Debian # imported from the archive --- .gitattributes | 1 + .gitignore | 23 + .perlcriticrc | 59 + Bundle/IkiWiki.pm | 37 + Bundle/IkiWiki/Extras.pm | 42 + CHANGELOG | 1 + IkiWiki.pm | 2991 ++++ IkiWiki/CGI.pm | 482 + IkiWiki/Plugin/404.pm | 81 + IkiWiki/Plugin/aggregate.pm | 789 ++ IkiWiki/Plugin/amazon_s3.pm | 257 + IkiWiki/Plugin/anonok.pm | 51 + IkiWiki/Plugin/attachment.pm | 395 + IkiWiki/Plugin/autoindex.pm | 138 + IkiWiki/Plugin/blogspam.pm | 130 + IkiWiki/Plugin/brokenlinks.pm | 56 + IkiWiki/Plugin/bzr.pm | 330 + IkiWiki/Plugin/calendar.pm | 514 + IkiWiki/Plugin/camelcase.pm | 73 + IkiWiki/Plugin/color.pm | 78 + IkiWiki/Plugin/comments.pm | 1088 ++ IkiWiki/Plugin/conditional.pm | 129 + IkiWiki/Plugin/creole.pm | 38 + IkiWiki/Plugin/cutpaste.pm | 90 + IkiWiki/Plugin/cvs.pm | 549 + IkiWiki/Plugin/darcs.pm | 438 + IkiWiki/Plugin/date.pm | 34 + IkiWiki/Plugin/ddate.pm | 41 + IkiWiki/Plugin/editdiff.pm | 78 + IkiWiki/Plugin/editpage.pm | 476 + IkiWiki/Plugin/edittemplate.pm | 164 + IkiWiki/Plugin/embed.pm | 77 + IkiWiki/Plugin/external.pm | 255 + IkiWiki/Plugin/favicon.pm | 33 + IkiWiki/Plugin/filecheck.pm | 224 + IkiWiki/Plugin/flattr.pm | 97 + IkiWiki/Plugin/format.pm | 54 + IkiWiki/Plugin/fortune.pm | 35 + IkiWiki/Plugin/getsource.pm | 94 + IkiWiki/Plugin/git.pm | 956 ++ IkiWiki/Plugin/goodstuff.pm | 43 + IkiWiki/Plugin/google.pm | 53 + IkiWiki/Plugin/goto.pm | 85 + IkiWiki/Plugin/graphviz.pm | 149 + IkiWiki/Plugin/haiku.pm | 60 + IkiWiki/Plugin/headinganchors.pm | 43 + IkiWiki/Plugin/highlight.pm | 225 + IkiWiki/Plugin/hnb.pm | 58 + IkiWiki/Plugin/html.pm | 33 + IkiWiki/Plugin/htmlbalance.pm | 58 + IkiWiki/Plugin/htmlscrubber.pm | 127 + IkiWiki/Plugin/htmltidy.pm | 71 + IkiWiki/Plugin/httpauth.pm | 117 + IkiWiki/Plugin/img.pm | 216 + IkiWiki/Plugin/inline.pm | 799 ++ IkiWiki/Plugin/link.pm | 176 + IkiWiki/Plugin/linkmap.pm | 113 + IkiWiki/Plugin/listdirectives.pm | 100 + IkiWiki/Plugin/localstyle.pm | 35 + IkiWiki/Plugin/lockedit.pm | 58 + IkiWiki/Plugin/map.pm | 163 + IkiWiki/Plugin/mdwn.pm | 118 + IkiWiki/Plugin/mercurial.pm | 400 + IkiWiki/Plugin/meta.pm | 469 + IkiWiki/Plugin/mirrorlist.pm | 71 + IkiWiki/Plugin/moderatedcomments.pm | 64 + IkiWiki/Plugin/monotone.pm | 772 + IkiWiki/Plugin/more.pm | 45 + IkiWiki/Plugin/norcs.pm | 72 + IkiWiki/Plugin/notifyemail.pm | 169 + IkiWiki/Plugin/opendiscussion.pm | 33 + IkiWiki/Plugin/openid.pm | 284 + IkiWiki/Plugin/orphans.pm | 68 + IkiWiki/Plugin/osm.pm | 596 + IkiWiki/Plugin/otl.pm | 93 + IkiWiki/Plugin/pagecount.pm | 40 + IkiWiki/Plugin/pagestats.pm | 120 + IkiWiki/Plugin/pagetemplate.pm | 50 + IkiWiki/Plugin/parentlinks.pm | 75 + IkiWiki/Plugin/passwordauth.pm | 450 + IkiWiki/Plugin/pingee.pm | 42 + IkiWiki/Plugin/pinger.pm | 121 + IkiWiki/Plugin/po.pm | 1399 ++ IkiWiki/Plugin/poll.pm | 183 + IkiWiki/Plugin/polygen.pm | 70 + IkiWiki/Plugin/postsparkline.pm | 149 + IkiWiki/Plugin/prettydate.pm | 127 + IkiWiki/Plugin/progress.pm | 76 + IkiWiki/Plugin/rawhtml.pm | 23 + IkiWiki/Plugin/recentchanges.pm | 251 + IkiWiki/Plugin/recentchangesdiff.pm | 80 + IkiWiki/Plugin/relativedate.pm | 71 + IkiWiki/Plugin/remove.pm | 297 + IkiWiki/Plugin/rename.pm | 617 + IkiWiki/Plugin/repolist.pm | 52 + IkiWiki/Plugin/rsync.pm | 45 + IkiWiki/Plugin/search.pm | 289 + IkiWiki/Plugin/shortcut.pm | 107 + IkiWiki/Plugin/sidebar.pm | 109 + IkiWiki/Plugin/signinedit.pm | 41 + IkiWiki/Plugin/skeleton.pm.example | 272 + IkiWiki/Plugin/smiley.pm | 107 + IkiWiki/Plugin/sortnaturally.pm | 38 + IkiWiki/Plugin/sparkline.pm | 173 + IkiWiki/Plugin/svn.pm | 380 + IkiWiki/Plugin/table.pm | 210 + IkiWiki/Plugin/tag.pm | 218 + IkiWiki/Plugin/template.pm | 73 + IkiWiki/Plugin/templatebody.pm | 81 + IkiWiki/Plugin/testpagespec.pm | 42 + IkiWiki/Plugin/teximg.pm | 191 + IkiWiki/Plugin/textile.pm | 35 + IkiWiki/Plugin/theme.pm | 75 + IkiWiki/Plugin/tla.pm | 299 + IkiWiki/Plugin/toc.pm | 142 + IkiWiki/Plugin/toggle.pm | 88 + IkiWiki/Plugin/trail.pm | 466 + IkiWiki/Plugin/transient.pm | 51 + IkiWiki/Plugin/txt.pm | 88 + IkiWiki/Plugin/typography.pm | 51 + IkiWiki/Plugin/underlay.pm | 41 + IkiWiki/Plugin/userlist.pm | 76 + IkiWiki/Plugin/version.pm | 48 + IkiWiki/Plugin/websetup.pm | 517 + IkiWiki/Plugin/wikitext.pm | 33 + IkiWiki/Plugin/wmd.pm | 51 + IkiWiki/Receive.pm | 91 + IkiWiki/Render.pm | 977 ++ IkiWiki/Setup.pm | 281 + IkiWiki/Setup/Automator.pm | 213 + IkiWiki/Setup/Standard.pm | 72 + IkiWiki/Setup/Yaml.pm | 49 + IkiWiki/UserInfo.pm | 77 + IkiWiki/Wrapper.pm | 304 + Makefile.PL | 192 + NEWS | 1 + README | 27 + auto-blog.setup | 54 + auto.setup | 44 + cpan/CPAN/MyConfig.pm | 44 + cpan/README | 7 + debian/.gitignore | 3 + debian/NEWS | 572 + debian/README.Debian | 18 + debian/changelog | 4779 +++++++ debian/compat | 1 + debian/control | 62 + debian/copyright | 348 + debian/docs | 1 + debian/link | 2 + debian/postinst | 14 + debian/preinst | 20 + debian/rules | 19 + doc/GPL | 340 + doc/TourBusStop.mdwn | 30 + doc/anchor.mdwn | 11 + doc/backlinks.mdwn | 2 + doc/banned_users.mdwn | 10 + doc/banned_users/discussion.mdwn | 31 + doc/basewiki.mdwn | 26 + doc/basewiki/index.mdwn | 7 + doc/basewiki/sandbox.mdwn | 32 + doc/blog.mdwn | 4 + doc/branches.mdwn | 25 + doc/bugs.mdwn | 13 + doc/bugs/2.45_Compilation_error.mdwn | 198 + doc/bugs/404_plugin_and_lighttpd.mdwn | 45 + doc/bugs/404_plugin_should_handle_403.mdwn | 16 + doc/bugs/404_when_cancel_create_page.mdwn | 60 + doc/bugs/4_spaces_after_bullet.mdwn | 18 + ...r_div_on_all_pages_to_improve_theming.mdwn | 149 + ...s_for_suggesting__47__accepting_edits.mdwn | 15 + ...regated_Atom_feeds_are_double-encoded.mdwn | 22 + ...low_overriding_of_symlink_restriction.mdwn | 139 + doc/bugs/Another_UTF-8_problem.mdwn | 16 + ...tachment_plug-in_not_committing_files.mdwn | 18 + doc/bugs/Broken_URL_to_your_blog_script.mdwn | 10 + doc/bugs/Broken_access_to_Ikiwiki_gitweb.mdwn | 19 + ...ebar_does_not_regenerate_the_subpages.mdwn | 8 + ...lder__44___non-existent_field_address.mdwn | 59 + .../CGI_edit_and_slash_in_page_title.mdwn | 18 + .../CGI_problem_with_some_webservers.mdwn | 108 + doc/bugs/CGI_showed_HTML_when_perl_error.mdwn | 40 + ...t_store_PERL5LIB_environment_variable.mdwn | 71 + ..._Recent_Changes_create_spurious_Links.mdwn | 11 + doc/bugs/Can__39__t_build_2.49__63__.mdwn | 35 + ...nect_to_ikiwiki_git_repo_through_http.mdwn | 18 + doc/bugs/Can__39__t_create_root_page.mdwn | 69 + doc/bugs/Can__39__t_deplete_page__63__.mdwn | 8 + ..._rebuild_wiki_pages_with_ikiwiki_2.49.mdwn | 44 + ...nline_pages_with_apostrophes_in_title.mdwn | 7 + doc/bugs/Changing_language.mdwn | 9 + ...sum_errors_on_the_pristine-tar_branch.mdwn | 112 + ...d_override_settings_in_the_setup_file.mdwn | 32 + ...re_not_sorted_by_their_date_attribute.mdwn | 71 + doc/bugs/Comments_dissapeared.mdwn | 69 + ...ink_is_to_index.html_if_usedirs_is_on.mdwn | 5 + ...er__34___OpenID_at_RecentChanges_page.mdwn | 44 + doc/bugs/Disappearing_Pages.mdwn | 41 + ...link_not_translated_after_page_update.mdwn | 27 + ...iscussion_link_not_translated_in_post.mdwn | 67 + ...n_of_main_page_generates_invalid_link.mdwn | 3 + ...40____41___really_return_a_hash__63__.mdwn | 10 + ...e_entry_in_Bundle::IkiWiki::Extras.pm.mdwn | 5 + .../Encoding_problem_in_calendar_plugin.mdwn | 73 + .../Error:_OpenID_failure:_time_bad_sig:.mdwn | 87 + ...ror:_Your_login_session_has_expired._.mdwn | 46 + ...his_page_--_missing_page_dependencies.mdwn | 46 + ...n:_Unknown_function___96__this__39___.mdwn | 70 + ...st_nesting_in_map_output_for_subpages.mdwn | 3 + ...scussion_pages_appear_as_non-existing.mdwn | 5 + .../External_link:_underscore_conversion.mdwn | 25 + doc/bugs/External_links_with_Creole.mdwn | 5 + ...cy_characters_get_munged_on_page_save.mdwn | 29 + doc/bugs/Feeds_get_wrong_timezone..mdwn | 10 + ...nk_to_index.html_instead_of_directory.mdwn | 37 + ...lons_cause_problems_for_Windows_users.mdwn | 75 + ...n_help_page_regardless_of_page_format.mdwn | 3 + ...t:_changed_behavior_w.r.t._timestamps.mdwn | 214 + .../Git:_web_commit_message_not_utf-8.mdwn | 17 + ...viz_plug-in_directive_changed_in_2.60.mdwn | 11 + ...ML_for_parentlinks_makes_theming_hard.mdwn | 45 + ...into_Atom_not_necessarily_well-formed.mdwn | 35 + ...created_when_editing_markdown_via_CGI.mdwn | 43 + ...light_extension_uses_hard_coded_paths.mdwn | 3 + ...rror_500_when_using_mercurial_backend.mdwn | 31 + ...yperestraier_search_plug-in_defective.mdwn | 55 + ...cation_not_set_correctly_in_make_test.mdwn | 24 + ...____41___broken_outside_ikiwiki__63__.mdwn | 20 + .../IkiWiki::Wrapper_should_use_destdir.mdwn | 23 + .../discussion.mdwn | 4 + ...use_file__39__s_mtime_for_Last_Edited.mdwn | 21 + .../Index_files_have_wrong_permissions.mdwn | 14 + ...Inline_doesn__39__t_wikilink_to_pages.mdwn | 96 + ...dds_newlines_which_can_break_markdown.mdwn | 43 + ..._in_eval_while_running_with_-T_switch.mdwn | 98 + doc/bugs/Insecure_dependency_in_mkdir.mdwn | 160 + doc/bugs/Insecure_dependency_in_utime.mdwn | 14 + ...rt_multiple_linkmaps_on_a_single_page.mdwn | 3 + ...missing_pages_should_always_be_styled.mdwn | 5 + ...nks_with_symbols_can__39__t_be_edited.mdwn | 22 + ...not_set_for_inline_or_archive_entries.mdwn | 22 + ...p_sorts_subtags_under_a_different_tag.mdwn | 49 + ...rl_should_read_r2__44___not_changeset.mdwn | 11 + ...__95__skip_setting.___40__patch__41__.mdwn | 11 + ...Missing_build-dep_on_perlmagick__63__.mdwn | 14 + ...onstant_domain_at_IkiWiki.pm_line_842.mdwn | 50 + doc/bugs/Monotone_rcs_support.mdwn | 58 + doc/bugs/More_permission_checking.mdwn | 17 + ...e_being_commented_on_while_commenting.mdwn | 11 + ...yed__59___need_page_refresh_to_appear.mdwn | 35 + ...rror:_Your_login_session_has_expired..mdwn | 39 + .../No_categories_in_RSS__47__Atom_feeds.mdwn | 7 + ..._items_when_filename_contains_a_colon.mdwn | 76 + ...inks_setting_for___34__no_limit__34__.mdwn | 4 + doc/bugs/No_progress_in_progress_bar.mdwn | 43 + ...e_listed_by___33__map_or___33__inline.mdwn | 68 + .../Obsolete_templates__47__estseek.conf.mdwn | 3 + .../OpenID_delegation_fails_on_my_server.mdwn | 53 + ...G_triggers_UTF-8_error_in_MimeInfo.pm.mdwn | 25 + .../PREFIX_not_honoured_for_underlaydir.mdwn | 44 + ...name_not_found_directly_after_commit.mdwn" | 145 + doc/bugs/Patch:_Fix_error_in_style.css.mdwn | 37 + ...epend_on___47__usr__47__bin__47__perl.mdwn | 6 + ...sing___39__cp_-a__39___in_Makefile.PL.mdwn | 77 + ...__39__t_refer_to_offsite_openid_image.mdwn | 19 + ...e_highlight_plugin_for_highlight_3.18.mdwn | 12 + ...moves_page_location_drop-down_options.mdwn | 10 + ...ith_displaying_smileys_on_inline_page.mdwn | 25 + ...h_editing_page_after_first_SVN_commit.mdwn | 209 + doc/bugs/Problem_with_toc.pm_plug-in.mdwn | 37 + .../Problem_with_umlauts_and_friends.mdwn | 16 + doc/bugs/Problems_using_cygwin.mdwn | 20 + .../Problems_with_graphviz.pm_plug-in.mdwn | 43 + ...ems_with_graphviz.pm_plug-in_previews.mdwn | 54 + ...centChanges_broken_with_empty_svnpath.mdwn | 26 + .../RecentChanges_contains_invalid_XHTML.mdwn | 55 + .../RecentChanges_links_to_deleted_pages.mdwn | 15 + ...move_redirect_pages_from_inline_pages.mdwn | 15 + ..._web_is_failing_when_using_subversion.mdwn | 28 + .../Running_on_an_alternative_port_fails.mdwn | 93 + doc/bugs/SSI_include_stripped_from_mdwn.mdwn | 21 + .../SVG_files_not_recognized_as_images.mdwn | 39 + doc/bugs/Search_Help_doesn__39__t_exist.mdwn | 8 + ...l__44___when_use__95__dirs_is_enabled.mdwn | 15 + ...ludes_text_from_navigational_elements.mdwn | 22 + ..._not_clickable_while_adding_a_comment.mdwn | 9 + ...attachments___34__snails_it_all__34__.mdwn | 47 + .../discussion.mdwn | 141 + doc/bugs/Smileys_in_the_block_code.mdwn | 34 + ...Spaces_in_link_text_for_ikiwiki_links.mdwn | 53 + ...ements_added_to_tags_in_inliine_pages.mdwn | 59 + .../discussion.mdwn | 9 + ...roken___34__FormattingHelp__34___link.mdwn | 3 + ...linked_srcdir_requires_trailing_slash.mdwn | 81 + .../Tab_delimited_tables_don__39__t_work.mdwn | 22 + ...variable_not_passed_as-is__63____33__.mdwn | 23 + ..._are_lower-cased_when_creating_a_page.mdwn | 37 + ...ate_plugins_do_not_play_well_together.mdwn | 30 + doc/bugs/Trailing_slash_breaks_links.mdwn | 9 + ...URLs_with_parentheses_displayed_badly.mdwn | 19 + doc/bugs/UTF-16_and_UTF-32_are_unhandled.mdwn | 29 + ...-8_BOM_showing_up_inside_a_page__63__.mdwn | 38 + doc/bugs/UTF-8_in_attachment_filenames.mdwn | 25 + ...able_to_add_attachments_to_some_pages.mdwn | 31 + ...efined_subroutine_IkiWiki::escapeHTML.mdwn | 27 + ...Undefined_subroutine_IkiWiki::refresh.mdwn | 7 + ...nderscores_in_links_don__39__t_appear.mdwn | 20 + ..._cp__40__1__41___for_installing_files.mdwn | 32 + ...uses_http:__47____47__localhost__63__.mdwn | 34 + ..._a_directive_does_not_contain_a_space.mdwn | 19 + ...omment_don__39__t_make_it_through_git.mdwn | 53 + ..._between_toc_plugin_and_page_sections.mdwn | 40 + doc/bugs/Wrong_permissions_on_4_smileys.mdwn | 10 + ...needs_xmlns_attribute_on_html_element.mdwn | 5 + ...4__meta__40__date__41____34___ignored.mdwn | 41 + ...only_first_139_characters_of_each_key.mdwn | 12 + ..._deletion_does_not_refresh_front_page.mdwn | 6 + .../__34__more__34___doesn__39__t_work.mdwn | 17 + ...__error_when_src_path_contains_spaces.mdwn | 5 + ..._PATH__125___should_include_PREFIXbin.mdwn | 19 + ...kes_ikiwiki_not_un-escape_HTML_at_all.mdwn | 47 + ...are_removed_from_markdown_inline_HTML.mdwn | 31 + .../__63__Discussion_when_not_CGI_mode.mdwn | 9 + ...___Use_correct_perl_when_running_make.html | 17 + ...c_plugin_and_UTF-8:_IkiWiki_and_UTF-8.mdwn | 11 + .../discussion.mdwn | 23 + ...o__93____93___doesn__39__t_disable_it.mdwn | 24 + ...9___for___96__.page__42____39____63__.mdwn | 35 + ...setting_not_propagated_to_CGI_wrapper.mdwn | 28 + doc/bugs/absolute_sizes_in_default_CSS.mdwn | 39 + .../aggregate_generates_long_filenames.mdwn | 40 + doc/bugs/aggregate_global_feed_names.mdwn | 13 + doc/bugs/aggregate_plugin_errors.mdwn | 62 + .../aggregate_plugin_errors/discussion.mdwn | 6 + ...in_should_honour_a_post__39__s_mctime.mdwn | 17 + doc/bugs/aggregate_removed_feeds_linger.mdwn | 11 + ...einline_planets_wrongly_link_to_posts.mdwn | 17 + ...n__39__t_always_work_with_img_plugin_.mdwn | 7 + doc/bugs/anonok_vs._httpauth.mdwn | 118 + ...xing_templates_and_creation__95__date.mdwn | 62 + ...__git_push_origin__34___is_sufficient.mdwn | 18 + ...scaping_underscores_in_filename__63__.mdwn | 22 + .../attachment:_failed_to_get_filehandle.mdwn | 115 + ...hment_plugin_enabled_by_default__63__.mdwn | 19 + ...oad_does_not_work_for_windows_clients.mdwn | 34 + ...cklink__40__.__41___doesn__39__t_work.mdwn | 57 + .../backlinks_onhover_thing_can_go_weird.mdwn | 43 + ...a_change_removing_an_invalid_pagespec.mdwn | 48 + ...es_but_meta_is_not_enabled_by_default.mdwn | 5 + ....__47___even_if_it_is_already_present.mdwn | 3 + doc/bugs/bestlink_change_update_issue.mdwn | 32 + doc/bugs/bestlink_returns_deleted_pages.mdwn | 75 + ...log_posts_not_added_to_mercurial_repo.mdwn | 50 + ...in_not_allowing_non-ASCII_chars__63__.mdwn | 15 + ..._95__options_whitelist_vs._IPv6__63__.mdwn | 4 + .../blogspam_marks_me_as_spam_on_ipv6.mdwn | 8 + ...ment_create_elements_id__61__feedlink.mdwn | 15 + doc/bugs/broken_page_after_buggy_remove.mdwn | 4 + doc/bugs/broken_parentlinks.mdwn | 50 + ...okenlinks_accumulates_duplicate_items.mdwn | 27 + doc/bugs/brokenlinks_false_positives.mdwn | 6 + doc/bugs/bug_in_cgiurl_port.mdwn | 15 + .../bug_when_toggling_in_a_preview_page.mdwn | 29 + ...:_Broken_pipe__34_____40__patch__41__.mdwn | 24 + ...oddly_when_older_ikiwiki_is_installed.mdwn | 31 + doc/bugs/build_in_opensolaris.mdwn | 74 + doc/bugs/bzr-update-syntax-error.mdwn | 11 + doc/bugs/bzr_2.0_breaks_bzr_plugin.mdwn | 87 + ...r_RecentChanges_dates_start_from_1969.mdwn | 16 + ..._plugin_does_not_define_rcs__95__diff.mdwn | 27 + ...t_mix_template_vars_inside_directives.mdwn | 61 + ...e_is_application__47__octet-stream....mdwn | 95 + .../cannot_clone_documented_git_repo.mdwn | 16 + ..._characters_error_with_utf-8_encoding.mdwn | 7 + doc/bugs/cannot_preview_shortcuts.mdwn | 17 + .../cannot_reliably_use_meta_in_template.mdwn | 18 + doc/bugs/cannot_revert_page_deletion.mdwn | 10 + doc/bugs/capitalized_attachment_names.mdwn | 14 + .../cgi_does_not_use_templatedir_overlay.mdwn | 26 + doc/bugs/cgi_wrapper_always_regenerated.mdwn | 16 + ...e_web_interface_fail_to_get_committed.mdwn | 71 + ...mg_directive_behave_not_as_documented.mdwn | 31 + .../clearenv_not_present_at_FreeBSD_.mdwn | 5 + .../discussion.mdwn | 1 + doc/bugs/clearing_email_in_prefs.mdwn | 5 + doc/bugs/colon:problem.mdwn | 12 + doc/bugs/colon:problem/discussion.mdwn | 1 + doc/bugs/comments_appear_two_times.mdwn | 24 + doc/bugs/comments_not_searchable.mdwn | 19 + ...s_preview_unsafe_with_allowdirectives.mdwn | 8 + ...produce_broken_links_in_RecentChanges.mdwn | 9 + ...1___in_wikilink-text_breaks_wikilinks.mdwn | 9 + .../conditional_preprocess_during_scan.mdwn | 112 + doc/bugs/conflicts.mdwn | 32 + ...pdated_time_information_for_the_feeds.mdwn | 113 + ..._in_the_python_proxy_even_if_disabled.mdwn | 74 + ...g_page_from_comment_creates_a_comment.mdwn | 9 + .../cutpaste.pm:_missing_filter_call.mdwn | 55 + ...e_timeformat__44___even_when_disabled.mdwn | 7 + ...ug_shortcut_should_expand_differently.mdwn | 17 + .../discussion.mdwn | 11 + ..._pull_in_packages_required_for_openid.mdwn | 9 + ...ortcut_creates_buggy_URLs_to_subpages.mdwn | 5 + .../default__95__pageext_not_working.mdwn | 16 + doc/bugs/definition_lists_should_be_bold.mdwn | 27 + ...defintion_lists_appear_to_be_disabled.mdwn | 54 + doc/bugs/deletion_warnings.mdwn | 89 + doc/bugs/depends_simple_mixup.mdwn | 88 + doc/bugs/diff_links_to_backtrace.mdwn | 9 + doc/bugs/disable_sub-discussion_pages.mdwn | 63 + doc/bugs/disabling_backlinks.mdwn | 32 + doc/bugs/discussion.mdwn | 18 + doc/bugs/discussion_of_what__63__.mdwn | 7 + ...ak_the_detection_of_the_best_location.mdwn | 6 + doc/bugs/discussion_removal.mdwn | 16 + ...big_brother_spy_on_our_users_on_login.mdwn | 79 + doc/bugs/done.mdwn | 3 + doc/bugs/dumpsetup_does_not_save_destdir.mdwn | 3 + ...esolves_links_differently_from_commit.mdwn | 23 + ...ing_gitbranch_template_is_really_slow.mdwn | 67 + ...age_turned_off_in_web_interface__63__.mdwn | 10 + ...dits_not_showing_up_in_compiled_pages.mdwn | 20 + .../edittemplate_seems_not_to_be_working.mdwn | 7 + ...uld_not_be_considered_as_broken_links.mdwn | 12 + doc/bugs/empty_div_element.mdwn | 35 + ...d_pages_that_use_enabled__40__x__41__.mdwn | 11 + .../encoding_issue_in_blogspam_plugin.mdwn | 34 + ...gated_pagespec_matches_internal_pages.mdwn | 30 + ...ions_of_dates_not_formatted_correctly.mdwn | 43 + ...with_gettext_can_clobber___36____64__.mdwn | 29 + .../errors_with_ampersand_in_filename.mdwn | 21 + ...oryurl_doesn__39__t_show_file_history.mdwn | 17 + ...links_inside_headings_don__39__t_work.mdwn | 24 + ..._cannot_access_ARGV_needed_for_getopt.mdwn | 14 + ...does_the_wrong_thing_from_index.mdwn2.mdwn | 7 + ...ot_prevent_tags_from_being_aggregated.mdwn | 32 + ...eds_get_removed_in_strange_conditions.mdwn | 57 + doc/bugs/filecheck_failing_to_find_files.mdwn | 65 + ...ind:_invalid_predicate___96__-L__39__.mdwn | 26 + doc/bugs/find_gnuism.mdwn | 7 + ...to_load_updated_pages_at_ikiwiki.info.mdwn | 14 + doc/bugs/format_bug.mdwn | 25 + doc/bugs/formbuilder_3.0401_broken.mdwn | 73 + ...i_characters_in_body_in_web_interface.mdwn | 126 + ...d_prune_remote_branches_when_fetching.mdwn | 14 + ...mmit_adds_files_that_were_not_tracked.mdwn | 19 + doc/bugs/git_fails_to_compile.mdwn | 32 + doc/bugs/git_mail_notification_race.mdwn | 57 + .../git_stderr_output_causes_problems.mdwn | 45 + doc/bugs/git_utf8.mdwn | 12 + ...es_script_picks_up_tags_from_anywhere.mdwn | 22 + ...gitweb_deficiency_w.r.t._log_messages.mdwn | 14 + ...deficiency_w.r.t._newly_created_pages.mdwn | 13 + doc/bugs/goto_with_bad_page_name.mdwn | 25 + .../graphviz_demo_generates_empty_graph.mdwn | 15 + ...hardcoded___34__Discussion__34___link.mdwn | 44 + .../helponformatting_link_disappears.mdwn | 5 + doc/bugs/html5_support.mdwn | 117 + ...ng_when_using_xhtml5___34__mode__34__.mdwn | 46 + doc/bugs/html_errors.mdwn | 5 + .../htmlbalance_fails_with_HTML-Tree_v4.mdwn | 18 + ...rubber_breaks_multimarkdown_footnotes.mdwn | 18 + ..._still_scrubbing_HTML_from_mdwn_pages.mdwn | 21 + ...s_email_obfuscation_by_Text::Markdown.mdwn | 37 + ...fig_file_which_may_break_other_usages.mdwn | 26 + doc/bugs/http_proxy_for_openid.mdwn | 85 + ...httpauth_conflicts_with_git_anon_push.mdwn | 25 + ...o_drop_privileges_and_execute_ikiwiki.mdwn | 30 + ...es_not_set_perl_moduels_path_properly.mdwn | 17 + ...0__eval_5__41___line_120__44___at_EOF.mdwn | 9 + ...require_blank_rcs_to_work_as_cgi_only.mdwn | 46 + doc/bugs/ikiwiki__39__s_ViewVC_down.mdwn | 3 + ...n_Solaris_due_to_missing_LOCK__95__EX.mdwn | 43 + .../ikiwiki_ignores_PATH_environment.mdwn | 24 + doc/bugs/ikiwiki_lacks_a_--quiet.mdwn | 29 + ...ly_honours_locks_when_asked_for_forms.mdwn | 34 + ...___if_external_plugins_return_nothing.mdwn | 12 + ...escaling_distorts_with_small_pictures.mdwn | 51 + ...inlined_pages_have_wrong_relative_URL.mdwn | 22 + doc/bugs/img_plugin_and_class_attr.mdwn | 27 + .../img_plugin_and_missing_heigth_value.mdwn | 7 + doc/bugs/img_plugin_causes_taint_failure.mdwn | 20 + ...__tag_without_src_attribute_post-2.20.mdwn | 36 + ...n_should_pass_through_class_attribute.mdwn | 49 + doc/bugs/img_test_failing_under_sbuild.mdwn | 25 + doc/bugs/img_vs_align.mdwn | 38 + .../img_with_alt_has_extra_double_quote.mdwn | 32 + doc/bugs/index.html__63__updated.mdwn | 15 + ...ml_is_made_visible_by_various_actions.mdwn | 16 + doc/bugs/iniline_breaks_toc_plugin.mdwn | 64 + ...9__s_match__61____34____34___pagespec.mdwn | 15 + doc/bugs/inline_archive_crash.mdwn | 6 + .../inline_breaks_PERMALINK_variable.mdwn | 25 + ..._empty_if_rootpage_doesn__39__t_exist.mdwn | 20 + .../inline_page_not_updated_on_removal.mdwn | 9 + ...otpage_option_is_not_case_insensitive.mdwn | 9 + ...diturl_even_when_editpage_is_disabled.html | 16 + ...inline_raw_broken_on_unknown_pagetype.mdwn | 29 + doc/bugs/inline_skip_causes_empty_inline.mdwn | 10 + doc/bugs/inline_sort-by-title_issues.mdwn | 57 + ...inline_sort_order_and_meta_date_value.mdwn | 314 + doc/bugs/install_into_home_dir_fails.mdwn | 57 + ...ling_from_svn_copies_.svn_directories.mdwn | 28 + ...l_error:_smileys.mdwn_cannot_be_found.mdwn | 41 + doc/bugs/ipv6_address_in_comments.mdwn | 19 + ...y-ui.min.css_missing_some_image_files.mdwn | 14 + ...-xml-perl_0.69_breaks_XML-RPC_plugins.mdwn | 13 + ..._page_at_root_if_non-root_page_exists.mdwn | 6 + .../linkmap_displays_underscore_escapes.mdwn | 37 + .../the_patch.pl | 68 + doc/bugs/links_from_sidebars.mdwn | 14 + doc/bugs/links_from_sidebars/discussion.mdwn | 5 + doc/bugs/links_misparsed_in_CSV_files.mdwn | 27 + ...rectives_doesn__39__t_register_a_link.mdwn | 145 + ...ut_an_invalid_pagespec_in_preferences.mdwn | 21 + doc/bugs/locking_fun.mdwn | 105 + .../login_page_non-obvious_with_openid.mdwn | 47 + ...n_page_should_note_cookie_requirement.mdwn | 39 + doc/bugs/logout_in_ikiwiki.mdwn | 44 + ...t_properly_generated_in_rssatom_feeds.mdwn | 29 + ...irectory_for_which_a_file_also_exists.mdwn | 26 + .../discussion.mdwn | 3 + ...4__common__95__prefix__34___correctly.mdwn | 70 + ...ls_to_close_ul_element_for_empty_list.mdwn | 93 + doc/bugs/map_generates_malformed_HTML.mdwn | 36 + ...s_inconsistent_about_bare_directories.mdwn | 86 + ...ot_title_when_show__61__title_is_used.mdwn | 20 + ...directories_sometimes_make_ugly_lists.mdwn | 62 + ...ug:_email_escaping_and_plus_addresses.mdwn | 37 + doc/bugs/markdown_module_location.mdwn | 49 + doc/bugs/mercurial_fail_to_add.mdwn | 34 + ...o_basewiki_causes_odd_inconsistencies.mdwn | 6 + doc/bugs/messed_up_repository.mdwn | 21 + doc/bugs/meta_inline.mdwn | 4 + .../methodResponse_in_add__95__plugins.mdwn | 41 + doc/bugs/minor:_tiny_rendering_error.mdwn | 5 + ...t_the_current_page___40__if_any__41__.mdwn | 101 + ...end_does_not_support_srcdir_in_subdir.mdwn | 5 + doc/bugs/more_and_RSS_generation.mdwn | 20 + .../multiple_encoding_issues_in_atom.mdwn | 8 + doc/bugs/multiple_pages_with_same_name.mdwn | 76 + doc/bugs/multiple_rss_feeds_per_page.mdwn | 31 + ...re_uploading_more_than_one_attachment.mdwn | 44 + .../nested_inlines_produce_no_output.mdwn | 12 + doc/bugs/nested_raw_included_inlines.mdwn | 51 + doc/bugs/newfile-test.mdwn | 11 + doc/bugs/no_commit_mails_for_new_pages.mdwn | 10 + ...ntainer_around_a_set_of_inlined_pages.mdwn | 23 + ...9__t_do_search_in_w3m_at_ikiwiki.info.mdwn | 32 + ...ine_pagenames_do_not_add_a_dependency.mdwn | 44 + ...mail_fails_with_some_openid_providers.mdwn | 111 + .../octal_umask_setting_is_unintuitive.mdwn | 55 + ..._should_respect_the_discussion_option.mdwn | 11 + .../discussion.mdwn | 26 + ...ed_with_simple_registration_extension.mdwn | 3 + ...ld_not_determine_ID_provider_from_URL.mdwn | 200 + ...penid_no_longer_pretty-prints_OpenIDs.mdwn | 17 + doc/bugs/openid_postsignin_failure.mdwn | 52 + ...o_not_display_properly_on_google_maps.mdwn | 14 + ..._maps_icon_path_have_a_trailing_slash.mdwn | 34 + ...40____41___usage_breaks_map_rendering.mdwn | 23 + ...rror_TypeError:_mapProjection_is_null.mdwn | 8 + doc/bugs/osm_sometimes_looses_some_nodes.mdwn | 5 + ..._list_the_full_path_to_affected_pages.mdwn | 14 + ...uild_fails_in_non-English_environment.mdwn | 11 + ...s_not_rebuilt_if_it_changes_extension.mdwn | 27 + ...oes_not_work_on_new_page_with_a_table.mdwn | 3 + doc/bugs/pagecount_is_broken.mdwn | 4 + doc/bugs/pagemtime_in_refresh_mode.mdwn | 28 + .../pages_missing_top-level_directory.mdwn | 78 + .../pages_under_templates_are_invalid.mdwn | 21 + ...ec:_tagged__40____41____44___globbing.mdwn | 36 + ...9__t_match___123__curly__125___braces.mdwn | 44 + ...spec_error_on_refresh_but_not_rebuild.mdwn | 32 + ...arsing_chokes_on_function__40____41__.mdwn | 64 + doc/bugs/pagestats_plugin_broken.mdwn | 29 + ...function_does_not_respect_meta_titles.mdwn | 289 + ...should_only_be_done_outside_html_tags.mdwn | 17 + doc/bugs/password_deletion.mdwn | 7 + ...e_character_in_subroutine_entry__34__.mdwn | 29 + doc/bugs/perl:_double_free_or_corruption.mdwn | 14 + doc/bugs/pipe-symbol_in_taglink_target.mdwn | 25 + doc/bugs/pipe_in_tables_as_characters.mdwn | 16 + ...__96__attachment__96___is_not_enabled.mdwn | 7 + ...edate_depends_on_locale_at_setup_file.mdwn | 16 + ...nfig_serves_index_directory_for_index.mdwn | 85 + ...che_config_serves_index.rss_for_index.mdwn | 36 + doc/bugs/po:_double_commits_of_po_files.mdwn | 22 + doc/bugs/po:_markdown_link_parse_bug.mdwn | 21 + ..._translated_versions_of_all_underlays.mdwn | 16 + doc/bugs/po:_new_pages_not_translatable.mdwn | 12 + ...ot_override_the_title_on_the_homepage.mdwn | 58 + .../po:_po4a_too_strict_on_html_pages.mdwn | 24 + .../po:_po_files_instead_of_html_files.mdwn | 30 + .../po:_ugly_messages_with_empty_files.mdwn | 6 + ...able_basewiki_pages_that_lack_po_fies.mdwn | 73 + doc/bugs/po_plugin_adds_new_dependency.mdwn | 38 + ...o_plugin_cannot_add_po_files_into_git.mdwn | 34 + doc/bugs/po_vs_templates.mdwn | 48 + doc/bugs/poll_in_inline.mdwn | 6 + ...can__39__t_vote_for_non-ascii_options.mdwn | 7 + doc/bugs/poll_plugin_uses_GET.mdwn | 8 + ...t_comments_that_will_not_be_displayed.mdwn | 34 + doc/bugs/possibly_po_related_error.mdwn | 20 + doc/bugs/post-commit_hangs.mdwn | 47 + ..._hook_can__39__t_be_compiled_with_tcc.mdwn | 19 + .../preprocessing_loop_control_too_tight.mdwn | 23 + ...ydate_with_weekday-date_inconsistency.mdwn | 32 + .../preview_base_url_should_be_absolute.mdwn | 53 + doc/bugs/preview_pagestate.mdwn | 13 + ...ing_new_page_can_leave_files_dangling.mdwn | 53 + ...with_an_edittemplate_reverts_edit_box.mdwn | 5 + .../problem_adding_tag_from_template.mdwn | 10 + doc/bugs/proxy.py_utf8_troubles.mdwn | 35 + .../prune_causing_taint_mode_failures.mdwn | 35 + doc/bugs/pruning_is_too_strict.mdwn | 12 + doc/bugs/pythonproxy-utf8_again.mdwn | 70 + doc/bugs/quieten_mercurial.mdwn | 34 + ..._91____91____33__included__93____93__.mdwn | 100 + ...hanging_the_underlaydir_config_option.mdwn | 12 + doc/bugs/recentchanges_escaping.mdwn | 5 + doc/bugs/recentchanges_feed_links.mdwn | 107 + ..._diffurl__61__1_when_diffurl_is_empty.mdwn | 18 + ...n_commits_which_remove_a_lot_of_files.mdwn | 46 + doc/bugs/relative_date_weird_results.mdwn | 4 + doc/bugs/removal_of_transient_pages.mdwn | 78 + ..._orphaned_sparkline-php_from_Suggests.mdwn | 22 + .../remove_plugin_and_untracked_files.mdwn | 6 + .../removing_pages_with_utf8_characters.mdwn | 51 + ...rename_fixup_not_attributed_to_author.mdwn | 12 + .../renaming_a_page_destroyed_some_links.mdwn | 12 + ...g_with_only_width_or_height_breaks_ie.mdwn | 9 + doc/bugs/rss_feed_cleanup_on_delete.mdwn | 6 + ..._encoding_of_entities_for_some_fields.mdwn | 52 + doc/bugs/rss_output_relative_links.mdwn | 3 + ...ails_on_file_containing_only_a_number.mdwn | 31 + ...dec_can__39__t_encode_character__34__.mdwn | 40 + doc/bugs/rst_plugin_hangs_on_utf-8.mdwn | 20 + ..._plugin_hangs_when_used_with_Python_3.mdwn | 37 + ...n_has_python_hardcode_in_shebang_line.mdwn | 15 + ...impleXMLRPCDispatcher_from_pyhton_2.5.mdwn | 13 + doc/bugs/rst_tweak.mdwn | 52 + ...34___fields_are_incorrectly_specified.mdwn | 29 + ...iguration_files_many_times_on_rebuild.mdwn | 9 + ...locale_data_in_the_installed_location.mdwn | 25 + doc/bugs/search_plugin_and_CGI_preview.mdwn | 19 + ...in_finds_no_results_with_xapian_1.2.7.mdwn | 14 + .../search_plugin_uses_wrong_css_path.mdwn | 14 + doc/bugs/search_template_missing_dep.mdwn | 4 + ...__bugs_contain_colons_in_the_filename.mdwn | 15 + doc/bugs/shortcut_encoding.mdwn | 28 + ..._will_not_work_without_shortcuts.mdwn.mdwn | 33 + ...tcuts_don__39__t_escape_from_Markdown.mdwn | 7 + .../sidebar_is_obscured_by_recentchanges.mdwn | 59 + ...ebar_not_updated_in_unedited_subpages.mdwn | 9 + .../sitemap_includes_images_directly.mdwn | 8 + ...ot_all_meta_fields_are_stored_escaped.mdwn | 44 + ...ome_strings_are_not_internationalized.mdwn | 47 + ...nk__93____93___doesn__39__t_make_link.mdwn | 32 + ...ers_in_tag_names_need_manual_escaping.mdwn | 3 + ..._certificates_not_checked_with_openid.mdwn | 85 + doc/bugs/strange_hook_id_in_skeleton.pm.mdwn | 5 + doc/bugs/stray___60____47__p__62___tags.mdwn | 17 + .../structured_config_data_is_mangled.mdwn | 61 + doc/bugs/support_for_openid2_logins.mdwn | 24 + doc/bugs/svg_and_pdf_conversion_fails.mdwn | 60 + doc/bugs/svn+ssh_commit_fail.mdwn | 5 + doc/bugs/svn-commit-hanging.mdwn | 7 + ...ilures_interpreted_as_merge_conflicts.mdwn | 21 + doc/bugs/svn_fails_to_update.mdwn | 89 + ...9__t_find_IkiWiki.pm_if_not_installed.mdwn | 22 + doc/bugs/syntax_error_in_aggregate.mdwn | 11 + ...syslog_fails_with_non-ASCII_wikinames.mdwn | 32 + doc/bugs/table_external_file_links.mdwn | 9 + ...dle___92__r__92__n_lines_in_CSV_files.mdwn | 5 + ...nges_introduced_by_typed_link_feature.mdwn | 16 + ...ag_plugin:_autotag_vs._staged_changes.mdwn | 17 + ...tagged__40____41___matching_wikilinks.mdwn | 35 + doc/bugs/tags__44___backlinks_and_3.x.mdwn | 34 + ...e_dir_not_used_when_creating_new_tags.mdwn | 43 + doc/bugs/taint_and_-T.mdwn | 30 + .../taint_issue_with_regular_expressions.mdwn | 35 + .../tbasewiki__95__brokenlinks.t_broken.mdwn | 60 + .../discussion.mdwn | 2 + ...plateForRecentChangesMissingCloseSpan.mdwn | 26 + ...mplate__95__syntax_test_is_incomplete.mdwn | 10 + doc/bugs/template_creation_error.mdwn | 272 + doc/bugs/template_evaluation_oddities.mdwn | 67 + doc/bugs/teximg_does_not_work_Preview.mdwn | 12 + ...if_same_tex_is_used_on_multiple_pages.mdwn | 24 + ...ies_if_input_has_a_non-utf8_character.mdwn | 14 + ...s_unclear_when_multiple_methods_exist.mdwn | 16 + ...ith_meta_enabled__44___causes_a_crash.mdwn | 3 + .../toc_displays_headings_from_sidebar.mdwn | 3 + doc/bugs/toc_in_sidebar.mdwn | 21 + ...pects_body_element_without_attributes.mdwn | 3 + doc/bugs/toggle_fails_on_Safari.mdwn | 58 + doc/bugs/trail_excess_dependencies.mdwn | 95 + doc/bugs/trail_shows_on_cgi_pages.mdwn | 12 + doc/bugs/trail_test_suite_failures.mdwn | 97 + doc/bugs/trails_depend_on_everything.mdwn | 16 + ..._tagbase_is_not_transient_autoindexed.mdwn | 76 + doc/bugs/transitive_dependencies.mdwn | 94 + doc/bugs/trouble_with_base_in_search.mdwn | 60 + ..._having_problems_with_meta_directives.mdwn | 19 + doc/bugs/typo_in_ikiwiki.setup.mdwn | 9 + .../typo_in_skeleton.pm:_sessionncgi.mdwn | 5 + ...matched_tags_won__39__t_get_converted.mdwn | 46 + .../undefined_value_as_a_HASH_reference.mdwn | 68 + doc/bugs/underlaydir_file_expose.mdwn | 13 + .../unicode_chars_in_wikiname_break_auth.mdwn | 20 + ...nicode_encoded_urls_and_recentchanges.mdwn | 38 + ...CGI_parameter_when_creating_todo_item.mdwn | 18 + ..._discussion_links_on_discussion_pages.mdwn | 36 + ...PI_change_breaks_wikis_with_po_plugin.mdwn | 98 + ...__44___...__44___1__41___not_absolute.mdwn | 9 + ..._links_on_recentchanges_pages_problem.mdwn | 12 + doc/bugs/utf-8_bug_in_websetup.pm.mdwn | 22 + doc/bugs/utf8_html_templates.mdwn | 22 + doc/bugs/utf8_svn_log.mdwn | 11 + doc/bugs/utf8_warnings_are_meaningless.mdwn | 9 + doc/bugs/web_reversion_on_ikiwiki.info.mdwn | 14 + ..._95__symlinks__95__before__95__srcdir.mdwn | 21 + ...re_in_match__95__included__40____41__.mdwn | 7 + doc/bugs/weird_syntax_in_aggregate.pm.mdwn | 9 + ...es_not_work_between_toc_and_an_inline.mdwn | 30 + ...ks_still_processed_inside_code_blocks.mdwn | 67 + ...aydir_or_templatedir_don__39__t_exist.mdwn | 15 + doc/bugs/wikilink_in_table.mdwn | 36 + doc/bugs/word_wrap.mdwn | 16 + ...pper_can__39__t_find_the_perl_modules.mdwn | 16 + doc/bugs/wrong_attachment_size.mdwn | 8 + doc/bugs/wrong_discussion_page_created.mdwn | 12 + ...reverting_an_ikiwiki_outside_git_root.mdwn | 8 + ...g_permissions_on_some_files_in_source.mdwn | 11 + ...rl_when_inside_another_blog-like_page.mdwn | 36 + doc/bugs/xgettext_issue.mdwn | 73 + doc/bugs/yaml:xs_codependency_not_listed.mdwn | 16 + ..._not_support_UTF-8_if_XS_is_installed.mdwn | 104 + doc/cgi.mdwn | 5 + doc/cgi/discussion.mdwn | 22 + doc/commit-internals.mdwn | 20 + doc/competition.mdwn | 19 + doc/consultants.mdwn | 9 + doc/contact.mdwn | 10 + doc/contact/discussion.mdwn | 14 + doc/convert.mdwn | 10 + doc/css.mdwn | 24 + doc/css/discussion.mdwn | 18 + doc/css_market.mdwn | 70 + doc/css_market/02_template.css | 307 + doc/css_market/02_template.tmpl | 20 + doc/css_market/bma.css | 108 + doc/css_market/cstamas.css | 69 + doc/css_market/discussion.mdwn | 37 + doc/css_market/embeddedmoose.css | 13 + doc/css_market/kirkambar.css | 142 + doc/css_market/zack.css | 193 + doc/download.mdwn | 49 + doc/examples.mdwn | 12 + doc/examples/blog.mdwn | 26 + doc/examples/blog/archives.mdwn | 8 + doc/examples/blog/comments.mdwn | 10 + doc/examples/blog/discussion.mdwn | 13 + doc/examples/blog/index.mdwn | 11 + doc/examples/blog/posts.mdwn | 3 + doc/examples/blog/posts/first_post.mdwn | 2 + doc/examples/blog/sidebar.mdwn | 10 + doc/examples/blog/tags.mdwn | 3 + doc/examples/softwaresite.mdwn | 19 + doc/examples/softwaresite/Makefile | 15 + doc/examples/softwaresite/bugs.mdwn | 4 + doc/examples/softwaresite/bugs/done.mdwn | 3 + .../bugs/fails_to_frobnicate.mdwn | 4 + doc/examples/softwaresite/bugs/hghg.mdwn | 1 + .../softwaresite/bugs/needs_more_bugs.mdwn | 3 + doc/examples/softwaresite/contact.mdwn | 7 + doc/examples/softwaresite/doc.mdwn | 5 + doc/examples/softwaresite/doc/faq.mdwn | 11 + doc/examples/softwaresite/doc/install.mdwn | 10 + doc/examples/softwaresite/doc/setup.mdwn | 4 + doc/examples/softwaresite/download.mdwn | 5 + doc/examples/softwaresite/index.mdwn | 13 + doc/examples/softwaresite/news.mdwn | 5 + .../softwaresite/news/version_1.0.mdwn | 1 + .../softwaresite/templates/release.mdwn | 7 + doc/favicon.ico | Bin 0 -> 371 bytes doc/features.mdwn | 183 + doc/forum.mdwn | 11 + doc/forum/404_-_not_found.mdwn | 22 + ..._3dea2600474f77fb986767da4d507d62._comment | 8 + ..._948e4678be6f82d9b541132405351a2c._comment | 31 + ..._4c7b1fa88776815bbc6aa286606214c2._comment | 8 + .../Accessing_meta_values_in_pages__63__.mdwn | 8 + .../Adding_a_custom_header_and_footer.mdwn | 13 + ..._e82dbfef77ff222a7fa07aab0a19fb18._comment | 10 + doc/forum/Adding_new_markup_to_markdown.mdwn | 11 + .../Allow_only_specific_OpenIDs_to_login.mdwn | 7 + ...kiwiki_inline_feed_to_identi.ca__63__.mdwn | 3 + ..._8a5acbb6234104b607c8c4cf16124ae4._comment | 8 + ..._155e5823860a91989647ede8b5c9224a._comment | 16 + ..._317f1202a3da1bfc845d4becbac4bba8._comment | 10 + doc/forum/Apache_XBitHack.mdwn | 28 + ...accidentally_committed_jiberish__63__.mdwn | 12 + ..._b425823f800fba82ad2aaaa0dbe6686a._comment | 10 + doc/forum/Asciidoc_plugin.mdwn | 14 + doc/forum/Attachment_and_sub-directory.mdwn | 5 + doc/forum/Background_picture_and_css.mdwn | 8 + .../Blog_posting_times_and_ikiwiki_state.mdwn | 28 + ..._87304dfa2caea7e526cdb04917524e8c._comment | 8 + doc/forum/Broken_after_upgrading_Ikiwiki.mdwn | 10 + ..._3d0588a845c58b3aedc35970e8dcc811._comment | 14 + ..._fd65d4b87a735b67543bb0cf4053b652._comment | 10 + ..._7c8b46eabdb25cbc01c56c7b53ed3b91._comment | 8 + doc/forum/CGI_script_and_HTTPS.mdwn | 29 + ..._3f8ef438ca7de11635d4e40080e7baa9._comment | 43 + ...dar:_listing_multiple_entries_per_day.mdwn | 21 + ..._d3dd0b97c63d615e3dee22ceacaa5a30._comment | 83 + ..._2311b96483bb91dc25d5e3695bbca513._comment | 12 + ..._d23f0cedd0b9e937eaf200eef55ac457._comment | 166 + ..._4be39c2043821848d4b25d0bf946a718._comment | 15 + ..._de545ebb6376066674ef2aaae4757b9c._comment | 97 + ...I_change_the_default_menu_items__63__.mdwn | 6 + ..._eb56fed3b5fc19c8dd49af4444a049c5._comment | 31 + ...ferent_favicons_for_each_folder__63__.mdwn | 1 + ..._a01112ba235e2f44a7655c36ef680e7e._comment | 19 + ..._b8ccd3c29249eca73766f567bce12569._comment | 8 + ...cognize_multimarkdown_meta_tags__63__.mdwn | 4 + .../Can_OpenID_users_be_adminusers__63__.mdwn | 69 + ...on_an_undefined_value_at_FirstTime.pm.html | 64 + ...an__39__t_get_comments_plugin_working.mdwn | 16 + ...ikiwiki_working_again_after_reinstall.mdwn | 16 + ..._87a360155ff0502fe08274911cc6a53f._comment | 8 + ...penID__44___but_can_use_Ikiwiki_login.mdwn | 5 + ..._79127e3c09a1d798146088dee5a67708._comment | 10 + ...es_live_somewhere_inside_srcdir__63__.mdwn | 8 + ..._d1e79825dfb5213d2d1cba2ace1707b1._comment | 8 + ..._8177ede5a586b1a573a13fd26f8d3cc0._comment | 8 + ...e_configured_as_multi_user_blog__63__.mdwn | 7 + ..._8e34b10699bed1b53b6c929ed1e9f19c._comment | 32 + ..._6083e16f72e12c03bdf739b84bd2f352._comment | 12 + ...t_page_of_results_using_search_plugin.mdwn | 26 + ...ge_is_added_rather_than_changed__63__.mdwn | 5 + ..._1397feebfb0fb7cc57af2f8b74ce047e._comment | 8 + ..._ad36c945f59fe525428fc30246911ff5._comment | 10 + ...meone_update_ikiwki_in_Macports__63__.mdwn | 5 + ..._87365ded9b202607d6431daf4e76e3c1._comment | 10 + doc/forum/Cannot_write_to_commitlock.mdwn | 32 + doc/forum/Chinese_file_name_corruption.mdwn | 5 + ..._765ac8b6f70083bb5aaaaac5beab461f._comment | 10 + doc/forum/Clarification_on_--cgi_option.mdwn | 4 + ..._deda457e4bff7dfe630dbc0192dfddea._comment | 11 + ...ed_comments_into_special_branch__63__.mdwn | 8 + ..._8403e8ff9c5c8dddb6d744632322f7bc._comment | 12 + doc/forum/Darcs_as_the_RCS___63__.mdwn | 13 + ..._IkiWiki__47__Setup__47__Automator.pm.mdwn | 19 + ..._aec4bf4ca7d04d580d2fa83fd3f7166f._comment | 8 + ..._c682ebb0e8e72088a8f92356dc31ef37._comment | 13 + ...20100815.7_-_update_recommended__63__.mdwn | 7 + ..._5e916c8fa90470909064ea73531f79d4._comment | 12 + ..._2fa15f0eaf8c860b82e366130c8563c7._comment | 8 + ..._c5af589dcdfe4f91dba50243762065e5._comment | 12 + ..._3090da7bafbf92a825edec8ffc45af20._comment | 12 + doc/forum/Define_custom_commands.mdwn | 1 + ..._7d82637bc8c706b69e4a55585677f6bf._comment | 11 + ...diting_with_editor_than_with_web-edit.mdwn | 24 + ..._ac6bda46ad00bfe980bc76c4a39aa796._comment | 9 + ..._10a46f8ee23c8935e20c70842671cee4._comment | 13 + ...____40__Blogging_and_Wiki_pages__41__.mdwn | 7 + ..._15651796492a6f04a19f4a481947c97c._comment | 16 + ...isable_account_creation_for_new_users.mdwn | 9 + ..._adafddb0aff7c2c1f4574101c4cf9073._comment | 8 + ..._865591f77966f1657a9a4b2426318c51._comment | 12 + ..._05193e563682f634f13691ee0a8359db._comment | 8 + doc/forum/Discussion_PageSpec__63__.mdwn | 3 + .../Doing_related_links_based_on_tags.mdwn | 31 + ...ing_to_localhost._What_happened__63__.mdwn | 13 + ..._cbab9b95923124b39cfccf5d2e88070c._comment | 14 + doc/forum/Dump_plugin.mdwn | 4 + ..._bfce80b3f5be78ec28692330843d4ae1._comment | 14 + ..._notifications_for_comment_moderation.mdwn | 3 + ..._668bf6a21310dcc8b882bc60a130ba06._comment | 12 + doc/forum/Empty_sha1sum_messages.mdwn | 11 + ..._b260b5e6b4c4f4c203b01183fee9fd69._comment | 10 + ..._d6a47838a3c81d0a75e6fc22e786c976._comment | 10 + ...oblem_in_french_with_ikiwiki-calendar.mdwn | 20 + ...iled_to_return_the_uploaded_file_name.mdwn | 11 + ..._66c321b9eb618d20872cee7d6ca9e44c._comment | 8 + ..._80296d67c7f1dd75b56b85c14f5efa3b._comment | 12 + ...ror:___34__do__34___parameter_missing.mdwn | 13 + ..._3a51c303ba1670f1567f323349b53837._comment | 16 + ..._c5f24a8c4d2de0267cf0de1908480e82._comment | 12 + doc/forum/Error:_bad_page_name.mdwn | 46 + ...iki__47__lockfile:_Permission_denied_.mdwn | 5 + ..._64146f306ec8c10614521359b6de4f82._comment | 10 + ..._ed2b4b8f7122b42bbde1189fbd2969dd._comment | 23 + doc/forum/Error_Code_1.mdwn | 7 + ..._0459afcc383aad382df67a19eaf2e731._comment | 8 + ..._is_locked_and_cannot_be_edited__34__.mdwn | 15 + ..._dc99a921813d4f8adf797a900ee0a2c1._comment | 18 + ..._48daf77f097ed94bf78cf97b0c027129._comment | 14 + doc/forum/Everyone_can_remove_comments.mdwn | 1 + .../Export_images_when_building_the_wiki.mdwn | 16 + ..._f7328be9b201f3eea6b90c269781fd0b._comment | 18 + ..._99a592c8ff9d2c2094132edd27356922._comment | 18 + ..._7f5a1ef639453c83748405d2b3b0b880._comment | 27 + ..._bd3b37fbee54f1bf510ef5fc6ba27e55._comment | 10 + doc/forum/File_wiki.setup.mdwn | 6 + doc/forum/Flowplayer.mdwn | 1 + ..._75d13cd915a736422db47e00dbe46671._comment | 9 + ..._1b2d3891006a87a4773bd126baacddfc._comment | 8 + ...rce_rebuild_of_page_using_some_plugin.mdwn | 5 + doc/forum/Formatting_algorithms.mdwn | 54 + ...Forward_slashes_being_escaped_as_252F.mdwn | 33 + ..._7702cf6d354ab600d6643b075b9f09da._comment | 12 + ...s_of_ikiwiki.info_are_broken._:__40__.mdwn | 14 + ...me_for_new_pages_fetched_from_the_VCS.mdwn | 7 + ..._9572dd6f7a2f6f630b12f24bb5c4a8ce._comment | 8 + doc/forum/Help_with_tag__95__autocreate.mdwn | 9 + doc/forum/Hide_text.mdwn | 3 + ..._f21d21c130f97a7b21d8a317178e2e0c._comment | 8 + ..._5a878865f34f78a89c4ec91a9425a085._comment | 8 + ...manage_a_bilingual_ikiwiki_site__63__.mdwn | 15 + ..._4389d65b14fa1b7134098e0ffe3bf055._comment | 10 + ...vert_the_banned__95__user_check__63__.mdwn | 33 + doc/forum/How_can_I_prevent_spam__63__.mdwn | 17 + ..._fd26fb7f1569e8c44ba8262794f938db._comment | 19 + ..._d098124f005976ee815d25c883bc9106._comment | 16 + ..._deb434d01aaefa18d2791e48d6c824ae._comment | 8 + doc/forum/How_do_I_enable_OpenID__63__.mdwn | 1 + ...How_does_ikiwiki_remember_times__63__.mdwn | 98 + ...ted_in_inline_archive_templates__63__.mdwn | 11 + ...er_delay_newly_pushed_revisions__63__.mdwn | 10 + ...se-over_pop-up_label_for_a_text__63__.mdwn | 8 + ...rizontable_bar_under_page_title__63__.mdwn | 3 + ..._f2e52d38f60888c7d5142de853123540._comment | 8 + ...ous_and_next_blog_on_blog_pages__63__.mdwn | 14 + ..._aad510f45be505efaabcb6fb860665a4._comment | 23 + ..._ee65792a5b796caa216f4e7a653fc668._comment | 23 + ...lid_extensions_for_source_files__63__.mdwn | 1 + ...ly_a_background_color_to_a_page__63__.mdwn | 1 + .../How_to_change_registration_page.mdwn | 9 + ..._43758a232e4360561bc84f710862ff40._comment | 14 + ..._8176ef231cf901802fc60b6d414018e6._comment | 8 + .../How_to_configure_po_plugin__63__.mdwn | 21 + ..._5e0cc4cdfd126f2f4af64104f02102d6._comment | 9 + ...ink_to_a_page_in_a_subdirectory__63__.mdwn | 26 + ..._d20ee1d8d7a3e77a445f8b887e807119._comment | 11 + ...ranslation_page_using_po_plugin__63__.mdwn | 24 + .../How_to_customize_page_title__63__.mdwn | 6 + ..._403e1f866b5e04e5899021f54bbdd1ed._comment | 10 + ...t_titled:__34___submission_form__63__.mdwn | 1 + ..._3dfa9ac6473d0d5ebc9d99ec39e96216._comment | 9 + ...not_map_to_Unicode__34___errors__63__.mdwn | 20 + ...obar__93____93___in_code_blocks__63__.mdwn | 9 + ..._ad000d39fd1dc05aa8ef6eb19d8d999b._comment | 8 + ...ubdir_but_not_ikiwiki_root_path__63__.mdwn | 26 + ...ne_a_page_from_another_git_repository.mdwn | 5 + ...st_all_pages_in_a_wiki_instance__63__.mdwn | 5 + ..._920bcc70fe6d081cf27aa2cc7c6136f4._comment | 8 + ..._to_list_new_pages__44___inline__63__.mdwn | 5 + ..._e989b18bade34a92a9c8fe7099036e15._comment | 13 + ...ions_and_comments_to_blog_posts__63__.mdwn | 11 + ..._e153beb17b6ada69c6ab09d1f491d112._comment | 8 + ...e_of_content_at_the_top_of_page__63__.mdwn | 3 + ..._6dedc31dd1145490bb5fa4ad14cc4c63._comment | 8 + ...rectory_into_a_new_subdirectory__63__.mdwn | 10 + ..._a83a1a33afbf245971733b4128809365._comment | 15 + ..._39__page__47__index.html__39___files.mdwn | 17 + ..._d9ee358ded5d5307ba73a8c11f81549d._comment | 8 + ...ow_to_remove_the_linebreak_in_license.mdwn | 11 + ...s_from___42__.mdwn_to___42__.md__63__.mdwn | 3 + ..._c2720ebfe56ad816f241693d9e2e5072._comment | 10 + ...eta_author_field_from_user_name__63__.mdwn | 3 + ..._0906e1f3eb8b826a7730233b95cb5ddd._comment | 10 + ...ow_to_set_up_a_page_as_internal__63__.mdwn | 5 + ..._to_set_up_git_repository_hook___63__.mdwn | 19 + ...nt_changes_for_individual_pages__63__.mdwn | 1 + ..._cd34affc6883f4e4bc5e7e7b711cc8ba._comment | 10 + ..._repository_is_on_a_remote_host__63__.mdwn | 3 + ..._0c71e17ae552cbab1056ac96fbd36c59._comment | 9 + ..._b309302a084fbd8bcd4cd9bd2509cf5a._comment | 10 + ...e_sidebar_differently_using_CSS__63__.mdwn | 13 + ...s_sidebar_for_a_particular_page__63__.mdwn | 7 + ...rkdown_instead_of_Text::MultiMarkdown.mdwn | 5 + ...t_labels_but_not_letter_in_toc_plugin.mdwn | 8 + doc/forum/Howto_add_tag_from_plugin_code.mdwn | 12 + ..._c61454825874a6fe1905cb549386deb0._comment | 77 + .../I_do_not_know_anything_abut_git.mdwn | 22 + ..._2efdf8563bcdeba73b11282157aba72d._comment | 10 + ..._3dd0fa0612a5fac785cc7d5ea23d42a5._comment | 8 + ...IWYG_ikiwiki_editor_for_Windows__63__.mdwn | 14 + ..._a66fd9d7ab4359784a5420cd899a1057._comment | 8 + ..._3351ff773fea3f640f4036bb8c7c7efd._comment | 10 + ..._273b2b63a9af2bc4eeb030e026436687._comment | 12 + ..._546771c13ea1b550301586e187d82cb5._comment | 8 + ...4___and_it__39__s_a_binary_file__63__.mdwn | 33 + ...iwiki_themes_for_mobile_devices__63__.mdwn | 7 + doc/forum/Include_attachment_in_a_page.mdwn | 9 + ..._275aad6ca3b2972749b7f6636b130035._comment | 12 + ...e_to_change_default_mdwn_suffix__63__.mdwn | 1 + ..._2a449c6017ecdb4f557963266fb4ec41._comment | 8 + ...reation_dates_relative_to_today__63__.mdwn | 26 + doc/forum/LaTeX_Error.mdwn | 66 + doc/forum/Last_visited_pages.mdwn | 1 + ..._e34650064dd645b35da98e80c0311df9._comment | 8 + ..._2a0c4e844da1deaa2c286e87c8eab84d._comment | 8 + doc/forum/Link_to_a_local_pdf_file.mdwn | 1 + ..._b6c57588042373f8e1f187041c1a8530._comment | 8 + doc/forum/Log_in_error.mdwn | 5 + ..._0ef13ea01a413160d81951636c15c3e6._comment | 10 + ...ike_to_add___63__updated_to_all_links.mdwn | 3 + ..._3fe4c5967e704355f9b594aed46baf67._comment | 13 + ..._to_new_host._Web_page_is_not_updated.mdwn | 27 + ..._b44a492c7f10395a31f3c0830ef33f0c._comment | 10 + ..._f9240b217b2d1ee8d51dada9cb1186b3._comment | 28 + ..._c3c5c41a4c220793c6d16f3fd6132272._comment | 15 + ..._1f6f9e3939a454c1eb8d2fb29bd519de._comment | 16 + ..._8611fc62797e70a0d2a61d94fcb03170._comment | 22 + ...epository_to_new_ikiwiki_system__63__.mdwn | 54 + ..._e5ce524c5d34b1d4218172296bd99100._comment | 8 + ..._65c4a4895f6541ff0ff2d094ff447bba._comment | 8 + doc/forum/Moving_wiki.git_folder__63__.mdwn | 17 + ..._05238461520613f4ed1b0d02ece663bd._comment | 11 + ..._72b2b842dfa0cfaf899fe7af12977519._comment | 10 + doc/forum/Multiple_urls.mdwn | 8 + ..._e4c1256346d5a421161c20e344d8bada._comment | 22 + .../Need_help_installing_h1title_plugin.mdwn | 5 + .../Need_help_setting_up_ikiwiki_CGI.mdwn | 16 + ..._0fc4573568711c56a0df4af620110c2f._comment | 12 + ..._89f2cd7d874a6257786478e4cae1e2bc._comment | 16 + ..._cbc20267fe5f0531f63db881d50596d1._comment | 20 + ..._2eaf53935eecd0a918755d728450a642._comment | 8 + ..._creating_pages_in_multiple_languages.mdwn | 6 + ..._something_more_powerful_than_Exclude.mdwn | 5 + ..._0019cd6b34c8d8678b2532de57a92d15._comment | 12 + ..._f577ab6beb9912471949d8d18c790267._comment | 11 + ..._1ed260b0083a290688425a006a83f603._comment | 8 + ..._c39bdaf38e1e20db74eb26f0560bd673._comment | 10 + ..._39b01857f7e0b388a6e7a3c1cf5388d5._comment | 9 + ..._1dccdfebad31446200213a2cae25f0e2._comment | 10 + ...tted_and_then_reviewed_before_posting.mdwn | 23 + ..._where_to_define_wiki__39__s_ID__63__.mdwn | 12 + ..._bf1bec748d6ab419276a73a7001024cf._comment | 8 + ..._14a1b269be6dbcc9b2068d3e18b55711._comment | 10 + ..._f581afcdb4481ea5d65bcc33bdbab99a._comment | 25 + ..._b0d39d30852bca1525ab9612a7532670._comment | 8 + ...IB__44___wrappers_and_homedir_install.mdwn | 38 + ...pec_results_from_independent_checkout.mdwn | 8 + doc/forum/Parent_Links_all_link_to_root.mdwn | 18 + ..._4b5ed25cceb7740f64ee08aba00a1d91._comment | 8 + ...g_-_tracking_non-post_files_in_a_blog.mdwn | 7 + ..._45ecaf6efa2065837fa54a42737f0a66._comment | 18 + ..._45ca7ef4190c281d703c8c7ca6979298._comment | 12 + ...use_meta_variables_in_templates__63__.mdwn | 11 + ..._556078a24041289d8f0b7ee756664690._comment | 20 + ..._e7e954218d39bc310015b95aa1a5212c._comment | 10 + ..._8b16c563c89eb6980ad6a5539d934d7a._comment | 8 + ..._76eadf93cce4e2168960131d4677c5fc._comment | 8 + ..._ddabe4a005042d19c7669038b49275c1._comment | 12 + doc/forum/Problem_with_gitweb.mdwn | 3 + ..._23cc0d87448d3cbdac20a005e9191589._comment | 10 + ..._697c6038009249e6a49d9e458a5ba271._comment | 47 + ..._6a5b96f7e0d6b169c090e3df7281d938._comment | 8 + ..._8a79b879205bd265d54e30f0eee2ac63._comment | 8 + doc/forum/Problem_with_local_git_commit.mdwn | 42 + doc/forum/Processing_non-pages.mdwn | 7 + ..._changes_on_main_site_or_on_a_sidebar.mdwn | 1 + ..._018b977ff7ee59fc53838e0c20c3a9a7._comment | 11 + ..._927c11f18315baa39f08ca4982ed2ab1._comment | 8 + .../Refresh_or_recreate_style.css__63__.mdwn | 40 + ..._3274be931d0b543c7f7cf641810817aa._comment | 8 + ...gex_for_Valid_Characters_in_Filenames.mdwn | 19 + ...d_backlinks_on_particular_pages__63__.mdwn | 3 + ...n_one_dest_page_from_same_source_page.mdwn | 51 + .../Revision_history_for_single_pages.mdwn | 3 + ..._d509d5d726cd7eab9472d723013f5ec4._comment | 8 + ..._d39a6177fc4c1e3c3c2c4e2592be9e3d._comment | 8 + ..._aecf2b031ace001afaa2a0f2b5f50c82._comment | 8 + doc/forum/Right-to-left_support.mdwn | 15 + ..._5b2bf4d037ae8db940296e6f58884927._comment | 21 + doc/forum/Run_script_on_markdown_source.mdwn | 1 + ...endered_old_revisions_via_pagehistory.mdwn | 1 + doc/forum/Setting_http__95__proxy.mdwn | 22 + ..._350a7c4834c9f422e107b646cdbae3b0._comment | 20 + ...plate_variable_from_config_file__63__.mdwn | 1 + ..._bb4b5a7a49f33d660b5116fc0ce3c92d._comment | 8 + .../Setting_up_a_development_environment.mdwn | 32 + ...ikiwiki_be_committed_and_pushed__63__.mdwn | 14 + ..._8e65d7d8298e3c31d2a16446a71c8049._comment | 10 + .../Should_not_create_an_existing_page.mdwn | 15 + doc/forum/Sidebar_with_links__63__.mdwn | 58 + doc/forum/Slow_ikiwiki_after_first_run.mdwn | 1 + doc/forum/Spaces_in_URLs.mdwn | 14 + doc/forum/Spaces_in_wikilinks.mdwn | 104 + doc/forum/Split_a_wiki.mdwn | 21 + ..._1599c26891b2071a2f1ca3fd90627fc4._comment | 8 + ..._1c54d3594f0350340f8dfb3e95c29ffd._comment | 20 + ..._9eac1d1b93df27d849acc574b1f0f26d._comment | 8 + ..._e193ba447c0188f72ba589180b5d529e._comment | 8 + doc/forum/TMPL__95__VAR_IS__95__ADMIN.mdwn | 1 + ..._3172568473e9b79ad7ab623afd19411a._comment | 13 + ..._4302d56a6fe68d17cc42d26e6f3566c2._comment | 8 + ..._4cc44e61b9c28a2d524fa874f115041a._comment | 14 + ..._33143bad68f3f6beae963a3d0ec5d0bd._comment | 53 + ..._ef790766456d723670f52cc9e3955e90._comment | 12 + ..._3db50264e01c8fad2e5567b5a9c7b6dc._comment | 23 + ..._bdc5c96022fdb8826b57d68a41ef6ca0._comment | 8 + doc/forum/Template_variables.mdwn | 20 + ..._6a2ab9450dbfb8c4ef78e7af2a1b51eb._comment | 11 + ..._9b366736171e45d5afd8247ff38501d1._comment | 8 + ..._727f8a407dc57e4abf48cdcec4ead666._comment | 8 + ...iki.cgi_was_not_found_on_this_server..mdwn | 11 + ..._d36ce6fab90e0a086ac84369af38d205._comment | 16 + ..._5836bba08172d2ddf6a43da87ebb0332._comment | 7 + ..._4eec15c8c383275db5401c8e3c2d9242._comment | 9 + ..._43ac867621efb68affa6ae2b92740cad._comment | 10 + ..._e098723bb12adfb91ab561cae21b492b._comment | 8 + ..._101183817ca4394890bd56a7694bedd9._comment | 10 + ..._2f514e6ba78d43d90e7ff4ae387e65e0._comment | 10 + ..._098bb7a3112751a7e6167483dde626bb._comment | 10 + ..._fbf403255c38da93caa5b98589fbb285._comment | 8 + ...il_plugin_links_with_Actiontabs_theme.mdwn | 47 + doc/forum/Translating_ikiwiki_interface.mdwn | 8 + ...from_RecentChanges_CGI_to_static_page.mdwn | 10 + ...9___base_URL_is_http_instead_of_https.mdwn | 55 + ..._ef4be9e70bd6d8c970fd8982f525d2d0._comment | 21 + ..._00fee67cc30b7c337710b37c27216a68._comment | 8 + ..._f402fb426e0460ce927b7847246f699f._comment | 19 + ..._db726bc81ec5feac76d17ea81f0f80a5._comment | 13 + ..._674f56100c0682eba36cc5327fbdae4a._comment | 61 + ...s_ways_to_use_Subversion_with_ikiwiki.mdwn | 23 + ...ference_between_tag_and_taglink__63__.mdwn | 9 + ..._b3553d65d12af4c4a87f1f66f961c8d9._comment | 49 + ...rong_with_my_recentchange_page___63__.mdwn | 13 + ...sted_as_a__47__b_and_not_only_b__63__.mdwn | 6 + ..._cd5ea3aac8a59793ece5bf01a6190b53._comment | 9 + doc/forum/Wikilink_to_a_symbolic_link.mdwn | 1 + ..._e3ad5099491e0c84cd7729eba82ce552._comment | 8 + ..._46848020b1e3d0cd55bc1ec0ba382aad._comment | 8 + .../Wikilink_to_section_of_a_wikipage.mdwn | 1 + ..._c1409a3c07dfc4ed7274560c962aba75._comment | 11 + ..._8a04eb7b0d7f17b9e5bb4cd04ba45871._comment | 8 + .../Xapian_search:_empty_postlist_table.mdwn | 34 + ..._de9a7c94beec2707eda0924ca58be9df._comment | 8 + ..._55f191e4b1306a318a30319f01802229._comment | 15 + ..._0bd424a89c3a52ff393a1e7e00c806be._comment | 24 + ..._40479ac2cfbca609f5f423e539a20ee0._comment | 8 + ..._397443138da276e11c2e9b9fa7b51406._comment | 8 + ..._3cd94b9a141ebbf96fcba4ebe99e1453._comment | 10 + ..._files_would_be_overwritten_by_merge:.mdwn | 35 + ..._2223c8b463b22a9dab53b71c01b67209._comment | 12 + ..._2466ce4303f5b8145bdfae23b6dbddda._comment | 10 + ..._34___on_Mageia_Linux_x86-64_Cauldron.mdwn | 23 + ..._abf7ec7c378ab0908685d72d159e9fd2._comment | 8 + ...___47__script__62___not_working__63__.mdwn | 13 + ..._953bd716373dcf51fa444ac098b7f971._comment | 8 + ..._c7360852f9bf069f28c193373333c9a8._comment | 8 + ..._6ffc30e27387366b48112198b66c01fa._comment | 8 + .../access_restrictions:_for_extranet.mdwn | 8 + ..._a0666c3c15661fb0fff70f313cd0d47d._comment | 29 + ..._563040aa099c9366dc5701eb4bc9c10d._comment | 20 + ...ternative_approach_to_structured_data.mdwn | 63 + ...ear_if_you_are_login_or_not_in_a_page.mdwn | 36 + doc/forum/attachments_fail_to_upload.mdwn | 8 + ..._577adde1dfa49463dfa8e169c462fc42._comment | 10 + ..._473f38c6d523496fac8dad13ac6d20c3._comment | 12 + ..._799a2f1b7b259157e97fd31ec76fb845._comment | 10 + ..._e37d1497acafd3fda547462f000636e3._comment | 8 + ..._da03f9c4917cb1ef52de984b8ba86b68._comment | 11 + ..._04498946a300ddb652dec73c2950f48f._comment | 19 + doc/forum/bashman.mdwn | 7 + doc/forum/blocked_by_blogspam.mdwn | 9 + ...ot_decode_string_with_wide_characters.mdwn | 12 + ..._83fbb415dd3ae6a19ed5ea5f82065c28._comment | 8 + ..._d258536c98538d4744f66eb3132439a9._comment | 20 + ..._d62173d0ae220ab7b063631952856587._comment | 10 + ..._d5d0174e09a94359c23fd9c006a22bbc._comment | 50 + ..._e652027a8f90ebef6f21613b5784ded2._comment | 8 + ..._ba76f7f8ef46fb58d36fb2cda4b242ff._comment | 8 + ..._e4f7c1da09571085070275e12c09b12f._comment | 10 + doc/forum/chinese_character_problem.mdwn | 21 + ...ning_up_discussion_pages_and_the_like.mdwn | 11 + doc/forum/converting_binary_files.mdwn | 29 + ...___40__where_are_they_set__63____41__.mdwn | 13 + doc/forum/create_download_link.mdwn | 4 + ..._4797493157c569f8893b53b5e5a58e73._comment | 14 + .../creating_redirect_index.mdwn__63___.mdwn | 6 + ..._6d609c3a2ba50da4129e15b60362c6d9._comment | 8 + .../cutpaste.pm_not_only_file-local.mdwn | 14 + ..._497c62f21fd1b87625b806407c72dbad._comment | 8 + doc/forum/debconf13_ikiwiki_bof.mdwn | 108 + ...ebian_backports_update_someone_please.mdwn | 18 + ...aths._Are_there_better_defaults__63__.mdwn | 8 + ..._3db622152a8ab53841cc13280ca31da4._comment | 10 + doc/forum/discussion.mdwn | 7 + ...__47____47____39___in_the_address_bar.mdwn | 3 + doc/forum/download_links_for_attachments.mdwn | 11 + ..._19fe525281e38d3bbe45b31248ca7880._comment | 10 + ..._06231e4ddc271260e51bc371637540de._comment | 14 + ..._64d12928bc24c48d6f0b5fbb2dfd8f6d._comment | 16 + ..._7612923064284646c2ed59e2cd52845d._comment | 34 + doc/forum/editing_a_comment.mdwn | 11 + doc/forum/editing_the_style_sheet.mdwn | 18 + ...2___40__Found__41___when_editing_page.mdwn | 59 + doc/forum/ever-growing_list_of_pages.mdwn | 29 + doc/forum/field__95__tags_not_linking.mdwn | 66 + ..._7c1540e6eb6aafd2e1c9c7016e6e6249._comment | 10 + ..._0c03cbaa4f748d2fb932fda08fe6e966._comment | 8 + ..._9f3a402173f9584d8a36bc61e5755f6d._comment | 8 + ..._455a2f921059f9ecca810bb8afed0fda._comment | 10 + ..._b82294c290a215d9aa6774ee20b5a552._comment | 10 + ..._57fb279ad50f8460341dc0f217acef06._comment | 10 + ..._8dae1024e80cf6ea765dee0318324d71._comment | 8 + ..._76a4fb4def8f13b906c848814de91660._comment | 12 + ..._64d51cc9ba953e7fed609c380e30bb7d._comment | 13 + ..._7a6eac4e216133f1cf6fc12336fc2496._comment | 8 + ..._e6941a0df00fb9f45563c30e01efa622._comment | 9 + ..._f08ded5a946458aeba59a2c4cec29b2f._comment | 8 + ..._6ea7de20c3db96589c05adbe97d57cfd._comment | 8 + ..._8ad385b61c46389d87c88b17430ab1f2._comment | 8 + ..._c3c5eced158babd8c3acb493a86b6ecb._comment | 8 + ..._9bd4b3df18a28a7ab3bbef5013856987._comment | 11 + doc/forum/field_and_forms.mdwn | 13 + ..._a0e976cb79f03dcff5e9a4511b90d160._comment | 19 + ...ating:_how_to_align_text_to_the_right.mdwn | 52 + ..._disabled___44___Is_it_possible__63__.mdwn | 6 + ..._747cc477584028ce2c7bc198070b1221._comment | 10 + ..._a230861b26dba6d61461862bfedbc09c._comment | 8 + ..._848b4801fc7887906a21a676e802023c._comment | 10 + doc/forum/google_openid_broken__63__.mdwn | 82 + ...e___39____47____39___as_tagbase__63__.mdwn | 13 + ..._e7897651ba8d9156526d36d6b7744eae._comment | 8 + ...tfile_from_metadata_in_multiple_pages.mdwn | 3 + ..._I_revert_edits_in_the_web_mode__63__.mdwn | 46 + ..._e4720e8e4fe74bd6cba746e8259832e6._comment | 8 + .../how_do_I_translate_a_TWiki_site.mdwn | 44 + ...add_post_titles_in_ikiwiki_blog__63__.mdwn | 28 + .../how_to_enable_multimarkdown__63__.mdwn | 9 + ..._037f858c4d0bcbb708c3efd264379500._comment | 14 + ..._b7d512a535490dabf8d6ce55439741c7._comment | 8 + ...get_nice_pdf_from_ikiwiki_pages__63__.mdwn | 3 + ..._332d32850c3dc0d45f5cc50434205f39._comment | 8 + .../how_to_have_a_plugin_delete_a_file.mdwn | 18 + ..._061c8bca174f7155d4065dd200c0c8db._comment | 11 + ..._864a20147885642ad3bbcf8400d8ee46._comment | 9 + ..._still_have_it_under_ikiwiki_template.mdwn | 3 + doc/forum/how_to_login_as_admin.mdwn | 18 + ..._295e130c6400a2d7336758e82bcd5647._comment | 10 + ...how_to_setup_ikiwiki_on_a_remote_host.mdwn | 35 + .../howto_install_the_pagedown_plugin.mdwn | 1 + ..._158fbcef24d20920c40968da8f10442a._comment | 8 + ...ml_source_pages_in_version_3.20100704.mdwn | 8 + doc/forum/ikiwiki.info_blogspam_problem.mdwn | 11 + ..._893a2f561ead36b531e2d6c887e6aaba._comment | 11 + doc/forum/ikiwiki_+_mathjax.mdwn | 1 + ..._8426a985ecfbb02d364116503ef3a0d4._comment | 8 + ..._ddb7a4d59bbe7145167d122a146e8f65._comment | 11 + ..._5a118654bc008bbb118285ff141eb6f1._comment | 8 + ..._873adec726e9b70394643ff28094ad39._comment | 9 + ..._f601e3f1c78345e4d80ec3ce62784e6f._comment | 8 + ..._305fddcd1e264b92d7ed7153ba27ce07._comment | 9 + ...reates_tmp__47___directory_in_destdir.mdwn | 10 + doc/forum/ikiwiki__39__s_notion_of_time.mdwn | 35 + doc/forum/ikiwiki_and_big_files.mdwn | 102 + ..._df8a9f4249af435cc335f77768a3278d._comment | 8 + ..._2d996f1124aedc10f345139c3d8b11df._comment | 19 + ..._dfbd38e2b457ea3c4f70266dbf8fbeab._comment | 8 + ..._fd8a0cb8872d9de55465e8db93d67619._comment | 8 + ..._3532b14ee10775dac634792c75a30e89._comment | 8 + .../ikiwiki_development_environment_tips.mdwn | 68 + ...rates_html_files_with_600_permission..mdwn | 8 + ..._6d73d412a9cc6f6ae426b62885c1f157._comment | 19 + ..._1392fcde369d11a264f31f6b8993ccec._comment | 8 + ..._962306f22ceb17afb4150e766e9a05b3._comment | 10 + ..._8b988d85cfde123798238d0348764c79._comment | 22 + ...toast___40__because_of_symlinks__41__.mdwn | 12 + doc/forum/ikiwiki_over_database__63__.wiki | 11 + doc/forum/ikiwiki_vim_integration.mdwn | 17 + doc/forum/ikiwiki_vim_syntaxfile.mdwn | 26 + ...ki_with_album___38___underlay_plugins.mdwn | 65 + ..._ea4faa2b5bb9216c0a0427f2071584ef._comment | 18 + ..._f38b4f9191d42c3d1a9651820b36a2ee._comment | 23 + ..._46d4c9cecc5d9a19693966820dd18380._comment | 17 + doc/forum/index_attachments.mdwn | 9 + ..._18b9531d273292b45051eef6a306ca26._comment | 10 + .../index_attachments/comment_2._comment | 31 + ..._050e5847641a27e0c14232632f3e700a._comment | 10 + .../index_attachments/comment_4._comment | 10 + .../inject__95__preprocess__95__tag.mdwn | 75 + .../installation_and_setup_questions.mdwn | 52 + doc/forum/installation_as_non-root_user.mdwn | 7 + doc/forum/installation_of_selected_docs.mdwn | 29 + ...possible_to_NOT_add_openid2_meta_tags.mdwn | 67 + doc/forum/java_script_slideshow.mdwn | 11 + ..._3eba0b2f3c12acc991dc3069d2b83d49._comment | 8 + ..._59d90f42b2ca2a5cc71a4d9ba9b9ee9f._comment | 10 + ..._820a86db38231cff7239f0a88b1925fd._comment | 21 + ..._a68972e3dd20b65119211d4ab120b294._comment | 10 + doc/forum/link_autocompletion_in_vim.mdwn | 22 + ...e_inside_the_wiki_without_inlining_it.mdwn | 72 + .../links_to_diff_on_recentchanges__63__.mdwn | 1 + ..._1dbc723cc2794f6d45de9cbd2fc2e0fd._comment | 8 + ..._4349c85d92cf9c1acf2e7678371ab12a._comment | 10 + ...lockedit:_pages_don__39__t_get_locked.mdwn | 12 + ..._bacffb831e5ce7ece7e670c55ad9f3af._comment | 14 + ..._ad268d3f2cd3d529cfff281e0ecb2f16._comment | 8 + ..._da2fb41c5313763e4393cdd921a3f36e._comment | 10 + ..._d0de7964db26cb6f3e81d6e8c29d860d._comment | 16 + ..._d60727c53197d1c667b59bc7250afd9f._comment | 10 + doc/forum/managing_todo_lists.mdwn | 44 + ...ing_pages_redirected_to_search-SOLVED.mdwn | 36 + ..._aa03c337b31d7acb95761eb51caab1ef._comment | 44 + doc/forum/move_pages.mdwn | 1 + ..._3f1b9563af1e729a7311e869cf7a7787._comment | 11 + ..._22b1c238faacbf10df5f03f415223b49._comment | 8 + ...4___gitosis_and_apache2_in_Debian_Sid.mdwn | 96 + .../multi_domain_setup_possible__63__.mdwn | 15 + ..._43f5df30d09046ccc4f7c44703979a11._comment | 17 + ..._75d6581f81b71fb8acbe3561047ea759._comment | 16 + ...ki_pages_on_local_filesystem_with_vim.mdwn | 130 + doc/forum/nginx:_404_plugin_not_working.mdwn | 12 + ..._02a82e468676ae64374cc91ec87e39d6._comment | 15 + ..._ce6bd8e98e4be08316522182f5f85a11._comment | 11 + ..._52b05c3274455db7bee3c1765776fd52._comment | 8 + ..._5a8c2987f442106c68eb822c5bce3bf1._comment | 23 + ..._0720cd8842dc1cb338b74a0e6fdb2aac._comment | 8 + doc/forum/pandoc-iki_plugin.mdwn | 5 + ..._11eef903493378fd704a6bd92e968508._comment | 8 + ..._2c437577390cffe3401f5cc2f08a2ab1._comment | 8 + .../paths_to_files_outside_the_wiki_root.mdwn | 34 + doc/forum/perl5lib_and_wrappers.mdwn | 13 + ...create_po_files___40__only_pot__41__..mdwn | 11 + doc/forum/possible_utf-8_problem__63__.mdwn | 26 + .../postsignin_redirect_not_working.mdwn | 30 + ...em_with_git_after_a_commit_of_ikiwiki.mdwn | 4 + ..._2b9986717769419a8ae0f730c36b7e65._comment | 22 + ..._should_be_under_control_of_RCS__63__.mdwn | 105 + ...ng_original_title_with_meta_directive.mdwn | 1 + doc/forum/remove_css__63__.mdwn | 5 + doc/forum/report_pagination.mdwn | 18 + doc/forum/screenplay_plugin.mdwn | 1 + ..._6c353acfc80b972ee3a34c8bb09dede3._comment | 8 + ..._1868aeebebefae80531f2031ffba35d3._comment | 8 + doc/forum/search_plugin_questions.mdwn | 13 + ..._d634b00ab758c9fbc43528b9a3176257._comment | 16 + ..._b731c664d314afd1d45485716f39ac3b._comment | 11 + doc/forum/section_editing.mdwn | 1 + ..._b193caa886a47c685ac7dafaf60c1761._comment | 12 + doc/forum/speeding_up_ikiwiki.mdwn | 90 + ..._interpreted_as_wikilinks__41____63__.html | 19 + ..._included_only_for_their_side_effects.mdwn | 16 + ..._plugin:_rebuilding_autocreated_pages.mdwn | 11 + ..._all_pages__44___not_populating_feeds.mdwn | 28 + ..._ec4ffab10e60510b53660b70908d1bd8._comment | 14 + ..._a47884ffd749df980cd62f4c1e3167ce._comment | 10 + ..._6c4affdbc637946506d0c28a8648dc6e._comment | 32 + doc/forum/teximg_not_working.mdwn | 26 + ..._35e2ebf3893fc0c7966490e1fef1e6cf._comment | 10 + ...tion_from_handwritten_html_to_ikiwiki.mdwn | 90 + ..._plugins:_newpage__44___jssearchfield.mdwn | 20 + doc/forum/understanding_filter_hooks.mdwn | 17 + doc/forum/upgrade_steps.mdwn | 147 + ...php-markdown-extra_with_ikiwiki__63__.mdwn | 3 + ..._66d48218361caa4c07bd714b82ed0021._comment | 8 + ..._f2ee0a4dce571d329f795e52139084c0._comment | 8 + ..._e388714f457ccb6ef73630179914558c._comment | 9 + ...edirs___38___indexpages_using_problem.mdwn | 17 + doc/forum/using_l10n__39__d_basewiki.mdwn | 7 + ..._eaab671848ee6129f6fe9399474eeac0._comment | 8 + ..._d907676a1db1210ca59506673c564359._comment | 10 + ..._5e9d5bc5ecaf63f9bfe3315b09a279aa._comment | 10 + doc/forum/using_svn+ssh_with_ikiwiki.mdwn | 11 + ...f8_warnings_for___34____92__xAB__34__.mdwn | 47 + ...___91__Save_Page__93___results_in_403.mdwn | 9 + ...web_service_API__44___fastcgi_support.mdwn | 18 + ...er_name_for_recent_changes_page__63__.mdwn | 3 + ..._e90085a9d61cdf623c20dfe57005472e._comment | 10 + ...en__95__few_page_editing_policy__63__.mdwn | 3 + doc/forum/where_are_the_tags.mdwn | 9 + ..._6a559c3bfe72011c45b006d33176da3d._comment | 14 + ...--setup_is_processing_right_now__63__.mdwn | 4 + ..._4f52f8fc083982bd5a572742cf35c74f._comment | 7 + doc/forum/wiki_clones_on_dynamic_IPs.mdwn | 10 + doc/forum/wiki_name_in_page_titles.mdwn | 32 + ...n:_Editformular_showing_existing_tags.mdwn | 15 + ...ow_OpenID_users_to_set_a_display_name.mdwn | 3 + doc/forum/wishlist:_support_staging_area.mdwn | 12 + doc/forum/wmd_editor_double_preview.mdwn | 3 + ..._0d3acf67f3c35f8c4156228f96dcd975._comment | 8 + doc/freesoftware.mdwn | 11 + doc/freesoftware/discussion.mdwn | 3 + doc/git.mdwn | 88 + doc/ikiwiki-calendar.mdwn | 53 + doc/ikiwiki-calendar/discussion.mdwn | 38 + doc/ikiwiki-makerepo.mdwn | 44 + doc/ikiwiki-makerepo/discussion.mdwn | 1 + doc/ikiwiki-mass-rebuild.mdwn | 33 + doc/ikiwiki-mass-rebuild/discussion.mdwn | 1 + doc/ikiwiki-transition.mdwn | 75 + doc/ikiwiki-update-wikilist.mdwn | 33 + doc/ikiwiki.mdwn | 17 + doc/ikiwiki/directive.mdwn | 56 + doc/ikiwiki/directive/aggregate.mdwn | 57 + .../directive/aggregate/discussion.mdwn | 10 + doc/ikiwiki/directive/brokenlinks.mdwn | 14 + .../directive/brokenlinks/discussion.mdwn | 3 + doc/ikiwiki/directive/calendar.mdwn | 60 + doc/ikiwiki/directive/color.mdwn | 25 + doc/ikiwiki/directive/comment.mdwn | 40 + doc/ikiwiki/directive/commentmoderation.mdwn | 9 + doc/ikiwiki/directive/copy.mdwn | 3 + doc/ikiwiki/directive/cut.mdwn | 3 + doc/ikiwiki/directive/cutpaste.mdwn | 50 + doc/ikiwiki/directive/date.mdwn | 16 + doc/ikiwiki/directive/edittemplate.mdwn | 54 + .../directive/edittemplate/discussion.mdwn | 2 + doc/ikiwiki/directive/flattr.mdwn | 45 + doc/ikiwiki/directive/format.mdwn | 29 + doc/ikiwiki/directive/fortune.mdwn | 8 + doc/ikiwiki/directive/graph.mdwn | 32 + doc/ikiwiki/directive/graph/discussion.mdwn | 27 + doc/ikiwiki/directive/haiku.mdwn | 15 + doc/ikiwiki/directive/if.mdwn | 50 + doc/ikiwiki/directive/img.mdwn | 42 + doc/ikiwiki/directive/img/discussion.mdwn | 34 + doc/ikiwiki/directive/inline.mdwn | 130 + doc/ikiwiki/directive/inline/discussion.mdwn | 163 + doc/ikiwiki/directive/linkmap.mdwn | 29 + doc/ikiwiki/directive/listdirectives.mdwn | 20 + doc/ikiwiki/directive/map.mdwn | 21 + doc/ikiwiki/directive/map/discussion.mdwn | 99 + doc/ikiwiki/directive/meta.mdwn | 212 + doc/ikiwiki/directive/meta/discussion.mdwn | 80 + doc/ikiwiki/directive/more.mdwn | 21 + doc/ikiwiki/directive/orphans.mdwn | 15 + doc/ikiwiki/directive/osm.mdwn | 69 + doc/ikiwiki/directive/osm/discussion.mdwn | 13 + doc/ikiwiki/directive/pagecount.mdwn | 10 + doc/ikiwiki/directive/pagestats.mdwn | 40 + .../directive/pagestats/discussion.mdwn | 18 + doc/ikiwiki/directive/pagetemplate.mdwn | 13 + doc/ikiwiki/directive/paste.mdwn | 3 + doc/ikiwiki/directive/ping.mdwn | 18 + doc/ikiwiki/directive/poll.mdwn | 27 + doc/ikiwiki/directive/polygen.mdwn | 11 + doc/ikiwiki/directive/postsparkline.mdwn | 45 + doc/ikiwiki/directive/progress.mdwn | 18 + doc/ikiwiki/directive/shortcut.mdwn | 9 + doc/ikiwiki/directive/sidebar.mdwn | 20 + doc/ikiwiki/directive/sidebar/discussion.mdwn | 10 + doc/ikiwiki/directive/sparkline.mdwn | 52 + doc/ikiwiki/directive/table.mdwn | 53 + doc/ikiwiki/directive/table/discussion.mdwn | 1 + doc/ikiwiki/directive/tag.mdwn | 35 + doc/ikiwiki/directive/tag/discussion.mdwn | 13 + doc/ikiwiki/directive/taglink.mdwn | 3 + doc/ikiwiki/directive/template.mdwn | 105 + doc/ikiwiki/directive/templatebody.mdwn | 28 + doc/ikiwiki/directive/testpagespec.mdwn | 24 + .../directive/testpagespec/discussion.mdwn | 6 + doc/ikiwiki/directive/teximg.mdwn | 23 + doc/ikiwiki/directive/toc.mdwn | 27 + doc/ikiwiki/directive/toggle.mdwn | 34 + doc/ikiwiki/directive/toggle/discussion.mdwn | 15 + doc/ikiwiki/directive/toggleable.mdwn | 3 + doc/ikiwiki/directive/trailitem.mdwn | 9 + doc/ikiwiki/directive/trailitems.mdwn | 25 + doc/ikiwiki/directive/traillink.mdwn | 16 + doc/ikiwiki/directive/trailoptions.mdwn | 18 + doc/ikiwiki/directive/version.mdwn | 12 + doc/ikiwiki/directive/waypoint.mdwn | 6 + doc/ikiwiki/formatting.mdwn | 106 + doc/ikiwiki/formatting/discussion.mdwn | 20 + doc/ikiwiki/markdown.mdwn | 11 + doc/ikiwiki/markdown/discussion.mdwn | 48 + doc/ikiwiki/openid.mdwn | 28 + doc/ikiwiki/pagespec.mdwn | 86 + doc/ikiwiki/pagespec/attachment.mdwn | 38 + .../pagespec/attachment/discussion.mdwn | 15 + doc/ikiwiki/pagespec/discussion.mdwn | 170 + doc/ikiwiki/pagespec/po.mdwn | 23 + doc/ikiwiki/pagespec/sorting.mdwn | 30 + doc/ikiwiki/searching.mdwn | 20 + doc/ikiwiki/subpage.mdwn | 12 + doc/ikiwiki/subpage/linkingrules.mdwn | 33 + doc/ikiwiki/wikilink.mdwn | 29 + doc/ikiwiki/wikilink/discussion.mdwn | 93 + doc/ikiwikiusers.mdwn | 207 + doc/ikiwikiusers/discussion.mdwn | 39 + doc/index.mdwn | 30 + doc/index/discussion.mdwn | 1 + doc/index/openid/discussion.mdwn | 62 + doc/install.mdwn | 48 + doc/install/discussion.mdwn | 358 + doc/local.css | 3 + doc/logo.mdwn | 69 + doc/logo/discussion.mdwn | 1 + doc/logo/favicon.svgz | Bin 0 -> 1412 bytes doc/logo/ikiwiki.png | Bin 0 -> 1157 bytes doc/logo/ikiwiki.svgz | Bin 0 -> 6276 bytes doc/logo/ikiwiki_button.png | Bin 0 -> 974 bytes doc/logo/ikiwiki_large.png | Bin 0 -> 1952 bytes doc/logo/ikiwiki_old.png | Bin 0 -> 335 bytes doc/logo/ikiwiki_old2.png | Bin 0 -> 1275 bytes doc/logo/ikiwiki_old2.svgz | Bin 0 -> 28488 bytes doc/news.mdwn | 9 + doc/news/Article_on_Ikiwiki_as_a_BTS.mdwn | 1 + doc/news/code_swarm.mdwn | 34 + doc/news/code_swarm/code_swarm.config | 51 + doc/news/code_swarm/code_swarm_log.pl | 25 + doc/news/code_swarm/discussion.mdwn | 3 + doc/news/code_swarm/screenshot.png | Bin 0 -> 64320 bytes doc/news/consultant_list.mdwn | 17 + doc/news/discussion.mdwn | 35 + doc/news/donations.mdwn | 1 + doc/news/git_push_to_this_wiki.mdwn | 3 + .../git_push_to_this_wiki/discussion.mdwn | 37 + doc/news/ikiwiki-hosting.mdwn | 16 + .../ikiwiki_accepted_for_Summer_of_Code.mdwn | 5 + doc/news/ikiwiki_screencast.mdwn | 12 + doc/news/ikiwiki_screencast/discussion.mdwn | 8 + doc/news/ikiwiki_version_2.0.mdwn | 32 + doc/news/ikiwiki_version_3.0.mdwn | 42 + doc/news/irc_channel.mdwn | 6 + doc/news/moved_to_git.mdwn | 10 + doc/news/moved_to_git/discussion.mdwn | 43 + doc/news/new_domain_name.mdwn | 1 + doc/news/no_more_email_notifications.mdwn | 14 + doc/news/openid.mdwn | 13 + doc/news/openid/discussion.mdwn | 128 + doc/news/server_move.mdwn | 9 + doc/news/server_move_2009.mdwn | 6 + doc/news/server_speed.mdwn | 9 + doc/news/server_speed/discussion.mdwn | 1 + doc/news/stylesheets.mdwn | 16 + doc/news/stylesheets/discussion.mdwn | 3 + doc/news/version_3.20140125.mdwn | 5 + doc/news/version_3.20140227.mdwn | 27 + doc/news/version_3.20140613.mdwn | 5 + doc/news/version_3.20140815.mdwn | 10 + doc/news/version_3.20140831.mdwn | 3 + doc/pagehistory.mdwn | 8 + doc/patch.mdwn | 12 + doc/patch/core.mdwn | 7 + doc/plugins.mdwn | 17 + doc/plugins/404.mdwn | 24 + doc/plugins/404/discussion.mdwn | 3 + doc/plugins/aggregate.mdwn | 57 + doc/plugins/aggregate/discussion.mdwn | 137 + doc/plugins/amazon_s3.mdwn | 68 + doc/plugins/amazon_s3/discussion.mdwn | 18 + doc/plugins/anonok.mdwn | 19 + doc/plugins/attachment.mdwn | 27 + doc/plugins/autoindex.mdwn | 10 + doc/plugins/autoindex/discussion.mdwn | 84 + doc/plugins/blogspam.mdwn | 32 + doc/plugins/brokenlinks.mdwn | 9 + doc/plugins/calendar.mdwn | 36 + doc/plugins/calendar/discussion.mdwn | 23 + doc/plugins/camelcase.mdwn | 13 + doc/plugins/color.mdwn | 5 + doc/plugins/comments.mdwn | 55 + doc/plugins/comments/discussion.mdwn | 232 + doc/plugins/conditional.mdwn | 5 + doc/plugins/conditional/discussion.mdwn | 76 + doc/plugins/contrib.mdwn | 7 + doc/plugins/contrib/addtag.mdwn | 73 + doc/plugins/contrib/album.mdwn | 154 + doc/plugins/contrib/album/discussion.mdwn | 889 ++ doc/plugins/contrib/asymptote.mdwn | 141 + .../ikiwiki/directive/asymptote.mdwn | 27 + doc/plugins/contrib/attach.mdwn | 47 + doc/plugins/contrib/attach/discussion.mdwn | 18 + doc/plugins/contrib/bibtex.mdwn | 59 + doc/plugins/contrib/cowsay.mdwn | 33 + doc/plugins/contrib/created_in_future.mdwn | 29 + .../contrib/created_in_future/discussion.mdwn | 1 + doc/plugins/contrib/datetime_cmp.mdwn | 86 + ...pyright__42___and___42__license__42__.mdwn | 62 + .../discussion.mdwn | 7 + doc/plugins/contrib/field.mdwn | 219 + doc/plugins/contrib/field/discussion.mdwn | 407 + doc/plugins/contrib/flattr.mdwn | 48 + doc/plugins/contrib/flattr/discussion.mdwn | 9 + doc/plugins/contrib/ftemplate.mdwn | 25 + doc/plugins/contrib/ftemplate/discussion.mdwn | 33 + .../ikiwiki/directive/ftemplate.mdwn | 106 + doc/plugins/contrib/gallery.mdwn | 39 + doc/plugins/contrib/gallery/discussion.mdwn | 45 + doc/plugins/contrib/getfield.mdwn | 137 + doc/plugins/contrib/getfield/discussion.mdwn | 79 + doc/plugins/contrib/googlemaps.mdwn | 21 + .../contrib/googlemaps/discussion.mdwn | 16 + doc/plugins/contrib/groupfile.mdwn | 105 + doc/plugins/contrib/highlightcode.mdwn | 10 + .../contrib/ikiwiki/directive/album.mdwn | 56 + .../contrib/ikiwiki/directive/albumimage.mdwn | 26 + .../ikiwiki/directive/albumsection.mdwn | 29 + .../ikiwiki/directive/jssearchfield.mdwn | 42 + .../contrib/ikiwiki/directive/ymlfront.mdwn | 17 + .../directive/ymlfront/discussion.mdwn | 37 + doc/plugins/contrib/imailhide.mdwn | 65 + doc/plugins/contrib/img.mdwn | 14 + doc/plugins/contrib/img/discussion.mdwn | 51 + doc/plugins/contrib/irclog.mdwn | 21 + doc/plugins/contrib/jscalendar.mdwn | 50 + doc/plugins/contrib/jssearchfield.mdwn | 35 + doc/plugins/contrib/justlogin.mdwn | 52 + doc/plugins/contrib/linguas.mdwn | 107 + doc/plugins/contrib/livefyre.mdwn | 14 + doc/plugins/contrib/localfavicon.mdwn | 7 + doc/plugins/contrib/mailbox.mdwn | 18 + doc/plugins/contrib/mailbox/discussion.mdwn | 8 + doc/plugins/contrib/mandoc.mdwn | 12 + doc/plugins/contrib/mathjax.mdwn | 13 + doc/plugins/contrib/mediawiki.mdwn | 10 + doc/plugins/contrib/mediawiki/discussion.mdwn | 9 + doc/plugins/contrib/monthcalendar.mdwn | 127 + doc/plugins/contrib/mscgen.mdwn | 52 + doc/plugins/contrib/navbar.mdwn | 43 + doc/plugins/contrib/navbar/discussion.mdwn | 2 + doc/plugins/contrib/newpage.mdwn | 29 + doc/plugins/contrib/newpage/discussion.mdwn | 10 + doc/plugins/contrib/nimble.mdwn | 6 + doc/plugins/contrib/opml.mdwn | 11 + doc/plugins/contrib/opml/discussion.mdwn | 4 + doc/plugins/contrib/pagespec_alias.mdwn | 28 + doc/plugins/contrib/pandoc.mdwn | 7 + doc/plugins/contrib/parenttag.mdwn | 14 + doc/plugins/contrib/plusone.mdwn | 35 + doc/plugins/contrib/pod.mdwn | 38 + doc/plugins/contrib/pod/discussion.mdwn | 14 + doc/plugins/contrib/poetry.mdwn | 107 + doc/plugins/contrib/postal.mdwn | 35 + doc/plugins/contrib/postal/discussion.mdwn | 24 + doc/plugins/contrib/purge.mdwn | 38 + doc/plugins/contrib/report.mdwn | 26 + doc/plugins/contrib/report/discussion.mdwn | 80 + .../report/ikiwiki/directive/report.mdwn | 175 + doc/plugins/contrib/sar.mdwn | 109 + doc/plugins/contrib/screenplay.pm.mdwn | 320 + doc/plugins/contrib/sidebar2.mdwn | 96 + doc/plugins/contrib/siterel2pagerel.mdwn | 30 + doc/plugins/contrib/sourcehighlight.mdwn | 30 + doc/plugins/contrib/syntax.mdwn | 65 + doc/plugins/contrib/syntax/discussion.mdwn | 23 + doc/plugins/contrib/taskreport.mdwn | 63 + doc/plugins/contrib/tex4ht.mdwn | 15 + doc/plugins/contrib/texinfo.mdwn | 122 + doc/plugins/contrib/todo.mdwn | 17 + doc/plugins/contrib/tracking.mdwn | 30 + doc/plugins/contrib/unixauth.mdwn | 21 + doc/plugins/contrib/unixauth/discussion.mdwn | 38 + doc/plugins/contrib/unixrelpagespec.mdwn | 42 + doc/plugins/contrib/video.mdwn | 25 + doc/plugins/contrib/video/discussion.mdwn | 3 + doc/plugins/contrib/wordcount.mdwn | 22 + doc/plugins/contrib/xslt.mdwn | 39 + doc/plugins/contrib/xslt/discussion.mdwn | 49 + doc/plugins/contrib/ymlfront.mdwn | 143 + doc/plugins/contrib/ymlfront/discussion.mdwn | 31 + doc/plugins/creole.mdwn | 22 + doc/plugins/creole/discussion.mdwn | 22 + doc/plugins/cutpaste.mdwn | 7 + doc/plugins/date.mdwn | 6 + doc/plugins/ddate.mdwn | 10 + doc/plugins/discussion.mdwn | 42 + doc/plugins/editdiff.mdwn | 13 + doc/plugins/editdiff/discussion.mdwn | 5 + doc/plugins/editpage.mdwn | 6 + doc/plugins/editpage/discussion.mdwn | 24 + doc/plugins/edittemplate.mdwn | 6 + doc/plugins/embed.mdwn | 53 + doc/plugins/favicon.mdwn | 7 + doc/plugins/favicon/discussion.mdwn | 19 + doc/plugins/filecheck.mdwn | 17 + doc/plugins/filecheck/discussion.mdwn | 85 + doc/plugins/flattr.mdwn | 9 + doc/plugins/format.mdwn | 9 + doc/plugins/format/discussion.mdwn | 15 + doc/plugins/fortune.mdwn | 14 + doc/plugins/getsource.mdwn | 14 + doc/plugins/getsource/discussion.mdwn | 3 + doc/plugins/goodstuff.mdwn | 29 + doc/plugins/goodstuff/discussion.mdwn | 8 + doc/plugins/google.mdwn | 11 + doc/plugins/google/discussion.mdwn | 25 + doc/plugins/goto.mdwn | 10 + doc/plugins/graphviz.mdwn | 25 + doc/plugins/haiku.mdwn | 12 + doc/plugins/haiku/discussion.mdwn | 5 + doc/plugins/headinganchors.mdwn | 7 + doc/plugins/headinganchors/discussion.mdwn | 49 + doc/plugins/highlight.mdwn | 77 + doc/plugins/highlight/discussion.mdwn | 37 + doc/plugins/hnb.mdwn | 6 + doc/plugins/hnb/discussion.mdwn | 28 + doc/plugins/html.mdwn | 11 + doc/plugins/htmlbalance.mdwn | 9 + doc/plugins/htmlbalance/discussion.mdwn | 10 + doc/plugins/htmlscrubber.mdwn | 51 + doc/plugins/htmlscrubber/discussion.mdwn | 18 + doc/plugins/htmltidy.mdwn | 11 + doc/plugins/httpauth.mdwn | 37 + doc/plugins/img.mdwn | 14 + doc/plugins/img/discussion.mdwn | 12 + doc/plugins/inline.mdwn | 6 + doc/plugins/install.mdwn | 19 + doc/plugins/link.mdwn | 5 + doc/plugins/linkmap.mdwn | 14 + doc/plugins/listdirectives.mdwn | 16 + doc/plugins/localstyle.mdwn | 12 + doc/plugins/lockedit.mdwn | 23 + doc/plugins/lockedit/discussion.mdwn | 18 + doc/plugins/map.mdwn | 11 + doc/plugins/map/discussion.mdwn | 49 + doc/plugins/mdwn.mdwn | 23 + doc/plugins/mdwn/discussion.mdwn | 7 + doc/plugins/meta.mdwn | 5 + doc/plugins/meta/discussion.mdwn | 18 + doc/plugins/mirrorlist.mdwn | 22 + doc/plugins/moderatedcomments.mdwn | 12 + doc/plugins/more.mdwn | 6 + doc/plugins/more/discussion.mdwn | 7 + doc/plugins/notifyemail.mdwn | 14 + doc/plugins/notifyemail/discussion.mdwn | 5 + doc/plugins/opendiscussion.mdwn | 11 + doc/plugins/openid.mdwn | 37 + doc/plugins/openid/discussion.mdwn | 26 + doc/plugins/openid/troubleshooting.mdwn | 253 + doc/plugins/orphans.mdwn | 16 + doc/plugins/orphans/discussion.mdwn | 22 + doc/plugins/osm.mdwn | 47 + doc/plugins/osm/discussion.mdwn | 25 + doc/plugins/otl.mdwn | 6 + doc/plugins/pagecount.mdwn | 11 + doc/plugins/pagestats.mdwn | 6 + doc/plugins/pagetemplate.mdwn | 6 + doc/plugins/parentlinks.mdwn | 5 + doc/plugins/passwordauth.mdwn | 33 + doc/plugins/passwordauth/discussion.mdwn | 151 + doc/plugins/pingee.mdwn | 11 + doc/plugins/pingee/discussion.mdwn | 9 + doc/plugins/pinger.mdwn | 20 + doc/plugins/pinger/discussion.mdwn | 1 + doc/plugins/po.mdwn | 260 + doc/plugins/po/discussion.mdwn | 721 + doc/plugins/poll.mdwn | 5 + doc/plugins/poll/discussion.mdwn | 1 + doc/plugins/polygen.mdwn | 25 + doc/plugins/postsparkline.mdwn | 14 + doc/plugins/prettydate.mdwn | 20 + doc/plugins/progress.mdwn | 5 + doc/plugins/rawhtml.mdwn | 13 + doc/plugins/rawhtml/discussion.mdwn | 7 + doc/plugins/recentchanges.mdwn | 32 + doc/plugins/recentchanges/discussion.mdwn | 17 + doc/plugins/recentchangesdiff.mdwn | 9 + doc/plugins/recentchangesdiff/discussion.mdwn | 28 + doc/plugins/relativedate.mdwn | 11 + doc/plugins/remove.mdwn | 7 + doc/plugins/rename.mdwn | 12 + doc/plugins/repolist.mdwn | 17 + doc/plugins/rst.mdwn | 18 + doc/plugins/rst/discussion.mdwn | 81 + doc/plugins/rsync.mdwn | 19 + doc/plugins/rsync/discussion.mdwn | 79 + doc/plugins/search.mdwn | 18 + doc/plugins/search/discussion.mdwn | 1 + doc/plugins/shortcut.mdwn | 9 + doc/plugins/shortcut/discussion.mdwn | 18 + doc/plugins/sidebar.mdwn | 28 + doc/plugins/sidebar/discussion.mdwn | 12 + doc/plugins/signinedit.mdwn | 5 + doc/plugins/smiley.mdwn | 9 + doc/plugins/sortnaturally.mdwn | 6 + doc/plugins/sparkline.mdwn | 22 + doc/plugins/table.mdwn | 12 + doc/plugins/table/discussion.mdwn | 73 + doc/plugins/tag.mdwn | 24 + doc/plugins/tag/discussion.mdwn | 31 + doc/plugins/template.mdwn | 7 + doc/plugins/templatebody.mdwn | 7 + doc/plugins/testpagespec.mdwn | 6 + doc/plugins/teximg.mdwn | 20 + doc/plugins/teximg/discussion.mdwn | 5 + doc/plugins/textile.mdwn | 6 + doc/plugins/theme.mdwn | 18 + doc/plugins/theme/discussion.mdwn | 26 + doc/plugins/toc.mdwn | 5 + doc/plugins/toc/discussion.mdwn | 31 + doc/plugins/toggle.mdwn | 7 + doc/plugins/toggle/discussion.mdwn | 43 + doc/plugins/trail.mdwn | 76 + doc/plugins/trail/discussion.mdwn | 185 + doc/plugins/transient.mdwn | 23 + doc/plugins/txt.mdwn | 19 + doc/plugins/txt/discussion.mdwn | 33 + doc/plugins/type/auth.mdwn | 4 + doc/plugins/type/bundle.mdwn | 3 + doc/plugins/type/chrome.mdwn | 3 + doc/plugins/type/comments.mdwn | 3 + doc/plugins/type/core.mdwn | 3 + doc/plugins/type/date.mdwn | 3 + doc/plugins/type/format.mdwn | 3 + doc/plugins/type/fun.mdwn | 3 + doc/plugins/type/html.mdwn | 3 + doc/plugins/type/link.mdwn | 3 + doc/plugins/type/meta.mdwn | 3 + doc/plugins/type/slow.mdwn | 5 + doc/plugins/type/special-purpose.mdwn | 3 + doc/plugins/type/tags.mdwn | 3 + doc/plugins/type/web.mdwn | 3 + doc/plugins/type/widget.mdwn | 4 + doc/plugins/typography.mdwn | 12 + doc/plugins/underlay.mdwn | 14 + doc/plugins/userlist.mdwn | 6 + doc/plugins/version.mdwn | 7 + doc/plugins/websetup.mdwn | 27 + doc/plugins/wikitext.mdwn | 23 + doc/plugins/wmd.mdwn | 16 + doc/plugins/wmd/discussion.mdwn | 22 + doc/plugins/write.mdwn | 1433 ++ doc/plugins/write/discussion.mdwn | 46 + doc/plugins/write/external.mdwn | 146 + doc/plugins/write/names.mdwn | 25 + doc/plugins/write/tutorial.mdwn | 189 + doc/plugins/write/tutorial/discussion.mdwn | 20 + doc/podcast.mdwn | 18 + doc/post-commit.mdwn | 19 + doc/post-commit/discussion.mdwn | 123 + doc/quotes.mdwn | 3 + doc/quotes/pizza.mdwn | 4 + doc/quotes/pizza/discussion.mdwn | 1 + doc/quotes/sold.mdwn | 3 + doc/rcs.mdwn | 44 + doc/rcs/bzr.mdwn | 8 + doc/rcs/cvs.mdwn | 46 + doc/rcs/cvs/discussion.mdwn | 191 + doc/rcs/darcs.mdwn | 15 + doc/rcs/details.mdwn | 292 + doc/rcs/details/discussion.mdwn | 15 + doc/rcs/git.mdwn | 153 + doc/rcs/git/discussion.mdwn | 129 + doc/rcs/git/wiki_edit_flow.svg | 707 + doc/rcs/mercurial.mdwn | 18 + doc/rcs/monotone.mdwn | 24 + doc/rcs/svn.mdwn | 9 + doc/rcs/svn/discussion.mdwn | 13 + doc/rcs/tla.mdwn | 13 + doc/recentchanges.mdwn | 7 + doc/reviewed.mdwn | 7 + doc/roadmap.mdwn | 95 + doc/roadmap/discussion.mdwn | 32 + doc/robots.txt | 2 + doc/sandbox.mdwn | 123 + doc/sandbox/NewPage.mdwn | 1 + doc/sandbox/New_blog_entry.mdwn | 3 + doc/sandbox/Test.py | 2 + doc/sandbox/discussion.mdwn | 7 + ...at_kind_of_a_blog_is_this__63____41__.mdwn | 3 + doc/sandbox/new__95__test.mdwn | 1 + doc/sandbox/testostereone.mdwn | 1 + doc/security.mdwn | 499 + doc/security/discussion.mdwn | 33 + doc/setup.mdwn | 152 + doc/setup/byhand.mdwn | 202 + doc/setup/byhand/discussion.mdwn | 7 + doc/setup/discussion.mdwn | 271 + doc/shortcuts.mdwn | 83 + doc/shortcuts/discussion.mdwn | 21 + doc/sitemap.mdwn | 5 + doc/smileys.mdwn | 56 + doc/smileys/alert.png | Bin 0 -> 220 bytes doc/smileys/angry.png | Bin 0 -> 295 bytes doc/smileys/attention.png | Bin 0 -> 164 bytes doc/smileys/biggrin.png | Bin 0 -> 173 bytes doc/smileys/checkmark.png | Bin 0 -> 133 bytes doc/smileys/devil.png | Bin 0 -> 354 bytes doc/smileys/frown.png | Bin 0 -> 168 bytes doc/smileys/icon-error.png | Bin 0 -> 397 bytes doc/smileys/icon-info.png | Bin 0 -> 171 bytes doc/smileys/idea.png | Bin 0 -> 372 bytes doc/smileys/neutral.png | Bin 0 -> 239 bytes doc/smileys/ohwell.png | Bin 0 -> 167 bytes doc/smileys/prio1.png | Bin 0 -> 153 bytes doc/smileys/prio2.png | Bin 0 -> 158 bytes doc/smileys/prio3.png | Bin 0 -> 153 bytes doc/smileys/question.png | Bin 0 -> 302 bytes doc/smileys/redface.png | Bin 0 -> 306 bytes doc/smileys/sad.png | Bin 0 -> 182 bytes doc/smileys/smile.png | Bin 0 -> 356 bytes doc/smileys/smile2.png | Bin 0 -> 334 bytes doc/smileys/smile3.png | Bin 0 -> 326 bytes doc/smileys/smile4.png | Bin 0 -> 275 bytes doc/smileys/star_off.png | Bin 0 -> 297 bytes doc/smileys/star_on.png | Bin 0 -> 370 bytes doc/smileys/thumbs-up.png | Bin 0 -> 118 bytes doc/smileys/tired.png | Bin 0 -> 157 bytes doc/smileys/tongue.png | Bin 0 -> 176 bytes doc/soc.mdwn | 20 + doc/soc/application.mdwn | 96 + doc/soc/discussion.mdwn | 2 + doc/soc/ideas.mdwn | 8 + doc/spam_fighting.mdwn | 35 + doc/style.css | 550 + doc/tags.mdwn | 26 + doc/tags/discussion.mdwn | 20 + doc/templates.mdwn | 99 + doc/templates/discussion.mdwn | 28 + doc/templates/gitbranch.mdwn | 16 + doc/templates/links.mdwn | 16 + doc/templates/note.mdwn | 11 + doc/templates/plugin.mdwn | 19 + doc/templates/popup.mdwn | 16 + doc/theme_market.mdwn | 15 + doc/themes.mdwn | 34 + doc/themes/actiontabs_small.png | Bin 0 -> 19202 bytes doc/themes/blueview_small.png | Bin 0 -> 18543 bytes doc/themes/discussion.mdwn | 20 + doc/themes/goldtype_small.png | Bin 0 -> 19240 bytes doc/themes/monochrome_small.png | Bin 0 -> 21054 bytes doc/themes/none_small.png | Bin 0 -> 18516 bytes doc/tipjar.mdwn | 25 + doc/tips.mdwn | 5 + doc/tips/Adding_Disqus_to_your_wiki.mdwn | 30 + .../discussion.mdwn | 1 + doc/tips/DreamHost.mdwn | 192 + doc/tips/DreamHost/discussion.mdwn | 18 + doc/tips/Emacs_and_markdown.html | 16 + ...ory_and_web_server_on_different_hosts.mdwn | 63 + .../separate-webserver.svg | 716 + doc/tips/Google_custom_search.mdwn | 12 + ..._git_repository_on_different_machines.mdwn | 157 + .../discussion.mdwn | 14 + .../separate-web-git-servers.svg | 783 ++ ...___the_album_and_the_underlay_plugins.mdwn | 64 + doc/tips/Importing_posts_from_Wordpress.mdwn | 102 + .../discussion.mdwn | 44 + ...ript_to_add_index.html_to_file:_links.mdwn | 63 + .../discusion.mdwn | 3 + .../discussion.mdwn | 2 + .../Make_calendar_start_week_on_Monday.mdwn | 9 + .../discussion.mdwn | 1 + doc/tips/Movable_Type_to_ikiwiki.mdwn | 37 + ...ght-to-left___40__RTL__41___page_text.mdwn | 49 + doc/tips/add_chatterbox_to_blog.mdwn | 24 + .../add_chatterbox_to_blog/discussion.mdwn | 43 + doc/tips/blog_script.mdwn | 6 + doc/tips/comments_feed.mdwn | 17 + .../convert_blogger_blogs_to_ikiwiki.mdwn | 5 + doc/tips/convert_mediawiki_to_ikiwiki.mdwn | 299 + .../discussion.mdwn | 669 + doc/tips/convert_moinmoin_to_ikiwiki.mdwn | 108 + .../discussion.mdwn | 7 + doc/tips/distributed_wikis.mdwn | 248 + .../distributed_wikis/decentralized_wikis.svg | 1511 ++ doc/tips/distributed_wikis/discussion.mdwn | 22 + doc/tips/distributed_wikis/ping-setup.svg | 1064 ++ doc/tips/dot_cgi.mdwn | 112 + doc/tips/dot_cgi/discussion.mdwn | 51 + doc/tips/emacs_syntax_highlighting.mdwn | 3 + doc/tips/embedding_content.mdwn | 35 + .../follow_wikilinks_from_inside_vim.mdwn | 47 + doc/tips/github.mdwn | 64 + .../howto_avoid_flooding_aggregators.mdwn | 28 + doc/tips/howto_limit_to_admin_users.mdwn | 9 + doc/tips/htaccess_file.mdwn | 27 + doc/tips/html5.mdwn | 27 + ...iki_as_a_requirements_management_tool.mdwn | 95 + .../discussion.mdwn | 21 + doc/tips/ikiwiki_on_mac_os_x.mdwn | 228 + doc/tips/ikiwiki_on_mac_os_x/discussion.mdwn | 16 + doc/tips/ikiwiki_via_gopher.mdwn | 22 + doc/tips/ikiwiki_via_gopher/discussion.mdwn | 8 + doc/tips/importing_posts_from_typo.mdwn | 1 + .../ikiwiki-wordpress-import.mdwn | 468 + doc/tips/inside_dot_ikiwiki.mdwn | 91 + doc/tips/inside_dot_ikiwiki/discussion.mdwn | 66 + ...ntegrated_issue_tracking_with_ikiwiki.mdwn | 277 + .../discussion.mdwn | 32 + doc/tips/laptop_wiki_with_git.mdwn | 93 + doc/tips/laptop_wiki_with_git/discussion.mdwn | 15 + doc/tips/laptop_wiki_with_git_extended.mdwn | 43 + .../discussion.mdwn | 1 + doc/tips/mailman_subscription_form.mdwn | 10 + doc/tips/markdown_and_eclipse.mdwn | 4 + doc/tips/mathopd_permissions.mdwn | 15 + doc/tips/migrating_podcast_to_ikiwiki.mdwn | 19 + .../monitor_page_changes_through_IRC.mdwn | 9 + doc/tips/nearlyfreespeech.mdwn | 108 + doc/tips/nearlyfreespeech/discussion.mdwn | 22 + doc/tips/optimising_ikiwiki.mdwn | 211 + doc/tips/parentlinks_style.mdwn | 143 + doc/tips/psgi.mdwn | 21 + doc/tips/redirections_for_usedirs.mdwn | 39 + doc/tips/spam_and_softwaresites.mdwn | 87 + .../spam_and_softwaresites/discussion.mdwn | 8 + doc/tips/switching_to_usedirs.mdwn | 28 + doc/tips/switching_to_usedirs/discussion.mdwn | 24 + doc/tips/untrusted_git_push.mdwn | 114 + doc/tips/untrusted_git_push/discussion.mdwn | 33 + doc/tips/upgrade_to_3.0.mdwn | 95 + ...web_interface_with_a_real_text_editor.mdwn | 17 + .../discussion.mdwn | 2 + doc/tips/vim_and_ikiwiki.mdwn | 28 + doc/tips/vim_syntax_highlighting.mdwn | 20 + .../vim_syntax_highlighting/discussion.mdwn | 8 + doc/tips/vim_syntax_highlighting/ikiwiki.vim | 71 + doc/tips/wikiannounce.mdwn | 8 + doc/tips/yaml_setup_files.mdwn | 12 + doc/todo.mdwn | 21 + doc/todo/ACL.mdwn | 98 + ...esults_in_unnecessary_feed_generation.mdwn | 80 + doc/todo/Account-creation_password.mdwn | 6 + doc/todo/Account_moderation.mdwn | 12 + ...d_DATE_parameter_for_use_in_templates.mdwn | 86 + doc/todo/Add_HTML_support_to_po_plugin.mdwn | 9 + ...list_available_pre-processor_commands.mdwn | 141 + doc/todo/Add_basename_in_edittemplate.mdwn | 8 + doc/todo/Add_camelcase_exclusions.mdwn | 23 + ...mmit_messages_for_add__47__edit_pages.mdwn | 43 + ...ve_commit_messages_for_removing_pages.mdwn | 32 + .../Add_label_to_search_form_input_field.mdwn | 56 + doc/todo/Add_nicer_math_formatting.mdwn | 31 + .../Add_showdown_GUI_input__47__edit.mdwn | 31 + ...dd_space_before_slash_in_parent_links.mdwn | 156 + ...atest_Text::Markdown_as_found_on_CPAN.mdwn | 45 + doc/todo/Adjust_goodstuff.mdwn | 12 + ..._the_path_in_addition_to_the_basename.mdwn | 79 + doc/todo/Allow_change_of_wiki_file_types.mdwn | 85 + ..._disabling_edit_and_preferences_links.mdwn | 81 + .../Allow_edittemplate_to_set_file_type.mdwn | 44 + .../Allow_filenames_that_are_all_type.mdwn | 41 + .../Allow_per-page_template_selection.mdwn | 43 + ...it_form_comment_field_to_be_mandatory.mdwn | 22 + ...t_to_extend_Mercurial_backend_support.mdwn | 258 + ..._and_maintain_Mercurial_wrapper_hooks.mdwn | 240 + .../Auto-setup_should_default_to_YAML.mdwn | 3 + ...etup_from_wikilist_in_Debian_package_.mdwn | 29 + doc/todo/BTS_integration.mdwn | 11 + ...dir_along_with_bestlink_in_IkiWiki.pm.mdwn | 51 + .../discussion.mdwn | 6 + doc/todo/Better_bug_tracking_support.mdwn | 71 + ...Better_reporting_of_validation_errors.mdwn | 2 + doc/todo/BibTeX.mdwn | 74 + doc/todo/BrowserID.mdwn | 25 + doc/todo/CGI_method_to_pullrefresh.mdwn | 7 + doc/todo/CSS_classes_for_links.mdwn | 138 + doc/todo/CVS_backend.mdwn | 16 + ...ar:_listing_multiple_entries_per_day_.mdwn | 94 + doc/todo/Case.mdwn | 4 + doc/todo/Commit_emails:_ones_own_changes.mdwn | 9 + ...m_length_of_log_message_for_web_edits.mdwn | 5 + .../Configureable_separator_of_page_name.mdwn | 12 + ...mend_gcc_+_libc6-dev__44___not_Depend.mdwn | 22 + doc/todo/Default_text_for_new_pages.mdwn | 104 + doc/todo/Does_not_support_non-UTF8_files.mdwn | 7 + doc/todo/Editing_po_files.mdwn | 5 + ...filtering_of_files_indexed_for_search.mdwn | 7 + doc/todo/Extensible_inlining.mdwn | 263 + doc/todo/Feature_parity_with_Trac.mdwn | 22 + ...__from_GitHub_Flavored_Markdown__41__.mdwn | 44 + ...o_not_put_a_border_around_image_links.mdwn | 7 + doc/todo/Fix_selflink_in_po_plugin.mdwn | 21 + .../FormBuilder__95__Template__95__patch.mdwn | 10 + ...FormattingHelp_should_open_new_window.mdwn | 1 + doc/todo/Gallery.mdwn | 83 + ...lates_inserted_by_the_template_plugin.mdwn | 111 + doc/todo/Google_Analytics_support.mdwn | 31 + doc/todo/Google_Sitemap_protocol.mdwn | 60 + ..._pdf__44___openoffice__44___documents.mdwn | 5 + doc/todo/IRC_topic.mdwn | 10 + doc/todo/Improve_display_of_OpenIDs.mdwn | 5 + doc/todo/Improve_markdown_speed.mdwn | 33 + doc/todo/Improve_signin_form_layout.mdwn | 44 + ...ing_the_efficiency_of_match__95__glob.mdwn | 228 + ..._plugin_option_to_show_full_page_path.mdwn | 30 + ..._36__tagbase_should_be_in__by_default.mdwn | 15 + doc/todo/Mailing_list.mdwn | 36 + .../Make_example_setup_file_consistent.mdwn | 33 + doc/todo/Mercurial_backend_update.mdwn | 969 ++ doc/todo/Modern_standard_layout.mdwn | 39 + ...re_flexible_po-plugin_for_translation.mdwn | 5 + ..._teximg_latex_preamble_to_config_file.mdwn | 156 + doc/todo/Moving_Pages.mdwn | 222 + .../Multiple_categorization_namespaces.mdwn | 103 + .../New_preprocessor_directive_syntax.mdwn | 21 + .../discussion.mdwn | 19 + doc/todo/OpenSearch.mdwn | 38 + ...tion_linktext_for_pagestats_directive.mdwn | 203 + ...on_to_disable_date_footer_for_inlines.mdwn | 31 + .../Option_to_make_title_an_h1__63__.mdwn | 14 + .../Overlay_directory_for_pagetemplates.mdwn | 9 + doc/todo/Pagination_next_prev_links.mdwn | 68 + ...__34___links_for_popular_feed_readers.mdwn | 6 + ...-compilation_inclusion_of_the_sidebar.mdwn | 67 + doc/todo/Print_link.mdwn | 73 + ..._relative_urls_for_stylesheet_linking.mdwn | 32 + doc/todo/RSS_fields.mdwn | 25 + doc/todo/RSS_links.mdwn | 17 + doc/todo/Raw_view_link.mdwn | 19 + ...hanges_page_links_without_cgi_wrapper.mdwn | 26 + ...multiple_destinations_from_one_source.mdwn | 85 + ...StructuredText_links_to_ikiwiki_pages.mdwn | 333 + ...Restrict_formats_allowed_for_comments.mdwn | 99 + doc/todo/Restrict_page_viewing.mdwn | 42 + doc/todo/Separate_OpenIDs_and_usernames.mdwn | 55 + ...ry_date_to_be_used_by_calendar_plugin.mdwn | 210 + .../discussion.mdwn | 44 + ...plates_for_whole_sections_of_the_site.mdwn | 63 + doc/todo/Short_wikilinks.mdwn | 104 + doc/todo/Shorter_feeds.mdwn | 11 + doc/todo/Silence_monotone_warning.mdwn | 17 + ...dencies_into_separate_Debian_packages.mdwn | 40 + ...n_should_be_subpage_if_siblings_exist.mdwn | 26 + doc/todo/Support_MultiMarkdown_3.X.mdwn | 10 + doc/todo/Support_XML-RPC-based_blogging.mdwn | 17 + .../Support__47__Switch_to_MultiMarkdown.mdwn | 35 + ...t_clipboard_copy__47__paste_of_images.mdwn | 3 + doc/todo/Support_preprocessing_CSS.mdwn | 1 + .../Support_subdirectory_of_a_git_repo.mdwn | 9 + .../Support_tab_insertion_in_textarea.mdwn | 15 + ...of_link__40____41___within_a_pagespec.mdwn | 45 + ...ags_list_in_page_footer_uses_basename.mdwn | 11 + ...rack_Markdown_Standardisation_Efforts.mdwn | 7 + doc/todo/Unit_tests.mdwn | 10 + doc/todo/Untrusted_push_in_Monotone.mdwn | 28 + doc/todo/Updated_bug_tracking_example.mdwn | 136 + .../Using_page_titles_in_internal_links.mdwn | 3 + doc/todo/Wikilink_to_a_symbolic_link.mdwn | 5 + .../Wrapper_config_with_multiline_regexp.mdwn | 36 + doc/todo/Zoned_ikiwiki.mdwn | 64 + ...this_page__34___checkbox_on_edit_form.mdwn | 10 + ...ing_functionality_for_the_meta_plugin.mdwn | 67 + ..._47___should_point_to_top-level_index.mdwn | 3 + .../a_navbar_based_on_page_properties.mdwn | 48 + doc/todo/abbreviation.mdwn | 7 + ..._force_particular_UUIDs_on_blog_posts.mdwn | 24 + doc/todo/absolute_urls_in_wikilinks.mdwn | 20 + doc/todo/access_keys.mdwn | 286 + doc/todo/ad-hoc_plugins.mdwn | 66 + ..._forward_age_sorting_option_to_inline.mdwn | 34 + doc/todo/add_remove_to_actionlist.mdwn | 20 + ..._new_pages_by_using_the_web_interface.mdwn | 79 + ...ommit_message_for_rename__44___remove.mdwn | 5 + doc/todo/aggregate_401_handling.mdwn | 20 + doc/todo/aggregate_locking.mdwn | 64 + doc/todo/aggregate_to_internal_pages.mdwn | 59 + doc/todo/aggregation.mdwn | 3 + doc/todo/alias_directive.mdwn | 72 + .../allow_CGI_to_create_dynamic_pages.mdwn | 3 + ...TMPL__95__LOOP_in_template_directives.mdwn | 278 + ...ning_a_user_when_moderating_a_comment.mdwn | 1 + .../allow_creation_of_non-existent_pages.mdwn | 13 + doc/todo/allow_disabling_backlinks.mdwn | 18 + .../allow_displaying_number_of_comments.mdwn | 30 + ...m_the___34__add_a_new_post__34___form.mdwn | 12 + ...quiring_description_when_editing_page.mdwn | 24 + .../allow_plugins_to_add_sorting_methods.mdwn | 304 + .../allow_site-wide_meta_definitions.mdwn | 169 + .../allow_wiki_syntax_in_commit_messages.mdwn | 21 + doc/todo/anon_push_of_comments.mdwn | 14 + doc/todo/anti-spam_protection.mdwn | 30 + .../apache_404_ErrorDocument_handler.mdwn | 25 + doc/todo/applydiff_plugin.mdwn | 110 + doc/todo/assumes_system_perl.mdwn | 20 + doc/todo/attachments.mdwn | 23 + ...ate_tag_pages_according_to_a_template.mdwn | 270 + doc/todo/auto_getctime_on_fresh_build.mdwn | 13 + doc/todo/auto_publish_expire.mdwn | 41 + doc/todo/auto_rebuild_on_template_change.mdwn | 78 + ...utoindex_should_use_add__95__autofile.mdwn | 120 + .../automatic_rebuilding_of_html_pages.mdwn | 5 + ...of_syntax_plugin_on_source_code_files.mdwn | 17 + .../discussion.mdwn | 215 + doc/todo/avatar.mdwn | 31 + doc/todo/avatar/discussion.mdwn | 1 + ..._attachement_ui_if_upload_not_allowed.mdwn | 25 + doc/todo/avoid_thrashing.mdwn | 22 + doc/todo/backlinks_result_is_lossy.mdwn | 12 + .../basewiki_should_be_self_documenting.mdwn | 40 + ...be_more_selective_about_running_hooks.mdwn | 68 + ...idebar_to_allow_for_multiple_sidebars.mdwn | 129 + doc/todo/beef_up_signin_page.mdwn | 17 + doc/todo/bitcoin_URI_scheme.mdwn | 16 + doc/todo/block_external_links.mdwn | 16 + doc/todo/blocking_ip_ranges.mdwn | 7 + doc/todo/blogging.mdwn | 137 + doc/todo/blogpost_plugin.mdwn | 156 + doc/todo/blogs.mdwn | 4 + doc/todo/blogspam_training.mdwn | 31 + .../break_up_page_template_into_subfiles.mdwn | 36 + ...kenlinks_should_group_links_to_a_page.mdwn | 21 + doc/todo/bugs-everywhere_integration.mdwn | 7 + doc/todo/bzr.mdwn | 194 + doc/todo/cache_backlinks.mdwn | 25 + ...hive_browsing_via_a_calendar_frontend.mdwn | 124 + doc/todo/calendar_autocreate.mdwn | 225 + ...alendar_with___34__create__34___links.mdwn | 10 + .../incomplete_patch.pl | 36 + ...ate-server-info_from_post-udpate_hook.mdwn | 15 + doc/todo/canonical_feed_location.mdwn | 16 + doc/todo/capitalize_title.mdwn | 31 + doc/todo/cas_authentication.mdwn | 184 + ...ate_and_mdate_available_for_templates.mdwn | 15 + doc/todo/cgi_hooks_get_session_objects.mdwn | 5 + doc/todo/clear_page_to_delete.mdwn | 35 + doc/todo/clickable-openid-urls-in-logs.mdwn | 23 + doc/todo/color_plugin.mdwn | 231 + doc/todo/comment_by_mail.mdwn | 3 + doc/todo/comment_by_mail/discussion.mdwn | 25 + doc/todo/comment_moderation_feed.mdwn | 16 + doc/todo/comments.mdwn | 170 + doc/todo/concatenating_or_compiling_CSS.mdwn | 159 + ...tional_text_based_on_ikiwiki_features.mdwn | 128 + doc/todo/conditional_underlay_files.mdwn | 29 + doc/todo/configurable_markdown_path.mdwn | 64 + ...onfigurable_tidy_command_for_htmltidy.mdwn | 8 + doc/todo/configurable_timezones.mdwn | 7 + doc/todo/conflict_free_comment_merges.mdwn | 23 + doc/todo/consistent_smileys.mdwn | 22 + doc/todo/copyright_based_on_pagespec.mdwn | 10 + ...pdated_time_information_for_the_feeds.mdwn | 113 + doc/todo/countdown_directive.mdwn | 5 + doc/todo/credentials_page.mdwn | 33 + doc/todo/ctime_on_blog_post_pages_.mdwn | 11 + doc/todo/custom_location_for_openlayers.mdwn | 17 + doc/todo/darcs.mdwn | 53 + doc/todo/datearchives-plugin.mdwn | 77 + doc/todo/default_content_for_new_post.mdwn | 66 + doc/todo/default_name_for_new_post.mdwn | 3 + doc/todo/dependency_types.mdwn | 579 + ...iption_meta_param_passed_to_templates.mdwn | 10 + doc/todo/different_search_engine.mdwn | 332 + doc/todo/directive_docs.mdwn | 79 + doc/todo/discuss_without_login.mdwn | 19 + doc/todo/discussion_page_as_blog.mdwn | 33 + .../discussion/castle.mdwn | 3 + .../discussion/castle/discussion.mdwn | 1 + .../discussion/Don__39__t_like_foo.mdwn | 3 + .../Don__39__t_like_foo/how_about_bar.mdwn | 1 + .../discussion/Don__39__t_like_foo/sdf.mdwn | 5 + .../castle/discussion/foo_is_ok.mdwn | 1 + .../discussion/castle/discussion/test.mdwn | 1 + doc/todo/do_not_make_links_backwards.mdwn | 125 + ...ocument_dependency_influences_in_code.mdwn | 28 + doc/todo/done.mdwn | 3 + ...ble-click_protection_for_form_buttons.mdwn | 5 + doc/todo/doxygen_support.mdwn | 7 + doc/todo/dynamic_rootpage.mdwn | 35 + doc/todo/ease_archivepage_styling.mdwn | 59 + ...edit_form:_no_fixed_size_for_textarea.mdwn | 52 + ...ook_in_templates_directory_by_default.mdwn | 8 + ...uld_support_uuid__44___date_variables.mdwn | 87 + doc/todo/else_parameter_for_map_plugin.mdwn | 56 + doc/todo/enable-htaccess-files.mdwn | 80 + ...nable_arbitrary_markup_for_directives.mdwn | 47 + doc/todo/etherpad_support.mdwn | 22 + doc/todo/excluding_commit_mails.mdwn | 19 + .../expose_html_language_and_direction.mdwn | 15 + doc/todo/fancypodcast.mdwn | 69 + doc/todo/fancypodcast/discussion.mdwn | 167 + ..._or_modperl_installation_instructions.mdwn | 20 + .../feed_enhancements_for_inline_pages.mdwn | 132 + doc/todo/fileupload.mdwn | 63 + doc/todo/fileupload/discussion.mdwn | 45 + doc/todo/fileupload/soc-proposal.mdwn | 71 + .../fileupload/soc-proposal/discussion.mdwn | 46 + doc/todo/filtering_content_when_inlining.mdwn | 16 + ...ntrol_over___60__object___47____62__s.mdwn | 98 + doc/todo/firm_up_plugin_interface.mdwn | 96 + .../flexible_relationships_between_pages.mdwn | 149 + .../blocks.pm.mdwn | 129 + ..._amazon_s3_pre-gzip-encode_safe_files.mdwn | 17 + doc/todo/format_escape.mdwn | 292 + ...rtune:_select_options_via_environment.mdwn | 34 + doc/todo/friendly_markup_names.mdwn | 13 + ...generated_po_stuff_not_ignored_by_git.mdwn | 6 + ...eric___39__do__61__goto__39___for_CGI.mdwn | 35 + doc/todo/generic_insert_links.mdwn | 24 + doc/todo/geotagging.mdwn | 7 + doc/todo/git-annex_support.mdwn | 99 + doc/todo/git-annex_support/discussion.mdwn | 15 + ...tive_path___40__fixes_git_ctime__41__.mdwn | 24 + doc/todo/git_attribution.mdwn | 9 + doc/todo/git_attribution/discussion.mdwn | 98 + ..._recentchanges_should_not_show_merges.mdwn | 20 + doc/todo/graphviz.mdwn | 19 + ...ion_for_man_pages_and_w3m_cgi_wrapper.mdwn | 94 + doc/todo/headless_git_branches.mdwn | 113 + doc/todo/hidden_links__47__tags.mdwn | 13 + ...o_detect_markdown_links_to_wiki_pages.mdwn | 1 + doc/todo/html.mdwn | 6 + doc/todo/htmlvalidation.mdwn | 47 + doc/todo/htpasswd_mirror_of_the_userdb.mdwn | 29 + doc/todo/http_bl_support.mdwn | 67 + doc/todo/httpauth_example.mdwn | 8 + doc/todo/httpauth_example/discussion.mdwn | 1 + ...auth_feature_parity_with_passwordauth.mdwn | 28 + doc/todo/hyphenation.mdwn | 32 + doc/todo/ikibot.mdwn | 9 + ...ised_wikis_documentation_and_graphics.mdwn | 14 + doc/todo/improve_globlists.mdwn | 8 + doc/todo/improved_mediawiki_support.mdwn | 9 + doc/todo/improved_parentlinks_styling.mdwn | 9 + doc/todo/inband_acl_data.mdwn | 75 + doc/todo/index.html_allowed.mdwn | 126 + .../inline:_numerical_ordering_by_title.mdwn | 254 + ...e_directive_should_support_pagination.mdwn | 8 + ...ion_for_pagespec-specific_show__61__N.mdwn | 3 + ...plugin:_ability_to_override_feed_name.mdwn | 29 + ...ne_plugin:_hide_feed_buttons_if_empty.mdwn | 7 + ...plugin:_specifying_ordered_page_names.mdwn | 19 + doc/todo/inline_postform_autotitles.mdwn | 63 + doc/todo/inline_raw_files.mdwn | 115 + doc/todo/inlines_inheriting_links.mdwn | 39 + ...Iceweasel_feed_subscription_mechanism.mdwn | 13 + doc/todo/interactive_todo_lists.mdwn | 49 + .../internal_definition_list_support.mdwn | 54 + doc/todo/l10n.mdwn | 84 + ...nguage_definition_for_the_meta_plugin.mdwn | 118 + doc/todo/latex.mdwn | 244 + doc/todo/latex/discussion.mdwn | 6 + .../let_inline_plugin_use_pagetemplates.mdwn | 5 + ..._markup_formats_available_for_editing.mdwn | 8 + doc/todo/link_map.mdwn | 6 + ...link_plugin_perhaps_too_general__63__.mdwn | 25 + doc/todo/linkbase.mdwn | 16 + .../linkify_and_preprocessor_ordering.mdwn | 24 + doc/todo/linktitle.mdwn | 19 + doc/todo/lists.mdwn | 3 + doc/todo/location_of_external_plugins.mdwn | 24 + doc/todo/location_of_ikiwiki-w3m.cgi.mdwn | 3 + doc/todo/logo.mdwn | 4 + doc/todo/lucene_search_engine.mdwn | 1 + doc/todo/mailnotification.mdwn | 59 + doc/todo/mailnotification/discussion.mdwn | 14 + ...ml-parser_use_encode_entities_numeric.mdwn | 19 + ...k_target_search_all_paths_as_fallback.mdwn | 27 + doc/todo/manpages.mdwn | 7 + ...entify__47__filter_on_trivial_changes.mdwn | 11 + .../matching_different_kinds_of_links.mdwn | 196 + doc/todo/mbox.mdwn | 18 + doc/todo/mdwn_itex.mdwn | 22 + doc/todo/mdwn_preview.mdwn | 339 + doc/todo/mdwn_preview/discussion.mdwn | 1 + doc/todo/mercurial.mdwn | 129 + doc/todo/mercurial/discussion.mdwn | 9 + doc/todo/meta_rcsid.mdwn | 51 + doc/todo/metadata.mdwn | 19 + ...documentation_for_recentchanges_feeds.mdwn | 28 + ...list_with_per-mirror_usedirs_settings.mdwn | 103 + doc/todo/missingparents.pm.mdwn | 267 + doc/todo/modify_page_filename_in_plugin.mdwn | 35 + doc/todo/monochrome_theme.mdwn | 48 + .../more_class__61____34____34___for_css.mdwn | 83 + .../more_customisable_titlepage_function.mdwn | 42 + doc/todo/more_flexible_inline_postform.mdwn | 23 + doc/todo/mtime.mdwn | 16 + doc/todo/multi-thread_ikiwiki.mdwn | 89 + doc/todo/multiple_output_formats.mdwn | 17 + doc/todo/multiple_repository_support.mdwn | 15 + doc/todo/multiple_simultaneous_rcs.mdwn | 26 + .../multiple_simultaneous_rcs/discussion.mdwn | 15 + doc/todo/multiple_template_directories.mdwn | 73 + doc/todo/multiple_templates.mdwn | 13 + doc/todo/natural_sorting.mdwn | 21 + doc/todo/need_global_renamepage_hook.mdwn | 115 + doc/todo/nested_preprocessor_directives.mdwn | 69 + doc/todo/online_configuration.mdwn | 28 + doc/todo/openid_enable_cache.mdwn | 4 + doc/todo/openid_user_filtering.mdwn | 13 + doc/todo/optimisation_via_git_log.mdwn | 27 + doc/todo/optimisations.mdwn | 15 + doc/todo/optimize_simple_dependencies.mdwn | 95 + ..._to_send_only_the_diff_in_notifyemail.mdwn | 11 + doc/todo/optional_underlaydir_prefix.mdwn | 46 + doc/todo/org_mode.mdwn | 36 + doc/todo/org_mode/Discussion.mdwn | 7 + ...95__optimisations__95__and__95__fixes.mdwn | 27 + doc/todo/osm_arbitrary_layers.mdwn | 43 + doc/todo/osm_plugin_GeoJSON_popup_patch.mdwn | 6 + doc/todo/osm_plugin_icon_patch.mdwn | 6 + doc/todo/outbound_proxy.mdwn | 57 + ...verriding_displayed_modification_time.mdwn | 27 + doc/todo/page_edit_disable.mdwn | 53 + doc/todo/pagedeletion.mdwn | 3 + doc/todo/pagedown_plugin.mdwn | 5 + doc/todo/pagedown_plugin/discussion.mdwn | 146 + doc/todo/pageindexes.mdwn | 5 + ..._can_result_in_excessive_dependencies.mdwn | 41 + doc/todo/pagespec_aliases.mdwn | 169 + doc/todo/pagespec_aliases/discussion.mdwn | 13 + doc/todo/pagespec_expansions.mdwn | 151 + doc/todo/pagespec_relative_to_a_target.mdwn | 101 + ...agespec_to_disable_ikiwiki_directives.mdwn | 5 + .../pagestats_among_a_subset_of_pages.mdwn | 28 + doc/todo/pal_plugin.mdwn | 9 + doc/todo/parse_debian_packages.mdwn | 70 + .../passwordauth:_sendmail_interface.mdwn | 65 + doc/todo/paste_plugin.mdwn | 36 + doc/todo/pastebin.mdwn | 11 + doc/todo/pdf_output.mdwn | 22 + doc/todo/pdfshare_plugin.mdwn | 1 + doc/todo/pedigree_plugin.mdwn | 194 + doc/todo/per-page_comment_control.mdwn | 31 + doc/todo/per_page_ACLs.mdwn | 18 + ...ical_name_for_equivalent_of_SQL_limit.mdwn | 44 + doc/todo/pingback_support.mdwn | 41 + doc/todo/please_add_some_table_styles.mdwn | 8 + doc/todo/pluggablerenderers.mdwn | 3 + doc/todo/plugin.mdwn | 118 + doc/todo/plugin_data_storage.mdwn | 94 + doc/todo/plugin_dependency_calulation.mdwn | 24 + ...lang_name_and_code_template_variables.mdwn | 7 + ...:_avoid_rebuilding_to_fix_meta_titles.mdwn | 60 + doc/todo/po:_better_documentation.mdwn | 3 + doc/todo/po:_better_links.mdwn | 12 + .../po:_better_translation_interface.mdwn | 7 + ...remove_po_files_when_disabling_plugin.mdwn | 19 + doc/todo/po:_rethink_pagespecs.mdwn | 40 + doc/todo/po:_should_cleanup_.pot_files.mdwn | 8 + doc/todo/po:_transifex_integration.mdwn | 13 + doc/todo/po:_translation_of_directives.mdwn | 8 + doc/todo/po_needstranslation_pagespec.mdwn | 12 + doc/todo/polltrails.mdwn | 3 + ...cessor_directive_for_proposed_changes.mdwn | 60 + ...tty-print_OpenIDs_even_if_not_enabled.mdwn | 29 + doc/todo/preview_changes.mdwn | 14 + .../preview_changes_before_git_commit.mdwn | 17 + doc/todo/progressbar_plugin.mdwn | 132 + doc/todo/provide_a_mailing_list.mdwn | 40 + ...provide_inline_diffs_in_recentchanges.mdwn | 27 + doc/todo/provide_sha1_for_git_diffurl.mdwn | 26 + doc/todo/publishing_in_the_future.mdwn | 135 + doc/todo/quieten-bzr.mdwn | 28 + doc/todo/rcs.mdwn | 25 + ...al_backend__44___based_on_Git_backend.mdwn | 40 + ...al_backend__44___based_on_Git_backend.mdwn | 157 + doc/todo/rcs_updates_needed.mdwn | 10 + doc/todo/recentchanges.mdwn | 144 + doc/todo/recentchanges_feed_with_comment.mdwn | 5 + doc/todo/recentchanges_path.mdwn | 9 + ...arkdown-discount_instead_of_depending.mdwn | 25 + doc/todo/redirect.mdwn | 53 + .../redirect_automatically_after_rename.mdwn | 10 + doc/todo/refreshing_recentchanges_page.mdwn | 20 + .../rel__61__nofollow_on_external_links.mdwn | 4 + doc/todo/rel_attribute_for_links.mdwn | 19 + doc/todo/relative_pagespec_deficiency.mdwn | 8 + doc/todo/remove_basewiki_redir_pages.mdwn | 4 + ..._HTML::Template_with_Template_Toolkit.mdwn | 115 + doc/todo/require_CAPTCHA_to_edit.mdwn | 327 + doc/todo/review_mechanism.mdwn | 35 + doc/todo/rewrite_ikiwiki_in_haskell.mdwn | 65 + .../discussion.mdwn | 61 + doc/todo/rss_title_description.mdwn | 35 + doc/todo/rst_plugin_python_rewrite.mdwn | 7 + .../salmon_protocol_for_comment_sharing.mdwn | 21 + doc/todo/search.mdwn | 5 + doc/todo/search_terms.mdwn | 7 + doc/todo/section-numbering.mdwn | 7 + doc/todo/selective_more_directive.mdwn | 28 + ...only_one_mail_per_page_in_notifyemail.mdwn | 7 + doc/todo/shortcut_link_text.mdwn | 19 + doc/todo/shortcut_optional_parameters.mdwn | 46 + .../shortcut_with_different_link_text.mdwn | 67 + ...with_no_url_parameter__44___only_desc.mdwn | 23 + doc/todo/should_optimise_pagespecs.mdwn | 313 + ...d_encoding_for_utf_chars_in_filenames.mdwn | 100 + doc/todo/sigs.mdwn | 25 + doc/todo/sigs/discussion.mdwn | 1 + ...sing_or_regex_in_template_or_shortcut.mdwn | 32 + doc/todo/skip_option_for_inline_plugin.mdwn | 8 + doc/todo/smarter_sorting.mdwn | 141 + ...rk_in_PreprocessorDirective_arguments.mdwn | 18 + doc/todo/softlinks.mdwn | 14 + ...arameter_for_map_plugin_and_directive.mdwn | 53 + .../incomplete_patch.pl.pl | 77 + .../python_algorithms.py | 86 + doc/todo/sortable_tables.mdwn | 3 + doc/todo/sortbylastcomment_plugin.mdwn | 13 + doc/todo/sorting_by_path.mdwn | 18 + doc/todo/source_link.mdwn | 135 + doc/todo/spell_check_plug-in.mdwn | 12 + doc/todo/strftime.mdwn | 4 + doc/todo/structured_page_data.mdwn | 633 + doc/todo/structured_page_data/discussion.mdwn | 1 + ...sheet_suggestion_for_verbatim_content.mdwn | 33 + doc/todo/submodule_support.mdwn | 15 + doc/todo/support_creole_markup.mdwn | 18 + doc/todo/support_dicts_in_setup.mdwn | 26 + doc/todo/support_for_SDF_documents.mdwn | 8 + ...or_plugins_written_in_other_languages.mdwn | 56 + doc/todo/support_includes_in_setup_files.mdwn | 10 + ...support_link__40__.__41___in_pagespec.mdwn | 21 + doc/todo/support_linking_to_cgit.mdwn | 45 + doc/todo/support_multi-row_table_headers.mdwn | 79 + doc/todo/support_multiple_perl_libraries.mdwn | 11 + ...pporting_comments_via_disussion_pages.mdwn | 222 + doc/todo/svg.mdwn | 77 + doc/todo/syntax_highlighting.mdwn | 120 + doc/todo/syntax_highlighting/discussion.mdwn | 28 + doc/todo/syslog_should_show_wiki_name.mdwn | 8 + doc/todo/table_with_header_column.mdwn | 7 + doc/todo/tag_pagespec_function.mdwn | 41 + doc/todo/tagging_with_a_publication_date.mdwn | 77 + doc/todo/tags.mdwn | 12 + doc/todo/target_filter_for_brokenlinks.mdwn | 9 + doc/todo/terminalclient.mdwn | 10 + doc/todo/test_coverage.mdwn | 24 + .../themes_should_ship_with_templates.mdwn | 19 + .../tidy_git__39__s_ctime_debug_output.mdwn | 15 + doc/todo/tla.mdwn | 7 + doc/todo/tmplvars_plugin.mdwn | 75 + doc/todo/tmplvars_plugin/discussion.mdwn | 1 + doc/todo/toc-with-human-readable-anchors.mdwn | 7 + ...___40__opposite_of_levels__61____41__.mdwn | 48 + doc/todo/toc_plugin_to_skip_one_level.mdwn | 23 + doc/todo/toggle_initial_state.mdwn | 6 + doc/todo/toplevel_index.mdwn | 37 + doc/todo/tracking_bugs_with_dependencies.mdwn | 680 + doc/todo/transient_pages.mdwn | 318 + doc/todo/translation_links.mdwn | 46 + ...edittemplate_verbosity_off_by_default.mdwn | 34 + doc/todo/two-way_convert_of_wikis.mdwn | 18 + doc/todo/typography_plugin_configuration.mdwn | 6 + .../unaccent_url_instead_of_encoding.mdwn | 24 + doc/todo/underlay.mdwn | 13 + ...emporary_file__47__directory_handling.mdwn | 19 + doc/todo/untrusted_git_push_hooks.mdwn | 12 + doc/todo/upgradehooks.mdwn | 8 + doc/todo/upload__95__figure.mdwn | 22 + .../use_secure_cookies_for_ssl_logins.mdwn | 36 + .../use_templates_for_the_img_plugin.mdwn | 29 + ..._95__redir_proposed_additional_module.mdwn | 8 + ...er-defined_templates_outside_the_wiki.mdwn | 10 + ...r_mechanism_like_etc_ikiwiki_wikilist.mdwn | 3 + doc/todo/userdir_links.mdwn | 5 + doc/todo/utf8.mdwn | 18 + doc/todo/vCard_rendering.mdwn | 100 + ...res_for_values__41___in_ikiwiki.setup.mdwn | 272 + ...r_https_in_urls_to_allow_serving_both.mdwn | 376 + doc/todo/wanted_pages_plugin.mdwn | 3 + doc/todo/wdiffs_in_recentchanges.mdwn | 1 + doc/todo/web-based_image_editing.mdwn | 3 + doc/todo/web_gui_for_managing_tags.mdwn | 12 + doc/todo/web_reversion.mdwn | 73 + ...up_should_link_to_plugin_descriptions.mdwn | 3 + ...formatted_comments_with_syntax_plugin.mdwn | 9 + doc/todo/wikilink_titles.mdwn | 4 + doc/todo/wikilinkfeatures.mdwn | 4 + doc/todo/wikitrails.mdwn | 51 + doc/todo/wikitrails/discussion.mdwn | 84 + doc/todo/wikiwyg.mdwn | 71 + doc/todo/wikiwyg/discussion.mdwn | 181 + doc/todo/wmd_editor_live_preview.mdwn | 11 + doc/todo/wrapperuser.mdwn | 7 + ...same_lang_when_indexing_and_searching.mdwn | 72 + doc/translation.mdwn | 46 + doc/translation/discussion.mdwn | 121 + doc/usage.mdwn | 389 + doc/usage/discussion.mdwn | 1 + doc/users.mdwn | 11 + doc/users/BerndZeimetz.mdwn | 8 + doc/users/Christine_Spang.mdwn | 1 + doc/users/DamianSmall.mdwn | 1 + doc/users/Daniel_Andersson.mdwn | 3 + doc/users/DavidBremner.mdwn | 1 + doc/users/David_Riebenbauer.mdwn | 8 + doc/users/Edward_Betts.mdwn | 4 + doc/users/Erkan_Yilmaz.mdwn | 2 + doc/users/Gianpaolo_Macario.mdwn | 14 + doc/users/GiuseppeBilotta.mdwn | 6 + doc/users/HenrikBrixAndersen.mdwn | 3 + doc/users/Jamie.mdwn | 1 + doc/users/JeremieKoenig.mdwn | 3 + doc/users/Jimmy_Tang.mdwn | 1 + doc/users/JoshBBall.mdwn | 3 + doc/users/Kai_Hendry.mdwn | 5 + doc/users/KarlMW.mdwn | 3 + doc/users/KarlMW/discussion.mdwn | 27 + doc/users/KathrynAndersen.mdwn | 8 + doc/users/KathrynAndersen/discussion.mdwn | 20 + doc/users/Larry_Clapp.mdwn | 3 + doc/users/LucaCapello.mdwn | 5 + doc/users/MatthiasIhrke.mdwn | 4 + doc/users/Mick_Pollard.mdwn | 1 + doc/users/NeilSmithline.mdwn | 1 + doc/users/NicolasLimare.mdwn | 1 + doc/users/Oblomov.mdwn | 1 + doc/users/Olea.mdwn | 4 + doc/users/OscarMorante.mdwn | 3 + doc/users/Perry.mdwn | 1 + doc/users/Ramsey.mdwn | 3 + doc/users/Remy.mdwn | 1 + doc/users/RickOwens.mdwn | 1 + doc/users/Simon_Michael.mdwn | 8 + doc/users/Stefano_Zacchiroli.mdwn | 1 + doc/users/StevenBlack.mdwn | 5 + doc/users/TaylorKillian.mdwn | 9 + doc/users/TaylorKillian/discussion.mdwn | 5 + doc/users/The_TOVA_Company.mdwn | 32 + doc/users/TimBosse.mdwn | 1 + doc/users/Tim_Lavoie.mdwn | 1 + doc/users/Will.mdwn | 28 + doc/users/acathur.mdwn | 3 + doc/users/acodispo.mdwn | 2 + doc/users/adamshand.mdwn | 7 + doc/users/ajt.mdwn | 20 + doc/users/aland.mdwn | 1 + doc/users/alexander.mdwn | 1 + doc/users/alexandredupas.mdwn | 7 + doc/users/anarcat.mdwn | 31 + doc/users/anarcat.wiki | 1 + doc/users/arpitjain.mdwn | 7 + doc/users/bartmassey.mdwn | 5 + doc/users/bbb.mdwn | 5 + doc/users/blipvert.mdwn | 1 + doc/users/bstpierre.mdwn | 1 + doc/users/cbaines.mdwn | 4 + doc/users/cfm.mdwn | 1 + doc/users/chris.mdwn | 7 + doc/users/chrismgray.mdwn | 4 + doc/users/chrysn.mdwn | 12 + doc/users/chrysn/interests.mdwn | 35 + doc/users/cord.mdwn | 1 + doc/users/cstamas.mdwn | 4 + doc/users/dark.mdwn | 3 + doc/users/dato.mdwn | 3 + doc/users/dirk.mdwn | 1 + doc/users/dom.mdwn | 3 + doc/users/donmarti.mdwn | 2 + doc/users/emptty.mdwn | 2 + doc/users/ericdrechsel.mdwn | 1 + doc/users/fil.mdwn | 1 + doc/users/fmarier.mdwn | 6 + doc/users/fr33domlover.mdwn | 10 + doc/users/harishcm.mdwn | 1 + doc/users/harningt.mdwn | 11 + doc/users/hb.mdwn | 11 + doc/users/hb/discussion.mdwn | 6 + doc/users/hendry.mdwn | 1 + doc/users/holger.mdwn | 3 + doc/users/intrigeri.mdwn | 4 + doc/users/iustin.mdwn | 1 + doc/users/ivan_shmakov.mdwn | 67 + doc/users/jasonblevins.mdwn | 89 + doc/users/jasonriedy.mdwn | 1 + doc/users/jaywalk.mdwn | 5 + doc/users/jcorneli.mdwn | 3 + doc/users/jeanprivat.mdwn | 1 + doc/users/jelmer.mdwn | 1 + doc/users/jeremyreed.mdwn | 3 + doc/users/jerojasro.mdwn | 3 + doc/users/jmtd.mdwn | 1 + doc/users/joey.mdwn | 8 + doc/users/jogo.mdwn | 5 + doc/users/jon.mdwn | 65 + doc/users/jonassmedegaard.mdwn | 5 + doc/users/josephturian.mdwn | 10 + doc/users/joshtriplett.mdwn | 16 + doc/users/joshtriplett/discussion.mdwn | 68 + doc/users/jrblevin.mdwn | 1 + doc/users/justint.mdwn | 1 + doc/users/jwalzer.mdwn | 3 + doc/users/kjs.mdwn | 11 + doc/users/kyle.mdwn | 2 + doc/users/madduck.mdwn | 9 + doc/users/marcelomagallon.mdwn | 3 + doc/users/mathdesc.mdwn | 190 + doc/users/mhameed.mdwn | 1 + doc/users/michaelrasmussen.wiki | 1 + doc/users/neale.mdwn | 10 + doc/users/nil.mdwn | 8 + doc/users/nolan.mdwn | 1 + doc/users/patrickwinnertz.mdwn | 10 + doc/users/pdurbin.mdwn | 1 + doc/users/pelle.mdwn | 1 + doc/users/perolofsson.mdwn | 7 + doc/users/peteg.mdwn | 7 + doc/users/peter_woodman.mdwn | 1 + doc/users/ptecza.mdwn | 21 + doc/users/rubykat.mdwn | 1 + doc/users/sabr.mdwn | 32 + doc/users/sabr/sub1.mdwn | 1 + doc/users/sabr/sub2.mdwn | 1 + doc/users/schmonz-web-ikiwiki.mdwn | 1 + doc/users/schmonz.mdwn | 32 + doc/users/seanh.mdwn | 1 + doc/users/simonraven.mdwn | 7 + doc/users/smcv.mdwn | 10 + doc/users/smcv/gallery.mdwn | 4 + doc/users/smcv/gallery/discussion.mdwn | 18 + doc/users/smcv/ready.mdwn | 10 + doc/users/solofo.mdwn | 1 + doc/users/spalax.mdwn | 21 + doc/users/sphynkx.mdwn | 1 + doc/users/ssm.mdwn | 3 + doc/users/sunny256.mdwn | 15 + doc/users/svend.mdwn | 4 + doc/users/tbm.mdwn | 3 + doc/users/tjgolubi.mdwn | 3 + doc/users/tschwinge.mdwn | 151 + doc/users/ttw.mdwn | 1 + doc/users/tupyakov_vladimir.mdwn | 1 + doc/users/tychoish.mdwn | 10 + doc/users/ulrik.mdwn | 3 + doc/users/undx.mdwn | 7 + doc/users/victormoral.mdwn | 6 + doc/users/weakish.mdwn | 3 + doc/users/weakishjiang.mdwn | 4 + doc/users/wentasah.mdwn | 9 + doc/users/wiebel.mdwn | 5 + doc/users/wtk.mdwn | 6 + doc/users/xma/discussion.mdwn | 18 + doc/users/xtaran.mdwn | 5 + doc/users/yds.mdwn | 1 + doc/w3mmode.mdwn | 11 + doc/w3mmode/ikiwiki.setup | 31 + doc/whyikiwiki.mdwn | 15 + doc/wikiicons/diff.png | Bin 0 -> 219 bytes doc/wikiicons/openidlogin-bg.gif | Bin 0 -> 336 bytes doc/wikiicons/revert.png | Bin 0 -> 397 bytes doc/wikiicons/search-bg.gif | Bin 0 -> 74 bytes doc/wishlist.mdwn | 6 + doc/wishlist/watched_pages.mdwn | 1 + docwiki.setup | 36 + gitremotes | 26 + icons/aol.svg | 101 + icons/livejournal.svg | 108 + icons/verisign.svg | 112 + ikiwiki-calendar.in | 66 + ikiwiki-makerepo | 175 + ikiwiki-mass-rebuild | 90 + ikiwiki-transition.in | 349 + ikiwiki-update-wikilist | 65 + ikiwiki-w3m.cgi | 15 + ikiwiki.in | 229 + ikiwiki.spec | 129 + mdwn2man | 43 + plugins/.gitignore | 1 + plugins/externaldemo | 144 + plugins/proxy.py | 339 + plugins/pythondemo | 382 + plugins/rst | 86 + pm_filter | 33 + po/.gitignore | 1 + po/Makefile | 97 + po/bg.po | 1473 ++ po/cs.po | 1459 ++ po/da.po | 1381 ++ po/de.po | 1442 ++ po/es.po | 1463 ++ po/fr.po | 1452 ++ po/gu.po | 1457 ++ po/ikiwiki.pot | 1347 ++ po/it.po | 1429 ++ po/pl.po | 1484 ++ po/po2wiki | 44 + po/sv.po | 1462 ++ po/tr.po | 1349 ++ po/underlay.setup | 32 + po/underlays/basewiki/ikiwiki.cs.po | 74 + po/underlays/basewiki/ikiwiki.da.po | 79 + po/underlays/basewiki/ikiwiki.de.po | 73 + po/underlays/basewiki/ikiwiki.es.po | 75 + po/underlays/basewiki/ikiwiki.fr.po | 73 + po/underlays/basewiki/ikiwiki/directive.cs.po | 130 + po/underlays/basewiki/ikiwiki/directive.da.po | 136 + po/underlays/basewiki/ikiwiki/directive.de.po | 137 + po/underlays/basewiki/ikiwiki/directive.es.po | 133 + po/underlays/basewiki/ikiwiki/directive.fr.po | 132 + .../basewiki/ikiwiki/formatting.cs.po | 288 + .../basewiki/ikiwiki/formatting.da.po | 299 + .../basewiki/ikiwiki/formatting.de.po | 299 + .../basewiki/ikiwiki/formatting.es.po | 295 + .../basewiki/ikiwiki/formatting.fr.po | 291 + po/underlays/basewiki/ikiwiki/markdown.cs.po | 48 + po/underlays/basewiki/ikiwiki/markdown.da.po | 55 + po/underlays/basewiki/ikiwiki/markdown.de.po | 52 + po/underlays/basewiki/ikiwiki/markdown.es.po | 50 + po/underlays/basewiki/ikiwiki/markdown.fr.po | 49 + po/underlays/basewiki/ikiwiki/openid.cs.po | 121 + po/underlays/basewiki/ikiwiki/openid.da.po | 95 + po/underlays/basewiki/ikiwiki/openid.de.po | 118 + po/underlays/basewiki/ikiwiki/openid.es.po | 123 + po/underlays/basewiki/ikiwiki/openid.fr.po | 122 + po/underlays/basewiki/ikiwiki/pagespec.cs.po | 278 + po/underlays/basewiki/ikiwiki/pagespec.da.po | 224 + po/underlays/basewiki/ikiwiki/pagespec.de.po | 279 + po/underlays/basewiki/ikiwiki/pagespec.es.po | 289 + po/underlays/basewiki/ikiwiki/pagespec.fr.po | 311 + .../ikiwiki/pagespec/attachment.cs.po | 120 + .../ikiwiki/pagespec/attachment.da.po | 123 + .../ikiwiki/pagespec/attachment.de.po | 124 + .../ikiwiki/pagespec/attachment.es.po | 127 + .../ikiwiki/pagespec/attachment.fr.po | 122 + .../basewiki/ikiwiki/pagespec/po.cs.po | 75 + .../basewiki/ikiwiki/pagespec/po.da.po | 84 + .../basewiki/ikiwiki/pagespec/po.de.po | 75 + .../basewiki/ikiwiki/pagespec/po.es.po | 77 + .../basewiki/ikiwiki/pagespec/po.fr.po | 75 + .../basewiki/ikiwiki/pagespec/sorting.de.po | 48 + po/underlays/basewiki/ikiwiki/searching.cs.po | 80 + po/underlays/basewiki/ikiwiki/searching.da.po | 91 + po/underlays/basewiki/ikiwiki/searching.de.po | 92 + po/underlays/basewiki/ikiwiki/searching.es.po | 84 + po/underlays/basewiki/ikiwiki/searching.fr.po | 87 + po/underlays/basewiki/ikiwiki/subpage.cs.po | 59 + po/underlays/basewiki/ikiwiki/subpage.da.po | 57 + po/underlays/basewiki/ikiwiki/subpage.de.po | 59 + po/underlays/basewiki/ikiwiki/subpage.es.po | 59 + po/underlays/basewiki/ikiwiki/subpage.fr.po | 52 + .../ikiwiki/subpage/linkingrules.cs.po | 100 + .../ikiwiki/subpage/linkingrules.da.po | 108 + .../ikiwiki/subpage/linkingrules.de.po | 109 + .../ikiwiki/subpage/linkingrules.es.po | 102 + .../ikiwiki/subpage/linkingrules.fr.po | 103 + po/underlays/basewiki/ikiwiki/wikilink.cs.po | 115 + po/underlays/basewiki/ikiwiki/wikilink.da.po | 96 + po/underlays/basewiki/ikiwiki/wikilink.de.po | 115 + po/underlays/basewiki/ikiwiki/wikilink.es.po | 118 + po/underlays/basewiki/ikiwiki/wikilink.fr.po | 112 + po/underlays/basewiki/index.cs.po | 27 + po/underlays/basewiki/index.da.po | 35 + po/underlays/basewiki/index.de.po | 29 + po/underlays/basewiki/index.es.po | 31 + po/underlays/basewiki/index.fr.po | 26 + po/underlays/basewiki/recentchanges.cs.po | 38 + po/underlays/basewiki/recentchanges.da.po | 44 + po/underlays/basewiki/recentchanges.de.po | 38 + po/underlays/basewiki/recentchanges.es.po | 40 + po/underlays/basewiki/recentchanges.fr.po | 37 + po/underlays/basewiki/sandbox.cs.po | 91 + po/underlays/basewiki/sandbox.da.po | 97 + po/underlays/basewiki/sandbox.de.po | 91 + po/underlays/basewiki/sandbox.es.po | 90 + po/underlays/basewiki/sandbox.fr.po | 88 + po/underlays/basewiki/shortcuts.cs.po | 269 + po/underlays/basewiki/shortcuts.da.po | 246 + po/underlays/basewiki/shortcuts.de.po | 287 + po/underlays/basewiki/shortcuts.es.po | 269 + po/underlays/basewiki/shortcuts.fr.po | 266 + po/underlays/basewiki/templates.cs.po | 339 + po/underlays/basewiki/templates.da.po | 254 + po/underlays/basewiki/templates.de.po | 346 + po/underlays/basewiki/templates.es.po | 345 + po/underlays/basewiki/templates.fr.po | 396 + po/underlays/basewiki/templates/note.cs.po | 55 + po/underlays/basewiki/templates/note.da.po | 48 + po/underlays/basewiki/templates/note.de.po | 53 + po/underlays/basewiki/templates/note.es.po | 56 + po/underlays/basewiki/templates/note.fr.po | 53 + po/underlays/basewiki/templates/popup.cs.po | 69 + po/underlays/basewiki/templates/popup.da.po | 57 + po/underlays/basewiki/templates/popup.de.po | 68 + po/underlays/basewiki/templates/popup.es.po | 71 + po/underlays/basewiki/templates/popup.fr.po | 64 + .../ikiwiki/directive/aggregate.da.po | 150 + .../ikiwiki/directive/aggregate.de.po | 189 + .../ikiwiki/directive/aggregate.fr.po | 177 + .../ikiwiki/directive/brokenlinks.da.po | 54 + .../ikiwiki/directive/brokenlinks.de.po | 57 + .../ikiwiki/directive/brokenlinks.fr.po | 51 + .../ikiwiki/directive/calendar.da.po | 150 + .../ikiwiki/directive/calendar.de.po | 205 + .../ikiwiki/directive/calendar.fr.po | 200 + .../directives/ikiwiki/directive/color.da.po | 81 + .../directives/ikiwiki/directive/color.de.po | 97 + .../directives/ikiwiki/directive/color.fr.po | 74 + .../ikiwiki/directive/comment.da.po | 123 + .../ikiwiki/directive/comment.de.po | 138 + .../ikiwiki/directive/comment.fr.po | 134 + .../directives/ikiwiki/directive/copy.da.po | 31 + .../directives/ikiwiki/directive/copy.de.po | 25 + .../directives/ikiwiki/directive/copy.fr.po | 24 + .../directives/ikiwiki/directive/cut.da.po | 31 + .../directives/ikiwiki/directive/cut.de.po | 25 + .../directives/ikiwiki/directive/cut.fr.po | 25 + .../ikiwiki/directive/cutpaste.da.po | 135 + .../ikiwiki/directive/cutpaste.de.po | 153 + .../ikiwiki/directive/cutpaste.fr.po | 139 + .../directives/ikiwiki/directive/date.de.po | 61 + .../ikiwiki/directive/edittemplate.da.po | 91 + .../ikiwiki/directive/edittemplate.de.po | 98 + .../ikiwiki/directive/edittemplate.fr.po | 109 + .../directives/ikiwiki/directive/format.da.po | 86 + .../directives/ikiwiki/directive/format.de.po | 93 + .../directives/ikiwiki/directive/format.fr.po | 90 + .../ikiwiki/directive/fortune.da.po | 43 + .../ikiwiki/directive/fortune.de.po | 42 + .../ikiwiki/directive/fortune.fr.po | 36 + .../directives/ikiwiki/directive/graph.da.po | 77 + .../directives/ikiwiki/directive/graph.de.po | 88 + .../directives/ikiwiki/directive/graph.fr.po | 70 + .../directives/ikiwiki/directive/haiku.da.po | 56 + .../directives/ikiwiki/directive/haiku.de.po | 60 + .../directives/ikiwiki/directive/haiku.fr.po | 49 + .../directives/ikiwiki/directive/if.da.po | 132 + .../directives/ikiwiki/directive/if.de.po | 145 + .../directives/ikiwiki/directive/if.fr.po | 138 + .../directives/ikiwiki/directive/img.da.po | 99 + .../directives/ikiwiki/directive/img.de.po | 124 + .../directives/ikiwiki/directive/img.fr.po | 123 + .../directives/ikiwiki/directive/inline.da.po | 247 + .../directives/ikiwiki/directive/inline.de.po | 385 + .../directives/ikiwiki/directive/inline.fr.po | 398 + .../ikiwiki/directive/linkmap.da.po | 83 + .../ikiwiki/directive/linkmap.de.po | 99 + .../ikiwiki/directive/linkmap.fr.po | 93 + .../ikiwiki/directive/listdirectives.da.po | 64 + .../ikiwiki/directive/listdirectives.de.po | 72 + .../ikiwiki/directive/listdirectives.fr.po | 69 + .../directives/ikiwiki/directive/map.da.po | 71 + .../directives/ikiwiki/directive/map.de.po | 77 + .../directives/ikiwiki/directive/map.fr.po | 77 + .../directives/ikiwiki/directive/meta.da.po | 448 + .../directives/ikiwiki/directive/meta.de.po | 470 + .../directives/ikiwiki/directive/meta.fr.po | 447 + .../directives/ikiwiki/directive/more.da.po | 67 + .../directives/ikiwiki/directive/more.de.po | 63 + .../directives/ikiwiki/directive/more.fr.po | 63 + .../ikiwiki/directive/orphans.da.po | 56 + .../ikiwiki/directive/orphans.de.po | 60 + .../ikiwiki/directive/orphans.fr.po | 49 + .../ikiwiki/directive/pagecount.da.po | 47 + .../ikiwiki/directive/pagecount.de.po | 48 + .../ikiwiki/directive/pagecount.fr.po | 40 + .../ikiwiki/directive/pagestats.da.po | 113 + .../ikiwiki/directive/pagestats.de.po | 117 + .../ikiwiki/directive/pagestats.fr.po | 120 + .../ikiwiki/directive/pagetemplate.da.po | 51 + .../ikiwiki/directive/pagetemplate.de.po | 66 + .../ikiwiki/directive/pagetemplate.fr.po | 66 + .../directives/ikiwiki/directive/paste.da.po | 31 + .../directives/ikiwiki/directive/paste.de.po | 25 + .../directives/ikiwiki/directive/paste.fr.po | 26 + .../directives/ikiwiki/directive/ping.da.po | 62 + .../directives/ikiwiki/directive/ping.de.po | 69 + .../directives/ikiwiki/directive/ping.fr.po | 55 + .../directives/ikiwiki/directive/poll.da.po | 77 + .../directives/ikiwiki/directive/poll.de.po | 87 + .../directives/ikiwiki/directive/poll.fr.po | 70 + .../ikiwiki/directive/polygen.da.po | 49 + .../ikiwiki/directive/polygen.de.po | 50 + .../ikiwiki/directive/polygen.fr.po | 42 + .../ikiwiki/directive/postsparkline.da.po | 128 + .../ikiwiki/directive/postsparkline.de.po | 149 + .../ikiwiki/directive/postsparkline.fr.po | 136 + .../ikiwiki/directive/progress.da.po | 59 + .../ikiwiki/directive/progress.de.po | 68 + .../ikiwiki/directive/progress.fr.po | 52 + .../ikiwiki/directive/shortcut.da.po | 44 + .../ikiwiki/directive/shortcut.de.po | 46 + .../ikiwiki/directive/shortcut.fr.po | 37 + .../ikiwiki/directive/sparkline.da.po | 145 + .../ikiwiki/directive/sparkline.de.po | 178 + .../ikiwiki/directive/sparkline.fr.po | 162 + .../directives/ikiwiki/directive/table.da.po | 135 + .../directives/ikiwiki/directive/table.de.po | 153 + .../directives/ikiwiki/directive/table.fr.po | 149 + .../directives/ikiwiki/directive/tag.da.po | 99 + .../directives/ikiwiki/directive/tag.de.po | 121 + .../directives/ikiwiki/directive/tag.fr.po | 118 + .../ikiwiki/directive/taglink.da.po | 31 + .../ikiwiki/directive/taglink.de.po | 25 + .../ikiwiki/directive/taglink.fr.po | 24 + .../ikiwiki/directive/template.da.po | 198 + .../ikiwiki/directive/template.de.po | 204 + .../ikiwiki/directive/template.fr.po | 239 + .../ikiwiki/directive/testpagespec.da.po | 76 + .../ikiwiki/directive/testpagespec.de.po | 84 + .../ikiwiki/directive/testpagespec.fr.po | 69 + .../directives/ikiwiki/directive/teximg.da.po | 77 + .../directives/ikiwiki/directive/teximg.de.po | 84 + .../directives/ikiwiki/directive/teximg.fr.po | 72 + .../directives/ikiwiki/directive/toc.da.po | 79 + .../directives/ikiwiki/directive/toc.de.po | 85 + .../directives/ikiwiki/directive/toc.fr.po | 76 + .../directives/ikiwiki/directive/toggle.da.po | 96 + .../directives/ikiwiki/directive/toggle.de.po | 113 + .../directives/ikiwiki/directive/toggle.fr.po | 108 + .../ikiwiki/directive/toggleable.da.po | 31 + .../ikiwiki/directive/toggleable.de.po | 25 + .../ikiwiki/directive/toggleable.fr.po | 24 + .../ikiwiki/directive/version.da.po | 51 + .../ikiwiki/directive/version.de.po | 50 + .../ikiwiki/directive/version.fr.po | 44 + po/underlays/smiley/smileys.da.po | 215 + po/underlays/smiley/smileys.de.po | 211 + po/underlays/smiley/smileys.fr.po | 209 + po/vi.po | 1460 ++ t/404.t | 44 + t/add_depends.t | 70 + t/autoindex-committed.t | 159 + t/autoindex.t | 172 + t/basename.t | 12 + t/basewiki_brokenlinks.t | 29 + t/basewiki_brokenlinks/index.mdwn | 1 + t/bazaar.t | 116 + t/beautify_urlpath.t | 17 + t/bestlink.t | 33 + t/calculate_changed_links.t | 58 + t/cmp_path.t | 48 + t/comments.t | 57 + t/conflicts.t | 131 + t/crazy-badass-perl-bug.t | 20 + t/cvs.t | 708 + t/dirname.t | 12 + t/file_pruned.t | 40 + t/find_src_files.t | 97 + t/git.t | 120 + t/html.t | 30 + t/htmlbalance.t | 23 + t/htmlize.t | 85 + t/img.t | 98 + t/img/redsquare.png | Bin 0 -> 84 bytes t/img/twopages.pdf | Bin 0 -> 2295 bytes t/index.t | 159 + t/inline.t | 68 + t/linkify.t | 112 + t/linkpage.t | 13 + t/map.t | 242 + t/mercurial.t | 75 + t/openiduser.t | 42 + t/pagename.t | 35 + t/pagespec_match.t | 147 + t/pagespec_match_list.t | 174 + t/pagespec_match_result.t | 84 + t/pagetitle.t | 13 + t/parentlinks.t | 81 + t/parentlinks/templates/parentlinks.tmpl | 4 + t/permalink.t | 14 + t/po.t | 250 + t/podcast.t | 233 + t/preprocess.t | 83 + t/prune.t | 23 + t/readfile.t | 12 + t/renamepage.t | 51 + t/rssurls.t | 37 + t/rst.t | 26 + t/svn.t | 78 + t/syntax.t | 20 + t/syslog.t | 18 + t/tag.t | 88 + t/template_syntax.t | 15 + t/templatebody.t | 123 + t/templates_documented.t | 14 + t/test1.mdwn | 2 + t/test2.mdwn | 5 + t/test3.mdwn | 1 + t/tinyblog/index.mdwn | 1 + t/tinyblog/post.mdwn | 1 + .../attempted_multiple_enclosures.mdwn | 4 + t/tinypodcast/fancy.mdwn | 1 + t/tinypodcast/piano.mp3 | Bin 0 -> 80991 bytes t/tinypodcast/pianopost.mdwn | 3 + t/tinypodcast/scroll.3gp | Bin 0 -> 21590 bytes t/tinypodcast/simple.mdwn | 1 + t/tinypodcast/simplepost.mdwn | 1 + t/tinypodcast/walter.ogg | Bin 0 -> 28714 bytes t/titlepage.t | 13 + t/trail.t | 292 + t/urlto.t | 51 + t/yesno.t | 23 + templates/aggregatepost.tmpl | 19 + templates/archivepage.tmpl | 19 + templates/atomitem.tmpl | 49 + templates/atompage.tmpl | 39 + templates/autoindex.tmpl | 1 + templates/autotag.tmpl | 4 + templates/blogpost.tmpl | 16 + templates/calendarmonth.tmpl | 5 + templates/calendaryear.tmpl | 1 + templates/change.tmpl | 57 + templates/comment.tmpl | 66 + templates/commentmoderation.tmpl | 32 + templates/editcomment.tmpl | 43 + templates/editconflict.tmpl | 7 + templates/editcreationconflict.tmpl | 9 + templates/editfailedsave.tmpl | 10 + templates/editpage.tmpl | 91 + templates/editpagegone.tmpl | 7 + templates/feedlink.tmpl | 8 + templates/googleform.tmpl | 8 + templates/inlinepage.tmpl | 78 + templates/microblog.tmpl | 22 + templates/notifyemail.tmpl | 9 + templates/openid-selector.tmpl | 43 + templates/page.tmpl | 225 + templates/passwordmail.tmpl | 15 + templates/pocreatepage.tmpl | 3 + templates/recentchanges.tmpl | 7 + templates/renamesummary.tmpl | 26 + templates/revert.tmpl | 21 + templates/rssitem.tmpl | 28 + templates/rsspage.tmpl | 16 + templates/searchform.tmpl | 6 + templates/searchquery.tmpl | 113 + templates/titlepage.tmpl | 7 + templates/trails.tmpl | 23 + themes/actiontabs/style.css | 149 + themes/blueview/background_darkness.png | Bin 0 -> 165 bytes themes/blueview/header_background.png | Bin 0 -> 53693 bytes themes/blueview/style.css | 281 + themes/goldtype/background_darkness.png | Bin 0 -> 165 bytes themes/goldtype/base.css | 1 + themes/goldtype/header_background.png | Bin 0 -> 196261 bytes themes/goldtype/style.css | 25 + themes/monochrome/gradient.png | Bin 0 -> 2466 bytes themes/monochrome/style.css | 57 + .../attachment/ikiwiki/images/pbar-ani.gif | Bin 0 -> 3323 bytes .../images/ui-bg_flat_0_aaaaaa_40x100.png | Bin 0 -> 180 bytes .../images/ui-bg_flat_75_ffffff_40x100.png | Bin 0 -> 178 bytes .../images/ui-bg_glass_55_fbf9ee_1x400.png | Bin 0 -> 120 bytes .../images/ui-bg_glass_65_ffffff_1x400.png | Bin 0 -> 105 bytes .../images/ui-bg_glass_75_dadada_1x400.png | Bin 0 -> 111 bytes .../images/ui-bg_glass_75_e6e6e6_1x400.png | Bin 0 -> 110 bytes .../images/ui-bg_glass_95_fef1ec_1x400.png | Bin 0 -> 119 bytes .../ui-bg_highlight-soft_75_cccccc_1x100.png | Bin 0 -> 101 bytes .../images/ui-icons_222222_256x240.png | Bin 0 -> 4369 bytes .../images/ui-icons_2e83ff_256x240.png | Bin 0 -> 4369 bytes .../images/ui-icons_454545_256x240.png | Bin 0 -> 4369 bytes .../images/ui-icons_888888_256x240.png | Bin 0 -> 4369 bytes .../images/ui-icons_cd0a0a_256x240.png | Bin 0 -> 4369 bytes underlays/attachment/ikiwiki/jquery-ui.css | 568 + underlays/attachment/ikiwiki/jquery-ui.js | 11729 ++++++++++++++++ .../attachment/ikiwiki/jquery-ui.min.css | 1 + underlays/attachment/ikiwiki/jquery-ui.min.js | 33 + .../ikiwiki/jquery.fileupload-ui.js | 357 + .../attachment/ikiwiki/jquery.fileupload.js | 720 + .../ikiwiki/jquery.iframe-transport.js | 133 + underlays/attachment/ikiwiki/jquery.tmpl.js | 486 + .../attachment/ikiwiki/jquery.tmpl.min.js | 1 + underlays/basewiki/favicon.ico | 1 + underlays/basewiki/ikiwiki.mdwn | 1 + underlays/basewiki/ikiwiki/directive.mdwn | 1 + underlays/basewiki/ikiwiki/formatting.mdwn | 1 + underlays/basewiki/ikiwiki/markdown.mdwn | 1 + underlays/basewiki/ikiwiki/openid.mdwn | 1 + underlays/basewiki/ikiwiki/pagespec.mdwn | 1 + .../basewiki/ikiwiki/pagespec/attachment.mdwn | 1 + underlays/basewiki/ikiwiki/pagespec/po.mdwn | 1 + .../basewiki/ikiwiki/pagespec/sorting.mdwn | 1 + underlays/basewiki/ikiwiki/searching.mdwn | 1 + underlays/basewiki/ikiwiki/subpage.mdwn | 1 + .../ikiwiki/subpage/linkingrules.mdwn | 1 + underlays/basewiki/ikiwiki/wikilink.mdwn | 1 + underlays/basewiki/index.mdwn | 1 + underlays/basewiki/local.css | 1 + underlays/basewiki/recentchanges.mdwn | 1 + underlays/basewiki/sandbox.mdwn | 1 + underlays/basewiki/shortcuts.mdwn | 1 + underlays/basewiki/style.css | 1 + underlays/basewiki/templates.mdwn | 1 + underlays/basewiki/templates/note.mdwn | 1 + underlays/basewiki/templates/popup.mdwn | 1 + underlays/basewiki/wikiicons | 1 + underlays/javascript/ikiwiki/ikiwiki.js | 54 + underlays/javascript/ikiwiki/relativedate.js | 75 + underlays/javascript/ikiwiki/toggle.js | 29 + underlays/jquery/ikiwiki/jquery.js | 8981 ++++++++++++ underlays/jquery/ikiwiki/jquery.min.js | 23 + .../openid-selector/ikiwiki/openid/aol.png | Bin 0 -> 460 bytes .../ikiwiki/openid/goa-account-flickr.png | Bin 0 -> 592 bytes .../ikiwiki/openid/goa-account-google.png | Bin 0 -> 825 bytes .../ikiwiki/openid/goa-account-yahoo.png | Bin 0 -> 741 bytes .../ikiwiki/openid/livejournal.png | Bin 0 -> 772 bytes .../ikiwiki/openid/openid-jquery.js | 260 + .../ikiwiki/openid/verisign.png | Bin 0 -> 714 bytes .../ikiwiki/openid/wordpress.png | Bin 0 -> 886 bytes underlays/osm/ikiwiki/images/osm.png | Bin 0 -> 2982 bytes underlays/osm/ikiwiki/osm.js | 166 + underlays/smiley/smileys | 1 + underlays/smiley/smileys.mdwn | 1 + wikilist | 12 + 3180 files changed, 207645 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 .perlcriticrc create mode 100644 Bundle/IkiWiki.pm create mode 100644 Bundle/IkiWiki/Extras.pm create mode 120000 CHANGELOG create mode 100644 IkiWiki.pm create mode 100644 IkiWiki/CGI.pm create mode 100644 IkiWiki/Plugin/404.pm create mode 100644 IkiWiki/Plugin/aggregate.pm create mode 100644 IkiWiki/Plugin/amazon_s3.pm create mode 100644 IkiWiki/Plugin/anonok.pm create mode 100644 IkiWiki/Plugin/attachment.pm create mode 100644 IkiWiki/Plugin/autoindex.pm create mode 100644 IkiWiki/Plugin/blogspam.pm create mode 100644 IkiWiki/Plugin/brokenlinks.pm create mode 100644 IkiWiki/Plugin/bzr.pm create mode 100644 IkiWiki/Plugin/calendar.pm create mode 100644 IkiWiki/Plugin/camelcase.pm create mode 100644 IkiWiki/Plugin/color.pm create mode 100644 IkiWiki/Plugin/comments.pm create mode 100644 IkiWiki/Plugin/conditional.pm create mode 100644 IkiWiki/Plugin/creole.pm create mode 100644 IkiWiki/Plugin/cutpaste.pm create mode 100644 IkiWiki/Plugin/cvs.pm create mode 100644 IkiWiki/Plugin/darcs.pm create mode 100644 IkiWiki/Plugin/date.pm create mode 100644 IkiWiki/Plugin/ddate.pm create mode 100644 IkiWiki/Plugin/editdiff.pm create mode 100644 IkiWiki/Plugin/editpage.pm create mode 100644 IkiWiki/Plugin/edittemplate.pm create mode 100644 IkiWiki/Plugin/embed.pm create mode 100644 IkiWiki/Plugin/external.pm create mode 100644 IkiWiki/Plugin/favicon.pm create mode 100644 IkiWiki/Plugin/filecheck.pm create mode 100644 IkiWiki/Plugin/flattr.pm create mode 100644 IkiWiki/Plugin/format.pm create mode 100644 IkiWiki/Plugin/fortune.pm create mode 100644 IkiWiki/Plugin/getsource.pm create mode 100644 IkiWiki/Plugin/git.pm create mode 100644 IkiWiki/Plugin/goodstuff.pm create mode 100644 IkiWiki/Plugin/google.pm create mode 100644 IkiWiki/Plugin/goto.pm create mode 100644 IkiWiki/Plugin/graphviz.pm create mode 100644 IkiWiki/Plugin/haiku.pm create mode 100644 IkiWiki/Plugin/headinganchors.pm create mode 100644 IkiWiki/Plugin/highlight.pm create mode 100644 IkiWiki/Plugin/hnb.pm create mode 100644 IkiWiki/Plugin/html.pm create mode 100644 IkiWiki/Plugin/htmlbalance.pm create mode 100644 IkiWiki/Plugin/htmlscrubber.pm create mode 100644 IkiWiki/Plugin/htmltidy.pm create mode 100644 IkiWiki/Plugin/httpauth.pm create mode 100644 IkiWiki/Plugin/img.pm create mode 100644 IkiWiki/Plugin/inline.pm create mode 100644 IkiWiki/Plugin/link.pm create mode 100644 IkiWiki/Plugin/linkmap.pm create mode 100644 IkiWiki/Plugin/listdirectives.pm create mode 100644 IkiWiki/Plugin/localstyle.pm create mode 100644 IkiWiki/Plugin/lockedit.pm create mode 100644 IkiWiki/Plugin/map.pm create mode 100644 IkiWiki/Plugin/mdwn.pm create mode 100644 IkiWiki/Plugin/mercurial.pm create mode 100644 IkiWiki/Plugin/meta.pm create mode 100644 IkiWiki/Plugin/mirrorlist.pm create mode 100644 IkiWiki/Plugin/moderatedcomments.pm create mode 100644 IkiWiki/Plugin/monotone.pm create mode 100644 IkiWiki/Plugin/more.pm create mode 100644 IkiWiki/Plugin/norcs.pm create mode 100644 IkiWiki/Plugin/notifyemail.pm create mode 100644 IkiWiki/Plugin/opendiscussion.pm create mode 100644 IkiWiki/Plugin/openid.pm create mode 100644 IkiWiki/Plugin/orphans.pm create mode 100644 IkiWiki/Plugin/osm.pm create mode 100644 IkiWiki/Plugin/otl.pm create mode 100644 IkiWiki/Plugin/pagecount.pm create mode 100644 IkiWiki/Plugin/pagestats.pm create mode 100644 IkiWiki/Plugin/pagetemplate.pm create mode 100644 IkiWiki/Plugin/parentlinks.pm create mode 100644 IkiWiki/Plugin/passwordauth.pm create mode 100644 IkiWiki/Plugin/pingee.pm create mode 100644 IkiWiki/Plugin/pinger.pm create mode 100644 IkiWiki/Plugin/po.pm create mode 100644 IkiWiki/Plugin/poll.pm create mode 100644 IkiWiki/Plugin/polygen.pm create mode 100644 IkiWiki/Plugin/postsparkline.pm create mode 100644 IkiWiki/Plugin/prettydate.pm create mode 100644 IkiWiki/Plugin/progress.pm create mode 100644 IkiWiki/Plugin/rawhtml.pm create mode 100644 IkiWiki/Plugin/recentchanges.pm create mode 100644 IkiWiki/Plugin/recentchangesdiff.pm create mode 100644 IkiWiki/Plugin/relativedate.pm create mode 100644 IkiWiki/Plugin/remove.pm create mode 100644 IkiWiki/Plugin/rename.pm create mode 100644 IkiWiki/Plugin/repolist.pm create mode 100644 IkiWiki/Plugin/rsync.pm create mode 100644 IkiWiki/Plugin/search.pm create mode 100644 IkiWiki/Plugin/shortcut.pm create mode 100644 IkiWiki/Plugin/sidebar.pm create mode 100644 IkiWiki/Plugin/signinedit.pm create mode 100644 IkiWiki/Plugin/skeleton.pm.example create mode 100644 IkiWiki/Plugin/smiley.pm create mode 100644 IkiWiki/Plugin/sortnaturally.pm create mode 100644 IkiWiki/Plugin/sparkline.pm create mode 100644 IkiWiki/Plugin/svn.pm create mode 100644 IkiWiki/Plugin/table.pm create mode 100644 IkiWiki/Plugin/tag.pm create mode 100644 IkiWiki/Plugin/template.pm create mode 100644 IkiWiki/Plugin/templatebody.pm create mode 100644 IkiWiki/Plugin/testpagespec.pm create mode 100644 IkiWiki/Plugin/teximg.pm create mode 100644 IkiWiki/Plugin/textile.pm create mode 100644 IkiWiki/Plugin/theme.pm create mode 100644 IkiWiki/Plugin/tla.pm create mode 100644 IkiWiki/Plugin/toc.pm create mode 100644 IkiWiki/Plugin/toggle.pm create mode 100644 IkiWiki/Plugin/trail.pm create mode 100644 IkiWiki/Plugin/transient.pm create mode 100644 IkiWiki/Plugin/txt.pm create mode 100644 IkiWiki/Plugin/typography.pm create mode 100644 IkiWiki/Plugin/underlay.pm create mode 100644 IkiWiki/Plugin/userlist.pm create mode 100644 IkiWiki/Plugin/version.pm create mode 100644 IkiWiki/Plugin/websetup.pm create mode 100644 IkiWiki/Plugin/wikitext.pm create mode 100644 IkiWiki/Plugin/wmd.pm create mode 100644 IkiWiki/Receive.pm create mode 100644 IkiWiki/Render.pm create mode 100644 IkiWiki/Setup.pm create mode 100644 IkiWiki/Setup/Automator.pm create mode 100644 IkiWiki/Setup/Standard.pm create mode 100644 IkiWiki/Setup/Yaml.pm create mode 100644 IkiWiki/UserInfo.pm create mode 100644 IkiWiki/Wrapper.pm create mode 100755 Makefile.PL create mode 120000 NEWS create mode 100644 README create mode 100644 auto-blog.setup create mode 100644 auto.setup create mode 100644 cpan/CPAN/MyConfig.pm create mode 100644 cpan/README create mode 100644 debian/.gitignore create mode 100644 debian/NEWS create mode 100644 debian/README.Debian create mode 100644 debian/changelog create mode 100644 debian/compat create mode 100644 debian/control create mode 100644 debian/copyright create mode 100644 debian/docs create mode 100644 debian/link create mode 100755 debian/postinst create mode 100755 debian/preinst create mode 100755 debian/rules create mode 100644 doc/GPL create mode 100644 doc/TourBusStop.mdwn create mode 100644 doc/anchor.mdwn create mode 100644 doc/backlinks.mdwn create mode 100644 doc/banned_users.mdwn create mode 100644 doc/banned_users/discussion.mdwn create mode 100644 doc/basewiki.mdwn create mode 100644 doc/basewiki/index.mdwn create mode 100644 doc/basewiki/sandbox.mdwn create mode 100644 doc/blog.mdwn create mode 100644 doc/branches.mdwn create mode 100644 doc/bugs.mdwn create mode 100644 doc/bugs/2.45_Compilation_error.mdwn create mode 100644 doc/bugs/404_plugin_and_lighttpd.mdwn create mode 100644 doc/bugs/404_plugin_should_handle_403.mdwn create mode 100644 doc/bugs/404_when_cancel_create_page.mdwn create mode 100644 doc/bugs/4_spaces_after_bullet.mdwn create mode 100644 doc/bugs/Add_a_footer_div_on_all_pages_to_improve_theming.mdwn create mode 100644 doc/bugs/Add_permissions_for_suggesting__47__accepting_edits.mdwn create mode 100644 doc/bugs/Aggregated_Atom_feeds_are_double-encoded.mdwn create mode 100644 doc/bugs/Allow_overriding_of_symlink_restriction.mdwn create mode 100644 doc/bugs/Another_UTF-8_problem.mdwn create mode 100644 doc/bugs/Attachment_plug-in_not_committing_files.mdwn create mode 100644 doc/bugs/Broken_URL_to_your_blog_script.mdwn create mode 100644 doc/bugs/Broken_access_to_Ikiwiki_gitweb.mdwn create mode 100644 doc/bugs/Building_a_sidebar_does_not_regenerate_the_subpages.mdwn create mode 100644 doc/bugs/CGI__44___formbuilder__44___non-existent_field_address.mdwn create mode 100644 doc/bugs/CGI_edit_and_slash_in_page_title.mdwn create mode 100644 doc/bugs/CGI_problem_with_some_webservers.mdwn create mode 100644 doc/bugs/CGI_showed_HTML_when_perl_error.mdwn create mode 100644 doc/bugs/CGI_wrapper_doesn__39__t_store_PERL5LIB_environment_variable.mdwn create mode 100644 doc/bugs/CamelCase_and_Recent_Changes_create_spurious_Links.mdwn create mode 100644 doc/bugs/Can__39__t_build_2.49__63__.mdwn create mode 100644 doc/bugs/Can__39__t_connect_to_ikiwiki_git_repo_through_http.mdwn create mode 100644 doc/bugs/Can__39__t_create_root_page.mdwn create mode 100644 doc/bugs/Can__39__t_deplete_page__63__.mdwn create mode 100644 doc/bugs/Can__39__t_rebuild_wiki_pages_with_ikiwiki_2.49.mdwn create mode 100644 doc/bugs/Cannot_inline_pages_with_apostrophes_in_title.mdwn create mode 100644 doc/bugs/Changing_language.mdwn create mode 100644 doc/bugs/Checksum_errors_on_the_pristine-tar_branch.mdwn create mode 100644 doc/bugs/Command-line_arguments_should_override_settings_in_the_setup_file.mdwn create mode 100644 doc/bugs/Comments_are_not_sorted_by_their_date_attribute.mdwn create mode 100644 doc/bugs/Comments_dissapeared.mdwn create mode 100644 doc/bugs/Comments_link_is_to_index.html_if_usedirs_is_on.mdwn create mode 100644 doc/bugs/Convert___34__somehost.com/user__34___OpenID_at_RecentChanges_page.mdwn create mode 100644 doc/bugs/Disappearing_Pages.mdwn create mode 100644 doc/bugs/Discussion_link_not_translated_after_page_update.mdwn create mode 100644 doc/bugs/Discussion_link_not_translated_in_post.mdwn create mode 100644 doc/bugs/Discussion_of_main_page_generates_invalid_link.mdwn create mode 100644 doc/bugs/Does_IkiWiki::Setup::load__40____41___really_return_a_hash__63__.mdwn create mode 100644 doc/bugs/Dupe_entry_in_Bundle::IkiWiki::Extras.pm.mdwn create mode 100644 doc/bugs/Encoding_problem_in_calendar_plugin.mdwn create mode 100644 doc/bugs/Error:_OpenID_failure:_time_bad_sig:.mdwn create mode 100644 doc/bugs/Error:_Your_login_session_has_expired._.mdwn create mode 100644 doc/bugs/Error:_no_text_was_copied_in_this_page_--_missing_page_dependencies.mdwn create mode 100644 doc/bugs/Exception:_Unknown_function___96__this__39___.mdwn create mode 100644 doc/bugs/Excessive_list_nesting_in_map_output_for_subpages.mdwn create mode 100644 doc/bugs/Existing_Discussion_pages_appear_as_non-existing.mdwn create mode 100644 doc/bugs/External_link:_underscore_conversion.mdwn create mode 100644 doc/bugs/External_links_with_Creole.mdwn create mode 100644 doc/bugs/Fancy_characters_get_munged_on_page_save.mdwn create mode 100644 doc/bugs/Feeds_get_wrong_timezone..mdwn create mode 100644 doc/bugs/Feeds_link_to_index.html_instead_of_directory.mdwn create mode 100644 doc/bugs/Filenames_with_colons_cause_problems_for_Windows_users.mdwn create mode 100644 doc/bugs/FormattingHelp_links_to_MarkDown_help_page_regardless_of_page_format.mdwn create mode 100644 doc/bugs/Git:_changed_behavior_w.r.t._timestamps.mdwn create mode 100644 doc/bugs/Git:_web_commit_message_not_utf-8.mdwn create mode 100644 doc/bugs/Graphviz_plug-in_directive_changed_in_2.60.mdwn create mode 100644 doc/bugs/HTML_for_parentlinks_makes_theming_hard.mdwn create mode 100644 doc/bugs/HTML_inlined_into_Atom_not_necessarily_well-formed.mdwn create mode 100644 doc/bugs/HTML_is_not_update_nor_created_when_editing_markdown_via_CGI.mdwn create mode 100644 doc/bugs/Highlight_extension_uses_hard_coded_paths.mdwn create mode 100644 doc/bugs/Http_error_500_when_using_mercurial_backend.mdwn create mode 100644 doc/bugs/Hyperestraier_search_plug-in_defective.mdwn create mode 100644 doc/bugs/INC_location_not_set_correctly_in_make_test.mdwn create mode 100644 doc/bugs/IkiWiki::Setup::load__40____41___broken_outside_ikiwiki__63__.mdwn create mode 100644 doc/bugs/IkiWiki::Wrapper_should_use_destdir.mdwn create mode 100644 doc/bugs/IkiWiki::Wrapper_should_use_destdir/discussion.mdwn create mode 100644 doc/bugs/IkiWiki_does_not_use_file__39__s_mtime_for_Last_Edited.mdwn create mode 100644 doc/bugs/Index_files_have_wrong_permissions.mdwn create mode 100644 doc/bugs/Inline_doesn__39__t_wikilink_to_pages.mdwn create mode 100644 doc/bugs/Inlining_adds_newlines_which_can_break_markdown.mdwn create mode 100644 doc/bugs/Insecure_dependency_in_eval_while_running_with_-T_switch.mdwn create mode 100644 doc/bugs/Insecure_dependency_in_mkdir.mdwn create mode 100644 doc/bugs/Insecure_dependency_in_utime.mdwn create mode 100644 doc/bugs/Linkmap_doesn__39__t_support_multiple_linkmaps_on_a_single_page.mdwn create mode 100644 doc/bugs/Links_to_missing_pages_should_always_be_styled.mdwn create mode 100644 doc/bugs/Links_with_symbols_can__39__t_be_edited.mdwn create mode 100644 doc/bugs/MTIME_not_set_for_inline_or_archive_entries.mdwn create mode 100644 doc/bugs/Map_sorts_subtags_under_a_different_tag.mdwn create mode 100644 doc/bugs/Mercurial_example_diffurl_should_read_r2__44___not_changeset.mdwn create mode 100644 doc/bugs/Meta_plugin_does_not_respect_htmlscrubber__95__skip_setting.___40__patch__41__.mdwn create mode 100644 doc/bugs/Missing_build-dep_on_perlmagick__63__.mdwn create mode 100644 doc/bugs/Missing_constant_domain_at_IkiWiki.pm_line_842.mdwn create mode 100644 doc/bugs/Monotone_rcs_support.mdwn create mode 100644 doc/bugs/More_permission_checking.mdwn create mode 100644 doc/bugs/Navbar_does_not_link_to_page_being_commented_on_while_commenting.mdwn create mode 100644 doc/bugs/New_comments_are_not_always_displayed__59___need_page_refresh_to_appear.mdwn create mode 100644 doc/bugs/No___34__sid__34___in_forms_resulting_in_Error:_Your_login_session_has_expired..mdwn create mode 100644 doc/bugs/No_categories_in_RSS__47__Atom_feeds.mdwn create mode 100644 doc/bugs/No_link_for_blog_items_when_filename_contains_a_colon.mdwn create mode 100644 doc/bugs/No_numbacklinks_setting_for___34__no_limit__34__.mdwn create mode 100644 doc/bugs/No_progress_in_progress_bar.mdwn create mode 100644 doc/bugs/Not_all_comments_are_listed_by___33__map_or___33__inline.mdwn create mode 100644 doc/bugs/Obsolete_templates__47__estseek.conf.mdwn create mode 100644 doc/bugs/OpenID_delegation_fails_on_my_server.mdwn create mode 100644 doc/bugs/PNG_triggers_UTF-8_error_in_MimeInfo.pm.mdwn create mode 100644 doc/bugs/PREFIX_not_honoured_for_underlaydir.mdwn create mode 100644 "doc/bugs/Pages_with_non-ascii_characters_like_\303\266\303\244\303\245_in_name_not_found_directly_after_commit.mdwn" create mode 100644 doc/bugs/Patch:_Fix_error_in_style.css.mdwn create mode 100644 doc/bugs/Perl_scripts_depend_on___47__usr__47__bin__47__perl.mdwn create mode 100644 doc/bugs/Please_avoid_using___39__cp_-a__39___in_Makefile.PL.mdwn create mode 100644 doc/bugs/Please_don__39__t_refer_to_offsite_openid_image.mdwn create mode 100644 doc/bugs/Please_update_highlight_plugin_for_highlight_3.18.mdwn create mode 100644 doc/bugs/Preview_removes_page_location_drop-down_options.mdwn create mode 100644 doc/bugs/Problem_with_displaying_smileys_on_inline_page.mdwn create mode 100644 doc/bugs/Problem_with_editing_page_after_first_SVN_commit.mdwn create mode 100644 doc/bugs/Problem_with_toc.pm_plug-in.mdwn create mode 100644 doc/bugs/Problem_with_umlauts_and_friends.mdwn create mode 100644 doc/bugs/Problems_using_cygwin.mdwn create mode 100644 doc/bugs/Problems_with_graphviz.pm_plug-in.mdwn create mode 100644 doc/bugs/Problems_with_graphviz.pm_plug-in_previews.mdwn create mode 100644 doc/bugs/RecentChanges_broken_with_empty_svnpath.mdwn create mode 100644 doc/bugs/RecentChanges_contains_invalid_XHTML.mdwn create mode 100644 doc/bugs/RecentChanges_links_to_deleted_pages.mdwn create mode 100644 doc/bugs/Remove_redirect_pages_from_inline_pages.mdwn create mode 100644 doc/bugs/Renaming_a_file_via_the_web_is_failing_when_using_subversion.mdwn create mode 100644 doc/bugs/Running_on_an_alternative_port_fails.mdwn create mode 100644 doc/bugs/SSI_include_stripped_from_mdwn.mdwn create mode 100644 doc/bugs/SVG_files_not_recognized_as_images.mdwn create mode 100644 doc/bugs/Search_Help_doesn__39__t_exist.mdwn create mode 100644 doc/bugs/Search_results_should_point_to_dir__44___not_index.html__44___when_use__95__dirs_is_enabled.mdwn create mode 100644 doc/bugs/Search_summary_includes_text_from_navigational_elements.mdwn create mode 100644 doc/bugs/Site_title_not_clickable_while_adding_a_comment.mdwn create mode 100644 doc/bugs/Slow_Filecheck_attachments___34__snails_it_all__34__.mdwn create mode 100644 doc/bugs/Slow_Filecheck_attachments___34__snails_it_all__34__/discussion.mdwn create mode 100644 doc/bugs/Smileys_in_the_block_code.mdwn create mode 100644 doc/bugs/Spaces_in_link_text_for_ikiwiki_links.mdwn create mode 100644 doc/bugs/Spurious___60__p__62___elements_added_to_tags_in_inliine_pages.mdwn create mode 100644 doc/bugs/Spurious___60__p__62___elements_added_to_tags_in_inliine_pages/discussion.mdwn create mode 100644 doc/bugs/Sub-Discussion_pages_have_a_broken___34__FormattingHelp__34___link.mdwn create mode 100644 doc/bugs/Symlinked_srcdir_requires_trailing_slash.mdwn create mode 100644 doc/bugs/Tab_delimited_tables_don__39__t_work.mdwn create mode 100644 doc/bugs/Template_variable_not_passed_as-is__63____33__.mdwn create mode 100644 doc/bugs/Titles_are_lower-cased_when_creating_a_page.mdwn create mode 100644 doc/bugs/Toc_map_and_template_plugins_do_not_play_well_together.mdwn create mode 100644 doc/bugs/Trailing_slash_breaks_links.mdwn create mode 100644 doc/bugs/URLs_with_parentheses_displayed_badly.mdwn create mode 100644 doc/bugs/UTF-16_and_UTF-32_are_unhandled.mdwn create mode 100644 doc/bugs/UTF-8_BOM_showing_up_inside_a_page__63__.mdwn create mode 100644 doc/bugs/UTF-8_in_attachment_filenames.mdwn create mode 100644 doc/bugs/Unable_to_add_attachments_to_some_pages.mdwn create mode 100644 doc/bugs/Undefined_subroutine_IkiWiki::escapeHTML.mdwn create mode 100644 doc/bugs/Undefined_subroutine_IkiWiki::refresh.mdwn create mode 100644 doc/bugs/Underscores_in_links_don__39__t_appear.mdwn create mode 100644 doc/bugs/Use_install__40__1__41___instead_of_cp__40__1__41___for_installing_files.mdwn create mode 100644 doc/bugs/W3MMode_still_uses_http:__47____47__localhost__63__.mdwn create mode 100644 doc/bugs/Warns_about_use_of_uninitialized_value_if_prefix__95__directives_is_on_and_a_directive_does_not_contain_a_space.mdwn create mode 100644 doc/bugs/Webedits_without_comment_don__39__t_make_it_through_git.mdwn create mode 100644 doc/bugs/Weird_interaction_between_toc_plugin_and_page_sections.mdwn create mode 100644 doc/bugs/Wrong_permissions_on_4_smileys.mdwn create mode 100644 doc/bugs/XHTML_needs_xmlns_attribute_on_html_element.mdwn create mode 100644 doc/bugs/__33__inline_sort__61____34__meta__40__date__41____34___ignored.mdwn create mode 100644 doc/bugs/__34__Currently_enabled_SSH_keys:__34___shows_only_first_139_characters_of_each_key.mdwn create mode 100644 doc/bugs/__34__First_post__34___deletion_does_not_refresh_front_page.mdwn create mode 100644 doc/bugs/__34__more__34___doesn__39__t_work.mdwn create mode 100644 doc/bugs/__34__skipping_bad_filename__34___error_when_src_path_contains_spaces.mdwn create mode 100644 doc/bugs/__36__ENV__123__PATH__125___should_include_PREFIXbin.mdwn create mode 100644 doc/bugs/__38__uuml__59___in_markup_makes_ikiwiki_not_un-escape_HTML_at_all.mdwn create mode 100644 doc/bugs/__60__br__62___tags_are_removed_from_markdown_inline_HTML.mdwn create mode 100644 doc/bugs/__63__Discussion_when_not_CGI_mode.mdwn create mode 100644 doc/bugs/__91__PATCH__93___Use_correct_perl_when_running_make.html create mode 100644 doc/bugs/__91__SOLVED__93___Pandoc_plugin_and_UTF-8:_IkiWiki_and_UTF-8.mdwn create mode 100644 doc/bugs/__91__SOLVED__93___Pandoc_plugin_and_UTF-8:_IkiWiki_and_UTF-8/discussion.mdwn create mode 100644 doc/bugs/__91____91____33__inline_postform__61__no__93____93___doesn__39__t_disable_it.mdwn create mode 100644 doc/bugs/__96____96__clear:_both__39____39___for___96__.page__42____39____63__.mdwn create mode 100644 doc/bugs/__96__wiki__95__file__95__chars__96___setting_not_propagated_to_CGI_wrapper.mdwn create mode 100644 doc/bugs/absolute_sizes_in_default_CSS.mdwn create mode 100644 doc/bugs/aggregate_generates_long_filenames.mdwn create mode 100644 doc/bugs/aggregate_global_feed_names.mdwn create mode 100644 doc/bugs/aggregate_plugin_errors.mdwn create mode 100644 doc/bugs/aggregate_plugin_errors/discussion.mdwn create mode 100644 doc/bugs/aggregate_plugin_should_honour_a_post__39__s_mctime.mdwn create mode 100644 doc/bugs/aggregate_removed_feeds_linger.mdwn create mode 100644 doc/bugs/aggregateinline_planets_wrongly_link_to_posts.mdwn create mode 100644 doc/bugs/align_doesn__39__t_always_work_with_img_plugin_.mdwn create mode 100644 doc/bugs/anonok_vs._httpauth.mdwn create mode 100644 doc/bugs/argument_isn__39__t_numeric:_mixing_templates_and_creation__95__date.mdwn create mode 100644 doc/bugs/assumes___34__git_push_origin__34___is_sufficient.mdwn create mode 100644 doc/bugs/attachment:_escaping_underscores_in_filename__63__.mdwn create mode 100644 doc/bugs/attachment:_failed_to_get_filehandle.mdwn create mode 100644 doc/bugs/attachment_plugin_enabled_by_default__63__.mdwn create mode 100644 doc/bugs/attachment_upload_does_not_work_for_windows_clients.mdwn create mode 100644 doc/bugs/backlink__40__.__41___doesn__39__t_work.mdwn create mode 100644 doc/bugs/backlinks_onhover_thing_can_go_weird.mdwn create mode 100644 doc/bugs/barfs_on_recentchange_entry_for_a_change_removing_an_invalid_pagespec.mdwn create mode 100644 doc/bugs/basewiki_uses_meta_directives_but_meta_is_not_enabled_by_default.mdwn create mode 100644 doc/bugs/beautify__95__urlpath_will_add_.__47___even_if_it_is_already_present.mdwn create mode 100644 doc/bugs/bestlink_change_update_issue.mdwn create mode 100644 doc/bugs/bestlink_returns_deleted_pages.mdwn create mode 100644 doc/bugs/blog_posts_not_added_to_mercurial_repo.mdwn create mode 100644 doc/bugs/blog_spam_plugin_not_allowing_non-ASCII_chars__63__.mdwn create mode 100644 doc/bugs/blogspam__95__options_whitelist_vs._IPv6__63__.mdwn create mode 100644 doc/bugs/blogspam_marks_me_as_spam_on_ipv6.mdwn create mode 100644 doc/bugs/both_inline_and_comment_create_elements_id__61__feedlink.mdwn create mode 100644 doc/bugs/broken_page_after_buggy_remove.mdwn create mode 100644 doc/bugs/broken_parentlinks.mdwn create mode 100644 doc/bugs/brokenlinks_accumulates_duplicate_items.mdwn create mode 100644 doc/bugs/brokenlinks_false_positives.mdwn create mode 100644 doc/bugs/bug_in_cgiurl_port.mdwn create mode 100644 doc/bugs/bug_when_toggling_in_a_preview_page.mdwn create mode 100644 doc/bugs/bugfix_for:___34__mtn:_operation_canceled:_Broken_pipe__34_____40__patch__41__.mdwn create mode 100644 doc/bugs/build_fails_oddly_when_older_ikiwiki_is_installed.mdwn create mode 100644 doc/bugs/build_in_opensolaris.mdwn create mode 100644 doc/bugs/bzr-update-syntax-error.mdwn create mode 100644 doc/bugs/bzr_2.0_breaks_bzr_plugin.mdwn create mode 100644 doc/bugs/bzr_RecentChanges_dates_start_from_1969.mdwn create mode 100644 doc/bugs/bzr_plugin_does_not_define_rcs__95__diff.mdwn create mode 100644 doc/bugs/can__39__t_mix_template_vars_inside_directives.mdwn create mode 100644 doc/bugs/can__39__t_upload_a_simple_png_image:_prohibited_by_allowed__95__attachments___40__file_MIME_type_is_application__47__octet-stream....mdwn create mode 100644 doc/bugs/cannot_clone_documented_git_repo.mdwn create mode 100644 doc/bugs/cannot_decode_wide_characters_error_with_utf-8_encoding.mdwn create mode 100644 doc/bugs/cannot_preview_shortcuts.mdwn create mode 100644 doc/bugs/cannot_reliably_use_meta_in_template.mdwn create mode 100644 doc/bugs/cannot_revert_page_deletion.mdwn create mode 100644 doc/bugs/capitalized_attachment_names.mdwn create mode 100644 doc/bugs/cgi_does_not_use_templatedir_overlay.mdwn create mode 100644 doc/bugs/cgi_wrapper_always_regenerated.mdwn create mode 100644 doc/bugs/changes_from_the_web_interface_fail_to_get_committed.mdwn create mode 100644 doc/bugs/class_parameter_of_img_directive_behave_not_as_documented.mdwn create mode 100644 doc/bugs/clearenv_not_present_at_FreeBSD_.mdwn create mode 100644 doc/bugs/clearenv_not_present_at_FreeBSD_/discussion.mdwn create mode 100644 doc/bugs/clearing_email_in_prefs.mdwn create mode 100644 doc/bugs/colon:problem.mdwn create mode 100644 doc/bugs/colon:problem/discussion.mdwn create mode 100644 doc/bugs/comments_appear_two_times.mdwn create mode 100644 doc/bugs/comments_not_searchable.mdwn create mode 100644 doc/bugs/comments_preview_unsafe_with_allowdirectives.mdwn create mode 100644 doc/bugs/comments_produce_broken_links_in_RecentChanges.mdwn create mode 100644 doc/bugs/complex_wiki-code___40__braces__41___in_wikilink-text_breaks_wikilinks.mdwn create mode 100644 doc/bugs/conditional_preprocess_during_scan.mdwn create mode 100644 doc/bugs/conflicts.mdwn create mode 100644 doc/bugs/correct_published_and_updated_time_information_for_the_feeds.mdwn create mode 100644 doc/bugs/crashes_in_the_python_proxy_even_if_disabled.mdwn create mode 100644 doc/bugs/creating_page_from_comment_creates_a_comment.mdwn create mode 100644 doc/bugs/cutpaste.pm:_missing_filter_call.mdwn create mode 100644 doc/bugs/ddate_plugin_causes_websetup_to_change_timeformat__44___even_when_disabled.mdwn create mode 100644 doc/bugs/debbug_shortcut_should_expand_differently.mdwn create mode 100644 doc/bugs/debbug_shortcut_should_expand_differently/discussion.mdwn create mode 100644 doc/bugs/debian_package_doesn__39__t_pull_in_packages_required_for_openid.mdwn create mode 100644 doc/bugs/debwiki_shortcut_creates_buggy_URLs_to_subpages.mdwn create mode 100644 doc/bugs/default__95__pageext_not_working.mdwn create mode 100644 doc/bugs/definition_lists_should_be_bold.mdwn create mode 100644 doc/bugs/defintion_lists_appear_to_be_disabled.mdwn create mode 100644 doc/bugs/deletion_warnings.mdwn create mode 100644 doc/bugs/depends_simple_mixup.mdwn create mode 100644 doc/bugs/diff_links_to_backtrace.mdwn create mode 100644 doc/bugs/disable_sub-discussion_pages.mdwn create mode 100644 doc/bugs/disabling_backlinks.mdwn create mode 100644 doc/bugs/discussion.mdwn create mode 100644 doc/bugs/discussion_of_what__63__.mdwn create mode 100644 doc/bugs/discussion_pages_with_uppercase_characters_break_the_detection_of_the_best_location.mdwn create mode 100644 doc/bugs/discussion_removal.mdwn create mode 100644 doc/bugs/do_not_let_big_brother_spy_on_our_users_on_login.mdwn create mode 100644 doc/bugs/done.mdwn create mode 100644 doc/bugs/dumpsetup_does_not_save_destdir.mdwn create mode 100644 doc/bugs/edit_preview_resolves_links_differently_from_commit.mdwn create mode 100644 doc/bugs/editing_gitbranch_template_is_really_slow.mdwn create mode 100644 doc/bugs/editmessage_turned_off_in_web_interface__63__.mdwn create mode 100644 doc/bugs/edits_not_showing_up_in_compiled_pages.mdwn create mode 100644 doc/bugs/edittemplate_seems_not_to_be_working.mdwn create mode 100644 doc/bugs/emails_should_not_be_considered_as_broken_links.mdwn create mode 100644 doc/bugs/empty_div_element.mdwn create mode 100644 doc/bugs/enabling_or_disabling_plugin_x_does_not_rebuild_pages_that_use_enabled__40__x__41__.mdwn create mode 100644 doc/bugs/encoding_issue_in_blogspam_plugin.mdwn create mode 100644 doc/bugs/entirely_negated_pagespec_matches_internal_pages.mdwn create mode 100644 doc/bugs/enumerations_of_dates_not_formatted_correctly.mdwn create mode 100644 doc/bugs/error_handlers_with_gettext_can_clobber___36____64__.mdwn create mode 100644 doc/bugs/errors_with_ampersand_in_filename.mdwn create mode 100644 doc/bugs/example_Mercurial_historyurl_doesn__39__t_show_file_history.mdwn create mode 100644 doc/bugs/external_links_inside_headings_don__39__t_work.mdwn create mode 100644 doc/bugs/external_plugins_cannot_access_ARGV_needed_for_getopt.mdwn create mode 100644 doc/bugs/feedfile_does_the_wrong_thing_from_index.mdwn2.mdwn create mode 100644 doc/bugs/feedpages_does_not_prevent_tags_from_being_aggregated.mdwn create mode 100644 doc/bugs/feeds_get_removed_in_strange_conditions.mdwn create mode 100644 doc/bugs/filecheck_failing_to_find_files.mdwn create mode 100644 doc/bugs/find:_invalid_predicate___96__-L__39__.mdwn create mode 100644 doc/bugs/find_gnuism.mdwn create mode 100644 doc/bugs/firefox_doesn__39__t_want_to_load_updated_pages_at_ikiwiki.info.mdwn create mode 100644 doc/bugs/format_bug.mdwn create mode 100644 doc/bugs/formbuilder_3.0401_broken.mdwn create mode 100644 doc/bugs/garbled_non-ascii_characters_in_body_in_web_interface.mdwn create mode 100644 doc/bugs/git.pm_should_prune_remote_branches_when_fetching.mdwn create mode 100644 doc/bugs/git_commit_adds_files_that_were_not_tracked.mdwn create mode 100644 doc/bugs/git_fails_to_compile.mdwn create mode 100644 doc/bugs/git_mail_notification_race.mdwn create mode 100644 doc/bugs/git_stderr_output_causes_problems.mdwn create mode 100644 doc/bugs/git_utf8.mdwn create mode 100644 doc/bugs/gitremotes_script_picks_up_tags_from_anywhere.mdwn create mode 100644 doc/bugs/gitweb_deficiency_w.r.t._log_messages.mdwn create mode 100644 doc/bugs/gitweb_deficiency_w.r.t._newly_created_pages.mdwn create mode 100644 doc/bugs/goto_with_bad_page_name.mdwn create mode 100644 doc/bugs/graphviz_demo_generates_empty_graph.mdwn create mode 100644 doc/bugs/hardcoded___34__Discussion__34___link.mdwn create mode 100644 doc/bugs/helponformatting_link_disappears.mdwn create mode 100644 doc/bugs/html5_support.mdwn create mode 100644 doc/bugs/html5_time_element__39__s_pubdate_wrong_when_using_xhtml5___34__mode__34__.mdwn create mode 100644 doc/bugs/html_errors.mdwn create mode 100644 doc/bugs/htmlbalance_fails_with_HTML-Tree_v4.mdwn create mode 100644 doc/bugs/htmlscrubber_breaks_multimarkdown_footnotes.mdwn create mode 100644 doc/bugs/htmlscrubber_still_scrubbing_HTML_from_mdwn_pages.mdwn create mode 100644 doc/bugs/htmlscrubber_undoes_email_obfuscation_by_Text::Markdown.mdwn create mode 100644 doc/bugs/htmltidy_has_no_possibilty_to_use_an_alternative_config_file_which_may_break_other_usages.mdwn create mode 100644 doc/bugs/http_proxy_for_openid.mdwn create mode 100644 doc/bugs/httpauth_conflicts_with_git_anon_push.mdwn create mode 100644 doc/bugs/ikiwiki-mass-rebuild_fails_to_drop_privileges_and_execute_ikiwiki.mdwn create mode 100644 doc/bugs/ikiwiki-transition_does_not_set_perl_moduels_path_properly.mdwn create mode 100644 doc/bugs/ikiwiki.setup:_syntax_error_at___40__eval_5__41___line_120__44___at_EOF.mdwn create mode 100644 doc/bugs/ikiwiki.setup_require_blank_rcs_to_work_as_cgi_only.mdwn create mode 100644 doc/bugs/ikiwiki__39__s_ViewVC_down.mdwn create mode 100644 doc/bugs/ikiwiki_cgi_fails_to_build_on_Solaris_due_to_missing_LOCK__95__EX.mdwn create mode 100644 doc/bugs/ikiwiki_ignores_PATH_environment.mdwn create mode 100644 doc/bugs/ikiwiki_lacks_a_--quiet.mdwn create mode 100644 doc/bugs/ikiwiki_overzealously_honours_locks_when_asked_for_forms.mdwn create mode 100644 doc/bugs/ikiwiki_renders___39__28__39___if_external_plugins_return_nothing.mdwn create mode 100644 doc/bugs/image_rescaling_distorts_with_small_pictures.mdwn create mode 100644 doc/bugs/images_in_inlined_pages_have_wrong_relative_URL.mdwn create mode 100644 doc/bugs/img_plugin_and_class_attr.mdwn create mode 100644 doc/bugs/img_plugin_and_missing_heigth_value.mdwn create mode 100644 doc/bugs/img_plugin_causes_taint_failure.mdwn create mode 100644 doc/bugs/img_plugin_renders___60__img__62___tag_without_src_attribute_post-2.20.mdwn create mode 100644 doc/bugs/img_plugin_should_pass_through_class_attribute.mdwn create mode 100644 doc/bugs/img_test_failing_under_sbuild.mdwn create mode 100644 doc/bugs/img_vs_align.mdwn create mode 100644 doc/bugs/img_with_alt_has_extra_double_quote.mdwn create mode 100644 doc/bugs/index.html__63__updated.mdwn create mode 100644 doc/bugs/index.html_is_made_visible_by_various_actions.mdwn create mode 100644 doc/bugs/iniline_breaks_toc_plugin.mdwn create mode 100644 doc/bugs/inline_action_buttons_circumvent_exclude_criteria_from_edittemplate__39__s_match__61____34____34___pagespec.mdwn create mode 100644 doc/bugs/inline_archive_crash.mdwn create mode 100644 doc/bugs/inline_breaks_PERMALINK_variable.mdwn create mode 100644 doc/bugs/inline_from_field_empty_if_rootpage_doesn__39__t_exist.mdwn create mode 100644 doc/bugs/inline_page_not_updated_on_removal.mdwn create mode 100644 doc/bugs/inline_plugin_rootpage_option_is_not_case_insensitive.mdwn create mode 100644 doc/bugs/inline_plugin_sets_editurl_even_when_editpage_is_disabled.html create mode 100644 doc/bugs/inline_raw_broken_on_unknown_pagetype.mdwn create mode 100644 doc/bugs/inline_skip_causes_empty_inline.mdwn create mode 100644 doc/bugs/inline_sort-by-title_issues.mdwn create mode 100644 doc/bugs/inline_sort_order_and_meta_date_value.mdwn create mode 100644 doc/bugs/install_into_home_dir_fails.mdwn create mode 100644 doc/bugs/installing_from_svn_copies_.svn_directories.mdwn create mode 100644 doc/bugs/internal_error:_smileys.mdwn_cannot_be_found.mdwn create mode 100644 doc/bugs/ipv6_address_in_comments.mdwn create mode 100644 doc/bugs/jquery-ui.min.css_missing_some_image_files.mdwn create mode 100644 doc/bugs/librpc-xml-perl_0.69_breaks_XML-RPC_plugins.mdwn create mode 100644 doc/bugs/linkingrules_should_document_how_to_link_to_page_at_root_if_non-root_page_exists.mdwn create mode 100644 doc/bugs/linkmap_displays_underscore_escapes.mdwn create mode 100644 doc/bugs/linkmap_displays_underscore_escapes/the_patch.pl create mode 100644 doc/bugs/links_from_sidebars.mdwn create mode 100644 doc/bugs/links_from_sidebars/discussion.mdwn create mode 100644 doc/bugs/links_misparsed_in_CSV_files.mdwn create mode 100644 doc/bugs/listdirectives_doesn__39__t_register_a_link.mdwn create mode 100644 doc/bugs/lockedit_plugin_should_alert_user_about_an_invalid_pagespec_in_preferences.mdwn create mode 100644 doc/bugs/locking_fun.mdwn create mode 100644 doc/bugs/login_page_non-obvious_with_openid.mdwn create mode 100644 doc/bugs/login_page_should_note_cookie_requirement.mdwn create mode 100644 doc/bugs/logout_in_ikiwiki.mdwn create mode 100644 doc/bugs/mailto:_links_not_properly_generated_in_rssatom_feeds.mdwn create mode 100644 doc/bugs/map_does_not_link_directory_for_which_a_file_also_exists.mdwn create mode 100644 doc/bugs/map_does_not_link_directory_for_which_a_file_also_exists/discussion.mdwn create mode 100644 doc/bugs/map_doesn__39__t_calculate___34__common__95__prefix__34___correctly.mdwn create mode 100644 doc/bugs/map_fails_to_close_ul_element_for_empty_list.mdwn create mode 100644 doc/bugs/map_generates_malformed_HTML.mdwn create mode 100644 doc/bugs/map_is_inconsistent_about_bare_directories.mdwn create mode 100644 doc/bugs/map_sorts_by_pagename_and_not_title_when_show__61__title_is_used.mdwn create mode 100644 doc/bugs/maps_with_nested_directories_sometimes_make_ugly_lists.mdwn create mode 100644 doc/bugs/markdown_bug:_email_escaping_and_plus_addresses.mdwn create mode 100644 doc/bugs/markdown_module_location.mdwn create mode 100644 doc/bugs/mercurial_fail_to_add.mdwn create mode 100644 doc/bugs/merging_to_basewiki_causes_odd_inconsistencies.mdwn create mode 100644 doc/bugs/messed_up_repository.mdwn create mode 100644 doc/bugs/meta_inline.mdwn create mode 100644 doc/bugs/methodResponse_in_add__95__plugins.mdwn create mode 100644 doc/bugs/minor:_tiny_rendering_error.mdwn create mode 100644 doc/bugs/misctemplate_does_not_respect_the_current_page___40__if_any__41__.mdwn create mode 100644 doc/bugs/monotone_backend_does_not_support_srcdir_in_subdir.mdwn create mode 100644 doc/bugs/more_and_RSS_generation.mdwn create mode 100644 doc/bugs/multiple_encoding_issues_in_atom.mdwn create mode 100644 doc/bugs/multiple_pages_with_same_name.mdwn create mode 100644 doc/bugs/multiple_rss_feeds_per_page.mdwn create mode 100644 doc/bugs/must_save_before_uploading_more_than_one_attachment.mdwn create mode 100644 doc/bugs/nested_inlines_produce_no_output.mdwn create mode 100644 doc/bugs/nested_raw_included_inlines.mdwn create mode 100644 doc/bugs/newfile-test.mdwn create mode 100644 doc/bugs/no_commit_mails_for_new_pages.mdwn create mode 100644 doc/bugs/no_easy_way_to_wrap_HTML_container_around_a_set_of_inlined_pages.mdwn create mode 100644 doc/bugs/no_search_button__44___hence_can__39__t_do_search_in_w3m_at_ikiwiki.info.mdwn create mode 100644 doc/bugs/nonexistent_pages_in_inline_pagenames_do_not_add_a_dependency.mdwn create mode 100644 doc/bugs/notifyemail_fails_with_some_openid_providers.mdwn create mode 100644 doc/bugs/octal_umask_setting_is_unintuitive.mdwn create mode 100644 doc/bugs/opendiscussion_should_respect_the_discussion_option.mdwn create mode 100644 doc/bugs/opendiscussion_should_respect_the_discussion_option/discussion.mdwn create mode 100644 doc/bugs/openid_incompatability_with_pyblosxom_openid_server_plugin_when_used_with_simple_registration_extension.mdwn create mode 100644 doc/bugs/openid_login_fails_wirth_Could_not_determine_ID_provider_from_URL.mdwn create mode 100644 doc/bugs/openid_no_longer_pretty-prints_OpenIDs.mdwn create mode 100644 doc/bugs/openid_postsignin_failure.mdwn create mode 100644 doc/bugs/osm_KML_maps_do_not_display_properly_on_google_maps.mdwn create mode 100644 doc/bugs/osm_KML_maps_icon_path_have_a_trailing_slash.mdwn create mode 100644 doc/bugs/osm_linkto__40____41___usage_breaks_map_rendering.mdwn create mode 100644 doc/bugs/osm_plugin_error_TypeError:_mapProjection_is_null.mdwn create mode 100644 doc/bugs/osm_sometimes_looses_some_nodes.mdwn create mode 100644 doc/bugs/output_of_successful_rename_should_list_the_full_path_to_affected_pages.mdwn create mode 100644 doc/bugs/package_build_fails_in_non-English_environment.mdwn create mode 100644 doc/bugs/page_is_not_rebuilt_if_it_changes_extension.mdwn create mode 100644 doc/bugs/page_preview_does_not_work_on_new_page_with_a_table.mdwn create mode 100644 doc/bugs/pagecount_is_broken.mdwn create mode 100644 doc/bugs/pagemtime_in_refresh_mode.mdwn create mode 100644 doc/bugs/pages_missing_top-level_directory.mdwn create mode 100644 doc/bugs/pages_under_templates_are_invalid.mdwn create mode 100644 doc/bugs/pagespec:_tagged__40____41____44___globbing.mdwn create mode 100644 doc/bugs/pagespec_can__39__t_match___123__curly__125___braces.mdwn create mode 100644 doc/bugs/pagespec_error_on_refresh_but_not_rebuild.mdwn create mode 100644 doc/bugs/pagespec_parsing_chokes_on_function__40____41__.mdwn create mode 100644 doc/bugs/pagestats_plugin_broken.mdwn create mode 100644 doc/bugs/pagetitle_function_does_not_respect_meta_titles.mdwn create mode 100644 doc/bugs/parsing_for_WikiWords_should_only_be_done_outside_html_tags.mdwn create mode 100644 doc/bugs/password_deletion.mdwn create mode 100644 doc/bugs/password_reset_fails_with___34__Wide_character_in_subroutine_entry__34__.mdwn create mode 100644 doc/bugs/perl:_double_free_or_corruption.mdwn create mode 100644 doc/bugs/pipe-symbol_in_taglink_target.mdwn create mode 100644 doc/bugs/pipe_in_tables_as_characters.mdwn create mode 100644 doc/bugs/plugin___96__rename__96___fails_if___96__attachment__96___is_not_enabled.mdwn create mode 100644 doc/bugs/plugins__47__relativedate_depends_on_locale_at_setup_file.mdwn create mode 100644 doc/bugs/po:__apache_config_serves_index_directory_for_index.mdwn create mode 100644 doc/bugs/po:_apache_config_serves_index.rss_for_index.mdwn create mode 100644 doc/bugs/po:_double_commits_of_po_files.mdwn create mode 100644 doc/bugs/po:_markdown_link_parse_bug.mdwn create mode 100644 doc/bugs/po:_might_not_add_translated_versions_of_all_underlays.mdwn create mode 100644 doc/bugs/po:_new_pages_not_translatable.mdwn create mode 100644 doc/bugs/po:_plugin_should_not_override_the_title_on_the_homepage.mdwn create mode 100644 doc/bugs/po:_po4a_too_strict_on_html_pages.mdwn create mode 100644 doc/bugs/po:_po_files_instead_of_html_files.mdwn create mode 100644 doc/bugs/po:_ugly_messages_with_empty_files.mdwn create mode 100644 doc/bugs/po:broken_links_to_translatable_basewiki_pages_that_lack_po_fies.mdwn create mode 100644 doc/bugs/po_plugin_adds_new_dependency.mdwn create mode 100644 doc/bugs/po_plugin_cannot_add_po_files_into_git.mdwn create mode 100644 doc/bugs/po_vs_templates.mdwn create mode 100644 doc/bugs/poll_in_inline.mdwn create mode 100644 doc/bugs/poll_plugin:_can__39__t_vote_for_non-ascii_options.mdwn create mode 100644 doc/bugs/poll_plugin_uses_GET.mdwn create mode 100644 doc/bugs/possible_to_post_comments_that_will_not_be_displayed.mdwn create mode 100644 doc/bugs/possibly_po_related_error.mdwn create mode 100644 doc/bugs/post-commit_hangs.mdwn create mode 100644 doc/bugs/post-update_hook_can__39__t_be_compiled_with_tcc.mdwn create mode 100644 doc/bugs/preprocessing_loop_control_too_tight.mdwn create mode 100644 doc/bugs/prettydate_with_weekday-date_inconsistency.mdwn create mode 100644 doc/bugs/preview_base_url_should_be_absolute.mdwn create mode 100644 doc/bugs/preview_pagestate.mdwn create mode 100644 doc/bugs/previewing_new_page_can_leave_files_dangling.mdwn create mode 100644 doc/bugs/previewing_with_an_edittemplate_reverts_edit_box.mdwn create mode 100644 doc/bugs/problem_adding_tag_from_template.mdwn create mode 100644 doc/bugs/proxy.py_utf8_troubles.mdwn create mode 100644 doc/bugs/prune_causing_taint_mode_failures.mdwn create mode 100644 doc/bugs/pruning_is_too_strict.mdwn create mode 100644 doc/bugs/pythonproxy-utf8_again.mdwn create mode 100644 doc/bugs/quieten_mercurial.mdwn create mode 100644 doc/bugs/raw_html_in-page_and___91____91____33__included__93____93__.mdwn create mode 100644 doc/bugs/rebuild_after_changing_the_underlaydir_config_option.mdwn create mode 100644 doc/bugs/recentchanges_escaping.mdwn create mode 100644 doc/bugs/recentchanges_feed_links.mdwn create mode 100644 doc/bugs/recentchanges_sets_has__95__diffurl__61__1_when_diffurl_is_empty.mdwn create mode 100644 doc/bugs/recentchangesdiff_crashes_on_commits_which_remove_a_lot_of_files.mdwn create mode 100644 doc/bugs/relative_date_weird_results.mdwn create mode 100644 doc/bugs/removal_of_transient_pages.mdwn create mode 100644 doc/bugs/remove_orphaned_sparkline-php_from_Suggests.mdwn create mode 100644 doc/bugs/remove_plugin_and_untracked_files.mdwn create mode 100644 doc/bugs/removing_pages_with_utf8_characters.mdwn create mode 100644 doc/bugs/rename_fixup_not_attributed_to_author.mdwn create mode 100644 doc/bugs/renaming_a_page_destroyed_some_links.mdwn create mode 100644 doc/bugs/resized_img_with_only_width_or_height_breaks_ie.mdwn create mode 100644 doc/bugs/rss_feed_cleanup_on_delete.mdwn create mode 100644 doc/bugs/rss_feeds_do_not_use_recommended_encoding_of_entities_for_some_fields.mdwn create mode 100644 doc/bugs/rss_output_relative_links.mdwn create mode 100644 doc/bugs/rst_fails_on_file_containing_only_a_number.mdwn create mode 100644 doc/bugs/rst_plugin_fails_with___34__uncaught_exception:___39__ascii__39___codec_can__39__t_encode_character__34__.mdwn create mode 100644 doc/bugs/rst_plugin_hangs_on_utf-8.mdwn create mode 100644 doc/bugs/rst_plugin_hangs_when_used_with_Python_3.mdwn create mode 100644 doc/bugs/rst_plugin_has_python_hardcode_in_shebang_line.mdwn create mode 100644 doc/bugs/rst_plugin_traceback_with_SimpleXMLRPCDispatcher_from_pyhton_2.5.mdwn create mode 100644 doc/bugs/rst_tweak.mdwn create mode 100644 doc/bugs/search:___34__link__34___and___34__title__34___fields_are_incorrectly_specified.mdwn create mode 100644 doc/bugs/search_creates_configuration_files_many_times_on_rebuild.mdwn create mode 100644 doc/bugs/search_for_locale_data_in_the_installed_location.mdwn create mode 100644 doc/bugs/search_plugin_and_CGI_preview.mdwn create mode 100644 doc/bugs/search_plugin_finds_no_results_with_xapian_1.2.7.mdwn create mode 100644 doc/bugs/search_plugin_uses_wrong_css_path.mdwn create mode 100644 doc/bugs/search_template_missing_dep.mdwn create mode 100644 doc/bugs/several_entries_in_docs__47__bugs_contain_colons_in_the_filename.mdwn create mode 100644 doc/bugs/shortcut_encoding.mdwn create mode 100644 doc/bugs/shortcut_plugin_will_not_work_without_shortcuts.mdwn.mdwn create mode 100644 doc/bugs/shortcuts_don__39__t_escape_from_Markdown.mdwn create mode 100644 doc/bugs/sidebar_is_obscured_by_recentchanges.mdwn create mode 100644 doc/bugs/sidebar_not_updated_in_unedited_subpages.mdwn create mode 100644 doc/bugs/sitemap_includes_images_directly.mdwn create mode 100644 doc/bugs/some_but_not_all_meta_fields_are_stored_escaped.mdwn create mode 100644 doc/bugs/some_strings_are_not_internationalized.mdwn create mode 100644 doc/bugs/space_in_a___91____91__page_link__93____93___doesn__39__t_make_link.mdwn create mode 100644 doc/bugs/special_characters_in_tag_names_need_manual_escaping.mdwn create mode 100644 doc/bugs/ssl_certificates_not_checked_with_openid.mdwn create mode 100644 doc/bugs/strange_hook_id_in_skeleton.pm.mdwn create mode 100644 doc/bugs/stray___60____47__p__62___tags.mdwn create mode 100644 doc/bugs/structured_config_data_is_mangled.mdwn create mode 100644 doc/bugs/support_for_openid2_logins.mdwn create mode 100644 doc/bugs/svg_and_pdf_conversion_fails.mdwn create mode 100644 doc/bugs/svn+ssh_commit_fail.mdwn create mode 100644 doc/bugs/svn-commit-hanging.mdwn create mode 100644 doc/bugs/svn_commit_failures_interpreted_as_merge_conflicts.mdwn create mode 100644 doc/bugs/svn_fails_to_update.mdwn create mode 100644 doc/bugs/svn_post-commit_wrapper_can__39__t_find_IkiWiki.pm_if_not_installed.mdwn create mode 100644 doc/bugs/syntax_error_in_aggregate.mdwn create mode 100644 doc/bugs/syslog_fails_with_non-ASCII_wikinames.mdwn create mode 100644 doc/bugs/table_external_file_links.mdwn create mode 100644 doc/bugs/table_plugin_does_not_handle___92__r__92__n_lines_in_CSV_files.mdwn create mode 100644 doc/bugs/tag_behavior_changes_introduced_by_typed_link_feature.mdwn create mode 100644 doc/bugs/tag_plugin:_autotag_vs._staged_changes.mdwn create mode 100644 doc/bugs/tagged__40____41___matching_wikilinks.mdwn create mode 100644 doc/bugs/tags__44___backlinks_and_3.x.mdwn create mode 100644 doc/bugs/tags_base_dir_not_used_when_creating_new_tags.mdwn create mode 100644 doc/bugs/taint_and_-T.mdwn create mode 100644 doc/bugs/taint_issue_with_regular_expressions.mdwn create mode 100644 doc/bugs/tbasewiki__95__brokenlinks.t_broken.mdwn create mode 100644 doc/bugs/tbasewiki__95__brokenlinks.t_broken/discussion.mdwn create mode 100644 doc/bugs/templateForRecentChangesMissingCloseSpan.mdwn create mode 100644 doc/bugs/template__95__syntax_test_is_incomplete.mdwn create mode 100644 doc/bugs/template_creation_error.mdwn create mode 100644 doc/bugs/template_evaluation_oddities.mdwn create mode 100644 doc/bugs/teximg_does_not_work_Preview.mdwn create mode 100644 doc/bugs/teximg_fails_if_same_tex_is_used_on_multiple_pages.mdwn create mode 100644 doc/bugs/textile_plugin_dies_if_input_has_a_non-utf8_character.mdwn create mode 100644 doc/bugs/the_login_page_is_unclear_when_multiple_methods_exist.mdwn create mode 100644 doc/bugs/title__40____41___in_a_PageSpec__44___with_meta_enabled__44___causes_a_crash.mdwn create mode 100644 doc/bugs/toc_displays_headings_from_sidebar.mdwn create mode 100644 doc/bugs/toc_in_sidebar.mdwn create mode 100644 doc/bugs/toggle_expects_body_element_without_attributes.mdwn create mode 100644 doc/bugs/toggle_fails_on_Safari.mdwn create mode 100644 doc/bugs/trail_excess_dependencies.mdwn create mode 100644 doc/bugs/trail_shows_on_cgi_pages.mdwn create mode 100644 doc/bugs/trail_test_suite_failures.mdwn create mode 100644 doc/bugs/trails_depend_on_everything.mdwn create mode 100644 doc/bugs/transient_autocreated_tagbase_is_not_transient_autoindexed.mdwn create mode 100644 doc/bugs/transitive_dependencies.mdwn create mode 100644 doc/bugs/trouble_with_base_in_search.mdwn create mode 100644 doc/bugs/txt_plugin_having_problems_with_meta_directives.mdwn create mode 100644 doc/bugs/typo_in_ikiwiki.setup.mdwn create mode 100644 doc/bugs/typo_in_skeleton.pm:_sessionncgi.mdwn create mode 100644 doc/bugs/undefined_tags_or_mismatched_tags_won__39__t_get_converted.mdwn create mode 100644 doc/bugs/undefined_value_as_a_HASH_reference.mdwn create mode 100644 doc/bugs/underlaydir_file_expose.mdwn create mode 100644 doc/bugs/unicode_chars_in_wikiname_break_auth.mdwn create mode 100644 doc/bugs/unicode_encoded_urls_and_recentchanges.mdwn create mode 100644 doc/bugs/unrecognized___34__do__61__blog__34___CGI_parameter_when_creating_todo_item.mdwn create mode 100644 doc/bugs/unwanted_discussion_links_on_discussion_pages.mdwn create mode 100644 doc/bugs/urlto_API_change_breaks_wikis_with_po_plugin.mdwn create mode 100644 doc/bugs/urlto__40____34____34____44___...__44___1__41___not_absolute.mdwn create mode 100644 doc/bugs/user_links_on_recentchanges_pages_problem.mdwn create mode 100644 doc/bugs/utf-8_bug_in_websetup.pm.mdwn create mode 100644 doc/bugs/utf8_html_templates.mdwn create mode 100644 doc/bugs/utf8_svn_log.mdwn create mode 100644 doc/bugs/utf8_warnings_are_meaningless.mdwn create mode 100644 doc/bugs/web_reversion_on_ikiwiki.info.mdwn create mode 100644 doc/bugs/websetup_eats_setupconf_and_allow__95__symlinks__95__before__95__srcdir.mdwn create mode 100644 doc/bugs/weird_signature_in_match__95__included__40____41__.mdwn create mode 100644 doc/bugs/weird_syntax_in_aggregate.pm.mdwn create mode 100644 doc/bugs/wiki_formatting_does_not_work_between_toc_and_an_inline.mdwn create mode 100644 doc/bugs/wiki_links_still_processed_inside_code_blocks.mdwn create mode 100644 doc/bugs/wiki_rebuild_should_throw_errors_if_the_configured_underlaydir_or_templatedir_don__39__t_exist.mdwn create mode 100644 doc/bugs/wikilink_in_table.mdwn create mode 100644 doc/bugs/word_wrap.mdwn create mode 100644 doc/bugs/wrapper_can__39__t_find_the_perl_modules.mdwn create mode 100644 doc/bugs/wrong_attachment_size.mdwn create mode 100644 doc/bugs/wrong_discussion_page_created.mdwn create mode 100644 doc/bugs/wrong_link_in_recentchanges_when_reverting_an_ikiwiki_outside_git_root.mdwn create mode 100644 doc/bugs/wrong_permissions_on_some_files_in_source.mdwn create mode 100644 doc/bugs/wrong_rss_url_when_inside_another_blog-like_page.mdwn create mode 100644 doc/bugs/xgettext_issue.mdwn create mode 100644 doc/bugs/yaml:xs_codependency_not_listed.mdwn create mode 100644 doc/bugs/yaml_setup_file_does_not_support_UTF-8_if_XS_is_installed.mdwn create mode 100644 doc/cgi.mdwn create mode 100644 doc/cgi/discussion.mdwn create mode 100644 doc/commit-internals.mdwn create mode 100644 doc/competition.mdwn create mode 100644 doc/consultants.mdwn create mode 100644 doc/contact.mdwn create mode 100644 doc/contact/discussion.mdwn create mode 100644 doc/convert.mdwn create mode 100644 doc/css.mdwn create mode 100644 doc/css/discussion.mdwn create mode 100644 doc/css_market.mdwn create mode 100644 doc/css_market/02_template.css create mode 100644 doc/css_market/02_template.tmpl create mode 100644 doc/css_market/bma.css create mode 100644 doc/css_market/cstamas.css create mode 100644 doc/css_market/discussion.mdwn create mode 100644 doc/css_market/embeddedmoose.css create mode 100644 doc/css_market/kirkambar.css create mode 100644 doc/css_market/zack.css create mode 100644 doc/download.mdwn create mode 100644 doc/examples.mdwn create mode 100644 doc/examples/blog.mdwn create mode 100644 doc/examples/blog/archives.mdwn create mode 100644 doc/examples/blog/comments.mdwn create mode 100644 doc/examples/blog/discussion.mdwn create mode 100644 doc/examples/blog/index.mdwn create mode 100644 doc/examples/blog/posts.mdwn create mode 100644 doc/examples/blog/posts/first_post.mdwn create mode 100644 doc/examples/blog/sidebar.mdwn create mode 100644 doc/examples/blog/tags.mdwn create mode 100644 doc/examples/softwaresite.mdwn create mode 100644 doc/examples/softwaresite/Makefile create mode 100644 doc/examples/softwaresite/bugs.mdwn create mode 100644 doc/examples/softwaresite/bugs/done.mdwn create mode 100644 doc/examples/softwaresite/bugs/fails_to_frobnicate.mdwn create mode 100644 doc/examples/softwaresite/bugs/hghg.mdwn create mode 100644 doc/examples/softwaresite/bugs/needs_more_bugs.mdwn create mode 100644 doc/examples/softwaresite/contact.mdwn create mode 100644 doc/examples/softwaresite/doc.mdwn create mode 100644 doc/examples/softwaresite/doc/faq.mdwn create mode 100644 doc/examples/softwaresite/doc/install.mdwn create mode 100644 doc/examples/softwaresite/doc/setup.mdwn create mode 100644 doc/examples/softwaresite/download.mdwn create mode 100644 doc/examples/softwaresite/index.mdwn create mode 100644 doc/examples/softwaresite/news.mdwn create mode 100644 doc/examples/softwaresite/news/version_1.0.mdwn create mode 100644 doc/examples/softwaresite/templates/release.mdwn create mode 100644 doc/favicon.ico create mode 100644 doc/features.mdwn create mode 100644 doc/forum.mdwn create mode 100644 doc/forum/404_-_not_found.mdwn create mode 100644 doc/forum/404_-_not_found/comment_1_3dea2600474f77fb986767da4d507d62._comment create mode 100644 doc/forum/404_-_not_found/comment_2_948e4678be6f82d9b541132405351a2c._comment create mode 100644 doc/forum/404_-_not_found/comment_3_4c7b1fa88776815bbc6aa286606214c2._comment create mode 100644 doc/forum/Accessing_meta_values_in_pages__63__.mdwn create mode 100644 doc/forum/Adding_a_custom_header_and_footer.mdwn create mode 100644 doc/forum/Adding_a_custom_header_and_footer/comment_1_e82dbfef77ff222a7fa07aab0a19fb18._comment create mode 100644 doc/forum/Adding_new_markup_to_markdown.mdwn create mode 100644 doc/forum/Allow_only_specific_OpenIDs_to_login.mdwn create mode 100644 doc/forum/Anyone_mirroring_ikiwiki_inline_feed_to_identi.ca__63__.mdwn create mode 100644 doc/forum/Anyone_mirroring_ikiwiki_inline_feed_to_identi.ca__63__/comment_1_8a5acbb6234104b607c8c4cf16124ae4._comment create mode 100644 doc/forum/Anyone_mirroring_ikiwiki_inline_feed_to_identi.ca__63__/comment_2_155e5823860a91989647ede8b5c9224a._comment create mode 100644 doc/forum/Anyone_mirroring_ikiwiki_inline_feed_to_identi.ca__63__/comment_3_317f1202a3da1bfc845d4becbac4bba8._comment create mode 100644 doc/forum/Apache_XBitHack.mdwn create mode 100644 doc/forum/Are_these_revisions_legit_or_accidentally_committed_jiberish__63__.mdwn create mode 100644 doc/forum/Are_these_revisions_legit_or_accidentally_committed_jiberish__63__/comment_1_b425823f800fba82ad2aaaa0dbe6686a._comment create mode 100644 doc/forum/Asciidoc_plugin.mdwn create mode 100644 doc/forum/Attachment_and_sub-directory.mdwn create mode 100644 doc/forum/Background_picture_and_css.mdwn create mode 100644 doc/forum/Blog_posting_times_and_ikiwiki_state.mdwn create mode 100644 doc/forum/Blog_posting_times_and_ikiwiki_state/comment_1_87304dfa2caea7e526cdb04917524e8c._comment create mode 100644 doc/forum/Broken_after_upgrading_Ikiwiki.mdwn create mode 100644 doc/forum/Broken_after_upgrading_Ikiwiki/comment_1_3d0588a845c58b3aedc35970e8dcc811._comment create mode 100644 doc/forum/Broken_after_upgrading_Ikiwiki/comment_2_fd65d4b87a735b67543bb0cf4053b652._comment create mode 100644 doc/forum/Broken_after_upgrading_Ikiwiki/comment_3_7c8b46eabdb25cbc01c56c7b53ed3b91._comment create mode 100644 doc/forum/CGI_script_and_HTTPS.mdwn create mode 100644 doc/forum/CGI_script_and_HTTPS/comment_1_3f8ef438ca7de11635d4e40080e7baa9._comment create mode 100644 doc/forum/Calendar:_listing_multiple_entries_per_day.mdwn create mode 100644 doc/forum/Calendar:_listing_multiple_entries_per_day/comment_1_d3dd0b97c63d615e3dee22ceacaa5a30._comment create mode 100644 doc/forum/Calendar:_listing_multiple_entries_per_day/comment_2_2311b96483bb91dc25d5e3695bbca513._comment create mode 100644 doc/forum/Calendar:_listing_multiple_entries_per_day/comment_3_d23f0cedd0b9e937eaf200eef55ac457._comment create mode 100644 doc/forum/Calendar:_listing_multiple_entries_per_day/comment_4_4be39c2043821848d4b25d0bf946a718._comment create mode 100644 doc/forum/Calendar:_listing_multiple_entries_per_day/comment_5_de545ebb6376066674ef2aaae4757b9c._comment create mode 100644 doc/forum/Can_I_change_the_default_menu_items__63__.mdwn create mode 100644 doc/forum/Can_I_change_the_default_menu_items__63__/comment_2_eb56fed3b5fc19c8dd49af4444a049c5._comment create mode 100644 doc/forum/Can_I_have_different_favicons_for_each_folder__63__.mdwn create mode 100644 doc/forum/Can_I_have_different_favicons_for_each_folder__63__/comment_1_a01112ba235e2f44a7655c36ef680e7e._comment create mode 100644 doc/forum/Can_I_have_different_favicons_for_each_folder__63__/comment_2_b8ccd3c29249eca73766f567bce12569._comment create mode 100644 doc/forum/Can_Ikiwiki_recognize_multimarkdown_meta_tags__63__.mdwn create mode 100644 doc/forum/Can_OpenID_users_be_adminusers__63__.mdwn create mode 100644 doc/forum/Can__39__t_call_method___34__distribution__34___on_an_undefined_value_at_FirstTime.pm.html create mode 100644 doc/forum/Can__39__t_get_comments_plugin_working.mdwn create mode 100644 doc/forum/Can__39__t_get_ikiwiki_working_again_after_reinstall.mdwn create mode 100644 doc/forum/Can__39__t_get_ikiwiki_working_again_after_reinstall/comment_1_87a360155ff0502fe08274911cc6a53f._comment create mode 100644 doc/forum/Can__39__t_login_using_Google__44___or_openID__44___but_can_use_Ikiwiki_login.mdwn create mode 100644 doc/forum/Can__39__t_login_using_Google__44___or_openID__44___but_can_use_Ikiwiki_login/comment_1_79127e3c09a1d798146088dee5a67708._comment create mode 100644 doc/forum/Can_custom_themes_live_somewhere_inside_srcdir__63__.mdwn create mode 100644 doc/forum/Can_custom_themes_live_somewhere_inside_srcdir__63__/comment_1_d1e79825dfb5213d2d1cba2ace1707b1._comment create mode 100644 doc/forum/Can_custom_themes_live_somewhere_inside_srcdir__63__/comment_2_8177ede5a586b1a573a13fd26f8d3cc0._comment create mode 100644 doc/forum/Can_ikiwiki_be_configured_as_multi_user_blog__63__.mdwn create mode 100644 doc/forum/Can_ikiwiki_be_configured_as_multi_user_blog__63__/comment_1_8e34b10699bed1b53b6c929ed1e9f19c._comment create mode 100644 doc/forum/Can_ikiwiki_be_configured_as_multi_user_blog__63__/comment_2_6083e16f72e12c03bdf739b84bd2f352._comment create mode 100644 doc/forum/Can_not_advance_past_first_page_of_results_using_search_plugin.mdwn create mode 100644 doc/forum/Can_one_tell_if_a_page_is_added_rather_than_changed__63__.mdwn create mode 100644 doc/forum/Can_one_tell_if_a_page_is_added_rather_than_changed__63__/comment_1_1397feebfb0fb7cc57af2f8b74ce047e._comment create mode 100644 doc/forum/Can_one_tell_if_a_page_is_added_rather_than_changed__63__/comment_2_ad36c945f59fe525428fc30246911ff5._comment create mode 100644 doc/forum/Can_someone_update_ikiwki_in_Macports__63__.mdwn create mode 100644 doc/forum/Can_someone_update_ikiwki_in_Macports__63__/comment_1_87365ded9b202607d6431daf4e76e3c1._comment create mode 100644 doc/forum/Cannot_write_to_commitlock.mdwn create mode 100644 doc/forum/Chinese_file_name_corruption.mdwn create mode 100644 doc/forum/Chinese_file_name_corruption/comment_1_765ac8b6f70083bb5aaaaac5beab461f._comment create mode 100644 doc/forum/Clarification_on_--cgi_option.mdwn create mode 100644 doc/forum/Clarification_on_--cgi_option/comment_1_deda457e4bff7dfe630dbc0192dfddea._comment create mode 100644 doc/forum/Commiting_all_moderated_comments_into_special_branch__63__.mdwn create mode 100644 doc/forum/Commiting_all_moderated_comments_into_special_branch__63__/comment_1_8403e8ff9c5c8dddb6d744632322f7bc._comment create mode 100644 doc/forum/Darcs_as_the_RCS___63__.mdwn create mode 100644 doc/forum/Debian_5.0.7:_Can__39__t_locate_IkiWiki__47__Setup__47__Automator.pm.mdwn create mode 100644 doc/forum/Debian_5.0.7:_Can__39__t_locate_IkiWiki__47__Setup__47__Automator.pm/comment_1_aec4bf4ca7d04d580d2fa83fd3f7166f._comment create mode 100644 doc/forum/Debian_5.0.7:_Can__39__t_locate_IkiWiki__47__Setup__47__Automator.pm/comment_4_c682ebb0e8e72088a8f92356dc31ef37._comment create mode 100644 doc/forum/Debian_squeeze_still_on_3.20100815.7_-_update_recommended__63__.mdwn create mode 100644 doc/forum/Debian_squeeze_still_on_3.20100815.7_-_update_recommended__63__/comment_1_5e916c8fa90470909064ea73531f79d4._comment create mode 100644 doc/forum/Debian_squeeze_still_on_3.20100815.7_-_update_recommended__63__/comment_2_2fa15f0eaf8c860b82e366130c8563c7._comment create mode 100644 doc/forum/Debian_squeeze_still_on_3.20100815.7_-_update_recommended__63__/comment_3_c5af589dcdfe4f91dba50243762065e5._comment create mode 100644 doc/forum/Debian_squeeze_still_on_3.20100815.7_-_update_recommended__63__/comment_4_3090da7bafbf92a825edec8ffc45af20._comment create mode 100644 doc/forum/Define_custom_commands.mdwn create mode 100644 doc/forum/Define_custom_commands/comment_1_7d82637bc8c706b69e4a55585677f6bf._comment create mode 100644 doc/forum/Different_behaviour_when_editing_with_editor_than_with_web-edit.mdwn create mode 100644 doc/forum/Different_behaviour_when_editing_with_editor_than_with_web-edit/comment_1_ac6bda46ad00bfe980bc76c4a39aa796._comment create mode 100644 doc/forum/Different_behaviour_when_editing_with_editor_than_with_web-edit/comment_3_10a46f8ee23c8935e20c70842671cee4._comment create mode 100644 doc/forum/Different_templates_for_subdirectories__63_____40__Blogging_and_Wiki_pages__41__.mdwn create mode 100644 doc/forum/Different_templates_for_subdirectories__63_____40__Blogging_and_Wiki_pages__41__/comment_1_15651796492a6f04a19f4a481947c97c._comment create mode 100644 doc/forum/Disable_account_creation_for_new_users.mdwn create mode 100644 doc/forum/Disable_account_creation_for_new_users/comment_1_adafddb0aff7c2c1f4574101c4cf9073._comment create mode 100644 doc/forum/Disable_account_creation_for_new_users/comment_2_865591f77966f1657a9a4b2426318c51._comment create mode 100644 doc/forum/Disable_account_creation_for_new_users/comment_3_05193e563682f634f13691ee0a8359db._comment create mode 100644 doc/forum/Discussion_PageSpec__63__.mdwn create mode 100644 doc/forum/Doing_related_links_based_on_tags.mdwn create mode 100644 doc/forum/Dot_CGI_pointing_to_localhost._What_happened__63__.mdwn create mode 100644 doc/forum/Dot_CGI_pointing_to_localhost._What_happened__63__/comment_1_cbab9b95923124b39cfccf5d2e88070c._comment create mode 100644 doc/forum/Dump_plugin.mdwn create mode 100644 doc/forum/Dump_plugin/comment_1_bfce80b3f5be78ec28692330843d4ae1._comment create mode 100644 doc/forum/Email_notifications_for_comment_moderation.mdwn create mode 100644 doc/forum/Email_notifications_for_comment_moderation/comment_1_668bf6a21310dcc8b882bc60a130ba06._comment create mode 100644 doc/forum/Empty_sha1sum_messages.mdwn create mode 100644 doc/forum/Empty_sha1sum_messages/comment_1_b260b5e6b4c4f4c203b01183fee9fd69._comment create mode 100644 doc/forum/Empty_sha1sum_messages/comment_2_d6a47838a3c81d0a75e6fc22e786c976._comment create mode 100644 doc/forum/Encoding_problem_in_french_with_ikiwiki-calendar.mdwn create mode 100644 doc/forum/Error:_CGI::tmpFileName_failed_to_return_the_uploaded_file_name.mdwn create mode 100644 doc/forum/Error:_CGI::tmpFileName_failed_to_return_the_uploaded_file_name/comment_1_66c321b9eb618d20872cee7d6ca9e44c._comment create mode 100644 doc/forum/Error:_CGI::tmpFileName_failed_to_return_the_uploaded_file_name/comment_2_80296d67c7f1dd75b56b85c14f5efa3b._comment create mode 100644 doc/forum/Error:___34__do__34___parameter_missing.mdwn create mode 100644 doc/forum/Error:___34__do__34___parameter_missing/comment_1_3a51c303ba1670f1567f323349b53837._comment create mode 100644 doc/forum/Error:___34__do__34___parameter_missing/comment_2_c5f24a8c4d2de0267cf0de1908480e82._comment create mode 100644 doc/forum/Error:_bad_page_name.mdwn create mode 100644 doc/forum/Error:_cannot_write_to___47__home__47__user__47__myiki2__47__.ikiwiki__47__lockfile:_Permission_denied_.mdwn create mode 100644 doc/forum/Error:_cannot_write_to___47__home__47__user__47__myiki2__47__.ikiwiki__47__lockfile:_Permission_denied_/comment_1_64146f306ec8c10614521359b6de4f82._comment create mode 100644 doc/forum/Error:_cannot_write_to___47__home__47__user__47__myiki2__47__.ikiwiki__47__lockfile:_Permission_denied_/comment_2_ed2b4b8f7122b42bbde1189fbd2969dd._comment create mode 100644 doc/forum/Error_Code_1.mdwn create mode 100644 doc/forum/Error_Code_1/comment_1_0459afcc383aad382df67a19eaf2e731._comment create mode 100644 doc/forum/Error___34__is_locked_and_cannot_be_edited__34__.mdwn create mode 100644 doc/forum/Error___34__is_locked_and_cannot_be_edited__34__/comment_1_dc99a921813d4f8adf797a900ee0a2c1._comment create mode 100644 doc/forum/Error___34__is_locked_and_cannot_be_edited__34__/comment_2_48daf77f097ed94bf78cf97b0c027129._comment create mode 100644 doc/forum/Everyone_can_remove_comments.mdwn create mode 100644 doc/forum/Export_images_when_building_the_wiki.mdwn create mode 100644 doc/forum/Export_images_when_building_the_wiki/comment_1_f7328be9b201f3eea6b90c269781fd0b._comment create mode 100644 doc/forum/Export_images_when_building_the_wiki/comment_2_99a592c8ff9d2c2094132edd27356922._comment create mode 100644 doc/forum/Export_images_when_building_the_wiki/comment_3_7f5a1ef639453c83748405d2b3b0b880._comment create mode 100644 doc/forum/Export_images_when_building_the_wiki/comment_4_bd3b37fbee54f1bf510ef5fc6ba27e55._comment create mode 100644 doc/forum/File_wiki.setup.mdwn create mode 100644 doc/forum/Flowplayer.mdwn create mode 100644 doc/forum/Flowplayer/comment_1_75d13cd915a736422db47e00dbe46671._comment create mode 100644 doc/forum/Flowplayer/comment_2_1b2d3891006a87a4773bd126baacddfc._comment create mode 100644 doc/forum/Force_rebuild_of_page_using_some_plugin.mdwn create mode 100644 doc/forum/Formatting_algorithms.mdwn create mode 100644 doc/forum/Forward_slashes_being_escaped_as_252F.mdwn create mode 100644 doc/forum/Forward_slashes_being_escaped_as_252F/comment_1_7702cf6d354ab600d6643b075b9f09da._comment create mode 100644 doc/forum/Google_searches_of_ikiwiki.info_are_broken._:__40__.mdwn create mode 100644 doc/forum/Have_creation_time_for_new_pages_fetched_from_the_VCS.mdwn create mode 100644 doc/forum/Have_creation_time_for_new_pages_fetched_from_the_VCS/comment_1_9572dd6f7a2f6f630b12f24bb5c4a8ce._comment create mode 100644 doc/forum/Help_with_tag__95__autocreate.mdwn create mode 100644 doc/forum/Hide_text.mdwn create mode 100644 doc/forum/Hide_text/comment_1_f21d21c130f97a7b21d8a317178e2e0c._comment create mode 100644 doc/forum/Hide_text/comment_2_5a878865f34f78a89c4ec91a9425a085._comment create mode 100644 doc/forum/How_best_to_manage_a_bilingual_ikiwiki_site__63__.mdwn create mode 100644 doc/forum/How_best_to_manage_a_bilingual_ikiwiki_site__63__/comment_1_4389d65b14fa1b7134098e0ffe3bf055._comment create mode 100644 doc/forum/How_can_I_invert_the_banned__95__user_check__63__.mdwn create mode 100644 doc/forum/How_can_I_prevent_spam__63__.mdwn create mode 100644 doc/forum/How_can_I_prevent_spam__63__/comment_1_fd26fb7f1569e8c44ba8262794f938db._comment create mode 100644 doc/forum/How_can_I_prevent_spam__63__/comment_2_d098124f005976ee815d25c883bc9106._comment create mode 100644 doc/forum/How_can_I_prevent_spam__63__/comment_3_deb434d01aaefa18d2791e48d6c824ae._comment create mode 100644 doc/forum/How_do_I_enable_OpenID__63__.mdwn create mode 100644 doc/forum/How_does_ikiwiki_remember_times__63__.mdwn create mode 100644 doc/forum/How_is_TITLE_evaluated_in_inline_archive_templates__63__.mdwn create mode 100644 doc/forum/How_long_does_server_delay_newly_pushed_revisions__63__.mdwn create mode 100644 doc/forum/How_to_add_a_mouse-over_pop-up_label_for_a_text__63__.mdwn create mode 100644 doc/forum/How_to_add_additional_links_to_the_gray_horizontable_bar_under_page_title__63__.mdwn create mode 100644 doc/forum/How_to_add_additional_links_to_the_gray_horizontable_bar_under_page_title__63__/comment_1_f2e52d38f60888c7d5142de853123540._comment create mode 100644 doc/forum/How_to_add_link_to_previous_and_next_blog_on_blog_pages__63__.mdwn create mode 100644 doc/forum/How_to_add_link_to_previous_and_next_blog_on_blog_pages__63__/comment_1_aad510f45be505efaabcb6fb860665a4._comment create mode 100644 doc/forum/How_to_add_link_to_previous_and_next_blog_on_blog_pages__63__/comment_2_ee65792a5b796caa216f4e7a653fc668._comment create mode 100644 doc/forum/How_to_allow_.markdown_and_.md_at_the_same_time_as_valid_extensions_for_source_files__63__.mdwn create mode 100644 doc/forum/How_to_apply_a_background_color_to_a_page__63__.mdwn create mode 100644 doc/forum/How_to_change_registration_page.mdwn create mode 100644 doc/forum/How_to_change_registration_page/comment_1_43758a232e4360561bc84f710862ff40._comment create mode 100644 doc/forum/How_to_change_registration_page/comment_2_8176ef231cf901802fc60b6d414018e6._comment create mode 100644 doc/forum/How_to_configure_po_plugin__63__.mdwn create mode 100644 doc/forum/How_to_configure_po_plugin__63__/comment_1_5e0cc4cdfd126f2f4af64104f02102d6._comment create mode 100644 doc/forum/How_to_create_a_WikiLink_to_a_page_in_a_subdirectory__63__.mdwn create mode 100644 doc/forum/How_to_create_a_WikiLink_to_a_page_in_a_subdirectory__63__/comment_1_d20ee1d8d7a3e77a445f8b887e807119._comment create mode 100644 doc/forum/How_to_create_first_translation_page_using_po_plugin__63__.mdwn create mode 100644 doc/forum/How_to_customize_page_title__63__.mdwn create mode 100644 doc/forum/How_to_customize_page_title__63__/comment_1_403e1f866b5e04e5899021f54bbdd1ed._comment create mode 100644 doc/forum/How_to_disable___34__Add_a_new_post_titled:__34___submission_form__63__.mdwn create mode 100644 doc/forum/How_to_disable___34__Add_a_new_post_titled:__34___submission_form__63__/comment_1_3dfa9ac6473d0d5ebc9d99ec39e96216._comment create mode 100644 doc/forum/How_to_fix___34__does_not_map_to_Unicode__34___errors__63__.mdwn create mode 100644 doc/forum/How_to_format___91____91__foobar__93____93___in_code_blocks__63__.mdwn create mode 100644 doc/forum/How_to_format___91____91__foobar__93____93___in_code_blocks__63__/comment_1_ad000d39fd1dc05aa8ef6eb19d8d999b._comment create mode 100644 doc/forum/How_to_generate_blog_archive_pages_in___47__blog_subdir_but_not_ikiwiki_root_path__63__.mdwn create mode 100644 doc/forum/How_to_inline_a_page_from_another_git_repository.mdwn create mode 100644 doc/forum/How_to_list_all_pages_in_a_wiki_instance__63__.mdwn create mode 100644 doc/forum/How_to_list_all_pages_in_a_wiki_instance__63__/comment_1_920bcc70fe6d081cf27aa2cc7c6136f4._comment create mode 100644 doc/forum/How_to_list_new_pages__44___inline__63__.mdwn create mode 100644 doc/forum/How_to_list_new_pages__44___inline__63__/comment_1_e989b18bade34a92a9c8fe7099036e15._comment create mode 100644 doc/forum/How_to_lock_all_pages_except_discussions_and_comments_to_blog_posts__63__.mdwn create mode 100644 doc/forum/How_to_lock_all_pages_except_discussions_and_comments_to_blog_posts__63__/comment_1_e153beb17b6ada69c6ab09d1f491d112._comment create mode 100644 doc/forum/How_to_make_a_table_of_content_at_the_top_of_page__63__.mdwn create mode 100644 doc/forum/How_to_make_a_table_of_content_at_the_top_of_page__63__/comment_1_6dedc31dd1145490bb5fa4ad14cc4c63._comment create mode 100644 doc/forum/How_to_migrate_multiple_pages_in_root_directory_into_a_new_subdirectory__63__.mdwn create mode 100644 doc/forum/How_to_migrate_multiple_pages_in_root_directory_into_a_new_subdirectory__63__/comment_1_a83a1a33afbf245971733b4128809365._comment create mode 100644 doc/forum/How_to_properly_create_--_in_a_wiki_--____39__page__47__index.html__39___files.mdwn create mode 100644 doc/forum/How_to_properly_create_--_in_a_wiki_--____39__page__47__index.html__39___files/comment_1_d9ee358ded5d5307ba73a8c11f81549d._comment create mode 100644 doc/forum/How_to_remove_the_linebreak_in_license.mdwn create mode 100644 doc/forum/How_to_rename_all_markdown_files_from___42__.mdwn_to___42__.md__63__.mdwn create mode 100644 doc/forum/How_to_rename_all_markdown_files_from___42__.mdwn_to___42__.md__63__/comment_1_c2720ebfe56ad816f241693d9e2e5072._comment create mode 100644 doc/forum/How_to_set_the_meta_author_field_from_user_name__63__.mdwn create mode 100644 doc/forum/How_to_set_the_meta_author_field_from_user_name__63__/comment_1_0906e1f3eb8b826a7730233b95cb5ddd._comment create mode 100644 doc/forum/How_to_set_up_a_page_as_internal__63__.mdwn create mode 100644 doc/forum/How_to_set_up_git_repository_hook___63__.mdwn create mode 100644 doc/forum/How_to_show_recent_changes_for_individual_pages__63__.mdwn create mode 100644 doc/forum/How_to_show_recent_changes_for_individual_pages__63__/comment_1_cd34affc6883f4e4bc5e7e7b711cc8ba._comment create mode 100644 doc/forum/How_to_specify_repository_is_on_a_remote_host__63__.mdwn create mode 100644 doc/forum/How_to_specify_repository_is_on_a_remote_host__63__/comment_1_0c71e17ae552cbab1056ac96fbd36c59._comment create mode 100644 doc/forum/How_to_specify_repository_is_on_a_remote_host__63__/comment_2_b309302a084fbd8bcd4cd9bd2509cf5a._comment create mode 100644 doc/forum/How_to_style_main_sidebar_and_SubPage_sidebar_differently_using_CSS__63__.mdwn create mode 100644 doc/forum/How_to_suppress_sidebar_for_a_particular_page__63__.mdwn create mode 100644 doc/forum/How_to_use___126____47__bin__47__multimarkdown_instead_of_Text::MultiMarkdown.mdwn create mode 100644 doc/forum/How_to_use_number_as_bullet_labels_but_not_letter_in_toc_plugin.mdwn create mode 100644 doc/forum/Howto_add_tag_from_plugin_code.mdwn create mode 100644 doc/forum/Howto_add_tag_from_plugin_code/comment_1_c61454825874a6fe1905cb549386deb0._comment create mode 100644 doc/forum/I_do_not_know_anything_abut_git.mdwn create mode 100644 doc/forum/I_do_not_know_anything_abut_git/comment_1_2efdf8563bcdeba73b11282157aba72d._comment create mode 100644 doc/forum/I_do_not_know_anything_abut_git/comment_2_3dd0fa0612a5fac785cc7d5ea23d42a5._comment create mode 100644 doc/forum/If_there__39__s_no_Windows_ikiwiki__44___how_about_a_WYSIWYG_ikiwiki_editor_for_Windows__63__.mdwn create mode 100644 doc/forum/If_there__39__s_no_Windows_ikiwiki__44___how_about_a_WYSIWYG_ikiwiki_editor_for_Windows__63__/comment_1_a66fd9d7ab4359784a5420cd899a1057._comment create mode 100644 doc/forum/If_there__39__s_no_Windows_ikiwiki__44___how_about_a_WYSIWYG_ikiwiki_editor_for_Windows__63__/comment_2_3351ff773fea3f640f4036bb8c7c7efd._comment create mode 100644 doc/forum/If_there__39__s_no_Windows_ikiwiki__44___how_about_a_WYSIWYG_ikiwiki_editor_for_Windows__63__/comment_3_273b2b63a9af2bc4eeb030e026436687._comment create mode 100644 doc/forum/If_there__39__s_no_Windows_ikiwiki__44___how_about_a_WYSIWYG_ikiwiki_editor_for_Windows__63__/comment_4_546771c13ea1b550301586e187d82cb5._comment create mode 100644 doc/forum/Ikiwiki_CGI_not_working_on_my_server__44___and_it__39__s_a_binary_file__63__.mdwn create mode 100644 doc/forum/Ikiwiki_themes_for_mobile_devices__63__.mdwn create mode 100644 doc/forum/Include_attachment_in_a_page.mdwn create mode 100644 doc/forum/Include_attachment_in_a_page/comment_1_275aad6ca3b2972749b7f6636b130035._comment create mode 100644 doc/forum/Is_it_possible_to_change_default_mdwn_suffix__63__.mdwn create mode 100644 doc/forum/Is_it_possible_to_change_default_mdwn_suffix__63__/comment_1_2a449c6017ecdb4f557963266fb4ec41._comment create mode 100644 doc/forum/Is_there_a_pagespec_for_creation_dates_relative_to_today__63__.mdwn create mode 100644 doc/forum/LaTeX_Error.mdwn create mode 100644 doc/forum/Last_visited_pages.mdwn create mode 100644 doc/forum/Last_visited_pages/comment_1_e34650064dd645b35da98e80c0311df9._comment create mode 100644 doc/forum/Last_visited_pages/comment_2_2a0c4e844da1deaa2c286e87c8eab84d._comment create mode 100644 doc/forum/Link_to_a_local_pdf_file.mdwn create mode 100644 doc/forum/Link_to_a_local_pdf_file/comment_1_b6c57588042373f8e1f187041c1a8530._comment create mode 100644 doc/forum/Log_in_error.mdwn create mode 100644 doc/forum/Log_in_error/comment_1_0ef13ea01a413160d81951636c15c3e6._comment create mode 100644 doc/forum/Map_Plugin__44___would_like_to_add___63__updated_to_all_links.mdwn create mode 100644 doc/forum/Map_Plugin__44___would_like_to_add___63__updated_to_all_links/comment_1_3fe4c5967e704355f9b594aed46baf67._comment create mode 100644 doc/forum/Migrated_ikiwiki_to_new_host._Web_page_is_not_updated.mdwn create mode 100644 doc/forum/Migrated_ikiwiki_to_new_host._Web_page_is_not_updated/comment_2_b44a492c7f10395a31f3c0830ef33f0c._comment create mode 100644 doc/forum/Migrated_ikiwiki_to_new_host._Web_page_is_not_updated/comment_2_f9240b217b2d1ee8d51dada9cb1186b3._comment create mode 100644 doc/forum/Migrated_ikiwiki_to_new_host._Web_page_is_not_updated/comment_3_c3c5c41a4c220793c6d16f3fd6132272._comment create mode 100644 doc/forum/Migrated_ikiwiki_to_new_host._Web_page_is_not_updated/comment_4_1f6f9e3939a454c1eb8d2fb29bd519de._comment create mode 100644 doc/forum/Migrated_ikiwiki_to_new_host._Web_page_is_not_updated/comment_5_8611fc62797e70a0d2a61d94fcb03170._comment create mode 100644 doc/forum/Migrating_old_repository_to_new_ikiwiki_system__63__.mdwn create mode 100644 doc/forum/Migrating_old_repository_to_new_ikiwiki_system__63__/comment_1_e5ce524c5d34b1d4218172296bd99100._comment create mode 100644 doc/forum/Migrating_old_repository_to_new_ikiwiki_system__63__/comment_3_65c4a4895f6541ff0ff2d094ff447bba._comment create mode 100644 doc/forum/Moving_wiki.git_folder__63__.mdwn create mode 100644 doc/forum/Moving_wiki.git_folder__63__/comment_1_05238461520613f4ed1b0d02ece663bd._comment create mode 100644 doc/forum/Moving_wiki.git_folder__63__/comment_2_72b2b842dfa0cfaf899fe7af12977519._comment create mode 100644 doc/forum/Multiple_urls.mdwn create mode 100644 doc/forum/Multiple_urls/comment_1_e4c1256346d5a421161c20e344d8bada._comment create mode 100644 doc/forum/Need_help_installing_h1title_plugin.mdwn create mode 100644 doc/forum/Need_help_setting_up_ikiwiki_CGI.mdwn create mode 100644 doc/forum/Need_help_setting_up_ikiwiki_CGI/comment_1_0fc4573568711c56a0df4af620110c2f._comment create mode 100644 doc/forum/Need_help_setting_up_ikiwiki_CGI/comment_3_89f2cd7d874a6257786478e4cae1e2bc._comment create mode 100644 doc/forum/Need_help_setting_up_ikiwiki_CGI/comment_3_cbc20267fe5f0531f63db881d50596d1._comment create mode 100644 doc/forum/Need_help_setting_up_ikiwiki_CGI/comment_4_2eaf53935eecd0a918755d728450a642._comment create mode 100644 doc/forum/Need_some_help_on_starting_to_use_po_plugin_for_creating_pages_in_multiple_languages.mdwn create mode 100644 doc/forum/Need_something_more_powerful_than_Exclude.mdwn create mode 100644 doc/forum/Need_something_more_powerful_than_Exclude/comment_2_0019cd6b34c8d8678b2532de57a92d15._comment create mode 100644 doc/forum/Need_something_more_powerful_than_Exclude/comment_2_f577ab6beb9912471949d8d18c790267._comment create mode 100644 doc/forum/Need_something_more_powerful_than_Exclude/comment_3_1ed260b0083a290688425a006a83f603._comment create mode 100644 doc/forum/Need_something_more_powerful_than_Exclude/comment_4_c39bdaf38e1e20db74eb26f0560bd673._comment create mode 100644 doc/forum/Need_something_more_powerful_than_Exclude/comment_5_39b01857f7e0b388a6e7a3c1cf5388d5._comment create mode 100644 doc/forum/Need_something_more_powerful_than_Exclude/comment_6_1dccdfebad31446200213a2cae25f0e2._comment create mode 100644 doc/forum/News_site_where_articles_are_submitted_and_then_reviewed_before_posting.mdwn create mode 100644 doc/forum/OpenID_not_working___47___where_to_define_wiki__39__s_ID__63__.mdwn create mode 100644 doc/forum/OpenID_not_working___47___where_to_define_wiki__39__s_ID__63__/comment_1_bf1bec748d6ab419276a73a7001024cf._comment create mode 100644 doc/forum/OpenID_not_working___47___where_to_define_wiki__39__s_ID__63__/comment_2_14a1b269be6dbcc9b2068d3e18b55711._comment create mode 100644 doc/forum/OpenID_not_working___47___where_to_define_wiki__39__s_ID__63__/comment_3_f581afcdb4481ea5d65bcc33bdbab99a._comment create mode 100644 doc/forum/OpenID_not_working___47___where_to_define_wiki__39__s_ID__63__/comment_4_b0d39d30852bca1525ab9612a7532670._comment create mode 100644 doc/forum/PERL5LIB__44___wrappers_and_homedir_install.mdwn create mode 100644 doc/forum/PageSpec_results_from_independent_checkout.mdwn create mode 100644 doc/forum/Parent_Links_all_link_to_root.mdwn create mode 100644 doc/forum/Parent_Links_all_link_to_root/comment_1_4b5ed25cceb7740f64ee08aba00a1d91._comment create mode 100644 doc/forum/Perhaps_I__39__m_doing_it_wrong_-_tracking_non-post_files_in_a_blog.mdwn create mode 100644 doc/forum/Perhaps_I__39__m_doing_it_wrong_-_tracking_non-post_files_in_a_blog/comment_1_45ecaf6efa2065837fa54a42737f0a66._comment create mode 100644 doc/forum/Perhaps_I__39__m_doing_it_wrong_-_tracking_non-post_files_in_a_blog/comment_2_45ca7ef4190c281d703c8c7ca6979298._comment create mode 100644 doc/forum/Possible_to_use_meta_variables_in_templates__63__.mdwn create mode 100644 doc/forum/Possible_to_use_meta_variables_in_templates__63__/comment_1_556078a24041289d8f0b7ee756664690._comment create mode 100644 doc/forum/Possible_to_use_meta_variables_in_templates__63__/comment_2_e7e954218d39bc310015b95aa1a5212c._comment create mode 100644 doc/forum/Possible_to_use_meta_variables_in_templates__63__/comment_3_8b16c563c89eb6980ad6a5539d934d7a._comment create mode 100644 doc/forum/Possible_to_use_meta_variables_in_templates__63__/comment_4_76eadf93cce4e2168960131d4677c5fc._comment create mode 100644 doc/forum/Possible_to_use_meta_variables_in_templates__63__/comment_5_ddabe4a005042d19c7669038b49275c1._comment create mode 100644 doc/forum/Problem_with_gitweb.mdwn create mode 100644 doc/forum/Problem_with_gitweb/comment_2_23cc0d87448d3cbdac20a005e9191589._comment create mode 100644 doc/forum/Problem_with_gitweb/comment_3_697c6038009249e6a49d9e458a5ba271._comment create mode 100644 doc/forum/Problem_with_gitweb/comment_3_6a5b96f7e0d6b169c090e3df7281d938._comment create mode 100644 doc/forum/Problem_with_gitweb/comment_5_8a79b879205bd265d54e30f0eee2ac63._comment create mode 100644 doc/forum/Problem_with_local_git_commit.mdwn create mode 100644 doc/forum/Processing_non-pages.mdwn create mode 100644 doc/forum/Recent_changes_on_main_site_or_on_a_sidebar.mdwn create mode 100644 doc/forum/Recent_changes_on_main_site_or_on_a_sidebar/comment_1_018b977ff7ee59fc53838e0c20c3a9a7._comment create mode 100644 doc/forum/Recent_changes_on_main_site_or_on_a_sidebar/comment_2_927c11f18315baa39f08ca4982ed2ab1._comment create mode 100644 doc/forum/Refresh_or_recreate_style.css__63__.mdwn create mode 100644 doc/forum/Refresh_or_recreate_style.css__63__/comment_1_3274be931d0b543c7f7cf641810817aa._comment create mode 100644 doc/forum/Regex_for_Valid_Characters_in_Filenames.mdwn create mode 100644 doc/forum/Remove_tags_and_backlinks_on_particular_pages__63__.mdwn create mode 100644 doc/forum/Render_more_than_one_dest_page_from_same_source_page.mdwn create mode 100644 doc/forum/Revision_history_for_single_pages.mdwn create mode 100644 doc/forum/Revision_history_for_single_pages/comment_1_d509d5d726cd7eab9472d723013f5ec4._comment create mode 100644 doc/forum/Revision_history_for_single_pages/comment_2_d39a6177fc4c1e3c3c2c4e2592be9e3d._comment create mode 100644 doc/forum/Revision_history_for_single_pages/comment_3_aecf2b031ace001afaa2a0f2b5f50c82._comment create mode 100644 doc/forum/Right-to-left_support.mdwn create mode 100644 doc/forum/Right-to-left_support/comment_1_5b2bf4d037ae8db940296e6f58884927._comment create mode 100644 doc/forum/Run_script_on_markdown_source.mdwn create mode 100644 doc/forum/See_rendered_old_revisions_via_pagehistory.mdwn create mode 100644 doc/forum/Setting_http__95__proxy.mdwn create mode 100644 doc/forum/Setting_http__95__proxy/comment_1_350a7c4834c9f422e107b646cdbae3b0._comment create mode 100644 doc/forum/Setting_template_variable_from_config_file__63__.mdwn create mode 100644 doc/forum/Setting_template_variable_from_config_file__63__/comment_1_bb4b5a7a49f33d660b5116fc0ce3c92d._comment create mode 100644 doc/forum/Setting_up_a_development_environment.mdwn create mode 100644 doc/forum/Should_files_in_.ikiwiki_be_committed_and_pushed__63__.mdwn create mode 100644 doc/forum/Should_files_in_.ikiwiki_be_committed_and_pushed__63__/comment_1_8e65d7d8298e3c31d2a16446a71c8049._comment create mode 100644 doc/forum/Should_not_create_an_existing_page.mdwn create mode 100644 doc/forum/Sidebar_with_links__63__.mdwn create mode 100644 doc/forum/Slow_ikiwiki_after_first_run.mdwn create mode 100644 doc/forum/Spaces_in_URLs.mdwn create mode 100644 doc/forum/Spaces_in_wikilinks.mdwn create mode 100644 doc/forum/Split_a_wiki.mdwn create mode 100644 doc/forum/Split_a_wiki/comment_1_1599c26891b2071a2f1ca3fd90627fc4._comment create mode 100644 doc/forum/Split_a_wiki/comment_2_1c54d3594f0350340f8dfb3e95c29ffd._comment create mode 100644 doc/forum/Split_a_wiki/comment_3_9eac1d1b93df27d849acc574b1f0f26d._comment create mode 100644 doc/forum/Split_a_wiki/comment_4_e193ba447c0188f72ba589180b5d529e._comment create mode 100644 doc/forum/TMPL__95__VAR_IS__95__ADMIN.mdwn create mode 100644 doc/forum/TMPL__95__VAR_IS__95__ADMIN/comment_1_3172568473e9b79ad7ab623afd19411a._comment create mode 100644 doc/forum/TMPL__95__VAR_IS__95__ADMIN/comment_2_4302d56a6fe68d17cc42d26e6f3566c2._comment create mode 100644 doc/forum/TMPL__95__VAR_IS__95__ADMIN/comment_3_4cc44e61b9c28a2d524fa874f115041a._comment create mode 100644 doc/forum/TMPL__95__VAR_IS__95__ADMIN/comment_4_33143bad68f3f6beae963a3d0ec5d0bd._comment create mode 100644 doc/forum/TMPL__95__VAR_IS__95__ADMIN/comment_5_ef790766456d723670f52cc9e3955e90._comment create mode 100644 doc/forum/TMPL__95__VAR_IS__95__ADMIN/comment_6_3db50264e01c8fad2e5567b5a9c7b6dc._comment create mode 100644 doc/forum/TMPL__95__VAR_IS__95__ADMIN/comment_7_bdc5c96022fdb8826b57d68a41ef6ca0._comment create mode 100644 doc/forum/Template_variables.mdwn create mode 100644 doc/forum/Template_variables/comment_1_6a2ab9450dbfb8c4ef78e7af2a1b51eb._comment create mode 100644 doc/forum/Template_variables/comment_2_9b366736171e45d5afd8247ff38501d1._comment create mode 100644 doc/forum/Template_variables/comment_3_727f8a407dc57e4abf48cdcec4ead666._comment create mode 100644 doc/forum/The_requested_URL___47____126__jean__47__blog__47__ikiwiki.cgi_was_not_found_on_this_server..mdwn create mode 100644 doc/forum/The_requested_URL___47____126__jean__47__blog__47__ikiwiki.cgi_was_not_found_on_this_server./comment_1_d36ce6fab90e0a086ac84369af38d205._comment create mode 100644 doc/forum/The_requested_URL___47____126__jean__47__blog__47__ikiwiki.cgi_was_not_found_on_this_server./comment_2_5836bba08172d2ddf6a43da87ebb0332._comment create mode 100644 doc/forum/The_requested_URL___47____126__jean__47__blog__47__ikiwiki.cgi_was_not_found_on_this_server./comment_3_4eec15c8c383275db5401c8e3c2d9242._comment create mode 100644 doc/forum/The_requested_URL___47____126__jean__47__blog__47__ikiwiki.cgi_was_not_found_on_this_server./comment_4_43ac867621efb68affa6ae2b92740cad._comment create mode 100644 doc/forum/The_requested_URL___47____126__jean__47__blog__47__ikiwiki.cgi_was_not_found_on_this_server./comment_5_e098723bb12adfb91ab561cae21b492b._comment create mode 100644 doc/forum/The_requested_URL___47____126__jean__47__blog__47__ikiwiki.cgi_was_not_found_on_this_server./comment_6_101183817ca4394890bd56a7694bedd9._comment create mode 100644 doc/forum/The_requested_URL___47____126__jean__47__blog__47__ikiwiki.cgi_was_not_found_on_this_server./comment_7_2f514e6ba78d43d90e7ff4ae387e65e0._comment create mode 100644 doc/forum/The_requested_URL___47____126__jean__47__blog__47__ikiwiki.cgi_was_not_found_on_this_server./comment_8_098bb7a3112751a7e6167483dde626bb._comment create mode 100644 doc/forum/The_requested_URL___47____126__jean__47__blog__47__ikiwiki.cgi_was_not_found_on_this_server./comment_9_fbf403255c38da93caa5b98589fbb285._comment create mode 100644 doc/forum/Trail_plugin_links_with_Actiontabs_theme.mdwn create mode 100644 doc/forum/Translating_ikiwiki_interface.mdwn create mode 100644 doc/forum/Upgrade_steps_from_RecentChanges_CGI_to_static_page.mdwn create mode 100644 doc/forum/Using_reverse_proxy__59___base_URL_is_http_instead_of_https.mdwn create mode 100644 doc/forum/Using_reverse_proxy__59___base_URL_is_http_instead_of_https/comment_1_ef4be9e70bd6d8c970fd8982f525d2d0._comment create mode 100644 doc/forum/Using_reverse_proxy__59___base_URL_is_http_instead_of_https/comment_2_00fee67cc30b7c337710b37c27216a68._comment create mode 100644 doc/forum/Using_reverse_proxy__59___base_URL_is_http_instead_of_https/comment_3_f402fb426e0460ce927b7847246f699f._comment create mode 100644 doc/forum/Using_reverse_proxy__59___base_URL_is_http_instead_of_https/comment_4_db726bc81ec5feac76d17ea81f0f80a5._comment create mode 100644 doc/forum/Using_reverse_proxy__59___base_URL_is_http_instead_of_https/comment_5_674f56100c0682eba36cc5327fbdae4a._comment create mode 100644 doc/forum/Various_ways_to_use_Subversion_with_ikiwiki.mdwn create mode 100644 doc/forum/What__39__s_the_difference_between_tag_and_taglink__63__.mdwn create mode 100644 doc/forum/What__39__s_the_difference_between_tag_and_taglink__63__/comment_1_b3553d65d12af4c4a87f1f66f961c8d9._comment create mode 100644 doc/forum/What_is_wrong_with_my_recentchange_page___63__.mdwn create mode 100644 doc/forum/When_do_tags_like_a__47__b_get_listed_as_a__47__b_and_not_only_b__63__.mdwn create mode 100644 doc/forum/When_do_tags_like_a__47__b_get_listed_as_a__47__b_and_not_only_b__63__/comment_1_cd5ea3aac8a59793ece5bf01a6190b53._comment create mode 100644 doc/forum/Wikilink_to_a_symbolic_link.mdwn create mode 100644 doc/forum/Wikilink_to_a_symbolic_link/comment_1_e3ad5099491e0c84cd7729eba82ce552._comment create mode 100644 doc/forum/Wikilink_to_a_symbolic_link/comment_2_46848020b1e3d0cd55bc1ec0ba382aad._comment create mode 100644 doc/forum/Wikilink_to_section_of_a_wikipage.mdwn create mode 100644 doc/forum/Wikilink_to_section_of_a_wikipage/comment_1_c1409a3c07dfc4ed7274560c962aba75._comment create mode 100644 doc/forum/Wikilink_to_section_of_a_wikipage/comment_2_8a04eb7b0d7f17b9e5bb4cd04ba45871._comment create mode 100644 doc/forum/Xapian_search:_empty_postlist_table.mdwn create mode 100644 doc/forum/Xapian_search:_empty_postlist_table/comment_1_de9a7c94beec2707eda0924ca58be9df._comment create mode 100644 doc/forum/Xapian_search:_empty_postlist_table/comment_2_55f191e4b1306a318a30319f01802229._comment create mode 100644 doc/forum/Xapian_search:_empty_postlist_table/comment_3_0bd424a89c3a52ff393a1e7e00c806be._comment create mode 100644 doc/forum/Xapian_search:_empty_postlist_table/comment_4_40479ac2cfbca609f5f423e539a20ee0._comment create mode 100644 doc/forum/Xapian_search:_empty_postlist_table/comment_5_397443138da276e11c2e9b9fa7b51406._comment create mode 100644 doc/forum/Xapian_search:_empty_postlist_table/comment_6_3cd94b9a141ebbf96fcba4ebe99e1453._comment create mode 100644 doc/forum/Your_local_changes_to_the_following_files_would_be_overwritten_by_merge:.mdwn create mode 100644 doc/forum/Your_local_changes_to_the_following_files_would_be_overwritten_by_merge:/comment_1_2223c8b463b22a9dab53b71c01b67209._comment create mode 100644 doc/forum/Your_local_changes_to_the_following_files_would_be_overwritten_by_merge:/comment_2_2466ce4303f5b8145bdfae23b6dbddda._comment create mode 100644 doc/forum/__34__Error:_cannot_decode_string_with_wide_characters__34___on_Mageia_Linux_x86-64_Cauldron.mdwn create mode 100644 doc/forum/__34__Error:_cannot_decode_string_with_wide_characters__34___on_Mageia_Linux_x86-64_Cauldron/comment_1_abf7ec7c378ab0908685d72d159e9fd2._comment create mode 100644 doc/forum/__42__.html_source_file_containing___60__script__62__...__60____47__script__62___not_working__63__.mdwn create mode 100644 doc/forum/__42__.html_source_file_containing___60__script__62__...__60____47__script__62___not_working__63__/comment_1_953bd716373dcf51fa444ac098b7f971._comment create mode 100644 doc/forum/__42__.html_source_file_containing___60__script__62__...__60____47__script__62___not_working__63__/comment_2_c7360852f9bf069f28c193373333c9a8._comment create mode 100644 doc/forum/__42__.html_source_file_containing___60__script__62__...__60____47__script__62___not_working__63__/comment_3_6ffc30e27387366b48112198b66c01fa._comment create mode 100644 doc/forum/access_restrictions:_for_extranet.mdwn create mode 100644 doc/forum/access_restrictions:_for_extranet/comment_1_a0666c3c15661fb0fff70f313cd0d47d._comment create mode 100644 doc/forum/access_restrictions:_for_extranet/comment_2_563040aa099c9366dc5701eb4bc9c10d._comment create mode 100644 doc/forum/an_alternative_approach_to_structured_data.mdwn create mode 100644 doc/forum/appear_if_you_are_login_or_not_in_a_page.mdwn create mode 100644 doc/forum/attachments_fail_to_upload.mdwn create mode 100644 doc/forum/attachments_fail_to_upload/comment_1_577adde1dfa49463dfa8e169c462fc42._comment create mode 100644 doc/forum/attachments_fail_to_upload/comment_2_473f38c6d523496fac8dad13ac6d20c3._comment create mode 100644 doc/forum/attachments_fail_to_upload/comment_3_799a2f1b7b259157e97fd31ec76fb845._comment create mode 100644 doc/forum/attachments_fail_to_upload/comment_4_e37d1497acafd3fda547462f000636e3._comment create mode 100644 doc/forum/attachments_fail_to_upload/comment_5_da03f9c4917cb1ef52de984b8ba86b68._comment create mode 100644 doc/forum/attachments_fail_to_upload/comment_6_04498946a300ddb652dec73c2950f48f._comment create mode 100644 doc/forum/bashman.mdwn create mode 100644 doc/forum/blocked_by_blogspam.mdwn create mode 100644 doc/forum/build_error:_Cannot_decode_string_with_wide_characters.mdwn create mode 100644 doc/forum/build_error:_Cannot_decode_string_with_wide_characters/comment_1_83fbb415dd3ae6a19ed5ea5f82065c28._comment create mode 100644 doc/forum/build_error:_Cannot_decode_string_with_wide_characters/comment_2_d258536c98538d4744f66eb3132439a9._comment create mode 100644 doc/forum/build_error:_Cannot_decode_string_with_wide_characters/comment_3_d62173d0ae220ab7b063631952856587._comment create mode 100644 doc/forum/build_error:_Cannot_decode_string_with_wide_characters/comment_4_d5d0174e09a94359c23fd9c006a22bbc._comment create mode 100644 doc/forum/build_error:_Cannot_decode_string_with_wide_characters/comment_5_e652027a8f90ebef6f21613b5784ded2._comment create mode 100644 doc/forum/build_error:_Cannot_decode_string_with_wide_characters/comment_6_ba76f7f8ef46fb58d36fb2cda4b242ff._comment create mode 100644 doc/forum/build_error:_Cannot_decode_string_with_wide_characters/comment_7_e4f7c1da09571085070275e12c09b12f._comment create mode 100644 doc/forum/chinese_character_problem.mdwn create mode 100644 doc/forum/cleaning_up_discussion_pages_and_the_like.mdwn create mode 100644 doc/forum/converting_binary_files.mdwn create mode 100644 doc/forum/copyright_and_license_template_variables___40__where_are_they_set__63____41__.mdwn create mode 100644 doc/forum/create_download_link.mdwn create mode 100644 doc/forum/create_download_link/comment_1_4797493157c569f8893b53b5e5a58e73._comment create mode 100644 doc/forum/creating_redirect_index.mdwn__63___.mdwn create mode 100644 doc/forum/creating_redirect_index.mdwn__63___/comment_1_6d609c3a2ba50da4129e15b60362c6d9._comment create mode 100644 doc/forum/cutpaste.pm_not_only_file-local.mdwn create mode 100644 doc/forum/cutpaste.pm_not_only_file-local/comment_1_497c62f21fd1b87625b806407c72dbad._comment create mode 100644 doc/forum/debconf13_ikiwiki_bof.mdwn create mode 100644 doc/forum/debian_backports_update_someone_please.mdwn create mode 100644 doc/forum/default_paths._Are_there_better_defaults__63__.mdwn create mode 100644 doc/forum/default_paths._Are_there_better_defaults__63__/comment_1_3db622152a8ab53841cc13280ca31da4._comment create mode 100644 doc/forum/discussion.mdwn create mode 100644 doc/forum/double_forward_slash___39____47____47____39___in_the_address_bar.mdwn create mode 100644 doc/forum/download_links_for_attachments.mdwn create mode 100644 doc/forum/download_links_for_attachments/comment_1_19fe525281e38d3bbe45b31248ca7880._comment create mode 100644 doc/forum/download_links_for_attachments/comment_2_06231e4ddc271260e51bc371637540de._comment create mode 100644 doc/forum/download_links_for_attachments/comment_3_64d12928bc24c48d6f0b5fbb2dfd8f6d._comment create mode 100644 doc/forum/download_links_for_attachments/comment_4_7612923064284646c2ed59e2cd52845d._comment create mode 100644 doc/forum/editing_a_comment.mdwn create mode 100644 doc/forum/editing_the_style_sheet.mdwn create mode 100644 doc/forum/error_302___40__Found__41___when_editing_page.mdwn create mode 100644 doc/forum/ever-growing_list_of_pages.mdwn create mode 100644 doc/forum/field__95__tags_not_linking.mdwn create mode 100644 doc/forum/field__95__tags_not_linking/comment_10_7c1540e6eb6aafd2e1c9c7016e6e6249._comment create mode 100644 doc/forum/field__95__tags_not_linking/comment_11_0c03cbaa4f748d2fb932fda08fe6e966._comment create mode 100644 doc/forum/field__95__tags_not_linking/comment_12_9f3a402173f9584d8a36bc61e5755f6d._comment create mode 100644 doc/forum/field__95__tags_not_linking/comment_13_455a2f921059f9ecca810bb8afed0fda._comment create mode 100644 doc/forum/field__95__tags_not_linking/comment_14_b82294c290a215d9aa6774ee20b5a552._comment create mode 100644 doc/forum/field__95__tags_not_linking/comment_15_57fb279ad50f8460341dc0f217acef06._comment create mode 100644 doc/forum/field__95__tags_not_linking/comment_16_8dae1024e80cf6ea765dee0318324d71._comment create mode 100644 doc/forum/field__95__tags_not_linking/comment_1_76a4fb4def8f13b906c848814de91660._comment create mode 100644 doc/forum/field__95__tags_not_linking/comment_2_64d51cc9ba953e7fed609c380e30bb7d._comment create mode 100644 doc/forum/field__95__tags_not_linking/comment_3_7a6eac4e216133f1cf6fc12336fc2496._comment create mode 100644 doc/forum/field__95__tags_not_linking/comment_4_e6941a0df00fb9f45563c30e01efa622._comment create mode 100644 doc/forum/field__95__tags_not_linking/comment_5_f08ded5a946458aeba59a2c4cec29b2f._comment create mode 100644 doc/forum/field__95__tags_not_linking/comment_6_6ea7de20c3db96589c05adbe97d57cfd._comment create mode 100644 doc/forum/field__95__tags_not_linking/comment_7_8ad385b61c46389d87c88b17430ab1f2._comment create mode 100644 doc/forum/field__95__tags_not_linking/comment_8_c3c5eced158babd8c3acb493a86b6ecb._comment create mode 100644 doc/forum/field__95__tags_not_linking/comment_9_9bd4b3df18a28a7ab3bbef5013856987._comment create mode 100644 doc/forum/field_and_forms.mdwn create mode 100644 doc/forum/field_and_forms/comment_1_a0e976cb79f03dcff5e9a4511b90d160._comment create mode 100644 doc/forum/formating:_how_to_align_text_to_the_right.mdwn create mode 100644 doc/forum/getsource_from_gitweb_with_cgi_disabled___44___Is_it_possible__63__.mdwn create mode 100644 doc/forum/getsource_from_gitweb_with_cgi_disabled___44___Is_it_possible__63__/comment_1_747cc477584028ce2c7bc198070b1221._comment create mode 100644 doc/forum/getsource_from_gitweb_with_cgi_disabled___44___Is_it_possible__63__/comment_2_a230861b26dba6d61461862bfedbc09c._comment create mode 100644 doc/forum/getsource_from_gitweb_with_cgi_disabled___44___Is_it_possible__63__/comment_3_848b4801fc7887906a21a676e802023c._comment create mode 100644 doc/forum/google_openid_broken__63__.mdwn create mode 100644 doc/forum/how_can_I_use___39____47____39___as_tagbase__63__.mdwn create mode 100644 doc/forum/how_can_I_use___39____47____39___as_tagbase__63__/comment_1_e7897651ba8d9156526d36d6b7744eae._comment create mode 100644 doc/forum/how_could_i_generate_a_flat_textfile_from_metadata_in_multiple_pages.mdwn create mode 100644 doc/forum/how_do_I_revert_edits_in_the_web_mode__63__.mdwn create mode 100644 doc/forum/how_do_I_revert_edits_in_the_web_mode__63__/comment_1_e4720e8e4fe74bd6cba746e8259832e6._comment create mode 100644 doc/forum/how_do_I_translate_a_TWiki_site.mdwn create mode 100644 doc/forum/how_to_add_post_titles_in_ikiwiki_blog__63__.mdwn create mode 100644 doc/forum/how_to_enable_multimarkdown__63__.mdwn create mode 100644 doc/forum/how_to_enable_multimarkdown__63__/comment_1_037f858c4d0bcbb708c3efd264379500._comment create mode 100644 doc/forum/how_to_enable_multimarkdown__63__/comment_2_b7d512a535490dabf8d6ce55439741c7._comment create mode 100644 doc/forum/how_to_get_nice_pdf_from_ikiwiki_pages__63__.mdwn create mode 100644 doc/forum/how_to_get_nice_pdf_from_ikiwiki_pages__63__/comment_1_332d32850c3dc0d45f5cc50434205f39._comment create mode 100644 doc/forum/how_to_have_a_plugin_delete_a_file.mdwn create mode 100644 doc/forum/how_to_have_a_plugin_delete_a_file/comment_1_061c8bca174f7155d4065dd200c0c8db._comment create mode 100644 doc/forum/how_to_have_a_plugin_delete_a_file/comment_2_864a20147885642ad3bbcf8400d8ee46._comment create mode 100644 doc/forum/how_to_load_an_external_page_and_still_have_it_under_ikiwiki_template.mdwn create mode 100644 doc/forum/how_to_login_as_admin.mdwn create mode 100644 doc/forum/how_to_login_as_admin/comment_1_295e130c6400a2d7336758e82bcd5647._comment create mode 100644 doc/forum/how_to_setup_ikiwiki_on_a_remote_host.mdwn create mode 100644 doc/forum/howto_install_the_pagedown_plugin.mdwn create mode 100644 doc/forum/howto_install_the_pagedown_plugin/comment_1_158fbcef24d20920c40968da8f10442a._comment create mode 100644 doc/forum/html_source_pages_in_version_3.20100704.mdwn create mode 100644 doc/forum/ikiwiki.info_blogspam_problem.mdwn create mode 100644 doc/forum/ikiwiki.info_blogspam_problem/comment_1_893a2f561ead36b531e2d6c887e6aaba._comment create mode 100644 doc/forum/ikiwiki_+_mathjax.mdwn create mode 100644 doc/forum/ikiwiki_+_mathjax/comment_1_8426a985ecfbb02d364116503ef3a0d4._comment create mode 100644 doc/forum/ikiwiki_+_mathjax/comment_2_ddb7a4d59bbe7145167d122a146e8f65._comment create mode 100644 doc/forum/ikiwiki_+_mathjax/comment_3_5a118654bc008bbb118285ff141eb6f1._comment create mode 100644 doc/forum/ikiwiki_+_mathjax/comment_4_873adec726e9b70394643ff28094ad39._comment create mode 100644 doc/forum/ikiwiki_+_mathjax/comment_5_f601e3f1c78345e4d80ec3ce62784e6f._comment create mode 100644 doc/forum/ikiwiki_+_mathjax/comment_6_305fddcd1e264b92d7ed7153ba27ce07._comment create mode 100644 doc/forum/ikiwiki_--setup_creates_tmp__47___directory_in_destdir.mdwn create mode 100644 doc/forum/ikiwiki__39__s_notion_of_time.mdwn create mode 100644 doc/forum/ikiwiki_and_big_files.mdwn create mode 100644 doc/forum/ikiwiki_and_big_files/comment_1_df8a9f4249af435cc335f77768a3278d._comment create mode 100644 doc/forum/ikiwiki_and_big_files/comment_2_2d996f1124aedc10f345139c3d8b11df._comment create mode 100644 doc/forum/ikiwiki_and_big_files/comment_3_dfbd38e2b457ea3c4f70266dbf8fbeab._comment create mode 100644 doc/forum/ikiwiki_and_big_files/comment_4_fd8a0cb8872d9de55465e8db93d67619._comment create mode 100644 doc/forum/ikiwiki_and_big_files/comment_5_3532b14ee10775dac634792c75a30e89._comment create mode 100644 doc/forum/ikiwiki_development_environment_tips.mdwn create mode 100644 doc/forum/ikiwiki_generates_html_files_with_600_permission..mdwn create mode 100644 doc/forum/ikiwiki_generates_html_files_with_600_permission./comment_1_6d73d412a9cc6f6ae426b62885c1f157._comment create mode 100644 doc/forum/ikiwiki_generates_html_files_with_600_permission./comment_2_1392fcde369d11a264f31f6b8993ccec._comment create mode 100644 doc/forum/ikiwiki_generates_html_files_with_600_permission./comment_3_962306f22ceb17afb4150e766e9a05b3._comment create mode 100644 doc/forum/ikiwiki_generates_html_files_with_600_permission./comment_4_8b988d85cfde123798238d0348764c79._comment create mode 100644 doc/forum/ikiwiki_not_usable_when_installed_with_toast___40__because_of_symlinks__41__.mdwn create mode 100644 doc/forum/ikiwiki_over_database__63__.wiki create mode 100644 doc/forum/ikiwiki_vim_integration.mdwn create mode 100644 doc/forum/ikiwiki_vim_syntaxfile.mdwn create mode 100644 doc/forum/ikiwiki_with_album___38___underlay_plugins.mdwn create mode 100644 doc/forum/ikiwiki_with_album___38___underlay_plugins/comment_1_ea4faa2b5bb9216c0a0427f2071584ef._comment create mode 100644 doc/forum/ikiwiki_with_album___38___underlay_plugins/comment_2_f38b4f9191d42c3d1a9651820b36a2ee._comment create mode 100644 doc/forum/ikiwiki_with_album___38___underlay_plugins/comment_3_46d4c9cecc5d9a19693966820dd18380._comment create mode 100644 doc/forum/index_attachments.mdwn create mode 100644 doc/forum/index_attachments/comment_1_18b9531d273292b45051eef6a306ca26._comment create mode 100644 doc/forum/index_attachments/comment_2._comment create mode 100644 doc/forum/index_attachments/comment_3_050e5847641a27e0c14232632f3e700a._comment create mode 100644 doc/forum/index_attachments/comment_4._comment create mode 100644 doc/forum/inject__95__preprocess__95__tag.mdwn create mode 100644 doc/forum/installation_and_setup_questions.mdwn create mode 100644 doc/forum/installation_as_non-root_user.mdwn create mode 100644 doc/forum/installation_of_selected_docs.mdwn create mode 100644 doc/forum/is_it_possible_to_NOT_add_openid2_meta_tags.mdwn create mode 100644 doc/forum/java_script_slideshow.mdwn create mode 100644 doc/forum/java_script_slideshow/comment_1_3eba0b2f3c12acc991dc3069d2b83d49._comment create mode 100644 doc/forum/java_script_slideshow/comment_2_59d90f42b2ca2a5cc71a4d9ba9b9ee9f._comment create mode 100644 doc/forum/java_script_slideshow/comment_3_820a86db38231cff7239f0a88b1925fd._comment create mode 100644 doc/forum/java_script_slideshow/comment_4_a68972e3dd20b65119211d4ab120b294._comment create mode 100644 doc/forum/link_autocompletion_in_vim.mdwn create mode 100644 doc/forum/link_to_an_image_inside_the_wiki_without_inlining_it.mdwn create mode 100644 doc/forum/links_to_diff_on_recentchanges__63__.mdwn create mode 100644 doc/forum/links_to_diff_on_recentchanges__63__/comment_1_1dbc723cc2794f6d45de9cbd2fc2e0fd._comment create mode 100644 doc/forum/links_to_diff_on_recentchanges__63__/comment_2_4349c85d92cf9c1acf2e7678371ab12a._comment create mode 100644 doc/forum/lockedit:_pages_don__39__t_get_locked.mdwn create mode 100644 doc/forum/lockedit:_pages_don__39__t_get_locked/comment_1_bacffb831e5ce7ece7e670c55ad9f3af._comment create mode 100644 doc/forum/lockedit:_pages_don__39__t_get_locked/comment_2_ad268d3f2cd3d529cfff281e0ecb2f16._comment create mode 100644 doc/forum/lockedit:_pages_don__39__t_get_locked/comment_3_da2fb41c5313763e4393cdd921a3f36e._comment create mode 100644 doc/forum/lockedit:_pages_don__39__t_get_locked/comment_4_d0de7964db26cb6f3e81d6e8c29d860d._comment create mode 100644 doc/forum/lockedit:_pages_don__39__t_get_locked/comment_5_d60727c53197d1c667b59bc7250afd9f._comment create mode 100644 doc/forum/managing_todo_lists.mdwn create mode 100644 doc/forum/missing_pages_redirected_to_search-SOLVED.mdwn create mode 100644 doc/forum/missing_pages_redirected_to_search-SOLVED/comment_1_aa03c337b31d7acb95761eb51caab1ef._comment create mode 100644 doc/forum/move_pages.mdwn create mode 100644 doc/forum/move_pages/comment_1_3f1b9563af1e729a7311e869cf7a7787._comment create mode 100644 doc/forum/move_pages/comment_2_22b1c238faacbf10df5f03f415223b49._comment create mode 100644 doc/forum/multi-user_setup_of_ikiwiki__44___gitosis_and_apache2_in_Debian_Sid.mdwn create mode 100644 doc/forum/multi_domain_setup_possible__63__.mdwn create mode 100644 doc/forum/multi_domain_setup_possible__63__/comment_1_43f5df30d09046ccc4f7c44703979a11._comment create mode 100644 doc/forum/multi_domain_setup_possible__63__/comment_2_75d6581f81b71fb8acbe3561047ea759._comment create mode 100644 doc/forum/navigation_of_wiki_pages_on_local_filesystem_with_vim.mdwn create mode 100644 doc/forum/nginx:_404_plugin_not_working.mdwn create mode 100644 doc/forum/nginx:_404_plugin_not_working/comment_1_02a82e468676ae64374cc91ec87e39d6._comment create mode 100644 doc/forum/nginx:_404_plugin_not_working/comment_2_ce6bd8e98e4be08316522182f5f85a11._comment create mode 100644 doc/forum/nginx:_404_plugin_not_working/comment_3_52b05c3274455db7bee3c1765776fd52._comment create mode 100644 doc/forum/nginx:_404_plugin_not_working/comment_4_5a8c2987f442106c68eb822c5bce3bf1._comment create mode 100644 doc/forum/nginx:_404_plugin_not_working/comment_5_0720cd8842dc1cb338b74a0e6fdb2aac._comment create mode 100644 doc/forum/pandoc-iki_plugin.mdwn create mode 100644 doc/forum/pandoc-iki_plugin/comment_1_11eef903493378fd704a6bd92e968508._comment create mode 100644 doc/forum/pandoc-iki_plugin/comment_2_2c437577390cffe3401f5cc2f08a2ab1._comment create mode 100644 doc/forum/paths_to_files_outside_the_wiki_root.mdwn create mode 100644 doc/forum/perl5lib_and_wrappers.mdwn create mode 100644 doc/forum/po_plugin_doesn__39__t_create_po_files___40__only_pot__41__..mdwn create mode 100644 doc/forum/possible_utf-8_problem__63__.mdwn create mode 100644 doc/forum/postsignin_redirect_not_working.mdwn create mode 100644 doc/forum/problem_with_git_after_a_commit_of_ikiwiki.mdwn create mode 100644 doc/forum/problem_with_git_after_a_commit_of_ikiwiki/comment_1_2b9986717769419a8ae0f730c36b7e65._comment create mode 100644 doc/forum/recentchanges_dir_should_be_under_control_of_RCS__63__.mdwn create mode 100644 doc/forum/recovering_original_title_with_meta_directive.mdwn create mode 100644 doc/forum/remove_css__63__.mdwn create mode 100644 doc/forum/report_pagination.mdwn create mode 100644 doc/forum/screenplay_plugin.mdwn create mode 100644 doc/forum/screenplay_plugin/comment_1_6c353acfc80b972ee3a34c8bb09dede3._comment create mode 100644 doc/forum/screenplay_plugin/comment_2_1868aeebebefae80531f2031ffba35d3._comment create mode 100644 doc/forum/search_plugin_questions.mdwn create mode 100644 doc/forum/search_plugin_questions/comment_1_d634b00ab758c9fbc43528b9a3176257._comment create mode 100644 doc/forum/search_plugin_questions/comment_2_b731c664d314afd1d45485716f39ac3b._comment create mode 100644 doc/forum/section_editing.mdwn create mode 100644 doc/forum/section_editing/comment_1_b193caa886a47c685ac7dafaf60c1761._comment create mode 100644 doc/forum/speeding_up_ikiwiki.mdwn create mode 100644 doc/forum/square_brackets_inside_backticks_generates_incorrect_html___40__interpreted_as_wikilinks__41____63__.html create mode 100644 doc/forum/suppressing_output_of_pages_included_only_for_their_side_effects.mdwn create mode 100644 doc/forum/tag_plugin:_rebuilding_autocreated_pages.mdwn create mode 100644 doc/forum/tags_acting_strangely:_not_picking_up_all_pages__44___not_populating_feeds.mdwn create mode 100644 doc/forum/tags_acting_strangely:_not_picking_up_all_pages__44___not_populating_feeds/comment_1_ec4ffab10e60510b53660b70908d1bd8._comment create mode 100644 doc/forum/tags_acting_strangely:_not_picking_up_all_pages__44___not_populating_feeds/comment_2_a47884ffd749df980cd62f4c1e3167ce._comment create mode 100644 doc/forum/tags_acting_strangely:_not_picking_up_all_pages__44___not_populating_feeds/comment_3_6c4affdbc637946506d0c28a8648dc6e._comment create mode 100644 doc/forum/teximg_not_working.mdwn create mode 100644 doc/forum/teximg_not_working/comment_2_35e2ebf3893fc0c7966490e1fef1e6cf._comment create mode 100644 doc/forum/transition_from_handwritten_html_to_ikiwiki.mdwn create mode 100644 doc/forum/two_new_contrib_plugins:_newpage__44___jssearchfield.mdwn create mode 100644 doc/forum/understanding_filter_hooks.mdwn create mode 100644 doc/forum/upgrade_steps.mdwn create mode 100644 doc/forum/use_php-markdown-extra_with_ikiwiki__63__.mdwn create mode 100644 doc/forum/use_php-markdown-extra_with_ikiwiki__63__/comment_1_66d48218361caa4c07bd714b82ed0021._comment create mode 100644 doc/forum/use_php-markdown-extra_with_ikiwiki__63__/comment_2_f2ee0a4dce571d329f795e52139084c0._comment create mode 100644 doc/forum/use_php-markdown-extra_with_ikiwiki__63__/comment_3_e388714f457ccb6ef73630179914558c._comment create mode 100644 doc/forum/usedirs___38___indexpages_using_problem.mdwn create mode 100644 doc/forum/using_l10n__39__d_basewiki.mdwn create mode 100644 doc/forum/using_l10n__39__d_basewiki/comment_1_eaab671848ee6129f6fe9399474eeac0._comment create mode 100644 doc/forum/using_l10n__39__d_basewiki/comment_2_d907676a1db1210ca59506673c564359._comment create mode 100644 doc/forum/using_l10n__39__d_basewiki/comment_3_5e9d5bc5ecaf63f9bfe3315b09a279aa._comment create mode 100644 doc/forum/using_svn+ssh_with_ikiwiki.mdwn create mode 100644 doc/forum/utf8_warnings_for___34____92__xAB__34__.mdwn create mode 100644 doc/forum/w3mmode___91__Save_Page__93___results_in_403.mdwn create mode 100644 doc/forum/web_service_API__44___fastcgi_support.mdwn create mode 100644 doc/forum/what_generates_user_name_for_recent_changes_page__63__.mdwn create mode 100644 doc/forum/what_generates_user_name_for_recent_changes_page__63__/comment_1_e90085a9d61cdf623c20dfe57005472e._comment create mode 100644 doc/forum/what_is_the_easiest_way_to_implement_order:_disallow_all__44___allow_chosen__95__few_page_editing_policy__63__.mdwn create mode 100644 doc/forum/where_are_the_tags.mdwn create mode 100644 doc/forum/where_are_the_tags/comment_1_6a559c3bfe72011c45b006d33176da3d._comment create mode 100644 doc/forum/which_file_ikiwiki_--setup_is_processing_right_now__63__.mdwn create mode 100644 doc/forum/which_file_ikiwiki_--setup_is_processing_right_now__63__/comment_1_4f52f8fc083982bd5a572742cf35c74f._comment create mode 100644 doc/forum/wiki_clones_on_dynamic_IPs.mdwn create mode 100644 doc/forum/wiki_name_in_page_titles.mdwn create mode 100644 doc/forum/wishlist-discussion:_Editformular_showing_existing_tags.mdwn create mode 100644 doc/forum/wishlist:_Allow_OpenID_users_to_set_a_display_name.mdwn create mode 100644 doc/forum/wishlist:_support_staging_area.mdwn create mode 100644 doc/forum/wmd_editor_double_preview.mdwn create mode 100644 doc/forum/wmd_editor_double_preview/comment_1_0d3acf67f3c35f8c4156228f96dcd975._comment create mode 100644 doc/freesoftware.mdwn create mode 100644 doc/freesoftware/discussion.mdwn create mode 100644 doc/git.mdwn create mode 100644 doc/ikiwiki-calendar.mdwn create mode 100644 doc/ikiwiki-calendar/discussion.mdwn create mode 100644 doc/ikiwiki-makerepo.mdwn create mode 100644 doc/ikiwiki-makerepo/discussion.mdwn create mode 100644 doc/ikiwiki-mass-rebuild.mdwn create mode 100644 doc/ikiwiki-mass-rebuild/discussion.mdwn create mode 100644 doc/ikiwiki-transition.mdwn create mode 100644 doc/ikiwiki-update-wikilist.mdwn create mode 100644 doc/ikiwiki.mdwn create mode 100644 doc/ikiwiki/directive.mdwn create mode 100644 doc/ikiwiki/directive/aggregate.mdwn create mode 100644 doc/ikiwiki/directive/aggregate/discussion.mdwn create mode 100644 doc/ikiwiki/directive/brokenlinks.mdwn create mode 100644 doc/ikiwiki/directive/brokenlinks/discussion.mdwn create mode 100644 doc/ikiwiki/directive/calendar.mdwn create mode 100644 doc/ikiwiki/directive/color.mdwn create mode 100644 doc/ikiwiki/directive/comment.mdwn create mode 100644 doc/ikiwiki/directive/commentmoderation.mdwn create mode 100644 doc/ikiwiki/directive/copy.mdwn create mode 100644 doc/ikiwiki/directive/cut.mdwn create mode 100644 doc/ikiwiki/directive/cutpaste.mdwn create mode 100644 doc/ikiwiki/directive/date.mdwn create mode 100644 doc/ikiwiki/directive/edittemplate.mdwn create mode 100644 doc/ikiwiki/directive/edittemplate/discussion.mdwn create mode 100644 doc/ikiwiki/directive/flattr.mdwn create mode 100644 doc/ikiwiki/directive/format.mdwn create mode 100644 doc/ikiwiki/directive/fortune.mdwn create mode 100644 doc/ikiwiki/directive/graph.mdwn create mode 100644 doc/ikiwiki/directive/graph/discussion.mdwn create mode 100644 doc/ikiwiki/directive/haiku.mdwn create mode 100644 doc/ikiwiki/directive/if.mdwn create mode 100644 doc/ikiwiki/directive/img.mdwn create mode 100644 doc/ikiwiki/directive/img/discussion.mdwn create mode 100644 doc/ikiwiki/directive/inline.mdwn create mode 100644 doc/ikiwiki/directive/inline/discussion.mdwn create mode 100644 doc/ikiwiki/directive/linkmap.mdwn create mode 100644 doc/ikiwiki/directive/listdirectives.mdwn create mode 100644 doc/ikiwiki/directive/map.mdwn create mode 100644 doc/ikiwiki/directive/map/discussion.mdwn create mode 100644 doc/ikiwiki/directive/meta.mdwn create mode 100644 doc/ikiwiki/directive/meta/discussion.mdwn create mode 100644 doc/ikiwiki/directive/more.mdwn create mode 100644 doc/ikiwiki/directive/orphans.mdwn create mode 100644 doc/ikiwiki/directive/osm.mdwn create mode 100644 doc/ikiwiki/directive/osm/discussion.mdwn create mode 100644 doc/ikiwiki/directive/pagecount.mdwn create mode 100644 doc/ikiwiki/directive/pagestats.mdwn create mode 100644 doc/ikiwiki/directive/pagestats/discussion.mdwn create mode 100644 doc/ikiwiki/directive/pagetemplate.mdwn create mode 100644 doc/ikiwiki/directive/paste.mdwn create mode 100644 doc/ikiwiki/directive/ping.mdwn create mode 100644 doc/ikiwiki/directive/poll.mdwn create mode 100644 doc/ikiwiki/directive/polygen.mdwn create mode 100644 doc/ikiwiki/directive/postsparkline.mdwn create mode 100644 doc/ikiwiki/directive/progress.mdwn create mode 100644 doc/ikiwiki/directive/shortcut.mdwn create mode 100644 doc/ikiwiki/directive/sidebar.mdwn create mode 100644 doc/ikiwiki/directive/sidebar/discussion.mdwn create mode 100644 doc/ikiwiki/directive/sparkline.mdwn create mode 100644 doc/ikiwiki/directive/table.mdwn create mode 100644 doc/ikiwiki/directive/table/discussion.mdwn create mode 100644 doc/ikiwiki/directive/tag.mdwn create mode 100644 doc/ikiwiki/directive/tag/discussion.mdwn create mode 100644 doc/ikiwiki/directive/taglink.mdwn create mode 100644 doc/ikiwiki/directive/template.mdwn create mode 100644 doc/ikiwiki/directive/templatebody.mdwn create mode 100644 doc/ikiwiki/directive/testpagespec.mdwn create mode 100644 doc/ikiwiki/directive/testpagespec/discussion.mdwn create mode 100644 doc/ikiwiki/directive/teximg.mdwn create mode 100644 doc/ikiwiki/directive/toc.mdwn create mode 100644 doc/ikiwiki/directive/toggle.mdwn create mode 100644 doc/ikiwiki/directive/toggle/discussion.mdwn create mode 100644 doc/ikiwiki/directive/toggleable.mdwn create mode 100644 doc/ikiwiki/directive/trailitem.mdwn create mode 100644 doc/ikiwiki/directive/trailitems.mdwn create mode 100644 doc/ikiwiki/directive/traillink.mdwn create mode 100644 doc/ikiwiki/directive/trailoptions.mdwn create mode 100644 doc/ikiwiki/directive/version.mdwn create mode 100644 doc/ikiwiki/directive/waypoint.mdwn create mode 100644 doc/ikiwiki/formatting.mdwn create mode 100644 doc/ikiwiki/formatting/discussion.mdwn create mode 100644 doc/ikiwiki/markdown.mdwn create mode 100644 doc/ikiwiki/markdown/discussion.mdwn create mode 100644 doc/ikiwiki/openid.mdwn create mode 100644 doc/ikiwiki/pagespec.mdwn create mode 100644 doc/ikiwiki/pagespec/attachment.mdwn create mode 100644 doc/ikiwiki/pagespec/attachment/discussion.mdwn create mode 100644 doc/ikiwiki/pagespec/discussion.mdwn create mode 100644 doc/ikiwiki/pagespec/po.mdwn create mode 100644 doc/ikiwiki/pagespec/sorting.mdwn create mode 100644 doc/ikiwiki/searching.mdwn create mode 100644 doc/ikiwiki/subpage.mdwn create mode 100644 doc/ikiwiki/subpage/linkingrules.mdwn create mode 100644 doc/ikiwiki/wikilink.mdwn create mode 100644 doc/ikiwiki/wikilink/discussion.mdwn create mode 100644 doc/ikiwikiusers.mdwn create mode 100644 doc/ikiwikiusers/discussion.mdwn create mode 100644 doc/index.mdwn create mode 100644 doc/index/discussion.mdwn create mode 100644 doc/index/openid/discussion.mdwn create mode 100644 doc/install.mdwn create mode 100644 doc/install/discussion.mdwn create mode 100644 doc/local.css create mode 100644 doc/logo.mdwn create mode 100644 doc/logo/discussion.mdwn create mode 100644 doc/logo/favicon.svgz create mode 100644 doc/logo/ikiwiki.png create mode 100644 doc/logo/ikiwiki.svgz create mode 100644 doc/logo/ikiwiki_button.png create mode 100644 doc/logo/ikiwiki_large.png create mode 100644 doc/logo/ikiwiki_old.png create mode 100644 doc/logo/ikiwiki_old2.png create mode 100644 doc/logo/ikiwiki_old2.svgz create mode 100644 doc/news.mdwn create mode 100644 doc/news/Article_on_Ikiwiki_as_a_BTS.mdwn create mode 100644 doc/news/code_swarm.mdwn create mode 100644 doc/news/code_swarm/code_swarm.config create mode 100755 doc/news/code_swarm/code_swarm_log.pl create mode 100644 doc/news/code_swarm/discussion.mdwn create mode 100644 doc/news/code_swarm/screenshot.png create mode 100644 doc/news/consultant_list.mdwn create mode 100644 doc/news/discussion.mdwn create mode 100644 doc/news/donations.mdwn create mode 100644 doc/news/git_push_to_this_wiki.mdwn create mode 100644 doc/news/git_push_to_this_wiki/discussion.mdwn create mode 100644 doc/news/ikiwiki-hosting.mdwn create mode 100644 doc/news/ikiwiki_accepted_for_Summer_of_Code.mdwn create mode 100644 doc/news/ikiwiki_screencast.mdwn create mode 100644 doc/news/ikiwiki_screencast/discussion.mdwn create mode 100644 doc/news/ikiwiki_version_2.0.mdwn create mode 100644 doc/news/ikiwiki_version_3.0.mdwn create mode 100644 doc/news/irc_channel.mdwn create mode 100644 doc/news/moved_to_git.mdwn create mode 100644 doc/news/moved_to_git/discussion.mdwn create mode 100644 doc/news/new_domain_name.mdwn create mode 100644 doc/news/no_more_email_notifications.mdwn create mode 100644 doc/news/openid.mdwn create mode 100644 doc/news/openid/discussion.mdwn create mode 100644 doc/news/server_move.mdwn create mode 100644 doc/news/server_move_2009.mdwn create mode 100644 doc/news/server_speed.mdwn create mode 100644 doc/news/server_speed/discussion.mdwn create mode 100644 doc/news/stylesheets.mdwn create mode 100644 doc/news/stylesheets/discussion.mdwn create mode 100644 doc/news/version_3.20140125.mdwn create mode 100644 doc/news/version_3.20140227.mdwn create mode 100644 doc/news/version_3.20140613.mdwn create mode 100644 doc/news/version_3.20140815.mdwn create mode 100644 doc/news/version_3.20140831.mdwn create mode 100644 doc/pagehistory.mdwn create mode 100644 doc/patch.mdwn create mode 100644 doc/patch/core.mdwn create mode 100644 doc/plugins.mdwn create mode 100644 doc/plugins/404.mdwn create mode 100644 doc/plugins/404/discussion.mdwn create mode 100644 doc/plugins/aggregate.mdwn create mode 100644 doc/plugins/aggregate/discussion.mdwn create mode 100644 doc/plugins/amazon_s3.mdwn create mode 100644 doc/plugins/amazon_s3/discussion.mdwn create mode 100644 doc/plugins/anonok.mdwn create mode 100644 doc/plugins/attachment.mdwn create mode 100644 doc/plugins/autoindex.mdwn create mode 100644 doc/plugins/autoindex/discussion.mdwn create mode 100644 doc/plugins/blogspam.mdwn create mode 100644 doc/plugins/brokenlinks.mdwn create mode 100644 doc/plugins/calendar.mdwn create mode 100644 doc/plugins/calendar/discussion.mdwn create mode 100644 doc/plugins/camelcase.mdwn create mode 100644 doc/plugins/color.mdwn create mode 100644 doc/plugins/comments.mdwn create mode 100644 doc/plugins/comments/discussion.mdwn create mode 100644 doc/plugins/conditional.mdwn create mode 100644 doc/plugins/conditional/discussion.mdwn create mode 100644 doc/plugins/contrib.mdwn create mode 100644 doc/plugins/contrib/addtag.mdwn create mode 100644 doc/plugins/contrib/album.mdwn create mode 100644 doc/plugins/contrib/album/discussion.mdwn create mode 100644 doc/plugins/contrib/asymptote.mdwn create mode 100644 doc/plugins/contrib/asymptote/ikiwiki/directive/asymptote.mdwn create mode 100644 doc/plugins/contrib/attach.mdwn create mode 100644 doc/plugins/contrib/attach/discussion.mdwn create mode 100644 doc/plugins/contrib/bibtex.mdwn create mode 100644 doc/plugins/contrib/cowsay.mdwn create mode 100644 doc/plugins/contrib/created_in_future.mdwn create mode 100644 doc/plugins/contrib/created_in_future/discussion.mdwn create mode 100644 doc/plugins/contrib/datetime_cmp.mdwn create mode 100644 doc/plugins/contrib/default_content_for___42__copyright__42___and___42__license__42__.mdwn create mode 100644 doc/plugins/contrib/default_content_for___42__copyright__42___and___42__license__42__/discussion.mdwn create mode 100644 doc/plugins/contrib/field.mdwn create mode 100644 doc/plugins/contrib/field/discussion.mdwn create mode 100644 doc/plugins/contrib/flattr.mdwn create mode 100644 doc/plugins/contrib/flattr/discussion.mdwn create mode 100644 doc/plugins/contrib/ftemplate.mdwn create mode 100644 doc/plugins/contrib/ftemplate/discussion.mdwn create mode 100644 doc/plugins/contrib/ftemplate/ikiwiki/directive/ftemplate.mdwn create mode 100644 doc/plugins/contrib/gallery.mdwn create mode 100644 doc/plugins/contrib/gallery/discussion.mdwn create mode 100644 doc/plugins/contrib/getfield.mdwn create mode 100644 doc/plugins/contrib/getfield/discussion.mdwn create mode 100644 doc/plugins/contrib/googlemaps.mdwn create mode 100644 doc/plugins/contrib/googlemaps/discussion.mdwn create mode 100644 doc/plugins/contrib/groupfile.mdwn create mode 100644 doc/plugins/contrib/highlightcode.mdwn create mode 100644 doc/plugins/contrib/ikiwiki/directive/album.mdwn create mode 100644 doc/plugins/contrib/ikiwiki/directive/albumimage.mdwn create mode 100644 doc/plugins/contrib/ikiwiki/directive/albumsection.mdwn create mode 100644 doc/plugins/contrib/ikiwiki/directive/jssearchfield.mdwn create mode 100644 doc/plugins/contrib/ikiwiki/directive/ymlfront.mdwn create mode 100644 doc/plugins/contrib/ikiwiki/directive/ymlfront/discussion.mdwn create mode 100644 doc/plugins/contrib/imailhide.mdwn create mode 100644 doc/plugins/contrib/img.mdwn create mode 100644 doc/plugins/contrib/img/discussion.mdwn create mode 100644 doc/plugins/contrib/irclog.mdwn create mode 100644 doc/plugins/contrib/jscalendar.mdwn create mode 100644 doc/plugins/contrib/jssearchfield.mdwn create mode 100644 doc/plugins/contrib/justlogin.mdwn create mode 100644 doc/plugins/contrib/linguas.mdwn create mode 100644 doc/plugins/contrib/livefyre.mdwn create mode 100644 doc/plugins/contrib/localfavicon.mdwn create mode 100644 doc/plugins/contrib/mailbox.mdwn create mode 100644 doc/plugins/contrib/mailbox/discussion.mdwn create mode 100644 doc/plugins/contrib/mandoc.mdwn create mode 100644 doc/plugins/contrib/mathjax.mdwn create mode 100644 doc/plugins/contrib/mediawiki.mdwn create mode 100644 doc/plugins/contrib/mediawiki/discussion.mdwn create mode 100644 doc/plugins/contrib/monthcalendar.mdwn create mode 100644 doc/plugins/contrib/mscgen.mdwn create mode 100644 doc/plugins/contrib/navbar.mdwn create mode 100644 doc/plugins/contrib/navbar/discussion.mdwn create mode 100644 doc/plugins/contrib/newpage.mdwn create mode 100644 doc/plugins/contrib/newpage/discussion.mdwn create mode 100644 doc/plugins/contrib/nimble.mdwn create mode 100644 doc/plugins/contrib/opml.mdwn create mode 100644 doc/plugins/contrib/opml/discussion.mdwn create mode 100644 doc/plugins/contrib/pagespec_alias.mdwn create mode 100644 doc/plugins/contrib/pandoc.mdwn create mode 100644 doc/plugins/contrib/parenttag.mdwn create mode 100644 doc/plugins/contrib/plusone.mdwn create mode 100644 doc/plugins/contrib/pod.mdwn create mode 100644 doc/plugins/contrib/pod/discussion.mdwn create mode 100644 doc/plugins/contrib/poetry.mdwn create mode 100644 doc/plugins/contrib/postal.mdwn create mode 100644 doc/plugins/contrib/postal/discussion.mdwn create mode 100644 doc/plugins/contrib/purge.mdwn create mode 100644 doc/plugins/contrib/report.mdwn create mode 100644 doc/plugins/contrib/report/discussion.mdwn create mode 100644 doc/plugins/contrib/report/ikiwiki/directive/report.mdwn create mode 100644 doc/plugins/contrib/sar.mdwn create mode 100644 doc/plugins/contrib/screenplay.pm.mdwn create mode 100644 doc/plugins/contrib/sidebar2.mdwn create mode 100644 doc/plugins/contrib/siterel2pagerel.mdwn create mode 100644 doc/plugins/contrib/sourcehighlight.mdwn create mode 100644 doc/plugins/contrib/syntax.mdwn create mode 100644 doc/plugins/contrib/syntax/discussion.mdwn create mode 100644 doc/plugins/contrib/taskreport.mdwn create mode 100644 doc/plugins/contrib/tex4ht.mdwn create mode 100644 doc/plugins/contrib/texinfo.mdwn create mode 100644 doc/plugins/contrib/todo.mdwn create mode 100644 doc/plugins/contrib/tracking.mdwn create mode 100644 doc/plugins/contrib/unixauth.mdwn create mode 100644 doc/plugins/contrib/unixauth/discussion.mdwn create mode 100644 doc/plugins/contrib/unixrelpagespec.mdwn create mode 100644 doc/plugins/contrib/video.mdwn create mode 100644 doc/plugins/contrib/video/discussion.mdwn create mode 100644 doc/plugins/contrib/wordcount.mdwn create mode 100644 doc/plugins/contrib/xslt.mdwn create mode 100644 doc/plugins/contrib/xslt/discussion.mdwn create mode 100644 doc/plugins/contrib/ymlfront.mdwn create mode 100644 doc/plugins/contrib/ymlfront/discussion.mdwn create mode 100644 doc/plugins/creole.mdwn create mode 100644 doc/plugins/creole/discussion.mdwn create mode 100644 doc/plugins/cutpaste.mdwn create mode 100644 doc/plugins/date.mdwn create mode 100644 doc/plugins/ddate.mdwn create mode 100644 doc/plugins/discussion.mdwn create mode 100644 doc/plugins/editdiff.mdwn create mode 100644 doc/plugins/editdiff/discussion.mdwn create mode 100644 doc/plugins/editpage.mdwn create mode 100644 doc/plugins/editpage/discussion.mdwn create mode 100644 doc/plugins/edittemplate.mdwn create mode 100644 doc/plugins/embed.mdwn create mode 100644 doc/plugins/favicon.mdwn create mode 100644 doc/plugins/favicon/discussion.mdwn create mode 100644 doc/plugins/filecheck.mdwn create mode 100644 doc/plugins/filecheck/discussion.mdwn create mode 100644 doc/plugins/flattr.mdwn create mode 100644 doc/plugins/format.mdwn create mode 100644 doc/plugins/format/discussion.mdwn create mode 100644 doc/plugins/fortune.mdwn create mode 100644 doc/plugins/getsource.mdwn create mode 100644 doc/plugins/getsource/discussion.mdwn create mode 100644 doc/plugins/goodstuff.mdwn create mode 100644 doc/plugins/goodstuff/discussion.mdwn create mode 100644 doc/plugins/google.mdwn create mode 100644 doc/plugins/google/discussion.mdwn create mode 100644 doc/plugins/goto.mdwn create mode 100644 doc/plugins/graphviz.mdwn create mode 100644 doc/plugins/haiku.mdwn create mode 100644 doc/plugins/haiku/discussion.mdwn create mode 100644 doc/plugins/headinganchors.mdwn create mode 100644 doc/plugins/headinganchors/discussion.mdwn create mode 100644 doc/plugins/highlight.mdwn create mode 100644 doc/plugins/highlight/discussion.mdwn create mode 100644 doc/plugins/hnb.mdwn create mode 100644 doc/plugins/hnb/discussion.mdwn create mode 100644 doc/plugins/html.mdwn create mode 100644 doc/plugins/htmlbalance.mdwn create mode 100644 doc/plugins/htmlbalance/discussion.mdwn create mode 100644 doc/plugins/htmlscrubber.mdwn create mode 100644 doc/plugins/htmlscrubber/discussion.mdwn create mode 100644 doc/plugins/htmltidy.mdwn create mode 100644 doc/plugins/httpauth.mdwn create mode 100644 doc/plugins/img.mdwn create mode 100644 doc/plugins/img/discussion.mdwn create mode 100644 doc/plugins/inline.mdwn create mode 100644 doc/plugins/install.mdwn create mode 100644 doc/plugins/link.mdwn create mode 100644 doc/plugins/linkmap.mdwn create mode 100644 doc/plugins/listdirectives.mdwn create mode 100644 doc/plugins/localstyle.mdwn create mode 100644 doc/plugins/lockedit.mdwn create mode 100644 doc/plugins/lockedit/discussion.mdwn create mode 100644 doc/plugins/map.mdwn create mode 100644 doc/plugins/map/discussion.mdwn create mode 100644 doc/plugins/mdwn.mdwn create mode 100644 doc/plugins/mdwn/discussion.mdwn create mode 100644 doc/plugins/meta.mdwn create mode 100644 doc/plugins/meta/discussion.mdwn create mode 100644 doc/plugins/mirrorlist.mdwn create mode 100644 doc/plugins/moderatedcomments.mdwn create mode 100644 doc/plugins/more.mdwn create mode 100644 doc/plugins/more/discussion.mdwn create mode 100644 doc/plugins/notifyemail.mdwn create mode 100644 doc/plugins/notifyemail/discussion.mdwn create mode 100644 doc/plugins/opendiscussion.mdwn create mode 100644 doc/plugins/openid.mdwn create mode 100644 doc/plugins/openid/discussion.mdwn create mode 100644 doc/plugins/openid/troubleshooting.mdwn create mode 100644 doc/plugins/orphans.mdwn create mode 100644 doc/plugins/orphans/discussion.mdwn create mode 100644 doc/plugins/osm.mdwn create mode 100644 doc/plugins/osm/discussion.mdwn create mode 100644 doc/plugins/otl.mdwn create mode 100644 doc/plugins/pagecount.mdwn create mode 100644 doc/plugins/pagestats.mdwn create mode 100644 doc/plugins/pagetemplate.mdwn create mode 100644 doc/plugins/parentlinks.mdwn create mode 100644 doc/plugins/passwordauth.mdwn create mode 100644 doc/plugins/passwordauth/discussion.mdwn create mode 100644 doc/plugins/pingee.mdwn create mode 100644 doc/plugins/pingee/discussion.mdwn create mode 100644 doc/plugins/pinger.mdwn create mode 100644 doc/plugins/pinger/discussion.mdwn create mode 100644 doc/plugins/po.mdwn create mode 100644 doc/plugins/po/discussion.mdwn create mode 100644 doc/plugins/poll.mdwn create mode 100644 doc/plugins/poll/discussion.mdwn create mode 100644 doc/plugins/polygen.mdwn create mode 100644 doc/plugins/postsparkline.mdwn create mode 100644 doc/plugins/prettydate.mdwn create mode 100644 doc/plugins/progress.mdwn create mode 100644 doc/plugins/rawhtml.mdwn create mode 100644 doc/plugins/rawhtml/discussion.mdwn create mode 100644 doc/plugins/recentchanges.mdwn create mode 100644 doc/plugins/recentchanges/discussion.mdwn create mode 100644 doc/plugins/recentchangesdiff.mdwn create mode 100644 doc/plugins/recentchangesdiff/discussion.mdwn create mode 100644 doc/plugins/relativedate.mdwn create mode 100644 doc/plugins/remove.mdwn create mode 100644 doc/plugins/rename.mdwn create mode 100644 doc/plugins/repolist.mdwn create mode 100644 doc/plugins/rst.mdwn create mode 100644 doc/plugins/rst/discussion.mdwn create mode 100644 doc/plugins/rsync.mdwn create mode 100644 doc/plugins/rsync/discussion.mdwn create mode 100644 doc/plugins/search.mdwn create mode 100644 doc/plugins/search/discussion.mdwn create mode 100644 doc/plugins/shortcut.mdwn create mode 100644 doc/plugins/shortcut/discussion.mdwn create mode 100644 doc/plugins/sidebar.mdwn create mode 100644 doc/plugins/sidebar/discussion.mdwn create mode 100644 doc/plugins/signinedit.mdwn create mode 100644 doc/plugins/smiley.mdwn create mode 100644 doc/plugins/sortnaturally.mdwn create mode 100644 doc/plugins/sparkline.mdwn create mode 100644 doc/plugins/table.mdwn create mode 100644 doc/plugins/table/discussion.mdwn create mode 100644 doc/plugins/tag.mdwn create mode 100644 doc/plugins/tag/discussion.mdwn create mode 100644 doc/plugins/template.mdwn create mode 100644 doc/plugins/templatebody.mdwn create mode 100644 doc/plugins/testpagespec.mdwn create mode 100644 doc/plugins/teximg.mdwn create mode 100644 doc/plugins/teximg/discussion.mdwn create mode 100644 doc/plugins/textile.mdwn create mode 100644 doc/plugins/theme.mdwn create mode 100644 doc/plugins/theme/discussion.mdwn create mode 100644 doc/plugins/toc.mdwn create mode 100644 doc/plugins/toc/discussion.mdwn create mode 100644 doc/plugins/toggle.mdwn create mode 100644 doc/plugins/toggle/discussion.mdwn create mode 100644 doc/plugins/trail.mdwn create mode 100644 doc/plugins/trail/discussion.mdwn create mode 100644 doc/plugins/transient.mdwn create mode 100644 doc/plugins/txt.mdwn create mode 100644 doc/plugins/txt/discussion.mdwn create mode 100644 doc/plugins/type/auth.mdwn create mode 100644 doc/plugins/type/bundle.mdwn create mode 100644 doc/plugins/type/chrome.mdwn create mode 100644 doc/plugins/type/comments.mdwn create mode 100644 doc/plugins/type/core.mdwn create mode 100644 doc/plugins/type/date.mdwn create mode 100644 doc/plugins/type/format.mdwn create mode 100644 doc/plugins/type/fun.mdwn create mode 100644 doc/plugins/type/html.mdwn create mode 100644 doc/plugins/type/link.mdwn create mode 100644 doc/plugins/type/meta.mdwn create mode 100644 doc/plugins/type/slow.mdwn create mode 100644 doc/plugins/type/special-purpose.mdwn create mode 100644 doc/plugins/type/tags.mdwn create mode 100644 doc/plugins/type/web.mdwn create mode 100644 doc/plugins/type/widget.mdwn create mode 100644 doc/plugins/typography.mdwn create mode 100644 doc/plugins/underlay.mdwn create mode 100644 doc/plugins/userlist.mdwn create mode 100644 doc/plugins/version.mdwn create mode 100644 doc/plugins/websetup.mdwn create mode 100644 doc/plugins/wikitext.mdwn create mode 100644 doc/plugins/wmd.mdwn create mode 100644 doc/plugins/wmd/discussion.mdwn create mode 100644 doc/plugins/write.mdwn create mode 100644 doc/plugins/write/discussion.mdwn create mode 100644 doc/plugins/write/external.mdwn create mode 100644 doc/plugins/write/names.mdwn create mode 100644 doc/plugins/write/tutorial.mdwn create mode 100644 doc/plugins/write/tutorial/discussion.mdwn create mode 100644 doc/podcast.mdwn create mode 100644 doc/post-commit.mdwn create mode 100644 doc/post-commit/discussion.mdwn create mode 100644 doc/quotes.mdwn create mode 100644 doc/quotes/pizza.mdwn create mode 100644 doc/quotes/pizza/discussion.mdwn create mode 100644 doc/quotes/sold.mdwn create mode 100644 doc/rcs.mdwn create mode 100644 doc/rcs/bzr.mdwn create mode 100644 doc/rcs/cvs.mdwn create mode 100644 doc/rcs/cvs/discussion.mdwn create mode 100644 doc/rcs/darcs.mdwn create mode 100644 doc/rcs/details.mdwn create mode 100644 doc/rcs/details/discussion.mdwn create mode 100644 doc/rcs/git.mdwn create mode 100644 doc/rcs/git/discussion.mdwn create mode 100644 doc/rcs/git/wiki_edit_flow.svg create mode 100644 doc/rcs/mercurial.mdwn create mode 100644 doc/rcs/monotone.mdwn create mode 100644 doc/rcs/svn.mdwn create mode 100644 doc/rcs/svn/discussion.mdwn create mode 100644 doc/rcs/tla.mdwn create mode 100644 doc/recentchanges.mdwn create mode 100644 doc/reviewed.mdwn create mode 100644 doc/roadmap.mdwn create mode 100644 doc/roadmap/discussion.mdwn create mode 100644 doc/robots.txt create mode 100644 doc/sandbox.mdwn create mode 100644 doc/sandbox/NewPage.mdwn create mode 100644 doc/sandbox/New_blog_entry.mdwn create mode 100644 doc/sandbox/Test.py create mode 100644 doc/sandbox/discussion.mdwn create mode 100644 doc/sandbox/hmm__44___what_kind_of_a_blog_is_this__63____41__.mdwn create mode 100644 doc/sandbox/new__95__test.mdwn create mode 100644 doc/sandbox/testostereone.mdwn create mode 100644 doc/security.mdwn create mode 100644 doc/security/discussion.mdwn create mode 100644 doc/setup.mdwn create mode 100644 doc/setup/byhand.mdwn create mode 100644 doc/setup/byhand/discussion.mdwn create mode 100644 doc/setup/discussion.mdwn create mode 100644 doc/shortcuts.mdwn create mode 100644 doc/shortcuts/discussion.mdwn create mode 100644 doc/sitemap.mdwn create mode 100644 doc/smileys.mdwn create mode 100644 doc/smileys/alert.png create mode 100644 doc/smileys/angry.png create mode 100644 doc/smileys/attention.png create mode 100644 doc/smileys/biggrin.png create mode 100644 doc/smileys/checkmark.png create mode 100644 doc/smileys/devil.png create mode 100644 doc/smileys/frown.png create mode 100644 doc/smileys/icon-error.png create mode 100644 doc/smileys/icon-info.png create mode 100644 doc/smileys/idea.png create mode 100644 doc/smileys/neutral.png create mode 100644 doc/smileys/ohwell.png create mode 100644 doc/smileys/prio1.png create mode 100644 doc/smileys/prio2.png create mode 100644 doc/smileys/prio3.png create mode 100644 doc/smileys/question.png create mode 100644 doc/smileys/redface.png create mode 100644 doc/smileys/sad.png create mode 100644 doc/smileys/smile.png create mode 100644 doc/smileys/smile2.png create mode 100644 doc/smileys/smile3.png create mode 100644 doc/smileys/smile4.png create mode 100644 doc/smileys/star_off.png create mode 100644 doc/smileys/star_on.png create mode 100644 doc/smileys/thumbs-up.png create mode 100644 doc/smileys/tired.png create mode 100644 doc/smileys/tongue.png create mode 100644 doc/soc.mdwn create mode 100644 doc/soc/application.mdwn create mode 100644 doc/soc/discussion.mdwn create mode 100644 doc/soc/ideas.mdwn create mode 100644 doc/spam_fighting.mdwn create mode 100644 doc/style.css create mode 100644 doc/tags.mdwn create mode 100644 doc/tags/discussion.mdwn create mode 100644 doc/templates.mdwn create mode 100644 doc/templates/discussion.mdwn create mode 100644 doc/templates/gitbranch.mdwn create mode 100644 doc/templates/links.mdwn create mode 100644 doc/templates/note.mdwn create mode 100644 doc/templates/plugin.mdwn create mode 100644 doc/templates/popup.mdwn create mode 100644 doc/theme_market.mdwn create mode 100644 doc/themes.mdwn create mode 100644 doc/themes/actiontabs_small.png create mode 100644 doc/themes/blueview_small.png create mode 100644 doc/themes/discussion.mdwn create mode 100644 doc/themes/goldtype_small.png create mode 100644 doc/themes/monochrome_small.png create mode 100644 doc/themes/none_small.png create mode 100644 doc/tipjar.mdwn create mode 100644 doc/tips.mdwn create mode 100644 doc/tips/Adding_Disqus_to_your_wiki.mdwn create mode 100644 doc/tips/Adding_Disqus_to_your_wiki/discussion.mdwn create mode 100644 doc/tips/DreamHost.mdwn create mode 100644 doc/tips/DreamHost/discussion.mdwn create mode 100644 doc/tips/Emacs_and_markdown.html create mode 100644 doc/tips/Git_repository_and_web_server_on_different_hosts.mdwn create mode 100644 doc/tips/Git_repository_and_web_server_on_different_hosts/separate-webserver.svg create mode 100644 doc/tips/Google_custom_search.mdwn create mode 100644 doc/tips/Hosting_Ikiwiki_and_master_git_repository_on_different_machines.mdwn create mode 100644 doc/tips/Hosting_Ikiwiki_and_master_git_repository_on_different_machines/discussion.mdwn create mode 100644 doc/tips/Hosting_Ikiwiki_and_master_git_repository_on_different_machines/separate-web-git-servers.svg create mode 100644 doc/tips/Ikiwiki_with_git-annex__44___the_album_and_the_underlay_plugins.mdwn create mode 100644 doc/tips/Importing_posts_from_Wordpress.mdwn create mode 100644 doc/tips/Importing_posts_from_Wordpress/discussion.mdwn create mode 100644 doc/tips/JavaScript_to_add_index.html_to_file:_links.mdwn create mode 100644 doc/tips/JavaScript_to_add_index.html_to_file:_links/discusion.mdwn create mode 100644 doc/tips/JavaScript_to_add_index.html_to_file:_links/discussion.mdwn create mode 100644 doc/tips/Make_calendar_start_week_on_Monday.mdwn create mode 100644 doc/tips/Make_calendar_start_week_on_Monday/discussion.mdwn create mode 100644 doc/tips/Movable_Type_to_ikiwiki.mdwn create mode 100644 doc/tips/Right-to-left___40__RTL__41___page_text.mdwn create mode 100644 doc/tips/add_chatterbox_to_blog.mdwn create mode 100644 doc/tips/add_chatterbox_to_blog/discussion.mdwn create mode 100644 doc/tips/blog_script.mdwn create mode 100644 doc/tips/comments_feed.mdwn create mode 100644 doc/tips/convert_blogger_blogs_to_ikiwiki.mdwn create mode 100644 doc/tips/convert_mediawiki_to_ikiwiki.mdwn create mode 100644 doc/tips/convert_mediawiki_to_ikiwiki/discussion.mdwn create mode 100644 doc/tips/convert_moinmoin_to_ikiwiki.mdwn create mode 100644 doc/tips/convert_moinmoin_to_ikiwiki/discussion.mdwn create mode 100644 doc/tips/distributed_wikis.mdwn create mode 100644 doc/tips/distributed_wikis/decentralized_wikis.svg create mode 100644 doc/tips/distributed_wikis/discussion.mdwn create mode 100644 doc/tips/distributed_wikis/ping-setup.svg create mode 100644 doc/tips/dot_cgi.mdwn create mode 100644 doc/tips/dot_cgi/discussion.mdwn create mode 100644 doc/tips/emacs_syntax_highlighting.mdwn create mode 100644 doc/tips/embedding_content.mdwn create mode 100644 doc/tips/follow_wikilinks_from_inside_vim.mdwn create mode 100644 doc/tips/github.mdwn create mode 100644 doc/tips/howto_avoid_flooding_aggregators.mdwn create mode 100644 doc/tips/howto_limit_to_admin_users.mdwn create mode 100644 doc/tips/htaccess_file.mdwn create mode 100644 doc/tips/html5.mdwn create mode 100644 doc/tips/ikiwiki_as_a_requirements_management_tool.mdwn create mode 100644 doc/tips/ikiwiki_as_a_requirements_management_tool/discussion.mdwn create mode 100644 doc/tips/ikiwiki_on_mac_os_x.mdwn create mode 100644 doc/tips/ikiwiki_on_mac_os_x/discussion.mdwn create mode 100644 doc/tips/ikiwiki_via_gopher.mdwn create mode 100644 doc/tips/ikiwiki_via_gopher/discussion.mdwn create mode 100644 doc/tips/importing_posts_from_typo.mdwn create mode 100644 doc/tips/importing_posts_from_wordpress/ikiwiki-wordpress-import.mdwn create mode 100644 doc/tips/inside_dot_ikiwiki.mdwn create mode 100644 doc/tips/inside_dot_ikiwiki/discussion.mdwn create mode 100644 doc/tips/integrated_issue_tracking_with_ikiwiki.mdwn create mode 100644 doc/tips/integrated_issue_tracking_with_ikiwiki/discussion.mdwn create mode 100644 doc/tips/laptop_wiki_with_git.mdwn create mode 100644 doc/tips/laptop_wiki_with_git/discussion.mdwn create mode 100644 doc/tips/laptop_wiki_with_git_extended.mdwn create mode 100644 doc/tips/laptop_wiki_with_git_extended/discussion.mdwn create mode 100644 doc/tips/mailman_subscription_form.mdwn create mode 100644 doc/tips/markdown_and_eclipse.mdwn create mode 100644 doc/tips/mathopd_permissions.mdwn create mode 100644 doc/tips/migrating_podcast_to_ikiwiki.mdwn create mode 100644 doc/tips/monitor_page_changes_through_IRC.mdwn create mode 100644 doc/tips/nearlyfreespeech.mdwn create mode 100644 doc/tips/nearlyfreespeech/discussion.mdwn create mode 100644 doc/tips/optimising_ikiwiki.mdwn create mode 100644 doc/tips/parentlinks_style.mdwn create mode 100644 doc/tips/psgi.mdwn create mode 100644 doc/tips/redirections_for_usedirs.mdwn create mode 100644 doc/tips/spam_and_softwaresites.mdwn create mode 100644 doc/tips/spam_and_softwaresites/discussion.mdwn create mode 100644 doc/tips/switching_to_usedirs.mdwn create mode 100644 doc/tips/switching_to_usedirs/discussion.mdwn create mode 100644 doc/tips/untrusted_git_push.mdwn create mode 100644 doc/tips/untrusted_git_push/discussion.mdwn create mode 100644 doc/tips/upgrade_to_3.0.mdwn create mode 100644 doc/tips/using_the_web_interface_with_a_real_text_editor.mdwn create mode 100644 doc/tips/using_the_web_interface_with_a_real_text_editor/discussion.mdwn create mode 100644 doc/tips/vim_and_ikiwiki.mdwn create mode 100644 doc/tips/vim_syntax_highlighting.mdwn create mode 100644 doc/tips/vim_syntax_highlighting/discussion.mdwn create mode 100644 doc/tips/vim_syntax_highlighting/ikiwiki.vim create mode 100644 doc/tips/wikiannounce.mdwn create mode 100644 doc/tips/yaml_setup_files.mdwn create mode 100644 doc/todo.mdwn create mode 100644 doc/todo/ACL.mdwn create mode 100644 doc/todo/A_page_that_inlines_pages__61____34____42____34___results_in_unnecessary_feed_generation.mdwn create mode 100644 doc/todo/Account-creation_password.mdwn create mode 100644 doc/todo/Account_moderation.mdwn create mode 100644 doc/todo/Add_DATE_parameter_for_use_in_templates.mdwn create mode 100644 doc/todo/Add_HTML_support_to_po_plugin.mdwn create mode 100644 doc/todo/Add_a_plugin_to_list_available_pre-processor_commands.mdwn create mode 100644 doc/todo/Add_basename_in_edittemplate.mdwn create mode 100644 doc/todo/Add_camelcase_exclusions.mdwn create mode 100644 doc/todo/Add_instructive_commit_messages_for_add__47__edit_pages.mdwn create mode 100644 doc/todo/Add_instructive_commit_messages_for_removing_pages.mdwn create mode 100644 doc/todo/Add_label_to_search_form_input_field.mdwn create mode 100644 doc/todo/Add_nicer_math_formatting.mdwn create mode 100644 doc/todo/Add_showdown_GUI_input__47__edit.mdwn create mode 100644 doc/todo/Add_space_before_slash_in_parent_links.mdwn create mode 100644 doc/todo/Add_support_for_latest_Text::Markdown_as_found_on_CPAN.mdwn create mode 100644 doc/todo/Adjust_goodstuff.mdwn create mode 100644 doc/todo/Allow_TITLE_to_include_part_of_the_path_in_addition_to_the_basename.mdwn create mode 100644 doc/todo/Allow_change_of_wiki_file_types.mdwn create mode 100644 doc/todo/Allow_disabling_edit_and_preferences_links.mdwn create mode 100644 doc/todo/Allow_edittemplate_to_set_file_type.mdwn create mode 100644 doc/todo/Allow_filenames_that_are_all_type.mdwn create mode 100644 doc/todo/Allow_per-page_template_selection.mdwn create mode 100644 doc/todo/Allow_web_edit_form_comment_field_to_be_mandatory.mdwn create mode 100644 doc/todo/Attempt_to_extend_Mercurial_backend_support.mdwn create mode 100644 doc/todo/Auto-setup_and_maintain_Mercurial_wrapper_hooks.mdwn create mode 100644 doc/todo/Auto-setup_should_default_to_YAML.mdwn create mode 100644 doc/todo/Automatic_aggregate_setup_from_wikilist_in_Debian_package_.mdwn create mode 100644 doc/todo/BTS_integration.mdwn create mode 100644 doc/todo/Bestdir_along_with_bestlink_in_IkiWiki.pm.mdwn create mode 100644 doc/todo/Bestdir_along_with_bestlink_in_IkiWiki.pm/discussion.mdwn create mode 100644 doc/todo/Better_bug_tracking_support.mdwn create mode 100644 doc/todo/Better_reporting_of_validation_errors.mdwn create mode 100644 doc/todo/BibTeX.mdwn create mode 100644 doc/todo/BrowserID.mdwn create mode 100644 doc/todo/CGI_method_to_pullrefresh.mdwn create mode 100644 doc/todo/CSS_classes_for_links.mdwn create mode 100644 doc/todo/CVS_backend.mdwn create mode 100644 doc/todo/Calendar:_listing_multiple_entries_per_day_.mdwn create mode 100644 doc/todo/Case.mdwn create mode 100644 doc/todo/Commit_emails:_ones_own_changes.mdwn create mode 100644 doc/todo/Configurable_minimum_length_of_log_message_for_web_edits.mdwn create mode 100644 doc/todo/Configureable_separator_of_page_name.mdwn create mode 100644 doc/todo/Debian_package_could_Recommend_gcc_+_libc6-dev__44___not_Depend.mdwn create mode 100644 doc/todo/Default_text_for_new_pages.mdwn create mode 100644 doc/todo/Does_not_support_non-UTF8_files.mdwn create mode 100644 doc/todo/Editing_po_files.mdwn create mode 100644 doc/todo/Enable_filtering_of_files_indexed_for_search.mdwn create mode 100644 doc/todo/Extensible_inlining.mdwn create mode 100644 doc/todo/Feature_parity_with_Trac.mdwn create mode 100644 doc/todo/Fenced_code_blocks___40__from_GitHub_Flavored_Markdown__41__.mdwn create mode 100644 doc/todo/Fix_CSS_to_not_put_a_border_around_image_links.mdwn create mode 100644 doc/todo/Fix_selflink_in_po_plugin.mdwn create mode 100644 doc/todo/FormBuilder__95__Template__95__patch.mdwn create mode 100644 doc/todo/FormattingHelp_should_open_new_window.mdwn create mode 100644 doc/todo/Gallery.mdwn create mode 100644 doc/todo/Give_access_to_more_TMPL__95__VAR_variables_in_templates_inserted_by_the_template_plugin.mdwn create mode 100644 doc/todo/Google_Analytics_support.mdwn create mode 100644 doc/todo/Google_Sitemap_protocol.mdwn create mode 100644 doc/todo/Have_xapian_index_pdf__44___openoffice__44___documents.mdwn create mode 100644 doc/todo/IRC_topic.mdwn create mode 100644 doc/todo/Improve_display_of_OpenIDs.mdwn create mode 100644 doc/todo/Improve_markdown_speed.mdwn create mode 100644 doc/todo/Improve_signin_form_layout.mdwn create mode 100644 doc/todo/Improving_the_efficiency_of_match__95__glob.mdwn create mode 100644 doc/todo/Inline_plugin_option_to_show_full_page_path.mdwn create mode 100644 doc/todo/Location_of_pages_starting_with___36__tagbase_should_be_in__by_default.mdwn create mode 100644 doc/todo/Mailing_list.mdwn create mode 100644 doc/todo/Make_example_setup_file_consistent.mdwn create mode 100644 doc/todo/Mercurial_backend_update.mdwn create mode 100644 doc/todo/Modern_standard_layout.mdwn create mode 100644 doc/todo/More_flexible_po-plugin_for_translation.mdwn create mode 100644 doc/todo/Move_teximg_latex_preamble_to_config_file.mdwn create mode 100644 doc/todo/Moving_Pages.mdwn create mode 100644 doc/todo/Multiple_categorization_namespaces.mdwn create mode 100644 doc/todo/New_preprocessor_directive_syntax.mdwn create mode 100644 doc/todo/New_preprocessor_directive_syntax/discussion.mdwn create mode 100644 doc/todo/OpenSearch.mdwn create mode 100644 doc/todo/Option_linktext_for_pagestats_directive.mdwn create mode 100644 doc/todo/Option_to_disable_date_footer_for_inlines.mdwn create mode 100644 doc/todo/Option_to_make_title_an_h1__63__.mdwn create mode 100644 doc/todo/Overlay_directory_for_pagetemplates.mdwn create mode 100644 doc/todo/Pagination_next_prev_links.mdwn create mode 100644 doc/todo/Plugins_to_provide___34__add_to__34___links_for_popular_feed_readers.mdwn create mode 100644 doc/todo/Post-compilation_inclusion_of_the_sidebar.mdwn create mode 100644 doc/todo/Print_link.mdwn create mode 100644 doc/todo/Protocol_relative_urls_for_stylesheet_linking.mdwn create mode 100644 doc/todo/RSS_fields.mdwn create mode 100644 doc/todo/RSS_links.mdwn create mode 100644 doc/todo/Raw_view_link.mdwn create mode 100644 doc/todo/RecentChanges_page_links_without_cgi_wrapper.mdwn create mode 100644 doc/todo/Render_multiple_destinations_from_one_source.mdwn create mode 100644 doc/todo/Resolve_native_reStructuredText_links_to_ikiwiki_pages.mdwn create mode 100644 doc/todo/Restrict_formats_allowed_for_comments.mdwn create mode 100644 doc/todo/Restrict_page_viewing.mdwn create mode 100644 doc/todo/Separate_OpenIDs_and_usernames.mdwn create mode 100644 doc/todo/Set_arbitrary_date_to_be_used_by_calendar_plugin.mdwn create mode 100644 doc/todo/Set_arbitrary_date_to_be_used_by_calendar_plugin/discussion.mdwn create mode 100644 doc/todo/Set_templates_for_whole_sections_of_the_site.mdwn create mode 100644 doc/todo/Short_wikilinks.mdwn create mode 100644 doc/todo/Shorter_feeds.mdwn create mode 100644 doc/todo/Silence_monotone_warning.mdwn create mode 100644 doc/todo/Split_plugins_with_external_dependencies_into_separate_Debian_packages.mdwn create mode 100644 doc/todo/Suggested_location_should_be_subpage_if_siblings_exist.mdwn create mode 100644 doc/todo/Support_MultiMarkdown_3.X.mdwn create mode 100644 doc/todo/Support_XML-RPC-based_blogging.mdwn create mode 100644 doc/todo/Support__47__Switch_to_MultiMarkdown.mdwn create mode 100644 doc/todo/Support_clipboard_copy__47__paste_of_images.mdwn create mode 100644 doc/todo/Support_preprocessing_CSS.mdwn create mode 100644 doc/todo/Support_subdirectory_of_a_git_repo.mdwn create mode 100644 doc/todo/Support_tab_insertion_in_textarea.mdwn create mode 100644 doc/todo/Support_wildcard_inside_of_link__40____41___within_a_pagespec.mdwn create mode 100644 doc/todo/Tags_list_in_page_footer_uses_basename.mdwn create mode 100644 doc/todo/Track_Markdown_Standardisation_Efforts.mdwn create mode 100644 doc/todo/Unit_tests.mdwn create mode 100644 doc/todo/Untrusted_push_in_Monotone.mdwn create mode 100644 doc/todo/Updated_bug_tracking_example.mdwn create mode 100644 doc/todo/Using_page_titles_in_internal_links.mdwn create mode 100644 doc/todo/Wikilink_to_a_symbolic_link.mdwn create mode 100644 doc/todo/Wrapper_config_with_multiline_regexp.mdwn create mode 100644 doc/todo/Zoned_ikiwiki.mdwn create mode 100644 doc/todo/__34__subscribe_to_this_page__34___checkbox_on_edit_form.mdwn create mode 100644 doc/todo/__42__forward__42__ing_functionality_for_the_meta_plugin.mdwn create mode 100644 doc/todo/__47___should_point_to_top-level_index.mdwn create mode 100644 doc/todo/a_navbar_based_on_page_properties.mdwn create mode 100644 doc/todo/abbreviation.mdwn create mode 100644 doc/todo/ability_to_force_particular_UUIDs_on_blog_posts.mdwn create mode 100644 doc/todo/absolute_urls_in_wikilinks.mdwn create mode 100644 doc/todo/access_keys.mdwn create mode 100644 doc/todo/ad-hoc_plugins.mdwn create mode 100644 doc/todo/add_forward_age_sorting_option_to_inline.mdwn create mode 100644 doc/todo/add_remove_to_actionlist.mdwn create mode 100644 doc/todo/adding_new_pages_by_using_the_web_interface.mdwn create mode 100644 doc/todo/adjust_commit_message_for_rename__44___remove.mdwn create mode 100644 doc/todo/aggregate_401_handling.mdwn create mode 100644 doc/todo/aggregate_locking.mdwn create mode 100644 doc/todo/aggregate_to_internal_pages.mdwn create mode 100644 doc/todo/aggregation.mdwn create mode 100644 doc/todo/alias_directive.mdwn create mode 100644 doc/todo/allow_CGI_to_create_dynamic_pages.mdwn create mode 100644 doc/todo/allow_TMPL__95__LOOP_in_template_directives.mdwn create mode 100644 doc/todo/allow_banning_a_user_when_moderating_a_comment.mdwn create mode 100644 doc/todo/allow_creation_of_non-existent_pages.mdwn create mode 100644 doc/todo/allow_disabling_backlinks.mdwn create mode 100644 doc/todo/allow_displaying_number_of_comments.mdwn create mode 100644 doc/todo/allow_full_post_from_the___34__add_a_new_post__34___form.mdwn create mode 100644 doc/todo/allow_option_for_requiring_description_when_editing_page.mdwn create mode 100644 doc/todo/allow_plugins_to_add_sorting_methods.mdwn create mode 100644 doc/todo/allow_site-wide_meta_definitions.mdwn create mode 100644 doc/todo/allow_wiki_syntax_in_commit_messages.mdwn create mode 100644 doc/todo/anon_push_of_comments.mdwn create mode 100644 doc/todo/anti-spam_protection.mdwn create mode 100644 doc/todo/apache_404_ErrorDocument_handler.mdwn create mode 100644 doc/todo/applydiff_plugin.mdwn create mode 100644 doc/todo/assumes_system_perl.mdwn create mode 100644 doc/todo/attachments.mdwn create mode 100644 doc/todo/auto-create_tag_pages_according_to_a_template.mdwn create mode 100644 doc/todo/auto_getctime_on_fresh_build.mdwn create mode 100644 doc/todo/auto_publish_expire.mdwn create mode 100644 doc/todo/auto_rebuild_on_template_change.mdwn create mode 100644 doc/todo/autoindex_should_use_add__95__autofile.mdwn create mode 100644 doc/todo/automatic_rebuilding_of_html_pages.mdwn create mode 100644 doc/todo/automatic_use_of_syntax_plugin_on_source_code_files.mdwn create mode 100644 doc/todo/automatic_use_of_syntax_plugin_on_source_code_files/discussion.mdwn create mode 100644 doc/todo/avatar.mdwn create mode 100644 doc/todo/avatar/discussion.mdwn create mode 100644 doc/todo/avoid_attachement_ui_if_upload_not_allowed.mdwn create mode 100644 doc/todo/avoid_thrashing.mdwn create mode 100644 doc/todo/backlinks_result_is_lossy.mdwn create mode 100644 doc/todo/basewiki_should_be_self_documenting.mdwn create mode 100644 doc/todo/be_more_selective_about_running_hooks.mdwn create mode 100644 doc/todo/beef_up_sidebar_to_allow_for_multiple_sidebars.mdwn create mode 100644 doc/todo/beef_up_signin_page.mdwn create mode 100644 doc/todo/bitcoin_URI_scheme.mdwn create mode 100644 doc/todo/block_external_links.mdwn create mode 100644 doc/todo/blocking_ip_ranges.mdwn create mode 100644 doc/todo/blogging.mdwn create mode 100644 doc/todo/blogpost_plugin.mdwn create mode 100644 doc/todo/blogs.mdwn create mode 100644 doc/todo/blogspam_training.mdwn create mode 100644 doc/todo/break_up_page_template_into_subfiles.mdwn create mode 100644 doc/todo/brokenlinks_should_group_links_to_a_page.mdwn create mode 100644 doc/todo/bugs-everywhere_integration.mdwn create mode 100644 doc/todo/bzr.mdwn create mode 100644 doc/todo/cache_backlinks.mdwn create mode 100644 doc/todo/calendar_--_archive_browsing_via_a_calendar_frontend.mdwn create mode 100644 doc/todo/calendar_autocreate.mdwn create mode 100644 doc/todo/calendar_with___34__create__34___links.mdwn create mode 100644 doc/todo/calendar_with___34__create__34___links/incomplete_patch.pl create mode 100644 doc/todo/call_git-update-server-info_from_post-udpate_hook.mdwn create mode 100644 doc/todo/canonical_feed_location.mdwn create mode 100644 doc/todo/capitalize_title.mdwn create mode 100644 doc/todo/cas_authentication.mdwn create mode 100644 doc/todo/cdate_and_mdate_available_for_templates.mdwn create mode 100644 doc/todo/cgi_hooks_get_session_objects.mdwn create mode 100644 doc/todo/clear_page_to_delete.mdwn create mode 100644 doc/todo/clickable-openid-urls-in-logs.mdwn create mode 100644 doc/todo/color_plugin.mdwn create mode 100644 doc/todo/comment_by_mail.mdwn create mode 100644 doc/todo/comment_by_mail/discussion.mdwn create mode 100644 doc/todo/comment_moderation_feed.mdwn create mode 100644 doc/todo/comments.mdwn create mode 100644 doc/todo/concatenating_or_compiling_CSS.mdwn create mode 100644 doc/todo/conditional_text_based_on_ikiwiki_features.mdwn create mode 100644 doc/todo/conditional_underlay_files.mdwn create mode 100644 doc/todo/configurable_markdown_path.mdwn create mode 100644 doc/todo/configurable_tidy_command_for_htmltidy.mdwn create mode 100644 doc/todo/configurable_timezones.mdwn create mode 100644 doc/todo/conflict_free_comment_merges.mdwn create mode 100644 doc/todo/consistent_smileys.mdwn create mode 100644 doc/todo/copyright_based_on_pagespec.mdwn create mode 100644 doc/todo/correct_published_and_updated_time_information_for_the_feeds.mdwn create mode 100644 doc/todo/countdown_directive.mdwn create mode 100644 doc/todo/credentials_page.mdwn create mode 100644 doc/todo/ctime_on_blog_post_pages_.mdwn create mode 100644 doc/todo/custom_location_for_openlayers.mdwn create mode 100644 doc/todo/darcs.mdwn create mode 100644 doc/todo/datearchives-plugin.mdwn create mode 100644 doc/todo/default_content_for_new_post.mdwn create mode 100644 doc/todo/default_name_for_new_post.mdwn create mode 100644 doc/todo/dependency_types.mdwn create mode 100644 doc/todo/description_meta_param_passed_to_templates.mdwn create mode 100644 doc/todo/different_search_engine.mdwn create mode 100644 doc/todo/directive_docs.mdwn create mode 100644 doc/todo/discuss_without_login.mdwn create mode 100644 doc/todo/discussion_page_as_blog.mdwn create mode 100644 doc/todo/discussion_page_as_blog/discussion/castle.mdwn create mode 100644 doc/todo/discussion_page_as_blog/discussion/castle/discussion.mdwn create mode 100644 doc/todo/discussion_page_as_blog/discussion/castle/discussion/Don__39__t_like_foo.mdwn create mode 100644 doc/todo/discussion_page_as_blog/discussion/castle/discussion/Don__39__t_like_foo/how_about_bar.mdwn create mode 100644 doc/todo/discussion_page_as_blog/discussion/castle/discussion/Don__39__t_like_foo/sdf.mdwn create mode 100644 doc/todo/discussion_page_as_blog/discussion/castle/discussion/foo_is_ok.mdwn create mode 100644 doc/todo/discussion_page_as_blog/discussion/castle/discussion/test.mdwn create mode 100644 doc/todo/do_not_make_links_backwards.mdwn create mode 100644 doc/todo/document_dependency_influences_in_code.mdwn create mode 100644 doc/todo/done.mdwn create mode 100644 doc/todo/double-click_protection_for_form_buttons.mdwn create mode 100644 doc/todo/doxygen_support.mdwn create mode 100644 doc/todo/dynamic_rootpage.mdwn create mode 100644 doc/todo/ease_archivepage_styling.mdwn create mode 100644 doc/todo/edit_form:_no_fixed_size_for_textarea.mdwn create mode 100644 doc/todo/edittemplate_should_look_in_templates_directory_by_default.mdwn create mode 100644 doc/todo/edittemplate_should_support_uuid__44___date_variables.mdwn create mode 100644 doc/todo/else_parameter_for_map_plugin.mdwn create mode 100644 doc/todo/enable-htaccess-files.mdwn create mode 100644 doc/todo/enable_arbitrary_markup_for_directives.mdwn create mode 100644 doc/todo/etherpad_support.mdwn create mode 100644 doc/todo/excluding_commit_mails.mdwn create mode 100644 doc/todo/expose_html_language_and_direction.mdwn create mode 100644 doc/todo/fancypodcast.mdwn create mode 100644 doc/todo/fancypodcast/discussion.mdwn create mode 100644 doc/todo/fastcgi_or_modperl_installation_instructions.mdwn create mode 100644 doc/todo/feed_enhancements_for_inline_pages.mdwn create mode 100644 doc/todo/fileupload.mdwn create mode 100644 doc/todo/fileupload/discussion.mdwn create mode 100644 doc/todo/fileupload/soc-proposal.mdwn create mode 100644 doc/todo/fileupload/soc-proposal/discussion.mdwn create mode 100644 doc/todo/filtering_content_when_inlining.mdwn create mode 100644 doc/todo/finer_control_over___60__object___47____62__s.mdwn create mode 100644 doc/todo/firm_up_plugin_interface.mdwn create mode 100644 doc/todo/flexible_relationships_between_pages.mdwn create mode 100644 doc/todo/flexible_relationships_between_pages/blocks.pm.mdwn create mode 100644 doc/todo/for_amazon_s3_pre-gzip-encode_safe_files.mdwn create mode 100644 doc/todo/format_escape.mdwn create mode 100644 doc/todo/fortune:_select_options_via_environment.mdwn create mode 100644 doc/todo/friendly_markup_names.mdwn create mode 100644 doc/todo/generated_po_stuff_not_ignored_by_git.mdwn create mode 100644 doc/todo/generic___39__do__61__goto__39___for_CGI.mdwn create mode 100644 doc/todo/generic_insert_links.mdwn create mode 100644 doc/todo/geotagging.mdwn create mode 100644 doc/todo/git-annex_support.mdwn create mode 100644 doc/todo/git-annex_support/discussion.mdwn create mode 100644 doc/todo/git-rev-list_requires_relative_path___40__fixes_git_ctime__41__.mdwn create mode 100644 doc/todo/git_attribution.mdwn create mode 100644 doc/todo/git_attribution/discussion.mdwn create mode 100644 doc/todo/git_recentchanges_should_not_show_merges.mdwn create mode 100644 doc/todo/graphviz.mdwn create mode 100644 doc/todo/hard-coded_location_for_man_pages_and_w3m_cgi_wrapper.mdwn create mode 100644 doc/todo/headless_git_branches.mdwn create mode 100644 doc/todo/hidden_links__47__tags.mdwn create mode 100644 doc/todo/hook_to_detect_markdown_links_to_wiki_pages.mdwn create mode 100644 doc/todo/html.mdwn create mode 100644 doc/todo/htmlvalidation.mdwn create mode 100644 doc/todo/htpasswd_mirror_of_the_userdb.mdwn create mode 100644 doc/todo/http_bl_support.mdwn create mode 100644 doc/todo/httpauth_example.mdwn create mode 100644 doc/todo/httpauth_example/discussion.mdwn create mode 100644 doc/todo/httpauth_feature_parity_with_passwordauth.mdwn create mode 100644 doc/todo/hyphenation.mdwn create mode 100644 doc/todo/ikibot.mdwn create mode 100644 doc/todo/improve_decentralised_wikis_documentation_and_graphics.mdwn create mode 100644 doc/todo/improve_globlists.mdwn create mode 100644 doc/todo/improved_mediawiki_support.mdwn create mode 100644 doc/todo/improved_parentlinks_styling.mdwn create mode 100644 doc/todo/inband_acl_data.mdwn create mode 100644 doc/todo/index.html_allowed.mdwn create mode 100644 doc/todo/inline:_numerical_ordering_by_title.mdwn create mode 100644 doc/todo/inline_directive_should_support_pagination.mdwn create mode 100644 doc/todo/inline_option_for_pagespec-specific_show__61__N.mdwn create mode 100644 doc/todo/inline_plugin:_ability_to_override_feed_name.mdwn create mode 100644 doc/todo/inline_plugin:_hide_feed_buttons_if_empty.mdwn create mode 100644 doc/todo/inline_plugin:_specifying_ordered_page_names.mdwn create mode 100644 doc/todo/inline_postform_autotitles.mdwn create mode 100644 doc/todo/inline_raw_files.mdwn create mode 100644 doc/todo/inlines_inheriting_links.mdwn create mode 100644 doc/todo/integration_with_Firefox_and_Iceweasel_feed_subscription_mechanism.mdwn create mode 100644 doc/todo/interactive_todo_lists.mdwn create mode 100644 doc/todo/internal_definition_list_support.mdwn create mode 100644 doc/todo/l10n.mdwn create mode 100644 doc/todo/language_definition_for_the_meta_plugin.mdwn create mode 100644 doc/todo/latex.mdwn create mode 100644 doc/todo/latex/discussion.mdwn create mode 100644 doc/todo/let_inline_plugin_use_pagetemplates.mdwn create mode 100644 doc/todo/limit_the_markup_formats_available_for_editing.mdwn create mode 100644 doc/todo/link_map.mdwn create mode 100644 doc/todo/link_plugin_perhaps_too_general__63__.mdwn create mode 100644 doc/todo/linkbase.mdwn create mode 100644 doc/todo/linkify_and_preprocessor_ordering.mdwn create mode 100644 doc/todo/linktitle.mdwn create mode 100644 doc/todo/lists.mdwn create mode 100644 doc/todo/location_of_external_plugins.mdwn create mode 100644 doc/todo/location_of_ikiwiki-w3m.cgi.mdwn create mode 100644 doc/todo/logo.mdwn create mode 100644 doc/todo/lucene_search_engine.mdwn create mode 100644 doc/todo/mailnotification.mdwn create mode 100644 doc/todo/mailnotification/discussion.mdwn create mode 100644 doc/todo/make_html-parser_use_encode_entities_numeric.mdwn create mode 100644 doc/todo/make_link_target_search_all_paths_as_fallback.mdwn create mode 100644 doc/todo/manpages.mdwn create mode 100644 doc/todo/mark_edit_as_trivial__44___identify__47__filter_on_trivial_changes.mdwn create mode 100644 doc/todo/matching_different_kinds_of_links.mdwn create mode 100644 doc/todo/mbox.mdwn create mode 100644 doc/todo/mdwn_itex.mdwn create mode 100644 doc/todo/mdwn_preview.mdwn create mode 100644 doc/todo/mdwn_preview/discussion.mdwn create mode 100644 doc/todo/mercurial.mdwn create mode 100644 doc/todo/mercurial/discussion.mdwn create mode 100644 doc/todo/meta_rcsid.mdwn create mode 100644 doc/todo/metadata.mdwn create mode 100644 doc/todo/minor_adjustment_to_setup_documentation_for_recentchanges_feeds.mdwn create mode 100644 doc/todo/mirrorlist_with_per-mirror_usedirs_settings.mdwn create mode 100644 doc/todo/missingparents.pm.mdwn create mode 100644 doc/todo/modify_page_filename_in_plugin.mdwn create mode 100644 doc/todo/monochrome_theme.mdwn create mode 100644 doc/todo/more_class__61____34____34___for_css.mdwn create mode 100644 doc/todo/more_customisable_titlepage_function.mdwn create mode 100644 doc/todo/more_flexible_inline_postform.mdwn create mode 100644 doc/todo/mtime.mdwn create mode 100644 doc/todo/multi-thread_ikiwiki.mdwn create mode 100644 doc/todo/multiple_output_formats.mdwn create mode 100644 doc/todo/multiple_repository_support.mdwn create mode 100644 doc/todo/multiple_simultaneous_rcs.mdwn create mode 100644 doc/todo/multiple_simultaneous_rcs/discussion.mdwn create mode 100644 doc/todo/multiple_template_directories.mdwn create mode 100644 doc/todo/multiple_templates.mdwn create mode 100644 doc/todo/natural_sorting.mdwn create mode 100644 doc/todo/need_global_renamepage_hook.mdwn create mode 100644 doc/todo/nested_preprocessor_directives.mdwn create mode 100644 doc/todo/online_configuration.mdwn create mode 100644 doc/todo/openid_enable_cache.mdwn create mode 100644 doc/todo/openid_user_filtering.mdwn create mode 100644 doc/todo/optimisation_via_git_log.mdwn create mode 100644 doc/todo/optimisations.mdwn create mode 100644 doc/todo/optimize_simple_dependencies.mdwn create mode 100644 doc/todo/option_to_send_only_the_diff_in_notifyemail.mdwn create mode 100644 doc/todo/optional_underlaydir_prefix.mdwn create mode 100644 doc/todo/org_mode.mdwn create mode 100644 doc/todo/org_mode/Discussion.mdwn create mode 100644 doc/todo/osm__95__optimisations__95__and__95__fixes.mdwn create mode 100644 doc/todo/osm_arbitrary_layers.mdwn create mode 100644 doc/todo/osm_plugin_GeoJSON_popup_patch.mdwn create mode 100644 doc/todo/osm_plugin_icon_patch.mdwn create mode 100644 doc/todo/outbound_proxy.mdwn create mode 100644 doc/todo/overriding_displayed_modification_time.mdwn create mode 100644 doc/todo/page_edit_disable.mdwn create mode 100644 doc/todo/pagedeletion.mdwn create mode 100644 doc/todo/pagedown_plugin.mdwn create mode 100644 doc/todo/pagedown_plugin/discussion.mdwn create mode 100644 doc/todo/pageindexes.mdwn create mode 100644 doc/todo/pagespec__95__match__95__list_can_result_in_excessive_dependencies.mdwn create mode 100644 doc/todo/pagespec_aliases.mdwn create mode 100644 doc/todo/pagespec_aliases/discussion.mdwn create mode 100644 doc/todo/pagespec_expansions.mdwn create mode 100644 doc/todo/pagespec_relative_to_a_target.mdwn create mode 100644 doc/todo/pagespec_to_disable_ikiwiki_directives.mdwn create mode 100644 doc/todo/pagestats_among_a_subset_of_pages.mdwn create mode 100644 doc/todo/pal_plugin.mdwn create mode 100644 doc/todo/parse_debian_packages.mdwn create mode 100644 doc/todo/passwordauth:_sendmail_interface.mdwn create mode 100644 doc/todo/paste_plugin.mdwn create mode 100644 doc/todo/pastebin.mdwn create mode 100644 doc/todo/pdf_output.mdwn create mode 100644 doc/todo/pdfshare_plugin.mdwn create mode 100644 doc/todo/pedigree_plugin.mdwn create mode 100644 doc/todo/per-page_comment_control.mdwn create mode 100644 doc/todo/per_page_ACLs.mdwn create mode 100644 doc/todo/pick_a_new_canonical_name_for_equivalent_of_SQL_limit.mdwn create mode 100644 doc/todo/pingback_support.mdwn create mode 100644 doc/todo/please_add_some_table_styles.mdwn create mode 100644 doc/todo/pluggablerenderers.mdwn create mode 100644 doc/todo/plugin.mdwn create mode 100644 doc/todo/plugin_data_storage.mdwn create mode 100644 doc/todo/plugin_dependency_calulation.mdwn create mode 100644 doc/todo/po:_add_lang_name_and_code_template_variables.mdwn create mode 100644 doc/todo/po:_avoid_rebuilding_to_fix_meta_titles.mdwn create mode 100644 doc/todo/po:_better_documentation.mdwn create mode 100644 doc/todo/po:_better_links.mdwn create mode 100644 doc/todo/po:_better_translation_interface.mdwn create mode 100644 doc/todo/po:_remove_po_files_when_disabling_plugin.mdwn create mode 100644 doc/todo/po:_rethink_pagespecs.mdwn create mode 100644 doc/todo/po:_should_cleanup_.pot_files.mdwn create mode 100644 doc/todo/po:_transifex_integration.mdwn create mode 100644 doc/todo/po:_translation_of_directives.mdwn create mode 100644 doc/todo/po_needstranslation_pagespec.mdwn create mode 100644 doc/todo/polltrails.mdwn create mode 100644 doc/todo/preprocessor_directive_for_proposed_changes.mdwn create mode 100644 doc/todo/pretty-print_OpenIDs_even_if_not_enabled.mdwn create mode 100644 doc/todo/preview_changes.mdwn create mode 100644 doc/todo/preview_changes_before_git_commit.mdwn create mode 100644 doc/todo/progressbar_plugin.mdwn create mode 100644 doc/todo/provide_a_mailing_list.mdwn create mode 100644 doc/todo/provide_inline_diffs_in_recentchanges.mdwn create mode 100644 doc/todo/provide_sha1_for_git_diffurl.mdwn create mode 100644 doc/todo/publishing_in_the_future.mdwn create mode 100644 doc/todo/quieten-bzr.mdwn create mode 100644 doc/todo/rcs.mdwn create mode 100644 doc/todo/rcs__95__diff_implementation_for_Mercurial_backend__44___based_on_Git_backend.mdwn create mode 100644 doc/todo/rcs__95__get__123__c__44__m__125__time_implementation_for_Mercurial_backend__44___based_on_Git_backend.mdwn create mode 100644 doc/todo/rcs_updates_needed.mdwn create mode 100644 doc/todo/recentchanges.mdwn create mode 100644 doc/todo/recentchanges_feed_with_comment.mdwn create mode 100644 doc/todo/recentchanges_path.mdwn create mode 100644 doc/todo/recommend_libtext-markdown-discount_instead_of_depending.mdwn create mode 100644 doc/todo/redirect.mdwn create mode 100644 doc/todo/redirect_automatically_after_rename.mdwn create mode 100644 doc/todo/refreshing_recentchanges_page.mdwn create mode 100644 doc/todo/rel__61__nofollow_on_external_links.mdwn create mode 100644 doc/todo/rel_attribute_for_links.mdwn create mode 100644 doc/todo/relative_pagespec_deficiency.mdwn create mode 100644 doc/todo/remove_basewiki_redir_pages.mdwn create mode 100644 doc/todo/replace_HTML::Template_with_Template_Toolkit.mdwn create mode 100644 doc/todo/require_CAPTCHA_to_edit.mdwn create mode 100644 doc/todo/review_mechanism.mdwn create mode 100644 doc/todo/rewrite_ikiwiki_in_haskell.mdwn create mode 100644 doc/todo/rewrite_ikiwiki_in_haskell/discussion.mdwn create mode 100644 doc/todo/rss_title_description.mdwn create mode 100644 doc/todo/rst_plugin_python_rewrite.mdwn create mode 100644 doc/todo/salmon_protocol_for_comment_sharing.mdwn create mode 100644 doc/todo/search.mdwn create mode 100644 doc/todo/search_terms.mdwn create mode 100644 doc/todo/section-numbering.mdwn create mode 100644 doc/todo/selective_more_directive.mdwn create mode 100644 doc/todo/send_only_one_mail_per_page_in_notifyemail.mdwn create mode 100644 doc/todo/shortcut_link_text.mdwn create mode 100644 doc/todo/shortcut_optional_parameters.mdwn create mode 100644 doc/todo/shortcut_with_different_link_text.mdwn create mode 100644 doc/todo/shortcut_with_no_url_parameter__44___only_desc.mdwn create mode 100644 doc/todo/should_optimise_pagespecs.mdwn create mode 100644 doc/todo/should_use_a_standard_encoding_for_utf_chars_in_filenames.mdwn create mode 100644 doc/todo/sigs.mdwn create mode 100644 doc/todo/sigs/discussion.mdwn create mode 100644 doc/todo/simple_text_parsing_or_regex_in_template_or_shortcut.mdwn create mode 100644 doc/todo/skip_option_for_inline_plugin.mdwn create mode 100644 doc/todo/smarter_sorting.mdwn create mode 100644 doc/todo/smileys_do_not_work_in_PreprocessorDirective_arguments.mdwn create mode 100644 doc/todo/softlinks.mdwn create mode 100644 doc/todo/sort_parameter_for_map_plugin_and_directive.mdwn create mode 100644 doc/todo/sort_parameter_for_map_plugin_and_directive/incomplete_patch.pl.pl create mode 100644 doc/todo/sort_parameter_for_map_plugin_and_directive/python_algorithms.py create mode 100644 doc/todo/sortable_tables.mdwn create mode 100644 doc/todo/sortbylastcomment_plugin.mdwn create mode 100644 doc/todo/sorting_by_path.mdwn create mode 100644 doc/todo/source_link.mdwn create mode 100644 doc/todo/spell_check_plug-in.mdwn create mode 100644 doc/todo/strftime.mdwn create mode 100644 doc/todo/structured_page_data.mdwn create mode 100644 doc/todo/structured_page_data/discussion.mdwn create mode 100644 doc/todo/stylesheet_suggestion_for_verbatim_content.mdwn create mode 100644 doc/todo/submodule_support.mdwn create mode 100644 doc/todo/support_creole_markup.mdwn create mode 100644 doc/todo/support_dicts_in_setup.mdwn create mode 100644 doc/todo/support_for_SDF_documents.mdwn create mode 100644 doc/todo/support_for_plugins_written_in_other_languages.mdwn create mode 100644 doc/todo/support_includes_in_setup_files.mdwn create mode 100644 doc/todo/support_link__40__.__41___in_pagespec.mdwn create mode 100644 doc/todo/support_linking_to_cgit.mdwn create mode 100644 doc/todo/support_multi-row_table_headers.mdwn create mode 100644 doc/todo/support_multiple_perl_libraries.mdwn create mode 100644 doc/todo/supporting_comments_via_disussion_pages.mdwn create mode 100644 doc/todo/svg.mdwn create mode 100644 doc/todo/syntax_highlighting.mdwn create mode 100644 doc/todo/syntax_highlighting/discussion.mdwn create mode 100644 doc/todo/syslog_should_show_wiki_name.mdwn create mode 100644 doc/todo/table_with_header_column.mdwn create mode 100644 doc/todo/tag_pagespec_function.mdwn create mode 100644 doc/todo/tagging_with_a_publication_date.mdwn create mode 100644 doc/todo/tags.mdwn create mode 100644 doc/todo/target_filter_for_brokenlinks.mdwn create mode 100644 doc/todo/terminalclient.mdwn create mode 100644 doc/todo/test_coverage.mdwn create mode 100644 doc/todo/themes_should_ship_with_templates.mdwn create mode 100644 doc/todo/tidy_git__39__s_ctime_debug_output.mdwn create mode 100644 doc/todo/tla.mdwn create mode 100644 doc/todo/tmplvars_plugin.mdwn create mode 100644 doc/todo/tmplvars_plugin/discussion.mdwn create mode 100644 doc/todo/toc-with-human-readable-anchors.mdwn create mode 100644 doc/todo/toc_plugin:_set_a_header_ceiling___40__opposite_of_levels__61____41__.mdwn create mode 100644 doc/todo/toc_plugin_to_skip_one_level.mdwn create mode 100644 doc/todo/toggle_initial_state.mdwn create mode 100644 doc/todo/toplevel_index.mdwn create mode 100644 doc/todo/tracking_bugs_with_dependencies.mdwn create mode 100644 doc/todo/transient_pages.mdwn create mode 100644 doc/todo/translation_links.mdwn create mode 100644 doc/todo/turn_edittemplate_verbosity_off_by_default.mdwn create mode 100644 doc/todo/two-way_convert_of_wikis.mdwn create mode 100644 doc/todo/typography_plugin_configuration.mdwn create mode 100644 doc/todo/unaccent_url_instead_of_encoding.mdwn create mode 100644 doc/todo/underlay.mdwn create mode 100644 doc/todo/unified_temporary_file__47__directory_handling.mdwn create mode 100644 doc/todo/untrusted_git_push_hooks.mdwn create mode 100644 doc/todo/upgradehooks.mdwn create mode 100644 doc/todo/upload__95__figure.mdwn create mode 100644 doc/todo/use_secure_cookies_for_ssl_logins.mdwn create mode 100644 doc/todo/use_templates_for_the_img_plugin.mdwn create mode 100644 doc/todo/usedirs__95__redir_proposed_additional_module.mdwn create mode 100644 doc/todo/user-defined_templates_outside_the_wiki.mdwn create mode 100644 doc/todo/user-subdir_mechanism_like_etc_ikiwiki_wikilist.mdwn create mode 100644 doc/todo/userdir_links.mdwn create mode 100644 doc/todo/utf8.mdwn create mode 100644 doc/todo/vCard_rendering.mdwn create mode 100644 doc/todo/varioki_--_add_template_variables___40__with_closures_for_values__41___in_ikiwiki.setup.mdwn create mode 100644 doc/todo/want_to_avoid_ikiwiki_using_http_or_https_in_urls_to_allow_serving_both.mdwn create mode 100644 doc/todo/wanted_pages_plugin.mdwn create mode 100644 doc/todo/wdiffs_in_recentchanges.mdwn create mode 100644 doc/todo/web-based_image_editing.mdwn create mode 100644 doc/todo/web_gui_for_managing_tags.mdwn create mode 100644 doc/todo/web_reversion.mdwn create mode 100644 doc/todo/websetup_should_link_to_plugin_descriptions.mdwn create mode 100644 doc/todo/wiki-formatted_comments_with_syntax_plugin.mdwn create mode 100644 doc/todo/wikilink_titles.mdwn create mode 100644 doc/todo/wikilinkfeatures.mdwn create mode 100644 doc/todo/wikitrails.mdwn create mode 100644 doc/todo/wikitrails/discussion.mdwn create mode 100644 doc/todo/wikiwyg.mdwn create mode 100644 doc/todo/wikiwyg/discussion.mdwn create mode 100644 doc/todo/wmd_editor_live_preview.mdwn create mode 100644 doc/todo/wrapperuser.mdwn create mode 100644 doc/todo/xapian_omega_same_lang_when_indexing_and_searching.mdwn create mode 100644 doc/translation.mdwn create mode 100644 doc/translation/discussion.mdwn create mode 100644 doc/usage.mdwn create mode 100644 doc/usage/discussion.mdwn create mode 100644 doc/users.mdwn create mode 100644 doc/users/BerndZeimetz.mdwn create mode 100644 doc/users/Christine_Spang.mdwn create mode 100644 doc/users/DamianSmall.mdwn create mode 100644 doc/users/Daniel_Andersson.mdwn create mode 100644 doc/users/DavidBremner.mdwn create mode 100644 doc/users/David_Riebenbauer.mdwn create mode 100644 doc/users/Edward_Betts.mdwn create mode 100644 doc/users/Erkan_Yilmaz.mdwn create mode 100644 doc/users/Gianpaolo_Macario.mdwn create mode 100644 doc/users/GiuseppeBilotta.mdwn create mode 100644 doc/users/HenrikBrixAndersen.mdwn create mode 100644 doc/users/Jamie.mdwn create mode 100644 doc/users/JeremieKoenig.mdwn create mode 100644 doc/users/Jimmy_Tang.mdwn create mode 100644 doc/users/JoshBBall.mdwn create mode 100644 doc/users/Kai_Hendry.mdwn create mode 100644 doc/users/KarlMW.mdwn create mode 100644 doc/users/KarlMW/discussion.mdwn create mode 100644 doc/users/KathrynAndersen.mdwn create mode 100644 doc/users/KathrynAndersen/discussion.mdwn create mode 100644 doc/users/Larry_Clapp.mdwn create mode 100644 doc/users/LucaCapello.mdwn create mode 100644 doc/users/MatthiasIhrke.mdwn create mode 100644 doc/users/Mick_Pollard.mdwn create mode 100644 doc/users/NeilSmithline.mdwn create mode 100644 doc/users/NicolasLimare.mdwn create mode 100644 doc/users/Oblomov.mdwn create mode 100644 doc/users/Olea.mdwn create mode 100644 doc/users/OscarMorante.mdwn create mode 100644 doc/users/Perry.mdwn create mode 100644 doc/users/Ramsey.mdwn create mode 100644 doc/users/Remy.mdwn create mode 100644 doc/users/RickOwens.mdwn create mode 100644 doc/users/Simon_Michael.mdwn create mode 100644 doc/users/Stefano_Zacchiroli.mdwn create mode 100644 doc/users/StevenBlack.mdwn create mode 100644 doc/users/TaylorKillian.mdwn create mode 100644 doc/users/TaylorKillian/discussion.mdwn create mode 100644 doc/users/The_TOVA_Company.mdwn create mode 100644 doc/users/TimBosse.mdwn create mode 100644 doc/users/Tim_Lavoie.mdwn create mode 100644 doc/users/Will.mdwn create mode 100644 doc/users/acathur.mdwn create mode 100644 doc/users/acodispo.mdwn create mode 100644 doc/users/adamshand.mdwn create mode 100644 doc/users/ajt.mdwn create mode 100644 doc/users/aland.mdwn create mode 100644 doc/users/alexander.mdwn create mode 100644 doc/users/alexandredupas.mdwn create mode 100644 doc/users/anarcat.mdwn create mode 100644 doc/users/anarcat.wiki create mode 100644 doc/users/arpitjain.mdwn create mode 100644 doc/users/bartmassey.mdwn create mode 100644 doc/users/bbb.mdwn create mode 100644 doc/users/blipvert.mdwn create mode 100644 doc/users/bstpierre.mdwn create mode 100644 doc/users/cbaines.mdwn create mode 100644 doc/users/cfm.mdwn create mode 100644 doc/users/chris.mdwn create mode 100644 doc/users/chrismgray.mdwn create mode 100644 doc/users/chrysn.mdwn create mode 100644 doc/users/chrysn/interests.mdwn create mode 100644 doc/users/cord.mdwn create mode 100644 doc/users/cstamas.mdwn create mode 100644 doc/users/dark.mdwn create mode 100644 doc/users/dato.mdwn create mode 100644 doc/users/dirk.mdwn create mode 100644 doc/users/dom.mdwn create mode 100644 doc/users/donmarti.mdwn create mode 100644 doc/users/emptty.mdwn create mode 100644 doc/users/ericdrechsel.mdwn create mode 100644 doc/users/fil.mdwn create mode 100644 doc/users/fmarier.mdwn create mode 100644 doc/users/fr33domlover.mdwn create mode 100644 doc/users/harishcm.mdwn create mode 100644 doc/users/harningt.mdwn create mode 100644 doc/users/hb.mdwn create mode 100644 doc/users/hb/discussion.mdwn create mode 100644 doc/users/hendry.mdwn create mode 100644 doc/users/holger.mdwn create mode 100644 doc/users/intrigeri.mdwn create mode 100644 doc/users/iustin.mdwn create mode 100644 doc/users/ivan_shmakov.mdwn create mode 100644 doc/users/jasonblevins.mdwn create mode 100644 doc/users/jasonriedy.mdwn create mode 100644 doc/users/jaywalk.mdwn create mode 100644 doc/users/jcorneli.mdwn create mode 100644 doc/users/jeanprivat.mdwn create mode 100644 doc/users/jelmer.mdwn create mode 100644 doc/users/jeremyreed.mdwn create mode 100644 doc/users/jerojasro.mdwn create mode 100644 doc/users/jmtd.mdwn create mode 100644 doc/users/joey.mdwn create mode 100644 doc/users/jogo.mdwn create mode 100644 doc/users/jon.mdwn create mode 100644 doc/users/jonassmedegaard.mdwn create mode 100644 doc/users/josephturian.mdwn create mode 100644 doc/users/joshtriplett.mdwn create mode 100644 doc/users/joshtriplett/discussion.mdwn create mode 100644 doc/users/jrblevin.mdwn create mode 100644 doc/users/justint.mdwn create mode 100644 doc/users/jwalzer.mdwn create mode 100644 doc/users/kjs.mdwn create mode 100644 doc/users/kyle.mdwn create mode 100644 doc/users/madduck.mdwn create mode 100644 doc/users/marcelomagallon.mdwn create mode 100644 doc/users/mathdesc.mdwn create mode 100644 doc/users/mhameed.mdwn create mode 100644 doc/users/michaelrasmussen.wiki create mode 100644 doc/users/neale.mdwn create mode 100644 doc/users/nil.mdwn create mode 100644 doc/users/nolan.mdwn create mode 100644 doc/users/patrickwinnertz.mdwn create mode 100644 doc/users/pdurbin.mdwn create mode 100644 doc/users/pelle.mdwn create mode 100644 doc/users/perolofsson.mdwn create mode 100644 doc/users/peteg.mdwn create mode 100644 doc/users/peter_woodman.mdwn create mode 100644 doc/users/ptecza.mdwn create mode 100644 doc/users/rubykat.mdwn create mode 100644 doc/users/sabr.mdwn create mode 100644 doc/users/sabr/sub1.mdwn create mode 100644 doc/users/sabr/sub2.mdwn create mode 100644 doc/users/schmonz-web-ikiwiki.mdwn create mode 100644 doc/users/schmonz.mdwn create mode 100644 doc/users/seanh.mdwn create mode 100644 doc/users/simonraven.mdwn create mode 100644 doc/users/smcv.mdwn create mode 100644 doc/users/smcv/gallery.mdwn create mode 100644 doc/users/smcv/gallery/discussion.mdwn create mode 100644 doc/users/smcv/ready.mdwn create mode 100644 doc/users/solofo.mdwn create mode 100644 doc/users/spalax.mdwn create mode 100644 doc/users/sphynkx.mdwn create mode 100644 doc/users/ssm.mdwn create mode 100644 doc/users/sunny256.mdwn create mode 100644 doc/users/svend.mdwn create mode 100644 doc/users/tbm.mdwn create mode 100644 doc/users/tjgolubi.mdwn create mode 100644 doc/users/tschwinge.mdwn create mode 100644 doc/users/ttw.mdwn create mode 100644 doc/users/tupyakov_vladimir.mdwn create mode 100644 doc/users/tychoish.mdwn create mode 100644 doc/users/ulrik.mdwn create mode 100644 doc/users/undx.mdwn create mode 100644 doc/users/victormoral.mdwn create mode 100644 doc/users/weakish.mdwn create mode 100644 doc/users/weakishjiang.mdwn create mode 100644 doc/users/wentasah.mdwn create mode 100644 doc/users/wiebel.mdwn create mode 100644 doc/users/wtk.mdwn create mode 100644 doc/users/xma/discussion.mdwn create mode 100644 doc/users/xtaran.mdwn create mode 100644 doc/users/yds.mdwn create mode 100644 doc/w3mmode.mdwn create mode 100644 doc/w3mmode/ikiwiki.setup create mode 100644 doc/whyikiwiki.mdwn create mode 100644 doc/wikiicons/diff.png create mode 100644 doc/wikiicons/openidlogin-bg.gif create mode 100644 doc/wikiicons/revert.png create mode 100644 doc/wikiicons/search-bg.gif create mode 100644 doc/wishlist.mdwn create mode 100644 doc/wishlist/watched_pages.mdwn create mode 100644 docwiki.setup create mode 100755 gitremotes create mode 100644 icons/aol.svg create mode 100644 icons/livejournal.svg create mode 100644 icons/verisign.svg create mode 100755 ikiwiki-calendar.in create mode 100755 ikiwiki-makerepo create mode 100755 ikiwiki-mass-rebuild create mode 100755 ikiwiki-transition.in create mode 100755 ikiwiki-update-wikilist create mode 100755 ikiwiki-w3m.cgi create mode 100755 ikiwiki.in create mode 100644 ikiwiki.spec create mode 100755 mdwn2man create mode 100644 plugins/.gitignore create mode 100755 plugins/externaldemo create mode 100755 plugins/proxy.py create mode 100755 plugins/pythondemo create mode 100755 plugins/rst create mode 100755 pm_filter create mode 100644 po/.gitignore create mode 100644 po/Makefile create mode 100644 po/bg.po create mode 100644 po/cs.po create mode 100644 po/da.po create mode 100644 po/de.po create mode 100644 po/es.po create mode 100644 po/fr.po create mode 100644 po/gu.po create mode 100644 po/ikiwiki.pot create mode 100644 po/it.po create mode 100644 po/pl.po create mode 100755 po/po2wiki create mode 100644 po/sv.po create mode 100644 po/tr.po create mode 100644 po/underlay.setup create mode 100644 po/underlays/basewiki/ikiwiki.cs.po create mode 100644 po/underlays/basewiki/ikiwiki.da.po create mode 100644 po/underlays/basewiki/ikiwiki.de.po create mode 100644 po/underlays/basewiki/ikiwiki.es.po create mode 100644 po/underlays/basewiki/ikiwiki.fr.po create mode 100644 po/underlays/basewiki/ikiwiki/directive.cs.po create mode 100644 po/underlays/basewiki/ikiwiki/directive.da.po create mode 100644 po/underlays/basewiki/ikiwiki/directive.de.po create mode 100644 po/underlays/basewiki/ikiwiki/directive.es.po create mode 100644 po/underlays/basewiki/ikiwiki/directive.fr.po create mode 100644 po/underlays/basewiki/ikiwiki/formatting.cs.po create mode 100644 po/underlays/basewiki/ikiwiki/formatting.da.po create mode 100644 po/underlays/basewiki/ikiwiki/formatting.de.po create mode 100644 po/underlays/basewiki/ikiwiki/formatting.es.po create mode 100644 po/underlays/basewiki/ikiwiki/formatting.fr.po create mode 100644 po/underlays/basewiki/ikiwiki/markdown.cs.po create mode 100644 po/underlays/basewiki/ikiwiki/markdown.da.po create mode 100644 po/underlays/basewiki/ikiwiki/markdown.de.po create mode 100644 po/underlays/basewiki/ikiwiki/markdown.es.po create mode 100644 po/underlays/basewiki/ikiwiki/markdown.fr.po create mode 100644 po/underlays/basewiki/ikiwiki/openid.cs.po create mode 100644 po/underlays/basewiki/ikiwiki/openid.da.po create mode 100644 po/underlays/basewiki/ikiwiki/openid.de.po create mode 100644 po/underlays/basewiki/ikiwiki/openid.es.po create mode 100644 po/underlays/basewiki/ikiwiki/openid.fr.po create mode 100644 po/underlays/basewiki/ikiwiki/pagespec.cs.po create mode 100644 po/underlays/basewiki/ikiwiki/pagespec.da.po create mode 100644 po/underlays/basewiki/ikiwiki/pagespec.de.po create mode 100644 po/underlays/basewiki/ikiwiki/pagespec.es.po create mode 100644 po/underlays/basewiki/ikiwiki/pagespec.fr.po create mode 100644 po/underlays/basewiki/ikiwiki/pagespec/attachment.cs.po create mode 100644 po/underlays/basewiki/ikiwiki/pagespec/attachment.da.po create mode 100644 po/underlays/basewiki/ikiwiki/pagespec/attachment.de.po create mode 100644 po/underlays/basewiki/ikiwiki/pagespec/attachment.es.po create mode 100644 po/underlays/basewiki/ikiwiki/pagespec/attachment.fr.po create mode 100644 po/underlays/basewiki/ikiwiki/pagespec/po.cs.po create mode 100644 po/underlays/basewiki/ikiwiki/pagespec/po.da.po create mode 100644 po/underlays/basewiki/ikiwiki/pagespec/po.de.po create mode 100644 po/underlays/basewiki/ikiwiki/pagespec/po.es.po create mode 100644 po/underlays/basewiki/ikiwiki/pagespec/po.fr.po create mode 100644 po/underlays/basewiki/ikiwiki/pagespec/sorting.de.po create mode 100644 po/underlays/basewiki/ikiwiki/searching.cs.po create mode 100644 po/underlays/basewiki/ikiwiki/searching.da.po create mode 100644 po/underlays/basewiki/ikiwiki/searching.de.po create mode 100644 po/underlays/basewiki/ikiwiki/searching.es.po create mode 100644 po/underlays/basewiki/ikiwiki/searching.fr.po create mode 100644 po/underlays/basewiki/ikiwiki/subpage.cs.po create mode 100644 po/underlays/basewiki/ikiwiki/subpage.da.po create mode 100644 po/underlays/basewiki/ikiwiki/subpage.de.po create mode 100644 po/underlays/basewiki/ikiwiki/subpage.es.po create mode 100644 po/underlays/basewiki/ikiwiki/subpage.fr.po create mode 100644 po/underlays/basewiki/ikiwiki/subpage/linkingrules.cs.po create mode 100644 po/underlays/basewiki/ikiwiki/subpage/linkingrules.da.po create mode 100644 po/underlays/basewiki/ikiwiki/subpage/linkingrules.de.po create mode 100644 po/underlays/basewiki/ikiwiki/subpage/linkingrules.es.po create mode 100644 po/underlays/basewiki/ikiwiki/subpage/linkingrules.fr.po create mode 100644 po/underlays/basewiki/ikiwiki/wikilink.cs.po create mode 100644 po/underlays/basewiki/ikiwiki/wikilink.da.po create mode 100644 po/underlays/basewiki/ikiwiki/wikilink.de.po create mode 100644 po/underlays/basewiki/ikiwiki/wikilink.es.po create mode 100644 po/underlays/basewiki/ikiwiki/wikilink.fr.po create mode 100644 po/underlays/basewiki/index.cs.po create mode 100644 po/underlays/basewiki/index.da.po create mode 100644 po/underlays/basewiki/index.de.po create mode 100644 po/underlays/basewiki/index.es.po create mode 100644 po/underlays/basewiki/index.fr.po create mode 100644 po/underlays/basewiki/recentchanges.cs.po create mode 100644 po/underlays/basewiki/recentchanges.da.po create mode 100644 po/underlays/basewiki/recentchanges.de.po create mode 100644 po/underlays/basewiki/recentchanges.es.po create mode 100644 po/underlays/basewiki/recentchanges.fr.po create mode 100644 po/underlays/basewiki/sandbox.cs.po create mode 100644 po/underlays/basewiki/sandbox.da.po create mode 100644 po/underlays/basewiki/sandbox.de.po create mode 100644 po/underlays/basewiki/sandbox.es.po create mode 100644 po/underlays/basewiki/sandbox.fr.po create mode 100644 po/underlays/basewiki/shortcuts.cs.po create mode 100644 po/underlays/basewiki/shortcuts.da.po create mode 100644 po/underlays/basewiki/shortcuts.de.po create mode 100644 po/underlays/basewiki/shortcuts.es.po create mode 100644 po/underlays/basewiki/shortcuts.fr.po create mode 100644 po/underlays/basewiki/templates.cs.po create mode 100644 po/underlays/basewiki/templates.da.po create mode 100644 po/underlays/basewiki/templates.de.po create mode 100644 po/underlays/basewiki/templates.es.po create mode 100644 po/underlays/basewiki/templates.fr.po create mode 100644 po/underlays/basewiki/templates/note.cs.po create mode 100644 po/underlays/basewiki/templates/note.da.po create mode 100644 po/underlays/basewiki/templates/note.de.po create mode 100644 po/underlays/basewiki/templates/note.es.po create mode 100644 po/underlays/basewiki/templates/note.fr.po create mode 100644 po/underlays/basewiki/templates/popup.cs.po create mode 100644 po/underlays/basewiki/templates/popup.da.po create mode 100644 po/underlays/basewiki/templates/popup.de.po create mode 100644 po/underlays/basewiki/templates/popup.es.po create mode 100644 po/underlays/basewiki/templates/popup.fr.po create mode 100644 po/underlays/directives/ikiwiki/directive/aggregate.da.po create mode 100644 po/underlays/directives/ikiwiki/directive/aggregate.de.po create mode 100644 po/underlays/directives/ikiwiki/directive/aggregate.fr.po create mode 100644 po/underlays/directives/ikiwiki/directive/brokenlinks.da.po create mode 100644 po/underlays/directives/ikiwiki/directive/brokenlinks.de.po create mode 100644 po/underlays/directives/ikiwiki/directive/brokenlinks.fr.po create mode 100644 po/underlays/directives/ikiwiki/directive/calendar.da.po create mode 100644 po/underlays/directives/ikiwiki/directive/calendar.de.po create mode 100644 po/underlays/directives/ikiwiki/directive/calendar.fr.po create mode 100644 po/underlays/directives/ikiwiki/directive/color.da.po create mode 100644 po/underlays/directives/ikiwiki/directive/color.de.po create mode 100644 po/underlays/directives/ikiwiki/directive/color.fr.po create mode 100644 po/underlays/directives/ikiwiki/directive/comment.da.po create mode 100644 po/underlays/directives/ikiwiki/directive/comment.de.po create mode 100644 po/underlays/directives/ikiwiki/directive/comment.fr.po create mode 100644 po/underlays/directives/ikiwiki/directive/copy.da.po create mode 100644 po/underlays/directives/ikiwiki/directive/copy.de.po create mode 100644 po/underlays/directives/ikiwiki/directive/copy.fr.po create mode 100644 po/underlays/directives/ikiwiki/directive/cut.da.po create mode 100644 po/underlays/directives/ikiwiki/directive/cut.de.po create mode 100644 po/underlays/directives/ikiwiki/directive/cut.fr.po create mode 100644 po/underlays/directives/ikiwiki/directive/cutpaste.da.po create mode 100644 po/underlays/directives/ikiwiki/directive/cutpaste.de.po create mode 100644 po/underlays/directives/ikiwiki/directive/cutpaste.fr.po create mode 100644 po/underlays/directives/ikiwiki/directive/date.de.po create mode 100644 po/underlays/directives/ikiwiki/directive/edittemplate.da.po create mode 100644 po/underlays/directives/ikiwiki/directive/edittemplate.de.po create mode 100644 po/underlays/directives/ikiwiki/directive/edittemplate.fr.po create mode 100644 po/underlays/directives/ikiwiki/directive/format.da.po create mode 100644 po/underlays/directives/ikiwiki/directive/format.de.po create mode 100644 po/underlays/directives/ikiwiki/directive/format.fr.po create mode 100644 po/underlays/directives/ikiwiki/directive/fortune.da.po create mode 100644 po/underlays/directives/ikiwiki/directive/fortune.de.po create mode 100644 po/underlays/directives/ikiwiki/directive/fortune.fr.po create mode 100644 po/underlays/directives/ikiwiki/directive/graph.da.po create mode 100644 po/underlays/directives/ikiwiki/directive/graph.de.po create mode 100644 po/underlays/directives/ikiwiki/directive/graph.fr.po create mode 100644 po/underlays/directives/ikiwiki/directive/haiku.da.po create mode 100644 po/underlays/directives/ikiwiki/directive/haiku.de.po create mode 100644 po/underlays/directives/ikiwiki/directive/haiku.fr.po create mode 100644 po/underlays/directives/ikiwiki/directive/if.da.po create mode 100644 po/underlays/directives/ikiwiki/directive/if.de.po create mode 100644 po/underlays/directives/ikiwiki/directive/if.fr.po create mode 100644 po/underlays/directives/ikiwiki/directive/img.da.po create mode 100644 po/underlays/directives/ikiwiki/directive/img.de.po create mode 100644 po/underlays/directives/ikiwiki/directive/img.fr.po create mode 100644 po/underlays/directives/ikiwiki/directive/inline.da.po create mode 100644 po/underlays/directives/ikiwiki/directive/inline.de.po create mode 100644 po/underlays/directives/ikiwiki/directive/inline.fr.po create mode 100644 po/underlays/directives/ikiwiki/directive/linkmap.da.po create mode 100644 po/underlays/directives/ikiwiki/directive/linkmap.de.po create mode 100644 po/underlays/directives/ikiwiki/directive/linkmap.fr.po create mode 100644 po/underlays/directives/ikiwiki/directive/listdirectives.da.po create mode 100644 po/underlays/directives/ikiwiki/directive/listdirectives.de.po create mode 100644 po/underlays/directives/ikiwiki/directive/listdirectives.fr.po create mode 100644 po/underlays/directives/ikiwiki/directive/map.da.po create mode 100644 po/underlays/directives/ikiwiki/directive/map.de.po create mode 100644 po/underlays/directives/ikiwiki/directive/map.fr.po create mode 100644 po/underlays/directives/ikiwiki/directive/meta.da.po create mode 100644 po/underlays/directives/ikiwiki/directive/meta.de.po create mode 100644 po/underlays/directives/ikiwiki/directive/meta.fr.po create mode 100644 po/underlays/directives/ikiwiki/directive/more.da.po create mode 100644 po/underlays/directives/ikiwiki/directive/more.de.po create mode 100644 po/underlays/directives/ikiwiki/directive/more.fr.po create mode 100644 po/underlays/directives/ikiwiki/directive/orphans.da.po create mode 100644 po/underlays/directives/ikiwiki/directive/orphans.de.po create mode 100644 po/underlays/directives/ikiwiki/directive/orphans.fr.po create mode 100644 po/underlays/directives/ikiwiki/directive/pagecount.da.po create mode 100644 po/underlays/directives/ikiwiki/directive/pagecount.de.po create mode 100644 po/underlays/directives/ikiwiki/directive/pagecount.fr.po create mode 100644 po/underlays/directives/ikiwiki/directive/pagestats.da.po create mode 100644 po/underlays/directives/ikiwiki/directive/pagestats.de.po create mode 100644 po/underlays/directives/ikiwiki/directive/pagestats.fr.po create mode 100644 po/underlays/directives/ikiwiki/directive/pagetemplate.da.po create mode 100644 po/underlays/directives/ikiwiki/directive/pagetemplate.de.po create mode 100644 po/underlays/directives/ikiwiki/directive/pagetemplate.fr.po create mode 100644 po/underlays/directives/ikiwiki/directive/paste.da.po create mode 100644 po/underlays/directives/ikiwiki/directive/paste.de.po create mode 100644 po/underlays/directives/ikiwiki/directive/paste.fr.po create mode 100644 po/underlays/directives/ikiwiki/directive/ping.da.po create mode 100644 po/underlays/directives/ikiwiki/directive/ping.de.po create mode 100644 po/underlays/directives/ikiwiki/directive/ping.fr.po create mode 100644 po/underlays/directives/ikiwiki/directive/poll.da.po create mode 100644 po/underlays/directives/ikiwiki/directive/poll.de.po create mode 100644 po/underlays/directives/ikiwiki/directive/poll.fr.po create mode 100644 po/underlays/directives/ikiwiki/directive/polygen.da.po create mode 100644 po/underlays/directives/ikiwiki/directive/polygen.de.po create mode 100644 po/underlays/directives/ikiwiki/directive/polygen.fr.po create mode 100644 po/underlays/directives/ikiwiki/directive/postsparkline.da.po create mode 100644 po/underlays/directives/ikiwiki/directive/postsparkline.de.po create mode 100644 po/underlays/directives/ikiwiki/directive/postsparkline.fr.po create mode 100644 po/underlays/directives/ikiwiki/directive/progress.da.po create mode 100644 po/underlays/directives/ikiwiki/directive/progress.de.po create mode 100644 po/underlays/directives/ikiwiki/directive/progress.fr.po create mode 100644 po/underlays/directives/ikiwiki/directive/shortcut.da.po create mode 100644 po/underlays/directives/ikiwiki/directive/shortcut.de.po create mode 100644 po/underlays/directives/ikiwiki/directive/shortcut.fr.po create mode 100644 po/underlays/directives/ikiwiki/directive/sparkline.da.po create mode 100644 po/underlays/directives/ikiwiki/directive/sparkline.de.po create mode 100644 po/underlays/directives/ikiwiki/directive/sparkline.fr.po create mode 100644 po/underlays/directives/ikiwiki/directive/table.da.po create mode 100644 po/underlays/directives/ikiwiki/directive/table.de.po create mode 100644 po/underlays/directives/ikiwiki/directive/table.fr.po create mode 100644 po/underlays/directives/ikiwiki/directive/tag.da.po create mode 100644 po/underlays/directives/ikiwiki/directive/tag.de.po create mode 100644 po/underlays/directives/ikiwiki/directive/tag.fr.po create mode 100644 po/underlays/directives/ikiwiki/directive/taglink.da.po create mode 100644 po/underlays/directives/ikiwiki/directive/taglink.de.po create mode 100644 po/underlays/directives/ikiwiki/directive/taglink.fr.po create mode 100644 po/underlays/directives/ikiwiki/directive/template.da.po create mode 100644 po/underlays/directives/ikiwiki/directive/template.de.po create mode 100644 po/underlays/directives/ikiwiki/directive/template.fr.po create mode 100644 po/underlays/directives/ikiwiki/directive/testpagespec.da.po create mode 100644 po/underlays/directives/ikiwiki/directive/testpagespec.de.po create mode 100644 po/underlays/directives/ikiwiki/directive/testpagespec.fr.po create mode 100644 po/underlays/directives/ikiwiki/directive/teximg.da.po create mode 100644 po/underlays/directives/ikiwiki/directive/teximg.de.po create mode 100644 po/underlays/directives/ikiwiki/directive/teximg.fr.po create mode 100644 po/underlays/directives/ikiwiki/directive/toc.da.po create mode 100644 po/underlays/directives/ikiwiki/directive/toc.de.po create mode 100644 po/underlays/directives/ikiwiki/directive/toc.fr.po create mode 100644 po/underlays/directives/ikiwiki/directive/toggle.da.po create mode 100644 po/underlays/directives/ikiwiki/directive/toggle.de.po create mode 100644 po/underlays/directives/ikiwiki/directive/toggle.fr.po create mode 100644 po/underlays/directives/ikiwiki/directive/toggleable.da.po create mode 100644 po/underlays/directives/ikiwiki/directive/toggleable.de.po create mode 100644 po/underlays/directives/ikiwiki/directive/toggleable.fr.po create mode 100644 po/underlays/directives/ikiwiki/directive/version.da.po create mode 100644 po/underlays/directives/ikiwiki/directive/version.de.po create mode 100644 po/underlays/directives/ikiwiki/directive/version.fr.po create mode 100644 po/underlays/smiley/smileys.da.po create mode 100644 po/underlays/smiley/smileys.de.po create mode 100644 po/underlays/smiley/smileys.fr.po create mode 100644 po/vi.po create mode 100755 t/404.t create mode 100755 t/add_depends.t create mode 100644 t/autoindex-committed.t create mode 100755 t/autoindex.t create mode 100755 t/basename.t create mode 100755 t/basewiki_brokenlinks.t create mode 100644 t/basewiki_brokenlinks/index.mdwn create mode 100755 t/bazaar.t create mode 100755 t/beautify_urlpath.t create mode 100755 t/bestlink.t create mode 100755 t/calculate_changed_links.t create mode 100755 t/cmp_path.t create mode 100755 t/comments.t create mode 100755 t/conflicts.t create mode 100755 t/crazy-badass-perl-bug.t create mode 100755 t/cvs.t create mode 100755 t/dirname.t create mode 100755 t/file_pruned.t create mode 100755 t/find_src_files.t create mode 100755 t/git.t create mode 100755 t/html.t create mode 100755 t/htmlbalance.t create mode 100755 t/htmlize.t create mode 100755 t/img.t create mode 100644 t/img/redsquare.png create mode 100644 t/img/twopages.pdf create mode 100755 t/index.t create mode 100755 t/inline.t create mode 100755 t/linkify.t create mode 100755 t/linkpage.t create mode 100755 t/map.t create mode 100755 t/mercurial.t create mode 100755 t/openiduser.t create mode 100755 t/pagename.t create mode 100755 t/pagespec_match.t create mode 100755 t/pagespec_match_list.t create mode 100755 t/pagespec_match_result.t create mode 100755 t/pagetitle.t create mode 100755 t/parentlinks.t create mode 100644 t/parentlinks/templates/parentlinks.tmpl create mode 100755 t/permalink.t create mode 100755 t/po.t create mode 100755 t/podcast.t create mode 100755 t/preprocess.t create mode 100755 t/prune.t create mode 100755 t/readfile.t create mode 100755 t/renamepage.t create mode 100755 t/rssurls.t create mode 100755 t/rst.t create mode 100755 t/svn.t create mode 100755 t/syntax.t create mode 100644 t/syslog.t create mode 100755 t/tag.t create mode 100755 t/template_syntax.t create mode 100755 t/templatebody.t create mode 100755 t/templates_documented.t create mode 100644 t/test1.mdwn create mode 100644 t/test2.mdwn create mode 100644 t/test3.mdwn create mode 100644 t/tinyblog/index.mdwn create mode 100644 t/tinyblog/post.mdwn create mode 100644 t/tinypodcast/attempted_multiple_enclosures.mdwn create mode 100644 t/tinypodcast/fancy.mdwn create mode 100644 t/tinypodcast/piano.mp3 create mode 100644 t/tinypodcast/pianopost.mdwn create mode 100644 t/tinypodcast/scroll.3gp create mode 100644 t/tinypodcast/simple.mdwn create mode 100644 t/tinypodcast/simplepost.mdwn create mode 100644 t/tinypodcast/walter.ogg create mode 100755 t/titlepage.t create mode 100755 t/trail.t create mode 100755 t/urlto.t create mode 100755 t/yesno.t create mode 100644 templates/aggregatepost.tmpl create mode 100644 templates/archivepage.tmpl create mode 100644 templates/atomitem.tmpl create mode 100644 templates/atompage.tmpl create mode 100644 templates/autoindex.tmpl create mode 100644 templates/autotag.tmpl create mode 100644 templates/blogpost.tmpl create mode 100644 templates/calendarmonth.tmpl create mode 100644 templates/calendaryear.tmpl create mode 100644 templates/change.tmpl create mode 100644 templates/comment.tmpl create mode 100644 templates/commentmoderation.tmpl create mode 100644 templates/editcomment.tmpl create mode 100644 templates/editconflict.tmpl create mode 100644 templates/editcreationconflict.tmpl create mode 100644 templates/editfailedsave.tmpl create mode 100644 templates/editpage.tmpl create mode 100644 templates/editpagegone.tmpl create mode 100644 templates/feedlink.tmpl create mode 100644 templates/googleform.tmpl create mode 100644 templates/inlinepage.tmpl create mode 100644 templates/microblog.tmpl create mode 100644 templates/notifyemail.tmpl create mode 100644 templates/openid-selector.tmpl create mode 100644 templates/page.tmpl create mode 100644 templates/passwordmail.tmpl create mode 100644 templates/pocreatepage.tmpl create mode 100644 templates/recentchanges.tmpl create mode 100644 templates/renamesummary.tmpl create mode 100644 templates/revert.tmpl create mode 100644 templates/rssitem.tmpl create mode 100644 templates/rsspage.tmpl create mode 100644 templates/searchform.tmpl create mode 100644 templates/searchquery.tmpl create mode 100644 templates/titlepage.tmpl create mode 100644 templates/trails.tmpl create mode 100644 themes/actiontabs/style.css create mode 100644 themes/blueview/background_darkness.png create mode 100644 themes/blueview/header_background.png create mode 100644 themes/blueview/style.css create mode 100644 themes/goldtype/background_darkness.png create mode 120000 themes/goldtype/base.css create mode 100644 themes/goldtype/header_background.png create mode 100644 themes/goldtype/style.css create mode 100644 themes/monochrome/gradient.png create mode 100644 themes/monochrome/style.css create mode 100644 underlays/attachment/ikiwiki/images/pbar-ani.gif create mode 100644 underlays/attachment/ikiwiki/images/ui-bg_flat_0_aaaaaa_40x100.png create mode 100644 underlays/attachment/ikiwiki/images/ui-bg_flat_75_ffffff_40x100.png create mode 100644 underlays/attachment/ikiwiki/images/ui-bg_glass_55_fbf9ee_1x400.png create mode 100644 underlays/attachment/ikiwiki/images/ui-bg_glass_65_ffffff_1x400.png create mode 100644 underlays/attachment/ikiwiki/images/ui-bg_glass_75_dadada_1x400.png create mode 100644 underlays/attachment/ikiwiki/images/ui-bg_glass_75_e6e6e6_1x400.png create mode 100644 underlays/attachment/ikiwiki/images/ui-bg_glass_95_fef1ec_1x400.png create mode 100644 underlays/attachment/ikiwiki/images/ui-bg_highlight-soft_75_cccccc_1x100.png create mode 100644 underlays/attachment/ikiwiki/images/ui-icons_222222_256x240.png create mode 100644 underlays/attachment/ikiwiki/images/ui-icons_2e83ff_256x240.png create mode 100644 underlays/attachment/ikiwiki/images/ui-icons_454545_256x240.png create mode 100644 underlays/attachment/ikiwiki/images/ui-icons_888888_256x240.png create mode 100644 underlays/attachment/ikiwiki/images/ui-icons_cd0a0a_256x240.png create mode 100644 underlays/attachment/ikiwiki/jquery-ui.css create mode 100644 underlays/attachment/ikiwiki/jquery-ui.js create mode 100644 underlays/attachment/ikiwiki/jquery-ui.min.css create mode 100644 underlays/attachment/ikiwiki/jquery-ui.min.js create mode 100644 underlays/attachment/ikiwiki/jquery.fileupload-ui.js create mode 100644 underlays/attachment/ikiwiki/jquery.fileupload.js create mode 100644 underlays/attachment/ikiwiki/jquery.iframe-transport.js create mode 100644 underlays/attachment/ikiwiki/jquery.tmpl.js create mode 100644 underlays/attachment/ikiwiki/jquery.tmpl.min.js create mode 120000 underlays/basewiki/favicon.ico create mode 120000 underlays/basewiki/ikiwiki.mdwn create mode 120000 underlays/basewiki/ikiwiki/directive.mdwn create mode 120000 underlays/basewiki/ikiwiki/formatting.mdwn create mode 120000 underlays/basewiki/ikiwiki/markdown.mdwn create mode 120000 underlays/basewiki/ikiwiki/openid.mdwn create mode 120000 underlays/basewiki/ikiwiki/pagespec.mdwn create mode 120000 underlays/basewiki/ikiwiki/pagespec/attachment.mdwn create mode 120000 underlays/basewiki/ikiwiki/pagespec/po.mdwn create mode 120000 underlays/basewiki/ikiwiki/pagespec/sorting.mdwn create mode 120000 underlays/basewiki/ikiwiki/searching.mdwn create mode 120000 underlays/basewiki/ikiwiki/subpage.mdwn create mode 120000 underlays/basewiki/ikiwiki/subpage/linkingrules.mdwn create mode 120000 underlays/basewiki/ikiwiki/wikilink.mdwn create mode 120000 underlays/basewiki/index.mdwn create mode 120000 underlays/basewiki/local.css create mode 120000 underlays/basewiki/recentchanges.mdwn create mode 120000 underlays/basewiki/sandbox.mdwn create mode 120000 underlays/basewiki/shortcuts.mdwn create mode 120000 underlays/basewiki/style.css create mode 120000 underlays/basewiki/templates.mdwn create mode 120000 underlays/basewiki/templates/note.mdwn create mode 120000 underlays/basewiki/templates/popup.mdwn create mode 120000 underlays/basewiki/wikiicons create mode 100644 underlays/javascript/ikiwiki/ikiwiki.js create mode 100644 underlays/javascript/ikiwiki/relativedate.js create mode 100644 underlays/javascript/ikiwiki/toggle.js create mode 100644 underlays/jquery/ikiwiki/jquery.js create mode 100644 underlays/jquery/ikiwiki/jquery.min.js create mode 100644 underlays/openid-selector/ikiwiki/openid/aol.png create mode 100644 underlays/openid-selector/ikiwiki/openid/goa-account-flickr.png create mode 100644 underlays/openid-selector/ikiwiki/openid/goa-account-google.png create mode 100644 underlays/openid-selector/ikiwiki/openid/goa-account-yahoo.png create mode 100644 underlays/openid-selector/ikiwiki/openid/livejournal.png create mode 100644 underlays/openid-selector/ikiwiki/openid/openid-jquery.js create mode 100644 underlays/openid-selector/ikiwiki/openid/verisign.png create mode 100644 underlays/openid-selector/ikiwiki/openid/wordpress.png create mode 100644 underlays/osm/ikiwiki/images/osm.png create mode 100644 underlays/osm/ikiwiki/osm.js create mode 120000 underlays/smiley/smileys create mode 120000 underlays/smiley/smileys.mdwn create mode 100644 wikilist diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..5d425843f --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +debian/changelog merge=dpkg-mergechangelogs diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..8528fe9be --- /dev/null +++ b/.gitignore @@ -0,0 +1,23 @@ +ikiwiki.setup +Makefile +Makefile.old +blib/* +/cover_db +doc/.ikiwiki/* +html/* +ikiwiki.out +ikiwiki-transition.out +ikiwiki-calendar.out +pm_to_blib +/MYMETA.json +/MYMETA.yml +*.man +/po/cover_db +po/po2wiki_stamp +po/underlays/*/*.mdwn +po/underlays/basewiki/*/*.mdwn +po/underlays/basewiki/*/*/*.mdwn +po/underlays/directives/ikiwiki/directive/*.mdwn +po/underlays_copy_stamp +underlays/locale +/t/tmp/ diff --git a/.perlcriticrc b/.perlcriticrc new file mode 100644 index 000000000..1e099736f --- /dev/null +++ b/.perlcriticrc @@ -0,0 +1,59 @@ +theme = core + pbp + cosmetic + bugs + maintenance + complexity + security + +# While there's good reason to not use subroutine prototypes, ikiwiki does +# use them, and changing away from them could lead to subtle bugs in stuff +# using the library. So for now, demote errors about them. +[Subroutines::ProhibitSubroutinePrototypes] +severity = 1 + +# Nice to have, but low priority. I do it for the hairy regexps. +[RegularExpressions::RequireExtendedFormatting] +severity = 1 + +# ProhibitStringyEval doesn't take into account that eval q{use Foo}; +# defers the use until the eval runs, which is often a useful optimisation. +# While eval {use Foo}; does not defer the use at all. +[-BuiltinFunctions::ProhibitStringyEval] + +# ikiwiki uses the method of switching other files to the IkiWiki package +# when they are part of the core program. I don't plan to have more than +# the one exporting module in IkiWiki, so let's ignore this test. +[-Modules::RequireFilenameMatchesPackage] +# IkiWiki also switches _out_ of the core package when a package namespace +# is a good way to group a set of functions. This doesn't mean I want it +# loading up a separate file though, so it's in the same file. +[-Modules::ProhibitMultiplePackages] + +# ikiwiki uses this when it makes sense, ie, for conditional variable +# localisation. +[-Variables::ProhibitConditionalDeclarations] + +# IkiWiki exports symbols, and uses globals, if it's bad form, that's too +# bad. :-) +[-Modules::ProhibitAutomaticExportation] +[-Variables::ProhibitPackageVars] + +# Stylistic checks that I don't agree with. Larry put both forms there for +# a reason; both forms can be abused. +[-BuiltinFunctions::RequireBlockGrep] +[-BuiltinFunctions::RequireBlockMap] +[-Variables::ProhibitPunctuationVars] +[-ControlStructures::ProhibitPostfixControls] + +# Sadly doesn't match my coding style. +[-CodeLayout::ProhibitHardTabs] + +# Sillyness. +[-Miscellanea::RequireRcsKeywords] + +# Sadly, perl doesn't offer a builtin better way in many cases. +[-ControlStructures::ProhibitCascadingIfElse] + +# Good god, man, it's perl. Get over it! +[-ValuesAndExpressions::ProhibitNoisyQuotes] +[-ValuesAndExpressions::ProhibitEmptyQuotes] +[-RegularExpressions::RequireLineBoundaryMatching] + +# When I use local vars, I have a damn good reason. +# (A shower after with lots of strong soap is also a nice thing.) +[-Variables::ProhibitLocalVars] diff --git a/Bundle/IkiWiki.pm b/Bundle/IkiWiki.pm new file mode 100644 index 000000000..005936250 --- /dev/null +++ b/Bundle/IkiWiki.pm @@ -0,0 +1,37 @@ +package Bundle::IkiWiki; + +$VERSION = '0.01'; + +1; + +__END__ + +=head1 NAME + +Bundle::IkiWiki - core modules that ikiwiki needs + +=head1 SYNOPSIS + +perl -MCPAN -e 'install Bundle::IkiWiki' + +=head1 CONTENTS + +Text::Markdown::Discount +HTML::Scrubber +HTML::Template +HTML::Parser +URI 1.36 +XML::Simple +Date::Parse +CGI::FormBuilder +CGI::Session +Mail::Sendmail +CGI +Data::Dumper +YAML::XS +JSON +RPC::XML + +=head1 AUTHOR + +Joey Hess diff --git a/Bundle/IkiWiki/Extras.pm b/Bundle/IkiWiki/Extras.pm new file mode 100644 index 000000000..0a7cd3ae3 --- /dev/null +++ b/Bundle/IkiWiki/Extras.pm @@ -0,0 +1,42 @@ +package Bundle::IkiWiki::Extras; + +$VERSION = '0.01'; + +1; + +__END__ + +=head1 NAME + +Bundle::IkiWiki - modules used by ikiwiki plugins + +=head1 SYNOPSIS + +perl -MCPAN -e 'install Bundle::IkiWiki::Extras' + +=head1 CONTENTS + +Authen::Passphrase +Search::Xapian +File::MimeInfo +Locale::gettext +Net::OpenID::Consumer +LWPx::ParanoidAgent +Crypt::SSLeay +Text::CSV +Text::Typography +Text::Textile +Text::WikiFormat +XML::Feed +Net::Amazon::S3 +Text::WikiCreole +Term::ReadLine::Gnu +HTML::Tree +Sort::Naturally +Gravatar::URL +Net::INET6Glue +XML::Writer + +=head1 AUTHOR + +Joey Hess diff --git a/CHANGELOG b/CHANGELOG new file mode 120000 index 000000000..d526672ce --- /dev/null +++ b/CHANGELOG @@ -0,0 +1 @@ +debian/changelog \ No newline at end of file diff --git a/IkiWiki.pm b/IkiWiki.pm new file mode 100644 index 000000000..d5d11ee85 --- /dev/null +++ b/IkiWiki.pm @@ -0,0 +1,2991 @@ +#!/usr/bin/perl + +package IkiWiki; + +use warnings; +use strict; +use Encode; +use URI::Escape q{uri_escape_utf8}; +use POSIX (); +use Storable; +use open qw{:utf8 :std}; + +use vars qw{%config %links %oldlinks %pagemtime %pagectime %pagecase + %pagestate %wikistate %renderedfiles %oldrenderedfiles + %pagesources %delpagesources %destsources %depends %depends_simple + @mass_depends %hooks %forcerebuild %loaded_plugins %typedlinks + %oldtypedlinks %autofiles @underlayfiles $lastrev $phase}; + +use Exporter q{import}; +our @EXPORT = qw(hook debug error htmlpage template template_depends + deptype add_depends pagespec_match pagespec_match_list bestlink + htmllink readfile writefile pagetype srcfile pagename + displaytime strftime_utf8 will_render gettext ngettext urlto targetpage + add_underlay pagetitle titlepage linkpage newpagefile + inject add_link add_autofile useragent + %config %links %pagestate %wikistate %renderedfiles + %pagesources %destsources %typedlinks); +our $VERSION = 3.00; # plugin interface version, next is ikiwiki version +our $version='unknown'; # VERSION_AUTOREPLACE done by Makefile, DNE +our $installdir='/usr'; # INSTALLDIR_AUTOREPLACE done by Makefile, DNE + +# Page dependency types. +our $DEPEND_CONTENT=1; +our $DEPEND_PRESENCE=2; +our $DEPEND_LINKS=4; + +# Phases of processing. +sub PHASE_SCAN () { 0 } +sub PHASE_RENDER () { 1 } +$phase = PHASE_SCAN; + +# Optimisation. +use Memoize; +memoize("abs2rel"); +memoize("sortspec_translate"); +memoize("pagespec_translate"); +memoize("template_file"); + +sub getsetup () { + wikiname => { + type => "string", + default => "wiki", + description => "name of the wiki", + safe => 1, + rebuild => 1, + }, + adminemail => { + type => "string", + default => undef, + example => 'me@example.com', + description => "contact email for wiki", + safe => 1, + rebuild => 0, + }, + adminuser => { + type => "string", + default => [], + description => "users who are wiki admins", + safe => 1, + rebuild => 0, + }, + banned_users => { + type => "string", + default => [], + description => "users who are banned from the wiki", + safe => 1, + rebuild => 0, + }, + srcdir => { + type => "string", + default => undef, + example => "$ENV{HOME}/wiki", + description => "where the source of the wiki is located", + safe => 0, # path + rebuild => 1, + }, + destdir => { + type => "string", + default => undef, + example => "/var/www/wiki", + description => "where to build the wiki", + safe => 0, # path + rebuild => 1, + }, + url => { + type => "string", + default => '', + example => "http://example.com/wiki", + description => "base url to the wiki", + safe => 1, + rebuild => 1, + }, + cgiurl => { + type => "string", + default => '', + example => "http://example.com/wiki/ikiwiki.cgi", + description => "url to the ikiwiki.cgi", + safe => 1, + rebuild => 1, + }, + cgi_wrapper => { + type => "string", + default => '', + example => "/var/www/wiki/ikiwiki.cgi", + description => "filename of cgi wrapper to generate", + safe => 0, # file + rebuild => 0, + }, + cgi_wrappermode => { + type => "string", + default => '06755', + description => "mode for cgi_wrapper (can safely be made suid)", + safe => 0, + rebuild => 0, + }, + cgi_overload_delay => { + type => "string", + default => '', + example => "10", + description => "number of seconds to delay CGI requests when overloaded", + safe => 1, + rebuild => 0, + }, + cgi_overload_message => { + type => "string", + default => '', + example => "Please wait", + description => "message to display when overloaded (may contain html)", + safe => 1, + rebuild => 0, + }, + only_committed_changes => { + type => "boolean", + default => 0, + description => "enable optimization of only refreshing committed changes?", + safe => 1, + rebuild => 0, + }, + rcs => { + type => "string", + default => '', + description => "rcs backend to use", + safe => 0, # don't allow overriding + rebuild => 0, + }, + default_plugins => { + type => "internal", + default => [qw{mdwn link inline meta htmlscrubber passwordauth + openid signinedit lockedit conditional + recentchanges parentlinks editpage + templatebody}], + description => "plugins to enable by default", + safe => 0, + rebuild => 1, + }, + add_plugins => { + type => "string", + default => [], + description => "plugins to add to the default configuration", + safe => 1, + rebuild => 1, + }, + disable_plugins => { + type => "string", + default => [], + description => "plugins to disable", + safe => 1, + rebuild => 1, + }, + templatedir => { + type => "string", + default => "$installdir/share/ikiwiki/templates", + description => "additional directory to search for template files", + advanced => 1, + safe => 0, # path + rebuild => 1, + }, + underlaydir => { + type => "string", + default => "$installdir/share/ikiwiki/basewiki", + description => "base wiki source location", + advanced => 1, + safe => 0, # path + rebuild => 0, + }, + underlaydirbase => { + type => "internal", + default => "$installdir/share/ikiwiki", + description => "parent directory containing additional underlays", + safe => 0, + rebuild => 0, + }, + wrappers => { + type => "internal", + default => [], + description => "wrappers to generate", + safe => 0, + rebuild => 0, + }, + underlaydirs => { + type => "internal", + default => [], + description => "additional underlays to use", + safe => 0, + rebuild => 0, + }, + verbose => { + type => "boolean", + example => 1, + description => "display verbose messages?", + safe => 1, + rebuild => 0, + }, + syslog => { + type => "boolean", + example => 1, + description => "log to syslog?", + safe => 1, + rebuild => 0, + }, + usedirs => { + type => "boolean", + default => 1, + description => "create output files named page/index.html?", + safe => 0, # changing requires manual transition + rebuild => 1, + }, + prefix_directives => { + type => "boolean", + default => 1, + description => "use '!'-prefixed preprocessor directives?", + safe => 0, # changing requires manual transition + rebuild => 1, + }, + indexpages => { + type => "boolean", + default => 0, + description => "use page/index.mdwn source files", + safe => 1, + rebuild => 1, + }, + discussion => { + type => "boolean", + default => 1, + description => "enable Discussion pages?", + safe => 1, + rebuild => 1, + }, + discussionpage => { + type => "string", + default => gettext("Discussion"), + description => "name of Discussion pages", + safe => 1, + rebuild => 1, + }, + html5 => { + type => "boolean", + default => 0, + description => "generate HTML5?", + advanced => 0, + safe => 1, + rebuild => 1, + }, + sslcookie => { + type => "boolean", + default => 0, + description => "only send cookies over SSL connections?", + advanced => 1, + safe => 1, + rebuild => 0, + }, + default_pageext => { + type => "string", + default => "mdwn", + description => "extension to use for new pages", + safe => 0, # not sanitized + rebuild => 0, + }, + htmlext => { + type => "string", + default => "html", + description => "extension to use for html files", + safe => 0, # not sanitized + rebuild => 1, + }, + timeformat => { + type => "string", + default => '%c', + description => "strftime format string to display date", + advanced => 1, + safe => 1, + rebuild => 1, + }, + locale => { + type => "string", + default => undef, + example => "en_US.UTF-8", + description => "UTF-8 locale to use", + advanced => 1, + safe => 0, + rebuild => 1, + }, + userdir => { + type => "string", + default => "", + example => "users", + description => "put user pages below specified page", + safe => 1, + rebuild => 1, + }, + numbacklinks => { + type => "integer", + default => 10, + description => "how many backlinks to show before hiding excess (0 to show all)", + safe => 1, + rebuild => 1, + }, + hardlink => { + type => "boolean", + default => 0, + description => "attempt to hardlink source files? (optimisation for large files)", + advanced => 1, + safe => 0, # paranoia + rebuild => 0, + }, + umask => { + type => "string", + example => "public", + description => "force ikiwiki to use a particular umask (keywords public, group or private, or a number)", + advanced => 1, + safe => 0, # paranoia + rebuild => 0, + }, + wrappergroup => { + type => "string", + example => "ikiwiki", + description => "group for wrappers to run in", + advanced => 1, + safe => 0, # paranoia + rebuild => 0, + }, + libdir => { + type => "string", + default => "", + example => "$ENV{HOME}/.ikiwiki/", + description => "extra library and plugin directory", + advanced => 1, + safe => 0, # directory + rebuild => 0, + }, + ENV => { + type => "string", + default => {}, + description => "environment variables", + safe => 0, # paranoia + rebuild => 0, + }, + timezone => { + type => "string", + default => "", + example => "US/Eastern", + description => "time zone name", + safe => 1, + rebuild => 1, + }, + include => { + type => "string", + default => undef, + example => '^\.htaccess$', + description => "regexp of normally excluded files to include", + advanced => 1, + safe => 0, # regexp + rebuild => 1, + }, + exclude => { + type => "string", + default => undef, + example => '^(*\.private|Makefile)$', + description => "regexp of files that should be skipped", + advanced => 1, + safe => 0, # regexp + rebuild => 1, + }, + wiki_file_prune_regexps => { + type => "internal", + default => [qr/(^|\/)\.\.(\/|$)/, qr/^\//, qr/^\./, qr/\/\./, + qr/\.x?html?$/, qr/\.ikiwiki-new$/, + qr/(^|\/).svn\//, qr/.arch-ids\//, qr/{arch}\//, + qr/(^|\/)_MTN\//, qr/(^|\/)_darcs\//, + qr/(^|\/)CVS\//, qr/\.dpkg-tmp$/], + description => "regexps of source files to ignore", + safe => 0, + rebuild => 1, + }, + wiki_file_chars => { + type => "string", + description => "specifies the characters that are allowed in source filenames", + default => "-[:alnum:]+/.:_", + safe => 0, + rebuild => 1, + }, + wiki_file_regexp => { + type => "internal", + description => "regexp of legal source files", + safe => 0, + rebuild => 1, + }, + web_commit_regexp => { + type => "internal", + default => qr/^web commit (by (.*?(?=: |$))|from ([0-9a-fA-F:.]+[0-9a-fA-F])):?(.*)/, + description => "regexp to parse web commits from logs", + safe => 0, + rebuild => 0, + }, + cgi => { + type => "internal", + default => 0, + description => "run as a cgi", + safe => 0, + rebuild => 0, + }, + cgi_disable_uploads => { + type => "internal", + default => 1, + description => "whether CGI should accept file uploads", + safe => 0, + rebuild => 0, + }, + post_commit => { + type => "internal", + default => 0, + description => "run as a post-commit hook", + safe => 0, + rebuild => 0, + }, + rebuild => { + type => "internal", + default => 0, + description => "running in rebuild mode", + safe => 0, + rebuild => 0, + }, + setup => { + type => "internal", + default => undef, + description => "running in setup mode", + safe => 0, + rebuild => 0, + }, + clean => { + type => "internal", + default => 0, + description => "running in clean mode", + safe => 0, + rebuild => 0, + }, + refresh => { + type => "internal", + default => 0, + description => "running in refresh mode", + safe => 0, + rebuild => 0, + }, + test_receive => { + type => "internal", + default => 0, + description => "running in receive test mode", + safe => 0, + rebuild => 0, + }, + wrapper_background_command => { + type => "internal", + default => '', + description => "background shell command to run", + safe => 0, + rebuild => 0, + }, + gettime => { + type => "internal", + description => "running in gettime mode", + safe => 0, + rebuild => 0, + }, + w3mmode => { + type => "internal", + default => 0, + description => "running in w3mmode", + safe => 0, + rebuild => 0, + }, + wikistatedir => { + type => "internal", + default => undef, + description => "path to the .ikiwiki directory holding ikiwiki state", + safe => 0, + rebuild => 0, + }, + setupfile => { + type => "internal", + default => undef, + description => "path to setup file", + safe => 0, + rebuild => 0, + }, + setuptype => { + type => "internal", + default => "Yaml", + description => "perl class to use to dump setup file", + safe => 0, + rebuild => 0, + }, + allow_symlinks_before_srcdir => { + type => "boolean", + default => 0, + description => "allow symlinks in the path leading to the srcdir (potentially insecure)", + safe => 0, + rebuild => 0, + }, + cookiejar => { + type => "string", + default => { file => "$ENV{HOME}/.ikiwiki/cookies" }, + description => "cookie control", + safe => 0, # hooks into perl module internals + rebuild => 0, + }, + useragent => { + type => "string", + default => undef, + example => "Wget/1.13.4 (linux-gnu)", + description => "set custom user agent string for outbound HTTP requests e.g. when fetching aggregated RSS feeds", + safe => 0, + rebuild => 0, + }, +} + +sub defaultconfig () { + my %s=getsetup(); + my @ret; + foreach my $key (keys %s) { + push @ret, $key, $s{$key}->{default}; + } + return @ret; +} + +# URL to top of wiki as a path starting with /, valid from any wiki page or +# the CGI; if that's not possible, an absolute URL. Either way, it ends with / +my $local_url; +# URL to CGI script, similar to $local_url +my $local_cgiurl; + +sub checkconfig () { + # locale stuff; avoid LC_ALL since it overrides everything + if (defined $ENV{LC_ALL}) { + $ENV{LANG} = $ENV{LC_ALL}; + delete $ENV{LC_ALL}; + } + if (defined $config{locale}) { + if (POSIX::setlocale(&POSIX::LC_ALL, $config{locale})) { + $ENV{LANG}=$config{locale}; + define_gettext(); + } + } + + if (! defined $config{wiki_file_regexp}) { + $config{wiki_file_regexp}=qr/(^[$config{wiki_file_chars}]+$)/; + } + + if (ref $config{ENV} eq 'HASH') { + foreach my $val (keys %{$config{ENV}}) { + $ENV{$val}=$config{ENV}{$val}; + } + } + if (defined $config{timezone} && length $config{timezone}) { + $ENV{TZ}=$config{timezone}; + } + else { + $config{timezone}=$ENV{TZ}; + } + + if ($config{w3mmode}) { + eval q{use Cwd q{abs_path}}; + error($@) if $@; + $config{srcdir}=possibly_foolish_untaint(abs_path($config{srcdir})); + $config{destdir}=possibly_foolish_untaint(abs_path($config{destdir})); + $config{cgiurl}="file:///\$LIB/ikiwiki-w3m.cgi/".$config{cgiurl} + unless $config{cgiurl} =~ m!file:///!; + $config{url}="file://".$config{destdir}; + } + + if ($config{cgi} && ! length $config{url}) { + error(gettext("Must specify url to wiki with --url when using --cgi")); + } + + if (defined $config{url} && length $config{url}) { + eval q{use URI}; + my $baseurl = URI->new($config{url}); + + $local_url = $baseurl->path . "/"; + $local_cgiurl = undef; + + if (length $config{cgiurl}) { + my $cgiurl = URI->new($config{cgiurl}); + + $local_cgiurl = $cgiurl->path; + + if ($cgiurl->scheme ne $baseurl->scheme or + $cgiurl->authority ne $baseurl->authority) { + # too far apart, fall back to absolute URLs + $local_url = "$config{url}/"; + $local_cgiurl = $config{cgiurl}; + } + } + + $local_url =~ s{//$}{/}; + } + else { + $local_cgiurl = $config{cgiurl}; + } + + $config{wikistatedir}="$config{srcdir}/.ikiwiki" + unless exists $config{wikistatedir} && defined $config{wikistatedir}; + + if (defined $config{umask}) { + my $u = possibly_foolish_untaint($config{umask}); + + if ($u =~ m/^\d+$/) { + umask($u); + } + elsif ($u eq 'private') { + umask(077); + } + elsif ($u eq 'group') { + umask(027); + } + elsif ($u eq 'public') { + umask(022); + } + else { + error(sprintf(gettext("unsupported umask setting %s"), $u)); + } + } + + run_hooks(checkconfig => sub { shift->() }); + + return 1; +} + +sub listplugins () { + my %ret; + + foreach my $dir (@INC, $config{libdir}) { + next unless defined $dir && length $dir; + foreach my $file (glob("$dir/IkiWiki/Plugin/*.pm")) { + my ($plugin)=$file=~/.*\/(.*)\.pm$/; + $ret{$plugin}=1; + } + } + foreach my $dir ($config{libdir}, "$installdir/lib/ikiwiki") { + next unless defined $dir && length $dir; + foreach my $file (glob("$dir/plugins/*")) { + $ret{basename($file)}=1 if -x $file; + } + } + + return keys %ret; +} + +sub loadplugins () { + if (defined $config{libdir} && length $config{libdir}) { + unshift @INC, possibly_foolish_untaint($config{libdir}); + } + + foreach my $plugin (@{$config{default_plugins}}, @{$config{add_plugins}}) { + loadplugin($plugin); + } + + if ($config{rcs}) { + if (exists $hooks{rcs}) { + error(gettext("cannot use multiple rcs plugins")); + } + loadplugin($config{rcs}); + } + if (! exists $hooks{rcs}) { + loadplugin("norcs"); + } + + run_hooks(getopt => sub { shift->() }); + if (grep /^-/, @ARGV) { + print STDERR "Unknown option (or missing parameter): $_\n" + foreach grep /^-/, @ARGV; + usage(); + } + + return 1; +} + +sub loadplugin ($;$) { + my $plugin=shift; + my $force=shift; + + return if ! $force && grep { $_ eq $plugin} @{$config{disable_plugins}}; + + foreach my $dir (defined $config{libdir} ? possibly_foolish_untaint($config{libdir}) : undef, + "$installdir/lib/ikiwiki") { + if (defined $dir && -x "$dir/plugins/$plugin") { + eval { require IkiWiki::Plugin::external }; + if ($@) { + my $reason=$@; + error(sprintf(gettext("failed to load external plugin needed for %s plugin: %s"), $plugin, $reason)); + } + import IkiWiki::Plugin::external "$dir/plugins/$plugin"; + $loaded_plugins{$plugin}=1; + return 1; + } + } + + my $mod="IkiWiki::Plugin::".possibly_foolish_untaint($plugin); + eval qq{use $mod}; + if ($@) { + error("Failed to load plugin $mod: $@"); + } + $loaded_plugins{$plugin}=1; + return 1; +} + +sub error ($;$) { + my $message=shift; + my $cleaner=shift; + log_message('err' => $message) if $config{syslog}; + if (defined $cleaner) { + $cleaner->(); + } + die $message."\n"; +} + +sub debug ($) { + return unless $config{verbose}; + return log_message(debug => @_); +} + +my $log_open=0; +my $log_failed=0; +sub log_message ($$) { + my $type=shift; + + if ($config{syslog}) { + require Sys::Syslog; + if (! $log_open) { + Sys::Syslog::setlogsock('unix'); + Sys::Syslog::openlog('ikiwiki', '', 'user'); + $log_open=1; + } + eval { + # keep a copy to avoid editing the original config repeatedly + my $wikiname = $config{wikiname}; + utf8::encode($wikiname); + Sys::Syslog::syslog($type, "[$wikiname] %s", join(" ", @_)); + }; + if ($@) { + print STDERR "failed to syslog: $@" unless $log_failed; + $log_failed=1; + print STDERR "@_\n"; + } + return $@; + } + elsif (! $config{cgi}) { + return print "@_\n"; + } + else { + return print STDERR "@_\n"; + } +} + +sub possibly_foolish_untaint ($) { + my $tainted=shift; + my ($untainted)=$tainted=~/(.*)/s; + return $untainted; +} + +sub basename ($) { + my $file=shift; + + $file=~s!.*/+!!; + return $file; +} + +sub dirname ($) { + my $file=shift; + + $file=~s!/*[^/]+$!!; + return $file; +} + +sub isinternal ($) { + my $page=shift; + return exists $pagesources{$page} && + $pagesources{$page} =~ /\._([^.]+)$/; +} + +sub pagetype ($) { + my $file=shift; + + if ($file =~ /\.([^.]+)$/) { + return $1 if exists $hooks{htmlize}{$1}; + } + my $base=basename($file); + if (exists $hooks{htmlize}{$base} && + $hooks{htmlize}{$base}{noextension}) { + return $base; + } + return; +} + +my %pagename_cache; + +sub pagename ($) { + my $file=shift; + + if (exists $pagename_cache{$file}) { + return $pagename_cache{$file}; + } + + my $type=pagetype($file); + my $page=$file; + $page=~s/\Q.$type\E*$// + if defined $type && !$hooks{htmlize}{$type}{keepextension} + && !$hooks{htmlize}{$type}{noextension}; + if ($config{indexpages} && $page=~/(.*)\/index$/) { + $page=$1; + } + + $pagename_cache{$file} = $page; + return $page; +} + +sub newpagefile ($$) { + my $page=shift; + my $type=shift; + + if (! $config{indexpages} || $page eq 'index') { + return $page.".".$type; + } + else { + return $page."/index.".$type; + } +} + +sub targetpage ($$;$) { + my $page=shift; + my $ext=shift; + my $filename=shift; + + if (defined $filename) { + return $page."/".$filename.".".$ext; + } + elsif (! $config{usedirs} || $page eq 'index') { + return $page.".".$ext; + } + else { + return $page."/index.".$ext; + } +} + +sub htmlpage ($) { + my $page=shift; + + return targetpage($page, $config{htmlext}); +} + +sub srcfile_stat { + my $file=shift; + my $nothrow=shift; + + return "$config{srcdir}/$file", stat(_) if -e "$config{srcdir}/$file"; + foreach my $dir (@{$config{underlaydirs}}, $config{underlaydir}) { + return "$dir/$file", stat(_) if -e "$dir/$file"; + } + error("internal error: $file cannot be found in $config{srcdir} or underlay") unless $nothrow; + return; +} + +sub srcfile ($;$) { + return (srcfile_stat(@_))[0]; +} + +sub add_literal_underlay ($) { + my $dir=shift; + + if (! grep { $_ eq $dir } @{$config{underlaydirs}}) { + unshift @{$config{underlaydirs}}, $dir; + } +} + +sub add_underlay ($) { + my $dir = shift; + + if ($dir !~ /^\//) { + $dir="$config{underlaydirbase}/$dir"; + } + + add_literal_underlay($dir); + # why does it return 1? we just don't know + return 1; +} + +sub readfile ($;$$) { + my $file=shift; + my $binary=shift; + my $wantfd=shift; + + if (-l $file) { + error("cannot read a symlink ($file)"); + } + + local $/=undef; + open (my $in, "<", $file) || error("failed to read $file: $!"); + binmode($in) if ($binary); + return \*$in if $wantfd; + my $ret=<$in>; + # check for invalid utf-8, and toss it back to avoid crashes + if (! utf8::valid($ret)) { + $ret=encode_utf8($ret); + } + close $in || error("failed to read $file: $!"); + return $ret; +} + +sub prep_writefile ($$) { + my $file=shift; + my $destdir=shift; + + my $test=$file; + while (length $test) { + if (-l "$destdir/$test") { + error("cannot write to a symlink ($test)"); + } + if (-f _ && $test ne $file) { + # Remove conflicting file. + foreach my $p (keys %renderedfiles, keys %oldrenderedfiles) { + foreach my $f (@{$renderedfiles{$p}}, @{$oldrenderedfiles{$p}}) { + if ($f eq $test) { + unlink("$destdir/$test"); + last; + } + } + } + } + $test=dirname($test); + } + + my $dir=dirname("$destdir/$file"); + if (! -d $dir) { + my $d=""; + foreach my $s (split(m!/+!, $dir)) { + $d.="$s/"; + if (! -d $d) { + mkdir($d) || error("failed to create directory $d: $!"); + } + } + } + + return 1; +} + +sub writefile ($$$;$$) { + my $file=shift; # can include subdirs + my $destdir=shift; # directory to put file in + my $content=shift; + my $binary=shift; + my $writer=shift; + + prep_writefile($file, $destdir); + + my $newfile="$destdir/$file.ikiwiki-new"; + if (-l $newfile) { + error("cannot write to a symlink ($newfile)"); + } + + my $cleanup = sub { unlink($newfile) }; + open (my $out, '>', $newfile) || error("failed to write $newfile: $!", $cleanup); + binmode($out) if ($binary); + if ($writer) { + $writer->(\*$out, $cleanup); + } + else { + print $out $content or error("failed writing to $newfile: $!", $cleanup); + } + close $out || error("failed saving $newfile: $!", $cleanup); + rename($newfile, "$destdir/$file") || + error("failed renaming $newfile to $destdir/$file: $!", $cleanup); + + return 1; +} + +my %cleared; +sub will_render ($$;$) { + my $page=shift; + my $dest=shift; + my $clear=shift; + + # Important security check for independently created files. + if (-e "$config{destdir}/$dest" && ! $config{rebuild} && + ! grep { $_ eq $dest } (@{$renderedfiles{$page}}, @{$oldrenderedfiles{$page}}, @{$wikistate{editpage}{previews}})) { + my $from_other_page=0; + # Expensive, but rarely runs. + foreach my $p (keys %renderedfiles, keys %oldrenderedfiles) { + if (grep { + $_ eq $dest || + dirname($_) eq $dest + } @{$renderedfiles{$p}}, @{$oldrenderedfiles{$p}}) { + $from_other_page=1; + last; + } + } + + error("$config{destdir}/$dest independently created, not overwriting with version from $page") + unless $from_other_page; + } + + # If $dest exists as a directory, remove conflicting files in it + # rendered from other pages. + if (-d _) { + foreach my $p (keys %renderedfiles, keys %oldrenderedfiles) { + foreach my $f (@{$renderedfiles{$p}}, @{$oldrenderedfiles{$p}}) { + if (dirname($f) eq $dest) { + unlink("$config{destdir}/$f"); + rmdir(dirname("$config{destdir}/$f")); + } + } + } + } + + if (! $clear || $cleared{$page}) { + $renderedfiles{$page}=[$dest, grep { $_ ne $dest } @{$renderedfiles{$page}}]; + } + else { + foreach my $old (@{$renderedfiles{$page}}) { + delete $destsources{$old}; + } + $renderedfiles{$page}=[$dest]; + $cleared{$page}=1; + } + $destsources{$dest}=$page; + + return 1; +} + +sub bestlink ($$) { + my $page=shift; + my $link=shift; + + my $cwd=$page; + if ($link=~s/^\/+//) { + # absolute links + $cwd=""; + } + $link=~s/\/$//; + + do { + my $l=$cwd; + $l.="/" if length $l; + $l.=$link; + + if (exists $pagesources{$l}) { + return $l; + } + elsif (exists $pagecase{lc $l}) { + return $pagecase{lc $l}; + } + } while $cwd=~s{/?[^/]+$}{}; + + if (length $config{userdir}) { + my $l = "$config{userdir}/".lc($link); + if (exists $pagesources{$l}) { + return $l; + } + elsif (exists $pagecase{lc $l}) { + return $pagecase{lc $l}; + } + } + + #print STDERR "warning: page $page, broken link: $link\n"; + return ""; +} + +sub isinlinableimage ($) { + my $file=shift; + + return $file =~ /\.(png|gif|jpg|jpeg|svg)$/i; +} + +sub pagetitle ($;$) { + my $page=shift; + my $unescaped=shift; + + if ($unescaped) { + $page=~s/(__(\d+)__|_)/$1 eq '_' ? ' ' : chr($2)/eg; + } + else { + $page=~s/(__(\d+)__|_)/$1 eq '_' ? ' ' : "&#$2;"/eg; + } + + return $page; +} + +sub titlepage ($) { + my $title=shift; + # support use w/o %config set + my $chars = defined $config{wiki_file_chars} ? $config{wiki_file_chars} : "-[:alnum:]+/.:_"; + $title=~s/([^$chars]|_)/$1 eq ' ' ? '_' : "__".ord($1)."__"/eg; + return $title; +} + +sub linkpage ($) { + my $link=shift; + my $chars = defined $config{wiki_file_chars} ? $config{wiki_file_chars} : "-[:alnum:]+/.:_"; + $link=~s/([^$chars])/$1 eq ' ' ? '_' : "__".ord($1)."__"/eg; + return $link; +} + +sub cgiurl (@) { + my %params=@_; + + my $cgiurl=$local_cgiurl; + + if (exists $params{cgiurl}) { + $cgiurl=$params{cgiurl}; + delete $params{cgiurl}; + } + + unless (%params) { + return $cgiurl; + } + + return $cgiurl."?". + join("&", map $_."=".uri_escape_utf8($params{$_}), keys %params); +} + +sub cgiurl_abs (@) { + eval q{use URI}; + URI->new_abs(cgiurl(@_), $config{cgiurl}); +} + +sub baseurl (;$) { + my $page=shift; + + return $local_url if ! defined $page; + + $page=htmlpage($page); + $page=~s/[^\/]+$//; + $page=~s/[^\/]+\//..\//g; + return $page; +} + +sub urlabs ($$) { + my $url=shift; + my $urlbase=shift; + + return $url unless defined $urlbase && length $urlbase; + + eval q{use URI}; + URI->new_abs($url, $urlbase)->as_string; +} + +sub abs2rel ($$) { + # Work around very innefficient behavior in File::Spec if abs2rel + # is passed two relative paths. It's much faster if paths are + # absolute! (Debian bug #376658; fixed in debian unstable now) + my $path="/".shift; + my $base="/".shift; + + require File::Spec; + my $ret=File::Spec->abs2rel($path, $base); + $ret=~s/^// if defined $ret; + return $ret; +} + +sub displaytime ($;$$) { + # Plugins can override this function to mark up the time to + # display. + my $time=formattime($_[0], $_[1]); + if ($config{html5}) { + return ''; + } + else { + return ''.$time.''; + } +} + +sub formattime ($;$) { + # Plugins can override this function to format the time. + my $time=shift; + my $format=shift; + if (! defined $format) { + $format=$config{timeformat}; + } + + return strftime_utf8($format, localtime($time)); +} + +my $strftime_encoding; +sub strftime_utf8 { + # strftime doesn't know about encodings, so make sure + # its output is properly treated as utf8. + # Note that this does not handle utf-8 in the format string. + ($strftime_encoding) = POSIX::setlocale(&POSIX::LC_TIME) =~ m#\.([^@]+)# + unless defined $strftime_encoding; + $strftime_encoding + ? Encode::decode($strftime_encoding, POSIX::strftime(@_)) + : POSIX::strftime(@_); +} + +sub date_3339 ($) { + my $time=shift; + + my $lc_time=POSIX::setlocale(&POSIX::LC_TIME); + POSIX::setlocale(&POSIX::LC_TIME, "C"); + my $ret=POSIX::strftime("%Y-%m-%dT%H:%M:%SZ", gmtime($time)); + POSIX::setlocale(&POSIX::LC_TIME, $lc_time); + return $ret; +} + +sub beautify_urlpath ($) { + my $url=shift; + + # Ensure url is not an empty link, and if necessary, + # add ./ to avoid colon confusion. + if ($url !~ /^\// && $url !~ /^\.\.?\//) { + $url="./$url"; + } + + if ($config{usedirs}) { + $url =~ s!/index.$config{htmlext}$!/!; + } + + return $url; +} + +sub urlto ($;$$) { + my $to=shift; + my $from=shift; + my $absolute=shift; + + if (! length $to) { + $to = 'index'; + } + + if (! $destsources{$to}) { + $to=htmlpage($to); + } + + if ($absolute) { + return $config{url}.beautify_urlpath("/".$to); + } + + if (! defined $from) { + my $u = $local_url || ''; + $u =~ s{/$}{}; + return $u.beautify_urlpath("/".$to); + } + + my $link = abs2rel($to, dirname(htmlpage($from))); + + return beautify_urlpath($link); +} + +sub isselflink ($$) { + # Plugins can override this function to support special types + # of selflinks. + my $page=shift; + my $link=shift; + + return $page eq $link; +} + +sub htmllink ($$$;@) { + my $lpage=shift; # the page doing the linking + my $page=shift; # the page that will contain the link (different for inline) + my $link=shift; + my %opts=@_; + + $link=~s/\/$//; + + my $bestlink; + if (! $opts{forcesubpage}) { + $bestlink=bestlink($lpage, $link); + } + else { + $bestlink="$lpage/".lc($link); + } + + my $linktext; + if (defined $opts{linktext}) { + $linktext=$opts{linktext}; + } + else { + $linktext=pagetitle(basename($link)); + } + + return "$linktext" + if length $bestlink && isselflink($page, $bestlink) && + ! defined $opts{anchor}; + + if (! $destsources{$bestlink}) { + $bestlink=htmlpage($bestlink); + + if (! $destsources{$bestlink}) { + my $cgilink = ""; + if (length $config{cgiurl}) { + $cgilink = " "create", + page => $link, + from => $lpage + )."\" rel=\"nofollow\">?"; + } + return "$cgilink$linktext" + } + } + + $bestlink=abs2rel($bestlink, dirname(htmlpage($page))); + $bestlink=beautify_urlpath($bestlink); + + if (! $opts{noimageinline} && isinlinableimage($bestlink)) { + return "\"$linktext\""; + } + + if (defined $opts{anchor}) { + $bestlink.="#".$opts{anchor}; + } + + my @attrs; + foreach my $attr (qw{rel class title}) { + if (defined $opts{$attr}) { + push @attrs, " $attr=\"$opts{$attr}\""; + } + } + + return "$linktext"; +} + +sub userpage ($) { + my $user=shift; + return length $config{userdir} ? "$config{userdir}/$user" : $user; +} + +sub openiduser ($) { + my $user=shift; + + if (defined $user && $user =~ m!^https?://! && + eval q{use Net::OpenID::VerifiedIdentity; 1} && !$@) { + my $display; + + if (Net::OpenID::VerifiedIdentity->can("DisplayOfURL")) { + $display = Net::OpenID::VerifiedIdentity::DisplayOfURL($user); + } + else { + # backcompat with old version + my $oid=Net::OpenID::VerifiedIdentity->new(identity => $user); + $display=$oid->display; + } + + # Convert "user.somehost.com" to "user [somehost.com]" + # (also "user.somehost.co.uk") + if ($display !~ /\[/) { + $display=~s/^([-a-zA-Z0-9]+?)\.([-.a-zA-Z0-9]+\.[a-z]+)$/$1 [$2]/; + } + # Convert "http://somehost.com/user" to "user [somehost.com]". + # (also "https://somehost.com/user/") + if ($display !~ /\[/) { + $display=~s/^https?:\/\/(.+)\/([^\/#?]+)\/?(?:[#?].*)?$/$2 [$1]/; + } + $display=~s!^https?://!!; # make sure this is removed + eval q{use CGI 'escapeHTML'}; + error($@) if $@; + return escapeHTML($display); + } + return; +} + +sub htmlize ($$$$) { + my $page=shift; + my $destpage=shift; + my $type=shift; + my $content=shift; + + my $oneline = $content !~ /\n/; + + if (exists $hooks{htmlize}{$type}) { + $content=$hooks{htmlize}{$type}{call}->( + page => $page, + content => $content, + ); + } + else { + error("htmlization of $type not supported"); + } + + run_hooks(sanitize => sub { + $content=shift->( + page => $page, + destpage => $destpage, + content => $content, + ); + }); + + if ($oneline) { + # hack to get rid of enclosing junk added by markdown + # and other htmlizers/sanitizers + $content=~s/^

//i; + $content=~s/<\/p>\n*$//i; + } + + return $content; +} + +sub linkify ($$$) { + my $page=shift; + my $destpage=shift; + my $content=shift; + + run_hooks(linkify => sub { + $content=shift->( + page => $page, + destpage => $destpage, + content => $content, + ); + }); + + return $content; +} + +our %preprocessing; +our $preprocess_preview=0; +sub preprocess ($$$;$$) { + my $page=shift; # the page the data comes from + my $destpage=shift; # the page the data will appear in (different for inline) + my $content=shift; + my $scan=shift; + my $preview=shift; + + # Using local because it needs to be set within any nested calls + # of this function. + local $preprocess_preview=$preview if defined $preview; + + my $handle=sub { + my $escape=shift; + my $prefix=shift; + my $command=shift; + my $params=shift; + $params="" if ! defined $params; + + if (length $escape) { + return "[[$prefix$command $params]]"; + } + elsif (exists $hooks{preprocess}{$command}) { + return "" if $scan && ! $hooks{preprocess}{$command}{scan}; + # Note: preserve order of params, some plugins may + # consider it significant. + my @params; + while ($params =~ m{ + (?:([-.\w]+)=)? # 1: named parameter key? + (?: + """(.*?)""" # 2: triple-quoted value + | + "([^"]*?)" # 3: single-quoted value + | + '''(.*?)''' # 4: triple-single-quote + | + <<([a-zA-Z]+)\n # 5: heredoc start + (.*?)\n\5 # 6: heredoc value + | + (\S+) # 7: unquoted value + ) + (?:\s+|$) # delimiter to next param + }msgx) { + my $key=$1; + my $val; + if (defined $2) { + $val=$2; + $val=~s/\r\n/\n/mg; + $val=~s/^\n+//g; + $val=~s/\n+$//g; + } + elsif (defined $3) { + $val=$3; + } + elsif (defined $4) { + $val=$4; + } + elsif (defined $7) { + $val=$7; + } + elsif (defined $6) { + $val=$6; + } + + if (defined $key) { + push @params, $key, $val; + } + else { + push @params, $val, ''; + } + } + if ($preprocessing{$page}++ > 8) { + # Avoid loops of preprocessed pages preprocessing + # other pages that preprocess them, etc. + return "[[!$command ". + sprintf(gettext("preprocessing loop detected on %s at depth %i"), + $page, $preprocessing{$page}). + "]]"; + } + my $ret; + if (! $scan) { + $ret=eval { + $hooks{preprocess}{$command}{call}->( + @params, + page => $page, + destpage => $destpage, + preview => $preprocess_preview, + ); + }; + if ($@) { + my $error=$@; + chomp $error; + $ret="[[!$command ". + gettext("Error").": $error"."]]"; + } + } + else { + # use void context during scan pass + eval { + $hooks{preprocess}{$command}{call}->( + @params, + page => $page, + destpage => $destpage, + preview => $preprocess_preview, + ); + }; + $ret=""; + } + $preprocessing{$page}--; + return $ret; + } + else { + return "[[$prefix$command $params]]"; + } + }; + + my $regex; + if ($config{prefix_directives}) { + $regex = qr{ + (\\?) # 1: escape? + \[\[(!) # directive open; 2: prefix + ([-\w]+) # 3: command + ( # 4: the parameters.. + \s+ # Must have space if parameters present + (?: + (?:[-.\w]+=)? # named parameter key? + (?: + """.*?""" # triple-quoted value + | + "[^"]*?" # single-quoted value + | + '''.*?''' # triple-single-quote + | + <<([a-zA-Z]+)\n # 5: heredoc start + (?:.*?)\n\5 # heredoc value + | + [^"\s\]]+ # unquoted value + ) + \s* # whitespace or end + # of directive + ) + *)? # 0 or more parameters + \]\] # directive closed + }sx; + } + else { + $regex = qr{ + (\\?) # 1: escape? + \[\[(!?) # directive open; 2: optional prefix + ([-\w]+) # 3: command + \s+ + ( # 4: the parameters.. + (?: + (?:[-.\w]+=)? # named parameter key? + (?: + """.*?""" # triple-quoted value + | + "[^"]*?" # single-quoted value + | + '''.*?''' # triple-single-quote + | + <<([a-zA-Z]+)\n # 5: heredoc start + (?:.*?)\n\5 # heredoc value + | + [^"\s\]]+ # unquoted value + ) + \s* # whitespace or end + # of directive + ) + *) # 0 or more parameters + \]\] # directive closed + }sx; + } + + $content =~ s{$regex}{$handle->($1, $2, $3, $4)}eg; + return $content; +} + +sub filter ($$$) { + my $page=shift; + my $destpage=shift; + my $content=shift; + + run_hooks(filter => sub { + $content=shift->(page => $page, destpage => $destpage, + content => $content); + }); + + return $content; +} + +sub check_canedit ($$$;$) { + my $page=shift; + my $q=shift; + my $session=shift; + my $nonfatal=shift; + + my $canedit; + run_hooks(canedit => sub { + return if defined $canedit; + my $ret=shift->($page, $q, $session); + if (defined $ret) { + if ($ret eq "") { + $canedit=1; + } + elsif (ref $ret eq 'CODE') { + $ret->() unless $nonfatal; + $canedit=0; + } + elsif (defined $ret) { + error($ret) unless $nonfatal; + $canedit=0; + } + } + }); + return defined $canedit ? $canedit : 1; +} + +sub check_content (@) { + my %params=@_; + + return 1 if ! exists $hooks{checkcontent}; # optimisation + + if (exists $pagesources{$params{page}}) { + my @diff; + my %old=map { $_ => 1 } + split("\n", readfile(srcfile($pagesources{$params{page}}))); + foreach my $line (split("\n", $params{content})) { + push @diff, $line if ! exists $old{$line}; + } + $params{diff}=join("\n", @diff); + } + + my $ok; + run_hooks(checkcontent => sub { + return if defined $ok; + my $ret=shift->(%params); + if (defined $ret) { + if ($ret eq "") { + $ok=1; + } + elsif (ref $ret eq 'CODE') { + $ret->() unless $params{nonfatal}; + $ok=0; + } + elsif (defined $ret) { + error($ret) unless $params{nonfatal}; + $ok=0; + } + } + + }); + return defined $ok ? $ok : 1; +} + +sub check_canchange (@) { + my %params = @_; + my $cgi = $params{cgi}; + my $session = $params{session}; + my @changes = @{$params{changes}}; + + my %newfiles; + foreach my $change (@changes) { + # This untaint is safe because we check file_pruned and + # wiki_file_regexp. + my ($file)=$change->{file}=~/$config{wiki_file_regexp}/; + $file=possibly_foolish_untaint($file); + if (! defined $file || ! length $file || + file_pruned($file)) { + error(gettext("bad file name %s"), $file); + } + + my $type=pagetype($file); + my $page=pagename($file) if defined $type; + + if ($change->{action} eq 'add') { + $newfiles{$file}=1; + } + + if ($change->{action} eq 'change' || + $change->{action} eq 'add') { + if (defined $page) { + check_canedit($page, $cgi, $session); + next; + } + else { + if (IkiWiki::Plugin::attachment->can("check_canattach")) { + IkiWiki::Plugin::attachment::check_canattach($session, $file, $change->{path}); + check_canedit($file, $cgi, $session); + next; + } + } + } + elsif ($change->{action} eq 'remove') { + # check_canremove tests to see if the file is present + # on disk. This will fail when a single commit adds a + # file and then removes it again. Avoid the problem + # by not testing the removal in such pairs of changes. + # (The add is still tested, just to make sure that + # no data is added to the repo that a web edit + # could not add.) + next if $newfiles{$file}; + + if (IkiWiki::Plugin::remove->can("check_canremove")) { + IkiWiki::Plugin::remove::check_canremove(defined $page ? $page : $file, $cgi, $session); + check_canedit(defined $page ? $page : $file, $cgi, $session); + next; + } + } + else { + error "unknown action ".$change->{action}; + } + + error sprintf(gettext("you are not allowed to change %s"), $file); + } +} + + +my $wikilock; + +sub lockwiki () { + # Take an exclusive lock on the wiki to prevent multiple concurrent + # run issues. The lock will be dropped on program exit. + if (! -d $config{wikistatedir}) { + mkdir($config{wikistatedir}); + } + open($wikilock, '>', "$config{wikistatedir}/lockfile") || + error ("cannot write to $config{wikistatedir}/lockfile: $!"); + if (! flock($wikilock, 2)) { # LOCK_EX + error("failed to get lock"); + } + return 1; +} + +sub unlockwiki () { + POSIX::close($ENV{IKIWIKI_CGILOCK_FD}) if exists $ENV{IKIWIKI_CGILOCK_FD}; + return close($wikilock) if $wikilock; + return; +} + +my $commitlock; + +sub commit_hook_enabled () { + open($commitlock, '+>', "$config{wikistatedir}/commitlock") || + error("cannot write to $config{wikistatedir}/commitlock: $!"); + if (! flock($commitlock, 1 | 4)) { # LOCK_SH | LOCK_NB to test + close($commitlock) || error("failed closing commitlock: $!"); + return 0; + } + close($commitlock) || error("failed closing commitlock: $!"); + return 1; +} + +sub disable_commit_hook () { + open($commitlock, '>', "$config{wikistatedir}/commitlock") || + error("cannot write to $config{wikistatedir}/commitlock: $!"); + if (! flock($commitlock, 2)) { # LOCK_EX + error("failed to get commit lock"); + } + return 1; +} + +sub enable_commit_hook () { + return close($commitlock) if $commitlock; + return; +} + +sub loadindex () { + %oldrenderedfiles=%pagectime=(); + my $rebuild=$config{rebuild}; + if (! $rebuild) { + %pagesources=%pagemtime=%oldlinks=%links=%depends= + %destsources=%renderedfiles=%pagecase=%pagestate= + %depends_simple=%typedlinks=%oldtypedlinks=(); + } + my $in; + if (! open ($in, "<", "$config{wikistatedir}/indexdb")) { + if (-e "$config{wikistatedir}/index") { + system("ikiwiki-transition", "indexdb", $config{srcdir}); + open ($in, "<", "$config{wikistatedir}/indexdb") || return; + } + else { + # gettime on first build + $config{gettime}=1 unless defined $config{gettime}; + return; + } + } + + my $index=Storable::fd_retrieve($in); + if (! defined $index) { + return 0; + } + + my $pages; + if (exists $index->{version} && ! ref $index->{version}) { + $pages=$index->{page}; + %wikistate=%{$index->{state}}; + # Handle plugins that got disabled by loading a new setup. + if (exists $config{setupfile}) { + require IkiWiki::Setup; + IkiWiki::Setup::disabled_plugins( + grep { ! $loaded_plugins{$_} } keys %wikistate); + } + } + else { + $pages=$index; + %wikistate=(); + } + + foreach my $src (keys %$pages) { + my $d=$pages->{$src}; + my $page; + if (exists $d->{page} && ! $rebuild) { + $page=$d->{page}; + } + else { + $page=pagename($src); + } + $pagectime{$page}=$d->{ctime}; + $pagesources{$page}=$src; + if (! $rebuild) { + $pagemtime{$page}=$d->{mtime}; + $renderedfiles{$page}=$d->{dest}; + if (exists $d->{links} && ref $d->{links}) { + $links{$page}=$d->{links}; + $oldlinks{$page}=[@{$d->{links}}]; + } + if (ref $d->{depends_simple} eq 'ARRAY') { + # old format + $depends_simple{$page}={ + map { $_ => 1 } @{$d->{depends_simple}} + }; + } + elsif (exists $d->{depends_simple}) { + $depends_simple{$page}=$d->{depends_simple}; + } + if (exists $d->{dependslist}) { + # old format + $depends{$page}={ + map { $_ => $DEPEND_CONTENT } + @{$d->{dependslist}} + }; + } + elsif (exists $d->{depends} && ! ref $d->{depends}) { + # old format + $depends{$page}={$d->{depends} => $DEPEND_CONTENT }; + } + elsif (exists $d->{depends}) { + $depends{$page}=$d->{depends}; + } + if (exists $d->{state}) { + $pagestate{$page}=$d->{state}; + } + if (exists $d->{typedlinks}) { + $typedlinks{$page}=$d->{typedlinks}; + + while (my ($type, $links) = each %{$typedlinks{$page}}) { + next unless %$links; + $oldtypedlinks{$page}{$type} = {%$links}; + } + } + } + $oldrenderedfiles{$page}=[@{$d->{dest}}]; + } + foreach my $page (keys %pagesources) { + $pagecase{lc $page}=$page; + } + foreach my $page (keys %renderedfiles) { + $destsources{$_}=$page foreach @{$renderedfiles{$page}}; + } + $lastrev=$index->{lastrev}; + @underlayfiles=@{$index->{underlayfiles}} if ref $index->{underlayfiles}; + return close($in); +} + +sub saveindex () { + run_hooks(savestate => sub { shift->() }); + + my @plugins=keys %loaded_plugins; + + if (! -d $config{wikistatedir}) { + mkdir($config{wikistatedir}); + } + my $newfile="$config{wikistatedir}/indexdb.new"; + my $cleanup = sub { unlink($newfile) }; + open (my $out, '>', $newfile) || error("cannot write to $newfile: $!", $cleanup); + + my %index; + foreach my $page (keys %pagemtime) { + next unless $pagemtime{$page}; + my $src=$pagesources{$page}; + + $index{page}{$src}={ + page => $page, + ctime => $pagectime{$page}, + mtime => $pagemtime{$page}, + dest => $renderedfiles{$page}, + links => $links{$page}, + }; + + if (exists $depends{$page}) { + $index{page}{$src}{depends} = $depends{$page}; + } + + if (exists $depends_simple{$page}) { + $index{page}{$src}{depends_simple} = $depends_simple{$page}; + } + + if (exists $typedlinks{$page} && %{$typedlinks{$page}}) { + $index{page}{$src}{typedlinks} = $typedlinks{$page}; + } + + if (exists $pagestate{$page}) { + $index{page}{$src}{state}=$pagestate{$page}; + } + } + + $index{state}={}; + foreach my $id (@plugins) { + $index{state}{$id}={}; # used to detect disabled plugins + foreach my $key (keys %{$wikistate{$id}}) { + $index{state}{$id}{$key}=$wikistate{$id}{$key}; + } + } + + $index{lastrev}=$lastrev; + $index{underlayfiles}=\@underlayfiles; + + $index{version}="3"; + my $ret=Storable::nstore_fd(\%index, $out); + return if ! defined $ret || ! $ret; + close $out || error("failed saving to $newfile: $!", $cleanup); + rename($newfile, "$config{wikistatedir}/indexdb") || + error("failed renaming $newfile to $config{wikistatedir}/indexdb", $cleanup); + + return 1; +} + +sub template_file ($) { + my $name=shift; + + my $tpage=($name =~ s/^\///) ? $name : "templates/$name"; + my $template; + if ($name !~ /\.tmpl$/ && exists $pagesources{$tpage}) { + $template=srcfile($pagesources{$tpage}, 1); + $name.=".tmpl"; + } + else { + $template=srcfile($tpage, 1); + } + + if (defined $template) { + return $template, $tpage, 1 if wantarray; + return $template; + } + else { + $name=~s:/::; # avoid path traversal + foreach my $dir ($config{templatedir}, + "$installdir/share/ikiwiki/templates") { + if (-e "$dir/$name") { + $template="$dir/$name"; + last; + } + } + if (defined $template) { + return $template, $tpage if wantarray; + return $template; + } + } + + return; +} + +sub template_depends ($$;@) { + my $name=shift; + my $page=shift; + + my ($filename, $tpage, $untrusted)=template_file($name); + if (! defined $filename) { + error(sprintf(gettext("template %s not found"), $name)) + } + + if (defined $page && defined $tpage) { + add_depends($page, $tpage); + } + + my @opts=( + filter => sub { + my $text_ref = shift; + ${$text_ref} = decode_utf8(${$text_ref}); + run_hooks(readtemplate => sub { + ${$text_ref} = shift->( + id => $name, + page => $tpage, + content => ${$text_ref}, + untrusted => $untrusted, + ); + }); + }, + loop_context_vars => 1, + die_on_bad_params => 0, + parent_global_vars => 1, + filename => $filename, + @_, + ($untrusted ? (no_includes => 1) : ()), + ); + return @opts if wantarray; + + require HTML::Template; + return HTML::Template->new(@opts); +} + +sub template ($;@) { + template_depends(shift, undef, @_); +} + +sub templateactions ($$) { + my $template=shift; + my $page=shift; + + my $have_actions=0; + my @actions; + run_hooks(pageactions => sub { + push @actions, map { { action => $_ } } + grep { defined } shift->(page => $page); + }); + $template->param(actions => \@actions); + + if ($config{cgiurl} && exists $hooks{auth}) { + $template->param(prefsurl => cgiurl(do => "prefs")); + $have_actions=1; + } + + if ($have_actions || @actions) { + $template->param(have_actions => 1); + } +} + +sub hook (@) { + my %param=@_; + + if (! exists $param{type} || ! ref $param{call} || ! exists $param{id}) { + error 'hook requires type, call, and id parameters'; + } + + return if $param{no_override} && exists $hooks{$param{type}}{$param{id}}; + + $hooks{$param{type}}{$param{id}}=\%param; + return 1; +} + +sub run_hooks ($$) { + # Calls the given sub for each hook of the given type, + # passing it the hook function to call. + my $type=shift; + my $sub=shift; + + if (exists $hooks{$type}) { + my (@first, @middle, @last); + foreach my $id (keys %{$hooks{$type}}) { + if ($hooks{$type}{$id}{first}) { + push @first, $id; + } + elsif ($hooks{$type}{$id}{last}) { + push @last, $id; + } + else { + push @middle, $id; + } + } + foreach my $id (@first, @middle, @last) { + $sub->($hooks{$type}{$id}{call}); + } + } + + return 1; +} + +sub rcs_update () { + $hooks{rcs}{rcs_update}{call}->(@_); +} + +sub rcs_prepedit ($) { + $hooks{rcs}{rcs_prepedit}{call}->(@_); +} + +sub rcs_commit (@) { + $hooks{rcs}{rcs_commit}{call}->(@_); +} + +sub rcs_commit_staged (@) { + $hooks{rcs}{rcs_commit_staged}{call}->(@_); +} + +sub rcs_add ($) { + $hooks{rcs}{rcs_add}{call}->(@_); +} + +sub rcs_remove ($) { + $hooks{rcs}{rcs_remove}{call}->(@_); +} + +sub rcs_rename ($$) { + $hooks{rcs}{rcs_rename}{call}->(@_); +} + +sub rcs_recentchanges ($) { + $hooks{rcs}{rcs_recentchanges}{call}->(@_); +} + +sub rcs_diff ($;$) { + $hooks{rcs}{rcs_diff}{call}->(@_); +} + +sub rcs_getctime ($) { + $hooks{rcs}{rcs_getctime}{call}->(@_); +} + +sub rcs_getmtime ($) { + $hooks{rcs}{rcs_getmtime}{call}->(@_); +} + +sub rcs_receive () { + $hooks{rcs}{rcs_receive}{call}->(); +} + +sub add_depends ($$;$) { + my $page=shift; + my $pagespec=shift; + my $deptype=shift || $DEPEND_CONTENT; + + # Is the pagespec a simple page name? + if ($pagespec =~ /$config{wiki_file_regexp}/ && + $pagespec !~ /[\s*?()!]/) { + $depends_simple{$page}{lc $pagespec} |= $deptype; + return 1; + } + + # Add explicit dependencies for influences. + my $sub=pagespec_translate($pagespec); + return unless defined $sub; + foreach my $p (keys %pagesources) { + my $r=$sub->($p, location => $page); + my $i=$r->influences; + my $static=$r->influences_static; + foreach my $k (keys %$i) { + next unless $r || $static || $k eq $page; + $depends_simple{$page}{lc $k} |= $i->{$k}; + } + last if $static; + } + + $depends{$page}{$pagespec} |= $deptype; + return 1; +} + +sub deptype (@) { + my $deptype=0; + foreach my $type (@_) { + if ($type eq 'presence') { + $deptype |= $DEPEND_PRESENCE; + } + elsif ($type eq 'links') { + $deptype |= $DEPEND_LINKS; + } + elsif ($type eq 'content') { + $deptype |= $DEPEND_CONTENT; + } + } + return $deptype; +} + +my $file_prune_regexp; +sub file_pruned ($) { + my $file=shift; + + if (defined $config{include} && length $config{include}) { + return 0 if $file =~ m/$config{include}/; + } + + if (! defined $file_prune_regexp) { + $file_prune_regexp='('.join('|', @{$config{wiki_file_prune_regexps}}).')'; + $file_prune_regexp=qr/$file_prune_regexp/; + } + return $file =~ m/$file_prune_regexp/; +} + +sub define_gettext () { + # If translation is needed, redefine the gettext function to do it. + # Otherwise, it becomes a quick no-op. + my $gettext_obj; + my $getobj; + if ((exists $ENV{LANG} && length $ENV{LANG}) || + (exists $ENV{LC_ALL} && length $ENV{LC_ALL}) || + (exists $ENV{LC_MESSAGES} && length $ENV{LC_MESSAGES})) { + $getobj=sub { + $gettext_obj=eval q{ + use Locale::gettext q{textdomain}; + Locale::gettext->domain('ikiwiki') + }; + }; + } + + no warnings 'redefine'; + *gettext=sub { + $getobj->() if $getobj; + if ($gettext_obj) { + $gettext_obj->get(shift); + } + else { + return shift; + } + }; + *ngettext=sub { + $getobj->() if $getobj; + if ($gettext_obj) { + $gettext_obj->nget(@_); + } + else { + return ($_[2] == 1 ? $_[0] : $_[1]) + } + }; +} + +sub gettext { + define_gettext(); + gettext(@_); +} + +sub ngettext { + define_gettext(); + ngettext(@_); +} + +sub yesno ($) { + my $val=shift; + + return (defined $val && (lc($val) eq gettext("yes") || lc($val) eq "yes" || $val eq "1")); +} + +sub inject { + # Injects a new function into the symbol table to replace an + # exported function. + my %params=@_; + + # This is deep ugly perl foo, beware. + no strict; + no warnings; + if (! defined $params{parent}) { + $params{parent}='::'; + $params{old}=\&{$params{name}}; + $params{name}=~s/.*:://; + } + my $parent=$params{parent}; + foreach my $ns (grep /^\w+::/, keys %{$parent}) { + $ns = $params{parent} . $ns; + inject(%params, parent => $ns) unless $ns eq '::main::'; + *{$ns . $params{name}} = $params{call} + if exists ${$ns}{$params{name}} && + \&{${$ns}{$params{name}}} == $params{old}; + } + use strict; + use warnings; +} + +sub add_link ($$;$) { + my $page=shift; + my $link=shift; + my $type=shift; + + push @{$links{$page}}, $link + unless grep { $_ eq $link } @{$links{$page}}; + + if (defined $type) { + $typedlinks{$page}{$type}{$link} = 1; + } +} + +sub add_autofile ($$$) { + my $file=shift; + my $plugin=shift; + my $generator=shift; + + $autofiles{$file}{plugin}=$plugin; + $autofiles{$file}{generator}=$generator; +} + +sub useragent () { + return LWP::UserAgent->new( + cookie_jar => $config{cookiejar}, + env_proxy => 1, # respect proxy env vars + agent => $config{useragent}, + ); +} + +sub sortspec_translate ($$) { + my $spec = shift; + my $reverse = shift; + + my $code = ""; + my @data; + while ($spec =~ m{ + \s* + (-?) # group 1: perhaps negated + \s* + ( # group 2: a word + \w+\([^\)]*\) # command(params) + | + [^\s]+ # or anything else + ) + \s* + }gx) { + my $negated = $1; + my $word = $2; + my $params = undef; + + if ($word =~ m/^(\w+)\((.*)\)$/) { + # command with parameters + $params = $2; + $word = $1; + } + elsif ($word !~ m/^\w+$/) { + error(sprintf(gettext("invalid sort type %s"), $word)); + } + + if (length $code) { + $code .= " || "; + } + + if ($negated) { + $code .= "-"; + } + + if (exists $IkiWiki::SortSpec::{"cmp_$word"}) { + if (defined $params) { + push @data, $params; + $code .= "IkiWiki::SortSpec::cmp_$word(\$data[$#data])"; + } + else { + $code .= "IkiWiki::SortSpec::cmp_$word(undef)"; + } + } + else { + error(sprintf(gettext("unknown sort type %s"), $word)); + } + } + + if (! length $code) { + # undefined sorting method... sort arbitrarily + return sub { 0 }; + } + + if ($reverse) { + $code="-($code)"; + } + + no warnings; + return eval 'sub { '.$code.' }'; +} + +sub pagespec_translate ($) { + my $spec=shift; + + # Convert spec to perl code. + my $code=""; + my @data; + while ($spec=~m{ + \s* # ignore whitespace + ( # 1: match a single word + \! # ! + | + \( # ( + | + \) # ) + | + \w+\([^\)]*\) # command(params) + | + [^\s()]+ # any other text + ) + \s* # ignore whitespace + }gx) { + my $word=$1; + if (lc $word eq 'and') { + $code.=' &'; + } + elsif (lc $word eq 'or') { + $code.=' |'; + } + elsif ($word eq "(" || $word eq ")" || $word eq "!") { + $code.=' '.$word; + } + elsif ($word =~ /^(\w+)\((.*)\)$/) { + if (exists $IkiWiki::PageSpec::{"match_$1"}) { + push @data, $2; + $code.="IkiWiki::PageSpec::match_$1(\$page, \$data[$#data], \@_)"; + } + else { + push @data, qq{unknown function in pagespec "$word"}; + $code.="IkiWiki::ErrorReason->new(\$data[$#data])"; + } + } + else { + push @data, $word; + $code.=" IkiWiki::PageSpec::match_glob(\$page, \$data[$#data], \@_)"; + } + } + + if (! length $code) { + $code="IkiWiki::FailReason->new('empty pagespec')"; + } + + no warnings; + return eval 'sub { my $page=shift; '.$code.' }'; +} + +sub pagespec_match ($$;@) { + my $page=shift; + my $spec=shift; + my @params=@_; + + # Backwards compatability with old calling convention. + if (@params == 1) { + unshift @params, 'location'; + } + + my $sub=pagespec_translate($spec); + return IkiWiki::ErrorReason->new("syntax error in pagespec \"$spec\"") + if ! defined $sub; + return $sub->($page, @params); +} + +# e.g. @pages = sort_pages("title", \@pages, reverse => "yes") +# +# Not exported yet, but could be in future if it is generally useful. +# Note that this signature is not the same as IkiWiki::SortSpec::sort_pages, +# which is "more internal". +sub sort_pages ($$;@) { + my $sort = shift; + my $list = shift; + my %params = @_; + $sort = sortspec_translate($sort, $params{reverse}); + return IkiWiki::SortSpec::sort_pages($sort, @$list); +} + +sub pagespec_match_list ($$;@) { + my $page=shift; + my $pagespec=shift; + my %params=@_; + + # Backwards compatability with old calling convention. + if (ref $page) { + print STDERR "warning: a plugin (".caller().") is using pagespec_match_list in an obsolete way, and needs to be updated\n"; + $params{list}=$page; + $page=$params{location}; # ugh! + } + + my $sub=pagespec_translate($pagespec); + error "syntax error in pagespec \"$pagespec\"" + if ! defined $sub; + my $sort=sortspec_translate($params{sort}, $params{reverse}) + if defined $params{sort}; + + my @candidates; + if (exists $params{list}) { + @candidates=exists $params{filter} + ? grep { ! $params{filter}->($_) } @{$params{list}} + : @{$params{list}}; + } + else { + @candidates=exists $params{filter} + ? grep { ! $params{filter}->($_) } keys %pagesources + : keys %pagesources; + } + + # clear params, remainder is passed to pagespec + $depends{$page}{$pagespec} |= ($params{deptype} || $DEPEND_CONTENT); + my $num=$params{num}; + delete @params{qw{num deptype reverse sort filter list}}; + + # when only the top matches will be returned, it's efficient to + # sort before matching to pagespec, + if (defined $num && defined $sort) { + @candidates=IkiWiki::SortSpec::sort_pages( + $sort, @candidates); + } + + my @matches; + my $firstfail; + my $count=0; + my $accum=IkiWiki::SuccessReason->new(); + foreach my $p (@candidates) { + my $r=$sub->($p, %params, location => $page); + error(sprintf(gettext("cannot match pages: %s"), $r)) + if $r->isa("IkiWiki::ErrorReason"); + unless ($r || $r->influences_static) { + $r->remove_influence($p); + } + $accum |= $r; + if ($r) { + push @matches, $p; + last if defined $num && ++$count == $num; + } + } + + # Add simple dependencies for accumulated influences. + my $i=$accum->influences; + foreach my $k (keys %$i) { + $depends_simple{$page}{lc $k} |= $i->{$k}; + } + + # when all matches will be returned, it's efficient to + # sort after matching + if (! defined $num && defined $sort) { + return IkiWiki::SortSpec::sort_pages( + $sort, @matches); + } + else { + return @matches; + } +} + +sub pagespec_valid ($) { + my $spec=shift; + + return defined pagespec_translate($spec); +} + +sub glob2re ($) { + my $re=quotemeta(shift); + $re=~s/\\\*/.*/g; + $re=~s/\\\?/./g; + return qr/^$re$/i; +} + +package IkiWiki::FailReason; + +use overload ( + '""' => sub { $_[0][0] }, + '0+' => sub { 0 }, + '!' => sub { bless $_[0], 'IkiWiki::SuccessReason'}, + '&' => sub { $_[0]->merge_influences($_[1], 1); $_[0] }, + '|' => sub { $_[1]->merge_influences($_[0]); $_[1] }, + fallback => 1, +); + +our @ISA = 'IkiWiki::SuccessReason'; + +package IkiWiki::SuccessReason; + +# A blessed array-ref: +# +# [0]: human-readable reason for success (or, in FailReason subclass, failure) +# [1]{""}: +# - if absent or false, the influences of this evaluation are "static", +# see the influences_static method +# - if true, they are dynamic (not static) +# [1]{any other key}: +# the dependency types of influences, as returned by the influences method + +use overload ( + # in string context, it's the human-readable reason + '""' => sub { $_[0][0] }, + # in boolean context, SuccessReason is 1 and FailReason is 0 + '0+' => sub { 1 }, + # negating a result gives the opposite result with the same influences + '!' => sub { bless $_[0], 'IkiWiki::FailReason'}, + # A & B = (A ? B : A) with the influences of both + '&' => sub { $_[1]->merge_influences($_[0], 1); $_[1] }, + # A | B = (A ? A : B) with the influences of both + '|' => sub { $_[0]->merge_influences($_[1]); $_[0] }, + fallback => 1, +); + +# SuccessReason->new("human-readable reason", page => deptype, ...) + +sub new { + my $class = shift; + my $value = shift; + return bless [$value, {@_}], $class; +} + +# influences(): return a reference to a copy of the hash +# { page => dependency type } describing the pages that indirectly influenced +# this result, but would not cause a dependency through ikiwiki's core +# dependency logic. +# +# See [[todo/dependency_types]] for extensive discussion of what this means. +# +# influences(page => deptype, ...): remove all influences, replace them +# with the arguments, and return a reference to a copy of the new influences. + +sub influences { + my $this=shift; + $this->[1]={@_} if @_; + my %i=%{$this->[1]}; + delete $i{""}; + return \%i; +} + +# True if this result has the same influences whichever page it matches, +# For instance, whether bar matches backlink(foo) is influenced only by +# the set of links in foo, so its only influence is { foo => DEPEND_LINKS }, +# which does not mention bar anywhere. +# +# False if this result would have different influences when matching +# different pages. For instance, when testing whether link(foo) matches bar, +# { bar => DEPEND_LINKS } is an influence on that result, because changing +# bar's links could change the outcome; so its influences are not the same +# as when testing whether link(foo) matches baz. +# +# Static influences are one of the things that make pagespec_match_list +# more efficient than repeated calls to pagespec_match. + +sub influences_static { + return ! $_[0][1]->{""}; +} + +# Change the influences of $this to be the influences of "$this & $other" +# or "$this | $other". +# +# If both $this and $other are either successful or have influences, +# or this is an "or" operation, the result has all the influences from +# either of the arguments. It has dynamic influences if either argument +# has dynamic influences. +# +# If this is an "and" operation, and at least one argument is a +# FailReason with no influences, the result has no influences, and they +# are not dynamic. For instance, link(foo) matching bar is influenced +# by bar, but enabled(ddate) has no influences. Suppose ddate is disabled; +# then (link(foo) and enabled(ddate)) not matching bar is not influenced by +# bar, because it would be false however often you edit bar. + +sub merge_influences { + my $this=shift; + my $other=shift; + my $anded=shift; + + # This "if" is odd because it needs to avoid negating $this + # or $other, which would alter the objects in-place. Be careful. + if (! $anded || (($this || %{$this->[1]}) && + ($other || %{$other->[1]}))) { + foreach my $influence (keys %{$other->[1]}) { + $this->[1]{$influence} |= $other->[1]{$influence}; + } + } + else { + # influence blocker + $this->[1]={}; + } +} + +# Change $this so it is not considered to be influenced by $torm. + +sub remove_influence { + my $this=shift; + my $torm=shift; + + delete $this->[1]{$torm}; +} + +package IkiWiki::ErrorReason; + +our @ISA = 'IkiWiki::FailReason'; + +package IkiWiki::PageSpec; + +sub derel ($$) { + my $path=shift; + my $from=shift; + + if ($path =~ m!^\.(/|$)!) { + if ($1) { + $from=~s#/?[^/]+$## if defined $from; + $path=~s#^\./##; + $path="$from/$path" if defined $from && length $from; + } + else { + $path = $from; + $path = "" unless defined $path; + } + } + + return $path; +} + +my %glob_cache; + +sub match_glob ($$;@) { + my $page=shift; + my $glob=shift; + my %params=@_; + + $glob=derel($glob, $params{location}); + + # Instead of converting the glob to a regex every time, + # cache the compiled regex to save time. + my $re=$glob_cache{$glob}; + unless (defined $re) { + $glob_cache{$glob} = $re = IkiWiki::glob2re($glob); + } + if ($page =~ $re) { + if (! IkiWiki::isinternal($page) || $params{internal}) { + return IkiWiki::SuccessReason->new("$glob matches $page"); + } + else { + return IkiWiki::FailReason->new("$glob matches $page, but the page is an internal page"); + } + } + else { + return IkiWiki::FailReason->new("$glob does not match $page"); + } +} + +sub match_internal ($$;@) { + return match_glob(shift, shift, @_, internal => 1) +} + +sub match_page ($$;@) { + my $page=shift; + my $match=match_glob($page, shift, @_); + if ($match) { + my $source=exists $IkiWiki::pagesources{$page} ? + $IkiWiki::pagesources{$page} : + $IkiWiki::delpagesources{$page}; + my $type=defined $source ? IkiWiki::pagetype($source) : undef; + if (! defined $type) { + return IkiWiki::FailReason->new("$page is not a page"); + } + } + return $match; +} + +sub match_link ($$;@) { + my $page=shift; + my $link=lc(shift); + my %params=@_; + + $link=derel($link, $params{location}); + my $from=exists $params{location} ? $params{location} : ''; + my $linktype=$params{linktype}; + my $qualifier=''; + if (defined $linktype) { + $qualifier=" with type $linktype"; + } + + my $links = $IkiWiki::links{$page}; + return IkiWiki::FailReason->new("$page has no links", $page => $IkiWiki::DEPEND_LINKS, "" => 1) + unless $links && @{$links}; + my $bestlink = IkiWiki::bestlink($from, $link); + foreach my $p (@{$links}) { + next unless (! defined $linktype || exists $IkiWiki::typedlinks{$page}{$linktype}{$p}); + + if (length $bestlink) { + if ($bestlink eq IkiWiki::bestlink($page, $p)) { + return IkiWiki::SuccessReason->new("$page links to $link$qualifier", $page => $IkiWiki::DEPEND_LINKS, "" => 1) + } + } + else { + if (match_glob($p, $link, %params)) { + return IkiWiki::SuccessReason->new("$page links to page $p$qualifier, matching $link", $page => $IkiWiki::DEPEND_LINKS, "" => 1) + } + my ($p_rel)=$p=~/^\/?(.*)/; + $link=~s/^\///; + if (match_glob($p_rel, $link, %params)) { + return IkiWiki::SuccessReason->new("$page links to page $p_rel$qualifier, matching $link", $page => $IkiWiki::DEPEND_LINKS, "" => 1) + } + } + } + return IkiWiki::FailReason->new("$page does not link to $link$qualifier", $page => $IkiWiki::DEPEND_LINKS, "" => 1); +} + +sub match_backlink ($$;@) { + my $page=shift; + my $testpage=shift; + my %params=@_; + if ($testpage eq '.') { + $testpage = $params{'location'} + } + my $ret=match_link($testpage, $page, @_); + $ret->influences($testpage => $IkiWiki::DEPEND_LINKS); + return $ret; +} + +sub match_created_before ($$;@) { + my $page=shift; + my $testpage=shift; + my %params=@_; + + $testpage=derel($testpage, $params{location}); + + if (exists $IkiWiki::pagectime{$testpage}) { + if ($IkiWiki::pagectime{$page} < $IkiWiki::pagectime{$testpage}) { + return IkiWiki::SuccessReason->new("$page created before $testpage", $testpage => $IkiWiki::DEPEND_PRESENCE); + } + else { + return IkiWiki::FailReason->new("$page not created before $testpage", $testpage => $IkiWiki::DEPEND_PRESENCE); + } + } + else { + return IkiWiki::ErrorReason->new("$testpage does not exist", $testpage => $IkiWiki::DEPEND_PRESENCE); + } +} + +sub match_created_after ($$;@) { + my $page=shift; + my $testpage=shift; + my %params=@_; + + $testpage=derel($testpage, $params{location}); + + if (exists $IkiWiki::pagectime{$testpage}) { + if ($IkiWiki::pagectime{$page} > $IkiWiki::pagectime{$testpage}) { + return IkiWiki::SuccessReason->new("$page created after $testpage", $testpage => $IkiWiki::DEPEND_PRESENCE); + } + else { + return IkiWiki::FailReason->new("$page not created after $testpage", $testpage => $IkiWiki::DEPEND_PRESENCE); + } + } + else { + return IkiWiki::ErrorReason->new("$testpage does not exist", $testpage => $IkiWiki::DEPEND_PRESENCE); + } +} + +sub match_creation_day ($$;@) { + my $page=shift; + my $d=shift; + if ($d !~ /^\d+$/) { + return IkiWiki::ErrorReason->new("invalid day $d"); + } + if ((localtime($IkiWiki::pagectime{$page}))[3] == $d) { + return IkiWiki::SuccessReason->new('creation_day matched'); + } + else { + return IkiWiki::FailReason->new('creation_day did not match'); + } +} + +sub match_creation_month ($$;@) { + my $page=shift; + my $m=shift; + if ($m !~ /^\d+$/) { + return IkiWiki::ErrorReason->new("invalid month $m"); + } + if ((localtime($IkiWiki::pagectime{$page}))[4] + 1 == $m) { + return IkiWiki::SuccessReason->new('creation_month matched'); + } + else { + return IkiWiki::FailReason->new('creation_month did not match'); + } +} + +sub match_creation_year ($$;@) { + my $page=shift; + my $y=shift; + if ($y !~ /^\d+$/) { + return IkiWiki::ErrorReason->new("invalid year $y"); + } + if ((localtime($IkiWiki::pagectime{$page}))[5] + 1900 == $y) { + return IkiWiki::SuccessReason->new('creation_year matched'); + } + else { + return IkiWiki::FailReason->new('creation_year did not match'); + } +} + +sub match_user ($$;@) { + shift; + my $user=shift; + my %params=@_; + + if (! exists $params{user}) { + return IkiWiki::ErrorReason->new("no user specified"); + } + + my $regexp=IkiWiki::glob2re($user); + + if (defined $params{user} && $params{user}=~$regexp) { + return IkiWiki::SuccessReason->new("user is $user"); + } + elsif (! defined $params{user}) { + return IkiWiki::FailReason->new("not logged in"); + } + else { + return IkiWiki::FailReason->new("user is $params{user}, not $user"); + } +} + +sub match_admin ($$;@) { + shift; + shift; + my %params=@_; + + if (! exists $params{user}) { + return IkiWiki::ErrorReason->new("no user specified"); + } + + if (defined $params{user} && IkiWiki::is_admin($params{user})) { + return IkiWiki::SuccessReason->new("user is an admin"); + } + elsif (! defined $params{user}) { + return IkiWiki::FailReason->new("not logged in"); + } + else { + return IkiWiki::FailReason->new("user is not an admin"); + } +} + +sub match_ip ($$;@) { + shift; + my $ip=shift; + my %params=@_; + + if (! exists $params{ip}) { + return IkiWiki::ErrorReason->new("no IP specified"); + } + + my $regexp=IkiWiki::glob2re(lc $ip); + + if (defined $params{ip} && lc $params{ip}=~$regexp) { + return IkiWiki::SuccessReason->new("IP is $ip"); + } + else { + return IkiWiki::FailReason->new("IP is $params{ip}, not $ip"); + } +} + +package IkiWiki::SortSpec; + +# This is in the SortSpec namespace so that the $a and $b that sort() uses +# are easily available in this namespace, for cmp functions to use them. +sub sort_pages { + my $f=shift; + sort $f @_ +} + +sub cmp_title { + IkiWiki::pagetitle(IkiWiki::basename($a)) + cmp + IkiWiki::pagetitle(IkiWiki::basename($b)) +} + +sub cmp_path { IkiWiki::pagetitle($a) cmp IkiWiki::pagetitle($b) } +sub cmp_mtime { $IkiWiki::pagemtime{$b} <=> $IkiWiki::pagemtime{$a} } +sub cmp_age { $IkiWiki::pagectime{$b} <=> $IkiWiki::pagectime{$a} } + +1 diff --git a/IkiWiki/CGI.pm b/IkiWiki/CGI.pm new file mode 100644 index 000000000..cb83319e6 --- /dev/null +++ b/IkiWiki/CGI.pm @@ -0,0 +1,482 @@ +#!/usr/bin/perl + +package IkiWiki; + +use warnings; +use strict; +use IkiWiki; +use IkiWiki::UserInfo; +use open qw{:utf8 :std}; +use Encode; + +sub printheader ($) { + my $session=shift; + + if (($ENV{HTTPS} && lc $ENV{HTTPS} ne "off") || $config{sslcookie}) { + print $session->header(-charset => 'utf-8', + -cookie => $session->cookie(-httponly => 1, -secure => 1)); + } + else { + print $session->header(-charset => 'utf-8', + -cookie => $session->cookie(-httponly => 1)); + } +} + +sub prepform { + my $form=shift; + my $buttons=shift; + my $session=shift; + my $cgi=shift; + + if (exists $hooks{formbuilder}) { + run_hooks(formbuilder => sub { + shift->(form => $form, cgi => $cgi, session => $session, + buttons => $buttons); + }); + } + + return $form; +} + +sub showform ($$$$;@) { + my $form=prepform(@_); + shift; + my $buttons=shift; + my $session=shift; + my $cgi=shift; + + printheader($session); + print cgitemplate($cgi, $form->title, + $form->render(submit => $buttons), @_); +} + +sub cgitemplate ($$$;@) { + my $cgi=shift; + my $title=shift; + my $content=shift; + my %params=@_; + + my $template=template("page.tmpl"); + + my $topurl = defined $cgi ? $cgi->url : $config{url}; + + my $page=""; + if (exists $params{page}) { + $page=delete $params{page}; + $params{forcebaseurl}=urlabs(urlto($page), $topurl); + } + run_hooks(pagetemplate => sub { + shift->( + page => $page, + destpage => $page, + template => $template, + ); + }); + templateactions($template, ""); + + $template->param( + dynamic => 1, + title => $title, + wikiname => $config{wikiname}, + content => $content, + baseurl => urlabs(baseurl(), $topurl), + html5 => $config{html5}, + %params, + ); + + return $template->output; +} + +sub redirect ($$) { + my $q=shift; + eval q{use URI}; + my $url=URI->new(urlabs(shift, $q->url)); + if (! $config{w3mmode}) { + print $q->redirect($url); + } + else { + print "Content-type: text/plain\n"; + print "W3m-control: GOTO $url\n\n"; + } +} + +sub decode_cgi_utf8 ($) { + # decode_form_utf8 method is needed for 5.01 + if ($] < 5.01) { + my $cgi = shift; + foreach my $f ($cgi->param) { + $cgi->param($f, map { decode_utf8 $_ } $cgi->param($f)); + } + } +} + +sub safe_decode_utf8 ($) { + my $octets = shift; + # call decode_utf8 on >= 5.20 only if it's not already decoded, + # otherwise it balks, on < 5.20, always call it + if ($] < 5.02 || !Encode::is_utf8($octets)) { + return decode_utf8($octets); + } + else { + return $octets; + } +} + +sub decode_form_utf8 ($) { + if ($] >= 5.01) { + my $form = shift; + foreach my $f ($form->field) { + my @value=map { safe_decode_utf8($_) } $form->field($f); + $form->field(name => $f, + value => \@value, + force => 1, + ); + } + } +} + +# Check if the user is signed in. If not, redirect to the signin form and +# save their place to return to later. +sub needsignin ($$) { + my $q=shift; + my $session=shift; + + if (! defined $session->param("name") || + ! userinfo_get($session->param("name"), "regdate")) { + $session->param(postsignin => $q->query_string); + cgi_signin($q, $session); + cgi_savesession($session); + exit; + } +} + +sub cgi_signin ($$;$) { + my $q=shift; + my $session=shift; + my $returnhtml=shift; + + decode_cgi_utf8($q); + eval q{use CGI::FormBuilder}; + error($@) if $@; + my $form = CGI::FormBuilder->new( + title => "signin", + name => "signin", + charset => "utf-8", + method => 'POST', + required => 'NONE', + javascript => 0, + params => $q, + action => cgiurl(), + header => 0, + template => {type => 'div'}, + stylesheet => 1, + ); + my $buttons=["Login"]; + + $form->field(name => "do", type => "hidden", value => "signin", + force => 1); + + decode_form_utf8($form); + run_hooks(formbuilder_setup => sub { + shift->(form => $form, cgi => $q, session => $session, + buttons => $buttons); + }); + decode_form_utf8($form); + + if ($form->submitted) { + $form->validate; + } + + if ($returnhtml) { + $form=prepform($form, $buttons, $session, $q); + return $form->render(submit => $buttons); + } + + showform($form, $buttons, $session, $q); +} + +sub cgi_postsignin ($$) { + my $q=shift; + my $session=shift; + + # Continue with whatever was being done before the signin process. + if (defined $session->param("postsignin")) { + my $postsignin=CGI->new($session->param("postsignin")); + $session->clear("postsignin"); + cgi($postsignin, $session); + cgi_savesession($session); + exit; + } + else { + if ($config{sslcookie} && ! $q->https()) { + error(gettext("probable misconfiguration: sslcookie is set, but you are attempting to login via http, not https")); + } + else { + error(gettext("login failed, perhaps you need to turn on cookies?")); + } + } +} + +sub cgi_prefs ($$) { + my $q=shift; + my $session=shift; + + needsignin($q, $session); + decode_cgi_utf8($q); + + # The session id is stored on the form and checked to + # guard against CSRF. + my $sid=$q->param('sid'); + if (! defined $sid) { + $q->delete_all; + } + elsif ($sid ne $session->id) { + error(gettext("Your login session has expired.")); + } + + eval q{use CGI::FormBuilder}; + error($@) if $@; + my $form = CGI::FormBuilder->new( + title => "preferences", + name => "preferences", + header => 0, + charset => "utf-8", + method => 'POST', + validate => { + email => 'EMAIL', + }, + required => 'NONE', + javascript => 0, + params => $q, + action => cgiurl(), + template => {type => 'div'}, + stylesheet => 1, + fieldsets => [ + [login => gettext("Login")], + [preferences => gettext("Preferences")], + [admin => gettext("Admin")] + ], + ); + my $buttons=["Save Preferences", "Logout", "Cancel"]; + + decode_form_utf8($form); + run_hooks(formbuilder_setup => sub { + shift->(form => $form, cgi => $q, session => $session, + buttons => $buttons); + }); + decode_form_utf8($form); + + $form->field(name => "do", type => "hidden", value => "prefs", + force => 1); + $form->field(name => "sid", type => "hidden", value => $session->id, + force => 1); + $form->field(name => "email", size => 50, fieldset => "preferences"); + + my $user_name=$session->param("name"); + + if (! $form->submitted) { + $form->field(name => "email", force => 1, + value => userinfo_get($user_name, "email")); + } + + if ($form->submitted eq 'Logout') { + $session->delete(); + redirect($q, baseurl(undef)); + return; + } + elsif ($form->submitted eq 'Cancel') { + redirect($q, baseurl(undef)); + return; + } + elsif ($form->submitted eq 'Save Preferences' && $form->validate) { + if (defined $form->field('email')) { + userinfo_set($user_name, 'email', $form->field('email')) || + error("failed to set email"); + } + + $form->text(gettext("Preferences saved.")); + } + + showform($form, $buttons, $session, $q, + prefsurl => "", # avoid showing the preferences link + ); +} + +sub cgi_custom_failure ($$$) { + my $q=shift; + my $httpstatus=shift; + my $message=shift; + + print $q->header( + -status => $httpstatus, + -charset => 'utf-8', + ); + print $message; + + # Internet Explod^Hrer won't show custom 404 responses + # unless they're >= 512 bytes + print ' ' x 512; + + exit; +} + +sub check_banned ($$) { + my $q=shift; + my $session=shift; + + my $banned=0; + my $name=$session->param("name"); + if (defined $name && + grep { $name eq $_ } @{$config{banned_users}}) { + $banned=1; + } + + foreach my $b (@{$config{banned_users}}) { + if (pagespec_match("", $b, + ip => $session->remote_addr(), + name => defined $name ? $name : "", + )) { + $banned=1; + last; + } + } + + if ($banned) { + $session->delete(); + cgi_savesession($session); + cgi_custom_failure( + $q, "403 Forbidden", + gettext("You are banned.")); + } +} + +sub cgi_getsession ($) { + my $q=shift; + + eval q{use CGI::Session; use HTML::Entities}; + error($@) if $@; + CGI::Session->name("ikiwiki_session_".encode_entities($config{wikiname})); + + my $oldmask=umask(077); + my $session = eval { + CGI::Session->new("driver:DB_File", $q, + { FileName => "$config{wikistatedir}/sessions.db" }) + }; + if (! $session || $@) { + my $error = $@; + error($error." ".CGI::Session->errstr()); + } + + umask($oldmask); + + return $session; +} + +# To guard against CSRF, the user's session id (sid) +# can be stored on a form. This function will check +# (for logged in users) that the sid on the form matches +# the session id in the cookie. +sub checksessionexpiry ($$) { + my $q=shift; + my $session = shift; + + if (defined $session->param("name")) { + my $sid=$q->param('sid'); + if (! defined $sid || $sid ne $session->id) { + error(gettext("Your login session has expired.")); + } + } +} + +sub cgi_savesession ($) { + my $session=shift; + + # Force session flush with safe umask. + my $oldmask=umask(077); + $session->flush; + umask($oldmask); +} + +sub cgi (;$$) { + my $q=shift; + my $session=shift; + + eval q{use CGI}; + error($@) if $@; + $CGI::DISABLE_UPLOADS=$config{cgi_disable_uploads}; + + if (! $q) { + binmode(STDIN); + $q=CGI->new; + binmode(STDIN, ":utf8"); + + run_hooks(cgi => sub { shift->($q) }); + } + + my $do=$q->param('do'); + if (! defined $do || ! length $do) { + my $error = $q->cgi_error; + if ($error) { + error("Request not processed: $error"); + } + else { + error("\"do\" parameter missing"); + } + } + + # Need to lock the wiki before getting a session. + lockwiki(); + loadindex(); + + if (! $session) { + $session=cgi_getsession($q); + } + + # Auth hooks can sign a user in. + if ($do ne 'signin' && ! defined $session->param("name")) { + run_hooks(auth => sub { + shift->($q, $session) + }); + if (defined $session->param("name")) { + # Make sure whatever user was authed is in the + # userinfo db. + if (! userinfo_get($session->param("name"), "regdate")) { + userinfo_setall($session->param("name"), { + email => defined $session->param("email") ? $session->param("email") : "", + password => "", + regdate => time, + }) || error("failed adding user"); + } + } + } + + check_banned($q, $session); + + run_hooks(sessioncgi => sub { shift->($q, $session) }); + + if ($do eq 'signin') { + cgi_signin($q, $session); + cgi_savesession($session); + } + elsif ($do eq 'prefs') { + cgi_prefs($q, $session); + } + elsif (defined $session->param("postsignin") || $do eq 'postsignin') { + cgi_postsignin($q, $session); + } + else { + error("unknown do parameter"); + } +} + +# Does not need to be called directly; all errors will go through here. +sub cgierror ($) { + my $message=shift; + + print "Content-type: text/html\n\n"; + print cgitemplate(undef, gettext("Error"), + "

".gettext("Error").": $message

"); + die $@; +} + +1 diff --git a/IkiWiki/Plugin/404.pm b/IkiWiki/Plugin/404.pm new file mode 100644 index 000000000..42cfa9e8a --- /dev/null +++ b/IkiWiki/Plugin/404.pm @@ -0,0 +1,81 @@ +#!/usr/bin/perl +# Copyright © 2009 Simon McVittie +# Licensed under the GNU GPL, version 2, or any later version published by the +# Free Software Foundation +package IkiWiki::Plugin::404; + +use warnings; +use strict; +use IkiWiki 3.00; + +sub import { + hook(type => "cgi", id => '404', call => \&cgi); + hook(type => "getsetup", id => '404', call => \&getsetup); + IkiWiki::loadplugin("goto"); +} + +sub getsetup () { + return + plugin => { + # not really a matter of safety, but enabling/disabling + # through a web interface is useless - it needs web + # server admin action too + safe => 0, + rebuild => 0, + section => "web", + } +} + +sub cgi_page_from_404 ($$$) { + my $path = shift; + my $baseurl = shift; + my $usedirs = shift; + + # fail if missing from environment or whatever + return undef unless defined $path; + return undef unless defined $baseurl; + + # with usedirs on, path is like /~fred/foo/bar/ or /~fred/foo/bar or + # /~fred/foo/bar/index.html + # with usedirs off, path is like /~fred/foo/bar.html + # baseurl is like 'http://people.example.com/~fred' + + # convert baseurl to ~fred + unless ($baseurl =~ s{^https?://[^/]+/?}{}) { + return undef; + } + + # convert path to /~fred/foo/bar + if ($usedirs) { + $path =~ s/\/*(?:index\.$config{htmlext})?$//; + } + else { + $path =~ s/\.$config{htmlext}$//; + } + + # remove /~fred/ + unless ($path =~ s{^/*\Q$baseurl\E/*}{}) { + return undef; + } + + # special case for the index + unless ($path) { + return 'index'; + } + + return $path; +} + +sub cgi ($) { + my $cgi=shift; + + if (exists $ENV{REDIRECT_STATUS} && + $ENV{REDIRECT_STATUS} eq '404') { + my $page = cgi_page_from_404( + Encode::decode_utf8($ENV{REDIRECT_URL}), + $config{url}, $config{usedirs}); + IkiWiki::Plugin::goto::cgi_goto($cgi, $page); + } +} + +1; diff --git a/IkiWiki/Plugin/aggregate.pm b/IkiWiki/Plugin/aggregate.pm new file mode 100644 index 000000000..fbf88c627 --- /dev/null +++ b/IkiWiki/Plugin/aggregate.pm @@ -0,0 +1,789 @@ +#!/usr/bin/perl +# Feed aggregation plugin. +package IkiWiki::Plugin::aggregate; + +use warnings; +use strict; +use IkiWiki 3.00; +use HTML::Parser; +use HTML::Tagset; +use HTML::Entities; +use open qw{:utf8 :std}; + +my %feeds; +my %guids; + +sub import { + hook(type => "getopt", id => "aggregate", call => \&getopt); + hook(type => "getsetup", id => "aggregate", call => \&getsetup); + hook(type => "checkconfig", id => "aggregate", call => \&checkconfig, + last => 1); + hook(type => "needsbuild", id => "aggregate", call => \&needsbuild); + hook(type => "preprocess", id => "aggregate", call => \&preprocess); + hook(type => "delete", id => "aggregate", call => \&delete); + hook(type => "savestate", id => "aggregate", call => \&savestate); + hook(type => "htmlize", id => "_aggregated", call => \&htmlize); + if (exists $config{aggregate_webtrigger} && $config{aggregate_webtrigger}) { + hook(type => "cgi", id => "aggregate", call => \&cgi); + } +} + +sub getopt () { + eval q{use Getopt::Long}; + error($@) if $@; + Getopt::Long::Configure('pass_through'); + GetOptions( + "aggregate" => \$config{aggregate}, + "aggregateinternal!" => \$config{aggregateinternal}, + ); +} + +sub getsetup () { + return + plugin => { + safe => 1, + rebuild => undef, + }, + aggregateinternal => { + type => "boolean", + example => 1, + description => "enable aggregation to internal pages?", + safe => 0, # enabling needs manual transition + rebuild => 0, + }, + aggregate_webtrigger => { + type => "boolean", + example => 0, + description => "allow aggregation to be triggered via the web?", + safe => 1, + rebuild => 0, + }, +} + +sub checkconfig () { + if (! defined $config{aggregateinternal}) { + $config{aggregateinternal}=1; + } + + # This is done here rather than in a refresh hook because it + # needs to run before the wiki is locked. + if ($config{aggregate} && ! ($config{post_commit} && + IkiWiki::commit_hook_enabled())) { + launchaggregation(); + } +} + +sub cgi ($) { + my $cgi=shift; + + if (defined $cgi->param('do') && + $cgi->param("do") eq "aggregate_webtrigger") { + $|=1; + print "Content-Type: text/plain\n\n"; + $config{cgi}=0; + $config{verbose}=1; + $config{syslog}=0; + print gettext("Aggregation triggered via web.")."\n\n"; + if (launchaggregation()) { + IkiWiki::lockwiki(); + IkiWiki::loadindex(); + require IkiWiki::Render; + IkiWiki::refresh(); + IkiWiki::saveindex(); + } + else { + print gettext("Nothing to do right now, all feeds are up-to-date!")."\n"; + } + exit 0; + } +} + +sub launchaggregation () { + # See if any feeds need aggregation. + loadstate(); + my @feeds=needsaggregate(); + return unless @feeds; + if (! lockaggregate()) { + error("an aggregation process is already running"); + } + # force a later rebuild of source pages + $IkiWiki::forcerebuild{$_->{sourcepage}}=1 + foreach @feeds; + + # Fork a child process to handle the aggregation. + # The parent process will then handle building the + # result. This avoids messy code to clear state + # accumulated while aggregating. + defined(my $pid = fork) or error("Can't fork: $!"); + if (! $pid) { + IkiWiki::loadindex(); + # Aggregation happens without the main wiki lock + # being held. This allows editing pages etc while + # aggregation is running. + aggregate(@feeds); + + IkiWiki::lockwiki; + # Merge changes, since aggregation state may have + # changed on disk while the aggregation was happening. + mergestate(); + expire(); + savestate(); + IkiWiki::unlockwiki; + exit 0; + } + waitpid($pid,0); + if ($?) { + error "aggregation failed with code $?"; + } + + clearstate(); + unlockaggregate(); + + return 1; +} + +# Pages with extension _aggregated have plain html markup, pass through. +sub htmlize (@) { + my %params=@_; + return $params{content}; +} + +# Used by ikiwiki-transition aggregateinternal. +sub migrate_to_internal { + if (! lockaggregate()) { + error("an aggregation process is currently running"); + } + + IkiWiki::lockwiki(); + loadstate(); + $config{verbose}=1; + + foreach my $data (values %guids) { + next unless $data->{page}; + next if $data->{expired}; + + $config{aggregateinternal} = 0; + my $oldname = "$config{srcdir}/".htmlfn($data->{page}); + if (! -e $oldname) { + $oldname = $IkiWiki::Plugin::transient::transientdir."/".htmlfn($data->{page}); + } + + my $oldoutput = $config{destdir}."/".IkiWiki::htmlpage($data->{page}); + + $config{aggregateinternal} = 1; + my $newname = $IkiWiki::Plugin::transient::transientdir."/".htmlfn($data->{page}); + + debug "moving $oldname -> $newname"; + if (-e $newname) { + if (-e $oldname) { + error("$newname already exists"); + } + else { + debug("already renamed to $newname?"); + } + } + elsif (-e $oldname) { + rename($oldname, $newname) || error("$!"); + } + else { + debug("$oldname not found"); + } + if (-e $oldoutput) { + require IkiWiki::Render; + debug("removing output file $oldoutput"); + IkiWiki::prune($oldoutput, $config{destdir}); + } + } + + savestate(); + IkiWiki::unlockwiki; + + unlockaggregate(); +} + +sub needsbuild (@) { + my $needsbuild=shift; + + loadstate(); + + foreach my $feed (values %feeds) { + if (exists $pagesources{$feed->{sourcepage}} && + grep { $_ eq $pagesources{$feed->{sourcepage}} } @$needsbuild) { + # Mark all feeds originating on this page as + # not yet seen; preprocess will unmark those that + # still exist. + markunseen($feed->{sourcepage}); + } + } + + return $needsbuild; +} + +sub preprocess (@) { + my %params=@_; + + foreach my $required (qw{name url}) { + if (! exists $params{$required}) { + error sprintf(gettext("missing %s parameter"), $required) + } + } + + my $feed={}; + my $name=$params{name}; + if (exists $feeds{$name}) { + $feed=$feeds{$name}; + } + else { + $feeds{$name}=$feed; + } + $feed->{name}=$name; + $feed->{sourcepage}=$params{page}; + $feed->{url}=$params{url}; + my $dir=exists $params{dir} ? $params{dir} : $params{page}."/".titlepage($params{name}); + $dir=~s/^\/+//; + ($dir)=$dir=~/$config{wiki_file_regexp}/; + $feed->{dir}=$dir; + $feed->{feedurl}=defined $params{feedurl} ? $params{feedurl} : ""; + $feed->{updateinterval}=defined $params{updateinterval} ? $params{updateinterval} * 60 : 15 * 60; + $feed->{expireage}=defined $params{expireage} ? $params{expireage} : 0; + $feed->{expirecount}=defined $params{expirecount} ? $params{expirecount} : 0; + if (exists $params{template}) { + $params{template}=~s/[^-_a-zA-Z0-9]+//g; + } + else { + $params{template} = "aggregatepost" + } + $feed->{template}=$params{template} . ".tmpl"; + delete $feed->{unseen}; + $feed->{lastupdate}=0 unless defined $feed->{lastupdate}; + $feed->{lasttry}=$feed->{lastupdate} unless defined $feed->{lasttry}; + $feed->{numposts}=0 unless defined $feed->{numposts}; + $feed->{newposts}=0 unless defined $feed->{newposts}; + $feed->{message}=gettext("new feed") unless defined $feed->{message}; + $feed->{error}=0 unless defined $feed->{error}; + $feed->{tags}=[]; + while (@_) { + my $key=shift; + my $value=shift; + if ($key eq 'tag') { + push @{$feed->{tags}}, $value; + } + } + + return "{url}."\">".$feed->{name}.": ". + ($feed->{error} ? "" : "").$feed->{message}. + ($feed->{error} ? "" : ""). + " (".$feed->{numposts}." ".gettext("posts"). + ($feed->{newposts} ? "; ".$feed->{newposts}. + " ".gettext("new") : ""). + ")"; +} + +sub delete (@) { + my @files=@_; + + # Remove feed data for removed pages. + foreach my $file (@files) { + my $page=pagename($file); + markunseen($page); + } +} + +sub markunseen ($) { + my $page=shift; + + foreach my $id (keys %feeds) { + if ($feeds{$id}->{sourcepage} eq $page) { + $feeds{$id}->{unseen}=1; + } + } +} + +my $state_loaded=0; + +sub loadstate () { + return if $state_loaded; + $state_loaded=1; + if (-e "$config{wikistatedir}/aggregate") { + open(IN, "<", "$config{wikistatedir}/aggregate") || + die "$config{wikistatedir}/aggregate: $!"; + while () { + $_=IkiWiki::possibly_foolish_untaint($_); + chomp; + my $data={}; + foreach my $i (split(/ /, $_)) { + my ($field, $val)=split(/=/, $i, 2); + if ($field eq "name" || $field eq "feed" || + $field eq "guid" || $field eq "message") { + $data->{$field}=decode_entities($val, " \t\n"); + } + elsif ($field eq "tag") { + push @{$data->{tags}}, $val; + } + else { + $data->{$field}=$val; + } + } + + if (exists $data->{name}) { + $feeds{$data->{name}}=$data; + } + elsif (exists $data->{guid}) { + $guids{$data->{guid}}=$data; + } + } + + close IN; + } +} + +sub savestate () { + return unless $state_loaded; + garbage_collect(); + my $newfile="$config{wikistatedir}/aggregate.new"; + my $cleanup = sub { unlink($newfile) }; + open (OUT, ">", $newfile) || error("open $newfile: $!", $cleanup); + foreach my $data (values %feeds, values %guids) { + my @line; + foreach my $field (keys %$data) { + if ($field eq "name" || $field eq "feed" || + $field eq "guid" || $field eq "message") { + push @line, "$field=".encode_entities($data->{$field}, " \t\n"); + } + elsif ($field eq "tags") { + push @line, "tag=$_" foreach @{$data->{tags}}; + } + else { + push @line, "$field=".$data->{$field} + if defined $data->{$field}; + } + } + print OUT join(" ", @line)."\n" || error("write $newfile: $!", $cleanup); + } + close OUT || error("save $newfile: $!", $cleanup); + rename($newfile, "$config{wikistatedir}/aggregate") || + error("rename $newfile: $!", $cleanup); + + my $timestamp=undef; + foreach my $feed (keys %feeds) { + my $t=$feeds{$feed}->{lastupdate}+$feeds{$feed}->{updateinterval}; + if (! defined $timestamp || $timestamp > $t) { + $timestamp=$t; + } + } + $newfile=~s/\.new$/time/; + open (OUT, ">", $newfile) || error("open $newfile: $!", $cleanup); + if (defined $timestamp) { + print OUT $timestamp."\n"; + } + close OUT || error("save $newfile: $!", $cleanup); +} + +sub garbage_collect () { + foreach my $name (keys %feeds) { + # remove any feeds that were not seen while building the pages + # that used to contain them + if ($feeds{$name}->{unseen}) { + delete $feeds{$name}; + } + } + + foreach my $guid (values %guids) { + # any guid whose feed is gone should be removed + if (! exists $feeds{$guid->{feed}}) { + if (exists $guid->{page}) { + unlink $IkiWiki::Plugin::transient::transientdir."/".htmlfn($guid->{page}) + || unlink "$config{srcdir}/".htmlfn($guid->{page}); + } + delete $guids{$guid->{guid}}; + } + # handle expired guids + elsif ($guid->{expired} && exists $guid->{page}) { + unlink "$config{srcdir}/".htmlfn($guid->{page}); + unlink $IkiWiki::Plugin::transient::transientdir."/".htmlfn($guid->{page}); + delete $guid->{page}; + delete $guid->{md5}; + } + } +} + +sub mergestate () { + # Load the current state in from disk, and merge into it + # values from the state in memory that might have changed + # during aggregation. + my %myfeeds=%feeds; + my %myguids=%guids; + clearstate(); + loadstate(); + + # All that can change in feed state during aggregation is a few + # fields. + foreach my $name (keys %myfeeds) { + if (exists $feeds{$name}) { + foreach my $field (qw{message lastupdate lasttry + numposts newposts error}) { + $feeds{$name}->{$field}=$myfeeds{$name}->{$field}; + } + } + } + + # New guids can be created during aggregation. + # Guids have a few fields that may be updated during aggregation. + # It's also possible that guids were removed from the on-disk state + # while the aggregation was in process. That would only happen if + # their feed was also removed, so any removed guids added back here + # will be garbage collected later. + foreach my $guid (keys %myguids) { + if (! exists $guids{$guid}) { + $guids{$guid}=$myguids{$guid}; + } + else { + foreach my $field (qw{md5}) { + $guids{$guid}->{$field}=$myguids{$guid}->{$field}; + } + } + } +} + +sub clearstate () { + %feeds=(); + %guids=(); + $state_loaded=0; +} + +sub expire () { + foreach my $feed (values %feeds) { + next unless $feed->{expireage} || $feed->{expirecount}; + my $count=0; + my %seen; + foreach my $item (sort { ($IkiWiki::pagectime{$b->{page}} || 0) <=> ($IkiWiki::pagectime{$a->{page}} || 0) } + grep { exists $_->{page} && $_->{feed} eq $feed->{name} } + values %guids) { + if ($feed->{expireage}) { + my $days_old = (time - ($IkiWiki::pagectime{$item->{page}} || 0)) / 60 / 60 / 24; + if ($days_old > $feed->{expireage}) { + debug(sprintf(gettext("expiring %s (%s days old)"), + $item->{page}, int($days_old))); + $item->{expired}=1; + } + } + elsif ($feed->{expirecount} && + $count >= $feed->{expirecount}) { + debug(sprintf(gettext("expiring %s"), $item->{page})); + $item->{expired}=1; + } + else { + if (! $seen{$item->{page}}) { + $seen{$item->{page}}=1; + $count++; + } + } + } + } +} + +sub needsaggregate () { + return values %feeds if $config{rebuild}; + return grep { time - $_->{lastupdate} >= $_->{updateinterval} } values %feeds; +} + +sub aggregate (@) { + eval q{use Net::INET6Glue::INET_is_INET6}; # may not be available + eval q{use XML::Feed}; + error($@) if $@; + eval q{use URI::Fetch}; + error($@) if $@; + + foreach my $feed (@_) { + $feed->{lasttry}=time; + $feed->{newposts}=0; + $feed->{message}=sprintf(gettext("last checked %s"), + displaytime($feed->{lasttry})); + $feed->{error}=0; + + debug(sprintf(gettext("checking feed %s ..."), $feed->{name})); + + if (! length $feed->{feedurl}) { + my @urls=XML::Feed->find_feeds($feed->{url}); + if (! @urls) { + $feed->{message}=sprintf(gettext("could not find feed at %s"), $feed->{url}); + $feed->{error}=1; + debug($feed->{message}); + next; + } + $feed->{feedurl}=pop @urls; + } + my $ua=useragent(); + my $res=URI::Fetch->fetch($feed->{feedurl}, UserAgent=>$ua); + if (! $res) { + $feed->{message}=URI::Fetch->errstr; + $feed->{error}=1; + debug($feed->{message}); + next; + } + + # lastupdate is only set if we were able to contact the server + $feed->{lastupdate}=$feed->{lasttry}; + + if ($res->status == URI::Fetch::URI_GONE()) { + $feed->{message}=gettext("feed not found"); + $feed->{error}=1; + debug($feed->{message}); + next; + } + my $content=$res->content; + my $f=eval{XML::Feed->parse(\$content)}; + if ($@) { + # One common cause of XML::Feed crashing is a feed + # that contains invalid UTF-8 sequences. Convert + # feed to ascii to try to work around. + $feed->{message}.=" ".sprintf(gettext("(invalid UTF-8 stripped from feed)")); + $f=eval { + $content=Encode::decode_utf8($content, 0); + XML::Feed->parse(\$content) + }; + } + if ($@) { + # Another possibility is badly escaped entities. + $feed->{message}.=" ".sprintf(gettext("(feed entities escaped)")); + $content=~s/\&(?!amp)(\w+);/&$1;/g; + $f=eval { + $content=Encode::decode_utf8($content, 0); + XML::Feed->parse(\$content) + }; + } + if ($@) { + # gettext can clobber $@ + my $error = $@; + $feed->{message}=gettext("feed crashed XML::Feed!")." ($error)"; + $feed->{error}=1; + debug($feed->{message}); + next; + } + if (! $f) { + $feed->{message}=XML::Feed->errstr; + $feed->{error}=1; + debug($feed->{message}); + next; + } + + foreach my $entry ($f->entries) { + # XML::Feed doesn't work around XML::Atom's bizarre + # API, so we will. Real unicode strings? Yes please. + # See [[bugs/Aggregated_Atom_feeds_are_double-encoded]] + local $XML::Atom::ForceUnicode = 1; + + my $c=$entry->content; + # atom feeds may have no content, only a summary + if (! defined $c && ref $entry->summary) { + $c=$entry->summary; + } + + add_page( + feed => $feed, + copyright => $f->copyright, + title => defined $entry->title ? decode_entities($entry->title) : "untitled", + author => defined $entry->author ? decode_entities($entry->author) : "", + link => $entry->link, + content => (defined $c && defined $c->body) ? $c->body : "", + guid => defined $entry->id ? $entry->id : time."_".$feed->{name}, + ctime => $entry->issued ? ($entry->issued->epoch || time) : time, + base => (defined $c && $c->can("base")) ? $c->base : undef, + ); + } + } +} + +sub add_page (@) { + my %params=@_; + + my $feed=$params{feed}; + my $guid={}; + my $mtime; + if (exists $guids{$params{guid}}) { + # updating an existing post + $guid=$guids{$params{guid}}; + return if $guid->{expired}; + write_page($feed, $guid, $mtime, \%params); + } + else { + # new post + $guid->{guid}=$params{guid}; + $guids{$params{guid}}=$guid; + $mtime=$params{ctime}; + $feed->{numposts}++; + $feed->{newposts}++; + + # assign it an unused page + my $page=titlepage($params{title}); + # escape slashes and periods in title so it doesn't specify + # directory name or trigger ".." disallowing code. + $page=~s!([/.])!"__".ord($1)."__"!eg; + $page=$feed->{dir}."/".$page; + ($page)=$page=~/$config{wiki_file_regexp}/; + if (! defined $page || ! length $page) { + $page=$feed->{dir}."/item"; + } + my $c=""; + while (exists $IkiWiki::pagecase{lc $page.$c} || + -e $IkiWiki::Plugin::transient::transientdir."/".htmlfn($page.$c) || + -e "$config{srcdir}/".htmlfn($page.$c)) { + $c++ + } + $page=$page.$c; + + $guid->{page}=$page; + eval { write_page($feed, $guid, $mtime, \%params) }; + if ($@) { + # assume failure was due to a too long filename + $c=""; + $page=$feed->{dir}."/item"; + while (exists $IkiWiki::pagecase{lc $page.$c} || + -e $IkiWiki::Plugin::transient::transientdir."/".htmlfn($page.$c) || + -e "$config{srcdir}/".htmlfn($page.$c)) { + $c++ + } + $page=$page.$c; + + $guid->{page}=$page; + write_page($feed, $guid, $mtime, \%params); + } + + debug(sprintf(gettext("creating new page %s"), $page)); + } +} + +sub write_page ($$$$$) { + my $feed=shift; + my $guid=shift; + my $mtime=shift; + my %params=%{shift()}; + + $guid->{feed}=$feed->{name}; + + # To write or not to write? Need to avoid writing unchanged pages + # to avoid unneccessary rebuilding. The mtime from rss cannot be + # trusted; let's use a digest. + eval q{use Digest::MD5 'md5_hex'}; + error($@) if $@; + require Encode; + my $digest=md5_hex(Encode::encode_utf8($params{content})); + return unless ! exists $guid->{md5} || $guid->{md5} ne $digest || $config{rebuild}; + $guid->{md5}=$digest; + + # Create the page. + my $template; + eval { + $template=template($feed->{template}, blind_cache => 1); + }; + if ($@) { + # gettext can clobber $@ + my $error = $@; + print STDERR gettext("failed to process template:")." $error"; + return; + } + $template->param(title => $params{title}) + if defined $params{title} && length($params{title}); + $template->param(author => $params{author}) + if defined $params{author} && length($params{author} + && $params{author} ne $feed->{name}); + $template->param(content => wikiescape(htmlabs($params{content}, + defined $params{base} ? $params{base} : $feed->{feedurl}))); + $template->param(name => $feed->{name}); + $template->param(url => $feed->{url}); + $template->param(copyright => $params{copyright}) + if defined $params{copyright} && length $params{copyright}; + $template->param(permalink => IkiWiki::urlabs($params{link}, $feed->{feedurl})) + if defined $params{link}; + if (ref $feed->{tags}) { + $template->param(tags => [map { tag => $_ }, @{$feed->{tags}}]); + } + writefile(htmlfn($guid->{page}), + $IkiWiki::Plugin::transient::transientdir, $template->output); + + if (defined $mtime && $mtime <= time) { + # Set the mtime, this lets the build process get the right + # creation time on record for the new page. + utime $mtime, $mtime, + $IkiWiki::Plugin::transient::transientdir."/".htmlfn($guid->{page}); + # Store it in pagectime for expiry code to use also. + $IkiWiki::pagectime{$guid->{page}}=$mtime + unless exists $IkiWiki::pagectime{$guid->{page}}; + } + else { + # Dummy value for expiry code. + $IkiWiki::pagectime{$guid->{page}}=time + unless exists $IkiWiki::pagectime{$guid->{page}}; + } +} + +sub wikiescape ($) { + # escape accidental wikilinks and preprocessor stuff + return encode_entities(shift, '\[\]'); +} + +sub htmlabs ($$) { + # Convert links in html from relative to absolute. + # Note that this is a heuristic, which is not specified by the rss + # spec and may not be right for all feeds. Also, see Debian + # bug #381359. + my $html=shift; + my $urlbase=shift; + + my $ret=""; + my $p = HTML::Parser->new(api_version => 3); + $p->handler(default => sub { $ret.=join("", @_) }, "text"); + $p->handler(start => sub { + my ($tagname, $pos, $text) = @_; + if (ref $HTML::Tagset::linkElements{$tagname}) { + while (4 <= @$pos) { + # use attribute sets from right to left + # to avoid invalidating the offsets + # when replacing the values + my($k_offset, $k_len, $v_offset, $v_len) = + splice(@$pos, -4); + my $attrname = lc(substr($text, $k_offset, $k_len)); + next unless grep { $_ eq $attrname } @{$HTML::Tagset::linkElements{$tagname}}; + next unless $v_offset; # 0 v_offset means no value + my $v = substr($text, $v_offset, $v_len); + $v =~ s/^([\'\"])(.*)\1$/$2/; + my $new_v=IkiWiki::urlabs($v, $urlbase); + $new_v =~ s/\"/"/g; # since we quote with "" + substr($text, $v_offset, $v_len) = qq("$new_v"); + } + } + $ret.=$text; + }, "tagname, tokenpos, text"); + $p->parse($html); + $p->eof; + + return $ret; +} + +sub htmlfn ($) { + return shift().".".($config{aggregateinternal} ? "_aggregated" : $config{htmlext}); +} + +my $aggregatelock; + +sub lockaggregate () { + # Take an exclusive lock to prevent multiple concurrent aggregators. + # Returns true if the lock was aquired. + if (! -d $config{wikistatedir}) { + mkdir($config{wikistatedir}); + } + open($aggregatelock, '>', "$config{wikistatedir}/aggregatelock") || + error ("cannot open to $config{wikistatedir}/aggregatelock: $!"); + if (! flock($aggregatelock, 2 | 4)) { # LOCK_EX | LOCK_NB + close($aggregatelock) || error("failed closing aggregatelock: $!"); + return 0; + } + return 1; +} + +sub unlockaggregate () { + return close($aggregatelock) if $aggregatelock; + return; +} + +1 diff --git a/IkiWiki/Plugin/amazon_s3.pm b/IkiWiki/Plugin/amazon_s3.pm new file mode 100644 index 000000000..a9da6bf12 --- /dev/null +++ b/IkiWiki/Plugin/amazon_s3.pm @@ -0,0 +1,257 @@ +#!/usr/bin/perl +package IkiWiki::Plugin::amazon_s3; + +use warnings; +no warnings 'redefine'; +use strict; +use IkiWiki 3.00; +use IkiWiki::Render; +use Net::Amazon::S3; + +# Store references to real subs before overriding them. +our %subs; +BEGIN { + foreach my $sub (qw{IkiWiki::writefile IkiWiki::prune}) { + $subs{$sub}=\&$sub; + } +}; + +sub import { + hook(type => "getopt", id => "amazon_s3", call => \&getopt); + hook(type => "getsetup", id => "amazon_s3", call => \&getsetup); + hook(type => "checkconfig", id => "amazon_s3", call => \&checkconfig); +} + +sub getopt () { + eval q{use Getopt::Long}; + error($@) if $@; + Getopt::Long::Configure('pass_through'); + GetOptions("delete-bucket" => sub { + my $bucket=getbucket(); + debug(gettext("deleting bucket..")); + my $resp = $bucket->list_all or die $bucket->err . ": " . $bucket->errstr; + foreach my $key (@{$resp->{keys}}) { + debug("\t".$key->{key}); + $bucket->delete_key($key->{key}) or die $bucket->err . ": " . $bucket->errstr; + } + $bucket->delete_bucket or die $bucket->err . ": " . $bucket->errstr; + debug(gettext("done")); + exit(0); + }); +} + +sub getsetup () { + return + plugin => { + safe => 0, + rebuild => 0, + }, + amazon_s3_key_id => { + type => "string", + example => "XXXXXXXXXXXXXXXXXXXX", + description => "public access key id", + safe => 1, + rebuild => 0, + }, + amazon_s3_key_id => { + type => "string", + example => "$ENV{HOME}/.s3_key", + description => "file holding secret key (must not be readable by others!)", + safe => 0, # ikiwiki reads this file + rebuild => 0, + }, + amazon_s3_bucket => { + type => "string", + example => "mywiki", + description => "globally unique name of bucket to store wiki in", + safe => 1, + rebuild => 1, + }, + amazon_s3_prefix => { + type => "string", + example => "wiki/", + description => "a prefix to prepend to each page name", + safe => 1, + rebuild => 1, + }, + amazon_s3_location => { + type => "string", + example => "EU", + description => "which S3 datacenter to use (leave blank for default)", + safe => 1, + rebuild => 1, + }, + amazon_s3_dupindex => { + type => "boolean", + example => 0, + description => "store each index file twice? (allows urls ending in \"/index.html\" and \"/\")", + safe => 1, + rebuild => 1, + }, +} + +sub checkconfig { + foreach my $field (qw{amazon_s3_key_id amazon_s3_key_file + amazon_s3_bucket}) { + if (! exists $config{$field} || ! defined $config{$field}) { + error(sprintf(gettext("Must specify %s"), $field)); + } + } + if (! exists $config{amazon_s3_prefix} || + ! defined $config{amazon_s3_prefix}) { + $config{amazon_s3_prefix}="wiki/"; + } +} + +{ +my $bucket; +sub getbucket { + return $bucket if defined $bucket; + + open(IN, "<", $config{amazon_s3_key_file}) || error($config{amazon_s3_key_file}.": ".$!); + my $key=; + chomp $key; + close IN; + + my $s3=Net::Amazon::S3->new({ + aws_access_key_id => $config{amazon_s3_key_id}, + aws_secret_access_key => $key, + retry => 1, + }); + + # make sure the bucket exists + if (exists $config{amazon_s3_location}) { + $bucket=$s3->add_bucket({ + bucket => $config{amazon_s3_bucket}, + location_constraint => $config{amazon_s3_location}, + }); + } + else { + $bucket=$s3->add_bucket({ + bucket => $config{amazon_s3_bucket}, + }); + } + + if (! $bucket) { + # Try to use existing bucket. + $bucket=$s3->bucket($config{amazon_s3_bucket}); + } + if (! $bucket) { + error(gettext("Failed to create S3 bucket: "). + $s3->err.": ".$s3->errstr."\n"); + } + + return $bucket; +} +} + +# Given a file, return any S3 keys associated with it. +sub file2keys ($) { + my $file=shift; + + my @keys; + if ($file =~ /^\Q$config{destdir}\/\E(.*)/) { + push @keys, $config{amazon_s3_prefix}.$1; + + # Munge foo/index.html to foo/ + if ($keys[0]=~/(^|.*\/)index.$config{htmlext}$/) { + # A duplicate might need to be stored under the + # unmunged name too. + if (!$config{usedirs} || $config{amazon_s3_dupindex}) { + push @keys, $1; + } + else { + @keys=($1); + } + } + } + return @keys; +} + +package IkiWiki; +use File::MimeInfo; +use Encode; + +# This is a wrapper around the real writefile. +sub writefile ($$$;$$) { + my $file=shift; + my $destdir=shift; + my $content=shift; + my $binary=shift; + my $writer=shift; + + # First, write the file to disk. + my $ret=$IkiWiki::Plugin::amazon_s3::subs{'IkiWiki::writefile'}->($file, $destdir, $content, $binary, $writer); + + my @keys=IkiWiki::Plugin::amazon_s3::file2keys("$destdir/$file"); + + # Store the data in S3. + if (@keys) { + my $bucket=IkiWiki::Plugin::amazon_s3::getbucket(); + + # The http layer tries to downgrade utf-8 + # content, but that can fail (see + # http://rt.cpan.org/Ticket/Display.html?id=35710), + # so force convert it to bytes. + $content=encode_utf8($content) if defined $content; + + my %opts=( + acl_short => 'public-read', + content_type => mimetype("$destdir/$file"), + ); + + # If there are multiple keys to write, data is sent + # multiple times. + # TODO: investigate using the new copy operation. + # (It may not be robust enough.) + foreach my $key (@keys) { + my $res; + if (! $writer) { + $res=$bucket->add_key($key, $content, \%opts); + } + else { + # This test for empty files is a workaround + # for this bug: + # http://rt.cpan.org//Ticket/Display.html?id=35731 + if (-z "$destdir/$file") { + $res=$bucket->add_key($key, "", \%opts); + } + else { + # read back in the file that the writer emitted + $res=$bucket->add_key_filename($key, "$destdir/$file", \%opts); + } + } + if (! $res) { + error(gettext("Failed to save file to S3: "). + $bucket->err.": ".$bucket->errstr."\n"); + } + } + } + + return $ret; +} + +# This is a wrapper around the real prune. +sub prune ($;$) { + my $file=shift; + my $up_to=shift; + + my @keys=IkiWiki::Plugin::amazon_s3::file2keys($file); + + # Prune files out of S3 too. + if (@keys) { + my $bucket=IkiWiki::Plugin::amazon_s3::getbucket(); + + foreach my $key (@keys) { + my $res=$bucket->delete_key($key); + if (! $res) { + error(gettext("Failed to delete file from S3: "). + $bucket->err.": ".$bucket->errstr."\n"); + } + } + } + + return $IkiWiki::Plugin::amazon_s3::subs{'IkiWiki::prune'}->($file, $up_to); +} + +1 diff --git a/IkiWiki/Plugin/anonok.pm b/IkiWiki/Plugin/anonok.pm new file mode 100644 index 000000000..0e74cbfad --- /dev/null +++ b/IkiWiki/Plugin/anonok.pm @@ -0,0 +1,51 @@ +#!/usr/bin/perl +package IkiWiki::Plugin::anonok; + +use warnings; +use strict; +use IkiWiki 3.00; + +sub import { + hook(type => "getsetup", id => "anonok", call => \&getsetup); + hook(type => "canedit", id => "anonok", call => \&canedit); +} + +sub getsetup () { + return + plugin => { + safe => 1, + rebuild => 0, + section => "auth", + }, + anonok_pagespec => { + type => "pagespec", + example => "*/discussion", + description => "PageSpec to limit which pages anonymous users can edit", + link => "ikiwiki/PageSpec", + safe => 1, + rebuild => 0, + }, +} + +sub canedit ($$$) { + my $page=shift; + my $cgi=shift; + my $session=shift; + + my $ret; + + if (exists $config{anonok_pagespec} && length $config{anonok_pagespec}) { + if (pagespec_match($page, $config{anonok_pagespec}, + location => $page)) { + return ""; + } + else { + return undef; + } + } + else { + return ""; + } +} + +1 diff --git a/IkiWiki/Plugin/attachment.pm b/IkiWiki/Plugin/attachment.pm new file mode 100644 index 000000000..d56dd18ad --- /dev/null +++ b/IkiWiki/Plugin/attachment.pm @@ -0,0 +1,395 @@ +#!/usr/bin/perl +package IkiWiki::Plugin::attachment; + +use warnings; +use strict; +use IkiWiki 3.00; + +sub import { + add_underlay("attachment"); + add_underlay("javascript"); + add_underlay("jquery"); + hook(type => "getsetup", id => "attachment", call => \&getsetup); + hook(type => "checkconfig", id => "attachment", call => \&checkconfig); + hook(type => "formbuilder_setup", id => "attachment", call => \&formbuilder_setup); + hook(type => "formbuilder", id => "attachment", call => \&formbuilder, last => 1); + IkiWiki::loadplugin("filecheck"); +} + +sub getsetup () { + return + plugin => { + safe => 1, + rebuild => 0, + section => "web", + }, + allowed_attachments => { + type => "pagespec", + example => "virusfree() and mimetype(image/*) and maxsize(50kb)", + description => "enhanced PageSpec specifying what attachments are allowed", + link => "ikiwiki/PageSpec/attachment", + safe => 1, + rebuild => 0, + }, + virus_checker => { + type => "string", + example => "clamdscan -", + description => "virus checker program (reads STDIN, returns nonzero if virus found)", + safe => 0, # executed + rebuild => 0, + }, +} + +sub check_canattach ($$;$) { + my $session=shift; + my $dest=shift; # where it's going to be put, under the srcdir + my $file=shift; # the path to the attachment currently + + # Don't allow an attachment to be uploaded with the same name as an + # existing page. + if (exists $IkiWiki::pagesources{$dest} && + $IkiWiki::pagesources{$dest} ne $dest) { + error(sprintf(gettext("there is already a page named %s"), $dest)); + } + + # Use a special pagespec to test that the attachment is valid. + my $allowed=1; + if (defined $config{allowed_attachments} && + length $config{allowed_attachments}) { + $allowed=pagespec_match($dest, + $config{allowed_attachments}, + file => $file, + user => $session->param("name"), + ip => $session->remote_addr(), + ); + } + + if (! $allowed) { + error(gettext("prohibited by allowed_attachments")." ($allowed)"); + } + else { + return 1; + } +} + +sub checkconfig () { + $config{cgi_disable_uploads}=0; +} + +sub formbuilder_setup (@) { + my %params=@_; + my $form=$params{form}; + my $q=$params{cgi}; + + if (defined $form->field("do") && ($form->field("do") eq "edit" || + $form->field("do") eq "create")) { + # Add attachment field, set type to multipart. + $form->enctype(&CGI::MULTIPART); + $form->field(name => 'attachment', type => 'file'); + # These buttons are not put in the usual place, so + # are not added to the normal formbuilder button list. + $form->tmpl_param("field-upload" => ''); + $form->tmpl_param("field-link" => ''); + + # Add all the javascript used by the attachments interface. + require IkiWiki::Plugin::toggle; + my $js=IkiWiki::Plugin::toggle::include_javascript($params{page}); + $js.=''."\n"; + my @jsfiles=qw{jquery.min jquery-ui.min + jquery.tmpl.min jquery.iframe-transport + jquery.fileupload jquery.fileupload-ui + }; + foreach my $file (@jsfiles) { + $js.=''."\n"; + } + $form->tmpl_param("javascript" => $js); + + # Start with the attachments interface toggled invisible, + # but if it was used, keep it open. + if ($form->submitted ne "Upload Attachment" && + (! defined $q->param("attachment_select") || + ! length $q->param("attachment_select"))) { + $form->tmpl_param("attachments-class" => "toggleable"); + } + else { + $form->tmpl_param("attachments-class" => "toggleable-open"); + } + + # Save attachments in holding area before previewing and + # saving. + if ($form->submitted eq "Preview" || + $form->submitted eq "Save Page") { + attachments_save($form, $params{session}); + } + } +} + +sub formbuilder (@) { + my %params=@_; + my $form=$params{form}; + my $q=$params{cgi}; + + return if ! defined $form->field("do") || ($form->field("do") ne "edit" && $form->field("do") ne "create") ; + + my $filename=Encode::decode_utf8($q->param('attachment')); + if (defined $filename && length $filename) { + attachment_store($filename, $form, $q, $params{session}); + } + + if ($form->submitted eq "Save Page") { + attachments_save($form, $params{session}); + } + + if ($form->submitted eq "Insert Links") { + my $page=quotemeta(Encode::decode_utf8($q->param("page"))); + my $add=""; + foreach my $f ($q->param("attachment_select")) { + $f=Encode::decode_utf8($f); + $f=~s/^$page\///; + if (IkiWiki::isinlinableimage($f) && + IkiWiki::Plugin::img->can("import")) { + $add.='[[!img '.$f.' align="right" size="" alt=""]]'; + } + else { + $add.="[[$f]]"; + } + $add.="\n"; + } + $form->field(name => 'editcontent', + value => $form->field('editcontent')."\n\n".$add, + force => 1) if length $add; + } + + # Generate the attachment list only after having added any new + # attachments. + $form->tmpl_param("attachment_list" => [attachment_list($form->field('page'))]); +} + +sub attachment_holding_location { + my $page=attachment_location(shift); + + my $dir=$config{wikistatedir}."/attachments/". + IkiWiki::possibly_foolish_untaint(linkpage($page)); + $dir=~s/\/$//; + return $dir; +} + +sub is_held_attachment { + my $attachment=shift; + + my $f=attachment_holding_location($attachment); + if (-f $f) { + return $f + } + else { + return undef; + } +} + +# Stores the attachment in a holding area, not yet in the wiki proper. +sub attachment_store { + my $filename=shift; + my $form=shift; + my $q=shift; + my $session=shift; + + # This is an (apparently undocumented) way to get the name + # of the temp file that CGI writes the upload to. + my $tempfile=$q->tmpFileName($filename); + if (! defined $tempfile || ! length $tempfile) { + # perl 5.8 needs an alternative, awful method + if ($q =~ /HASH/ && exists $q->{'.tmpfiles'}) { + foreach my $key (keys(%{$q->{'.tmpfiles'}})) { + $tempfile=$q->tmpFileName(\$key); + last if defined $tempfile && length $tempfile; + } + } + if (! defined $tempfile || ! length $tempfile) { + error("CGI::tmpFileName failed to return the uploaded file name"); + } + } + + $filename=IkiWiki::basename($filename); + $filename=~s/.*\\+(.+)/$1/; # hello, windows + $filename=IkiWiki::possibly_foolish_untaint(linkpage($filename)); + my $dest=attachment_holding_location($form->field('page')); + + # Check that the user is allowed to edit the attachment. + my $final_filename= + linkpage(IkiWiki::possibly_foolish_untaint( + attachment_location($form->field('page')))). + $filename; + eval { + if (IkiWiki::file_pruned($final_filename)) { + error(gettext("bad attachment filename")); + } + IkiWiki::check_canedit($final_filename, $q, $session); + # And that the attachment itself is acceptable. + check_canattach($session, $final_filename, $tempfile); + }; + if ($@) { + # save error in case called functions clobber $@ + my $error = $@; + json_response($q, $form, $dest."/".$filename, $error); + error $error; + } + + # Move the attachment into holding directory. + # Try to use a fast rename; fall back to copying. + IkiWiki::prep_writefile($filename, $dest); + unlink($dest."/".$filename); + if (rename($tempfile, $dest."/".$filename)) { + # The temp file has tight permissions; loosen up. + chmod(0666 & ~umask, $dest."/".$filename); + } + else { + my $fh=$q->upload('attachment'); + if (! defined $fh || ! ref $fh) { + # needed by old CGI versions + $fh=$q->param('attachment'); + if (! defined $fh || ! ref $fh) { + # even that doesn't always work, + # fall back to opening the tempfile + $fh=undef; + open($fh, "<", $tempfile) || error("failed to open \"$tempfile\": $!"); + } + } + binmode($fh); + require IkiWiki::Render; + writefile($filename, $dest, undef, 1, sub { + IkiWiki::fast_file_copy($tempfile, $filename, $fh, @_); + }); + } + + json_response($q, $form, $dest."/".$filename, stored_msg()); +} + +# Save all stored attachments for a page. +sub attachments_save { + my $form=shift; + my $session=shift; + + # Move attachments out of holding directory. + my @attachments; + my $dir=attachment_holding_location($form->field('page')); + foreach my $filename (glob("$dir/*")) { + $filename=Encode::decode_utf8($filename); + next unless -f $filename; + my $destdir=linkpage(IkiWiki::possibly_foolish_untaint( + attachment_location($form->field('page')))); + my $absdestdir=$config{srcdir}."/".$destdir; + my $destfile=IkiWiki::basename($filename); + my $dest=$absdestdir.$destfile; + unlink($dest); + IkiWiki::prep_writefile($destfile, $absdestdir); + rename($filename, $dest); + push @attachments, $destdir.$destfile; + } + return unless @attachments; + require IkiWiki::Render; + IkiWiki::prune($dir, $config{wikistatedir}."/attachments"); + + # Check the attachments in and trigger a wiki refresh. + if ($config{rcs}) { + IkiWiki::rcs_add($_) foreach @attachments; + IkiWiki::disable_commit_hook(); + IkiWiki::rcs_commit_staged( + message => gettext("attachment upload"), + session => $session, + ); + IkiWiki::enable_commit_hook(); + IkiWiki::rcs_update(); + } + IkiWiki::refresh(); + IkiWiki::saveindex(); +} + +sub attachment_location ($) { + my $page=shift; + + # Put the attachment in a subdir of the page it's attached + # to, unless that page is the "index" page. + return "" if $page eq 'index'; + $page.="/" if length $page; + + return $page; +} + +sub attachment_list ($) { + my $page=shift; + my $loc=attachment_location($page); + + my $std=sub { + my $file=shift; + my $mtime=shift; + my $date=shift; + my $size=shift; + + name => $file, + size => IkiWiki::Plugin::filecheck::humansize($size), + mtime => $date, + mtime_raw => $mtime, + }; + + # attachments already in the wiki + my %attachments; + foreach my $f (values %pagesources) { + if (! defined pagetype($f) && + $f=~m/^\Q$loc\E[^\/]+$/) { + $attachments{$f}={ + $std->($f, $IkiWiki::pagemtime{$f}, displaytime($IkiWiki::pagemtime{$f}), (stat($f))[7]), + link => htmllink($page, $page, $f, noimageinline => 1), + }; + } + } + + # attachments in holding directory + my $dir=attachment_holding_location($page); + my $heldmsg=gettext("this attachment is not yet saved"); + foreach my $file (glob("$dir/*")) { + $file=Encode::decode_utf8($file); + next unless -f $file; + my $base=IkiWiki::basename($file); + my $f=$loc.$base; + $attachments{$f}={ + $std->($f, (stat($file))[9]*2, stored_msg(), (stat(_))[7]), + link => $base, + } + } + + # Sort newer attachments to the end of the list. + return sort { $a->{mtime_raw} <=> $b->{mtime_raw} || $a->{link} cmp $b->{link} } + values %attachments; +} + +sub stored_msg { + gettext("just uploaded"); +} + +sub json_response ($$$$) { + my $q=shift; + my $form=shift; + my $filename=shift; + my $stored_msg=shift; + + if (! defined $form->submitted || + $form->submitted ne "Upload Attachment") { + eval q{use JSON}; + error $@ if $@; + print "Content-type: text/html\n\n"; + my $size=-s $filename; + print to_json([ + { + name => IkiWiki::basename($filename), + size => $size, + humansize => IkiWiki::Plugin::filecheck::humansize($size), + stored_msg => $stored_msg, + + } + ]); + exit 0; + } +} + +1 diff --git a/IkiWiki/Plugin/autoindex.pm b/IkiWiki/Plugin/autoindex.pm new file mode 100644 index 000000000..d5ee4b58f --- /dev/null +++ b/IkiWiki/Plugin/autoindex.pm @@ -0,0 +1,138 @@ +#!/usr/bin/perl +package IkiWiki::Plugin::autoindex; + +use warnings; +use strict; +use IkiWiki 3.00; +use Encode; + +sub import { + hook(type => "checkconfig", id => "autoindex", call => \&checkconfig); + hook(type => "getsetup", id => "autoindex", call => \&getsetup); + hook(type => "refresh", id => "autoindex", call => \&refresh); + IkiWiki::loadplugin("transient"); +} + +sub getsetup () { + return + plugin => { + safe => 1, + rebuild => 0, + }, + autoindex_commit => { + type => "boolean", + example => 1, + default => 1, + description => "commit autocreated index pages", + safe => 1, + rebuild => 0, + }, +} + +sub checkconfig () { + if (! defined $config{autoindex_commit}) { + $config{autoindex_commit} = 1; + } +} + +sub genindex ($) { + my $page=shift; + my $file=newpagefile($page, $config{default_pageext}); + + add_autofile($file, "autoindex", sub { + my $message = sprintf(gettext("creating index page %s"), + $page); + debug($message); + + my $dir = $config{srcdir}; + if (! $config{autoindex_commit}) { + $dir = $IkiWiki::Plugin::transient::transientdir; + } + + my $template = template("autoindex.tmpl"); + $template->param(page => $page); + writefile($file, $dir, $template->output); + + if ($config{rcs} && $config{autoindex_commit}) { + IkiWiki::disable_commit_hook(); + IkiWiki::rcs_add($file); + IkiWiki::rcs_commit_staged(message => $message); + IkiWiki::enable_commit_hook(); + } + }); +} + +sub refresh () { + eval q{use File::Find}; + error($@) if $@; + eval q{use Cwd}; + error($@) if $@; + my $origdir=getcwd(); + + my (%pages, %dirs); + foreach my $dir ($config{srcdir}, @{$config{underlaydirs}}, $config{underlaydir}) { + chdir($dir) || next; + + find({ + no_chdir => 1, + wanted => sub { + my $file=decode_utf8($_); + $file=~s/^\.\/?//; + return unless length $file; + if (IkiWiki::file_pruned($file)) { + $File::Find::prune=1; + } + elsif (! -l $_) { + my ($f) = $file =~ /$config{wiki_file_regexp}/; # untaint + return unless defined $f; + return if $f =~ /\._([^.]+)$/; # skip internal page + if (! -d _) { + $pages{pagename($f)}=1; + } + elsif ($dir eq $config{srcdir} || ! $config{autoindex_commit}) { + $dirs{$f}=1; + } + } + } + }, '.'); + + chdir($origdir) || die "chdir $origdir: $!"; + } + + # Compatibility code. + # + # {deleted} contains pages that have been deleted at some point. + # This plugin used to delete from the hash sometimes, but no longer + # does; in [[todo/autoindex_should_use_add__95__autofile]] Joey + # thought the old behaviour was probably a bug. + # + # The effect of listing a page in {deleted} was to avoid re-creating + # it; we migrate these pages to {autofile} which has the same effect. + # However, {autofile} contains source filenames whereas {deleted} + # contains page names. + my %deleted; + if (ref $wikistate{autoindex}{deleted}) { + %deleted=%{$wikistate{autoindex}{deleted}}; + delete $wikistate{autoindex}{deleted}; + } + elsif (ref $pagestate{index}{autoindex}{deleted}) { + # an even older version + %deleted=%{$pagestate{index}{autoindex}{deleted}}; + delete $pagestate{index}{autoindex}; + } + + if (keys %deleted) { + foreach my $dir (keys %deleted) { + my $file=newpagefile($dir, $config{default_pageext}); + $wikistate{autoindex}{autofile}{$file} = 1; + } + } + + foreach my $dir (keys %dirs) { + if (! exists $pages{$dir} && grep /^$dir\/.*/, keys %pages) { + genindex($dir); + } + } +} + +1 diff --git a/IkiWiki/Plugin/blogspam.pm b/IkiWiki/Plugin/blogspam.pm new file mode 100644 index 000000000..e48ed729f --- /dev/null +++ b/IkiWiki/Plugin/blogspam.pm @@ -0,0 +1,130 @@ +#!/usr/bin/perl +package IkiWiki::Plugin::blogspam; + +use warnings; +use strict; +use IkiWiki 3.00; +use Encode; + +my $defaulturl='http://test.blogspam.net:8888/'; + +sub import { + hook(type => "getsetup", id => "blogspam", call => \&getsetup); + hook(type => "checkconfig", id => "blogspam", call => \&checkconfig); + hook(type => "checkcontent", id => "blogspam", call => \&checkcontent); +} + +sub getsetup () { + return + plugin => { + safe => 1, + rebuild => 0, + section => "auth", + }, + blogspam_pagespec => { + type => 'pagespec', + example => 'postcomment(*)', + description => 'PageSpec of pages to check for spam', + link => 'ikiwiki/PageSpec', + safe => 1, + rebuild => 0, + }, + blogspam_options => { + type => "string", + example => "blacklist=1.2.3.4,blacklist=8.7.6.5,max-links=10", + description => "options to send to blogspam server", + link => "http://blogspam.net/api/testComment.html#options", + safe => 1, + rebuild => 0, + }, + blogspam_server => { + type => "string", + default => $defaulturl, + description => "blogspam server XML-RPC url", + safe => 1, + rebuild => 0, + }, +} + +sub checkconfig () { + # This is done at checkconfig time because printing an error + # if the module is missing when a spam is posted would not + # let the admin know about the problem. + eval q{ + use RPC::XML; + use RPC::XML::Client; + $RPC::XML::ENCODING = 'utf-8'; + }; + error $@ if $@; +} + +sub checkcontent (@) { + my %params=@_; + my $session=$params{session}; + + my $spec='!admin()'; + if (exists $config{blogspam_pagespec} && + length $config{blogspam_pagespec}) { + $spec.=" and (".$config{blogspam_pagespec}.")"; + } + + my $user=$session->param("name"); + return undef unless pagespec_match($params{page}, $spec, + (defined $user ? (user => $user) : ()), + (defined $session->remote_addr() ? (ip => $session->remote_addr()) : ()), + location => $params{page}); + + my $url=$defaulturl; + $url = $config{blogspam_server} if exists $config{blogspam_server}; + + my $client = RPC::XML::Client->new($url); + + my @options = split(",", $config{blogspam_options}) + if exists $config{blogspam_options}; + + # Allow short comments and whitespace-only edits, unless the user + # has overridden min-words themselves. + push @options, "min-words=0" + unless grep /^min-words=/i, @options; + # Wiki pages can have a lot of urls, unless the user specifically + # wants to limit them. + push @options, "exclude=lotsaurls" + unless grep /^max-links/i, @options; + # Unless the user specified a size check, disable such checking. + push @options, "exclude=size" + unless grep /^(?:max|min)-size/i, @options; + # This test has absurd false positives on words like "alpha" + # and "buy". + push @options, "exclude=stopwords"; + + my %req=( + ip => $session->remote_addr(), + comment => encode_utf8(defined $params{diff} ? $params{diff} : $params{content}), + subject => encode_utf8(defined $params{subject} ? $params{subject} : ""), + name => encode_utf8(defined $params{author} ? $params{author} : ""), + link => encode_utf8(exists $params{url} ? $params{url} : ""), + options => join(",", @options), + site => encode_utf8($config{url}), + version => "ikiwiki ".$IkiWiki::version, + ); + my $res = $client->send_request('testComment', \%req); + + if (! ref $res || ! defined $res->value) { + debug("failed to get response from blogspam server ($url)"); + return undef; + } + elsif ($res->value =~ /^SPAM:(.*)/) { + eval q{use Data::Dumper}; + debug("blogspam server reports ".$res->value.": ".Dumper(\%req)); + return gettext("Sorry, but that looks like spam to blogspam: ").$1; + } + elsif ($res->value ne 'OK') { + debug("blogspam server failure: ".$res->value); + return undef; + } + else { + return undef; + } +} + +1 diff --git a/IkiWiki/Plugin/brokenlinks.pm b/IkiWiki/Plugin/brokenlinks.pm new file mode 100644 index 000000000..8ee734bf9 --- /dev/null +++ b/IkiWiki/Plugin/brokenlinks.pm @@ -0,0 +1,56 @@ +#!/usr/bin/perl +# Provides a list of broken links. +package IkiWiki::Plugin::brokenlinks; + +use warnings; +use strict; +use IkiWiki 3.00; + +sub import { + hook(type => "getsetup", id => "brokenlinks", call => \&getsetup); + hook(type => "preprocess", id => "brokenlinks", call => \&preprocess); +} + +sub getsetup { + return + plugin => { + safe => 1, + rebuild => undef, + }, +} + +sub preprocess (@) { + my %params=@_; + $params{pages}="*" unless defined $params{pages}; + + my @broken; + foreach my $link (keys %IkiWiki::brokenlinks) { + next if $link =~ /.*\/\Q$config{discussionpage}\E/i && $config{discussion}; + + my @pages=pagespec_match_list($params{page}, $params{pages}, + list => $IkiWiki::brokenlinks{$link}, + # needs to update when links on a page change + deptype => deptype("links") + ); + next unless @pages; + + my $page=$IkiWiki::brokenlinks{$link}->[0]; + push @broken, sprintf(gettext("%s from %s"), + htmllink($page, $params{destpage}, $link, noimageinline => 1), + join(", ", map { + htmllink($params{page}, $params{destpage}, $_, noimageinline => 1) + } @pages) + ); + } + + return gettext("There are no broken links!") unless @broken; + return "
    \n" + .join("\n", + map { + "
  • $_
  • " + } + sort @broken) + ."
\n"; +} + +1 diff --git a/IkiWiki/Plugin/bzr.pm b/IkiWiki/Plugin/bzr.pm new file mode 100644 index 000000000..e2b102dee --- /dev/null +++ b/IkiWiki/Plugin/bzr.pm @@ -0,0 +1,330 @@ +#!/usr/bin/perl +package IkiWiki::Plugin::bzr; + +use warnings; +use strict; +use IkiWiki; +use Encode; +use URI::Escape q{uri_escape_utf8}; +use open qw{:utf8 :std}; + +sub import { + hook(type => "checkconfig", id => "bzr", call => \&checkconfig); + hook(type => "getsetup", id => "bzr", call => \&getsetup); + hook(type => "rcs", id => "rcs_update", call => \&rcs_update); + hook(type => "rcs", id => "rcs_prepedit", call => \&rcs_prepedit); + hook(type => "rcs", id => "rcs_commit", call => \&rcs_commit); + hook(type => "rcs", id => "rcs_commit_staged", call => \&rcs_commit_staged); + hook(type => "rcs", id => "rcs_add", call => \&rcs_add); + hook(type => "rcs", id => "rcs_remove", call => \&rcs_remove); + hook(type => "rcs", id => "rcs_rename", call => \&rcs_rename); + hook(type => "rcs", id => "rcs_recentchanges", call => \&rcs_recentchanges); + hook(type => "rcs", id => "rcs_diff", call => \&rcs_diff); + hook(type => "rcs", id => "rcs_getctime", call => \&rcs_getctime); + hook(type => "rcs", id => "rcs_getmtime", call => \&rcs_getmtime); +} + +sub checkconfig () { + if (defined $config{bzr_wrapper} && length $config{bzr_wrapper}) { + push @{$config{wrappers}}, { + wrapper => $config{bzr_wrapper}, + wrappermode => (defined $config{bzr_wrappermode} ? $config{bzr_wrappermode} : "06755"), + }; + } +} + +sub getsetup () { + return + plugin => { + safe => 0, # rcs plugin + rebuild => undef, + section => "rcs", + }, + bzr_wrapper => { + type => "string", + #example => "", # FIXME add example + description => "bzr post-commit hook to generate", + safe => 0, # file + rebuild => 0, + }, + bzr_wrappermode => { + type => "string", + example => '06755', + description => "mode for bzr_wrapper (can safely be made suid)", + safe => 0, + rebuild => 0, + }, + historyurl => { + type => "string", + #example => "", # FIXME add example + description => "url to show file history, using loggerhead ([[file]] substituted)", + safe => 1, + rebuild => 1, + }, + diffurl => { + type => "string", + example => "http://example.com/revision?start_revid=[[r2]]#[[file]]-s", + description => "url to view a diff, using loggerhead ([[file]] and [[r2]] substituted)", + safe => 1, + rebuild => 1, + }, +} + +sub bzr_log ($) { + my $out = shift; + my @infos = (); + my $key = undef; + + my %info; + while (<$out>) { + my $line = $_; + my ($value); + if ($line =~ /^message:/) { + $key = "message"; + $info{$key} = ""; + } + elsif ($line =~ /^(modified|added|renamed|renamed and modified|removed):/) { + $key = "files"; + $info{$key} = "" unless defined $info{$key}; + } + elsif (defined($key) and $line =~ /^ (.*)/) { + $info{$key} .= "$1\n"; + } + elsif ($line eq "------------------------------------------------------------\n") { + push @infos, {%info} if keys %info; + %info = (); + $key = undef; + } + elsif ($line =~ /: /) { + chomp $line; + if ($line =~ /^revno: (\d+)/) { + $key = "revno"; + $value = $1; + } + else { + ($key, $value) = split /: +/, $line, 2; + } + $info{$key} = $value; + } + } + close $out; + push @infos, {%info} if keys %info; + + return @infos; +} + +sub rcs_update () { + my @cmdline = ("bzr", "update", "--quiet", $config{srcdir}); + if (system(@cmdline) != 0) { + warn "'@cmdline' failed: $!"; + } +} + +sub rcs_prepedit ($) { + return ""; +} + +sub bzr_author ($) { + my $session=shift; + + return unless defined $session; + + my $user=$session->param("name"); + my $ipaddr=$session->remote_addr(); + + if (defined $user) { + return IkiWiki::possibly_foolish_untaint($user); + } + elsif (defined $ipaddr) { + return "Anonymous from ".IkiWiki::possibly_foolish_untaint($ipaddr); + } + else { + return "Anonymous"; + } +} + +sub rcs_commit (@) { + my %params=@_; + + my $user=bzr_author($params{session}); + + $params{message} = IkiWiki::possibly_foolish_untaint($params{message}); + if (! length $params{message}) { + $params{message} = "no message given"; + } + + my @cmdline = ("bzr", "commit", "--quiet", "-m", $params{message}, + (defined $user ? ("--author", $user) : ()), + $config{srcdir}."/".$params{file}); + if (system(@cmdline) != 0) { + warn "'@cmdline' failed: $!"; + } + + return undef; # success +} + +sub rcs_commit_staged (@) { + my %params=@_; + + my $user=bzr_author($params{session}); + + $params{message} = IkiWiki::possibly_foolish_untaint($params{message}); + if (! length $params{message}) { + $params{message} = "no message given"; + } + + my @cmdline = ("bzr", "commit", "--quiet", "-m", $params{message}, + (defined $user ? ("--author", $user) : ()), + $config{srcdir}); + if (system(@cmdline) != 0) { + warn "'@cmdline' failed: $!"; + } + + return undef; # success +} + +sub rcs_add ($) { + my ($file) = @_; + + my @cmdline = ("bzr", "add", "--quiet", "$config{srcdir}/$file"); + if (system(@cmdline) != 0) { + warn "'@cmdline' failed: $!"; + } +} + +sub rcs_remove ($) { + my ($file) = @_; + + my @cmdline = ("bzr", "rm", "--quiet", "$config{srcdir}/$file"); + if (system(@cmdline) != 0) { + warn "'@cmdline' failed: $!"; + } +} + +sub rcs_rename ($$) { + my ($src, $dest) = @_; + + my $parent = IkiWiki::dirname($dest); + if (system("bzr", "add", "--quiet", "$config{srcdir}/$parent") != 0) { + warn("bzr add $parent failed\n"); + } + + my @cmdline = ("bzr", "mv", "--quiet", "$config{srcdir}/$src", "$config{srcdir}/$dest"); + if (system(@cmdline) != 0) { + warn "'@cmdline' failed: $!"; + } +} + +sub rcs_recentchanges ($) { + my ($num) = @_; + + my @cmdline = ("bzr", "log", "-v", "--show-ids", "--limit", $num, + $config{srcdir}); + open (my $out, "@cmdline |"); + + eval q{use Date::Parse}; + error($@) if $@; + + my @ret; + foreach my $info (bzr_log($out)) { + my @pages = (); + my @message = (); + + foreach my $msgline (split(/\n/, $info->{message})) { + push @message, { line => $msgline }; + } + + foreach my $file (split(/\n/, $info->{files})) { + my ($filename, $fileid) = ($file =~ /^(.*?) +([^ ]+)$/); + + # Skip directories + next if ($filename =~ /\/$/); + + # Skip source name in renames + $filename =~ s/^.* => //; + + my $efilename = uri_escape_utf8($filename); + + my $diffurl = defined $config{'diffurl'} ? $config{'diffurl'} : ""; + $diffurl =~ s/\[\[file\]\]/$efilename/go; + $diffurl =~ s/\[\[file-id\]\]/$fileid/go; + $diffurl =~ s/\[\[r2\]\]/$info->{revno}/go; + + push @pages, { + page => pagename($filename), + diffurl => $diffurl, + }; + } + + my $user = $info->{"committer"}; + if (defined($info->{"author"})) { $user = $info->{"author"}; } + $user =~ s/\s*<.*>\s*$//; + $user =~ s/^\s*//; + + push @ret, { + rev => $info->{"revno"}, + user => $user, + committype => "bzr", + when => str2time($info->{"timestamp"}), + message => [@message], + pages => [@pages], + }; + } + + return @ret; +} + +sub rcs_diff ($;$) { + my $taintedrev=shift; + my $maxlines=shift; + my ($rev) = $taintedrev =~ /^(\d+(\.\d+)*)$/; # untaint + + my $prevspec = "before:" . $rev; + my $revspec = "revno:" . $rev; + my @cmdline = ("bzr", "diff", "--old", $config{srcdir}, + "--new", $config{srcdir}, + "-r", $prevspec . ".." . $revspec); + open (my $out, "@cmdline |"); + my @lines; + while (my $line=<$out>) { + last if defined $maxlines && @lines == $maxlines; + push @lines, $line; + } + if (wantarray) { + return @lines; + } + else { + return join("", @lines); + } +} + +sub extract_timestamp (@) { + open (my $out, "-|", @_); + my @log = bzr_log($out); + + if (length(scalar(@log)) < 1) { + return 0; + } + + eval q{use Date::Parse}; + error($@) if $@; + + my $time = str2time($log[0]->{"timestamp"}); + return $time; +} + +sub rcs_getctime ($) { + my ($file) = @_; + + my @cmdline = ("bzr", "log", "--forward", "--limit", '1', "$config{srcdir}/$file"); + return extract_timestamp(@cmdline); +} + +sub rcs_getmtime ($) { + my ($file) = @_; + + my @cmdline = ("bzr", "log", "--limit", '1', "$config{srcdir}/$file"); + return extract_timestamp(@cmdline); +} + +1 diff --git a/IkiWiki/Plugin/calendar.pm b/IkiWiki/Plugin/calendar.pm new file mode 100644 index 000000000..682bfb6fb --- /dev/null +++ b/IkiWiki/Plugin/calendar.pm @@ -0,0 +1,514 @@ +#! /usr/bin/perl +# Copyright (c) 2006, 2007 Manoj Srivastava +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + +require 5.002; +package IkiWiki::Plugin::calendar; + +use warnings; +use strict; +use IkiWiki 3.00; +use Time::Local; + +my $time=time; +my @now=localtime($time); + +sub import { + hook(type => "getsetup", id => "calendar", call => \&getsetup); + hook(type => "needsbuild", id => "calendar", call => \&needsbuild); + hook(type => "preprocess", id => "calendar", call => \&preprocess); +} + +sub getsetup () { + return + plugin => { + safe => 1, + rebuild => undef, + section => "widget", + }, + archivebase => { + type => "string", + example => "archives", + description => "base of the archives hierarchy", + safe => 1, + rebuild => 1, + }, + archive_pagespec => { + type => "pagespec", + example => "page(posts/*) and !*/Discussion", + description => "PageSpec of pages to include in the archives; used by ikiwiki-calendar command", + link => 'ikiwiki/PageSpec', + safe => 1, + rebuild => 0, + }, +} + +sub is_leap_year (@) { + my %params=@_; + return ($params{year} % 4 == 0 && (($params{year} % 100 != 0) || $params{year} % 400 == 0)); +} + +sub month_days { + my %params=@_; + my $days_in_month = (31,28,31,30,31,30,31,31,30,31,30,31)[$params{month}-1]; + if ($params{month} == 2 && is_leap_year(%params)) { + $days_in_month++; + } + return $days_in_month; +} + +sub format_month (@) { + my %params=@_; + + my %linkcache; + foreach my $p (pagespec_match_list($params{page}, + "creation_year($params{year}) and creation_month($params{month}) and ($params{pages})", + # add presence dependencies to update + # month calendar when pages are added/removed + deptype => deptype("presence"))) { + my $mtime = $IkiWiki::pagectime{$p}; + my @date = localtime($mtime); + my $mday = $date[3]; + my $month = $date[4] + 1; + my $year = $date[5] + 1900; + my $mtag = sprintf("%02d", $month); + + if (! $linkcache{"$year/$mtag/$mday"}) { + $linkcache{"$year/$mtag/$mday"} = []; + } + push(@{$linkcache{"$year/$mtag/$mday"}}, $p); + } + + my $pmonth = $params{month} - 1; + my $nmonth = $params{month} + 1; + my $pyear = $params{year}; + my $nyear = $params{year}; + + # Adjust for January and December + if ($params{month} == 1) { + $pmonth = 12; + $pyear--; + } + if ($params{month} == 12) { + $nmonth = 1; + $nyear++; + } + + # Add padding. + $pmonth=sprintf("%02d", $pmonth); + $nmonth=sprintf("%02d", $nmonth); + + my $calendar="\n"; + + # When did this month start? + my @monthstart = localtime(timelocal(0,0,0,1,$params{month}-1,$params{year}-1900)); + + my $future_dom = 0; + my $today = 0; + if ($params{year} == $now[5]+1900 && $params{month} == $now[4]+1) { + $future_dom = $now[3]+1; + $today = $now[3]; + } + + # Find out month names for this, next, and previous months + my $monthabbrev=strftime_utf8("%b", @monthstart); + my $monthname=strftime_utf8("%B", @monthstart); + my $pmonthname=strftime_utf8("%B", localtime(timelocal(0,0,0,1,$pmonth-1,$pyear-1900))); + my $nmonthname=strftime_utf8("%B", localtime(timelocal(0,0,0,1,$nmonth-1,$nyear-1900))); + + my $archivebase = 'archives'; + $archivebase = $config{archivebase} if defined $config{archivebase}; + $archivebase = $params{archivebase} if defined $params{archivebase}; + + # Calculate URL's for monthly archives. + my ($url, $purl, $nurl)=("$monthname $params{year}",'',''); + if (exists $pagesources{"$archivebase/$params{year}/$params{month}"}) { + $url = htmllink($params{page}, $params{destpage}, + "$archivebase/$params{year}/".$params{month}, + noimageinline => 1, + linktext => "$monthabbrev $params{year}", + title => $monthname); + } + add_depends($params{page}, "$archivebase/$params{year}/$params{month}", + deptype("presence")); + if (exists $pagesources{"$archivebase/$pyear/$pmonth"}) { + $purl = htmllink($params{page}, $params{destpage}, + "$archivebase/$pyear/$pmonth", + noimageinline => 1, + linktext => "\←", + title => $pmonthname); + } + add_depends($params{page}, "$archivebase/$pyear/$pmonth", + deptype("presence")); + if (exists $pagesources{"$archivebase/$nyear/$nmonth"}) { + $nurl = htmllink($params{page}, $params{destpage}, + "$archivebase/$nyear/$nmonth", + noimageinline => 1, + linktext => "\→", + title => $nmonthname); + } + add_depends($params{page}, "$archivebase/$nyear/$nmonth", + deptype("presence")); + + # Start producing the month calendar + $calendar=< + + $purl + $url + $nurl + + +EOF + + # Suppose we want to start the week with day $week_start_day + # If $monthstart[6] == 1 + my $week_start_day = $params{week_start_day}; + + my $start_day = 1 + (7 - $monthstart[6] + $week_start_day) % 7; + my %downame; + my %dowabbr; + for my $dow ($week_start_day..$week_start_day+6) { + my @day=localtime(timelocal(0,0,0,$start_day++,$params{month}-1,$params{year}-1900)); + my $downame = strftime_utf8("%A", @day); + my $dowabbr = substr($downame, 0, 1); + $downame{$dow % 7}=$downame; + $dowabbr{$dow % 7}=$dowabbr; + $calendar.= qq{\t\t$dowabbr\n}; + } + + $calendar.=< +EOF + + my $wday; + # we start with a week_start_day, and skip until we get to the first + for ($wday=$week_start_day; $wday != $monthstart[6]; $wday++, $wday %= 7) { + $calendar.=qq{\t\n} if $wday == $week_start_day; + $calendar.=qq{\t\t \n}; + } + + # At this point, either the first is a week_start_day, in which case + # nothing has been printed, or else we are in the middle of a row. + for (my $day = 1; $day <= month_days(year => $params{year}, month => $params{month}); + $day++, $wday++, $wday %= 7) { + # At this point, on a week_start_day, we close out a row, + # and start a new one -- unless it is week_start_day on the + # first, where we do not close a row -- since none was started. + if ($wday == $week_start_day) { + $calendar.=qq{\t\n} unless $day == 1; + $calendar.=qq{\t\n}; + } + + my $tag; + my $key="$params{year}/$params{month}/$day"; + if (defined $linkcache{$key}) { + if ($day == $today) { + $tag='month-calendar-day-this-day'; + } + else { + $tag='month-calendar-day-link'; + } + $calendar.=qq{\t\t}; + $calendar.=qq{}; + $calendar.=qq{\n}; + } + else { + if ($day == $today) { + $tag='month-calendar-day-this-day'; + } + elsif ($day == $future_dom) { + $tag='month-calendar-day-future'; + } + else { + $tag='month-calendar-day-nolink'; + } + $calendar.=qq{\t\t$day\n}; + } + } + + # finish off the week + for (; $wday != $week_start_day; $wday++, $wday %= 7) { + $calendar.=qq{\t\t \n}; + } + $calendar.=< + +EOF + + return $calendar; +} + +sub format_year (@) { + my %params=@_; + + my @post_months; + foreach my $p (pagespec_match_list($params{page}, + "creation_year($params{year}) and ($params{pages})", + # add presence dependencies to update + # year calendar's links to months when + # pages are added/removed + deptype => deptype("presence"))) { + my $mtime = $IkiWiki::pagectime{$p}; + my @date = localtime($mtime); + my $month = $date[4] + 1; + + $post_months[$month]++; + } + + my $calendar="\n"; + + my $pyear = $params{year} - 1; + my $nyear = $params{year} + 1; + + my $thisyear = $now[5]+1900; + my $future_month = 0; + $future_month = $now[4]+1 if $params{year} == $thisyear; + + my $archivebase = 'archives'; + $archivebase = $config{archivebase} if defined $config{archivebase}; + $archivebase = $params{archivebase} if defined $params{archivebase}; + + # calculate URL's for previous and next years + my ($url, $purl, $nurl)=("$params{year}",'',''); + if (exists $pagesources{"$archivebase/$params{year}"}) { + $url = htmllink($params{page}, $params{destpage}, + "$archivebase/$params{year}", + noimageinline => 1, + linktext => $params{year}, + title => $params{year}); + } + add_depends($params{page}, "$archivebase/$params{year}", deptype("presence")); + if (exists $pagesources{"$archivebase/$pyear"}) { + $purl = htmllink($params{page}, $params{destpage}, + "$archivebase/$pyear", + noimageinline => 1, + linktext => "\←", + title => $pyear); + } + add_depends($params{page}, "$archivebase/$pyear", deptype("presence")); + if (exists $pagesources{"$archivebase/$nyear"}) { + $nurl = htmllink($params{page}, $params{destpage}, + "$archivebase/$nyear", + noimageinline => 1, + linktext => "\→", + title => $nyear); + } + add_depends($params{page}, "$archivebase/$nyear", deptype("presence")); + + # Start producing the year calendar + my $m=$params{months_per_row}-2; + $calendar=< + + $purl + $url + $nurl + + + Months + +EOF + + for (my $month = 1; $month <= 12; $month++) { + my @day=localtime(timelocal(0,0,0,15,$month-1,$params{year}-1900)); + my $murl; + my $monthname = strftime_utf8("%B", @day); + my $monthabbr = strftime_utf8("%b", @day); + $calendar.=qq{\t\n} if ($month % $params{months_per_row} == 1); + my $tag; + my $mtag=sprintf("%02d", $month); + if ($month == $params{month} && $thisyear == $params{year}) { + $tag = 'year-calendar-this-month'; + } + elsif ($pagesources{"$archivebase/$params{year}/$mtag"}) { + $tag = 'year-calendar-month-link'; + } + elsif ($future_month && $month >= $future_month) { + $tag = 'year-calendar-month-future'; + } + else { + $tag = 'year-calendar-month-nolink'; + } + + if ($pagesources{"$archivebase/$params{year}/$mtag"} && + $post_months[$mtag]) { + $murl = htmllink($params{page}, $params{destpage}, + "$archivebase/$params{year}/$mtag", + noimageinline => 1, + linktext => $monthabbr, + title => $monthname); + $calendar.=qq{\t}; + $calendar.=$murl; + $calendar.=qq{\t\n}; + } + else { + $calendar.=qq{\t$monthabbr\n}; + } + add_depends($params{page}, "$archivebase/$params{year}/$mtag", + deptype("presence")); + + $calendar.=qq{\t\n} if ($month % $params{months_per_row} == 0); + } + + $calendar.=< +EOF + + return $calendar; +} + +sub setnextchange ($$) { + my $page=shift; + my $timestamp=shift; + + if (! exists $pagestate{$page}{calendar}{nextchange} || + $pagestate{$page}{calendar}{nextchange} > $timestamp) { + $pagestate{$page}{calendar}{nextchange}=$timestamp; + } +} + +sub preprocess (@) { + my %params=@_; + + my $thisyear=1900 + $now[5]; + my $thismonth=1 + $now[4]; + + $params{pages} = "*" unless defined $params{pages}; + $params{type} = "month" unless defined $params{type}; + $params{week_start_day} = 0 unless defined $params{week_start_day}; + $params{months_per_row} = 3 unless defined $params{months_per_row}; + $params{year} = $thisyear unless defined $params{year}; + $params{month} = $thismonth unless defined $params{month}; + + my $relativeyear=0; + if ($params{year} < 1) { + $relativeyear=1; + $params{year}=$thisyear+$params{year}; + } + my $relativemonth=0; + if ($params{month} < 1) { + $relativemonth=1; + my $monthoff=$params{month}; + $params{month}=($thismonth+$monthoff) % 12; + $params{month}=12 if $params{month}==0; + my $yearoff=POSIX::ceil(($thismonth-$params{month}) / -12) + - int($monthoff / 12); + $params{year}-=$yearoff; + } + + $params{month} = sprintf("%02d", $params{month}); + + if ($params{type} eq 'month' && $params{year} == $thisyear + && $params{month} == $thismonth) { + # calendar for current month, updates next midnight + setnextchange($params{destpage}, ($time + + (60 - $now[0]) # seconds + + (59 - $now[1]) * 60 # minutes + + (23 - $now[2]) * 60 * 60 # hours + )); + } + elsif ($params{type} eq 'month' && + (($params{year} == $thisyear && $params{month} > $thismonth) || + $params{year} > $thisyear)) { + # calendar for upcoming month, updates 1st of that month + setnextchange($params{destpage}, + timelocal(0, 0, 0, 1, $params{month}-1, $params{year})); + } + elsif (($params{type} eq 'year' && $params{year} == $thisyear) || + $relativemonth) { + # Calendar for current year updates 1st of next month. + # Any calendar relative to the current month also updates + # then. + if ($thismonth < 12) { + setnextchange($params{destpage}, + timelocal(0, 0, 0, 1, $thismonth+1-1, $params{year})); + } + else { + setnextchange($params{destpage}, + timelocal(0, 0, 0, 1, 1-1, $params{year}+1)); + } + } + elsif ($relativeyear) { + # Any calendar relative to the current year updates 1st + # of next year. + setnextchange($params{destpage}, + timelocal(0, 0, 0, 1, 1-1, $thisyear+1)); + } + elsif ($params{type} eq 'year' && $params{year} > $thisyear) { + # calendar for upcoming year, updates 1st of that year + setnextchange($params{destpage}, + timelocal(0, 0, 0, 1, 1-1, $params{year})); + } + else { + # calendar for past month or year, does not need + # to update any more + delete $pagestate{$params{destpage}}{calendar}; + } + + my $calendar=""; + if ($params{type} eq 'month') { + $calendar=format_month(%params); + } + elsif ($params{type} eq 'year') { + $calendar=format_year(%params); + } + + return "\n
$calendar
\n"; +} #}} + +sub needsbuild (@) { + my $needsbuild=shift; + foreach my $page (keys %pagestate) { + if (exists $pagestate{$page}{calendar}{nextchange}) { + if ($pagestate{$page}{calendar}{nextchange} <= $time) { + # force a rebuild so the calendar shows + # the current day + push @$needsbuild, $pagesources{$page}; + } + if (exists $pagesources{$page} && + grep { $_ eq $pagesources{$page} } @$needsbuild) { + # remove state, will be re-added if + # the calendar is still there during the + # rebuild + delete $pagestate{$page}{calendar}; + } + } + } + return $needsbuild; +} + +1 diff --git a/IkiWiki/Plugin/camelcase.pm b/IkiWiki/Plugin/camelcase.pm new file mode 100644 index 000000000..088447d6b --- /dev/null +++ b/IkiWiki/Plugin/camelcase.pm @@ -0,0 +1,73 @@ +#!/usr/bin/perl +# CamelCase links +package IkiWiki::Plugin::camelcase; + +use warnings; +use strict; +use IkiWiki 3.00; + +# This regexp is based on the one in Text::WikiFormat. +my $link_regexp=qr{ + (? "getsetup", id => "camelcase", call => \&getsetup); + hook(type => "linkify", id => "camelcase", call => \&linkify); + hook(type => "scan", id => "camelcase", call => \&scan); +} + +sub getsetup () { + return + plugin => { + safe => 1, + rebuild => undef, + }, + camelcase_ignore => { + type => "string", + example => [], + description => "list of words to not turn into links", + safe => 1, + rebuild => undef, # might change links + }, +} + +sub linkify (@) { + my %params=@_; + my $page=$params{page}; + my $destpage=$params{destpage}; + + $params{content}=~s{$link_regexp}{ + ignored($1) ? $1 : htmllink($page, $destpage, linkpage($1)) + }eg; + + return $params{content}; +} + +sub scan (@) { + my %params=@_; + my $page=$params{page}; + my $content=$params{content}; + + while ($content =~ /$link_regexp/g) { + add_link($page, linkpage($1)) unless ignored($1) + } +} + +sub ignored ($) { + my $word=lc shift; + grep { $word eq lc $_ } @{$config{'camelcase_ignore'}} +} + +1 diff --git a/IkiWiki/Plugin/color.pm b/IkiWiki/Plugin/color.pm new file mode 100644 index 000000000..9bb2359ce --- /dev/null +++ b/IkiWiki/Plugin/color.pm @@ -0,0 +1,78 @@ +#!/usr/bin/perl +# Ikiwiki text colouring plugin +# Paweł‚ Tęcza +package IkiWiki::Plugin::color; + +use warnings; +use strict; +use IkiWiki 3.00; + +sub import { + hook(type => "preprocess", id => "color", call => \&preprocess); + hook(type => "format", id => "color", call => \&format); + hook(type => "getsetup", id => "color", call => \&getsetup); +} + +sub getsetup () { + return + plugin => { + safe => 1, + rebuild => undef, + section => "widget", + }, +} + +sub preserve_style ($$$) { + my $foreground = shift; + my $background = shift; + my $text = shift; + + $foreground = defined $foreground ? lc($foreground) : ''; + $background = defined $background ? lc($background) : ''; + $text = '' unless (defined $text); + + # Validate colors. Only color name or color code are valid. + $foreground = '' unless ($foreground && + ($foreground =~ /^[a-z]+$/ || $foreground =~ /^#[0-9a-f]{3,6}$/)); + $background = '' unless ($background && + ($background =~ /^[a-z]+$/ || $background =~ /^#[0-9a-f]{3,6}$/)); + + my $preserved = ''; + $preserved .= ''; + $preserved .= 'color: '.$foreground if ($foreground); + $preserved .= '; ' if ($foreground && $background); + $preserved .= 'background-color: '.$background if ($background); + $preserved .= ''; + $preserved .= ''.$text.''; + + return $preserved; + +} + +sub replace_preserved_style ($) { + my $content = shift; + + $content =~ s!((color: ([a-z]+|\#[0-9a-f]{3,6})?)?((; )?(background-color: ([a-z]+|\#[0-9a-f]{3,6})?)?)?)!!g; + $content =~ s!!!g; + + return $content; +} + +sub preprocess (@) { + my %params = @_; + + return preserve_style($params{foreground}, $params{background}, + # Preprocess the text to expand any preprocessor directives + # embedded inside it. + IkiWiki::preprocess($params{page}, $params{destpage}, + $params{text})); +} + +sub format (@) { + my %params = @_; + + $params{content} = replace_preserved_style($params{content}); + return $params{content}; +} + +1 diff --git a/IkiWiki/Plugin/comments.pm b/IkiWiki/Plugin/comments.pm new file mode 100644 index 000000000..98ae13810 --- /dev/null +++ b/IkiWiki/Plugin/comments.pm @@ -0,0 +1,1088 @@ +#!/usr/bin/perl +# Copyright © 2006-2008 Joey Hess +# Copyright © 2008 Simon McVittie +# Licensed under the GNU GPL, version 2, or any later version published by the +# Free Software Foundation +package IkiWiki::Plugin::comments; + +use warnings; +use strict; +use IkiWiki 3.00; +use Encode; + +use constant PREVIEW => "Preview"; +use constant POST_COMMENT => "Post comment"; +use constant CANCEL => "Cancel"; + +my $postcomment; +my %commentstate; + +sub import { + hook(type => "checkconfig", id => 'comments', call => \&checkconfig); + hook(type => "getsetup", id => 'comments', call => \&getsetup); + hook(type => "preprocess", id => 'comment', call => \&preprocess, + scan => 1); + hook(type => "preprocess", id => 'commentmoderation', call => \&preprocess_moderation); + # here for backwards compatability with old comments + hook(type => "preprocess", id => '_comment', call => \&preprocess); + hook(type => "sessioncgi", id => 'comment', call => \&sessioncgi); + hook(type => "htmlize", id => "_comment", call => \&htmlize); + hook(type => "htmlize", id => "_comment_pending", + call => \&htmlize_pending); + hook(type => "pagetemplate", id => "comments", call => \&pagetemplate); + hook(type => "formbuilder_setup", id => "comments", + call => \&formbuilder_setup); + # Load goto to fix up user page links for logged-in commenters + IkiWiki::loadplugin("goto"); + IkiWiki::loadplugin("inline"); + IkiWiki::loadplugin("transient"); +} + +sub getsetup () { + return + plugin => { + safe => 1, + rebuild => 1, + section => "web", + }, + comments_pagespec => { + type => 'pagespec', + example => 'blog/* and !*/Discussion', + description => 'PageSpec of pages where comments are allowed', + link => 'ikiwiki/PageSpec', + safe => 1, + rebuild => 1, + }, + comments_closed_pagespec => { + type => 'pagespec', + example => 'blog/controversial or blog/flamewar', + description => 'PageSpec of pages where posting new comments is not allowed', + link => 'ikiwiki/PageSpec', + safe => 1, + rebuild => 1, + }, + comments_pagename => { + type => 'string', + default => 'comment_', + description => 'Base name for comments, e.g. "comment_" for pages like "sandbox/comment_12"', + safe => 0, # manual page moving required + rebuild => undef, + }, + comments_allowdirectives => { + type => 'boolean', + example => 0, + description => 'Interpret directives in comments?', + safe => 1, + rebuild => 0, + }, + comments_allowauthor => { + type => 'boolean', + example => 0, + description => 'Allow anonymous commenters to set an author name?', + safe => 1, + rebuild => 0, + }, + comments_commit => { + type => 'boolean', + example => 1, + description => 'commit comments to the VCS', + # old uncommitted comments are likely to cause + # confusion if this is changed + safe => 0, + rebuild => 0, + }, + comments_allowformats => { + type => 'string', + default => '', + example => 'mdwn txt', + description => 'Restrict formats for comments to (no restriction if empty)', + safe => 1, + rebuild => 0, + }, + +} + +sub checkconfig () { + $config{comments_commit} = 1 + unless defined $config{comments_commit}; + if (! $config{comments_commit}) { + $config{only_committed_changes}=0; + } + $config{comments_pagespec} = '' + unless defined $config{comments_pagespec}; + $config{comments_closed_pagespec} = '' + unless defined $config{comments_closed_pagespec}; + $config{comments_pagename} = 'comment_' + unless defined $config{comments_pagename}; + $config{comments_allowformats} = '' + unless defined $config{comments_allowformats}; +} + +sub htmlize { + my %params = @_; + return $params{content}; +} + +sub htmlize_pending { + my %params = @_; + return sprintf(gettext("this comment needs %s"), + ''. + gettext("moderation").''); +} + +# FIXME: copied verbatim from meta +sub safeurl ($) { + my $url=shift; + if (exists $IkiWiki::Plugin::htmlscrubber::{safe_url_regexp} && + defined $IkiWiki::Plugin::htmlscrubber::safe_url_regexp) { + return $url=~/$IkiWiki::Plugin::htmlscrubber::safe_url_regexp/; + } + else { + return 1; + } +} + +sub isallowed ($) { + my $format = shift; + return ! $config{comments_allowformats} || $config{comments_allowformats} =~ /\b$format\b/; +} + +sub preprocess { + my %params = @_; + my $page = $params{page}; + + my $format = $params{format}; + if (defined $format && (! exists $IkiWiki::hooks{htmlize}{$format} || + ! isallowed($format))) { + error(sprintf(gettext("unsupported page format %s"), $format)); + } + + my $content = $params{content}; + if (! defined $content) { + error(gettext("comment must have content")); + } + $content =~ s/\\"/"/g; + + if (defined wantarray) { + if ($config{comments_allowdirectives}) { + $content = IkiWiki::preprocess($page, $params{destpage}, + $content); + } + + # no need to bother with htmlize if it's just HTML + $content = IkiWiki::htmlize($page, $params{destpage}, $format, $content) + if defined $format; + + IkiWiki::run_hooks(sanitize => sub { + $content = shift->( + page => $page, + destpage => $params{destpage}, + content => $content, + ); + }); + } + else { + IkiWiki::preprocess($page, $params{destpage}, $content, 1); + } + + # set metadata, possibly overriding [[!meta]] directives from the + # comment itself + + my $commentuser; + my $commentip; + my $commentauthor; + my $commentauthorurl; + my $commentopenid; + if (defined $params{username}) { + $commentuser = $params{username}; + + my $oiduser = eval { IkiWiki::openiduser($commentuser) }; + + if (defined $oiduser) { + # looks like an OpenID + $commentauthorurl = $commentuser; + $commentauthor = (defined $params{nickname} && length $params{nickname}) ? $params{nickname} : $oiduser; + $commentopenid = $commentuser; + } + else { + $commentauthorurl = IkiWiki::cgiurl( + do => 'goto', + page => IkiWiki::userpage($commentuser) + ); + + $commentauthor = $commentuser; + } + } + else { + if (defined $params{ip}) { + $commentip = $params{ip}; + } + $commentauthor = gettext("Anonymous"); + } + + $commentstate{$page}{commentuser} = $commentuser; + $commentstate{$page}{commentopenid} = $commentopenid; + $commentstate{$page}{commentip} = $commentip; + $commentstate{$page}{commentauthor} = $commentauthor; + $commentstate{$page}{commentauthorurl} = $commentauthorurl; + $commentstate{$page}{commentauthoravatar} = $params{avatar}; + if (! defined $pagestate{$page}{meta}{author}) { + $pagestate{$page}{meta}{author} = $commentauthor; + } + if (! defined $pagestate{$page}{meta}{authorurl}) { + $pagestate{$page}{meta}{authorurl} = $commentauthorurl; + } + + if ($config{comments_allowauthor}) { + if (defined $params{claimedauthor}) { + $pagestate{$page}{meta}{author} = $params{claimedauthor}; + } + + if (defined $params{url}) { + my $url=$params{url}; + + eval q{use URI::Heuristic}; + if (! $@) { + $url=URI::Heuristic::uf_uristr($url); + } + + if (safeurl($url)) { + $pagestate{$page}{meta}{authorurl} = $url; + } + } + } + else { + $pagestate{$page}{meta}{author} = $commentauthor; + $pagestate{$page}{meta}{authorurl} = $commentauthorurl; + } + + if (defined $params{subject}) { + # decode title the same way meta does + eval q{use HTML::Entities}; + $pagestate{$page}{meta}{title} = decode_entities($params{subject}); + } + + if ($params{page} =~ m/\/\Q$config{comments_pagename}\E\d+_/) { + $pagestate{$page}{meta}{permalink} = urlto(IkiWiki::dirname($params{page})). + "#".page_to_id($params{page}); + } + + eval q{use Date::Parse}; + if (! $@) { + my $time = str2time($params{date}); + $IkiWiki::pagectime{$page} = $time if defined $time; + } + + return $content; +} + +sub preprocess_moderation { + my %params = @_; + + $params{desc}=gettext("Comment Moderation") + unless defined $params{desc}; + + if (length $config{cgiurl}) { + return ''.$params{desc}.''; + } + else { + return $params{desc}; + } +} + +sub sessioncgi ($$) { + my $cgi=shift; + my $session=shift; + + my $do = $cgi->param('do'); + if ($do eq 'comment') { + editcomment($cgi, $session); + } + elsif ($do eq 'commentmoderation') { + commentmoderation($cgi, $session); + } + elsif ($do eq 'commentsignin') { + IkiWiki::cgi_signin($cgi, $session); + exit; + } +} + +# Mostly cargo-culted from IkiWiki::plugin::editpage +sub editcomment ($$) { + my $cgi=shift; + my $session=shift; + + IkiWiki::decode_cgi_utf8($cgi); + + eval q{use CGI::FormBuilder}; + error($@) if $@; + + my @buttons = (POST_COMMENT, PREVIEW, CANCEL); + my $form = CGI::FormBuilder->new( + fields => [qw{do sid page subject editcontent type author + email url subscribe anonsubscribe}], + charset => 'utf-8', + method => 'POST', + required => [qw{editcontent}], + javascript => 0, + params => $cgi, + action => IkiWiki::cgiurl(), + header => 0, + table => 0, + template => { template('editcomment.tmpl') }, + ); + + IkiWiki::decode_form_utf8($form); + IkiWiki::run_hooks(formbuilder_setup => sub { + shift->(title => "comment", form => $form, cgi => $cgi, + session => $session, buttons => \@buttons); + }); + IkiWiki::decode_form_utf8($form); + + my $type = $form->param('type'); + if (defined $type && length $type && $IkiWiki::hooks{htmlize}{$type}) { + $type = IkiWiki::possibly_foolish_untaint($type); + } + else { + $type = $config{default_pageext}; + } + + + my @page_types; + if (exists $IkiWiki::hooks{htmlize}) { + foreach my $key (grep { !/^_/ && isallowed($_) } keys %{$IkiWiki::hooks{htmlize}}) { + push @page_types, [$key, $IkiWiki::hooks{htmlize}{$key}{longname} || $key]; + } + } + @page_types=sort @page_types; + + $form->field(name => 'do', type => 'hidden'); + $form->field(name => 'sid', type => 'hidden', value => $session->id, + force => 1); + $form->field(name => 'page', type => 'hidden'); + $form->field(name => 'subject', type => 'text', size => 72); + $form->field(name => 'editcontent', type => 'textarea', rows => 10); + $form->field(name => "type", value => $type, force => 1, + type => 'select', options => \@page_types); + + my $username=$session->param('name'); + $form->tmpl_param(username => $username); + + $form->field(name => "subscribe", type => 'hidden'); + $form->field(name => "anonsubscribe", type => 'hidden'); + if (IkiWiki::Plugin::notifyemail->can("subscribe")) { + if (defined $username) { + $form->field(name => "subscribe", type => "checkbox", + options => [gettext("email replies to me")]); + } + elsif (IkiWiki::Plugin::passwordauth->can("anonuser")) { + $form->field(name => "anonsubscribe", type => "checkbox", + options => [gettext("email replies to me")]); + } + } + + if ($config{comments_allowauthor} and + ! defined $session->param('name')) { + $form->tmpl_param(allowauthor => 1); + $form->field(name => 'author', type => 'text', size => '40'); + $form->field(name => 'email', type => 'text', size => '40'); + $form->field(name => 'url', type => 'text', size => '40'); + } + else { + $form->tmpl_param(allowauthor => 0); + $form->field(name => 'author', type => 'hidden', value => '', + force => 1); + $form->field(name => 'email', type => 'hidden', value => '', + force => 1); + $form->field(name => 'url', type => 'hidden', value => '', + force => 1); + } + + if (! defined $session->param('name')) { + # Make signinurl work and return here. + $form->tmpl_param(signinurl => IkiWiki::cgiurl(do => 'commentsignin')); + $session->param(postsignin => $ENV{QUERY_STRING}); + IkiWiki::cgi_savesession($session); + } + + # The untaint is OK (as in editpage) because we're about to pass + # it to file_pruned and wiki_file_regexp anyway. + my ($page) = $form->field('page')=~/$config{wiki_file_regexp}/; + $page = IkiWiki::possibly_foolish_untaint($page); + if (! defined $page || ! length $page || + IkiWiki::file_pruned($page)) { + error(gettext("bad page name")); + } + + $form->title(sprintf(gettext("commenting on %s"), + IkiWiki::pagetitle(IkiWiki::basename($page)))); + + $form->tmpl_param('helponformattinglink', + htmllink($page, $page, 'ikiwiki/formatting', + noimageinline => 1, + linktext => 'FormattingHelp'), + allowdirectives => $config{allow_directives}); + + if ($form->submitted eq CANCEL) { + # bounce back to the page they wanted to comment on, and exit. + IkiWiki::redirect($cgi, urlto($page)); + exit; + } + + if (not exists $pagesources{$page}) { + error(sprintf(gettext( + "page '%s' doesn't exist, so you can't comment"), + $page)); + } + + # There's no UI to get here, but someone might construct the URL, + # leading to a comment that exists in the repository but isn't + # shown + if (!pagespec_match($page, $config{comments_pagespec}, + location => $page)) { + error(sprintf(gettext( + "comments on page '%s' are not allowed"), + $page)); + } + + if (pagespec_match($page, $config{comments_closed_pagespec}, + location => $page)) { + error(sprintf(gettext( + "comments on page '%s' are closed"), + $page)); + } + + # Set a flag to indicate that we're posting a comment, + # so that postcomment() can tell it should match. + $postcomment=1; + IkiWiki::check_canedit($page, $cgi, $session); + $postcomment=0; + + my $content = "[[!comment format=$type\n"; + + if (defined $session->param('name')) { + my $username = $session->param('name'); + $username =~ s/"/"/g; + $content .= " username=\"$username\"\n"; + } + if (defined $session->param('nickname')) { + my $nickname = $session->param('nickname'); + $nickname =~ s/"/"/g; + $content .= " nickname=\"$nickname\"\n"; + } + elsif (defined $session->remote_addr()) { + $content .= " ip=\"".$session->remote_addr()."\"\n"; + } + + if ($config{comments_allowauthor}) { + my $author = $form->field('author'); + if (defined $author && length $author) { + $author =~ s/"/"/g; + $content .= " claimedauthor=\"$author\"\n"; + } + my $url = $form->field('url'); + if (defined $url && length $url) { + $url =~ s/"/"/g; + $content .= " url=\"$url\"\n"; + } + } + + my $avatar=getavatar($session->param('name')); + if (defined $avatar && length $avatar) { + $avatar =~ s/"/"/g; + $content .= " avatar=\"$avatar\"\n"; + } + + my $subject = $form->field('subject'); + if (defined $subject && length $subject) { + $subject =~ s/"/"/g; + } + else { + $subject = "comment ".(num_comments($page, $config{srcdir}) + 1); + } + $content .= " subject=\"$subject\"\n"; + + $content .= " date=\"" . strftime_utf8('%Y-%m-%dT%H:%M:%SZ', gmtime) . "\"\n"; + + my $editcontent = $form->field('editcontent'); + $editcontent="" if ! defined $editcontent; + $editcontent =~ s/\r\n/\n/g; + $editcontent =~ s/\r/\n/g; + $editcontent =~ s/"/\\"/g; + $content .= " content=\"\"\"\n$editcontent\n\"\"\"]]\n"; + + my $location=unique_comment_location($page, $content, $config{srcdir}); + + # This is essentially a simplified version of editpage: + # - the user does not control the page that's created, only the parent + # - it's always a create operation, never an edit + # - this means that conflicts should never happen + # - this means that if they do, rocks fall and everyone dies + + if ($form->submitted eq PREVIEW) { + my $preview=previewcomment($content, $location, $page, time); + IkiWiki::run_hooks(format => sub { + $preview = shift->(page => $page, + content => $preview); + }); + $form->tmpl_param(page_preview => $preview); + } + else { + $form->tmpl_param(page_preview => ""); + } + + if ($form->submitted eq POST_COMMENT && $form->validate) { + IkiWiki::checksessionexpiry($cgi, $session); + + if (IkiWiki::Plugin::notifyemail->can("subscribe")) { + my $subspec="comment($page)"; + if (defined $username && + length $form->field("subscribe")) { + IkiWiki::Plugin::notifyemail::subscribe( + $username, $subspec); + } + elsif (length $form->field("email") && + length $form->field("anonsubscribe")) { + IkiWiki::Plugin::notifyemail::anonsubscribe( + $form->field("email"), $subspec); + } + } + + $postcomment=1; + my $ok=IkiWiki::check_content(content => $form->field('editcontent'), + subject => $form->field('subject'), + $config{comments_allowauthor} ? ( + author => $form->field('author'), + url => $form->field('url'), + ) : (), + page => $location, + cgi => $cgi, + session => $session, + nonfatal => 1, + ); + $postcomment=0; + + if (! $ok) { + $location=unique_comment_location($page, $content, $IkiWiki::Plugin::transient::transientdir, "._comment_pending"); + writefile("$location._comment_pending", $IkiWiki::Plugin::transient::transientdir, $content); + + # Refresh so anything that deals with pending + # comments can be updated. + require IkiWiki::Render; + IkiWiki::refresh(); + IkiWiki::saveindex(); + + IkiWiki::printheader($session); + print IkiWiki::cgitemplate($cgi, gettext(gettext("comment stored for moderation")), + "

". + gettext("Your comment will be posted after moderator review"). + "

"); + exit; + } + + # FIXME: could probably do some sort of graceful retry + # on error? Would require significant unwinding though + my $file = "$location._comment"; + writefile($file, $config{srcdir}, $content); + + my $conflict; + + if ($config{rcs} and $config{comments_commit}) { + my $message = gettext("Added a comment"); + if (defined $form->field('subject') && + length $form->field('subject')) { + $message = sprintf( + gettext("Added a comment: %s"), + $form->field('subject')); + } + + IkiWiki::rcs_add($file); + IkiWiki::disable_commit_hook(); + $conflict = IkiWiki::rcs_commit_staged( + message => $message, + session => $session, + ); + IkiWiki::enable_commit_hook(); + IkiWiki::rcs_update(); + } + + # Now we need a refresh + require IkiWiki::Render; + IkiWiki::refresh(); + IkiWiki::saveindex(); + + # this should never happen, unless a committer deliberately + # breaks it or something + error($conflict) if defined $conflict; + + # Jump to the new comment on the page. + # The trailing question mark tries to avoid broken + # caches and get the most recent version of the page. + IkiWiki::redirect($cgi, urlto($page). + "?updated#".page_to_id($location)); + + } + else { + IkiWiki::showform($form, \@buttons, $session, $cgi, + page => $page); + } + + exit; +} + +sub getavatar ($) { + my $user=shift; + return undef unless defined $user; + + my $avatar; + eval q{use Libravatar::URL}; + if (! $@) { + my $oiduser = eval { IkiWiki::openiduser($user) }; + my $https=defined $config{url} && $config{url}=~/^https:/; + + if (defined $oiduser) { + eval { + $avatar = libravatar_url(openid => $user, https => $https); + } + } + if (! defined $avatar && + (my $email = IkiWiki::userinfo_get($user, 'email'))) { + eval { + $avatar = libravatar_url(email => $email, https => $https); + } + } + } + return $avatar; +} + + +sub commentmoderation ($$) { + my $cgi=shift; + my $session=shift; + + IkiWiki::needsignin($cgi, $session); + if (! IkiWiki::is_admin($session->param("name"))) { + error(gettext("you are not logged in as an admin")); + } + + IkiWiki::decode_cgi_utf8($cgi); + + if (defined $cgi->param('sid')) { + IkiWiki::checksessionexpiry($cgi, $session); + + my $rejectalldefer=$cgi->param('rejectalldefer'); + + my %vars=$cgi->Vars; + my $added=0; + foreach my $id (keys %vars) { + if ($id =~ /(.*)\._comment(?:_pending)?$/) { + $id=decode_utf8($id); + my $action=$cgi->param($id); + next if $action eq 'Defer' && ! $rejectalldefer; + + # Make sure that the id is of a legal + # pending comment. + my ($f) = $id =~ /$config{wiki_file_regexp}/; + if (! defined $f || ! length $f || + IkiWiki::file_pruned($f)) { + error("illegal file"); + } + + my $page=IkiWiki::dirname($f); + my $filedir=$IkiWiki::Plugin::transient::transientdir; + my $file="$filedir/$f"; + if (! -e $file) { + # old location + $file="$config{srcdir}/$f"; + $filedir=$config{srcdir}; + if (! -e $file) { + # older location + $file="$config{wikistatedir}/comments_pending/".$f; + $filedir="$config{wikistatedir}/comments_pending"; + } + } + + if ($action eq 'Accept') { + my $content=eval { readfile($file) }; + next if $@; # file vanished since form was displayed + my $dest=unique_comment_location($page, $content, $config{srcdir})."._comment"; + writefile($dest, $config{srcdir}, $content); + if ($config{rcs} and $config{comments_commit}) { + IkiWiki::rcs_add($dest); + } + $added++; + } + + require IkiWiki::Render; + IkiWiki::prune($file, $filedir); + } + } + + if ($added) { + my $conflict; + if ($config{rcs} and $config{comments_commit}) { + my $message = gettext("Comment moderation"); + IkiWiki::disable_commit_hook(); + $conflict=IkiWiki::rcs_commit_staged( + message => $message, + session => $session, + ); + IkiWiki::enable_commit_hook(); + IkiWiki::rcs_update(); + } + + # Now we need a refresh + require IkiWiki::Render; + IkiWiki::refresh(); + IkiWiki::saveindex(); + + error($conflict) if defined $conflict; + } + } + + my @comments=map { + my ($id, $dir, $ctime)=@{$_}; + my $content=readfile("$dir/$id"); + my $preview=previewcomment($content, $id, + $id, $ctime); + { + id => $id, + view => $preview, + } + } sort { $b->[2] <=> $a->[2] } comments_pending(); + + my $template=template("commentmoderation.tmpl"); + $template->param( + sid => $session->id, + comments => \@comments, + cgiurl => IkiWiki::cgiurl(), + ); + IkiWiki::printheader($session); + my $out=$template->output; + IkiWiki::run_hooks(format => sub { + $out = shift->(page => "", content => $out); + }); + print IkiWiki::cgitemplate($cgi, gettext("comment moderation"), $out); + exit; +} + +sub formbuilder_setup (@) { + my %params=@_; + + my $form=$params{form}; + if ($form->title eq "preferences" && + IkiWiki::is_admin($params{session}->param("name"))) { + push @{$params{buttons}}, "Comment Moderation"; + if ($form->submitted && $form->submitted eq "Comment Moderation") { + commentmoderation($params{cgi}, $params{session}); + } + } +} + +sub comments_pending () { + my @ret; + + eval q{use File::Find}; + error($@) if $@; + eval q{use Cwd}; + error($@) if $@; + my $origdir=getcwd(); + + my $find_comments=sub { + my $dir=shift; + my $extension=shift; + return unless -d $dir; + + chdir($dir) || die "chdir $dir: $!"; + + find({ + no_chdir => 1, + wanted => sub { + my $file=decode_utf8($_); + $file=~s/^\.\///; + return if ! length $file || IkiWiki::file_pruned($file) + || -l $_ || -d _ || $file !~ /\Q$extension\E$/; + my ($f) = $file =~ /$config{wiki_file_regexp}/; # untaint + if (defined $f) { + my $ctime=(stat($_))[10]; + push @ret, [$f, $dir, $ctime]; + } + } + }, "."); + + chdir($origdir) || die "chdir $origdir: $!"; + }; + + $find_comments->($IkiWiki::Plugin::transient::transientdir, "._comment_pending"); + # old location + $find_comments->($config{srcdir}, "._comment_pending"); + # old location + $find_comments->("$config{wikistatedir}/comments_pending/", + "._comment"); + + return @ret; +} + +sub previewcomment ($$$) { + my $content=shift; + my $location=shift; + my $page=shift; + my $time=shift; + + # Previewing a comment should implicitly enable comment posting mode. + my $oldpostcomment=$postcomment; + $postcomment=1; + + my $preview = IkiWiki::htmlize($location, $page, '_comment', + IkiWiki::linkify($location, $page, + IkiWiki::preprocess($location, $page, + IkiWiki::filter($location, $page, $content), 0, 1))); + + my $template = template("comment.tmpl"); + $template->param(content => $preview); + $template->param(ctime => displaytime($time, undef, 1)); + $template->param(html5 => $config{html5}); + + IkiWiki::run_hooks(pagetemplate => sub { + shift->(page => $location, + destpage => $page, + template => $template); + }); + + $template->param(have_actions => 0); + + $postcomment=$oldpostcomment; + + return $template->output; +} + +sub commentsshown ($) { + my $page=shift; + + return pagespec_match($page, $config{comments_pagespec}, + location => $page); +} + +sub commentsopen ($) { + my $page = shift; + + return length $config{cgiurl} > 0 && + (! length $config{comments_closed_pagespec} || + ! pagespec_match($page, $config{comments_closed_pagespec}, + location => $page)); +} + +sub pagetemplate (@) { + my %params = @_; + + my $page = $params{page}; + my $template = $params{template}; + my $shown = ($template->query(name => 'commentslink') || + $template->query(name => 'commentsurl') || + $template->query(name => 'atomcommentsurl') || + $template->query(name => 'comments')) && + commentsshown($page); + + if ($template->query(name => 'comments')) { + my $comments = undef; + if ($shown) { + $comments = IkiWiki::preprocess_inline( + pages => "comment($page) and !comment($page/*)", + template => 'comment', + show => 0, + reverse => 'yes', + page => $page, + destpage => $params{destpage}, + feedfile => 'comments', + emptyfeeds => 'no', + ); + } + + if (defined $comments && length $comments) { + $template->param(comments => $comments); + } + + if ($shown && commentsopen($page)) { + $template->param(addcommenturl => addcommenturl($page)); + } + } + + if ($shown) { + if ($template->query(name => 'commentsurl')) { + $template->param(commentsurl => + urlto($page).'#comments'); + } + + if ($template->query(name => 'atomcommentsurl') && $config{usedirs}) { + # This will 404 until there are some comments, but I + # think that's probably OK... + $template->param(atomcommentsurl => + urlto($page).'comments.atom'); + } + + if ($template->query(name => 'commentslink')) { + my $num=num_comments($page, $config{srcdir}); + my $link; + if ($num > 0) { + $link = htmllink($page, $params{destpage}, $page, + linktext => sprintf(ngettext("%i comment", "%i comments", $num), $num), + anchor => "comments", + noimageinline => 1 + ); + } + elsif (commentsopen($page)) { + $link = "". + #translators: Here "Comment" is a verb; + #translators: the user clicks on it to + #translators: post a comment. + gettext("Comment"). + ""; + } + $template->param(commentslink => $link) + if defined $link; + } + } + + # everything below this point is only relevant to the comments + # themselves + if (!exists $commentstate{$page}) { + return; + } + + if ($template->query(name => 'commentid')) { + $template->param(commentid => page_to_id($page)); + } + + if ($template->query(name => 'commentuser')) { + $template->param(commentuser => + $commentstate{$page}{commentuser}); + } + + if ($template->query(name => 'commentopenid')) { + $template->param(commentopenid => + $commentstate{$page}{commentopenid}); + } + + if ($template->query(name => 'commentip')) { + $template->param(commentip => + $commentstate{$page}{commentip}); + } + + if ($template->query(name => 'commentauthor')) { + $template->param(commentauthor => + $commentstate{$page}{commentauthor}); + } + + if ($template->query(name => 'commentauthorurl')) { + $template->param(commentauthorurl => + $commentstate{$page}{commentauthorurl}); + } + + if ($template->query(name => 'commentauthoravatar')) { + $template->param(commentauthoravatar => + $commentstate{$page}{commentauthoravatar}); + } + + if ($template->query(name => 'removeurl') && + IkiWiki::Plugin::remove->can("check_canremove") && + length $config{cgiurl}) { + $template->param(removeurl => IkiWiki::cgiurl(do => 'remove', + page => $page)); + $template->param(have_actions => 1); + } +} + +sub addcommenturl ($) { + my $page=shift; + + return IkiWiki::cgiurl(do => 'comment', page => $page); +} + +sub num_comments ($$) { + my $page=shift; + my $dir=shift; + + my @comments=glob("$dir/$page/$config{comments_pagename}*._comment"); + return int @comments; +} + +sub unique_comment_location ($$$$) { + my $page=shift; + eval q{use Digest::MD5 'md5_hex'}; + error($@) if $@; + my $content_md5=md5_hex(Encode::encode_utf8(shift)); + my $dir=shift; + my $ext=shift || "._comment"; + + my $location; + my $i = num_comments($page, $dir); + do { + $i++; + $location = "$page/$config{comments_pagename}${i}_${content_md5}"; + } while (-e "$dir/$location$ext"); + + return $location; +} + +sub page_to_id ($) { + # Converts a comment page name into a unique, legal html id + # attribute value, that can be used as an anchor to link to the + # comment. + my $page=shift; + + eval q{use Digest::MD5 'md5_hex'}; + error($@) if $@; + + return "comment-".md5_hex(Encode::encode_utf8(($page))); +} + +package IkiWiki::PageSpec; + +sub match_postcomment ($$;@) { + my $page = shift; + my $glob = shift; + + if (! $postcomment) { + return IkiWiki::FailReason->new("not posting a comment"); + } + return match_glob($page, $glob, @_); +} + +sub match_comment ($$;@) { + my $page = shift; + my $glob = shift; + + if (! $postcomment) { + # To see if it's a comment, check the source file type. + # Deal with comments that were just deleted. + my $source=exists $IkiWiki::pagesources{$page} ? + $IkiWiki::pagesources{$page} : + $IkiWiki::delpagesources{$page}; + my $type=defined $source ? IkiWiki::pagetype($source) : undef; + if (! defined $type || $type ne "_comment") { + return IkiWiki::FailReason->new("$page is not a comment"); + } + } + + return match_glob($page, "$glob/*", internal => 1, @_); +} + +sub match_comment_pending ($$;@) { + my $page = shift; + my $glob = shift; + + my $source=exists $IkiWiki::pagesources{$page} ? + $IkiWiki::pagesources{$page} : + $IkiWiki::delpagesources{$page}; + my $type=defined $source ? IkiWiki::pagetype($source) : undef; + if (! defined $type || $type ne "_comment_pending") { + return IkiWiki::FailReason->new("$page is not a pending comment"); + } + + return match_glob($page, "$glob/*", internal => 1, @_); +} + +1 diff --git a/IkiWiki/Plugin/conditional.pm b/IkiWiki/Plugin/conditional.pm new file mode 100644 index 000000000..b450f1a0a --- /dev/null +++ b/IkiWiki/Plugin/conditional.pm @@ -0,0 +1,129 @@ +#!/usr/bin/perl +package IkiWiki::Plugin::conditional; + +use warnings; +use strict; +use IkiWiki 3.00; + +sub import { + hook(type => "getsetup", id => "conditional", call => \&getsetup); + hook(type => "preprocess", id => "if", call => \&preprocess_if); +} + +sub getsetup { + return + plugin => { + safe => 1, + rebuild => undef, + section => "widget", + }, +} + +sub preprocess_if (@) { + my %params=@_; + + foreach my $param (qw{test then}) { + if (! exists $params{$param}) { + error sprintf(gettext('%s parameter is required'), $param); + } + } + + my $result=0; + if ((exists $params{all} && ! IkiWiki::yesno($params{all})) || + # An optimisation to avoid needless looping over every page + # for simple uses of some of the tests. + $params{test} =~ /^([\s\!()]*((enabled|sourcepage|destpage|included)\([^)]*\)|(and|or))[\s\!()]*)+$/) { + $result=pagespec_match($params{page}, $params{test}, + location => $params{page}, + sourcepage => $params{page}, + destpage => $params{destpage}); + my $i = $result->influences; + foreach my $k (keys %$i) { + # minor optimization: influences are always simple dependencies + $IkiWiki::depends_simple{$params{page}}{lc $k} |= $i->{$k}; + } + } + else { + $result=pagespec_match_list($params{page}, $params{test}, + # stop after first match + num => 1, + sourcepage => $params{page}, + destpage => $params{destpage}, + ); + } + + my $ret; + if ($result) { + $ret=$params{then}; + } + elsif (exists $params{else}) { + $ret=$params{else}; + } + else { + $ret=""; + } + return IkiWiki::preprocess($params{page}, $params{destpage}, $ret); +} + +package IkiWiki::PageSpec; + +sub match_enabled ($$;@) { + shift; + my $plugin=shift; + + # test if the plugin is enabled + if (UNIVERSAL::can("IkiWiki::Plugin::".$plugin, "import")) { + return IkiWiki::SuccessReason->new("$plugin is enabled"); + } + else { + return IkiWiki::FailReason->new("$plugin is not enabled"); + } +} + +sub match_sourcepage ($$;@) { + shift; + my $glob=shift; + my %params=@_; + + $glob=derel($glob, $params{location}); + + return IkiWiki::FailReason->new("cannot match sourcepage") unless exists $params{sourcepage}; + if (match_glob($params{sourcepage}, $glob, @_)) { + return IkiWiki::SuccessReason->new("sourcepage matches $glob"); + } + else { + return IkiWiki::FailReason->new("sourcepage does not match $glob"); + } +} + +sub match_destpage ($$;@) { + shift; + my $glob=shift; + my %params=@_; + + $glob=derel($glob, $params{location}); + + return IkiWiki::FailReason->new("cannot match destpage") unless exists $params{destpage}; + if (match_glob($params{destpage}, $glob, @_)) { + return IkiWiki::SuccessReason->new("destpage matches $glob"); + } + else { + return IkiWiki::FailReason->new("destpage does not match $glob"); + } +} + +sub match_included ($$;@) { + shift; + shift; + my %params=@_; + + return IkiWiki::FailReason->new("cannot match included") unless exists $params{sourcepage} && exists $params{destpage}; + if ($params{sourcepage} ne $params{destpage}) { + return IkiWiki::SuccessReason->new("page $params{sourcepage} is included"); + } + else { + return IkiWiki::FailReason->new("page $params{sourcepage} is not included"); + } +} + +1 diff --git a/IkiWiki/Plugin/creole.pm b/IkiWiki/Plugin/creole.pm new file mode 100644 index 000000000..a1e4b31d3 --- /dev/null +++ b/IkiWiki/Plugin/creole.pm @@ -0,0 +1,38 @@ +#!/usr/bin/perl +# WikiCreole markup +# based on the WikiText plugin. +package IkiWiki::Plugin::creole; + +use warnings; +use strict; +use IkiWiki 3.00; + +sub import { + hook(type => "getsetup", id => "creole", call => \&getsetup); + hook(type => "htmlize", id => "creole", call => \&htmlize); +} + +sub getsetup { + return + plugin => { + safe => 1, + rebuild => 1, # format plugin + section => "format", + }, +} + +sub htmlize (@) { + my %params=@_; + my $content = $params{content}; + + eval q{use Text::WikiCreole}; + return $content if $@; + + # don't parse WikiLinks, ikiwiki already does + creole_customlinks(); + creole_custombarelinks(); + + return creole_parse($content); +} + +1 diff --git a/IkiWiki/Plugin/cutpaste.pm b/IkiWiki/Plugin/cutpaste.pm new file mode 100644 index 000000000..0f6ea0b1f --- /dev/null +++ b/IkiWiki/Plugin/cutpaste.pm @@ -0,0 +1,90 @@ +#!/usr/bin/perl +package IkiWiki::Plugin::cutpaste; + +use warnings; +use strict; +use IkiWiki 3.00; + +sub import { + hook(type => "getsetup", id => "cutpaste", call => \&getsetup); + hook(type => "needsbuild", id => "cutpaste", call => \&needsbuild); + hook(type => "preprocess", id => "cut", call => \&preprocess_cut, scan => 1); + hook(type => "preprocess", id => "copy", call => \&preprocess_copy, scan => 1); + hook(type => "preprocess", id => "paste", call => \&preprocess_paste); +} + +sub getsetup () { + return + plugin => { + safe => 1, + rebuild => undef, + section => "widget", + }, +} + +sub needsbuild (@) { + my $needsbuild=shift; + foreach my $page (keys %pagestate) { + if (exists $pagestate{$page}{cutpaste}) { + if (exists $pagesources{$page} && + grep { $_ eq $pagesources{$page} } @$needsbuild) { + # remove state, will be re-added if + # the cut/copy directive is still present + # on rebuild. + delete $pagestate{$page}{cutpaste}; + } + } + } + return $needsbuild; +} + +sub preprocess_cut (@) { + my %params=@_; + + foreach my $param (qw{id text}) { + if (! exists $params{$param}) { + error sprintf(gettext('%s parameter is required'), $param); + } + } + + $pagestate{$params{page}}{cutpaste}{$params{id}} = $params{text}; + + return "" if defined wantarray; +} + +sub preprocess_copy (@) { + my %params=@_; + + foreach my $param (qw{id text}) { + if (! exists $params{$param}) { + error sprintf(gettext('%s parameter is required'), $param); + } + } + + $pagestate{$params{page}}{cutpaste}{$params{id}} = $params{text}; + + return IkiWiki::preprocess($params{page}, $params{destpage}, $params{text}) + if defined wantarray; +} + +sub preprocess_paste (@) { + my %params=@_; + + foreach my $param (qw{id}) { + if (! exists $params{$param}) { + error sprintf(gettext('%s parameter is required'), $param); + } + } + + if (! exists $pagestate{$params{page}}{cutpaste}) { + error gettext('no text was copied in this page'); + } + if (! exists $pagestate{$params{page}}{cutpaste}{$params{id}}) { + error sprintf(gettext('no text was copied in this page with id %s'), $params{id}); + } + + return IkiWiki::preprocess($params{page}, $params{destpage}, + $pagestate{$params{page}}{cutpaste}{$params{id}}); +} + +1; diff --git a/IkiWiki/Plugin/cvs.pm b/IkiWiki/Plugin/cvs.pm new file mode 100644 index 000000000..841aec914 --- /dev/null +++ b/IkiWiki/Plugin/cvs.pm @@ -0,0 +1,549 @@ +#!/usr/bin/perl +package IkiWiki::Plugin::cvs; + +# Copyright (c) 2009 Amitai Schlair +# All rights reserved. +# +# This code is derived from software contributed to ikiwiki +# by Amitai Schlair. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY IKIWIKI AND CONTRIBUTORS ``AS IS'' +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION +# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +use warnings; +use strict; +use IkiWiki; + +use URI::Escape q{uri_escape_utf8}; +use File::chdir; + + +# GENERAL PLUGIN API CALLS + +sub import { + hook(type => "checkconfig", id => "cvs", call => \&checkconfig); + hook(type => "getsetup", id => "cvs", call => \&getsetup); + hook(type => "genwrapper", id => "cvs", call => \&genwrapper); + + hook(type => "rcs", id => "rcs_update", call => \&rcs_update); + hook(type => "rcs", id => "rcs_prepedit", call => \&rcs_prepedit); + hook(type => "rcs", id => "rcs_commit", call => \&rcs_commit); + hook(type => "rcs", id => "rcs_commit_staged", call => \&rcs_commit_staged); + hook(type => "rcs", id => "rcs_add", call => \&rcs_add); + hook(type => "rcs", id => "rcs_remove", call => \&rcs_remove); + hook(type => "rcs", id => "rcs_rename", call => \&rcs_rename); + hook(type => "rcs", id => "rcs_recentchanges", call => \&rcs_recentchanges); + hook(type => "rcs", id => "rcs_diff", call => \&rcs_diff); + hook(type => "rcs", id => "rcs_getctime", call => \&rcs_getctime); + hook(type => "rcs", id => "rcs_getmtime", call => \&rcs_getmtime); +} + +sub checkconfig () { + if (! defined $config{cvspath}) { + $config{cvspath}="ikiwiki"; + } + if (exists $config{cvspath}) { + # code depends on the path not having extraneous slashes + $config{cvspath}=~tr#/#/#s; + $config{cvspath}=~s/\/$//; + $config{cvspath}=~s/^\///; + } + if (defined $config{cvs_wrapper} && length $config{cvs_wrapper}) { + push @{$config{wrappers}}, { + wrapper => $config{cvs_wrapper}, + wrappermode => (defined $config{cvs_wrappermode} ? $config{cvs_wrappermode} : "04755"), + }; + } +} + +sub getsetup () { + return + plugin => { + safe => 0, # rcs plugin + rebuild => undef, + section => "rcs", + }, + cvsrepo => { + type => "string", + example => "/cvs/wikirepo", + description => "cvs repository location", + safe => 0, # path + rebuild => 0, + }, + cvspath => { + type => "string", + example => "ikiwiki", + description => "path inside repository where the wiki is located", + safe => 0, # paranoia + rebuild => 0, + }, + cvs_wrapper => { + type => "string", + example => "/cvs/wikirepo/CVSROOT/post-commit", + description => "cvs post-commit hook to generate (triggered by CVSROOT/loginfo entry)", + safe => 0, # file + rebuild => 0, + }, + cvs_wrappermode => { + type => "string", + example => '04755', + description => "mode for cvs_wrapper (can safely be made suid)", + safe => 0, + rebuild => 0, + }, + historyurl => { + type => "string", + example => "http://cvs.example.org/cvsweb.cgi/ikiwiki/[[file]]", + description => "cvsweb url to show file history ([[file]] substituted)", + safe => 1, + rebuild => 1, + }, + diffurl => { + type => "string", + example => "http://cvs.example.org/cvsweb.cgi/ikiwiki/[[file]].diff?r1=text&tr1=[[r1]]&r2=text&tr2=[[r2]]", + description => "cvsweb url to show a diff ([[file]], [[r1]], and [[r2]] substituted)", + safe => 1, + rebuild => 1, + }, +} + +sub genwrapper () { + return <$tmpfile"); + if ($? == -1) { + error "couldn't run cvsps: $!\n"; + } + elsif (($? >> 8) != 0) { + error "cvsps exited " . ($? >> 8) . ": $!\n"; + } + + tie(*SPSVC, 'File::ReadBackwards', $tmpfile) + || error "couldn't open $tmpfile for read: $!\n"; + + while (my $line = ) { + $line =~ /^$/ || error "expected blank line, got $line"; + + my ($rev, $user, $committype, $when); + my (@message, @pages); + + # We're reading backwards. + # Forwards, an entry looks like so: + # --------------------- + # PatchSet $rev + # Date: $when + # Author: $user (or user CGI runs as, for web commits) + # Branch: branch + # Tag: tag + # Log: + # @message_lines + # Members: + # @pages (and revisions) + # + + while ($line = ) { + last if ($line =~ /^Members:/); + for ($line) { + s/^\s+//; + s/\s+$//; + } + my ($page, $revs) = split(/:/, $line); + my ($oldrev, $newrev) = split(/->/, $revs); + $oldrev =~ s/INITIAL/0/; + $newrev =~ s/\(DEAD\)//; + my $diffurl = defined $config{diffurl} ? $config{diffurl} : ""; + my $epage = join('/', + map { uri_escape_utf8($_) } split('/', $page) + ); + $diffurl=~s/\[\[file\]\]/$epage/g; + $diffurl=~s/\[\[r1\]\]/$oldrev/g; + $diffurl=~s/\[\[r2\]\]/$newrev/g; + unshift @pages, { + page => pagename($page), + diffurl => $diffurl, + } if length $page; + } + + while ($line = ) { + last if ($line =~ /^Log:$/); + chomp $line; + unshift @message, { line => $line }; + } + $committype = "web"; + if (defined $message[0] && + $message[0]->{line}=~/$config{web_commit_regexp}/) { + $user=defined $2 ? "$2" : "$3"; + $message[0]->{line}=$4; + } + else { + $committype="cvs"; + } + + $line = ; # Tag + $line = ; # Branch + + $line = ; + if ($line =~ /^Author: (.*)$/) { + $user = $1 unless defined $user && length $user; + } + else { + error "expected Author, got $line"; + } + + $line = ; + if ($line =~ /^Date: (.*)$/) { + $when = str2time($1, 'UTC'); + } + else { + error "expected Date, got $line"; + } + + $line = ; + if ($line =~ /^PatchSet (.*)$/) { + $rev = $1; + } + else { + error "expected PatchSet, got $line"; + } + + $line = ; # --------------------- + + push @ret, { + rev => $rev, + user => $user, + committype => $committype, + when => $when, + message => [@message], + pages => [@pages], + } if @pages; + last if @ret >= $num; + } + + unlink($tmpfile) || error "couldn't unlink $tmpfile: $!\n"; + + return @ret; +} + +sub rcs_diff ($;$) { + my $rev=IkiWiki::possibly_foolish_untaint(int(shift)); + my $maxlines=shift; + + local $CWD = $config{srcdir}; + + # diff output is unavoidably preceded by the cvsps PatchSet entry + my @cvsps = `env TZ=UTC cvsps -q --cvs-direct -z 30 -g -s $rev`; + my $blank_lines_seen = 0; + + # skip log, get to the diff + while (my $line = shift @cvsps) { + $blank_lines_seen++ if ($line =~ /^$/); + last if $blank_lines_seen == 2; + } + + @cvsps = @cvsps[0..$maxlines-1] + if defined $maxlines && @cvsps > $maxlines; + + if (wantarray) { + return @cvsps; + } + else { + return join("", @cvsps); + } +} + +sub rcs_getctime ($) { + my $file=shift; + + local $CWD = $config{srcdir}; + + my $cvs_log_infoline=qr/^date: (.+);\s+author/; + + open CVSLOG, "cvs -Q log -r1.1 '$file' |" + || error "couldn't get cvs log output: $!\n"; + + my $date; + while () { + if (/$cvs_log_infoline/) { + $date=$1; + } + } + close CVSLOG || warn "cvs log $file exited $?"; + + if (! defined $date) { + warn "failed to parse cvs log for $file\n"; + return 0; + } + + eval q{use Date::Parse}; + error($@) if $@; + $date=str2time($date, 'UTC'); + debug("found ctime ".localtime($date)." for $file"); + return $date; +} + +sub rcs_getmtime ($) { + error "rcs_getmtime is not implemented for cvs\n"; # TODO +} + + +# INTERNAL SUPPORT ROUTINES + +sub commitmessage (@) { + my %params=@_; + + if (defined $params{session}) { + if (defined $params{session}->param("name")) { + return "web commit by ". + $params{session}->param("name"). + (length $params{message} ? ": $params{message}" : ""); + } + elsif (defined $params{session}->remote_addr()) { + return "web commit from ". + $params{session}->remote_addr(). + (length $params{message} ? ": $params{message}" : ""); + } + } + return $params{message}; +} + +sub cvs_info ($$) { + my $field=shift; + my $file=shift; + + local $CWD = $config{srcdir}; + + my $info=`cvs status $file`; + my ($ret)=$info=~/^\s*$field:\s*(\S+)/m; + return $ret; +} + +sub cvs_is_controlling { + my $dir=shift; + $dir=$config{srcdir} unless defined($dir); + return (-d "$dir/CVS") ? 1 : 0; +} + +sub cvs_keyword_subst_args ($) { + my $file = shift; + + local $CWD = $config{srcdir}; + + eval q{use File::MimeInfo}; + error($@) if $@; + my $filemime = File::MimeInfo::default($file); + # if (-T $file) { + + defined($filemime) && $filemime eq 'text/plain' + ? return ('-kkv', $file) + : return ('-kb', $file); +} + +sub cvs_runcvs(@) { + my @cmd = @_; + unshift @cmd, 'cvs', '-Q'; + + # CVS can't operate outside a srcdir, so we're always setting $CWD. + # "local $CWD" restores the previous value when we go out of scope. + # Usually that's correct. But if we're removing the last file from + # a directory, the post-commit hook will exec in a working directory + # that's about to not exist (CVS will prune it). + # + # chdir() manually here, so we can selectively not chdir() back. + + my $oldcwd = $CWD; + chdir($config{srcdir}); + + eval q{ + use IPC::Open3; + use Symbol qw(gensym); + use IO::File; + }; + error($@) if $@; + + my $cvsout = ''; + my $cvserr = ''; + local *CATCHERR = IO::File->new_tmpfile; + my $pid = open3(gensym(), \*CATCHOUT, ">&CATCHERR", @cmd); + while (my $l = ) { + $cvsout .= $l + unless 1; + } + waitpid($pid, 0); + my $ret = $? >> 8; + seek CATCHERR, 0, 0; + while (my $l = ) { + $cvserr .= $l + unless $l =~ /^cvs commit: changing keyword expansion /; + } + + print STDOUT $cvsout; + print STDERR $cvserr; + + chdir($oldcwd) if -d $oldcwd; + + return ($ret == 0) ? 1 : 0; +} + +1 diff --git a/IkiWiki/Plugin/darcs.pm b/IkiWiki/Plugin/darcs.pm new file mode 100644 index 000000000..646f65df1 --- /dev/null +++ b/IkiWiki/Plugin/darcs.pm @@ -0,0 +1,438 @@ +#!/usr/bin/perl +package IkiWiki::Plugin::darcs; + +use warnings; +use strict; +use URI::Escape q{uri_escape_utf8}; +use IkiWiki; + +sub import { + hook(type => "checkconfig", id => "darcs", call => \&checkconfig); + hook(type => "getsetup", id => "darcs", call => \&getsetup); + hook(type => "rcs", id => "rcs_update", call => \&rcs_update); + hook(type => "rcs", id => "rcs_prepedit", call => \&rcs_prepedit); + hook(type => "rcs", id => "rcs_commit", call => \&rcs_commit); + hook(type => "rcs", id => "rcs_commit_staged", call => \&rcs_commit_staged); + hook(type => "rcs", id => "rcs_add", call => \&rcs_add); + hook(type => "rcs", id => "rcs_remove", call => \&rcs_remove); + hook(type => "rcs", id => "rcs_rename", call => \&rcs_rename); + hook(type => "rcs", id => "rcs_recentchanges", call => \&rcs_recentchanges); + hook(type => "rcs", id => "rcs_diff", call => \&rcs_diff); + hook(type => "rcs", id => "rcs_getctime", call => \&rcs_getctime); + hook(type => "rcs", id => "rcs_getmtime", call => \&rcs_getmtime); +} + +sub silentsystem (@) { + open(SAVED_STDOUT, ">&STDOUT"); + open(STDOUT, ">/dev/null"); + my $ret = system @_; + open(STDOUT, ">&SAVED_STDOUT"); + return $ret; +} + +sub darcs_info ($$$) { + my $field = shift; + my $repodir = shift; + my $file = shift; # Relative to the repodir. + + my $child = open(DARCS_CHANGES, "-|"); + if (! $child) { + exec('darcs', 'changes', '--repodir', $repodir, '--xml-output', $file) or + error("failed to run 'darcs changes'"); + } + + # Brute force for now. :-/ + while () { + last if /^<\/created_as>$/; + } + ($_) = =~ /$field=\'([^\']+)/; + $field eq 'hash' and s/\.gz//; # Strip away the '.gz' from 'hash'es. + + close(DARCS_CHANGES); + + return $_; +} + +sub file_in_vc ($$) { + my $repodir = shift; + my $file = shift; + + my $child = open(DARCS_MANIFEST, "-|"); + if (! $child) { + exec('darcs', 'query', 'manifest', '--repodir', $repodir) or + error("failed to run 'darcs query manifest'"); + } + my $found=0; + while () { + $found = 1 if /^(\.\/)?$file$/; + } + close(DARCS_MANIFEST) or error("'darcs query manifest' exited " . $?); + + return $found; +} + +sub darcs_rev ($) { + my $file = shift; # Relative to the repodir. + my $repodir = $config{srcdir}; + + return "" unless file_in_vc($repodir, $file); + my $hash = darcs_info('hash', $repodir, $file); + return defined $hash ? $hash : ""; +} + +sub checkconfig () { + if (defined $config{darcs_wrapper} && length $config{darcs_wrapper}) { + push @{$config{wrappers}}, { + wrapper => $config{darcs_wrapper}, + wrappermode => (defined $config{darcs_wrappermode} ? $config{darcs_wrappermode} : "06755"), + }; + } +} + +sub getsetup () { + return + plugin => { + safe => 0, # rcs plugin + rebuild => undef, + section => "rcs", + }, + darcs_wrapper => { + type => "string", + example => "/darcs/repo/_darcs/ikiwiki-wrapper", + description => "wrapper to generate (set as master repo apply hook)", + safe => 0, # file + rebuild => 0, + }, + darcs_wrappermode => { + type => "string", + example => '06755', + description => "mode for darcs_wrapper (can safely be made suid)", + safe => 0, + rebuild => 0, + }, + historyurl => { + type => "string", + example => "http://darcs.example.com/darcsweb.cgi?r=wiki;a=filehistory;f=[[file]]", + description => "darcsweb url to show file history ([[file]] substituted)", + safe => 1, + rebuild => 1, + }, + diffurl => { + type => "string", + example => "http://darcs.example.com/darcsweb.cgi?r=wiki;a=filediff;h=[[hash]];f=[[file]]", + description => "darcsweb url to show a diff ([[hash]] and [[file]] substituted)", + safe => 1, + rebuild => 1, + }, +} + +sub rcs_update () { + silentsystem('darcs', "pull", "--repodir", $config{srcdir}, "-qa") +} + +sub rcs_prepedit ($) { + # Prepares to edit a file under revision control. Returns a token that + # must be passed to rcs_commit() when the file is to be commited. For us, + # this token the hash value of the latest patch that modifies the file, + # i.e. something like its current revision. + + my $file = shift; # Relative to the repodir. + my $rev = darcs_rev($file); + return $rev; +} + +sub commitauthor (@) { + my %params=@_; + + my $author="anon\@web"; + if (defined $params{session}) { + if (defined $params{session}->param("name")) { + return $params{session}->param("name").'@web'; + } + elsif (defined $params{session}->remote_addr()) { + return $params{session}->remote_addr().'@web'; + } + } + return 'anon@web'; +} + +sub rcs_commit (@) { + # Commit the page. Returns 'undef' on success and a version of the page + # with conflict markers on failure. + my %params=@_; + + my ($file, $message, $token) = + ($params{file}, $params{message}, $params{token}); + + # Compute if the "revision" of $file changed. + my $changed = darcs_rev($file) ne $token; + + # Yes, the following is a bit convoluted. + if ($changed) { + # TODO. Invent a better, non-conflicting name. + rename("$config{srcdir}/$file", "$config{srcdir}/$file.save") or + error("failed to rename $file to $file.save: $!"); + + # Roll the repository back to $token. + + # TODO. Can we be sure that no changes are lost? I think that + # we can, if we make sure that the 'darcs push' below will always + # succeed. + + # We need to revert everything as 'darcs obliterate' might choke + # otherwise. + # TODO: 'yes | ...' needed? Doesn't seem so. + silentsystem('darcs', "revert", "--repodir", $config{srcdir}, "--all") == 0 || + error("'darcs revert' failed"); + # Remove all patches starting at $token. + my $child = open(DARCS_OBLITERATE, "|-"); + if (! $child) { + open(STDOUT, ">/dev/null"); + exec('darcs', "obliterate", "--repodir", $config{srcdir}, + "--match", "hash " . $token) and + error("'darcs obliterate' failed"); + } + 1 while print DARCS_OBLITERATE "y"; + close(DARCS_OBLITERATE); + # Restore the $token one. + silentsystem('darcs', "pull", "--quiet", "--repodir", $config{srcdir}, + "--match", "hash " . $token, "--all") == 0 || + error("'darcs pull' failed"); + + # We're back at $token. Re-install the modified file. + rename("$config{srcdir}/$file.save", "$config{srcdir}/$file") or + error("failed to rename $file.save to $file: $!"); + } + + # Record the changes. + my $author=commitauthor(%params); + if (!defined $message || !length($message)) { + $message = "empty message"; + } + silentsystem('darcs', 'record', '--repodir', $config{srcdir}, '--all', + '-m', $message, '--author', $author, $file) == 0 || + error("'darcs record' failed"); + + # Update the repository by pulling from the default repository, which is + # master repository. + silentsystem('darcs', "pull", "--quiet", "--repodir", $config{srcdir}, + "--all") == 0 || error("'darcs pull' failed"); + + # If this updating yields any conflicts, we'll record them now to resolve + # them. If nothing is recorded, there are no conflicts. + $token = darcs_rev($file); + # TODO: Use only the first line here, i.e. only the patch name? + writefile("$file.log", $config{srcdir}, 'resolve conflicts: ' . $message); + silentsystem('darcs', 'record', '--repodir', $config{srcdir}, '--all', + '-m', 'resolve conflicts: ' . $message, '--author', $author, $file) == 0 || + error("'darcs record' failed"); + my $conflicts = darcs_rev($file) ne $token; + unlink("$config{srcdir}/$file.log") or + error("failed to remove '$file.log'"); + + # Push the changes to the main repository. + silentsystem('darcs', 'push', '--quiet', '--repodir', $config{srcdir}, '--all') == 0 || + error("'darcs push' failed"); + # TODO: darcs send? + + if ($conflicts) { + my $document = readfile("$config{srcdir}/$file"); + # Try to leave everything in a consistent state. + # TODO: 'yes | ...' needed? Doesn't seem so. + silentsystem('darcs', "revert", "--repodir", $config{srcdir}, "--all") == 0 || + warn("'darcs revert' failed"); + return $document; + } + else { + return undef; + } +} + +sub rcs_commit_staged (@) { + my %params=@_; + + my $author=commitauthor(%params); + if (!defined $params{message} || !length($params{message})) { + $params{message} = "empty message"; + } + + silentsystem('darcs', "record", "--repodir", $config{srcdir}, + "-a", "-A", $author, + "-m", $params{message}, + ) == 0 || error("'darcs record' failed"); + + # Push the changes to the main repository. + silentsystem('darcs', 'push', '--quiet', '--repodir', $config{srcdir}, '--all') == 0 || + error("'darcs push' failed"); + # TODO: darcs send? + + return undef; +} + +sub rcs_add ($) { + my $file = shift; # Relative to the repodir. + + if(! file_in_vc($config{srcdir}, $file)) { + # Intermediate directories will be added automagically. + system('darcs', 'add', '--quiet', '--repodir', $config{srcdir}, + '--boring', $file) == 0 || error("'darcs add' failed"); + } +} + +sub rcs_remove ($) { + my $file = shift; # Relative to the repodir. + + unlink($config{srcdir}.'/'.$file); +} + +sub rcs_rename ($$) { + my $a = shift; # Relative to the repodir. + my $b = shift; # Relative to the repodir. + + system('darcs', 'mv', '--repodir', $config{srcdir}, $a, $b) == 0 || + error("'darcs mv' failed"); +} + +sub rcs_recentchanges ($) { + my $num=shift; + my @ret; + + eval q{use Date::Parse}; + eval q{use XML::Simple}; + + my $repodir=$config{srcdir}; + + my $child = open(LOG, "-|"); + if (! $child) { + $ENV{"DARCS_DONT_ESCAPE_ANYTHING"}=1; + exec("darcs", "changes", "--xml", + "--summary", + "--repodir", "$repodir", + "--last", "$num") + || error("'darcs changes' failed to run"); + } + my $data; + $data .= $_ while(); + close LOG; + + my $log = XMLin($data, ForceArray => 1); + + foreach my $patch (@{$log->{patch}}) { + my $date=$patch->{local_date}; + my $hash=$patch->{hash}; + my $when=str2time($date); + my (@pages, @files, @pg); + push @pages, $_ foreach (@{$patch->{summary}->[0]->{modify_file}}); + push @pages, $_ foreach (@{$patch->{summary}->[0]->{add_file}}); + push @pages, $_ foreach (@{$patch->{summary}->[0]->{remove_file}}); + foreach my $f (@pages) { + $f = $f->{content} if ref $f; + $f =~ s,^\s+,,; $f =~ s,\s+$,,; # cut whitespace + + push @files, $f; + } + foreach my $p (@{$patch->{summary}->[0]->{move}}) { + push @files, $p->{from}; + } + + foreach my $f (@files) { + my $d = defined $config{'diffurl'} ? $config{'diffurl'} : ""; + my $ef = uri_escape_utf8($f); + $d =~ s/\[\[file\]\]/$ef/go; + $d =~ s/\[\[hash\]\]/$hash/go; + + push @pg, { + page => pagename($f), + diffurl => $d, + }; + } + next unless (scalar @pg > 0); + + my @message; + push @message, { line => $_ } foreach (@{$patch->{name}}); + + my $committype; + my $author; + if ($patch->{author} =~ /(.*)\@web$/) { + $author = $1; + $committype = "web"; + } + else { + $author=$patch->{author}; + $committype = "darcs"; + } + + push @ret, { + rev => $patch->{hash}, + user => $author, + committype => $committype, + when => $when, + message => [@message], + pages => [@pg], + }; + } + + return @ret; +} + +sub rcs_diff ($;$) { + my $rev=shift; + my $maxlines=shift; + my @lines; + my $repodir=$config{srcdir}; + foreach my $line (`darcs diff --repodir $repodir --match 'hash $rev'`) { + if (@lines || $line=~/^diff/) { + last if defined $maxlines && @lines == $maxlines; + push @lines, $line."\n"; + } + } + if (wantarray) { + return @lines; + } + else { + return join("", @lines); + } +} + +sub rcs_getctime ($) { + my $file=shift; + + eval q{use Date::Parse}; + eval q{use XML::Simple}; + local $/=undef; + + my $child = open(LOG, "-|"); + if (! $child) { + exec("darcs", "changes", "--xml", "--reverse", + "--repodir", $config{srcdir}, $file) + || error("'darcs changes $file' failed to run"); + } + + my $data; + { + local $/=undef; + $data = ; + } + close LOG; + + my $log = XMLin($data, ForceArray => 1); + + my $datestr = $log->{patch}[0]->{local_date}; + + if (! defined $datestr) { + warn "failed to get ctime for $file"; + return 0; + } + + my $date = str2time($datestr); + + debug("ctime for '$file': ". localtime($date)); + + return $date; +} + +sub rcs_getmtime ($) { + error "rcs_getmtime is not implemented for darcs\n"; # TODO +} + +1 diff --git a/IkiWiki/Plugin/date.pm b/IkiWiki/Plugin/date.pm new file mode 100644 index 000000000..ea5c9a9c5 --- /dev/null +++ b/IkiWiki/Plugin/date.pm @@ -0,0 +1,34 @@ +#!/usr/bin/perl +package IkiWiki::Plugin::date; + +use warnings; +use strict; +use IkiWiki 3.00; + +sub import { + hook(type => "getsetup", id => "date", call => \&getsetup); + hook(type => "preprocess", id => "date", call => \&preprocess); +} + +sub getsetup () { + return + plugin => { + safe => 1, + rebuild => undef, + section => "widget", + }, +} + +sub preprocess (@) { + my $str=shift; + + eval q{use Date::Parse}; + error $@ if $@; + my $time = str2time($str); + if (! defined $time) { + error("unable to parse $str"); + } + return displaytime($time); +} + +1 diff --git a/IkiWiki/Plugin/ddate.pm b/IkiWiki/Plugin/ddate.pm new file mode 100644 index 000000000..bb77ce59f --- /dev/null +++ b/IkiWiki/Plugin/ddate.pm @@ -0,0 +1,41 @@ +#!/usr/bin/perl +# Discordian date support fnord ikiwiki. +package IkiWiki::Plugin::ddate; + +use IkiWiki 3.00; +no warnings; + +sub import { + hook(type => "getsetup", id => "ddate", call => \&getsetup); +} + +sub getsetup { + return + plugin => { + safe => 1, + rebuild => 1, + }, +} + +sub IkiWiki::formattime ($;$) { + my $time=shift; + my $format=shift; + if (! defined $format) { + $format=$config{timeformat}; + if ($format eq '%c') { + $format='on %A, the %e of %B, %Y. %N%nCelebrate %H'; + } + } + eval q{ + use DateTime; + use DateTime::Calendar::Discordian; + }; + if ($@) { + return "some time or other ($@ -- hail Eris!)"; + } + my $dt = DateTime->from_epoch(epoch => $time); + my $dd = DateTime::Calendar::Discordian->from_object(object => $dt); + return $dd->strftime($format); +} + +5 diff --git a/IkiWiki/Plugin/editdiff.pm b/IkiWiki/Plugin/editdiff.pm new file mode 100644 index 000000000..015ce9c14 --- /dev/null +++ b/IkiWiki/Plugin/editdiff.pm @@ -0,0 +1,78 @@ +#!/usr/bin/perl +# This plugin adds a "Diff" button to the page edit form. +package IkiWiki::Plugin::editdiff; + +use warnings; +use strict; +use IkiWiki 3.00; +use HTML::Entities; +use IPC::Open2; + +sub import { + hook(type => "getsetup", id => "editdiff", call => \&getsetup); + hook(type => "formbuilder_setup", id => "editdiff", + call => \&formbuilder_setup); +} + +sub getsetup () { + return + plugin => { + safe => 1, + rebuild => 0, + section => "web", + }, +} + +sub diff ($$) { + my $orig=shift; + my $content=shift; + + my $sigpipe=0; + $SIG{PIPE} = sub { $sigpipe=1; }; + + my $pid = open2(*DIFFOUT, *DIFFIN, 'diff', '-u', $orig, '-'); + binmode($_, ':utf8') foreach (*DIFFIN, *DIFFOUT); + + print DIFFIN $content; + close DIFFIN; + my $ret=''; + while () { + if (defined $ret) { + $ret.=$_; + } + elsif (/^\@\@/) { + $ret=$_; + } + } + close DIFFOUT; + waitpid $pid, 0; + + $SIG{PIPE}="default"; + return "couldn't run diff\n" if $sigpipe; + + return "
".encode_entities($ret)."
"; +} + +sub formbuilder_setup { + my %params=@_; + my $form=$params{form}; + + return if ! defined $form->field("do") || $form->field("do") ne "edit"; + + my $page=$form->field("page"); + $page = IkiWiki::possibly_foolish_untaint($page); + return unless exists $pagesources{$page}; + + push @{$params{buttons}}, "Diff"; + + if ($form->submitted eq "Diff") { + my $content=$form->field('editcontent'); + $content=~s/\r\n/\n/g; + $content=~s/\r/\n/g; + + my $diff = diff(srcfile($pagesources{$page}), $content); + $form->tmpl_param("page_diff", $diff); + } +} + +1 diff --git a/IkiWiki/Plugin/editpage.pm b/IkiWiki/Plugin/editpage.pm new file mode 100644 index 000000000..3047869c4 --- /dev/null +++ b/IkiWiki/Plugin/editpage.pm @@ -0,0 +1,476 @@ +#!/usr/bin/perl +package IkiWiki::Plugin::editpage; + +use warnings; +use strict; +use IkiWiki; +use open qw{:utf8 :std}; + +sub import { + hook(type => "getsetup", id => "editpage", call => \&getsetup); + hook(type => "refresh", id => "editpage", call => \&refresh); + hook(type => "sessioncgi", id => "editpage", call => \&IkiWiki::cgi_editpage); +} + +sub getsetup () { + return + plugin => { + safe => 1, + rebuild => 1, + section => "core", + }, +} + +sub refresh () { + if (exists $wikistate{editpage} && exists $wikistate{editpage}{previews}) { + # Expire old preview files after one hour. + my $expire=time - (60 * 60); + + my @previews; + foreach my $file (@{$wikistate{editpage}{previews}}) { + my $mtime=(stat("$config{destdir}/$file"))[9]; + if (defined $mtime && $mtime <= $expire) { + # Avoid deleting a preview that was later saved. + my $delete=1; + foreach my $page (keys %renderedfiles) { + if (grep { $_ eq $file } @{$renderedfiles{$page}}) { + $delete=0; + } + } + if ($delete) { + debug(sprintf(gettext("removing old preview %s"), $file)); + IkiWiki::prune("$config{destdir}/$file", $config{destdir}); + } + } + elsif (defined $mtime) { + push @previews, $file; + } + } + $wikistate{editpage}{previews}=\@previews; + } +} + +# Back to ikiwiki namespace for the rest, this code is very much +# internal to ikiwiki even though it's separated into a plugin, +# and other plugins use the function below. +package IkiWiki; + +sub cgi_editpage ($$) { + my $q=shift; + my $session=shift; + + my $do=$q->param('do'); + return unless $do eq 'create' || $do eq 'edit'; + + decode_cgi_utf8($q); + + my @fields=qw(do rcsinfo subpage from page type editcontent + editmessage subscribe); + my @buttons=("Save Page", "Preview", "Cancel"); + eval q{use CGI::FormBuilder}; + error($@) if $@; + my $form = CGI::FormBuilder->new( + fields => \@fields, + charset => "utf-8", + method => 'POST', + required => [qw{editcontent}], + javascript => 0, + params => $q, + action => IkiWiki::cgiurl(), + header => 0, + table => 0, + template => { template("editpage.tmpl") }, + ); + + decode_form_utf8($form); + run_hooks(formbuilder_setup => sub { + shift->(form => $form, cgi => $q, session => $session, + buttons => \@buttons); + }); + decode_form_utf8($form); + + # This untaint is safe because we check file_pruned and + # wiki_file_regexp. + my ($page)=$form->field('page')=~/$config{wiki_file_regexp}/; + if (! defined $page) { + error(gettext("bad page name")); + } + $page=possibly_foolish_untaint($page); + my $absolute=($page =~ s#^/+##); # absolute name used to force location + if (! defined $page || ! length $page || + file_pruned($page)) { + error(gettext("bad page name")); + } + + my $baseurl = urlto($page); + + my $from; + if (defined $form->field('from')) { + ($from)=$form->field('from')=~/$config{wiki_file_regexp}/; + } + + my $file; + my $type; + if (exists $pagesources{$page} && $form->field("do") ne "create") { + $file=$pagesources{$page}; + $type=pagetype($file); + if (! defined $type || $type=~/^_/) { + error(sprintf(gettext("%s is not an editable page"), $page)); + } + if (! $form->submitted) { + $form->field(name => "rcsinfo", + value => rcs_prepedit($file), force => 1); + } + $form->field(name => "editcontent", validate => '/.*/'); + } + else { + $type=$form->param('type'); + if (defined $type && length $type && $hooks{htmlize}{$type}) { + $type=possibly_foolish_untaint($type); + } + elsif (defined $from && exists $pagesources{$from}) { + # favor the type of linking page + $type=pagetype($pagesources{$from}); + } + $type=$config{default_pageext} + if ! defined $type || $type=~/^_/; # not internal type + $file=newpagefile($page, $type); + if (! $form->submitted) { + $form->field(name => "rcsinfo", value => "", force => 1); + } + $form->field(name => "editcontent", validate => '/.+/'); + } + + $form->field(name => "do", type => 'hidden'); + $form->field(name => "sid", type => "hidden", value => $session->id, + force => 1); + $form->field(name => "from", type => 'hidden'); + $form->field(name => "rcsinfo", type => 'hidden'); + $form->field(name => "subpage", type => 'hidden'); + $form->field(name => "page", value => $page, force => 1); + $form->field(name => "type", value => $type, force => 1); + $form->field(name => "editmessage", type => "text", size => 80); + $form->field(name => "editcontent", type => "textarea", rows => 20, + cols => 80); + $form->tmpl_param("can_commit", $config{rcs}); + $form->tmpl_param("helponformattinglink", + htmllink($page, $page, "ikiwiki/formatting", + noimageinline => 1, + linktext => "FormattingHelp")); + + my $cansubscribe=IkiWiki::Plugin::notifyemail->can("subscribe") + && IkiWiki::Plugin::comments->can("import") + && defined $session->param('name'); + if ($cansubscribe) { + $form->field(name => "subscribe", type => "checkbox", + options => [gettext("email comments to me")]); + } + else { + $form->field(name => "subscribe", type => 'hidden'); + } + + my $previewing=0; + if ($form->submitted eq "Cancel") { + if ($form->field("do") eq "create" && defined $from) { + redirect($q, urlto($from)); + } + elsif ($form->field("do") eq "create") { + redirect($q, baseurl(undef)); + } + else { + redirect($q, $baseurl); + } + exit; + } + elsif ($form->submitted eq "Preview") { + $previewing=1; + + my $new=not exists $pagesources{$page}; + # temporarily record its type + $pagesources{$page}=$page.".".$type if $new; + my %wasrendered=map { $_ => 1 } @{$renderedfiles{$page}}; + + my $content=$form->field('editcontent'); + + run_hooks(editcontent => sub { + $content=shift->( + content => $content, + page => $page, + cgi => $q, + session => $session, + ); + }); + my $preview=htmlize($page, $page, $type, + linkify($page, $page, + preprocess($page, $page, + filter($page, $page, $content), 0, 1))); + run_hooks(format => sub { + $preview=shift->( + page => $page, + content => $preview, + ); + }); + $form->tmpl_param("page_preview", $preview); + + # Previewing may have created files on disk. + # Keep a list of these to be deleted later. + my %previews = map { $_ => 1 } @{$wikistate{editpage}{previews}}; + foreach my $f (@{$renderedfiles{$page}}) { + $previews{$f}=1 unless $wasrendered{$f}; + } + + # Throw out any other state changes made during previewing, + # and save the previews list. + loadindex(); + @{$wikistate{editpage}{previews}} = keys %previews; + saveindex(); + } + elsif ($form->submitted eq "Save Page") { + $form->tmpl_param("page_preview", ""); + } + + if ($form->submitted ne "Save Page" || ! $form->validate) { + if ($form->field("do") eq "create") { + my @page_locs; + my $best_loc; + if (! defined $from || ! length $from || + $from ne $form->field('from') || + file_pruned($from) || + $absolute || + $form->submitted) { + @page_locs=$best_loc=$page; + unshift @page_locs, lc($page) + if ! $form->submitted && lc($page) ne $page; + } + elsif (lc $page eq lc $config{discussionpage}) { + @page_locs=$best_loc="$from/".lc($page); + } + else { + my $dir=$from."/"; + $dir=~s![^/]+/+$!!; + + if ((defined $form->field('subpage') && + length $form->field('subpage'))) { + $best_loc="$from/$page"; + } + else { + $best_loc=$dir.$page; + } + + my $mixedcase=lc($page) ne $page; + + push @page_locs, $dir.lc($page) if $mixedcase; + push @page_locs, $dir.$page; + push @page_locs, $from."/".lc($page) if $mixedcase; + push @page_locs, $from."/".$page; + while (length $dir) { + $dir=~s![^/]+/+$!!; + push @page_locs, $dir.lc($page) if $mixedcase; + push @page_locs, $dir.$page; + } + + my $userpage=IkiWiki::userpage($page); + push @page_locs, $userpage + if ! grep { $_ eq $userpage } @page_locs; + } + + @page_locs = grep { + ! exists $pagecase{lc $_} + } @page_locs; + if (! @page_locs) { + # hmm, someone else made the page in the + # meantime? + if ($previewing) { + # let them go ahead with the edit + # and resolve the conflict at save + # time + @page_locs=$page; + } + else { + redirect($q, $baseurl); + exit; + } + } + + my @editable_locs = grep { + check_canedit($_, $q, $session, 1) + } @page_locs; + if (! @editable_locs) { + # now let it throw an error, or prompt for + # login + map { check_canedit($_, $q, $session) } + ($best_loc, @page_locs); + } + + my @page_types; + if (exists $hooks{htmlize}) { + foreach my $key (grep { !/^_/ } keys %{$hooks{htmlize}}) { + push @page_types, [$key, $hooks{htmlize}{$key}{longname} || $key]; + } + } + @page_types=sort @page_types; + + $form->tmpl_param("page_select", 1); + $form->field(name => "page", type => 'select', + options => [ map { [ $_, pagetitle($_, 1) ] } @editable_locs ], + value => $best_loc); + $form->field(name => "type", type => 'select', + options => \@page_types); + $form->title(sprintf(gettext("creating %s"), pagetitle(basename($page)))); + + } + elsif ($form->field("do") eq "edit") { + check_canedit($page, $q, $session); + if (! defined $form->field('editcontent') || + ! length $form->field('editcontent')) { + my $content=""; + if (exists $pagesources{$page}) { + $content=readfile(srcfile($pagesources{$page})); + $content=~s/\n/\r\n/g; + } + $form->field(name => "editcontent", value => $content, + force => 1); + } + $form->tmpl_param("page_select", 0); + $form->field(name => "page", type => 'hidden'); + $form->field(name => "type", type => 'hidden'); + $form->title(sprintf(gettext("editing %s"), pagetitle(basename($page)))); + } + + showform($form, \@buttons, $session, $q, page => $page); + } + else { + # save page + check_canedit($page, $q, $session); + checksessionexpiry($q, $session, $q->param('sid')); + + my $exists=-e "$config{srcdir}/$file"; + + if ($form->field("do") ne "create" && ! $exists && + ! defined srcfile($file, 1)) { + $form->tmpl_param("message", template("editpagegone.tmpl")->output); + $form->field(name => "do", value => "create", force => 1); + $form->tmpl_param("page_select", 0); + $form->field(name => "page", type => 'hidden'); + $form->field(name => "type", type => 'hidden'); + $form->title(sprintf(gettext("editing %s"), $page)); + showform($form, \@buttons, $session, $q, + page => $page); + exit; + } + elsif ($form->field("do") eq "create" && $exists) { + $form->tmpl_param("message", template("editcreationconflict.tmpl")->output); + $form->field(name => "do", value => "edit", force => 1); + $form->tmpl_param("page_select", 0); + $form->field(name => "page", type => 'hidden'); + $form->field(name => "type", type => 'hidden'); + $form->title(sprintf(gettext("editing %s"), $page)); + $form->field("editcontent", + value => readfile("$config{srcdir}/$file"). + "\n\n\n".$form->field("editcontent"), + force => 1); + showform($form, \@buttons, $session, $q, + page => $page); + exit; + } + + my $message=""; + if (defined $form->field('editmessage') && + length $form->field('editmessage')) { + $message=$form->field('editmessage'); + } + + my $content=$form->field('editcontent'); + check_content(content => $content, page => $page, + cgi => $q, session => $session, + subject => $message); + run_hooks(editcontent => sub { + $content=shift->( + content => $content, + page => $page, + cgi => $q, + session => $session, + ); + }); + $content=~s/\r\n/\n/g; + $content=~s/\r/\n/g; + $content.="\n" if $content !~ /\n$/; + + $config{cgi}=0; # avoid cgi error message + eval { writefile($file, $config{srcdir}, $content) }; + $config{cgi}=1; + if ($@) { + # save $@ in case a called function clobbers it + my $error = $@; + $form->field(name => "rcsinfo", value => rcs_prepedit($file), + force => 1); + my $mtemplate=template("editfailedsave.tmpl"); + $mtemplate->param(error_message => $error); + $form->tmpl_param("message", $mtemplate->output); + $form->field("editcontent", value => $content, force => 1); + $form->tmpl_param("page_select", 0); + $form->field(name => "page", type => 'hidden'); + $form->field(name => "type", type => 'hidden'); + $form->title(sprintf(gettext("editing %s"), $page)); + showform($form, \@buttons, $session, $q, + page => $page); + exit; + } + + my $conflict; + if ($config{rcs}) { + if (! $exists) { + rcs_add($file); + } + + # Prevent deadlock with post-commit hook by + # signaling to it that it should not try to + # do anything. + disable_commit_hook(); + $conflict=rcs_commit( + file => $file, + message => $message, + token => $form->field("rcsinfo"), + session => $session, + ); + enable_commit_hook(); + rcs_update(); + } + + # Refresh even if there was a conflict, since other changes + # may have been committed while the post-commit hook was + # disabled. + require IkiWiki::Render; + refresh(); + saveindex(); + + if (defined $conflict) { + $form->field(name => "rcsinfo", value => rcs_prepedit($file), + force => 1); + $form->tmpl_param("message", template("editconflict.tmpl")->output); + $form->field("editcontent", value => $conflict, force => 1); + $form->field("do", "edit", force => 1); + $form->tmpl_param("page_select", 0); + $form->field(name => "page", type => 'hidden'); + $form->field(name => "type", type => 'hidden'); + $form->title(sprintf(gettext("editing %s"), $page)); + showform($form, \@buttons, $session, $q, + page => $page); + } + else { + # The trailing question mark tries to avoid broken + # caches and get the most recent version of the page. + redirect($q, $baseurl."?updated"); + } + + if ($cansubscribe && length $form->field("subscribe")) { + my $subspec="comment($page)"; + IkiWiki::Plugin::notifyemail::subscribe( + $session->param('name'), $subspec); + } + } + + exit; +} + +1 diff --git a/IkiWiki/Plugin/edittemplate.pm b/IkiWiki/Plugin/edittemplate.pm new file mode 100644 index 000000000..c2a8da29f --- /dev/null +++ b/IkiWiki/Plugin/edittemplate.pm @@ -0,0 +1,164 @@ +#!/usr/bin/perl +package IkiWiki::Plugin::edittemplate; + +use warnings; +use strict; +use IkiWiki 3.00; +use HTML::Template; +use Encode; + +sub import { + hook(type => "getsetup", id => "edittemplate", + call => \&getsetup); + hook(type => "needsbuild", id => "edittemplate", + call => \&needsbuild); + hook(type => "preprocess", id => "edittemplate", + call => \&preprocess); + hook(type => "formbuilder", id => "edittemplate", + call => \&formbuilder); +} + +sub getsetup () { + return + plugin => { + safe => 1, + rebuild => undef, + section => "web", + }, +} + +sub needsbuild (@) { + my $needsbuild=shift; + + foreach my $page (keys %pagestate) { + if (exists $pagestate{$page}{edittemplate}) { + if (exists $pagesources{$page} && + grep { $_ eq $pagesources{$page} } @$needsbuild) { + # remove state, it will be re-added + # if the preprocessor directive is still + # there during the rebuild + delete $pagestate{$page}{edittemplate}; + } + } + } + + return $needsbuild; +} + +sub preprocess (@) { + my %params=@_; + + return "" if $params{page} ne $params{destpage}; + + if (! exists $params{template} || ! length($params{template})) { + error gettext("template not specified") + } + if (! exists $params{match} || ! length($params{match})) { + error gettext("match not specified") + } + + my $link=linkpage($params{template}); + add_depends($params{page}, $link, deptype("presence")); + my $bestlink=bestlink($params{page}, $link); + if (! length $bestlink) { + add_depends($params{page}, "templates/$link", deptype("presence")); + $link="/templates/".$link; + $bestlink=bestlink($params{page}, $link); + } + $pagestate{$params{page}}{edittemplate}{$params{match}}=$bestlink; + + return "" if ($params{silent} && IkiWiki::yesno($params{silent})) && + length $bestlink; + return sprintf(gettext("edittemplate %s registered for %s"), + htmllink($params{page}, $params{destpage}, $link), + $params{match}); +} + +sub formbuilder (@) { + my %params=@_; + my $form=$params{form}; + + return if $form->field("do") ne "create" || + (defined $form->field("editcontent") && length $form->field("editcontent")); + + my $page=$form->field("page"); + + # The tricky bit here is that $page is probably just the base + # page name, without any subdir, but the pagespec for a template + # probably does include the subdir (ie, "bugs/*"). We don't know + # what subdir the user will pick to put the page in. So, try them + # all, starting with the one that was made default. + my @page_locs=$page; + foreach my $field ($form->field) { + if ($field eq 'page') { + @page_locs=$field->def_value; + + # FormBuilder is on the bad crack. See #551499 + my @options=map { ref $_ ? @$_ : $_ } $field->options; + + push @page_locs, @options; + } + } + foreach my $p (@page_locs) { + foreach my $registering_page (keys %pagestate) { + if (exists $pagestate{$registering_page}{edittemplate}) { + foreach my $pagespec (sort keys %{$pagestate{$registering_page}{edittemplate}}) { + if (pagespec_match($p, $pagespec, location => $registering_page)) { + my $template=$pagestate{$registering_page}{edittemplate}{$pagespec}; + $form->field(name => "editcontent", + value => filltemplate($template, $page)); + my $type=pagetype($pagesources{$template}) + if $pagesources{$template}; + $form->field(name => "type", + value => $type) + if defined $type; + return; + } + } + } + } + } +} + +sub filltemplate ($$) { + my $template_page=shift; + my $page=shift; + + my $template; + eval { + # force page name absolute so it doesn't look in templates/ + $template=template("/".$template_page); + }; + if ($@) { + # gettext can clobber $@ + my $error = $@; + # Indicate that the earlier preprocessor directive set + # up a template that doesn't work. + return "[[!edittemplate ".gettext("failed to process template:")." $error]]"; + } + + $template->param(name => $page); + + if ($template->query(name => 'uuid')) { + my $uuid; + if (open(my $fh, "<", "/proc/sys/kernel/random/uuid")) { + $uuid = <$fh>; + chomp $uuid; + close $fh; + } + else { + eval { + require UUID::Tiny; + $uuid = UUID::Tiny::create_uuid_as_string(UUID::Tiny::UUID_V4()); + }; + } + $template->param(uuid => $uuid); + } + + my $time = time(); + $template->param(time => IkiWiki::date_3339($time)); + + return $template->output; +} + +1 diff --git a/IkiWiki/Plugin/embed.pm b/IkiWiki/Plugin/embed.pm new file mode 100644 index 000000000..a7d38358f --- /dev/null +++ b/IkiWiki/Plugin/embed.pm @@ -0,0 +1,77 @@ +#!/usr/bin/perl +package IkiWiki::Plugin::embed; + +use warnings; +use strict; +use IkiWiki 3.00; + +my $attribr=qr/[^<>"]+/; + +# regexp matching known-safe html +my $safehtml=qr{( + # google maps + <\s*iframe\s+width="\d+"\s+height="\d+"\s+frameborder="$attribr"\s+ + scrolling="$attribr"\s+marginheight="\d+"\s+marginwidth="\d+"\s+ + src="http://maps.google.com/\?$attribr"\s*>\s* + + | + + # youtube + <\s*object\s+width="\d+"\s+height="\d+"\s*>\s* + <\s*param\s+name="movie"\s+value="http://www.youtube.com/v/$attribr"\s*>\s* + \s* + <\s*param\s+name="wmode"\s+value="transparent"\s*>\s*\s* + \s*\s* + + | + + # google video + <\s*embed\s+style="\s*width:\d+px;\s+height:\d+px;\s*"\s+id="$attribr"\s+ + type="application/x-shockwave-flash"\s+ + src="http://video.google.com/googleplayer.swf\?$attribr"\s+ + flashvars=""\s*>\s* + + | + + # google calendar + <\s*iframe\s+src="http://www.google.com/calendar/embed\?src=$attribr"\s+ + style="\s*border-width:\d+\s*"\s+width="\d+"\s+frameborder="\d+"\s* + height="\d+"\s*>\s* +)}sx; + +my @embedded; + +sub import { + hook(type => "getsetup", id => "embed", call => \&getsetup); + hook(type => "filter", id => "embed", call => \&filter); +} + +sub getsetup () { + return + plugin => { + safe => 1, + rebuild => undef, + }, +} + +sub embed ($) { + hook(type => "format", id => "embed", call => \&format) unless @embedded; + push @embedded, shift; + return "
"; +} + +sub filter (@) { + my %params=@_; + $params{content} =~ s/$safehtml/embed($1)/eg; + return $params{content}; +} + +sub format (@) { + my %params=@_; + $params{content} =~ s/
<\/div>/$embedded[$1]/eg; + return $params{content}; +} + +1 diff --git a/IkiWiki/Plugin/external.pm b/IkiWiki/Plugin/external.pm new file mode 100644 index 000000000..a4cc1dd3c --- /dev/null +++ b/IkiWiki/Plugin/external.pm @@ -0,0 +1,255 @@ +#!/usr/bin/perl +# Support for external plugins written in other languages. +# Communication via XML RPC to a pipe. +# See externaldemo for an example of a plugin that uses this. +package IkiWiki::Plugin::external; + +use warnings; +use strict; +use IkiWiki 3.00; +use RPC::XML; +use IPC::Open2; +use IO::Handle; + +my %plugins; + +sub import { + my $self=shift; + my $plugin=shift; + return unless defined $plugin; + + my ($plugin_read, $plugin_write); + my $pid = open2($plugin_read, $plugin_write, + IkiWiki::possibly_foolish_untaint($plugin)); + + # open2 doesn't respect "use open ':utf8'" + binmode($plugin_read, ':utf8'); + binmode($plugin_write, ':utf8'); + + $plugins{$plugin}={in => $plugin_read, out => $plugin_write, pid => $pid, + accum => ""}; + + $RPC::XML::ENCODING="utf-8"; + $RPC::XML::FORCE_STRING_ENCODING="true"; + + rpc_call($plugins{$plugin}, "import"); +} + +sub rpc_write ($$) { + my $fh=shift; + my $string=shift; + + $fh->print($string."\n"); + $fh->flush; +} + +sub rpc_call ($$;@) { + my $plugin=shift; + my $command=shift; + + # send the command + my $req=RPC::XML::request->new($command, @_); + rpc_write($plugin->{out}, $req->as_string); + + # process incoming rpc until a result is available + while ($_ = $plugin->{in}->getline) { + $plugin->{accum}.=$_; + while ($plugin->{accum} =~ /^\s*(<\?xml\s.*?<\/(?:methodCall|methodResponse)>)\n(.*)/s) { + $plugin->{accum}=$2; + my $parser; + eval q{ + use RPC::XML::ParserFactory; + $parser = RPC::XML::ParserFactory->new; + }; + if ($@) { + # old interface + eval q{ + use RPC::XML::Parser; + $parser = RPC::XML::Parser->new; + }; + } + my $r=$parser->parse($1); + error("XML RPC parser failure: $r") unless ref $r; + if ($r->isa('RPC::XML::response')) { + my $value=$r->value; + if ($r->is_fault($value)) { + # throw the error as best we can + print STDERR $value->string."\n"; + return ""; + } + elsif ($value->isa('RPC::XML::array')) { + return @{$value->value}; + } + elsif ($value->isa('RPC::XML::struct')) { + my %hash=%{$value->value}; + + # XML-RPC v1 does not allow for + # nil/null/None/undef values to be + # transmitted. The extension + # is the right fix, but for + # back-compat, let external plugins send + # a hash with one key "null" pointing + # to an empty string. + if (exists $hash{null} && + $hash{null} eq "" && + int(keys(%hash)) == 1) { + return undef; + } + + return %hash; + } + else { + return $value->value; + } + } + + my $name=$r->name; + my @args=map { $_->value } @{$r->args}; + + # When dispatching a function, first look in + # IkiWiki::RPC::XML. This allows overriding + # IkiWiki functions with RPC friendly versions. + my $ret; + if (exists $IkiWiki::RPC::XML::{$name}) { + $ret=$IkiWiki::RPC::XML::{$name}($plugin, @args); + } + elsif (exists $IkiWiki::{$name}) { + $ret=$IkiWiki::{$name}(@args); + } + else { + error("XML RPC call error, unknown function: $name"); + } + + # XML-RPC v1 does not allow for nil/null/None/undef + # values to be transmitted, so until XML::RPC::Parser + # honours v2 (), send a hash with one key "null" + # pointing to an empty string. + if (! defined $ret) { + $ret={"null" => ""}; + } + + my $string=eval { RPC::XML::response->new($ret)->as_string }; + if ($@ && ref $ret) { + # One common reason for serialisation to + # fail is a complex return type that cannot + # be represented as an XML RPC response. + # Handle this case by just returning 1. + $string=eval { RPC::XML::response->new(1)->as_string }; + } + if ($@) { + error("XML response serialisation failed: $@"); + } + rpc_write($plugin->{out}, $string); + } + } + + return undef; +} + +package IkiWiki::RPC::XML; +use Memoize; + +sub getvar ($$$) { + my $plugin=shift; + my $varname="IkiWiki::".shift; + my $key=shift; + + no strict 'refs'; + my $ret=$varname->{$key}; + use strict 'refs'; + return $ret; +} + +sub setvar ($$$;@) { + my $plugin=shift; + my $varname="IkiWiki::".shift; + my $key=shift; + my $value=shift; + + no strict 'refs'; + my $ret=$varname->{$key}=$value; + use strict 'refs'; + return $ret; +} + +sub getstate ($$$$) { + my $plugin=shift; + my $page=shift; + my $id=shift; + my $key=shift; + + return $IkiWiki::pagestate{$page}{$id}{$key}; +} + +sub setstate ($$$$;@) { + my $plugin=shift; + my $page=shift; + my $id=shift; + my $key=shift; + my $value=shift; + + return $IkiWiki::pagestate{$page}{$id}{$key}=$value; +} + +sub getargv ($) { + my $plugin=shift; + + return \@ARGV; +} + +sub setargv ($@) { + my $plugin=shift; + my $array=shift; + + @ARGV=@$array; +} + +sub inject ($@) { + # Bind a given perl function name to a particular RPC request. + my $plugin=shift; + my %params=@_; + + if (! exists $params{name} || ! exists $params{call}) { + die "inject needs name and call parameters"; + } + my $sub = sub { + IkiWiki::Plugin::external::rpc_call($plugin, $params{call}, @_) + }; + $sub=memoize($sub) if $params{memoize}; + + # This will add it to the symbol table even if not present. + no warnings; + eval qq{*$params{name}=\$sub}; + use warnings; + + # This will ensure that everywhere it was exported to sees + # the injected version. + IkiWiki::inject(name => $params{name}, call => $sub); + return 1; +} + +sub hook ($@) { + # the call parameter is a function name to call, since XML RPC + # cannot pass a function reference + my $plugin=shift; + my %params=@_; + + my $callback=$params{call}; + delete $params{call}; + + IkiWiki::hook(%params, call => sub { + IkiWiki::Plugin::external::rpc_call($plugin, $callback, @_); + }); +} + +sub pagespec_match ($@) { + # convert return object into a XML RPC boolean + my $plugin=shift; + my $page=shift; + my $spec=shift; + + return RPC::XML::boolean->new(0 + IkiWiki::pagespec_match( + $page, $spec, @_)); +} + +1 diff --git a/IkiWiki/Plugin/favicon.pm b/IkiWiki/Plugin/favicon.pm new file mode 100644 index 000000000..6060914c5 --- /dev/null +++ b/IkiWiki/Plugin/favicon.pm @@ -0,0 +1,33 @@ +#!/usr/bin/perl +# favicon plugin. + +package IkiWiki::Plugin::favicon; + +use warnings; +use strict; +use IkiWiki 3.00; + +sub import { + hook(type => "getsetup", id => "favicon", call => \&getsetup); + hook(type => "pagetemplate", id => "favicon", call => \&pagetemplate); +} + +sub getsetup () { + return + plugin => { + safe => 1, + rebuild => 1, + }, +} + +sub pagetemplate (@) { + my %params=@_; + + my $template=$params{template}; + + if ($template->query(name => "favicon")) { + $template->param(favicon => "favicon.ico"); + } +} + +1 diff --git a/IkiWiki/Plugin/filecheck.pm b/IkiWiki/Plugin/filecheck.pm new file mode 100644 index 000000000..6e6528398 --- /dev/null +++ b/IkiWiki/Plugin/filecheck.pm @@ -0,0 +1,224 @@ +#!/usr/bin/perl +package IkiWiki::Plugin::filecheck; + +use warnings; +use strict; +use IkiWiki 3.00; + +my %units=( # size in bytes + B => 1, + byte => 1, + KB => 2 ** 10, + kilobyte => 2 ** 10, + K => 2 ** 10, + KB => 2 ** 10, + kilobyte => 2 ** 10, + M => 2 ** 20, + MB => 2 ** 20, + megabyte => 2 ** 20, + G => 2 ** 30, + GB => 2 ** 30, + gigabyte => 2 ** 30, + T => 2 ** 40, + TB => 2 ** 40, + terabyte => 2 ** 40, + P => 2 ** 50, + PB => 2 ** 50, + petabyte => 2 ** 50, + E => 2 ** 60, + EB => 2 ** 60, + exabyte => 2 ** 60, + Z => 2 ** 70, + ZB => 2 ** 70, + zettabyte => 2 ** 70, + Y => 2 ** 80, + YB => 2 ** 80, + yottabyte => 2 ** 80, + # ikiwiki, if you find you need larger data quantities, either modify + # yourself to add them, or travel back in time to 2008 and kill me. + # -- Joey +); + +sub import { + hook(type => "getsetup", id => "filecheck", call => \&getsetup); +} + +sub getsetup () { + return + plugin => { + safe => 1, + rebuild => undef, + }, +} + +sub parsesize ($) { + my $size=shift; + + no warnings; + my $base=$size+0; # force to number + use warnings; + foreach my $unit (sort keys %units) { + if ($size=~/[0-9\s]\Q$unit\E$/i) { + return $base * $units{$unit}; + } + } + return $base; +} + +# This is provided for other plugins that want to convert back the other way. +sub humansize ($) { + my $size=shift; + + foreach my $unit (reverse sort { $units{$a} <=> $units{$b} || $b cmp $a } keys %units) { + if ($size / $units{$unit} > 0.25) { + return (int($size / $units{$unit} * 10)/10).$unit; + } + } + return $size; # near zero, or negative +} + +package IkiWiki::PageSpec; + +sub match_maxsize ($$;@) { + my $page=shift; + my $maxsize=eval{IkiWiki::Plugin::filecheck::parsesize(shift)}; + if ($@) { + return IkiWiki::ErrorReason->new("unable to parse maxsize (or number too large)"); + } + + my %params=@_; + my $file=exists $params{file} ? $params{file} : IkiWiki::srcfile($IkiWiki::pagesources{$page}); + if (! defined $file) { + return IkiWiki::ErrorReason->new("file does not exist"); + } + + if (-s $file > $maxsize) { + return IkiWiki::FailReason->new("file too large (".(-s $file)." > $maxsize)"); + } + else { + return IkiWiki::SuccessReason->new("file not too large"); + } +} + +sub match_minsize ($$;@) { + my $page=shift; + my $minsize=eval{IkiWiki::Plugin::filecheck::parsesize(shift)}; + if ($@) { + return IkiWiki::ErrorReason->new("unable to parse minsize (or number too large)"); + } + + my %params=@_; + my $file=exists $params{file} ? $params{file} : IkiWiki::srcfile($IkiWiki::pagesources{$page}); + if (! defined $file) { + return IkiWiki::ErrorReason->new("file does not exist"); + } + + if (-s $file < $minsize) { + return IkiWiki::FailReason->new("file too small"); + } + else { + return IkiWiki::SuccessReason->new("file not too small"); + } +} + +sub match_mimetype ($$;@) { + my $page=shift; + my $wanted=shift; + + my %params=@_; + my $file=exists $params{file} ? $params{file} : IkiWiki::srcfile($IkiWiki::pagesources{$page}); + if (! defined $file) { + return IkiWiki::ErrorReason->new("file does not exist"); + } + + # Get the mime type. + # + # First, try File::Mimeinfo. This is fast, but doesn't recognise + # all files. + eval q{use File::MimeInfo::Magic}; + my $mimeinfo_ok=! $@; + my $mimetype; + if ($mimeinfo_ok) { + $mimetype=File::MimeInfo::Magic::magic($file); + } + + # Fall back to using file, which has a more complete + # magic database. + if (! defined $mimetype) { + open(my $file_h, "-|", "file", "-bi", $file); + $mimetype=<$file_h>; + chomp $mimetype; + close $file_h; + } + if (! defined $mimetype) { + # Fall back to default value. + $mimetype=File::MimeInfo::Magic::default($file) + if $mimeinfo_ok; + if (! defined $mimetype) { + $mimetype="unknown"; + } + } + # Ignore any parameters, we only want the type itself + $mimetype =~ s/;.*//; + + my $regexp=IkiWiki::glob2re($wanted); + if ($mimetype!~$regexp) { + return IkiWiki::FailReason->new("file MIME type is $mimetype, not $wanted"); + } + else { + return IkiWiki::SuccessReason->new("file MIME type is $mimetype"); + } +} + +sub match_virusfree ($$;@) { + my $page=shift; + my $wanted=shift; + + my %params=@_; + my $file=exists $params{file} ? $params{file} : IkiWiki::srcfile($IkiWiki::pagesources{$page}); + if (! defined $file) { + return IkiWiki::ErrorReason->new("file does not exist"); + } + + if (! exists $IkiWiki::config{virus_checker} || + ! length $IkiWiki::config{virus_checker}) { + return IkiWiki::ErrorReason->new("no virus_checker configured"); + } + + # The file needs to be fed into the virus checker on stdin, + # because the file is not world-readable, and if clamdscan is + # used, clamd would fail to read it. + eval q{use IPC::Open2}; + error($@) if $@; + open (IN, "<", $file) || return IkiWiki::ErrorReason->new("failed to read file"); + binmode(IN); + my $sigpipe=0; + $SIG{PIPE} = sub { $sigpipe=1 }; + my $pid=open2(\*CHECKER_OUT, "<&IN", $IkiWiki::config{virus_checker}); + my $reason=; + chomp $reason; + 1 while (); + close(CHECKER_OUT); + waitpid $pid, 0; + $SIG{PIPE}="DEFAULT"; + if ($sigpipe || $?) { + if (! length $reason) { + $reason="virus checker $IkiWiki::config{virus_checker}; failed with no output"; + } + return IkiWiki::FailReason->new("file seems to contain a virus ($reason)"); + } + else { + return IkiWiki::SuccessReason->new("file seems virusfree ($reason)"); + } +} + +sub match_ispage ($$;@) { + my $filename=shift; + + if (defined IkiWiki::pagetype($filename)) { + return IkiWiki::SuccessReason->new("file is a wiki page"); + } + else { + return IkiWiki::FailReason->new("file is not a wiki page"); + } +} diff --git a/IkiWiki/Plugin/flattr.pm b/IkiWiki/Plugin/flattr.pm new file mode 100644 index 000000000..3aee1eb93 --- /dev/null +++ b/IkiWiki/Plugin/flattr.pm @@ -0,0 +1,97 @@ +#!/usr/bin/perl +package IkiWiki::Plugin::flattr; + +use warnings; +use strict; +use IkiWiki 3.00; + +sub import { + hook(type => "getsetup", id => "flattr", call => \&getsetup); + hook(type => "preprocess", id => "flattr", call => \&preprocess); + hook(type => "format", id => "flattr", call => \&format); +} + +sub getsetup () { + return + plugin => { + safe => 1, + rebuild => undef, + }, + flattr_userid => { + type => "string", + example => 'joeyh', + description => "userid or user name to use by default for Flattr buttons", + advanced => 0, + safe => 1, + rebuild => undef, + }, +} + +my %flattr_pages; + +sub preprocess (@) { + my %params=@_; + + $flattr_pages{$params{destpage}}=1; + + my $url=$params{url}; + if (! defined $url) { + $url=urlto($params{page}, "", 1); + } + + my @fields; + foreach my $field (qw{language uid button hidden category tags}) { + if (exists $params{$field}) { + push @fields, "$field:$params{$field}"; + } + } + + return ''. + (exists $params{description} ? $params{description} : ''). + ''; +} + +sub format (@) { + my %params=@_; + + # Add flattr's javascript to pages with flattr buttons. + if ($flattr_pages{$params{page}}) { + if (! ($params{content}=~s!^(]*>)!$1.flattrjs()!em)) { + # no tag, probably in preview mode + $params{content}=flattrjs().$params{content}; + } + } + return $params{content}; +} + +my $js_cached; +sub flattrjs { + return $js_cached if defined $js_cached; + + my $js_url='https://api.flattr.com/js/0.5.0/load.js?mode=auto'; + if (defined $config{flattr_userid}) { + my $userid=$config{flattr_userid}; + $userid=~s/[^-A-Za-z0-9_]//g; # sanitize for inclusion in javascript + $js_url.="&uid=$userid"; + } + + # This is Flattr's standard javascript snippet to include their + # external javascript file, asynchronously. + return $js_cached=<<"EOF"; + +EOF +} + +1 diff --git a/IkiWiki/Plugin/format.pm b/IkiWiki/Plugin/format.pm new file mode 100644 index 000000000..b596bc0a1 --- /dev/null +++ b/IkiWiki/Plugin/format.pm @@ -0,0 +1,54 @@ +#!/usr/bin/perl +package IkiWiki::Plugin::format; + +use warnings; +use strict; +use IkiWiki 3.00; + +sub import { + hook(type => "preprocess", id => "format", call => \&preprocess); + hook(type => "getsetup", id => "format", call => \&getsetup); +} + +sub getsetup () { + return + plugin => { + safe => 1, + rebuild => undef, + section => "widget", + }, +} + +sub preprocess (@) { + my %params=@_; + my $format=shift; + shift; + my $text=IkiWiki::preprocess($params{page}, $params{destpage}, shift); + shift; + + if (! defined $format || ! defined $text) { + error(gettext("must specify format and text")); + } + + # Other plugins can register htmlizeformat hooks to add support + # for page types not suitable for htmlize, or that need special + # processing when included via format. Try them until one succeeds. + my $ret; + IkiWiki::run_hooks(htmlizeformat => sub { + $ret=shift->($format, $text) + unless defined $ret; + }); + + if (defined $ret) { + return $ret; + } + elsif (exists $IkiWiki::hooks{htmlize}{$format}) { + return IkiWiki::htmlize($params{page}, $params{destpage}, + $format, $text); + } + else { + error(sprintf(gettext("unsupported page format %s"), $format)); + } +} + +1 diff --git a/IkiWiki/Plugin/fortune.pm b/IkiWiki/Plugin/fortune.pm new file mode 100644 index 000000000..f481c7eac --- /dev/null +++ b/IkiWiki/Plugin/fortune.pm @@ -0,0 +1,35 @@ +#!/usr/bin/perl +# Include a fortune in a page +package IkiWiki::Plugin::fortune; + +use warnings; +use strict; +use IkiWiki 3.00; + +sub import { + hook(type => "getsetup", id => "fortune", call => \&getsetup); + hook(type => "preprocess", id => "fortune", call => \&preprocess); +} + +sub getsetup () { + return + plugin => { + safe => 1, + rebuild => undef, + section => "widget", + }, +} + +sub preprocess (@) { + $ENV{PATH}="$ENV{PATH}:/usr/games:/usr/local/games"; + my $f = `fortune 2>/dev/null`; + + if ($?) { + error gettext("fortune failed"); + } + else { + return "
$f
\n"; + } +} + +1 diff --git a/IkiWiki/Plugin/getsource.pm b/IkiWiki/Plugin/getsource.pm new file mode 100644 index 000000000..0a21413bd --- /dev/null +++ b/IkiWiki/Plugin/getsource.pm @@ -0,0 +1,94 @@ +#!/usr/bin/perl +package IkiWiki::Plugin::getsource; + +use warnings; +use strict; +use IkiWiki; +use open qw{:utf8 :std}; + +sub import { + hook(type => "getsetup", id => "getsource", call => \&getsetup); + hook(type => "pagetemplate", id => "getsource", call => \&pagetemplate); + hook(type => "cgi", id => "getsource", call => \&cgi_getsource); +} + +sub getsetup () { + return + plugin => { + safe => 1, + rebuild => 1, + section => "web", + }, + getsource_mimetype => { + type => "string", + example => "text/plain; charset=utf-8", + description => "Mime type for returned source.", + safe => 1, + rebuild => 0, + }, +} + +sub pagetemplate (@) { + my %params=@_; + + my $page=$params{page}; + my $template=$params{template}; + + if (length $config{cgiurl}) { + $template->param(getsourceurl => IkiWiki::cgiurl(do => "getsource", page => $page)); + $template->param(have_actions => 1); + } +} + +sub cgi_getsource ($) { + my $cgi=shift; + + return unless defined $cgi->param('do') && + $cgi->param("do") eq "getsource"; + + IkiWiki::decode_cgi_utf8($cgi); + + my $page=$cgi->param('page'); + + if (! defined $page || $page !~ /$config{wiki_file_regexp}/) { + error("invalid page parameter"); + } + + # For %pagesources. + IkiWiki::loadindex(); + + if (! exists $pagesources{$page}) { + IkiWiki::cgi_custom_failure( + $cgi, + "404 Not Found", + IkiWiki::cgitemplate($cgi, gettext("missing page"), + "

". + sprintf(gettext("The page %s does not exist."), + htmllink("", "", $page)). + "

")); + exit; + } + + if (! defined pagetype($pagesources{$page})) { + IkiWiki::cgi_custom_failure( + $cgi->header(-status => "403 Forbidden"), + IkiWiki::cgitemplate($cgi, gettext("not a page"), + "

". + sprintf(gettext("%s is an attachment, not a page."), + htmllink("", "", $page)). + "

")); + exit; + } + + if (! $config{getsource_mimetype}) { + $config{getsource_mimetype} = "text/plain; charset=utf-8"; + } + + print "Content-Type: $config{getsource_mimetype}\r\n"; + print ("\r\n"); + print readfile(srcfile($pagesources{$page})); + + exit 0; +} + +1 diff --git a/IkiWiki/Plugin/git.pm b/IkiWiki/Plugin/git.pm new file mode 100644 index 000000000..75b89e476 --- /dev/null +++ b/IkiWiki/Plugin/git.pm @@ -0,0 +1,956 @@ +#!/usr/bin/perl +package IkiWiki::Plugin::git; + +use warnings; +use strict; +use IkiWiki; +use Encode; +use URI::Escape q{uri_escape_utf8}; +use open qw{:utf8 :std}; + +my $sha1_pattern = qr/[0-9a-fA-F]{40}/; # pattern to validate Git sha1sums +my $dummy_commit_msg = 'dummy commit'; # message to skip in recent changes + +sub import { + hook(type => "checkconfig", id => "git", call => \&checkconfig); + hook(type => "getsetup", id => "git", call => \&getsetup); + hook(type => "genwrapper", id => "git", call => \&genwrapper); + hook(type => "rcs", id => "rcs_update", call => \&rcs_update); + hook(type => "rcs", id => "rcs_prepedit", call => \&rcs_prepedit); + hook(type => "rcs", id => "rcs_commit", call => \&rcs_commit); + hook(type => "rcs", id => "rcs_commit_staged", call => \&rcs_commit_staged); + hook(type => "rcs", id => "rcs_add", call => \&rcs_add); + hook(type => "rcs", id => "rcs_remove", call => \&rcs_remove); + hook(type => "rcs", id => "rcs_rename", call => \&rcs_rename); + hook(type => "rcs", id => "rcs_recentchanges", call => \&rcs_recentchanges); + hook(type => "rcs", id => "rcs_diff", call => \&rcs_diff); + hook(type => "rcs", id => "rcs_getctime", call => \&rcs_getctime); + hook(type => "rcs", id => "rcs_getmtime", call => \&rcs_getmtime); + hook(type => "rcs", id => "rcs_receive", call => \&rcs_receive); + hook(type => "rcs", id => "rcs_preprevert", call => \&rcs_preprevert); + hook(type => "rcs", id => "rcs_revert", call => \&rcs_revert); + hook(type => "rcs", id => "rcs_find_changes", call => \&rcs_find_changes); + hook(type => "rcs", id => "rcs_get_current_rev", call => \&rcs_get_current_rev); +} + +sub checkconfig () { + if (! defined $config{gitorigin_branch}) { + $config{gitorigin_branch}="origin"; + } + if (! defined $config{gitmaster_branch}) { + $config{gitmaster_branch}="master"; + } + if (defined $config{git_wrapper} && + length $config{git_wrapper}) { + push @{$config{wrappers}}, { + wrapper => $config{git_wrapper}, + wrappermode => (defined $config{git_wrappermode} ? $config{git_wrappermode} : "06755"), + wrapper_background_command => $config{git_wrapper_background_command}, + }; + } + + if (defined $config{git_test_receive_wrapper} && + length $config{git_test_receive_wrapper} && + defined $config{untrusted_committers} && + @{$config{untrusted_committers}}) { + push @{$config{wrappers}}, { + test_receive => 1, + wrapper => $config{git_test_receive_wrapper}, + wrappermode => (defined $config{git_wrappermode} ? $config{git_wrappermode} : "06755"), + }; + } + + # Avoid notes, parser does not handle and they only slow things down. + $ENV{GIT_NOTES_REF}=""; + + # Run receive test only if being called by the wrapper, and not + # when generating same. + if ($config{test_receive} && ! exists $config{wrapper}) { + require IkiWiki::Receive; + IkiWiki::Receive::test(); + } +} + +sub getsetup () { + return + plugin => { + safe => 0, # rcs plugin + rebuild => undef, + section => "rcs", + }, + git_wrapper => { + type => "string", + example => "/git/wiki.git/hooks/post-update", + description => "git hook to generate", + safe => 0, # file + rebuild => 0, + }, + git_wrapper_background_command => { + type => "string", + example => "git push github", + description => "shell command for git_wrapper to run, in the background", + safe => 0, # command + rebuild => 0, + }, + git_wrappermode => { + type => "string", + example => '06755', + description => "mode for git_wrapper (can safely be made suid)", + safe => 0, + rebuild => 0, + }, + git_test_receive_wrapper => { + type => "string", + example => "/git/wiki.git/hooks/pre-receive", + description => "git pre-receive hook to generate", + safe => 0, # file + rebuild => 0, + }, + untrusted_committers => { + type => "string", + example => [], + description => "unix users whose commits should be checked by the pre-receive hook", + safe => 0, + rebuild => 0, + }, + historyurl => { + type => "string", + example => "http://git.example.com/gitweb.cgi?p=wiki.git;a=history;f=[[file]];hb=HEAD", + description => "gitweb url to show file history ([[file]] substituted)", + safe => 1, + rebuild => 1, + }, + diffurl => { + type => "string", + example => "http://git.example.com/gitweb.cgi?p=wiki.git;a=blobdiff;f=[[file]];h=[[sha1_to]];hp=[[sha1_from]];hb=[[sha1_commit]];hpb=[[sha1_parent]]", + description => "gitweb url to show a diff ([[file]], [[sha1_to]], [[sha1_from]], [[sha1_commit]], and [[sha1_parent]] substituted)", + safe => 1, + rebuild => 1, + }, + gitorigin_branch => { + type => "string", + example => "origin", + description => "where to pull and push changes (set to empty string to disable)", + safe => 0, # paranoia + rebuild => 0, + }, + gitmaster_branch => { + type => "string", + example => "master", + description => "branch that the wiki is stored in", + safe => 0, # paranoia + rebuild => 0, + }, +} + +sub genwrapper { + if ($config{test_receive}) { + require IkiWiki::Receive; + return IkiWiki::Receive::genwrapper(); + } + else { + return ""; + } +} + +my $git_dir=undef; +my $prefix=undef; + +sub in_git_dir ($$) { + $git_dir=shift; + my @ret=shift->(); + $git_dir=undef; + $prefix=undef; + return @ret; +} + +sub safe_git (&@) { + # Start a child process safely without resorting to /bin/sh. + # Returns command output (in list content) or success state + # (in scalar context), or runs the specified data handler. + + my ($error_handler, $data_handler, @cmdline) = @_; + + my $pid = open my $OUT, "-|"; + + error("Cannot fork: $!") if !defined $pid; + + if (!$pid) { + # In child. + # Git commands want to be in wc. + if (! defined $git_dir) { + chdir $config{srcdir} + or error("cannot chdir to $config{srcdir}: $!"); + } + else { + chdir $git_dir + or error("cannot chdir to $git_dir: $!"); + } + exec @cmdline or error("Cannot exec '@cmdline': $!"); + } + # In parent. + + # git output is probably utf-8 encoded, but may contain + # other encodings or invalidly encoded stuff. So do not rely + # on the normal utf-8 IO layer, decode it by hand. + binmode($OUT); + + my @lines; + while (<$OUT>) { + $_=decode_utf8($_, 0); + + chomp; + + if (! defined $data_handler) { + push @lines, $_; + } + else { + last unless $data_handler->($_); + } + } + + close $OUT; + + $error_handler->("'@cmdline' failed: $!") if $? && $error_handler; + + return wantarray ? @lines : ($? == 0); +} +# Convenient wrappers. +sub run_or_die ($@) { safe_git(\&error, undef, @_) } +sub run_or_cry ($@) { safe_git(sub { warn @_ }, undef, @_) } +sub run_or_non ($@) { safe_git(undef, undef, @_) } + + +sub merge_past ($$$) { + # Unlike with Subversion, Git cannot make a 'svn merge -rN:M file'. + # Git merge commands work with the committed changes, except in the + # implicit case of '-m' of git checkout(1). So we should invent a + # kludge here. In principle, we need to create a throw-away branch + # in preparing for the merge itself. Since branches are cheap (and + # branching is fast), this shouldn't cost high. + # + # The main problem is the presence of _uncommitted_ local changes. One + # possible approach to get rid of this situation could be that we first + # make a temporary commit in the master branch and later restore the + # initial state (this is possible since Git has the ability to undo a + # commit, i.e. 'git reset --soft HEAD^'). The method can be summarized + # as follows: + # + # - create a diff of HEAD:current-sha1 + # - dummy commit + # - create a dummy branch and switch to it + # - rewind to past (reset --hard to the current-sha1) + # - apply the diff and commit + # - switch to master and do the merge with the dummy branch + # - make a soft reset (undo the last commit of master) + # + # The above method has some drawbacks: (1) it needs a redundant commit + # just to get rid of local changes, (2) somewhat slow because of the + # required system forks. Until someone points a more straight method + # (which I would be grateful) I have implemented an alternative method. + # In this approach, we hide all the modified files from Git by renaming + # them (using the 'rename' builtin) and later restore those files in + # the throw-away branch (that is, we put the files themselves instead + # of applying a patch). + + my ($sha1, $file, $message) = @_; + + my @undo; # undo stack for cleanup in case of an error + my $conflict; # file content with conflict markers + + eval { + # Hide local changes from Git by renaming the modified file. + # Relative paths must be converted to absolute for renaming. + my ($target, $hidden) = ( + "$config{srcdir}/${file}", "$config{srcdir}/${file}.${sha1}" + ); + rename($target, $hidden) + or error("rename '$target' to '$hidden' failed: $!"); + # Ensure to restore the renamed file on error. + push @undo, sub { + return if ! -e "$hidden"; # already renamed + rename($hidden, $target) + or warn "rename '$hidden' to '$target' failed: $!"; + }; + + my $branch = "throw_away_${sha1}"; # supposed to be unique + + # Create a throw-away branch and rewind backward. + push @undo, sub { run_or_cry('git', 'branch', '-D', $branch) }; + run_or_die('git', 'branch', $branch, $sha1); + + # Switch to throw-away branch for the merge operation. + push @undo, sub { + if (!run_or_cry('git', 'checkout', $config{gitmaster_branch})) { + run_or_cry('git', 'checkout','-f',$config{gitmaster_branch}); + } + }; + run_or_die('git', 'checkout', $branch); + + # Put the modified file in _this_ branch. + rename($hidden, $target) + or error("rename '$hidden' to '$target' failed: $!"); + + # _Silently_ commit all modifications in the current branch. + run_or_non('git', 'commit', '-m', $message, '-a'); + # ... and re-switch to master. + run_or_die('git', 'checkout', $config{gitmaster_branch}); + + # Attempt to merge without complaining. + if (!run_or_non('git', 'pull', '--no-commit', '.', $branch)) { + $conflict = readfile($target); + run_or_die('git', 'reset', '--hard'); + } + }; + my $failure = $@; + + # Process undo stack (in reverse order). By policy cleanup + # actions should normally print a warning on failure. + while (my $handle = pop @undo) { + $handle->(); + } + + error("Git merge failed!\n$failure\n") if $failure; + + return $conflict; +} + +sub decode_git_file ($) { + my $file=shift; + + # git does not output utf-8 filenames, but instead + # double-quotes them with the utf-8 characters + # escaped as \nnn\nnn. + if ($file =~ m/^"(.*)"$/) { + ($file=$1) =~ s/\\([0-7]{1,3})/chr(oct($1))/eg; + } + + # strip prefix if in a subdir + if (! defined $prefix) { + ($prefix) = run_or_die('git', 'rev-parse', '--show-prefix'); + if (! defined $prefix) { + $prefix=""; + } + } + $file =~ s/^\Q$prefix\E//; + + return decode("utf8", $file); +} + +sub parse_diff_tree ($) { + # Parse the raw diff tree chunk and return the info hash. + # See git-diff-tree(1) for the syntax. + my $dt_ref = shift; + + # End of stream? + return if ! @{ $dt_ref } || + !defined $dt_ref->[0] || !length $dt_ref->[0]; + + my %ci; + # Header line. + while (my $line = shift @{ $dt_ref }) { + return if $line !~ m/^(.+) ($sha1_pattern)/; + + my $sha1 = $2; + $ci{'sha1'} = $sha1; + last; + } + + # Identification lines for the commit. + while (my $line = shift @{ $dt_ref }) { + # Regexps are semi-stolen from gitweb.cgi. + if ($line =~ m/^tree ([0-9a-fA-F]{40})$/) { + $ci{'tree'} = $1; + } + elsif ($line =~ m/^parent ([0-9a-fA-F]{40})$/) { + # XXX: collecting in reverse order + push @{ $ci{'parents'} }, $1; + } + elsif ($line =~ m/^(author|committer) (.*) ([0-9]+) (.*)$/) { + my ($who, $name, $epoch, $tz) = + ($1, $2, $3, $4 ); + + $ci{ $who } = $name; + $ci{ "${who}_epoch" } = $epoch; + $ci{ "${who}_tz" } = $tz; + + if ($name =~ m/^([^<]+)\s+<([^@>]+)/) { + $ci{"${who}_name"} = $1; + $ci{"${who}_username"} = $2; + } + elsif ($name =~ m/^([^<]+)\s+<>$/) { + $ci{"${who}_username"} = $1; + } + else { + $ci{"${who}_username"} = $name; + } + } + elsif ($line =~ m/^$/) { + # Trailing empty line signals next section. + last; + } + } + + debug("No 'tree' seen in diff-tree output") if !defined $ci{'tree'}; + + if (defined $ci{'parents'}) { + $ci{'parent'} = @{ $ci{'parents'} }[0]; + } + else { + $ci{'parent'} = 0 x 40; + } + + # Commit message (optional). + while ($dt_ref->[0] =~ /^ /) { + my $line = shift @{ $dt_ref }; + $line =~ s/^ //; + push @{ $ci{'comment'} }, $line; + } + shift @{ $dt_ref } if $dt_ref->[0] =~ /^$/; + + # Modified files. + while (my $line = shift @{ $dt_ref }) { + if ($line =~ m{^ + (:+) # number of parents + ([^\t]+)\t # modes, sha1, status + (.*) # file names + $}xo) { + my $num_parents = length $1; + my @tmp = split(" ", $2); + my ($file, $file_to) = split("\t", $3); + my @mode_from = splice(@tmp, 0, $num_parents); + my $mode_to = shift(@tmp); + my @sha1_from = splice(@tmp, 0, $num_parents); + my $sha1_to = shift(@tmp); + my $status = shift(@tmp); + + if (length $file) { + push @{ $ci{'details'} }, { + 'file' => decode_git_file($file), + 'sha1_from' => $sha1_from[0], + 'sha1_to' => $sha1_to, + 'mode_from' => $mode_from[0], + 'mode_to' => $mode_to, + 'status' => $status, + }; + } + next; + }; + last; + } + + return \%ci; +} + +sub git_commit_info ($;$) { + # Return an array of commit info hashes of num commits + # starting from the given sha1sum. + my ($sha1, $num) = @_; + + my @opts; + push @opts, "--max-count=$num" if defined $num; + + my @raw_lines = run_or_die('git', 'log', @opts, + '--pretty=raw', '--raw', '--abbrev=40', '--always', '-c', + '-r', $sha1, '--', '.'); + + my @ci; + while (my $parsed = parse_diff_tree(\@raw_lines)) { + push @ci, $parsed; + } + + warn "Cannot parse commit info for '$sha1' commit" if !@ci; + + return wantarray ? @ci : $ci[0]; +} + +sub rcs_find_changes ($) { + my $oldrev=shift; + + # Note that git log will sometimes show files being added that + # don't exist. Particularly, git merge -s ours can result in a + # merge commit where some files were not really added. + # This is why the code below verifies that the files really + # exist. + my @raw_lines = run_or_die('git', 'log', + '--pretty=raw', '--raw', '--abbrev=40', '--always', '-c', + '--no-renames', , '--reverse', + '-r', "$oldrev..HEAD", '--', '.'); + + # Due to --reverse, we see changes in chronological order. + my %changed; + my %deleted; + my $nullsha = 0 x 40; + my $newrev=$oldrev; + while (my $ci = parse_diff_tree(\@raw_lines)) { + $newrev=$ci->{sha1}; + foreach my $i (@{$ci->{details}}) { + my $file=$i->{file}; + if ($i->{sha1_to} eq $nullsha) { + if (! -e "$config{srcdir}/$file") { + delete $changed{$file}; + $deleted{$file}=1; + } + } + else { + if (-e "$config{srcdir}/$file") { + delete $deleted{$file}; + $changed{$file}=1; + } + } + } + } + + return (\%changed, \%deleted, $newrev); +} + +sub git_sha1_file ($) { + my $file=shift; + git_sha1("--", $file); +} + +sub git_sha1 (@) { + # Ignore error since a non-existing file might be given. + my ($sha1) = run_or_non('git', 'rev-list', '--max-count=1', 'HEAD', + '--', @_); + if (defined $sha1) { + ($sha1) = $sha1 =~ m/($sha1_pattern)/; # sha1 is untainted now + } + return defined $sha1 ? $sha1 : ''; +} + +sub rcs_get_current_rev () { + git_sha1(); +} + +sub rcs_update () { + # Update working directory. + + if (length $config{gitorigin_branch}) { + run_or_cry('git', 'pull', '--prune', $config{gitorigin_branch}); + } +} + +sub rcs_prepedit ($) { + # Return the commit sha1sum of the file when editing begins. + # This will be later used in rcs_commit if a merge is required. + my ($file) = @_; + + return git_sha1_file($file); +} + +sub rcs_commit (@) { + # Try to commit the page; returns undef on _success_ and + # a version of the page with the rcs's conflict markers on + # failure. + my %params=@_; + + # Check to see if the page has been changed by someone else since + # rcs_prepedit was called. + my $cur = git_sha1_file($params{file}); + my ($prev) = $params{token} =~ /^($sha1_pattern)$/; # untaint + + if (defined $cur && defined $prev && $cur ne $prev) { + my $conflict = merge_past($prev, $params{file}, $dummy_commit_msg); + return $conflict if defined $conflict; + } + + return rcs_commit_helper(@_); +} + +sub rcs_commit_staged (@) { + # Commits all staged changes. Changes can be staged using rcs_add, + # rcs_remove, and rcs_rename. + return rcs_commit_helper(@_); +} + +sub rcs_commit_helper (@) { + my %params=@_; + + my %env=%ENV; + + if (defined $params{session}) { + # Set the commit author and email based on web session info. + my $u; + if (defined $params{session}->param("name")) { + $u=$params{session}->param("name"); + } + elsif (defined $params{session}->remote_addr()) { + $u=$params{session}->remote_addr(); + } + if (defined $u) { + $u=encode_utf8($u); + $ENV{GIT_AUTHOR_NAME}=$u; + } + if (defined $params{session}->param("nickname")) { + $u=encode_utf8($params{session}->param("nickname")); + $u=~s/\s+/_/g; + $u=~s/[^-_0-9[:alnum:]]+//g; + } + if (defined $u) { + $ENV{GIT_AUTHOR_EMAIL}="$u\@web"; + } + } + + $params{message} = IkiWiki::possibly_foolish_untaint($params{message}); + my @opts; + if ($params{message} !~ /\S/) { + # Force git to allow empty commit messages. + # (If this version of git supports it.) + my ($version)=`git --version` =~ /git version (.*)/; + if ($version ge "1.7.8") { + push @opts, "--allow-empty-message", "--no-edit"; + } + if ($version ge "1.7.2") { + push @opts, "--allow-empty-message"; + } + elsif ($version ge "1.5.4") { + push @opts, '--cleanup=verbatim'; + } + else { + $params{message}.="."; + } + } + if (exists $params{file}) { + push @opts, '--', $params{file}; + } + # git commit returns non-zero if nothing really changed. + # So we should ignore its exit status (hence run_or_non). + if (run_or_non('git', 'commit', '-m', $params{message}, '-q', @opts)) { + if (length $config{gitorigin_branch}) { + run_or_cry('git', 'push', $config{gitorigin_branch}, $config{gitmaster_branch}); + } + } + + %ENV=%env; + return undef; # success +} + +sub rcs_add ($) { + # Add file to archive. + + my ($file) = @_; + + run_or_cry('git', 'add', $file); +} + +sub rcs_remove ($) { + # Remove file from archive. + + my ($file) = @_; + + run_or_cry('git', 'rm', '-f', $file); +} + +sub rcs_rename ($$) { + my ($src, $dest) = @_; + + run_or_cry('git', 'mv', '-f', $src, $dest); +} + +sub rcs_recentchanges ($) { + # List of recent changes. + + my ($num) = @_; + + eval q{use Date::Parse}; + error($@) if $@; + + my @rets; + foreach my $ci (git_commit_info('HEAD', $num || 1)) { + # Skip redundant commits. + next if ($ci->{'comment'} && @{$ci->{'comment'}}[0] eq $dummy_commit_msg); + + my ($sha1, $when) = ( + $ci->{'sha1'}, + $ci->{'author_epoch'} + ); + + my @pages; + foreach my $detail (@{ $ci->{'details'} }) { + my $file = $detail->{'file'}; + my $efile = join('/', + map { uri_escape_utf8($_) } split('/', $file) + ); + + my $diffurl = defined $config{'diffurl'} ? $config{'diffurl'} : ""; + $diffurl =~ s/\[\[file\]\]/$efile/go; + $diffurl =~ s/\[\[sha1_parent\]\]/$ci->{'parent'}/go; + $diffurl =~ s/\[\[sha1_from\]\]/$detail->{'sha1_from'}/go; + $diffurl =~ s/\[\[sha1_to\]\]/$detail->{'sha1_to'}/go; + $diffurl =~ s/\[\[sha1_commit\]\]/$sha1/go; + + push @pages, { + page => pagename($file), + diffurl => $diffurl, + }; + } + + my @messages; + my $pastblank=0; + foreach my $line (@{$ci->{'comment'}}) { + $pastblank=1 if $line eq ''; + next if $pastblank && $line=~m/^ *(signed[ \-]off[ \-]by[ :]|acked[ \-]by[ :]|cc[ :])/i; + push @messages, { line => $line }; + } + + my $user=$ci->{'author_username'}; + my $web_commit = ($ci->{'author'} =~ /\@web>/); + my $nickname; + + # Set nickname only if a non-url author_username is available, + # and author_name is an url. + if ($user !~ /:\/\// && defined $ci->{'author_name'} && + $ci->{'author_name'} =~ /:\/\//) { + $nickname=$user; + $user=$ci->{'author_name'}; + } + + # compatability code for old web commit messages + if (! $web_commit && + defined $messages[0] && + $messages[0]->{line} =~ m/$config{web_commit_regexp}/) { + $user = defined $2 ? "$2" : "$3"; + $messages[0]->{line} = $4; + $web_commit=1; + } + + push @rets, { + rev => $sha1, + user => $user, + nickname => $nickname, + committype => $web_commit ? "web" : "git", + when => $when, + message => [@messages], + pages => [@pages], + } if @pages; + + last if @rets >= $num; + } + + return @rets; +} + +sub rcs_diff ($;$) { + my $rev=shift; + my $maxlines=shift; + my ($sha1) = $rev =~ /^($sha1_pattern)$/; # untaint + my @lines; + my $addlines=sub { + my $line=shift; + return if defined $maxlines && @lines == $maxlines; + push @lines, $line."\n" + if (@lines || $line=~/^diff --git/); + return 1; + }; + safe_git(undef, $addlines, "git", "show", $sha1); + if (wantarray) { + return @lines; + } + else { + return join("", @lines); + } +} + +{ +my %time_cache; + +sub findtimes ($$) { + my $file=shift; + my $id=shift; # 0 = mtime ; 1 = ctime + + if (! keys %time_cache) { + my $date; + foreach my $line (run_or_die('git', 'log', + '--pretty=format:%at', + '--name-only', '--relative')) { + if (! defined $date && $line =~ /^(\d+)$/) { + $date=$line; + } + elsif (! length $line) { + $date=undef; + } + else { + my $f=decode_git_file($line); + + if (! $time_cache{$f}) { + $time_cache{$f}[0]=$date; # mtime + } + $time_cache{$f}[1]=$date; # ctime + } + } + } + + return exists $time_cache{$file} ? $time_cache{$file}[$id] : 0; +} + +} + +sub rcs_getctime ($) { + my $file=shift; + + return findtimes($file, 1); +} + +sub rcs_getmtime ($) { + my $file=shift; + + return findtimes($file, 0); +} + +{ +my $ret; +sub git_find_root { + # The wiki may not be the only thing in the git repo. + # Determine if it is in a subdirectory by examining the srcdir, + # and its parents, looking for the .git directory. + + return @$ret if defined $ret; + + my $subdir=""; + my $dir=$config{srcdir}; + while (! -d "$dir/.git") { + $subdir=IkiWiki::basename($dir)."/".$subdir; + $dir=IkiWiki::dirname($dir); + if (! length $dir) { + error("cannot determine root of git repo"); + } + } + + $ret=[$subdir, $dir]; + return @$ret; +} + +} + +sub git_parse_changes { + my $reverted = shift; + my @changes = @_; + + my ($subdir, $rootdir) = git_find_root(); + my @rets; + foreach my $ci (@changes) { + foreach my $detail (@{ $ci->{'details'} }) { + my $file = $detail->{'file'}; + + # check that all changed files are in the subdir + if (length $subdir && + ! ($file =~ s/^\Q$subdir\E//)) { + error sprintf(gettext("you are not allowed to change %s"), $file); + } + + my ($action, $mode, $path); + if ($detail->{'status'} =~ /^[M]+\d*$/) { + $action="change"; + $mode=$detail->{'mode_to'}; + } + elsif ($detail->{'status'} =~ /^[AM]+\d*$/) { + $action= $reverted ? "remove" : "add"; + $mode=$detail->{'mode_to'}; + } + elsif ($detail->{'status'} =~ /^[DAM]+\d*/) { + $action= $reverted ? "add" : "remove"; + $mode=$detail->{'mode_from'}; + } + else { + error "unknown status ".$detail->{'status'}; + } + + # test that the file mode is ok + if ($mode !~ /^100[64][64][64]$/) { + error sprintf(gettext("you cannot act on a file with mode %s"), $mode); + } + if ($action eq "change") { + if ($detail->{'mode_from'} ne $detail->{'mode_to'}) { + error gettext("you are not allowed to change file modes"); + } + } + + # extract attachment to temp file + if (($action eq 'add' || $action eq 'change') && + ! pagetype($file)) { + eval q{use File::Temp}; + die $@ if $@; + my $fh; + ($fh, $path)=File::Temp::tempfile(undef, UNLINK => 1); + my $cmd = "cd $git_dir && ". + "git show $detail->{sha1_to} > '$path'"; + if (system($cmd) != 0) { + error("failed writing temp file '$path'."); + } + } + + push @rets, { + file => $file, + action => $action, + path => $path, + }; + } + } + + return @rets; +} + +sub rcs_receive () { + my @rets; + while (<>) { + chomp; + my ($oldrev, $newrev, $refname) = split(' ', $_, 3); + + # only allow changes to gitmaster_branch + if ($refname !~ /^refs\/heads\/\Q$config{gitmaster_branch}\E$/) { + error sprintf(gettext("you are not allowed to change %s"), $refname); + } + + # Avoid chdir when running git here, because the changes + # are in the master git repo, not the srcdir repo. + # (Also, if a subdir is involved, we don't want to chdir to + # it and only see changes in it.) + # The pre-receive hook already puts us in the right place. + in_git_dir(".", sub { + push @rets, git_parse_changes(0, git_commit_info($oldrev."..".$newrev)); + }); + } + + return reverse @rets; +} + +sub rcs_preprevert ($) { + my $rev=shift; + my ($sha1) = $rev =~ /^($sha1_pattern)$/; # untaint + + # Examine changes from root of git repo, not from any subdir, + # in order to see all changes. + my ($subdir, $rootdir) = git_find_root(); + in_git_dir($rootdir, sub { + my @commits=git_commit_info($sha1, 1); + + if (! @commits) { + error "unknown commit"; # just in case + } + + # git revert will fail on merge commits. Add a nice message. + if (exists $commits[0]->{parents} && + @{$commits[0]->{parents}} > 1) { + error gettext("you are not allowed to revert a merge"); + } + + git_parse_changes(1, @commits); + }); +} + +sub rcs_revert ($) { + # Try to revert the given rev; returns undef on _success_. + my $rev = shift; + my ($sha1) = $rev =~ /^($sha1_pattern)$/; # untaint + + if (run_or_non('git', 'revert', '--no-commit', $sha1)) { + return undef; + } + else { + run_or_die('git', 'reset', '--hard'); + return sprintf(gettext("Failed to revert commit %s"), $sha1); + } +} + +1 diff --git a/IkiWiki/Plugin/goodstuff.pm b/IkiWiki/Plugin/goodstuff.pm new file mode 100644 index 000000000..451cd6f84 --- /dev/null +++ b/IkiWiki/Plugin/goodstuff.pm @@ -0,0 +1,43 @@ +#!/usr/bin/perl +# Bundle of good stuff. +package IkiWiki::Plugin::goodstuff; + +use warnings; +use strict; +use IkiWiki 3.00; + +my @bundle=qw{ + brokenlinks + img + map + more + orphans + pagecount + pagestats + progress + shortcut + smiley + tag + table + template + toc + toggle + repolist +}; + +sub import { + hook(type => "getsetup", id => "goodstuff", call => \&getsetup); + foreach my $plugin (@bundle) { + IkiWiki::loadplugin($plugin); + } +} + +sub getsetup { + return + plugin => { + safe => 1, + rebuild => undef, + }, +} + +1 diff --git a/IkiWiki/Plugin/google.pm b/IkiWiki/Plugin/google.pm new file mode 100644 index 000000000..68cde261c --- /dev/null +++ b/IkiWiki/Plugin/google.pm @@ -0,0 +1,53 @@ +#!/usr/bin/perl +package IkiWiki::Plugin::google; + +use warnings; +use strict; +use IkiWiki 3.00; +use URI; + +sub import { + hook(type => "getsetup", id => "google", call => \&getsetup); + hook(type => "checkconfig", id => "google", call => \&checkconfig); + hook(type => "pagetemplate", id => "google", call => \&pagetemplate); +} + +sub getsetup () { + return + plugin => { + safe => 1, + rebuild => 1, + section => "web", + }, +} + +sub checkconfig () { + if (! length $config{url}) { + error(sprintf(gettext("Must specify %s when using the %s plugin"), "url", 'google')); + } + + # This is a mass dependency, so if the search form template + # changes, every page is rebuilt. + add_depends("", "templates/googleform.tmpl"); +} + +my $form; +sub pagetemplate (@) { + my %params=@_; + my $page=$params{page}; + my $template=$params{template}; + + # Add search box to page header. + if ($template->query(name => "searchform")) { + if (! defined $form) { + my $searchform = template("googleform.tmpl", blind_cache => 1); + $searchform->param(url => $config{url}); + $searchform->param(html5 => $config{html5}); + $form=$searchform->output; + } + + $template->param(searchform => $form); + } +} + +1 diff --git a/IkiWiki/Plugin/goto.pm b/IkiWiki/Plugin/goto.pm new file mode 100644 index 000000000..6b596ac8b --- /dev/null +++ b/IkiWiki/Plugin/goto.pm @@ -0,0 +1,85 @@ +#!/usr/bin/perl +package IkiWiki::Plugin::goto; + +use warnings; +use strict; +use IkiWiki 3.00; + +sub import { + hook(type => "cgi", id => 'goto', call => \&cgi); + hook(type => "getsetup", id => 'goto', call => \&getsetup); +} + +sub getsetup () { + return + plugin => { + safe => 1, + rebuild => 0, + section => "web", + } +} + +# cgi_goto(CGI, [page]) +# Redirect to a specified page, or display "not found". If not specified, +# the page param from the CGI object is used. +sub cgi_goto ($;$) { + my $q = shift; + my $page = shift; + + if (!defined $page) { + $page = IkiWiki::decode_utf8($q->param("page")); + + if (!defined $page) { + error("missing page parameter"); + } + } + + # It's possible that $page is not a valid page name; + # if so attempt to turn it into one. + if ($page !~ /$config{wiki_file_regexp}/) { + $page=titlepage($page); + } + + IkiWiki::loadindex(); + + my $link; + if (! IkiWiki::isinternal($page)) { + $link = bestlink("", $page); + } + elsif (defined $pagestate{$page}{meta}{permalink}) { + # Can only redirect to an internal page if it has a + # permalink. + IkiWiki::redirect($q, $pagestate{$page}{meta}{permalink}); + } + + if (! defined $link || ! length $link) { + IkiWiki::cgi_custom_failure( + $q, + "404 Not Found", + IkiWiki::cgitemplate($q, gettext("missing page"), + "

". + sprintf(gettext("The page %s does not exist."), + htmllink("", "", $page)). + "

") + ) + } + else { + IkiWiki::redirect($q, urlto($link)); + } + + exit; +} + +sub cgi ($) { + my $cgi=shift; + my $do = $cgi->param('do'); + + if (defined $do && ($do eq 'goto' || $do eq 'commenter' || + $do eq 'recentchanges_link')) { + # goto is the preferred name for this; recentchanges_link and + # commenter are for compatibility with any saved URLs + cgi_goto($cgi); + } +} + +1; diff --git a/IkiWiki/Plugin/graphviz.pm b/IkiWiki/Plugin/graphviz.pm new file mode 100644 index 000000000..d4018edaa --- /dev/null +++ b/IkiWiki/Plugin/graphviz.pm @@ -0,0 +1,149 @@ +#!/usr/bin/perl +# graphviz plugin for ikiwiki: render graphviz source as an image. +# Josh Triplett +package IkiWiki::Plugin::graphviz; + +use warnings; +use strict; +use IkiWiki 3.00; +use IPC::Open2; + +sub import { + hook(type => "getsetup", id => "graphviz", call => \&getsetup); + hook(type => "needsbuild", id => "version", call => \&needsbuild); + hook(type => "preprocess", id => "graph", call => \&graph, scan => 1); +} + +sub getsetup () { + return + plugin => { + safe => 1, + rebuild => undef, + section => "widget", + }, +} + +my %graphviz_programs = ( + "dot" => 1, "neato" => 1, "fdp" => 1, "twopi" => 1, "circo" => 1 +); + +sub needsbuild { + my $needsbuild=shift; + foreach my $page (keys %pagestate) { + if (exists $pagestate{$page}{graph} && + exists $pagesources{$page} && + grep { $_ eq $pagesources{$page} } @$needsbuild) { + # remove state, will be re-added if + # the graph is still there during the rebuild + delete $pagestate{$page}{graph}; + } + } + return $needsbuild; +} + +sub render_graph (\%) { + my %params = %{(shift)}; + + my $src = "charset=\"utf-8\";\n"; + $src .= "ratio=compress;\nsize=\"".($params{width}+0).", ".($params{height}+0)."\";\n" + if defined $params{width} and defined $params{height}; + $src .= $params{src}; + $src .= "}\n"; + + # Use the sha1 of the graphviz code as part of its filename, + # and as a unique identifier for its imagemap. + eval q{use Digest::SHA}; + error($@) if $@; + my $sha=IkiWiki::possibly_foolish_untaint(Digest::SHA::sha1_hex($params{type}.$src)); + $src = "$params{type} graph$sha {\n".$src; + + my $dest=$params{page}."/graph-".$sha.".png"; + will_render($params{page}, $dest); + + my $map=$pagestate{$params{destpage}}{graph}{$sha}; + if (! -e "$config{destdir}/$dest" || ! defined $map) { + # Use ikiwiki's function to create the image file, this makes + # sure needed subdirs are there and does some sanity checking. + writefile($dest, $config{destdir}, ""); + + my $pid; + my $sigpipe=0; + $SIG{PIPE}=sub { $sigpipe=1 }; + $pid=open2(*IN, *OUT, "$params{prog} -Tpng -o '$config{destdir}/$dest' -Tcmapx"); + + # open2 doesn't respect "use open ':utf8'" + binmode (IN, ':utf8'); + binmode (OUT, ':utf8'); + + print OUT $src; + close OUT; + + local $/ = undef; + $map=$pagestate{$params{destpage}}{graph}{$sha}=; + close IN; + + waitpid $pid, 0; + $SIG{PIPE}="DEFAULT"; + error gettext("failed to run graphviz") if ($sigpipe || $?); + } + + return "\n". + $map; +} + +sub graph (@) { + my %params=@_; + + # Support wikilinks in the graph source. + my $src=$params{src}; + $src="" unless defined $src; + $src=IkiWiki::linkify($params{page}, $params{destpage}, $params{src}); + return unless defined wantarray; # scan mode short-circuit + if ($src ne $params{src}) { + # linkify makes html links, but graphviz wants plain + # urls. This is, frankly a hack: Process source as html, + # throw out everything inside tags that is not a href. + my $s; + my $nested=0; + use HTML::Parser; + error $@ if $@; + my $p=HTML::Parser->new(api_version => 3); + $p->handler(start => sub { + my %attrs=%{shift()}; + if (exists $attrs{href}) { + if ($s=~/href\s*=\s*"$/) { + $s.=$attrs{href}; + } + elsif ($s=~/href\s*=\s*$/) { + $s.="\"$attrs{href}\""; + } + else { + $s.="href=\"$attrs{href}\""; + } + } + $nested++; + }, "attr"); + $p->handler(end => sub { + $nested--; + }); + $p->handler(default => sub { + $s.=join("", @_) unless $nested; + }, "text"); + $p->parse($src); + $p->eof; + $s=~s/\[ href= \]//g; # handle self-links + $params{src}=$s; + } + else { + $params{src}=$src; + } + + $params{type} = "digraph" unless defined $params{type}; + $params{prog} = "dot" unless defined $params{prog}; + error gettext("prog not a valid graphviz program") unless $graphviz_programs{$params{prog}}; + + return render_graph(%params); +} + +1 diff --git a/IkiWiki/Plugin/haiku.pm b/IkiWiki/Plugin/haiku.pm new file mode 100644 index 000000000..bf23dce67 --- /dev/null +++ b/IkiWiki/Plugin/haiku.pm @@ -0,0 +1,60 @@ +#!/usr/bin/perl +# haiku generator plugin +package IkiWiki::Plugin::haiku; + +use warnings; +use strict; +use IkiWiki 3.00; + +sub import { + hook(type => "getsetup", id => "haiku", call => \&getsetup); + hook(type => "preprocess", id => "haiku", call => \&preprocess); +} + +sub getsetup { + return + plugin => { + safe => 1, + rebuild => undef, + section => "widget", + }, +} + +sub preprocess (@) { + my %params=@_; + + my $haiku; + eval q{use Coy}; + if ($@ || ! Coy->can("Coy::with_haiku")) { + my @canned=( + "The lack of a Coy: + No darting, subtle haiku. + Instead, canned tuna. + ", + "apt-get install Coy + no, wait, that's not quite it + instead: libcoy-perl + ", + "Coyly I'll do it, + no code, count Five-Seven-Five + to make a haiku. + ", + ); + + $haiku=$canned[rand @canned]; + } + else { + $haiku=Coy::with_haiku($params{hint} ? $params{hint} : $params{page}); + + # trim off other text + $haiku=~s/\s+-----\n//s; + $haiku=~s/\s+-----.*//s; + } + + $haiku=~s/^\s+//mg; + $haiku=~s/\n/
\n/mg; + + return "\n\n

$haiku

\n\n"; +} + +1 diff --git a/IkiWiki/Plugin/headinganchors.pm b/IkiWiki/Plugin/headinganchors.pm new file mode 100644 index 000000000..ece6f4eac --- /dev/null +++ b/IkiWiki/Plugin/headinganchors.pm @@ -0,0 +1,43 @@ +#!/usr/bin/perl +# quick HTML heading id adder by Paul Wise +package IkiWiki::Plugin::headinganchors; + +use warnings; +use strict; +use IkiWiki 3.00; +use URI::Escape; + +sub import { + hook(type => "getsetup", id => "headinganchors", call => \&getsetup); + hook(type => "sanitize", id => "headinganchors", call => \&headinganchors); +} + +sub getsetup () { + return + plugin => { + safe => 1, + rebuild => undef, + section => "widget", + }, +} + +sub text_to_anchor { + my $str = shift; + $str =~ s/^\s+//; + $str =~ s/\s+$//; + $str =~ s/\s/_/g; + $str =~ s/"//g; + $str =~ s/^[^a-zA-Z]/z-/; # must start with an alphabetical character + $str = uri_escape_utf8($str); + $str =~ s/%/./g; + return $str; +} + +sub headinganchors (@) { + my %params=@_; + my $content=$params{content}; + $content=~s{([^>]*)}{''.$2.''}gie; + return $content; +} + +1 diff --git a/IkiWiki/Plugin/highlight.pm b/IkiWiki/Plugin/highlight.pm new file mode 100644 index 000000000..ce919748a --- /dev/null +++ b/IkiWiki/Plugin/highlight.pm @@ -0,0 +1,225 @@ +#!/usr/bin/perl +package IkiWiki::Plugin::highlight; + +# This has been tested with highlight 2.16 and highlight 3.2+svn19. +# In particular version 3.2 won't work. It detects the different +# versions by the presence of the the highlight::DataDir class. + +use warnings; +use strict; +use IkiWiki 3.00; +use Encode; + +my $data_dir; + +sub import { + hook(type => "getsetup", id => "highlight", call => \&getsetup); + hook(type => "checkconfig", id => "highlight", call => \&checkconfig); + # this hook is used by the format plugin + hook(type => "htmlizeformat", id => "highlight", + call => \&htmlizeformat, last => 1); +} + +sub getsetup () { + return + plugin => { + safe => 1, + rebuild => 1, # format plugin + section => "format", + }, + tohighlight => { + type => "string", + example => ".c .h .cpp .pl .py Makefile:make", + description => "types of source files to syntax highlight", + safe => 1, + rebuild => 1, + }, + filetypes_conf => { + type => "string", + example => "/etc/highlight/filetypes.conf", + description => "location of highlight's filetypes.conf", + safe => 0, + rebuild => undef, + }, + langdefdir => { + type => "string", + example => "/usr/share/highlight/langDefs", + description => "location of highlight's langDefs directory", + safe => 0, + rebuild => undef, + }, +} + +sub checkconfig () { + eval q{use highlight}; + if (highlight::DataDir->can('new')) { + $data_dir=new highlight::DataDir(); + $data_dir->searchDataDir(""); + } else { + $data_dir=undef; + } + + if (! exists $config{filetypes_conf}) { + if (! $data_dir ) { + $config{filetypes_conf}= "/etc/highlight/filetypes.conf"; + } elsif ( $data_dir -> can('searchFile') ) { + # 3.18 + + $config{filetypes_conf}= + $data_dir -> searchFile("filetypes.conf"); + } else { + # 3.9 + + $config{filetypes_conf}= + $data_dir -> getConfDir() . "/filetypes.conf"; + } + } + # note that this is only used for old versions of highlight + # where $data_dir will not be defined. + if (! exists $config{langdefdir}) { + $config{langdefdir}= "/usr/share/highlight/langDefs"; + + } + if (exists $config{tohighlight} && read_filetypes()) { + foreach my $file (split ' ', $config{tohighlight}) { + my @opts = $file=~s/^\.// ? + (keepextension => 1) : + (noextension => 1); + my $ext = $file=~s/:(.*)// ? $1 : $file; + + my $langfile=ext2langfile($ext); + if (! defined $langfile) { + error(sprintf(gettext( + "tohighlight contains unknown file type '%s'"), + $ext)); + } + + hook( + type => "htmlize", + id => $file, + call => sub { + my %params=@_; + highlight($langfile, $file, $params{content}); + }, + longname => sprintf(gettext("Source code: %s"), $file), + @opts, + ); + } + } +} + +sub htmlizeformat { + my $format=lc shift; + my $langfile=ext2langfile($format); + + if (! defined $langfile) { + return; + } + + return Encode::decode_utf8(highlight($langfile, $format, shift)); +} + +my %ext2lang; +my $filetypes_read=0; +my %highlighters; + +# Parse highlight's config file to get extension => language mappings. +sub read_filetypes () { + my $f; + if (!open($f, $config{filetypes_conf})) { + warn($config{filetypes_conf}.": ".$!); + return 0; + }; + + local $/=undef; + my $config=<$f>; + close $f; + + # highlight >= 3.2 format (bind-style) + while ($config=~m/Lang\s*=\s*\"([^"]+)\"[,\s]+Extensions\s*=\s*{([^}]+)}/sg) { + my $lang=$1; + foreach my $bit (split ',', $2) { + $bit=~s/.*"(.*)".*/$1/s; + $ext2lang{$bit}=$lang; + } + } + + # highlight < 3.2 format + if (! keys %ext2lang) { + foreach (split("\n", $config)) { + if (/^\$ext\((.*)\)=(.*)$/) { + $ext2lang{$_}=$1 foreach $1, split ' ', $2; + } + } + } + + return $filetypes_read=1; +} + + +sub searchlangdef { + my $lang=shift; + + if ($data_dir) { + return $data_dir->getLangPath($lang . ".lang"); + } else { + return "$config{langdefdir}/$lang.lang"; + } + +} +# Given a filename extension, determines the language definition to +# use to highlight it. +sub ext2langfile ($) { + my $ext=shift; + + my $langfile=searchlangdef($ext); + return $langfile if exists $highlighters{$langfile}; + + read_filetypes() unless $filetypes_read; + if (exists $ext2lang{$ext}) { + return searchlangdef($ext2lang{$ext}); + } + # If a language only has one common extension, it will not + # be listed in filetypes, so check the langfile. + elsif (-e $langfile) { + return $langfile; + } + else { + return undef; + } +} + +# Interface to the highlight C library. +sub highlight ($$) { + my $langfile=shift; + my $extorfile=shift; + my $input=shift; + + eval q{use highlight}; + if ($@) { + print STDERR gettext("warning: highlight perl module not available; falling back to pass through"); + return $input; + } + + my $gen; + if (! exists $highlighters{$langfile}) { + $gen = highlight::CodeGenerator::getInstance($highlight::XHTML); + $gen->setFragmentCode(1); # generate html fragment + $gen->setHTMLEnclosePreTag(1); # include stylish
+		if ($data_dir){
+			# new style, requires a real theme, but has no effect
+			$gen->initTheme($data_dir->getThemePath("seashell.theme"));
+		} else {
+			# old style, anything works.
+			$gen->initTheme("/dev/null");
+		}
+		$gen->loadLanguage($langfile); # must come after initTheme
+		$gen->setEncoding("utf-8");
+		$highlighters{$langfile}=$gen;
+	}
+	else {		
+		$gen=$highlighters{$langfile};
+	}
+
+	return "
".$gen->generateString($input)."
"; +} + +1 diff --git a/IkiWiki/Plugin/hnb.pm b/IkiWiki/Plugin/hnb.pm new file mode 100644 index 000000000..5157a6b93 --- /dev/null +++ b/IkiWiki/Plugin/hnb.pm @@ -0,0 +1,58 @@ +#!/usr/bin/perl +# hnb markup +# Licensed under the GPL v2 or greater +# Copyright (C) 2008 by Axel Beckert +# +# TODO: Make a switch to allow both HTML export routines of hnb +# (`export_html` and `export_htmlcss`) to be used. + +package IkiWiki::Plugin::hnb; + +use warnings; +use strict; +use IkiWiki 3.00; +use File::Temp qw(:mktemp); + +sub import { + hook(type => "getsetup", id => "hnb", call => \&getsetup); + hook(type => "htmlize", id => "hnb", call => \&htmlize); +} + +sub getsetup () { + return + plugin => { + safe => 1, + rebuild => 1, # format plugin + section => "format", + }, +} + +sub htmlize (@) { + my %params = @_; + + # hnb outputs version number etc. every time to STDOUT, so + # using files makes it easier to seprarate. + + my ($infh, $tmpin) = mkstemp( "/tmp/ikiwiki-hnbin.XXXXXXXXXX" ); + my ($outfh, $tmpout) = mkstemp( "/tmp/ikiwiki-hnbout.XXXXXXXXXX" ); + + open(TMP, '>', $tmpin) or die "Can't write to $tmpin: $!"; + print TMP $params{content}; + close TMP; + + system("hnb '$tmpin' 'go root' 'export_html $tmpout' > /dev/null"); + unlink $tmpin; + + open(TMP, '<', $tmpout) or die "Can't read from $tmpout: $!"; + local $/; + my $ret = ; + close TMP; + unlink $tmpout; + + $ret =~ s/.*//si; + $ret =~ s/.*//si; + + return $ret; +} + +1; diff --git a/IkiWiki/Plugin/html.pm b/IkiWiki/Plugin/html.pm new file mode 100644 index 000000000..4dbae081b --- /dev/null +++ b/IkiWiki/Plugin/html.pm @@ -0,0 +1,33 @@ +#!/usr/bin/perl +# Raw html as a wiki page type. +package IkiWiki::Plugin::html; + +use warnings; +use strict; +use IkiWiki 3.00; + +sub import { + hook(type => "getsetup", id => "html", call => \&getsetup); + hook(type => "htmlize", id => "html", call => \&htmlize); + hook(type => "htmlize", id => "htm", call => \&htmlize); + + # ikiwiki defaults to skipping .html files as a security measure; + # make it process them so this plugin can take effect + $config{wiki_file_prune_regexps} = [ grep { !m/\\\.x\?html\?\$/ } @{$config{wiki_file_prune_regexps}} ]; +} + +sub getsetup () { + return + plugin => { + safe => 1, + rebuild => 1, # format plugin + section => "format", + }, +} + +sub htmlize (@) { + my %params=@_; + return $params{content}; +} + +1 diff --git a/IkiWiki/Plugin/htmlbalance.pm b/IkiWiki/Plugin/htmlbalance.pm new file mode 100644 index 000000000..da450eea7 --- /dev/null +++ b/IkiWiki/Plugin/htmlbalance.pm @@ -0,0 +1,58 @@ +#!/usr/bin/perl +package IkiWiki::Plugin::htmlbalance; + +# htmlbalance: Parse and re-serialize HTML to ensure balanced tags +# +# Copyright 2008 Simon McVittie +# Licensed under the GNU GPL, version 2, or any later version published by the +# Free Software Foundation + +use warnings; +use strict; +use IkiWiki 3.00; +use HTML::Entities; + +sub import { + hook(type => "getsetup", id => "htmlbalance", call => \&getsetup); + hook(type => "sanitize", id => "htmlbalance", call => \&sanitize); +} + +sub getsetup () { + return + plugin => { + safe => 1, + rebuild => undef, + }, +} + +sub sanitize (@) { + my %params=@_; + my $ret = ''; + + eval q{use HTML::TreeBuilder}; + error $@ if $@; + my $tree = HTML::TreeBuilder->new(); + $tree->ignore_unknown(0); + $tree->ignore_ignorable_whitespace(0); + $tree->no_space_compacting(1); + $tree->p_strict(1); + $tree->store_comments(0); + $tree->store_declarations(0); + $tree->store_pis(0); + $tree->parse_content($params{content}); + my @nodes = $tree->disembowel(); + foreach my $node (@nodes) { + if (ref $node) { + $ret .= $node->as_HTML(undef, '', {}); + chomp $ret; + $node->delete(); + } + else { + $ret .= encode_entities($node); + } + } + $tree->delete(); + return $ret; +} + +1 diff --git a/IkiWiki/Plugin/htmlscrubber.pm b/IkiWiki/Plugin/htmlscrubber.pm new file mode 100644 index 000000000..36c012c73 --- /dev/null +++ b/IkiWiki/Plugin/htmlscrubber.pm @@ -0,0 +1,127 @@ +#!/usr/bin/perl +package IkiWiki::Plugin::htmlscrubber; + +use warnings; +use strict; +use IkiWiki 3.00; + +# This regexp matches urls that are in a known safe scheme. +# Feel free to use it from other plugins. +our $safe_url_regexp; + +sub import { + hook(type => "getsetup", id => "htmlscrubber", call => \&getsetup); + hook(type => "sanitize", id => "htmlscrubber", call => \&sanitize); + + # Only known uri schemes are allowed to avoid all the ways of + # embedding javascrpt. + # List at http://en.wikipedia.org/wiki/URI_scheme + my $uri_schemes=join("|", map quotemeta, + # IANA registered schemes + "http", "https", "ftp", "mailto", "file", "telnet", "gopher", + "aaa", "aaas", "acap", "cap", "cid", "crid", + "dav", "dict", "dns", "fax", "go", "h323", "im", "imap", + "ldap", "mid", "news", "nfs", "nntp", "pop", "pres", + "sip", "sips", "snmp", "tel", "urn", "wais", "xmpp", + "z39.50r", "z39.50s", + # Selected unofficial schemes + "aim", "callto", "cvs", "ed2k", "feed", "fish", "gg", + "irc", "ircs", "lastfm", "ldaps", "magnet", "mms", + "msnim", "notes", "rsync", "secondlife", "skype", "ssh", + "sftp", "smb", "sms", "snews", "webcal", "ymsgr", + "bitcoin", "git", "svn", "bzr", "darcs", "hg" + ); + # data is a special case. Allow a few data:image/ types, + # but disallow data:text/javascript and everything else. + $safe_url_regexp=qr/^(?:(?:$uri_schemes):|data:image\/(?:png|jpeg|gif)|[^:]+(?:$|[\/\?#]))|^#/i; +} + +sub getsetup () { + return + plugin => { + safe => 1, + rebuild => undef, + section => "core", + }, + htmlscrubber_skip => { + type => "pagespec", + example => "!*/Discussion", + description => "PageSpec specifying pages not to scrub", + link => "ikiwiki/PageSpec", + safe => 1, + rebuild => undef, + }, +} + +sub sanitize (@) { + my %params=@_; + + if (exists $config{htmlscrubber_skip} && + length $config{htmlscrubber_skip} && + exists $params{page} && + pagespec_match($params{page}, $config{htmlscrubber_skip})) { + return $params{content}; + } + + return scrubber()->scrub($params{content}); +} + +my $_scrubber; +sub scrubber { + return $_scrubber if defined $_scrubber; + + eval q{use HTML::Scrubber}; + error($@) if $@; + # Lists based on http://feedparser.org/docs/html-sanitization.html + # With html5 tags added. + $_scrubber = HTML::Scrubber->new( + allow => [qw{ + a abbr acronym address area b big blockquote br br/ + button caption center cite code col colgroup dd del + dfn dir div dl dt em fieldset font form h1 h2 h3 h4 + h5 h6 hr hr/ i img input ins kbd label legend li map + menu ol optgroup option p p/ pre q s samp select small + span strike strong sub sup table tbody td textarea + tfoot th thead tr tt u ul var + + video audio source section nav article aside hgroup + header footer figure figcaption time mark canvas + datalist progress meter ruby rt rp details summary + }], + default => [undef, { ( + map { $_ => 1 } qw{ + abbr accept accept-charset accesskey + align alt axis border cellpadding cellspacing + char charoff charset checked class + clear cols colspan color compact coords + datetime dir disabled enctype for frame + headers height hreflang hspace id ismap + label lang maxlength media method + multiple name nohref noshade nowrap prompt + readonly rel rev rows rowspan rules scope + selected shape size span start summary + tabindex target title type valign + value vspace width + + autofocus autoplay preload loopstart + loopend end playcount controls pubdate + placeholder min max step low high optimum + form required autocomplete novalidate pattern + list formenctype formmethod formnovalidate + formtarget reversed spellcheck open hidden + } ), + "/" => 1, # emit proper
XHTML + href => $safe_url_regexp, + src => $safe_url_regexp, + action => $safe_url_regexp, + formaction => $safe_url_regexp, + cite => $safe_url_regexp, + longdesc => $safe_url_regexp, + poster => $safe_url_regexp, + usemap => $safe_url_regexp, + }], + ); + return $_scrubber; +} + +1 diff --git a/IkiWiki/Plugin/htmltidy.pm b/IkiWiki/Plugin/htmltidy.pm new file mode 100644 index 000000000..da77e60f1 --- /dev/null +++ b/IkiWiki/Plugin/htmltidy.pm @@ -0,0 +1,71 @@ +#!/usr/bin/perl +# HTML Tidy plugin +# requires 'tidy' binary, found in Debian or http://tidy.sf.net/ +# mostly a proof-of-concept on how to use external filters. +# It is particularly useful when the html plugin is used. +# +# by Faidon Liambotis +package IkiWiki::Plugin::htmltidy; + +use warnings; +use strict; +use IkiWiki 3.00; +use IPC::Open2; + +sub import { + hook(type => "getsetup", id => "tidy", call => \&getsetup); + hook(type => "sanitize", id => "tidy", call => \&sanitize); + hook(type => "checkconfig", id => "tidy", call => \&checkconfig); +} + +sub getsetup () { + return + plugin => { + safe => 1, + rebuild => undef, + }, + htmltidy => { + type => "string", + description => "tidy command line", + safe => 0, # path + rebuild => undef, + }, +} + +sub checkconfig () { + if (! defined $config{htmltidy}) { + $config{htmltidy}="tidy -quiet -asxhtml -utf8 --show-body-only yes --show-warnings no --tidy-mark no --markup yes"; + } +} + +sub sanitize (@) { + my %params=@_; + + return $params{content} unless defined $config{htmltidy}; + + my $pid; + my $sigpipe=0; + $SIG{PIPE}=sub { $sigpipe=1 }; + $pid=open2(*IN, *OUT, "$config{htmltidy} 2>/dev/null"); + + # open2 doesn't respect "use open ':utf8'" + binmode (IN, ':utf8'); + binmode (OUT, ':utf8'); + + print OUT $params{content}; + close OUT; + + local $/ = undef; + my $ret=; + close IN; + waitpid $pid, 0; + + $SIG{PIPE}="DEFAULT"; + if ($sigpipe || ! defined $ret) { + return gettext("htmltidy failed to parse this html"); + } + + return $ret; +} + +1 diff --git a/IkiWiki/Plugin/httpauth.pm b/IkiWiki/Plugin/httpauth.pm new file mode 100644 index 000000000..76d574b2a --- /dev/null +++ b/IkiWiki/Plugin/httpauth.pm @@ -0,0 +1,117 @@ +#!/usr/bin/perl +# HTTP basic auth plugin. +package IkiWiki::Plugin::httpauth; + +use warnings; +use strict; +use IkiWiki 3.00; + +sub import { + hook(type => "checkconfig", id => "httpauth", call => \&checkconfig); + hook(type => "getsetup", id => "httpauth", call => \&getsetup); + hook(type => "auth", id => "httpauth", call => \&auth); + hook(type => "formbuilder_setup", id => "httpauth", + call => \&formbuilder_setup); + hook(type => "canedit", id => "httpauth", call => \&canedit, + first => 1); +} + +sub getsetup () { + return + plugin => { + safe => 1, + rebuild => 0, + section => "auth", + }, + cgiauthurl => { + type => "string", + example => "http://example.com/wiki/auth/ikiwiki.cgi", + description => "url to redirect to when authentication is needed", + safe => 1, + rebuild => 0, + }, + httpauth_pagespec => { + type => "pagespec", + example => "!*/Discussion", + description => "PageSpec of pages where only httpauth will be used for authentication", + safe => 0, + rebuild => 0, + }, +} + +sub checkconfig () { + if ($config{cgi} && defined $config{cgiauthurl} && + keys %{$IkiWiki::hooks{auth}} < 2) { + # There are no other auth hooks registered, so avoid + # the normal signin form, and jump right to httpauth. + require IkiWiki::CGI; + inject(name => "IkiWiki::cgi_signin", call => sub ($$) { + my $cgi=shift; + redir_cgiauthurl($cgi, $cgi->query_string()); + }); + } +} + +sub redir_cgiauthurl ($;@) { + my $cgi=shift; + + IkiWiki::redirect($cgi, + @_ > 1 ? IkiWiki::cgiurl(cgiurl => $config{cgiauthurl}, @_) + : $config{cgiauthurl}."?@_" + ); + exit; +} + +sub auth ($$) { + my $cgi=shift; + my $session=shift; + + if (defined $cgi->remote_user()) { + $session->param("name", $cgi->remote_user()); + } +} + +sub formbuilder_setup (@) { + my %params=@_; + + my $form=$params{form}; + my $session=$params{session}; + my $cgi=$params{cgi}; + my $buttons=$params{buttons}; + + if ($form->title eq "signin" && + ! defined $cgi->remote_user() && defined $config{cgiauthurl}) { + my $button_text="Login with HTTP auth"; + push @$buttons, $button_text; + + if ($form->submitted && $form->submitted eq $button_text) { + # bounce thru cgiauthurl and then back to + # the stored postsignin action + redir_cgiauthurl($cgi, do => "postsignin"); + } + } +} + +sub canedit ($$$) { + my $page=shift; + my $cgi=shift; + my $session=shift; + + if (! defined $cgi->remote_user() && + (! defined $session->param("name") || + ! IkiWiki::userinfo_get($session->param("name"), "regdate")) && + defined $config{httpauth_pagespec} && + length $config{httpauth_pagespec} && + defined $config{cgiauthurl} && + pagespec_match($page, $config{httpauth_pagespec})) { + return sub { + # bounce thru cgiauthurl and back to edit action + redir_cgiauthurl($cgi, $cgi->query_string()); + }; + } + else { + return undef; + } +} + +1 diff --git a/IkiWiki/Plugin/img.pm b/IkiWiki/Plugin/img.pm new file mode 100644 index 000000000..17a58ca7a --- /dev/null +++ b/IkiWiki/Plugin/img.pm @@ -0,0 +1,216 @@ +#!/usr/bin/perl +# Ikiwiki enhanced image handling plugin +# Christian Mock cm@tahina.priv.at 20061002 +package IkiWiki::Plugin::img; + +use warnings; +use strict; +use IkiWiki 3.00; + +my %imgdefaults; + +sub import { + hook(type => "getsetup", id => "img", call => \&getsetup); + hook(type => "preprocess", id => "img", call => \&preprocess, scan => 1); +} + +sub getsetup () { + return + plugin => { + safe => 1, + rebuild => undef, + section => "widget", + }, +} + +sub preprocess (@) { + my ($image) = $_[0] =~ /$config{wiki_file_regexp}/; # untaint + my %params=@_; + + if (! defined $image) { + error("bad image filename"); + } + + if (exists $imgdefaults{$params{page}}) { + foreach my $key (keys %{$imgdefaults{$params{page}}}) { + if (! exists $params{$key}) { + $params{$key}=$imgdefaults{$params{page}}->{$key}; + } + } + } + + if (! exists $params{size} || ! length $params{size}) { + $params{size}='full'; + } + + if ($image eq 'defaults') { + $imgdefaults{$params{page}} = \%params; + return ''; + } + + add_link($params{page}, $image); + add_depends($params{page}, $image); + + # optimisation: detect scan mode, and avoid generating the image + if (! defined wantarray) { + return; + } + + my $file = bestlink($params{page}, $image); + my $srcfile = srcfile($file, 1); + if (! length $file || ! defined $srcfile) { + return htmllink($params{page}, $params{destpage}, $image); + } + + my $dir = $params{page}; + my $base = IkiWiki::basename($file); + my $issvg = $base=~s/\.svg$/.png/i; + my $ispdf = $base=~s/\.pdf$/.png/i; + my $pagenumber = exists($params{pagenumber}) ? int($params{pagenumber}) : 0; + if ($pagenumber != 0) { + $base = "p$pagenumber-$base"; + } + + eval q{use Image::Magick}; + error gettext("Image::Magick is not installed") if $@; + my $im = Image::Magick->new(); + my $imglink; + my $imgdatalink; + my $r = $im->Read("$srcfile\[$pagenumber]"); + error sprintf(gettext("failed to read %s: %s"), $file, $r) if $r; + + if (! defined $im->Get("width") || ! defined $im->Get("height")) { + error sprintf(gettext("failed to get dimensions of %s"), $file); + } + + my ($dwidth, $dheight); + + if ($params{size} eq 'full') { + $dwidth = $im->Get("width"); + $dheight = $im->Get("height"); + } else { + my ($w, $h) = ($params{size} =~ /^(\d*)x(\d*)$/); + error sprintf(gettext('wrong size format "%s" (should be WxH)'), $params{size}) + unless (defined $w && defined $h && + (length $w || length $h)); + + if ($im->Get("width") == 0 || $im->Get("height") == 0) { + ($dwidth, $dheight)=(0, 0); + } elsif (! length $w || (length $h && $im->Get("height")*$w > $h * $im->Get("width"))) { + # using height because only height is given or ... + # because original image is more portrait than $w/$h + # ... slimness of $im > $h/w + # ... $im->Get("height")/$im->Get("width") > $h/$w + # ... $im->Get("height")*$w > $h * $im->Get("width") + + $dheight=$h; + $dwidth=$h / $im->Get("height") * $im->Get("width"); + } else { # (! length $h) or $w is what determines the resized size + $dwidth=$w; + $dheight=$w / $im->Get("width") * $im->Get("height"); + } + } + + if ($dwidth < $im->Get("width") || $ispdf) { + # resize down, or resize to pixels at all + + my $outfile = "$config{destdir}/$dir/$params{size}-$base"; + $imglink = "$dir/$params{size}-$base"; + + will_render($params{page}, $imglink); + + if (-e $outfile && (-M $srcfile >= -M $outfile)) { + $im = Image::Magick->new; + $r = $im->Read($outfile); + error sprintf(gettext("failed to read %s: %s"), $outfile, $r) if $r; + } + else { + $r = $im->Resize(geometry => "${dwidth}x${dheight}"); + error sprintf(gettext("failed to resize: %s"), $r) if $r; + + $im->set(($issvg || $ispdf) ? (magick => 'png') : ()); + my @blob = $im->ImageToBlob(); + # don't actually write resized file in preview mode; + # rely on width and height settings + if (! $params{preview}) { + writefile($imglink, $config{destdir}, $blob[0], 1); + } + else { + eval q{use MIME::Base64}; + error($@) if $@; + $imgdatalink = "data:image/".$im->Get("magick").";base64,".encode_base64($blob[0]); + } + } + + # always get the true size of the resized image (it could be + # that imagemagick did its calculations differently) + $dwidth = $im->Get("width"); + $dheight = $im->Get("height"); + } else { + $imglink = $file; + } + + if (! defined($dwidth) || ! defined($dheight)) { + error sprintf(gettext("failed to determine size of image %s"), $file) + } + + my ($fileurl, $imgurl); + my $urltobase = $params{preview} ? undef : $params{destpage}; + $fileurl=urlto($file, $urltobase); + $imgurl=$imgdatalink ? $imgdatalink : urlto($imglink, $urltobase); + + if (! exists $params{class}) { + $params{class}="img"; + } + + my $attrs=''; + foreach my $attr (qw{alt title class id hspace vspace}) { + if (exists $params{$attr}) { + $attrs.=" $attr=\"$params{$attr}\""; + } + } + + my $imgtag=''; + + my $link; + if (! defined $params{link}) { + $link=$fileurl; + } + elsif ($params{link} =~ /^\w+:\/\//) { + $link=$params{link}; + } + + if (defined $link) { + $imgtag=''.$imgtag.''; + } + else { + my $b = bestlink($params{page}, $params{link}); + + if (length $b) { + add_depends($params{page}, $b, deptype("presence")); + $imgtag=htmllink($params{page}, $params{destpage}, + $params{link}, linktext => $imgtag, + noimageinline => 1, + ); + } + } + + if (exists $params{caption}) { + return ''. + ''. + ''. + '
'.$params{caption}.'
'.$imgtag.'
'; + } + else { + return $imgtag; + } +} + +1 diff --git a/IkiWiki/Plugin/inline.pm b/IkiWiki/Plugin/inline.pm new file mode 100644 index 000000000..f578526cc --- /dev/null +++ b/IkiWiki/Plugin/inline.pm @@ -0,0 +1,799 @@ +#!/usr/bin/perl +# Page inlining and blogging. +package IkiWiki::Plugin::inline; + +use warnings; +use strict; +use Encode; +use IkiWiki 3.00; +use URI; + +my %knownfeeds; +my %page_numfeeds; +my @inline; +my $nested=0; + +sub import { + hook(type => "getopt", id => "inline", call => \&getopt); + hook(type => "getsetup", id => "inline", call => \&getsetup); + hook(type => "checkconfig", id => "inline", call => \&checkconfig); + hook(type => "sessioncgi", id => "inline", call => \&sessioncgi); + hook(type => "preprocess", id => "inline", + call => \&IkiWiki::preprocess_inline, scan => 1); + hook(type => "pagetemplate", id => "inline", + call => \&IkiWiki::pagetemplate_inline); + hook(type => "format", id => "inline", call => \&format, first => 1); + # Hook to change to do pinging since it's called late. + # This ensures each page only pings once and prevents slow + # pings interrupting page builds. + hook(type => "rendered", id => "inline", call => \&IkiWiki::pingurl); +} + +sub getopt () { + eval q{use Getopt::Long}; + error($@) if $@; + Getopt::Long::Configure('pass_through'); + GetOptions( + "rss!" => \$config{rss}, + "atom!" => \$config{atom}, + "allowrss!" => \$config{allowrss}, + "allowatom!" => \$config{allowatom}, + "pingurl=s" => sub { + push @{$config{pingurl}}, $_[1]; + }, + ); +} + +sub getsetup () { + return + plugin => { + safe => 1, + rebuild => undef, + section => "core", + }, + rss => { + type => "boolean", + example => 0, + description => "enable rss feeds by default?", + safe => 1, + rebuild => 1, + }, + atom => { + type => "boolean", + example => 0, + description => "enable atom feeds by default?", + safe => 1, + rebuild => 1, + }, + allowrss => { + type => "boolean", + example => 0, + description => "allow rss feeds to be used?", + safe => 1, + rebuild => 1, + }, + allowatom => { + type => "boolean", + example => 0, + description => "allow atom feeds to be used?", + safe => 1, + rebuild => 1, + }, + pingurl => { + type => "string", + example => "http://rpc.technorati.com/rpc/ping", + description => "urls to ping (using XML-RPC) on feed update", + safe => 1, + rebuild => 0, + }, +} + +sub checkconfig () { + if (($config{rss} || $config{atom}) && ! length $config{url}) { + error(gettext("Must specify url to wiki with --url when using --rss or --atom")); + } + if ($config{rss}) { + push @{$config{wiki_file_prune_regexps}}, qr/\.rss$/; + } + if ($config{atom}) { + push @{$config{wiki_file_prune_regexps}}, qr/\.atom$/; + } + if (! exists $config{pingurl}) { + $config{pingurl}=[]; + } +} + +sub format (@) { + my %params=@_; + + # Fill in the inline content generated earlier. This is actually an + # optimisation. + $params{content}=~s{
}{ + delete @inline[$1,] + }eg; + return $params{content}; +} + +sub sessioncgi ($$) { + my $q=shift; + my $session=shift; + + if ($q->param('do') eq 'blog') { + my $page=titlepage(decode_utf8($q->param('title'))); + $page=~s/(\/)/"__".ord($1)."__"/eg; # don't create subdirs + # if the page already exists, munge it to be unique + my $from=$q->param('from'); + my $add=""; + while (exists $IkiWiki::pagecase{lc($from."/".$page.$add)}) { + $add=1 unless length $add; + $add++; + } + $q->param('page', "/$from/$page$add"); + # now go create the page + $q->param('do', 'create'); + # make sure the editpage plugin is loaded + if (IkiWiki->can("cgi_editpage")) { + IkiWiki::cgi_editpage($q, $session); + } + else { + error(gettext("page editing not allowed")); + } + exit; + } +} + +# Back to ikiwiki namespace for the rest, this code is very much +# internal to ikiwiki even though it's separated into a plugin. +package IkiWiki; + +my %toping; +my %feedlinks; + +sub preprocess_inline (@) { + my %params=@_; + + if (! exists $params{pages} && ! exists $params{pagenames}) { + error gettext("missing pages parameter"); + } + + if (! defined wantarray) { + # Running in scan mode: only do the essentials + + if (yesno($params{trail}) && IkiWiki::Plugin::trail->can("preprocess_trailitems")) { + # default to sorting age, the same as inline itself, + # but let the params override that + IkiWiki::Plugin::trail::preprocess_trailitems(sort => 'age', %params); + } + + return; + } + + if (yesno($params{trail}) && IkiWiki::Plugin::trail->can("preprocess_trailitems")) { + scalar IkiWiki::Plugin::trail::preprocess_trailitems(sort => 'age', %params); + } + + my $raw=yesno($params{raw}); + my $archive=yesno($params{archive}); + my $rss=(($config{rss} || $config{allowrss}) && exists $params{rss}) ? yesno($params{rss}) : $config{rss}; + my $atom=(($config{atom} || $config{allowatom}) && exists $params{atom}) ? yesno($params{atom}) : $config{atom}; + my $quick=exists $params{quick} ? yesno($params{quick}) : 0; + my $feeds=exists $params{feeds} ? yesno($params{feeds}) : !$quick && ! $raw; + my $emptyfeeds=exists $params{emptyfeeds} ? yesno($params{emptyfeeds}) : 1; + my $feedonly=yesno($params{feedonly}); + if (! exists $params{show} && ! $archive) { + $params{show}=10; + } + if (! exists $params{feedshow} && exists $params{show}) { + $params{feedshow}=$params{show}; + } + my $title; + if (exists $params{title}) { + $title = $params{title}; + } + else { + $title = $params{page} ne "index" ? pagetitle($params{page}) : $config{wikiname}; + } + my $desc; + if (exists $params{description}) { + $desc = $params{description} + } + else { + $desc = $config{wikiname}; + } + my $actions=yesno($params{actions}); + if (exists $params{template}) { + $params{template}=~s/[^-_a-zA-Z0-9]+//g; + } + else { + $params{template} = $archive ? "archivepage" : "inlinepage"; + } + + my @list; + + if (exists $params{pagenames}) { + foreach my $p (qw(sort pages)) { + if (exists $params{$p}) { + error sprintf(gettext("the %s and %s parameters cannot be used together"), + "pagenames", $p); + } + } + + @list = split ' ', $params{pagenames}; + + if (yesno($params{reverse})) { + @list=reverse(@list); + } + + foreach my $p (@list) { + add_depends($params{page}, $p, deptype($quick ? "presence" : "content")); + } + + @list = grep { exists $pagesources{$_} } @list; + } + else { + my $num=0; + if ($params{show}) { + $num=$params{show}; + } + if ($params{feedshow} && $num < $params{feedshow} && $num > 0) { + $num=$params{feedshow}; + } + if ($params{skip} && $num) { + $num+=$params{skip}; + } + + @list = pagespec_match_list($params{page}, $params{pages}, + deptype => deptype($quick ? "presence" : "content"), + filter => sub { $_[0] eq $params{page} }, + sort => exists $params{sort} ? $params{sort} : "age", + reverse => yesno($params{reverse}), + ($num ? (num => $num) : ()), + ); + } + + if (exists $params{skip}) { + @list=@list[$params{skip} .. $#list]; + } + + my @feedlist; + if ($feeds) { + if (exists $params{feedshow} && + $params{feedshow} && @list > $params{feedshow}) { + @feedlist=@list[0..$params{feedshow} - 1]; + } + else { + @feedlist=@list; + } + } + + if ($params{show} && @list > $params{show}) { + @list=@list[0..$params{show} - 1]; + } + + if ($feeds && exists $params{feedpages}) { + @feedlist = pagespec_match_list( + $params{page}, "($params{pages}) and ($params{feedpages})", + deptype => deptype($quick ? "presence" : "content"), + list => \@feedlist, + ); + } + + my ($feedbase, $feednum); + if ($feeds) { + # Ensure that multiple feeds on a page go to unique files. + + # Feedfile can lead to conflicts if usedirs is not enabled, + # so avoid supporting it in that case. + delete $params{feedfile} if ! $config{usedirs}; + # Tight limits on legal feedfiles, to avoid security issues + # and conflicts. + if (defined $params{feedfile}) { + if ($params{feedfile} =~ /\// || + $params{feedfile} !~ /$config{wiki_file_regexp}/) { + error("illegal feedfile"); + } + $params{feedfile}=possibly_foolish_untaint($params{feedfile}); + } + $feedbase=targetpage($params{page}, "", $params{feedfile}); + + my $feedid=join("\0", $feedbase, map { $_."\0".$params{$_} } sort keys %params); + if (exists $knownfeeds{$feedid}) { + $feednum=$knownfeeds{$feedid}; + } + else { + if (exists $page_numfeeds{$params{destpage}}{$feedbase}) { + if ($feeds) { + $feednum=$knownfeeds{$feedid}=++$page_numfeeds{$params{destpage}}{$feedbase}; + } + } + else { + $feednum=$knownfeeds{$feedid}=""; + if ($feeds) { + $page_numfeeds{$params{destpage}}{$feedbase}=1; + } + } + } + } + + my ($rssurl, $atomurl, $rssdesc, $atomdesc); + if ($feeds) { + if ($rss) { + $rssurl=abs2rel($feedbase."rss".$feednum, dirname(htmlpage($params{destpage}))); + $rssdesc = sprintf(gettext("%s (RSS feed)"), $desc); + } + if ($atom) { + $atomurl=abs2rel($feedbase."atom".$feednum, dirname(htmlpage($params{destpage}))); + $atomdesc = sprintf(gettext("%s (Atom feed)"), $desc); + } + } + + my $ret=""; + + my $postform = (exists $params{rootpage}); + if (exists $params{postform}) { + $postform = yesno($params{postform}); + } + + if (length $config{cgiurl} && ! $params{preview} && $postform && + IkiWiki->can("cgi_editpage")) { + # Add a blog post form, with feed buttons. + my $formtemplate=template_depends("blogpost.tmpl", $params{page}, blind_cache => 1); + $formtemplate->param(cgiurl => IkiWiki::cgiurl()); + $formtemplate->param(rootpage => rootpage(%params)); + if ($feeds) { + if ($rss) { + $formtemplate->param(rssurl => $rssurl); + $formtemplate->param(rssdesc => $rssdesc); + } + if ($atom) { + $formtemplate->param(atomurl => $atomurl); + $formtemplate->param(atomdesc => $atomdesc); + } + } + if (exists $params{postformtext}) { + $formtemplate->param(postformtext => + $params{postformtext}); + } + else { + $formtemplate->param(postformtext => + gettext("Add a new post titled:")); + } + if (exists $params{id}) { + $formtemplate->param(postformid => + $params{id}); + } + $ret.=$formtemplate->output; + + # The post form includes the feed buttons, so + # emptyfeeds cannot be hidden. + $emptyfeeds=1; + } + elsif ($feeds && !$params{preview} && ($emptyfeeds || @feedlist)) { + # Add feed buttons. + my $linktemplate=template_depends("feedlink.tmpl", $params{page}, blind_cache => 1); + if ($rss) { + $linktemplate->param(rssurl => $rssurl); + $linktemplate->param(rssdesc => $rssdesc); + } + if ($atom) { + $linktemplate->param(atomurl => $atomurl); + $linktemplate->param(atomdesc => $atomdesc); + } + if (exists $params{id}) { + $linktemplate->param(id => $params{id}); + } + $ret.=$linktemplate->output; + } + + if (! $feedonly) { + my $template; + if (! $raw) { + # cannot use wiki pages as templates; template not sanitized due to + # format hook hack + eval { + $template=template_depends($params{template}.".tmpl", $params{page}, + blind_cache => 1); + }; + if ($@) { + # gettext can clobber $@ + my $error = $@; + error sprintf(gettext("failed to process template %s"), $params{template}.".tmpl").": $error"; + } + } + my $needcontent=$raw || (!($archive && $quick) && $template->query(name => 'content')); + + foreach my $page (@list) { + my $file = $pagesources{$page}; + my $type = pagetype($file); + if (! $raw) { + if ($needcontent) { + # Get the content before populating the + # template, since getting the content uses + # the same template if inlines are nested. + my $content=get_inline_content($page, $params{destpage}); + $template->param(content => $content); + } + $template->param(pageurl => urlto($page, $params{destpage})); + $template->param(inlinepage => $page); + $template->param(title => pagetitle(basename($page))); + $template->param(ctime => displaytime($pagectime{$page}, $params{timeformat}, 1)); + $template->param(mtime => displaytime($pagemtime{$page}, $params{timeformat})); + $template->param(first => 1) if $page eq $list[0]; + $template->param(last => 1) if $page eq $list[$#list]; + $template->param(html5 => $config{html5}); + + if ($actions) { + my $file = $pagesources{$page}; + my $type = pagetype($file); + if ($config{discussion}) { + if ($page !~ /.*\/\Q$config{discussionpage}\E$/i && + (length $config{cgiurl} || + exists $pagesources{$page."/".lc($config{discussionpage})})) { + $template->param(have_actions => 1); + $template->param(discussionlink => + htmllink($page, + $params{destpage}, + $config{discussionpage}, + noimageinline => 1, + forcesubpage => 1)); + } + } + if (length $config{cgiurl} && + defined $type && + IkiWiki->can("cgi_editpage")) { + $template->param(have_actions => 1); + $template->param(editurl => cgiurl(do => "edit", page => $page)); + + } + } + + run_hooks(pagetemplate => sub { + shift->(page => $page, destpage => $params{destpage}, + template => $template,); + }); + + $ret.=$template->output; + $template->clear_params; + } + else { + if (defined $type) { + $ret.="\n". + linkify($page, $params{destpage}, + preprocess($page, $params{destpage}, + filter($page, $params{destpage}, + readfile(srcfile($file))))); + } + else { + $ret.="\n". + readfile(srcfile($file)); + } + } + } + } + + if ($feeds && ($emptyfeeds || @feedlist)) { + if ($rss) { + my $rssp=$feedbase."rss".$feednum; + will_render($params{destpage}, $rssp); + if (! $params{preview}) { + writefile($rssp, $config{destdir}, + genfeed("rss", + $config{url}."/".$rssp, $title, $desc, $params{guid}, $params{page}, @feedlist)); + $toping{$params{destpage}}=1 unless $config{rebuild}; + $feedlinks{$params{destpage}}.=qq{}; + } + } + if ($atom) { + my $atomp=$feedbase."atom".$feednum; + will_render($params{destpage}, $atomp); + if (! $params{preview}) { + writefile($atomp, $config{destdir}, + genfeed("atom", $config{url}."/".$atomp, $title, $desc, $params{guid}, $params{page}, @feedlist)); + $toping{$params{destpage}}=1 unless $config{rebuild}; + $feedlinks{$params{destpage}}.=qq{}; + } + } + } + + clear_inline_content_cache(); + + return $ret if $raw || $nested; + push @inline, $ret; + return "
\n\n"; +} + +sub pagetemplate_inline (@) { + my %params=@_; + my $page=$params{page}; + my $template=$params{template}; + + $template->param(feedlinks => $feedlinks{$page}) + if exists $feedlinks{$page} && $template->query(name => "feedlinks"); +} + +{ +my %inline_content; +my $cached_destpage=""; + +sub get_inline_content ($$) { + my $page=shift; + my $destpage=shift; + + if (exists $inline_content{$page} && $cached_destpage eq $destpage) { + return $inline_content{$page}; + } + + my $file=$pagesources{$page}; + my $type=pagetype($file); + my $ret=""; + if (defined $type) { + $nested++; + $ret=htmlize($page, $destpage, $type, + linkify($page, $destpage, + preprocess($page, $destpage, + filter($page, $destpage, + readfile(srcfile($file)))))); + $nested--; + if (isinternal($page)) { + # make inlined text of internal pages searchable + run_hooks(indexhtml => sub { + shift->(page => $page, destpage => $destpage, + content => $ret); + }); + } + } + + if ($cached_destpage ne $destpage) { + clear_inline_content_cache(); + $cached_destpage=$destpage; + } + return $inline_content{$page}=$ret; +} + +sub clear_inline_content_cache () { + %inline_content=(); +} + +} + +sub date_822 ($) { + my $time=shift; + + my $lc_time=POSIX::setlocale(&POSIX::LC_TIME); + POSIX::setlocale(&POSIX::LC_TIME, "C"); + my $ret=POSIX::strftime("%a, %d %b %Y %H:%M:%S %z", localtime($time)); + POSIX::setlocale(&POSIX::LC_TIME, $lc_time); + return $ret; +} + +sub absolute_urls ($$) { + # needed because rss sucks + my $html=shift; + my $baseurl=shift; + + my $url=$baseurl; + $url=~s/[^\/]+$//; + my $urltop; # calculated if needed + + my $ret=""; + + eval q{use HTML::Parser; use HTML::Tagset}; + die $@ if $@; + my $p = HTML::Parser->new(api_version => 3); + $p->handler(default => sub { $ret.=join("", @_) }, "text"); + $p->handler(start => sub { + my ($tagname, $pos, $text) = @_; + if (ref $HTML::Tagset::linkElements{$tagname}) { + while (4 <= @$pos) { + # use attribute sets from right to left + # to avoid invalidating the offsets + # when replacing the values + my ($k_offset, $k_len, $v_offset, $v_len) = + splice(@$pos, -4); + my $attrname = lc(substr($text, $k_offset, $k_len)); + next unless grep { $_ eq $attrname } @{$HTML::Tagset::linkElements{$tagname}}; + next unless $v_offset; # 0 v_offset means no value + my $v = substr($text, $v_offset, $v_len); + $v =~ s/^([\'\"])(.*)\1$/$2/; + eval q{use HTML::Entities}; + my $dv = decode_entities($v); + if ($dv=~/^#/) { + $v=$baseurl.$v; # anchor + } + elsif ($dv=~/^(?!\w+:)[^\/]/) { + $v=$url.$v; # relative url + } + elsif ($dv=~/^\//) { + if (! defined $urltop) { + # what is the non path part of the url? + my $top_uri = URI->new($url); + $top_uri->path_query(""); # reset the path + $urltop = $top_uri->as_string; + } + $v=$urltop.$v; # url relative to top of site + } + $v =~ s/\"/"/g; # since we quote with "" + substr($text, $v_offset, $v_len) = qq("$v"); + } + } + $ret.=$text; + }, "tagname, tokenpos, text"); + $p->parse($html); + $p->eof; + + return $ret; +} + +sub genenclosure { + my $itemtemplate=shift; + my $url=shift; + my $file=shift; + + return unless $itemtemplate->query(name => "enclosure"); + + my $size=(srcfile_stat($file))[8]; + my $mime="unknown"; + eval q{use File::MimeInfo}; + if (! $@) { + $mime = mimetype($file); + } + $itemtemplate->param( + enclosure => $url, + type => $mime, + length => $size, + ); +} + +sub genfeed ($$$$$@) { + my $feedtype=shift; + my $feedurl=shift; + my $feedtitle=shift; + my $feeddesc=shift; + my $guid=shift; + my $page=shift; + my @pages=@_; + + my $url=URI->new(encode_utf8(urlto($page,"",1))); + + my $itemtemplate=template_depends($feedtype."item.tmpl", $page, blind_cache => 1); + my $content=""; + my $lasttime = 0; + foreach my $p (@pages) { + my $u=URI->new(encode_utf8(urlto($p, "", 1))); + my $pcontent = absolute_urls(get_inline_content($p, $page), $url); + my $fancy_enclosure_seen = 0; + + $itemtemplate->param( + title => pagetitle(basename($p)), + url => $u, + permalink => $u, + cdate_822 => date_822($pagectime{$p}), + mdate_822 => date_822($pagemtime{$p}), + cdate_3339 => date_3339($pagectime{$p}), + mdate_3339 => date_3339($pagemtime{$p}), + ); + + if (exists $pagestate{$p}) { + if (exists $pagestate{$p}{meta}{guid}) { + eval q{use HTML::Entities}; + $itemtemplate->param(guid => HTML::Entities::encode_numeric($pagestate{$p}{meta}{guid})); + } + + if (exists $pagestate{$p}{meta}{updated}) { + $itemtemplate->param(mdate_822 => date_822($pagestate{$p}{meta}{updated})); + $itemtemplate->param(mdate_3339 => date_3339($pagestate{$p}{meta}{updated})); + } + + if (exists $pagestate{$p}{meta}{enclosure}) { + my $absurl = $pagestate{$p}{meta}{enclosure}; + my $file = $pagestate{$p}{meta}{enclosurefile}; + genenclosure($itemtemplate, $absurl, $file); + $fancy_enclosure_seen = 1; + } + } + + my $file=$pagesources{$p}; + unless ($fancy_enclosure_seen || defined(pagetype($file))) { + genenclosure($itemtemplate, $u, $file); + $itemtemplate->param(simplepodcast => 1); + } + + $itemtemplate->param(content => $pcontent); + + run_hooks(pagetemplate => sub { + shift->(page => $p, destpage => $page, + template => $itemtemplate); + }); + + $content.=$itemtemplate->output; + $itemtemplate->clear_params; + + $lasttime = $pagemtime{$p} if $pagemtime{$p} > $lasttime; + } + + my $template=template_depends($feedtype."page.tmpl", $page, blind_cache => 1); + $template->param( + title => $feedtitle, + wikiname => $config{wikiname}, + pageurl => $url, + content => $content, + feeddesc => $feeddesc, + guid => $guid, + feeddate => date_3339($lasttime), + feeddate_822 => date_822($lasttime), + feedurl => $feedurl, + ); + run_hooks(pagetemplate => sub { + shift->(page => $page, destpage => $page, + template => $template); + }); + + return $template->output; +} + +sub pingurl (@) { + return unless @{$config{pingurl}} && %toping; + + eval q{require RPC::XML::Client}; + if ($@) { + debug(gettext("RPC::XML::Client not found, not pinging")); + return; + } + + # daemonize here so slow pings don't slow down wiki updates + defined(my $pid = fork) or error("Can't fork: $!"); + return if $pid; + chdir '/'; + POSIX::setsid() or error("Can't start a new session: $!"); + open STDIN, '/dev/null'; + open STDOUT, '>/dev/null'; + open STDERR, '>&STDOUT' or error("Can't dup stdout: $!"); + + # Don't need to keep a lock on the wiki as a daemon. + IkiWiki::unlockwiki(); + + foreach my $page (keys %toping) { + my $title=pagetitle(basename($page), 0); + my $url=urlto($page, "", 1); + foreach my $pingurl (@{$config{pingurl}}) { + debug("Pinging $pingurl for $page"); + eval { + my $client = RPC::XML::Client->new($pingurl); + my $req = RPC::XML::request->new('weblogUpdates.ping', + $title, $url); + my $res = $client->send_request($req); + if (! ref $res) { + error("Did not receive response to ping"); + } + my $r=$res->value; + if (! exists $r->{flerror} || $r->{flerror}) { + error("Ping rejected: ".(exists $r->{message} ? $r->{message} : "[unknown reason]")); + } + }; + if ($@) { + error "Ping failed: $@"; + } + } + } + + exit 0; # daemon done +} + + +sub rootpage (@) { + my %params=@_; + + my $rootpage; + if (exists $params{rootpage}) { + $rootpage=bestlink($params{page}, $params{rootpage}); + if (!length $rootpage) { + $rootpage=$params{rootpage}; + } + } + else { + $rootpage=$params{page}; + } + return $rootpage; +} + +1 diff --git a/IkiWiki/Plugin/link.pm b/IkiWiki/Plugin/link.pm new file mode 100644 index 000000000..1ba28eafd --- /dev/null +++ b/IkiWiki/Plugin/link.pm @@ -0,0 +1,176 @@ +#!/usr/bin/perl +package IkiWiki::Plugin::link; + +use warnings; +use strict; +use IkiWiki 3.00; + +my $link_regexp; + +my $email_regexp = qr/^.+@.+\..+$/; +my $url_regexp = qr/^(?:[^:]+:\/\/|mailto:).*/i; + +sub import { + hook(type => "getsetup", id => "link", call => \&getsetup); + hook(type => "checkconfig", id => "link", call => \&checkconfig); + hook(type => "linkify", id => "link", call => \&linkify); + hook(type => "scan", id => "link", call => \&scan); + hook(type => "renamepage", id => "link", call => \&renamepage); +} + +sub getsetup () { + return + plugin => { + safe => 1, + rebuild => 1, + section => "core", + }, +} + +sub checkconfig () { + if ($config{prefix_directives}) { + $link_regexp = qr{ + \[\[(?=[^!]) # beginning of link + (?: + ([^\]\|]+) # 1: link text + \| # followed by '|' + )? # optional + + ([^\n\r\]#]+) # 2: page to link to + (?: + \# # '#', beginning of anchor + ([^\s\]]+) # 3: anchor text + )? # optional + + \]\] # end of link + }x; + } + else { + $link_regexp = qr{ + \[\[ # beginning of link + (?: + ([^\]\|\n\s]+) # 1: link text + \| # followed by '|' + )? # optional + + ([^\s\]#]+) # 2: page to link to + (?: + \# # '#', beginning of anchor + ([^\s\]]+) # 3: anchor text + )? # optional + + \]\] # end of link + }x; + } +} + +sub is_externallink ($$;$) { + my $page = shift; + my $url = shift; + my $anchor = shift; + + if (defined $anchor) { + $url.="#".$anchor; + } + + return ($url =~ /$url_regexp|$email_regexp/) +} + +sub externallink ($$;$) { + my $url = shift; + my $anchor = shift; + my $pagetitle = shift; + + if (defined $anchor) { + $url.="#".$anchor; + } + + # build pagetitle + if (! $pagetitle) { + $pagetitle = $url; + # use only the email address as title for mailto: urls + if ($pagetitle =~ /^mailto:.*/) { + $pagetitle =~ s/^mailto:([^?]+).*/$1/; + } + } + + if ($url !~ /$url_regexp/) { + # handle email addresses (without mailto:) + $url = "mailto:" . $url; + } + + return "$pagetitle"; +} + +sub linkify (@) { + my %params=@_; + my $page=$params{page}; + my $destpage=$params{destpage}; + + $params{content} =~ s{(\\?)$link_regexp}{ + defined $2 + ? ( $1 + ? "[[$2|$3".(defined $4 ? "#$4" : "")."]]" + : is_externallink($page, $3, $4) + ? externallink($3, $4, $2) + : htmllink($page, $destpage, linkpage($3), + anchor => $4, linktext => pagetitle($2))) + : ( $1 + ? "[[$3".(defined $4 ? "#$4" : "")."]]" + : is_externallink($page, $3, $4) + ? externallink($3, $4) + : htmllink($page, $destpage, linkpage($3), + anchor => $4)) + }eg; + + return $params{content}; +} + +sub scan (@) { + my %params=@_; + my $page=$params{page}; + my $content=$params{content}; + + while ($content =~ /(? "getsetup", id => "linkmap", call => \&getsetup); + hook(type => "preprocess", id => "linkmap", call => \&preprocess); +} + +sub getsetup () { + return + plugin => { + safe => 1, + rebuild => undef, + section => "widget", + }, +} + +my $mapnum=0; + +sub pageescape { + my $item = shift; + # encoding explicitly in case ikiwiki is configured to accept <> or & + # in file names + my $title = pagetitle($item, 1); + # it would not be necessary to encode *all* the html entities (<> would + # be sufficient, &" probably a good idea), as dot accepts utf8, but it + # isn't bad either + $title = encode_entities($title); + return("<$title>"); +} + +sub preprocess (@) { + my %params=@_; + + $params{pages}="*" unless defined $params{pages}; + + $mapnum++; + my $connected=IkiWiki::yesno($params{connected}); + + # Get all the items to map. + my %mapitems = map { $_ => urlto($_, $params{destpage}) } + pagespec_match_list($params{page}, $params{pages}, + # update when a page is added or removed, or its + # links change + deptype => deptype("presence", "links")); + + my $dest=$params{page}."/linkmap.png"; + + # Use ikiwiki's function to create the file, this makes sure needed + # subdirs are there and does some sanity checking. + will_render($params{page}, $dest); + writefile($dest, $config{destdir}, ""); + + # Run dot to create the graphic and get the map data. + my $pid; + my $sigpipe=0; + $SIG{PIPE}=sub { $sigpipe=1 }; + $pid=open2(*IN, *OUT, "dot -Tpng -o '$config{destdir}/$dest' -Tcmapx"); + + # open2 doesn't respect "use open ':utf8'" + binmode (IN, ':utf8'); + binmode (OUT, ':utf8'); + + print OUT "digraph linkmap$mapnum {\n"; + print OUT "concentrate=true;\n"; + print OUT "charset=\"utf-8\";\n"; + print OUT "ratio=compress;\nsize=\"".($params{width}+0).", ".($params{height}+0)."\";\n" + if defined $params{width} and defined $params{height}; + my %shown; + my $show=sub { + my $item=shift; + if (! $shown{$item}) { + print OUT pageescape($item)." [shape=box,href=\"$mapitems{$item}\"];\n"; + $shown{$item}=1; + } + }; + foreach my $item (keys %mapitems) { + $show->($item) unless $connected; + foreach my $link (map { bestlink($item, $_) } @{$links{$item}}) { + next unless length $link and $mapitems{$link}; + foreach my $endpoint ($item, $link) { + $show->($endpoint); + } + print OUT pageescape($item)." -> ".pageescape($link).";\n"; + } + } + print OUT "}\n"; + close OUT || error gettext("failed to run dot"); + + local $/=undef; + my $ret="\"".gettext("linkmap").\n". + ; + close IN || error gettext("failed to run dot"); + + waitpid $pid, 0; + if ($?) { + error gettext("failed to run dot"); + } + $SIG{PIPE}="DEFAULT"; + error gettext("failed to run dot") if $sigpipe; + + return $ret; +} + +1 diff --git a/IkiWiki/Plugin/listdirectives.pm b/IkiWiki/Plugin/listdirectives.pm new file mode 100644 index 000000000..835e25388 --- /dev/null +++ b/IkiWiki/Plugin/listdirectives.pm @@ -0,0 +1,100 @@ +#!/usr/bin/perl +# Ikiwiki listdirectives plugin. +package IkiWiki::Plugin::listdirectives; + +use warnings; +use strict; +use IkiWiki 3.00; + +sub import { + add_underlay("directives"); + hook(type => "getsetup", id => "listdirectives", call => \&getsetup); + hook(type => "checkconfig", id => "listdirectives", call => \&checkconfig); + hook(type => "needsbuild", id => "listdirectives", call => \&needsbuild); + hook(type => "preprocess", id => "listdirectives", call => \&preprocess); +} + +sub getsetup () { + return + plugin => { + safe => 1, + rebuild => undef, + section => "widget", + }, + directive_description_dir => { + type => "string", + description => "directory in srcdir that contains directive descriptions", + example => "ikiwiki/directive", + safe => 1, + rebuild => 1, + }, +} + +my @fulllist; +my @shortlist; +my $pluginstring; + +sub checkconfig () { + if (! defined $config{directive_description_dir}) { + $config{directive_description_dir} = "ikiwiki/directive"; + } + else { + $config{directive_description_dir} =~ s/\/+$//; + } +} + +sub needsbuild (@) { + my $needsbuild=shift; + + @fulllist = grep { ! /^_/ } sort keys %{$IkiWiki::hooks{preprocess}}; + @shortlist = grep { ! $IkiWiki::hooks{preprocess}{$_}{shortcut} } @fulllist; + $pluginstring = join(' ', @shortlist) . " : " . join(' ', @fulllist); + + foreach my $page (keys %pagestate) { + if (exists $pagestate{$page}{listdirectives}{shown}) { + if ($pagestate{$page}{listdirectives}{shown} ne $pluginstring) { + push @$needsbuild, $pagesources{$page}; + } + if (exists $pagesources{$page} && + grep { $_ eq $pagesources{$page} } @$needsbuild) { + # remove state, will be re-added if + # the [[!listdirectives]] is still there during the + # rebuild + delete $pagestate{$page}{listdirectives}{shown}; + } + } + } + + return $needsbuild; +} + +sub preprocess (@) { + my %params=@_; + + $pagestate{$params{destpage}}{listdirectives}{shown}=$pluginstring; + + my @pluginlist; + + if (defined $params{generated}) { + @pluginlist = @fulllist; + } + else { + @pluginlist = @shortlist; + } + + my $result = '
    '; + + foreach my $plugin (@pluginlist) { + $result .= '
  • '; + my $link=linkpage($config{directive_description_dir}."/".$plugin); + add_depends($params{page}, $link, deptype("presence")); + $result .= htmllink($params{page}, $params{destpage}, $link); + $result .= '
  • '; + } + + $result .= "
"; + + return $result; +} + +1 diff --git a/IkiWiki/Plugin/localstyle.pm b/IkiWiki/Plugin/localstyle.pm new file mode 100644 index 000000000..111f4dc30 --- /dev/null +++ b/IkiWiki/Plugin/localstyle.pm @@ -0,0 +1,35 @@ +#!/usr/bin/perl + +package IkiWiki::Plugin::localstyle; + +use warnings; +use strict; +use IkiWiki 3.00; + +sub import { + hook(type => "getsetup", id => "localstyle", call => \&getsetup); + hook(type => "pagetemplate", id => "localstyle", call => \&pagetemplate); +} + +sub getsetup () { + return + plugin => { + safe => 1, + rebuild => 1, + }, +} + +sub pagetemplate (@) { + my %params=@_; + + my $template=$params{template}; + + if ($template->query(name => "local_css")) { + my $best=bestlink($params{page}, 'local.css'); + if ($best) { + $template->param(local_css => $best); + } + } +} + +1 diff --git a/IkiWiki/Plugin/lockedit.pm b/IkiWiki/Plugin/lockedit.pm new file mode 100644 index 000000000..5b50fd115 --- /dev/null +++ b/IkiWiki/Plugin/lockedit.pm @@ -0,0 +1,58 @@ +#!/usr/bin/perl +package IkiWiki::Plugin::lockedit; + +use warnings; +use strict; +use IkiWiki 3.00; + +sub import { + hook(type => "getsetup", id => "lockedit", call => \&getsetup); + hook(type => "canedit", id => "lockedit", call => \&canedit); +} + +sub getsetup () { + return + plugin => { + safe => 1, + rebuild => 0, + section => "auth", + }, + locked_pages => { + type => "pagespec", + example => "!*/Discussion", + description => "PageSpec controlling which pages are locked", + link => "ikiwiki/PageSpec", + safe => 1, + rebuild => 0, + }, +} + +sub canedit ($$) { + my $page=shift; + my $cgi=shift; + my $session=shift; + + my $user=$session->param("name"); + return undef if defined $user && IkiWiki::is_admin($user); + + if (defined $config{locked_pages} && length $config{locked_pages} && + pagespec_match($page, $config{locked_pages}, + user => $session->param("name"), + ip => $session->remote_addr(), + )) { + if ((! defined $user || + ! IkiWiki::userinfo_get($session->param("name"), "regdate")) && + exists $IkiWiki::hooks{auth}) { + return sub { IkiWiki::needsignin($cgi, $session) }; + } + else { + return sprintf(gettext("%s is locked and cannot be edited"), + htmllink("", "", $page, noimageinline => 1)); + + } + } + + return undef; +} + +1 diff --git a/IkiWiki/Plugin/map.pm b/IkiWiki/Plugin/map.pm new file mode 100644 index 000000000..4a9bf58db --- /dev/null +++ b/IkiWiki/Plugin/map.pm @@ -0,0 +1,163 @@ +#!/usr/bin/perl +# +# Produce a hierarchical map of links. +# +# by Alessandro Dotti Contra +# +# Revision: 0.2 +package IkiWiki::Plugin::map; + +use warnings; +use strict; +use IkiWiki 3.00; + +sub import { + hook(type => "getsetup", id => "map", call => \&getsetup); + hook(type => "preprocess", id => "map", call => \&preprocess); +} + +sub getsetup () { + return + plugin => { + safe => 1, + rebuild => undef, + section => "widget", + }, +} + +sub preprocess (@) { + my %params=@_; + $params{pages}="*" unless defined $params{pages}; + + # Needs to update whenever a page is added or removed (or in some + # cases, when its content changes, if show= is specified). + my $deptype=deptype(exists $params{show} ? "content" : "presence"); + + my $common_prefix; + + # Get all the items to map. + my %mapitems; + foreach my $page (pagespec_match_list($params{page}, $params{pages}, + deptype => $deptype)) { + if (exists $params{show} && + exists $pagestate{$page} && + exists $pagestate{$page}{meta}{$params{show}}) { + $mapitems{$page}=$pagestate{$page}{meta}{$params{show}}; + } + else { + $mapitems{$page}=''; + } + # Check for a common prefix. + if (! defined $common_prefix) { + $common_prefix=$page; + } + elsif (length $common_prefix && + $page !~ /^\Q$common_prefix\E(\/|$)/) { + my @a=split(/\//, $page); + my @b=split(/\//, $common_prefix); + $common_prefix=""; + while (@a && @b && $a[0] eq $b[0]) { + if (length $common_prefix) { + $common_prefix.="/"; + } + $common_prefix.=shift(@a); + shift @b; + } + } + } + + # Common prefix should not be a page in the map. + while (defined $common_prefix && length $common_prefix && + exists $mapitems{$common_prefix}) { + $common_prefix=IkiWiki::dirname($common_prefix); + } + + # Set this to 1 or more spaces to pretty-print maps for debugging + my $spaces = ""; + + # Create the map. + my $parent=""; + my $indent=0; + my $openli=0; + my $addparent=""; + my $map = "
\n"; + + if (! keys %mapitems) { + # return empty div for empty map + $map .= "
\n"; + return $map; + } + else { + $map .= "
    \n"; + } + + foreach my $item (sort keys %mapitems) { + my @linktext = (length $mapitems{$item} ? (linktext => $mapitems{$item}) : ()); + $item=~s/^\Q$common_prefix\E\/// + if defined $common_prefix && length $common_prefix; + my $depth = ($item =~ tr/\//\//) + 1; + my $baseitem=IkiWiki::dirname($item); + while (length $parent && length $baseitem && $baseitem !~ /^\Q$parent\E(\/|$)/) { + $parent=IkiWiki::dirname($parent); + last if length $addparent && $baseitem =~ /^\Q$addparent\E(\/|$)/; + $addparent=""; + $map .= ($spaces x $indent) . "\n"; + if ($indent > 1) { + $map .= ($spaces x $indent) . "
\n"; + } + $indent--; + } + while ($depth < $indent) { + $map .= ($spaces x $indent) . "\n"; + if ($indent > 1) { + $map .= ($spaces x $indent) . "\n"; + } + $indent--; + } + my @bits=split("/", $item); + my $p=""; + $p.="/".shift(@bits) for 1..$indent; + while ($depth > $indent) { + $indent++; + if ($indent > 1) { + $map .= ($spaces x $indent) . "
    \n"; + } + if ($depth > $indent) { + $p.="/".shift(@bits); + $addparent=$p; + $addparent=~s/^\///; + $map .= ($spaces x $indent) . "
  • \n"; + $map .= ($spaces x $indent) + .htmllink($params{page}, $params{destpage}, + "/".$common_prefix.$p, class => "mapparent", + noimageinline => 1) + ."\n"; + $openli=1; + } + else { + $openli=0; + } + } + $map .= ($spaces x $indent) . "
  • \n" if $openli; + $map .= ($spaces x $indent) . "
  • \n"; + $map .= ($spaces x $indent) + .htmllink($params{page}, $params{destpage}, + "/".$common_prefix."/".$item, + @linktext, + class => "mapitem", noimageinline => 1) + ."\n"; + $openli=1; + $parent=$item; + } + while ($indent > 0) { + $map .= ($spaces x $indent) . "
  • \n"; + $indent--; + $map .= ($spaces x $indent) . "
\n"; + } + $map =~ s{\n *\n *
    \n}{\n}gs; + $map =~ s{}{}g; + $map .= "
\n"; + return $map; +} + +1 diff --git a/IkiWiki/Plugin/mdwn.pm b/IkiWiki/Plugin/mdwn.pm new file mode 100644 index 000000000..014e78eea --- /dev/null +++ b/IkiWiki/Plugin/mdwn.pm @@ -0,0 +1,118 @@ +#!/usr/bin/perl +# Markdown markup language +package IkiWiki::Plugin::mdwn; + +use warnings; +use strict; +use IkiWiki 3.00; + +sub import { + hook(type => "getsetup", id => "mdwn", call => \&getsetup); + hook(type => "htmlize", id => "mdwn", call => \&htmlize, longname => "Markdown"); +} + +sub getsetup () { + return + plugin => { + safe => 1, + rebuild => 1, # format plugin + section => "format", + }, + multimarkdown => { + type => "boolean", + example => 0, + description => "enable multimarkdown features?", + safe => 1, + rebuild => 1, + }, + nodiscount => { + type => "boolean", + example => 0, + description => "disable use of markdown discount?", + safe => 1, + rebuild => 1, + }, +} + +my $markdown_sub; +sub htmlize (@) { + my %params=@_; + my $content = $params{content}; + + if (! defined $markdown_sub) { + # Markdown is forked and splintered upstream and can be + # available in a variety of forms. Support them all. + no warnings 'once'; + $blosxom::version="is a proper perl module too much to ask?"; + use warnings 'all'; + + if (exists $config{multimarkdown} && $config{multimarkdown}) { + eval q{use Text::MultiMarkdown}; + if ($@) { + debug(gettext("multimarkdown is enabled, but Text::MultiMarkdown is not installed")); + } + else { + $markdown_sub=sub { + Text::MultiMarkdown::markdown(shift, {use_metadata => 0}); + } + } + } + if (! defined $markdown_sub && + (! exists $config{nodiscount} || ! $config{nodiscount})) { + eval q{use Text::Markdown::Discount}; + if (! $@) { + $markdown_sub=sub { + my $t=shift; + # Workaround for discount binding bug + # https://rt.cpan.org/Ticket/Display.html?id=73657 + return "" if $t=~/^\s*$/; + # Workaround for discount's eliding + # of + +Notice the trailing `/` after the `icon.png`. This breaks display on nginx - the file that gets served isn't the icon, but the frontpage for some reason. I followed the [[setup instructions|tips/dot cgi]] for Nginx that I just had to write because there weren't any, so maybe I screwed up some part, but it does seem to me that the trailing slash is wrong regardless. + +(Also notice how the style tag is being turned over backwards by the HTML sanitizer here, cute. :P) + +I wrote a crude hack for this, but this strikes me as a similar problem to the one we found in [[bugs/osm linkto() usage breaks map rendering]]. However, I am at a loss how to fix this cleanly because we cannot `will_render()` the tag icons, as they are already generated out there! Weird. Anyways, here's the stupid [[patch]]: + +[[!format diff """ +diff --git a/IkiWiki/Plugin/osm.pm b/IkiWiki/Plugin/osm.pm +index a7baa5f..c9650d0 100644 +--- a/IkiWiki/Plugin/osm.pm ++++ b/IkiWiki/Plugin/osm.pm +@@ -192,6 +192,7 @@ sub process_waypoint { + } + } + $icon = urlto($icon, $dest, 1); ++ $icon =~ s!/*$!!; # hack - urlto shouldn't be appending a slash in the first place + $tag = '' unless $tag; + register_rendered_files($map, $page, $dest); + $pagestate{$page}{'osm'}{$map}{'waypoints'}{$name} = { +"""]] + +I'm not writing this to a branch out of sheer shame of my misunderstanding. ;) There also may be a workaround that could be done in Nginx too. --[[anarcat]] + +> [[applied|done]], but I'm not happy with this either --[[Joey]] diff --git a/doc/bugs/osm_linkto__40____41___usage_breaks_map_rendering.mdwn b/doc/bugs/osm_linkto__40____41___usage_breaks_map_rendering.mdwn new file mode 100644 index 000000000..89c08b73c --- /dev/null +++ b/doc/bugs/osm_linkto__40____41___usage_breaks_map_rendering.mdwn @@ -0,0 +1,23 @@ +[[!template id=gitbranch branch=anarcat/master author="[[anarcat]]"]] + +Under some circumstances that remain unclear to me, the usage of `urlto()` in the revised version of the [[plugins/osm]] plugin break the map totally. The javascript console in Chromium tells me the following: + + GET http://mesh.openisp.ca/map/pois.kml/ 404 (Not Found) + +Indeed, that URL yields a 404. The proper URL is . --[[anarcat]] + +## Proposed solution + +The problem seems to be caused by `urlto()` being called for the `osm` +directive before the generated files are registered with `will_render()` +from the `waypoint` directive. Proposed patch adds a function that is +called from the `preprocess` hook for both directives that registers the +files. + +Here is a [[patch]] to IkiWiki/Plugin/osm.pm: + +--[[deuxpi]] + +I confirm the patch works, and I added it to my master branch. --[[anarcat]] + +> [[applied|done]]. Thanks guys. --[[Joey]] diff --git a/doc/bugs/osm_plugin_error_TypeError:_mapProjection_is_null.mdwn b/doc/bugs/osm_plugin_error_TypeError:_mapProjection_is_null.mdwn new file mode 100644 index 000000000..42e2edb2c --- /dev/null +++ b/doc/bugs/osm_plugin_error_TypeError:_mapProjection_is_null.mdwn @@ -0,0 +1,8 @@ +[[!template id=gitbranch branch=cbaines/osm-layers-patch author="[[cbaines]]"]] + +Using the osm plugin with a simple \[[!osm]] directive does not seem to work, a "TypeError: mapProjection is null" is given. I believe this is because the client side Javascript uses the options.layers, which is always Null. + +[[!tag patch]] +I have produced a patch for this issue, but beware, while it appears to fix the problem for me, I have little understanding of perl and the existing code base. + +> It looks sound, but I have yet to test it. --[[anarcat]] diff --git a/doc/bugs/osm_sometimes_looses_some_nodes.mdwn b/doc/bugs/osm_sometimes_looses_some_nodes.mdwn new file mode 100644 index 000000000..9de1b4e23 --- /dev/null +++ b/doc/bugs/osm_sometimes_looses_some_nodes.mdwn @@ -0,0 +1,5 @@ +I have heard repeated reports on that editing a page that has a waypoint in it will sometimes make that waypoint disappear from the main map. I have yet to understand why that happens or how, but multiple users have reported that. + +A workaround is to rebuild the whole wiki, although sometimes re-editing the same page will bring the waypoint back on the map. + +I have been able to reproduce this by simply creating a new node. It will not show up on the map until the wiki is rebuilt or the node is resaved. -- [[anarcat]] diff --git a/doc/bugs/output_of_successful_rename_should_list_the_full_path_to_affected_pages.mdwn b/doc/bugs/output_of_successful_rename_should_list_the_full_path_to_affected_pages.mdwn new file mode 100644 index 000000000..132d23463 --- /dev/null +++ b/doc/bugs/output_of_successful_rename_should_list_the_full_path_to_affected_pages.mdwn @@ -0,0 +1,14 @@ +I've just renamed a page and received the following as a result: + +

+Successfully renamed users/jondowland.mdwn to users/jon.mdwn. +

+

+ +The following pages have been automatically modified to update their links to users/jon.mdwn: +

... + +In this situation I think the link to pages should be expanded to show the entire path, since there is quite likely to be a lot of things like "discussion". -- [[users/Jon]] + +[[done]] diff --git a/doc/bugs/package_build_fails_in_non-English_environment.mdwn b/doc/bugs/package_build_fails_in_non-English_environment.mdwn new file mode 100644 index 000000000..521ba62f8 --- /dev/null +++ b/doc/bugs/package_build_fails_in_non-English_environment.mdwn @@ -0,0 +1,11 @@ +basewiki_brokenlinks.t fails when running dpkg-buildpackage in non-English environment : it greps for an (non-)error message that is i18n'd. This of course does not happen when building in a proper chroot environment... which happens to fail as well, for other reasons, but this will be for another bug. + +The `LANG=` on line 9 does not seem to do what it's supposed to, go figure. + +I've never had to understand the Unix locales, so I randomly tried to replace `LANG=` in basewiki_brokenlinks.t with : + +- `LANG=C` : fails +- `LANGUAGE=` : fails +- `LANGUAGE=C` : works! + +> For maximum precedence it should have been LC_ALL=C. [[done]], I think... --[[smcv]] diff --git a/doc/bugs/page_is_not_rebuilt_if_it_changes_extension.mdwn b/doc/bugs/page_is_not_rebuilt_if_it_changes_extension.mdwn new file mode 100644 index 000000000..e47be8d28 --- /dev/null +++ b/doc/bugs/page_is_not_rebuilt_if_it_changes_extension.mdwn @@ -0,0 +1,27 @@ +Suppose a wiki has a source page a.mdwn, which is then moved to a.wiki. +(Suppose both the mdwn and wikitext plugins are enabled, so this changes how "a" is rendered.) +Currently, when the wiki is refreshed, ikiwiki doesn't notice the change +and the page is not rebuilt. + +I have a [[patch]] that fixes this. +The relevant commit on [my Github fork of ikiwiki](http://github.com/gmcmanus/ikiwiki/) is: + + b6a3b8a683fed7a7f6d77a5b3f2dfbd14c849843 + +The patch (ab)uses`%forcerebuild`, which is meant for use by plugins. +If, for some reason, a plugin deletes the page's entry in `%forcerebuild`, it won't be rebuilt. + +This patch uncovers another problem. +Suppose a wiki has a source page "a" (no extension) +which is then moved to "a.mdwn" (or vice versa). +ikiwiki fails when trying to create a directory "a" where there is a file "a" +(or vice versa). + +The same problem occurs if both "a" and "a.mdwn" exist in the wiki. + +> Thank you for looking into it! +> +> On the use of forcerebuild, I think it's acceptable; plugins that unset +> it would break other plugins that set it, too. +> +> [[cherry-picked|done]] --[[Joey]] diff --git a/doc/bugs/page_preview_does_not_work_on_new_page_with_a_table.mdwn b/doc/bugs/page_preview_does_not_work_on_new_page_with_a_table.mdwn new file mode 100644 index 000000000..65dffd671 --- /dev/null +++ b/doc/bugs/page_preview_does_not_work_on_new_page_with_a_table.mdwn @@ -0,0 +1,3 @@ +If the table plugin is enabled, then creating a page, inserting a `\[[!table ...]` and clicking preview yields "htmlization of not supported" (sic). --[[madduck]] + +[[fix0red|done]] --[[Joey]] diff --git a/doc/bugs/pagecount_is_broken.mdwn b/doc/bugs/pagecount_is_broken.mdwn new file mode 100644 index 000000000..57df6b75d --- /dev/null +++ b/doc/bugs/pagecount_is_broken.mdwn @@ -0,0 +1,4 @@ +The [[plugins/pagecount]] plugin seems to be broken, as it claims there are +\[[!pagecount ]] pages in this wiki. (if it's not 0, the bug is fixed) + +[[fixed|done]] --[[Joey]] diff --git a/doc/bugs/pagemtime_in_refresh_mode.mdwn b/doc/bugs/pagemtime_in_refresh_mode.mdwn new file mode 100644 index 000000000..f926ec86c --- /dev/null +++ b/doc/bugs/pagemtime_in_refresh_mode.mdwn @@ -0,0 +1,28 @@ +I'd like a way to always ask the RCS (Git) to update a file's mtime in +refresh mode. This is currently only done on the first build, and later +for `--gettime --rebuild`. But always rebuilding is too heavy-weight for +this use-case. My options are to either manually set the mtime before +refreshing, or to have ikiwiki do it at command. I used to do the +former, but would now like the latter, as ikiwiki now generally does this +timestamp handling. + +From a quick look, the code in `IkiWiki/Render.pm:find_new_files` is +relevant: `if (! $pagemtime{$page}) { [...]`. + +How would you like to tackle this? + +--[[tschwinge]] + +> This could be done via a `needsbuild` hook. The hook is passed +> the list of changed files, and it should be safe to call `rcs_getmtime` +> and update the `pagemtime` for each. +> +> That lets the feature be done by a plugin, which seems good, since +> `rcs_getmtime` varies between very slow and not very fast, depending on +> VCS. +> +> AFAICS, the only use case for doing this is if you commit changes and +> then delay pushing them to a DVCS repo. Since then the file mtime will +> be when the change was pushed, not when it was committed. But I've +> generally felt that recording when a change was published to the repo +> of a wiki as its mtime is good enough. --[[Joey]] diff --git a/doc/bugs/pages_missing_top-level_directory.mdwn b/doc/bugs/pages_missing_top-level_directory.mdwn new file mode 100644 index 000000000..77c31cd27 --- /dev/null +++ b/doc/bugs/pages_missing_top-level_directory.mdwn @@ -0,0 +1,78 @@ +Hi, + +I've rebuilt two sites now, and anything that requires a working directory structure isn't working properly. I have no idea how it's doing this. I don't see anything in my templates, and I haven't messed around with the back-end code much. + +An example would show this best I think. + +
+/                   <- root of site
+/About/             <- sub-directory
+      /Policy/      <- sub-sub-
+
+ +When you're on /About/, any generated links get mapped to /Policy/ and NOT /About/Policy/ - of course this results in a 404 error. + +I used to be able to use relative links or absolute ones to get the links I want, and now I can't do either. The generated link results in a 404 due to the stripping of a directory. + +I don't know if it's related to the fact that I have one ikiwiki install under another (/blog/ under / is also ikiwiki), but both are FUBAR. + +> what do you mean by generated links: do you mean the output of +> [[ikiwiki/wikilink]]s? Or are you generating links some other way? +> When you say "on /About/, any generated links get mapped to +> /Policy/ and NOT /About/Policy" can you provide an example of what +> source generates the link? -- [[Jon]] + +>> No, a \[[map]] call, such as: +>> +>> (actual code)
+>> = = = = =
+>> \[[!map pages="About/*" show="title"]]
+>> = = = = =
+>> +>> The end result is:
+>> (actual code) +>> +
+<div class="map">
+<ul>
+<li><a class="mapitem" href="./Policy/">Policy</a>
+<ul>
+<li><a class="mapitem" href="./Policy/Microblog/">Microblogging subscription policy</a>
+</li>
+</ul>
+</li>
+</ul>
+</div>
+
+ +> I'm also confused about what is generating the links. The map directive? +> You? --[[Joey]] + +>> see above :) + +>> I suspect this is due to git scanning everything under the pwd of the .git/ directory, but not totally so. + +>>> Ikiwiki never, ever, looks in directories with names starting with a +>>> dot. --[[Joey]] + +>> Other ikiwiki sites I have don't do this, and work OK, on the same server, but different docroots. + +>>> Well, I've moved my blog to under my site's docroot - in terms of git +>>> and ikiwiki - and it's still cutting out a whole directory level. I +>>> have no idea what's going on. I need to check the code. The site is at +>>> http://simonraven.kisikew.org/ - if you follow the "About" link, you'll +>>> understand exactly what's going on, if you look at the URL in your +>>> status bar (or under your cursor if you're using a text browser). + +>>>> Your page contains the following in its html: +>>>> `` +>>>> +>>>> Given a link like "./Policy/", which is *correct*, and when on the +>>>> About page will normally link to the About/Policy page, this causes +>>>> the link to really link to ".././Policy/" which is of course broken. +>>>> +>>>> Ikiwiki's standard page templates do not contain this base tag, so +>>>> I guess your customised templates are broken. --[[Joey]] [[done]] + +>>>>> I totally forgot about that tag... good catch. I was thinking it was my template that was broken, since yesterday, but I couldn't see what. Thank you very much for your eyes. + diff --git a/doc/bugs/pages_under_templates_are_invalid.mdwn b/doc/bugs/pages_under_templates_are_invalid.mdwn new file mode 100644 index 000000000..20d711fcb --- /dev/null +++ b/doc/bugs/pages_under_templates_are_invalid.mdwn @@ -0,0 +1,21 @@ +Pages under templates/ are invalid (in fact, not only invalid, but also not well-formed) xhtml pages. + +This problem is especially serious when you change extension from .html to +.xhtml in ikiwiki.setup and use Firefox. Since Firefox will display a error +message only for not well-formed application/xhtml+xml pages. + +It seems that HTML::Template also support `` syntax instead +of ``. Chaning to this syntax will solve this problem, I guess. + + +Even if changed to `` style, the problem may still exist if the template contains if else block. + +Maybe just encode all < and > when compling pages within the templates folder will solve this problem. + +> I never noticed this bug, since it only happens if the htmlscrubber is +> disabled. --[[Joey]] + +>> My `templatebody` branch on [[template creation error]] fixes this. +>> --[[smcv]] + +>>> [[Merged|done]] --[[smcv]] diff --git a/doc/bugs/pagespec:_tagged__40____41____44___globbing.mdwn b/doc/bugs/pagespec:_tagged__40____41____44___globbing.mdwn new file mode 100644 index 000000000..f9cb37487 --- /dev/null +++ b/doc/bugs/pagespec:_tagged__40____41____44___globbing.mdwn @@ -0,0 +1,36 @@ +With the current HEAD (b10d353490197b576ef7bf2e8bf8016039efbd2d), +globbing in `tagged()` pagespecs doesn't work for me. For example, +`tagged(*)` doesn't match any pages. (It does in this wiki installation +here, though.) + +I did not yet do any testing to figure out when this broke. + +--[[tschwinge]] + +[[!map pages="*/a* and tagged(*ose)"]] + +> Are you sure that `tagged()` ever matches pages there? Take globbing +> out of the equasion. +> +> This could be as simple as you having not rebuilt the wiki +> on upgrade to the version that tracks tagged links. --[[Joey]] + +>> Yes, it is a globbing issue: + +>> \[[!map pages="tagged(open_i*ue_gdb)" show=title]] + +>> ... doesn't show anything. + +>> \[[!map pages="tagged(open_issue_gdb)" show=title]] + +>> ... does show a map of eight pages. Also, it's working fine on the +>> autotags pages. + +>> --[[tschwinge]] + +>>> Only way I can reproduce something like this is if tagbase is not set. +>>> I have fixed a bug there, see if it works for you? +>>> --[[Joey]] + +>>>> This is now indeed [[fixed|done]] (thanks!) -- even though I already +>>>> did have tagbase set. diff --git a/doc/bugs/pagespec_can__39__t_match___123__curly__125___braces.mdwn b/doc/bugs/pagespec_can__39__t_match___123__curly__125___braces.mdwn new file mode 100644 index 000000000..dee1e9891 --- /dev/null +++ b/doc/bugs/pagespec_can__39__t_match___123__curly__125___braces.mdwn @@ -0,0 +1,44 @@ +I want match pages which have actually curly braces in the names (like this one), but this matches a lot of pages without the braces in their names :( : + +[[!inline show="3" feeds="no" archive="yes" pages="*_{*}_*"]] + +(note: the inline above has been restricted to 3 matches to keep this page +concise. Hopefully it is still clear that this page is not in the output set, +and the 3 pages in the output set do not contain curly braces in their +titles). + +When escaped, it doesn't work at all: + +[[!inline show="3" feeds="no" archive="yes" pages="*_\{*}_*"]] + +[[!inline show="3" feeds="no" archive="yes" pages="*_{*\}_*"]] + +More tests: + +"\*{\*": + +[[!inline show="3" feeds="no" archive="yes" pages="*{*"]] + +"\*\\{\*": + +[[!inline show="3" feeds="no" archive="yes" pages="*\{*"]] + +> This is due to the current handling of quoting and escaping issues +> when converting a pagespec to perl code. `safequote` is used to +> safely quote an input string as a `q{}` quote, and it strips +> curlies when doing so to avoid one being used to break out of the `q{}`. +> +> Alternative ways to handle it would be: +> +> * Escape curlies. But then you have to deal with backslashes +> in the user's input as they could try to defeat your escaping. +> Gets tricky. +> +> * Avoid exposing user input to interpolation as a string. One +> way that comes to mind is to have a local string lookup hash, +> and insert each user specified string into it, then use the hash +> to lookup the specified strings at runtime. [[done]] +> +> --[[Joey]] + +Thank you! I'll try it. --Ivan Z. diff --git a/doc/bugs/pagespec_error_on_refresh_but_not_rebuild.mdwn b/doc/bugs/pagespec_error_on_refresh_but_not_rebuild.mdwn new file mode 100644 index 000000000..df941af37 --- /dev/null +++ b/doc/bugs/pagespec_error_on_refresh_but_not_rebuild.mdwn @@ -0,0 +1,32 @@ +I'm getting this error message when I refresh my wiki: + + $ hg commit -u me -m "Minor corrections" + refreshing wiki.. + scanning htmletc/moco-conf-rooms.mdwn + building htmletc/moco-conf-rooms.mdwn + Use of uninitialized value in concatenation (.) or string at /usr/local/lib/perl5/site_perl/5.8.9/Text/Typography.pm line 542. + building sidebar.mdwn, which depends on htmletc/moco-conf-rooms + building contact.mdwn, which depends on sidebar + building 500.mdwn, which depends on sidebar + Use of uninitialized value in concatenation (.) or string at /usr/local/lib/perl5/site_perl/5.8.9/Text/Typography.pm line 542. + building ceramics.mdwn, which depends on sidebar + building glossary.mdwn, which depends on sidebar + syntax error in pagespec "internal(glossary/comment_*)" + warning: post-commit hook exited with status 2 + +But there is no error if I use `ikiwiki --rebuild` to regenerate the whole thing. + +> You neglect to say what version of ikiwiki this is, +> or give any information to reproduce the bug. +> +> My guess: A version older than 3.20100403, which included +> 799b93d258bad917262ac160df74136f05d4a451, +> which could lead to incorrect "syntax error in pagespec" +> that only happened some of the time. +> +> (The Text::Typography warning seems probably unrelated.) +> --[[Joey]] + +>> I'm sorry, I don't know what I was thinking there. It's ikiwiki 3.20100212, and manually applying the patch you linked to made the bug go away. (Upgrading ikiwiki is a pain on nearlyfreespeech, especially if you don't want to keep the build directory around -- please consider making ikiwiki runnable directly from a git clone.) + +[[!meta link="done"]] diff --git a/doc/bugs/pagespec_parsing_chokes_on_function__40____41__.mdwn b/doc/bugs/pagespec_parsing_chokes_on_function__40____41__.mdwn new file mode 100644 index 000000000..78fed0e5d --- /dev/null +++ b/doc/bugs/pagespec_parsing_chokes_on_function__40____41__.mdwn @@ -0,0 +1,64 @@ +The pagespec regexes don't allow functions with no arguments. + +IkiWiki.pm, around line 1035: + +
+$spec=~m{
+                \s*             # ignore whitespace
+                (               # 1: match a single word
+                        \!              # !
+                |
+                        \(              # (
+                |
+                        \)              # )
+                |
+                        \w+\([^\)]+\)   # command(params)
+                |
+                        [^\s()]+        # any other text
+                )
+                \s*             # ignore whitespace
+        }igx
+
+ +command(params) of course might be just command(). (See +conditional.pm: match_included.) Trying to feed +ikiwiki a pagespec without params will get you instead: + +IkiWiki::PageSpec::match_glob($page, q{function}, @params) ( ) + +Which is completely not desired. The second + on that line should be a *. + +None of the builtin pagespecs "work" with no parameters, so it's hard to +write a unit test for this. But can we at least write a helpful note in +case the user is given to rebuilding the wiki by hand. --Ethan + +
+--- ikiwiki/IkiWiki.pm	2007-07-26 15:15:22.716860000 -0700
++++ ikidev/IkiWiki.pm	2007-07-26 21:34:45.542248000 -0700
+@@ -1032,7 +1032,7 @@
+ 		|
+ 			\)		# )
+ 		|
+-			\w+\([^\)]+\)	# command(params)
++			\w+\([^\)]*\)	# command(params)
+ 		|
+ 			[^\s()]+	# any other text
+ 		)
+@@ -1075,6 +1075,10 @@
+ 	}
+ 
+ 	my $ret=eval pagespec_translate($spec);
++	if ($@){
++		my $t = pagespec_translate($spec);
++		print "evaluating pagespec failed: $t $@\n";
++	}
+ 	return IkiWiki::FailReason->new("syntax error") if $@;
+ 	return $ret;
+ }
+
+ +> Thanks, [[done]] --[[Joey]] +> +> Note that the printing of the error isn't needed though. pagespec_match() +> returns an IkiWiki::FailReason object if parsing fails, and its caller +> can use that as desired to print the error. diff --git a/doc/bugs/pagestats_plugin_broken.mdwn b/doc/bugs/pagestats_plugin_broken.mdwn new file mode 100644 index 000000000..0ae74b4ee --- /dev/null +++ b/doc/bugs/pagestats_plugin_broken.mdwn @@ -0,0 +1,29 @@ +Since at least version 2.0 (and certainly a few version before), it seems that the pagestats plugin is broken : each matched page has a count of 2. +This is also (of course) producing flat tag cloud. + +My perl knowledge is very limited, but the call : + + my @bl = IkiWiki::backlinks($page); + $counts{$page} = scalar(@bl); + +return allways 2, which seems to me "obvious", because the backlinks() function is returning two array of links... + +Patch is : + + --- /usr/share/perl5/IkiWiki/Plugin/pagestats.pm 2007-04-27 04:33:43.000000000 +0200 + +++ ./pagestats.pm 2007-05-12 16:47:14.000000000 +0200 + @@ -36,7 +36,7 @@ + if (pagespec_match($page, $params{pages}, location => $params{page})) { + use IkiWiki::Render; + my @bl = IkiWiki::backlinks($page); + - $counts{$page} = scalar(@bl); + + $counts{$page} = scalar(@{$bl[0]})+scalar(@{$bl[1]}); + $max = $counts{$page} if $counts{$page} > $max; + } + } + + + +--[[users/hb]] + +thanks, [[done]] --[[Joey]] diff --git a/doc/bugs/pagetitle_function_does_not_respect_meta_titles.mdwn b/doc/bugs/pagetitle_function_does_not_respect_meta_titles.mdwn new file mode 100644 index 000000000..15d28f989 --- /dev/null +++ b/doc/bugs/pagetitle_function_does_not_respect_meta_titles.mdwn @@ -0,0 +1,289 @@ +[[!tag patch plugins/inline patch/core]] + +The `IkiWiki::pagetitle` function does not respect title changes via `meta.title`. It really should, so that links rendered with `htmllink` get the proper title in the link text. + +--[[madduck]] + +---- + +It is possible to set a Page-Title in the meta-plugin, but that one isn't +reused in parentlinks. This patch may fix it. + +
    +
  • I give pagetitle the full path to a page. +
  • I redefine the 'pagetitle'-sub to deal with it. +
  • to maintain compatibility for IkiWikis without the meta-plugin, i added a 'basename' to the Original-pagetitle. +
+ +
+diff -c /usr/share/perl5/IkiWiki/Render.pm.distrib /usr/share/perl5/IkiWiki/Render.pm
+*** /usr/share/perl5/IkiWiki/Render.pm.distrib  Wed Aug  6 07:34:55 2008
+--- /usr/share/perl5/IkiWiki/Render.pm  Tue Aug 26 23:29:32 2008
+***************
+*** 102,108 ****
+        $template->param(
+                title => $page eq 'index' 
+                        ? $config{wikiname} 
+!                       : pagetitle(basename($page)),
+                wikiname => $config{wikiname},
+                content => $content,
+                backlinks => $backlinks,
+--- 102,108 ----
+        $template->param(
+                title => $page eq 'index' 
+                        ? $config{wikiname} 
+!                       : pagetitle($page),
+                wikiname => $config{wikiname},
+                content => $content,
+                backlinks => $backlinks,
+
+diff -c /usr/share/perl5/IkiWiki/Plugin/parentlinks.pm.distrib /usr/share/perl5/IkiWiki/Plugin/parentlinks.pm
+*** /usr/share/perl5/IkiWiki/Plugin/parentlinks.pm.distrib      Wed Aug  6 07:34:55 2008
+--- /usr/share/perl5/IkiWiki/Plugin/parentlinks.pm      Tue Aug 26 23:19:43 2008
+***************
+*** 44,50 ****
+                        "height_$height" => 1,
+                };
+                $path.="/".$dir;
+!               $title=IkiWiki::pagetitle($dir);
+                $i++;
+        }
+        return @ret;
+--- 44,50 ----
+                        "height_$height" => 1,
+                };
+                $path.="/".$dir;
+!               $title=IkiWiki::pagetitle($path);
+                $i++;
+        }
+        return @ret;
+
+diff -c /usr/share/perl5/IkiWiki.pm.distrib /usr/share/perl5/IkiWiki.pm
+*** /usr/share/perl5/IkiWiki.pm.distrib Wed Aug  6 07:48:34 2008
+--- /usr/share/perl5/IkiWiki.pm Tue Aug 26 23:47:30 2008
+***************
+*** 792,797 ****
+--- 792,799 ----
+        my $page=shift;
+        my $unescaped=shift;
+  
++       $page=basename($page);
++ 
+        if ($unescaped) {
+                $page=~s/(__(\d+)__|_)/$1 eq '_' ? ' ' : chr($2)/eg;
+    	}
+
+diff -c /usr/share/perl5/IkiWiki/Plugin/meta.pm.distrib /usr/share/perl5/IkiWiki/Plugin/meta.pm
+*** /usr/share/perl5/IkiWiki/Plugin/meta.pm.distrib     Wed Aug  6 07:34:55 2008
+--- /usr/share/perl5/IkiWiki/Plugin/meta.pm     Tue Aug 26 23:30:58 2008
+***************
+*** 3,8 ****
+--- 3,9 ----
+  package IkiWiki::Plugin::meta;
+  
+  use warnings;
++ no warnings 'redefine';
+  use strict;
+  use IkiWiki 2.00;
+  
+***************
+*** 289,294 ****
+--- 290,319 ----
+        }
+  }
+  
++ sub IkiWiki::pagetitle ($;$) {
++       my $page=shift;
++       my $unescaped=shift;
++ 
++       if ($page =~ m#/#) {
++               $page =~ s#^/##;
++               $page =~ s#/index$##;
++               if ($pagestate{"$page/index"}{meta}{title}) {
++                       $page = $pagestate{"$page/index"}{meta}{title};
++               } else {
++                       $page = IkiWiki::basename($page);
++               }
++       }
++ 
++       if ($unescaped) {
++               $page=~s/(__(\d+)__|_)/$1 eq '_' ? ' ' : chr($2)/eg;
++       }
++       else {
++               $page=~s/(__(\d+)__|_)/$1 eq '_' ? ' ' : "&#$2;"/eg;
++       }
++ 
++       return $page;
++ }
++ 
+  package IkiWiki::PageSpec;
+  
+  sub match_title ($$;@) {
+
+
+ +---- + +> A few quick notes about it: + +> - Using inline would avoid the redefinition + code duplication. +> - A few plugins would need to be upgraded. +> - It may be necessary to adapt the testsuite in `t/pagetitle.t`, as well. +> +> --[[intrigeri]] +> +>> It was actually more complicated than expected. A working prototype is +>> now in my `meta` branch, see my userpage for the up-to-date url. +>> Thus tagging patch. --[[intrigeri]] +>> +>>> Joey, please consider merging my `meta` branch. --[[intrigeri]] + +So, looking at your meta branch: --[[Joey]] + +* Inter-page dependencies. If page A links to page B, and page B currently + has no title, then A will display the link as "B". Now page B is modified + and a title is added. Nothing updates "A". + The added overhead of rebuilding every page that links to B when B is + changed (as the `indexhtml` hook of the po plugin does) is IMHO a killer. + That could be hundreds or thousands of pages, making interactive editing + way slow. This is probably the main reason I had not attempted this whole + thing myself. IMHO this calls for some kind of intellegent dependency + handler that can detect when B's title has changed and only rebuild pages + that link to B in that case. +* Looks like some plugins that use `pagetitle` to format it for display + were not changed to use `nicepagetitle` (for example, rename). + But most of those callers intend to display the page name + as a title, but including the parent directories in the path. (Ie, + "renaming foo/page title to bar/page title" -- + you want to know it's moved from foo to bar.) `nicepagetitle` does not + allow doing that since it always takes the `basename`. +* I don't like the name `nicepagetitle`. It's not very descriptive, is it? + And it seems very confusing to choose whether to use the "nice" or original + version. My hope is that adding a second function is unnecessary. + As I understand it, you added a new function for two reasons: + 1) It needs the full page name, not basename. + 2) `titlepage(pagetitle($page))` reversability. + + 1) If you look at all the callers + Of `pagetitle` most of them pass a complete page name, not just the + basename. In most cases `pagetitle` is used to display the full name + of the page, including any subdirectory it's in. So why not just make + it consitently be given the full name of the page, with another argument + specifying if we want to get back just the base name. + + 2) I can't find any code that actually uses the reversability like that. + The value passed to `titlepage` always comes from some external + source. Unless I missed one. +* The use of `File::Spec->rel2abs` is a bit scary. +* Does it really make sense to call `pagetitle` on the meta title + in meta's `nicepagetitle`? What if the meta title is something like + "foo_bar" -- that would be changed to "foo bar". +* parentlinks is changed to use `nicepagetitle(bestlink($page, $path))`. + Won't `bestlink` return "" if the parent page in question does not exist? +* `backlinks()` is changed to add an additional `title` field + to the hash returned, but AFAICS this is not used in the template. +* Shouldn't `Render.pm` use nicepagetitle when getting the title for the + page template? Then meta would not need to override the title in the + `pagetemplate` hook. (Although this would eliminate handling of + `title_overridden` -- but that is little used and would not catch + all the other ways titles can be overridden with this patch anyway.) + +> I'm not a reviewer or anything, but can I chime in on changes to pagetitle? +> I don't think having meta-titles in wikilinks and the parentlinks path by +> default is necessarily a good thing. I don't consider the meta-title of a page +> as used in `` to be the same thing as the short title you +> want in those contexts - IMO, the meta-title is the "formal" title of the page, +> enough to identify it with no other context, and frequently too long to be used +> as a link title or a parentlink, whereas the parentlinks title in particular +> should be some abbreviated form that's enough to identify it in context. +> [tbm](http://www.cyrius.com/) expressed a similar opinion when I was discussing +> ikiwiki with him at the weekend. +> +> It's a matter of taste whether wikilinks are "like a parentlink" or "like a +> `<title>`"; I could be persuaded either way on that one. +> +> An example from my site: [this page](http://www.pseudorandom.co.uk/2004/debian/ipsec/) +> is the parent of [this page](http://www.pseudorandom.co.uk/2004/debian/ipsec/wifi/) +> with a title too long to use in the latter's parentlinks; I think the titles of +> both those pages are too long to use as wikilink text too. Similarly, tbm's page +> about [Debian on Orion devices from Buffalo](http://www.cyrius.com/debian/orion/buffalo/) +> can simply be called "Buffalo" in context. +> +> Having a `\[[!meta abbrev="..."]]` that took precedence over title +> in parentlinks and possibly wikilinks might be a good way to fix this? Or if your +> preference goes the other way, perhaps a `\[[!meta longtitle=""]]` could take +> precedence when generating the `<title>` and the title that comes after the +> parentlinks. --[[smcv]] + +>> I think you've convinced me. (I had always had some doubt in my mind as +>> to whether using titles in all these other places would make sense.) +>> +>> Instead of meta abbrev, you could have a meta pagename that +>> overrides the page name displayed everywhere (in turn overridden by +>> meta title iff the page's title is being displayed). But is this complexity +>> needed? We have meta redir, so if you want to change the name of a page, +>> you can just rename it, and put in a stub redirection page so links +>> still work. +>> +>> This leaves the [[plugins/contrib/po]] plugin, which really does need +>> a way to change the displayed page name everywhere, and at least a +>> subset of the changes in the meta branch are needed to support that. +>> +>> (This would also get around my concern about inter-page dependency +>> handling, since po contains a workaround for that, and it's probably +>> acceptable to use potentially slow methods to handle this case.) +>> --[[Joey]] + +>>> I'm glad to implement whatever decision we'll make, but I don't +>>> clearly understand what this discussion's conclusion is. It seems +>>> like we agree at least on one point: meta page titles shall not be +>>> displayed all over the place by default; I have therefore disabled +>>> `meta_overrides_page_title` by default in my `meta` branch. +>>> +>>> My next question is then: do we only want to satisfy the `po` +>>> plugin needs? Or do we want to allow people who want this, such as +>>> [[madduck]], to turn on a config switch so that meta page titles +>>> are displayed as wikilinks titles? In the latter case, what level +>>> of configurability do we want? I can think of a quite inelegant +>>> way to implement full configurability, and provide a configuration +>>> switch for every place where links are displayed, such as +>>> wikilinks, parentlinks, etc., but I don't think the added bonus is +>>> worth the complexity of it. +>>> +>>> I think we can roughly split the needs into three categories: +>>> +>>> 1. never display any modified page title in links; this is the +>>> current behaviour, and we should keep it as the default one +>>> 2. display modified page titles only at well chosen places; that +>>> could be "manual" wikilinks, I mean those generated by the +>>> `link`, `camelcase` & al. plugins, the recentchanges page, and +>>> maybe a few other places; keep the usual pagename-based title +>>> for every other link, such as the parentlinks ones. +>>> The inter-page dependency problem remains, though. As a first +>>> step, I'm in favour of the "slow, but correct" implementation, +>>> with a big warning stating that enabling this option can make +>>> a wiki really sluggish; if someone really wants this to work +>>> fast, he/she'll implement a clever dependency handler :) +>>> 3. display modified page titles all over the place; IMHO, we +>>> should implement only the bits needed so that the `po` plugin +>>> can set this up, rather than provide this as +>>> a user-configurable option. +>>> +>>> So my question is: do we want to implement the #2 case, or not? +>>> I propose myself to only implement #1 and #3 to start with, but do +>>> it in a way that leaves room for #2. +>>> +>>> --[[intrigeri]] +>>> +>>>> I agree, we should concentrate on getting just enough functionality +>>>> for the po plugin, because I want to merge the po plugin soon. +>>>> If #2 gets tackled later, we will certianly have all kinds of fun. +>>>> no matter what is done for the po plugin. --[[Joey]] + +>>>>> For the record: I've gotten used to the lack of this feature, +>>>>> and it now seems much less important to me than it was when +>>>>> initially developing the po plugin. So, I'm hereby officially +>>>>> removing this from my plate. If anyone else wants to start from +>>>>> scratch, or from my initial work, I'm happy to review the +>>>>> po-related part of things -- just drop me an email in this +>>>>> case. --[[intrigeri]] diff --git a/doc/bugs/parsing_for_WikiWords_should_only_be_done_outside_html_tags.mdwn b/doc/bugs/parsing_for_WikiWords_should_only_be_done_outside_html_tags.mdwn new file mode 100644 index 000000000..44938c754 --- /dev/null +++ b/doc/bugs/parsing_for_WikiWords_should_only_be_done_outside_html_tags.mdwn @@ -0,0 +1,17 @@ +When having a link to e.g. http://www.chumba.com/media/Chumbawamba-EnoughIsEnough.mp3 inside an anquor tag ikiwiki seems to parse EnoughIsEnough as WikiWord and breaks the link with that. As a general rule I would suggest that inside tags there should never be any WikiWord parsing, this is just asking for problems. + +You can see an example of the breakage on <http://wiki.debian-community.org/planets/de/> - scroll down to the Chumbawamba entry. + +>> There's a great workaround for this bug: Disable the +>> [[plugins/camelcase]] plugin. :-) I really don't recommend using that +>> plugin. _Especially_ not when aggregating third-party content as you do +>> in the example. +>> +>> Fixing this at the html parsing level would involve making ikiwiki 2 +>> times slower, not even counting the html parsing overhead, since it +>> would have to fully render pages in the "scan" pass. +>> +>> All I can do is improve the regexp it uses to try to avoid false +>> positives. Which I've now [[done]]. +>> +>> --[[Joey]] diff --git a/doc/bugs/password_deletion.mdwn b/doc/bugs/password_deletion.mdwn new file mode 100644 index 000000000..ff2cd2c61 --- /dev/null +++ b/doc/bugs/password_deletion.mdwn @@ -0,0 +1,7 @@ +I have just deleted my password, accidentally (which is not a crisis, but it shouldn't really happen). + +I logged in to tweak my page subscriptions, did so, and clicked 'save preferences' - unfortunately, the password boxes are cleared when you arrive at the preferences page and if you don't fill them in again then the new password (which is blank) gets saved. I'm sure I'm not the first one to notice this - I'm just writing here because I've not yet found anywhere where this inconvenience is documented. + +-- [[KarlMW]] + +[[fixed|done]] --[[Joey]] diff --git a/doc/bugs/password_reset_fails_with___34__Wide_character_in_subroutine_entry__34__.mdwn b/doc/bugs/password_reset_fails_with___34__Wide_character_in_subroutine_entry__34__.mdwn new file mode 100644 index 000000000..b9452a5ef --- /dev/null +++ b/doc/bugs/password_reset_fails_with___34__Wide_character_in_subroutine_entry__34__.mdwn @@ -0,0 +1,29 @@ +Similar to [[bugs/syslog_fails_with_non-ASCII_wikinames]], this bug happens when the wiki name has non-ascii characters in the site name. In my case, it has the "CⒶTS" string. + +We get the following error in a password reset: + + Error: Wide character in subroutine entry at /usr/share/perl5/Mail/Sendmail.pm line 308. + +Help! :) --[[anarcat]] + +> I assume this means Mail::Sendmail doesn't know how to send Unicode +> strings, so any string passed to it (or any message body, or something?) +> will need to be passed through `encode_utf8()`. It looks as though +> Mail::Sendmail also defaults to +> +> Content-Type: 'text/plain; charset="iso-8859-1"' +> +> so it'll need a `'Content-Type' => 'text/plain; charset="utf-8"'` +> too. +> +> I'm disappointed to see how many of the library modules used by ikiwiki +> are not Unicode-clean... but then again, Mail::Sendmail was last released +> in 2003 so it's hardly surprising. I wonder whether [[!cpan Email::Sender]] +> is any better? +> +> (If you know Python 2, the analogous situation would be "doesn't +> know how to send unicode objects, so you have to get a str object +> with `a_unicode_object.encode('utf-8')`".) --[[smcv]] + +>> Shameless plug: [[todo/passwordauth:_sendmail_interface]]. Though, I have +>> no idea whether that is UTF-8-safe. --[[tschwinge]] diff --git a/doc/bugs/perl:_double_free_or_corruption.mdwn b/doc/bugs/perl:_double_free_or_corruption.mdwn new file mode 100644 index 000000000..8499b6388 --- /dev/null +++ b/doc/bugs/perl:_double_free_or_corruption.mdwn @@ -0,0 +1,14 @@ +If your perl is dumping core, that's a perl bug (or a libc bug or the like) by +definition, not an ikiwiki bug. Ikiwiki is pure perl code; pure perl code +can't cause perl to dump core unless it tickles a perl bug. + +Calling this [[done]] since this is not the right forum. You'll need to +figure out what's wrong with your perl, I'm afraid. --[[Joey]] + +<pre> +rendering todo/more_class__61____34____34___for_css.mdwn +rendering todo/Support_subdirectory_of_a_git_repo.mdwn +rendering todo/link_map.mdwn +rendering todo/calendar_--_archive_browsing_via_a_calendar_frontend.mdwn +*** glibc detected *** perl: double free or corruption (!prev): 0x00000000018a7bd0 *** +</pre> diff --git a/doc/bugs/pipe-symbol_in_taglink_target.mdwn b/doc/bugs/pipe-symbol_in_taglink_target.mdwn new file mode 100644 index 000000000..e467959be --- /dev/null +++ b/doc/bugs/pipe-symbol_in_taglink_target.mdwn @@ -0,0 +1,25 @@ +[[!tag bugs wishlist]] + +Escaping pipe-symbol in [[taglink|ikwiki/directive/taglink]] targets doesn't work as I wanted: + +[[!taglink smth_with_a_pipe|about_the_\|-symbol]] +[[!taglink smth_with_a_pipe|about_the_|-symbol]] + +as opposed to simple wikilinks: + +[[a link to smth with a pipe|about the \|-symbol]] +[[a link to smth with a pipe|about the |-symbol]] + +And it seems to work in pagespecs: + +tagged: + +[[!map pages="tagged(about the |-symbol)"]] + +[[!map pages="tagged(about the \|-symbol)"]] + +link: + +[[!map pages="link(about the |-symbol)"]] + +[[!map pages="link(about the \|-symbol)"]] diff --git a/doc/bugs/pipe_in_tables_as_characters.mdwn b/doc/bugs/pipe_in_tables_as_characters.mdwn new file mode 100644 index 000000000..12d5e1597 --- /dev/null +++ b/doc/bugs/pipe_in_tables_as_characters.mdwn @@ -0,0 +1,16 @@ +How to put '|' character in a field ? I tried escaping it but it does not work. +Seems tables are disabled here ? + +> Explicitly specify format=csv, then you can use pipes as values and even +> use quotes to unambiguously include commas in values. --[[Joey]] + +>> Great! thanks. + +>>> Guess I can mark this [[done]] --[[Joey]] + +See this example: + +[[!table class=table1 data=""" +aaaaaaaaaaaaaaa|b|c +--\|\|--|e|f +"""]] diff --git a/doc/bugs/plugin___96__rename__96___fails_if___96__attachment__96___is_not_enabled.mdwn b/doc/bugs/plugin___96__rename__96___fails_if___96__attachment__96___is_not_enabled.mdwn new file mode 100644 index 000000000..6bc8bb815 --- /dev/null +++ b/doc/bugs/plugin___96__rename__96___fails_if___96__attachment__96___is_not_enabled.mdwn @@ -0,0 +1,7 @@ +ikiwiki 3.20110712: A try to rename a page through the web interface without plugin `attachment` enabled renders: + + Error: Undefined subroutine &IkiWiki::Plugin::attachment::attachment_holding_location called at /usr/share/perl5/IkiWiki/Plugin/rename.pm line 326. + +Enabling `attachment` makes it work. Some check if `attachment` is enabled before running that code path would solve it. Not sure of the best way to check it. --[[Daniel Andersson]] + +> [[fixed|done]] --[[Joey]] diff --git a/doc/bugs/plugins__47__relativedate_depends_on_locale_at_setup_file.mdwn b/doc/bugs/plugins__47__relativedate_depends_on_locale_at_setup_file.mdwn new file mode 100644 index 000000000..a9a39ac47 --- /dev/null +++ b/doc/bugs/plugins__47__relativedate_depends_on_locale_at_setup_file.mdwn @@ -0,0 +1,16 @@ +[[plugins/relativedate]] does not works when russian locale defined at setup file (locale => 'ru_RU.UTF-8'). This is happen because javascript for this plugin takes either elements title or content itself. If russian locale is turned on then title generated on russian language and JS can't convert it into Date object. innerHTML is language independent (YYYY-MM-DD HH:mm) always. + +If I switch locale to en_US.UTF-8 then this plugin correctly parses text date and print relative date. But when I mouseover on date I see unusual formating of the date (it uses AM/PM format while russians use 24-h notation). + +P.S. All pages but RecentChanges show well-formated date. RecentChanges show date formated using locale. Anyway, plugin does not work without en_US locale. + +> [[Fixed|done]]. Now it uses C locale for the date put in the title, +> that is used by relativedate. The mouseover will display the date in your +> native locale. +> +> Only exception is that when javascript is disabled... then +> relativedate can't work, so instead you will see your localized date +> displayed; but on mouseover you will get shown the C locale date. +> --[[Joey]] + +>> Thanks. diff --git a/doc/bugs/po:__apache_config_serves_index_directory_for_index.mdwn b/doc/bugs/po:__apache_config_serves_index_directory_for_index.mdwn new file mode 100644 index 000000000..fd7cd518c --- /dev/null +++ b/doc/bugs/po:__apache_config_serves_index_directory_for_index.mdwn @@ -0,0 +1,85 @@ +Similarly to [[po:_apache_config_serves_index.rss_for_index]], +the [[plugins/po]] apache config has another bug. + +The use of "DirectoryIndex index", when combined with multiviews, is intended +to serve up a localized version of the index.??.html file. + +But, if the site's toplevel index page has a discussion page, that +is "/index/discussion/index.html". Or, if the img plugin is used to scale +an image on the index page, that will be "/index/foo.jpg". In either case, +the "index" directory exists, and so apache happily displays that +directory, rather than the site's index page! + +--[[Joey]] + +> Ack, we do have a problem. Seems like ikiwiki's use of `index/` as +> the directory for homepage's sub-pages and attachments makes it +> conflict deeply with Apache's `MultiViews`: as the [MultiViews +> documentation](http://httpd.apache.org/docs/2.2/mod/mod_negotiation.html#multiviews) +> says, `index.*` are considered as possible matches only if the +> `index/` directory *does not exist*. Neither type maps nor +> `mod_mime` config parameters seem to allow overriding this behavior. +> Worse even, I guess any page called `index` would have the same +> issues, not only the wiki homepage. + +> I can think of two workarounds, both kinda stink: +> +> 1. Have the homepage's `targetpage` be something else than +> `index.html`. +> 2. Have the directory for the homepage's sub-pages and attachments +> be something else than `index`. +> +> I doubt either of those can be implemented without ugly special +> casing. Any other idea? --[[intrigeri]] + +>> As I understand it, this is how you'd do it with type maps: +>> +>> * turn off MultiViews +>> * `AddHandler type-map .var` +>> * `DirectoryIndex index.var` +>> * make `index.var` a typemap (text file) pointing to `index.en.html`, +>> `index.fr.html`, etc. +>> +>> I'm not sure how well that fits into IkiWiki's structure, though; +>> perhaps the master language could be responsible for generating the +>> type-map on behalf of all slave languages, or something? +>> +>> Another possibility would be to use filenames like `index.html.en` +>> and `index.html.fr`, and set `DirectoryIndex index.html`? This could +>> get problematic for languages whose ISO codes conventionally mean +>> something else as extensions (Polish, `.pl`, is the usual example, +>> since many sites interpret `.pl` as "this is a (Perl) CGI"). +>> --[[smcv]] + +>>> There is something to be said about "index/foo" being really ugly +>>> and perhaps it would be nice to use something else. There does not +>>> appear to even be one function that could be changed; "$page/foo" is +>>> hardwired into ikiwiki in many places as a place to dump subsidiary +>>> content -- and it's not even consistent, since there is also eg, +>>> "$page.rss". I agree, approaching it from this direction would be a +>>> mess or a lot of work. +>>> +>>> Type maps seem like a valid option, but also a lot of clutter. +>>> +>>> `index.html.pl` does seem to be asking for trouble, even if apache +>>> can be configured to DTRT. It would make serving actual up perl scripts +>>> hard, at least. But that is some good out of the box thinking.. +>>> perhaps "index.foo.pl.html"? +>>> +>>> However, that would mean that +>>> web servers need to be configured differently to serve translated +>>> and non-translated sites. The current apache configuration for po +>>> can be used with non-po sites and they still work. --[[Joey]] + +>>>> I am vulnerable to the same problem because I use MultiViews, though I don't use the `po` module; +>>>> I have to serve both Australian English and American English for my company's website +>>>> (for SEO purposes; certain words that relate to our products are spelt differently in US and Australian English, and we need to be able to be googled with both spellings). +>>>> I'm just fortunate that nobody has thought to add attachments to the front page yet. +>>>> I raise this to point out that this is going to be a recurring problem that won't necessarily be fixed by changing the `po` module in isolation. +>>>> +>>>> One could argue that "index" is already a special case, since it is the top page of the site. +>>>> Things like parentlinks already use a special case for the top page (checking the variable HAS_PARENTLINKS). +>>>> Likewise, when --usedirs is true, index is treated as a special case, since it generates "index.html" and not "index/index.html". +>>>> +>>>> Unfortunately, I'm not sure what the best approach to solving this would be. +>>>> --[[KathrynAndersen]] diff --git a/doc/bugs/po:_apache_config_serves_index.rss_for_index.mdwn b/doc/bugs/po:_apache_config_serves_index.rss_for_index.mdwn new file mode 100644 index 000000000..a2b68c4b1 --- /dev/null +++ b/doc/bugs/po:_apache_config_serves_index.rss_for_index.mdwn @@ -0,0 +1,36 @@ +The apache config documented in [[plugins/po]] has a subtle bug. It works +until a site gets an index.atom or index.rss file. (Acutally, with po +enabled, they're called index.en.atom or index.en.rss etc, but the result +is the same). + +Then, when wget, curl, or w3m is pointed at http://site/, apache serves +up the rss/atom file rather than the index page. + +Analysis: + +* /etc/mime.types gives mime types to .rss and .atom files +* `mod_negotiation`'s MultiViews allows any file with a mime type to be + served up via content negotiation, if the client requests that type. +* wget etc send `Accept: */*` to accept all content types. Compare + with firefox, which sends `Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*` +* So apache has a tie between a html encoded Enlish file, and a rss encoded + English file and the client has no preference. In a tie, apache will serve up the + *smallest* file, which tends to be the rss file. (Apache's docs say it uses that + strange criteria to break ties; see <http://httpd.apache.org/docs/2.0/mod/mod_mime.html#multiviewsmatch>) + +The only way I have found to work around this problem is to remove +atom and rss from /etc/mime.types. Of course, that has other undesirable +results. + +I wonder if it would be worth making the po plugin generate apache +[type map files](http://httpd.apache.org/docs/2.0/mod/mod_negotiation.html#typemaps). +That should avoid this problem. +--[[Joey]] + +Update: A non-intrusive fix is to add this to apache configuration. +This tunes the "quality" of the rss and atom files, in an apparently currently +undocumented way (though someone on #httpd suggested it should get documented). +Result is that apache will prefer serving index.html. --[[Joey]] [[done]] + + AddType application/rss+xml;qs=0.8 .rss + AddType application/atom+xml;qs=0.8 .atom diff --git a/doc/bugs/po:_double_commits_of_po_files.mdwn b/doc/bugs/po:_double_commits_of_po_files.mdwn new file mode 100644 index 000000000..2f3015e2b --- /dev/null +++ b/doc/bugs/po:_double_commits_of_po_files.mdwn @@ -0,0 +1,22 @@ +When adding a new english page, the po files are created, committed, +and then committed again. The second commit makes this change: + + -"Content-Type: text/plain; charset=utf-8\n" + -"Content-Transfer-Encoding: ENCODING" + +"Content-Type: text/plain; charset=UTF-8\n" + +"Content-Transfer-Encoding: ENCODING\n" + +Same thing happens when a change to an existing page triggers a po file +update. --[[Joey]] + +> * The s/utf-8/UTF-8 part has been fixed. +> * The ENCODING\n part is due to an inconsistency in po4a, which +> I've just send a patch for. --[[intrigeri]] + +>> I resubmitted the patch to po4a upstream, sending it this time to +>> their mailing-list: +>> [post archive](http://lists.alioth.debian.org/pipermail/po4a-devel/2010-July/001897.html). +>> --[[intrigeri]] + +>>> Seems to me Debian Squeeze's po4a does not expose this bug anymore +>>> => [[done]]. --[[intrigeri]] diff --git a/doc/bugs/po:_markdown_link_parse_bug.mdwn b/doc/bugs/po:_markdown_link_parse_bug.mdwn new file mode 100644 index 000000000..1aa4eb803 --- /dev/null +++ b/doc/bugs/po:_markdown_link_parse_bug.mdwn @@ -0,0 +1,21 @@ +Apparently this is legal markdown, though unusual syntax for a link: + + [Branchable](http://www.branchable.com/ "Ikiwiki hosting") + +If that is put on a translatable page, the translations display it not as a +link, but as plain text. + +Probably a po4a bug, but I don't see the bug clearly in the gernerated po +file: + + "This was posted automatically by [Branchable](http://www.branchable.com/ " + "\"Ikiwiki hosting\") when I signed up." + +--[[Joey]] + +> I cannot reproduce this on my Squeeze system with ikiwiki Git code; +> both the page in the master language and translation pages perfectly +> display the link (and tooltip) in my testing environment. Were you +> using an oldest po4a, such as Lenny's one? --[[intrigeri]] + +>> Quite likely. Not seeing the problem now, [[done]] --[[Joey]] diff --git a/doc/bugs/po:_might_not_add_translated_versions_of_all_underlays.mdwn b/doc/bugs/po:_might_not_add_translated_versions_of_all_underlays.mdwn new file mode 100644 index 000000000..82aed400d --- /dev/null +++ b/doc/bugs/po:_might_not_add_translated_versions_of_all_underlays.mdwn @@ -0,0 +1,16 @@ +[[plugins/po]]'s `checkconfig` looks in the `underlaydirs`, but plugins that +add underlays typically do so in their own `checkconfig`. + +As far as I can see, this will result in it not adding translated versions +of underlays added by a plugin that comes after it in `$config{add_plugins}`; +for instance, if you have `add_plugins => qw(po smiley)`, you'll probably +not get the translated versions of `smileys.mdwn`. (I haven't tested this.) + +> It doesn't happen because smiley adds the underlay unconditionally on +> import. Which is really more usual. + +To see them all, `po` should use `last => 1` when registering the hook. +--[[smcv]] + +> At least all that don't last their hooks too! But, added, since +> it will make the problem much less likely to occur. --[[Joey]] [[done]] diff --git a/doc/bugs/po:_new_pages_not_translatable.mdwn b/doc/bugs/po:_new_pages_not_translatable.mdwn new file mode 100644 index 000000000..c19f66594 --- /dev/null +++ b/doc/bugs/po:_new_pages_not_translatable.mdwn @@ -0,0 +1,12 @@ +Today I added a new English page to l10n.ikiwiki.info. When I saved, +the page did not have the translation links at the top. I waited until +the po plugin had, in the background, created the po files, and refreshed; +still did not see the translation links. Only when I touched the page +source and refreshed did it finally add the translation links. +I can reproduce this bug in a test site. --[[Joey]] + +> I could reproduce this bug at some point during the merge of a buggy +> version of my ordered slave languages patch, but I cannot anymore. +> Could you please try again? --[[intrigeri]] + +>> Cannot reproduce with 3.20100722, [[done]] I guess. --[[Joey]] diff --git a/doc/bugs/po:_plugin_should_not_override_the_title_on_the_homepage.mdwn b/doc/bugs/po:_plugin_should_not_override_the_title_on_the_homepage.mdwn new file mode 100644 index 000000000..8f9374707 --- /dev/null +++ b/doc/bugs/po:_plugin_should_not_override_the_title_on_the_homepage.mdwn @@ -0,0 +1,58 @@ +The po plugin systematically overrides the title of the homepage with the wikiname. This prevents explicitly changing it with a meta directive. It should rather check whether it was overridden before setting it back. + +Here is a simple patch for that: + + diff --git a/Plugin/po.pm b/Plugin/po.pm + index 6395ebd..a048c6a 100644 + --- a/Plugin/po.pm + +++ b/Plugin/po.pm + @@ -333,7 +333,7 @@ sub pagetemplate (@) { + && $masterpage eq "index") { + $template->param('parentlinks' => []); + } + - if (ishomepage($page) && $template->query(name => "title")) { + + if (ishomepage($page) && $template->query(name => "title") && !$template->query(name => "title_overridden")) { + $template->param(title => $config{wikiname}); + } + } + +Thanks. + +> I fixed this patch a bit and applied it to my po branch, thanks +> (commit 406485917). +> +> But... a bug (probably in HTML::Template) prevents this +> theoretically correct solution to actually work. +> Setting a parameter that does not appear in the template, such as +> `title_overridden`, is not working on my install: the value does not +> seem to be stored anywhere, and when accessing it later using +> `$template->param('title_overridden')` it is always undef. +> Adding `<TMPL_IF TMPL_VAR TITLE_OVERRIDDEN></TMPL_IF>` in +> `page.tmpl` is a working, but ugly workaround. +> +> I am nevertheless in favour of merging the fix into ikiwiki. +> We'll then need to find how to find the remaining (smaller) bug so +> that this code can actually work. +> +> I'd like others to test my po branch and see if they can reproduce +> the bug I am talking of. +> +> --[[intrigeri]] + +>> Commit 406485917 looks fine to me, FWIW --[[smcv]] + +>>> I tracked the HTML::Template bug (or missing documentation?) a bit +>>> more. This lead to commit b2a2246ba in my po branch, that enables +>>> HTML::Template's parent_global_vars option which makes +>>> title_overridden work. +>>> +>>> OTOH I feel this workaround is a bit ugly as this option is not +>>> documented. IMHO being forced to use it reveals a bug in +>>> HTML::Template. I reported this: +>>> https://rt.cpan.org/Public/Bug/Display.html?id=64158. +>>> +>>> But still, I think we need to apply the workaround as +>>> HTML::Template's author has not updated any dist on CPAN for more +>>> than one year. --[[intrigeri]] + +>>>> All merged, [[done]]. --[[Joey]] diff --git a/doc/bugs/po:_po4a_too_strict_on_html_pages.mdwn b/doc/bugs/po:_po4a_too_strict_on_html_pages.mdwn new file mode 100644 index 000000000..d672d1c04 --- /dev/null +++ b/doc/bugs/po:_po4a_too_strict_on_html_pages.mdwn @@ -0,0 +1,24 @@ +On some source .html pages, po4a wrongly detects a malformed document, +which makes the po plugin error out and the wiki build is aborted. + +I've pushed a [[patch]] to my `po` branch to fix this: it makes po4a +warn, instead of error'ing out, when it detects a malformed input +document. + +This is really a po4a bug which I will report, but since most ikiwiki +users are gonna live with Squeeze's po4a for a while, I think we +should workaround it in ikiwiki. + +Also, the current state of things makes it a bit too easy to break a +given ikiwiki site build (DoS) when both the html and po plugins are +enabled: inserting a html tag without closing it is enough. + +--[[intrigeri]] + +> Hmm, so this happened while I was away at the beach and I have a big +> backlog of stuff, only saw it now. I've merged the match for master and +> will be releasing that soon. I will cherry-pick the fix into at least +> my debian-stable branch too. I don't know if this is worth doing a whole +> security advisory for. --[[Joey]] + +[[done]] diff --git a/doc/bugs/po:_po_files_instead_of_html_files.mdwn b/doc/bugs/po:_po_files_instead_of_html_files.mdwn new file mode 100644 index 000000000..f84dc8ff4 --- /dev/null +++ b/doc/bugs/po:_po_files_instead_of_html_files.mdwn @@ -0,0 +1,30 @@ +On the home page of my wiki, when i click on the link "ikiwiki", i get the english file instead of the french file. +At the bottom of this page, there is the "Links" line: +Links: index index.fr templates templates.fr +When i click on "templates.fr", i get the po.file instead of html. + + Sorry for the noise! I set "po_master_language" to fr and all was ok. + +> Any chance you could be a bit more verbose about what the +> misconfiguration was? I don't think the po plugin should behave like that +> in any configuration. Unless, perhaps, it was just not configured to +> support any languages at all, and so the po file was treated as a raw +> file. --[[Joey]] + +>> I can reproduce the bug with: + # po plugin + # master language (non-PO files) + po_master_language => { + code => 'en', + name => 'English' + }, + # slave languages (PO files) + po_slave_languages => [qw{fr|Français}], + +>>> I've never found any `.po` file in the destination directory on +>>> any of my PO-enabled ikiwiki instances. Without more information, +>>> there's nothing I can do: the config snippet pasted above is more +>>> or less the example one and does not allow me to reproduce the +>>> bug. --[[intrigeri]] + +>>>> I think it's best to close this as unreproducible. [[done]] --[[Joey]] diff --git a/doc/bugs/po:_ugly_messages_with_empty_files.mdwn b/doc/bugs/po:_ugly_messages_with_empty_files.mdwn new file mode 100644 index 000000000..d3992b6bc --- /dev/null +++ b/doc/bugs/po:_ugly_messages_with_empty_files.mdwn @@ -0,0 +1,6 @@ +If there are empty .mdwn files, the po plugin displays some ugly messages. + +> This is due to a bug in po4a (not checking definedness of a +> variable). One-liner patch sent. --[[intrigeri]] + +>> This seems to be fixed in po4a 0.40 => [[done]]. --[[intrigeri]] diff --git a/doc/bugs/po:broken_links_to_translatable_basewiki_pages_that_lack_po_fies.mdwn b/doc/bugs/po:broken_links_to_translatable_basewiki_pages_that_lack_po_fies.mdwn new file mode 100644 index 000000000..121d33807 --- /dev/null +++ b/doc/bugs/po:broken_links_to_translatable_basewiki_pages_that_lack_po_fies.mdwn @@ -0,0 +1,73 @@ +broken links to translatable basewiki pages that lack po files +-------------------------------------------------------------- + +If a page is not translated yet, the "translated" version of it +displays wikilinks to other, existing (but not yet translated?) +pages as edit links, as if those pages do not exist. + +That's really confusing, especially as clicking such a link +brings up an edit form to create a new, english page. + +This is with po_link_to=current or negotiated. With default, it doesn't +happen.. + +Also, this may only happen if the page being linked to is coming from an +underlay, and the underlays lack translation to a given language. +--[[Joey]] + +> Any simple testcase to reproduce it, please? I've never seen this +> happen yet. --[[intrigeri]] + +>> Sure, go here <http://l10n.ikiwiki.info/smiley/smileys/index.sv.html> +>> (Currently 0% translateed) and see the 'WikiLink' link at the bottom, +>> which goes to <http://l10n.ikiwiki.info/ikiwiki.cgi?page=ikiwiki/wikilink&from=smiley/smileys&do=create> +>> Compare with eg, the 100% translated Dansk version, where +>> the WikiLink link links to the English WikiLink page. --[[Joey]] + +>>> Seems not related to the page/string translation status: the 0% +>>> translated Spanish version has the correct link, just like the +>>> Dansk version => I'm changing the bug title accordingly. +>>> +>>> I tested forcing the sv html page to be rebuilt by translating a +>>> string in it, it did not fix the bug. I did the same for the +>>> Spanish page, it did not introduce the bug. So this is really +>>> weird. +>>> +>>> The smiley underlay seems to be the only place where the wrong +>>> thing happens: the basewiki underlay has similar examples +>>> that do not exhibit this bug. An underlay linking to another might +>>> be necessary to reproduce it. Going to dig deeper. --[[intrigeri]] + +>>>> After a few hours lost in the Perl debugger, I think I have found +>>>> the root cause of the problem: in l10n wiki's configured +>>>> `underlaydir`, the basewiki is present in every slave language +>>>> that is enabled for this wiki *but* Swedish. With such a +>>>> configuration, the `ikiwiki/wikilink` page indeed does not exist +>>>> in Swedish language: no `ikiwiki/wikilink.sv.po` can be found +>>>> where ikiwiki is looking. Have a look to +>>>> <http://l10n.ikiwiki.info/ikiwiki/>, the basewiki is not +>>>> available in Swedish language on this wiki. So this is not a po +>>>> bug, but a configuration or directories layout issue. This is +>>>> solved by adding the Swedish basewiki to the underlay dir, which +>>>> is I guess not a possibility in the l10n wiki context. I guess +>>>> this could be solved by adding `SRCDIR/basewiki` as an underlay +>>>> to your l10n wiki configuration, possibly using the +>>>> `add_underlays` configuration directive. --[[intrigeri]] + +>>>>> There is no complete Swedish underlay translation yet, so it is not +>>>>> shipped in ikiwiki. I don't think it's a misconfiguration to use +>>>>> a language that doesn't have translated underlays. --[[Joey]] + +>>>>>> Ok. The problem is triggered when using a language that doesn't +>>>>>> have translated underlays, *and* defining +>>>>>> `po_translatable_pages` in a way that renders the base wiki +>>>>>> pages translatable in po's view of things, which in turns makes +>>>>>> the po plugin act as if the translation pages did exist, +>>>>>> although they do not in this case. I still need to have a deep +>>>>>> look at the underlays-related code you added to `po.pm` a while +>>>>>> ago. Stay tuned. --[[intrigeri]] + +>>>>>>> Fixed in my po branch, along with other related small bugs that +>>>>>>> happen in the very same situation only. --[[intrigeri]] + +>>>>>>>> Merged. Not tested yet, but I trust you; [[done]] --[[Joey]] diff --git a/doc/bugs/po_plugin_adds_new_dependency.mdwn b/doc/bugs/po_plugin_adds_new_dependency.mdwn new file mode 100644 index 000000000..3ddcc30f2 --- /dev/null +++ b/doc/bugs/po_plugin_adds_new_dependency.mdwn @@ -0,0 +1,38 @@ +Was it intended that the po plugin add a new dependency? + +> Yes; see debian/control Build-Depends. However, I have made it disable +> building that is po4a is not available. [[done]] --[[Joey]] + + PERL5LIB=.. ./po2wiki underlay.setup + Failed to load plugin IkiWiki::Plugin::po: Can't locate Locale/Po4a/Common.pm in @INC (@INC contains: .. /Library/Perl/Updates/5.8.8 /System/Library/Perl/5.8.8/darwin-thread-multi-2level /System/Library/Perl/5.8.8 /Library/Perl/5.8.8/darwin-thread-multi-2level /Library/Perl/5.8.8 /Library/Perl /Network/Library/Perl/5.8.8/darwin-thread-multi-2level /Network/Library/Perl/5.8.8 /Network/Library/Perl /System/Library/Perl/Extras/5.8.8/darwin-thread-multi-2level /System/Library/Perl/Extras/5.8.8 /Library/Perl/5.8.6 /Library/Perl/5.8.1 /sw/lib/perl5/5.8.8/darwin-thread-multi-2level /sw/lib/perl5/5.8.8 /sw/lib/perl5/darwin-thread-multi-2level /sw/lib/perl5 /sw/lib/perl5/darwin /usr/local/lib/perl5/site_perl/5.8.8/darwin-thread-multi-2level /usr/local/lib/perl5/site_perl/5.8.8 /usr/local/lib/perl5/site_perl .) at ../IkiWiki/Plugin/po.pm line 13. + BEGIN failed--compilation aborted at ../IkiWiki/Plugin/po.pm line 13. + Compilation failed in require at (eval 27) line 2. + BEGIN failed--compilation aborted at (eval 27) line 2. + + make[1]: *** [po2wiki_stamp] Error 2 + make: *** [extra_build] Error 2 + +And it looks like this dependency is not easy to work around. The issue is that the newly translated base wiki means that the po plugin is being used by the build system. It is no longer optional. I've turned it off in my workspace like this: (heavy handed, but it lets me keep going until a proper fix is available) + + diff --git a/Makefile.PL b/Makefile.PL + index 602d8fb..68728b7 100755 + --- a/Makefile.PL + +++ b/Makefile.PL + @@ -42,7 +42,7 @@ extra_build: ikiwiki.out ikiwiki.setup docwiki + ./mdwn2man ikiwiki-makerepo 1 doc/ikiwiki-makerepo.mdwn > ikiwiki-makerepo.man + ./mdwn2man ikiwiki-transition 1 doc/ikiwiki-transition.mdwn > ikiwiki-transition.man + ./mdwn2man ikiwiki-update-wikilist 1 doc/ikiwiki-update-wikilist.mdwn > ikiwiki-update-wikilist.man + - $(MAKE) -C po + + # $(MAKE) -C po + + docwiki: ikiwiki.out + $(PERL) -Iblib/lib $(extramodules) $(tflag) ikiwiki.out -libdir . -setup docwiki.setup -refresh + @@ -114,7 +114,7 @@ extra_install: underlay_install + install ikiwiki.out $(DESTDIR)$(PREFIX)/bin/ikiwiki + install ikiwiki-makerepo ikiwiki-transition ikiwiki-update-wikilist $(DESTDIR)$(PREFIX)/bin/ + + - $(MAKE) -C po install DESTDIR=$(DESTDIR) PREFIX=$(PREFIX) + + # $(MAKE) -C po install DESTDIR=$(DESTDIR) PREFIX=$(PREFIX) + + # These might fail if a regular user is installing into a home + # directory. diff --git a/doc/bugs/po_plugin_cannot_add_po_files_into_git.mdwn b/doc/bugs/po_plugin_cannot_add_po_files_into_git.mdwn new file mode 100644 index 000000000..8e3399611 --- /dev/null +++ b/doc/bugs/po_plugin_cannot_add_po_files_into_git.mdwn @@ -0,0 +1,34 @@ +po files are not added to git (error: /path/to/po/file not in repository tree) in my setup. + +I have set absolute path for srcdir = '/path/to/repo/doc/'. The root of my git repository is '/path/to/repo/'. When I enable the po plugin, it creates all po files and produces an error when it try to add the file saying that the /path/to/repo/doc/index.fr.po is not in the repository tree. + +I have no problem when I use an relative path like srcdir = '.'. + +I have an other issue with the po plugin when I set the srcdir to './doc/' (provided that my config file is in /path/to/repo). In this case the po plugin try to add 'doc/doc/index.fr.po' which does not exists (seems like the srcdir path is prepended twice). + +> You should never use a relative srcdir path with ikiwiki. +> +> I wonder what version of git you have there, since it works ok with the +> version I have here. But, the po plugin is definitly doing the wrong +> thing; it's telling git to add the po file with the full scrdir path +> rather than relative to its root. Fixed that. [[done]] --[[Joey]] + +>> Yeah, I figured for the relative path +>> Git version 1.6.3.3 (on both my dev and server machines) +>> +>> Here is an example of what I get when I update the po file on my laptop and I push to the master repository: + + From /srv/git/sb + 5eb4619..ecac4d7 master -> origin/master + scanning doc.fr.po + building doc.fr.po + building doc.mdwn, which depends on doc.fr + building recentchanges.mdwn, which depends on recentchanges/change_ecac4d7311b15a3a3ed03102b9250487315740bc + fatal: '/srv/www/sb.l.n/new/doc/doc.fr.po' is outside repository + 'git add /srv/www/sb.l.n/new/doc/doc.fr.po' failed: at /usr/share/perl5/IkiWiki/Plugin/git.pm line 161. + done + To ssh://git.lohrun.net/var/cache/git/songbook.git + 5eb4619..ecac4d7 master -> master + +>> The root repository used to run ikiwiki is `/srv/www/sb.l.n/new/` +>> -- [[AlexandreDupas]] diff --git a/doc/bugs/po_vs_templates.mdwn b/doc/bugs/po_vs_templates.mdwn new file mode 100644 index 000000000..d826546e6 --- /dev/null +++ b/doc/bugs/po_vs_templates.mdwn @@ -0,0 +1,48 @@ +The po plugin's protection against processing loops (i.e. the +alreadyfiltered stuff) is playing against us: the template plugin +triggers a filter hooks run with the very same ($page, $destpage) +arguments pair that is used to identify an already filtered page. + +Processing an included template can then mark the whole translation +page as already filtered, which prevented `po_to_markup` to be called on +the PO content. + +Symptoms: the unprocessed gettext file goes unfiltered to the +generated HTML. + +This has been fixed in my po branch. + +> My commit dcd57dd5c9f3265bb7a78a5696b90976698c43aa updates the +> bugfix in a much more elegant manner. Its main disadvantage is to +> add an (optional) argument to IkiWiki::filter. Please review. + +-- [[intrigeri]] + +>> Hmm. Don't like adding a fourth positional parameter to that (or +>> any really) function. +>> +>> I think it's quite possible that some of the directives that are +>> calling filter do so unnecessarily. For example, conditional, +>> cutpaste, more, and toggle each re-filter text that comes from the +>> page and so has already been filtered. They could probably drop +>> the filtering. template likewise does not need to filter the +>> parameters passed into it. Does it need to filter the template output? +>> Well, it allows the (deprecated) embed plugin to work on template +>> content, but that's about it. +>> +>> Note also that the only other plugin to provide a filter, txt, +>> could also run into similar problems as po has, in theory (it looks at +>> the page parameter and assumes the content is for the whole page). +>> +>> [[!template id=gitbranch branch=origin/filter-full author="[[joey]]"]] +>> So, I've made a filter-full branch, where I attempt to fix this +>> by avoiding unnecessary filtering. Can you check it and merge it into +>> your po branch and remove your other workarounds so I can merge? +>> --[[Joey]] + +>>> I merged your filter-full branch into my po branch and reverted my +>>> other workarounds. According to my tests this works ok. I'm glad +>>> you found this solution, as I didn't like changing the filter +>>> prototype. I believe you can now merge this code. --[[intrigeri]] + +[[!tag patch done]] diff --git a/doc/bugs/poll_in_inline.mdwn b/doc/bugs/poll_in_inline.mdwn new file mode 100644 index 000000000..61c144915 --- /dev/null +++ b/doc/bugs/poll_in_inline.mdwn @@ -0,0 +1,6 @@ +When the poll directive appears in an inline, clicking on the button is +supposed to vote and go to the page for that poll. Instead, I see it always +apparantly skip counting my vote, and redirect to the page for that poll. +--[[Joey]] + +> [[fixed|done]] --[[Joey]] diff --git a/doc/bugs/poll_plugin:_can__39__t_vote_for_non-ascii_options.mdwn b/doc/bugs/poll_plugin:_can__39__t_vote_for_non-ascii_options.mdwn new file mode 100644 index 000000000..0f045c254 --- /dev/null +++ b/doc/bugs/poll_plugin:_can__39__t_vote_for_non-ascii_options.mdwn @@ -0,0 +1,7 @@ +I don't seem to be able to vote for options that have non-ascii names, using the poll plugin. + +As an example, see http://test.liw.fi/testpoll/index.html: the "red", "green", and "blue" options work fine, but the "ehkä" one does not. +--[liw](http://liw.fi/) + +> Ok, 4.5 hours of beating my head against a brick wall, and I've fixed this. +> [[done]] --[[Joey]] diff --git a/doc/bugs/poll_plugin_uses_GET.mdwn b/doc/bugs/poll_plugin_uses_GET.mdwn new file mode 100644 index 000000000..0538aaa93 --- /dev/null +++ b/doc/bugs/poll_plugin_uses_GET.mdwn @@ -0,0 +1,8 @@ +The [[plugins/poll]] plugin uses GET for the vote links. As a result, the +[[news/openid]] poll has a number of votes from Google. :) + +done -- [[Joey]] + +Not quite; [the `<form>` `method` attribute defaults to GET](http://www.w3.org/TR/html401/interact/forms.html#adef-method). The forms each need the attribute `method="POST"`. + +[[bugs/done]] -- [[Joey]] diff --git a/doc/bugs/possible_to_post_comments_that_will_not_be_displayed.mdwn b/doc/bugs/possible_to_post_comments_that_will_not_be_displayed.mdwn new file mode 100644 index 000000000..83d662cbf --- /dev/null +++ b/doc/bugs/possible_to_post_comments_that_will_not_be_displayed.mdwn @@ -0,0 +1,34 @@ +[[!template id=gitbranch branch=smcv/ready/comments author="[[smcv]]" +browse="http://git.pseudorandom.co.uk/smcv/ikiwiki.git/shortlog/refs/heads/ready/comments"]] +[[!tag patch users/smcv/ready]] + +The ability to post comments depends on several factors: + +* `comments_pagespec` controls whether comments on a particular + page will be displayed +* `comments_closed_pagespec` controls whether comments on + a particular page are allowed +* the `check_canedit` call controls whether comments are allowed + for a particular combination of page and user + +If `check_canedit` says that a user can post a comment +(in particular, if [[plugins/opendiscussion]] is enabled or +[[plugins/lockedit]] is disabled or permissive), +and `comments_closed_pagespec` does not contradict it, +then users who construct a `do=comment` CGI URL manually +can post comments that will not be displayed. I don't think +this is a security flaw as such, which is why I'm not +reporting it privately, but it violates least-astonishment. + +My `ready/comments` branch fixes this, by changing the test +at submission time from (pseudocode) + + !comments_closed_pagespec && check_canedit + +to + + comments_pagespec && !comments_closed_pagespec && check_canedit + +--[[smcv]] + +> [[merged|done]] --[[smcv]] diff --git a/doc/bugs/possibly_po_related_error.mdwn b/doc/bugs/possibly_po_related_error.mdwn new file mode 100644 index 000000000..2a65ae606 --- /dev/null +++ b/doc/bugs/possibly_po_related_error.mdwn @@ -0,0 +1,20 @@ +A site got stuck like this: + +<pre> +/home/b-fusioninventory/public_html/documentation/index.es.html independently created, not overwriting with version from documentation.es +</pre> + +I tried rebuilding it, and the rebuild failed like this: + +<pre> +building recentchanges/change_ef4b9f92821335d96732c4b2c93ed96bc84c2f0d._change, which depends on templates/page.tmpl +removing recentchanges/change_9ca1de878ea654566ce4a8a031d1ad8ed135ea1c/index.html, no longer built by recentchanges/change_9ca1de878ea654566ce4a8a031d1ad8ed135ea1c +internal error: recentchanges/change_9ca1de878ea654566ce4a8a031d1ad8ed135ea1c._change cannot be found in /home/b-fusioninventory/source or underlay +</pre> + +This internal error seems like the root cause of the original failure. +ikiwiki crashed and did not record that it wrote the index.es.html file. + +Deleting the indexdb and rebuilding cleaned up the problem. + +This needs more investigation. --[[Joey]] diff --git a/doc/bugs/post-commit_hangs.mdwn b/doc/bugs/post-commit_hangs.mdwn new file mode 100644 index 000000000..32820d886 --- /dev/null +++ b/doc/bugs/post-commit_hangs.mdwn @@ -0,0 +1,47 @@ +# post-commit hangs + +I installed ikiwiki v3.14159 in /usr/local from tarball (/usr contains an older version). Having done so, and used ikiwiki-transition to update setup file, the post commit hook is now blocking in flock (as seen by ps). I should also mention that I added the goodstuff, attachment and remove plugins (which was the purpose of upgrading to v3). Any clues as how to debug/fix gratefully received. The wiki is publically viewable at wiki.sgcm.org.uk if that helps. + +> It's blocking when you do what? Save a page from the web? Make a commit +> to the underlaying VCS? Which VCS? These are all different code paths.. +> --[[Joey]] + +>> It's blocking when I run "ikiwiki --setup ikiwiki.setup" (which calls hg update, which calls ikiwiki --post-commit). +>> Hmm, maybe it's the recursive call to ikiwiki which is the problem. +>> The underlying VCS is mercurial. --Ali + +>>> You're not supposed to run ikiwiki -setup manually in your post commit hook. +>>> Doing so will certianly lead to a locking problem; it also forces ikiwiki to rebuild +>>> the entire wiki anytime a single page changes, which is very inefficient! +>>> +>>> Instead, you should use the `mercurial_wrapper` setting +>>> in the setup file, which will make ikiwiki generate a small +>>> executable expressly designed to be run at post commit time. +>>> Or, you can use the `--post-commit` option, as documented +>>> in [[rcs/mecurial]] --[[Joey]] + +>>>> I don't run ikiwiki --setup in the commit hook; I run ikiwiki --post-commit (as mentioned above). +>>>> I'm trying to run ikiwiki --setup from the command line after modifying the setup file. +>>>> ikiwiki --setup is calling hg update, which is calling ikiwiki --post-commit. Am I not supposed to do that? --Ali + +>>>>> No, I don't think that hg update should call ikiwiki anything. The +>>>>> [[hgrc_example|rcs/mercurial]] doesn't seem to configure it to do that? --[[Joey]] + +>>>>>> Ok, I'm not sure I understand what's going on, but my problem is solved. +>>>>>> +>>>>>> My hgrc used to say: +>>>>>> +>>>>>> [hooks] +>>>>>> +>>>>>> incoming.update = hg up +>>>>>> +>>>>>> update.ikiwiki = ikiwiki --setup /home/ikiwiki/ikiwiki.setup --post-commit +>>>>>> +>>>>>> I've now changed it to match the example page and it works. Thanks --Ali. + +>>>>>>> [[done]] + +> Also, how have you arranged to keep it from seeing the installation in /usr? Perl could well be loading +> modules from the old installation, and if it's one with a different locking strategy that would explain your problem. --[[Joey]] + +>> Good point. Not knowing perl, I just assumed /usr/local would take precedence. I've now used "dpkg -r ikiwiki" to remove the problem. --Ali diff --git a/doc/bugs/post-update_hook_can__39__t_be_compiled_with_tcc.mdwn b/doc/bugs/post-update_hook_can__39__t_be_compiled_with_tcc.mdwn new file mode 100644 index 000000000..a8fb19888 --- /dev/null +++ b/doc/bugs/post-update_hook_can__39__t_be_compiled_with_tcc.mdwn @@ -0,0 +1,19 @@ +Thinking that any c compiler would do the job, I tried to use tcc with ikiwiki, as explicitely allowed by the Debian package dependencies. + +I installed `tcc` and `libc6-dev` (for `libcrt1`). The wrapper compilation was OK, but the wrapper fails to run correctly and dies with + + usage: ikiwiki [options] source dest + ikiwiki --setup configfile + +Everything works fine with gcc. + +versions: Debian lenny + backports + +> Seems that tcc does not respect changing where `environ` points as a way +> to change the environment seen after `exec` +> +> Given that the man page for `clearenv` suggests using `environ=NULL` +> if `clearenv` is not available, I would be lerry or using tcc to compile +> stuff, since that could easily lead to a security compromise of code that +> expects that to work. However, I have fixed ikiwiki to use `clearenv`. +> --[[Joey]] [[done]] diff --git a/doc/bugs/preprocessing_loop_control_too_tight.mdwn b/doc/bugs/preprocessing_loop_control_too_tight.mdwn new file mode 100644 index 000000000..7cf92af57 --- /dev/null +++ b/doc/bugs/preprocessing_loop_control_too_tight.mdwn @@ -0,0 +1,23 @@ +the preprocessing hook makes sure that no infinite loops occur by restricting the depth of nested directives to 3. + +this is insufficient in some situations in which sidebars are conditionally assembled from templates. + +given there are no limits on the number of directives per page and the number of edits a user can do in a particular time frame, i assume that raising that limit slightly won't make the DoS attacks that can be done against ikiwiki too much worse. + +i'd like to suggest 8 as a new value for recursion depth limit. most people can wrap their minds around a depth 3 nested directive setup, but when you reach a depth of 8, it's likely to be easier to write a dedicated plugin. + +<code><pre> +diff --git a/IkiWiki.pm b/IkiWiki.pm +index 75c9579..ad0f8b0 100644 +--- a/IkiWiki.pm ++++ b/IkiWiki.pm +@@ -1487 +1487 @@ sub preprocess ($$$;$$) { +- if ($preprocessing{$page}++ > 3) { ++ if ($preprocessing{$page}++ > 8) { +</pre></code> + +[[!tag patch]] + +> [[Seems reasonable|users/smcv/ready]] --smcv + +>> [[done]] --[[Joey]] diff --git a/doc/bugs/prettydate_with_weekday-date_inconsistency.mdwn b/doc/bugs/prettydate_with_weekday-date_inconsistency.mdwn new file mode 100644 index 000000000..430d65a3f --- /dev/null +++ b/doc/bugs/prettydate_with_weekday-date_inconsistency.mdwn @@ -0,0 +1,32 @@ +Prettydate creates strings like this: _Last edited in the wee hours of Tuesday night, July 1st, 2009_. However, July 1st is a Wednesday, so either date or Weekday should be modified. In the spirit is probably _Tuesday night, June 30th_. --ulrik + +> The default prettydate times are fairly idiosyncratic to +> how [[Joey]] thinks about time. Specifically, it's still +> Tuesday night until he wakes up Wednesday morning -- which +> could be in the afternoon. :-P But, Joey also realizes +> that dates change despite his weird time sense, and so +> July 1st starts at midnight on Tuesday and continues +> through Tuesday night and part of Wednesday. +> +> (This might not be as idiosyncratic as I make it out to be.. +> I think that many people would agree that in the wee hours +> of New Years Eve, when they're staggering home ahead of +> the burning daylight, the date is already January 1st.) +> +> I think the bug here is that prettydate can't represent +> all views of time. While the times +> of day can be configured, and it's possible to configure it +> to call times after midnight "Wednesday morning, July 1st", +> it is not possible to configure the date or weekday based +> on the time of day. +> +> In order to do so, prettydate's timetable would need to be +> extended to include the "%B %o, %Y" part, and that extended +> to include "%B-", "%o-", and "%Y-" to refer to the day +> before. +> +> --[[Joey]] + +>> fair enough, I think I can get converted to a warped time perspective. --ulrik + +>>> Perhaps we can consider this [[done]], then? --[[smcv]] diff --git a/doc/bugs/preview_base_url_should_be_absolute.mdwn b/doc/bugs/preview_base_url_should_be_absolute.mdwn new file mode 100644 index 000000000..f160a84c4 --- /dev/null +++ b/doc/bugs/preview_base_url_should_be_absolute.mdwn @@ -0,0 +1,53 @@ +The edit page CGI defines a `base` tag with an URL which is not +absolute, which can break the preview function in some circumstances +(with e.g. images not showing). The trivial [[patch]] that fixes +it can be found [[here|http://sprunge.us/EPHT]] as well as on [[my +git|http://git.oblomov.eu/ikiwiki]]. + +> That patch does mean that if you're accessing the CGI via HTTPS but your +> $config{url} and $config{cgiurl} are HTTP, you'll get preview images loaded +> via HTTP, causing the browser to complain. See +> [[todo/want_to_avoid_ikiwiki_using_http_or_https_in_urls_to_allow_serving_both]] +> for background. +> +> Perhaps the CGI could form its `<base>` URL by using +> `URI->new_abs(urlto(...), $cgi->url)` instead? +> +> You'd also need to change `IkiWiki/Wrapper.pm` to pass at least the +> SERVER_NAME and SERVER_PORT through the environment, probably. +> +> Joey's last comment on +> [[todo/want_to_avoid_ikiwiki_using_http_or_https_in_urls_to_allow_serving_both]] +> suggests that this might already work, but I'm not quite sure how - I'd +> expect it to need more environment variables? --[[smcv]] +> +>> `CGI::url` uses `REQUEST_URI`. So it could be used, but I don't see +>> how to get from the `CGI::url` to an url to the page that is being +>> edited. --[[Joey]] +>>> (The right rune seems to be: `URI->new_abs(urlto($params{page}), $cgi->url))` --[[Joey]] + +--- + +Update: This bug is worse than it first appeared, and does not only affect +previewing. The cgi always has a `<base>` url, and it's always relative, +and that can break various links etc. For example, when the 404 plugin +displays a missing page, it has a Recentchanges link, which would be broken +if the cgi was in an unusual place. + +`misctemplate` needs to *always* set an absolute baseurl. Which is a problem, +since `misctemplate` is not currently passed a cgi object from which to +construct one. --[[Joey]] + +Update: Worse and worse. `baseurl(undef)` can be a relative url, but +nearly every use of it I can find actually needs to be absolute. +the numerous `redirect($q, baseurl(undef))` all need to be absolute +according to `CGI` documentation. + +So, I'm seriously thinking about reverting the part of +[[todo/want_to_avoid_ikiwiki_using_http_or_https_in_urls_to_allow_serving_both]] +that made `baseurl(undef)` relative. +And I suppose, re-opening that todo. :( --[[Joey]] + +---- + +This was fixed in version 3.20110105 [[done]] --[[Joey]] diff --git a/doc/bugs/preview_pagestate.mdwn b/doc/bugs/preview_pagestate.mdwn new file mode 100644 index 000000000..7f7ec0976 --- /dev/null +++ b/doc/bugs/preview_pagestate.mdwn @@ -0,0 +1,13 @@ +If a change to a page is previewed, but not saved, `%pagestate` and +`%wikistate` can be changed, and saved. Actually, it's not limited to +those. Seems that spurious dependencies can be added, though existing +dependencies will at least not be removed. + +It calls saveindex to record state about files created on disk for the +preview. Those files will expire later. However, saveindex also +saves other state changes. + +Seems like it needs to isolate all state changes when previewing... ugh. +--[[Joey]] + +[[done]] diff --git a/doc/bugs/previewing_new_page_can_leave_files_dangling.mdwn b/doc/bugs/previewing_new_page_can_leave_files_dangling.mdwn new file mode 100644 index 000000000..22df485ad --- /dev/null +++ b/doc/bugs/previewing_new_page_can_leave_files_dangling.mdwn @@ -0,0 +1,53 @@ +Steps to reproduce: + +1. Make a new post via web interface. +2. Use a directive that generates extra files (say, teximg). +3. Click cancel. + +What I expect: + +The files that teximg created should (eventually) be removed, along with the whole directory of the non-existant new post. + +What I got: + +I refresh and rebuild a few times, and the files are still dangling there. If I then try to create a post with the same name and same content, I get a "file independently created, not overwriting" error. + +> This is specific to previewing when creating a new page. If the page +> previously existed, the next update to the page will remove the stale +> preview files. +> +> Problem is that ikiwiki doesn't store state about files rendered by a +> page if the page doesn't exist yet. +> +> However, just storing that state wouldn't entirely solve the problem, +> since it would still not delete the leftovers until the page is updated, +> which it never is if it's previewed and then canceled. And requiring the +> cancel button be hit doesn't solve this, because people won't. +> +> Also, it's not really ideal that an existing page has to be updated to +> remove stale files, because if the edit is aborted, the page might not be +> updated for a long time. +> +> One fix would be to stash a copy of `%renderedfiles` before generating +> the preview, then compare it afterwards to see how it changed and +> determine what files were added, and record those someplace, and delete +> them on a future refresh (after some reasonable time period). [[done]] +> +> Another approach would be to make previewing always render files with +> some well-known temporary name. Then all such temp files could be removed +> periodically. This would need changes to all plugins that write files +> during preview though. For example, `will_render` might be changed to +> return the actual filename to write to. --[[Joey]] + +For teximg, I think this can be fixed by using data url like graphviz, but +I think plugins in general should be allowed to create files during preview +and have them be cleaned up when the user presses cancel. This segues into +what my actual problem is: I wrote a htmlize plugin to format .tex files as +page images (following hnb and teximg, since I was completely unfamiliar +with perl until yesterday (and ikiwiki until a few days ago)), and there is +no way to tell if I'm in preview mode (so I can use data url and not leave +files dangling) or commit mode (so I can use real images and not have +bloated html). + +> It seems too ugly to thread an indicator to preview mode through to +> htmlize, so I'd prefer to not deal with the problem that way. diff --git a/doc/bugs/previewing_with_an_edittemplate_reverts_edit_box.mdwn b/doc/bugs/previewing_with_an_edittemplate_reverts_edit_box.mdwn new file mode 100644 index 000000000..4405a7ab8 --- /dev/null +++ b/doc/bugs/previewing_with_an_edittemplate_reverts_edit_box.mdwn @@ -0,0 +1,5 @@ +The 'editcontent' textarea that should be saved across previews is being overridden whenever an edittemplate is in use, 'losing' edits on preview unless the browser maintains them in history. + + --[[JoeRayhawk]] + +> ugly one... [[done]] --[[Joey]] diff --git a/doc/bugs/problem_adding_tag_from_template.mdwn b/doc/bugs/problem_adding_tag_from_template.mdwn new file mode 100644 index 000000000..0d1cf45a8 --- /dev/null +++ b/doc/bugs/problem_adding_tag_from_template.mdwn @@ -0,0 +1,10 @@ +I tried to make the [[plugin_template|templates/plugin]] automatically add the +`type/core` tag if passed the `core` parameter. However, this did not appear +to have the desired effect: if I removed `type/core` from the tags on a plugin +page that used `core=1` in the template (such as [[plugins/mdwn]]), the +`type/core` tag disappeared, and the template did not supply +it. --[[JoshTriplett]] + +Problem was that setting a tag cleared all earlier tags. [[bugs/done]], and +I like the idea of the autotagging.. +--[[Joey]] diff --git a/doc/bugs/proxy.py_utf8_troubles.mdwn b/doc/bugs/proxy.py_utf8_troubles.mdwn new file mode 100644 index 000000000..7e8f70e59 --- /dev/null +++ b/doc/bugs/proxy.py_utf8_troubles.mdwn @@ -0,0 +1,35 @@ +when writing an external plugin using `proxy.py`, the getstate and setstate +functions don't accept unicode data: + + uncaught exception: 'ascii' codec can't encode character u'\xe4' in position 25: ordinal not in range(128) + Traceback (most recent call last): + File "proxy.py", line 309, in run + self._in_fd, self._out_fd) + File "proxy.py", line 192, in handle_rpc + ret = self._dispatcher.dispatch(method, params) + File "proxy.py", line 84, in dispatch + return self._dispatch(method, params) + File "/usr/lib/python2.7/SimpleXMLRPCServer.py", line 420, in _dispatch + return func(*params) + File "proxy.py", line 251, in hook_proxy + ret = function(self, *args) + File "/home/chrysn/git/ikiwiki-plugins//plugins/my_plugin", line 49, in data2html + proxy.setstate(kwargs['page'], 'meta', 'title', unicode_containing_umlauts) + File "proxy.py", line 291, in setstate + return self.rpc('setstate', page, id, key, value) + File "proxy.py", line 233, in rpc + *args, **kwargs) + File "proxy.py", line 178, in send_rpc + cmd, data)) + UnicodeEncodeError: 'ascii' codec can't encode character u'\xe4' in position 25: ordinal not in range(128) + +the culprit is the last `_debug_fn` invocation in `send_rpc` (line 178), where +unicode data is format-fed into a string. while this could be circumvented by +making the formatting string a unicode string, that would cause trouble with +python3 and we'd just move the problem to the stderr writing later on; instead, +"`cmd, data))`" should become "`cmd, repr(data)))`" and everything is fine. +debug output doesn't look that pretty any more, but is safe. + +--[[chrysn]] + +> ok, [[done]] --[[Joey]] diff --git a/doc/bugs/prune_causing_taint_mode_failures.mdwn b/doc/bugs/prune_causing_taint_mode_failures.mdwn new file mode 100644 index 000000000..5fc1d8b75 --- /dev/null +++ b/doc/bugs/prune_causing_taint_mode_failures.mdwn @@ -0,0 +1,35 @@ +Using ikiwiki version 2.5gpa1 (the backport to Debian 3.1), I suddenly started getting the following error when rebuilding the wiki: + +<pre> +successfully generated /home/ikiwiki/cgi-bin/ikiwiki.cgi +Insecure dependency in rmdir while running with -T switch at /usr/share/perl5/IkiWiki/Render.pm line 242. +BEGIN failed--compilation aborted at (eval 5) line 130. +</pre> + +I've no idea what's happening (hey, I'm a C programmer), but I've hacked prune() to workaround this as follows: + +<pre> +use Scalar::Util qw(tainted); + +sub prune ($) { + my $file=shift; + + unlink($file); + my $dir=dirname($file); + if (!tainted($file) && $dir =~ /^(.*)$/) { + $dir = $1; + } + while (rmdir($dir)) { + $dir=dirname($dir); + if (!tainted($file) && $dir =~ /^(.*)$/) { + $dir = $1; + } + } +} +</pre> + +> Old versions of perl are known to have bugs with taint checking. +> I don't really support using ikiwiki with the perl 5.8.4 in debian +> oldstable, and would recommend upgrading. --[[Joey]] + +[[!tag patch done]] diff --git a/doc/bugs/pruning_is_too_strict.mdwn b/doc/bugs/pruning_is_too_strict.mdwn new file mode 100644 index 000000000..ee954e4bc --- /dev/null +++ b/doc/bugs/pruning_is_too_strict.mdwn @@ -0,0 +1,12 @@ +ikiwiki compiles my wiki successfully. But the svn post-commit hook it installs doesn't work at all. Instead of rendering the files, it deletes their rendered versions. The reason is that the src directory, /home/.kelli/glasserc/wikiwc, matches the prune regexp, so no files in the wiki get added to @files. + +I think the prune regexp would be more useful if it was only used to check the relative path from the src root to a file in the wiki. + +> I agree with this feature wish. Here is a _first cut_ +> implementation for this feature. +> +> --[[roktas]] + +[[bugs/Done]], and sorry it took so long to apply --[[Joey]] + +> Thank you! -- Ethan \ No newline at end of file diff --git a/doc/bugs/pythonproxy-utf8_again.mdwn b/doc/bugs/pythonproxy-utf8_again.mdwn new file mode 100644 index 000000000..f068782b4 --- /dev/null +++ b/doc/bugs/pythonproxy-utf8_again.mdwn @@ -0,0 +1,70 @@ +[[!template id=gitbranch branch=chrysn/more-proxy-utf8-fail author="[[chrysn]]"]] +[[!template id=gitbranch author="[[chrysn]], [[smcv]]" branch=smcv/ready/more-proxy-utf8-fail + browse=http://git.pseudorandom.co.uk/smcv/ikiwiki.git/shortlog/refs/heads/ready/more-proxy-utf8-fail]] + +the recently introduced fixes for [[crashes in the python proxy even if disabled]] +caused the typical python2 implicit conversion failures ("'ascii' codec +can't...") on my debian sid system -- to fix it, i had to revert commit 154c4ea9e. + +i did not dig down all the way to the xml / xmlrpc modules, but my impression +is that some module changed its behavior between stable and sid and now +generates `unicode` strings instead of `str`. + +a [[patch]] to allow both versions by inspecting the types and en-/decoding on +demand should work both for anarcat's and my case. i did not test the python3 +version, but i'm pretty sure it was already broken after the abovementioned +patch. + +-- [[chrysn]] + +> update 2014-06-29: the problem persists, but i found it is not trivial to +> reproduce. to demonstrate, use this test plugin: +> +> #!/usr/bin/env python +> # -*- coding: utf-8 -*- +> +> from proxy import IkiWikiProcedureProxy +> +> def preprocess(self, proxy, *args): +> return repr(self.rpc('pagetype', 'schön')) +> +> proxy = IkiWikiProcedureProxy(__name__) +> proxy.hook('preprocess', preprocess, id='testdirective') +> proxy.run() +> +> note that when the 'schön' is stored in a variable, the exception changes -- +> it seems to me that the issue is related to the way exceptions are encoded. +> +> the suggested patch still applies and solves the issue. --[[chrysn]] + +>> In this patch band: +>> +>> - xml = _IkiWikiExtPluginXMLRPCHandler._read(in_fd).decode('utf8') +>> + response = _IkiWikiExtPluginXMLRPCHandler._read(in_fd) +>> + if isinstance(response, unicode): +>> + xml = response.encode('utf8') +>> +>> I think you mean `response.decode`, not `response.encode`. +>> +>> Other than that it looks good to me. I like the use of `repr` in debug +>> messages. --[[smcv]] + +>>> afaict, encode is fine there -- the relevant methods in python2 are +>>> `unicode.encode` which gives a `str`, and `str.decode` which usually gives +>>> a `unicode`. (i'd happily ditch python2 and port all plugins to python3, +>>> where this is all easier, but my [[todo/vCard rendering]] still uses an +>>> ancient module.) --[[chrysn]] + +>>>> You were right about this, `encode` is appropriate to go from `unicode` +>>>> to `str` under Python 2. However, Python 3 is still broken. +>>>> +>>>> My `ready/more-proxy-utf8-fail` branch, based on yours, +>>>> [[fixes the `rst` test when run under Python 3|bugs/rst_plugin_hangs_when_used_with_Python_3]] +>>>> and hopefully also fixes this one. Please check that it still +>>>> fixes your test-case too. +>>>> +>>>> Joey, I think this is [[ready for merge|users/smcv/ready]] even if it +>>>> doesn't fix chrysn's bug - it does fix Python 3 support +>>>> in general. --[[smcv]] + +>>>>> [[merged|done]] --[[smcv]] diff --git a/doc/bugs/quieten_mercurial.mdwn b/doc/bugs/quieten_mercurial.mdwn new file mode 100644 index 000000000..3fd75ea1b --- /dev/null +++ b/doc/bugs/quieten_mercurial.mdwn @@ -0,0 +1,34 @@ +The mercurial backend does not pass the --quiet option to hg, and it sometimes prints +messages which are then taken for CGI output, causing errors and general trouble. --Michał + + --- iki/usr/share/perl5/IkiWiki/Rcs/mercurial.pm 2006-12-29 02:48:30.000000000 +0100 + +++ /usr/share/perl5/IkiWiki/Rcs/mercurial.pm 2007-03-18 22:45:24.000000000 +0100 + @@ -55,7 +55,7 @@ + } + + sub rcs_update () { + - my @cmdline = ("hg", "-R", "$config{srcdir}", "update"); + + my @cmdline = ("hg", "-q", "-R", "$config{srcdir}", "update"); + if (system(@cmdline) != 0) { + warn "'@cmdline' failed: $!"; + } + @@ -80,7 +80,7 @@ + + $message = possibly_foolish_untaint($message); + + - my @cmdline = ("hg", "-R", "$config{srcdir}", "commit", + + my @cmdline = ("hg", "-q", "-R", "$config{srcdir}", "commit", + "-m", "$message", "-u", "$user"); + if (system(@cmdline) != 0) { + warn "'@cmdline' failed: $!"; + @@ -92,7 +92,7 @@ + sub rcs_add ($) { + my ($file) = @_; + + - my @cmdline = ("hg", "-R", "$config{srcdir}", "add", "$file"); + + my @cmdline = ("hg", "-q", "-R", "$config{srcdir}", "add", "$file"); + if (system(@cmdline) != 0) { + warn "'@cmdline' failed: $!"; + } + +Thanks much for the patch. [[bugs/done]] --[[Joey]] diff --git a/doc/bugs/raw_html_in-page_and___91____91____33__included__93____93__.mdwn b/doc/bugs/raw_html_in-page_and___91____91____33__included__93____93__.mdwn new file mode 100644 index 000000000..5860d330a --- /dev/null +++ b/doc/bugs/raw_html_in-page_and___91____91____33__included__93____93__.mdwn @@ -0,0 +1,100 @@ +I'm trying to add a flickr stream thing to my (static) ikiwiki. I've disabled htmlscrubber and enabled rawhtml, and I get many strange errors. + +[[!toc ]] + +## putting the html right into the markdown index.mdwn + +This should work, but html code (listing 1) shows up with a hash replaced for the actual content (listing 2) + +I have to suspect that replacing html with some hash is a bug. + +> Congrats, you're another person to fall afoul of markdown [[!debbug 380212]]. +> The fix is to use Text::Markdown, or markdown 1.0.2 instead of buggy +> old markdown 1.0.1. --[[Joey]] [[!tag done]] + +## inlining raw html + +This would be my prefered solution. in index.mdwn: + + \[[!inline pages="flickr.html" rss="no"]] + +but this refuses to show any content. Trying to RTFM and adding raw="yes" results in this error: + + uppdaterar wiki.. + söker av index.mdwn + ritar upp index.mdwn + private//ikiwiki.setup: Can't call method "param" on an undefined value at /usr/share/perl5/IkiWiki/Plugin/inline.pm line 253. + BEGIN failed--compilation aborted at (eval 10) line 63. + + +## current workaround: iframe + +I'm no html guru so I put the stuff in an iframe, but that doesn't work, since the links are script-generated and need a target="" attribute in them to load in the right place (replacing ikiwiki page). + +Ikiwiki version: 2.44 + +plugin configuration: + + disable_plugins => [qw{htmlscrubber}], + add_plugins => [qw{img map rawhtml toggle template prettydate haiku meta}], + +best regards +ulrik + + +## listing 1 + <!-- Start of Flickr Badge --> + <style type="text/css"> + #flickr_badge_source_txt {padding:0; font: 11px Arial, Helvetica, Sans serif; color:#666666;} + #flickr_badge_icon {display:block !important; margin:0 !important; border: 1px solid rgb(0, 0, 0) !important;} + #flickr_icon_td {padding:0 5px 0 0 !important;} + .flickr_badge_image {text-align:center !important;} + .flickr_badge_image img {border: 1px solid black !important;} + #flickr_www {display:none; text-align:left; padding:0 10px 0 10px !important; font: 11px Arial, Helvetica, Sans serif !important; color:#3993ff !important;} + #flickr_badge_uber_wrapper a:hover, + #flickr_badge_uber_wrapper a:link, + #flickr_badge_uber_wrapper a:active, + #flickr_badge_uber_wrapper a:visited {text-decoration:none !important; background:inherit !important;color:#6600CC;} + #flickr_badge_wrapper {} + #flickr_badge_source {padding:0 !important; font: 11px Arial, Helvetica, Sans serif !important; color:#666666 !important;} + </style> + <table id="flickr_badge_uber_wrapper" cellpadding="0" cellspacing="10" border="0"> + <tr> + <td><a href="http://www.flickr.com" id="flickr_www">www.<strong style="color:#3993ff">flick<span style="color:#ff1c92">r</span></strong>.com</a><table cellpadding="0" cellspacing="2" border="0" id="flickr_badge_wrapper"> + <tr> + <script type="text/javascript" src="http://www.flickr.com/badge_code_v2.gne?show_name=1&count=5&display=latest&size=s&layout=h&source=user&user=23579158%40N05"></script> + <td id="flickr_badge_source" valign="center" align="center"> + <table cellpadding="0" cellspacing="0" border="0"><tr> + <td width="10" id="flickr_icon_td"><a href="http://www.flickr.com/photos/23579158@N05/"><img id="flickr_badge_icon" alt="englabenny's items" src="http://farm3.static.flickr.com/2338/buddyicons/23579158@N05.jpg?1211285412#23579158@N05" align="left" width="48" height="48"></a></td> + <td id="flickr_badge_source_txt"><nobr>Go to</nobr> <a href="http://www.flickr.com/photos/23579158@N05/">englabenny's photostream</a></td> + </tr></table> + </td> + </tr> + </table> + </td></tr></table> + <!-- End of Flickr Badge --> + + +## listing 2 + <!-- Start of Flickr Badge --> + <style type="text/css"> + #flickr_badge_source_txt {padding:0; font: 11px Arial, Helvetica, Sans serif; color:#666666;} + #flickr_badge_icon {display:block !important; margin:0 !important; border: 1px solid rgb(0, 0, 0) !important;} + #flickr_icon_td {padding:0 5px 0 0 !important;} + .flickr_badge_image {text-align:center !important;} + .flickr_badge_image img {border: 1px solid black !important;} + #flickr_www {display:none; text-align:left; padding:0 10px 0 10px !important; font: 11px Arial, Helvetica, Sans serif !important; color:#3993ff !important;} + #flickr_badge_uber_wrapper a:hover, + #flickr_badge_uber_wrapper a:link, + #flickr_badge_uber_wrapper a:active, + #flickr_badge_uber_wrapper a:visited {text-decoration:none !important; background:inherit !important;color:#6600CC;} + #flickr_badge_wrapper {} + #flickr_badge_source {padding:0 !important; font: 11px Arial, Helvetica, Sans serif !important; color:#666666 !important;} + </style> + + + 7383eb73071488c9ef46d617acf3e402 + + + </td></tr></table> + <!-- End of Flickr Badge --> diff --git a/doc/bugs/rebuild_after_changing_the_underlaydir_config_option.mdwn b/doc/bugs/rebuild_after_changing_the_underlaydir_config_option.mdwn new file mode 100644 index 000000000..8613ef03c --- /dev/null +++ b/doc/bugs/rebuild_after_changing_the_underlaydir_config_option.mdwn @@ -0,0 +1,12 @@ +It seems that rebuild a wiki (`ikiwiki --rebuild`) after changing the `underlaydir` config option doesn't remove the pages coming from the previous underlaydir. + +I've noticed this with the debian package version 3.20100102.3~bpo50+1. + +Perhaps it is possible to improve this or mention it in the manual page? + +--prosper + +> --rebuild causes ikiwiki to throw away all its info about what it built +> before, so it will never clean up pages that have been removed, by any +> means. Suggest you do a --refresh, possibly followed by a --rebuild +> if that is really necessary. --[[Joey]] diff --git a/doc/bugs/recentchanges_escaping.mdwn b/doc/bugs/recentchanges_escaping.mdwn new file mode 100644 index 000000000..1ad16d198 --- /dev/null +++ b/doc/bugs/recentchanges_escaping.mdwn @@ -0,0 +1,5 @@ +When committing a page like this one, with an escaped toc directive in it: + + \[[!toc ]] + +The recentchangesdiff comes back with it unescaped. Which can be confusing. diff --git a/doc/bugs/recentchanges_feed_links.mdwn b/doc/bugs/recentchanges_feed_links.mdwn new file mode 100644 index 000000000..ef0f9d1c4 --- /dev/null +++ b/doc/bugs/recentchanges_feed_links.mdwn @@ -0,0 +1,107 @@ +(Moved from [[plugins/recentchanges/discussion]]) + +I've just upgraded to ikiwiki 2.50 with the `recentchanges` plugin enabled, and +figured out that I have to turn on `rss` in `ikiwiki.setup` in order to get the +recentchanges feed. Now the feed shows up, but the links in the feed go to the +change pages, e.g. `recentchanges/change_1700.html`. I can see a `recentchanges` +directory created in the working copy, containing files like `change_1700._change` +but for some reason they are not getting htmlized and carried over. I can see +in `recentchanges.pm` that it explicitly registers an `htmlize` hook for the +`_change` type, but something isn't happening. I also see `return if $type=~/^_/;` in +`render()` in `Render.pm` so I guess the upshot is I'm not sure how this is +supposed to work; is there a bug here or just something I overlooked that I need +to turn on? --Chapman Flack + +> It's a (minor) bug that recentchanges optimises away generating the +> change pages, but that the rss/atom feed still links to them. --[[Joey]] + +>> Hmm, ok, what's the intended correct behavior? To really generate the +>> change pages, or to change the links in the feed to point somewhere else that's +>> not missing? If you can easily point me to the right neighborhood in the code +>> I might work on a patch for this. It may be a (minor) bug in the grand scheme +>> of things, but it does seem pretty goofy if you've just clicked an RSS link. :) +>> --Chap (p.s. should this be moved to bugs?) + +>>> The latter -- I think making the permalink point to +>>> "recentchanges#someid" will probably work. Probably first by addressing the +>>> todo about [[todo/ability_to_force_particular_UUIDs_on_blog_posts]], +>>> and then by just using that new ability in the page. --[[Joey]] + +>>>> <del title="Prerequisite done now?">Ah. The prerequisite todo looks like more than I'd like to take on. +>>>> In the meantime, would it be very involved to change whatever bug now +>>>> optimizes away the change pages, or to simply have all the links in the +>>>> feed point to the recentchanges page itself, with no fragment id? +>>>> Either would be a bit nicer than having broken links in the feed. --Chap</del> + +>>>> Does the completion of that todo mean it would be straightforward to get +>>>> recentchanges working now? Is it just that the recentchanges plugin +>>>> needs to generate `\[[!meta guid=something]]` into the internal files, +>>>> and the inline plugin would then generate working links in feeds? How should +>>>> the guid be constructed? Something based on the rcs revision number? I guess +>>>> I'm still not completely clear on your vision for how it ought to work. --Chap + +>>>> My idea is to use `\[[meta guid="http://url/recentchanges#rev"]]`, with the +>>>> `#rev` anchor also included in the change file, and being the rcs's +>>>> internal revision id. Then the guid is globally unique, and actually +>>>> links to the change in the recentchanges page. And, when the change +>>>> has fallen off the page, the link will still go to the recentchanges page. +>>>> +>>>> First, need to check that guids in rss and atom feeds can have anchors in +>>>> them, and that the anchor is treated as part of the guid. (If the guid +>>>> is interpreted as just "http://url/recentchanges", then it's +>>>> not a very good guid.) If using an anchor for a guid is a problem, +>>>> it could instead generate a random uuid, and use `\[[meta +>>>> guid="urn:uuid:<foo>" permalink="http://url/recentchanges"]]` + +>>>>> I had a quick look into this after fixing the "prerequisite", but got +>>>>> bogged down in minor details. Anyway, I'd be happy to help. +>>>>> I think the guid stuff is actually fairly irrelevant, you just need +>>>>> `\[[!meta permalink]]` (and in fact you're using guid incorrectly, by +>>>>> expecting it to be treated as a link). +>>>>> +>>>>> My advice would be: first, fix the bug as reported, by +>>>>> using `\[[!meta permalink="http://blah/blah/blah#change-$rev"]]` (starting +>>>>> anchor names with a number isn't syntactically valid, if I remember +>>>>> correctly, so do have a prefix like "change-" or "rev-" or something). +>>>>> +>>>>> Then, optionally, force the guid too (although it defaults to the permalink +>>>>> anyway, so this shouldn't actually be necessary). +>>>>> +>>>>> Some more explanation of how guids work: it's actually easier to think +>>>>> about them in Atom terms than in RSS terms, since Atom has a clearer +>>>>> conceptual model. +>>>>> +>>>>> The `\[[!meta permalink]]` becomes the `<link>` +>>>>> element in Atom, which contains a link that users can follow; if it's not +>>>>> explicitly given, ikiwiki uses its idea of the page's URL. +>>>>> +>>>>> The `\[[!meta guid]]` becomes the `<id>` element in Atom, which contains an +>>>>> opaque, not-necessarily-resolvable identifier; if it's +>>>>> not explicitly given, ikiwiki uses the same URL as the `<link>`. +>>>>> +>>>>> In RSS the semantics aren't so clear-cut (which is part of why Atom exists!), +>>>>> but the way ikiwiki interprets them is: +>>>>> +>>>>> * `<link>` is the same as in Atom +>>>>> * if `\[[!meta guid]]` is explicitly given, put it in `<guid permalink="no">` +>>>>> (the assumption in this case is that it's a UUID or something) +>>>>> * if `\[[!meta guid]]` is not explicitly given, copy the `<link>` into the `<guid>` +>>>>> +>>>>> I believe RSS aggregators (are meant to) compare `<guid>`s as opaque +>>>>> strings, so using an anchor there should be fine. Atom aggregators are certainly +>>>>> required to compare `<id>`s as opaque strings. +>>>>> +>>>>> --[[smcv]] + +>>>>>> Here's my attempt at a [[patch]] for anchor-based change permalinks: +>>>>>> <http://pastie.org/295016>. +>>>>>> --[[JasonBlevins]], 2008-10-17 + +[[JasonBlevins]] nailed it, [[done]] --[[Joey]] + +> Thanks for applying the patch (and improving it). There's still one small issue: +> the old opening div tag still needs to be removed (it's hard to see the removed line +> with the pastie color scheme). +> --[[JasonBlevins]], 2008-10-18 + +>> Thanks, missed that when I had to hand-apply the patch. --[[Joey]] diff --git a/doc/bugs/recentchanges_sets_has__95__diffurl__61__1_when_diffurl_is_empty.mdwn b/doc/bugs/recentchanges_sets_has__95__diffurl__61__1_when_diffurl_is_empty.mdwn new file mode 100644 index 000000000..6c6e24b02 --- /dev/null +++ b/doc/bugs/recentchanges_sets_has__95__diffurl__61__1_when_diffurl_is_empty.mdwn @@ -0,0 +1,18 @@ +recentchanges.pm sets the template variable HAS_DIFFURL to 1 based solely on whether or not diffurl is defined. I found that diffurl was defined, but empty. The recentchanges template depends on this for recentchangesdiff to properly function -- diff toggling is dependent on HAS_DIFFURL evaluating to false. Adding a check for a non-zero length diffurl fixed the issue for me. A patch against ikiwiki-3.20121212 is as follows: + + --- a/IkiWiki/Plugin/recentchanges.pm 2013-01-27 20:08:59.000000000 -0800 + +++ b/IkiWiki/Plugin/recentchanges.pm 2013-01-27 20:08:30.000000000 -0800 + @@ -181,7 +181,8 @@ sub store ($$$) { + else { + $_->{link} = pagetitle($_->{page}); + } + - if (defined $_->{diffurl}) { + + if (defined $_->{diffurl} && + + length($_->{diffurl}) > 0) { + $has_diffurl=1; + } + + +(There should be one more line at the bottom with a single space on it...) + +> [[applied|done]] --[[Joey]] diff --git a/doc/bugs/recentchangesdiff_crashes_on_commits_which_remove_a_lot_of_files.mdwn b/doc/bugs/recentchangesdiff_crashes_on_commits_which_remove_a_lot_of_files.mdwn new file mode 100644 index 000000000..b3578f26a --- /dev/null +++ b/doc/bugs/recentchangesdiff_crashes_on_commits_which_remove_a_lot_of_files.mdwn @@ -0,0 +1,46 @@ +[[plugins/recentchangesdiff]] causes rendering to segfault if a commit removes a lot of contents. I removed close to 400 files, total size of about 950Kb in a single commit and now `ikiwiki` segfaults on refresh and rebuild: + + [...] + rendering recentchanges.mdwn + [1] 5541 segmentation fault ikiwiki --verbose --setup ikiwiki.setup --refresh + +If I disable the plugin, the segfault does not happen, but I have to remove `wc/recentchanges/*` or else it will crash just as well. + +This is reproducible, but I cannot provide the source code. + +> Can you provide a sanitised version of the source code? I've tried +> ikiwiki on some files that are just large, and cannot reproduce any +> problems, so it must be something in the specific file. (A perl bug is +> also clearly involved here.) --[[Joey]] + +The tarball is at http://scratch.madduck.net/__tmp__recentchanges-segfault.tgz - unpack it in `/tmp` and `chdir()` to /tmp/cdt.taF18912, then run + + ikiwiki --setup ikiwiki.setup + # segfaults + git checkout HEAD^ + ikiwiki --setup ikiwiki.setup + # segfaults + rm -rf wc/recentchanges + ikiwiki --setup ikiwiki.setup + # works + +> I can reproduce it fine with that, thanks, and it's really looking like a +> pure perl bug, that is triggered by markdown. Here's a simpler test case: + + joey@kodama:/tmp>markdown < f + zsh: segmentation fault markdown < f + +> Where f is a 6.3 mb file that I +> extracted from ikiwiki's rendering pipeline. + +> It seems to be crashing at markdown line 345, which is a big nasty +> `s///` statement. + +> The good news: markdown version 1.0.2~b8-2 does not trigger this perl bug. +> I only see it with 1.0.1. (Bad news: Newer versions of markdown are +> slooooooow, especially on such large files.) + +> I'm calling this [[done]] since I've filed [[!debbug 470676]] on perl, and +> also have modified recentchangesdiff to only show the first 200 lines of +> diff, which should be enough without bloating the recentchanges into +> perl-crashing territory. --[[Joey]] diff --git a/doc/bugs/relative_date_weird_results.mdwn b/doc/bugs/relative_date_weird_results.mdwn new file mode 100644 index 000000000..9f35e47f7 --- /dev/null +++ b/doc/bugs/relative_date_weird_results.mdwn @@ -0,0 +1,4 @@ +I just submitted a new bug, and... after clicking "save", my brand new bug page displays, at the bottom: "Last edited 6 hours and 3 minutes ago". Timezone issue, I guess? (Hint: I'm in France) -- [[intrigeri]] + +> Yep, it wasn't including a timezone in the machine parseable time. +> [[done]] --[[Joey]] diff --git a/doc/bugs/removal_of_transient_pages.mdwn b/doc/bugs/removal_of_transient_pages.mdwn new file mode 100644 index 000000000..6d0caf42e --- /dev/null +++ b/doc/bugs/removal_of_transient_pages.mdwn @@ -0,0 +1,78 @@ +The remove plugin cannot remove [[todo/transient_pages]]. + +> this turns out to be harder than +> I'd hoped, because I don't want to introduce a vulnerability in the +> non-regular-file detection, so I'd rather defer that. --[[smcv]] + +This is particularly a problem for tag pages, and autoindex +created pages. So both plugins default to not creating transient +pages, until this is fixed. --[[Joey]] + +> I'll try to work out which of the checks are required for security +> and which are just nice-to-have, but I'd appreciate any pointers +> you could give. --[[smcv]] + +>> I assume by "non-regular file", you are referring to the check +>> in remove that the file "Must exist on disk, and be a regular file" ? +>> --[[Joey]] + +>>> Yes. It's not entirely clear to me why that's there... --s + +>>>> Yeah, 2461ce0de6231bfeea4d98c86806cdbb85683297 doesn't really +>>>> say, and I tend to assume that when I've written paranoid code +>>>> it's there for a reason. I think that here the concern was that +>>>> the file might be in some underlay that the user should not be able +>>>> to affect by web edits. The `-f` check seems rather redundant, +>>>> surely if it's in `%pagesources` ikiwiki has already verified it's +>>>> safe. --[[Joey]] + +---- + +[[!template id=gitbranch branch=smcv/ready/transient-rm author="[[Simon McVittie|smcv]]"]] + +Here's a branch. It special-cases the `$transientdir`, but in such a way +that the special case could easily be extended to other locations where +deletion should be allowed. + +It also changes `IkiWiki::prune()` to optionally stop pruning empty +parent directories at the point where you'd expect it to (for instance, +previously it would remove the `$transientdir` itself, if it turns out +to be empty), and updates callers. + +The new `prune` API looks like this: + + IkiWiki::prune("$config{srcdir}/$file", $config{srcdir}); + +with the second argument optional. I wonder whether it ought to look +more like `writefile`: + + IkiWiki::prune($config{srcdir}, $file); + +although that would be either an incompatible change to internal API +(forcing all callers to update to 2-argument), or being a bit +inconsistent between the one-and two-argument forms. Thoughts? + +--[[smcv]] + +> I've applied the branch as-is, so this bug is [[done]]. +> `prune` is not an exported API so changing it would be ok.. +> I think required 2-argument would be better, but have not checked +> all the call sites to see if the `$file` is available split out +> as that would need. --[[Joey]] + +[[!template id=gitbranch branch=smcv/ready/prune author="[[Simon McVittie|smcv]]"]] + +>> Try this, then? I had to make some changes to `attachment` +>> to make the split versions available. I suggest reviewing +>> patch-by-patch. + +>>> Branch updated; I'd missed a use of prune in ikiwiki.in itself. +>>> Unfortunately, this means it does still need to support the +>>> "undefined top directory" case: there isn't an obvious top +>>> directory for wrappers. --[[smcv]] + +>> I also tried to fix a related bug which I found while testing it: +>> the special case for renaming held attachments didn't seem to work. +>> (`smcv/wip/rename-held`.) Unfortunately, it seems that with that +>> change, the held attachment is committed to the `srcdir` when you +>> rename it, which doesn't seem to be the intention either? --[[smcv]] diff --git a/doc/bugs/remove_orphaned_sparkline-php_from_Suggests.mdwn b/doc/bugs/remove_orphaned_sparkline-php_from_Suggests.mdwn new file mode 100644 index 000000000..ab08c0b26 --- /dev/null +++ b/doc/bugs/remove_orphaned_sparkline-php_from_Suggests.mdwn @@ -0,0 +1,22 @@ +Hi! + +How about to replace sparkline-php from Suggests by a better alternative? + +I would like to file a RM bug to get it out of archive. Do you have a better alternative for it? PHP has a lot of them.. + +Thanks + +> sparline-php is orphaned *in Debian*. Upstream, is has seen activity as +> recently as 11 months ago. +> +> I don't know of a better alternative. I looked at the perl sparkline +> stuff in CPAN and is was bad enough that the pain of using php from this +> perl program was a better alternative. +> +> Anyway, it works great; maintaining the sparkline-php package in Debian +> would certianly be much less work than finding some alternative and +> rewriting the ikiwiki code to use it, *and* packaging that alternative +> and maintaining it in Debian. So your suggestion doesn't make a lot of +> sense; Debian should just find a maintainer for sparkline-php. --[[Joey]] + +[[done]] diff --git a/doc/bugs/remove_plugin_and_untracked_files.mdwn b/doc/bugs/remove_plugin_and_untracked_files.mdwn new file mode 100644 index 000000000..07408c3bc --- /dev/null +++ b/doc/bugs/remove_plugin_and_untracked_files.mdwn @@ -0,0 +1,6 @@ +The [[plugins/remove]] plugin does not report an error if git rm fails. (It +probably doesn't if other VCS backends fail too). This can happen for example +if a page in your source directory is not a tracked file for whatever reason +(in my case, due to renaming the files and forgetting to commit that change). + + -- [[Jon]] diff --git a/doc/bugs/removing_pages_with_utf8_characters.mdwn b/doc/bugs/removing_pages_with_utf8_characters.mdwn new file mode 100644 index 000000000..0d96aa75f --- /dev/null +++ b/doc/bugs/removing_pages_with_utf8_characters.mdwn @@ -0,0 +1,51 @@ +I have a page with the name "umläute". When I try to remove it, ikiwiki says: + +Error: ?umläute does not exist + +> I'm curious about the '?' in the "?umläute" message. Suggests that the +> filename starts with another strange character. Can I get a copy of a +> git repository or tarball containing this file? --[[Joey]] + +I wrote the following patch, which seems to work on my machine. I'm running on FreeBSD 6.3-RELEASE with ikiwiki-3.20100102.3 and perl-5.8.9_3. + + --- remove.pm.orig 2009-12-14 23:26:20.000000000 +0100 + +++ remove.pm 2010-01-18 17:49:39.000000000 +0100 + @@ -193,6 +193,7 @@ + # and that the user is allowed to edit(/remove) it. + my @files; + foreach my $page (@pages) { + + $page = Encode::decode_utf8($page); + check_canremove($page, $q, $session); + + # This untaint is safe because of the + + +> The problem with this patch is that, in a recent fix to the same +> plugin, I made `@pages` come from `$form->field("page")`, and +> that, in turn is already run through `decode_form_utf8` just above the +> code you patched. So I need to understand why that is apparently not +> working for you. (It works fine for me, even when deleting a file named +> "umläute" --[[Joey]] + +---- + +> Update, having looked at the file in the src of the wiki that +> is causing trouble for remove, it is: `uml\303\203\302\244ute.mdwn` +> And that is not utf-8 encoded, which, represented the same +> would be: `uml\303\244ute.mdwn` +> +> I think it's doubly-utf-8 encoded, which perhaps explains why the above +> patch works around the problem (since the page name gets doubly-decoded +> with it). The patch doesn't fix related problems when using remove, etc. +> +> Apparently, on apoca's system, perl encodes filenames differently +> depending on locale settings. On mine, it does not. Ie, this perl +> program always creates a file named `uml\303\244ute`, no matter +> whether I run it with LANG="" or LANG="en_US.UTF-8": +> +> perl -e 'use IkiWiki; writefile("umläute", "./", "baz")' +> +> Remains to be seen if this is due to the older version of perl used +> there, or perhaps FreeBSD itself. --[[Joey]] +> +> Update: Perl 5.10 fixed the problem. --[[Joey]] diff --git a/doc/bugs/rename_fixup_not_attributed_to_author.mdwn b/doc/bugs/rename_fixup_not_attributed_to_author.mdwn new file mode 100644 index 000000000..bcfafac22 --- /dev/null +++ b/doc/bugs/rename_fixup_not_attributed_to_author.mdwn @@ -0,0 +1,12 @@ +When I renamed `todo/transient_in-memory_pages` to [[todo/transient pages]], +`rename::fixlinks` was meant to blame me for the link-fixing commit, and title it +`update for rename of %s to %s`. Instead, it blamed Joey for the commit, +and didn't set a commit message. + +(It also committed a pile of recentchanges pages which shouldn't have +been committed, for which see [[bugs/git_commit_adds_files_that_were_not_tracked]].) + +--[[smcv]] + +> It was calling `rcs_commit` old-style, and so not passing the session +> object that is used to get the user's name. [[fixed|done]] --[[Joey]] diff --git a/doc/bugs/renaming_a_page_destroyed_some_links.mdwn b/doc/bugs/renaming_a_page_destroyed_some_links.mdwn new file mode 100644 index 000000000..fd7a80bd4 --- /dev/null +++ b/doc/bugs/renaming_a_page_destroyed_some_links.mdwn @@ -0,0 +1,12 @@ +When renaming a page here, ikiwiki destroyed unrelated links from unrelated pages. You can see the effect [here](http://mesh.openisp.ca/recentchanges/#diff-dc8dfa96efd3a4d649f571c3aa776f20b3ce0131), or by checking out the git tree (`git://mesh.openisp.ca/ +`) and looking at commit `dc8dfa96efd3a4d649f571c3aa776f20b3ce0131`. + +The renamed page was `configuration/bat-hosts` to `configuration/batman/bat-hosts` and the deleted links were ``\[[AUR | https://aur.archlinux.org/]]` and `\[[CHANGELOG|http://svn.dd-wrt.com:8000/browser/src/router/batman-adv/CHANGELOG]]`. --[[anarcat]] + +> <del>Nevermind that, that commit was unrelated to the rename and probably an operator error.</del> - No, actually, I just reproduced this again - see [another example](http://mesh.openisp.ca/recentchanges/#diff-d67dc2f0fdc149b13122fd6cba887a01c693e949). + +>> Looks like these all involve the wacky wikilink form that includes an +>> external url in the link. Fixed rename code to know about those. +>> [[done]] --[[Joey]] + +>>> Phew!!! Thanks a *lot* for that one, it was really annoying! :) --[[anarcat]] diff --git a/doc/bugs/resized_img_with_only_width_or_height_breaks_ie.mdwn b/doc/bugs/resized_img_with_only_width_or_height_breaks_ie.mdwn new file mode 100644 index 000000000..a5a1c6768 --- /dev/null +++ b/doc/bugs/resized_img_with_only_width_or_height_breaks_ie.mdwn @@ -0,0 +1,9 @@ +When using the img directive while reducing the size of the image by only specifying either the width ("100x") or height ("x100"), the resulting HTML breaks/confuses IE (at least 8 and 9). + +In those cases img plugin do generate HTML with the missing attribute as "empty". For example, if the new size is specified as "100x", the resulting HTML will be <img ... width="100" height=""/>. When IE encounters such empty attributes, the image is sort of compressed into a one (1!) pixel high (or wide) image, which is **not** what you expected. + +If we instead always get the resulting the width and height from the resized image, and uses those values in the img attrs, we make IE happy (and all other renders as well). + +A patch (tested and deployed) is sitting waiting in my git repository. + +> I've applied your patch. Thanks! [[done]] --[[Joey]] diff --git a/doc/bugs/rss_feed_cleanup_on_delete.mdwn b/doc/bugs/rss_feed_cleanup_on_delete.mdwn new file mode 100644 index 000000000..fe0400ff8 --- /dev/null +++ b/doc/bugs/rss_feed_cleanup_on_delete.mdwn @@ -0,0 +1,6 @@ +If a page stops inlining anthing, its rss feed file will linger around and +not be deleted. + +(The linkmap plugin has the same problem with the png files it creates.) + +[[bugs/done]] diff --git a/doc/bugs/rss_feeds_do_not_use_recommended_encoding_of_entities_for_some_fields.mdwn b/doc/bugs/rss_feeds_do_not_use_recommended_encoding_of_entities_for_some_fields.mdwn new file mode 100644 index 000000000..0a435cea3 --- /dev/null +++ b/doc/bugs/rss_feeds_do_not_use_recommended_encoding_of_entities_for_some_fields.mdwn @@ -0,0 +1,52 @@ +The Atom and RSS templates use `ESCAPE=HTML` in the title elements. However, HTML-escaped characters aren't valid according to <http://feedvalidator.org/>. + +Removing `ESCAPE=HTML` works fine, but I haven't checked to see if there are any characters it won't work for. + +For Atom, at least, I believe adding `type="xhtml"` to the title element will work. I don't think there's an equivalent for RSS. + +> Removing the ESCAPE=HTML will not work, feed validator hates that just as +> much. It wants rss feeds to use a specific style of escaping that happens +> to work in some large percentage of all rss consumers. (Most of which are +> broken). +> <http://www.rssboard.org/rss-profile#data-types-characterdata> +> There's also no actual spec about how this should work. +> +> This will be a total beast to fix. The current design is very clean in +> that all (well, nearly all) xml/html escaping is pushed back to the +> templates. This allows plugins to substitute fields in the templates +> without worrying about getting escaping right in the plugins -- and a +> plugin doesn't even know what kind of template is being filled out when +> it changes a field's value, so it can't do different types of escaping +> for different templates. +> +> The only reasonable approach seems to be extending HTML::Template with an +> ESCAPE=RSS and using that. Unfortunately its design does not allow doing +> so without hacking its code in several places. I've contacted its author +> to see if he'd accept such a patch. +> +> (A secondary bug is that using meta title currently results in unnecessry +> escaping of the title value before it reaches the template. This makes +> the escaping issues show up much more than they need to, since lots more +> characters are currently being double-escaped in the rss.) +> +> --[[Joey]] + +> Update: Ok, I've fixed this for titles, as a special case, but the +> underlying problem remains for other fields in rss feeds (such as +> author), so I'm leaving this bug report open. --[[Joey]] + +>> I'm curious if there has been any progress on better RSS output? +>> I've been prototyping a new blog and getting good RSS out of it +>> seems important as the bulk of my current readers use RSS. +>> I note, in passing that the "more" plugin doesn't quite do what +>> I want either - I'd like to pass a full RSS feed of a post and only +>> have "more" apply to the front page of the blog. Is there a way to do that? +>> -- [[dtaht]] +>> +>>> To be clear, the RSS spec sucks to such an extent that, as far as +>>> I know, there is no sort of title escaping that will work in all +>>> RSS consumers. Titles are currently escaped in the way +>>> that tends to break the fewest according to what I've read. +>>> If you're unlucky enough to +>>> have a "&" or "<" in your **name**, then you may still run into +>>> problems with how that is escaped in rss feeds. --[[Joey]] diff --git a/doc/bugs/rss_output_relative_links.mdwn b/doc/bugs/rss_output_relative_links.mdwn new file mode 100644 index 000000000..ff607cbb3 --- /dev/null +++ b/doc/bugs/rss_output_relative_links.mdwn @@ -0,0 +1,3 @@ +RSS output contains relative links. Ie. +http://kitenet.net/~joey/blog/index.rss contains a link to +http://kitenet.net/~joey/blog/../blog.html diff --git a/doc/bugs/rst_fails_on_file_containing_only_a_number.mdwn b/doc/bugs/rst_fails_on_file_containing_only_a_number.mdwn new file mode 100644 index 000000000..57e0cf6aa --- /dev/null +++ b/doc/bugs/rst_fails_on_file_containing_only_a_number.mdwn @@ -0,0 +1,31 @@ +If you create a foo.rst containing only a number, such as "11", rendering +results in the following error being thrown. (Now that I've fixed the error +throwing code..): + + exceptions.TypeError:coercing to Unicode: need string or buffer, int found + +--[[Joey]] + +> Does this patch against proxy.py help? + + index 5136b3c..545e226 100755 + --- a/plugins/proxy.py + +++ b/plugins/proxy.py + @@ -88,7 +101,7 @@ class _IkiWikiExtPluginXMLRPCHandler(object): + + @staticmethod + def _write(out_fd, data): + - out_fd.write(data) + + out_fd.write(str(data)) + out_fd.flush() + + @staticmethod + +> No, still the same failure. I think it's failing parsing the input data, +> (which perl probably transmitted as an int due to perl internals) +> not writing out its response. --[[Joey]] + +> On second thought, this was a bug in ikiwiki, it should be transmitting +> that as a string. Fixed in external.pm --[[Joey]] + +>> [[done]] a while ago, then. I've added a regression test now. --[[smcv]] diff --git a/doc/bugs/rst_plugin_fails_with___34__uncaught_exception:___39__ascii__39___codec_can__39__t_encode_character__34__.mdwn b/doc/bugs/rst_plugin_fails_with___34__uncaught_exception:___39__ascii__39___codec_can__39__t_encode_character__34__.mdwn new file mode 100644 index 000000000..1893e7089 --- /dev/null +++ b/doc/bugs/rst_plugin_fails_with___34__uncaught_exception:___39__ascii__39___codec_can__39__t_encode_character__34__.mdwn @@ -0,0 +1,40 @@ + I get this error when enabling the `rst` plugin. I am running IkiWiki +3.20130904.1ubuntu1 on Ubuntu 14.04 in a non-English UTF-8 locale; the +pages can also contain characters in UTF-8 encoding. + + uncaught exception: 'ascii' codec can't encode character u'\xa9' in position 13: ordinal not in range(128) + Traceback (most recent call last): + File "/usr/lib/ikiwiki/plugins/proxy.py", line 309, in run + self._in_fd, self._out_fd) + File "/usr/lib/ikiwiki/plugins/proxy.py", line 192, in handle_rpc + ret = self._dispatcher.dispatch(method, params) + File "/usr/lib/ikiwiki/plugins/proxy.py", line 84, in dispatch + return self._dispatch(method, params) + File "/usr/lib/python2.7/SimpleXMLRPCServer.py", line 420, in _dispatch + return func(*params) + File "/usr/lib/ikiwiki/plugins/proxy.py", line 253, in hook_proxy + "{0} hook `{1}' returned: [{2}]".format(type, name, ret)) + UnicodeEncodeError: 'ascii' codec can't encode character u'\xa9' in position 13: ordinal not in range(128) + + Traceback (most recent call last): + File "/usr/lib/ikiwiki/plugins/rst", line 86, in <module> + proxy.run() + File "/usr/lib/ikiwiki/plugins/proxy.py", line 317, in run + self.error('uncaught exception: {0}\n{1}'.format(e, tb)) + File "/usr/lib/ikiwiki/plugins/proxy.py", line 298, in error + self.rpc('error', msg) + File "/usr/lib/ikiwiki/plugins/proxy.py", line 233, in rpc + *args, **kwargs) + File "/usr/lib/ikiwiki/plugins/proxy.py", line 173, in send_rpc + raise GoingDown() + proxy.py.GoingDown + +A fix is akin to the one for +<http://ikiwiki.info/bugs/proxy.py_utf8_troubles/>: change +`...format(type, name, ret)` in `proxy.py` line 253 to `format(type, +name, repr(ret))` (which should not hurt since it's a message +for debugging purposes only). + + +> this is [[fixed|done]] in commit [154c4ea9](http://source.ikiwiki.branchable.com/?p=source.git;a=commit;h=154c4ea9e65d033756330a7f8c5c0fa285380bf0) +> (november 2013), which is included in 3.20140227. --[[chrysn]] diff --git a/doc/bugs/rst_plugin_hangs_on_utf-8.mdwn b/doc/bugs/rst_plugin_hangs_on_utf-8.mdwn new file mode 100644 index 000000000..b0f417209 --- /dev/null +++ b/doc/bugs/rst_plugin_hangs_on_utf-8.mdwn @@ -0,0 +1,20 @@ +When rendering an rst page with utf-8 characters in (specifically but not +solely "£"), ikiwiki seems to hang. + +Killing with Control-C gives the following traceback: + + Traceback (most recent call last): + File "/usr/lib/ikiwiki/plugins/rst", line 97, in ? + handler.handle_request() + File "/usr/lib/ikiwiki/plugins/rst", line 74, in handle_request + ret = rpc_read(processor) + File "/usr/lib/ikiwiki/plugins/rst", line 42, in rpc_read + line = sys.stdin.readline() + KeyboardInterrupt + +rst2html on the same file has no problem rendering the file as expected. The +markdown plugin also has no problems rendering the same file, so I'm guessing +it's a problem with the XML-RPC interface. + +Sorry for the delay, this is now fixed! --[[Joey]] +[[!tag done]] diff --git a/doc/bugs/rst_plugin_hangs_when_used_with_Python_3.mdwn b/doc/bugs/rst_plugin_hangs_when_used_with_Python_3.mdwn new file mode 100644 index 000000000..001d990ca --- /dev/null +++ b/doc/bugs/rst_plugin_hangs_when_used_with_Python_3.mdwn @@ -0,0 +1,37 @@ +During ikiwiki make phase the rst process hangs: +[ps output](http://dpaste.com/21TQQKT) +[gdb backtrace 1](http://dpaste.com/0VQBW6D) +[gdb backtrace 1](http://dpaste.com/1VHS88Y) + +working with python 2.7 +[http://dpaste.com/0985A91](http://dpaste.com/0985A91) +not working with python3.3~3.4 +[http://dpaste.com/0ACNK3W](http://dpaste.com/0ACNK3W) + +> Retitled this bug report since it seems to be specific to Python 3. +> +> The `rst` plugin is probably more commonly used with Python 2. +> It seems likely that there is some Python-3-specific bug in `proxy.py`, +> perhaps introduced by [commit 154c4ea + "properly encode and decode from/to utf8 when sending rpc to ikiwiki"]( +http://source.ikiwiki.branchable.com/?p=source.git;a=commitdiff;h=154c4ea9e65d033756330a7f8c5c0fa285380bf0). +> +> I can reproduce this on Debian by installing `python3-docutils` +> and changing the first line of `plugins/proxy.py`, the first +> line of `plugins/pythondemo`, the first line of `plugins/rst` +> and the `system()` call in `t/rst.t` to use `python3` instead +> of `python`. --[[smcv]] + +looks like the problem is in proxy.py +ml = _IkiWikiExtPluginXMLRPCHandler._read(in_fd).decode('utf8') + +without decode('utf8') is working + +> That call was introduced +> [[to fix a bug under Python 2|bugs/crashes_in_the_python_proxy_even_if_disabled]] +> so it cannot just be removed, but I've put a proposed branch on +> [[this related bug|bugs/pythonproxy-utf8_again]]. [[!tag patch]] --smcv + +tested and fixed with patch [http://git.pseudorandom.co.uk/smcv/ikiwiki.git/commitdiff/38bd51bc1bab0cabd97dfe3cb598220a2c02550a](http://git.pseudorandom.co.uk/smcv/ikiwiki.git/commitdiff/38bd51bc1bab0cabd97dfe3cb598220a2c02550a) and patch [http://git.pseudorandom.co.uk/smcv/ikiwiki.git/commitdiff/81506fae8a6d5360f6d830b0e07190e60a7efd1c](http://git.pseudorandom.co.uk/smcv/ikiwiki.git/commitdiff/81506fae8a6d5360f6d830b0e07190e60a7efd1c) + +> [[done]], pending release --[[smcv]] diff --git a/doc/bugs/rst_plugin_has_python_hardcode_in_shebang_line.mdwn b/doc/bugs/rst_plugin_has_python_hardcode_in_shebang_line.mdwn new file mode 100644 index 000000000..a594adc09 --- /dev/null +++ b/doc/bugs/rst_plugin_has_python_hardcode_in_shebang_line.mdwn @@ -0,0 +1,15 @@ +Current the rst plugin uses this shebang line: + + #!/usr/bin/python + +The problem is that rst plugin uses some feature (for example, iterator comprehension) which is unavailable on old version of Python. + +So rst plugin will not work on a machine which has an old version of python in system path even though +the user have installed a new version of python in other place. For example, I am using ikiwiki with the rst plugin on Mac OS X 10.4 which ships python 2.3 but I do have python2.6 installed on /opt/local/bin/python (via macports). + +Thus I suggest to change the shebang line to: + + #!/usr/bin/env python + +> [[done]], although the irony of all the perl hashbangs in ikiwiki +> being hardcoded doesn't escape me. --[[Joey]] diff --git a/doc/bugs/rst_plugin_traceback_with_SimpleXMLRPCDispatcher_from_pyhton_2.5.mdwn b/doc/bugs/rst_plugin_traceback_with_SimpleXMLRPCDispatcher_from_pyhton_2.5.mdwn new file mode 100644 index 000000000..9997d383b --- /dev/null +++ b/doc/bugs/rst_plugin_traceback_with_SimpleXMLRPCDispatcher_from_pyhton_2.5.mdwn @@ -0,0 +1,13 @@ +After adding rst to plugins, ikiwiki --setup fails: + + Traceback (most recent call last): + File "/usr/lib/ikiwiki/plugins/rst", line 93, in <module> + handler = SimpleStdinOutXMLRPCHandler() + File "/usr/lib/ikiwiki/plugins/rst", line 65, in __init__ + SimpleXMLRPCDispatcher.__init__(self) + TypeError: __init__() takes exactly 3 arguments (1 given) + +This is ikiwiki version 2.40 and +[SimpleXMLRPCServer.py](http://svn.python.org/view/python/tags/r25/Lib/SimpleXMLRPCServer.py?rev=51918&view=markup) from python-2.5 + +[[done]] diff --git a/doc/bugs/rst_tweak.mdwn b/doc/bugs/rst_tweak.mdwn new file mode 100644 index 000000000..8667a459b --- /dev/null +++ b/doc/bugs/rst_tweak.mdwn @@ -0,0 +1,52 @@ +rst.pm disallows raw HTML input. (It's meant as a security feature.) +IkiWiki generates HTML in rst files pretty much all the time. As +such, we should enable raw HTML support. --Ethan + +> [[done]], although I did add a news item about it, since it could break +> the security of certian setups that don't use the htmlscrubber. --[[Joey]] + +<pre> +Index: IkiWiki/Plugin/rst.pm +=================================================================== +--- IkiWiki/Plugin/rst.pm (revision 3926) ++++ IkiWiki/Plugin/rst.pm (working copy) +@@ -30,7 +30,7 @@ + html = publish_string(stdin.read(), writer_name='html', + settings_overrides = { 'halt_level': 6, + 'file_insertion_enabled': 0, +- 'raw_enabled': 0 } ++ 'raw_enabled': 1 } + ); + print html[html.find('<body>')+6:html.find('</body>')].strip(); + "; +</pre> + +---- + +Does the Perl version of this plugin still exist? There appears to be no "rst.pm" in the current distribution; all there is is the python version. --Peter + +> No, only the python version exists. It does have `raw_enabled` set. +> --[[Joey]] + +I am sorry, but I am confused. Does this mean that I can use Ikiwiki +features that translate to HTML in rst files? For example, when I use a +\[[pagename]]-style link in a rst file, the page generated by Ikiwiki's rst +plugin says <a href="./../pagename/">pagename</a> as text. The link +is expanded correctly, but the result isn't interpreted as HTML. Is that +what is supposed to happen? --Peter + +> `raw_enabled` allows you to use the +> [raw directive](http://docutils.sourceforge.net/docs/ref/rst/directives.html), +> but this is not used by ikiwiki for wikilinks or anything else. +> That's why the [[plugin_page|plugins/rst]] has its note about +> issues with wikilinks and directives. You'd have to put those inside +> raw directives yourself to avoid rst escaping their result. --[[Joey]] + +You can also create a raw "role" which is at least easier than raw directives. + + .. role:: ikiwiki(raw) + :format: html + + :ikiwiki:`\[[WikiLink]]` + +A role assigns meaning to interpreted text (for example :acronym:`ABC`) or :PEP:`8`. --ulrik [kaizer.se] diff --git a/doc/bugs/search:___34__link__34___and___34__title__34___fields_are_incorrectly_specified.mdwn b/doc/bugs/search:___34__link__34___and___34__title__34___fields_are_incorrectly_specified.mdwn new file mode 100644 index 000000000..c088d1eae --- /dev/null +++ b/doc/bugs/search:___34__link__34___and___34__title__34___fields_are_incorrectly_specified.mdwn @@ -0,0 +1,29 @@ +Currently, ikiwiki indexes the "title" and "link" fields of a page +using the prefix "Z". +This is incorrect. +"Z" is for stemmed terms, +which xapian inserts itself. +Furthermore, the custom field "LINK" should use the "X" prefix. +(This is according to the [xapian-omega documentation] [xapian].) + +I have a [patch][] that fixes this. +Once it is applied, +the wiki should be rebuilt to fix the search index. + +What problems does the current behaviour cause? +Consider the [[tags]] page. +ikiwiki indexes the term "ZStags" for its title. +xapian stems this and also indexes "ZZStag". +(Notice the additional "Z".) +Now when [searching for "title:tags"] [search], +xapian stems this and searches for "ZStag", +and so only finds pages which were indexed by _ikiwiki_ with "ZStag" +(i.e. those pages with the singular "tag" in the title). + +--Gabriel. + +[xapian]: http://xapian.org/docs/omega/termprefixes.html + [patch]: http://www.gmcmanus.org/0001-Use-correct-term-prefixes-when-searching.patch +[search]: http://ikiwiki.info/ikiwiki.cgi?P=title%3Atags + +[[!tag done]] diff --git a/doc/bugs/search_creates_configuration_files_many_times_on_rebuild.mdwn b/doc/bugs/search_creates_configuration_files_many_times_on_rebuild.mdwn new file mode 100644 index 000000000..e933feeca --- /dev/null +++ b/doc/bugs/search_creates_configuration_files_many_times_on_rebuild.mdwn @@ -0,0 +1,9 @@ +Currently, if ikiwiki is rebuilding then search.pm will (wastefully) +create its configuration files every time it indexes a file. + +[This patch](http://www.gmcmanus.org/0001-search-generate-configuration-files-once-only-when.patch) +ensures the configuration files are created only once. + +--Gabriel + +> [[Done]] (and fixed your url) --[[Joey]] diff --git a/doc/bugs/search_for_locale_data_in_the_installed_location.mdwn b/doc/bugs/search_for_locale_data_in_the_installed_location.mdwn new file mode 100644 index 000000000..08af5fe2c --- /dev/null +++ b/doc/bugs/search_for_locale_data_in_the_installed_location.mdwn @@ -0,0 +1,25 @@ +It seems like gettext only searches for locale information in /usr/share/locale, by default. I installed ikiwiki into /usr/local, therefore the locale information wasn't found. This patch fixes the issue: + + --- a/IkiWiki.pm + +++ b/IkiWiki.pm + @@ -1057,6 +1057,7 @@ sub gettext { + $gettext_obj=undef; + return shift; + } + + $gettext_obj->dir("$installdir/share/locale/"); + } + return $gettext_obj->get(shift); + } + +[[!tag patch patch/core]] +-- [[ThomasBleher]] + +> According to my testing, this patch makes ikiwiki's localisation fail for +> `LANG=fr_FR` when everything is installed to the default locations, +> though `LANG=es_ES` works. I don't understand this behavior, especially +> since strace shows it successfully opening the file +> `/usr/share/locale/fr/LC_MESSAGES/ikiwiki.mo`. +> +> (Also, it should check that $installdir is set before using it.) +> +> --[[Joey]] diff --git a/doc/bugs/search_plugin_and_CGI_preview.mdwn b/doc/bugs/search_plugin_and_CGI_preview.mdwn new file mode 100644 index 000000000..2a3d270b7 --- /dev/null +++ b/doc/bugs/search_plugin_and_CGI_preview.mdwn @@ -0,0 +1,19 @@ +Text on a page gets indexed when you preview. + +I discovered this by using (perhaps this is weird) the Sandbox to +preview my markup in a file that I was preparing to check in through svn. +I just deleted the original Sandbox text in the edit form, pasted in my +file, hit Preview, then cancelled the edit, leaving the Sandbox unchanged. + +After that, the Sandbox was one of the search hits for terms in the new +page, and the Sandbox excerpt in the search results showed text taken +from the new page, that was never really in the Sandbox page at all. + +Clicking Edit and then Preview on the original Sandbox page corrected +the problem, of course. + +Making the indexing only happen on a real commit might also speed the +Preview up a small amount. +--Chapman Flack + +[[!tag done]] diff --git a/doc/bugs/search_plugin_finds_no_results_with_xapian_1.2.7.mdwn b/doc/bugs/search_plugin_finds_no_results_with_xapian_1.2.7.mdwn new file mode 100644 index 000000000..3bc430f68 --- /dev/null +++ b/doc/bugs/search_plugin_finds_no_results_with_xapian_1.2.7.mdwn @@ -0,0 +1,14 @@ +I'm using the most recent release of ikiwiki (3.20110905), the Perl shipped with SuSE 11.4 (v5.12.3), and built and installed xapian 1.2.7 from source, as it seems the current stable version that's encouraged for use by xapian. + +After enabling the search plugin and pointing ikiwiki to the omega program, rerunning ikiwiki --setup, and attempting a search, all searches return 0 results. No errors are reported by omindex or ikiwiki while producing the indexes in .ikiwiki/xapian/*, and the files appear to contain the indexed data. I don't think it's a problem in indexing. + +When running omega by hand in the .ikiwiki/xapian directory, providing queries on the command-line, runs correctly but again provides no results. + +I found that Debian stable is currently shipping 1.2.3, and on a hunch, I built that version, and searching now works fine. This looks like the usage of xapian's query template has changed somewhere between 1.2.3 and 1.2.7. Someone more familiar with xapian's query template language should be able to figure out what needs to be changed more specifically. + +> Debian has 1.2.7 now, and I have it installed and searching is working +> fine with it. --[[Joey]] + +> I have this same issue. I tried xapian version 1.2.5. 1.2.8, 1.2.13. I will try and see if installing 1.2.3 fixes this issue. --[[Ramsey]] + +> 1.2.3 didn't fix the issue either --[[Ramsey]] diff --git a/doc/bugs/search_plugin_uses_wrong_css_path.mdwn b/doc/bugs/search_plugin_uses_wrong_css_path.mdwn new file mode 100644 index 000000000..688d51ee6 --- /dev/null +++ b/doc/bugs/search_plugin_uses_wrong_css_path.mdwn @@ -0,0 +1,14 @@ +The search result page uses a wrong path for the css files. + +This is, because the search plugin provides $config{cgiurl} as +basepath to the misc template. And so the path to the css +files ends up to be "$config{cgiurl}/local.css". But this is +wrong if $config{cgiurl} is not the same as $config{url}. + +Maybe misctemplate() and misc.tmpl should use an additional +variable which points always to the base of the wiki. + +e.g. use "wikibase" for css and favicon and "baseurl" for the <base> tag. + +> thanks for pointing this bug out, I've fixed it --[[Joey]]. +[[!tag done]] diff --git a/doc/bugs/search_template_missing_dep.mdwn b/doc/bugs/search_template_missing_dep.mdwn new file mode 100644 index 000000000..eebc5926e --- /dev/null +++ b/doc/bugs/search_template_missing_dep.mdwn @@ -0,0 +1,4 @@ +The [[plugins/search]] plugin caches a filled in version of `page.tmpl` for +omega. This is updated only if missing or on rebuild, so if the template is +modified otherwise and normal refresh allowed to update the rest of the +site, this gets missed and a stale template is used. --[[Joey]] [[done]] diff --git a/doc/bugs/several_entries_in_docs__47__bugs_contain_colons_in_the_filename.mdwn b/doc/bugs/several_entries_in_docs__47__bugs_contain_colons_in_the_filename.mdwn new file mode 100644 index 000000000..9b65aa2fd --- /dev/null +++ b/doc/bugs/several_entries_in_docs__47__bugs_contain_colons_in_the_filename.mdwn @@ -0,0 +1,15 @@ +I just tried to clone the git repo onto a windows machine to test things out a bit and it turns out i cannot even successfully checkout the code because of those colons. Would a patch changing those to underscores be accepted? --Mithaldu + +> Well, this is a difficult thing. Ikiwiki has a configuration setting to +> prevent it writing filenames with colons, but for backwards compatability +> that is not enabled by default. Also nothing would stop people from +> making commits that added filenames with colons even if it were disabled +> in ikiwiki. I don't know that trying to work around obscure limitations +> in OSs that I've never heard of ikiwiki being used on is worth the bother +> TBH, but have not really made up my mind. --[[Joey]] + +>> I'm not trying to run it there. Ikiwiki is way too friggin' weird to try that. I just want to be able to check out the main repo so i can work in a native editor. Right now your core repository is downright hostile to cross-platform development in any way, shape or form. (Just plain splitting the docs from the code would work too.) --Mithaldu + +>>> Does(n't) cygwin handle the filename limitation/translations? If so, can you check out via git inside a cygwin environment? — [[Jon]] + +>>>> That actually allows me to check things out, but the resulting repo isn't compatible with most of the rest of my system, so it's extremely painful. --Mithaldu diff --git a/doc/bugs/shortcut_encoding.mdwn b/doc/bugs/shortcut_encoding.mdwn new file mode 100644 index 000000000..66fd81023 --- /dev/null +++ b/doc/bugs/shortcut_encoding.mdwn @@ -0,0 +1,28 @@ +* The URL is rewritten to + <http://cvs.savannah.gnu.org/viewvc/gnumach/ddb%2Fdb%5Fexpr%2Eh?view=log&root=hurd&pathrev=gnumach-1-branch>, + which the remove server doesn't like. Mind the esacping of [^A-Za-z0-9]. + Might this be a problem of the web server? + +Also, I'd like to put the shortcut usages into backticks +-- `[[!iki shortcuts]]` -- +to have them displayed in the usual backtick-formatting. +That also doesn't work, but this is an already-reported issue, as far as I know. + +--[[tschwinge]] + +> The encoding of the shortcut text is done so that a shortcut can have +> spaces in it etc and they're converted into a valid url. As in the +> example of a shortcut to the wikipedia page for "War of 1812" (although +> the example puts underscores in, it should also work without them). +> +> I suspect that if I dropped the endoding of characters other than space +> and maybe plus, it would break some shortcuts though. Consider a shortcut +> used to do a google search for "foo&bar". You want to encode the "&" +> in that search, otherwise google will search for just foo! +> +> It does seem to be partly a web server problem, since savannah's viewvc +> doesn't decode the escaped characters in the path string. +> +> I could add a %S that is not escaped, and leave %s escaped.. --[[Joey]] +> +> [[done]] diff --git a/doc/bugs/shortcut_plugin_will_not_work_without_shortcuts.mdwn.mdwn b/doc/bugs/shortcut_plugin_will_not_work_without_shortcuts.mdwn.mdwn new file mode 100644 index 000000000..5cc669106 --- /dev/null +++ b/doc/bugs/shortcut_plugin_will_not_work_without_shortcuts.mdwn.mdwn @@ -0,0 +1,33 @@ +On my initial ikiwiki -setup auto.setup, I get the following error: + + shortcut plugin will not work without shortcuts.mdwn + /home/turian/utils/etc/ikiwiki/auto.setup: ikiwiki --refresh --setup /home/turian/iki.setup failed at IkiWiki/Setup/Automator.pm line 105. + + +This is using the latest git pull of ikiwiki. +I am not sure why it is not finding shortcuts.mdwn. -- [[JosephTurian]] + +> The error, and the weird paths suggest to me that you +> have installed ikiwiki in a strange way, and it is failing +> to find its basewiki underlay. The `$installdir` is +> hardcoded into IkiWiki.pm at build time, based on the PREFIX +> setting (see README). +> +> If that's not set right, you'll have other problems than just this one, +> so I suggest you check how you installed ikiwiki. +> +> Anyway, I've made the shortcut plugin only warn about this.. +> --[[Joey]] + +> > I have +> > $installdir="/home/turian/utils/" +> > and the underlay dir is set to: +> > "$installdir/share/ikiwiki/basewiki", +> > which does contain shortcuts.mdwn. So I am not sure why it is not finding it. +> > I am grappling with installing ikiwiki in a user account, and would like to get the directories set up correctly. +> > How can I debug this issue further? + +>>>> Why don't you strace it and look at where it's looking for +>>>> shortcuts.mdwn. --[[Joey]] + +>>>>>> Hmm, so change the PERL5LIB seemed to fix this. [[Done]]. diff --git a/doc/bugs/shortcuts_don__39__t_escape_from_Markdown.mdwn b/doc/bugs/shortcuts_don__39__t_escape_from_Markdown.mdwn new file mode 100644 index 000000000..022987efb --- /dev/null +++ b/doc/bugs/shortcuts_don__39__t_escape_from_Markdown.mdwn @@ -0,0 +1,7 @@ +Writing [[!wikipedia Low_frequency_oscillation]] causes the word "frequency" +to show up in italics, since underscores are Markdown for italics. Using +[[!wikipedia low frequency oscillation]] works in this case, because Wikipedia +will redirect, but it's hardly clean. Maybe the shortcuts plugin should +run pagetitle() on the text of its link? --Ethan + +> [[bugs/done]] --[[Joey]] diff --git a/doc/bugs/sidebar_is_obscured_by_recentchanges.mdwn b/doc/bugs/sidebar_is_obscured_by_recentchanges.mdwn new file mode 100644 index 000000000..6acc13b84 --- /dev/null +++ b/doc/bugs/sidebar_is_obscured_by_recentchanges.mdwn @@ -0,0 +1,59 @@ +I've set up a simple sidebar on an otherwise fairly default wiki. The sidebar uses css float:right and sits above most pages quite nicely. + +For example, my wiki's [front](http://www.cse.unsw.edu.au/~cs3431/wiki/) and [news](http://www.cse.unsw.edu.au/~cs3431/wiki/news/) pages show the sidebar nicely floating on top of the background. (As a side note, I had to add: + + #sidebar { + border: 1px solid; + background: white; + } + +to <code>local.css</code> to get the border and make sure that the RSS feed's grey title didn't show through on the news page.) + +> Hmm the background color setting seems like a change it makes sense to make to +> style.css .. done. +> --[[Joey]] + +Unfortunately, the [recentchanges](http://www.cse.unsw.edu.au/~cs3431/wiki/recentchanges/) page doesn't look so nice - the sidebar appears below the recentchanges list. + +I don't understand why the sidebar is appearing below the recentchanges inline, but above the news inline. + +> I don't see the problem here in firefox 3. The sidebar is at the top of +> both pages. However, it might have to do with the recentchanges page +> itself using floating elements to build up the table-like display. --[[Joey]] + +>> I didn't test in firefox. I now have screenshots for both firefox and safari. It is still interesting to compare the layout. The first is quite broken. The second is only a little broken. The third is what I was expecting. + +Here is a screenshot of the broken behaviour in Safari: + +<img src="http://www.cse.unsw.edu.au/~willu/screenshots/safari-1.png" alt="screenshot of broken behaviour in Safari" width="50%" /> + +Here is a screenshot of the same thing in FireFox. Notice that while there are no overlaps, there is still a large gap in the layout. + +<img src="http://www.cse.unsw.edu.au/~willu/screenshots/firefox-1.png" alt="screenshot of semi-working behaviour in Firefox" width="50%" /> + +Here is an inline news page (in Safari, but it looks similar in firefox). I was expecting both of the previous layouts to look like this. + +<img src="http://www.cse.unsw.edu.au/~willu/screenshots/safari-2.png" alt="screenshot of working behaviour in Safari" width="50%" /> + +What really surprises me is WHY this looks any different. And when you look at style.css you see that recentchanges and sidebar both use float, whereas normal inline pages do not. +Note that in the third (working) screenshot, the top bullet point is wrapped. This is because the sidebar is floated. + +I think there is: + + * A display bug in safari, and + * It would be nice to clean up the way recentchanges are displayed so that there isn't a vertical gap for the sidebar. I'll play with this and see what I can do. + +Looked at this a little more. I've found the following. Here is my current local.css: + + div.recentchanges { + clear: both; + overflow: visible; + } + +Adding "clear: both;" makes the recentchanges div start below (as in further down the page) the sidebar. This makes safari behave like firefox above (changes the 1st screenshot to look more like the 2nd screenshot). + +Adding "overflow: visible;" (or removing "overflow: auto" from style.css) makes the sidebar appear above (as in printed over the top of, not higher up the page) the recentchanges (similar to the third screen shot above). Unfortunately because ".recentchanges .pagelinks" uses "float: right;" it looks strange in other ways. For this reason I use the "clear:both;" as well. + +-- [[users/Will]] + +>> Looks like [[Joey]] has added `clear:both;` to style.css, so this is [[bugs/done]]. -- [[Will]] diff --git a/doc/bugs/sidebar_not_updated_in_unedited_subpages.mdwn b/doc/bugs/sidebar_not_updated_in_unedited_subpages.mdwn new file mode 100644 index 000000000..c3e0ee18c --- /dev/null +++ b/doc/bugs/sidebar_not_updated_in_unedited_subpages.mdwn @@ -0,0 +1,9 @@ +I turned on the sidebar plugin, with global_sidebars on (in the web setup page), created a sidebar page in the root, and edited the sidebar a few times. + +I then noticed that all pages on the root had been updated with a sidebar, but no subpages (i.e. a/b). Only after editing a subpage did it get a sidebar. Editing sidebar itself only updated subpages with sidebars, the other subpages had not been refreshed (proven by their unchanged filesystem date) + +After calling ikiwiki --setup on the command line all pages were updated. So this seems to be a difference between web-started --setup and command-line --setup. Or it just doesn't work the first time --setup is called after sidebars are enabled. + + + + diff --git a/doc/bugs/sitemap_includes_images_directly.mdwn b/doc/bugs/sitemap_includes_images_directly.mdwn new file mode 100644 index 000000000..d9d07c65f --- /dev/null +++ b/doc/bugs/sitemap_includes_images_directly.mdwn @@ -0,0 +1,8 @@ +A bug in the plugin [[/plugins/map]]: It displays images inline. + +When I tried, it displayed the one image I have in my small wiki inline in the map. ideally it should link to it, just like it links to pages. [example at my site][uw]. Note that I normally keep images outside, but this time I thought, why not have it all at the same place? (Images are also contextual content (fits to its subpage))--ulrik + +[uw]: http://www.student.lu.se/~cif04usv/wiki/sitemap.html + +> [[done]] (hope noone was relying on the map inlining their images..) +> --[[Joey]] diff --git a/doc/bugs/some_but_not_all_meta_fields_are_stored_escaped.mdwn b/doc/bugs/some_but_not_all_meta_fields_are_stored_escaped.mdwn new file mode 100644 index 000000000..587771ba4 --- /dev/null +++ b/doc/bugs/some_but_not_all_meta_fields_are_stored_escaped.mdwn @@ -0,0 +1,44 @@ +[[!template id=gitbranch branch=smcv/unescaped-meta author="[[Simon_McVittie|smcv]]"]] +[[!tag patch]] +(Warning: this branch has not been tested thoroughly.) + +While discussing the [[plugins/meta]] plugin on IRC, Joey pointed out that +it stores most meta fields unescaped, but 'title', 'guid' and 'description' +are special-cased and stored escaped (with numeric XML/HTML entities). This +is to avoid emitting markup in the `<title>` of a HTML page, or in an RSS/Atom +feed, neither of which are subject to the [[plugins/htmlscrubber]]. + +However, having the meta fields "partially escaped" like this is somewhat +error-prone. Joey suggested that perhaps everything should be stored +unescaped, and the escaping should be done on output; this branch +implements that. + +Points of extra subtlety: + +* The title given to the [[plugins/search]] plugin was previously HTML; + now it's plain text, potentially containing markup characters. I suspect + that that's what Xapian wants anyway (which is why I didn't change it), + but I could be wrong... + + > AFAICS, this if anything, fixes a bug, xapian definitely expects + > unescaped text here. --[[Joey]] + +* Page descriptions in the HTML `<head>` were previously double-escaped: + the description was stored escaped with numeric entities, then that was + output with a second layer of escaping! In this branch, I just emit + the page description escaped once, as was presumably the intention. + +* It's safe to apply this change to a wiki and neglect to rebuild it + (assuming I implemented it correctly!), but until the wiki is rebuilt, + titles, descriptions and GUIDs for unchanged pages will appear + double-escaped on any page that inlines them in `quick=yes` mode, and + is rebuilt for some other reason. The failure mode is too much escaping + rather than too little, so it shouldn't be a security problem. + +* Reverting this change, if applied, is more dangerous; until the wiki is + rebuilt, any titles, descriptions and GUIDs on unchanged pages that + contained markup could appear unescaped on any page that inlines them + in `quick=yes` mode, and is rebuilt for some other reason. The failure + mode here would be too little escaping, i.e. cross-site scripting. + +[[!tag done]] diff --git a/doc/bugs/some_strings_are_not_internationalized.mdwn b/doc/bugs/some_strings_are_not_internationalized.mdwn new file mode 100644 index 000000000..a1b38257a --- /dev/null +++ b/doc/bugs/some_strings_are_not_internationalized.mdwn @@ -0,0 +1,47 @@ +A lot of strings in ikiwiki are hardcoded and not taken for locales resources through gettext. This is bad because ikiwiki is thus difficult to spread for non-english users. + +I mean that, for instance in CGI.pm, line like: + +`my @buttons=("Save Page", "Preview", "Cancel");` + +should be written as + +`my @buttons=(gettext("Save Page"), gettext("Preview"), gettext("Cancel"));` + +> Yes, these need to be fixed. But note that the localised texts come back +> into ikiwiki and are used in various places, including plugins. +> Including, possibly, third-party plugins. So localising the buttons would +> seem to require converting from the translations back into the C locale +> when the form is posted. --[[Joey]] + +>> Wouldn't it be more easy to change all calls to the corrects ones (including in plugins) ? +>> For instance in the same file (CGI.pm): `elsif ($form->submitted eq gettext("Save Page")) {`. +>> That way no conversion to the C locale is needed. +>> gettext use should just be publicized in documentation (at least in [[plugins/write]]). --[[bbb]] + +>>> It would be easy, but it could break third-party plugins that hardcode +>>> the english strings. It's also probably less efficient to run gettext +>>> over and over. --[[Joey]] + +In standards templates things seems wrongly written too. For instance in page.tmpl line like: + +`<li><a href="<TMPL_VAR EDITURL>" rel="nofollow">Edit</a></li>` + +should be written as + +`<li><a href="<TMPL_VAR EDITURL>" rel="nofollow"><TMPL_VAR EDITURL_TEXT</a></li>` + +with EDITURL_TEXT variable initialized in Render.pm through a gettext call. + +Am I wrong ? + +> No, that's not a sane way to localise the templates. The templates can be +> translated by making a copy and modifying it, or by using a tool to +> generate .mo files from the templates, and generate translated templates +> from .po files. (See [[todo/l10n]] for one attempt.) But pushing the +> localisation of random strings in the templates through the ikiwiki +> program defeats the purpose of having templates at all. --[[Joey]] + +If not I can spend some time preparing patches for such corrections if it can help. + +-- [[/users/bbb]] diff --git a/doc/bugs/space_in_a___91____91__page_link__93____93___doesn__39__t_make_link.mdwn b/doc/bugs/space_in_a___91____91__page_link__93____93___doesn__39__t_make_link.mdwn new file mode 100644 index 000000000..39f5d891e --- /dev/null +++ b/doc/bugs/space_in_a___91____91__page_link__93____93___doesn__39__t_make_link.mdwn @@ -0,0 +1,32 @@ +I attempted to make a new webpage by having wiki code with + [[!new page]] + [newpage] + +This was converted to literal: + [[!new page]] +and the correct hyperlink: + ?newpage + +So when has a space it doesn't let you create a new page. I am using 1.35. Let's see what happens here: + +[[!new page]] + +A moment later ... same thing ... it is not a link (no question mark to create). + +Is this documented? How do I create a webpage with space in filename? + +> You use underscores in place of spaces. I've improved the docs a bit. +> Spaces are not allowed because preprocessor directives look like +> wikilinks, except they contain one or more spaces.. --[[Joey]] + +Examples in various files show spaces within the double brackets. + +> I don't know of any that do that, can you either point me to them or fix +> them in the wiki? Note that examples of preprocessor directives _will_ +> contain spaces. --[[Joey]] + +(By the way, the Page Location dropdown above has underscores for spaces and underscore91underscore and 93 and 39 instead of left bracket, right bracket and single quote. When rendered on final page it will be correct but in the select option box it looks strange.) + +> This is fixed now. --Ethan + +>> Calling this [[bugs/done]], all issues seem addressed. --[[Joey]] diff --git a/doc/bugs/special_characters_in_tag_names_need_manual_escaping.mdwn b/doc/bugs/special_characters_in_tag_names_need_manual_escaping.mdwn new file mode 100644 index 000000000..4ff6763a3 --- /dev/null +++ b/doc/bugs/special_characters_in_tag_names_need_manual_escaping.mdwn @@ -0,0 +1,3 @@ +Having read i18n_characters_in_post_title, I have a page named `St John's` in a file named `St_John__39__s.mdwn`. Regular wikilinks like `\\[[St_John's]]` successfully point to that page. However, if I tag a page with `\[[!tag St_John's]]`, that link is shown as pointing to a non-existant page. Modify the tag to read `\[[!tag St_John__39__s]]` works around the problem. + +[[done]] in 1.49 --[[Joey]] diff --git a/doc/bugs/ssl_certificates_not_checked_with_openid.mdwn b/doc/bugs/ssl_certificates_not_checked_with_openid.mdwn new file mode 100644 index 000000000..04ece0ae8 --- /dev/null +++ b/doc/bugs/ssl_certificates_not_checked_with_openid.mdwn @@ -0,0 +1,85 @@ +As far as I can tell, ikiwiki is not checking the SSL certificate of the remote host when using openid authentication. If so, this would allow for man-in-the-middle type attacks. Alternatively, maybe I am getting myself confused. + +Test #1: Enter URL as openid server that cannot be verified (either because the certificate is self signed or signed by an unknown CA). I get no SSL errors. + +Test #2: Download net\_ssl\_test from dodgy source (it uses the same SSL perl library, and test again. It seems to complain (on same site ikiwiki worked with) when it can't verify the signature. Although there is other breakage with the version I managed to download (eg. argument parsing is broken; also if I try to connect to a proxy server, it instructs the proxy server to connect to itself for some weird reason). + +For now, I want to try and resolve the issues with net\_ssl\_test, and run more tests. However, in the meantime, I thought I would document the issue here. + +-- Brian May + +> Openid's security model does not rely on the openid consumer (ie, +> ikiwiki) performing any sanity checking of the openid server. All the +> security authentication goes on between your web browser and the openid +> server. This may involve ssl, or not. +> +>> Note that I'm not an openid expert, and the above may need to be taken +>> with a grain of salt. I also can make no general statements about openid +>> being secure. ;-) --[[Joey]] +> +> For example, my openid is "http://joey.kitenet.net/". If I log in with +> this openid, ikiwiki connects to that http url to determine what openid +> server it uses, and then redirects my browser to the server +> (https://www.myopenid.com/server), which validates the user and redirects +> the browser back to ikiwiki with a flag set indicating that the openid +> was validated. At no point does ikiwiki need to verify that the https url +> is good. +> --[[Joey]] + +>> Ok, so I guess the worst that could happen when ikiwiki talks to the http +>> address is that it gets intercepted, and ikiwiki gets the wrong address. +>> ikiwiki will then redirect the browser to the wrong address. An attacker could +>> trick ikiwiki to redirect to their site which always validates the user +>> and then redirects back to ikiwiki. The legitimate user may not even notice. +>> That doesn't so seem secure to me... + +>> All the attacker needs is access to the network somewhere between ikiwiki +>> and http://joey.kitenet.net/ or the ability to inject false DNS host names +>> for use by ikiwiki and the rest is simple. + +>> -- Brian May + +>>> I guess that the place to add SSL cert checking would be in either +>>> [[!cpan LWPx::ParanoidAgent]] or [[!cpan Net::OpenID::Consumer]]. Adding +>>> it to ikiwiki itself, which is just a user of those libraries, doesn't +>>> seem right. +>>> +>>> It's not particularly clear to me how a SSL cert can usefully be +>>> checked at this level, where there is no way to do anything but +>>> succeed, or fail; and where the extent of the check that can be done is +>>> that the SSL cert is issued by a trusted party and matches the domain name +>>> of the site being connected to. I also don't personally think that SSL +>>> certs are the right fix for DNS poisoning issues. --[[Joey]] + +I was a bit vague myself on the details on openid. So I looked up the standard. +I was surprised to note that they have already considered these issues, in +section 15.1.2, <http://openid.net/specs/openid-authentication-2_0.html#anchor41>. + +It says: + +"Using SSL with certificates signed by a trusted authority prevents these kinds of +attacks by verifying the results of the DNS look-up against the certificate. Once +the validity of the certificate has been established, tampering is not possible. +Impersonating an SSL server requires forging or stealing a certificate, which is +significantly harder than the network based attacks." + +With regards to implementation, I am surprised that the libraries don't seem to +do this checking, already, and by default. Unfortunately, I am not sure how to test +this adequately, see [[!debbug 466055]]. -- Brian May + +--- + +I think [[!cpan Crypt::SSLeay]] already supports checking the certificate. The trick +is to get [[!cpan LWP::UserAgent]], which is used by [[!cpan LWPx::ParanoidAgent]] to +enable this checking. + +I think the trick is to set one of the the following environment variables before retrieving +the data: + +$ENV{HTTPS\_CA\_DIR} = "/etc/ssl/certs/"; +$ENV{HTTPS\_CA\_FILE} = "/etc/ssl/certs/file.pem"; + +Unfortunately I get weird results if the certificate verification fails, see [[!debbug 503440]]. +It still seems to work though, regardless. + +-- Brian May diff --git a/doc/bugs/strange_hook_id_in_skeleton.pm.mdwn b/doc/bugs/strange_hook_id_in_skeleton.pm.mdwn new file mode 100644 index 000000000..5e96acf60 --- /dev/null +++ b/doc/bugs/strange_hook_id_in_skeleton.pm.mdwn @@ -0,0 +1,5 @@ + hook(type => "savestate", id => "savestate", call => \&savestate); + +Shouldn't that id be "skeleton", like all the other ids? --Ethan + +[[done]] diff --git a/doc/bugs/stray___60____47__p__62___tags.mdwn b/doc/bugs/stray___60____47__p__62___tags.mdwn new file mode 100644 index 000000000..99d6fe09f --- /dev/null +++ b/doc/bugs/stray___60____47__p__62___tags.mdwn @@ -0,0 +1,17 @@ +When using the [[plugins/htmltidy]] plugin (and possibly in other circumstances), ikiwiki sometimes creates more `</p>` tags than `<p>` tags, causing unbalanced markup. I've previously noticed unbalanced tags when a `\[[!map]]` matches no pages. This is part of the reason I developed [[plugins/htmlbalance]]. + +This is particularly noticeable if htmltidy is enabled when building the docwiki: on the 'contrib' plugin pages, the title becomes `foo </p> (third-party plugin)` (with the angle-brackets escaped - it seems the text gets sanitized but is then escaped anyway). + +I believe that this snippet in `IkiWiki.pm` might be the reason for the imbalance: + + if ($oneline) { + # hack to get rid of enclosing junk added by markdown + # and other htmlizers + $content=~s/^<p>//i; + $content=~s/<\/p>$//i; + chomp $content; + } + +The fact that HTML in a `\[[!meta title]]` is added but then escaped might indicate that some other bug is involved. + +> [[done]] --[[Joey]] diff --git a/doc/bugs/structured_config_data_is_mangled.mdwn b/doc/bugs/structured_config_data_is_mangled.mdwn new file mode 100644 index 000000000..869d48e96 --- /dev/null +++ b/doc/bugs/structured_config_data_is_mangled.mdwn @@ -0,0 +1,61 @@ +Put something like this in the setup file: + +~~~ +conversion: + - from: odt + to: pdf + command: [unoconv, -f, pdf, -o, $OUTPUTDIR, $INPUTFILE] + - from: ditaa + to: png + command: [ditaa, $INPUTFILE, $OUTPUTFILE, -s, 0.7] +~~~ + +However `Dumper($config{conversion})` shows: + +~~~ +$VAR1 = [ + 'HASH(0x164e1a0)', + 'HASH(0x164e3c8)' + ]; +~~~ + +I think it is getting mangled in `sub merge` in `IkiWiki/Setup.pm` and its calls to `possibly_foolish_untaint` + +Workaround: force the array values to be strings, and then re-parse them using YAML::XS::Load: + +~~~ +conversion: + - | + from: [odt, odp] + to: pdf + command: [unoconv, -f, pdf, -o, $OUTPUTDIR, $INPUTFILE] + - | + from: ditaa + to: png + command: [ditaa, $INPUTFILE, $OUTPUTFILE, -s, 0.7] + +... + +sub checkconfig { + if (!defined $config{conversion} || ref $config{conversion} ne "ARRAY") { + error(sprintf(gettext("Must specify '%s' and it must be a list"), "conversion")); + } + for (my $i=0; $i < @{$config{conversion}}; $i++) { + $config{conversion}->[$i] = YAML::XS::Load($config{conversion}->[$i]) if + ref $config{conversion}->[$i] ne 'HASH'; + } +} +~~~ + +> `getsetup` defines config options to be one of: boolean, string, integer, +> pagespec, "internal" (non-user-visible string), ref to an array of one of +> those scalar types, or ref to a hash { string => one of those scalar types }. +> IkiWiki::Setup also appears to support regexps (qr//), although that's +> not documented (presumably they're treated the same as strings). +> +> Supporting arbitrary arrays/hashes as values would require some way to +> untaint the values recursively. +> +> Complex config data also can't be used with the [[plugins/websetup]] +> plugin, which currently supports everything that IkiWiki::Setup does, +> except for hashes. --[[smcv]] diff --git a/doc/bugs/support_for_openid2_logins.mdwn b/doc/bugs/support_for_openid2_logins.mdwn new file mode 100644 index 000000000..a71ed7ba9 --- /dev/null +++ b/doc/bugs/support_for_openid2_logins.mdwn @@ -0,0 +1,24 @@ +I have several complaints that users cannot contribute to my ikiwiki instances since they only have OpenID logins that support OpenID2. E.g. Yahoo!'s OpenID only supports 2.0+ + +This is not the fault of ikiwiki, though the problem lies within the [perl openid consumer](http://packages.qa.debian.org/libn/libnet-openid-consumer-perl.html) in Debian which is a 1.x implementation AFAIK. + +I've contacted JanRain who have pointed me to: + +* [OpenID4Perl](http://code.sxip.com/openid4perl/) +* Some [work](http://code.sixapart.com/svn/openid/trunk/perl/) by David Recordon + +However both Perl OpenID 2.x implementations have not been released and are incomplete implementations. :( + +> Both of the projects referenced above have since been released. +> Net::OpenID::Consumer 0.x in Debian is indeed only an OpenID 1 +> implementation. However, Net::OpenID::Consumer 1.x claims to be +> an OpenID 2 implementation (it's the second of the projects +> above). I've filed a bug in Debian asking for the package to be +> updated. --[[smcv]] + +> Net::OpenID::Consumer 1.x is now in Debian unstable --[[dom]] + +> I've tested with yahoo, and it works with the updated module. Sweet and +> [[done]] --[[Joey]] + +## A quick fix for the impatient running stable is simply `sudo apt-get install libnet-openid-consumer-perl -t unstable` diff --git a/doc/bugs/svg_and_pdf_conversion_fails.mdwn b/doc/bugs/svg_and_pdf_conversion_fails.mdwn new file mode 100644 index 000000000..9910959f9 --- /dev/null +++ b/doc/bugs/svg_and_pdf_conversion_fails.mdwn @@ -0,0 +1,60 @@ +[[!template id=gitbranch branch=chrysn/imgforpdf author="[[chrysn]]"]] + +when using the [[img plugin|plugins/img]] with an svg file, it is supposed to +convert it into a png for display in all browsers, and because the typical use +case is rendering small preview versions. + +this currently doesn't work (at least with graphicsmagick-libmagick-dev-compat +1.3.18-1) due to the sequence imagemagick options are set, needs an extension +to work for pdfs (or any other imagemagick compatibile file) too, and should +have an additional parameter for page selection. + +i've provided a series of [[!taglink patch]]es in the chrysn/imgforpdf [[git]] +branch. + +i'd prefer to go a step further, and not only convert pdf and svg files to png, +but everything (with the possible exception of jpg files), as most other image +formats can't be displayed in a browser anyway -- but i didn't in this patch +series, as it would alter the file names of existing images, i don't know if +that needs special care or breaks something i don't use; this way, my patches +should be safe for inclusion. + +--[[chrysn]] + +> update 2014-06-29: the patch still applies and fixes the issue. in the +> meantime, i noticed that the desired effect doesn't happen when no explicit +> size is set. as scalable graphics don't necessarily have a natural size +> anyway, i don't consider that a showstopper. --[[chrysn]] + +>> This all looks good in principle, but I would like to do a more detailed +>> review, and test it with "real ImageMagick" in case its behaviour differs +>> from GraphicsMagick. +>> +>> An automated regression test for the desired behaviour in `t/` would +>> be great. There are SVGs and PNGs in the docwiki already; there are no +>> JPEGs or PDFs, but perhaps you could add a trivially small example +>> of each to `t/`? Imitating `t/tag.t` or `t/trail.t`, and skipping the +>> test if the required modules are missing like `t/podcast.t` does, +>> seems like it would work best. +>> +>> I agree that everything not in an interoperable web format should be +>> converted to PNG when it's scaled down, but yes, that's more likely +>> to be a breaking change, so it seems best to do that as a separate +>> branch. In practice I think this means JPEG -> JPEG and everything +>> else -> PNG, since JPEG is commonly used for photos and photo-like +>> images that don't compress well under lossless compression. --[[smcv]] + +>>> i've added a unit test and tested it with the [[!debsid perlmagick]] +>>> package, the [[!debsid graphicsmagick-libmagick-dev-compat]] package and +>>> the experimental [[!debpts libimage-magick-perl]] package (where the +>>> [[!debpts libmagickcore-6.q16-2-extra]] package is required too), in the +>>> meantime filing [[!debbug 753770]]. (why is it that it sometime seems i +>>> find more bugs in ikiwiki's dependencies than in itself when working with +>>> it?) +>>> +>>> the unit test also checks for file removal when it is not created any more, +>>> which works, so my biggest fear about the all-to-png change is unwarranted. +>>> i'll have a look at that some time, but i think as things are, this is +>>> ready now, please review again. --[[chrysn]] + +>>>> [[merged|done]] --[[smcv]] diff --git a/doc/bugs/svn+ssh_commit_fail.mdwn b/doc/bugs/svn+ssh_commit_fail.mdwn new file mode 100644 index 000000000..b58f43721 --- /dev/null +++ b/doc/bugs/svn+ssh_commit_fail.mdwn @@ -0,0 +1,5 @@ +If I try to do a web commit, to a svn+ssh repo, it fails with +"Host key verification failed." +I think that the setuid isn't fully taking; it should be running as me, +but commit log shows www-data. So maybe it has the wrong username? Or +EUID/Real UID screwage. [[bugs/done]] diff --git a/doc/bugs/svn-commit-hanging.mdwn b/doc/bugs/svn-commit-hanging.mdwn new file mode 100644 index 000000000..e5c5dde14 --- /dev/null +++ b/doc/bugs/svn-commit-hanging.mdwn @@ -0,0 +1,7 @@ +When I'm committing a page via the Web, Ikiwiki hangs at the `svn commit` stage. I'm sure that this is a result of all my local modifications, so there's no need to consider this a bug per se, but I'd be interested in hearing whether anybody else has seen this. -- [[Ben]] + +What kinds of local modifications are those? --[[Joey]] + +Many. ;-) I have the usedirs patch applied, about 10 minor patches to customise things that weren't otherwise customisable, and a custom SVN hook. As you would expect, the problem was the hook (which I'd forgotten about)... Pretend I was never here. ;-) -- [[Ben]] + +[[bugs/done]] ;-) --[[Joey]] diff --git a/doc/bugs/svn_commit_failures_interpreted_as_merge_conflicts.mdwn b/doc/bugs/svn_commit_failures_interpreted_as_merge_conflicts.mdwn new file mode 100644 index 000000000..0c9bce4b9 --- /dev/null +++ b/doc/bugs/svn_commit_failures_interpreted_as_merge_conflicts.mdwn @@ -0,0 +1,21 @@ +I'm attempting a merge with the SVN plugin via the web interface +with ikiwiki-3.20100403 and subversion 1.6.11. + +The web interface says + + Your changes conflict with other changes made to the page. + + Conflict markers have been inserted into the page content. Reconcile the conflict and commit again to save your changes. + +However there are no merge conflict markers in the page. My apache error log says: + + [Fri Apr 30 16:43:57 2010] [error] [client 10.64.64.42] svn: Commit failed (details follow):, referer: https://unixwiki.ncl.ac.uk/ikiwiki.cgi + [Fri Apr 30 16:43:57 2010] [error] [client 10.64.64.42] svn: Authorization failed, referer: https://unixwiki.ncl.ac.uk/ikiwiki.cgi + +-- [[Jon]] + +> Only way for this to be improved would be for the svn plugin to +> explicitly check the file for conflict markers. I guess it could +> change the error message then, but the actual behavior of putting the +> changed file back in the editor so the user can recommit is about right +> as far as error recovery goes. --[[Joey]] diff --git a/doc/bugs/svn_fails_to_update.mdwn b/doc/bugs/svn_fails_to_update.mdwn new file mode 100644 index 000000000..6ed839cf6 --- /dev/null +++ b/doc/bugs/svn_fails_to_update.mdwn @@ -0,0 +1,89 @@ +In poking around at the svn backend I found that the svn post-commit +hook calls to svn update fail regularly with an error code of 256. +Apparently during the post-commit hook can't update because the +working copy is locked from the commit. Since the post-commit hook doesn't send +errors anywhere and svn update runs with --quiet anyhow, this error +isn't usually visible, but on my system: + + ethan@sundance:~/tests/webtemplates/ikiwiki3/wc$ svn commit -m "Blah.." + Sending index.mdwn + Transmitting file data . + Committed revision 3. + + #verifying output was created + ethan@sundance:~/tests/webtemplates/ikiwiki3/wc$ less ../dest/index.html + + ethan@sundance:~/tests/webtemplates/ikiwiki3/wc$ svn info + Path: . + URL: file:///home/ethan/tests/webtemplates/ikiwiki3/svn/trunk + Repository Root: file:///home/ethan/tests/webtemplates/ikiwiki3/svn + Repository UUID: f42bb0d6-3c1e-0410-b2d4-aeaad48dd6c4 + Revision: 2 + Node Kind: directory + Schedule: normal + Last Changed Author: ethan + Last Changed Rev: 2 + Last Changed Date: 2006-09-24 21:15:55 -0400 (Sun, 24 Sep 2006) + +A sample error message (obtained through file redirection) is: + + svn: Working copy '.' locked + svn: run 'svn cleanup' to remove locks (type 'svn help cleanup' for details) + +Did I do something stupid again or is this the case on your system too? +--Ethan + +Additional note: this doesn't happen when performing svn commits from another wc, +but *does* happen when committing from the web. +--Ethan + +> Yeah, this makes sense now that you bring it up. Perhaps I should make +> ikiwiki skip the update when called from the post-commit hook if the repo +> is locked, although this could mask other problems.. --[[Joey]] + +>> I don't think it's (yet) a serious problem, because any commit to the repo +>> either comes from another WC, in which case, no problem, or it is committed by +>> ikiwiki through its own WC, in which case that WC is "the newest". The only problem +>> is that ikiwiki's rcs information for web commits gets screwed up. I think the +>> correct fix is to call rcs_update from rcs_commit in svn.pm, if +>> the commit succeeds. I'm not sure whether this ought to happen for all RCSes +>> or just svn. --Ethan + +>>> You say that the rcs information for web commits is screwed up .. how? +>>> Does this affect something that I'm not seeing? --[[Joey]] + +I just meant that when you call ikiwiki.cgi?do=edit, it gets the +"current" RCS revision, and uses that in the merges later if there +are other edits in the meantime. So I guess if you have a file a.mdwn, +and at revision X it contains the list: + + a + b + c + d + +And then one user edits it by removing "c" from web, and +then starts editing it again, ikiwiki.cgi will think the edit "started" +at revision X (although it's really X+1). So if another user edits via +web in the meantime, the subsequent merge will try to remove "c" again. +To be honest I don't know what will happen in this case (svn merge fails? +conflict markers?), but I'm pretty sure it's a problem. Anyhow, I think we +should call update manually after commit, I just don't know if this should +be RCS-specific, or whether it's safe to update after commit on all RCSes. +--Ethan + +Hmm, turns out that isn't the case! svn's prepedit function calls svn info +which gets the "right" information even when the WC isn't current. I am +having problems merging but that probably has nothing to do with this bug. +[This patch](http://ikidev.betacantrips.com/patches/update.patch) calls +rcs_update after commit in CGI.pm, it might be a good idea anyhow. --Ethan + +> Ok, I follow you. I am unsure whether this problem effects other rcses +> besides svn. Depends on how they handle locking, etc. But calling +> rcs_update will always be safe, so I'll do that. [[bugs/done]] +> +> That still leaves the issue that it calls svn update in the post-commit +> hook when it's locked and fails with that error message. Granted svn does +> throw that away by default, but it's still ugly and wasteful. But +> checking for a lock first is even uglier (and racey) and more wasteful, +> so I don't see a fix.. --[[Joey]] diff --git a/doc/bugs/svn_post-commit_wrapper_can__39__t_find_IkiWiki.pm_if_not_installed.mdwn b/doc/bugs/svn_post-commit_wrapper_can__39__t_find_IkiWiki.pm_if_not_installed.mdwn new file mode 100644 index 000000000..49e956a23 --- /dev/null +++ b/doc/bugs/svn_post-commit_wrapper_can__39__t_find_IkiWiki.pm_if_not_installed.mdwn @@ -0,0 +1,22 @@ +If you're using ikiwiki without installing it, the svn post-commit wrapper will die (in a difficult-to-debug way) when it tries to execute ikiwiki.pl because it can't find IkiWiki.pm. + +I'm not sure how to fix this in a secure way. For now I'm just changing use lib '.' in ikiwiki.pl to point to the hard-coded directory where ikiwiki was unpacked. + +> This workaround doesn't work here. "`./ikiwiki.pl --setup ikiwiki.setup`" is ok, but the +> wrappers fail in action. Using "`FindBin`" seems a solution. Here is a (kinda ugly) +> [patch](http://git.kirkambar.net/?p=ikiwiki.git;a=commitdiff;h=44511c00b98b3efedd4d31f15ea928fcf221401e) +> which also allows you to use `basewiki` + `templates` in the source directory. The patched +> version works fine in my [homepage](http://kirkambar.net). --[[Roktas]] + +New versions of ikiwiki support installation to nonstandard paths, just set +PREFIX to the path when running Makefile.PL, and it will set up ikiwiki to +look in the place it installed the libraries for its perl libraries, etc. + +I don't understand why the wrappers would fail if it were confgured link +that. --[[Joey]] + +> I didn't install it, which was the problem. I'm running ikiwiki from a +> hosting account somewhere so I didn't even try. You're right, it works +> fine if you actually follow the directions. :) --Ethan + +Ok, well, I'll mark this [[bugs/done]] then. --[[Joey]] diff --git a/doc/bugs/syntax_error_in_aggregate.mdwn b/doc/bugs/syntax_error_in_aggregate.mdwn new file mode 100644 index 000000000..1e69e7fab --- /dev/null +++ b/doc/bugs/syntax_error_in_aggregate.mdwn @@ -0,0 +1,11 @@ +Current git : + + $ perl -c IkiWiki/Plugin/aggregate.pm + syntax error at IkiWiki/Plugin/aggregate.pm line 427, near "24;" + IkiWiki/Plugin/aggregate.pm had compilation errors. + +This prevents a Debian package build (due to `t/syntax.t`). + +Not knowing the units being used, I don't know where to add the missing parenthesis. + +[[done]] diff --git a/doc/bugs/syslog_fails_with_non-ASCII_wikinames.mdwn b/doc/bugs/syslog_fails_with_non-ASCII_wikinames.mdwn new file mode 100644 index 000000000..0d40d232a --- /dev/null +++ b/doc/bugs/syslog_fails_with_non-ASCII_wikinames.mdwn @@ -0,0 +1,32 @@ +[[!template id=gitbranch branch=anarcat/dev/syslog_utf8 author="[[anarcat]]"]] + +[[this feature|todo/syslog_should_show_wiki_name]] made it so syslog doesn't work anymore if the site being logged has non-ASCII characters it in. + +Specifically, my wiki was named "CⒶTS", and nothing was showing up in syslog. When I changed that to "C@TS", it worked again. + +My guess is this sits somewhere here: + +[[!format perl """ + return eval { + Sys::Syslog::syslog($type, "[$config{wikiname}] %s", join(" ", @_)); + }; +"""]] + +Yet I am not sure how to fix that kind of problem in Perl... --[[anarcat]] + +> If I remove the "eval" above, I get: +> +> Error: Wide character in syswrite at /usr/lib/perl/5.14/Sys/Syslog.pm line 485. +> +> I have improved a little the error handling in log_message() so that we see *something* when syslog fails, see the branch documented above. I can also confirm that reverting [[todo/syslog_should_show_wiki_name]] fixes the bug. Finally, I have a unit test that reproduces the problem in git, and a working patch for the bug, again in git. +> +> > One last note: I noticed that this problem also happens elsewhere in ikiwiki. For example, the [[plugins/notifyemail]] plugin will silently fail to send notifications if the pages contain unicode. The [[plugins/notifychanges]] plugin I am working on (in [[todo/option to send only the diff in notifyemail]]) seems to be working around the issue so far, but there's no telling which similar problem are out there. + +>> I'd merge it. --[[smcv]] + +>>> I've merged it, but I don't feel it fixes this bug. --[[Joey]] + +>>>> (I removed the patch tag to take it off the patches list.) +>>>> +>>>> What else is needed? Systematic classification of outputs into +>>>> those that do and don't cope with Unicode? --[[smcv]] diff --git a/doc/bugs/table_external_file_links.mdwn b/doc/bugs/table_external_file_links.mdwn new file mode 100644 index 000000000..7b35383c5 --- /dev/null +++ b/doc/bugs/table_external_file_links.mdwn @@ -0,0 +1,9 @@ +If wikilinks are put in an external table file, those links are not seen at +scan time, and so ikiwiki does not know to update the page containing the +table when the pages the links point to change (are added, removed, etc). + +There seem only two solutions to that bug -- either really make wikilinks +in an external table file not work (probably by escaping them), +or run the preprocess code also in scan (expensive!). --[[Joey]] + +[[done]] diff --git a/doc/bugs/table_plugin_does_not_handle___92__r__92__n_lines_in_CSV_files.mdwn b/doc/bugs/table_plugin_does_not_handle___92__r__92__n_lines_in_CSV_files.mdwn new file mode 100644 index 000000000..001407ab8 --- /dev/null +++ b/doc/bugs/table_plugin_does_not_handle___92__r__92__n_lines_in_CSV_files.mdwn @@ -0,0 +1,5 @@ +The table plugin seems to be unable to read a CSV file that uses \r\n for line delimiters. +The same file with \r works fine. The error message is "Empty data". +--liw + +I was seeing this as well on an Ubuntu 11.04 system with Ubuntu 11.04, Perl 5.10.1, IkiWiki 3.20110124ubuntu1, and libtext-csv-perl 1.21-1, all installed from APT. However, when I removed libtext-csv-perl from APT and installed it from CPAN, the problem went away. FWIW, what CPAN grabbed was MAKAMAKA/Text-CSV-1.21.tar.gz. --micahrl diff --git a/doc/bugs/tag_behavior_changes_introduced_by_typed_link_feature.mdwn b/doc/bugs/tag_behavior_changes_introduced_by_typed_link_feature.mdwn new file mode 100644 index 000000000..ed93a2eb7 --- /dev/null +++ b/doc/bugs/tag_behavior_changes_introduced_by_typed_link_feature.mdwn @@ -0,0 +1,16 @@ +The use of typed links for tags and some of the consequent changes +introduced some unwanted functionality variations in the tag system. Two +problems in particular could be observed, when compared to the use of +tags in older versions of IkiWiki: + +* tags in feeds (both rss and atom) would use the file path as their + name (e.g. you would have `<category term="tags/sometag" />` in an atom + item for a page tagged sometag with a tagbase of tags), whereas they + appeared pure before +* tags containing a slash character would appear without the slash + character but be used with the slash character in other circumstances + (effect visible by tagging a page with a name such as "with/slash") + +I've written a [[patch]] to fix this issues by introducing a `tagname()` function that reverts `taglink()`, and it's available [[here|http://sprunge.us/SHRj]] as well as on my [[git|http://git.oblomov.eu/ikiwiki]] + +> [[Applied|done]], with some regexp improvements. --[[Joey]] diff --git a/doc/bugs/tag_plugin:_autotag_vs._staged_changes.mdwn b/doc/bugs/tag_plugin:_autotag_vs._staged_changes.mdwn new file mode 100644 index 000000000..e5526bedf --- /dev/null +++ b/doc/bugs/tag_plugin:_autotag_vs._staged_changes.mdwn @@ -0,0 +1,17 @@ +The autotag functionality of the tag plugin committed (when doing its +first commit) all changes that have been staged (in Git). I suggest it +should be restricted to the specific file only. --[[tschwinge]] + +> This is not specific to the tag plugin. Same can happen +> if you rename a file, or post a comment, or remove a file +> via web interface. All of these use `rcs_commit_staged`. +> +> This is why ikiwiki is supposed to have a checkout of +> the repository that it uses for its own purposes, and nobody else +> should mess with. There are various notes about that being needed here +> and there; you're free to not give ikiwiki its own repo, but you have to +> be aware that it can fight with you if you're making changes to the same +> repo. [[done]] --[[Joey]] + +>> Ack, that is reasonable. (And it's only been a very minor problem +>> during manual testing.) --[[tschwinge]] diff --git a/doc/bugs/tagged__40____41___matching_wikilinks.mdwn b/doc/bugs/tagged__40____41___matching_wikilinks.mdwn new file mode 100644 index 000000000..a211654f1 --- /dev/null +++ b/doc/bugs/tagged__40____41___matching_wikilinks.mdwn @@ -0,0 +1,35 @@ +It may be that I'm simply misunderstanding something, but what is the rationale +for having `tagged()` also match normal wikilinks? + +> It simply hasn't been implemented yet -- see the answer in +> [[todo/tag_pagespec_function]]. Tags and wikilinks share the same +> underlying implementation, although ab reasonable expectation is that +> they are kept separate. --Ivan Z. + +The following situation. I have `tagbase => 'tag'`. On some pages, scattered +over the whole wiki, I use `\[[!tag open_issue_gdb]]` to declare that this page +contains information about an open issue with GDB. Then, I have a page +`/tag/open_issues_gdb.mdwn` that essentially contains `\[[!map +pages="tagged(open_issue_gdb)"]]`. So far, so good: this page indeed does list +all pages that are tagged like this. But now, when I add in `/gdb.mdwn` a link +to this page, like `\[[Open Issues|tag/open_issue_gdb]]`, then `/gdb.mdwn` +itself shows up in the map on `tag/open_issues_gdb.mdwn`. In my understanding +this is due to the wikilink being equal to a `\[[!tag ...]]`. What's the +rationale on this, or what am I doing wrong, and how to achieve what I want? + +--[[tschwinge]] + +> What you are doing "wrong" is putting non-tag pages (i.e. +> `/tag/open_issues_gdb.mdwn`) under your tagbase. The rationale for +> implementing tag as it has been, I think, is one of simplicity and +> conciseness. -- [[Jon]] + +>> No, he has no pages under tagbase that aren't tags. This bug +>> is valid. [[todo/matching_different_kinds_of_links]] is probably +>> how it will eventually be solved. --[[Joey]] + +>>> [[Done]]: `tagged` no longer matches other wikilinks. --[[smcv]] + +> And this is an illustration why a clean work-around (without changing the software) is not possible: while thinking about [[todo/matching_different_kinds_of_links]], I thought one could work around the problem by simply explicitly including the kind of the relation into the link target (like the tagbase in tags), and by having a separate page without the "tagbase" to link to when one wants simply to refer to the tag without tagging. But this won't work: one has to at least once refer to the real tag page if one wants to talk about it, and this reference will count as tagging (unwanted). --Ivan Z. + +> But well, perhaps there is a workaround without introducing different kinds of links. One could modify the [[tag plugin|plugins/tag]] so that it adds 2 links to a page: for tagging -- `tagbase/TAG`, and for navigation -- `tagdescription/TAG` (displayed at the bottom). Then the `tagdescription/TAG` page would hold whatever list one wishes (with `tagged(TAG)` in the pagespec), and whenever one wants to merely refer to the tag, one should link to `tagdescription/TAG`--this link won't count as tagging. So, `tagbase/TAG` would become completely auxiliary (internal) link targets for ikiwiki, the users would edit or link to only `tagdescription/TAG`. --Ivan Z. diff --git a/doc/bugs/tags__44___backlinks_and_3.x.mdwn b/doc/bugs/tags__44___backlinks_and_3.x.mdwn new file mode 100644 index 000000000..4fe9a4723 --- /dev/null +++ b/doc/bugs/tags__44___backlinks_and_3.x.mdwn @@ -0,0 +1,34 @@ +I think there might be an issue in the backlinks calculation in ikiwiki 3.04. + +I've just migrated to 3.04. In doing so, the following pagespec + +> "log/* and !link(tag/aggregation) and !link(tag/draft) and !*/Discussion" + +...started matching pages which contained + +> \[\[!template draft\]\] + +The page templates/draft.mdwn contains (amongst some markup) + +> \[\[!tag draft \]\] + +Prior to migration, the pagespec definitely took effect post-transclusion. + +An example: <http://jmtd.net/log/too_much_debconf_a_bad_thing/> contains the +template inclusion, which can be seen to have worked due to markup at the +bottom of the page. It even includes a "Tags: draft" link at the bottom. + +Strangely, <http://jmtd.net/tag/draft/> does not contain backlinks to pages +which are tagged using the procedure above. + +After the first rebuild, it's broken, after a subsequent refresh, it is fixed. +I've reproduced this twice (but assumed I'd done something wrong the first +time, so went ahead and migrated live, spamming planet debian in the process +:(). I will try and put together a testcase. -- [[users/Jon]], 2009/02/17 + +> Looks like the same problem as +> [[cannot_reliably_use_meta_in_template]]. AFAIK, this has never worked +> reliably, although the linked page has a simple, though potentially +> expensive fix. --[[Joey]] + +> fix made, [[done]] --[[Joey]] diff --git a/doc/bugs/tags_base_dir_not_used_when_creating_new_tags.mdwn b/doc/bugs/tags_base_dir_not_used_when_creating_new_tags.mdwn new file mode 100644 index 000000000..f2243ab2d --- /dev/null +++ b/doc/bugs/tags_base_dir_not_used_when_creating_new_tags.mdwn @@ -0,0 +1,43 @@ +I'm using the tags plugin with tagbase="tags". + +Already existing tags, corresponding to pages like tags/foo.html work just +fine. + +If I add to a page a tag which is not existing (e.g. with [[!tag newtag]]) +the just modified page will have a link which point to tags/newtag. This is +in theory correct, but in practice leads to creating a tags/newtag subpage +of the page I'm editing, while my tagbase is supposed to be relative to the +wiki root. + +When used in a wiki which already have some tags this leads to mixing up +tags located in tags/ and tags located in whatever/tags/. + +> When a new page is being edited, ikiwiki lets you chose where the page +> will be created, so you'll get a dropdown list of possible locations for +> the tag page. You should be able to choose between either tags/foo or +> page/tags/foo. +> +> The way that ikiwiki decides which location to default to in this box is +> fairly involved; but in general it will default to creating the page at +> the same level as the tagged page. So if the tag is on any toplevel page +> in the wiki, it will default to creating `tags/foo`; if the tag is on a +> page in a subdirectory, it will default to creating subdir/tags/foo. +> +> I personally like this behavior; it allows me to create a subdirectory +> for a particular thing and use tags that are specific to that thing, +> which are kept confined to that subdirectory by default. For example, +> this is used for ikiwiki's own plugins tags, which are all located +> under plugins/type/* and which apply to pages under plugins/*. +> +> It's clearly not the right default for every situation though. Explcitly +> setting a tagbase probably lessons the likelyhood that it's the right +> default for things under that tag base. I'd not be opposed to adding a +> special case to change the default in this case, or adding a +> configuration option to change the default globally. On the other hand, +> it is pretty simple to just check the location and select the right one +> from the list when creating a new page.. +> +> --[[Joey]] + +> And, this is [[done]], creating tags with tagbase will put them under the +> tagbase, unless the tag name starts with "/". --[[Joey]] diff --git a/doc/bugs/taint_and_-T.mdwn b/doc/bugs/taint_and_-T.mdwn new file mode 100644 index 000000000..21ef17673 --- /dev/null +++ b/doc/bugs/taint_and_-T.mdwn @@ -0,0 +1,30 @@ +By default, tflag is not defined. But ikiwiki.in has -T causing build failure: + +perl -Iblib/lib ikiwiki.out -libdir . -setup docwiki.setup -refresh +"-T" is on the #! line, it must also be used on the command line at ikiwiki.out +line 1. + +> pm_filter removes the -T from ikiwiki.in when generating ikiwiki.out +> unless NOTAINT=0 is set. I cannot reproduce your problem. --[[Joey]] + +>> Thanks. Now I see. NetBSD and DragonFly and several other systems don't have /usr/bin/perl so that path is replaced in the sh-bang lines of various scripts. So it doesn't match in the pm_filter expression. Can you please consider providing a variable or not matching on that assumed path to perl. + + --- pm_filter.orig 2008-04-28 07:59:58 -0700 + +++ pm_filter 2008-04-28 08:01:21 -0700 + @@ -20,6 +20,6 @@ + $_="use lib '$libdir';\n"; + } + } + -elsif ($. == 1 && ($ENV{NOTAINT} || ! exists $ENV{NOTAINT}) && m{^(#!/usr/bin/perl) -T$}) { + +elsif ($. == 1 && ($ENV{NOTAINT} || ! exists $ENV{NOTAINT}) && m{^(#!.*) -T$}) { + $_=qq{$1\n}; + } + +>> --[[JeremyReed]] + +>> I could look for "#!.*perl -T", if that would work. #!.*-T is perhaps +>> over-broad. --[[Joey]] + +>>> Yes, being more precise should be fine. Note that some may have bin/perl5 or bin/perl5.8.8 for example, so please consider optional number, like ^(#!/.*/perl[0-9]*.*) -T$ or something like that. + +[[done]] diff --git a/doc/bugs/taint_issue_with_regular_expressions.mdwn b/doc/bugs/taint_issue_with_regular_expressions.mdwn new file mode 100644 index 000000000..172b49fd1 --- /dev/null +++ b/doc/bugs/taint_issue_with_regular_expressions.mdwn @@ -0,0 +1,35 @@ +Built from 2.1.17 source, works fine on commandline, but not working from CGI wrapper. Traced problem to regular expressions failing to match, specifically in contexts like the following in Render.pm: + + my ($f)=/$config{wiki_file_regexp}/; # untaint + +It works if I replace it with: + + my ($f)=/(^[-[:alnum:]_.:\/+]+$)/; # untaint + +which is exactly the same regular expression drawn out as a constant. It appears that %config gets some tainted data and is itself being marked entirely tainted, which may prevent using regular expressions contained in it for untainting other data. I'm using Perl 5.8.8. + +> How could `%config` possible get tainted? That would be a major security +> hole. It seems more likely that perl containes to have taint flag bugs +> even in 5.8. See also: [[prune_causing_taint_mode_failures]], +> [[Insecure_dependency_in_mkdir]], +> [[Insecure_dependency_in_eval_while_running_with_-T_switch]], +> and especially [[!debbug 411786]] +> +> The last of those was the last straw for me, and I disabled taint +> checking in the debian package. You can do the same by building ikiwiki +> with NOTAINT=1. :-( --[[Joey]] + +---------------- +Continuing to dig into the problem I reported, it may not be taint after all. Running strings on the ikiwiki.cgi wrapper, I see stuff like: + + 'wiki_file_regexp' => bless( do{\(my $o = undef)}, 'Regexp' ) + +without any payload of the actual regexp, and that would also certainly also have the observed effect of the regexps being completely broken while running in CGI mode. This seems to implicate Data::Dumper (2.101). After upgrading Data::Dumper to 2.121 I get: + + 'wiki_file_regexp' => qr/(?-xism:(^[-[:alnum:]_.:\/+]+$))/ + +This would call for at most an installation prerequisite of Data::Dumper >= 1.121. A look at the module's changelog shows that no intervening versions were actually released, so 1.121 would be the minimal good one. + +> You must have a very old version of perl there. This seems to be a bug in +> data dumper before 2.11, which didn't properly dump q// objects. Prereq +> added, [[done]] --[[Joey]] diff --git a/doc/bugs/tbasewiki__95__brokenlinks.t_broken.mdwn b/doc/bugs/tbasewiki__95__brokenlinks.t_broken.mdwn new file mode 100644 index 000000000..db3917d21 --- /dev/null +++ b/doc/bugs/tbasewiki__95__brokenlinks.t_broken.mdwn @@ -0,0 +1,60 @@ +t/basewiki_brokenlinks.t was failing with the following error: + + t/basewiki_brokenlinks.....Can't locate IkiWiki.pm in @INC (@INC contains: /etc/perl /usr/lib/perl5/vendor_perl/5.8.8/i686-linux + /usr/lib/perl5/vendor_perl/5.8.8 /usr/lib/perl5/vendor_perl /usr/lib/perl5/site_perl/5.8.8/i686-linux /usr/lib/perl5/site_perl/5.8.8 + /usr/lib/perl5/site_perl /usr/lib/perl5/5.8.8/i686-linux /usr/lib/perl5/5.8.8 /usr/local/lib/site_perl) at ./ikiwiki.out line 9. + +When ikiwiki.out is executed the 'blib/lib' directory isn't inherited by the child process. I can add "use lib 'blib/lib'" to ikiwiki.out easily enough, but I can't figure out how to add it to ikiwiki.in so that pm_filter doesn't strip it out. + +Anyway, once the 'use lib' is added I get the following error: + + t/basewiki_brokenlinks.....ok 1/3Can't locate object method "new" via package "HTML::Template" at blib/lib/IkiWiki.pm line 858. + +After some digging I found that HTML::Template is being required after the new statement, again, easily fixed: + + Index: IkiWiki.pm + =================================================================== + --- IkiWiki.pm (revision 3724) + +++ IkiWiki.pm (working copy) + @@ -842,7 +842,6 @@ + return ""; + } + + - require HTML::Template; + my @ret=( + filter => sub { + my $text_ref = shift; + @@ -857,6 +856,7 @@ + } + + sub template ($;@) { + + require HTML::Template; + HTML::Template->new(template_params(@_)); + } + +**That** gave me: + + t/basewiki_brokenlinks.....ok 1/3HTML::Template->new called with multiple (or no) template sources specified! A valid call to new() has exactly one filename => 'file' OR exactly one scalarref => \$scalar OR exactly one arrayref => \@array OR exactly one filehandle => *FH at blib/lib/IkiWiki.pm line 858 + +After some step through I figured out that the template directory was invalid, again easily fixed: + + Index: t/basewiki_brokenlinks.t + =================================================================== + --- t/basewiki_brokenlinks.t (revision 3724) + +++ t/basewiki_brokenlinks.t (working copy) + @@ -4,6 +4,6 @@ + use Test::More tests => 3; + + ok(! system("make ikiwiki.out")); + -ok(! system("PERL5LIB=. ./ikiwiki.out -plugin brokenlinks -rebuild -underlaydir=basewiki t/basewiki_brokenlinks t/basewiki_brokenlinks/out")); + +ok(! system("PERL5LIB=. ./ikiwiki.out -plugin brokenlinks -rebuild -underlaydir=basewiki -templatedir=templates t/basewiki_brokenlinks t/basewiki_brokenlinks/out")); + ok(`grep 'no broken links' t/basewiki_brokenlinks/out/index.html`); + system("rm -rf t/basewiki_brokenlinks/out t/basewiki_brokenlinks/.ikiwiki"); + +Other than ikiwiki.in, am I missing something here? + +>> I think this is [[!debbug 425891]]. I have sent there a patch that incorporates the original +>> author's two diffs but has a more correct solution to the first problem described +>> above. -- Thomas, 2007-06-26 + +[[done]] diff --git a/doc/bugs/tbasewiki__95__brokenlinks.t_broken/discussion.mdwn b/doc/bugs/tbasewiki__95__brokenlinks.t_broken/discussion.mdwn new file mode 100644 index 000000000..7c20eb3c3 --- /dev/null +++ b/doc/bugs/tbasewiki__95__brokenlinks.t_broken/discussion.mdwn @@ -0,0 +1,2 @@ +For what it's worth: I encounter exactly the same issues when building and +testing ikiwiki 2.1 on NetBSD/i386 3.1. \ No newline at end of file diff --git a/doc/bugs/templateForRecentChangesMissingCloseSpan.mdwn b/doc/bugs/templateForRecentChangesMissingCloseSpan.mdwn new file mode 100644 index 000000000..5c322991a --- /dev/null +++ b/doc/bugs/templateForRecentChangesMissingCloseSpan.mdwn @@ -0,0 +1,26 @@ +In the template for ikiwiki's recent changes page + + /usr/share/ikiwiki/templates/change.tmpl + +there is a missing </span> tag after the + + <span class="changedate"><TMPL_VAR COMMITDATE> + +This results in the recentchanges/ page being invalid and rendering quite horrifyingly in Internet Exploder. + +[I'm running](http://wiki.shlrm.org) (linked so you can see the one I'm running if you need to) the latest version of ikiwiki, and I note that it's broken on [ikiwiki.info](http://validator.w3.org/check?uri=http%3A%2F%2Fikiwiki.info%2Frecentchanges%2F&charset=%28detect+automatically%29&doctype=Inline&group=0&user-agent=W3C_Validator%2F1.767) too :) + +[This one on debian](https://www.icanttype.org/recentchanges/) is somehow [valid](http://validator.w3.org/check?uri=https%3A%2F%2Fwww.icanttype.org%2F%2Frecentchanges%2F&charset=%28detect+automatically%29&doctype=Inline&group=0&user-agent=W3C_Validator%2F1.767), although it's using the same template. Perhaps there's an additional scrubbing going on his end. + +Thanks, +David + +PS: I have fixed the template by hand on my server, so it will validate, however ikiwiki.info will not. + +> [[!template id="gitbranch" branch=smcv/trivia author="[[smcv]]"]] [[!tag patch]] +> Enabling either [[plugins/htmltidy]] or [[plugins/htmlbalance]] will automatically fix unbalanced +> markup like this; using [[plugins/comments]] without having one or other of those is a bad idea +> from the point of view of avoiding comment forgery, which is probably why icanttype.org works +> correctly. Anyway, I've fixed this in a branch: Joey, care to review smcv/trivia? --[[smcv]] + +[[done]], thanks guys --[[Joey]] diff --git a/doc/bugs/template__95__syntax_test_is_incomplete.mdwn b/doc/bugs/template__95__syntax_test_is_incomplete.mdwn new file mode 100644 index 000000000..d50b727e8 --- /dev/null +++ b/doc/bugs/template__95__syntax_test_is_incomplete.mdwn @@ -0,0 +1,10 @@ +[[!template id=gitbranch branch=smcv/ready/template-syntax-test + browse="http://git.pseudorandom.co.uk/smcv/ikiwiki.git/shortlog/refs/heads/ready/template-syntax-test" + author="[[smcv]]"]] +[[!tag patch]] + +`t/template_syntax.t` looks as though it's meant to check the syntax of +`doc/templates/*.mdwn` as well as `templates/*.tmpl`, but it doesn't. +Patch in my git repository. --[[smcv]] + +> [[merged|done]] --[[Joey]] diff --git a/doc/bugs/template_creation_error.mdwn b/doc/bugs/template_creation_error.mdwn new file mode 100644 index 000000000..33a863ec5 --- /dev/null +++ b/doc/bugs/template_creation_error.mdwn @@ -0,0 +1,272 @@ +Hi, +I am trying to build a template. The compilation of this template results in a weird exception. I have isolated the cause of the exception to the following point: + +If i have this in the template code: + +\[[!inline<br/> +pages="\<TMPL_VAR SEL_PAGES\>"<br/> +template=extract-entry<br/> +\]]<br/> + +There is no problem at all. I can use the template with the desired result. But if I try to use this (just adding the "show" parameter): + +\[[!inline <br/> +pages="\<TMPL_VAR SEL_PAGES>"<br/> +template=extract-entry<br/> +show=\<TMPL_VAR CNTPG><br/> +\]]<br/> + +I get this exception on the Git bash console: + +<pre> +$ git push +Counting objects: 7, done. +Delta compression using up to 8 threads. +Compressing objects: 100% (4/4), done. +Writing objects: 100% (4/4), 410 bytes, done. +Total 4 (delta 3), reused 0 (delta 0) +remote: From /home/b-odelama-com/source +remote: eb1421e..5e1bac5 master -> origin/master +remote: Argument "\x{3c}\x{54}..." isn't numeric in numeric lt (<) at /usr/share/perl5/IkiWiki/Plugin/inline.pm line 231. +remote: Argument "\x{3c}\x{54}..." isn't numeric in numeric lt (<) at /usr/share/perl5/IkiWiki/Plugin/inline.pm line 231. +To ssh://b-odelama-com@odelama-com.branchable.com/ + eb1421e..5e1bac5 master -> master +</pre> + +Please, let me know what to do to avoid this kind of error. + +> When you add a template page `templates/foo.mdwn` for use +> the [[ikiwiki/directive/template]] directive, two things happen: +> +> 1. `\[[!template id=foo ...]]` becomes available; +> 2. a wiki page `templates/foo` is built, resulting in a HTML file, +> typically `templates/foo/index.html` +> +> The warnings you're seeing are the second of these: when ikiwiki +> tries to process `templates/foo.mdwn` as an ordinary page, without +> interpreting the `<TMPL_VAR>` directives, `inline` receives invalid +> input. +> +> This is a bit of a design flaw in [[plugins/template]] and +> [[plugins/edittemplate]], I think - ideally it would be possible to +> avoid parts of the page being interpreted when the page is being +> rendered normally rather than being used as a template. +> +> There *is* a trick to avoid parts of the page being interpreted when +> the page is being used as a template, while having them appear +> when it's rendered as a page: +> +> <TMPL_IF FALSE> +> <!-- This part only appears when being used as a page. +> It assumes that you never set FALSE to a true value :-) --> +> \[[!meta robots="noindex,nofollow"]] +> This template is used to describe a thing. Parameters: +> * name: the name of the thing +> * size: the size of the thing +> </TMPL_IF> +> +> The thing is called <TMPL_VAR name> and its size is <TMPL_VAR size> +> +> I suppose you could maybe extend that to something like this: +> +> <TMPL_IF FALSE> +> <!-- This part only appears when being used as a page. +> It assumes that you never set FALSE to a true value :-) --> +> \[[!meta robots="noindex,nofollow"]] +> This template is used to describe a thing. Parameters: +> * name: the name of the thing +> * size: the size of the thing +> </TMPL_IF> +> +> <TMPL_IF FALSE> +> \[[!if test="included() and !included()" then=""" +> </TMPL_IF> +> <!-- This part only appears when being used as a template. It also +> assumes that you never set FALSE to a true value, and it +> relies on the [[ikiwiki/pagespec]] "included() and !included()" +> never being true. --> +> The thing is called <TMPL_VAR name> and its size is <TMPL_VAR size> +> <TMPL_IF FALSE> +> """]] +> </TMPL_IF> +> +> but that's far harder than it ought to be! +> +> Perhaps the right solution would be to change how the template plugin +> works, so that templates are expected to contain a new `definetemplate` +> directive: +> +> This template is used to describe a thing. Parameters: +> * name: the name of the thing +> * size: the size of the thing +> +> \[[!definetemplate """ +> The thing is called <TMPL_VAR name> and its size is <TMPL_VAR size> +> """]] +> +> with templates not containing a `\[[!definetemplate]]` being treated +> as if the whole text of the page was copied into a `\[[!definetemplate]]`, +> for backwards compatibility? +> +> --[[smcv]] + +>> OK, here is a branch implementing what I said. It adds the `definetemplate` +>> directive to [[plugins/goodstuff]] as its last commit. +>> +>> Templates with the current strange semantics will still work, until +>> IkiWiki breaks compatibility. +>> +>> Possible controversies: +>> +>> * Should the `definetemplate` plugin be core, or in goodstuff, or neither? +>> +>> * Should \[[!definetemplate]] be allowed on any page (with the implementation +>> of `template("foo")` looking for a `definetemplate` in `templates/foo`, +>> then a `definetemplate` in `foo`, then fall back to the current logic)? +>> If not, should \[[!definetemplate]] raise an error when used on a page not +>> in `templates/`, since it will have no practical effect there? +>> +>> * Is it OK to rely on `definetemplate` being enabled in the basewiki's +>> templates? +>> +>> * Should the "use definetemplate" wording in the documentation of +>> template and edittemplate be stronger? Should those plugins automatically +>> load definetemplate? +>> +>> --[[smcv]] + +>>> this looks like a good idea to me. +>>> +>>> * i'd put it in core, and add a transition for the time compatibility gets +>>> broken, provided the transitioning system will be used in that. templates +>>> can't be expected to just work as markdown+ikiwiki too. +>>> +>>> (it being in core would also solve my qualms about `section => "web"` / +>>> `\[[!tag type/web]]`). +>>> +>>> * if definetemplate gets deemed core, no "use definetemplate!" notes on the +>>> template/edittemplate pages will be required any more. +>>> +>>> * first i was sceptical of the approach of re-running scan to make sure the +>>> `my %templates` is filled, but it is indeed a practical solution. +>>> +>>> * the name "`definetemplate`" gives me the first impression that something +>>> is assigned (as in `#define`), but actually it highlights a region in the +>>> file. wouldn't "`templatebody`" be a better description of the meaning of +>>> the directive? +>>> +>>> --[[chrysn]] + +>>>> Thanks for your feedback! +>>>> Looking at its description on this wiki, I agree that `type/web` doesn't +>>>> fit, and core does seem better. I like your `templatebody` suggestion, +>>>> too, particularly if templates remain restricted to `/templates`. +>>>> I'll try to come up with better wording for the documentation to say +>>>> "use `templatebody`, like this", with a note about backwards +>>>> compatibility later. +>>>> +>>>> Rationale for `my %templates`: yes it does seem a bit odd, but +>>>> if I used `$pagestate{$tpage}{template}` instead of a `my` variable, +>>>> I'd sometimes _still_ have to force a `scan`, because +>>>> [[plugins/template]] has to expand the template at scan time so that +>>>> it can contain links etc. - so I have to make sure that if the +>>>> template has changed, it has already been scanned (scanning happens +>>>> in random order, so that can't be guaranteed). This means there's +>>>> no benefit in reading it back from the index, so it might as well +>>>> just be in-memory. +>>>> +>>>> I suppose an alternative way to do it would be to remember what was +>>>> passed to `needsbuild`, and only force a `scan` for templates that +>>>> were in that list - which potentially reduces CPU time and I/O a +>>>> little, in exchange for a bigger index. I could do that if Joey +>>>> wants me to, but I think the current approach is simpler, +>>>> so I'll stick with the current approach if it isn't vetoed. +>>>> --[[smcv]] + +>>>>> @name: even outside `/templates`, `\[[!templatebody]]` would be +>>>>> interpreted as "when this page is used as a template, this is what its +>>>>> contents should be", and be suitable. +>>>>> +>>>>> @`%templates`: my surprise wasn't to it not being in `%pagestate`, but +>>>>> rather that the `scan` function was used for it at all, rather than plain +>>>>> directive parsing that ignores everything else -- but i agree that it's +>>>>> the right thing to do in this situation. +>>>>> +>>>>> --[[chrysn]] + +---- + +[[!template id=gitbranch author="[[smcv]]" branch=smcv/ready/templatebody + browse=http://git.pseudorandom.co.uk/smcv/ikiwiki.git/shortlog/refs/heads/ready/templatebody]] +[[!tag patch users/smcv/ready]] +Branch and directive renamed to `ready/templatebody` as chrysn suggested. +It's on-by-default now (or will be if that branch is merged). +Joey, any chance you could review this? + +There is one known buglet: `template_syntax.t` asserts that the entire +file is a valid HTML::Template, whereas it would ideally be doing the +same logic as IkiWiki itself. I don't think that's serious. --[[smcv]] + +> Looking over this, I notice it adds a hash containing all scanned +> files. This seems to me to be potentially a scalability problem on +> rebuild of a site with many pages. Ikiwiki already keeps a lot +> of info in memory, and this adds to it, for what is a fairly +> minor reason. It seems to me there should be a way to avoid this. --[[Joey]] + +>> Maybe. Are plugins expected to cope with scanning the same +>> page more than once? If so, it's just a tradeoff between +>> "spend more time scanning the template repeatedly" and +>> "spend more memory on avoiding it", and it would be OK to +>> omit that, or reduce it to a set of scanned *templates* +>> (in practice that would mean scanning each template twice +>> in a rebuild). --s +>>> [Commit f7303db5](http://source.ikiwiki.branchable.com/?p=source.git;a=commitdiff;h=f7303db5) +>>> suggests that scanning the same page more than once is problematic, +>>> so that solution is probably not going to work. +>>> +>>> The best idea I've come up with so far is to track whether +>>> we're in the scan or render phase. If we're in the scan +>>> phase, I think we do need to keep track of which pages +>>> we've scanned, so we don't do them again? (Or perhaps that's +>>> unnecessary - commit f7303db5 removed a scan call that's in +>>> the render phase.) If we're in the render phase, we can assume +>>> that all changed pages have been scanned already, so we can +>>> drop the contents of `%scanned` and rely on a single boolean +>>> flag instead. +>>> +>>> `%scanned` is likely to be no larger than `%rendered`, which +>>> we already track, and whose useful lifetime does not overlap +>>> with `%scanned` now. I was tempted to merge them both and call +>>> the result `%done_in_this_phase`, but that would lead to really +>>> confusing situations if a bug led to `render` being called sooner +>>> than it ought to be. +>>> +>>> My ulterior motive here is that I would like to formalize +>>> the existence of different phases of wiki processing - at the +>>> moment there are at least two phases, namely "it's too soon to +>>> match pagespecs reliably" and "everything has been scanned, +>>> you may use pagespecs now", but those phases don't have names, +>>> so [[plugins/write]] doesn't describe them. +>>> +>>> I'm also considering adding warnings +>>> if people try to match a pagespec before scanning has finished, +>>> which can't possibly guarantee the right result, as discussed in +>>> [[conditional_preprocess_during_scan]]. My `wip-too-soon` branch +>>> is a start towards that; the docwiki builds successfully, but +>>> the tests that use IkiWiki internals also need updating to +>>> set `$phase = PHASE_RENDER` before they start preprocessing. --s + +>>>> reviewing those modifications, i think this is a good way to go. along +>>>> with warning about pagespecs evaluated in scan phase, i think it should be +>>>> an error to invoke scan in the render phase; that would mean that +>>>> `readtemplate` needs to check whether it's invoked as a scan or not to +>>>> decide whether to scan the template page, but would be generally more +>>>> robust for future plugin writing. +>>>> +>>>> **addendum**: if the new phase state is used to create warnings/errors +>>>> about improper ikiwiki api use of plugins (which is something i'd +>>>> advocate), that should likewise warn if `add_link` actually adds a link in +>>>> the render phase. such a warning would have helped spotting the +>>>> link-related [[template evaluation oddities]] earlier. --[[chrysn]] + +>>>>> [[Merged|done]] --[[smcv]] diff --git a/doc/bugs/template_evaluation_oddities.mdwn b/doc/bugs/template_evaluation_oddities.mdwn new file mode 100644 index 000000000..06ef57375 --- /dev/null +++ b/doc/bugs/template_evaluation_oddities.mdwn @@ -0,0 +1,67 @@ +[[ikiwiki/directive/template]]s expose odd behavior when it comes to composing +links and directives: + +* the parameters are passed through the preprocessor twice, once on + per-parameter basis and once for the final result (which usually contains the + preprocessed parameters). + + one of the results it that you have to write: + + \[[!template id="infobox" body=""" + Just use the \\\[[!template]] directive! + """]] + + (that'd be three backslashes in front of the opening [.) + + <!-- if you read this and wonder why there are only three backslashes in the + source code too, look at how backslash-escaping directives is implemented. + --> + + this also means that parts which are not used by the template at all still + have their side effects without showing. + + furthermore, the evaluation sequence is hard to predict. this might or might + not be a problem, depending on whether someone comes up with a less contrived + example (this one assumes a ``\[[!literal value]]`` directive that just + returns value but protects it from the preprocessor): + + we can use `\[[!literal """[[!invalid example]]"""]]`, but we can't use + `\[[!template id=literalator value="""[[!invalid example]]"""]]` with a + 'literalator' template `<span class="literal">\[[!literal """<TMPL_VAR + value>"""]]</span>` because then the `invalid` directive comes to action in + the first (per-argument) preprocessor run + +* links in templates are not stored at all; they appear, but the backlinks + don't work unless the link is explicit in one of the arguments. + + \[[!template id="linker" destination="foo"]] + + with a 'linker' template like + + Go to \[[<TMPL_VAR destination>]]! + + would result in a link to 'destination', but would not be registered in the + scan phase and thus not show a backlink from 'foo'. + + (a ``\[[!link to=...]]`` directive, as suggested in + [[todo/flexible relationships between pages]], does get evaluated properly + though.) + + this seems to be due to linkification being called before preprocess rather + than as a part of it, or (if that is on purpose) by the template plugin not + running linkification as an extra step (not even once). + +(nb: there is a way to include the ``raw_`` value of a directive, but that only +refers to htmlification, not directive evaluation.) + +both those behaviors are non-intuitive and afaict undocumented. personally, i'd +swap them out for passing the parameters as-is to the template, then running +the linkifier and preprocessor on the final result. that would be as if all +parameters were queried `raw_` -- then again, i don't see where `raw_` makes +anything not work that worked originally, so obviously i'm missing something. + + +i think it boils down to one question: are those behaviors necessary for +compatibility reasons, and if yes, why? + +--[[chrysn]] diff --git a/doc/bugs/teximg_does_not_work_Preview.mdwn b/doc/bugs/teximg_does_not_work_Preview.mdwn new file mode 100644 index 000000000..1900ac299 --- /dev/null +++ b/doc/bugs/teximg_does_not_work_Preview.mdwn @@ -0,0 +1,12 @@ +Using ikiwiki 2.6.1 package with git 1.5.3.1 backend in Debian. + +The teximg plugin creates .png and .log files in $basedir/teximg/ even in Preview mode. This causes "File foo independently created, not overwriting with version from page bar"-errors from the will_render()-function, when repeatedly clicking "Preview" or trying to save the page after a preview. + +In my opinion there are two ways to fix this cleanly: + +1. change the plugin: do not create any files when rendering a preview. Instead, inline the images as base64-encoded like the graphviz-plugin. Disadvantage is a very slow preview if it contains a lot of latex. + +2. provide a clean way for plugins to create additional files even for previews. This files can be removed when the "Save Page" button is clicked or on the next page view, for example. On this instance one might also reconsider putting all tex-images into one folder and naming them after their md5-cksum. The hashspace may be large, but not infinite. The technically ingenuous user might not be able to handle cross-page Hash-collisions. + +Preview issue [[fixed|done]] (but see +[[teximg_fails_if_same_tex_is_used_on_multiple_pages]]) --[[Joey]] diff --git a/doc/bugs/teximg_fails_if_same_tex_is_used_on_multiple_pages.mdwn b/doc/bugs/teximg_fails_if_same_tex_is_used_on_multiple_pages.mdwn new file mode 100644 index 000000000..700492345 --- /dev/null +++ b/doc/bugs/teximg_fails_if_same_tex_is_used_on_multiple_pages.mdwn @@ -0,0 +1,24 @@ +If the same teximg is put on multiple pages, the second one will fail: + +Error: /home/joey/html//teximg/3eb2b61be1e909df9008a499863eec90.png independently created, not overwriting with version from pics + +Ikiwiki doesn't support the concept of two different pages owning the same +file; only one page can own a file. I don't see a good way around that, +w/o large changes to ikiwiki. + +This could be fixed by making the teximg directory be a subdirectory +of the page containing the image. I seem to remember suggesting this to +winnie, and I forget why it wasn't done.. maybe because the same teximg +on multiple pages was expected to work, and as an optimisation for that case? +--[[Joey]] + +---- +At first the plugin doesn't use the writefile etc. functions of ikiwiki, but uses own ones (so the created img wasn't owned by any page). +Then this setup of course works. + +After switching to the ikiwiki functions it seems so that I doesn't test this again... sorry a error of mine. I'll work out a fix for this. +I think this will be a own dir for images for every page. + +--[[PatrickWinnertz]] + +[[!tag done]] diff --git a/doc/bugs/textile_plugin_dies_if_input_has_a_non-utf8_character.mdwn b/doc/bugs/textile_plugin_dies_if_input_has_a_non-utf8_character.mdwn new file mode 100644 index 000000000..bdd07210e --- /dev/null +++ b/doc/bugs/textile_plugin_dies_if_input_has_a_non-utf8_character.mdwn @@ -0,0 +1,14 @@ + 20:03:56$ ikiwiki --setup *setup --rebuild + successfully generated /home/jon/git/ikiwiki/hooks/post-update + utf8 "\x92" does not map to Unicode at /usr/share/perl5/IkiWiki.pm line 320, <$in> chunk 1. + utf8 "\x92" does not map to Unicode at /usr/share/perl5/IkiWiki.pm line 320, <$in> chunk 1. + ikiwiki.setup: Malformed UTF-8 character (fatal) at /usr/share/perl5/Text/Textile.pm line 775. + BEGIN failed--compilation aborted at (eval 6) line 166. + +The first two complaints happen if textile is not loaded, the third fatal one happens if it is. + +0x92 is "single quote" in the evil windows default codepage. It would be nice to handle this gracefully and not abort ikiwiki at this point, or alternatively, die fatally but mention which input page caused the error. + +Interestingly enough, in my case, the input file has several other bad windows characters (0xFC, u-umlaut) which have not caused ikiwiki to abort. ikiwiki version 2.50. -- [[users/Jon]] + +> Fixed in git. [[done]] --[[Joey]] diff --git a/doc/bugs/the_login_page_is_unclear_when_multiple_methods_exist.mdwn b/doc/bugs/the_login_page_is_unclear_when_multiple_methods_exist.mdwn new file mode 100644 index 000000000..70266c49c --- /dev/null +++ b/doc/bugs/the_login_page_is_unclear_when_multiple_methods_exist.mdwn @@ -0,0 +1,16 @@ +When multiple login methods are enabled, the ikiwiki login page lists one form per method, e.g. + + * one for openid + * one for local user/password store + +Followed by the "login" button underneath. It's not obvious to anyone unfamiliar with the software that these are distinct forms, or that there are multiple ways of logging in, etc. -- [[Jon]] + +> As discussed in [[login_page_non-obvious_with_openid]], +> architectural reasons disallow multiple forms, with multiple +> submit buttons. But the default style sheet includes +> a styling for the openid portion of the form that makes +> it visually distinct from the rest of the form. I'm sure the styling +> could be improved, but the current form does not seem too non-obvious +> to me, or to naive users in the field. --[[Joey]] + +>> [[done]], better fixed by new fancy openid login form. --[[Joey]] diff --git a/doc/bugs/title__40____41___in_a_PageSpec__44___with_meta_enabled__44___causes_a_crash.mdwn b/doc/bugs/title__40____41___in_a_PageSpec__44___with_meta_enabled__44___causes_a_crash.mdwn new file mode 100644 index 000000000..8dc78a4a9 --- /dev/null +++ b/doc/bugs/title__40____41___in_a_PageSpec__44___with_meta_enabled__44___causes_a_crash.mdwn @@ -0,0 +1,3 @@ +When the meta plugin is enabled, use of the title() predicate in a [[PageSpec]] fails with "Undefined subroutine &IkiWiki::Plugin::meta::pagetitle called". The [[patch]] is to replace "pagetitle" with "IkiWiki::pagetitle" in the meta plugin, as in [this git commit](http://git.debian.org/?p=users/smcv/ikiwiki.git;a=commit;h=1f26a1bf1655b1d0223b24ba1db70579a3774eb1) (git://git.debian.org/git/users/smcv/ikiwiki.git, branch=master, commit=1f26a). + +[[done]] thanks! diff --git a/doc/bugs/toc_displays_headings_from_sidebar.mdwn b/doc/bugs/toc_displays_headings_from_sidebar.mdwn new file mode 100644 index 000000000..469ca8a33 --- /dev/null +++ b/doc/bugs/toc_displays_headings_from_sidebar.mdwn @@ -0,0 +1,3 @@ +The [[/ikiwiki/directive/toc]] directive scrapes all headings from the page, including those in the sidebar. So, if the sidebar includes navigational headers, every page with a table of contents will display those navigational headers before the headers in that page's content. + +I'd like some way to exclude the sidebar from the table of contents. As discussed via Jabber, perhaps toc could have a config option to ignore headers inside a nav tag or a tag with id="sidebar". diff --git a/doc/bugs/toc_in_sidebar.mdwn b/doc/bugs/toc_in_sidebar.mdwn new file mode 100644 index 000000000..447a0e51b --- /dev/null +++ b/doc/bugs/toc_in_sidebar.mdwn @@ -0,0 +1,21 @@ +Putting a toc in the sidebar used to work, but was broken by +commit 9652cdfe2eb16150518e34af33c8858118fe0a09, which, in turn fixed a bug +with the toc not appearing during page preview. + +So, if toc is a sanitize hook, it can't be used in the sidebar, because the +sidebar is only added to the page later. If the toc is a format hook, it +shows up in the sidebar, but not at page preview time (because format hooks +are not called during preview). Also, calling the toc as a format hook +makes any headers that are hardcoded into the page template show up in the +toc, which is rarely desirable. + +I can't think of a way between these that works in all cases. Maybe call +the format hooks when generating a page preview? Maybe add an option to toc +to make it embeddable in the sidebar? + +Hmm, I think I need to call format during preview. Another case is that +inline uses a format hook to insert the inlined content.. + +--[[Joey]] + +[[done]] diff --git a/doc/bugs/toggle_expects_body_element_without_attributes.mdwn b/doc/bugs/toggle_expects_body_element_without_attributes.mdwn new file mode 100644 index 000000000..0b39346f4 --- /dev/null +++ b/doc/bugs/toggle_expects_body_element_without_attributes.mdwn @@ -0,0 +1,3 @@ +The toggle plugins checks for a `<body>` in the page; if not found, javascript tags are inserted at the top of the document. Since my page uses `<body onload="javascript:fixLinks()">`; a plain `<body>` is not found and I get script links before the docstring declaration. Please see the source of the following toggle-using page: http://kaizer.se/wiki/kupfer/ -- ulrik [kaizer.se] + +[[fixed|done]] --[[Joey]] diff --git a/doc/bugs/toggle_fails_on_Safari.mdwn b/doc/bugs/toggle_fails_on_Safari.mdwn new file mode 100644 index 000000000..25f62e088 --- /dev/null +++ b/doc/bugs/toggle_fails_on_Safari.mdwn @@ -0,0 +1,58 @@ +The [[plugins/toggle]] plugin has no effect when viewed on the Safari web browser. + +All toggles appear open all the time. + +I don't know if this is true for other webkit browsers (the new Konqueror, the iPhone, etc). +I'm currently testing in the Safari nightly builds, but I've seen the bug in the current release +of Safari too. + +Looking at the Safari Web Inspector, it believes there is a parse error on line 47 of the +[[news]] page. This is the definition of the getElementsByClass(class) function. + + 45 } + 46 + 47 function getElementsByClass(class) { + SyntaxError: Parse error + 48 var ret = new Array(); + +> Reproduced in epiphany-webkit on debian. +> +> Also noticed something interesting when I opened the page in vim. It +> highlighted the "class" like a type definition, not a variable. Sure +> enough, replacing with "c" fixed it. +> +> I wonder if webkit is actually in the right here, and using a reseved +> word like, presumably, "class" as a variable name is not legal. As I try +> to ignore javascript as much as possible, I can't say. [[done]] --[[Joey]] + +>> I also started having a look at this. I found the same issue with the +>> the variable 'class'. I'm not a javascript guru so I looked on the web +>> at other implementations of getElementsByClass() and noticed some +>> things that we might use. I took a bunch of different ideas and came +>> up with this: + + function getElementsByClass(cls, node, tag) { + if (document.getElementsByClass) + return document.getElementsByClass(cls, node, tag); + if (! node) node = document; + if (! tag) tag = '*'; + var ret = new Array(); + var pattern = new RegExp("(^|\\s)"+cls+"(\\s|$)"); + var els = node.getElementsByTagName(tag); + for (i = 0; i < els.length; i++) { + if ( pattern.test(els[i].className) ) { + ret.push(els[i]); + } + } + return ret; + } + +>> Most of the changes are minor, except that this one will use the +>> built in function if it is available. That is likely to be significantly +>> faster. Adding the extra parameters doesn't cause a problem -- +>> they're filled in with useful defaults. + +>> I don't know if it is worth making this change, but it is there if you want it. + +>>> Well, it seems to work. Although god only knows about IE. Suppose I +>>> might as well.. --[[Joey]] diff --git a/doc/bugs/trail_excess_dependencies.mdwn b/doc/bugs/trail_excess_dependencies.mdwn new file mode 100644 index 000000000..f806a62eb --- /dev/null +++ b/doc/bugs/trail_excess_dependencies.mdwn @@ -0,0 +1,95 @@ +I've just modified the trail plugin to use only presence, and not +content dependencies. Using content dependencies, particularly to the page +that defines the trail, meant that every time that page changed, *every* +page in the trail gets rebuilt. This leads to users setting up sites that +have horrible performance, if the trail is defined in, for example, the top +page of a blog. + +Unfortunatly, this change to presence dependencies has +introduced a bug. Now when an existing trail is removed, the pages in the +trail don't get rebuilt to remove the trail (both html display and state). + +> Actually, this particular case is usually OK. Suppose a trail `untrail` +> contains `untrail/a` (as is the case in the regression +> test I'm writing), and you build the wiki, then edit `untrail` to no +> longer be a trail, and refresh. `untrail` has changed, so it is +> rendered. Assuming that the template of either `untrail` or another +> changed page happens to contain the `TRAILS` variable (which is not +> guaranteed, but is highly likely), `I::P::t::prerender` +> is invoked. It notices that `untrail/a` was previously a trail +> member and is no longer, and rebuilds it with the diagnostic +> "building untrail/a, its previous or next page has changed". +> +> Strictly speaking, I should change `I::P::t::build_affected` +> so it calls `prerender`, so we're guaranteed to have done the +> recalculation. Fixed in my branch. --[[smcv]] + +I think that to fix this bug, the plugin should use a hook to +force rebuilding of all the pages that were in the trail, when +the trail is removed (or changed). + +> The case of "the trail is changed" is still broken: +> if the order of items changes, or the trail is removed, +> then the logic above means it's OK, but if you +> change the `\[[!meta title]]` of the trail, or anything else +> used in the prev/up/next bar, the items won't show that +> change. Fixed in my branch. --[[smcv]] + +There's a difficulty in doing that: The needsbuild hook runs before the scan +hook, so before it has a chance to see if the trail directive is still there. +It'd need some changes to ikiwiki's hooks. + +> That's what `build_affected` is for, and trail already used it. --s + +(An improvement in this area would probably simplify other plugins, which +currently abuse the needsbuild hook to unset state, to handle the case +where the directive that resulted in that state is removed.) + +I apologise for introducing a known bug, but the dependency mess was too +bad to leave as-is. And I have very little time (and regrettably, even less +power) to deal with it right now. :( --[[Joey]] + +[[!template id=gitbranch branch=smcv/ready/trail author="[[Simon_McVittie|smcv]]"]] +[[!tag patch]] + +> I believe my `ready/trail` branch fixes this. There are regression tests. +> +> Here is an analysis of how the trail pages interdepend. +> +> * If *trail* contains a page *member* which does exist, *member* depends +> on *trail*. This is so that if the trail directive is deleted from +> *trail*, or if *trail*'s "friendly" title or trail settings are changed, +> the trail navigation bar in *member* will pick up that change. This is +> now only a presence dependency, which isn't enough to make those happen +> correctly. [Edited to add: actually, the title is the only thing that +> can affect *member* without affecting the order of members.] +> +> * If *trail* contains consecutive pages *m1* and *m2* in that order, +> *m1* and *m2* depend on each other. This is so that if one's +> "friendly" title changes, the other is rebuilt. This is now only +> a presence dependency, which isn't enough to make those happen +> correctly. In my branch, I explicitly track the "friendly" title +> for every page that's edited and is involved in a trail somehow. +> +> * If *trail* has *member* in its `pagenames` but there is no page called +> *member*, then *trail* must be rebuilt if *member* is created. This +> was always a presence dependency, and is fine. +> +> In addition, the `trail` plugin remembers the maps +> { trail => next item in that trail } and { trail => previous item in +> that trail } for each page. If either changes, the page gets rebuilt +> by `build_affected`, with almost the same logic as is used to update +> pages that link to a changed page. My branch extends this to track the +> "friendly title" of each page involved in a trail, either by being +> the trail itself or a member (or both). +> +> I think it's true to say that the trail always depends on every member, +> even if it doesn't display them. This might mean that we can use +> "render the trail page" as an opportunity to work out whether any of +> its members are also going to need re-rendering? +> [Edited to add: actually, I didn't need this to be true, but I made the +> regression test check it anyway.] +> +> --[[smcv]] + +>>> Thanks **very** much! [[done]] --[[Joey]] diff --git a/doc/bugs/trail_shows_on_cgi_pages.mdwn b/doc/bugs/trail_shows_on_cgi_pages.mdwn new file mode 100644 index 000000000..af1de3028 --- /dev/null +++ b/doc/bugs/trail_shows_on_cgi_pages.mdwn @@ -0,0 +1,12 @@ +When commenting on, or I think editing, a page that uses the trail +plugin, the trail is displayed across the top of the page. This should not +happen, probably. --[[Joey]] + +> [[!template id=gitbranch branch=smcv/ready/no-trails-if-dynamic author="[[smcv]]"]] +> [[!tag patch]] +> Fixed in my branch. --[[smcv]] + +>> [[merged|done]], although I am ambivilant about hiding the search box, +>> and unsure about hiding the sidebar. At least the latter fixes an +>> annoying layout problem with the comment page, where the textarea +>> appears below the sidebar due to its width. --[[Joey]] diff --git a/doc/bugs/trail_test_suite_failures.mdwn b/doc/bugs/trail_test_suite_failures.mdwn new file mode 100644 index 000000000..a3b7159ec --- /dev/null +++ b/doc/bugs/trail_test_suite_failures.mdwn @@ -0,0 +1,97 @@ +[[!template id=gitbranch branch=smcv/trail author=smcv]] [[!tag patch]] + +`t/trail.t` has some test suite failures. This is after applying +[[smcv]]'s patch that fixed some races that caused it to fail +sometimes. These remaining failures may also be intermittant, +although I can get them reliably on my laptop. I've added some debugging +output, which seems to point to an actual bug in the plugin AFAICS. --[[Joey]] + +> I can reproduce this reliably at 0a23666ddd but not 3.20120203. Bisecting +> indicates that it regressed in aaa72a3a80f, "inline: When the pagenames list +> includes pages that do not exist, skip them". +> +> I don't think this is the bug noted in the commit message - the inline +> containing `sorting/new` uses `pages`, not `pagenames`. --[[smcv]] + +>> It seems you removed `trail` support from `inline` in that commit. +>> Assuming that wasn't intentional, this is fixed in `smcv/trail`. +>> --[[smcv]] + +>>> Looks like a bad merge of some kind. pulled, [[done]] --[[Joey]] + +<pre> +ok 71 - expected n=sorting/end p=sorting/beginning in sorting/middle.html +not ok 72 - expected n=sorting/new p=sorting/middle in sorting/end.html +# Failed test 'expected n=sorting/new p=sorting/middle in sorting/end.html' +# at t/trail.t line 13. +# got: 'n=sorting/linked2 p=sorting/middle' +# expected: 'n=sorting/new p=sorting/middle' +not ok 73 - expected n=sorting/old p=sorting/end in sorting/new.html +# Failed test 'expected n=sorting/old p=sorting/end in sorting/new.html' +# at t/trail.t line 13. +# got: undef +# expected: 'n=sorting/old p=sorting/end' +not ok 74 - expected n=sorting/ancient p=sorting/new in sorting/old.html +# Failed test 'expected n=sorting/ancient p=sorting/new in sorting/old.html' +# at t/trail.t line 13. +# got: undef +# expected: 'n=sorting/ancient p=sorting/new' +not ok 75 - expected n=sorting/linked2 p=sorting/old in sorting/ancient.html +# Failed test 'expected n=sorting/linked2 p=sorting/old in sorting/ancient.html' +# at t/trail.t line 13. +# got: undef +# expected: 'n=sorting/linked2 p=sorting/old' +not ok 76 - expected n= p=sorting/ancient in sorting/linked2.html +# Failed test 'expected n= p=sorting/ancient in sorting/linked2.html' +# at t/trail.t line 13. +# got: 'n= p=sorting/end' +# expected: 'n= p=sorting/ancient' +ok 77 +</pre> + +Here, the "new" page does not seem to be included into the trail as expected. +Looking at the rendered page, there is no trail directive output on it either. +--[[Joey]] + +<pre> +ok 90 +not ok 91 - expected n=sorting/new p= in sorting/old.html +# Failed test 'expected n=sorting/new p= in sorting/old.html' +# at t/trail.t line 13. +# got: undef +# expected: 'n=sorting/new p=' +not ok 92 - expected n=sorting/middle p=sorting/old in sorting/new.html +# Failed test 'expected n=sorting/middle p=sorting/old in sorting/new.html' +# at t/trail.t line 13. +# got: undef +# expected: 'n=sorting/middle p=sorting/old' +not ok 93 - expected n=sorting/linked2 p=sorting/new in sorting/middle.html +# Failed test 'expected n=sorting/linked2 p=sorting/new in sorting/middle.html' +# at t/trail.t line 13. +# got: 'n=sorting/linked2 p=' +# expected: 'n=sorting/linked2 p=sorting/new' +ok 94 - expected n=sorting/linked p=sorting/middle in sorting/linked2.html +ok 95 - expected n=sorting/end p=sorting/linked2 in sorting/linked.html +ok 96 - expected n=sorting/a/c p=sorting/linked in sorting/end.html +ok 97 - expected n=sorting/beginning p=sorting/end in sorting/a/c.html +ok 98 - expected n=sorting/a/b p=sorting/a/c in sorting/beginning.html +not ok 99 - expected n=sorting/ancient p=sorting/beginning in sorting/a/b.html +# Failed test 'expected n=sorting/ancient p=sorting/beginning in sorting/a/b.html' +# at t/trail.t line 13. +# got: 'n=sorting/z/a p=sorting/beginning' +# expected: 'n=sorting/ancient p=sorting/beginning' +not ok 100 - expected n=sorting/z/a p=sorting/a/b in sorting/ancient.html +# Failed test 'expected n=sorting/z/a p=sorting/a/b in sorting/ancient.html' +# at t/trail.t line 13. +# got: undef +# expected: 'n=sorting/z/a p=sorting/a/b' +not ok 101 - expected n= p=sorting/ancient in sorting/z/a.html +# Failed test 'expected n= p=sorting/ancient in sorting/z/a.html' +# at t/trail.t line 13. +# got: 'n= p=sorting/a/b' +# expected: 'n= p=sorting/ancient' +ok 102 +</pre> + +Haven't investigated, but looks like the same sort of problem, a +page expected to be in the trail isn't. --[[Joey]] diff --git a/doc/bugs/trails_depend_on_everything.mdwn b/doc/bugs/trails_depend_on_everything.mdwn new file mode 100644 index 000000000..8e9edcf43 --- /dev/null +++ b/doc/bugs/trails_depend_on_everything.mdwn @@ -0,0 +1,16 @@ +[[!template id=gitbranch branch=smcv/ready/trail-sort +author="[[Simon McVittie|smcv]]" +browse=http://git.pseudorandom.co.uk/smcv/ikiwiki.git/shortlog/refs/heads/ready/trail-sort]] +[[!tag patch users/smcv/ready]] + +On [[trail's discussion page|plugins/trail/discussion]], [[kjs]] pointed out +that [[plugins/trail]] and [[plugins/contrib/album]] get excessive +dependencies on `internal(*)`. I tracked this down to their (ab)use of +`pagespec_match_list` with the pagespec `internal(*)` to sort a pre-existing +list of pages. + +They should just sort the pages instead; they'll already have all the +dependencies they need. My branch adds `IkiWiki::sort_pages` but does not +make it plugin API just yet. --[[smcv]] + +> [[merged|done]] --[[smcv]] diff --git a/doc/bugs/transient_autocreated_tagbase_is_not_transient_autoindexed.mdwn b/doc/bugs/transient_autocreated_tagbase_is_not_transient_autoindexed.mdwn new file mode 100644 index 000000000..a52b31c25 --- /dev/null +++ b/doc/bugs/transient_autocreated_tagbase_is_not_transient_autoindexed.mdwn @@ -0,0 +1,76 @@ + mkdir -p ikiwiki-tag-test/raw/a_dir/ ikiwiki-tag-test/rendered/ + echo '\[[!taglink a_tag]]' > ikiwiki-tag-test/raw/a_dir/a_page.mdwn + ikiwiki --verbose --plugin tag --plugin autoindex --plugin mdwn --set autoindex_commit=0 --set tagbase=tag --set tag_autocreate=1 --set tag_autocreate_commit=0 ikiwiki-tag-test/raw/ ikiwiki-tag-test/rendered/ + ls -al ikiwiki-tag-test/raw/.ikiwiki/transient/ + ls -al ikiwiki-tag-test/rendered/tag/ + +Shouldn't `ikiwiki-tag-test/raw/.ikiwiki/transient/tag.mdwn` and `ikiwiki-tag-test/rendered/tag/index.html` exist? + +[[!tag patch users/smcv/ready]] +[[!template id=gitbranch branch=smcv/ready/autoindex author=smcv + browse=http://git.pseudorandom.co.uk/smcv/ikiwiki.git/shortlog/refs/heads/ready/autoindex]] +[[!template id=gitbranch branch=smcv/ready/autoindex-more-often author=smcv + browse=http://git.pseudorandom.co.uk/smcv/ikiwiki.git/shortlog/refs/heads/ready/autoindex-more-often]] + +> To have a starting point to (maybe) change this, my `ready/autoindex` +> branch adds a regression test for the current behaviour, both with +> and without `autoindex_commit` enabled. It also fixes an unnecessary +> and potentially harmful special case for the transient directory. +> +> The fact that files in underlays (including transient files) don't +> trigger autoindexing is deliberate. However, this is the second +> request to change this behaviour: the first was +> [[!debbug 611068]], which has a patch from Tuomas Jormola. +> On that bug report, Joey explains why it's undesirable +> for the original behaviour of autoindex (when the +> index isn't transient). +> +> I'm not sure whether the same reasoning still applies when the +> index is transient, though (`autoindex_commit => 0`), +> because the index pages won't be cluttering up people's +> git repositories any more? My `autoindex-more` branch changes +> the logic so it will do what you want in the `autoindex_commit => 0` +> case, and amends the appropriate regression test. --[[smcv]] + +>> the autoindex-more-often branch looks good to me in general. +>> +>> i do have doubts about the 3ba2ef1a patch ("remove unnecessary special case +>> for transient underlay"): now that we consider the complete transient +>> directory as well, the sequence in which the refresh hooks are called starts +>> to matter, and pages created by other plugins in a similar fashion as by +>> autoindex will only be included the next time refresh gets called. +>> +>> *addendum:* i just found where i discussed the issue of fighting transient +>> pages last, it was on [[todo/alias directive]]. the example cited there +>> (conflicts with autotag) would probably work here as well. (imagine a +>> `tags/project/completed` and a `tags/project/inprogress` exist, and a page +>> is tagge `tags/project`. will that be an autoindex or an autotag?) +>> +>> --[[chrysn]] + +>>> That's a fair point. I think what happens is down to commit vs. refresh +>>> timing. +>>> +>>> If pages tagged t/p/c, t/p/i and t/p are all created between one +>>> refresh and the next, with none of those tag pages existing, I think the +>>> answer is that they would all be autotags, because until t/p/c and +>>> t/p/i are created, there's no reason to need t/p as an autoindex. +>>> +>>> If there were already pages tagged t/p/c and t/p/i at the previous +>>> refresh, then t/p would already be an autoindex, and that's a +>>> valid page, so autotagging wouldn't touch it. +>>> +>>> I can't see much reason to prefer one over the other; the ideal answer +>>> is probably to have a tag-cloud *and* a list of child pages, but this +>>> seems a weird enough thing to do that I'd be OK with a wiki user +>>> having to disambiguate it themselves. "Whichever automatic process +>>> happens first, happens" is at least easy to explain, and I consider +>>> both autoindices and autotags to be time-saving conveniences rather +>>> than something fundamental. --s + +>>>> i think a behavior that does the right thing when there is a right thing +>>>> and *something* when there is ambiguity is ok for now; especially, it's +>>>> not up to the autoindex branch to come up with a solution to the general +>>>> problem. --[[chrysn]] + +>>>>> [[Merged|done]] --[[smcv]] diff --git a/doc/bugs/transitive_dependencies.mdwn b/doc/bugs/transitive_dependencies.mdwn new file mode 100644 index 000000000..c44fe7962 --- /dev/null +++ b/doc/bugs/transitive_dependencies.mdwn @@ -0,0 +1,94 @@ +If a sidebar contains a map, or inline (etc), one would expect a +add/remove of any of the mapped/inlined pages to cause a full wiki +rebuild. But this does not happen. + +If page A inlines page B, which inlines page C, a change to C will cause B +to be updated, but A will not "notice" that this means A needs to be +updated. + +One way to look at this bug is that it's a bug in where dependencies are +recorded when preprocessing the rendered or sidebar page. The current code +does: + + add_depends($params{page}, $somepage); + +Where `$params{page}` is page B. If this is changed to `$params{destpage}`, +then the dependency is added to page A, and updates to C cause it to +change. This does result in the page A's getting lots more dependency info +recorded than before (essentially a copy of all the B's dependency info). + +It's also a fragile, since all plugins that handle dependencies have to be +changed, and do this going forward. And it seems non-obvious that this should +be done. Or really, whether to use `page` or `destpage` there. Currently, +making the "wrong" choice and using `destpage` instead of `page` (which nearly +everything uses) will just result in semi-redundant dependency info being +recorded. If we make destpage mandatory to fix this, goofing up will lead to +this bug coming back. Ugh. + +---- + +## rebuild = change approach + +[[!template id=gitbranch branch=origin/transitive-dependencies author="[[joey]]"]] + +Another approach to fix it is to say that anything that causes a +rebuild of B is treated as a change of B. Then when C is changed, B is +rebuilt due to dependencies, and in turn this means A is rebuilt because B +"changed". + +This is essentially what is done with wikilinks now, and why, if a sidebar +links to page C, add/remove of C causes all pages to be rebuilt, as seen +here: + + removing old page meep + building sidebar.mdwn, which links to meep + building TourBusStop.mdwn, which depends on sidebar + building contact.mdwn, which depends on sidebar + ... + +Downsides here: + +* Means a minimum of 2x as much time spent resolving dependencies, + at least in my simple implementation, which re-runs the dependency + resolution loop until no new pages are rebuilt. + (I added an optimisation that gets it down to 1.5X as much work on + average, still 2x as much worst case. I suppose building a directed + graph and traversing it would be theoretically more efficient.) +* Causes extra work for some transitive dependencies that we don't + actually care about. This is amelorated, but not solved by + the current work on [[todo/dependency_types]]. + For example, changing index causes + plugins/brokenlinks to update in the first pass; if there's a second + pass, plugins/map is no longer updated (contentless dependencies FTW), + but plugins is, because it depends on plugins/brokenlinks. + (Of course, this is just a special case of the issue that a real + modification to plugins/brokenlinks causes an unnecessary update of + plugins, and could be solved by adding more dependency types.) + +[[done]] --[[Joey]] + +> Some questions/comments... I've thought about this a lot for [[todo/tracking_bugs_with_dependencies]]. +> +> * When you say that anything that causes a rebuild of B is treated as a change of B, are you: i) Treating +> any rebuild as a change, or ii) Treating any rebuild that gives a new result as a change? Option ii) would +> lead to fewer rebuilds. Implementation is easy: when you're about to rebuild a page, load the old rendered html in. Do the rebuild. Compare +> the new and old html. If there is a difference, then mark that page as having changed. If there is no difference +> then you don't need to mark that pages as changed, even though it has been rebuilt. (This would ignore pages in meta-data that don't +> cause changes in html, but I don't think that is a huge issue.) + +>> That is a good idea. I will have to look at it to see if the overhead of +>> reading back in the html of every page before building actually is a +>> win though. So far, I've focused on avoiding unnecessary rebuilds, and +>> there is still some room for more dependency types doing so. +>> (Particularly for metadata dependencies..) --[[Joey]] + +> * The second comment I have relates to cycles in transitive dependencies. At the moment I don't think this is +> possible, but with some additions it may well become so. This could be problematic as it could lead to a) +> updates that never complete, or b) it being theoretically unclear what the final result should be (i.e. you +> can construct logical paradoxes in the system). I think the point above about marking things as changed only when +> the output actually changes fixes any cases that are well defined. For logical paradoxes and infinite loops (e.g. +> two pages that include each other), you might want to put a limit on the number of times you'll rebuild a page in any +> given run of ikiwiki. Say, only allow a page to rebuild twice on any run, regardless of whether a page it depends on changes. +> This is not a perfect solution, but would be a good approximation. -- [[Will]] + +>> Ikiwiki only builds any given output file once per run, already. --[[Joey]] diff --git a/doc/bugs/trouble_with_base_in_search.mdwn b/doc/bugs/trouble_with_base_in_search.mdwn new file mode 100644 index 000000000..ca6a6c5cc --- /dev/null +++ b/doc/bugs/trouble_with_base_in_search.mdwn @@ -0,0 +1,60 @@ +For security reasons, one of the sites I'm in charge of uses a Reverse Proxy to grab the content from another machine behind our firewall. +Let's call the out-facing machine Alfred and the one behind the firewall Betty. + +For the static pages, everything is fine. However, when trying to use the search, all the links break. +This is because, when Alfred passes the search query on to Betty, the search result has a "base" tag which points to Betty, and all the links to the "found" pages are relative. +So we have + + <base href="Betty.example.com"/> + ... + <a href="./path/to/found/page/">path/to/found/page</a> + +This breaks things for anyone on Alfred, because Betty is behind a firewall and they can't get there. + +What would be better is if it were possible to have a "base" which didn't reference the hostname, and for the "found" links not to be relative. +Something like this: + + <base href="/"/> + ... + <a href="/path/to/found/page/">path/to/found/page</a> + +The workaround I've come up with is this. + +1. Set the "url" in the config to ' ' (a single space). It can't be empty because too many things complain if it is. +2. Patch the search plugin so that it saves an absolute URL rather than a relative one. + +Here's a patch: + + diff --git a/IkiWiki/Plugin/search.pm b/IkiWiki/Plugin/search.pm + index 3f0b7c9..26c4d46 100644 + --- a/IkiWiki/Plugin/search.pm + +++ b/IkiWiki/Plugin/search.pm + @@ -113,7 +113,7 @@ sub indexhtml (@) { + } + $sample=~s/\n/ /g; + + - my $url=urlto($params{destpage}, ""); + + my $url=urlto($params{destpage}, undef); + if (defined $pagestate{$params{page}}{meta}{permalink}) { + $url=$pagestate{$params{page}}{meta}{permalink} + } + +It works for me, but it has the odd side-effect of prefixing links with a space. Fortunately that doesn't seem to break browsers. +And I'm sure someone else could come up with something better and more general. + +--[[KathrynAndersen]] + +> The `<base href>` is required to be genuinely absolute (HTML 4.01 §12.4). +> Have you tried setting `url` to the public-facing URL, i.e. with `alfred` +> as the hostname? That seems like the cleanest solution to me; if you're +> one of the few behind the firewall and you access the site via `betty` +> directly, my HTTP vs. HTTPS cleanup in recent versions should mean that +> you rarely get redirected to `alfred`, because most URLs are either +> relative or "local" (start with '/'). --[[smcv]] + +>> I did try setting `url` to the "Alfred" machine, but that doesn't seem clean to me at all, since it forces someone to go to Alfred when they started off on Betty. +>> Even worse, it prevents me from setting up a test environment on, say, Cassandra, because as soon as one tries to search, one goes to Alfred, then Betty, and not back to Cassandra at all. +>> Hardcoded solutions make me nervous. + +>> I suppose what I would like would be to not need to use a `<base href>` in searching at all. +>> --[[KathrynAndersen]] diff --git a/doc/bugs/txt_plugin_having_problems_with_meta_directives.mdwn b/doc/bugs/txt_plugin_having_problems_with_meta_directives.mdwn new file mode 100644 index 000000000..22224483e --- /dev/null +++ b/doc/bugs/txt_plugin_having_problems_with_meta_directives.mdwn @@ -0,0 +1,19 @@ +When applying my usual copyright and licensing header to a [[plugins/txt]] +page, garbled output is created. + +Here is the header: + + \[[meta copyright="Copyright © 2001, 2002, 2003, 2004, 2005, 2008 Free + Software Foundation, Inc."]] + + \[[meta license="""[[toggle id="license" text="GFDL 1.2+"]][[toggleable + id="license" text="Permission is granted to copy, distribute and/or modify + this document under the terms of the GNU Free Documentation License, + Version 1.2 or any later version published by the Free Software Foundation; + with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. + A copy of the license is included in the section entitled + [[GNU_Free_Documentation_License|/fdl]]."]]"""]] + +--[[tschwinge]] + +> [[done]], made it less zealous about encoding html entities. --[[Joey]] diff --git a/doc/bugs/typo_in_ikiwiki.setup.mdwn b/doc/bugs/typo_in_ikiwiki.setup.mdwn new file mode 100644 index 000000000..a7b10ec8c --- /dev/null +++ b/doc/bugs/typo_in_ikiwiki.setup.mdwn @@ -0,0 +1,9 @@ +Dot is automatically inserted. The htmlext option should be + + #htmlext => 'htm', + +instead of + + #htmlext => '.htm', + +> [[done]] --[[Joey]] diff --git a/doc/bugs/typo_in_skeleton.pm:_sessionncgi.mdwn b/doc/bugs/typo_in_skeleton.pm:_sessionncgi.mdwn new file mode 100644 index 000000000..4772aceee --- /dev/null +++ b/doc/bugs/typo_in_skeleton.pm:_sessionncgi.mdwn @@ -0,0 +1,5 @@ +skeleton.pm.example contains the typo "sessionncgi" when defining a sub, which means the skeleton plugin won't work as a session CGI action as-is. [My repository has a patch on the 'trivia' branch](http://git.debian.org/?p=users/smcv/ikiwiki.git;a=commitdiff;h=72ffc85d). --[[smcv]] + +[[!tag patch]] + +[[done]] diff --git a/doc/bugs/undefined_tags_or_mismatched_tags_won__39__t_get_converted.mdwn b/doc/bugs/undefined_tags_or_mismatched_tags_won__39__t_get_converted.mdwn new file mode 100644 index 000000000..b01fc44f2 --- /dev/null +++ b/doc/bugs/undefined_tags_or_mismatched_tags_won__39__t_get_converted.mdwn @@ -0,0 +1,46 @@ +If you put in something such as undefined tags or mismatched tags in .mdwn file, ikiwiki will put <p></p> around them. But ikiwiki will NOT convert < and > to &lt; and &gt;! + + <section> + + some text + + </section> + + +the output html + + <p><section></p> <p>some text</p> <p></section></p> + +And another example of mismatched tags: + + + + <div> + + some text + + </div> + </div> + + +The out put is: + + <div> + + some text + + </div> + + <p></div></p> + +> This is a bug in markdown. Actually, not converting `<` and `>` in tags is a +> markdown feature -- markdown allows inserting arbirary html, even if it's +> made-up tags. And putting paragraph tags around your `<section>` tag is +> understandable, since markdown can't know if `<section>` is intended to +> be a block-level tag or not. The bug is that it puts the `<p>` around the +> trailing `<div>` -- it does know what a div is, and it should know that's +> illegal and not do it. I've filed a [bug report](http://bugs.debian.org/459269) about that issue +> alone. If you feel the other things you brought up are bugs, please talk +> to the markdown maintainer. --[[Joey]] + +[[!tag done]] diff --git a/doc/bugs/undefined_value_as_a_HASH_reference.mdwn b/doc/bugs/undefined_value_as_a_HASH_reference.mdwn new file mode 100644 index 000000000..228c3baac --- /dev/null +++ b/doc/bugs/undefined_value_as_a_HASH_reference.mdwn @@ -0,0 +1,68 @@ +Hello, + +does anyone have an idea why I see the following error when I run websetup (Setup button in Preferences)? + + Error: Can't use an undefined value as a HASH reference at /usr/share/perl5/IkiWiki/Plugin/websetup.pm line 82, line 97. + +Maybe, related to this is also + + $ ikiwiki --setup /etc/ikiwiki/auto-blog.setup + What will the blog be named? tmpblog + What revision control system to use? git + What wiki user (or openid) will be admin? wsh + + + Setting up tmpblog ... + Importing /home/wsh/tmpblog into git + Initialized empty shared Git repository in /home/wsh/tmpblog.git/ + Initialized empty Git repository in /home/wsh/tmpblog/.git/ + [master (root-commit) d6847e1] initial commit + 8 files changed, 48 insertions(+) + create mode 100644 .gitignore + create mode 100644 archives.mdwn + create mode 100644 comments.mdwn + create mode 100644 index.mdwn + create mode 100644 posts.mdwn + create mode 100644 posts/first_post.mdwn + create mode 100644 sidebar.mdwn + create mode 100644 tags.mdwn + Counting objects: 11, done. + Delta compression using up to 4 threads. + Compressing objects: 100% (9/9), done. + Writing objects: 100% (11/11), 1.53 KiB, done. + Total 11 (delta 0), reused 0 (delta 0) + Unpacking objects: 100% (11/11), done. + To /home/wsh/tmpblog.git + * [new branch] master -> master + Directory /home/wsh/tmpblog is now a clone of git repository /home/wsh/tmpblog.git + Reference found where even-sized list expected at /usr/share/perl5/IkiWiki/Setup.pm line 177, <GEN4> line 97. + Reference found where even-sized list expected at /usr/share/perl5/IkiWiki/Setup.pm line 224, <GEN4> line 97. + Use of uninitialized value $section in hash element at /usr/share/perl5/IkiWiki/Setup.pm line 226, <GEN4> line 97. + Use of uninitialized value $section in hash element at /usr/share/perl5/IkiWiki/Setup.pm line 227, <GEN4> line 97. + Use of uninitialized value $section in concatenation (.) or string at /usr/share/perl5/IkiWiki/Setup.pm line 233, <GEN4> line 97. + /etc/ikiwiki/auto-blog.setup: Can't use an undefined value as a HASH reference at /usr/share/perl5/IkiWiki/Setup.pm line 252, <GEN4> line 97. + + usage: ikiwiki [options] source dest + ikiwiki --setup configfile + +I'm on Debian unstable. + +Thanks, +-Michal + +> Some plugin has a broken getsetup hook, and is feeding a corrupted setup list in. Both the websetup and the auto.setup files cause all plugins to be loaded and all their setup to be available. +> +> This command will help you find the plugin. Here it prints some noise around the rst plugin, for unrelated reasons, +> but what you're looking for is the plugin printed before the "even sized list" message. + +<pre> +perl -le 'use warnings; use strict; use Data::Dumper; use IkiWiki; %config=IkiWiki::defaultconfig(); use IkiWiki::Setup; my @s=IkiWiki::Setup::getsetup(); foreach my $pair (@s) { print "plugin ".$pair->[0]; my $setup=$pair->[1]; if ($pair->[0] eq "rst") { print Dumper($setup)} my %s=@{$setup} }' +</pre> + +> I was able to replicate this by making a plugin's getsetup hook return a list reference, rather than a list, +> and have put in a guard against that sort of thing. +> --[[Joey]] + +>> Thanks. Your command didn't helped me, but with trial and error approach I found that the victim an old version asciidoc plugin. For some reason, asciidoc was never listed in the output of the command. --[[wentasah]] + +>>> Ok. My fix should prevent the problem, so [[done]] --[[Joey]] diff --git a/doc/bugs/underlaydir_file_expose.mdwn b/doc/bugs/underlaydir_file_expose.mdwn new file mode 100644 index 000000000..4ee30e39d --- /dev/null +++ b/doc/bugs/underlaydir_file_expose.mdwn @@ -0,0 +1,13 @@ +If a file in the srcdir is removed, exposing a file in the underlaydir, +ikiwiki will not notice the removal, and the +page from the underlay will not be built. (However, it will be if the wiki +gets rebuilt.) + +> This problem is caused by ikiwiki storing only filenames relative to +> the srcdir or underlay, and mtime comparison not handling this case. + +> A related problem occurs if changing a site's theme with the +> [[plugins/theme]] plugin. The style.css of the old and new theme +> often has the same mtime, so ikiwiki does not update it w/o a rebuild. +> This is worked around in theme.pm with a special-purpose needsbuild hook. +> --[[Joey]] diff --git a/doc/bugs/unicode_chars_in_wikiname_break_auth.mdwn b/doc/bugs/unicode_chars_in_wikiname_break_auth.mdwn new file mode 100644 index 000000000..472597c46 --- /dev/null +++ b/doc/bugs/unicode_chars_in_wikiname_break_auth.mdwn @@ -0,0 +1,20 @@ +I spent hours trying to understand why my wiki suddenly refused me to log in (using passwordauth). +The failure message was always: `login failed, perhaps you need to turn on cookies?` + +Inspecting the cookie information (thanks to Iceweasel's webdeveloper add-on), I realized there were some weird-looking encoded chars in the cookie name. + +Replacing "·" with "-" in `wikiname` fixed this login issue. + +> Hmm, Recai sent me a patch a long time ago to handle utf-8 here by encoding +> the wikiname. But it doesn't seem to work, somehow the encoded utf-8 +> value still doesn't make it through. (CGI::Session seems to have underermined utf-8 +> issues too.) Seems like I will have to possibly break some sessions and +> entity-encode the wikiname in the cookie.. [[done]]. --[[Joey]] + +>> I confirm it fixes the bug for me. --[[intrigeri]] + +(BTW, such a char was replaced by -I don't remember what encoding thingie- in my setup file, when running `ikiwiki-transition setupformat`.) + +> Thanks for the heads up, fixed that too. --[[Joey]] + +>> I confirm it fixes the bug for me. --[[intrigeri]] diff --git a/doc/bugs/unicode_encoded_urls_and_recentchanges.mdwn b/doc/bugs/unicode_encoded_urls_and_recentchanges.mdwn new file mode 100644 index 000000000..262aa24fc --- /dev/null +++ b/doc/bugs/unicode_encoded_urls_and_recentchanges.mdwn @@ -0,0 +1,38 @@ +it appears that unicode characters in the title that are unicode letters are spared the __ filename encoding but instead saved in their utf8 encoding. (correct me if i'm wrong; didn't find the code that does this.) -- see below for examples. + +> Filenames can have any alphanumerics in them without the __ escaping. +> Your locale determines whether various unicode characters are considered +> alphanumeric. In other words, it just looks at the \[[:alpha:]] character +> class, whatever your locale defines it to be. --[[Joey]] + +this is not a problem per se, but (at least with git backend) the recent changes missinterpret the file name character set (it seems to read the filenames as latin1) and both display wrong titles and create broken links. + +the problem can be shown with an auto-setup'd ikiwiki without cgi when manually creating utf8 encoded filenames and running ikiwiki with LANG=en_GB.UTF-8 . + +> Encoding issue, I figured out a fix. [[done]] --[[Joey]] + +>> the link text works now, but the link goes to +>> `ikiwiki.cgi?page=uml%C3%A4ute&do=recentchanges_link`, which fails with +>> "missing page". it seems that bestlink can't handle utf8 encoded texts. (the +>> same happens, by the way, when using meta-redir to a page with high bytes in +>> the name.) +>> +>>> The problem is that all cgi inputs have to be explicitly decoded to +>>> utf-8, which I've now done for `recentchange_link`. +>>>> thanks a lot, i think that closed the bug. +>>> +>>> I cannot, however, reproduce a problem with meta redir. Here it +>>> generated the following html, which redirected the browser ok: +>>> <meta http-equiv="refresh" content="0; URL=./../â/" /> +>>>> sorry, my fault -- it was the blank which needed to be replaced by an +>>>> underscore, not the high byte character +>> +>> update: i've had a look at the git options; you could run git with '-z' (NUL +>> termination) in the `git_commit_info` function; this would require some +>> changes in `parse_diff_tree`, but otherwise completely eliminate the +>> problems with git escaping. +>> +>>> If you would like to develop a patch to that effect, I'd be glad to +>>> drop the current nasty code. +>>>> i'll have a look, but i'm afraid that's above my current perl skills. +>>>> --[[chrysn]] diff --git a/doc/bugs/unrecognized___34__do__61__blog__34___CGI_parameter_when_creating_todo_item.mdwn b/doc/bugs/unrecognized___34__do__61__blog__34___CGI_parameter_when_creating_todo_item.mdwn new file mode 100644 index 000000000..934f1480e --- /dev/null +++ b/doc/bugs/unrecognized___34__do__61__blog__34___CGI_parameter_when_creating_todo_item.mdwn @@ -0,0 +1,18 @@ +While I am creating this entry, the following appears +as the page title, above the form: + + ikiwiki/ creating unrecognized "do=blog" CGI parameter when creating todo item + +An the following appears below: + + Content-type: text/html + ikiwiki/ Error + + Error: unknown do parameter + +This is harmless. +I have to go, but will have a look at what could be going on when I'm back. + +--[[JeremieKoenig]] + +[[fixed|done]] --[[Joey]] diff --git a/doc/bugs/unwanted_discussion_links_on_discussion_pages.mdwn b/doc/bugs/unwanted_discussion_links_on_discussion_pages.mdwn new file mode 100644 index 000000000..c74a094ce --- /dev/null +++ b/doc/bugs/unwanted_discussion_links_on_discussion_pages.mdwn @@ -0,0 +1,36 @@ +Background: some po translations (amongst which `fr.po`) translate "discussion" to an upper-cased word (in French: "Discussion"). +By the way, this is wished e.g. in German, where such a noun has to be written with an upper-cased "D", but I can not see +the logic behind the added "D" in French. + +Anyway, this gettext-translated word is used to name the discussion pages, as `$discussionlink` in `Render.pm` is +built from `gettext("discussion")`. In the same piece of code, a case-sensitive regexp that tests wether the page +being rendered is a discussion page is case-sensitive. + +On the other hand, new discussion pages are created with a name built from `gettext("Discussion")` (please note the upper-cased +"D"). Such a new page name seems to be automagically downcased. + +This leads to newly created discussion pages not being recognized as discussion pages by the +`$page !~ /.*\/\Q$discussionlink\E$/` regexp, so that then end with an unwanted discussion link. + +A simple fix that seems to work is to make this regexp case-insensitive: + + git diff IkiWiki/Render.pm + diff --git a/IkiWiki/Render.pm b/IkiWiki/Render.pm + index adae9f0..093c25b 100644 + --- a/IkiWiki/Render.pm + +++ b/IkiWiki/Render.pm + @@ -77,7 +77,7 @@ sub genpage ($$) { + } + if ($config{discussion}) { + my $discussionlink=gettext("discussion"); + - if ($page !~ /.*\/\Q$discussionlink\E$/ && + + if ($page !~ /.*\/\Q$discussionlink\E$/i && + (length $config{cgiurl} || + exists $links{$page."/".$discussionlink})) { + $template->param(discussionlink => htmllink($page, $page, gettext("Discussion"), noimageinline => 1, forcesubpage => 1)); + +But the best way would be to avoid assuming implicitely that translators will translate "discussion" and "Discussion" the same way. + +> [[done]] --[[Joey]] + +[[!tag patch]] diff --git a/doc/bugs/urlto_API_change_breaks_wikis_with_po_plugin.mdwn b/doc/bugs/urlto_API_change_breaks_wikis_with_po_plugin.mdwn new file mode 100644 index 000000000..4268a1390 --- /dev/null +++ b/doc/bugs/urlto_API_change_breaks_wikis_with_po_plugin.mdwn @@ -0,0 +1,98 @@ +The po plugin needs to be updated to match the urlto sub API and +signature changes. Else a wiki with the po plugin enabled cannot be +refreshed / rebuilt because of (correct) Perl errors. + +My po branch contains a fix. +--[[intrigeri]] + +> The commit looks sane to me, for what it's worth. Joey, please +> consider merging? --[[smcv]] + +>> Merged. --[[Joey]] + +Also, I fear the lack of any useful `$from` parameter might break some +l10n'd link niceness when using `po_link_to = current` but I have not +investigated this yet. +--[[intrigeri]] + +> If `urlto` is called without a second parameter, it means we need +> a URL valid from either the CGI URL or any page in the wiki, +> (so we'd previously have set the third parameter true), but we +> don't *necessarily* need an absolute URL - so return what you'd +> have returned if asked for an absolute URL, but looking like +> `/bugs/` rather than `http://ikiwiki.info/bugs/` if possible. +> +> It looks as though `beautify_urlpath` under `po_link_to = current`, +> and 3-argument `urlto`, aren't tested by `t/po.t` - perhaps you +> could add some test cases there? To test 3-argument `urlto` you'd +> need to add `$config{baseurl} = "http://example.com"` or +> something. --[[smcv]] + +>> I'm leaving this bug report open until this can be checked. --[[Joey]] + +>>> My `ready/urlto` branch improves the test coverage. The bugfix from +>>> that branch fixes most of `po` too, but leaves behind some perhaps +>>> less-than-ideal behaviour: links where the current language is unknown, +>>> with `po_link_to = current`, always go to the master language, +>>> whereas perhaps it'd be better to go to the negotiated language in +>>> this case? --[[smcv]] + +>>>> Thanks for taking care, thanks for these improvements! +>>>> +>>>> OTOH I consider any of these behaviours (either the brand new one +>>>> = link to master language, or the alternative one = link to +>>>> negotiated) as a regression. Any of these is contrary to what +>>>> `po_link_to = current` is supposed to do according to the +>>>> documentation. +>>>> +>>>> Let's be less technical, let me display my practical usecase +>>>> (making this possible was one of the main reasons I initially +>>>> implemented `po_link_to = current`). +>>>> +>>>> Summary: the current state of things is an annoying regression +>>>> and it needs to be fixed. +>>>> +>>>> Context: I participate in building a Live system based on Debian +>>>> Live; the project's multilingual website +>>>> ([T(A)ILS](https://amnesia.boum.org/) is built using ikiwiki. A +>>>> static / offline copy is shipped on ISO images; this is the way +>>>> end-user documentation lands on the CDs. Note that no webserver +>>>> runs on the Live system to serve this wiki, so `po_link_to = +>>>> current` is compulsory. A user can choose her preferred language +>>>> at boot time. Depending on her decision, The desktop shortcut +>>>> that points to the embedded documentation (i.e. static wiki) +>>>> links to a different entry point depending on the chosen +>>>> language. +>>>> +>>>> The previous (documented) behaviour was deadly simple: if I am +>>>> presented a page in English (master language) it means it does +>>>> not exist in my preferred language; the computer always displays +>>>> me the best available version according to my needs. The new +>>>> behaviour brings a troubling seemingly random factor into the +>>>> user navigation experience and IMHO is a mess from a web +>>>> ergonomics point of view (no content negotiation available, +>>>> remember): I sometimes am shown an English page although it is +>>>> fully translated in my language one click away, and on the +>>>> contrary I sometimes I am shown the optimal page. This, is, well, +>>>> interesting. This practically forces the non-English speaking +>>>> website visitor to check the otherlanguages list on every single +>>>> page to make sure *herself* there is nothing better available, +>>>> and sometimes click on her preferred language link to get a page +>>>> she actually can read. +>>>> +>>>> I unfortunately might not be able to dedicate the needed time to +>>>> help fix this in a timely manner, so I don't want to urge anyone. +>>>> Take care! --[[intrigeri]] + +>>>>> I can see why this is bad, but to the best of my knowledge it's +>>>>> not a regression: each of the calls to 1-argument `urlto` was +>>>>> previously a call to 3-argument `urlto`, which always produces +>>>>> a fully absolute URL, so in either case there isn't enough +>>>>> context to know the current language. Links that were previously +>>>>> 2-argument `urlto` still have a defined second argument; +>>>>> I've just edited `plugins/write` to clarify why the second +>>>>> argument should be provided whenever possible. --[[smcv]] + +>>>>>> Ok. I am sorry for the burden that arose from my +>>>>>> misunderstanding. No need to keep this bug open then => +>>>>>> [[done]] --[[intrigeri]] diff --git a/doc/bugs/urlto__40____34____34____44___...__44___1__41___not_absolute.mdwn b/doc/bugs/urlto__40____34____34____44___...__44___1__41___not_absolute.mdwn new file mode 100644 index 000000000..8a93848b3 --- /dev/null +++ b/doc/bugs/urlto__40____34____34____44___...__44___1__41___not_absolute.mdwn @@ -0,0 +1,9 @@ +[[!template id=gitbranch branch=smcv/ready/urlto author="[[Simon_McVittie|smcv]]"]] +[[!tag patch]] + +urlto() has a special-case for a zero-length first argument, but it +produces a relative path even if the third argument is given and true. + +My `ready/urlto` branch simplifies this special case so it works. --[[smcv]] + +[[merged|done]] --[[Joey]] diff --git a/doc/bugs/user_links_on_recentchanges_pages_problem.mdwn b/doc/bugs/user_links_on_recentchanges_pages_problem.mdwn new file mode 100644 index 000000000..d00f6815b --- /dev/null +++ b/doc/bugs/user_links_on_recentchanges_pages_problem.mdwn @@ -0,0 +1,12 @@ +When I click on a linked username for commits on the recentchanges page (on +the live ikiwiki.info) I get a link such as +<http://ikiwiki.info/ikiwiki.cgi?page=users%2Fjoey&do=recentchanges_link> +which returns something like + + <a href="http://ikiwiki.info">ikiwiki</a>/ Error + <p class="error">Error: unknown do parameter + +-- [[Jon]] + +> That was fixed in 3.04 but ikiwiki.info had not been upgraded to it yet. +> [[done]] --[[Joey]] diff --git a/doc/bugs/utf-8_bug_in_websetup.pm.mdwn b/doc/bugs/utf-8_bug_in_websetup.pm.mdwn new file mode 100644 index 000000000..debedb01c --- /dev/null +++ b/doc/bugs/utf-8_bug_in_websetup.pm.mdwn @@ -0,0 +1,22 @@ +[[!tag patch bugs]] + +I type chinese characters into the fields. After press "save setup" button the characters turn into gibberish. + +I submit a patch that solve the problem for me. --Lingo + +> Fully fixing it is slightly more complex, but now [[done]] --[[Joey]] + +---- + + --- websetup.pm 2009-12-02 05:07:46.000000000 +0800 + +++ /usr/share/perl5/IkiWiki/Plugin/websetup.pm 2010-01-08 22:05:16.000000000 +0800 + @@ -308,7 +308,8 @@ + $fields{$_}=$shown{$_} foreach keys %shown; + } + } + - + + + + IkiWiki::decode_form_utf8($form); + if ($form->submitted eq "Cancel") { + IkiWiki::redirect($cgi, $config{url}); + return; diff --git a/doc/bugs/utf8_html_templates.mdwn b/doc/bugs/utf8_html_templates.mdwn new file mode 100644 index 000000000..a750b23f6 --- /dev/null +++ b/doc/bugs/utf8_html_templates.mdwn @@ -0,0 +1,22 @@ +HTML::Template does not read files as utf-8, so modifying ikiwiki's +template files to contain utf-8 won't currently work. + +It seems that the best way to fix this would be to make HTML::Template +support utf-8. + +A workaround is to change all the template reading code like this: + + - my $template=HTML::Template->new(blind_cache => 1, + - filename => "$config{templatedir}/page.tmpl"); + + open(TMPL, "<:utf8", "$config{templatedir}/page.tmpl"); + + my $template=HTML::Template->new(filehandle => *TMPL); + + close(TMPL); + +However, this will make ikiwiki slower when rebuilding a wiki, since it +won't cache templates. + +Could be approached by using HTML::Template's support for filters. Just make it use a filter that turns on utf-8 + +Or by subclassing it and overriding the \_init\_template method, though that's a bit uglier + +[[bugs/done]] diff --git a/doc/bugs/utf8_svn_log.mdwn b/doc/bugs/utf8_svn_log.mdwn new file mode 100644 index 000000000..abd957719 --- /dev/null +++ b/doc/bugs/utf8_svn_log.mdwn @@ -0,0 +1,11 @@ +svn log messages containing utf-8 (such as r773) don't get displayed +right in RecentChanges. The problem is ikiwiki runs svn log in locale C, +which makes it spit out eacaped charcters for utf-8 chars. If it's run in +locale en_US.UTF-8, it would be ok, but that would require the system +have that locale. + +Seems that the right fix for this is to use svn log --xml, which is +always utf-8 and come up with a parser for that. Also fixes the spoofing +issue in [[security]]. + +[[bugs/done]] diff --git a/doc/bugs/utf8_warnings_are_meaningless.mdwn b/doc/bugs/utf8_warnings_are_meaningless.mdwn new file mode 100644 index 000000000..7c1efa0a0 --- /dev/null +++ b/doc/bugs/utf8_warnings_are_meaningless.mdwn @@ -0,0 +1,9 @@ +Hunting down what was generating + + utf8 "\xEB" does not map to Unicode at /usr/share/perl5/IkiWiki.pm line 873, <$in> chunk 1. + +lead me to a call to `utf8::valid`, which lead to http://perldoc.perl.org/utf8.html which says this is an "INTERNAL" function: + +> Main reason for this routine is to allow Perl's testsuite to check that operations have left strings in a consistent state. You most probably want to use `utf8::is_utf8()` instead. + +Apparently the main point of the function is to emit the warning in unit tests - problem is, in the ikiwiki context, the only useful thing to warn about would be the name of the file you're trying to parse, not the name of the source code. Alternatively, since the code does continue on with the data, *not* whining about it might be an option :-) but an actionable message would be better. diff --git a/doc/bugs/web_reversion_on_ikiwiki.info.mdwn b/doc/bugs/web_reversion_on_ikiwiki.info.mdwn new file mode 100644 index 000000000..6f18cfcba --- /dev/null +++ b/doc/bugs/web_reversion_on_ikiwiki.info.mdwn @@ -0,0 +1,14 @@ +I created [[sandbox/revert me]] and then tried the revert button on +[[recentchanges]], but I was not allowed to revert it. The specific error +was + + Error: you are not allowed to change sandbox/revert_me.mdwn + +I've just tried reading through the revert code, and I haven't figured out +what permission I am lacking. Perhaps the error message could be a little +clearer on that. The error might have been thrown by git_parse_changes in +git.pm or check_canchange in IkiWiki.pm, via IkiWiki::Receive. -- Jon + +[[fixed|done]] --[[Joey]] + +: Brilliant, many thanks. -- [[Jon]] diff --git a/doc/bugs/websetup_eats_setupconf_and_allow__95__symlinks__95__before__95__srcdir.mdwn b/doc/bugs/websetup_eats_setupconf_and_allow__95__symlinks__95__before__95__srcdir.mdwn new file mode 100644 index 000000000..47063d5cf --- /dev/null +++ b/doc/bugs/websetup_eats_setupconf_and_allow__95__symlinks__95__before__95__srcdir.mdwn @@ -0,0 +1,21 @@ +My web server runs in a chroot jail. This makes things interesting because the paths are slightly different depending on whether you are inside or outside the chroot. + +To override an incorrectly guessed path, I set setupconf in the .setup file. I also set allow_symlinks_before_srcdir=>1. However, when I tried websetup, the setup file was correctly changed but these important settings disappeared. This seems like a bug. + +> I don't know what "setupconf" is. This is the first mention of it in the +> ikiwiki source tree. +> +> I've fixed the `allow_symlinks_before_srcdir` issue. --[[Joey]] + +I meant setupfile as in IkiWiki::Setup::dump($config{setupfile}) from IkiWiki/Plugin/websetup.pm + +Sorry for the confusion. + +> Ok, that's an internal setting that I never envisioned someone digging +> out and setting in their setup file. It could be made an exported config +> option, but then every generated setup file will have this setting in it, +> which will be at best redundant. +> +> Can you find another solution, such as a symlink, for your special case? + +I see your point. [[done]] diff --git a/doc/bugs/weird_signature_in_match__95__included__40____41__.mdwn b/doc/bugs/weird_signature_in_match__95__included__40____41__.mdwn new file mode 100644 index 000000000..cd9f27735 --- /dev/null +++ b/doc/bugs/weird_signature_in_match__95__included__40____41__.mdwn @@ -0,0 +1,7 @@ +Is this a bug? IkiWiki/Plugins/conditional.pm: + +`sub match_included ($$;$) { #{{{` + +The other match_XXX functions seem to take ($$;@). --Ethan + +> indeed, [[done]] --[[Joey]] diff --git a/doc/bugs/weird_syntax_in_aggregate.pm.mdwn b/doc/bugs/weird_syntax_in_aggregate.pm.mdwn new file mode 100644 index 000000000..632ff2c35 --- /dev/null +++ b/doc/bugs/weird_syntax_in_aggregate.pm.mdwn @@ -0,0 +1,9 @@ + open (IN, "$config{wikistatedir}/aggregate" || + die "$config{wikistatedir}/aggregate: $!"); + +It looks like the intent was "open this file, and die if you can't", +but I'm pretty sure it actually means "open this file and ignore errors +silently". Shouldn't this be `open(IN, $file) || die "$file: $!";` +(i.e. with the parens before the call to `die`)? --Ethan + +> Thanks, [[done]] --[[Joey]] diff --git a/doc/bugs/wiki_formatting_does_not_work_between_toc_and_an_inline.mdwn b/doc/bugs/wiki_formatting_does_not_work_between_toc_and_an_inline.mdwn new file mode 100644 index 000000000..29e03f2d6 --- /dev/null +++ b/doc/bugs/wiki_formatting_does_not_work_between_toc_and_an_inline.mdwn @@ -0,0 +1,30 @@ +Wiki formatting between `\[[!toc ]]` and an inline fails to render. The +problem does not seem to trigger if the inline uses the titlepage template, +or if it doesn't match any pages. See example below; also reproducible +with a single-file wiki containing the text below, rendered via `ikiwiki +--plugin toc`. + +> This is [[!debbug 421843]], and I suspect it affects certian other plugins +> that also use empty divs as placeholders. It's fixed in markdown 1.0.2 b7 +> (available in debian experimental). So I'll [[close|done]] this as it's +> not really an ikiwiki bug. --[[Joey]] + +[[!toc ]] + +**not bold** + +`not fixed-pitch` + +# heading not rendered + +[not a link](http://ikiwiki.info) + +[[!inline pages="news/*" description="Sparse News" show=1 feeds=no]] + +**bold** + +`fixed-pitch` + +# heading rendered + +[a link](http://ikiwiki.info) diff --git a/doc/bugs/wiki_links_still_processed_inside_code_blocks.mdwn b/doc/bugs/wiki_links_still_processed_inside_code_blocks.mdwn new file mode 100644 index 000000000..9f0a1d102 --- /dev/null +++ b/doc/bugs/wiki_links_still_processed_inside_code_blocks.mdwn @@ -0,0 +1,67 @@ +In [[ikiwiki/markdown]] syntax, none of the other special characters get processed +inside a code block. However, in ikiwiki, [[wiki_links|ikiwiki/wikilink]] and +[[preprocessor_directives|ikiwiki/directive]] still get processed +inside a code block, requiring additional escaping. For example, `[links +don't work](#here)`, but `a [[ikiwiki/wikilink]] becomes HTML`. --[[JoshTriplett]] + +Indented lines provide a good way to escape a block of text containing +markdown syntax, but ikiwiki links like \[[this]] are still +interpreted within such a block. I think that intepretation should not +be happening. That is I should be able to write: + + [[this]] + +and have it render like: + + \[[this]] + +--[[cworth]] + +---- + +> Has there been any progress or ideas on this bug recently? I use an +> expanded CamelCase regexp, and without much escaping in freelink text, or +> url links, or in codeblocks I get IkiWiki's attempt at creating a "link +> within a link". +> +> I have no ideas other than perhaps once IkiWiki encounters \[\[ or the +> position is reset with a backreference from a CamelCased word, further +> processing of wikilinks is disabled until the position is reset and a "no +> not makelinks" flag or variable is cleared. +> +> I've come up with some _really_ ugly workarounds to handle case specific +> stuff like codeblocks but the problem creeps up again and again in +> unexpected places. I'd be happy to come up with a patch if anyone has a +> bright idea on a nice clean way (_in theroy_) to fix this. I'm out of ideas. +> +> --CharlesMauch + +> I've moved the above comment here because it seems to be talking about +> this bug, not the similar Smileys bug. +> +> In the case of either bug, no, I don't have an idea of a solution yet. +> --[[Joey]] + +> I've now solved a similar bug involving the smiley plugin. The code used +> there should give some strong hints how to fix this bug, though I haven't +> tried to apply the method yet. --[[Joey]] + +>> As far, as I can see, smileys bug is solved by checking for code/pre. In +>> this case, however, this is not applicable. WikiLinks/directives *should* be +>> expanded before passing text to formatter, as their expansion may contain +>> markup. Directives should be processed before, as they may provide *partial* +>> markup (eg `template` ones), that have no sense except when in the page +>> cotext. Links should be processed before, because, at least multimarkdown may +>> try to expand them as anchor-links. +>> +>> For now, my partial solution is to restrict links to not have space at the +>> start, this way in many cases escaping in code may be done in natural way +>> and not break copypastability. For example, shell 'if \[[ condition ]];' +>> will work fine with this. +>> +>> Maybe directives can also be restricted to only be allowed on the line by +>> themselves (not separated by blank lines, however) or something similar. +>> +>> --[[isbear]] + +[[!debbug 487397]] diff --git a/doc/bugs/wiki_rebuild_should_throw_errors_if_the_configured_underlaydir_or_templatedir_don__39__t_exist.mdwn b/doc/bugs/wiki_rebuild_should_throw_errors_if_the_configured_underlaydir_or_templatedir_don__39__t_exist.mdwn new file mode 100644 index 000000000..c8f6ed05f --- /dev/null +++ b/doc/bugs/wiki_rebuild_should_throw_errors_if_the_configured_underlaydir_or_templatedir_don__39__t_exist.mdwn @@ -0,0 +1,15 @@ +I originally set up ikiwiki by using the debian package, but had some odd issues, so i figured i'd try installing from git. To do that i uninstalled the debian package and then did the Makefile dance from the git dir. In that process the original dirs configured in templatedir underlaydir in my wiki were deleted; HOWEVER when rebuilding the script just went ahead and did not even note the lack of those dirs. It would be nice if it threw errors if the dirs were configured, but non-existant. + +> Hmm. This behavior was explicitly coded into ikiwiki for underlay dirs: +> [commit](http://source.ikiwiki.branchable.com/?p=source.git;a=commitdiff;h=cb4b99929757f970d5ae697f0d09514ad624ed46). +> Pity I didn't say why, but presumably there are cases +> where one of the underlaydirs is expected to be missing, or where +> this robustness of not crashing is needed. +> +> The situation with missing templatedirs is more clear: When +> it's looking for a given template file it just tries to open it in each +> directory in turn, and uses the first file found; checking that a +> directory exists would be extra work and there's a nice error message if +> a template cannot be found. --[[Joey]] + +>> I'd agree with the thought behind that ... if it actually had thrown an error. However it did not. How about just checking the config variables when the template and/or config is set up? --Mithaldu diff --git a/doc/bugs/wikilink_in_table.mdwn b/doc/bugs/wikilink_in_table.mdwn new file mode 100644 index 000000000..cca01718c --- /dev/null +++ b/doc/bugs/wikilink_in_table.mdwn @@ -0,0 +1,36 @@ +I try to create wikilink in table. But it does not work. Here is example: + + \[[!table class=table1 data=""" + \[[wikilink_test|index]] + \[[wikilink_test\|index]] + [wikilink test](/servers/webmail1) + """]] + +First two wikilink entries do not work. + +The last one is url link and it works but it is not a wikilink. Or maybe it does not matter if I use URL links in stead of wikilinks for local wiki content? + +> [[fixed|done]] --[[Joey]] + +>> works !! Great! + +What exactly is a difference between wikilink and URL reference to the same page ? + +> ikiwiki will not be able to track pages linked using urls as having a +> link. + +Trying to report this I found something weird. I changed in the example [[ with || because wiki renders something wrongly. You can see what I tried originally here: + + \[[!table class=table1 data=""" + \[[wikilink_test|servers/webmail1]] + \[[wikilink_test|servers/webmail1]] + [wikilink test](/servers/webmail1) + """]] + +Please click edit to see unrendered text. First, it is not monospace-d (I have 4 spaces) and second, some wierd html is shown... +Am I doing something wrong ? + +> See above for the right way to do it. Note that I also fixed a minor bug +> in ikiwiki to allow this. --[[Joey]] + +>> Just curious ... if I wanted to have that block in monospace (four spaces in front of each line), how can I do that ? diff --git a/doc/bugs/word_wrap.mdwn b/doc/bugs/word_wrap.mdwn new file mode 100644 index 000000000..95cfc1538 --- /dev/null +++ b/doc/bugs/word_wrap.mdwn @@ -0,0 +1,16 @@ +Web browsers don't word-wrap lines in submitted text, which makes editing a +page that someone wrote in a web browser annoying (`gqip` is vim user's +friend here). Is there any way to improve this? + +> See "using the web interface with a real text editor" on the [[tips]] +> page. --[[JoshTriplett]] + +>> Would it be useful to allow a "max width" plugin, which would force on commit the split of long lines ? + +>>> Please, no. That would wreak havoc on code blocks and arguments to +>>> preprocessor directives, and it would make bulleted lists and quoted +>>> blocks look bogus (because the subsequent lines would not match), among +>>> other problems. On the other hand, if you want to propose a piece of +>>> client-side JavaScript that looks at the active selection in a text area +>>> and word-wraps it, and have a plugin that adds a "Word-Wrap Selection" +>>> button to the editor, that seems fine. --[[JoshTriplett]] diff --git a/doc/bugs/wrapper_can__39__t_find_the_perl_modules.mdwn b/doc/bugs/wrapper_can__39__t_find_the_perl_modules.mdwn new file mode 100644 index 000000000..9804d86c5 --- /dev/null +++ b/doc/bugs/wrapper_can__39__t_find_the_perl_modules.mdwn @@ -0,0 +1,16 @@ +If i intsall perl modules in my custom directory, cgi wrapper can't find them. I found clearing enviroment variables in code of wrapper. But information about custom directories put to perl with PERL5LIB variable. + +Workaround: add newenviron variable PERL5LIB + +My additional question - what wrapper do? I'am russian hosting provider. I am interesting with ikiwiki. + +> The wrapper allows ikiwiki to run as the user who owns the wiki, which +> is generally not the same as the user that runs the web server. +> (It also handles some other things, like some locking.) +> +> As a suid program, the wrapper cannot safely let environment variables +> pass through. +> +> If you want to install ikiwiki's perl modules in a nonstandard location, +> you can set `INSTALL_BASE` when running `Makefile.PL`. ikiwiki will then +> be built to look in that location. --[[Joey]] [[!tag done]] diff --git a/doc/bugs/wrong_attachment_size.mdwn b/doc/bugs/wrong_attachment_size.mdwn new file mode 100644 index 000000000..958576d5d --- /dev/null +++ b/doc/bugs/wrong_attachment_size.mdwn @@ -0,0 +1,8 @@ +Using ikiwiki 3.20100815.7 on Debian Squeeze or ikiwiki 3.20100815~bpo50+1 on Debian Lenny, the [[attachments|plugins/attachment] list on an edit page all show the same (wrong) file size, which is the size of one of the files. +You can see the phenomenon on this wiki page: +<http://tools.ipol.im/ikiwiki.cgi?page=sandbox&do=edit>. + +-- [[nil|users/nil]] + +> This bug was fixed in version 3.20100926: "attachment: Fix attachment file size +> display." [[done]] --[[Joey]] diff --git a/doc/bugs/wrong_discussion_page_created.mdwn b/doc/bugs/wrong_discussion_page_created.mdwn new file mode 100644 index 000000000..f9399da72 --- /dev/null +++ b/doc/bugs/wrong_discussion_page_created.mdwn @@ -0,0 +1,12 @@ +I seem to have broken Discussion page creation links. --[[Joey]] + +For the toplevel, it needs to save to index/discussion. index/Discussion +or Discussion won't work. It defaults to Discussion on the toplevel. +And this is particularly bad as it breaks all other discussion links on +other pages. + +For other pages, it should save to page/discussion. page/Discussion does +not work. And it defaults to Discussion which is just *wrong*. + +> This was broken by [[Titles_are_lower-cased_when_creating_a_page]]. +> Added a fix. [[done]] --[[Joey]] diff --git a/doc/bugs/wrong_link_in_recentchanges_when_reverting_an_ikiwiki_outside_git_root.mdwn b/doc/bugs/wrong_link_in_recentchanges_when_reverting_an_ikiwiki_outside_git_root.mdwn new file mode 100644 index 000000000..5f7450b79 --- /dev/null +++ b/doc/bugs/wrong_link_in_recentchanges_when_reverting_an_ikiwiki_outside_git_root.mdwn @@ -0,0 +1,8 @@ +in ikiwiki instances that don't reside in the git root directory (the only ones i know of are ikiwiki itself), reverts show the wrong link in the recentchanges (for example, in the ikiwiki main repository's 4530430 and its revert, the main index page was edited, but the revert shows doc/index as a link). + +the expected behavior is to compensate for the modified root directory (i.e., show index instead of doc/index). + +> This seems to work OK now - commit 84c4ca33 and its reversion both +> appear correctly in [[recentchanges]]. Looking at git history, +> Joey [[fixed this|done]] in commit 1b6c1895 before 3.20120203. +> --[[smcv]] diff --git a/doc/bugs/wrong_permissions_on_some_files_in_source.mdwn b/doc/bugs/wrong_permissions_on_some_files_in_source.mdwn new file mode 100644 index 000000000..2cecd8b1b --- /dev/null +++ b/doc/bugs/wrong_permissions_on_some_files_in_source.mdwn @@ -0,0 +1,11 @@ +A few files in the source are only readable by root: +ikiwiki/basewiki/favicon.ico +ikiwiki/doc/logo/ikiwiki_large.png +ikiwiki/doc/logo/ikiwiki.svgz +ikiwiki/templates/atomitem.tmpl +ikiwiki/templates/atompage.tmpl + +This means that (depending on installation) maybe the permissions are wrong for the final install. +So when ikiwiki is ran (as non-root) it fails. + +> [[bugs/done]] (in my tree) --[[Joey]] diff --git a/doc/bugs/wrong_rss_url_when_inside_another_blog-like_page.mdwn b/doc/bugs/wrong_rss_url_when_inside_another_blog-like_page.mdwn new file mode 100644 index 000000000..f1dde7e9f --- /dev/null +++ b/doc/bugs/wrong_rss_url_when_inside_another_blog-like_page.mdwn @@ -0,0 +1,36 @@ +I have a blog-like page collecting item, that's ok, display is good, rss +url is correct. In some of the items, I have another rss. When viewing the +item itself, url of the rss is correct. But when viewing the item inside +the main page, the basepath of the rss is wrong, thus the url doesn't go +anywhere. + +For example : + +(1) a blog-like page which is collecting tag entry : + +* address of the page : /tag.html +* address of the rss : /tag.rss + +(2) a tag item "foo" +which is containing a rss, listing all the foo-tagged pages. + +* address of the item : /tag/foo.html +* address of the rss : /tag/foo.rss + +(3) when viewing /tag.html + +* the rss url inside tag/foo.html is /foo.rss, not /tag/foo.rss + +Is it a bug or did I miss something ? + +> I've fixed at least +> two bugs in this area in the unreleased ikiwiki in subversion, one just +> now. If you still see the problem using the ikiwiki version in +> subversion, it would be helpful if you could post a tarball of your wiki, +> or a test case derived from it that I can use to reproduce the problem +> --[[Joey]] + +>> Joey, thank you, it's ok now. (since the version 1.40, AFAIK, maybe earlier) +>> --Hugues (hb) + +>>> Thanks for the followup, tagging this [[bugs/done]]. diff --git a/doc/bugs/xgettext_issue.mdwn b/doc/bugs/xgettext_issue.mdwn new file mode 100644 index 000000000..dc49c69a1 --- /dev/null +++ b/doc/bugs/xgettext_issue.mdwn @@ -0,0 +1,73 @@ +I ran into a problem when installing from svn. I got "invalid variable +interpolation" errors for Wrappers.pm. I added the flag '--extract-all' to +'po/Makefile' and 'po/t' to the xgettext line. Once I did that I was able +to make and make test just fine. --HarleyPig + +> It would be helpful if you could post the actual error message you saw. +> Also would be nice to know what versions of perl and gettext you have. +> Perhaps your xgettext is an older version from before it natively +> supported perl. +> Adding --extract-all doesn't seem like a good idea, since this causes it +> to treat every string in the entire wiki as translatable. I don't know +> what you're talking about regarding 'po/t'. --[[Joey]] + +>> make[1]: Entering directory `/home/www/ikiwiki/po' +>> Rebuilding the pot file +>> xgettext ../IkiWiki/CGI.pm ../IkiWiki/Plugin/aggregate.pm ../IkiWiki/Plugin/brokenlinks.pm ../IkiWiki/Plugin/camelcase.pm ../IkiWiki/Plugin/ddate.pm ../IkiWiki/Plugin/favicon.pm ../IkiWiki/Plugin/fortune.pm ../IkiWiki/Plugin/goodstuff.pm ../IkiWiki/Plugin/googlecalendar.pm ../IkiWiki/Plugin/haiku.pm ../IkiWiki/Plugin/html.pm ../IkiWiki/Plugin/htmlscrubber.pm ../IkiWiki/Plugin/htmltidy.pm ../IkiWiki/Plugin/httpauth.pm ../IkiWiki/Plugin/img.pm ../IkiWiki/Plugin/inline.pm ../IkiWiki/Plugin/linkmap.pm ../IkiWiki/Plugin/map.pm ../IkiWiki/Plugin/mdwn.pm ../IkiWiki/Plugin/meta.pm ../IkiWiki/Plugin/mirrorlist.pm ../IkiWiki/Plugin/openid.pm ../IkiWiki/Plugin/orphans.pm ../IkiWiki/Plugin/otl.pm ../IkiWiki/Plugin/pagecount.pm ../IkiWiki/Plugin/pagestats.pm ../IkiWiki/Plugin/passwordauth.pm ../IkiWiki/Plugin/poll.pm ../IkiWiki/Plugin/polygen.pm ../IkiWiki/Plugin/rawhtml.pm ../IkiWiki/Plugin/rst.pm ../IkiWiki/Plugin/search.pm ../IkiWiki/Plugin/shortcut.pm ../IkiWiki/Plugin/sidebar.pm ../IkiWiki/Plugin/skeleton.pm ../IkiWiki/Plugin/smiley.pm ../IkiWiki/Plugin/tag.pm ../IkiWiki/Plugin/template.pm ../IkiWiki/Plugin/textile.pm ../IkiWiki/Plugin/toc.pm ../IkiWiki/Plugin/toggle.pm ../IkiWiki/Plugin/typography.pm ../IkiWiki/Plugin/wikitext.pm ../IkiWiki/Rcs/Stub.pm ../IkiWiki/Rcs/git.pm ../IkiWiki/Rcs/mercurial.pm ../IkiWiki/Rcs/svn.pm ../IkiWiki/Rcs/tla.pm ../IkiWiki/Render.pm ../IkiWiki/Setup.pm ../IkiWiki/Setup/Standard.pm ../IkiWiki/UserInfo.pm ../IkiWiki/Wrapper.pm ../ikiwiki.in ../IkiWiki.pm -o ikiwiki.pot -Lperl --add-comments=translators ../IkiWiki/Wrapper.pm:64: invalid variable interpolation at "$" +>> make[1]: *** [ikiwiki.pot] Error 1 +>> make[1]: Leaving directory `/home/www/ikiwiki/po' +>> make: *** [extra_build] Error 2 +>> +>> harleypig ikiwiki # xgettext --version +>> +>> xgettext (GNU gettext-tools) 0.15 +>> +>> harleypig ikiwiki # perl -v +>> +>> This is perl, v5.8.8 built for i686-linux +>> +>> Sorry about the po/t report ... it was the test file I used to figure out what was wrong and I forgot to remove it. This is against the subversion repository, version 2338. +>> The referenced line has a $! variable, which the documentation for gettext indicates is the problem. + +>>> Ok, I think that you need to upgrade xgettext to 0.16. However, there's +>>> no reason why you should need to rebuild the pot file anyway, so I've +>>> checked it into svn, and that's one problem [[bugs/done]]. + +>>>> FWIW, I get the same error when building manually from SVN trunk on Ubuntu Edgy. I'm also using xgettext 0.15, because it's the latest version that's in the repos. However, +>>>> I don't think that's the sole problem because I can build fine on another (Debian) box which is running _0.14.4_... I know very little about `gettext`, but could this be +>>>> related to my language settings? On the Edgy box I have `LANGUAGE=en_GB:en` and `LANG=en_GB.UTF-8`. The `ikiwiki` package installs on Edgy with no problems. --Ben + +>>>>> You'll only see the problem if it needs to rebuild po/ikiwiki.pot, +>>>>> which it generally doesn't if you're just building the package. If +>>>>> you edit files and build, it will rebuilt the pot and then fail with +>>>>> older gettexts. --[[Joey]] + +>>>>>> I guess I'm confused then, because I do get that error when I just build. :-( To reproduce: + + svn co svn://ikiwiki.kitenet.net/ikiwiki/trunk ikiwiki + cd ikiwiki + perl Makefile.PL + make + +>>>>>> Then I see: + +<pre> +./mdwn2man ikiwiki 1 doc/usage.mdwn > ikiwiki.man +./mdwn2man ikiwiki-mass-rebuild 8 doc/ikiwiki-mass-rebuild.mdwn > ikiwiki-mass-rebuild.man +./pm_filter /usr/local 1.44 /usr/local/share/perl/5.8.8 < ikiwiki.in > ikiwiki.out +make -C po +make[1]: Entering directory `/home/ben/tmp/ikiwiki/po' +Rebuilding the pot file +xgettext ../IkiWiki/CGI.pm ../IkiWiki/Plugin/aggregate.pm ../IkiWiki/Plugin/anonok.pm ../IkiWiki/Plugin/brokenlinks.pm ../IkiWiki/Plugin/camelcase.pm ../IkiWiki/Plugin/conditional.pm ../IkiWiki/Plugin/ddate.pm ../IkiWiki/Plugin/favicon.pm ../IkiWiki/Plugin/fortune.pm ../IkiWiki/Plugin/goodstuff.pm ../IkiWiki/Plugin/googlecalendar.pm ../IkiWiki/Plugin/haiku.pm ../IkiWiki/Plugin/html.pm ../IkiWiki/Plugin/htmlscrubber.pm ../IkiWiki/Plugin/htmltidy.pm ../IkiWiki/Plugin/httpauth.pm ../IkiWiki/Plugin/img.pm ../IkiWiki/Plugin/inline.pm ../IkiWiki/Plugin/linkmap.pm ../IkiWiki/Plugin/lockedit.pm ../IkiWiki/Plugin/map.pm ../IkiWiki/Plugin/mdwn.pm ../IkiWiki/Plugin/meta.pm ../IkiWiki/Plugin/mirrorlist.pm ../IkiWiki/Plugin/more.pm ../IkiWiki/Plugin/opendiscussion.pm ../IkiWiki/Plugin/openid.pm ../IkiWiki/Plugin/orphans.pm ../IkiWiki/Plugin/otl.pm ../IkiWiki/Plugin/pagecount.pm ../IkiWiki/Plugin/pagestats.pm ../IkiWiki/Plugin/passwordauth.pm ../IkiWiki/Plugin/poll.pm ../IkiWiki/Plugin/polygen.pm ../IkiWiki/Plugin/prettydate.pm ../IkiWiki/Plugin/rawhtml.pm ../IkiWiki/Plugin/rst.pm ../IkiWiki/Plugin/search.pm ../IkiWiki/Plugin/shortcut.pm ../IkiWiki/Plugin/sidebar.pm ../IkiWiki/Plugin/signinedit.pm ../IkiWiki/Plugin/skeleton.pm ../IkiWiki/Plugin/smiley.pm ../IkiWiki/Plugin/tag.pm ../IkiWiki/Plugin/template.pm ../IkiWiki/Plugin/textile.pm ../IkiWiki/Plugin/toc.pm ../IkiWiki/Plugin/toggle.pm ../IkiWiki/Plugin/typography.pm ../IkiWiki/Plugin/wikitext.pm ../IkiWiki/Rcs/Stub.pm ../IkiWiki/Rcs/git.pm ../IkiWiki/Rcs/mercurial.pm ../IkiWiki/Rcs/svn.pm ../IkiWiki/Rcs/tla.pm ../IkiWiki/Render.pm ../IkiWiki/Setup.pm ../IkiWiki/Setup/Standard.pm ../IkiWiki/UserInfo.pm ../IkiWiki/Wrapper.pm ../ikiwiki.in ../IkiWiki.pm -o ikiwiki.pot -Lperl --add-comments=translators +../IkiWiki/Wrapper.pm:64: invalid variable interpolation at "$" +make[1]: *** [ikiwiki.pot] Error 1 +make[1]: Leaving directory `/home/ben/tmp/ikiwiki/po' +make: *** [extra_build] Error 2 +</pre> + +>>>>>> Other than installing a newer version of `gettext` from outside of the repos, is there any workaround? + +>>>>>>> It's probably because you're pulling it from svn, and I don't +>>>>>>> always update the pot file every time I commit to svn. So this will +>>>>>>> affect svn checkouts, but not released tarballs. Anyway, I put in a +>>>>>>> workaround.. [[bugs/done]] --[[Joey]] diff --git a/doc/bugs/yaml:xs_codependency_not_listed.mdwn b/doc/bugs/yaml:xs_codependency_not_listed.mdwn new file mode 100644 index 000000000..3ae156db6 --- /dev/null +++ b/doc/bugs/yaml:xs_codependency_not_listed.mdwn @@ -0,0 +1,16 @@ +YAML:XS is not listed as a dep in the spec file which results in + +``` +HOME=/home/me /usr/bin/perl -Iblib/lib ikiwiki.in -dumpsetup ikiwiki.setup +Can't locate YAML/XS.pm in @INC (@INC contains: . blib/lib /usr/local/lib64/perl5 /usr/local/share/perl5 /usr/lib64/perl5/vendor_perl /usr/share/perl5/vendor_perl /usr/lib64/perl5 /usr/share/perl5) at (eval 39) line 2. +BEGIN failed--compilation aborted at (eval 39) line 2. +make: *** [ikiwiki.setup] Error 2 +error: Bad exit status from /var/tmp/rpm-tmp.Sgq2QK (%build) +``` + +when trying to build + +> Ok, added. [[done]] --[[Joey]] +>> Appears to be missing in 'Makefile.PL' also. -- [[ttw]] + +>>> Added --[[Joey]] diff --git a/doc/bugs/yaml_setup_file_does_not_support_UTF-8_if_XS_is_installed.mdwn b/doc/bugs/yaml_setup_file_does_not_support_UTF-8_if_XS_is_installed.mdwn new file mode 100644 index 000000000..73da32d0c --- /dev/null +++ b/doc/bugs/yaml_setup_file_does_not_support_UTF-8_if_XS_is_installed.mdwn @@ -0,0 +1,104 @@ +I converted an ikiwiki setup file to YAML as +[[documented|tips/yaml_setup_files]]. + +On my Debian Squeeze system, attempting to build the wiki using the +YAML setup file triggers the following error message: + + YAML::XS::Load Error: The problem: + + Invalid trailing UTF-8 octet + + was found at document: 0 + usage: ikiwiki [options] source dest + ikiwiki --setup configfile + +Indeed, my setup file contains UTF-8 characters. + +Deinstalling YAML::XS ([[!debpkg libyaml-libyaml-perl]]) resolves this +issue. According to YAML::Any's POD, YAML::Syck is used instead of +YAML::XS in this case since it's the best YAML implementaion available +on my system. + +No encoding-related setting is mentionned in YAML::XS' POD. We may +consider there is a bug in there. I'll see if it's known / fixed +somewhere as soon as I get online. + +Joey, as a (hopefully) temporary workaround, what do you think of +explicitely using YAML::Syck (or whatever other YAML implementation +that does not expose this bug) rather than letting YAML::Any pick its +preferred one? + +--[[intrigeri]] + +> Upgrading YAML::XS ([[!debpkg libyaml-libyaml-perl]]) to current sid +> version (0.34-1) fixes this bug for me. --[[intrigeri]] + +>> libyaml-syck-perl's description mentions that the module is now +>> deprecated. (I had to do some ugly workaround to make unicode work with +>> Syck earlier.) So it appears the new YAML::Xs is the +>> way to go longterm, and presumably YAML::Any will start depending on it +>> in due course? --[[Joey]] + +>>> Right. Since this bug is fixed in current testing/sid, only +>>> Squeeze needs to be taken care of. As far as Debian Squeeze is +>>> concerned, I see two ways out of the current buggy situation: +>>> +>>> 1. Add `Conflicts: libyaml-libyaml-perl (< 0.34-1~)` to the +>>> ikiwiki packages uploaded to stable and squeeze-backports. +>>> Additionally uploading the newer, fixed `libyaml-libyaml-perl` +>>> to squeeze-backports would make the resulting situation a bit +>>> easier to deal with from the Debian stable user point of view. +>>> 2. Patch the ikiwiki packages uploaded to stable and +>>> squeeze-backports: +>>> - either to workaround the bug by explicitly using YAML::Syck +>>> (yeah, it's deprecated, but it's Debian stable) +>>> - or to make the bug easier to workaround by the user, e.g. by +>>> warning her of possible problems in case YAML::Any has chosen +>>> YAML::XS as its preferred implementation (the +>>> `YAML::Any->implementation` module method can come in handy +>>> in this case). +>>> +>>> I tend to prefer the first aforementioned solution, but any of +>>> these will anyway be kinda ugly, so... + +>>>> I was wrong: I just experienced that bug with YAML::XS 0.34-1 +>>>> too. Seems like [[!cpanrt 54683]]. --[[intrigeri]] + +>>>>> Yes, [[!debbug 625713]] reports this also affects debian unstable. +>>>>> So, I will add a conflict I guess. [[done]] --[[Joey]] + +>>>>>> With the additional info and test cases I provided on the +>>>>>> Debian bug (Message #22), I now doubt this is a YAML::XS bug +>>>>>> very much. Also, the RT bug I linked to happens with `use +>>>>>> utf8`, which is not the case in ikiwiki AFAIK => I think you +>>>>>> shall reconsider whether this bug really is YAML::XS' fault, or +>>>>>> YAML::Any's fault, or Perl's fault, or... the way ikiwiki +>>>>>> slurps and untaints UTF-8 YAML setup files. Sorry for providing +>>>>>> information that may have been misguided. --[[intrigeri]] + +>>>>>>> `use utf8` is completely irrelevant; that only tells +>>>>>>> perl to support utf8 in its source code. +>>>>>>> +>>>>>>> I don't know what `Path::Class::File` is, but if it +>>>>>>> provides non-decoded bytes to the module than it would likely +>>>>>>> avoid this failure, while resulting in parsed yaml where every +>>>>>>> string was likewise not decoded unicode, which is not very useful. +>>>>>>> --[[Joey]] + +>>>>>>>> You guessed right about the non-decoded bytes being passed to +>>>>>>>> YAML::XS, except this is the way it shall be done. YAML::XS +>>>>>>>> POD reads: "YAML::XS only deals with streams of utf8 octets". +>>>>>>>> Feed it with non-decoded UTF-8 bytes and it gives you +>>>>>>>> properly encoded UTF-8 Perl strings in exchange. +>>>>>>>> +>>>>>>>> Once this has been made clear, since 1. this module indeed +>>>>>>>> seems to be the future of YAML in Perl, and 2. is depended on +>>>>>>>> by other popular software such as dh-make-perl (on the 2nd +>>>>>>>> degree), I suggest using it explicitly instead of the current +>>>>>>>> "try to support every single YAML Perl module and end up +>>>>>>>> conflicting with the now recommended one" nightmare. +>>>>>>>> --[[intrigeri]] + +>>>>>>>>> Ok, [[done]] (although YAML::Syck does also still work.) --[[Joey]] + +>>>>>>>>>> Thanks a lot. --[[intrigeri]] diff --git a/doc/cgi.mdwn b/doc/cgi.mdwn new file mode 100644 index 000000000..1448fa4d5 --- /dev/null +++ b/doc/cgi.mdwn @@ -0,0 +1,5 @@ +While ikiwiki is primarily a wiki compiler, which generates static html +pages, it does use CGI for online page editing. + +To enable CGI, you need to create and install an ikiwiki.cgi wrapper. +[[Setup]] explains how to do this. diff --git a/doc/cgi/discussion.mdwn b/doc/cgi/discussion.mdwn new file mode 100644 index 000000000..4cd7c5a9c --- /dev/null +++ b/doc/cgi/discussion.mdwn @@ -0,0 +1,22 @@ +## Markdown or CGI error prevents web-based editing + +I have a working ikiwiki configuration with an SVN backend, running on Ubuntu 7.10, Apache 2.2.4. I'm using Perl 5.8.8, however, I had to use Text::Markdown 1.0.5 from CPAN instead of the latest because I had the same issue as someone [here](http://ikiwiki.info/index/discussion/) (Namely I was getting this error until I used the old Markdown version: "*** glibc detected *** double free or corruption (!prev): 0x0922e478 *** +"). + +> aside: that might have been related to [Text::Markdown bug #37297](http://rt.cpan.org/Public/Bug/Display.html?id=37297). +> --ChapmanFlack 9Jul2008 + +CGI seems to be working at least partly - the History and Recent Changes pages both work. However, if I attempt to edit or create a page, I get this error: + Error: Failed to load plugin IkiWiki::Plugin::mdwn: Can't locate IkiWiki/Plugin/mdwn.pm in @INC (@INC contains: /etc/perl /usr/local/lib/perl/5.8.8 /usr/local/share/perl/5.8.8 /usr/lib/perl5 /usr/share/perl5 /usr/lib/perl/5.8 /usr/share/perl/5.8 /usr/local/lib/site_perl .) at (eval 6) line 2. BEGIN failed--compilation aborted at (eval 6) line 2. + +Since ikiwiki builds, it has to be finding Markdown at build time, right? What am I doing wrong here? I would appreciate a point in the right direction. Thanks. --mrled + +> Ikiwiki is failing to find `IkiWiki/Plugin/mdwn.pm` which is a plugin included in ikiwiki itself. +> So, that file must not have been installed in any of the directories in the @INC search path listed. +> Either fix the installation so ikiwiki's perl modules are installed in one of the standard locations, +> or you could use the `libdir` setting in the setup file to point ikiwiki +> at the directory the perl modules are installed. --[[Joey]] + +>> Ah hah! That helped... once I knew that it was ikiwiki's internal thing, I was able to figure out that it was a permissions issue. For the record, I didn't change permissions or the default install prefix of /usr/local (well, at least not on purpose). Thanks for your help. --mrled + +>>> Interesting.. so just a permissions problem of some sort that prevented the cgi from seeing the modules that were there in-path? --[[Joey]] diff --git a/doc/commit-internals.mdwn b/doc/commit-internals.mdwn new file mode 100644 index 000000000..3a464ffbf --- /dev/null +++ b/doc/commit-internals.mdwn @@ -0,0 +1,20 @@ +Saving this irc transcript here, since it's a fairly in-depth discussion of +how ikiwiki handles commits, locking, etc, and avoids some races while +doing so. + + <tschwinge> What happens if I edit a page and in the underground a new version is installed into the svn repository? + <tschwinge> The revision when I started editing was saved, right? + <joeyh> what happens, exactly is: + <joeyh> 1. the new version that was committed first get into svn, and ikiwiki updates its WC to have the new version + <joeyh> 2. When you save your edit, ikiwiki detects a conflict. + <joeyh> 3. It uses svn merge to try to resolve it; if it's resolved it adds your changes transparently + <joeyh> 4. If the conflict needs manual resolution, it displays the page with conflict markers in the editor for you to resolve + <tschwinge> Ok. + <joeyh> Note that in step 2, it detects the conflict by using svn info to get the current Revision of the page in the WC, and compares that to a revision that is stored when you start to edit the page + <joeyh> that's why rcs_prepedit exists, to get that revision info + <tschwinge> But isn't there a race condition? + <joeyh> well, there is locking going on too + <joeyh> ikiwiki won't update the WC in step 1. if another instance of itself is getting the Revision info + <tschwinge> Is that lockwiki()? + <joeyh> yeah + <joeyh> note that when it gets the current Revision info of a page during its conflict detection, svn could have changed the page in the repo, and the WC not been updated yet due to the lock, but this isn't a race since the commit will then fail due to a regular svn conflict and the conflict detction will still work. diff --git a/doc/competition.mdwn b/doc/competition.mdwn new file mode 100644 index 000000000..2c782ea92 --- /dev/null +++ b/doc/competition.mdwn @@ -0,0 +1,19 @@ +When I started ikiwiki in 2006, there were no other existing systems that +filled quite the niche of generating a static html wiki out of markdown +files stored in a [[VCS|rcs]]. My +[first blog about ikiwiki](http://kitenet.net/~joey/blog/entry/seeking_wiki/) +looked at some projects that were semi-close, and found them wanting. + +My hope was that besides being useful to all its [[users|ikiwikiusers]], +ikiwiki would help spread its underlying concepts. Let a thousand flowers +bloom! These are some that have sprung up since. --[[Joey]] + +* [Gitit](http://gitit.johnmacfarlane.net/) is a wiki backed by a git (or + darcs) filestore. No static rendering here; pages are generated on the fly. + It's written in Haskell and uses the amazing PanDoc to generate html + from markdown or many other formats. + +* [Markdoc](http://blog.zacharyvoase.com/post/246800035) statically builds + a wiki from markdown source (which can be in a VCS, if you check it in). + It includes a built-in webserver to ease serving the generated static + html. diff --git a/doc/consultants.mdwn b/doc/consultants.mdwn new file mode 100644 index 000000000..ee0915600 --- /dev/null +++ b/doc/consultants.mdwn @@ -0,0 +1,9 @@ +Ikiwiki is free software, worked on by various people to "scratch their +itch". Some people either don't have the time or have specialized needs and +are willing to hire someone to either maintain or add additional +functionality to ikiwiki. The following is a list of people who are +available to do consulting or other work on ikiwiki. + +* [[Joey]] wrote ikiwiki. He is available for consulting on a part-time basis. + +Feel free to add yourself to this list. diff --git a/doc/contact.mdwn b/doc/contact.mdwn new file mode 100644 index 000000000..dab092549 --- /dev/null +++ b/doc/contact.mdwn @@ -0,0 +1,10 @@ +The ikiwiki project strongly encourages collaboration through ikiwiki itself, +and thus does not have a mailing list. Anyone can create an account on +ikiwiki's own wiki. ikiwiki provides a [[bug_tracker|bugs]], a +[[TODO_list|TODO]], and "discussion" sub-pages for every page, as well as a +[[forum]] for general questions and discussion. ikiwiki +developers monitor [[RecentChanges]] closely, via the webpage, email, +and IRC, and respond in a timely fashion. + +You could also drop by the IRC channel `#ikiwiki` on +[OFTC](http://www.oftc.net/) (`irc.oftc.net`). diff --git a/doc/contact/discussion.mdwn b/doc/contact/discussion.mdwn new file mode 100644 index 000000000..7bc479463 --- /dev/null +++ b/doc/contact/discussion.mdwn @@ -0,0 +1,14 @@ +... does not having a mailing list really encourage people to "collaborate +through ikiwiki itself"? Personally, I strongly prefer to participate in +mailing lists via my mail/nntp client. I follow over 50 mailing lists, so +if I can't participate in a mailing list mail or nntp, I'll probably just +not participate at all. I suspect there are others in my situation. I +think that by not having an SMTP-driven mailing list, ikiwiki is passing up +a big opportunity to build community. -- AdamMegacz + +> If you want to gate ikiwiki's various rss feeds to email, that's +> [trivial](http://rss2email.infogami.com/) --[[Joey]] + +Also see [[this_wishlist_request|todo/provide_a_mailing_list]]. Sure, you can +collaborate with RSS and a wiki, but the ikiwiki community is not only made up +of developers. diff --git a/doc/convert.mdwn b/doc/convert.mdwn new file mode 100644 index 000000000..a6f19a802 --- /dev/null +++ b/doc/convert.mdwn @@ -0,0 +1,10 @@ +Do you have an existing wiki or blog using other software, and would like +to convert it to ikiwiki? Various tools and techniques have been developed +to handle such conversions. + +* [[tips/convert_mediawiki_to_ikiwiki]] +* [[tips/convert_moinmoin_to_ikiwiki]] +* [[tips/convert_blogger_blogs_to_ikiwiki]] +* [[tips/Movable_Type_to_ikiwiki]] + +In addition, [[JoshTriplett]] has written scripts to convert Twiki sites, see [his page](/users/JoshTriplett) for more information. diff --git a/doc/css.mdwn b/doc/css.mdwn new file mode 100644 index 000000000..bc070cb99 --- /dev/null +++ b/doc/css.mdwn @@ -0,0 +1,24 @@ +[[!meta title="CSS"]] + +## Using CSS with ikiwiki + +Ikiwiki comes with two CSS stylesheets: [[style.css]] and [[local.css]]. +The idea is to customize the second one, overriding the first one and +defining brand new rendering rules. + +While ikiwiki's default use of stylesheets is intentionally quite plain and +minimalistic, CSS allows creating any kind of look you can dream up. + +The [[theme_plugin|plugins/theme]] provides some prepackaged [[themes]] in an +easy to use way. + +The [[css_market]] page is an attempt to collect user contributed local.css +files. + +## Per-page CSS + +The [[plugins/meta]] plugin can be used to add additional style sheets to a +page. + +The [[plugins/localstyle]] plugin can be used to override the toplevel +[[local.css]] for a whole section of the wiki. diff --git a/doc/css/discussion.mdwn b/doc/css/discussion.mdwn new file mode 100644 index 000000000..dc9663e56 --- /dev/null +++ b/doc/css/discussion.mdwn @@ -0,0 +1,18 @@ +I must be doing something wrong. Running setup: + +$ ikiwiki --setup MyIkiwiki.setup + +overwrites my local.css with the default (empty) version. + +I am using ikiwiki_3.1415926.tar.gz installed into /usr/local. + +--- +Sorry. Never mind. RTFM. --refresh duh. + +> Hmm, well. Using --refresh is a good thing because it allow ikiwiki to +> update a site quicker. But, it must only be hiding the real problem. +> Sounds like you are trying to edit local.css directly inside +> the destdir. But ikiwiki has a local.css located in its basewiki, +> so when you rebuild your local mods are lost. Fix is to put you +> locally modified local.css inside the srcdir, along with the other pages +> of your wiki. --[[Joey]] diff --git a/doc/css_market.mdwn b/doc/css_market.mdwn new file mode 100644 index 000000000..376f81b8b --- /dev/null +++ b/doc/css_market.mdwn @@ -0,0 +1,70 @@ +[[!meta title="CSS Market"]] + +User contributed stylesheet files for ikiwiki. Unless otherwise noted, +these style sheets can be installed by copying them into your wiki's source +dir with a filename of `local.css`. + +Some of stylesheets have developed into fullfledged [[themes]] that are +included in ikiwiki for easy use. + +Feel free to add your own stylesheets here. (Upload as wiki pages; wiki +gnomes will convert them to css files..) + +* **[lessish.css](https://raw.github.com/spiffin/ikiwiki_lessish/master/lessish.css)**, contributed by [[Spiffin]], + A responsive stylesheet based on the [Less CSS Framework](http://lessframework.com). + Links: [PNG preview](https://github.com/spiffin/ikiwiki_lessish/blob/master/lessish_preview.png) and [GitHub repo](https://github.com/spiffin/ikiwiki_lessish). + +* **[[css_market/zack.css]]**, contributed by [[StefanoZacchiroli]], + customized mostly for *blogging purposes*, can be seen in action on + [zack's blog](http://upsilon.cc/~zack/blog/) + [[!meta stylesheet="zack"]] + +* **[[css_market/kirkambar.css]]**, contributed by [[Roktas]]. This far from perfect + stylesheet follows a [Gitweb](http://www.kernel.org/git/?p=git/git.git;a=tree;f=gitweb) + like theme, so it may provide a consistent look'n feel along with the [[rcs/git]] backend. ;-) + [[!meta stylesheet="kirkambar"]] + +* **[[css_market/embeddedmoose.css]]**, contributed by [[JoshTriplett]]. + Designed for [Embedded Moose](http://embeddedmoose.com). Some ideas from the + Debian lighttpd index.html page. + [[!meta stylesheet="embeddedmoose"]] + +* **[[02_Template.css]]**, contributed and adapted by [maxx](http://martin.wuertele.net/), [original](http://www.openwebdesign.org/viewdesign.phtml?id=3057) + designed by [jarico](http://www.openwebdesign.org/userinfo.phtml?user=jcarico) + (License: public domain). You'll need a modified page.tmpl + **[[css_market/02_Template.tmpl]]**. If you prefer + [my header image](http://martin.wuertele.net/images/header.png) you can + use it under the terms of the MIT License (see png comment). + [[!meta stylesheet="02_Template"]] + +* **[[css_market/cstamas.css]]**, contributed by [[cstamas]]. + This one is based on embeddedmoose, however it is slightly different now. + [My webpage's](http://users.itk.ppke.hu/~cstamas/tag/english) is not the same. + You can grab some pictures used as background patterns from there. + [[!meta stylesheet="cstamas"]] + +* **[[css_market/bma.css]]**, contributed by [bma](http://subvert.org.uk/~bma/). + Not quite the same as I use on my site, since that has slightly modified + templates. + [[!meta stylesheet="bma"]] + +* ** http://blog.lastlog.de/, contributed by joachim schiele; please feel free to copy. + +* **[blankoblues.css][1]**, contributed by [[Blanko]]. Can be seen on [Blankoblues Demo][2]. Local.css and templates available [here][3]. + +* **[contraste.css][4]**, contributed by [[Blanko]]. Can be seen on [Contraste Demo][5]. Local.css and templates available [here][6]. + +* **[wiki.css](http://cyborginstitute.net/includes/wiki.css)** by [[tychoish]]. + I typically throw this in as `local.css` in new wikis as a slightly more clear and readable + layout for wikis that need to be functional and elegant, but not necessarily uniquely designed. + Currently in use by the [the outeralliance wiki](http://oa.criticalfutures.com/). +* **[ikiwiked gray-green](https://github.com/AntPortal/ikiwiked/raw/master/theme/gray-green/local.css)**, contributed by [Danny Castonguay](https://antportal.com/). +* **[ikiwiked gray-orange](https://github.com/AntPortal/ikiwiked/raw/master/theme/gray-orange/local.css)**, contributed by [Danny Castonguay](https://antportal.com/). Can be seen in action at [antportal.com/wiki](https://antportal.com/wiki/). Feel free to modify and contribute on [Github](https://github.com/AntPortal/ikiwiked) +<!-- Page links --> + + [1]: http://olivier.dossmann.net/demo/ikiwiki/blankoblues/src/local.css (Download Blankoblues CSS) + [2]: http://olivier.dossmann.net/demo/ikiwiki/blankoblues/htdocs/ (Take a tour on Blankoblues Demo) + [3]: http://olivier.dossmann.net/demo/ikiwiki/blankoblues/blankoblues.tar.gz (Download local.css and templates for Blankoblues theme) + [4]: http://olivier.dossmann.net/demo/ikiwiki/contraste/src/local.css (Download Contraste CSS) + [5]: http://olivier.dossmann.net/demo/ikiwiki/contraste/htdocs/ (Take a tour on Contraste Demo) + [6]: http://olivier.dossmann.net/demo/ikiwiki/contraste/contraste.tar.gz (Download local.css and templates for Contraste theme) diff --git a/doc/css_market/02_template.css b/doc/css_market/02_template.css new file mode 100644 index 000000000..522d9a452 --- /dev/null +++ b/doc/css_market/02_template.css @@ -0,0 +1,307 @@ +/* ikiwiki local style sheet */ + +/* Add local styling here, instead of modifying style.css. */ + +/* This stylesheet is based on 02 Template + (http://www.openwebdesign.org/viewdesign.phtml?id=3057) + by jarico (http://www.openwebdesign.org/userinfo.phtml?user=jcarico) + + License: public domain + + modifications for ikiwiki by Martin Wuertele <web@wuertele.net> +*/ + +/******** General tags ********/ + +body{ + padding:0; + margin:0; + border:none; + font-family:georgia, arial; + font-size:12px; + background:url(images/bg.png) repeat-x top #4B546B; + /*background:#4B546B;*/ + color:#000000; +} + +#pagestyle{ + width:80%; + padding-top:5px; + padding-bottom:5px; + padding-left:5px; + padding-right:5px; + margin:0 auto; + border:none; + background-color:#FFFFFF; + +} + +#pagehead{ + background:url(images/header.png) no-repeat center #808080; + height:203px; +} + +a{ + margin:0; + padding:0; + border-bottom:1px #8994AF dotted; + border-top:none; + border-left:none; + border-right:none; + background-color:transparent; + color:#000000; + display:inline; + color:#8994AF; + text-decoration:none; +} + +a:hover{ + margin:0; + padding:0; + border-bottom:1px #4B556A dotted; + border-top:none; + border-left:none; + border-right:none; + background-color:transparent; + color:#000000; + display:inline; + color:#4B556A; + text-decoration:none; +} + +a img{ + border:0; +} + +p{ + margin:0 0 18px 10px; +} + +pre{ + margin:0 0 18px 10px; +} + +ul,ol,dl{ +} + +ul ul,ol ol{ + margin:4px 0 4px 35px; +} + +h1{ + font-family:georgia, arial; + font-size:16px; + color:#4A5368; + text-transform:uppercase; + font-weight:bold; + padding:0; + margin-top:0; + margin-bottom:5px; + margin-left:auto; + margin-right:auto; +} + +h2{ + font-family:georgia, arial; + font-size:14px; + color:#4A5368; + text-transform:uppercase; + font-weight:bold; + padding:0; + margin-top:0; + margin-bottom:5px; + margin-left:auto; + margin-right:auto; +} + +h3{ + font-family:georgia, arial; + font-size:12px; + color:#4A5368; + text-transform:uppercase; + font-weight:bold; + padding:0; + margin-top:0; + margin-bottom:5px; + margin-left:auto; + margin-right:auto; +} + +blockquote{ +} + +#pageheader{ +} + +#afront { +} + +.header{ + width:auto; + border:none; + padding-top:1px; + padding-bottom:10px; + padding-left:5px; + padding-right:5px; + text-align:left; + margin:0; + height:20px; + line-height:20px; + font-family:georgia, arial; + font-size:12px; + color:#808080; +} + +.actions { + border-bottom: none; +} + +#backlinks{ + width:auto; + border:none; + padding-top:0; + padding-bottom:1px; + padding-left:5px; + padding-right:5px; + text-align:right; + margin:0; + height:20px; + line-height:20px; + font-family:georgia, arial; + font-size:12px; + color:#808080; +} + +div.tags { + border: none; +} + +#content{ +} + +#contentalt{ +} + +#pageinfo { + border: none; +} + +.inlinepage { + border:none; + padding:5px 10px; + margin:0 +} + +.inlinepage .header { + font-family:georgia, arial; + font-size:16px; + color:#4A5368; + text-transform:uppercase; + font-weight:bold; + padding:0; + margin-top:0; + margin-bottom:5px; + margin-left:auto; + margin-right:auto; +} + +#tags { + border: none; +} + +/******** Content variations ********/ + +.feedbutton { + color:#ffffff; + font-size:0.9em; + background-color:#4088b8; + border:1px solid #c8c8c8; + line-height:1.3em; + padding: 0px 0.5em 0px 0.5em; +} + +/*.feedbutton:hover { + color: #4088b8 !important; + background: #ffffff; +}*/ + + +/******** sidebar ********/ + +#sidebar{ + float:right; + width:175px; + background-color:#FFFFFF; + border:1px #808080 solid; + padding:5px 10px; + margin:0; + height:100% +} + +#sidebar ul{ + list-style:none; +} + +#sidebar li{ + list-style:none; +} + +#sidebar li a{ +} + +#sidebar ul ul{ +} + +#sidebar ul ul li a{ +} + +#sidebar h1{ + font-family:georgia, arial; + font-size:16px; + color:#4A5368; + text-transform:uppercase; + font-weight:bold; + padding:0; + margin-top:0; + margin-bottom:5px; + margin-left:auto; + margin-right:auto; +} + +#sidebar h2{ + margin:3px 0px 8px 0px; +} + + +/* CSS fixes */ +.popup:focus .balloon { + position: absolute; + display: inline; + margin: 1em 0 0 -2em; + padding: 0.625em; + border: 2px solid; + background-color: #dee; + color: black; +} + + + +/******** Footer ********/ +#footer{ + clear:both; + text-align:right; + color:#808080; + border-top:1px #808080 solid; + margin:0 auto; + padding:8px 0; +} + +.pagedate{ + font-size:small; + text-align:right; + margin:0; + font-family:georgia, arial; + font-size:10px; + color:#808080; + padding:8px 0; +} diff --git a/doc/css_market/02_template.tmpl b/doc/css_market/02_template.tmpl new file mode 100644 index 000000000..e35c5eb05 --- /dev/null +++ b/doc/css_market/02_template.tmpl @@ -0,0 +1,20 @@ +--- /usr/share/ikiwiki/templates/page.tmpl 2007-12-03 20:09:46.000000000 +0100 ++++ templates/page.tmpl 2007-12-05 21:15:38.000000000 +0100 +@@ -14,6 +14,9 @@ + </head> + <body> + ++<div id="pagestyle"> ++<div id="pagehead"> ++</div> + <div class="header"> + <span> + <TMPL_LOOP NAME="PARENTLINKS"> +@@ -111,5 +100,7 @@ + <!-- from <TMPL_VAR NAME=WIKINAME> --> + </div> + ++</div> ++ + </body> + </html> diff --git a/doc/css_market/bma.css b/doc/css_market/bma.css new file mode 100644 index 000000000..347f4430d --- /dev/null +++ b/doc/css_market/bma.css @@ -0,0 +1,108 @@ +/* + * local.css: stylesheet for subvert.org.uk. + * Copyright © 2008 Benjamin M. A'Lee <bma@subvert.org.uk> + * + * This work is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 3, as + * published by the Free Software Foundation. + * + * This work is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this work. If not, see <http://www.gnu.org/licenses/>. + */ + +/* Positioning first. Colours at the end. */ + +body { + font-family: sans-serif; + margin: 0; + padding: 0; +} + +#content { + margin: 1em 15em 0 1em; + padding: 2em 3em 4em 1.5em; + border: 1px solid; +} + +#sidebar { + width: 10em; + min-height: 50%; + + font-family: sans-serif; + text-align: left; + margin: 1em 1em 2em 1em; + line-height: 1em; + border: 1px solid; + + position: absolute; + right: 0; + top: 5; +} + +#sidebar h2 { + font-size: 1em; +} + + +.header { + padding: 1ex; + border-bottom: solid 1px; + margin: 0; + font-size: 1.5em; +} + +#footer { + border: 1px solid; + padding: .5em; + padding-left: 1em; + margin: 1em 15em 1em 1em; +} + +.pagedate, .pagelicense, .pagecopyright { + margin-top: 0; + margin-bottom: 0; +} + +#pageinfo { + border: none; +} + +.inlinepage { + border: none; +} + +.pagelicense p, .pagecopyright p { + display: inline; +} + +pre { + overflow: auto; + border: solid; + border-width: thin; + padding: 5px 10px; +} + +/* Set colours here. */ + +body { + background: royalblue; +} + +#content, #footer, .header { + background-color: silver; + border-color: black; +} + +#sidebar { + background-color: silver; + border-color: black; +} + +pre, code { + background-color: #EEEEEE; +} diff --git a/doc/css_market/cstamas.css b/doc/css_market/cstamas.css new file mode 100644 index 000000000..0855f3b86 --- /dev/null +++ b/doc/css_market/cstamas.css @@ -0,0 +1,69 @@ +/* This template is based on: + * "Embedded Moose local.css for use with ikiwiki + * Written by Josh Triplett <josh@freedesktop.org> + * Some ideas from the Debian lighttpd index.html page." + * + * The improoved version is made by + * Csillag Tamas <cstamas@digitus.itk.ppke.hu> + * 2008-01-?? + * */ + +body { + background: #474747; +} + +#content { + background: #333333; + margin: 10px 0px; + border: 1px dotted #c0c0c0; + padding: 10px; + font-family: sans-serif; + color: #acacac +} + +h1 { + font-size: 150%; + color: #e6deee; +} + +h2 { + font-size: 130%; + color: #e6deee; +} + +a { + color: #efefef; + border-bottom: 1px dashed; + text-decoration: none; +} + +a:hover { background: #300000; } + +pre { + color: #d0d0d0; + border: 1px dotted #c0c0c0; + background: black; + padding: 2px; + font-size: 110%; +} + +.feedbutton { background: #ff0000; } + +.header { + background: #800000; + border: 2px solid #500000; + padding: 10px; + color: #efefef; + font-family: sans-serif; +} + +.header a { margin-right: 1ex; color: #efefef; font-family: sans-serif;} +.pagedate, .tags, #backlinks { background: #640000; border: 2px solid #500000; padding: 4px; color: #efefef; font-family: sans-serif;} +.tags { color: yellow } +.selflink { background: yellow; color: black } + +.actions ul { background: #640000; border: none; padding-bottom: 0px; font-family: sans-serif;} +.actions a { margin-right: 1ex; color: #dfdfdf; font-family: sans-serif;} +#footer { border: none; font-family: sans-serif;} + + diff --git a/doc/css_market/discussion.mdwn b/doc/css_market/discussion.mdwn new file mode 100644 index 000000000..3dc47b55a --- /dev/null +++ b/doc/css_market/discussion.mdwn @@ -0,0 +1,37 @@ +What is the correct way to install the .tmpl files? -- [[JosephTurian]] + +> For themes that need them, you can set `templatedir` to some directory in +> your setup file, and put the templates there. Or install directly overtop +> ikiwiki's standard templates (in, eg `/usr/share/ikiwiki/templates`) +> --[[Joey]] + +---- + +How can I update a .css file uploaded to the CSS market? +My CSS has been updated to address comments (for the comments plugin), but I cannot find a way to update zack.css. +The most recent version is always available at: <http://git.upsilon.cc/cgi-bin/gitweb.cgi?p=zack-homepage.git;a=blob_plain;f=local.css;hb=HEAD> + +-- [[StefanoZacchiroli]] + +> Just letting me know about the change works -- updated. --[[Joey]] + +---- + +Added small changes to embeddedmoose.css to work with ikiwiki 3.x. Figured here is as good as any until Josh can review and update if he so chooses: <http://bosboot.org/tb-embeddedmoose.css>. It removes annoying borders around the header and footer. -- [[TimBosse]] + +----- + +I removed this from the list since both places to download it are broken. +--[[Joey]] + +* **Refresh**, contributed by [[FredericLespez]]. Adapted from a free template + designed by [styleshout](http://www.styleshout.com). + You can see it [here](http://fred.ccheznous.org). You can download the local.css file and + the modified templates [here](http://fred.ccheznous.org/refresh_20060602.tgz). + + * This link (above) seems to deliver an empty tarball. + + * You'll find a updated version of these templates [here](http://www.der-winnie.de/~winnie/configs/ikiwiki-templates.tar.gz). + These templates are known to work with ikiwiki 2.31, and since I'll install always the newest one on my server I'll will update them on a regular basis. + * (This link appears to be broken?) + diff --git a/doc/css_market/embeddedmoose.css b/doc/css_market/embeddedmoose.css new file mode 100644 index 000000000..3d19fca3f --- /dev/null +++ b/doc/css_market/embeddedmoose.css @@ -0,0 +1,13 @@ +/* Embedded Moose local.css for use with ikiwiki + * Written by Josh Triplett <josh@freedesktop.org> + * Some ideas from the Debian lighttpd index.html page. */ + +body { background: #e7e7e7; } + +#content { background: #ffffff; margin: 10px 0px; border: 2px solid #c0c0c0; padding: 10px; font-family: sans-serif;} + +.header { background: #4b6983; border: 2px solid #7590ae; padding: 10px; color: #ffffff; font-family: sans-serif;} +.header a { margin-right: 1ex; color: #ffffff; font-family: sans-serif;} + +.actions ul { border: none; padding-bottom: 0px; font-family: sans-serif;} +#footer { border: none; font-family: sans-serif;} diff --git a/doc/css_market/kirkambar.css b/doc/css_market/kirkambar.css new file mode 100644 index 000000000..e756a1260 --- /dev/null +++ b/doc/css_market/kirkambar.css @@ -0,0 +1,142 @@ +/* + * IkiWiki `local.css` stylesheet following the Gitweb theme. + * + * Copyright © 2006 Recai Oktaş <roktasATdebian.org> + * + * Licensed under the GNU General Public License, version 2. + * See the file `http://www.gnu.org/copyleft/gpl.txt`. + * + */ + + +/* + * ----------------------------------------------------------------------------- + * Generic style elements. + * ----------------------------------------------------------------------------- + */ + +body { + font-family: "Trebuchet MS", + "Luxi Sans", + "Bitstream Vera Sans", + "Tahoma", + "Verdana", + "Arial", + "Helvetica", + sans-serif; + padding: 1em; + margin: 0; + font-size: 100.01%; + line-height: 1.5em; + color: black; + background-color: white; +} + +pre, tt, code { + font-family: "Bitstream Vera Sans Mono", + "Luxi Mono", + "Courier New", + "Courier", + monospace; +} + +pre, tt, code, tr.changeinfo, .blogform { + color: inherit; + background-color: #f6f6f0; +} + +pre { + margin: 0px 96px 0px 48px; + padding: 12px 0px 12px 0px; +} + +h1, h2, h3, h4, h5, h6, dl, dt { + font-weight: bold; + background-color: inherit; + color: #c00040 !important; +} + +h1, h2, h3, h4, h5, h6 { + letter-spacing: .04em; +} + + +/* + * ----------------------------------------------------------------------------- + * Headers, footers. + * ----------------------------------------------------------------------------- + */ + +.header, #footer, .changeheader { + color: black !important; + background-color: #d9d8d1; +} + +.header, #footer { + height: 1.8em; + padding: 6px 6px; + border: 1px solid #aaa; + margin-bottom: 4px; + display: block; +} + +.header { + font-size: 120.01%; + font-weight: normal; + letter-spacing: .11em; +} + +span.header { + background-image: none !important; + text-align: right; +} + +.header { /* Optional header logo (right aligned). */ + background-image: url(/* ENTER HEADER LOGO PATH */); + background-repeat: no-repeat; + background-position: 99%; +} + +#footer { /* Optional footer logo (right aligned). */ + background-image: url(/* ENTER FOOTER LOGO PATH */); + background-repeat: no-repeat; + background-position: 99%; +} + + +/* + * ----------------------------------------------------------------------------- + * Specials. + * ----------------------------------------------------------------------------- + */ + +#searchform { + position: absolute; + top: 25px; + right: 90px; +} + + +td.changetime { + font-style: italic; +} + +td.changelog { + font-style: normal; + font-size: x-small; + font-weight: bold; +} + +/* + * Attribution `div` for IkiWiki. Use something like as follows: + * <div id="attribution"> + * This site is maintained using Joey Hess's + * <a href="http://ikiwiki.info/"> + * <img src="ikiwiki.png" title="IkiWiki" alt="IkiWiki" /> + * </a>. + * </div> + */ +#attribution img { + border: 1px solid black; + padding: 2px; +} diff --git a/doc/css_market/zack.css b/doc/css_market/zack.css new file mode 100644 index 000000000..5a0521d54 --- /dev/null +++ b/doc/css_market/zack.css @@ -0,0 +1,193 @@ +/* local.css stylesheet to be used with ikiwiki + * + * Copyright: (C) 2006 Stefano Zacchiroli <zack@debian.org> + * License: GNU General Public License version 2 or above. + * + * TODO + * - plone-like actions in the toplevel bar, but remember: resist the + * temptation of making them floating to the right: the breadcrumb trail can + * grow indefinitely + * - blog form aligned to the right, keeping the RSS logo to the left + * - some rendering for the tags (a la 'xhtml' logo of plone? ...) + * - some rendering for backlinks + * - some rendering for posting dates + */ + +body { + font-family: sans-serif; + font-size: medium; +} +h1, h2, h3, h4 { + font-weight: normal; +} +h1 { font-size: 140%; } +h2 { font-size: 120%; } +h3 { font-size: 110%; } +h4 { font-size: 105% } + +a { text-decoration: none; } +a:hover { text-decoration: underline; } + +.flow { + float: right; + margin-left: 10px; + margin-bottom: 10px; + text-align: center; +} + +.attrib-caption { + font-size: xx-small; + font-style: italic; +} + +input { + border: solid 1px; + border-color: #aaa; +} + +.header { font-weight: normal; } + +.selflink { text-decoration: underline; } + +.pageheader .actions ul, +#sitemeta { + border-top: solid 1px; + border-bottom: solid 1px; + font-size: small; + border-color: #aaa; + background: #eee; +} +.actions ul { + padding: 1px; + margin-top: 5px; +} +#sitemeta { + padding: 0; + margin-bottom: 5px; +} +#backlinks, +.tags { + margin-top: 0; + margin-bottom: 0; +} + +#pageinfo { + border: none; +} + +#searchform div:before { + font-size: small; + content: "search:"; +} +#searchform input { + border-top: none; + border-bottom: none; + vertical-align: bottom; + margin-right: 7px; +} + +#sidebar { + border: solid; + border-width: 1px; + padding: 0; + margin-top: 15px; + border: 1px solid; + border-color: #aaa; + background: #eee; + width: 16ex; +} +#sidebar ul { + margin: 0; + padding-left: 1em; + list-style-type: none; +} +#sidebar ul ul { + padding-left: 1.5em; + font-size: 90%; +} + +#pageinfo, +#footer { + margin: 0; +} +#pageinfo { + font-size: small; +} +.pagecopyright, +.pagelicense, +.pagedate { + margin: 0; + display: inline; +} +#backlinks { + margin-top: 5px; + margin-bottom: 10px; + font-size: larger; +} +.validation { + display: inline; + float: right; +} + +.pagecloud { + margin-left: 5px; +} + +table.identikit tr th { + text-align: right; + vertical-align: top; +} +table.identikit tr th:after { + content: ":"; +} +table.identikit tr td { + text-align: left; + vertical-align: top; +} + +.doi_logo , .doi_logo a { + background: #3965bd; + color: white !important; + font-size: 80%; + text-decoration: none; + font-family: times; + font-weight: bold; + padding: 0px 1px 0px 2px; +} + +#comments { + margin-top: 5ex; + border-top: solid 1px; + border-color: #aaa; + font-size: small; +} + +#comments #feedlink { + text-align: right; +} +#comments #feedlink:before { + content: "comment feeds: "; +} + +.addcomment { + padding: 5px; + font-style: italic; +} + +.comment { + border: none; + background-color: #eee; + margin: 5px; + margin-top: 10px; +} + +.comment-subject { + font-style: normal; +} + +.comment-header { + border-top: solid 1px; + border-color: #aaa; + text-align: right; + font-style: normal; +} diff --git a/doc/download.mdwn b/doc/download.mdwn new file mode 100644 index 000000000..100f72843 --- /dev/null +++ b/doc/download.mdwn @@ -0,0 +1,49 @@ +Here's how to get ikiwiki in source or prepackaged form. See [[setup]] for +how to use it, and be sure to add your wiki to [[IkiwikiUsers]] if you use +ikiwiki. + +## source + +Ikiwiki is developed in a [[git_repository|git]]. + +The best place to download a tarball of the latest release is from +<http://packages.debian.org/unstable/source/ikiwiki>. + +Manual installation steps and requirements are listed on the [[install]] page. + +## Debian / Ubuntu packages + +To install with [apt](http://www.debian.org/doc/manuals/debian-reference/ch02.en.html#_basic_package_management_operations), if using Debian or Ubuntu: + + apt-get install ikiwiki + +Or download the deb from <http://packages.debian.org/unstable/web/ikiwiki>. + +There is a backport of a recent version of ikiwiki for Debian 5.0 at +<http://packages.debian.org/lenny-backports/ikiwiki>. + +There is also an unofficial backport of ikiwiki for Ubuntu Jaunty, provided by +[[Paweł_Tęcza|users/ptecza]], +at [http://gpa.net.icm.edu.pl/ubuntu/](http://gpa.net.icm.edu.pl/ubuntu/index-en.html). + +## RPM packages + +Fedora versions 8 and newer have RPMs of ikiwiki available. + +Ikiwiki's source includes a RPM spec file, which you can use to build your +own RPM. + +## BSD ports + +NetBSD, Mac OS X, Solaris, and many other platforms: [pkgsrc](http://www.pkgsrc.org/) has an [ikiwiki package](http://pkgsrc.se/www/ikiwiki). + +FreeBSD has ikiwiki in its +[ports collection](http://www.freshports.org/www/ikiwiki/). + +## Other packages + +Gentoo has an [ebuild](http://bugs.gentoo.org/show_bug.cgi?id=144453) in its bug database. + +The [openSUSE Build Service](http://software.opensuse.org/search?baseproject=ALL&p=1&q=ikiwiki) has packages for openSUSE + +A [PKGBUILD for Arch Linux](http://aur.archlinux.org/packages.php?ID=12284) is in the AUR. diff --git a/doc/examples.mdwn b/doc/examples.mdwn new file mode 100644 index 000000000..19631ad47 --- /dev/null +++ b/doc/examples.mdwn @@ -0,0 +1,12 @@ +To make it easier to get started using ikiwiki for some common tasks, this +page gives some examples of ways to use ikiwiki. + +* [[blog]] - a weblog with tags, a tag cloud, archives, and an optional sidebar +* [[softwaresite]] - a website for some software package, the package + can also build static html docs from its wiki + +Each example is contained in its own subdirectory; just copy the source +files into your wiki to start using one of the examples. + +The [[tips]] page has some other ideas for ways to use ikiwiki, and the +[[css_market]] and [[theme market|themes]] has some example stylesheets to change ikiwiki's look. diff --git a/doc/examples/blog.mdwn b/doc/examples/blog.mdwn new file mode 100644 index 000000000..5f8f6c3ce --- /dev/null +++ b/doc/examples/blog.mdwn @@ -0,0 +1,26 @@ +This is an [[example_blog|index]]. Just copy the blog subdirectory into +your wiki to quickly get started blogging with ikiwiki. + +Or, run this command to set up a blog with ikiwiki. + + % ikiwiki -setup /etc/ikiwiki/auto-blog.setup + +Some additional configuration you might want to do, if not using +`auto-blog.setup`: + +* Make sure to configure ikiwiki to generate RSS or Atom feeds. + +* Make sure you have the [[tag|plugins/tag]] plugin enabled, and the + `tagbase` set to "tags". Tag pages will then automatically be created. + An example of how to tag a post is: + \[[!tag life]] + +* Enable the [[pagestats|plugins/pagestats]] plugin to get a tag cloud + to display on the [[index]]. + +* Enable the [[comments|plugins/comments]] plugin to + enable comments to posts to the blog. + +* Enable the [[calendar|plugins/calendar]] plugin and run the + [[ikiwiki-calendar]] command from cron daily to get an interlinked + set of calendar archives. diff --git a/doc/examples/blog/archives.mdwn b/doc/examples/blog/archives.mdwn new file mode 100644 index 000000000..d07b73b74 --- /dev/null +++ b/doc/examples/blog/archives.mdwn @@ -0,0 +1,8 @@ +[[!if test="archives/*" then=""" +Browse through blog archives by year: +[[!map pages="./archives/* and !./archives/*/* and !*/Discussion"]] +""" +else=""" +You need to use the `ikiwiki-calendar` program to generate calendar-based +archive pages. +"""]] diff --git a/doc/examples/blog/comments.mdwn b/doc/examples/blog/comments.mdwn new file mode 100644 index 000000000..e22b50a34 --- /dev/null +++ b/doc/examples/blog/comments.mdwn @@ -0,0 +1,10 @@ +[[!sidebar content=""" +[[!inline pages="comment_pending(./posts/*)" feedfile=pendingmoderation +description="comments pending moderation" show=-1]] +Comments in the [[!commentmoderation desc="moderation queue"]]: +[[!pagecount pages="comment_pending(./posts/*)"]] +"""]] + +Recent comments on posts in the [[blog|index]]: +[[!inline pages="./posts/*/Discussion or comment(./posts/*)" +template="comment"]] diff --git a/doc/examples/blog/discussion.mdwn b/doc/examples/blog/discussion.mdwn new file mode 100644 index 000000000..d9c716658 --- /dev/null +++ b/doc/examples/blog/discussion.mdwn @@ -0,0 +1,13 @@ +##How to remove the postform for my blog from front page? + +I have an inline to create a blog on the front page of my site. I don't want any visitors to see that form nor attempt to click "Edit" on it. I tried setting postform="no" but I did not notice any change. + +Any suggestions on how I can have a private webpage that offers the blog post form ("Add a new post titled:") and also turn off that form from my front page but still keep the blog articles displayed from the front page? + +I looked at the "inline" docs but may have overlooked this. + +I do see I can disable the editpage plugin to remove from front page. But then that made it so I can't add a new blog posting (I want to just not from the front page). + +-- [[JeremyReed]] + +> You need two separate inlines, one on your front page which can be as simple as `\[[!inline pages="blog/*"]]`, and another on a hidden/unadvertised page, which has `postform=yes` added, that you will use to add posts. Removing the 'Edit' link from the front page (and all other pages — presumably you don't want it on blog post pages either) can be achieved in a number of ways. I do it by removing it from my `page.tmpl` file (point `templatedir` in your setup file to a directory under your control; copy `/usr/share/ikiwiki/templates/page.tmpl` into it, and remember that every time ikiwiki is upgraded, potentially the file has changed, and you might need to merge in the changes). A better way might be to hide the link via CSS (`.actions { display: none; }`). You can't add pages via the web interface if you remove [[plugins/editpage]] from your setup. You should look at [[plugins/lockedit]] to make sure that only you can edit pages/submit blog posts, should anyone else stumble across your unadvertised "submit blog post" page. — [[Jon]] diff --git a/doc/examples/blog/index.mdwn b/doc/examples/blog/index.mdwn new file mode 100644 index 000000000..7914cd203 --- /dev/null +++ b/doc/examples/blog/index.mdwn @@ -0,0 +1,11 @@ +[[!if test="enabled(sidebar)" then=""" +[[!sidebar]] +""" else=""" +[[!inline pages=sidebar raw=yes]] +"""]] + +[[!inline pages="page(./posts/*) and !*/Discussion" show="10" +actions=yes rootpage="posts"]] + + +This blog is powered by [ikiwiki](http://ikiwiki.info). diff --git a/doc/examples/blog/posts.mdwn b/doc/examples/blog/posts.mdwn new file mode 100644 index 000000000..2bd0f1d6f --- /dev/null +++ b/doc/examples/blog/posts.mdwn @@ -0,0 +1,3 @@ +Here is a full list of posts to the [[blog|index]]. + +[[!inline pages="page(./posts/*) and !*/Discussion" archive=yes feedshow=10 quick=yes trail=yes]] diff --git a/doc/examples/blog/posts/first_post.mdwn b/doc/examples/blog/posts/first_post.mdwn new file mode 100644 index 000000000..343497d18 --- /dev/null +++ b/doc/examples/blog/posts/first_post.mdwn @@ -0,0 +1,2 @@ +This is the first post to this example blog. To add new posts, just add +files to the posts/ subdirectory, or use the web form. diff --git a/doc/examples/blog/sidebar.mdwn b/doc/examples/blog/sidebar.mdwn new file mode 100644 index 000000000..e0895f63f --- /dev/null +++ b/doc/examples/blog/sidebar.mdwn @@ -0,0 +1,10 @@ +[[!if test="enabled(calendar)" then=""" +[[!calendar pages="page(./posts/*) and !*/Discussion"]] +"""]] + +[[Recent Comments|comments]] + +[[Archives]] + +[[Tags]]: +[[!pagestats style="list" pages="./tags/*" among="./posts/*"]] diff --git a/doc/examples/blog/tags.mdwn b/doc/examples/blog/tags.mdwn new file mode 100644 index 000000000..b5eca5b71 --- /dev/null +++ b/doc/examples/blog/tags.mdwn @@ -0,0 +1,3 @@ +[[!pagestats pages="./tags/*" among="./posts/*"]] + +On the right you can see the tag cloud for this blog. diff --git a/doc/examples/softwaresite.mdwn b/doc/examples/softwaresite.mdwn new file mode 100644 index 000000000..99f791177 --- /dev/null +++ b/doc/examples/softwaresite.mdwn @@ -0,0 +1,19 @@ +This is an [[example_software_package_website|index]]. +Just copy the softwaresite subdirectory into your wiki to quickly produce +a website for a piece of software. + +Some additional configuration you might want to do: + +* Make sure to configure ikiwiki to generate RSS or Atom feeds. + +* The softwaresite/doc subdirectory is intended to hold docs about your + software package. These docs can be included in the package itself; + there is a [[softwaresite/Makefile]] that will use ikiwiki to build + static html documentation. ikiwiki itself uses a similar system to build + its documentation. + +* Read the [[tips/integrated_issue_tracking_with_ikiwiki]] article for tips + about how to use ikiwiki as a BTS. + +* Read [[tips/spam_and_softwaresites]] for information on how to keep spam + and spam-fighting commits out of your main version control history. diff --git a/doc/examples/softwaresite/Makefile b/doc/examples/softwaresite/Makefile new file mode 100644 index 000000000..f2c4d8e54 --- /dev/null +++ b/doc/examples/softwaresite/Makefile @@ -0,0 +1,15 @@ +# Build static html docs suitable for being shipped in the software +# package. This depends on ikiwiki being installed to build the docs. + +ifeq ($(shell which ikiwiki),) +IKIWIKI=echo "** ikiwiki not found" >&2 ; echo ikiwiki +else +IKIWIKI=ikiwiki +endif + +all: + $(IKIWIKI) `pwd` html -v --wikiname FooBar --plugin=goodstuff \ + --exclude=html --exclude=Makefile + +clean: + rm -rf .ikiwiki html diff --git a/doc/examples/softwaresite/bugs.mdwn b/doc/examples/softwaresite/bugs.mdwn new file mode 100644 index 000000000..46ead2b62 --- /dev/null +++ b/doc/examples/softwaresite/bugs.mdwn @@ -0,0 +1,4 @@ +This is FooBar's bug list. Link bugs to [[bugs/done]] when done. + +[[!inline pages="./bugs/* and !./bugs/done and !link(done) +and !*/Discussion" actions=yes postform=yes show=0]] diff --git a/doc/examples/softwaresite/bugs/done.mdwn b/doc/examples/softwaresite/bugs/done.mdwn new file mode 100644 index 000000000..ad332e2a2 --- /dev/null +++ b/doc/examples/softwaresite/bugs/done.mdwn @@ -0,0 +1,3 @@ +recently fixed [[bugs]] + +[[!inline pages="./* and link(./done) and !*/Discussion" sort=mtime show=10]] diff --git a/doc/examples/softwaresite/bugs/fails_to_frobnicate.mdwn b/doc/examples/softwaresite/bugs/fails_to_frobnicate.mdwn new file mode 100644 index 000000000..0f47e810a --- /dev/null +++ b/doc/examples/softwaresite/bugs/fails_to_frobnicate.mdwn @@ -0,0 +1,4 @@ +FooBar, when used with the `--frob` option, fails to properly frobnicate +output. + +> This is fixed in [[news/version_1.0]]; marking this bug [[done]]. diff --git a/doc/examples/softwaresite/bugs/hghg.mdwn b/doc/examples/softwaresite/bugs/hghg.mdwn new file mode 100644 index 000000000..cece64126 --- /dev/null +++ b/doc/examples/softwaresite/bugs/hghg.mdwn @@ -0,0 +1 @@ +hghg diff --git a/doc/examples/softwaresite/bugs/needs_more_bugs.mdwn b/doc/examples/softwaresite/bugs/needs_more_bugs.mdwn new file mode 100644 index 000000000..a150570a4 --- /dev/null +++ b/doc/examples/softwaresite/bugs/needs_more_bugs.mdwn @@ -0,0 +1,3 @@ +FooBar does not have enough bugs, which suggests that it's not a real Free +Software project. Please help create more bugs by adding code to FooBar! +:-) diff --git a/doc/examples/softwaresite/contact.mdwn b/doc/examples/softwaresite/contact.mdwn new file mode 100644 index 000000000..facfa900f --- /dev/null +++ b/doc/examples/softwaresite/contact.mdwn @@ -0,0 +1,7 @@ +To reach the authors of FooBar, join channel `#foobar` on the `examplenet` +irc network. + +There's also a mailing list, +[foobar-l](http://example.com/mailman/listinfo/foobar-l). + +Be sure to read the [[doc/FAQ]] first. diff --git a/doc/examples/softwaresite/doc.mdwn b/doc/examples/softwaresite/doc.mdwn new file mode 100644 index 000000000..f134febb6 --- /dev/null +++ b/doc/examples/softwaresite/doc.mdwn @@ -0,0 +1,5 @@ +Documentation for FooBar. + +* First, you'll want to [[install]] it. +* Then you'll want to [[setup]] the config files. +* There's also a [[FAQ]]. diff --git a/doc/examples/softwaresite/doc/faq.mdwn b/doc/examples/softwaresite/doc/faq.mdwn new file mode 100644 index 000000000..fe0c3eff0 --- /dev/null +++ b/doc/examples/softwaresite/doc/faq.mdwn @@ -0,0 +1,11 @@ +FooBar frequently asked questions. + +[[!toc ]] + +## Is this a real program? + +No, it's just an example. + +## Really? + +Yes, really. diff --git a/doc/examples/softwaresite/doc/install.mdwn b/doc/examples/softwaresite/doc/install.mdwn new file mode 100644 index 000000000..1e877a45a --- /dev/null +++ b/doc/examples/softwaresite/doc/install.mdwn @@ -0,0 +1,10 @@ +Installing FooBar is pretty straightforward: + + tar xzvf foobar.tar.gz + cd foobar + ./configure + make + make install + +Note that you'll need `libfrobnicate` installed first. You might also want to +edit `config.h`. diff --git a/doc/examples/softwaresite/doc/setup.mdwn b/doc/examples/softwaresite/doc/setup.mdwn new file mode 100644 index 000000000..aa2b26345 --- /dev/null +++ b/doc/examples/softwaresite/doc/setup.mdwn @@ -0,0 +1,4 @@ +FooBar is configured via the config file `/etc/foobarrc`, and the per-user +`~/.foobarrc`. + +The file format should be self-explanatory. diff --git a/doc/examples/softwaresite/download.mdwn b/doc/examples/softwaresite/download.mdwn new file mode 100644 index 000000000..1b4e599eb --- /dev/null +++ b/doc/examples/softwaresite/download.mdwn @@ -0,0 +1,5 @@ +FooBar tarballs can be downloaded from +[here](http://foobar.example.com/download/). + +There's also a Subversion repository, at +`svn://foobar.example.com/foobar/trunk`. diff --git a/doc/examples/softwaresite/index.mdwn b/doc/examples/softwaresite/index.mdwn new file mode 100644 index 000000000..e03a969a0 --- /dev/null +++ b/doc/examples/softwaresite/index.mdwn @@ -0,0 +1,13 @@ +FooBar is an amazing example program that does not exist. Use it for all +your example program needs. This is its wiki. + +* **[[download]]** +* [[news]] +* [[documentation|doc]] +* [[bugs]] +* [[contact]] + +---- + +This wiki is powered by [ikiwiki](http://ikiwiki.info). + diff --git a/doc/examples/softwaresite/news.mdwn b/doc/examples/softwaresite/news.mdwn new file mode 100644 index 000000000..20efba6e0 --- /dev/null +++ b/doc/examples/softwaresite/news.mdwn @@ -0,0 +1,5 @@ +This is where announcements of new releases, features, and other news is +posted. FooBar users are recommended to subscribe to this page's RSS +feed. + +[[!inline pages="./news/* and !*/Discussion" rootpage="news" show="30"]] diff --git a/doc/examples/softwaresite/news/version_1.0.mdwn b/doc/examples/softwaresite/news/version_1.0.mdwn new file mode 100644 index 000000000..83c805e6e --- /dev/null +++ b/doc/examples/softwaresite/news/version_1.0.mdwn @@ -0,0 +1 @@ +Version 1.0 of foobar is released. [[Download]] it today! diff --git a/doc/examples/softwaresite/templates/release.mdwn b/doc/examples/softwaresite/templates/release.mdwn new file mode 100644 index 000000000..ac7ff93c7 --- /dev/null +++ b/doc/examples/softwaresite/templates/release.mdwn @@ -0,0 +1,7 @@ +<TMPL_IF news>News for FooBar <TMPL_VAR version>: + +<TMPL_VAR news> + +</TMPL_IF> +FooBar <TMPL_VAR version> released with [[!toggle text="these changes" id="changelog"]] +[[!toggleable id="changelog" text="""<TMPL_VAR changelog>"""]] diff --git a/doc/favicon.ico b/doc/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..b55eba2800de9d41d9288bc084cde8ff649f8414 GIT binary patch literal 371 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf<Z~8yL>2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4<ivthz5Jr|+3#$mfQmkNx;Tbd zoL+i)W7Z)DhK7g2Zxr~ZS#etJ>|iYvb(EPa+q&zOa)`j((!$bUnK`mDb6hk<)MZ=V z$uj+7Q4)DvUolOkpxyA$a?7Ick7GMF<VLd;{uWY7nzcpfsmi@r?yFKiJs*q9w;d2* zKmLeI=gAX=K2t9{rpg-Sj~DFrGF}hc5qQ|^<f*+$oxAi7l*XT(fBK+$4$p)j;ae7q zS8(biEPTzgr|RD~5qHU}EN0(zUoaWY*>Lp9OowpRvLByCA6P9ux1iPhkB!U&^A`O# zACoLxau+mmbG03R!4+cYERxuhdZk#-w@2nNU)6v8;0N0cJG8$nc31EE{p<wL?+l)< KelF{r5}E+h#*R4v literal 0 HcmV?d00001 diff --git a/doc/features.mdwn b/doc/features.mdwn new file mode 100644 index 000000000..61b23bb59 --- /dev/null +++ b/doc/features.mdwn @@ -0,0 +1,183 @@ +An overview of some of ikiwiki's features: +[[!toc ]] + +## Uses a real RCS + +Rather than implement its own system for storing page histories etc, +ikiwiki uses a real [[Revision_Control_System|rcs]]. This isn't (just) +because we're lazy, it's because a real RCS is a good thing to have, and +there are advantages to using one that are not possible with a standard +wiki. + +Instead of editing pages in a stupid web form, you can use vim and commit +changes via [[Subversion|rcs/svn]], [[rcs/git]], or any of a number of other +[[Revision_Control_Systems|rcs]]. + +Ikiwiki can be run from a [[post-commit]] hook to update your wiki +immediately whenever you commit a change using the RCS. + +It's even possible to securely let +[[anonymous_users_git_push_changes|tips/untrusted_git_push]] +to the wiki. + +Note that ikiwiki does not require a RCS to function. If you want to +run a simple wiki without page history, it can do that too. + +## A wiki compiler + +Ikiwiki is a wiki compiler; it builds a static website for your wiki, and +updates it as pages are edited. It is fast and smart about updating a wiki, +it only builds pages that have changed (and tracks things like creation of +new pages and links that can indirectly cause a page to need a rebuild) + +## Supports many markup languages + +By default, pages in the wiki are written using the [[ikiwiki/MarkDown]] format. +Any page with a filename ending in ".mdwn" is converted from markdown to html +by ikiwiki. Markdown understands text formatted as it would be in an email, +and is quite smart about converting it to html. The only additional markup +provided by ikiwiki on top of regular markdown is the [[ikiwiki/WikiLink]] and +the [[ikiwiki/directive]]. + +If you prefer to use some other markup language, ikiwiki allows others to +easily be added by [[plugins]]. For example it also supports traditional +[[plugins/WikiText]] formatted pages, pages written as pure +[[plugins/HTML]], or pages written in [[reStructuredText|plugins/rst]] +or [[Textile|plugins/textile]]. + +Ikiwiki also supports files of any other type, including plain text, +images, etc. These are not converted to wiki pages, they are just copied +unchanged by ikiwiki as it builds your wiki. So you can check in an image, +program, or other special file and link to it from your wiki pages. + +## Blogging + +You can turn any page in the wiki into a [[blog]]. Pages matching a +specified [[ikiwiki/PageSpec]] will be displayed as a weblog within the blog +page. And RSS or Atom feeds can be generated to follow the blog. + +Ikiwiki's own [[TODO]], [[news]], and [[plugins]] pages are good examples +of some of the flexible ways that this can be used. There is also an +[[example_blog|examples/blog]] set up that you can copy into your own wiki. + +Ikiwiki can also [[plugins/aggregate]] external blogs, feeding them into +the wiki. This can be used to create a Planet type site that aggregates +interesting feeds. + +You can also mix blogging with [[podcasting|podcast]]. Simply drop +media files where they will be picked up like blog posts. For +fuller-featured podcast feeds, enclose media files in blog posts +using [[plugins/meta]]. Either way, this will work for any files +that you would care to syndicate. + +## Valid html and [[css]] + +Ikiwiki aims to produce +[valid XHTML 1.0](http://validator.w3.org/check?url=referer). +(Experimental [[tips/HTML5]] support is also available.) + +Ikiwiki generates html using [[templates]], and uses [[css]], so you +can change the look and layout of all pages in any way you would like. + +Ikiwiki ships with several ready to use [[themes]]. + +## [[Plugins]] + +Plugins can be used to add additional features to ikiwiki. The interface is +quite flexible, allowing plugins to implement additional markup languages, +register [[directives|ikiwiki/directive]], provide a [[RCS]] backend, hook +into [[CGI]] mode, and much more. Most of ikiwiki's features are actually +provided by plugins. + +The standard language for ikiwiki plugins is perl, but ikiwiki also supports +[[plugins/write/external]] plugins: Standalone programs that can be written in +any language and communicate with ikiwiki using XML RPC. + +## [[todo/utf8]] + +After rather a lot of fiddling, we think that ikiwiki correctly and fully +supports utf8 everywhere. + +## Other features + +The above are the core design goals and features of ikiwiki, but on that +foundation a lot of other important features are added. Here is an +incomplete list of some of them. + +### [[Tags]] + +You can tag pages and use these tags in various ways. Tags will show +up in the ways you'd expect, like at the bottom of pages, in blogs, and +in RSS and Atom feeds. + +### [[SubPages|ikiwiki/SubPage]] + +Arbitrarily deep hierarchies of pages with fairly simple and useful +[[ikiwiki/SubPage/LinkingRules]] + +### [[BackLinks]] + +Automatically included on pages. Rather faster than eg MoinMoin and +always there to help with navigation. + +### Smart merging and conflict resolution in your web browser + +Since it uses a real RCS, ikiwiki takes advantage of its smart merging to +avoid any conflicts when two people edit different parts of the same page +at the same time. No annoying warnings about other editors, or locking, +etc, instead the other person's changes will be automatically merged with +yours when you commit. + +In the rare cases where automatic merging fails due to the same part of a +page being concurrently edited, regular commit conflict markers are +shown in the file to resolve the conflict, so if you're already familiar +with that there's no new commit marker syntax to learn. + +### [[RecentChanges]], editing pages in a web browser + +Nearly the definition of a wiki, although perhaps ikiwiki challenges how +much of that web gunk a wiki really needs. These features are optional +and can be enabled by enabling [[CGI]] and a [[Revision_Control_System|rcs]]. + +### User registration + +Can optionally be configured to allow only registered users to edit +pages. + +User registration can be done using a web form, or ikiwiki can be +configured to accept users authenticated with OpenID, or HTTP basic +authentication, or other methods implemented via plugins. + +### Discussion pages + +Thanks to subpages, every page can easily and automatically have a +/Discussion subpage. By default, these links are included in the +[[templates]] for each page. If you prefer blog-style +[[plugins/comments]], that is available too. + +### Edit controls + +Wiki admins can lock pages so that only other admins can edit them. Or a +wiki can be set up to allow anyone to edit Discussion pages, but only +registered users to edit other pages. These are just two possibilities, +since page edit controls can be changed via plugins. + +### [[PageHistory]] + +Well, sorta. Rather than implementing YA history browser, it can link to +[[ViewVC]] or the like to browse the history of a wiki page. + +### Full text search + +Ikiwiki can use the xapian search engine to add powerful +full text [[plugins/search]] capabilities to your wiki. + +### Translation via po files + +The [[plugins/po]] plugin allows translating individual wiki pages using +standard `po` files. + +### [[w3mmode]] + +Can be set up so that w3m can be used to browse a wiki and edit pages +without using a web server. diff --git a/doc/forum.mdwn b/doc/forum.mdwn new file mode 100644 index 000000000..62b62a401 --- /dev/null +++ b/doc/forum.mdwn @@ -0,0 +1,11 @@ +This is a place for questions and discussions that don't have a Discussion +page fitting enough. Users of ikiwiki can ask questions here. + +Note that for more formal bug reports or todo items, you can also edit the +[[bugs]] and [[todo]] pages. + + +## Current topics ## + +[[!inline pages="forum/* and !forum/discussion and !forum/*/*" +archive=yes rootpage="forum" postformtext="Add a new thread titled:" show=0]] diff --git a/doc/forum/404_-_not_found.mdwn b/doc/forum/404_-_not_found.mdwn new file mode 100644 index 000000000..dc3318901 --- /dev/null +++ b/doc/forum/404_-_not_found.mdwn @@ -0,0 +1,22 @@ +Hi, + +I've followed the tutorial to install ikiwiki. Once installed (on a Ubuntu +10.04 distro running under VirtualBox on a Windows XP, SP3 host), I can +access the **http://ubuntu1004/index.lighttpd.html** page without any +issues. + +But when I try to access the page **http://ubuntu1004/~geertvc/gwiki** (as +is mentioned at the end of the ikiwiki setup), I get the error message +"**404 - not found**". + +I've also followed the "dot-cgi" trick, but with the same negative result. +The web server I've installed, is lighttpd. + +What did I miss? + +Best rgds, + +--Geert + +> Perhaps your webserver is not exporting your `public_html` directory +> in `~geertvc`? Check its configuration. --[[Joey]] diff --git a/doc/forum/404_-_not_found/comment_1_3dea2600474f77fb986767da4d507d62._comment b/doc/forum/404_-_not_found/comment_1_3dea2600474f77fb986767da4d507d62._comment new file mode 100644 index 000000000..453419cf3 --- /dev/null +++ b/doc/forum/404_-_not_found/comment_1_3dea2600474f77fb986767da4d507d62._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://jmtd.livejournal.com/" + ip="188.222.50.68" + subject="comment 1" + date="2010-09-09T21:41:07Z" + content=""" +You probably need to run \"lighttpd-enable-mod userdir\" +"""]] diff --git a/doc/forum/404_-_not_found/comment_2_948e4678be6f82d9b541132405351a2c._comment b/doc/forum/404_-_not_found/comment_2_948e4678be6f82d9b541132405351a2c._comment new file mode 100644 index 000000000..c3fb72db5 --- /dev/null +++ b/doc/forum/404_-_not_found/comment_2_948e4678be6f82d9b541132405351a2c._comment @@ -0,0 +1,31 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawllEHb4oGNaUrl7vyziQGrxAlQFri_BfaE" + nickname="Geert" + subject="comment 2" + date="2010-09-12T06:45:27Z" + content=""" +After a re-installation of ikiwiki (first removed all old files), I get the following feedback: + + Successfully set up gwiki: + url: http://ubuntu1004/~geertvc/gwiki + srcdir: ~/gwiki + destdir: ~/public_html/gwiki + repository: ~/gwiki.git + To modify settings, edit ~/gwiki.setup and then run: + ikiwiki -setup ~/gwiki.setup + + +In the lighttpd config file (/etc/lighttpd/lighttpd.conf), I've now changed the item \"server.document-root\" from the default \"/var/www\" to (in my case) \"/home/geertvc/public_html/gwiki\". I've taken the destdir location (see above) as document root for lighttpd. + +When doing this, I can see the \"index.html\" page of ikiwiki (by typing the following URL in the address box of the browser: \"ubuntu1004/index.html\"). So, that seems to be the right modification, right? Or isn't it? + +Note: when I take the directory \"/home/geertvc/gwiki\" (= the URL given above), then things do not work. I can't see the content of \"index.html\", I get the error message I mentioned in my initial post (404 - not found). + +But when clicking, for instance, the \"Edit\" button, the link brings me to the following location: + + http://ubuntu1004/~geertvc/gwiki/ikiwiki.cgi?page=index&do=edit + +However, there's not at all a file called \"ikiwiki.cgi\" at that location. The location of the file \"ikiwiki.cgi\" is \"/home/geertvc/public_html/gwiki\", so why is the link \"Edit\" leading me to that (wrong?) location? + +Apparently, something is still wrong with my settings. Hope, with the above information, someone can put me on the right track... +"""]] diff --git a/doc/forum/404_-_not_found/comment_3_4c7b1fa88776815bbc6aa286606214c2._comment b/doc/forum/404_-_not_found/comment_3_4c7b1fa88776815bbc6aa286606214c2._comment new file mode 100644 index 000000000..9f606f04e --- /dev/null +++ b/doc/forum/404_-_not_found/comment_3_4c7b1fa88776815bbc6aa286606214c2._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://jmtd.livejournal.com/" + ip="78.105.191.131" + subject="Follow instructions" + date="2010-09-12T12:26:49Z" + content=""" +Please re-read my comment. If you enable usersdirs then /~user corresponds to ~/public_html. The change you have made has / corresponding instead, which is why the links don't work. +"""]] diff --git a/doc/forum/Accessing_meta_values_in_pages__63__.mdwn b/doc/forum/Accessing_meta_values_in_pages__63__.mdwn new file mode 100644 index 000000000..78594f912 --- /dev/null +++ b/doc/forum/Accessing_meta_values_in_pages__63__.mdwn @@ -0,0 +1,8 @@ +If I set a meta value on a page (lets say \[[!meta author="Adam Shand"]] is there some way to retrieve the value of author and put it somewhere visible on the page? Eg. can I write: + +author: $author + +I know I can update the raw templates but it'd be nice to be able to do this in the pages them selves. + +Cheers, +Adam. diff --git a/doc/forum/Adding_a_custom_header_and_footer.mdwn b/doc/forum/Adding_a_custom_header_and_footer.mdwn new file mode 100644 index 000000000..d9bdedc6a --- /dev/null +++ b/doc/forum/Adding_a_custom_header_and_footer.mdwn @@ -0,0 +1,13 @@ +I want to do some things that I think are easiest accomplished +by allowing me to add arbitrary HTML to be embedded on all pages +in the site. Specifically, I want to add meta tags to the top of +the page so that it renders pretty-like in things like Twitter, +and I want to add Piwik tracking to the bottom of the page. + +So how do I do that? + +I could write a whole new template for the site, but I suspect +that there's a more modular approach that is advised. And if you +have ideas of totally different ways do do this, do tell. + +Thanks diff --git a/doc/forum/Adding_a_custom_header_and_footer/comment_1_e82dbfef77ff222a7fa07aab0a19fb18._comment b/doc/forum/Adding_a_custom_header_and_footer/comment_1_e82dbfef77ff222a7fa07aab0a19fb18._comment new file mode 100644 index 000000000..d10961c19 --- /dev/null +++ b/doc/forum/Adding_a_custom_header_and_footer/comment_1_e82dbfef77ff222a7fa07aab0a19fb18._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="spalax" + ip="82.216.247.172" + subject="Use page.tmpl" + date="2014-05-16T17:11:01Z" + content=""" +I think the right thing to do is to copy the default `page.tmpl` to your wiki (in your template directory), and add the code you wish. + +-- [[Louis|spalax]] +"""]] diff --git a/doc/forum/Adding_new_markup_to_markdown.mdwn b/doc/forum/Adding_new_markup_to_markdown.mdwn new file mode 100644 index 000000000..39d233add --- /dev/null +++ b/doc/forum/Adding_new_markup_to_markdown.mdwn @@ -0,0 +1,11 @@ +I'm using ikiwiki to manage my personal wiki. One of the things I'm toying with is storing my grocery list in a wiki. The way I typically grocery-shop is to make one huge master list containing all the items I typically buy in a single cycle. Then, on any given trip, I make a subset list containing only the items I need. I'd like to streamline this process by making the master list a series of checkboxes. Before each trip, I load the list page on my phone, check off all the items I already have, then check off individual items as I get them. + +I'm not sure if there's a convenient way of adding checkboxes to wiki pages, and after a bit of thought I decided that "( )" would be a good markup for this. Ideally I'd like to still have access to other markdown conventions so I could, say, organize the list with headings and such when it grows large, so I don't want to create an entirely separate format, or a separate copy of the markdown plugin. + +Is there an existing means of, say, adding supersets to wiki markup? I suppose I could use an inline directive that inserts a multisellect HTML element, but I really like ( ). :) + +Ideal would be some sort of filter infrastructure. Plugins could register with a larger filter plugin that adds an inline directive. I could then invoke the checkbox filter at the top of my grocery list, and all instances of ( ) would be replaced with HTML. Might also make sense for the individual filters to specify whether or not they're invoked before or after the page template, or perhaps just always invoke them after. *shrug* + +Does something like this exist? I'd really like to avoid messing around with raw HTML or an inline for each of 40-50 list items. :) + +-- [[Nolan]] diff --git a/doc/forum/Allow_only_specific_OpenIDs_to_login.mdwn b/doc/forum/Allow_only_specific_OpenIDs_to_login.mdwn new file mode 100644 index 000000000..27eb69647 --- /dev/null +++ b/doc/forum/Allow_only_specific_OpenIDs_to_login.mdwn @@ -0,0 +1,7 @@ +How do I allow only specific OpenIDs to log in to ikiwiki? I found a way to only allow edits from specific OpenIDs, but I would like to restrict the logins and not the edits. Currently I've disabled the passwordauth plugin, locked all pages, and set the allowed OpenIDs as adminuser: + + adminuser => [qw{MY_OPENIDS}], + disable_plugins => [qw{passwordauth}], + locked_pages => '*', + +The problem with this solution is that every OpenID that logs in is saved in ikiwiki's `userdb` file, which I'd like to avoid. Pointers to the documentation or a sample setup are very welcome. Thanks! diff --git a/doc/forum/Anyone_mirroring_ikiwiki_inline_feed_to_identi.ca__63__.mdwn b/doc/forum/Anyone_mirroring_ikiwiki_inline_feed_to_identi.ca__63__.mdwn new file mode 100644 index 000000000..c0b896515 --- /dev/null +++ b/doc/forum/Anyone_mirroring_ikiwiki_inline_feed_to_identi.ca__63__.mdwn @@ -0,0 +1,3 @@ +Is anyone successfull mirroring feeds from ikiwiki to identi.ca (or another status.net instance)? How did you set up your feed? + +When I try to, identi.ca presents me with an error about no "author ID URI" being found in the feed. Indeed the ikiwiki-generated atom feed only has got a global "author" - I presume identi.ca requires author information in each entry. Is it possible to set up ikiwiki's feed that way? diff --git a/doc/forum/Anyone_mirroring_ikiwiki_inline_feed_to_identi.ca__63__/comment_1_8a5acbb6234104b607c8c4cf16124ae4._comment b/doc/forum/Anyone_mirroring_ikiwiki_inline_feed_to_identi.ca__63__/comment_1_8a5acbb6234104b607c8c4cf16124ae4._comment new file mode 100644 index 000000000..1d710d153 --- /dev/null +++ b/doc/forum/Anyone_mirroring_ikiwiki_inline_feed_to_identi.ca__63__/comment_1_8a5acbb6234104b607c8c4cf16124ae4._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="Franek" + ip="188.99.178.40" + subject="[[!meta author="..." + date="2012-05-19T14:51:42Z" + content=""" +Adding [[!meta author=\"me\"]] to the entries and/or the feedpage does not help. +"""]] diff --git a/doc/forum/Anyone_mirroring_ikiwiki_inline_feed_to_identi.ca__63__/comment_2_155e5823860a91989647ede8b5c9224a._comment b/doc/forum/Anyone_mirroring_ikiwiki_inline_feed_to_identi.ca__63__/comment_2_155e5823860a91989647ede8b5c9224a._comment new file mode 100644 index 000000000..6c709b3f0 --- /dev/null +++ b/doc/forum/Anyone_mirroring_ikiwiki_inline_feed_to_identi.ca__63__/comment_2_155e5823860a91989647ede8b5c9224a._comment @@ -0,0 +1,16 @@ +[[!comment format=mdwn + username="Franek" + ip="188.99.178.40" + subject="Further enquiries" + date="2012-05-20T10:46:07Z" + content=""" +I did some more experiments setting not only \"[[!meta author=...\", but also \"authorurl\" globally and per-entry in various combinations, with no success. As far as I could see, \"authorurl\" had no effect on the atom feed whatsoever. + +It seems that identi.ca wants a feed to have an <author> field with a <uri> subfield, as described here: [[http://www.atomenabled.org/developers/syndication/#person]] . Is there a way to achieve this with ikiwiki inline-feeds? + +I also found two old and unresolved status.net bugreports on the matter: + +[[http://status.net/open-source/issues/2840]] + +[[http://status.net/open-source/issues/2839]] +"""]] diff --git a/doc/forum/Anyone_mirroring_ikiwiki_inline_feed_to_identi.ca__63__/comment_3_317f1202a3da1bfc845d4becbac4bba8._comment b/doc/forum/Anyone_mirroring_ikiwiki_inline_feed_to_identi.ca__63__/comment_3_317f1202a3da1bfc845d4becbac4bba8._comment new file mode 100644 index 000000000..6bda93433 --- /dev/null +++ b/doc/forum/Anyone_mirroring_ikiwiki_inline_feed_to_identi.ca__63__/comment_3_317f1202a3da1bfc845d4becbac4bba8._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="Franek" + ip="92.74.26.119" + subject="kind of solved, but another problem comes up" + date="2012-05-26T19:31:19Z" + content=""" +The templates atompage.tmpl and/or atomitem.tmpl appear to be what would have to be altered to satisfy identi.ca. I did that on my system, just hard-coding a <uri> element into <author> for testing. In one respect, it worked: identi.ca does not complain about the missing author uri any more. In another, it did not, another error comes up now: \"Internal server error\" and something like \"could not add feed\". + +I do not know where to go from this very unspecific error message. I guess I am going to try something like twitterfeed.com, for now. +"""]] diff --git a/doc/forum/Apache_XBitHack.mdwn b/doc/forum/Apache_XBitHack.mdwn new file mode 100644 index 000000000..d5da0825e --- /dev/null +++ b/doc/forum/Apache_XBitHack.mdwn @@ -0,0 +1,28 @@ +I'd like to be able to use the Apache XBitHack to enable Server Side Includes on my site. Yes, it is possible to enable SSI by setting the page extension to .shtml, and that is what I am doing at the moment. +However, the disadvantage of this approach is that the server does not give a LastModified header, which means that the content can't be cached. However, the way that I am using SSI is such that the main content of the page really is "last modified" when the page was last modified, so I'd like to be able to indicate that. And using the XBitHack - that is, setting the executable bit on the generated page - would enable me to do that. + +I gather from the [[security]] page that having the executable bit set on files is considered a security hole, but how big a hole would it be if I'm the only one editing the site? Is there a way, a somewhat safe way, of implementing XBitHack for IkiWiki? + +-- [[KathrynAndersen]] + +> The risk with execute bits on files in the generated site is that someone +> commits an executable, ikiwiki copies it as-is, and now the web browser +> can be used to run it. Obviously if you're the only committer, that is +> not much of a risk. Or you can lock down apache to not allow running +> arbitrary files. It's also pretty unlikely that a rendered mdwn file +> would result in a html page that can be run as an executable. So an +> option that makes all files rendered from mdwn or other markups +> get the x bit set would be pretty safe even with untrusted editors. --[[Joey]] + +>> So how about this: if something has a page-type (i.e. mdwn or whatever authorized page types there are) +>> then add something at the end of the process (would that be the "changes" hook?) +>> which sets the x bit on the generated page file. Would that work? + +>> Or is there a way to say "tell me all the generated files that end in .html" and use that as a list to start from? + +>> --[[KathrynAndersen]] + +>>> Yes, the `change` hook is passed the names of source files that got +>>> built. Use `pagetype` to check which got htmlized (and filter out ones +>>> that got copied), and then use `htmlpage` to get the name of the html +>>> file that was generated, and chmod it. --[[Joey]] diff --git a/doc/forum/Are_these_revisions_legit_or_accidentally_committed_jiberish__63__.mdwn b/doc/forum/Are_these_revisions_legit_or_accidentally_committed_jiberish__63__.mdwn new file mode 100644 index 000000000..ec9980c30 --- /dev/null +++ b/doc/forum/Are_these_revisions_legit_or_accidentally_committed_jiberish__63__.mdwn @@ -0,0 +1,12 @@ +When rebuilding, I see + + building recentchanges/change_63476fba3a519d42ee56c7611250ada41111356d._change, which depends on templates/page.tmpl + building recentchanges/change_bd07c4308d5eea2cd27ad067a502318dc0e9c8bb._change, which depends on templates/page.tmpl + building recentchanges/change_6c2a66b022276951d79f29c1221d22fe1592f67f._change, which depends on templates/page.tmpl + building recentchanges/change_f08669f128d618d0da460234b2cee555b0818584._change, which depends on templates/page.tmpl + building recentchanges/change_b0347df66da5c515dc0d1d612ecdfbe203a0a674._change, which depends on templates/page.tmpl + building recentchanges/change_0bb246c481e9ede8686f6caa4de40b9e94642e40._change, which depends on templates/page.tmpl + building recentchanges/change_511846ca75fb2e87fb90582ead282d104a5e13fc._change, which depends on templates/page.tmpl + ... + +Are these accidentally committed gibberish? If so, how to remove them properly? diff --git a/doc/forum/Are_these_revisions_legit_or_accidentally_committed_jiberish__63__/comment_1_b425823f800fba82ad2aaaa0dbe6686a._comment b/doc/forum/Are_these_revisions_legit_or_accidentally_committed_jiberish__63__/comment_1_b425823f800fba82ad2aaaa0dbe6686a._comment new file mode 100644 index 000000000..9326f73d5 --- /dev/null +++ b/doc/forum/Are_these_revisions_legit_or_accidentally_committed_jiberish__63__/comment_1_b425823f800fba82ad2aaaa0dbe6686a._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + nickname="joey" + subject="comment 1" + date="2011-12-30T18:13:18Z" + content=""" +They are little per-change pages that are inlined together to produce your RecentChanges page. + +(They're not committed to git, only stored internally.) +"""]] diff --git a/doc/forum/Asciidoc_plugin.mdwn b/doc/forum/Asciidoc_plugin.mdwn new file mode 100644 index 000000000..57d6fd91e --- /dev/null +++ b/doc/forum/Asciidoc_plugin.mdwn @@ -0,0 +1,14 @@ +I have completely overhauled the Asciidoc plugin for ikiwiki that was created by [[Karl Mowson|http://www.mowson.org/karl/colophon/]]. The source can be downloaded from my [[Dropbox|http://dl.dropbox.com/u/11256359/asciidoc.pm]]. + +### Features + +* Uses a filter hook to escape WikiLinks and Directives using Asciidoc `+++` passthrough macros, to avoid them being processed by Asciidoc. This behavior is configurable in the wiki setup file. +* Adds a preprocessor directive 'asciidoc' which allows extra Asciidoc command-line options to be passed on a per-page basis. Each parameter name is the option name (the leading `--` will be inserted automatically), and the parameter value is the option value. Currently, only 'conf-file' and 'doctype' are allowed (or even useful). +* Sets the page title from the first line in the Asciidoc file using a meta directive. This behavior is configurable in the wiki setup file. +* Searches for an Asciidoc configuration file named the same as the wiki if none is specified in the setup file. +* Asciidoc configuration files are stored in the wiki. They should be named `._conf` to avoid publishing them. + +### Problems + +* Escaping Directives is not optimal. It prevents markup from being used in Directives, and the passthrough macros have to include extra spaces to avoid having directives that return an empty string collapse to `++++++`. In addition, I had to borrow the regexps from the Ikiwiki source code; it would be nice if this were available as part of the API. +* Handling of Asciidoc errors is suboptimal; they are simply inserted into the returned page. This could be fixed in Perl 5.12 by using the run_forked() in IPC::Cmd. diff --git a/doc/forum/Attachment_and_sub-directory.mdwn b/doc/forum/Attachment_and_sub-directory.mdwn new file mode 100644 index 000000000..91d7aee27 --- /dev/null +++ b/doc/forum/Attachment_and_sub-directory.mdwn @@ -0,0 +1,5 @@ +Hi. + +If I create a page and attach a file to the page, ikiwiki creates a sub-directory with the page name and places the attachment in the sub-directory regardless of usedirs setup. Is there any setup not to create the sub-directory and to place the attachment in the same directory where the page is, so that I can edit and properly *preview* at a local machine using third-party markdown editors? + +Thanks in advance. diff --git a/doc/forum/Background_picture_and_css.mdwn b/doc/forum/Background_picture_and_css.mdwn new file mode 100644 index 000000000..827100984 --- /dev/null +++ b/doc/forum/Background_picture_and_css.mdwn @@ -0,0 +1,8 @@ +Is it possible to put two different background pictures into the right and left sides of the following ikiwiki css? + +[lessish css theme](https://raw.github.com/spiffin/ikiwiki_lessish/master/lessish.css) + +Is it also possible to have a background like this: [http://ysharifi.wordpress.com/](http://ysharifi.wordpress.com/) +or this [tex.stackexchange.com](tex.stackexchange.com) + +I am not a css expert so, it would be nice if you could provide some details. diff --git a/doc/forum/Blog_posting_times_and_ikiwiki_state.mdwn b/doc/forum/Blog_posting_times_and_ikiwiki_state.mdwn new file mode 100644 index 000000000..0c1da5b97 --- /dev/null +++ b/doc/forum/Blog_posting_times_and_ikiwiki_state.mdwn @@ -0,0 +1,28 @@ +What I wanted +------------- + +I thought to myself it would be nice to see from the console the dates that my ikiwiki blog posts were published. Especially as I would like to know the order of my todo list without having to view the webpage. + +What I discovered +----------------- + +Looked at the code and saw the functions for grabbing the ctime from git but couldn't reconcile them to the "Posted" date in the RSS feed. Some more reading and I figured out that the Posted time is taken from the UNIX ctime when first uploaded into the repository and this information is stored in the page state via a Perl storable database - indexdb. (I'm sure most know this but to be clear in UNIX ctime is *not* the actual creation time of a file. UNIX has no facility for recording the actual creation time - however on first upload to the wiki it's good enough). + +Wrote a Perl script to query and sort indexdb. Now I can list my todos or blog posts in the order they appear on the web. Handy. + +However the ikiwiki state is specifically excluded via '.gitignore'. I work a lot on trains and not having this file in my cloned wiki means I can't list published posts or my todos in the proper order. I can get an approximation from git logs but, dam it, I want it the same! + +What can I do? +-------------- + +Is it a spectacularly bad idea to include the ikiwiki state file in my cloned repo (I suspect it is). What else could be done? Can I disable pagestate somehow or force ikiwiki to always use git commit times for Posted times? + +> Have you tried running ikiwiki with the `--gettime` option on your laptop, +> to force it to retrieve initial commit times from git? You should only +> need to do that once, and it'll be cached in the pagestate thereafter. +> +> Because that functionality is slow on every supported VCS except git, +> ikiwiki tries to avoid using it unless it's really needed. [[rcs]] +> lists it as "fast" for git, though, so depending how fast it really is +> and how large your wiki is, you might be able to get away with running +> ikiwiki with `--gettime` all the time? --[[smcv]] diff --git a/doc/forum/Blog_posting_times_and_ikiwiki_state/comment_1_87304dfa2caea7e526cdb04917524e8c._comment b/doc/forum/Blog_posting_times_and_ikiwiki_state/comment_1_87304dfa2caea7e526cdb04917524e8c._comment new file mode 100644 index 000000000..62bae02b0 --- /dev/null +++ b/doc/forum/Blog_posting_times_and_ikiwiki_state/comment_1_87304dfa2caea7e526cdb04917524e8c._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawmwYptyV5ptNt8LCbMYsmpcNkk9_DRt-EY" + nickname="Matt" + subject="comment 1" + date="2010-11-04T11:52:53Z" + content=""" +Perhaps I have a different setup from you but on my laptop I don't have ikiwiki installed - only a clone of the git repo. You mean to run --gettime on the post-update git hook? +"""]] diff --git a/doc/forum/Broken_after_upgrading_Ikiwiki.mdwn b/doc/forum/Broken_after_upgrading_Ikiwiki.mdwn new file mode 100644 index 000000000..aea5fdbd9 --- /dev/null +++ b/doc/forum/Broken_after_upgrading_Ikiwiki.mdwn @@ -0,0 +1,10 @@ +I upgraded my Debian server from 5 to 6, then I updated ikiwiki. Now I can't rebuild my Ikiwiki instance: + + $ ikiwiki --setup ./pages.setup + Failed to load plugin IkiWiki::Plugin::scrubber: Can't locate IkiWiki/Plugin/scrubber.pm in @INC (@INC contains: /home/xyzfoobar/devel/ikiwiki/lib /etc/perl /usr/local/lib/perl/5.10.1 /usr/local/share/perl/5.10.1 /usr/lib/perl5 /usr/share/perl5 /usr/lib/perl/5.10 /usr/share/perl/5.10 /usr/local/lib/site_perl .) at (eval 77) line 2. + BEGIN failed--compilation aborted at (eval 77) line 2. + + $ ikiwiki --version + ikiwiki version 3.20100815.7 + +What's the proper way to fix this? diff --git a/doc/forum/Broken_after_upgrading_Ikiwiki/comment_1_3d0588a845c58b3aedc35970e8dcc811._comment b/doc/forum/Broken_after_upgrading_Ikiwiki/comment_1_3d0588a845c58b3aedc35970e8dcc811._comment new file mode 100644 index 000000000..93360d167 --- /dev/null +++ b/doc/forum/Broken_after_upgrading_Ikiwiki/comment_1_3d0588a845c58b3aedc35970e8dcc811._comment @@ -0,0 +1,14 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawnZ0g2UAijV7RGrKtWPljCCAYHBJ3pwPvM" + nickname="Meng" + subject="comment 1" + date="2011-12-20T07:21:19Z" + content=""" +If I try to create new setup file + + $ ikiwiki --dumpsetup newpages.setup + Traceback (most recent call last): + File \"/usr/lib/ikiwiki/plugins/rst\", line 18, in <module> + from docutils.core import publish_parts; + ImportError: No module named docutils.core +"""]] diff --git a/doc/forum/Broken_after_upgrading_Ikiwiki/comment_2_fd65d4b87a735b67543bb0cf4053b652._comment b/doc/forum/Broken_after_upgrading_Ikiwiki/comment_2_fd65d4b87a735b67543bb0cf4053b652._comment new file mode 100644 index 000000000..47fa4ae7b --- /dev/null +++ b/doc/forum/Broken_after_upgrading_Ikiwiki/comment_2_fd65d4b87a735b67543bb0cf4053b652._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + nickname="joey" + subject="comment 2" + date="2011-12-20T15:16:23Z" + content=""" +Your setup file seems to refer to a \"scrubber\" plugin, which has never existed in ikiwiki. Perhaps a typo of \"htmlscrubber\"? + +3.20100815.7 is an old version of ikiwiki. The current version avoids the rst docutils breakage. Installing python-docutils on Debian can work around that problem as well. +"""]] diff --git a/doc/forum/Broken_after_upgrading_Ikiwiki/comment_3_7c8b46eabdb25cbc01c56c7b53ed3b91._comment b/doc/forum/Broken_after_upgrading_Ikiwiki/comment_3_7c8b46eabdb25cbc01c56c7b53ed3b91._comment new file mode 100644 index 000000000..72d38e76c --- /dev/null +++ b/doc/forum/Broken_after_upgrading_Ikiwiki/comment_3_7c8b46eabdb25cbc01c56c7b53ed3b91._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawnZ0g2UAijV7RGrKtWPljCCAYHBJ3pwPvM" + nickname="Meng" + subject="comment 3" + date="2011-12-20T16:58:23Z" + content=""" +Thanks. That was exactly the issue. When editing my setup file, I accidentally splitted `htmlscrubber` to `html` and `scrubber`. +"""]] diff --git a/doc/forum/CGI_script_and_HTTPS.mdwn b/doc/forum/CGI_script_and_HTTPS.mdwn new file mode 100644 index 000000000..2f255002d --- /dev/null +++ b/doc/forum/CGI_script_and_HTTPS.mdwn @@ -0,0 +1,29 @@ +Dear ikiwiki folks, + +using Debian Wheezy and ikiwiki 3.20120629 for some reason when accessing the site using HTTP (and not HTTPS), going to Edit, so executing the CGI script, all URLs are prepended with HTTPS, which I do not want. + + <base href="https://www.example.org/" /> + +Trying to look at the source, I guess it is originating from `IkiWiki/CGI.pm`. + + sub printheader ($) { + my $session=shift; + + if (($ENV{HTTPS} && lc $ENV{HTTPS} ne "off") || $config{sslcookie}) { + print $session->header(-charset => 'utf-8', + -cookie => $session->cookie(-httponly => 1, -secure => 1)); + } + else { + print $session->header(-charset => 'utf-8', + -cookie => $session->cookie(-httponly => 1)); + } + } + +Does it check if HTTPS is enabled in the environment? During `ikiwiki --setup example.setup` or when the CGI script is run when the site is accessed (for example in an Apache environment)? + +Can this somehow be disabled in ikiwiki. Reading the code I guess I could somehow set `HTTPS = off` somewhere in the `VirtualHost` section of the Apache configuration. + + +Thanks, + +--[[PaulePanter]] diff --git a/doc/forum/CGI_script_and_HTTPS/comment_1_3f8ef438ca7de11635d4e40080e7baa9._comment b/doc/forum/CGI_script_and_HTTPS/comment_1_3f8ef438ca7de11635d4e40080e7baa9._comment new file mode 100644 index 000000000..03f1032e9 --- /dev/null +++ b/doc/forum/CGI_script_and_HTTPS/comment_1_3f8ef438ca7de11635d4e40080e7baa9._comment @@ -0,0 +1,43 @@ +[[!comment format=mdwn + username="http://smcv.pseudorandom.co.uk/" + nickname="smcv" + subject="comment 1" + date="2012-11-05T11:27:02Z" + content=""" +IkiWiki generates self-referential URLs using the `url` and `cgiurl` +configuration parameters, and the `urlto()` and `cgiurl()` functions; +the code you quoted isn't involved (it's choosing whether to set +HTTPS-only cookies or not, rather than choosing how to generate +self-referential URLs). + +If you want your wiki to be accessible via both HTTP and HTTPS, and use +whichever the user first requested, you should set both `url` and +`cgiurl` to the same URI scheme and hostname with no port specified, +either both `http` or both `https`, for instance: + + url: http://www.example.com/ + cgiurl: http://www.example.com/ikiwiki.cgi + +or + + url: https://example.org/wiki/ + cgiurl: https://example.org/cgi-bin/ikiwiki + +(or the Perl-syntax equivalents if you're not using a YAML +setup file). + +If you use one of those, IkiWiki will attempt to generate +path-only links, like \"/wiki/\" and \"/cgi-bin/ikiwiki?...\", +whenever it's valid to do so. A visitor using HTTP will stay +on HTTP and a visitor using HTTPS will stay on HTTPS. + +The choice of `http` or `https` for the `url` and `cgiurl` +still matters when a URL *must* be absolute, such as in an +RSS feed. + +I improved this code in late 2010 for this todo item: +[[todo/want_to_avoid_ikiwiki_using_http_or_https_in_urls_to_allow_serving_both]]. +It's possible that it has regressed (that's happened +a couple of times). If it has, please quote your exact +`url` and `cgiurl` configuration. +"""]] diff --git a/doc/forum/Calendar:_listing_multiple_entries_per_day.mdwn b/doc/forum/Calendar:_listing_multiple_entries_per_day.mdwn new file mode 100644 index 000000000..c3ecf36be --- /dev/null +++ b/doc/forum/Calendar:_listing_multiple_entries_per_day.mdwn @@ -0,0 +1,21 @@ +Hi, + +I'd very much like to be able to list my blog posts on a daily basis (used for logging work) - rather than have the Calendar plugin return the first post only. + +There was some effort to do this as detailed here. + +[[todo/Set_arbitrary_date_to_be_used_by_calendar_plugin]] + +I had a quick go at doing something similar on Debian Stable (Ikiwiki 3.0) but alas my Ikiwiki fu is not strong enough. + +I'm not sure how I go about swapping the link on the day number to a link to, I guess, a dynamically generated page of links? + + $linkcach{"$year/$mtag/$mday"}{$p} = ${p} + +and a suitable whilst loop looks to be all that's needed... + +Any pointers appreciated. + +A [[!taglink patch]] has been proposed in [comment](#comment-d6f94e2b779d1c038b6359aad79ed14b) + +> This has been applied. --[[Joey]] diff --git a/doc/forum/Calendar:_listing_multiple_entries_per_day/comment_1_d3dd0b97c63d615e3dee22ceacaa5a30._comment b/doc/forum/Calendar:_listing_multiple_entries_per_day/comment_1_d3dd0b97c63d615e3dee22ceacaa5a30._comment new file mode 100644 index 000000000..ca287581a --- /dev/null +++ b/doc/forum/Calendar:_listing_multiple_entries_per_day/comment_1_d3dd0b97c63d615e3dee22ceacaa5a30._comment @@ -0,0 +1,83 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawnXybLxkPMYpP3yw4b_I6IdC3cKTD-xEdU" + nickname="Matt" + subject="comment 1" + date="2011-11-29T00:52:49Z" + content=""" +So I ported the original patch mentioned to the latest Debian version. Well at least the bits that matter to me. See below. + +In doing so I realized that it does quite work how I imagined it would; instead of generating a dynamic page for a particular day with a list of links it actually fills in the calendar with the details of the posts (making for some ugly formatting). + +I'm hoping the tag generation pages will give me a clue how to alter this into what I want. + +<pre> +diff --git a/IkiWiki/Plugin/calendar.pm b/IkiWiki/Plugin/calendar.pm +index c7d2b7c..c931fe6 100644 +--- a/IkiWiki/Plugin/calendar.pm ++++ b/IkiWiki/Plugin/calendar.pm +@@ -75,6 +75,8 @@ sub format_month (@) { + my %params=@_; + + my %linkcache; ++ my @list; ++ my $detail = 1; + foreach my $p (pagespec_match_list($params{page}, + \"creation_year($params{year}) and creation_month($params{month}) and ($params{pages})\", + # add presence dependencies to update +@@ -88,7 +90,7 @@ sub format_month (@) { + my $mtag = sprintf(\"%02d\", $month); + + # Only one posting per day is being linked to. +- $linkcache{\"$year/$mtag/$mday\"} = $p; ++ $linkcache{\"$year/$mtag/$mday\"}{$p} = $IkiWiki::pagesources{$p}; + } + + my $pmonth = $params{month} - 1; +@@ -219,14 +221,38 @@ EOF + $tag='month-calendar-day-this-day'; + } + else { +- $tag='month-calendar-day-link'; ++ if ( $detail == 0 ) { ++ $tag='month-calendar-day-link'; ++ } ++ else{ ++ $tag='month-calendar-day'; ++ } + } + $calendar.=qq{\t\t<td class=\"$tag $downame{$wday}\">}; +- $calendar.=htmllink($params{page}, $params{destpage}, +- $linkcache{$key}, +- noimageinline => 1, +- linktext => $day, +- title => pagetitle(IkiWiki::basename($linkcache{$key}))); ++ if ( $detail == 0 ) { ++ $calendar.=htmllink($params{page}, $params{destpage}, ++ $linkcache{$key}, ++ noimageinline => 1, ++ linktext => $day, ++ title => pagetitle(IkiWiki::basename($linkcache{$key}))); ++ } ++ else { ++ my $day_label = qq{<span class=\"month-calendar-day-label\">$day</span>}; ++ $calendar.=qq{$day_label\n}; ++ my $srcpage; my $destpage; ++ while(($srcpage,$destpage) = each(%{$linkcache{$key}})) { ++ my $title = IkiWiki::basename(pagename($srcpage)); ++ if (exists $pagestate{$srcpage}{meta}{title} ) { ++ $title = $pagestate{$srcpage}{meta}{title}; ++ } ++ $calendar.=qq{\t\t<div class=\"$tag $downame{$wday}\">}; ++ $calendar.=htmllink($params{page}, $params{destpage}, ++ pagename($destpage), ++ linktext => $title); ++ push @list, pagename($linkcache{$key}{$srcpage}); ++ $calendar.=qq{\t\t</div>}; ++ } ++ } + $calendar.=qq{</td>\n}; + } + else { + +</pre> +"""]] diff --git a/doc/forum/Calendar:_listing_multiple_entries_per_day/comment_2_2311b96483bb91dc25d5e3695bbca513._comment b/doc/forum/Calendar:_listing_multiple_entries_per_day/comment_2_2311b96483bb91dc25d5e3695bbca513._comment new file mode 100644 index 000000000..ef100b555 --- /dev/null +++ b/doc/forum/Calendar:_listing_multiple_entries_per_day/comment_2_2311b96483bb91dc25d5e3695bbca513._comment @@ -0,0 +1,12 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawnXybLxkPMYpP3yw4b_I6IdC3cKTD-xEdU" + nickname="Matt" + subject="comment 2" + date="2011-11-29T01:30:09Z" + content=""" +To revert the changes made above it is necessary not only to switch the detail level back down but to also regenerate the side-bar index.html file + + ikiwiki --setup blog.setup + +should do it. +"""]] diff --git a/doc/forum/Calendar:_listing_multiple_entries_per_day/comment_3_d23f0cedd0b9e937eaf200eef55ac457._comment b/doc/forum/Calendar:_listing_multiple_entries_per_day/comment_3_d23f0cedd0b9e937eaf200eef55ac457._comment new file mode 100644 index 000000000..2433967e5 --- /dev/null +++ b/doc/forum/Calendar:_listing_multiple_entries_per_day/comment_3_d23f0cedd0b9e937eaf200eef55ac457._comment @@ -0,0 +1,166 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawnXybLxkPMYpP3yw4b_I6IdC3cKTD-xEdU" + nickname="Matt" + subject="comment 3" + date="2011-11-30T20:42:55Z" + content=""" +I got to grip with things to make a patch to do this. :-) + +Here it is in case of use to anyone. + +<pre> +From f0554c5b61e1915086d5cf071f095ff233c2590d Mon Sep 17 00:00:00 2001 +From: Matt Ford <matt@dancingfrog.co.uk> +Date: Wed, 30 Nov 2011 19:40:10 +0000 +Subject: [PATCH] Patch to allow daily archival generation and link to them in + the calendar + +--- + IkiWiki/Plugin/calendar.pm | 17 ++++++++++++++++- + ikiwiki-calendar.in | 34 +++++++++++++++++++++++++++++++--- + templates/calendarday.tmpl | 5 +++++ + templates/calendarmonth.tmpl | 2 +- + templates/calendaryear.tmpl | 2 +- + 5 files changed, 54 insertions(+), 6 deletions(-) + create mode 100644 templates/calendarday.tmpl + +diff --git a/IkiWiki/Plugin/calendar.pm b/IkiWiki/Plugin/calendar.pm +index c7d2b7c..9999c03 100644 +--- a/IkiWiki/Plugin/calendar.pm ++++ b/IkiWiki/Plugin/calendar.pm +@@ -47,6 +47,13 @@ sub getsetup () { + safe => 1, + rebuild => 1, + }, ++ archiveday => { ++ type => \"boolean\", ++ example => 1, ++ description => \"enable archiving on a daily basis (otherwise monthly)\", ++ safe => 1, ++ rebuild => 1, ++ }, + archive_pagespec => { + type => \"pagespec\", + example => \"page(posts/*) and !*/Discussion\", +@@ -222,11 +229,19 @@ EOF + $tag='month-calendar-day-link'; + } + $calendar.=qq{\t\t<td class=\"$tag $downame{$wday}\">}; +- $calendar.=htmllink($params{page}, $params{destpage}, ++ if (exists $pagesources{\"$archivebase/$params{year}/$params{month}/\".sprintf(\"%02d\",$day)}) { ++ $calendar.=htmllink($params{page}, $params{destpage}, ++ \"$archivebase/$params{year}/$params{month}/\".sprintf(\"%02d\",$day), ++ noimageinline => 1, ++ linktext => \"$day\", ++ title => \"$key\"); ++ }else{ ++ $calendar.=htmllink($params{page}, $params{destpage}, + $linkcache{$key}, + noimageinline => 1, + linktext => $day, + title => pagetitle(IkiWiki::basename($linkcache{$key}))); ++ } + $calendar.=qq{</td>\n}; + } + else { +diff --git a/ikiwiki-calendar.in b/ikiwiki-calendar.in +index 037ef7d..af22bc5 100755 +--- a/ikiwiki-calendar.in ++++ b/ikiwiki-calendar.in +@@ -30,21 +30,44 @@ IkiWiki::checkconfig(); + my $archivebase = 'archives'; + $archivebase = $config{archivebase} if defined $config{archivebase}; + ++my $archiveday = 0; ++$archiveday = $config{archiveday} if defined $config{archiveday}; ++ + if (! defined $pagespec) { + $pagespec=$config{archive_pagespec} || \"*\"; + } + +-sub writearchive ($$;$) { ++sub is_leap_year { ++ my $year=shift; ++ return ($year % 4 == 0 && (($year % 100 != 0) || $year % 400 == 0)); ++} ++ ++sub month_days { ++ my $month=shift; ++ my $year=shift; ++ my $days_in_month = (31,28,31,30,31,30,31,31,30,31,30,31)[$month-1]; ++ if ($month == 2 && is_leap_year($year)) { ++ $days_in_month++; ++ } ++ return $days_in_month; ++} ++ ++sub writearchive ($$;$;$) { + my $template=template(shift); + my $year=shift; + my $month=shift; ++ my $day=shift; + +- my $page=defined $month ? \"$year/$month\" : $year; ++ my $page; ++ if (defined $year) {$page = \"$year\"}; ++ if (defined $month) {$page = \"$year/$month\"}; ++ if (defined $day) {$page = \"$year/$month/$day\"}; + + my $pagefile=newpagefile(\"$archivebase/$page\", $config{default_pageext}); + $template->param(pagespec => $pagespec); + $template->param(year => $year); + $template->param(month => $month) if defined $month; ++ $template->param(day => $day) if defined $day; + + if ($force || ! -e \"$config{srcdir}/$pagefile\") { + writefile($pagefile, $config{srcdir}, $template->output); +@@ -54,8 +77,13 @@ sub writearchive ($$;$) { + + foreach my $y ($startyear..$endyear) { + writearchive(\"calendaryear.tmpl\", $y); +- foreach my $m (qw{01 02 03 04 05 06 07 08 09 10 11 12}) { ++ foreach my $m (map {sprintf(\"%02d\",$_)} (1..12)) { + writearchive(\"calendarmonth.tmpl\", $y, $m); ++ if ($archiveday ) { ++ foreach my $d (map {sprintf(\"%02d\",$_)} (1..month_days($m,$y))) { ++ writearchive(\"calendarday.tmpl\", $y, $m, $d); ++ } ++ } + } + } + +diff --git a/templates/calendarday.tmpl b/templates/calendarday.tmpl +new file mode 100644 +index 0000000..ac963b9 +--- /dev/null ++++ b/templates/calendarday.tmpl +@@ -0,0 +1,5 @@ ++[[!sidebar content=\"\"\" ++[[!calendar type=month month=<TMPL_VAR MONTH> year=<TMPL_VAR YEAR> pages=\"<TMPL_VAR PAGESPEC>\"]] ++\"\"\"]] ++ ++[[!inline pages=\"creation_day(<TMPL_VAR DAY>) and creation_month(<TMPL_VAR MONTH>) and creation_year(<TMPL_VAR YEAR>) and <TMPL_VAR PAGESPEC>\" archive=\"yes\" show=0 feeds=no reverse=yes]] +diff --git a/templates/calendarmonth.tmpl b/templates/calendarmonth.tmpl +index 23cd954..c998c16 100644 +--- a/templates/calendarmonth.tmpl ++++ b/templates/calendarmonth.tmpl +@@ -2,4 +2,4 @@ + [[!calendar type=month month=<TMPL_VAR MONTH> year=<TMPL_VAR YEAR> pages=\"<TMPL_VAR PAGESPEC>\"]] + \"\"\"]] + +-[[!inline pages=\"creation_month(<TMPL_VAR MONTH>) and creation_year(<TMPL_VAR YEAR>) and <TMPL_VAR PAGESPEC>\" show=0 feeds=no reverse=yes]] ++[[!inline pages=\"creation_month(<TMPL_VAR MONTH>) and creation_year(<TMPL_VAR YEAR>) and <TMPL_VAR PAGESPEC>\" archive=\"yes\" show=0 feeds=no reverse=yes]] +diff --git a/templates/calendaryear.tmpl b/templates/calendaryear.tmpl +index 714bd6d..b6e33c5 100644 +--- a/templates/calendaryear.tmpl ++++ b/templates/calendaryear.tmpl +@@ -1 +1 @@ +-[[!calendar type=year year=<TMPL_VAR YEAR> pages=\"<TMPL_VAR PAGESPEC>\"]] ++[[!calendar type=year year=<TMPL_VAR YEAR> pages=\"<TMPL_VAR PAGESPEC>\" archive=\"yes\"]] +-- +1.7.7.3 + +: + +</pre> +"""]] diff --git a/doc/forum/Calendar:_listing_multiple_entries_per_day/comment_4_4be39c2043821848d4b25d0bf946a718._comment b/doc/forum/Calendar:_listing_multiple_entries_per_day/comment_4_4be39c2043821848d4b25d0bf946a718._comment new file mode 100644 index 000000000..a71276d6b --- /dev/null +++ b/doc/forum/Calendar:_listing_multiple_entries_per_day/comment_4_4be39c2043821848d4b25d0bf946a718._comment @@ -0,0 +1,15 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + nickname="joey" + subject="comment 4" + date="2012-02-21T17:23:00Z" + content=""" +To be clear, this patch creates a `yyyy/mm/dd` file for each day, listing the posts for that day, so the calendar can link to it rather than a random single post. + +While a valid solution certainly, that's a lot of added pages! Especially a high overhead for such a minor UI point as this. + +Surely something interesting could be done with javascript or some other form of UI to make clicking on a day in a calendar that has multiple posts present a list of them? That would have essentially no overhead, since the calendar plugin already has a list of the posts made on a given day. + +Ikiwiki already does something similar to deal with the case where a page has a great many backlinks.. It makes a UI element that, if hovered over, pops up a display of all the rest. This is done quite simply in the `page.tmpl` +using the popup and balloon CSS classes. Calendar could also use this. +"""]] diff --git a/doc/forum/Calendar:_listing_multiple_entries_per_day/comment_5_de545ebb6376066674ef2aaae4757b9c._comment b/doc/forum/Calendar:_listing_multiple_entries_per_day/comment_5_de545ebb6376066674ef2aaae4757b9c._comment new file mode 100644 index 000000000..fef852066 --- /dev/null +++ b/doc/forum/Calendar:_listing_multiple_entries_per_day/comment_5_de545ebb6376066674ef2aaae4757b9c._comment @@ -0,0 +1,97 @@ +[[!comment format=mdwn + username="spalax" + subject="Popup listing multiple entries per day" + date="2012-06-08T00:56:06Z" + content=""" +[[!tag patch]] + +Hello, +here is a patch that: + +- if there is a single entry in one day, does not change anything (compared to the previous version of the calendar plugin); +- if there are several entries, when mouse passes over the day, displays a popup listing all the entries of that day. + +That's all. No new pages for each day, takes as little space as it took before, and only a few lines more in the source. + +The only thing I am not totally happy with is the CSS. We have to say that the text is aligned on the left (otherwise, it is aligned on the right, as is each day of the calendar), but I do not know which place is the more sensible to put that line of CSS in. + +Regards, +-- Louis + + + diff --git a/IkiWiki/Plugin/calendar.pm b/IkiWiki/Plugin/calendar.pm + index d443198..2c9ed79 100644 + --- a/IkiWiki/Plugin/calendar.pm + +++ b/IkiWiki/Plugin/calendar.pm + @@ -86,8 +86,11 @@ sub format_month (@) { + my $year = $date[5] + 1900; + my $mtag = sprintf(\"%02d\", $month); + + - # Only one posting per day is being linked to. + - $linkcache{\"$year/$mtag/$mday\"} = $p; + + # Several postings per day + + if (! $linkcache{\"$year/$mtag/$mday\"}) { + + $linkcache{\"$year/$mtag/$mday\"} = []; + + } + + push(@{$linkcache{\"$year/$mtag/$mday\"}}, $p); + } + + my $pmonth = $params{month} - 1; + @@ -221,11 +224,36 @@ EOF + $tag='month-calendar-day-link'; + } + $calendar.=qq{\t\t<td class=\"$tag $downame{$wday}\">}; + - $calendar.=htmllink($params{page}, $params{destpage}, + - $linkcache{$key}, + - noimageinline => 1, + - linktext => $day, + - title => pagetitle(IkiWiki::basename($linkcache{$key}))); + + if ( scalar(@{$linkcache{$key}}) == 1) { + + # Only one posting on this page + + my $page = $linkcache{$key}[0]; + + $calendar.=htmllink($params{page}, $params{destpage}, + + $page, + + noimageinline => 1, + + linktext => $day, + + title => pagetitle(IkiWiki::basename($page))); + + } else { + + $calendar.=qq{<div class='popup'>$day<div class='balloon'>}; + + # Several postings on this page + + $calendar.=qq{<ul>}; + + foreach my $page (@{$linkcache{$key}}) { + + $calendar.= qq{\n\t\t\t<li>}; + + my $title; + + if (exists $pagestate{$page}{meta}{title}) { + + $title = \"$pagestate{$page}{meta}{title}\"; + + } else { + + $title = pagetitle(IkiWiki::basename($page)); + + } + + $calendar.=htmllink($params{page}, $params{destpage}, + + $page, + + noimageinline => 1, + + linktext => $title, + + title => $title); + + $calendar.= '</li>'; + + } + + $calendar.=qq{\n\t\t</ul>}; + + $calendar.=qq{</div></div>}; + + } + $calendar.=qq{</td>\n}; + } + else { + diff --git a/doc/style.css b/doc/style.css + old mode 100644 + new mode 100755 + index 6e2afce..4149229 + --- a/doc/style.css + +++ b/doc/style.css + @@ -316,6 +316,7 @@ div.progress-done { + .popup .paren, + .popup .expand { + display: none; + + text-align: left; + } + .popup:hover .balloon, + .popup:focus .balloon { + +"""]] diff --git a/doc/forum/Can_I_change_the_default_menu_items__63__.mdwn b/doc/forum/Can_I_change_the_default_menu_items__63__.mdwn new file mode 100644 index 000000000..58134ab6d --- /dev/null +++ b/doc/forum/Can_I_change_the_default_menu_items__63__.mdwn @@ -0,0 +1,6 @@ +I'm looking for a way to change the RecentChanges, Preferences, Branchable, Comment menu items from my wiki page. I can see that the value for these items are set in template variables. Is there a way I can change these variables? If so can you tell me how? + +Thanks, + +Maria + diff --git a/doc/forum/Can_I_change_the_default_menu_items__63__/comment_2_eb56fed3b5fc19c8dd49af4444a049c5._comment b/doc/forum/Can_I_change_the_default_menu_items__63__/comment_2_eb56fed3b5fc19c8dd49af4444a049c5._comment new file mode 100644 index 000000000..22b1c0558 --- /dev/null +++ b/doc/forum/Can_I_change_the_default_menu_items__63__/comment_2_eb56fed3b5fc19c8dd49af4444a049c5._comment @@ -0,0 +1,31 @@ +[[!comment format=mdwn + username="http://jmtd.livejournal.com/" + ip="188.222.50.68" + subject="comment 2" + date="2011-10-30T21:23:03Z" + content=""" +You need to define a `templatedir` and put a copy of your current version of ikiwiki's `page.tmpl` file into that directory. Then, edit around line 62 or thereabouts, e.g. + + <li><a href=\"<TMPL_VAR EDITURL>\" rel=\"nofollow\">Edit</a></li> + </TMPL_IF> + <TMPL_IF RECENTCHANGESURL> + -<li><a href=\"<TMPL_VAR RECENTCHANGESURL>\">RecentChanges</a></li> + +<li><a href=\"<TMPL_VAR RECENTCHANGESURL>\">Recent Changes</a></li> + </TMPL_IF> + <TMPL_IF HISTORYURL> + -<li><a href=\"<TMPL_VAR HISTORYURL>\">History</a></li> + +<li><a href=\"<TMPL_VAR HISTORYURL>\">Site history</a></li> + </TMPL_IF> + <TMPL_IF GETSOURCEURL> + -<li><a href=\"<TMPL_VAR GETSOURCEURL>\">Source</a></li> + +<li><a href=\"<TMPL_VAR GETSOURCEURL>\">View Source</a></li> + </TMPL_IF> + <TMPL_IF PREFSURL> + -<li><a href=\"<TMPL_VAR PREFSURL>\">Preferences</a></li> + +<li><a href=\"<TMPL_VAR PREFSURL>\">Your Preferences</a></li> + </TMPL_IF> + <TMPL_IF ACTIONS> + <TMPL_LOOP ACTIONS> + +— [[Jon]] +"""]] diff --git a/doc/forum/Can_I_have_different_favicons_for_each_folder__63__.mdwn b/doc/forum/Can_I_have_different_favicons_for_each_folder__63__.mdwn new file mode 100644 index 000000000..0fefb3560 --- /dev/null +++ b/doc/forum/Can_I_have_different_favicons_for_each_folder__63__.mdwn @@ -0,0 +1 @@ +I would like to have different favicons for different parts (folders) of my Ikiwiki site, like you can have different CSS files via the localstyle plugin. Is this possible? If not, could it be made possible? diff --git a/doc/forum/Can_I_have_different_favicons_for_each_folder__63__/comment_1_a01112ba235e2f44a7655c36ef680e7e._comment b/doc/forum/Can_I_have_different_favicons_for_each_folder__63__/comment_1_a01112ba235e2f44a7655c36ef680e7e._comment new file mode 100644 index 000000000..dee6e610e --- /dev/null +++ b/doc/forum/Can_I_have_different_favicons_for_each_folder__63__/comment_1_a01112ba235e2f44a7655c36ef680e7e._comment @@ -0,0 +1,19 @@ +[[!comment format=mdwn + username="http://smcv.pseudorandom.co.uk/" + nickname="smcv" + subject="comment 1" + date="2011-11-21T11:37:02Z" + content=""" +You could use [[plugins/pagetemplate]] to override all of `page.tmpl`, but +that's using a sledgehammer to crack a nut. + +Another way to do it would be to modify `IkiWiki/Plugins/favicon.pm` +to use `bestlink` to find the favicon, like [[plugins/localstyle]] does. +If you made it a config option (`localfavicon => 1` or something) +it could probably be included in ikiwiki as part of the official +[[plugins/favicon]] plugin? + +Another way would be to have a new `localfavicon` plugin which overrides +the template variable from [[plugins/favicon]], using `last => 1` to +make sure it \"wins\". +"""]] diff --git a/doc/forum/Can_I_have_different_favicons_for_each_folder__63__/comment_2_b8ccd3c29249eca73766f567bce12569._comment b/doc/forum/Can_I_have_different_favicons_for_each_folder__63__/comment_2_b8ccd3c29249eca73766f567bce12569._comment new file mode 100644 index 000000000..0c8ca3bce --- /dev/null +++ b/doc/forum/Can_I_have_different_favicons_for_each_folder__63__/comment_2_b8ccd3c29249eca73766f567bce12569._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="Franek" + ip="178.7.43.64" + subject="comment 2" + date="2012-06-25T09:58:03Z" + content=""" +I did as you suggested (finally) and created a simple modification of the [[plugins/favicon]] plugin: [[plugins/contrib/localfavicon]]. It checks for the \"localfavicon\" option, and if it is set, it uses bestlink() to determine which favicon to use for each page; if not, it behaves just like the original favicon plugin. +"""]] diff --git a/doc/forum/Can_Ikiwiki_recognize_multimarkdown_meta_tags__63__.mdwn b/doc/forum/Can_Ikiwiki_recognize_multimarkdown_meta_tags__63__.mdwn new file mode 100644 index 000000000..3e5fc8bb5 --- /dev/null +++ b/doc/forum/Can_Ikiwiki_recognize_multimarkdown_meta_tags__63__.mdwn @@ -0,0 +1,4 @@ +[[!meta author=tjgolubi]] + +It would be nice, if configured for multimarkdown, for ikiwiki to recognize and use/remove meta information from multimarkdown documents. +Title, Author, and Date would be especially nice. -- [[tjgolubi]] diff --git a/doc/forum/Can_OpenID_users_be_adminusers__63__.mdwn b/doc/forum/Can_OpenID_users_be_adminusers__63__.mdwn new file mode 100644 index 000000000..17c60c423 --- /dev/null +++ b/doc/forum/Can_OpenID_users_be_adminusers__63__.mdwn @@ -0,0 +1,69 @@ +I've just finished an upgrade to 3.141 and am trying to give myself admin rights to play with the new webadmin features. My login is via OpenID but from reading on the wiki I believe that OpenID users should be able to be granted admin rights. However I'm obviously doing something wrong as when I click on the "Preferences" link at the top of the page I don't see any admin features. + +My login is: http://adam.shand.net/ + +In .ikiwiki/userdb I see: + +> adam@shand.net +> email <br> +> password <br> +> locked_pages <br> +> banned <br> +> 1229722296 <br> +> regdate <br> +> http://adam.shand.net/ <br> + +And in my config file I have: + +> adminuser => [qw{http://adam.shand.net/}], + +Any pointers to what I'm doing wrong would be much appreciated. + +Thanks, +Adam. + +> This is certianly supposed to work. For example, the admin +> user on my ikiwikis is `http://joey.kitenet.net/` +> +> The only caveat I know of to make it work is that the +> adminuser openid url has to exactly match the openid url that +> ikiwiki sees when you log in. Including any trailing slash, +> and the `http://`. --[[Joey]] + +>> Hrm, it's not working. I'm sure I've made a silly mistake somewhere but +>> I've looked and looked and just can't find it. Any suggestions on where +>> to look for debugging information would be much appreciated. -- [[Adam]] + +>>> Well, you could use this patch to add debugging info about admin +>>> username comparisons: + +<pre> +diff --git a/IkiWiki/UserInfo.pm b/IkiWiki/UserInfo.pm +index 0bf100a..77b467a 100644 +--- a/IkiWiki/UserInfo.pm ++++ b/IkiWiki/UserInfo.pm +@@ -71,6 +71,8 @@ sub userinfo_setall ($$) { + sub is_admin ($) { + my $user_name=shift; + ++ print STDERR "is_admin test @{$config{adminuser}} vs $user_name: ".(grep { $_ eq $user_name } @{$config{adminuser}})."\n"; ++ + return grep { $_ eq $user_name } @{$config{adminuser}}; + } + +</pre> + +>>>> After applying that change to what is probably +>>>> `/usr/share/perl5/IkiWiki/UserInfo.pm` on your system, +>>>> when you go to the preferences page it should log in your web server's +>>>> error.log, something like this: + + [Wed Jul 08 12:54:35 2009] [error] [client 127.0.1.1] is_admin test http://joey.kitenet.net/ vs http://joey.kitenet.net/: 1 + +>>>> So you can see if the two usernames/openids match. If the end is "0", +>>>> they don't match. If nothing is logged, you have not enabled the websetup plugin. +>>>> If the end if "1" you should see the "Setup" button, if not the +>>>> problem is not in determining if you're an admin, but elsewhere.. +>>>> --[[Joey]] + +I was being incredibly stupid and missed that websetup is a **plugin** and thus needed to be enabled. Many thanks for your patient assistance, by helping me eliminate the unlikely it eventually led me to the obvious. Cheers. -- [[Adam]] diff --git a/doc/forum/Can__39__t_call_method___34__distribution__34___on_an_undefined_value_at_FirstTime.pm.html b/doc/forum/Can__39__t_call_method___34__distribution__34___on_an_undefined_value_at_FirstTime.pm.html new file mode 100644 index 000000000..b68395856 --- /dev/null +++ b/doc/forum/Can__39__t_call_method___34__distribution__34___on_an_undefined_value_at_FirstTime.pm.html @@ -0,0 +1,64 @@ +This really look like a general PERL problem, but google search returns no relative result of undfined method 'distribution' at FireTime.pm at all. Answer on where to look for answer is appreciated too. Using perl 5.18 on NETBSD 6.1 + +<pre> +$ PERL5LIB=`pwd`/ikiwiki:`pwd`/ikiwiki/cpan:`pwd`/lib/perl5 PERL_MM_USE_DEFAULT=1 perl -MCPAN -e 'CPAN::Shell->install("Bundle::IkiWiki")' +perl: warning: Setting locale failed. +perl: warning: Please check that your locale settings: + LC_ALL = "en_US.UTF-8", + LANG = "en_US.UTF-8" + are supported and installed on your system. +perl: warning: Falling back to the standard locale ("C"). +perl: warning: Setting locale failed. +perl: warning: Please check that your locale settings: + LC_ALL = "en_US.UTF-8", + LANG = "en_US.UTF-8" + are supported and installed on your system. +perl: warning: Falling back to the standard locale ("C"). + +CPAN.pm requires configuration, but most of it can be done automatically. +If you answer 'no' below, you will enter an interactive dialog for each +configuration option instead. + +Would you like to configure as much as possible automatically? [yes] yes + + <install_help> + +Warning: You do not have write permission for Perl library directories. + +To install modules, you need to configure a local Perl library directory or +escalate your privileges. CPAN can help you by bootstrapping the local::lib +module or by configuring itself to use 'sudo' (if available). You may also +resolve this problem manually if you need to customize your setup. + +What approach do you want? (Choose 'local::lib', 'sudo' or 'manual') + [local::lib] local::lib + +Autoconfigured everything but 'urllist'. + +Now you need to choose your CPAN mirror sites. You can let me +pick mirrors for you, you can select them from a list or you +can enter them by hand. + +Would you like me to automatically choose some CPAN mirror +sites for you? (This means connecting to the Internet) [yes] yes +Trying to fetch a mirror list from the Internet +Fetching with LWP: +http://www.perl.org/CPAN/MIRRORED.BY + +Looking for CPAN mirrors near you (please be patient) +.......................... done! + +New urllist + http://cpan.llarian.net/ + http://mirrors.syringanetworks.net/CPAN/ + http://noodle.portalus.net/CPAN/ + +Autoconfiguration complete. + +Attempting to bootstrap local::lib... + +Writing /arpa/tz/w/weiwu/.local/share/.cpan/CPAN/MyConfig.pm for bootstrap... +commit: wrote '/arpa/tz/w/weiwu/.local/share/.cpan/CPAN/MyConfig.pm' +Can't call method "distribution" on an undefined value at /usr/pkg/lib/perl5/5.18.0/CPAN/FirstTime.pm line 1257. +$ rm -r /arpa/tz/w/weiwu/.local/share/.cpan/ +</pre> diff --git a/doc/forum/Can__39__t_get_comments_plugin_working.mdwn b/doc/forum/Can__39__t_get_comments_plugin_working.mdwn new file mode 100644 index 000000000..f189d9b64 --- /dev/null +++ b/doc/forum/Can__39__t_get_comments_plugin_working.mdwn @@ -0,0 +1,16 @@ +I feel like I must be missing something. + +My blog is based on Ikiwiki, and uses /yyyy/mm/dd/title/ for blog posts. +Because I use the plugin that generates index pages for subdirectories, I +have to use /????/??/??/* to identify posts and avoid missing the index +pages for years, months and days. + +I've enabled the comments plugin, but no matter what I do, I can't seem to make the comment form appear on my posts. I've removed the entire site and have rebuilt. I've set the pagespec to /????/??/??/* and ./????/??/??/*, but neither seems to work. I don't see any output, or anything else to indicate that pages aren't working. + +Are there any other plugins that need to be enabled for this to work? I think I've locked things down such that anonymous users can't edit by enabling signinedit and setting a lock, but this may be blocking the ability to comment (though I don't recall seeing anything in the docs about needing additional plugins.) + +> Just use '????/??/??/*' , and it will work. +> [[Pagespecs|ikiwiki/pagespec]] are automatically matched absolute to the +> top of the site, and adding a leading "/" is not necessary and will +> make the PageSpec not match. (And the relative PageSpec with "./" is +> not right in this case either). --[[Joey]] diff --git a/doc/forum/Can__39__t_get_ikiwiki_working_again_after_reinstall.mdwn b/doc/forum/Can__39__t_get_ikiwiki_working_again_after_reinstall.mdwn new file mode 100644 index 000000000..08187e6f2 --- /dev/null +++ b/doc/forum/Can__39__t_get_ikiwiki_working_again_after_reinstall.mdwn @@ -0,0 +1,16 @@ +My server got hacked by an EXIM vulnerability, and so I reimaged the system. After installing ikiwiki I can't get it to accept my old setup file, and I'm not sure what to do. + +I'm running debian stable with security updates. Running setup I get. +Can't use an undefined value as an ARRAY reference at /usr/share/perl5/IkiWiki/Setup/Standard.pm line 33. +That line in the source file has something todo with wrappers. Also since the reinstall there is no /etc/ikiwiki/auto.setup + +After futzing with it for over an hour I tried installing the debian backports version, and get a new different error. + +Can't exec "git": No such file or directory at /usr/share/perl5/IkiWiki/Plugin/git.pm line 169. +Cannot exec 'git pull origin': No such file or directory +'git pull origin' failed: at /usr/share/perl5/IkiWiki/Plugin/git.pm line 195. +Can't exec "git": No such file or directory at /usr/share/perl5/IkiWiki/Plugin/git.pm line 169. +Cannot exec 'git log --max-count=100 --pretty=raw --raw --abbrev=40 --always -c -r HEAD -- .': No such file or directory +'git log --max-count=100 --pretty=raw --raw --abbrev=40 --always -c -r HEAD -- .' failed: + +Any ideas how I can get ikiwiki working again? diff --git a/doc/forum/Can__39__t_get_ikiwiki_working_again_after_reinstall/comment_1_87a360155ff0502fe08274911cc6a53f._comment b/doc/forum/Can__39__t_get_ikiwiki_working_again_after_reinstall/comment_1_87a360155ff0502fe08274911cc6a53f._comment new file mode 100644 index 000000000..fa974765f --- /dev/null +++ b/doc/forum/Can__39__t_get_ikiwiki_working_again_after_reinstall/comment_1_87a360155ff0502fe08274911cc6a53f._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawkpwzlIQkUFJvJ8dF2-Y-sQklGpVB1fTzk" + nickname="Daniel" + subject="Fixed." + date="2011-01-19T10:18:16Z" + content=""" +Oops forgot to install git. Could have used a more helpful error message. +"""]] diff --git a/doc/forum/Can__39__t_login_using_Google__44___or_openID__44___but_can_use_Ikiwiki_login.mdwn b/doc/forum/Can__39__t_login_using_Google__44___or_openID__44___but_can_use_Ikiwiki_login.mdwn new file mode 100644 index 000000000..11d8c23a8 --- /dev/null +++ b/doc/forum/Can__39__t_login_using_Google__44___or_openID__44___but_can_use_Ikiwiki_login.mdwn @@ -0,0 +1,5 @@ +I find that users can't login my Ikiwiki instance using Google, or openID, but can use Ikiwiki user name and password to login. + +Using the two formers get error + + Error: ... is locked and cannot be edited diff --git a/doc/forum/Can__39__t_login_using_Google__44___or_openID__44___but_can_use_Ikiwiki_login/comment_1_79127e3c09a1d798146088dee5a67708._comment b/doc/forum/Can__39__t_login_using_Google__44___or_openID__44___but_can_use_Ikiwiki_login/comment_1_79127e3c09a1d798146088dee5a67708._comment new file mode 100644 index 000000000..41ff2fc36 --- /dev/null +++ b/doc/forum/Can__39__t_login_using_Google__44___or_openID__44___but_can_use_Ikiwiki_login/comment_1_79127e3c09a1d798146088dee5a67708._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + nickname="joey" + subject="comment 1" + date="2011-12-22T16:15:34Z" + content=""" +That error message means that the user has logged in, but the lockedit plugin has been configured, via `locked_pages` to not let some pages be edited by them. + +Inability to log in with openid is a separate problem, I can only guess as you didn't say how it fails when you try to log in by openid, but perhaps you need to install the Net::OpenID::Consumer perl module from cpan. +"""]] diff --git a/doc/forum/Can_custom_themes_live_somewhere_inside_srcdir__63__.mdwn b/doc/forum/Can_custom_themes_live_somewhere_inside_srcdir__63__.mdwn new file mode 100644 index 000000000..a07c31c00 --- /dev/null +++ b/doc/forum/Can_custom_themes_live_somewhere_inside_srcdir__63__.mdwn @@ -0,0 +1,8 @@ +Do custom [[themes]] have to live outside of the wiki (eg. `/usr/share/ikiwiki/themes/`) or is there a way for them to live inside of the wiki srcdir? + +I haven't been able to find a way so for now I'm just using a symlink, but that's a bit ugly. + +I ask because I do most of my ikiwiki work on my laptop and then push changes to my server. It's not a big deal but it's annoying to have to sync the themes separately and it seems like something which should be able to live inside the wiki like templates. + +Cheers, +[[AdamShand]] diff --git a/doc/forum/Can_custom_themes_live_somewhere_inside_srcdir__63__/comment_1_d1e79825dfb5213d2d1cba2ace1707b1._comment b/doc/forum/Can_custom_themes_live_somewhere_inside_srcdir__63__/comment_1_d1e79825dfb5213d2d1cba2ace1707b1._comment new file mode 100644 index 000000000..027127b41 --- /dev/null +++ b/doc/forum/Can_custom_themes_live_somewhere_inside_srcdir__63__/comment_1_d1e79825dfb5213d2d1cba2ace1707b1._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://smcv.pseudorandom.co.uk/" + nickname="smcv" + subject="comment 1" + date="2011-01-29T18:17:40Z" + content=""" +The theme plugin is just a shortcut for adding an underlay with a style.css and maybe some images. If you want to base your design on a modified theme, copy the theme's style.css (or part of it) to the local.css in your wiki's repository; you can also copy in the images and disable the theme plugin entirely. +"""]] diff --git a/doc/forum/Can_custom_themes_live_somewhere_inside_srcdir__63__/comment_2_8177ede5a586b1a573a13fd26f8d3cc0._comment b/doc/forum/Can_custom_themes_live_somewhere_inside_srcdir__63__/comment_2_8177ede5a586b1a573a13fd26f8d3cc0._comment new file mode 100644 index 000000000..2b312731e --- /dev/null +++ b/doc/forum/Can_custom_themes_live_somewhere_inside_srcdir__63__/comment_2_8177ede5a586b1a573a13fd26f8d3cc0._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://adam.shand.net/" + nickname="Adam" + subject="Doh." + date="2011-01-29T19:32:18Z" + content=""" +Ah that makes sense, thanks! +"""]] diff --git a/doc/forum/Can_ikiwiki_be_configured_as_multi_user_blog__63__.mdwn b/doc/forum/Can_ikiwiki_be_configured_as_multi_user_blog__63__.mdwn new file mode 100644 index 000000000..118b534ed --- /dev/null +++ b/doc/forum/Can_ikiwiki_be_configured_as_multi_user_blog__63__.mdwn @@ -0,0 +1,7 @@ +All the ikiwiki blogs I have seen have a single user blog. Is it possible to give every user a blog, where they can create their own pages in their own directory = based on their user name? + +I feel that a wiki might give more options in the way users share and collaborate when compared to a blog engine (like Word Press in multi user format) + +Is this the best place to post a question like this? There doesn't seem to be much traffic in this forum +Thanks for your help +Richard diff --git a/doc/forum/Can_ikiwiki_be_configured_as_multi_user_blog__63__/comment_1_8e34b10699bed1b53b6c929ed1e9f19c._comment b/doc/forum/Can_ikiwiki_be_configured_as_multi_user_blog__63__/comment_1_8e34b10699bed1b53b6c929ed1e9f19c._comment new file mode 100644 index 000000000..1f0577c9c --- /dev/null +++ b/doc/forum/Can_ikiwiki_be_configured_as_multi_user_blog__63__/comment_1_8e34b10699bed1b53b6c929ed1e9f19c._comment @@ -0,0 +1,32 @@ +[[!comment format=mdwn + username="http://smcv.pseudorandom.co.uk/" + nickname="smcv" + subject="It's a wiki: any editor can have as many blogs as they want" + date="2013-07-17T08:17:05Z" + content=""" +Ikiwiki is a wiki, so you can certainly have multiple users. Any user +with appropriate access can create any number of blogs: they just need +to put an [[ikiwiki/directive/inline]] directive on any page they can +edit, with a [[ikiwiki/PageSpec]] pointing to pages (blog posts) in a +directory where they can create pages. + +If you want a limited set of users to be able to edit the wiki without +making them full wiki admins, you can use [[plugins/lockedit]]: + + locked_pages: * and !(user(bob) or user(chris)) + +or if you want \"most\" users to only be able to write on their own blog, and +not on other users' blogs (for instance: Alice the wiki admin can edit +anything, but Bob can only edit `users/bob/...` and Chris can only edit +`users/chris/...`) then you can use [[plugins/lockedit]], something like: + + locked_pages: * and !(user(bob) and (users/bob or users/bob/*)) and !(user(chris) and (users/chris or users/chris/*)) + +(Wiki admins can always edit locked pages.) + +If you have lots of users and you know a bit of Perl, you might want +to [[write a plugin|plugins/write]] that adds a function-like +[[ikiwiki/PageSpec]] like `owndirectory(users)`, which would match if +there is a logged-in user and the page being edited is equal to or +a subpage of their directory in users. +"""]] diff --git a/doc/forum/Can_ikiwiki_be_configured_as_multi_user_blog__63__/comment_2_6083e16f72e12c03bdf739b84bd2f352._comment b/doc/forum/Can_ikiwiki_be_configured_as_multi_user_blog__63__/comment_2_6083e16f72e12c03bdf739b84bd2f352._comment new file mode 100644 index 000000000..10929a35a --- /dev/null +++ b/doc/forum/Can_ikiwiki_be_configured_as_multi_user_blog__63__/comment_2_6083e16f72e12c03bdf739b84bd2f352._comment @@ -0,0 +1,12 @@ +[[!comment format=mdwn + username="http://smcv.pseudorandom.co.uk/" + nickname="smcv" + subject="comment 2" + date="2013-07-17T08:23:32Z" + content=""" +IkiWiki's own [[bugs]], [[news]] and [[to-do list|todo]] are functionally +equivalent to blogs, in fact. ([[news]] is the most obviously blog-like, +[[bugs]] is like a blog except that solved bugs disappear from the +page/feed, and [[todo]] only shows titles, not content, but is otherwise +like [[bugs]].) +"""]] diff --git a/doc/forum/Can_not_advance_past_first_page_of_results_using_search_plugin.mdwn b/doc/forum/Can_not_advance_past_first_page_of_results_using_search_plugin.mdwn new file mode 100644 index 000000000..1a9391e48 --- /dev/null +++ b/doc/forum/Can_not_advance_past_first_page_of_results_using_search_plugin.mdwn @@ -0,0 +1,26 @@ +I'm using the [[/plugins/search/]] plugin and it correctly displays the first page of results, but the "Next" button doesn't work. + +If I search for "linux", for example, I see "1-10 of exactly 65 matches" and this in my browser's address bar: https://example.com/ikiwiki.cgi?P=linux + +Then, I scroll down and click "Next" and I see. . . + +> Although this page is encrypted, the information you have entered is to be sent over an unencrypted connection and could easily be read by a third party. +> +> Are you sure you want to continue sending this information? + +. . . then I click "Continue" but I'm stuck on the first page of search results (it still says "1-10 of exactly 65 matches") and I have the following in my browser's address bar: + +https://example.com/ikiwiki.cgi?P=linux&DEFAULTOP=or&%253E=Next&DB=default&FMT=query&xP=Zlinux&xDB=default&xFILTERS=--O + +I noticed that if I change what's in the address bar to the following, I **can** advance to page 2 (it shows "11-20 of exactly 65 matches"). That is to say, I'm removing "25" from "%253E" as a work around: + +https://example.com/ikiwiki.cgi?P=linux&DEFAULTOP=or&%3E=Next&DB=default&FMT=query&xP=Zlinux&xDB=default&xFILTERS=--O + +Based on this output, I might need to make a change to "searchquery.tmpl", which is under [[/templates]]. . . + + [wikiuser@ikiwiki1 ~]$ grep -r DEFAULTOP /usr/share/ikiwiki + /usr/share/ikiwiki/templates/searchquery.tmpl:<SELECT NAME=DEFAULTOP> + [wikiuser@ikiwiki1 ~]$ rpm -qf /usr/share/ikiwiki/templates/searchquery.tmpl + ikiwiki-3.20120202-1.el6.noarch + +. . . but I would appreciate any guidance on what the fix might be. diff --git a/doc/forum/Can_one_tell_if_a_page_is_added_rather_than_changed__63__.mdwn b/doc/forum/Can_one_tell_if_a_page_is_added_rather_than_changed__63__.mdwn new file mode 100644 index 000000000..4c06cbabb --- /dev/null +++ b/doc/forum/Can_one_tell_if_a_page_is_added_rather_than_changed__63__.mdwn @@ -0,0 +1,5 @@ +In the plugin interface, there are hooks for "deleted" and "changed" and the "changed" interfaces includes files which are *either* changed or added. Is there any way of telling that a file has been added rather than changed? With some plugins (for example, [[plugins/sidebar]]) if a new page (of a certain sort) is added, the only way one can fix up the dependencies is to rebuild the whole site from scratch. This is Not Good. Now, one could do something in the "changed" hook, but since one can't tell if a file has been changed or added, if one did something for every changed file, one would be doing a lot of needless work (so one might as well rebuild the site when one *knows* that a new (relevant) page has been added). + +But I really would like to be able to do things just to the *new* files, so is there any way that one can distinguish the changed files from the added files? + +-- [[KathrynAndersen]] diff --git a/doc/forum/Can_one_tell_if_a_page_is_added_rather_than_changed__63__/comment_1_1397feebfb0fb7cc57af2f8b74ce047e._comment b/doc/forum/Can_one_tell_if_a_page_is_added_rather_than_changed__63__/comment_1_1397feebfb0fb7cc57af2f8b74ce047e._comment new file mode 100644 index 000000000..7ddbb40fd --- /dev/null +++ b/doc/forum/Can_one_tell_if_a_page_is_added_rather_than_changed__63__/comment_1_1397feebfb0fb7cc57af2f8b74ce047e._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + nickname="joey" + subject="comment 1" + date="2011-06-20T00:22:54Z" + content=""" +I think that presence dependencies mostly cover this case. But no, there is not currently a hook that gets information about which files changed vs were added. The information is available at the time the hooks are called so some new ones could be added. +"""]] diff --git a/doc/forum/Can_one_tell_if_a_page_is_added_rather_than_changed__63__/comment_2_ad36c945f59fe525428fc30246911ff5._comment b/doc/forum/Can_one_tell_if_a_page_is_added_rather_than_changed__63__/comment_2_ad36c945f59fe525428fc30246911ff5._comment new file mode 100644 index 000000000..4cffde3fc --- /dev/null +++ b/doc/forum/Can_one_tell_if_a_page_is_added_rather_than_changed__63__/comment_2_ad36c945f59fe525428fc30246911ff5._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="http://kerravonsen.dreamwidth.org/" + ip="202.173.183.92" + subject="comment 2" + date="2011-06-20T03:24:49Z" + content=""" +If new hooks could be added, that would be greatly appreciated. Perhaps two new hooks: `added` and `updated` (the \"updated\" hook would be for files which were already-existing files which were changed). + +--[[KathrynAndersen]] +"""]] diff --git a/doc/forum/Can_someone_update_ikiwki_in_Macports__63__.mdwn b/doc/forum/Can_someone_update_ikiwki_in_Macports__63__.mdwn new file mode 100644 index 000000000..f1208622c --- /dev/null +++ b/doc/forum/Can_someone_update_ikiwki_in_Macports__63__.mdwn @@ -0,0 +1,5 @@ +The Ikiwiki in Macports is a very old version: + + $ ikiwiki --version + ikiwiki version 3.20110608 + diff --git a/doc/forum/Can_someone_update_ikiwki_in_Macports__63__/comment_1_87365ded9b202607d6431daf4e76e3c1._comment b/doc/forum/Can_someone_update_ikiwki_in_Macports__63__/comment_1_87365ded9b202607d6431daf4e76e3c1._comment new file mode 100644 index 000000000..b01e742f2 --- /dev/null +++ b/doc/forum/Can_someone_update_ikiwki_in_Macports__63__/comment_1_87365ded9b202607d6431daf4e76e3c1._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawlcaGfdn9Kye1Gc8aGb67PDVQW4mKbQD7E" + nickname="Amitai" + subject="that someone is probably elsewhere" + date="2013-09-14T18:04:24Z" + content=""" +Have you tried contacting the package maintainer or, failing that, submitting an update request to the relevant mailing list? + +(Note that [[I've asked this question before|forum/build_error:_Cannot_decode_string_with_wide_characters/#comment-8eb5e0300e6224157e0d7d55bf956bb8]].) +"""]] diff --git a/doc/forum/Cannot_write_to_commitlock.mdwn b/doc/forum/Cannot_write_to_commitlock.mdwn new file mode 100644 index 000000000..07e53453a --- /dev/null +++ b/doc/forum/Cannot_write_to_commitlock.mdwn @@ -0,0 +1,32 @@ +I am following the laptop wiki with git tip page. I have set up my local and remote wiki as suggested. However, when I try to push my local changes back to the server I get the following error: + +Writing objects: 100% (4/4), 359 bytes, done. +Total 4 (delta 2), reused 0 (delta 0) +cannot write to /home/ian/ianbarton/.ikiwiki/commitlock: No such file or directory +To ian@wilkesley.org:~/ikiwiki/ianbarton.git + 5cf9054..16a871d master -> master + +The relevnt bit of my setup file is: + +git_wrapper => '/home/ian/ianbarton.git/hooks/post-commit', + +Now ~/ianbarton/.ikiwiki exists and is owned and writable by me. I have tried touching commitlock and also removing lock and commitlock before pushing. Any suggestions for further trouble shooting? + +Ian. + +> I'm guessing that this is some kind of permissions problem, +> and that the error message is just being misleading. +> +> When you push the changes to the server, what user is +> git logging into the server as? If that user is different +> than `ian` (possibly due to using git-daemon?), the post-commit +> wrapper needs to be setuid to `ian`. This ensures that ikiwiki +> runs as you and can see and write to the files. --[[Joey]] + +The user is logging as ian, the same user as the laptop. I can push and pull git repos on the same server owned by the same user via ssh with no problem. I have deleted and re-started from scratch several times. However, for my use case I think it's simpler to keep the repo on my local computer and just rsync the web pages to the server. + +Ian. + +Ian, you've copied over the repo created by ikiwiki --setup, which contains hook/post-update - just remove that file which is not required anymore on the git server side. + +Serge diff --git a/doc/forum/Chinese_file_name_corruption.mdwn b/doc/forum/Chinese_file_name_corruption.mdwn new file mode 100644 index 000000000..49d7d5b3f --- /dev/null +++ b/doc/forum/Chinese_file_name_corruption.mdwn @@ -0,0 +1,5 @@ +I added a file with Chinese file name, and committed and pushed it to my Ikiwiki instance on Web. It displays correctly in browser. But, the file name shows up like + +http://i53.tinypic.com/2cikb9y.png + +Is there a way to fix it? diff --git a/doc/forum/Chinese_file_name_corruption/comment_1_765ac8b6f70083bb5aaaaac5beab461f._comment b/doc/forum/Chinese_file_name_corruption/comment_1_765ac8b6f70083bb5aaaaac5beab461f._comment new file mode 100644 index 000000000..c3e17c205 --- /dev/null +++ b/doc/forum/Chinese_file_name_corruption/comment_1_765ac8b6f70083bb5aaaaac5beab461f._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + nickname="joey" + subject="comment 1" + date="2011-08-05T21:03:11Z" + content=""" +It's hard to tell from this small screenshot what I'm supposed to be looking at, but the \"Parent directory\" and date suggests this is an apache dirindex listing, which has nothing to do with ikiwiki. + +Ikiwiki is (or attempts to be) utf-8 clean on filenames and content, so as long as you use that encoding and have the requisite fonts your chinese filenames will display ok in ikiwiki. Apache probably doesn't try to get this right at all, or needs some more configuration. +"""]] diff --git a/doc/forum/Clarification_on_--cgi_option.mdwn b/doc/forum/Clarification_on_--cgi_option.mdwn new file mode 100644 index 000000000..182b09b4b --- /dev/null +++ b/doc/forum/Clarification_on_--cgi_option.mdwn @@ -0,0 +1,4 @@ + +May anyone explain what's the intended use of --cgi option ? + +I understand you may run the cgi wrapper from command line using --cgi, but what is this option useful for ?. Perhaps for use with SSI pages ?. Any example ? diff --git a/doc/forum/Clarification_on_--cgi_option/comment_1_deda457e4bff7dfe630dbc0192dfddea._comment b/doc/forum/Clarification_on_--cgi_option/comment_1_deda457e4bff7dfe630dbc0192dfddea._comment new file mode 100644 index 000000000..9ead810f6 --- /dev/null +++ b/doc/forum/Clarification_on_--cgi_option/comment_1_deda457e4bff7dfe630dbc0192dfddea._comment @@ -0,0 +1,11 @@ +[[!comment format=mdwn + username="http://smcv.pseudorandom.co.uk/" + nickname="smcv" + subject="comment 1" + date="2011-10-05T11:10:26Z" + content=""" +The `--cgi` option is for internal use (the compiled CGI wrapper +basically cleans the environment, and runs `ikiwiki --cgi ...` +to do the real work). It isn't useful from a command line unless +you're doing something extremely strange. +"""]] diff --git a/doc/forum/Commiting_all_moderated_comments_into_special_branch__63__.mdwn b/doc/forum/Commiting_all_moderated_comments_into_special_branch__63__.mdwn new file mode 100644 index 000000000..e45069c63 --- /dev/null +++ b/doc/forum/Commiting_all_moderated_comments_into_special_branch__63__.mdwn @@ -0,0 +1,8 @@ +I only interact with ikiwiki via cli & git; thus I would love to be able to moderate comments via git from all remote checkouts without being forced to ssh to my server and do that locally. + +Is anyone aware of a way to check all comments into a special branch, possibly called "moderation", and with a normal suffix, not "_comment_pending"? That would allow me to cherry-pick from that branch without having to remember to rename and simply delete all spam etc from the branch. + +Every now and then, I could delete the whole branch, thus cleaning out crud. As the approved comments live in master, that would not be a problem. + + +RichiH diff --git a/doc/forum/Commiting_all_moderated_comments_into_special_branch__63__/comment_1_8403e8ff9c5c8dddb6d744632322f7bc._comment b/doc/forum/Commiting_all_moderated_comments_into_special_branch__63__/comment_1_8403e8ff9c5c8dddb6d744632322f7bc._comment new file mode 100644 index 000000000..5aa5af039 --- /dev/null +++ b/doc/forum/Commiting_all_moderated_comments_into_special_branch__63__/comment_1_8403e8ff9c5c8dddb6d744632322f7bc._comment @@ -0,0 +1,12 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + nickname="joey" + subject="comment 1" + date="2012-03-22T16:56:39Z" + content=""" +A branch makes sense if it's used in a way that never ties its history with mainline, so all the spam can eventually be dropped out of git, by deleting the branch. Though this is clearly an expert user level option. + +Probably the easiest way to get there would be to keep the branch, checked out, in `.ikiwiki/comments_pending/`. The old code that used that directory is still in ikiwiki for backwards compatability, so it should be easy to get comments written into that location. Then a minimum of vcs-specific code would be needed to set up the branch and commit pending comments to it. + +But there's a wrinkle -- if you just cherry pick from that branch, the comments_pending directory will retain all the old spam, growing without bounds. And the web moderation interface will show them all. I suppose you could check out the branch and revert or delete spammy comments too, but this is feeling like a lot of work the user needs to do in order to use git to moderate spammy comments. I have to think most users would prefer, as I do, to occasionally flailing at a web form in this case. +"""]] diff --git a/doc/forum/Darcs_as_the_RCS___63__.mdwn b/doc/forum/Darcs_as_the_RCS___63__.mdwn new file mode 100644 index 000000000..9664240ee --- /dev/null +++ b/doc/forum/Darcs_as_the_RCS___63__.mdwn @@ -0,0 +1,13 @@ +Hi, + +I have successfully installed and set up my first instance of [[ikiwiki]] on my dedicated server. Following [[joey]]'s screencasts made this easy (thank you). + +Currently, I have set up the RCS to be git but I do not like this very much. I'd rather want darcs but if I replace rcs settings, it fails. + +What should I put in the configuration file to use darcs ? + +> Darcs is not yet supported. It's being [[worked_on|todo/darcs]]. + +> > That's good news for me then ! Thank you. + +>>> Better news: It will be in version 2.10. --[[Joey]] diff --git a/doc/forum/Debian_5.0.7:_Can__39__t_locate_IkiWiki__47__Setup__47__Automator.pm.mdwn b/doc/forum/Debian_5.0.7:_Can__39__t_locate_IkiWiki__47__Setup__47__Automator.pm.mdwn new file mode 100644 index 000000000..b501a11c8 --- /dev/null +++ b/doc/forum/Debian_5.0.7:_Can__39__t_locate_IkiWiki__47__Setup__47__Automator.pm.mdwn @@ -0,0 +1,19 @@ +Hi People, + +first thanks for this nice an usable piece of software. + +Recently i moved to a new server, reinstalled ikiwiki via aptitude and now i'm getting this error: + + ikiwiki -setup /etc/ikiwiki/auto.setup + /etc/ikiwiki/auto.setup: Can't locate IkiWiki/Setup/Automator.pm in @INC (@INC contains: /etc/perl /usr/local/lib/perl/5.10.0 /usr/local/share/perl/5.10.0 /usr/lib/perl5 /usr/share/perl5 /usr/lib/perl/5.10 /usr/share/perl/5.10 /usr/local/lib/site_perl .) at (eval 10) line 13. + +Or with an existing wiki: + + ikiwiki -setup younameit.setup + younameit.setup: Can't use an undefined value as an ARRAY reference at /usr/share/perl5/IkiWiki/Setup/Standard.pm line 33. + BEGIN failed--compilation aborted at (eval 10) line 293. + +Can you help? + +Best wishes, +Tobias. diff --git a/doc/forum/Debian_5.0.7:_Can__39__t_locate_IkiWiki__47__Setup__47__Automator.pm/comment_1_aec4bf4ca7d04d580d2fa83fd3f7166f._comment b/doc/forum/Debian_5.0.7:_Can__39__t_locate_IkiWiki__47__Setup__47__Automator.pm/comment_1_aec4bf4ca7d04d580d2fa83fd3f7166f._comment new file mode 100644 index 000000000..2c884e261 --- /dev/null +++ b/doc/forum/Debian_5.0.7:_Can__39__t_locate_IkiWiki__47__Setup__47__Automator.pm/comment_1_aec4bf4ca7d04d580d2fa83fd3f7166f._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + nickname="joey" + subject="comment 1" + date="2011-01-25T19:18:21Z" + content=""" +You're using an old version of ikiwiki with setup files from a newer version. That won't work for various reasons, and the simplest fix is to upgrade your server to the version you had before. +"""]] diff --git a/doc/forum/Debian_5.0.7:_Can__39__t_locate_IkiWiki__47__Setup__47__Automator.pm/comment_4_c682ebb0e8e72088a8f92356dc31ef37._comment b/doc/forum/Debian_5.0.7:_Can__39__t_locate_IkiWiki__47__Setup__47__Automator.pm/comment_4_c682ebb0e8e72088a8f92356dc31ef37._comment new file mode 100644 index 000000000..35a258885 --- /dev/null +++ b/doc/forum/Debian_5.0.7:_Can__39__t_locate_IkiWiki__47__Setup__47__Automator.pm/comment_4_c682ebb0e8e72088a8f92356dc31ef37._comment @@ -0,0 +1,13 @@ +[[!comment format=mdwn + username="tk" + ip="79.222.20.29" + subject="comment 4" + date="2011-01-26T12:34:29Z" + content=""" +Thank you for the fast reply, Joey! +I tried it with ikiwiki from debian backports and it works as usual :) + +Bye, +Tobias. + +"""]] diff --git a/doc/forum/Debian_squeeze_still_on_3.20100815.7_-_update_recommended__63__.mdwn b/doc/forum/Debian_squeeze_still_on_3.20100815.7_-_update_recommended__63__.mdwn new file mode 100644 index 000000000..50b5ea900 --- /dev/null +++ b/doc/forum/Debian_squeeze_still_on_3.20100815.7_-_update_recommended__63__.mdwn @@ -0,0 +1,7 @@ +Unfortunately debian stable / squeeze repos are still on version 3.20100815.7 + +Do you think squeeze will update to a newer version soon? I am lacking support of the gallery plugin and 1 more that I forgot right now ;) + +Is everyone else upgrading by directly installing via dpkg (no updates, but yeah)? + +Regards diff --git a/doc/forum/Debian_squeeze_still_on_3.20100815.7_-_update_recommended__63__/comment_1_5e916c8fa90470909064ea73531f79d4._comment b/doc/forum/Debian_squeeze_still_on_3.20100815.7_-_update_recommended__63__/comment_1_5e916c8fa90470909064ea73531f79d4._comment new file mode 100644 index 000000000..e6d09b5ab --- /dev/null +++ b/doc/forum/Debian_squeeze_still_on_3.20100815.7_-_update_recommended__63__/comment_1_5e916c8fa90470909064ea73531f79d4._comment @@ -0,0 +1,12 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + nickname="joey" + subject="comment 1" + date="2012-01-16T14:52:22Z" + content=""" +Nothing wrong with 3.20100815.7 unless you need newer features. + +At Branchable we run Debian stable and backport the current ikiwiki to run on it. This is quite easy to do, it just builds and works. (Edit debian/control and s/markdown-discount/markdown/) + +It's probably time someone released a backport. I have historically not done that myself though. +"""]] diff --git a/doc/forum/Debian_squeeze_still_on_3.20100815.7_-_update_recommended__63__/comment_2_2fa15f0eaf8c860b82e366130c8563c7._comment b/doc/forum/Debian_squeeze_still_on_3.20100815.7_-_update_recommended__63__/comment_2_2fa15f0eaf8c860b82e366130c8563c7._comment new file mode 100644 index 000000000..07955ac38 --- /dev/null +++ b/doc/forum/Debian_squeeze_still_on_3.20100815.7_-_update_recommended__63__/comment_2_2fa15f0eaf8c860b82e366130c8563c7._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawndsaC4GaIBw49WNdbk2Faqfm_mrtQgul8" + nickname="Christian" + subject="thats cool" + date="2012-01-16T15:31:22Z" + content=""" +thanks +"""]] diff --git a/doc/forum/Debian_squeeze_still_on_3.20100815.7_-_update_recommended__63__/comment_3_c5af589dcdfe4f91dba50243762065e5._comment b/doc/forum/Debian_squeeze_still_on_3.20100815.7_-_update_recommended__63__/comment_3_c5af589dcdfe4f91dba50243762065e5._comment new file mode 100644 index 000000000..3ab401eb8 --- /dev/null +++ b/doc/forum/Debian_squeeze_still_on_3.20100815.7_-_update_recommended__63__/comment_3_c5af589dcdfe4f91dba50243762065e5._comment @@ -0,0 +1,12 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawndsaC4GaIBw49WNdbk2Faqfm_mrtQgul8" + nickname="Christian" + subject="Great! It worked!" + date="2012-01-17T01:18:06Z" + content=""" +Thanks Joey, also for the replacement hint, had to install one or two dependencies and it worked like a charm. Version from the day before yesterday now. (Awesome!) + +I have not upgraded the mypage.setup file, yet. I included \"headinganchors\" which does not seem to work right now. The page compiles without errors but contains no anchors when viewed in browser. Hm.. + +Great job thanks again! +"""]] diff --git a/doc/forum/Debian_squeeze_still_on_3.20100815.7_-_update_recommended__63__/comment_4_3090da7bafbf92a825edec8ffc45af20._comment b/doc/forum/Debian_squeeze_still_on_3.20100815.7_-_update_recommended__63__/comment_4_3090da7bafbf92a825edec8ffc45af20._comment new file mode 100644 index 000000000..569a73546 --- /dev/null +++ b/doc/forum/Debian_squeeze_still_on_3.20100815.7_-_update_recommended__63__/comment_4_3090da7bafbf92a825edec8ffc45af20._comment @@ -0,0 +1,12 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawndsaC4GaIBw49WNdbk2Faqfm_mrtQgul8" + nickname="Christian" + subject="updating setup file" + date="2012-01-17T01:30:32Z" + content=""" +just for the record - I created a new wiki and the setup file is then automatically in YAML format. I think I am going to just transfer the settings from the \"old\" setup file to the new one. + +If anyone has an idea why the headinganchors don't work, pls let me know. + +As for the rest - insanely cool piece of software - great +"""]] diff --git a/doc/forum/Define_custom_commands.mdwn b/doc/forum/Define_custom_commands.mdwn new file mode 100644 index 000000000..c8ac00eed --- /dev/null +++ b/doc/forum/Define_custom_commands.mdwn @@ -0,0 +1 @@ +Is it possible to define custom "commands" in ikiwiki? For example if I write &%test&% in the source of a wiki-page in markdown, the word "test" should be displayed red, bold and italic. diff --git a/doc/forum/Define_custom_commands/comment_1_7d82637bc8c706b69e4a55585677f6bf._comment b/doc/forum/Define_custom_commands/comment_1_7d82637bc8c706b69e4a55585677f6bf._comment new file mode 100644 index 000000000..da57072a9 --- /dev/null +++ b/doc/forum/Define_custom_commands/comment_1_7d82637bc8c706b69e4a55585677f6bf._comment @@ -0,0 +1,11 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + nickname="joey" + subject="comment 1" + date="2011-09-05T17:33:51Z" + content=""" +Plugins can be written that do this kind of arbitrary transformation. For +example, the smiley plugin does. + +However, this is not usual in ikiwiki, instead there is a specific syntax for a [[ikiwiki/directive]] that is used consistently for a great many things of this sort. +"""]] diff --git a/doc/forum/Different_behaviour_when_editing_with_editor_than_with_web-edit.mdwn b/doc/forum/Different_behaviour_when_editing_with_editor_than_with_web-edit.mdwn new file mode 100644 index 000000000..5440ddf73 --- /dev/null +++ b/doc/forum/Different_behaviour_when_editing_with_editor_than_with_web-edit.mdwn @@ -0,0 +1,24 @@ +Hi, + +today I encountered a strange behaviour of ikiwiki that I'm trying to understand... + +I linked to a subpage using + +\[[somename|/path/from/root/dir/filename]] + +and saved the file. Then I added it to the repo, committed it, and ran + + ikiwiki --setup setupfile.setup + +Afterwards some older links of the same style were displayed correctly, but one new link remained black - i.e. with no question mark to it. I figure that means ikiwiki has recognized the syntax but did not create a link in the html file. + +I messed around a bit, recompiling many times did not work. After a while I opened the file via the web editing formular and saved it from there ("Save Page"). + +After that the link was there. + +I dont know why. My question is - what does ikiwiki do differently when saved from the web form than when saving an editor and then running ikiwiki --setup setupfile.setup. + +Btw. my version is still 3.20100815.7 since I'm on squeeze and like to stick with the repo versions. + +Thanks in advance, +Chris diff --git a/doc/forum/Different_behaviour_when_editing_with_editor_than_with_web-edit/comment_1_ac6bda46ad00bfe980bc76c4a39aa796._comment b/doc/forum/Different_behaviour_when_editing_with_editor_than_with_web-edit/comment_1_ac6bda46ad00bfe980bc76c4a39aa796._comment new file mode 100644 index 000000000..91e7d9e7a --- /dev/null +++ b/doc/forum/Different_behaviour_when_editing_with_editor_than_with_web-edit/comment_1_ac6bda46ad00bfe980bc76c4a39aa796._comment @@ -0,0 +1,9 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawnam4a8RtFwaWkKOX2BkA5I7cpGHcFw8E0" + nickname="Christian" + subject="comment 1" + date="2011-12-03T17:17:57Z" + content=""" +with \"no question mark to it\" means \"being no link (target exists) AND with no question mark to it\" +thx +"""]] diff --git a/doc/forum/Different_behaviour_when_editing_with_editor_than_with_web-edit/comment_3_10a46f8ee23c8935e20c70842671cee4._comment b/doc/forum/Different_behaviour_when_editing_with_editor_than_with_web-edit/comment_3_10a46f8ee23c8935e20c70842671cee4._comment new file mode 100644 index 000000000..a14752ffe --- /dev/null +++ b/doc/forum/Different_behaviour_when_editing_with_editor_than_with_web-edit/comment_3_10a46f8ee23c8935e20c70842671cee4._comment @@ -0,0 +1,13 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawnam4a8RtFwaWkKOX2BkA5I7cpGHcFw8E0" + nickname="Christian" + subject="comment 3" + date="2011-12-03T17:25:58Z" + content=""" +One more thing: my syntax with the above post is not correct - the linking syntax was/is + + \[[somename|path/from/website/root/dir/filename]] + +ie. I got one slash too much above. + +"""]] diff --git a/doc/forum/Different_templates_for_subdirectories__63_____40__Blogging_and_Wiki_pages__41__.mdwn b/doc/forum/Different_templates_for_subdirectories__63_____40__Blogging_and_Wiki_pages__41__.mdwn new file mode 100644 index 000000000..8d6700651 --- /dev/null +++ b/doc/forum/Different_templates_for_subdirectories__63_____40__Blogging_and_Wiki_pages__41__.mdwn @@ -0,0 +1,7 @@ +I have been mucking about with ikiwiki for two whole days now. + +I like many things about it. Even though I've been spending most of my time wrestling with css I did manage to write a whole lot of blog posts and love what ikiwiki is doing for the "revise" part of my writing cycle. And I like the idea of integrating the wiki and the blog into one unifying architecture.... + +But... I would like very much to have different page templates for blogging and wiki-ing, some way of specifying that for stuff in the "/posts" directory I'd rather use blogpost.tmpl rather than page.tmpl. I just spent a few minutes looking at the perl for this (I assume Render.pm) and my mind dumped core... + +(generically, some way to specify output formatting on a subdirectory basis would be good) diff --git a/doc/forum/Different_templates_for_subdirectories__63_____40__Blogging_and_Wiki_pages__41__/comment_1_15651796492a6f04a19f4a481947c97c._comment b/doc/forum/Different_templates_for_subdirectories__63_____40__Blogging_and_Wiki_pages__41__/comment_1_15651796492a6f04a19f4a481947c97c._comment new file mode 100644 index 000000000..e92f4107d --- /dev/null +++ b/doc/forum/Different_templates_for_subdirectories__63_____40__Blogging_and_Wiki_pages__41__/comment_1_15651796492a6f04a19f4a481947c97c._comment @@ -0,0 +1,16 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawlY5yDefnXSHvWGbJ9kvhnAyQZiAAttENk" + nickname="Javier" + subject="comment 1" + date="2010-10-21T15:00:50Z" + content=""" +You can do what you want with the [[ikiwiki/directive/pagetemplate]] directive, but in a slightly cumbersome way, because you have to say what template you want in every page that differs from the default. + +See also: [[templates]] + +And, a perhaps more proper solution to your problem, although I don't fully understand the way of tackling it, in [[todo/multiple_template_directories]]. + +If you could create a proper page in this wiki, centralizing all the knowledge dispersed in those pages, it would be nice ;) + +--[[jerojasro]] +"""]] diff --git a/doc/forum/Disable_account_creation_for_new_users.mdwn b/doc/forum/Disable_account_creation_for_new_users.mdwn new file mode 100644 index 000000000..4a24323b3 --- /dev/null +++ b/doc/forum/Disable_account_creation_for_new_users.mdwn @@ -0,0 +1,9 @@ +Hi, +I'm planning on abusing ikiwiki as a mini-CMS for a static website and think it's exactly the right system for it. Great stuff btw. + +But I still got a problem that I can't solve at the moment. For the static website (with commenting enabled tho) I want no one else to edit the pages, i.e. I want to turn off the editing function for everyone except me. + +That works with the lockedit plugin so far, and I can also hide the edit and preferences links on the pages. But if someone manually enters the link to the edit page he/she can still create an account (I have disabled openid and plan to use passwordauth only). The account can then not be used to edit pages but still, everyone can create accounts in userdb over and over. Is there a way to solve that? I just don't see it right now. + +Best regards, +Chris diff --git a/doc/forum/Disable_account_creation_for_new_users/comment_1_adafddb0aff7c2c1f4574101c4cf9073._comment b/doc/forum/Disable_account_creation_for_new_users/comment_1_adafddb0aff7c2c1f4574101c4cf9073._comment new file mode 100644 index 000000000..116b2a592 --- /dev/null +++ b/doc/forum/Disable_account_creation_for_new_users/comment_1_adafddb0aff7c2c1f4574101c4cf9073._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawnam4a8RtFwaWkKOX2BkA5I7cpGHcFw8E0" + nickname="Christian" + subject="comment on my own question" + date="2011-11-30T15:15:21Z" + content=""" +REALLY great was what I wanted to say - all the essentials are there, including commenting and search function. What else can you want <3 +"""]] diff --git a/doc/forum/Disable_account_creation_for_new_users/comment_2_865591f77966f1657a9a4b2426318c51._comment b/doc/forum/Disable_account_creation_for_new_users/comment_2_865591f77966f1657a9a4b2426318c51._comment new file mode 100644 index 000000000..d04cfb6db --- /dev/null +++ b/doc/forum/Disable_account_creation_for_new_users/comment_2_865591f77966f1657a9a4b2426318c51._comment @@ -0,0 +1,12 @@ +[[!comment format=mdwn + username="http://smcv.pseudorandom.co.uk/" + nickname="smcv" + subject="comment 2" + date="2011-11-30T16:09:16Z" + content=""" +Not currently possible, but you can configure [[plugins/passwordauth]] to + require an `account_creation_password`, and not tell anyone else what +it is; or you could use [[plugins/httpauth]] for authenticated editing. +(My mostly-static ikiwiki sites only allow [[plugins/httpauth]] over +HTTPS.) +"""]] diff --git a/doc/forum/Disable_account_creation_for_new_users/comment_3_05193e563682f634f13691ee0a8359db._comment b/doc/forum/Disable_account_creation_for_new_users/comment_3_05193e563682f634f13691ee0a8359db._comment new file mode 100644 index 000000000..66b521407 --- /dev/null +++ b/doc/forum/Disable_account_creation_for_new_users/comment_3_05193e563682f634f13691ee0a8359db._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawnam4a8RtFwaWkKOX2BkA5I7cpGHcFw8E0" + nickname="Christian" + subject="thx" + date="2011-11-30T18:50:50Z" + content=""" +thank you for your quick reply, smcv! +"""]] diff --git a/doc/forum/Discussion_PageSpec__63__.mdwn b/doc/forum/Discussion_PageSpec__63__.mdwn new file mode 100644 index 000000000..2860d0d17 --- /dev/null +++ b/doc/forum/Discussion_PageSpec__63__.mdwn @@ -0,0 +1,3 @@ +I've looked around but haven't found it. Can you set a Discussion PageSpec so only certain pages allow discussion? + +> Not currently, sorry. --[[Joey]] diff --git a/doc/forum/Doing_related_links_based_on_tags.mdwn b/doc/forum/Doing_related_links_based_on_tags.mdwn new file mode 100644 index 000000000..9f6a1b937 --- /dev/null +++ b/doc/forum/Doing_related_links_based_on_tags.mdwn @@ -0,0 +1,31 @@ +I've been recently using a template this + + ---- + Related posts: + + \[[!inline pages="blog/posts/* + and !blog/posts/*/* + and !Discussion + and !tagged(draft) + and <TMPL_VAR raw_tagged>" + archive="yes" + quick="yes" + show="5"]] + +Which I then call by doing this at the end of my blog posts on my +ikiwiki install + + \[[!tag software linux]] + \[[!template id=related tagged="tagged(software) or tagged(linux)"]] + +It somewhat works, I was wondering if anyone else has tried to do +something like the above to get "related posts" based on tags. The way +that I have done it isn't very clever as it only links to the last 5 +most recently posted items based on my parameters. Is it possible to +"randomly" select a bunch of links from a set of user defined +pagespecs? + +I know that the [[backlinks]] plugin exists for this sort of stuff +(related links), it just lacks some user configuration options. + +> I guess what you need is an extension to [[ikiwiki/pagespec/sorting]] to support "random" as a sort method. Remember though, that the chosen few would only change when the page was regenerated, not on every page view. -- [[Jon]] diff --git a/doc/forum/Dot_CGI_pointing_to_localhost._What_happened__63__.mdwn b/doc/forum/Dot_CGI_pointing_to_localhost._What_happened__63__.mdwn new file mode 100644 index 000000000..930b9b9fc --- /dev/null +++ b/doc/forum/Dot_CGI_pointing_to_localhost._What_happened__63__.mdwn @@ -0,0 +1,13 @@ +# Dot CGI pointing to localhost. What happened? + +My ikiwiki broke. For some reason ikiwiki.cgi started pointing to +https://localhost:80/ instead of the real URL. Can somebody help me find out +why this has happened and perhaps fix it? Now login and recentchanges do not +work because of it. + +I believe the change happened after my hosting provider upgraded their server +OS from Debian oldstable to stable. Rebuilding the .cgi or the wiki hasn't +helped nor has helpdesk been helpful. Any hints as to debug this are +appreciated. + +Thanks! diff --git a/doc/forum/Dot_CGI_pointing_to_localhost._What_happened__63__/comment_1_cbab9b95923124b39cfccf5d2e88070c._comment b/doc/forum/Dot_CGI_pointing_to_localhost._What_happened__63__/comment_1_cbab9b95923124b39cfccf5d2e88070c._comment new file mode 100644 index 000000000..eb1007b0e --- /dev/null +++ b/doc/forum/Dot_CGI_pointing_to_localhost._What_happened__63__/comment_1_cbab9b95923124b39cfccf5d2e88070c._comment @@ -0,0 +1,14 @@ +[[!comment format=mdwn + username="http://smcv.pseudorandom.co.uk/" + nickname="smcv" + subject="comment 1" + date="2013-11-22T09:03:38Z" + content=""" +The CGI automatically builds self-referential URLs based on how you +accessed it, so if your web host puts it behind a +[reverse proxy](https://en.wikipedia.org/wiki/Reverse_proxy) or +something, that might make it try to redirect to localhost? + +If that's it, then `$q->url` with `$params{cgiurl}` in +`IkiWiki/CGI.pm` and `IkiWiki/Plugin/openid.pm` would work around it. +"""]] diff --git a/doc/forum/Dump_plugin.mdwn b/doc/forum/Dump_plugin.mdwn new file mode 100644 index 000000000..ff3bfea90 --- /dev/null +++ b/doc/forum/Dump_plugin.mdwn @@ -0,0 +1,4 @@ +I have a second plugin that adds a directive 'dump', and dumps all sorts of information (env variables and template variables) about a page into the end of the page. It's cheesy, but it's available in my [[Dropbox|http://dl.dropbox.com/u/11256359/dump.pm]] as well as the Asciidoc plugin. + +### Issues +* It really ought to use some kind of template instead of HTML. In fact, it ought to embed its information in template variables of some kind rather than stuffing it into the end of the page. diff --git a/doc/forum/Dump_plugin/comment_1_bfce80b3f5be78ec28692330843d4ae1._comment b/doc/forum/Dump_plugin/comment_1_bfce80b3f5be78ec28692330843d4ae1._comment new file mode 100644 index 000000000..855b72bbb --- /dev/null +++ b/doc/forum/Dump_plugin/comment_1_bfce80b3f5be78ec28692330843d4ae1._comment @@ -0,0 +1,14 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawngqGADV9fidHK5qabIzKN0bx1ZIfvaTqs" + nickname="Glenn" + subject="New dump plugin" + date="2010-10-03T00:45:47Z" + content=""" +I took my own advice and rewrote the dump plugin so that it uses a template. A sample template has been added to my [[Dropbox|http://dl.dropbox.com/u/11256359/dump.tmpl]]. + +### Issues: + +* Dumps appear at the end of the page rather than where the directive occurs. +* For some reason I haven't yet figured out, dumps don't appear in page previews. +* I haven't tested inlined content and the dump plugin. +"""]] diff --git a/doc/forum/Email_notifications_for_comment_moderation.mdwn b/doc/forum/Email_notifications_for_comment_moderation.mdwn new file mode 100644 index 000000000..6a840ce53 --- /dev/null +++ b/doc/forum/Email_notifications_for_comment_moderation.mdwn @@ -0,0 +1,3 @@ +I use both [[plugins/moderatedcomments/]] and [[plugins/anonok]] on my [blog](http://feeding.cloud.geek.nz) but having to remember to visit the comment moderation page manually is not ideal. + +Is there a way to get an email notification (or maybe even just an RSS feed) whenever a new comment enters the moderation queue? diff --git a/doc/forum/Email_notifications_for_comment_moderation/comment_1_668bf6a21310dcc8b882bc60a130ba06._comment b/doc/forum/Email_notifications_for_comment_moderation/comment_1_668bf6a21310dcc8b882bc60a130ba06._comment new file mode 100644 index 000000000..06140728e --- /dev/null +++ b/doc/forum/Email_notifications_for_comment_moderation/comment_1_668bf6a21310dcc8b882bc60a130ba06._comment @@ -0,0 +1,12 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawm6VdLM7IKcNgkDiJ2YKHpcWli9bRLsZDk" + nickname="Oscar" + subject="How to get a comment moderation feed" + date="2013-02-25T18:04:21Z" + content=""" +I was looking for the same subject and I have found the following: + +http://ikiwiki.info/tips/comments_feed/ + + +"""]] diff --git a/doc/forum/Empty_sha1sum_messages.mdwn b/doc/forum/Empty_sha1sum_messages.mdwn new file mode 100644 index 000000000..f464232c4 --- /dev/null +++ b/doc/forum/Empty_sha1sum_messages.mdwn @@ -0,0 +1,11 @@ +Hi, + +running ikiwiki from squeeze backports I see frequently in the logs: + +> Empty sha1sum for 'ikiwiki/pagespec.mdwn'. + +The page varies. What are these messages about? The code that emits this +comes from the git plugin, and this page is indeed not in git. So is +this just noise? Or rather, why does ikiwiki need to look at these? + +thanks in advance! diff --git a/doc/forum/Empty_sha1sum_messages/comment_1_b260b5e6b4c4f4c203b01183fee9fd69._comment b/doc/forum/Empty_sha1sum_messages/comment_1_b260b5e6b4c4f4c203b01183fee9fd69._comment new file mode 100644 index 000000000..7ad6f2815 --- /dev/null +++ b/doc/forum/Empty_sha1sum_messages/comment_1_b260b5e6b4c4f4c203b01183fee9fd69._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + nickname="joey" + subject="comment 1" + date="2012-03-22T17:06:05Z" + content=""" +Hmm, this is a debug message, so only printed or logged if verbose mode is enabled. As far as I can see, in normal operation this could only happen if you use the web interface to edit a page that's coming originally from ikiwiki's underlay -- such as `ikiwiki/pagespec.mdwn`, or a page in the srcdir whose file is indeed not checked into git for some reason. + +Doesn't seem useful, so I've nuked the message. +"""]] diff --git a/doc/forum/Empty_sha1sum_messages/comment_2_d6a47838a3c81d0a75e6fc22e786c976._comment b/doc/forum/Empty_sha1sum_messages/comment_2_d6a47838a3c81d0a75e6fc22e786c976._comment new file mode 100644 index 000000000..452fc946a --- /dev/null +++ b/doc/forum/Empty_sha1sum_messages/comment_2_d6a47838a3c81d0a75e6fc22e786c976._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="http://k1024.org/~iusty/" + nickname="Iustin Pop" + subject="Re: comment 1" + date="2012-03-22T19:34:55Z" + content=""" +Hmm, I see this 2-3 times a day on a internet exposed ikiwiki. There shouldn't be any editing of such files, especially not of files from the underlay - the only editing permissions are for blog comments. + +I'll have to check what's going on better, thanks for the reply! +"""]] diff --git a/doc/forum/Encoding_problem_in_french_with_ikiwiki-calendar.mdwn b/doc/forum/Encoding_problem_in_french_with_ikiwiki-calendar.mdwn new file mode 100644 index 000000000..472412de1 --- /dev/null +++ b/doc/forum/Encoding_problem_in_french_with_ikiwiki-calendar.mdwn @@ -0,0 +1,20 @@ +Hi! + +I'm using the ikiwiki calendar plugin. + +My website is in french (locale fr_FR.UTF-8), and calendars that are generated by the plugin makes some encodi$ + +I don't know how the plugin generate translation for dates, but I've seen that there is no ikiwiki translation$ + +That's why I suppose (but I'm not sure) that it use date unix command to insert date into the html page, witho$ + +Could I have forgotten some options to make it nice or not? + +Is someone could test it and verify if it works or not? + +Thanks. + +Zut + +> This was discussed in [[bugs/Encoding_problem_in_calendar_plugin]] +> and is now fixed. --[[Joey]] diff --git a/doc/forum/Error:_CGI::tmpFileName_failed_to_return_the_uploaded_file_name.mdwn b/doc/forum/Error:_CGI::tmpFileName_failed_to_return_the_uploaded_file_name.mdwn new file mode 100644 index 000000000..ad52c0091 --- /dev/null +++ b/doc/forum/Error:_CGI::tmpFileName_failed_to_return_the_uploaded_file_name.mdwn @@ -0,0 +1,11 @@ +I tried to upload a file to my wiki last week, and got this error: + + Error: CGI::tmpFileName failed to return the uploaded file name + +This used to work, and I honestly don't know what could have changed to screw it up. + +I see that there's a lot of frustrated comments around this particular block of code in `attachment.pm`; so, for the record, I'm on Debian 6, using perl `5.10.1-17squeeze4`. + +Any thoughts? + +~jonathon diff --git a/doc/forum/Error:_CGI::tmpFileName_failed_to_return_the_uploaded_file_name/comment_1_66c321b9eb618d20872cee7d6ca9e44c._comment b/doc/forum/Error:_CGI::tmpFileName_failed_to_return_the_uploaded_file_name/comment_1_66c321b9eb618d20872cee7d6ca9e44c._comment new file mode 100644 index 000000000..fb499004e --- /dev/null +++ b/doc/forum/Error:_CGI::tmpFileName_failed_to_return_the_uploaded_file_name/comment_1_66c321b9eb618d20872cee7d6ca9e44c._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawlRjjrKEyPmXnh2qBEGx9PgH5DP32wCMAQ" + nickname="Jonathon" + subject="ikiwiki version" + date="2013-01-02T14:59:19Z" + content=""" +I should also identify that I'm using ikiwiki `3.20100815.9`. +"""]] diff --git a/doc/forum/Error:_CGI::tmpFileName_failed_to_return_the_uploaded_file_name/comment_2_80296d67c7f1dd75b56b85c14f5efa3b._comment b/doc/forum/Error:_CGI::tmpFileName_failed_to_return_the_uploaded_file_name/comment_2_80296d67c7f1dd75b56b85c14f5efa3b._comment new file mode 100644 index 000000000..e7659413e --- /dev/null +++ b/doc/forum/Error:_CGI::tmpFileName_failed_to_return_the_uploaded_file_name/comment_2_80296d67c7f1dd75b56b85c14f5efa3b._comment @@ -0,0 +1,12 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawlRjjrKEyPmXnh2qBEGx9PgH5DP32wCMAQ" + nickname="Jonathon" + subject="figured it out" + date="2013-01-19T15:59:09Z" + content=""" +It looks like this was just another expression of [the header size limit issue] [1] that has already been reported and addressed. + +I got `3.20120629` from `squeeze-backports`, and my issue has been resolved. + +[1]: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=638009 +"""]] diff --git a/doc/forum/Error:___34__do__34___parameter_missing.mdwn b/doc/forum/Error:___34__do__34___parameter_missing.mdwn new file mode 100644 index 000000000..402217e82 --- /dev/null +++ b/doc/forum/Error:___34__do__34___parameter_missing.mdwn @@ -0,0 +1,13 @@ +Hi + +I'm stuck with a «Error: "do" parameter missing» message I can't fix. + +I'm using ikiwiki 3.20100815.7 on a debian 6.0.4 system. + +Error redirection is obvisously configured, also the dot cgi thing. + +You can test it at http://wikimix.cc/thisuridoesntexist + +The procedure of creating a reference to a new page gives the same error. + +Any clue? diff --git a/doc/forum/Error:___34__do__34___parameter_missing/comment_1_3a51c303ba1670f1567f323349b53837._comment b/doc/forum/Error:___34__do__34___parameter_missing/comment_1_3a51c303ba1670f1567f323349b53837._comment new file mode 100644 index 000000000..a01a33468 --- /dev/null +++ b/doc/forum/Error:___34__do__34___parameter_missing/comment_1_3a51c303ba1670f1567f323349b53837._comment @@ -0,0 +1,16 @@ +[[!comment format=mdwn + username="http://smcv.pseudorandom.co.uk/" + nickname="smcv" + subject="comment 1" + date="2012-05-22T13:46:20Z" + content=""" +Did you enable the [[plugins/404]] plugin? + +Which web server? That plugin is meant to work with Apache 2; in +principle it should be possible to make it work with other web servers, +but it'll need some setup. + +The 404 plugin relies on your web server giving IkiWiki some extra +information about 404s; lighttpd doesn't currently provide enough +information for IkiWiki to detect 404s reliably, for instance. +"""]] diff --git a/doc/forum/Error:___34__do__34___parameter_missing/comment_2_c5f24a8c4d2de0267cf0de1908480e82._comment b/doc/forum/Error:___34__do__34___parameter_missing/comment_2_c5f24a8c4d2de0267cf0de1908480e82._comment new file mode 100644 index 000000000..dd2fdb248 --- /dev/null +++ b/doc/forum/Error:___34__do__34___parameter_missing/comment_2_c5f24a8c4d2de0267cf0de1908480e82._comment @@ -0,0 +1,12 @@ +[[!comment format=mdwn + username="http://ismael.olea.org/" + ip="150.214.94.198" + subject="comment 2" + date="2012-05-22T21:24:37Z" + content=""" +Gosh, that was it. + +Grrr. Sorry for being too rookie O:-) + +Thanks! +"""]] diff --git a/doc/forum/Error:_bad_page_name.mdwn b/doc/forum/Error:_bad_page_name.mdwn new file mode 100644 index 000000000..70277a1e4 --- /dev/null +++ b/doc/forum/Error:_bad_page_name.mdwn @@ -0,0 +1,46 @@ +I'm trying to use ikiwiki for the first time. In the start, I had problems +with installing the package, because I don't have a root account on my +server. + +When I solved this, I finally set up my wiki, but whenever I try to edit a +page, I get an error: “Error: bad page name”. + +What am I doing wrong? The wiki is at +<http://atrey.karlin.mff.cuni.cz/~onderka/wiki/>, the setupfile I used at +<http://atrey.karlin.mff.cuni.cz/~onderka/wiki/ikiwiki.setup>. + +> This means that one of the checks that ikiwiki uses to prevent +> editing files with strange or insecure names has fired incorrectly. +> Your setup file seems fine. +> We can figure out what is going wrong through a series of tests: +> +> * Test if your perl has a problem with matching alphanumerics: +> `perl -le 'print int "index"=~/^([-[:alnum:]+\/.:_]+)$/'` +> * Check if something is breaking pruning of disallowed files: +> `perl -le 'use IkiWiki; %config=IkiWiki::defaultconfig(); print ! IkiWiki::file_pruned("index")'` +> --[[Joey]] + +>>Both seem to run fine: + + onderka@atrey:~$ perl -le 'print int "index"=~/^([-[:alnum:]+\/.:_]+)$/' + 1 + onderka@atrey:~$ perl -le 'use IkiWiki; %config=IkiWiki::defaultconfig(); print ! IkiWiki::file_pruned("index")' + 1 + +>>> Try installing this [instrumented +>>> version](http://kitenet.net/~joey/tmp/editpage.pm) of +>>> `IkiWiki/Plugin/editpage.pm`, which will add some debugging info +>>> to the error message. --[[Joey]] + +>>>>When I tried to `make` ikiwiki with this file, I got the error + + ../IkiWiki/Plugin/editpage.pm:101: invalid variable interpolation at "$" + +>>>>> Sorry about that, I've corrected the above file. --[[Joey]] + +>>>>>> Hmm, funny. Now that I reinstalled it with your changed file, it started working. I didn't remember how exactly did I install it the last time, so this time, it seems I did it correctly. Thank you very much for your help. + +>>>>>>> Well, this makes me suspect you installed an older version of +>>>>>>> ikiwiki and my file, which is from the latest version, included a +>>>>>>> fix for whatever bug you were seeing. If I were you, I'd ensure +>>>>>>> that I have a current version of ikiwiki installed. --[[Joey]] diff --git a/doc/forum/Error:_cannot_write_to___47__home__47__user__47__myiki2__47__.ikiwiki__47__lockfile:_Permission_denied_.mdwn b/doc/forum/Error:_cannot_write_to___47__home__47__user__47__myiki2__47__.ikiwiki__47__lockfile:_Permission_denied_.mdwn new file mode 100644 index 000000000..c6af80ab1 --- /dev/null +++ b/doc/forum/Error:_cannot_write_to___47__home__47__user__47__myiki2__47__.ikiwiki__47__lockfile:_Permission_denied_.mdwn @@ -0,0 +1,5 @@ +I installed a new wiki on my local machine. When I click on edit, I get the following error: + +`Error: cannot write to /home/user/myiki2/.ikiwiki/lockfile: Permission denied` + +I checked the permissions of that file and assured that they are the same as in my other working ikiwiki, but it doesn't help. Any idea? diff --git a/doc/forum/Error:_cannot_write_to___47__home__47__user__47__myiki2__47__.ikiwiki__47__lockfile:_Permission_denied_/comment_1_64146f306ec8c10614521359b6de4f82._comment b/doc/forum/Error:_cannot_write_to___47__home__47__user__47__myiki2__47__.ikiwiki__47__lockfile:_Permission_denied_/comment_1_64146f306ec8c10614521359b6de4f82._comment new file mode 100644 index 000000000..02f70860d --- /dev/null +++ b/doc/forum/Error:_cannot_write_to___47__home__47__user__47__myiki2__47__.ikiwiki__47__lockfile:_Permission_denied_/comment_1_64146f306ec8c10614521359b6de4f82._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="https://launchpad.net/~tale" + nickname="tale" + subject="What are the permissions?" + date="2011-12-28T19:35:25Z" + content=""" +What exactly are the permissions for the lockfile and the directory it is in? + +What user is the ikiwiki running as? +"""]] diff --git a/doc/forum/Error:_cannot_write_to___47__home__47__user__47__myiki2__47__.ikiwiki__47__lockfile:_Permission_denied_/comment_2_ed2b4b8f7122b42bbde1189fbd2969dd._comment b/doc/forum/Error:_cannot_write_to___47__home__47__user__47__myiki2__47__.ikiwiki__47__lockfile:_Permission_denied_/comment_2_ed2b4b8f7122b42bbde1189fbd2969dd._comment new file mode 100644 index 000000000..cc1a30adb --- /dev/null +++ b/doc/forum/Error:_cannot_write_to___47__home__47__user__47__myiki2__47__.ikiwiki__47__lockfile:_Permission_denied_/comment_2_ed2b4b8f7122b42bbde1189fbd2969dd._comment @@ -0,0 +1,23 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawk_MMtLPS7osC5MjX00q2ATjvvXPWqm0ik" + nickname="micheal" + subject="comment 2" + date="2011-12-28T23:06:06Z" + content=""" +<code> +stat -c '%A %a %U %G %n' myiki2 myiki1 +drwxr-xr-x 755 user user myiki2 +drwxr-xr-x 755 user user myiki1 + +stat -c '%A %a %U %G %n' myiki2/.ikiwiki myiki1/.ikiwiki +drwxr-xr-x 755 user user myiki2/.ikiwiki +drwxr-xr-x 755 user user myiki1/.ikiwiki + +stat -c '%A %a %U %G %n' myiki2/.ikiwiki/lockfile myiki1/.ikiwiki/lockfile +-rw-r--r-- 644 user user myiki2/.ikiwiki/lockfile +-rw-r--r-- 644 user user myiki1/.ikiwiki/lockfile +</code> + +As you see, myiki2 has the same permissions as myiki1, but myiki1 works. + +"""]] diff --git a/doc/forum/Error_Code_1.mdwn b/doc/forum/Error_Code_1.mdwn new file mode 100644 index 000000000..3e6878bb7 --- /dev/null +++ b/doc/forum/Error_Code_1.mdwn @@ -0,0 +1,7 @@ +Hi. I'm new to ikiwiki. I typed + +"make install" + +and got "Error Code 1". + +Any help is appreciated. diff --git a/doc/forum/Error_Code_1/comment_1_0459afcc383aad382df67a19eaf2e731._comment b/doc/forum/Error_Code_1/comment_1_0459afcc383aad382df67a19eaf2e731._comment new file mode 100644 index 000000000..f4bb410eb --- /dev/null +++ b/doc/forum/Error_Code_1/comment_1_0459afcc383aad382df67a19eaf2e731._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + nickname="joey" + subject="comment 1" + date="2011-02-25T18:57:22Z" + content=""" +Read the README file. Ikiwiki's source does not include a Makefile; you have to run ./Makefile.PL to create one. +"""]] diff --git a/doc/forum/Error___34__is_locked_and_cannot_be_edited__34__.mdwn b/doc/forum/Error___34__is_locked_and_cannot_be_edited__34__.mdwn new file mode 100644 index 000000000..44d25af70 --- /dev/null +++ b/doc/forum/Error___34__is_locked_and_cannot_be_edited__34__.mdwn @@ -0,0 +1,15 @@ +I returned to one of my old ikiwiki blogs and received the above error message after entering (on the web interface of the blog) a title for a new post. + +I found the following three locks in the .ikiwiki directory of the blog: + +-rw-r--r-- 1 zoidberg zoidberg 0 May 23 15:10 cgilock +-rw-r--r-- 1 zoidberg zoidberg 0 May 23 15:20 lockfile +-rw------- 1 zoidberg zoidberg 0 May 23 15:10 sessions.db.lck + +When I delete these and and again try to create a new post the above error message reappears and the locks have been recreated. + +Re-running 'ikiwiki --setup myblog.setup' disclosed a couple of permission problems (files owned by root - bah), but fixing them has had no effect on hte behavior of the blog. + +I really would like to rehab this ikiwiki blog! + +*Thanks!* diff --git a/doc/forum/Error___34__is_locked_and_cannot_be_edited__34__/comment_1_dc99a921813d4f8adf797a900ee0a2c1._comment b/doc/forum/Error___34__is_locked_and_cannot_be_edited__34__/comment_1_dc99a921813d4f8adf797a900ee0a2c1._comment new file mode 100644 index 000000000..7aed7a21e --- /dev/null +++ b/doc/forum/Error___34__is_locked_and_cannot_be_edited__34__/comment_1_dc99a921813d4f8adf797a900ee0a2c1._comment @@ -0,0 +1,18 @@ +[[!comment format=mdwn + username="http://smcv.pseudorandom.co.uk/" + nickname="smcv" + subject="comment 1" + date="2014-05-23T22:02:07Z" + content=""" +I believe that error message indicates that the [[plugins/lockedit]] +plugin is preventing editing. Either make the user account you're +trying to use into a wiki admin via the `adminuser` setting: + + # either or both of these + adminuser: + - yourname + - http://your-openid.example.com/ + +or allow that user to edit pages by altering the `locked_pages` +setting. +"""]] diff --git a/doc/forum/Error___34__is_locked_and_cannot_be_edited__34__/comment_2_48daf77f097ed94bf78cf97b0c027129._comment b/doc/forum/Error___34__is_locked_and_cannot_be_edited__34__/comment_2_48daf77f097ed94bf78cf97b0c027129._comment new file mode 100644 index 000000000..f94e7785e --- /dev/null +++ b/doc/forum/Error___34__is_locked_and_cannot_be_edited__34__/comment_2_48daf77f097ed94bf78cf97b0c027129._comment @@ -0,0 +1,14 @@ +[[!comment format=mdwn + username="http://bob-bernstein.myopenid.com/" + nickname="bernstein" + subject="comment 2" + date="2014-05-24T02:04:07Z" + content=""" +Thanks. Your prompt reply encouraged me to poke around a bit more. I found a perl module was missing (how I cannot imagine) XML/Writer.pm. Installing the relevant deb seemed to fix things up. + +nb This is a rather old install of ikiwiki. It dates from 2009. + +ps Your use of ikiwiki for your homepage is quite impressive, and tasteful! + +*Thanks!* +"""]] diff --git a/doc/forum/Everyone_can_remove_comments.mdwn b/doc/forum/Everyone_can_remove_comments.mdwn new file mode 100644 index 000000000..5e30b08ed --- /dev/null +++ b/doc/forum/Everyone_can_remove_comments.mdwn @@ -0,0 +1 @@ +Having enabled anonok and leads to the undesirable situation, that everybody is able to remove every comment. Is there an easy workaround, or am I missing something? --[[wiebel]] diff --git a/doc/forum/Export_images_when_building_the_wiki.mdwn b/doc/forum/Export_images_when_building_the_wiki.mdwn new file mode 100644 index 000000000..9802ea4ed --- /dev/null +++ b/doc/forum/Export_images_when_building_the_wiki.mdwn @@ -0,0 +1,16 @@ +My repository contains image sources made with tools like Inkspace, Dia, LibreOffice, Gimp and so on. + +Instead of pushing the images themselves into git or manually exporting them to PNG/SVG, +I'd like to keep just the sources in git, and have ikiwiki compile them into the final +images just like it compiles Markdown into HTML. Is it possible to add new files types +and tell ikiwiki how to compile them? + +(After reading some plugin docs...) + +I just read 'perlintro' yesterday in unrelated context, but... +could it maybe be done by writing a plugin like this one, +which compiles textile? + +<http://source.ikiwiki.branchable.com/?p=source.git;a=blob;f=IkiWiki/Plugin/textile.pm;h=56bb4bffce83bf9fa47b1ad731f46c8dc8d9f652;hb=HEAD> + +-- [[fr33domlover]] diff --git a/doc/forum/Export_images_when_building_the_wiki/comment_1_f7328be9b201f3eea6b90c269781fd0b._comment b/doc/forum/Export_images_when_building_the_wiki/comment_1_f7328be9b201f3eea6b90c269781fd0b._comment new file mode 100644 index 000000000..182be88f3 --- /dev/null +++ b/doc/forum/Export_images_when_building_the_wiki/comment_1_f7328be9b201f3eea6b90c269781fd0b._comment @@ -0,0 +1,18 @@ +[[!comment format=mdwn + username="spalax" + ip="82.216.247.172" + subject="Other plugins to study" + date="2014-05-16T10:38:17Z" + content=""" +Several plugins process data using external programs. You may have a look at: + +- [[plugins/teximg]] which calls LaTeX; +- [[plugins/graphviz]] which calls graphviz; +- [[plugins/contrib/pandoc]] which calls pandoc. + +The first and second plugins I mentionned create an image using an external +tool, and integrate it in the page. It may be exactly what you want. + +-- [[Louis|spalax]] + +"""]] diff --git a/doc/forum/Export_images_when_building_the_wiki/comment_2_99a592c8ff9d2c2094132edd27356922._comment b/doc/forum/Export_images_when_building_the_wiki/comment_2_99a592c8ff9d2c2094132edd27356922._comment new file mode 100644 index 000000000..0c270987e --- /dev/null +++ b/doc/forum/Export_images_when_building_the_wiki/comment_2_99a592c8ff9d2c2094132edd27356922._comment @@ -0,0 +1,18 @@ +[[!comment format=mdwn + username="fr33domlover" + ip="85.65.55.38" + subject="comment 2" + date="2014-05-17T11:10:35Z" + content=""" +Thanks, I already saw those. + +I need a plugin of exactly the same kind, but which calls other tools, such as Dia and Inkspace. +In addition, embedding into a page means the same image may end up being generated +many times. So it's best to generate the image as an attachment of some page, and then +all other pages in the wiki can use it. What do you think? + +Also, if I write a plugin (and test it of course), where do I publish it so people can +see and enjoy it? Is [[plugins]] moderated? + +-- [[fr33domlover]] +"""]] diff --git a/doc/forum/Export_images_when_building_the_wiki/comment_3_7f5a1ef639453c83748405d2b3b0b880._comment b/doc/forum/Export_images_when_building_the_wiki/comment_3_7f5a1ef639453c83748405d2b3b0b880._comment new file mode 100644 index 000000000..48aec10ec --- /dev/null +++ b/doc/forum/Export_images_when_building_the_wiki/comment_3_7f5a1ef639453c83748405d2b3b0b880._comment @@ -0,0 +1,27 @@ +[[!comment format=mdwn + username="spalax" + ip="82.216.247.172" + subject="comment 3" + date="2014-05-17T13:49:14Z" + content=""" +> I need a plugin of exactly the same kind, but which calls other tools, such as Dia and Inkspace. +> In addition, embedding into a page means the same image may end up being generated +> many times. So it's best to generate the image as an attachment of some page, and then +> all other pages in the wiki can use it. What do you think? + +Then the [[plugins/contrib/pandoc]] may be a good start, since *you can configure it for Pandoc to take over processing of all .mkdn files, or only files with a different extension.* Have a look at it to make your plugin process files with a particular extension. Then, it will be possible to have several pages refer to the same file, generated only once (maybe by storing stuff in `%pagestate` or `%wikistate`. + +Have a look at [[plugins/write]] to write your plugin. + +> Also, if I write a plugin (and test it of course), where do I publish it so people can +> see and enjoy it? Is [[plugins]] moderated? + +What is usually done is: + +- you publish your code somewhere (your server, or on github or something like that); +- you advertise your plugin by creating a subpage of [[plugins/contrib]]. Use the [[templates/plugin]] [[template|templates]] (it generates the frame you can see on the right of [[one of my plugins|plugins/contrib/jscalendar]], for example): + + \[[!template id=plugin name=YourFancyPlugin author=\"[[fr33domlover]]\"]] + +-- [[Louis|spalax]] +"""]] diff --git a/doc/forum/Export_images_when_building_the_wiki/comment_4_bd3b37fbee54f1bf510ef5fc6ba27e55._comment b/doc/forum/Export_images_when_building_the_wiki/comment_4_bd3b37fbee54f1bf510ef5fc6ba27e55._comment new file mode 100644 index 000000000..5f5647a57 --- /dev/null +++ b/doc/forum/Export_images_when_building_the_wiki/comment_4_bd3b37fbee54f1bf510ef5fc6ba27e55._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="fr33domlover" + ip="85.65.55.38" + subject="comment 4" + date="2014-05-17T14:46:15Z" + content=""" +Great, thanks. I'll take a look. But it's a bit different, because images are not HTML pages at all. + +Thanks for the quick replies :-) +"""]] diff --git a/doc/forum/File_wiki.setup.mdwn b/doc/forum/File_wiki.setup.mdwn new file mode 100644 index 000000000..173988fd5 --- /dev/null +++ b/doc/forum/File_wiki.setup.mdwn @@ -0,0 +1,6 @@ +Hi, + +I'd like to know if there were a way to get the user's directory path where the file wiki.setup is, and the name of this file. Because i'm working on an improvement of the plugin userlist, and i want to modify the .setup file but i haven't found a way to dynamically get this file. + +> The [[plugins/websetup]] plugin rewrites the setup file. You may find your +> answer in its code. [[Louis|spalax]] diff --git a/doc/forum/Flowplayer.mdwn b/doc/forum/Flowplayer.mdwn new file mode 100644 index 000000000..9bf3ab3af --- /dev/null +++ b/doc/forum/Flowplayer.mdwn @@ -0,0 +1 @@ +[Flowplayer](http://flowplayer.org) is the open source flash video player plugin. [My site](http://mcfrisk.kapsi.fi) has raw html enabled to work with old content so I was able to use the raw html and javascript [examples](http://flowplayer.org/documentation/installation/index.html) in blog posts, but some of them fail when combined on the [aggregate page](http://mcfrisk.kapsi.fi/skiing/). Any hints on how to properly use Flowplayer with ikiwiki? diff --git a/doc/forum/Flowplayer/comment_1_75d13cd915a736422db47e00dbe46671._comment b/doc/forum/Flowplayer/comment_1_75d13cd915a736422db47e00dbe46671._comment new file mode 100644 index 000000000..159e9dce1 --- /dev/null +++ b/doc/forum/Flowplayer/comment_1_75d13cd915a736422db47e00dbe46671._comment @@ -0,0 +1,9 @@ +[[!comment format=mdwn + username="Sphynkx" + ip="85.238.106.185" + subject="Videoplugin" + date="2011-06-27T02:27:19Z" + content=""" +Hello!! +Test my [videoplugin](http://ikiwiki.info/plugins/contrib/video/)!! +"""]] diff --git a/doc/forum/Flowplayer/comment_2_1b2d3891006a87a4773bd126baacddfc._comment b/doc/forum/Flowplayer/comment_2_1b2d3891006a87a4773bd126baacddfc._comment new file mode 100644 index 000000000..597638397 --- /dev/null +++ b/doc/forum/Flowplayer/comment_2_1b2d3891006a87a4773bd126baacddfc._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://mcfrisk.myopenid.com/" + nickname="mikko.rapeli" + subject="Bad html" + date="2011-07-02T19:09:22Z" + content=""" +My problems on the aggregate pages were resolved by checking and fixing html validation problems with the embedded video stuff. I will have look at the video plugin later, and maybe html5 and `<video>` tag as well. +"""]] diff --git a/doc/forum/Force_rebuild_of_page_using_some_plugin.mdwn b/doc/forum/Force_rebuild_of_page_using_some_plugin.mdwn new file mode 100644 index 000000000..3880a89e6 --- /dev/null +++ b/doc/forum/Force_rebuild_of_page_using_some_plugin.mdwn @@ -0,0 +1,5 @@ +I'm writing a plugin and I'd like to force all the pages that include a directive which my plugin defines to be rebuilt when the wiki is refreshed (whether or not those pages have changed). + +I've found the "needsbuild" hook which I could use to get pages to be rebuilt. But how can I work out which pages include my directive? And will needsbuild get called for every occurrence of my directive? I only need to rebuild those pages once (obviously). When the needsbuild hook gets called, is it because the directive match its 'id' hook() parameter has been encountered? And does needsbuild know what page is being processed? + +Or is there some other way of doing this? diff --git a/doc/forum/Formatting_algorithms.mdwn b/doc/forum/Formatting_algorithms.mdwn new file mode 100644 index 000000000..c7f4aaa76 --- /dev/null +++ b/doc/forum/Formatting_algorithms.mdwn @@ -0,0 +1,54 @@ +I'm using ikiwiki for a software project, and in the design process one of the things I sometimes write +algorithms. It doesn't happen much, but for components of functional nature it's very useful. + +I've been thinking how to write them in the wiki. I can use a numbered list and manually make +keywords __bold__, but it's not optimal. I could also use plain text formatting and indent using tabs, +but again there is no highlighting of any keywords or formatting of structures. +Before I do that, I'd like to know if there are better options. + +One option I know is LaTeX, which has some very nice packages. You write pseudo-code which looks +very much like source code, and the result looks great, very readable and high quality. + +I saw the [[plugins/teximg]] plugin, but the explanation there is poor: Does the plugin handle things +that aren't formulas? Could it work with a LaTeX document or with an algorithm environment? + +Of course, of you have other suggestions I'll be happy to hear. I want to make a careful choice before +I start writing many algorithms :-) + +> You may try to see if you can select a pseudo-code languages in one of the +> highlight plugins ([[plugins/contrib/highlightcode]], +> [[plugins/contrib/sourcehighlight]], [[plugins/highlight]], other ?). The +> list of supported languages with the [[plugins/highlight]] plugin is +> [[here|http://www.andre-simon.de/doku/highlight/en/langs.php]], and if you +> cannot find your languages, I think you can define your own +> [[here|http://www.andre-simon.de/doku/highlight/en/plugins.php]]. +> +> -- [[Louis|spalax]] + +>> Thanks, I looked at it. I don't think there's any special language for algorithms +>> (anyway I couldn't find any), but for the record I found the following possibilities: +>> +>> 1. LaTeX: Not very readable in source form, but could be highlighted, didn't try +>> 2. Writing in a subset of Python/Pascal/Fortran and using their highlighting +>> 3. Define a new highlight syntax +>> +>> What about [[plugins/teximg]]? If it can be used to generate algorithms from LaTeX, it would be +>> an easy excellent solution. +>> +>> --[[fr33domlover]] + +> [[plugins/teximg]] is the best thing that currently exists. Since it isn't +> enabled on this wiki, and the author's ikiwiki has disappeared, I put one of +> the test formulas into a private test wiki of mine. Here's a screenshot: +> <http://imgur.com/nT6mefx> +> +> I think it would be great if someone [[wrote a +> plugin for something nicer|todo/Add_nicer_math_formatting]]. -- [[Jon]] + +>> [[plugins/teximg]] is fine for math (al least for GUI browsers, I didn't try with w3m etc.), +>> but what I'm looking for is a solution for formatting **algorithms**. If teximg can help +>> with that, great, otherwise there's the 3 workarounds I mentioned above. +>> +>> Do you have any ideas not mentioned? :-) +>> +>> -- [[fr33domlover]] diff --git a/doc/forum/Forward_slashes_being_escaped_as_252F.mdwn b/doc/forum/Forward_slashes_being_escaped_as_252F.mdwn new file mode 100644 index 000000000..5df81e561 --- /dev/null +++ b/doc/forum/Forward_slashes_being_escaped_as_252F.mdwn @@ -0,0 +1,33 @@ +When I try to edit a page that has a forward slash in the URL, I get "Error: +bad page name". I think the problem is because the forward slash is escaped as +`%252F` instead of `%2F`. + +For example, if I go to `http://ciffer.net/~svend/tech/hosts/` and click Edit, +I am sent to a page with the URL +`http://ciffer.net/~svend/ikiwiki.cgi?page=tech%252Fhosts&do=edit`. + +I am running ikiwiki 3.20100504~bpo50+1 on Debian Lenny. + + +> But on your page, the Edit link is escaped normally and correctly (using %2F). +> Look at the page source! +> +> The problem is that your web server is forcing a hard (302) redirect +> to the doubly-escaped url. In wireshark I see your web server send back: + + HTTP/1.1 302 Found\r\n + Apache/2.2.9 (Debian) PHP/5.2.6-1+lenny9 with Suhosin-Patch + Location: http://ciffer.net/~svend/ikiwiki.cgi?page=tech%252Fhosts&do=edit + +> You'll need to investigate why your web server is doing that... --[[Joey]] + +>> Thanks for pointing me in the right direction. I have the following redirect +>> in my Apache config. + + RewriteEngine on + RewriteCond %{HTTP_HOST} ^www\.ciffer\.net$ + RewriteRule /(.*) http://ciffer.net/$1 [L,R] + +>> and my ikiwiki url setting contained `www.ciffer.net`, which was causing the +>> redirect. Correcting the url fixed the problem. I'm still not sure why +>> Apache was mangling the URL. --[[Svend]] diff --git a/doc/forum/Forward_slashes_being_escaped_as_252F/comment_1_7702cf6d354ab600d6643b075b9f09da._comment b/doc/forum/Forward_slashes_being_escaped_as_252F/comment_1_7702cf6d354ab600d6643b075b9f09da._comment new file mode 100644 index 000000000..7c9ccbca1 --- /dev/null +++ b/doc/forum/Forward_slashes_being_escaped_as_252F/comment_1_7702cf6d354ab600d6643b075b9f09da._comment @@ -0,0 +1,12 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawm6gCEo_Z36OJ7x5kyZn52lEVvyjn3zSUc" + nickname="Ángel" + subject="comment 1" + date="2013-05-31T16:03:03Z" + content=""" +Simply add the NE (No escape) flag: + +RewriteEngine on +RewriteCond %{HTTP_HOST} ^www\.ciffer\.net$ +RewriteRule /(.*) http://ciffer.net/$1 [L,R,NE] +"""]] diff --git a/doc/forum/Google_searches_of_ikiwiki.info_are_broken._:__40__.mdwn b/doc/forum/Google_searches_of_ikiwiki.info_are_broken._:__40__.mdwn new file mode 100644 index 000000000..3716a1475 --- /dev/null +++ b/doc/forum/Google_searches_of_ikiwiki.info_are_broken._:__40__.mdwn @@ -0,0 +1,14 @@ +I know that these pages exist on ikiwiki.info: + +* http://ikiwiki.info/ikiwiki/formatting/ +* http://ikiwiki.info/ikiwiki/subpage/ + +But I can't get either to show up in Google search results. I have even tried: +> site:ikiwiki.info inurl:formatting + +and + +> site:ikiwiki.info inurl:formatting -inurl:discussion + +...Is this some robots.txt problem? + diff --git a/doc/forum/Have_creation_time_for_new_pages_fetched_from_the_VCS.mdwn b/doc/forum/Have_creation_time_for_new_pages_fetched_from_the_VCS.mdwn new file mode 100644 index 000000000..1ce63dbcf --- /dev/null +++ b/doc/forum/Have_creation_time_for_new_pages_fetched_from_the_VCS.mdwn @@ -0,0 +1,7 @@ +I use ikiwiki for my blog, and I'd like the creation page of each page to be the one registered in the VCS. However, the only way to get that is really with the --gettime flag, which gets ALL the timestamps from the VCS... which take quite some time after a few years of writing ;-) + +So I'd like to suggest that ikiwiki could fetch ctime through rcs_getctime() by default when it finds a new page... + +mtime is a different matter, not so important to me... + +-- [Richard Levitte](http://journal.richard.levitte.org/) diff --git a/doc/forum/Have_creation_time_for_new_pages_fetched_from_the_VCS/comment_1_9572dd6f7a2f6f630b12f24bb5c4a8ce._comment b/doc/forum/Have_creation_time_for_new_pages_fetched_from_the_VCS/comment_1_9572dd6f7a2f6f630b12f24bb5c4a8ce._comment new file mode 100644 index 000000000..d9e974c8a --- /dev/null +++ b/doc/forum/Have_creation_time_for_new_pages_fetched_from_the_VCS/comment_1_9572dd6f7a2f6f630b12f24bb5c4a8ce._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + nickname="joey" + subject="comment 1" + date="2011-07-19T15:50:41Z" + content=""" +This is not done for reasons of speed. `rcs_getctime` is for many VCSs still slow, requiring a new svn or whatever to be forked off (and in the case of svn, possibly make a network connection). In the case where a commit comes in that adds multiple pages, that would be a lot of work. And for the VCSs where it's not slow, it manages to not be slow by optimising for the case where *all* the times for all pages are looked up in one go .. which is still rather a lot to do when only a single new page has been added. So we lose either way, and it's not suitable for being run all the time, unfortunately. +"""]] diff --git a/doc/forum/Help_with_tag__95__autocreate.mdwn b/doc/forum/Help_with_tag__95__autocreate.mdwn new file mode 100644 index 000000000..f470c57cf --- /dev/null +++ b/doc/forum/Help_with_tag__95__autocreate.mdwn @@ -0,0 +1,9 @@ +I have the tag plugin enabled, and these additional lines in my setup file: + + tagbase => "tags", + tag_autocreate => 1, + tag_autocreate_commit => 1, + +However, when I use a !tag or !taglink directive, nothing gets autocreated in the tags/ directory. What am I doing wrong? + +Edit: I'm using ikiwiki version 3.20100122ubuntu1 on Ubuntu 10.04.3 LTS... upgraded to ikiwiki_3.20110905_all from the debian repository and that solved my problem. Oops. :) diff --git a/doc/forum/Hide_text.mdwn b/doc/forum/Hide_text.mdwn new file mode 100644 index 000000000..cb4568342 --- /dev/null +++ b/doc/forum/Hide_text.mdwn @@ -0,0 +1,3 @@ +I want to make a kind of puzzle page with ikiwiki. For that I want to have the solution text hidden directly below the puzzle which appears if I click a button. + +Is it possible to do this in ikiwiki? diff --git a/doc/forum/Hide_text/comment_1_f21d21c130f97a7b21d8a317178e2e0c._comment b/doc/forum/Hide_text/comment_1_f21d21c130f97a7b21d8a317178e2e0c._comment new file mode 100644 index 000000000..7b2031d48 --- /dev/null +++ b/doc/forum/Hide_text/comment_1_f21d21c130f97a7b21d8a317178e2e0c._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + nickname="joey" + subject="comment 1" + date="2011-09-07T20:58:18Z" + content=""" +Sounds like you want [[ikiwiki/directive/toggle]] +"""]] diff --git a/doc/forum/Hide_text/comment_2_5a878865f34f78a89c4ec91a9425a085._comment b/doc/forum/Hide_text/comment_2_5a878865f34f78a89c4ec91a9425a085._comment new file mode 100644 index 000000000..80a8d4281 --- /dev/null +++ b/doc/forum/Hide_text/comment_2_5a878865f34f78a89c4ec91a9425a085._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawk_MMtLPS7osC5MjX00q2ATjvvXPWqm0ik" + nickname="micheal" + subject="comment 2" + date="2011-09-11T11:59:35Z" + content=""" +Thanks, that's exactly what I wanted! +"""]] diff --git a/doc/forum/How_best_to_manage_a_bilingual_ikiwiki_site__63__.mdwn b/doc/forum/How_best_to_manage_a_bilingual_ikiwiki_site__63__.mdwn new file mode 100644 index 000000000..8528c3b68 --- /dev/null +++ b/doc/forum/How_best_to_manage_a_bilingual_ikiwiki_site__63__.mdwn @@ -0,0 +1,15 @@ +For example, I need to deploy a wiki site in English and a non-English language. It can be assumed all pages are available in English. Some of the pages are/should be available in the other language. When a user creates/edits the one version of a page, he may or may not create/edit the version of the opposite language. + +Is there some recommended settings for this? + +For example, I'd like a link pointing to the opposite language version displayed on a page: + + This is an English page <LINK TO LOCAL LANGUAGE VERSION> + +and + + &*^&*^*(*()*)(^%^$%^%^&*^ <LINK TO ENGLISH VERSION> + +Any ideas how best to achieve something like this? + +Also, can I have non-ASCII char in source file names (`.mdwn`)? diff --git a/doc/forum/How_best_to_manage_a_bilingual_ikiwiki_site__63__/comment_1_4389d65b14fa1b7134098e0ffe3bf055._comment b/doc/forum/How_best_to_manage_a_bilingual_ikiwiki_site__63__/comment_1_4389d65b14fa1b7134098e0ffe3bf055._comment new file mode 100644 index 000000000..019c585e8 --- /dev/null +++ b/doc/forum/How_best_to_manage_a_bilingual_ikiwiki_site__63__/comment_1_4389d65b14fa1b7134098e0ffe3bf055._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + nickname="joey" + subject="comment 1" + date="2011-05-22T22:24:12Z" + content=""" +Use the [[po_plugin|plugins/po]] for this. + +(Yes, you may use any utf-8 in filenames of pages, as well as page contents.) +"""]] diff --git a/doc/forum/How_can_I_invert_the_banned__95__user_check__63__.mdwn b/doc/forum/How_can_I_invert_the_banned__95__user_check__63__.mdwn new file mode 100644 index 000000000..2436b2e56 --- /dev/null +++ b/doc/forum/How_can_I_invert_the_banned__95__user_check__63__.mdwn @@ -0,0 +1,33 @@ +Trying to lockdown a wiki so that it can only be edited by certain users and figured I'd just set + + banned_users: + - !user(myadmin) + +in my config but it doesn't work. I'm sure I must be doing something daft? + +PS: the user is authenticated via 'httpauth', would that make a difference? + +> That's not how `banned_users` works. Make yourself an admin: +> +> adminuser: +> - myadmin +> +> and disallow editing by non-admins: +> +> locked_pages: '*' +> +> You can enable the `opendiscussion` and/or `anonok` plugins if you want +> unprivileged users, perhaps logging in with an OpenID, to be able to +> edit discussion pages (if enabled via `discussion`) or post comments. +> +> You can also relax the `locked_pages` setting if you want unprivileged +> users to be able to edit certain areas of the site. +> +> --[[smcv]] + +>> That was my initial setup but it wasn't working and I got caught-up on the `banned_user` idea. It would seem I was getting tricked by some credential-caching-weirdness. Fired up another browser and `locked_pages` works perfectly. Thanks. -- fergus + +>>> Browsers generally remember HTTP auth credentials until they're closed +>>> or get a 401 error, and don't generally have a way to "log out". +>>> As far as I'm aware, there's nothing that [[plugins/httpauth]] can +>>> do about that. --[[smcv]] diff --git a/doc/forum/How_can_I_prevent_spam__63__.mdwn b/doc/forum/How_can_I_prevent_spam__63__.mdwn new file mode 100644 index 000000000..44e31927e --- /dev/null +++ b/doc/forum/How_can_I_prevent_spam__63__.mdwn @@ -0,0 +1,17 @@ +I am getting continuous spam like this: + + discussion 85.25.146.11 web 11:02:19 05/17/13 2rand[0,1,1] + discussion 85.25.146.11 web 11:02:13 05/17/13 2rand[0,1,1] + +The bot uses an IP address as the username and puts '2rand[0,1,1]' as comment text. + +I do not have a page 'discussion' in use, so I have redirected this page with an apache2 +Alias to a static page, just in case anyone stumbles on it. This means it cannot really +be edited via the web. However the bots that post +this spam are evidently not opening the page to edit it, but merely sending a cgi request +as if they had edited the page. The result is that no damage is done on the site and no +benefit is achieved for the spammer since google cannot see the result. However, the +logs are stuffed with spurious entries and a page is constantly recompiled, which wastes +resources. + +Is there some way to reject edits that do not arise from an established session? diff --git a/doc/forum/How_can_I_prevent_spam__63__/comment_1_fd26fb7f1569e8c44ba8262794f938db._comment b/doc/forum/How_can_I_prevent_spam__63__/comment_1_fd26fb7f1569e8c44ba8262794f938db._comment new file mode 100644 index 000000000..a7293288c --- /dev/null +++ b/doc/forum/How_can_I_prevent_spam__63__/comment_1_fd26fb7f1569e8c44ba8262794f938db._comment @@ -0,0 +1,19 @@ +[[!comment format=mdwn + username="http://joeyh.name/" + nickname="joey" + subject="comment 1" + date="2013-05-17T17:55:46Z" + content=""" +Normally ikiwiki requires a valid session cookie of a logged in user to edit pages. It sounds like you may have the opendiscussion or anonok plugins enabled, which allows anyone to edit without logging in. Recommend disabling them. + +Since you know the spammer's IP, put it into ikiwiki.setup: + +<pre> +banned_users: + - ip(85.25.146.11) +</pre> + +If the user was logging in, you could also put their username in the ban list. + +You can also try enabling the blogspam plugin. +"""]] diff --git a/doc/forum/How_can_I_prevent_spam__63__/comment_2_d098124f005976ee815d25c883bc9106._comment b/doc/forum/How_can_I_prevent_spam__63__/comment_2_d098124f005976ee815d25c883bc9106._comment new file mode 100644 index 000000000..53e743361 --- /dev/null +++ b/doc/forum/How_can_I_prevent_spam__63__/comment_2_d098124f005976ee815d25c883bc9106._comment @@ -0,0 +1,16 @@ +[[!comment format=mdwn + username="http://claimid.com/richard-lyons" + nickname="richard-lyons" + subject="comment 2" + date="2013-05-17T20:56:23Z" + content=""" +I did indeed have opendiscussion active. I shall wait to see what happens after disabling it. + +The bots seem to make 5 consecutive edits at short intervals (around 2 minutes) using an IP +address as a username. I do not know if the IP is the one from which they work. There are +usually two or three sets of five edits using different IP addresses as username in each hour. + +I did try blocking specific IPs but they constantly change. + +It would be good if blocking could match a regexp, but as far as I can see this is not an option, +"""]] diff --git a/doc/forum/How_can_I_prevent_spam__63__/comment_3_deb434d01aaefa18d2791e48d6c824ae._comment b/doc/forum/How_can_I_prevent_spam__63__/comment_3_deb434d01aaefa18d2791e48d6c824ae._comment new file mode 100644 index 000000000..64783befc --- /dev/null +++ b/doc/forum/How_can_I_prevent_spam__63__/comment_3_deb434d01aaefa18d2791e48d6c824ae._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://claimid.com/richard-lyons" + nickname="richard-lyons" + subject="SOLVED -- How can I prevent spam?" + date="2013-05-18T08:13:19Z" + content=""" +I can now confirm that this particular attack has stopped after removing the opendiscussion plugin. +"""]] diff --git a/doc/forum/How_do_I_enable_OpenID__63__.mdwn b/doc/forum/How_do_I_enable_OpenID__63__.mdwn new file mode 100644 index 000000000..a4e1a4531 --- /dev/null +++ b/doc/forum/How_do_I_enable_OpenID__63__.mdwn @@ -0,0 +1 @@ +I'm trying to set up a new ikiwiki based blog and I want commentors to be able to log in with OpenID. To enable OpenID I installed Net::OpenID::Consumer, and enabled the openid plugin in my blog.setup file and ran the ikiwiki --setup command. Despite doing that I still only see the username and password in the login screen. What am I missing? diff --git a/doc/forum/How_does_ikiwiki_remember_times__63__.mdwn b/doc/forum/How_does_ikiwiki_remember_times__63__.mdwn new file mode 100644 index 000000000..6b7739fd0 --- /dev/null +++ b/doc/forum/How_does_ikiwiki_remember_times__63__.mdwn @@ -0,0 +1,98 @@ +This is similar to the last post in this forum. I want to know exactly how ikiwiki remembers the times associated with pages, especially when using it for blogging, so I know whether I can trust it or not. From that last thread, I think what ikiwiki does is this: + +* The created time of a file is when that file was first committed into the versioning repository (in my case git) + + > If `--getctime` it used, yes. In normal operation, when new files + > are added, ikiwiki sets the creation time to the ctime of the file + > on disk, rather than bothering to ask the VCS. --[[Joey]] + +* The modified time of a file is what that file was last updated in the repository + + > Almost right, the modified time is actually taken from the + > modification time of the file in disk. --[[Joey]] + +And with a blog, by default, the posts are ordered by creation time, although an option can order them by modified time. + +Okay. So this should mean that the times are safe if, for example, I delete my working copy and then clone another one from the bare git repository, or otherwise mess up the creation times and mtimes stored as file metadata on the filesystem. + +Do I have it right? + +> Some VCS, like git, set the file mtimes to the current time +> when making a new checkout, so they will be lost if you do that. +> The creation times can be retrived using the `--getctime` option. +> --[[Joey]] +> +> > Thanks for the clarification. I ran some tests of my own to make sure I understand it right, and I'm satisfied +> > that the order of posts in my blog can be retrieved from the VCS using the `--getctime` option, at least if I +> > choose to order my posts by creation time rather than modification time. But I now know that I can't rely on +> > page modification times in ikiwiki as these can be lost permanently. +> +> > > Update: It's now renamed to `--gettime`, and pulls both the creation +> > > and modification times. Also, per [[todo/auto_getctime_on_fresh_build]], +> > > this is now done automatically the first time ikiwiki builds a +> > > srcdir. So, no need to worry about this any more! --[[Joey]] +> > +> > I would suggest that there should at least be a `--getmtime` option like you describe, and perhaps that +> > `--getctime` and `--getmtime` be _on by default_. In my opinion the creation times and modification times of +> > pages in ikiwiki are part of the user's content and are important to protect, because the user may be relying +> > on them, especially if they use blogging or lists of recently modified pages, etc. Right now the modification +> > times can be lost permanently. +> > +> > Is there a typo in the description of `--getctime` in the man page? +> > +> > > --getctime +> > > Pull **last changed time** for each new page out of the revision +> > > control system. This rarely used option provides a way to get +> > > the real creation times of items in weblogs, such as when build‐ +> > > ing a wiki from a new Subversion checkout. It is unoptimised and +> > > quite slow. It is best used with --rebuild, to force ikiwiki to +> > > get the ctime for all pages. +> > +> > Surely it is not the _last changed time_ but the _first seen time_ of each page that is pulled out of the VCS? +> > If the aim is to get the real creation times of items in weblogs, then the last times that the items were +> > changed in the VCS is not going to help. -- [[seanh]] +>>> Typo, fixed. --[[Joey]] + +> > > If you want to preserve the date of a page, the best way to do it is to +> > > use [[ikiwiki/directive/meta]] date="foo". This will survive checkouts, +> > > VCS migrations, etc. -- [[Jon]] +> > > +> > > > That's a good tip Jon. That would also survive renaming a page by renaming its mdwn file, which would +> > > > normally lose the times also. (And in that case I think both times are irretrievable, even by +> > > > `--getctime`). I might start using a simple script to make blog posts that creates a file for +> > > > me, puts today's date in the file as a meta, and opens the file in my editor. -- [[seanh]] + +>>>>> I use a script that does that and also sets up templates and tags +>>>>> for a new item: + + #!/bin/sh + set -u + set -e + + if [ $# -ne 1 ]; then + echo usage: $0 pagename >&2 + exit 1 + fi + + pagename="$1" + + if [ -e "$pagename" ]; then + echo error: "$pagename" exists >&2 + exit 1 + fi + + date=$(date) + echo '\[[!template id=draft]]' >> "$pagename" + echo "\[[!meta date=\"$date\"]]" >> "$pagename" + echo "\[[!tag draft]]" >> "$pagename" + git add "$pagename" + $EDITOR "$pagename" + +>>>>> -- [[Jon]] + +> A quick workaround for me to get modification times right is the following +> little zsh script, which unfortunately only works for git: + +>> Elided; no longer needed since --gettime does that, and much faster! --[[Joey]] + +> --[[David_Riebenbauer]] diff --git a/doc/forum/How_is_TITLE_evaluated_in_inline_archive_templates__63__.mdwn b/doc/forum/How_is_TITLE_evaluated_in_inline_archive_templates__63__.mdwn new file mode 100644 index 000000000..fc84fabbd --- /dev/null +++ b/doc/forum/How_is_TITLE_evaluated_in_inline_archive_templates__63__.mdwn @@ -0,0 +1,11 @@ +Hi, + +I'm wondering how is TITLE evaluated in inline archive templates? + +Needless to say, I don't know much perl except the code that looks similar to other languages like bash. + +I found this line: + +$template->param(title => pagetitle(basename($page))); + +It seems to return a page name (pagetitle having no effect). Or maybe I'm not testing this the right way! diff --git a/doc/forum/How_long_does_server_delay_newly_pushed_revisions__63__.mdwn b/doc/forum/How_long_does_server_delay_newly_pushed_revisions__63__.mdwn new file mode 100644 index 000000000..dea95c285 --- /dev/null +++ b/doc/forum/How_long_does_server_delay_newly_pushed_revisions__63__.mdwn @@ -0,0 +1,10 @@ +So I + +1. checked out the repository of the my Ikiwiki instance and added new page and editted existing pages in the working copy +2. Then add and commit the revisions: `git add .` and `git commit -m "update"` +3. Then push it to server: `git push` + +I then go to browser and go to the Ikiwiki URL of recent changes. I didn't find the new revision, neither I can open the new pages. +Is there a way to verify my revision did go in? How long does the server delays processing it? + + diff --git a/doc/forum/How_to_add_a_mouse-over_pop-up_label_for_a_text__63__.mdwn b/doc/forum/How_to_add_a_mouse-over_pop-up_label_for_a_text__63__.mdwn new file mode 100644 index 000000000..cf9245404 --- /dev/null +++ b/doc/forum/How_to_add_a_mouse-over_pop-up_label_for_a_text__63__.mdwn @@ -0,0 +1,8 @@ +How to add a mouse-over pop-up label for a text? + +I'd like to have the following effect: + +when a user move the mouse arrow on top of the text, a small window will show up at the upper right of the text and the window contains some additional information about the text. + +Any idea how to achieve this? + diff --git a/doc/forum/How_to_add_additional_links_to_the_gray_horizontable_bar_under_page_title__63__.mdwn b/doc/forum/How_to_add_additional_links_to_the_gray_horizontable_bar_under_page_title__63__.mdwn new file mode 100644 index 000000000..537ba6161 --- /dev/null +++ b/doc/forum/How_to_add_additional_links_to_the_gray_horizontable_bar_under_page_title__63__.mdwn @@ -0,0 +1,3 @@ +How to add additional links to the gray horizontable bar under page title? + +What I meant by the gray horizontable bar shows "Edit RecentChanges Preferences". I want to disable those three but add some other links to other pages in my website. diff --git a/doc/forum/How_to_add_additional_links_to_the_gray_horizontable_bar_under_page_title__63__/comment_1_f2e52d38f60888c7d5142de853123540._comment b/doc/forum/How_to_add_additional_links_to_the_gray_horizontable_bar_under_page_title__63__/comment_1_f2e52d38f60888c7d5142de853123540._comment new file mode 100644 index 000000000..1bb3fa7cb --- /dev/null +++ b/doc/forum/How_to_add_additional_links_to_the_gray_horizontable_bar_under_page_title__63__/comment_1_f2e52d38f60888c7d5142de853123540._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawmb2CAGUNU_Kx6YSImD2ox6MtjuaM6Jp1E" + nickname="Nicolas" + subject="comment 1" + date="2012-11-09T08:34:42Z" + content=""" +You could use custom templates and hardcode those links there. +"""]] diff --git a/doc/forum/How_to_add_link_to_previous_and_next_blog_on_blog_pages__63__.mdwn b/doc/forum/How_to_add_link_to_previous_and_next_blog_on_blog_pages__63__.mdwn new file mode 100644 index 000000000..3f771e777 --- /dev/null +++ b/doc/forum/How_to_add_link_to_previous_and_next_blog_on_blog_pages__63__.mdwn @@ -0,0 +1,14 @@ +In a Ikiwiki instance, I made a subdirectory to hold blog pages + + /website + blog.mdwn + ... + + /website/blog + /website/blog/blog1.mdwn + /website/blog/blog2.mdwn + ... + +On blog.mdwn, reader by default see the last 10 posts, but it seems there is no link to blog pages older than that. What's a good way to make titles of blog pages older also somehow visible to reader at the blog front page `blog.mdwn`? + +On any individual blog page such as `blog1.mdwn`, there is not a link to the blog pages immediately before and after it. How to make such links? diff --git a/doc/forum/How_to_add_link_to_previous_and_next_blog_on_blog_pages__63__/comment_1_aad510f45be505efaabcb6fb860665a4._comment b/doc/forum/How_to_add_link_to_previous_and_next_blog_on_blog_pages__63__/comment_1_aad510f45be505efaabcb6fb860665a4._comment new file mode 100644 index 000000000..ce99b8475 --- /dev/null +++ b/doc/forum/How_to_add_link_to_previous_and_next_blog_on_blog_pages__63__/comment_1_aad510f45be505efaabcb6fb860665a4._comment @@ -0,0 +1,23 @@ +[[!comment format=mdwn + username="http://smcv.pseudorandom.co.uk/" + nickname="smcv" + subject="use trail=yes, and an extra inline with archive=yes" + date="2012-08-04T17:22:18Z" + content=""" +To get just the titles of older posts, you want an inline with +`archive=\"yes\"`, probably one that skips the same number of posts +displayed in full: + + [[!inline pages=\"blog/* and !*/Discussion\" + skip=\"10\" feeds=\"no\" archive=\"yes\"]] + +To get 'next' and 'previous' links on each post, use a recent +IkiWiki version, enable the [[plugins/trail]] plugin and add +`trail=\"yes\"` to your main inline: + + [[!inline pages=\"blog/* and !*/Discussion\" + show=\"10\" trail=\"yes\"]] + +For instance see +[my blog](http://git.pseudorandom.co.uk/pseudorandom.co.uk/smcv.git/blob/83e9a713d77778b58460ed04f6c48665d817f3cd:/index.mdwn). +"""]] diff --git a/doc/forum/How_to_add_link_to_previous_and_next_blog_on_blog_pages__63__/comment_2_ee65792a5b796caa216f4e7a653fc668._comment b/doc/forum/How_to_add_link_to_previous_and_next_blog_on_blog_pages__63__/comment_2_ee65792a5b796caa216f4e7a653fc668._comment new file mode 100644 index 000000000..5546c4789 --- /dev/null +++ b/doc/forum/How_to_add_link_to_previous_and_next_blog_on_blog_pages__63__/comment_2_ee65792a5b796caa216f4e7a653fc668._comment @@ -0,0 +1,23 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawmKyeW2G4jjSdnL1m6kPPtAiGFUBsnYCfY" + nickname="FName" + subject="How to install the trail package?" + date="2012-08-09T00:11:26Z" + content=""" +I tried putting + +trail + +in + + add_plugins => [qw{ + ... + trail + ... + }] + +in site.setup and rebuild. It gives error + + Failed to load plugin IkiWiki::Plugin::trail: Can't locate IkiWiki/Plugin/trail.pm in @IN ... + +"""]] diff --git a/doc/forum/How_to_allow_.markdown_and_.md_at_the_same_time_as_valid_extensions_for_source_files__63__.mdwn b/doc/forum/How_to_allow_.markdown_and_.md_at_the_same_time_as_valid_extensions_for_source_files__63__.mdwn new file mode 100644 index 000000000..d5f144957 --- /dev/null +++ b/doc/forum/How_to_allow_.markdown_and_.md_at_the_same_time_as_valid_extensions_for_source_files__63__.mdwn @@ -0,0 +1 @@ +How to allow .markdown and .md (at the same time) as valid extensions for source files? The default is .mdwn. diff --git a/doc/forum/How_to_apply_a_background_color_to_a_page__63__.mdwn b/doc/forum/How_to_apply_a_background_color_to_a_page__63__.mdwn new file mode 100644 index 000000000..5beba1258 --- /dev/null +++ b/doc/forum/How_to_apply_a_background_color_to_a_page__63__.mdwn @@ -0,0 +1 @@ +I want one page to use gray background color (full page, not just background of text). How? diff --git a/doc/forum/How_to_change_registration_page.mdwn b/doc/forum/How_to_change_registration_page.mdwn new file mode 100644 index 000000000..f339f71c4 --- /dev/null +++ b/doc/forum/How_to_change_registration_page.mdwn @@ -0,0 +1,9 @@ +Well, I simply don't see it. +I would like to change the "account registration" page, where it says user, password, repeat password, Account Creation Password, E-Mail. + +I simply want it to ask a question like "Who's your daddy" or "What are we all working on" instead of "Account creation password". + +I already grepped through the files of the source which I compiled ikiwiki from - I just can't find it. I'm a noob in cgi, it seems to be somewhat in there, but that could also be totally wrong. + +Can you tell me where to look? + diff --git a/doc/forum/How_to_change_registration_page/comment_1_43758a232e4360561bc84f710862ff40._comment b/doc/forum/How_to_change_registration_page/comment_1_43758a232e4360561bc84f710862ff40._comment new file mode 100644 index 000000000..5edd993d7 --- /dev/null +++ b/doc/forum/How_to_change_registration_page/comment_1_43758a232e4360561bc84f710862ff40._comment @@ -0,0 +1,14 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + nickname="joey" + subject="comment 1" + date="2012-01-30T19:30:20Z" + content=""" +Sure.. You're looking for the file `IkiWiki/Plugin/passwordauth.pm` + +This line in particular is the text that gets modified and displayed to the user. + +<pre> + name => \"account_creation_password\", +</pre> +"""]] diff --git a/doc/forum/How_to_change_registration_page/comment_2_8176ef231cf901802fc60b6d414018e6._comment b/doc/forum/How_to_change_registration_page/comment_2_8176ef231cf901802fc60b6d414018e6._comment new file mode 100644 index 000000000..8e67162e1 --- /dev/null +++ b/doc/forum/How_to_change_registration_page/comment_2_8176ef231cf901802fc60b6d414018e6._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawndsaC4GaIBw49WNdbk2Faqfm_mrtQgul8" + nickname="Christian" + subject="comment 2" + date="2012-02-29T06:58:26Z" + content=""" +thanks! +"""]] diff --git a/doc/forum/How_to_configure_po_plugin__63__.mdwn b/doc/forum/How_to_configure_po_plugin__63__.mdwn new file mode 100644 index 000000000..a03358ddd --- /dev/null +++ b/doc/forum/How_to_configure_po_plugin__63__.mdwn @@ -0,0 +1,21 @@ +I put + + # po plugin + po_master_language => 'en|English', + + po_slave_languages => [ 'zh|Chinese'] + + +in page.setup. And did + + $ikiwiki --setup ./page.setup + +but get errors: + + Can't use string ("en|English") as a HASH ref while "strict refs" in use at /usr/share/perl5/IkiWiki/Plugin/po.pm line 162. + +Line 162 of the file reads + + delete $config{po_slave_languages}{$config{po_master_language}{code}};; + +What's wrong? How to fix it? diff --git a/doc/forum/How_to_configure_po_plugin__63__/comment_1_5e0cc4cdfd126f2f4af64104f02102d6._comment b/doc/forum/How_to_configure_po_plugin__63__/comment_1_5e0cc4cdfd126f2f4af64104f02102d6._comment new file mode 100644 index 000000000..fc194b3e6 --- /dev/null +++ b/doc/forum/How_to_configure_po_plugin__63__/comment_1_5e0cc4cdfd126f2f4af64104f02102d6._comment @@ -0,0 +1,9 @@ +[[!comment format=mdwn + username="intrigeri" + ip="88.80.28.70" + subject="Please upgrade" + date="2011-12-20T09:34:56Z" + content=""" +You seem to be using an older version of ikiwiki. Either use a hash ref (see [old documentation](http://source.ikiwiki.branchable.com/?p=source.git;a=blobdiff;f=doc/plugins/po.mdwn;h=c36414c8e85f5bb11e2c3a7c3bd41e829abe15a6;hp=53327c1dae94ef5896119cc874133a9a3c1a9b4e;hb=862fc7c1ab1f7d709561bcb02fc8ede57b90a51b;hpb=e50df5ea7601b6a1fc03994650ddff728aba7b57)) or upgrade. + +"""]] diff --git a/doc/forum/How_to_create_a_WikiLink_to_a_page_in_a_subdirectory__63__.mdwn b/doc/forum/How_to_create_a_WikiLink_to_a_page_in_a_subdirectory__63__.mdwn new file mode 100644 index 000000000..75d98fea1 --- /dev/null +++ b/doc/forum/How_to_create_a_WikiLink_to_a_page_in_a_subdirectory__63__.mdwn @@ -0,0 +1,26 @@ +How to create a WikiLink to a page in a subdirectory? + +I have a page I want to create Wikilink to in + + + website/subdir/page.mdwn + + +And the wikilink I want to create should be in a page in the website root directory: + + + website/index.mdwn + + +If I just write + + \[[page]] + +it seems it will assume the page should be found at + + + website/page.mdwn + +and adds a question mark ? in front of the link in the generated HTML file. + +How to make such a Wikilink? diff --git a/doc/forum/How_to_create_a_WikiLink_to_a_page_in_a_subdirectory__63__/comment_1_d20ee1d8d7a3e77a445f8b887e807119._comment b/doc/forum/How_to_create_a_WikiLink_to_a_page_in_a_subdirectory__63__/comment_1_d20ee1d8d7a3e77a445f8b887e807119._comment new file mode 100644 index 000000000..524852fad --- /dev/null +++ b/doc/forum/How_to_create_a_WikiLink_to_a_page_in_a_subdirectory__63__/comment_1_d20ee1d8d7a3e77a445f8b887e807119._comment @@ -0,0 +1,11 @@ +[[!comment format=mdwn + username="http://smcv.pseudorandom.co.uk/" + nickname="smcv" + subject="comment 1" + date="2012-06-27T07:31:30Z" + content=""" +`\[[subdir/page]]`. + +IkiWiki terminology is that a page in a subdirectory is a \"subpage\". +See [[ikiwiki/SubPage]] and [[ikiwiki/subpage/LinkingRules]] for more details. +"""]] diff --git a/doc/forum/How_to_create_first_translation_page_using_po_plugin__63__.mdwn b/doc/forum/How_to_create_first_translation_page_using_po_plugin__63__.mdwn new file mode 100644 index 000000000..e9dd6654b --- /dev/null +++ b/doc/forum/How_to_create_first_translation_page_using_po_plugin__63__.mdwn @@ -0,0 +1,24 @@ +I followed instructions at + + http://ikiwiki.info/plugins/po/ + +and added to `configfile` + + po_master_language => 'en|English', + po_slave_languages => [ 'zh|Chinese' ], + po_translatable_pages => '(* and !*/Discussion and !blog/*/comment_*)', + po_link_to => 'current' + +and did + + ikiwiki --setup configfile + +But I don't seem to see any change in the newly built site. + +How do I actually use po to create translation pages? + +1) I have existing pages that's in English. How do I add translated versions of some of those pages in the slave language? + +2) How do I add new pages with the primary language version and alternative versions in slave languages? + +The documentation of po is not explicit with what are the concrete steps. diff --git a/doc/forum/How_to_customize_page_title__63__.mdwn b/doc/forum/How_to_customize_page_title__63__.mdwn new file mode 100644 index 000000000..1e5be83b8 --- /dev/null +++ b/doc/forum/How_to_customize_page_title__63__.mdwn @@ -0,0 +1,6 @@ +The title of a page typically looks like + + `home/ dir1` + `home/ dir1/ dir2 + +I want to customize the `/` to something else. What's the proper way of doing it? diff --git a/doc/forum/How_to_customize_page_title__63__/comment_1_403e1f866b5e04e5899021f54bbdd1ed._comment b/doc/forum/How_to_customize_page_title__63__/comment_1_403e1f866b5e04e5899021f54bbdd1ed._comment new file mode 100644 index 000000000..e8d79038b --- /dev/null +++ b/doc/forum/How_to_customize_page_title__63__/comment_1_403e1f866b5e04e5899021f54bbdd1ed._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + nickname="joey" + subject="comment 1" + date="2011-05-22T22:23:15Z" + content=""" +The only way to do that, other than some css3 hacks, is to edit `page.tmpl`. Which is not really recommended as then you get to maintain the customized version. + +More usual is to use a directive to set the actual page title displayed at the end: \[[!meta title=\"foo\"]] +"""]] diff --git a/doc/forum/How_to_disable___34__Add_a_new_post_titled:__34___submission_form__63__.mdwn b/doc/forum/How_to_disable___34__Add_a_new_post_titled:__34___submission_form__63__.mdwn new file mode 100644 index 000000000..1443a188b --- /dev/null +++ b/doc/forum/How_to_disable___34__Add_a_new_post_titled:__34___submission_form__63__.mdwn @@ -0,0 +1 @@ +After setting up a blog subdirectory. It has a input field for inputing title of a new post. How to disable that? diff --git a/doc/forum/How_to_disable___34__Add_a_new_post_titled:__34___submission_form__63__/comment_1_3dfa9ac6473d0d5ebc9d99ec39e96216._comment b/doc/forum/How_to_disable___34__Add_a_new_post_titled:__34___submission_form__63__/comment_1_3dfa9ac6473d0d5ebc9d99ec39e96216._comment new file mode 100644 index 000000000..bad773924 --- /dev/null +++ b/doc/forum/How_to_disable___34__Add_a_new_post_titled:__34___submission_form__63__/comment_1_3dfa9ac6473d0d5ebc9d99ec39e96216._comment @@ -0,0 +1,9 @@ +[[!comment format=mdwn + username="http://smcv.pseudorandom.co.uk/" + nickname="smcv" + subject="comment 1" + date="2013-09-17T07:46:01Z" + content=""" +Remove the `rootpage` parameter, and don't set the `postform` parameter +to `yes` or `1`. +"""]] diff --git a/doc/forum/How_to_fix___34__does_not_map_to_Unicode__34___errors__63__.mdwn b/doc/forum/How_to_fix___34__does_not_map_to_Unicode__34___errors__63__.mdwn new file mode 100644 index 000000000..20a4ad022 --- /dev/null +++ b/doc/forum/How_to_fix___34__does_not_map_to_Unicode__34___errors__63__.mdwn @@ -0,0 +1,20 @@ +I'm getting a number of errors like this when running ikiwiki: + + utf8 "\xA2" does not map to Unicode at /usr/local/share/perl/5.10.0/IkiWiki.pm line 739, <$in> chunk 1. + +I think it's because some of my files contain non-utf8, non-unicode, or somehow bad characters in them, probably fancy quotes and the like that have been copy-and-pasted from my web browser. The problem is that I have hundreds of files, I transferred them all over from pyblosxom to ikiwiki at once, and the error message doesn't tell me which file the error comes from. How can I fix this? + +Thanks +-- seanh + +> Unfortunatly, these messages are logged by perl so there's no way to add +> a filename to them. +> +> If you run the build in --verbose mode, you should see which page ikiwiki +> is working on, and unless it inlines some other page, you can be pretty +> sure that page contains invalid utf-8 if the message is then printed. +> +> Another option is to use the `isutf8` program from +> [moreutils](http://kitenet.net/~joey/code/moreutils/), +> and run it on each file, it will tell you the line number +> and character position that is invalid. --[[Joey]] diff --git a/doc/forum/How_to_format___91____91__foobar__93____93___in_code_blocks__63__.mdwn b/doc/forum/How_to_format___91____91__foobar__93____93___in_code_blocks__63__.mdwn new file mode 100644 index 000000000..e26ef8d12 --- /dev/null +++ b/doc/forum/How_to_format___91____91__foobar__93____93___in_code_blocks__63__.mdwn @@ -0,0 +1,9 @@ +Normally if i indent by 4 spaces, the text will format as computer code, for example, + + int main () { + ... + } + +but it doesn't work for [ [ foobar ] ] (remove the space between the two square brackets). It will expose code like: + + [[foobar]] diff --git a/doc/forum/How_to_format___91____91__foobar__93____93___in_code_blocks__63__/comment_1_ad000d39fd1dc05aa8ef6eb19d8d999b._comment b/doc/forum/How_to_format___91____91__foobar__93____93___in_code_blocks__63__/comment_1_ad000d39fd1dc05aa8ef6eb19d8d999b._comment new file mode 100644 index 000000000..aa26b086b --- /dev/null +++ b/doc/forum/How_to_format___91____91__foobar__93____93___in_code_blocks__63__/comment_1_ad000d39fd1dc05aa8ef6eb19d8d999b._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://acathur.myopenid.com/" + ip="31.56.6.65" + subject="comment 1" + date="2012-02-26T08:08:15Z" + content=""" +doing `\\[[foobar]]` works for me +"""]] diff --git a/doc/forum/How_to_generate_blog_archive_pages_in___47__blog_subdir_but_not_ikiwiki_root_path__63__.mdwn b/doc/forum/How_to_generate_blog_archive_pages_in___47__blog_subdir_but_not_ikiwiki_root_path__63__.mdwn new file mode 100644 index 000000000..e4901d78b --- /dev/null +++ b/doc/forum/How_to_generate_blog_archive_pages_in___47__blog_subdir_but_not_ikiwiki_root_path__63__.mdwn @@ -0,0 +1,26 @@ +My Ikiwiki and blog has structure + + /website + blog.mdwn + ... + + /website/blog + /website/blog/blog1.mdwn + /website/blog/blog2.mdwn + ... + +After running + + ikiwiki-calendar ./foo.setup "/blog/*" + +I got a + + /website/archives/ + +and archive pages in it. + +I'd like to have it in + + /website/blog/archives/ + +as those are archive pages for blog pages only. How to do it? diff --git a/doc/forum/How_to_inline_a_page_from_another_git_repository.mdwn b/doc/forum/How_to_inline_a_page_from_another_git_repository.mdwn new file mode 100644 index 000000000..528a48b6e --- /dev/null +++ b/doc/forum/How_to_inline_a_page_from_another_git_repository.mdwn @@ -0,0 +1,5 @@ +I am migrating a dev site which was previously using Trac. + +Some of the wiki pages include RST documents from the code repository. What would be the best way to do this using ikiwiki? I would prefer not to include the full code repository in ikiwiki src as there are many source files I do not want to be processed by ikiwiki. + +A possible solution would be something like underlay, but for which only explicitly named files would be processed by ikiwiki. diff --git a/doc/forum/How_to_list_all_pages_in_a_wiki_instance__63__.mdwn b/doc/forum/How_to_list_all_pages_in_a_wiki_instance__63__.mdwn new file mode 100644 index 000000000..dcc0b15c6 --- /dev/null +++ b/doc/forum/How_to_list_all_pages_in_a_wiki_instance__63__.mdwn @@ -0,0 +1,5 @@ +How to list all pages in a wiki instance? + + + +How to list all pages in a wiki instance? I basically need an index of all existing pages. diff --git a/doc/forum/How_to_list_all_pages_in_a_wiki_instance__63__/comment_1_920bcc70fe6d081cf27aa2cc7c6136f4._comment b/doc/forum/How_to_list_all_pages_in_a_wiki_instance__63__/comment_1_920bcc70fe6d081cf27aa2cc7c6136f4._comment new file mode 100644 index 000000000..748f9f04c --- /dev/null +++ b/doc/forum/How_to_list_all_pages_in_a_wiki_instance__63__/comment_1_920bcc70fe6d081cf27aa2cc7c6136f4._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://kerravonsen.dreamwidth.org/" + ip="202.173.183.92" + subject="comment 1" + date="2011-08-17T23:36:56Z" + content=""" +Use the [[plugins/map]] plugin. +"""]] diff --git a/doc/forum/How_to_list_new_pages__44___inline__63__.mdwn b/doc/forum/How_to_list_new_pages__44___inline__63__.mdwn new file mode 100644 index 000000000..f28e8b99b --- /dev/null +++ b/doc/forum/How_to_list_new_pages__44___inline__63__.mdwn @@ -0,0 +1,5 @@ +Hi, I'd love to include a "New posts" list into my front page, like at <http://danhixon.github.com/> for example. + +It should be different from recent changes in that it shouldn't show modifications of existing pages, and in that it would be inside a page with other content. + +Thanks, Thomas diff --git a/doc/forum/How_to_list_new_pages__44___inline__63__/comment_1_e989b18bade34a92a9c8fe7099036e15._comment b/doc/forum/How_to_list_new_pages__44___inline__63__/comment_1_e989b18bade34a92a9c8fe7099036e15._comment new file mode 100644 index 000000000..cf6f642d4 --- /dev/null +++ b/doc/forum/How_to_list_new_pages__44___inline__63__/comment_1_e989b18bade34a92a9c8fe7099036e15._comment @@ -0,0 +1,13 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + nickname="joey" + subject="use an inline directive" + date="2010-11-29T20:39:37Z" + content=""" +This is what the [[ikiwiki/directive/inline]] directive is for. It's often used, to for example, show new posts to a blog. If you want to show new posts to anywhere in your site, or whatever, you can configure the [[ikiwiki/PageSpec]] in it to do that, too. + +For example, you could use this: + + The most recent 3 pages added to this site: + \[[!inline pages=\"*\" archive=yes show=4]] +"""]] diff --git a/doc/forum/How_to_lock_all_pages_except_discussions_and_comments_to_blog_posts__63__.mdwn b/doc/forum/How_to_lock_all_pages_except_discussions_and_comments_to_blog_posts__63__.mdwn new file mode 100644 index 000000000..18ff8f1f5 --- /dev/null +++ b/doc/forum/How_to_lock_all_pages_except_discussions_and_comments_to_blog_posts__63__.mdwn @@ -0,0 +1,11 @@ +I enabled `comments`, `lockedit` plugins. I put blog posts in `~/foobar.com/static/blog/` and other pages in `~/foobar.com/static/`. I want to + +* allow Wiki-style `Discussion` to my pages outside of `blog` +* allow blog-style comment to my blog posts +* lock all pages that's not comment or discussion + +How to achieve this? + +Is it `locked_pages => '!blog/comment_* and !*/Discussion'` for `lockedit` plugin, right? + + diff --git a/doc/forum/How_to_lock_all_pages_except_discussions_and_comments_to_blog_posts__63__/comment_1_e153beb17b6ada69c6ab09d1f491d112._comment b/doc/forum/How_to_lock_all_pages_except_discussions_and_comments_to_blog_posts__63__/comment_1_e153beb17b6ada69c6ab09d1f491d112._comment new file mode 100644 index 000000000..21abe8d83 --- /dev/null +++ b/doc/forum/How_to_lock_all_pages_except_discussions_and_comments_to_blog_posts__63__/comment_1_e153beb17b6ada69c6ab09d1f491d112._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + nickname="joey" + subject="comment 1" + date="2011-05-22T17:23:55Z" + content=""" +Almost.. `'* and !*/Discussion and !postcomment(blog/*)'` +"""]] diff --git a/doc/forum/How_to_make_a_table_of_content_at_the_top_of_page__63__.mdwn b/doc/forum/How_to_make_a_table_of_content_at_the_top_of_page__63__.mdwn new file mode 100644 index 000000000..b185e3b61 --- /dev/null +++ b/doc/forum/How_to_make_a_table_of_content_at_the_top_of_page__63__.mdwn @@ -0,0 +1,3 @@ +How to make a table of content at the top of page? + +Ideally, it should be a programmable approach, for example, allow such table of content to be made automatically when the page length is longer than certain configurable threshold. diff --git a/doc/forum/How_to_make_a_table_of_content_at_the_top_of_page__63__/comment_1_6dedc31dd1145490bb5fa4ad14cc4c63._comment b/doc/forum/How_to_make_a_table_of_content_at_the_top_of_page__63__/comment_1_6dedc31dd1145490bb5fa4ad14cc4c63._comment new file mode 100644 index 000000000..49d25ed02 --- /dev/null +++ b/doc/forum/How_to_make_a_table_of_content_at_the_top_of_page__63__/comment_1_6dedc31dd1145490bb5fa4ad14cc4c63._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawnxp2XU8gIribhhGhGuYtU6eMMwHv5gUGI" + nickname="Amitai" + subject="comment 1" + date="2011-06-05T17:11:40Z" + content=""" +To insert one where you want it, [[ikiwiki/directive/toc]]. +"""]] diff --git a/doc/forum/How_to_migrate_multiple_pages_in_root_directory_into_a_new_subdirectory__63__.mdwn b/doc/forum/How_to_migrate_multiple_pages_in_root_directory_into_a_new_subdirectory__63__.mdwn new file mode 100644 index 000000000..c7c2b72a7 --- /dev/null +++ b/doc/forum/How_to_migrate_multiple_pages_in_root_directory_into_a_new_subdirectory__63__.mdwn @@ -0,0 +1,10 @@ +How to migrate multiple pages in root directory into a new subdirectory? + +I have multiple pages in the root directory of my website: + + $ pwd + /home/doss/public_html + $ ls + a. mdwn b.mdwn section.mdwn subdir + +What's the procedures to migrate a.mdwn and b.mdwn to subdir and keep correct links to them that might exist in other pages like section.mdwn? diff --git a/doc/forum/How_to_migrate_multiple_pages_in_root_directory_into_a_new_subdirectory__63__/comment_1_a83a1a33afbf245971733b4128809365._comment b/doc/forum/How_to_migrate_multiple_pages_in_root_directory_into_a_new_subdirectory__63__/comment_1_a83a1a33afbf245971733b4128809365._comment new file mode 100644 index 000000000..1935c7081 --- /dev/null +++ b/doc/forum/How_to_migrate_multiple_pages_in_root_directory_into_a_new_subdirectory__63__/comment_1_a83a1a33afbf245971733b4128809365._comment @@ -0,0 +1,15 @@ +[[!comment format=mdwn + username="http://jmtd.livejournal.com/" + ip="94.65.111.123" + subject="comment 1" + date="2011-08-22T12:53:03Z" + content=""" +If you use the [[plugins/rename]] plugin and go page-by-page, it will update backlinks for you. + +If you want to move a lot of files, such that it is impractical to do one at a time, you could write a script that + + * moved each page to the new location + * replaced the old page with one containing a [[plugins/meta]] redirect to the new location. + +-- [[Jon]] +"""]] diff --git a/doc/forum/How_to_properly_create_--_in_a_wiki_--____39__page__47__index.html__39___files.mdwn b/doc/forum/How_to_properly_create_--_in_a_wiki_--____39__page__47__index.html__39___files.mdwn new file mode 100644 index 000000000..4b7f468bf --- /dev/null +++ b/doc/forum/How_to_properly_create_--_in_a_wiki_--____39__page__47__index.html__39___files.mdwn @@ -0,0 +1,17 @@ +I am trying **in a wiki** to "manually," i.e. not using the web interface, use the "page/index.html" type of page creation. + +In my working clone src dir I can use, in succession, commands such as: + +mkdir MyNewPage + +touch MyNewPage/index.mdwn + +git add MyNewPage MyNewPage/index.mdwn + +[here I edit the new index.mdwn] + +git commit -a + +git push + +These are, roughly, the steps I have taken, and they seem to work. But surely there is a more elegant, **Ikiwiki-ish** solution. diff --git a/doc/forum/How_to_properly_create_--_in_a_wiki_--____39__page__47__index.html__39___files/comment_1_d9ee358ded5d5307ba73a8c11f81549d._comment b/doc/forum/How_to_properly_create_--_in_a_wiki_--____39__page__47__index.html__39___files/comment_1_d9ee358ded5d5307ba73a8c11f81549d._comment new file mode 100644 index 000000000..7412aa936 --- /dev/null +++ b/doc/forum/How_to_properly_create_--_in_a_wiki_--____39__page__47__index.html__39___files/comment_1_d9ee358ded5d5307ba73a8c11f81549d._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="https://me.yahoo.com/a/eetjWe8B34ZeUsHyFzpwC5QvBcEuVxllSvpJHw--#376d7" + nickname="Bob" + subject="SOLVED. NEVER MIND. SORRY." + date="2014-06-03T00:33:59Z" + content=""" +I get it. All I have to do is create NewPage.mdwn, add, commit, git pull and then git push, and lo and behold, NewPage/index.html is in my destination dir. +"""]] diff --git a/doc/forum/How_to_remove_the_linebreak_in_license.mdwn b/doc/forum/How_to_remove_the_linebreak_in_license.mdwn new file mode 100644 index 000000000..4e43cb9c3 --- /dev/null +++ b/doc/forum/How_to_remove_the_linebreak_in_license.mdwn @@ -0,0 +1,11 @@ +I entered + + <small>this is my license</small> + +into `license.mdwn`, and it shows up as + + License: + this is my license + + +I'd like to remove the line break, ideally also the redundant `License:`. How to do that? diff --git a/doc/forum/How_to_rename_all_markdown_files_from___42__.mdwn_to___42__.md__63__.mdwn b/doc/forum/How_to_rename_all_markdown_files_from___42__.mdwn_to___42__.md__63__.mdwn new file mode 100644 index 000000000..d11f7a3c5 --- /dev/null +++ b/doc/forum/How_to_rename_all_markdown_files_from___42__.mdwn_to___42__.md__63__.mdwn @@ -0,0 +1,3 @@ +Github does not take .mdwn as Markdown files: https://github.com/github/markup/blob/b865add2e053f8cea3d7f4d9dcba001bdfd78994/lib/github/markups.rb#L1 + +I'd like to use filename extensions complaint to GitHub. My question is after renaming all markdown files from *.mdwn to *.md how do I correct all the dependencies? Does simply committing the renamed files to the source repository suffice? diff --git a/doc/forum/How_to_rename_all_markdown_files_from___42__.mdwn_to___42__.md__63__/comment_1_c2720ebfe56ad816f241693d9e2e5072._comment b/doc/forum/How_to_rename_all_markdown_files_from___42__.mdwn_to___42__.md__63__/comment_1_c2720ebfe56ad816f241693d9e2e5072._comment new file mode 100644 index 000000000..c458b5345 --- /dev/null +++ b/doc/forum/How_to_rename_all_markdown_files_from___42__.mdwn_to___42__.md__63__/comment_1_c2720ebfe56ad816f241693d9e2e5072._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="fr33domlover" + ip="85.65.55.38" + subject="comment 1" + date="2014-05-16T08:49:30Z" + content=""" +I don't know, but I remember there's a setting in the setup file which sets the extension for Markdown files. I would create a dummy wiki for tests, where I'd create some files with .md extension and change that setting in the setup file. Then try rebuilding the wiki and see what happens. + +I'm just a user, I don't know beyond that. +"""]] diff --git a/doc/forum/How_to_set_the_meta_author_field_from_user_name__63__.mdwn b/doc/forum/How_to_set_the_meta_author_field_from_user_name__63__.mdwn new file mode 100644 index 000000000..e0d6829fc --- /dev/null +++ b/doc/forum/How_to_set_the_meta_author_field_from_user_name__63__.mdwn @@ -0,0 +1,3 @@ +Several users will post to the same blog. I would like the meta "author" field to be set to their ikiwiki username automatically and attached to their posts such that they can not alter it. I imagine one could use the \<TMPL_VAR USER> variable in the "inlinepage" template, but this variable does not seem to be set. How can I accomplish that? + +Related question: is there a way to see all the variables which are set and their value? diff --git a/doc/forum/How_to_set_the_meta_author_field_from_user_name__63__/comment_1_0906e1f3eb8b826a7730233b95cb5ddd._comment b/doc/forum/How_to_set_the_meta_author_field_from_user_name__63__/comment_1_0906e1f3eb8b826a7730233b95cb5ddd._comment new file mode 100644 index 000000000..2d7c02a8e --- /dev/null +++ b/doc/forum/How_to_set_the_meta_author_field_from_user_name__63__/comment_1_0906e1f3eb8b826a7730233b95cb5ddd._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawnNqLKszWk9EoD4CDCqNXJRIklKFBCN1Ao" + nickname="maurizio" + subject="comment 1" + date="2012-06-22T20:33:59Z" + content=""" +This does not seem to be possible directly according to the discussion here: [[Possible to use meta variables in templates?]]. + +The solution I chose in the end was to set up a template which prepares the meta and suggests the author to fill it in with his user name. Maybe the best way would be to create actually one blog per author, define a template for each author (based on the pagespec and on the lockedpages to constrain authors to write only on their blog) and then an inline page which includes all the individual blogs. +"""]] diff --git a/doc/forum/How_to_set_up_a_page_as_internal__63__.mdwn b/doc/forum/How_to_set_up_a_page_as_internal__63__.mdwn new file mode 100644 index 000000000..ed771292d --- /dev/null +++ b/doc/forum/How_to_set_up_a_page_as_internal__63__.mdwn @@ -0,0 +1,5 @@ +I have a folder with few administrative tasks, like a page showing the comments waiting for moderation. + +There is no link from "normal/public" pages in my site to this administrative pages, but it doesn't prevent the possibility of any person writing down that address in the browser address-bar or finding that address in the browser navigation history. + +Please, is there any way or best-practice restricting the access to this kind of pages? I know that these pages will eventually ask the user to log-in as admin, but I don't want them to see this stuff. diff --git a/doc/forum/How_to_set_up_git_repository_hook___63__.mdwn b/doc/forum/How_to_set_up_git_repository_hook___63__.mdwn new file mode 100644 index 000000000..34bc4ace2 --- /dev/null +++ b/doc/forum/How_to_set_up_git_repository_hook___63__.mdwn @@ -0,0 +1,19 @@ +Hi, + +I want to set up hooks for Git, and I don't know how to. Is there any documentation somewhere? Basically, I'd like to do what [[/ikiwiki-makerepo]] does, but manually. + +Why? Because I want to have a special layout to my repository. Especially, I want to include at the root level some special files: + +- the nginx configuration +- the script that installs the nginx configuration to the system +- the script that starts the fast-cgi wrapper +- the `ikiwiki.setup` file +- ... + +And I want the ikiwiki sources to be in a subdirectory `src/` and the generated files in `out/` (where the nginx configuration points). + +So, what is the special `post-update` hook generated by [[/ikiwiki-makerepo]]? I noticed it was an ELF file, why not a script? What does it do? + +Thanks, + +Mildred diff --git a/doc/forum/How_to_show_recent_changes_for_individual_pages__63__.mdwn b/doc/forum/How_to_show_recent_changes_for_individual_pages__63__.mdwn new file mode 100644 index 000000000..890f24a33 --- /dev/null +++ b/doc/forum/How_to_show_recent_changes_for_individual_pages__63__.mdwn @@ -0,0 +1 @@ +The "RecentChanges" shown under page titles on a individual is linked to the revision history page for the whole site where change to every file in the wiki is listed. Is there a way to get that for individual pages? diff --git a/doc/forum/How_to_show_recent_changes_for_individual_pages__63__/comment_1_cd34affc6883f4e4bc5e7e7b711cc8ba._comment b/doc/forum/How_to_show_recent_changes_for_individual_pages__63__/comment_1_cd34affc6883f4e4bc5e7e7b711cc8ba._comment new file mode 100644 index 000000000..8ed341c09 --- /dev/null +++ b/doc/forum/How_to_show_recent_changes_for_individual_pages__63__/comment_1_cd34affc6883f4e4bc5e7e7b711cc8ba._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + nickname="joey" + subject="comment 1" + date="2012-03-03T15:01:34Z" + content=""" +The RecentChanges page is a wiki page like any other, containing a special inline directive. You can copy that, and modify the inline's [[ikiwiki/PageSpec]] to match pages changed by a specific author, or with a specific title. + +If you want separate change logs for *every* page, install gitweb and configure historyurl. There will then be a \"History\" link going to the gitweb for each page. +"""]] diff --git a/doc/forum/How_to_specify_repository_is_on_a_remote_host__63__.mdwn b/doc/forum/How_to_specify_repository_is_on_a_remote_host__63__.mdwn new file mode 100644 index 000000000..ad8f27252 --- /dev/null +++ b/doc/forum/How_to_specify_repository_is_on_a_remote_host__63__.mdwn @@ -0,0 +1,3 @@ +I'm new to ikiwiki and I'm trying to install it and set it up. I've read the documentation but I still don't understand how access to the repository works. We want ikiwiki to run on one machine but we want the repository to be on a separate machine running svn. How can I configure ikiwiki to access the repository on the remote machine? And how is authentication on the remote host handled in ikiwiki? Does there have to be a one-to-one correspondence between account names (and passwords) on the ikiwiki machine and the accounts on the svn machine? Thanks, + +Eric diff --git a/doc/forum/How_to_specify_repository_is_on_a_remote_host__63__/comment_1_0c71e17ae552cbab1056ac96fbd36c59._comment b/doc/forum/How_to_specify_repository_is_on_a_remote_host__63__/comment_1_0c71e17ae552cbab1056ac96fbd36c59._comment new file mode 100644 index 000000000..954ef0810 --- /dev/null +++ b/doc/forum/How_to_specify_repository_is_on_a_remote_host__63__/comment_1_0c71e17ae552cbab1056ac96fbd36c59._comment @@ -0,0 +1,9 @@ +[[!comment format=mdwn + username="http://adam.shand.net/" + nickname="Adam" + subject="Depending ..." + date="2011-01-25T03:00:12Z" + content=""" +... on exactly what you are trying to do, you may find some answers [[here|forum/how_to_setup_ikiwiki_on_a_remote_host/]]. + +"""]] diff --git a/doc/forum/How_to_specify_repository_is_on_a_remote_host__63__/comment_2_b309302a084fbd8bcd4cd9bd2509cf5a._comment b/doc/forum/How_to_specify_repository_is_on_a_remote_host__63__/comment_2_b309302a084fbd8bcd4cd9bd2509cf5a._comment new file mode 100644 index 000000000..4ceb69474 --- /dev/null +++ b/doc/forum/How_to_specify_repository_is_on_a_remote_host__63__/comment_2_b309302a084fbd8bcd4cd9bd2509cf5a._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + nickname="joey" + subject="here's the scoop .. but, don't do it" + date="2011-01-25T18:30:01Z" + content=""" +To do what you describe, you would set up the svn repository on your server, and then do a regular svn checkout of it to the machine running ikiwiki, and configure ikiwiki to use that directory as its srcdir. The only unix user ikiwiki does anything as is the one you use to set it up, so it's up to you to allow that user to commit to svn without needing to enter a password. + +However, I don't recommend this configuration at all. You're adding a ssh (or webdav) connection overhead to every edit to the wiki, since ikiwiki's commit to svn will have to be pushed across the network to the server. And ikiwiki's svn support is missing many of the [[newer_ikiwiki_features|rcs]], such as including for example support for easily reverting edits. +"""]] diff --git a/doc/forum/How_to_style_main_sidebar_and_SubPage_sidebar_differently_using_CSS__63__.mdwn b/doc/forum/How_to_style_main_sidebar_and_SubPage_sidebar_differently_using_CSS__63__.mdwn new file mode 100644 index 000000000..09cf01435 --- /dev/null +++ b/doc/forum/How_to_style_main_sidebar_and_SubPage_sidebar_differently_using_CSS__63__.mdwn @@ -0,0 +1,13 @@ +How to style main sidebar and SubPage sidebar differently using CSS? + +I have a main sidebar + + /sidebar.mdwn + +and a SubPage sidebar + + /blog/sidebar.mdwn + +How to style the two differently using CSS? + +For example I'd like the sidebar shown on any page inside /blog to have a blue border and any other page outside of /blog to have a sidebar with red border. diff --git a/doc/forum/How_to_suppress_sidebar_for_a_particular_page__63__.mdwn b/doc/forum/How_to_suppress_sidebar_for_a_particular_page__63__.mdwn new file mode 100644 index 000000000..e34a92520 --- /dev/null +++ b/doc/forum/How_to_suppress_sidebar_for_a_particular_page__63__.mdwn @@ -0,0 +1,7 @@ +I normally want to use the sidebar, but for one particular page, if I want to suppress it, how do I do it? + +Putting + + \[[!sidebar content=""""""]] + +into the page source produces a collapsed table which is not ideal. diff --git a/doc/forum/How_to_use___126____47__bin__47__multimarkdown_instead_of_Text::MultiMarkdown.mdwn b/doc/forum/How_to_use___126____47__bin__47__multimarkdown_instead_of_Text::MultiMarkdown.mdwn new file mode 100644 index 000000000..5dadb600d --- /dev/null +++ b/doc/forum/How_to_use___126____47__bin__47__multimarkdown_instead_of_Text::MultiMarkdown.mdwn @@ -0,0 +1,5 @@ +[[!meta author=tjgolubi]] + +I want to configure IkiWiki to use Fletcher Penney's recent version of [[MultiMarkdown|http://fletcherpenney.net/multimarkdown]] instead of the default perl implementation. +I don't know perl, but I think I need to replace the mdwn.pm plugin with something that uses "open2". +Please help me get started. -- [[tjgolubi]] diff --git a/doc/forum/How_to_use_number_as_bullet_labels_but_not_letter_in_toc_plugin.mdwn b/doc/forum/How_to_use_number_as_bullet_labels_but_not_letter_in_toc_plugin.mdwn new file mode 100644 index 000000000..dd77e9441 --- /dev/null +++ b/doc/forum/How_to_use_number_as_bullet_labels_but_not_letter_in_toc_plugin.mdwn @@ -0,0 +1,8 @@ +I am using toc plugin, and it gives me + + 1. Section1 + 2. Section2 + a. subsection21 + b. subsection22 + +How do I make a. and b. as 2.1 and 2.2, respectively? diff --git a/doc/forum/Howto_add_tag_from_plugin_code.mdwn b/doc/forum/Howto_add_tag_from_plugin_code.mdwn new file mode 100644 index 000000000..a17faf727 --- /dev/null +++ b/doc/forum/Howto_add_tag_from_plugin_code.mdwn @@ -0,0 +1,12 @@ +Hi, I want to add tags to some pages automatically (generating album images +and want to tag all generated pages). I managed to do so in following way: + + IkiWiki::Plugin::tag::preprocess_tag( + page => $viewer, + destpage => $params{destpage}, + map { ($_ => 1) } @tags, + ); + +This works, however if some tag does not exist, it is not created. I tracked it so far that I found that the Render.pm's method gen_autofile() is not called , so it is most likely that I need to somehow trigger Render.pm's refresh()...but how can I do it? + +BTW: The code is modified album plugin that is in [my git](https://github.com/llipavsky/ikiwiki) diff --git a/doc/forum/Howto_add_tag_from_plugin_code/comment_1_c61454825874a6fe1905cb549386deb0._comment b/doc/forum/Howto_add_tag_from_plugin_code/comment_1_c61454825874a6fe1905cb549386deb0._comment new file mode 100644 index 000000000..2122083ec --- /dev/null +++ b/doc/forum/Howto_add_tag_from_plugin_code/comment_1_c61454825874a6fe1905cb549386deb0._comment @@ -0,0 +1,77 @@ +[[!comment format=mdwn + username="http://smcv.pseudorandom.co.uk/" + nickname="smcv" + subject="comment 1" + date="2013-07-01T09:13:51Z" + content=""" +(If you want to branch from my version of album, please add my git repo +as a remote and merge or cherry-pick the album4 branch: pasting from my +gitweb seems to have given you some incorrect UTF-8.) + +The problem you have here is that for this plugin, the correct order +for IkiWiki to do things is quite subtle. Am I right in thinking that +the feature you want goes something like this? + +> To add a set of tags to every \"viewer\" page in the album, you can add +> the tags parameter to the album: +> +> \[[!album tags=\"holiday hawaii\"]] +> +> The individual viewers will all be tagged \"holiday\" and \"hawaii\", +> for instance. These tags cannot be removed by editing the viewers. + +`preprocess_albumimage` runs twice: once in the scan stage, and once in +the render stage. In the render stage, it's too late to add tags, because +tags are a special form of [[ikiwiki/wikilinks]], and wikilinks have to +be added during the scan stage to work correctly. + +The part of `preprocess_albumimage` after the line +`return unless defined wantarray;` only runs in the render stage, which +is too late. You'd need to set up the tags further up: just after the +calls to `IkiWiki::Plugin::meta::preprocess` would be a good place. + +I would also suggest checking for +`IkiWiki::Plugin::tag->can('preprocess_tag')`, +like I do for meta - if you do that, you won't need to force the tag plugin +to be loaded. + +Unfortunately, I'm still not sure that this is fully correct. Pages +are scanned in a random order. If the `\[[!album]]` is scanned before +a \"viewer\" page, then everything is fine: the tags are present when +the \"viewer\" is scanned. However, if the \"viewer\" is scanned first, +then it will get the tags that the `\[[!album]]` had in the *previous* +IkiWiki run (if any), which are still in the index, because the +`\[[!album]]` hasn't been re-scanned yet... + +Are you sure this form of the feature is what you want? You'll end up with +a *lot* of pages with those tags. If it's what you want, it might be +clearer how it works if you changed the syntax to something like this, +perhaps? + +> +> \[[!album tag_all=\"holiday hawaii\"]] + +Another possible syntax would be to have the feature be more like this: + +> If you use the `tag_default` parameter to the `\[[!album]]` directive, +> each \"viewer\" page created for images will have those tags by +> default. Changing the `\[[!album]]` will not affect any \"viewer\" +> pages that have already been created, and editing the \"viewer\" +> can add or remove those default tags. +> +> \[[!album tag_default=\"holiday hawaii\"]] + +which I think removes the ordering problems? If you go this route, +you'd want to either add e.g. `[[!tag holiday hawaii]]` +to the generated viewer page in `create_viewer`, or add a `tag` +parameter to `\[[!albumimage]]` that's a shortcut for the +tag directive, in the same way that author is a shortcut for +`[[!meta author]]`). + +The purpose of the \"shortcut\" parameters in `\[[!albumimage]]`, +like title, author and date, is that I eventually want to add +a specialized CGI interface to this plugin so you can edit +all the images of an album in one go; when I add that, +it'll probably only be able to process something as +machine-readable as `\[[!albumimage]]`. +"""]] diff --git a/doc/forum/I_do_not_know_anything_abut_git.mdwn b/doc/forum/I_do_not_know_anything_abut_git.mdwn new file mode 100644 index 000000000..31358bbb1 --- /dev/null +++ b/doc/forum/I_do_not_know_anything_abut_git.mdwn @@ -0,0 +1,22 @@ +I want to learn how to use a text editor in addition to the web interface. I am stuck on pushing changes back to where they're supposed to go. + +I have done: + + git clone Zoidwicky.git Zoidwicky.src + +and then, after editing sidebar.mdwn in that new Zoidwicky.src directory + + git commit sidebar.mdwn + +Now I believe I must use git push to move that change to I am not sure where. + +I learn best by example. Would someone be good enough to post an example of what that 'git push" command might look like? + +Here are some samples of what I have tried: + + $ git push sidebar.mdwn Zoidwicky.git + fatal: Invalid gitfile format: sidebar.mdwn + + $ git push sidebar.mdwn /home/zoid/Zoidwicky.git/ + fatal: remote part of refspec is not a valid name in /home/zoidberg/Zoidwicky.git + diff --git a/doc/forum/I_do_not_know_anything_abut_git/comment_1_2efdf8563bcdeba73b11282157aba72d._comment b/doc/forum/I_do_not_know_anything_abut_git/comment_1_2efdf8563bcdeba73b11282157aba72d._comment new file mode 100644 index 000000000..7649feece --- /dev/null +++ b/doc/forum/I_do_not_know_anything_abut_git/comment_1_2efdf8563bcdeba73b11282157aba72d._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="http://kerravonsen.dreamwidth.org/" + ip="203.206.140.235" + subject="comment 1" + date="2014-05-24T23:30:43Z" + content=""" +Just use \"git push\" without any arguments at all. + + git push +"""]] diff --git a/doc/forum/I_do_not_know_anything_abut_git/comment_2_3dd0fa0612a5fac785cc7d5ea23d42a5._comment b/doc/forum/I_do_not_know_anything_abut_git/comment_2_3dd0fa0612a5fac785cc7d5ea23d42a5._comment new file mode 100644 index 000000000..18617ac9e --- /dev/null +++ b/doc/forum/I_do_not_know_anything_abut_git/comment_2_3dd0fa0612a5fac785cc7d5ea23d42a5._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://bob-bernstein.myopenid.com/" + nickname="bernstein" + subject="comment 2" + date="2014-05-25T03:39:41Z" + content=""" +Ah. That is simple enough even for me! Thank you so much! +"""]] diff --git a/doc/forum/If_there__39__s_no_Windows_ikiwiki__44___how_about_a_WYSIWYG_ikiwiki_editor_for_Windows__63__.mdwn b/doc/forum/If_there__39__s_no_Windows_ikiwiki__44___how_about_a_WYSIWYG_ikiwiki_editor_for_Windows__63__.mdwn new file mode 100644 index 000000000..e23d3fddf --- /dev/null +++ b/doc/forum/If_there__39__s_no_Windows_ikiwiki__44___how_about_a_WYSIWYG_ikiwiki_editor_for_Windows__63__.mdwn @@ -0,0 +1,14 @@ +Since ikiwiki doesn't have much of a chance of working in windows, how about we compromise by making an offline ikiwiki editor for Windows? In fact, it might be advantageous to use it in Linux, too... + +It should be very simple: It would enter the source wiki and show the Markdown code by default, but would have an option to preview your page in another tab. + +Basic features: + +* wikilinks, maps, images, inlinepages, and other basic functions should all work in the preview +* perhaps use local.css to format preview +* See the DVCS history with diffs and all +* have a discussion tab to easily see what other people have said about the page + +If we want to add some more bells and whistles, maybe we could throw in some buttons to insert markdown formatting (like in forums, mediawiki, or RES). + +Any thoughts on this? diff --git a/doc/forum/If_there__39__s_no_Windows_ikiwiki__44___how_about_a_WYSIWYG_ikiwiki_editor_for_Windows__63__/comment_1_a66fd9d7ab4359784a5420cd899a1057._comment b/doc/forum/If_there__39__s_no_Windows_ikiwiki__44___how_about_a_WYSIWYG_ikiwiki_editor_for_Windows__63__/comment_1_a66fd9d7ab4359784a5420cd899a1057._comment new file mode 100644 index 000000000..20fd763e2 --- /dev/null +++ b/doc/forum/If_there__39__s_no_Windows_ikiwiki__44___how_about_a_WYSIWYG_ikiwiki_editor_for_Windows__63__/comment_1_a66fd9d7ab4359784a5420cd899a1057._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://kerravonsen.dreamwidth.org/" + ip="202.173.183.92" + subject="comment 1" + date="2012-01-13T22:32:47Z" + content=""" +It would probably be quite complex to write, and difficult to maintain. I don't think much of your chances of getting someone to write it. If you want to write it yourself, have fun doing so! +"""]] diff --git a/doc/forum/If_there__39__s_no_Windows_ikiwiki__44___how_about_a_WYSIWYG_ikiwiki_editor_for_Windows__63__/comment_2_3351ff773fea3f640f4036bb8c7c7efd._comment b/doc/forum/If_there__39__s_no_Windows_ikiwiki__44___how_about_a_WYSIWYG_ikiwiki_editor_for_Windows__63__/comment_2_3351ff773fea3f640f4036bb8c7c7efd._comment new file mode 100644 index 000000000..b83042c36 --- /dev/null +++ b/doc/forum/If_there__39__s_no_Windows_ikiwiki__44___how_about_a_WYSIWYG_ikiwiki_editor_for_Windows__63__/comment_2_3351ff773fea3f640f4036bb8c7c7efd._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawkr8GVPw30JBR34Btg-SKcS8gxEf7zpSJQ" + nickname="Lawrence" + subject="comment 2" + date="2012-01-14T03:14:38Z" + content=""" +Eh, ok, lol. I know that implementing most of the wiki features over again could be difficult, and so would a Git diff reader, but it shouldn't be that hard to get Wikilinking or a markdown previewer working. + +Could you point out some specific problems of this approach, so that it would help me out to do so? +"""]] diff --git a/doc/forum/If_there__39__s_no_Windows_ikiwiki__44___how_about_a_WYSIWYG_ikiwiki_editor_for_Windows__63__/comment_3_273b2b63a9af2bc4eeb030e026436687._comment b/doc/forum/If_there__39__s_no_Windows_ikiwiki__44___how_about_a_WYSIWYG_ikiwiki_editor_for_Windows__63__/comment_3_273b2b63a9af2bc4eeb030e026436687._comment new file mode 100644 index 000000000..e5eaf2c4c --- /dev/null +++ b/doc/forum/If_there__39__s_no_Windows_ikiwiki__44___how_about_a_WYSIWYG_ikiwiki_editor_for_Windows__63__/comment_3_273b2b63a9af2bc4eeb030e026436687._comment @@ -0,0 +1,12 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawkr8GVPw30JBR34Btg-SKcS8gxEf7zpSJQ" + nickname="Lawrence" + subject="comment 3" + date="2012-01-14T17:41:52Z" + content=""" +Like, there's already a whole host of Markdown previewer apps that are pretty good. [Here's a](http://www.macworld.com/article/164744/2012/01/marked_excels_at_previewing_markdown_and_html_documents.html) popular one on Mac, and there are many more... + +There's also a plugin for Emacs that does so, and even resolves wikilinks (in some way..). + +But I'd have to say that I probably made a misleading title, WYSIWYG would probably be low on the list of needed features. And I'm just dumping an idea I have here in case anyone has any suggestions or comments, I'll probably do it myself in my free time. +"""]] diff --git a/doc/forum/If_there__39__s_no_Windows_ikiwiki__44___how_about_a_WYSIWYG_ikiwiki_editor_for_Windows__63__/comment_4_546771c13ea1b550301586e187d82cb5._comment b/doc/forum/If_there__39__s_no_Windows_ikiwiki__44___how_about_a_WYSIWYG_ikiwiki_editor_for_Windows__63__/comment_4_546771c13ea1b550301586e187d82cb5._comment new file mode 100644 index 000000000..472417457 --- /dev/null +++ b/doc/forum/If_there__39__s_no_Windows_ikiwiki__44___how_about_a_WYSIWYG_ikiwiki_editor_for_Windows__63__/comment_4_546771c13ea1b550301586e187d82cb5._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawndsaC4GaIBw49WNdbk2Faqfm_mrtQgul8" + nickname="Christian" + subject="just my 2 cents" + date="2012-01-17T11:10:09Z" + content=""" +why? +"""]] diff --git a/doc/forum/Ikiwiki_CGI_not_working_on_my_server__44___and_it__39__s_a_binary_file__63__.mdwn b/doc/forum/Ikiwiki_CGI_not_working_on_my_server__44___and_it__39__s_a_binary_file__63__.mdwn new file mode 100644 index 000000000..35db20dc8 --- /dev/null +++ b/doc/forum/Ikiwiki_CGI_not_working_on_my_server__44___and_it__39__s_a_binary_file__63__.mdwn @@ -0,0 +1,33 @@ +Hey, trying to get ikiwiki working on my account on a shared webserver. Actually installing ikiwiki on the server is phase 2. For now I'm running the latest ikiwiki (from source) locally, compiling the output with the ikiwiki command, then rsyncing the output dir up to the server. This works for the static HTML files, but the CGI file doesn't work, the server redirects to an error page. The error log on the server says "Premature end of script headers: /path/to/ikiwiki.cgi" + +My first thought was that this is a Perl CGI and I would need to change the shebang to point to the unusual location of Perl on this server, it's at /usr/pkg/bin/perl. But when I looked at ikiwiki.cgi I found it was a binary file. + +Why is it a binary? And what can I do about this error? + +> It's a binary because it's SUID, so that it has permission to write to the ikiwiki repository. See [[security]], under 'suid wrappers', for more on that. +> +> As to why you get 'premature end of script headers', that suggests there is a problem running +> the script (and there is output occurring before the HTTP headers are printed). Do you have access +> to the webserver logs for your host? They might contain some clues. Are you sure that the webserver +> is setup for CGI properly? -- [[Jon]] + +> Quite likely your laptop and your server do not run the same +> OS, so the wrapper binary cannot just be copied from one +> to the other and run. Also, the wrapper is just that, a +> thin wrapper which then runs ikiwiki. As ikiwiki is not +> yet installed on your server, that's another reason what +> you're trying can't work. +> +> If installing ikiwiki on the server is not possible or +> too much work right now, you could try building your wiki +> on your laptop with cgi disabled in the setup file. +> The result would be a static website that you could deploy to +> the server this way. Of course, it wouldn't be editable +> on the server, and other features that need the CGI would +> also be disabled. --[[Joey]] + +> > Ah, ok thanks. Yes the server runs a different OS and ikiwiki +> > is not installed on it. I've got it working as a static site, +> > so if I want the CGI I'll have to install ikiwiki on the server. +> > Ok. It might not work as I don't have root access, but I might +> > give it a try. Thanks diff --git a/doc/forum/Ikiwiki_themes_for_mobile_devices__63__.mdwn b/doc/forum/Ikiwiki_themes_for_mobile_devices__63__.mdwn new file mode 100644 index 000000000..dc1b31cd8 --- /dev/null +++ b/doc/forum/Ikiwiki_themes_for_mobile_devices__63__.mdwn @@ -0,0 +1,7 @@ +Has anyone else created ikiwiki themes for mobile devices like phones and tablets? + +I've been using Blueview theme for a few years and finally tried to adapt the theme for my phone. +My local.css is [here](http://mcfrisk.kapsi.fi/local.css), and my hobby web page full of images and videos [here](http://mcfrisk.kapsi.fi/skiing/). + +Previously I also had problems like wasted screen space, big minimum width and images not scaled down to the CSS element. Those got fixed as well. +Would be nice if others could test that and maybe share their setups. diff --git a/doc/forum/Include_attachment_in_a_page.mdwn b/doc/forum/Include_attachment_in_a_page.mdwn new file mode 100644 index 000000000..e4a5a53ec --- /dev/null +++ b/doc/forum/Include_attachment_in_a_page.mdwn @@ -0,0 +1,9 @@ +Is there any way of embedding an attachment in a page - like, when I upload a picture, I would like to have it showing on a page.... I tried the Markdown image syntax like this: + + ![Alt text](/path/to/img.jpg "Optional title") + +But if you upload a PDF, f.ex., there will be a "broken URL/no image" thumbnail, although the link to the uploaded file works correctly, if entered correctly. + +So if it's just an image I want to embed, then I would want to use HTML syntax directly, I guess. (Like stated [[here|http://daringfireball.net/projects/markdown/syntax#img]].) But in case it's some other type of attachment it would be nice to be able to have some specific include syntax or the like. + +Probably a feature for the "attachment" plugin's wishlist!? diff --git a/doc/forum/Include_attachment_in_a_page/comment_1_275aad6ca3b2972749b7f6636b130035._comment b/doc/forum/Include_attachment_in_a_page/comment_1_275aad6ca3b2972749b7f6636b130035._comment new file mode 100644 index 000000000..a6f995626 --- /dev/null +++ b/doc/forum/Include_attachment_in_a_page/comment_1_275aad6ca3b2972749b7f6636b130035._comment @@ -0,0 +1,12 @@ +[[!comment format=mdwn + username="http://jmtd.net/" + nickname="Jon Dowland" + subject="comment 1" + date="2012-04-02T12:51:33Z" + content=""" +Forgive me if I don't fully understand the question, but: + + * the attachment functionality includes a button \"Insert Links\" which, on the edit form for a page, inserts the correct markup to link to the attachment, which addresses the general case + + * For images which you want inline, you could convert the basic wikilink e.g. `\[[foo.png]]` into a call to the [[plugins/img]] plugin e.g. `\[[!img foo.png]]` +"""]] diff --git a/doc/forum/Is_it_possible_to_change_default_mdwn_suffix__63__.mdwn b/doc/forum/Is_it_possible_to_change_default_mdwn_suffix__63__.mdwn new file mode 100644 index 000000000..6a1059d48 --- /dev/null +++ b/doc/forum/Is_it_possible_to_change_default_mdwn_suffix__63__.mdwn @@ -0,0 +1 @@ +I usually use .md as a Markdown file extension. I know other people use .txt. Is there any way to modify ikiwiki setup to accept this as the suffix for Markdown pages (instead of .mdwn)? diff --git a/doc/forum/Is_it_possible_to_change_default_mdwn_suffix__63__/comment_1_2a449c6017ecdb4f557963266fb4ec41._comment b/doc/forum/Is_it_possible_to_change_default_mdwn_suffix__63__/comment_1_2a449c6017ecdb4f557963266fb4ec41._comment new file mode 100644 index 000000000..da6377607 --- /dev/null +++ b/doc/forum/Is_it_possible_to_change_default_mdwn_suffix__63__/comment_1_2a449c6017ecdb4f557963266fb4ec41._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + nickname="joey" + subject="comment 1" + date="2011-05-20T14:12:38Z" + content=""" +It's fairly easy to make a copy of the mdwn plugin and s/mdwn/foo/ in it and get what you want. But I don't see value in providing this option in ikiwiki as it just reduces interoperability. Not all options are good options, and this would be a bad one. +"""]] diff --git a/doc/forum/Is_there_a_pagespec_for_creation_dates_relative_to_today__63__.mdwn b/doc/forum/Is_there_a_pagespec_for_creation_dates_relative_to_today__63__.mdwn new file mode 100644 index 000000000..53c70e50a --- /dev/null +++ b/doc/forum/Is_there_a_pagespec_for_creation_dates_relative_to_today__63__.mdwn @@ -0,0 +1,26 @@ +Dear users, + + +using the directive inline, I want to show all pages (for example named 2008.10.2:foo.mdwn or 2009.12.3:bar.mdwn), whose date in the title are in the future. So in this example only the second one. + +I did not find a directive doing this in [[/ikiwiki/PageSpec]]. + +Does somebody have an idea? I just came up with using a tag “recent” or using a separate folder. But this would be a quite some work to maintain this setup. + + +Thanks, + +Paul + +> There's no such pagespec, and doing one is difficult, because such a +> pagespec will change what it matches over time. So ikiwiki would have to +> somehow figure out that pages matched by it yesterday no longer match, +> and that pages containing the pagespec need to be rebuilt. Which means +> you'd also need a cron job. + +>> Thank you for the explanation. + +> I suspect what you're trying to accomplish is +> [[todo/tagging_with_a_publication_date]]? --[[Joey]] + +>> Yeah, something like that. Thanks! --[[PaulePanter]] diff --git a/doc/forum/LaTeX_Error.mdwn b/doc/forum/LaTeX_Error.mdwn new file mode 100644 index 000000000..587baec6c --- /dev/null +++ b/doc/forum/LaTeX_Error.mdwn @@ -0,0 +1,66 @@ +Greetings. + +I am put this code in one page: +[[!teximg code="\frac{1}{5}" alt="1/5"]] + +this is the configuration file ikiwiki.info: + +add_plugins => [qw{sidebar goodstuff textile html htmlscrubber table pagetemplate teximg map meta anonok img version textile txt}] + + *Here the log* + +This is pdfTeXk, Version 3.141592-1.40.3 (Web2C 7.5.6) (format=latex 2008.8.4) 5 AUG 2008 10:01 +entering extended mode + %&-line parsing enabled. +**/tmp/fb7742f8dd0c66473643ba40592e2be2.SBQfJo94ii/fb7742f8dd0c66473643ba40592e +2be2.tex + +(/tmp/fb7742f8dd0c66473643ba40592e2be2.SBQfJo94ii/fb7742f8dd0c66473643ba40592e2 +be2.tex + +[...] + +Package scrkbase Info: You've used the obsolete option `12pt'. +(scrkbase) \KOMAoptions{fontsize=12pt} will be used instead. +(scrkbase) You should do this change too on input line 594. + +[...] + +! LaTeX Error: File `mhchem.sty' not found. + +Type X to quit or <RETURN> to proceed, +or enter new name. (Default extension: sty) + +Enter file name: +! Emergency stop. +<read *> + +l.1 ...l}\usepackage[version=3]{mhchem}\usepackage + + {amsmath}\usepackage{amsfo... + +(cannot \read from terminal in nonstop modes) + + +Here is how much of TeX's memory you used: + 761 strings out of 94074 + 10268 string characters out of 1167096 + 66007 words of memory out of 1500000 + 4120 multiletter control sequences out of 10000+50000 + 3938 words of font info for 15 fonts, out of 1200000 for 2000 + 645 hyphenation exceptions out of 8191 + 30i,1n,28p,410b,45s stack positions out of 5000i,500n,6000p,200000b,10000s +No pages of output. + + +Some idea ?. + +>> It looks like teximg uses some less standard LaTeX packages. (see line 100 of Ikiwiki/Plugin/teximg.pm in the Ikiwiki source.) +>> A quick work-around for an end-user would be to install the 'mhchem' LaTeX package (look in [CTAN](http://www.ctan.org/) ). +>> A medium-term workaround would be to replace 'scrartcl' on line 100 with 'article', and delete line 101 in the teximg source. +>> Longer term it would be nice to give teximg a configurable preamble. +>> Hrm - maybe that configurable preamble should be a [[todo]]? -- [[users/Will]] + +>>>Yes it works. Thanks. I am writing some code for examples. + + diff --git a/doc/forum/Last_visited_pages.mdwn b/doc/forum/Last_visited_pages.mdwn new file mode 100644 index 000000000..ae87cf177 --- /dev/null +++ b/doc/forum/Last_visited_pages.mdwn @@ -0,0 +1 @@ +Is it possible to add a list of the n last visited pages on the bottom of each ikiwiki page (or maybe on a sidebar)? diff --git a/doc/forum/Last_visited_pages/comment_1_e34650064dd645b35da98e80c0311df9._comment b/doc/forum/Last_visited_pages/comment_1_e34650064dd645b35da98e80c0311df9._comment new file mode 100644 index 000000000..c5e2cc8ad --- /dev/null +++ b/doc/forum/Last_visited_pages/comment_1_e34650064dd645b35da98e80c0311df9._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://kerravonsen.dreamwidth.org/" + ip="202.173.183.92" + subject="comment 1" + date="2011-11-27T11:09:55Z" + content=""" +Only if you could do it with JavaScript or SSI; remember IkiWiki is a wiki *compiler* - all the pages are generated beforehand, their content remains the same no matter what your visitor is doing. +"""]] diff --git a/doc/forum/Last_visited_pages/comment_2_2a0c4e844da1deaa2c286e87c8eab84d._comment b/doc/forum/Last_visited_pages/comment_2_2a0c4e844da1deaa2c286e87c8eab84d._comment new file mode 100644 index 000000000..c5e90752d --- /dev/null +++ b/doc/forum/Last_visited_pages/comment_2_2a0c4e844da1deaa2c286e87c8eab84d._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawk_MMtLPS7osC5MjX00q2ATjvvXPWqm0ik" + nickname="micheal" + subject="comment 2" + date="2011-11-27T12:23:31Z" + content=""" +How to to it with JavaScript OR SSI? +"""]] diff --git a/doc/forum/Link_to_a_local_pdf_file.mdwn b/doc/forum/Link_to_a_local_pdf_file.mdwn new file mode 100644 index 000000000..61d6829a0 --- /dev/null +++ b/doc/forum/Link_to_a_local_pdf_file.mdwn @@ -0,0 +1 @@ +How can I make a link to a local file (for example a pdf file) in ikiwiki? diff --git a/doc/forum/Link_to_a_local_pdf_file/comment_1_b6c57588042373f8e1f187041c1a8530._comment b/doc/forum/Link_to_a_local_pdf_file/comment_1_b6c57588042373f8e1f187041c1a8530._comment new file mode 100644 index 000000000..b8dc275f5 --- /dev/null +++ b/doc/forum/Link_to_a_local_pdf_file/comment_1_b6c57588042373f8e1f187041c1a8530._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + nickname="joey" + subject="comment 1" + date="2011-08-05T21:09:21Z" + content=""" +Typically this is done using standard markdown html linking. +"""]] diff --git a/doc/forum/Log_in_error.mdwn b/doc/forum/Log_in_error.mdwn new file mode 100644 index 000000000..b9281f90f --- /dev/null +++ b/doc/forum/Log_in_error.mdwn @@ -0,0 +1,5 @@ +When i login my Ikiwiki instance using Google, it issues error + + url_fetch_error: Error fetching URL: Internal Server Error + +then fail. How to fix it? diff --git a/doc/forum/Log_in_error/comment_1_0ef13ea01a413160d81951636c15c3e6._comment b/doc/forum/Log_in_error/comment_1_0ef13ea01a413160d81951636c15c3e6._comment new file mode 100644 index 000000000..df36f9e72 --- /dev/null +++ b/doc/forum/Log_in_error/comment_1_0ef13ea01a413160d81951636c15c3e6._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + nickname="joey" + subject="comment 1" + date="2011-08-05T20:54:02Z" + content=""" +This error suggests that ikiwiki's attempt to contact google to check your openid is failing. + +What version on [[!cpan Openid::Consumer]] is that? Version 1.03 has a slightly different error message, perhaps you have an old version that is somehow broken. +"""]] diff --git a/doc/forum/Map_Plugin__44___would_like_to_add___63__updated_to_all_links.mdwn b/doc/forum/Map_Plugin__44___would_like_to_add___63__updated_to_all_links.mdwn new file mode 100644 index 000000000..fcffe690f --- /dev/null +++ b/doc/forum/Map_Plugin__44___would_like_to_add___63__updated_to_all_links.mdwn @@ -0,0 +1,3 @@ +Map Plugin, would like to add ?updated to all links created. + +When I edit a page and then click that page in a map in a sidebar Safari always shows me a cached page. diff --git a/doc/forum/Map_Plugin__44___would_like_to_add___63__updated_to_all_links/comment_1_3fe4c5967e704355f9b594aed46baf67._comment b/doc/forum/Map_Plugin__44___would_like_to_add___63__updated_to_all_links/comment_1_3fe4c5967e704355f9b594aed46baf67._comment new file mode 100644 index 000000000..ce1a78584 --- /dev/null +++ b/doc/forum/Map_Plugin__44___would_like_to_add___63__updated_to_all_links/comment_1_3fe4c5967e704355f9b594aed46baf67._comment @@ -0,0 +1,13 @@ +[[!comment format=mdwn + username="justint" + ip="24.182.207.250" + subject="skip it" + date="2010-10-13T05:30:50Z" + content=""" +skip it, I added + + <meta http-equiv=\"expires\" value=\"Thu, 16 Mar 2000 11:00:00 GMT\" /> + <meta http-equiv=\"pragma\" content=\"no-cache\" /> + +to my page.tmpl and the problem went away. +"""]] diff --git a/doc/forum/Migrated_ikiwiki_to_new_host._Web_page_is_not_updated.mdwn b/doc/forum/Migrated_ikiwiki_to_new_host._Web_page_is_not_updated.mdwn new file mode 100644 index 000000000..b659212b6 --- /dev/null +++ b/doc/forum/Migrated_ikiwiki_to_new_host._Web_page_is_not_updated.mdwn @@ -0,0 +1,27 @@ +I copied ikiwiki from old host to new. Old is Debian GNU/Linux version 5.0.7, with ikiwiki 3.1415926~bpo50+1 +New host is 5.0.8 with ikiwiki 3.20100815~bpo50+1 + +I have ikiwiki.setup and both GIT repos from old host, src and src.git, the latter is bare repo. + +I suspect I have messed up things in the old host, since the src directory tree is much larger than the src.git. +tale@tugelbend:~/wiki$ du -sh src src.git/ +8,3M src +2,6M src.git/ + +If I clone the src.git to the new host, I get after ikiwiki --setup web pages from year 2009. So I did the migration like this: + +Copy the src directory to the new host to temp dir; git clone --bare /tmp/Foo/src ~/wiki/wiki.git +cd ~/wiki +git clone wiki.git wiki.src +cd .. +ikiwiki --setup ikiwiki.setup + +I believe I have modified the ikiwiki.setup file correctly, I get no error messages and it makes the web page with the +same content as on old host. But when I git clone wiki.git a working copy for myself, and edit it, git commit -a ; git push +I am sad to see the web page is not updated. + +How can I see what is wrong? The hook seems OK: +taleman@porixi:~/wiki$ ls -lh wiki.git/hooks/post-update +-rwsr-sr-x 1 taleman taleman 14K 23.12. 17:42 wiki.git/hooks/post-update + +ikiwiki --setup created that and did not claim any errors. diff --git a/doc/forum/Migrated_ikiwiki_to_new_host._Web_page_is_not_updated/comment_2_b44a492c7f10395a31f3c0830ef33f0c._comment b/doc/forum/Migrated_ikiwiki_to_new_host._Web_page_is_not_updated/comment_2_b44a492c7f10395a31f3c0830ef33f0c._comment new file mode 100644 index 000000000..576d11f0b --- /dev/null +++ b/doc/forum/Migrated_ikiwiki_to_new_host._Web_page_is_not_updated/comment_2_b44a492c7f10395a31f3c0830ef33f0c._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + nickname="joey" + subject="comment 2" + date="2011-12-25T00:07:28Z" + content=""" +Try running the post-update hook by hand and see if it pulls the changes into ~/wiki/wiki.src and see if it updates the site. + +Make sure `gitorigin_branch` is set in the setup file. +"""]] diff --git a/doc/forum/Migrated_ikiwiki_to_new_host._Web_page_is_not_updated/comment_2_f9240b217b2d1ee8d51dada9cb1186b3._comment b/doc/forum/Migrated_ikiwiki_to_new_host._Web_page_is_not_updated/comment_2_f9240b217b2d1ee8d51dada9cb1186b3._comment new file mode 100644 index 000000000..635aa9340 --- /dev/null +++ b/doc/forum/Migrated_ikiwiki_to_new_host._Web_page_is_not_updated/comment_2_f9240b217b2d1ee8d51dada9cb1186b3._comment @@ -0,0 +1,28 @@ +[[!comment format=mdwn + username="https://launchpad.net/~tale" + nickname="tale" + subject="comment 2" + date="2011-12-27T16:18:31Z" + content=""" +In both old and new host gitorigin_branch is empty string in ikiwiki.setup. + + tale@tugelbend:~$ grep -i gitorigin ikiwiki.setup + gitorigin_branch => '', + +The branches subdir is empty on both hosts: + + tale@tugelbend:~$ LANG=C ls -lha wiki/src.git/branches/ + total 8.0K + drwxr-xr-x 2 tale tale 4.0K Dec 24 2009 . + drwxr-xr-x 7 tale tale 4.0K Dec 24 2009 .. + tale@tugelbend:~$ + +I do not know what value I should assign to gitorigin_branch. + +I tried + + wiki.git/hooks/post-update + +but nothing seems to happen. No output, web page stays the same. File timestamps are not updated +on the dest directory. +"""]] diff --git a/doc/forum/Migrated_ikiwiki_to_new_host._Web_page_is_not_updated/comment_3_c3c5c41a4c220793c6d16f3fd6132272._comment b/doc/forum/Migrated_ikiwiki_to_new_host._Web_page_is_not_updated/comment_3_c3c5c41a4c220793c6d16f3fd6132272._comment new file mode 100644 index 000000000..f845f130f --- /dev/null +++ b/doc/forum/Migrated_ikiwiki_to_new_host._Web_page_is_not_updated/comment_3_c3c5c41a4c220793c6d16f3fd6132272._comment @@ -0,0 +1,15 @@ +[[!comment format=mdwn + username="https://launchpad.net/~tale" + nickname="tale" + subject="Editing via browser works" + date="2011-12-27T18:47:16Z" + content=""" +I now set up virtual host in apache2 and fudged the ipnumber to correspond to hostnames the ikiwiki uses. I do not want to update DNS before I have checked the site works. + +Now I can log in using OpenID and edit the wiki via browser. This time the web pages are updated and the changes I made appear in the wiki. + +I cheched the gitorigin_branch setting was empty string even in 2009 when I got this wiki. I begin to suspect editing the wiki using a git checkout would not work even in the host the ikiwiki is currently running on, and maybe did not work in the host it was running on in 2009. + +It looks to me like ikiwiki is working on this new host except git configuration is somehow messed up. It is possible I never did use git checkout on the old host. + +"""]] diff --git a/doc/forum/Migrated_ikiwiki_to_new_host._Web_page_is_not_updated/comment_4_1f6f9e3939a454c1eb8d2fb29bd519de._comment b/doc/forum/Migrated_ikiwiki_to_new_host._Web_page_is_not_updated/comment_4_1f6f9e3939a454c1eb8d2fb29bd519de._comment new file mode 100644 index 000000000..1a5a91466 --- /dev/null +++ b/doc/forum/Migrated_ikiwiki_to_new_host._Web_page_is_not_updated/comment_4_1f6f9e3939a454c1eb8d2fb29bd519de._comment @@ -0,0 +1,16 @@ +[[!comment format=mdwn + username="https://launchpad.net/~tale" + nickname="tale" + subject="Checked old host, git messed up there, too" + date="2011-12-27T18:59:38Z" + content=""" +I did + git clone src.git +on the host ikiwiki is currently running on, and got an old version of the wiki, not the one that is diplayed on the web page. + +So even there editing via browser works, but git checks out an old version and the changes I make do not get shown on the web page after git push. + +This new host I set up is thus no worse, actually slighty better now because git clone at least gets me the sources the web pages are generated from. + +How to figure out what is wrong with ikiwiki setup in the using git part? +"""]] diff --git a/doc/forum/Migrated_ikiwiki_to_new_host._Web_page_is_not_updated/comment_5_8611fc62797e70a0d2a61d94fcb03170._comment b/doc/forum/Migrated_ikiwiki_to_new_host._Web_page_is_not_updated/comment_5_8611fc62797e70a0d2a61d94fcb03170._comment new file mode 100644 index 000000000..137c198cc --- /dev/null +++ b/doc/forum/Migrated_ikiwiki_to_new_host._Web_page_is_not_updated/comment_5_8611fc62797e70a0d2a61d94fcb03170._comment @@ -0,0 +1,22 @@ +[[!comment format=mdwn + username="https://launchpad.net/~tale" + nickname="tale" + subject="branch = master, still no luck" + date="2011-12-28T03:22:57Z" + content=""" +I learned from docs setting gitorigin_branch to empty string disables git pushing and pulling. So guessing + +gitorigin_branch => 'master', + +seemed a good idea. + +However, now ikiwiki -setup gives: + + taleman@porixi:~$ ikiwiki -setup ikiwiki.setup + successfully generated /var/www/ikiwiki/debian.fi/ikiwiki.cgi + successfully generated /home/taleman/wiki/wiki.git/hooks/post-update + fatal: 'master': unable to chdir or not a git archive + fatal: The remote end hung up unexpectedly + 'git pull master' failed: at /usr/share/perl5/IkiWiki/Plugin/git.pm line 195. + taleman@porixi:~$ +"""]] diff --git a/doc/forum/Migrating_old_repository_to_new_ikiwiki_system__63__.mdwn b/doc/forum/Migrating_old_repository_to_new_ikiwiki_system__63__.mdwn new file mode 100644 index 000000000..d7a33b526 --- /dev/null +++ b/doc/forum/Migrating_old_repository_to_new_ikiwiki_system__63__.mdwn @@ -0,0 +1,54 @@ +How do I setup an old ikiwiki repository on a new system? + +I have a git repository from an old ikiwiki system. +I reformatted that hard drive, but saved the repository. + +I copied it the repository to my new system, which is now the "master" host. +I installed ikiwiki on the new system. + +How do I set up an ikiwiki system using a pre-existing repository (instead of creating a new one)? --[[JosephTurian]] + +> Well, if you have: +> * A git repository of the wiki +> * A setup file for the wiki +> +> Then you should: +> +> 1. Manually set up a bare git repository, and push +> your backed up repository to it. +> 2. `git clone` from the bare git repository to +> recreate the ikiwiki srcdir +> 3. `git clone` from the bare git repository a second time, +> to create a checkout you can manually edit (optional) +> +> If you preserved your repository, but not the setup file, +> the easiest way to make one is probably to run +> `ikiwiki -dumpsetup` and edit the setup file. --[[Joey]] + +> > I get the following errors after running ikiwiki setup: + + shortcut plugin will not work without shortcuts.mdwn + shortcut plugin will not work without shortcuts.mdwn + successfully generated /home/turian/public_html/iki/ikiwiki.cgi + shortcut plugin will not work without shortcuts.mdwn + successfully generated /home/turian/repos/iki.git/hooks/post-update + Can't stat /usr/share/ikiwiki/basewiki/../javascript: No such file or directory + at /home/turian/utils//lib/perl5/site_perl/5.8.8//IkiWiki/Plugin/autoindex.pm line 60 + Can't stat /usr/share/ikiwiki/basewiki/../smiley: No such file or directory + at /home/turian/utils//lib/perl5/site_perl/5.8.8//IkiWiki/Plugin/autoindex.pm line 60 + Can't stat /usr/share/ikiwiki/basewiki: No such file or directory + at /home/turian/utils//lib/perl5/site_perl/5.8.8//IkiWiki/Plugin/autoindex.pm line 60 + Can't stat /usr/share/ikiwiki/basewiki/../javascript: No such file or directory + at /home/turian/utils//lib/perl5/site_perl/5.8.8//IkiWiki/Render.pm line 320 + Can't stat /usr/share/ikiwiki/basewiki/../smiley: No such file or directory + at /home/turian/utils//lib/perl5/site_perl/5.8.8//IkiWiki/Render.pm line 320 + Can't stat /usr/share/ikiwiki/basewiki: No such file or directory + at /home/turian/utils//lib/perl5/site_perl/5.8.8//IkiWiki/Render.pm line 320 + internal error: smileys.mdwn cannot be found in /home/turian/iki or underlay + +> > How do I resolve these errors? I have my PERL5LIB location set correctly. + +>>> Well, that's unrelated to the original question, but +>>> I guess you should set `underlaydir` in your setup file to +>>> point to whereever you have installed the basewiki directory. +>>> --[[Joey]] diff --git a/doc/forum/Migrating_old_repository_to_new_ikiwiki_system__63__/comment_1_e5ce524c5d34b1d4218172296bd99100._comment b/doc/forum/Migrating_old_repository_to_new_ikiwiki_system__63__/comment_1_e5ce524c5d34b1d4218172296bd99100._comment new file mode 100644 index 000000000..78703bc27 --- /dev/null +++ b/doc/forum/Migrating_old_repository_to_new_ikiwiki_system__63__/comment_1_e5ce524c5d34b1d4218172296bd99100._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="https://launchpad.net/~tale" + nickname="tale" + subject="When is ikiwiki --setup run?" + date="2011-12-23T13:49:54Z" + content=""" +Am I to run ikiwiki --setup after all the three steps? +"""]] diff --git a/doc/forum/Migrating_old_repository_to_new_ikiwiki_system__63__/comment_3_65c4a4895f6541ff0ff2d094ff447bba._comment b/doc/forum/Migrating_old_repository_to_new_ikiwiki_system__63__/comment_3_65c4a4895f6541ff0ff2d094ff447bba._comment new file mode 100644 index 000000000..a9bb2791a --- /dev/null +++ b/doc/forum/Migrating_old_repository_to_new_ikiwiki_system__63__/comment_3_65c4a4895f6541ff0ff2d094ff447bba._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + nickname="joey" + subject="comment 3" + date="2011-12-25T00:08:22Z" + content=""" +You run ikiwiki -setup when you have all the files in place for ikiwiki and would like it to rebuild the site and generate the wrappers. +"""]] diff --git a/doc/forum/Moving_wiki.git_folder__63__.mdwn b/doc/forum/Moving_wiki.git_folder__63__.mdwn new file mode 100644 index 000000000..77d1da1ee --- /dev/null +++ b/doc/forum/Moving_wiki.git_folder__63__.mdwn @@ -0,0 +1,17 @@ +Hi folks, I created a simple wiki to keep notes and references for projects, it's worked quite nice so far. I decided to use git as it's what I use daily to manage code, and it's available on all my machines. + +Anyway, I wanted to move all the wiki source stuff into a subfolder so that it stops cluttering up my ~ directory. However, there seems to be a problem with moving wiki.git (I moved wiki, wiki.git and wiki.setup) and I'm not sure where to tell ikiwiki that the git directory has been moved. I changed + + srcdir => '/home/pixel/.notebook/wiki', + git_wrapper => '/home/pixel/.notebook/wiki.git/hooks/post-update', + +and that seems to be fine. However when I go to run ikiwiki --setup things go wrong: + + pixel@tosh: [~ (ruby-1.9.2-p0)] ➔ ikiwiki -setup .notebook/wiki.setup + successfully generated /home/pixel/public_html/wiki/ikiwiki.cgi + successfully generated /home/pixel/.notebook/wiki.git/hooks/post-update + fatal: '/home/pixel/wiki.git' does not appear to be a git repository + fatal: The remote end hung up unexpectedly + 'git pull origin' failed: at /usr/share/perl5/IkiWiki/Plugin/git.pm line 193. + +I've gone through wiki.setup and nothing has jumped out as the place to set this, have I missed something? diff --git a/doc/forum/Moving_wiki.git_folder__63__/comment_1_05238461520613f4ed1b0d02ece663bd._comment b/doc/forum/Moving_wiki.git_folder__63__/comment_1_05238461520613f4ed1b0d02ece663bd._comment new file mode 100644 index 000000000..d654591c0 --- /dev/null +++ b/doc/forum/Moving_wiki.git_folder__63__/comment_1_05238461520613f4ed1b0d02ece663bd._comment @@ -0,0 +1,11 @@ +[[!comment format=mdwn + username="http://users.itk.ppke.hu/~cstamas/openid/" + ip="212.183.140.47" + subject="comment 1" + date="2010-10-27T22:45:28Z" + content=""" +I think you want to edit + + .git/config + +"""]] diff --git a/doc/forum/Moving_wiki.git_folder__63__/comment_2_72b2b842dfa0cfaf899fe7af12977519._comment b/doc/forum/Moving_wiki.git_folder__63__/comment_2_72b2b842dfa0cfaf899fe7af12977519._comment new file mode 100644 index 000000000..f2e7ece18 --- /dev/null +++ b/doc/forum/Moving_wiki.git_folder__63__/comment_2_72b2b842dfa0cfaf899fe7af12977519._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="http://pixel.dreamwidth.org/" + ip="65.29.14.21" + subject="comment 2" + date="2010-10-28T02:54:15Z" + content=""" +That did it thanks! + +Should I make some sort of edit in the setup page? I've used git for a while and for whatever reason it never occurred to me that this was from git, not from ikiwiki itself. +"""]] diff --git a/doc/forum/Multiple_urls.mdwn b/doc/forum/Multiple_urls.mdwn new file mode 100644 index 000000000..03125d27c --- /dev/null +++ b/doc/forum/Multiple_urls.mdwn @@ -0,0 +1,8 @@ +Hi, +Is there a way of making a given ikiwiki instance accessible both from the LAN where it's server is and from the WAN? + +Say I have ikiwiki installed on a server connected to a router. That router has port forwarding and dyndns configured so I could open ikiwiki from outside the LAN. Trying to open normal ikiwiki pages, from outside the LAN, or with a proxy, works. However, the Editing and Preferences pages, for example, redirect to http://192.168.x.x/~username/ikiwiki/ikiwiki.cgi?page=posts%2Fhello_world&do=edit (in the case of the edit page), which of course only exists inside the LAN, and fails loading. + +Editing the "url" and "cgiurl" directives in the .setup file to point to the dyndns address makes it work from the outside, but I can't edit the pages from inside the LAN anymore with this configuration. The normal pages, once again, are accessible. Edit or Preferences, on the other hand, redirect to the public address, which I can't open from inside the same LAN it points to. + +For this reason I ask, is there an way to have multiple urls point to the same ikiwiki page, namely a LAN IP url and a public IP one? Thanks in advance. diff --git a/doc/forum/Multiple_urls/comment_1_e4c1256346d5a421161c20e344d8bada._comment b/doc/forum/Multiple_urls/comment_1_e4c1256346d5a421161c20e344d8bada._comment new file mode 100644 index 000000000..9806f5376 --- /dev/null +++ b/doc/forum/Multiple_urls/comment_1_e4c1256346d5a421161c20e344d8bada._comment @@ -0,0 +1,22 @@ +[[!comment format=mdwn + username="http://kerravonsen.dreamwidth.org/" + ip="60.241.8.244" + subject="A Few Ways To Do This" + date="2012-10-09T02:02:09Z" + content=""" +I don't think one can alter IkiWiki to have multiple URLs, because the URL is built in to the CGI when the CGI is generated. + +1. Use the external hostname (say, foo.com) for the URL, and tell your local machine that foo.com has an IP of 192.168.x.x, thus making it accessible from within the LAN. +2. Give the URL as a relative-absolute URL; that is, rather than \"http://foo.com/ikiwiki.cgi\" give it as \"/ikiwiki.cgi\". This doesn't always work, though. +3. Build two versions of the site from the same git repo. One for access from inside, and one for access from outside. Both setup files would need to be identical, apart from + + * the destination directory + * the URLs + * the git-update file name; one would need to call it something other than post-update. + + Then one would make a new \"post-update\" file which calls *both* of the ikiwiki post-update scripts, so that both versions of the site are updated when you make a change. + Then set up your web-server to point to the \"external\" directory for the external site, and the \"internal\" directory for the internal site; easy enough to do if you use virtual hosts. + +Yes, I know the third one is somewhat complex... I use the idea myself in order to make two versions of a site where one is editable and the other is not, but that's not what you're aiming for, I know. + +"""]] diff --git a/doc/forum/Need_help_installing_h1title_plugin.mdwn b/doc/forum/Need_help_installing_h1title_plugin.mdwn new file mode 100644 index 000000000..f6de2fe6f --- /dev/null +++ b/doc/forum/Need_help_installing_h1title_plugin.mdwn @@ -0,0 +1,5 @@ +I am trying to install plugins that's not included in Ikiwiki following instructions at `http://ikiwiki.info/plugins/install/`. So far I tried `http://jblevins.org/git/ikiwiki/plugins.git/plain/h1title.pm` and `http://ikiwiki.info/plugins/contrib/default_content_for___42__copyright__42___and___42__license__42__/`. After putting these `.pm` files in `/home/foo/website/libi/IkiWiki/Plugin` and making them executable, I rebuilt the wiki instance. But the plugins aren't working. + +Any ideas what might be wrong? + +Is there some way to debug? diff --git a/doc/forum/Need_help_setting_up_ikiwiki_CGI.mdwn b/doc/forum/Need_help_setting_up_ikiwiki_CGI.mdwn new file mode 100644 index 000000000..66c820c34 --- /dev/null +++ b/doc/forum/Need_help_setting_up_ikiwiki_CGI.mdwn @@ -0,0 +1,16 @@ +After installing and setting up Ikiwiki on my Debian server. I somehow got the following error when trying to edit index page in browser / online: + + Not Found + + The requested URL /foobar.com/static/ikiwiki.cgi was not found on this server. + + Additionally, a 404 Not Found error was encountered while trying to use an ErrorDocument to handle the request. + + +My `foobar.setup` has the following for CGI configuration + + cgiurl => 'http:/foobar.com/static/ikiwiki.cgi', + cgi_wrapper => '/home/foobaruser/foobar.com/static/ikiwiki.cgi', + + +What could be wrong? diff --git a/doc/forum/Need_help_setting_up_ikiwiki_CGI/comment_1_0fc4573568711c56a0df4af620110c2f._comment b/doc/forum/Need_help_setting_up_ikiwiki_CGI/comment_1_0fc4573568711c56a0df4af620110c2f._comment new file mode 100644 index 000000000..3c5be5c6e --- /dev/null +++ b/doc/forum/Need_help_setting_up_ikiwiki_CGI/comment_1_0fc4573568711c56a0df4af620110c2f._comment @@ -0,0 +1,12 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + nickname="joey" + subject="comment 1" + date="2011-05-20T13:56:51Z" + content=""" +Well, your cgiurl is an invalid url (valid urls start with \"http://\" , not \"http:/\") + +Perhaps you also have a misconfigured web server. You don't say if `/home/foobaruser/foobar.com/` is configured to be served up for foobar.com. Or perhaps you need to follow the instructions in [[tips/dot_cgi]]. + +Or, perhaps `/home/foobaruser/foobar.com/static/ikiwiki.cgi` does not exist; did you run ikiwiki -setup? +"""]] diff --git a/doc/forum/Need_help_setting_up_ikiwiki_CGI/comment_3_89f2cd7d874a6257786478e4cae1e2bc._comment b/doc/forum/Need_help_setting_up_ikiwiki_CGI/comment_3_89f2cd7d874a6257786478e4cae1e2bc._comment new file mode 100644 index 000000000..ed771bd00 --- /dev/null +++ b/doc/forum/Need_help_setting_up_ikiwiki_CGI/comment_3_89f2cd7d874a6257786478e4cae1e2bc._comment @@ -0,0 +1,16 @@ +[[!comment format=mdwn + username="https://profiles.google.com/lumeng.dev" + nickname="lumeng.dev" + subject="comment 3" + date="2011-05-21T19:11:27Z" + content=""" +After testing using a test CGI script (thanks to smcv), I confirmed this is not a problem of the server not being set up to serve CGI. I then tried changing the permissions of `ikiwiki.cgi` and found: + +* on the remote server, if I have `-rwsr-sr-x` for `ikiwiki.cgi`, the CGI features such as `Preference` and `Edit` buttons don't work, but if I set it `-rwsr-xr-x`, it works. The server is a Debian VPS. + +* in contrast, on my local LAMP server `localhost`, both permissions work + +Any ideas? + +Thanks! +"""]] diff --git a/doc/forum/Need_help_setting_up_ikiwiki_CGI/comment_3_cbc20267fe5f0531f63db881d50596d1._comment b/doc/forum/Need_help_setting_up_ikiwiki_CGI/comment_3_cbc20267fe5f0531f63db881d50596d1._comment new file mode 100644 index 000000000..4e645ef0b --- /dev/null +++ b/doc/forum/Need_help_setting_up_ikiwiki_CGI/comment_3_cbc20267fe5f0531f63db881d50596d1._comment @@ -0,0 +1,20 @@ +[[!comment format=mdwn + username="http://smcv.pseudorandom.co.uk/" + nickname="smcv" + subject="comment 3" + date="2011-05-21T18:27:15Z" + content=""" +Here is a simple CGI script: + + #!/bin/sh + printf \"Content-type: text/plain\r\n\" + printf \"\r\n\" + printf \"Hello, world!\r\n\" + +Here is a simple Perl CGI script: + + #!/usr/bin/perl + print \"Content-type: text/plain\r\n\"; + print \"\r\n\"; + print \"Hello, world!\r\n\"; +"""]] diff --git a/doc/forum/Need_help_setting_up_ikiwiki_CGI/comment_4_2eaf53935eecd0a918755d728450a642._comment b/doc/forum/Need_help_setting_up_ikiwiki_CGI/comment_4_2eaf53935eecd0a918755d728450a642._comment new file mode 100644 index 000000000..057a09a51 --- /dev/null +++ b/doc/forum/Need_help_setting_up_ikiwiki_CGI/comment_4_2eaf53935eecd0a918755d728450a642._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="https://profiles.google.com/lumeng.dev" + nickname="lumeng.dev" + subject="comment 4" + date="2011-05-21T19:36:19Z" + content=""" +BTW, I use `cgi_wrappermode => '06755'` in my `wiki.setup` +"""]] diff --git a/doc/forum/Need_some_help_on_starting_to_use_po_plugin_for_creating_pages_in_multiple_languages.mdwn b/doc/forum/Need_some_help_on_starting_to_use_po_plugin_for_creating_pages_in_multiple_languages.mdwn new file mode 100644 index 000000000..5e4e56fde --- /dev/null +++ b/doc/forum/Need_some_help_on_starting_to_use_po_plugin_for_creating_pages_in_multiple_languages.mdwn @@ -0,0 +1,6 @@ +I've installed the po plugin. I'm still trying to figure out how to use it. + +I have a Ikiwiki instance with multiple existing pages in English. + +How do I use po to create alternative pages in slave languages for these existing pages? + diff --git a/doc/forum/Need_something_more_powerful_than_Exclude.mdwn b/doc/forum/Need_something_more_powerful_than_Exclude.mdwn new file mode 100644 index 000000000..5e8043258 --- /dev/null +++ b/doc/forum/Need_something_more_powerful_than_Exclude.mdwn @@ -0,0 +1,5 @@ +When I originally looked at the "exclude" option, I thought it meant that it excluded pages completely, but it apparently doesn't. What I've found in practice is that a file which matches the "exclude" regex is excluded from *processing*, but it is still copied over to the destination directory. Thus, for example, if I have "^Makefile$" as the exclude pattern, and I have a file `src/foo/Makefile`, then that file is copied unaltered into `dest/foo/Makefile`. However, what I want is for `src/foo/Makefile` to be completely ignored: that it is not only not processed, but not even *copied* into the destination directory. + +I'm not sure if the current behaviour is a bug or a feature, but I would like a "totally ignore this file" feature if it's possible to have one. + +-- [[KathrynAndersen]] diff --git a/doc/forum/Need_something_more_powerful_than_Exclude/comment_2_0019cd6b34c8d8678b2532de57a92d15._comment b/doc/forum/Need_something_more_powerful_than_Exclude/comment_2_0019cd6b34c8d8678b2532de57a92d15._comment new file mode 100644 index 000000000..7842caeac --- /dev/null +++ b/doc/forum/Need_something_more_powerful_than_Exclude/comment_2_0019cd6b34c8d8678b2532de57a92d15._comment @@ -0,0 +1,12 @@ +[[!comment format=mdwn + username="http://smcv.pseudorandom.co.uk/" + nickname="smcv" + subject="expression anchored too closely?" + date="2010-11-23T10:43:21Z" + content=""" +It looks as though you might only be excluding a top-level Makefile, and not a Makefile in subdirectories. Try excluding `(^|/)Makefile$` instead, for instance? (See `wiki_file_prune_regexps` in `IkiWiki.pm` for hints.) + +The match operation in `&file_pruned` ends up a bit like this: + + \"foo/Makefile\" =~ m{…|…|…|(^|/)Makefile$} +"""]] diff --git a/doc/forum/Need_something_more_powerful_than_Exclude/comment_2_f577ab6beb9912471949d8d18c790267._comment b/doc/forum/Need_something_more_powerful_than_Exclude/comment_2_f577ab6beb9912471949d8d18c790267._comment new file mode 100644 index 000000000..bd964d540 --- /dev/null +++ b/doc/forum/Need_something_more_powerful_than_Exclude/comment_2_f577ab6beb9912471949d8d18c790267._comment @@ -0,0 +1,11 @@ +[[!comment format=mdwn + username="http://kerravonsen.dreamwidth.org/" + ip="60.241.8.244" + subject="Missed It By That Much" + date="2010-11-25T02:55:20Z" + content=""" +I discovered that I not only needed to change the regexp, but I also needed to delete .ikiwiki/indexdb because `file_pruned` only gets called for files that aren't in the `%pagesources` hash, and since the file in question was already there because it had been put there before the exclude regex was changed, it wasn't even being checked! + +[[KathrynAndersen]] + +"""]] diff --git a/doc/forum/Need_something_more_powerful_than_Exclude/comment_3_1ed260b0083a290688425a006a83f603._comment b/doc/forum/Need_something_more_powerful_than_Exclude/comment_3_1ed260b0083a290688425a006a83f603._comment new file mode 100644 index 000000000..8b93acd79 --- /dev/null +++ b/doc/forum/Need_something_more_powerful_than_Exclude/comment_3_1ed260b0083a290688425a006a83f603._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + nickname="joey" + subject="comment 3" + date="2010-11-29T20:41:49Z" + content=""" +`%pagesources` gets nuked when you rebuild the whole wiki with eg, ikiwiki -setup or ikiwiki -rebuild. So you shouldn't normally need to remove the indexdb, just rebuild when making this sort of change that affects the whole site. +"""]] diff --git a/doc/forum/Need_something_more_powerful_than_Exclude/comment_4_c39bdaf38e1e20db74eb26f0560bd673._comment b/doc/forum/Need_something_more_powerful_than_Exclude/comment_4_c39bdaf38e1e20db74eb26f0560bd673._comment new file mode 100644 index 000000000..15f1fecb8 --- /dev/null +++ b/doc/forum/Need_something_more_powerful_than_Exclude/comment_4_c39bdaf38e1e20db74eb26f0560bd673._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="http://kerravonsen.dreamwidth.org/" + ip="60.241.8.244" + subject="comment 4" + date="2010-11-30T02:35:43Z" + content=""" +One would think that would be the case, yes, but for some reason it didn't work for me. 8-( + +[[KathrynAndersen]] +"""]] diff --git a/doc/forum/Need_something_more_powerful_than_Exclude/comment_5_39b01857f7e0b388a6e7a3c1cf5388d5._comment b/doc/forum/Need_something_more_powerful_than_Exclude/comment_5_39b01857f7e0b388a6e7a3c1cf5388d5._comment new file mode 100644 index 000000000..17228b891 --- /dev/null +++ b/doc/forum/Need_something_more_powerful_than_Exclude/comment_5_39b01857f7e0b388a6e7a3c1cf5388d5._comment @@ -0,0 +1,9 @@ +[[!comment format=mdwn + username="http://tbm.myopenid.com/" + ip="188.222.45.200" + subject="Still there?" + date="2012-03-20T18:35:41Z" + content=""" +Joey, I believe I see the same problem with 3.20120202. I add foo.mdwn, run ikiwiki --setup ikiwiki.setup, add \"exclude: foo\", run --setup again and it still says \"building foo.mdwn\". + +"""]] diff --git a/doc/forum/Need_something_more_powerful_than_Exclude/comment_6_1dccdfebad31446200213a2cae25f0e2._comment b/doc/forum/Need_something_more_powerful_than_Exclude/comment_6_1dccdfebad31446200213a2cae25f0e2._comment new file mode 100644 index 000000000..d93684d10 --- /dev/null +++ b/doc/forum/Need_something_more_powerful_than_Exclude/comment_6_1dccdfebad31446200213a2cae25f0e2._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawkiulxucQx_YZQZUVJdNF6oMaZwWb8JF2M" + nickname="Martin" + subject="Reproduced" + date="2012-07-25T02:23:13Z" + content=""" +I also encountered this bug (having to delete indexdb) in 3.20120629. + +-- Martin +"""]] diff --git a/doc/forum/News_site_where_articles_are_submitted_and_then_reviewed_before_posting.mdwn b/doc/forum/News_site_where_articles_are_submitted_and_then_reviewed_before_posting.mdwn new file mode 100644 index 000000000..8dd755274 --- /dev/null +++ b/doc/forum/News_site_where_articles_are_submitted_and_then_reviewed_before_posting.mdwn @@ -0,0 +1,23 @@ +[[!meta date="2008-04-28 14:57:25 -0400"]] + +I am considering moving a news site to Ikiwiki. I am hoping that Ikiwiki has a feature where anonymous posters can submit a form that moderators can review and then accept for it to be posted on a news webpage (like front page of the website). + +> Well, you can have one blog that contains unreviewed articles, and +> moderators can then add a tag that makes the article show up in the main +> news feed. There's nothing stopping someone submitting an article +> pre-tagged though. If you absolutely need to lock that down, you could +> have one blog with unreviewed articles in one subdirectory, and reviewers +> then move the file over to another subdirectory when they're ready to +> publish it. (This second subdirectory would be locked to prevent others +> from writing to it.) --[[Joey]] + +Also it would be good if the news page would keep maybe just the latest 10 entries with links to an archive that make it easy to browse to old entries by date. (Could have over a thousand news articles.) + +> The inline plugin allows setting up things like this. + +Plus users be able to post feedback to news items. If anonymous, they must be approved first. I'd prefer to not use normal "wiki" editor for feedback. + +Any thoughts or examples on this? Any links to examples of news sites or blogs with outside feedback using ikiwiki? + +Thanks --[[JeremyReed]] + diff --git a/doc/forum/OpenID_not_working___47___where_to_define_wiki__39__s_ID__63__.mdwn b/doc/forum/OpenID_not_working___47___where_to_define_wiki__39__s_ID__63__.mdwn new file mode 100644 index 000000000..e58844bac --- /dev/null +++ b/doc/forum/OpenID_not_working___47___where_to_define_wiki__39__s_ID__63__.mdwn @@ -0,0 +1,12 @@ +Hi, + +unfortunately, openID is not working at my wiki. I get the error + +no_identity_server: The provided URL doesn't declare its OpenID identity server. + +I think this is related to the ID of my wiki not being defined right. Where and how do I have to define it? I have used the !meta openid as described on ikiwiki.info (are there two quotes at the end where only one should be (joeyh example) on index.html. + +Somehow I think its not transferred right to the openID provider of the user upon login. + +thanks in advance +chris diff --git a/doc/forum/OpenID_not_working___47___where_to_define_wiki__39__s_ID__63__/comment_1_bf1bec748d6ab419276a73a7001024cf._comment b/doc/forum/OpenID_not_working___47___where_to_define_wiki__39__s_ID__63__/comment_1_bf1bec748d6ab419276a73a7001024cf._comment new file mode 100644 index 000000000..06d2a332b --- /dev/null +++ b/doc/forum/OpenID_not_working___47___where_to_define_wiki__39__s_ID__63__/comment_1_bf1bec748d6ab419276a73a7001024cf._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawndsaC4GaIBw49WNdbk2Faqfm_mrtQgul8" + nickname="Christian" + subject="apache module?" + date="2012-01-18T15:40:57Z" + content=""" +Do I have to install the openid apache module, load it, and configure apache to use my openid? Except that in my case I can get it from the package system, there is a description <a href=\"http://findingscience.com/mod_auth_openid/\">here</a> what I mean. I got a feeling that's it. +"""]] diff --git a/doc/forum/OpenID_not_working___47___where_to_define_wiki__39__s_ID__63__/comment_2_14a1b269be6dbcc9b2068d3e18b55711._comment b/doc/forum/OpenID_not_working___47___where_to_define_wiki__39__s_ID__63__/comment_2_14a1b269be6dbcc9b2068d3e18b55711._comment new file mode 100644 index 000000000..3078a1473 --- /dev/null +++ b/doc/forum/OpenID_not_working___47___where_to_define_wiki__39__s_ID__63__/comment_2_14a1b269be6dbcc9b2068d3e18b55711._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + nickname="joey" + subject="comment 2" + date="2012-01-30T19:34:00Z" + content=""" +Yes, good spotting, [[ikiwiki/directive/meta]] had a doubled quote in the openid example. + +Otherwise, that example will work. You don't need anything installed on your server to add openid delegation to a page. +"""]] diff --git a/doc/forum/OpenID_not_working___47___where_to_define_wiki__39__s_ID__63__/comment_3_f581afcdb4481ea5d65bcc33bdbab99a._comment b/doc/forum/OpenID_not_working___47___where_to_define_wiki__39__s_ID__63__/comment_3_f581afcdb4481ea5d65bcc33bdbab99a._comment new file mode 100644 index 000000000..1ac15d74c --- /dev/null +++ b/doc/forum/OpenID_not_working___47___where_to_define_wiki__39__s_ID__63__/comment_3_f581afcdb4481ea5d65bcc33bdbab99a._comment @@ -0,0 +1,25 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawnp4lzWSX1pvSpwAoboehP3SSbmbQESe80" + nickname="Felipe Augusto" + subject="I'm trying to use OpenID without success" + date="2012-02-08T04:54:22Z" + content=""" +I'm using ikiwiki package from Debian squeeze and I can't seem +to be able to make OpenID work. It's a blog and when I try to +add a comment and click on SignIn, I'm redirected to + +>http://my.site/ikiwiki.cgi?do=commentsignin + + +Once I click on Google logo/icon, it takes a while before showing + +>no_identity_server: The provided URL doesn't declare its OpenID identity server. + + +It's not clear for me what's wrong or if I should add meta openid in some page. +This is the version of libnet-openid-consumer-perl: 1.03-1. It also fails for +Yahoo! and other providers, we never get redirected to Google/Yahoo! or other +verification page. + +Thank you in advance! +"""]] diff --git a/doc/forum/OpenID_not_working___47___where_to_define_wiki__39__s_ID__63__/comment_4_b0d39d30852bca1525ab9612a7532670._comment b/doc/forum/OpenID_not_working___47___where_to_define_wiki__39__s_ID__63__/comment_4_b0d39d30852bca1525ab9612a7532670._comment new file mode 100644 index 000000000..ce3cf2156 --- /dev/null +++ b/doc/forum/OpenID_not_working___47___where_to_define_wiki__39__s_ID__63__/comment_4_b0d39d30852bca1525ab9612a7532670._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawndsaC4GaIBw49WNdbk2Faqfm_mrtQgul8" + nickname="Christian" + subject="comment 4" + date="2012-02-29T06:59:21Z" + content=""" +I had the error with squeeze, too. Have now moved to passwordauth, at least for now... +"""]] diff --git a/doc/forum/PERL5LIB__44___wrappers_and_homedir_install.mdwn b/doc/forum/PERL5LIB__44___wrappers_and_homedir_install.mdwn new file mode 100644 index 000000000..fba941efc --- /dev/null +++ b/doc/forum/PERL5LIB__44___wrappers_and_homedir_install.mdwn @@ -0,0 +1,38 @@ +What is the way to tell wrappers that PERL5LIB should include ~/bin directories? + +Having this in the wiki.setup doesn't help anymore: + + # environment variables + ENV => { + PATH => '/home/user/bin/bin:/usr/local/bin:/usr/bin:/bin:/usr/games:/home/user/ikiwiki/usr/bin/:/home/user/ikiwiki/usr/sbin/:/home/user/bin/bin/:~/bin/bin/', + PERL5LIB => '/home/user/bin/share/perl/5.10.0:/home/user/bin/lib/perl/5.10.0' + }, + +Or at least I get CGI errors and running ikiwiki.cgi manually fails too: + + Use of uninitialized value $tainted in pattern match (m//) at /usr/share/perl5/IkiWiki.pm line 233. + Argument "" isn't numeric in umask at /usr/share/perl5/IkiWiki.pm line 139. + Undefined subroutine &IkiWiki::cgierror called at /home/user/bin/bin/ikiwiki line 199. + +Server has an older ikiwiki installed but I'd like to use a newer version from git, and I don't have root access. + +> You can't set `PERL5LIB` in `ENV` in a setup file, because ikiwiki is already +> running before it reads that, and so it has little effect. Your error +> messages do look like a new bin/ikiwiki is using an old version of +> `IkiWiki.pm`. +> +> The thing to do is set `INSTALL_BASE` when you're installing ikiwiki from +> source. Like so: + + cd ikiwiki + perl Makefile.PL INSTALL_BASE=$HOME PREFIX= + make install + +> Then `$HOME/bin/ikiwiki` will have hardcoded into it to look +> for ikiwiki's perl modules in `$HOME/lib/perl5/` +> (This is documented in the README file by the way.) --[[Joey]] + +>> Ok, *perl Makefile.PL INSTALL_BASE=$HOME/bin PREFIX=* finally did it for me. I tried too many things with +>> these paths so I wasn't sure which actually worked. After that I did +>> *$ ikiwiki --setup www.setup --wrappers --rebuild*. Somehow in this update mess I seem to have lost the user +>> accounts, maybe the --rebuild was too much. diff --git a/doc/forum/PageSpec_results_from_independent_checkout.mdwn b/doc/forum/PageSpec_results_from_independent_checkout.mdwn new file mode 100644 index 000000000..693287d2b --- /dev/null +++ b/doc/forum/PageSpec_results_from_independent_checkout.mdwn @@ -0,0 +1,8 @@ +I'd like to be able to do PageSpec matches independent of the Ikiwiki checkout, but at best I'm currently restricted to copying over and using whatever is in the indexdb with this approach: + + perl -MIkiWiki -le '$config{wikistatedir}=".ikiwiki"; IkiWiki::loadindex(); print foreach pagespec_match_list("", shift)' "bugs/*" + +I get the impression there's a way to build up enough state to run pagespec matches without doing any rendering, but I don't know how. Any ideas? -- JoeRayhawk + +> It's not possible to build up enough state without at a minimum +> performing the scan pass of rendering on every page. --[[Joey]] diff --git a/doc/forum/Parent_Links_all_link_to_root.mdwn b/doc/forum/Parent_Links_all_link_to_root.mdwn new file mode 100644 index 000000000..b9c4c8e1a --- /dev/null +++ b/doc/forum/Parent_Links_all_link_to_root.mdwn @@ -0,0 +1,18 @@ +My parent links all link to the root instead of to the appropriate index.mdwn. Is this a sign of a broken link pre-compile? Is there some setting that controls this? + +<code> +\<span class="parentlinks"> + +\<a href="../../../">root\</a>/ + +\<a href="../../../">level1\</a>/ + +\<a href="../../../">level2\</a>/ + +\</span> +</code> + +Thanks, +Sean + +ikiwiki version 3.20100722 - Pretty plain Jane install diff --git a/doc/forum/Parent_Links_all_link_to_root/comment_1_4b5ed25cceb7740f64ee08aba00a1d91._comment b/doc/forum/Parent_Links_all_link_to_root/comment_1_4b5ed25cceb7740f64ee08aba00a1d91._comment new file mode 100644 index 000000000..656cc0f56 --- /dev/null +++ b/doc/forum/Parent_Links_all_link_to_root/comment_1_4b5ed25cceb7740f64ee08aba00a1d91._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://joeyh.name/" + ip="4.154.4.117" + subject="comment 1" + date="2012-06-03T17:11:11Z" + content=""" +All I can think is that you must have modified the `page.tmpl` template and broken the url inside the parenlinks loop somehow. +"""]] diff --git a/doc/forum/Perhaps_I__39__m_doing_it_wrong_-_tracking_non-post_files_in_a_blog.mdwn b/doc/forum/Perhaps_I__39__m_doing_it_wrong_-_tracking_non-post_files_in_a_blog.mdwn new file mode 100644 index 000000000..383ae17cc --- /dev/null +++ b/doc/forum/Perhaps_I__39__m_doing_it_wrong_-_tracking_non-post_files_in_a_blog.mdwn @@ -0,0 +1,7 @@ +I've been searching on this topic for a while and haven't found a solution, so I'd like to ask here. + +I have a blog which I mostly use as a tech-note reminder system for myself (how did I setup my server, etc). Occasionally I find it useful to include files which are not posts, and links to those files. + +Right now, I scp the files to the server to get them in a place accessible by the web server, then use a relative link within the post. This works, but it strikes me that the files are as much a part of the post as the post itself, and therefore should be tracked. The problem with tracking the files is the inline directive gives those files their own entries as posts in the blog. I do not want them to have their own entries, but I *do* want them co-located with the file containing the post from which they are referenced. + +So, is there a way to have *only* `*.mdwn` files be picked up as posts by the inline directive (I tried using a PageSpec of `*.mdwn`, but that didn't work)? Or, conversely, to exclude other files from being picked up as posts? Or am I not seeing another way to go about this task? diff --git a/doc/forum/Perhaps_I__39__m_doing_it_wrong_-_tracking_non-post_files_in_a_blog/comment_1_45ecaf6efa2065837fa54a42737f0a66._comment b/doc/forum/Perhaps_I__39__m_doing_it_wrong_-_tracking_non-post_files_in_a_blog/comment_1_45ecaf6efa2065837fa54a42737f0a66._comment new file mode 100644 index 000000000..4d2c93238 --- /dev/null +++ b/doc/forum/Perhaps_I__39__m_doing_it_wrong_-_tracking_non-post_files_in_a_blog/comment_1_45ecaf6efa2065837fa54a42737f0a66._comment @@ -0,0 +1,18 @@ +[[!comment format=mdwn + username="http://smcv.pseudorandom.co.uk/" + nickname="smcv" + subject="comment 1" + date="2012-01-03T11:29:59Z" + content=""" +Change the [[ikiwiki/pagespec]] in the `inline`, for instance from +`posts/*` to `page(posts/*)`. + +`page(*)` only matches \"pages\" (things that get rendered to HTML, which is just +`.mdwn` files in a default ikiwiki, but can include other things with the right +plugins). + +On my blog I use \"`2* and copyright(*)`\", which is a bit of a hack: it matches +files in the directories I use for posts (which are year-based), but only if +they have an explicit copyright statement - which my blog posts do, but +\"structural\" pages (like a list of all posts from 2011) don't. +"""]] diff --git a/doc/forum/Perhaps_I__39__m_doing_it_wrong_-_tracking_non-post_files_in_a_blog/comment_2_45ca7ef4190c281d703c8c7ca6979298._comment b/doc/forum/Perhaps_I__39__m_doing_it_wrong_-_tracking_non-post_files_in_a_blog/comment_2_45ca7ef4190c281d703c8c7ca6979298._comment new file mode 100644 index 000000000..ecb6f5df9 --- /dev/null +++ b/doc/forum/Perhaps_I__39__m_doing_it_wrong_-_tracking_non-post_files_in_a_blog/comment_2_45ca7ef4190c281d703c8c7ca6979298._comment @@ -0,0 +1,12 @@ +[[!comment format=mdwn + username="dave" + ip="24.209.97.191" + subject="comment 2" + date="2012-01-04T04:01:54Z" + content=""" +Thank you sir, that was exactly what I needed! + +Don't know why I didn't think to try page - apparently I have a special blindness which applies to looking at the pagespec help page. ;) + +Anyway, thanks again, that fixed it. +"""]] diff --git a/doc/forum/Possible_to_use_meta_variables_in_templates__63__.mdwn b/doc/forum/Possible_to_use_meta_variables_in_templates__63__.mdwn new file mode 100644 index 000000000..3c214d457 --- /dev/null +++ b/doc/forum/Possible_to_use_meta_variables_in_templates__63__.mdwn @@ -0,0 +1,11 @@ +I'm trying to create a [[!iki plugins/template desc=template]] which references variables from the [[!iki plugins/meta desc=meta]] plugin, but either it's not supported or I'm doing something wrong. This is what my template looks like: + + <div class="attributionbox"> + <p><b>Written by:</b> <a href="<TMPL_VAR AUTHORURL>"><TMPL_VAR AUTHOR></a></p> + <p><TMPL_VAR text></b></p> + </div> + +The template is working because I get the content, but all the places where I reference meta variables are blank. Is this supposed to work or am I trying to do something unsupported? Many thanks for any pointers. + +Cheers, +[[AdamShand]] diff --git a/doc/forum/Possible_to_use_meta_variables_in_templates__63__/comment_1_556078a24041289d8f0b7ee756664690._comment b/doc/forum/Possible_to_use_meta_variables_in_templates__63__/comment_1_556078a24041289d8f0b7ee756664690._comment new file mode 100644 index 000000000..3aeeec793 --- /dev/null +++ b/doc/forum/Possible_to_use_meta_variables_in_templates__63__/comment_1_556078a24041289d8f0b7ee756664690._comment @@ -0,0 +1,20 @@ +[[!comment format=mdwn + username="http://smcv.pseudorandom.co.uk/" + nickname="smcv" + subject="not supported at the moment" + date="2011-01-24T15:17:59Z" + content=""" +This isn't supported, because [[ikiwiki/directive/template]] templates +don't run `pagetemplate` hooks (which is how information gets from +[[ikiwiki/directive/meta]] into, for instance, `page.tmpl`). The only +inputs to the `HTML::Template` are the parameters passed to the +directive, plus the `raw_`-prefixed versions of those, plus the extra +parameters passed to every `preprocess` hook (currently `page`, `destpage` +and `preview`). + +I think having `pagetemplate` hooks run for this sort of template +by default would be rather astonishing, but perhaps some sort of +opt-in while defining the template would be reasonable? One problem +with that is that the templates used by [[ikiwiki/directive/template]] +are just wiki pages, and don't really have any special syntax support. +"""]] diff --git a/doc/forum/Possible_to_use_meta_variables_in_templates__63__/comment_2_e7e954218d39bc310015b95aa1a5212c._comment b/doc/forum/Possible_to_use_meta_variables_in_templates__63__/comment_2_e7e954218d39bc310015b95aa1a5212c._comment new file mode 100644 index 000000000..b53188128 --- /dev/null +++ b/doc/forum/Possible_to_use_meta_variables_in_templates__63__/comment_2_e7e954218d39bc310015b95aa1a5212c._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="http://adam.shand.net/" + nickname="Adam" + subject="Bummer." + date="2011-01-24T15:26:33Z" + content=""" +Thanks for the quick response! I'm trying to figure out some way that I can reference meta variables inside of a page. Specifically I'm trying to create an attribution box which lists all of the information I have about who wrote the page, where the original can be found etc. I can just pass the values to the template, but it would be really nice not have to put this information in for the meta plugin and my attribution box! + +The changes you suggest sound wonderful but are beyond my abilities right row. Any ideas how I might accomplish this in the mean time? +"""]] diff --git a/doc/forum/Possible_to_use_meta_variables_in_templates__63__/comment_3_8b16c563c89eb6980ad6a5539d934d7a._comment b/doc/forum/Possible_to_use_meta_variables_in_templates__63__/comment_3_8b16c563c89eb6980ad6a5539d934d7a._comment new file mode 100644 index 000000000..a20f8f5c6 --- /dev/null +++ b/doc/forum/Possible_to_use_meta_variables_in_templates__63__/comment_3_8b16c563c89eb6980ad6a5539d934d7a._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://smcv.pseudorandom.co.uk/" + nickname="smcv" + subject="comment 3" + date="2011-01-24T20:58:52Z" + content=""" +I usually just have a template that contains a suitable `\[[!meta]]` directive. +"""]] diff --git a/doc/forum/Possible_to_use_meta_variables_in_templates__63__/comment_4_76eadf93cce4e2168960131d4677c5fc._comment b/doc/forum/Possible_to_use_meta_variables_in_templates__63__/comment_4_76eadf93cce4e2168960131d4677c5fc._comment new file mode 100644 index 000000000..b5c626130 --- /dev/null +++ b/doc/forum/Possible_to_use_meta_variables_in_templates__63__/comment_4_76eadf93cce4e2168960131d4677c5fc._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://kerravonsen.dreamwidth.org/" + ip="202.173.183.92" + subject="contrib plugins can do this" + date="2011-01-24T23:11:40Z" + content=""" +You can do this by using the [[plugins/contrib/field]] plugin with the [[plugins/contrib/ftemplate]] plugin. +"""]] diff --git a/doc/forum/Possible_to_use_meta_variables_in_templates__63__/comment_5_ddabe4a005042d19c7669038b49275c1._comment b/doc/forum/Possible_to_use_meta_variables_in_templates__63__/comment_5_ddabe4a005042d19c7669038b49275c1._comment new file mode 100644 index 000000000..6279b20ba --- /dev/null +++ b/doc/forum/Possible_to_use_meta_variables_in_templates__63__/comment_5_ddabe4a005042d19c7669038b49275c1._comment @@ -0,0 +1,12 @@ +[[!comment format=mdwn + username="http://adam.shand.net/" + nickname="Adam" + subject="Thanks!" + date="2011-01-25T02:51:35Z" + content=""" +smcv, sorry I don't understand? How are you getting the \[[!meta] to work on a template page, I thought that's what you said didn't work? Do you mean a pagetemplate? + +kerravonsen, thanks for the pointer I'll check those out. + +I realised last night that I think I could also do this with a pagetemplate, since I should be able to access meta variables there. A little clumsy for what I want to do but should hopefully work fine. Would be really neat with the [section template](http://ikiwiki.info/todo/Set_templates_for_whole_sections_of_the_site/) plugin, I'll have to look at that. +"""]] diff --git a/doc/forum/Problem_with_gitweb.mdwn b/doc/forum/Problem_with_gitweb.mdwn new file mode 100644 index 000000000..98a7f39a3 --- /dev/null +++ b/doc/forum/Problem_with_gitweb.mdwn @@ -0,0 +1,3 @@ +I use gitweb to display the pagehistories of my local ikiwiki. However since a few weeks it doesn't work anymore and displays just: 404 - No such project. I don't remember that I changed something with my wiki. Any ideas how to fix this? I guess that it could be a permission problem, however I don't really know which permissions are important in this case. + + diff --git a/doc/forum/Problem_with_gitweb/comment_2_23cc0d87448d3cbdac20a005e9191589._comment b/doc/forum/Problem_with_gitweb/comment_2_23cc0d87448d3cbdac20a005e9191589._comment new file mode 100644 index 000000000..f80bd38d8 --- /dev/null +++ b/doc/forum/Problem_with_gitweb/comment_2_23cc0d87448d3cbdac20a005e9191589._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + nickname="joey" + subject="comment 2" + date="2012-03-05T21:08:45Z" + content=""" +This seems entirely a gitweb configuration problem, so look at `/etc/gitweb.conf` + +Or, if you are able to navigate to a gitweb url that does show your wiki's source, fix up ikiwiki's `historyurl` to use the url that works. +"""]] diff --git a/doc/forum/Problem_with_gitweb/comment_3_697c6038009249e6a49d9e458a5ba271._comment b/doc/forum/Problem_with_gitweb/comment_3_697c6038009249e6a49d9e458a5ba271._comment new file mode 100644 index 000000000..72eeda124 --- /dev/null +++ b/doc/forum/Problem_with_gitweb/comment_3_697c6038009249e6a49d9e458a5ba271._comment @@ -0,0 +1,47 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawk_MMtLPS7osC5MjX00q2ATjvvXPWqm0ik" + nickname="micheal" + subject="comment 3" + date="2012-03-06T09:50:53Z" + content=""" +I don't know how to navigate to a gitweb url that does show my wiki's source. + +My gitweb.conf looks like this: + + cat /etc/gitweb.conf + # path to git projects (<project>.git) + #$projectroot = \"/var/cache/git\"; + $projectroot = \"/home/myuser/myiki\"; + + # directory to use for temp files + $git_temp = \"/tmp\"; + + # Change This + $site_name = \"myiki\"; + + # target of the home link on top of all pages + #$home_link = $my_uri || \"/\"; + + # html text to include at home page + #$home_text = \"indextext.html\"; + + # file with project list; by default, simply scan the projectroot dir. + #$projects_list = $projectroot; + + # stylesheet to use + #@stylesheets = (\"static/gitweb.css\"); + + # javascript code for gitweb + #$javascript = \"static/gitweb.js\"; + + # logo to use + #$logo = \"static/git-logo.png\"; + + # the 'favicon' + #$favicon = \"static/git-favicon.png\"; + + # git-diff-tree(1) options to use for generated patches + #@diff_opts = (\"-M\"); + @diff_opts = (); + +"""]] diff --git a/doc/forum/Problem_with_gitweb/comment_3_6a5b96f7e0d6b169c090e3df7281d938._comment b/doc/forum/Problem_with_gitweb/comment_3_6a5b96f7e0d6b169c090e3df7281d938._comment new file mode 100644 index 000000000..c8bbe9ba1 --- /dev/null +++ b/doc/forum/Problem_with_gitweb/comment_3_6a5b96f7e0d6b169c090e3df7281d938._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawk_MMtLPS7osC5MjX00q2ATjvvXPWqm0ik" + nickname="micheal" + subject="comment 3" + date="2012-03-27T17:35:49Z" + content=""" +Any ideas??? +"""]] diff --git a/doc/forum/Problem_with_gitweb/comment_5_8a79b879205bd265d54e30f0eee2ac63._comment b/doc/forum/Problem_with_gitweb/comment_5_8a79b879205bd265d54e30f0eee2ac63._comment new file mode 100644 index 000000000..242ce8928 --- /dev/null +++ b/doc/forum/Problem_with_gitweb/comment_5_8a79b879205bd265d54e30f0eee2ac63._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawk_MMtLPS7osC5MjX00q2ATjvvXPWqm0ik" + nickname="micheal" + subject="comment 5" + date="2012-03-29T18:55:37Z" + content=""" +Solved by `sudo chmod a+x /home/myuser` +"""]] diff --git a/doc/forum/Problem_with_local_git_commit.mdwn b/doc/forum/Problem_with_local_git_commit.mdwn new file mode 100644 index 000000000..e9dfdb417 --- /dev/null +++ b/doc/forum/Problem_with_local_git_commit.mdwn @@ -0,0 +1,42 @@ +I have a problem when I edit my wiki with a text editor and use just git to commit. + +Suppose `iki` is my scrdir and `iki.git` my repository. Then I did `git clone iki.git myiki` to get a copy. Then I do + + cd myiki + echo "test" >> somepage.mdwm" + git add somepage.mdwm + git pull + git commit -m "test" + git push + +Then I get the following error message + + Counting objects: 5, done. + Delta compression using up to 2 threads. + Compressing objects: 100% (2/2), done. + Writing objects: 100% (3/3), 287 bytes, done. + Total 3 (delta 1), reused 0 (delta 0) + Unpacking objects: 100% (3/3), done. + remote: From /home/myuser/iki + remote: 32bb6be..1f3a647 master -> origin/master + remote: There are no candidates for merging among the refs that you just fetched. + remote: Generally this means that you provided a wildcard refspec which had no + remote: matches on the remote end. + remote: 'git pull --prune origin' failed: at /usr/share/perl5/IkiWiki/Plugin/git.pm line 207. + remote: skipping bad filename local.css~ + remote: skipping bad filename #tex_sandbox.mdwn# + To /home/myuser/iki.git + 32bb6be..1f3a647 master -> master + +When I check the repository via gitk I see that everything seems to be ok, if I check the scrdir the same way origin master is one step away from master and the change doesn't appear on the iki web page. Then I tried to do a `sudo git pull --prune origin master` in my scrdir which sets master to the head, but the change isn't there anyway. It foremost appears when I do a second change as above or if I do `sudo ikiwiki --setup iki.setup`. + +By the way the setup gives me a similar error message: + + successfully generated /var/www/iki/ikiwiki.cgi + successfully generated /home/myuser/iki.git/hooks/post-update + There are no candidates for merging among the refs that you just fetched. + Generally this means that you provided a wildcard refspec which had no + matches on the remote end. + 'git pull --prune origin' failed: at /usr/share/perl5/IkiWiki/Plugin/git.pm line 207. + +Any ideas what may be wrong here and how to fix this? diff --git a/doc/forum/Processing_non-pages.mdwn b/doc/forum/Processing_non-pages.mdwn new file mode 100644 index 000000000..23af417a4 --- /dev/null +++ b/doc/forum/Processing_non-pages.mdwn @@ -0,0 +1,7 @@ +I'd like to be able to write a plugin that minifies CSS pages, but the whole plugin mechanism appears to be oriented towards generating HTML pages. That is, all files appear to be split into "pages with page types" and "pages without page types". Pages without page types are copied from the source to the destination directory and that's all. Pages *with* page-types go through the whole gamut: scan, filter, preprocess, linkify, htmlize, sanitize, format, and then they're written as "foo.html". + +I could be mistaken, but I don't think registering "css" as a page-type would work. Sure, I could then process the content to my heart's content, but at the end, my foo.css file would be saved as foo.html, which is NOT what I want. + +What I would like would be something in-between, where one could take `foo.css`, process it (in this case, run a minify over it) and output it as `foo.css`. + +How? diff --git a/doc/forum/Recent_changes_on_main_site_or_on_a_sidebar.mdwn b/doc/forum/Recent_changes_on_main_site_or_on_a_sidebar.mdwn new file mode 100644 index 000000000..0c328a9f1 --- /dev/null +++ b/doc/forum/Recent_changes_on_main_site_or_on_a_sidebar.mdwn @@ -0,0 +1 @@ +Is it possible to display the recent changes on the main site of the wiki or on a sidebar? diff --git a/doc/forum/Recent_changes_on_main_site_or_on_a_sidebar/comment_1_018b977ff7ee59fc53838e0c20c3a9a7._comment b/doc/forum/Recent_changes_on_main_site_or_on_a_sidebar/comment_1_018b977ff7ee59fc53838e0c20c3a9a7._comment new file mode 100644 index 000000000..1bc0cc509 --- /dev/null +++ b/doc/forum/Recent_changes_on_main_site_or_on_a_sidebar/comment_1_018b977ff7ee59fc53838e0c20c3a9a7._comment @@ -0,0 +1,11 @@ +[[!comment format=mdwn + username="jean_magnan" + ip="81.56.145.104" + subject="comment 1" + date="2011-12-19T10:20:59Z" + content=""" +Hi, +I have this line in the sidebar file, it says to show the titles and dates of the last 5 pages: + +[[!inline pages=\"*\" archive=\"yes\" show=\"5\"]] +"""]] diff --git a/doc/forum/Recent_changes_on_main_site_or_on_a_sidebar/comment_2_927c11f18315baa39f08ca4982ed2ab1._comment b/doc/forum/Recent_changes_on_main_site_or_on_a_sidebar/comment_2_927c11f18315baa39f08ca4982ed2ab1._comment new file mode 100644 index 000000000..2b6237bc4 --- /dev/null +++ b/doc/forum/Recent_changes_on_main_site_or_on_a_sidebar/comment_2_927c11f18315baa39f08ca4982ed2ab1._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + nickname="joey" + subject="comment 2" + date="2011-12-20T15:13:48Z" + content=""" +The [[RecentChanges]] page is a regular wiki page that inlines a few special pages with a special template. That content can be copied anywhere else in the wiki to get the same effect. +"""]] diff --git a/doc/forum/Refresh_or_recreate_style.css__63__.mdwn b/doc/forum/Refresh_or_recreate_style.css__63__.mdwn new file mode 100644 index 000000000..262b0e3c6 --- /dev/null +++ b/doc/forum/Refresh_or_recreate_style.css__63__.mdwn @@ -0,0 +1,40 @@ +I was trying to use plain blueview theme but that's not what I see in the installed style.css: + + ~/src/ikiwiki/themes/blueview$ grep bzed style.css + /* bzed theme for ikiwiki + ~/src/ikiwiki/themes/blueview$ wc -l style.css + 281 style.css + $ grep bzed ~/www/style.css + /* bzed theme for ikiwiki + /* bzed theme for ikiwiki + /* bzed theme for ikiwiki + /* bzed theme for ikiwiki + /* bzed theme for ikiwiki + /* bzed theme for ikiwiki + /* bzed theme for ikiwiki + /* bzed theme for ikiwiki + /* bzed theme for ikiwiki + /* bzed theme for ikiwiki + $ wc -l ~/www/style.css + 7913 + +I have installed ikiwiki to my home directory on the shared server and it seems the big css file is there too: + + $ grep bzed ~/bin/share/ikiwiki/themes/blueview/style.css + /* bzed theme for ikiwiki + /* bzed theme for ikiwiki + /* bzed theme for ikiwiki + /* bzed theme for ikiwiki + /* bzed theme for ikiwiki + /* bzed theme for ikiwiki + /* bzed theme for ikiwiki + /* bzed theme for ikiwiki + /* bzed theme for ikiwiki + /* bzed theme for ikiwiki + $ wc -l ~/bin/share/ikiwiki/themes/blueview/style.css + 7913 + +Is the style.css really supposed to be that big? +If not, how to create it from scratch? + +Reason why I'm debugging the css is that I'd like to make it better on small handset screens, like drop all margins, inline or hide sidebar etc. Chromium shows that the processed css is quite a mess. diff --git a/doc/forum/Refresh_or_recreate_style.css__63__/comment_1_3274be931d0b543c7f7cf641810817aa._comment b/doc/forum/Refresh_or_recreate_style.css__63__/comment_1_3274be931d0b543c7f7cf641810817aa._comment new file mode 100644 index 000000000..608dca0ce --- /dev/null +++ b/doc/forum/Refresh_or_recreate_style.css__63__/comment_1_3274be931d0b543c7f7cf641810817aa._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://mcfrisk.myopenid.com/" + nickname="mikko.rapeli" + subject="bug/feature in Makefile.PL" + date="2013-03-30T11:53:41Z" + content=""" +Theme style.css files were appended when installing in Makefile.PL. IMO overwriting the destination files is more correct. Sent a patch to Joey. +"""]] diff --git a/doc/forum/Regex_for_Valid_Characters_in_Filenames.mdwn b/doc/forum/Regex_for_Valid_Characters_in_Filenames.mdwn new file mode 100644 index 000000000..618576f81 --- /dev/null +++ b/doc/forum/Regex_for_Valid_Characters_in_Filenames.mdwn @@ -0,0 +1,19 @@ +I'm sure that this is documented somewhere but I've ransacked the wiki and I can't find it. :-( What are the allowed characters in an ikiwiki page name? I'm writing a simple script to make updating my blog easier and need to filter invalid characters (so far I've found that # and , aren't allowed ;-)). Thanks for any pointers. -- [[AdamShand]] + +> The default `wiki_file_regexp` matches filenames containing only +> `[-[:alnum:]_.:/+]` +> +> The titlepage() function will convert freeform text to a valid +> page name. See [[todo/should_use_a_standard_encoding_for_utf_chars_in_filenames]] +> for an example. --[[Joey]] + +>> Perfect, thanks! +>> +>> In the end I decided that I didn't need any special characters in filenames and replaced everything but alphanumeric characters with underscores. In addition to replacing bad characters I also collapse multiple underscores into a single one, and strip off trailing and leading underscores to make tidy filenames. If it's useful to anybody else here's a sed example: +>> +>> # echo "++ Bad: ~@#$%^&*()_=}{[];,? Iki: +_-:./ Num: 65.5 ++" | sed -e 's/[^A-Za-z0-9_]/_/g' -e 's/__*/_/g' -e 's/^_//g' -e 's/_$//g' +>> Bad_Iki_Num_65_5 +>> +>>--[[AdamShand]] + +[[!meta date="2008-01-18 23:40:02 -0500"]] diff --git a/doc/forum/Remove_tags_and_backlinks_on_particular_pages__63__.mdwn b/doc/forum/Remove_tags_and_backlinks_on_particular_pages__63__.mdwn new file mode 100644 index 000000000..ca99b2431 --- /dev/null +++ b/doc/forum/Remove_tags_and_backlinks_on_particular_pages__63__.mdwn @@ -0,0 +1,3 @@ +Hello, + +I would like to use !taglink to create a series of links, which are also tags, in the main part of my wikipages. But since these will already be on the page, there's no need to have them at the bottom of the page. Is there any way to turn off the display of tags (and also of backlinks) at the bottom of the page? I understand I could just delete the sections from page.tmpl but wondered if there was a more elegant way to do it. Thanks. diff --git a/doc/forum/Render_more_than_one_dest_page_from_same_source_page.mdwn b/doc/forum/Render_more_than_one_dest_page_from_same_source_page.mdwn new file mode 100644 index 000000000..e7362c903 --- /dev/null +++ b/doc/forum/Render_more_than_one_dest_page_from_same_source_page.mdwn @@ -0,0 +1,51 @@ +Is it possible to render more than one destination page from the same source page? +That is, same source, slightly different presentation at the other end, needing a different output file. + +> It's possible to render more than one output _file_ from a given source +> page. See, for example, the inline plugin's generation of rss files. +> This is done by calling `will_render()` and using `writefile()` to +> generate the additional files. Probably in a format hook if you want +> to generate html files. + +>> Thanks for the tip, I'll take a look at that. -- [[KathrynAndersen]] + +> It's not possible for one source file to represent multiple wiki pages. +> There is a 1:1 mapping between source filenames and page names. The +> difference between wiki pages and output files is that you can use +> wikilinks to link to wiki pages, etc. --[[Joey]] + +I have two problems that would be solved by being able to do this. + +[[!toc startlevel=2]] + +##"full" and "print" versions of a page. + +One has a page "foo", which is rendered into foo.html. +One also wants a foo-print.html page, which uses "page-print.tmpl" rather than "page.tmpl" as its template. + +I want to do this for every page on the site, automatically, so it isn't feasible to do it by hand. + +> Did you know that ikiwiki's `style.css` arranges for pages to display +> differently when printed out? Things like the Action bar are hidden in +> printouts (search for `@media print`). So I don't see a reason to need +> whole files for printing when you can use these style sheet tricks. +> --[[Joey]] + +>>Fair enough. --[[KathrynAndersen]] + +##"en" and "en-us" versions of a page. + +My site is in non-US English. However, I want US-English people to find my site when they search for it when they use US spelling on certain search terms (such as "optimise" versus "optimize"). This requires a (crude) US-English version of the site where the spellings are changed automatically, and the LANG is "en-us" rather than "en". (No, don't tell me to use keywords; Google ignores keywords and has for a number of years). + +So I want the page "foo" to render to "foo.en.html" and "foo.en-us.html" where the content is the same, just some automated word-substitution applied before foo.en-us.html is written. And do this for every page on the site. + +I can't do this with the "po" plugin, as it considers "en-us" not to be a valid language. And the "po" plugin is probably overkill for what I want anyway. + +But I'm not sure how to achieve the result I need. + +-- [[KathrynAndersen]] + +> Sounds like this could be considered a single page that generates two +> html files, so could be handled per above. --[[Joey]] + +>>Thanks! --[[KathrynAndersen]] diff --git a/doc/forum/Revision_history_for_single_pages.mdwn b/doc/forum/Revision_history_for_single_pages.mdwn new file mode 100644 index 000000000..76b4f7608 --- /dev/null +++ b/doc/forum/Revision_history_for_single_pages.mdwn @@ -0,0 +1,3 @@ +In other wikis [[for example|http://en.wikipedia.org/w/index.php?title=Main_Page&action=history]] in mediawiki there is a revision history of every single page (and not only of the whole wiki). + +Is it possible to have this in ikiwiki, too? diff --git a/doc/forum/Revision_history_for_single_pages/comment_1_d509d5d726cd7eab9472d723013f5ec4._comment b/doc/forum/Revision_history_for_single_pages/comment_1_d509d5d726cd7eab9472d723013f5ec4._comment new file mode 100644 index 000000000..242702e91 --- /dev/null +++ b/doc/forum/Revision_history_for_single_pages/comment_1_d509d5d726cd7eab9472d723013f5ec4._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://kerravonsen.dreamwidth.org/" + ip="202.173.183.92" + subject="comment 1" + date="2011-09-26T22:52:07Z" + content=""" +Er, but IkiWiki does have this. Click on \"History\" and you get the revision history of that page. +"""]] diff --git a/doc/forum/Revision_history_for_single_pages/comment_2_d39a6177fc4c1e3c3c2c4e2592be9e3d._comment b/doc/forum/Revision_history_for_single_pages/comment_2_d39a6177fc4c1e3c3c2c4e2592be9e3d._comment new file mode 100644 index 000000000..4ca754fd7 --- /dev/null +++ b/doc/forum/Revision_history_for_single_pages/comment_2_d39a6177fc4c1e3c3c2c4e2592be9e3d._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawk_MMtLPS7osC5MjX00q2ATjvvXPWqm0ik" + nickname="micheal" + subject="comment 2" + date="2011-09-27T17:49:15Z" + content=""" +Hm. I overlooked that ikiwiki.info has this. However my own wiki doesn't. Do I have adjust any settings to get this? +"""]] diff --git a/doc/forum/Revision_history_for_single_pages/comment_3_aecf2b031ace001afaa2a0f2b5f50c82._comment b/doc/forum/Revision_history_for_single_pages/comment_3_aecf2b031ace001afaa2a0f2b5f50c82._comment new file mode 100644 index 000000000..f3ddff19d --- /dev/null +++ b/doc/forum/Revision_history_for_single_pages/comment_3_aecf2b031ace001afaa2a0f2b5f50c82._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://smcv.pseudorandom.co.uk/" + nickname="smcv" + subject="comment 3" + date="2011-09-29T16:10:22Z" + content=""" +`historyurl` is the setting in the `.setup` file: it just links to an external history viewer, which is likely to be more advanced and better-suited to your [[RCS]] than anything built into ikiwiki would be. Use your favourite viewer for the RCS you're using - ikiwiki.info uses gitweb, you could also use something like cgit - and write `\[[file]]` where you want the filename to appear. +"""]] diff --git a/doc/forum/Right-to-left_support.mdwn b/doc/forum/Right-to-left_support.mdwn new file mode 100644 index 000000000..7ca4f9ad6 --- /dev/null +++ b/doc/forum/Right-to-left_support.mdwn @@ -0,0 +1,15 @@ +Does ikiwiki support RTL languages? I read somewhere it does, but I don't see +any mention of that here (or anywhere else... that info may be wrong). + +I'd like to add RTL support to my wiki, for text direction and maybe for the +page layout too. Before I edit my CSS, page.tmpl and possibly Perl for +automatic direction setting - does ikiwiki support this in any way? + +On my wiki (ikiwiki version from Debian 7 stable) everything is aligned to +the left, and unicode RTL characters cannot change that - the .tmpl and +css files would need to be changed, it seems. + +I will happily share my insights and code, if I manage to get anything +useful to work :-) + +--[[fr33domlover]] diff --git a/doc/forum/Right-to-left_support/comment_1_5b2bf4d037ae8db940296e6f58884927._comment b/doc/forum/Right-to-left_support/comment_1_5b2bf4d037ae8db940296e6f58884927._comment new file mode 100644 index 000000000..1e9558f96 --- /dev/null +++ b/doc/forum/Right-to-left_support/comment_1_5b2bf4d037ae8db940296e6f58884927._comment @@ -0,0 +1,21 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawmfcr1X7TXwuCju7vCBG6vii455SX1Qxro" + nickname="Mesar" + subject="comment 1" + date="2014-08-30T17:53:53Z" + content=""" +Hi, + +You need ikiwiki 3.20140227 or newer, which includes the patch to expose the language code/direction see [[todo/expose_html_language_and_direction/]] +After which you need to modify the templates to make use of the tags. + +I'm currently running this on http://addons.nvda-project.org +The config/templates can be [found here](https://bitbucket.org/nvdaaddonteam/ikiwiki-ctl) + +I haven't investigated how this functions when the po plugin is disabled, but I am guessing that you can simply enable the po plugin, define your master language, and miss out any slave languages. + +I would be intrested to hear feedback/what you got to work, as we are a bunch of blind people running the project above, so the correct markup was the goal in our case, I haven't had any feedback on its visual appearance. + + +--[[mhameed]] +"""]] diff --git a/doc/forum/Run_script_on_markdown_source.mdwn b/doc/forum/Run_script_on_markdown_source.mdwn new file mode 100644 index 000000000..614815c9b --- /dev/null +++ b/doc/forum/Run_script_on_markdown_source.mdwn @@ -0,0 +1 @@ +How can I add a button to each wiki page which launches an external application or script with the markdown code of the current page as input? diff --git a/doc/forum/See_rendered_old_revisions_via_pagehistory.mdwn b/doc/forum/See_rendered_old_revisions_via_pagehistory.mdwn new file mode 100644 index 000000000..465746ef9 --- /dev/null +++ b/doc/forum/See_rendered_old_revisions_via_pagehistory.mdwn @@ -0,0 +1 @@ +Via `historyurl` and `gitweb` I can view the markdown source of old revisions of a page (by clicking on `blob` in `gitweb`). Is it also possible to see the rendered versions of this old revisions directly (i.e. such they would be rendered by ikiwiki, not only the markdown source)? diff --git a/doc/forum/Setting_http__95__proxy.mdwn b/doc/forum/Setting_http__95__proxy.mdwn new file mode 100644 index 000000000..3bf8a76bc --- /dev/null +++ b/doc/forum/Setting_http__95__proxy.mdwn @@ -0,0 +1,22 @@ +Hi! My wiki is behind a proxy and, as I understood looking in the web, I need to set the environment variables using ENV inside the wiki's config. + +So far I tried: + +ENV: { + http_proxy => 'http://proxy.uns.edu.ar:1280/', + https_proxy => 'http://proxy.uns.edu.ar:1280/' +} + +without luck, as I get: + + +YAML::XS::Load Error: The problem: + + found unexpected ':' + +was found at document: 1, line: 85, column: 22 +while scanning a plain scalar at line: 85, column: 3 +usage: ikiwiki [options] source dest + ikiwiki --setup configfile + +What am I missing? (maybe learning perl?) diff --git a/doc/forum/Setting_http__95__proxy/comment_1_350a7c4834c9f422e107b646cdbae3b0._comment b/doc/forum/Setting_http__95__proxy/comment_1_350a7c4834c9f422e107b646cdbae3b0._comment new file mode 100644 index 000000000..3623652ab --- /dev/null +++ b/doc/forum/Setting_http__95__proxy/comment_1_350a7c4834c9f422e107b646cdbae3b0._comment @@ -0,0 +1,20 @@ +[[!comment format=mdwn + username="http://smcv.pseudorandom.co.uk/" + nickname="smcv" + subject="comment 1" + date="2012-10-10T13:45:10Z" + content=""" +If your wiki configuration is written in YAML (it says IkiWiki::Setup::Yaml near the top), the correct syntax is something like + + ENV: + http_proxy: http://proxy.uns.edu.ar:1280/ + https_proxy: http://proxy.uns.edu.ar:1280/ + +or + + ENV: { http_proxy: 'http://proxy.uns.edu.ar:1280/', https_proxy: 'http://proxy.uns.edu.ar:1280/' } + +(many variations are possible, see <http://www.yaml.org/>). + +The syntax you quoted is correct for Perl-syntax setup files (which will mention IkiWiki::Setup::Standard near the top), but not YAML ones. +"""]] diff --git a/doc/forum/Setting_template_variable_from_config_file__63__.mdwn b/doc/forum/Setting_template_variable_from_config_file__63__.mdwn new file mode 100644 index 000000000..ac7631e60 --- /dev/null +++ b/doc/forum/Setting_template_variable_from_config_file__63__.mdwn @@ -0,0 +1 @@ +Is ist possible to set a template variable from the config file? diff --git a/doc/forum/Setting_template_variable_from_config_file__63__/comment_1_bb4b5a7a49f33d660b5116fc0ce3c92d._comment b/doc/forum/Setting_template_variable_from_config_file__63__/comment_1_bb4b5a7a49f33d660b5116fc0ce3c92d._comment new file mode 100644 index 000000000..6dddb1f21 --- /dev/null +++ b/doc/forum/Setting_template_variable_from_config_file__63__/comment_1_bb4b5a7a49f33d660b5116fc0ce3c92d._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://kerravonsen.dreamwidth.org/" + ip="202.173.183.92" + subject="comment 1" + date="2011-08-29T23:07:21Z" + content=""" +With the [[plugins/contrib/field]] plugin one can; set the `field_allow_config` config value to 1, and the config variables are accessible with a \"CONFIG-\" prefix. That is, if you set a value \"foo\" in the config file, then you would access it in in the template as `<TMPL_VAR CONFIG-FOO>`. +"""]] diff --git a/doc/forum/Setting_up_a_development_environment.mdwn b/doc/forum/Setting_up_a_development_environment.mdwn new file mode 100644 index 000000000..0b4e555c1 --- /dev/null +++ b/doc/forum/Setting_up_a_development_environment.mdwn @@ -0,0 +1,32 @@ +Hi, + +I'm trying to setup a development environment to hack on the comments plugin and I'm having problems getting my Ikiwiki CGI to use my git checkout as the libdir and templatedir instead of the system one. + +My <tt>.setup</tt> contains: + + srcdir => '/home/francois/wiki/testblog', + destdir => '/var/www/testblog', + url => 'http://localhost/testblog', + cgiurl => 'http://localhost/testblog/ikiwiki.cgi', + cgi_wrapper => '/var/www/testblog/ikiwiki.cgi', + templatedir => '/home/francois/devel/remote/ikiwiki/templates', + underlaydir => '/home/francois/devel/remote/ikiwiki/doc', + libdir => '/home/francois/devel/remote/ikiwiki', + ENV => {}, + git_wrapper => '/home/francois/wiki/testblog.git/hooks/post-update', + +Now, if I modify <tt>~/devel/remote/ikiwiki/templates/comment.tmpl</tt>, my changes don't appear when I add a comment to a blog post. On the other hand, if I hack <tt>/usr/share/ikiwiki/templates/comment.tmpl</tt> and cause the page to be rebuilt by adding a new comment then that does have an effect. + +The same is true for <tt>~/devel/remote/ikiwiki/Ikiwiki/Plugin/comments.pm</tt> (doesn't appear to be used) and <tt>/usr/share/perl5/Ikiwiki/Plugin/comments.pm</tt> (my hacks affect pages as they are recompiled). + +I must be missing something obvious, but the [[ikiwiki development environment tips]] didn't help me... + +Cheers, + +[[Francois|fmarier]] + +> I updated the [[ikiwiki development environment tips]] page with my +> approach to running ikiwiki from the git checkout (with changes). For +> the templates, also make sure that you do not have custom templates in +> your src dir as they will be used instead of those from the template +> dir if found. --GB diff --git a/doc/forum/Should_files_in_.ikiwiki_be_committed_and_pushed__63__.mdwn b/doc/forum/Should_files_in_.ikiwiki_be_committed_and_pushed__63__.mdwn new file mode 100644 index 000000000..f5b1d58d1 --- /dev/null +++ b/doc/forum/Should_files_in_.ikiwiki_be_committed_and_pushed__63__.mdwn @@ -0,0 +1,14 @@ +In my local working copy, I discovered a .ikiwiki directory with files and subdirectories. What are they for in a working copy? Should them be committed to central repository (origin) on remote server? + + $ git status + # On branch master + # Changes to be committed: + # (use "git reset HEAD <file>..." to unstage) + # + # new file: .ikiwiki/commitlock + # new file: .ikiwiki/indexdb + # new file: .ikiwiki/lockfile + # new file: .ikiwiki/transient/recentchanges/change_0326ad7c7aa2c40b8db5d59033ecda7ed4d61295._change + <snip> + +Should these be committed and pushed? diff --git a/doc/forum/Should_files_in_.ikiwiki_be_committed_and_pushed__63__/comment_1_8e65d7d8298e3c31d2a16446a71c8049._comment b/doc/forum/Should_files_in_.ikiwiki_be_committed_and_pushed__63__/comment_1_8e65d7d8298e3c31d2a16446a71c8049._comment new file mode 100644 index 000000000..43e7a0068 --- /dev/null +++ b/doc/forum/Should_files_in_.ikiwiki_be_committed_and_pushed__63__/comment_1_8e65d7d8298e3c31d2a16446a71c8049._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + nickname="joey" + subject="comment 1" + date="2011-12-22T16:12:42Z" + content=""" +Absolutely not. If you use ikiwiki-makerepo to set up ikiwiki, it makes a `.gitignore` containing `/.ikiwiki` + +The `.ikiwiki` directory is where ikiwiki stores all the state it needs to track about a given build of a wiki. +"""]] diff --git a/doc/forum/Should_not_create_an_existing_page.mdwn b/doc/forum/Should_not_create_an_existing_page.mdwn new file mode 100644 index 000000000..b9500757f --- /dev/null +++ b/doc/forum/Should_not_create_an_existing_page.mdwn @@ -0,0 +1,15 @@ +[[!meta date="2007-01-08 14:55:31 +0000"]] + +This might be a bug, but will discuss it here first. +Clicking on an old "?" or going to a create link but new Markdown content exists, should not go into "create" mode, but should do a regular "edit". + +> I belive that currently it does a redirect to the new static web page. +> At least that's the intent of the code. --[[Joey]] + +>> Try at your site: `?page=discussion&from=index&do=create` +>> It brings up an empty textarea to start a new webpage -- even though it already exists here. --reed + +>>> Ah, right. Notice that the resulting form allows saving the page as +>>> discussion, or users/discussion, but not index/discussion, since this +>>> page already exists. If all the pages existed, it would do the redirect +>>> thing. --[[Joey]] diff --git a/doc/forum/Sidebar_with_links__63__.mdwn b/doc/forum/Sidebar_with_links__63__.mdwn new file mode 100644 index 000000000..790ee85a2 --- /dev/null +++ b/doc/forum/Sidebar_with_links__63__.mdwn @@ -0,0 +1,58 @@ +I'm trying to create a template to use as a sidebar with links. The template will be static +(no variables are used). I first created a page with this directive: \[[!template id=sidebar]], +and then created the template with the web interface. + +This is the code I put in the template: + + <div class="infobox"> + <ul> + <li>\[[Existing internal link|exists]]</li> + <li>\[[Non-existing internal link|doesnotexist]]</li> + <li>[External link](http://google.com/)</li> + </ul> + <http://google.com/> + </div> + +This is the relevant part of the resulting html file `template/sidebar.html`: + + <div class="infobox"> + <ul> + <li><a href="../exists.html">Existing internal link</a></li> + <li><span class="createlink"><a href="http://localhost/cgi-bin/itesohome.cgi?page=doesnotexist&from=templates%2Fsidebar&do=create" rel="nofollow">?</a>Non-existing internal link</span></li> + <li>[External link](http://google.com/)</li> + </ul> + </div> + +Note that the `<http://google.com/>` link has disappeared, and that `[External link](http://google.com/)` +has been copied literally instead of being converted to a link, as I expected. + +> Templates aren't Markdown page. [[ikiwiki/WikiLink]] only are expanded. --[[Jogo]] + +>> Thanks for the help Jogo. Looking at the [[templates]] page, it says that +"...you can include WikiLinks and all other forms of wiki markup in the template." I read this +to mean that a template may indeed include Markdown. Am I wrong in my interpratation? --[[buo]] + +>> I discovered that if I eliminate all html from my sidebar.mdwn template, the links are +rendered properly. It seems that the mix of Markdown and html is confusing some part of +Ikiwiki. --[[buo]] + +Worse, this is the relevant part of the html file of the page that includes the template: + + <div class="infobox"> + <ul> + <li><span class="selflink">Existing internal link</span></li> + <li><span class="createlink"><a href="http://localhost/cgi-bin/itesohome.cgi?page=doesnotexist&from=research&do=create" rel="nofollow">?</a>Non-existing internal link</span></li> + <li>[External link](http://google.com/)</li> + </ul> + </div> + +Note that the `Existing internal link` is no longer a link. It is only text. + +What am I doing wrong? Any help or pointers will be appreciated. --[[buo]] + +----- + +I think I have figured this out. I thought the template was filled and then +processed to convert Markdown to html. Instead, the text in each variable is +processed and then the template is filled. I somehow misunderstood the +[[templates]] page. -- [[buo]] diff --git a/doc/forum/Slow_ikiwiki_after_first_run.mdwn b/doc/forum/Slow_ikiwiki_after_first_run.mdwn new file mode 100644 index 000000000..db07f6dc3 --- /dev/null +++ b/doc/forum/Slow_ikiwiki_after_first_run.mdwn @@ -0,0 +1 @@ +I have local ikiwiki on my notebook. When I save an edit the first time after booting and logging in, saving is very slow. Any idea how to fix this? diff --git a/doc/forum/Spaces_in_URLs.mdwn b/doc/forum/Spaces_in_URLs.mdwn new file mode 100644 index 000000000..4749f4dc5 --- /dev/null +++ b/doc/forum/Spaces_in_URLs.mdwn @@ -0,0 +1,14 @@ +There is one file on my site that had a space in the name; +on my old site, this link worked: +[http://dada.pink/scarsdale/Statement 20140527.pdf](http://dada.pink/scarsdale/Statement 20140527.pdf) + +Now that I've moved to Ikiwiki, that doesn't work. So I moved the file here: +[http://dada.pink/scarsdale/Statement_20140527.pdf](http://dada.pink/scarsdale/Statement_20140527.pdf) + +Is there a better approach to maintaining this link than setting an alias in Apache? + +> You can add the space character to the `wiki_file_chars` argument in your setup file. -- [[Jon]] + +>> a space character is not allowed in a url; user agents that read one usually represent it in percent encoded form (`%20`). if you use that, things also work for direct links, which i assume caused the problem (for both the links in the original description render correctly): `\[[http://dada.pink/scarsdale/Statement%2020140527.pdf]]` renders [[http://dada.pink/scarsdale/Statement%2020140527.pdf]]. +>> +>> spaces are allowed in internal pages because wiki page names are not urls per se but converted using conversion rules -- this allows people to not think about url rules and just link to pages, but when you're linking outside ikiwiki, some strings just aren't valid urls. --[[chrysn]] diff --git a/doc/forum/Spaces_in_wikilinks.mdwn b/doc/forum/Spaces_in_wikilinks.mdwn new file mode 100644 index 000000000..9326ac448 --- /dev/null +++ b/doc/forum/Spaces_in_wikilinks.mdwn @@ -0,0 +1,104 @@ +[[!meta date="2007-07-02 13:21:29 +0000"]] + +# Spaces in WikiLinks? + +Hello Joey, + +I've just switched from ikiwiki 2.0 to ikiwiki 2.2 and I'm really surprised +that I can't use the spaces in WikiLinks. Could you please tell me why the spaces +aren't allowed in WikiLinks now? + +My best regards, + +--[[PaweB|ptecza]] + +> See [[bugs/Spaces_in_link_text_for_ikiwiki_links]] + +---- + +# Build in OpenSolaris? + +Moved to [[bugs/build_in_opensolaris]] --[[Joey]] + +---- + +# Various ways to use Subversion with ikiwiki + +I'm playing around with various ways that I can use subversion with ikiwiki. + +* Is it possible to have ikiwiki point to a subversion repository which is on a different server? The basic checkin/checkout functionality seems to work but there doesn't seem to be any way to make the post-commit hook work for a non-local server? + +> This is difficult to do since ikiwiki's post-commit wrapper expects to +> run on a machine that contains both the svn repository and the .ikiwiki +> state directory. However, with recent versions of ikiwiki, you can get +> away without running the post-commit wrapper on commit, and all you lose +> is the ability to send commit notification emails. + +> (And now that [[recentchanges]] includes rss, you can just subscribe to +> that, no need to worry about commit notification emails anymore.) + +* Is it possible / sensible to have ikiwiki share a subversion repository with other data (either completely unrelated files or another ikiwiki instance)? This works in part but again the post-commit hook seems problematic. + +--[[AdamShand]] + +> Sure, see ikiwiki's subversion repository for example of non-wiki files +> in the same repo. If you have two wikis in one repository, you will need +> to write a post-commit script that calls the post-commit wrappers for each +> wiki. + +---- + +# Regex for Valid Characters in Filenames + +I'm sure that this is documented somewhere but I've ransacked the wiki and I can't find it. :-( What are the allowed characters in an ikiwiki page name? I'm writing a simple script to make updating my blog easier and need to filter invalid characters (so far I've found that # and , aren't allowed ;-)). Thanks for any pointers. -- [[AdamShand]] + +> The default `wiki_file_regexp` matches filenames containing only +> `[-[:alnum:]_.:/+]` +> +> The titlepage() function will convert freeform text to a valid +> page name. See [[todo/should_use_a_standard_encoding_for_utf_chars_in_filenames]] +> for an example. --[[Joey]] + +>> Perfect, thanks! +>> +>> In the end I decided that I didn't need any special characters in filenames and replaced everything but alphanumeric characters with underscores. In addition to replacing bad characters I also collapse multiple underscores into a single one, and strip off trailing and leading underscores to make tidy filenames. If it's useful to anybody else here's a sed example: +>> +>> # echo "++ Bad: ~@#$%^&*()_=}{[];,? Iki: +_-:./ Num: 65.5 ++" | sed -e 's/[^A-Za-z0-9_]/_/g' -e 's/__*/_/g' -e 's/^_//g' -e 's/_$//g' +>> Bad_Iki_Num_65_5 +>> +>>--[[AdamShand]] + +# Upgrade steps from RecentChanges CGI to static page? + +Where are the upgrade steps for RecentChanges change from CGI to static feed? +I run multiple ikiwiki-powered sites on multiple servers, but today I just upgraded one to 2.32.3. +Please have a look at +<http://bsdwiki.reedmedia.net/wiki/recentchanges.html> +Any suggestions? + +> There are no upgrade steps required. It does look like you need to enable +> the meta plugin to get a good recentchanges page though.. --[[Joey]] + +# News site where articles are submitted and then reviewed before posting? + +I am considering moving a news site to Ikiwiki. I am hoping that Ikiwiki has a feature where anonymous posters can submit a form that moderators can review and then accept for it to be posted on a news webpage (like front page of the website). + +> Well, you can have one blog that contains unreviewed articles, and +> moderators can then add a tag that makes the article show up in the main +> news feed. There's nothing stopping someone submitting an article +> pre-tagged though. If you absolutely need to lock that down, you could +> have one blog with unreviewed articles in one subdirectory, and reviewers +> then move the file over to another subdirectory when they're ready to +> publish it. (This second subdirectory would be locked to prevent others +> from writing to it.) --[[Joey]] + +Also it would be good if the news page would keep maybe just the latest 10 entries with links to an archive that make it easy to browse to old entries by date. (Could have over a thousand news articles.) + +> The inline plugin allows setting up things like this. + +Plus users be able to post feedback to news items. If anonymous, they must be approved first. I'd prefer to not use normal "wiki" editor for feedback. + +Any thoughts or examples on this? Any links to examples of news sites or blogs with outside feedback using ikiwiki? + +Thanks --[[JeremyReed]] + diff --git a/doc/forum/Split_a_wiki.mdwn b/doc/forum/Split_a_wiki.mdwn new file mode 100644 index 000000000..f1c7e50da --- /dev/null +++ b/doc/forum/Split_a_wiki.mdwn @@ -0,0 +1,21 @@ +Is it possible to split an ikiwiki (with git backend) in to two? + +Suppose I have an ikiwiki called myiki + +which contains the pages + +pageA1,pageA2,...,pageB1,pageB2,... + +now I want to have two wikis called myikiA and myikiB + +such that + +myikiA contains pageA1,pageA2,... + +The history of myikiA should contain the whole history of those pages but no history of pageB1,pageB2,... + +and + +myikiB contains pageB1,pageB2,... + +The history of myikiB should contain the whole history of those pages but no history of pageA1,pageA2,... diff --git a/doc/forum/Split_a_wiki/comment_1_1599c26891b2071a2f1ca3fd90627fc4._comment b/doc/forum/Split_a_wiki/comment_1_1599c26891b2071a2f1ca3fd90627fc4._comment new file mode 100644 index 000000000..66401914a --- /dev/null +++ b/doc/forum/Split_a_wiki/comment_1_1599c26891b2071a2f1ca3fd90627fc4._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://kerravonsen.dreamwidth.org/" + ip="202.173.183.92" + subject="comment 1" + date="2011-12-03T19:45:06Z" + content=""" +The only thing I can think of is to clone the wiki, and for WikiA, delete PageB, and for WikiB, delete PageA. This won't remove the histories of those pages, but it will at least remove those pages. +"""]] diff --git a/doc/forum/Split_a_wiki/comment_2_1c54d3594f0350340f8dfb3e95c29ffd._comment b/doc/forum/Split_a_wiki/comment_2_1c54d3594f0350340f8dfb3e95c29ffd._comment new file mode 100644 index 000000000..8040ad5e2 --- /dev/null +++ b/doc/forum/Split_a_wiki/comment_2_1c54d3594f0350340f8dfb3e95c29ffd._comment @@ -0,0 +1,20 @@ +[[!comment format=mdwn + username="http://smcv.pseudorandom.co.uk/" + nickname="smcv" + subject="comment 2" + date="2011-12-04T13:37:27Z" + content=""" +If just deleting the unwanted pages is insufficient (e.g. perhaps they +contain information that must not be made public), you can split a git +repository (including ikiwiki repositories) with `git filter-branch` (see +[this stackoverflow question](http://stackoverflow.com/questions/359424/detach-subdirectory-into-separate-git-repository), +for instance). + +This preserves the history of each individual page, but rewrites the +entire history of the repository (it re-does every commit, pretending +that the addition of the omitted pages and every subsequent edit to +them had never happened); it's like `git rebase` but more so. + +As a result, existing branches will no longer be able to push to the +rewritten repository. +"""]] diff --git a/doc/forum/Split_a_wiki/comment_3_9eac1d1b93df27d849acc574b1f0f26d._comment b/doc/forum/Split_a_wiki/comment_3_9eac1d1b93df27d849acc574b1f0f26d._comment new file mode 100644 index 000000000..e2dbd2546 --- /dev/null +++ b/doc/forum/Split_a_wiki/comment_3_9eac1d1b93df27d849acc574b1f0f26d._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawk_MMtLPS7osC5MjX00q2ATjvvXPWqm0ik" + nickname="micheal" + subject="comment 3" + date="2011-12-04T14:03:55Z" + content=""" +@smcv: Thanks, that looks promising. The example from stackoverflow is with subdirectories. What do I have to change to match a list of single files (pages) instead? +"""]] diff --git a/doc/forum/Split_a_wiki/comment_4_e193ba447c0188f72ba589180b5d529e._comment b/doc/forum/Split_a_wiki/comment_4_e193ba447c0188f72ba589180b5d529e._comment new file mode 100644 index 000000000..450529697 --- /dev/null +++ b/doc/forum/Split_a_wiki/comment_4_e193ba447c0188f72ba589180b5d529e._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawk_MMtLPS7osC5MjX00q2ATjvvXPWqm0ik" + nickname="micheal" + subject="comment 4" + date="2011-12-09T09:21:05Z" + content=""" +I have put the question on stackoverflow: http://stackoverflow.com/questions/8443372/split-an-ikiwiki +"""]] diff --git a/doc/forum/TMPL__95__VAR_IS__95__ADMIN.mdwn b/doc/forum/TMPL__95__VAR_IS__95__ADMIN.mdwn new file mode 100644 index 000000000..c8eec0bc9 --- /dev/null +++ b/doc/forum/TMPL__95__VAR_IS__95__ADMIN.mdwn @@ -0,0 +1 @@ +Could someone point out where I could implement a template variable? I would like an IS_ADMIN. I'm pretty sure I could do it but I'm sure someone has an opinion on where this might belong. I want to hide the edit links on my blog for non-admin users. diff --git a/doc/forum/TMPL__95__VAR_IS__95__ADMIN/comment_1_3172568473e9b79ad7ab623afd19411a._comment b/doc/forum/TMPL__95__VAR_IS__95__ADMIN/comment_1_3172568473e9b79ad7ab623afd19411a._comment new file mode 100644 index 000000000..7967ea6f0 --- /dev/null +++ b/doc/forum/TMPL__95__VAR_IS__95__ADMIN/comment_1_3172568473e9b79ad7ab623afd19411a._comment @@ -0,0 +1,13 @@ +[[!comment format=mdwn + username="http://smcv.pseudorandom.co.uk/" + nickname="smcv" + subject="comment 1" + date="2011-02-23T11:14:14Z" + content=""" +This isn't possible without out-of-band mechanisms (Javascript or something). +ikiwiki produces static HTML; template variables are evaluated when the HTML +is compiled, and admins and non-admins see the exact same file. + +(More precisely, URLs containing `/ikiwiki.cgi/` are dynamically-generated +pages; everything else is static.) +"""]] diff --git a/doc/forum/TMPL__95__VAR_IS__95__ADMIN/comment_2_4302d56a6fe68d17cc42d26e6f3566c2._comment b/doc/forum/TMPL__95__VAR_IS__95__ADMIN/comment_2_4302d56a6fe68d17cc42d26e6f3566c2._comment new file mode 100644 index 000000000..5e34ab4f8 --- /dev/null +++ b/doc/forum/TMPL__95__VAR_IS__95__ADMIN/comment_2_4302d56a6fe68d17cc42d26e6f3566c2._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://smcv.pseudorandom.co.uk/" + nickname="smcv" + subject="comment 2" + date="2011-02-23T11:16:56Z" + content=""" +See [[bugs/logout in ikiwiki]] for discussion of a similar issue. +"""]] diff --git a/doc/forum/TMPL__95__VAR_IS__95__ADMIN/comment_3_4cc44e61b9c28a2d524fa874f115041a._comment b/doc/forum/TMPL__95__VAR_IS__95__ADMIN/comment_3_4cc44e61b9c28a2d524fa874f115041a._comment new file mode 100644 index 000000000..e152091bc --- /dev/null +++ b/doc/forum/TMPL__95__VAR_IS__95__ADMIN/comment_3_4cc44e61b9c28a2d524fa874f115041a._comment @@ -0,0 +1,14 @@ +[[!comment format=mdwn + username="justint" + ip="24.182.207.250" + subject="IS_ADMIN template wouldn't work" + date="2011-02-23T16:03:31Z" + content=""" +Ok, I think I get it. The template is used when IkiWiki is compiling the static pages, then users access the static pages. So at the time the templates are compiled there isn't a concept of who is accessing the page or what their session may be like (be it admin or anon or whatever). + +Is there a simple way to serve a different static page based on session information? Off the top of my head I would say no but I thought I would ask. I suppose I could try to compile two static sites, one for me and one for the world. That would solve my IS_ADMIN problem, but I don't think its a solution for similar types of things. + +I like ikiwiki for what it is, I get the feeling I may be asking it to do something it wasn't meant to do. If so I'd appreciate it if someone told me to stop trying. [[users/justint]] + + +"""]] diff --git a/doc/forum/TMPL__95__VAR_IS__95__ADMIN/comment_4_33143bad68f3f6beae963a3d0ec5d0bd._comment b/doc/forum/TMPL__95__VAR_IS__95__ADMIN/comment_4_33143bad68f3f6beae963a3d0ec5d0bd._comment new file mode 100644 index 000000000..ab7370c5a --- /dev/null +++ b/doc/forum/TMPL__95__VAR_IS__95__ADMIN/comment_4_33143bad68f3f6beae963a3d0ec5d0bd._comment @@ -0,0 +1,53 @@ +[[!comment format=mdwn + username="http://smcv.pseudorandom.co.uk/" + nickname="smcv" + subject="comment 4" + date="2011-02-23T16:19:28Z" + content=""" +> ... at the time the templates are compiled there isn't a concept of who is accessing the page + +Yes, this is the problem with what you're asking for. + +> Is there a simple way to serve a different static page based on session information? + +No, the thing serving the static pages is your web server; IkiWiki isn't involved +at all. + +> I suppose I could try to compile two static sites, one for me and one for the world + +I've done similar in the past with two setup files, under the same user ID, running +different checkouts of the same git repository - one for me, on https with +[[plugins/httpauth]], and one for the world, with only [[plugins/openid]]. You have +to make them write their git wrappers to different filenames, and make the real +git hook be a shell script that runs one wiki's wrapper, then the other, to refresh +both wikis when something gets committed. + +It's a bit fiddly to admin (you have to duplicate most setup changes in the two +setup files), but can be made to work. I've given up on that in favour of having +a single wiki reachable from both http and https, with [[plugins/httpauth]] +only working over https. + +> I get the feeling I may be asking it to do something it wasn't meant to do. + +Pretty much, yes. + +> If so I'd appreciate it if someone told me to stop trying. + +I can help! \"Stop trying.\" :-) + +But, if you want this functionality badly enough, one way you could get +it would be to have all the links on all the pages (for the benefit of +`NoScript` users), use Javascript to make an XMLHTTPRequest (or something) +to to a CGI action provided by a [[plugin|plugins/write]] +(`ikiwiki.cgi?do=amiadminornot` or something), and if that says the user +isn't an admin, hide some of the links to not confuse them. + +That would break the normal way that people log in to ikiwiki (by trying +to do something that needs them logged-in, like editing), so you'd also +want to add a \"Log In\" button or link (or just remember that editing your +Preferences has the side-effect of logging you in). + +Note that hiding the links isn't useful for security, only for +usability - the actual edit obviously needs to check whether the +user is a logged-in admin, and it already does. +"""]] diff --git a/doc/forum/TMPL__95__VAR_IS__95__ADMIN/comment_5_ef790766456d723670f52cc9e3955e90._comment b/doc/forum/TMPL__95__VAR_IS__95__ADMIN/comment_5_ef790766456d723670f52cc9e3955e90._comment new file mode 100644 index 000000000..5cbc0d206 --- /dev/null +++ b/doc/forum/TMPL__95__VAR_IS__95__ADMIN/comment_5_ef790766456d723670f52cc9e3955e90._comment @@ -0,0 +1,12 @@ +[[!comment format=mdwn + username="justint" + ip="24.182.207.250" + subject="easy money" + date="2011-02-23T17:47:35Z" + content=""" +I've done a plugin, but I haven't done a CGI one yet. I can probably handle it though. I have a little javascript, I could probably do that too. + +I'm fuzzy on the log in bit, I don't know how to bring up a log in page in IkiWiki (that would just return to the calling page and not an edit page). + +If I were going to do this I'd want to have a log out button appear when the user is logged in. Is it possible to add a log out function to the same plugin? +"""]] diff --git a/doc/forum/TMPL__95__VAR_IS__95__ADMIN/comment_6_3db50264e01c8fad2e5567b5a9c7b6dc._comment b/doc/forum/TMPL__95__VAR_IS__95__ADMIN/comment_6_3db50264e01c8fad2e5567b5a9c7b6dc._comment new file mode 100644 index 000000000..4d1c224b7 --- /dev/null +++ b/doc/forum/TMPL__95__VAR_IS__95__ADMIN/comment_6_3db50264e01c8fad2e5567b5a9c7b6dc._comment @@ -0,0 +1,23 @@ +[[!comment format=mdwn + username="http://smcv.pseudorandom.co.uk/" + nickname="smcv" + subject="comment 6" + date="2011-02-23T18:08:37Z" + content=""" +> I'm fuzzy on the log in bit, I don't know how to bring up a log in page in IkiWiki + +Cheap hack: make a link to `cgiurl(do => prefs)` and the user will have +to press Back a couple of times when they've logged in :-) + +Less-cheap hack: have a CGI plugin that responds to `do=login` by doing +basically the same thing as `IkiWiki::needsignin`, but instead of +returning to the `QUERY_STRING`, return to the HTTP referer, or +a page whose name is passed in the query string, or some such. + +> If I were going to do this I'd want to have a log out button appear +> when the user is logged in. Is it possible to add a log out function to the same plugin? + +I don't see why not; you could create it from Javascript for logged-in +users only. That'd close the bug [[bugs/logout in ikiwiki]] (see that +bug for related ideas). +"""]] diff --git a/doc/forum/TMPL__95__VAR_IS__95__ADMIN/comment_7_bdc5c96022fdb8826b57d68a41ef6ca0._comment b/doc/forum/TMPL__95__VAR_IS__95__ADMIN/comment_7_bdc5c96022fdb8826b57d68a41ef6ca0._comment new file mode 100644 index 000000000..79fd8516f --- /dev/null +++ b/doc/forum/TMPL__95__VAR_IS__95__ADMIN/comment_7_bdc5c96022fdb8826b57d68a41ef6ca0._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="justint" + ip="24.182.207.250" + subject="Continuing discussion..." + date="2011-02-24T02:59:04Z" + content=""" +Ok, I'll go over to the [[bugs/logout_in_ikiwiki]] page. Thank you for your help. +"""]] diff --git a/doc/forum/Template_variables.mdwn b/doc/forum/Template_variables.mdwn new file mode 100644 index 000000000..f0a8fe86c --- /dev/null +++ b/doc/forum/Template_variables.mdwn @@ -0,0 +1,20 @@ +Hi, + +I am very confused with the template variables. I cannot find any documentation of which ones are available, where are they set, etc. + +I see that in the default templates, there are things like this (rssitem.tmpl): + + <TMPL_IF AUTHOR> + <title><TMPL_VAR AUTHOR ESCAPE=HTML>: <TMPL_VAR TITLE> + + + <TMPL_VAR TITLE> + + +But I don't get this in my RSS, and I don't know how to add those variables, except for mentions of some plugins that are not yet merged. + +I also see that the 'author' data is one of the fields that can be set with the meta directive, but I understand that meta is processed after the templates, so it cannot be the source; right? + +Any help appreciated! + +PS: what I am tring to do now is to add a proper author field to my feeds, but I also want to understand how to use the templating system. diff --git a/doc/forum/Template_variables/comment_1_6a2ab9450dbfb8c4ef78e7af2a1b51eb._comment b/doc/forum/Template_variables/comment_1_6a2ab9450dbfb8c4ef78e7af2a1b51eb._comment new file mode 100644 index 000000000..5f5ce1fce --- /dev/null +++ b/doc/forum/Template_variables/comment_1_6a2ab9450dbfb8c4ef78e7af2a1b51eb._comment @@ -0,0 +1,11 @@ +[[!comment format=mdwn + username="http://tincho.org/" + nickname="tincho" + subject="Update" + date="2013-10-02T05:40:59Z" + content=""" +well, it seems that if I do set up the author and authorurl meta variables in the index.mdwn, I get the author in the ATOM feed file. I don't know why, if it is because the feed creation is invoked from that page or if it is automagically taken from the main page. + +At the same time, the rss feed does not get the author, even if the default template should have included it for each item in the feed. + +"""]] diff --git a/doc/forum/Template_variables/comment_2_9b366736171e45d5afd8247ff38501d1._comment b/doc/forum/Template_variables/comment_2_9b366736171e45d5afd8247ff38501d1._comment new file mode 100644 index 000000000..30b4a7e6a --- /dev/null +++ b/doc/forum/Template_variables/comment_2_9b366736171e45d5afd8247ff38501d1._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawlcaGfdn9Kye1Gc8aGb67PDVQW4mKbQD7E" + nickname="Amitai" + subject="comment 2" + date="2013-11-05T19:18:10Z" + content=""" +What version of ikiwiki are you running? [[news/Version 3.20130904]] introduced some changes to the RSS and Atom templates that may help you. +"""]] diff --git a/doc/forum/Template_variables/comment_3_727f8a407dc57e4abf48cdcec4ead666._comment b/doc/forum/Template_variables/comment_3_727f8a407dc57e4abf48cdcec4ead666._comment new file mode 100644 index 000000000..d26bc2f66 --- /dev/null +++ b/doc/forum/Template_variables/comment_3_727f8a407dc57e4abf48cdcec4ead666._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="https://tincho.startssl.com/" + nickname="tincho" + subject="comment 3" + date="2013-11-05T19:35:45Z" + content=""" +I am using the same version as you say. And the entry template has a place for author that does not get populated. The page template does not, on the other hand. +"""]] diff --git a/doc/forum/The_requested_URL___47____126__jean__47__blog__47__ikiwiki.cgi_was_not_found_on_this_server..mdwn b/doc/forum/The_requested_URL___47____126__jean__47__blog__47__ikiwiki.cgi_was_not_found_on_this_server..mdwn new file mode 100644 index 000000000..4061a7348 --- /dev/null +++ b/doc/forum/The_requested_URL___47____126__jean__47__blog__47__ikiwiki.cgi_was_not_found_on_this_server..mdwn @@ -0,0 +1,11 @@ +Hi, +Installed ikiwiki on my ubuntu (04.10) box; after creating a blog according to your setup instructions I cannot edit files on the web interface, and I get this errer «The requested URL /~jean/blog/ikiwiki.cgi was not found on this server.» +I have no idea what to do (sorry for my ignorance) + +tia, + +> Make sure you have a `~/public_html/ikiwiki.cgi`. Your setup +> file should generate that via the `cgi_wrapper` option. +> +> Maybe you need to follow the [[tips/dot_cgi]] tip to make apache see it. +> --[[Joey]] diff --git a/doc/forum/The_requested_URL___47____126__jean__47__blog__47__ikiwiki.cgi_was_not_found_on_this_server./comment_1_d36ce6fab90e0a086ac84369af38d205._comment b/doc/forum/The_requested_URL___47____126__jean__47__blog__47__ikiwiki.cgi_was_not_found_on_this_server./comment_1_d36ce6fab90e0a086ac84369af38d205._comment new file mode 100644 index 000000000..f95972c4f --- /dev/null +++ b/doc/forum/The_requested_URL___47____126__jean__47__blog__47__ikiwiki.cgi_was_not_found_on_this_server./comment_1_d36ce6fab90e0a086ac84369af38d205._comment @@ -0,0 +1,16 @@ +[[!comment format=mdwn + username="jeanm" + subject="comment 1" + date="2010-06-19T13:35:37Z" + content=""" +OK, I followed the dot cgi tip and this error diappears, thanks a lot! So ubuntu doesn't provide a \"working out of the box\" ikiwiki. + +But I get a new error message now when trying to edit a page: + +Error: \"do\" parameter missing + +My plugins now: +add_plugins => [qw{goodstuff websetup comments blogspam 404 muse}], + + +"""]] diff --git a/doc/forum/The_requested_URL___47____126__jean__47__blog__47__ikiwiki.cgi_was_not_found_on_this_server./comment_2_5836bba08172d2ddf6a43da87ebb0332._comment b/doc/forum/The_requested_URL___47____126__jean__47__blog__47__ikiwiki.cgi_was_not_found_on_this_server./comment_2_5836bba08172d2ddf6a43da87ebb0332._comment new file mode 100644 index 000000000..0a544eeb1 --- /dev/null +++ b/doc/forum/The_requested_URL___47____126__jean__47__blog__47__ikiwiki.cgi_was_not_found_on_this_server./comment_2_5836bba08172d2ddf6a43da87ebb0332._comment @@ -0,0 +1,7 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + subject="do parameter missing" + date="2010-06-23T17:03:12Z" + content=""" +That's an unusual problem. Normally the url or form that calls ikiwiki.cgi includes a \"do\" parameter, like \"do=edit\". I'd have to see the site to debug why it is missing for you. +"""]] diff --git a/doc/forum/The_requested_URL___47____126__jean__47__blog__47__ikiwiki.cgi_was_not_found_on_this_server./comment_3_4eec15c8c383275db5401c8e3c2d9242._comment b/doc/forum/The_requested_URL___47____126__jean__47__blog__47__ikiwiki.cgi_was_not_found_on_this_server./comment_3_4eec15c8c383275db5401c8e3c2d9242._comment new file mode 100644 index 000000000..faf3ad31b --- /dev/null +++ b/doc/forum/The_requested_URL___47____126__jean__47__blog__47__ikiwiki.cgi_was_not_found_on_this_server./comment_3_4eec15c8c383275db5401c8e3c2d9242._comment @@ -0,0 +1,9 @@ +[[!comment format=mdwn + username="jeanm" + ip="81.56.145.104" + subject="do parameter missing" + date="2010-06-30T07:30:08Z" + content=""" +the site address is piaffer.org, with a link to blog just over the picture. +tia, +"""]] diff --git a/doc/forum/The_requested_URL___47____126__jean__47__blog__47__ikiwiki.cgi_was_not_found_on_this_server./comment_4_43ac867621efb68affa6ae2b92740cad._comment b/doc/forum/The_requested_URL___47____126__jean__47__blog__47__ikiwiki.cgi_was_not_found_on_this_server./comment_4_43ac867621efb68affa6ae2b92740cad._comment new file mode 100644 index 000000000..d8b516f5f --- /dev/null +++ b/doc/forum/The_requested_URL___47____126__jean__47__blog__47__ikiwiki.cgi_was_not_found_on_this_server./comment_4_43ac867621efb68affa6ae2b92740cad._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + nickname="joey" + subject="comment 4" + date="2010-07-04T18:16:26Z" + content=""" +What is the muse plugin that you have enabled? I am not familiar with it. + +Apparently your ikiwiki is not seeing cgi parameters that should be passed to it. This appears to be some kind of web server misconfiguration, or possibly a broken ikiwiki wrapper or broken CGI.pm. +"""]] diff --git a/doc/forum/The_requested_URL___47____126__jean__47__blog__47__ikiwiki.cgi_was_not_found_on_this_server./comment_5_e098723bb12adfb91ab561cae21b492b._comment b/doc/forum/The_requested_URL___47____126__jean__47__blog__47__ikiwiki.cgi_was_not_found_on_this_server./comment_5_e098723bb12adfb91ab561cae21b492b._comment new file mode 100644 index 000000000..b832d64f4 --- /dev/null +++ b/doc/forum/The_requested_URL___47____126__jean__47__blog__47__ikiwiki.cgi_was_not_found_on_this_server./comment_5_e098723bb12adfb91ab561cae21b492b._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + nickname="joey" + subject="do parameter missing" + date="2010-07-08T06:04:44Z" + content=""" +I just debugged this problem with someone else who was using ngix-fcgi. There was a problem with it not passing CGI environment variables properly. If you're using that, it might explain your problem. +"""]] diff --git a/doc/forum/The_requested_URL___47____126__jean__47__blog__47__ikiwiki.cgi_was_not_found_on_this_server./comment_6_101183817ca4394890bd56a7694bedd9._comment b/doc/forum/The_requested_URL___47____126__jean__47__blog__47__ikiwiki.cgi_was_not_found_on_this_server./comment_6_101183817ca4394890bd56a7694bedd9._comment new file mode 100644 index 000000000..25a4e8bae --- /dev/null +++ b/doc/forum/The_requested_URL___47____126__jean__47__blog__47__ikiwiki.cgi_was_not_found_on_this_server./comment_6_101183817ca4394890bd56a7694bedd9._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="jeanm" + ip="81.56.145.104" + subject="comment 6" + date="2010-07-12T17:43:31Z" + content=""" +I'm using apache and mostly firefox. +I've tried some changes in my config but still the same problem, then I fell ill and unable to try anything more. Now I seem to be better and I will go back to the problem soon. +Thx +"""]] diff --git a/doc/forum/The_requested_URL___47____126__jean__47__blog__47__ikiwiki.cgi_was_not_found_on_this_server./comment_7_2f514e6ba78d43d90e7ff4ae387e65e0._comment b/doc/forum/The_requested_URL___47____126__jean__47__blog__47__ikiwiki.cgi_was_not_found_on_this_server./comment_7_2f514e6ba78d43d90e7ff4ae387e65e0._comment new file mode 100644 index 000000000..e35436e9d --- /dev/null +++ b/doc/forum/The_requested_URL___47____126__jean__47__blog__47__ikiwiki.cgi_was_not_found_on_this_server./comment_7_2f514e6ba78d43d90e7ff4ae387e65e0._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawm_oOJLk8xnq4K5yRKzEoPPr9dMAFjiSi4" + nickname="Bayle" + subject="how to fix '"do" parameter missing' on nginx-fcgi?" + date="2011-10-31T05:57:43Z" + content=""" +I also get \"Error: \"do\" parameter missing\" and am using nginx with fcgi. What was the problem with the environment variables and how should i fix it? thanks, + bayle + +"""]] diff --git a/doc/forum/The_requested_URL___47____126__jean__47__blog__47__ikiwiki.cgi_was_not_found_on_this_server./comment_8_098bb7a3112751a7e6167483dde626bb._comment b/doc/forum/The_requested_URL___47____126__jean__47__blog__47__ikiwiki.cgi_was_not_found_on_this_server./comment_8_098bb7a3112751a7e6167483dde626bb._comment new file mode 100644 index 000000000..ff0d79dbd --- /dev/null +++ b/doc/forum/The_requested_URL___47____126__jean__47__blog__47__ikiwiki.cgi_was_not_found_on_this_server./comment_8_098bb7a3112751a7e6167483dde626bb._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="http://andrewspiers.pip.verisignlabs.com/" + ip="118.209.91.42" + subject="passing environment variables." + date="2012-08-24T03:47:07Z" + content=""" +I am getting this 'Error: \"do\" parameter missing' when trying to log in as well. I am using Apache and Firefox. The Apache error log says \"Died at /usr/share/perl5/IkiWiki/CGI.pm line 428.\" when it dies. + +I do have ssl set up, not sure if this is part of the problem? +"""]] diff --git a/doc/forum/The_requested_URL___47____126__jean__47__blog__47__ikiwiki.cgi_was_not_found_on_this_server./comment_9_fbf403255c38da93caa5b98589fbb285._comment b/doc/forum/The_requested_URL___47____126__jean__47__blog__47__ikiwiki.cgi_was_not_found_on_this_server./comment_9_fbf403255c38da93caa5b98589fbb285._comment new file mode 100644 index 000000000..53c44d14f --- /dev/null +++ b/doc/forum/The_requested_URL___47____126__jean__47__blog__47__ikiwiki.cgi_was_not_found_on_this_server./comment_9_fbf403255c38da93caa5b98589fbb285._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://andrewspiers.pip.verisignlabs.com/" + ip="118.209.91.42" + subject="comment 9" + date="2012-08-24T04:29:06Z" + content=""" +SSL was the problem, it was necessary to specify https:// in the url=> and cgiurl=> parameters in ikiwiki.setup, the redirect wasn't working otherwise. +"""]] diff --git a/doc/forum/Trail_plugin_links_with_Actiontabs_theme.mdwn b/doc/forum/Trail_plugin_links_with_Actiontabs_theme.mdwn new file mode 100644 index 000000000..decaaa1bc --- /dev/null +++ b/doc/forum/Trail_plugin_links_with_Actiontabs_theme.mdwn @@ -0,0 +1,47 @@ +I'm using the trail plugin with the actiontabs theme, and the prev/next links +seem to appear in a strange way on the page. + +I use modified CSS, but it changes just the colors and some font sizes. +Nothing related to positions and trails. + +Here's an example - the top prev/next links appear above the action tabs. +Is this normal? I'm using the ikiwiki version from Debian 7 stable. + +- If you use OpenNIC: +- If you don't (will work only until the IP changes): + +I can look at the CSS and try to figure this out, but I don't know much CSS or +how the trail plugin works. If anyone uses trails, especially with actiontabs, and +can help me - it will be great. + +Thanks in advance! + +--[[fr33domlover]] + +> I looked at the file *page.tmpl* and it seems I may be able to change +> the trail link location if I edit that file. Would it be a good/possible solution to +> edit it and put it in the git repo to be used instead of the default one? +> +> --[[fr33domlover]] + +>> That's how I intended trails to look with actiontabs: +>> is +>> another example. +>> +>> With the way the actiontabs theme works, if you want to move the +>> trail bits down into the content area (white background in the +>> unedited theme) you might have to alter both `page.tmpl` +>> and the actiontabs CSS. You'll see that the actiontabs CSS +>> has a special case for trails, because the tabs and the trail +>> links would overlap otherwise - you might have to remove +>> that special case. --[[smcv]] + +>>> Thanks, I'll try that. But I've been using those trails in the last +>>> several hours and I'm beginning to get used to the current +>>> layout. Maybe I'll just keep it :-) +>>> +>>> (Anyway the way trail links look on my wiki is valid, it's exactly +>>> like on your link, only with different colors. I suppose it's +>>> just a cosmetic issue then) +>>> +>>> --[[fr33domlover]] diff --git a/doc/forum/Translating_ikiwiki_interface.mdwn b/doc/forum/Translating_ikiwiki_interface.mdwn new file mode 100644 index 000000000..747af15b5 --- /dev/null +++ b/doc/forum/Translating_ikiwiki_interface.mdwn @@ -0,0 +1,8 @@ +I am using ikiwiki for a spanish language wiki. I've read the [[translation]] page and [[plugins/po]] plugin page but it is not completely clear to me. As I understand it the po plugin is the recommended way to create translated versions of existing pages in your wiki based on a master language. But I actually don't need that as myself and other users already edit the wiki in spanish. What I would actually like is to have the ikiwiki interface itself translated into spanish. +Is it possible to have my wiki always appear in spanish? I can see that the debian package already includes po files for spanish. How do i activate the spanish translation permanently? Did I miss something obvious? + +> Ikiwiki has a Spanish translation of much of the program's output. +> However, there is currently no translation of the page.tmpl and other +> templates that are used to build your wiki. You can of course modify +> these and translate them yourself, but we have no way to maintaining +> those translations in po files. --[[Joey]] diff --git a/doc/forum/Upgrade_steps_from_RecentChanges_CGI_to_static_page.mdwn b/doc/forum/Upgrade_steps_from_RecentChanges_CGI_to_static_page.mdwn new file mode 100644 index 000000000..298ff49f1 --- /dev/null +++ b/doc/forum/Upgrade_steps_from_RecentChanges_CGI_to_static_page.mdwn @@ -0,0 +1,10 @@ +Where are the upgrade steps for RecentChanges change from CGI to static feed? +I run multiple ikiwiki-powered sites on multiple servers, but today I just upgraded one to 2.32.3. +Please have a look at + +Any suggestions? + +> There are no upgrade steps required. It does look like you need to enable +> the meta plugin to get a good recentchanges page though.. --[[Joey]] + +[[!meta date="2008-02-23 21:10:42 -0500"]] diff --git a/doc/forum/Using_reverse_proxy__59___base_URL_is_http_instead_of_https.mdwn b/doc/forum/Using_reverse_proxy__59___base_URL_is_http_instead_of_https.mdwn new file mode 100644 index 000000000..0e606dd93 --- /dev/null +++ b/doc/forum/Using_reverse_proxy__59___base_URL_is_http_instead_of_https.mdwn @@ -0,0 +1,55 @@ +Hello. + +My setup is as follows: I am running Debian on a VPS. I am using the reverse proxy pound, among other things, to provide SSL support for the webserver thttpd, which is serving the ikiwiki pages and running the ikiwiki CGI. The wiki is only accessible through https. + +I recently upgraded from squeeze to wheezy. This broke page editing. It seems that the edit pages now include a base url that points to an http address, instead of the https address specified in the config. I guess this is a result of the changes discussed here: + +[[http://ikiwiki.info/todo/want_to_avoid_ikiwiki_using_http_or_https_in_urls_to_allow_serving_both/]] + +Because of the reverse proxy, I suppose that, as far as the webserver is concerned, it is receiving an http (rather than https) request. I don't think it's at all SSL-aware. So I don't think there's any way the webserver could tell the CGI that it's actually being accessed via https. (Feel free to correct me on this point if you are more knowledgeable about reverse proxies, HTTP and SSL. I see that, according to the Wikipedia page for thttpd, it doesn't pass on the X-Forwarded-For HTTP header to CGI scripts, but I don't see how that would be useful in detecting this anyhow.) + +If ikiwiki's new behaviour is intentional, rather than a bug in ikiwiki or an error in my configuration, is there some option I can set or plugin I can enable to make it honour the URLs explicitly stated in my configuration? My current solution is to revert to the old version of ikiwiki from Debian Squeeze. + +I see that a number of people have had vaguely similar problems from other bugs/forum posts. This person seems to be someone having the reverse problem, of the base URL being https instead of http: + +[[http://ikiwiki.info/forum/CGI_script_and_HTTPS/]] + +This person is also using a reverse proxy, and has problems with setting the base, but I think this is a feature request rather than a regression: + +[[http://ikiwiki.info/bugs/trouble_with_base_in_search/]] + +This one sounds most like my situation: + +[[http://ikiwiki.info/forum/Dot_CGI_pointing_to_localhost._What_happened__63__/]] + +There is a comment here that hints at a workaround. Am I right in reading this as a suggestion to patch the source? Is that the official recommended solution? + +-- Martin. + +--- + +From my .setup (domains changed): + + srcdir => '/home/myusername/wiki', + # where to build the wiki + destdir => '/var/www/secure.example.com/wiki', + # base url to the wiki + url => 'https://secure.example.com/wiki', + # url to the ikiwiki.cgi + cgiurl => 'https://secure.example.com/cgi-bin/wiki/ikiwiki.cgi', + # filename of cgi wrapper to generate + cgi_wrapper => '/var/www/secure.example.com/cgi-bin/wiki/ikiwiki.cgi', + # mode for cgi_wrapper (can safely be made suid) + cgi_wrappermode => '06755', + +Old base in an edit page: + + + +New base in an edit page, after upgrading ikiwiki package, but before regenerating wrapper: + + + +New base in an edit page, after regenerating wrapper: + + diff --git a/doc/forum/Using_reverse_proxy__59___base_URL_is_http_instead_of_https/comment_1_ef4be9e70bd6d8c970fd8982f525d2d0._comment b/doc/forum/Using_reverse_proxy__59___base_URL_is_http_instead_of_https/comment_1_ef4be9e70bd6d8c970fd8982f525d2d0._comment new file mode 100644 index 000000000..acbcea54e --- /dev/null +++ b/doc/forum/Using_reverse_proxy__59___base_URL_is_http_instead_of_https/comment_1_ef4be9e70bd6d8c970fd8982f525d2d0._comment @@ -0,0 +1,21 @@ +[[!comment format=mdwn + username="http://smcv.pseudorandom.co.uk/" + nickname="smcv" + subject="comment 1" + date="2013-12-20T09:54:51Z" + content=""" +One way to solve this would be a new `$config{hard_code_urls}` +option whose semantics are \"you're behind a reverse proxy, hard-code +`$config{cgiurl}` and `${url}` in output rather than using the +address from the HTTP request\" (in other words, selectively undo some +of the automatic self-referential URL detection). + +Another possibility would be to avoid using ``, and when producing +CGI pages, make all links look like `/sandbox/` or +`/cgi-bin/ikiwiki.cgi?...`; but that can only work if your content and +CGI are on the same domain, and is likely to be more complex. + +The `` is required to be an absolute URI (including the +protocol and domain name) so the CGI output can't avoid doing a certain +amount of hard-coding, unfortunately. +"""]] diff --git a/doc/forum/Using_reverse_proxy__59___base_URL_is_http_instead_of_https/comment_2_00fee67cc30b7c337710b37c27216a68._comment b/doc/forum/Using_reverse_proxy__59___base_URL_is_http_instead_of_https/comment_2_00fee67cc30b7c337710b37c27216a68._comment new file mode 100644 index 000000000..26674f98c --- /dev/null +++ b/doc/forum/Using_reverse_proxy__59___base_URL_is_http_instead_of_https/comment_2_00fee67cc30b7c337710b37c27216a68._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawn1IY7Q6CUIdfPRp2foUdFSIKgaPpMI934" + nickname="Martin" + subject="comment 2" + date="2013-12-23T20:52:17Z" + content=""" +I think the option to treat the URLs in the config as hard-coded (effectively ignoring the address from the HTTP request) would be most useful. +"""]] diff --git a/doc/forum/Using_reverse_proxy__59___base_URL_is_http_instead_of_https/comment_3_f402fb426e0460ce927b7847246f699f._comment b/doc/forum/Using_reverse_proxy__59___base_URL_is_http_instead_of_https/comment_3_f402fb426e0460ce927b7847246f699f._comment new file mode 100644 index 000000000..8b976fac2 --- /dev/null +++ b/doc/forum/Using_reverse_proxy__59___base_URL_is_http_instead_of_https/comment_3_f402fb426e0460ce927b7847246f699f._comment @@ -0,0 +1,19 @@ +[[!comment format=mdwn + username="amcalvo" + ip="78.53.114.169" + subject="Workaround for Nginx" + date="2014-05-05T21:49:10Z" + content=""" +Thank you for the analysis. I have worked around the issue by using the , something like: + +~~~ +location { + # Proxy stuff... + sub_filter 'http://example.com' 'https://example.com'; + +} +~~~ + +Best regards, +amc. +"""]] diff --git a/doc/forum/Using_reverse_proxy__59___base_URL_is_http_instead_of_https/comment_4_db726bc81ec5feac76d17ea81f0f80a5._comment b/doc/forum/Using_reverse_proxy__59___base_URL_is_http_instead_of_https/comment_4_db726bc81ec5feac76d17ea81f0f80a5._comment new file mode 100644 index 000000000..d0b2952b0 --- /dev/null +++ b/doc/forum/Using_reverse_proxy__59___base_URL_is_http_instead_of_https/comment_4_db726bc81ec5feac76d17ea81f0f80a5._comment @@ -0,0 +1,13 @@ +[[!comment format=mdwn + username="amcalvo" + ip="78.53.114.169" + subject="comment 4" + date="2014-05-05T21:56:36Z" + content=""" +A correction to the above comment, one needs activate multiple replacements: + +~~~ + sub_filter 'http://example.com' 'https://example.com'; + sub_filter_once off; +~~~ +"""]] diff --git a/doc/forum/Using_reverse_proxy__59___base_URL_is_http_instead_of_https/comment_5_674f56100c0682eba36cc5327fbdae4a._comment b/doc/forum/Using_reverse_proxy__59___base_URL_is_http_instead_of_https/comment_5_674f56100c0682eba36cc5327fbdae4a._comment new file mode 100644 index 000000000..1546c67a0 --- /dev/null +++ b/doc/forum/Using_reverse_proxy__59___base_URL_is_http_instead_of_https/comment_5_674f56100c0682eba36cc5327fbdae4a._comment @@ -0,0 +1,61 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawk6z7Jsfi_XWfzFJNZIjYUcjgrthg4aPUU" + nickname="Alejandro" + subject="Same Trick in Apache" + date="2014-09-10T18:58:24Z" + content=""" +I got it working with Apache 2.4 and Virtual Hosts on both HTTP 1.1 and HTTPS (SNI). The procedure is somewhat analogous to the nginx procedure above. So here is my set-up in the hopes will help other avoid this pain. + +## Set-up + + CLIENT <---- HTTPS ----> REVERSE PROXY <---- HTTP ----> IKIWIKI + + +## The HTTP to HTTPS Redirect + +To assure that all your HTTP requests are being redirected to HTTPS I chose to use mod_rewrite because simple Redirect does not pass query parameters. You will want an HTTP VHost that will redirect with something like the one below (notice the subtle ? before query string). **Note: This will NOT re-write ikiwiki's http:// URLs (base tag, etc.)**. For that I use a content filter like you will see below. This HTTP to HTTPS redirect is required though for both security and for the /foo/?updated URI form in this set-up. + +
+
+<VirtualHost *:80>
+    ServerName imass.name
+    RewriteEngine On
+    RewriteCond %{HTTPS} off
+    RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}?%{QUERY_STRING}
+    ErrorLog /var/log/imass.name-error.log
+    LogLevel warn
+    CustomLog /var/log/imass.name-access.log combined
+</VirtualHost>
+
+
+ +## The SSL Virtual Host + +This part is a bit more tricky. First I am using SNI as I don't care for non-SNI user agents. Second, you need to use a filter that replaces all http:// to https:// before the response is set. Note that this alone won't deal with ?update so you will need the HTTP to HTTPS set-up above anyway. Third, I use HTTP Auth so I don't know if this will work with your particular Auth set-up (although it should IMHO), YMMV: + +
+
+<VirtualHost *:443>
+    ServerName imass.name
+    ProxyHTMLEnable On
+    ProxyHTMLExtended On
+    SSLEngine on
+    SSLCertificateFile XXX
+    SSLCertificateKeyFile XXX
+    SSLCertificateChainFile XXX
+    SSLOptions +StdEnvVars
+    ProxyPreserveHost On
+    ProxyHTMLURLMap http:// https://
+    ProxyPass / http://192.168.101.101/
+    ProxyPassReverse / http://192.168.101.101/
+    LogLevel warn
+    ErrorLog /var/log/imass.name-ssl-error.log
+    TransferLog \"/var/log/imass.name-ssl-access.log\"
+    CustomLog \"/var/log/imass.name-ssl-request.log\" \"%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \\"%r\\" %b\"
+</VirtualHost>
+
+
+ + + +"""]] diff --git a/doc/forum/Various_ways_to_use_Subversion_with_ikiwiki.mdwn b/doc/forum/Various_ways_to_use_Subversion_with_ikiwiki.mdwn new file mode 100644 index 000000000..8eed30cd8 --- /dev/null +++ b/doc/forum/Various_ways_to_use_Subversion_with_ikiwiki.mdwn @@ -0,0 +1,23 @@ +[[!meta date="2007-08-17 03:54:10 +0000"]] + +I'm playing around with various ways that I can use subversion with ikiwiki. + +* Is it possible to have ikiwiki point to a subversion repository which is on a different server? The basic checkin/checkout functionality seems to work but there doesn't seem to be any way to make the post-commit hook work for a non-local server? + +> This is difficult to do since ikiwiki's post-commit wrapper expects to +> run on a machine that contains both the svn repository and the .ikiwiki +> state directory. However, with recent versions of ikiwiki, you can get +> away without running the post-commit wrapper on commit, and all you lose +> is the ability to send commit notification emails. + +> (And now that [[recentchanges]] includes rss, you can just subscribe to +> that, no need to worry about commit notification emails anymore.) + +* Is it possible / sensible to have ikiwiki share a subversion repository with other data (either completely unrelated files or another ikiwiki instance)? This works in part but again the post-commit hook seems problematic. + +--[[AdamShand]] + +> Sure, see ikiwiki's subversion repository for example of non-wiki files +> in the same repo. If you have two wikis in one repository, you will need +> to write a post-commit script that calls the post-commit wrappers for each +> wiki. --[[Joey]] diff --git a/doc/forum/What__39__s_the_difference_between_tag_and_taglink__63__.mdwn b/doc/forum/What__39__s_the_difference_between_tag_and_taglink__63__.mdwn new file mode 100644 index 000000000..4fee07db4 --- /dev/null +++ b/doc/forum/What__39__s_the_difference_between_tag_and_taglink__63__.mdwn @@ -0,0 +1,9 @@ +It occurred to me the difference between tag and taglink, as described in http://ikiwiki.info/ikiwiki/directive/tag/ is just that the latter enable the option to have a displayed form of the tag different from the tag itself, e.g. a tag `foo` can be displayed as `bar` using + + \[[!taglink foo|bar]] + +while with tag you can only display the tag `foo` as itself + + \[[!tag foo]] + +Is that it? diff --git a/doc/forum/What__39__s_the_difference_between_tag_and_taglink__63__/comment_1_b3553d65d12af4c4a87f1f66f961c8d9._comment b/doc/forum/What__39__s_the_difference_between_tag_and_taglink__63__/comment_1_b3553d65d12af4c4a87f1f66f961c8d9._comment new file mode 100644 index 000000000..239444516 --- /dev/null +++ b/doc/forum/What__39__s_the_difference_between_tag_and_taglink__63__/comment_1_b3553d65d12af4c4a87f1f66f961c8d9._comment @@ -0,0 +1,49 @@ +[[!comment format=mdwn + username="http://smcv.pseudorandom.co.uk/" + nickname="smcv" + subject="comment 1" + date="2012-08-19T15:05:35Z" + content=""" +`\[[!tag]]` does not produce any output in the body of the page, but +stores an invisible tag (which, in the default templates, gets displayed +in the footer of the page). + +For instance, this + + Here is some text about badgers + \[[!tag badger]] + +or this + + \[[!tag badger]] + Here is some text about badgers + +or even this + + Here is some text about \[[!tag badger]]badgers + +will all come out like this: + + Edit | RecentChanges | etc. + ---- + Here is some text about badgers + ---- + tags: badger + +`\[[!taglink]]` produces a [[ikiwiki/WikiLink]] in the body of the +page, *and* stores an invisible tag like `\[[!tag]]`. + +So this: + + Some text about \[[!tag mushrooms]] and toadstools + +renders like this + + Edit | RecentChanges | etc. + ---- + Some text about _mushrooms_ and toadstools + ---- + tags: mushrooms + +where `_mushrooms_` represents a hyperlink. +"""]] diff --git a/doc/forum/What_is_wrong_with_my_recentchange_page___63__.mdwn b/doc/forum/What_is_wrong_with_my_recentchange_page___63__.mdwn new file mode 100644 index 000000000..4914cba59 --- /dev/null +++ b/doc/forum/What_is_wrong_with_my_recentchange_page___63__.mdwn @@ -0,0 +1,13 @@ +Hi again, + +I have finally finished my setup *but* I still have a problem with RecentChanges page. + +Can somebody check it for me at [http://maillard.mobi/~xma/wiki/recentchanges/] and tell what is wrong ? + +Thank you. + +--[[xma]] + +> Looks to me like you don't have the meta plugin enabled. --[[Joey]] + +> > You are right. Now all is ok. --[[xma]] diff --git a/doc/forum/When_do_tags_like_a__47__b_get_listed_as_a__47__b_and_not_only_b__63__.mdwn b/doc/forum/When_do_tags_like_a__47__b_get_listed_as_a__47__b_and_not_only_b__63__.mdwn new file mode 100644 index 000000000..42f470a8b --- /dev/null +++ b/doc/forum/When_do_tags_like_a__47__b_get_listed_as_a__47__b_and_not_only_b__63__.mdwn @@ -0,0 +1,6 @@ +Hello, + +For example the page [[plugins/tag|plugins/tag]] here is tagged type/link and type/tags, what gets listed exactly so below the page's content. However, when I use tags like concept/getopt or lang/Perl on my private wiki, it gets only listed as getopt and Perl. Is this behavior configurable or is it implemented firstly in a version later than 3.20100815~bpo50+1 (for which I'm stuck ATM.)? + +Greetings, + Mike Dornberger diff --git a/doc/forum/When_do_tags_like_a__47__b_get_listed_as_a__47__b_and_not_only_b__63__/comment_1_cd5ea3aac8a59793ece5bf01a6190b53._comment b/doc/forum/When_do_tags_like_a__47__b_get_listed_as_a__47__b_and_not_only_b__63__/comment_1_cd5ea3aac8a59793ece5bf01a6190b53._comment new file mode 100644 index 000000000..953a7141b --- /dev/null +++ b/doc/forum/When_do_tags_like_a__47__b_get_listed_as_a__47__b_and_not_only_b__63__/comment_1_cd5ea3aac8a59793ece5bf01a6190b53._comment @@ -0,0 +1,9 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + nickname="joey" + subject="comment 1" + date="2012-04-19T17:32:18Z" + content=""" +I think this change was made in 2011, in commit a17469e3882f55bee93863c6e265b96b80ec9fef. + +"""]] diff --git a/doc/forum/Wikilink_to_a_symbolic_link.mdwn b/doc/forum/Wikilink_to_a_symbolic_link.mdwn new file mode 100644 index 000000000..69c39725c --- /dev/null +++ b/doc/forum/Wikilink_to_a_symbolic_link.mdwn @@ -0,0 +1 @@ +If I want to make a link to a local pdf-file I put the file into my scrdir and use the usual wikilink syntax. However if I put only a symbolic link into the scrdir instead of the actual file, it doesn't work. Is there a way to make that ikiwiki handles symbolic links in this situation? diff --git a/doc/forum/Wikilink_to_a_symbolic_link/comment_1_e3ad5099491e0c84cd7729eba82ce552._comment b/doc/forum/Wikilink_to_a_symbolic_link/comment_1_e3ad5099491e0c84cd7729eba82ce552._comment new file mode 100644 index 000000000..c47897d3c --- /dev/null +++ b/doc/forum/Wikilink_to_a_symbolic_link/comment_1_e3ad5099491e0c84cd7729eba82ce552._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://kerravonsen.dreamwidth.org/" + ip="202.173.183.92" + subject="comment 1" + date="2011-09-27T21:00:16Z" + content=""" +No, because disallowing symbolic links is a security feature which can't be disabled. +"""]] diff --git a/doc/forum/Wikilink_to_a_symbolic_link/comment_2_46848020b1e3d0cd55bc1ec0ba382aad._comment b/doc/forum/Wikilink_to_a_symbolic_link/comment_2_46848020b1e3d0cd55bc1ec0ba382aad._comment new file mode 100644 index 000000000..f8058f4fd --- /dev/null +++ b/doc/forum/Wikilink_to_a_symbolic_link/comment_2_46848020b1e3d0cd55bc1ec0ba382aad._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawk_MMtLPS7osC5MjX00q2ATjvvXPWqm0ik" + nickname="micheal" + subject="comment 2" + date="2011-09-28T17:14:11Z" + content=""" +I use ikiwiki only locally for my personal use. So it wouldn't be a security issue for me. Perhaps there is some \"hack\" to achieve what I want? +"""]] diff --git a/doc/forum/Wikilink_to_section_of_a_wikipage.mdwn b/doc/forum/Wikilink_to_section_of_a_wikipage.mdwn new file mode 100644 index 000000000..1a6c04e21 --- /dev/null +++ b/doc/forum/Wikilink_to_section_of_a_wikipage.mdwn @@ -0,0 +1 @@ +Is it possible to link directly to a specific section of another ikiwiki-page? diff --git a/doc/forum/Wikilink_to_section_of_a_wikipage/comment_1_c1409a3c07dfc4ed7274560c962aba75._comment b/doc/forum/Wikilink_to_section_of_a_wikipage/comment_1_c1409a3c07dfc4ed7274560c962aba75._comment new file mode 100644 index 000000000..ace6b66a8 --- /dev/null +++ b/doc/forum/Wikilink_to_section_of_a_wikipage/comment_1_c1409a3c07dfc4ed7274560c962aba75._comment @@ -0,0 +1,11 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + nickname="joey" + subject="comment 1" + date="2011-09-07T20:58:46Z" + content=""" +Quoting [[ikiwiki/wikilink]]: + +> To link to an anchor inside a page, you can use something like +> `\[[WikiLink#foo]]` . +"""]] diff --git a/doc/forum/Wikilink_to_section_of_a_wikipage/comment_2_8a04eb7b0d7f17b9e5bb4cd04ba45871._comment b/doc/forum/Wikilink_to_section_of_a_wikipage/comment_2_8a04eb7b0d7f17b9e5bb4cd04ba45871._comment new file mode 100644 index 000000000..1583dae2f --- /dev/null +++ b/doc/forum/Wikilink_to_section_of_a_wikipage/comment_2_8a04eb7b0d7f17b9e5bb4cd04ba45871._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawk_MMtLPS7osC5MjX00q2ATjvvXPWqm0ik" + nickname="micheal" + subject="comment 2" + date="2011-09-11T12:00:08Z" + content=""" +Thanks! +"""]] diff --git a/doc/forum/Xapian_search:_empty_postlist_table.mdwn b/doc/forum/Xapian_search:_empty_postlist_table.mdwn new file mode 100644 index 000000000..704f017ca --- /dev/null +++ b/doc/forum/Xapian_search:_empty_postlist_table.mdwn @@ -0,0 +1,34 @@ +Hi, + +I'm trying to set up a personal wiki and I'm having trouble getting +search to work. All my searches give zero results. I eventually +figured out that the Xapian database that's being created has an empty +postlist table. The position and termlist tables are all fine, and +when I add new content to the wiki I can see the database is updated +and the search terms are in the position table in plaintext. But I +can't query for them, even using Xapian's command line tools. + +
+mexon:~/Test/.ikiwiki/xapian/default$ ls -l
+total 76
+-rw-rw-r-- 1 mexon mexon     0 Dec 16 15:56 flintlock
+-rw-rw-r-- 1 mexon mexon    28 Dec 16 15:55 iamchert
+-rw-rw-r-- 1 mexon mexon    13 Dec 16 15:55 position.baseA
+-rw-rw-r-- 1 mexon mexon 49152 Dec 16 15:55 position.DB
+-rw-rw-r-- 1 mexon mexon    13 Dec 16 15:55 postlist.baseA
+-rw-rw-r-- 1 mexon mexon     0 Dec 16 15:55 postlist.DB
+-rw-rw-r-- 1 mexon mexon    13 Dec 16 15:55 record.baseA
+-rw-rw-r-- 1 mexon mexon     0 Dec 16 15:55 record.DB
+-rw-rw-r-- 1 mexon mexon    13 Dec 16 15:55 termlist.baseA
+-rw-rw-r-- 1 mexon mexon 16384 Dec 16 15:55 termlist.DB
+mexon:~/Test/.ikiwiki/xapian/default$ delve -a .
+All terms in database:
+mexon:~/Test/.ikiwiki/xapian/default$ 
+
+ +I don't know how to debug from here. Clearly ikiwiki is doing +something right when it's building the database, but one of the tables +is missing. Can anyone guess what's wrong, or tell me where to start +troubleshooting? + +I'm using Centos 5. Xapian is version 1.2.5. Ikiwiki version 3.20111107. diff --git a/doc/forum/Xapian_search:_empty_postlist_table/comment_1_de9a7c94beec2707eda0924ca58be9df._comment b/doc/forum/Xapian_search:_empty_postlist_table/comment_1_de9a7c94beec2707eda0924ca58be9df._comment new file mode 100644 index 000000000..23e539f06 --- /dev/null +++ b/doc/forum/Xapian_search:_empty_postlist_table/comment_1_de9a7c94beec2707eda0924ca58be9df._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + nickname="joey" + subject="comment 1" + date="2011-12-16T18:51:16Z" + content=""" +Perhaps you should try a current verison of xapian, 1.2.7 works here. You don't say what version of the xapian perl module you have; 1.2.7.0 is working here. The \"postlist\" is an internal part of xapian AFAICS, not something that has to be explicitly set up, and it gets populated here. +"""]] diff --git a/doc/forum/Xapian_search:_empty_postlist_table/comment_2_55f191e4b1306a318a30319f01802229._comment b/doc/forum/Xapian_search:_empty_postlist_table/comment_2_55f191e4b1306a318a30319f01802229._comment new file mode 100644 index 000000000..41cdf3d4a --- /dev/null +++ b/doc/forum/Xapian_search:_empty_postlist_table/comment_2_55f191e4b1306a318a30319f01802229._comment @@ -0,0 +1,15 @@ +[[!comment format=mdwn + username="https://me.yahoo.com/a/2d7oNP9wlop3PaHlGlGS1J2ppVqXf4zQAw--#17b9b" + nickname="Matthew" + subject="comment 2" + date="2011-12-17T09:10:38Z" + content=""" +I'm using RPMs to install Xapian packages, xapian-omega and xapian-bindings-perl, and they're all 1.2.5. I originally tried building and installing Xapian 1.2.7 from source, but found that ikiwiki failed like this: + +
+Use of inherited AUTOLOAD for non-method Search::Xapian::DB_CREATE_OR_OPEN() is deprecated at /home/mexon/system/Linux//lib/perl5/site_perl/5.8.8/IkiWiki/Plugin/search.pm line 220.
+Can't locate auto/Search/Xapian/DB_CREATE_O.al in @INC (@INC contains: /home/mat/.ikiwiki /home/mexon/system/Linux//lib/perl5/site_perl/5.8.8/i386-linux-thread-multi /home/mexon/system/Linux//lib/perl5/site_perl/5.8.8 /home/mexon/system/perl5lib /usr/lib/perl5/site_perl/5.8.8/i386-linux-thread-multi /usr/lib/perl5/site_perl/5.8.8 /usr/lib/perl5/site_perl /usr/lib/perl5/vendor_perl/5.8.8/i386-linux-thread-multi /usr/lib/perl5/vendor_perl/5.8.8 /usr/lib/perl5/vendor_perl /usr/lib/perl5/5.8.8/i386-linux-thread-multi /usr/lib/perl5/5.8.8 .) at /home/mexon/system/Linux//lib/perl5/site_perl/5.8.8/IkiWiki/Plugin/search.pm line 220
+
+ +Much fruitless googling later I found that there were these 1.2.5 RPMs lying around so I switched to those. If you know a solution to the DB_CREATE_O problem I could give 1.2.7 another go. +"""]] diff --git a/doc/forum/Xapian_search:_empty_postlist_table/comment_3_0bd424a89c3a52ff393a1e7e00c806be._comment b/doc/forum/Xapian_search:_empty_postlist_table/comment_3_0bd424a89c3a52ff393a1e7e00c806be._comment new file mode 100644 index 000000000..05f9c874e --- /dev/null +++ b/doc/forum/Xapian_search:_empty_postlist_table/comment_3_0bd424a89c3a52ff393a1e7e00c806be._comment @@ -0,0 +1,24 @@ +[[!comment format=mdwn + username="https://me.yahoo.com/a/2d7oNP9wlop3PaHlGlGS1J2ppVqXf4zQAw--#17b9b" + nickname="Matthew" + subject="comment 3" + date="2011-12-19T06:18:56Z" + content=""" +I had another go, this time with Xapian 1.2.8.0, and I finally got it working. The errors I was seeing earlier were because Xapian installs itself in /usr/local, but the default CentOS environment doesn't have /usr/local/lib in the LD_LIBRARY_PATH. As usual, the problem and solution are very duh, it's the error messages that make everything hard. It's a lot more clear if you do a \"make test\" while building Search::Xapian: + +
+mexon:~/ikiwiki-temp/Search-Xapian-1.2.8.0$ make test
+PERL_DL_NONLAZY=1 /usr/bin/perl \"-MExtUtils::Command::MM\" \"-e\" \"test_harness(0, 'blib/lib', 'blib/arch')\" t/*.t
+t/01use...............
+#   Failed test 'use Search::Xapian;'
+#   in t/01use.t at line 3.
+#     Tried to use 'Search::Xapian'.
+#     Error:  Can't load '/home/mexon/ikiwiki-temp/Search-Xapian-1.2.8.0/blib/arch/auto/Search/Xapian/Xapian.so' for module Search::Xapian: libxapian.so.22: cannot open shared object file: No such file or directory at /usr/lib/perl5/5.8.8/i386-linux-thread-multi/DynaLoader.pm line 230.
+#  at (eval 3) line 2
+# Compilation failed in require at (eval 3) line 2.
+# BEGIN failed--compilation aborted at t/01use.t line 3.
+# Looks like you failed 1 test of 3.
+
+ +So yeah. Worth noting that Xapian 1.2.5 is apparently broken with ikiwiki. Maybe some kind of warning? +"""]] diff --git a/doc/forum/Xapian_search:_empty_postlist_table/comment_4_40479ac2cfbca609f5f423e539a20ee0._comment b/doc/forum/Xapian_search:_empty_postlist_table/comment_4_40479ac2cfbca609f5f423e539a20ee0._comment new file mode 100644 index 000000000..a120f976d --- /dev/null +++ b/doc/forum/Xapian_search:_empty_postlist_table/comment_4_40479ac2cfbca609f5f423e539a20ee0._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawlXywgEUJjKArnORJR-5hmNFv8bTraXO1Y" + nickname="Ramsey" + subject="The same issue is happening with me" + date="2013-03-06T13:10:15Z" + content=""" +I use ikiwiki version 3.20130212 and tried xapian versions 1.2.5, 1.2.8, 1.2.13. All to no avail. The postlist.DB file is empty for me. I think that is the crux of the problem. Does anybody know why this could be? +"""]] diff --git a/doc/forum/Xapian_search:_empty_postlist_table/comment_5_397443138da276e11c2e9b9fa7b51406._comment b/doc/forum/Xapian_search:_empty_postlist_table/comment_5_397443138da276e11c2e9b9fa7b51406._comment new file mode 100644 index 000000000..56dd7c61d --- /dev/null +++ b/doc/forum/Xapian_search:_empty_postlist_table/comment_5_397443138da276e11c2e9b9fa7b51406._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawljJoWAYhI55qm4hRLdzIOQBNMVB6fgrs8" + nickname="Ramsey" + subject="comment 5" + date="2013-03-06T22:42:54Z" + content=""" +Tried version xapian 1.2.3 and it did not work either. Can someone please help me debug this? +"""]] diff --git a/doc/forum/Xapian_search:_empty_postlist_table/comment_6_3cd94b9a141ebbf96fcba4ebe99e1453._comment b/doc/forum/Xapian_search:_empty_postlist_table/comment_6_3cd94b9a141ebbf96fcba4ebe99e1453._comment new file mode 100644 index 000000000..2d456f36e --- /dev/null +++ b/doc/forum/Xapian_search:_empty_postlist_table/comment_6_3cd94b9a141ebbf96fcba4ebe99e1453._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="https://launchpad.net/~ojwb" + nickname="ojwb" + subject="comment 6" + date="2013-08-26T03:20:05Z" + content=""" +As a Xapian database is updated, changes are written out straight away to most of the tables, but the postlist changes are batched up in memory and only written to disk just before they are committed (or to free up memory during a large transaction). So the empty postlist table you're seeing means that some documents were indexed, but the indexer stopped running before anything was committed. By default, there's an auto-commit every 10000 documents added, removed, or changed, so it presumably managed to process less than 10000 documents. + +The issue with 1.2.5 RPMs may be down to there being two versions of the Xapian perl bindings, both of which claim to be Search::Xapian and both of which have been packaged up as RPMs. For Xapian 1.2.x, you probably want to use the XS bindings (perl-Search-Xapian) not those generated with SWIG (xapian-bindings-perl). The SWIG-generated ones are aimed to replace the XS ones, but in 1.2.x they're not really ready for prime time. If your perl bindings are described with a 4 coponent version (e.g. 1.2.15.0) then you should be good; if it's 3 components (e.g. 1.2.15) then you probably want the other ones. +"""]] diff --git a/doc/forum/Your_local_changes_to_the_following_files_would_be_overwritten_by_merge:.mdwn b/doc/forum/Your_local_changes_to_the_following_files_would_be_overwritten_by_merge:.mdwn new file mode 100644 index 000000000..911e4c8ab --- /dev/null +++ b/doc/forum/Your_local_changes_to_the_following_files_would_be_overwritten_by_merge:.mdwn @@ -0,0 +1,35 @@ +In my first attempt to edit in a text editor I chose sidebar.mdwn. I committed it after the editing, and get this when I execute "git push:" + +$ git push + + Counting objects: 5, done. + + Delta compression using up to 8 threads. + + Compressing objects: 100% (3/3), done. + + Writing objects: 100% (3/3), 289 bytes, done. + + Total 3 (delta 2), reused 0 (delta 0) + + Unpacking objects: 100% (3/3), done. + + remote: From /home/zoidberg/Zoidwicky + + remote: e878e6a..0ac0c44 master -> origin/master + + remote: error: Your local changes to the following files would be overwritten by merge: + + remote: sidebar.mdwn + + remote: Please, commit your changes or stash them before you can merge. + + remote: Aborting + + remote: 'git pull --prune origin' failed: at /usr/share/perl5/IkiWiki/Plugin/git.pm line 218. + + To /home/zoidberg/Zoidwicky.git + + e878e6a..0ac0c44 master -> master + +I have committed my changes to sidebar.mdwn and given my reason for doing so. Also, I get this complaint about sidebar.mdwn when I try 'git push' after editng other files. So I am stuck here. Pls. help. diff --git a/doc/forum/Your_local_changes_to_the_following_files_would_be_overwritten_by_merge:/comment_1_2223c8b463b22a9dab53b71c01b67209._comment b/doc/forum/Your_local_changes_to_the_following_files_would_be_overwritten_by_merge:/comment_1_2223c8b463b22a9dab53b71c01b67209._comment new file mode 100644 index 000000000..b306c9bcf --- /dev/null +++ b/doc/forum/Your_local_changes_to_the_following_files_would_be_overwritten_by_merge:/comment_1_2223c8b463b22a9dab53b71c01b67209._comment @@ -0,0 +1,12 @@ +[[!comment format=mdwn + username="http://bob-bernstein.myopenid.com/" + nickname="bernstein" + subject="FIXED! YIPPEE!" + date="2014-05-26T04:26:17Z" + content=""" +Just diddling around I got the old copy of sidebar.mdwn out of the way, i.e. I moved it out of, not the .git directory in my home dir, but the \"plain\" one. I really ought to learn the names of these things. At any rate it was what git called my \"local copy,\" so I got it out of there. + +Now with the logjam broken I can edit, commit, and push changes, apparently, 'til the cows come home. + +Thank yourse A::! +"""]] diff --git a/doc/forum/Your_local_changes_to_the_following_files_would_be_overwritten_by_merge:/comment_2_2466ce4303f5b8145bdfae23b6dbddda._comment b/doc/forum/Your_local_changes_to_the_following_files_would_be_overwritten_by_merge:/comment_2_2466ce4303f5b8145bdfae23b6dbddda._comment new file mode 100644 index 000000000..690808a00 --- /dev/null +++ b/doc/forum/Your_local_changes_to_the_following_files_would_be_overwritten_by_merge:/comment_2_2466ce4303f5b8145bdfae23b6dbddda._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="http://bob-bernstein.myopenid.com/" + nickname="bernstein" + subject="Fat Fingers" + date="2014-05-26T04:29:44Z" + content=""" +Make that last line, above: + +Thank youse ALL! +"""]] diff --git a/doc/forum/__34__Error:_cannot_decode_string_with_wide_characters__34___on_Mageia_Linux_x86-64_Cauldron.mdwn b/doc/forum/__34__Error:_cannot_decode_string_with_wide_characters__34___on_Mageia_Linux_x86-64_Cauldron.mdwn new file mode 100644 index 000000000..c5a91be06 --- /dev/null +++ b/doc/forum/__34__Error:_cannot_decode_string_with_wide_characters__34___on_Mageia_Linux_x86-64_Cauldron.mdwn @@ -0,0 +1,23 @@ +When running ikiwiki-3.20140102-1.mga4 on Mageia Linux x86-64 4/Cauldron with perl-5.18.1-3.mga4 , I am getting this error after I try to preview a page that contains unicode, at least in firefox-24.2.0-2.mga4 (note that I added "use Carp::Always;" to Ikiwiki.pm to get the stack trace): + +
+Error: Cannot decode string with wide characters at /usr/lib/perl5/vendor_perl/5.18.1/x86_64-linux-thread-multi/Encode.pm line 215. 
+Encode::decode_utf8('# Freenode programming channel FAQ\x{d}\x{a}\x{d}\x{a}This page is intended t...') called at /usr/lib/perl5/vendor_perl/5.18.1/IkiWiki/CGI.pm line 117 
+IkiWiki::decode_form_utf8('CGI::FormBuilder=HASH(0x2f7b880)') called at /usr/lib/perl5/vendor_perl/5.18.1/IkiWiki/Plugin/editpage.pm line 90 
+IkiWiki::cgi_editpage('CGI=HASH(0x21ad628)', 'CGI::Session=HASH(0x280fb88)') called at /usr/lib/perl5/vendor_perl/5.18.1/IkiWiki/CGI.pm line 442
+IkiWiki::__ANON__('CODE(0x23ec970)') called at /usr/lib/perl5/vendor_perl/5.18.1/IkiWiki.pm line 2085
+IkiWiki::run_hooks('sessioncgi', 'CODE(0x2a5be20)') called at /usr/lib/perl5/vendor_perl/5.18.1/IkiWiki/CGI.pm line 442
+IkiWiki::cgi() called at /usr/bin/ikiwiki line 191 eval {...} called at /usr/bin/ikiwiki line 191
+IkiWiki::main() called at /usr/bin/ikiwiki line 228
+
+ +I have upgraded the ikiwiki instance using "ikiwiki -setup" and am running ikiwiki.cgi on a local Apache server. + +Can anyone shed any light on this problem and guide me what I need to do to fix it? + +Regards, + +-- [Shlomi Fish](http://www.shlomifish.org/) + +> [[Merged anarcat's fix for +this|bugs/garbled non-ascii characters in body in web interface]] --[[smcv]] diff --git a/doc/forum/__34__Error:_cannot_decode_string_with_wide_characters__34___on_Mageia_Linux_x86-64_Cauldron/comment_1_abf7ec7c378ab0908685d72d159e9fd2._comment b/doc/forum/__34__Error:_cannot_decode_string_with_wide_characters__34___on_Mageia_Linux_x86-64_Cauldron/comment_1_abf7ec7c378ab0908685d72d159e9fd2._comment new file mode 100644 index 000000000..8b066b391 --- /dev/null +++ b/doc/forum/__34__Error:_cannot_decode_string_with_wide_characters__34___on_Mageia_Linux_x86-64_Cauldron/comment_1_abf7ec7c378ab0908685d72d159e9fd2._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="https://id.koumbit.net/anarcat" + ip="72.0.72.144" + subject="comment 1" + date="2014-09-10T03:00:22Z" + content=""" +i had a similar issue, reported in [[bugs/garbled_non-ascii_characters_in_body_in_web_interface]]. +"""]] diff --git a/doc/forum/__42__.html_source_file_containing___60__script__62__...__60____47__script__62___not_working__63__.mdwn b/doc/forum/__42__.html_source_file_containing___60__script__62__...__60____47__script__62___not_working__63__.mdwn new file mode 100644 index 000000000..61d612a69 --- /dev/null +++ b/doc/forum/__42__.html_source_file_containing___60__script__62__...__60____47__script__62___not_working__63__.mdwn @@ -0,0 +1,13 @@ +Is a *.html source file containing supposed to work? + +I added a `foo.html` containing + + + +after normal build when I visit `http://foobar.com/foo/` it gives me a normal page with head and footnote texts but empty body +
+
+
+
+ +Any ideas how this could/should work? diff --git a/doc/forum/__42__.html_source_file_containing___60__script__62__...__60____47__script__62___not_working__63__/comment_1_953bd716373dcf51fa444ac098b7f971._comment b/doc/forum/__42__.html_source_file_containing___60__script__62__...__60____47__script__62___not_working__63__/comment_1_953bd716373dcf51fa444ac098b7f971._comment new file mode 100644 index 000000000..e985b595c --- /dev/null +++ b/doc/forum/__42__.html_source_file_containing___60__script__62__...__60____47__script__62___not_working__63__/comment_1_953bd716373dcf51fa444ac098b7f971._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + nickname="joey" + subject="comment 1" + date="2011-05-21T23:37:23Z" + content=""" +Ikiwiki has a [[plugins/htmlscrubber]] that removes possibly insecure javascript (ie, all javascript) by default. It can be configured. Or you can use the [[plugins/rawhtml]] plugin if you want to include raw html in a site without ikiwiki touching it at all. +"""]] diff --git a/doc/forum/__42__.html_source_file_containing___60__script__62__...__60____47__script__62___not_working__63__/comment_2_c7360852f9bf069f28c193373333c9a8._comment b/doc/forum/__42__.html_source_file_containing___60__script__62__...__60____47__script__62___not_working__63__/comment_2_c7360852f9bf069f28c193373333c9a8._comment new file mode 100644 index 000000000..c5ac9a92f --- /dev/null +++ b/doc/forum/__42__.html_source_file_containing___60__script__62__...__60____47__script__62___not_working__63__/comment_2_c7360852f9bf069f28c193373333c9a8._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="https://profiles.google.com/lumeng.dev" + nickname="lumeng.dev" + subject="comment 2" + date="2011-05-22T01:22:42Z" + content=""" +Is it possible to have a section of `rawhtml` in a `foo.mdwn` file so I can mix `markdown` with `HTML` with ``? +"""]] diff --git a/doc/forum/__42__.html_source_file_containing___60__script__62__...__60____47__script__62___not_working__63__/comment_3_6ffc30e27387366b48112198b66c01fa._comment b/doc/forum/__42__.html_source_file_containing___60__script__62__...__60____47__script__62___not_working__63__/comment_3_6ffc30e27387366b48112198b66c01fa._comment new file mode 100644 index 000000000..44f82ed2c --- /dev/null +++ b/doc/forum/__42__.html_source_file_containing___60__script__62__...__60____47__script__62___not_working__63__/comment_3_6ffc30e27387366b48112198b66c01fa._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + nickname="joey" + subject="comment 3" + date="2011-05-22T17:27:32Z" + content=""" +No, if the htmlscrubber is enabled for that page it will still scrub it. +"""]] diff --git a/doc/forum/access_restrictions:_for_extranet.mdwn b/doc/forum/access_restrictions:_for_extranet.mdwn new file mode 100644 index 000000000..66f0f7fea --- /dev/null +++ b/doc/forum/access_restrictions:_for_extranet.mdwn @@ -0,0 +1,8 @@ +Hi folks, + +are there any plugins or best-ways to create a kind of extranet. Just a few pages or namespaces with access restrictions? + +There is a [htaccess solution](http://www.branchable.com/forum/Read_access_restrictions/). Would be fine, but only if there are other solutions. + +greetz +klml diff --git a/doc/forum/access_restrictions:_for_extranet/comment_1_a0666c3c15661fb0fff70f313cd0d47d._comment b/doc/forum/access_restrictions:_for_extranet/comment_1_a0666c3c15661fb0fff70f313cd0d47d._comment new file mode 100644 index 000000000..767fb7c03 --- /dev/null +++ b/doc/forum/access_restrictions:_for_extranet/comment_1_a0666c3c15661fb0fff70f313cd0d47d._comment @@ -0,0 +1,29 @@ +[[!comment format=mdwn + username="http://smcv.pseudorandom.co.uk/" + nickname="smcv" + subject="comment 1" + date="2012-04-15T20:53:44Z" + content=""" +Read/view access and write/edit access are rather different. +You can limit write access via wiki configuration, and even +configure it over the web with [[plugins/websetup]]. + +The only way to limit read access is to restrict access to the + entire wiki via `.htaccess` or other web server configuration, +preferably combined with use of `https`. +IkiWiki can't limit read access to pages on its own[*], +because it's a wiki compiler: when a page is viewed, the web +server serves the compiled HTML without IkiWiki being involved. + +The best way to integrate access control into IkiWiki would +probably be to have a CGI user interface for `.htaccess` or +equivalent - but you'd still have to be careful, because, +for instance, if a user can edit public pages, then they +can insert a `\[[!include]]` directive to make the content +of a private page public. As a result, the safest way to +use it is to keep public and private information in +separate wikis. + +[\*] strictly speaking, it *could* via a new plugin, but +that would defeat many of its advantages +"""]] diff --git a/doc/forum/access_restrictions:_for_extranet/comment_2_563040aa099c9366dc5701eb4bc9c10d._comment b/doc/forum/access_restrictions:_for_extranet/comment_2_563040aa099c9366dc5701eb4bc9c10d._comment new file mode 100644 index 000000000..75b9d49bc --- /dev/null +++ b/doc/forum/access_restrictions:_for_extranet/comment_2_563040aa099c9366dc5701eb4bc9c10d._comment @@ -0,0 +1,20 @@ +[[!comment format=mdwn + username="klml" + ip="188.174.93.195" + subject="comment 2" + date="2012-04-16T19:57:20Z" + content=""" +hi smcv, + +> when a page is viewed, the web server serves the compiled HTML without IkiWiki being involved. + +yes you are right, but I still think its a feature ;) + +> The best way to integrate access control into IkiWiki would probably be to have a CGI user interface for .htaccess or equivalent - but you'd still have to be careful, because, for instance, if a user can edit public pages, then they can insert a \[[!include]] directive to make the content of a private page public. + +My usecase is a website with an small internal area, its just for not \"so public\" files, no private files. And I only have some trusted users. + +thx +klml + +"""]] diff --git a/doc/forum/an_alternative_approach_to_structured_data.mdwn b/doc/forum/an_alternative_approach_to_structured_data.mdwn new file mode 100644 index 000000000..6e6af8adb --- /dev/null +++ b/doc/forum/an_alternative_approach_to_structured_data.mdwn @@ -0,0 +1,63 @@ +## First Pass + +Looking at the discussion about [[todo/structured_page_data]], it looks a bit like folks are bogged down in figuring out what *markup* to use for structured page data, something I doubt that people will really agree on. And thus, little progress is made. + +I propose that, rather than worry about what the data looks like, that we take a similar approach +to the way Revision Control Systems are used in ikiwiki: a front-end + back-end approach. +The front-end would be a common interface, where queries are made about the structured data, +and there would be any number of back-ends, which could use whatever markup or format that they desired. + +To that purpose, I've written the [[plugins/contrib/field]] plugin for a possible front-end. +I called it "field" because each page could be considered a "record" where one could request the values of "fields" of that record. +The idea is that back-end plugins would register functions which can be called when the value of a field is desired. + +This is gone into in more depth on the plugin page itself, but I would appreciate feedback and improvements on the approach. +I think it could be really powerful and useful, especially if it becomes part of ikiwiki proper. + +--[[KathrynAndersen]] + +> It looks like an interesting idea. I don't have time right now to look at it in depth, but it looks interesting. -- [[Will]] + +> I agree such a separation makes some sense. But note that the discussion on [[todo/structured_page_data]] +> talks about associating data types with fields for a good reason: It's hard to later develop a good UI for +> querying or modifying a page's data if all the data has an implicit type "string". --[[Joey]] + +>> I'm not sure that having an implicit type of "string" is really such a bad thing. After all, Perl itself manages with just string and number, and easily converts from one to the other. Strong typing is generally used to (a) restrict what can be done with the data and/or (b) restrict how the data is input. The latter could be done with some sort of validated form, but that, too, could be decoupled from looking up and returning the value of a field. --[[KathrynAndersen]] + +## Second Pass + +I have written additional plugins which integrate with the [[plugins/contrib/field]] plugin to both set and get structured page data. + +* [[plugins/contrib/getfield]] - query field values inside a page using {{$*fieldname*}} markup +* [[plugins/contrib/ftemplate]] - like [[plugins/template]] but uses "field" data as well as passed-in data +* [[plugins/contrib/ymlfront]] - looks for YAML-format data at the front of a page; this is just one possible back-end for the structured data + +--[[KathrynAndersen]] + +> I'm not an IkiWiki committer ([[Joey]] is the only one I think) +> but I really like the look of this scheme. In particular, +> having `getfield` interop with `field` without being *part of* +> `field` makes me happy, since I'm not very keen on `getfield`'s +> syntax (i.e. "ugh, yet another mini-markup-language without a +> proper escaping mechanism"), but this way people can experiment +> with different syntaxes while keeping `field` for the +> behind-the-scenes bits. +> +>> I've started using `field` on a private site and it's working +>> well for me; I'll try to do some code review on its +>> [[plugins/contrib/field/discussion]] page. --s +> +> My [[plugins/contrib/album]] plugin could benefit from +> integration with `field` for photos' captions and so on, +> probably... I'll try to work on that at some point. +> +> [[plugins/contrib/report]] may be doing too much, though: +> it seems to be an variation on `\[[inline archive="yes"]]`, +> with an enhanced version of sorting, a mini version of +> [[todo/wikitrails]], and some other misc. I suspect it could +> usefully be divided up into discrete features? One good way +> to do that might be to shuffle bits of its functionality into +> the IkiWiki distribution and/or separate plugins, until there's +> nothing left in `report` itself and it can just go away. +> +> --[[smcv]] diff --git a/doc/forum/appear_if_you_are_login_or_not_in_a_page.mdwn b/doc/forum/appear_if_you_are_login_or_not_in_a_page.mdwn new file mode 100644 index 000000000..be9854a08 --- /dev/null +++ b/doc/forum/appear_if_you_are_login_or_not_in_a_page.mdwn @@ -0,0 +1,36 @@ +Hi, + +Can you give me a hint for showing if one user is logged or not. If user is logged, then I want to display the user name, as wikipedia or dokuwiki for example. +Regards, +Xan. + +> ikiwiki doesn't serve pages, so this can't be done inside ikiwiki. +> For certain kinds of authentication it might be possible anyway. +> For instance, if you're using [[plugins/httpauth]] exclusively and +> your server has PHP, you could put ` ?>` in all the relevant ikiwiki [[templates]] and arrange for the +> generated HTML pages to get run through the PHP interpreter. The trick +> would work differently with other [[plugins/type/auth]] plugins, +> if at all. --[[Schmonz]] + +>> Thanks a lot, Xan. + +>>> Another possible trick would be to use some Javascript to make a +>>> "who am I?" AJAX request to the CGI (the CGI would receive the +>>> session cookie, if any, and be able to answer). Obviously, this +>>> wouldn't work for users who've disabled Javascript, but since it's +>>> non-essential, that's not so bad. You'd need to +>>> [[write_a_plugin|plugins/write]] to add a suitable CGI action, +>>> perhaps ?do=whoami, and insert the Javascript. --[[smcv]] + +>>>> It's an idea, but you're trading off a serious speed hit for a very +>>>> minor thing. --[[Joey]] + +>>>> Cool idea. A similar trick (I first saw it +>>>> [here](http://www.peej.co.uk/articles/http-auth-with-html-forms.html)) +>>>> could be used to provide a [[plugins/passwordauth]]-like login form +>>>> for [[plugins/httpauth]]. --[[Schmonz]] + +>>>>> I always assumed the entire reason someone might want to use the +>>>>> httpauth plugin is to avoid nasty site-specific login forms.. +>>>>> --[[Joey]] diff --git a/doc/forum/attachments_fail_to_upload.mdwn b/doc/forum/attachments_fail_to_upload.mdwn new file mode 100644 index 000000000..62e363a16 --- /dev/null +++ b/doc/forum/attachments_fail_to_upload.mdwn @@ -0,0 +1,8 @@ +I am having a problem with ikiwiki on an armel processor based machine running 32 bit debian squeeze. +I first installed the ikiwiki deb from the repos and realized there was a problem uploading images. +I downloaded the latest version of ikiwiki from the git repo and made sure I had all of the necessary dependencies and libraries. +Make doesn't seem to complain about anything being missing and make test passes fine. I can create a new wiki and edit pages but anytime I try to upload an image it fails. +I have the attachment plugin activated.And I added mimetype(image/*) and maxsize(5000kb) to the PageSpec field but that made no difference. +I am able to successully add images to the appropriate folders manually via the command line and the commit them to git but I'd liekt o make it work through the web interface. Is there anything that I may have missed? + +Edit: I just noticed that if I save the page anyway after the the javascript ui reports that the upload has failed, the file has in fact uploaded. diff --git a/doc/forum/attachments_fail_to_upload/comment_1_577adde1dfa49463dfa8e169c462fc42._comment b/doc/forum/attachments_fail_to_upload/comment_1_577adde1dfa49463dfa8e169c462fc42._comment new file mode 100644 index 000000000..7d2d66c14 --- /dev/null +++ b/doc/forum/attachments_fail_to_upload/comment_1_577adde1dfa49463dfa8e169c462fc42._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + nickname="joey" + subject="comment 1" + date="2012-03-01T16:11:09Z" + content=""" +Saying \"it fails\" is not going to get the best help. If you can look in your web server's error.log file, or get a error message from somewhere else, you might get somewhere. + +You might also check if the machine is running out of memory. It's quite likely that a POSTed attachment is all buffered in the web server's memory before ikiwiki gets ahold of it. +"""]] diff --git a/doc/forum/attachments_fail_to_upload/comment_2_473f38c6d523496fac8dad13ac6d20c3._comment b/doc/forum/attachments_fail_to_upload/comment_2_473f38c6d523496fac8dad13ac6d20c3._comment new file mode 100644 index 000000000..f491a9b71 --- /dev/null +++ b/doc/forum/attachments_fail_to_upload/comment_2_473f38c6d523496fac8dad13ac6d20c3._comment @@ -0,0 +1,12 @@ +[[!comment format=mdwn + username="jaime" + ip="201.141.41.68" + subject="comment 2" + date="2012-03-01T20:08:47Z" + content=""" +Sorry, \"failed\" is just the message ikwiki's web interface returns. Nginx's error logs don't seem to register anything when the \"failure\" occurs. I am not sure how to properly monitor what is happening with the web server's memory at the time of uploading but just watching htop I can see that the ikiwiki begins to use 100% if the cpu until the process stops but there doesn't seem to be much impact on the overall memory usage, seems to remain about half of available memory. +I'm sorry if that is not helpful. If you can give me some pointers on where to look for more detailed information I can follow instructions. + + + +"""]] diff --git a/doc/forum/attachments_fail_to_upload/comment_3_799a2f1b7b259157e97fd31ec76fb845._comment b/doc/forum/attachments_fail_to_upload/comment_3_799a2f1b7b259157e97fd31ec76fb845._comment new file mode 100644 index 000000000..ebf2756a4 --- /dev/null +++ b/doc/forum/attachments_fail_to_upload/comment_3_799a2f1b7b259157e97fd31ec76fb845._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + nickname="joey" + subject="comment 3" + date="2012-03-03T14:54:10Z" + content=""" +What version are you running on squeeze? The version shipped with Debian stable does not have the javascript uploader. + +There was a recent problem involving filenames with unicode characters that broke the javascript uploader as you describe, which was fixed in a recent release. +"""]] diff --git a/doc/forum/attachments_fail_to_upload/comment_4_e37d1497acafd3fda547462f000636e3._comment b/doc/forum/attachments_fail_to_upload/comment_4_e37d1497acafd3fda547462f000636e3._comment new file mode 100644 index 000000000..148c7b799 --- /dev/null +++ b/doc/forum/attachments_fail_to_upload/comment_4_e37d1497acafd3fda547462f000636e3._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="jaime" + ip="201.141.91.196" + subject="ikiwiki version 3.20120203" + date="2012-03-05T19:52:02Z" + content=""" +I installed ikiwiki version 3.20120203 from source. Should I pull more recent changes from the repo? +"""]] diff --git a/doc/forum/attachments_fail_to_upload/comment_5_da03f9c4917cb1ef52de984b8ba86b68._comment b/doc/forum/attachments_fail_to_upload/comment_5_da03f9c4917cb1ef52de984b8ba86b68._comment new file mode 100644 index 000000000..dbe0d6574 --- /dev/null +++ b/doc/forum/attachments_fail_to_upload/comment_5_da03f9c4917cb1ef52de984b8ba86b68._comment @@ -0,0 +1,11 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + nickname="joey" + subject="comment 5" + date="2012-03-05T20:48:50Z" + content=""" +Your version already contains the unicode fix, which was commit 1572c3c376df36ea09e27a1ea437e3a75cdf0f84. + +I think it's possible that the javascript file upload widget is timing out waiting for a response from ikiwiki when uploading the file. Since this is a slow CPU, it might exceed some limit in that code. At this point all I know is that the javascript file upload widget is setting an error flag, which is displayed as \"failed!\" in red. The next step is probably to get a http protocol analizer like firebug and see what if anything is being returned by the ikiwiki.cgi when the attachment is uploaded to it -- it should return some JSON with a `stored_msg` field. + +"""]] diff --git a/doc/forum/attachments_fail_to_upload/comment_6_04498946a300ddb652dec73c2950f48f._comment b/doc/forum/attachments_fail_to_upload/comment_6_04498946a300ddb652dec73c2950f48f._comment new file mode 100644 index 000000000..877050eb5 --- /dev/null +++ b/doc/forum/attachments_fail_to_upload/comment_6_04498946a300ddb652dec73c2950f48f._comment @@ -0,0 +1,19 @@ +[[!comment format=mdwn + username="jaime" + ip="201.141.54.196" + subject="comment 6" + date="2012-03-08T01:34:57Z" + content=""" +Ok... figured out how to use firebug, started the profile, and tried uploading an image. POST http://myserver/ikiwiki.cgi immediately turns red with a little X as I get the javascript \"failed\" message in the ui. In the post tab of firebug, halfway through the binary content of the png I can see the message \"... Firebug request size limit has been reached by Firebug. ... \" + +So next I try uploading a tiny 3k image. This time the post completes and I can see \"Error: Can't locate JSON.pm in @INC\" in the output. A bit of googling tells me I need to install the libjson-perl package. Done. + +I try and upload the tiny 3k image again. This time it works. :) +I try and upload a 9k image and the POST just dies just like before with the \"... Firebug request size limit has been reached by Firebug. ... \" in the post tab. + +So I tried changing the extensions.firebug.netDisplayedPostBodyLimit variable in firefox to see if that would me to get more info. Now the I don't get the request size limit message but the post still doesn't get anything back. + +I decided to try some other http protocal analyzers. Firefox 10 internal webdeveloper tools don't give me any more info. +Next I tried HttpFox and the only thing I get back is this... +Error loading content (NS_ERROR_DOCUMENT_NOT_CACHED) +"""]] diff --git a/doc/forum/bashman.mdwn b/doc/forum/bashman.mdwn new file mode 100644 index 000000000..32c006bfb --- /dev/null +++ b/doc/forum/bashman.mdwn @@ -0,0 +1,7 @@ + [[!teximg code="\{}_pF_q(a_1,...,a_p;c_1,...,c_q;z) = \sum_{n=0}^\infty \frac{(a_1)_n\cdot\cdot\cdot(a_p)_n}{(c_1)_n\cdot\cdot\cdot(c_q)_n} \frac{z^n}{n!}"]] + +JAJAJA, the teximg is not loaded... :-( + +Bye. + +> This wiki does not have teximg enabled. --[[Joey]] diff --git a/doc/forum/blocked_by_blogspam.mdwn b/doc/forum/blocked_by_blogspam.mdwn new file mode 100644 index 000000000..c28f38572 --- /dev/null +++ b/doc/forum/blocked_by_blogspam.mdwn @@ -0,0 +1,9 @@ +[[!meta title="Wrongfully blocked by blogspam"]] + +For a few days, I can no longer post anything on ikiwiki.info using the web interface, but I can still do so using git. Everytime I try to edit a page, I get following message: + + Error: Sorry, but that looks like spam to [[blogspam|http://blogspam.net/]]: Comment rejected by admin. + +Does someone know what the problem is? + +--[[Louis|spalax]] diff --git a/doc/forum/build_error:_Cannot_decode_string_with_wide_characters.mdwn b/doc/forum/build_error:_Cannot_decode_string_with_wide_characters.mdwn new file mode 100644 index 000000000..2e5ac7e6e --- /dev/null +++ b/doc/forum/build_error:_Cannot_decode_string_with_wide_characters.mdwn @@ -0,0 +1,12 @@ + $ ikiwiki -setup mywiki.setup + generating wrappers.. + rebuilding wiki.. + Cannot decode string with wide characters at /opt/local/lib/perl5/5.12.3/darwin-multi-2level/Encode.pm line 175. + +I am running Mac OS X 10.6.8 + + $ ikiwiki --version + ikiwiki version 3.20110608 + $ perl --version + + This is perl 5, version 12, subversion 3 (v5.12.3) built for darwin-multi-2level diff --git a/doc/forum/build_error:_Cannot_decode_string_with_wide_characters/comment_1_83fbb415dd3ae6a19ed5ea5f82065c28._comment b/doc/forum/build_error:_Cannot_decode_string_with_wide_characters/comment_1_83fbb415dd3ae6a19ed5ea5f82065c28._comment new file mode 100644 index 000000000..d1b555b2a --- /dev/null +++ b/doc/forum/build_error:_Cannot_decode_string_with_wide_characters/comment_1_83fbb415dd3ae6a19ed5ea5f82065c28._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + nickname="joey" + subject="comment 1" + date="2012-03-13T03:57:42Z" + content=""" +The problem could be your system's locale setting. Perhaps LANG is not set to a utf-8 capable locale. +"""]] diff --git a/doc/forum/build_error:_Cannot_decode_string_with_wide_characters/comment_2_d258536c98538d4744f66eb3132439a9._comment b/doc/forum/build_error:_Cannot_decode_string_with_wide_characters/comment_2_d258536c98538d4744f66eb3132439a9._comment new file mode 100644 index 000000000..28222618d --- /dev/null +++ b/doc/forum/build_error:_Cannot_decode_string_with_wide_characters/comment_2_d258536c98538d4744f66eb3132439a9._comment @@ -0,0 +1,20 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawmKyeW2G4jjSdnL1m6kPPtAiGFUBsnYCfY" + nickname="FName" + subject="comment 2" + date="2012-03-13T04:43:25Z" + content=""" + $ locale + LANG=\"en_US.UTF-8\" + LC_COLLATE=\"en_US.UTF-8\" + LC_CTYPE=\"en_US.UTF-8\" + LC_MESSAGES=\"en_US.UTF-8\" + LC_MONETARY=\"en_US.UTF-8\" + LC_NUMERIC=\"en_US.UTF-8\" + LC_TIME=\"en_US.UTF-8\" + LC_ALL= + $ uname -a + Darwin x4430 10.8.0 Darwin Kernel Version 10.8.0: Tue Jun 7 16:33:36 PDT 2011; root:xnu-1504.15.3~1/RELEASE_I386 i386 + +Does it look OK? +"""]] diff --git a/doc/forum/build_error:_Cannot_decode_string_with_wide_characters/comment_3_d62173d0ae220ab7b063631952856587._comment b/doc/forum/build_error:_Cannot_decode_string_with_wide_characters/comment_3_d62173d0ae220ab7b063631952856587._comment new file mode 100644 index 000000000..8dc2f9851 --- /dev/null +++ b/doc/forum/build_error:_Cannot_decode_string_with_wide_characters/comment_3_d62173d0ae220ab7b063631952856587._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + nickname="joey" + subject="comment 3" + date="2012-03-16T20:33:20Z" + content=""" +The locale settings look ok. + +I'd try upgrading your perl. 5.12.3 is rather old, and the code that is failing is part of perl. +"""]] diff --git a/doc/forum/build_error:_Cannot_decode_string_with_wide_characters/comment_4_d5d0174e09a94359c23fd9c006a22bbc._comment b/doc/forum/build_error:_Cannot_decode_string_with_wide_characters/comment_4_d5d0174e09a94359c23fd9c006a22bbc._comment new file mode 100644 index 000000000..57c99bee9 --- /dev/null +++ b/doc/forum/build_error:_Cannot_decode_string_with_wide_characters/comment_4_d5d0174e09a94359c23fd9c006a22bbc._comment @@ -0,0 +1,50 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawmKyeW2G4jjSdnL1m6kPPtAiGFUBsnYCfY" + nickname="FName" + subject="Still can't use ikiwiki on Mac OS X" + date="2012-10-21T17:12:15Z" + content=""" +I'm still not able to use Ikiwiki on Mac: + + $ ikiwiki --setup ./web.setup + generating wrappers.. + rebuilding wiki.. + Cannot decode string with wide characters at /opt/local/lib/perl5/5.12.4/darwin-thread-multi-2level/Encode.pm line 174. + + + $ ls -la /opt/local/bin/perl* + lrwxr-xr-x 1 root admin 20 Oct 21 12:06 /opt/local/bin/perl -> /opt/local/bin/perl5 + lrwxr-xr-x 1 root admin 23 Oct 21 12:06 /opt/local/bin/perl5 -> /opt/local/bin/perl5.12 + -rwxr-xr-x 1 root admin 9896 Jun 26 01:39 /opt/local/bin/perl5.12 + lrwxr-xr-x 1 root admin 8 Jun 26 01:39 /opt/local/bin/perl5.12.4 -> perl5.12 + -rwxr-xr-x 1 root admin 10000 Jun 26 01:55 /opt/local/bin/perl5.14 + lrwxr-xr-x 1 root admin 8 Jun 26 01:56 /opt/local/bin/perl5.14.2 -> perl5.14 + -rwxr-xr-x 1 root admin 10000 Aug 23 13:41 /opt/local/bin/perl5.16 + lrwxr-xr-x 1 root admin 8 Aug 23 13:42 /opt/local/bin/perl5.16.1 -> perl5.16 + lrwxr-xr-x 1 root admin 12 Oct 21 11:44 /opt/local/bin/perlbug -> perlbug-5.16 + -rwxr-xr-x 2 root admin 45815 Jun 26 01:39 /opt/local/bin/perlbug-5.12 + -rwxr-xr-x 2 root admin 45203 Jun 26 01:55 /opt/local/bin/perlbug-5.14 + -rwxr-xr-x 2 root admin 41712 Aug 23 13:41 /opt/local/bin/perlbug-5.16 + lrwxr-xr-x 1 root admin 12 Oct 21 11:44 /opt/local/bin/perldoc -> perldoc-5.16 + -rwxr-xr-x 1 root admin 244 Jun 26 01:39 /opt/local/bin/perldoc-5.12 + -rwxr-xr-x 1 root admin 244 Jun 26 01:55 /opt/local/bin/perldoc-5.14 + -rwxr-xr-x 1 root admin 244 Aug 23 13:41 /opt/local/bin/perldoc-5.16 + lrwxr-xr-x 1 root admin 12 Oct 21 11:44 /opt/local/bin/perlivp -> perlivp-5.16 + -rwxr-xr-x 1 root admin 12484 Jun 26 01:39 /opt/local/bin/perlivp-5.12 + -rwxr-xr-x 1 root admin 12297 Jun 26 01:55 /opt/local/bin/perlivp-5.14 + -rwxr-xr-x 1 root admin 10802 Aug 23 13:41 /opt/local/bin/perlivp-5.16 + lrwxr-xr-x 1 root admin 15 Oct 21 11:44 /opt/local/bin/perlthanks -> perlthanks-5.16 + -rwxr-xr-x 2 root admin 45815 Jun 26 01:39 /opt/local/bin/perlthanks-5.12 + -rwxr-xr-x 2 root admin 45203 Jun 26 01:55 /opt/local/bin/perlthanks-5.14 + -rwxr-xr-x 2 root admin 41712 Aug 23 13:41 /opt/local/bin/perlthanks-5.16 + + +If I simply relink `/opt/local/bin/perl` to a newer version of perl such as `/opt/local/bin/perl5.16`, it still doesn't work, as it seems + + $ ikiwiki -version + ikiwiki version 3.20110608 + +simply force to use perl5.12. + + +"""]] diff --git a/doc/forum/build_error:_Cannot_decode_string_with_wide_characters/comment_5_e652027a8f90ebef6f21613b5784ded2._comment b/doc/forum/build_error:_Cannot_decode_string_with_wide_characters/comment_5_e652027a8f90ebef6f21613b5784ded2._comment new file mode 100644 index 000000000..08bde8c85 --- /dev/null +++ b/doc/forum/build_error:_Cannot_decode_string_with_wide_characters/comment_5_e652027a8f90ebef6f21613b5784ded2._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawnxp2XU8gIribhhGhGuYtU6eMMwHv5gUGI" + nickname="Amitai" + subject="may I recommend pkgsrc?" + date="2012-10-22T03:50:56Z" + content=""" +Looks like the MacPorts ikiwiki package is old. I use ikiwiki from pkgsrc as mentioned in [[tips/ikiwiki_on_mac_os_x]]. I also maintain the package, so it's updated regularly. +"""]] diff --git a/doc/forum/build_error:_Cannot_decode_string_with_wide_characters/comment_6_ba76f7f8ef46fb58d36fb2cda4b242ff._comment b/doc/forum/build_error:_Cannot_decode_string_with_wide_characters/comment_6_ba76f7f8ef46fb58d36fb2cda4b242ff._comment new file mode 100644 index 000000000..a4ae63add --- /dev/null +++ b/doc/forum/build_error:_Cannot_decode_string_with_wide_characters/comment_6_ba76f7f8ef46fb58d36fb2cda4b242ff._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawmKyeW2G4jjSdnL1m6kPPtAiGFUBsnYCfY" + nickname="FName" + subject="Am i the only one using MacPorts and Ikiwiki together?" + date="2013-08-10T23:45:40Z" + content=""" +This exact same problem has been stopping me from using Ikiwiki locally. I'm still able to push to remote Ikiwiki instance. But I'd like to push it to local repo and have the website built locally first so I can confirm everything runs fine. Everytime I try to build it locally, i have this exact same problem. +"""]] diff --git a/doc/forum/build_error:_Cannot_decode_string_with_wide_characters/comment_7_e4f7c1da09571085070275e12c09b12f._comment b/doc/forum/build_error:_Cannot_decode_string_with_wide_characters/comment_7_e4f7c1da09571085070275e12c09b12f._comment new file mode 100644 index 000000000..447cec80f --- /dev/null +++ b/doc/forum/build_error:_Cannot_decode_string_with_wide_characters/comment_7_e4f7c1da09571085070275e12c09b12f._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="schmonz" + ip="198.228.228.165" + subject="MacPorts still hasn't updated past 2011 ikiwiki with a seriously old Perl" + date="2013-08-11T01:40:23Z" + content=""" +According to [this page](http://www.macports.org/ports.php?by=name&substr=Ikiwiki) nothing has changed in MacPorts' ikiwiki build. Have you tried contacting the package maintainer or, failing that, submitting an update request to the relevant mailing list? + +If MacPorts is this behind the times, it doesn't make sense to me to recommend it to anyone. But I'm biased in favor of pkgsrc, so I don't feel comfortable editing the [[tips/ikiwiki on Mac OS X]] page to promote the thing I happen to prefer... but pkgsrc has Perl 5.18, and I keep pkgsrc's ikiwiki package updated at every release. --[[schmonz]] +"""]] diff --git a/doc/forum/chinese_character_problem.mdwn b/doc/forum/chinese_character_problem.mdwn new file mode 100644 index 000000000..aea55703f --- /dev/null +++ b/doc/forum/chinese_character_problem.mdwn @@ -0,0 +1,21 @@ +just finished setting up ikiwiki.. + +I can type chinese, save and display it correctly in ikiwiki for the first time. However, when i try to edit the page again, the chinese character in the form is unrecognizable. you can see it here + +I am using the latest ikiwiki(manually installed as non-root user) and CGI::FormBuilder(3.0501) on Debian 4.0 + +这个没问题 it is not a problem on ikiwiki website though. + +Thanks. + + +> Is your system perhaps not configured with a utf-8 default locale? Or ikiwiki not configured to use it? +> Make sure that some utf-8 locale is enabled (in /etc/locale.gen on Debian for example) and try setting `locale` in your > ikiwiki setup file. --[[Joey]] + +I have installed locales-all and locale -a shows that zh_CN.UTF-8 is installed(there is no /etc/local.gen file though). then I enabled this line "locale => 'zh_CN.UTF-8'" in my wiki setup and -setup again. but that generated lots error messages "Missing constant domain at (eval 30) line 3" + +sorry being a n00b on this thing what else can I do? + +> See [[bugs/Missing_constant_domain_at_IkiWiki.pm_line_842]]. +> Looks like you need to upgrade to a newer version of +> [[!cpan Locale::gettext]] --[[Joey]] diff --git a/doc/forum/cleaning_up_discussion_pages_and_the_like.mdwn b/doc/forum/cleaning_up_discussion_pages_and_the_like.mdwn new file mode 100644 index 000000000..35ceae59b --- /dev/null +++ b/doc/forum/cleaning_up_discussion_pages_and_the_like.mdwn @@ -0,0 +1,11 @@ +For example in [[forum/ikiwiki__39__s_notion_of_time]], should one remove the +text about the implementation bug that has been fixed, or should it stay there, +for reference? --[[tschwinge]] + +> I have no problem with cleaning up obsolete stuff in the forum, tips, etc. +> --[[Joey]] + +That's also what I think: such discussions or comments on [[forum]] discussion +pages, or generally on all pages' [[Discussion]] subpages, can be removed if +either they're simply not valid / interesting / ... anymore, or if they've been +used to improve the *real* documentation. --[[tschwinge]] diff --git a/doc/forum/converting_binary_files.mdwn b/doc/forum/converting_binary_files.mdwn new file mode 100644 index 000000000..6b3187f38 --- /dev/null +++ b/doc/forum/converting_binary_files.mdwn @@ -0,0 +1,29 @@ +I would like to use ikiwiki to build a static site which needs some transformations to be made on binary assets. A simple example is to translate a .odp presentation to .pdf using (e.g.) unoconv. If I add a new .odp attachment, or push one into the repo, I want the corresponding .pdf to appear in the generated site. What's the right place to hook in to do this? + +I've made an experimental prototype which hooks into needsbuild, builds the pages then and there, and at the same time removes them from the list of pages to be built. + +~~~ +sub needsbuild { + my $files=shift; + my $nfiles=[]; + foreach my $f (@$files) { + if ($f =~ /\.odp$/) { + my $g = $f; + $g =~ s/\.odp$/\.pdf/; + debug("building $f to $g"); + will_render($f, $g); + if (system("unoconv","-f","pdf","-o",IkiWiki::dirname("$config{destdir}/$g"),srcfile($f)) != 0) { + error("unoconv: failed to translate $f to $g"); + } + } + else { + push @$nfiles, $f; + } + }; + return $nfiles; +} +~~~ + +It appears to work, but is this the right way to do it, bearing in mind ikiwiki's dependency tracking and the like? And is the usage of will_render() correct? + +[[BrianCandler]] diff --git a/doc/forum/copyright_and_license_template_variables___40__where_are_they_set__63____41__.mdwn b/doc/forum/copyright_and_license_template_variables___40__where_are_they_set__63____41__.mdwn new file mode 100644 index 000000000..afca582fd --- /dev/null +++ b/doc/forum/copyright_and_license_template_variables___40__where_are_they_set__63____41__.mdwn @@ -0,0 +1,13 @@ +The default template includes TMPL_IF LICENSE and TMPL_IF COPYRIGHT, but I can't figure out where these are set. + +This page seems to indicate they are created by the [[plugins/meta]] plugin: + +[[Default Content for Copyright and License|plugins/contrib/default_content_for___42__copyright__42___and___42__license__42__/]] + +Is this true? It just seems a little odd that the default template contains variables that are set by a non-default plugin, so I just wanted to confirm that. + +Thanks! + +--[[users/acodispo]] + +> It is true. --[[Joey]] diff --git a/doc/forum/create_download_link.mdwn b/doc/forum/create_download_link.mdwn new file mode 100644 index 000000000..44899b118 --- /dev/null +++ b/doc/forum/create_download_link.mdwn @@ -0,0 +1,4 @@ +Thank you very much for ikiwiki. I successfully started using it. +Now I have a simple question that I am not able to answer myself at the moment: + +In the directory structure of ikiwiki I placed a file (in this case a video). In an ikiwiki page I would like to create a link to this file, so that the user can download it. Of course I can do this using a link to the absolute url, including hostname and the full path. But when I move the wiki to another host, this will not be valid anymore. Therefore my question: Is there a way to automatically create a link to a file by relatively specifying the destination? Say, I have a directory foo with a page foo/bar.mdwn and a folder foo/downloads with a file foo/downloads/video.mp4, I would like to refer to this file using "downloads/video.mp4" or something similar. Is there such a possibility? diff --git a/doc/forum/create_download_link/comment_1_4797493157c569f8893b53b5e5a58e73._comment b/doc/forum/create_download_link/comment_1_4797493157c569f8893b53b5e5a58e73._comment new file mode 100644 index 000000000..cec5fd6bb --- /dev/null +++ b/doc/forum/create_download_link/comment_1_4797493157c569f8893b53b5e5a58e73._comment @@ -0,0 +1,14 @@ +[[!comment format=mdwn + username="http://smcv.pseudorandom.co.uk/" + nickname="smcv" + subject="comment 1" + date="2011-09-11T10:20:14Z" + content=""" +You could use a relative URL in a standard [[ikiwiki/MarkDown]] link: + + [download the video](../downloads/video.mp4) + +or an ikiwiki [[ikiwiki/WikiLink]] to the file (just like you would for a page): + + \[[download the video|foo/bar/downloads/video.mp4]] +"""]] diff --git a/doc/forum/creating_redirect_index.mdwn__63___.mdwn b/doc/forum/creating_redirect_index.mdwn__63___.mdwn new file mode 100644 index 000000000..50d85183f --- /dev/null +++ b/doc/forum/creating_redirect_index.mdwn__63___.mdwn @@ -0,0 +1,6 @@ +Hi - we are switching to ikiwiki for the Savannah documentation . I installed the Debian ikiwiki package and it is working fine. My question: is it possible to redirect the top-level index.mdwn to another page? (Traditionally we have used .) + +Sorry if this is obvious. I looked around for existing plugins or methods, but what I found seemed to have other prerequisites that I could not easily figure out, and looked to be more about moving pages than redirecting. I could do it at the Apache level, but I thought it would be simpler and cleaner to do it within ikiwiki itself if possible (e.g., with some plugin+directive in index.mdwn?). + +Any pointers or info greatly appreciated. Thanks, +karl@gnu.org diff --git a/doc/forum/creating_redirect_index.mdwn__63___/comment_1_6d609c3a2ba50da4129e15b60362c6d9._comment b/doc/forum/creating_redirect_index.mdwn__63___/comment_1_6d609c3a2ba50da4129e15b60362c6d9._comment new file mode 100644 index 000000000..7395f17d7 --- /dev/null +++ b/doc/forum/creating_redirect_index.mdwn__63___/comment_1_6d609c3a2ba50da4129e15b60362c6d9._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawlcaGfdn9Kye1Gc8aGb67PDVQW4mKbQD7E" + nickname="Amitai" + subject="comment 1" + date="2013-09-04T16:42:17Z" + content=""" +Sounds like you're looking for `[[!meta redir=foo]]`. See the docs for the [[ikiwiki/directive/meta]] directive. +"""]] diff --git a/doc/forum/cutpaste.pm_not_only_file-local.mdwn b/doc/forum/cutpaste.pm_not_only_file-local.mdwn new file mode 100644 index 000000000..c75fc53e0 --- /dev/null +++ b/doc/forum/cutpaste.pm_not_only_file-local.mdwn @@ -0,0 +1,14 @@ +I'd like to use the cutpaste plugin, but not only on a file-local basis: fileA +has \[[!cut id=foo text="foo"]], and fileB does \[[!absorb pagenames=fileA]], +and can then use \[[!paste id=foo]]. + +Therefore, I've written an [*absorb* directive / +plugin](http://nic-nac-project.de/~schwinge/ikiwiki/absorb.pm), which is meant to +absorb pages in order to get hold of their *cut* and *copy* directives' +contents. This does work as expected. But it also absorbs page fileA's *meta* +values, like a *meta title*, etc. How to avoid / solve this? + +Alternatively, do you have a better suggestion about how to achieve what I +described in the first paragraph? + +--[[tschwinge]] diff --git a/doc/forum/cutpaste.pm_not_only_file-local/comment_1_497c62f21fd1b87625b806407c72dbad._comment b/doc/forum/cutpaste.pm_not_only_file-local/comment_1_497c62f21fd1b87625b806407c72dbad._comment new file mode 100644 index 000000000..8cc724a72 --- /dev/null +++ b/doc/forum/cutpaste.pm_not_only_file-local/comment_1_497c62f21fd1b87625b806407c72dbad._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://kerravonsen.dreamwidth.org/" + ip="60.241.8.244" + subject="field and getfield and ymlfront" + date="2010-08-12T02:33:54Z" + content=""" +Have you considered trying the [[plugins/contrib/field]] plugin, and its associated plugins? [[plugins/contrib/ymlfront]] can give you the source (\"cut\") and [[plugins/contrib/getfield]] and/or [[plugins/contrib/report]] can get you the value (\"paste\") including the values from other pages. +"""]] diff --git a/doc/forum/debconf13_ikiwiki_bof.mdwn b/doc/forum/debconf13_ikiwiki_bof.mdwn new file mode 100644 index 000000000..8659da7c3 --- /dev/null +++ b/doc/forum/debconf13_ikiwiki_bof.mdwn @@ -0,0 +1,108 @@ +There has been a meeting of people interested in ikiwiki +[[during debconf13|http://penta.debconf.org/dc13_schedule/events/1060.en.html]] +on 2013-08-11. Videos of the event are linked there for download, or +[[can be viewed online|http://www.irill.org/videos/debconf13/ikiwiki_BoF.webm]]. + +Summary +======= + +Ikiwiki's state and development +------------------------------- + +Ikiwiki has reached a stable state with a working ecosystem, with the majority +of changes being minor adaptions and bugfixes these days. + +It is unlikely that there will be a major overhaul any time soon. + +If incompatible changes are to be made, that might warrant a 4.$DATE +transition, especially given that the [[ikiwiki-transition]] mechanism has not +been used for some time. Potential changes for such a transition will be +discussed (see below). + +Names of pages and links +------------------------ + +Several of [[the issues chrysn deals with|users/chrysn]] revolve about the +differences betwen a page's name, its title, the name of source and destination +page, how they are converted, and which is used when. + +chrysn has starting to draft a page on [[plugins/write/names]], and +would appreciate review and comments. + +Themability +----------- + +The default theme of ikiwiki is more appealing to the people who are expected +to run an ikiwiki setup; end users with Web 2.$current_minor_version +expectations often don't have there tastes served well. + +[[Recently|version 3.20130518]], templates have become more theming friendly, +but for the general case still require the theme to be known to mainline +ikiwiki, lest generic templates diverge. A planned feature is generalized +sidebars, where more places inside the template can be filled using the same +mechanism as currently used in the [[pluginssidebar]] pluin, but changes there +require a complete rebuild. (Not worse than the rebuilds required when changing +the main templates, but it would be more tempting to frequently change them.) + +Examples of fancy ikiwiki themes have been brought up: + + * https://www.gresille.org/ + * https://nos-oignons.net/ + * http://www.rezine.org/accueil/association/ + * https://cas-libres.poivron.org/ + +A generalized version of the [[bootstrap|http://twitter.github.com/bootstrap/]] +[[theme|theme market]] would be appreciated, as the current one is targeted +towards a particular installation. + +Performance +----------- + +Rebuilding many pages takes considerable time, especially when sidebars are +changed. + +A faster way to use the page index (eg. sqlite) would help speeding up the +usual rebuilds, but would not help speeding up massive rebuilds. + +RDF backend +----------- + +On the priority level "crazy ideas", it was discussed to augment or finally +change the index to an RDF triple collection. Statements would be extracted +from the source pages in the scan hook, and form a triple store. Pagespecs +would be resolved to SPARQL queries against that database; also the +[[todo/structured page data]] fields could be addressed with this. + +Optimizations are still possible, even more generally, for example with +dependencies on other pages' title: + +* page A sets its own title with `\[[!meta title="the A page"]]`, which results + in the statement '`<./page_A> dc:title "the A page" .`'. + +* page B uses some kind of auto-titling link to page A: `\[[~|page A]]`, which + queries for '`<./page_A> dc:title ?a`'. + +* When page B is built, it is stored that it depends on statements involving + the term `<./page_A>`, and the current hash value of all statements about + that term. (Those will be computed for all observed statements at scan time. + Pages that use more complex queries might not be able to list all their + dependencies.) + + Also, the queries and query results executing during building page B are + stored in a separate cache. + +* When some other page starts linking to page A, the first cache is + invalidated, as now there are more statements on the subject of + '`<./page_A>`', so page B might need to be rebuilt. Before that is done, its + cached queries are executed. If their results did not change, page B does not + need any further action. + +vCard support +------------- + +The topic of combining ikiwiki with +[[calypso|http://keithp.com/blogs/calypso/]] was brought up +[[in another event|http://penta.debconf.org/dc13_schedule/events/1087.en.html]] +during the same DebConf. + +For further details, see [[todo/vCard rendering]]. diff --git a/doc/forum/debian_backports_update_someone_please.mdwn b/doc/forum/debian_backports_update_someone_please.mdwn new file mode 100644 index 000000000..7102d12a1 --- /dev/null +++ b/doc/forum/debian_backports_update_someone_please.mdwn @@ -0,0 +1,18 @@ +I'm just in the process of deploying ikiwiki and I'd love to use it in the html5 mode instead of in XHTML. Any chance that the ikiwiki's .deb in debian backports will be updated any time soon? + +> Formerer does a good job keeping the backport up-to-date with whatever is in Debian testing. +> Which is the policy of what Backports should contain. So, I just need to stop releasing ikiwiki +> for 2 weeks. :) --[[Joey]] + +>> And are there any chances you doing it... or rather not doing it? + +>>> Sure, I'm busily not doing it right now. Should reach testing in 3 +>>> days. I generally schedule things so a new ikiwiki reaches testing +>>> every 2 weeks to month. Getting important new features and bugfixes out +>>> can take priority though. --[[Joey]] + +>>>> Great! Thanks. + +>>>> Still not available in the backports; did you break the silence on the wire and got back to work [[Joey]]? + +>>>> I was blinded by my stupidity... thanks! diff --git a/doc/forum/default_paths._Are_there_better_defaults__63__.mdwn b/doc/forum/default_paths._Are_there_better_defaults__63__.mdwn new file mode 100644 index 000000000..ab955a513 --- /dev/null +++ b/doc/forum/default_paths._Are_there_better_defaults__63__.mdwn @@ -0,0 +1,8 @@ +Is there a reason for srcdir and repository to be put into the home dir by default? Especially the srcdir seems to be misplaced there because it looks, smells and usually has the same name as the clone you want to generate exactly there to edit the wiki on the command line. Both srcdir and repository should usually be left alone and that doesn't sound like the files you would want to place highly visible into $HOME + +Sure, I have no problem relocating the dirs myself or editing/replacing /etc/ikiwiki/auto.setup whenever I reinstall a new PC, but a better default would spare me and others a bit of work. + +To me it seems $HOME/.ikiwiki/ might be a good default for storing all this essentially-to-be-ignored dirs as it is created anyway. + +Right? Wrong? + diff --git a/doc/forum/default_paths._Are_there_better_defaults__63__/comment_1_3db622152a8ab53841cc13280ca31da4._comment b/doc/forum/default_paths._Are_there_better_defaults__63__/comment_1_3db622152a8ab53841cc13280ca31da4._comment new file mode 100644 index 000000000..da24613e8 --- /dev/null +++ b/doc/forum/default_paths._Are_there_better_defaults__63__/comment_1_3db622152a8ab53841cc13280ca31da4._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="http://christian.amsuess.com/chrysn" + ip="84.114.244.41" + subject="default paths: basedir spec" + date="2014-05-04T13:30:20Z" + content=""" +i have no opinion on *whether* there should be different default directories, but *if* new directories are desired, they should go to their respective paths according to [basedir-spec](http://freedesktop.org/wiki/Specifications/basedir-spec/). + +i'm no expert in that, but i think it means that the setup files go to `XDG_CONFIG_HOME` (`~/.config/ikiwiki/${wikiname_short}.setup`), and srcdir and repository go to `XDG_DATA_HOME` (`~/.local/share/ikiwiki/${wikiname_short}`). +"""]] diff --git a/doc/forum/discussion.mdwn b/doc/forum/discussion.mdwn new file mode 100644 index 000000000..93cf4656e --- /dev/null +++ b/doc/forum/discussion.mdwn @@ -0,0 +1,7 @@ +I like the idea of this forum heirarchy -- but I think a map would be clearer than inlining the sub-pages. -- [[users/Jon]] + +> The easier way to accomplish this is to set archive=yes in the inline. +> Switching to archive view can be useful when there are a lot of long +> posts and people tend to want to scan by title to find interesting ones +> and not necessarily read them all, which probably fits this forum pretty +> well --[[Joey]] diff --git a/doc/forum/double_forward_slash___39____47____47____39___in_the_address_bar.mdwn b/doc/forum/double_forward_slash___39____47____47____39___in_the_address_bar.mdwn new file mode 100644 index 000000000..b5fb2aa18 --- /dev/null +++ b/doc/forum/double_forward_slash___39____47____47____39___in_the_address_bar.mdwn @@ -0,0 +1,3 @@ +Why do all the pages are preceded with a double forward slash in the address bar... ie. http://example.org//ikiwiki/pagespec/ .. maybe someone knows? + +> Sorted, base url in the .setup file had the unnecessary '/' suffix. diff --git a/doc/forum/download_links_for_attachments.mdwn b/doc/forum/download_links_for_attachments.mdwn new file mode 100644 index 000000000..4d6e9c70c --- /dev/null +++ b/doc/forum/download_links_for_attachments.mdwn @@ -0,0 +1,11 @@ +hi, +I'm not sure if I'm doing something wrong but I can't figure out how to get a download link for uploaded attachments. +I'd like to be able to upload arbitrary attachments eg. settings.xml or .gitinore or setup.txt or stuff.zip and be able to add a link to the wiki page which should let the user instantly download that file. +I thought it might be as simple as adding a directive eg. [[!downloadlink .gitinore]] . + +This is driving me nuts, so any help or pointers will be appreciated even if I have to dig in to write a plugin. +I'm running the 3.20100815.9 on Debian 6.0 but then also tried a manual install of 3.20130904.1 which seemed to have caused a bunch of timeout errors and not much improvement on the attachment issue. +Should I try the git version? + +thanks +marius diff --git a/doc/forum/download_links_for_attachments/comment_1_19fe525281e38d3bbe45b31248ca7880._comment b/doc/forum/download_links_for_attachments/comment_1_19fe525281e38d3bbe45b31248ca7880._comment new file mode 100644 index 000000000..5e16410d2 --- /dev/null +++ b/doc/forum/download_links_for_attachments/comment_1_19fe525281e38d3bbe45b31248ca7880._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawnWrt_1YwzE4yP3dF061Wy7uNjPDefJm_I" + nickname="Marius" + subject="Did anybody see this?" + date="2013-10-14T10:59:47Z" + content=""" +Did I post it at the right place? + +thanks +"""]] diff --git a/doc/forum/download_links_for_attachments/comment_2_06231e4ddc271260e51bc371637540de._comment b/doc/forum/download_links_for_attachments/comment_2_06231e4ddc271260e51bc371637540de._comment new file mode 100644 index 000000000..aadc366b2 --- /dev/null +++ b/doc/forum/download_links_for_attachments/comment_2_06231e4ddc271260e51bc371637540de._comment @@ -0,0 +1,14 @@ +[[!comment format=mdwn + username="http://smcv.pseudorandom.co.uk/" + nickname="smcv" + subject="comment 2" + date="2013-10-15T19:48:15Z" + content=""" +It should be as simple as putting the attachment's name in double square +brackets, like `\[[stuff.zip]]`? There isn't really any difference +between a download link and any other link. + +(Or if it's attached to a different page, follow the same +[[ikiwiki/subpage/linkingrules]] as for pages, e.g. you might +write `\[[sandbox/stuff.zip]]` for a file attached to the [[sandbox]].) +"""]] diff --git a/doc/forum/download_links_for_attachments/comment_3_64d12928bc24c48d6f0b5fbb2dfd8f6d._comment b/doc/forum/download_links_for_attachments/comment_3_64d12928bc24c48d6f0b5fbb2dfd8f6d._comment new file mode 100644 index 000000000..7e84786b6 --- /dev/null +++ b/doc/forum/download_links_for_attachments/comment_3_64d12928bc24c48d6f0b5fbb2dfd8f6d._comment @@ -0,0 +1,16 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawnWrt_1YwzE4yP3dF061Wy7uNjPDefJm_I" + nickname="Marius" + subject="that works sort of, depending on the extention" + date="2013-10-18T12:03:26Z" + content=""" +[[setup.txt]] - opens the plain text in the same browser window +[[settings.xml]] - opens the formatted xml as html i.e. I can't right click and save as, I have to copy the text, create an empty file and paste it in +[[.gitignore]] - it does not recognise this file, I have to rename it to gitignore.txt and explain to the user to rename it. + +What I would like is a way to consistently get a dialog that asks the user where to save the file with the correct default file name.. +I've recently figured out how to do this with javascript - it's a bit messy but it works: +http://stackoverflow.com/a/11486284/381083 + +thanks +"""]] diff --git a/doc/forum/download_links_for_attachments/comment_4_7612923064284646c2ed59e2cd52845d._comment b/doc/forum/download_links_for_attachments/comment_4_7612923064284646c2ed59e2cd52845d._comment new file mode 100644 index 000000000..eb6593868 --- /dev/null +++ b/doc/forum/download_links_for_attachments/comment_4_7612923064284646c2ed59e2cd52845d._comment @@ -0,0 +1,34 @@ +[[!comment format=mdwn + username="http://smcv.pseudorandom.co.uk/" + nickname="smcv" + subject="comment 4" + date="2013-10-18T16:56:09Z" + content=""" +> \[[setup.txt]] - opens the plain text in the same browser window + +That's the browser's choice: the web server says \"this is text/plain\" +and the browser decides to display it in the window. IkiWiki doesn't +actually serve the file, just provides a link to it; to force it +to be downloaded rather than opened, you'd have to configure +your web server to offer it as \"Content-Disposition: attachment\" +(e.g. ). + +The only way IkiWiki could get involved in this would be to +have the file download go via the CGI script, which could +add that header. That isn't currently a feature it has; +you could maybe add a plugin if you need this? + +> \[[settings.xml]] - opens the formatted xml as html + +Again, this is between the web server and the browser. + +> \[[.gitignore]] - it does not recognise this file + +IkiWiki excludes files related to the source code control systems +it uses, in order to avoid accidentally publishing a `.gitignore` +that's intended to control ignored files for the git repo +containing the pages' source. This is controlled by the +`wiki_file_prune_regexps`, `exclude` and `include` config options. +You can put `.gitignore` in `include` if you need to publish +files with that name. +"""]] diff --git a/doc/forum/editing_a_comment.mdwn b/doc/forum/editing_a_comment.mdwn new file mode 100644 index 000000000..eb534365e --- /dev/null +++ b/doc/forum/editing_a_comment.mdwn @@ -0,0 +1,11 @@ +Is it possible to edit a comment? I did not find any button for it. + +> It was a design decision to not allow editing comments via the web +> interface. The thinking being that comments on blogs tend to not allow +> editing, and allowing wiki-style editing by anyone would sort of defeat +> the purpose of comments. +> +> I do think there is room to support more forum-style comments in ikiwiki. +> As long as the comment is not posted by an anonymous user, it would be +> possible to open up editing to the original commenter. One day, perhaps.. +> --[[Joey]] diff --git a/doc/forum/editing_the_style_sheet.mdwn b/doc/forum/editing_the_style_sheet.mdwn new file mode 100644 index 000000000..b4aa8c89b --- /dev/null +++ b/doc/forum/editing_the_style_sheet.mdwn @@ -0,0 +1,18 @@ +[[!meta date="2006-12-29 04:19:51 +0000"]] + +It would be nice to be able to edit the stylesheet by means of the cgi. Or is this possible? I wasn't able to achieve it. +Ok, that's my last 2 cents for a while. --[Mazirian](http://mazirian.com) + +> I don't support editing it, but if/when ikiwiki gets [[todo/fileupload]] support, +> it'll be possible to upload a style sheet. (If .css is in the allowed +> extensions list.. no idea how safe that would be, a style sheet is +> probably a great place to put XSS attacks and evil javascript that would +> be filtered out of any regular page in ikiwiki). --[[Joey]] + +>> I hadn't thought of that at all. It's a common feature and one I've +>> relied on safely, because the wikis I am maintaining at the moment +>> are all private and restricted to trusted users. Given that the whole +>> point of ikiwiki is to be able to access and edit via the shell as +>> well as the web, I suppose the features doesn't add a lot. By the +>> way, the w3m mode is brilliant. I haven't tried it yet, but the idea +>> is great. diff --git a/doc/forum/error_302___40__Found__41___when_editing_page.mdwn b/doc/forum/error_302___40__Found__41___when_editing_page.mdwn new file mode 100644 index 000000000..aa2db2f8a --- /dev/null +++ b/doc/forum/error_302___40__Found__41___when_editing_page.mdwn @@ -0,0 +1,59 @@ +I have an [IkiWiki site](http://ocikbapps.uzh.ch/gc3wiki), which works +fine, except for one page which I cannot edit with the CGI. Only this +single page is failing, editing every other works as expected. + +When clicking every button (well, except "Cancel") on the edit form, I +get a "302 Found" page in the browser; the Apache logs show: + + [client XXX] malformed header from script. Bad header=according%20to%20the%20availab: ikiwiki.cgi + +Capturing the output from `ikiwiki.cgi`, I see that just these two +lines are sent: + + Status: 302 Found + Location: https://ocikbapps.uzh.ch/gc3wiki/ikiwiki.auth.cgi?_submitted=1;do=edit;..;_submit=Preview;attachment= + +The total size in bytes of the reply is 16189; I thought this might be +an issue with Apache imposing some limit on the header size; indeed, +`tcpflow` shows that the "302 Found" message is encapsulated into an +HTTP 500 "internal server error" response. + +So I added this to Apache's config (std Debian 6.0): + + # cat /etc/apache2/conf.d/limits.conf + LimitRequestFieldSize 65534 + LimitRequestLine 65534 + +But I'm still getting the same error. + +Any suggestions? + + +**Update 2011-08-16:** +[This bug report](https://bugzilla.mozilla.org/show_bug.cgi?id=513989) +shows the exact same symptoms; the solution they adopted is to not +perform the redirect when the URL length exceeds the default Apache +value of 8190. + +Regarding Apache limits: apparently, Apache (as of version 2.2.17) +only applies the `LimitRequestLine` and `LimitRequestFiledsize` in +client HTTP transactions; when dealing with the HTTP responses +generated by CGI scripts, the code from `server/util_script.c` +applies: (function `ap_scan_script_header_err_core`, lines 403--433) + + char x[MAX_STRING_LEN]; + char *w, *l; + [...] + if (buffer) { + *buffer = '\0'; + } + w = buffer ? buffer : x; + [...] + while (1) { + int rv = (*getsfunc) (w, MAX_STRING_LEN - 1, getsfunc_data); + +where `MAX_STRING_LEN` is defined in `httpd.h` to be equal to +`HUGE_STRING_LEN`, that is, 8192. + +> This has been filed as [[!debbug 638009]], so let's only +> discuss it in one place (ie, there) --[[Joey]] diff --git a/doc/forum/ever-growing_list_of_pages.mdwn b/doc/forum/ever-growing_list_of_pages.mdwn new file mode 100644 index 000000000..9920e34bb --- /dev/null +++ b/doc/forum/ever-growing_list_of_pages.mdwn @@ -0,0 +1,29 @@ +What is overyone's idea about the ever-growing list of pages in bugs/ etc.? +Once linked to `done`, they're removed from the rendered [[bugs]] page -- but +they're still present in the repository. + +Shouldn't there be some clean-up at some point for those that have been +resolved? Or should all of them be kept online forever? + +--[[tschwinge]] + +> To answer a question with a question, what harm does having the done bugs +> around cause? At some point in the future perhaps the number of done pages +> will be large enough to be a time or space concern. Do you think we've +> reached a point now? One advantage of having them around is that people +> running older versions of the Ikiwiki software may find the page explaining +> that the bug is fixed if they perform a search. -- [[Jon]] + +> I like to keep old bugs around. --[[Joey]] + +So, I guess it depends on whether you want to represent the development of the +software (meaning: which bugs are open, which are fixed) *(a)* in a snapshot of +the repository (a checkout; that is, what you see rendered on +), or *(b)* if that information is to be contained in the +backing repository's revision history only. Both approaches are valid. For +people used to using Git for accessing a project's history, *(b)* is what +they're used to, but for those poor souls ;-) that only use a web browser to +access this database, *(a)* is the more useful approach indeed. For me, using +Git, it is a bit of a hindrance, as, when doing a full-text search for a +keyword on a checkout, I'd frequently hit pages that reported a bug, but are +tagged `done` by now. --[[tschwinge]] diff --git a/doc/forum/field__95__tags_not_linking.mdwn b/doc/forum/field__95__tags_not_linking.mdwn new file mode 100644 index 000000000..0b91e58f3 --- /dev/null +++ b/doc/forum/field__95__tags_not_linking.mdwn @@ -0,0 +1,66 @@ +Hey There. + +I'm using the [[plugins/contrib/field]] plugin together with [[plugins/contrib/ftemplate/ikiwiki/directive/ftemplate]] and [[plugins/contrib/ymlfront]]. Everything looks good, but there are no links created as defined in field_tags. I hope it's just a mistake by me and someone can help me. + +All three plugins are activated and ikiwiki's setup file reads + + # field plugin + # simple registration + field_register => [qw{meta}], + + # allow the config to be queried as a field + field_allow_config => 1, + + # flag certain fields as "tags" + field_tags => { + Autor => '/users', + Rubrik => '/rubriken', + Themen => '/themen', + BuchTitel => 'rezensionen/titel', + BuchAutor => '/rezensionen/autoren', + Verlag => 'rezensionen/verlage', + }, + +I use this template to ask the users for the fields: + + --- + Autor: + BuchTitel: + BuchUntertitel: + BuchAutor: + Verlag: + ISBN: + Seiten: + Preis: + Rubrik: Rezensionen + Themen: + - (Anti-)Repression + - Aktion + - ... + --- + [[!ftemplate id="rezi"]] + +And this one tells what to do with them: + + \[[!meta author=""]] + \[[!meta title=": "]] + + + :
+ ****
+ -
+ *rezensiert von *

+ * Verlag:
+ * ISBN:
+ * Seiten:
+ * Preis:

+ Rubrik:
+ Themen: + + , + +
+ + # just for testing if infobox is the problem + +Do I have to register another plugin with field or what is wrong here? diff --git a/doc/forum/field__95__tags_not_linking/comment_10_7c1540e6eb6aafd2e1c9c7016e6e6249._comment b/doc/forum/field__95__tags_not_linking/comment_10_7c1540e6eb6aafd2e1c9c7016e6e6249._comment new file mode 100644 index 000000000..f6bf1eff4 --- /dev/null +++ b/doc/forum/field__95__tags_not_linking/comment_10_7c1540e6eb6aafd2e1c9c7016e6e6249._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="http://kerravonsen.dreamwidth.org/" + ip="60.241.8.244" + subject="comment 10" + date="2011-09-06T02:31:13Z" + content=""" +Hmmm. They are the latest versions. + +So what do you get when you use ``? Is that blank? +"""]] diff --git a/doc/forum/field__95__tags_not_linking/comment_11_0c03cbaa4f748d2fb932fda08fe6e966._comment b/doc/forum/field__95__tags_not_linking/comment_11_0c03cbaa4f748d2fb932fda08fe6e966._comment new file mode 100644 index 000000000..ddbb39197 --- /dev/null +++ b/doc/forum/field__95__tags_not_linking/comment_11_0c03cbaa4f748d2fb932fda08fe6e966._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://xlogon.net/bacuh" + ip="209.234.253.228" + subject="comment 11" + date="2011-09-06T02:41:24Z" + content=""" +No. This gives the expected result. +"""]] diff --git a/doc/forum/field__95__tags_not_linking/comment_12_9f3a402173f9584d8a36bc61e5755f6d._comment b/doc/forum/field__95__tags_not_linking/comment_12_9f3a402173f9584d8a36bc61e5755f6d._comment new file mode 100644 index 000000000..6ec12a52f --- /dev/null +++ b/doc/forum/field__95__tags_not_linking/comment_12_9f3a402173f9584d8a36bc61e5755f6d._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://kerravonsen.dreamwidth.org/" + ip="60.241.8.244" + subject="comment 12" + date="2011-09-06T02:53:39Z" + content=""" +Okay, I'm going to release the latest version from another branch. Give me an hour. +"""]] diff --git a/doc/forum/field__95__tags_not_linking/comment_13_455a2f921059f9ecca810bb8afed0fda._comment b/doc/forum/field__95__tags_not_linking/comment_13_455a2f921059f9ecca810bb8afed0fda._comment new file mode 100644 index 000000000..0d0d78783 --- /dev/null +++ b/doc/forum/field__95__tags_not_linking/comment_13_455a2f921059f9ecca810bb8afed0fda._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="http://xlogon.net/bacuh" + ip="209.234.253.228" + subject="comment 13" + date="2011-09-06T03:07:10Z" + content=""" +There's no rush. But please don't forget to document this -TAGPAGE thing. ;) I can't find any reference to it. Should be mentioned in the manpage. + +Thanks for your help. +"""]] diff --git a/doc/forum/field__95__tags_not_linking/comment_14_b82294c290a215d9aa6774ee20b5a552._comment b/doc/forum/field__95__tags_not_linking/comment_14_b82294c290a215d9aa6774ee20b5a552._comment new file mode 100644 index 000000000..0b29fafea --- /dev/null +++ b/doc/forum/field__95__tags_not_linking/comment_14_b82294c290a215d9aa6774ee20b5a552._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="http://kerravonsen.dreamwidth.org/" + ip="60.241.8.244" + subject="comment 14" + date="2011-09-06T03:42:22Z" + content=""" +Releases done. And, yes, updating the docs was one of the things I did. + +So, if you can try again with the latest version... +"""]] diff --git a/doc/forum/field__95__tags_not_linking/comment_15_57fb279ad50f8460341dc0f217acef06._comment b/doc/forum/field__95__tags_not_linking/comment_15_57fb279ad50f8460341dc0f217acef06._comment new file mode 100644 index 000000000..c7f527efd --- /dev/null +++ b/doc/forum/field__95__tags_not_linking/comment_15_57fb279ad50f8460341dc0f217acef06._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="http://xlogon.net/bacuh" + ip="209.234.253.228" + subject="comment 15" + date="2011-09-06T04:07:12Z" + content=""" +Great. This works. + +Thanks again. +"""]] diff --git a/doc/forum/field__95__tags_not_linking/comment_16_8dae1024e80cf6ea765dee0318324d71._comment b/doc/forum/field__95__tags_not_linking/comment_16_8dae1024e80cf6ea765dee0318324d71._comment new file mode 100644 index 000000000..d8288f2d6 --- /dev/null +++ b/doc/forum/field__95__tags_not_linking/comment_16_8dae1024e80cf6ea765dee0318324d71._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://kerravonsen.dreamwidth.org/" + ip="60.241.8.244" + subject="comment 16" + date="2011-09-06T06:55:43Z" + content=""" +Yay! +"""]] diff --git a/doc/forum/field__95__tags_not_linking/comment_1_76a4fb4def8f13b906c848814de91660._comment b/doc/forum/field__95__tags_not_linking/comment_1_76a4fb4def8f13b906c848814de91660._comment new file mode 100644 index 000000000..23e1ebae1 --- /dev/null +++ b/doc/forum/field__95__tags_not_linking/comment_1_76a4fb4def8f13b906c848814de91660._comment @@ -0,0 +1,12 @@ +[[!comment format=mdwn + username="http://kerravonsen.dreamwidth.org/" + ip="202.173.183.92" + subject="comment 1" + date="2011-09-05T22:23:17Z" + content=""" +The `field_tags` option behaves like \[[!tag ]] rather than \[[!taglink ]] - that is, it flags the page as being linked to the tag page. In order to have an actual link, you have to put a link in the template, and use the \"tagpage\" variable suffix. + +For example: + + *rezensiert von \[[]]* +"""]] diff --git a/doc/forum/field__95__tags_not_linking/comment_2_64d51cc9ba953e7fed609c380e30bb7d._comment b/doc/forum/field__95__tags_not_linking/comment_2_64d51cc9ba953e7fed609c380e30bb7d._comment new file mode 100644 index 000000000..ea9ece867 --- /dev/null +++ b/doc/forum/field__95__tags_not_linking/comment_2_64d51cc9ba953e7fed609c380e30bb7d._comment @@ -0,0 +1,13 @@ +[[!comment format=mdwn + username="http://xlogon.net/bacuh" + ip="209.234.253.228" + subject="comment 2" + date="2011-09-05T23:18:34Z" + content=""" +This doesn't work. Even with a exact copy of your code it just get + + [[]] + +where the \"taglinks\" should be. + +"""]] diff --git a/doc/forum/field__95__tags_not_linking/comment_3_7a6eac4e216133f1cf6fc12336fc2496._comment b/doc/forum/field__95__tags_not_linking/comment_3_7a6eac4e216133f1cf6fc12336fc2496._comment new file mode 100644 index 000000000..57ea22fde --- /dev/null +++ b/doc/forum/field__95__tags_not_linking/comment_3_7a6eac4e216133f1cf6fc12336fc2496._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://xlogon.net/bacuh" + ip="209.234.253.228" + subject="comment 3" + date="2011-09-05T23:46:40Z" + content=""" +BTW: The PageSpecs provided by field are working. +"""]] diff --git a/doc/forum/field__95__tags_not_linking/comment_4_e6941a0df00fb9f45563c30e01efa622._comment b/doc/forum/field__95__tags_not_linking/comment_4_e6941a0df00fb9f45563c30e01efa622._comment new file mode 100644 index 000000000..7bce25c8e --- /dev/null +++ b/doc/forum/field__95__tags_not_linking/comment_4_e6941a0df00fb9f45563c30e01efa622._comment @@ -0,0 +1,9 @@ +[[!comment format=mdwn + username="http://kerravonsen.dreamwidth.org/" + ip="60.241.8.244" + subject="comment 4" + date="2011-09-06T01:31:25Z" + content=""" +Hmmm. +What happens when you just have ``? Is that blank too? +"""]] diff --git a/doc/forum/field__95__tags_not_linking/comment_5_f08ded5a946458aeba59a2c4cec29b2f._comment b/doc/forum/field__95__tags_not_linking/comment_5_f08ded5a946458aeba59a2c4cec29b2f._comment new file mode 100644 index 000000000..cbbb45b6e --- /dev/null +++ b/doc/forum/field__95__tags_not_linking/comment_5_f08ded5a946458aeba59a2c4cec29b2f._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://xlogon.net/bacuh" + ip="209.234.253.228" + subject="comment 5" + date="2011-09-06T01:40:46Z" + content=""" +It makes no difference. Neither with a capitalized nor with an uncapitalized \"-tagpage\". +"""]] diff --git a/doc/forum/field__95__tags_not_linking/comment_6_6ea7de20c3db96589c05adbe97d57cfd._comment b/doc/forum/field__95__tags_not_linking/comment_6_6ea7de20c3db96589c05adbe97d57cfd._comment new file mode 100644 index 000000000..cfd5e7981 --- /dev/null +++ b/doc/forum/field__95__tags_not_linking/comment_6_6ea7de20c3db96589c05adbe97d57cfd._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://kerravonsen.dreamwidth.org/" + ip="60.241.8.244" + subject="comment 6" + date="2011-09-06T01:56:22Z" + content=""" +I meant, if you just have `` without the square brackets `[[` around it, is that blank too? +"""]] diff --git a/doc/forum/field__95__tags_not_linking/comment_7_8ad385b61c46389d87c88b17430ab1f2._comment b/doc/forum/field__95__tags_not_linking/comment_7_8ad385b61c46389d87c88b17430ab1f2._comment new file mode 100644 index 000000000..e077f6e27 --- /dev/null +++ b/doc/forum/field__95__tags_not_linking/comment_7_8ad385b61c46389d87c88b17430ab1f2._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://xlogon.net/bacuh" + ip="209.234.253.228" + subject="comment 7" + date="2011-09-06T02:02:39Z" + content=""" +Sorry for being unclear; I tried exactly that. It's still blank. +"""]] diff --git a/doc/forum/field__95__tags_not_linking/comment_8_c3c5eced158babd8c3acb493a86b6ecb._comment b/doc/forum/field__95__tags_not_linking/comment_8_c3c5eced158babd8c3acb493a86b6ecb._comment new file mode 100644 index 000000000..e7e4d1dba --- /dev/null +++ b/doc/forum/field__95__tags_not_linking/comment_8_c3c5eced158babd8c3acb493a86b6ecb._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://kerravonsen.dreamwidth.org/" + ip="60.241.8.244" + subject="comment 8" + date="2011-09-06T02:13:06Z" + content=""" +Which versions of field and ftemplate are you using? +"""]] diff --git a/doc/forum/field__95__tags_not_linking/comment_9_9bd4b3df18a28a7ab3bbef5013856987._comment b/doc/forum/field__95__tags_not_linking/comment_9_9bd4b3df18a28a7ab3bbef5013856987._comment new file mode 100644 index 000000000..d82c691c8 --- /dev/null +++ b/doc/forum/field__95__tags_not_linking/comment_9_9bd4b3df18a28a7ab3bbef5013856987._comment @@ -0,0 +1,11 @@ +[[!comment format=mdwn + username="http://xlogon.net/bacuh" + ip="209.234.253.228" + subject="comment 9" + date="2011-09-06T02:27:47Z" + content=""" +* field: 1.20110610 +* ftemplate: 1.20100519 + +Both were downloaded two days ago from their git repositorie's master branch. +"""]] diff --git a/doc/forum/field_and_forms.mdwn b/doc/forum/field_and_forms.mdwn new file mode 100644 index 000000000..97fda1856 --- /dev/null +++ b/doc/forum/field_and_forms.mdwn @@ -0,0 +1,13 @@ +Dear ikiwiki users, and specially [[users/KathrynAndersen]] ([[users/rubykat]]): +have you considered some way of extending ikiwiki to allow some kind of +on-the-fly generation of web forms to create new pages? these web forms should +offer as many fields as one has defined in some [[page +template|plugins/contrib/ftemplate]], and, once POSTed, should create a page +using that template, with those fields already filled with the values the user +provided. + +I see this a a generalization of the `postform` option of the +[[ikiwiki/directive/inline]] directive. That option tells ikiwiki to create a +form with one field already filled (title). + +What are your ideas about this? diff --git a/doc/forum/field_and_forms/comment_1_a0e976cb79f03dcff5e9a4511b90d160._comment b/doc/forum/field_and_forms/comment_1_a0e976cb79f03dcff5e9a4511b90d160._comment new file mode 100644 index 000000000..3e10dbbd9 --- /dev/null +++ b/doc/forum/field_and_forms/comment_1_a0e976cb79f03dcff5e9a4511b90d160._comment @@ -0,0 +1,19 @@ +[[!comment format=mdwn + username="http://kerravonsen.dreamwidth.org/" + ip="60.241.8.244" + subject="Limitations" + date="2010-11-23T02:18:52Z" + content=""" +I'd already had a look at this idea before you posted this suggestion, and I ran into difficulties. +So far as I can see, it makes most sense to use the mechanisms already in place for editing pages, and enhance them. +Unfortunately, the whole edit-page setup expects a template file (by default, when editing pages, editpage.tmpl) +and anything apart from \"submit\" buttons must have a placeholder in the template file, or it doesn't get displayed at all in the form. +At least, that's what I've found - I could be mistaken. + +But if it's true, that rather puts the kybosh on dynamically generated forms, so far as I can see. +I mean, if you knew beforehand what all your fields were going to be, you could make a copy of editpage.tmpl, add in your fields where you want, and then make a plugin that uses that template instead of editpage.tmpl, but that's very limited. + +If someone could come up with a way of making dynamic forms, that would solve the problem, but I've come up against a brick wall myself. Joey? Anyone? + +-- [[KathrynAndersen]] +"""]] diff --git a/doc/forum/formating:_how_to_align_text_to_the_right.mdwn b/doc/forum/formating:_how_to_align_text_to_the_right.mdwn new file mode 100644 index 000000000..e01eccb92 --- /dev/null +++ b/doc/forum/formating:_how_to_align_text_to_the_right.mdwn @@ -0,0 +1,52 @@ +As in title, how to align text to the right? + +> Add to your local.css a class that aligns text to the right: + + .alignright { text-align: right; } + +> And then you just just use `` around +> other html. +> +> You can refine that, and allow right-aligning markdowned text +> by using the [[ikiwiki/directive/template]] +> directive, with a template that contains the html. The +> [[templates/note]] template does something similar. --[[Joey]] + +>> Thanks! + +----- +
+[[!format mdwn """ +This is my text with [a markdown link](#). + +Here's a *second* paragraph. +"""]] +
+ +> There is more than one way to do it. If [[plugins/format]] is enabled, then this: +> +>
+> \[[!format mdwn """ +> This is my text with [a markdown link](#). +> +> Here's a *second* paragraph. +> """]] +>
+> +> is rendered like the box in this page. +> +> (I'm using the `notebox` class used by the `note` template here, but you could +> use any class.) --[[smcv]] + +----- +> Doing this myself and noted that [[ikiwiki/markdown]] down does not allow the enclosure of block level elements directly; and thus we cannot switch the `span` suggested above for `div` in changing block level elements (not if you wish to include markdown, anyway). For example, I want to create a paragraph (with markdown text) which is right aligned, and so add the following + +>> +>> This is my text with [a markdown link](/) +>> + +> The *correct* thing to do here is create a template (as indicated above) **but** a workaround I found useful was to over-ride the `inline` nature of the `span` element, as follows + +>> .align_right { display: block ; text-align: right ; } + +> you may also like to remove the padding and margins since they will be provided by the enclosing block. -- fergus diff --git a/doc/forum/getsource_from_gitweb_with_cgi_disabled___44___Is_it_possible__63__.mdwn b/doc/forum/getsource_from_gitweb_with_cgi_disabled___44___Is_it_possible__63__.mdwn new file mode 100644 index 000000000..0219329c8 --- /dev/null +++ b/doc/forum/getsource_from_gitweb_with_cgi_disabled___44___Is_it_possible__63__.mdwn @@ -0,0 +1,6 @@ +Hi, + +I'm thinking about running my wiki with cgi disabled. I already did the gitweb setup. + +Is it possible to use gitweb to give me what getsource gives me. You know, like the History item but with: +http://127.0.0.1/gitweb/gitweb.cgi?p=wiki.git;a=blob_plain;f=\[[file]];hb=HEAD diff --git a/doc/forum/getsource_from_gitweb_with_cgi_disabled___44___Is_it_possible__63__/comment_1_747cc477584028ce2c7bc198070b1221._comment b/doc/forum/getsource_from_gitweb_with_cgi_disabled___44___Is_it_possible__63__/comment_1_747cc477584028ce2c7bc198070b1221._comment new file mode 100644 index 000000000..c506a363c --- /dev/null +++ b/doc/forum/getsource_from_gitweb_with_cgi_disabled___44___Is_it_possible__63__/comment_1_747cc477584028ce2c7bc198070b1221._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawnQs9icnfI79gWOQY_Yxv2XmYI3z703PrQ" + nickname="misc" + subject="Solved - patched source" + date="2011-07-21T15:36:47Z" + content=""" +Ok, I implemented sourceurl and it worked. I didn't want to touch the source code at first but it turned out to be very easy to work with. + +Thank you for your excellent and creative work on ikiwiki. +"""]] diff --git a/doc/forum/getsource_from_gitweb_with_cgi_disabled___44___Is_it_possible__63__/comment_2_a230861b26dba6d61461862bfedbc09c._comment b/doc/forum/getsource_from_gitweb_with_cgi_disabled___44___Is_it_possible__63__/comment_2_a230861b26dba6d61461862bfedbc09c._comment new file mode 100644 index 000000000..1cf1d3282 --- /dev/null +++ b/doc/forum/getsource_from_gitweb_with_cgi_disabled___44___Is_it_possible__63__/comment_2_a230861b26dba6d61461862bfedbc09c._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://smcv.pseudorandom.co.uk/" + nickname="smcv" + subject="comment 2" + date="2011-07-23T11:07:27Z" + content=""" +Could you attach the patch here, please? That sounds like a useful feature to have. +"""]] diff --git a/doc/forum/getsource_from_gitweb_with_cgi_disabled___44___Is_it_possible__63__/comment_3_848b4801fc7887906a21a676e802023c._comment b/doc/forum/getsource_from_gitweb_with_cgi_disabled___44___Is_it_possible__63__/comment_3_848b4801fc7887906a21a676e802023c._comment new file mode 100644 index 000000000..ea28449c7 --- /dev/null +++ b/doc/forum/getsource_from_gitweb_with_cgi_disabled___44___Is_it_possible__63__/comment_3_848b4801fc7887906a21a676e802023c._comment @@ -0,0 +1,10 @@ +[[!comment format=mdwn + username="https://www.google.com/accounts/o8/id?id=AItOawnQs9icnfI79gWOQY_Yxv2XmYI3z703PrQ" + nickname="misc" + subject="patch - getsource from gitweb" + date="2011-07-24T23:50:07Z" + content=""" +> Could you attach the patch here, please? That sounds like a useful feature to have. + + +"""]] diff --git a/doc/forum/google_openid_broken__63__.mdwn b/doc/forum/google_openid_broken__63__.mdwn new file mode 100644 index 000000000..d25d8fe4c --- /dev/null +++ b/doc/forum/google_openid_broken__63__.mdwn @@ -0,0 +1,82 @@ +Now that google supports using thier profiles as OpenIDs, that can be used +directly to sign into ikiwiki. Just use, for example, + . Tested and it works. --[[Joey]] + +> This seems to work fine if you use the profile directly as an OpenID. It doesn't seem to work with delegation. From that I can see, this is a deliberate decision by Google for security reasons. See the response [here](http://groups.google.com/group/google-federated-login-api/browse_thread/thread/825067789537568c/23451a68c8b8b057?show_docid=23451a68c8b8b057). -- [[Will]] + +### adding the GMail OpenID as an admin is unhandy +Adding the non-human-friendly OpenID from Gmail as an admin for ikiwiki (if you haven't set up a profile with a readabe URL) is unhandy; first, you need to discover the URL, for example, by making a web edit with it (like me [here](http://source.ikiwiki.branchable.com/?p=source.git;a=search;s=https://www.google.com/accounts/o8/id%3Fid%3DAItOawl3JW_Ow4xMqj98Ig1vwGx_AnjUSsgwE8E;st=author)), and then copy the URL to ikiwiki.setup. --Ivan Z. + +## historical discussion + +when I login via to this wiki (or ours) via Google's OpenID, I get this error: + +Error: OpenID failure: no_identity_server: The provided URL doesn't declare its OpenID identity server. + +Any idea how to fix this?? + +> Google is [doing things with openid that are not in the spec](http://googledataapis.blogspot.com/2008/10/federated-login-for-google-account.html) +> and it's not clear to me that they intend regular openid to work at all. +> What is your google openid URL so I can take a look at the data they are +> providing? --[[Joey]] + + +http://openid-provider.appspot.com/larrylud + +> I've debugged this some and filed +> on the Openid perl +> module. It's a pretty easy fix, so I hope upstream will fix it quickly. +> --[[Joey]] + +>> A little more information here: I'm using that same openid provider at the moment. Note that +>> that provider isn't google - it is someone using the google API to authenticate. I normally have it +>> set up as a redirect from my home page (which means I can change providers easily). + + + + +>> In that mode it works (I used it to log in to make this edit). However, when I try the openid +>> URL directly, it doesn't work. I think there is something weird with re-direction. I hope this +>> isn't a more general security hole. +>> -- [[Will]] + +---- + +So, while the above bug will probably get fixed sooner or later, +the best approach for those of you needing a google openid now is +to use gmail. + + +Just a note that someone has apparently figured out how to use a google +openid, and not a third-party provider either, to edit this site. +The openid is + +(what a mouthfull!), and I don't know who that is or how to use it since it +points to a fairly useless xml document, rather than a web page. --[[Joey]] + +> That string is what's received via the discovery protocol. The user logging in with a Google account is not supposed to write that when logging in, but rather . The OpenID client library will accept that and redirect the user to a sign in page, which will return that string as the OpenID. It's not really usable as an identifier for edits and whatnots, but an alternative would be to use the attribute exchange extension to get the email address and display that. See . + +> Yahoo's OpenID implementation works alike, but I haven't looked at it as much. It uses to receive the endpoint. + +> I've added buttons that submit the two above URLs for logging in with a Google and Yahoo OpenID, respectively, to my locally changed OpenID login plugin. + +> Using the Google profile page as the OpenID is really orthogonal to the above. --[[kaol]] + +>> First, I don't accept that the openid google returns from their +>> generic signin url *has* to be so freaking ugly. For contrast, +>> look at the openid you log in as if you use the yahoo url. +>> . Nice and clean, now +>> munged by ikiwiki to "joeyhess [me.yahoo.com]". +>> +>> Displaying email addresses is not really an option, because ikiwiki +>> can't leak user email addresses like that. Displaying nicknames or +>> usernames is, see [[todo/Separate_OpenIDs_and_usernames]]. +>> +>> It would probably be good if the openid plugin could be configured with +>> a list of generic openid urls, so it can add quick login buttons using +>> those urls. +>> +>> The ugly google url will still be exposed here and there where +>> a unique user id is needed. That can be avoided by not using the generic +>> , but instead your own profile +>> like . --[[Joey]] diff --git a/doc/forum/how_can_I_use___39____47____39___as_tagbase__63__.mdwn b/doc/forum/how_can_I_use___39____47____39___as_tagbase__63__.mdwn new file mode 100644 index 000000000..8a24152dc --- /dev/null +++ b/doc/forum/how_can_I_use___39____47____39___as_tagbase__63__.mdwn @@ -0,0 +1,13 @@ +I'd like tags to be top-level pages, like /some-tag. + +I achieve this most of the time by *not* defining `tagbase`. + +However, this goes wrong if the name of a tag matches the name of a page further down a tree. + +Example: + + * tag scm, corresponding page /scm + * a page /log/scm tagged 'scm' does not link to /scm + * a page /log/puppet tagged 'scm' links to /log/scm in the Tags: section + +Is this possible, or am I pushing tags too far (again)? -- [[Jon]] diff --git a/doc/forum/how_can_I_use___39____47____39___as_tagbase__63__/comment_1_e7897651ba8d9156526d36d6b7744eae._comment b/doc/forum/how_can_I_use___39____47____39___as_tagbase__63__/comment_1_e7897651ba8d9156526d36d6b7744eae._comment new file mode 100644 index 000000000..361c51b09 --- /dev/null +++ b/doc/forum/how_can_I_use___39____47____39___as_tagbase__63__/comment_1_e7897651ba8d9156526d36d6b7744eae._comment @@ -0,0 +1,8 @@ +[[!comment format=mdwn + username="http://joey.kitenet.net/" + nickname="joey" + subject="comment 1" + date="2010-12-05T20:15:28Z" + content=""" +From the code, it seems to me like setting tagbase to \"/\" would actually do what you want. Does it not work? +"""]] diff --git a/doc/forum/how_could_i_generate_a_flat_textfile_from_metadata_in_multiple_pages.mdwn b/doc/forum/how_could_i_generate_a_flat_textfile_from_metadata_in_multiple_pages.mdwn new file mode 100644 index 000000000..d82a419a3 --- /dev/null +++ b/doc/forum/how_could_i_generate_a_flat_textfile_from_metadata_in_multiple_pages.mdwn @@ -0,0 +1,3 @@ +I am already using the [[plugins/contrib/report]] plugin to generate reports aggregated from multiple pages, and it's great! However, I am now looking at generating non-HTML reports. Basically, I want to generate a BIND zonefile from the data aggregated from similar reports. I have gone as far as using the [[plugins/pagetemplate]] plugin to have an empty page as a template - but even that bit doesn't work as i still get pesky ` +>> --- +>> +>> (It might require a different case combination due to implementation +>> details, I'm not sure.) +>> +>> It's difficult for `field` to do anything about this, because it doesn't +>> know whether a field is meant to be plain text, HTML, a URL, or something +>> else. +>> +>> If `field`'s `pagetemplate` hook did something more limiting - like +>> only emitting template variables starting with `field_`, or from some +>> finite set, or something - then this would cease to be a problem, I think? +>> +>> `ftemplate` and `getfield` don't have this problem, as far as I can see, +>> because their output is in contexts where the user could equally well have +>> written raw HTML directly; the user can cause themselves confusion, but +>> can't cause harmful output. --[[smcv]] + +From a coding style point of view, the `$CamelCase` variable names aren't +IkiWiki style, and the `match_foo` functions look as though they could benefit +from being thin wrappers around a common `&IkiWiki::Plugin::field::match` +function (see `meta` for a similar approach). + +I think the documentation would probably be clearer in a less manpage-like +and more ikiwiki-like style? + +> I don't think ikiwiki *has* a "style" for docs, does it? So I followed the Perl Module style. And I'm rather baffled as to why having the docs laid out in clear sections... make them less clear. --[[KathrynAndersen]] + +>> I keep getting distracted by the big shouty headings :-) +>> I suppose what I was really getting at was that when this plugin +>> is merged, its docs will end up split between its plugin +>> page, [[plugins/write]] and [[ikiwiki/PageSpec]]; on some of the +>> contrib plugins I've added I've tried to separate the docs +>> according to how they'll hopefully be laid out after merge. --s + +If one of my branches from [[todo/allow_plugins_to_add_sorting_methods]] is +accepted, a `field()` cmp type would mean that [[plugins/contrib/report]] can +stop reimplementing sorting. Here's the implementation I'm using, with +your "sortspec" concept (a sort-hook would be very similar): if merged, +I think it should just be part of `field` rather than a separate plugin. + + # Copyright © 2010 Simon McVittie, released under GNU GPL >= 2 + package IkiWiki::Plugin::fieldsort; + use warnings; + use strict; + use IkiWiki 3.00; + use IkiWiki::Plugin::field; + + sub import { + hook(type => "getsetup", id => "fieldsort", call => \&getsetup); + } + + sub getsetup () { + return + plugin => { + safe => 1, + rebuild => undef, + }, + } + + package IkiWiki::SortSpec; + + sub cmp_field { + if (!length $_[0]) { + error("sort=field requires a parameter"); + } + + my $left = IkiWiki::Plugin::field::field_get_value($_[0], $a); + my $right = IkiWiki::Plugin::field::field_get_value($_[0], $b); + + $left = "" unless defined $left; + $right = "" unless defined $right; + return $left cmp $right; + } + + 1; + +---- + +Disclaimer: I've only looked at this plugin and ymlfront, not other related +stuff yet. (I quite like ymlfront, so I looked at this as its dependency. :) +I also don't want to annoy you with a lot of design discussion +if your main goal was to write a plugin that did exactly what you wanted. + +My first question is: Why we need another plugin storing metadata +about the page, when we already have the meta plugin? Much of the +complication around the field plugin has to do with it accessing info +belonging to the meta plugin, and generalizing that to be able to access +info stored by other plugins too. (But I don't see any other plugins that +currently store such info). Then too, it raises points of confusion like +smcv's discuission of field author vs meta author above. --[[Joey]] + +> The point is exactly in the generalization, to provide a uniform interface for accessing structured data, no matter what the source of it, whether that be the meta plugin or some other plugin. + +> There were a few reasons for this: + +>1. In converting my site over from PmWiki, I needed something that was equivalent to PmWiki's Page-Text-Variables (which is how PmWiki implements structured data). +>2. I also wanted an equivalent of PmWiki's Page-Variables, which, rather than being simple variables, are the return-value of a function. This gives one a lot of power, because one can do calculations, derive one thing from another. Heck, just being able to have a "basename" variable is useful. +>3. I noticed that in the discussion about structured data, it was mired down in disagreements about what form the structured data should take; I wanted to overcome that hurdle by decoupling the form from the content. +>4. I actually use this to solve (1), because, while I do use ymlfront, initially my pages were in PmWiki format (I wrote (another) unreleased plugin which parses PmWiki format) including PmWiki's Page-Text-Variables for structured data. So I needed something that could deal with multiple formats. + +> So, yes, it does cater to mostly my personal needs, but I think it is more generally useful, also. +> --[[KathrynAndersen]] + +>> Is it fair to say, then, that `field`'s purpose is to take other +>> plugins' arbitrary per-page data, and present it as a single +>> merged/flattened string => string map per page? From the plugins +>> here, things you then use that merged map for include: +>> +>> * sorting - stolen by [[todo/allow_plugins_to_add_sorting_methods]] +>> * substitution into pages with Perl-like syntax - `getfield` +>> * substitution into wiki-defined templates - the `pagetemplate` +>> hook +>> * substitution into user-defined templates - `ftemplate` +>> +>> As I mentioned above, the flattening can cause collisions (and in the +>> `pagetemplate` case, even security problems). +>> +>> I wonder whether conflating Page Text Variables with Page Variables +>> causes `field` to be more general than it needs to be? +>> To define a Page Variable (function-like field), you need to write +>> a plugin containing that Perl function; if we assume that `field` +>> or something resembling it gets merged into ikiwiki, then it's +>> reasonable to expect third-party plugins to integrate with whatever +>> scaffolding there is for these (either in an enabled-by-default +>> plugin that most people are expected to leave enabled, like `meta` +>> now, or in the core), and it doesn't seem onerous to expect each +>> plugin that wants to participate in this mechanism to have code to +>> do so. While it's still contrib, `field` could just have a special case +>> for the meta plugin, rather than the converse? +>> +>> If Page Text Variables are limited to being simple strings as you +>> suggest over in [[forum/an_alternative_approach_to_structured_data]], +>> then they're functionally similar to `meta` fields, so one way to +>> get their functionality would be to extend `meta` so that +>> +>> \[[!meta badger="mushroom"]] +>> +>> (for an unrecognised keyword `badger`) would store +>> `$pagestate{$page}{meta}{badger} = "mushroom"`? Getting this to +>> appear in templates might be problematic, because a naive +>> `pagetemplate` hook would have the same problem that `field` combined +>> with `ymlfront` currently does. +>> +>> One disadvantage that would appear if the function-like and +>> meta-like fields weren't in the same namespace would be that it +>> wouldn't be possible to switch a field from being meta-like to being +>> function-like without changing any wiki content that referenced it. +>> +>> Perhaps meta-like fields should just *be* `meta` (with the above +>> enhancement), as a trivial case of function-like fields? That would +>> turn `ymlfront` into an alternative syntax for `meta`, I think? +>> That, in turn, would hopefully solve the special-fields problem, +>> by just delegating it to meta. I've been glad of the ability to define +>> new ad-hoc fields with this plugin without having to write an extra plugin +>> to do so (listing books with a `bookauthor` and sorting them by +>> `"field(bookauthor) title"`), but that'd be just as easy if `meta` +>> accepted ad-hoc fields? +>> +>> --[[smcv]] + +>>> Your point above about cross-site scripting is a valid one, and something I +>>> hadn't thought of (oops). + +>>> I still want to be able to populate pagetemplate templates with field, because I +>>> use it for a number of things, such as setting which CSS files to use for a +>>> given page, and, as I said, for titles. But apart from the titles, I +>>> realize I've been setting them in places other than the page data itself. +>>> (Another unreleased plugin, `concon`, uses Config::Context to be able to +>>> set variables on a per-site, per-directory and a per-page basis). + +>>> The first possible solution is what you suggested above: for field to only +>>> set values in pagetemplate which are prefixed with *field_*. I don't think +>>> this is quite satisfactory, since that would still mean that people could +>>> put un-scrubbed values into a pagetemplate, albeit they would be values +>>> named field_foo, etc. --[[KathrynAndersen]] + +>>>> They can already do similar; `PERMALINK` is pre-sanitized to +>>>> ensure that it's a "safe" URL, but if an extremely confused wiki admin was +>>>> to put `COPYRIGHT` in their RSS/Atom feed's ``, a malicious user +>>>> could put an unsafe (e.g. Javascript) URL in there (`COPYRIGHT` *is* +>>>> HTML-scrubbed, but "javascript:alert('pwned!')" is just text as far as a +>>>> HTML sanitizer is concerned, so it passes straight through). The solution +>>>> is to not use variables in situations where that variable would be +>>>> inappropriate. Because `field` is so generic, the definition of what's +>>>> appropriate is difficult. --[[smcv]] + +>>> An alternative solution would be to classify field registration as "secure" +>>> and "insecure". Sources such as ymlfront would be insecure, sources such +>>> as concon (or the $config hash) would be secure, since they can't be edited +>>> as pages. Then, when doing pagetemplate substitution (but not ftemplate +>>> substitution) the insecure sources could be HTML-escaped. +>>> --[[KathrynAndersen]] + +>>>> Whether you trust the supplier of data seems orthogonal to whether its value +>>>> is (meant to be) interpreted as plain text, HTML, a URL or what? +>>>> +>>>> Even in cases where you trust the supplier, you need to escape things +>>>> suitably for the context, not for security but for correctness. The +>>>> definition of the value, and the context it's being used in, changes the +>>>> processing you need to do. An incomplete list: +>>>> +>>>> * HTML used as HTML needs to be html-scrubbed if and only if untrusted +>>>> * URLs used as URLs need to be put through `safeurl()` if and only if +>>>> untrusted +>>>> * HTML used as plain text needs tags removed regardless +>>>> * URLs used as plain text are safe +>>>> * URLs or plain text used in HTML need HTML-escaping (and URLs also need +>>>> `safeurl()` if untrusted) +>>>> * HTML or plain text used in URLs need URL-escaping (and the resulting +>>>> URL might need sanitizing too?) +>>>> +>>>> I can't immediately think of other data types we'd be interested in beyond +>>>> text, HTML and URL, but I'm sure there are plenty. + +>>>>> But isn't this a problem with anything that uses pagetemplates? Or is +>>>>> the point that, with plugins other than `field`, they all know, +>>>>> beforehand, the names of all the fields that they are dealing with, and +>>>>> thus the writer of the plugin knows which treatment each particular field +>>>>> needs? For example, that `meta` knows that `title` needs to be +>>>>> HTML-escaped, and that `baseurl` doesn't. In that case, yes, I see the problem. +>>>>> It's a tricky one. It isn't as if there's only ever going to be a fixed set of fields that need different treatment, either. Because the site admin is free to add whatever fields they like to the page template (if they aren't using the default one, that is. I'm not using the default one myself). +>>>>> Mind you, for trusted sources, since the person writing the page template and the person providing the variable are the same, they themselves would know whether the value will be treated as HTML, plain text, or a URL, and thus could do the needed escaping themselves when writing down the value. + +>>>>> Looking at the content of the default `page.tmpl` let's see what variables fall into which categories: + +>>>>> * **Used as URL:** BASEURL, EDITURL, PARENTLINKS->URL, RECENTCHANGESURL, HISTORYURL, GETSOURCEURL, PREFSURL, OTHERLANGUAGES->URL, ADDCOMMENTURL, BACKLINKS->URL, MORE_BACKLINKS->URL +>>>>> * **Used as part of a URL:** FAVICON, LOCAL_CSS +>>>>> * **Needs to be HTML-escaped:** TITLE +>>>>> * **Used as-is (as HTML):** FEEDLINKS, RELVCS, META, PERCENTTRANSLATED, SEARCHFORM, COMMENTSLINK, DISCUSSIONLINK, OTHERLANGUAGES->PERCENT, SIDEBAR, CONTENT, COMMENTS, TAGS->LINK, COPYRIGHT, LICENSE, MTIME, EXTRAFOOTER + +>>>>> This looks as if only TITLE needs HTML-escaping all the time, and that the URLS all end with "URL" in their name. Unfortunately the FAVICON and LOCAL_CSS which are part of URLS don't have "URL" in their name, though that's fair enough, since they aren't full URLs. + +>>>>> --K.A. + +>>>> One reasonable option would be to declare that `field` takes text-valued +>>>> fields, in which case either consumers need to escape +>>>> it with ``, and not interpret it as a URL +>>>> without first checking `safeurl`), or the pagetemplate hook needs to +>>>> pre-escape. + +>>>>> Since HTML::Template does have the ability to do ESCAPE=HTML/URL/JS, why not take advantage of that? Some things, like TITLE, probably should have ESCAPE=HTML all the time; that would solve the "to escape or not to escape" problem that `meta` has with titles. After all, when one *sorts* by title, one doesn't really want HTML-escaping in it; only when one uses it in a template. -- K.A. + +>>>> Another reasonable option would be to declare that `field` takes raw HTML, +>>>> in which case consumers need to only use it in contexts that will be +>>>> HTML-scrubbed (but it becomes unsuitable for using as text - problematic +>>>> for text-based things like sorting or URLs, and not ideal for searching). +>>>> +>>>> You could even let each consumer choose how it's going to use the field, +>>>> by having the `foo` field generate `TEXT_FOO` and `HTML_FOO` variables? +>>>> --[[smcv]] + +>>>>> Something similar is already done in `template` and `ftemplate` with the `raw_` prefix, which determines whether the variable should have `htmlize` run over it first before the value is applied to the template. Of course, that isn't scrubbing or escaping, because with those templates, the scrubbing is done afterwards as part of the normal processing. + +>>> Another problem, as you point out, is special-case fields, such as a number of +>>> those defined by `meta`, which have side-effects associated with them, more +>>> than just providing a value to pagetemplate. Perhaps `meta` should deal with +>>> the side-effects, but use `field` as an interface to get the values of those special fields. + +>>> --[[KathrynAndersen]] + +----- + +I think the main point is: what is (or should be) the main point of the +field plugin? If it's essentially a way to present a consistent +interface to access page-related structured information, then it makes +sense to have it very general. Plugins registering with fields would +then present ways for recovering the structure information from the page +(`ymlfront`, `meta`, etc), ways to manipulate it (like `meta` does), +etc. + +In this sense, security should be entirely up to the plugins, although +the fields plugin could provide some auxiliary infrastructure (like +determining where the data comes from and raise or lower the security +level accoringly). + +Namespacing is important, and it should be considered at the field +plugin interface level. A plugin should be able to register as +responsible for the processing of all data belonging to a given +namespace, but plugins should be able to set data in any namespace. So +for example, `meta` register are `meta` fields processing, and whatever +method is used to set the data (`meta` directive, `ymlfront`, etc) it +gets a say on what to do with data in its namespace. + +What I'm thinking of is something you could call fieldsets. The nice +thing about them is that, aside from the ones defined by plugins (like +`meta`), it would be possible to define custom ones (with a generic, +default processor) in an appropriate file (like smileys and shortcuts) +with a syntax like: + + [[!fieldset book namespace=book + fields="author title isbn" + fieldtype="text text text"]] + +after which, you coude use + + [[!book author="A. U. Thor" + title="Fields of Iki"]] + +and the data would be available under the book namespace, and thus +as BOOK_AUTHOR, BOOK_TITLE etc in templates. + +Security, in this sense, would be up to the plugin responsible for the +namespace processing (the default handler would HTML-escape text fields +scrub, html fields, safeurl()ify url fields, etc.) + +> So, are you saying that getting a field value is sort of a two-stage process? Get the value from anywhere, and then call the "security processor" for that namespace to "secure" the value? I think "namespaces" are really orthogonal to this issue. What the issue seems to be is: + + * what form do we expect the raw field to be in? (text, URL, HTML) + * what form do we expect the "secured" output to be in? (raw HTML, scrubbed HTML, escaped HTML, URL) + +> Only if we know both these things will we know what sort of security processing needs to be done. + +>> Fieldsets are orthogonal to the security issue in the sense that you can use +>> them without worrying about the field security issue, but they happen to be +>> a rather clean way of answering those two questions, by allowing you to +>> attach preprocessing attributes to a field in a way that the user +>> (supposedly) cannot mingle with. + +> There is also a difference between field values that are used inside pagetemplate, and field values which are used as part of a page's content (e.g. with ftemplate). If you have a TITLE, you want it to be HTML-escaped if you're using it inside pagetemplate, but you don't want it to be HTML-escaped if you're using it inside a page's content. On the other hand, if you have, say, FEEDLINKS used inside pagetemplate, you don't wish it to be HTML-escaped at all, or your page content will be completely stuffed. + +>> Not to talk about the many different ways date-like fields might be need +>> processing. It has already been proposed to solve this problem by exposing +>> the field values under different names depending on the kind or amout of +>> postprocessing they had (e.g. RAW_SOMEFIELD, SOMEFIELD, to which we could add +>> HTML_SOMEFIELD, URL_SOMEFIELD or whatever). Again, fieldsets offer a simple way +>> of letting Ikiwiki know what kind of postprocessing should be offered for +>> that particular field. + +> So, somehow, we have to know the meaning of a field before we can use it properly, which kind of goes against the idea of having something generic. + +>> We could have a default field type (text, for example), and a way to set a +>> different field type (which is what my fieldset proposal was about). + +> --[[KathrynAndersen]] + +----- + +I was just looking at HTML5 and wondered if the field plugin should generate the new Microdata tags (as well as the internal structures)? -- [[Will]] + +> This could just as easily be done as a separate plugin. Feel free to do so. --[[KathrynAndersen]] diff --git a/doc/plugins/contrib/flattr.mdwn b/doc/plugins/contrib/flattr.mdwn new file mode 100644 index 000000000..e9b4bf857 --- /dev/null +++ b/doc/plugins/contrib/flattr.mdwn @@ -0,0 +1,48 @@ +[[!template id=plugin name=flattr author="[[jaywalk]]"]] + +[flattr.com](http://flattr.com/) is a flatrate micropayment service, which revolves around the idea of having flattr buttons everywhere that people visiting your site can use to "flattr" you. + +This plugin makes it easier to put flattr buttons in ikiwiki. It supports both the static kind as well as the counting dynamic javascript version. The dynamic version does not work if [[htmlscrubber|/plugins/htmlscrubber]] is active on the page. + +The dynamic button does not require creation of the page on flattr before being added to a page, the static one does. + +I wrote some notes on [jonatan.walck.se](http://jonatan.walck.se/software/ikiwiki/plugin/flattr/) and put the source here: [flattr.pm](http://jonatan.walck.se/software/ikiwiki/flattr.pm) + +This plugin is licensed under [CC0](http://creativecommons.org/publicdomain/zero/1.0/) (public domain). + +Note that there is now a [[plugins/flattr]] plugin bundled with ikiwiki. It +is less configurable, not supporting static buttons, but simpler to use. + +# Usage # + + # [[!flattr args]] where args are in the form of arg=value. + # Possible args: + # type - static or dynamic. Defaults to static. + + # vars in static mode: + # -------------------- + # Required: + # url - URL to flattr page, + # e.g. http://flattr.com/thing/1994/jaywalks-weblog + # Optional: + # style - Set to compact for compact button. + + # vars in dynamic mode: + # --------------------- + # Required: + # None. + # Optional: + # uid - Set the default in the plugin, override if needed. + # title - The title defaults to $wikiname/some/path (like on the top of + # the wiki). + # desc - A description of the content. Defaults to " ". + # cat - Category, this can be text, images, video, audio, software or + # rest. Defaults to text. + # lang - Language, list of available choises is on + # https://flattr.com/support/integrate/languages. Defaults to en_GB. + # tag - A list of comma separated tags. Empty per default. + # url - URL to thing to flattred, + # e.g. http://jonatan.walck.se/weblog + # style - Set it to compact to get the small button, big for any other + # value including empty. + diff --git a/doc/plugins/contrib/flattr/discussion.mdwn b/doc/plugins/contrib/flattr/discussion.mdwn new file mode 100644 index 000000000..586139e9c --- /dev/null +++ b/doc/plugins/contrib/flattr/discussion.mdwn @@ -0,0 +1,9 @@ +FWIW, it is possible for a plugin like this to add javascript to pages that +are protected by htmlscrubber. Just return a token in your preprocess hook, +and then have a format hook that replaces the token with the javascript. +--[[Joey]] + +> Thanks, That's good to know. I'll try to continue the development of this +> plugin later, for now I just needed it to work. :) It will most likely +> evolve as my page does too. +> --[[jaywalk]] diff --git a/doc/plugins/contrib/ftemplate.mdwn b/doc/plugins/contrib/ftemplate.mdwn new file mode 100644 index 000000000..d82867f94 --- /dev/null +++ b/doc/plugins/contrib/ftemplate.mdwn @@ -0,0 +1,25 @@ +[[!template id=plugin name=ftemplate author="[[rubykat]]"]] +[[!tag type/meta type/format]] + +This plugin provides the [[ikiwiki/directive/ftemplate]] directive. + +This is like the [[ikiwiki/directive/template]] directive, with the addition +that one does not have to provide all the values in the call to the template, +because ftemplate can query structured data ("fields") using the [[field]] +plugin. + +## Activate the plugin + + add_plugins => [qw{goodstuff ftemplate ....}], + +## PREREQUISITES + + IkiWiki + IkiWiki::Plugin::field + HTML::Template + Encode + +## DOWNLOAD + +* browse at GitHub: +* git repo at git://github.com/rubykat/ikiplugins.git diff --git a/doc/plugins/contrib/ftemplate/discussion.mdwn b/doc/plugins/contrib/ftemplate/discussion.mdwn new file mode 100644 index 000000000..1e0bca5d8 --- /dev/null +++ b/doc/plugins/contrib/ftemplate/discussion.mdwn @@ -0,0 +1,33 @@ +I initially thought this wasn't actually necessary - the combination +of [[plugins/template]] with [[plugins/contrib/field]]'s `pagetemplate` +hook ought to provide the same functionality. However, `template` +doesn't run `pagetemplate` hooks; a more general version of this +plugin would be to have a variant of `template` that runs `pagetemplate` +hooks (probably easiest to just patch `template` to implement a +second directive, or have a special parameter `run_hooks="yes"`, +or something). + +> I got the impression that `pagetemplate` hooks are intended to be completely independent of `template` variables; page-template is for the actual `page.tmpl` template, while `template` is for other templates which are used inside the page content. So I don't understand why one would need a run_hooks option. --[[KathrynAndersen]] + +>> `Render`, `inline`, `comments` and `recentchanges` run `pagetemplate` +>> hooks, as does anything that uses `IkiWiki::misctemplate`. From that +>> quick survey, it seems as though `template` is the only thing that +>> uses `HTML::Template` but *doesn't* run `pagetemplate` hooks? +>> +>> It just seems strange to me that `field` needs to have its own +>> variant of `template` (this), its own variant of `inline` (`report`), +>> and so on - I'd tend to lean more towards having `field` +>> enhance the existing plugins. I'm not an ikiwiki committer, +>> mind... Joey, your opinion would be appreciated! --[[smcv]] + +>>> I did it that way basically because I needed the functionality ASAP, and I didn't want to step on anyone's toes, so I made them as separate plugins. If Joey wants to integrate the functionality into IkiWiki proper, I would be very happy, but I don't want to put pressure on him. --[[KathrynAndersen]] + +Another missing thing is that `ftemplate` looks in +the "system" templates directories, not just in the wiki, but that +seems orthogonal (and might be a good enhancement to `template` anyway). +--[[smcv]] + +> Yes, I added that because I wanted the option of not having to make all my templates work as wiki pages also. --[[KathrynAndersen]] + +>> Joey has added support for +>> [[todo/user-defined_templates_outside_the_wiki]] now. --s diff --git a/doc/plugins/contrib/ftemplate/ikiwiki/directive/ftemplate.mdwn b/doc/plugins/contrib/ftemplate/ikiwiki/directive/ftemplate.mdwn new file mode 100644 index 000000000..3009fc830 --- /dev/null +++ b/doc/plugins/contrib/ftemplate/ikiwiki/directive/ftemplate.mdwn @@ -0,0 +1,106 @@ +The `ftemplate` directive is supplied by the [[!iki plugins/contrib/ftemplate desc=ftemplate]] plugin. + +This is like the [[ikiwiki/directive/template]] directive, with the addition +that one does not have to provide all the values in the call to the template, +because ftemplate can query structured data ("fields") using the +[[plugins/contrib/field]] plugin. + +Templates are files that can be filled out and inserted into pages in +the wiki, by using the ftemplate directive. The directive has an id +parameter that identifies the template to use. + +Additional parameters can be used to fill out the template, in +addition to the "field" values. Passed-in values override the +"field" values. + +There are two places where template files can live. One is in the /templates +directory on the wiki. These templates are wiki pages, and can be edited from +the web like other wiki pages. + +The second place where template files can live is in the global +templates directory (the same place where the page.tmpl template lives). +This is a useful place to put template files if you want to prevent +them being edited from the web, and you don't want to have to make +them work as wiki pages. + +### EXAMPLES + +#### Example 1 + +PageA: + + \[[!meta title="I Am Page A"]] + \[[!meta description="A is for Apple."]] + \[[!meta author="Fred Nurk"]] + \[[!ftemplate id="mytemplate"]] + +Template "mytemplate": + + # + by + + **Summary:** + +This will give: + +

I Am Page A

+

by Fred Nurk

+

Summary: A is for Apple. + +#### Example 2: Overriding values + +PageB: + + \[[!meta title="I Am Page B"]] + \[[!meta description="B is for Banana."]] + \[[!meta author="Fred Nurk"]] + \[[!ftemplate id="mytemplate" title="Bananananananas"]] + +This will give: + +

Bananananananas

+

by Fred Nurk

+

Summary: B is for Banana. + +#### Example 3: Loops + +(this example uses the [[plugins/contrib/ymlfront]] plugin) + +Page C: + + --- + BookAuthor: Georgette Heyer + BookTitle: Black Sheep + BookGenre: + - Historical + - Romance + --- + \[[ftemplate id="footemplate"]] + + I like this book. + +Template "footemplate": + + # + by + + ( + + , + + ) + +This will give: + +

Black Sheep

+

by Georgette Heyer

+ +

(Historical, Romance)

+ +

I like this book.

+ +### LIMITATIONS + +One cannot query the values of fields on pages other than the current +page. If you want to do that, check out the [[plugins/contrib/report]] +plugin. diff --git a/doc/plugins/contrib/gallery.mdwn b/doc/plugins/contrib/gallery.mdwn new file mode 100644 index 000000000..72df13bd0 --- /dev/null +++ b/doc/plugins/contrib/gallery.mdwn @@ -0,0 +1,39 @@ +[[!template id=plugin name=gallery author="[[arpitjain]]"]] + +This plugin would create a nice looking gallery of the images. It has been build over the img plugin in Ikiwiki + +GIT repo of the plugin is located at + + +USAGE : +\[[!gallery imagedir="images" option="value"]] + +Available options :
+ * imagedir(required) => Directory containing images. It will scan all the files with jpg|png|gif extension from the directory and will put it in the gallery.
+ * thumbnailsize(optional,Default=200x200) => Size of the thumbnail that you want to generate for the gallery.
+ * resize(optional, Default=>800x600) => Width and Height to resize image to. resize="0" for turning resizing off.
+ * alt(optional) => If image can not be displayed, it will display the text contained in alt argument.
+ * cols(optional,Default=3) => Number of columns of thumbnails that you want to generate.
+ * rows(optional, Default=>3) => Number of Rows on a gallery page.
+ * title(optional) => Title of the gallery.
+ * sort(optional) => "asc" or "desc" . You can sort in ascending or descending order of names of images.
+ * vcs(optional,Default=1) => This value decides whether to put the images out of IkiWiki's tree. If you set vcs=0, then you can specify a directory outside IkiWiki tree also to lookup. In that case you can also give absolute link of the image directory.
+ * exif(optional, Default=>0) => Specify whether to Display exif information or not.
+ +Additionaly, you can put Comment file filename.comm in image directory where filename is name of the image. Comments would then be displayed in the gallery. + +Features of the Gallery Plugin:
+* You can go the next image by clicking on the right side of the image or by pressing 'n'.
+* Similary, you can go the previous image by clicking on the left side of the image or by pressing 'p'.
+* Press esc to close the gallery.
+* While on image, nearby images are preloaded in the background, so as to make the browsing fast.
+ +It uses templated named [Lightbox](http://www.hudddletogether.com). +For any feedback or query, feel free to mail me at arpitjain11 [AT] gmail.com + +Additional details are available [here](http://myweb.unomaha.edu/~ajain/ikiwikigallery.html). +> That link is broken. --[[JosephTurian]] + +-- [[arpitjain]] + +[[!tag plugins]] [[!tag patch]] [[!tag soc]] [[!tag wishlist]] diff --git a/doc/plugins/contrib/gallery/discussion.mdwn b/doc/plugins/contrib/gallery/discussion.mdwn new file mode 100644 index 000000000..08fc2456f --- /dev/null +++ b/doc/plugins/contrib/gallery/discussion.mdwn @@ -0,0 +1,45 @@ +# Adaptation to Newer Versions of ikiwiki + +I tried using this plugin, but to no success so far. I used *gallery* git branch, +rebased it onto the *origin/master*, built a Debian package and installed that one. + +However, I can't even get simply things like this to work: + + $ cat web/index.mdwn + [[!gallery imagedir="b" vcs="0"]] + $ ls web/b/ + 1.jpg 2.jpg 3.jpg 4.jpg + $ ikiwiki [...] --plugin gallery web web.rendered + [...] + $ grep gallery web.rendered/index.html +

[[!gallery Failed to Read Directory b.]]

+ +When using `vcs="1"` it's no better: + + $ ikiwiki [...] --plugin gallery web web.rendered + scanning index.mdwn + internal error: b/800x600-1.jpg cannot be found in web or underlay + +--[[tschwinge]] + +Its probably because of the restriction of permissions by plugins in newer version of IkiWiki. +For the time being, you can turn resizing off till I look into conditional underlay directory feature. + +USAGE : [[!gallery imagedir="directory" resize="0"]] + +New version updated at SVN REPO : http://ned.snow-crash.org:8080/svn/ikiwiki-gallery/ + +--[[arpitjain]] + + +# Bug With Referring to *js* and *css* Files + +In the generated files `gallery/index/index.html` and `gallery/index/*/gallery_*` +it should not be referred to `/js` but to `../../js` and `../../../js`, respectively. +Likewise for `/css`. + + +# All Thumbnails on One Page + +Could `rows="0"` be used to state that all thumbnails should be put on the same page, +no matter how much there are? diff --git a/doc/plugins/contrib/getfield.mdwn b/doc/plugins/contrib/getfield.mdwn new file mode 100644 index 000000000..61e80c58a --- /dev/null +++ b/doc/plugins/contrib/getfield.mdwn @@ -0,0 +1,137 @@ +[[!template id=plugin name=getfield author="[[rubykat]]"]] +[[!tag type/meta type/format]] +[[!toc]] +## NAME + +IkiWiki::Plugin::getfield - query the values of fields + +## SYNOPSIS + + # activate the plugin + add_plugins => [qw{goodstuff getfield ....}], + +## DESCRIPTION + +This plugin provides a way of querying the meta-data (data fields) of a page +inside the page content (rather than inside a template) This provides a way to +use per-page structured data, where each page is treated like a record, and the +structured data are fields in that record. This can include the meta-data for +that page, such as the page title. + +This plugin is meant to be used in conjunction with the [[field]] plugin. + +### USAGE + +One can get the value of a field by using special markup in the page. +This does not use directive markup, in order to make it easier to +use the markup inside other directives. There are four forms: + +* \{{$*fieldname*}} + + This queries the value of *fieldname* for the source page. + + For example: + + \[[!meta title="My Long and Complicated Title With Potential For Spelling Mistakes"]] + # {{$title}} + + When the page is processed, this will give you: + +

My Long and Complicated Title With Potential For Spelling Mistakes

+ +* \{{$*pagename*#*fieldname*}} + + This queries the value of *fieldname* for the page *pagename*. + + For example: + + On PageFoo: + + \[[!meta title="I Am Page Foo"]] + + Stuff about Foo. + + On PageBar: + + For more info, see \[[\{{$PageFoo#title}}|PageFoo]]. + + When PageBar is displayed: + + <p>For more info, see <a href="PageFoo">I Am Page Foo</a>.</p> + +* \{{+$*fieldname*+}} + + This queries the value of *fieldname* for the destination page; that is, + the value when this page is included inside another page. + + For example: + + On PageA: + + \[[!meta title="I Am Page A"]] + # {{+$title+}} + + Stuff about A. + + On PageB: + + \[[!meta title="I Am Page B"]] + \[[!inline pagespec="PageA"]] + + When PageA is displayed: + +

I Am Page A

+

Stuff about A.

+ + When PageB is displayed: + +

I Am Page B

+

Stuff about A.

+ +* \{{+$*pagename*#*fieldname*+}} + + This queries the value of *fieldname* for the page *pagename*; the + only difference between this and \{{$*pagename*#*fieldname*}} is + that the full name of *pagename* is calculated relative to the + destination page rather than the source page. + + I can't really think of a reason why this should be needed, but + this format has been added for completeness. + +### Escaping + +Getfield markup can be escaped by putting a backwards slash `\` +in front of the markup. +If that is done, then the markup is displayed as-is. + +### No Value Found + +If no value is found for the given field, then the field name is returned. + +For example: + +On PageFoo: + + \[[!meta title="Foo"]] + My title is {{$title}}. + + My description is {{$description}}. + +When PageFoo is displayed: + +

My title is Foo.

+ +

My description is description.

+ +This is because "description" hasn't been defined for that page. + +### More Examples + +Listing all the sub-pages of the current page: + + \[[!map pages="{{$page}}/*"]] + +## DOWNLOAD + +* browse at GitHub: +* git repo at git://github.com/rubykat/ikiplugins.git diff --git a/doc/plugins/contrib/getfield/discussion.mdwn b/doc/plugins/contrib/getfield/discussion.mdwn new file mode 100644 index 000000000..13ea8b1b3 --- /dev/null +++ b/doc/plugins/contrib/getfield/discussion.mdwn @@ -0,0 +1,79 @@ +## Multiple values arrays + +This breaks if there are multiple values for a single key. It works fine in the report plugin, but inline display shows the ARRAY reference, e.g. + + IPv6: + - fd64:2c08:9fa7:4::1 + - 2001:470:1d:4a6::1 + +and: + + {{$IPv6}} + +yields: + + ARRAY(0x266db10) + +Seems to me this could be checked and `join(" ")`'d. :) -- [[anarcat]] + +> I wrote a stupid fix for this, which works for getfield, but isn't as good for report. It simply does that `join()`. Here's the patch: +> +> [[!format diff """ +--- a/IkiWiki/Plugin/field.pm ++++ b/IkiWiki/Plugin/field.pm +@@ -322,6 +322,9 @@ sub field_get_value ($$;@) { + { + $basevalue = calculated_values($lc_field_name, $page); + } ++ if (ref($basevalue) eq "ARRAY") { ++ $basevalue = join(" ", @{$basevalue}); # hack ++ } + if (defined $basevalue) + { + $Cache{$page}{$basename} = $basevalue; +@@ -360,6 +363,9 @@ sub field_get_value ($$;@) { + { + $value = $basevalue; + } ++ if (ref($value) eq "ARRAY") { ++ $value = join(" ", @{$value}); # hack ++ } + if (defined $value) + { + $Cache{$page}{$lc_field_name} = $value; +"""]] +> +> Seems to me this should be the default, at the very least in getfield. But at least, with the above patch we don't see expanded Perl ref's. ;) --[[anarcat]] + +## Templating, and other uses + +Like you mentioned in [[ftemplate]] IIRC, it'll only work on the same page. If it can be made to work anywhere, or from a specific place in the wiki - configurable, possibly - you'll have something very similar to mediawiki's templates. I can already think of a few uses for this combined with [[template]] ;) . --[[SR|users/simonraven]] + +> Yes, I mentioned "only current page" in the "LIMITATIONS" section. + +> What do you think would be a good syntax for querying other pages? +> It needs to resolve to a single page, though I guess using "bestlink" to find the closest page would mean that one didn't have to spell out the whole page. + +>> I don't know the internals very well, I think that's how other plugins do it. *goes to check* Usually it's a `foreach` loop, and use a `pagestate{foo}` to check the page's status/state. There's also some stuff like 'pagespec_match_list($params{page}` ... they do slightly different thing depending on need. --[[SR|users/simonraven]] + +>>> No, I meant what markup I should use; the actual implementation probably wouldn't be too difficult. + +>>> The current markup is {{$*fieldname*}}; what you're wanting, perhaps it should be represented like {{$*pagename*:*fieldname*}}, or {{$*pagename*::*fieldname*}} or something else... +>>> -- [[KathrynAndersen]] + +>>>> Oh. Hmm. I like your idea actually, or alternately, in keeping more with other plugins, doing it like {{pagename/fieldname}}. The meaning of the separator is less clear with /, but avoids potential issues with filename clashes that have a colon in them. It also keeps a certain logic - at least to me. Either way, I think both are good choices. [[SR|users/simonraven]] + +>>>>> What about using {{pagename#fieldname}}? The meaning of the hash in URLs sort of fits with what is needed here (reference to a 'named' thing within the page) and it won't conflict with actual hash usages (unless we expect different named parts of pages to define different values for the same field ...) +>>>>> -- [[Oblomov]] +>>>>>> That's a good one too. --[[simonraven]] +>>>>>>> Done! I used {{$*pagename*#*fieldname*}} for the format. -- [[users/KathrynAndersen]] + + +> I'm also working on a "report" plugin, which will basically apply a template like [[ftemplate]] does, but to a list of pages given from a pagespec, rather than the current page. + +> -- [[users/KathrynAndersen]] + +>> Ooh, sounds nice :) . --[[SR|users/simonraven]] + +>>> I've now released the [[plugins/contrib/report]] plugin. I've been using it on my site; the holdup on releasing was because I hadn't yet written the docs for it. I hope you find it useful. +>>> -- [[users/KathrynAndersen]] diff --git a/doc/plugins/contrib/googlemaps.mdwn b/doc/plugins/contrib/googlemaps.mdwn new file mode 100644 index 000000000..c43490b13 --- /dev/null +++ b/doc/plugins/contrib/googlemaps.mdwn @@ -0,0 +1,21 @@ +[[!template id=plugin name=googlemaps author="Christian Mock"]] +[[!tag type/special-purpose todo/geotagging]] + +`googlemaps` is a plugin that allows using the [Google Maps API][2] +from ikiwiki. + +[2]: http://www.google.com/apis/maps/ + +The plugin supports importing GPS tracks from [gpx][1] files, reducing +the number of points in those tracks via [gpsbabel][2], and drawing +them as an overlay on the map. the center of the map and zoom level +can be calculated automatically. + +[1]: http://www.topografix.com/gpx.asp +[2]: http://www.gpsbabel.org/ + +It can be [found here][3]. + +[3]: http://www.tahina.priv.at/hacks/googlemaps.html + +See also [[plugins/osm]]. diff --git a/doc/plugins/contrib/googlemaps/discussion.mdwn b/doc/plugins/contrib/googlemaps/discussion.mdwn new file mode 100644 index 000000000..b148c0eee --- /dev/null +++ b/doc/plugins/contrib/googlemaps/discussion.mdwn @@ -0,0 +1,16 @@ +Very neat. The warnings about it not being very secure are of course spot on. +Seems that the need to embed the api key on the page is a security problem of one sort. + +The call to gpsbabel _seems_ secure thanks to the sanitisation done to the filename passed to gpsbabel. + +I probably won't ever add this to ikiwiki, but it's a great third-party plugin! + +--[[Joey]] + +----- + +Can this plugin be extended to allow the user to switch the displayed to +many available maps, similar to the functionality provided by +[OSMify](http://blog.johnmckerrell.com/2007/12/31/new-version-of-osmify-bookmarklet/) +which allow replacing maps with one of the [OpenStreetMap](http://openstreetmap.org/) renderings. +-- [[users/vibrog]] diff --git a/doc/plugins/contrib/groupfile.mdwn b/doc/plugins/contrib/groupfile.mdwn new file mode 100644 index 000000000..e5c0ded42 --- /dev/null +++ b/doc/plugins/contrib/groupfile.mdwn @@ -0,0 +1,105 @@ +[[!template id=plugin name=groupfile core=0 author="[[Jogo]]"]] + +This plugin add a `group(groupname)` function to [[ikiwiki/PageSpec]], which is true +only if the actual user is member of the group named `groupname`. + +Groups membership are read from a file. The syntax of this file is very close to +usual `/etc/passwd` Unix file : the group's name, followed by a colon, followed by +a coma separated list of user's names. For exemple : + + dev:toto,foo + i18n:zorba + +----- + + #!/usr/bin/perl + # GroupFile plugin. + # by Joseph Boudou + + package IkiWiki::Plugin::groupfile; + + use warnings; + use strict; + use IkiWiki 3.00; + + sub import { + hook(type => 'getsetup', id => 'groups', call => \&get_setup); + } + + sub get_setup () { + return ( + plugin => { + safe => 0, + rebuild => 0, + }, + group_file => { + type => 'string', + example => '/etc/ikiwiki/group', + description => 'group file location', + safe => 0, + rebuild => 0, + }, + ); + } + + my $users_of = 0; + + sub get_groups () { + if (not $users_of) { + + if (not defined $config{group_file}) { + return 'group_file option not set'; + } + + open my $file, '<', $config{group_file} + or return 'Unable to open group_file'; + + $users_of = {}; + READ: + while (<$file>) { + next READ if (/^\s*$/); + + if (/^(\w+):([\w,]+)/) { + %{ $users_of->{$1} } = map { $_ => 1 } split /,/, $2; + } + else { + $users_of = "Error at group_file:$."; + last READ; + } + } + + close $file; + } + + return $users_of; + } + + package IkiWiki::PageSpec; + + sub match_group ($$;@) { + shift; + my $group = shift; + my %params = @_; + + if (not exists $params{user}) { + return IkiWiki::ErrorReason->new('no user specified'); + } + if (not defined $params{user}) { + return IkiWiki::FailReason->new('not logged in'); + } + + my $users_of = IkiWiki::Plugin::groupfile::get_groups(); + if (not ref $users_of) { + return IkiWiki::ErrorReason->new($users_of); + } + + if (exists $users_of->{$group}{ $params{user} }) { + return IkiWiki::SuccessReason->new("user is member of $group"); + } + else { + return IkiWiki::FailReason->new( + "user $params{user} isn't member of $group"); + } + } + + 1 diff --git a/doc/plugins/contrib/highlightcode.mdwn b/doc/plugins/contrib/highlightcode.mdwn new file mode 100644 index 000000000..f1df204bb --- /dev/null +++ b/doc/plugins/contrib/highlightcode.mdwn @@ -0,0 +1,10 @@ +[[!template id=plugin name=highlightcode author="[[sabr]]"]] +[[!tag type/format]] + +(An alternative to this plugin, [[plugins/highlight]], is now provided with IkiWiki. --[[smcv]]) + +A small plugin to allow Ikiwiki to display source files complete with syntax highlighting. Files with recognized extensions (i.e. my-file.cpp) are be rendered just like any other Ikiwiki page. You can even edit your source files with Ikiwiki's editor. + +It uses the Syntax::Highlight::Engine::Kate Perl module to do the highlighting. + +It can be found at: --[[sabr]] diff --git a/doc/plugins/contrib/ikiwiki/directive/album.mdwn b/doc/plugins/contrib/ikiwiki/directive/album.mdwn new file mode 100644 index 000000000..433eec8bd --- /dev/null +++ b/doc/plugins/contrib/ikiwiki/directive/album.mdwn @@ -0,0 +1,56 @@ +The `album` directive is supplied by the [[!iki plugins/contrib/album desc=album]] plugin. + +Each page containing an `album` directive is treated as a photo album +or image gallery. Example usage is as simple as: + + \[[!album]] + +Every image attached to an album or its [[subpages|ikiwiki/subpage]] is +considered to be part of the album. A "viewer" page, with the wiki's default +page extension, will be generated in the +[[transient underlay|plugins/transient]] to display the +image, if there isn't already a page of the same name as the image: for +instance, if `debconf` is an album and `debconf/tuesday/p100.jpg` exists, +then `debconf/tuesday/p100.mdwn` might be created. + +The album is treated as a [[!iki plugins/contrib/trail desc=trail]], which +gives each viewer page a link back to the album, and a link to the previous +and next viewer in the album. + +The `album` directive also produces an [[ikiwiki/directive/inline]] which +automatically includes all the viewers for this album, except those that +will appear in an [[albumsection]]. If every image in the album is in a +section, then the `album` directive is still required, but won't produce +any output in the page. + +The `inline` can include some extra information about the images, including +file size and a thumbnail made using [[ikiwiki/directive/img]]). The +default template is `albumitem.tmpl`, which takes advantage of these things. + +## Options + +The directive can have some options for the entire album. The defaults are: + + \[[!album + sort="-age" + size="full" + thumbnailsize="96x96" + viewertemplate="albumviewer" + prevtemplate="albumprev" + nexttemplate="albumnext" + +* `sort` - sets the order in which images appear, defaulting to earliest + creation date first +* `size` - if not `full`, the [[ikiwiki/directive/img]] in the viewer page + will be resized to be no larger than this +* `thumbnailsize` - the [[ikiwiki/directive/img]] in the album page, + which can also be used in the previous/next links, will be no larger than + this +* `viewertemplate` - the template used for the [[albumimage]] in each + viewer page +* `prevtemplate` - the template used to replace `` if used in + the viewer page +* `nexttemplate` - the template used to replace `` if used in + the viewer page + +[[!meta robots="noindex, follow"]] diff --git a/doc/plugins/contrib/ikiwiki/directive/albumimage.mdwn b/doc/plugins/contrib/ikiwiki/directive/albumimage.mdwn new file mode 100644 index 000000000..2385bb535 --- /dev/null +++ b/doc/plugins/contrib/ikiwiki/directive/albumimage.mdwn @@ -0,0 +1,26 @@ +The `albumimage` directive is supplied by the [[!iki plugins/contrib/album desc=album]] plugin. + +Each viewer page produced by the [[album]] directive +contains an `albumimage` directive, which is replaced by an +[[ikiwiki/directive/img]], wrapped in some formatting using a +template (by default it's `albumviewer.tmpl`). That template can also include +links to the next and previous photos, in addition to those provided by the +[[!iki plugins/contrib/trail desc=trail]] plugin. + +The next/previous links are themselves implemented by evaluating a template, +either `albumnext.tmpl` or `albumprev.tmpl` by default. + +The directive can also have parameters: + +* `title`, `date`, `updated`, `author`, `authorurl`, `copyright`, `license` + and `description` are short-cuts for the corresponding + [[ikiwiki/directive/meta]] directives + +* `caption` sets a caption which is displayed near this image in the album + and viewer pages + +The viewer page can also contain any text and markup before or after the +`albumimage` directive, which will appear before or after the image in the +viewer page. + +[[!meta robots="noindex, follow"]] diff --git a/doc/plugins/contrib/ikiwiki/directive/albumsection.mdwn b/doc/plugins/contrib/ikiwiki/directive/albumsection.mdwn new file mode 100644 index 000000000..7e5749e05 --- /dev/null +++ b/doc/plugins/contrib/ikiwiki/directive/albumsection.mdwn @@ -0,0 +1,29 @@ +The `albumsection` directive is supplied by the [[!iki plugins/contrib/album desc=album]] plugin. + +The `albumsection` directive is used to split an album into sections. It can +only appear on a page that also has the [[album]] directive. + +The `filter` parameter is a [[ikiwiki/PageSpec]] against which viewer pages +are matched. The `albumsection` directive displays all the images that match +the filter, and the `album` directive displays any leftover images, like +this: + + # Holiday photos + + \[[!album]] + + + ## People + + \[[!albumsection filter="tagged(people)"]] + + + ## Landscapes + + \[[!albumsection filter="tagged(landscapes)"]] + + +[[!meta robots="noindex, follow"]] diff --git a/doc/plugins/contrib/ikiwiki/directive/jssearchfield.mdwn b/doc/plugins/contrib/ikiwiki/directive/jssearchfield.mdwn new file mode 100644 index 000000000..5d338901d --- /dev/null +++ b/doc/plugins/contrib/ikiwiki/directive/jssearchfield.mdwn @@ -0,0 +1,42 @@ +The `jssearchfield` directive is supplied by the [[!iki plugins/contrib/jssearchfield desc=jssearchfield]] plugin. + +This enables one to search the structured data ("field" values) of +multiple pages. A search form is constructed, and the searching is +done with Javascript, which means that the entire thing is self-contained. +This depends on the [[!iki plugins/contrib/field]] plugin. + +The pages to search are selected by a PageSpec given by the "pages" +parameter. +The fields to search are given by the "fields" parameter. By default, +the field name is given, and the user can type the search parameter for +that field into a text input field. + +## OPTIONS + +**pages**: A PageSpec to determine the pages to search through. + +**fields**: The fields to put into the search form, and to display +in the results. + +**tagfields**: Display the given fields as a list of tags that can +be selected from, rather than having a text input field. Every distinct +value of that field will be listed, so it is best used for things with +short values, like "Author" rather than long ones like "Description". +Note that "tagfields" must be a subset of "fields". + +**sort**: A SortSpec to determine how the matching pages should be sorted; this is the "default" sort order that the results will be displayed in. +The search form also gives the option of "random" sort, which will +display the search results in random order. + +## SEARCHING + +The search form that is created by this directive contains the following: + +* for each search field, a label, plus either a text input field, or a list of checkboxes with values next to them if the field is also a tagfield. Note that the lists of checkboxes are initially hidden; one must click on the triangle next to the label to display them. +* a "sort" toggle. One can select either "default" or "random". +* A "Search!" button, to trigger the search if needed (see below) +* A "Reset" button, which will clear all the values. + +The searching is dynamic. As soon as a value is changed, either by tabbing out of the text field, or by selecting or de-selecting a checkbox, the search +results are updated. Furthermore, for tagfields, the tagfield lists +themselves are updated to reflect the current search results. diff --git a/doc/plugins/contrib/ikiwiki/directive/ymlfront.mdwn b/doc/plugins/contrib/ikiwiki/directive/ymlfront.mdwn new file mode 100644 index 000000000..1a01834f8 --- /dev/null +++ b/doc/plugins/contrib/ikiwiki/directive/ymlfront.mdwn @@ -0,0 +1,17 @@ +The `ymlfront` directive is supplied by the [[!iki plugins/contrib/ymlfront desc=ymlfront]] plugin. + +This directive allows the user to define arbitrary meta-data in YAML format. + + \[[!ymlfront data=""" + foo: fooness + bar: The Royal Pigeon + baz: 2 + """]] + +There is one argument to this directive. + +* **data:** + The YAML-format data. This should be enclosed inside triple-quotes to preserve the data correctly. + +If more than one ymlfront directive is given per page, the result is undefined. +Likewise, it is inadvisable to try to mix the non-directive ymlfront format with the directive form of the data. diff --git a/doc/plugins/contrib/ikiwiki/directive/ymlfront/discussion.mdwn b/doc/plugins/contrib/ikiwiki/directive/ymlfront/discussion.mdwn new file mode 100644 index 000000000..f49c85079 --- /dev/null +++ b/doc/plugins/contrib/ikiwiki/directive/ymlfront/discussion.mdwn @@ -0,0 +1,37 @@ +I can't seem to make this work. I have tried, in this [sandbox](http://mesh.openisp.ca/sandbox), to set values for fields and then display them with the getfield meta syntax, but it doesn't seem to be working. + +The getfield, field and ymlfront plugins are enabled. I have tried with and without the following field registration: + + # field plugin + # define the fields for the meshmtl project + field_register: + - meta + - hostname + - MAC + - IP + +I have tried both the ymlfront directive and the YAML markup (with the +`---` delimiter), no luck. Any idea what I am doing wrong? -- +[[anarcat]] + +> I'm afraid I can't tell from here what the problem could be. It's clear that ymlfront is turned on, or the ymlfront directive in your sandbox page wouldn't be processed. The only thing I can suggest, in order to get more information about what could be going wrong, would be to do a dump of your indexdb file (see [[tips/inside dot ikiwiki]]) and see what the data for your sandbox page is. If there is field data there, that would indicate a problem with getfield; if there isn't field data there, that would indicate a problem with field or ymlfront. + +> Oh, and you only need to register "meta" with field_register; that will enable the data defined by the "meta" plugin to be read by field. Unless "hostname", "MAC" and "IP" are plugins, you don't need to add them to field_register. They can be taken care of by the ymlfront plugin. Perhaps that is the problem? + +> --[[KathrynAndersen]] + +> > I have tried removing the other fields from the declaration, no luck. I did, however, notice the following error in the `--rebuild` output: +> > +> > ymlfront parse: Load of sandbox data failed: YAML Error: Stream does not end with newline character +> > Code: YAML_PARSE_ERR_NO_FINAL_NEWLINE +> > Line: 0 +> > Document: 0 +> > at /usr/share/perl5/YAML/Loader.pm line 38 +> > +> > Now *that* has to be related... ;) In the index.db, there is no ymlfront metadata for the sandbox page... Note that the `---` delimiter approach doesn't trigger the warning but doesn't populate the DB either... +> > +> > Finally note that after adding debugging code, I was able to figure out that this seems to be using the `YAML::XS` library. I have also traced the data and confirmed that `$yml_str` does get properly initialized in `parse_yml`, and it is where the error is generated. So maybe there's something wrong with the YAML library? +> > +> > Update: well, look here: using `YAML::Syck` doesn't yield the same error *and* the metadata actually works! So this is a problem specific to `YAML::Any`. Hardcoding `use YAML::XS` or *even* `use YAML::Any` fixed the problem for me. +> > +> > Now delimiters also work, but the output is kind of ugly: it gets parsed as regular markdown makup so the `---` makes horizontal lines in the beginning and headings in the end... --[[anarcat]] diff --git a/doc/plugins/contrib/imailhide.mdwn b/doc/plugins/contrib/imailhide.mdwn new file mode 100644 index 000000000..6009aa012 --- /dev/null +++ b/doc/plugins/contrib/imailhide.mdwn @@ -0,0 +1,65 @@ +[[!template id=plugin name=imailhide author="Peter_Vizi"]] +[[!tag type/widget type/html]] + +# Mailhide Plugin for Ikiwiki + +This plugin provides the directive mailhide, that uses the [Mailhide +API][1] to protect email addresses from spammers. + +## Dependencies + +The [Captcha::reCAPTCHA::Mailhide][2] perl module is required for this +plugin. + +## Download + +You can get the source code from [github][3]. + +## Installation + +Copy `imailhide.pm` to `/usr/share/perl/5.10.0/IkiWiki/Plugin` or +`~/.ikiwiki/IkiWiki/Plugin`, and enable it in your `.setup` file + + add_plugins => [qw{goodstuff imailhide ....}], + mailhide_public_key => "8s99vSA99fF11mao193LWdpa==", + mailhide_private_key => "6b5e4545326b5e4545326b5e45453223", + mailhide_default_style => "short", + +## Configuration + +### `mailhide_public_key` + +This is your personal public key that you can get at [Google][4]. + +### `mailhide_private_key` + +This is your personal private key that you can get at [Google][4]. + +### `mailhide_default_style` + +As per the recommendation of the [Mailhide API documentation][5], you +can define this as `short` or `long`. The `short` parameter will +result in `john` links, while the `long` parameter +will result in `joh...@example.com`. + +## Parameters + +### `email` + +*Required.* This is the email addres that you want to hide. + +### `style` + +*Optional.* You can set the style parameter individually for each + `mailhide` call. See `mailhide_default_style` for details. + +## Known Issues + +1. [opening new window when displaying email address][6] + +[1]: http://www.google.com/recaptcha/mailhide/ +[2]: http://search.cpan.org/perldoc?Captcha::reCAPTCHA::Mailhide +[3]: http://github.com/petervizi/imailhide +[4]: http://www.google.com/recaptcha/mailhide/apikey +[5]: http://code.google.com/apis/recaptcha/docs/mailhideapi.html +[6]: http://github.com/petervizi/imailhide/issues#issue/1 diff --git a/doc/plugins/contrib/img.mdwn b/doc/plugins/contrib/img.mdwn new file mode 100644 index 000000000..6c25966e0 --- /dev/null +++ b/doc/plugins/contrib/img.mdwn @@ -0,0 +1,14 @@ +[[!template id=plugin name=img author="Christian Mock"]] +[[!tag type/chrome]] + +`img` is an enhanced image handling plugin. + +the intention is to make image handling as easy as possible, so the +plugin can scale down images for direct inclusion into the page, +providing a link to one or more larger or full-size versions on their +own page. `width` and `height` attributes are included in the `` +tag, and `alt` text can be specified. + +the plugin uses the ImageMagick tools via PerlMagick. + +it can be found [here](http://www.tahina.priv.at/hacks/img.html). diff --git a/doc/plugins/contrib/img/discussion.mdwn b/doc/plugins/contrib/img/discussion.mdwn new file mode 100644 index 000000000..ea4ccb042 --- /dev/null +++ b/doc/plugins/contrib/img/discussion.mdwn @@ -0,0 +1,51 @@ +This is a good idea, I was just the other day stuck writing ugly html to +properly size an image for a blog post. Putting the image sizing support +into a plugin instead of trying to shoehorn it into a wikilink seems like +the way to go. + +I have two issues with this plugin as it's implemented now, the first is +that the generation of whole pages containing a scaled version of the image +seems gratuituous, as well as buggy. If you want three pages with +differently scaled versions of the image, why not just create three pages +and use the plugin once per page? Something like this on the first one if +it's got multiple clickable thumbnails: + + \[[!img foo.jpg width=256 link=page2]] + +This on the second: + + \[[!img foo.jpg width=1024 link=page3]] + \[[small|page1]] + \[[medium|page2]] + \[[large|page3]] + +This on the third: + + \[[!img foo.jpg link=page3]] + \[[small|page1]] + \[[medium|page2]] + \[[large|parge3]] + +Granted, this is more work, but it's more flexible too, and it doesn't have +it creating new pages on the fly, which I don't personally like.. + +---- + +The second issue is whether it should use imagemagick to scale the image +and generate a new scaled one, or just emit html that sets the sizes of the +image. Benefits to scaling: + +1. Saves download time and bandwidth, especially if generating a page with a + lot of thumbnails of large images. + +Benefits of not scaling: + +1. Avoids any security issues with imagemagick. +2. Avoids issue of how to clean up old scaled images that are no longer being + used. (Granted, this is a general ikiwiki problem that will eventually + be fixed in a general way. (Update: now fixed in a general way, use the + will_render function.)) +3. Makes clicking on thumbnails display the full version really fast, since + it's cached. :-) + +--[[Joey]] diff --git a/doc/plugins/contrib/irclog.mdwn b/doc/plugins/contrib/irclog.mdwn new file mode 100644 index 000000000..634f010c9 --- /dev/null +++ b/doc/plugins/contrib/irclog.mdwn @@ -0,0 +1,21 @@ +The [irclog](https://github.com/ironchicken/ikiwiki-irclog) plugin allows including a formatted IRC log in your wiki. + +### Usage + +The `[[!irclog]]` directive takes the following arguments: + +`location` (required) + +The URI of your IRC log file. Currently the URI schemes `file:`, `http:`, and `ssh:` have been implemented. Only `ssh:` has been tested: `ssh://host/path/to/#channel`. + +`earliest` (optional) + +A date/time in the format `%F %T` (i.e. `YYYY-MM-DD HH:MM:SS`). Events before this time will not be included. String comparison is used, so you can omit portions of the date/time if you like, e.g. `YYYY-MM`. + +`latest` (optional) + +A date/time. Events after this time will not be included. + +`keywords` (optional) + +A mapping of keywords to translations, formatted like a Perl hash, e.g.: "richard=>\[[richard]\]". In this case occurrences of "richard" will be replaced with "\[[richard]\]" (which will later be processed as a WikiLink). diff --git a/doc/plugins/contrib/jscalendar.mdwn b/doc/plugins/contrib/jscalendar.mdwn new file mode 100644 index 000000000..8123b3132 --- /dev/null +++ b/doc/plugins/contrib/jscalendar.mdwn @@ -0,0 +1,50 @@ +[[!meta author="spalax"]] +[[!template id=plugin name=jscalendar author="[[Louis|spalax]]"]] + +# Jscalendar + +Jscalendar is a javascript equivalent to the [[calendar|plugins/calendar]] plugin. + +## Description + +Here are some differences compared to this latter plugin. + +* Pros + * No need to rebuild the page containing the calendar each time day changes, or + a page (indexed by the calendar) is added, changed or deleted. This is + particularly useful if you want to have this calendar in the sidebar. + * Smooth navigation among months. +* Cons + * Javascript :( . + +## Usage + +### Examples of directive + + \[[!jscalendar type="month" ]] + + \[[!jscalendar type="month" archivebase="calendar"]] + + \[[!jscalendar type="month" year=2014 month=08 pages="posts/* and !posts/*"]] + + \[[!jscalendar type="month" year=-1 month=08]] + +### Setup file + +This plugin uses the options used by the [[plugins/calendar]] plugin: + + 'archivebase' => "archive", + 'archive_pagespec' => "posts/* and ! posts/*/*", + 'week_start_day' => 1, + 'month_link' => 1, + +The `archivebase` and `archive_pagespec` can be overloaded by the very same +options of the directive. + +## Example + +You can see this plugin in action on [[our website|http://www.gresille.org]]. + +Code and documentation can be found here : [[https://atelier.gresille.org/projects/gresille-ikiwiki/wiki/Jscalendar]] + +-- Louis diff --git a/doc/plugins/contrib/jssearchfield.mdwn b/doc/plugins/contrib/jssearchfield.mdwn new file mode 100644 index 000000000..2d41ee24f --- /dev/null +++ b/doc/plugins/contrib/jssearchfield.mdwn @@ -0,0 +1,35 @@ +[[!template id=plugin name=jssearchfield author="[[rubykat]]"]] +[[!tag type/search]] +IkiWiki::Plugin::jssearchfield - Create a search form to search page field data. + +This plugin provides the [[ikiwiki/directive/jssearchfield]] directive. This +enables one to search the structured data ("field" values) of multiple pages. +This uses Javascript for the searching, which means that the entire thing +is self-contained and does not require a server or CGI access, unlike +the default IkiWiki search. This means that it can be used in places such +as ebook readers. The disadvantage is that because Javascript runs +in the browser, the searching is only as fast as the machine your browser +is running on. + +Because this uses Javascript, the htmlscrubber must be turned off for any page where the directive is used. + +This plugin depends on the [[!iki plugins/contrib/field]] plugin. + +## Activate the plugin + + # activate the plugin + add_plugins => [qw{goodstuff field jssearchfield ....}], + + # disable scrubbing for search page + htmlscrubber_skip => 'mysearchpage', + +## PREREQUISITES + + IkiWiki + IkiWiki::Plugin::field + HTML::Template + +## DOWNLOAD + +* browse at GitHub: +* git repo at git://github.com/rubykat/ikiplugins.git diff --git a/doc/plugins/contrib/justlogin.mdwn b/doc/plugins/contrib/justlogin.mdwn new file mode 100644 index 000000000..90645b9ef --- /dev/null +++ b/doc/plugins/contrib/justlogin.mdwn @@ -0,0 +1,52 @@ +This plugin has been abandoned while still in development. Currently it does bring up the login page and the login page does, with proper credentials, log in the user, but the returning page goes to prefs. I have no idea why. I decided to go in another direction so if someone wants to take over then please do so. Otherwise I have no problem if this page needs to be deleted. [[users/justint/]] + +Place this code into a page: + +<form action="http://portable.local/cgi-bin/ikiwiki.cgi" method="get"> + +<input type="hidden" name="do" value="justlogin" /> + +<input type="submit" value="Login" /></form> + +This is the plugin so far: +#!/usr/bin/perl + # Bring up a login page that returns to the calling page + package IkiWiki::Plugin::justlogin; + + use warnings; + use strict; + use IkiWiki 3.00; + + sub import { + hook(type => "sessioncgi", id => "justlogin", call => \&sessioncgi); + } + + sub sessioncgi ($$) { + my $q=shift; + my $session=shift; + + debug("jl sessioncgi1 running."); + + if ($q->param("do") eq "justlogin") { + debug("jl do=justlogin running."); + if (! defined $session->param("name") ) { + debug("jl param!defined running."); + $session->param("postsignin" => $ENV{HTTP_REFERER} ); + $session->param("do" => "justgoback" ); + IkiWiki::cgi_signin($q, $session); + IkiWiki::cgi_savesession($session); + } + exit; + } elsif ($session->param("do") eq "justgoback") { + debug("jl justgoback running."); + my $page=$q->param("postsignin"); + $session->clear("postsignin"); + $session->clear("do"); + IkiWiki::cgi_savesession($session); + IkiWiki::redirect($q, $page); + exit; + } + } + + 1 + diff --git a/doc/plugins/contrib/linguas.mdwn b/doc/plugins/contrib/linguas.mdwn new file mode 100644 index 000000000..84ece042e --- /dev/null +++ b/doc/plugins/contrib/linguas.mdwn @@ -0,0 +1,107 @@ +[[!template id=plugin name=linguas author="Jordà Polo"]] + +Linguas +======= + +Linguas is a plugin for [ikiwiki](http://ikiwiki.info/) that +allows translations of wiki pages. + +Download: [linguas.pm](http://ettin.org/pub/ikiwiki/linguas.pm) (2006-08-21). + +Note that even though it is still available for download, this plugin is no +longer actively maintained. If you are interested in multilingual wiki pages, you +can also take a look at other approaches such as [[todo/l10n]], [[plugins/po]], +or Lars Wirzenius's +[Static website, with translations, using IkiWiki](http://liw.iki.fi/liw/log/2007-05.html#20070528b). + +Usage +----- + +Translatable pages and translations must have the following format: +`pagename.$LANG`, where `$LANG` is a ISO639-1 (two-letter) language code. +To enable linguas, add the following line in the source code of the page: + + \[[!linguas ]] + +Note that linguas is only required in one of the pages (the original, +for instance); the rest of translations will be automatically +updated. Additionally, it is also possible to specify the title of +the translation: + + \[[!linguas title="Translated title"]] + + +Template +-------- + +This is the template code that should be added to `templates/page.tmpl`: + + +
+

+
    + +
  • +
    +
+
+
+ + +TODO/Known Problems +------------------- + +* The current language list only contains 4 languages (ca, de, en, +es), and is "hardcoded" in linguas.pm. Would be interesting to define +it in ikiwiki.setup, though some problems were found while trying to do +so. (Actually, defining hash-like arguments from the command like works +fine, but it fails from ikiwiki.setup.) + + > My guess about this is that it's because of the way Setup/Standard.pm + > untaints the config items from the file. It has code to handle arrays, + > but not hashes or more complex data structures. --[[Joey]] + + > > Right. With this simple + > > [patch](http://ettin.org/pub/ikiwiki/hash_setup.patch) it seems to + > > work. However, note that 1) it only allows simple hashes, hashes of + > > hashes will not work (I don't think getops can handle complex hashes + > > anyway); 2) I don't really know when/why you call + > > `possibly_foolish_untaint()`; and 3) I'm no perl guru ;). --Jordà + + > > > It's good. Applied.. + +* Wiki links to other translated pages require the full page name +including the `.$LANG`. It should be possible to link automatically +to pages with the same `.$LANG`, but that would probably require some +changes in IkiWiki. (I'm not sure though, I still haven't looked at +it... any hints?) + + > Have you considered using the form ll/page? This would let more usual + > linking rules apply amoung pages without needing to specify the + > language. I'm not sure if you're supporting browser content + > negotiation, or whether that other layout would be harder to support it + > though. --[[Joey]] + + > > Actually, I'm happy with the way it works now (and yeah, it is very + > > easy to take advantage of content negotiation). I just wanted + > > something simple to translatte a single page (or a few pages), not + > > the entire wiki. I'm not even sure it is a good idea to have fully + > > multilingual wikis, in most cases I would go for a different wiki + > > for each language. That said, I think it is an interesting idea, so + > > I'll take a look when I have the time. Thanks for your comments. + > > --Jordà + +* The changes to htmllink in ikiwiki 1.44 broke this plugin. +The following fixes it: + + --- linguas.pm.orig 2006-08-23 19:07:04.000000000 +0200 + +++ linguas.pm 2007-03-24 01:53:18.000000000 +0100 + @@ -100,7 +100,7 @@ + if (exists $linguas{$2} && defined $linguas{$2}) { + $link = $linguas{$2}{'name'}; + } + - push @links, IkiWiki::htmllink($page, $destpage, $trans, 0, 0, $link); + + push @links, IkiWiki::htmllink($page, $destpage, $trans, noimageinline => 0, forcesubpage => 0, linktext => $link); + } + + my $otherlinguas = 'Translations:'; diff --git a/doc/plugins/contrib/livefyre.mdwn b/doc/plugins/contrib/livefyre.mdwn new file mode 100644 index 000000000..d4a62c0cc --- /dev/null +++ b/doc/plugins/contrib/livefyre.mdwn @@ -0,0 +1,14 @@ +[[!template id=plugin name=livefyre core=0 author="[[cmauch]]"]] +[[!tag type/special-purpose]] + +[LiveFyre](http://www.livefyre.com) is a third party comment and discussion system similar in some ways to Disqus or IntenseDebate. All three services use javascript to attach comments to your site without the need to use a native commenting system. + +This plugin is designed to replace the commenting system in IkiWiki entirely. It embeds LiveFyre comments on your ikiwiki blog or posts. It is was originally based on the [Disqus Plugin](https://code.google.com/p/ikiwiki-plugin-disqus/). After a few days of noticing odd page title names on the livefyre moderation interface, I updated the script to make use of JSON. I made extensive use of the [integration guide](https://github.com/Livefyre/livefyre-docs/wiki/StreamHub-Integration-Guide) to get it all running. + +It's loud and messy and slow, but kind of neat too. + +Requires the [[!cpan JSON]], [[!cpan JSON::WebToken]], and [[!cpan Digest::MD5]] perl modules to be available. + +You can grab the source [here](https://bitbucket.org/cmauch/ikiwiki/src/master/IkiWiki/Plugin/livefyre.pm) + +See the POD documention in the module for installation and configuration instructions. diff --git a/doc/plugins/contrib/localfavicon.mdwn b/doc/plugins/contrib/localfavicon.mdwn new file mode 100644 index 000000000..66c9fdf5c --- /dev/null +++ b/doc/plugins/contrib/localfavicon.mdwn @@ -0,0 +1,7 @@ +[[!template id=plugin name=localfavicon author="Franek"]] + +This is a trivial modification of the [[plugins/favicon]] plugin to allow different favicons for different parts of the site. For this, the option "localfavicon" has to be set to 1 in the setup file, otherwise the plugin behaves just like the favicon plugin. + +For now, it can be downloaded here: [[http://perm.lemtank.de/localfavicon.pm]] + +See the [[this forum thread|forum/Can_I_have_different_favicons_for_each_folder__63__]] for discussion. diff --git a/doc/plugins/contrib/mailbox.mdwn b/doc/plugins/contrib/mailbox.mdwn new file mode 100644 index 000000000..b7a9f81c7 --- /dev/null +++ b/doc/plugins/contrib/mailbox.mdwn @@ -0,0 +1,18 @@ +[[!template id=plugin name=mailbox author="[[DavidBremner]]"]] +[[!tag type/format]] + +The `mailbox` plugin adds support to ikiwiki for +rendering mailbox file into a page displaying the mails +in the mailbox. It supports mbox, maildir, and MH folders, +does threading, and deals with MIME. + +One hitch I noticed was that it is not currently possible to treat a +maildir or an MH directory as a page (i.e. just call it foo.mh and have it +transformed to page foo). I'm not sure if this is possible and worthwhile +to fix. It is certainly workable to use a [[!mailbox ]] directive. +-- [[DavidBremner]] + +This plugin is not in ikiwiki yet, but can be downloaded +from + + diff --git a/doc/plugins/contrib/mailbox/discussion.mdwn b/doc/plugins/contrib/mailbox/discussion.mdwn new file mode 100644 index 000000000..9520fdd70 --- /dev/null +++ b/doc/plugins/contrib/mailbox/discussion.mdwn @@ -0,0 +1,8 @@ +# The remote repo + +For some reason, `git fetch` from http://pivot.cs.unb.ca/git/ikimailbox.git/ didn't work very smoothly for me: it hung, and I had to restart it 3 times before the download was complete. + +I'm writing this just to let you know that there might be some problems with such connections to your http-server. --Ivan Z. +> I can't replicate this (two months later!) +> I can suggest trying the git:// url for download if you can. +> Also, if you really want to get my attention, send me email [[DavidBremner]] diff --git a/doc/plugins/contrib/mandoc.mdwn b/doc/plugins/contrib/mandoc.mdwn new file mode 100644 index 000000000..672a268cc --- /dev/null +++ b/doc/plugins/contrib/mandoc.mdwn @@ -0,0 +1,12 @@ +[[!template id=plugin name=mandoc author="[[schmonz]]"]] +[[!template id=gitbranch branch=schmonz/mandoc author="[[schmonz]]"]] +[[!tag type/format]] + +This plugin lets ikiwiki convert Unix man pages to HTML. It uses +[mdocml](http://mdocml.bsd.lv/) for the conversion, and postprocesses +xrefs into hyperlinks. + +Possible enhancements: + +* configurable path and args to `mandoc` (and it could be `groff`) +* configurable location for rendered manpages (such as subdirs per section) diff --git a/doc/plugins/contrib/mathjax.mdwn b/doc/plugins/contrib/mathjax.mdwn new file mode 100644 index 000000000..a784b95d9 --- /dev/null +++ b/doc/plugins/contrib/mathjax.mdwn @@ -0,0 +1,13 @@ +[[!template id="plugin" name="mathjax" author="Baldur Kristinsson"]] + +The [mathjax plugin](https://github.com/bk/ikiwiki-plugin-mathjax), available on GitHub, provides easy MathJax support for ikiwiki. + +Features: + +- No change needed to page.tmpl +- Javascript is only loaded on pages which need it. +- Both inline and display math are supported. +- Unlike [[the pandoc plugin|plugins/contrib/pandoc]] or a solution based on editing page.tmpl, no irritating conflicts with the smiley plugin. +- Unlike the pandoc plugin, it is easy to use in shared hosting or other environments where you have difficulty in installing extra software (beyond Perl modules, obviously). + +However, if you need the power of Pandoc, such as bibliography support or pdf generation, then that is probably the better option for you. diff --git a/doc/plugins/contrib/mediawiki.mdwn b/doc/plugins/contrib/mediawiki.mdwn new file mode 100644 index 000000000..13c2d04b2 --- /dev/null +++ b/doc/plugins/contrib/mediawiki.mdwn @@ -0,0 +1,10 @@ +[[!template id=plugin name=mediawiki author="[[sabr]]"]] +[[!tag type/format]] + +The Mediawiki plugin allows ikiwiki to process pages written using MediaWiki +markup. + +Available at . + +This plugin originally lived at , but that +website has disappeared. diff --git a/doc/plugins/contrib/mediawiki/discussion.mdwn b/doc/plugins/contrib/mediawiki/discussion.mdwn new file mode 100644 index 000000000..c288d9bd1 --- /dev/null +++ b/doc/plugins/contrib/mediawiki/discussion.mdwn @@ -0,0 +1,9 @@ +Anyone know a safe place where this plugin can be found? -- mjr at phonecoop.coop + +> I ended up doing a backassward way of doing it, as described at the [convert discussion page](http://ikiwiki.info/tips/convert_mediawiki_to_ikiwiki/discussion/). -[[simonraven]] + +>> I've mirrored it at . -- [[Jon]] + +--- + +Something that gives me better results is to edit the source of the [[wikitext]] plugin, and change all occurences of Text::WikiFormat to Text::MediawikiFormat. (This of course depends on ''libtext-mediawikiformat-perl'' instead of ''libtext-wikiformat-perl'' -- [[gi1242]] diff --git a/doc/plugins/contrib/monthcalendar.mdwn b/doc/plugins/contrib/monthcalendar.mdwn new file mode 100644 index 000000000..c21be0abe --- /dev/null +++ b/doc/plugins/contrib/monthcalendar.mdwn @@ -0,0 +1,127 @@ +[[!meta author="spalax"]] +[[!template id=plugin name=monthcalendar author="[[Louis|spalax]]"]] + +# Monthcalendar + +This plugin displays a calendar, containing in each of its day the list of links of pages published on this day. It can be used, for example, to display archives of blog posts, or to announce events. + +The difference between this plugin and the [[plugins/calendar]] plugin is that the calendar displayed by this plugin is a big one, containing the full title of every page indexed in it. + +## Usage + +### Directive + + \[[!monthcalendar type="month" year="2012" month="06" pages="events/*"]] + +### Automation + +By using the following line in template `calendarmonth.tmpl`, you can have `ikiwiki-calendar` using this plugin to display monthly archives. + + \[[!monthcalendar type="month" year="" month="" pages=""]] + +## CSS + +Here is an example of CSS properly rendering the calendar produced by this +plugin. +[[!toggle id=css text="CSS"]] +[[!toggleable id=css text=""" + /* Calendar */ + .monthcalendar + { + color:#aaa; + /* font-size:18pt; */ + margin-top:1em; + margin-bottom:1em; + width: 100%; + } + + .monthcalendar table, + .monthcalendar td, + .monthcalendar th + { + border: 1px solid #ccc; + } + + #content .monthcalendar td + { + padding: 0; + position: relative; + } + + .monthcalendar td div + { + min-height: 10ex; + height: 100%; + position: relative; + } + + .monthcalendar th + { + vertical-align: middle; + } + + .monthcalendar td ul + { + padding-left: 0.5em; + list-style: dot; + list-style-position: inside; + text-align: left; + font-size: 8pt; + position: relative; + z-index: 10; + font-weight: bold; + } + + table.monthcalendar + { + table-layout: fixed; + } + + .monthcalendar .selflink + { + color:#444444; + } + + .monthcalendar-day-head { + text-transform:capitalize; + } + + .monthcalendar-head { + text-transform:capitalize; + } + + .monthcalendar-daynumber + { + float: left; + position: absolute; + display: block; + font-size: 7ex; + color: #ccc; + line-height: 100%; + z-index: 5; + padding-top: 0.3ex; + text-align: right; + width: 1.8em; + } + + /* List of pages */ + + .monthcalendar-pagelist { + display: flex; + flex-direction: column; + } + + .monthcalendar-item { + opacity: 0; + height: 0; + } + + .monthcalendar-item:target { + opacity: 1; + height: initial; + } +"""]] + +## Code + +Code and documentation can be found here : [[https://atelier.gresille.org/projects/gresille-ikiwiki/wiki/Monthcalendar]]. diff --git a/doc/plugins/contrib/mscgen.mdwn b/doc/plugins/contrib/mscgen.mdwn new file mode 100644 index 000000000..792aaa4e3 --- /dev/null +++ b/doc/plugins/contrib/mscgen.mdwn @@ -0,0 +1,52 @@ +[[!template id=plugin name=mscgen author="[[users/Tjgolubi]]"]] +[[!tag type/widget]] + +## NAME + +IkiWiki::Plugin::mscgen - embed message sequence chart + +## SYNOPSIS + +In the ikiwiki setup file, enable this plugin by adding it to the list of active plugins. + + add_plugins: + - mscgen + +## DESCRIPTION + +This plugin provides the msc [[ikiwiki/directive]]. +This directive allows embedding [mscgen](http://www.mcternan.me.uk/mscgen/) +message sequence chart graphs in an ikiwiki page. + +Here's an example that shows how an mscgen message sequence chart is embedded into an ikiwiki page. + + \[[!msc src=""" + arcgradient = 8; + + a [label="Client"],b [label="Server"]; + + a=>b [label="data1"]; + a-xb [label="data2"]; + a=>b [label="data3"]; + a<=b [label="ack1, nack2"]; + a=>b [label="data2", arcskip="1"]; + |||; + a<=b [label="ack3"]; + |||; + """]] + +Security implications: to be determined. + +This plugin borrows heavily from the [[graphviz|plugins/graphviz]] plugin written by [[JoshTriplett]]. + +## PREREQUISITES + IkiWiki + mscgen + Digest::SHA + +## DOWNLOAD + +* browse at GitHub: +* repo at git://github.com/tjgolubi/ikiwiki.mscgen.git + + diff --git a/doc/plugins/contrib/navbar.mdwn b/doc/plugins/contrib/navbar.mdwn new file mode 100644 index 000000000..9de66f787 --- /dev/null +++ b/doc/plugins/contrib/navbar.mdwn @@ -0,0 +1,43 @@ +[[!template id=plugin name=navbar author="[[TobiOetiker]]"]] + +The Navbar Plugin renders a Navigation Bar into your page. It is based on code +from the [[sidebar_plugin|plugins/sidebar]]. + +The plugin looks for a page called "navbar" + +This page must contain a itemized list of the form + + + * \[[Welcome|index]] + * \[[Management|mgmt]] + * \[[Leadership|mgmt/lead]] + * \[[Kidnapping|mgmt/kidnapping]] + * \[[Information_Technology|it]] + * \[[Windows|it/windows]] + * \[[Mobile_Communication|it/mobile]] + +This list will be turned into a folding menu structure + +Include this into your templates. + + + + + + +To make a nice menu, some css magic is required, but since this is required to make +ikiwiki look good anyway, I won't go into details here ... + +See the navbar in action on + +Tobi Oetiker 2006.12.30 + +If you are interested in this, drop me a line tobi at oetiker dot ch + + +In the meanwhile, I ([[MartinQuinson]]) have hacked this a bit to make it fit my needs. The result is [[here|http://www.loria.fr/~quinson/Hacking/ikiwiki/]] + +In the meanwhile I too have hacked this for my needs and fixed a few bugs in Martin's version. +The result (and source / instructions) can be found [[here|http://wiki.math.cmu.edu/iki/wiki/tips/20140720-ikiwiki-navbar.html]]. (It is not mobile ready yet, but might be soon...) diff --git a/doc/plugins/contrib/navbar/discussion.mdwn b/doc/plugins/contrib/navbar/discussion.mdwn new file mode 100644 index 000000000..0bbec743c --- /dev/null +++ b/doc/plugins/contrib/navbar/discussion.mdwn @@ -0,0 +1,2 @@ +Where can I download this plugin ? +-- [[jogo]] diff --git a/doc/plugins/contrib/newpage.mdwn b/doc/plugins/contrib/newpage.mdwn new file mode 100644 index 000000000..54c2f53d0 --- /dev/null +++ b/doc/plugins/contrib/newpage.mdwn @@ -0,0 +1,29 @@ +[[!template id=plugin name=newpage author="[[rubykat]]"]] +[[!tag type/web]] +[[!toc]] +## NAME + +IkiWiki::Plugin::newpage - add a "create new page" form to actions + +## SYNOPSIS + + # activate the plugin + add_plugins => [qw{goodstuff newpage ....}], + +## DESCRIPTION + +This plugin adds a new action to the "ACTIONS" section of a page; +a button labelled "create" and an input field next to it. + +The common way of creating a new page is to edit a different page +and add a link to the new page. However, there are some situations +where that is a nuisance; for example, where pages are listed using +a [[plugins/map]] directive. The newpage plugin enables +one to simply type the name of the new page, click the "create" button, +and one is then taken to the standard IkiWiki create-page form. + +## DOWNLOAD + +* browse at GitHub: +* git repo at git://github.com/rubykat/ikiplugins.git + diff --git a/doc/plugins/contrib/newpage/discussion.mdwn b/doc/plugins/contrib/newpage/discussion.mdwn new file mode 100644 index 000000000..fb186463d --- /dev/null +++ b/doc/plugins/contrib/newpage/discussion.mdwn @@ -0,0 +1,10 @@ +How is this better than creating an inline with `rootpage` set, +which creates a similar new page form? I sometimes make the inline match +nothing, while still creating pages, in the odd cases where I have a map +or such displaying the pages. --[[Joey]] + +> I wanted something that would automatically be available on every page, but only when editing was enabled. +> One of the sites I maintain as webmaster () has a two-stage publication process. The "working" site is on an internal server, where it is set up as a wiki that authorized users in the company can edit. When they're satisfied with the changes they've made, the "working" site gets pushed (with git) to the "production" site, which is on a different server. The ikiwiki setup for the production site has editing completely disabled, because it is the site which is exposed to the outside world. +> For that site, I want all sign that it's a wiki to be hidden. Therefore using an inline directive would be unsuitable. + +> --[[KathrynAndersen]] diff --git a/doc/plugins/contrib/nimble.mdwn b/doc/plugins/contrib/nimble.mdwn new file mode 100644 index 000000000..29e2686e9 --- /dev/null +++ b/doc/plugins/contrib/nimble.mdwn @@ -0,0 +1,6 @@ +[[!template id=plugin name=nimble author="[[schmonz]]"]] +[[!template id=gitbranch branch=schmonz/nimble author="[[schmonz]]"]] +[[!tag type/format]] + +This plugin lets ikiwiki convert [Nimble](http://was.tl/projects/nimble/) +to HTML. diff --git a/doc/plugins/contrib/opml.mdwn b/doc/plugins/contrib/opml.mdwn new file mode 100644 index 000000000..3f98e8065 --- /dev/null +++ b/doc/plugins/contrib/opml.mdwn @@ -0,0 +1,11 @@ +[[!template id=plugin name=opml author="[[JanWalzer|jwalzer]]"]] +[[!tag type/format]] + +The idea of this plugin is to parse in an OPML-File and output a linklist, maybe some customization. +OPML-Files are xml-files that most RSS-Readers write out, to summarize their subscribes feedlist. + +I have a "dumb" perlscript running on my website, that tries to do a opml2mdwn transformation, but its quite bad on that. + +This Plugin is **NOT Ready** in any way. I'm just putting this page up as a hook, to discuss it. + +I intend to work on this, but I'd appreciate any help on this. diff --git a/doc/plugins/contrib/opml/discussion.mdwn b/doc/plugins/contrib/opml/discussion.mdwn new file mode 100644 index 000000000..3a145c79a --- /dev/null +++ b/doc/plugins/contrib/opml/discussion.mdwn @@ -0,0 +1,4 @@ +If this is the wrong place for the development of the plugin, please mode it on to a more appropriate one. + +Currently I'm quite stuck with the perl-stuff itself. I'm trying to become comfortable with the language, but it seems, the language doesn't like me. I'm lost in complex datastructures, when trying to iterate through the output of XML::Simple. --[[Jan|jwalzer]] + diff --git a/doc/plugins/contrib/pagespec_alias.mdwn b/doc/plugins/contrib/pagespec_alias.mdwn new file mode 100644 index 000000000..cb642ad33 --- /dev/null +++ b/doc/plugins/contrib/pagespec_alias.mdwn @@ -0,0 +1,28 @@ +[[!template id=plugin name=pagespec_alias author="[[Jon]]"]] +[[!tag type/meta]] + +The pagespec_alias plugin allows the administrator(s) of a wiki to define +[[PageSpec]] aliases: short names for PageSpecs to ease re-use. + +Within the setup file, the `pagespec_aliases` value is treated as a list +of key/value pairs. The keys define alias names, the values the pagespecs +to which they refer. + +For example: + + pagespec_aliases: + image: "*.png or *.jpg or *.jpeg or *.gif or *.ico" + helper: "*.css or *.js" + boring: "image() or helper() or internal(*)" + +With the above, you could use the pagespec aliases such as + + \[[!map pages="!boring()"]] + +To define a site map which excluded various page names which might be +uninteresting to include in a site map. + + +## Download + + * diff --git a/doc/plugins/contrib/pandoc.mdwn b/doc/plugins/contrib/pandoc.mdwn new file mode 100644 index 000000000..c93803605 --- /dev/null +++ b/doc/plugins/contrib/pandoc.mdwn @@ -0,0 +1,7 @@ +[[!template id=plugin name=pandoc author="profjim"]] + +This plugin enables Markdown processing using [Pandoc](http://johnmacfarlane.net/pandoc/). You can configure it for Pandoc to take over processing of all .mkdn files, or only files with a different extension. Given the features Pandoc has added over the past 6-12 months, this makes for a very powerful combination, e.g. with code block syntax highlighting and lots of options for how to process and display inline TeX. + +This is an expanded and updated version of [[Jason Blevin|users/jasonblevins]]'s pandoc plugin. Get it and see further details at . + +A version, merging enhancements in various forks is available at . PR are welcome. diff --git a/doc/plugins/contrib/parenttag.mdwn b/doc/plugins/contrib/parenttag.mdwn new file mode 100644 index 000000000..5dc01c7c5 --- /dev/null +++ b/doc/plugins/contrib/parenttag.mdwn @@ -0,0 +1,14 @@ +[[!meta author="spalax"]] +[[!template id=plugin name=parenttag author="[[Louis|spalax]]"]] +[[!tag type/tags]] + +This plugin deals with subtags (e.g. `mathematics/calculus`). Whenever a page is tagged, it is automatically tagged with its subtags as well: the following directives are equivalent: + + \[[!tag mathematics/calculus]] + \[[!tag mathematics mathematics/calculus]] + +The `taglink` directive is changed as well: instead of displaying the leaf of the tag, the full path (up to `tagbase` configuration option) is displayed, each bit linking to its corresponding page. For instance, directive `\[[!taglink mathematics/calculus]]` creates a link similar to `\[[TAGBASE/mathematics]]/\[[TAGBASE/mathematics/calculus]]`. + +## Code + +Code and documentation can be found here : [[https://atelier.gresille.org/projects/gresille-ikiwiki/wiki/Parenttag]]. diff --git a/doc/plugins/contrib/plusone.mdwn b/doc/plugins/contrib/plusone.mdwn new file mode 100644 index 000000000..a8d4c67fd --- /dev/null +++ b/doc/plugins/contrib/plusone.mdwn @@ -0,0 +1,35 @@ +[[!template id=plugin name=plusone author="[[BerndZeimetz]]"]] +[[!toc]] +[[!tag plugins]] [[!tag patch]] [[!tag wishlist]] + +## NAME + +IkiWiki::Plugin::plusone - Adding the +1 button to your posts + +## SYNOPSIS + + # activate the plugin + add_plugins => [qw{goodstuff plusone ....}], + + # set some options: + plusone_count => 1, + plusone_size => 'standard', + plusone_lang => 'en-US', + + +## DESCRIPTION + +This plugin allows to add a google plusone button using the plusone directive + [[!plusone ]] +where ever you want the button to show up. + +## plusone directive +The plusone directive allows to override the automativally generated url by specifying the wanted url as option: + [[!plusone url="http://bzed.de/"]] + + +## DOWNLOAD + +* single file: [plusone.pm](http://git.recluse.de/?p=users/bzed/ikiwiki.git;a=blob_plain;f=IkiWiki/Plugin/plusone.pm;hb=refs/heads/plusone) +* browse repository: +* git repo: `git://git.recluse.de/users/bzed/ikiwiki.git` or (Use the plusone branch) diff --git a/doc/plugins/contrib/pod.mdwn b/doc/plugins/contrib/pod.mdwn new file mode 100644 index 000000000..97a9c648a --- /dev/null +++ b/doc/plugins/contrib/pod.mdwn @@ -0,0 +1,38 @@ +[[!template id=plugin name=pod author="[[rubykat]]"]] +[[!tag type/format]] +## NAME + +IkiWiki::Plugin::pod - process pages written in POD format. + +## SYNOPSIS + +In the ikiwiki setup file, enable this plugin by adding it to the +list of active plugins. + + add_plugins => [qw{goodstuff pod ....}], + +## DESCRIPTION + +IkiWiki::Plugin::pod is an IkiWiki plugin enabling ikiwiki to +process pages written in POD ([Plain Old Documentation](http://en.wikipedia.org/wiki/Plain_Old_Documentation)) format. +This will treat files with a `.pod` or `.pm` extension as files +which contain POD markup. + +## OPTIONS + +The following options can be set in the ikiwiki setup file. + +* **pod_index:** If true, this will generate an index (table of contents) for the page. +* **pod_toplink:** The label to be used for links back to the top of the page. If this is empty, then no top-links will be generated. + +## PREREQUISITES + + IkiWiki + Pod::Xhtml + IO::String + +## DOWNLOAD + +* browse at GitHub: +* git repo at git://github.com/rubykat/ikiplugins.git + diff --git a/doc/plugins/contrib/pod/discussion.mdwn b/doc/plugins/contrib/pod/discussion.mdwn new file mode 100644 index 000000000..9187b1350 --- /dev/null +++ b/doc/plugins/contrib/pod/discussion.mdwn @@ -0,0 +1,14 @@ +My one concern about this plugin is the `=for` markup in POD. + +> Some format names that formatters currently are known to +> accept include "roff", "man", "latex", "tex", "text", and "html". + +I don't know which of these [[!cpan Pod::Xhtml]] supports. If it currently +supports, or later support latex, that could be problimatic since that +could maybe be used to include files or run code. --[[Joey]] + +> I don't know, either; the documentation for [[!cpan Pod:Xhtml]] is silent on this subject. --[[KathrynAndersen]] + +>> I'm afraid the only approach is to audit the existing code in the perl +>> module(s), and then hope nothing is added to them later that opens a +>> security hole. --[[Joey]] diff --git a/doc/plugins/contrib/poetry.mdwn b/doc/plugins/contrib/poetry.mdwn new file mode 100644 index 000000000..aed2e420a --- /dev/null +++ b/doc/plugins/contrib/poetry.mdwn @@ -0,0 +1,107 @@ +[[!meta author="spalax"]] +[[!template id=plugin name=poetry author="[[Louis|spalax]]"]] + +# Poetry + +The poetry plugin provides the [[ikiwiki/directive/poetry]] directive, used to +render poetry (or songs). + +## Why? + +### Typography + +In regular text, there are two different meaning of a new line: a break between +two paragraphs, and the line wrap. + +When rendering poetry, we need a third one: the carriage return between two +verse lines. This one should be different from the line wrap carriage return, +otherwise one will not be able to tell apart these two: is a word displayed at +the begenning of its line a new verse line, or the previous verse line, +continuing on a new line because it is too long? + +Generally, wrapped text is indented, whereas verse lines are not. + +### Markdown + +One could use carriage return (two white spaces at the end of a line) between +verse lines, and paragraph break between stanzas, but: + +* adding white spaces at the end of lines is painful; +* there is no easy way to render chorus (in a different way from verses). + +## Usage + +The directive takes only one argument `content`, containing the poetry to +render. Carriage returns are respected. + +Chorus are lines with `> ` as a starting character. + +Lines starting with `) ` are consored/outdated/crossed out verses. + +[[!toggle id=example text="View example"]] +[[!toggleable id=example text=''' + \[[!poetry content=""" + This is a verse + Made of several lines + + > And here is the chorus + > La la la! + > A beautiful chorus + + Another verse + A bit longer + Than the previous one + + ) This one is deleted + ) Because I did not like it + """]] +''']] + + +## CSS + +This plugin is useless without some corresponding CSS. An example is given +below. + +[[!toggle id=css text="CSS"]] +[[!toggleable id=css text=""" + .poetry { + padding-left: 1em; + border-left: 0.1em solid lightgray; + border-radius: 0.5em; + } + + .poetry .stanza { + padding-left: 1em; + } + + .poetry .paren { + font-style: italic; + font-size: smaller; + text-decoration: line-through; + } + + .poetry .paren:hover { + text-decoration: initial; + } + + .poetry .chorus { + margin-left: 0.1em; + padding-left: 2em; + border-left: 0.3em solid slategray; + } + + .poetry .line { + display: block; + text-indent: -1em; + } +"""]] + +## Example + +This plugin is used to render songs on [this choir's +website](http://barricades.int.eu.org/repertoire/bread_and_roses/). + +## Code + +Code and documentation can be found here : [[https://atelier.gresille.org/projects/gresille-ikiwiki/wiki/Poetry]]. diff --git a/doc/plugins/contrib/postal.mdwn b/doc/plugins/contrib/postal.mdwn new file mode 100644 index 000000000..c522f8bcb --- /dev/null +++ b/doc/plugins/contrib/postal.mdwn @@ -0,0 +1,35 @@ +[[!template id=plugin name=postal author="[[DavidBremner]]"]] +[[!tag type/special-purpose]] + +The `postal` plugin allows users to send mail to +a special address to comment on a page. It uses the [[mailbox]] +plugin to display their comments in the wiki. + +This plugin is not in ikiwiki yet, but can be downloaded +from + +Details: + + * Adds a mailto: url to each page matching some pagespec + (currently every page gets a comment footer) + + * This mailto url goes to an address identifying the page (something like + user-iki-blog~I\_hate\_markdown@host.fqdn.tld). + [more details](http://www.cs.unb.ca/~bremner/blog/posts/encoding) + + * on the mail receiving end, these messages are either deleted, or ran through + a filter to be turned into blog posts. I have +[written](http://pivot.cs.unb.ca/git/?p=ikipostal.git;a=blob_plain;f=filters/postal-accept.pl;hb=HEAD) + a filter that decodes the address and writes the message into an appropriate +mailbox. The changes are then checked into version control; typically a hook then updates the html version of the wiki. + * work in progress can be + + - [cloned](http://pivot.cs.unb.ca/git/ikipostal.git), or + - [browsed](http://pivot.cs.unb.ca/git/?p=ikipostal.git;a=summary) + + * I would be interested in any ideas people have about security. + +The current version of this plugin is now running on my home page. See for example +[a recent post in my blog](http://www.cs.unb.ca/~bremner/blog/posts/can-i-haz-a-distributed-rss/). +Unfortunately although the [[mailbox|todo/mbox]] renderer supports threading, I haven't had +a chance to implement comments on comments yet. --[[DavidBremner]] diff --git a/doc/plugins/contrib/postal/discussion.mdwn b/doc/plugins/contrib/postal/discussion.mdwn new file mode 100644 index 000000000..4eaacc044 --- /dev/null +++ b/doc/plugins/contrib/postal/discussion.mdwn @@ -0,0 +1,24 @@ +It seems like the filter 'postal-accept.pl' I wrote doesn't refresh thoroughly enough. When a comment is added it calls + + IkiWiki::add_depends($page,$comments_page); + +And then after adding the actual comment, it ends with + + IkiWiki::refresh(); + IkiWiki::saveindex(); + +Sure enough, the page being commented on is refreshed, but not any inline pages (e.g. tags pages, blog top level) that contain it. +Is there a way to recursively refresh? Or should it work that way by default. I guess it is some part of the api that I don't understand, +since I think not many people grub about in the internals of ikiwiki this way. +It would be nice to figure this out, doing a full rebuild every time I get a blog comment is not that fun. + +[[DavidBremner]] + +> Ikiwiki currently doesn't have support for transitive dependencies. +> This is discussed deep inside [[todo/tracking_bugs_with_dependencies]] +> and in [[todo/inlines_inheriting_links]]. +> +> FYI, the [[plugins/comments]] plugin avoids this problem by only showing the +> comments on the page, and not on pages that inline it. --[[Joey]] +>> Ok, thanks for the speedy response. I guess I should do the same thing. +>> [[DavidBremner]] diff --git a/doc/plugins/contrib/purge.mdwn b/doc/plugins/contrib/purge.mdwn new file mode 100644 index 000000000..62fcfb30d --- /dev/null +++ b/doc/plugins/contrib/purge.mdwn @@ -0,0 +1,38 @@ +[[!template id=plugin name=purge core=0 author="[[users/ssm]]"]] + +IkiWiki plugin to send PURGE requests to remote http cache server (like Varnish Cache) when your content changes. + +PURGE requests are sent for the changed page, as well as all pages indirectly changed when ikiwiki rebuilds the web pages. + +# Download + +Download from [Github](https://github.com/ssm/ikiwiki-plugin-purge) + +# Configure ikiwiki + + # purge_url (mandatory), the address of your cache server. + purge_url: http://example.com/ + + # purge_timeout (optional, default 5) timeout in seconds for a purge request. + + # purge_method (optional, default "PURGE") HTTP method to use. + +# Configure your cache server + +For Varnish, you'll need to add a handler for the non-standard "PURGE" method, and preferrably an ACL which restricts who can send these requests to empty your cache. + + acl origin_server { + "localhost"; + "192.0.2.0"/24; + "2001:db8::"/64; + } + + sub vcl_recv { + if (req.method == "PURGE") { + if (!client.ip ~ origin_server) { + return(synth(405,"Not allowed.")); + } + return (purge); + } + } + diff --git a/doc/plugins/contrib/report.mdwn b/doc/plugins/contrib/report.mdwn new file mode 100644 index 000000000..0bd5392c6 --- /dev/null +++ b/doc/plugins/contrib/report.mdwn @@ -0,0 +1,26 @@ +[[!template id=plugin name=report author="[[rubykat]]"]] +[[!tag type/meta type/format]] +IkiWiki::Plugin::report - Produce templated reports from page field data. + +This plugin provides the [[ikiwiki/directive/report]] directive. This enables +one to report on the structured data ("field" values) of multiple pages; the +output is formatted via a template. This depends on the +[[plugins/contrib/field]] plugin. + + +## Activate the plugin + + # activate the plugin + add_plugins => [qw{goodstuff report ....}], + +## PREREQUISITES + + IkiWiki + IkiWiki::Plugin::field + HTML::Template + Encode + +## DOWNLOAD + +* browse at GitHub: +* git repo at git://github.com/rubykat/ikiplugins.git diff --git a/doc/plugins/contrib/report/discussion.mdwn b/doc/plugins/contrib/report/discussion.mdwn new file mode 100644 index 000000000..419c4bca6 --- /dev/null +++ b/doc/plugins/contrib/report/discussion.mdwn @@ -0,0 +1,80 @@ +Wow, this plugin does a lot... it seems to be `inline` (but without the feeds +or the ability to not have `archive="yes"`), plus part of +[[plugins/contrib/trail]], plus some sorting, plus an ingenious workaround +for template evaluation being relatively stateless. + +A large part of this plugin would just fall off if one of the versions of +"[[todo/allow_plugins_to_add_sorting_methods]]" was merged, which was a +large part of the idea of that feature request :-) To make use of that +you'd have to use `pagespec_match_list` in the trail case too, but that's +easy enough - just add `list => [@the_trail_pages]` to the arguments. + +Another large part would fall off if this plugin required, and internally +invoked, `inline` (like my `comments` plugin does) - `inline` runs +`pagetemplate` hooks, and in particular, it'll run the `field` hook. +Alternatively, this plugin could invoke `pagetemplate` hooks itself, +removing the special case for `field`. + +Perhaps the `headers` thing could migrate into inline somehow? That might +lead to making inline too big, though. + +> I think inline is *already* too big, honestly. --[[KathrynAndersen]] + +>> A fair point; perhaps my complaint should be that *inline* does +>> too many orthogonal things. I suppose the headers feature wouldn't +>> really make sense in an inline that didn't have `archive="yes"`, +>> so it'd make sense to recommend this plugin as a replacement +>> for inlining with archive=yes (for which I now realise "inline" +>> is the wrong verb anyway :-) ) --s + +>>> I think *inline* would be a bit less unwieldy if there was some way of factoring out the feed stuff into a separate plugin, but I don't know if that's possible. --K.A. + +Is the intention that the `trail` part is a performance hack, or a way +to select pages? How does it relate to [[todo/wikitrails]] or +[[plugins/contrib/trail]]? --[[smcv]] + +> The `trail` part is *both* a performance hack, and a way to select pages. I have over 5000 pages on my site, I need all the performance hacks I can get. +> For the performance hack, it is a way of reducing the need to iterate through every single page in the wiki in order to find matching pages. +> For the way-to-select-pages, yes, it is intended to be similar to [[todo/wikitrails]] and [[plugins/contrib/trail]] (and will be more similar with the new release which will be happening soon; it will add prev_* and next_* variables). +> The idea is that, rather than having to add special "trail" links on PageA to indicate that a page is part of the trail, +> it takes advantage of the `%links` hash, which already contains, for each page, an array of the links from that page to other pages. No need for special markup, just use what's there; a trail is defined as "all the pages linked to from page X", and since it's an array, it has an order already. +> But to avoid that being too limiting, one can use a `pages=...` pagespec to filter that list to a subset; only the pages one is interested in. +> And one can also sort it, if one so desires. +> --[[KathrynAndersen]] + +>> That's an interesting approach to trails; I'd missed the fact that +>> links are already ordered. +>> +>> This does have the same problems as tags, though: see +>> [[bugs/tagged()_matching_wikilinks]] and +>> [[todo/matching_different_kinds_of_links]]. I suppose the question +>> now is whether new code should be consistent with `tag` (and +>> potentially be fixed at the same time as tag itself), or try to +>> avoid those problems? +>> +>> The combination of `trail` with another pagespec in this plugin +>> does provide a neat way for it to work around having unwanted +>> pages in the report, by limiting by a suitable tag or subdirectory +>> or something. --s + +>>> Either that, or somehow combine tagging with fields, such that one could declare a tag, and it would create both a link and a field with a given value. (I've been working on something like that, but it still has bugs). +>>> That way, the test for whether something is tagged would be something like "link(tag/foo) and field(tag foo)". +>>> --K.A. + +>>>> I can see that this'd work well for 1:1 relationships like next +>>>> and previous, but I don't think that'd work for pages with more than +>>>> one tag - as far as I can see, `field`'s data model is that each +>>>> page has no more than one value for each field? +>>>> [[todo/Matching_different_kinds_of_links]] has some thoughts about +>>>> how it could be implemented, though. --s + +>>>>> You have a point there. I'm not sure what would be better: to add the concept of arrays/sets to `field`, or to think of tags as a special case. Problem is, I find tags as they currently exist to be too limiting. I prefer something that can be used for Faceted Tagging ; that is, things like Author:Fred Nurk, Genre:Historical, Rating:Good, and so on. Of course, that doesn't mean that each tag is limited to only one value, either; just to take the above examples, something might have more than one author, or have multiple genres (such as Historical + Romance). + +>>>>> It might be that adding arrays to the `field` plugin is a good way to go: after all, even though field=value is the most common, with the flexibility of things like YAML, one could define all sorts of things. What I'm not so sure about is how to return the values when queried, since some things would be expecting scalars all the time. Ah, perhaps I could use wantarray? +>>>>> Is there a way of checking a HTML::Template template to see if it expecting an array for a particular value? +>>>>> --[[KathrynAndersen]] + +How about arrays? +----------------- + +In [[plugins/contrib/getfield/discussion]], I outline how there's a problem in getfield displaying array refs when the data is a YAML array. I also propose a patch there so that arrays are join'd with a space separator, which is less than ideal, but at least works for getfield. However, for report, I am not sure it's as good. Should it make two rows for those? How should we parse this? Thanks. -- [[anarcat]] diff --git a/doc/plugins/contrib/report/ikiwiki/directive/report.mdwn b/doc/plugins/contrib/report/ikiwiki/directive/report.mdwn new file mode 100644 index 000000000..4a740f97f --- /dev/null +++ b/doc/plugins/contrib/report/ikiwiki/directive/report.mdwn @@ -0,0 +1,175 @@ +[[!toc]] +The `report` directive is supplied by the [[!iki plugins/contrib/report desc=report]] plugin. + +This enables one to report on the structured data ("field" values) of +multiple pages; the output is formatted via a template. This depends +on the [[plugins/contrib/field]] plugin. + +The pages to report on are selected by a PageSpec given by the "pages" +parameter. The template is given by the "template" parameter. +The template expects the data from a single page; it is applied +to each matching page separately, one after the other. + +Additional parameters can be used to fill out the template, in +addition to the "field" values. Passed-in values override the +"field" values. + +There are two places where template files can live. One is in the +/templates directory on the wiki. These templates are wiki pages, and +can be edited from the web like other wiki pages. + +The second place where template files can live is in the global +templates directory (the same place where the page.tmpl template lives). +This is a useful place to put template files if you want to prevent +them being edited from the web, and you don't want to have to make +them work as wiki pages. + +## OPTIONS + +**template**: The template to use for the report. + +**pages**: A PageSpec to determine the pages to report on. + +**pagenames**: If given instead of pages, this is interpreted as a +space-separated list of links to pages, and they are shown in exactly the order +given: the sort and pages parameters cannot be used in conjunction with this +one. If they are used, they will be ignored. + +**trail**: A page or pages to use as a "trail" page. + +When a trail page is used, the matching pages are limited to (a subset +of) the pages which that page links to; the "pages" pagespec in this +case, rather than selecting pages from the entire wiki, will select +pages from within the set of pages given by the trail page. + +Additional space-separated trail pages can be given in this option. +For example: + + trail="animals/cats animals/dogs" + +This will take the links from both the "animals/cats" page and the +"animals/dogs" page as the set of pages to apply the PageSpec to. + +**start**: Start the report at the given page-index; the index starts +from zero. + +**count**: Report only on N pages where count=N. + +**sort**: A SortSpec to determine how the matching pages should be sorted. + +**here_only**: Report on the current page only. + +This is useful in combination with "prev_" and "next_" variables to +make a navigation trail. +If the current page doesn't match the pagespec, then no pages will +be reported on. + +### Headers + +An additional option is the "headers" option. This is a space-separated +list of field names which are to be used as headers in the report. This +is a way of getting around one of the limitations of HTML::Template, that +is, not being able to do tests such as +"if this-header is not equal to previous-header". + +Instead, that logic is performed inside the plugin. The template is +given parameters "HEADER1", "HEADER2" and so on, for each header. +If the value of a header field is the same as the previous value, +then HEADER**N** is set to be empty, but if the value of the header +field is new, then HEADER**N** is given that value. + +#### Example + +Suppose you're writing a blog in which you record "moods", and you +want to display your blog posts by mood. + + \[[!report template="mood_summary" + pages="blog/*" + sort="Mood Date title" + headers="Mood"]] + +The "mood_summary" template might be like this: + + + ## + + ### + () \[[]] + + +### Multi-page Reports + +Reports can now be split over multiple pages, so that there aren't +too many items per report-page. + +**per_page**: how many items to show per report-page. + +**first_page_is_index**: If true, the first page of the report is just +an index which contains links to the other report pages. +If false, the first page will contain report-content as well as links +to the other pages. + +### Advanced Options + +The following options are used to improve efficiency when dealing +with large numbers of pages; most people probably won't need them. + +**maketrail**: + +Make a trail; if true, then this report is called in "scan" mode and the +pages which match the pagespec are added to the list of links from this +page. This can be used by *another* report by setting this page to be a +"trail" page in *that* report. + +It is not possible to use "trail" and "maketrail" at the same time. +By default, "maketrail" is false. + +## TEMPLATE PARAMETERS + +The templates are in HTML::Template format, just as [[plugins/template]] and +[[ftemplate]] are. The parameters passed in to the template are as follows: + +### Fields + +The structured data from the current matching page. This includes +"title" and "description" if they are defined. + +### Common values + +Values known for all pages: + +* page (the current page) +* destpage (the destination page) +* basename (the base name of the page) +* recno (N if the page is the Nth page in the report) + +### Prev_Page And Next_Page + +The "prev_page" and "next_page" variables will give the value of the +previous page in the matching pages, or the next page in the matching pages. +This is mainly useful for a "here_only" report. + +### Passed-in values + +Any additional parameters to the report directive are passed to the +template; a parameter will override the matching "field" value. +For example, if you have a "Mood" field, and you pass Mood="bad" to +the report, then that will be the Mood which is given for the whole +report. + +Generally this is useful if one wishes to make a more generic +template and hide or show portions of it depending on what +values are passed in the report directive call. + +For example, one could have a "hide_mood" parameter which would hide +the "Mood" section of your template when it is true, which one could +use when the Mood is one of the headers. + +### Headers + +See the section on Headers. + +### First and Last + +If this is the first page-record in the report, then "first" is true. +If this is the last page-record in the report, then "last" is true. diff --git a/doc/plugins/contrib/sar.mdwn b/doc/plugins/contrib/sar.mdwn new file mode 100644 index 000000000..77c41a955 --- /dev/null +++ b/doc/plugins/contrib/sar.mdwn @@ -0,0 +1,109 @@ +[[!template id=plugin name=sar author="[[VictorMoral]]"]] +[[!tag type/chrome type/slow ]] + +The `sar` plugin is useful to make global or local search and replace operations +using common or specific terms. + +The characteristics are: + +- Support for a global dictionary page (optional but recommended). +- Is possible to replace the first appearance with a text and the rest with +other. + +The global dictionary page is like this: + + ## Sites and projects + + - [[!sar search="ikiwiki" first="[IkiWiki](http://ikiwiki.info)" next="_IkiWiki_"]] + - [[!sar search="debian" first="[Debian](http://debian.org)" next="_Debian_"]] + - [[!sar search="perl" first="[Perl](http://perl.org)" next="_Perl_"]] + - [[!sar search="linux" replace="GNU/Linux"]] + + ## Persons + - [[!sar search="joey" first="[Joey Hess](http://ikiwiki.info/users/joey]]" next="_Joey_" ]] + - [[!sar search="angel" first="[Angel](http://triptico.com)" next="Angel"]] + + ## Technical terms + + - [[!sar search="smtp" first="\[[!wp SMTP]]" next="‘SMTP‘"]] + - [[!sar search="pop3" first="\[[!wp POP3]]" next="’POP3’"]] + +The search expressions must be surrounded by double dashes in a source ikiwiki +page, like this: + + Mis programas están escritos en lenguaje --perl--, funcionando con el + sistema --debian--, y mis páginas web funcionan con --ikiwiki-- cuyo autor + es --joey--. + + --ikiwiki-- es un buen software. + +After a filter operation the content is: + + Mis programas están escritos en lenguaje [Perl](http://perl.org), + funcionando con el sistema [Debian](http://debian.org), y mis páginas web + funcionan con [IkiWiki](http://ikiwiki.info) cuyo autor es [Joey + Hess](http://ikiwiki.info/users/joey). + + _IkiWiki_ es un buen software. + +_Note_: I chose this syntax because don't clashes with markdown and it is easy to write. + +A _search and replace_ directive has the following parameters: + +- `search`: define the text to search. +- `first`: define the replace text in the first match. +- `next`: define the replace text in all matches except the first. +- `replace`: define the replace text in all matches. + +Now the code is used at my site without problems, and the author will +appreciate any help with his development or his english. + +## Configuration + +The plugin need the following global values: + +- `sar_mainpage`: define the global dictionary page. The default value is `sar`. +- `sar_pagespec`: enable the plugin with a selection of pages. The default +value is `*`, but a recommended value is `link(tag/sar)`. + +## Synopsis + +In a ikiwiki source page we can write this + + \[[!sar search=debian replace="__Debian__"]] + +for define a global replace for the term `--debian--` or + + \[[!sar search=ibm first=’[IBM](http://www.ibm.com)’ + next="_IBM_"]] + +to define a replace for the first match of the string `--ibm--` and a different +replace for the rest. + +## Changelog + +### version 0.8 + +- First functional version with the new sar expressions. + +### version 0.7 + +- New design for the search expressions. + +### version 0.6 + +- Minor bugfixes in the pages selection. +- Call to add_depends() for every page filtered + +### version 0.5 + +- This is the first functional version. + +## Download + +The module can be downloaded from: + +- [My personal site](http://taquiones.net/files/misc) +- [My personal Debian repository](http://taquiones.net/files/debian) + + diff --git a/doc/plugins/contrib/screenplay.pm.mdwn b/doc/plugins/contrib/screenplay.pm.mdwn new file mode 100644 index 000000000..5ff082da5 --- /dev/null +++ b/doc/plugins/contrib/screenplay.pm.mdwn @@ -0,0 +1,320 @@ +This plugin works for me. It follows the standard for a movie screenplay pretty closely, I am not aware of any errors in format. Please let me know if you find any. + +Right now all it does is display your pages properly in a web browser. What I would like to add is the ability to output a file that could easily be printed once the screenplay is finished. We keep all the scenes we work on in one folder and eventually we will want to print a script out of that folder. It would be great if an up to date PDF or TXT script could be put in the folder when a scene is saved. I will do it, it just isn't a priority yet. + +I am not a published writer and not an authority on script formatting. I got what I know out of a book. + +Briefly, you type a command on a line, like ".d", then on the next line (for the dialog command) you type a person's name. Then you hit return again and write the words he is supposed to speak out all on one line. When you save your document this simple text will become a properly formatted script. + +Thank you Joey for having me here. + +###Headings: + Most headings should begin with a transition. The list of valid commands is: + .fi => FADE IN: a gradual transition from a solid color to an image + .fo => FADE OUT. + .ftb => FADE TO BLACK. + .ftw => FADE TO WHITE. + .ct => CUT TO: indicates an instantaneous shift from one shot to the next + .shot => lack of an explicit transition assumes a cut + .hct => HARD CUT TO: describes a jarring transition + .qct => QUICK CUT TO: describes a cut sooner than expected + .tct => TIME CUT TO: emphasizes time passing + .mct => MATCH CUT TO: image in first shot visually or thematically matches image in second + .dt => DISSOLVE TO: gradual transition from image to another implies passage of time. + .rdt => RIPPLE DISSOLVE TO: indicates transition into daydream or imagination + .wt => WIPE TO: new image slides over top of last one + + Example transition: + + .fi (or any transition command) <= Writes a transition line, except .shot which omits it. + type shot heading here <= this line will be capitalized + First direction. <= these lines are not capitalized. + Second direction. + Third direction, etc... + + Direction without a shot heading: + .dir + First direction. + Second direction. + Third direction, etc... + + Some items aren't implemented in dialogue yet: + 1) you must watch that you don't leave a " -- " dangling on a line by itself, + instead, carry the last word onto the line with a dash + 2) observe lyrical line endings in dialogue by indenting wrapped lines by two spaces + 3) you must watch that the four line limit for parenthetical direction is not exceeded + + Example dialogue: + + .d + char name <= this line will be capitalized + this is what he's saying <= Dialogue + raises hand to wave <= Parenthetical direction + this is more of what he's saying <= Dialogue + this is going to be in parenthesis <= Parenthetical direction + this is more of what he's saying, etc... <= Dialogue + + .note + Allows you to add a temporary note to a script without getting an error. + All notes need to be removed eventually because they are a format violation. + + + + ###name this file screenplay.pm and pop it in your Plugin folder. Then you need to add the plugin to your Ikiwiki setup file. + + #!/usr/bin/perl + # Screenplay markup language + package IkiWiki::Plugin::screenplay; + + use warnings; + use strict; + use IkiWiki 3.00; + use Text::Format; + use Log::Log4perl qw(:easy); + Log::Log4perl->easy_init($INFO); + #Log::Log4perl->easy_init($ERROR); + + sub import { + hook(type => "getsetup", id => "screenplay", call => \&getsetup); + hook(type => "htmlize", id => "screenplay", call => \&htmlize, longname => "Screenplay"); + } + + sub getsetup () { + return + plugin => { + safe => 1, + rebuild => 1, # format plugin + section => "format", + }, + } + + sub htmlize (@) { + #set up variables and fill with defaults + my %params=@_; + my $content = $params{content}; + my @lines = split(/\r\n|\r|\n/, $content); + my @chunk; + my @formatted; + my $current_line = shift(@lines); + my $current_command = ""; + my $current_chunk = ""; + + while (scalar(@lines) > 0) { + until ( &dot_command($current_line) || scalar(@lines) == 0 ) { + #skip spaces; mark bad lines + unless ( &blank_line($current_line) ) { + push(@formatted, "
"); + push(@formatted, &no_command($current_line)); + } + $current_line = shift(@lines); + } + + #Exit while loop if we're out of lines + last if (scalar(@lines) == 0); + + #set command for chunk + $current_command = $current_line; + $current_line = shift(@lines); + + #get chunk, i.e. all text up to next blank line or a dot command. + until (substr($current_line,0,1) eq '.' || $current_line =~ m// || $current_line =~ m/^\s*$/) { + push(@chunk,$current_line); + $current_line = shift(@lines); + last unless defined $current_line; + } + + #Start with a blank line unless unneeded. + if (scalar(@formatted) > 0 ) { + push(@formatted, "
"); + } + + #remaining lines are not commands. + if (scalar(@chunk)) { + $current_chunk = shift(@chunk); + if ($current_command eq ".shot") { + push(@formatted, &indent(&chunk(uc($current_chunk),57),17)); + while (scalar(@chunk)) { + $current_chunk = shift(@chunk); + push(@formatted, "
"); + push(@formatted, &indent(&chunk($current_chunk,57),17)); + } + + } elsif ($current_command eq ".note") { + push(@formatted, "NOTE:
"); + push(@formatted, &chunk($current_chunk,75)); + while (scalar(@chunk)) { + $current_chunk = shift(@chunk); + push(@formatted, "
"); + push(@formatted, &chunk($current_chunk,75)); + } + + } elsif ($current_command eq ".dir") { + push(@formatted, &indent(&chunk($current_chunk,57),17)); + while (scalar(@chunk)) { + $current_chunk = shift(@chunk); + push(@formatted, "
"); + push(@formatted, &indent(&chunk($current_chunk,57),17)); + } + + } elsif ($current_command eq ".d") { + push(@formatted, &indent(&chunk(uc($current_chunk),32),41)); + $current_chunk = shift(@chunk); + push(@formatted, &indent(&chunk($current_chunk,34),27)); + while (scalar(@chunk) / 2 >= 1 ) { + $current_chunk = shift(@chunk); + push(@formatted, &indent(&chunk(&pd($current_chunk),19),34)); + $current_chunk = shift(@chunk); + push(@formatted, &indent(&chunk($current_chunk,34),27)); + } + + } elsif ($current_command eq ".pd") { + push(@formatted, &indent(&chunk(uc($current_chunk),32),41)); + $current_chunk = shift(@chunk); + push(@formatted, &indent(&chunk(&pd($current_chunk),19),34)); + $current_chunk = shift(@chunk); + push(@formatted, &indent(&chunk($current_chunk,34),27)); + while (scalar(@chunk) / 2 >= 1 ) { + $current_chunk = shift(@chunk); + push(@formatted, &indent(&chunk(&pd($current_chunk),19),34)); + $current_chunk = shift(@chunk); + push(@formatted, &indent(&chunk($current_chunk,34),27)); + } + + } elsif ($current_command =~ m/^\.(fi|fo|ct|hct|qct|tct|mct|dt|rdt)$/) { + if ($current_command eq ".fi") { + push(@formatted, &indent(&chunk(uc("FADE IN:"),20),17)); + } elsif ($current_command eq ".fo") { + push(@formatted, &indent(&chunk(uc("FADE OUT:"),20),60)); + } elsif ($current_command eq ".ct") { + push(@formatted, &indent(&chunk(uc("CUT TO:"),20),60)); + } elsif ($current_command eq ".hct") { + push(@formatted, &indent(&chunk(uc("HARD CUT TO:"),20),60)); + } elsif ($current_command eq ".qct") { + push(@formatted, &indent(&chunk(uc("QUICK CUT TO:"),20),60)); + } elsif ($current_command eq ".tct") { + push(@formatted, &indent(&chunk(uc("TIME CUT TO:"),20),60)); + } elsif ($current_command eq ".mct") { + push(@formatted, &indent(&chunk(uc("MATCH CUT TO:"),20),60)); + } elsif ($current_command eq ".dt") { + push(@formatted, &indent(&chunk(uc("DISSOLVE TO:"),20),60)); + } elsif ($current_command eq ".rdt") { + push(@formatted, &indent(&chunk(uc("RIPPLE DISSOLVE TO:"),20),60)); + } elsif ($current_command eq ".wt") { + push(@formatted, &indent(&chunk(uc("WIPE TO:"),20),60)); + } + push(@formatted, &indent(&chunk(uc($current_chunk),57),17)); + while (scalar(@chunk)) { + $current_chunk = shift(@chunk); + push(@formatted, "
"); + push(@formatted, &indent(&chunk($current_chunk,57),17)); + } + + } + #mark the rest of the chunk as 'no command' + if (scalar(@chunk)) { + $current_chunk = shift(@chunk); + push(@formatted, &no_command($current_chunk)); + } + + } + } + my @content; + my $i = 0; + $current_line = ""; + while (scalar(@formatted)) { + $i++; + $current_line = shift(@formatted); + if ( $i % 60 == 0 ) { + push(@content, &indent($i/60 . ".
",72) ); + } + push(@content, $current_line); + } + $content = join("\r\n",@content); + return $content; + } + + sub blank_line { + my $line = shift(@_); + my $ret = 0; + + if ($line =~ m// || $line =~ m/^\s*$/) { + $ret = 1; + } else { + $ret = 0; + } + + return $ret; + } + + sub chunk () { + my $unchunked = shift(@_); + my $columns = shift(@_); + my $text = new Text::Format; + $text->rightFill(1); + $text->columns($columns); + $text->firstIndent(0); + $text->tabstop(0); + $text->extraSpace(1); + my @chunked = split /\n/, $text->format($unchunked); + my @formatted; + foreach (@chunked) { + push(@formatted, $_ . "
"); + } + return @formatted; + } + + sub dot_command { + my $line = shift(@_); + my $ret = 0; + + if ($line =~ m/^\.(ct|dir|dt|d|fi|fo|hct|mct|note|pd|qct|rdt|shot|tct)$/) { + $ret = 1; + } else { + $ret = 0; + } + + return $ret; + } + + sub indent () { + my @unindented = @_; + my $spaces = pop @unindented; + my @indented; + foreach (@unindented) { + push(@indented, " " x $spaces . $_); + } + return @indented; + } + + sub no_command () { + my $line = shift(@_); + my $text = new Text::Format; + $text->rightFill(1); + $text->columns(68); + $text->firstIndent(0); + $text->tabstop(0); + $text->extraSpace(1); + my @chunked = split /\n/, $text->format($line); + my @formatted; + push(@formatted, ("NO COMMAND: ")); + foreach (@chunked) { + push(@formatted, ( $_ . "
" )); + } + return @formatted; + } + + sub pd () { + my @chunk = @_; + # add '(' to top item + my $line = "(" . shift(@chunk); + unshift(@chunk, $line); + + # add ')' to bottom item + $line = pop(@chunk) . ")"; + push(@chunk, $line); + + return @chunk; + } + + 1 + diff --git a/doc/plugins/contrib/sidebar2.mdwn b/doc/plugins/contrib/sidebar2.mdwn new file mode 100644 index 000000000..5c169bfd4 --- /dev/null +++ b/doc/plugins/contrib/sidebar2.mdwn @@ -0,0 +1,96 @@ +[[!meta author="spalax"]] +[[!template id=plugin name=sidebar2 author="[[Louis|spalax]]"]] +[[!tag type/chrome]] + +*Claim:* The [[sidebar|plugins/sidebar]] plugin has nothing +to do with sidebars. This plugin renders some page (which happens to be named +`sidebar`) and put the result in template variable `SIDEBAR` of template +`page.tmpl`. But the fact that it is a sidebar, i.e. a bar appearing on the +side on the screen, is done by CSS. + +What if I want a sidebar, and a [[navigation bar|plugins/contrib/navbar]], and +a footer a bit more elaborated than the one in the template, etc.? This plugin +allows this. + +# Configuration + +If no option is given, or if option `global_sidebars` is a boolean, this plugin +is identical to the [[sidebar plugin|plugins/sidebar/]] (if not, please [report +a bug](https://atelier.gresille.org/projects/gresille-ikiwiki/issues)). +Otherwise, `global_sidebars` is a list of sidebars to include. The list is as +follow: + + global_sidebars => [ + "var1", "page1", "pagespec1", + "var2", "page2", "pagespec2", + ] + +The meaning is: if available, render `page1` in pages matching `pagespec1`, and +put it in variable `var1` of the page template, and so on for `var2`, `page2`, +etc. + +The default, which gives the behaviour of the sidebar plugin, is +`global_sidebars => ["sidebar", "sidebar", "*"]`. + +*Remark: It would be more sensible to have a list of lists, as the following example, but I did not manage to do so because of [[this bug|bugs/structured_config_data_is_mangled]].* + + global_sidebars => [ + ["var1", "page1", "pagespec1"], + ["var2", "page2", "pagespec2"], + ] + +# Improvements over sidebar plugin + +* You can add several "sidebars" to your wiki. For example, to have a sidebar, a submenu that appears only in documentation pages (`doc/*`), and a footer, your `global_sidebars` would be: + + global_sidebars => [ + "sidebar", "sidebar", "*", + "menu", "/doc/menu", "doc/*", + "footer", "/footer", "*" + ] + +* You can enable sidebars only in certain pages matching the pagespec. If, for + the same template variable, several pagespec match the current page, the + first page in the list is taken into account. + + For example, the following configuration says: render `menu` as the sidebar + for every page, excepted subpages of `doc`, for which the `doc_menu` page + should be rendered. + + global_sidebars => [ + "sidebar", "doc_menu", "doc/*", + "sidebar", "menu", "*", + ] + +# Directive + +The behaviour of the `sidebar` directive is similar to the directive of the +original [[sidebar|plugins/sidebar]], excepted that a new `var` argument is +available. + +If this `var` argument is set, instead of applying to the default `sidebar` +template variable, the directive applies to the value given in the argument. + +For example, the following command forces the `footer` sidebar to appear on the +current page. + + \[[!sidebar var=footer]] + +The following command forces the `footer` sidebar to appaer, containing the +content given in argument. + + \[[!sidebar var=footer content="TEST"]] + +# Which pages to render? + +Here is the decision process to decide what is rendered in a template variable +handled by this plugin. + +1. If the page contains the [[sidebar|ikiwiki/directive/sidebar]] directive, with a `content` argument, this content is rendered. +2. If the page contains the [[sidebar|ikiwiki/directive/sidebar]] directive with no `content` argument, the first rule for the considered template variable is applied, disregarding the pagespec. +3. If none of the above, the first rule having its pagespec patching the current page is applied. +4. If none of the above, the variable is left empty. + +# Download and install + +Code and documentation: [[https://atelier.gresille.org/projects/gresille-ikiwiki/wiki/Sidebar2]]. diff --git a/doc/plugins/contrib/siterel2pagerel.mdwn b/doc/plugins/contrib/siterel2pagerel.mdwn new file mode 100644 index 000000000..9b09657bf --- /dev/null +++ b/doc/plugins/contrib/siterel2pagerel.mdwn @@ -0,0 +1,30 @@ +[[!template id=plugin name=siterel2pagerel author="[[PaulWise]]"]] + +This is a simple plugin to convert all site-relative links to page-relative +links (converts /foo into ../../../foo or similar). It works as a +postprocessing filter, allowing it to work on mdwn, wiki, html, rst and any +other format that produces html. The code is available here: + + #!/usr/bin/perl + # quick HTML siterel2pagerel link hack by Paul Wise + package IkiWiki::Plugin::siterel2pagerel; + + use warnings; + use strict; + use IkiWiki 2.00; + + sub import { + hook(type => "sanitize", id => "siterel2pagerel", call => \&siterel2pagerel); + } + + sub siterel2pagerel (@) { + my %params=@_; + my $baseurl=IkiWiki::baseurl($params{page}); + my $content=$params{content}; + $content=~s/("foo,bar"` in your setup file. +where foo and bar are the (source-supported) languages you want to +highlight +### Issues + +- I would like to have a link to the raw source; using will_render() and then copying the file should work. + +> You might also like to look at the [[todo/source_link]] todo. -- [[Will]] + +- Is there a way to configure the colors used by source-highlight (other than editing the globally installed "default.style" file)? It would help if I could pass the command arbitrary command-line arguments; then I could configure which config file it's supposed to use. For instance, I'm not a fan of hard-coding the colors into the HTML output. IMHO, css-style formatting should be preferred. All that can be set via the command line ... --Peter + +> I don't really have time right now, but it should be easy to add, if you look at how src-lang is handled. Patches are welcome :-) --[[DavidBremner]] + +Note that [[Will]] wrote a plugin that uses source-highlight also. It's +available +[[here|todo/automatic_use_of_syntax_plugin_on_source_code_files/discussion]]. +--[[Joey]] + +To be honest, [[Will]]'s version of this looks more polished. I will try his +plugin and see if it can just replace mine. --[[DavidBremner]] + + +*Updated* Now uses keepextension so multiple extensions should be OK diff --git a/doc/plugins/contrib/syntax.mdwn b/doc/plugins/contrib/syntax.mdwn new file mode 100644 index 000000000..da4213000 --- /dev/null +++ b/doc/plugins/contrib/syntax.mdwn @@ -0,0 +1,65 @@ +[[!template id=plugin name=syntax author="[[VictorMoral]]"]] +[[!tag type/chrome type/slow]] + +The `syntax` plugin adds support to ikiwiki for syntax highlighting through the *vim* editor and its perl interface [[!cpan Text::VimColor]]. It depends on a functional vim installation. + +The plugin inserts a fragment of HTML with special marks from a file or a string text. It accepts the following parameters: + +* **type** (optional): this is the file type for vim syntax highlighthing. It can be omitted if the param *file* exists. +* **file**: Path to the source file. It must exist on every rebuild of the wiki. +* **text**: Text string with the source. +* **description** (optional): little description about the content. +* **linenumbers** (optional): enable the line numering of the source page. A value greater than zero is the first line number. + +The params *file* and *text* are mutually exclusive. + +In the case of file parameter, `syntax` will build a html link for direct download. + +Example: + + \[[!syntax type="perl" text=""" + #!/usr/bin/perl + + my $a = "World"; + print "Hello, ${a}\n"; + """]] + +or + + \[[!syntax file="/examples/hello.pl" description="My first perl program"]] + +This plugin create the following CSS styles: + +* syntax +* synComment +* synConstant +* syncIdentifier +* synPreProc +* synType +* synSpecial +* synUnderlined +* synError +* synTodo +* synTitle + +It can be downloaded from [here](http://taquiones.net/files/misc/) or through my personal debian repository at . There is a page with examples: + +_**NOTE:** all the above links are broken_ + +Any help, comments or critics are welcome at . + +## version 0.9 + +- Add a force_subpage parameter for link build +- Fix a bug in syntax page link +- Documented a bug with markdown indented text +- Documented the syntax directive + +## version 0.7 + +- Version change to GPL +- Add *linenumbers* parameter +- The *file* parameter should be point to a ikiwiki source page. +- The *description* parameter will be converted on a URL if the *file* parameter exist. + +I need help for debugging this module. Thanks in advance. diff --git a/doc/plugins/contrib/syntax/discussion.mdwn b/doc/plugins/contrib/syntax/discussion.mdwn new file mode 100644 index 000000000..af6c07aa5 --- /dev/null +++ b/doc/plugins/contrib/syntax/discussion.mdwn @@ -0,0 +1,23 @@ +I'd like to include this in ikiwiki. Using vim for syntax highlighting is +suprising to me, but it seems to work great. Would it be possible to +license it the same as the rest of ikiwiki (GPL) instead of dragging in the +perl license? + +> Yes, no problem. I'm writing the next version. --[[VictorMoral]] + +Text::VimColor will need to be added to Debian.. + +It looks to me like the file parameter is a security hole, since it allows +inclusion of arbitrary files into the wiki, including ones outside of the +wiki source tree. I think this option should either be removed, or be +limited to reading files inside the wiki source tree. If it's retained it +should also add an appropriate dependency on the included file. + +> You are right, Joey. I didn't think on it because i don't use the cgi mode. :-) I'm working on it. --[[VictorMoral]] + +--[[Joey]] + +> It looks like the author of Text::VimColor has already made a Debian package. I've +> contacted him, but no answer back yet. --[[Roktas]] + +>>Meanwhile i've got a debian package for Text::VimColor [in my repository](http://taquiones.net/files/debian/). --[[VictorMoral]] diff --git a/doc/plugins/contrib/taskreport.mdwn b/doc/plugins/contrib/taskreport.mdwn new file mode 100644 index 000000000..377c9ed39 --- /dev/null +++ b/doc/plugins/contrib/taskreport.mdwn @@ -0,0 +1,63 @@ +[[!meta author="spalax"]] +[[!template id=plugin name=taskreport author="[[Louis|spalax]]"]] + +# Taskreport + +The taskreport plugin provides the `task` directive (see below), displaying +[taskwarrior](http://taskwarrior.org) data as a table. + +## Plugin options + +* `task_bin`: path to the task binary. Default is "task". +* `task_common`: arguments to all task calls. Can be used, for example, to set + a non-default taskrc location. +* `task_dir`: directory where to find task data files, if non-default. This + directory must be handled by IkiWiki. Otherwise, use the `task_common` + argument. This argument must be relative to the root of the wiki sources. +* `task_tmpdir`: directory where to copy task data files before calling task. + It can be used to circumvent [[lack of `--read-only` + option|https://bug.tasktools.org/browse/TW-204]]. Otherwise, those data files may + be modified by the task call. Setting this directory ensure that they are + not. This argument should be absolute (I do not know what would happen + otherwise). +* `task_columns`: List of default columns to display with the + task directive. Default is all available columns. + + +## Directive + +### Directive options + +Options are: + +* `arg`: arguments to add to the task call. For example, to display a list of + pending tasks tagged `ikiwiki`, set it to `"status:pending +ikiwiki"`. +* `show`: number of tasks to show. Default is 0, and means: print all tasks. +* `sort`: tasks are sorted according to this column. Default is `urgency`. +* `reverse`: set yes to reverse order. +* `annotations`: set to yes to display annotations. Default is "yes". + +### Task system call + +When using this directive, the result of the following system call is printed: + + TASK_BIN export rc.verbose=nothing TASK_COMMON [rc.data.location=DIR] ARG + +* `TASK_BIN` and `TASK_COMMON` are the `task_bin` and `task_common` options set in ikiwiki setup. +* If `task_dir` and `task_tmpdir` are set in ikiwiki setup, `DIR` is `task_tmpdir` ; if only `task_dir` is set, `DIR` is `task_dir` ; otherwise, this part is not used. +* `ARG` is the `arg` option of the directive. + +### CSS + +To allow CSS customization, the following classes are used. + +* `task` is the class of the table. +* `urgency`, `project`, etc. are the class of the `th` and `td` elements for the corresponding task attributes. +* `annotation` is the class of the `tr` element of the table containing an annotation. + + +## Download and install + +Code and documentation can be found here : [[https://atelier.gresille.org/projects/gresille-ikiwiki/wiki/Taskreport]] + +-- [[Louis|spalax]] diff --git a/doc/plugins/contrib/tex4ht.mdwn b/doc/plugins/contrib/tex4ht.mdwn new file mode 100644 index 000000000..bee18d96f --- /dev/null +++ b/doc/plugins/contrib/tex4ht.mdwn @@ -0,0 +1,15 @@ +[[!template id=plugin name=tex4ht core=0 author="[[DavidBremner]]"]] + +I have written a simple wrapper around tex4ht to convert tex files to html. This is slow, and currently noisy. I do not recommend it for running from cgi. But for interactive conversion of +my old tex4ht based home page, it seems to work OK. + +The current version is available from +[git](http://pivot.cs.unb.ca/git?p=ikiplugins.git;a=blob_plain;f=IkiWiki/Plugin/tex4ht.pm;hb=HEAD) + +### Other related ideas/plugins: + +- [[todo/latex]] There is work in progress at converting snippets of latex. No idea how the hybrid approach of tex4ht (part font, part bitmaps) compares to the [[todo/latex]] approach. + +- pandoc can also convert latex to html or markdown. It is much faster than tex4ht; on the other hand, the rendering quality is not quite as good, and pandoc does not understand user defined TeX macros. + +[[!tag type/slow]] diff --git a/doc/plugins/contrib/texinfo.mdwn b/doc/plugins/contrib/texinfo.mdwn new file mode 100644 index 000000000..b6a6c4bf3 --- /dev/null +++ b/doc/plugins/contrib/texinfo.mdwn @@ -0,0 +1,122 @@ +[[!template id=plugin name=texinfo author="[[tschwinge]]"]] + +[[I|tschwinge]] started writing a plugin to render +[GNU Texinfo](http://www.gnu.org/software/texinfo/) +inside the ikiwiki environment. + +This plugin is not neccessarily meant to enable people to write arbitrary +wiki pages in the Texinfo format (even though that is possible, of course), +but rather to ease collaboration on existing Texinfo documents. + +The plugin is available at +. + +It's very basic at the moment, but will be improved over time. + +It also has not really been audited for any security issues. + + +# Issues + +## How can I use verbatiminclude? + +I only can post a file ... + +## N-to-M Mapping of Input and Output Files + +Conventional ikiwiki [[*htmlize*ing|plugins/write#index6h3]] plugins +have a one-to-one mapping of input file and output file: +`some/where/page.mdwn` is rendered to `some/where/page.html`. +This can also be achieved for Texinfo files, but is somewhat +unusual there, when rendering them to HTML. In general, there +is a N-to-M mapping: + +* N Texinfo input files (a main `.texi` file, + several helper files (`fdl.texi`, `version.texi`, ...), and + additional text files which are included from the main `.texi` + file, e.g. `history.texi`, `libfoo.texi`, `libbar.texi`. --[[tschwinge]] + +> As far as multiple input files, you'd need to use add_depends() +> to let ikiwiki know that a change to any of those files should cause a +> rebuild of the "main" file. --[[Joey]] + +>> (?) I'll see about a frob to get `makeinfo` provide me with a list of additional files +>> it used for rendering a given `.texi` file. --[[tschwinge]] + +> I guess you'd also have to somehow deal with +> it wanting to render pages for each of the helper files. Not quite sure +> what the best way would be to avoid that. --[[Joey]] + +>> Might it be an option to simply not render the pages that are already +>> being used as an `include` file for another `.texi` file? +>> But how to assemble that list before actually having rendered all `.texi` files? +>> One possibility might be to already render them at ikiwiki's *scanning* stage and +>> store the rendered HTML files into temporary directories, and then at ikiwiki's +>> *rendering* stage simply install the desired ones into the main tree and discard +>> the others. --[[tschwinge]] + +* M Texinfo output files: the main `.texi` file (which `include`s + the other input files) is usually rendered into a (flat) hierarchy + of HTML files, one file per node, see the table on + + for an example. --[[tschwinge]] + +> Ikiwiki is perfectly happy with a page creating other files (see eg, the +> img and teximg plugins, as well as the inline plugin's rss generation). +> The will_render() function supports that. +> +> What hasn't been done though is a page creating more than one other _page_. +> Perhaps you could call IkiWiki::genpage by hand for each additional page. +> You might also want to manipulate each data structure that tracks info about +> pages, adding the additional pages to them, so that they're first class +> pages that work as pages everywhere in ikiwiki (ie, can be inlined, +> appear in a site map, be linked to, etc). Not sure how to do that, +> and perhaps you could get away without doing it actually. --[[Joey]] + +>> Currently I use `makeinfo --no-split` and render to stdout, so that I can +>> easily capture the output and stuff it into the appropriate ikiwiki data structure. +>> If we want to have multiple output files (which we'll eventually want to have, +>> to avoid having such large single-file outputs), we won't be able to +>> do this anymore. +>> (?) Then we'll need a way to find the main output file, which +>> will be the one to be copied into what ikiwiki expects to be the main output +>> of the rendered `.texi` file. +>> Perhaps (again) parse the `.texi` file for a `@setfilename` statement? +>> The other generated files will also have to +>> copied somewhere (preferably into a subdirectory named alike the main file +>> to avoid name space collisions; but need to take care of links between the files then) +>> and need to be registed within the ikiwiki system. +>> --[[tschwinge]] + +There needs to be some logic to establish a mapping between the *N* input files +and the *M* output files. +(At least for web-editing via CGI this is needed: ikiwiki (currently) needs to be able +to deduce *one* input file from a given output file) +Easiest would be either to have *N = 1* +(plus perhaps some input files that are not meant to be editable, like `gpl.texi`) +or to have +*M = N* and have a (?) one-to-one mapping between *input file n* and *output file m* +(which is not possible in Texinfo's `makeinfo` at the moment). +--[[tschwinge]] + + +## `makeinfo` Output + +`makeinfo --html` is being used for rendering. It creates stand-alone +HTML files, while ikiwiki only needs the files' ``s. + +(?) One possibility (which is what I'm doing at the moment) is to simply cut away +everythin until `` is seen and after `` has been seen. --[[tschwinge]] + + +# Bugs + +## Non-functional Texinfo Commands + +Those commands are know to not work currently: + +* `@printindex` +* `@shortcontents` +* `@contents` + +This is due to `makeinfo` not providing this functionality if rendering to stdout. diff --git a/doc/plugins/contrib/todo.mdwn b/doc/plugins/contrib/todo.mdwn new file mode 100644 index 000000000..d8ba05681 --- /dev/null +++ b/doc/plugins/contrib/todo.mdwn @@ -0,0 +1,17 @@ +[[!template id=plugin name=todo author="Joël Porquet"]] +[[!tag type/widget]] + +This plugin provides the todo [[ikiwiki/directive]], which enables a page to be marked as a todo page. Additionally a deadline date can be provided. + +An example of a page marked as todo could be: + + \[[!todo deadline="3 April 1982"]] + # Title of what should be done for April 3, 1982 + blabla + +This plugin also provides ways to display pages marked as todo, and can even sort those pages by deadline dates: + + \[[!inline pages="* and todo() and !todo(done)" archive="yes" sort="todo(deadline)"]] + +The full documentation and source code can be found here: + diff --git a/doc/plugins/contrib/tracking.mdwn b/doc/plugins/contrib/tracking.mdwn new file mode 100644 index 000000000..06d4120cd --- /dev/null +++ b/doc/plugins/contrib/tracking.mdwn @@ -0,0 +1,30 @@ +[[!template id=plugin name=tracking author="[[BerndZeimetz]]"]] +[[!toc]] +[[!tag plugins]] [[!tag patch]] [[!tag wishlist]] + +## NAME + +IkiWiki::Plugin::tracking - enable google/piwik visitor tracking + +## SYNOPSIS + + # activate the plugin + add_plugins => [qw{goodstuff tracking ....}], + + # to use Piwik: + piwik_id => '1', + piwik_https_url => "https://ssl.example.com/piwik/", + piwik_http_url => "http://www.example.com/piwik/", + + # to use Google Analytics: + google_analytics_id => "UA-xxxxxx-x" + +## DESCRIPTION + +This plugin includes the necessary tracking codes for Piwik and/or Google Analytics on all pages. Tracking codes will only be included if the necessary config options are set. The plugin could be enhanced to support goals/profiles and similar things, but I do not plan to do so. + +## DOWNLOAD + +* single files: [tracking.pm](http://git.recluse.de/?p=users/bzed/ikiwiki.git;a=blob;f=IkiWiki/Plugin/tracking.pm;hb=refs/heads/tracking) [piwik.tmpl](http://git.recluse.de/?p=users/bzed/ikiwiki.git;a=blob;f=templates/piwik.tmpl;hb=refs/heads/tracking) [google_analytics.tmpl](http://git.recluse.de/?p=users/bzed/ikiwiki.git;a=blob;f=templates/google_analytics.tmpl;hb=refs/heads/tracking) +* browse repository: +* git repo: `git://git.recluse.de/users/bzed/ikiwiki.git` or (Use the tracking branch) diff --git a/doc/plugins/contrib/unixauth.mdwn b/doc/plugins/contrib/unixauth.mdwn new file mode 100644 index 000000000..c97312b59 --- /dev/null +++ b/doc/plugins/contrib/unixauth.mdwn @@ -0,0 +1,21 @@ +[[!template id=plugin name=unixauth core=0 author="[[schmonz]]"]] +[[!tag type/auth]] + +[[!template id=gitbranch branch=unixauth author="[[schmonz]]"]] + +This plugin authenticates users against the Unix user database. It presents a similar UI to [[plugins/passwordauth]], but simpler, as there's no need to be able to register or change one's password. + +To authenticate, either [checkpassword](http://cr.yp.to/checkpwd.html) or [pwauth](http://www.unixpapa.com/pwauth/) must be installed and configured. `checkpassword` is strongly preferred. If your web server runs as an unprivileged user -- as it darn well should! -- then `checkpassword` needs to be setuid root. (Or your ikiwiki CGI wrapper, I guess, but don't do that.) Other checkpassword implementations are available, notably [checkpassword-pam](http://checkpasswd-pam.sourceforge.net/). + +Config variables that affect the behavior of `unixauth`: + +* `unixauth_type`: defaults to unset, can be "checkpassword" or "pwauth" +* `unixauth_command`: defaults to unset, should contain the full path and any arguments +* `unixauth_requiressl`: defaults to 1, can be 0 +* `sslcookie`: needs to be 1 if `unixauth_requiressl` is 1 (perhaps this should be done automatically?) + +__Security__: [As with passwordauth](/security/#index14h2), be wary of sending usernames and passwords in cleartext. Unlike passwordauth, sniffing `unixauth` credentials can get an attacker much further than mere wiki access. Therefore, this plugin defaults to not even _displaying_ the login form fields unless we're running under SSL. Nobody should be able to do anything remotely dumb until the admin has done at least a little thinking. After that, dumb things are always possible. ;-) + +`unixauth` needs the `HTTPS` environment variable, available in ikiwiki 2.67 or later (fixed in #[502047](http://bugs.debian.org/502047)), without which it fails closed. + +The plugin has not been tested with newer versions of ikiwiki. [[schmonz]] hopes to have time to polish this plugin soon. diff --git a/doc/plugins/contrib/unixauth/discussion.mdwn b/doc/plugins/contrib/unixauth/discussion.mdwn new file mode 100644 index 000000000..232649863 --- /dev/null +++ b/doc/plugins/contrib/unixauth/discussion.mdwn @@ -0,0 +1,38 @@ +The security of this plugin scares me. As noted in the plugin +documentation, you basically have to use it with SSL, since snooping on the +login password doesn't give you an essentially useless account -- it gives +you an actual account on the machine! + +Also, apparently pwauth defers *all* auth attempts if one fails, and it +does this by using a lock file, and sleeping after a failed auth attempt. +Which is needed to avoid brute-forcing, since this is a significant +password.. but how will that interact with ikiwiki? Well, ikiwiki _also_ +uses a lock file. So, at a minimum, someone can not only try to brute-force +the pwauth password, but the ikiwiki processes that stack up due to that +will also keep ikiwiki's lock held. Which basically DOSes the wiki for +everyone else; noone else can try to log in, or log out, or edit a page, +all of which require taking the lock. + +So I don't think I'll be accepting this plugin into ikiwiki itself.. +--[[Joey]] + +Thanks for the comments. That's definitely an undesirable interaction between pwauth and ikiwiki; in my current application it wouldn't be a serious problem, but I'd like this plugin to be general-purpose and safe enough for inclusion in ikiwiki. It's the system-users-are-wiki-users idea I'm married to here, not pwauth itself; can you suggest another approach I might take? +-- [[schmonz]] + +> Have you considered using [[plugins/httpauth]] and then the appropriate apache module? There are apache modules like [mod_authnz_external](http://unixpapa.com/mod_auth_external.html) that might help. The advantage of these solutions is that they usually make the security implications explicit. -- Will + +Actually, yes. That's how I made sure I had pwauth working to begin with. I'm partial to the form-based approach because I'm not aware of any way to reliably "log out" browsers from HTTP authentication. If that *is* reliably possible, then I worked way too hard for no reason. ;-) +-- [[schmonz]] + +I've added support for [checkpassword](http://cr.yp.to/checkpwd/interface.html), since those generally don't have any rate-limiting cleverness to interfere with ikiwiki's, and made a few other changes. Please check out the plugin docs again and let me know if this is closer to being acceptable. +-- [[schmonz]] + +> I actually think that the rate limiting is a good thing. After all, +> ikiwiki doesn't do its own login rate limiting. Just need to find a way +> to disentangle the two locks. --[[Joey]] + +>> Ah, ok, I misunderstood your comment. I'll see what I can figure out. --[[schmonz]] + +>>> My time's been limited for this, but I just saw [[todo/avoid_thrashing]]. How does that interact with pwauth or checkpassword? --[[schmonz]] + +>>>> The DOS still happens, it just uses less memory. --[[Joey]] diff --git a/doc/plugins/contrib/unixrelpagespec.mdwn b/doc/plugins/contrib/unixrelpagespec.mdwn new file mode 100644 index 000000000..a35f76c30 --- /dev/null +++ b/doc/plugins/contrib/unixrelpagespec.mdwn @@ -0,0 +1,42 @@ +[[!template id=plugin name=unixrelpagespec core=0 author="[[Jogo]]"]] + +I don't understand why `./*` correspond to siblings and not subpages. +This is probably only meaningfull with [[plugins/autoindex]] turned on. + +Here is a small plugin wich follow usual Unix convention : + +- `./*` expand to subpages +- `../*` expand to siblings + +--- + #!/usr/bin/perl + # UnixRelPageSpec plugin. + # by Joseph Boudou + + package IkiWiki::Plugin::unixrelpagespec; + + use warnings; + use strict; + use IkiWiki 3.00; + + sub import { + inject( + name => 'IkiWiki::PageSpec::derel', + call => \&unix_derel + ); + } + + sub unix_derel ($$) { + my $path = shift; + my $from = shift; + + if ($path =~ m!^\.{1,2}/!) { + $from =~ s#/?[^/]+$## if (defined $from and $path =~ m/^\.{2}/); + $path =~ s#^\.{1,2}/##; + $path = "$from/$path" if length $from; + } + + return $path; + } + + 1; diff --git a/doc/plugins/contrib/video.mdwn b/doc/plugins/contrib/video.mdwn new file mode 100644 index 000000000..baa0c6500 --- /dev/null +++ b/doc/plugins/contrib/video.mdwn @@ -0,0 +1,25 @@ +[[!template id=plugin name=video author="[[Yury Chumak|sphynkx]]"]] + +## Video + +This plugin provides embedding video on wikipages. Plugin uses most simple embedding method - only with *embed* tag and without any JS-scripts. + +###Usage + +>\[\[\!video width=100 height=100 type="application/x-shockwave-flash" src="/\_jwplayer/player.swf" allowscriptaccess="always" allowfullscreen="true" autostart="false" file="path\_to\_video"\]\] + +All parameters are optional except *file* and will be replaced with the default settings as showed in the above example. + +*file* is relative path in webdir or web-address (to Youtube page). + +### Install +Download and unpack [archive](http://sphynkx.org.ua/progr/videoplug/jw_videoplugin.tar.bz2) in your ikiwiki webdir. +Or download [JW Player](http://www.longtailvideo.com/players/jw-flv-player/) and [perl module](http://sphynkx.org.ua/progr/videoplug/video.pm) separately. Make dir *\_jwplayer* and put player.swf in it. Also put *video.pm* in *Plugin* dir. In Ikiwiki configuration switch on the plugin: + + add_plugins => [qw{.......... video}] + +### Note + +[Htmlscrubber](http://ikiwiki.info/plugins/htmlscrubber/) may block *embed* tag. + +If embed tag present but video not playing - check mode of unpacked *player.swf*. diff --git a/doc/plugins/contrib/video/discussion.mdwn b/doc/plugins/contrib/video/discussion.mdwn new file mode 100644 index 000000000..577790988 --- /dev/null +++ b/doc/plugins/contrib/video/discussion.mdwn @@ -0,0 +1,3 @@ +I'm sure this is useful to its author in his situation, but I have to point +out that ikiwiki supports the html5 `
").addClass("ui-button-text").html(this.options.label).appendTo(p.empty()).text(),m=this.options.icons,l=m.primary&&m.secondary,o=[];if(m.primary||m.secondary){if(this.options.text){o.push("ui-button-text-icon"+(l?"s":(m.primary?"-primary":"-secondary")))}if(m.primary){p.prepend("")}if(m.secondary){p.append("")}if(!this.options.text){o.push(l?"ui-button-icons-only":"ui-button-icon-only");if(!this.hasTitle){p.attr("title",n)}}}else{o.push("ui-button-text-only")}p.addClass(o.join(" "))}});f.widget("ui.buttonset",{options:{items:":button, :submit, :reset, :checkbox, :radio, a, :data(button)"},_create:function(){this.element.addClass("ui-buttonset")},_init:function(){this.refresh()},_setOption:function(l,m){if(l==="disabled"){this.buttons.button("option",l,m)}f.Widget.prototype._setOption.apply(this,arguments)},refresh:function(){var l=this.element.css("direction")==="ltr";this.buttons=this.element.find(this.options.items).filter(":ui-button").button("refresh").end().not(":ui-button").button().end().map(function(){return f(this).button("widget")[0]}).removeClass("ui-corner-all ui-corner-left ui-corner-right").filter(":first").addClass(l?"ui-corner-left":"ui-corner-right").end().filter(":last").addClass(l?"ui-corner-right":"ui-corner-left").end().end()},destroy:function(){this.element.removeClass("ui-buttonset");this.buttons.map(function(){return f(this).button("widget")[0]}).removeClass("ui-corner-left ui-corner-right").end().button("destroy");f.Widget.prototype.destroy.call(this)}})}(jQuery));(function(e,f){var c="ui-dialog ui-widget ui-widget-content ui-corner-all ",b={buttons:true,height:true,maxHeight:true,maxWidth:true,minHeight:true,minWidth:true,width:true},d={maxHeight:true,maxWidth:true,minHeight:true,minWidth:true},a=e.attrFn||{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true,click:true};e.widget("ui.dialog",{options:{autoOpen:true,buttons:{},closeOnEscape:true,closeText:"close",dialogClass:"",draggable:true,hide:null,height:"auto",maxHeight:false,maxWidth:false,minHeight:150,minWidth:150,modal:false,position:{my:"center",at:"center",collision:"fit",using:function(h){var g=e(this).css(h).offset().top;if(g<0){e(this).css("top",h.top-g)}}},resizable:true,show:null,stack:true,title:"",width:300,zIndex:1000},_create:function(){this.originalTitle=this.element.attr("title");if(typeof this.originalTitle!=="string"){this.originalTitle=""}this.options.title=this.options.title||this.originalTitle;var o=this,p=o.options,m=p.title||" ",h=e.ui.dialog.getTitleId(o.element),n=(o.uiDialog=e("
")).appendTo(document.body).hide().addClass(c+p.dialogClass).css({zIndex:p.zIndex}).attr("tabIndex",-1).css("outline",0).keydown(function(q){if(p.closeOnEscape&&q.keyCode&&q.keyCode===e.ui.keyCode.ESCAPE){o.close(q);q.preventDefault()}}).attr({role:"dialog","aria-labelledby":h}).mousedown(function(q){o.moveToTop(false,q)}),j=o.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(n),i=(o.uiDialogTitlebar=e("
")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(n),l=e('').addClass("ui-dialog-titlebar-close ui-corner-all").attr("role","button").hover(function(){l.addClass("ui-state-hover")},function(){l.removeClass("ui-state-hover")}).focus(function(){l.addClass("ui-state-focus")}).blur(function(){l.removeClass("ui-state-focus")}).click(function(q){o.close(q);return false}).appendTo(i),k=(o.uiDialogTitlebarCloseText=e("")).addClass("ui-icon ui-icon-closethick").text(p.closeText).appendTo(l),g=e("").addClass("ui-dialog-title").attr("id",h).html(m).prependTo(i);if(e.isFunction(p.beforeclose)&&!e.isFunction(p.beforeClose)){p.beforeClose=p.beforeclose}i.find("*").add(i).disableSelection();if(p.draggable&&e.fn.draggable){o._makeDraggable()}if(p.resizable&&e.fn.resizable){o._makeResizable()}o._createButtons(p.buttons);o._isOpen=false;if(e.fn.bgiframe){n.bgiframe()}},_init:function(){if(this.options.autoOpen){this.open()}},destroy:function(){var g=this;if(g.overlay){g.overlay.destroy()}g.uiDialog.hide();g.element.unbind(".dialog").removeData("dialog").removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body");g.uiDialog.remove();if(g.originalTitle){g.element.attr("title",g.originalTitle)}return g},widget:function(){return this.uiDialog},close:function(j){var g=this,i,h;if(false===g._trigger("beforeClose",j)){return}if(g.overlay){g.overlay.destroy()}g.uiDialog.unbind("keypress.ui-dialog");g._isOpen=false;if(g.options.hide){g.uiDialog.hide(g.options.hide,function(){g._trigger("close",j)})}else{g.uiDialog.hide();g._trigger("close",j)}e.ui.dialog.overlay.resize();if(g.options.modal){i=0;e(".ui-dialog").each(function(){if(this!==g.uiDialog[0]){h=e(this).css("z-index");if(!isNaN(h)){i=Math.max(i,h)}}});e.ui.dialog.maxZ=i}return g},isOpen:function(){return this._isOpen},moveToTop:function(k,j){var g=this,i=g.options,h;if((i.modal&&!k)||(!i.stack&&!i.modal)){return g._trigger("focus",j)}if(i.zIndex>e.ui.dialog.maxZ){e.ui.dialog.maxZ=i.zIndex}if(g.overlay){e.ui.dialog.maxZ+=1;g.overlay.$el.css("z-index",e.ui.dialog.overlay.maxZ=e.ui.dialog.maxZ)}h={scrollTop:g.element.attr("scrollTop"),scrollLeft:g.element.attr("scrollLeft")};e.ui.dialog.maxZ+=1;g.uiDialog.css("z-index",e.ui.dialog.maxZ);g.element.attr(h);g._trigger("focus",j);return g},open:function(){if(this._isOpen){return}var h=this,i=h.options,g=h.uiDialog;h.overlay=i.modal?new e.ui.dialog.overlay(h):null;h._size();h._position(i.position);g.show(i.show);h.moveToTop(true);if(i.modal){g.bind("keypress.ui-dialog",function(l){if(l.keyCode!==e.ui.keyCode.TAB){return}var k=e(":tabbable",this),m=k.filter(":first"),j=k.filter(":last");if(l.target===j[0]&&!l.shiftKey){m.focus(1);return false}else{if(l.target===m[0]&&l.shiftKey){j.focus(1);return false}}})}e(h.element.find(":tabbable").get().concat(g.find(".ui-dialog-buttonpane :tabbable").get().concat(g.get()))).eq(0).focus();h._isOpen=true;h._trigger("open");return h},_createButtons:function(j){var i=this,g=false,h=e("
").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),k=e("
").addClass("ui-dialog-buttonset").appendTo(h);i.uiDialog.find(".ui-dialog-buttonpane").remove();if(typeof j==="object"&&j!==null){e.each(j,function(){return !(g=true)})}if(g){e.each(j,function(l,n){n=e.isFunction(n)?{click:n,text:l}:n;var m=e('').click(function(){n.click.apply(i.element[0],arguments)}).appendTo(k);e.each(n,function(o,p){if(o==="click"){return}if(o in a){m[o](p)}else{m.attr(o,p)}});if(e.fn.button){m.button()}});h.appendTo(i.uiDialog)}},_makeDraggable:function(){var g=this,j=g.options,k=e(document),i;function h(l){return{position:l.position,offset:l.offset}}g.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(l,m){i=j.height==="auto"?"auto":e(this).height();e(this).height(e(this).height()).addClass("ui-dialog-dragging");g._trigger("dragStart",l,h(m))},drag:function(l,m){g._trigger("drag",l,h(m))},stop:function(l,m){j.position=[m.position.left-k.scrollLeft(),m.position.top-k.scrollTop()];e(this).removeClass("ui-dialog-dragging").height(i);g._trigger("dragStop",l,h(m));e.ui.dialog.overlay.resize()}})},_makeResizable:function(l){l=(l===f?this.options.resizable:l);var h=this,k=h.options,g=h.uiDialog.css("position"),j=(typeof l==="string"?l:"n,e,s,w,se,sw,ne,nw");function i(m){return{originalPosition:m.originalPosition,originalSize:m.originalSize,position:m.position,size:m.size}}h.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:h.element,maxWidth:k.maxWidth,maxHeight:k.maxHeight,minWidth:k.minWidth,minHeight:h._minHeight(),handles:j,start:function(m,n){e(this).addClass("ui-dialog-resizing");h._trigger("resizeStart",m,i(n))},resize:function(m,n){h._trigger("resize",m,i(n))},stop:function(m,n){e(this).removeClass("ui-dialog-resizing");k.height=e(this).height();k.width=e(this).width();h._trigger("resizeStop",m,i(n));e.ui.dialog.overlay.resize()}}).css("position",g).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_minHeight:function(){var g=this.options;if(g.height==="auto"){return g.minHeight}else{return Math.min(g.minHeight,g.height)}},_position:function(h){var i=[],j=[0,0],g;if(h){if(typeof h==="string"||(typeof h==="object"&&"0" in h)){i=h.split?h.split(" "):[h[0],h[1]];if(i.length===1){i[1]=i[0]}e.each(["left","top"],function(l,k){if(+i[l]===i[l]){j[l]=i[l];i[l]=k}});h={my:i.join(" "),at:i.join(" "),offset:j.join(" ")}}h=e.extend({},e.ui.dialog.prototype.options.position,h)}else{h=e.ui.dialog.prototype.options.position}g=this.uiDialog.is(":visible");if(!g){this.uiDialog.show()}this.uiDialog.css({top:0,left:0}).position(e.extend({of:window},h));if(!g){this.uiDialog.hide()}},_setOptions:function(j){var h=this,g={},i=false;e.each(j,function(k,l){h._setOption(k,l);if(k in b){i=true}if(k in d){g[k]=l}});if(i){this._size()}if(this.uiDialog.is(":data(resizable)")){this.uiDialog.resizable("option",g)}},_setOption:function(j,k){var h=this,g=h.uiDialog;switch(j){case"beforeclose":j="beforeClose";break;case"buttons":h._createButtons(k);break;case"closeText":h.uiDialogTitlebarCloseText.text(""+k);break;case"dialogClass":g.removeClass(h.options.dialogClass).addClass(c+k);break;case"disabled":if(k){g.addClass("ui-dialog-disabled")}else{g.removeClass("ui-dialog-disabled")}break;case"draggable":var i=g.is(":data(draggable)");if(i&&!k){g.draggable("destroy")}if(!i&&k){h._makeDraggable()}break;case"position":h._position(k);break;case"resizable":var l=g.is(":data(resizable)");if(l&&!k){g.resizable("destroy")}if(l&&typeof k==="string"){g.resizable("option","handles",k)}if(!l&&k!==false){h._makeResizable(k)}break;case"title":e(".ui-dialog-title",h.uiDialogTitlebar).html(""+(k||" "));break}e.Widget.prototype._setOption.apply(h,arguments)},_size:function(){var k=this.options,h,j,g=this.uiDialog.is(":visible");this.element.show().css({width:"auto",minHeight:0,height:0});if(k.minWidth>k.width){k.width=k.minWidth}h=this.uiDialog.css({height:"auto",width:k.width}).height();j=Math.max(0,k.minHeight-h);if(k.height==="auto"){if(e.support.minHeight){this.element.css({minHeight:j,height:"auto"})}else{this.uiDialog.show();var i=this.element.css("height","auto").height();if(!g){this.uiDialog.hide()}this.element.height(Math.max(i,j))}}else{this.element.height(Math.max(k.height-h,0))}if(this.uiDialog.is(":data(resizable)")){this.uiDialog.resizable("option","minHeight",this._minHeight())}}});e.extend(e.ui.dialog,{version:"1.8.14",uuid:0,maxZ:0,getTitleId:function(g){var h=g.attr("id");if(!h){this.uuid+=1;h=this.uuid}return"ui-dialog-title-"+h},overlay:function(g){this.$el=e.ui.dialog.overlay.create(g)}});e.extend(e.ui.dialog.overlay,{instances:[],oldInstances:[],maxZ:0,events:e.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),function(g){return g+".dialog-overlay"}).join(" "),create:function(h){if(this.instances.length===0){setTimeout(function(){if(e.ui.dialog.overlay.instances.length){e(document).bind(e.ui.dialog.overlay.events,function(i){if(e(i.target).zIndex()").addClass("ui-widget-overlay")).appendTo(document.body).css({width:this.width(),height:this.height()});if(e.fn.bgiframe){g.bgiframe()}this.instances.push(g);return g},destroy:function(g){var h=e.inArray(g,this.instances);if(h!=-1){this.oldInstances.push(this.instances.splice(h,1)[0])}if(this.instances.length===0){e([document,window]).unbind(".dialog-overlay")}g.remove();var i=0;e.each(this.instances,function(){i=Math.max(i,this.css("z-index"))});this.maxZ=i},height:function(){var h,g;if(e.browser.msie&&e.browser.version<7){h=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight);g=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight);if(h").appendTo(this.element).addClass("ui-slider-range ui-widget-header"+((k.range==="min"||k.range==="max")?" ui-slider-range-"+k.range:""))}for(var f=j.length;fp){e=p;h=b(this);k=o}});if(g.range===true&&this.values(1)===g.min){k+=1;h=b(this.handles[k])}m=this._start(f,k);if(m===false){return false}this._mouseSliding=true;n._handleIndex=k;h.addClass("ui-state-active").focus();i=h.offset();d=!b(f.target).parents().andSelf().is(".ui-slider-handle");this._clickOffset=d?{left:0,top:0}:{left:f.pageX-i.left-(h.width()/2),top:f.pageY-i.top-(h.height()/2)-(parseInt(h.css("borderTopWidth"),10)||0)-(parseInt(h.css("borderBottomWidth"),10)||0)+(parseInt(h.css("marginTop"),10)||0)};if(!this.handles.hasClass("ui-state-hover")){this._slide(f,k,l)}this._animateOff=true;return true},_mouseStart:function(d){return true},_mouseDrag:function(f){var d={x:f.pageX,y:f.pageY},e=this._normValueFromMouse(d);this._slide(f,this._handleIndex,e);return false},_mouseStop:function(d){this.handles.removeClass("ui-state-active");this._mouseSliding=false;this._stop(d,this._handleIndex);this._change(d,this._handleIndex);this._handleIndex=null;this._clickOffset=null;this._animateOff=false;return false},_detectOrientation:function(){this.orientation=(this.options.orientation==="vertical")?"vertical":"horizontal"},_normValueFromMouse:function(e){var d,h,g,f,i;if(this.orientation==="horizontal"){d=this.elementSize.width;h=e.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)}else{d=this.elementSize.height;h=e.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)}g=(h/d);if(g>1){g=1}if(g<0){g=0}if(this.orientation==="vertical"){g=1-g}f=this._valueMax()-this._valueMin();i=this._valueMin()+g*f;return this._trimAlignValue(i)},_start:function(f,e){var d={handle:this.handles[e],value:this.value()};if(this.options.values&&this.options.values.length){d.value=this.values(e);d.values=this.values()}return this._trigger("start",f,d)},_slide:function(h,g,f){var d,e,i;if(this.options.values&&this.options.values.length){d=this.values(g?0:1);if((this.options.values.length===2&&this.options.range===true)&&((g===0&&f>d)||(g===1&&f1){this.options.values[e]=this._trimAlignValue(h);this._refreshValue();this._change(null,e);return}if(arguments.length){if(b.isArray(arguments[0])){g=this.options.values;d=arguments[0];for(f=0;f=this._valueMax()){return this._valueMax()}var d=(this.options.step>0)?this.options.step:1,e=(f-this._valueMin())%d;alignValue=f-e;if(Math.abs(e)*2>=d){alignValue+=(e>0)?d:(-d)}return parseFloat(alignValue.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var g=this.options.range,f=this.options,m=this,e=(!this._animateOff)?f.animate:false,h,d={},i,k,j,l;if(this.options.values&&this.options.values.length){this.handles.each(function(o,n){h=(m.values(o)-m._valueMin())/(m._valueMax()-m._valueMin())*100;d[m.orientation==="horizontal"?"left":"bottom"]=h+"%";b(this).stop(1,1)[e?"animate":"css"](d,f.animate);if(m.options.range===true){if(m.orientation==="horizontal"){if(o===0){m.range.stop(1,1)[e?"animate":"css"]({left:h+"%"},f.animate)}if(o===1){m.range[e?"animate":"css"]({width:(h-i)+"%"},{queue:false,duration:f.animate})}}else{if(o===0){m.range.stop(1,1)[e?"animate":"css"]({bottom:(h)+"%"},f.animate)}if(o===1){m.range[e?"animate":"css"]({height:(h-i)+"%"},{queue:false,duration:f.animate})}}}i=h})}else{k=this.value();j=this._valueMin();l=this._valueMax();h=(l!==j)?(k-j)/(l-j)*100:0;d[m.orientation==="horizontal"?"left":"bottom"]=h+"%";this.handle.stop(1,1)[e?"animate":"css"](d,f.animate);if(g==="min"&&this.orientation==="horizontal"){this.range.stop(1,1)[e?"animate":"css"]({width:h+"%"},f.animate)}if(g==="max"&&this.orientation==="horizontal"){this.range[e?"animate":"css"]({width:(100-h)+"%"},{queue:false,duration:f.animate})}if(g==="min"&&this.orientation==="vertical"){this.range.stop(1,1)[e?"animate":"css"]({height:h+"%"},f.animate)}if(g==="max"&&this.orientation==="vertical"){this.range[e?"animate":"css"]({height:(100-h)+"%"},{queue:false,duration:f.animate})}}}});b.extend(b.ui.slider,{version:"1.8.14"})}(jQuery));(function(d,f){var c=0,b=0;function e(){return ++c}function a(){return ++b}d.widget("ui.tabs",{options:{add:null,ajaxOptions:null,cache:false,cookie:null,collapsible:false,disable:null,disabled:[],enable:null,event:"click",fx:null,idPrefix:"ui-tabs-",load:null,panelTemplate:"
",remove:null,select:null,show:null,spinner:"Loading…",tabTemplate:"
  • #{label}
  • "},_create:function(){this._tabify(true)},_setOption:function(g,h){if(g=="selected"){if(this.options.collapsible&&h==this.options.selected){return}this.select(h)}else{this.options[g]=h;this._tabify()}},_tabId:function(g){return g.title&&g.title.replace(/\s/g,"_").replace(/[^\w\u00c0-\uFFFF-]/g,"")||this.options.idPrefix+e()},_sanitizeSelector:function(g){return g.replace(/:/g,"\\:")},_cookie:function(){var g=this.cookie||(this.cookie=this.options.cookie.name||"ui-tabs-"+a());return d.cookie.apply(null,[g].concat(d.makeArray(arguments)))},_ui:function(h,g){return{tab:h,panel:g,index:this.anchors.index(h)}},_cleanup:function(){this.lis.filter(".ui-state-processing").removeClass("ui-state-processing").find("span:data(label.tabs)").each(function(){var g=d(this);g.html(g.data("label.tabs")).removeData("label.tabs")})},_tabify:function(u){var v=this,j=this.options,h=/^#.+/;this.list=this.element.find("ol,ul").eq(0);this.lis=d(" > li:has(a[href])",this.list);this.anchors=this.lis.map(function(){return d("a",this)[0]});this.panels=d([]);this.anchors.each(function(x,o){var w=d(o).attr("href");var y=w.split("#")[0],z;if(y&&(y===location.toString().split("#")[0]||(z=d("base")[0])&&y===z.href)){w=o.hash;o.href=w}if(h.test(w)){v.panels=v.panels.add(v.element.find(v._sanitizeSelector(w)))}else{if(w&&w!=="#"){d.data(o,"href.tabs",w);d.data(o,"load.tabs",w.replace(/#.*$/,""));var B=v._tabId(o);o.href="#"+B;var A=v.element.find("#"+B);if(!A.length){A=d(j.panelTemplate).attr("id",B).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").insertAfter(v.panels[x-1]||v.list);A.data("destroy.tabs",true)}v.panels=v.panels.add(A)}else{j.disabled.push(x)}}});if(u){this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all");this.list.addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.lis.addClass("ui-state-default ui-corner-top");this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom");if(j.selected===f){if(location.hash){this.anchors.each(function(w,o){if(o.hash==location.hash){j.selected=w;return false}})}if(typeof j.selected!=="number"&&j.cookie){j.selected=parseInt(v._cookie(),10)}if(typeof j.selected!=="number"&&this.lis.filter(".ui-tabs-selected").length){j.selected=this.lis.index(this.lis.filter(".ui-tabs-selected"))}j.selected=j.selected||(this.lis.length?0:-1)}else{if(j.selected===null){j.selected=-1}}j.selected=((j.selected>=0&&this.anchors[j.selected])||j.selected<0)?j.selected:0;j.disabled=d.unique(j.disabled.concat(d.map(this.lis.filter(".ui-state-disabled"),function(w,o){return v.lis.index(w)}))).sort();if(d.inArray(j.selected,j.disabled)!=-1){j.disabled.splice(d.inArray(j.selected,j.disabled),1)}this.panels.addClass("ui-tabs-hide");this.lis.removeClass("ui-tabs-selected ui-state-active");if(j.selected>=0&&this.anchors.length){v.element.find(v._sanitizeSelector(v.anchors[j.selected].hash)).removeClass("ui-tabs-hide");this.lis.eq(j.selected).addClass("ui-tabs-selected ui-state-active");v.element.queue("tabs",function(){v._trigger("show",null,v._ui(v.anchors[j.selected],v.element.find(v._sanitizeSelector(v.anchors[j.selected].hash))[0]))});this.load(j.selected)}d(window).bind("unload",function(){v.lis.add(v.anchors).unbind(".tabs");v.lis=v.anchors=v.panels=null})}else{j.selected=this.lis.index(this.lis.filter(".ui-tabs-selected"))}this.element[j.collapsible?"addClass":"removeClass"]("ui-tabs-collapsible");if(j.cookie){this._cookie(j.selected,j.cookie)}for(var m=0,s;(s=this.lis[m]);m++){d(s)[d.inArray(m,j.disabled)!=-1&&!d(s).hasClass("ui-tabs-selected")?"addClass":"removeClass"]("ui-state-disabled")}if(j.cache===false){this.anchors.removeData("cache.tabs")}this.lis.add(this.anchors).unbind(".tabs");if(j.event!=="mouseover"){var l=function(o,i){if(i.is(":not(.ui-state-disabled)")){i.addClass("ui-state-"+o)}};var p=function(o,i){i.removeClass("ui-state-"+o)};this.lis.bind("mouseover.tabs",function(){l("hover",d(this))});this.lis.bind("mouseout.tabs",function(){p("hover",d(this))});this.anchors.bind("focus.tabs",function(){l("focus",d(this).closest("li"))});this.anchors.bind("blur.tabs",function(){p("focus",d(this).closest("li"))})}var g,n;if(j.fx){if(d.isArray(j.fx)){g=j.fx[0];n=j.fx[1]}else{g=n=j.fx}}function k(i,o){i.css("display","");if(!d.support.opacity&&o.opacity){i[0].style.removeAttribute("filter")}}var q=n?function(i,o){d(i).closest("li").addClass("ui-tabs-selected ui-state-active");o.hide().removeClass("ui-tabs-hide").animate(n,n.duration||"normal",function(){k(o,n);v._trigger("show",null,v._ui(i,o[0]))})}:function(i,o){d(i).closest("li").addClass("ui-tabs-selected ui-state-active");o.removeClass("ui-tabs-hide");v._trigger("show",null,v._ui(i,o[0]))};var r=g?function(o,i){i.animate(g,g.duration||"normal",function(){v.lis.removeClass("ui-tabs-selected ui-state-active");i.addClass("ui-tabs-hide");k(i,g);v.element.dequeue("tabs")})}:function(o,i,w){v.lis.removeClass("ui-tabs-selected ui-state-active");i.addClass("ui-tabs-hide");v.element.dequeue("tabs")};this.anchors.bind(j.event+".tabs",function(){var o=this,x=d(o).closest("li"),i=v.panels.filter(":not(.ui-tabs-hide)"),w=v.element.find(v._sanitizeSelector(o.hash));if((x.hasClass("ui-tabs-selected")&&!j.collapsible)||x.hasClass("ui-state-disabled")||x.hasClass("ui-state-processing")||v.panels.filter(":animated").length||v._trigger("select",null,v._ui(this,w[0]))===false){this.blur();return false}j.selected=v.anchors.index(this);v.abort();if(j.collapsible){if(x.hasClass("ui-tabs-selected")){j.selected=-1;if(j.cookie){v._cookie(j.selected,j.cookie)}v.element.queue("tabs",function(){r(o,i)}).dequeue("tabs");this.blur();return false}else{if(!i.length){if(j.cookie){v._cookie(j.selected,j.cookie)}v.element.queue("tabs",function(){q(o,w)});v.load(v.anchors.index(this));this.blur();return false}}}if(j.cookie){v._cookie(j.selected,j.cookie)}if(w.length){if(i.length){v.element.queue("tabs",function(){r(o,i)})}v.element.queue("tabs",function(){q(o,w)});v.load(v.anchors.index(this))}else{throw"jQuery UI Tabs: Mismatching fragment identifier."}if(d.browser.msie){this.blur()}});this.anchors.bind("click.tabs",function(){return false})},_getIndex:function(g){if(typeof g=="string"){g=this.anchors.index(this.anchors.filter("[href$="+g+"]"))}return g},destroy:function(){var g=this.options;this.abort();this.element.unbind(".tabs").removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible").removeData("tabs");this.list.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.anchors.each(function(){var h=d.data(this,"href.tabs");if(h){this.href=h}var i=d(this).unbind(".tabs");d.each(["href","load","cache"],function(j,k){i.removeData(k+".tabs")})});this.lis.unbind(".tabs").add(this.panels).each(function(){if(d.data(this,"destroy.tabs")){d(this).remove()}else{d(this).removeClass(["ui-state-default","ui-corner-top","ui-tabs-selected","ui-state-active","ui-state-hover","ui-state-focus","ui-state-disabled","ui-tabs-panel","ui-widget-content","ui-corner-bottom","ui-tabs-hide"].join(" "))}});if(g.cookie){this._cookie(null,g.cookie)}return this},add:function(j,i,h){if(h===f){h=this.anchors.length}var g=this,l=this.options,n=d(l.tabTemplate.replace(/#\{href\}/g,j).replace(/#\{label\}/g,i)),m=!j.indexOf("#")?j.replace("#",""):this._tabId(d("a",n)[0]);n.addClass("ui-state-default ui-corner-top").data("destroy.tabs",true);var k=g.element.find("#"+m);if(!k.length){k=d(l.panelTemplate).attr("id",m).data("destroy.tabs",true)}k.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide");if(h>=this.lis.length){n.appendTo(this.list);k.appendTo(this.list[0].parentNode)}else{n.insertBefore(this.lis[h]);k.insertBefore(this.panels[h])}l.disabled=d.map(l.disabled,function(p,o){return p>=h?++p:p});this._tabify();if(this.anchors.length==1){l.selected=0;n.addClass("ui-tabs-selected ui-state-active");k.removeClass("ui-tabs-hide");this.element.queue("tabs",function(){g._trigger("show",null,g._ui(g.anchors[0],g.panels[0]))});this.load(0)}this._trigger("add",null,this._ui(this.anchors[h],this.panels[h]));return this},remove:function(g){g=this._getIndex(g);var i=this.options,j=this.lis.eq(g).remove(),h=this.panels.eq(g).remove();if(j.hasClass("ui-tabs-selected")&&this.anchors.length>1){this.select(g+(g+1=g?--l:l});this._tabify();this._trigger("remove",null,this._ui(j.find("a")[0],h[0]));return this},enable:function(g){g=this._getIndex(g);var h=this.options;if(d.inArray(g,h.disabled)==-1){return}this.lis.eq(g).removeClass("ui-state-disabled");h.disabled=d.grep(h.disabled,function(k,j){return k!=g});this._trigger("enable",null,this._ui(this.anchors[g],this.panels[g]));return this},disable:function(h){h=this._getIndex(h);var g=this,i=this.options;if(h!=i.selected){this.lis.eq(h).addClass("ui-state-disabled");i.disabled.push(h);i.disabled.sort();this._trigger("disable",null,this._ui(this.anchors[h],this.panels[h]))}return this},select:function(g){g=this._getIndex(g);if(g==-1){if(this.options.collapsible&&this.options.selected!=-1){g=this.options.selected}else{return this}}this.anchors.eq(g).trigger(this.options.event+".tabs");return this},load:function(j){j=this._getIndex(j);var h=this,l=this.options,g=this.anchors.eq(j)[0],i=d.data(g,"load.tabs");this.abort();if(!i||this.element.queue("tabs").length!==0&&d.data(g,"cache.tabs")){this.element.dequeue("tabs");return}this.lis.eq(j).addClass("ui-state-processing");if(l.spinner){var k=d("span",g);k.data("label.tabs",k.html()).html(l.spinner)}this.xhr=d.ajax(d.extend({},l.ajaxOptions,{url:i,success:function(n,m){h.element.find(h._sanitizeSelector(g.hash)).html(n);h._cleanup();if(l.cache){d.data(g,"cache.tabs",true)}h._trigger("load",null,h._ui(h.anchors[j],h.panels[j]));try{l.ajaxOptions.success(n,m)}catch(o){}},error:function(o,m,n){h._cleanup();h._trigger("load",null,h._ui(h.anchors[j],h.panels[j]));try{l.ajaxOptions.error(o,m,j,g)}catch(n){}}}));h.element.dequeue("tabs");return this},abort:function(){this.element.queue([]);this.panels.stop(false,true);this.element.queue("tabs",this.element.queue("tabs").splice(-2,2));if(this.xhr){this.xhr.abort();delete this.xhr}this._cleanup();return this},url:function(h,g){this.anchors.eq(h).removeData("cache.tabs").data("load.tabs",g);return this},length:function(){return this.anchors.length}});d.extend(d.ui.tabs,{version:"1.8.14"});d.extend(d.ui.tabs.prototype,{rotation:null,rotate:function(i,k){var g=this,l=this.options;var h=g._rotate||(g._rotate=function(m){clearTimeout(g.rotation);g.rotation=setTimeout(function(){var n=l.selected;g.select(++n'))}$.extend(Datepicker.prototype,{markerClassName:"hasDatepicker",maxRows:4,log:function(){if(this.debug){console.log.apply("",arguments)}},_widgetDatepicker:function(){return this.dpDiv},setDefaults:function(settings){extendRemove(this._defaults,settings||{});return this},_attachDatepicker:function(target,settings){var inlineSettings=null;for(var attrName in this._defaults){var attrValue=target.getAttribute("date:"+attrName);if(attrValue){inlineSettings=inlineSettings||{};try{inlineSettings[attrName]=eval(attrValue)}catch(err){inlineSettings[attrName]=attrValue}}}var nodeName=target.nodeName.toLowerCase();var inline=(nodeName=="div"||nodeName=="span");if(!target.id){this.uuid+=1;target.id="dp"+this.uuid}var inst=this._newInst($(target),inline);inst.settings=$.extend({},settings||{},inlineSettings||{});if(nodeName=="input"){this._connectDatepicker(target,inst)}else{if(inline){this._inlineDatepicker(target,inst)}}},_newInst:function(target,inline){var id=target[0].id.replace(/([^A-Za-z0-9_-])/g,"\\\\$1");return{id:id,input:target,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:inline,dpDiv:(!inline?this.dpDiv:bindHover($('
    ')))}},_connectDatepicker:function(target,inst){var input=$(target);inst.append=$([]);inst.trigger=$([]);if(input.hasClass(this.markerClassName)){return}this._attachments(input,inst);input.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).keyup(this._doKeyUp).bind("setData.datepicker",function(event,key,value){inst.settings[key]=value}).bind("getData.datepicker",function(event,key){return this._get(inst,key)});this._autoSize(inst);$.data(target,PROP_NAME,inst)},_attachments:function(input,inst){var appendText=this._get(inst,"appendText");var isRTL=this._get(inst,"isRTL");if(inst.append){inst.append.remove()}if(appendText){inst.append=$(''+appendText+"");input[isRTL?"before":"after"](inst.append)}input.unbind("focus",this._showDatepicker);if(inst.trigger){inst.trigger.remove()}var showOn=this._get(inst,"showOn");if(showOn=="focus"||showOn=="both"){input.focus(this._showDatepicker)}if(showOn=="button"||showOn=="both"){var buttonText=this._get(inst,"buttonText");var buttonImage=this._get(inst,"buttonImage");inst.trigger=$(this._get(inst,"buttonImageOnly")?$("").addClass(this._triggerClass).attr({src:buttonImage,alt:buttonText,title:buttonText}):$('').addClass(this._triggerClass).html(buttonImage==""?buttonText:$("").attr({src:buttonImage,alt:buttonText,title:buttonText})));input[isRTL?"before":"after"](inst.trigger);inst.trigger.click(function(){if($.datepicker._datepickerShowing&&$.datepicker._lastInput==input[0]){$.datepicker._hideDatepicker()}else{$.datepicker._showDatepicker(input[0])}return false})}},_autoSize:function(inst){if(this._get(inst,"autoSize")&&!inst.inline){var date=new Date(2009,12-1,20);var dateFormat=this._get(inst,"dateFormat");if(dateFormat.match(/[DM]/)){var findMax=function(names){var max=0;var maxI=0;for(var i=0;imax){max=names[i].length;maxI=i}}return maxI};date.setMonth(findMax(this._get(inst,(dateFormat.match(/MM/)?"monthNames":"monthNamesShort"))));date.setDate(findMax(this._get(inst,(dateFormat.match(/DD/)?"dayNames":"dayNamesShort")))+20-date.getDay())}inst.input.attr("size",this._formatDate(inst,date).length)}},_inlineDatepicker:function(target,inst){var divSpan=$(target);if(divSpan.hasClass(this.markerClassName)){return}divSpan.addClass(this.markerClassName).append(inst.dpDiv).bind("setData.datepicker",function(event,key,value){inst.settings[key]=value}).bind("getData.datepicker",function(event,key){return this._get(inst,key)});$.data(target,PROP_NAME,inst);this._setDate(inst,this._getDefaultDate(inst),true);this._updateDatepicker(inst);this._updateAlternate(inst);inst.dpDiv.show()},_dialogDatepicker:function(input,date,onSelect,settings,pos){var inst=this._dialogInst;if(!inst){this.uuid+=1;var id="dp"+this.uuid;this._dialogInput=$('');this._dialogInput.keydown(this._doKeyDown);$("body").append(this._dialogInput);inst=this._dialogInst=this._newInst(this._dialogInput,false);inst.settings={};$.data(this._dialogInput[0],PROP_NAME,inst)}extendRemove(inst.settings,settings||{});date=(date&&date.constructor==Date?this._formatDate(inst,date):date);this._dialogInput.val(date);this._pos=(pos?(pos.length?pos:[pos.pageX,pos.pageY]):null);if(!this._pos){var browserWidth=document.documentElement.clientWidth;var browserHeight=document.documentElement.clientHeight;var scrollX=document.documentElement.scrollLeft||document.body.scrollLeft;var scrollY=document.documentElement.scrollTop||document.body.scrollTop;this._pos=[(browserWidth/2)-100+scrollX,(browserHeight/2)-150+scrollY]}this._dialogInput.css("left",(this._pos[0]+20)+"px").css("top",this._pos[1]+"px");inst.settings.onSelect=onSelect;this._inDialog=true;this.dpDiv.addClass(this._dialogClass);this._showDatepicker(this._dialogInput[0]);if($.blockUI){$.blockUI(this.dpDiv)}$.data(this._dialogInput[0],PROP_NAME,inst);return this},_destroyDatepicker:function(target){var $target=$(target);var inst=$.data(target,PROP_NAME);if(!$target.hasClass(this.markerClassName)){return}var nodeName=target.nodeName.toLowerCase();$.removeData(target,PROP_NAME);if(nodeName=="input"){inst.append.remove();inst.trigger.remove();$target.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",this._doKeyUp)}else{if(nodeName=="div"||nodeName=="span"){$target.removeClass(this.markerClassName).empty()}}},_enableDatepicker:function(target){var $target=$(target);var inst=$.data(target,PROP_NAME);if(!$target.hasClass(this.markerClassName)){return}var nodeName=target.nodeName.toLowerCase();if(nodeName=="input"){target.disabled=false;inst.trigger.filter("button").each(function(){this.disabled=false}).end().filter("img").css({opacity:"1.0",cursor:""})}else{if(nodeName=="div"||nodeName=="span"){var inline=$target.children("."+this._inlineClass);inline.children().removeClass("ui-state-disabled");inline.find("select.ui-datepicker-month, select.ui-datepicker-year").removeAttr("disabled")}}this._disabledInputs=$.map(this._disabledInputs,function(value){return(value==target?null:value)})},_disableDatepicker:function(target){var $target=$(target);var inst=$.data(target,PROP_NAME);if(!$target.hasClass(this.markerClassName)){return}var nodeName=target.nodeName.toLowerCase();if(nodeName=="input"){target.disabled=true;inst.trigger.filter("button").each(function(){this.disabled=true}).end().filter("img").css({opacity:"0.5",cursor:"default"})}else{if(nodeName=="div"||nodeName=="span"){var inline=$target.children("."+this._inlineClass);inline.children().addClass("ui-state-disabled");inline.find("select.ui-datepicker-month, select.ui-datepicker-year").attr("disabled","disabled")}}this._disabledInputs=$.map(this._disabledInputs,function(value){return(value==target?null:value)});this._disabledInputs[this._disabledInputs.length]=target},_isDisabledDatepicker:function(target){if(!target){return false}for(var i=0;i-1)}},_doKeyUp:function(event){var inst=$.datepicker._getInst(event.target);if(inst.input.val()!=inst.lastVal){try{var date=$.datepicker.parseDate($.datepicker._get(inst,"dateFormat"),(inst.input?inst.input.val():null),$.datepicker._getFormatConfig(inst));if(date){$.datepicker._setDateFromField(inst);$.datepicker._updateAlternate(inst);$.datepicker._updateDatepicker(inst)}}catch(event){$.datepicker.log(event)}}return true},_showDatepicker:function(input){input=input.target||input;if(input.nodeName.toLowerCase()!="input"){input=$("input",input.parentNode)[0]}if($.datepicker._isDisabledDatepicker(input)||$.datepicker._lastInput==input){return}var inst=$.datepicker._getInst(input);if($.datepicker._curInst&&$.datepicker._curInst!=inst){if($.datepicker._datepickerShowing){$.datepicker._triggerOnClose($.datepicker._curInst)}$.datepicker._curInst.dpDiv.stop(true,true)}var beforeShow=$.datepicker._get(inst,"beforeShow");extendRemove(inst.settings,(beforeShow?beforeShow.apply(input,[input,inst]):{}));inst.lastVal=null;$.datepicker._lastInput=input;$.datepicker._setDateFromField(inst);if($.datepicker._inDialog){input.value=""}if(!$.datepicker._pos){$.datepicker._pos=$.datepicker._findPos(input);$.datepicker._pos[1]+=input.offsetHeight}var isFixed=false;$(input).parents().each(function(){isFixed|=$(this).css("position")=="fixed";return !isFixed});if(isFixed&&$.browser.opera){$.datepicker._pos[0]-=document.documentElement.scrollLeft;$.datepicker._pos[1]-=document.documentElement.scrollTop}var offset={left:$.datepicker._pos[0],top:$.datepicker._pos[1]};$.datepicker._pos=null;inst.dpDiv.empty();inst.dpDiv.css({position:"absolute",display:"block",top:"-1000px"});$.datepicker._updateDatepicker(inst);offset=$.datepicker._checkOffset(inst,offset,isFixed);inst.dpDiv.css({position:($.datepicker._inDialog&&$.blockUI?"static":(isFixed?"fixed":"absolute")),display:"none",left:offset.left+"px",top:offset.top+"px"});if(!inst.inline){var showAnim=$.datepicker._get(inst,"showAnim");var duration=$.datepicker._get(inst,"duration");var postProcess=function(){var cover=inst.dpDiv.find("iframe.ui-datepicker-cover");if(!!cover.length){var borders=$.datepicker._getBorders(inst.dpDiv);cover.css({left:-borders[0],top:-borders[1],width:inst.dpDiv.outerWidth(),height:inst.dpDiv.outerHeight()})}};inst.dpDiv.zIndex($(input).zIndex()+1);$.datepicker._datepickerShowing=true;if($.effects&&$.effects[showAnim]){inst.dpDiv.show(showAnim,$.datepicker._get(inst,"showOptions"),duration,postProcess)}else{inst.dpDiv[showAnim||"show"]((showAnim?duration:null),postProcess)}if(!showAnim||!duration){postProcess()}if(inst.input.is(":visible")&&!inst.input.is(":disabled")){inst.input.focus()}$.datepicker._curInst=inst}},_updateDatepicker:function(inst){var self=this;self.maxRows=4;var borders=$.datepicker._getBorders(inst.dpDiv);instActive=inst;inst.dpDiv.empty().append(this._generateHTML(inst));var cover=inst.dpDiv.find("iframe.ui-datepicker-cover");if(!!cover.length){cover.css({left:-borders[0],top:-borders[1],width:inst.dpDiv.outerWidth(),height:inst.dpDiv.outerHeight()})}inst.dpDiv.find("."+this._dayOverClass+" a").mouseover();var numMonths=this._getNumberOfMonths(inst);var cols=numMonths[1];var width=17;inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");if(cols>1){inst.dpDiv.addClass("ui-datepicker-multi-"+cols).css("width",(width*cols)+"em")}inst.dpDiv[(numMonths[0]!=1||numMonths[1]!=1?"add":"remove")+"Class"]("ui-datepicker-multi");inst.dpDiv[(this._get(inst,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl");if(inst==$.datepicker._curInst&&$.datepicker._datepickerShowing&&inst.input&&inst.input.is(":visible")&&!inst.input.is(":disabled")&&inst.input[0]!=document.activeElement){inst.input.focus()}if(inst.yearshtml){var origyearshtml=inst.yearshtml;setTimeout(function(){if(origyearshtml===inst.yearshtml&&inst.yearshtml){inst.dpDiv.find("select.ui-datepicker-year:first").replaceWith(inst.yearshtml)}origyearshtml=inst.yearshtml=null},0)}},_getBorders:function(elem){var convert=function(value){return{thin:1,medium:2,thick:3}[value]||value};return[parseFloat(convert(elem.css("border-left-width"))),parseFloat(convert(elem.css("border-top-width")))]},_checkOffset:function(inst,offset,isFixed){var dpWidth=inst.dpDiv.outerWidth();var dpHeight=inst.dpDiv.outerHeight();var inputWidth=inst.input?inst.input.outerWidth():0;var inputHeight=inst.input?inst.input.outerHeight():0;var viewWidth=document.documentElement.clientWidth+$(document).scrollLeft();var viewHeight=document.documentElement.clientHeight+$(document).scrollTop();offset.left-=(this._get(inst,"isRTL")?(dpWidth-inputWidth):0);offset.left-=(isFixed&&offset.left==inst.input.offset().left)?$(document).scrollLeft():0;offset.top-=(isFixed&&offset.top==(inst.input.offset().top+inputHeight))?$(document).scrollTop():0;offset.left-=Math.min(offset.left,(offset.left+dpWidth>viewWidth&&viewWidth>dpWidth)?Math.abs(offset.left+dpWidth-viewWidth):0);offset.top-=Math.min(offset.top,(offset.top+dpHeight>viewHeight&&viewHeight>dpHeight)?Math.abs(dpHeight+inputHeight):0);return offset},_findPos:function(obj){var inst=this._getInst(obj);var isRTL=this._get(inst,"isRTL");while(obj&&(obj.type=="hidden"||obj.nodeType!=1||$.expr.filters.hidden(obj))){obj=obj[isRTL?"previousSibling":"nextSibling"]}var position=$(obj).offset();return[position.left,position.top]},_triggerOnClose:function(inst){var onClose=this._get(inst,"onClose");if(onClose){onClose.apply((inst.input?inst.input[0]:null),[(inst.input?inst.input.val():""),inst])}},_hideDatepicker:function(input){var inst=this._curInst;if(!inst||(input&&inst!=$.data(input,PROP_NAME))){return}if(this._datepickerShowing){var showAnim=this._get(inst,"showAnim");var duration=this._get(inst,"duration");var postProcess=function(){$.datepicker._tidyDialog(inst);this._curInst=null};if($.effects&&$.effects[showAnim]){inst.dpDiv.hide(showAnim,$.datepicker._get(inst,"showOptions"),duration,postProcess)}else{inst.dpDiv[(showAnim=="slideDown"?"slideUp":(showAnim=="fadeIn"?"fadeOut":"hide"))]((showAnim?duration:null),postProcess)}if(!showAnim){postProcess()}$.datepicker._triggerOnClose(inst);this._datepickerShowing=false;this._lastInput=null;if(this._inDialog){this._dialogInput.css({position:"absolute",left:"0",top:"-100px"});if($.blockUI){$.unblockUI();$("body").append(this.dpDiv)}}this._inDialog=false}},_tidyDialog:function(inst){inst.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},_checkExternalClick:function(event){if(!$.datepicker._curInst){return}var $target=$(event.target);if($target[0].id!=$.datepicker._mainDivId&&$target.parents("#"+$.datepicker._mainDivId).length==0&&!$target.hasClass($.datepicker.markerClassName)&&!$target.hasClass($.datepicker._triggerClass)&&$.datepicker._datepickerShowing&&!($.datepicker._inDialog&&$.blockUI)){$.datepicker._hideDatepicker()}},_adjustDate:function(id,offset,period){var target=$(id);var inst=this._getInst(target[0]);if(this._isDisabledDatepicker(target[0])){return}this._adjustInstDate(inst,offset+(period=="M"?this._get(inst,"showCurrentAtPos"):0),period);this._updateDatepicker(inst)},_gotoToday:function(id){var target=$(id);var inst=this._getInst(target[0]);if(this._get(inst,"gotoCurrent")&&inst.currentDay){inst.selectedDay=inst.currentDay;inst.drawMonth=inst.selectedMonth=inst.currentMonth;inst.drawYear=inst.selectedYear=inst.currentYear}else{var date=new Date();inst.selectedDay=date.getDate();inst.drawMonth=inst.selectedMonth=date.getMonth();inst.drawYear=inst.selectedYear=date.getFullYear()}this._notifyChange(inst);this._adjustDate(target)},_selectMonthYear:function(id,select,period){var target=$(id);var inst=this._getInst(target[0]);inst._selectingMonthYear=false;inst["selected"+(period=="M"?"Month":"Year")]=inst["draw"+(period=="M"?"Month":"Year")]=parseInt(select.options[select.selectedIndex].value,10);this._notifyChange(inst);this._adjustDate(target)},_clickMonthYear:function(id){var target=$(id);var inst=this._getInst(target[0]);if(inst.input&&inst._selectingMonthYear){setTimeout(function(){inst.input.focus()},0)}inst._selectingMonthYear=!inst._selectingMonthYear},_selectDay:function(id,month,year,td){var target=$(id);if($(td).hasClass(this._unselectableClass)||this._isDisabledDatepicker(target[0])){return}var inst=this._getInst(target[0]);inst.selectedDay=inst.currentDay=$("a",td).html();inst.selectedMonth=inst.currentMonth=month;inst.selectedYear=inst.currentYear=year;this._selectDate(id,this._formatDate(inst,inst.currentDay,inst.currentMonth,inst.currentYear))},_clearDate:function(id){var target=$(id);var inst=this._getInst(target[0]);this._selectDate(target,"")},_selectDate:function(id,dateStr){var target=$(id);var inst=this._getInst(target[0]);dateStr=(dateStr!=null?dateStr:this._formatDate(inst));if(inst.input){inst.input.val(dateStr)}this._updateAlternate(inst);var onSelect=this._get(inst,"onSelect");if(onSelect){onSelect.apply((inst.input?inst.input[0]:null),[dateStr,inst])}else{if(inst.input){inst.input.trigger("change")}}if(inst.inline){this._updateDatepicker(inst)}else{this._hideDatepicker();this._lastInput=inst.input[0];if(typeof(inst.input[0])!="object"){inst.input.focus()}this._lastInput=null}},_updateAlternate:function(inst){var altField=this._get(inst,"altField");if(altField){var altFormat=this._get(inst,"altFormat")||this._get(inst,"dateFormat");var date=this._getDate(inst);var dateStr=this.formatDate(altFormat,date,this._getFormatConfig(inst));$(altField).each(function(){$(this).val(dateStr)})}},noWeekends:function(date){var day=date.getDay();return[(day>0&&day<6),""]},iso8601Week:function(date){var checkDate=new Date(date.getTime());checkDate.setDate(checkDate.getDate()+4-(checkDate.getDay()||7));var time=checkDate.getTime();checkDate.setMonth(0);checkDate.setDate(1);return Math.floor(Math.round((time-checkDate)/86400000)/7)+1},parseDate:function(format,value,settings){if(format==null||value==null){throw"Invalid arguments"}value=(typeof value=="object"?value.toString():value+"");if(value==""){return null}var shortYearCutoff=(settings?settings.shortYearCutoff:null)||this._defaults.shortYearCutoff;shortYearCutoff=(typeof shortYearCutoff!="string"?shortYearCutoff:new Date().getFullYear()%100+parseInt(shortYearCutoff,10));var dayNamesShort=(settings?settings.dayNamesShort:null)||this._defaults.dayNamesShort;var dayNames=(settings?settings.dayNames:null)||this._defaults.dayNames;var monthNamesShort=(settings?settings.monthNamesShort:null)||this._defaults.monthNamesShort;var monthNames=(settings?settings.monthNames:null)||this._defaults.monthNames;var year=-1;var month=-1;var day=-1;var doy=-1;var literal=false;var lookAhead=function(match){var matches=(iFormat+1-1){month=1;day=doy;do{var dim=this._getDaysInMonth(year,month-1);if(day<=dim){break}month++;day-=dim}while(true)}var date=this._daylightSavingAdjust(new Date(year,month-1,day));if(date.getFullYear()!=year||date.getMonth()+1!=month||date.getDate()!=day){throw"Invalid date"}return date},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:(((1970-1)*365+Math.floor(1970/4)-Math.floor(1970/100)+Math.floor(1970/400))*24*60*60*10000000),formatDate:function(format,date,settings){if(!date){return""}var dayNamesShort=(settings?settings.dayNamesShort:null)||this._defaults.dayNamesShort;var dayNames=(settings?settings.dayNames:null)||this._defaults.dayNames;var monthNamesShort=(settings?settings.monthNamesShort:null)||this._defaults.monthNamesShort;var monthNames=(settings?settings.monthNames:null)||this._defaults.monthNames;var lookAhead=function(match){var matches=(iFormat+112?date.getHours()+2:0);return date},_setDate:function(inst,date,noChange){var clear=!date;var origMonth=inst.selectedMonth;var origYear=inst.selectedYear;var newDate=this._restrictMinMax(inst,this._determineDate(inst,date,new Date()));inst.selectedDay=inst.currentDay=newDate.getDate();inst.drawMonth=inst.selectedMonth=inst.currentMonth=newDate.getMonth();inst.drawYear=inst.selectedYear=inst.currentYear=newDate.getFullYear();if((origMonth!=inst.selectedMonth||origYear!=inst.selectedYear)&&!noChange){this._notifyChange(inst)}this._adjustInstDate(inst);if(inst.input){inst.input.val(clear?"":this._formatDate(inst))}},_getDate:function(inst){var startDate=(!inst.currentYear||(inst.input&&inst.input.val()=="")?null:this._daylightSavingAdjust(new Date(inst.currentYear,inst.currentMonth,inst.currentDay)));return startDate},_generateHTML:function(inst){var today=new Date();today=this._daylightSavingAdjust(new Date(today.getFullYear(),today.getMonth(),today.getDate()));var isRTL=this._get(inst,"isRTL");var showButtonPanel=this._get(inst,"showButtonPanel");var hideIfNoPrevNext=this._get(inst,"hideIfNoPrevNext");var navigationAsDateFormat=this._get(inst,"navigationAsDateFormat");var numMonths=this._getNumberOfMonths(inst);var showCurrentAtPos=this._get(inst,"showCurrentAtPos");var stepMonths=this._get(inst,"stepMonths");var isMultiMonth=(numMonths[0]!=1||numMonths[1]!=1);var currentDate=this._daylightSavingAdjust((!inst.currentDay?new Date(9999,9,9):new Date(inst.currentYear,inst.currentMonth,inst.currentDay)));var minDate=this._getMinMaxDate(inst,"min");var maxDate=this._getMinMaxDate(inst,"max");var drawMonth=inst.drawMonth-showCurrentAtPos;var drawYear=inst.drawYear;if(drawMonth<0){drawMonth+=12;drawYear--}if(maxDate){var maxDraw=this._daylightSavingAdjust(new Date(maxDate.getFullYear(),maxDate.getMonth()-(numMonths[0]*numMonths[1])+1,maxDate.getDate()));maxDraw=(minDate&&maxDrawmaxDraw){drawMonth--;if(drawMonth<0){drawMonth=11;drawYear--}}}inst.drawMonth=drawMonth;inst.drawYear=drawYear;var prevText=this._get(inst,"prevText");prevText=(!navigationAsDateFormat?prevText:this.formatDate(prevText,this._daylightSavingAdjust(new Date(drawYear,drawMonth-stepMonths,1)),this._getFormatConfig(inst)));var prev=(this._canAdjustMonth(inst,-1,drawYear,drawMonth)?''+prevText+"":(hideIfNoPrevNext?"":''+prevText+""));var nextText=this._get(inst,"nextText");nextText=(!navigationAsDateFormat?nextText:this.formatDate(nextText,this._daylightSavingAdjust(new Date(drawYear,drawMonth+stepMonths,1)),this._getFormatConfig(inst)));var next=(this._canAdjustMonth(inst,+1,drawYear,drawMonth)?''+nextText+"":(hideIfNoPrevNext?"":''+nextText+""));var currentText=this._get(inst,"currentText");var gotoDate=(this._get(inst,"gotoCurrent")&&inst.currentDay?currentDate:today);currentText=(!navigationAsDateFormat?currentText:this.formatDate(currentText,gotoDate,this._getFormatConfig(inst)));var controls=(!inst.inline?'":"");var buttonPanel=(showButtonPanel)?'
    '+(isRTL?controls:"")+(this._isInRange(inst,gotoDate)?'":"")+(isRTL?"":controls)+"
    ":"";var firstDay=parseInt(this._get(inst,"firstDay"),10);firstDay=(isNaN(firstDay)?0:firstDay);var showWeek=this._get(inst,"showWeek");var dayNames=this._get(inst,"dayNames");var dayNamesShort=this._get(inst,"dayNamesShort");var dayNamesMin=this._get(inst,"dayNamesMin");var monthNames=this._get(inst,"monthNames");var monthNamesShort=this._get(inst,"monthNamesShort");var beforeShowDay=this._get(inst,"beforeShowDay");var showOtherMonths=this._get(inst,"showOtherMonths");var selectOtherMonths=this._get(inst,"selectOtherMonths");var calculateWeek=this._get(inst,"calculateWeek")||this.iso8601Week;var defaultDate=this._getDefaultDate(inst);var html="";for(var row=0;row1){switch(col){case 0:calender+=" ui-datepicker-group-first";cornerClass=" ui-corner-"+(isRTL?"right":"left");break;case numMonths[1]-1:calender+=" ui-datepicker-group-last";cornerClass=" ui-corner-"+(isRTL?"left":"right");break;default:calender+=" ui-datepicker-group-middle";cornerClass="";break}}calender+='">'}calender+='
    '+(/all|left/.test(cornerClass)&&row==0?(isRTL?next:prev):"")+(/all|right/.test(cornerClass)&&row==0?(isRTL?prev:next):"")+this._generateMonthYearHeader(inst,drawMonth,drawYear,minDate,maxDate,row>0||col>0,monthNames,monthNamesShort)+'
    ';var thead=(showWeek?'":"");for(var dow=0;dow<7;dow++){var day=(dow+firstDay)%7;thead+="=5?' class="ui-datepicker-week-end"':"")+'>'+dayNamesMin[day]+""}calender+=thead+"";var daysInMonth=this._getDaysInMonth(drawYear,drawMonth);if(drawYear==inst.selectedYear&&drawMonth==inst.selectedMonth){inst.selectedDay=Math.min(inst.selectedDay,daysInMonth)}var leadDays=(this._getFirstDayOfMonth(drawYear,drawMonth)-firstDay+7)%7;var curRows=Math.ceil((leadDays+daysInMonth)/7);var numRows=(isMultiMonth?this.maxRows>curRows?this.maxRows:curRows:curRows);this.maxRows=numRows;var printDate=this._daylightSavingAdjust(new Date(drawYear,drawMonth,1-leadDays));for(var dRow=0;dRow";var tbody=(!showWeek?"":'");for(var dow=0;dow<7;dow++){var daySettings=(beforeShowDay?beforeShowDay.apply((inst.input?inst.input[0]:null),[printDate]):[true,""]);var otherMonth=(printDate.getMonth()!=drawMonth);var unselectable=(otherMonth&&!selectOtherMonths)||!daySettings[0]||(minDate&&printDatemaxDate);tbody+='";printDate.setDate(printDate.getDate()+1);printDate=this._daylightSavingAdjust(printDate)}calender+=tbody+""}drawMonth++;if(drawMonth>11){drawMonth=0;drawYear++}calender+="
    '+this._get(inst,"weekHeader")+"
    '+this._get(inst,"calculateWeek")(printDate)+""+(otherMonth&&!showOtherMonths?" ":(unselectable?''+printDate.getDate()+"":''+printDate.getDate()+""))+"
    "+(isMultiMonth?""+((numMonths[0]>0&&col==numMonths[1]-1)?'
    ':""):"");group+=calender}html+=group}html+=buttonPanel+($.browser.msie&&parseInt($.browser.version,10)<7&&!inst.inline?'':"");inst._keyEvent=false;return html},_generateMonthYearHeader:function(inst,drawMonth,drawYear,minDate,maxDate,secondary,monthNames,monthNamesShort){var changeMonth=this._get(inst,"changeMonth");var changeYear=this._get(inst,"changeYear");var showMonthAfterYear=this._get(inst,"showMonthAfterYear");var html='
    ';var monthHtml="";if(secondary||!changeMonth){monthHtml+=''+monthNames[drawMonth]+""}else{var inMinYear=(minDate&&minDate.getFullYear()==drawYear);var inMaxYear=(maxDate&&maxDate.getFullYear()==drawYear);monthHtml+='"}if(!showMonthAfterYear){html+=monthHtml+(secondary||!(changeMonth&&changeYear)?" ":"")}if(!inst.yearshtml){inst.yearshtml="";if(secondary||!changeYear){html+=''+drawYear+""}else{var years=this._get(inst,"yearRange").split(":");var thisYear=new Date().getFullYear();var determineYear=function(value){var year=(value.match(/c[+-].*/)?drawYear+parseInt(value.substring(1),10):(value.match(/[+-].*/)?thisYear+parseInt(value,10):parseInt(value,10)));return(isNaN(year)?thisYear:year)};var year=determineYear(years[0]);var endYear=Math.max(year,determineYear(years[1]||""));year=(minDate?Math.max(year,minDate.getFullYear()):year);endYear=(maxDate?Math.min(endYear,maxDate.getFullYear()):endYear);inst.yearshtml+='";html+=inst.yearshtml;inst.yearshtml=null}}html+=this._get(inst,"yearSuffix");if(showMonthAfterYear){html+=(secondary||!(changeMonth&&changeYear)?" ":"")+monthHtml}html+="
    ";return html},_adjustInstDate:function(inst,offset,period){var year=inst.drawYear+(period=="Y"?offset:0);var month=inst.drawMonth+(period=="M"?offset:0);var day=Math.min(inst.selectedDay,this._getDaysInMonth(year,month))+(period=="D"?offset:0);var date=this._restrictMinMax(inst,this._daylightSavingAdjust(new Date(year,month,day)));inst.selectedDay=date.getDate();inst.drawMonth=inst.selectedMonth=date.getMonth();inst.drawYear=inst.selectedYear=date.getFullYear();if(period=="M"||period=="Y"){this._notifyChange(inst)}},_restrictMinMax:function(inst,date){var minDate=this._getMinMaxDate(inst,"min");var maxDate=this._getMinMaxDate(inst,"max");var newDate=(minDate&&datemaxDate?maxDate:newDate);return newDate},_notifyChange:function(inst){var onChange=this._get(inst,"onChangeMonthYear");if(onChange){onChange.apply((inst.input?inst.input[0]:null),[inst.selectedYear,inst.selectedMonth+1,inst])}},_getNumberOfMonths:function(inst){var numMonths=this._get(inst,"numberOfMonths");return(numMonths==null?[1,1]:(typeof numMonths=="number"?[1,numMonths]:numMonths))},_getMinMaxDate:function(inst,minMax){return this._determineDate(inst,this._get(inst,minMax+"Date"),null)},_getDaysInMonth:function(year,month){return 32-this._daylightSavingAdjust(new Date(year,month,32)).getDate()},_getFirstDayOfMonth:function(year,month){return new Date(year,month,1).getDay()},_canAdjustMonth:function(inst,offset,curYear,curMonth){var numMonths=this._getNumberOfMonths(inst);var date=this._daylightSavingAdjust(new Date(curYear,curMonth+(offset<0?offset:numMonths[0]*numMonths[1]),1));if(offset<0){date.setDate(this._getDaysInMonth(date.getFullYear(),date.getMonth()))}return this._isInRange(inst,date)},_isInRange:function(inst,date){var minDate=this._getMinMaxDate(inst,"min");var maxDate=this._getMinMaxDate(inst,"max");return((!minDate||date.getTime()>=minDate.getTime())&&(!maxDate||date.getTime()<=maxDate.getTime()))},_getFormatConfig:function(inst){var shortYearCutoff=this._get(inst,"shortYearCutoff");shortYearCutoff=(typeof shortYearCutoff!="string"?shortYearCutoff:new Date().getFullYear()%100+parseInt(shortYearCutoff,10));return{shortYearCutoff:shortYearCutoff,dayNamesShort:this._get(inst,"dayNamesShort"),dayNames:this._get(inst,"dayNames"),monthNamesShort:this._get(inst,"monthNamesShort"),monthNames:this._get(inst,"monthNames")}},_formatDate:function(inst,day,month,year){if(!day){inst.currentDay=inst.selectedDay;inst.currentMonth=inst.selectedMonth;inst.currentYear=inst.selectedYear}var date=(day?(typeof day=="object"?day:this._daylightSavingAdjust(new Date(year,month,day))):this._daylightSavingAdjust(new Date(inst.currentYear,inst.currentMonth,inst.currentDay)));return this.formatDate(this._get(inst,"dateFormat"),date,this._getFormatConfig(inst))}});function bindHover(dpDiv){var selector="button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";return dpDiv.bind("mouseout",function(event){var elem=$(event.target).closest(selector);if(!elem.length){return}elem.removeClass("ui-state-hover ui-datepicker-prev-hover ui-datepicker-next-hover")}).bind("mouseover",function(event){var elem=$(event.target).closest(selector);if($.datepicker._isDisabledDatepicker(instActive.inline?dpDiv.parent()[0]:instActive.input[0])||!elem.length){return}elem.parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");elem.addClass("ui-state-hover");if(elem.hasClass("ui-datepicker-prev")){elem.addClass("ui-datepicker-prev-hover")}if(elem.hasClass("ui-datepicker-next")){elem.addClass("ui-datepicker-next-hover")}})}function extendRemove(target,props){$.extend(target,props);for(var name in props){if(props[name]==null||props[name]==undefined){target[name]=props[name]}}return target}function isArray(a){return(a&&(($.browser.safari&&typeof a=="object"&&a.length)||(a.constructor&&a.constructor.toString().match(/\Array\(\)/))))}$.fn.datepicker=function(options){if(!this.length){return this}if(!$.datepicker.initialized){$(document).mousedown($.datepicker._checkExternalClick).find("body").append($.datepicker.dpDiv);$.datepicker.initialized=true}var otherArgs=Array.prototype.slice.call(arguments,1);if(typeof options=="string"&&(options=="isDisabled"||options=="getDate"||options=="widget")){return $.datepicker["_"+options+"Datepicker"].apply($.datepicker,[this[0]].concat(otherArgs))}if(options=="option"&&arguments.length==2&&typeof arguments[1]=="string"){return $.datepicker["_"+options+"Datepicker"].apply($.datepicker,[this[0]].concat(otherArgs))}return this.each(function(){typeof options=="string"?$.datepicker["_"+options+"Datepicker"].apply($.datepicker,[this].concat(otherArgs)):$.datepicker._attachDatepicker(this,options)})};$.datepicker=new Datepicker();$.datepicker.initialized=false;$.datepicker.uuid=new Date().getTime();$.datepicker.version="1.8.14";window["DP_jQuery_"+dpuuid]=$})(jQuery);(function(a,b){a.widget("ui.progressbar",{options:{value:0,max:100},min:0,_create:function(){this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min,"aria-valuemax":this.options.max,"aria-valuenow":this._value()});this.valueDiv=a("
    ").appendTo(this.element);this.oldValue=this._value();this._refreshValue()},destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow");this.valueDiv.remove();a.Widget.prototype.destroy.apply(this,arguments)},value:function(c){if(c===b){return this._value()}this._setOption("value",c);return this},_setOption:function(c,d){if(c==="value"){this.options.value=d;this._refreshValue();if(this._value()===this.options.max){this._trigger("complete")}}a.Widget.prototype._setOption.apply(this,arguments)},_value:function(){var c=this.options.value;if(typeof c!=="number"){c=0}return Math.min(this.options.max,Math.max(this.min,c))},_percentage:function(){return 100*this._value()/this.options.max},_refreshValue:function(){var d=this.value();var c=this._percentage();if(this.oldValue!==d){this.oldValue=d;this._trigger("change")}this.valueDiv.toggle(d>this.min).toggleClass("ui-corner-right",d===this.options.max).width(c.toFixed(0)+"%");this.element.attr("aria-valuenow",d)}});a.extend(a.ui.progressbar,{version:"1.8.14"})})(jQuery);jQuery.effects||(function(h,e){h.effects={};h.each(["backgroundColor","borderBottomColor","borderLeftColor","borderRightColor","borderTopColor","borderColor","color","outlineColor"],function(n,m){h.fx.step[m]=function(o){if(!o.colorInit){o.start=l(o.elem,m);o.end=j(o.end);o.colorInit=true}o.elem.style[m]="rgb("+Math.max(Math.min(parseInt((o.pos*(o.end[0]-o.start[0]))+o.start[0],10),255),0)+","+Math.max(Math.min(parseInt((o.pos*(o.end[1]-o.start[1]))+o.start[1],10),255),0)+","+Math.max(Math.min(parseInt((o.pos*(o.end[2]-o.start[2]))+o.start[2],10),255),0)+")"}});function j(n){var m;if(n&&n.constructor==Array&&n.length==3){return n}if(m=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(n)){return[parseInt(m[1],10),parseInt(m[2],10),parseInt(m[3],10)]}if(m=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(n)){return[parseFloat(m[1])*2.55,parseFloat(m[2])*2.55,parseFloat(m[3])*2.55]}if(m=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(n)){return[parseInt(m[1],16),parseInt(m[2],16),parseInt(m[3],16)]}if(m=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(n)){return[parseInt(m[1]+m[1],16),parseInt(m[2]+m[2],16),parseInt(m[3]+m[3],16)]}if(m=/rgba\(0, 0, 0, 0\)/.exec(n)){return a.transparent}return a[h.trim(n).toLowerCase()]}function l(o,m){var n;do{n=h.curCSS(o,m);if(n!=""&&n!="transparent"||h.nodeName(o,"body")){break}m="backgroundColor"}while(o=o.parentNode);return j(n)}var a={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0],transparent:[255,255,255]};var f=["add","remove","toggle"],c={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};function g(){var p=document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle,q={},n,o;if(p&&p.length&&p[0]&&p[p[0]]){var m=p.length;while(m--){n=p[m];if(typeof p[n]=="string"){o=n.replace(/\-(\w)/g,function(r,s){return s.toUpperCase()});q[o]=p[n]}}}else{for(n in p){if(typeof p[n]==="string"){q[n]=p[n]}}}return q}function b(n){var m,o;for(m in n){o=n[m];if(o==null||h.isFunction(o)||m in c||(/scrollbar/).test(m)||(!(/color/i).test(m)&&isNaN(parseFloat(o)))){delete n[m]}}return n}function i(m,o){var p={_:0},n;for(n in o){if(m[n]!=o[n]){p[n]=o[n]}}return p}h.effects.animateClass=function(m,n,p,o){if(h.isFunction(p)){o=p;p=null}return this.queue(function(){var u=h(this),q=u.attr("style")||" ",v=b(g.call(this)),s,r=u.attr("class");h.each(f,function(w,x){if(m[x]){u[x+"Class"](m[x])}});s=b(g.call(this));u.attr("class",r);u.animate(i(v,s),{queue:false,duration:n,easing:p,complete:function(){h.each(f,function(w,x){if(m[x]){u[x+"Class"](m[x])}});if(typeof u.attr("style")=="object"){u.attr("style").cssText="";u.attr("style").cssText=q}else{u.attr("style",q)}if(o){o.apply(this,arguments)}h.dequeue(this)}})})};h.fn.extend({_addClass:h.fn.addClass,addClass:function(n,m,p,o){return m?h.effects.animateClass.apply(this,[{add:n},m,p,o]):this._addClass(n)},_removeClass:h.fn.removeClass,removeClass:function(n,m,p,o){return m?h.effects.animateClass.apply(this,[{remove:n},m,p,o]):this._removeClass(n)},_toggleClass:h.fn.toggleClass,toggleClass:function(o,n,m,q,p){if(typeof n=="boolean"||n===e){if(!m){return this._toggleClass(o,n)}else{return h.effects.animateClass.apply(this,[(n?{add:o}:{remove:o}),m,q,p])}}else{return h.effects.animateClass.apply(this,[{toggle:o},n,m,q])}},switchClass:function(m,o,n,q,p){return h.effects.animateClass.apply(this,[{add:o,remove:m},n,q,p])}});h.extend(h.effects,{version:"1.8.14",save:function(n,o){for(var m=0;m").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0});m.wrap(o);o=m.parent();if(m.css("position")=="static"){o.css({position:"relative"});m.css({position:"relative"})}else{h.extend(n,{position:m.css("position"),zIndex:m.css("z-index")});h.each(["top","left","bottom","right"],function(p,q){n[q]=m.css(q);if(isNaN(parseInt(n[q],10))){n[q]="auto"}});m.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})}return o.css(n).show()},removeWrapper:function(m){if(m.parent().is(".ui-effects-wrapper")){return m.parent().replaceWith(m)}return m},setTransition:function(n,p,m,o){o=o||{};h.each(p,function(r,q){unit=n.cssUnit(q);if(unit[0]>0){o[q]=unit[0]*m+unit[1]}});return o}});function d(n,m,o,p){if(typeof n=="object"){p=m;o=null;m=n;n=m.effect}if(h.isFunction(m)){p=m;o=null;m={}}if(typeof m=="number"||h.fx.speeds[m]){p=o;o=m;m={}}if(h.isFunction(o)){p=o;o=null}m=m||{};o=o||m.duration;o=h.fx.off?0:typeof o=="number"?o:o in h.fx.speeds?h.fx.speeds[o]:h.fx.speeds._default;p=p||m.complete;return[n,m,o,p]}function k(m){if(!m||typeof m==="number"||h.fx.speeds[m]){return true}if(typeof m==="string"&&!h.effects[m]){return true}return false}h.fn.extend({effect:function(p,o,r,u){var n=d.apply(this,arguments),q={options:n[1],duration:n[2],callback:n[3]},s=q.options.mode,m=h.effects[p];if(h.fx.off||!m){if(s){return this[s](q.duration,q.callback)}else{return this.each(function(){if(q.callback){q.callback.call(this)}})}}return m.call(this,q)},_show:h.fn.show,show:function(n){if(k(n)){return this._show.apply(this,arguments)}else{var m=d.apply(this,arguments);m[1].mode="show";return this.effect.apply(this,m)}},_hide:h.fn.hide,hide:function(n){if(k(n)){return this._hide.apply(this,arguments)}else{var m=d.apply(this,arguments);m[1].mode="hide";return this.effect.apply(this,m)}},__toggle:h.fn.toggle,toggle:function(n){if(k(n)||typeof n==="boolean"||h.isFunction(n)){return this.__toggle.apply(this,arguments)}else{var m=d.apply(this,arguments);m[1].mode="toggle";return this.effect.apply(this,m)}},cssUnit:function(m){var n=this.css(m),o=[];h.each(["em","px","%","pt"],function(p,q){if(n.indexOf(q)>0){o=[parseFloat(n),q]}});return o}});h.easing.jswing=h.easing.swing;h.extend(h.easing,{def:"easeOutQuad",swing:function(n,o,m,q,p){return h.easing[h.easing.def](n,o,m,q,p)},easeInQuad:function(n,o,m,q,p){return q*(o/=p)*o+m},easeOutQuad:function(n,o,m,q,p){return -q*(o/=p)*(o-2)+m},easeInOutQuad:function(n,o,m,q,p){if((o/=p/2)<1){return q/2*o*o+m}return -q/2*((--o)*(o-2)-1)+m},easeInCubic:function(n,o,m,q,p){return q*(o/=p)*o*o+m},easeOutCubic:function(n,o,m,q,p){return q*((o=o/p-1)*o*o+1)+m},easeInOutCubic:function(n,o,m,q,p){if((o/=p/2)<1){return q/2*o*o*o+m}return q/2*((o-=2)*o*o+2)+m},easeInQuart:function(n,o,m,q,p){return q*(o/=p)*o*o*o+m},easeOutQuart:function(n,o,m,q,p){return -q*((o=o/p-1)*o*o*o-1)+m},easeInOutQuart:function(n,o,m,q,p){if((o/=p/2)<1){return q/2*o*o*o*o+m}return -q/2*((o-=2)*o*o*o-2)+m},easeInQuint:function(n,o,m,q,p){return q*(o/=p)*o*o*o*o+m},easeOutQuint:function(n,o,m,q,p){return q*((o=o/p-1)*o*o*o*o+1)+m},easeInOutQuint:function(n,o,m,q,p){if((o/=p/2)<1){return q/2*o*o*o*o*o+m}return q/2*((o-=2)*o*o*o*o+2)+m},easeInSine:function(n,o,m,q,p){return -q*Math.cos(o/p*(Math.PI/2))+q+m},easeOutSine:function(n,o,m,q,p){return q*Math.sin(o/p*(Math.PI/2))+m},easeInOutSine:function(n,o,m,q,p){return -q/2*(Math.cos(Math.PI*o/p)-1)+m},easeInExpo:function(n,o,m,q,p){return(o==0)?m:q*Math.pow(2,10*(o/p-1))+m},easeOutExpo:function(n,o,m,q,p){return(o==p)?m+q:q*(-Math.pow(2,-10*o/p)+1)+m},easeInOutExpo:function(n,o,m,q,p){if(o==0){return m}if(o==p){return m+q}if((o/=p/2)<1){return q/2*Math.pow(2,10*(o-1))+m}return q/2*(-Math.pow(2,-10*--o)+2)+m},easeInCirc:function(n,o,m,q,p){return -q*(Math.sqrt(1-(o/=p)*o)-1)+m},easeOutCirc:function(n,o,m,q,p){return q*Math.sqrt(1-(o=o/p-1)*o)+m},easeInOutCirc:function(n,o,m,q,p){if((o/=p/2)<1){return -q/2*(Math.sqrt(1-o*o)-1)+m}return q/2*(Math.sqrt(1-(o-=2)*o)+1)+m},easeInElastic:function(n,q,m,w,v){var r=1.70158;var u=0;var o=w;if(q==0){return m}if((q/=v)==1){return m+w}if(!u){u=v*0.3}if(o").css({position:"absolute",visibility:"visible",left:-e*(h/f),top:-g*(d/l)}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:h/f,height:d/l,left:m.left+e*(h/f)+(c.options.mode=="show"?(e-Math.floor(f/2))*(h/f):0),top:m.top+g*(d/l)+(c.options.mode=="show"?(g-Math.floor(l/2))*(d/l):0),opacity:c.options.mode=="show"?0:1}).animate({left:m.left+e*(h/f)+(c.options.mode=="show"?0:(e-Math.floor(f/2))*(h/f)),top:m.top+g*(d/l)+(c.options.mode=="show"?0:(g-Math.floor(l/2))*(d/l)),opacity:c.options.mode=="show"?1:0},c.duration||500)}}setTimeout(function(){c.options.mode=="show"?k.css({visibility:"visible"}):k.css({visibility:"visible"}).hide();if(c.callback){c.callback.apply(k[0])}k.dequeue();a("div.ui-effects-explode").remove()},c.duration||500)})}})(jQuery);(function(a,b){a.effects.fade=function(c){return this.queue(function(){var d=a(this),e=a.effects.setMode(d,c.options.mode||"hide");d.animate({opacity:e},{queue:false,duration:c.duration,easing:c.options.easing,complete:function(){(c.callback&&c.callback.apply(this,arguments));d.dequeue()}})})}})(jQuery);(function(a,b){a.effects.fold=function(c){return this.queue(function(){var f=a(this),l=["position","top","bottom","left","right"];var i=a.effects.setMode(f,c.options.mode||"hide");var p=c.options.size||15;var o=!(!c.options.horizFirst);var h=c.duration?c.duration/2:a.fx.speeds._default/2;a.effects.save(f,l);f.show();var e=a.effects.createWrapper(f).css({overflow:"hidden"});var j=((i=="show")!=o);var g=j?["width","height"]:["height","width"];var d=j?[e.width(),e.height()]:[e.height(),e.width()];var k=/([0-9]+)%/.exec(p);if(k){p=parseInt(k[1],10)/100*d[i=="hide"?0:1]}if(i=="show"){e.css(o?{height:0,width:p}:{height:p,width:0})}var n={},m={};n[g[0]]=i=="show"?d[0]:p;m[g[1]]=i=="show"?d[1]:0;e.animate(n,h,c.options.easing).animate(m,h,c.options.easing,function(){if(i=="hide"){f.hide()}a.effects.restore(f,l);a.effects.removeWrapper(f);if(c.callback){c.callback.apply(f[0],arguments)}f.dequeue()})})}})(jQuery);(function(a,b){a.effects.highlight=function(c){return this.queue(function(){var e=a(this),d=["backgroundImage","backgroundColor","opacity"],g=a.effects.setMode(e,c.options.mode||"show"),f={backgroundColor:e.css("backgroundColor")};if(g=="hide"){f.opacity=0}a.effects.save(e,d);e.show().css({backgroundImage:"none",backgroundColor:c.options.color||"#ffff99"}).animate(f,{queue:false,duration:c.duration,easing:c.options.easing,complete:function(){(g=="hide"&&e.hide());a.effects.restore(e,d);(g=="show"&&!a.support.opacity&&this.style.removeAttribute("filter"));(c.callback&&c.callback.apply(this,arguments));e.dequeue()}})})}})(jQuery);(function(a,b){a.effects.pulsate=function(c){return this.queue(function(){var e=a(this),f=a.effects.setMode(e,c.options.mode||"show");times=((c.options.times||5)*2)-1;duration=c.duration?c.duration/2:a.fx.speeds._default/2,isVisible=e.is(":visible"),animateTo=0;if(!isVisible){e.css("opacity",0).show();animateTo=1}if((f=="hide"&&isVisible)||(f=="show"&&!isVisible)){times--}for(var d=0;d').appendTo(document.body).addClass(c.options.className).css({top:e.top,left:e.left,height:g.innerHeight(),width:g.innerWidth(),position:"absolute"}).animate(h,c.duration,c.options.easing,function(){d.remove();(c.callback&&c.callback.apply(g[0],arguments));g.dequeue()})})}})(jQuery); \ No newline at end of file diff --git a/underlays/attachment/ikiwiki/jquery.fileupload-ui.js b/underlays/attachment/ikiwiki/jquery.fileupload-ui.js new file mode 100644 index 000000000..61897ba55 --- /dev/null +++ b/underlays/attachment/ikiwiki/jquery.fileupload-ui.js @@ -0,0 +1,357 @@ +/* + * jQuery File Upload User Interface Plugin 5.0.13 + * https://github.com/blueimp/jQuery-File-Upload + * + * Copyright 2010, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * http://creativecommons.org/licenses/MIT/ + */ + +/*jslint nomen: true, unparam: true, regexp: true */ +/*global window, document, URL, webkitURL, FileReader, jQuery */ + +(function ($) { + 'use strict'; + + // The UI version extends the basic fileupload widget and adds + // a complete user interface based on the given upload/download + // templates. + $.widget('blueimpUI.fileupload', $.blueimp.fileupload, { + + options: { + // By default, files added to the widget are uploaded as soon + // as the user clicks on the start buttons. To enable automatic + // uploads, set the following option to true: + autoUpload: true, + // The file upload template that is given as first argument to the + // jQuery.tmpl method to render the file uploads: + uploadTemplate: $('#template-upload'), + // The file download template, that is given as first argument to the + // jQuery.tmpl method to render the file downloads: + downloadTemplate: $('#template-download'), + // The expected data type of the upload response, sets the dataType + // option of the $.ajax upload requests: + dataType: 'json', + + // The add callback is invoked as soon as files are added to the fileupload + // widget (via file input selection, drag & drop or add API call). + // See the basic file upload widget for more information: + add: function (e, data) { + var that = $(this).data('fileupload'); + data.isAdjusted = true; + data.isValidated = that._validate(data.files); + data.context = that._renderUpload(data.files) + .appendTo($(this).find('.files')).fadeIn(function () { + // Fix for IE7 and lower: + $(this).show(); + }).data('data', data); + if ((that.options.autoUpload || data.autoUpload) && + data.isValidated) { + data.jqXHR = data.submit(); + } + }, + // Callback for the start of each file upload request: + send: function (e, data) { + if (!data.isValidated) { + var that = $(this).data('fileupload'); + if (!that._validate(data.files)) { + return false; + } + } + if (data.context && data.dataType && + data.dataType.substr(0, 6) === 'iframe') { + // Iframe Transport does not support progress events. + // In lack of an indeterminate progress bar, we set + // the progress to 100%, showing the full animated bar: + data.context.find('.ui-progressbar').progressbar( + 'value', + parseInt(100, 10) + ); + } + }, + // Callback for successful uploads: + done: function (e, data) { + var that = $(this).data('fileupload'); + if (data.context) { + data.context.each(function (index) { + var file = ($.isArray(data.result) && + data.result[index]) || {error: 'emptyResult'}; + $(this).fadeOut(function () { + that._renderDownload([file]) + .css('display', 'none') + .replaceAll(this) + .fadeIn(function () { + // Fix for IE7 and lower: + $(this).show(); + }); + }); + }); + } else { + that._renderDownload(data.result) + .css('display', 'none') + .appendTo($(this).find('.files')) + .fadeIn(function () { + // Fix for IE7 and lower: + $(this).show(); + }); + } + }, + // Callback for failed (abort or error) uploads: + fail: function (e, data) { + var that = $(this).data('fileupload'); + if (data.context) { + data.context.each(function (index) { + $(this).fadeOut(function () { + if (data.errorThrown !== 'abort') { + var file = data.files[index]; + file.error = file.error || data.errorThrown + || true; + that._renderDownload([file]) + .css('display', 'none') + .replaceAll(this) + .fadeIn(function () { + // Fix for IE7 and lower: + $(this).show(); + }); + } else { + data.context.remove(); + } + }); + }); + } else if (data.errorThrown !== 'abort') { + data.context = that._renderUpload(data.files) + .css('display', 'none') + .appendTo($(this).find('.files')) + .fadeIn(function () { + // Fix for IE7 and lower: + $(this).show(); + }).data('data', data); + } + }, + // Callback for upload progress events: + progress: function (e, data) { + if (data.context) { + data.context.find('.ui-progressbar').progressbar( + 'value', + parseInt(data.loaded / data.total * 100, 10) + ); + } + }, + // Callback for global upload progress events: + progressall: function (e, data) { + $(this).find('.fileupload-progressbar').progressbar( + 'value', + parseInt(data.loaded / data.total * 100, 10) + ); + }, + // Callback for uploads start, equivalent to the global ajaxStart event: + start: function () { + $(this).find('.fileupload-progressbar') + .progressbar('value', 0).fadeIn(); + }, + // Callback for uploads stop, equivalent to the global ajaxStop event: + stop: function () { + $(this).find('.fileupload-progressbar').fadeOut(); + }, + }, + + _createObjectURL: function (file) { + var undef = 'undefined', + urlAPI = (typeof window.createObjectURL !== undef && window) || + (typeof URL !== undef && URL) || + (typeof webkitURL !== undef && webkitURL); + return urlAPI ? urlAPI.createObjectURL(file) : false; + }, + + _revokeObjectURL: function (url) { + var undef = 'undefined', + urlAPI = (typeof window.revokeObjectURL !== undef && window) || + (typeof URL !== undef && URL) || + (typeof webkitURL !== undef && webkitURL); + return urlAPI ? urlAPI.revokeObjectURL(url) : false; + }, + + // Link handler, that allows to download files + // by drag & drop of the links to the desktop: + _enableDragToDesktop: function () { + var link = $(this), + url = link.prop('href'), + name = decodeURIComponent(url.split('/').pop()) + .replace(/:/g, '-'), + type = 'application/octet-stream'; + link.bind('dragstart', function (e) { + try { + e.originalEvent.dataTransfer.setData( + 'DownloadURL', + [type, name, url].join(':') + ); + } catch (err) {} + }); + }, + + _hasError: function (file) { + if (file.error) { + return file.error; + } + return null; + }, + + _validate: function (files) { + var that = this, + valid; + $.each(files, function (index, file) { + file.error = that._hasError(file); + valid = !file.error; + }); + return valid; + }, + + _uploadTemplateHelper: function (file) { + return file; + }, + + _renderUploadTemplate: function (files) { + var that = this; + return $.tmpl( + this.options.uploadTemplate, + $.map(files, function (file) { + return that._uploadTemplateHelper(file); + }) + ); + }, + + _renderUpload: function (files) { + var that = this, + options = this.options, + tmpl = this._renderUploadTemplate(files); + if (!(tmpl instanceof $)) { + return $(); + } + tmpl.css('display', 'none'); + // .slice(1).remove().end().first() removes all but the first + // element and selects only the first for the jQuery collection: + tmpl.find('.progress div').slice(1).remove().end().first() + .progressbar(); + tmpl.find('.start button').slice( + this.options.autoUpload ? 0 : 1 + ).remove().end().first() + .button({ + text: false, + icons: {primary: 'ui-icon-circle-arrow-e'} + }); + tmpl.find('.cancel button').slice(1).remove().end().first() + .button({ + text: false, + icons: {primary: 'ui-icon-cancel'} + }); + return tmpl; + }, + + _downloadTemplateHelper: function (file) { + return file; + }, + + _renderDownloadTemplate: function (files) { + var that = this; + return $.tmpl( + this.options.downloadTemplate, + $.map(files, function (file) { + return that._downloadTemplateHelper(file); + }) + ); + }, + + _renderDownload: function (files) { + var tmpl = this._renderDownloadTemplate(files); + if (!(tmpl instanceof $)) { + return $(); + } + tmpl.css('display', 'none'); + tmpl.find('a').each(this._enableDragToDesktop); + return tmpl; + }, + + _startHandler: function (e) { + e.preventDefault(); + var tmpl = $(this).closest('.template-upload'), + data = tmpl.data('data'); + if (data && data.submit && !data.jqXHR) { + data.jqXHR = data.submit(); + $(this).fadeOut(); + } + }, + + _cancelHandler: function (e) { + e.preventDefault(); + var tmpl = $(this).closest('.template-upload'), + data = tmpl.data('data') || {}; + if (!data.jqXHR) { + data.errorThrown = 'abort'; + e.data.fileupload._trigger('fail', e, data); + } else { + data.jqXHR.abort(); + } + }, + + _initEventHandlers: function () { + $.blueimp.fileupload.prototype._initEventHandlers.call(this); + var filesList = this.element.find('.files'), + eventData = {fileupload: this}; + filesList.find('.start button') + .live( + 'click.' + this.options.namespace, + eventData, + this._startHandler + ); + filesList.find('.cancel button') + .live( + 'click.' + this.options.namespace, + eventData, + this._cancelHandler + ); + }, + + _destroyEventHandlers: function () { + var filesList = this.element.find('.files'); + filesList.find('.start button') + .die('click.' + this.options.namespace); + filesList.find('.cancel button') + .die('click.' + this.options.namespace); + $.blueimp.fileupload.prototype._destroyEventHandlers.call(this); + }, + + _initTemplates: function () { + // Handle cases where the templates are defined + // after the widget library has been included: + if (this.options.uploadTemplate instanceof $ && + !this.options.uploadTemplate.length) { + this.options.uploadTemplate = $( + this.options.uploadTemplate.selector + ); + } + if (this.options.downloadTemplate instanceof $ && + !this.options.downloadTemplate.length) { + this.options.downloadTemplate = $( + this.options.downloadTemplate.selector + ); + } + }, + + _create: function () { + $.blueimp.fileupload.prototype._create.call(this); + this._initTemplates(); + }, + + enable: function () { + $.blueimp.fileupload.prototype.enable.call(this); + }, + + disable: function () { + $.blueimp.fileupload.prototype.disable.call(this); + } + + }); + +}(jQuery)); diff --git a/underlays/attachment/ikiwiki/jquery.fileupload.js b/underlays/attachment/ikiwiki/jquery.fileupload.js new file mode 100644 index 000000000..1e3c6bf97 --- /dev/null +++ b/underlays/attachment/ikiwiki/jquery.fileupload.js @@ -0,0 +1,720 @@ +/* + * jQuery File Upload Plugin 5.0.2 + * https://github.com/blueimp/jQuery-File-Upload + * + * Copyright 2010, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * http://creativecommons.org/licenses/MIT/ + */ + +/*jslint nomen: true, unparam: true, regexp: true */ +/*global document, XMLHttpRequestUpload, Blob, File, FormData, location, jQuery */ + +(function ($) { + 'use strict'; + + // The fileupload widget listens for change events on file input fields + // defined via fileInput setting and drop events of the given dropZone. + // In addition to the default jQuery Widget methods, the fileupload widget + // exposes the "add" and "send" methods, to add or directly send files + // using the fileupload API. + // By default, files added via file input selection, drag & drop or + // "add" method are uploaded immediately, but it is possible to override + // the "add" callback option to queue file uploads. + $.widget('blueimp.fileupload', { + + options: { + // The namespace used for event handler binding on the dropZone and + // fileInput collections. + // If not set, the name of the widget ("fileupload") is used. + namespace: undefined, + // The drop target collection, by the default the complete document. + // Set to null or an empty collection to disable drag & drop support: + dropZone: $(document), + // The file input field collection, that is listened for change events. + // If undefined, it is set to the file input fields inside + // of the widget element on plugin initialization. + // Set to null or an empty collection to disable the change listener. + fileInput: undefined, + // By default, the file input field is replaced with a clone after + // each input field change event. This is required for iframe transport + // queues and allows change events to be fired for the same file + // selection, but can be disabled by setting the following option to false: + replaceFileInput: true, + // The parameter name for the file form data (the request argument name). + // If undefined or empty, the name property of the file input field is + // used, or "files[]" if the file input name property is also empty: + paramName: undefined, + // By default, each file of a selection is uploaded using an individual + // request for XHR type uploads. Set to false to upload file + // selections in one request each: + singleFileUploads: true, + // Set the following option to true to issue all file upload requests + // in a sequential order: + sequentialUploads: false, + // Set the following option to true to force iframe transport uploads: + forceIframeTransport: false, + // By default, XHR file uploads are sent as multipart/form-data. + // The iframe transport is always using multipart/form-data. + // Set to false to enable non-multipart XHR uploads: + multipart: true, + // To upload large files in smaller chunks, set the following option + // to a preferred maximum chunk size. If set to 0, null or undefined, + // or the browser does not support the required Blob API, files will + // be uploaded as a whole. + maxChunkSize: undefined, + // When a non-multipart upload or a chunked multipart upload has been + // aborted, this option can be used to resume the upload by setting + // it to the size of the already uploaded bytes. This option is most + // useful when modifying the options object inside of the "add" or + // "send" callbacks, as the options are cloned for each file upload. + uploadedBytes: undefined, + // By default, failed (abort or error) file uploads are removed from the + // global progress calculation. Set the following option to false to + // prevent recalculating the global progress data: + recalculateProgress: true, + + // Additional form data to be sent along with the file uploads can be set + // using this option, which accepts an array of objects with name and + // value properties, a function returning such an array, a FormData + // object (for XHR file uploads), or a simple object. + // The form of the first fileInput is given as parameter to the function: + formData: function (form) { + return form.serializeArray(); + }, + + // The add callback is invoked as soon as files are added to the fileupload + // widget (via file input selection, drag & drop or add API call). + // If the singleFileUploads option is enabled, this callback will be + // called once for each file in the selection for XHR file uplaods, else + // once for each file selection. + // The upload starts when the submit method is invoked on the data parameter. + // The data object contains a files property holding the added files + // and allows to override plugin options as well as define ajax settings. + // Listeners for this callback can also be bound the following way: + // .bind('fileuploadadd', func); + // data.submit() returns a Promise object and allows to attach additional + // handlers using jQuery's Deferred callbacks: + // data.submit().done(func).fail(func).always(func); + add: function (e, data) { + data.submit(); + }, + + // Other callbacks: + // Callback for the start of each file upload request: + // send: function (e, data) {}, // .bind('fileuploadsend', func); + // Callback for successful uploads: + // done: function (e, data) {}, // .bind('fileuploaddone', func); + // Callback for failed (abort or error) uploads: + // fail: function (e, data) {}, // .bind('fileuploadfail', func); + // Callback for completed (success, abort or error) requests: + // always: function (e, data) {}, // .bind('fileuploadalways', func); + // Callback for upload progress events: + // progress: function (e, data) {}, // .bind('fileuploadprogress', func); + // Callback for global upload progress events: + // progressall: function (e, data) {}, // .bind('fileuploadprogressall', func); + // Callback for uploads start, equivalent to the global ajaxStart event: + // start: function (e) {}, // .bind('fileuploadstart', func); + // Callback for uploads stop, equivalent to the global ajaxStop event: + // stop: function (e) {}, // .bind('fileuploadstop', func); + // Callback for change events of the fileInput collection: + // change: function (e, data) {}, // .bind('fileuploadchange', func); + // Callback for drop events of the dropZone collection: + // drop: function (e, data) {}, // .bind('fileuploaddrop', func); + // Callback for dragover events of the dropZone collection: + // dragover: function (e) {}, // .bind('fileuploaddragover', func); + + // The plugin options are used as settings object for the ajax calls. + // The following are jQuery ajax settings required for the file uploads: + processData: false, + contentType: false, + cache: false + }, + + // A list of options that require a refresh after assigning a new value: + _refreshOptionsList: ['namespace', 'dropZone', 'fileInput'], + + _isXHRUpload: function (options) { + var undef = 'undefined'; + return !options.forceIframeTransport && + typeof XMLHttpRequestUpload !== undef && typeof File !== undef && + (!options.multipart || typeof FormData !== undef); + }, + + _getFormData: function (options) { + var formData; + if (typeof options.formData === 'function') { + return options.formData(options.form); + } else if ($.isArray(options.formData)) { + return options.formData; + } else if (options.formData) { + formData = []; + $.each(options.formData, function (name, value) { + formData.push({name: name, value: value}); + }); + return formData; + } + return []; + }, + + _getTotal: function (files) { + var total = 0; + $.each(files, function (index, file) { + total += file.size || 1; + }); + return total; + }, + + _onProgress: function (e, data) { + if (e.lengthComputable) { + var total = data.total || this._getTotal(data.files), + loaded = parseInt( + e.loaded / e.total * (data.chunkSize || total), + 10 + ) + (data.uploadedBytes || 0); + this._loaded += loaded - (data.loaded || data.uploadedBytes || 0); + data.lengthComputable = true; + data.loaded = loaded; + data.total = total; + // Trigger a custom progress event with a total data property set + // to the file size(s) of the current upload and a loaded data + // property calculated accordingly: + this._trigger('progress', e, data); + // Trigger a global progress event for all current file uploads, + // including ajax calls queued for sequential file uploads: + this._trigger('progressall', e, { + lengthComputable: true, + loaded: this._loaded, + total: this._total + }); + } + }, + + _initProgressListener: function (options) { + var that = this, + xhr = options.xhr ? options.xhr() : $.ajaxSettings.xhr(); + // Accesss to the native XHR object is required to add event listeners + // for the upload progress event: + if (xhr.upload && xhr.upload.addEventListener) { + xhr.upload.addEventListener('progress', function (e) { + that._onProgress(e, options); + }, false); + options.xhr = function () { + return xhr; + }; + } + }, + + _initXHRData: function (options) { + var formData, + file = options.files[0]; + if (!options.multipart || options.blob) { + // For non-multipart uploads and chunked uploads, + // file meta data is not part of the request body, + // so we transmit this data as part of the HTTP headers. + // For cross domain requests, these headers must be allowed + // via Access-Control-Allow-Headers or removed using + // the beforeSend callback: + options.headers = $.extend(options.headers, { + 'X-File-Name': file.name, + 'X-File-Type': file.type, + 'X-File-Size': file.size + }); + if (!options.blob) { + // Non-chunked non-multipart upload: + options.contentType = file.type; + options.data = file; + } else if (!options.multipart) { + // Chunked non-multipart upload: + options.contentType = 'application/octet-stream'; + options.data = options.blob; + } + } + if (options.multipart && typeof FormData !== 'undefined') { + if (options.formData instanceof FormData) { + formData = options.formData; + } else { + formData = new FormData(); + $.each(this._getFormData(options), function (index, field) { + formData.append(field.name, field.value); + }); + } + if (options.blob) { + formData.append(options.paramName, options.blob); + } else { + $.each(options.files, function (index, file) { + // File objects are also Blob instances. + // This check allows the tests to run with + // dummy objects: + if (file instanceof Blob) { + formData.append(options.paramName, file); + } + }); + } + options.data = formData; + } + // Blob reference is not needed anymore, free memory: + options.blob = null; + }, + + _initIframeSettings: function (options) { + // Setting the dataType to iframe enables the iframe transport: + options.dataType = 'iframe ' + (options.dataType || ''); + // The iframe transport accepts a serialized array as form data: + options.formData = this._getFormData(options); + }, + + _initDataSettings: function (options) { + if (this._isXHRUpload(options)) { + if (!this._chunkedUpload(options, true)) { + if (!options.data) { + this._initXHRData(options); + } + this._initProgressListener(options); + } + } else { + this._initIframeSettings(options); + } + }, + + _initFormSettings: function (options) { + // Retrieve missing options from the input field and the + // associated form, if available: + if (!options.form || !options.form.length) { + options.form = $(options.fileInput.prop('form')); + } + if (!options.paramName) { + options.paramName = options.fileInput.prop('name') || + 'files[]'; + } + if (!options.url) { + options.url = options.form.prop('action') || location.href; + } + // The HTTP request method must be "POST" or "PUT": + options.type = (options.type || options.form.prop('method') || '') + .toUpperCase(); + if (options.type !== 'POST' && options.type !== 'PUT') { + options.type = 'POST'; + } + }, + + _getAJAXSettings: function (data) { + var options = $.extend({}, this.options, data); + this._initFormSettings(options); + this._initDataSettings(options); + return options; + }, + + // Maps jqXHR callbacks to the equivalent + // methods of the given Promise object: + _enhancePromise: function (promise) { + promise.success = promise.done; + promise.error = promise.fail; + promise.complete = promise.always; + return promise; + }, + + // Creates and returns a Promise object enhanced with + // the jqXHR methods abort, success, error and complete: + _getXHRPromise: function (resolveOrReject, context, args) { + var dfd = $.Deferred(), + promise = dfd.promise(); + context = context || this.options.context || promise; + if (resolveOrReject === true) { + dfd.resolveWith(context, args); + } else if (resolveOrReject === false) { + dfd.rejectWith(context, args); + } + promise.abort = dfd.promise; + return this._enhancePromise(promise); + }, + + // Uploads a file in multiple, sequential requests + // by splitting the file up in multiple blob chunks. + // If the second parameter is true, only tests if the file + // should be uploaded in chunks, but does not invoke any + // upload requests: + _chunkedUpload: function (options, testOnly) { + var that = this, + file = options.files[0], + fs = file.size, + ub = options.uploadedBytes = options.uploadedBytes || 0, + mcs = options.maxChunkSize || fs, + // Use the Blob methods with the slice implementation + // according to the W3C Blob API specification: + slice = file.webkitSlice || file.mozSlice || file.slice, + upload, + n, + jqXHR, + pipe; + if (!(this._isXHRUpload(options) && slice && (ub || mcs < fs)) || + options.data) { + return false; + } + if (testOnly) { + return true; + } + if (ub >= fs) { + file.error = 'uploadedBytes'; + return this._getXHRPromise(false); + } + // n is the number of blobs to upload, + // calculated via filesize, uploaded bytes and max chunk size: + n = Math.ceil((fs - ub) / mcs); + // The chunk upload method accepting the chunk number as parameter: + upload = function (i) { + if (!i) { + return that._getXHRPromise(true); + } + // Upload the blobs in sequential order: + return upload(i -= 1).pipe(function () { + // Clone the options object for each chunk upload: + var o = $.extend({}, options); + o.blob = slice.call( + file, + ub + i * mcs, + ub + (i + 1) * mcs + ); + // Store the current chunk size, as the blob itself + // will be dereferenced after data processing: + o.chunkSize = o.blob.size; + // Process the upload data (the blob and potential form data): + that._initXHRData(o); + // Add progress listeners for this chunk upload: + that._initProgressListener(o); + jqXHR = ($.ajax(o) || that._getXHRPromise(false, o.context)) + .done(function () { + // Create a progress event if upload is done and + // no progress event has been invoked for this chunk: + if (!o.loaded) { + that._onProgress($.Event('progress', { + lengthComputable: true, + loaded: o.chunkSize, + total: o.chunkSize + }), o); + } + options.uploadedBytes = o.uploadedBytes + += o.chunkSize; + }); + return jqXHR; + }); + }; + // Return the piped Promise object, enhanced with an abort method, + // which is delegated to the jqXHR object of the current upload, + // and jqXHR callbacks mapped to the equivalent Promise methods: + pipe = upload(n); + pipe.abort = function () { + return jqXHR.abort(); + }; + return this._enhancePromise(pipe); + }, + + _beforeSend: function (e, data) { + if (this._active === 0) { + // the start callback is triggered when an upload starts + // and no other uploads are currently running, + // equivalent to the global ajaxStart event: + this._trigger('start'); + } + this._active += 1; + // Initialize the global progress values: + this._loaded += data.uploadedBytes || 0; + this._total += this._getTotal(data.files); + }, + + _onDone: function (result, textStatus, jqXHR, options) { + if (!this._isXHRUpload(options)) { + // Create a progress event for each iframe load: + this._onProgress($.Event('progress', { + lengthComputable: true, + loaded: 1, + total: 1 + }), options); + } + options.result = result; + options.textStatus = textStatus; + options.jqXHR = jqXHR; + this._trigger('done', null, options); + }, + + _onFail: function (jqXHR, textStatus, errorThrown, options) { + options.jqXHR = jqXHR; + options.textStatus = textStatus; + options.errorThrown = errorThrown; + this._trigger('fail', null, options); + if (options.recalculateProgress) { + // Remove the failed (error or abort) file upload from + // the global progress calculation: + this._loaded -= options.loaded || options.uploadedBytes || 0; + this._total -= options.total || this._getTotal(options.files); + } + }, + + _onAlways: function (result, textStatus, jqXHR, errorThrown, options) { + this._active -= 1; + options.result = result; + options.textStatus = textStatus; + options.jqXHR = jqXHR; + options.errorThrown = errorThrown; + this._trigger('always', null, options); + if (this._active === 0) { + // The stop callback is triggered when all uploads have + // been completed, equivalent to the global ajaxStop event: + this._trigger('stop'); + // Reset the global progress values: + this._loaded = this._total = 0; + } + }, + + _onSend: function (e, data) { + var that = this, + jqXHR, + pipe, + options = that._getAJAXSettings(data), + send = function (resolve, args) { + jqXHR = jqXHR || ( + (resolve !== false && + that._trigger('send', e, options) !== false && + (that._chunkedUpload(options) || $.ajax(options))) || + that._getXHRPromise(false, options.context, args) + ).done(function (result, textStatus, jqXHR) { + that._onDone(result, textStatus, jqXHR, options); + }).fail(function (jqXHR, textStatus, errorThrown) { + that._onFail(jqXHR, textStatus, errorThrown, options); + }).always(function (a1, a2, a3) { + if (!a3 || typeof a3 === 'string') { + that._onAlways(undefined, a2, a1, a3, options); + } else { + that._onAlways(a1, a2, a3, undefined, options); + } + }); + return jqXHR; + }; + this._beforeSend(e, options); + if (this.options.sequentialUploads) { + // Return the piped Promise object, enhanced with an abort method, + // which is delegated to the jqXHR object of the current upload, + // and jqXHR callbacks mapped to the equivalent Promise methods: + pipe = (this._sequence = this._sequence.pipe(send, send)); + pipe.abort = function () { + if (!jqXHR) { + return send(false, [undefined, 'abort', 'abort']); + } + return jqXHR.abort(); + }; + return this._enhancePromise(pipe); + } + return send(); + }, + + _onAdd: function (e, data) { + var that = this, + result = true, + options = $.extend({}, this.options, data); + if (options.singleFileUploads && this._isXHRUpload(options)) { + $.each(data.files, function (index, file) { + var newData = $.extend({}, data, {files: [file]}); + newData.submit = function () { + return that._onSend(e, newData); + }; + return (result = that._trigger('add', e, newData)); + }); + return result; + } else if (data.files.length) { + data = $.extend({}, data); + data.submit = function () { + return that._onSend(e, data); + }; + return this._trigger('add', e, data); + } + }, + + // File Normalization for Gecko 1.9.1 (Firefox 3.5) support: + _normalizeFile: function (index, file) { + if (file.name === undefined && file.size === undefined) { + file.name = file.fileName; + file.size = file.fileSize; + } + }, + + _replaceFileInput: function (input) { + var inputClone = input.clone(true); + $('
    ').append(inputClone)[0].reset(); + // Detaching allows to insert the fileInput on another form + // without loosing the file input value: + input.after(inputClone).detach(); + // Replace the original file input element in the fileInput + // collection with the clone, which has been copied including + // event handlers: + this.options.fileInput = this.options.fileInput.map(function (i, el) { + if (el === input[0]) { + return inputClone[0]; + } + return el; + }); + }, + + _onChange: function (e) { + var that = e.data.fileupload, + data = { + files: $.each($.makeArray(e.target.files), that._normalizeFile), + fileInput: $(e.target), + form: $(e.target.form) + }; + if (!data.files.length) { + // If the files property is not available, the browser does not + // support the File API and we add a pseudo File object with + // the input value as name with path information removed: + data.files = [{name: e.target.value.replace(/^.*\\/, '')}]; + } + // Store the form reference as jQuery data for other event handlers, + // as the form property is not available after replacing the file input: + if (data.form.length) { + data.fileInput.data('blueimp.fileupload.form', data.form); + } else { + data.form = data.fileInput.data('blueimp.fileupload.form'); + } + if (that.options.replaceFileInput) { + that._replaceFileInput(data.fileInput); + } + if (that._trigger('change', e, data) === false || + that._onAdd(e, data) === false) { + return false; + } + }, + + _onDrop: function (e) { + var that = e.data.fileupload, + dataTransfer = e.dataTransfer = e.originalEvent.dataTransfer, + data = { + files: $.each( + $.makeArray(dataTransfer && dataTransfer.files), + that._normalizeFile + ) + }; + if (that._trigger('drop', e, data) === false || + that._onAdd(e, data) === false) { + return false; + } + e.preventDefault(); + }, + + _onDragOver: function (e) { + var that = e.data.fileupload, + dataTransfer = e.dataTransfer = e.originalEvent.dataTransfer; + if (that._trigger('dragover', e) === false) { + return false; + } + if (dataTransfer) { + dataTransfer.dropEffect = dataTransfer.effectAllowed = 'copy'; + } + e.preventDefault(); + }, + + _initEventHandlers: function () { + var ns = this.options.namespace || this.name; + this.options.dropZone + .bind('dragover.' + ns, {fileupload: this}, this._onDragOver) + .bind('drop.' + ns, {fileupload: this}, this._onDrop); + this.options.fileInput + .bind('change.' + ns, {fileupload: this}, this._onChange); + }, + + _destroyEventHandlers: function () { + var ns = this.options.namespace || this.name; + this.options.dropZone + .unbind('dragover.' + ns, this._onDragOver) + .unbind('drop.' + ns, this._onDrop); + this.options.fileInput + .unbind('change.' + ns, this._onChange); + }, + + _beforeSetOption: function (key, value) { + this._destroyEventHandlers(); + }, + + _afterSetOption: function (key, value) { + var options = this.options; + if (!options.fileInput) { + options.fileInput = $(); + } + if (!options.dropZone) { + options.dropZone = $(); + } + this._initEventHandlers(); + }, + + _setOption: function (key, value) { + var refresh = $.inArray(key, this._refreshOptionsList) !== -1; + if (refresh) { + this._beforeSetOption(key, value); + } + $.Widget.prototype._setOption.call(this, key, value); + if (refresh) { + this._afterSetOption(key, value); + } + }, + + _create: function () { + var options = this.options; + if (options.fileInput === undefined) { + options.fileInput = this.element.is('input:file') ? + this.element : this.element.find('input:file'); + } else if (!options.fileInput) { + options.fileInput = $(); + } + if (!options.dropZone) { + options.dropZone = $(); + } + this._sequence = this._getXHRPromise(true); + this._active = this._loaded = this._total = 0; + this._initEventHandlers(); + }, + + destroy: function () { + this._destroyEventHandlers(); + $.Widget.prototype.destroy.call(this); + }, + + enable: function () { + $.Widget.prototype.enable.call(this); + this._initEventHandlers(); + }, + + disable: function () { + this._destroyEventHandlers(); + $.Widget.prototype.disable.call(this); + }, + + // This method is exposed to the widget API and allows adding files + // using the fileupload API. The data parameter accepts an object which + // must have a files property and can contain additional options: + // .fileupload('add', {files: filesList}); + add: function (data) { + if (!data || this.options.disabled) { + return; + } + data.files = $.each($.makeArray(data.files), this._normalizeFile); + this._onAdd(null, data); + }, + + // This method is exposed to the widget API and allows sending files + // using the fileupload API. The data parameter accepts an object which + // must have a files property and can contain additional options: + // .fileupload('send', {files: filesList}); + // The method returns a Promise object for the file upload call. + send: function (data) { + if (data && !this.options.disabled) { + data.files = $.each($.makeArray(data.files), this._normalizeFile); + if (data.files.length) { + return this._onSend(null, data); + } + } + return this._getXHRPromise(false, data && data.context); + } + + }); + +}(jQuery)); \ No newline at end of file diff --git a/underlays/attachment/ikiwiki/jquery.iframe-transport.js b/underlays/attachment/ikiwiki/jquery.iframe-transport.js new file mode 100644 index 000000000..e859dfe49 --- /dev/null +++ b/underlays/attachment/ikiwiki/jquery.iframe-transport.js @@ -0,0 +1,133 @@ +/* + * jQuery Iframe Transport Plugin 1.1 + * https://github.com/blueimp/jQuery-File-Upload + * + * Copyright 2011, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * http://creativecommons.org/licenses/MIT/ + */ + +/*jslint unparam: true */ +/*global jQuery */ + +(function ($) { + 'use strict'; + + // Helper variable to create unique names for the transport iframes: + var counter = 0; + + // The iframe transport accepts two additional options: + // options.fileInput: a jQuery collection of file input fields + // options.formData: an array of objects with name and value properties, + // equivalent to the return data of .serializeArray(), e.g.: + // [{name: a, value: 1}, {name: b, value: 2}] + $.ajaxTransport('iframe', function (options, originalOptions, jqXHR) { + if (options.type === 'POST' || options.type === 'GET') { + var form, + iframe; + return { + send: function (headers, completeCallback) { + form = $('
    '); + // javascript:false as initial iframe src + // prevents warning popups on HTTPS in IE6. + // IE versions below IE8 cannot set the name property of + // elements that have already been added to the DOM, + // so we set the name along with the iframe HTML markup: + iframe = $( + '' + ).bind('load', function () { + var fileInputClones; + iframe + .unbind('load') + .bind('load', function () { + // The complete callback returns the + // iframe content document as response object: + completeCallback( + 200, + 'success', + {'iframe': iframe.contents()} + ); + // Fix for IE endless progress bar activity bug + // (happens on form submits to iframe targets): + $('') + .appendTo(form); + form.remove(); + }); + form + .prop('target', iframe.prop('name')) + .prop('action', options.url) + .prop('method', options.type); + if (options.formData) { + $.each(options.formData, function (index, field) { + $('') + .prop('name', field.name) + .val(field.value) + .appendTo(form); + }); + } + if (options.fileInput && options.fileInput.length && + options.type === 'POST') { + fileInputClones = options.fileInput.clone(); + // Insert a clone for each file input field: + options.fileInput.after(function (index) { + return fileInputClones[index]; + }); + // Appending the file input fields to the hidden form + // removes them from their original location: + form + .append(options.fileInput) + .prop('enctype', 'multipart/form-data') + // enctype must be set as encoding for IE: + .prop('encoding', 'multipart/form-data'); + } + form.submit(); + // Insert the file input fields at their original location + // by replacing the clones with the originals: + if (fileInputClones && fileInputClones.length) { + options.fileInput.each(function (index, input) { + $(fileInputClones[index]).replaceWith(input); + }); + } + }); + form.append(iframe).appendTo('body'); + }, + abort: function () { + if (iframe) { + // javascript:false as iframe src aborts the request + // and prevents warning popups on HTTPS in IE6. + // concat is used to avoid the "Script URL" JSLint error: + iframe + .unbind('load') + .prop('src', 'javascript'.concat(':false;')); + } + if (form) { + form.remove(); + } + } + }; + } + }); + + // The iframe transport returns the iframe content document as response. + // The following adds converters from iframe to text, json, html, and script: + $.ajaxSetup({ + converters: { + 'iframe text': function (iframe) { + return iframe.text(); + }, + 'iframe json': function (iframe) { + return $.parseJSON(iframe.text()); + }, + 'iframe html': function (iframe) { + return iframe.find('body').html(); + }, + 'iframe script': function (iframe) { + return $.globalEval(iframe.text()); + } + } + }); + +}(jQuery)); \ No newline at end of file diff --git a/underlays/attachment/ikiwiki/jquery.tmpl.js b/underlays/attachment/ikiwiki/jquery.tmpl.js new file mode 100644 index 000000000..1c5b2d62f --- /dev/null +++ b/underlays/attachment/ikiwiki/jquery.tmpl.js @@ -0,0 +1,486 @@ +/* + * jQuery Templating Plugin + * Copyright 2010, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + */ +(function( jQuery, undefined ){ + var oldManip = jQuery.fn.domManip, tmplItmAtt = "_tmplitem", htmlExpr = /^[^<]*(<[\w\W]+>)[^>]*$|\{\{\! /, + newTmplItems = {}, wrappedItems = {}, appendToTmplItems, topTmplItem = { key: 0, data: {} }, itemKey = 0, cloneIndex = 0, stack = []; + + function newTmplItem( options, parentItem, fn, data ) { + // Returns a template item data structure for a new rendered instance of a template (a 'template item'). + // The content field is a hierarchical array of strings and nested items (to be + // removed and replaced by nodes field of dom elements, once inserted in DOM). + var newItem = { + data: data || (parentItem ? parentItem.data : {}), + _wrap: parentItem ? parentItem._wrap : null, + tmpl: null, + parent: parentItem || null, + nodes: [], + calls: tiCalls, + nest: tiNest, + wrap: tiWrap, + html: tiHtml, + update: tiUpdate + }; + if ( options ) { + jQuery.extend( newItem, options, { nodes: [], parent: parentItem } ); + } + if ( fn ) { + // Build the hierarchical content to be used during insertion into DOM + newItem.tmpl = fn; + newItem._ctnt = newItem._ctnt || newItem.tmpl( jQuery, newItem ); + newItem.key = ++itemKey; + // Keep track of new template item, until it is stored as jQuery Data on DOM element + (stack.length ? wrappedItems : newTmplItems)[itemKey] = newItem; + } + return newItem; + } + + // Override appendTo etc., in order to provide support for targeting multiple elements. (This code would disappear if integrated in jquery core). + jQuery.each({ + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" + }, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var ret = [], insert = jQuery( selector ), elems, i, l, tmplItems, + parent = this.length === 1 && this[0].parentNode; + + appendToTmplItems = newTmplItems || {}; + if ( parent && parent.nodeType === 11 && parent.childNodes.length === 1 && insert.length === 1 ) { + insert[ original ]( this[0] ); + ret = this; + } else { + for ( i = 0, l = insert.length; i < l; i++ ) { + cloneIndex = i; + elems = (i > 0 ? this.clone(true) : this).get(); + jQuery.fn[ original ].apply( jQuery(insert[i]), elems ); + ret = ret.concat( elems ); + } + cloneIndex = 0; + ret = this.pushStack( ret, name, insert.selector ); + } + tmplItems = appendToTmplItems; + appendToTmplItems = null; + jQuery.tmpl.complete( tmplItems ); + return ret; + }; + }); + + jQuery.fn.extend({ + // Use first wrapped element as template markup. + // Return wrapped set of template items, obtained by rendering template against data. + tmpl: function( data, options, parentItem ) { + return jQuery.tmpl( this[0], data, options, parentItem ); + }, + + // Find which rendered template item the first wrapped DOM element belongs to + tmplItem: function() { + return jQuery.tmplItem( this[0] ); + }, + + // Consider the first wrapped element as a template declaration, and get the compiled template or store it as a named template. + template: function( name ) { + return jQuery.template( name, this[0] ); + }, + + domManip: function( args, table, callback, options ) { + // This appears to be a bug in the appendTo, etc. implementation + // it should be doing .call() instead of .apply(). See #6227 + if ( args[0] && args[0].nodeType ) { + var dmArgs = jQuery.makeArray( arguments ), argsLength = args.length, i = 0, tmplItem; + while ( i < argsLength && !(tmplItem = jQuery.data( args[i++], "tmplItem" ))) {} + if ( argsLength > 1 ) { + dmArgs[0] = [jQuery.makeArray( args )]; + } + if ( tmplItem && cloneIndex ) { + dmArgs[2] = function( fragClone ) { + // Handler called by oldManip when rendered template has been inserted into DOM. + jQuery.tmpl.afterManip( this, fragClone, callback ); + }; + } + oldManip.apply( this, dmArgs ); + } else { + oldManip.apply( this, arguments ); + } + cloneIndex = 0; + if ( !appendToTmplItems ) { + jQuery.tmpl.complete( newTmplItems ); + } + return this; + } + }); + + jQuery.extend({ + // Return wrapped set of template items, obtained by rendering template against data. + tmpl: function( tmpl, data, options, parentItem ) { + var ret, topLevel = !parentItem; + if ( topLevel ) { + // This is a top-level tmpl call (not from a nested template using {{tmpl}}) + parentItem = topTmplItem; + tmpl = jQuery.template[tmpl] || jQuery.template( null, tmpl ); + wrappedItems = {}; // Any wrapped items will be rebuilt, since this is top level + } else if ( !tmpl ) { + // The template item is already associated with DOM - this is a refresh. + // Re-evaluate rendered template for the parentItem + tmpl = parentItem.tmpl; + newTmplItems[parentItem.key] = parentItem; + parentItem.nodes = []; + if ( parentItem.wrapped ) { + updateWrapped( parentItem, parentItem.wrapped ); + } + // Rebuild, without creating a new template item + return jQuery( build( parentItem, null, parentItem.tmpl( jQuery, parentItem ) )); + } + if ( !tmpl ) { + return []; // Could throw... + } + if ( typeof data === "function" ) { + data = data.call( parentItem || {} ); + } + if ( options && options.wrapped ) { + updateWrapped( options, options.wrapped ); + } + ret = jQuery.isArray( data ) ? + jQuery.map( data, function( dataItem ) { + return dataItem ? newTmplItem( options, parentItem, tmpl, dataItem ) : null; + }) : + [ newTmplItem( options, parentItem, tmpl, data ) ]; + return topLevel ? jQuery( build( parentItem, null, ret ) ) : ret; + }, + + // Return rendered template item for an element. + tmplItem: function( elem ) { + var tmplItem; + if ( elem instanceof jQuery ) { + elem = elem[0]; + } + while ( elem && elem.nodeType === 1 && !(tmplItem = jQuery.data( elem, "tmplItem" )) && (elem = elem.parentNode) ) {} + return tmplItem || topTmplItem; + }, + + // Set: + // Use $.template( name, tmpl ) to cache a named template, + // where tmpl is a template string, a script element or a jQuery instance wrapping a script element, etc. + // Use $( "selector" ).template( name ) to provide access by name to a script block template declaration. + + // Get: + // Use $.template( name ) to access a cached template. + // Also $( selectorToScriptBlock ).template(), or $.template( null, templateString ) + // will return the compiled template, without adding a name reference. + // If templateString includes at least one HTML tag, $.template( templateString ) is equivalent + // to $.template( null, templateString ) + template: function( name, tmpl ) { + if (tmpl) { + // Compile template and associate with name + if ( typeof tmpl === "string" ) { + // This is an HTML string being passed directly in. + tmpl = buildTmplFn( tmpl ) + } else if ( tmpl instanceof jQuery ) { + tmpl = tmpl[0] || {}; + } + if ( tmpl.nodeType ) { + // If this is a template block, use cached copy, or generate tmpl function and cache. + tmpl = jQuery.data( tmpl, "tmpl" ) || jQuery.data( tmpl, "tmpl", buildTmplFn( tmpl.innerHTML )); + } + return typeof name === "string" ? (jQuery.template[name] = tmpl) : tmpl; + } + // Return named compiled template + return name ? (typeof name !== "string" ? jQuery.template( null, name ): + (jQuery.template[name] || + // If not in map, treat as a selector. (If integrated with core, use quickExpr.exec) + jQuery.template( null, htmlExpr.test( name ) ? name : jQuery( name )))) : null; + }, + + encode: function( text ) { + // Do HTML encoding replacing < > & and ' and " by corresponding entities. + return ("" + text).split("<").join("<").split(">").join(">").split('"').join(""").split("'").join("'"); + } + }); + + jQuery.extend( jQuery.tmpl, { + tag: { + "tmpl": { + _default: { $2: "null" }, + open: "if($notnull_1){_=_.concat($item.nest($1,$2));}" + // tmpl target parameter can be of type function, so use $1, not $1a (so not auto detection of functions) + // This means that {{tmpl foo}} treats foo as a template (which IS a function). + // Explicit parens can be used if foo is a function that returns a template: {{tmpl foo()}}. + }, + "wrap": { + _default: { $2: "null" }, + open: "$item.calls(_,$1,$2);_=[];", + close: "call=$item.calls();_=call._.concat($item.wrap(call,_));" + }, + "each": { + _default: { $2: "$index, $value" }, + open: "if($notnull_1){$.each($1a,function($2){with(this){", + close: "}});}" + }, + "if": { + open: "if(($notnull_1) && $1a){", + close: "}" + }, + "else": { + _default: { $1: "true" }, + open: "}else if(($notnull_1) && $1a){" + }, + "html": { + // Unecoded expression evaluation. + open: "if($notnull_1){_.push($1a);}" + }, + "=": { + // Encoded expression evaluation. Abbreviated form is ${}. + _default: { $1: "$data" }, + open: "if($notnull_1){_.push($.encode($1a));}" + }, + "!": { + // Comment tag. Skipped by parser + open: "" + } + }, + + // This stub can be overridden, e.g. in jquery.tmplPlus for providing rendered events + complete: function( items ) { + newTmplItems = {}; + }, + + // Call this from code which overrides domManip, or equivalent + // Manage cloning/storing template items etc. + afterManip: function afterManip( elem, fragClone, callback ) { + // Provides cloned fragment ready for fixup prior to and after insertion into DOM + var content = fragClone.nodeType === 11 ? + jQuery.makeArray(fragClone.childNodes) : + fragClone.nodeType === 1 ? [fragClone] : []; + + // Return fragment to original caller (e.g. append) for DOM insertion + callback.call( elem, fragClone ); + + // Fragment has been inserted:- Add inserted nodes to tmplItem data structure. Replace inserted element annotations by jQuery.data. + storeTmplItems( content ); + cloneIndex++; + } + }); + + //========================== Private helper functions, used by code above ========================== + + function build( tmplItem, nested, content ) { + // Convert hierarchical content into flat string array + // and finally return array of fragments ready for DOM insertion + var frag, ret = content ? jQuery.map( content, function( item ) { + return (typeof item === "string") ? + // Insert template item annotations, to be converted to jQuery.data( "tmplItem" ) when elems are inserted into DOM. + (tmplItem.key ? item.replace( /(<\w+)(?=[\s>])(?![^>]*_tmplitem)([^>]*)/g, "$1 " + tmplItmAtt + "=\"" + tmplItem.key + "\" $2" ) : item) : + // This is a child template item. Build nested template. + build( item, tmplItem, item._ctnt ); + }) : + // If content is not defined, insert tmplItem directly. Not a template item. May be a string, or a string array, e.g. from {{html $item.html()}}. + tmplItem; + if ( nested ) { + return ret; + } + + // top-level template + ret = ret.join(""); + + // Support templates which have initial or final text nodes, or consist only of text + // Also support HTML entities within the HTML markup. + ret.replace( /^\s*([^<\s][^<]*)?(<[\w\W]+>)([^>]*[^>\s])?\s*$/, function( all, before, middle, after) { + frag = jQuery( middle ).get(); + + storeTmplItems( frag ); + if ( before ) { + frag = unencode( before ).concat(frag); + } + if ( after ) { + frag = frag.concat(unencode( after )); + } + }); + return frag ? frag : unencode( ret ); + } + + function unencode( text ) { + // Use createElement, since createTextNode will not render HTML entities correctly + var el = document.createElement( "div" ); + el.innerHTML = text; + return jQuery.makeArray(el.childNodes); + } + + // Generate a reusable function that will serve to render a template against data + function buildTmplFn( markup ) { + return new Function("jQuery","$item", + "var $=jQuery,call,_=[],$data=$item.data;" + + + // Introduce the data as local variables using with(){} + "with($data){_.push('" + + + // Convert the template into pure JavaScript + jQuery.trim(markup) + .replace( /([\\'])/g, "\\$1" ) + .replace( /[\r\t\n]/g, " " ) + .replace( /\$\{([^\}]*)\}/g, "{{= $1}}" ) + .replace( /\{\{(\/?)(\w+|.)(?:\(((?:[^\}]|\}(?!\}))*?)?\))?(?:\s+(.*?)?)?(\(((?:[^\}]|\}(?!\}))*?)\))?\s*\}\}/g, + function( all, slash, type, fnargs, target, parens, args ) { + var tag = jQuery.tmpl.tag[ type ], def, expr, exprAutoFnDetect; + if ( !tag ) { + throw "Template command not found: " + type; + } + def = tag._default || []; + if ( parens && !/\w$/.test(target)) { + target += parens; + parens = ""; + } + if ( target ) { + target = unescape( target ); + args = args ? ("," + unescape( args ) + ")") : (parens ? ")" : ""); + // Support for target being things like a.toLowerCase(); + // In that case don't call with template item as 'this' pointer. Just evaluate... + expr = parens ? (target.indexOf(".") > -1 ? target + parens : ("(" + target + ").call($item" + args)) : target; + exprAutoFnDetect = parens ? expr : "(typeof(" + target + ")==='function'?(" + target + ").call($item):(" + target + "))"; + } else { + exprAutoFnDetect = expr = def.$1 || "null"; + } + fnargs = unescape( fnargs ); + return "');" + + tag[ slash ? "close" : "open" ] + .split( "$notnull_1" ).join( target ? "typeof(" + target + ")!=='undefined' && (" + target + ")!=null" : "true" ) + .split( "$1a" ).join( exprAutoFnDetect ) + .split( "$1" ).join( expr ) + .split( "$2" ).join( fnargs ? + fnargs.replace( /\s*([^\(]+)\s*(\((.*?)\))?/g, function( all, name, parens, params ) { + params = params ? ("," + params + ")") : (parens ? ")" : ""); + return params ? ("(" + name + ").call($item" + params) : all; + }) + : (def.$2||"") + ) + + "_.push('"; + }) + + "');}return _;" + ); + } + function updateWrapped( options, wrapped ) { + // Build the wrapped content. + options._wrap = build( options, true, + // Suport imperative scenario in which options.wrapped can be set to a selector or an HTML string. + jQuery.isArray( wrapped ) ? wrapped : [htmlExpr.test( wrapped ) ? wrapped : jQuery( wrapped ).html()] + ).join(""); + } + + function unescape( args ) { + return args ? args.replace( /\\'/g, "'").replace(/\\\\/g, "\\" ) : null; + } + function outerHtml( elem ) { + var div = document.createElement("div"); + div.appendChild( elem.cloneNode(true) ); + return div.innerHTML; + } + + // Store template items in jQuery.data(), ensuring a unique tmplItem data data structure for each rendered template instance. + function storeTmplItems( content ) { + var keySuffix = "_" + cloneIndex, elem, elems, newClonedItems = {}, i, l, m; + for ( i = 0, l = content.length; i < l; i++ ) { + if ( (elem = content[i]).nodeType !== 1 ) { + continue; + } + elems = elem.getElementsByTagName("*"); + for ( m = elems.length - 1; m >= 0; m-- ) { + processItemKey( elems[m] ); + } + processItemKey( elem ); + } + function processItemKey( el ) { + var pntKey, pntNode = el, pntItem, tmplItem, key; + // Ensure that each rendered template inserted into the DOM has its own template item, + if ( (key = el.getAttribute( tmplItmAtt ))) { + while ( pntNode.parentNode && (pntNode = pntNode.parentNode).nodeType === 1 && !(pntKey = pntNode.getAttribute( tmplItmAtt ))) { } + if ( pntKey !== key ) { + // The next ancestor with a _tmplitem expando is on a different key than this one. + // So this is a top-level element within this template item + // Set pntNode to the key of the parentNode, or to 0 if pntNode.parentNode is null, or pntNode is a fragment. + pntNode = pntNode.parentNode ? (pntNode.nodeType === 11 ? 0 : (pntNode.getAttribute( tmplItmAtt ) || 0)) : 0; + if ( !(tmplItem = newTmplItems[key]) ) { + // The item is for wrapped content, and was copied from the temporary parent wrappedItem. + tmplItem = wrappedItems[key]; + tmplItem = newTmplItem( tmplItem, newTmplItems[pntNode]||wrappedItems[pntNode], null, true ); + tmplItem.key = ++itemKey; + newTmplItems[itemKey] = tmplItem; + } + if ( cloneIndex ) { + cloneTmplItem( key ); + } + } + el.removeAttribute( tmplItmAtt ); + } else if ( cloneIndex && (tmplItem = jQuery.data( el, "tmplItem" )) ) { + // This was a rendered element, cloned during append or appendTo etc. + // TmplItem stored in jQuery data has already been cloned in cloneCopyEvent. We must replace it with a fresh cloned tmplItem. + cloneTmplItem( tmplItem.key ); + newTmplItems[tmplItem.key] = tmplItem; + pntNode = jQuery.data( el.parentNode, "tmplItem" ); + pntNode = pntNode ? pntNode.key : 0; + } + if ( tmplItem ) { + pntItem = tmplItem; + // Find the template item of the parent element. + // (Using !=, not !==, since pntItem.key is number, and pntNode may be a string) + while ( pntItem && pntItem.key != pntNode ) { + // Add this element as a top-level node for this rendered template item, as well as for any + // ancestor items between this item and the item of its parent element + pntItem.nodes.push( el ); + pntItem = pntItem.parent; + } + // Delete content built during rendering - reduce API surface area and memory use, and avoid exposing of stale data after rendering... + delete tmplItem._ctnt; + delete tmplItem._wrap; + // Store template item as jQuery data on the element + jQuery.data( el, "tmplItem", tmplItem ); + } + function cloneTmplItem( key ) { + key = key + keySuffix; + tmplItem = newClonedItems[key] = + (newClonedItems[key] || newTmplItem( tmplItem, newTmplItems[tmplItem.parent.key + keySuffix] || tmplItem.parent, null, true )); + } + } + } + + //---- Helper functions for template item ---- + + function tiCalls( content, tmpl, data, options ) { + if ( !content ) { + return stack.pop(); + } + stack.push({ _: content, tmpl: tmpl, item:this, data: data, options: options }); + } + + function tiNest( tmpl, data, options ) { + // nested template, using {{tmpl}} tag + return jQuery.tmpl( jQuery.template( tmpl ), data, options, this ); + } + + function tiWrap( call, wrapped ) { + // nested template, using {{wrap}} tag + var options = call.options || {}; + options.wrapped = wrapped; + // Apply the template, which may incorporate wrapped content, + return jQuery.tmpl( jQuery.template( call.tmpl ), call.data, options, call.item ); + } + + function tiHtml( filter, textOnly ) { + var wrapped = this._wrap; + return jQuery.map( + jQuery( jQuery.isArray( wrapped ) ? wrapped.join("") : wrapped ).filter( filter || "*" ), + function(e) { + return textOnly ? + e.innerText || e.textContent : + e.outerHTML || outerHtml(e); + }); + } + + function tiUpdate() { + var coll = this.nodes; + jQuery.tmpl( null, null, null, this).insertBefore( coll[0] ); + jQuery( coll ).remove(); + } +})( jQuery ); diff --git a/underlays/attachment/ikiwiki/jquery.tmpl.min.js b/underlays/attachment/ikiwiki/jquery.tmpl.min.js new file mode 100644 index 000000000..f08e81dcc --- /dev/null +++ b/underlays/attachment/ikiwiki/jquery.tmpl.min.js @@ -0,0 +1 @@ +(function(a){var r=a.fn.domManip,d="_tmplitem",q=/^[^<]*(<[\w\W]+>)[^>]*$|\{\{\! /,b={},f={},e,p={key:0,data:{}},h=0,c=0,l=[];function g(e,d,g,i){var c={data:i||(d?d.data:{}),_wrap:d?d._wrap:null,tmpl:null,parent:d||null,nodes:[],calls:u,nest:w,wrap:x,html:v,update:t};e&&a.extend(c,e,{nodes:[],parent:d});if(g){c.tmpl=g;c._ctnt=c._ctnt||c.tmpl(a,c);c.key=++h;(l.length?f:b)[h]=c}return c}a.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(f,d){a.fn[f]=function(n){var g=[],i=a(n),k,h,m,l,j=this.length===1&&this[0].parentNode;e=b||{};if(j&&j.nodeType===11&&j.childNodes.length===1&&i.length===1){i[d](this[0]);g=this}else{for(h=0,m=i.length;h0?this.clone(true):this).get();a.fn[d].apply(a(i[h]),k);g=g.concat(k)}c=0;g=this.pushStack(g,f,i.selector)}l=e;e=null;a.tmpl.complete(l);return g}});a.fn.extend({tmpl:function(d,c,b){return a.tmpl(this[0],d,c,b)},tmplItem:function(){return a.tmplItem(this[0])},template:function(b){return a.template(b,this[0])},domManip:function(d,l,j){if(d[0]&&d[0].nodeType){var f=a.makeArray(arguments),g=d.length,i=0,h;while(i1)f[0]=[a.makeArray(d)];if(h&&c)f[2]=function(b){a.tmpl.afterManip(this,b,j)};r.apply(this,f)}else r.apply(this,arguments);c=0;!e&&a.tmpl.complete(b);return this}});a.extend({tmpl:function(d,h,e,c){var j,k=!c;if(k){c=p;d=a.template[d]||a.template(null,d);f={}}else if(!d){d=c.tmpl;b[c.key]=c;c.nodes=[];c.wrapped&&n(c,c.wrapped);return a(i(c,null,c.tmpl(a,c)))}if(!d)return[];if(typeof h==="function")h=h.call(c||{});e&&e.wrapped&&n(e,e.wrapped);j=a.isArray(h)?a.map(h,function(a){return a?g(e,c,d,a):null}):[g(e,c,d,h)];return k?a(i(c,null,j)):j},tmplItem:function(b){var c;if(b instanceof a)b=b[0];while(b&&b.nodeType===1&&!(c=a.data(b,"tmplItem"))&&(b=b.parentNode));return c||p},template:function(c,b){if(b){if(typeof b==="string")b=o(b);else if(b instanceof a)b=b[0]||{};if(b.nodeType)b=a.data(b,"tmpl")||a.data(b,"tmpl",o(b.innerHTML));return typeof c==="string"?(a.template[c]=b):b}return c?typeof c!=="string"?a.template(null,c):a.template[c]||a.template(null,q.test(c)?c:a(c)):null},encode:function(a){return(""+a).split("<").join("<").split(">").join(">").split('"').join(""").split("'").join("'")}});a.extend(a.tmpl,{tag:{tmpl:{_default:{$2:"null"},open:"if($notnull_1){_=_.concat($item.nest($1,$2));}"},wrap:{_default:{$2:"null"},open:"$item.calls(_,$1,$2);_=[];",close:"call=$item.calls();_=call._.concat($item.wrap(call,_));"},each:{_default:{$2:"$index, $value"},open:"if($notnull_1){$.each($1a,function($2){with(this){",close:"}});}"},"if":{open:"if(($notnull_1) && $1a){",close:"}"},"else":{_default:{$1:"true"},open:"}else if(($notnull_1) && $1a){"},html:{open:"if($notnull_1){_.push($1a);}"},"=":{_default:{$1:"$data"},open:"if($notnull_1){_.push($.encode($1a));}"},"!":{open:""}},complete:function(){b={}},afterManip:function(f,b,d){var e=b.nodeType===11?a.makeArray(b.childNodes):b.nodeType===1?[b]:[];d.call(f,b);m(e);c++}});function i(e,g,f){var b,c=f?a.map(f,function(a){return typeof a==="string"?e.key?a.replace(/(<\w+)(?=[\s>])(?![^>]*_tmplitem)([^>]*)/g,"$1 "+d+'="'+e.key+'" $2'):a:i(a,e,a._ctnt)}):e;if(g)return c;c=c.join("");c.replace(/^\s*([^<\s][^<]*)?(<[\w\W]+>)([^>]*[^>\s])?\s*$/,function(f,c,e,d){b=a(e).get();m(b);if(c)b=j(c).concat(b);if(d)b=b.concat(j(d))});return b?b:j(c)}function j(c){var b=document.createElement("div");b.innerHTML=c;return a.makeArray(b.childNodes)}function o(b){return new Function("jQuery","$item","var $=jQuery,call,_=[],$data=$item.data;with($data){_.push('"+a.trim(b).replace(/([\\'])/g,"\\$1").replace(/[\r\t\n]/g," ").replace(/\$\{([^\}]*)\}/g,"{{= $1}}").replace(/\{\{(\/?)(\w+|.)(?:\(((?:[^\}]|\}(?!\}))*?)?\))?(?:\s+(.*?)?)?(\(((?:[^\}]|\}(?!\}))*?)\))?\s*\}\}/g,function(m,l,j,d,b,c,e){var i=a.tmpl.tag[j],h,f,g;if(!i)throw"Template command not found: "+j;h=i._default||[];if(c&&!/\w$/.test(b)){b+=c;c=""}if(b){b=k(b);e=e?","+k(e)+")":c?")":"";f=c?b.indexOf(".")>-1?b+c:"("+b+").call($item"+e:b;g=c?f:"(typeof("+b+")==='function'?("+b+").call($item):("+b+"))"}else g=f=h.$1||"null";d=k(d);return"');"+i[l?"close":"open"].split("$notnull_1").join(b?"typeof("+b+")!=='undefined' && ("+b+")!=null":"true").split("$1a").join(g).split("$1").join(f).split("$2").join(d?d.replace(/\s*([^\(]+)\s*(\((.*?)\))?/g,function(d,c,b,a){a=a?","+a+")":b?")":"";return a?"("+c+").call($item"+a:d}):h.$2||"")+"_.push('"})+"');}return _;")}function n(c,b){c._wrap=i(c,true,a.isArray(b)?b:[q.test(b)?b:a(b).html()]).join("")}function k(a){return a?a.replace(/\\'/g,"'").replace(/\\\\/g,"\\"):null}function s(b){var a=document.createElement("div");a.appendChild(b.cloneNode(true));return a.innerHTML}function m(o){var n="_"+c,k,j,l={},e,p,i;for(e=0,p=o.length;e=0;i--)m(j[i]);m(k)}function m(j){var p,i=j,k,e,m;if(m=j.getAttribute(d)){while(i.parentNode&&(i=i.parentNode).nodeType===1&&!(p=i.getAttribute(d)));if(p!==m){i=i.parentNode?i.nodeType===11?0:i.getAttribute(d)||0:0;if(!(e=b[m])){e=f[m];e=g(e,b[i]||f[i],null,true);e.key=++h;b[h]=e}c&&o(m)}j.removeAttribute(d)}else if(c&&(e=a.data(j,"tmplItem"))){o(e.key);b[e.key]=e;i=a.data(j.parentNode,"tmplItem");i=i?i.key:0}if(e){k=e;while(k&&k.key!=i){k.nodes.push(j);k=k.parent}delete e._ctnt;delete e._wrap;a.data(j,"tmplItem",e)}function o(a){a=a+n;e=l[a]=l[a]||g(e,b[e.parent.key+n]||e.parent,null,true)}}}function u(a,d,c,b){if(!a)return l.pop();l.push({_:a,tmpl:d,item:this,data:c,options:b})}function w(d,c,b){return a.tmpl(a.template(d),c,b,this)}function x(b,d){var c=b.options||{};c.wrapped=d;return a.tmpl(a.template(b.tmpl),b.data,c,b.item)}function v(d,c){var b=this._wrap;return a.map(a(a.isArray(b)?b.join(""):b).filter(d||"*"),function(a){return c?a.innerText||a.textContent:a.outerHTML||s(a)})}function t(){var b=this.nodes;a.tmpl(null,null,null,this).insertBefore(b[0]);a(b).remove()}})(jQuery) \ No newline at end of file diff --git a/underlays/basewiki/favicon.ico b/underlays/basewiki/favicon.ico new file mode 120000 index 000000000..399fec7c6 --- /dev/null +++ b/underlays/basewiki/favicon.ico @@ -0,0 +1 @@ +../../doc/favicon.ico \ No newline at end of file diff --git a/underlays/basewiki/ikiwiki.mdwn b/underlays/basewiki/ikiwiki.mdwn new file mode 120000 index 000000000..6d43605d5 --- /dev/null +++ b/underlays/basewiki/ikiwiki.mdwn @@ -0,0 +1 @@ +../../doc/ikiwiki.mdwn \ No newline at end of file diff --git a/underlays/basewiki/ikiwiki/directive.mdwn b/underlays/basewiki/ikiwiki/directive.mdwn new file mode 120000 index 000000000..ba130b744 --- /dev/null +++ b/underlays/basewiki/ikiwiki/directive.mdwn @@ -0,0 +1 @@ +../../../doc/ikiwiki/directive.mdwn \ No newline at end of file diff --git a/underlays/basewiki/ikiwiki/formatting.mdwn b/underlays/basewiki/ikiwiki/formatting.mdwn new file mode 120000 index 000000000..cf9d704c6 --- /dev/null +++ b/underlays/basewiki/ikiwiki/formatting.mdwn @@ -0,0 +1 @@ +../../../doc/ikiwiki/formatting.mdwn \ No newline at end of file diff --git a/underlays/basewiki/ikiwiki/markdown.mdwn b/underlays/basewiki/ikiwiki/markdown.mdwn new file mode 120000 index 000000000..7e7417010 --- /dev/null +++ b/underlays/basewiki/ikiwiki/markdown.mdwn @@ -0,0 +1 @@ +../../../doc/ikiwiki/markdown.mdwn \ No newline at end of file diff --git a/underlays/basewiki/ikiwiki/openid.mdwn b/underlays/basewiki/ikiwiki/openid.mdwn new file mode 120000 index 000000000..f4644f74d --- /dev/null +++ b/underlays/basewiki/ikiwiki/openid.mdwn @@ -0,0 +1 @@ +../../../doc/ikiwiki/openid.mdwn \ No newline at end of file diff --git a/underlays/basewiki/ikiwiki/pagespec.mdwn b/underlays/basewiki/ikiwiki/pagespec.mdwn new file mode 120000 index 000000000..0d7bba269 --- /dev/null +++ b/underlays/basewiki/ikiwiki/pagespec.mdwn @@ -0,0 +1 @@ +../../../doc/ikiwiki/pagespec.mdwn \ No newline at end of file diff --git a/underlays/basewiki/ikiwiki/pagespec/attachment.mdwn b/underlays/basewiki/ikiwiki/pagespec/attachment.mdwn new file mode 120000 index 000000000..ea6c45a78 --- /dev/null +++ b/underlays/basewiki/ikiwiki/pagespec/attachment.mdwn @@ -0,0 +1 @@ +../../../../doc/ikiwiki/pagespec/attachment.mdwn \ No newline at end of file diff --git a/underlays/basewiki/ikiwiki/pagespec/po.mdwn b/underlays/basewiki/ikiwiki/pagespec/po.mdwn new file mode 120000 index 000000000..255c3de9a --- /dev/null +++ b/underlays/basewiki/ikiwiki/pagespec/po.mdwn @@ -0,0 +1 @@ +../../../../doc/ikiwiki/pagespec/po.mdwn \ No newline at end of file diff --git a/underlays/basewiki/ikiwiki/pagespec/sorting.mdwn b/underlays/basewiki/ikiwiki/pagespec/sorting.mdwn new file mode 120000 index 000000000..93ccbb18d --- /dev/null +++ b/underlays/basewiki/ikiwiki/pagespec/sorting.mdwn @@ -0,0 +1 @@ +../../../../doc/ikiwiki/pagespec/sorting.mdwn \ No newline at end of file diff --git a/underlays/basewiki/ikiwiki/searching.mdwn b/underlays/basewiki/ikiwiki/searching.mdwn new file mode 120000 index 000000000..d94120e36 --- /dev/null +++ b/underlays/basewiki/ikiwiki/searching.mdwn @@ -0,0 +1 @@ +../../../doc/ikiwiki/searching.mdwn \ No newline at end of file diff --git a/underlays/basewiki/ikiwiki/subpage.mdwn b/underlays/basewiki/ikiwiki/subpage.mdwn new file mode 120000 index 000000000..f1109f251 --- /dev/null +++ b/underlays/basewiki/ikiwiki/subpage.mdwn @@ -0,0 +1 @@ +../../../doc/ikiwiki/subpage.mdwn \ No newline at end of file diff --git a/underlays/basewiki/ikiwiki/subpage/linkingrules.mdwn b/underlays/basewiki/ikiwiki/subpage/linkingrules.mdwn new file mode 120000 index 000000000..6694188b2 --- /dev/null +++ b/underlays/basewiki/ikiwiki/subpage/linkingrules.mdwn @@ -0,0 +1 @@ +../../../../doc/ikiwiki/subpage/linkingrules.mdwn \ No newline at end of file diff --git a/underlays/basewiki/ikiwiki/wikilink.mdwn b/underlays/basewiki/ikiwiki/wikilink.mdwn new file mode 120000 index 000000000..0fb5cc3f2 --- /dev/null +++ b/underlays/basewiki/ikiwiki/wikilink.mdwn @@ -0,0 +1 @@ +../../../doc/ikiwiki/wikilink.mdwn \ No newline at end of file diff --git a/underlays/basewiki/index.mdwn b/underlays/basewiki/index.mdwn new file mode 120000 index 000000000..37c114529 --- /dev/null +++ b/underlays/basewiki/index.mdwn @@ -0,0 +1 @@ +../../doc/basewiki/index.mdwn \ No newline at end of file diff --git a/underlays/basewiki/local.css b/underlays/basewiki/local.css new file mode 120000 index 000000000..01a7b0448 --- /dev/null +++ b/underlays/basewiki/local.css @@ -0,0 +1 @@ +../../doc/local.css \ No newline at end of file diff --git a/underlays/basewiki/recentchanges.mdwn b/underlays/basewiki/recentchanges.mdwn new file mode 120000 index 000000000..7bd039623 --- /dev/null +++ b/underlays/basewiki/recentchanges.mdwn @@ -0,0 +1 @@ +../../doc/recentchanges.mdwn \ No newline at end of file diff --git a/underlays/basewiki/sandbox.mdwn b/underlays/basewiki/sandbox.mdwn new file mode 120000 index 000000000..0761adf3c --- /dev/null +++ b/underlays/basewiki/sandbox.mdwn @@ -0,0 +1 @@ +../../doc/basewiki/sandbox.mdwn \ No newline at end of file diff --git a/underlays/basewiki/shortcuts.mdwn b/underlays/basewiki/shortcuts.mdwn new file mode 120000 index 000000000..2e6bfcdc2 --- /dev/null +++ b/underlays/basewiki/shortcuts.mdwn @@ -0,0 +1 @@ +../../doc/shortcuts.mdwn \ No newline at end of file diff --git a/underlays/basewiki/style.css b/underlays/basewiki/style.css new file mode 120000 index 000000000..9383b4afe --- /dev/null +++ b/underlays/basewiki/style.css @@ -0,0 +1 @@ +../../doc/style.css \ No newline at end of file diff --git a/underlays/basewiki/templates.mdwn b/underlays/basewiki/templates.mdwn new file mode 120000 index 000000000..a7bb48f95 --- /dev/null +++ b/underlays/basewiki/templates.mdwn @@ -0,0 +1 @@ +../../doc/templates.mdwn \ No newline at end of file diff --git a/underlays/basewiki/templates/note.mdwn b/underlays/basewiki/templates/note.mdwn new file mode 120000 index 000000000..f44d40c80 --- /dev/null +++ b/underlays/basewiki/templates/note.mdwn @@ -0,0 +1 @@ +../../../doc/templates/note.mdwn \ No newline at end of file diff --git a/underlays/basewiki/templates/popup.mdwn b/underlays/basewiki/templates/popup.mdwn new file mode 120000 index 000000000..4761d7f4f --- /dev/null +++ b/underlays/basewiki/templates/popup.mdwn @@ -0,0 +1 @@ +../../../doc/templates/popup.mdwn \ No newline at end of file diff --git a/underlays/basewiki/wikiicons b/underlays/basewiki/wikiicons new file mode 120000 index 000000000..b333d714a --- /dev/null +++ b/underlays/basewiki/wikiicons @@ -0,0 +1 @@ +../../doc/wikiicons \ No newline at end of file diff --git a/underlays/javascript/ikiwiki/ikiwiki.js b/underlays/javascript/ikiwiki/ikiwiki.js new file mode 100644 index 000000000..aebc5cf7e --- /dev/null +++ b/underlays/javascript/ikiwiki/ikiwiki.js @@ -0,0 +1,54 @@ +// ikiwiki's javascript utility function library + +var hooks; + +// Run onload as soon as the DOM is ready, if possible. +// gecko, opera 9 +if (document.addEventListener) { + document.addEventListener("DOMContentLoaded", run_hooks_onload, false); +} +// other browsers +window.onload = run_hooks_onload; + +var onload_done = 0; + +function run_hooks_onload() { + // avoid firing twice + if (onload_done) + return; + onload_done = true; + + run_hooks("onload"); +} + +function run_hooks(name) { + if (typeof(hooks) != "undefined") { + for (var i = 0; i < hooks.length; i++) { + if (hooks[i].name == name) { + hooks[i].call(); + } + } + } +} + +function hook(name, call) { + if (typeof(hooks) == "undefined") + hooks = new Array; + hooks.push({name: name, call: call}); +} + +function getElementsByClass(cls, node, tag) { + if (document.getElementsByClass) + return document.getElementsByClass(cls, node, tag); + if (! node) node = document; + if (! tag) tag = '*'; + var ret = new Array(); + var pattern = new RegExp("(^|\\s)"+cls+"(\\s|$)"); + var els = node.getElementsByTagName(tag); + for (i = 0; i < els.length; i++) { + if ( pattern.test(els[i].className) ) { + ret.push(els[i]); + } + } + return ret; +} diff --git a/underlays/javascript/ikiwiki/relativedate.js b/underlays/javascript/ikiwiki/relativedate.js new file mode 100644 index 000000000..2a270d627 --- /dev/null +++ b/underlays/javascript/ikiwiki/relativedate.js @@ -0,0 +1,75 @@ +// Causes html elements in the 'relativedate' class to be displayed +// as relative dates. The date is parsed from the title attribute, or from +// the element content. + +var dateElements; + +hook("onload", getDates); + +function getDates() { + dateElements = getElementsByClass('relativedate'); + for (var i = 0; i < dateElements.length; i++) { + var elt = dateElements[i]; + var title = elt.attributes.title; + var d = new Date(title ? title.value : elt.innerHTML); + if (! isNaN(d)) { + dateElements[i].date=d; + elt.title=elt.innerHTML; + } + } + + showDates(); +} + +function showDates() { + for (var i = 0; i < dateElements.length; i++) { + var elt = dateElements[i]; + var d = elt.date; + if (! isNaN(d)) { + elt.innerHTML=relativeDate(d); + } + } + setTimeout(showDates,30000); // keep updating every 30s +} + +var timeUnits = [ + { unit: 'year', seconds: 60 * 60 * 24 * 364 }, + { unit: 'month', seconds: 60 * 60 * 24 * 30 }, + { unit: 'day', seconds: 60 * 60 * 24 }, + { unit: 'hour', seconds: 60 * 60 }, + { unit: 'minute', seconds: 60 }, +]; + +function relativeDate(date) { + var now = new Date(); + var offset = date.getTime() - now.getTime(); + var seconds = Math.round(Math.abs(offset) / 1000); + + // hack to avoid reading just in the future if there is a minor + // amount of clock slip + if (offset >= 0 && seconds < 30 * 60 * 60) { + return "just now"; + } + + var ret = ""; + var shown = 0; + for (i = 0; i < timeUnits.length; i++) { + if (seconds >= timeUnits[i].seconds) { + var num = Math.floor(seconds / timeUnits[i].seconds); + seconds -= num * timeUnits[i].seconds; + if (ret) + ret += "and "; + ret += num + " " + timeUnits[i].unit + (num > 1 ? "s" : "") + " "; + + if (++shown == 2) + break; + } + else if (shown) + break; + } + + if (! ret) + ret = "less than a minute " + + return ret + (offset < 0 ? "ago" : "from now"); +} diff --git a/underlays/javascript/ikiwiki/toggle.js b/underlays/javascript/ikiwiki/toggle.js new file mode 100644 index 000000000..d190b737a --- /dev/null +++ b/underlays/javascript/ikiwiki/toggle.js @@ -0,0 +1,29 @@ +// Uses CSS to hide toggleables, to avoid any flashing on page load. The +// CSS is only emitted after it tests that it's going to be able +// to show the toggleables. +if (document.getElementById && document.getElementsByTagName && document.createTextNode) { + document.write(''); + hook("onload", inittoggle); +} + +function inittoggle() { + var as = getElementsByClass('toggle'); + for (var i = 0; i < as.length; i++) { + var id = as[i].href.match(/#(\w.+)/)[1]; + if (document.getElementById(id).className == "toggleable") + document.getElementById(id).style.display="none"; + as[i].onclick = function() { + toggle(this); + return false; + } + } +} + +function toggle(s) { + var id = s.href.match(/#(\w.+)/)[1]; + style = document.getElementById(id).style; + if (style.display == "none") + style.display = "block"; + else + style.display = "none"; +} diff --git a/underlays/jquery/ikiwiki/jquery.js b/underlays/jquery/ikiwiki/jquery.js new file mode 100644 index 000000000..f3201aacb --- /dev/null +++ b/underlays/jquery/ikiwiki/jquery.js @@ -0,0 +1,8981 @@ +/*! + * jQuery JavaScript Library v1.6.2 + * http://jquery.com/ + * + * Copyright 2011, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * Copyright 2011, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * + * Date: Thu Jun 30 14:16:56 2011 -0400 + */ +(function( window, undefined ) { + +// Use the correct document accordingly with window argument (sandbox) +var document = window.document, + navigator = window.navigator, + location = window.location; +var jQuery = (function() { + +// Define a local copy of jQuery +var jQuery = function( selector, context ) { + // The jQuery object is actually just the init constructor 'enhanced' + return new jQuery.fn.init( selector, context, rootjQuery ); + }, + + // Map over jQuery in case of overwrite + _jQuery = window.jQuery, + + // Map over the $ in case of overwrite + _$ = window.$, + + // A central reference to the root jQuery(document) + rootjQuery, + + // A simple way to check for HTML strings or ID strings + // (both of which we optimize for) + quickExpr = /^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, + + // Check if a string has a non-whitespace character in it + rnotwhite = /\S/, + + // Used for trimming whitespace + trimLeft = /^\s+/, + trimRight = /\s+$/, + + // Check for digits + rdigit = /\d/, + + // Match a standalone tag + rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/, + + // JSON RegExp + rvalidchars = /^[\],:{}\s]*$/, + rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, + rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, + rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, + + // Useragent RegExp + rwebkit = /(webkit)[ \/]([\w.]+)/, + ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/, + rmsie = /(msie) ([\w.]+)/, + rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/, + + // Matches dashed string for camelizing + rdashAlpha = /-([a-z])/ig, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return letter.toUpperCase(); + }, + + // Keep a UserAgent string for use with jQuery.browser + userAgent = navigator.userAgent, + + // For matching the engine and version of the browser + browserMatch, + + // The deferred used on DOM ready + readyList, + + // The ready event handler + DOMContentLoaded, + + // Save a reference to some core methods + toString = Object.prototype.toString, + hasOwn = Object.prototype.hasOwnProperty, + push = Array.prototype.push, + slice = Array.prototype.slice, + trim = String.prototype.trim, + indexOf = Array.prototype.indexOf, + + // [[Class]] -> type pairs + class2type = {}; + +jQuery.fn = jQuery.prototype = { + constructor: jQuery, + init: function( selector, context, rootjQuery ) { + var match, elem, ret, doc; + + // Handle $(""), $(null), or $(undefined) + if ( !selector ) { + return this; + } + + // Handle $(DOMElement) + if ( selector.nodeType ) { + this.context = this[0] = selector; + this.length = 1; + return this; + } + + // The body element only exists once, optimize finding it + if ( selector === "body" && !context && document.body ) { + this.context = document; + this[0] = document.body; + this.selector = selector; + this.length = 1; + return this; + } + + // Handle HTML strings + if ( typeof selector === "string" ) { + // Are we dealing with HTML string or an ID? + if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = quickExpr.exec( selector ); + } + + // Verify a match, and that no context was specified for #id + if ( match && (match[1] || !context) ) { + + // HANDLE: $(html) -> $(array) + if ( match[1] ) { + context = context instanceof jQuery ? context[0] : context; + doc = (context ? context.ownerDocument || context : document); + + // If a single string is passed in and it's a single tag + // just do a createElement and skip the rest + ret = rsingleTag.exec( selector ); + + if ( ret ) { + if ( jQuery.isPlainObject( context ) ) { + selector = [ document.createElement( ret[1] ) ]; + jQuery.fn.attr.call( selector, context, true ); + + } else { + selector = [ doc.createElement( ret[1] ) ]; + } + + } else { + ret = jQuery.buildFragment( [ match[1] ], [ doc ] ); + selector = (ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment).childNodes; + } + + return jQuery.merge( this, selector ); + + // HANDLE: $("#id") + } else { + elem = document.getElementById( match[2] ); + + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id !== match[2] ) { + return rootjQuery.find( selector ); + } + + // Otherwise, we inject the element directly into the jQuery object + this.length = 1; + this[0] = elem; + } + + this.context = document; + this.selector = selector; + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return (context || rootjQuery).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return rootjQuery.ready( selector ); + } + + if (selector.selector !== undefined) { + this.selector = selector.selector; + this.context = selector.context; + } + + return jQuery.makeArray( selector, this ); + }, + + // Start with an empty selector + selector: "", + + // The current version of jQuery being used + jquery: "1.6.2", + + // The default length of a jQuery object is 0 + length: 0, + + // The number of elements contained in the matched element set + size: function() { + return this.length; + }, + + toArray: function() { + return slice.call( this, 0 ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + return num == null ? + + // Return a 'clean' array + this.toArray() : + + // Return just the object + ( num < 0 ? this[ this.length + num ] : this[ num ] ); + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems, name, selector ) { + // Build a new jQuery matched element set + var ret = this.constructor(); + + if ( jQuery.isArray( elems ) ) { + push.apply( ret, elems ); + + } else { + jQuery.merge( ret, elems ); + } + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + ret.context = this.context; + + if ( name === "find" ) { + ret.selector = this.selector + (this.selector ? " " : "") + selector; + } else if ( name ) { + ret.selector = this.selector + "." + name + "(" + selector + ")"; + } + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + // (You can seed the arguments with an array of args, but this is + // only used internally.) + each: function( callback, args ) { + return jQuery.each( this, callback, args ); + }, + + ready: function( fn ) { + // Attach the listeners + jQuery.bindReady(); + + // Add the callback + readyList.done( fn ); + + return this; + }, + + eq: function( i ) { + return i === -1 ? + this.slice( i ) : + this.slice( i, +i + 1 ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ), + "slice", slice.call(arguments).join(",") ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map(this, function( elem, i ) { + return callback.call( elem, i, elem ); + })); + }, + + end: function() { + return this.prevObject || this.constructor(null); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: [].sort, + splice: [].splice +}; + +// Give the init function the jQuery prototype for later instantiation +jQuery.fn.init.prototype = jQuery.fn; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + target = arguments[1] || {}; + // skip the boolean and the target + i = 2; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction(target) ) { + target = {}; + } + + // extend jQuery itself if only one argument is passed + if ( length === i ) { + target = this; + --i; + } + + for ( ; i < length; i++ ) { + // Only deal with non-null/undefined values + if ( (options = arguments[ i ]) != null ) { + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { + if ( copyIsArray ) { + copyIsArray = false; + clone = src && jQuery.isArray(src) ? src : []; + + } else { + clone = src && jQuery.isPlainObject(src) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend({ + noConflict: function( deep ) { + if ( window.$ === jQuery ) { + window.$ = _$; + } + + if ( deep && window.jQuery === jQuery ) { + window.jQuery = _jQuery; + } + + return jQuery; + }, + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Hold (or release) the ready event + holdReady: function( hold ) { + if ( hold ) { + jQuery.readyWait++; + } else { + jQuery.ready( true ); + } + }, + + // Handle when the DOM is ready + ready: function( wait ) { + // Either a released hold or an DOMready/load event and not yet ready + if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) { + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( !document.body ) { + return setTimeout( jQuery.ready, 1 ); + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + + // Trigger any bound ready events + if ( jQuery.fn.trigger ) { + jQuery( document ).trigger( "ready" ).unbind( "ready" ); + } + } + }, + + bindReady: function() { + if ( readyList ) { + return; + } + + readyList = jQuery._Deferred(); + + // Catch cases where $(document).ready() is called after the + // browser event has already occurred. + if ( document.readyState === "complete" ) { + // Handle it asynchronously to allow scripts the opportunity to delay ready + return setTimeout( jQuery.ready, 1 ); + } + + // Mozilla, Opera and webkit nightlies currently support this event + if ( document.addEventListener ) { + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", jQuery.ready, false ); + + // If IE event model is used + } else if ( document.attachEvent ) { + // ensure firing before onload, + // maybe late but safe also for iframes + document.attachEvent( "onreadystatechange", DOMContentLoaded ); + + // A fallback to window.onload, that will always work + window.attachEvent( "onload", jQuery.ready ); + + // If IE and not a frame + // continually check to see if the document is ready + var toplevel = false; + + try { + toplevel = window.frameElement == null; + } catch(e) {} + + if ( document.documentElement.doScroll && toplevel ) { + doScrollCheck(); + } + } + }, + + // See test/unit/core.js for details concerning isFunction. + // Since version 1.3, DOM methods and functions like alert + // aren't supported. They return false on IE (#2968). + isFunction: function( obj ) { + return jQuery.type(obj) === "function"; + }, + + isArray: Array.isArray || function( obj ) { + return jQuery.type(obj) === "array"; + }, + + // A crude way of determining if an object is a window + isWindow: function( obj ) { + return obj && typeof obj === "object" && "setInterval" in obj; + }, + + isNaN: function( obj ) { + return obj == null || !rdigit.test( obj ) || isNaN( obj ); + }, + + type: function( obj ) { + return obj == null ? + String( obj ) : + class2type[ toString.call(obj) ] || "object"; + }, + + isPlainObject: function( obj ) { + // Must be an Object. + // Because of IE, we also have to check the presence of the constructor property. + // Make sure that DOM nodes and window objects don't pass through, as well + if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { + return false; + } + + // Not own constructor property must be Object + if ( obj.constructor && + !hasOwn.call(obj, "constructor") && + !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { + return false; + } + + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own. + + var key; + for ( key in obj ) {} + + return key === undefined || hasOwn.call( obj, key ); + }, + + isEmptyObject: function( obj ) { + for ( var name in obj ) { + return false; + } + return true; + }, + + error: function( msg ) { + throw msg; + }, + + parseJSON: function( data ) { + if ( typeof data !== "string" || !data ) { + return null; + } + + // Make sure leading/trailing whitespace is removed (IE can't handle it) + data = jQuery.trim( data ); + + // Attempt to parse using the native JSON parser first + if ( window.JSON && window.JSON.parse ) { + return window.JSON.parse( data ); + } + + // Make sure the incoming data is actual JSON + // Logic borrowed from http://json.org/json2.js + if ( rvalidchars.test( data.replace( rvalidescape, "@" ) + .replace( rvalidtokens, "]" ) + .replace( rvalidbraces, "")) ) { + + return (new Function( "return " + data ))(); + + } + jQuery.error( "Invalid JSON: " + data ); + }, + + // Cross-browser xml parsing + // (xml & tmp used internally) + parseXML: function( data , xml , tmp ) { + + if ( window.DOMParser ) { // Standard + tmp = new DOMParser(); + xml = tmp.parseFromString( data , "text/xml" ); + } else { // IE + xml = new ActiveXObject( "Microsoft.XMLDOM" ); + xml.async = "false"; + xml.loadXML( data ); + } + + tmp = xml.documentElement; + + if ( ! tmp || ! tmp.nodeName || tmp.nodeName === "parsererror" ) { + jQuery.error( "Invalid XML: " + data ); + } + + return xml; + }, + + noop: function() {}, + + // Evaluates a script in a global context + // Workarounds based on findings by Jim Driscoll + // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context + globalEval: function( data ) { + if ( data && rnotwhite.test( data ) ) { + // We use execScript on Internet Explorer + // We use an anonymous function so that context is window + // rather than jQuery in Firefox + ( window.execScript || function( data ) { + window[ "eval" ].call( window, data ); + } )( data ); + } + }, + + // Converts a dashed string to camelCased string; + // Used by both the css and data modules + camelCase: function( string ) { + return string.replace( rdashAlpha, fcamelCase ); + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); + }, + + // args is for internal usage only + each: function( object, callback, args ) { + var name, i = 0, + length = object.length, + isObj = length === undefined || jQuery.isFunction( object ); + + if ( args ) { + if ( isObj ) { + for ( name in object ) { + if ( callback.apply( object[ name ], args ) === false ) { + break; + } + } + } else { + for ( ; i < length; ) { + if ( callback.apply( object[ i++ ], args ) === false ) { + break; + } + } + } + + // A special, fast, case for the most common use of each + } else { + if ( isObj ) { + for ( name in object ) { + if ( callback.call( object[ name ], name, object[ name ] ) === false ) { + break; + } + } + } else { + for ( ; i < length; ) { + if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) { + break; + } + } + } + } + + return object; + }, + + // Use native String.trim function wherever possible + trim: trim ? + function( text ) { + return text == null ? + "" : + trim.call( text ); + } : + + // Otherwise use our own trimming functionality + function( text ) { + return text == null ? + "" : + text.toString().replace( trimLeft, "" ).replace( trimRight, "" ); + }, + + // results is for internal usage only + makeArray: function( array, results ) { + var ret = results || []; + + if ( array != null ) { + // The window, strings (and functions) also have 'length' + // The extra typeof function check is to prevent crashes + // in Safari 2 (See: #3039) + // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 + var type = jQuery.type( array ); + + if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) { + push.call( ret, array ); + } else { + jQuery.merge( ret, array ); + } + } + + return ret; + }, + + inArray: function( elem, array ) { + + if ( indexOf ) { + return indexOf.call( array, elem ); + } + + for ( var i = 0, length = array.length; i < length; i++ ) { + if ( array[ i ] === elem ) { + return i; + } + } + + return -1; + }, + + merge: function( first, second ) { + var i = first.length, + j = 0; + + if ( typeof second.length === "number" ) { + for ( var l = second.length; j < l; j++ ) { + first[ i++ ] = second[ j ]; + } + + } else { + while ( second[j] !== undefined ) { + first[ i++ ] = second[ j++ ]; + } + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, inv ) { + var ret = [], retVal; + inv = !!inv; + + // Go through the array, only saving the items + // that pass the validator function + for ( var i = 0, length = elems.length; i < length; i++ ) { + retVal = !!callback( elems[ i ], i ); + if ( inv !== retVal ) { + ret.push( elems[ i ] ); + } + } + + return ret; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var value, key, ret = [], + i = 0, + length = elems.length, + // jquery objects are treated as arrays + isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ; + + // Go through the array, translating each of the items to their + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + + // Go through every key on the object, + } else { + for ( key in elems ) { + value = callback( elems[ key ], key, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + } + + // Flatten any nested arrays + return ret.concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + if ( typeof context === "string" ) { + var tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + var args = slice.call( arguments, 2 ), + proxy = function() { + return fn.apply( context, args.concat( slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; + + return proxy; + }, + + // Mutifunctional method to get and set values to a collection + // The value/s can optionally be executed if it's a function + access: function( elems, key, value, exec, fn, pass ) { + var length = elems.length; + + // Setting many attributes + if ( typeof key === "object" ) { + for ( var k in key ) { + jQuery.access( elems, k, key[k], exec, fn, value ); + } + return elems; + } + + // Setting one attribute + if ( value !== undefined ) { + // Optionally, function values get executed if exec is true + exec = !pass && exec && jQuery.isFunction(value); + + for ( var i = 0; i < length; i++ ) { + fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); + } + + return elems; + } + + // Getting an attribute + return length ? fn( elems[0], key ) : undefined; + }, + + now: function() { + return (new Date()).getTime(); + }, + + // Use of jQuery.browser is frowned upon. + // More details: http://docs.jquery.com/Utilities/jQuery.browser + uaMatch: function( ua ) { + ua = ua.toLowerCase(); + + var match = rwebkit.exec( ua ) || + ropera.exec( ua ) || + rmsie.exec( ua ) || + ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) || + []; + + return { browser: match[1] || "", version: match[2] || "0" }; + }, + + sub: function() { + function jQuerySub( selector, context ) { + return new jQuerySub.fn.init( selector, context ); + } + jQuery.extend( true, jQuerySub, this ); + jQuerySub.superclass = this; + jQuerySub.fn = jQuerySub.prototype = this(); + jQuerySub.fn.constructor = jQuerySub; + jQuerySub.sub = this.sub; + jQuerySub.fn.init = function init( selector, context ) { + if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) { + context = jQuerySub( context ); + } + + return jQuery.fn.init.call( this, selector, context, rootjQuerySub ); + }; + jQuerySub.fn.init.prototype = jQuerySub.fn; + var rootjQuerySub = jQuerySub(document); + return jQuerySub; + }, + + browser: {} +}); + +// Populate the class2type map +jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +}); + +browserMatch = jQuery.uaMatch( userAgent ); +if ( browserMatch.browser ) { + jQuery.browser[ browserMatch.browser ] = true; + jQuery.browser.version = browserMatch.version; +} + +// Deprecated, use jQuery.browser.webkit instead +if ( jQuery.browser.webkit ) { + jQuery.browser.safari = true; +} + +// IE doesn't match non-breaking spaces with \s +if ( rnotwhite.test( "\xA0" ) ) { + trimLeft = /^[\s\xA0]+/; + trimRight = /[\s\xA0]+$/; +} + +// All jQuery objects should point back to these +rootjQuery = jQuery(document); + +// Cleanup functions for the document ready method +if ( document.addEventListener ) { + DOMContentLoaded = function() { + document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + jQuery.ready(); + }; + +} else if ( document.attachEvent ) { + DOMContentLoaded = function() { + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( document.readyState === "complete" ) { + document.detachEvent( "onreadystatechange", DOMContentLoaded ); + jQuery.ready(); + } + }; +} + +// The DOM ready check for Internet Explorer +function doScrollCheck() { + if ( jQuery.isReady ) { + return; + } + + try { + // If IE is used, use the trick by Diego Perini + // http://javascript.nwbox.com/IEContentLoaded/ + document.documentElement.doScroll("left"); + } catch(e) { + setTimeout( doScrollCheck, 1 ); + return; + } + + // and execute any waiting functions + jQuery.ready(); +} + +return jQuery; + +})(); + + +var // Promise methods + promiseMethods = "done fail isResolved isRejected promise then always pipe".split( " " ), + // Static reference to slice + sliceDeferred = [].slice; + +jQuery.extend({ + // Create a simple deferred (one callbacks list) + _Deferred: function() { + var // callbacks list + callbacks = [], + // stored [ context , args ] + fired, + // to avoid firing when already doing so + firing, + // flag to know if the deferred has been cancelled + cancelled, + // the deferred itself + deferred = { + + // done( f1, f2, ...) + done: function() { + if ( !cancelled ) { + var args = arguments, + i, + length, + elem, + type, + _fired; + if ( fired ) { + _fired = fired; + fired = 0; + } + for ( i = 0, length = args.length; i < length; i++ ) { + elem = args[ i ]; + type = jQuery.type( elem ); + if ( type === "array" ) { + deferred.done.apply( deferred, elem ); + } else if ( type === "function" ) { + callbacks.push( elem ); + } + } + if ( _fired ) { + deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] ); + } + } + return this; + }, + + // resolve with given context and args + resolveWith: function( context, args ) { + if ( !cancelled && !fired && !firing ) { + // make sure args are available (#8421) + args = args || []; + firing = 1; + try { + while( callbacks[ 0 ] ) { + callbacks.shift().apply( context, args ); + } + } + finally { + fired = [ context, args ]; + firing = 0; + } + } + return this; + }, + + // resolve with this as context and given arguments + resolve: function() { + deferred.resolveWith( this, arguments ); + return this; + }, + + // Has this deferred been resolved? + isResolved: function() { + return !!( firing || fired ); + }, + + // Cancel + cancel: function() { + cancelled = 1; + callbacks = []; + return this; + } + }; + + return deferred; + }, + + // Full fledged deferred (two callbacks list) + Deferred: function( func ) { + var deferred = jQuery._Deferred(), + failDeferred = jQuery._Deferred(), + promise; + // Add errorDeferred methods, then and promise + jQuery.extend( deferred, { + then: function( doneCallbacks, failCallbacks ) { + deferred.done( doneCallbacks ).fail( failCallbacks ); + return this; + }, + always: function() { + return deferred.done.apply( deferred, arguments ).fail.apply( this, arguments ); + }, + fail: failDeferred.done, + rejectWith: failDeferred.resolveWith, + reject: failDeferred.resolve, + isRejected: failDeferred.isResolved, + pipe: function( fnDone, fnFail ) { + return jQuery.Deferred(function( newDefer ) { + jQuery.each( { + done: [ fnDone, "resolve" ], + fail: [ fnFail, "reject" ] + }, function( handler, data ) { + var fn = data[ 0 ], + action = data[ 1 ], + returned; + if ( jQuery.isFunction( fn ) ) { + deferred[ handler ](function() { + returned = fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise().then( newDefer.resolve, newDefer.reject ); + } else { + newDefer[ action ]( returned ); + } + }); + } else { + deferred[ handler ]( newDefer[ action ] ); + } + }); + }).promise(); + }, + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + if ( obj == null ) { + if ( promise ) { + return promise; + } + promise = obj = {}; + } + var i = promiseMethods.length; + while( i-- ) { + obj[ promiseMethods[i] ] = deferred[ promiseMethods[i] ]; + } + return obj; + } + }); + // Make sure only one callback list will be used + deferred.done( failDeferred.cancel ).fail( deferred.cancel ); + // Unexpose cancel + delete deferred.cancel; + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + return deferred; + }, + + // Deferred helper + when: function( firstParam ) { + var args = arguments, + i = 0, + length = args.length, + count = length, + deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ? + firstParam : + jQuery.Deferred(); + function resolveFunc( i ) { + return function( value ) { + args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; + if ( !( --count ) ) { + // Strange bug in FF4: + // Values changed onto the arguments object sometimes end up as undefined values + // outside the $.when method. Cloning the object into a fresh array solves the issue + deferred.resolveWith( deferred, sliceDeferred.call( args, 0 ) ); + } + }; + } + if ( length > 1 ) { + for( ; i < length; i++ ) { + if ( args[ i ] && jQuery.isFunction( args[ i ].promise ) ) { + args[ i ].promise().then( resolveFunc(i), deferred.reject ); + } else { + --count; + } + } + if ( !count ) { + deferred.resolveWith( deferred, args ); + } + } else if ( deferred !== firstParam ) { + deferred.resolveWith( deferred, length ? [ firstParam ] : [] ); + } + return deferred.promise(); + } +}); + + + +jQuery.support = (function() { + + var div = document.createElement( "div" ), + documentElement = document.documentElement, + all, + a, + select, + opt, + input, + marginDiv, + support, + fragment, + body, + testElementParent, + testElement, + testElementStyle, + tds, + events, + eventName, + i, + isSupported; + + // Preliminary tests + div.setAttribute("className", "t"); + div.innerHTML = "
    a"; + + all = div.getElementsByTagName( "*" ); + a = div.getElementsByTagName( "a" )[ 0 ]; + + // Can't get basic test support + if ( !all || !all.length || !a ) { + return {}; + } + + // First batch of supports tests + select = document.createElement( "select" ); + opt = select.appendChild( document.createElement("option") ); + input = div.getElementsByTagName( "input" )[ 0 ]; + + support = { + // IE strips leading whitespace when .innerHTML is used + leadingWhitespace: ( div.firstChild.nodeType === 3 ), + + // Make sure that tbody elements aren't automatically inserted + // IE will insert them into empty tables + tbody: !div.getElementsByTagName( "tbody" ).length, + + // Make sure that link elements get serialized correctly by innerHTML + // This requires a wrapper element in IE + htmlSerialize: !!div.getElementsByTagName( "link" ).length, + + // Get the style information from getAttribute + // (IE uses .cssText instead) + style: /top/.test( a.getAttribute("style") ), + + // Make sure that URLs aren't manipulated + // (IE normalizes it by default) + hrefNormalized: ( a.getAttribute( "href" ) === "/a" ), + + // Make sure that element opacity exists + // (IE uses filter instead) + // Use a regex to work around a WebKit issue. See #5145 + opacity: /^0.55$/.test( a.style.opacity ), + + // Verify style float existence + // (IE uses styleFloat instead of cssFloat) + cssFloat: !!a.style.cssFloat, + + // Make sure that if no value is specified for a checkbox + // that it defaults to "on". + // (WebKit defaults to "" instead) + checkOn: ( input.value === "on" ), + + // Make sure that a selected-by-default option has a working selected property. + // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) + optSelected: opt.selected, + + // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) + getSetAttribute: div.className !== "t", + + // Will be defined later + submitBubbles: true, + changeBubbles: true, + focusinBubbles: false, + deleteExpando: true, + noCloneEvent: true, + inlineBlockNeedsLayout: false, + shrinkWrapBlocks: false, + reliableMarginRight: true + }; + + // Make sure checked status is properly cloned + input.checked = true; + support.noCloneChecked = input.cloneNode( true ).checked; + + // Make sure that the options inside disabled selects aren't marked as disabled + // (WebKit marks them as disabled) + select.disabled = true; + support.optDisabled = !opt.disabled; + + // Test to see if it's possible to delete an expando from an element + // Fails in Internet Explorer + try { + delete div.test; + } catch( e ) { + support.deleteExpando = false; + } + + if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { + div.attachEvent( "onclick", function() { + // Cloning a node shouldn't copy over any + // bound event handlers (IE does this) + support.noCloneEvent = false; + }); + div.cloneNode( true ).fireEvent( "onclick" ); + } + + // Check if a radio maintains it's value + // after being appended to the DOM + input = document.createElement("input"); + input.value = "t"; + input.setAttribute("type", "radio"); + support.radioValue = input.value === "t"; + + input.setAttribute("checked", "checked"); + div.appendChild( input ); + fragment = document.createDocumentFragment(); + fragment.appendChild( div.firstChild ); + + // WebKit doesn't clone checked state correctly in fragments + support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; + + div.innerHTML = ""; + + // Figure out if the W3C box model works as expected + div.style.width = div.style.paddingLeft = "1px"; + + body = document.getElementsByTagName( "body" )[ 0 ]; + // We use our own, invisible, body unless the body is already present + // in which case we use a div (#9239) + testElement = document.createElement( body ? "div" : "body" ); + testElementStyle = { + visibility: "hidden", + width: 0, + height: 0, + border: 0, + margin: 0 + }; + if ( body ) { + jQuery.extend( testElementStyle, { + position: "absolute", + left: -1000, + top: -1000 + }); + } + for ( i in testElementStyle ) { + testElement.style[ i ] = testElementStyle[ i ]; + } + testElement.appendChild( div ); + testElementParent = body || documentElement; + testElementParent.insertBefore( testElement, testElementParent.firstChild ); + + // Check if a disconnected checkbox will retain its checked + // value of true after appended to the DOM (IE6/7) + support.appendChecked = input.checked; + + support.boxModel = div.offsetWidth === 2; + + if ( "zoom" in div.style ) { + // Check if natively block-level elements act like inline-block + // elements when setting their display to 'inline' and giving + // them layout + // (IE < 8 does this) + div.style.display = "inline"; + div.style.zoom = 1; + support.inlineBlockNeedsLayout = ( div.offsetWidth === 2 ); + + // Check if elements with layout shrink-wrap their children + // (IE 6 does this) + div.style.display = ""; + div.innerHTML = "
    "; + support.shrinkWrapBlocks = ( div.offsetWidth !== 2 ); + } + + div.innerHTML = "
    t
    "; + tds = div.getElementsByTagName( "td" ); + + // Check if table cells still have offsetWidth/Height when they are set + // to display:none and there are still other visible table cells in a + // table row; if so, offsetWidth/Height are not reliable for use when + // determining if an element has been hidden directly using + // display:none (it is still safe to use offsets if a parent element is + // hidden; don safety goggles and see bug #4512 for more information). + // (only IE 8 fails this test) + isSupported = ( tds[ 0 ].offsetHeight === 0 ); + + tds[ 0 ].style.display = ""; + tds[ 1 ].style.display = "none"; + + // Check if empty table cells still have offsetWidth/Height + // (IE < 8 fail this test) + support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); + div.innerHTML = ""; + + // Check if div with explicit width and no margin-right incorrectly + // gets computed margin-right based on width of container. For more + // info see bug #3333 + // Fails in WebKit before Feb 2011 nightlies + // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right + if ( document.defaultView && document.defaultView.getComputedStyle ) { + marginDiv = document.createElement( "div" ); + marginDiv.style.width = "0"; + marginDiv.style.marginRight = "0"; + div.appendChild( marginDiv ); + support.reliableMarginRight = + ( parseInt( ( document.defaultView.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0; + } + + // Remove the body element we added + testElement.innerHTML = ""; + testElementParent.removeChild( testElement ); + + // Technique from Juriy Zaytsev + // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/ + // We only care about the case where non-standard event systems + // are used, namely in IE. Short-circuiting here helps us to + // avoid an eval call (in setAttribute) which can cause CSP + // to go haywire. See: https://developer.mozilla.org/en/Security/CSP + if ( div.attachEvent ) { + for( i in { + submit: 1, + change: 1, + focusin: 1 + } ) { + eventName = "on" + i; + isSupported = ( eventName in div ); + if ( !isSupported ) { + div.setAttribute( eventName, "return;" ); + isSupported = ( typeof div[ eventName ] === "function" ); + } + support[ i + "Bubbles" ] = isSupported; + } + } + + // Null connected elements to avoid leaks in IE + testElement = fragment = select = opt = body = marginDiv = div = input = null; + + return support; +})(); + +// Keep track of boxModel +jQuery.boxModel = jQuery.support.boxModel; + + + + +var rbrace = /^(?:\{.*\}|\[.*\])$/, + rmultiDash = /([a-z])([A-Z])/g; + +jQuery.extend({ + cache: {}, + + // Please use with caution + uuid: 0, + + // Unique for each copy of jQuery on the page + // Non-digits removed to match rinlinejQuery + expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ), + + // The following elements throw uncatchable exceptions if you + // attempt to add expando properties to them. + noData: { + "embed": true, + // Ban all objects except for Flash (which handle expandos) + "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", + "applet": true + }, + + hasData: function( elem ) { + elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; + + return !!elem && !isEmptyDataObject( elem ); + }, + + data: function( elem, name, data, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var internalKey = jQuery.expando, getByName = typeof name === "string", thisCache, + + // We have to handle DOM nodes and JS objects differently because IE6-7 + // can't GC object references properly across the DOM-JS boundary + isNode = elem.nodeType, + + // Only DOM nodes need the global jQuery cache; JS object data is + // attached directly to the object so GC can occur automatically + cache = isNode ? jQuery.cache : elem, + + // Only defining an ID for JS objects if its cache already exists allows + // the code to shortcut on the same path as a DOM node with no cache + id = isNode ? elem[ jQuery.expando ] : elem[ jQuery.expando ] && jQuery.expando; + + // Avoid doing any more work than we need to when trying to get data on an + // object that has no data at all + if ( (!id || (pvt && id && !cache[ id ][ internalKey ])) && getByName && data === undefined ) { + return; + } + + if ( !id ) { + // Only DOM nodes need a new unique ID for each element since their data + // ends up in the global cache + if ( isNode ) { + elem[ jQuery.expando ] = id = ++jQuery.uuid; + } else { + id = jQuery.expando; + } + } + + if ( !cache[ id ] ) { + cache[ id ] = {}; + + // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery + // metadata on plain JS objects when the object is serialized using + // JSON.stringify + if ( !isNode ) { + cache[ id ].toJSON = jQuery.noop; + } + } + + // An object can be passed to jQuery.data instead of a key/value pair; this gets + // shallow copied over onto the existing cache + if ( typeof name === "object" || typeof name === "function" ) { + if ( pvt ) { + cache[ id ][ internalKey ] = jQuery.extend(cache[ id ][ internalKey ], name); + } else { + cache[ id ] = jQuery.extend(cache[ id ], name); + } + } + + thisCache = cache[ id ]; + + // Internal jQuery data is stored in a separate object inside the object's data + // cache in order to avoid key collisions between internal data and user-defined + // data + if ( pvt ) { + if ( !thisCache[ internalKey ] ) { + thisCache[ internalKey ] = {}; + } + + thisCache = thisCache[ internalKey ]; + } + + if ( data !== undefined ) { + thisCache[ jQuery.camelCase( name ) ] = data; + } + + // TODO: This is a hack for 1.5 ONLY. It will be removed in 1.6. Users should + // not attempt to inspect the internal events object using jQuery.data, as this + // internal data object is undocumented and subject to change. + if ( name === "events" && !thisCache[name] ) { + return thisCache[ internalKey ] && thisCache[ internalKey ].events; + } + + return getByName ? + // Check for both converted-to-camel and non-converted data property names + thisCache[ jQuery.camelCase( name ) ] || thisCache[ name ] : + thisCache; + }, + + removeData: function( elem, name, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var internalKey = jQuery.expando, isNode = elem.nodeType, + + // See jQuery.data for more information + cache = isNode ? jQuery.cache : elem, + + // See jQuery.data for more information + id = isNode ? elem[ jQuery.expando ] : jQuery.expando; + + // If there is already no cache entry for this object, there is no + // purpose in continuing + if ( !cache[ id ] ) { + return; + } + + if ( name ) { + var thisCache = pvt ? cache[ id ][ internalKey ] : cache[ id ]; + + if ( thisCache ) { + delete thisCache[ name ]; + + // If there is no data left in the cache, we want to continue + // and let the cache object itself get destroyed + if ( !isEmptyDataObject(thisCache) ) { + return; + } + } + } + + // See jQuery.data for more information + if ( pvt ) { + delete cache[ id ][ internalKey ]; + + // Don't destroy the parent cache unless the internal data object + // had been the only thing left in it + if ( !isEmptyDataObject(cache[ id ]) ) { + return; + } + } + + var internalCache = cache[ id ][ internalKey ]; + + // Browsers that fail expando deletion also refuse to delete expandos on + // the window, but it will allow it on all other JS objects; other browsers + // don't care + if ( jQuery.support.deleteExpando || cache != window ) { + delete cache[ id ]; + } else { + cache[ id ] = null; + } + + // We destroyed the entire user cache at once because it's faster than + // iterating through each key, but we need to continue to persist internal + // data if it existed + if ( internalCache ) { + cache[ id ] = {}; + // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery + // metadata on plain JS objects when the object is serialized using + // JSON.stringify + if ( !isNode ) { + cache[ id ].toJSON = jQuery.noop; + } + + cache[ id ][ internalKey ] = internalCache; + + // Otherwise, we need to eliminate the expando on the node to avoid + // false lookups in the cache for entries that no longer exist + } else if ( isNode ) { + // IE does not allow us to delete expando properties from nodes, + // nor does it have a removeAttribute function on Document nodes; + // we must handle all of these cases + if ( jQuery.support.deleteExpando ) { + delete elem[ jQuery.expando ]; + } else if ( elem.removeAttribute ) { + elem.removeAttribute( jQuery.expando ); + } else { + elem[ jQuery.expando ] = null; + } + } + }, + + // For internal use only. + _data: function( elem, name, data ) { + return jQuery.data( elem, name, data, true ); + }, + + // A method for determining if a DOM node can handle the data expando + acceptData: function( elem ) { + if ( elem.nodeName ) { + var match = jQuery.noData[ elem.nodeName.toLowerCase() ]; + + if ( match ) { + return !(match === true || elem.getAttribute("classid") !== match); + } + } + + return true; + } +}); + +jQuery.fn.extend({ + data: function( key, value ) { + var data = null; + + if ( typeof key === "undefined" ) { + if ( this.length ) { + data = jQuery.data( this[0] ); + + if ( this[0].nodeType === 1 ) { + var attr = this[0].attributes, name; + for ( var i = 0, l = attr.length; i < l; i++ ) { + name = attr[i].name; + + if ( name.indexOf( "data-" ) === 0 ) { + name = jQuery.camelCase( name.substring(5) ); + + dataAttr( this[0], name, data[ name ] ); + } + } + } + } + + return data; + + } else if ( typeof key === "object" ) { + return this.each(function() { + jQuery.data( this, key ); + }); + } + + var parts = key.split("."); + parts[1] = parts[1] ? "." + parts[1] : ""; + + if ( value === undefined ) { + data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]); + + // Try to fetch any internally stored data first + if ( data === undefined && this.length ) { + data = jQuery.data( this[0], key ); + data = dataAttr( this[0], key, data ); + } + + return data === undefined && parts[1] ? + this.data( parts[0] ) : + data; + + } else { + return this.each(function() { + var $this = jQuery( this ), + args = [ parts[0], value ]; + + $this.triggerHandler( "setData" + parts[1] + "!", args ); + jQuery.data( this, key, value ); + $this.triggerHandler( "changeData" + parts[1] + "!", args ); + }); + } + }, + + removeData: function( key ) { + return this.each(function() { + jQuery.removeData( this, key ); + }); + } +}); + +function dataAttr( elem, key, data ) { + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + var name = "data-" + key.replace( rmultiDash, "$1-$2" ).toLowerCase(); + + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = data === "true" ? true : + data === "false" ? false : + data === "null" ? null : + !jQuery.isNaN( data ) ? parseFloat( data ) : + rbrace.test( data ) ? jQuery.parseJSON( data ) : + data; + } catch( e ) {} + + // Make sure we set the data so it isn't changed later + jQuery.data( elem, key, data ); + + } else { + data = undefined; + } + } + + return data; +} + +// TODO: This is a hack for 1.5 ONLY to allow objects with a single toJSON +// property to be considered empty objects; this property always exists in +// order to make sure JSON.stringify does not expose internal metadata +function isEmptyDataObject( obj ) { + for ( var name in obj ) { + if ( name !== "toJSON" ) { + return false; + } + } + + return true; +} + + + + +function handleQueueMarkDefer( elem, type, src ) { + var deferDataKey = type + "defer", + queueDataKey = type + "queue", + markDataKey = type + "mark", + defer = jQuery.data( elem, deferDataKey, undefined, true ); + if ( defer && + ( src === "queue" || !jQuery.data( elem, queueDataKey, undefined, true ) ) && + ( src === "mark" || !jQuery.data( elem, markDataKey, undefined, true ) ) ) { + // Give room for hard-coded callbacks to fire first + // and eventually mark/queue something else on the element + setTimeout( function() { + if ( !jQuery.data( elem, queueDataKey, undefined, true ) && + !jQuery.data( elem, markDataKey, undefined, true ) ) { + jQuery.removeData( elem, deferDataKey, true ); + defer.resolve(); + } + }, 0 ); + } +} + +jQuery.extend({ + + _mark: function( elem, type ) { + if ( elem ) { + type = (type || "fx") + "mark"; + jQuery.data( elem, type, (jQuery.data(elem,type,undefined,true) || 0) + 1, true ); + } + }, + + _unmark: function( force, elem, type ) { + if ( force !== true ) { + type = elem; + elem = force; + force = false; + } + if ( elem ) { + type = type || "fx"; + var key = type + "mark", + count = force ? 0 : ( (jQuery.data( elem, key, undefined, true) || 1 ) - 1 ); + if ( count ) { + jQuery.data( elem, key, count, true ); + } else { + jQuery.removeData( elem, key, true ); + handleQueueMarkDefer( elem, type, "mark" ); + } + } + }, + + queue: function( elem, type, data ) { + if ( elem ) { + type = (type || "fx") + "queue"; + var q = jQuery.data( elem, type, undefined, true ); + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !q || jQuery.isArray(data) ) { + q = jQuery.data( elem, type, jQuery.makeArray(data), true ); + } else { + q.push( data ); + } + } + return q || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + fn = queue.shift(), + defer; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + } + + if ( fn ) { + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift("inprogress"); + } + + fn.call(elem, function() { + jQuery.dequeue(elem, type); + }); + } + + if ( !queue.length ) { + jQuery.removeData( elem, type + "queue", true ); + handleQueueMarkDefer( elem, type, "queue" ); + } + } +}); + +jQuery.fn.extend({ + queue: function( type, data ) { + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + } + + if ( data === undefined ) { + return jQuery.queue( this[0], type ); + } + return this.each(function() { + var queue = jQuery.queue( this, type, data ); + + if ( type === "fx" && queue[0] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + }); + }, + dequeue: function( type ) { + return this.each(function() { + jQuery.dequeue( this, type ); + }); + }, + // Based off of the plugin by Clint Helfers, with permission. + // http://blindsignals.com/index.php/2009/07/jquery-delay/ + delay: function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[time] || time : time; + type = type || "fx"; + + return this.queue( type, function() { + var elem = this; + setTimeout(function() { + jQuery.dequeue( elem, type ); + }, time ); + }); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, object ) { + if ( typeof type !== "string" ) { + object = type; + type = undefined; + } + type = type || "fx"; + var defer = jQuery.Deferred(), + elements = this, + i = elements.length, + count = 1, + deferDataKey = type + "defer", + queueDataKey = type + "queue", + markDataKey = type + "mark", + tmp; + function resolve() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + } + while( i-- ) { + if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) || + ( jQuery.data( elements[ i ], queueDataKey, undefined, true ) || + jQuery.data( elements[ i ], markDataKey, undefined, true ) ) && + jQuery.data( elements[ i ], deferDataKey, jQuery._Deferred(), true ) )) { + count++; + tmp.done( resolve ); + } + } + resolve(); + return defer.promise(); + } +}); + + + + +var rclass = /[\n\t\r]/g, + rspace = /\s+/, + rreturn = /\r/g, + rtype = /^(?:button|input)$/i, + rfocusable = /^(?:button|input|object|select|textarea)$/i, + rclickable = /^a(?:rea)?$/i, + rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, + rinvalidChar = /\:|^on/, + formHook, boolHook; + +jQuery.fn.extend({ + attr: function( name, value ) { + return jQuery.access( this, name, value, true, jQuery.attr ); + }, + + removeAttr: function( name ) { + return this.each(function() { + jQuery.removeAttr( this, name ); + }); + }, + + prop: function( name, value ) { + return jQuery.access( this, name, value, true, jQuery.prop ); + }, + + removeProp: function( name ) { + name = jQuery.propFix[ name ] || name; + return this.each(function() { + // try/catch handles cases where IE balks (such as removing a property on window) + try { + this[ name ] = undefined; + delete this[ name ]; + } catch( e ) {} + }); + }, + + addClass: function( value ) { + var classNames, i, l, elem, + setClass, c, cl; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).addClass( value.call(this, j, this.className) ); + }); + } + + if ( value && typeof value === "string" ) { + classNames = value.split( rspace ); + + for ( i = 0, l = this.length; i < l; i++ ) { + elem = this[ i ]; + + if ( elem.nodeType === 1 ) { + if ( !elem.className && classNames.length === 1 ) { + elem.className = value; + + } else { + setClass = " " + elem.className + " "; + + for ( c = 0, cl = classNames.length; c < cl; c++ ) { + if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) { + setClass += classNames[ c ] + " "; + } + } + elem.className = jQuery.trim( setClass ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classNames, i, l, elem, className, c, cl; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).removeClass( value.call(this, j, this.className) ); + }); + } + + if ( (value && typeof value === "string") || value === undefined ) { + classNames = (value || "").split( rspace ); + + for ( i = 0, l = this.length; i < l; i++ ) { + elem = this[ i ]; + + if ( elem.nodeType === 1 && elem.className ) { + if ( value ) { + className = (" " + elem.className + " ").replace( rclass, " " ); + for ( c = 0, cl = classNames.length; c < cl; c++ ) { + className = className.replace(" " + classNames[ c ] + " ", " "); + } + elem.className = jQuery.trim( className ); + + } else { + elem.className = ""; + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isBool = typeof stateVal === "boolean"; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( i ) { + jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); + }); + } + + return this.each(function() { + if ( type === "string" ) { + // toggle individual class names + var className, + i = 0, + self = jQuery( this ), + state = stateVal, + classNames = value.split( rspace ); + + while ( (className = classNames[ i++ ]) ) { + // check each className given, space seperated list + state = isBool ? state : !self.hasClass( className ); + self[ state ? "addClass" : "removeClass" ]( className ); + } + + } else if ( type === "undefined" || type === "boolean" ) { + if ( this.className ) { + // store className if set + jQuery._data( this, "__className__", this.className ); + } + + // toggle whole className + this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; + } + }); + }, + + hasClass: function( selector ) { + var className = " " + selector + " "; + for ( var i = 0, l = this.length; i < l; i++ ) { + if ( (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { + return true; + } + } + + return false; + }, + + val: function( value ) { + var hooks, ret, + elem = this[0]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.nodeName.toLowerCase() ] || jQuery.valHooks[ elem.type ]; + + if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { + return ret; + } + + ret = elem.value; + + return typeof ret === "string" ? + // handle most common string cases + ret.replace(rreturn, "") : + // handle cases where value is null/undef or number + ret == null ? "" : ret; + } + + return undefined; + } + + var isFunction = jQuery.isFunction( value ); + + return this.each(function( i ) { + var self = jQuery(this), val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call( this, i, self.val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + } else if ( typeof val === "number" ) { + val += ""; + } else if ( jQuery.isArray( val ) ) { + val = jQuery.map(val, function ( value ) { + return value == null ? "" : value + ""; + }); + } + + hooks = jQuery.valHooks[ this.nodeName.toLowerCase() ] || jQuery.valHooks[ this.type ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + }); + } +}); + +jQuery.extend({ + valHooks: { + option: { + get: function( elem ) { + // attributes.value is undefined in Blackberry 4.7 but + // uses .value. See #6932 + var val = elem.attributes.value; + return !val || val.specified ? elem.value : elem.text; + } + }, + select: { + get: function( elem ) { + var value, + index = elem.selectedIndex, + values = [], + options = elem.options, + one = elem.type === "select-one"; + + // Nothing was selected + if ( index < 0 ) { + return null; + } + + // Loop through all the selected options + for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) { + var option = options[ i ]; + + // Don't return options that are disabled or in a disabled optgroup + if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && + (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + // Fixes Bug #2551 -- select.val() broken in IE after form.reset() + if ( one && !values.length && options.length ) { + return jQuery( options[ index ] ).val(); + } + + return values; + }, + + set: function( elem, value ) { + var values = jQuery.makeArray( value ); + + jQuery(elem).find("option").each(function() { + this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; + }); + + if ( !values.length ) { + elem.selectedIndex = -1; + } + return values; + } + } + }, + + attrFn: { + val: true, + css: true, + html: true, + text: true, + data: true, + width: true, + height: true, + offset: true + }, + + attrFix: { + // Always normalize to ensure hook usage + tabindex: "tabIndex" + }, + + attr: function( elem, name, value, pass ) { + var nType = elem.nodeType; + + // don't get/set attributes on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return undefined; + } + + if ( pass && name in jQuery.attrFn ) { + return jQuery( elem )[ name ]( value ); + } + + // Fallback to prop when attributes are not supported + if ( !("getAttribute" in elem) ) { + return jQuery.prop( elem, name, value ); + } + + var ret, hooks, + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + // Normalize the name if needed + if ( notxml ) { + name = jQuery.attrFix[ name ] || name; + + hooks = jQuery.attrHooks[ name ]; + + if ( !hooks ) { + // Use boolHook for boolean attributes + if ( rboolean.test( name ) ) { + + hooks = boolHook; + + // Use formHook for forms and if the name contains certain characters + } else if ( formHook && name !== "className" && + (jQuery.nodeName( elem, "form" ) || rinvalidChar.test( name )) ) { + + hooks = formHook; + } + } + } + + if ( value !== undefined ) { + + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return undefined; + + } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + elem.setAttribute( name, "" + value ); + return value; + } + + } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) { + return ret; + + } else { + + ret = elem.getAttribute( name ); + + // Non-existent attributes return null, we normalize to undefined + return ret === null ? + undefined : + ret; + } + }, + + removeAttr: function( elem, name ) { + var propName; + if ( elem.nodeType === 1 ) { + name = jQuery.attrFix[ name ] || name; + + if ( jQuery.support.getSetAttribute ) { + // Use removeAttribute in browsers that support it + elem.removeAttribute( name ); + } else { + jQuery.attr( elem, name, "" ); + elem.removeAttributeNode( elem.getAttributeNode( name ) ); + } + + // Set corresponding property to false for boolean attributes + if ( rboolean.test( name ) && (propName = jQuery.propFix[ name ] || name) in elem ) { + elem[ propName ] = false; + } + } + }, + + attrHooks: { + type: { + set: function( elem, value ) { + // We can't allow the type property to be changed (since it causes problems in IE) + if ( rtype.test( elem.nodeName ) && elem.parentNode ) { + jQuery.error( "type property can't be changed" ); + } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { + // Setting the type on a radio button after the value resets the value in IE6-9 + // Reset value to it's default in case type is set after value + // This is for element creation + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + }, + tabIndex: { + get: function( elem ) { + // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set + // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + var attributeNode = elem.getAttributeNode("tabIndex"); + + return attributeNode && attributeNode.specified ? + parseInt( attributeNode.value, 10 ) : + rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? + 0 : + undefined; + } + }, + // Use the value property for back compat + // Use the formHook for button elements in IE6/7 (#1954) + value: { + get: function( elem, name ) { + if ( formHook && jQuery.nodeName( elem, "button" ) ) { + return formHook.get( elem, name ); + } + return name in elem ? + elem.value : + null; + }, + set: function( elem, value, name ) { + if ( formHook && jQuery.nodeName( elem, "button" ) ) { + return formHook.set( elem, value, name ); + } + // Does not return so that setAttribute is also used + elem.value = value; + } + } + }, + + propFix: { + tabindex: "tabIndex", + readonly: "readOnly", + "for": "htmlFor", + "class": "className", + maxlength: "maxLength", + cellspacing: "cellSpacing", + cellpadding: "cellPadding", + rowspan: "rowSpan", + colspan: "colSpan", + usemap: "useMap", + frameborder: "frameBorder", + contenteditable: "contentEditable" + }, + + prop: function( elem, name, value ) { + var nType = elem.nodeType; + + // don't get/set properties on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return undefined; + } + + var ret, hooks, + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + if ( notxml ) { + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + return (elem[ name ] = value); + } + + } else { + if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== undefined ) { + return ret; + + } else { + return elem[ name ]; + } + } + }, + + propHooks: {} +}); + +// Hook for boolean attributes +boolHook = { + get: function( elem, name ) { + // Align boolean attributes with corresponding properties + return jQuery.prop( elem, name ) ? + name.toLowerCase() : + undefined; + }, + set: function( elem, value, name ) { + var propName; + if ( value === false ) { + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + // value is true since we know at this point it's type boolean and not false + // Set boolean attributes to the same name and set the DOM property + propName = jQuery.propFix[ name ] || name; + if ( propName in elem ) { + // Only set the IDL specifically if it already exists on the element + elem[ propName ] = true; + } + + elem.setAttribute( name, name.toLowerCase() ); + } + return name; + } +}; + +// IE6/7 do not support getting/setting some attributes with get/setAttribute +if ( !jQuery.support.getSetAttribute ) { + + // propFix is more comprehensive and contains all fixes + jQuery.attrFix = jQuery.propFix; + + // Use this for any attribute on a form in IE6/7 + formHook = jQuery.attrHooks.name = jQuery.attrHooks.title = jQuery.valHooks.button = { + get: function( elem, name ) { + var ret; + ret = elem.getAttributeNode( name ); + // Return undefined if nodeValue is empty string + return ret && ret.nodeValue !== "" ? + ret.nodeValue : + undefined; + }, + set: function( elem, value, name ) { + // Check form objects in IE (multiple bugs related) + // Only use nodeValue if the attribute node exists on the form + var ret = elem.getAttributeNode( name ); + if ( ret ) { + ret.nodeValue = value; + return value; + } + } + }; + + // Set width and height to auto instead of 0 on empty string( Bug #8150 ) + // This is for removals + jQuery.each([ "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + set: function( elem, value ) { + if ( value === "" ) { + elem.setAttribute( name, "auto" ); + return value; + } + } + }); + }); +} + + +// Some attributes require a special call on IE +if ( !jQuery.support.hrefNormalized ) { + jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + get: function( elem ) { + var ret = elem.getAttribute( name, 2 ); + return ret === null ? undefined : ret; + } + }); + }); +} + +if ( !jQuery.support.style ) { + jQuery.attrHooks.style = { + get: function( elem ) { + // Return undefined in the case of empty string + // Normalize to lowercase since IE uppercases css property names + return elem.style.cssText.toLowerCase() || undefined; + }, + set: function( elem, value ) { + return (elem.style.cssText = "" + value); + } + }; +} + +// Safari mis-reports the default selected property of an option +// Accessing the parent's selectedIndex property fixes it +if ( !jQuery.support.optSelected ) { + jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { + get: function( elem ) { + var parent = elem.parentNode; + + if ( parent ) { + parent.selectedIndex; + + // Make sure that it also works with optgroups, see #5701 + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + }); +} + +// Radios and checkboxes getter/setter +if ( !jQuery.support.checkOn ) { + jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + get: function( elem ) { + // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified + return elem.getAttribute("value") === null ? "on" : elem.value; + } + }; + }); +} +jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { + set: function( elem, value ) { + if ( jQuery.isArray( value ) ) { + return (elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0); + } + } + }); +}); + + + + +var rnamespaces = /\.(.*)$/, + rformElems = /^(?:textarea|input|select)$/i, + rperiod = /\./g, + rspaces = / /g, + rescape = /[^\w\s.|`]/g, + fcleanup = function( nm ) { + return nm.replace(rescape, "\\$&"); + }; + +/* + * A number of helper functions used for managing events. + * Many of the ideas behind this code originated from + * Dean Edwards' addEvent library. + */ +jQuery.event = { + + // Bind an event to an element + // Original by Dean Edwards + add: function( elem, types, handler, data ) { + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + if ( handler === false ) { + handler = returnFalse; + } else if ( !handler ) { + // Fixes bug #7229. Fix recommended by jdalton + return; + } + + var handleObjIn, handleObj; + + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + } + + // Make sure that the function being executed has a unique ID + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure + var elemData = jQuery._data( elem ); + + // If no elemData is found then we must be trying to bind to one of the + // banned noData elements + if ( !elemData ) { + return; + } + + var events = elemData.events, + eventHandle = elemData.handle; + + if ( !events ) { + elemData.events = events = {}; + } + + if ( !eventHandle ) { + elemData.handle = eventHandle = function( e ) { + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ? + jQuery.event.handle.apply( eventHandle.elem, arguments ) : + undefined; + }; + } + + // Add elem as a property of the handle function + // This is to prevent a memory leak with non-native events in IE. + eventHandle.elem = elem; + + // Handle multiple events separated by a space + // jQuery(...).bind("mouseover mouseout", fn); + types = types.split(" "); + + var type, i = 0, namespaces; + + while ( (type = types[ i++ ]) ) { + handleObj = handleObjIn ? + jQuery.extend({}, handleObjIn) : + { handler: handler, data: data }; + + // Namespaced event handlers + if ( type.indexOf(".") > -1 ) { + namespaces = type.split("."); + type = namespaces.shift(); + handleObj.namespace = namespaces.slice(0).sort().join("."); + + } else { + namespaces = []; + handleObj.namespace = ""; + } + + handleObj.type = type; + if ( !handleObj.guid ) { + handleObj.guid = handler.guid; + } + + // Get the current list of functions bound to this event + var handlers = events[ type ], + special = jQuery.event.special[ type ] || {}; + + // Init the event handler queue + if ( !handlers ) { + handlers = events[ type ] = []; + + // Check for a special event handler + // Only use addEventListener/attachEvent if the special + // events handler returns false + if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + // Bind the global event handler to the element + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle, false ); + + } else if ( elem.attachEvent ) { + elem.attachEvent( "on" + type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add the function to the element's handler list + handlers.push( handleObj ); + + // Keep track of which events have been used, for event optimization + jQuery.event.global[ type ] = true; + } + + // Nullify elem to prevent memory leaks in IE + elem = null; + }, + + global: {}, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, pos ) { + // don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + if ( handler === false ) { + handler = returnFalse; + } + + var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType, + elemData = jQuery.hasData( elem ) && jQuery._data( elem ), + events = elemData && elemData.events; + + if ( !elemData || !events ) { + return; + } + + // types is actually an event object here + if ( types && types.type ) { + handler = types.handler; + types = types.type; + } + + // Unbind all events for the element + if ( !types || typeof types === "string" && types.charAt(0) === "." ) { + types = types || ""; + + for ( type in events ) { + jQuery.event.remove( elem, type + types ); + } + + return; + } + + // Handle multiple events separated by a space + // jQuery(...).unbind("mouseover mouseout", fn); + types = types.split(" "); + + while ( (type = types[ i++ ]) ) { + origType = type; + handleObj = null; + all = type.indexOf(".") < 0; + namespaces = []; + + if ( !all ) { + // Namespaced event handlers + namespaces = type.split("."); + type = namespaces.shift(); + + namespace = new RegExp("(^|\\.)" + + jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)"); + } + + eventType = events[ type ]; + + if ( !eventType ) { + continue; + } + + if ( !handler ) { + for ( j = 0; j < eventType.length; j++ ) { + handleObj = eventType[ j ]; + + if ( all || namespace.test( handleObj.namespace ) ) { + jQuery.event.remove( elem, origType, handleObj.handler, j ); + eventType.splice( j--, 1 ); + } + } + + continue; + } + + special = jQuery.event.special[ type ] || {}; + + for ( j = pos || 0; j < eventType.length; j++ ) { + handleObj = eventType[ j ]; + + if ( handler.guid === handleObj.guid ) { + // remove the given handler for the given type + if ( all || namespace.test( handleObj.namespace ) ) { + if ( pos == null ) { + eventType.splice( j--, 1 ); + } + + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + + if ( pos != null ) { + break; + } + } + } + + // remove generic event handler if no more handlers exist + if ( eventType.length === 0 || pos != null && eventType.length === 1 ) { + if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) { + jQuery.removeEvent( elem, type, elemData.handle ); + } + + ret = null; + delete events[ type ]; + } + } + + // Remove the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + var handle = elemData.handle; + if ( handle ) { + handle.elem = null; + } + + delete elemData.events; + delete elemData.handle; + + if ( jQuery.isEmptyObject( elemData ) ) { + jQuery.removeData( elem, undefined, true ); + } + } + }, + + // Events that are safe to short-circuit if no handlers are attached. + // Native DOM events should not be added, they may have inline handlers. + customEvent: { + "getData": true, + "setData": true, + "changeData": true + }, + + trigger: function( event, data, elem, onlyHandlers ) { + // Event object or event type + var type = event.type || event, + namespaces = [], + exclusive; + + if ( type.indexOf("!") >= 0 ) { + // Exclusive events trigger only for the exact event (no namespaces) + type = type.slice(0, -1); + exclusive = true; + } + + if ( type.indexOf(".") >= 0 ) { + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split("."); + type = namespaces.shift(); + namespaces.sort(); + } + + if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) { + // No jQuery handlers for this event type, and it can't have inline handlers + return; + } + + // Caller can pass in an Event, Object, or just an event type string + event = typeof event === "object" ? + // jQuery.Event object + event[ jQuery.expando ] ? event : + // Object literal + new jQuery.Event( type, event ) : + // Just the event type (string) + new jQuery.Event( type ); + + event.type = type; + event.exclusive = exclusive; + event.namespace = namespaces.join("."); + event.namespace_re = new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)"); + + // triggerHandler() and global events don't bubble or run the default action + if ( onlyHandlers || !elem ) { + event.preventDefault(); + event.stopPropagation(); + } + + // Handle a global trigger + if ( !elem ) { + // TODO: Stop taunting the data cache; remove global events and always attach to document + jQuery.each( jQuery.cache, function() { + // internalKey variable is just used to make it easier to find + // and potentially change this stuff later; currently it just + // points to jQuery.expando + var internalKey = jQuery.expando, + internalCache = this[ internalKey ]; + if ( internalCache && internalCache.events && internalCache.events[ type ] ) { + jQuery.event.trigger( event, data, internalCache.handle.elem ); + } + }); + return; + } + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // Clean up the event in case it is being reused + event.result = undefined; + event.target = elem; + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data != null ? jQuery.makeArray( data ) : []; + data.unshift( event ); + + var cur = elem, + // IE doesn't like method names with a colon (#3533, #8272) + ontype = type.indexOf(":") < 0 ? "on" + type : ""; + + // Fire event on the current element, then bubble up the DOM tree + do { + var handle = jQuery._data( cur, "handle" ); + + event.currentTarget = cur; + if ( handle ) { + handle.apply( cur, data ); + } + + // Trigger an inline bound script + if ( ontype && jQuery.acceptData( cur ) && cur[ ontype ] && cur[ ontype ].apply( cur, data ) === false ) { + event.result = false; + event.preventDefault(); + } + + // Bubble up to document, then to window + cur = cur.parentNode || cur.ownerDocument || cur === event.target.ownerDocument && window; + } while ( cur && !event.isPropagationStopped() ); + + // If nobody prevented the default action, do it now + if ( !event.isDefaultPrevented() ) { + var old, + special = jQuery.event.special[ type ] || {}; + + if ( (!special._default || special._default.call( elem.ownerDocument, event ) === false) && + !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name name as the event. + // Can't use an .isFunction)() check here because IE6/7 fails that test. + // IE<9 dies on focus to hidden element (#1486), may want to revisit a try/catch. + try { + if ( ontype && elem[ type ] ) { + // Don't re-trigger an onFOO event when we call its FOO() method + old = elem[ ontype ]; + + if ( old ) { + elem[ ontype ] = null; + } + + jQuery.event.triggered = type; + elem[ type ](); + } + } catch ( ieError ) {} + + if ( old ) { + elem[ ontype ] = old; + } + + jQuery.event.triggered = undefined; + } + } + + return event.result; + }, + + handle: function( event ) { + event = jQuery.event.fix( event || window.event ); + // Snapshot the handlers list since a called handler may add/remove events. + var handlers = ((jQuery._data( this, "events" ) || {})[ event.type ] || []).slice(0), + run_all = !event.exclusive && !event.namespace, + args = Array.prototype.slice.call( arguments, 0 ); + + // Use the fix-ed Event rather than the (read-only) native event + args[0] = event; + event.currentTarget = this; + + for ( var j = 0, l = handlers.length; j < l; j++ ) { + var handleObj = handlers[ j ]; + + // Triggered event must 1) be non-exclusive and have no namespace, or + // 2) have namespace(s) a subset or equal to those in the bound event. + if ( run_all || event.namespace_re.test( handleObj.namespace ) ) { + // Pass in a reference to the handler function itself + // So that we can later remove it + event.handler = handleObj.handler; + event.data = handleObj.data; + event.handleObj = handleObj; + + var ret = handleObj.handler.apply( this, args ); + + if ( ret !== undefined ) { + event.result = ret; + if ( ret === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + + if ( event.isImmediatePropagationStopped() ) { + break; + } + } + } + return event.result; + }, + + props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "), + + fix: function( event ) { + if ( event[ jQuery.expando ] ) { + return event; + } + + // store a copy of the original event object + // and "clone" to set read-only properties + var originalEvent = event; + event = jQuery.Event( originalEvent ); + + for ( var i = this.props.length, prop; i; ) { + prop = this.props[ --i ]; + event[ prop ] = originalEvent[ prop ]; + } + + // Fix target property, if necessary + if ( !event.target ) { + // Fixes #1925 where srcElement might not be defined either + event.target = event.srcElement || document; + } + + // check if target is a textnode (safari) + if ( event.target.nodeType === 3 ) { + event.target = event.target.parentNode; + } + + // Add relatedTarget, if necessary + if ( !event.relatedTarget && event.fromElement ) { + event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement; + } + + // Calculate pageX/Y if missing and clientX/Y available + if ( event.pageX == null && event.clientX != null ) { + var eventDocument = event.target.ownerDocument || document, + doc = eventDocument.documentElement, + body = eventDocument.body; + + event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0); + event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0); + } + + // Add which for key events + if ( event.which == null && (event.charCode != null || event.keyCode != null) ) { + event.which = event.charCode != null ? event.charCode : event.keyCode; + } + + // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs) + if ( !event.metaKey && event.ctrlKey ) { + event.metaKey = event.ctrlKey; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + // Note: button is not normalized, so don't use it + if ( !event.which && event.button !== undefined ) { + event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) )); + } + + return event; + }, + + // Deprecated, use jQuery.guid instead + guid: 1E8, + + // Deprecated, use jQuery.proxy instead + proxy: jQuery.proxy, + + special: { + ready: { + // Make sure the ready event is setup + setup: jQuery.bindReady, + teardown: jQuery.noop + }, + + live: { + add: function( handleObj ) { + jQuery.event.add( this, + liveConvert( handleObj.origType, handleObj.selector ), + jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) ); + }, + + remove: function( handleObj ) { + jQuery.event.remove( this, liveConvert( handleObj.origType, handleObj.selector ), handleObj ); + } + }, + + beforeunload: { + setup: function( data, namespaces, eventHandle ) { + // We only want to do this special case on windows + if ( jQuery.isWindow( this ) ) { + this.onbeforeunload = eventHandle; + } + }, + + teardown: function( namespaces, eventHandle ) { + if ( this.onbeforeunload === eventHandle ) { + this.onbeforeunload = null; + } + } + } + } +}; + +jQuery.removeEvent = document.removeEventListener ? + function( elem, type, handle ) { + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle, false ); + } + } : + function( elem, type, handle ) { + if ( elem.detachEvent ) { + elem.detachEvent( "on" + type, handle ); + } + }; + +jQuery.Event = function( src, props ) { + // Allow instantiation without the 'new' keyword + if ( !this.preventDefault ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = (src.defaultPrevented || src.returnValue === false || + src.getPreventDefault && src.getPreventDefault()) ? returnTrue : returnFalse; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // timeStamp is buggy for some events on Firefox(#3843) + // So we won't rely on the native value + this.timeStamp = jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +function returnFalse() { + return false; +} +function returnTrue() { + return true; +} + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + preventDefault: function() { + this.isDefaultPrevented = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + + // if preventDefault exists run it on the original event + if ( e.preventDefault ) { + e.preventDefault(); + + // otherwise set the returnValue property of the original event to false (IE) + } else { + e.returnValue = false; + } + }, + stopPropagation: function() { + this.isPropagationStopped = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + // if stopPropagation exists run it on the original event + if ( e.stopPropagation ) { + e.stopPropagation(); + } + // otherwise set the cancelBubble property of the original event to true (IE) + e.cancelBubble = true; + }, + stopImmediatePropagation: function() { + this.isImmediatePropagationStopped = returnTrue; + this.stopPropagation(); + }, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse +}; + +// Checks if an event happened on an element within another element +// Used in jQuery.event.special.mouseenter and mouseleave handlers +var withinElement = function( event ) { + + // Check if mouse(over|out) are still within the same parent element + var related = event.relatedTarget, + inside = false, + eventType = event.type; + + event.type = event.data; + + if ( related !== this ) { + + if ( related ) { + inside = jQuery.contains( this, related ); + } + + if ( !inside ) { + + jQuery.event.handle.apply( this, arguments ); + + event.type = eventType; + } + } +}, + +// In case of event delegation, we only need to rename the event.type, +// liveHandler will take care of the rest. +delegate = function( event ) { + event.type = event.data; + jQuery.event.handle.apply( this, arguments ); +}; + +// Create mouseenter and mouseleave events +jQuery.each({ + mouseenter: "mouseover", + mouseleave: "mouseout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + setup: function( data ) { + jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig ); + }, + teardown: function( data ) { + jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement ); + } + }; +}); + +// submit delegation +if ( !jQuery.support.submitBubbles ) { + + jQuery.event.special.submit = { + setup: function( data, namespaces ) { + if ( !jQuery.nodeName( this, "form" ) ) { + jQuery.event.add(this, "click.specialSubmit", function( e ) { + var elem = e.target, + type = elem.type; + + if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) { + trigger( "submit", this, arguments ); + } + }); + + jQuery.event.add(this, "keypress.specialSubmit", function( e ) { + var elem = e.target, + type = elem.type; + + if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) { + trigger( "submit", this, arguments ); + } + }); + + } else { + return false; + } + }, + + teardown: function( namespaces ) { + jQuery.event.remove( this, ".specialSubmit" ); + } + }; + +} + +// change delegation, happens here so we have bind. +if ( !jQuery.support.changeBubbles ) { + + var changeFilters, + + getVal = function( elem ) { + var type = elem.type, val = elem.value; + + if ( type === "radio" || type === "checkbox" ) { + val = elem.checked; + + } else if ( type === "select-multiple" ) { + val = elem.selectedIndex > -1 ? + jQuery.map( elem.options, function( elem ) { + return elem.selected; + }).join("-") : + ""; + + } else if ( jQuery.nodeName( elem, "select" ) ) { + val = elem.selectedIndex; + } + + return val; + }, + + testChange = function testChange( e ) { + var elem = e.target, data, val; + + if ( !rformElems.test( elem.nodeName ) || elem.readOnly ) { + return; + } + + data = jQuery._data( elem, "_change_data" ); + val = getVal(elem); + + // the current data will be also retrieved by beforeactivate + if ( e.type !== "focusout" || elem.type !== "radio" ) { + jQuery._data( elem, "_change_data", val ); + } + + if ( data === undefined || val === data ) { + return; + } + + if ( data != null || val ) { + e.type = "change"; + e.liveFired = undefined; + jQuery.event.trigger( e, arguments[1], elem ); + } + }; + + jQuery.event.special.change = { + filters: { + focusout: testChange, + + beforedeactivate: testChange, + + click: function( e ) { + var elem = e.target, type = jQuery.nodeName( elem, "input" ) ? elem.type : ""; + + if ( type === "radio" || type === "checkbox" || jQuery.nodeName( elem, "select" ) ) { + testChange.call( this, e ); + } + }, + + // Change has to be called before submit + // Keydown will be called before keypress, which is used in submit-event delegation + keydown: function( e ) { + var elem = e.target, type = jQuery.nodeName( elem, "input" ) ? elem.type : ""; + + if ( (e.keyCode === 13 && !jQuery.nodeName( elem, "textarea" ) ) || + (e.keyCode === 32 && (type === "checkbox" || type === "radio")) || + type === "select-multiple" ) { + testChange.call( this, e ); + } + }, + + // Beforeactivate happens also before the previous element is blurred + // with this event you can't trigger a change event, but you can store + // information + beforeactivate: function( e ) { + var elem = e.target; + jQuery._data( elem, "_change_data", getVal(elem) ); + } + }, + + setup: function( data, namespaces ) { + if ( this.type === "file" ) { + return false; + } + + for ( var type in changeFilters ) { + jQuery.event.add( this, type + ".specialChange", changeFilters[type] ); + } + + return rformElems.test( this.nodeName ); + }, + + teardown: function( namespaces ) { + jQuery.event.remove( this, ".specialChange" ); + + return rformElems.test( this.nodeName ); + } + }; + + changeFilters = jQuery.event.special.change.filters; + + // Handle when the input is .focus()'d + changeFilters.focus = changeFilters.beforeactivate; +} + +function trigger( type, elem, args ) { + // Piggyback on a donor event to simulate a different one. + // Fake originalEvent to avoid donor's stopPropagation, but if the + // simulated event prevents default then we do the same on the donor. + // Don't pass args or remember liveFired; they apply to the donor event. + var event = jQuery.extend( {}, args[ 0 ] ); + event.type = type; + event.originalEvent = {}; + event.liveFired = undefined; + jQuery.event.handle.call( elem, event ); + if ( event.isDefaultPrevented() ) { + args[ 0 ].preventDefault(); + } +} + +// Create "bubbling" focus and blur events +if ( !jQuery.support.focusinBubbles ) { + jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler while someone wants focusin/focusout + var attaches = 0; + + jQuery.event.special[ fix ] = { + setup: function() { + if ( attaches++ === 0 ) { + document.addEventListener( orig, handler, true ); + } + }, + teardown: function() { + if ( --attaches === 0 ) { + document.removeEventListener( orig, handler, true ); + } + } + }; + + function handler( donor ) { + // Donor event is always a native one; fix it and switch its type. + // Let focusin/out handler cancel the donor focus/blur event. + var e = jQuery.event.fix( donor ); + e.type = fix; + e.originalEvent = {}; + jQuery.event.trigger( e, null, e.target ); + if ( e.isDefaultPrevented() ) { + donor.preventDefault(); + } + } + }); +} + +jQuery.each(["bind", "one"], function( i, name ) { + jQuery.fn[ name ] = function( type, data, fn ) { + var handler; + + // Handle object literals + if ( typeof type === "object" ) { + for ( var key in type ) { + this[ name ](key, data, type[key], fn); + } + return this; + } + + if ( arguments.length === 2 || data === false ) { + fn = data; + data = undefined; + } + + if ( name === "one" ) { + handler = function( event ) { + jQuery( this ).unbind( event, handler ); + return fn.apply( this, arguments ); + }; + handler.guid = fn.guid || jQuery.guid++; + } else { + handler = fn; + } + + if ( type === "unload" && name !== "one" ) { + this.one( type, data, fn ); + + } else { + for ( var i = 0, l = this.length; i < l; i++ ) { + jQuery.event.add( this[i], type, handler, data ); + } + } + + return this; + }; +}); + +jQuery.fn.extend({ + unbind: function( type, fn ) { + // Handle object literals + if ( typeof type === "object" && !type.preventDefault ) { + for ( var key in type ) { + this.unbind(key, type[key]); + } + + } else { + for ( var i = 0, l = this.length; i < l; i++ ) { + jQuery.event.remove( this[i], type, fn ); + } + } + + return this; + }, + + delegate: function( selector, types, data, fn ) { + return this.live( types, data, fn, selector ); + }, + + undelegate: function( selector, types, fn ) { + if ( arguments.length === 0 ) { + return this.unbind( "live" ); + + } else { + return this.die( types, null, fn, selector ); + } + }, + + trigger: function( type, data ) { + return this.each(function() { + jQuery.event.trigger( type, data, this ); + }); + }, + + triggerHandler: function( type, data ) { + if ( this[0] ) { + return jQuery.event.trigger( type, data, this[0], true ); + } + }, + + toggle: function( fn ) { + // Save reference to arguments for access in closure + var args = arguments, + guid = fn.guid || jQuery.guid++, + i = 0, + toggler = function( event ) { + // Figure out which function to execute + var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i; + jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 ); + + // Make sure that clicks stop + event.preventDefault(); + + // and execute the function + return args[ lastToggle ].apply( this, arguments ) || false; + }; + + // link all the functions, so any of them can unbind this click handler + toggler.guid = guid; + while ( i < args.length ) { + args[ i++ ].guid = guid; + } + + return this.click( toggler ); + }, + + hover: function( fnOver, fnOut ) { + return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); + } +}); + +var liveMap = { + focus: "focusin", + blur: "focusout", + mouseenter: "mouseover", + mouseleave: "mouseout" +}; + +jQuery.each(["live", "die"], function( i, name ) { + jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) { + var type, i = 0, match, namespaces, preType, + selector = origSelector || this.selector, + context = origSelector ? this : jQuery( this.context ); + + if ( typeof types === "object" && !types.preventDefault ) { + for ( var key in types ) { + context[ name ]( key, data, types[key], selector ); + } + + return this; + } + + if ( name === "die" && !types && + origSelector && origSelector.charAt(0) === "." ) { + + context.unbind( origSelector ); + + return this; + } + + if ( data === false || jQuery.isFunction( data ) ) { + fn = data || returnFalse; + data = undefined; + } + + types = (types || "").split(" "); + + while ( (type = types[ i++ ]) != null ) { + match = rnamespaces.exec( type ); + namespaces = ""; + + if ( match ) { + namespaces = match[0]; + type = type.replace( rnamespaces, "" ); + } + + if ( type === "hover" ) { + types.push( "mouseenter" + namespaces, "mouseleave" + namespaces ); + continue; + } + + preType = type; + + if ( liveMap[ type ] ) { + types.push( liveMap[ type ] + namespaces ); + type = type + namespaces; + + } else { + type = (liveMap[ type ] || type) + namespaces; + } + + if ( name === "live" ) { + // bind live handler + for ( var j = 0, l = context.length; j < l; j++ ) { + jQuery.event.add( context[j], "live." + liveConvert( type, selector ), + { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } ); + } + + } else { + // unbind live handler + context.unbind( "live." + liveConvert( type, selector ), fn ); + } + } + + return this; + }; +}); + +function liveHandler( event ) { + var stop, maxLevel, related, match, handleObj, elem, j, i, l, data, close, namespace, ret, + elems = [], + selectors = [], + events = jQuery._data( this, "events" ); + + // Make sure we avoid non-left-click bubbling in Firefox (#3861) and disabled elements in IE (#6911) + if ( event.liveFired === this || !events || !events.live || event.target.disabled || event.button && event.type === "click" ) { + return; + } + + if ( event.namespace ) { + namespace = new RegExp("(^|\\.)" + event.namespace.split(".").join("\\.(?:.*\\.)?") + "(\\.|$)"); + } + + event.liveFired = this; + + var live = events.live.slice(0); + + for ( j = 0; j < live.length; j++ ) { + handleObj = live[j]; + + if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) { + selectors.push( handleObj.selector ); + + } else { + live.splice( j--, 1 ); + } + } + + match = jQuery( event.target ).closest( selectors, event.currentTarget ); + + for ( i = 0, l = match.length; i < l; i++ ) { + close = match[i]; + + for ( j = 0; j < live.length; j++ ) { + handleObj = live[j]; + + if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) && !close.elem.disabled ) { + elem = close.elem; + related = null; + + // Those two events require additional checking + if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) { + event.type = handleObj.preType; + related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0]; + + // Make sure not to accidentally match a child element with the same selector + if ( related && jQuery.contains( elem, related ) ) { + related = elem; + } + } + + if ( !related || related !== elem ) { + elems.push({ elem: elem, handleObj: handleObj, level: close.level }); + } + } + } + } + + for ( i = 0, l = elems.length; i < l; i++ ) { + match = elems[i]; + + if ( maxLevel && match.level > maxLevel ) { + break; + } + + event.currentTarget = match.elem; + event.data = match.handleObj.data; + event.handleObj = match.handleObj; + + ret = match.handleObj.origHandler.apply( match.elem, arguments ); + + if ( ret === false || event.isPropagationStopped() ) { + maxLevel = match.level; + + if ( ret === false ) { + stop = false; + } + if ( event.isImmediatePropagationStopped() ) { + break; + } + } + } + + return stop; +} + +function liveConvert( type, selector ) { + return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspaces, "&"); +} + +jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + + "change select submit keydown keypress keyup error").split(" "), function( i, name ) { + + // Handle event binding + jQuery.fn[ name ] = function( data, fn ) { + if ( fn == null ) { + fn = data; + data = null; + } + + return arguments.length > 0 ? + this.bind( name, data, fn ) : + this.trigger( name ); + }; + + if ( jQuery.attrFn ) { + jQuery.attrFn[ name ] = true; + } +}); + + + +/*! + * Sizzle CSS Selector Engine + * Copyright 2011, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * More information: http://sizzlejs.com/ + */ +(function(){ + +var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, + done = 0, + toString = Object.prototype.toString, + hasDuplicate = false, + baseHasDuplicate = true, + rBackslash = /\\/g, + rNonWord = /\W/; + +// Here we check if the JavaScript engine is using some sort of +// optimization where it does not always call our comparision +// function. If that is the case, discard the hasDuplicate value. +// Thus far that includes Google Chrome. +[0, 0].sort(function() { + baseHasDuplicate = false; + return 0; +}); + +var Sizzle = function( selector, context, results, seed ) { + results = results || []; + context = context || document; + + var origContext = context; + + if ( context.nodeType !== 1 && context.nodeType !== 9 ) { + return []; + } + + if ( !selector || typeof selector !== "string" ) { + return results; + } + + var m, set, checkSet, extra, ret, cur, pop, i, + prune = true, + contextXML = Sizzle.isXML( context ), + parts = [], + soFar = selector; + + // Reset the position of the chunker regexp (start from head) + do { + chunker.exec( "" ); + m = chunker.exec( soFar ); + + if ( m ) { + soFar = m[3]; + + parts.push( m[1] ); + + if ( m[2] ) { + extra = m[3]; + break; + } + } + } while ( m ); + + if ( parts.length > 1 && origPOS.exec( selector ) ) { + + if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { + set = posProcess( parts[0] + parts[1], context ); + + } else { + set = Expr.relative[ parts[0] ] ? + [ context ] : + Sizzle( parts.shift(), context ); + + while ( parts.length ) { + selector = parts.shift(); + + if ( Expr.relative[ selector ] ) { + selector += parts.shift(); + } + + set = posProcess( selector, set ); + } + } + + } else { + // Take a shortcut and set the context if the root selector is an ID + // (but not if it'll be faster if the inner selector is an ID) + if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && + Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { + + ret = Sizzle.find( parts.shift(), context, contextXML ); + context = ret.expr ? + Sizzle.filter( ret.expr, ret.set )[0] : + ret.set[0]; + } + + if ( context ) { + ret = seed ? + { expr: parts.pop(), set: makeArray(seed) } : + Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); + + set = ret.expr ? + Sizzle.filter( ret.expr, ret.set ) : + ret.set; + + if ( parts.length > 0 ) { + checkSet = makeArray( set ); + + } else { + prune = false; + } + + while ( parts.length ) { + cur = parts.pop(); + pop = cur; + + if ( !Expr.relative[ cur ] ) { + cur = ""; + } else { + pop = parts.pop(); + } + + if ( pop == null ) { + pop = context; + } + + Expr.relative[ cur ]( checkSet, pop, contextXML ); + } + + } else { + checkSet = parts = []; + } + } + + if ( !checkSet ) { + checkSet = set; + } + + if ( !checkSet ) { + Sizzle.error( cur || selector ); + } + + if ( toString.call(checkSet) === "[object Array]" ) { + if ( !prune ) { + results.push.apply( results, checkSet ); + + } else if ( context && context.nodeType === 1 ) { + for ( i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) { + results.push( set[i] ); + } + } + + } else { + for ( i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && checkSet[i].nodeType === 1 ) { + results.push( set[i] ); + } + } + } + + } else { + makeArray( checkSet, results ); + } + + if ( extra ) { + Sizzle( extra, origContext, results, seed ); + Sizzle.uniqueSort( results ); + } + + return results; +}; + +Sizzle.uniqueSort = function( results ) { + if ( sortOrder ) { + hasDuplicate = baseHasDuplicate; + results.sort( sortOrder ); + + if ( hasDuplicate ) { + for ( var i = 1; i < results.length; i++ ) { + if ( results[i] === results[ i - 1 ] ) { + results.splice( i--, 1 ); + } + } + } + } + + return results; +}; + +Sizzle.matches = function( expr, set ) { + return Sizzle( expr, null, null, set ); +}; + +Sizzle.matchesSelector = function( node, expr ) { + return Sizzle( expr, null, null, [node] ).length > 0; +}; + +Sizzle.find = function( expr, context, isXML ) { + var set; + + if ( !expr ) { + return []; + } + + for ( var i = 0, l = Expr.order.length; i < l; i++ ) { + var match, + type = Expr.order[i]; + + if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { + var left = match[1]; + match.splice( 1, 1 ); + + if ( left.substr( left.length - 1 ) !== "\\" ) { + match[1] = (match[1] || "").replace( rBackslash, "" ); + set = Expr.find[ type ]( match, context, isXML ); + + if ( set != null ) { + expr = expr.replace( Expr.match[ type ], "" ); + break; + } + } + } + } + + if ( !set ) { + set = typeof context.getElementsByTagName !== "undefined" ? + context.getElementsByTagName( "*" ) : + []; + } + + return { set: set, expr: expr }; +}; + +Sizzle.filter = function( expr, set, inplace, not ) { + var match, anyFound, + old = expr, + result = [], + curLoop = set, + isXMLFilter = set && set[0] && Sizzle.isXML( set[0] ); + + while ( expr && set.length ) { + for ( var type in Expr.filter ) { + if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) { + var found, item, + filter = Expr.filter[ type ], + left = match[1]; + + anyFound = false; + + match.splice(1,1); + + if ( left.substr( left.length - 1 ) === "\\" ) { + continue; + } + + if ( curLoop === result ) { + result = []; + } + + if ( Expr.preFilter[ type ] ) { + match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); + + if ( !match ) { + anyFound = found = true; + + } else if ( match === true ) { + continue; + } + } + + if ( match ) { + for ( var i = 0; (item = curLoop[i]) != null; i++ ) { + if ( item ) { + found = filter( item, match, i, curLoop ); + var pass = not ^ !!found; + + if ( inplace && found != null ) { + if ( pass ) { + anyFound = true; + + } else { + curLoop[i] = false; + } + + } else if ( pass ) { + result.push( item ); + anyFound = true; + } + } + } + } + + if ( found !== undefined ) { + if ( !inplace ) { + curLoop = result; + } + + expr = expr.replace( Expr.match[ type ], "" ); + + if ( !anyFound ) { + return []; + } + + break; + } + } + } + + // Improper expression + if ( expr === old ) { + if ( anyFound == null ) { + Sizzle.error( expr ); + + } else { + break; + } + } + + old = expr; + } + + return curLoop; +}; + +Sizzle.error = function( msg ) { + throw "Syntax error, unrecognized expression: " + msg; +}; + +var Expr = Sizzle.selectors = { + order: [ "ID", "NAME", "TAG" ], + + match: { + ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, + CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, + NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/, + ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/, + TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/, + CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/, + POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/, + PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/ + }, + + leftMatch: {}, + + attrMap: { + "class": "className", + "for": "htmlFor" + }, + + attrHandle: { + href: function( elem ) { + return elem.getAttribute( "href" ); + }, + type: function( elem ) { + return elem.getAttribute( "type" ); + } + }, + + relative: { + "+": function(checkSet, part){ + var isPartStr = typeof part === "string", + isTag = isPartStr && !rNonWord.test( part ), + isPartStrNotTag = isPartStr && !isTag; + + if ( isTag ) { + part = part.toLowerCase(); + } + + for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { + if ( (elem = checkSet[i]) ) { + while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} + + checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ? + elem || false : + elem === part; + } + } + + if ( isPartStrNotTag ) { + Sizzle.filter( part, checkSet, true ); + } + }, + + ">": function( checkSet, part ) { + var elem, + isPartStr = typeof part === "string", + i = 0, + l = checkSet.length; + + if ( isPartStr && !rNonWord.test( part ) ) { + part = part.toLowerCase(); + + for ( ; i < l; i++ ) { + elem = checkSet[i]; + + if ( elem ) { + var parent = elem.parentNode; + checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false; + } + } + + } else { + for ( ; i < l; i++ ) { + elem = checkSet[i]; + + if ( elem ) { + checkSet[i] = isPartStr ? + elem.parentNode : + elem.parentNode === part; + } + } + + if ( isPartStr ) { + Sizzle.filter( part, checkSet, true ); + } + } + }, + + "": function(checkSet, part, isXML){ + var nodeCheck, + doneName = done++, + checkFn = dirCheck; + + if ( typeof part === "string" && !rNonWord.test( part ) ) { + part = part.toLowerCase(); + nodeCheck = part; + checkFn = dirNodeCheck; + } + + checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML ); + }, + + "~": function( checkSet, part, isXML ) { + var nodeCheck, + doneName = done++, + checkFn = dirCheck; + + if ( typeof part === "string" && !rNonWord.test( part ) ) { + part = part.toLowerCase(); + nodeCheck = part; + checkFn = dirNodeCheck; + } + + checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML ); + } + }, + + find: { + ID: function( match, context, isXML ) { + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + return m && m.parentNode ? [m] : []; + } + }, + + NAME: function( match, context ) { + if ( typeof context.getElementsByName !== "undefined" ) { + var ret = [], + results = context.getElementsByName( match[1] ); + + for ( var i = 0, l = results.length; i < l; i++ ) { + if ( results[i].getAttribute("name") === match[1] ) { + ret.push( results[i] ); + } + } + + return ret.length === 0 ? null : ret; + } + }, + + TAG: function( match, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( match[1] ); + } + } + }, + preFilter: { + CLASS: function( match, curLoop, inplace, result, not, isXML ) { + match = " " + match[1].replace( rBackslash, "" ) + " "; + + if ( isXML ) { + return match; + } + + for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { + if ( elem ) { + if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) { + if ( !inplace ) { + result.push( elem ); + } + + } else if ( inplace ) { + curLoop[i] = false; + } + } + } + + return false; + }, + + ID: function( match ) { + return match[1].replace( rBackslash, "" ); + }, + + TAG: function( match, curLoop ) { + return match[1].replace( rBackslash, "" ).toLowerCase(); + }, + + CHILD: function( match ) { + if ( match[1] === "nth" ) { + if ( !match[2] ) { + Sizzle.error( match[0] ); + } + + match[2] = match[2].replace(/^\+|\s*/g, ''); + + // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' + var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec( + match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" || + !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); + + // calculate the numbers (first)n+(last) including if they are negative + match[2] = (test[1] + (test[2] || 1)) - 0; + match[3] = test[3] - 0; + } + else if ( match[2] ) { + Sizzle.error( match[0] ); + } + + // TODO: Move to normal caching system + match[0] = done++; + + return match; + }, + + ATTR: function( match, curLoop, inplace, result, not, isXML ) { + var name = match[1] = match[1].replace( rBackslash, "" ); + + if ( !isXML && Expr.attrMap[name] ) { + match[1] = Expr.attrMap[name]; + } + + // Handle if an un-quoted value was used + match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" ); + + if ( match[2] === "~=" ) { + match[4] = " " + match[4] + " "; + } + + return match; + }, + + PSEUDO: function( match, curLoop, inplace, result, not ) { + if ( match[1] === "not" ) { + // If we're dealing with a complex expression, or a simple one + if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { + match[3] = Sizzle(match[3], null, null, curLoop); + + } else { + var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); + + if ( !inplace ) { + result.push.apply( result, ret ); + } + + return false; + } + + } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { + return true; + } + + return match; + }, + + POS: function( match ) { + match.unshift( true ); + + return match; + } + }, + + filters: { + enabled: function( elem ) { + return elem.disabled === false && elem.type !== "hidden"; + }, + + disabled: function( elem ) { + return elem.disabled === true; + }, + + checked: function( elem ) { + return elem.checked === true; + }, + + selected: function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + parent: function( elem ) { + return !!elem.firstChild; + }, + + empty: function( elem ) { + return !elem.firstChild; + }, + + has: function( elem, i, match ) { + return !!Sizzle( match[3], elem ).length; + }, + + header: function( elem ) { + return (/h\d/i).test( elem.nodeName ); + }, + + text: function( elem ) { + var attr = elem.getAttribute( "type" ), type = elem.type; + // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) + // use getAttribute instead to test this case + return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null ); + }, + + radio: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type; + }, + + checkbox: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type; + }, + + file: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "file" === elem.type; + }, + + password: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "password" === elem.type; + }, + + submit: function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && "submit" === elem.type; + }, + + image: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "image" === elem.type; + }, + + reset: function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && "reset" === elem.type; + }, + + button: function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && "button" === elem.type || name === "button"; + }, + + input: function( elem ) { + return (/input|select|textarea|button/i).test( elem.nodeName ); + }, + + focus: function( elem ) { + return elem === elem.ownerDocument.activeElement; + } + }, + setFilters: { + first: function( elem, i ) { + return i === 0; + }, + + last: function( elem, i, match, array ) { + return i === array.length - 1; + }, + + even: function( elem, i ) { + return i % 2 === 0; + }, + + odd: function( elem, i ) { + return i % 2 === 1; + }, + + lt: function( elem, i, match ) { + return i < match[3] - 0; + }, + + gt: function( elem, i, match ) { + return i > match[3] - 0; + }, + + nth: function( elem, i, match ) { + return match[3] - 0 === i; + }, + + eq: function( elem, i, match ) { + return match[3] - 0 === i; + } + }, + filter: { + PSEUDO: function( elem, match, i, array ) { + var name = match[1], + filter = Expr.filters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + + } else if ( name === "contains" ) { + return (elem.textContent || elem.innerText || Sizzle.getText([ elem ]) || "").indexOf(match[3]) >= 0; + + } else if ( name === "not" ) { + var not = match[3]; + + for ( var j = 0, l = not.length; j < l; j++ ) { + if ( not[j] === elem ) { + return false; + } + } + + return true; + + } else { + Sizzle.error( name ); + } + }, + + CHILD: function( elem, match ) { + var type = match[1], + node = elem; + + switch ( type ) { + case "only": + case "first": + while ( (node = node.previousSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + + if ( type === "first" ) { + return true; + } + + node = elem; + + case "last": + while ( (node = node.nextSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + + return true; + + case "nth": + var first = match[2], + last = match[3]; + + if ( first === 1 && last === 0 ) { + return true; + } + + var doneName = match[0], + parent = elem.parentNode; + + if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) { + var count = 0; + + for ( node = parent.firstChild; node; node = node.nextSibling ) { + if ( node.nodeType === 1 ) { + node.nodeIndex = ++count; + } + } + + parent.sizcache = doneName; + } + + var diff = elem.nodeIndex - last; + + if ( first === 0 ) { + return diff === 0; + + } else { + return ( diff % first === 0 && diff / first >= 0 ); + } + } + }, + + ID: function( elem, match ) { + return elem.nodeType === 1 && elem.getAttribute("id") === match; + }, + + TAG: function( elem, match ) { + return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match; + }, + + CLASS: function( elem, match ) { + return (" " + (elem.className || elem.getAttribute("class")) + " ") + .indexOf( match ) > -1; + }, + + ATTR: function( elem, match ) { + var name = match[1], + result = Expr.attrHandle[ name ] ? + Expr.attrHandle[ name ]( elem ) : + elem[ name ] != null ? + elem[ name ] : + elem.getAttribute( name ), + value = result + "", + type = match[2], + check = match[4]; + + return result == null ? + type === "!=" : + type === "=" ? + value === check : + type === "*=" ? + value.indexOf(check) >= 0 : + type === "~=" ? + (" " + value + " ").indexOf(check) >= 0 : + !check ? + value && result !== false : + type === "!=" ? + value !== check : + type === "^=" ? + value.indexOf(check) === 0 : + type === "$=" ? + value.substr(value.length - check.length) === check : + type === "|=" ? + value === check || value.substr(0, check.length + 1) === check + "-" : + false; + }, + + POS: function( elem, match, i, array ) { + var name = match[2], + filter = Expr.setFilters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + } + } + } +}; + +var origPOS = Expr.match.POS, + fescape = function(all, num){ + return "\\" + (num - 0 + 1); + }; + +for ( var type in Expr.match ) { + Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) ); + Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) ); +} + +var makeArray = function( array, results ) { + array = Array.prototype.slice.call( array, 0 ); + + if ( results ) { + results.push.apply( results, array ); + return results; + } + + return array; +}; + +// Perform a simple check to determine if the browser is capable of +// converting a NodeList to an array using builtin methods. +// Also verifies that the returned array holds DOM nodes +// (which is not the case in the Blackberry browser) +try { + Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType; + +// Provide a fallback method if it does not work +} catch( e ) { + makeArray = function( array, results ) { + var i = 0, + ret = results || []; + + if ( toString.call(array) === "[object Array]" ) { + Array.prototype.push.apply( ret, array ); + + } else { + if ( typeof array.length === "number" ) { + for ( var l = array.length; i < l; i++ ) { + ret.push( array[i] ); + } + + } else { + for ( ; array[i]; i++ ) { + ret.push( array[i] ); + } + } + } + + return ret; + }; +} + +var sortOrder, siblingCheck; + +if ( document.documentElement.compareDocumentPosition ) { + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { + return a.compareDocumentPosition ? -1 : 1; + } + + return a.compareDocumentPosition(b) & 4 ? -1 : 1; + }; + +} else { + sortOrder = function( a, b ) { + // The nodes are identical, we can exit early + if ( a === b ) { + hasDuplicate = true; + return 0; + + // Fallback to using sourceIndex (in IE) if it's available on both nodes + } else if ( a.sourceIndex && b.sourceIndex ) { + return a.sourceIndex - b.sourceIndex; + } + + var al, bl, + ap = [], + bp = [], + aup = a.parentNode, + bup = b.parentNode, + cur = aup; + + // If the nodes are siblings (or identical) we can do a quick check + if ( aup === bup ) { + return siblingCheck( a, b ); + + // If no parents were found then the nodes are disconnected + } else if ( !aup ) { + return -1; + + } else if ( !bup ) { + return 1; + } + + // Otherwise they're somewhere else in the tree so we need + // to build up a full list of the parentNodes for comparison + while ( cur ) { + ap.unshift( cur ); + cur = cur.parentNode; + } + + cur = bup; + + while ( cur ) { + bp.unshift( cur ); + cur = cur.parentNode; + } + + al = ap.length; + bl = bp.length; + + // Start walking down the tree looking for a discrepancy + for ( var i = 0; i < al && i < bl; i++ ) { + if ( ap[i] !== bp[i] ) { + return siblingCheck( ap[i], bp[i] ); + } + } + + // We ended someplace up the tree so do a sibling check + return i === al ? + siblingCheck( a, bp[i], -1 ) : + siblingCheck( ap[i], b, 1 ); + }; + + siblingCheck = function( a, b, ret ) { + if ( a === b ) { + return ret; + } + + var cur = a.nextSibling; + + while ( cur ) { + if ( cur === b ) { + return -1; + } + + cur = cur.nextSibling; + } + + return 1; + }; +} + +// Utility function for retreiving the text value of an array of DOM nodes +Sizzle.getText = function( elems ) { + var ret = "", elem; + + for ( var i = 0; elems[i]; i++ ) { + elem = elems[i]; + + // Get the text from text nodes and CDATA nodes + if ( elem.nodeType === 3 || elem.nodeType === 4 ) { + ret += elem.nodeValue; + + // Traverse everything else, except comment nodes + } else if ( elem.nodeType !== 8 ) { + ret += Sizzle.getText( elem.childNodes ); + } + } + + return ret; +}; + +// Check to see if the browser returns elements by name when +// querying by getElementById (and provide a workaround) +(function(){ + // We're going to inject a fake input element with a specified name + var form = document.createElement("div"), + id = "script" + (new Date()).getTime(), + root = document.documentElement; + + form.innerHTML = ""; + + // Inject it into the root element, check its status, and remove it quickly + root.insertBefore( form, root.firstChild ); + + // The workaround has to do additional checks after a getElementById + // Which slows things down for other browsers (hence the branching) + if ( document.getElementById( id ) ) { + Expr.find.ID = function( match, context, isXML ) { + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + + return m ? + m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? + [m] : + undefined : + []; + } + }; + + Expr.filter.ID = function( elem, match ) { + var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); + + return elem.nodeType === 1 && node && node.nodeValue === match; + }; + } + + root.removeChild( form ); + + // release memory in IE + root = form = null; +})(); + +(function(){ + // Check to see if the browser returns only elements + // when doing getElementsByTagName("*") + + // Create a fake element + var div = document.createElement("div"); + div.appendChild( document.createComment("") ); + + // Make sure no comments are found + if ( div.getElementsByTagName("*").length > 0 ) { + Expr.find.TAG = function( match, context ) { + var results = context.getElementsByTagName( match[1] ); + + // Filter out possible comments + if ( match[1] === "*" ) { + var tmp = []; + + for ( var i = 0; results[i]; i++ ) { + if ( results[i].nodeType === 1 ) { + tmp.push( results[i] ); + } + } + + results = tmp; + } + + return results; + }; + } + + // Check to see if an attribute returns normalized href attributes + div.innerHTML = ""; + + if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && + div.firstChild.getAttribute("href") !== "#" ) { + + Expr.attrHandle.href = function( elem ) { + return elem.getAttribute( "href", 2 ); + }; + } + + // release memory in IE + div = null; +})(); + +if ( document.querySelectorAll ) { + (function(){ + var oldSizzle = Sizzle, + div = document.createElement("div"), + id = "__sizzle__"; + + div.innerHTML = "

    "; + + // Safari can't handle uppercase or unicode characters when + // in quirks mode. + if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { + return; + } + + Sizzle = function( query, context, extra, seed ) { + context = context || document; + + // Only use querySelectorAll on non-XML documents + // (ID selectors don't work in non-HTML documents) + if ( !seed && !Sizzle.isXML(context) ) { + // See if we find a selector to speed up + var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query ); + + if ( match && (context.nodeType === 1 || context.nodeType === 9) ) { + // Speed-up: Sizzle("TAG") + if ( match[1] ) { + return makeArray( context.getElementsByTagName( query ), extra ); + + // Speed-up: Sizzle(".CLASS") + } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) { + return makeArray( context.getElementsByClassName( match[2] ), extra ); + } + } + + if ( context.nodeType === 9 ) { + // Speed-up: Sizzle("body") + // The body element only exists once, optimize finding it + if ( query === "body" && context.body ) { + return makeArray( [ context.body ], extra ); + + // Speed-up: Sizzle("#ID") + } else if ( match && match[3] ) { + var elem = context.getElementById( match[3] ); + + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id === match[3] ) { + return makeArray( [ elem ], extra ); + } + + } else { + return makeArray( [], extra ); + } + } + + try { + return makeArray( context.querySelectorAll(query), extra ); + } catch(qsaError) {} + + // qSA works strangely on Element-rooted queries + // We can work around this by specifying an extra ID on the root + // and working up from there (Thanks to Andrew Dupont for the technique) + // IE 8 doesn't work on object elements + } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { + var oldContext = context, + old = context.getAttribute( "id" ), + nid = old || id, + hasParent = context.parentNode, + relativeHierarchySelector = /^\s*[+~]/.test( query ); + + if ( !old ) { + context.setAttribute( "id", nid ); + } else { + nid = nid.replace( /'/g, "\\$&" ); + } + if ( relativeHierarchySelector && hasParent ) { + context = context.parentNode; + } + + try { + if ( !relativeHierarchySelector || hasParent ) { + return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra ); + } + + } catch(pseudoError) { + } finally { + if ( !old ) { + oldContext.removeAttribute( "id" ); + } + } + } + } + + return oldSizzle(query, context, extra, seed); + }; + + for ( var prop in oldSizzle ) { + Sizzle[ prop ] = oldSizzle[ prop ]; + } + + // release memory in IE + div = null; + })(); +} + +(function(){ + var html = document.documentElement, + matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector; + + if ( matches ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9 fails this) + var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ), + pseudoWorks = false; + + try { + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( document.documentElement, "[test!='']:sizzle" ); + + } catch( pseudoError ) { + pseudoWorks = true; + } + + Sizzle.matchesSelector = function( node, expr ) { + // Make sure that attribute selectors are quoted + expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']"); + + if ( !Sizzle.isXML( node ) ) { + try { + if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) { + var ret = matches.call( node, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || !disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9, so check for that + node.document && node.document.nodeType !== 11 ) { + return ret; + } + } + } catch(e) {} + } + + return Sizzle(expr, null, null, [node]).length > 0; + }; + } +})(); + +(function(){ + var div = document.createElement("div"); + + div.innerHTML = "
    "; + + // Opera can't find a second classname (in 9.6) + // Also, make sure that getElementsByClassName actually exists + if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { + return; + } + + // Safari caches class attributes, doesn't catch changes (in 3.2) + div.lastChild.className = "e"; + + if ( div.getElementsByClassName("e").length === 1 ) { + return; + } + + Expr.order.splice(1, 0, "CLASS"); + Expr.find.CLASS = function( match, context, isXML ) { + if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { + return context.getElementsByClassName(match[1]); + } + }; + + // release memory in IE + div = null; +})(); + +function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + + if ( elem ) { + var match = false; + + elem = elem[dir]; + + while ( elem ) { + if ( elem.sizcache === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 && !isXML ){ + elem.sizcache = doneName; + elem.sizset = i; + } + + if ( elem.nodeName.toLowerCase() === cur ) { + match = elem; + break; + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + + if ( elem ) { + var match = false; + + elem = elem[dir]; + + while ( elem ) { + if ( elem.sizcache === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 ) { + if ( !isXML ) { + elem.sizcache = doneName; + elem.sizset = i; + } + + if ( typeof cur !== "string" ) { + if ( elem === cur ) { + match = true; + break; + } + + } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { + match = elem; + break; + } + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +if ( document.documentElement.contains ) { + Sizzle.contains = function( a, b ) { + return a !== b && (a.contains ? a.contains(b) : true); + }; + +} else if ( document.documentElement.compareDocumentPosition ) { + Sizzle.contains = function( a, b ) { + return !!(a.compareDocumentPosition(b) & 16); + }; + +} else { + Sizzle.contains = function() { + return false; + }; +} + +Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement; + + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +var posProcess = function( selector, context ) { + var match, + tmpSet = [], + later = "", + root = context.nodeType ? [context] : context; + + // Position selectors must be done after the filter + // And so must :not(positional) so we move all PSEUDOs to the end + while ( (match = Expr.match.PSEUDO.exec( selector )) ) { + later += match[0]; + selector = selector.replace( Expr.match.PSEUDO, "" ); + } + + selector = Expr.relative[selector] ? selector + "*" : selector; + + for ( var i = 0, l = root.length; i < l; i++ ) { + Sizzle( selector, root[i], tmpSet ); + } + + return Sizzle.filter( later, tmpSet ); +}; + +// EXPOSE +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; +jQuery.expr[":"] = jQuery.expr.filters; +jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; + + +})(); + + +var runtil = /Until$/, + rparentsprev = /^(?:parents|prevUntil|prevAll)/, + // Note: This RegExp should be improved, or likely pulled from Sizzle + rmultiselector = /,/, + isSimple = /^.[^:#\[\.,]*$/, + slice = Array.prototype.slice, + POS = jQuery.expr.match.POS, + // methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend({ + find: function( selector ) { + var self = this, + i, l; + + if ( typeof selector !== "string" ) { + return jQuery( selector ).filter(function() { + for ( i = 0, l = self.length; i < l; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + }); + } + + var ret = this.pushStack( "", "find", selector ), + length, n, r; + + for ( i = 0, l = this.length; i < l; i++ ) { + length = ret.length; + jQuery.find( selector, this[i], ret ); + + if ( i > 0 ) { + // Make sure that the results are unique + for ( n = length; n < ret.length; n++ ) { + for ( r = 0; r < length; r++ ) { + if ( ret[r] === ret[n] ) { + ret.splice(n--, 1); + break; + } + } + } + } + } + + return ret; + }, + + has: function( target ) { + var targets = jQuery( target ); + return this.filter(function() { + for ( var i = 0, l = targets.length; i < l; i++ ) { + if ( jQuery.contains( this, targets[i] ) ) { + return true; + } + } + }); + }, + + not: function( selector ) { + return this.pushStack( winnow(this, selector, false), "not", selector); + }, + + filter: function( selector ) { + return this.pushStack( winnow(this, selector, true), "filter", selector ); + }, + + is: function( selector ) { + return !!selector && ( typeof selector === "string" ? + jQuery.filter( selector, this ).length > 0 : + this.filter( selector ).length > 0 ); + }, + + closest: function( selectors, context ) { + var ret = [], i, l, cur = this[0]; + + // Array + if ( jQuery.isArray( selectors ) ) { + var match, selector, + matches = {}, + level = 1; + + if ( cur && selectors.length ) { + for ( i = 0, l = selectors.length; i < l; i++ ) { + selector = selectors[i]; + + if ( !matches[ selector ] ) { + matches[ selector ] = POS.test( selector ) ? + jQuery( selector, context || this.context ) : + selector; + } + } + + while ( cur && cur.ownerDocument && cur !== context ) { + for ( selector in matches ) { + match = matches[ selector ]; + + if ( match.jquery ? match.index( cur ) > -1 : jQuery( cur ).is( match ) ) { + ret.push({ selector: selector, elem: cur, level: level }); + } + } + + cur = cur.parentNode; + level++; + } + } + + return ret; + } + + // String + var pos = POS.test( selectors ) || typeof selectors !== "string" ? + jQuery( selectors, context || this.context ) : + 0; + + for ( i = 0, l = this.length; i < l; i++ ) { + cur = this[i]; + + while ( cur ) { + if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { + ret.push( cur ); + break; + + } else { + cur = cur.parentNode; + if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) { + break; + } + } + } + } + + ret = ret.length > 1 ? jQuery.unique( ret ) : ret; + + return this.pushStack( ret, "closest", selectors ); + }, + + // Determine the position of an element within + // the matched set of elements + index: function( elem ) { + if ( !elem || typeof elem === "string" ) { + return jQuery.inArray( this[0], + // If it receives a string, the selector is used + // If it receives nothing, the siblings are used + elem ? jQuery( elem ) : this.parent().children() ); + } + // Locate the position of the desired element + return jQuery.inArray( + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[0] : elem, this ); + }, + + add: function( selector, context ) { + var set = typeof selector === "string" ? + jQuery( selector, context ) : + jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), + all = jQuery.merge( this.get(), set ); + + return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? + all : + jQuery.unique( all ) ); + }, + + andSelf: function() { + return this.add( this.prevObject ); + } +}); + +// A painfully simple check to see if an element is disconnected +// from a document (should be improved, where feasible). +function isDisconnected( node ) { + return !node || !node.parentNode || node.parentNode.nodeType === 11; +} + +jQuery.each({ + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return jQuery.dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return jQuery.dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return jQuery.nth( elem, 2, "nextSibling" ); + }, + prev: function( elem ) { + return jQuery.nth( elem, 2, "previousSibling" ); + }, + nextAll: function( elem ) { + return jQuery.dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return jQuery.dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return jQuery.dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return jQuery.dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return jQuery.sibling( elem.parentNode.firstChild, elem ); + }, + children: function( elem ) { + return jQuery.sibling( elem.firstChild ); + }, + contents: function( elem ) { + return jQuery.nodeName( elem, "iframe" ) ? + elem.contentDocument || elem.contentWindow.document : + jQuery.makeArray( elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var ret = jQuery.map( this, fn, until ), + // The variable 'args' was introduced in + // https://github.com/jquery/jquery/commit/52a0238 + // to work around a bug in Chrome 10 (Dev) and should be removed when the bug is fixed. + // http://code.google.com/p/v8/issues/detail?id=1050 + args = slice.call(arguments); + + if ( !runtil.test( name ) ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + ret = jQuery.filter( selector, ret ); + } + + ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; + + if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) { + ret = ret.reverse(); + } + + return this.pushStack( ret, name, args.join(",") ); + }; +}); + +jQuery.extend({ + filter: function( expr, elems, not ) { + if ( not ) { + expr = ":not(" + expr + ")"; + } + + return elems.length === 1 ? + jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : + jQuery.find.matches(expr, elems); + }, + + dir: function( elem, dir, until ) { + var matched = [], + cur = elem[ dir ]; + + while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { + if ( cur.nodeType === 1 ) { + matched.push( cur ); + } + cur = cur[dir]; + } + return matched; + }, + + nth: function( cur, result, dir, elem ) { + result = result || 1; + var num = 0; + + for ( ; cur; cur = cur[dir] ) { + if ( cur.nodeType === 1 && ++num === result ) { + break; + } + } + + return cur; + }, + + sibling: function( n, elem ) { + var r = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + r.push( n ); + } + } + + return r; + } +}); + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, keep ) { + + // Can't pass null or undefined to indexOf in Firefox 4 + // Set to 0 to skip string check + qualifier = qualifier || 0; + + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep(elements, function( elem, i ) { + var retVal = !!qualifier.call( elem, i, elem ); + return retVal === keep; + }); + + } else if ( qualifier.nodeType ) { + return jQuery.grep(elements, function( elem, i ) { + return (elem === qualifier) === keep; + }); + + } else if ( typeof qualifier === "string" ) { + var filtered = jQuery.grep(elements, function( elem ) { + return elem.nodeType === 1; + }); + + if ( isSimple.test( qualifier ) ) { + return jQuery.filter(qualifier, filtered, !keep); + } else { + qualifier = jQuery.filter( qualifier, filtered ); + } + } + + return jQuery.grep(elements, function( elem, i ) { + return (jQuery.inArray( elem, qualifier ) >= 0) === keep; + }); +} + + + + +var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, + rleadingWhitespace = /^\s+/, + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, + rtagName = /<([\w:]+)/, + rtbody = /", "" ], + legend: [ 1, "
    ", "
    " ], + thead: [ 1, "", "
    " ], + tr: [ 2, "", "
    " ], + td: [ 3, "", "
    " ], + col: [ 2, "", "
    " ], + area: [ 1, "", "" ], + _default: [ 0, "", "" ] + }; + +wrapMap.optgroup = wrapMap.option; +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// IE can't serialize and