Adding /includes
authordan@scribus.fuhry.local.fuhry.local
Wed, 13 Jun 2007 16:07:17 -0400
changeset 1 fe660c52c48f
parent 0 902822492a68
child 2 0931d60f5bdb
Adding /includes
includes/captcha.php
includes/captcha/fonts/assimila.ttf
includes/captcha/fonts/elephant.ttf
includes/captcha/fonts/swash_normal.ttf
includes/captcha/fonts/trekker_regular.ttf
includes/clientside/admin-menu.js
includes/clientside/css/enano-shared.css
includes/clientside/css/enano-shared.css~
includes/clientside/dbx-key.js
includes/clientside/dbx.css
includes/clientside/dbx.js
includes/clientside/jsres.php
includes/clientside/md5.js
includes/clientside/sbedit.js
includes/clientside/static/.acl.js.marks
includes/clientside/static/acl.js
includes/clientside/static/admin-menu.js
includes/clientside/static/ajax.js
includes/clientside/static/autocomplete.js
includes/clientside/static/base64.js
includes/clientside/static/comments.js
includes/clientside/static/dropdown.js
includes/clientside/static/dynano.js
includes/clientside/static/editor.js
includes/clientside/static/enano-lib-basic.js
includes/clientside/static/faders.js
includes/clientside/static/faders.js~
includes/clientside/static/fat.js
includes/clientside/static/flyin.js
includes/clientside/static/grippy.js
includes/clientside/static/json.js
includes/clientside/static/loader.js
includes/clientside/static/md5.js
includes/clientside/static/misc.js
includes/clientside/static/misc.js~
includes/clientside/static/rijndael.js
includes/clientside/static/sliders.js
includes/clientside/static/template-compiler.js
includes/clientside/static/toolbar.js
includes/clientside/static/windows.js
includes/clientside/tinymce/blank.htm
includes/clientside/tinymce/langs/en.js
includes/clientside/tinymce/langs/readme.txt
includes/clientside/tinymce/license.txt
includes/clientside/tinymce/plugins/advhr/css/advhr.css
includes/clientside/tinymce/plugins/advhr/editor_plugin.js
includes/clientside/tinymce/plugins/advhr/editor_plugin_src.js
includes/clientside/tinymce/plugins/advhr/images/advhr.gif
includes/clientside/tinymce/plugins/advhr/jscripts/rule.js
includes/clientside/tinymce/plugins/advhr/langs/en.js
includes/clientside/tinymce/plugins/advhr/readme.txt
includes/clientside/tinymce/plugins/advhr/rule.htm
includes/clientside/tinymce/plugins/advimage/css/advimage.css
includes/clientside/tinymce/plugins/advimage/editor_plugin.js
includes/clientside/tinymce/plugins/advimage/editor_plugin_src.js
includes/clientside/tinymce/plugins/advimage/image.htm
includes/clientside/tinymce/plugins/advimage/images/sample.gif
includes/clientside/tinymce/plugins/advimage/jscripts/functions.js
includes/clientside/tinymce/plugins/advimage/langs/en.js
includes/clientside/tinymce/plugins/advimage/readme.txt
includes/clientside/tinymce/plugins/advlink/css/advlink.css
includes/clientside/tinymce/plugins/advlink/editor_plugin.js
includes/clientside/tinymce/plugins/advlink/editor_plugin_src.js
includes/clientside/tinymce/plugins/advlink/jscripts/functions.js
includes/clientside/tinymce/plugins/advlink/langs/en.js
includes/clientside/tinymce/plugins/advlink/link.htm
includes/clientside/tinymce/plugins/advlink/readme.txt
includes/clientside/tinymce/plugins/autosave/editor_plugin.js
includes/clientside/tinymce/plugins/autosave/editor_plugin_src.js
includes/clientside/tinymce/plugins/autosave/langs/en.js
includes/clientside/tinymce/plugins/autosave/readme.txt
includes/clientside/tinymce/plugins/bbcode/editor_plugin.js
includes/clientside/tinymce/plugins/bbcode/editor_plugin_src.js
includes/clientside/tinymce/plugins/cleanup/editor_plugin.js
includes/clientside/tinymce/plugins/cleanup/editor_plugin_src.js
includes/clientside/tinymce/plugins/cleanup/readme.txt
includes/clientside/tinymce/plugins/contextmenu/css/contextmenu.css
includes/clientside/tinymce/plugins/contextmenu/editor_plugin.js
includes/clientside/tinymce/plugins/contextmenu/editor_plugin_src.js
includes/clientside/tinymce/plugins/contextmenu/images/spacer.gif
includes/clientside/tinymce/plugins/contextmenu/readme.txt
includes/clientside/tinymce/plugins/devkit/css/devkit.css
includes/clientside/tinymce/plugins/devkit/css/devkit_ui.css
includes/clientside/tinymce/plugins/devkit/devkit.htm
includes/clientside/tinymce/plugins/devkit/editor_plugin.js
includes/clientside/tinymce/plugins/devkit/editor_plugin_src.js
includes/clientside/tinymce/plugins/devkit/images/flip_down.gif
includes/clientside/tinymce/plugins/devkit/images/flip_up.gif
includes/clientside/tinymce/plugins/devkit/jscripts/devkit.js
includes/clientside/tinymce/plugins/devkit/jscripts/diff.js
includes/clientside/tinymce/plugins/devkit/langs/en.js
includes/clientside/tinymce/plugins/directionality/editor_plugin.js
includes/clientside/tinymce/plugins/directionality/editor_plugin_src.js
includes/clientside/tinymce/plugins/directionality/images/ltr.gif
includes/clientside/tinymce/plugins/directionality/images/rtl.gif
includes/clientside/tinymce/plugins/directionality/langs/en.js
includes/clientside/tinymce/plugins/directionality/readme.txt
includes/clientside/tinymce/plugins/emotions/editor_plugin.js
includes/clientside/tinymce/plugins/emotions/editor_plugin_src.js
includes/clientside/tinymce/plugins/emotions/emotions.htm
includes/clientside/tinymce/plugins/emotions/images/emotions.gif
includes/clientside/tinymce/plugins/emotions/images/readme.txt
includes/clientside/tinymce/plugins/emotions/images/smiley-cool.gif
includes/clientside/tinymce/plugins/emotions/images/smiley-cry.gif
includes/clientside/tinymce/plugins/emotions/images/smiley-embarassed.gif
includes/clientside/tinymce/plugins/emotions/images/smiley-foot-in-mouth.gif
includes/clientside/tinymce/plugins/emotions/images/smiley-frown.gif
includes/clientside/tinymce/plugins/emotions/images/smiley-innocent.gif
includes/clientside/tinymce/plugins/emotions/images/smiley-kiss.gif
includes/clientside/tinymce/plugins/emotions/images/smiley-laughing.gif
includes/clientside/tinymce/plugins/emotions/images/smiley-money-mouth.gif
includes/clientside/tinymce/plugins/emotions/images/smiley-sealed.gif
includes/clientside/tinymce/plugins/emotions/images/smiley-smile.gif
includes/clientside/tinymce/plugins/emotions/images/smiley-surprised.gif
includes/clientside/tinymce/plugins/emotions/images/smiley-tongue-out.gif
includes/clientside/tinymce/plugins/emotions/images/smiley-undecided.gif
includes/clientside/tinymce/plugins/emotions/images/smiley-wink.gif
includes/clientside/tinymce/plugins/emotions/images/smiley-yell.gif
includes/clientside/tinymce/plugins/emotions/jscripts/functions.js
includes/clientside/tinymce/plugins/emotions/langs/en.js
includes/clientside/tinymce/plugins/emotions/readme.txt
includes/clientside/tinymce/plugins/flash/css/content.css
includes/clientside/tinymce/plugins/flash/css/flash.css
includes/clientside/tinymce/plugins/flash/editor_plugin.js
includes/clientside/tinymce/plugins/flash/editor_plugin_src.js
includes/clientside/tinymce/plugins/flash/flash.htm
includes/clientside/tinymce/plugins/flash/images/flash.gif
includes/clientside/tinymce/plugins/flash/jscripts/flash.js
includes/clientside/tinymce/plugins/flash/langs/en.js
includes/clientside/tinymce/plugins/flash/readme.txt
includes/clientside/tinymce/plugins/fullpage/blank.htm
includes/clientside/tinymce/plugins/fullpage/css/fullpage.css
includes/clientside/tinymce/plugins/fullpage/editor_plugin.js
includes/clientside/tinymce/plugins/fullpage/editor_plugin_src.js
includes/clientside/tinymce/plugins/fullpage/fullpage.htm
includes/clientside/tinymce/plugins/fullpage/images/add.gif
includes/clientside/tinymce/plugins/fullpage/images/fullpage.gif
includes/clientside/tinymce/plugins/fullpage/images/move_down.gif
includes/clientside/tinymce/plugins/fullpage/images/move_up.gif
includes/clientside/tinymce/plugins/fullpage/images/remove.gif
includes/clientside/tinymce/plugins/fullpage/jscripts/fullpage.js
includes/clientside/tinymce/plugins/fullpage/langs/en.js
includes/clientside/tinymce/plugins/fullscreen/css/page.css
includes/clientside/tinymce/plugins/fullscreen/editor_plugin.js
includes/clientside/tinymce/plugins/fullscreen/editor_plugin_src.js
includes/clientside/tinymce/plugins/fullscreen/fullscreen.htm
includes/clientside/tinymce/plugins/fullscreen/images/fullscreen.gif
includes/clientside/tinymce/plugins/fullscreen/langs/en.js
includes/clientside/tinymce/plugins/fullscreen/readme.txt
includes/clientside/tinymce/plugins/iespell/editor_plugin.js
includes/clientside/tinymce/plugins/iespell/editor_plugin_src.js
includes/clientside/tinymce/plugins/iespell/images/iespell.gif
includes/clientside/tinymce/plugins/iespell/langs/en.js
includes/clientside/tinymce/plugins/iespell/readme.txt
includes/clientside/tinymce/plugins/inlinepopups/css/inlinepopup.css
includes/clientside/tinymce/plugins/inlinepopups/editor_plugin.js
includes/clientside/tinymce/plugins/inlinepopups/editor_plugin_src.js
includes/clientside/tinymce/plugins/inlinepopups/images/spacer.gif
includes/clientside/tinymce/plugins/inlinepopups/images/window_close.gif
includes/clientside/tinymce/plugins/inlinepopups/images/window_maximize.gif
includes/clientside/tinymce/plugins/inlinepopups/images/window_minimize.gif
includes/clientside/tinymce/plugins/inlinepopups/images/window_resize.gif
includes/clientside/tinymce/plugins/inlinepopups/jscripts/mcwindows.js
includes/clientside/tinymce/plugins/inlinepopups/readme.txt
includes/clientside/tinymce/plugins/insertdatetime/editor_plugin.js
includes/clientside/tinymce/plugins/insertdatetime/editor_plugin_src.js
includes/clientside/tinymce/plugins/insertdatetime/images/insertdate.gif
includes/clientside/tinymce/plugins/insertdatetime/images/inserttime.gif
includes/clientside/tinymce/plugins/insertdatetime/langs/en.js
includes/clientside/tinymce/plugins/insertdatetime/readme.txt
includes/clientside/tinymce/plugins/layer/editor_plugin.js
includes/clientside/tinymce/plugins/layer/editor_plugin_src.js
includes/clientside/tinymce/plugins/layer/images/absolute.gif
includes/clientside/tinymce/plugins/layer/images/backward.gif
includes/clientside/tinymce/plugins/layer/images/forward.gif
includes/clientside/tinymce/plugins/layer/images/insert_layer.gif
includes/clientside/tinymce/plugins/layer/images/insertlayer.gif
includes/clientside/tinymce/plugins/layer/images/movebackward.gif
includes/clientside/tinymce/plugins/layer/images/moveforward.gif
includes/clientside/tinymce/plugins/layer/langs/en.js
includes/clientside/tinymce/plugins/layer/readme.txt
includes/clientside/tinymce/plugins/media/css/content.css
includes/clientside/tinymce/plugins/media/css/media.css
includes/clientside/tinymce/plugins/media/editor_plugin.js
includes/clientside/tinymce/plugins/media/editor_plugin_src.js
includes/clientside/tinymce/plugins/media/images/flash.gif
includes/clientside/tinymce/plugins/media/images/media.gif
includes/clientside/tinymce/plugins/media/images/quicktime.gif
includes/clientside/tinymce/plugins/media/images/realmedia.gif
includes/clientside/tinymce/plugins/media/images/shockwave.gif
includes/clientside/tinymce/plugins/media/images/windowsmedia.gif
includes/clientside/tinymce/plugins/media/jscripts/embed.js
includes/clientside/tinymce/plugins/media/jscripts/media.js
includes/clientside/tinymce/plugins/media/langs/en.js
includes/clientside/tinymce/plugins/media/media.htm
includes/clientside/tinymce/plugins/nonbreaking/editor_plugin.js
includes/clientside/tinymce/plugins/nonbreaking/editor_plugin_src.js
includes/clientside/tinymce/plugins/nonbreaking/images/nonbreaking.gif
includes/clientside/tinymce/plugins/nonbreaking/langs/en.js
includes/clientside/tinymce/plugins/noneditable/css/noneditable.css
includes/clientside/tinymce/plugins/noneditable/editor_plugin.js
includes/clientside/tinymce/plugins/noneditable/editor_plugin_src.js
includes/clientside/tinymce/plugins/noneditable/readme.txt
includes/clientside/tinymce/plugins/paste/blank.htm
includes/clientside/tinymce/plugins/paste/css/blank.css
includes/clientside/tinymce/plugins/paste/css/pasteword.css
includes/clientside/tinymce/plugins/paste/editor_plugin.js
includes/clientside/tinymce/plugins/paste/editor_plugin_src.js
includes/clientside/tinymce/plugins/paste/images/pastetext.gif
includes/clientside/tinymce/plugins/paste/images/pasteword.gif
includes/clientside/tinymce/plugins/paste/images/selectall.gif
includes/clientside/tinymce/plugins/paste/jscripts/pastetext.js
includes/clientside/tinymce/plugins/paste/jscripts/pasteword.js
includes/clientside/tinymce/plugins/paste/langs/en.js
includes/clientside/tinymce/plugins/paste/pastetext.htm
includes/clientside/tinymce/plugins/paste/pasteword.htm
includes/clientside/tinymce/plugins/paste/readme.txt
includes/clientside/tinymce/plugins/preview/editor_plugin.js
includes/clientside/tinymce/plugins/preview/editor_plugin_src.js
includes/clientside/tinymce/plugins/preview/example.html
includes/clientside/tinymce/plugins/preview/images/preview.gif
includes/clientside/tinymce/plugins/preview/jscripts/embed.js
includes/clientside/tinymce/plugins/preview/langs/en.js
includes/clientside/tinymce/plugins/preview/readme.txt
includes/clientside/tinymce/plugins/print/editor_plugin.js
includes/clientside/tinymce/plugins/print/editor_plugin_src.js
includes/clientside/tinymce/plugins/print/images/print.gif
includes/clientside/tinymce/plugins/print/langs/en.js
includes/clientside/tinymce/plugins/print/readme.txt
includes/clientside/tinymce/plugins/readme.txt
includes/clientside/tinymce/plugins/save/editor_plugin.js
includes/clientside/tinymce/plugins/save/editor_plugin_src.js
includes/clientside/tinymce/plugins/save/images/save.gif
includes/clientside/tinymce/plugins/save/langs/en.js
includes/clientside/tinymce/plugins/save/readme.txt
includes/clientside/tinymce/plugins/searchreplace/css/searchreplace.css
includes/clientside/tinymce/plugins/searchreplace/editor_plugin.js
includes/clientside/tinymce/plugins/searchreplace/editor_plugin_src.js
includes/clientside/tinymce/plugins/searchreplace/images/replace.gif
includes/clientside/tinymce/plugins/searchreplace/images/replace_all_button_bg.gif
includes/clientside/tinymce/plugins/searchreplace/images/replace_button_bg.gif
includes/clientside/tinymce/plugins/searchreplace/images/search.gif
includes/clientside/tinymce/plugins/searchreplace/jscripts/searchreplace.js
includes/clientside/tinymce/plugins/searchreplace/langs/en.js
includes/clientside/tinymce/plugins/searchreplace/readme.txt
includes/clientside/tinymce/plugins/searchreplace/searchreplace.htm
includes/clientside/tinymce/plugins/style/css/props.css
includes/clientside/tinymce/plugins/style/editor_plugin.js
includes/clientside/tinymce/plugins/style/editor_plugin_src.js
includes/clientside/tinymce/plugins/style/images/apply_button_bg.gif
includes/clientside/tinymce/plugins/style/images/style_info.gif
includes/clientside/tinymce/plugins/style/images/styleprops.gif
includes/clientside/tinymce/plugins/style/jscripts/props.js
includes/clientside/tinymce/plugins/style/langs/en.js
includes/clientside/tinymce/plugins/style/props.htm
includes/clientside/tinymce/plugins/style/readme.txt
includes/clientside/tinymce/plugins/table/cell.htm
includes/clientside/tinymce/plugins/table/css/cell.css
includes/clientside/tinymce/plugins/table/css/row.css
includes/clientside/tinymce/plugins/table/css/table.css
includes/clientside/tinymce/plugins/table/editor_plugin.js
includes/clientside/tinymce/plugins/table/editor_plugin_src.js
includes/clientside/tinymce/plugins/table/images/buttons.gif
includes/clientside/tinymce/plugins/table/images/table.gif
includes/clientside/tinymce/plugins/table/images/table_cell_props.gif
includes/clientside/tinymce/plugins/table/images/table_delete.gif
includes/clientside/tinymce/plugins/table/images/table_delete_col.gif
includes/clientside/tinymce/plugins/table/images/table_delete_row.gif
includes/clientside/tinymce/plugins/table/images/table_insert_col_after.gif
includes/clientside/tinymce/plugins/table/images/table_insert_col_before.gif
includes/clientside/tinymce/plugins/table/images/table_insert_row_after.gif
includes/clientside/tinymce/plugins/table/images/table_insert_row_before.gif
includes/clientside/tinymce/plugins/table/images/table_merge_cells.gif
includes/clientside/tinymce/plugins/table/images/table_row_props.gif
includes/clientside/tinymce/plugins/table/images/table_split_cells.gif
includes/clientside/tinymce/plugins/table/jscripts/cell.js
includes/clientside/tinymce/plugins/table/jscripts/merge_cells.js
includes/clientside/tinymce/plugins/table/jscripts/row.js
includes/clientside/tinymce/plugins/table/jscripts/table.js
includes/clientside/tinymce/plugins/table/langs/en.js
includes/clientside/tinymce/plugins/table/merge_cells.htm
includes/clientside/tinymce/plugins/table/readme.txt
includes/clientside/tinymce/plugins/table/row.htm
includes/clientside/tinymce/plugins/table/table.htm
includes/clientside/tinymce/plugins/template/blank.htm
includes/clientside/tinymce/plugins/template/css/template.css
includes/clientside/tinymce/plugins/template/editor_plugin.js
includes/clientside/tinymce/plugins/template/editor_plugin_src.js
includes/clientside/tinymce/plugins/template/images/template.gif
includes/clientside/tinymce/plugins/template/jscripts/template.js
includes/clientside/tinymce/plugins/template/langs/en.js
includes/clientside/tinymce/plugins/template/template.htm
includes/clientside/tinymce/plugins/visualchars/editor_plugin.js
includes/clientside/tinymce/plugins/visualchars/editor_plugin_src.js
includes/clientside/tinymce/plugins/visualchars/images/visualchars.gif
includes/clientside/tinymce/plugins/visualchars/langs/en.js
includes/clientside/tinymce/plugins/xhtmlxtras/abbr.htm
includes/clientside/tinymce/plugins/xhtmlxtras/acronym.htm
includes/clientside/tinymce/plugins/xhtmlxtras/attributes.htm
includes/clientside/tinymce/plugins/xhtmlxtras/cite.htm
includes/clientside/tinymce/plugins/xhtmlxtras/css/attributes.css
includes/clientside/tinymce/plugins/xhtmlxtras/css/popup.css
includes/clientside/tinymce/plugins/xhtmlxtras/css/xhtmlxtras.css
includes/clientside/tinymce/plugins/xhtmlxtras/del.htm
includes/clientside/tinymce/plugins/xhtmlxtras/editor_plugin.js
includes/clientside/tinymce/plugins/xhtmlxtras/editor_plugin_src.js
includes/clientside/tinymce/plugins/xhtmlxtras/images/abbr.gif
includes/clientside/tinymce/plugins/xhtmlxtras/images/acronym.gif
includes/clientside/tinymce/plugins/xhtmlxtras/images/attribs.gif
includes/clientside/tinymce/plugins/xhtmlxtras/images/cite.gif
includes/clientside/tinymce/plugins/xhtmlxtras/images/date_time.gif
includes/clientside/tinymce/plugins/xhtmlxtras/images/del.gif
includes/clientside/tinymce/plugins/xhtmlxtras/images/ins.gif
includes/clientside/tinymce/plugins/xhtmlxtras/images/remove_button_bg.gif
includes/clientside/tinymce/plugins/xhtmlxtras/ins.htm
includes/clientside/tinymce/plugins/xhtmlxtras/jscripts/abbr.js
includes/clientside/tinymce/plugins/xhtmlxtras/jscripts/acronym.js
includes/clientside/tinymce/plugins/xhtmlxtras/jscripts/attributes.js
includes/clientside/tinymce/plugins/xhtmlxtras/jscripts/cite.js
includes/clientside/tinymce/plugins/xhtmlxtras/jscripts/del.js
includes/clientside/tinymce/plugins/xhtmlxtras/jscripts/element_common.js
includes/clientside/tinymce/plugins/xhtmlxtras/jscripts/ins.js
includes/clientside/tinymce/plugins/xhtmlxtras/langs/en.js
includes/clientside/tinymce/plugins/zoom/editor_plugin.js
includes/clientside/tinymce/plugins/zoom/editor_plugin_src.js
includes/clientside/tinymce/plugins/zoom/readme.txt
includes/clientside/tinymce/switcher.js
includes/clientside/tinymce/themes/advanced/about.htm
includes/clientside/tinymce/themes/advanced/anchor.htm
includes/clientside/tinymce/themes/advanced/charmap.htm
includes/clientside/tinymce/themes/advanced/color_picker.htm
includes/clientside/tinymce/themes/advanced/css/colorpicker.css
includes/clientside/tinymce/themes/advanced/css/editor_content.css
includes/clientside/tinymce/themes/advanced/css/editor_popup.css
includes/clientside/tinymce/themes/advanced/css/editor_ui.css
includes/clientside/tinymce/themes/advanced/docs/en/about.htm
includes/clientside/tinymce/themes/advanced/docs/en/common_buttons.htm
includes/clientside/tinymce/themes/advanced/docs/en/create_accessible_content.htm
includes/clientside/tinymce/themes/advanced/docs/en/images/insert_anchor_window.gif
includes/clientside/tinymce/themes/advanced/docs/en/images/insert_image_window.gif
includes/clientside/tinymce/themes/advanced/docs/en/images/insert_link_window.gif
includes/clientside/tinymce/themes/advanced/docs/en/images/insert_table_window.gif
includes/clientside/tinymce/themes/advanced/docs/en/index.htm
includes/clientside/tinymce/themes/advanced/docs/en/insert_anchor_button.htm
includes/clientside/tinymce/themes/advanced/docs/en/insert_image_button.htm
includes/clientside/tinymce/themes/advanced/docs/en/insert_link_button.htm
includes/clientside/tinymce/themes/advanced/docs/en/insert_table_button.htm
includes/clientside/tinymce/themes/advanced/docs/en/style.css
includes/clientside/tinymce/themes/advanced/editor_template.js
includes/clientside/tinymce/themes/advanced/editor_template_src.js
includes/clientside/tinymce/themes/advanced/image.htm
includes/clientside/tinymce/themes/advanced/images/anchor.gif
includes/clientside/tinymce/themes/advanced/images/anchor_symbol.gif
includes/clientside/tinymce/themes/advanced/images/backcolor.gif
includes/clientside/tinymce/themes/advanced/images/bold.gif
includes/clientside/tinymce/themes/advanced/images/bold_de_se.gif
includes/clientside/tinymce/themes/advanced/images/bold_es.gif
includes/clientside/tinymce/themes/advanced/images/bold_fr.gif
includes/clientside/tinymce/themes/advanced/images/bold_ru.gif
includes/clientside/tinymce/themes/advanced/images/bold_tw.gif
includes/clientside/tinymce/themes/advanced/images/browse.gif
includes/clientside/tinymce/themes/advanced/images/bullist.gif
includes/clientside/tinymce/themes/advanced/images/button_menu.gif
includes/clientside/tinymce/themes/advanced/images/buttons.gif
includes/clientside/tinymce/themes/advanced/images/cancel_button_bg.gif
includes/clientside/tinymce/themes/advanced/images/charmap.gif
includes/clientside/tinymce/themes/advanced/images/cleanup.gif
includes/clientside/tinymce/themes/advanced/images/close.gif
includes/clientside/tinymce/themes/advanced/images/code.gif
includes/clientside/tinymce/themes/advanced/images/color.gif
includes/clientside/tinymce/themes/advanced/images/colors.jpg
includes/clientside/tinymce/themes/advanced/images/copy.gif
includes/clientside/tinymce/themes/advanced/images/custom_1.gif
includes/clientside/tinymce/themes/advanced/images/cut.gif
includes/clientside/tinymce/themes/advanced/images/forecolor.gif
includes/clientside/tinymce/themes/advanced/images/help.gif
includes/clientside/tinymce/themes/advanced/images/hr.gif
includes/clientside/tinymce/themes/advanced/images/image.gif
includes/clientside/tinymce/themes/advanced/images/indent.gif
includes/clientside/tinymce/themes/advanced/images/insert_button_bg.gif
includes/clientside/tinymce/themes/advanced/images/italic.gif
includes/clientside/tinymce/themes/advanced/images/italic_de_se.gif
includes/clientside/tinymce/themes/advanced/images/italic_es.gif
includes/clientside/tinymce/themes/advanced/images/italic_ru.gif
includes/clientside/tinymce/themes/advanced/images/italic_tw.gif
includes/clientside/tinymce/themes/advanced/images/justifycenter.gif
includes/clientside/tinymce/themes/advanced/images/justifyfull.gif
includes/clientside/tinymce/themes/advanced/images/justifyleft.gif
includes/clientside/tinymce/themes/advanced/images/justifyright.gif
includes/clientside/tinymce/themes/advanced/images/link.gif
includes/clientside/tinymce/themes/advanced/images/menu_check.gif
includes/clientside/tinymce/themes/advanced/images/newdocument.gif
includes/clientside/tinymce/themes/advanced/images/numlist.gif
includes/clientside/tinymce/themes/advanced/images/opacity.png
includes/clientside/tinymce/themes/advanced/images/outdent.gif
includes/clientside/tinymce/themes/advanced/images/paste.gif
includes/clientside/tinymce/themes/advanced/images/redo.gif
includes/clientside/tinymce/themes/advanced/images/removeformat.gif
includes/clientside/tinymce/themes/advanced/images/separator.gif
includes/clientside/tinymce/themes/advanced/images/spacer.gif
includes/clientside/tinymce/themes/advanced/images/statusbar_resize.gif
includes/clientside/tinymce/themes/advanced/images/strikethrough.gif
includes/clientside/tinymce/themes/advanced/images/sub.gif
includes/clientside/tinymce/themes/advanced/images/sup.gif
includes/clientside/tinymce/themes/advanced/images/underline.gif
includes/clientside/tinymce/themes/advanced/images/underline_es.gif
includes/clientside/tinymce/themes/advanced/images/underline_fr.gif
includes/clientside/tinymce/themes/advanced/images/underline_ru.gif
includes/clientside/tinymce/themes/advanced/images/underline_tw.gif
includes/clientside/tinymce/themes/advanced/images/undo.gif
includes/clientside/tinymce/themes/advanced/images/unlink.gif
includes/clientside/tinymce/themes/advanced/images/visualaid.gif
includes/clientside/tinymce/themes/advanced/images/xp/tab_bg.gif
includes/clientside/tinymce/themes/advanced/images/xp/tab_end.gif
includes/clientside/tinymce/themes/advanced/images/xp/tab_sel_bg.gif
includes/clientside/tinymce/themes/advanced/images/xp/tab_sel_end.gif
includes/clientside/tinymce/themes/advanced/images/xp/tabs_bg.gif
includes/clientside/tinymce/themes/advanced/jscripts/about.js
includes/clientside/tinymce/themes/advanced/jscripts/anchor.js
includes/clientside/tinymce/themes/advanced/jscripts/charmap.js
includes/clientside/tinymce/themes/advanced/jscripts/color_picker.js
includes/clientside/tinymce/themes/advanced/jscripts/image.js
includes/clientside/tinymce/themes/advanced/jscripts/link.js
includes/clientside/tinymce/themes/advanced/jscripts/source_editor.js
includes/clientside/tinymce/themes/advanced/langs/en.js
includes/clientside/tinymce/themes/advanced/link.htm
includes/clientside/tinymce/themes/advanced/source_editor.htm
includes/clientside/tinymce/themes/simple/css/editor_content.css
includes/clientside/tinymce/themes/simple/css/editor_popup.css
includes/clientside/tinymce/themes/simple/css/editor_ui.css
includes/clientside/tinymce/themes/simple/editor_template.js
includes/clientside/tinymce/themes/simple/editor_template_src.js
includes/clientside/tinymce/themes/simple/images/bold.gif
includes/clientside/tinymce/themes/simple/images/bold_de_se.gif
includes/clientside/tinymce/themes/simple/images/bold_fr.gif
includes/clientside/tinymce/themes/simple/images/bold_ru.gif
includes/clientside/tinymce/themes/simple/images/bold_tw.gif
includes/clientside/tinymce/themes/simple/images/bullist.gif
includes/clientside/tinymce/themes/simple/images/buttons.gif
includes/clientside/tinymce/themes/simple/images/cleanup.gif
includes/clientside/tinymce/themes/simple/images/italic.gif
includes/clientside/tinymce/themes/simple/images/italic_de_se.gif
includes/clientside/tinymce/themes/simple/images/italic_ru.gif
includes/clientside/tinymce/themes/simple/images/italic_tw.gif
includes/clientside/tinymce/themes/simple/images/numlist.gif
includes/clientside/tinymce/themes/simple/images/redo.gif
includes/clientside/tinymce/themes/simple/images/separator.gif
includes/clientside/tinymce/themes/simple/images/spacer.gif
includes/clientside/tinymce/themes/simple/images/strikethrough.gif
includes/clientside/tinymce/themes/simple/images/underline.gif
includes/clientside/tinymce/themes/simple/images/underline_fr.gif
includes/clientside/tinymce/themes/simple/images/underline_ru.gif
includes/clientside/tinymce/themes/simple/images/underline_tw.gif
includes/clientside/tinymce/themes/simple/images/undo.gif
includes/clientside/tinymce/tiny_mce.js
includes/clientside/tinymce/tiny_mce_popup.js
includes/clientside/tinymce/tiny_mce_src.js
includes/clientside/tinymce/utils/editable_selects.js
includes/clientside/tinymce/utils/form_utils.js
includes/clientside/tinymce/utils/mclayer.js
includes/clientside/tinymce/utils/mctabs.js
includes/clientside/tinymce/utils/validate.js
includes/comment.php
includes/common.php
includes/common.php~
includes/constants.php
includes/dbal.php
includes/debugger/debugConsole.class.php
includes/debugger/debugConsole.config.php
includes/debugger/debugConsole.functions.php
includes/debugger/debugConsole.php
includes/diff.php
includes/diffengine/Engine/native.php
includes/diffengine/Engine/string.php
includes/diffengine/Engine/xdiff.php
includes/diffengine/Renderer.php
includes/diffengine/Renderer/inline.php
includes/diffengine/Renderer/unified.php
includes/diffengine/Renderer/xhtml.php
includes/email.php
includes/functions.php
includes/functions.php~
includes/graphs.php
includes/index.php
includes/js-compressor.php
includes/json.php
includes/magic.mime.mgc
includes/pageprocess.php
includes/pageprocess.php~
includes/pageutils.php
includes/pageutils.php~
includes/paths.php
includes/paths.php~
includes/plugins.php
includes/render.php
includes/render.php~
includes/rijndael.php
includes/search.php
includes/sessions.php
includes/sessions.php~
includes/stats.php
includes/template.php
includes/template.php~
includes/wikiengine/Default.php
includes/wikiengine/Mediawiki.php
includes/wikiengine/Parse.php
includes/wikiengine/Parse/Default/Anchor.php
includes/wikiengine/Parse/Default/Blockquote.php
includes/wikiengine/Parse/Default/Bold.php
includes/wikiengine/Parse/Default/Break.php
includes/wikiengine/Parse/Default/Center.php
includes/wikiengine/Parse/Default/Code.php
includes/wikiengine/Parse/Default/Colortext.php
includes/wikiengine/Parse/Default/Deflist.php
includes/wikiengine/Parse/Default/Delimiter.php
includes/wikiengine/Parse/Default/Embed.php
includes/wikiengine/Parse/Default/Emphasis.php
includes/wikiengine/Parse/Default/Freelink.php
includes/wikiengine/Parse/Default/Function.php
includes/wikiengine/Parse/Default/Heading.php
includes/wikiengine/Parse/Default/Horiz.php
includes/wikiengine/Parse/Default/Html.php
includes/wikiengine/Parse/Default/Image.php
includes/wikiengine/Parse/Default/Include.php
includes/wikiengine/Parse/Default/Interwiki.php
includes/wikiengine/Parse/Default/Italic.php
includes/wikiengine/Parse/Default/List.php
includes/wikiengine/Parse/Default/Newline.php
includes/wikiengine/Parse/Default/Paragraph.php
includes/wikiengine/Parse/Default/Phplookup.php
includes/wikiengine/Parse/Default/Prefilter.php
includes/wikiengine/Parse/Default/Raw.php
includes/wikiengine/Parse/Default/Revise.php
includes/wikiengine/Parse/Default/Smiley.php
includes/wikiengine/Parse/Default/Strong.php
includes/wikiengine/Parse/Default/Subscript.php
includes/wikiengine/Parse/Default/Superscript.php
includes/wikiengine/Parse/Default/Table.php
includes/wikiengine/Parse/Default/Tighten.php
includes/wikiengine/Parse/Default/Toc.php
includes/wikiengine/Parse/Default/Tt.php
includes/wikiengine/Parse/Default/Underline.php
includes/wikiengine/Parse/Default/Url.php
includes/wikiengine/Parse/Default/Wikilink.php
includes/wikiengine/Parse/Mediawiki/Anchor.php
includes/wikiengine/Parse/Mediawiki/Blockquote.php
includes/wikiengine/Parse/Mediawiki/Bold.php
includes/wikiengine/Parse/Mediawiki/Break.php
includes/wikiengine/Parse/Mediawiki/Center.php
includes/wikiengine/Parse/Mediawiki/Code.php
includes/wikiengine/Parse/Mediawiki/Colortext.php
includes/wikiengine/Parse/Mediawiki/Deflist.php
includes/wikiengine/Parse/Mediawiki/Delimiter.php
includes/wikiengine/Parse/Mediawiki/Embed.php
includes/wikiengine/Parse/Mediawiki/Emphasis.php
includes/wikiengine/Parse/Mediawiki/Freelink.php
includes/wikiengine/Parse/Mediawiki/Function.php
includes/wikiengine/Parse/Mediawiki/Heading.php
includes/wikiengine/Parse/Mediawiki/Horiz.php
includes/wikiengine/Parse/Mediawiki/Html.php
includes/wikiengine/Parse/Mediawiki/Image.php
includes/wikiengine/Parse/Mediawiki/Include.php
includes/wikiengine/Parse/Mediawiki/Interwiki.php
includes/wikiengine/Parse/Mediawiki/Italic.php
includes/wikiengine/Parse/Mediawiki/List.php
includes/wikiengine/Parse/Mediawiki/Newline.php
includes/wikiengine/Parse/Mediawiki/Paragraph.php
includes/wikiengine/Parse/Mediawiki/Phplookup.php
includes/wikiengine/Parse/Mediawiki/Prefilter.php
includes/wikiengine/Parse/Mediawiki/Raw.php
includes/wikiengine/Parse/Mediawiki/Revise.php
includes/wikiengine/Parse/Mediawiki/Smiley.php
includes/wikiengine/Parse/Mediawiki/Strong.php
includes/wikiengine/Parse/Mediawiki/Subscript.php
includes/wikiengine/Parse/Mediawiki/Superscript.php
includes/wikiengine/Parse/Mediawiki/Table.php
includes/wikiengine/Parse/Mediawiki/Tighten.php
includes/wikiengine/Parse/Mediawiki/Toc.php
includes/wikiengine/Parse/Mediawiki/Tt.php
includes/wikiengine/Parse/Mediawiki/Underline.php
includes/wikiengine/Parse/Mediawiki/Url.php
includes/wikiengine/Parse/Mediawiki/Wikilink.php
includes/wikiengine/Render.php
includes/wikiengine/Render/Plain.php
includes/wikiengine/Render/Plain/Anchor.php
includes/wikiengine/Render/Plain/Blockquote.php
includes/wikiengine/Render/Plain/Bold.php
includes/wikiengine/Render/Plain/Box.php
includes/wikiengine/Render/Plain/Break.php
includes/wikiengine/Render/Plain/Center.php
includes/wikiengine/Render/Plain/Code.php
includes/wikiengine/Render/Plain/Colortext.php
includes/wikiengine/Render/Plain/Deflist.php
includes/wikiengine/Render/Plain/Delimiter.php
includes/wikiengine/Render/Plain/Embed.php
includes/wikiengine/Render/Plain/Emphasis.php
includes/wikiengine/Render/Plain/Font.php
includes/wikiengine/Render/Plain/Freelink.php
includes/wikiengine/Render/Plain/Function.php
includes/wikiengine/Render/Plain/Heading.php
includes/wikiengine/Render/Plain/Horiz.php
includes/wikiengine/Render/Plain/Html.php
includes/wikiengine/Render/Plain/Image.php
includes/wikiengine/Render/Plain/Include.php
includes/wikiengine/Render/Plain/Interwiki.php
includes/wikiengine/Render/Plain/Italic.php
includes/wikiengine/Render/Plain/List.php
includes/wikiengine/Render/Plain/Newline.php
includes/wikiengine/Render/Plain/Page.php
includes/wikiengine/Render/Plain/Paragraph.php
includes/wikiengine/Render/Plain/Phplookup.php
includes/wikiengine/Render/Plain/Plugin.php
includes/wikiengine/Render/Plain/Prefilter.php
includes/wikiengine/Render/Plain/Preformatted.php
includes/wikiengine/Render/Plain/Raw.php
includes/wikiengine/Render/Plain/Revise.php
includes/wikiengine/Render/Plain/Smiley.php
includes/wikiengine/Render/Plain/Specialchar.php
includes/wikiengine/Render/Plain/Strong.php
includes/wikiengine/Render/Plain/Subscript.php
includes/wikiengine/Render/Plain/Superscript.php
includes/wikiengine/Render/Plain/Table.php
includes/wikiengine/Render/Plain/Tighten.php
includes/wikiengine/Render/Plain/Titlebar.php
includes/wikiengine/Render/Plain/Toc.php
includes/wikiengine/Render/Plain/Tt.php
includes/wikiengine/Render/Plain/Underline.php
includes/wikiengine/Render/Plain/Url.php
includes/wikiengine/Render/Plain/Wikilink.php
includes/wikiengine/Render/Xhtml.php
includes/wikiengine/Render/Xhtml/Anchor.php
includes/wikiengine/Render/Xhtml/Blockquote.php
includes/wikiengine/Render/Xhtml/Bold.php
includes/wikiengine/Render/Xhtml/Box.php
includes/wikiengine/Render/Xhtml/Break.php
includes/wikiengine/Render/Xhtml/Center.php
includes/wikiengine/Render/Xhtml/Code.php
includes/wikiengine/Render/Xhtml/Colortext.php
includes/wikiengine/Render/Xhtml/Deflist.php
includes/wikiengine/Render/Xhtml/Delimiter.php
includes/wikiengine/Render/Xhtml/Embed.php
includes/wikiengine/Render/Xhtml/Emphasis.php
includes/wikiengine/Render/Xhtml/Font.php
includes/wikiengine/Render/Xhtml/Freelink.php
includes/wikiengine/Render/Xhtml/Function.php
includes/wikiengine/Render/Xhtml/Heading.php
includes/wikiengine/Render/Xhtml/Horiz.php
includes/wikiengine/Render/Xhtml/Html.php
includes/wikiengine/Render/Xhtml/Image.php
includes/wikiengine/Render/Xhtml/Include.php
includes/wikiengine/Render/Xhtml/Interwiki.php
includes/wikiengine/Render/Xhtml/Italic.php
includes/wikiengine/Render/Xhtml/List.php
includes/wikiengine/Render/Xhtml/Newline.php
includes/wikiengine/Render/Xhtml/Page.php
includes/wikiengine/Render/Xhtml/Paragraph.php
includes/wikiengine/Render/Xhtml/Phplookup.php
includes/wikiengine/Render/Xhtml/Plugin.php
includes/wikiengine/Render/Xhtml/Prefilter.php
includes/wikiengine/Render/Xhtml/Preformatted.php
includes/wikiengine/Render/Xhtml/Raw.php
includes/wikiengine/Render/Xhtml/Revise.php
includes/wikiengine/Render/Xhtml/Smiley.php
includes/wikiengine/Render/Xhtml/Specialchar.php
includes/wikiengine/Render/Xhtml/Strong.php
includes/wikiengine/Render/Xhtml/Subscript.php
includes/wikiengine/Render/Xhtml/Superscript.php
includes/wikiengine/Render/Xhtml/Table.php
includes/wikiengine/Render/Xhtml/Tighten.php
includes/wikiengine/Render/Xhtml/Titlebar.php
includes/wikiengine/Render/Xhtml/Toc.php
includes/wikiengine/Render/Xhtml/Tt.php
includes/wikiengine/Render/Xhtml/Underline.php
includes/wikiengine/Render/Xhtml/Url.php
includes/wikiengine/Render/Xhtml/Wikilink.php
includes/wikiengine/Tables.php
includes/wikiformat.php
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/captcha.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,747 @@
+<?php
+/*
+ * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
+ * Version 1.0 (Banshee)
+ * Copyright (C) 2006-2007 Dan Fuhry
+ * captcha.php - visual confirmation system used during registration
+ *
+ * This program is Free Software; you can redistribute 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 details.
+ *
+ * This file contains code written by Paul Sohier (www.paulscripts.nl). The CAPTCHA code was ported from the phpBB Better
+ * Captcha mod, and has been released under the GPLv2 by the original author.
+ *
+ * This file contains code written by the phpBB team (www.phpbb.com). phpBB is licensed under the GPLv2.
+ */
+ 
+class captcha
+{
+  var $chars, $confirm_id, $compat, $code, $captcha_config;
+  function __construct($code)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    // Check if GD exists, otherwise we will use the fallback phpBB confirm image
+    $this->compat = false;
+    if(!extension_loaded("gd")){
+      $this->compat = true;
+    }
+    if(!function_exists("gd_info") || !function_exists('imagettftext')){
+      $this->compat = true;
+    }
+    $this->code = $code;
+    
+    $hex = Array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F');
+    $latticecolor = '#';
+    for($i=0;$i<6;$i++) $latticecolor .= $hex[mt_rand(0, 15)];
+    
+    $this->captcha_config = array (
+      'width' => '350',
+      'height' => '90',
+      'background_color' => '#E5ECF9',
+      'jpeg' => '0',
+      'jpeg_quality' => '95',
+      'pre_letters' => '1',
+      'pre_letters_great' => '0',
+      'font' => '1',
+      'chess' => '2',
+      'ellipses' => '2',
+      'arcs' => '2',
+      'lines' => '2',
+      'image' => '0',
+      'gammacorrect' => '0.8',
+      'foreground_lattice_x' => (string)mt_rand(25, 30),
+      'foreground_lattice_y' => (string)mt_rand(25, 30),
+      'lattice_color' => $latticecolor,
+    );
+  }
+  function captcha($code)
+  {
+    $this->__construct($code);    
+  }
+  function dss_rand()
+  {
+    global $db;
+    
+    $val = microtime() .  mt_rand();
+    $val = md5($val . 'a');
+    return substr($val, 4, 16);
+  }
+  
+  function make_image()
+  {
+    $code=$this->code;
+    if($this->compat)
+    {
+      // We can we will generate a single filtered png 
+      // Thanks to DavidMJ for emulating zlib within the code :)
+      $_png = $this->define_filtered_pngs();
+      
+      $total_width = 320;
+      $total_height = 50;
+      $img_height = 40;
+      $img_width = 0;
+      $l = 0;
+      
+      list($usec, $sec) = explode(' ', microtime()); 
+      mt_srand($sec * $usec); 
+      
+      $char_widths = array();
+      for ($i = 0; $i < strlen($code); $i++)
+      {
+        $char = $code{$i};
+      
+        $width = mt_rand(0, 4);
+        $char_widths[] = $width;
+        $img_width += $_png[$char]['width'] - $width;
+      }
+      
+      $offset_x = mt_rand(0, $total_width - $img_width);
+      $offset_y = mt_rand(0, $total_height - $img_height);
+      
+      $image = '';
+      $hold_chars = array();
+      for ($i = 0; $i < $total_height; $i++)
+      {
+        $image .= chr(0);
+      
+        if ($i > $offset_y && $i < $offset_y + $img_height)
+        {
+          $j = 0;
+      
+          for ($k = 0; $k < $offset_x; $k++)
+          {
+            $image .= chr(mt_rand(140, 255));
+          }
+      
+          for ($k = 0; $k < strlen($code); $k++)
+          {
+            $char = $code{$k};
+      
+            if (empty($hold_chars[$char]))
+            {
+              $hold_chars[$char] = explode("\n", chunk_split(base64_decode($_png[$char]['data']), $_png[$char]['width'] + 1, "\n"));
+            }
+            $image .= $this->randomise(substr($hold_chars[$char][$l], 1), $char_widths[$j]);
+            $j++;
+          }
+      
+          for ($k = $offset_x + $img_width; $k < $total_width; $k++)
+          {
+            $image .= chr(mt_rand(140, 255));
+          }
+      
+          $l++;
+        }
+        else
+        {
+          for ($k = 0; $k < $total_width; $k++)
+          {
+            $image .= chr(mt_rand(140, 255));
+          }
+        }
+      
+      }
+      unset($hold);
+      
+      $image = $this->create_png($image, $total_width, $total_height);
+  
+      // Output image
+      header('Content-Type: image/png');
+      header('Cache-control: no-cache, no-store');
+      echo $image;
+      
+      unset($image);
+      unset($_png);
+    } elseif(defined('ENANO_CAPTCHA_BIGNFAT')) {
+      // Prefs
+      $total_width = $this->captcha_config['width'];
+      $total_height = $this->captcha_config['height'];
+      
+      $hex_bg_color = $this->get_rgb($this->captcha_config['background_color']);
+      $bg_color = array();
+      $bg_color = explode(",", $hex_bg_color);
+      
+      $jpeg = $this->captcha_config['jpeg'];
+      $img_quality = $this->captcha_config['jpeg_quality'];
+      // Max quality is 95
+      
+      $pre_letters = $this->captcha_config['pre_letters'];
+      $pre_letter_great = $this->captcha_config['pre_letters_great'];
+      $rnd_font = $this->captcha_config['font'];
+      $chess = $this->captcha_config['chess'];
+      $ellipses = $this->captcha_config['ellipses'];
+      $arcs = $this->captcha_config['arcs'];
+      $lines = $this->captcha_config['lines'];
+      $image = $this->captcha_config['image'];
+      
+      $gammacorrect = $this->captcha_config['gammacorrect'];
+      
+      $foreground_lattice_y = $this->captcha_config['foreground_lattice_y'];
+      $foreground_lattice_x = $this->captcha_config['foreground_lattice_x'];
+      $hex_lattice_color = $this->get_rgb($this->captcha_config['lattice_color']);
+      $rgb_lattice_color = array();
+      $rgb_lattice_color = explode(",", $hex_lattice_color);
+      
+      $font_debug = false;
+      
+      // Fonts and images init
+      if ($image)
+      {
+        $bg_imgs = array();
+        if ($img_dir = opendir(ENANO_ROOT.'/includes/captcha/pics/'))
+        {
+          while (true == ($file = @readdir($img_dir))) 
+          { 
+            if ((substr(strtolower($file), -3) == 'jpg') || (substr(strtolower($file), -3) == 'gif'))    
+            {         
+              $bg_imgs[] = $file; 
+            }     
+          }
+          closedir($img_dir);
+        }
+        // Grab a random Background Image or set FALSE if none was found
+        $bg_img = ( count($bg_imgs) ) ? rand(0, (count($bg_imgs)-1)) : false;
+      }
+      
+      $fonts = array();
+      if ($fonts_dir = opendir(ENANO_ROOT.'/includes/captcha/fonts/'))
+      {
+        while (true == ($file = @readdir($fonts_dir))) 
+        { 
+          if ((substr(strtolower($file), strlen($file)-3, strlen($file)) == 'ttf'))
+          {         
+            $fonts[] = $file; 
+          }     
+        }
+        closedir($fonts_dir);
+      } else {
+        die('Error reading directory: '.ENANO_ROOT.'/includes/captcha/fonts/');
+      }
+      $font = rand(0, (count($fonts)-1));
+      
+      // Generate
+      $image = ($this->gdVersion() >= 2) ? imagecreatetruecolor($total_width, $total_height) : imagecreate($total_width, $total_height);
+      $background_color = imagecolorallocate($image, $bg_color[0], $bg_color[1], $bg_color[2]);
+      imagefill($image, 0, 0, $background_color);
+      
+      // Generate backgrund
+      if ($chess == '1' || $chess == '2' && rand(0,1))
+      {
+        // Draw rectangles
+        for($i = 0; $i <= 8; $i++)
+        {
+          $rectanglecolor = imagecolorallocate($image, rand(100,200),rand(100,200),rand(100,200));
+          imagefilledrectangle($image, 0, 0, round($total_width-($total_width/8*$i)), round($total_height), $rectanglecolor);
+          $rectanglecolor = imagecolorallocate($image, rand(100,200),rand(100,200),rand(100,200));
+          imagefilledrectangle($image, 0, 0, round($total_width-($total_width/8*$i)), round($total_height/2), $rectanglecolor);
+        }
+      }
+      if ($ellipses == '1' || $ellipses == '2' && rand(0,1))
+      {
+        // Draw random ellipses
+        for ($i = 1; $i <= 60; $i++)
+        {
+          $ellipsecolor = imagecolorallocate($image, rand(100,250),rand(100,250),rand(100,250));
+          imagefilledellipse($image, round(rand(0, $total_width)), round(rand(0, $total_height)), round(rand(0, $total_width/8)), round(rand(0, $total_height/4)), $ellipsecolor);	
+        }
+      }
+      if ($arcs == '1' || $arcs == '2' && rand(0,1))
+      {
+        // Draw random partial ellipses
+        for ($i = 0; $i <= 30; $i++)
+        {
+          $linecolor = imagecolorallocate($image, rand(120,255),rand(120,255),rand(120,255));
+          $cx = round(rand(1, $total_width));
+          $cy = round(rand(1, $total_height));
+          $int_w = round(rand(1, $total_width/2));
+          $int_h = round(rand(1, $total_height));
+          imagearc($image, $cx, $cy, $int_w, $int_h, round(rand(0, 190)), round(rand(191, 360)), $linecolor);
+          imagearc($image, $cx-1, $cy-1, $int_w, $int_h, round(rand(0, 190)), round(rand(191, 360)), $linecolor);
+        }
+      }
+      if ($lines == '1' || $lines == '2' && rand(0,1))
+      {
+        // Draw random lines
+        for ($i = 0; $i <= 50; $i++)
+        {
+          $linecolor = imagecolorallocate($image, rand(120,255),rand(120,255),rand(120,255));
+          imageline($image, round(rand(1, $total_width*3)), round(rand(1, $total_height*5)), round(rand(1, $total_width/2)), round(rand(1, $total_height*2)), $linecolor);
+        }
+      }
+      
+      $text_color_array = array('255,51,0', '51,77,255', '204,51,102', '0,153,0', '255,166,2', '255,0,255', '255,0,0', '0,255,0', '0,0,255', '0,255,255');
+      shuffle($text_color_array);
+      $pre_text_color_array = array('255,71,20', '71,20,224', '224,71,122', '20,173,20', '255,186,22', '25,25,25');
+      shuffle($pre_text_color_array);
+      $white = imagecolorallocate($image, 255, 255, 255);
+      $gray = imagecolorallocate($image, 100, 100, 100);
+      $black = imagecolorallocate($image, 0, 0, 0);
+      $lattice_color = imagecolorallocate($image, $rgb_lattice_color[0], $rgb_lattice_color[1], $rgb_lattice_color[2]);
+      
+      $x_char_position = (round(($total_width - 12) / strlen($code)) + mt_rand(-3, 5));
+      
+      for ($i = 0; $i < strlen($code); $i++)
+      {
+        mt_srand((double)microtime()*1000000);
+      
+        $char = $code{$i};
+        $size = mt_rand(floor($total_height / 3.5), ceil($total_height / 2.8));
+        $font = ($rnd_font) ? rand(0, (count($fonts)-1)) : $font;
+        $angle = mt_rand(-30, 30);
+      
+        $char_pos = array();
+        $char_pos = imagettfbbox($size, $angle, ENANO_ROOT.'/includes/captcha/fonts/'.$fonts[$font], $char);
+        $letter_width = abs($char_pos[0]) + abs($char_pos[4]);
+        $letter_height = abs($char_pos[1]) + abs($char_pos[5]);
+      
+        $x_pos = ($x_char_position / 4) + ($i * $x_char_position);
+        ($i == strlen($code)-1 && $x_pos >= ($total_width - ($letter_width + 5))) ? $x_pos = ($total_width - ($letter_width + 5)) : '';
+        $y_pos = mt_rand(($size * 1.4 ), $total_height - ($size * 0.4));
+      
+      //	Pre letters
+        $size = ($pre_letter_great) ? $size + (2 * $pre_letters) : $size - (2 * $pre_letters);
+        for ($count = 1; $count <= $pre_letters; $count++)
+        {
+          $pre_angle = $angle + mt_rand(-20, 20);
+      
+          $text_color = $pre_text_color_array[mt_rand(0,count($pre_text_color_array)-1)];
+          $text_color = explode(",", $text_color);
+          $textcolor = imagecolorallocate($image, $text_color[0], $text_color[1], $text_color[2]);
+      
+          imagettftext($image, $size, $pre_angle, $x_pos, $y_pos-2, $white, ENANO_ROOT.'/includes/captcha/fonts/'.$fonts[$font], $char);
+          imagettftext($image, $size, $pre_angle, $x_pos+2, $y_pos, $black, ENANO_ROOT.'/includes/captcha/fonts/'.$fonts[$font], $char);
+          imagettftext($image, $size, $pre_angle, $x_pos+1, $y_pos-1, $textcolor, ENANO_ROOT.'/includes/captcha/fonts/'.$fonts[$font], $char);
+      
+          $size = ($pre_letter_great) ? $size - 2 : $size + 2;
+        }
+      
+      //	Final letters
+        $text_color = $text_color_array[mt_rand(0,count($text_color_array)-1)];
+        $text_color = explode(",", $text_color);
+        $textcolor = imagecolorallocate($image, $text_color[0], $text_color[1], $text_color[2]);
+      
+        imagettftext($image, $size, $angle, $x_pos, $y_pos-2, $white, ENANO_ROOT.'/includes/captcha/fonts/'.$fonts[$font], $char);
+        imagettftext($image, $size, $angle, $x_pos+2, $y_pos, $black, ENANO_ROOT.'/includes/captcha/fonts/'.$fonts[$font], $char);
+        imagettftext($image, $size, $angle, $x_pos+1, $y_pos-1, $textcolor, ENANO_ROOT.'/includes/captcha/fonts/'.$fonts[$font], $char);
+      }
+      
+      
+      ($gammacorrect) ? imagegammacorrect($image, 1.0, $gammacorrect) : '';
+      
+      // Generate a white lattice in foreground
+      if ($foreground_lattice_y)
+      {
+        // x lines
+        $ih = round($total_height / $foreground_lattice_y);
+        for ($i = 0; $i <= $ih; $i++)
+        {
+          imageline($image, 0, $i*$foreground_lattice_y, $total_width, $i*$foreground_lattice_y, $lattice_color);
+        }
+      }
+      if ($foreground_lattice_x)
+      {
+        // y lines
+        $iw = round($total_width / $foreground_lattice_x);
+        for ($i = 0; $i <= $iw; $i++)
+        {
+          imageline($image, $i*$foreground_lattice_x, 0, $i*$foreground_lattice_x, $total_height, $lattice_color);
+        }
+      }
+      
+      // Font debug
+      if ($font_debug && !$rnd_font)
+      {
+        imagestring($image, 5, 2, 0, $fonts[$font], $white);
+        imagestring($image, 5, 5, 0, $fonts[$font], $white);
+        imagestring($image, 5, 4, 2, $fonts[$font], $gray);
+        imagestring($image, 5, 3, 1, $fonts[$font], $black);
+      }
+      
+      // Display
+      header("Last-Modified: " . gmdate("D, d M Y H:i:s") ." GMT"); 
+      header("Pragma: no-cache"); 
+      header("Cache-Control: no-store, no-cache, max-age=0, must-revalidate");
+      (!$jpeg) ? header("Content-Type: image/png") : header("Content-Type: image/jpeg");
+      
+      (!$jpeg) ? imagepng($image) : imagejpeg($image, '', $img_quality);
+      imagedestroy($image);
+    } else {
+      /**
+        * The next part is orginnaly written by ted from mastercode.nl and modified for use in Enano.
+        **/
+      header("content-type:image/png");
+      header('Cache-control: no-cache, no-store');
+      $breedte = 320;
+      $hoogte = 60;
+      $img = imagecreatetruecolor($breedte,$hoogte);
+      $achtergrond = imagecolorallocate($img, $this->color("bg"), $this->color("bg"), $this->color("bg"));
+      
+      imagefilledrectangle($img, 0, 0, $breedte-1, $hoogte-1, $achtergrond);
+      for($g = 0;$g < 30; $g++)
+      {
+        $t = $this->dss_rand();
+        $t = $t[0];
+            
+        $ypos = rand(0,$hoogte);
+        $xpos = rand(0,$breedte);
+            
+        $kleur = imagecolorallocate($img, $this->color("bgtekst"), $this->color("bgtekst"), $this->color("bgtekst"));
+            
+        imagettftext($img, $this->size(), $this->move(), $xpos, $ypos, $kleur, $this->font(), $t);
+      } 			
+      $stukje = $breedte / (strlen($code) + 3);
+      
+      for($j = 0;$j < strlen($code); $j++)
+      {
+        
+        
+        $tek = $code[$j];
+        $ypos = rand(33,43);
+        $xpos = $stukje * ($j+1);
+            
+        $kleur2 = imagecolorallocate($img, $this->color("tekst"), $this->color("tekst"), $this->color("tekst"));
+        
+        imagettftext($img, $this->size(), $this->move(), $xpos, $ypos, $kleur2, $this->font() , $tek);
+      }
+        
+      imagepng($img);
+    }
+  }
+  /**
+    * Some functions :)
+    * Also orginally written by mastercode.nl
+    **/
+  /**
+    * Function to create a random color
+    * @param $type string Mode for the color
+    * @return int
+    **/
+  function color($type)
+  {
+    switch($type)
+    {
+      case "bg": 
+        $kleur = rand(224,255); 
+      break;
+      case "tekst": 
+        $kleur = rand(0,127); 
+      break;
+      case "bgtekst": 
+        $kleur = rand(200,224); 
+      break;
+      default: 
+        $kleur = rand(0,255); 
+      break;
+    }
+    return $kleur;
+  }
+  /**
+    * Function to ranom the size
+    * @return int
+    **/
+  function size()
+  {
+    $grootte = rand(14,30);
+    return $grootte;
+  }
+  /**
+    * Function to random the posistion
+    * @return int
+    **/
+  function move()
+  {
+    $draai = rand(-25,25);
+    return $draai;
+  }
+  /**
+    * Function to return a ttf file from fonts map
+    * @return string
+    **/
+  function font()
+  {
+    $f = @opendir(ENANO_ROOT . '/includes/captcha/fonts/');
+    if(!$f) die('Can\'t open '.ENANO_ROOT.'/includes/captcha/fonts/ for reading');
+    $ar = array();
+    while(($file = @readdir($f)) !== false)
+    {
+      if(!in_array($file, array('.','..')) && strstr($file, '.ttf'))
+      {
+        $ar[] = $file;
+      }
+    }
+    if(count($ar))
+    {
+      shuffle($ar);
+      $i = rand(0,(count($ar) - 1));
+      return ENANO_ROOT . '/includes/captcha/fonts/' . $ar[$i];
+    }
+  }
+  
+  // This is designed to randomise the pixels of the image data within
+  // certain limits so as to keep it readable. It also varies the image
+  // width a little
+  function randomise($scanline, $width)
+  {
+    $new_line = '';
+    $start = floor($width/2);
+    $end = strlen($scanline) - ceil($width/2);
+  
+    for ($i = $start; $i < $end; $i++)
+    {
+      $pixel = ord($scanline{$i});
+  
+      if ($pixel < 190)
+      {
+        $new_line .= chr(mt_rand(0, 205));
+      }
+      else if ($pixel > 190)
+      {
+        $new_line .= chr(mt_rand(145, 255));
+      }
+      else
+      {
+        $new_line .= $scanline{$i};
+      }
+    }
+  
+    return $new_line;
+  }
+  
+  // This creates a chunk of the given type, with the given data
+  // of the given length adding the relevant crc
+  function png_chunk($length, $type, $data)
+  {
+    $raw = $type;
+    $raw .= $data;
+    $crc = crc32($raw);
+    $raw .= pack('C4', $crc >> 24, $crc >> 16, $crc >> 8, $crc);
+  
+    return pack('C4', $length >> 24, $length >> 16, $length >> 8, $length) . $raw;
+  }
+  
+  // Creates greyscale 8bit png - The PNG spec can be found at
+  // http://www.libpng.org/pub/png/spec/PNG-Contents.html we use
+  // png because it's a fully recognised open standard and supported
+  // by practically all modern browsers and OSs
+  function create_png($raw_image, $width, $height)
+  
+  {
+    // SIG
+    $image = pack('C8', 137, 80, 78, 71, 13, 10, 26, 10);
+    // IHDR
+    $raw = pack('C4', $width >> 24, $width >> 16, $width >> 8, $width);
+    $raw .= pack('C4', $height >> 24, $height >> 16, $height >> 8, $height);
+    $raw .= pack('C5', 8, 0, 0, 0, 0);
+    $image .= $this->png_chunk(13, 'IHDR', $raw);
+  
+    if (@extension_loaded('zlib'))
+    {
+      $raw_image = gzcompress($raw_image);
+      $length = strlen($raw_image);
+    }
+    else
+    {
+      // The total length of this image, uncompressed, is just a calculation of pixels
+      $length = ($width + 1) * $height;
+  
+      // Adler-32 hash generation
+      // Optimized Adler-32 loop ported from the GNU Classpath project
+      $temp_length = $length;
+      $s1 = 1;
+      $s2 = $index = 0;
+  
+      while ($temp_length > 0)
+      {
+        // We can defer the modulo operation:
+        // s1 maximally grows from 65521 to 65521 + 255 * 3800
+        // s2 maximally grows by 3800 * median(s1) = 2090079800 < 2^31
+        $substract_value = ($temp_length < 3800) ? $temp_length : 3800;
+        $temp_length -= $substract_value;
+  
+        while (--$substract_value >= 0)
+        {
+          $s1 += ord($raw_image[$index]);
+          $s2 += $s1;
+  
+          $index++;
+        }
+  
+        $s1 %= 65521;
+        $s2 %= 65521;
+      }
+      $adler_hash = pack('N', ($s2 << 16) | $s1);
+  
+      // This is the same thing as gzcompress($raw_image, 0) but does not need zlib
+      $raw_image = pack('C3v2', 0x78, 0x01, 0x01, $length, ~$length) . $raw_image . $adler_hash;
+  
+      // The Zlib header + Adler hash make us add on 11
+      $length += 11;
+    }
+  
+    // IDAT
+    $image .= $this->png_chunk($length, 'IDAT', $raw_image);
+  
+    // IEND
+    $image .= $this->png_chunk(0, 'IEND', '');
+  
+    return $image;
+  }
+  
+  // Each 'data' element is base64_encoded uncompressed IDAT
+  // png image data
+  function define_filtered_pngs()
+  {
+    $_png = array(
+      '0' => array('data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A///////////////////olFAkBAAAGDyA4P///M31/////////////wD////////////////0dAgAAAAAAAAAAAAEcPipFGHn////////////AP//////////////6DAAAAAAAAAAAAAAAAAALSEAN+T///////////8A//////////////xAAAAAAAAAAAAAAAAAAAAAACPA/////////////wD/////////////oAAAAAAAAAAAAAAAAAAAAAAAev//////////////AP////////////8oAAAAAAAAPNj/zDAAAAAAAABD//////////////8A////////////1AAAAAAAABjw////5BAAAAAAAADo/////////////wD///////////+QAAAAAAAAbP//////QgAAAAAAAKj/////////////AP///////////1wAAAAAAACs/////8AXAAAAAAAAcP////////////8A////////////OAAAAAAAAND////dNwAAAAAAAABI/////////////wD///////////8gAAAAAAAA4P//7koACwAAAAAAACT/////////////AP///////////wgAAAAAAAD///VqAwaPAAAAAAAAEP////////////8A////////////AAAAAAAAAP/8kQYDavUAAAAAAAAA/////////////wD///////////8AAAAAAAAA/6kNAEru/wAAAAAAAAD/////////////AP///////////wAAAAAAAADAIwA33f//AAAAAAAAAP////////////8A////////////FAAAAAAAADYAI8D///8AAAAAAAAQ/////////////wD///////////8kAAAAAAAAAA2p////5AAAAAAAACD/////////////AP///////////0gAAAAAAAAFkfz////UAAAAAAAAQP////////////8A////////////cAAAAAAAAET1/////7AAAAAAAABo/////////////wD///////////+oAAAAAAAAXfX/////sAAAAAAAAGj/////////////AAAAALgAAAAAAAAwAAAAAAAAAAAAAAD////////////oAAAAAAAACOT////oEAAAAAAAAOD/////////////AP////////////8+AAAAAAAAKMz/zDQAAAAAAAA0//////////////8A////////////7jgAAAAAAAAAAAAAAAAAAAAAAKT//////////////wD///////////VqAwIAAAAAAAAAAAAAAAAAAAA8////////////////AP//////////rQcDaVEAAAAAAAAAAAAAAAAAKOj///////////////8A///////////nblnu/IAIAAAAAAAAAAAAAFzw/////////////////wD////////////79////+iITCAAAAAgSITg////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////w==','width' => 40), 
+      '1' => array('data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////8BAAAAAAAP//////////////////AP////////////////////////9sAAAAAAAA//////////////////8A////////////////////////pAAAAAAAAAD//////////////////wD//////////////////////6wEAAAAAAAAAP//////////////////AP////////////////////h4AAAAAAAAAAAA//////////////////8A//////////////////ygJAAAAAAAAAAAAAD//////////////////wD//////////////9x8HAAAAAAAAAAAAAAAAP//////////////////AP//////////////AAAAAAAAAAAAAAAAAAAA//////////////////8A//////////////8AAAAAAAAAAAAAAAAAAAD//////////////////wD//////////////wAAAAAAAAR4AAAAAAAAAP//////////////////AP//////////////AAAAAAA4zP8AAAAAAAAA//////////////////8A//////////////8AAAA4sP///wAAAAAAAAD//////////////////wD//////////////yR80P//////AAAAAAAAAP//////////////////AP////////////////////////8AAAAAAAAA//////////////////8A/////////////////////////wAAAAAAAAD//////////////////wD/////////////////////////AAAAAAAAAP//////////////////AP////////////////////////8AAAAAAAAA//////////////////8A/////////////////////////wAAAAAAAAD//////////////////wD/////////////////////////AAAAAAAAAP//////////////////AP////////////////////////8AAAAAAAAA//////////////////8A/////////////////////////wAAAAAAAAD//////////////////wD/////////////////////////AAAAAAAAAP//////////////////AP////////////////////////8AAAAAAAAA//////////////////8A/////////////////////////wAAAAAAAAD//////////////////wD/////////////////////////AAAAAAAAAP//////////////////AP////////////////////////8AAAAAAAAA//////////////////8A/////////////////////////wAAAAAAAAD//////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=','width' => 40), 
+      '2' => array('data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP/////////////////okFAkCAAABCBIfNT///////////////////8A///////////////8hAgAAAAAAAAAAAAAAFTo/////////////////wD//////////////1QAAAAAAAAAAAAAAAAAACjo////////////////AP////////////+MAAAAAAAAAAAAAAAAAAAAADj///////////////8A////////////9BAAAAAAAAAAAAAAAAAAAAAAALD//////////////wD///////////+gAAAAAAAAAHjs+KwMAAAAAAAAVP//////////////AP///////////1gAAAAAAABM/////6QAAAAAAAAU//////////////8A////////////KAAAAAAAALj/////+AAAAAAAAAD//////////////wD///////////+MfGBMOCAI8P/////wAAAAAAAACP//////////////AP///////////////////////////5wAAAAAAAAw//////////////8A///////////////////////////oFAAAAAAAAHz//////////////wD/////////////////////////6CgAAAAAAAAE3P//////////////AP///////////////////////9ggAAAAAAAAAHT///////////////8A//////////////////////+0DAAAAAAAAAA8+P///////////////wD/////////////////////gAAAAAAAAAAAKOj/////////////////AP//////////////////9FAAAAAAAAAAADzw//////////////////8A/////////////////+g4AAAAAAAAAABk/P///////////////////wD////////////////oKAAAAAAAAAAMqP//////////////////////AP//////////////6CgAAAAAAAAAMNz///////////////////////8A//////////////g4AAAAAAAAAFT0/////////////////////////wD/////////////bAAAAAAAAABU/P//////////////////////////AP///////////8wAAAAAAAAAAAAAAAAAAAAAAAAA//////////////8A////////////SAAAAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////9wAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////AP//////////hAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////////8A//////////9AAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////xAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////AP////////////////////////////////////////////////////8=','width' => 40), 
+      '3' => array('data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD////////////////8sGg0FAAAACA4cLz8////////////////////AP//////////////rBgAAAAAAAAAAAAAACTA//////////////////8A/////////////3QAAAAAAAAAAAAAAAAAAASs/////////////////wD///////////+YAAAAAAAAAAAAAAAAAAAAAAjc////////////////AP//////////6AwAAAAAAAAAAAAAAAAAAAAAAGT///////////////8A//////////94AAAAAAAABJDw/8g4AAAAAAAAHP///////////////wD//////////yAAAAAAAACE/////9gAAAAAAAAA////////////////AP///////////NSwiGQ4FOT//////AAAAAAAABD///////////////8A//////////////////////////+YAAAAAAAAVP///////////////wD//////////////////////P/ggAQAAAAAAATM////////////////AP////////////////////9gAAAAAAAAAAAElP////////////////8A/////////////////////0AAAAAAAAAAHLj//////////////////wD/////////////////////OAAAAAAAAAAwkPj/////////////////AP////////////////////8gAAAAAAAAAAAAINj///////////////8A/////////////////////xAAAAAAAAAAAAAAIPD//////////////wD/////////////////////uOz/4HgEAAAAAAAAhP//////////////AP///////////////////////////3wAAAAAAAAw//////////////8A////////////////////////////6AAAAAAAAAj//////////////wD/////////////////////////////AAAAAAAAAP//////////////AP//////////tJh8YEQoDNz//////+AAAAAAAAAY//////////////8A//////////88AAAAAAAAaP//////dAAAAAAAAEz//////////////wD//////////6QAAAAAAAAAdOD/5HQAAAAAAAAApP//////////////AP///////////CgAAAAAAAAAAAAAAAAAAAAAACD4//////////////8A////////////yAQAAAAAAAAAAAAAAAAAAAAEuP///////////////wD/////////////rAQAAAAAAAAAAAAAAAAABJD/////////////////AP//////////////zDQAAAAAAAAAAAAAACTA//////////////////8A/////////////////8BwOCAAAAAUNGi0/P///////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=','width' => 40), 
+      '4' => array('data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP//////////////////////////nAAAAAAAAAD///////////////8A/////////////////////////8AEAAAAAAAAAP///////////////wD////////////////////////gGAAAAAAAAAAA////////////////AP//////////////////////9DAAAAAAAAAAAAD///////////////8A//////////////////////9UAAAAAAAAAAAAAP///////////////wD/////////////////////hAAAAAAAAAAAAAAA////////////////AP///////////////////7QAAAAAAAAAAAAAAAD///////////////8A///////////////////UDAAAAAAUAAAAAAAAAP///////////////wD/////////////////7CQAAAAABMAAAAAAAAAA////////////////AP////////////////xEAAAAAACU/wAAAAAAAAD///////////////8A////////////////cAAAAAAAZP//AAAAAAAAAP///////////////wD//////////////6AAAAAAADz8//8AAAAAAAAA////////////////AP/////////////IBAAAAAAc6P///wAAAAAAAAD///////////////8A////////////5BgAAAAADMz/////AAAAAAAAAP///////////////wD///////////g0AAAAAACk//////8AAAAAAAAA////////////////AP//////////XAAAAAAAfP///////wAAAAAAAAD///////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////8A////////////////////////////AAAAAAAAAP///////////////wD///////////////////////////8AAAAAAAAA////////////////AP///////////////////////////wAAAAAAAAD///////////////8A////////////////////////////AAAAAAAAAP///////////////wD///////////////////////////8AAAAAAAAA////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=','width' => 40), 
+      '5' => array('data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP//////////////8AAAAAAAAAAAAAAAAAAAAAAA//////////////8A///////////////MAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////////6wAAAAAAAAAAAAAAAAAAAAAAP//////////////AP//////////////iAAAAAAAAAAAAAAAAAAAAAAA//////////////8A//////////////9kAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////////0QAAAAAAAAAAAAAAAAAAAAAAP//////////////AP//////////////IAAAAAAAYP////////////////////////////8A//////////////wAAAAAAAB8/////////////////////////////wD/////////////3AAAAAAAAIj/////////////////////////////AP////////////+4AAAAAAAAoLRYHAAEKGTE//////////////////8A/////////////5QAAAAAAAAQAAAAAAAAAABY9P///////////////wD/////////////dAAAAAAAAAAAAAAAAAAAAAA89P//////////////AP////////////9QAAAAAAAAAAAAAAAAAAAAAABg//////////////8A/////////////zAAAAAAAAAAAAAAAAAAAAAAAADQ/////////////wD/////////////IAAAAAAAAGjY/+h4BAAAAAAAAGz/////////////AP//////////////9NS0lHSc//////90AAAAAAAALP////////////8A/////////////////////////////9QAAAAAAAAE/////////////wD//////////////////////////////wAAAAAAAAD/////////////AP/////////////////////////////8AAAAAAAAEP////////////8A////////////pIRwWEAgDOD//////8wAAAAAAAA8/////////////wD///////////9EAAAAAAAAaP//////ZAAAAAAAAHz/////////////AP///////////6QAAAAAAAAAaOD/4GQAAAAAAAAE4P////////////8A/////////////CQAAAAAAAAAAAAAAAAAAAAAAGD//////////////wD/////////////yAQAAAAAAAAAAAAAAAAAAAAc7P//////////////AP//////////////rAwAAAAAAAAAAAAAAAAAGNj///////////////8A////////////////0EAAAAAAAAAAAAAAAFTo/////////////////wD//////////////////8h4QCAAAAAcQHzU////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=','width' => 40), 
+      '6' => array('data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD///////////////////+0ZCwMAAAUNGjI////////////////////AP/////////////////EMAAAAAAAAAAAAABM6P////////////////8A////////////////lAQAAAAAAAAAAAAAAAAo6P///////////////wD//////////////6wAAAAAAAAAAAAAAAAAAABI////////////////AP/////////////oEAAAAAAAAAAAAAAAAAAAAACw//////////////8A/////////////3AAAAAAAAAoxP/YPAAAAAAAAEj//////////////wD////////////4EAAAAAAACOD////YDCBAVGiAoP//////////////AP///////////7gAAAAAAABY//////////////////////////////8A////////////eAAAAAAAAJT//////////////////////////////wD///////////9MAAAAAAAAvP/IXBgABCx03P//////////////////AP///////////ygAAAAAAADcdAAAAAAAAAAEiP////////////////8A////////////FAAAAAAAAFAAAAAAAAAAAAAAcP///////////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAlP//////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAAAQ8P////////////8A////////////AAAAAAAAAABAyP/kZAAAAAAAAACQ/////////////wD///////////8MAAAAAAAALPj/////WAAAAAAAAET/////////////AP///////////yQAAAAAAACY///////MAAAAAAAAFP////////////8A////////////SAAAAAAAAMD///////wAAAAAAAAA/////////////wD///////////9wAAAAAAAAvP///////wAAAAAAAAD/////////////AP///////////7QAAAAAAACI///////UAAAAAAAAJP////////////8A////////////+AwAAAAAACDw/////2wAAAAAAABY/////////////wD/////////////cAAAAAAAADC8/Ox4AAAAAAAAAKj/////////////AP/////////////oEAAAAAAAAAAAAAAAAAAAAAAk/P////////////8A//////////////+oAAAAAAAAAAAAAAAAAAAABLj//////////////wD///////////////+QAAAAAAAAAAAAAAAAAACQ////////////////AP////////////////+0JAAAAAAAAAAAAAAkuP////////////////8A///////////////////8sGg0FAAADCxgqPz//////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=','width' => 40), 
+      '7' => array('data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAAAABP////////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAAAy4/////////////wD//////////////////////////+QUAAAAAAAEuP//////////////AP/////////////////////////8QAAAAAAAAKT///////////////8A/////////////////////////4wAAAAAAAB0/////////////////wD////////////////////////cCAAAAAAANPz/////////////////AP///////////////////////0QAAAAAAATY//////////////////8A//////////////////////+0AAAAAAAAeP///////////////////wD//////////////////////CQAAAAAABTw////////////////////AP////////////////////+gAAAAAAAAkP////////////////////8A/////////////////////ywAAAAAABDw/////////////////////wD///////////////////+4AAAAAAAAbP//////////////////////AP///////////////////1wAAAAAAADQ//////////////////////8A///////////////////4DAAAAAAAMP///////////////////////wD//////////////////7QAAAAAAAB8////////////////////////AP//////////////////aAAAAAAAAMj///////////////////////8A//////////////////8oAAAAAAAM/P///////////////////////wD/////////////////8AAAAAAAAET/////////////////////////AP////////////////+0AAAAAAAAcP////////////////////////8A/////////////////4wAAAAAAACY/////////////////////////wD/////////////////WAAAAAAAAMD/////////////////////////AP////////////////80AAAAAAAA4P////////////////////////8A/////////////////xAAAAAAAAD4/////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=','width' => 40), 
+      '8' => array('data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD////////////////////IdDQUAAAEIEiA1P//////////////////AP/////////////////gRAAAAAAAAAAAAAAAROD///////////////8A////////////////0BgAAAAAAAAAAAAAAAAAEMj//////////////wD///////////////AcAAAAAAAAAAAAAAAAAAAAHPD/////////////AP//////////////hAAAAAAAAAAAAAAAAAAAAAAAhP////////////8A//////////////8sAAAAAAAAKMz/zCgAAAAAAAAs/////////////wD//////////////wAAAAAAAADM////zAAAAAAAAAD/////////////AP//////////////BAAAAAAAAP//////AAAAAAAABP////////////8A//////////////8sAAAAAAAAzP///9QAAAAAAAAw/////////////wD//////////////3wAAAAAAAAoyP/YNAAAAAAAAIT/////////////AP//////////////7BgAAAAAAAAAAAAAAAAAAAAc8P////////////8A////////////////xBgAAAAAAAAAAAAAAAAAGNj//////////////wD/////////////////tAQAAAAAAAAAAAAAAACo////////////////AP///////////////HAAAAAAAAAAAAAAAAAAAAB8//////////////8A//////////////9gAAAAAAAAAAAAAAAAAAAAAAB8/////////////wD/////////////wAAAAAAAAABk4P/UWAAAAAAAAATQ////////////AP////////////9UAAAAAAAAaP//////XAAAAAAAAGT///////////8A/////////////xgAAAAAAADg///////cAAAAAAAAJP///////////wD/////////////AAAAAAAAAP////////8AAAAAAAAA////////////AP////////////8AAAAAAAAA4P//////3AAAAAAAAAT///////////8A/////////////ygAAAAAAABg//////9cAAAAAAAALP///////////wD/////////////ZAAAAAAAAABY1P/cXAAAAAAAAABw////////////AP/////////////QAAAAAAAAAAAAAAAAAAAAAAAABNz///////////8A//////////////9gAAAAAAAAAAAAAAAAAAAAAAB0/////////////wD///////////////Q8AAAAAAAAAAAAAAAAAAAAUPz/////////////AP////////////////x4CAAAAAAAAAAAAAAAEIT8//////////////8A///////////////////smFQwGAAAABg0ZKT0/////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=','width' => 40), 
+      '9' => array('data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD///////////////////ysYCwMAAAUNGiw/P//////////////////AP////////////////+4JAAAAAAAAAAAAAAkuP////////////////8A////////////////lAQAAAAAAAAAAAAAAAAAkP///////////////wD//////////////8AEAAAAAAAAAAAAAAAAAAAAqP//////////////AP/////////////8JAAAAAAAAAAAAAAAAAAAAAAQ7P////////////8A/////////////6wAAAAAAAAAfOz8vCwAAAAAAABw/////////////wD/////////////WAAAAAAAAHD/////7BgAAAAAAAz4////////////AP////////////8kAAAAAAAA1P//////hAAAAAAAALT///////////8A/////////////wAAAAAAAAD///////+4AAAAAAAAcP///////////wD/////////////AAAAAAAAAPz//////8AAAAAAAABI////////////AP////////////8UAAAAAAAAzP//////lAAAAAAAACT///////////8A/////////////0QAAAAAAABY//////gsAAAAAAAADP///////////wD/////////////kAAAAAAAAABw5P/IPAAAAAAAAAAA////////////AP/////////////wEAAAAAAAAAAAAAAAAAAAAAAAAAD///////////8A//////////////+UAAAAAAAAAAAAAAAAAAAAAAAAAP///////////wD///////////////9wAAAAAAAAAAAAAFAAAAAAAAAU////////////AP////////////////+IBAAAAAAAAABw3AAAAAAAACj///////////8A///////////////////cdCwEABhcxP+8AAAAAAAATP///////////wD//////////////////////////////5AAAAAAAAB4////////////AP//////////////////////////////UAAAAAAAALj///////////8A//////////////+kgGxUQCAM2P///+AIAAAAAAAQ+P///////////wD//////////////0gAAAAAAAA42P/EKAAAAAAAAHD/////////////AP//////////////sAAAAAAAAAAAAAAAAAAAAAAQ6P////////////8A////////////////TAAAAAAAAAAAAAAAAAAAAKz//////////////wD////////////////oKAAAAAAAAAAAAAAAAASU////////////////AP/////////////////sUAAAAAAAAAAAAAAwxP////////////////8A////////////////////yHA0FAAADCxktP///////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=','width' => 40), 
+      'A' => array('data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD//////////////////+QAAAAAAAAAAAAAAOT/////////////////AP//////////////////kAAAAAAAAAAAAAAAkP////////////////8A//////////////////88AAAAAAAAAAAAAAA8/////////////////wD/////////////////5AAAAAAAAAAAAAAAAADk////////////////AP////////////////+QAAAAAAAAAAAAAAAAAJD///////////////8A/////////////////zwAAAAAAAAAAAAAAAAAPP///////////////wD////////////////kAAAAAAAAAAgAAAAAAAAA5P//////////////AP///////////////5AAAAAAAAAAgAAAAAAAAACQ//////////////8A////////////////PAAAAAAAAAz8HAAAAAAAADz//////////////wD//////////////+QAAAAAAAAAWP9kAAAAAAAAANz/////////////AP//////////////kAAAAAAAAACk/7wAAAAAAAAAhP////////////8A//////////////88AAAAAAAABOz//BQAAAAAAAAw/////////////wD/////////////4AAAAAAAAAA8////ZAAAAAAAAADc////////////AP////////////+EAAAAAAAAAIj///+8AAAAAAAAAIT///////////8A/////////////zAAAAAAAAAA2P////wQAAAAAAAAMP///////////wD////////////cAAAAAAAAACT//////1wAAAAAAAAA3P//////////AP///////////4QAAAAAAAAAAAAAAAAAAAAAAAAAAACE//////////8A////////////MAAAAAAAAAAAAAAAAAAAAAAAAAAAADD//////////wD//////////9wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANz/////////AP//////////hAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAhP////////8A//////////8wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAw/////////wD/////////3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADc////////AP////////+EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIT///////8A/////////zAAAAAAAAAAhP///////////2QAAAAAAAAAMP///////wD////////cAAAAAAAAAADM////////////vAAAAAAAAAAA3P//////AP///////4QAAAAAAAAAHP/////////////4DAAAAAAAAACE//////8A////////MAAAAAAAAABk//////////////9cAAAAAAAAADD//////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=','width' => 40), 
+      'B' => array('data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAEDh83P///////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAEhP//////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAeP////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAxP///////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAABY////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAABT///////////8A//////////8AAAAAAAAAAP/////4zEwAAAAAAAAAAP///////////wD//////////wAAAAAAAAAA////////7AAAAAAAAAAQ////////////AP//////////AAAAAAAAAAD////////sAAAAAAAAAEj///////////8A//////////8AAAAAAAAAAP/////4zEQAAAAAAAAAtP///////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAFz/////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAiA/P////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAIjPj//////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAGKz/////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAJT///////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAABNz//////////wD//////////wAAAAAAAAAA///////sqCAAAAAAAAAAbP//////////AP//////////AAAAAAAAAAD/////////yAAAAAAAAAAs//////////8A//////////8AAAAAAAAAAP//////////AAAAAAAAAAT//////////wD//////////wAAAAAAAAAA/////////7wAAAAAAAAAAP//////////AP//////////AAAAAAAAAAD//////+ikGAAAAAAAAAAY//////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFT//////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsP//////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAADj///////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAc6P///////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAATOj/////////////AP//////////AAAAAAAAAAAAAAAAAAAEIEBkkNj///////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=','width' => 40), 
+      'C' => array('data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP//////////////////5JRULBAAAAgkTIDQ//////////////////8A////////////////1FAAAAAAAAAAAAAAAABAyP///////////////wD//////////////4gEAAAAAAAAAAAAAAAAAAAElP//////////////AP////////////9wAAAAAAAAAAAAAAAAAAAAAAAAlP////////////8A////////////kAAAAAAAAAAAAAAAAAAAAAAAAAAEyP///////////wD//////////9wIAAAAAAAAAAAAAAAAAAAAAAAAAAAw////////////AP//////////WAAAAAAAAAAAWMz/8JwQAAAAAAAAAACw//////////8A/////////+wEAAAAAAAAAID//////9QMAAAAAAAAAET//////////wD/////////nAAAAAAAAAAo/P///////3wAAAAABDBspP//////////AP////////9gAAAAAAAAAIz/////////3BxQjMT0//////////////8A/////////zQAAAAAAAAAzP///////////////////////////////wD/////////GAAAAAAAAADo////////////////////////////////AP////////8AAAAAAAAAAP////////////////////////////////8A/////////wAAAAAAAAAA/////////////////////////////////wD/////////AAAAAAAAAAD/////////////////////////////////AP////////8cAAAAAAAAAOj///////////////////////////////8A/////////zgAAAAAAAAA0P/////////kIGio7P///////////////wD/////////bAAAAAAAAACg/////////5wAAAAAMHS49P//////////AP////////+oAAAAAAAAAEz/////////PAAAAAAAAAAc//////////8A//////////QIAAAAAAAAALz//////6QAAAAAAAAAAGT//////////wD//////////3AAAAAAAAAADIzo/+SEBAAAAAAAAAAAyP//////////AP//////////7BAAAAAAAAAAAAAAAAAAAAAAAAAAAED///////////8A////////////rAAAAAAAAAAAAAAAAAAAAAAAAAAE0P///////////wD/////////////fAAAAAAAAAAAAAAAAAAAAAAAAJz/////////////AP//////////////iAQAAAAAAAAAAAAAAAAAAASY//////////////8A////////////////yEAAAAAAAAAAAAAAAAA8yP///////////////wD//////////////////9yIUCwQAAAAIEB4yP//////////////////AP////////////////////////////////////////////////////8=','width' => 40), 
+      'D' => array('data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD///////////8AAAAAAAAAAAAAAAAADChQkOT/////////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAABGjw//////////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAACDY/////////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAABjk////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAED///////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAKj//////////wD///////////8AAAAAAAAAAP///+isSAAAAAAAAAAANP//////////AP///////////wAAAAAAAAAA////////hAAAAAAAAAAA2P////////8A////////////AAAAAAAAAAD/////////MAAAAAAAAACQ/////////wD///////////8AAAAAAAAAAP////////+MAAAAAAAAAFj/////////AP///////////wAAAAAAAAAA/////////8gAAAAAAAAAMP////////8A////////////AAAAAAAAAAD/////////5AAAAAAAAAAY/////////wD///////////8AAAAAAAAAAP//////////AAAAAAAAAAD/////////AP///////////wAAAAAAAAAA//////////8AAAAAAAAAAP////////8A////////////AAAAAAAAAAD//////////wAAAAAAAAAA/////////wD///////////8AAAAAAAAAAP/////////wAAAAAAAAABD/////////AP///////////wAAAAAAAAAA/////////9QAAAAAAAAAJP////////8A////////////AAAAAAAAAAD/////////qAAAAAAAAABI/////////wD///////////8AAAAAAAAAAP////////9QAAAAAAAAAHj/////////AP///////////wAAAAAAAAAA////////uAAAAAAAAAAAvP////////8A////////////AAAAAAAAAAD////w0HwEAAAAAAAAACT8/////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAoP//////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAAAAADz8//////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAY6P///////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAKNz/////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAACHT0//////////////8A////////////AAAAAAAAAAAAAAAAABg4bKj0/////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=','width' => 40), 
+      'E' => array('data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP//////////AAAAAAAAAAD///////////////////////////////8A//////////8AAAAAAAAAAP///////////////////////////////wD//////////wAAAAAAAAAA////////////////////////////////AP//////////AAAAAAAAAAD///////////////////////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////////8A//////////8AAAAAAAAAAP///////////////////////////////wD//////////wAAAAAAAAAA////////////////////////////////AP//////////AAAAAAAAAAD///////////////////////////////8A//////////8AAAAAAAAAAP///////////////////////////////wD//////////wAAAAAAAAAA////////////////////////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////////////////////////////////////////////////8=','width' => 40),
+      'F' => array('data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAA////////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAD///////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAP///////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAA////////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAD///////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAP///////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=','width' => 40), 
+      'G' => array('data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD//////////////////MB8TCgQAAAACCA4YJzs////////////////AP///////////////JQcAAAAAAAAAAAAAAAAAAhw8P////////////8A/////////////9gwAAAAAAAAAAAAAAAAAAAAAAAk2P///////////wD////////////EDAAAAAAAAAAAAAAAAAAAAAAAAAAc7P//////////AP//////////2AwAAAAAAAAAAAAAAAAAAAAAAAAAAABY//////////8A//////////wwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADQ/////////wD/////////kAAAAAAAAAAAEHzQ/P/gmCAAAAAAAAAAAFz/////////AP////////wcAAAAAAAAACjg////////8CwAAAAAAAAgWP////////8A////////vAAAAAAAAAAI2P//////////yBRAcJjI8P///////////wD///////94AAAAAAAAAGD/////////////////////////////////AP///////0AAAAAAAAAAsP////////////////////////////////8A////////IAAAAAAAAADc/////////////////////////////////wD///////8AAAAAAAAAAP///////wAAAAAAAAAAAAAAAAD/////////AP///////wAAAAAAAAAA////////AAAAAAAAAAAAAAAAAP////////8A////////AAAAAAAAAAD///////8AAAAAAAAAAAAAAAAA/////////wD///////8gAAAAAAAAAOD//////wAAAAAAAAAAAAAAAAD/////////AP///////0AAAAAAAAAAtP//////AAAAAAAAAAAAAAAAAP////////8A////////cAAAAAAAAABw//////8AAAAAAAAAAAAAAAAA/////////wD///////+8AAAAAAAAABDs////////////AAAAAAAAAAD/////////AP////////wYAAAAAAAAADz0//////////AAAAAAAAAAAP////////8A/////////5AAAAAAAAAAACCY4P//3KhcCAAAAAAAAAAA/////////wD/////////+CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////AP//////////xAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIP////////8A////////////rAQAAAAAAAAAAAAAAAAAAAAAAAAAAGTw/////////wD/////////////vBQAAAAAAAAAAAAAAAAAAAAAADjI////////////AP//////////////8HAQAAAAAAAAAAAAAAAAAEiw//////////////8A//////////////////iwcEAgBAAABCA4aKDk/////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=','width' => 40), 
+      'H' => array('data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=','width' => 40), 
+      'I' => array('data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAA////////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAD///////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAP///////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAA////////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAD///////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAP///////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAA////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAD///////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAP///////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAA////////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAD///////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAP///////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAA////////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAD///////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=','width' => 40),
+      'J' => array('data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP///////////////////////////wAAAAAAAAAA//////////////8A////////////////////////////AAAAAAAAAAD//////////////wD///////////////////////////8AAAAAAAAAAP//////////////AP///////////////////////////wAAAAAAAAAA//////////////8A////////////////////////////AAAAAAAAAAD//////////////wD///////////////////////////8AAAAAAAAAAP//////////////AP///////////////////////////wAAAAAAAAAA//////////////8A////////////////////////////AAAAAAAAAAD//////////////wD///////////////////////////8AAAAAAAAAAP//////////////AP///////////////////////////wAAAAAAAAAA//////////////8A////////////////////////////AAAAAAAAAAD//////////////wD///////////////////////////8AAAAAAAAAAP//////////////AP///////////////////////////wAAAAAAAAAA//////////////8A////////////////////////////AAAAAAAAAAD//////////////wD///////////////////////////8AAAAAAAAAAP//////////////AP///////////////////////////wAAAAAAAAAA//////////////8A////////////////////////////AAAAAAAAAAj//////////////wD//////////+zMrIxwUDAQ//////wAAAAAAAAAIP//////////////AP//////////DAAAAAAAAADo////2AAAAAAAAAA0//////////////8A//////////8wAAAAAAAAAKj///+YAAAAAAAAAFj//////////////wD//////////2gAAAAAAAAAIND/yBgAAAAAAAAAkP//////////////AP//////////vAAAAAAAAAAAAAAAAAAAAAAAAADc//////////////8A////////////MAAAAAAAAAAAAAAAAAAAAAAAUP///////////////wD////////////EBAAAAAAAAAAAAAAAAAAAABjk////////////////AP////////////+sBAAAAAAAAAAAAAAAAAAY2P////////////////8A///////////////EMAAAAAAAAAAAAAAAVOj//////////////////wD/////////////////vHBAIAAAABg8fNT/////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=','width' => 40),
+      'K' => array('data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD///////8AAAAAAAAAAP//////////wAQAAAAAAAAAAABw////////AP///////wAAAAAAAAAA/////////9AMAAAAAAAAAAAAcP////////8A////////AAAAAAAAAAD////////cGAAAAAAAAAAAAHD//////////wD///////8AAAAAAAAAAP//////6CgAAAAAAAAAAABs////////////AP///////wAAAAAAAAAA//////Q0AAAAAAAAAAAAVPz///////////8A////////AAAAAAAAAAD////8RAAAAAAAAAAAAFT8/////////////wD///////8AAAAAAAAAAP///1gAAAAAAAAAAABU/P//////////////AP///////wAAAAAAAAAA//9wAAAAAAAAAAAASPz///////////////8A////////AAAAAAAAAAD/jAAAAAAAAAAAADz0/////////////////wD///////8AAAAAAAAAAKQAAAAAAAAAAAA89P//////////////////AP///////wAAAAAAAAAABAAAAAAAAAAAFPT///////////////////8A////////AAAAAAAAAAAAAAAAAAAAAAAApP///////////////////wD///////8AAAAAAAAAAAAAAAAAAAAAAAAU8P//////////////////AP///////wAAAAAAAAAAAAAAAAAAAAAAAABk//////////////////8A////////AAAAAAAAAAAAAAAAAAAAAAAAAADE/////////////////wD///////8AAAAAAAAAAAAAAAAoEAAAAAAAACz8////////////////AP///////wAAAAAAAAAAAAAAGNiAAAAAAAAAAIj///////////////8A////////AAAAAAAAAAAAABjY//gYAAAAAAAACOD//////////////wD///////8AAAAAAAAAAAAY2P///5wAAAAAAAAASP//////////////AP///////wAAAAAAAAAAGNj//////CgAAAAAAAAAqP////////////8A////////AAAAAAAAAADI////////sAAAAAAAAAAc8P///////////wD///////8AAAAAAAAAAP//////////QAAAAAAAAABs////////////AP///////wAAAAAAAAAA///////////IAAAAAAAAAATI//////////8A////////AAAAAAAAAAD///////////9YAAAAAAAAADD8/////////wD///////8AAAAAAAAAAP///////////9wEAAAAAAAAAJD/////////AP///////wAAAAAAAAAA/////////////3AAAAAAAAAADOT///////8A////////AAAAAAAAAAD/////////////7BAAAAAAAAAAUP///////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=','width' => 40), 
+      'L' => array('data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAD/////////////////////////////AP////////////8AAAAAAAAAAP////////////////////////////8A/////////////wAAAAAAAAAA/////////////////////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A/////////////wAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD/////////////AAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=','width' => 40), 
+      'M' => array('data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A//////8AAAAAAAAAAAAAAHz//////3wAAAAAAAAAAAAAAP///////wD//////wAAAAAAAAAAAAAATP//////UAAAAAAAAAAAAAAA////////AP//////AAAAAAAAAAAAAAAc//////8cAAAAAAAAAAAAAAD///////8A//////8AAAAAAAAAAAAAAADw////8AAAAAAAAAAAAAAAAP///////wD//////wAAAAAAAAAAAAAAALz////AAAAAAAAAAAAAAAAA////////AP//////AAAAAAAAAAAAAAAAkP///5AAAAAAAAAAAAAAAAD///////8A//////8AAAAAAAAAAAAAAABc////ZAAAAAAAAAAAAAAAAP///////wD//////wAAAAAAAAAoAAAAADD///8wAAAAACQAAAAAAAAA////////AP//////AAAAAAAAAFwAAAAABPz//AgAAAAAXAAAAAAAAAD///////8A//////8AAAAAAAAAkAAAAAAA0P/UAAAAAACQAAAAAAAAAP///////wD//////wAAAAAAAADMAAAAAACg/6gAAAAAAMQAAAAAAAAA////////AP//////AAAAAAAAAPgEAAAAAHD/dAAAAAAE+AAAAAAAAAD///////8A//////8AAAAAAAAA/zQAAAAAQP9IAAAAADD/AAAAAAAAAP///////wD//////wAAAAAAAAD/bAAAAAAQ/xQAAAAAaP8AAAAAAAAA////////AP//////AAAAAAAAAP+gAAAAAADQAAAAAACc/wAAAAAAAAD///////8A//////8AAAAAAAAA/9QAAAAAAGgAAAAAAND/AAAAAAAAAP///////wD//////wAAAAAAAAD//wwAAAAAFAAAAAAM/P8AAAAAAAAA////////AP//////AAAAAAAAAP//RAAAAAAAAAAAADz//wAAAAAAAAD///////8A//////8AAAAAAAAA//94AAAAAAAAAAAAcP//AAAAAAAAAP///////wD//////wAAAAAAAAD//7AAAAAAAAAAAACo//8AAAAAAAAA////////AP//////AAAAAAAAAP//5AAAAAAAAAAAANz//wAAAAAAAAD///////8A//////8AAAAAAAAA////HAAAAAAAAAAQ////AAAAAAAAAP///////wD//////wAAAAAAAAD///9QAAAAAAAAAEz///8AAAAAAAAA////////AP//////AAAAAAAAAP///4gAAAAAAAAAfP///wAAAAAAAAD///////8A//////8AAAAAAAAA////vAAAAAAAAACw////AAAAAAAAAP///////wD//////wAAAAAAAAD////wAAAAAAAAAOz///8AAAAAAAAA////////AP//////AAAAAAAAAP////8sAAAAAAAc/////wAAAAAAAAD///////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=','width' => 40), 
+      'N' => array('data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////AAAAAAAAALD/////////////AAAAAAAAAP//////////AP////////8AAAAAAAAAFOj///////////8AAAAAAAAA//////////8A/////////wAAAAAAAAAASP///////////wAAAAAAAAD//////////wD/////////AAAAAAAAAAAAkP//////////AAAAAAAAAP//////////AP////////8AAAAAAAAAAAAI1P////////8AAAAAAAAA//////////8A/////////wAAAAAAAAAAAAAw+P///////wAAAAAAAAD//////////wD/////////AAAAAAAAAAAAAABw////////AAAAAAAAAP//////////AP////////8AAAAAAAAAAAAAAAC8//////8AAAAAAAAA//////////8A/////////wAAAAAAAAAAAAAAABzs/////wAAAAAAAAD//////////wD/////////AAAAAAAAAAAAAAAAAFD/////AAAAAAAAAP//////////AP////////8AAAAAAAAAAAAAAAAAAJz///8AAAAAAAAA//////////8A/////////wAAAAAAAAAUAAAAAAAADNz//wAAAAAAAAD//////////wD/////////AAAAAAAAALQAAAAAAAAANPz/AAAAAAAAAP//////////AP////////8AAAAAAAAA/2wAAAAAAAAAfP8AAAAAAAAA//////////8A/////////wAAAAAAAAD/+CwAAAAAAAAExAAAAAAAAAD//////////wD/////////AAAAAAAAAP//0AQAAAAAAAAgAAAAAAAAAP//////////AP////////8AAAAAAAAA////jAAAAAAAAAAAAAAAAAAA//////////8A/////////wAAAAAAAAD/////RAAAAAAAAAAAAAAAAAD//////////wD/////////AAAAAAAAAP/////kFAAAAAAAAAAAAAAAAP//////////AP////////8AAAAAAAAA//////+sAAAAAAAAAAAAAAAA//////////8A/////////wAAAAAAAAD///////9kAAAAAAAAAAAAAAD//////////wD/////////AAAAAAAAAP////////QkAAAAAAAAAAAAAP//////////AP////////8AAAAAAAAA/////////8wEAAAAAAAAAAAA//////////8A/////////wAAAAAAAAD//////////4QAAAAAAAAAAAD//////////wD/////////AAAAAAAAAP///////////DwAAAAAAAAAAP//////////AP////////8AAAAAAAAA////////////4BAAAAAAAAAA//////////8A/////////wAAAAAAAAD/////////////qAAAAAAAAAD//////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=','width' => 40), 
+      'O' => array('data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A///////////////////0qGw4HAAAABw4aKT0/////////////////wD////////////////wcAwAAAAAAAAAAAAAAAho6P//////////////AP//////////////uBQAAAAAAAAAAAAAAAAAAAAMoP////////////8A/////////////6AEAAAAAAAAAAAAAAAAAAAAAAAAkP///////////wD///////////+4BAAAAAAAAAAAAAAAAAAAAAAAAAAAoP//////////AP//////////8BQAAAAAAAAAAAAAAAAAAAAAAAAAAAAM5P////////8A//////////9wAAAAAAAAAAAsrPD/7KQsAAAAAAAAAABg/////////wD/////////+BAAAAAAAAAAUPj///////hQAAAAAAAAAAjs////////AP////////+sAAAAAAAAABDw//////////AYAAAAAAAAAKD///////8A/////////2wAAAAAAAAAdP///////////3wAAAAAAAAAYP///////wD/////////OAAAAAAAAAC4////////////xAAAAAAAAAAw////////AP////////8cAAAAAAAAAOD////////////oAAAAAAAAABT///////8A/////////wAAAAAAAAAA//////////////8AAAAAAAAAAP///////wD/////////AAAAAAAAAAD//////////////wAAAAAAAAAA////////AP////////8AAAAAAAAAAP/////////////8AAAAAAAAAAD///////8A/////////xwAAAAAAAAA5P///////////+AAAAAAAAAAHP///////wD/////////NAAAAAAAAAC8////////////uAAAAAAAAAA4////////AP////////9oAAAAAAAAAHj///////////98AAAAAAAAAGT///////8A/////////6gAAAAAAAAAGPD/////////+BgAAAAAAAAApP///////wD/////////9AwAAAAAAAAAUPz///////xcAAAAAAAAAAjs////////AP//////////cAAAAAAAAAAALKjs//CwOAAAAAAAAAAAYP////////8A///////////wFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzk/////////wD///////////+4BAAAAAAAAAAAAAAAAAAAAAAAAAAAoP//////////AP////////////+QAAAAAAAAAAAAAAAAAAAAAAAAAJD///////////8A//////////////+sEAAAAAAAAAAAAAAAAAAAAAyg/////////////wD////////////////oZAgAAAAAAAAAAAAAAARg4P//////////////AP//////////////////9KhsOCAAAAAUMFyc7P////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=','width' => 40), 
+      'P' => array('data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP///////////wAAAAAAAAAAAAAAAAAACCxguP////////////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAOOD//////////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAGOD/////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAAAARP////////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAxP///////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAAABo////////////AP///////////wAAAAAAAAAA////6JwMAAAAAAAAADD///////////8A////////////AAAAAAAAAAD//////6AAAAAAAAAADP///////////wD///////////8AAAAAAAAAAP//////9AAAAAAAAAAA////////////AP///////////wAAAAAAAAAA///////0AAAAAAAAAAD///////////8A////////////AAAAAAAAAAD//////5gAAAAAAAAAHP///////////wD///////////8AAAAAAAAAAP///9iICAAAAAAAAABI////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAJD///////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAI6P///////////wD///////////8AAAAAAAAAAAAAAAAAAAAAAAAAAIT/////////////AP///////////wAAAAAAAAAAAAAAAAAAAAAAAABU/P////////////8A////////////AAAAAAAAAAAAAAAAAAAAAAAIhPz//////////////wD///////////8AAAAAAAAAAAAAAAAABCRMkOz/////////////////AP///////////wAAAAAAAAAA//////////////////////////////8A////////////AAAAAAAAAAD//////////////////////////////wD///////////8AAAAAAAAAAP//////////////////////////////AP///////////wAAAAAAAAAA//////////////////////////////8A////////////AAAAAAAAAAD//////////////////////////////wD///////////8AAAAAAAAAAP//////////////////////////////AP///////////wAAAAAAAAAA//////////////////////////////8A////////////AAAAAAAAAAD//////////////////////////////wD///////////8AAAAAAAAAAP//////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=','width' => 40), 
+      'Q' => array('data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////SoaDQcAAAAHDhoqPT///////////////////8A//////////////BwDAAAAAAAAAAAAAAACHDo/////////////////wD///////////+4FAAAAAAAAAAAAAAAAAAAABCo////////////////AP//////////nAQAAAAAAAAAAAAAAAAAAAAAAACQ//////////////8A/////////7gEAAAAAAAAAAAAAAAAAAAAAAAAAACg/////////////wD////////wFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzo////////////AP///////3AAAAAAAAAAACyo8P/sqCwAAAAAAAAAAGT///////////8A///////4EAAAAAAAAABM+P///////FQAAAAAAAAACPT//////////wD//////7AAAAAAAAAAFPD/////////9BgAAAAAAAAApP//////////AP//////bAAAAAAAAAB4////////////fAAAAAAAAABk//////////8A//////84AAAAAAAAALz///////////+8AAAAAAAAADT//////////wD//////xwAAAAAAAAA6P///////////+QAAAAAAAAAHP//////////AP//////AAAAAAAAAAD//////////////wAAAAAAAAAA//////////8A//////8AAAAAAAAAAP//////////////AAAAAAAAAAD//////////wD//////wAAAAAAAAAA/P////////////8AAAAAAAAAAP//////////AP//////GAAAAAAAAADg////////////4AAAAAAAAAAc//////////8A//////84AAAAAAAAALT////MJHTo//+8AAAAAAAAADT//////////wD//////2wAAAAAAAAAdP///2AAABCg/3wAAAAAAAAAZP//////////AP//////rAAAAAAAAAAY9P/sCAAAAABMGAAAAAAAAACk//////////8A///////4EAAAAAAAAABU/P+0OAAAAAAAAAAAAAAACPT//////////wD///////94AAAAAAAAAAA4sPD/gAAAAAAAAAAAAABk////////////AP////////AcAAAAAAAAAAAAAAAAAAAAAAAAAAAADOT///////////8A/////////7wEAAAAAAAAAAAAAAAAAAAAAAAAAACQ/////////////wD//////////6wEAAAAAAAAAAAAAAAAAAAAAAAAABSs////////////AP///////////7gUAAAAAAAAAAAAAAAAAAAAAAAAAABAwP////////8A//////////////BwDAAAAAAAAAAAAAAABAgAAAAAAAA8/////////wD////////////////0qGg0GAAAABgwXJjkxBgAAAAAALD/////////AP//////////////////////////////////5DQAAAAk/P////////8A////////////////////////////////////+GwAAJD//////////wD//////////////////////////////////////8A49P//////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=','width' => 40), 
+      'R' => array('data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////wAAAAAAAAAAAAAAAAAAAAQgOGSk+P///////////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAcuP//////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAEsP////////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQ6P///////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB8////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAADD///////////8A/////////wAAAAAAAAAA///////svDgAAAAAAAAACP///////////wD/////////AAAAAAAAAAD/////////7AAAAAAAAAAA////////////AP////////8AAAAAAAAAAP/////////cAAAAAAAAABD///////////8A/////////wAAAAAAAAAA//////DQoCQAAAAAAAAAQP///////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAACU////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAIPj///////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAzU/////////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAA02P//////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAxctPz///////////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAEDY/////////////////wD/////////AAAAAAAAAAD/9LAsAAAAAAAAAAzc////////////////AP////////8AAAAAAAAAAP///+wkAAAAAAAAADD8//////////////8A/////////wAAAAAAAAAA/////8QAAAAAAAAAAJD//////////////wD/////////AAAAAAAAAAD//////1QAAAAAAAAAFPD/////////////AP////////8AAAAAAAAAAP//////3AQAAAAAAAAAgP////////////8A/////////wAAAAAAAAAA////////aAAAAAAAAAAM6P///////////wD/////////AAAAAAAAAAD////////oCAAAAAAAAABs////////////AP////////8AAAAAAAAAAP////////+AAAAAAAAAAATc//////////8A/////////wAAAAAAAAAA//////////AUAAAAAAAAAFj//////////wD/////////AAAAAAAAAAD//////////5AAAAAAAAAAAND/////////AP////////8AAAAAAAAAAP//////////+CQAAAAAAAAAQP////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=','width' => 40), 
+      'S' => array('data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP/////////////////8vHBEIAgAAAQgQHC8/P////////////////8A////////////////pCQAAAAAAAAAAAAAAAAcoP///////////////wD//////////////FwAAAAAAAAAAAAAAAAAAAAAXP//////////////AP////////////9oAAAAAAAAAAAAAAAAAAAAAAAAhP////////////8A////////////zAAAAAAAAAAAAAAAAAAAAAAAAAAI6P///////////wD///////////9cAAAAAAAAAAAAAAAAAAAAAAAAAACA////////////AP///////////xgAAAAAAAAAUOD/8KwkAAAAAAAAADj///////////8A////////////AAAAAAAAAAD0/////8wABCAgICxASP///////////wD///////////8MAAAAAAAAAMz/////////////////////////////AP///////////0AAAAAAAAAACFiQxPT///////////////////////8A////////////oAAAAAAAAAAAAAAAADBwtPT//////////////////wD////////////8QAAAAAAAAAAAAAAAAAAACFTA////////////////AP/////////////oOAAAAAAAAAAAAAAAAAAAAABM6P////////////8A///////////////4fAgAAAAAAAAAAAAAAAAAAAAY2P///////////wD/////////////////7IwwAAAAAAAAAAAAAAAAAAAo+P//////////AP/////////////////////koGw0BAAAAAAAAAAAAACU//////////8A///////////////////////////4uFgAAAAAAAAAADz//////////wD//////////2BgSEA0IBwA6P///////5QAAAAAAAAADP//////////AP//////////JAAAAAAAAACc/////////AAAAAAAAAAA//////////8A//////////9YAAAAAAAAACDo///////AAAAAAAAAABT//////////wD//////////6QAAAAAAAAAACCk7P/snBQAAAAAAAAAUP//////////AP//////////+BAAAAAAAAAAAAAAAAAAAAAAAAAAAACs//////////8A////////////kAAAAAAAAAAAAAAAAAAAAAAAAAAAOP///////////wD////////////8RAAAAAAAAAAAAAAAAAAAAAAAABjc////////////AP/////////////0PAAAAAAAAAAAAAAAAAAAAAAg2P////////////8A///////////////8hBQAAAAAAAAAAAAAAAAMdPT//////////////wD/////////////////+LRwSCAMAAAAHDhoqPT/////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=','width' => 40), 
+      'T' => array('data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD///////////////////8AAAAAAAAAAP//////////////////////AP///////////////////wAAAAAAAAAA//////////////////////8A////////////////////AAAAAAAAAAD//////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=','width' => 40), 
+      'U' => array('data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////AAAAAAAAAAD///////////8AAAAAAAAAAP//////////AP////////8AAAAAAAAAAP///////////wAAAAAAAAAA//////////8A/////////wAAAAAAAAAA////////////AAAAAAAAAAD//////////wD/////////JAAAAAAAAADk/////////+gAAAAAAAAAHP//////////AP////////9MAAAAAAAAAJz/////////nAAAAAAAAABE//////////8A/////////4gAAAAAAAAAHOj//////+ggAAAAAAAAAHz//////////wD/////////0AAAAAAAAAAAIJzs/+ykIAAAAAAAAAAA0P//////////AP//////////QAAAAAAAAAAAAAAAAAAAAAAAAAAAAED///////////8A///////////IBAAAAAAAAAAAAAAAAAAAAAAAAAAE0P///////////wD///////////+YAAAAAAAAAAAAAAAAAAAAAAAAAJj/////////////AP////////////+UBAAAAAAAAAAAAAAAAAAAAASU//////////////8A///////////////IPAAAAAAAAAAAAAAAAAAwyP///////////////wD/////////////////0IxYOCAIAAAEIEiAyP//////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=','width' => 40), 
+      'V' => array('data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD//////zAAAAAAAAAAYP//////////////ZAAAAAAAAAAw////////AP//////kAAAAAAAAAAU/P////////////8UAAAAAAAAAJD///////8A///////oBAAAAAAAAADE////////////xAAAAAAAAAAE7P///////wD///////9MAAAAAAAAAHD///////////94AAAAAAAAAEz/////////AP///////6gAAAAAAAAAJP///////////yQAAAAAAAAArP////////8A////////+BAAAAAAAAAA1P/////////YAAAAAAAAABT4/////////wD/////////aAAAAAAAAACE/////////4QAAAAAAAAAbP//////////AP/////////EAAAAAAAAADT/////////OAAAAAAAAADM//////////8A//////////8kAAAAAAAAAOT//////+QAAAAAAAAAKP///////////wD//////////4QAAAAAAAAAmP//////nAAAAAAAAACI////////////AP//////////5AAAAAAAAABE//////9EAAAAAAAABOT///////////8A////////////QAAAAAAAAAT0////9AgAAAAAAABI/////////////wD///////////+gAAAAAAAAAKT///+kAAAAAAAAAKj/////////////AP////////////QIAAAAAAAAXP///1wAAAAAAAAM+P////////////8A/////////////1wAAAAAAAAM+P/8DAAAAAAAAGT//////////////wD/////////////vAAAAAAAAAC8/7wAAAAAAAAAxP//////////////AP//////////////HAAAAAAAAGj/aAAAAAAAACT///////////////8A//////////////94AAAAAAAAHP8cAAAAAAAAhP///////////////wD//////////////9gAAAAAAAAAkAAAAAAAAADk////////////////AP///////////////zgAAAAAAAAQAAAAAAAAQP////////////////8A////////////////lAAAAAAAAAAAAAAAAACg/////////////////wD////////////////sCAAAAAAAAAAAAAAADPT/////////////////AP////////////////9QAAAAAAAAAAAAAABg//////////////////8A/////////////////7AAAAAAAAAAAAAAAMD//////////////////wD//////////////////BQAAAAAAAAAAAAc////////////////////AP//////////////////cAAAAAAAAAAAAHz///////////////////8A///////////////////MAAAAAAAAAAAA3P///////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=','width' => 40), 
+      'W' => array('data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A//8cAAAAAAAAALz/////4AAAAAAAAAAA6P////+8AAAAAAAAABz//wD//1QAAAAAAAAAjP////+gAAAAAAAAAACo/////4wAAAAAAAAAUP//AP//jAAAAAAAAABU/////2AAAAAAAAAAAGj/////VAAAAAAAAACM//8A///EAAAAAAAAACT/////IAAAAAAAAAAAKP////8kAAAAAAAAAMT//wD///gEAAAAAAAAAPD//+AAAAAAAAAAAAAA6P//8AAAAAAAAAAE9P//AP///zAAAAAAAAAAvP//oAAAAAAAAAAAAACo//+8AAAAAAAAADD///8A////bAAAAAAAAACM//9gAAAAAAAAAAAAAGT//4wAAAAAAAAAaP///wD///+kAAAAAAAAAFT//yAAAAAAAAAAAAAAIP//VAAAAAAAAACc////AP///9gAAAAAAAAAJP/gAAAAAAAAAAAAAAAA4P8kAAAAAAAAANT///8A/////xAAAAAAAAAA8KAAAAAAAAAAAAAAAACg8AAAAAAAAAAQ/////wD/////TAAAAAAAAAC8YAAAAAAAAAAAAAAAAGC8AAAAAAAAAET/////AP////+AAAAAAAAAAIwgAAAAAAAAAAAAAAAAIIwAAAAAAAAAfP////8A/////7gAAAAAAAAANAAAAAAAACwwAAAAAAAANAAAAAAAAACw/////wD/////8AAAAAAAAAAAAAAAAAAAdHgAAAAAAAAAAAAAAAAAAOz/////AP//////KAAAAAAAAAAAAAAAAAC4vAAAAAAAAAAAAAAAAAAg//////8A//////9gAAAAAAAAAAAAAAAACPj4CAAAAAAAAAAAAAAAAFj//////wD//////5QAAAAAAAAAAAAAAABE//9IAAAAAAAAAAAAAAAAkP//////AP//////0AAAAAAAAAAAAAAAAIj//4wAAAAAAAAAAAAAAADI//////8A///////8DAAAAAAAAAAAAAAAzP//1AAAAAAAAAAAAAAABPj//////wD///////88AAAAAAAAAAAAABT/////GAAAAAAAAAAAAAA0////////AP///////3QAAAAAAAAAAAAAWP////9gAAAAAAAAAAAAAHD///////8A////////sAAAAAAAAAAAAACg/////6QAAAAAAAAAAAAApP///////wD////////kAAAAAAAAAAAAAOT/////6AAAAAAAAAAAAADc////////AP////////8cAAAAAAAAAAAo////////MAAAAAAAAAAAEP////////8A/////////1QAAAAAAAAAAHD///////94AAAAAAAAAABM/////////wD/////////jAAAAAAAAAAAtP///////7wAAAAAAAAAAID/////////AP/////////EAAAAAAAAAAT0////////+AgAAAAAAAAAuP////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=','width' => 40), 
+      'X' => array('data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD///////9UAAAAAAAAAKz///////////+sAAAAAAAAAFD/////////AP///////+QQAAAAAAAAFOT/////////8BwAAAAAAAAM5P////////8A/////////5gAAAAAAAAATP////////9kAAAAAAAAAJD//////////wD//////////0AAAAAAAAAAoP//////wAAAAAAAAAA0/P//////////AP//////////2AgAAAAAAAAQ4P////gkAAAAAAAABMz///////////8A////////////iAAAAAAAAABA////dAAAAAAAAABw/////////////wD////////////8MAAAAAAAAACU/9AEAAAAAAAAHPD/////////////AP/////////////IBAAAAAAAAAzYMAAAAAAAAACs//////////////8A//////////////90AAAAAAAAABAAAAAAAAAATP///////////////wD///////////////QgAAAAAAAAAAAAAAAAAAzg////////////////AP///////////////7wAAAAAAAAAAAAAAAAAjP////////////////8A/////////////////2AAAAAAAAAAAAAAADD8/////////////////wD/////////////////7BQAAAAAAAAAAAAEyP//////////////////AP/////////////////gDAAAAAAAAAAAAAjY//////////////////8A/////////////////0AAAAAAAAAAAAAAADj8/////////////////wD///////////////+UAAAAAAAAAAAAAAAAAJD/////////////////AP//////////////4AwAAAAAAAAAAAAAAAAADOD///////////////8A//////////////9AAAAAAAAAAAAAAAAAAAAAQP///////////////wD/////////////nAAAAAAAAAAAWAAAAAAAAAAAlP//////////////AP///////////+QQAAAAAAAAAGD/YAAAAAAAAAAM4P////////////8A////////////TAAAAAAAAAAs9P/0LAAAAAAAAABM/////////////wD//////////6AAAAAAAAAADNT////UDAAAAAAAAACg////////////AP/////////kEAAAAAAAAACg//////+gAAAAAAAAABDk//////////8A/////////0wAAAAAAAAAYP////////9gAAAAAAAAAEz//////////wD///////+oAAAAAAAAACz0//////////QsAAAAAAAAAKT/////////AP//////7BQAAAAAAAAM1P///////////9QMAAAAAAAAFOz///////8A//////9UAAAAAAAAAKD//////////////6AAAAAAAAAAVP///////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=','width' => 40), 
+      'Y' => array('data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP///////1QAAAAAAAAAAGj//////////2gAAAAAAAAAAFT///////8A////////5BAAAAAAAAAAAMT////////EAAAAAAAAAAAQ5P///////wD/////////mAAAAAAAAAAAKPj/////+CgAAAAAAAAAAJj/////////AP//////////PAAAAAAAAAAAgP////+AAAAAAAAAAAA8//////////8A///////////YCAAAAAAAAAAE2P//2AQAAAAAAAAACNj//////////wD///////////+AAAAAAAAAAAA4//84AAAAAAAAAACA////////////AP////////////woAAAAAAAAAACUlAAAAAAAAAAAKPz///////////8A/////////////8gAAAAAAAAAABAQAAAAAAAAAADI/////////////wD//////////////2wAAAAAAAAAAAAAAAAAAAAAbP//////////////AP//////////////8BwAAAAAAAAAAAAAAAAAABzw//////////////8A////////////////tAAAAAAAAAAAAAAAAAAAtP///////////////wD/////////////////VAAAAAAAAAAAAAAAAFT/////////////////AP/////////////////oEAAAAAAAAAAAAAAQ6P////////////////8A//////////////////+cAAAAAAAAAAAAAJz//////////////////wD///////////////////9AAAAAAAAAAABA////////////////////AP///////////////////9gAAAAAAAAAANj///////////////////8A/////////////////////wAAAAAAAAAA/////////////////////wD/////////////////////AAAAAAAAAAD/////////////////////AP////////////////////8AAAAAAAAAAP////////////////////8A/////////////////////wAAAAAAAAAA/////////////////////wD/////////////////////AAAAAAAAAAD/////////////////////AP////////////////////8AAAAAAAAAAP////////////////////8A/////////////////////wAAAAAAAAAA/////////////////////wD/////////////////////AAAAAAAAAAD/////////////////////AP////////////////////8AAAAAAAAAAP////////////////////8A/////////////////////wAAAAAAAAAA/////////////////////wD/////////////////////AAAAAAAAAAD/////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=','width' => 40), 
+      'Z' => array('data' => 'AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////////8A//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////////wD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////AP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAQ//////////////8A/////////////////////////1AAAAAAAAAABLz//////////////wD///////////////////////98AAAAAAAAAACY////////////////AP//////////////////////pAAAAAAAAAAAaP////////////////8A/////////////////////8QIAAAAAAAAAET8/////////////////wD////////////////////gGAAAAAAAAAAo9P//////////////////AP//////////////////9CwAAAAAAAAAFNz///////////////////8A//////////////////xMAAAAAAAAAATA/////////////////////wD/////////////////eAAAAAAAAAAAnP//////////////////////AP///////////////5wAAAAAAAAAAHT///////////////////////8A///////////////ABAAAAAAAAABM/P///////////////////////wD/////////////3BQAAAAAAAAALPT/////////////////////////AP////////////QoAAAAAAAAABjg//////////////////////////8A///////////8SAAAAAAAAAAExP///////////////////////////wD//////////2wAAAAAAAAAAKD/////////////////////////////AP////////+YAAAAAAAAAAB8//////////////////////////////8A/////////wQAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A/////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////wD/////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8A/////////////////////////////////////////////////////wD/////////////////////////////////////////////////////AP////////////////////////////////////////////////////8=','width' => 40), 
+    );
+  
+    return $_png;
+  }
+  
+  // These define base64_encoded raw png image data used
+  // when we cannot generate our own single png image
+  function define_raw_pngs()
+  {
+    $_png = array(
+      '0' => 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAAAAACpleexAAAAFXRFWHRDcmVhdGlvbiBUaW1lAAfTBQ4QKCNGXKO6AAAAB3RJTUUH0wUOEDQ6EUG1VwAAAAlwSFlzAAALEgAACxIB0t1+/AAAAXNJREFUeNpj/M9AHGAiUt2wVvhyaqAqKyOjpG3jQwaGv+e+IUn9RwJfSjjg4iwFP1aKJD6HyyErfGGAYrquIoP5E2wK/zigu0v5wH9sChdgeKDqP1aFGhBZmxv/z0Dd4IxV4RWIpMQHIPuJAITzAqEQETx7IFQIP5CQNoJwDmALxzMQCuyjg1chnBPYwtECwr8AZN41h0p6YHOjAkTuwf//77wYuCEcFWwKOWA2fM1iZuuHcASwKYQ55c9ENuasrxgRjKlwJS+D17v/hBUeUGYwv/sfn0IRiJQZJIbxuFEFagjvSlDUQNgK2GIGqpC1JRhIfoAqxBYz0DRhn8IMJO+giKEqhMaMJBeI3AHhIKdkRPqG8DlAifqFADyasKRHO6h1Z/6fMYEwTbCmx3cWGCl8CTaFwBhGz+M2/7EpXMvOnBmIok7jBVaFz/Mi3/1pQORrhpgPyOr+M8IL0j9/gKpeLjhy5QEwoDVsYuRR3cE4IktcAJNx8cJaZBeQAAAAAElFTkSuQmCC', 
+      '1' => 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAAAAACpleexAAAAFXRFWHRDcmVhdGlvbiBUaW1lAAfTBQ4QMi//xxVKAAAAB3RJTUUH0wUOEDYLcqnX7wAAAAlwSFlzAAALEgAACxIB0t1+/AAAAHpJREFUeNpj/M9AHGAiUh1WhR8FGUGAsMKaD9iM/I8BlmCVwVS4hoUohT8qcNiFyv2zQIWBCIV3amRwu54RKcDRAgQ1KigIcJYK7CqR3QsCFmf+Y8qgeQakbANMAz6FKjUXECbj8zWa76nm61GFw1UhI10KqVGFNFQIADdK9Zj7PsV9AAAAAElFTkSuQmCC', 
+      '2' => 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAAAAACpleexAAAAFXRFWHRDcmVhdGlvbiBUaW1lAAfTBQ4QMwPUBEjoAAAAB3RJTUUH0wUOEDUqFe2UcgAAAAlwSFlzAAALEgAACxIB0t1+/AAAAQxJREFUeNpj/M9AHGAiUt2owkGrkAWF93LFgStPfjCwyGiYRGijqfyPAH9aOJAkQl78RwbICkNQjdB4gUNhD7qzLLAr/CKA4YENSAoRvl7zAUJXvPmxhgfCXILVMxEQvg+IDVUhgtVqDYjkDhD7B2aQIMIx5cOTN29evLAAsaEKObBajQzmQOQMcIQjHLwQgSisIaDwBdS5LHfwK7yhAHVVyX+8CrdAA5HB5gdehQ3Yoxpd4ZcAmDqbD//xKISEIjhU//zHoxDmXQaeFRhOZ8CmzuDOf3wKf8DsDfnyH6/CHJi6P//xKjyDJethVehBpMI7DPgVwrPCCgb8AK5wDwGFcNMF8EkCASOx1QcAGUxu1untnFIAAAAASUVORK5CYII=', 
+      '3' => 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAAAAACpleexAAAAFXRFWHRDcmVhdGlvbiBUaW1lAAfTBQ4QMxBQugk2AAAAB3RJTUUH0wUOEDU3duv4qwAAAAlwSFlzAAALEgAACxIB0t1+/AAAATdJREFUeNpj/M9AHGAiUt0IVciCzPm7ZceZB28YGBQkLHwcmNFU/keANRJI4ioH/qMAJIUlaHatwaFwBrqrOO5gVfiCB8P9KVgVVkAtnPDh/wkLCFsGq0IFiGQLiH0D06P/GWHJ7O+NOzfuXLlzQRrEhgSawHscwYPurxAcwQMBf/4/aIAYyHIGr8IEeDhO+Y9XoQNUncwOVHGMRPEDSovc+IkzrpGDCQgUbuC1WgBhhsIHfAp3vPn/oIIFKfRxKQSDGohCA4IKX0DTD7YoRAWMUJ9iyQpbn4DBBWUQ5yFEDDnFw622gXAzwBxoYvfB5sYlUI0lD/4/gWWKJdgU/tHAcKjCD6y+PsGCpo4FJbaRgmcNqkqWCThTzxkTJHXo+Ro1HA9uOPHiATDlKJj4eKCVFIzDqWgGAK7GW/haPS+zAAAAAElFTkSuQmCC', 
+      '4' => 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAAAAACpleexAAAAFXRFWHRDcmVhdGlvbiBUaW1lAAfTBQ4QMyqWttCEAAAAB3RJTUUH0wUOEDUxn4hdngAAAAlwSFlzAAALEgAACxIB0t1+/AAAAKBJREFUeNpj/M9AHGAiUh2FCucyQgCK4H9McIAFixwWhQ8kGIhS+MWAgTiFIQzEKWxhIE7hFgbiFF7hASkQIajwjQpInuUAIYV/XMDyU/4TUlgAlk75T0jhArCszR9CCk+AY07mxX8CCp+AY47nzH8CCn+YgOWW/CekMAYsVfMfl0JGmCBq4kNEDp2zAn0UMmItABjRvDykPTO43DgyFQIANP6pTFLWAdoAAAAASUVORK5CYII=', 
+      '5' => 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAAAAACpleexAAAAFXRFWHRDcmVhdGlvbiBUaW1lAAfTBQ4QMzPy3XhEAAAAB3RJTUUH0wUOEDUk8lW5dQAAAAlwSFlzAAALEgAACxIB0t1+/AAAAQpJREFUeNpj/M9AHGAiUt2oQuIVfmREBzgU3iHWxAfEKiTaRFpZnfAfAbAr/AsxUYagiVCbeQgqhPpFYmukLCOrZupRNJUIB02BCAjAZCK+/Ed2LoJZgm6bzRfsCgMw3JWAXaEBpg8uIGSRPPMBQmXc+P+iggXCnoOQZUQK1K8PgEAjGcQs7QGL6FzG5mtkcAUiyYIQYcRRUkDTLEIWR1b4ixamQMPhrKUP3rx48eDNFXmwdyFiOthixgXqaTAnBcKpwRaOS6A6Mx78fwBVx/IAm8I/KsTGzAkWNHUyb7Ar/L8GNSlK3MCRev7/v+CApC7kBUoUoAX4yQ0nHjwAWqpiE6GNFgNDoAwHAKC2Q2lMNcCmAAAAAElFTkSuQmCC', 
+      '6' => 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAAAAACpleexAAAAFXRFWHRDcmVhdGlvbiBUaW1lAAfTBQ4QNAObRd4vAAAAB3RJTUUH0wUOEDUc2lcB6wAAAAlwSFlzAAALEgAACxIB0t1+/AAAATtJREFUeNpj/M9AHGAiUh2Gwq2puryMjKKmmSfRVf5HBkcMEBI+L1CkUBROYUE2QuMFLoVr0CzzwKHwhQC6szZgV1gAtfHI/xs2mEYywsPxp8QHEMVxQ56B4aaJiIKIiIRCPDZf74DwI/5jB4hwPAChbAgG+BWoExlOxkoysuqW3sUV4BoQ/p0SqARLB44AF4HIByDMKMCuEIu7phCrUOADNl/DgMOJ/09SIMwPC7B5hgfC1/kB4kRAOC7YrFaByM0Ac85AOCLYrFaBhSMIQNPlG2wBDg3HP2CSGU/MuEAoiKVXUWxB9cwPiG8UwEGSg5FCMNOjwZ4/byqgpqwgMoWr/MGeZ1agqWPZgSNz/Z+AqnDCf1wK/29B8qbKDhQpRtTE8HfLjjMP3jDwKJh4hKCGJSPNC6lRhTRWCABWpdoxd/bZ4QAAAABJRU5ErkJggg==', 
+      '7' => 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAAAAACpleexAAAAFXRFWHRDcmVhdGlvbiBUaW1lAAfTBQ4QNA18/fMoAAAAB3RJTUUH0wUOEDUVo4u5TwAAAAlwSFlzAAALEgAACxIB0t1+/AAAAM9JREFUeNpj/M9AHGAiUt2oQnorZIGzGLFJIyJ40HqGhUiFPFuQ/YUFPBGBmLcDSQybwj8OEDOW/CegsAeiruQ/AYV3OMDqTP4QUugCceCN/wQUQn1a8Z+Awj8qYHUiHwgpXAAxcMJ/Qgp1wOoEPhBSuANiYM5/QgpjIAovEFL4gweszgAz0NASxZ4vYMqHYDKDBiIWhWhWa0CS1x9CVn+8AaYsmAlZfQRC6RDMChADGTQIKjxDrMI7EEoBi0JGlMJe8AOY+sFOSCEeQHQBAABCZ7xyT9fJhwAAAABJRU5ErkJggg==', 
+      '8' => 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAAAAACpleexAAAAFXRFWHRDcmVhdGlvbiBUaW1lAAfTBQ4QNBeBnwpSAAAAB3RJTUUH0wUOEDUOKe5wowAAAAlwSFlzAAALEgAACxIB0t1+/AAAATVJREFUeNpj/M9AHGAiUt1AKmRB459cc+DBGwYWGQ2LEG1Umf/I4IELkozLA2QpFIUXJFDMEDiBQ+EHGTR3yHzArrAFwwct2BXqQGQ1zvw/owFh6mBXCDXmDJB5BsOrjEhxzfoHIgkiGCGB9xtrgEPtOwvEV6FWY4+ZAAgVc5LhZgKEGYI9wN+gBiPu4Pl/BFWlxA1cMfN/C0rUr8AVhX8K0KyuwaEwASNmarAqPACVTXnw/0oENBFewKYQGhYZYE4MVBM2hVAvQ1LhHQhHBVsUMjIgYhCdhy3PPASTd6GOxBYz0KhOQHajDjY3pkC1Rlz5fweqjqEAm8ILGK5gYLlDZICXYI+ZLzZo6gL+4EgUfyo4kJQJtCCpQ8kKQPB2zZ47L14AU5iMgUMAN7IM43AqHwdQIQAhMPz6Gz5V/wAAAABJRU5ErkJggg==', 
+      '9' => 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAAAAACpleexAAAAFXRFWHRDcmVhdGlvbiBUaW1lAAfTBQ4QNCQ+T2tEAAAAB3RJTUUH0wUOEDUHUDLIBwAAAAlwSFlzAAALEgAACxIB0t1+/AAAAUZJREFUeNpj/M9AHGAiUh26wr9rE3V5GRlFTTM3/kVT+R8Z7FBBSKjsQJFCUTiFBcWMCbgUHmBBs20FdoV/VNDUMQi8wapwDVS65s2fPToQZgFWhRFIkm8kwGyeH9gUQm2+Aua0QDhb4LJI4XgHQmmDSRMIZw+emIEENAeEcwObQhEIdQHiABRbUGPGBSIQAWL/gHqbB5tnJkC1Fjz5f8IGwxwkhR8EsCQarFE4hViF/wsQCgKgHsSu8H8HLFkUQL2rgUPh/zslOiwMEjFH/kND2geXQvQgqMAWhSjgAIRygAswIuXCpXfevHjz4M0ZdQaGhxo/wAnyBTuWmPnvARGxuPH/iAa+9Ph/A7r9Ai+wK/zvg6ZwzX8cCl9oICtjmfIfl8L/bwIQ6gyO/Met8P//EwUmwHTJo5OyBU2CkdaF1KhCWisEAM/sJxmZkdWnAAAAAElFTkSuQmCC', 
+      'A' => 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAAAAACpleexAAAAFXRFWHRDcmVhdGlvbiBUaW1lAAfTBQ4QFwy1U7TfAAAAB3RJTUUH0wUOEC0ZKCZtPQAAAAlwSFlzAAALEgAACxIB0t1+/AAAAO1JREFUeNrt1LERwiAUBuAHZ2GRwsIypQMwQEZwgBQpM4QDZBSLFI7gCA5gQWGRdA5gkTuMSh48eMTUnq96wH98B+QiDCwruTD3D76qF676ueAp0Y9lSBXeSkFWaLAje3T+kkzK4SgpBzZw8pqxJWcdOJuRsyGPbWDk0tS20zw9SXsobdfytJVXdzNsP61i6Zt3K7Ht0UeUgbPdjsrOXMd+2IS2C2qb271HVWi7YANcNXFQsUEVBTXwNdl46jYRxPl52dnwRUZbhkLSDmS8DnxFRWiULxg8UxvobefuRR8ZQYDKtffVVcQWv/RrfgJC4bd0upw4MQAAAABJRU5ErkJggg==', 
+      'B' => 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAAAAACpleexAAAAFXRFWHRDcmVhdGlvbiBUaW1lAAfTBQ4QGAusrz2zAAAAB3RJTUUH0wUOEC01Gv4B3gAAAAlwSFlzAAALEgAACxIB0t1+/AAAANJJREFUeNpj/M9AHGAiUh0tFTKiAUHL2rsoKv9DARZDWFr+IwA+hQwMFcQqZDhCrMIIYhWK4FYIYv8444PuV+wK//9/A+UJwBUSCHAL3OEIsdoFyttCpGdiiAtHjoY/RCnk6PlBbBRKrCE6CqcQq5DlDs5whIT3CgUI788EvOEIBCegXB2YPCNMBSNMISqf5TeUjysK90LpP/itfrFEAhZCMHkWdKMYUbk2MAah7BqD02pUYEFkgMu8IE6hD0IdpmegwSejoKLjoY7syaFU7A0HhQA2e4cJytImvAAAAABJRU5ErkJggg==', 
+      'C' => 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAAAAACpleexAAAAFXRFWHRDcmVhdGlvbiBUaW1lAAfTBQ4QGBbPqVFqAAAAB3RJTUUH0wUOEC4BEGemqAAAAAlwSFlzAAALEgAACxIB0t1+/AAAASlJREFUeNpj/M9AHGAiUt2owkGrkAWV+3TDgRtPPjBwyGiYBOijSv1HAlcCkGUcTiDLISvsQDOeZQp2hQWYDpuCTeEEbD44ganwDgc2vxpgKoyAyUWc+f9hjgCMtwFd4RuYRxog/ueBcl3QFc6BSmj8gfBrwE40yFmCrjABqrAH5mSZgJ4jX7AEjwlU4Zn/OAAsrp9AaRlccc0IzdeMsBilOPWQrBDmtpfEKnwBpZ8qZq58i6IS6vscKHcBcgQYlOz4gh6OK6AKfaB8G5hN6Aq/wBLPHjB3CczCFIzUA0u2PD0v/j9pgaf1ExgK3wgwYAEOWFL4GizqWC5gyzM1mArnEJkLZ2DPhf//n3BAVmeDkq8ZUZPL3TUn7gBLCgYFBYsAcxQZRmKrDwABNsv9SJSDwwAAAABJRU5ErkJggg==', 
+      'D' => 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAAAAACpleexAAAAFXRFWHRDcmVhdGlvbiBUaW1lAAfTBQ4QGC1+orhOAAAAB3RJTUUH0wUOEC4yr7fHvgAAAAlwSFlzAAALEgAACxIB0t1+/AAAAM9JREFUeNpj/M9AHGAiUt1AKmSBsxiRhXlkNBxCpFFU/ocBTDMyPvxHADwKGRgUbhCpkEHiCZEKGRyIVciwArdCIPPFGg8YzwSvQiBogXFvEFD43wDKnQDl44yZGCh9glAU2sCsJqRQBkq/gMUw3G2wuP6PnU/H9PgRSgsQUvgESosQUngFSqsQUrgCSsNiCFcU7oBx9+CL6w8XamB5SeUPkelxAZEJ1+YPcQolXhCXFTTuEJULOUq+IOVrFgasQELBxMaHG1mEcTiVjwOoEADAIkCnGpmJKgAAAABJRU5ErkJggg==', 
+      'E' => 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAAAAACpleexAAAAFXRFWHRDcmVhdGlvbiBUaW1lAAfTBQ4QGDeDwEE0AAAAB3RJTUUH0wUOEC8CkHXGUwAAAAlwSFlzAAALEgAACxIB0t1+/AAAAD5JREFUeNpj/M9AHGAiUt2owkGrkAXGYMQqjUgJQ8EzpPsa05+D140oMYTk4KEQ4MMqZqgUhcM1czESW30AABfqB1XDnLzcAAAAAElFTkSuQmCC', 
+      'F' => 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAAAAACpleexAAAAFXRFWHRDcmVhdGlvbiBUaW1lAAfTBQ4QGQe8AkDZAAAAB3RJTUUH0wUOEC8JB6cf2wAAAAlwSFlzAAALEgAACxIB0t1+/AAAADlJREFUeNpj/M9AHGAiUt3wUsiCYDJikUYE3lDwDDm+xvTp4HUjIoaQXTsUAnxYxcyoQryAcUSWuAAW/gZTg/yEMAAAAABJRU5ErkJggg==', 
+      'G' => 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAAAAACpleexAAAAFXRFWHRDcmVhdGlvbiBUaW1lAAfTBQ4QGRFI1vWIAAAAB3RJTUUH0wUOEC8QY8y3GwAAAAlwSFlzAAALEgAACxIB0t1+/AAAASZJREFUeNpj/M9AHGAiUt0IVciCwvt7ZM+FOy8+MDBwSEho2AQII8v9R4A/U2RQtHEUfEBIIim8YYBhn8oNLAqP8GBxmcwbDIU3sKljYIhAV/jHgAE7uICmcAJMQqDmwp//D2YowPgxqAr/wPyr8QAi8EEHwleIQFW4BxYicG+eEHEomHECET5QhRVQhQn/cQFoFJ6AKgwgFNcPoFwdnAoZIXmGERahKDwkIdqlR1j4PiRW4RVCCmExvQenQrSYEXiDiAoUBfC4loAK23yBSnzArhCRehRmAJPFnRUxHDgU/lDA7zZECj/Cgl2dAkaeWYNVZcoHDIX/94hgKLM4gS27/v9QIICizGMDkiQjSon7c8eBCw+e/GFgkZEwsHCRRpZiHE5FMwCa2YE+WcAOUwAAAABJRU5ErkJggg==', 
+      'H' => 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAAAAACpleexAAAAFXRFWHRDcmVhdGlvbiBUaW1lAAfTBQ4QGRw2Z4k1AAAAB3RJTUUH0wUOEC8agxleBQAAAAlwSFlzAAALEgAACxIB0t1+/AAAAD1JREFUeNpj/M9AHGAiUt2oQvyABUozQml4+KMLDAXPDAWFLGh8RlwKh4JnaB88GOlxELhxVCFewDgEynAAN2sFVHAvevkAAAAASUVORK5CYII=', 
+      'I' => 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAAAAACpleexAAAAFXRFWHRDcmVhdGlvbiBUaW1lAAfTBQ4QGSlg1E0WAAAAB3RJTUUH0wUOEC86uHd+zQAAAAlwSFlzAAALEgAACxIB0t1+/AAAAD5JREFUeNpj/M9AHGAiUt1AKmRBMBkxJJE9OhQ8Q32FjGhxDQsjjCQwFDwzqnCwKkRKZqO5EBMwDqcSl2iFAMMeB0s/kLo2AAAAAElFTkSuQmCC', 
+      'J' => 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAAAAACpleexAAAAFXRFWHRDcmVhdGlvbiBUaW1lAAfTBQ4QGywiiNsbAAAAB3RJTUUH0wUOEDAFw0tdbgAAAAlwSFlzAAALEgAACxIB0t1+/AAAAKdJREFUeNpj/M9AHGAiUh3xClmwijJCaSR3Ud/qUYWjCklTyIHEhifctw8ePHgCxO+B7L9QMQlsChW+QOiX4gwMd6BiItisVoHSB6AYWQwM/kNBBszkC/9PwKyc8B8B4Ar3YPHMHWwK/xtgqAv4j1XhEfScK/EEu8L/a1BVStz4j0Ph/yPItoe8QFH3nxGlkNq75cKDB0DDVBwitNEcwjhwpdmoQrwAAN6ioiFapgUdAAAAAElFTkSuQmCC', 
+      'K' => 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAAAAACpleexAAAAFXRFWHRDcmVhdGlvbiBUaW1lAAfTBQ4QHAEoFhGpAAAAB3RJTUUH0wUOEDANzZDVXAAAAAlwSFlzAAALEgAACxIB0t1+/AAAAPZJREFUeNpj/M9AHGAiUt2owgFSyAgFMOGDrDARxkKo0H8wYEDh/b/AAzepACqEVeEdCQx1WBW+0ICry/mPR+EXE7i6kD94FP5xwaYOi8IIrOowFRbA1Xkgq8NQ2ANXZ/PlPx6FS3CpQ1fIAmOIoKn7jxbXf2CMNxvQIxvVRAQQ+YDXaiSQQqxChiOEFGoIQGidP/gVStxogLI68CqUuPH/BzSVcTzAoxCo7v//ObBIxK0QrO7/H1iCXIFT4QkIFxbaMh9wKYQJO0D5OYQUnoDF/QkCCuHJ1+APAYV3YOloAgGF8JTO84SAwjfQiGQIgPAZqV4rAACnKSarzdlc4gAAAABJRU5ErkJggg==', 
+      'L' => 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAAAAACpleexAAAAFXRFWHRDcmVhdGlvbiBUaW1lAAfTBQ4QHA64qQw4AAAAB3RJTUUH0wUOEDAXMPIsJgAAAAlwSFlzAAALEgAACxIB0t1+/AAAADlJREFUeNpj/M9AHGAiUt2QUMiCYDJCaezhMBQ8M6pwVCEdFLJgCjEisRH5Zyh4hvoKGUdkQUq0QgARaARRV9jUFQAAAABJRU5ErkJggg==', 
+      'M' => 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAAAAACpleexAAAAFXRFWHRDcmVhdGlvbiBUaW1lAAfTBQ4QHBhMfblpAAAAB3RJTUUH0wUOEDAqaJpgNwAAAAlwSFlzAAALEgAACxIB0t1+/AAAAPNJREFUeNrdlK0OgzAUhS8bCQYxMYmcmEAgEAgejQfZQyG2pAIxOYlATkAu691o2tvSYia2iv7lyzn3NG0jhG1tt5H7Aggom7ZuaKPhBFqKV+pFWDGjjcxStEAYXuvBkrKtoVX+gdRiK9i6sxjgeVGUMJzWwZLACaZOTqoAOAronmrlBuvPkQsIgHn8BqnE2AMmhaaYJ57jqTRFMwsDyW249XaJLhAujizm7UFM5XCUXTqiTvBLQYWRc7H3WWt+3NmlyGbOGh9q/45mjQxUb+CA6A2jSqu5MweX0ooQWLJxLYx6fz0GwmBOsww5GP3At/dX4Ayb7qpFI9y5ygAAAABJRU5ErkJggg==', 
+      'N' => 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAAAAACpleexAAAAFXRFWHRDcmVhdGlvbiBUaW1lAAfTBQ4QHC6DxyzwAAAAB3RJTUUH0wUOEDAye/b4YQAAAAlwSFlzAAALEgAACxIB0t1+/AAAALRJREFUeNpj/M9AHGAiUt0IV8gIARsRMlAROP8/BEB5Ii/+/0cVgXNRhRk8iFXIMIFYhRxXiFTIYPCDSIUMBcQqZNhDrEKZN0QqZAggViHDHIIKRSAUzx1CCrdAaZM/BBT+z4Eyaggp/KEDYbAcIaDw/wUWCEuBkML/PagBgFvhfxdiFT4RIVLh/zXEKvyfQqzCLypEKvx/hoVIhf9biFX4x4ZIhf8fCBCp8P8KNBHG4VQ0AwDEOyeZhO5p1AAAAABJRU5ErkJggg==', 
+      'O' => 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAAAAACpleexAAAAFXRFWHRDcmVhdGlvbiBUaW1lAAfTBQ4QHQExDSDoAAAAB3RJTUUH0wUOEDA4myMRfwAAAAlwSFlzAAALEgAACxIB0t1+/AAAATtJREFUeNpj/M9AHGAiUt3wUsiCyv265ciZJ08YGGRkDGwCuFGk/iOBDwU8SDIcGS+Q5JAV7hBBs45nAVaFC1gwXTYBi8IdWNQxMCzAUPhBBJs6Bp4n6AoLYFI6az78f7NEB8ZNQFP4QwAqEfADwg+A+f0NqsI1UHGBDzCnSKC6EhYzB6B0Cj+UwZ+CKgNTeAZKu8C94QGlL6DGjAyU+wAeXC+gIiIQLiM0KzDC9CFCBlWICsnsL3aFMDc+hcs8QZWBKYSF2g24whvYFZpA6T1whUegNCwyoYGxAmYyLGZ+wOxYghqFX2BpO+APmP8nBspHj2uk1LPizf8PGyxgXPTUQ3x6JDqF//8/AYs6bHkGmCYF0O3FnguBCSaFA0kZS8IDJDlG1IIUVFK8eABMWzI6DgHCyDKMI7LEBQCD5YgI9wbKGgAAAABJRU5ErkJggg==', 
+      'P' => 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAAAAACpleexAAAAFXRFWHRDcmVhdGlvbiBUaW1lAAfTBQ4QHQvR2Mn2AAAAB3RJTUUH0wUOEDEDMzPJGgAAAAlwSFlzAAALEgAACxIB0t1+/AAAAKVJREFUeNpj/M9AHGAiUh05ChlRAKdu4k5Ulf9hANMQiwf/EQCfQgaJB0QqZHAhViHDEbg0AV8vwRM8QN0v5vBAOSfw+BrMWQDl8MClGeEKGGEKQcRXHmQemTGD1RMy+N14o4MDyvGAS7NgGMaIzPHAYyIy4HhBZMy0EBmFIX+IUsjRgqQOi2fAgEVBwyVGGEUEQw2O3EbLzDWSFDIOhtJsVCEWAAC/Yt2X+2PYcgAAAABJRU5ErkJggg==', 
+      'Q' => 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAAAAACpleexAAAAFXRFWHRDcmVhdGlvbiBUaW1lAAfTBQ4QHRxSC0wxAAAAB3RJTUUH0wUOEDEKSu9xvgAAAAlwSFlzAAALEgAACxIB0t1+/AAAAW1JREFUeNpj/M9AHGAiUt2QUMiCzPm65cCZF08YGGRkDBx8uNFU/oeDDwU8SOIcBS/+IwOEwh0iaEYIrMCqcA4LprsmYFG4A4s6BoYFGAo/iGBTx8DzAl1hAUxKZ8WH/29W6MC4KWgKfwhAJXx+gPl/QmB+/4KqcANUXOQDVPiLBFRkCUwhJGb2wGzihzK4U6CMA6hReAbKc4F7wwFKX0CNGRkoB+HJJ1ARGZgAIziFM8J0IUIGXYjMZPaXkEJYYDyBiz+EuRFVoQKUdwWIz6qWvmRguAMVkUBVaIIUalPu9GgshIefAWrwrIHp//L/DQc4KjFiBi2uQ/7832KB5AX0uP5fAZOx2PDhfwNCIXrq+f9BhgEb4HmCkcL3YE3hSHkBnmfWYFMpsoaYXAgGDgcwFKLlaxYOCG2DqRCYrldkmIACUMIgZsaTI5Cg3IBNISp4AoovlT+EFf7/kYPkb3wK//8/YAGPGcYhUIYDAHBC9Yak1w7iAAAAAElFTkSuQmCC', 
+      'R' => 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAAAAACpleexAAAAFXRFWHRDcmVhdGlvbiBUaW1lAAfTBQ4QHSkEuIgSAAAAB3RJTUUH0wUOEDEUsOBM3QAAAAlwSFlzAAALEgAACxIB0t1+/AAAAOZJREFUeNpj/M9AHGAiUh0NFLJAaUY0YRkJHYcQdmSh/xCAzRCZHf8RAJ9CBpYNRCpkEHgBV4jfMx+mEOVGIDDAaTWY82aPBZTLgV8hUCkaH6cbP8B8gxHgyODjgwstMDfiVIgWQyFE+lrhB3EBznOFuJgxuUFMXPPEbPmDpA53FH55osKMIoAe4F826MDMvPMfj9WgWFGBBeIf/Ar/H4FxJhBQ+B8WzCIfCCi8A4uvBgIK/2fA/POCgMIXHFBuDqH02ABLM3cIKPwgAuVHEFD4fwJM4AIBhT9goe4AFWAcAsXesFIIAEvJyZHTCSiTAAAAAElFTkSuQmCC', 
+      'S' => 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAAAAACpleexAAAAFXRFWHRDcmVhdGlvbiBUaW1lAAfTBQ4QHTRnvuTLAAAAB3RJTUUH0wUOEDEbIF9RTAAAAAlwSFlzAAALEgAACxIB0t1+/AAAAVZJREFUeNpj/M9AHGAiUt2oQvyABYX398CWK3de/GBgkVEw8HFgRpH7jwSWqCDLyCxAlkNS+CcG3boY7AozMB3Wgk3hGSw+4HgBl0b4egIWhT9mYPGMBFQg4MH/D2tgvrKASzPC0yMjlP7CDSTOmrDIMDDwiHBsxzSRBypw5j9WgFDoAPNAxIQjX/ApXIDsC4OCLV9wKfzjwIACOEIO4IiZFxbooePzAqvC/z9qONBUStzAqvD//zc9BqgqNX5gVwgETxbkmCClvSk4FYLdsCMCptAGI2YSGV78+PLmz5MX4mDu1ByIMM9n9JiBxe4caGChy8MZMMsUIEFyAMoVwVC4BGaEwpI3/9/MEYGlJQyFPwQYsIE1mL7GlnCR0iNSXLtgqpO4gy1mvtigq1NAxCBKgP9pEUFWxlOCnNIYUYrmn3v23Ljx5gsw88sYOPhwI0sxDoEyHAABtSc836a1EQAAAABJRU5ErkJggg==', 
+      'T' => 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAAAAACpleexAAAAFXRFWHRDcmVhdGlvbiBUaW1lAAfTBQ4QHgUdTbcyAAAAB3RJTUUH0wUOEDEgkVS4aAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADdJREFUeNpj/M9AHGAiUt0IVcgCpRlxyMODeSh4hmiFjGipB+Z7jEQ1FDwzqnBU4WBSyDicimYAb/AFTaJpyH8AAAAASUVORK5CYII=', 
+      'U' => 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAAAAACpleexAAAAFXRFWHRDcmVhdGlvbiBUaW1lAAfTBQ4QHhEHl2NPAAAAB3RJTUUH0wUOEDEon48wWgAAAAlwSFlzAAALEgAACxIB0t1+/AAAAKlJREFUeNpj/M9AHGAiUh3xClmgNCOUhrsEXYD6Vo8qHFVIuUIVKP0USr+E0jLoCjWg9A4ovQVNHJjUIaADZsILMPeFApRfA5X/D1N4AaZRYc6b/2+WwNQxXEBX+N8Bqxcc/mMoPMGCRR3LBUyF/2dgUTjjPxaF/6egm8ky5T9Whf9P2KCoMziBJPefEaWQurjnzIMXL34wsMhoWHiYo2hjHLjSbFQhXgAAKzejCLAOcVMAAAAASUVORK5CYII=', 
+      'V' => 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAAAAACpleexAAAAFXRFWHRDcmVhdGlvbiBUaW1lAAfTBQ4QHh/gL05IAAAAB3RJTUUH0wUOEDEuduyVbwAAAAlwSFlzAAALEgAACxIB0t1+/AAAAVNJREFUeNpj/M9AHGAiUt2owoFRaMgIAYlIMqlQMUMo/z8ITIByRP78hwMRqNgECBei8AULVPQIXN0RqAjLGwgfYrW4B1R4DdzmLVDaQxjZ6v8roDwVuIkqMK3/ka3+/0MAKn4FKn4D5uof/5GtZmCPgEpsQHNDBDsDitVwt5tA+RZQ/pn/qFYj3PQEzHsC5WnA3QyPmQQU3+5AE0VYDTfDBcxzgQbik/8YVv93gMp9AbK/cEAD8T+m1TBb/oD8veEHhs0IE2GmxADZMRAmz4//WKxGkv3DA2Gm/MeqcA/Ujj1w1hHsCv/LQKQz/megRzyawgqIvAxMRwsuhbCEAEvGT3AphEUwNCU5IEv9R8lcUH9/wAxE5HAEgjccSBI8X3CbKOyBxAnhxm3i/w1IEgdQZFA98/+PCFydDKo6VKsZmGPQ0wgOq/+fgYvfQTORkeq1AgCIAvD7+THsDgAAAABJRU5ErkJggg==', 
+      'W' => 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAAAAACpleexAAAAFXRFWHRDcmVhdGlvbiBUaW1lAAfTBQ4QFhZRKnzkAAAAB3RJTUUH0wUOEDIR66frkQAAAAlwSFlzAAALEgAACxIB0t1+/AAAAXNJREFUeNrtlK1ywkAUhZdMZsJMKyIqKhAIBAKBiEBEVCDyCJV9iIo+Do9QGRERgUBEVCAqKhAIREVERURnTvfn3t27xSA6g+kOQ/ZkP/aec5NlBHXZSC7k/sE/AhUwoVkDPQ58/2RUQ2IC6B1XpN7MV8tg62/pUdjSDO7OwR2J0pbekpqZYlMG50bNSGwBDQ4pyV5YtCZ7mqZf1mO2IN2Jynba0XRx49pThjQCbEKWFfVRpIlBzlK4PuLdpxEWlTr4LHvYMEDOaTYS3HCW3DAJt8mmaSXYchZbOfEzkyYGZRbrEbX8qe7GMpLqFeyxV9F4fon1pwcxjxbqJpJTBPBJLoyHYSz1I3xq78aOMssepHZZHFjKhbX9/AZd6e9bsdABeyHTQXiE2PLO6PugCwiP/r1QVLYSlpXwKE1Wno7b7jY+hoWj0aegPyA9+jPrzgqwZJ0j8hhMVtElmDoD19FFPAvamc+sOXBm+KdYEzC63p/9D7Tr72kj/8qjAAAAAElFTkSuQmCC', 
+      'X' => 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAAAAACpleexAAAAFXRFWHRDcmVhdGlvbiBUaW1lAAfTBQ4QHi/G9n7kAAAAB3RJTUUH0wUOEDIXAsROpAAAAAlwSFlzAAALEgAACxIB0t1+/AAAAT9JREFUeNpj/M9AHGAiUt3IVhjKCAFr4RJroSKBMIH/YPBEAMITeQLh//8gAxHggQlAFf6fAdXnA+WnQPkT/qMp/O8AlVkA5h2A8kz+YCi8wQGREngA5PxQgXBYzvzHUPi/A2qIA5BdAmUX/Mei8I8BVHbK/wssEJbMB2wK/5+ASvPcgGlZ8x+rQriFAmghgKHwiwJKXPA8wKXw/x4UhT3/cSr8n4CkzuAPHoVvRODqWE6gyPxHTT1ffiAUCjCgAhRtDkgSFnisnoJixAScCh/wEBk8DmiucsChcA5MQQSMMQWrQlgiZ0iAByey5QiFPlBZnS//v+hgxjZc4QKYKVeAnCswby3AUAi3eAGKNoEn6Ap94A5EjXUfNIUrEA6EALgzl6AohCUGsAMhAOZMkTfICkMw3I5wZgiEyzicimYAFRFkVwgDfJ0AAAAASUVORK5CYII=', 
+      'Y' => 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAAAAACpleexAAAAFXRFWHRDcmVhdGlvbiBUaW1lAAfTBQ4QHjkyIsu1AAAAB3RJTUUH0wUOEDIkvRQvsgAAAAlwSFlzAAALEgAACxIB0t1+/AAAANJJREFUeNrt1L0NgzAQBWAcUVB6AAZgBAoKhmAICoZgCAoKxmAECkbwABSUlBRILwF8duwYhFJEihJ37+6T5T9g8K6N20X3FdDDNjKKOeTIqZLtWcKBU73bCx1lPhgQNTWieY1zRLmGCZFQp1xTSSmBDUUgW754BF+GQLxAPUkMxMb0FlzUsqpKLXhxQPRqo+oIerggCvuMC7jhFJounA4gWhO2OIL6Jp/uzglHrh0fTyAaDRucQaTkUpxDQVBYDWZ/hYze6bsv/A8/DNlP/kgvwzuer4kCMGPZDgAAAABJRU5ErkJggg==', 
+      'Z' => 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAAAAACpleexAAAAFXRFWHRDcmVhdGlvbiBUaW1lAAfTBQ4QHwfqWOdfAAAAB3RJTUUH0wUOEDIrLasyIwAAAAlwSFlzAAALEgAACxIB0t1+/AAAAL5JREFUeNrl1C0OwkAQBWCWQIJEVPQIFT0GAlHBMRBIBKIHqahAIDlERY9R0UOs3ORh5qVLunmp5GfUZvczbzKzDqtltV7ofgtueHCp16h33xBGwn0KYqoTO/J868Csaj418e0cPujOkLDfmTsECcfcXOGhoC/NZQMUDBUDd5DwxiAtJGzprpCw48xVQcIhM1d6KOgLc/kIBcORgXtIeGGQOyRs6Oq0g7P92YbkRE7bRZhcwhh+6nLF5f7yx30B8Z7FgxzMWtEAAAAASUVORK5CYII=', 
+    );
+  
+    return $_png;
+  }
+  
+  // Function get_rgb by Frank Burian
+  // http://www.phpfuncs.org/?content=show&id=46
+  function get_rgb($hex) { 
+    $hex_array = array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 
+        'A' => 10, 'B' => 11, 'C' => 12, 'D' => 13, 'E' => 14, 
+        'F' => 15); 
+    $hex = str_replace('#', '', strtoupper($hex)); 
+    if (($length = strlen($hex)) == 3) { 
+        $hex = $hex{0}.$hex{0}.$hex{1}.$hex{1}.$hex{2}.$hex{2}; 
+        $length = 6; 
+    } 
+    if ($length != 6 or strlen(str_replace(array_keys($hex_array), '', $hex))) 
+        return NULL; 
+    $rgb['r'] = $hex_array[$hex{0}] * 16 + $hex_array[$hex{1}]; 
+    $rgb['g'] = $hex_array[$hex{2}] * 16 + $hex_array[$hex{3}]; 
+    $rgb['b']= $hex_array[$hex{4}] * 16 + $hex_array[$hex{5}]; 
+    return $rgb['r'].','.$rgb['g'].','.$rgb['b']; 
+  }
+  
+  // Function  gdVersion by Hagan Fox
+  // http://de3.php.net/manual/en/function.gd-info.php#52481
+  function gdVersion($user_ver = 0)
+  {
+     if (! extension_loaded('gd')) { return; }
+     static $gd_ver = 0;
+     // Just accept the specified setting if it's 1.
+     if ($user_ver == 1) { $gd_ver = 1; return 1; }
+     // Use the static variable if function was called previously.
+     if ($user_ver !=2 && $gd_ver > 0 ) { return $gd_ver; }
+     // Use the gd_info() function if possible.
+     if (function_exists('gd_info')) {
+         $ver_info = gd_info();
+         preg_match('/\d/', $ver_info['GD Version'], $match);
+         $gd_ver = $match[0];
+         return $match[0];
+     }
+     // If phpinfo() is disabled use a specified / fail-safe choice...
+     if (preg_match('/phpinfo/', ini_get('disable_functions'))) {
+         if ($user_ver == 2) {
+             $gd_ver = 2;
+             return 2;
+         } else {
+             $gd_ver = 1;
+             return 1;
+         }
+     }
+     // ...otherwise use phpinfo().
+     ob_start();
+     phpinfo(8);
+     $info = ob_get_contents();
+     ob_end_clean();
+     $info = stristr($info, 'gd version');
+     preg_match('/\d/', $info, $match);
+     $gd_ver = $match[0];
+     return $match[0];
+  }
+    
+}
+
+// define('ENANO_CAPTCHA_BIGNFAT', '');
+  
+?>
Binary file includes/captcha/fonts/assimila.ttf has changed
Binary file includes/captcha/fonts/elephant.ttf has changed
Binary file includes/captcha/fonts/swash_normal.ttf has changed
Binary file includes/captcha/fonts/trekker_regular.ttf has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/admin-menu.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,161 @@
+/*
+ * Midget - an open source wiki-like CMS
+ * Copyright (C) 2006 Dan Fuhry
+ *
+ * This program is Free Software; you can redistribute 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 details.
+ *
+ * Some code found in this script is not licensed under the GNU General Public License; however, it is believed that the license terms shown
+ * below are GPL-compatible. If you believe that this is not the case, please drop a note to support@midget.no-ip.org.
+ */
+ 
+/*
+ * Title: Tigra Tree
+ * Description: See the demo at url
+ * URL: http://www.softcomplex.com/products/tigra_tree_menu/
+ * Version: 1.1
+ * Date: 11-12-2002 (mm-dd-yyyy)
+ * Notes: This script is free. Visit official site for further details.
+ * 
+ * There is no license fee or royalty fee to be paid at any time for using the Tigra Tree Menu v1.x
+ * You may include the source code or modified source code within your own projects for either personal or commercial use but excluding the restrictions outlined below. The following restrictions apply to all parts of the component, including all source code, samples and documentation.
+ *
+ * - Header block of script file (tree.js) CAN NOT be modified or removed.
+ * - The above items CAN NOT be sold as are, either individually or together.
+ * - The above items CAN NOT be modified and then sold as a library component, either individually or together. 
+ */
+ 
+function tree (a_items, a_template) {
+
+	this.a_tpl      = a_template;
+	this.a_config   = a_items;
+	this.o_root     = this;
+	this.a_index    = [];
+	this.o_selected = null;
+	this.n_depth    = -1;
+	
+	var o_icone = new Image(),
+		o_iconl = new Image();
+	o_icone.src = a_template['icon_e'];
+	o_iconl.src = a_template['icon_l'];
+	a_template['im_e'] = o_icone;
+	a_template['im_l'] = o_iconl;
+	for (var i = 0; i < 64; i++)
+		if (a_template['icon_' + i]) {
+			var o_icon = new Image();
+			a_template['im_' + i] = o_icon;
+			o_icon.src = a_template['icon_' + i];
+		}
+	
+	this.toggle = function (n_id) {	var o_item = this.a_index[n_id]; o_item.open(o_item.b_opened) };
+	this.select = function (n_id) { return this.a_index[n_id].select(); };
+	this.mout   = function (n_id) { this.a_index[n_id].upstatus(true) };
+	this.mover  = function (n_id) { this.a_index[n_id].upstatus() };
+
+	this.a_children = [];
+	for (var i = 0; i < a_items.length; i++)
+		new tree_item(this, i);
+
+	this.n_id = trees.length;
+	trees[this.n_id] = this;
+	
+	for (var i = 0; i < this.a_children.length; i++) {
+		document.write(this.a_children[i].init());
+		this.a_children[i].open();
+	}
+}
+function tree_item (o_parent, n_order) {
+
+	this.n_depth  = o_parent.n_depth + 1;
+	this.a_config = o_parent.a_config[n_order + (this.n_depth ? 2 : 0)];
+	if (!this.a_config) return;
+
+	this.o_root    = o_parent.o_root;
+	this.o_parent  = o_parent;
+	this.n_order   = n_order;
+	this.b_opened  = !this.n_depth;
+
+	this.n_id = this.o_root.a_index.length;
+	this.o_root.a_index[this.n_id] = this;
+	o_parent.a_children[n_order] = this;
+
+	this.a_children = [];
+	for (var i = 0; i < this.a_config.length - 2; i++)
+		new tree_item(this, i);
+
+	this.get_icon = item_get_icon;
+	this.open     = item_open;
+	this.select   = item_select;
+	this.init     = item_init;
+	this.upstatus = item_upstatus;
+	this.is_last  = function () { return this.n_order == this.o_parent.a_children.length - 1 };
+}
+
+function item_open (b_close) {
+	var o_idiv = get_element('i_div' + this.o_root.n_id + '_' + this.n_id);
+	if (!o_idiv) return;
+	
+	if (!o_idiv.innerHTML) {
+		var a_children = [];
+		for (var i = 0; i < this.a_children.length; i++)
+			a_children[i]= this.a_children[i].init();
+		o_idiv.innerHTML = a_children.join('');
+	}
+	o_idiv.style.display = (b_close ? 'none' : 'block');
+	
+	this.b_opened = !b_close;
+	var o_jicon = document.images['j_img' + this.o_root.n_id + '_' + this.n_id],
+		o_iicon = document.images['i_img' + this.o_root.n_id + '_' + this.n_id];
+	if (o_jicon) o_jicon.src = this.get_icon(true);
+	if (o_iicon) o_iicon.src = this.get_icon();
+	this.upstatus();
+}
+
+function item_select (b_deselect) {
+	if (!b_deselect) {
+		var o_olditem = this.o_root.o_selected;
+		this.o_root.o_selected = this;
+		if (o_olditem) o_olditem.select(true);
+	}
+	var o_iicon = document.images['i_img' + this.o_root.n_id + '_' + this.n_id];
+	if (o_iicon) o_iicon.src = this.get_icon();
+	get_element('i_txt' + this.o_root.n_id + '_' + this.n_id).style.fontWeight = b_deselect ? 'normal' : 'bold';
+	
+	this.upstatus();
+	return Boolean(this.a_config[1]);
+}
+
+function item_upstatus (b_clear) {
+	window.setTimeout('window.status="' + (b_clear ? '' : this.a_config[0] + (this.a_config[1] ? ' ('+ this.a_config[1] + ')' : '')) + '"', 10);
+}
+
+function item_init () {
+	var a_offset = [],
+		o_current_item = this.o_parent;
+	for (var i = this.n_depth; i > 1; i--) {
+		a_offset[i] = '<img src="' + this.o_root.a_tpl[o_current_item.is_last() ? 'icon_e' : 'icon_l'] + '" border="0" align="absbottom">';
+		o_current_item = o_current_item.o_parent;
+	}
+	return '<table cellpadding="0" cellspacing="0" border="0"><tr><td nowrap>' + (this.n_depth ? a_offset.join('') + (this.a_children.length
+		? '<a href="javascript: trees[' + this.o_root.n_id + '].toggle(' + this.n_id + ')" onmouseover="trees[' + this.o_root.n_id + '].mover(' + this.n_id + ')" onmouseout="trees[' + this.o_root.n_id + '].mout(' + this.n_id + ')"><img src="' + this.get_icon(true) + '" border="0" align="absbottom" name="j_img' + this.o_root.n_id + '_' + this.n_id + '"></a>'
+		: '<img src="' + this.get_icon(true) + '" border="0" align="absbottom">') : '')
+  // CODE MODIFICATION
+  // removed: 
+	//	+ '<a href="' + this.a_config[1] + '" target="' + this.o_root.a_tpl['target'] + '" onclick="return trees[' + this.o_root.n_id + '].select(' + this.n_id + ')" ondblclick="trees[' + this.o_root.n_id + '].toggle(' + this.n_id + ')" onmouseover="trees[' + this.o_root.n_id + '].mover(' + this.n_id + ')" onmouseout="trees[' + this.o_root.n_id + '].mout(' + this.n_id + ')" class="t' + this.o_root.n_id + 'i" id="i_txt' + this.o_root.n_id + '_' + this.n_id + '"><img src="' + this.get_icon() + '" border="0" align="absbottom" name="i_img' + this.o_root.n_id + '_' + this.n_id + '" class="t' + this.o_root.n_id + 'im">' + this.a_config[0] + '</a></td></tr></table>' + (this.a_children.length ? '<div id="i_div' + this.o_root.n_id + '_' + this.n_id + '" style="display:none"></div>' : '');
+  // added:
+      + '<a href="' + this.a_config[1] + '" target="' + this.o_root.a_tpl['target'] + '" onclick="return trees[' + this.o_root.n_id + '].select(' + this.n_id + ')" ondblclick="trees[' + this.o_root.n_id + '].toggle(' + this.n_id + ')" onmouseover="trees[' + this.o_root.n_id + '].mover(' + this.n_id + ')" onmouseout="trees[' + this.o_root.n_id + '].mout(' + this.n_id + ')" class="t' + this.o_root.n_id + 'i" id="i_txt' + this.o_root.n_id + '_' + this.n_id + '">' + this.a_config[0] + '</a></td></tr></table>' + (this.a_children.length ? '<div id="i_div' + this.o_root.n_id + '_' + this.n_id + '" style="display:none"></div>' : '');
+}
+
+function item_get_icon (b_junction) {
+	return this.o_root.a_tpl['icon_' + ((this.n_depth ? 0 : 32) + (this.a_children.length ? 16 : 0) + (this.a_children.length && this.b_opened ? 8 : 0) + (!b_junction && this.o_root.o_selected == this ? 4 : 0) + (b_junction ? 2 : 0) + (b_junction && this.is_last() ? 1 : 0))];
+}
+
+var trees = [];
+get_element = document.all ?
+	function (s_id) { return document.all[s_id] } :
+	function (s_id) { return document.getElementById(s_id) };
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/css/enano-shared.css	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,400 @@
+/*
+ * Shared stuff that all Enano themes (should) use
+ */
+
+/* Information, warning, question, error, and wait boxes */
+div.error-box                     { background-image: url(../../../images/error.png);    background-repeat: no-repeat; background-color: #FFF4F4; border: 1px dashed #406080; padding: 10px 10px 10px 50px; margin: 1em 0 0 0; min-height: 25px; }
+div.info-box                      { background-image: url(../../../images/info.png);     background-repeat: no-repeat; background-color: #F4F4FF; border: 1px dashed #406080; padding: 10px 10px 10px 50px; margin: 1em 0 0 0; min-height: 25px; }
+div.warning-box                   { background-image: url(../../../images/warning.png);  background-repeat: no-repeat; background-color: #FFFFF4; border: 1px dashed #406080; padding: 10px 10px 10px 50px; margin: 1em 0 0 0; min-height: 25px; }
+div.question-box                  { background-image: url(../../../images/question.png); background-repeat: no-repeat; background-color: #F4FFF4; border: 1px dashed #406080; padding: 10px 10px 10px 50px; margin: 1em 0 0 0; min-height: 25px; }
+div.wait-box                      { background-image: url(../../../images/wait.png);     background-repeat: no-repeat; background-color: #FFF4FF; border: 1px dashed #406080; padding: 10px 10px 10px 50px; margin: 1em 0 0 0; min-height: 25px; }
+
+/* toolbar */
+div.toolbar {
+  border-bottom: 1px solid #909090;
+  background-color: #D0D0D0;
+  padding: 2px 0;
+  height: 22px;
+  font-family: arial, sans-serif;
+  font-size: 8pt;
+}
+div.toolbar ul {
+  margin: 0;
+  padding: 0;
+}
+div.toolbar ul li {
+  list-style: none;
+  margin: 0;
+  float: left;
+}
+div.toolbar a img {
+  opacity: 0.6;
+  /*filter: alpha(opacity=60);*/
+}
+div.toolbar a:hover img {
+  opacity: 1;
+  /*filter: alpha(opacity=100);*/
+}
+div.toolbar a {
+  display: block;
+  padding: 2px;
+  border: 1px solid transparent;
+  cursor: default;
+  width: auto;
+  color: #000000;
+  margin: 0 2px;
+  max-height: 16px;
+  text-decoration: none;
+}
+div.toolbar a:hover {
+  border: 1px solid #202090;
+  background-color: #ceceed;
+  color: #000000;
+  text-decoration: none;
+}
+div.toolbar a:active {
+  border: 1px solid #A0A0A0;
+  background-color: #E0E0E0;
+}
+div.toolbar img {
+  margin: 0;
+  padding: 0;
+  display: inline;
+  border-width: 0px;
+}
+div.toolbar a span {
+  position: relative;
+  top: -4px;
+}
+div.toolbar li span {
+  padding-left: 2px;
+  padding-right: 5px;
+}
+
+/* vertical toolbar */
+div.toolbar_vert {
+  border: 1px solid #909090;
+  background-color: #D0D0D0;
+  padding: 2px 0;
+}
+div.toolbar_vert ul {
+  margin: 0;
+  padding: 0;
+}
+div.toolbar_vert ul li {
+  list-style: none;
+  margin: 0;
+}
+div.toolbar_vert a img {
+  opacity: 0.6;
+  /*filter: alpha(opacity=60);*/
+}
+div.toolbar_vert a:hover img {
+  opacity: 1;
+  /*filter: alpha(opacity=100);*/
+}
+div.toolbar_vert a {
+  display: block;
+  padding: 2px;
+  border: 1px solid transparent;
+  cursor: default;
+  width: auto;
+  color: #000000;
+  margin: 0 2px;
+  max-height: 16px;
+  text-decoration: none;
+}
+div.toolbar_vert a:hover {
+  border: 1px solid #202090;
+  background-color: #ceceed;
+  color: #000000;
+  text-decoration: none;
+}
+div.toolbar_vert a:active {
+  border: 1px solid #A0A0A0;
+  background-color: #E0E0E0;
+}
+div.toolbar_vert img {
+  margin: 0;
+  padding: 0;
+  display: inline;
+  border-width: 0px;
+}
+div.toolbar_vert a span {
+  position: relative;
+  top: -4px;
+}
+div.toolbar_vert li span {
+  padding-left: 2px;
+  padding-right: 5px;
+}
+
+/* Tables */
+.tblholder                        { margin: 10px 0 0 0; padding: 0; border: 1px solid #AAAAAA; background-color: #E8E8E8; }
+
+/* The beautiful tables inside what may not obviously be mdg-comment divs */
+div.tblholder td.row1             { padding: 4px; background-color: #E0E0E0; }
+div.tblholder td.row2             { padding: 4px; background-color: #F0F0F0; }
+div.tblholder td.row3             { padding: 4px; background-color: #E8E8E8; }
+div.tblholder th                  { padding: 4px; background-color: #7080A0; font-weight: bold; text-align: center; color: #FFFFFF; }
+div.tblholder th.subhead          { padding: 4px; background-color: #90A0B0; font-weight: bold; text-align: center; color: #FFFFFF; }
+div.tblholder table               { background-color: #FFFFFF; width: 100%; }
+
+/* Well, not Midget and not comments (usually), but that's what the class is called ;-). Basically an informational window or used as a wrapper for tables. */
+.mdg-comment, .mdg-infobox        { margin-left: 1em; padding: 7px; border: 1px solid #AAAAAA; background-color: #E8E8E8; }
+
+/* JWS window theming */
+div.jswindow                      { border: 2px solid #7090B0; border-top: 5px solid #7090B0; padding: 0px; font-family: Trebuchet MS, tahoma, verdana, arial, sans-serif; font-size: 9pt; display: none; position: absolute; background-color: #FFFFFF; }
+div.titlebar                      { background-color: #7090B0; color: #FFFFFF; font-family: Trebuchet MS, tahoma, verdana, arial, sans-serif; font-size: 9pt; padding-bottom: 4px; cursor: default; }
+div.titlebar div.closebtn         { width: 16px; height: 16px; border: 1px solid #B0D0F0; background-color: #90B0D0; display: block; }
+div.titlebar div.closebtn:hover   { width: 16px; height: 16px; border: 1px solid #FFFFFF; background-color: #B0D0F0; display: block; }
+div.titlebar table, div.titlebar td { margin: 0; padding: 0; }
+div.jswindow div.content          { padding: 10px; margin: 0; background-color: #FFFFFF; }
+
+/* Search results */
+div.search-result h3   { font-size: 14pt; margin: 10px 0 0 0; }
+div.search-result h3 a { color: blue !important; font-weight: normal; padding-bottom: 0; }
+div.search-result p    { margin: 10px 0 0 0 !important; font-family: arial, helvetica, sans-serif; font-size: 10pt; }
+div.search-result span.search-result-info { color: green; }
+div.search-result span.search-term, div.search-result span.title-search-term { background-color: #FFFFC0; font-weight: bold; }
+
+/*
+ * Search box
+ */
+ 
+input.js-search-box {
+  font-size: 13px;
+  margin: 0;
+  padding: 1px !important;
+  background-image: url(../../../images/search-box-normal.gif);
+  height: 15px;
+  background-repeat: repeat-x;
+  border-width: 1px;
+  border-style: solid;
+  border-color: #6c6c6c;
+  color: #C0C0C0;
+}
+
+input.js-search-box:focus {
+  background-image: url(../../../images/search-box-hilite.gif);
+  color: #666;
+}
+
+div.js-search-submit {
+  display: block;
+  position: absolute;
+  width: 24px;
+  height: 19px;
+  font-size: 1px;
+  line-height: 19px;
+  clip: rect(0px, 24px, 19px, 0px);
+  overflow: hidden;
+  margin: 0;
+  padding: 0;
+  background: transparent url(../../../images/search-btn-normal.png) no-repeat !important;
+  background-repeat: no-repeat;
+  cursor: pointer;
+}
+
+div.js-search-submit:hover {
+  background-image: url(../../../images/search-btn-hilite.png);
+}
+
+input[type ^="text"].username, input[type ^="password"].password {
+  padding: 2px 2px 2px 27px;
+  width: 96px;
+  height: 15px;
+  border: 0px none #000;
+  font-size: 11px;
+}
+input[type ^="text"].username {
+  background-image: url(../../../images/login-username.png);
+}
+input[type ^="password"].password {
+  background-image: url(../../../images/login-password.png);
+}
+
+/*
+ * jBox menu system
+ */
+
+div.menu, div.menu_nojs {
+  background-color: #D0D0D0;
+  border: 1px solid #A0A0A0;
+  font-size: 9pt;
+}
+div.menu a, div.menu div.label {
+  padding: 2pt 5px;
+  text-decoration: none;
+  display: block;
+  float: left;
+  color: #404040;
+}
+div.menu_nojs a, div.menu_nojs div.label {
+  padding: 2pt 5px;
+  text-decoration: none;
+  display: block;
+  color: #404040;
+}
+div.menu div.label, div.menu_nojs div.label {
+  color: #101010;
+}
+div.menu span.sep, div.menu_nojs span.sep {
+  display: block;
+  float: left;
+  width: 5px;
+}
+div.menu div.multopts, div.menu_nojs div.multopts {
+  line-height: 17pt;
+}
+div.menu div.multopts a, div.menu div.multopts div.label, div.menu_nojs div.multopts a, div.menu_nojs div.multopts div.label {
+  float: none;
+  display: inline;
+}
+div.menu a:hover, div.menu_nojs a:hover {
+  color: #FFFFFF;
+  background-color: #808080;
+}
+div.menu input[type ^="text"], div.menu input[type ^="password"], div.menu_nojs input[type ^="text"], div.menu_nojs input[type ^="password"] {
+  border-width: 0;
+  font-size: 9pt;
+  padding: 4px 5px;
+  max-width: 70px;
+  background-color: #E0E0E0;
+}
+div.menu input[type ^="text"]:hover, div.menu input[type ^="password"]:hover, div.menu_nojs input[type ^="text"]:hover, div.menu_nojs input[type ^="password"]:hover {
+  background-color: #E8E8E8;
+}
+div.menu input[type ^="text"]:focus, div.menu input[type ^="password"]:focus, div.menu_nojs input[type ^="text"]:focus, div.menu_nojs input[type ^="password"]:focus {
+  background-color: #F0F0F0;
+}
+div.menu input[type ^="button"], div.menu input[type ^="submit"], div.menu_nojs input[type ^="button"], div.menu_nojs input[type ^="submit"] {
+  border-width: 0;
+  font-size: 9pt;
+  padding: 3px 5px;
+  max-width: 70px;
+}
+div.menu a.current, div.menu a.current:hover, div.menu_nojs a.current, div.menu_nojs a.current:hover {
+  color: #FFFFFF;
+  background-color: #505050;
+}
+div.menu ul {
+  display: none;
+  position: absolute;
+  padding: 0;
+  margin: 0;
+  background-color: #D0D0D0;
+  border: 1px solid #A0A0A0;
+  min-width: 120px;
+}
+div.menu_nojs ul {
+  display: block;
+  clear: both;
+}
+div.menu ul li, div.menu_nojs ul li {
+  list-style: none;
+}
+div.menu ul a, div.menu_nojs ul a {
+  float: none;
+  margin: 0;
+}
+span.menuclear {
+  font-size: 1px;
+  height: 0px;
+  width: 0px;
+  clear: left;
+  line-height: 0px;
+  display: block;
+}
+
+/*
+ * Docking Boxes code (for the sidebar editor)
+ */
+ 
+/* group container(s) */
+#sbedit {
+  margin: 0;
+  padding: 0;
+  /* position:relative; /* additional outer containers must also have position:relative */
+}
+/* keyboard navigation tooltip */
+.dbx-tooltip {
+  display:block;
+  position:absolute;
+  margin:36px 0 0 125px;
+  width:185px;
+  border:1px solid #000;
+  background:#ffd;
+  color:#000;
+  font:normal normal normal 0.85em tahoma, arial, sans-serif;
+  padding:2px 4px 3px 5px;
+  text-align:left;
+  }
+* html .dbx-tooltip { width:195px; }
+
+/* use CSS2 system colors in CSS2 browsers 
+   but not safari, which doesn't support them */
+*[class="dbx-tooltip"]:lang(en) {
+  border-color:InfoText;
+  background:InfoBackground;
+  color:InfoText;
+  font:small-caption;
+  font-weight:normal;
+  }
+/* additional clone styles */
+.dbx-clone {
+  opacity: 0.8;
+}
+.dbx-content ul {
+  margin: 0; padding: 0;
+  list-style: none;
+}
+.dbx-content li a, .dbx-content li a:hover {
+  text-decoration: none; color: #666;
+}
+.dbx-content2 {
+  margin: 0px 1px 0px 1px;
+}
+
+/* Progress bars */
+div.progressbar {
+  padding: 2px;
+  background-color: #90A0B0;
+  width: 308px;
+}
+div.progressbar_inner {
+  min-width: 30px;
+  color: white;
+  background-color: #7080A0;
+  padding: 4px;
+}
+/* User notification - courtest of wikipedia.org (not sure if this is included with MediaWiki) */
+/* user notification thing */
+
+.usermessage {
+	background-color: #ffce7b;
+	border: 1px solid #ffa500;
+	color: black;
+	margin: 10px 0 1em;
+	padding: .5em 1em;
+	vertical-align: middle;
+}
+.usermessage a:link, .usermessage a:active, .usermessage a:visited {
+  color: #CA7520;
+}
+.usermessage a:hover {
+  color: #AA5500 !important;
+}
+div.thumbnail {
+  display: table;
+  border: 1px solid #AAAAAA;
+  background-color: #F0F0F0;
+  padding: 4px;
+  margin-bottom: 10px;
+}
+div.thumbnail-inner {
+  background-image: url(../../../images/thumbnail.png);
+  background-position: top right;
+  background-repeat: no-repeat;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/css/enano-shared.css~	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,401 @@
+/*
+ * Shared stuff that all Enano themes (should) use
+ */
+
+/* Information, warning, question, error, and wait boxes */
+div.error-box                     { background-image: url(../../../images/error.png);    background-repeat: no-repeat; background-color: #FFF4F4; border: 1px dashed #406080; padding: 10px 10px 10px 50px; margin: 1em 0 0 0; min-height: 25px; }
+div.info-box                      { background-image: url(../../../images/info.png);     background-repeat: no-repeat; background-color: #F4F4FF; border: 1px dashed #406080; padding: 10px 10px 10px 50px; margin: 1em 0 0 0; min-height: 25px; }
+div.warning-box                   { background-image: url(../../../images/warning.png);  background-repeat: no-repeat; background-color: #FFFFF4; border: 1px dashed #406080; padding: 10px 10px 10px 50px; margin: 1em 0 0 0; min-height: 25px; }
+div.question-box                  { background-image: url(../../../images/question.png); background-repeat: no-repeat; background-color: #F4FFF4; border: 1px dashed #406080; padding: 10px 10px 10px 50px; margin: 1em 0 0 0; min-height: 25px; }
+div.wait-box                      { background-image: url(../../../images/wait.png);     background-repeat: no-repeat; background-color: #FFF4FF; border: 1px dashed #406080; padding: 10px 10px 10px 50px; margin: 1em 0 0 0; min-height: 25px; }
+
+/* toolbar */
+div.toolbar {
+  border-bottom: 1px solid #909090;
+  background-color: #D0D0D0;
+  padding: 2px 0;
+  height: 22px;
+  font-family: arial, sans-serif;
+  font-size: 8pt;
+}
+div.toolbar ul {
+  margin: 0;
+  padding: 0;
+}
+div.toolbar ul li {
+  list-style: none;
+  margin: 0;
+  float: left;
+}
+div.toolbar a img {
+  opacity: 0.6;
+  /*filter: alpha(opacity=60);*/
+}
+div.toolbar a:hover img {
+  opacity: 1;
+  /*filter: alpha(opacity=100);*/
+}
+div.toolbar a {
+  display: block;
+  padding: 2px;
+  border: 1px solid transparent;
+  cursor: default;
+  width: auto;
+  color: #000000;
+  margin: 0 2px;
+  max-height: 16px;
+  text-decoration: none;
+}
+div.toolbar a:hover {
+  border: 1px solid #202090;
+  background-color: #ceceed;
+  color: #000000;
+  text-decoration: none;
+}
+div.toolbar a:active {
+  border: 1px solid #A0A0A0;
+  background-color: #E0E0E0;
+}
+div.toolbar img {
+  margin: 0;
+  padding: 0;
+  display: inline;
+  border-width: 0px;
+}
+div.toolbar a span {
+  position: relative;
+  top: -4px;
+}
+div.toolbar li span {
+  padding-left: 2px;
+  padding-right: 5px;
+}
+
+/* vertical toolbar */
+div.toolbar_vert {
+  border: 1px solid #909090;
+  background-color: #D0D0D0;
+  padding: 2px 0;
+}
+div.toolbar_vert ul {
+  margin: 0;
+  padding: 0;
+}
+div.toolbar_vert ul li {
+  list-style: none;
+  margin: 0;
+}
+div.toolbar_vert a img {
+  opacity: 0.6;
+  /*filter: alpha(opacity=60);*/
+}
+div.toolbar_vert a:hover img {
+  opacity: 1;
+  /*filter: alpha(opacity=100);*/
+}
+div.toolbar_vert a {
+  display: block;
+  padding: 2px;
+  border: 1px solid transparent;
+  cursor: default;
+  width: auto;
+  color: #000000;
+  margin: 0 2px;
+  max-height: 16px;
+  text-decoration: none;
+}
+div.toolbar_vert a:hover {
+  border: 1px solid #202090;
+  background-color: #ceceed;
+  color: #000000;
+  text-decoration: none;
+}
+div.toolbar_vert a:active {
+  border: 1px solid #A0A0A0;
+  background-color: #E0E0E0;
+}
+div.toolbar_vert img {
+  margin: 0;
+  padding: 0;
+  display: inline;
+  border-width: 0px;
+}
+div.toolbar_vert a span {
+  position: relative;
+  top: -4px;
+}
+div.toolbar_vert li span {
+  padding-left: 2px;
+  padding-right: 5px;
+}
+
+/* Tables */
+.tblholder                        { margin: 10px 0 0 0; padding: 0; border: 1px solid #AAAAAA; background-color: #E8E8E8; }
+
+/* The beautiful tables inside what may not obviously be mdg-comment divs */
+div.tblholder td.row1             { padding: 4px; background-color: #E0E0E0; }
+div.tblholder td.row2             { padding: 4px; background-color: #F0F0F0; }
+div.tblholder td.row3             { padding: 4px; background-color: #E8E8E8; }
+div.tblholder th                  { padding: 4px; background-color: #7080A0; font-weight: bold; text-align: center; color: #FFFFFF; }
+div.tblholder th.subhead          { padding: 4px; background-color: #90A0B0; font-weight: bold; text-align: center; color: #FFFFFF; }
+div.tblholder table               { background-color: #FFFFFF; width: 100%; }
+
+/* Well, not Midget and not comments (usually), but that's what the class is called ;-). Basically an informational window or used as a wrapper for tables. */
+.mdg-comment, .mdg-infobox        { margin-left: 1em; padding: 7px; border: 1px solid #AAAAAA; background-color: #E8E8E8; }
+
+/* JWS window theming */
+div.jswindow                      { border: 2px solid #7090B0; border-top: 5px solid #7090B0; padding: 0px; font-family: Trebuchet MS, tahoma, verdana, arial, sans-serif; font-size: 9pt; display: none; position: absolute; background-color: #FFFFFF; }
+div.titlebar                      { background-color: #7090B0; color: #FFFFFF; font-family: Trebuchet MS, tahoma, verdana, arial, sans-serif; font-size: 9pt; padding-bottom: 4px; cursor: default; }
+div.titlebar div.closebtn         { width: 16px; height: 16px; border: 1px solid #B0D0F0; background-color: #90B0D0; display: block; }
+div.titlebar div.closebtn:hover   { width: 16px; height: 16px; border: 1px solid #FFFFFF; background-color: #B0D0F0; display: block; }
+div.titlebar table, div.titlebar td { margin: 0; padding: 0; }
+div.jswindow div.content          { padding: 10px; margin: 0; background-color: #FFFFFF; }
+
+/* Search results */
+div.search-result h3   { font-size: 14pt; margin: 10px 0 0 0; }
+div.search-result h3 a { color: blue !important; font-weight: normal; padding-bottom: 0; }
+div.search-result p    { margin: 10px 0 0 0 !important; font-family: arial, helvetica, sans-serif; font-size: 10pt; }
+div.search-result span.search-result-info { color: green; }
+div.search-result span.search-term, div.search-result span.title-search-term { background-color: #FFFFC0; font-weight: bold; }
+
+/*
+ * Search box
+ */
+ 
+input.js-search-box {
+  font-size: 13px;
+  margin: 0;
+  padding: 1px !important;
+  background-image: url(../../../images/search-box-normal.gif);
+  height: 15px;
+  background-repeat: repeat-x;
+  border-width: 1px;
+  border-style: solid;
+  border-color: #6c6c6c;
+  color: #C0C0C0;
+}
+
+input.js-search-box:focus {
+  background-image: url(../../../images/search-box-hilite.gif);
+  color: #666;
+}
+
+div.js-search-submit {
+  display: block;
+  position: absolute;
+  width: 24px;
+  height: 19px;
+  font-size: 1px;
+  line-height: 19px;
+  clip: rect(0px, 24px, 19px, 0px);
+  overflow: hidden;
+  margin: 0;
+  padding: 0;
+  background: transparent url(../../../images/search-btn-normal.png) no-repeat !important;
+  background-repeat: no-repeat;
+  cursor: pointer;
+}
+
+div.js-search-submit:hover {
+  background-image: url(../../../images/search-btn-hilite.png);
+}
+
+input[type ^="text"].username, input[type ^="password"].password {
+  padding: 2px 2px 2px 27px;
+  width: 96px;
+  height: 15px;
+  border: 0px none #000;
+  font-size: 11px;
+}
+input[type ^="text"].username {
+  background-image: url(../../../images/login-username.png);
+}
+input[type ^="password"].password {
+  background-image: url(../../../images/login-password.png);
+}
+
+/*
+ * jBox menu system
+ */
+
+div.menu, div.menu_nojs {
+  background-color: #D0D0D0;
+  border: 1px solid #A0A0A0;
+  font-size: 9pt;
+}
+div.menu a, div.menu div.label {
+  padding: 2pt 5px;
+  text-decoration: none;
+  display: block;
+  float: left;
+  color: #404040;
+}
+div.menu_nojs a, div.menu_nojs div.label {
+  padding: 2pt 5px;
+  text-decoration: none;
+  display: block;
+  color: #404040;
+}
+div.menu div.label, div.menu_nojs div.label {
+  color: #101010;
+}
+div.menu span.sep, div.menu_nojs span.sep {
+  display: block;
+  float: left;
+  width: 5px;
+}
+div.menu div.multopts, div.menu_nojs div.multopts {
+  line-height: 17pt;
+}
+div.menu div.multopts a, div.menu div.multopts div.label, div.menu_nojs div.multopts a, div.menu_nojs div.multopts div.label {
+  float: none;
+  display: inline;
+}
+div.menu a:hover, div.menu_nojs a:hover {
+  color: #FFFFFF;
+  background-color: #808080;
+}
+div.menu input[type ^="text"], div.menu input[type ^="password"], div.menu_nojs input[type ^="text"], div.menu_nojs input[type ^="password"] {
+  border-width: 0;
+  font-size: 9pt;
+  padding: 4px 5px;
+  max-width: 70px;
+  background-color: #E0E0E0;
+}
+div.menu input[type ^="text"]:hover, div.menu input[type ^="password"]:hover, div.menu_nojs input[type ^="text"]:hover, div.menu_nojs input[type ^="password"]:hover {
+  background-color: #E8E8E8;
+}
+div.menu input[type ^="text"]:focus, div.menu input[type ^="password"]:focus, div.menu_nojs input[type ^="text"]:focus, div.menu_nojs input[type ^="password"]:focus {
+  background-color: #F0F0F0;
+}
+div.menu input[type ^="button"], div.menu input[type ^="submit"], div.menu_nojs input[type ^="button"], div.menu_nojs input[type ^="submit"] {
+  border-width: 0;
+  font-size: 9pt;
+  padding: 3px 5px;
+  max-width: 70px;
+}
+div.menu a.current, div.menu a.current:hover, div.menu_nojs a.current, div.menu_nojs a.current:hover {
+  color: #FFFFFF;
+  background-color: #505050;
+}
+div.menu ul {
+  display: none;
+  position: absolute;
+  padding: 0;
+  margin: 0;
+  background-color: #D0D0D0;
+  border: 1px solid #A0A0A0;
+  min-width: 120px;
+}
+div.menu_nojs ul {
+  display: block;
+  clear: both;
+}
+div.menu ul li, div.menu_nojs ul li {
+  list-style: none;
+}
+div.menu ul a, div.menu_nojs ul a {
+  float: none;
+  margin: 0;
+}
+span.menuclear {
+  font-size: 1px;
+  height: 0px;
+  width: 0px;
+  clear: left;
+  line-height: 0px;
+  display: block;
+}
+
+/*
+ * Docking Boxes code (for the sidebar editor)
+ */
+ 
+/* group container(s) */
+#sbedit {
+  margin: 0;
+  padding: 0;
+  /* position:relative; /* additional outer containers must also have position:relative */
+}
+/* keyboard navigation tooltip */
+.dbx-tooltip {
+  display:block;
+  position:absolute;
+  margin:36px 0 0 125px;
+  width:185px;
+  border:1px solid #000;
+  background:#ffd;
+  color:#000;
+  font:normal normal normal 0.85em tahoma, arial, sans-serif;
+  padding:2px 4px 3px 5px;
+  text-align:left;
+  }
+* html .dbx-tooltip { width:195px; }
+
+/* use CSS2 system colors in CSS2 browsers 
+   but not safari, which doesn't support them */
+*[class="dbx-tooltip"]:lang(en) {
+  border-color:InfoText;
+  background:InfoBackground;
+  color:InfoText;
+  font:small-caption;
+  font-weight:normal;
+  }
+/* additional clone styles */
+.dbx-clone {
+  opacity: 0.8;
+}
+.dbx-content ul {
+  margin: 0; padding: 0;
+  list-style: none;
+}
+.dbx-content li a, .dbx-content li a:hover {
+  text-decoration: none; color: #666;
+}
+.dbx-content2 {
+  margin: 0px 1px 0px 1px;
+}
+
+/* Progress bars */
+div.progressbar {
+  padding: 2px;
+  background-color: #90A0B0;
+  width: 308px;
+}
+div.progressbar_inner {
+  min-width: 30px;
+  color: white;
+  background-color: #7080A0;
+  padding: 4px;
+}
+/* User notification - courtest of wikipedia.org (not sure if this is included with MediaWiki) */
+/* user notification thing */
+
+.usermessage {
+	background-color: #ffce7b;
+	border: 1px solid #ffa500;
+	color: black;
+	margin: 10px 0 1em;
+	padding: .5em 1em;
+	vertical-align: middle;
+}
+.usermessage a:link, .usermessage a:active, .usermessage a:visited {
+  color: #CA7520;
+}
+.usermessage a:hover {
+  color: #AA5500 !important;
+}
+div.thumbnail {
+  display: table;
+  border: 1px solid #AAAAAA;
+  background-color: #F0F0F0;
+  padding: 4px;
+  margin-bottom: 10px;
+  padding-bottom: 0;
+}
+div.thumbnail-inner {
+  background-image: url(../../../images/thumbnail.png);
+  background-position: top right;
+  background-repeat: no-repeat;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/dbx-key.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,63 @@
+function dbx_set_key()
+{
+  //initialise the docking boxes manager
+  var manager = new dbxManager('main');   //session ID [/-_a-zA-Z0-9/]
+  
+  //onstatechange fires when any group state changes
+	manager.onstatechange = function()
+	{
+		//copy the state string to a local var
+		var state = this.state;
+
+		//remove group name and open/close state tokens
+		state = state.replace(/sbedit_(left|right)=/ig, '').replace(/[\-\+]/g, '');
+
+		//split into an array
+    state = state.split('&');
+    
+		//output field
+		var field = document.getElementById('divOrder_Left');
+    field.value = state[0];
+    var field = document.getElementById('divOrder_Right');
+    field.value = state[1];
+
+		//return value determines whether cookie is set
+		return false;
+	};
+  
+  //create new docking boxes group
+  var sbedit_left = new dbxGroup(
+    'sbedit_left',   // container ID [/-_a-zA-Z0-9/]
+    'vertical', // orientation ['vertical'|'horizontal']
+    '7',        // drag threshold ['n' pixels]
+    'no',       // restrict drag movement to container axis ['yes'|'no']
+    '10',       // animate re-ordering [frames per transition, or '0' for no effect]
+    'no',       // include open/close toggle buttons ['yes'|'no']
+    'open',     // default state ['open'|'closed']
+    'open',     // word for "open", as in "open this box"
+    'close',    // word for "close", as in "close this box"
+    'click-down and drag to move this box',     // sentence for "move this box" by mouse
+    'click to %toggle% this box',               // pattern-match sentence for "(open|close) this box" by mouse
+    'use the arrow keys to move this box',      // sentence for "move this box" by keyboard
+    ', or press the enter key to %toggle% it',  // pattern-match sentence-fragment for "(open|close) this box" by keyboard
+    '%mytitle%  [%dbxtitle%]'                   // pattern-match syntax for title-attribute conflicts
+  );
+  
+  //create new docking boxes group
+  var sbedit_right = new dbxGroup(
+    'sbedit_right',   // container ID [/-_a-zA-Z0-9/]
+    'vertical', // orientation ['vertical'|'horizontal']
+    '7',        // drag threshold ['n' pixels]
+    'no',       // restrict drag movement to container axis ['yes'|'no']
+    '10',       // animate re-ordering [frames per transition, or '0' for no effect]
+    'no',       // include open/close toggle buttons ['yes'|'no']
+    'open',     // default state ['open'|'closed']
+    'open',     // word for "open", as in "open this box"
+    'close',    // word for "close", as in "close this box"
+    'click-down and drag to move this box',     // sentence for "move this box" by mouse
+    'click to %toggle% this box',               // pattern-match sentence for "(open|close) this box" by mouse
+    'use the arrow keys to move this box',      // sentence for "move this box" by keyboard
+    ', or press the enter key to %toggle% it',  // pattern-match sentence-fragment for "(open|close) this box" by keyboard
+    '%mytitle%  [%dbxtitle%]'                   // pattern-match syntax for title-attribute conflicts
+  );
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/dbx.css	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,34 @@
+/****************************************************************
+  Docking Boxes core CSS: YOU MUST NOT CHANGE OR OVERRIDE THESE 
+*****************************************************************/
+.dbx-clone {
+	position:absolute;
+	visibility:hidden;
+	}
+.dbx-clone, .dbx-clone .dbx-handle-cursor {
+	cursor:move !important;
+	}
+.dbx-dummy {
+	display:block;
+	width:0;
+	height:0;
+	overflow:hidden;
+	}
+.dbx-group, .dbx-box, .dbx-handle {
+	position:relative;
+	display:block;
+	}
+
+
+
+/****************************************************************
+  avoid padding, margins or borders on dbx-box, 
+  to reduce visual discrepancies between it and the clone.  
+  overall, dbx-box is best left as visually unstyled as possible 
+*****************************************************************/
+.dbx-box {
+	margin:0;
+	padding:0;
+	border:none;
+	}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/dbx.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,6 @@
+// DBX2.05 :: Docking Boxes (dbx)
+// *****************************************************
+// DOM scripting by brothercake -- http://www.brothercake.com/
+// GNU Lesser General Public License -- http://www.gnu.org/licenses/lgpl.html
+//******************************************************
+var dbx;function dbxManager(sid){dbx = this;if(!/^[-_a-z0-9]+$/i.test(sid)) { alert('Error from dbxManager:\n"' + sid + '" is an invalid session ID'); return; }this.supported = !(document.getElementsByTagName('*').length == 0 || (navigator.vendor == 'KDE' && typeof window.sidebar == 'undefined'));if(!this.supported) { return; }this.etype = typeof document.addEventListener != 'undefined' ? 'addEventListener' : typeof document.attachEvent != 'undefined' ? 'attachEvent' : 'none';this.eprefix = (this.etype == 'attachEvent' ? 'on' : '');if(typeof window.opera != 'undefined' && parseFloat(navigator.userAgent.toLowerCase().split(/opera[\/ ]/)[1].split(' ')[0], 10) < 7.5){this.etype = 'none';}if(this.etype == 'none') { this.supported = false; return; }this.running = 0;this.sid = sid;this.savedata = {};this.cookiestate = this.getCookieState();};dbxManager.prototype.setCookieState = function(){var now = new Date();now.setTime(now.getTime() + (365*24*60*60*1000));var str = '';for(j in this.savedata){if(typeof this.savedata[j]!='function'){str += j + '=' + this.savedata[j] + '&'}}this.state = str.replace(/^(.+)&$/, '$1');this.cookiestring = this.state.replace(/,/g, '|');this.cookiestring = this.cookiestring.replace(/=/g, ':');if(typeof this.onstatechange == 'undefined' || this.onstatechange()){document.cookie = 'dbx-' + this.sid + '='+ this.cookiestring+ '; expires=' + now.toGMTString()+ '; path=/';}};dbxManager.prototype.getCookieState = function(){this.cookiestate = null;if(document.cookie){if(document.cookie.indexOf('dbx-' + this.sid)!=-1){this.cookie = document.cookie.split('dbx-' + this.sid + '=')[1].split(';')[0].split('&');for(var i in this.cookie){if(typeof this.cookie[i]!='function'){this.cookie[i] = this.cookie[i].replace(/\|/g, ',');this.cookie[i]= this.cookie[i].replace(/:/g, '=');this.cookie[i] = this.cookie[i].split('=');this.cookie[i][1] = this.cookie[i][1].split(',');}}this.cookiestate = {};for(i in this.cookie){if(typeof this.cookie[i]!='function'){this.cookiestate[this.cookie[i][0]] = this.cookie[i][1];}}}}return this.cookiestate;};dbxManager.prototype.addDataMember = function(gid, order){this.savedata[gid] = order;};dbxManager.prototype.createElement = function(tag){return typeof document.createElementNS != 'undefined' ? document.createElementNS('http://www.w3.org/1999/xhtml', tag) : document.createElement(tag);};dbxManager.prototype.getTarget = function(e, pattern, node){if(typeof node != 'undefined'){var target = node;}else{target = typeof e.target != 'undefined' ? e.target : e.srcElement;}var regex = new RegExp(pattern, '');while(!regex.test(target.className)){target = target.parentNode;}return target;};function dbxGroup(gid, dir, thresh, fix, ani, togs, def, open, close, move, toggle, kmove, ktoggle, syntax){if(!/^[-_a-z0-9]+$/i.test(gid)) { alert('Error from dbxGroup:\n"' + gid + '" is an invalid container ID'); return; }this.container = document.getElementById(gid);if(this.container == null || !dbx.supported) { return; }var self = this;this.gid = gid;this.dragok = false;this.box = null;this.vertical = dir == 'vertical';this.threshold = parseInt(thresh, 10);this.restrict = fix == 'yes';this.resolution = parseInt(ani, 10);this.toggles = togs == 'yes';this.defopen = def != 'closed';this.vocab = {'open' : open,'close' : close,'move' : move,'toggle' : toggle,'kmove' : kmove,'ktoggle' : ktoggle,'syntax' : syntax};this.container.style.position = 'relative';this.container.style.display = 'block';if(typeof window.opera != 'undefined'){this.container.style.display = 'run-in';}this.boxes = [];this.buttons = [];this.order = [];this.eles = this.container.getElementsByTagName('*');for(var i=0; i<this.eles.length; i++){if(/dbx\-box/i.test(this.eles[i].className) && !/dbx\-dummy/i.test(this.eles[i].className)){this.eles[i].style.position = 'relative';this.eles[i].style.display = 'block';this.boxes.push(this.eles[i]);this.eles[i].className += ' dbx-box-open';this.eles[i].className += ' dbxid' + this.order.length;this.order.push(this.order.length.toString() + '+');this.eles[i][dbx.etype](dbx.eprefix + 'mousedown', function(e){if(!e) { e = window.event; }self.mousedown(e, dbx.getTarget(e, 'dbx\-box'));}, false);}if(/dbx\-handle/i.test(this.eles[i].className)){this.eles[i].style.position = 'relative';this.eles[i].style.display = 'block';this.eles[i].className += ' dbx-handle-cursor';this.eles[i].setAttribute('title', this.eles[i].getAttribute('title') == null || this.eles[i].title == '' ? this.vocab.move : this.vocab.syntax.replace('%mytitle%', this.eles[i].title).replace('%dbxtitle%', this.vocab.move));if(this.toggles){this.buttons.push(this.addToggleBehavior(this.eles[i]));}else{this.eles[i][dbx.etype](dbx.eprefix + 'key' + (typeof document.uniqueID != 'undefined' || navigator.vendor == 'Apple Computer, Inc.' ? 'down' : 'press'), function(e){if(!e) { e = window.event; }return self.keypress(e, dbx.getTarget(e, 'dbx\-handle'));}, false);this.eles[i][dbx.etype](dbx.eprefix + 'focus', function(e){if(!e) { e = window.event; }self.createTooltip(null, dbx.getTarget(e, 'dbx\-handle'));}, false);this.eles[i][dbx.etype](dbx.eprefix + 'blur', function(){self.removeTooltip();}, false);}}}dbx.addDataMember(this.gid, this.order.join(','));var dummy = this.container.appendChild(dbx.createElement('span'));dummy.className = 'dbx-box dbx-dummy';dummy.style.display = 'block';dummy.style.width = '0';dummy.style.height = '0';dummy.style.overflow = 'hidden';if(this.vertical) { dummy.className += ' dbx-offdummy'; }this.boxes.push(dummy);if(dbx.cookiestate != null && typeof dbx.cookiestate[this.gid] != 'undefined'){var num = dbx.cookiestate[this.gid].length;if(num == this.boxes.length - 1){for(i=0; i<num; i++){var index = parseInt(dbx.cookiestate[this.gid][i], 10);this.container.insertBefore(this.boxes[index], dummy);if(this.toggles && /\-$/.test(dbx.cookiestate[this.gid][i])){this.toggleBoxState(this.buttons[index], false);}}this.getBoxOrder();}}else if(!this.defopen && this.toggles){var len = this.buttons.length;for(i=0; i<len; i++){this.toggleBoxState(this.buttons[i], true);}}document[dbx.etype](dbx.eprefix + 'mouseout', function(e){if(typeof e.target == 'undefined') { e = window.event; e.relatedTarget = e.toElement; }if(e.relatedTarget == null){self.mouseup(e);}}, false);document[dbx.etype](dbx.eprefix + 'mousemove', function(e){self.mousemove(e);return !self.dragok;}, false);document[dbx.etype](dbx.eprefix + 'mouseup', function(e){self.mouseup(e);}, false);this.keydown = false;document[dbx.etype](dbx.eprefix + 'keydown', function(){self.keydown = true;}, false);document[dbx.etype](dbx.eprefix + 'keyup', function(){self.keydown = false;}, false);};dbxGroup.prototype.addToggleBehavior = function(){var self = this;var button = arguments[0].appendChild(dbx.createElement('a'));button.appendChild(document.createTextNode('\u00a0'));button.style.cursor = 'pointer';button.href = 'javascript:void(null)';button.className = ( button.className ) ? button.className+' dbx-toggle dbx-toggle-open' : 'dbx-toggle dbx-toggle-open';button.setAttribute('title', this.vocab.toggle.replace('%toggle%', this.vocab.close));button.hasfocus = typeof window.opera != 'undefined' || navigator.vendor == 'Apple Computer, Inc.' ? null : false;this.tooltip = null;button.onclick = function(){if(this.hasfocus === true || this.hasfocus === null){self.removeTooltip();self.toggleBoxState(this, true);}};button['onkey' + (typeof document.uniqueID != 'undefined' || navigator.vendor == 'Apple Computer, Inc.' ? 'down' : 'press')] = function(e){if(!e) { e = window.event; }return self.keypress(e, this);};button.onfocus = function(){var len = self.buttons.length;for(var i=0; i<len; i++){self.buttons[i].className = self.buttons[i].className.replace(/[ ](dbx\-toggle\-hilite\-)(open|closed)/, '');}var isopen = (/dbx\-toggle\-open/.test(this.className));this.className += ' dbx-toggle-hilite-' + (isopen ? 'open' : 'closed');self.createTooltip(isopen, this);this.isactive = true;if(this.hasfocus !== null) { this.hasfocus = true; }};button.onblur = function(){this.className = this.className.replace(/[ ](dbx\-toggle\-hilite\-)(open|closed)/, '');self.removeTooltip();if(this.hasfocus !== null) { this.hasfocus = false; }};return button;};dbxGroup.prototype.toggleBoxState = function(button, regen){var isopen = (/dbx\-toggle\-open/.test(button.className));var parent = dbx.getTarget(null, 'dbx\-box', button);dbx.box = parent;dbx.toggle = button;if(typeof dbx.container == 'undefined'){dbx.group = dbx.getTarget(null, 'dbx\-group', parent);}else { dbx.group = dbx.container; }if((!isopen && (typeof dbx.onboxopen == 'undefined' || dbx.onboxopen()))||(isopen && (typeof dbx.onboxclose == 'undefined' || dbx.onboxclose()))){cn = 'dbx-toggle dbx-toggle-' + (isopen ? 'closed' : 'open');button.className = ( button.className ) ? button.className+' '+cn : cn;button.title = this.vocab.toggle.replace('%toggle%', isopen ? this.vocab.open : this.vocab.close);if(typeof button.isactive != 'undefined'){button.className += ' dbx-toggle-hilite-' + (isopen ? 'closed' : 'open')}parent.className = parent.className.replace(/[ ](dbx-box-)(open|closed)/, ' $1' + (isopen ? 'closed' : 'open'));if(regen) { this.getBoxOrder(); }}};dbxGroup.prototype.shiftBoxPosition = function(e, anchor, positive){var parent = dbx.getTarget(null, 'dbx\-box', anchor);dbx.group = this.container;dbx.box = parent;dbx.event = e;if(typeof dbx.onboxdrag == 'undefined' || dbx.onboxdrag()){var positions = [];var len = this.boxes.length;for(var i=0; i<len; i++){positions[i] = [i, this.boxes[i][this.vertical ? 'offsetTop' : 'offsetLeft']];if(parent == this.boxes[i]) { this.idref = i; }}positions.sort(this.compare);for(i=0; i<len; i++){if(positions[i][0] == this.idref){if((positive && i < len - 2) || (!positive && i > 0)){var sibling = this.boxes[positions[i + (positive ? 1 : -1)][0]];if(this.resolution > 0){var visipos = { 'x' : parent.offsetLeft, 'y' : parent.offsetTop };var siblingpos = { 'x' : sibling.offsetLeft, 'y' : sibling.offsetTop };}var obj = { 'insert' : (positive ? sibling : parent), 'before' : (positive ? parent : sibling) };this.container.insertBefore(obj.insert, obj.before);if(this.resolution > 0){var animators ={'sibling' : new dbxAnimator(this, sibling, siblingpos, this.resolution, true, anchor),'parent' : new dbxAnimator(this, parent, visipos, this.resolution, true, anchor)};}else{anchor.focus();}break;}}}this.getBoxOrder();}};dbxGroup.prototype.compare = function(a, b){return a[1] - b[1];};dbxGroup.prototype.createTooltip = function(isopen, anchor){if(this.keydown){this.tooltip = this.container.appendChild(dbx.createElement('span'));this.tooltip.style.visibility = 'hidden';this.tooltip.className = 'dbx-tooltip';if(isopen != null){this.tooltip.appendChild(document.createTextNode(this.vocab.kmove + this.vocab.ktoggle.replace('%toggle%', isopen ? this.vocab.close : this.vocab.open)));}else{this.tooltip.appendChild(document.createTextNode(this.vocab.kmove));}var parent = dbx.getTarget(null, 'dbx\-box', anchor);this.tooltip.style.left = parent.offsetLeft + 'px';this.tooltip.style.top = parent.offsetTop + 'px';var tooltip = this.tooltip;window.setTimeout(function(){if(tooltip != null) { tooltip.style.visibility = 'visible'; }}, 500);}};dbxGroup.prototype.removeTooltip = function(){if(this.tooltip != null){this.tooltip.parentNode.removeChild(this.tooltip);this.tooltip = null;}};dbxGroup.prototype.mousedown = function(e, box){var node = typeof e.target != 'undefined' ? e.target : e.srcElement;if(node.nodeName == '#text') { node = node.parentNode; }if(!/dbx\-(toggle|box|group)/i.test(node.className)){while(!/dbx\-(handle|box|group)/i.test(node.className)){node = node.parentNode;}}if(/dbx\-handle/i.test(node.className)){this.removeTooltip();this.released = false;this.initial = { 'x' : e.clientX, 'y' : e.clientY };this.current = { 'x' : 0, 'y' : 0 };this.createCloneBox(box);if(typeof e.preventDefault != 'undefined' ) { e.preventDefault(); }if(typeof document.onselectstart != 'undefined'){document.onselectstart = function() { return false; }}}};dbxGroup.prototype.mousemove = function(e){if(this.dragok && this.box != null){this.positive = this.vertical ? (e.clientY > this.current.y ? true : false) : (e.clientX > this.current.x ? true : false);this.current = { 'x' : e.clientX, 'y' : e.clientY };var overall = { 'x' : this.current.x - this.initial.x, 'y' : this.current.y - this.initial.y };if(((overall.x >= 0 && overall.x <= this.threshold) || (overall.x <= 0 && overall.x >= 0 - this.threshold))&&((overall.y >= 0 && overall.y <= this.threshold) || (overall.y <= 0 && overall.y >= 0 - this.threshold))){this.current.x -= overall.x;this.current.y -= overall.y;}if(this.released || overall.x > this.threshold || overall.x < (0 - this.threshold) || overall.y > this.threshold || overall.y < (0 - this.threshold)){dbx.group = this.container;dbx.box = this.box;dbx.event = e;if(typeof dbx.onboxdrag == 'undefined' || dbx.onboxdrag()){this.released = true;if(!this.restrict || !this.vertical) { this.boxclone.style.left = (this.current.x - this.difference.x) + 'px'; }if(!this.restrict || this.vertical) { this.boxclone.style.top = (this.current.y - this.difference.y) + 'px'; }this.moveOriginalToPosition(this.current.x, this.current.y);if(typeof e.preventDefault != 'undefined' ) { e.preventDefault(); }}}}return true;};dbxGroup.prototype.mouseup = function(e){if(this.box != null){this.moveOriginalToPosition(e.clientX, e.clientY);this.removeCloneBox();this.getBoxOrder();if(typeof document.onselectstart != 'undefined'){document.onselectstart = function() { return true; }}}this.dragok = false;};dbxGroup.prototype.keypress = function(e, anchor){if(/^(3[7-9])|(40)$/.test(e.keyCode)){this.removeTooltip();if((this.vertical && /^(38|40)$/.test(e.keyCode)) || (!this.vertical && /^(37|39)$/.test(e.keyCode))){this.shiftBoxPosition(e, anchor, /^[3][78]$/.test(e.keyCode) ? false : true);if(typeof e.preventDefault != 'undefined') { e.preventDefault(); }else { return false; }typeof e.stopPropagation != 'undefined' ? e.stopPropagation() : e.cancelBubble = true;this.keydown = false;}}return true;};dbxGroup.prototype.getBoxOrder = function(){this.order = [];var len = this.eles.length;for(var j=0; j<len; j++){if(/dbx\-box/i.test(this.eles[j].className) && !/dbx\-(clone|dummy)/i.test(this.eles[j].className)){this.order.push(this.eles[j].className.split('dbxid')[1] + (/dbx\-box\-open/i.test(this.eles[j].className) ? '+' : '-'));}}dbx.savedata[this.gid] = this.order.join(',');dbx.setCookieState();};dbxGroup.prototype.createClone = function(){var clone = this.container.appendChild(arguments[0].cloneNode(true));clone.className += ' dbx-clone';clone.style.position = 'absolute';clone.style.visibility = 'hidden';clone.style.zIndex = arguments[1];clone.style.left = arguments[2].x + 'px';clone.style.top = arguments[2].y + 'px';clone.style.width = arguments[0].offsetWidth + 'px';clone.style.height = arguments[0].offsetHeight + 'px';return clone;};dbxGroup.prototype.createCloneBox = function(box){this.box = box;this.position = { 'x' : this.box.offsetLeft, 'y' : this.box.offsetTop };this.difference = { 'x' : (this.initial.x - this.position.x), 'y' : (this.initial.y - this.position.y) };this.boxclone = this.createClone(this.box, 30000, this.position);this.boxclone.style.cursor = 'move';this.dragok = true;};dbxGroup.prototype.removeCloneBox = function(){this.container.removeChild(this.boxclone);this.box.style.visibility = 'visible';this.box = null;};dbxGroup.prototype.moveOriginalToPosition = function(clientX, clientY){var cloneprops = {'xy' : this.vertical ? clientY - this.difference.y : clientX - this.difference.x,'wh' : this.vertical ? this.boxclone.offsetHeight : this.boxclone.offsetWidth};this.box.style.visibility = 'hidden';this.boxclone.style.visibility = 'visible';var len = this.boxes.length;for(var i=0; i<len; i++){var boxprops = {'xy' : this.vertical ? this.boxes[i].offsetTop : this.boxes[i].offsetLeft,'wh' : this.vertical ? this.boxes[i].offsetHeight : this.boxes[i].offsetWidth};if((this.positive && cloneprops.xy + cloneprops.wh > boxprops.xy && cloneprops.xy < boxprops.xy)||(!this.positive && cloneprops.xy < boxprops.xy && cloneprops.xy + cloneprops.wh > boxprops.xy)){if(this.boxes[i] == this.box) { return; }var sibling = this.box.nextSibling;while(sibling.className == null || !/dbx\-box/.test(sibling.className)){sibling = sibling.nextSibling;}if(this.boxes[i] == sibling) { return; }if(this.resolution > 0){if(this.box[this.vertical ? 'offsetTop' : 'offsetLeft'] < boxprops.xy){var visibox = this.boxes[i].previousSibling;while(visibox.className == null || !/dbx\-box/.test(visibox.className)){visibox = visibox.previousSibling;}}else{visibox = this.boxes[i];}var visipos = { 'x' : visibox.offsetLeft, 'y' : visibox.offsetTop };}var prepos = { 'x' : this.box.offsetLeft, 'y' : this.box.offsetTop };this.container.insertBefore(this.box, this.boxes[i]);this.initial.x += (this.box.offsetLeft - prepos.x);this.initial.y += (this.box.offsetTop - prepos.y);if(this.resolution > 0 && visibox != this.box){var animator = new dbxAnimator(this, visibox, visipos, this.resolution, false, null);}else{}break;}}};function dbxAnimator(caller, box, pos, res, kbd, anchor){this.caller = caller;this.box = box;this.timer = null;var before = pos[this.caller.vertical ? 'y' : 'x'];var after = this.box[this.caller.vertical ? 'offsetTop' : 'offsetLeft'];if(before != after){if(dbx.running > this.caller.boxes.length - 1) { return; }var clone = this.caller.createClone(this.box, 29999, arguments[2]);clone.style.visibility = 'visible';this.box.style.visibility = 'hidden';this.animateClone(clone,before,after > before ? after - before : 0 - (before - after),this.caller.vertical ? 'top' : 'left',res,kbd,anchor);}};dbxAnimator.prototype.animateClone = function(clone, current, change, dir, res, kbd, anchor){var self = this;var count = 0;dbx.running ++;this.timer = window.setInterval(function(){count ++;current += change / res;clone.style[dir] = current + 'px';if(count == res){window.clearTimeout(self.timer);self.timer = null;dbx.running --;self.caller.container.removeChild(clone);self.box.style.visibility = 'visible';if(kbd){if(anchor != null && anchor.parentNode.style.visibility != 'hidden'){anchor.focus();}else if(self.caller.toggles){var button = self.caller.buttons[parseInt(self.box.className.split('dbxid')[1],10)];if(button != null && typeof button.isactive != 'undefined'){button.focus();}}}}}, 20);};if(typeof window.attachEvent != 'undefined'){window.attachEvent('onunload', function(){var ev = ['mousedown', 'mousemove', 'mouseup', 'mouseout', 'click', 'keydown', 'keyup', 'focus', 'blur', 'selectstart', 'statechange', 'boxdrag', 'boxopen', 'boxclose'];var el = ev.length;var dl = document.all.length;for(var i=0; i<dl; i++){for(var j=0; j<el; j++){document.all[i]['on' + ev[j]] = null;}}});}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/jsres.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,94 @@
+<?php
+
+/*
+ * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
+ * Version 1.0 (Banshee)
+ * Copyright (C) 2006-2007 Dan Fuhry
+ * jsres.php - the Enano client-side runtime, a.k.a. AJAX on steroids
+ *
+ * This program is Free Software; you can redistribute 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 details.
+ */
+
+if(!isset($_GET['title'])) $_GET['title'] = 'null';
+require('../common.php');
+
+define('ENABLE_COMPRESSION', '');
+
+ob_start();
+header('Content-type: text/javascript');
+
+$file = ( isset($_GET['file']) ) ? $_GET['file'] : 'enano-lib-basic.js';
+
+if(!preg_match('/^([a-z0-9_-]+)\.js$/i', $file))
+  die('// ERROR: Hacking attempt');
+
+$fname = './static/' . $file;
+if ( !file_exists($fname) )
+  die('// ERROR: File not found: ' . $file);
+
+$everything = file_get_contents($fname);
+
+$mtime = filemtime($fname);
+header('Last-Modified: '.date('D, d M Y H:i:s T', $mtime));
+header('Content-disposition: attachment; filename=' . $file);
+
+if(defined('ENABLE_COMPRESSION'))
+{
+  echo "/*
+ * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
+ * Version 1.0 (Banshee)
+ * [Aggressively compressed] Javascript client code
+ * Copyright (C) 2006-2007 Dan Fuhry
+ * Enano is Free Software, licensed under the GNU General Public License; see http://www.enanocms.org/ for details.
+ */
+
+";
+  
+  $cache_file = ENANO_ROOT . '/cache/jsres-' . $file . '.php';
+  
+  if ( file_exists($cache_file) )
+  {
+    $cached = file_get_contents ( $cache_file );
+    $data = unserialize ( $cached );
+    if ( $data['md5'] == md5 ( $everything ) )
+    {
+      echo "// The code in this file was fetched from cache\n\n";
+      echo $data['code'];
+      exit;
+    }
+  }
+  
+  if ( getConfig('cache_thumbs') == '1' )
+  {
+    $js_compressor = new JavascriptCompressor();
+    $packed = $js_compressor->getPacked($everything);
+    $data = Array(
+      'md5' => md5 ( $everything ),
+      'code' => $packed
+      );
+    echo "// The code in this file was fetched from the static scripts and compressed (packed code cached)\n\n";
+    echo $packed;
+    
+    $fh = @fopen($cache_file, 'w');
+    if (!$fh)
+      die('// ERROR: Can\'t open cache file for writing');
+    fwrite($fh, serialize ( $data ) );
+    fclose($fh);
+    
+    exit;
+  }
+  
+  echo "// The code in this file was not compressed because packed-script caching is disabled\n\n";
+  echo $everything;
+  
+}
+else
+{
+  echo "// The code in this file was not compressed because all script compression is disabled\n\n";
+  echo $everything;
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/md5.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,30 @@
+// Javascript implementation of the MD5 algorithm - used for encrypting password before sending them over the Internet
+var hexcase = 0; var b64pad  = ""; var chrsz   = 8;
+function hex_md5(s){ return binl2hex(core_md5(str2binl(s), s.length * chrsz));}
+function b64_md5(s){ return binl2b64(core_md5(str2binl(s), s.length * chrsz));}
+function str_md5(s){ return binl2str(core_md5(str2binl(s), s.length * chrsz));}
+function hex_hmac_md5(key, data) { return binl2hex(core_hmac_md5(key, data)); }
+function b64_hmac_md5(key, data) { return binl2b64(core_hmac_md5(key, data)); }
+function str_hmac_md5(key, data) { return binl2str(core_hmac_md5(key, data)); }
+function md5_vm_test() { return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72"; }
+function core_md5(x, len) { x[len >> 5] |= 0x80 << ((len) % 32); x[(((len + 64) >>> 9) << 4) + 14] = len; var a =  1732584193; var b = -271733879; var c = -1732584194; var d =  271733878; for(var i = 0; i < x.length; i += 16) { var olda = a; var oldb = b; var oldc = c; var oldd = d; a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);c = md5_ff(c, d, a, b, x[i+ 2], 17,  606105819);b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
+         a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);d = md5_ff(d, a, b, c, x[i+ 5], 12,  1200080426);c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);a = md5_ff(a, b, c, d, x[i+ 8], 7 ,  1770035416);d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);c = md5_ff(c, d, a, b, x[i+10], 17, -42063);b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);a = md5_ff(a, b, c, d, x[i+12], 7 ,  1804603682);d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
+         c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);b = md5_ff(b, c, d, a, x[i+15], 22,  1236535329);a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);c = md5_gg(c, d, a, b, x[i+11], 14,  643717713);b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);d = md5_gg(d, a, b, c, x[i+10], 9 ,  38016083);c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
+         a = md5_gg(a, b, c, d, x[i+ 9], 5 ,  568446438);d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);b = md5_gg(b, c, d, a, x[i+ 8], 20,  1163531501);a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);c = md5_gg(c, d, a, b, x[i+ 7], 14,  1735328473);b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
+         c = md5_hh(c, d, a, b, x[i+11], 16,  1839030562);b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);d = md5_hh(d, a, b, c, x[i+ 4], 11,  1272893353);c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);a = md5_hh(a, b, c, d, x[i+13], 4 ,  681279174);d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);b = md5_hh(b, c, d, a, x[i+ 6], 23,  76029189);
+         a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);c = md5_hh(c, d, a, b, x[i+15], 16,  530742520);b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);d = md5_ii(d, a, b, c, x[i+ 7], 10,  1126891415);c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);a = md5_ii(a, b, c, d, x[i+12], 6 ,  1700485571);d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
+         c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);a = md5_ii(a, b, c, d, x[i+ 8], 6 ,  1873313359);d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);b = md5_ii(b, c, d, a, x[i+13], 21,  1309151649);a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);c = md5_ii(c, d, a, b, x[i+ 2], 15,  718787259);b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
+         a = safe_add(a, olda); b = safe_add(b, oldb); c = safe_add(c, oldc); d = safe_add(d, oldd); } return Array(a, b, c, d); }
+function md5_cmn(q, a, b, x, s, t) { return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b); }
+function md5_ff(a, b, c, d, x, s, t) { return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t); }
+function md5_gg(a, b, c, d, x, s, t) { return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t); }
+function md5_hh(a, b, c, d, x, s, t) { return md5_cmn(b ^ c ^ d, a, b, x, s, t); }
+function md5_ii(a, b, c, d, x, s, t) { return md5_cmn(c ^ (b | (~d)), a, b, x, s, t); }
+function core_hmac_md5(key, data) { var bkey = str2binl(key); if(bkey.length > 16) bkey = core_md5(bkey, key.length * chrsz); var ipad = Array(16), opad = Array(16); for(var i = 0; i < 16; i++) { ipad[i] = bkey[i] ^ 0x36363636; opad[i] = bkey[i] ^ 0x5C5C5C5C; } var hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz); return core_md5(opad.concat(hash), 512 + 128); }
+function safe_add(x, y) {var lsw = (x & 0xFFFF) + (y & 0xFFFF);var msw = (x >> 16) + (y >> 16) + (lsw >> 16);return (msw << 16) | (lsw & 0xFFFF); }
+function bit_rol(num, cnt) { return (num << cnt) | (num >>> (32 - cnt)); }
+function str2binl(str) { var bin = Array(); var mask = (1 << chrsz) - 1; for(var i = 0; i < str.length * chrsz; i += chrsz) bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32); return bin; }
+function binl2str(bin) { var str = ""; var mask = (1 << chrsz) - 1; for(var i = 0; i < bin.length * 32; i += chrsz) str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask); return str; }
+function binl2hex(binarray) { var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; var str = ""; for(var i = 0; i < binarray.length * 4; i++) { str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) + hex_tab.charAt((binarray[i>>2] >> ((i%4)*8  )) & 0xF); } return str; }
+function binl2b64(binarray) { var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; var str = ""; for(var i = 0; i < binarray.length * 4; i += 3) { var triplet = (((binarray[i >> 2] >> 8 * ( i   %4)) & 0xFF) << 16) | (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 ) |  ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF); for(var j = 0; j < 4; j++) { if(i * 8 + j * 6 > binarray.length * 32) str += b64pad; else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F); } } return str; }
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/sbedit.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,122 @@
+var disenable_currentBlock;
+function ajaxDisenableBlock(id)
+{
+  disenable_currentBlock = document.getElementById('disabled_'+id);
+  ajaxGet(makeUrlNS('Special', 'EditSidebar', 'action=disenable&ajax=true&noheaders&id='+id), function()
+    {
+      if(ajax.readyState == 4)
+      {
+        if(ajax.responseText == 'GOOD')
+        {
+          if(disenable_currentBlock.style.display == 'none')
+          {
+            disenable_currentBlock.style.display = 'inline';
+          }
+          else
+          {
+            disenable_currentBlock.style.display = 'none';
+          }
+        } 
+        else
+        {
+          document.getElementById('ajaxEditContainer').innerHTML = ajax.responseText;
+        }
+      }
+    });
+}
+
+var delete_currentBlock;
+function ajaxDeleteBlock(id, oElm)
+{
+  delete_currentBlock = { 0 : id, 1 : oElm };
+  ajaxGet(makeUrlNS('Special', 'EditSidebar', 'action=delete&ajax=true&noheaders&id='+id), function()
+    {
+      if(ajax.readyState == 4)
+      {
+        if(ajax.responseText == 'GOOD')
+        {
+          e = delete_currentBlock[1];
+          e = e.parentNode.parentNode;
+          e.parentNode.removeChild(e);
+        } 
+        else
+        {
+          document.getElementById('ajaxEditContainer').innerHTML = ajax.responseText;
+        }
+      }
+    });
+}
+
+var blockEdit_current;
+function ajaxEditBlock(id, oElm)
+{
+  blockEdit_current = { 0 : id, 1 : oElm };
+  ajaxGet(makeUrlNS('Special', 'EditSidebar', 'action=getsource&noheaders&id='+id), function()
+    {
+      if(ajax.readyState == 4)
+      {
+        id = blockEdit_current[0];
+        oElm = blockEdit_current[1];
+        var thediv = document.createElement('div');
+        //if(!oElm.id) oElm.id = 'autoEditButton_'+Math.floor(Math.random() * 100000);
+        oElm = oElm.parentNode;
+        o = fetch_offset(oElm);
+        d = fetch_dimensions(oElm);
+        top = o['top'] + d['h'] + 'px';
+        left = o['left'] + 'px';
+        thediv.style.top = top;
+        thediv.style.left = left;
+        thediv.style.position = 'absolute';
+        thediv.className = 'mdg-comment';
+        thediv.style.margin = '0';
+        if(ajax.responseText == 'HOUSTON_WE_HAVE_A_PLUGIN')
+        {
+          thediv.innerHTML = '<h3>This block cannot be edited.</h3><p>This is a plugin block, and cannot be edited.</p><p><a href="#" onclick="this.parentNode.parentNode.parentNode.removeChild(this.parentNode.parentNode); return false;">close</a></p>';
+        }
+        else
+        {
+          ta = document.createElement('textarea');
+          ta.rows = '15';
+          ta.cols = '50';
+          ta.innerHTML = ajax.responseText;
+          thediv.appendChild(ta);
+          b = document.createElement('br');
+          thediv.appendChild(b);
+          thediv.innerHTML += '<a href="#" onclick="ajaxSaveBlock(this, \''+id+'\'); return false;">save</a>  |  <a href="#" onclick="if(confirm(\'Do you really want to discard your changes?\')) this.parentNode.parentNode.removeChild(this.parentNode); return false;">cancel</a>';
+        }
+        body = document.getElementsByTagName('body');
+        body = body[0];
+        body.appendChild(thediv);
+      }
+    });
+}
+
+var blockSave_current;
+function ajaxSaveBlock(oElm, id)
+{
+  taContent = escape(oElm.previousSibling.previousSibling.value);
+  taContent = taContent.replace(unescape('%0A'), '%0A');
+  taContent = taContent.replace('+', '%2B');
+  blockSave_current = { 0 : id, 1 : oElm };
+  ajaxPost(makeUrlNS('Special', 'EditSidebar', 'noheaders&action=save&id='+id), 'content='+taContent, function()
+    {
+      if(ajax.readyState == 4)
+      {
+        id   = blockSave_current[0];
+        oElm = blockSave_current[1];
+        eval(ajax.responseText);
+        if(status == 'GOOD')
+        {
+          parent = document.getElementById('disabled_'+id).parentNode.parentNode;
+          oElm.parentNode.parentNode.removeChild(oElm.parentNode);
+          content = content.replace('%a', unescape('%0A'));
+          parent.firstChild.nextSibling.nextSibling.nextSibling.innerHTML = content; // $content is set in ajax.responseText
+        }
+        else
+        {
+          alert(status);
+        }
+      }
+    });
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/static/.acl.js.marks	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+!t;10617;10617
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/static/acl.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,696 @@
+// Javascript routines for the ACL editor
+
+var aclManagerID = 'enano_aclmanager_' + Math.floor(Math.random() * 1000000);
+var aclPermList = false;
+var aclDataCache = false;
+
+function ajaxOpenACLManager(page_id, namespace)
+{
+  if(IE)
+    return true;
+  if(!page_id || !namespace)
+  {
+    var data = strToPageID(title);
+    var page_id = data[0];
+    var namespace = data[1];
+  }
+  var params = {
+      'mode' : 'listgroups',
+      'page_id' : page_id,
+      'namespace' : namespace
+    };
+  params = toJSONString(params);
+  params = ajaxEscape(params);
+  ajaxPost(stdAjaxPrefix+'&_mode=acljson', 'acl_params='+params, function() {
+      if(ajax.readyState == 4)
+      {
+        __aclBuildWizardWindow();
+        groups = parseJSON(ajax.responseText);
+        aclDataCache = groups;
+        __aclBuildSelector(groups);
+      }
+    });
+  return false;
+}
+
+function ajaxACLSwitchToSelector()
+{
+  params = {
+      'mode' : 'listgroups'
+    };
+  if ( aclDataCache.page_id && aclDataCache.namespace )
+  {
+    params.page_id   = aclDataCache.page_id;
+    params.namespace = aclDataCache.namespace;
+  }
+  params = toJSONString(params);
+  params = ajaxEscape(params);
+  ajaxPost(stdAjaxPrefix+'&_mode=acljson', 'acl_params='+params, function() {
+      if(ajax.readyState == 4)
+      {
+        document.getElementById(aclManagerID+'_main').innerHTML = '';
+        document.getElementById(aclManagerID + '_back').style.display = 'none';
+        document.getElementById(aclManagerID + '_next').value = 'Next >';
+        groups = parseJSON(ajax.responseText);
+        aclDataCache = groups;
+        thispage = strToPageID(title);
+        groups.page_id = thispage[0];
+        groups.namespace = thispage[1];
+        __aclBuildSelector(groups);
+      }
+    });
+}
+
+function __aclBuildSelector(groups)
+{
+  thispage = strToPageID(title);
+  do_scopesel = ( thispage[0] == groups.page_id && thispage[1] == groups.namespace );
+  
+  seed = Math.floor(Math.random() * 1000000);
+        
+  main = document.getElementById(aclManagerID + '_main');
+  main.style.padding = '10px';
+  
+  selector = document.createElement('div');
+  
+  grpsel = __aclBuildGroupsHTML(groups);
+  grpsel.name = 'group_id';
+  
+  span = document.createElement('div');
+  span.id = "enACL_grpbox_"+seed+"";
+  
+  // Build the selector
+  grpb = document.createElement('input');
+  grpb.type = 'radio';
+  grpb.name  = 'target_type';
+  grpb.value = 1; // ACL_TYPE_GROUP
+  grpb.checked = 'checked';
+  grpb.className = seed;
+  grpb.onclick = function() { seed = this.className; document.getElementById('enACL_grpbox_'+seed).style.display = 'block'; document.getElementById('enACL_usrbox_'+seed).style.display = 'none'; };
+  lbl = document.createElement('label');
+  lbl.appendChild(grpb);
+  lbl.appendChild(document.createTextNode('A usergroup'));
+  lbl.style.display = 'block';
+  span.appendChild(grpsel);
+  
+  usrb = document.createElement('input');
+  usrb.type = 'radio';
+  usrb.name  = 'target_type';
+  usrb.value = 2; // ACL_TYPE_USER
+  usrb.className = seed;
+  usrb.onclick = function() { seed = this.className; document.getElementById('enACL_grpbox_'+seed).style.display = 'none'; document.getElementById('enACL_usrbox_'+seed).style.display = 'block'; };
+  lbl2 = document.createElement('label');
+  lbl2.appendChild(usrb);
+  lbl2.appendChild(document.createTextNode('A specific user'));
+  lbl2.style.display = 'block';
+  
+  usrsel = document.createElement('input');
+  usrsel.type = 'text';
+  usrsel.name = 'username';
+  usrsel.onkeyup = function() { ajaxUserNameComplete(this); };
+  usrsel.id = 'userfield_' + aclManagerID;
+  try {
+    usrsel.setAttribute("autocomplete","off");
+  } catch(e) {};
+  
+  span2 = document.createElement('div');
+  span2.id = "enACL_usrbox_"+seed+"";
+  span2.style.display = 'none';
+  span2.appendChild(usrsel);
+  
+  // Scope selector
+  if(do_scopesel)
+  {
+    scopediv1 = document.createElement('div');
+    scopediv2 = document.createElement('div');
+    scopeRadioPage = document.createElement('input');
+      scopeRadioPage.type = 'radio';
+      scopeRadioPage.name = 'scope';
+      scopeRadioPage.value = 'page';
+      scopeRadioPage.checked = 'checked';
+    scopeRadioGlobal = document.createElement('input');
+      scopeRadioGlobal.type = 'radio';
+      scopeRadioGlobal.name = 'scope';
+      scopeRadioGlobal.value = 'global';
+    lblPage = document.createElement('label');
+      lblPage.style.display = 'block';
+      lblPage.appendChild(scopeRadioPage);
+      lblPage.appendChild(document.createTextNode('Only this page'));
+    lblGlobal = document.createElement('label');
+      lblGlobal.style.display = 'block';
+      lblGlobal.appendChild(scopeRadioGlobal);
+      lblGlobal.appendChild(document.createTextNode('The entire website'));
+    scopediv1.appendChild(lblPage);
+    scopediv2.appendChild(lblGlobal);
+    
+    scopedesc = document.createElement('p');
+    scopedesc.appendChild(document.createTextNode('What should this access rule control?'));
+  }
+  
+  // Styles
+  span.style.marginLeft = '13px';
+  span.style.padding = '5px 0';
+  span2.style.marginLeft = '13px';
+  span2.style.padding = '5px 0';
+  
+  selector.appendChild(lbl);
+  selector.appendChild(span);
+  
+  selector.appendChild(lbl2);
+  selector.appendChild(span2);
+  
+  container = document.createElement('div');
+  container.style.margin = 'auto';
+  container.style.width = '360px';
+  container.style.paddingTop = '70px';
+  
+  head = document.createElement('h2');
+  head.appendChild(document.createTextNode('Manage page access'));
+  
+  desc = document.createElement('p');
+  desc.appendChild(document.createTextNode('Please select who should be affected by this access rule.'));
+  
+  container.appendChild(head);
+  container.appendChild(desc);
+  container.appendChild(selector);
+  
+  if(do_scopesel)
+  {
+    container.appendChild(scopedesc);
+    container.appendChild(scopediv1);
+    container.appendChild(scopediv2);
+  }
+  
+  main.appendChild(container);
+  
+  var mode = document.createElement('input');
+  mode.name = 'mode';
+  mode.type = 'hidden';
+  mode.id = aclManagerID + '_mode';
+  mode.value = 'seltarget';
+  
+  var theform = document.getElementById(aclManagerID + '_formobj_id');
+  if ( !theform.mode )
+  {
+    theform.appendChild(mode);
+  }
+  else
+  {
+    theform.removeChild(theform.mode);
+    theform.appendChild(mode);
+  }
+}
+
+var aclDebugWin = false;
+
+function aclDebug(text)
+{
+  if(!aclDebugWin)
+    aclDebugWin = pseudoWindowOpen("data:text/html;plain,<html><head><title>debug win</title></head><body><h1>Debug window</h1></body></html>", "aclDebugWin");
+    setTimeout(function() {
+  aclDebugWin.pre = aclDebugWin.document.createElement('pre');
+  aclDebugWin.pre.appendChild(aclDebugWin.document.createTextNode(text));
+  aclDebugWin.b = aclDebugWin.document.getElementsByTagName('body')[0];
+    aclDebugWin.b.appendChild(aclDebugWin.pre);}, 1000);
+}
+
+var pseudoWindows = new Object();
+
+function pseudoWindowOpen(url, id)
+{
+  if(pseudoWindows[id])
+  {
+    document.getElementById('pseudowin_ifr_'+id).src = url;
+  }
+  else
+  {
+    win = document.createElement('iframe');
+    win.style.position='fixed';
+    win.style.width = '640px';
+    win.style.height = '480px';
+    win.style.top = '0px';
+    win.style.left = '0px';
+    win.style.zIndex = getHighestZ() + 1;
+    win.style.backgroundColor = '#FFFFFF';
+    win.name = 'pseudo_ifr_'+id;
+    win.id = 'pseudowindow_ifr_'+id;
+    win.src = url;
+    body = document.getElementsByTagName('body')[0];
+    body.appendChild(win);
+  }
+  win_obj = eval("( pseudo_ifr_"+id+" )");
+  return win_obj;
+}
+
+function __aclJSONSubmitAjaxHandler(params)
+{
+  params = toJSONString(params);
+  params = ajaxEscape(params);
+  ajaxPost(stdAjaxPrefix+'&_mode=acljson', 'acl_params='+params, function() {
+      if(ajax.readyState == 4)
+      {
+        try {
+          data = parseJSON(ajax.responseText);
+        } catch(e) {
+          aclDebug(e+"\n\nResponse:\n"+ajax.responseText);
+        }
+        aclDataCache = data;
+        switch(data.mode)
+        {
+          case 'seltarget':
+            
+            // Build the ACL edit form
+            // try {
+              act_desc = ( data.type == 'new' ) ? 'Create access rule' : 'Editing permissions';
+              target_type_t = ( data.target_type == 1 ) ? 'group' : 'user';
+              target_name_t = data.target_name;
+              var scope_type = ( data.page_id == false && data.namespace == false ) ? 'this entire site' : 'this page';
+              html = '<h2>'+act_desc+'</h2><p>This panel allows you to edit what the '+target_type_t+' "<b>'+target_name_t+'</b>" can do on <b>' + scope_type + '</b>. Unless you set a permission to "Deny", these permissions may be overridden by other rules.</p>';
+              parser = new templateParser(data.template.acl_field_begin);
+              html += parser.run();
+              
+              cls = 'row2';
+              for(var i in data.acl_types)
+              {
+                if(typeof(data.acl_types[i]) == 'number')
+                {
+                  cls = ( cls == 'row1' ) ? 'row2' : 'row1';
+                  p = new templateParser(data.template.acl_field_item);
+                  vars = new Object();
+                  vars['FIELD_DESC'] = data.acl_descs[i];
+                  vars['FIELD_DENY_CHECKED'] = '';
+                  vars['FIELD_DISALLOW_CHECKED'] = '';
+                  vars['FIELD_WIKIMODE_CHECKED'] = '';
+                  vars['FIELD_ALLOW_CHECKED'] = '';
+                  vars['FIELD_NAME'] = i;
+                  switch(data.current_perms[i])
+                  {
+                    case 1:
+                      vars['FIELD_DENY_CHECKED'] = 'checked="checked"';
+                      break;
+                    case 2:
+                    default:
+                      vars['FIELD_DISALLOW_CHECKED'] = 'checked="checked"';
+                      break;
+                    case 3:
+                      vars['FIELD_WIKIMODE_CHECKED'] = 'checked="checked"';
+                      break;
+                    case 4:
+                      vars['FIELD_ALLOW_CHECKED'] = 'checked="checked"';
+                      break;
+                  }
+                  vars['ROW_CLASS'] = cls;
+                  p.assign_vars(vars);
+                  html += p.run();
+                }
+              }
+              
+              var parser = new templateParser(data.template.acl_field_end);
+              html += parser.run();
+              
+              if(data.type == 'edit')
+                html += '<p id="'+aclManagerID+'_deletelnk" style="text-align: right;"><a href="#delete_acl_rule" onclick="if(confirm(\'Do you really want to delete this rule?\')) __aclDeleteRule(); return false;" style="color: red;">Delete this rule</a></p>';
+              
+              var main = document.getElementById(aclManagerID + '_main');
+              main.innerHTML = html;
+              
+              var form = document.getElementById(aclManagerID + '_formobj_id');
+              
+              var modeobj = form_fetch_field(form, 'mode');
+              if ( modeobj )
+                modeobj.value = 'save_' + data.type;
+              else
+                alert('modeobj is invalid: '+modeobj);
+              
+              aclPermList = array_keys(data.acl_types);
+              
+              document.getElementById(aclManagerID + '_back').style.display = 'inline';
+              document.getElementById(aclManagerID + '_next').value = 'Save Changes';
+              
+            // } catch(e) { alert(e); aclDebug(ajax.responseText); }
+            
+            break;
+          case 'success':
+            var note = document.createElement('div');
+            note.className = 'info-box';
+            note.style.marginLeft = '0';
+            var b = document.createElement('b');
+            b.appendChild(document.createTextNode('Permissions updated'));
+            note.appendChild(b);
+            note.appendChild(document.createElement('br'));
+            note.appendChild(document.createTextNode('The permissions for '+data.target_name+' on this page have been updated successfully.'));
+            note.appendChild(document.createElement('br'));
+            var a = document.createElement('a');
+            a.href = 'javascript:void(0);';
+            a.onclick = function() { this.parentNode.parentNode.removeChild(this.parentNode); return false; };
+            a.appendChild(document.createTextNode('[ dismiss :'));
+            note.appendChild(a);
+            var a2 = document.createElement('a');
+            a2.href = 'javascript:void(0);';
+            a2.onclick = function() { killACLManager(); return false; };
+            a2.appendChild(document.createTextNode(': close manager ]'));
+            note.appendChild(a2);
+            document.getElementById(aclManagerID + '_main').insertBefore(note, document.getElementById(aclManagerID + '_main').firstChild);
+            if(!document.getElementById(aclManagerID+'_deletelnk'))
+              document.getElementById(aclManagerID + '_main').innerHTML += '<p id="'+aclManagerID+'_deletelnk" style="text-align: right;"><a href="#delete_acl_rule" onclick="if(confirm(\'Do you really want to delete this rule?\')) __aclDeleteRule(); return false;" style="color: red;">Delete this rule</a></p>';
+            //fadeInfoBoxes();
+            break;
+          case 'delete':
+            
+            params = {
+              'mode' : 'listgroups'
+            };
+          params = toJSONString(params);
+          params = ajaxEscape(params);
+          ajaxPost(stdAjaxPrefix+'&_mode=acljson', 'acl_params='+params, function() {
+              if(ajax.readyState == 4)
+              {
+                document.getElementById(aclManagerID+'_main').innerHTML = '';
+                document.getElementById(aclManagerID + '_back').style.display = 'none';
+                document.getElementById(aclManagerID + '_next').value = 'Next >';
+                var thispage = strToPageID(title);
+                groups.page_id = thispage[0];
+                groups.namespace = thispage[1];
+                __aclBuildSelector(groups);
+                
+                note = document.createElement('div');
+                note.className = 'info-box';
+                note.style.marginLeft = '0';
+                b = document.createElement('b');
+                b.appendChild(document.createTextNode('Entry deleted'));
+                note.appendChild(b);
+                note.appendChild(document.createElement('br'));
+                note.appendChild(document.createTextNode('The access rules for '+aclDataCache.target_name+' on this page have been deleted.'));
+                note.appendChild(document.createElement('br'));
+                a = document.createElement('a');
+                a.href = '#';
+                a.onclick = function() { this.parentNode.parentNode.removeChild(this.parentNode); return false; };
+                a.appendChild(document.createTextNode('[ dismiss :'));
+                note.appendChild(a);
+                a = document.createElement('a');
+                a.href = '#';
+                a.onclick = function() { killACLManager(); return false; };
+                a.appendChild(document.createTextNode(': close manager ]'));
+                note.appendChild(a);
+                document.getElementById(aclManagerID + '_main').insertBefore(note, document.getElementById(aclManagerID + '_main').firstChild);
+                //fadeInfoBoxes();
+                
+              }
+            });
+            
+            break;
+          case 'error':
+            alert("Server side processing error:\n"+data.error);
+            break;
+          case 'debug':
+            aclDebug(data.text);
+            break;
+          default:
+            alert("Invalid JSON response from server\nMode: "+data.mode+"\nJSON string: "+ajax.responseText);
+            break;
+        }
+      }
+    });
+}
+
+function __aclBuildGroupsHTML(groups)
+{
+  groups = groups.groups;
+  select = document.createElement('select');
+  for(var i in groups)
+  {
+    if(typeof(groups[i]['name']) == 'string' && i != 'toJSONString')
+    {
+      o = document.createElement('option');
+      o.value = groups[i]['id'];
+      t = document.createTextNode(groups[i]['name']);
+      o.appendChild(t);
+      select.appendChild(o);
+    }
+  }
+  return select;
+}
+
+function __aclBuildWizardWindow()
+{
+  darken();
+  box = document.createElement('div');
+  box.style.width = '640px'
+  box.style.height = '440px';
+  box.style.position = 'fixed';
+  width = getWidth();
+  height = getHeight();
+  box.style.left = ( width / 2 - 320 ) + 'px';
+  box.style.top = ( height / 2 - 250 ) + 'px';
+  box.style.backgroundColor = 'white';
+  box.style.zIndex = getHighestZ() + 1;
+  box.id = aclManagerID;
+  box.style.opacity = '0';
+  box.style.filter = 'alpha(opacity=0)';
+  box.style.display = 'none';
+  
+  mainwin = document.createElement('div');
+  mainwin.id = aclManagerID + '_main';
+  mainwin.style.clip = 'rect(0px,640px,440px,0px)';
+  mainwin.style.overflow = 'auto';
+  mainwin.style.width = '620px';
+  mainwin.style.height = '420px';
+  
+  panel = document.createElement('div');
+  panel.style.width = '620px';
+  panel.style.padding = '10px';
+  panel.style.lineHeight = '40px';
+  panel.style.textAlign = 'right';
+  panel.style.position = 'fixed';
+  panel.style.left = ( width / 2 - 320 ) + 'px';
+  panel.style.top = ( height / 2 + 190 ) + 'px';
+  panel.style.backgroundColor = '#D0D0D0';
+  panel.style.opacity = '0';
+  panel.style.filter = 'alpha(opacity=0)';
+  panel.id = aclManagerID + '_panel';
+  
+  form = document.createElement('form');
+  form.method = 'post';
+  form.action = 'javascript:void(0)';
+  form.onsubmit = function() { if(this.username && !submitAuthorized) return false; __aclSubmitManager(this); return false; };
+  form.name = aclManagerID + '_formobj';
+  form.id   = aclManagerID + '_formobj_id';
+  
+  back = document.createElement('input');
+  back.type = 'button';
+  back.value = '< Back';
+  back.style.fontWeight = 'normal';
+  back.onclick = function() { ajaxACLSwitchToSelector(); return false; };
+  back.style.display = 'none';
+  back.id = aclManagerID + '_back';
+  
+  saver = document.createElement('input');
+  saver.type = 'submit';
+  saver.value = 'Next >';
+  saver.style.fontWeight = 'bold';
+  saver.id = aclManagerID + '_next';
+  
+  closer = document.createElement('input');
+  closer.type = 'button';
+  closer.value = 'Cancel Changes';
+  closer.onclick = function() { if(!confirm('Do you really want to close the ACL manager?')) return false; killACLManager(); return false; }
+  
+  spacer1 = document.createTextNode('  ');
+  spacer2 = document.createTextNode('  ');
+  
+  panel.appendChild(back);
+  panel.appendChild(spacer1);
+  panel.appendChild(saver);
+  panel.appendChild(spacer2);
+  panel.appendChild(closer);
+  form.appendChild(mainwin);
+  form.appendChild(panel);
+  box.appendChild(form);
+  
+  body = document.getElementsByTagName('body')[0];
+  body.appendChild(box);
+  setTimeout("document.getElementById('"+aclManagerID+"').style.display = 'block'; opacity('"+aclManagerID+"', 0, 100, 500); opacity('"+aclManagerID + '_panel'+"', 0, 100, 500);", 1000);
+}
+
+function killACLManager()
+{
+  el = document.getElementById(aclManagerID);
+  if(el)
+  {
+    el.parentNode.removeChild(el);
+    enlighten();
+  }
+}
+
+function __aclSubmitManager(form)
+{
+  var thefrm = document.forms[form.name];
+  var modeobj = form_fetch_field(thefrm, 'mode');
+  if ( typeof(modeobj) == 'object' )
+  {
+    var mode = (thefrm.mode.value) ? thefrm.mode.value : 'cant_get';
+  }
+  else
+  {
+    var mode = '';
+  }
+  switch(mode)
+  {
+    case 'cant_get':
+      alert('BUG: can\'t get the state value from the form field.');
+      break;
+    case 'seltarget':
+      var target_type = parseInt(getRadioState(thefrm, 'target_type'));
+      if(isNaN(target_type))
+      {
+        alert('Please select a target type.');
+        return false;
+      }
+      target_id = ( target_type == 1 ) ? parseInt(thefrm.group_id.value) : thefrm.username.value;
+      
+      obj = { 'mode' : mode, 'target_type' : target_type, 'target_id' : target_id };
+      
+      thispage = strToPageID(title);
+      do_scopesel = ( thispage[0] == aclDataCache.page_id && thispage[1] == aclDataCache.namespace );
+      
+      if(do_scopesel)
+      {
+        scope = getRadioState(thefrm, 'scope');
+        if(scope == 'page')
+        {
+          pageid = strToPageID(title);
+          obj['page_id'] = pageid[0];
+          obj['namespace'] = pageid[1];
+        }
+        else if(scope == 'global')
+        {
+          obj['page_id'] = false;
+          obj['namespace'] = false;
+        }
+        else
+        {
+          alert('Invalid scope');
+          return false;
+        }
+      }
+      else
+      {
+        obj['page_id'] = aclDataCache.page_id;
+        obj['namespace'] = aclDataCache.namespace;
+      }
+      if(target_id == '')
+      {
+        alert('Please enter a username.');
+        return false;
+      }
+      __aclJSONSubmitAjaxHandler(obj);
+      break;
+    case 'save_edit':
+    case 'save_new':
+      var form = document.forms[aclManagerID + '_formobj'];
+      selections = new Object();
+      for(var i in aclPermList)
+      {
+        if(i != 'toJSONString' && i != aclPermList.length-1)
+        {
+          selections[aclPermList[i]] = getRadioState(form, aclPermList[i]);
+          if(!selections[aclPermList[i]])
+          {
+            alert("Invalid return from getRadioState: "+i+": "+selections[i]+" ("+typeof(selections[i])+")");
+            return false;
+          }
+        }
+      }
+      obj = new Object();
+      obj['perms'] = selections;
+      obj['mode'] = mode;
+      obj['target_type'] = aclDataCache.target_type;
+      obj['target_id'] = aclDataCache.target_id;
+      obj['target_name'] = aclDataCache.target_name;
+      obj['page_id'] = aclDataCache.page_id;
+      obj['namespace'] = aclDataCache.namespace;
+      __aclJSONSubmitAjaxHandler(obj);
+      break;
+    default:
+      alert("JSON form submit: invalid mode string "+mode+", stopping execution");
+      return false;
+      break;
+  }
+}
+
+function getRadioState(form, name)
+{
+  inputs = form.getElementsByTagName('input');
+  radios = new Array();
+  for(var i in inputs)
+  {
+    if(inputs[i]) if(inputs[i].type == 'radio')
+      radios.push(inputs[i]);
+  }
+  for(var i in radios)
+  {
+    if(radios[i].checked && radios[i].name == name)
+      return radios[i].value;
+  }
+  return false;
+}
+
+function __aclSetAllRadios(val)
+{
+  val = val+'';
+  form = document.forms[aclManagerID + '_formobj'];
+  if (!form)
+    return false;
+  inputs = form.getElementsByTagName('input');
+  radios = new Array();
+  for(var i in inputs)
+  {
+    if(inputs[i].type == 'radio')
+      radios.push(inputs[i]);
+  }
+  for(var i in radios)
+  {
+    if(radios[i].value == val)
+      radios[i].checked = true;
+    else
+      radios[i].checked = false;
+  }
+}
+
+function __aclDeleteRule()
+{
+  if(!aclDataCache) return false;
+  if(aclDataCache.mode != 'seltarget') return false;
+  parms = {
+    'target_type' : aclDataCache.target_type,
+    'target_id' : aclDataCache.target_id,
+    'target_name' : aclDataCache.target_name,
+    'page_id' : aclDataCache.page_id,
+    'namespace' : aclDataCache.namespace,
+    'mode' : 'delete'
+  };
+  __aclJSONSubmitAjaxHandler(parms);
+}
+
+function array_keys(obj)
+{
+  keys = new Array();
+  for(var i in obj)
+    keys.push(i);
+  return keys;
+}
+
+function form_fetch_field(form, name)
+{
+  var fields = form.getElementsByTagName('input');
+  if ( fields.length < 1 )
+    return false;
+  for ( var i = 0; i < fields.length; i++ )
+  {
+    var field = fields[i];
+    if ( field.name == name )
+      return field;
+  }
+  return false;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/static/admin-menu.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,209 @@
+/*
+ * Enano - an open source wiki-like CMS
+ * Copyright (C) 2006-2007 Dan Fuhry
+ *
+ * This program is Free Software; you can redistribute 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 details.
+ *
+ * Some code found in this script is not licensed under the GNU General Public License; however, it is believed that the license terms shown
+ * below are GPL-compatible. If you believe that this is not the case, please drop a note to support@enano.homelinux.org.
+ */
+ 
+/*
+ * Title: Tigra Tree
+ * Description: See the demo at url
+ * URL: http://www.softcomplex.com/products/tigra_tree_menu/
+ * Version: 1.1
+ * Date: 11-12-2002 (mm-dd-yyyy)
+ * Notes: This script is free. Visit official site for further details.
+ * 
+ * There is no license fee or royalty fee to be paid at any time for using the Tigra Tree Menu v1.x
+ * You may include the source code or modified source code within your own projects for either personal
+ * or commercial use but excluding the restrictions outlined below. The following restrictions apply to
+ * all parts of the component, including all source code, samples and documentation.
+ *
+ * - Header block of script file (tree.js) CAN NOT be modified or removed.
+ * - The above items CAN NOT be sold as are, either individually or together.
+ * - The above items CAN NOT be modified and then sold as a library component, either individually or together. 
+ */
+ 
+var ck = readCookie('admin_menu_state');
+if(ck)
+{
+  var ck = parseInt(ck);
+}
+else
+{
+  ck = 0;
+}
+ck = ( isNaN(ck) ) ? 0 : ck;
+
+function tree (a_items, a_template) {
+
+	this.a_tpl      = a_template;
+	this.a_config   = a_items;
+	this.o_root     = this;
+	this.a_index    = [];
+	this.o_selected = null;
+	this.n_depth    = -1;
+	
+	var o_icone = new Image(),
+		o_iconl = new Image();
+	o_icone.src = a_template['icon_e'];
+	o_iconl.src = a_template['icon_l'];
+	a_template['im_e'] = o_icone;
+	a_template['im_l'] = o_iconl;
+	for (var i = 0; i < 64; i++)
+		if (a_template['icon_' + i]) {
+			var o_icon = new Image();
+			a_template['im_' + i] = o_icon;
+			o_icon.src = a_template['icon_' + i];
+		}
+	
+	this.toggle = function (n_id,co) { var o_item = this.a_index[n_id]; o_item.open(o_item.b_opened,co); };
+  this.open   = function (n_id,co) { var o_item = this.a_index[n_id]; o_item.open(false,co); };
+	this.select = function (n_id)    { return this.a_index[n_id].select(); };
+	this.mout   = function (n_id)    { this.a_index[n_id].upstatus(true) };
+	this.mover  = function (n_id)    { this.a_index[n_id].upstatus() };
+
+	this.a_children = [];
+	for (var i = 0; i < a_items.length; i++)
+  {
+		new tree_item(this, i);
+  }
+
+	this.n_id = trees.length;
+	trees[this.n_id] = this;
+	
+	for (var i = 0; i < this.a_children.length; i++) {
+		document.write(this.a_children[i].init());
+		this.a_children[i].open(false, true);
+	}
+}
+function tree_item (o_parent, n_order) {
+
+	this.n_depth  = o_parent.n_depth + 1;
+	this.a_config = o_parent.a_config[n_order + (this.n_depth ? 2 : 0)];
+	if (!this.a_config) return;
+
+	this.o_root    = o_parent.o_root;
+	this.o_parent  = o_parent;
+	this.n_order   = n_order;
+	this.b_opened  = !this.n_depth;
+
+	this.n_id = this.o_root.a_index.length;
+	this.o_root.a_index[this.n_id] = this;
+	o_parent.a_children[n_order] = this;
+
+	this.a_children = [];
+	for (var i = 0; i < this.a_config.length - 2; i++)
+  {
+		new tree_item(this, i);
+  }
+  
+	this.get_icon = item_get_icon;
+	this.open     = item_open;
+	this.select   = item_select;
+	this.init     = item_init;
+	this.upstatus = item_upstatus;
+	this.is_last  = function () { return this.n_order == this.o_parent.a_children.length - 1 };
+  
+  // CODE MODIFICATION
+  // added:
+    // Do we need to open the branch?
+    n = Math.pow(2, this.n_id);
+    var disp = ( ck & n ) ? true : false;
+    s = ( disp ) ? 'open' : 'closed';
+    //if(s=='open') alert(this.n_id + ': ' + s);
+    if(disp) setTimeout('trees['+trees.length+'].open('+this.n_id+', true);', 10);
+  // END MODIFICATIONS
+}
+
+function item_open (b_close, nocookie) {
+  //alert('item_open('+this.n_id+');');
+	var o_idiv = get_element('i_div' + this.o_root.n_id + '_' + this.n_id);
+	if (!o_idiv) return;
+	
+	if (!o_idiv.innerHTML) {
+		var a_children = [];
+		for (var i = 0; i < this.a_children.length; i++)
+    {
+			a_children[i]= this.a_children[i].init();
+    }
+		o_idiv.innerHTML = a_children.join('');
+	}
+	o_idiv.style.display = (b_close ? 'none' : 'block');
+  
+  // CODE MODIFICATION
+  // added:
+    if(!nocookie)
+    {
+      // The idea here is to use a bitwise field. Nice 'n simple, right? Object of the game is to assemble
+      // a binary number that depicts the open/closed state of the entire menu in one cookie.
+      n = Math.pow(2, this.n_id);
+      ck = ( b_close ) ? ck-n : ck+n;
+      //alert('open(): doing the cookie routine for id '+this.n_id+"\nResult for bitwise op: "+ck);
+      createCookie('admin_menu_state', ck, 365);
+    } else {
+      //alert('open(): NOT doing the cookie routine for id '+this.n_id);
+    }
+  // END MODIFICATIONS
+	
+	this.b_opened = !b_close;
+	var o_jicon = document.images['j_img' + this.o_root.n_id + '_' + this.n_id],
+		o_iicon = document.images['i_img' + this.o_root.n_id + '_' + this.n_id];
+	if (o_jicon) o_jicon.src = this.get_icon(true);
+	if (o_iicon) o_iicon.src = this.get_icon();
+	this.upstatus();
+}
+
+function item_select (b_deselect) {
+	if (!b_deselect) {
+		var o_olditem = this.o_root.o_selected;
+		this.o_root.o_selected = this;
+		if (o_olditem) o_olditem.select(true);
+	}
+	var o_iicon = document.images['i_img' + this.o_root.n_id + '_' + this.n_id];
+	if (o_iicon) o_iicon.src = this.get_icon();
+	get_element('i_txt' + this.o_root.n_id + '_' + this.n_id).style.fontWeight = b_deselect ? 'normal' : 'bold';
+	
+	this.upstatus();
+	return Boolean(this.a_config[1]);
+}
+
+function item_upstatus (b_clear) {
+	window.setTimeout('window.status="' + (b_clear ? '' : this.a_config[0] + (this.a_config[1] ? ' ('+ this.a_config[1] + ')' : '')) + '"', 10);
+}
+
+function item_init () {
+	var a_offset = [],
+		o_current_item = this.o_parent;
+	for (var i = this.n_depth; i > 1; i--) {
+		a_offset[i] = '<img src="' + this.o_root.a_tpl[o_current_item.is_last() ? 'icon_e' : 'icon_l'] + '" border="0" align="absbottom">';
+		o_current_item = o_current_item.o_parent;
+	}
+	return '<table cellpadding="0" cellspacing="0" border="0"><tr><td nowrap="nowrap">' + (this.n_depth ? a_offset.join('') + (this.a_children.length
+		? '<a href="javascript: trees[' + this.o_root.n_id + '].toggle(' + this.n_id + ')" onmouseover="trees[' + this.o_root.n_id + '].mover(' + this.n_id + ')" onmouseout="trees[' + this.o_root.n_id + '].mout(' + this.n_id + ')"><img src="' + this.get_icon(true) + '" border="0" align="absbottom" name="j_img' + this.o_root.n_id + '_' + this.n_id + '"></a>'
+		: '<img src="' + this.get_icon(true) + '" border="0" align="absbottom">') : '')
+  // CODE MODIFICATION
+  // removed: 
+	//	+ '<a href="' + this.a_config[1] + '" target="' + this.o_root.a_tpl['target'] + '" onclick="return trees[' + this.o_root.n_id + '].select(' + this.n_id + ')" ondblclick="trees[' + this.o_root.n_id + '].toggle(' + this.n_id + ')" onmouseover="trees[' + this.o_root.n_id + '].mover(' + this.n_id + ')" onmouseout="trees[' + this.o_root.n_id + '].mout(' + this.n_id + ')" class="t' + this.o_root.n_id + 'i" id="i_txt' + this.o_root.n_id + '_' + this.n_id + '"><img src="' + this.get_icon() + '" border="0" align="absbottom" name="i_img' + this.o_root.n_id + '_' + this.n_id + '" class="t' + this.o_root.n_id + 'im">' + this.a_config[0] + '</a></td></tr></table>' + (this.a_children.length ? '<div id="i_div' + this.o_root.n_id + '_' + this.n_id + '" style="display:none"></div>' : '');
+  // added:
+  + '<a href="' + this.a_config[1] + '" target="' + this.o_root.a_tpl['target'] + '" onclick="return trees[' + this.o_root.n_id + '].select(' + this.n_id + ')" ondblclick="trees[' + this.o_root.n_id + '].toggle(' + this.n_id + ')" onmouseover="trees[' + this.o_root.n_id + '].mover(' + this.n_id + ')" onmouseout="trees[' + this.o_root.n_id + '].mout(' + this.n_id + ')" class="t' + this.o_root.n_id + 'i" id="i_txt' + this.o_root.n_id + '_' + this.n_id + '">' + this.a_config[0] + '</a></td></tr></table>' + (this.a_children.length ? '<div id="i_div' + this.o_root.n_id + '_' + this.n_id + '" style="display:none"></div>' : '');
+  // END MODIFICATIONS
+  alert('i_div' + this.o_root.n_id + '_' + this.n_id);
+}
+
+function item_get_icon (b_junction) {
+	return this.o_root.a_tpl['icon_' + ((this.n_depth ? 0 : 32) + (this.a_children.length ? 16 : 0) + (this.a_children.length && this.b_opened ? 8 : 0) + (!b_junction && this.o_root.o_selected == this ? 4 : 0) + (b_junction ? 2 : 0) + (b_junction && this.is_last() ? 1 : 0))];
+}
+
+var trees = [];
+get_element = document.all ?
+	function (s_id) { return document.all[s_id] } :
+	function (s_id) { return document.getElementById(s_id) };
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/static/ajax.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,571 @@
+/*
+ * AJAX applets
+ */
+ 
+function ajaxGet(uri, f) {
+  if (window.XMLHttpRequest) {
+    ajax = new XMLHttpRequest();
+  } else {
+    if (window.ActiveXObject) {           
+      ajax = new ActiveXObject("Microsoft.XMLHTTP");
+    } else {
+      alert('Enano client-side runtime error: No AJAX support, unable to continue');
+      return;
+    }
+  }
+  ajax.onreadystatechange = f;
+  ajax.open('GET', uri, true);
+  ajax.setRequestHeader( "If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT" );
+  ajax.send(null);
+}
+
+function ajaxPost(uri, parms, f) {
+  if (window.XMLHttpRequest) {
+    ajax = new XMLHttpRequest();
+  } else {
+    if (window.ActiveXObject) {           
+      ajax = new ActiveXObject("Microsoft.XMLHTTP");
+    } else {
+      alert('Enano client-side runtime error: No AJAX support, unable to continue');
+      return;
+    }
+  }
+  ajax.onreadystatechange = f;
+  ajax.open('POST', uri, true);
+  ajax.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
+  ajax.setRequestHeader("Content-length", parms.length);
+  ajax.setRequestHeader("Connection", "close");
+  ajax.send(parms);
+}
+
+function ajaxEscape(text)
+{
+  text = escape(text);
+  text = text.replace(/\+/g, '%2B', text);
+  return text;
+}
+
+// Page editor
+
+function ajaxEditor() {
+  setAjaxLoading();
+  ajaxGet(stdAjaxPrefix+'&_mode=getsource', function() {
+      if(ajax.readyState == 4) {
+        unsetAjaxLoading();
+        if(edit_open) {
+          c=confirm('Do you really want to revert your changes?');
+          if(!c) return;
+        }
+        edit_open = true;
+        selectButtonMajor('article');
+        selectButtonMinor('edit');
+        if(in_array('ajaxEditArea', grippied_textareas))
+        {
+          // Allow the textarea grippifier to re-create the resizer control on the textarea
+          grippied_textareas.pop(in_array('ajaxEditArea', grippied_textareas));
+        }
+        disableUnload('If you do, any changes that you have made to this page will be lost.');
+        var switcher = ( readCookie('enano_editor_mode') == 'tinymce' ) ?
+                        '<a href="#" onclick="setEditorText(); return false;">wikitext editor</a>  |  graphical editor' :
+                        'wikitext editor  |  <a href="#" onclick="setEditorMCE(); return false;">graphical editor</a>' ;
+        document.getElementById('ajaxEditContainer').innerHTML = '\
+        <div id="mdgPreviewContainer"></div> \
+        <span id="switcher">' + switcher + '</span><br />\
+        <form name="mdgAjaxEditor" method="get" action="#" onsubmit="ajaxSavePage(); return false;">\
+        <textarea id="ajaxEditArea" rows="20" cols="60" style="display: block; margin: 1em 0 1em 1em; width: 96.5%;">'+ajax.responseText+'</textarea><br />\
+          Edit summary: <input id="ajaxEditSummary" size="40" /><br />\
+          <input id="ajaxEditMinor" name="minor" type="checkbox" /> <label for="ajaxEditMinor">This is a minor edit</label><br />\
+          <a href="#" onclick="void(ajaxSavePage()); return false;">save changes</a>  |  <a href="#" onclick="void(ajaxShowPreview()); return false;">preview changes</a>  |  <a href="#" onclick="void(ajaxEditor()); return false;">revert changes</a>  |  <a href="#" onclick="void(ajaxDiscard()); return false;">discard changes</a>  |  <a href="#" onclick="ajaxWikiEditHelp(); return false;">formatting help</a>\
+          <br />\
+          '+editNotice+'\
+        </form>';
+        // initTextareas();
+        if(readCookie('enano_editor_mode') == 'tinymce')
+        {
+          $('ajaxEditArea').switchToMCE();
+        }
+      }
+  });
+}
+
+function setEditorMCE()
+{
+  $('ajaxEditArea').switchToMCE();
+  createCookie('enano_editor_mode', 'tinymce', 365);
+  $('switcher').object.innerHTML = '<a href="#" onclick="setEditorText(); return false;">wikitext editor</a>  |  graphical editor';
+}
+
+function setEditorText()
+{
+  $('ajaxEditArea').destroyMCE();
+  createCookie('enano_editor_mode', 'text', 365);
+  $('switcher').object.innerHTML = 'wikitext editor  |  <a href="#" onclick="setEditorMCE(); return false;">graphical editor</a>';
+}
+
+function ajaxViewSource() {
+  setAjaxLoading();
+  ajaxGet(stdAjaxPrefix+'&_mode=getsource', function() {
+      if(ajax.readyState == 4) {
+        unsetAjaxLoading();
+        if(edit_open) {
+          c=confirm('Do you really want to revert your changes?');
+          if(!c) return;
+        }
+        edit_open = true;
+        selectButtonMajor('article');
+        selectButtonMinor('edit');
+        if(in_array('ajaxEditArea', grippied_textareas))
+        {
+          // Allow the textarea grippifier to re-create the resizer control on the textarea
+          grippied_textareas.pop(in_array('ajaxEditArea', grippied_textareas));
+        }
+        document.getElementById('ajaxEditContainer').innerHTML = '\
+          <form method="get" action="#" onsubmit="ajaxSavePage(); return false;">\
+            <textarea readonly="readonly" id="ajaxEditArea" rows="20" cols="60" style="display: block; margin: 1em 0 1em 1em; width: 96.5%;">'+ajax.responseText+'</textarea><br />\
+            <a href="#" onclick="void(ajaxReset()); return false;">close viewer</a>\
+          </form>';
+        initTextareas();
+      }
+  });
+}
+
+function ajaxShowPreview()
+{
+  goBusy('Loading preview...');
+  var text = ajaxEscape($('ajaxEditArea').getContent());
+  if(document.mdgAjaxEditor.minor.checked) minor='&minor';
+  else minor='';
+  ajaxPost(stdAjaxPrefix+'&_mode=preview', 'summary='+document.getElementById('ajaxEditSummary').value+minor+'&text='+text, function() {
+    if(ajax.readyState == 4) {
+      unBusy();
+      edit_open = false;
+      document.getElementById('mdgPreviewContainer').innerHTML = ajax.responseText;
+    }
+  });
+}
+
+function ajaxSavePage() {
+  goBusy('Saving page...');
+  var text = ajaxEscape($('ajaxEditArea').getContent());
+  if(document.mdgAjaxEditor.minor.checked) minor='&minor';
+  else minor='';
+  ajaxPost(stdAjaxPrefix+'&_mode=savepage', 'summary='+document.getElementById('ajaxEditSummary').value+minor+'&text='+text, function() {
+    if(ajax.readyState == 4) {
+      unBusy();
+      edit_open = false;
+      document.getElementById('ajaxEditContainer').innerHTML = ajax.responseText;
+      enableUnload();
+      unselectAllButtonsMinor();
+    }
+  });
+}
+
+function ajaxDiscard() {
+  c = confirm('Do you really want to discard your changes?');
+  if(!c) return;
+  ajaxReset();
+}
+
+function ajaxReset() {
+  enableUnload();
+  setAjaxLoading();
+  ajaxGet(stdAjaxPrefix+'&_mode=getpage&noheaders', function() {
+    if(ajax.readyState == 4) {
+      unsetAjaxLoading();
+      edit_open = false;
+      document.getElementById('ajaxEditContainer').innerHTML = ajax.responseText;
+      selectButtonMajor('article');
+      unselectAllButtonsMinor();
+    }
+  });
+}
+
+// Miscellaneous AJAX applets
+
+function ajaxProtect(l) {
+  if(shift) {
+    r = 'NO_REASON';
+  } else {
+    r = prompt('Reason for (un)protecting:');
+    if(!r || r=='') return;
+  }
+  setAjaxLoading();
+  document.getElementById('protbtn_0').style.textDecoration = 'none';
+  document.getElementById('protbtn_1').style.textDecoration = 'none';
+  document.getElementById('protbtn_2').style.textDecoration = 'none';
+  document.getElementById('protbtn_'+l).style.textDecoration = 'underline';
+  ajaxPost(stdAjaxPrefix+'&_mode=protect', 'reason='+escape(r)+'&level='+l, function() {
+    if(ajax.readyState == 4) {
+      unsetAjaxLoading();
+      if(ajax.responseText != 'good')
+        alert(ajax.responseText);
+    }
+  });
+}
+
+function ajaxRename() {
+  r = prompt('What title should this page be renamed to?\nNote: This does not and will never change the URL of this page, that must be done from the admin panel.');
+  if(!r || r=='') return;
+  setAjaxLoading();
+  ajaxPost(stdAjaxPrefix+'&_mode=rename', 'newtitle='+escape(r), function() {
+    if(ajax.readyState == 4) {
+      unsetAjaxLoading();
+      alert(ajax.responseText);
+    }
+  });
+}
+
+function ajaxMakePage() {
+  setAjaxLoading();
+  ajaxPost(ENANO_SPECIAL_CREATEPAGE, ENANO_CREATEPAGE_PARAMS, function() {
+    if(ajax.readyState == 4) {
+      unsetAjaxLoading();
+      window.location.reload();
+    }
+  });
+}
+
+function ajaxDeletePage() {
+  c = confirm('You are about to DESTROY this page. Do you REALLY want to do this?');
+  if(!c) return;
+  c = confirm('You\'re ABSOLUTELY sure???');
+  if(!c) return;
+  setAjaxLoading();
+  ajaxGet(stdAjaxPrefix+'&_mode=deletepage', function() {
+    if(ajax.readyState == 4) {
+      unsetAjaxLoading();
+      alert(ajax.responseText);
+      window.location.reload();                                                                           
+    }
+  });
+}
+
+function ajaxDelVote() {
+  c = confirm('Are you sure that you want to vote that this page be deleted?');
+  if(!c) return;
+  setAjaxLoading();
+  ajaxGet(stdAjaxPrefix+'&_mode=delvote', function() {
+    if(ajax.readyState == 4) {
+      unsetAjaxLoading();
+      alert(ajax.responseText);
+    }
+  });
+}
+
+function ajaxResetDelVotes() {
+  c = confirm('This will reset the number of votes against this page to zero. Do you really want to do this?');
+  if(!c) return;
+  setAjaxLoading();
+  ajaxGet(stdAjaxPrefix+'&_mode=resetdelvotes', function() {
+    if(ajax.readyState == 4) {
+      unsetAjaxLoading();
+      alert(ajax.responseText);
+      item = document.getElementById('mdgDeleteVoteNoticeBox');
+      if(item)
+      {
+        opacity('mdgDeleteVoteNoticeBox', 100, 0, 1000);
+        setTimeout("document.getElementById('mdgDeleteVoteNoticeBox').style.display = 'none';", 1000);
+      }
+    }
+  });
+}
+
+function ajaxSetWikiMode(val) {
+  setAjaxLoading();
+  document.getElementById('wikibtn_0').style.textDecoration = 'none';
+  document.getElementById('wikibtn_1').style.textDecoration = 'none';
+  document.getElementById('wikibtn_2').style.textDecoration = 'none';
+  document.getElementById('wikibtn_'+val).style.textDecoration = 'underline';
+  ajaxGet(stdAjaxPrefix+'&_mode=setwikimode&mode='+val, function() {
+    if(ajax.readyState == 4) {
+      unsetAjaxLoading();
+      if(ajax.responseText!='GOOD')
+      {
+        alert(ajax.responseText);
+      }
+    }
+  });
+}
+
+// Editing/saving category information
+// This was not easy to write, I hope enjoy it, and dang I swear I'm gonna
+// find someone to work on just the Javascript part of Enano...
+
+function ajaxCatEdit() {
+  setAjaxLoading();
+  ajaxGet(stdAjaxPrefix+'&_mode=catedit', function() {
+    if(ajax.readyState == 4) {
+      unsetAjaxLoading();
+      edit_open = false;
+      eval(ajax.responseText);
+    }
+  });
+}
+
+function ajaxCatSave()
+{
+  if(!catlist)
+  {
+    alert('Var catlist has no properties');
+    return;
+  }
+  query='';
+  for(i=0;i<catlist.length;i++)
+  {
+    l = 'if(document.forms.mdgCatForm.mdgCat_'+catlist[i]+'.checked) s = true; else s = false;';
+    eval(l);
+    if(s) query = query + '&' + catlist[i] + '=true';
+  }
+  setAjaxLoading();
+  query = query.substring(1, query.length);
+  ajaxPost(stdAjaxPrefix+'&_mode=catsave', query, function() {
+    if(ajax.readyState == 4) {
+      unsetAjaxLoading();
+      edit_open = false;
+      if(ajax.responseText != 'GOOD') alert(ajax.responseText);
+      ajaxReset();
+    }
+  });
+}
+
+// History stuff
+
+function ajaxHistory() {
+  setAjaxLoading();
+  ajaxGet(stdAjaxPrefix+'&_mode=histlist', function() {
+    if(ajax.readyState == 4) {
+      unsetAjaxLoading();
+      edit_open = false;
+      selectButtonMajor('article');
+      selectButtonMinor('history');
+      document.getElementById('ajaxEditContainer').innerHTML = ajax.responseText;
+      buildDiffList();
+    }
+  });
+}
+
+function ajaxHistView(oldid, tit) {
+  if(!tit) tit=title;
+  setAjaxLoading();
+  ajaxGet(append_sid(scriptPath+'/ajax.php?title='+tit+'&_mode=getpage&oldid='+oldid), function() {
+    if(ajax.readyState == 4) {
+      unsetAjaxLoading();
+      edit_open = false;
+      document.getElementById('ajaxEditContainer').innerHTML = ajax.responseText;
+    }
+  });
+}
+
+function ajaxRollback(id) {
+  setAjaxLoading();
+  ajaxGet(stdAjaxPrefix+'&_mode=rollback&id='+id, function() {
+    if(ajax.readyState == 4) {
+      unsetAjaxLoading();
+      alert(ajax.responseText);
+    }
+  });
+}
+
+function ajaxClearLogs() {
+  c = confirm('You are about to DESTROY all log entries for this page. As opposed to (example) deleting this page, this action is completely IRREVERSIBLE and should not be used except in dire circumstances. Do you REALLY want to do this?');
+  if(!c) return;
+  c = confirm('You\'re ABSOLUTELY sure???');
+  if(!c) return;
+  setAjaxLoading();
+  ajaxGet(stdAjaxPrefix+'&_mode=flushlogs', function() {
+    if(ajax.readyState == 4) {
+      unsetAjaxLoading();
+      alert(ajax.responseText);
+      window.location.reload();
+    }
+  });
+}
+
+var timelist;
+
+function buildDiffList()
+{
+  arrDiff1Buttons = getElementsByClassName(document, 'input', 'clsDiff1Radio');
+  arrDiff2Buttons = getElementsByClassName(document, 'input', 'clsDiff2Radio');
+  var len = arrDiff1Buttons.length;
+  if ( len < 1 )
+    return false;
+  timelist = new Array();
+  for ( var i = 0; i < len; i++ )
+  {
+    timelist.push( arrDiff2Buttons[i].id.substr(6) );
+  }
+  timelist.push( arrDiff1Buttons[len-1].id.substr(6) );
+  delete(timelist.toJSONString);
+  for ( var i = 1; i < timelist.length-1; i++ )
+  {
+    if ( i >= timelist.length ) break;
+    arrDiff2Buttons[i].style.display = 'none';
+  }
+}
+
+function selectDiff1Button(obj)
+{
+  var this_time = obj.id.substr(6);
+  var index = parseInt(in_array(this_time, timelist));
+  for ( var i = 0; i < timelist.length - 1; i++ )
+  {
+    if ( i < timelist.length - 1 )
+    {
+      var state = ( i < index ) ? 'inline' : 'none';
+      var id = 'diff2_' + timelist[i];
+      document.getElementById(id).style.display = state;
+      
+      // alert("Debug:\nIndex: "+index+"\nState: "+state+"\ni: "+i);
+    }
+  }
+}
+
+function selectDiff2Button(obj)
+{
+  var this_time = obj.id.substr(6);
+  var index = parseInt(in_array(this_time, timelist));
+  for ( var i = 1; i < timelist.length; i++ )
+  {
+    if ( i < timelist.length - 1 )
+    {
+      var state = ( i > index ) ? 'inline' : 'none';
+      var id = 'diff1_' + timelist[i];
+      document.getElementById(id).style.display = state;
+      
+      // alert("Debug:\nIndex: "+index+"\nState: "+state+"\ni: "+i);
+    }
+  }
+}
+
+function ajaxHistDiff()
+{
+  var id1=false;
+  var id2=false;
+  for ( i = 0; i < arrDiff1Buttons.length; i++ )
+  {
+    k = i + '';
+    kpp = i + 1;
+    kpp = kpp + '';
+    if(arrDiff1Buttons[k].checked) id1 = arrDiff1Buttons[k].id.substr(6);
+    if(arrDiff2Buttons[k].checked) id2 = arrDiff2Buttons[k].id.substr(6);
+  }
+  if(!id1 || !id2) { alert('BUG: Couldn\'t get checked radiobutton state'); return; }
+  setAjaxLoading();
+  ajaxGet(stdAjaxPrefix+'&_mode=pagediff&diff1='+id1+'&diff2='+id2, function()
+    {
+      if(ajax.readyState==4)
+      {
+        unsetAjaxLoading();
+        document.getElementById('ajaxEditContainer').innerHTML = ajax.responseText;
+      }
+    });
+}
+
+// Change the user's preferred style/theme
+
+function ajaxChangeStyle()
+{
+  var win = document.getElementById("cn2");
+  win.innerHTML = ' \
+    <form action="'+ENANO_SPECIAL_CHANGESTYLE+'" onsubmit="jws.closeWin(\'root2\');" method="post" style="text-align: center"> \
+    <h3>Select a theme...</h3>\
+    <select id="mdgThemeID" name="theme" onchange="ajaxGetStyles(this.value);"> \
+    '+ENANO_THEME_LIST+' \
+    </select> \
+    <div id="styleSelector"></div>\
+    <br /><br />\
+    <input type="hidden" name="return_to" value="'+title+'" />\
+    <input id="styleSubmitter" type="submit" style="display: none; font-weight: bold" value="Change theme" /> \
+    <input type="button" value="Cancel" onclick="jws.closeWin(\'root2\');" /> \
+    </form> \
+  ';
+  ajaxGetStyles(ENANO_CURRENT_THEME);
+  jws.openWin('root2', 340, 300);
+}
+
+function ajaxGetStyles(id) {
+  setAjaxLoading();
+  ajaxGet(stdAjaxPrefix+'&_mode=getstyles&id='+id, function() {
+    if(ajax.readyState == 4) {
+      unsetAjaxLoading();
+      eval(ajax.responseText);
+      html = '<h3>And a style...</h3><select id="mdgStyleID" name="style">';
+      for(i=0;i<list.length;i++) {
+        lname = list[i].substr(0, 1).toUpperCase() + list[i].substr(1, list[i].length);
+        html = html + '<option value="'+list[i]+'">'+lname+'</option>';
+      }
+      html = html + '</select>';
+      document.getElementById('styleSelector').innerHTML = html;
+      document.getElementById('styleSubmitter').style.display = 'inline'; 
+    }
+  });
+}
+
+function ajaxSwapCSS() {
+  setAjaxLoading();
+  if(_css) {
+    document.getElementById('mdgCss').href = main_css;
+    _css = false;
+  } else {
+    document.getElementById('mdgCss').href = print_css;
+    _css = true;
+  }
+  unsetAjaxLoading();
+  menuOff();
+}
+
+function ajaxSetPassword()
+{
+  pass = hex_sha1(document.getElementById('mdgPassSetField').value);
+  setAjaxLoading();
+  ajaxPost(stdAjaxPrefix+'&_mode=setpass', 'password='+pass, function()
+    {
+      unsetAjaxLoading();
+      if(ajax.readyState==4)
+      {
+        alert(ajax.responseText);
+      }
+    }
+  );
+}
+
+function ajaxWikiEditHelp()
+{
+  jws.openWin('root3', 640, 480);
+  setAjaxLoading();
+  ajaxGet(stdAjaxPrefix+'&_mode=wikihelp', function() {
+      if(ajax.readyState==4)
+      {
+        unsetAjaxLoading();
+        document.getElementById('cn3').innerHTML = ajax.responseText;
+      }
+    });
+}
+
+function ajaxStartLogin()
+{
+  ajaxPromptAdminAuth(function(k) {
+      window.location.reload();
+    }, 2);
+}
+
+function ajaxAdminPage()
+{
+  if ( auth_level < USER_LEVEL_ADMIN )
+  {
+    ajaxPromptAdminAuth(function(k) {
+      ENANO_SID = k;
+      auth_level = USER_LEVEL_ADMIN;
+      var loc = String(window.location + '');
+      window.location = append_sid(loc);
+      var loc = makeUrlNS('Special', 'Administration', 'module=' + namespace_list['Admin'] + 'PageManager&source=ajax&page_id=' + ajaxEscape(title));
+      if ( (ENANO_SID + ' ').length > 1 )
+        window.location = loc;
+    }, 9);
+    return false;
+  }
+  var loc = makeUrlNS('Special', 'Administration', 'module=' + namespace_list['Admin'] + 'PageManager&source=ajax&page_id=' + ajaxEscape(title));
+  window.location = loc;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/static/autocomplete.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,308 @@
+/*
+ * Auto-completing page/username fields
+ */
+
+// The ultimate Javascript app: AJAX auto-completion, which responds to up/down arrow keys, the enter key, and the escape key
+// The idea was pilfered mercilessly from vBulletin, but uses about 8
+// bytes of vB code. All the rest was coded by me, Mr. Javascript Newbie...
+
+// ...in about 8 hours.
+// You folks better like this stuff.
+
+function nameCompleteEventHandler(e)
+{
+  if(!e) e = window.event;
+  switch(e.keyCode)
+  {
+    case 38: // up
+      unSelectMove('up');
+      break;
+    case 40: // down
+      unSelectMove('down');
+      break;
+    case 27: // escape
+    case 9:  // tab
+      destroyUsernameDropdowns();
+      break;
+    case 13: // enter
+      unSelect();
+      break;
+    default: return false; break;
+  }
+  return true;
+}
+
+function unSelectMove(dir)
+{
+  if(submitAuthorized) return false;
+  var thediv = document.getElementById(unObjDivCurrentId);
+  thetable = thediv.firstChild;
+  cel = thetable.firstChild.firstChild;
+  d = true;
+  index = false;
+  changed = false;
+  // Object of the game: extract the username, determine its index in the userlist array, and then color the menu items and set unObjCurrentSelection
+  while(d) // Set to false if an exception occurs or if we arrive at our destination
+  {
+    //*
+    if(!cel) d=false;
+    celbak = cel;
+    cel = cel.nextSibling;
+    if(!cel) d=false;
+    try {
+      if(cel.firstChild.nextSibling) html = cel.firstChild.nextSibling.innerHTML;
+      else html = cel.firstChild.innerHTML;
+      cel.firstChild.className = 'row1';
+      if(cel.firstChild.nextSibling) cel.firstChild.nextSibling.className = 'row1';
+      thename = html.substr(7, html.length-15);
+      // FINALLY! we have extracted the username
+      // Now get its position in the userlist array
+      if(thename == unObjCurrentSelection)
+      {
+        index = parseInt(in_array(thename, userlist));
+      }
+      if(typeof(index) == 'number')
+      {
+        if(dir=='down')
+          n = index+1;
+        else if(dir == 'up')
+          n = index - 1;
+        
+        // Try to trap moving the selection up or down beyond the top of bottom
+        if(n > userlist.length-1 || n < 0)
+        {
+          cel.firstChild.className = 'row2';
+          if(cel.firstChild.nextSibling) cel.firstChild.nextSibling.className = 'row2';
+          return;
+        }
+        
+        if(dir=='down') no=cel.nextSibling;
+        else if(dir=='up') no=cel.previousSibling;
+        no.firstChild.className = 'row2';
+        if(no.firstChild.nextSibling) no.firstChild.nextSibling.className = 'row2';
+        if(no.firstChild.id)
+        {
+          scroll = getScrollOffset() + getHeight();
+          elemht = getElementHeight(no.firstChild.id);
+          elemoff = fetch_offset(no.firstChild);
+          whereto = elemoff['top'] + elemht;
+          if(whereto > scroll)
+          {
+            window.location.hash = '#'+no.firstChild.id;
+            unObj.focus();
+          }
+        }
+        cel=cel.nextSibling;
+        unObjCurrentSelection = userlist[n];
+        index = false;
+        changed = true;
+        return;
+      }
+    } catch(e) { }
+    //*/ d = false;
+  }
+}
+
+function unSelect()
+{
+  if(!unObj || submitAuthorized) return false;
+  if ( unObjCurrentSelection )
+    unObj.value = unObjCurrentSelection;
+  destroyUsernameDropdowns(); 
+}
+
+function in_array(needle, haystack)
+{
+  for(var i in haystack)
+  {
+    if(haystack[i] == needle) return i;
+  }
+  return false;
+}
+
+function ajaxUserNameComplete(o)
+{
+  if(!o) {destroyUsernameDropdowns(); return;}
+  if(!o.value) {destroyUsernameDropdowns(); return;}
+  if(o.value.length < 3) {destroyUsernameDropdowns(); return;}
+  //if(IE) return; // This control doesn't work in IE. Yes, it's true! document.createElement doesn't work.
+  if(!o.id)
+  {
+    o.id = 'usernametextboxobj_' + Math.floor(Math.random() * 10000000);
+  }
+  unObj = o;
+  o.setAttribute("autocomplete","off");
+  o.onkeyup = function(e, o) { o=unObj; if(!nameCompleteEventHandler(e)) ajaxUserNameComplete(o); }
+  val = escape(o.value).replace('+', '%2B');
+  ajaxGet(stdAjaxPrefix+'&_mode=fillusername&name='+val, function()
+    {
+      if(ajax.readyState==4)
+      {
+        // Determine the appropriate left/top positions, then create a div to use for the drop-down list
+        // The trick here is to be able to make the div dynamically destroy itself depending on how far the user's mouse is from it
+        destroyUsernameDropdowns();
+        off = fetch_offset(unObj);
+        dim = fetch_dimensions(unObj);
+        left = off['left'];
+        i1 = off['top'];
+        i2 = dim['h'];
+        var top = 0;
+        top = i1 + i2;
+        var thediv = document.createElement('div');
+        thediv.className = 'tblholder';
+        thediv.style.marginTop = '0px';
+        thediv.style.position = 'absolute';
+        thediv.style.top  = top  + 'px';
+        thediv.style.left = left + 'px';
+        thediv.style.zIndex = getHighestZ() + 2;
+        id = 'usernamehoverobj_' + Math.floor(Math.random() * 10000000);
+        unObjDivCurrentId = id;
+        thediv.id = id;
+        unObj.onblur = function() { destroyUsernameDropdowns(); }
+        
+        eval(ajax.responseText);
+        if(errorstring)
+        {
+          html = '<span style="color: #555; padding: 4px;">'+errorstring+'</span>';
+        }
+        else
+        {
+          html = '<table border="0" cellspacing="1" cellpadding="3" style="width: auto;"><tr><th><small>Username matches</small></th></tr>';
+          cls = 'row2';
+          unObjCurrentSelection = userlist[0];
+          for(i=0;i<userlist.length;i++)
+          {
+            tmpnam = 'listobjnode_'+Math.floor(Math.random() * 10000000);
+            html = html + '<tr><td id="'+tmpnam+'" class="'+cls+'" style="cursor: pointer;" onclick="document.getElementById(\''+unObj.id+'\').value=\''+userlist[i]+'\';destroyUsernameDropdowns();"><small>'+userlist[i]+'</small></td></tr>';
+            if(cls=='row2') cls='row1';
+          }
+          html = html + '</table>';
+        }
+        
+        thediv.innerHTML = html;
+        var body = document.getElementsByTagName('body');
+        body = body[0];
+        unSelectMenuOn = true;
+        submitAuthorized = false;
+        body.appendChild(thediv);
+      }
+    });
+}
+
+function ajaxPageNameComplete(o)
+{
+  if(!o) {destroyUsernameDropdowns(); return;}
+  if(!o.value) {destroyUsernameDropdowns(); return;}
+  if(o.value.length < 3) {destroyUsernameDropdowns(); return;}
+  if(IE) return; // This control doesn't work in IE. Yes, it's true! document.createElement doesn't work.
+  if(!o.id)
+  {
+    o.id = 'usernametextboxobj_' + Math.floor(Math.random() * 10000000);
+  }
+  o.setAttribute("autocomplete","off");
+  unObj = o;
+  o.onkeyup = function(e, o) { o=unObj; if(!nameCompleteEventHandler(e)) ajaxPageNameComplete(o); }
+  val = escape(o.value).replace('+', '%2B');
+  ajaxGet(stdAjaxPrefix+'&_mode=fillpagename&name='+val, function()
+    {
+      if(!ajax) return;
+      if(ajax.readyState==4)
+      {
+        // Determine the appropriate left/top positions, then create a div to use for the drop-down list
+        // The trick here is to be able to make the div dynamically destroy itself depending on how far the user's mouse is from it
+        destroyUsernameDropdowns();
+        off = fetch_offset(unObj);
+        dim = fetch_dimensions(unObj);
+        left = off['left'];
+        top = off['top'] + dim['h'];
+        var thediv = document.createElement('div');
+        thediv.className = 'tblholder';
+        thediv.style.marginTop = '0px';
+        thediv.style.position = 'absolute';
+        thediv.style.top  = top  + 'px';
+        thediv.style.left = left + 'px';
+        thediv.style.zIndex = getHighestZ() + 2;
+        id = 'usernamehoverobj_' + Math.floor(Math.random() * 10000000);
+        unObjDivCurrentId = id;
+        thediv.id = id;
+        
+        eval(ajax.responseText);
+        if(errorstring)
+        {
+          html = '<span style="color: #555; padding: 4px;">'+errorstring+'</span>';
+        }
+        else
+        {
+          html = '<table border="0" cellspacing="1" cellpadding="3" style="width: auto;"><tr><th colspan="2">Page name matches</th></tr><tr><th><small>Page title</small></th><th><small>Page ID</small></th></tr>';
+          cls = 'row2';
+          unObjCurrentSelection = userlist[0];
+          for(i=0;i<userlist.length;i++)
+          {
+            tmpnam = 'listobjnode_'+Math.floor(Math.random() * 10000000);
+            html = html + '<tr><td id="'+tmpnam+'" class="'+cls+'" style="cursor: pointer;" onclick="document.getElementById(\''+unObj.id+'\').value=\''+userlist[i]+'\';destroyUsernameDropdowns();"><small>'+namelist[i]+'</small></td><td class="'+cls+'" style="cursor: pointer;" onclick="document.getElementById(\''+unObj.id+'\').value=\''+userlist[i]+'\';destroyUsernameDropdowns();"><small>'+userlist[i]+'</small></td></tr>';
+            if(cls=='row2') cls='row1';
+          }
+          html = html + '</table>';
+        }
+        
+        thediv.innerHTML = html;
+        var body = document.getElementsByTagName('body');
+        body = body[0];
+        unSelectMenuOn = true;
+        submitAuthorized = false;
+        body.appendChild(thediv);
+        
+        unObj.onblur = function() { CheckDestroyUsernameDropdowns(thediv.id); };
+      }
+    });
+}
+
+function CheckDestroyUsernameDropdowns(id)
+{
+  elem = document.getElementById(id);
+  if(!elem) return;
+  if(queryOnObj(elem, 100))
+  {
+    destroyUsernameDropdowns();
+  }
+}
+
+function destroyUsernameDropdowns()
+{
+  var divs = document.getElementsByTagName('div');
+  var prefix = 'usernamehoverobj_';
+  for(i=0;i<divs.length;i++)                                                                                                                                                                                                                         
+  {
+    if ( divs[i].id )
+    {
+      if(divs[i].id.substr(0, prefix.length)==prefix)
+      {
+        divs[i].innerHTML = '';
+        divs[i].style.display = 'none';
+      }
+    }
+  }
+  unSelectMenuOn = false;
+  unObjDivCurrentId = false;
+  unObjCurrentSelection = false;
+  submitAuthorized = true;
+}
+
+function get_parent_form(o)
+{
+  if ( !o.parentNode )
+    return false;
+  if ( o.tagName == 'FORM' )
+    return o;
+  var p = o.parentNode;
+  while(true)
+  {
+    if ( p.tagName == 'FORM' )
+      return p;
+    else if ( !p )
+      return false;
+    else
+      p = p.parentNode;
+  }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/static/base64.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,113 @@
+// Base64 encoder/decoder - pulled from http://ostermiller.org/calc/encode.html. Licensed under the GPL.
+
+var END_OF_INPUT = -1;
+
+var base64Chars = new Array(
+    'A','B','C','D','E','F','G','H',
+    'I','J','K','L','M','N','O','P',
+    'Q','R','S','T','U','V','W','X',
+    'Y','Z','a','b','c','d','e','f',
+    'g','h','i','j','k','l','m','n',
+    'o','p','q','r','s','t','u','v',
+    'w','x','y','z','0','1','2','3',
+    '4','5','6','7','8','9','+','/'
+);
+
+var reverseBase64Chars = new Array();
+for (var i=0; i < base64Chars.length; i++){
+    reverseBase64Chars[base64Chars[i]] = i;
+}
+
+var base64Str;
+var base64Count;
+
+function setBase64Str(str){
+    base64Str = str;
+    base64Count = 0;
+}
+function readBase64(){    
+    if (!base64Str) return END_OF_INPUT;
+    if (base64Count >= base64Str.length) return END_OF_INPUT;
+    var c = base64Str.charCodeAt(base64Count) & 0xff;
+    base64Count++;
+    return c;
+}
+function encodeBase64(str){
+    setBase64Str(str);
+    var result = '';
+    var inBuffer = new Array(3);
+    var lineCount = 0;
+    var done = false;
+    while (!done && (inBuffer[0] = readBase64()) != END_OF_INPUT){
+        inBuffer[1] = readBase64();
+        inBuffer[2] = readBase64();
+        result += (base64Chars[ inBuffer[0] >> 2 ]);
+        if (inBuffer[1] != END_OF_INPUT){
+            result += (base64Chars [(( inBuffer[0] << 4 ) & 0x30) | (inBuffer[1] >> 4) ]);
+            if (inBuffer[2] != END_OF_INPUT){
+                result += (base64Chars [((inBuffer[1] << 2) & 0x3c) | (inBuffer[2] >> 6) ]);
+                result += (base64Chars [inBuffer[2] & 0x3F]);
+            } else {
+                result += (base64Chars [((inBuffer[1] << 2) & 0x3c)]);
+                result += ('=');
+                done = true;
+            }
+        } else {
+            result += (base64Chars [(( inBuffer[0] << 4 ) & 0x30)]);
+            result += ('=');
+            result += ('=');
+            done = true;
+        }
+        lineCount += 4;
+        if (lineCount >= 76){
+            result += ('\n');
+            lineCount = 0;
+        }
+    }
+    return result;
+}
+function readReverseBase64(){   
+    if (!base64Str) return END_OF_INPUT;
+    while (true){      
+        if (base64Count >= base64Str.length) return END_OF_INPUT;
+        var nextCharacter = base64Str.charAt(base64Count);
+        base64Count++;
+        if (reverseBase64Chars[nextCharacter]){
+            return reverseBase64Chars[nextCharacter];
+        }
+        if (nextCharacter == 'A') return 0;
+    }
+    return END_OF_INPUT;
+}
+
+function ntos(n){
+    n=n.toString(16);
+    if (n.length == 1) n="0"+n;
+    n="%"+n;
+    return unescape(n);
+}
+
+function decodeBase64(str){
+    setBase64Str(str);
+    var result = "";
+    var inBuffer = new Array(4);
+    var done = false;
+    while (!done && (inBuffer[0] = readReverseBase64()) != END_OF_INPUT
+        && (inBuffer[1] = readReverseBase64()) != END_OF_INPUT){
+        inBuffer[2] = readReverseBase64();
+        inBuffer[3] = readReverseBase64();
+        result += ntos((((inBuffer[0] << 2) & 0xff)| inBuffer[1] >> 4));
+        if (inBuffer[2] != END_OF_INPUT){
+            result +=  ntos((((inBuffer[1] << 4) & 0xff)| inBuffer[2] >> 2));
+            if (inBuffer[3] != END_OF_INPUT){
+                result +=  ntos((((inBuffer[2] << 6)  & 0xff) | inBuffer[3]));
+            } else {
+                done = true;
+            }
+        } else {
+            done = true;
+        }
+    }
+    return result;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/static/comments.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,569 @@
+// Comments
+
+var comment_template = false;
+
+function ajaxComments(parms) {
+  setAjaxLoading();
+  var pid = strToPageID(title);
+  if(!parms)
+  {
+    var parms = {
+      'mode' : 'fetch'
+    };
+  }
+  parms.page_id = pid[0];
+  parms.namespace = pid[1];
+  if(comment_template)
+    parms.have_template = true;
+  parms = ajaxEscape(toJSONString(parms));
+  ajaxPost(stdAjaxPrefix+'&_mode=comments', 'data=' + parms, function() {
+    if(ajax.readyState == 4) {
+      unsetAjaxLoading();
+      selectButtonMajor('discussion');
+      unselectAllButtonsMinor();
+      // IE compatibility - doing ajax.responseText.substr() doesn't work
+      var rsptxt = ajax.responseText + '';
+      if ( rsptxt.substr(0, 1) != '{' )
+      {
+        document.getElementById('ajaxEditContainer').innerHTML = '<p>Comment system Javascript runtime: invalid JSON response from server, response text:</p><pre>' + ajax.responseText + '</pre>';
+        return false;
+      }
+      var response = parseJSON(ajax.responseText);
+      switch(response.mode)
+      {
+        case 'fetch':
+          document.getElementById('ajaxEditContainer').innerHTML = 'Rendering response...';
+          if(response.template)
+            comment_template = response.template;
+          setAjaxLoading();
+          renderComments(response);
+          unsetAjaxLoading();
+          break;
+        case 'redraw':
+          redrawComment(response);
+          break;
+        case 'annihilate':
+          annihiliateComment(response.id);
+          break;
+        case 'materialize':
+          alert('Your comment has been posted. If it does not appear right away, it is probably awaiting approval.');
+          hideCommentForm();
+          materializeComment(response);
+          break;
+        case 'error':
+          alert(response.error);
+          break;
+        default:
+          alert(ajax.responseText);
+          break;
+      }
+    }
+  });
+}
+
+function renderComments(data)
+{
+  
+  var html = '';
+  
+  // Header
+  
+    html += '<h3>Article Comments</h3>';
+    
+    var ns = ( strToPageID(title)[1]=='Article' ) ? 'article' : ( strToPageID(title)[1].toLowerCase() ) + ' page';
+  
+    // Counters
+    if ( data.auth_mod_comments )
+    {
+      var cnt = ( data.auth_mod_comments ) ? data.count_total : data.count_appr;
+      if ( cnt == 0 ) cnt = 'no';
+      var s  = ( cnt == 1 ) ? '' : 's';
+      var is = ( cnt == 1 ) ? 'is' : 'are';
+      html += "<p id=\"comment_status\">There "+is+" " + cnt + " comment"+s+" on this "+ns+".";
+      if ( data.count_unappr > 0 )
+      {
+        html += ' <span style="color: #D84308">' + data.count_unappr + ' of those are unapproved.</span>';
+      }
+      html += '</p>';
+    }
+    else
+    {
+      var cnt = data.count_appr;
+      if ( cnt == 0 ) cnt = 'no';
+      var s  = ( cnt == 1 ) ? '' : 's';
+      var is = ( cnt == 1 ) ? 'is' : 'are';
+      html += "<p id=\"comment_status\">There "+is+" " + cnt + " comment"+s+" on this "+ns+".";
+      if ( data.count_unappr > 0 )
+      {
+        var s  = ( data.count_unappr == 1 ) ? '' : 's';
+        var is = ( data.count_unappr == 1 ) ? 'is' : 'are';
+        html += ' However, there '+is+' '+data.count_unappr+' additional comment'+s+' awaiting approval.';
+      }
+      html += '</p>';
+    }
+    
+  // Comment display
+  
+  if ( data.count_total > 0 )
+  {
+    var parser = new templateParser(comment_template);
+    for ( var i = 0; i < data.comments.length; i++ )
+    {
+      var tplvars = new Object();
+      
+      if ( data.comments[i].approved != '1' && !data.auth_mod_comments )
+        continue;
+      
+      tplvars.ID = i;
+      tplvars.DATETIME = data.comments[i].time;
+      tplvars.SUBJECT = data.comments[i].subject;
+      tplvars.DATA = data.comments[i].comment_data;
+      tplvars.SIGNATURE = data.comments[i].signature;
+      
+      if ( data.comments[i].approved != '1' )
+        tplvars.SUBJECT += ' <span style="color: #D84308">(Unapproved)</span>';
+      
+      // Name
+      tplvars.NAME = data.comments[i].name;
+      if ( data.comments[i].user_id > 1 )
+        tplvars.NAME = '<a href="' + makeUrlNS('User', data.comments[i].name) + '">' + data.comments[i].name + '</a>';
+      
+      // User level
+      tplvars.USER_LEVEL = 'Guest';
+      if ( data.comments[i].user_level >= data.user_level.member ) tplvars.USER_LEVEL = 'Member';
+      if ( data.comments[i].user_level >= data.user_level.mod ) tplvars.USER_LEVEL = 'Moderator';
+      if ( data.comments[i].user_level >= data.user_level.admin ) tplvars.USER_LEVEL = 'Administrator';
+      
+      // Send PM link
+      tplvars.SEND_PM_LINK=(data.comments[i].user_id>1)?'<a onclick="window.open(this.href); return false;" href="'+ makeUrlNS('Special', 'PrivateMessages/Compose/To/' + ( data.comments[i].name.replace(/ /g, '_') )) +'">Send private message</a><br />':'';
+      
+      // Add buddy link
+      tplvars.ADD_BUDDY_LINK=(data.comments[i].user_id>1)?'<a onclick="window.open(this.href); return false;" href="'+ makeUrlNS('Special', 'PrivateMessages/FriendList/Add/' + ( data.comments[i].name.replace(/ /g, '_') )) +'">Add to buddy list</a><br />':'';
+      
+      // Edit link
+      tplvars.EDIT_LINK='<a href="#edit_'+i+'" onclick="editComment(\''+i+'\', this); return false;" id="cmteditlink_'+i+'">edit</a>';
+      
+      // Delete link
+      tplvars.DELETE_LINK='<a href="#delete_'+i+'" onclick="deleteComment(\''+i+'\'); return false;">delete</a>';
+      
+      // Moderation: (Un)approve link
+      var appr = ( data.comments[i].approved == 1 ) ? 'Unapprove' : 'Approve';
+      tplvars.MOD_APPROVE_LINK='<a href="#approve_'+i+'" id="comment_approve_'+i+'" onclick="approveComment(\''+i+'\'); return false;">'+appr+'</a>';
+      
+      // Moderation: Delete post link
+      tplvars.MOD_DELETE_LINK='<a href="#mod_del_'+i+'" onclick="deleteComment(\''+i+'\'); return false;">Delete</a>';
+      
+      var tplbool = new Object();
+      
+      tplbool.signature = ( data.comments[i].signature == '' ) ? false : true;
+      tplbool.can_edit = ( data.auth_edit_comments && ( ( data.comments[i].user_id == data.user_id && data.logged_in ) || data.auth_mod_comments ) );
+      tplbool.auth_mod = data.auth_mod_comments;
+      
+      parser.assign_vars(tplvars);
+      parser.assign_bool(tplbool);
+      
+      html += '<div id="comment_holder_' + i + '"><input type="hidden" value="'+data.comments[i].comment_id+'" /><input type="hidden" id="comment_source_'+i+'" />' + parser.run() + '</div>';
+    }
+  }
+  
+  // Posting form
+  
+    html += '<h3>Got something to say?</h3>';
+    html += '<p>If you have comments or suggestions on this article, you can shout it out here.';
+    if ( data.approval_needed )
+      html+=' Before your post will be visible to the public, a moderator will have to approve it.';
+    html += ' <a id="leave_comment_button" href="#" onclick="displayCommentForm(); return false;">Leave a comment...</a></p>';
+    html += '<div id="comment_form" style="display: none;">';
+    html += '  <table border="0">';
+    html += '    <tr><td>Your name/screen name:</td><td>';
+    if ( data.user_id > 1 ) html += data.username + '<input id="commentform_name" type="hidden" value="'+data.username+'" size="40" />';
+    else html += '<input id="commentform_name" type="text" size="40" />';
+    html += '    </td></tr>';
+    html += '    <tr><td>Comment subject:</td><td><input id="commentform_subject" type="text" size="40" /></td></tr>';
+    html += '    <tr><td>Comment:</td><td><textarea id="commentform_message" rows="15" cols="50"></textarea></td></tr>';
+    if ( !data.logged_in && data.guest_posting == '1' )
+    {
+      html += '  <tr><td>Visual confirmation:<br /><small>Please enter the confirmation code seen in the image on the right into the box. If you cannot read the code, please click on the image to generate a new one. This helps to prevent automated bot posting.</small></td><td>';
+      html += '  <img alt="CAPTCHA image" src="'+makeUrlNS('Special', 'Captcha/' + data.captcha)+'" onclick="this.src=\''+makeUrlNS('Special', 'Captcha/' + data.captcha)+'/\'+Math.floor(Math.random()*10000000);" style="cursor: pointer;" /><br />';
+      html += '  Confirmation code: <input type="text" size="8" id="commentform_captcha" />';
+      html += '  <!-- This input is used to track the ID of the CAPTCHA image --> <input type="hidden" id="commentform_captcha_id" value="'+data.captcha+'" />';
+      html += '  </td></tr>';
+    }
+    html += '    <tr><td colspan="2" style="text-align: center;"><input type="button" onclick="submitComment();" value="Submit comment" /></td></tr>';
+    html += '  </table>';
+    html += '</div>';
+    
+  document.getElementById('ajaxEditContainer').innerHTML = html;
+  
+  for ( i = 0; i < data.comments.length; i++ )
+  {
+    document.getElementById('comment_source_'+i).value = data.comments[i].comment_source;
+  }
+  
+}
+
+function displayCommentForm()
+{
+  document.getElementById('leave_comment_button').style.display = 'none';
+  document.getElementById('comment_form').style.display = 'block';
+}
+
+function hideCommentForm()
+{
+  document.getElementById('leave_comment_button').style.display = 'inline';
+  document.getElementById('comment_form').style.display = 'none';
+}
+
+function editComment(id, link)
+{
+  var ctr = document.getElementById('subject_'+id);
+  var subj = trim(ctr.firstChild.nodeValue); // If there's a span in there that says 'unapproved', this eliminates it
+  ctr.innerHTML = '';
+  var ipt = document.createElement('input');
+  ipt.id = 'subject_edit_'+id;
+  ipt.value = subj;
+  ctr.appendChild(ipt);
+  
+  var src = document.getElementById('comment_source_'+id).value;
+  var cmt = document.getElementById('comment_'+id);
+  cmt.innerHTML = '';
+  var ta = document.createElement('textarea');
+  ta.rows = '10';
+  ta.cols = '40';
+  ta.value = src;
+  ta.id = 'comment_edit_'+id;
+  cmt.appendChild(ta);
+  
+  link.style.fontWeight = 'bold';
+  link.innerHTML = 'save';
+  link.onclick = function() { var id = this.id.substr(this.id.indexOf('_')+1); saveComment(id, this); return false; };
+}
+
+function saveComment(id, link)
+{
+  var data = document.getElementById('comment_edit_'+id).value;
+  var subj = document.getElementById('subject_edit_'+id).value;
+  var div = document.getElementById('comment_holder_'+id);
+  var real_id = div.getElementsByTagName('input')[0]['value'];
+  var req = {
+    'mode' : 'edit',
+    'id'   : real_id,
+    'local_id' : id,
+    'data' : data,
+    'subj' : subj
+  };
+  link.style.fontWeight = 'normal';
+  link.innerHTML = 'edit';
+  link.onclick = function() { var id = this.id.substr(this.id.indexOf('_')+1); editComment(id, this); return false; };
+  ajaxComments(req);
+}
+
+function deleteComment(id)
+{
+  //var c = confirm('Do you really want to delete this comment?');
+  //if(!c);
+  //  return false;
+  var div = document.getElementById('comment_holder_'+id);
+  var real_id = div.getElementsByTagName('input')[0]['value'];
+  var req = {
+    'mode' : 'delete',
+    'id'   : real_id,
+    'local_id' : id
+  };
+  ajaxComments(req);
+}
+
+function submitComment()
+{
+  var name = document.getElementById('commentform_name').value;
+  var subj = document.getElementById('commentform_subject').value;
+  var text = document.getElementById('commentform_message').value;
+  if ( document.getElementById('commentform_captcha') )
+  {
+    var captcha_code = document.getElementById('commentform_captcha').value;
+    var captcha_id   = document.getElementById('commentform_captcha_id').value;
+  }
+  else
+  {
+    var captcha_code = '';
+    var captcha_id   = '';
+  }
+  var req = {
+    'mode' : 'submit',
+    'name' : name,
+    'subj' : subj,
+    'text' : text,
+    'captcha_code' : captcha_code,
+    'captcha_id'   : captcha_id
+  };
+  ajaxComments(req);
+}
+
+function redrawComment(data)
+{
+  if ( data.subj )
+  {
+    document.getElementById('subject_' + data.id).innerHTML = data.subj;
+  }
+  if ( data.approved && data.approved != '1' )
+  {
+    document.getElementById('subject_' + data.id).innerHTML += ' <span style="color: #D84308">(Unapproved)</span>';
+  }
+  if ( data.approved )
+  {
+    var appr = ( data.approved == '1' ) ? 'Unapprove' : 'Approve';
+    document.getElementById('comment_approve_'+data.id).innerHTML = appr;
+    var p = document.getElementById('comment_status');
+    var count = p.firstChild.nodeValue.split(' ')[2];
+    if ( p.firstChild.nextSibling )
+    {
+      var span = p.firstChild.nextSibling;
+      var is = ( data.approved == '1' ) ? -1 : 1;
+      var n_unapp = parseInt(span.firstChild.nodeValue.split(' ')[0]) + is;
+      n_unapp = n_unapp + '';
+    }
+    else
+    {
+      var span = document.createElement('span');
+      p.innerHTML += ' ';
+      span.innerHTML = ' ';
+      span.style.color = '#D84308';
+      var n_unapp = '1';
+      p.appendChild(span);
+    }
+    span.innerHTML = n_unapp + ' of those are unapproved.';
+    if ( n_unapp == '0' )
+      p.removeChild(span);
+  }
+  if ( data.text )
+  {
+    document.getElementById('comment_' + data.id).innerHTML = data.text;
+  }
+  if ( data.src )
+  {
+    document.getElementById('comment_source_' + data.id).value = data.src;
+  }
+}
+
+function approveComment(id)
+{
+  var div = document.getElementById('comment_holder_'+id);
+  var real_id = div.getElementsByTagName('input')[0]['value'];
+  var req = {
+    'mode' : 'approve',
+    'id'   : real_id,
+    'local_id' : id
+  };
+  ajaxComments(req);
+}
+
+// Does the actual DOM object removal
+function annihiliateComment(id) // Did I spell that right?
+{
+  // Approved?
+  var p = document.getElementById('comment_status');
+  
+  if(document.getElementById('comment_approve_'+id))
+  {
+    var appr = document.getElementById('comment_approve_'+id).firstChild.nodeValue;
+    if ( p.firstChild.nextSibling && appr == 'Approve' )
+    {
+      var span = p.firstChild.nextSibling;
+      var t = span.firstChild.nodeValue;
+      var n_unapp = ( parseInt(t.split(' ')[0]) ) - 1;
+      if ( n_unapp == 0 )
+        p.removeChild(span);
+      else
+        span.firstChild.nodeValue = n_unapp + t.substr(t.indexOf(' '));
+    }
+  }
+  
+  var div = document.getElementById('comment_holder_'+id);
+  div.parentNode.removeChild(div);
+  var t = p.firstChild.nodeValue.split(' ');
+  t[2] = ( parseInt(t[2]) - 1 ) + '';
+  delete(t.toJSONString);
+  if ( t[2] == '1' )
+  {
+    t[1] = 'is';
+    t[3] = 'comment';
+  }
+  else
+  {
+    t[1] = 'are';
+    t[3] = 'comments';
+  }
+  t = implode(' ', t);
+  p.firstChild.nodeValue = t;
+}
+
+function materializeComment(data)
+{
+  // Intelligently get an ID
+
+  var i = 0;
+  var brother;
+  while ( true )
+  {
+    var x = document.getElementById('comment_holder_'+i);
+    if(!x)
+      break;
+    brother = x;
+    i++;
+  }
+  
+  var parser = new templateParser(comment_template);
+  var tplvars = new Object();
+  
+  if ( data.approved != '1' && !data.auth_mod_comments )
+    return false;
+  
+  tplvars.ID = i;
+  tplvars.DATETIME = data.time;
+  tplvars.SUBJECT = data.subject;
+  tplvars.DATA = data.comment_data;
+  tplvars.SIGNATURE = data.signature;
+  
+  tplvars.NAME = data.name;
+  if ( data.user_id > 1 )
+    tplvars.NAME = '<a href="' + makeUrlNS('User', data.name) + '">' + data.name + '</a>';
+  
+  if ( data.approved != '1' )
+    tplvars.SUBJECT += ' <span style="color: #D84308">(Unapproved)</span>';
+  
+  // User level
+  tplvars.USER_LEVEL = 'Guest';
+  if ( data.user_level >= data.user_level_list.member ) tplvars.USER_LEVEL = 'Member';
+  if ( data.user_level >= data.user_level_list.mod ) tplvars.USER_LEVEL = 'Moderator';
+  if ( data.user_level >= data.user_level_list.admin ) tplvars.USER_LEVEL = 'Administrator';
+  
+  // Send PM link
+  tplvars.SEND_PM_LINK=(data.user_id>1)?'<a onclick="window.open(this.href); return false;" href="'+ makeUrlNS('Special', 'PrivateMessages/Compose/To/' + ( data.name.replace(/ /g, '_') )) +'">Send private message</a><br />':'';
+  
+  // Add buddy link
+  tplvars.ADD_BUDDY_LINK=(data.user_id>1)?'<a onclick="window.open(this.href); return false;" href="'+ makeUrlNS('Special', 'PrivateMessages/FriendList/Add/' + ( data.name.replace(/ /g, '_') )) +'">Add to buddy list</a><br />':'';
+  
+  // Edit link
+  tplvars.EDIT_LINK='<a href="#edit_'+i+'" onclick="editComment(\''+i+'\', this); return false;" id="cmteditlink_'+i+'">edit</a>';
+  
+  // Delete link
+  tplvars.DELETE_LINK='<a href="#delete_'+i+'" onclick="deleteComment(\''+i+'\'); return false;">delete</a>';
+  
+  // Moderation: (Un)approve link
+  var appr = ( data.approved == 1 ) ? 'Unapprove' : 'Approve';
+  tplvars.MOD_APPROVE_LINK='<a href="#approve_'+i+'" id="comment_approve_'+i+'" onclick="approveComment(\''+i+'\'); return false;">'+appr+'</a>';
+  
+  // Moderation: Delete post link
+  tplvars.MOD_DELETE_LINK='<a href="#mod_del_'+i+'" onclick="deleteComment(\''+i+'\'); return false;">Delete</a>';
+  
+  var tplbool = new Object();
+  
+  tplbool.signature = ( data.signature == '' ) ? false : true;
+  tplbool.can_edit = ( data.auth_edit_comments && ( ( data.user_id == data.user_id && data.logged_in ) || data.auth_mod_comments ) );
+  tplbool.auth_mod = data.auth_mod_comments;
+  
+  parser.assign_vars(tplvars);
+  parser.assign_bool(tplbool);
+  
+  var div = document.createElement('div');
+  div.id = 'comment_holder_'+i;
+  
+  div.innerHTML = '<input type="hidden" value="'+data.comment_id+'" /><input type="hidden" id="comment_source_'+i+'" />' + parser.run();
+  
+  if ( brother )
+  {
+    brother.parentNode.insertBefore(div, brother.nextSibling);
+  }
+  else
+  {
+    // No comments in ajaxEditContainer, insert it after the header
+    var aec = document.getElementById("ajaxEditContainer");
+    aec.insertBefore(div, aec.firstChild.nextSibling.nextSibling);
+  }
+  
+  document.getElementById('comment_source_'+i).value = data.comment_source;
+  
+  var p = document.getElementById('comment_status');
+  var t = p.firstChild.nodeValue.split(' ');
+  var n = ( isNaN(parseInt(t[2])) ) ? 0 : parseInt(t[2]);
+  t[2] = ( n + 1 ) + '';
+  delete(t.toJSONString);
+  if ( t[2] == '1' )
+  {
+    t[1] = 'is';
+    t[3] = 'comment';
+  }
+  else
+  {
+    t[1] = 'are';
+    t[3] = 'comments';
+  }
+  t = implode(' ', t);
+  p.firstChild.nodeValue = t;
+  
+  if(document.getElementById('comment_approve_'+i))
+  {
+    var appr = document.getElementById('comment_approve_'+i).firstChild.nodeValue;
+    if ( p.firstChild.nextSibling && appr == 'Approve' )
+    {
+      var span = p.firstChild.nextSibling;
+      var t = span.firstChild.nodeValue;
+      var n_unapp = ( parseInt(t.split(' ')[0]) ) - 1;
+      if ( n_unapp == 0 )
+        p.removeChild(span);
+      else
+        span.firstChild.nodeValue = n_unapp + t.substr(t.indexOf(' '));
+    }
+    else if ( appr == 'Approve' && !p.firstChild.nextSibling )
+    {
+      var span = document.createElement('span');
+      p.innerHTML += ' ';
+      span.innerHTML = '1 of those are unapproved.';
+      span.style.color = '#D84308';
+      var n_unapp = '1';
+      p.appendChild(span);
+    }
+  }
+  
+}
+
+function htmlspecialchars(text)
+{
+  text = text.replace(/</g, '&lt;');
+  text = text.replace(/>/g, '&gt;');
+  return text;
+}
+
+// Equivalent to PHP trim() function
+function trim(text)
+{
+  text = text.replace(/^([\s]+)/, '');
+  text = text.replace(/([\s]+)$/, '');
+  return text;
+}
+
+// Equivalent to PHP implode() function
+function implode(chr, arr)
+{
+  if ( typeof ( arr.toJSONString ) == 'function' )
+    delete(arr.toJSONString);
+  
+  var ret = '';
+  var c = 0;
+  for ( var i in arr )
+  {
+    if(i=='toJSONString')continue;
+    if ( c > 0 )
+      ret += chr;
+    ret += arr[i];
+    c++;
+  }
+  return ret;
+}
+
+function nl2br(text)
+{
+  var regex = new RegExp(unescape('%0A'), 'g');
+  return text.replace(regex, '<br />' + unescape('%0A'));
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/static/dropdown.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,508 @@
+/*
+ * The jBox menu system. Written by Dan Fuhry and licensed under the GPL.
+ */
+
+// Cache of DOM and event objects, used in setTimeout() calls due to scope rules
+var jBoxObjCache = new Object();
+
+// Cache of "correct" heights for unordered list objects used in submenus. Helps the animation routine know what height it's aiming for.
+var jBoxMenuHeights = new Object();
+
+// Blocks animations from running if there's already an animation going on the same object
+var jBoxSlideBlocker = new Object();
+
+// Speed at which the menus should slide open. 1 to 100 or -1 to disable.
+// Setting this higher than 100 will cause an infinite loop in the browser.
+// Default is 80 - anything higher than 90 means exponential speed increase
+var slide_speed = 80;
+
+// Inertia value to start with
+// Default is 0
+var inertia_base = 0;
+
+// Value added to inertia_base on each frame - generally 1 to 3 is good, with 1 being slowest animation
+// Default is 1
+var inertia_inc  = 1;
+
+// Opacity that menus should fade to. 1 to 100 or -1 to disable fades. This only works if the slide effect is also enabled.
+// Default is 100
+var jBox_opacity = 100;
+
+// Adds the jBox CSS to the HTML header. Called on window onload.
+function jBoxInit()
+{
+  setTimeout('jBoxBatchSetup();', 200);
+}
+
+// Initializes each menu.
+function jBoxBatchSetup()
+{
+  var menus = document.getElementsByClassName('div', 'menu_nojs');
+  if ( menus.length > 0 )
+  {
+    for ( var i in menus )
+    {
+      if ( typeof(menus[i]) != 'object')
+        continue; // toJSONString() compatibility
+      jBoxSetup(menus[i]);
+    }
+  }
+}
+
+// Initializes a div with a jBox menu in it.
+function jBoxSetup(obj)
+{
+  $(obj).addClass('menu');
+  removeTextNodes(obj);
+  for ( var i in obj.childNodes )
+  {
+    /* normally this would be done in about 2 lines of code, but javascript is so picky..... */
+    if ( obj.childNodes[i] )
+    {
+      if ( obj.childNodes[i].tagName )
+      {
+        if ( obj.childNodes[i].tagName.toLowerCase() == 'a' )
+        {
+          if ( obj.childNodes[i].nextSibling.tagName )
+          {
+            if ( obj.childNodes[i].nextSibling.tagName.toLowerCase() == 'ul' || ( obj.childNodes[i].nextSibling.tagName.toLowerCase() == 'div' && obj.childNodes[i].nextSibling.className == 'submenu' ) )
+            {
+              // Calculate height
+              var ul = obj.childNodes[i].nextSibling;
+              domObjChangeOpac(0, ul);
+              ul.style.display = 'block';
+              var dim = fetch_dimensions(ul);
+              if ( !ul.id )
+                ul.id = 'jBoxmenuobj_' + Math.floor(Math.random() * 10000000);
+              jBoxMenuHeights[ul.id] = parseInt(dim['h']) - 2; // subtract 2px for border width
+              ul.style.display = 'none';
+              domObjChangeOpac(100, ul);
+              
+              // Setup events
+              obj.childNodes[i].onmouseover = function()  { jBoxOverHandler(this); };
+              obj.childNodes[i].onmouseout = function(e)  { jBoxOutHandler(this, e); };
+              obj.childNodes[i].nextSibling.onmouseout = function(e)  { jBoxOutHandler(this, e); };
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
+// Called when user hovers mouse over a submenu
+function jBoxOverHandler(obj)
+{
+  // Random ID used to track the object to perform on
+  var seed = Math.floor(Math.random() * 1000000);
+  jBoxObjCache[seed] = obj;
+  
+  // Sleep for a (little more than a tenth of a) second to see if the user really wants the menu to expand
+  setTimeout('if(isOverObj(jBoxObjCache['+seed+'], false, false)) jBoxOverHandlerBin(jBoxObjCache['+seed+']);', 150);
+}
+
+// Displays a menu.
+function jBoxOverHandlerBin(obj)
+{
+  var others = obj.parentNode.getElementsByTagName('ul');
+  for ( var i in others )
+  {
+    if(typeof(others[i]) == 'object')
+    {
+      others[i].style.display = 'none';
+      others[i].previousSibling.className = '';
+    }
+  }
+  var others = obj.parentNode.getElementsByTagName('div');
+  for ( var i in others )
+  {
+    if(typeof(others[i]) == 'object')
+    {
+      if ( others[i].className == 'submenu' )
+      {
+        others[i].style.display = 'none';
+        others[i].previousSibling.className = '';
+      }
+    }
+  }
+  if(obj.nextSibling.tagName.toLowerCase() == 'ul' || ( obj.nextSibling.tagName.toLowerCase() == 'div' && obj.nextSibling.className == 'submenu' ))
+  {
+    obj.className = 'liteselected';
+    var ul = obj.nextSibling;
+    var dim = fetch_dimensions(obj);
+    var off = fetch_offset(obj);
+    var dimh = parseInt(dim['h']);
+    var offtop = parseInt(off['top']);
+    var top = dimh + offtop;
+    left = off['left'];
+    ul.style.left = left + 'px';
+    ul.style.top = top + 'px';
+    domObjChangeOpac(0, ul);
+    ul.style.clip = 'rect(auto,auto,auto,auto)';
+    ul.style.overflow = 'visible';
+    ul.style.display = 'block';
+    slideOut(ul);
+  }
+}
+
+function jBoxOutHandler(obj, event)
+{
+  var seed = Math.floor(Math.random() * 1000000);
+  var seed2 = Math.floor(Math.random() * 1000000);
+  jBoxObjCache[seed] = obj;
+  jBoxObjCache[seed2] = event;
+  setTimeout('jBoxOutHandlerBin(jBoxObjCache['+seed+'], jBoxObjCache['+seed2+']);', 750);
+}
+
+function jBoxOutHandlerBin(obj, event)
+{
+  var caller = obj.tagName.toLowerCase();
+  if(caller == 'a')
+  {
+    a = obj;
+    ul = obj.nextSibling;
+  }
+  else if(caller == 'ul' || caller == 'div')
+  {
+    a = obj.previousSibling;
+    ul = obj;
+  }
+  else
+  {
+    return false;
+  }
+  
+  if (!isOverObj(a, false, event) && !isOverObj(ul, true, event))
+  {
+    a.className = '';
+    
+    slideIn(ul);
+    
+  }
+  
+  return true;
+}
+
+// Slide an element downwards until it is at full height.
+// First parameter should be a DOM object with style.display = block and opacity = 0.
+
+var sliderobj = new Object();
+
+function slideOut(obj)
+{
+  if ( jBoxSlideBlocker[obj.id] )
+    return false;
+  
+  jBoxSlideBlocker[obj.id] = true;
+  
+  if ( slide_speed == -1 )
+  {
+    obj.style.display = 'block';
+    return false;
+  }
+  
+  var currentheight = 0;
+  var targetheight = jBoxMenuHeights[obj.id];
+  var inertiabase = inertia_base;
+  var inertiainc = inertia_inc;
+  slideStep(obj, 0);
+  domObjChangeOpac(100, obj);
+  obj.style.overflow = 'hidden';
+  
+  // Don't edit past here
+  var timercnt = 0;
+  
+  var seed = Math.floor(Math.random() * 1000000);
+  sliderobj[seed] = obj;
+  
+  var framecnt = 0;
+  
+  while(true)
+  {
+    framecnt++;
+    timercnt += ( 100 - slide_speed );
+    inertiabase += inertiainc;
+    currentheight += inertiabase;
+    if ( currentheight > targetheight )
+      currentheight = targetheight;
+    setTimeout('slideStep(sliderobj['+seed+'], '+currentheight+', '+targetheight+');', timercnt);
+    if ( currentheight >= targetheight )
+      break;
+  }
+  timercnt = timercnt + ( 100 - slide_speed );
+  setTimeout('jBoxSlideBlocker[sliderobj['+seed+'].id] = false;', timercnt);
+  var opacstep = jBox_opacity / framecnt;
+  var opac = 0;
+  var timerstep = 0;
+  domObjChangeOpac(0, obj);
+  while(true)
+  {
+    timerstep += ( 100 - slide_speed );
+    opac += opacstep;
+    setTimeout('domObjChangeOpac('+opac+', sliderobj['+seed+']);', timerstep);
+    if ( opac >= jBox_opacity )
+      break;
+  }
+}
+
+function slideIn(obj)
+{
+  if ( obj.style.display != 'block' )
+    return false;
+  
+  if ( jBoxSlideBlocker[obj.id] )
+    return false;
+  
+  jBoxSlideBlocker[obj.id] = true;
+  
+  var targetheight = 0;
+  var dim = fetch_dimensions(obj);
+  var currentheight = jBoxMenuHeights[obj.id];
+  var origheight = currentheight;
+  var inertiabase = inertia_base;
+  var inertiainc = inertia_inc;
+  domObjChangeOpac(100, obj);
+  obj.style.overflow = 'hidden';
+  
+  // Don't edit past here
+  var timercnt = 0;
+  
+  var seed = Math.floor(Math.random() * 1000000);
+  sliderobj[seed] = obj;
+  
+  var framecnt = 0;
+  
+  for(var j = 0;j<100;j++) // while(true)
+  {
+    framecnt++;
+    timercnt = timercnt + ( 100 - slide_speed );
+    inertiabase = inertiabase + inertiainc;
+    currentheight = currentheight - inertiabase;
+    if ( currentheight < targetheight )
+      currentheight = targetheight;
+    setTimeout('slideStep(sliderobj['+seed+'], '+currentheight+');', timercnt);
+    if ( currentheight <= targetheight )
+      break;
+  }
+  timercnt += ( 100 - slide_speed );
+  setTimeout('sliderobj['+seed+'].style.display="none";sliderobj['+seed+'].style.height="'+origheight+'px";jBoxSlideBlocker[sliderobj['+seed+'].id] = false;', timercnt);
+  
+  var opacstep = jBox_opacity / framecnt;
+  var opac = jBox_opacity;
+  var timerstep = 0;
+  domObjChangeOpac(100, obj);
+  while(true)
+  {
+    timerstep += ( 100 - slide_speed );
+    opac -= opacstep;
+    setTimeout('domObjChangeOpac('+opac+', sliderobj['+seed+']);', timerstep);
+    if ( opac <= 0 )
+      break;
+  }
+  
+}
+
+function slideStep(obj, height, maxheight)
+{
+  obj.style.height = height + 'px';
+  //obj.style.clip = 'rect(3px,auto,'+maxheight+'px,auto)';
+  obj.style.overflow = 'hidden';
+  //obj.style.clip = 'rect('+height+'px,0px,'+maxheight+'px,auto);';
+}
+
+function isOverObj(obj, bias, event)
+{
+  var fieldUL = new Object();
+  var dim = fetch_dimensions(obj);
+  var off = fetch_offset(obj);
+  fieldUL['top'] = off['top'];
+  fieldUL['left'] = off['left'];
+  fieldUL['right'] = off['left'] + dim['w'];
+  fieldUL['bottom'] = off['top'] + dim['h'];
+  
+  //document.getElementById('debug').innerHTML = '<br /><br /><br /><br /><br />Mouse: x: '+mouseX+', y:' + mouseY + '<br />'; // + document.getElementById('debug').innerHTML;
+  
+  if(bias)
+  {
+    if ( ( mouseX < fieldUL['left'] + 2 || mouseX > fieldUL['right']  - 5 ) ||
+         ( mouseY < fieldUL['top']  - 2 || mouseY > fieldUL['bottom'] - 2 ) )
+    {
+       return false;
+    }
+  }
+  else
+  {
+    if ( ( mouseX < fieldUL['left'] || mouseX > fieldUL['right']  ) ||
+         ( mouseY < fieldUL['top']  || mouseY > fieldUL['bottom'] ) )
+       return false;
+  }
+     
+  return true;
+  
+  /*
+  var tgt = event.target;
+  if ( !tgt )
+    return false;
+  do {
+    if ( tgt == obj )
+      return true;
+    tgt = tgt.parentNode;
+  } while (tgt.tagName.toLowerCase() != 'body' );
+  return false;
+  */
+}
+
+function jBoxGarbageCollection(e)
+{
+  setMousePos(e);
+  var menus = document.getElementsByClassName('div', 'menu');
+  if ( menus.length > 0 )
+  {
+    for ( var i in menus )
+    {
+      if ( typeof(menus[i]) != 'object')
+        continue; // toJSONString() compatibility
+      var uls = menus[i].getElementsByTagName('ul');
+      if ( uls.length > 0 )
+      {
+        for ( var j = 0; j < uls.length; j++ )
+        {
+          if ( !isOverObj(uls[j], false, e) )
+          {
+            uls[j].previousSibling.className = '';
+            //uls[j].style.display = 'none';
+            slideIn(uls[j]);
+          }
+        }
+      }
+      var uls = getElementsByClassName(menus[i], 'divs', 'submenu');
+      if ( uls.length > 0 )
+      {
+        for ( var j = 0; j < uls.length; j++ )
+        {
+          if ( !isOverObj(uls[j], false, e) )
+          {
+            uls[j].previousSibling.className = '';
+            //uls[j].style.display = 'none';
+            slideIn(uls[j]);
+          }
+        }
+      }
+    }
+  }
+}
+
+document.onclick = jBoxGarbageCollection;
+
+function removeTextNodes(obj)
+{
+  if(obj)
+  {
+    if(typeof(obj.tagName) != 'string')
+    {
+      if ( obj.nodeType == 3 && obj.data.match(/^([\s]*)$/ig) ) 
+      {
+        obj.parentNode.removeChild(obj);
+        return;
+      }
+    }
+    if(obj.firstChild)
+    {
+      for(var i in obj.childNodes)
+      {
+        removeTextNodes(obj.childNodes[i]);
+      }
+    }
+  }
+}
+
+var getElementsByClassName = function(parent, type, cls) {
+  if(!type)
+    type = '*';
+  ret = new Array();
+  el = parent.getElementsByTagName(type);
+  for ( var i in el )
+  {
+    if ( typeof(el[i]) != 'object')
+      continue; // toJSONString() compatibility
+    if(el[i].className)
+    {
+      if(el[i].className.indexOf(' ') > 0)
+      {
+        classes = el[i].className.split(' ');
+      }
+      else
+      {
+        classes = new Array();
+        classes.push(el[i].className);
+      }
+      if ( in_array(cls, classes) )
+        ret.push(el[i]);
+    }
+  }
+  return ret;
+}
+
+document.getElementsByClassName = function(type, cls) {
+  return getElementsByClassName(document, type, cls);
+}
+
+function setMousePos(event)
+{
+  if(IE)
+  {
+    if(!event)
+    {
+      event = window.event;
+    }
+    clX = event.clientX;
+    sL  = document.body.scrollLeft;
+    mouseX = clX + sL;
+    mouseY = event.clientY + document.body.scrollTop;
+    return;
+  }
+  if( typeof(event.clientX) == 'number' )
+  {
+    mouseX = event.clientX;
+    mouseY = event.clientY;
+    return;
+  }
+  else if( typeof(event.layerX) == 'number' )
+  {
+    mouseX = event.layerX;
+    mouseY = event.layerY;
+    return;
+  }
+  else if( typeof(event.offsetX) == 'number' )
+  {
+    mouseX = event.offsetX;
+    mouseY = event.offsetY;
+    return;
+  }
+  else if( typeof(event.screenX) == 'number' )
+  {
+    mouseX = event.screenX;
+    mouseY = event.screenY;
+    return;
+  }
+  else if( typeof(event.x) == 'number' )
+  {
+    mouseX = event.x;
+    mouseY = event.y;
+    return;
+  }
+}
+
+document.onmousemove = function(e)
+{
+  setMousePos(e);
+};
+
+function domObjChangeOpac(opacity, id) {
+    var object = id.style;
+    object.opacity = (opacity / 100);
+    object.MozOpacity = (opacity / 100);
+    object.KhtmlOpacity = (opacity / 100);
+    object.filter = "alpha(opacity=" + opacity + ")";
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/static/dynano.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,129 @@
+// The "Dynano" Javascript framework. Similar in syntax to JQuery but only has what Enano needs.
+
+var $ = function(id)
+{
+  return new DNobj(id);
+}
+var $dynano = $;
+function DNobj(id)
+{
+  this.object = ( typeof(id) == 'object' ) ? id : document.getElementById(id);
+  this.height = __DNObjGetHeight(this.object);
+  this.width = __DNObjGetWidth(this.object);
+  
+  if ( this.object.tagName == 'TEXTAREA' && typeof(tinyMCE) == 'object' )
+  {
+    this.object.dnIsMCE = 'no';
+    this.switchToMCE = DN_switchToMCE;
+    this.destroyMCE = DN_destroyMCE;
+    this.getContent = DN_mceFetchContent;
+  }
+}
+function __DNObjGetHeight(o) {
+  return o.offsetHeight;
+}
+
+function __DNObjGetWidth(o) {
+  return o.offsetWidth;
+}
+
+function addClass(obj, clsname)
+{
+  var cnt = obj.className;
+  var space = ( (cnt + '').length > 0 ) ? ' ' : '';
+  var cls = cnt + space + clsname;
+  obj.className = cls;
+}
+
+function rmClass(obj, clsname)
+{
+  var cnt = obj.className;
+  if ( cnt == clsname )
+  {
+    obj.className = '';
+  }
+  else
+  {
+    cnt = cnt.replace(clsname, '');
+    cnt = trim(cnt);
+    obj.className = cnt;
+  }
+}
+
+function hasClass(obj, clsname)
+{
+  var cnt = obj.className;
+  if ( !cnt )
+    return false;
+  if ( cnt == clsname )
+    return true;
+  cnt = cnt.split(' ');
+  
+  for ( var i in cnt )
+    if ( cnt[i] == clsname )
+      return true;
+    
+  return false;
+}
+function __DNObjGetLeft(obj) {
+  var left_offset = obj.offsetLeft;
+  while ((obj = obj.offsetParent) != null) {
+    left_offset += obj.offsetLeft;
+  }
+  return left_offset;
+}
+
+function __DNObjGetTop(obj) {
+  var left_offset = obj.offsetTop;
+  while ((obj = obj.offsetParent) != null) {
+    left_offset += obj.offsetTop;
+  }
+  return left_offset;
+}
+
+function DN_switchToMCE()
+{
+  //if ( this.object.dn_is_mce )
+  //  return this;
+  if ( !this.object.id )
+    this.object.id = 'textarea_' + Math.floor(Math.random() * 1000000);
+  if ( !this.object.name )
+    this.object.name = 'textarea_' + Math.floor(Math.random() * 1000000);
+  tinyMCE.addMCEControl(this.object, this.object.name, document);
+  this.object.dnIsMCE = 'yes';
+  return this;
+}
+
+function DN_destroyMCE()
+{
+  //if ( !this.object.dn_is_mce )
+  //  return this;
+  if ( this.object.name )
+    tinyMCE.removeMCEControl(this.object.name);
+  this.object.dnIsMCE = 'no';
+  return this;
+}
+
+function DN_mceFetchContent()
+{
+  if ( this.object.name )
+  {
+    var text = this.object.value;
+    if ( tinyMCE.getInstanceById(this.object.name) )
+      text = tinyMCE.getContent(this.object.name);
+    return text;
+  }
+  else
+  {
+    return this.object.value;
+  }
+}
+
+DNobj.prototype.addClass = function(clsname) { addClass(this.object, clsname); return this; };
+DNobj.prototype.rmClass  = function(clsname) { rmClass( this.object, clsname); return this; };
+DNobj.prototype.hasClass = function(clsname) { return hasClass(this.object, clsname); };
+DNobj.prototype.Height   = function()        { return __DNObjGetHeight(this.object); }
+DNobj.prototype.Width    = function()        { return __DNObjGetWidth( this.object); }
+DNobj.prototype.Left     = function()        { /* return this.object.offsetLeft; */ return __DNObjGetLeft(this.object); }
+DNobj.prototype.Top      = function()        { /* return this.object.offsetTop;  */ return __DNObjGetTop( this.object); }
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/static/editor.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,22 @@
+// Javascript routines for the page editor
+
+function initTinyMCE(e)
+{
+  if ( typeof(tinyMCE) == 'object' )
+  {
+    tinyMCE.init({
+      mode : "exact",
+      elements : '',
+      plugins : 'table',
+      theme_advanced_resize_horizontal : false,
+      theme_advanced_resizing : true,
+      theme_advanced_toolbar_location : "top",
+      theme_advanced_toolbar_align : "left",
+      theme_advanced_buttons1_add : "fontselect,fontsizeselect",
+      theme_advanced_buttons3_add_before : "tablecontrols,separator",
+      theme_advanced_statusbar_location : 'bottom'
+    });
+  }
+}
+addOnloadHook(initTinyMCE);
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/static/enano-lib-basic.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,328 @@
+/*
+ * Enano - an open source wiki-like CMS
+ * Copyright (C) 2006-2007 Dan Fuhry
+ * Javascript client library
+ *
+ * This program is Free Software; you can redistribute 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 details.
+ *
+ * For more information about Enano, please visit http://www.enanocms.org/.
+ * All of the code in these script files may be used freely so long as the above license block is displayed and your
+ * modified code is distributed under the GPL. See the page Special:About_Enano on this website for more information.
+ */
+
+if(typeof title != 'string')
+{
+  alert('Uh-oh! The required dynamic (PHP-generated) Javascript variables don\'t seem to be available. Javascript is going to be seriously broken.');
+}
+
+// Run-time variables
+
+var detect = navigator.userAgent.toLowerCase();
+var IE;
+
+// dummy tinyMCE object
+var tinyMCE = new Object();
+
+// Detect whether the user is running the Evil One or not...
+
+function checkIt(string) {
+  place = detect.indexOf(string) + 1;
+  thestring = string;
+  return place;
+}
+if (checkIt('msie')) IE = true;
+else IE = false;
+
+var cmt_open;
+var list;
+var edit_open = false;
+var catlist = new Array();
+var arrDiff1Buttons = new Array();
+var arrDiff2Buttons = new Array();
+var arrTimeIdList   = new Array();
+var list;
+var unObj;
+var unSelectMenuOn = false;
+var unObjDivCurrentId = false;
+var unObjCurrentSelection = false;
+var userlist = new Array();
+var submitAuthorized = true;
+var rDnsObj;
+var rDnsBannerObj;
+var ns4 = document.layers;
+var op5 = (navigator.userAgent.indexOf("Opera 5")!=-1) ||(navigator.userAgent.indexOf("Opera/5")!=-1);
+var op6 = (navigator.userAgent.indexOf("Opera 6")!=-1) ||(navigator.userAgent.indexOf("Opera/6")!=-1);
+var agt=navigator.userAgent.toLowerCase();
+var mac = (agt.indexOf("mac")!=-1);
+var ie = (agt.indexOf("msie") != -1);
+var mac_ie = mac && ie;
+var mouseX = 0;
+var mouseY = 0;
+var menuheight;
+var inertiabase = 1;
+var inertiainc = 1;
+var slideintervalinc = 20;
+var inertiabaseoriginal = inertiabase;
+var heightnow;
+var targetheight;
+var block;
+var slideinterval;
+var divheights = new Array();
+var __menutimeout = false;
+var startmouseX = false;
+var startmouseY = false;
+var startScroll = false;
+var is_dragging = false;
+var current_ta  = false;
+var startwidth  = false;
+var startheight = false;
+var do_width    = false;
+
+// You have an NSIS coder in your midst...
+var MB_OK = 1;
+var MB_OKCANCEL = 2;
+var MB_YESNO = 4;
+var MB_YESNOCANCEL = 8;
+var MB_ABORTRETRYIGNORE = 16;
+var MB_ICONINFORMATION = 32;
+var MB_ICONEXCLAMATION = 64;
+var MB_ICONSTOP = 128;
+var MB_ICONQUESTION = 256;
+var MB_ICONLOCK = 512;
+
+// Syntax:
+// messagebox(MB_OK|MB_ICONINFORMATION, 'Title', 'Text');
+// :-D
+
+var main_css = document.getElementById('mdgCss').href;
+if(main_css.indexOf('?') > -1) {
+  sep = '&';
+} else sep = '?';
+var _css = false;
+var print_css = main_css + sep + 'printable';
+
+var shift;
+
+function makeUrl(page, query, html_friendly)
+{
+  url = contentPath+page;
+  if(url.indexOf('?') > 0) sep = '&';
+  else sep = '?';
+  if(query)
+  {
+    url = url + sep + query;
+  }
+  if(html_friendly)
+  {
+    url = url.replace('&', '&amp;');
+    url = url.replace('<', '&lt;');
+    url = url.replace('>', '&gt;');
+  }
+  return url;
+}
+
+function makeUrlNS(namespace, page, query, html_friendly)
+{
+  var url = contentPath+namespace_list[namespace]+(page.replace(/ /g, '_'));
+  if(url.indexOf('?') > 0) sep = '&';
+  else sep = '?';
+  if(query)
+  {
+    url = url + sep + query;
+  }
+  if(html_friendly)
+  {
+    url = url.replace('&', '&amp;');
+    url = url.replace('<', '&lt;');
+    url = url.replace('>', '&gt;');
+  }
+  return append_sid(url);
+}
+
+function strToPageID(string)
+{
+  // Convert Special:UploadFile to ['UploadFile', 'Special'], but convert 'Image:Enano.png' to ['Enano.png', 'File']
+  for(var i in namespace_list)
+    if(namespace_list[i] != '')
+      if(namespace_list[i] == string.substr(0, namespace_list[i].length))
+        return [string.substr(namespace_list[i].length), i];
+  return [string, 'Article'];
+}
+
+function append_sid(url)
+{
+  sep = ( url.indexOf('?') > 0 ) ? '&' : '?';
+  if(ENANO_SID.length > 10)
+  {
+    url = url + sep + 'auth=' + ENANO_SID;
+    sep = '&';
+  }
+  if ( pagepass.length > 0 )
+  {
+    url = url + sep + 'pagepass=' + pagepass;
+  }
+  return url;
+}
+
+var stdAjaxPrefix = append_sid(scriptPath+'/ajax.php?title='+title);
+
+// Code for parsing JSON strings - full source code in json.js
+if(!Object.prototype.toJSONString){Array.prototype.toJSONString=function(){var a=['['],b,i,l=this.length,v;function p(s){if(b){a.push(',');}
+a.push(s);b=true;}
+for(i=0;i<l;i+=1){v=this[i];switch(typeof v){case'undefined':case'function':case'unknown':break;case'object':if(v){if(typeof v.toJSONString==='function'){p(v.toJSONString());}}else{p("null");}
+break;default:p(v.toJSONString());}}
+a.push(']');return a.join('');};Boolean.prototype.toJSONString=function(){return String(this);};Date.prototype.toJSONString=function(){function f(n){return n<10?'0'+n:n;}
+return'"'+this.getFullYear()+'-'+
+f(this.getMonth()+1)+'-'+
+f(this.getDate())+'T'+
+f(this.getHours())+':'+
+f(this.getMinutes())+':'+
+f(this.getSeconds())+'"';};Number.prototype.toJSONString=function(){return isFinite(this)?String(this):"null";};Object.prototype.toJSONString=function(){var a=['{'],b,i,v;function p(s){if(b){a.push(',');}
+a.push(i.toJSONString(),':',s);b=true;}
+for(i in this){if(this.hasOwnProperty(i)){v=this[i];switch(typeof v){case'undefined':case'function':case'unknown':break;case'object':if(v){if(typeof v.toJSONString==='function'){p(v.toJSONString());}}else{p("null");}
+break;default:p(v.toJSONString());}}}
+a.push('}');return a.join('');};(function(s){var m={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'};s.parseJSON=function(filter){try{if(/^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/.test(this)){var j=eval('('+this+')');if(typeof filter==='function'){function walk(k,v){if(v&&typeof v==='object'){for(var i in v){if(v.hasOwnProperty(i)){v[i]=walk(i,v[i]);}}}
+return filter(k,v);}
+return walk('',j);}
+return j;}}catch(e){}
+throw new SyntaxError("parseJSON");};s.toJSONString=function(){if(/["\\\x00-\x1f]/.test(this)){return'"'+this.replace(/([\x00-\x1f\\"])/g,function(a,b){var c=m[b];if(c){return c;}
+c=b.charCodeAt();return'\\u00'+
+Math.floor(c/16).toString(16)+
+(c%16).toString(16);})+'"';}
+return'"'+this+'"';};})(String.prototype);}
+
+function disableJSONExts()
+{
+  delete(Object.prototype.toJSONString);
+  delete(Array.prototype.toJSONString);
+  delete(Boolean.prototype.toJSONString);
+  delete(Date.prototype.toJSONString);
+  delete(Number.prototype.toJSONString);
+  delete(String.prototype.toJSONString);
+}
+
+// JSON extensions are deprecated now - use the toJSONString **function**
+disableJSONExts();
+
+var $_REQUEST = new Object();
+if ( window.location.hash )
+{
+  var hash = String(window.location.hash);
+  hash = hash.substr(1);
+  var reqobj = hash.split(';');
+  var a, b;
+  for ( var i = 0; i < reqobj.length; i++ )
+  {
+    a = reqobj[i].substr(0, reqobj[i].indexOf(':'));
+    b = reqobj[i].substr( ( reqobj[i].indexOf(':') + 1 ) );
+    $_REQUEST[a] = b;
+  }
+}
+
+var head = document.getElementsByTagName('head')[0];
+var script = document.createElement('script');
+script.type="text/javascript";
+script.src=scriptPath+"/includes/clientside/tinymce/tiny_mce_src.js";
+head.appendChild(script);
+
+// Start loading files
+var thefiles = [
+  'misc.js',
+  'admin-menu.js',
+  'ajax.js',
+  'autocomplete.js',
+  'base64.js',
+  'dropdown.js',
+  'faders.js',
+  'fat.js',
+  'grippy.js',
+  'json.js',
+  'md5.js',
+  'sliders.js',
+  'toolbar.js',
+  'windows.js',
+  'rijndael.js',
+  'template-compiler.js',
+  'acl.js',
+  'comments.js',
+  'editor.js',
+  'dynano.js',
+  'flyin.js',
+  'loader.js'
+];
+
+var problem_scripts = {
+  'faders.js' : true,
+  'acl.js' : true,
+  'admin-menu.js' : true,
+  'loader.js' : true
+};
+
+for(var f in thefiles)
+{
+  if ( typeof(thefiles[f]) != 'string' )
+    continue;
+  var script = document.createElement('script');
+  script.type="text/javascript";
+  //if ( problem_scripts[thefiles[f]] )
+    script.src=scriptPath+"/includes/clientside/static/"+thefiles[f];
+  //else
+  //  script.src=scriptPath+"/includes/clientside/jsres.php?file="+thefiles[f];
+  head.appendChild(script);
+}
+
+var onload_hooks = new Array();
+
+function addOnloadHook(func)
+{
+  if ( typeof ( func ) == 'function' )
+    onload_hooks[onload_hooks.length] = func;
+}
+
+function runOnloadHooks(e)
+{
+  var _errorTrapper = 0;
+  for ( var _oLc = 0; _oLc < onload_hooks.length; _oLc++ )
+  {
+    _errorTrapper++;
+    if ( _errorTrapper >= 1000 )
+      break;
+    var _f = onload_hooks[_oLc];
+    if ( typeof(_f) == 'function' )
+    {
+      _f(e);
+    }
+  }
+}
+
+addOnloadHook(function() {
+  if ( $_REQUEST['do'] )
+  {
+    var act = $_REQUEST['do'];
+    switch(act)
+    {
+      case 'comments':
+        ajaxComments();
+        break;
+      case 'edit':
+        ajaxEditor();
+        break;
+      case 'login':
+        ajaxStartLogin();
+        break;
+      case 'history':
+        ajaxHistory();
+        break;
+      case 'catedit':
+        ajaxCatEdit();
+        break;
+    }
+  }
+});
+
+
+//*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/static/faders.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,393 @@
+// Message box system
+
+function darken(nofade)
+{
+  if(IE)
+    nofade = true;
+  if(document.getElementById('specialLayer_darkener'))
+  {
+    document.getElementById('specialLayer_darkener').style.display = 'block';
+    if(nofade)
+    {
+      document.getElementById('specialLayer_darkener').style.opacity = '0.7';
+      document.getElementById('specialLayer_darkener').style.filter = 'alpha(opacity=70)';
+    }
+    else
+    {
+      opacity('specialLayer_darkener', 0, 70, 1000);
+    }
+  } else {
+    w = getWidth();
+    h = getHeight();
+    var thediv = document.createElement('div');
+    if(IE)
+      thediv.style.position = 'absolute';
+    else
+      thediv.style.position = 'fixed';
+    thediv.style.top = '0px';
+    thediv.style.left = '0px';
+    thediv.style.opacity = '0';
+    thediv.style.filter = 'alpha(opacity=0)';
+    thediv.style.backgroundColor = '#000000';
+    thediv.style.width =  '100%';
+    thediv.style.height = '100%';
+    thediv.zIndex = getHighestZ() + 5;
+    thediv.id = 'specialLayer_darkener';
+    if(nofade)
+    {
+      thediv.style.opacity = '0.7';
+      thediv.style.filter = 'alpha(opacity=70)';
+      body = document.getElementsByTagName('body');
+      body = body[0];
+      body.appendChild(thediv);
+    } else {
+      body = document.getElementsByTagName('body');
+      body = body[0];
+      body.appendChild(thediv);
+      opacity('specialLayer_darkener', 0, 70, 1000);
+    }
+  }
+}
+
+function enlighten(nofade)
+{
+  if(IE)
+    nofade = true;
+  if(document.getElementById('specialLayer_darkener'))
+  {
+    if(nofade)
+    {
+      document.getElementById('specialLayer_darkener').style.display = 'none';
+    }
+    opacity('specialLayer_darkener', 70, 0, 1000);
+    setTimeout("document.getElementById('specialLayer_darkener').style.display = 'none';", 1000);
+  }
+}
+
+/**
+ * The ultimate message box framework for Javascript
+ * Syntax is (almost) identical to the MessageBox command in NSIS
+ * @param int type - a bitfield consisting of the MB_* constants
+ * @param string title - the blue text at the top of the window
+ * @param string text - HTML for the body of the message box
+ * Properties:
+ *   onclick - an array of functions to be called on button click events
+ *             NOTE: key names are to be strings, and they must be the value of the input, CaSe-SeNsItIvE
+ *   onbeforeclick - same as onclick but called before the messagebox div is destroyed
+ * Example:
+ *   var my_message = new messagebox(MB_OK|MB_ICONSTOP, 'Error logging in', 'The username and/or password is incorrect. Please check the username and retype your password');
+ *   my_message.onclick['OK'] = function() {
+ *       document.getElementById('password').value = '';
+ *     };
+ * Deps:
+ *   Modern browser that supports DOM
+ *   darken() and enlighten() (above)
+ *   opacity() - required for darken() and enlighten()
+ *   MB_* constants are defined in enano-lib-basic.js
+ */
+
+var mb_current_obj;
+
+function messagebox(type, title, message)
+{
+  var y = getScrollOffset();
+  if(document.getElementById('messageBox')) return;
+  darken(true);
+  var master_div = document.createElement('div');
+  var mydiv = document.createElement('div');
+  mydiv.style.width = '400px';
+  mydiv.style.height = '200px';
+  w = getWidth();
+  h = getHeight();
+  //master_div.style.left = (w / 2) - 200+'px';
+  //master_div.style.top = (h / 2) + y - 120+'px';
+  master_div.style.top = '-10000px';
+  master_div.style.position = ( IE ) ? 'absolute' : 'fixed';
+  z = getHighestZ(); // document.getElementById('specialLayer_darkener').style.zIndex;
+  mydiv.style.zIndex = parseInt(z) + 1;
+  mydiv.style.backgroundColor = '#FFFFFF';
+  mydiv.style.padding = '10px';
+  mydiv.style.marginBottom = '1px';
+  mydiv.id = 'messageBox';
+  mydiv.style.overflow = 'auto';
+  
+  var buttondiv = document.createElement('div');
+  buttondiv.style.width = '400px';
+  w = getWidth();
+  h = getHeight();
+  // buttondiv.style.left = (w / 2) - 200+'px';
+  // buttondiv.style.top = (h / 2) + y + 101+'px';
+  // buttondiv.style.position = ( IE ) ? 'absolute' : 'fixed';
+  z = getHighestZ(); // document.getElementById('specialLayer_darkener').style.zIndex;
+  buttondiv.style.zIndex = parseInt(z) + 1;
+  buttondiv.style.backgroundColor = '#C0C0C0';
+  buttondiv.style.padding = '10px';
+  buttondiv.style.textAlign = 'right';
+  buttondiv.style.verticalAlign = 'middle';
+  buttondiv.id = 'messageBoxButtons';
+  
+  this.clickHandler = function() { messagebox_click(this, mb_current_obj); };
+  
+  if(type & MB_ICONINFORMATION || type & MB_ICONSTOP || type & MB_ICONQUESTION || type & MB_ICONEXCLAMATION || type & MB_ICONLOCK)
+  {
+    mydiv.style.paddingLeft = '50px';
+    mydiv.style.width = '360px';
+    mydiv.style.backgroundRepeat = 'no-repeat';
+  }
+  
+  if(type & MB_ICONINFORMATION)
+  {
+    mydiv.style.backgroundImage = 'url(\''+scriptPath+'/images/info.png\')';
+  }
+  
+  if(type & MB_ICONQUESTION)
+  {
+    mydiv.style.backgroundImage = 'url(\''+scriptPath+'/images/question.png\')';
+  }
+  
+  if(type & MB_ICONSTOP)
+  {
+    mydiv.style.backgroundImage = 'url(\''+scriptPath+'/images/error.png\')';
+  }
+  
+  if(type & MB_ICONEXCLAMATION)
+  {
+    mydiv.style.backgroundImage = 'url(\''+scriptPath+'/images/warning.png\')';
+  }
+  
+  if(type & MB_ICONLOCK)
+  {
+    mydiv.style.backgroundImage = 'url(\''+scriptPath+'/images/lock.png\')';
+  }
+  
+  if(type & MB_OK)
+  {
+    btn = document.createElement('input');
+    btn.type = 'button';
+    btn.value = 'OK';
+    btn.onclick = this.clickHandler;
+    btn.style.margin = '0 3px';
+    buttondiv.appendChild(btn);
+  }
+  
+  if(type & MB_OKCANCEL)
+  {
+    btn = document.createElement('input');
+    btn.type = 'button';
+    btn.value = 'OK';
+    btn.onclick = this.clickHandler;
+    btn.style.margin = '0 3px';
+    buttondiv.appendChild(btn);
+    
+    btn = document.createElement('input');
+    btn.type = 'button';
+    btn.value = 'Cancel';
+    btn.onclick = this.clickHandler;
+    btn.style.margin = '0 3px';
+    buttondiv.appendChild(btn);
+  }
+  
+  if(type & MB_YESNO)
+  {
+    btn = document.createElement('input');
+    btn.type = 'button';
+    btn.value = 'Yes';
+    btn.onclick = this.clickHandler;
+    btn.style.margin = '0 3px';
+    buttondiv.appendChild(btn);
+    
+    btn = document.createElement('input');
+    btn.type = 'button';
+    btn.value = 'No';
+    btn.onclick = this.clickHandler;
+    btn.style.margin = '0 3px';
+    buttondiv.appendChild(btn);
+  }
+  
+  if(type & MB_YESNOCANCEL)
+  {
+    btn = document.createElement('input');
+    btn.type = 'button';
+    btn.value = 'Yes';
+    btn.onclick = this.clickHandler;
+    btn.style.margin = '0 3px';
+    buttondiv.appendChild(btn);
+    
+    btn = document.createElement('input');
+    btn.type = 'button';
+    btn.value = 'No';
+    btn.onclick = this.clickHandler;
+    btn.style.margin = '0 3px';
+    buttondiv.appendChild(btn);
+    
+    btn = document.createElement('input');
+    btn.type = 'button';
+    btn.value = 'Cancel';
+    btn.onclick = this.clickHandler;
+    btn.style.margin = '0 3px';
+    buttondiv.appendChild(btn);
+  }
+  
+  heading = document.createElement('h2');
+  heading.innerHTML = title;
+  heading.style.color = '#50A0D0';
+  heading.style.fontFamily = 'trebuchet ms, verdana, arial, helvetica, sans-serif';
+  heading.style.fontSize = '12pt';
+  heading.style.fontWeight = 'lighter';
+  heading.style.textTransform = 'lowercase';
+  heading.style.marginTop = '0';
+  mydiv.appendChild(heading);
+  
+  var text = document.createElement('div');
+  text.innerHTML = String(message);
+  this.text_area = text;
+  mydiv.appendChild(text);
+  
+  this.updateContent = function(text)
+    {
+      this.text_area.innerHTML = text;
+    };
+  
+  //domObjChangeOpac(0, mydiv);
+  //domObjChangeOpac(0, master_div);
+  
+  body = document.getElementsByTagName('body');
+  body = body[0];
+  master_div.appendChild(mydiv);
+  master_div.appendChild(buttondiv);
+  
+  body.appendChild(master_div);
+  
+  setTimeout('mb_runFlyIn();', 100);
+  
+  this.onclick = new Array();
+  this.onbeforeclick = new Array();
+  mb_current_obj = this;
+}
+
+function mb_runFlyIn()
+{
+  var mydiv = document.getElementById('messageBox');
+  var maindiv = mydiv.parentNode;
+  fly_in_top(maindiv, true, false);
+}
+
+function messagebox_click(obj, mb)
+{
+  val = obj.value;
+  if(typeof mb.onbeforeclick[val] == 'function')
+  {
+    var o = mb.onbeforeclick[val];
+    var resp = o();
+    if ( resp )
+      return false;
+    o = false;
+  }
+  
+  var mydiv = document.getElementById('messageBox');
+  var maindiv = mydiv.parentNode;
+  var to = fly_out_top(maindiv, true, false);
+  
+  setTimeout("var mbdiv = document.getElementById('messageBox'); mbdiv.parentNode.removeChild(mbdiv.nextSibling); mbdiv.parentNode.removeChild(mbdiv); enlighten(true);", to);
+  if(typeof mb.onclick[val] == 'function')
+  {
+    o = mb.onclick[val];
+    o();
+    o = false;
+  }
+}
+
+function testMessageBox()
+{
+  mb = new messagebox(MB_OKCANCEL|MB_ICONINFORMATION, 'Javascripted dynamic message boxes', 'This is soooooo coool, now if only document.createElement() worked in IE!<br />this is some more text<br /><br /><br /><br /><br />this is some more text<br /><br /><br /><br /><br />this is some more text<br /><br /><br /><br /><br />this is some more text<br /><br /><br /><br /><br />this is some more text<br /><br /><br /><br /><br />this is some more text<br /><br /><br /><br /><br />this is some more text<br /><br /><br /><br /><br />this is some more text');
+  mb.onclick['OK'] = function()
+    {
+      alert('You clicked OK!');
+    }
+  mb.onbeforeclick['Cancel'] = function()
+    {
+      alert('You clicked Cancel!');
+    }
+}
+
+// Function to fade classes info-box, warning-box, error-box, etc.
+
+function fadeInfoBoxes()
+{
+  var divs = new Array();
+  d = document.getElementsByTagName('div');
+  j = 0;
+  for(var i in d)
+  {
+    if ( !d[i].tagName )
+      continue;
+    if(d[i].className=='info-box' || d[i].className=='error-box' || d[i].className=='warning-box' || d[i].className=='question-box')
+    {
+      divs[j] = d[i];
+      j++;
+    }
+  }
+  if(divs.length < 1) return;
+  for(i in divs)
+  {
+    if(!divs[i].id) divs[i].id = 'autofade_'+Math.floor(Math.random() * 100000);
+    switch(divs[i].className)
+    {
+      case 'info-box':
+      default:
+        from = '#3333FF';
+        break;
+      case 'error-box':
+        from = '#FF3333';
+        break;
+      case 'warning-box':
+        from = '#FFFF33';
+        break;
+      case 'question-box':
+        from = '#33FF33';
+        break;
+    }
+    Fat.fade_element(divs[i].id,30,2000,from,Fat.get_bgcolor(divs[i].id));
+  }
+}
+
+// Alpha fades
+
+function opacity(id, opacStart, opacEnd, millisec) {
+    //speed for each frame
+    var speed = Math.round(millisec / 100);
+    var timer = 0;
+
+    //determine the direction for the blending, if start and end are the same nothing happens
+    if(opacStart > opacEnd) {
+        for(i = opacStart; i >= opacEnd; i--) {
+            setTimeout("changeOpac(" + i + ",'" + id + "')",(timer * speed));
+            timer++;
+        }
+    } else if(opacStart < opacEnd) {
+        for(i = opacStart; i <= opacEnd; i++)
+            {
+            setTimeout("changeOpac(" + i + ",'" + id + "')",(timer * speed));
+            timer++;
+        }
+    }
+}
+
+//change the opacity for different browsers
+function changeOpac(opacity, id) {
+    var object = document.getElementById(id).style;
+    object.opacity = (opacity / 100);
+    object.MozOpacity = (opacity / 100);
+    object.KhtmlOpacity = (opacity / 100);
+    object.filter = "alpha(opacity=" + opacity + ")";
+}
+
+function mb_logout()
+{
+  var mb = new messagebox(MB_YESNO|MB_ICONQUESTION, 'Are you sure you want to log out?', 'If you log out, you will no longer be able to access your user preferences, your private messages, or certain areas of this site until you log in again.');
+  mb.onclick['Yes'] = function()
+    {
+      window.location = makeUrlNS('Special', 'Logout/' + title);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/static/faders.js~	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,393 @@
+// Message box system
+
+function darken(nofade)
+{
+  if(IE)
+    nofade = true;
+  if(document.getElementById('specialLayer_darkener'))
+  {
+    document.getElementById('specialLayer_darkener').style.display = 'block';
+    if(nofade)
+    {
+      document.getElementById('specialLayer_darkener').style.opacity = '0.7';
+      document.getElementById('specialLayer_darkener').style.filter = 'alpha(opacity=70)';
+    }
+    else
+    {
+      opacity('specialLayer_darkener', 0, 70, 1000);
+    }
+  } else {
+    w = getWidth();
+    h = getHeight();
+    var thediv = document.createElement('div');
+    if(IE)
+      thediv.style.position = 'absolute';
+    else
+      thediv.style.position = 'fixed';
+    thediv.style.top = '0px';
+    thediv.style.left = '0px';
+    thediv.style.opacity = '0';
+    thediv.style.filter = 'alpha(opacity=0)';
+    thediv.style.backgroundColor = '#000000';
+    thediv.style.width =  '100%';
+    thediv.style.height = '100%';
+    thediv.zIndex = getHighestZ() + 5;
+    thediv.id = 'specialLayer_darkener';
+    if(nofade)
+    {
+      thediv.style.opacity = '0.7';
+      thediv.style.filter = 'alpha(opacity=70)';
+      body = document.getElementsByTagName('body');
+      body = body[0];
+      body.appendChild(thediv);
+    } else {
+      body = document.getElementsByTagName('body');
+      body = body[0];
+      body.appendChild(thediv);
+      opacity('specialLayer_darkener', 0, 70, 1000);
+    }
+  }
+}
+
+function enlighten(nofade)
+{
+  if(IE)
+    nofade = true;
+  if(document.getElementById('specialLayer_darkener'))
+  {
+    if(nofade)
+    {
+      document.getElementById('specialLayer_darkener').style.display = 'none';
+    }
+    opacity('specialLayer_darkener', 70, 0, 1000);
+    setTimeout("document.getElementById('specialLayer_darkener').style.display = 'none';", 1000);
+  }
+}
+
+/**
+ * The ultimate message box framework for Javascript
+ * Syntax is (almost) identical to the MessageBox command in NSIS
+ * @param int type - a bitfield consisting of the MB_* constants
+ * @param string title - the blue text at the top of the window
+ * @param string text - HTML for the body of the message box
+ * Properties:
+ *   onclick - an array of functions to be called on button click events
+ *             NOTE: key names are to be strings, and they must be the value of the input, CaSe-SeNsItIvE
+ *   onbeforeclick - same as onclick but called before the messagebox div is destroyed
+ * Example:
+ *   var my_message = new messagebox(MB_OK|MB_ICONSTOP, 'Error logging in', 'The username and/or password is incorrect. Please check the username and retype your password');
+ *   my_message.onclick['OK'] = function() {
+ *       document.getElementById('password').value = '';
+ *     };
+ * Deps:
+ *   Modern browser that supports DOM
+ *   darken() and enlighten() (above)
+ *   opacity() - required for darken() and enlighten()
+ *   MB_* constants are defined in enano-lib-basic.js
+ */
+
+var mb_current_obj;
+
+function messagebox(type, title, message)
+{
+  var y = getScrollOffset();
+  if(document.getElementById('messageBox')) return;
+  darken(true);
+  var master_div = document.createElement('div');
+  var mydiv = document.createElement('div');
+  mydiv.style.width = '400px';
+  mydiv.style.height = '200px';
+  w = getWidth();
+  h = getHeight();
+  //master_div.style.left = (w / 2) - 200+'px';
+  //master_div.style.top = (h / 2) + y - 120+'px';
+  master_div.style.top = '-10000px';
+  master_div.style.position = ( IE ) ? 'absolute' : 'fixed';
+  z = getHighestZ(); // document.getElementById('specialLayer_darkener').style.zIndex;
+  mydiv.style.zIndex = parseInt(z) + 1;
+  mydiv.style.backgroundColor = '#FFFFFF';
+  mydiv.style.padding = '10px';
+  mydiv.style.marginBottom = '1px';
+  mydiv.id = 'messageBox';
+  mydiv.style.overflow = 'auto';
+  
+  var buttondiv = document.createElement('div');
+  buttondiv.style.width = '400px';
+  w = getWidth();
+  h = getHeight();
+  // buttondiv.style.left = (w / 2) - 200+'px';
+  // buttondiv.style.top = (h / 2) + y + 101+'px';
+  // buttondiv.style.position = ( IE ) ? 'absolute' : 'fixed';
+  z = getHighestZ(); // document.getElementById('specialLayer_darkener').style.zIndex;
+  buttondiv.style.zIndex = parseInt(z) + 1;
+  buttondiv.style.backgroundColor = '#C0C0C0';
+  buttondiv.style.padding = '10px';
+  buttondiv.style.textAlign = 'right';
+  buttondiv.style.verticalAlign = 'middle';
+  buttondiv.id = 'messageBoxButtons';
+  
+  this.clickHandler = function() { messagebox_click(this, mb_current_obj); };
+  
+  if(type & MB_ICONINFORMATION || type & MB_ICONSTOP || type & MB_ICONQUESTION || type & MB_ICONEXCLAMATION || type & MB_ICONLOCK)
+  {
+    mydiv.style.paddingLeft = '50px';
+    mydiv.style.width = '360px';
+    mydiv.style.backgroundRepeat = 'no-repeat';
+  }
+  
+  if(type & MB_ICONINFORMATION)
+  {
+    mydiv.style.backgroundImage = 'url(\''+scriptPath+'/images/info.png\')';
+  }
+  
+  if(type & MB_ICONQUESTION)
+  {
+    mydiv.style.backgroundImage = 'url(\''+scriptPath+'/images/question.png\')';
+  }
+  
+  if(type & MB_ICONSTOP)
+  {
+    mydiv.style.backgroundImage = 'url(\''+scriptPath+'/images/error.png\')';
+  }
+  
+  if(type & MB_ICONEXCLAMATION)
+  {
+    mydiv.style.backgroundImage = 'url(\''+scriptPath+'/images/warning.png\')';
+  }
+  
+  if(type & MB_ICONLOCK)
+  {
+    mydiv.style.backgroundImage = 'url(\''+scriptPath+'/images/lock.png\')';
+  }
+  
+  if(type & MB_OK)
+  {
+    btn = document.createElement('input');
+    btn.type = 'button';
+    btn.value = 'OK';
+    btn.onclick = this.clickHandler;
+    btn.style.margin = '0 3px';
+    buttondiv.appendChild(btn);
+  }
+  
+  if(type & MB_OKCANCEL)
+  {
+    btn = document.createElement('input');
+    btn.type = 'button';
+    btn.value = 'OK';
+    btn.onclick = this.clickHandler;
+    btn.style.margin = '0 3px';
+    buttondiv.appendChild(btn);
+    
+    btn = document.createElement('input');
+    btn.type = 'button';
+    btn.value = 'Cancel';
+    btn.onclick = this.clickHandler;
+    btn.style.margin = '0 3px';
+    buttondiv.appendChild(btn);
+  }
+  
+  if(type & MB_YESNO)
+  {
+    btn = document.createElement('input');
+    btn.type = 'button';
+    btn.value = 'Yes';
+    btn.onclick = this.clickHandler;
+    btn.style.margin = '0 3px';
+    buttondiv.appendChild(btn);
+    
+    btn = document.createElement('input');
+    btn.type = 'button';
+    btn.value = 'No';
+    btn.onclick = this.clickHandler;
+    btn.style.margin = '0 3px';
+    buttondiv.appendChild(btn);
+  }
+  
+  if(type & MB_YESNOCANCEL)
+  {
+    btn = document.createElement('input');
+    btn.type = 'button';
+    btn.value = 'Yes';
+    btn.onclick = this.clickHandler;
+    btn.style.margin = '0 3px';
+    buttondiv.appendChild(btn);
+    
+    btn = document.createElement('input');
+    btn.type = 'button';
+    btn.value = 'No';
+    btn.onclick = this.clickHandler;
+    btn.style.margin = '0 3px';
+    buttondiv.appendChild(btn);
+    
+    btn = document.createElement('input');
+    btn.type = 'button';
+    btn.value = 'Cancel';
+    btn.onclick = this.clickHandler;
+    btn.style.margin = '0 3px';
+    buttondiv.appendChild(btn);
+  }
+  
+  heading = document.createElement('h2');
+  heading.innerHTML = title;
+  heading.style.color = '#50A0D0';
+  heading.style.fontFamily = 'trebuchet ms, verdana, arial, helvetica, sans-serif';
+  heading.style.fontSize = '12pt';
+  heading.style.fontWeight = 'lighter';
+  heading.style.textTransform = 'lowercase';
+  heading.style.marginTop = '0';
+  mydiv.appendChild(heading);
+  
+  var text = document.createElement('div');
+  text.innerHTML = String(message);
+  this.text_area = text;
+  mydiv.appendChild(text);
+  
+  this.updateContent = function(text)
+    {
+      this.text_area.innerHTML = text;
+    };
+  
+  //domObjChangeOpac(0, mydiv);
+  //domObjChangeOpac(0, master_div);
+  
+  body = document.getElementsByTagName('body');
+  body = body[0];
+  master_div.appendChild(mydiv);
+  master_div.appendChild(buttondiv);
+  
+  body.appendChild(master_div);
+  
+  setTimeout('mb_runFlyIn();', 100);
+  
+  this.onclick = new Array();
+  this.onbeforeclick = new Array();
+  mb_current_obj = this;
+}
+
+function mb_runFlyIn()
+{
+  var mydiv = document.getElementById('messageBox');
+  var maindiv = mydiv.parentNode;
+  fly_in_top(maindiv, true, false);
+}
+
+function messagebox_click(obj, mb)
+{
+  val = obj.value;
+  if(typeof mb.onbeforeclick[val] == 'function')
+  {
+    var o = mb.onbeforeclick[val];
+    var resp = o();
+    if ( resp )
+      return false;
+    o = false;
+  }
+  
+  var mydiv = document.getElementById('messageBox');
+  var maindiv = mydiv.parentNode;
+  var to = fly_out_top(maindiv, true, false);
+  
+  setTimeout("var mbdiv = document.getElementById('messageBox'); mbdiv.parentNode.removeChild(mbdiv.nextSibling); mbdiv.parentNode.removeChild(mbdiv); enlighten(true);", to);
+  if(typeof mb.onclick[val] == 'function')
+  {
+    o = mb.onclick[val];
+    o();
+    o = false;
+  }
+}
+
+function testMessageBox()
+{
+  mb = new messagebox(MB_OKCANCEL|MB_ICONINFORMATION, 'Javascripted dynamic message boxes', 'This is soooooo coool, now if only document.createElement() worked in IE!<br />this is some more text<br /><br /><br /><br /><br />this is some more text<br /><br /><br /><br /><br />this is some more text<br /><br /><br /><br /><br />this is some more text<br /><br /><br /><br /><br />this is some more text<br /><br /><br /><br /><br />this is some more text<br /><br /><br /><br /><br />this is some more text<br /><br /><br /><br /><br />this is some more text');
+  mb.onclick['OK'] = function()
+    {
+      alert('You clicked OK!');
+    }
+  mb.onbeforeclick['Cancel'] = function()
+    {
+      alert('You clicked Cancel!');
+    }
+}
+
+// Function to fade classes info-box, warning-box, error-box, etc.
+
+function fadeInfoBoxes()
+{
+  var divs = new Array();
+  d = document.getElementsByTagName('div');
+  j = 0;
+  for(var i in d)
+  {
+    if ( !d[i].tagName )
+      continue;
+    if(d[i].className=='info-box' || d[i].className=='error-box' || d[i].className=='warning-box' || d[i].className=='question-box')
+    {
+      divs[j] = d[i];
+      j++;
+    }
+  }
+  if(divs.length < 1) return;
+  for(i in divs)
+  {
+    if(!divs[i].id) divs[i].id = 'autofade_'+Math.floor(Math.random() * 100000);
+    switch(divs[i].className)
+    {
+      case 'info-box':
+      default:
+        from = '#3333FF';
+        break;
+      case 'error-box':
+        from = '#FF3333';
+        break;
+      case 'warning-box':
+        from = '#FFFF33';
+        break;
+      case 'question-box':
+        from = '#33FF33';
+        break;
+    }
+    Fat.fade_element(divs[i].id,30,2000,from,Fat.get_bgcolor(divs[i].id));
+  }
+}
+
+// Alpha fades
+
+function opacity(id, opacStart, opacEnd, millisec) {
+    //speed for each frame
+    var speed = Math.round(millisec / 100);
+    var timer = 0;
+
+    //determine the direction for the blending, if start and end are the same nothing happens
+    if(opacStart > opacEnd) {
+        for(i = opacStart; i >= opacEnd; i--) {
+            setTimeout("changeOpac(" + i + ",'" + id + "')",(timer * speed));
+            timer++;
+        }
+    } else if(opacStart < opacEnd) {
+        for(i = opacStart; i <= opacEnd; i++)
+            {
+            setTimeout("changeOpac(" + i + ",'" + id + "')",(timer * speed));
+            timer++;
+        }
+    }
+}
+
+//change the opacity for different browsers
+function changeOpac(opacity, id) {
+    var object = document.getElementById(id).style;
+    object.opacity = (opacity / 100);
+    object.MozOpacity = (opacity / 100);
+    object.KhtmlOpacity = (opacity / 100);
+    object.filter = "alpha(opacity=" + opacity + ")";
+}
+
+function mb_logout()
+{
+  var mb = new messagebox(MB_YESNO|MB_ICONQUESTION, 'Are you sure you want to log out?', 'If you log out, you will no longer be able to access your user preferences, certain areas of this site, and this awesome logout confirmation screen until you login again.<br /><br />OK, not funny. I\'ll remove the bad humor in Banshee.');
+  mb.onclick['Yes'] = function()
+    {
+      window.location = makeUrlNS('Special', 'Logout/' + title);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/static/fat.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,93 @@
+// @name      The Fade Anything Technique
+// @namespace http://www.axentric.com/aside/fat/
+// @version   1.0-RC1
+// @author    Adam Michela
+
+var Fat = {
+	make_hex : function (r,g,b) 
+	{
+		r = r.toString(16); if (r.length == 1) r = '0' + r;
+		g = g.toString(16); if (g.length == 1) g = '0' + g;
+		b = b.toString(16); if (b.length == 1) b = '0' + b;
+		return "#" + r + g + b;
+	},
+	fade_all : function ()
+	{
+		var a = document.getElementsByTagName("*");
+		for (var i = 0; i < a.length; i++) 
+		{
+			var o = a[i];
+			var r = /fade-?(\w{3,6})?/.exec(o.className);
+			if (r)
+			{
+				if (!r[1]) r[1] = "";
+        if (!o.id) o.id = 'autofat_'+Math.floor(Math.random() * 100000);
+				if (o.id) Fat.fade_element(o.id,null,null,"#"+r[1]);
+			}
+		}
+	},
+	fade_element : function (id, fps, duration, from, to) 
+	{
+		if (!fps) fps = 30;
+		if (!duration) duration = 3000;
+		if (!from || from=="#") from = "#FFFF33";
+		if (!to) to = this.get_bgcolor(id);
+		
+		var frames = Math.round(fps * (duration / 1000));
+		var interval = duration / frames;
+		var delay = interval;
+		var frame = 0;
+		
+		if (from.length < 7) from += from.substr(1,3);
+		if (to.length < 7) to += to.substr(1,3);
+		
+		var rf = parseInt(from.substr(1,2),16);
+		var gf = parseInt(from.substr(3,2),16);
+		var bf = parseInt(from.substr(5,2),16);
+		var rt = parseInt(to.substr(1,2),16);
+		var gt = parseInt(to.substr(3,2),16);
+		var bt = parseInt(to.substr(5,2),16);
+		
+		var r,g,b,h;
+		while (frame < frames)
+		{
+			r = Math.floor(rf * ((frames-frame)/frames) + rt * (frame/frames));
+			g = Math.floor(gf * ((frames-frame)/frames) + gt * (frame/frames));
+			b = Math.floor(bf * ((frames-frame)/frames) + bt * (frame/frames));
+			h = this.make_hex(r,g,b);
+		
+			setTimeout("Fat.set_bgcolor('"+id+"','"+h+"')", delay);
+
+			frame++;
+			delay = interval * frame; 
+		}
+		setTimeout("Fat.set_bgcolor('"+id+"','"+to+"')", delay);
+	},
+	set_bgcolor : function (id, c)
+	{
+		var o = document.getElementById(id);
+    if(!o) return;
+		o.style.backgroundColor = c;
+	},
+	get_bgcolor : function (id)
+	{
+		var o = document.getElementById(id);
+		while(o)
+		{
+			var c;
+			if (window.getComputedStyle) c = window.getComputedStyle(o,null).getPropertyValue("background-color");
+			if (o.currentStyle) c = o.currentStyle.backgroundColor;
+			if ((c != "" && c != "transparent") || o.tagName == "BODY") { break; }
+			o = o.parentNode;
+		}
+		if (c == undefined || c == "" || c == "transparent") c = "#FFFFFF";
+		var rgb = c.match(/rgb\s*\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)/);
+		if (rgb) c = this.make_hex(parseInt(rgb[1]),parseInt(rgb[2]),parseInt(rgb[3]));
+		return c;
+	}
+}
+
+window.onload = function () 
+	{
+	Fat.fade_all();
+	}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/static/flyin.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,195 @@
+// Make an HTML element fly in from the top or bottom.
+// Includes inertia!
+
+// vB, don't even try. It's GPL like the rest of Enano. I know you're jealous. >:)
+
+var fly_in_cache = new Object();
+var FI_TOP = 1;
+var FI_BOTTOM = 2;
+var FI_IN = 1;
+var FI_OUT = 2;
+var FI_UP = 1;
+var FI_DOWN = 2;
+
+// Placeholder functions, to make organization a little easier :-)
+
+function fly_in_top(element, nofade, height_taken_care_of)
+{
+  return fly_core(element, nofade, FI_TOP, FI_IN, height_taken_care_of);
+}
+
+function fly_in_bottom(element, nofade, height_taken_care_of)
+{
+  return fly_core(element, nofade, FI_BOTTOM, FI_IN, height_taken_care_of);
+}
+
+function fly_out_top(element, nofade, height_taken_care_of)
+{
+  return fly_core(element, nofade, FI_TOP, FI_OUT, height_taken_care_of);
+}
+
+function fly_out_bottom(element, nofade, height_taken_care_of)
+{
+  return fly_core(element, nofade, FI_BOTTOM, FI_OUT, height_taken_care_of);
+}
+
+function fly_core(element, nofade, origin, direction, height_taken_care_of)
+{
+  if ( !element || typeof(element) != 'object' )
+    return false;
+  // target dimensions
+  var top, left;
+  // initial dimensions
+  var topi, lefti;
+  // current dimensions
+  var topc, leftc;
+  // screen dimensions
+  var w = getWidth();
+  var h = getHeight();
+  var y = parseInt ( getScrollOffset() );
+  // temp vars
+  var dim, off, diff, dist, ratio, opac_factor;
+  // setup element
+  element.style.position = 'absolute';
+  
+  dim = [ $(element).Height(), $(element).Width() ];
+  off = [ $(element).Top(), $(element).Left() ];
+  
+  if ( height_taken_care_of )
+  {
+    top = off[0];
+    left = off[1];
+  }
+  else
+  {
+    top  = Math.round(( h / 2 ) - ( dim[0] / 2 )) + y; // - ( h / 4 ));
+    left = Math.round(( w / 2 ) - ( dim[1] / 2 ));
+  }
+  
+  // you can change this around to get it to fly in from corners or be on the left/right side
+  lefti = left;
+  
+  // calculate first frame Y position
+  if ( origin == FI_TOP && direction == FI_IN )
+  {
+    topi = 0 - dim[0] + y;
+  }
+  else if ( origin == FI_TOP && direction == FI_OUT )
+  {
+    topi = top;
+    top = 0 - dim[0] + y;
+  }
+  else if ( origin == FI_BOTTOM && direction == FI_IN )
+  {
+    topi = h + y;
+  }
+  else if ( origin == FI_BOTTOM && direction == FI_OUT )
+  {
+    topi = top;
+    top = h + y;
+  }
+  
+  var abs_dir = ( ( origin == FI_TOP && direction == FI_IN ) || ( origin == FI_BOTTOM && direction == FI_OUT ) ) ? FI_DOWN : FI_UP;
+  
+  /*
+   * Framestepper parameters
+   */
+  
+  // starting value for inertia
+  var inertiabase = 1;
+  // increment for inertia, or 0 to disable inertia effects
+  var inertiainc  = 1;
+  // when the progress reaches this %, deceleration is activated
+  var divider = 0.666667;
+  // multiplier for deceleration, setting this above 2 can cause some weird slowdown effects
+  var decelerate  = 2; // 1 / divider; // reciprocal of the divider
+  
+  /*
+   * Timer parameters
+   */
+  
+  // how long animation start is delayed, you want this at 0
+  var timer = 0;
+  // frame ttl
+  var timestep = 12;
+  // sanity check
+  var frames = 0;
+  
+  // cache element so it can be changed from within setTimeout()
+  var rand_seed = Math.floor(Math.random() * 1000000);
+  fly_in_cache[rand_seed] = element;
+  
+  // set element left pos, you can comment this out to preserve left position
+  element.style.left = left + 'px';
+  element.style.top  = topi + 'px';
+  
+  if ( nofade )
+  {
+    domObjChangeOpac(100, element);
+  }
+  
+  // total distance to be traveled
+  dist = abs(top - topi);
+  
+  // animation loop
+  
+  while ( true )
+  {
+    // used for a sanity check
+    frames++;
+    
+    // time until this frame should be executed
+    timer += timestep;
+    
+    // math stuff
+    // how far we are along in animation...
+    diff = abs(top - topi);
+    // ...in %
+    ratio = abs( 1 - ( diff / dist ) );
+    // decelerate if we're more than 2/3 of the way there
+    if ( ratio < divider )
+      inertiabase += inertiainc;
+    else
+      inertiabase -= ( inertiainc * decelerate );
+    
+    // if the deceleration factor is anywhere above 1 then technically that can cause an infinite loop
+    // so leave this in there unless decelerate is set to 1
+    if ( inertiabase < 1 )
+      inertiabase = 1;
+    
+    // uncomment to disable inertia
+    // inertiabase = 3;
+    
+    // figure out frame Y position
+    topi = ( abs_dir == FI_UP ) ? topi - inertiabase : topi + inertiabase;
+    if ( ( abs_dir == FI_DOWN && topi > top ) || ( abs_dir == FI_UP && top > topi ) )
+      topi = top;
+    
+    // tell the browser to do it
+    setTimeout('var o = fly_in_cache['+rand_seed+']; o.style.top=\''+topi+'px\';', timer);
+    if ( !nofade )
+    {
+      // handle fade
+      opac_factor = ratio * 100;
+      if ( direction == FI_OUT )
+        opac_factor = 100 - opac_factor;
+      setTimeout('var o = fly_in_cache['+rand_seed+']; domObjChangeOpac('+opac_factor+', o);', timer);
+    }
+    
+    // if we're done or if our sanity check failed then break out of the loop
+    if ( ( abs_dir == FI_DOWN && topi >= top ) || ( abs_dir == FI_UP && top >= topi ) || frames > 1000 )
+      break;
+  }
+  
+  //timer += timestep;
+  setTimeout('delete(fly_in_cache['+rand_seed+']);', timer);
+  return timer;
+}
+
+function abs(i)
+{
+  if ( isNaN(i) )
+    return i;
+  return ( i < 0 ) ? ( 0 - i ) : i;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/static/grippy.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,91 @@
+// Resizable textareas (fun!)
+
+function taStartDrag()
+{
+  obj = this;
+  current_ta = obj.previousSibling;
+  startmouseX = mouseX;
+  startmouseY = mouseY;
+  startScroll = getScrollOffset();
+  is_dragging = true;
+  startwidth  = getElementWidth(current_ta.id);
+  startheight = getElementHeight(current_ta.id);
+  var body = document.getElementsByTagName('body');
+  body = body[0];
+  body.style.cursor = 's-resize';
+}
+function taInDrag()
+{
+  if(!is_dragging) return;
+  cw = startwidth;
+  ch = startheight;
+  mx = mouseX;
+  my = mouseY + getScrollOffset() - startScroll;
+  ch = -6 + ch + ( my - startmouseY );
+  current_ta.style.height = ch+'px';
+  if(do_width)
+  {
+    current_ta.style.width  = mx+'px';
+    current_ta.nextSibling.style.width  = mx+'px';
+  }
+}
+function taCloseDrag()
+{
+  is_dragging = false;
+  current_ta = false;
+  body = document.getElementsByTagName('body');
+  body = body[0];
+  body.style.cursor = 'default';
+}
+
+var grippied_textareas = new Array();
+
+function initTextareas()
+{
+  var textareas = document.getElementsByTagName('textarea');
+  for (i = 0;i < textareas.length;i++)
+  {
+    if(!textareas[i].id)
+      textareas[i].id = 'autoTextArea_'+Math.floor(Math.random()*100000);
+    cta = textareas[i];
+    var divchk = ( in_array(cta.id, grippied_textareas) ) ? false : true;
+    if(divchk)
+    {
+      grippied_textareas.push(cta.id);
+      makeGrippy(cta);
+    }
+  }
+}
+
+function makeGrippy(cta)
+{
+  var thediv = document.createElement('div');
+  thediv.style.backgroundColor = '#ceceed';
+  thediv.style.backgroundImage = 'url('+scriptPath+'/images/grippy.gif)';
+  thediv.style.backgroundPosition = 'bottom right';
+  thediv.style.backgroundRepeat = 'no-repeat';
+  thediv.style.width = getElementWidth(cta.id)+'px';
+  thediv.style.cursor = 's-resize';
+  thediv.style.className = 'ThisIsATextareaGrippy';
+  thediv.id = 'autoGrippy_'+Math.floor(Math.random()*100000);
+  thediv.style.height = '12px';
+  thediv.onmousedown = taStartDrag;
+  thediv.style.border = '1px solid #0000A0';
+  if(cta.style.marginBottom)
+  {
+    thediv.style.marginBottom = cta.style.marginBottom;
+    cta.style.marginBottom = '0';
+  }
+  if(cta.style.marginLeft)
+  {
+    thediv.style.marginLeft = cta.style.marginLeft;
+  }
+  if(cta.style.marginRight)
+  {
+    thediv.style.marginRight = cta.style.marginRight;
+  }
+  document.onmouseup = taCloseDrag;
+  if(cta.nextSibling) cta.parentNode.insertBefore(thediv, cta.nextSibling);
+  else cta.parentNode.appendChild(thediv);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/static/json.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,172 @@
+/*
+    json.js
+    2007-03-20
+
+    All of the code contained within this file is released into
+    the public domain. Optionally, you may distribute this code
+    under the terms of the GNU General Public License as well
+    (public domain licensing allows this).
+    
+*/
+
+function toJSONString(input)
+{
+  var m = {
+          '\b': '\\b',
+          '\t': '\\t',
+          '\n': '\\n',
+          '\f': '\\f',
+          '\r': '\\r',
+          '"' : '\\"',
+          '\\': '\\\\'
+          };
+  var t = typeof(input);
+  switch(t)
+  {
+    case 'string':
+      if (/["\\\x00-\x1f]/.test(input))
+      {
+          return '"' + input.replace(/([\x00-\x1f\\"])/g, function(a, b)
+            {
+              var c = m[b];
+              if (c) {
+                  return c;
+              }
+              c = b.charCodeAt();
+              return '\\u00' +
+                  Math.floor(c / 16).toString(16) +
+                  (c % 16).toString(16);
+          }) + '"';
+      }
+      return '"' + input + '"';
+      break;
+    case 'array':
+      var a = ['['],  
+            b,          
+            i,          
+            l = input.length,
+            v;          
+
+        function p(s) {
+
+            if (b) {
+                a.push(',');
+            }
+            a.push(s);
+            b = true;
+        }
+
+        for (i = 0; i < l; i += 1) {
+            v = input[i];
+            switch (typeof v) {
+            case 'object':
+              if (v) {
+                p(toJSONString(v));
+              } else {
+                p("null");
+              }
+              break;
+            case 'array':
+            case 'string':
+            case 'number':
+            case 'boolean':
+                p(toJSONString(v));
+            }
+        }
+
+        a.push(']');
+        return a.join('');
+      break;
+    case 'date':
+      function f(n)
+      {
+        return n < 10 ? '0' + n : n;
+      }
+      return '"' + input.getFullYear() + '-' +
+                 f(input.getMonth() + 1) + '-' +
+                 f(input.getDate()) + 'T' +
+                 f(input.getHours()) + ':' +
+                 f(input.getMinutes()) + ':' +
+                 f(input.getSeconds()) + '"';
+                 
+    case 'boolean':
+      return String(input);
+      break;
+    case 'number':
+      return isFinite(input) ? String(input) : "null";
+      break;
+    case 'object':
+      var a = ['{'],  
+          b,          
+          k,          
+          v;          
+
+      function p(s)
+      {
+        if (b)
+        {
+          a.push(',');
+        }
+        a.push(toJSONString(k), ':', s);
+        b = true;
+      }
+
+      for (k in input) 
+      {
+        if (input.hasOwnProperty(k))
+        {
+          v = input[k];
+          switch (typeof v) {
+
+            case 'object':
+              if (v) {
+                p(toJSONString(v));
+              } else {
+                p("null");
+              }
+              break;
+            case 'string':
+            case 'number':
+            case 'boolean':
+              p(toJSONString(v));
+              break;
+          }
+        }
+      }
+
+      a.push('}');
+      return a.join('');
+      break;
+  }
+}
+
+function parseJSON(string, filter)
+{
+  try {
+    if (/^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/.
+            test(string))
+    {
+  
+        var j = eval('(' + string + ')');
+        if (typeof filter === 'function') {
+  
+            function walk(k, v) {
+                if (v && typeof v === 'object') {
+                    for (var i in v) {
+                        if (v.hasOwnProperty(i)) {
+                            v[i] = walk(i, v[i]);
+                        }
+                    }
+                }
+                return filter(k, v);
+            }
+  
+            j = walk('', j);
+        }
+        return j;
+    }
+  } catch (e) {
+  
+  }
+  throw new SyntaxError("parseJSON");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/static/loader.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,46 @@
+// Some final stuff - loader routines, etc.
+
+var __tmpEnanoStartup9843275;
+  
+function enanoStartup(e) {
+  if ( !e )
+  {
+    // Delay initting sliders until images are loaded
+    if ( typeof(window.onload) == 'function' )
+      __tmpEnanoStartup9843275 = window.onload;
+    else
+      __tmpEnanoStartup9843275 = function(){};
+    window.onload = function(e){__tmpEnanoStartup9843275(e);initSliders();};
+  }
+  else
+  {
+    initSliders();
+  }
+}
+
+function mdgInnerLoader(e)
+{
+  jws.startup();
+  enanoStartup(e);
+  if(window.location.hash == '#comments') ajaxComments();
+  window.onkeydown=isKeyPressed;
+  window.onkeyup=function(e) { isKeyPressed(e); };
+  Fat.fade_all();
+  fadeInfoBoxes();
+  //initTextareas();
+  buildSearchBoxes();
+  jBoxInit();
+  if(typeof (dbx_set_key) == 'function')
+  {
+    dbx_set_key();
+  }
+  runOnloadHooks(e);
+}
+if(window.onload) var ld = window.onload;
+else var ld = function() {return;};
+function enano_init(e) {
+  ld(e);
+  mdgInnerLoader(e);
+}
+window.onload = enano_init;
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/static/md5.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,51 @@
+// Javascript implementation of the and SHA1 hash algorithms - both written by Paul Johnston, licensed under the BSD license
+
+// MD5
+var hexcase = 0; var b64pad  = ""; var chrsz   = 8;
+function hex_md5(s){ return binl2hex(core_md5(str2binl(s), s.length * chrsz));}
+function b64_md5(s){ return binl2b64(core_md5(str2binl(s), s.length * chrsz));}
+function str_md5(s){ return binl2str(core_md5(str2binl(s), s.length * chrsz));}
+function hex_hmac_md5(key, data) { return binl2hex(core_hmac_md5(key, data)); }
+function b64_hmac_md5(key, data) { return binl2b64(core_hmac_md5(key, data)); }
+function str_hmac_md5(key, data) { return binl2str(core_hmac_md5(key, data)); }
+function md5_vm_test() { return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72"; }
+function core_md5(x, len) { x[len >> 5] |= 0x80 << ((len) % 32); x[(((len + 64) >>> 9) << 4) + 14] = len; var a =  1732584193; var b = -271733879; var c = -1732584194; var d =  271733878; for(var i = 0; i < x.length; i += 16) { var olda = a; var oldb = b; var oldc = c; var oldd = d; a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);c = md5_ff(c, d, a, b, x[i+ 2], 17,  606105819);b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
+         a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);d = md5_ff(d, a, b, c, x[i+ 5], 12,  1200080426);c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);a = md5_ff(a, b, c, d, x[i+ 8], 7 ,  1770035416);d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);c = md5_ff(c, d, a, b, x[i+10], 17, -42063);b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);a = md5_ff(a, b, c, d, x[i+12], 7 ,  1804603682);d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
+         c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);b = md5_ff(b, c, d, a, x[i+15], 22,  1236535329);a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);c = md5_gg(c, d, a, b, x[i+11], 14,  643717713);b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);d = md5_gg(d, a, b, c, x[i+10], 9 ,  38016083);c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
+         a = md5_gg(a, b, c, d, x[i+ 9], 5 ,  568446438);d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);b = md5_gg(b, c, d, a, x[i+ 8], 20,  1163531501);a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);c = md5_gg(c, d, a, b, x[i+ 7], 14,  1735328473);b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
+         c = md5_hh(c, d, a, b, x[i+11], 16,  1839030562);b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);d = md5_hh(d, a, b, c, x[i+ 4], 11,  1272893353);c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);a = md5_hh(a, b, c, d, x[i+13], 4 ,  681279174);d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);b = md5_hh(b, c, d, a, x[i+ 6], 23,  76029189);
+         a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);c = md5_hh(c, d, a, b, x[i+15], 16,  530742520);b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);d = md5_ii(d, a, b, c, x[i+ 7], 10,  1126891415);c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);a = md5_ii(a, b, c, d, x[i+12], 6 ,  1700485571);d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
+         c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);a = md5_ii(a, b, c, d, x[i+ 8], 6 ,  1873313359);d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);b = md5_ii(b, c, d, a, x[i+13], 21,  1309151649);a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);c = md5_ii(c, d, a, b, x[i+ 2], 15,  718787259);b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
+         a = safe_add(a, olda); b = safe_add(b, oldb); c = safe_add(c, oldc); d = safe_add(d, oldd); } return Array(a, b, c, d); }
+function md5_cmn(q, a, b, x, s, t) { return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b); }
+function md5_ff(a, b, c, d, x, s, t) { return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t); }
+function md5_gg(a, b, c, d, x, s, t) { return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t); }
+function md5_hh(a, b, c, d, x, s, t) { return md5_cmn(b ^ c ^ d, a, b, x, s, t); }
+function md5_ii(a, b, c, d, x, s, t) { return md5_cmn(c ^ (b | (~d)), a, b, x, s, t); }
+function core_hmac_md5(key, data) { var bkey = str2binl(key); if(bkey.length > 16) bkey = core_md5(bkey, key.length * chrsz); var ipad = Array(16), opad = Array(16); for(var i = 0; i < 16; i++) { ipad[i] = bkey[i] ^ 0x36363636; opad[i] = bkey[i] ^ 0x5C5C5C5C; } var hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz); return core_md5(opad.concat(hash), 512 + 128); }
+function safe_add(x, y) {var lsw = (x & 0xFFFF) + (y & 0xFFFF);var msw = (x >> 16) + (y >> 16) + (lsw >> 16);return (msw << 16) | (lsw & 0xFFFF); }
+function bit_rol(num, cnt) { return (num << cnt) | (num >>> (32 - cnt)); }
+function str2binl(str) { var bin = Array(); var mask = (1 << chrsz) - 1; for(var i = 0; i < str.length * chrsz; i += chrsz)bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32); return bin;}
+function binl2str(bin) { var str = ""; var mask = (1 << chrsz) - 1; for(var i = 0; i < bin.length * 32; i += chrsz) str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask); return str; }
+function binl2hex(binarray) { var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; var str = ""; for(var i = 0; i < binarray.length * 4; i++) { str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) + hex_tab.charAt((binarray[i>>2] >> ((i%4)*8  )) & 0xF); } return str; }
+function binl2b64(binarray) { var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; var str = ""; for(var i = 0; i < binarray.length * 4; i += 3) { var triplet = (((binarray[i >> 2] >> 8 * ( i   %4)) & 0xFF) << 16) | (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 ) |  ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF); for(var j = 0; j < 4; j++) { if(i * 8 + j * 6 > binarray.length * 32) str += b64pad; else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F); } } return str; }
+
+// SHA1
+function hex_sha1(s){return binb2hex(core_sha1(str2binb(s),s.length * chrsz));}
+function b64_sha1(s){return binb2b64(core_sha1(str2binb(s),s.length * chrsz));}
+function str_sha1(s){return binb2str(core_sha1(str2binb(s),s.length * chrsz));}
+function hex_hmac_sha1(key, data){ return binb2hex(core_hmac_sha1(key, data));}
+function b64_hmac_sha1(key, data){ return binb2b64(core_hmac_sha1(key, data));}
+function str_hmac_sha1(key, data){ return binb2str(core_hmac_sha1(key, data));}
+function sha1_vm_test() {   return hex_sha1("abc") == "a9993e364706816aba3e25717850c26c9cd0d89d"; }
+function core_sha1(x, len) { x[len >> 5] |= 0x80 << (24 - len % 32); x[((len + 64 >> 9) << 4) + 15] = len; var w = Array(80); var a =  1732584193; var b = -271733879; var c = -1732584194; var d =  271733878; var e = -1009589776; for(var i = 0; i < x.length; i += 16) { var olda = a; var oldb = b; var oldc = c; var oldd = d; var olde = e; for(var j = 0; j < 80; j++) { if(j < 16) w[j] = x[i + j]; else w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1); var t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)), safe_add(safe_add(e, w[j]), sha1_kt(j))); e = d; d = c; c = rol(b, 30); b = a; a = t; } a = safe_add(a, olda); b = safe_add(b, oldb); c = safe_add(c, oldc); d = safe_add(d, oldd); e = safe_add(e, olde); } return Array(a, b, c, d, e);}
+function sha1_ft(t, b, c, d){ if(t < 20) return (b & c) | ((~b) & d); if(t < 40) return b ^ c ^ d; if(t < 60) return (b & c) | (b & d) | (c & d); return b ^ c ^ d;}
+function sha1_kt(t){ return (t < 20) ?  1518500249 : (t < 40) ?  1859775393 : (t < 60) ? -1894007588 : -899497514;}
+function core_hmac_sha1(key, data){ var bkey = str2binb(key); if(bkey.length > 16) bkey = core_sha1(bkey, key.length * chrsz); var ipad = Array(16), opad = Array(16); for(var i = 0; i < 16; i++) { ipad[i] = bkey[i] ^ 0x36363636; opad[i] = bkey[i] ^ 0x5C5C5C5C; } var hash = core_sha1(ipad.concat(str2binb(data)), 512 + data.length * chrsz); return core_sha1(opad.concat(hash), 512 + 160);}
+function safe_add(x, y){ var lsw = (x & 0xFFFF) + (y & 0xFFFF); var msw = (x >> 16) + (y >> 16) + (lsw >> 16); return (msw << 16) | (lsw & 0xFFFF);}
+function rol(num, cnt){ return (num << cnt) | (num >>> (32 - cnt));}
+function str2binb(str){ var bin = Array(); var mask = (1 << chrsz) - 1; for(var i = 0; i < str.length * chrsz; i += chrsz) bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (32 - chrsz - i%32); return bin;}
+function binb2str(bin){ var str = ""; var mask = (1 << chrsz) - 1; for(var i = 0; i < bin.length * 32; i += chrsz) str += String.fromCharCode((bin[i>>5] >>> (32 - chrsz - i%32)) & mask); return str;}
+function binb2hex(binarray){ var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; var str = ""; for(var i = 0; i < binarray.length * 4; i++) { str += hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8+4)) & 0xF) + hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8  )) & 0xF); } return str;}
+function binb2b64(binarray){ var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; var str = ""; for(var i = 0; i < binarray.length * 4; i += 3) { var triplet = (((binarray[i   >> 2] >> 8 * (3 -  i   %4)) & 0xFF) << 16) | (((binarray[i+1 >> 2] >> 8 * (3 - (i+1)%4)) & 0xFF) << 8 ) |  ((binarray[i+2 >> 2] >> 8 * (3 - (i+2)%4)) & 0xFF); for(var j = 0; j < 4; j++) { if(i * 8 + j * 6 > binarray.length * 32) str += b64pad; else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F); } } return str;}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/static/misc.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,575 @@
+// Some additional DHTML functions
+
+function fetch_offset(obj) {
+  var left_offset = obj.offsetLeft;
+  var top_offset = obj.offsetTop;
+  while ((obj = obj.offsetParent) != null) {
+    left_offset += obj.offsetLeft;
+    top_offset += obj.offsetTop;
+  }
+  return { 'left' : left_offset, 'top' : top_offset };
+}
+
+function fetch_dimensions(o) {
+  var w = o.offsetWidth;
+  var h = o.offsetHeight;
+  return { 'w' : w, 'h' : h };
+}
+
+function findParentForm(o)
+{
+  // Not implemented - someone please let me know how to do this, what I need to do is
+  // find the first parent <form> tag above param 'o', not sure how to do it with DOM
+}
+
+function ajaxReverseDNS(o, text)
+{
+  if(text) var ipaddr = text;
+  else var ipaddr = o.innerHTML;
+  rDnsObj = o;
+  rDnsBannerObj = bannerOn('Retrieving reverse DNS info...');
+  ajaxGet(stdAjaxPrefix+'&_mode=rdns&ip='+ipaddr, function() {
+      if(ajax.readyState == 4)
+      {
+        off = fetch_offset(rDnsObj);
+        dim = fetch_dimensions(rDnsObj);
+        right = off['left'] + dim['w'];
+        top = off['top'] + dim['h'];
+        var thediv = document.createElement('div');
+        thediv.className = 'info-box';
+        thediv.style.margin = '0';
+        thediv.style.position = 'absolute';
+        thediv.style.top  = top  + 'px';
+        thediv.style.display = 'none';
+        thediv.style.zIndex = getHighestZ() + 2;
+        thediv.id = 'mdgDynamic_rDnsInfoDiv_'+Math.floor(Math.random() * 1000000);
+        thediv.innerHTML = '<b>Reverse DNS:</b><br />'+ajax.responseText+' <a href="#" onclick="elem = document.getElementById(\''+thediv.id+'\'); elem.innerHTML = \'\'; elem.style.display = \'none\';return false;">Close</a>';
+        var body = document.getElementsByTagName('body');
+        body = body[0];
+        bannerOff(rDnsBannerObj);
+        body.appendChild(thediv);
+        thediv.style.display = 'block';
+        left = fetch_dimensions(thediv);
+        thediv.style.display = 'none';
+        left = right - left['w'];
+        thediv.style.left = left + 'px';
+        thediv.style.display = 'block';
+        fadeInfoBoxes();
+      }
+    });
+}
+
+function bannerOn(text)
+{
+  darken(true);
+  var thediv = document.createElement('div');
+  thediv.className = 'mdg-comment';
+  thediv.style.padding = '0';
+  thediv.style.marginLeft = '0';
+  thediv.style.position = 'absolute';
+  thediv.style.display = 'none';
+  thediv.style.padding = '4px';
+  thediv.style.fontSize = '14pt';
+  thediv.id = 'mdgDynamic_bannerDiv_'+Math.floor(Math.random() * 1000000);
+  thediv.innerHTML = text;
+  
+  var body = document.getElementsByTagName('body');
+  body = body[0];
+  body.appendChild(thediv);
+  body.style.cursor = 'wait';
+  
+  thediv.style.display = 'block';
+  dim = fetch_dimensions(thediv);
+  thediv.style.display = 'none';
+  bdim = { 'w' : getWidth(), 'h' : getHeight() };
+  so = getScrollOffset();
+  
+  left = (bdim['w'] / 2) - ( dim['w'] / 2 );
+  top  = (bdim['h'] / 2) - ( dim['h'] / 2 ) + so;
+  
+  thediv.style.top  = top  + 'px';
+  thediv.style.left = left + 'px';
+  
+  thediv.style.display = 'block';
+  
+  return thediv.id;
+}
+
+function bannerOff(id)
+{
+  e = document.getElementById(id);
+  if(!e) return;
+  e.innerHTML = '';
+  e.style.display = 'none';
+  var body = document.getElementsByTagName('body');
+  body = body[0];
+  body.style.cursor = 'default';
+  enlighten(true);
+}
+
+function disableUnload(message)
+{
+  if(typeof message != 'string') message = 'You may want to save your changes first.';
+  var body = document.getElementsByTagName('body');
+  body = body[0];
+  body.onbeforeunload='return unescape(\''+escape(message)+'\')';
+}
+
+function enableUnload()
+{
+  var body = document.getElementsByTagName('body');
+  body = body[0];
+  body.onbeforeunload = null;
+}
+
+/**
+ * Gets the highest z-index of all divs in the document
+ * @return integer
+ */
+function getHighestZ()
+{
+  z = 0;
+  var divs = document.getElementsByTagName('div');
+  for(var i = 0; i < divs.length; i++)
+  {
+    if(divs[i].style.zIndex > z) z = divs[i].style.zIndex;
+  }
+  return z;
+}
+
+function isKeyPressed(event)
+{
+  if (event.shiftKey==1)
+  {
+    shift = true;
+  }
+  else
+  {
+    shift = false;
+  }
+}
+
+function moveDiv(div, newparent)
+{
+  var backup = div;
+  var oldparent = div.parentNode;
+  oldparent.removeChild(div);
+  newparent.appendChild(backup);
+}
+
+function readCookie(name) {var nameEQ = name + "=";var ca = document.cookie.split(';');for(var i=0;i < ca.length;i++){var c = ca[i];while (c.charAt(0)==' ') c = c.substring(1,c.length);if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);}return null;}
+function createCookie(name,value,days){if (days){var date = new Date();date.setTime(date.getTime()+(days*24*60*60*1000));var expires = "; expires="+date.toGMTString();}else var expires = "";document.cookie = name+"="+value+expires+"; path=/";}
+function eraseCookie(name) {createCookie(name,"",-1);}
+
+var busyBannerID;
+function goBusy(msg)
+{
+  if(!msg) msg = 'Please wait...';
+  body = document.getElementsByTagName('body');
+  body = body[0];
+  body.style.cursor = 'wait';
+  busyBannerID = bannerOn(msg);
+}
+
+function unBusy()
+{
+  body = document.getElementsByTagName('body');
+  body = body[0];
+  body.style.cursor = 'default';
+  bannerOff(busyBannerID);
+}
+
+function setAjaxLoading()
+{
+  if ( document.getElementById('ajaxloadicon') )
+  {
+    document.getElementById('ajaxloadicon').src=scriptPath + '/images/loading.gif';
+  }
+}
+
+function unsetAjaxLoading()
+{
+  if ( document.getElementById('ajaxloadicon') )
+  {
+    document.getElementById('ajaxloadicon').src=scriptPath + '/images/spacer.gif';
+  }
+}
+
+/*
+ * Search boxes
+ */
+ 
+function buildSearchBoxes()
+{
+  var divs = document.getElementsByTagName('*');
+  var boxes = new Array();
+  for ( var i = 0; i < divs.length; i++ )
+  {
+    if ( divs[i].className)
+    {
+      if ( divs[i].className.substr(0, 9) == 'searchbox' )
+      {
+        boxes.push(divs[i]);
+      }
+    }
+  }
+  for ( var i = 0; i < boxes.length; i++ )
+  {
+    if ( boxes[i].className.match(/^searchbox\[([0-9]+)px\]$/) )
+    {
+      var width = boxes[i].className.match(/^searchbox\[([0-9]+)px\]$/);
+      width = parseInt(width[1]);
+    }
+    else
+    {
+      var width = 120;
+    }
+    createSearchBox(boxes[i], width);
+  }
+}
+
+function createSearchBox(parent, width)
+{
+  if ( typeof(parent) != 'object')
+  {
+    alert('BUG: createSearchBox(): parent is not an object');
+    return false;
+  }
+  //parent.style.padding = '0px';
+  //parent.style.textAlign = 'center';
+  parent.style.width = width + 'px';
+  var submit = document.createElement('div');
+  submit.onclick = function() { searchFormSubmit(this); };
+  submit.className = 'js-search-submit';
+  var input = document.createElement('input');
+  input.className = 'js-search-box';
+  input.value = 'Search';
+  input.name = 'q';
+  input.style.width = ( width - 28 ) + 'px';
+  input.onfocus = function() { if ( this.value == 'Search' ) this.value = ''; };
+  input.onblur  = function() { if ( this.value == '' ) this.value = 'Search'; };
+  parent.appendChild(input);
+  var off = fetch_offset(input);
+  var top = off['top'] + 'px';
+  var left = ( parseInt(off['left']) + ( width - 24 ) ) + 'px';
+  submit.style.top = top;
+  submit.style.left = left;
+  parent.appendChild(submit);
+}
+
+function searchFormSubmit(obj)
+{
+  var input = obj.previousSibling;
+  if ( input.value == 'Search' || input.value == '' )
+    return false;
+  var p = obj;
+  while(true)
+  {
+    p = p.parentNode;
+    if ( !p )
+      break;
+    if ( typeof(p.tagName) != 'string' )
+      break;
+    else if ( p.tagName.toLowerCase() == 'form' )
+    {
+      p.submit();
+    }
+    else if ( p.tagName.toLowerCase() == 'body' )
+    {
+      break;
+    }
+  }
+}
+
+/*
+ * AJAX login box (experimental)
+ */
+
+var ajax_auth_prompt_cache = false;
+var ajax_auth_mb_cache = false;
+var ajax_auth_level_cache = false;
+
+function ajaxPromptAdminAuth(call_on_ok, level)
+{
+  if ( typeof(call_on_ok) == 'function' )
+  {
+    ajax_auth_prompt_cache = call_on_ok;
+  }
+  if ( !level )
+    level = 2;
+  ajax_auth_level_cache = level;
+  var loading_win = '<div align="center" style="text-align: center;"> \
+      <p>Fetching an encryption key...</p> \
+      <p><small>Not working? Use the <a href="'+makeUrlNS('Special', 'Login/' + title)+'">alternate login form</a>.</p> \
+      <p><img alt="Please wait..." src="'+scriptPath+'/images/loading-big.gif" /></p> \
+    </div>';
+  ajax_auth_mb_cache = new messagebox(MB_OKCANCEL|MB_ICONLOCK, 'Please enter your username and password to continue.', loading_win);
+  ajax_auth_mb_cache.onbeforeclick['OK'] = ajaxValidateLogin;
+  ajaxAuthLoginInnerSetup();
+}
+
+function ajaxAuthLoginInnerSetup()
+{
+  ajaxGet(makeUrlNS('Special', 'Login', 'act=getkey'), function() {
+      if ( ajax.readyState == 4 )
+      {
+        var response = ajax.responseText;
+        if ( response.substr(0,1) != '{' )
+        {
+          alert('Invalid JSON response from server: ' + response);
+          return false;
+        }
+        response = parseJSON(response);
+        var form_html = ' \
+          <table border="0" align="center"> \
+            <tr> \
+              <td>Username:</td><td><input tabindex="1" id="ajaxlogin_user" type="text"     size="25" /> \
+            </tr> \
+            <tr> \
+              <td>Password:</td><td><input tabindex="2" id="ajaxlogin_pass" type="password" size="25" /> \
+            </tr> \
+            <tr> \
+              <td colspan="2" style="text-align: center;"> \
+                <br /><small>Trouble logging in? Try the <a href="'+makeUrlNS('Special', 'Login/' + title)+'">full login form</a>.<br /> \
+                Did you <a href="'+makeUrlNS('Special', 'PasswordReset')+'">forget your password</a>?<br /> \
+                Maybe you need to <a href="'+makeUrlNS('Special', 'Register')+'">create an account</a>.</small> \
+              </td> \
+            </tr> \
+          </table> \
+          <input type="hidden" id="ajaxlogin_crypt_key"       value="' + response.key + '" /> \
+          <input type="hidden" id="ajaxlogin_crypt_challenge" value="' + response.challenge + '" /> \
+        </form>';
+        ajax_auth_mb_cache.updateContent(form_html);
+        $('messageBox').object.nextSibling.firstChild.tabindex = '3';
+        $('ajaxlogin_user').object.focus();
+        $('ajaxlogin_pass').object.onblur = function() { $('messageBox').object.nextSibling.firstChild.focus(); };
+      }
+    });
+}
+
+function ajaxValidateLogin()
+{
+  var username,password,auth_enabled,crypt_key,crypt_data,challenge_salt,challenge_data;
+  username = document.getElementById('ajaxlogin_user');
+  if ( !username )
+    return false;
+  username = document.getElementById('ajaxlogin_user').value;
+  password = document.getElementById('ajaxlogin_pass').value;
+  auth_enabled = false;
+  
+  disableJSONExts();
+  
+  //
+  // Encryption test
+  //
+  
+  var str = '';
+  for(i=0;i<keySizeInBits/4;i++)
+  {
+    str+='0';
+  }
+  str = hexToByteArray(str);
+  var ct  = rijndaelEncrypt(str, str, 'ECB');
+  ct      = byteArrayToHex(ct);
+  var v;
+  switch(keySizeInBits)
+  {
+    case 128:
+      v = '66e94bd4ef8a2c3b884cfa59ca342b2e';
+      break;
+    case 192:
+      v = 'aae06992acbf52a3e8f4a96ec9300bd7aae06992acbf52a3e8f4a96ec9300bd7';
+      break;
+    case 256:
+      v = 'dc95c078a2408989ad48a21492842087dc95c078a2408989ad48a21492842087';
+      break;
+  }
+  auth_enabled = ( ct == v && md5_vm_test() );
+  if ( !auth_enabled )
+  {
+    alert('Login error: encryption sanity check failed\n');
+    return true;
+  }
+  
+  crypt_key = document.getElementById('ajaxlogin_crypt_key').value;
+  challenge_salt = document.getElementById('ajaxlogin_crypt_challenge').value;
+  
+  var crypt_key_md5 = hex_md5(crypt_key);
+  
+  challenge_data = hex_md5(password + challenge_salt) + challenge_salt;
+  
+  password = stringToByteArray(password);
+  crypt_key = hexToByteArray(crypt_key);
+  
+  crypt_data = rijndaelEncrypt(password, crypt_key, 'ECB');
+  crypt_data = byteArrayToHex(crypt_data);
+  
+  var json_data = {
+    'username' : username,
+    'crypt_key' : crypt_key_md5,
+    'challenge' : challenge_data,
+    'crypt_data' : crypt_data,
+    'level' : ajax_auth_level_cache
+  };
+  
+  json_data = toJSONString(json_data);
+  json_data = ajaxEscape(json_data);
+  
+  var loading_win = '<div align="center" style="text-align: center;"> \
+      <p>Logging in...</p> \
+      <p><img alt="Please wait..." src="'+scriptPath+'/images/loading-big.gif" /></p> \
+    </div>';
+    
+  ajax_auth_mb_cache.updateContent(loading_win);
+  
+  ajaxPost(makeUrlNS('Special', 'Login', 'act=ajaxlogin'), 'params=' + json_data, function() {
+      if ( ajax.readyState == 4 )
+      {
+        var response = ajax.responseText;
+        if ( response.substr(0,1) != '{' )
+        {
+          alert('Invalid JSON response from server: ' + response);
+          ajaxAuthLoginInnerSetup();
+          return false;
+        }
+        response = parseJSON(response);
+        switch(response.result)
+        {
+          case 'success':
+            if ( typeof(ajax_auth_prompt_cache) == 'function' )
+            {
+              ajax_auth_prompt_cache(response.key);
+            }
+            break;
+          case 'success_reset':
+            var conf = confirm('You have logged in using a temporary password. Before you can log in, you must finish resetting your password. Do you want to reset your real password now?');
+            if ( conf )
+            {
+              var url = makeUrlNS('Special', 'PasswordReset/stage2/' + response.user_id + '/' + response.temppass);
+              window.location = url;
+            }
+            else
+            {
+              ajaxAuthLoginInnerSetup();
+            }
+            break;
+          case 'error':
+            alert(response.error);
+            ajaxAuthLoginInnerSetup();
+            break;
+          default:
+            alert(ajax.responseText);
+            break;
+        }
+      }
+    });
+  
+  return true;
+  
+}
+
+// This code is in the public domain. Feel free to link back to http://jan.moesen.nu/
+function sprintf()
+{
+  if (!arguments || arguments.length < 1 || !RegExp)
+  {
+    return;
+  }
+  var str = arguments[0];
+  var re = /([^%]*)%('.|0|\x20)?(-)?(\d+)?(\.\d+)?(%|b|c|d|u|f|o|s|x|X)(.*)/;
+  var a = b = [], numSubstitutions = 0, numMatches = 0;
+  while (a = re.exec(str))
+  {
+    var leftpart = a[1], pPad = a[2], pJustify = a[3], pMinLength = a[4];
+    var pPrecision = a[5], pType = a[6], rightPart = a[7];
+    
+    //alert(a + '\n' + [a[0], leftpart, pPad, pJustify, pMinLength, pPrecision);
+
+    numMatches++;
+    if (pType == '%')
+    {
+      subst = '%';
+    }
+    else
+    {
+      numSubstitutions++;
+      if (numSubstitutions >= arguments.length)
+      {
+        alert('Error! Not enough function arguments (' + (arguments.length - 1) + ', excluding the string)\nfor the number of substitution parameters in string (' + numSubstitutions + ' so far).');
+      }
+      var param = arguments[numSubstitutions];
+      var pad = '';
+             if (pPad && pPad.substr(0,1) == "'") pad = leftpart.substr(1,1);
+        else if (pPad) pad = pPad;
+      var justifyRight = true;
+             if (pJustify && pJustify === "-") justifyRight = false;
+      var minLength = -1;
+             if (pMinLength) minLength = parseInt(pMinLength);
+      var precision = -1;
+             if (pPrecision && pType == 'f') precision = parseInt(pPrecision.substring(1));
+      var subst = param;
+             if (pType == 'b') subst = parseInt(param).toString(2);
+        else if (pType == 'c') subst = String.fromCharCode(parseInt(param));
+        else if (pType == 'd') subst = parseInt(param) ? parseInt(param) : 0;
+        else if (pType == 'u') subst = Math.abs(param);
+        else if (pType == 'f') subst = (precision > -1) ? Math.round(parseFloat(param) * Math.pow(10, precision)) / Math.pow(10, precision): parseFloat(param);
+        else if (pType == 'o') subst = parseInt(param).toString(8);
+        else if (pType == 's') subst = param;
+        else if (pType == 'x') subst = ('' + parseInt(param).toString(16)).toLowerCase();
+        else if (pType == 'X') subst = ('' + parseInt(param).toString(16)).toUpperCase();
+    }
+    str = leftpart + subst + rightPart;
+  }
+  return str;
+}
+
+function paginator_goto(parentobj, this_page, num_pages, perpage, url_string)
+{
+  var height = $(parentobj).Height();
+  var width  = $(parentobj).Width();
+  var left   = $(parentobj).Left();
+  var top    = $(parentobj).Top();
+  var left_pos = left + width ;
+  var top_pos = height + top;
+  var div = document.createElement('div');
+  div.style.position = 'absolute';
+  div.style.top = top_pos + 'px';
+  div.className = 'question-box';
+  div.style.margin = '1px 0 0 2px';
+  var vtmp = 'input_' + Math.floor(Math.random() * 1000000);
+  div.innerHTML = 'Go to page:<br /><input type="text" size="2" style="padding: 1px; font-size: 8pt;" value="'+(parseInt(this_page)+1)+'" id="'+vtmp+'" />&emsp;<a href="#" onclick="paginator_submit(this, '+num_pages+', '+perpage+', unescape(\'' + escape(url_string) + '\')); return false;" style="font-size: 14pt; text-decoration: none;">&raquo;</a>&emsp;<a href="#" onclick="fly_out_top(this.parentNode, false, true); return false;" style="font-size: 14pt; text-decoration: none;">&times;</a>';
+  
+  var body = document.getElementsByTagName('body')[0];
+  body.appendChild(div);
+  
+  document.getElementById(vtmp).onkeypress = function(e){if(e.keyCode==13)this.nextSibling.nextSibling.onclick();};
+  document.getElementById(vtmp).focus();
+  
+  // fade the div
+  /*
+  if(!div.id) div.id = 'autofade_'+Math.floor(Math.random() * 100000);
+  var from = '#33FF33';
+  Fat.fade_element(div.id,30,2000,from,Fat.get_bgcolor(div.id));
+  */
+  fly_in_bottom(div, false, true);
+  
+  var divh = $(div).Width();
+  left_pos = left_pos - divh;
+  div.style.left = left_pos + 'px';
+}
+
+function paginator_submit(obj, max, perpage, formatstring)
+{
+  var userinput = obj.previousSibling.previousSibling.value;
+  userinput = parseInt(userinput);
+  var offset = ( userinput - 1 ) * perpage;
+  if ( userinput > max || isNaN(userinput) || userinput < 1 )
+  {
+    new messagebox(MB_OK|MB_ICONSTOP, 'Invalid entry', 'Please enter a page number between 1 and ' + max + '.');
+    return false;
+  }
+  var url = sprintf(formatstring, String(offset));
+  fly_out_top(obj.parentNode, false, true);
+  window.location = url;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/static/misc.js~	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,563 @@
+// Some additional DHTML functions
+
+function fetch_offset(obj) {
+  var left_offset = obj.offsetLeft;
+  var top_offset = obj.offsetTop;
+  while ((obj = obj.offsetParent) != null) {
+    left_offset += obj.offsetLeft;
+    top_offset += obj.offsetTop;
+  }
+  return { 'left' : left_offset, 'top' : top_offset };
+}
+
+function fetch_dimensions(o) {
+  var w = o.offsetWidth;
+  var h = o.offsetHeight;
+  return { 'w' : w, 'h' : h };
+}
+
+function findParentForm(o)
+{
+  // Not implemented - someone please let me know how to do this, what I need to do is
+  // find the first parent <form> tag above param 'o', not sure how to do it with DOM
+}
+
+function ajaxReverseDNS(o, text)
+{
+  if(text) var ipaddr = text;
+  else var ipaddr = o.innerHTML;
+  rDnsObj = o;
+  rDnsBannerObj = bannerOn('Retrieving reverse DNS info...');
+  ajaxGet(stdAjaxPrefix+'&_mode=rdns&ip='+ipaddr, function() {
+      if(ajax.readyState == 4)
+      {
+        off = fetch_offset(rDnsObj);
+        dim = fetch_dimensions(rDnsObj);
+        right = off['left'] + dim['w'];
+        top = off['top'] + dim['h'];
+        var thediv = document.createElement('div');
+        thediv.className = 'info-box';
+        thediv.style.margin = '0';
+        thediv.style.position = 'absolute';
+        thediv.style.top  = top  + 'px';
+        thediv.style.display = 'none';
+        thediv.style.zIndex = getHighestZ() + 2;
+        thediv.id = 'mdgDynamic_rDnsInfoDiv_'+Math.floor(Math.random() * 1000000);
+        thediv.innerHTML = '<b>Reverse DNS:</b><br />'+ajax.responseText+' <a href="#" onclick="elem = document.getElementById(\''+thediv.id+'\'); elem.innerHTML = \'\'; elem.style.display = \'none\';return false;">Close</a>';
+        var body = document.getElementsByTagName('body');
+        body = body[0];
+        bannerOff(rDnsBannerObj);
+        body.appendChild(thediv);
+        thediv.style.display = 'block';
+        left = fetch_dimensions(thediv);
+        thediv.style.display = 'none';
+        left = right - left['w'];
+        thediv.style.left = left + 'px';
+        thediv.style.display = 'block';
+        fadeInfoBoxes();
+      }
+    });
+}
+
+function bannerOn(text)
+{
+  darken(true);
+  var thediv = document.createElement('div');
+  thediv.className = 'mdg-comment';
+  thediv.style.padding = '0';
+  thediv.style.marginLeft = '0';
+  thediv.style.position = 'absolute';
+  thediv.style.display = 'none';
+  thediv.style.padding = '4px';
+  thediv.style.fontSize = '14pt';
+  thediv.id = 'mdgDynamic_bannerDiv_'+Math.floor(Math.random() * 1000000);
+  thediv.innerHTML = text;
+  
+  var body = document.getElementsByTagName('body');
+  body = body[0];
+  body.appendChild(thediv);
+  body.style.cursor = 'wait';
+  
+  thediv.style.display = 'block';
+  dim = fetch_dimensions(thediv);
+  thediv.style.display = 'none';
+  bdim = { 'w' : getWidth(), 'h' : getHeight() };
+  so = getScrollOffset();
+  
+  left = (bdim['w'] / 2) - ( dim['w'] / 2 );
+  top  = (bdim['h'] / 2) - ( dim['h'] / 2 ) + so;
+  
+  thediv.style.top  = top  + 'px';
+  thediv.style.left = left + 'px';
+  
+  thediv.style.display = 'block';
+  
+  return thediv.id;
+}
+
+function bannerOff(id)
+{
+  e = document.getElementById(id);
+  if(!e) return;
+  e.innerHTML = '';
+  e.style.display = 'none';
+  var body = document.getElementsByTagName('body');
+  body = body[0];
+  body.style.cursor = 'default';
+  enlighten(true);
+}
+
+function disableUnload(message)
+{
+  if(typeof message != 'string') message = 'You may want to save your changes first.';
+  var body = document.getElementsByTagName('body');
+  body = body[0];
+  body.onbeforeunload='return unescape(\''+escape(message)+'\')';
+}
+
+function enableUnload()
+{
+  var body = document.getElementsByTagName('body');
+  body = body[0];
+  body.onbeforeunload = null;
+}
+
+/**
+ * Gets the highest z-index of all divs in the document
+ * @return integer
+ */
+function getHighestZ()
+{
+  z = 0;
+  var divs = document.getElementsByTagName('div');
+  for(var i = 0; i < divs.length; i++)
+  {
+    if(divs[i].style.zIndex > z) z = divs[i].style.zIndex;
+  }
+  return z;
+}
+
+function isKeyPressed(event)
+{
+  if (event.shiftKey==1)
+  {
+    shift = true;
+  }
+  else
+  {
+    shift = false;
+  }
+}
+
+function moveDiv(div, newparent)
+{
+  var backup = div;
+  var oldparent = div.parentNode;
+  oldparent.removeChild(div);
+  newparent.appendChild(backup);
+}
+
+function readCookie(name) {var nameEQ = name + "=";var ca = document.cookie.split(';');for(var i=0;i < ca.length;i++){var c = ca[i];while (c.charAt(0)==' ') c = c.substring(1,c.length);if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);}return null;}
+function createCookie(name,value,days){if (days){var date = new Date();date.setTime(date.getTime()+(days*24*60*60*1000));var expires = "; expires="+date.toGMTString();}else var expires = "";document.cookie = name+"="+value+expires+"; path=/";}
+function eraseCookie(name) {createCookie(name,"",-1);}
+
+var busyBannerID;
+function goBusy(msg)
+{
+  if(!msg) msg = 'Please wait...';
+  body = document.getElementsByTagName('body');
+  body = body[0];
+  body.style.cursor = 'wait';
+  busyBannerID = bannerOn(msg);
+}
+
+function unBusy()
+{
+  body = document.getElementsByTagName('body');
+  body = body[0];
+  body.style.cursor = 'default';
+  bannerOff(busyBannerID);
+}
+
+function setAjaxLoading()
+{
+  if ( document.getElementById('ajaxloadicon') )
+  {
+    document.getElementById('ajaxloadicon').src=scriptPath + '/images/loading.gif';
+  }
+}
+
+function unsetAjaxLoading()
+{
+  if ( document.getElementById('ajaxloadicon') )
+  {
+    document.getElementById('ajaxloadicon').src=scriptPath + '/images/spacer.gif';
+  }
+}
+
+/*
+ * Search boxes
+ */
+ 
+function buildSearchBoxes()
+{
+  var divs = document.getElementsByTagName('*');
+  var boxes = new Array();
+  for ( var i = 0; i < divs.length; i++ )
+  {
+    if ( divs[i].className)
+    {
+      if ( divs[i].className.substr(0, 9) == 'searchbox' )
+      {
+        boxes.push(divs[i]);
+      }
+    }
+  }
+  for ( var i = 0; i < boxes.length; i++ )
+  {
+    if ( boxes[i].className.match(/^searchbox\[([0-9]+)px\]$/) )
+    {
+      var width = boxes[i].className.match(/^searchbox\[([0-9]+)px\]$/);
+      width = parseInt(width[1]);
+    }
+    else
+    {
+      var width = 120;
+    }
+    createSearchBox(boxes[i], width);
+  }
+}
+
+function createSearchBox(parent, width)
+{
+  if ( typeof(parent) != 'object')
+  {
+    alert('BUG: createSearchBox(): parent is not an object');
+    return false;
+  }
+  //parent.style.padding = '0px';
+  //parent.style.textAlign = 'center';
+  parent.style.width = width + 'px';
+  var submit = document.createElement('div');
+  submit.onclick = function() { searchFormSubmit(this); };
+  submit.className = 'js-search-submit';
+  var input = document.createElement('input');
+  input.className = 'js-search-box';
+  input.value = 'Search';
+  input.name = 'q';
+  input.style.width = ( width - 28 ) + 'px';
+  input.onfocus = function() { if ( this.value == 'Search' ) this.value = ''; };
+  input.onblur  = function() { if ( this.value == '' ) this.value = 'Search'; };
+  parent.appendChild(input);
+  var off = fetch_offset(input);
+  var top = off['top'] + 'px';
+  var left = ( parseInt(off['left']) + ( width - 24 ) ) + 'px';
+  submit.style.top = top;
+  submit.style.left = left;
+  parent.appendChild(submit);
+}
+
+function searchFormSubmit(obj)
+{
+  var input = obj.previousSibling;
+  if ( input.value == 'Search' || input.value == '' )
+    return false;
+  var p = obj;
+  while(true)
+  {
+    p = p.parentNode;
+    if ( !p )
+      break;
+    if ( typeof(p.tagName) != 'string' )
+      break;
+    else if ( p.tagName.toLowerCase() == 'form' )
+    {
+      p.submit();
+    }
+    else if ( p.tagName.toLowerCase() == 'body' )
+    {
+      break;
+    }
+  }
+}
+
+/*
+ * AJAX login box (experimental)
+ */
+
+var ajax_auth_prompt_cache = false;
+var ajax_auth_mb_cache = false;
+var ajax_auth_level_cache = false;
+
+function ajaxPromptAdminAuth(call_on_ok, level)
+{
+  if ( typeof(call_on_ok) == 'function' )
+  {
+    ajax_auth_prompt_cache = call_on_ok;
+  }
+  if ( !level )
+    level = 2;
+  ajax_auth_level_cache = level;
+  var loading_win = '<div align="center" style="text-align: center;"> \
+      <p>Fetching an encryption key...</p> \
+      <p><small>Not working? Use the <a href="'+makeUrlNS('Special', 'Login/' + title)+'">alternate login form</a>.</p> \
+      <p><img alt="Please wait..." src="'+scriptPath+'/images/loading-big.gif" /></p> \
+    </div>';
+  ajax_auth_mb_cache = new messagebox(MB_OKCANCEL|MB_ICONLOCK, 'Please enter your username and password to continue.', loading_win);
+  ajax_auth_mb_cache.onbeforeclick['OK'] = ajaxValidateLogin;
+  ajaxAuthLoginInnerSetup();
+}
+
+function ajaxAuthLoginInnerSetup()
+{
+  ajaxGet(makeUrlNS('Special', 'Login', 'act=getkey'), function() {
+      if ( ajax.readyState == 4 )
+      {
+        var response = ajax.responseText;
+        if ( response.substr(0,1) != '{' )
+        {
+          alert('Invalid JSON response from server: ' + response);
+          return false;
+        }
+        response = parseJSON(response);
+        var form_html = ' \
+          <table border="0" align="center"> \
+            <tr> \
+              <td>Username:</td><td><input tabindex="1" id="ajaxlogin_user" type="text"     size="25" /> \
+            </tr> \
+            <tr> \
+              <td>Password:</td><td><input tabindex="2" id="ajaxlogin_pass" type="password" size="25" /> \
+            </tr> \
+            <tr> \
+              <td colspan="2" style="text-align: center;"> \
+                <br /><small>Trouble logging in? Try the <a href="'+makeUrlNS('Special', 'Login/' + title)+'">full login form</a>.<br /> \
+                Did you <a href="'+makeUrlNS('Special', 'PasswordReset')+'">forget your password</a>?<br /> \
+                Maybe you need to <a href="'+makeUrlNS('Special', 'Register')+'">create an account</a>.</small> \
+              </td> \
+            </tr> \
+          </table> \
+          <input type="hidden" id="ajaxlogin_crypt_key"       value="' + response.key + '" /> \
+          <input type="hidden" id="ajaxlogin_crypt_challenge" value="' + response.challenge + '" /> \
+        </form>';
+        ajax_auth_mb_cache.updateContent(form_html);
+        $('messageBox').object.nextSibling.firstChild.tabindex = '3';
+        $('ajaxlogin_user').object.focus();
+        $('ajaxlogin_pass').object.onblur = function() { $('messageBox').object.nextSibling.firstChild.focus(); };
+      }
+    });
+}
+
+function ajaxValidateLogin()
+{
+  var username,password,auth_enabled,crypt_key,crypt_data,challenge_salt,challenge_data;
+  username = document.getElementById('ajaxlogin_user');
+  if ( !username )
+    return false;
+  username = document.getElementById('ajaxlogin_user').value;
+  password = document.getElementById('ajaxlogin_pass').value;
+  auth_enabled = false;
+  
+  disableJSONExts();
+  
+  //
+  // Encryption test
+  //
+  
+  var str = '';
+  for(i=0;i<keySizeInBits/4;i++)
+  {
+    str+='0';
+  }
+  str = hexToByteArray(str);
+  var ct  = rijndaelEncrypt(str, str, 'ECB');
+  ct      = byteArrayToHex(ct);
+  var v;
+  switch(keySizeInBits)
+  {
+    case 128:
+      v = '66e94bd4ef8a2c3b884cfa59ca342b2e';
+      break;
+    case 192:
+      v = 'aae06992acbf52a3e8f4a96ec9300bd7aae06992acbf52a3e8f4a96ec9300bd7';
+      break;
+    case 256:
+      v = 'dc95c078a2408989ad48a21492842087dc95c078a2408989ad48a21492842087';
+      break;
+  }
+  auth_enabled = ( ct == v && md5_vm_test() );
+  if ( !auth_enabled )
+  {
+    alert('Login error: encryption sanity check failed\n');
+    return true;
+  }
+  
+  crypt_key = document.getElementById('ajaxlogin_crypt_key').value;
+  challenge_salt = document.getElementById('ajaxlogin_crypt_challenge').value;
+  
+  var crypt_key_md5 = hex_md5(crypt_key);
+  
+  challenge_data = hex_md5(password + challenge_salt) + challenge_salt;
+  
+  password = stringToByteArray(password);
+  crypt_key = hexToByteArray(crypt_key);
+  
+  crypt_data = rijndaelEncrypt(password, crypt_key, 'ECB');
+  crypt_data = byteArrayToHex(crypt_data);
+  
+  var json_data = {
+    'username' : username,
+    'crypt_key' : crypt_key_md5,
+    'challenge' : challenge_data,
+    'crypt_data' : crypt_data,
+    'level' : ajax_auth_level_cache
+  };
+  
+  json_data = toJSONString(json_data);
+  json_data = ajaxEscape(json_data);
+  
+  var loading_win = '<div align="center" style="text-align: center;"> \
+      <p>Logging in...</p> \
+      <p><img alt="Please wait..." src="'+scriptPath+'/images/loading-big.gif" /></p> \
+    </div>';
+    
+  ajax_auth_mb_cache.updateContent(loading_win);
+  
+  ajaxPost(makeUrlNS('Special', 'Login', 'act=ajaxlogin'), 'params=' + json_data, function() {
+      if ( ajax.readyState == 4 )
+      {
+        var response = ajax.responseText;
+        if ( response.substr(0,1) != '{' )
+        {
+          alert('Invalid JSON response from server: ' + response);
+          ajaxAuthLoginInnerSetup();
+          return false;
+        }
+        response = parseJSON(response);
+        switch(response.result)
+        {
+          case 'success':
+            if ( typeof(ajax_auth_prompt_cache) == 'function' )
+            {
+              ajax_auth_prompt_cache(response.key);
+            }
+            break;
+          case 'error':
+            alert(response.error);
+            ajaxAuthLoginInnerSetup();
+            break;
+          default:
+            alert(ajax.responseText);
+            break;
+        }
+      }
+    });
+  
+  return true;
+  
+}
+
+// This code is in the public domain. Feel free to link back to http://jan.moesen.nu/
+function sprintf()
+{
+  if (!arguments || arguments.length < 1 || !RegExp)
+  {
+    return;
+  }
+  var str = arguments[0];
+  var re = /([^%]*)%('.|0|\x20)?(-)?(\d+)?(\.\d+)?(%|b|c|d|u|f|o|s|x|X)(.*)/;
+  var a = b = [], numSubstitutions = 0, numMatches = 0;
+  while (a = re.exec(str))
+  {
+    var leftpart = a[1], pPad = a[2], pJustify = a[3], pMinLength = a[4];
+    var pPrecision = a[5], pType = a[6], rightPart = a[7];
+    
+    //alert(a + '\n' + [a[0], leftpart, pPad, pJustify, pMinLength, pPrecision);
+
+    numMatches++;
+    if (pType == '%')
+    {
+      subst = '%';
+    }
+    else
+    {
+      numSubstitutions++;
+      if (numSubstitutions >= arguments.length)
+      {
+        alert('Error! Not enough function arguments (' + (arguments.length - 1) + ', excluding the string)\nfor the number of substitution parameters in string (' + numSubstitutions + ' so far).');
+      }
+      var param = arguments[numSubstitutions];
+      var pad = '';
+             if (pPad && pPad.substr(0,1) == "'") pad = leftpart.substr(1,1);
+        else if (pPad) pad = pPad;
+      var justifyRight = true;
+             if (pJustify && pJustify === "-") justifyRight = false;
+      var minLength = -1;
+             if (pMinLength) minLength = parseInt(pMinLength);
+      var precision = -1;
+             if (pPrecision && pType == 'f') precision = parseInt(pPrecision.substring(1));
+      var subst = param;
+             if (pType == 'b') subst = parseInt(param).toString(2);
+        else if (pType == 'c') subst = String.fromCharCode(parseInt(param));
+        else if (pType == 'd') subst = parseInt(param) ? parseInt(param) : 0;
+        else if (pType == 'u') subst = Math.abs(param);
+        else if (pType == 'f') subst = (precision > -1) ? Math.round(parseFloat(param) * Math.pow(10, precision)) / Math.pow(10, precision): parseFloat(param);
+        else if (pType == 'o') subst = parseInt(param).toString(8);
+        else if (pType == 's') subst = param;
+        else if (pType == 'x') subst = ('' + parseInt(param).toString(16)).toLowerCase();
+        else if (pType == 'X') subst = ('' + parseInt(param).toString(16)).toUpperCase();
+    }
+    str = leftpart + subst + rightPart;
+  }
+  return str;
+}
+
+function paginator_goto(parentobj, this_page, num_pages, perpage, url_string)
+{
+  var height = $(parentobj).Height();
+  var width  = $(parentobj).Width();
+  var left   = $(parentobj).Left();
+  var top    = $(parentobj).Top();
+  var left_pos = left + width ;
+  var top_pos = height + top;
+  var div = document.createElement('div');
+  div.style.position = 'absolute';
+  div.style.top = top_pos + 'px';
+  div.className = 'question-box';
+  div.style.margin = '1px 0 0 2px';
+  var vtmp = 'input_' + Math.floor(Math.random() * 1000000);
+  div.innerHTML = 'Go to page:<br /><input type="text" size="2" style="padding: 1px; font-size: 8pt;" value="'+(parseInt(this_page)+1)+'" id="'+vtmp+'" />&emsp;<a href="#" onclick="paginator_submit(this, '+num_pages+', '+perpage+', unescape(\'' + escape(url_string) + '\')); return false;" style="font-size: 14pt; text-decoration: none;">&raquo;</a>&emsp;<a href="#" onclick="fly_out_top(this.parentNode, false, true); return false;" style="font-size: 14pt; text-decoration: none;">&times;</a>';
+  
+  var body = document.getElementsByTagName('body')[0];
+  body.appendChild(div);
+  
+  document.getElementById(vtmp).onkeypress = function(e){if(e.keyCode==13)this.nextSibling.nextSibling.onclick();};
+  document.getElementById(vtmp).focus();
+  
+  // fade the div
+  /*
+  if(!div.id) div.id = 'autofade_'+Math.floor(Math.random() * 100000);
+  var from = '#33FF33';
+  Fat.fade_element(div.id,30,2000,from,Fat.get_bgcolor(div.id));
+  */
+  fly_in_bottom(div, false, true);
+  
+  var divh = $(div).Width();
+  left_pos = left_pos - divh;
+  div.style.left = left_pos + 'px';
+}
+
+function paginator_submit(obj, max, perpage, formatstring)
+{
+  var userinput = obj.previousSibling.previousSibling.value;
+  userinput = parseInt(userinput);
+  var offset = ( userinput - 1 ) * perpage;
+  if ( userinput > max || isNaN(userinput) || userinput < 1 )
+  {
+    new messagebox(MB_OK|MB_ICONSTOP, 'Invalid entry', 'Please enter a page number between 1 and ' + max + '.');
+    return false;
+  }
+  var url = sprintf(formatstring, String(offset));
+  fly_out_top(obj.parentNode, false, true);
+  window.location = url;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/static/rijndael.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,579 @@
+/* rijndael.js      Rijndael Reference Implementation
+   Copyright (c) 2001 Fritz Schneider
+ 
+ This software is provided as-is, without express or implied warranty.  
+ Permission to use, copy, modify, distribute or sell this software, with or
+ without fee, for any purpose and by any individual or organization, is hereby
+ granted, provided that the above copyright notice and this paragraph appear 
+ in all copies. Distribution as a part of an application or binary must
+ include the above copyright notice in the documentation and/or other materials
+ provided with the application or distribution.
+
+
+   As the above disclaimer notes, you are free to use this code however you
+   want. However, I would request that you send me an email 
+   (fritz /at/ cs /dot/ ucsd /dot/ edu) to say hi if you find this code useful
+   or instructional. Seeing that people are using the code acts as 
+   encouragement for me to continue development. If you *really* want to thank
+   me you can buy the book I wrote with Thomas Powell, _JavaScript:
+   _The_Complete_Reference_ :)
+
+   This code is an UNOPTIMIZED REFERENCE implementation of Rijndael. 
+   If there is sufficient interest I can write an optimized (word-based, 
+   table-driven) version, although you might want to consider using a 
+   compiled language if speed is critical to your application. As it stands,
+   one run of the monte carlo test (10,000 encryptions) can take up to 
+   several minutes, depending upon your processor. You shouldn't expect more
+   than a few kilobytes per second in throughput.
+
+   Also note that there is very little error checking in these functions. 
+   Doing proper error checking is always a good idea, but the ideal 
+   implementation (using the instanceof operator and exceptions) requires
+   IE5+/NS6+, and I've chosen to implement this code so that it is compatible
+   with IE4/NS4. 
+
+   And finally, because JavaScript doesn't have an explicit byte/char data 
+   type (although JavaScript 2.0 most likely will), when I refer to "byte" 
+   in this code I generally mean "32 bit integer with value in the interval 
+   [0,255]" which I treat as a byte.
+
+   See http://www-cse.ucsd.edu/~fritz/rijndael.html for more documentation
+   of the (very simple) API provided by this code.
+
+                                               Fritz Schneider
+                                               fritz at cs.ucsd.edu
+ 
+*/
+
+// Rijndael parameters --  Valid values are 128, 192, or 256
+
+var keySizeInBits =   ( typeof AES_BITS == 'number' ) ? AES_BITS : 128;
+var blockSizeInBits = ( typeof AES_BLOCKSIZE == 'number' ) ? AES_BLOCKSIZE : 128;
+
+///////  You shouldn't have to modify anything below this line except for
+///////  the function getRandomBytes().
+//
+// Note: in the following code the two dimensional arrays are indexed as
+//       you would probably expect, as array[row][column]. The state arrays
+//       are 2d arrays of the form state[4][Nb].
+
+
+// The number of rounds for the cipher, indexed by [Nk][Nb]
+var roundsArray = [ ,,,,[,,,,10,, 12,, 14],, 
+                        [,,,,12,, 12,, 14],, 
+                        [,,,,14,, 14,, 14] ];
+
+// The number of bytes to shift by in shiftRow, indexed by [Nb][row]
+var shiftOffsets = [ ,,,,[,1, 2, 3],,[,1, 2, 3],,[,1, 3, 4] ];
+
+// The round constants used in subkey expansion
+var Rcon = [ 
+0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 
+0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 
+0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 
+0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 
+0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 ];
+
+// Precomputed lookup table for the SBox
+var SBox = [
+ 99, 124, 119, 123, 242, 107, 111, 197,  48,   1, 103,  43, 254, 215, 171, 
+118, 202, 130, 201, 125, 250,  89,  71, 240, 173, 212, 162, 175, 156, 164, 
+114, 192, 183, 253, 147,  38,  54,  63, 247, 204,  52, 165, 229, 241, 113, 
+216,  49,  21,   4, 199,  35, 195,  24, 150,   5, 154,   7,  18, 128, 226, 
+235,  39, 178, 117,   9, 131,  44,  26,  27, 110,  90, 160,  82,  59, 214, 
+179,  41, 227,  47, 132,  83, 209,   0, 237,  32, 252, 177,  91, 106, 203, 
+190,  57,  74,  76,  88, 207, 208, 239, 170, 251,  67,  77,  51, 133,  69, 
+249,   2, 127,  80,  60, 159, 168,  81, 163,  64, 143, 146, 157,  56, 245, 
+188, 182, 218,  33,  16, 255, 243, 210, 205,  12,  19, 236,  95, 151,  68,  
+23,  196, 167, 126,  61, 100,  93,  25, 115,  96, 129,  79, 220,  34,  42, 
+144, 136,  70, 238, 184,  20, 222,  94,  11, 219, 224,  50,  58,  10,  73,
+  6,  36,  92, 194, 211, 172,  98, 145, 149, 228, 121, 231, 200,  55, 109, 
+141, 213,  78, 169, 108,  86, 244, 234, 101, 122, 174,   8, 186, 120,  37,  
+ 46,  28, 166, 180, 198, 232, 221, 116,  31,  75, 189, 139, 138, 112,  62, 
+181, 102,  72,   3, 246,  14,  97,  53,  87, 185, 134, 193,  29, 158, 225,
+248, 152,  17, 105, 217, 142, 148, 155,  30, 135, 233, 206,  85,  40, 223,
+140, 161, 137,  13, 191, 230,  66, 104,  65, 153,  45,  15, 176,  84, 187,  
+ 22 ];
+
+// Precomputed lookup table for the inverse SBox
+var SBoxInverse = [
+ 82,   9, 106, 213,  48,  54, 165,  56, 191,  64, 163, 158, 129, 243, 215, 
+251, 124, 227,  57, 130, 155,  47, 255, 135,  52, 142,  67,  68, 196, 222, 
+233, 203,  84, 123, 148,  50, 166, 194,  35,  61, 238,  76, 149,  11,  66, 
+250, 195,  78,   8,  46, 161, 102,  40, 217,  36, 178, 118,  91, 162,  73, 
+109, 139, 209,  37, 114, 248, 246, 100, 134, 104, 152,  22, 212, 164,  92, 
+204,  93, 101, 182, 146, 108, 112,  72,  80, 253, 237, 185, 218,  94,  21,  
+ 70,  87, 167, 141, 157, 132, 144, 216, 171,   0, 140, 188, 211,  10, 247, 
+228,  88,   5, 184, 179,  69,   6, 208,  44,  30, 143, 202,  63,  15,   2, 
+193, 175, 189,   3,   1,  19, 138, 107,  58, 145,  17,  65,  79, 103, 220, 
+234, 151, 242, 207, 206, 240, 180, 230, 115, 150, 172, 116,  34, 231, 173,
+ 53, 133, 226, 249,  55, 232,  28, 117, 223, 110,  71, 241,  26, 113,  29, 
+ 41, 197, 137, 111, 183,  98,  14, 170,  24, 190,  27, 252,  86,  62,  75, 
+198, 210, 121,  32, 154, 219, 192, 254, 120, 205,  90, 244,  31, 221, 168,
+ 51, 136,   7, 199,  49, 177,  18,  16,  89,  39, 128, 236,  95,  96,  81,
+127, 169,  25, 181,  74,  13,  45, 229, 122, 159, 147, 201, 156, 239, 160,
+224,  59,  77, 174,  42, 245, 176, 200, 235, 187,  60, 131,  83, 153,  97, 
+ 23,  43,   4, 126, 186, 119, 214,  38, 225, 105,  20,  99,  85,  33,  12,
+125 ];
+
+function str_split(string, chunklen)
+{
+  if(!chunklen) chunklen = 1;
+  ret = new Array();
+  for ( i = 0; i < string.length; i+=chunklen )
+  {
+    ret[ret.length] = string.slice(i, i+chunklen);
+  }
+  return ret;
+}
+
+// This method circularly shifts the array left by the number of elements
+// given in its parameter. It returns the resulting array and is used for 
+// the ShiftRow step. Note that shift() and push() could be used for a more 
+// elegant solution, but they require IE5.5+, so I chose to do it manually. 
+
+function cyclicShiftLeft(theArray, positions) {
+  var temp = theArray.slice(0, positions);
+  theArray = theArray.slice(positions).concat(temp);
+  return theArray;
+}
+
+// Cipher parameters ... do not change these
+var Nk = keySizeInBits / 32;                   
+var Nb = blockSizeInBits / 32;
+var Nr = roundsArray[Nk][Nb];
+
+// Multiplies the element "poly" of GF(2^8) by x. See the Rijndael spec.
+
+function xtime(poly) {
+  poly <<= 1;
+  return ((poly & 0x100) ? (poly ^ 0x11B) : (poly));
+}
+
+// Multiplies the two elements of GF(2^8) together and returns the result.
+// See the Rijndael spec, but should be straightforward: for each power of
+// the indeterminant that has a 1 coefficient in x, add y times that power
+// to the result. x and y should be bytes representing elements of GF(2^8)
+
+function mult_GF256(x, y) {
+  var bit, result = 0;
+  
+  for (bit = 1; bit < 256; bit *= 2, y = xtime(y)) {
+    if (x & bit) 
+      result ^= y;
+  }
+  return result;
+}
+
+// Performs the substitution step of the cipher. State is the 2d array of
+// state information (see spec) and direction is string indicating whether
+// we are performing the forward substitution ("encrypt") or inverse 
+// substitution (anything else)
+
+function byteSub(state, direction) {
+  var S;
+  if (direction == "encrypt")           // Point S to the SBox we're using
+    S = SBox;
+  else
+    S = SBoxInverse;
+  for (var i = 0; i < 4; i++)           // Substitute for every byte in state
+    for (var j = 0; j < Nb; j++)
+       state[i][j] = S[state[i][j]];
+}
+
+// Performs the row shifting step of the cipher.
+
+function shiftRow(state, direction) {
+  for (var i=1; i<4; i++)               // Row 0 never shifts
+    if (direction == "encrypt")
+       state[i] = cyclicShiftLeft(state[i], shiftOffsets[Nb][i]);
+    else
+       state[i] = cyclicShiftLeft(state[i], Nb - shiftOffsets[Nb][i]);
+
+}
+
+// Performs the column mixing step of the cipher. Most of these steps can
+// be combined into table lookups on 32bit values (at least for encryption)
+// to greatly increase the speed. 
+
+function mixColumn(state, direction) {
+  var b = [];                            // Result of matrix multiplications
+  for (var j = 0; j < Nb; j++) {         // Go through each column...
+    for (var i = 0; i < 4; i++) {        // and for each row in the column...
+      if (direction == "encrypt")
+        b[i] = mult_GF256(state[i][j], 2) ^          // perform mixing
+               mult_GF256(state[(i+1)%4][j], 3) ^ 
+               state[(i+2)%4][j] ^ 
+               state[(i+3)%4][j];
+      else 
+        b[i] = mult_GF256(state[i][j], 0xE) ^ 
+               mult_GF256(state[(i+1)%4][j], 0xB) ^
+               mult_GF256(state[(i+2)%4][j], 0xD) ^
+               mult_GF256(state[(i+3)%4][j], 9);
+    }
+    for (var i = 0; i < 4; i++)          // Place result back into column
+      state[i][j] = b[i];
+  }
+}
+
+// Adds the current round key to the state information. Straightforward.
+
+function addRoundKey(state, roundKey) {
+  for (var j = 0; j < Nb; j++) {                 // Step through columns...
+    state[0][j] ^= (roundKey[j] & 0xFF);         // and XOR
+    state[1][j] ^= ((roundKey[j]>>8) & 0xFF);
+    state[2][j] ^= ((roundKey[j]>>16) & 0xFF);
+    state[3][j] ^= ((roundKey[j]>>24) & 0xFF);
+  }
+}
+
+// This function creates the expanded key from the input (128/192/256-bit)
+// key. The parameter key is an array of bytes holding the value of the key.
+// The returned value is an array whose elements are the 32-bit words that 
+// make up the expanded key.
+
+function keyExpansion(key) {
+  var expandedKey = new Array();
+  var temp;
+
+  // in case the key size or parameters were changed...
+  Nk = keySizeInBits / 32;                   
+  Nb = blockSizeInBits / 32;
+  Nr = roundsArray[Nk][Nb];
+
+  for (var j=0; j < Nk; j++)     // Fill in input key first
+    expandedKey[j] = 
+      (key[4*j]) | (key[4*j+1]<<8) | (key[4*j+2]<<16) | (key[4*j+3]<<24);
+
+  // Now walk down the rest of the array filling in expanded key bytes as
+  // per Rijndael's spec
+  for (j = Nk; j < Nb * (Nr + 1); j++) {    // For each word of expanded key
+    temp = expandedKey[j - 1];
+    if (j % Nk == 0) 
+      temp = ( (SBox[(temp>>8) & 0xFF]) |
+               (SBox[(temp>>16) & 0xFF]<<8) |
+               (SBox[(temp>>24) & 0xFF]<<16) |
+               (SBox[temp & 0xFF]<<24) ) ^ Rcon[Math.floor(j / Nk) - 1];
+    else if (Nk > 6 && j % Nk == 4)
+      temp = (SBox[(temp>>24) & 0xFF]<<24) |
+             (SBox[(temp>>16) & 0xFF]<<16) |
+             (SBox[(temp>>8) & 0xFF]<<8) |
+             (SBox[temp & 0xFF]);
+    expandedKey[j] = expandedKey[j-Nk] ^ temp;
+  }
+  return expandedKey;
+}
+
+// Rijndael's round functions... 
+
+function Round(state, roundKey) {
+  byteSub(state, "encrypt");
+  shiftRow(state, "encrypt");
+  mixColumn(state, "encrypt");
+  addRoundKey(state, roundKey);
+}
+
+function InverseRound(state, roundKey) {
+  addRoundKey(state, roundKey);
+  mixColumn(state, "decrypt");
+  shiftRow(state, "decrypt");
+  byteSub(state, "decrypt");
+}
+
+function FinalRound(state, roundKey) {
+  byteSub(state, "encrypt");
+  shiftRow(state, "encrypt");
+  addRoundKey(state, roundKey);
+}
+
+function InverseFinalRound(state, roundKey){
+  addRoundKey(state, roundKey);
+  shiftRow(state, "decrypt");
+  byteSub(state, "decrypt");  
+}
+
+// encrypt is the basic encryption function. It takes parameters
+// block, an array of bytes representing a plaintext block, and expandedKey,
+// an array of words representing the expanded key previously returned by
+// keyExpansion(). The ciphertext block is returned as an array of bytes.
+
+function encrypt(block, expandedKey) {
+  var i;  
+  if (!block || block.length*8 != blockSizeInBits)
+     return; 
+  if (!expandedKey)
+     return;
+
+  block = packBytes(block);
+  addRoundKey(block, expandedKey);
+  for (i=1; i<Nr; i++) 
+    Round(block, expandedKey.slice(Nb*i, Nb*(i+1)));
+  FinalRound(block, expandedKey.slice(Nb*Nr)); 
+  return unpackBytes(block);
+}
+
+// decrypt is the basic decryption function. It takes parameters
+// block, an array of bytes representing a ciphertext block, and expandedKey,
+// an array of words representing the expanded key previously returned by
+// keyExpansion(). The decrypted block is returned as an array of bytes.
+
+function decrypt(block, expandedKey) {
+  var i;
+  if (!block || block.length*8 != blockSizeInBits)
+     return;
+  if (!expandedKey)
+     return;
+
+  block = packBytes(block);
+  InverseFinalRound(block, expandedKey.slice(Nb*Nr)); 
+  for (i = Nr - 1; i>0; i--) 
+    InverseRound(block, expandedKey.slice(Nb*i, Nb*(i+1)));
+  addRoundKey(block, expandedKey);
+  return unpackBytes(block);
+}
+
+// This method takes a byte array (byteArray) and converts it to a string by
+// applying String.fromCharCode() to each value and concatenating the result.
+// The resulting string is returned. Note that this function SKIPS zero bytes
+// under the assumption that they are padding added in formatPlaintext().
+// Obviously, do not invoke this method on raw data that can contain zero
+// bytes. It is really only appropriate for printable ASCII/Latin-1 
+// values. Roll your own function for more robust functionality :)
+
+function byteArrayToString(byteArray) {
+  var result = "";
+  for(var i=0; i<byteArray.length; i++)
+    if (byteArray[i] != 0) 
+      result += String.fromCharCode(byteArray[i]);
+  return result;
+}
+
+// This function takes an array of bytes (byteArray) and converts them
+// to a hexadecimal string. Array element 0 is found at the beginning of 
+// the resulting string, high nibble first. Consecutive elements follow
+// similarly, for example [16, 255] --> "10ff". The function returns a 
+// string.
+
+function byteArrayToHex(byteArray) {
+  var result = "";
+  if (!byteArray)
+    return;
+  for (var i=0; i<byteArray.length; i++)
+    result += ((byteArray[i]<16) ? "0" : "") + byteArray[i].toString(16);
+
+  return result;
+}
+
+// This function converts a string containing hexadecimal digits to an 
+// array of bytes. The resulting byte array is filled in the order the
+// values occur in the string, for example "10FF" --> [16, 255]. This
+// function returns an array. 
+
+function hexToByteArray(hexString) {
+  /*
+  var byteArray = [];
+  if (hexString.length % 2)             // must have even length
+    return;
+  if (hexString.indexOf("0x") == 0 || hexString.indexOf("0X") == 0)
+    hexString = hexString.substring(2);
+  for (var i = 0; i<hexString.length; i += 2) 
+    byteArray[Math.floor(i/2)] = parseInt(hexString.slice(i, i+2), 16);
+  return byteArray;
+  */
+  var bytes = new Array();
+  hexString = str_split(hexString, 2);
+  //alert(hexString.toString());
+  //return false;
+  for( var i in hexString )
+  {
+    bytes[bytes.length] = parseInt(hexString[i], 16);
+  }
+  //alert(bytes.toString());
+  return bytes;
+}
+
+// This function packs an array of bytes into the four row form defined by
+// Rijndael. It assumes the length of the array of bytes is divisible by
+// four. Bytes are filled in according to the Rijndael spec (starting with
+// column 0, row 0 to 3). This function returns a 2d array.
+
+function packBytes(octets) {
+  var state = new Array();
+  if (!octets || octets.length % 4)
+    return;
+
+  state[0] = new Array();  state[1] = new Array(); 
+  state[2] = new Array();  state[3] = new Array();
+  for (var j=0; j<octets.length; j+= 4) {
+     state[0][j/4] = octets[j];
+     state[1][j/4] = octets[j+1];
+     state[2][j/4] = octets[j+2];
+     state[3][j/4] = octets[j+3];
+  }
+  return state;  
+}
+
+// This function unpacks an array of bytes from the four row format preferred
+// by Rijndael into a single 1d array of bytes. It assumes the input "packed"
+// is a packed array. Bytes are filled in according to the Rijndael spec. 
+// This function returns a 1d array of bytes.
+
+function unpackBytes(packed) {
+  var result = new Array();
+  for (var j=0; j<packed[0].length; j++) {
+    result[result.length] = packed[0][j];
+    result[result.length] = packed[1][j];
+    result[result.length] = packed[2][j];
+    result[result.length] = packed[3][j];
+  }
+  return result;
+}
+
+// This function takes a prospective plaintext (string or array of bytes)
+// and pads it with zero bytes if its length is not a multiple of the block 
+// size. If plaintext is a string, it is converted to an array of bytes
+// in the process. The type checking can be made much nicer using the 
+// instanceof operator, but this operator is not available until IE5.0 so I 
+// chose to use the heuristic below. 
+
+function formatPlaintext(plaintext) {
+  var bpb = blockSizeInBits / 8;               // bytes per block
+  var i;
+
+  // if primitive string or String instance
+  if (typeof plaintext == "string" || plaintext.split) {
+    // alert('AUUGH you idiot it\'s NOT A STRING ITS A '+typeof(plaintext)+'!!!');
+    // return false;
+    plaintext = plaintext.split("");
+    // Unicode issues here (ignoring high byte)
+    for (i=0; i<plaintext.length; i++)
+      plaintext[i] = plaintext[i].charCodeAt(0) & 0xFF;
+  } 
+
+  for (i = bpb - (plaintext.length % bpb); i > 0 && i < bpb; i--) 
+    plaintext[plaintext.length] = 0;
+  
+  return plaintext;
+}
+
+// Returns an array containing "howMany" random bytes. YOU SHOULD CHANGE THIS
+// TO RETURN HIGHER QUALITY RANDOM BYTES IF YOU ARE USING THIS FOR A "REAL"
+// APPLICATION.
+
+function getRandomBytes(howMany) {
+  var i;
+  var bytes = new Array();
+  for (i=0; i<howMany; i++)
+    bytes[i] = Math.round(Math.random()*255);
+  return bytes;
+}
+
+// rijndaelEncrypt(plaintext, key, mode)
+// Encrypts the plaintext using the given key and in the given mode. 
+// The parameter "plaintext" can either be a string or an array of bytes. 
+// The parameter "key" must be an array of key bytes. If you have a hex 
+// string representing the key, invoke hexToByteArray() on it to convert it 
+// to an array of bytes. The third parameter "mode" is a string indicating
+// the encryption mode to use, either "ECB" or "CBC". If the parameter is
+// omitted, ECB is assumed.
+// 
+// An array of bytes representing the cihpertext is returned. To convert 
+// this array to hex, invoke byteArrayToHex() on it. If you are using this 
+// "for real" it is a good idea to change the function getRandomBytes() to 
+// something that returns truly random bits.
+
+function rijndaelEncrypt(plaintext, key, mode) {
+  var expandedKey, i, aBlock;
+  var bpb = blockSizeInBits / 8;          // bytes per block
+  var ct;                                 // ciphertext
+
+  if (typeof plaintext != 'object' || typeof key != 'object')
+  {
+    alert( 'Invalid params\nplaintext: '+typeof(plaintext)+'\nkey: '+typeof(key) );
+    return false;
+  }
+  if (key.length*8 == keySizeInBits+8)
+    key.length = keySizeInBits / 8;
+  if (key.length*8 != keySizeInBits)
+  {
+    alert( 'Key length is bad!\nLength: '+key.length+'\nExpected: '+keySizeInBits / 8 );
+    return false;
+  }
+  if (mode == "CBC")
+    ct = getRandomBytes(bpb);             // get IV
+  else {
+    mode = "ECB";
+    ct = new Array();
+  }
+
+  // convert plaintext to byte array and pad with zeros if necessary. 
+  plaintext = formatPlaintext(plaintext);
+
+  expandedKey = keyExpansion(key);
+  
+  for (var block=0; block<plaintext.length / bpb; block++) {
+    aBlock = plaintext.slice(block*bpb, (block+1)*bpb);
+    if (mode == "CBC")
+      for (var i=0; i<bpb; i++) 
+        aBlock[i] ^= ct[block*bpb + i];
+    ct = ct.concat(encrypt(aBlock, expandedKey));
+  }
+
+  return ct;
+}
+
+// rijndaelDecrypt(ciphertext, key, mode)
+// Decrypts the using the given key and mode. The parameter "ciphertext" 
+// must be an array of bytes. The parameter "key" must be an array of key 
+// bytes. If you have a hex string representing the ciphertext or key, 
+// invoke hexToByteArray() on it to convert it to an array of bytes. The
+// parameter "mode" is a string, either "CBC" or "ECB".
+// 
+// An array of bytes representing the plaintext is returned. To convert 
+// this array to a hex string, invoke byteArrayToHex() on it. To convert it 
+// to a string of characters, you can use byteArrayToString().
+
+function rijndaelDecrypt(ciphertext, key, mode) {
+  var expandedKey;
+  var bpb = blockSizeInBits / 8;          // bytes per block
+  var pt = new Array();                   // plaintext array
+  var aBlock;                             // a decrypted block
+  var block;                              // current block number
+
+  if (!ciphertext || !key || typeof ciphertext == "string")
+    return;
+  if (key.length*8 != keySizeInBits)
+    return; 
+  if (!mode)
+    mode = "ECB";                         // assume ECB if mode omitted
+
+  expandedKey = keyExpansion(key);
+ 
+  // work backwards to accomodate CBC mode 
+  for (block=(ciphertext.length / bpb)-1; block>0; block--) {
+    aBlock = 
+     decrypt(ciphertext.slice(block*bpb,(block+1)*bpb), expandedKey);
+    if (mode == "CBC") 
+      for (var i=0; i<bpb; i++) 
+        pt[(block-1)*bpb + i] = aBlock[i] ^ ciphertext[(block-1)*bpb + i];
+    else 
+      pt = aBlock.concat(pt);
+  }
+
+  // do last block if ECB (skips the IV in CBC)
+  if (mode == "ECB")
+    pt = decrypt(ciphertext.slice(0, bpb), expandedKey).concat(pt);
+
+  return pt;
+}
+
+function stringToByteArray(text)
+{
+  result = new Array();
+  for ( i=0; i<text.length; i++ )
+  {
+    result[result.length] = text.charCodeAt(i);
+  }
+  return result;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/static/sliders.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,210 @@
+// Sliding drawers on the sidebar
+
+// our global vars
+// the delay between the slide in/out, and a little inertia
+
+var sliders_initted = false;
+      
+function initSliders()
+{
+  sliders_initted = true;
+    // detect whether the user has ie or not, how we get the height is different 
+    var useragent = navigator.userAgent.toLowerCase();
+    var ie = ((useragent.indexOf('msie') != -1) && (useragent.indexOf('opera') == -1) && (useragent.indexOf('webtv') == -1));
+    
+    if(ie)
+      return;
+    
+    var divs = getElementsByClassName(document, "div", "slideblock");
+    
+    for(var i=0; i<divs.length; i++)
+    {
+        // set a unique id for this slider
+        divs[i].metaid = i;
+        
+        // get the original height
+        var baseheight = (ie) ? divs[i].offsetHeight + "px" : document.defaultView.getComputedStyle(divs[i], null).getPropertyValue('height', null);
+
+        // use cookies to toggle whether to display it or not
+        var id = ( divs[i].parentNode.firstChild.nextSibling ) ? divs[i].parentNode.firstChild.nextSibling.firstChild : divs[i].parentNode.parentNode.firstChild.nextSibling.firstChild;
+        
+        if(id.innerHTML || id.nextSibling.length < 1) id = id.innerHTML;
+        else id = id.nextSibling.innerHTML; // Gecko fix
+        
+        var cookieName = 'mdgSliderState_'+i; // id.replace(' ', '_');
+        //alert(cookieName + ': ' + readCookie(cookieName));
+        if(readCookie(cookieName)=='closed')
+        {
+          divs[i].style.display = "none";
+        }
+        else
+        {
+          divs[i].style.display = "block";
+        }
+
+        // "save" our div height, because once it's display is set to none we can't get the original height again
+        var d = new div();
+        d.el = divs[i];
+        d.ht = baseheight.substring(0, baseheight.indexOf("p"));
+
+        // store our saved version
+        divheights[i] = d;        
+    }
+}
+
+// this is one of our divs, it just has a DOM reference to the element and the original height
+function div(_el, _ht)
+{
+    this.el = _el;
+    this.ht = _ht;
+}
+
+function toggle(t)
+{
+  if(IE)
+    return false;
+  if ( !sliders_initted )
+    initSliders();
+    // reset our inertia base and interval
+    inertiabase = inertiabaseoriginal;
+    clearInterval(slideinterval);
+
+    // get our block
+    block = t.parentNode.nextSibling;
+
+    // for mozilla, it doesn't like whitespace between elements
+    if(block.className == undefined)
+        block = t.parentNode.nextSibling.nextSibling;
+      
+    if(block.style.display == "none")
+    {
+        block.style.display = "block";
+        block.style.height = "1px";
+
+        // our goal and current height
+        targetheight = divheight(block);
+        heightnow = 1;
+        
+        // remember toggled state
+        cookieName = 'mdgSliderState_'+block.metaid; // t.innerHTML.replace(' ', '_');
+        createCookie(cookieName, 'open', 3650);
+
+        // our interval
+        slideinterval = setInterval(slideout, slideintervalinc);
+    }
+    else
+    {
+        // our goal and current height
+        targetheight = 1;
+        heightnow = divheight(block);
+        
+        // remember toggled state
+        cookieName = 'mdgSliderState_'+block.metaid; // t.innerHTML.replace(' ', '_');
+        createCookie(cookieName, 'closed', 3650);
+
+        // our interval
+        slideinterval = setInterval(slidein, slideintervalinc);
+    }
+}
+
+// this is our slidein function the interval uses, it keeps subtracting
+// from the height till it's 1px then it hides it
+function slidein()
+{
+    if(heightnow > targetheight)
+    {
+        // reduce the height by intertiabase * inertiainc
+        heightnow -= inertiabase;
+
+        // increase the intertiabase by the amount to keep it changing
+        inertiabase += inertiainc;
+
+        // it's possible to exceed the height we want so we use a ternary - (condition) ? when true : when false;
+        block.style.height = (heightnow > 1) ? heightnow + "px" : targetheight + "px";
+    }
+    else
+    {
+        // finished, so hide the div properly and kill the interval
+        clearInterval(slideinterval);
+        block.style.display = "none";
+    }
+}
+
+// this is the function our slideout interval uses, it keeps adding
+// to the height till it's fully displayed
+function slideout()
+{
+    block.style.display = 'block';
+    if(heightnow < targetheight)
+    {
+        // increases the height by the inertia stuff
+        heightnow += inertiabase;
+
+        // increase the inertia stuff
+        inertiabase += inertiainc;
+
+        // it's possible to exceed the height we want so we use a ternary - (condition) ? when true : when false;
+        block.style.height = (heightnow < targetheight) ? heightnow + "px" : targetheight + "px";
+        
+    }
+    else
+    {
+        // finished, so make sure the height is what it's meant to be (inertia can make it off a little)
+        // then kill the interval
+        clearInterval(slideinterval);
+        block.style.height = targetheight + "px";
+    }
+}
+
+// returns the height of the div from our array of such things
+function divheight(d)
+{
+    for(var i=0; i<divheights.length; i++)
+    {
+        if(divheights[i].el == d)
+        {
+            return divheights[i].ht;
+        }
+    }
+}
+
+/*
+    the getElementsByClassName function I pilfered from this guy.  It's
+    a useful function that'll return any/all tags with a specific css class.
+
+    Written by Jonathan Snook, http://www.snook.ca/jonathan
+    Add-ons by Robert Nyman, http://www.robertnyman.com
+    
+    Modified to match all elements that match the class name plus an integer after the name
+    This is used in Enano to allow sliding sidebar widgets that use their own CSS
+*/
+function getElementsByClassName(oElm, strTagName, strClassName)
+{
+    // first it gets all of the specified tags
+    var arrElements = (strTagName == "*" && document.all) ? document.all : oElm.getElementsByTagName(strTagName);
+    
+    // then it sets up an array that'll hold the results
+    var arrReturnElements = new Array();
+
+    // some regex stuff you don't need to worry about
+    strClassName = strClassName.replace(/\-/g, "\\-");
+
+    var oRegExp = new RegExp("(^|\\s)" + strClassName + "([0-9]*)(\\s|$)");
+    var oElement;
+    
+    // now it iterates through the elements it grabbed above
+    for(var i=0; i<arrElements.length; i++)
+    {
+        oElement = arrElements[i];
+
+        // if the class matches what we're looking for it ads to the results array
+        if(oElement.className.match(oRegExp))
+        {
+            arrReturnElements.push(oElement);
+        }
+    }
+
+    // then it kicks the results back to us
+    return (arrReturnElements)
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/static/template-compiler.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,78 @@
+// An implementation of Enano's template compiler in Javascript. Same exact API
+// as the PHP version - constructor accepts text, then the assign_vars, assign_bool, and run methods.
+
+function templateParser(text)
+{
+  this.tpl_code    = text;
+  this.tpl_strings = new Object();
+  this.tpl_bool    = new Object();
+  this.assign_vars = __tpAssignVars;
+  this.assign_bool = __tpAssignBool;
+  this.run         = __tpRun;
+}
+
+function __tpAssignVars(vars)
+{
+  for(var i in vars)
+  {
+    this.tpl_strings[i] = vars[i];
+  }
+}
+
+function __tpAssignBool(vars)
+{
+  for(var i in vars)
+  {
+    this.tpl_bool[i] = ( vars[i] ) ? true : false; 
+  }
+}
+
+function __tpRun()
+{
+  if(typeof(this.tpl_code) == 'string')
+  {
+    tpl_code = __tpCompileTemplate(this.tpl_code);
+    try {
+      compiled = eval(tpl_code);
+    }
+    catch(e)
+    {
+      alert(e);
+      aclDebug(tpl_code);
+    }
+    return compiled;
+  }
+  return false;
+}
+
+function __tpCompileTemplate(code)
+{
+  // Compile plaintext/template code to javascript code
+  code = code.replace(/\\/g, "\\\\");
+  code = code.replace(/\'/g,  "\\'");
+  code = code.replace(/\"/g,  '\\"');
+  code = code.replace(new RegExp(unescape('%0A'), 'g'), '\\n');
+  code = "'" + code + "'";
+  code = code.replace(/\{([A-z0-9_-]+)\}/ig, "' + this.tpl_strings['$1'] + '");
+  code = code.replace(/\<!-- BEGIN ([A-z0-9_-]+) --\>([\s\S]*?)\<!-- BEGINELSE \1 --\>([\s\S]*?)\<!-- END \1 --\>/ig, "' + ( ( this.tpl_bool['$1'] == true ) ? '$2' : '$3' ) + '");
+  code = code.replace(/\<!-- BEGIN ([A-z0-9_-]+) --\>([\s\S]*?)\<!-- END \1 --\>/ig, "' + ( ( this.tpl_bool['$1'] == true ) ? '$2' : '' ) + '");
+  return code;
+}
+
+function __tpExtractVars(code)
+{
+  code = code.replace('\\', "\\\\");
+  code = code.replace("'",  "\\'");
+  code = code.replace('"',  '\\"');
+  code = code.replace(new RegExp(unescape('%0A'), 'g'), "\\n");
+  code = code.match(/\<!-- VAR ([A-z0-9_-]+) --\>([\s\S]*?)\<!-- ENDVAR \1 -->/g);
+  code2 = '';
+  for(var i in code)
+    if(typeof(code[i]) == 'string')
+      code2 = code2 + code[i];
+  code = code2.replace(/\<!-- VAR ([A-z0-9_-]+) --\>([\s\S]*?)\<!-- ENDVAR \1 -->/g, "'$1' : \"$2\",");
+  code = '( { ' + code + ' "________null________" : false } )';
+  vars = eval(code);
+  return vars;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/static/toolbar.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,60 @@
+// Page toolbar - selecting buttons
+
+function unselectAllButtonsMajor()
+{
+  if ( !document.getElementById('pagebar_main') )
+    return false;
+  obj = document.getElementById('pagebar_main').firstChild;
+  while(obj)
+  {
+    if(obj.id == 'mdgToolbar_article' || obj.id == 'mdgToolbar_discussion')
+    {
+      obj.className = '';
+    }
+    obj = obj.nextSibling;
+  }
+}
+
+function unselectAllButtonsMinor()
+{
+  if ( !document.getElementById('pagebar_main') )
+    return false;
+  obj = document.getElementById('pagebar_main').firstChild.nextSibling;
+  while(obj)
+  {
+    if ( obj.className != 'selected' )
+    {
+      obj = obj.nextSibling;
+      continue;
+    }
+    if(obj.id != 'mdgToolbar_article' && obj.id != 'mdgToolbar_discussion')
+    {
+      if ( obj.className )
+        obj.className = '';
+    }
+    obj = obj.nextSibling;
+  }
+}
+
+function selectButtonMajor(which)
+{
+  if ( !document.getElementById('pagebar_main') )
+    return false;
+  if(typeof(document.getElementById('mdgToolbar_'+which)) == 'object')
+  {
+    unselectAllButtonsMajor();
+    document.getElementById('mdgToolbar_'+which).className = 'selected';
+  }
+}
+
+function selectButtonMinor(which)
+{
+  if ( !document.getElementById('pagebar_main') )
+    return false;
+  if(typeof(document.getElementById('mdgToolbar_'+which)) == 'object')
+  {
+    unselectAllButtonsMinor();
+    document.getElementById('mdgToolbar_'+which).className = 'selected';
+  }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/static/windows.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,342 @@
+/*
+ * Enano JWS - Javascript Windowing System
+ * Sorry if I stole the name ;)
+ * Copyright (C) 2006-2007 Dan Fuhry
+ * Yes, it's part of Enano, so it's GPL
+ */
+
+  var position;
+  function getScrollOffset()
+  {
+    var position;
+    if (self.pageYOffset)
+    {
+      position = self.pageYOffset;
+    }
+    else if (document.documentElement && document.documentElement.scrollTop)
+    {
+      position = document.documentElement.scrollTop;
+    }
+    else if (document.body)
+    {
+      position = document.body.scrollTop;
+    }
+    return position;
+  }
+  position = getScrollOffset();
+  
+  var jws = {
+    position : position,
+    obj : null,
+    startup : function() {
+      jws.debug('jws.startup()');
+      var divs = document.getElementsByTagName('div');
+      if(IE) { position = document.body.scrollTop; }
+      else   { position = window.pageYOffset; }
+      for(i=0;i<divs.length;i++) {
+        if(divs[i].id && divs[i].id.substr(0, 4) == 'root') {
+          divs[i].onClick = 'jws.focus(\''+divs[i].id+'\')';
+          var tb = i + 1
+          tb = divs[tb];
+          tb.innerHTML = '<table border="0" width="100%"><tr><td>' + tb.innerHTML + '</td><td align="right"><div align="center" class="closebtn" onclick="jws.closeWin(\''+divs[i].id+'\');">X</div></td></tr></table>';
+          divs[i].style.width = '640px';
+          divs[i].style.height = '480px';
+          Drag.init(tb, divs[i]);
+        }
+      }
+    },
+    initWindow : function(o) {
+      jws.debug('jws.initWindow('+o+' ['+o.id+'])');
+      var divs = document.getElementsByTagName('div');
+      for(i=0;i<divs.length;i++) {
+        if(divs[i].id && divs[i].id == o.id) {
+          var tb = i + 1
+          tb = divs[tb];
+          tb.innerHTML = '<table border="0" width="100%"><tr><td>' + tb.innerHTML + '</td><td align="right"><div class="closebtn" onclick="jws.closeWin(\''+divs[i].id+'\');"></div></td></tr></table>';
+          divs[i].style.width = '640px';
+          divs[i].style.height = '480px';
+          Drag.init(tb, divs[i]);
+        }
+      }
+    },
+    closeWin : function(id) {
+      jws.debug('jws.closeWin(\''+id+'\')');
+      document.getElementById(id).style.display = 'none';
+      enlighten();
+    },
+    openWin : function(id, x, y) {
+      darken();
+      var e = document.getElementById(id);
+      if(!x) x = 640;
+      if(!y) y = 480;
+      jws.debug('jws.openWin(\''+id+'\', '+x+', '+y+')');
+      e.style.display = 'block';
+      e.style.width   = x+'px';
+      e.style.height  = y+'px';
+      
+      var divs = document.getElementsByTagName('div');
+      for(i=0;i<divs.length;i++) {
+        if(divs[i].id && divs[i].id == e.id) {
+          var cn = i + 3;
+          cn = divs[cn];
+          
+          var h = getElementHeight(e.id) - 53;
+          var w = getElementWidth(cn.id) - 20;
+          cn.style.width   =  w + 'px';
+          cn.style.height  =  h + 'px';
+          cn.style.clip.top = 0 + 'px';
+          cn.style.clip.left = 0 + 'px';
+          cn.style.clip.right =  w + 'px';
+          cn.style.clip.bottom = h + 'px';
+          cn.style.overflow = 'auto';
+        }
+      }
+      jws.setpos(id);
+      jws.focus(id);
+    },
+    setpos : function(el) {
+      jws.debug('jws.setpos(\''+el+'\')');
+      el = document.getElementById(el);
+      var w = getWidth();
+      var h = getHeight();
+      var ew = getElementWidth(el.id);
+      var eh = getElementHeight(el.id);
+      px = (w/2) - (ew/2);
+      py = (h/2) - (eh/2);
+      if (IE) { position = document.body.scrollTop; }
+      else    { position = window.pageYOffset; }
+      py=py+0;
+      if ( IE )
+        el.style.position = "absolute";
+      else
+        el.style.position = "fixed";
+      el.style.left=px+'px';
+      el.style.top =py+'px';
+    },
+    scrollHandler : function() {
+      var divs = document.getElementsByTagName('div');
+      for(i=0;i<divs.length;i++) {
+        if(divs[i].id && divs[i].id.substr(0, 4) == 'root' && divs[i].style.display == 'block') {
+          c = divs[i];
+          jws.debug('jws.scrollHandler(): moving element: '+c.id);
+          var t = c.style.top;
+          var py = t.substr(0, t.length - 2);
+          py = parseInt(py);
+          if(jws.position) { py = py - jws.position; }
+          position = getScrollOffset();
+          py=py+position;                                                           
+          c.style.position = "absolute";
+          if(!isNaN(py)) c.style.top =py+'px';
+          jws.debug('jws.scrollHandler(): value of py: '+py);
+        }
+      }
+      jws.position = position;
+    },
+    focus : function(e) {
+      e = document.getElementById(e);
+      if(e.style.zindex) z = e.style.zindex;
+      else z = 1;
+      z=z+5;
+      e.style.zIndex = z;
+    },
+    debug : function(t) {
+      if(document.getElementById('jsw-debug-console')) {
+        dbg = document.getElementById('jsw-debug-console');
+        debugdata = dbg.innerHTML;
+        dbg.innerHTML = debugdata+"<br />"+t;
+      }
+    }
+  } // class jws
+
+//window.onscroll=jws['scrollHandler'];
+
+/*
+ * Utility functions
+ */
+ 
+// getElementWidth() and getElementHeight()
+// Source: http://www.aspandjavascript.co.uk/javascript/javascript_api/get_element_width_height.asp
+
+function getElementHeight(Elem) {
+  if (ns4) {
+    var elem = getObjNN4(document, Elem);
+    return elem.clip.height;
+  } else {
+    if(document.getElementById) {
+      var elem = document.getElementById(Elem);
+    } else if (document.all){
+      var elem = document.all[Elem];
+    }
+    if (op5) { 
+      xPos = elem.style.pixelHeight;
+    } else {
+      xPos = elem.offsetHeight;
+    }
+    return xPos;
+  } 
+}
+
+function getElementWidth(Elem) {
+  if (ns4) {
+    var elem = getObjNN4(document, Elem);
+    return elem.clip.width;
+  } else {
+    if(document.getElementById) {
+      var elem = document.getElementById(Elem);
+    } else if (document.all){
+      var elem = document.all[Elem];
+    }
+    if (op5) {
+      xPos = elem.style.pixelWidth;
+    } else {
+      xPos = elem.offsetWidth;
+    }
+    return xPos;
+  }
+}
+
+function getHeight() {
+  var myHeight = 0;
+  if( typeof( window.innerWidth ) == 'number' ) {
+    myHeight = window.innerHeight;
+  } else if( document.documentElement &&
+      ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {
+    myHeight = document.documentElement.clientHeight;
+  } else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
+    myHeight = document.body.clientHeight;
+  }
+  return myHeight;
+}           
+
+function getWidth() {
+  var myWidth = 0;
+  if( typeof( window.innerWidth ) == 'number' ) {
+    myWidth = window.innerWidth;
+  } else if( document.documentElement &&
+      ( document.documentElement.clientWidth || document.documentElement.clientWidth ) ) {
+    myWidth = document.documentElement.clientWidth;
+  } else if( document.body && ( document.body.clientWidth || document.body.clientWidth ) ) {
+    myWidth = document.body.clientWidth;
+  }
+  return myWidth;
+}
+
+/**************************************************
+ * dom-drag.js
+ * 09.25.2001
+ * www.youngpup.net
+ **************************************************/
+
+var Drag = {
+
+  obj : null,
+
+  init : function(o, oRoot, minX, maxX, minY, maxY, bSwapHorzRef, bSwapVertRef, fXMapper, fYMapper)
+  {
+    o.onmousedown	= Drag.start;
+
+    o.hmode			= bSwapHorzRef ? false : true ;
+    o.vmode			= bSwapVertRef ? false : true ;
+
+    o.root = oRoot && oRoot != null ? oRoot : o ;
+
+    if (o.hmode  && isNaN(parseInt(o.root.style.left  ))) o.root.style.left   = "0px";
+    if (o.vmode  && isNaN(parseInt(o.root.style.top   ))) o.root.style.top    = "0px";
+    if (!o.hmode && isNaN(parseInt(o.root.style.right ))) o.root.style.right  = "0px";
+    if (!o.vmode && isNaN(parseInt(o.root.style.bottom))) o.root.style.bottom = "0px";
+
+    o.minX	= typeof minX != 'undefined' ? minX : null;
+    o.minY	= typeof minY != 'undefined' ? minY : null;
+    o.maxX	= typeof maxX != 'undefined' ? maxX : null;
+    o.maxY	= typeof maxY != 'undefined' ? maxY : null;
+
+    o.xMapper = fXMapper ? fXMapper : null;
+    o.yMapper = fYMapper ? fYMapper : null;
+
+    o.root.onDragStart	= new Function();
+    o.root.onDragEnd	= new Function();
+    o.root.onDrag		= new Function();
+  },
+
+  start : function(e)
+  {
+    var o = Drag.obj = this;
+    e = Drag.fixE(e);
+    var y = parseInt(o.vmode ? o.root.style.top  : o.root.style.bottom);
+    var x = parseInt(o.hmode ? o.root.style.left : o.root.style.right );
+    o.root.onDragStart(x, y);
+
+    o.lastMouseX	= e.clientX;
+    o.lastMouseY	= e.clientY;
+
+    if (o.hmode) {
+      if (o.minX != null)	o.minMouseX	= e.clientX - x + o.minX;
+      if (o.maxX != null)	o.maxMouseX	= o.minMouseX + o.maxX - o.minX;
+    } else {
+      if (o.minX != null) o.maxMouseX = -o.minX + e.clientX + x;
+      if (o.maxX != null) o.minMouseX = -o.maxX + e.clientX + x;
+    }
+
+    if (o.vmode) {
+      if (o.minY != null)	o.minMouseY	= e.clientY - y + o.minY;
+      if (o.maxY != null)	o.maxMouseY	= o.minMouseY + o.maxY - o.minY;
+    } else {
+      if (o.minY != null) o.maxMouseY = -o.minY + e.clientY + y;
+      if (o.maxY != null) o.minMouseY = -o.maxY + e.clientY + y;
+    }
+
+    document.onmousemove	= Drag.drag;
+    document.onmouseup		= Drag.end;
+
+    return false;
+  },
+
+  drag : function(e)
+  {
+    e = Drag.fixE(e);
+    var o = Drag.obj;
+
+    var ey	= e.clientY;
+    var ex	= e.clientX;
+    var y = parseInt(o.vmode ? o.root.style.top  : o.root.style.bottom);
+    var x = parseInt(o.hmode ? o.root.style.left : o.root.style.right );
+    var nx, ny;
+
+    if (o.minX != null) ex = o.hmode ? Math.max(ex, o.minMouseX) : Math.min(ex, o.maxMouseX);
+    if (o.maxX != null) ex = o.hmode ? Math.min(ex, o.maxMouseX) : Math.max(ex, o.minMouseX);
+    if (o.minY != null) ey = o.vmode ? Math.max(ey, o.minMouseY) : Math.min(ey, o.maxMouseY);
+    if (o.maxY != null) ey = o.vmode ? Math.min(ey, o.maxMouseY) : Math.max(ey, o.minMouseY);
+
+    nx = x + ((ex - o.lastMouseX) * (o.hmode ? 1 : -1));
+    ny = y + ((ey - o.lastMouseY) * (o.vmode ? 1 : -1));
+
+    if (o.xMapper)		nx = o.xMapper(y)
+    else if (o.yMapper)	ny = o.yMapper(x)
+
+    Drag.obj.root.style[o.hmode ? "left" : "right"] = nx + "px";
+    Drag.obj.root.style[o.vmode ? "top" : "bottom"] = ny + "px";
+    Drag.obj.lastMouseX	= ex;
+    Drag.obj.lastMouseY	= ey;
+
+    Drag.obj.root.onDrag(nx, ny);
+    return false;
+  },
+
+  end : function()
+  {
+    document.onmousemove = getMouseXY;
+    document.onmouseup   = null;
+    Drag.obj.root.onDragEnd(	parseInt(Drag.obj.root.style[Drag.obj.hmode ? "left" : "right"]), 
+                  parseInt(Drag.obj.root.style[Drag.obj.vmode ? "top" : "bottom"]));
+    Drag.obj = null;
+  },
+
+  fixE : function(e)
+  {
+    if (typeof e == 'undefined') e = window.event;
+    if (typeof e.layerX == 'undefined') e.layerX = e.offsetX;
+    if (typeof e.layerY == 'undefined') e.layerY = e.offsetY;
+    return e;
+  }
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/blank.htm	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,9 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>blank_page</title>
+	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+</head>
+<body class="mceContentBody">
+
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/langs/en.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,41 @@
+// UK lang variables
+
+tinyMCE.addToLang('',{
+bold_desc : 'Bold (Ctrl+B)',
+italic_desc : 'Italic (Ctrl+I)',
+underline_desc : 'Underline (Ctrl+U)',
+striketrough_desc : 'Strikethrough',
+justifyleft_desc : 'Align left',
+justifycenter_desc : 'Align center',
+justifyright_desc : 'Align right',
+justifyfull_desc : 'Align full',
+bullist_desc : 'Unordered list',
+numlist_desc : 'Ordered list',
+outdent_desc : 'Outdent',
+indent_desc : 'Indent',
+undo_desc : 'Undo (Ctrl+Z)',
+redo_desc : 'Redo (Ctrl+Y)',
+link_desc : 'Insert/edit link',
+unlink_desc : 'Unlink',
+image_desc : 'Insert/edit image',
+cleanup_desc : 'Cleanup messy code',
+focus_alert : 'A editor instance must be focused before using this command.',
+edit_confirm : 'Do you want to use the WYSIWYG mode for this textarea?',
+insert_link_title : 'Insert/edit link',
+insert : 'Insert',
+update : 'Update',
+cancel : 'Cancel',
+insert_link_url : 'Link URL',
+insert_link_target : 'Target',
+insert_link_target_same : 'Open link in the same window',
+insert_link_target_blank : 'Open link in a new window',
+insert_image_title : 'Insert/edit image',
+insert_image_src : 'Image URL',
+insert_image_alt : 'Image description',
+help_desc : 'Help',
+bold_img : "bold.gif",
+italic_img : "italic.gif",
+underline_img : "underline.gif",
+clipboard_msg : 'Copy/Cut/Paste is not available in Mozilla and Firefox.\nDo you want more information about this issue?',
+popup_blocked : 'Sorry, but we have noticed that your popup-blocker has disabled a window that provides application functionality. You will need to disable popup blocking on this site in order to fully utilize this tool.'
+});
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/langs/readme.txt	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,9 @@
+Beginning with version 2.0.5 the language packs are no
+longer included with the core distribution.
+Language packs can be downloaded from the TinyMCE website:
+http://tinymce.moxiecode.com/download.php
+
+The language pack codes are based on ISO-639-1:
+http://www.loc.gov/standards/iso639-2/englangn.html
+
+Plrease try using entities if possible. Like &aring; etc for non a-z characters.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/license.txt	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,504 @@
+		  GNU LESSER GENERAL PUBLIC LICENSE
+		       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+		  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library 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
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/advhr/css/advhr.css	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,23 @@
+input.radio {
+	border: 1px none #000000;
+	background-color: transparent;
+	vertical-align: middle;
+}
+
+.panel_wrapper div.current {
+	height: 80px;
+}
+
+#width {
+	width: 50px;
+	vertical-align: middle;
+}
+
+#width2 {
+	width: 50px;
+	vertical-align: middle;
+}
+
+#size {
+	width: 100px;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/advhr/editor_plugin.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+tinyMCE.importPluginLanguagePack('advhr');var TinyMCE_AdvancedHRPlugin={getInfo:function(){return{longname:'Advanced HR',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/advhr',version:tinyMCE.majorVersion+"."+tinyMCE.minorVersion}},getControlHTML:function(cn){switch(cn){case"advhr":return tinyMCE.getButtonHTML(cn,'lang_insert_advhr_desc','{$pluginurl}/images/advhr.gif','mceAdvancedHr')}return""},execCommand:function(editor_id,element,command,user_interface,value){switch(command){case"mceAdvancedHr":var template=new Array();template['file']='../../plugins/advhr/rule.htm';template['width']=250;template['height']=160;template['width']+=tinyMCE.getLang('lang_advhr_delta_width',0);template['height']+=tinyMCE.getLang('lang_advhr_delta_height',0);var size="",width="",noshade="";if(tinyMCE.selectedElement!=null&&tinyMCE.selectedElement.nodeName.toLowerCase()=="hr"){tinyMCE.hrElement=tinyMCE.selectedElement;if(tinyMCE.hrElement){size=tinyMCE.hrElement.getAttribute('size')?tinyMCE.hrElement.getAttribute('size'):"";width=tinyMCE.hrElement.getAttribute('width')?tinyMCE.hrElement.getAttribute('width'):"";noshade=tinyMCE.hrElement.getAttribute('noshade')?tinyMCE.hrElement.getAttribute('noshade'):""}tinyMCE.openWindow(template,{editor_id:editor_id,size:size,width:width,noshade:noshade,mceDo:'update'})}else{if(tinyMCE.isMSIE){tinyMCE.execInstanceCommand(editor_id,'mceInsertContent',false,'<hr />')}else{tinyMCE.openWindow(template,{editor_id:editor_id,inline:"yes",size:size,width:width,noshade:noshade,mceDo:'insert'})}}return true}return false},handleNodeChange:function(editor_id,node,undo_index,undo_levels,visual_aid,any_selection){if(node==null)return;do{if(node.nodeName=="HR"){tinyMCE.switchClass(editor_id+'_advhr','mceButtonSelected');return true}}while((node=node.parentNode));tinyMCE.switchClass(editor_id+'_advhr','mceButtonNormal');return true}};tinyMCE.addPlugin("advhr",TinyMCE_AdvancedHRPlugin);
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/advhr/editor_plugin_src.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,90 @@
+/**
+ * $Id: editor_plugin_src.js 201 2007-02-12 15:56:56Z spocke $
+ *
+ * @author Moxiecode
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+/* Import plugin specific language pack */
+tinyMCE.importPluginLanguagePack('advhr');
+
+var TinyMCE_AdvancedHRPlugin = {
+	getInfo : function() {
+		return {
+			longname : 'Advanced HR',
+			author : 'Moxiecode Systems AB',
+			authorurl : 'http://tinymce.moxiecode.com',
+			infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/advhr',
+			version : tinyMCE.majorVersion + "." + tinyMCE.minorVersion
+		}
+	},
+
+	getControlHTML : function(cn) {
+		switch (cn) {
+			case "advhr":
+				return tinyMCE.getButtonHTML(cn, 'lang_insert_advhr_desc', '{$pluginurl}/images/advhr.gif', 'mceAdvancedHr');
+		}
+
+		return "";
+	},
+
+	/**
+	 * Executes the mceAdvanceHr command.
+	 */
+	execCommand : function(editor_id, element, command, user_interface, value) {
+		// Handle commands
+		switch (command) {
+			case "mceAdvancedHr":
+				var template = new Array();
+
+				template['file']   = '../../plugins/advhr/rule.htm'; // Relative to theme
+				template['width']  = 250;
+				template['height'] = 160;
+
+				template['width']  += tinyMCE.getLang('lang_advhr_delta_width', 0);
+				template['height'] += tinyMCE.getLang('lang_advhr_delta_height', 0);
+
+				var size = "", width = "", noshade = "";
+				if (tinyMCE.selectedElement != null && tinyMCE.selectedElement.nodeName.toLowerCase() == "hr") {
+					tinyMCE.hrElement = tinyMCE.selectedElement;
+
+					if (tinyMCE.hrElement) {
+						size    = tinyMCE.hrElement.getAttribute('size') ? tinyMCE.hrElement.getAttribute('size') : "";
+						width   = tinyMCE.hrElement.getAttribute('width') ? tinyMCE.hrElement.getAttribute('width') : "";
+						noshade = tinyMCE.hrElement.getAttribute('noshade') ? tinyMCE.hrElement.getAttribute('noshade') : "";
+					}
+
+					tinyMCE.openWindow(template, {editor_id : editor_id, size : size, width : width, noshade : noshade, mceDo : 'update'});
+				} else {
+					if (tinyMCE.isMSIE) {
+						tinyMCE.execInstanceCommand(editor_id, 'mceInsertContent', false,'<hr />');
+					} else {
+						tinyMCE.openWindow(template, {editor_id : editor_id, inline : "yes", size : size, width : width, noshade : noshade, mceDo : 'insert'});
+					}
+				}
+
+				return true;
+		}
+
+		// Pass to next handler in chain
+		return false;
+	},
+
+	handleNodeChange : function(editor_id, node, undo_index, undo_levels, visual_aid, any_selection) {
+		if (node == null)
+			return;
+
+		do {
+			if (node.nodeName == "HR") {
+				tinyMCE.switchClass(editor_id + '_advhr', 'mceButtonSelected');
+				return true;
+			}
+		} while ((node = node.parentNode));
+
+		tinyMCE.switchClass(editor_id + '_advhr', 'mceButtonNormal');
+
+		return true;
+	}
+};
+
+tinyMCE.addPlugin("advhr", TinyMCE_AdvancedHRPlugin);
Binary file includes/clientside/tinymce/plugins/advhr/images/advhr.gif has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/advhr/jscripts/rule.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,43 @@
+function init() {
+	tinyMCEPopup.resizeToInnerSize();
+
+	var formObj = document.forms[0];
+	formObj.width.value  = tinyMCE.getWindowArg('width');
+	formObj.size.value   = tinyMCE.getWindowArg('size');
+	formObj.insert.value = tinyMCE.getLang('lang_' + tinyMCE.getWindowArg('mceDo'),'Insert',true);
+	if (tinyMCE.getWindowArg('noshade')) {
+		formObj.noshade.checked = true;
+	}
+	if (tinyMCE.getWindowArg('width').lastIndexOf('%')!=-1) {
+		formObj.width2.value = "%";
+		formObj.width.value  = formObj.width.value.substring(0,formObj.width.value.length-1);
+	}
+}
+
+function insertHR() {
+	var formObj = document.forms[0];
+	var width   = formObj.width.value;
+	var size    = formObj.size.value;
+	var html = '<hr';
+	if (size!='' && size!=0) {
+		html += ' size="' + size + '"';
+	}
+	if (width!='' && width!=0) {
+		html += ' width="' + width;
+		if (formObj.width2.value=='%') {
+			html += '%';
+		}
+		html += '"';
+	}
+	if (formObj.noshade.checked==true) {
+		html += ' noshade="noshade"';
+	}
+	html += ' />';
+
+	tinyMCEPopup.execCommand("mceInsertContent", true, html);
+	tinyMCEPopup.close();
+}
+
+function cancelAction() {
+	tinyMCEPopup.close();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/advhr/langs/en.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,8 @@
+// UK lang variables
+
+tinyMCE.addToLang('',{
+insert_advhr_desc : 'Horizontale rule',
+insert_advhr_width : 'Width',
+insert_advhr_size : 'Height',
+insert_advhr_noshade : 'No shadow'
+});
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/advhr/readme.txt	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+Check the TinyMCE documentation for details on this plugin.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/advhr/rule.htm	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,61 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>{$lang_insert_advhr_desc}</title>
+	<script language="javascript" type="text/javascript" src="../../tiny_mce_popup.js"></script>
+	<script language="javascript" type="text/javascript" src="jscripts/rule.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/mctabs.js"></script>
+	<link href="css/advhr.css" rel="stylesheet" type="text/css" />
+	<base target="_self" />
+</head>
+<body onload="tinyMCEPopup.executeOnLoad('init();');">
+<form onsubmit="insertHR();return false;" action="#">
+	<div class="tabs">
+		<ul>
+			<li id="general_tab" class="current"><span><a href="javascript:mcTabs.displayTab('general_tab','general_panel');" onmousedown="return false;">{$lang_insert_advhr_desc}</a></span></li>
+		</ul>
+	</div>
+
+	<div class="panel_wrapper">
+		<div id="general_panel" class="panel current">
+			<table border="0" cellpadding="4" cellspacing="0">
+                    <tr>
+                        <td><label for="width">{$lang_insert_advhr_width}</label></td>
+                        <td nowrap="nowrap">
+                            <input id="width" name="width" type="text" value="" />
+                            <select name="width2" id="width2">
+                                <option value="">px</option>
+                                <option value="%">%</option>
+                            </select>
+                        </td>
+                    </tr>
+                    <tr>
+                        <td><label for="size">{$lang_insert_advhr_size}</label></td>
+                        <td><select id="size" name="size">
+                            <option value="">Normal</option>
+                            <option value="1">1</option>
+                            <option value="2">2</option>
+                            <option value="3">3</option>
+                            <option value="4">4</option>
+                            <option value="5">5</option>
+                        </select></td>
+                    </tr>
+                    <tr>
+                        <td><label for="noshade">{$lang_insert_advhr_noshade}</label></td>
+                        <td><input type="checkbox" name="noshade" id="noshade" class="radio" /></td>
+                    </tr>
+            </table>
+		</div>
+	</div>
+
+	<div class="mceActionPanel">
+		<div style="float: left">
+			<input type="button" id="insert" name="insert" value="{$lang_insert}" onclick="insertHR();" />
+		</div>
+
+		<div style="float: right">
+			<input type="button" id="cancel" name="cancel" value="{$lang_cancel}" onclick="tinyMCEPopup.close();" />
+		</div>
+	</div>
+</form>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/advimage/css/advimage.css	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,66 @@
+/* CSS file for advimage plugin popup */
+
+.mceImageList {
+	width: 280px;
+}
+
+.mceActionPanel {
+	margin-top: 7px;
+}
+
+.alignPreview {
+	border: 1px solid black;
+	width: 140px;
+	height: 140px;
+	overflow: hidden;
+	padding: 5px;
+}
+
+.checkbox {
+	border: 0;
+}
+
+.panel_wrapper div.current {
+	height: 305px;
+}
+
+#prev {
+	margin: 0;
+	border: 1px
+	solid black;
+	width: 99%;
+	height: 150px;
+	overflow: auto;
+}
+
+#align, #classlist {
+	width: 150px;
+}
+
+#width, #height {
+	vertical-align: middle;
+	width: 50px;
+	text-align: center;
+}
+
+#vspace, #hspace, #border {
+	vertical-align: middle;
+	width: 30px;
+	text-align: center;
+}
+
+#classlist {
+	width: 180px;
+}
+
+input {
+	width: 280px;
+}
+
+#constrain, #onmousemovecheck {
+	width: auto;
+}
+
+#id, #dir, #lang, #usemap, #longdesc {
+	width: 200px;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/advimage/editor_plugin.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+tinyMCE.importPluginLanguagePack('advimage');var TinyMCE_AdvancedImagePlugin={getInfo:function(){return{longname:'Advanced image',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/advimage',version:tinyMCE.majorVersion+"."+tinyMCE.minorVersion}},getControlHTML:function(cn){switch(cn){case"image":return tinyMCE.getButtonHTML(cn,'lang_image_desc','{$themeurl}/images/image.gif','mceAdvImage')}return""},execCommand:function(editor_id,element,command,user_interface,value){switch(command){case"mceAdvImage":var template=new Array();template['file']='../../plugins/advimage/image.htm';template['width']=480;template['height']=380;template['width']+=tinyMCE.getLang('lang_advimage_delta_width',0);template['height']+=tinyMCE.getLang('lang_advimage_delta_height',0);var inst=tinyMCE.getInstanceById(editor_id);var elm=inst.getFocusElement();if(elm!=null&&tinyMCE.getAttrib(elm,'class').indexOf('mceItem')!=-1)return true;tinyMCE.openWindow(template,{editor_id:editor_id,inline:"yes"});return true}return false},cleanup:function(type,content){switch(type){case"insert_to_editor_dom":var imgs=content.getElementsByTagName("img"),src,i;for(i=0;i<imgs.length;i++){var onmouseover=tinyMCE.cleanupEventStr(tinyMCE.getAttrib(imgs[i],'onmouseover'));var onmouseout=tinyMCE.cleanupEventStr(tinyMCE.getAttrib(imgs[i],'onmouseout'));if((src=this._getImageSrc(onmouseover))!=""){if(tinyMCE.getParam('convert_urls'))src=tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'],src);imgs[i].setAttribute('onmouseover',"this.src='"+src+"';")}if((src=this._getImageSrc(onmouseout))!=""){if(tinyMCE.getParam('convert_urls'))src=tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'],src);imgs[i].setAttribute('onmouseout',"this.src='"+src+"';")}}break;case"get_from_editor_dom":var imgs=content.getElementsByTagName("img");for(var i=0;i<imgs.length;i++){var onmouseover=tinyMCE.cleanupEventStr(tinyMCE.getAttrib(imgs[i],'onmouseover'));var onmouseout=tinyMCE.cleanupEventStr(tinyMCE.getAttrib(imgs[i],'onmouseout'));if((src=this._getImageSrc(onmouseover))!=""){if(tinyMCE.getParam('convert_urls'))src=eval(tinyMCE.settings['urlconverter_callback']+"(src, null, true);");imgs[i].setAttribute('onmouseover',"this.src='"+src+"';")}if((src=this._getImageSrc(onmouseout))!=""){if(tinyMCE.getParam('convert_urls'))src=eval(tinyMCE.settings['urlconverter_callback']+"(src, null, true);");imgs[i].setAttribute('onmouseout',"this.src='"+src+"';")}}break}return content},handleNodeChange:function(editor_id,node,undo_index,undo_levels,visual_aid,any_selection){if(node==null)return;do{if(node.nodeName=="IMG"&&tinyMCE.getAttrib(node,'class').indexOf('mceItem')==-1){tinyMCE.switchClass(editor_id+'_advimage','mceButtonSelected');return true}}while((node=node.parentNode));tinyMCE.switchClass(editor_id+'_advimage','mceButtonNormal');return true},_getImageSrc:function(s){var sr,p=-1;if(!s)return"";if((p=s.indexOf('this.src='))!=-1){sr=s.substring(p+10);sr=sr.substring(0,sr.indexOf('\''));return sr}return""}};tinyMCE.addPlugin("advimage",TinyMCE_AdvancedImagePlugin);
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/advimage/editor_plugin_src.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,148 @@
+/**
+ * $Id: editor_plugin_src.js 201 2007-02-12 15:56:56Z spocke $
+ *
+ * @author Moxiecode
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+/* Import plugin specific language pack */
+tinyMCE.importPluginLanguagePack('advimage');
+
+var TinyMCE_AdvancedImagePlugin = {
+	getInfo : function() {
+		return {
+			longname : 'Advanced image',
+			author : 'Moxiecode Systems AB',
+			authorurl : 'http://tinymce.moxiecode.com',
+			infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/advimage',
+			version : tinyMCE.majorVersion + "." + tinyMCE.minorVersion
+		};
+	},
+
+	getControlHTML : function(cn) {
+		switch (cn) {
+			case "image":
+				return tinyMCE.getButtonHTML(cn, 'lang_image_desc', '{$themeurl}/images/image.gif', 'mceAdvImage');
+		}
+
+		return "";
+	},
+
+	execCommand : function(editor_id, element, command, user_interface, value) {
+		switch (command) {
+			case "mceAdvImage":
+				var template = new Array();
+
+				template['file']   = '../../plugins/advimage/image.htm';
+				template['width']  = 480;
+				template['height'] = 380;
+
+				// Language specific width and height addons
+				template['width']  += tinyMCE.getLang('lang_advimage_delta_width', 0);
+				template['height'] += tinyMCE.getLang('lang_advimage_delta_height', 0);
+
+				var inst = tinyMCE.getInstanceById(editor_id);
+				var elm = inst.getFocusElement();
+
+				if (elm != null && tinyMCE.getAttrib(elm, 'class').indexOf('mceItem') != -1)
+					return true;
+
+				tinyMCE.openWindow(template, {editor_id : editor_id, inline : "yes"});
+
+				return true;
+		}
+
+		return false;
+	},
+
+	cleanup : function(type, content) {
+		switch (type) {
+			case "insert_to_editor_dom":
+				var imgs = content.getElementsByTagName("img"), src, i;
+				for (i=0; i<imgs.length; i++) {
+					var onmouseover = tinyMCE.cleanupEventStr(tinyMCE.getAttrib(imgs[i], 'onmouseover'));
+					var onmouseout = tinyMCE.cleanupEventStr(tinyMCE.getAttrib(imgs[i], 'onmouseout'));
+
+					if ((src = this._getImageSrc(onmouseover)) != "") {
+						if (tinyMCE.getParam('convert_urls'))
+							src = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], src);
+
+						imgs[i].setAttribute('onmouseover', "this.src='" + src + "';");
+					}
+
+					if ((src = this._getImageSrc(onmouseout)) != "") {
+						if (tinyMCE.getParam('convert_urls'))
+							src = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], src);
+
+						imgs[i].setAttribute('onmouseout', "this.src='" + src + "';");
+					}
+				}
+				break;
+
+			case "get_from_editor_dom":
+				var imgs = content.getElementsByTagName("img");
+				for (var i=0; i<imgs.length; i++) {
+					var onmouseover = tinyMCE.cleanupEventStr(tinyMCE.getAttrib(imgs[i], 'onmouseover'));
+					var onmouseout = tinyMCE.cleanupEventStr(tinyMCE.getAttrib(imgs[i], 'onmouseout'));
+
+					if ((src = this._getImageSrc(onmouseover)) != "") {
+						if (tinyMCE.getParam('convert_urls'))
+							src = eval(tinyMCE.settings['urlconverter_callback'] + "(src, null, true);");
+
+						imgs[i].setAttribute('onmouseover', "this.src='" + src + "';");
+					}
+
+					if ((src = this._getImageSrc(onmouseout)) != "") {
+						if (tinyMCE.getParam('convert_urls'))
+							src = eval(tinyMCE.settings['urlconverter_callback'] + "(src, null, true);");
+
+						imgs[i].setAttribute('onmouseout', "this.src='" + src + "';");
+					}
+				}
+				break;
+		}
+
+		return content;
+	},
+
+	handleNodeChange : function(editor_id, node, undo_index, undo_levels, visual_aid, any_selection) {
+		if (node == null)
+			return;
+
+		do {
+			if (node.nodeName == "IMG" && tinyMCE.getAttrib(node, 'class').indexOf('mceItem') == -1) {
+				tinyMCE.switchClass(editor_id + '_advimage', 'mceButtonSelected');
+				return true;
+			}
+		} while ((node = node.parentNode));
+
+		tinyMCE.switchClass(editor_id + '_advimage', 'mceButtonNormal');
+
+		return true;
+	},
+
+	/**
+	 * Returns the image src from a scripted mouse over image str.
+	 *
+	 * @param {string} s String to get real src from.
+	 * @return Image src from a scripted mouse over image str.
+	 * @type string
+	 */
+	_getImageSrc : function(s) {
+		var sr, p = -1;
+
+		if (!s)
+			return "";
+
+		if ((p = s.indexOf('this.src=')) != -1) {
+			sr = s.substring(p + 10);
+			sr = sr.substring(0, sr.indexOf('\''));
+
+			return sr;
+		}
+
+		return "";
+	}
+};
+
+tinyMCE.addPlugin("advimage", TinyMCE_AdvancedImagePlugin);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/advimage/image.htm	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,241 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>{$lang_insert_image_title}</title>
+	<script language="javascript" type="text/javascript" src="../../tiny_mce_popup.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/mctabs.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/form_utils.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/validate.js"></script>
+	<script language="javascript" type="text/javascript" src="jscripts/functions.js"></script>
+	<link href="css/advimage.css" rel="stylesheet" type="text/css" />
+	<base target="_self" />
+</head>
+<body id="advimage" onload="tinyMCEPopup.executeOnLoad('init();');" style="display: none">
+    <form onsubmit="insertAction();return false;" action="#"> 
+		<div class="tabs">
+			<ul>
+				<li id="general_tab" class="current"><span><a href="javascript:mcTabs.displayTab('general_tab','general_panel');" onmousedown="return false;">{$lang_advimage_tab_general}</a></span></li>
+				<li id="appearance_tab"><span><a href="javascript:mcTabs.displayTab('appearance_tab','appearance_panel');" onmousedown="return false;">{$lang_advimage_tab_appearance}</a></span></li>
+				<li id="advanced_tab"><span><a href="javascript:mcTabs.displayTab('advanced_tab','advanced_panel');" onmousedown="return false;">{$lang_advimage_tab_advanced}</a></span></li>
+			</ul>
+		</div>
+
+		<div class="panel_wrapper">
+			<div id="general_panel" class="panel current">
+				<fieldset>
+						<legend>{$lang_advimage_general}</legend>
+
+						<table class="properties">
+							<tr>
+								<td class="column1"><label id="srclabel" for="src">{$lang_insert_image_src}</label></td>
+								<td colspan="2"><table border="0" cellspacing="0" cellpadding="0">
+									<tr> 
+									  <td><input name="src" type="text" id="src" value="" onchange="showPreviewImage(this.value);" /></td> 
+									  <td id="srcbrowsercontainer">&nbsp;</td>
+									</tr>
+								  </table></td>
+							</tr>
+							<tr id="imagelistsrcrow">
+								<td class="column1"><label for="imagelistsrc">{$lang_image_list}</label></td>
+								<td colspan="2" id="imagelistsrccontainer">&nbsp;</td>
+							</tr>
+							<tr> 
+								<td class="column1"><label id="altlabel" for="alt">{$lang_insert_image_alt}</label></td> 
+								<td colspan="2"><input id="alt" name="alt" type="text" value="" /></td> 
+							</tr> 
+							<tr> 
+								<td class="column1"><label id="titlelabel" for="title">{$lang_advimage_title}</label></td> 
+								<td colspan="2"><input id="title" name="title" type="text" value="" /></td> 
+							</tr>
+						</table>
+				</fieldset>
+
+				<fieldset>
+					<legend>{$lang_advimage_preview}</legend>
+					<div id="prev"></div>
+				</fieldset>
+			</div>
+
+			<div id="appearance_panel" class="panel">
+				<fieldset>
+					<legend>{$lang_advimage_tab_appearance}</legend>
+
+					<table border="0" cellpadding="4" cellspacing="0">
+						<tr> 
+							<td class="column1"><label id="alignlabel" for="align">{$lang_insert_image_align}</label></td> 
+							<td><select id="align" name="align" onchange="changeAppearance();"> 
+									<option value="">{$lang_insert_image_align_default}</option> 
+									<option value="baseline">{$lang_insert_image_align_baseline}</option> 
+									<option value="top">{$lang_insert_image_align_top}</option> 
+									<option value="middle">{$lang_insert_image_align_middle}</option> 
+									<option value="bottom">{$lang_insert_image_align_bottom}</option> 
+									<option value="texttop">{$lang_insert_image_align_texttop}</option> 
+									<option value="absmiddle">{$lang_insert_image_align_absmiddle}</option> 
+									<option value="absbottom">{$lang_insert_image_align_absbottom}</option> 
+									<option value="left">{$lang_insert_image_align_left}</option> 
+									<option value="right">{$lang_insert_image_align_right}</option> 
+								</select> 
+							</td>
+							<td rowspan="6" valign="top">
+								<div class="alignPreview">
+									<img id="alignSampleImg" src="images/sample.gif" alt="{$lang_advimage_example_img}" />
+									Lorem ipsum, Dolor sit amet, consectetuer adipiscing loreum ipsum edipiscing elit, sed diam
+									nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.Loreum ipsum
+									edipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam
+									erat volutpat.
+								</div>
+							</td>
+						</tr>
+
+						<tr>
+							<td class="column1"><label id="widthlabel" for="width">{$lang_insert_image_dimensions}</label></td>
+							<td nowrap="nowrap">
+								<input name="width" type="text" id="width" value="" size="5" maxlength="5" class="size" onchange="changeHeight();" /> x 
+								<input name="height" type="text" id="height" value="" size="5" maxlength="5" class="size" onchange="changeWidth();" /> px
+							</td>
+						</tr>
+
+						<tr>
+							<td>&nbsp;</td>
+							<td><table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input id="constrain" type="checkbox" name="constrain" class="checkbox" /></td>
+										<td><label id="constrainlabel" for="constrain">{$lang_advimage_constrain_proportions}</label></td>
+									</tr>
+								</table></td>
+						</tr>
+
+						<tr>
+							<td class="column1"><label id="vspacelabel" for="vspace">{$lang_insert_image_vspace}</label></td> 
+							<td><input name="vspace" type="text" id="vspace" value="" size="3" maxlength="3" class="number" onchange="changeAppearance();updateStyle();" />
+							</td>
+						</tr>
+
+						<tr> 
+							<td class="column1"><label id="hspacelabel" for="hspace">{$lang_insert_image_hspace}</label></td> 
+							<td><input name="hspace" type="text" id="hspace" value="" size="3" maxlength="3" class="number" onchange="changeAppearance();updateStyle();" /></td> 
+						</tr>
+
+						<tr>
+							<td class="column1"><label id="borderlabel" for="border">{$lang_insert_image_border}</label></td> 
+							<td><input id="border" name="border" type="text" value="" size="3" maxlength="3" class="number" onchange="changeAppearance();updateStyle();" /></td> 
+						</tr>
+
+						<tr>
+							<td><label id="classlabel" for="classlist">{$lang_class_name}</label></td>
+							<td colspan="2">
+								 <select id="classlist" name="classlist">
+									<option value="" selected>{$lang_not_set}</option>
+								 </select>
+							</td>
+						</tr>
+
+						<tr>
+							<td class="column1"><label id="stylelabel" for="style">{$lang_advimage_style}</label></td> 
+							<td colspan="2"><input id="style" name="style" type="text" value="" onchange="styleUpdated();" /></td> 
+						</tr>
+
+						<!-- <tr>
+							<td class="column1"><label id="classeslabel" for="classes">{$lang_advimage_classes}</label></td> 
+							<td colspan="2"><input id="classes" name="classes" type="text" value="" onchange="selectByValue(this.form,'classlist',this.value,true);" /></td> 
+						</tr> -->
+					</table>
+				</fieldset>
+			</div>
+
+			<div id="advanced_panel" class="panel">
+				<fieldset>
+					<legend>{$lang_advimage_swap_image}</legend>
+
+					<input type="checkbox" id="onmousemovecheck" name="onmousemovecheck" class="checkbox" onclick="changeMouseMove();" />
+					<label id="onmousemovechecklabel" for="onmousemovecheck">{$lang_advimage_alt_image}</label>
+
+					<table border="0" cellpadding="4" cellspacing="0" width="100%">
+							<tr>
+								<td class="column1"><label id="onmouseoversrclabel" for="onmouseoversrc">{$lang_advimage_mouseover}</label></td> 
+								<td><table border="0" cellspacing="0" cellpadding="0"> 
+									<tr> 
+									  <td><input id="onmouseoversrc" name="onmouseoversrc" type="text" value="" /></td> 
+									  <td id="onmouseoversrccontainer">&nbsp;</td>
+									</tr>
+								  </table></td>
+							</tr>
+							<tr id="imagelistoverrow">
+								<td class="column1"><label for="imagelistover">{$lang_image_list}</label></td>
+								<td id="imagelistovercontainer">&nbsp;</td>
+							</tr>
+							<tr> 
+								<td class="column1"><label id="onmouseoutsrclabel" for="onmouseoutsrc">{$lang_advimage_mouseout}</label></td> 
+								<td class="column2"><table border="0" cellspacing="0" cellpadding="0"> 
+									<tr> 
+									  <td><input id="onmouseoutsrc" name="onmouseoutsrc" type="text" value="" /></td> 
+									  <td id="onmouseoutsrccontainer">&nbsp;</td>
+									</tr> 
+								  </table></td> 
+							</tr>
+							<tr id="imagelistoutrow">
+								<td class="column1"><label for="imagelistout">{$lang_image_list}</label></td>
+								<td id="imagelistoutcontainer">&nbsp;</td>
+							</tr>
+					</table>
+				</fieldset>
+
+				<fieldset>
+					<legend>{$lang_advimage_misc}</legend>
+
+					<table border="0" cellpadding="4" cellspacing="0">
+						<tr>
+							<td class="column1"><label id="idlabel" for="id">{$lang_advimage_id}</label></td> 
+							<td><input id="id" name="id" type="text" value="" /></td> 
+						</tr>
+
+						<tr>
+							<td class="column1"><label id="dirlabel" for="dir">{$lang_advimage_langdir}</label></td> 
+							<td>
+								<select id="dir" name="dir" onchange="changeAppearance();"> 
+										<option value="">{$lang_not_set}</option> 
+										<option value="ltr">{$lang_advimage_ltr}</option> 
+										<option value="rtl">{$lang_advimage_rtl}</option> 
+								</select>
+							</td> 
+						</tr>
+
+						<tr>
+							<td class="column1"><label id="langlabel" for="lang">{$lang_advimage_langcode}</label></td> 
+							<td>
+								<input id="lang" name="lang" type="text" value="" />
+							</td> 
+						</tr>
+
+						<tr>
+							<td class="column1"><label id="usemaplabel" for="usemap">{$lang_advimage_image_map}</label></td> 
+							<td>
+								<input id="usemap" name="usemap" type="text" value="" />
+							</td> 
+						</tr>
+
+						<tr>
+							<td class="column1"><label id="longdesclabel" for="longdesc">{$lang_advimage_long_desc}</label></td>
+							<td><table border="0" cellspacing="0" cellpadding="0">
+									<tr>
+									  <td><input id="longdesc" name="longdesc" type="text" value="" /></td>
+									  <td id="longdesccontainer">&nbsp;</td>
+									</tr>
+								</table></td> 
+						</tr>
+					</table>
+				</fieldset>
+			</div>
+		</div>
+
+		<div class="mceActionPanel">
+			<div style="float: left">
+				<input type="button" id="insert" name="insert" value="{$lang_insert}" onclick="insertAction();" />
+			</div>
+
+			<div style="float: right">
+				<input type="button" id="cancel" name="cancel" value="{$lang_cancel}" onclick="cancelAction();" />
+			</div>
+		</div>
+    </form>
+</body> 
+</html> 
Binary file includes/clientside/tinymce/plugins/advimage/images/sample.gif has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/advimage/jscripts/functions.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,534 @@
+/* Functions for the advimage plugin popup */
+
+var preloadImg = null;
+var orgImageWidth, orgImageHeight;
+
+function preinit() {
+	// Initialize
+	tinyMCE.setWindowArg('mce_windowresize', false);
+
+	// Import external list url javascript
+	var url = tinyMCE.getParam("external_image_list_url");
+	if (url != null) {
+		// Fix relative
+		if (url.charAt(0) != '/' && url.indexOf('://') == -1)
+			url = tinyMCE.documentBasePath + "/" + url;
+
+		document.write('<sc'+'ript language="javascript" type="text/javascript" src="' + url + '"></sc'+'ript>');
+	}
+}
+
+function convertURL(url, node, on_save) {
+	return eval("tinyMCEPopup.windowOpener." + tinyMCE.settings['urlconverter_callback'] + "(url, node, on_save);");
+}
+
+function getImageSrc(str) {
+	var pos = -1;
+
+	if (!str)
+		return "";
+
+	if ((pos = str.indexOf('this.src=')) != -1) {
+		var src = str.substring(pos + 10);
+
+		src = src.substring(0, src.indexOf('\''));
+
+		if (tinyMCE.getParam('convert_urls'))
+			src = convertURL(src, null, true);
+
+		return src;
+	}
+
+	return "";
+}
+
+function init() {
+	tinyMCEPopup.resizeToInnerSize();
+
+	var formObj = document.forms[0];
+	var inst = tinyMCE.getInstanceById(tinyMCE.getWindowArg('editor_id'));
+	var elm = inst.getFocusElement();
+	var action = "insert";
+	var html = "";
+
+	// Image list src
+	html = getImageListHTML('imagelistsrc','src','onSelectMainImage');
+	if (html == "")
+		document.getElementById("imagelistsrcrow").style.display = 'none';
+	else
+		document.getElementById("imagelistsrccontainer").innerHTML = html;
+
+	// Image list oversrc
+	html = getImageListHTML('imagelistover','onmouseoversrc');
+	if (html == "")
+		document.getElementById("imagelistoverrow").style.display = 'none';
+	else
+		document.getElementById("imagelistovercontainer").innerHTML = html;
+
+	// Image list outsrc
+	html = getImageListHTML('imagelistout','onmouseoutsrc');
+	if (html == "")
+		document.getElementById("imagelistoutrow").style.display = 'none';
+	else
+		document.getElementById("imagelistoutcontainer").innerHTML = html;
+
+	// Src browser
+	html = getBrowserHTML('srcbrowser','src','image','advimage');
+	document.getElementById("srcbrowsercontainer").innerHTML = html;
+
+	// Over browser
+	html = getBrowserHTML('oversrcbrowser','onmouseoversrc','image','advimage');
+	document.getElementById("onmouseoversrccontainer").innerHTML = html;
+
+	// Out browser
+	html = getBrowserHTML('outsrcbrowser','onmouseoutsrc','image','advimage');
+	document.getElementById("onmouseoutsrccontainer").innerHTML = html;
+
+	// Longdesc browser
+	html = getBrowserHTML('longdescbrowser','longdesc','file','advimage');
+	document.getElementById("longdesccontainer").innerHTML = html;
+
+	// Resize some elements
+	if (isVisible('srcbrowser'))
+		document.getElementById('src').style.width = '260px';
+
+	if (isVisible('oversrcbrowser'))
+		document.getElementById('onmouseoversrc').style.width = '260px';
+
+	if (isVisible('outsrcbrowser'))
+		document.getElementById('onmouseoutsrc').style.width = '260px';
+
+	if (isVisible('longdescbrowser'))
+		document.getElementById('longdesc').style.width = '180px';
+
+	// Check action
+	if (elm != null && elm.nodeName == "IMG")
+		action = "update";
+
+	formObj.insert.value = tinyMCE.getLang('lang_' + action, 'Insert', true); 
+
+	if (action == "update") {
+		var src = tinyMCE.getAttrib(elm, 'src');
+		var onmouseoversrc = getImageSrc(tinyMCE.cleanupEventStr(tinyMCE.getAttrib(elm, 'onmouseover')));
+		var onmouseoutsrc = getImageSrc(tinyMCE.cleanupEventStr(tinyMCE.getAttrib(elm, 'onmouseout')));
+
+		src = convertURL(src, elm, true);
+
+		// Use mce_src if found
+		var mceRealSrc = tinyMCE.getAttrib(elm, 'mce_src');
+		if (mceRealSrc != "") {
+			src = mceRealSrc;
+
+			if (tinyMCE.getParam('convert_urls'))
+				src = convertURL(src, elm, true);
+		}
+
+		if (onmouseoversrc != "" && tinyMCE.getParam('convert_urls'))
+			onmouseoversrc = convertURL(onmouseoversrc, elm, true);
+
+		if (onmouseoutsrc != "" && tinyMCE.getParam('convert_urls'))
+			onmouseoutsrc = convertURL(onmouseoutsrc, elm, true);
+
+		// Setup form data
+		var style = tinyMCE.parseStyle(tinyMCE.getAttrib(elm, "style"));
+
+		// Store away old size
+		orgImageWidth = trimSize(getStyle(elm, 'width'))
+		orgImageHeight = trimSize(getStyle(elm, 'height'));
+
+		formObj.src.value    = src;
+		formObj.alt.value    = tinyMCE.getAttrib(elm, 'alt');
+		formObj.title.value  = tinyMCE.getAttrib(elm, 'title');
+		formObj.border.value = trimSize(getStyle(elm, 'border', 'borderWidth'));
+		formObj.vspace.value = tinyMCE.getAttrib(elm, 'vspace');
+		formObj.hspace.value = tinyMCE.getAttrib(elm, 'hspace');
+		formObj.width.value  = orgImageWidth;
+		formObj.height.value = orgImageHeight;
+		formObj.onmouseoversrc.value = onmouseoversrc;
+		formObj.onmouseoutsrc.value  = onmouseoutsrc;
+		formObj.id.value  = tinyMCE.getAttrib(elm, 'id');
+		formObj.dir.value  = tinyMCE.getAttrib(elm, 'dir');
+		formObj.lang.value  = tinyMCE.getAttrib(elm, 'lang');
+		formObj.longdesc.value  = tinyMCE.getAttrib(elm, 'longdesc');
+		formObj.usemap.value  = tinyMCE.getAttrib(elm, 'usemap');
+		formObj.style.value  = tinyMCE.serializeStyle(style);
+
+		// Select by the values
+		if (tinyMCE.isMSIE)
+			selectByValue(formObj, 'align', getStyle(elm, 'align', 'styleFloat'));
+		else
+			selectByValue(formObj, 'align', getStyle(elm, 'align', 'cssFloat'));
+
+		addClassesToList('classlist', 'advimage_styles');
+
+		selectByValue(formObj, 'classlist', tinyMCE.getAttrib(elm, 'class'));
+		selectByValue(formObj, 'imagelistsrc', src);
+		selectByValue(formObj, 'imagelistover', onmouseoversrc);
+		selectByValue(formObj, 'imagelistout', onmouseoutsrc);
+
+		updateStyle();
+		showPreviewImage(src, true);
+		changeAppearance();
+
+		window.focus();
+	} else
+		addClassesToList('classlist', 'advimage_styles');
+
+	// If option enabled default contrain proportions to checked
+	if (tinyMCE.getParam("advimage_constrain_proportions", true))
+		formObj.constrain.checked = true;
+
+	// Check swap image if valid data
+	if (formObj.onmouseoversrc.value != "" || formObj.onmouseoutsrc.value != "")
+		setSwapImageDisabled(false);
+	else
+		setSwapImageDisabled(true);
+}
+
+function setSwapImageDisabled(state) {
+	var formObj = document.forms[0];
+
+	formObj.onmousemovecheck.checked = !state;
+
+	setBrowserDisabled('overbrowser', state);
+	setBrowserDisabled('outbrowser', state);
+
+	if (formObj.imagelistover)
+		formObj.imagelistover.disabled = state;
+
+	if (formObj.imagelistout)
+		formObj.imagelistout.disabled = state;
+
+	formObj.onmouseoversrc.disabled = state;
+	formObj.onmouseoutsrc.disabled  = state;
+}
+
+function setAttrib(elm, attrib, value) {
+	var formObj = document.forms[0];
+	var valueElm = formObj.elements[attrib];
+
+	if (typeof(value) == "undefined" || value == null) {
+		value = "";
+
+		if (valueElm)
+			value = valueElm.value;
+	}
+
+	if (value != "") {
+		elm.setAttribute(attrib, value);
+
+		if (attrib == "style")
+			attrib = "style.cssText";
+
+		if (attrib == "longdesc")
+			attrib = "longDesc";
+
+		if (attrib == "width") {
+			attrib = "style.width";
+			value = value + "px";
+			value = value.replace(/%px/g, 'px');
+		}
+
+		if (attrib == "height") {
+			attrib = "style.height";
+			value = value + "px";
+			value = value.replace(/%px/g, 'px');
+		}
+
+		if (attrib == "class")
+			attrib = "className";
+
+		eval('elm.' + attrib + "=value;");
+	} else
+		elm.removeAttribute(attrib);
+}
+
+function makeAttrib(attrib, value) {
+	var formObj = document.forms[0];
+	var valueElm = formObj.elements[attrib];
+
+	if (typeof(value) == "undefined" || value == null) {
+		value = "";
+
+		if (valueElm)
+			value = valueElm.value;
+	}
+
+	if (value == "")
+		return "";
+
+	// XML encode it
+	value = value.replace(/&/g, '&amp;');
+	value = value.replace(/\"/g, '&quot;');
+	value = value.replace(/</g, '&lt;');
+	value = value.replace(/>/g, '&gt;');
+
+	return ' ' + attrib + '="' + value + '"';
+}
+
+function insertAction() {
+	var inst = tinyMCE.getInstanceById(tinyMCE.getWindowArg('editor_id'));
+	var elm = inst.getFocusElement();
+	var formObj = document.forms[0];
+	var src = formObj.src.value;
+	var onmouseoversrc = formObj.onmouseoversrc.value;
+	var onmouseoutsrc = formObj.onmouseoutsrc.value;
+
+	if (!AutoValidator.validate(formObj)) {
+		alert(tinyMCE.getLang('lang_invalid_data'));
+		return false;
+	}
+
+	if (tinyMCE.getParam("accessibility_warnings")) {
+		if (formObj.alt.value == "" && !confirm(tinyMCE.getLang('lang_advimage_missing_alt', '', true)))
+			return;
+	}
+
+	if (onmouseoversrc && onmouseoversrc != "")
+		onmouseoversrc = "this.src='" + convertURL(onmouseoversrc, tinyMCE.imgElement) + "';";
+
+	if (onmouseoutsrc && onmouseoutsrc != "")
+		onmouseoutsrc = "this.src='" + convertURL(onmouseoutsrc, tinyMCE.imgElement) + "';";
+
+	if (elm != null && elm.nodeName == "IMG") {
+		setAttrib(elm, 'src', convertURL(src, tinyMCE.imgElement));
+		setAttrib(elm, 'mce_src', src);
+		setAttrib(elm, 'alt');
+		setAttrib(elm, 'title');
+		setAttrib(elm, 'border');
+		setAttrib(elm, 'vspace');
+		setAttrib(elm, 'hspace');
+		setAttrib(elm, 'width');
+		setAttrib(elm, 'height');
+		setAttrib(elm, 'onmouseover', onmouseoversrc);
+		setAttrib(elm, 'onmouseout', onmouseoutsrc);
+		setAttrib(elm, 'id');
+		setAttrib(elm, 'dir');
+		setAttrib(elm, 'lang');
+		setAttrib(elm, 'longdesc');
+		setAttrib(elm, 'usemap');
+		setAttrib(elm, 'style');
+		setAttrib(elm, 'class', getSelectValue(formObj, 'classlist'));
+		setAttrib(elm, 'align', getSelectValue(formObj, 'align'));
+
+		//tinyMCEPopup.execCommand("mceRepaint");
+
+		// Repaint if dimensions changed
+		if (formObj.width.value != orgImageWidth || formObj.height.value != orgImageHeight)
+			inst.repaint();
+
+		// Refresh in old MSIE
+		if (tinyMCE.isMSIE5)
+			elm.outerHTML = elm.outerHTML;
+	} else {
+		var html = "<img";
+
+		html += makeAttrib('src', convertURL(src, tinyMCE.imgElement));
+		html += makeAttrib('mce_src', src);
+		html += makeAttrib('alt');
+		html += makeAttrib('title');
+		html += makeAttrib('border');
+		html += makeAttrib('vspace');
+		html += makeAttrib('hspace');
+		html += makeAttrib('width');
+		html += makeAttrib('height');
+		html += makeAttrib('onmouseover', onmouseoversrc);
+		html += makeAttrib('onmouseout', onmouseoutsrc);
+		html += makeAttrib('id');
+		html += makeAttrib('dir');
+		html += makeAttrib('lang');
+		html += makeAttrib('longdesc');
+		html += makeAttrib('usemap');
+		html += makeAttrib('style');
+		html += makeAttrib('class', getSelectValue(formObj, 'classlist'));
+		html += makeAttrib('align', getSelectValue(formObj, 'align'));
+		html += " />";
+
+		tinyMCEPopup.execCommand("mceInsertContent", false, html);
+	}
+
+	tinyMCE._setEventsEnabled(inst.getBody(), false);
+	tinyMCEPopup.close();
+}
+
+function cancelAction() {
+	tinyMCEPopup.close();
+}
+
+function changeAppearance() {
+	var formObj = document.forms[0];
+	var img = document.getElementById('alignSampleImg');
+
+	if (img) {
+		img.align = formObj.align.value;
+		img.border = formObj.border.value;
+		img.hspace = formObj.hspace.value;
+		img.vspace = formObj.vspace.value;
+	}
+}
+
+function changeMouseMove() {
+	var formObj = document.forms[0];
+
+	setSwapImageDisabled(!formObj.onmousemovecheck.checked);
+}
+
+function updateStyle() {
+	var formObj = document.forms[0];
+	var st = tinyMCE.parseStyle(formObj.style.value);
+
+	if (tinyMCE.getParam('inline_styles', false)) {
+		st['width'] = formObj.width.value == '' ? '' : formObj.width.value + "px";
+		st['height'] = formObj.height.value == '' ? '' : formObj.height.value + "px";
+		st['border-width'] = formObj.border.value == '' ? '' : formObj.border.value + "px";
+		st['margin-top'] = formObj.vspace.value == '' ? '' : formObj.vspace.value + "px";
+		st['margin-bottom'] = formObj.vspace.value == '' ? '' : formObj.vspace.value + "px";
+		st['margin-left'] = formObj.hspace.value == '' ? '' : formObj.hspace.value + "px";
+		st['margin-right'] = formObj.hspace.value == '' ? '' : formObj.hspace.value + "px";
+	} else {
+		st['width'] = st['height'] = st['border-width'] = null;
+
+		if (st['margin-top'] == st['margin-bottom'])
+			st['margin-top'] = st['margin-bottom'] = null;
+
+		if (st['margin-left'] == st['margin-right'])
+			st['margin-left'] = st['margin-right'] = null;
+	}
+
+	formObj.style.value = tinyMCE.serializeStyle(st);
+}
+
+function styleUpdated() {
+	var formObj = document.forms[0];
+	var st = tinyMCE.parseStyle(formObj.style.value);
+
+	if (st['width'])
+		formObj.width.value = st['width'].replace('px', '');
+
+	if (st['height'])
+		formObj.height.value = st['height'].replace('px', '');
+
+	if (st['margin-top'] && st['margin-top'] == st['margin-bottom'])
+		formObj.vspace.value = st['margin-top'].replace('px', '');
+
+	if (st['margin-left'] && st['margin-left'] == st['margin-right'])
+		formObj.hspace.value = st['margin-left'].replace('px', '');
+
+	if (st['border-width'])
+		formObj.border.value = st['border-width'].replace('px', '');
+}
+
+function changeHeight() {
+	var formObj = document.forms[0];
+
+	if (!formObj.constrain.checked || !preloadImg) {
+		updateStyle();
+		return;
+	}
+
+	if (formObj.width.value == "" || formObj.height.value == "")
+		return;
+
+	var temp = (parseInt(formObj.width.value) / parseInt(preloadImg.width)) * preloadImg.height;
+	formObj.height.value = temp.toFixed(0);
+	updateStyle();
+}
+
+function changeWidth() {
+	var formObj = document.forms[0];
+
+	if (!formObj.constrain.checked || !preloadImg) {
+		updateStyle();
+		return;
+	}
+
+	if (formObj.width.value == "" || formObj.height.value == "")
+		return;
+
+	var temp = (parseInt(formObj.height.value) / parseInt(preloadImg.height)) * preloadImg.width;
+	formObj.width.value = temp.toFixed(0);
+	updateStyle();
+}
+
+function onSelectMainImage(target_form_element, name, value) {
+	var formObj = document.forms[0];
+
+	formObj.alt.value = name;
+	formObj.title.value = name;
+
+	resetImageData();
+	showPreviewImage(formObj.elements[target_form_element].value, false);
+}
+
+function showPreviewImage(src, start) {
+	var formObj = document.forms[0];
+
+	selectByValue(document.forms[0], 'imagelistsrc', src);
+
+	var elm = document.getElementById('prev');
+	var src = src == "" ? src : tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], src);
+
+	if (!start && tinyMCE.getParam("advimage_update_dimensions_onchange", true))
+		resetImageData();
+
+	if (src == "")
+		elm.innerHTML = "";
+	else
+		elm.innerHTML = '<img id="previewImg" src="' + src + '" border="0" onload="updateImageData();" onerror="resetImageData();" />'
+}
+
+function updateImageData() {
+	var formObj = document.forms[0];
+
+	preloadImg = document.getElementById('previewImg');
+
+	if (formObj.width.value == "")
+		formObj.width.value = preloadImg.width;
+
+	if (formObj.height.value == "")
+		formObj.height.value = preloadImg.height;
+
+	updateStyle();
+}
+
+function resetImageData() {
+	var formObj = document.forms[0];
+	formObj.width.value = formObj.height.value = "";	
+}
+
+function getSelectValue(form_obj, field_name) {
+	var elm = form_obj.elements[field_name];
+
+	if (elm == null || elm.options == null)
+		return "";
+
+	return elm.options[elm.selectedIndex].value;
+}
+
+function getImageListHTML(elm_id, target_form_element, onchange_func) {
+	if (typeof(tinyMCEImageList) == "undefined" || tinyMCEImageList.length == 0)
+		return "";
+
+	var html = "";
+
+	html += '<select id="' + elm_id + '" name="' + elm_id + '"';
+	html += ' class="mceImageList" onfocus="tinyMCE.addSelectAccessibility(event, this, window);" onchange="this.form.' + target_form_element + '.value=';
+	html += 'this.options[this.selectedIndex].value;';
+
+	if (typeof(onchange_func) != "undefined")
+		html += onchange_func + '(\'' + target_form_element + '\',this.options[this.selectedIndex].text,this.options[this.selectedIndex].value);';
+
+	html += '"><option value="">---</option>';
+
+	for (var i=0; i<tinyMCEImageList.length; i++)
+		html += '<option value="' + tinyMCEImageList[i][1] + '">' + tinyMCEImageList[i][0] + '</option>';
+
+	html += '</select>';
+
+	return html;
+
+	// tinyMCE.debug('-- image list start --', html, '-- image list end --');
+}
+
+// While loading
+preinit();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/advimage/langs/en.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,27 @@
+// UK lang variables
+
+tinyMCE.addToLang('advimage',{
+tab_general : 'General',
+tab_appearance : 'Appearance',
+tab_advanced : 'Advanced',
+general : 'General',
+title : 'Title',
+preview : 'Preview',
+constrain_proportions : 'Constrain proportions',
+langdir : 'Language direction',
+langcode : 'Language code',
+long_desc : 'Long description link',
+style : 'Style',
+classes : 'Classes',
+ltr : 'Left to right',
+rtl : 'Right to left',
+id : 'Id',
+image_map : 'Image map',
+swap_image : 'Swap image',
+alt_image : 'Alternative image',
+mouseover : 'for mouse over',
+mouseout : 'for mouse out',
+misc : 'Miscellaneous',
+example_img : 'Appearance&nbsp;preview&nbsp;image',
+missing_alt : 'Are you sure you want to continue without including an Image Description? Without  it the image may not be accessible to some users with disabilities, or to those using a text browser, or browsing the Web with images turned off.'
+});
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/advimage/readme.txt	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+Check the TinyMCE documentation for details on this plugin.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/advlink/css/advlink.css	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,35 @@
+/* CSS file for advimage plugin popup */
+
+.mceLinkList, .mceAnchorList, #targetlist {
+	width: 280px;
+}
+
+.mceActionPanel {
+	margin-top: 7px;
+}
+
+.panel_wrapper div.current {
+	height: 320px;
+}
+
+#classlist, #title, #href {
+	width: 280px;
+}
+
+#popupurl, #popupname {
+	width: 200px;
+}
+
+#popupwidth, #popupheight, #popupleft, #popuptop {
+	width: 30px;
+	vertical-align: middle;
+	text-align: center;
+}
+
+#id, #style, #classes, #target, #dir, #hreflang, #lang, #charset, #type, #rel, #rev, #tabindex, #accesskey {
+	width: 200px;
+}
+
+#events_panel input {
+	width: 200px;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/advlink/editor_plugin.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+tinyMCE.importPluginLanguagePack('advlink');var TinyMCE_AdvancedLinkPlugin={getInfo:function(){return{longname:'Advanced link',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/advlink',version:tinyMCE.majorVersion+"."+tinyMCE.minorVersion}},initInstance:function(inst){inst.addShortcut('ctrl','k','lang_advlink_desc','mceAdvLink')},getControlHTML:function(cn){switch(cn){case"link":return tinyMCE.getButtonHTML(cn,'lang_link_desc','{$themeurl}/images/link.gif','mceAdvLink')}return""},execCommand:function(editor_id,element,command,user_interface,value){switch(command){case"mceAdvLink":var anySelection=false;var inst=tinyMCE.getInstanceById(editor_id);var focusElm=inst.getFocusElement();var selectedText=inst.selection.getSelectedText();if(tinyMCE.selectedElement)anySelection=(tinyMCE.selectedElement.nodeName.toLowerCase()=="img")||(selectedText&&selectedText.length>0);if(anySelection||(focusElm!=null&&focusElm.nodeName=="A")){var template=new Array();template['file']='../../plugins/advlink/link.htm';template['width']=480;template['height']=400;template['width']+=tinyMCE.getLang('lang_advlink_delta_width',0);template['height']+=tinyMCE.getLang('lang_advlink_delta_height',0);tinyMCE.openWindow(template,{editor_id:editor_id,inline:"yes"})}return true}return false},handleNodeChange:function(editor_id,node,undo_index,undo_levels,visual_aid,any_selection){if(node==null)return;do{if(node.nodeName=="A"&&tinyMCE.getAttrib(node,'href')!=""){tinyMCE.switchClass(editor_id+'_advlink','mceButtonSelected');return true}}while((node=node.parentNode));if(any_selection){tinyMCE.switchClass(editor_id+'_advlink','mceButtonNormal');return true}tinyMCE.switchClass(editor_id+'_advlink','mceButtonDisabled');return true}};tinyMCE.addPlugin("advlink",TinyMCE_AdvancedLinkPlugin);
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/advlink/editor_plugin_src.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,88 @@
+/**
+ * $Id: editor_plugin_src.js 201 2007-02-12 15:56:56Z spocke $
+ *
+ * @author Moxiecode
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+/* Import plugin specific language pack */
+tinyMCE.importPluginLanguagePack('advlink');
+
+var TinyMCE_AdvancedLinkPlugin = {
+	getInfo : function() {
+		return {
+			longname : 'Advanced link',
+			author : 'Moxiecode Systems AB',
+			authorurl : 'http://tinymce.moxiecode.com',
+			infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/advlink',
+			version : tinyMCE.majorVersion + "." + tinyMCE.minorVersion
+		};
+	},
+
+	initInstance : function(inst) {
+		inst.addShortcut('ctrl', 'k', 'lang_advlink_desc', 'mceAdvLink');
+	},
+
+	getControlHTML : function(cn) {
+		switch (cn) {
+			case "link":
+				return tinyMCE.getButtonHTML(cn, 'lang_link_desc', '{$themeurl}/images/link.gif', 'mceAdvLink');
+		}
+
+		return "";
+	},
+
+	execCommand : function(editor_id, element, command, user_interface, value) {
+		switch (command) {
+			case "mceAdvLink":
+				var anySelection = false;
+				var inst = tinyMCE.getInstanceById(editor_id);
+				var focusElm = inst.getFocusElement();
+				var selectedText = inst.selection.getSelectedText();
+
+				if (tinyMCE.selectedElement)
+					anySelection = (tinyMCE.selectedElement.nodeName.toLowerCase() == "img") || (selectedText && selectedText.length > 0);
+
+				if (anySelection || (focusElm != null && focusElm.nodeName == "A")) {
+					var template = new Array();
+
+					template['file']   = '../../plugins/advlink/link.htm';
+					template['width']  = 480;
+					template['height'] = 400;
+
+					// Language specific width and height addons
+					template['width']  += tinyMCE.getLang('lang_advlink_delta_width', 0);
+					template['height'] += tinyMCE.getLang('lang_advlink_delta_height', 0);
+
+					tinyMCE.openWindow(template, {editor_id : editor_id, inline : "yes"});
+				}
+
+				return true;
+		}
+
+		return false;
+	},
+
+	handleNodeChange : function(editor_id, node, undo_index, undo_levels, visual_aid, any_selection) {
+		if (node == null)
+			return;
+
+		do {
+			if (node.nodeName == "A" && tinyMCE.getAttrib(node, 'href') != "") {
+				tinyMCE.switchClass(editor_id + '_advlink', 'mceButtonSelected');
+				return true;
+			}
+		} while ((node = node.parentNode));
+
+		if (any_selection) {
+			tinyMCE.switchClass(editor_id + '_advlink', 'mceButtonNormal');
+			return true;
+		}
+
+		tinyMCE.switchClass(editor_id + '_advlink', 'mceButtonDisabled');
+
+		return true;
+	}
+};
+
+tinyMCE.addPlugin("advlink", TinyMCE_AdvancedLinkPlugin);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/advlink/jscripts/functions.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,568 @@
+/* Functions for the advlink plugin popup */
+
+var templates = {
+	"window.open" : "window.open('${url}','${target}','${options}')"
+};
+
+function preinit() {
+	// Initialize
+	tinyMCE.setWindowArg('mce_windowresize', false);
+
+	// Import external list url javascript
+	var url = tinyMCE.getParam("external_link_list_url");
+	if (url != null) {
+		// Fix relative
+		if (url.charAt(0) != '/' && url.indexOf('://') == -1)
+			url = tinyMCE.documentBasePath + "/" + url;
+
+		document.write('<sc'+'ript language="javascript" type="text/javascript" src="' + url + '"></sc'+'ript>');
+	}
+}
+
+function changeClass() {
+	var formObj = document.forms[0];
+	formObj.classes.value = getSelectValue(formObj, 'classlist');
+}
+
+function init() {
+	tinyMCEPopup.resizeToInnerSize();
+
+	var formObj = document.forms[0];
+	var inst = tinyMCE.getInstanceById(tinyMCE.getWindowArg('editor_id'));
+	var elm = inst.getFocusElement();
+	var action = "insert";
+	var html;
+
+	document.getElementById('hrefbrowsercontainer').innerHTML = getBrowserHTML('hrefbrowser','href','file','advlink');
+	document.getElementById('popupurlbrowsercontainer').innerHTML = getBrowserHTML('popupurlbrowser','popupurl','file','advlink');
+	document.getElementById('linklisthrefcontainer').innerHTML = getLinkListHTML('linklisthref','href');
+	document.getElementById('anchorlistcontainer').innerHTML = getAnchorListHTML('anchorlist','href');
+	document.getElementById('targetlistcontainer').innerHTML = getTargetListHTML('targetlist','target');
+
+	// Link list
+	html = getLinkListHTML('linklisthref','href');
+	if (html == "")
+		document.getElementById("linklisthrefrow").style.display = 'none';
+	else
+		document.getElementById("linklisthrefcontainer").innerHTML = html;
+
+	// Resize some elements
+	if (isVisible('hrefbrowser'))
+		document.getElementById('href').style.width = '260px';
+
+	if (isVisible('popupurlbrowser'))
+		document.getElementById('popupurl').style.width = '180px';
+
+	elm = tinyMCE.getParentElement(elm, "a");
+	if (elm != null && elm.nodeName == "A")
+		action = "update";
+
+	formObj.insert.value = tinyMCE.getLang('lang_' + action, 'Insert', true); 
+
+	setPopupControlsDisabled(true);
+
+	if (action == "update") {
+		var href = tinyMCE.getAttrib(elm, 'href');
+
+		href = convertURL(href, elm, true);
+
+		// Use mce_href if found
+		var mceRealHref = tinyMCE.getAttrib(elm, 'mce_href');
+		if (mceRealHref != "") {
+			href = mceRealHref;
+
+			if (tinyMCE.getParam('convert_urls'))
+				href = convertURL(href, elm, true);
+		}
+
+		var onclick = tinyMCE.cleanupEventStr(tinyMCE.getAttrib(elm, 'onclick'));
+
+		// Setup form data
+		setFormValue('href', href);
+		setFormValue('title', tinyMCE.getAttrib(elm, 'title'));
+		setFormValue('id', tinyMCE.getAttrib(elm, 'id'));
+		setFormValue('style', tinyMCE.serializeStyle(tinyMCE.parseStyle(tinyMCE.getAttrib(elm, "style"))));
+		setFormValue('rel', tinyMCE.getAttrib(elm, 'rel'));
+		setFormValue('rev', tinyMCE.getAttrib(elm, 'rev'));
+		setFormValue('charset', tinyMCE.getAttrib(elm, 'charset'));
+		setFormValue('hreflang', tinyMCE.getAttrib(elm, 'hreflang'));
+		setFormValue('dir', tinyMCE.getAttrib(elm, 'dir'));
+		setFormValue('lang', tinyMCE.getAttrib(elm, 'lang'));
+		setFormValue('tabindex', tinyMCE.getAttrib(elm, 'tabindex', typeof(elm.tabindex) != "undefined" ? elm.tabindex : ""));
+		setFormValue('accesskey', tinyMCE.getAttrib(elm, 'accesskey', typeof(elm.accesskey) != "undefined" ? elm.accesskey : ""));
+		setFormValue('type', tinyMCE.getAttrib(elm, 'type'));
+		setFormValue('onfocus', tinyMCE.cleanupEventStr(tinyMCE.getAttrib(elm, 'onfocus')));
+		setFormValue('onblur', tinyMCE.cleanupEventStr(tinyMCE.getAttrib(elm, 'onblur')));
+		setFormValue('onclick', onclick);
+		setFormValue('ondblclick', tinyMCE.cleanupEventStr(tinyMCE.getAttrib(elm, 'ondblclick')));
+		setFormValue('onmousedown', tinyMCE.cleanupEventStr(tinyMCE.getAttrib(elm, 'onmousedown')));
+		setFormValue('onmouseup', tinyMCE.cleanupEventStr(tinyMCE.getAttrib(elm, 'onmouseup')));
+		setFormValue('onmouseover', tinyMCE.cleanupEventStr(tinyMCE.getAttrib(elm, 'onmouseover')));
+		setFormValue('onmousemove', tinyMCE.cleanupEventStr(tinyMCE.getAttrib(elm, 'onmousemove')));
+		setFormValue('onmouseout', tinyMCE.cleanupEventStr(tinyMCE.getAttrib(elm, 'onmouseout')));
+		setFormValue('onkeypress', tinyMCE.cleanupEventStr(tinyMCE.getAttrib(elm, 'onkeypress')));
+		setFormValue('onkeydown', tinyMCE.cleanupEventStr(tinyMCE.getAttrib(elm, 'onkeydown')));
+		setFormValue('onkeyup', tinyMCE.cleanupEventStr(tinyMCE.getAttrib(elm, 'onkeyup')));
+		setFormValue('target', tinyMCE.getAttrib(elm, 'target'));
+		setFormValue('classes', tinyMCE.getAttrib(elm, 'class'));
+
+		// Parse onclick data
+		if (onclick != null && onclick.indexOf('window.open') != -1)
+			parseWindowOpen(onclick);
+		else
+			parseFunction(onclick);
+
+		// Select by the values
+		selectByValue(formObj, 'dir', tinyMCE.getAttrib(elm, 'dir'));
+		selectByValue(formObj, 'rel', tinyMCE.getAttrib(elm, 'rel'));
+		selectByValue(formObj, 'rev', tinyMCE.getAttrib(elm, 'rev'));
+		selectByValue(formObj, 'linklisthref', href);
+
+		if (href.charAt(0) == '#')
+			selectByValue(formObj, 'anchorlist', href);
+
+		addClassesToList('classlist', 'advlink_styles');
+
+		selectByValue(formObj, 'classlist', tinyMCE.getAttrib(elm, 'class'), true);
+		selectByValue(formObj, 'targetlist', tinyMCE.getAttrib(elm, 'target'), true);
+	} else
+		addClassesToList('classlist', 'advlink_styles');
+
+	window.focus();
+}
+
+function setFormValue(name, value) {
+	document.forms[0].elements[name].value = value;
+}
+
+function convertURL(url, node, on_save) {
+	return eval("tinyMCEPopup.windowOpener." + tinyMCE.settings['urlconverter_callback'] + "(url, node, on_save);");
+}
+
+function parseWindowOpen(onclick) {
+	var formObj = document.forms[0];
+
+	// Preprocess center code
+	if (onclick.indexOf('return false;') != -1) {
+		formObj.popupreturn.checked = true;
+		onclick = onclick.replace('return false;', '');
+	} else
+		formObj.popupreturn.checked = false;
+
+	var onClickData = parseLink(onclick);
+
+	if (onClickData != null) {
+		formObj.ispopup.checked = true;
+		setPopupControlsDisabled(false);
+
+		var onClickWindowOptions = parseOptions(onClickData['options']);
+		var url = onClickData['url'];
+
+		if (tinyMCE.getParam('convert_urls'))
+			url = convertURL(url, null, true);
+
+		formObj.popupname.value = onClickData['target'];
+		formObj.popupurl.value = url;
+		formObj.popupwidth.value = getOption(onClickWindowOptions, 'width');
+		formObj.popupheight.value = getOption(onClickWindowOptions, 'height');
+
+		formObj.popupleft.value = getOption(onClickWindowOptions, 'left');
+		formObj.popuptop.value = getOption(onClickWindowOptions, 'top');
+
+		if (formObj.popupleft.value.indexOf('screen') != -1)
+			formObj.popupleft.value = "c";
+
+		if (formObj.popuptop.value.indexOf('screen') != -1)
+			formObj.popuptop.value = "c";
+
+		formObj.popuplocation.checked = getOption(onClickWindowOptions, 'location') == "yes";
+		formObj.popupscrollbars.checked = getOption(onClickWindowOptions, 'scrollbars') == "yes";
+		formObj.popupmenubar.checked = getOption(onClickWindowOptions, 'menubar') == "yes";
+		formObj.popupresizable.checked = getOption(onClickWindowOptions, 'resizable') == "yes";
+		formObj.popuptoolbar.checked = getOption(onClickWindowOptions, 'toolbar') == "yes";
+		formObj.popupstatus.checked = getOption(onClickWindowOptions, 'status') == "yes";
+		formObj.popupdependent.checked = getOption(onClickWindowOptions, 'dependent') == "yes";
+
+		buildOnClick();
+	}
+}
+
+function parseFunction(onclick) {
+	var formObj = document.forms[0];
+	var onClickData = parseLink(onclick);
+
+	// TODO: Add stuff here
+}
+
+function getOption(opts, name) {
+	return typeof(opts[name]) == "undefined" ? "" : opts[name];
+}
+
+function setPopupControlsDisabled(state) {
+	var formObj = document.forms[0];
+
+	formObj.popupname.disabled = state;
+	formObj.popupurl.disabled = state;
+	formObj.popupwidth.disabled = state;
+	formObj.popupheight.disabled = state;
+	formObj.popupleft.disabled = state;
+	formObj.popuptop.disabled = state;
+	formObj.popuplocation.disabled = state;
+	formObj.popupscrollbars.disabled = state;
+	formObj.popupmenubar.disabled = state;
+	formObj.popupresizable.disabled = state;
+	formObj.popuptoolbar.disabled = state;
+	formObj.popupstatus.disabled = state;
+	formObj.popupreturn.disabled = state;
+	formObj.popupdependent.disabled = state;
+
+	setBrowserDisabled('popupurlbrowser', state);
+}
+
+function parseLink(link) {
+	link = link.replace(new RegExp('&#39;', 'g'), "'");
+
+	var fnName = link.replace(new RegExp("\\s*([A-Za-z0-9\.]*)\\s*\\(.*", "gi"), "$1");
+
+	// Is function name a template function
+	var template = templates[fnName];
+	if (template) {
+		// Build regexp
+		var variableNames = template.match(new RegExp("'?\\$\\{[A-Za-z0-9\.]*\\}'?", "gi"));
+		var regExp = "\\s*[A-Za-z0-9\.]*\\s*\\(";
+		var replaceStr = "";
+		for (var i=0; i<variableNames.length; i++) {
+			// Is string value
+			if (variableNames[i].indexOf("'${") != -1)
+				regExp += "'(.*)'";
+			else // Number value
+				regExp += "([0-9]*)";
+
+			replaceStr += "$" + (i+1);
+
+			// Cleanup variable name
+			variableNames[i] = variableNames[i].replace(new RegExp("[^A-Za-z0-9]", "gi"), "");
+
+			if (i != variableNames.length-1) {
+				regExp += "\\s*,\\s*";
+				replaceStr += "<delim>";
+			} else
+				regExp += ".*";
+		}
+
+		regExp += "\\);?";
+
+		// Build variable array
+		var variables = new Array();
+		variables["_function"] = fnName;
+		var variableValues = link.replace(new RegExp(regExp, "gi"), replaceStr).split('<delim>');
+		for (var i=0; i<variableNames.length; i++)
+			variables[variableNames[i]] = variableValues[i];
+
+		return variables;
+	}
+
+	return null;
+}
+
+function parseOptions(opts) {
+	if (opts == null || opts == "")
+		return new Array();
+
+	// Cleanup the options
+	opts = opts.toLowerCase();
+	opts = opts.replace(/;/g, ",");
+	opts = opts.replace(/[^0-9a-z=,]/g, "");
+
+	var optionChunks = opts.split(',');
+	var options = new Array();
+
+	for (var i=0; i<optionChunks.length; i++) {
+		var parts = optionChunks[i].split('=');
+
+		if (parts.length == 2)
+			options[parts[0]] = parts[1];
+	}
+
+	return options;
+}
+
+function buildOnClick() {
+	var formObj = document.forms[0];
+
+	if (!formObj.ispopup.checked) {
+		formObj.onclick.value = "";
+		return;
+	}
+
+	var onclick = "window.open('";
+	var url = formObj.popupurl.value;
+
+	if (tinyMCE.getParam('convert_urls'))
+		url = convertURL(url, null, true);
+
+	onclick += url + "','";
+	onclick += formObj.popupname.value + "','";
+
+	if (formObj.popuplocation.checked)
+		onclick += "location=yes,";
+
+	if (formObj.popupscrollbars.checked)
+		onclick += "scrollbars=yes,";
+
+	if (formObj.popupmenubar.checked)
+		onclick += "menubar=yes,";
+
+	if (formObj.popupresizable.checked)
+		onclick += "resizable=yes,";
+
+	if (formObj.popuptoolbar.checked)
+		onclick += "toolbar=yes,";
+
+	if (formObj.popupstatus.checked)
+		onclick += "status=yes,";
+
+	if (formObj.popupdependent.checked)
+		onclick += "dependent=yes,";
+
+	if (formObj.popupwidth.value != "")
+		onclick += "width=" + formObj.popupwidth.value + ",";
+
+	if (formObj.popupheight.value != "")
+		onclick += "height=" + formObj.popupheight.value + ",";
+
+	if (formObj.popupleft.value != "") {
+		if (formObj.popupleft.value != "c")
+			onclick += "left=" + formObj.popupleft.value + ",";
+		else
+			onclick += "left='+(screen.availWidth/2-" + (formObj.popupwidth.value/2) + ")+',";
+	}
+
+	if (formObj.popuptop.value != "") {
+		if (formObj.popuptop.value != "c")
+			onclick += "top=" + formObj.popuptop.value + ",";
+		else
+			onclick += "top='+(screen.availHeight/2-" + (formObj.popupheight.value/2) + ")+',";
+	}
+
+	if (onclick.charAt(onclick.length-1) == ',')
+		onclick = onclick.substring(0, onclick.length-1);
+
+	onclick += "');";
+
+	if (formObj.popupreturn.checked)
+		onclick += "return false;";
+
+	// tinyMCE.debug(onclick);
+
+	formObj.onclick.value = onclick;
+
+	if (formObj.href.value == "")
+		formObj.href.value = url;
+}
+
+function setAttrib(elm, attrib, value) {
+	var formObj = document.forms[0];
+	var valueElm = formObj.elements[attrib.toLowerCase()];
+
+	if (typeof(value) == "undefined" || value == null) {
+		value = "";
+
+		if (valueElm)
+			value = valueElm.value;
+	}
+
+	if (value != "") {
+		elm.setAttribute(attrib.toLowerCase(), value);
+
+		if (attrib == "style")
+			attrib = "style.cssText";
+
+		if (attrib.substring(0, 2) == 'on')
+			value = 'return true;' + value;
+
+		if (attrib == "class")
+			attrib = "className";
+
+		eval('elm.' + attrib + "=value;");
+	} else
+		elm.removeAttribute(attrib);
+}
+
+function getAnchorListHTML(id, target) {
+	var inst = tinyMCE.getInstanceById(tinyMCE.getWindowArg('editor_id'));
+	var nodes = inst.getBody().getElementsByTagName("a");
+
+	var html = "";
+
+	html += '<select id="' + id + '" name="' + id + '" class="mceAnchorList" onfocus="tinyMCE.addSelectAccessibility(event, this, window);" onchange="this.form.' + target + '.value=';
+	html += 'this.options[this.selectedIndex].value;">';
+	html += '<option value="">---</option>';
+
+	for (var i=0; i<nodes.length; i++) {
+		if ((name = tinyMCE.getAttrib(nodes[i], "name")) != "")
+			html += '<option value="#' + name + '">' + name + '</option>';
+	}
+
+	html += '</select>';
+
+	return html;
+}
+
+function insertAction() {
+	var inst = tinyMCE.getInstanceById(tinyMCE.getWindowArg('editor_id'));
+	var elm = inst.getFocusElement();
+
+	elm = tinyMCE.getParentElement(elm, "a");
+
+	tinyMCEPopup.execCommand("mceBeginUndoLevel");
+
+	// Create new anchor elements
+	if (elm == null) {
+		if (tinyMCE.isSafari)
+			tinyMCEPopup.execCommand("mceInsertContent", false, '<a href="#mce_temp_url#">' + inst.selection.getSelectedHTML() + '</a>');
+		else
+			tinyMCEPopup.execCommand("createlink", false, "#mce_temp_url#");
+
+		var elementArray = tinyMCE.getElementsByAttributeValue(inst.getBody(), "a", "href", "#mce_temp_url#");
+		for (var i=0; i<elementArray.length; i++) {
+			var elm = elementArray[i];
+
+			// Move cursor behind the new anchor
+			if (tinyMCE.isGecko) {
+				var sp = inst.getDoc().createTextNode(" ");
+
+				if (elm.nextSibling)
+					elm.parentNode.insertBefore(sp, elm.nextSibling);
+				else
+					elm.parentNode.appendChild(sp);
+
+				// Set range after link
+				var rng = inst.getDoc().createRange();
+				rng.setStartAfter(elm);
+				rng.setEndAfter(elm);
+
+				// Update selection
+				var sel = inst.getSel();
+				sel.removeAllRanges();
+				sel.addRange(rng);
+			}
+
+			setAllAttribs(elm);
+		}
+	} else
+		setAllAttribs(elm);
+
+	tinyMCE._setEventsEnabled(inst.getBody(), false);
+	tinyMCEPopup.execCommand("mceEndUndoLevel");
+	tinyMCEPopup.close();
+}
+
+function setAllAttribs(elm) {
+	var formObj = document.forms[0];
+	var href = formObj.href.value;
+	var target = getSelectValue(formObj, 'targetlist');
+
+	// Make anchors absolute
+	if (href.charAt(0) != '#')
+		href = convertURL(href, elm);
+
+	setAttrib(elm, 'href', href);
+	setAttrib(elm, 'mce_href', href);
+	setAttrib(elm, 'title');
+	setAttrib(elm, 'target', target == '_self' ? '' : target);
+	setAttrib(elm, 'id');
+	setAttrib(elm, 'style');
+	setAttrib(elm, 'class', getSelectValue(formObj, 'classlist'));
+	setAttrib(elm, 'rel');
+	setAttrib(elm, 'rev');
+	setAttrib(elm, 'charset');
+	setAttrib(elm, 'hreflang');
+	setAttrib(elm, 'dir');
+	setAttrib(elm, 'lang');
+	setAttrib(elm, 'tabindex');
+	setAttrib(elm, 'accesskey');
+	setAttrib(elm, 'type');
+	setAttrib(elm, 'onfocus');
+	setAttrib(elm, 'onblur');
+	setAttrib(elm, 'onclick');
+	setAttrib(elm, 'ondblclick');
+	setAttrib(elm, 'onmousedown');
+	setAttrib(elm, 'onmouseup');
+	setAttrib(elm, 'onmouseover');
+	setAttrib(elm, 'onmousemove');
+	setAttrib(elm, 'onmouseout');
+	setAttrib(elm, 'onkeypress');
+	setAttrib(elm, 'onkeydown');
+	setAttrib(elm, 'onkeyup');
+
+	// Refresh in old MSIE
+	if (tinyMCE.isMSIE5)
+		elm.outerHTML = elm.outerHTML;
+}
+
+function getSelectValue(form_obj, field_name) {
+	var elm = form_obj.elements[field_name];
+
+	if (elm == null || elm.options == null)
+		return "";
+
+	return elm.options[elm.selectedIndex].value;
+}
+
+function getLinkListHTML(elm_id, target_form_element, onchange_func) {
+	if (typeof(tinyMCELinkList) == "undefined" || tinyMCELinkList.length == 0)
+		return "";
+
+	var html = "";
+
+	html += '<select id="' + elm_id + '" name="' + elm_id + '"';
+	html += ' class="mceLinkList" onfocus="tinyMCE.addSelectAccessibility(event, this, window);" onchange="this.form.' + target_form_element + '.value=';
+	html += 'this.options[this.selectedIndex].value;';
+
+	if (typeof(onchange_func) != "undefined")
+		html += onchange_func + '(\'' + target_form_element + '\',this.options[this.selectedIndex].text,this.options[this.selectedIndex].value);';
+
+	html += '"><option value="">---</option>';
+
+	for (var i=0; i<tinyMCELinkList.length; i++)
+		html += '<option value="' + tinyMCELinkList[i][1] + '">' + tinyMCELinkList[i][0] + '</option>';
+
+	html += '</select>';
+
+	return html;
+
+	// tinyMCE.debug('-- image list start --', html, '-- image list end --');
+}
+
+function getTargetListHTML(elm_id, target_form_element) {
+	var targets = tinyMCE.getParam('theme_advanced_link_targets', '').split(';');
+	var html = '';
+
+	html += '<select id="' + elm_id + '" name="' + elm_id + '" onfocus="tinyMCE.addSelectAccessibility(event, this, window);" onchange="this.form.' + target_form_element + '.value=';
+	html += 'this.options[this.selectedIndex].value;">';
+
+	html += '<option value="_self">' + tinyMCE.getLang('lang_advlink_target_same') + '</option>';
+	html += '<option value="_blank">' + tinyMCE.getLang('lang_advlink_target_blank') + ' (_blank)</option>';
+	html += '<option value="_parent">' + tinyMCE.getLang('lang_advlink_target_parent') + ' (_parent)</option>';
+	html += '<option value="_top">' + tinyMCE.getLang('lang_advlink_target_top') + ' (_top)</option>';
+
+	for (var i=0; i<targets.length; i++) {
+		var key, value;
+
+		if (targets[i] == "")
+			continue;
+
+		key = targets[i].split('=')[0];
+		value = targets[i].split('=')[1];
+
+		html += '<option value="' + key + '">' + value + ' (' + key + ')</option>';
+	}
+
+	html += '</select>';
+
+	return html;
+}
+
+// While loading
+preinit();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/advlink/langs/en.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,46 @@
+// UK lang variables
+
+tinyMCE.addToLang('advlink',{
+general_tab : 'General',
+popup_tab : 'Popup',
+events_tab : 'Events',
+advanced_tab : 'Advanced',
+general_props : 'General properties',
+popup_props : 'Popup properties',
+event_props : 'Events',
+advanced_props : 'Advanced properties',
+popup_opts : 'Options',
+anchor_names : 'Anchors',
+target_same : 'Open in this window / frame',
+target_parent : 'Open in parent window / frame',
+target_top : 'Open in top frame (replaces all frames)',
+target_blank : 'Open in new window',
+popup : 'Javascript popup',
+popup_url : 'Popup URL',
+popup_name : 'Window name',
+popup_return : 'Insert \'return false\'',
+popup_scrollbars : 'Show scrollbars',
+popup_statusbar : 'Show status bar',
+popup_toolbar : 'Show toolbars',
+popup_menubar : 'Show menu bar',
+popup_location : 'Show location bar',
+popup_resizable : 'Make window resizable',
+popup_dependent : 'Dependent (Mozilla/Firefox only)',
+popup_size : 'Size',
+popup_position : 'Position (X/Y)',
+id : 'Id',
+style: 'Style',
+classes : 'Classes',
+target_name : 'Target name',
+langdir : 'Language direction',
+target_langcode : 'Target language',
+langcode : 'Language code',
+encoding : 'Target character encoding',
+mime : 'Target MIME type',
+rel : 'Relationship page to target',
+rev : 'Relationship target to page',
+tabindex : 'Tabindex',
+accesskey : 'Accesskey',
+ltr : 'Left to right',
+rtl : 'Right to left'
+});
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/advlink/link.htm	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,337 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>{$lang_insert_link_title}</title>
+	<script language="javascript" type="text/javascript" src="../../tiny_mce_popup.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/mctabs.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/form_utils.js"></script>
+	<script language="javascript" type="text/javascript" src="jscripts/functions.js"></script>
+	<link href="css/advlink.css" rel="stylesheet" type="text/css" />
+	<base target="_self" />
+</head>
+<body id="advlink" onload="tinyMCEPopup.executeOnLoad('init();');" style="display: none">
+    <form onsubmit="insertAction();return false;" action="#">
+		<div class="tabs">
+			<ul>
+				<li id="general_tab" class="current"><span><a href="javascript:mcTabs.displayTab('general_tab','general_panel');" onmousedown="return false;">{$lang_advlink_general_tab}</a></span></li>
+				<li id="popup_tab"><span><a href="javascript:mcTabs.displayTab('popup_tab','popup_panel');" onmousedown="return false;">{$lang_advlink_popup_tab}</a></span></li>
+				<li id="events_tab"><span><a href="javascript:mcTabs.displayTab('events_tab','events_panel');" onmousedown="return false;">{$lang_advlink_events_tab}</a></span></li>
+				<li id="advanced_tab"><span><a href="javascript:mcTabs.displayTab('advanced_tab','advanced_panel');" onmousedown="return false;">{$lang_advlink_advanced_tab}</a></span></li>
+			</ul>
+		</div>
+
+		<div class="panel_wrapper">
+			<div id="general_panel" class="panel current">
+				<fieldset>
+					<legend>{$lang_advlink_general_props}</legend>
+
+					<table border="0" cellpadding="4" cellspacing="0">
+						<tr>
+						  <td nowrap="nowrap"><label id="hreflabel" for="href">{$lang_insert_link_url}</label></td>
+						  <td><table border="0" cellspacing="0" cellpadding="0">
+								<tr>
+								  <td><input id="href" name="href" type="text" value="" onchange="selectByValue(this.form,'linklisthref',this.value);" /></td>
+								  <td id="hrefbrowsercontainer">&nbsp;</td>
+								</tr>
+							  </table></td>
+						</tr>
+						<tr id="linklisthrefrow">
+							<td class="column1"><label for="linklisthref">{$lang_link_list}</label></td>
+							<td colspan="2" id="linklisthrefcontainer">&nbsp;</td>
+						</tr>
+						<tr>
+							<td class="column1"><label for="anchorlist">{$lang_advlink_anchor_names}</label></td>
+							<td colspan="2" id="anchorlistcontainer">&nbsp;</td>
+						</tr>
+						<tr>
+							<td><label id="targetlistlabel" for="targetlist">{$lang_insert_link_target}</label></td>
+							<td id="targetlistcontainer">&nbsp;</td>
+						</tr>
+						<tr>
+							<td nowrap="nowrap"><label id="titlelabel" for="title">{$lang_theme_insert_link_titlefield}</label></td>
+							<td><input id="title" name="title" type="text" value="" /></td>
+						</tr>
+						<tr>
+							<td><label id="classlabel" for="classlist">{$lang_class_name}</label></td>
+							<td>
+								 <select id="classlist" name="classlist" onchange="changeClass();">
+									<option value="" selected>{$lang_not_set}</option>
+								 </select>
+							</td>
+						</tr>
+					</table>
+				</fieldset>
+			</div>
+
+			<div id="popup_panel" class="panel">
+				<fieldset>
+					<legend>{$lang_advlink_popup_props}</legend>
+
+					<input type="checkbox" id="ispopup" name="ispopup" class="radio" onclick="setPopupControlsDisabled(!this.checked);buildOnClick();" />
+					<label id="ispopuplabel" for="ispopup">{$lang_advlink_popup}</label>
+
+					<table border="0" cellpadding="0" cellspacing="4">
+						<tr>
+							<td nowrap="nowrap"><label for="popupurl">{$lang_advlink_popup_url}</label>&nbsp;</td>
+							<td>
+								<table border="0" cellspacing="0" cellpadding="0">
+									<tr>
+										<td><input type="text" name="popupurl" id="popupurl" value="" onchange="buildOnClick();" /></td>
+										<td id="popupurlbrowsercontainer">&nbsp;</td>
+									</tr>
+								</table>
+							</td>
+						</tr>
+						<tr>
+							<td nowrap="nowrap"><label for="popupname">{$lang_advlink_popup_name}</label>&nbsp;</td>
+							<td><input type="text" name="popupname" id="popupname" value="" onchange="buildOnClick();" /></td>
+						</tr>
+						<tr>
+							<td nowrap="nowrap"><label>{$lang_advlink_popup_size}</label>&nbsp;</td>
+							<td nowrap="nowrap">
+								<input type="text" id="popupwidth" name="popupwidth" value="" onchange="buildOnClick();" /> x
+								<input type="text" id="popupheight" name="popupheight" value="" onchange="buildOnClick();" /> px
+							</td>
+						</tr>
+						<tr>
+							<td nowrap="nowrap" id="labelleft"><label>{$lang_advlink_popup_position}</label>&nbsp;</td>
+							<td nowrap="nowrap">
+								<input type="text" id="popupleft" name="popupleft" value="" onchange="buildOnClick();" /> /                                
+								<input type="text" id="popuptop" name="popuptop" value="" onchange="buildOnClick();" /> (c /c = center)
+							</td>
+						</tr>
+					</table>
+
+					<fieldset>
+						<legend>{$lang_advlink_popup_opts}</legend>
+
+						<table border="0" cellpadding="0" cellspacing="4">
+							<tr>
+								<td><input type="checkbox" id="popuplocation" name="popuplocation" class="checkbox" onchange="buildOnClick();" /></td>
+								<td nowrap="nowrap"><label id="popuplocationlabel" for="popuplocation">{$lang_advlink_popup_location}</label></td>
+								<td><input type="checkbox" id="popupscrollbars" name="popupscrollbars" class="checkbox" onchange="buildOnClick();" /></td>
+								<td nowrap="nowrap"><label id="popupscrollbarslabel" for="popupscrollbars">{$lang_advlink_popup_scrollbars}</label></td>
+							</tr>
+							<tr>
+								<td><input type="checkbox" id="popupmenubar" name="popupmenubar" class="checkbox" onchange="buildOnClick();" /></td>
+								<td nowrap="nowrap"><label id="popupmenubarlabel" for="popupmenubar">{$lang_advlink_popup_menubar}</label></td>
+								<td><input type="checkbox" id="popupresizable" name="popupresizable" class="checkbox" onchange="buildOnClick();" /></td>
+								<td nowrap="nowrap"><label id="popupresizablelabel" for="popupresizable">{$lang_advlink_popup_resizable}</label></td>
+							</tr>
+							<tr>
+								<td><input type="checkbox" id="popuptoolbar" name="popuptoolbar" class="checkbox" onchange="buildOnClick();" /></td>
+								<td nowrap="nowrap"><label id="popuptoolbarlabel" for="popuptoolbar">{$lang_advlink_popup_toolbar}</label></td>
+								<td><input type="checkbox" id="popupdependent" name="popupdependent" class="checkbox" onchange="buildOnClick();" /></td>
+								<td nowrap="nowrap"><label id="popupdependentlabel" for="popupdependent">{$lang_advlink_popup_dependent}</label></td>
+							</tr>
+							<tr>
+								<td><input type="checkbox" id="popupstatus" name="popupstatus" class="checkbox" onchange="buildOnClick();" /></td>
+								<td nowrap="nowrap"><label id="popupstatuslabel" for="popupstatus">{$lang_advlink_popup_statusbar}</label></td>
+								<td><input type="checkbox" id="popupreturn" name="popupreturn" class="checkbox" onchange="buildOnClick();" checked="checked" /></td>
+								<td nowrap="nowrap"><label id="popupreturnlabel" for="popupreturn">{$lang_advlink_popup_return}</label></td>
+							</tr>
+						</table>
+					</fieldset>
+				</fieldset>
+			</div>
+
+			<div id="advanced_panel" class="panel">
+			<fieldset>
+					<legend>{$lang_advlink_advanced_props}</legend>
+
+					<table border="0" cellpadding="0" cellspacing="4">
+						<tr>
+							<td class="column1"><label id="idlabel" for="id">{$lang_advlink_id}</label></td> 
+							<td><input id="id" name="id" type="text" value="" /></td> 
+						</tr>
+
+						<tr>
+							<td><label id="stylelabel" for="style">{$lang_advlink_style}</label></td>
+							<td><input type="text" id="style" name="style" value="" /></td>
+						</tr>
+
+						<tr>
+							<td><label id="classeslabel" for="classes">{$lang_advlink_classes}</label></td>
+							<td><input type="text" id="classes" name="classes" value="" onchange="selectByValue(this.form,'classlist',this.value,true);" /></td>
+						</tr>
+
+						<tr>
+							<td><label id="targetlabel" for="target">{$lang_advlink_target_name}</label></td>
+							<td><input type="text" id="target" name="target" value="" onchange="selectByValue(this.form,'targetlist',this.value,true);" /></td>
+						</tr>
+
+						<tr>
+							<td class="column1"><label id="dirlabel" for="dir">{$lang_advlink_langdir}</label></td> 
+							<td>
+								<select id="dir" name="dir"> 
+										<option value="">{$lang_not_set}</option> 
+										<option value="ltr">{$lang_advlink_ltr}</option> 
+										<option value="rtl">{$lang_advlink_rtl}</option> 
+								</select>
+							</td> 
+						</tr>
+
+						<tr>
+							<td><label id="hreflanglabel" for="hreflang">{$lang_advlink_target_langcode}</label></td>
+							<td><input type="text" id="hreflang" name="hreflang" value="" /></td>
+						</tr>
+
+						<tr>
+							<td class="column1"><label id="langlabel" for="lang">{$lang_advlink_langcode}</label></td> 
+							<td>
+								<input id="lang" name="lang" type="text" value="" />
+							</td> 
+						</tr>
+
+						<tr>
+							<td><label id="charsetlabel" for="charset">{$lang_advlink_encoding}</label></td>
+							<td><input type="text" id="charset" name="charset" value="" /></td>
+						</tr>
+
+						<tr>
+							<td><label id="typelabel" for="type">{$lang_advlink_mime}</label></td>
+							<td><input type="text" id="type" name="type" value="" /></td>
+						</tr>
+
+						<tr>
+							<td><label id="rellabel" for="rel">{$lang_advlink_rel}</label></td>
+							<td><select id="rel" name="rel"> 
+									<option value="">{$lang_not_set}</option> 
+									<option value="lightbox">Lightbox</option> 
+									<option value="alternate">Alternate</option> 
+									<option value="designates">Designates</option> 
+									<option value="stylesheet">Stylesheet</option> 
+									<option value="start">Start</option> 
+									<option value="next">Next</option> 
+									<option value="prev">Prev</option> 
+									<option value="contents">Contents</option> 
+									<option value="index">Index</option> 
+									<option value="glossary">Glossary</option> 
+									<option value="copyright">Copyright</option> 
+									<option value="chapter">Chapter</option> 
+									<option value="subsection">Subsection</option> 
+									<option value="appendix">Appendix</option> 
+									<option value="help">Help</option> 
+									<option value="bookmark">Bookmark</option>
+									<option value="nofollow">No Follow</option>
+									<option value="tag">Tag</option>
+								</select> 
+							</td>
+						</tr>
+
+						<tr>
+							<td><label id="revlabel" for="rev">{$lang_advlink_rev}</label></td>
+							<td><select id="rev" name="rev"> 
+									<option value="">{$lang_not_set}</option> 
+									<option value="alternate">Alternate</option> 
+									<option value="designates">Designates</option> 
+									<option value="stylesheet">Stylesheet</option> 
+									<option value="start">Start</option> 
+									<option value="next">Next</option> 
+									<option value="prev">Prev</option> 
+									<option value="contents">Contents</option> 
+									<option value="index">Index</option> 
+									<option value="glossary">Glossary</option> 
+									<option value="copyright">Copyright</option> 
+									<option value="chapter">Chapter</option> 
+									<option value="subsection">Subsection</option> 
+									<option value="appendix">Appendix</option> 
+									<option value="help">Help</option> 
+									<option value="bookmark">Bookmark</option> 
+								</select> 
+							</td>
+						</tr>
+
+						<tr>
+							<td><label id="tabindexlabel" for="tabindex">{$lang_advlink_tabindex}</label></td>
+							<td><input type="text" id="tabindex" name="tabindex" value="" /></td>
+						</tr>
+
+						<tr>
+							<td><label id="accesskeylabel" for="accesskey">{$lang_advlink_accesskey}</label></td>
+							<td><input type="text" id="accesskey" name="accesskey" value="" /></td>
+						</tr>
+					</table>
+				</fieldset>
+			</div>
+
+			<div id="events_panel" class="panel">
+			<fieldset>
+					<legend>{$lang_advlink_event_props}</legend>
+
+					<table border="0" cellpadding="0" cellspacing="4">
+						<tr>
+							<td class="column1"><label for="onfocus">onfocus</label></td> 
+							<td><input id="onfocus" name="onfocus" type="text" value="" /></td> 
+						</tr>
+
+						<tr>
+							<td class="column1"><label for="onblur">onblur</label></td> 
+							<td><input id="onblur" name="onblur" type="text" value="" /></td> 
+						</tr>
+
+						<tr>
+							<td class="column1"><label for="onclick">onclick</label></td> 
+							<td><input id="onclick" name="onclick" type="text" value="" /></td> 
+						</tr>
+
+						<tr>
+							<td class="column1"><label for="ondblclick">ondblclick</label></td> 
+							<td><input id="ondblclick" name="ondblclick" type="text" value="" /></td> 
+						</tr>
+
+						<tr>
+							<td class="column1"><label for="onmousedown">onmousedown</label></td> 
+							<td><input id="onmousedown" name="onmousedown" type="text" value="" /></td> 
+						</tr>
+
+						<tr>
+							<td class="column1"><label for="onmouseup">onmouseup</label></td> 
+							<td><input id="onmouseup" name="onmouseup" type="text" value="" /></td> 
+						</tr>
+
+						<tr>
+							<td class="column1"><label for="onmouseover">onmouseover</label></td> 
+							<td><input id="onmouseover" name="onmouseover" type="text" value="" /></td> 
+						</tr>
+
+						<tr>
+							<td class="column1"><label for="onmousemove">onmousemove</label></td> 
+							<td><input id="onmousemove" name="onmousemove" type="text" value="" /></td> 
+						</tr>
+
+						<tr>
+							<td class="column1"><label for="onmouseout">onmouseout</label></td> 
+							<td><input id="onmouseout" name="onmouseout" type="text" value="" /></td> 
+						</tr>
+
+						<tr>
+							<td class="column1"><label for="onkeypress">onkeypress</label></td> 
+							<td><input id="onkeypress" name="onkeypress" type="text" value="" /></td> 
+						</tr>
+
+						<tr>
+							<td class="column1"><label for="onkeydown">onkeydown</label></td> 
+							<td><input id="onkeydown" name="onkeydown" type="text" value="" /></td> 
+						</tr>
+
+						<tr>
+							<td class="column1"><label for="onkeyup">onkeyup</label></td> 
+							<td><input id="onkeyup" name="onkeyup" type="text" value="" /></td> 
+						</tr>
+					</table>
+				</fieldset>
+			</div>
+		</div>
+
+		<div class="mceActionPanel">
+			<div style="float: left">
+				<input type="button" id="insert" name="insert" value="{$lang_insert}" onclick="insertAction();" />
+			</div>
+
+			<div style="float: right">
+				<input type="button" id="cancel" name="cancel" value="{$lang_cancel}" onclick="tinyMCEPopup.close();" />
+			</div>
+		</div>
+    </form>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/advlink/readme.txt	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+Check the TinyMCE documentation for details on this plugin.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/autosave/editor_plugin.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+tinyMCE.importPluginLanguagePack('autosave');var TinyMCE_AutoSavePlugin={getInfo:function(){return{longname:'Auto save',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/autosave',version:tinyMCE.majorVersion+"."+tinyMCE.minorVersion}},_beforeUnloadHandler:function(){var n,inst,anyDirty=false,msg=tinyMCE.getLang("lang_autosave_unload_msg");if(tinyMCE.getParam("fullscreen_is_enabled"))return;for(n in tinyMCE.instances){inst=tinyMCE.instances[n];if(!tinyMCE.isInstance(inst))continue;if(inst.isDirty())return msg}return}};window.onbeforeunload=TinyMCE_AutoSavePlugin._beforeUnloadHandler;tinyMCE.addPlugin("autosave",TinyMCE_AutoSavePlugin);
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/autosave/editor_plugin_src.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,46 @@
+/**
+ * $Id: editor_plugin_src.js 201 2007-02-12 15:56:56Z spocke $
+ *
+ * @author Moxiecode
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+/* Import plugin specific language pack */
+tinyMCE.importPluginLanguagePack('autosave');
+
+var TinyMCE_AutoSavePlugin = {
+	getInfo : function() {
+		return {
+			longname : 'Auto save',
+			author : 'Moxiecode Systems AB',
+			authorurl : 'http://tinymce.moxiecode.com',
+			infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/autosave',
+			version : tinyMCE.majorVersion + "." + tinyMCE.minorVersion
+		};
+	},
+
+	// Private plugin internal methods
+
+	_beforeUnloadHandler : function() {
+		var n, inst, anyDirty = false, msg = tinyMCE.getLang("lang_autosave_unload_msg");
+
+		if (tinyMCE.getParam("fullscreen_is_enabled"))
+			return;
+
+		for (n in tinyMCE.instances) {
+			inst = tinyMCE.instances[n];
+
+			if (!tinyMCE.isInstance(inst))
+				continue;
+
+			if (inst.isDirty())
+				return msg;
+		}
+
+		return;
+	}
+};
+
+window.onbeforeunload = TinyMCE_AutoSavePlugin._beforeUnloadHandler;
+
+tinyMCE.addPlugin("autosave", TinyMCE_AutoSavePlugin);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/autosave/langs/en.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,5 @@
+// EN lang variables
+
+tinyMCE.addToLang('',{
+autosave_unload_msg : 'The changes you made will be lost if you navigate away from this page.'
+});
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/autosave/readme.txt	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+Check the TinyMCE documentation for details on this plugin.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/bbcode/editor_plugin.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+var TinyMCE_BBCodePlugin={getInfo:function(){return{longname:'BBCode Plugin',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/bbcode',version:tinyMCE.majorVersion+"."+tinyMCE.minorVersion}},cleanup:function(type,content){var dialect=tinyMCE.getParam('bbcode_dialect','punbb').toLowerCase();switch(type){case"insert_to_editor":content=this['_'+dialect+'_bbcode2html'](content);break;case"get_from_editor":content=this['_'+dialect+'_html2bbcode'](content);break}return content},_punbb_html2bbcode:function(s){s=tinyMCE.trim(s);function rep(re,str){s=s.replace(re,str)};rep(/<a href=\"(.*?)\".*?>(.*?)<\/a>/gi,"[url]$1[/url]");rep(/<font.*?color=\"(.*?)\".*?class=\"codeStyle\".*?>(.*?)<\/font>/gi,"[code][color=$1]$2[/color][/code]");rep(/<font.*?color=\"(.*?)\".*?class=\"quoteStyle\".*?>(.*?)<\/font>/gi,"[quote][color=$1]$2[/color][/quote]");rep(/<font.*?class=\"codeStyle\".*?color=\"(.*?)\".*?>(.*?)<\/font>/gi,"[code][color=$1]$2[/color][/code]");rep(/<font.*?class=\"quoteStyle\".*?color=\"(.*?)\".*?>(.*?)<\/font>/gi,"[quote][color=$1]$2[/color][/quote]");rep(/<font.*?color=\"(.*?)\".*?>(.*?)<\/font>/gi,"[color=$1]$2[/color]");rep(/<font>(.*?)<\/font>/gi,"$1");rep(/<img.*?src=\"(.*?)\".*?\/>/gi,"[img]$1[/img]");rep(/<span class=\"codeStyle\">(.*?)<\/span>/gi,"[code]$1[/code]");rep(/<span class=\"quoteStyle\">(.*?)<\/span>/gi,"[quote]$1[/quote]");rep(/<strong class=\"codeStyle\">(.*?)<\/strong>/gi,"[code][b]$1[/b][/code]");rep(/<strong class=\"quoteStyle\">(.*?)<\/strong>/gi,"[quote][b]$1[/b][/quote]");rep(/<em class=\"codeStyle\">(.*?)<\/em>/gi,"[code][i]$1[/i][/code]");rep(/<em class=\"quoteStyle\">(.*?)<\/em>/gi,"[quote][i]$1[/i][/quote]");rep(/<u class=\"codeStyle\">(.*?)<\/u>/gi,"[code][u]$1[/u][/code]");rep(/<u class=\"quoteStyle\">(.*?)<\/u>/gi,"[quote][u]$1[/u][/quote]");rep(/<\/(strong|b)>/gi,"[/b]");rep(/<(strong|b)>/gi,"[b]");rep(/<\/(em|i)>/gi,"[/i]");rep(/<(em|i)>/gi,"[i]");rep(/<\/u>/gi,"[/u]");rep(/<u>/gi,"[u]");rep(/<br \/>/gi,"\n");rep(/<br\/>/gi,"\n");rep(/<br>/gi,"\n");rep(/<p>/gi,"");rep(/<\/p>/gi,"\n");rep(/&nbsp;/gi," ");rep(/&quot;/gi,"\"");rep(/&lt;/gi,"<");rep(/&gt;/gi,">");rep(/&amp;/gi,"&");rep(/&undefined;/gi,"'");return s},_punbb_bbcode2html:function(s){s=tinyMCE.trim(s);function rep(re,str){s=s.replace(re,str)};rep(/\n/gi,"<br />");rep(/\[b\]/gi,"<strong>");rep(/\[\/b\]/gi,"</strong>");rep(/\[i\]/gi,"<em>");rep(/\[\/i\]/gi,"</em>");rep(/\[u\]/gi,"<u>");rep(/\[\/u\]/gi,"</u>");rep(/\[url\](.*?)\[\/url\]/gi,"<a href=\"$1\">$1</a>");rep(/\[img\](.*?)\[\/img\]/gi,"<img src=\"$1\" />");rep(/\[color=(.*?)\](.*?)\[\/color\]/gi,"<font color=\"$1\">$2</font>");rep(/\[code\](.*?)\[\/code\]/gi,"<span class=\"codeStyle\">$1</span>&nbsp;");rep(/\[quote.*?\](.*?)\[\/quote\]/gi,"<span class=\"quoteStyle\">$1</span>&nbsp;");return s}};tinyMCE.addPlugin("bbcode",TinyMCE_BBCodePlugin);
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/bbcode/editor_plugin_src.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,102 @@
+var TinyMCE_BBCodePlugin = {
+	getInfo : function() {
+		return {
+			longname : 'BBCode Plugin',
+			author : 'Moxiecode Systems AB',
+			authorurl : 'http://tinymce.moxiecode.com',
+			infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/bbcode',
+			version : tinyMCE.majorVersion + "." + tinyMCE.minorVersion
+		};
+	},
+
+	cleanup : function(type, content) {
+		var dialect = tinyMCE.getParam('bbcode_dialect', 'punbb').toLowerCase();
+
+		switch (type) {
+			case "insert_to_editor":
+				content = this['_' + dialect + '_bbcode2html'](content);
+				break;
+
+			case "get_from_editor":
+				content = this['_' + dialect + '_html2bbcode'](content);
+				break;
+		}
+
+		return content;
+	},
+
+	// Private methods
+
+	// HTML -> BBCode in PunBB dialect
+	_punbb_html2bbcode : function(s) {
+		s = tinyMCE.trim(s);
+
+		function rep(re, str) {
+			s = s.replace(re, str);
+		};
+
+		// example: <strong> to [b]
+		rep(/<a href=\"(.*?)\".*?>(.*?)<\/a>/gi,"[url]$1[/url]");
+		rep(/<font.*?color=\"(.*?)\".*?class=\"codeStyle\".*?>(.*?)<\/font>/gi,"[code][color=$1]$2[/color][/code]");
+		rep(/<font.*?color=\"(.*?)\".*?class=\"quoteStyle\".*?>(.*?)<\/font>/gi,"[quote][color=$1]$2[/color][/quote]");
+		rep(/<font.*?class=\"codeStyle\".*?color=\"(.*?)\".*?>(.*?)<\/font>/gi,"[code][color=$1]$2[/color][/code]");
+		rep(/<font.*?class=\"quoteStyle\".*?color=\"(.*?)\".*?>(.*?)<\/font>/gi,"[quote][color=$1]$2[/color][/quote]");
+		rep(/<font.*?color=\"(.*?)\".*?>(.*?)<\/font>/gi,"[color=$1]$2[/color]");
+		rep(/<font>(.*?)<\/font>/gi,"$1");
+		rep(/<img.*?src=\"(.*?)\".*?\/>/gi,"[img]$1[/img]");
+		rep(/<span class=\"codeStyle\">(.*?)<\/span>/gi,"[code]$1[/code]");
+		rep(/<span class=\"quoteStyle\">(.*?)<\/span>/gi,"[quote]$1[/quote]");
+		rep(/<strong class=\"codeStyle\">(.*?)<\/strong>/gi,"[code][b]$1[/b][/code]");
+		rep(/<strong class=\"quoteStyle\">(.*?)<\/strong>/gi,"[quote][b]$1[/b][/quote]");
+		rep(/<em class=\"codeStyle\">(.*?)<\/em>/gi,"[code][i]$1[/i][/code]");
+		rep(/<em class=\"quoteStyle\">(.*?)<\/em>/gi,"[quote][i]$1[/i][/quote]");
+		rep(/<u class=\"codeStyle\">(.*?)<\/u>/gi,"[code][u]$1[/u][/code]");
+		rep(/<u class=\"quoteStyle\">(.*?)<\/u>/gi,"[quote][u]$1[/u][/quote]");
+		rep(/<\/(strong|b)>/gi,"[/b]");
+		rep(/<(strong|b)>/gi,"[b]");
+		rep(/<\/(em|i)>/gi,"[/i]");
+		rep(/<(em|i)>/gi,"[i]");
+		rep(/<\/u>/gi,"[/u]");
+		rep(/<u>/gi,"[u]");
+		rep(/<br \/>/gi,"\n");
+		rep(/<br\/>/gi,"\n");
+		rep(/<br>/gi,"\n");
+		rep(/<p>/gi,"");
+		rep(/<\/p>/gi,"\n");
+		rep(/&nbsp;/gi," ");
+		rep(/&quot;/gi,"\"");
+		rep(/&lt;/gi,"<");
+		rep(/&gt;/gi,">");
+		rep(/&amp;/gi,"&");
+		rep(/&undefined;/gi,"'"); // quickfix
+
+		return s; 
+	},
+
+	// BBCode -> HTML from PunBB dialect
+	_punbb_bbcode2html : function(s) {
+		s = tinyMCE.trim(s);
+
+		function rep(re, str) {
+			s = s.replace(re, str);
+		};
+
+		// example: [b] to <strong>
+		rep(/\n/gi,"<br />");
+		rep(/\[b\]/gi,"<strong>");
+		rep(/\[\/b\]/gi,"</strong>");
+		rep(/\[i\]/gi,"<em>");
+		rep(/\[\/i\]/gi,"</em>");
+		rep(/\[u\]/gi,"<u>");
+		rep(/\[\/u\]/gi,"</u>");
+		rep(/\[url\](.*?)\[\/url\]/gi,"<a href=\"$1\">$1</a>");
+		rep(/\[img\](.*?)\[\/img\]/gi,"<img src=\"$1\" />");
+		rep(/\[color=(.*?)\](.*?)\[\/color\]/gi,"<font color=\"$1\">$2</font>");
+		rep(/\[code\](.*?)\[\/code\]/gi,"<span class=\"codeStyle\">$1</span>&nbsp;");
+		rep(/\[quote.*?\](.*?)\[\/quote\]/gi,"<span class=\"quoteStyle\">$1</span>&nbsp;");
+
+		return s; 
+	}
+};
+
+tinyMCE.addPlugin("bbcode", TinyMCE_BBCodePlugin);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/cleanup/editor_plugin_src.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,10 @@
+/**
+ * $Id: editor_plugin_src.js 162 2007-01-03 16:16:52Z spocke $
+ *
+ * Experimental plugin for new Cleanup routine, this logic will be moved into the core ones it's stable enougth.
+ *
+ * @author Moxiecode
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+/* Dummy file since cleanup is now moved to core */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/cleanup/readme.txt	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+Dummy plugin since cleanup is now moved into core.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/contextmenu/css/contextmenu.css	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,74 @@
+.contextMenuIEPopup {
+	padding: 0;
+	margin: 0;
+	border: 0;
+	overflow: hidden;
+}
+
+.contextMenu {
+	position: absolute;
+	cursor: default;
+	z-index: 1000;
+	border: 1px solid #D4D0C8;
+	background-color: #FFFFFF;
+}
+
+.contextMenuItem, .contextMenuItemOver {
+}
+
+.contextMenuSeparator {
+	width: 100%;
+	background-color: #D4D0C8;
+	border: 0;
+}
+
+.contextMenuImage, .contextMenuItemDisabled {
+	border: 0;
+}
+
+.contextMenuIcon {
+	background-color: #F0F0EE;
+}
+
+.contextMenuItemOver .contextMenuIcon {
+	background-color: #B6BDD2;
+}
+
+.contextMenuIcon {
+	background-color: #F0F0EE;
+}
+
+.contextMenuItemDisabled img {
+	filter:progid:DXImageTransform.Microsoft.Alpha(opacity=30);
+	-moz-opacity:0.3;
+	opacity: 0.3;
+}
+
+.contextMenuText {
+	font-family: Tahoma, Verdana, Arial, Helvetica;
+	font-size: 11px;
+	line-height: 20px;
+}
+
+.contextMenuItemDisabled {
+	color: #AAAAAA;
+}
+
+.contextMenuText a {
+	display: block;
+	line-height: 20px;
+	width: 100%;
+	text-decoration: none;
+	color: black;
+	font-weight: normal;
+	margin: 0;
+	padding: 0;
+}
+
+.contextMenuText a:hover {
+	background-color: #B6BDD2;
+	text-decoration: none !important;
+	font-weight: normal;
+	margin: 0;
+	padding: 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/contextmenu/editor_plugin.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+if(!tinyMCE.settings['contextmenu_skip_plugin_css']){tinyMCE.loadCSS(tinyMCE.baseURL+"/plugins/contextmenu/css/contextmenu.css")}var TinyMCE_ContextMenuPlugin={_contextMenu:null,getInfo:function(){return{longname:'Context menus',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/contextmenu',version:tinyMCE.majorVersion+"."+tinyMCE.minorVersion}},initInstance:function(inst){if(tinyMCE.isMSIE5_0&&tinyMCE.isOpera)return;TinyMCE_ContextMenuPlugin._contextMenu=new TinyMCE_ContextMenu({commandhandler:"TinyMCE_ContextMenuPlugin._commandHandler",spacer_image:tinyMCE.baseURL+"/plugins/contextmenu/images/spacer.gif"});tinyMCE.addEvent(inst.getDoc(),"click",TinyMCE_ContextMenuPlugin._hideContextMenu);tinyMCE.addEvent(inst.getDoc(),"keypress",TinyMCE_ContextMenuPlugin._hideContextMenu);tinyMCE.addEvent(inst.getDoc(),"keydown",TinyMCE_ContextMenuPlugin._hideContextMenu);tinyMCE.addEvent(document,"click",TinyMCE_ContextMenuPlugin._hideContextMenu);tinyMCE.addEvent(document,"keypress",TinyMCE_ContextMenuPlugin._hideContextMenu);tinyMCE.addEvent(document,"keydown",TinyMCE_ContextMenuPlugin._hideContextMenu);if(tinyMCE.isGecko){tinyMCE.addEvent(inst.getDoc(),"contextmenu",function(e){TinyMCE_ContextMenuPlugin._showContextMenu(tinyMCE.isMSIE?inst.contentWindow.event:e,inst)})}else tinyMCE.addEvent(inst.getDoc(),"contextmenu",TinyMCE_ContextMenuPlugin._onContextMenu)},_onContextMenu:function(e){var elm=tinyMCE.isMSIE?e.srcElement:e.target;var targetInst,body;if((body=tinyMCE.getParentElement(elm,"body"))!=null){for(var n in tinyMCE.instances){var inst=tinyMCE.instances[n];if(!tinyMCE.isInstance(inst))continue;if(body==inst.getBody()){targetInst=inst;break}}return TinyMCE_ContextMenuPlugin._showContextMenu(tinyMCE.isMSIE?targetInst.contentWindow.event:e,targetInst)}},_showContextMenu:function(e,inst){function getAttrib(elm,name){return elm.getAttribute(name)?elm.getAttribute(name):""}var x,y,elm,contextMenu;var pos=tinyMCE.getAbsPosition(inst.iframeElement);x=tinyMCE.isMSIE?e.screenX:pos.absLeft+(e.pageX-inst.getBody().scrollLeft);y=tinyMCE.isMSIE?e.screenY:pos.absTop+(e.pageY-inst.getBody().scrollTop);elm=tinyMCE.isMSIE?e.srcElement:e.target;contextMenu=this._contextMenu;contextMenu.inst=inst;window.setTimeout(function(){var theme=tinyMCE.getParam("theme");contextMenu.clearAll();var sel=inst.selection.getSelectedText().length!=0||elm.nodeName=="IMG";contextMenu.addItem(tinyMCE.baseURL+"/themes/"+theme+"/images/cut.gif","$lang_cut_desc","Cut","",!sel);contextMenu.addItem(tinyMCE.baseURL+"/themes/"+theme+"/images/copy.gif","$lang_copy_desc","Copy","",!sel);contextMenu.addItem(tinyMCE.baseURL+"/themes/"+theme+"/images/paste.gif","$lang_paste_desc","Paste","",false);if(sel||(elm?(elm.nodeName=='A'&&tinyMCE.getAttrib(elm,'name')=='')||(elm.nodeName=='IMG'):false)){contextMenu.addSeparator();contextMenu.addItem(tinyMCE.baseURL+"/themes/advanced/images/link.gif","$lang_link_desc",inst.hasPlugin("advlink")?"mceAdvLink":"mceLink");contextMenu.addItem(tinyMCE.baseURL+"/themes/advanced/images/unlink.gif","$lang_unlink_desc","unlink","",(elm?(elm.nodeName!='A')&&(elm.nodeName!='IMG'):true))}elm=tinyMCE.getParentElement(elm,"img,table,td"+(inst.hasPlugin("advhr")?',hr':''));if(elm){switch(elm.nodeName){case"IMG":contextMenu.addSeparator();if(tinyMCE.hasPlugin('flash')&&tinyMCE.getAttrib(elm,'class').indexOf('mceItemFlash')!=-1)contextMenu.addItem(tinyMCE.baseURL+"/plugins/flash/images/flash.gif","$lang_flash_props","mceFlash");else if(tinyMCE.hasPlugin('media')&&/mceItem(Flash|ShockWave|WindowsMedia|QuickTime|RealMedia)/.test(tinyMCE.getAttrib(elm,'class')))contextMenu.addItem(tinyMCE.baseURL+"/plugins/flash/images/flash.gif","$lang_media_title","mceMedia");else contextMenu.addItem(tinyMCE.baseURL+"/themes/"+theme+"/images/image.gif","$lang_image_props_desc",inst.hasPlugin("advimage")?"mceAdvImage":"mceImage");break;case"HR":contextMenu.addSeparator();contextMenu.addItem(tinyMCE.baseURL+"/plugins/advhr/images/advhr.gif","$lang_insert_advhr_desc","mceAdvancedHr");break;case"TABLE":case"TD":if(inst.hasPlugin("table")){var colspan=(elm.nodeName=="TABLE")?"":getAttrib(elm,"colspan");var rowspan=(elm.nodeName=="TABLE")?"":getAttrib(elm,"rowspan");colspan=colspan==""?"1":colspan;rowspan=rowspan==""?"1":rowspan;contextMenu.addSeparator();contextMenu.addItem(tinyMCE.baseURL+"/themes/"+theme+"/images/cut.gif","$lang_table_cut_row_desc","mceTableCutRow");contextMenu.addItem(tinyMCE.baseURL+"/themes/"+theme+"/images/copy.gif","$lang_table_copy_row_desc","mceTableCopyRow");contextMenu.addItem(tinyMCE.baseURL+"/themes/"+theme+"/images/paste.gif","$lang_table_paste_row_before_desc","mceTablePasteRowBefore","",inst.tableRowClipboard==null);contextMenu.addItem(tinyMCE.baseURL+"/themes/"+theme+"/images/paste.gif","$lang_table_paste_row_after_desc","mceTablePasteRowAfter","",inst.tableRowClipboard==null);contextMenu.addSeparator();contextMenu.addItem(tinyMCE.baseURL+"/plugins/table/images/table.gif","$lang_table_desc","mceInsertTable","insert");contextMenu.addItem(tinyMCE.baseURL+"/plugins/table/images/table.gif","$lang_table_props_desc","mceInsertTable");contextMenu.addItem(tinyMCE.baseURL+"/plugins/table/images/table_cell_props.gif","$lang_table_cell_desc","mceTableCellProps");contextMenu.addItem(tinyMCE.baseURL+"/plugins/table/images/table_delete.gif","$lang_table_del","mceTableDelete");contextMenu.addSeparator();contextMenu.addItem(tinyMCE.baseURL+"/plugins/table/images/table_row_props.gif","$lang_table_row_desc","mceTableRowProps");contextMenu.addItem(tinyMCE.baseURL+"/plugins/table/images/table_insert_row_before.gif","$lang_table_row_before_desc","mceTableInsertRowBefore");contextMenu.addItem(tinyMCE.baseURL+"/plugins/table/images/table_insert_row_after.gif","$lang_table_row_after_desc","mceTableInsertRowAfter");contextMenu.addItem(tinyMCE.baseURL+"/plugins/table/images/table_delete_row.gif","$lang_table_delete_row_desc","mceTableDeleteRow");contextMenu.addSeparator();contextMenu.addItem(tinyMCE.baseURL+"/plugins/table/images/table_insert_col_before.gif","$lang_table_col_before_desc","mceTableInsertColBefore");contextMenu.addItem(tinyMCE.baseURL+"/plugins/table/images/table_insert_col_after.gif","$lang_table_col_after_desc","mceTableInsertColAfter");contextMenu.addItem(tinyMCE.baseURL+"/plugins/table/images/table_delete_col.gif","$lang_table_delete_col_desc","mceTableDeleteCol");contextMenu.addSeparator();contextMenu.addItem(tinyMCE.baseURL+"/plugins/table/images/table_split_cells.gif","$lang_table_split_cells_desc","mceTableSplitCells","",(colspan=="1"&&rowspan=="1"));contextMenu.addItem(tinyMCE.baseURL+"/plugins/table/images/table_merge_cells.gif","$lang_table_merge_cells_desc","mceTableMergeCells","",false)}break}}else{if(inst.hasPlugin("table")){contextMenu.addSeparator();contextMenu.addItem(tinyMCE.baseURL+"/plugins/table/images/table.gif","$lang_table_desc","mceInsertTable","insert")}}contextMenu.show(x,y)},10);tinyMCE.cancelEvent(e);return false},_hideContextMenu:function(){if(TinyMCE_ContextMenuPlugin._contextMenu)TinyMCE_ContextMenuPlugin._contextMenu.hide()},_commandHandler:function(command,value){var cm=TinyMCE_ContextMenuPlugin._contextMenu;cm.hide();var ui=false;if(command=="mceInsertTable"||command=="mceTableCellProps"||command=="mceTableRowProps"||command=="mceTableMergeCells")ui=true;if(command=="Paste")value=null;if(tinyMCE.getParam("dialog_type")=="modal"&&tinyMCE.isMSIE){window.setTimeout(function(){cm.inst.execCommand(command,ui,value)},100)}else cm.inst.execCommand(command,ui,value)}};tinyMCE.addPlugin("contextmenu",TinyMCE_ContextMenuPlugin);function TinyMCE_ContextMenu(settings){var doc,self=this;function defParam(key,def_val){settings[key]=typeof(settings[key])!="undefined"?settings[key]:def_val}this.isMSIE=(navigator.appName=="Microsoft Internet Explorer");this.contextMenuDiv=document.createElement("div");this.contextMenuDiv.className="contextMenu";this.contextMenuDiv.setAttribute("class","contextMenu");this.contextMenuDiv.style.display="none";this.contextMenuDiv.style.position='absolute';this.contextMenuDiv.style.zindex=1000;this.contextMenuDiv.style.left='0';this.contextMenuDiv.style.top='0';this.contextMenuDiv.unselectable="on";document.body.appendChild(this.contextMenuDiv);defParam("commandhandler","");defParam("spacer_image","images/spacer.gif");this.items=new Array();this.settings=settings;this.html="";if(tinyMCE.isMSIE&&!tinyMCE.isMSIE5_0&&!tinyMCE.isOpera){this.pop=window.createPopup();doc=this.pop.document;doc.open();doc.write('<html><head><link href="'+tinyMCE.baseURL+'/plugins/contextmenu/css/contextmenu.css" rel="stylesheet" type="text/css" /></head><body unselectable="yes" class="contextMenuIEPopup"></body></html>');doc.close()}};TinyMCE_ContextMenu.prototype={clearAll:function(){this.html="";this.contextMenuDiv.innerHTML=""},addSeparator:function(){this.html+='<tr class="contextMenuItem"><td class="contextMenuIcon"><img src="'+this.settings['spacer_image']+'" width="20" height="1" class="contextMenuImage" /></td><td><img class="contextMenuSeparator" width="1" height="1" src="'+this.settings['spacer_image']+'" /></td></tr>'},addItem:function(icon,title,command,value,disabled){if(title.charAt(0)=='$')title=tinyMCE.getLang(title.substring(1));var onMouseDown='';var html='';if(tinyMCE.isMSIE&&!tinyMCE.isMSIE5_0)onMouseDown='contextMenu.execCommand(\''+command+'\', \''+value+'\');return false;';else onMouseDown=this.settings['commandhandler']+'(\''+command+'\', \''+value+'\');return false;';if(icon=="")icon=this.settings['spacer_image'];if(!disabled)html+='<tr class="contextMenuItem">';else html+='<tr class="contextMenuItemDisabled">';html+='<td class="contextMenuIcon"><img src="'+icon+'" width="20" height="20" class="contextMenuImage" /></td>';html+='<td><div class="contextMenuText">';html+='<a href="javascript:void(0);" onclick="'+onMouseDown+'" onmousedown="return false;">&#160;';html+=title;html+='&#160;</a>';html+='</div></td>';html+='</tr>';this.html+=html},show:function(x,y){var vp,width,height,yo;if(this.html=="")return;var html='';html+='<a href="#"></a><table border="0" cellpadding="0" cellspacing="0">';html+=this.html;html+='</table>';this.contextMenuDiv.innerHTML=html;this.contextMenuDiv.style.display="block";width=this.contextMenuDiv.offsetWidth;height=this.contextMenuDiv.offsetHeight;this.contextMenuDiv.style.display="none";if(tinyMCE.isMSIE&&!tinyMCE.isMSIE5_0&&!tinyMCE.isOpera){this.pop.document.body.innerHTML='<div class="contextMenu">'+html+"</div>";this.pop.document.tinyMCE=tinyMCE;this.pop.document.contextMenu=this;this.pop.show(x,y,width,height)}else{vp=this.getViewPort();yo=tinyMCE.isMSIE5_0?document.body.scrollTop:self.pageYOffset;this.contextMenuDiv.style.left=(x>vp.left+vp.width-width?vp.left+vp.width-width:x)+'px';this.contextMenuDiv.style.top=(y>vp.top+vp.height-height?vp.top+vp.height-height:y)+'px';this.contextMenuDiv.style.display="block"}},getViewPort:function(){return{left:self.pageXOffset||self.document.documentElement.scrollLeft||self.document.body.scrollLeft,top:self.pageYOffset||self.document.documentElement.scrollTop||self.document.body.scrollTop,width:document.documentElement.offsetWidth||document.body.offsetWidth,height:self.innerHeight||document.documentElement.clientHeight||document.body.clientHeight}},hide:function(){if(tinyMCE.isMSIE&&!tinyMCE.isMSIE5_0&&!tinyMCE.isOpera)this.pop.hide();else this.contextMenuDiv.style.display="none"},execCommand:function(command,value){eval(this.settings['commandhandler']+"(command, value);")}};
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/contextmenu/editor_plugin_src.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,357 @@
+/**
+ * $Id: editor_plugin_src.js 201 2007-02-12 15:56:56Z spocke $
+ *
+ * @author Moxiecode
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+/* Import plugin specific language pack */
+if (!tinyMCE.settings['contextmenu_skip_plugin_css']) {
+	tinyMCE.loadCSS(tinyMCE.baseURL + "/plugins/contextmenu/css/contextmenu.css");
+}
+
+var TinyMCE_ContextMenuPlugin = {
+	// Private fields
+	_contextMenu : null,
+
+	getInfo : function() {
+		return {
+			longname : 'Context menus',
+			author : 'Moxiecode Systems AB',
+			authorurl : 'http://tinymce.moxiecode.com',
+			infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/contextmenu',
+			version : tinyMCE.majorVersion + "." + tinyMCE.minorVersion
+		};
+	},
+
+	initInstance : function(inst) {
+		// Is not working on MSIE 5.0 or Opera no contextmenu event
+		if (tinyMCE.isMSIE5_0 && tinyMCE.isOpera)
+			return;
+
+		TinyMCE_ContextMenuPlugin._contextMenu = new TinyMCE_ContextMenu({
+			commandhandler : "TinyMCE_ContextMenuPlugin._commandHandler",
+			spacer_image : tinyMCE.baseURL + "/plugins/contextmenu/images/spacer.gif"
+		});
+
+		// Add hide event handles
+		tinyMCE.addEvent(inst.getDoc(), "click", TinyMCE_ContextMenuPlugin._hideContextMenu);
+		tinyMCE.addEvent(inst.getDoc(), "keypress", TinyMCE_ContextMenuPlugin._hideContextMenu);
+		tinyMCE.addEvent(inst.getDoc(), "keydown", TinyMCE_ContextMenuPlugin._hideContextMenu);
+		tinyMCE.addEvent(document, "click", TinyMCE_ContextMenuPlugin._hideContextMenu);
+		tinyMCE.addEvent(document, "keypress", TinyMCE_ContextMenuPlugin._hideContextMenu);
+		tinyMCE.addEvent(document, "keydown", TinyMCE_ContextMenuPlugin._hideContextMenu);
+
+		// Attach contextmenu event
+		if (tinyMCE.isGecko) {
+			tinyMCE.addEvent(inst.getDoc(), "contextmenu", function(e) {TinyMCE_ContextMenuPlugin._showContextMenu(tinyMCE.isMSIE ? inst.contentWindow.event : e, inst);});
+		} else
+			tinyMCE.addEvent(inst.getDoc(), "contextmenu", TinyMCE_ContextMenuPlugin._onContextMenu);
+	},
+
+	// Private plugin internal methods
+
+	_onContextMenu : function(e) {
+		var elm = tinyMCE.isMSIE ? e.srcElement : e.target;
+		var targetInst, body;
+
+		// Find instance
+		if ((body = tinyMCE.getParentElement(elm, "body")) != null) {
+			for (var n in tinyMCE.instances) {
+				var inst = tinyMCE.instances[n];
+				if (!tinyMCE.isInstance(inst))
+					continue;
+
+				if (body == inst.getBody()) {
+					targetInst = inst;
+					break;
+				}
+			}
+
+			return TinyMCE_ContextMenuPlugin._showContextMenu(tinyMCE.isMSIE ? targetInst.contentWindow.event : e, targetInst);
+		}
+	},
+
+	_showContextMenu : function(e, inst) {
+		function getAttrib(elm, name) {
+			return elm.getAttribute(name) ? elm.getAttribute(name) : "";
+		}
+
+		var x, y, elm, contextMenu;
+		var pos = tinyMCE.getAbsPosition(inst.iframeElement);
+
+		x = tinyMCE.isMSIE ? e.screenX : pos.absLeft + (e.pageX - inst.getBody().scrollLeft);
+		y = tinyMCE.isMSIE ? e.screenY : pos.absTop + (e.pageY - inst.getBody().scrollTop);
+		elm = tinyMCE.isMSIE ? e.srcElement : e.target;
+
+		contextMenu = this._contextMenu;
+		contextMenu.inst = inst;
+
+		// Mozilla needs some time
+		window.setTimeout(function () {
+			var theme = tinyMCE.getParam("theme");
+
+			contextMenu.clearAll();
+			var sel = inst.selection.getSelectedText().length != 0 || elm.nodeName == "IMG";
+
+			// Default items
+			contextMenu.addItem(tinyMCE.baseURL + "/themes/" + theme + "/images/cut.gif", "$lang_cut_desc", "Cut", "", !sel);
+			contextMenu.addItem(tinyMCE.baseURL + "/themes/" + theme + "/images/copy.gif", "$lang_copy_desc", "Copy", "", !sel);
+			contextMenu.addItem(tinyMCE.baseURL + "/themes/" + theme + "/images/paste.gif", "$lang_paste_desc", "Paste", "", false);
+
+			if (sel || (elm ? (elm.nodeName == 'A' && tinyMCE.getAttrib(elm, 'name') == '') || (elm.nodeName == 'IMG') : false)) {
+				contextMenu.addSeparator();
+				contextMenu.addItem(tinyMCE.baseURL + "/themes/advanced/images/link.gif", "$lang_link_desc", inst.hasPlugin("advlink") ? "mceAdvLink" : "mceLink");
+				contextMenu.addItem(tinyMCE.baseURL + "/themes/advanced/images/unlink.gif", "$lang_unlink_desc", "unlink", "", (elm ? (elm.nodeName != 'A') && (elm.nodeName != 'IMG') : true));
+			}
+
+			// Get element
+			elm = tinyMCE.getParentElement(elm, "img,table,td" + (inst.hasPlugin("advhr") ? ',hr' : ''));
+			if (elm) {
+				switch (elm.nodeName) {
+					case "IMG":
+						contextMenu.addSeparator();
+
+						// If flash
+						if (tinyMCE.hasPlugin('flash') && tinyMCE.getAttrib(elm, 'class').indexOf('mceItemFlash') != -1)
+							contextMenu.addItem(tinyMCE.baseURL + "/plugins/flash/images/flash.gif", "$lang_flash_props", "mceFlash");
+						else if (tinyMCE.hasPlugin('media') && /mceItem(Flash|ShockWave|WindowsMedia|QuickTime|RealMedia)/.test(tinyMCE.getAttrib(elm, 'class')))
+							contextMenu.addItem(tinyMCE.baseURL + "/plugins/flash/images/flash.gif", "$lang_media_title", "mceMedia");
+						else
+							contextMenu.addItem(tinyMCE.baseURL + "/themes/" + theme + "/images/image.gif", "$lang_image_props_desc", inst.hasPlugin("advimage") ? "mceAdvImage" : "mceImage");
+						break;
+
+					case "HR":
+						contextMenu.addSeparator();
+						contextMenu.addItem(tinyMCE.baseURL + "/plugins/advhr/images/advhr.gif", "$lang_insert_advhr_desc", "mceAdvancedHr");
+						break;
+
+					case "TABLE":
+					case "TD":
+						// Is table plugin loaded
+						if (inst.hasPlugin("table")) {
+							var colspan = (elm.nodeName == "TABLE") ? "" : getAttrib(elm, "colspan");
+							var rowspan = (elm.nodeName == "TABLE") ? "" : getAttrib(elm, "rowspan");
+
+							colspan = colspan == "" ? "1" : colspan;
+							rowspan = rowspan == "" ? "1" : rowspan;
+
+							contextMenu.addSeparator();
+							contextMenu.addItem(tinyMCE.baseURL + "/themes/" + theme + "/images/cut.gif", "$lang_table_cut_row_desc", "mceTableCutRow");
+							contextMenu.addItem(tinyMCE.baseURL + "/themes/" + theme + "/images/copy.gif", "$lang_table_copy_row_desc", "mceTableCopyRow");
+							contextMenu.addItem(tinyMCE.baseURL + "/themes/" + theme + "/images/paste.gif", "$lang_table_paste_row_before_desc", "mceTablePasteRowBefore", "", inst.tableRowClipboard == null);
+							contextMenu.addItem(tinyMCE.baseURL + "/themes/" + theme + "/images/paste.gif", "$lang_table_paste_row_after_desc", "mceTablePasteRowAfter", "", inst.tableRowClipboard == null);
+
+	/*						contextMenu.addItem(tinyMCE.baseURL + "/themes/" + theme + "/images/justifyleft.gif", "$lang_justifyleft_desc", "JustifyLeft", "", false);
+							contextMenu.addItem(tinyMCE.baseURL + "/themes/" + theme + "/images/justifycenter.gif", "$lang_justifycenter_desc", "JustifyCenter", "", false);
+							contextMenu.addItem(tinyMCE.baseURL + "/themes/" + theme + "/images/justifyright.gif", "$lang_justifyright_desc", "JustifyRight", "", false);
+							contextMenu.addItem(tinyMCE.baseURL + "/themes/" + theme + "/images/justifyfull.gif", "$lang_justifyfull_desc", "JustifyFull", "", false);*/
+							contextMenu.addSeparator();
+							contextMenu.addItem(tinyMCE.baseURL + "/plugins/table/images/table.gif", "$lang_table_desc", "mceInsertTable", "insert");
+							contextMenu.addItem(tinyMCE.baseURL + "/plugins/table/images/table.gif", "$lang_table_props_desc", "mceInsertTable");
+							contextMenu.addItem(tinyMCE.baseURL + "/plugins/table/images/table_cell_props.gif", "$lang_table_cell_desc", "mceTableCellProps");
+							contextMenu.addItem(tinyMCE.baseURL + "/plugins/table/images/table_delete.gif", "$lang_table_del", "mceTableDelete");
+							contextMenu.addSeparator();
+							contextMenu.addItem(tinyMCE.baseURL + "/plugins/table/images/table_row_props.gif", "$lang_table_row_desc", "mceTableRowProps");
+							contextMenu.addItem(tinyMCE.baseURL + "/plugins/table/images/table_insert_row_before.gif", "$lang_table_row_before_desc", "mceTableInsertRowBefore");
+							contextMenu.addItem(tinyMCE.baseURL + "/plugins/table/images/table_insert_row_after.gif", "$lang_table_row_after_desc", "mceTableInsertRowAfter");
+							contextMenu.addItem(tinyMCE.baseURL + "/plugins/table/images/table_delete_row.gif", "$lang_table_delete_row_desc", "mceTableDeleteRow");
+							contextMenu.addSeparator();
+							contextMenu.addItem(tinyMCE.baseURL + "/plugins/table/images/table_insert_col_before.gif", "$lang_table_col_before_desc", "mceTableInsertColBefore");
+							contextMenu.addItem(tinyMCE.baseURL + "/plugins/table/images/table_insert_col_after.gif", "$lang_table_col_after_desc", "mceTableInsertColAfter");
+							contextMenu.addItem(tinyMCE.baseURL + "/plugins/table/images/table_delete_col.gif", "$lang_table_delete_col_desc", "mceTableDeleteCol");
+							contextMenu.addSeparator();
+							contextMenu.addItem(tinyMCE.baseURL + "/plugins/table/images/table_split_cells.gif", "$lang_table_split_cells_desc", "mceTableSplitCells", "", (colspan == "1" && rowspan == "1"));
+							contextMenu.addItem(tinyMCE.baseURL + "/plugins/table/images/table_merge_cells.gif", "$lang_table_merge_cells_desc", "mceTableMergeCells", "", false);
+						}
+						break;
+				}
+			}  else {
+				// Add table specific
+				if (inst.hasPlugin("table")) {
+					contextMenu.addSeparator();
+					contextMenu.addItem(tinyMCE.baseURL + "/plugins/table/images/table.gif", "$lang_table_desc", "mceInsertTable", "insert");
+				}
+			}
+
+			contextMenu.show(x, y);
+		}, 10);
+
+		// Cancel default handeling
+		tinyMCE.cancelEvent(e);
+		return false;
+	},
+
+	_hideContextMenu : function() {
+		if (TinyMCE_ContextMenuPlugin._contextMenu)
+			TinyMCE_ContextMenuPlugin._contextMenu.hide();
+	},
+
+	_commandHandler : function(command, value) {
+		var cm = TinyMCE_ContextMenuPlugin._contextMenu;
+
+		cm.hide();
+
+		// UI must be true on these
+		var ui = false;
+		if (command == "mceInsertTable" || command == "mceTableCellProps" || command == "mceTableRowProps" || command == "mceTableMergeCells")
+			ui = true;
+
+		if (command == "Paste")
+			value = null;
+
+		if (tinyMCE.getParam("dialog_type") == "modal" && tinyMCE.isMSIE) {
+			// Cell properties will generate access denied error is this isn't done?!
+			window.setTimeout(function() {
+				cm.inst.execCommand(command, ui, value);
+			}, 100);
+		} else
+			cm.inst.execCommand(command, ui, value);
+	}
+};
+
+tinyMCE.addPlugin("contextmenu", TinyMCE_ContextMenuPlugin);
+
+// Context menu class
+
+function TinyMCE_ContextMenu(settings) {
+	var doc, self = this;
+
+	// Default value function
+	function defParam(key, def_val) {
+		settings[key] = typeof(settings[key]) != "undefined" ? settings[key] : def_val;
+	}
+
+	this.isMSIE = (navigator.appName == "Microsoft Internet Explorer");
+
+	// Setup contextmenu div
+	this.contextMenuDiv = document.createElement("div");
+	this.contextMenuDiv.className = "contextMenu";
+	this.contextMenuDiv.setAttribute("class", "contextMenu");
+	this.contextMenuDiv.style.display = "none";
+	this.contextMenuDiv.style.position = 'absolute';
+	this.contextMenuDiv.style.zindex = 1000;
+	this.contextMenuDiv.style.left = '0';
+	this.contextMenuDiv.style.top = '0';
+	this.contextMenuDiv.unselectable = "on";
+
+	document.body.appendChild(this.contextMenuDiv);
+
+	// Setup default values
+	defParam("commandhandler", "");
+	defParam("spacer_image", "images/spacer.gif");
+
+	this.items = new Array();
+	this.settings = settings;
+	this.html = "";
+
+	// IE Popup
+	if (tinyMCE.isMSIE && !tinyMCE.isMSIE5_0 && !tinyMCE.isOpera) {
+		this.pop = window.createPopup();
+		doc = this.pop.document;
+		doc.open();
+		doc.write('<html><head><link href="' + tinyMCE.baseURL + '/plugins/contextmenu/css/contextmenu.css" rel="stylesheet" type="text/css" /></head><body unselectable="yes" class="contextMenuIEPopup"></body></html>');
+		doc.close();
+	}
+};
+
+TinyMCE_ContextMenu.prototype = {
+	clearAll : function() {
+		this.html = "";
+		this.contextMenuDiv.innerHTML = "";
+	},
+
+	addSeparator : function() {
+		this.html += '<tr class="contextMenuItem"><td class="contextMenuIcon"><img src="' + this.settings['spacer_image'] + '" width="20" height="1" class="contextMenuImage" /></td><td><img class="contextMenuSeparator" width="1" height="1" src="' + this.settings['spacer_image'] + '" /></td></tr>';
+	},
+
+	addItem : function(icon, title, command, value, disabled) {
+		if (title.charAt(0) == '$')
+			title = tinyMCE.getLang(title.substring(1));
+
+		var onMouseDown = '';
+		var html = '';
+
+		if (tinyMCE.isMSIE && !tinyMCE.isMSIE5_0)
+			onMouseDown = 'contextMenu.execCommand(\'' + command + '\', \'' + value + '\');return false;';
+		else
+			onMouseDown = this.settings['commandhandler'] + '(\'' + command + '\', \'' + value + '\');return false;';
+
+		if (icon == "")
+			icon = this.settings['spacer_image'];
+
+		if (!disabled)
+			html += '<tr class="contextMenuItem">';
+		else
+			html += '<tr class="contextMenuItemDisabled">';
+
+		html += '<td class="contextMenuIcon"><img src="' + icon + '" width="20" height="20" class="contextMenuImage" /></td>';
+		html += '<td><div class="contextMenuText">';
+		html += '<a href="javascript:void(0);" onclick="' + onMouseDown + '" onmousedown="return false;">&#160;';
+
+		// Add text
+		html += title;
+
+		html += '&#160;</a>';
+		html += '</div></td>';
+		html += '</tr>';
+
+		// Add to main
+		this.html += html;
+	},
+
+	show : function(x, y) {
+		var vp, width, height, yo;
+
+		if (this.html == "")
+			return;
+
+		var html = '';
+
+		html += '<a href="#"></a><table border="0" cellpadding="0" cellspacing="0">';
+		html += this.html;
+		html += '</table>';
+
+		this.contextMenuDiv.innerHTML = html;
+
+		// Get dimensions
+		this.contextMenuDiv.style.display = "block";
+		width = this.contextMenuDiv.offsetWidth;
+		height = this.contextMenuDiv.offsetHeight;
+		this.contextMenuDiv.style.display = "none";
+
+		if (tinyMCE.isMSIE && !tinyMCE.isMSIE5_0 && !tinyMCE.isOpera) {
+			// Setup popup and show
+			this.pop.document.body.innerHTML = '<div class="contextMenu">' + html + "</div>";
+			this.pop.document.tinyMCE = tinyMCE;
+			this.pop.document.contextMenu = this;
+			this.pop.show(x, y, width, height);
+		} else {
+			vp = this.getViewPort();
+			yo = tinyMCE.isMSIE5_0 ? document.body.scrollTop : self.pageYOffset;
+			this.contextMenuDiv.style.left = (x > vp.left + vp.width - width ? vp.left + vp.width - width : x) + 'px';
+			this.contextMenuDiv.style.top = (y > vp.top + vp.height - height ? vp.top + vp.height - height : y) + 'px';
+			this.contextMenuDiv.style.display = "block";
+		}
+	},
+
+	getViewPort : function() {
+		return {
+			left : self.pageXOffset || self.document.documentElement.scrollLeft || self.document.body.scrollLeft,
+			top: self.pageYOffset || self.document.documentElement.scrollTop || self.document.body.scrollTop,
+			width : document.documentElement.offsetWidth || document.body.offsetWidth,
+			height : self.innerHeight || document.documentElement.clientHeight || document.body.clientHeight
+		};
+	},
+
+	hide : function() {
+		if (tinyMCE.isMSIE && !tinyMCE.isMSIE5_0 && !tinyMCE.isOpera)
+			this.pop.hide();
+		else
+			this.contextMenuDiv.style.display = "none";
+	},
+
+	execCommand : function(command, value) {
+		eval(this.settings['commandhandler'] + "(command, value);");
+	}
+};
Binary file includes/clientside/tinymce/plugins/contextmenu/images/spacer.gif has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/contextmenu/readme.txt	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+Check the TinyMCE documentation for details on this plugin.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/devkit/css/devkit.css	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,117 @@
+body {
+	overflow: hidden;
+}
+
+h1 {
+	font-size: 14px;
+	margin: 0 0 10px 0;
+}
+
+h2 {
+	font-size: 12px;
+	margin: 3px 0 3px 0;
+}
+
+h3 {
+	font-size: 11px;
+	margin: 3px 0 3px 0;
+}
+
+#log {
+	font-family: Verdana;
+	border: 1px solid gray;
+	width: 100%; height: 240px;
+	overflow: scroll;
+	white-space: nowrap;
+}
+
+#log span {
+	display: block;
+}
+
+#log span.msg {
+	float: left;
+}
+
+#log span.time {
+	float: left;
+}
+
+#log br {
+	clear: both;
+}
+
+#logfilter {
+	width: 350px;
+}
+
+#logenabled {
+	border: 0;
+}
+
+#settings_panel span, #info_panel span, #content_panel span, #command_states_panel span, #undo_redo_panel span {
+	display: block;
+	margin: 5px 0 5px 0;
+}
+
+div.data {
+	width: 100%; height: 240px;
+	overflow: scroll;
+	border: 1px solid gray;
+}
+
+#misc_panel div.data {
+	height: 270px;
+}
+
+.data input {
+	width: 265px;
+	border: 0;
+}
+
+.data h2 {
+	margin-left: 5px;
+}
+
+.data h3 {
+	margin-left: 7px;
+}
+
+.data div {
+	margin-left: 7px;
+}
+
+.data table {
+	margin: 0 0 15px 15px;
+}
+
+.data p {
+	margin: 0; padding: 0;
+	margin-top: 5px;
+	margin-left: 5px;
+}
+
+table, td {
+	border: 1px solid gray;
+	border-collapse: collapse;
+}
+
+#flip {
+	position: absolute;
+	left: 295; top: 384px;
+}
+
+.bspec {
+	color: gray;
+}
+
+.dep {
+	color: #880000;
+}
+
+.col1 {
+	width: 265px;
+}
+
+div.undodata {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/devkit/css/devkit_ui.css	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,15 @@
+#devkit {
+	position: absolute;
+	top: -385px; right: 0;
+	width: 640px; height: 390px;
+	border: 1px solid black;
+	z-index: 10000;
+}
+
+.devkitup {
+	top: -385px !important;
+}
+
+.devkitdown {
+	top: 0 !important;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/devkit/devkit.htm	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,140 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>{$lang_devkit_title}</title>
+	<script language="javascript" type="text/javascript" src="../../tiny_mce_popup.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/mctabs.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/form_utils.js"></script>
+	<script language="javascript" type="text/javascript" src="jscripts/devkit.js"></script>
+	<script language="javascript" type="text/javascript" src="jscripts/diff.js"></script>
+	<link href="css/devkit.css" rel="stylesheet" type="text/css" />
+	<base target="_self" />
+</head>
+<body id="devkit" onload="tinyMCEPopup.executeOnLoad('init();');" style="display: none">
+    <form action="#">
+		<h1>{$lang_devkit_title}</h1>
+
+		<div class="tabs">
+			<ul>
+				<li id="log_tab" class="current"><span><a href="javascript:mcTabs.displayTab('log_tab','log_panel');" onmousedown="return false;">{$lang_devkit_log_tab}</a></span></li>
+				<li id="info_tab"><span><a href="javascript:mcTabs.displayTab('info_tab','info_panel');" onmousedown="return false;">{$lang_devkit_info_tab}</a></span></li>
+				<li id="settings_tab"><span><a href="javascript:mcTabs.displayTab('settings_tab','settings_panel');" onmousedown="return false;">{$lang_devkit_settings_tab}</a></span></li>
+				<li id="content_tab"><span><a href="javascript:mcTabs.displayTab('content_tab','content_panel');" onmousedown="return false;">{$lang_devkit_content_tab}</a></span></li>
+				<!-- <li id="command_states_tab"><span><a href="javascript:mcTabs.displayTab('command_states_tab','command_states_panel');" onmousedown="return false;">{$lang_devkit_command_states_tab}</a></span></li> -->
+				<li id="undo_redo_tab"><span><a href="javascript:mcTabs.displayTab('undo_redo_tab','undo_redo_panel');" onmousedown="return false;">{$lang_devkit_undo_redo_tab}</a></span></li>
+				<li id="misc_tab"><span><a href="javascript:mcTabs.displayTab('misc_tab','misc_panel');" onmousedown="return false;">{$lang_devkit_misc_tab}</a></span></li>
+			</ul>
+		</div>
+
+		<div class="panel_wrapper">
+			<div id="log_panel" class="panel current">
+				<fieldset>
+					<legend>{$lang_devkit_log_tab}</legend>
+
+					<div style="float: left">
+						<label>{$lang_devkit_filter} </label><input type="text" id="logfilter" name="logfilter" value="" onchange="changeFilter(this.value);" />
+					</div>
+
+					<div style="float: left">
+						<input type="checkbox" id="logenabled" name="logenabled" value="true" checked="checked" onclick="toggleLog(this.checked);" />
+					</div>
+
+					<div style="float: right">
+						<a href="javascript:clearLog();">[{$lang_devkit_clear_log}]</a>
+					</div>
+
+					<br style="clear: both" />
+
+					<div id="log">
+					</div>
+
+					<input type="checkbox" id="debug_events" name="debug_events" class="checkbox" onclick="toggleDebugEvents(this.checked);" /><label for="debug_events" onclick="toggleDebugEvents(this.form.debug_events.checked);">{$lang_devkit_debug_events}</label>
+				</fieldset>
+			</div>
+
+			<div id="info_panel" class="panel">
+				<fieldset>
+					<legend>{$lang_devkit_info_tab}</legend>
+
+					<span><a href="javascript:renderInfo();">[{$lang_devkit_refresh}]</a></span>
+
+					<div id="info" class="data">
+						<p>{$lang_devkit_info_help}</p>
+					</div>
+				</fieldset>
+			</div>
+
+			<div id="settings_panel" class="panel">
+			<fieldset>
+					<legend>{$lang_devkit_settings_tab}</legend>
+
+					<span><a href="javascript:renderSettings();">[{$lang_devkit_refresh}]</a></span>
+
+					<div id="settings" class="data">
+						<p>{$lang_devkit_settings_help}</p>
+					</div>
+				</fieldset>
+			</div>
+
+			<div id="content_panel" class="panel">
+			<fieldset>
+					<legend>{$lang_devkit_content_tab}</legend>
+
+					<span><a href="javascript:renderContent();">[{$lang_devkit_refresh}]</a></span>
+
+					<div id="content" class="data">
+						<p>{$lang_devkit_content_help}</p>
+					</div>
+				</fieldset>
+			</div>
+
+			<div id="command_states_panel" class="panel">
+			<fieldset>
+					<legend>{$lang_devkit_command_states_tab}</legend>
+
+					<span><a href="javascript:renderCommandStates();">[{$lang_devkit_refresh}]</a></span>
+
+					<div id="command_states" class="data">
+						<p>{$lang_devkit_command_states_help}</p>
+					</div>
+				</fieldset>
+			</div>
+
+			<div id="undo_redo_panel" class="panel">
+				<fieldset>
+					<legend>{$lang_devkit_undo_redo_tab}</legend>
+
+					<span><a href="javascript:renderUndoRedo();">[{$lang_devkit_refresh}]</a></span>
+
+					<div id="undo_redo" class="data">
+						<p>{$lang_devkit_undo_redo_help}</p>
+					</div>
+
+					<input type="checkbox" id="undo_diff" name="undo_diff" class="checkbox" /><label for="undo_diff">{$lang_devkit_undo_diff}</label>
+				</fieldset>
+			</div>
+
+			<div id="misc_panel" class="panel">
+				<fieldset>
+					<legend>{$lang_devkit_misc_tab}</legend>
+
+					<div class="data">
+						<p>{$lang_devkit_misc_help}</p>
+						<hr />
+						<p>Selection: <a href="#" onmousedown="return storeSelection();">[Store selection]</a> <a href="#" onmousedown="return restoreSelection();">[Restore selection]</a></p>
+						<hr />
+						<div><strong>Insert custom HTML content</strong></div>
+						<div><textarea id="htmlcont" name="htmlcont" style="width: 90%" rows="5"></textarea></div>
+						<div><a href="#" onclick="return tinyMCE.execCommand('mceInsertContent',false,document.getElementById('htmlcont').value);">[Insert content]</a></div>
+						<hr />
+						<div><strong>Eval JS:</strong></div>
+						<div><textarea id="jscont" name="jscont" style="width: 90%" rows="5">tinyMCE.execCommand('Bold',false,null);</textarea></div>
+						<div><a href="#" onclick="return parent.window.eval(document.getElementById('jscont').value);">[Evaluate]</a></div>
+					</div>
+				</fieldset>
+			</div>
+		</div>
+    </form>
+
+	<div id="flip"><a href="javascript:toggleFlip();" onmousedown="return false;"><img id="flipbtn" src="images/flip_down.gif" border="0" /></a></div>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/devkit/editor_plugin.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+tinyMCE.importPluginLanguagePack('devkit');var TinyMCE_DevKitPlugin={_logFilter:'\\[(importCSS|execCommand|execInstanceCommand|debug)\\]',_logPadding:'',_startTime:null,_benchMark:false,_winLoaded:false,_isDebugEvents:false,getInfo:function(){return{longname:'Development Kit',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/devkit',version:tinyMCE.majorVersion+"."+tinyMCE.minorVersion}},initInstance:function(inst){this._setup()},_setup:function(){if(this._loaded)return;this._loaded=true;document.___TinyMCE=tinyMCE;this._logFilter=tinyMCE.getParam('devkit_log_filter',this._logFilter);this._benchMark=tinyMCE.getParam('devkit_bench_mark',false);var ifr=document.createElement('iframe');ifr.setAttribute("id","devkit");ifr.setAttribute("frameBorder","0");ifr.setAttribute("src",tinyMCE.baseURL+'/plugins/devkit/devkit.htm');document.body.appendChild(ifr);tinyMCE.importCSS(document,tinyMCE.baseURL+'/plugins/devkit/css/devkit_ui.css')},_start:function(){this._logPadding+='\u00a0';return new Date().getTime()},_end:function(st){if(this._logPadding.length>0)this._logPadding=this._logPadding.substring(0,this._logPadding.length-1);if(this._benchMark)this._log("benchmark","Execution time: "+(new Date().getTime()-st))},_log:function(t){var m,a,i,e=document.getElementById('devkit'),now=new Date().getTime();if(!this._startTime)this._startTime=now;m=(this._logPadding.length>1?this._logPadding:'')+'['+(now-this._startTime)+'] ['+t+'] ';a=this._log.arguments;for(i=1;i<a.length;i++){if(typeof(a[i])=='undefined')continue;if(i>1)m+=', ';m+=a[i]}if(!new RegExp(this._logFilter,'gi').test(m)){if(this._logPadding.length>0)this._logPadding=this._logPadding.substring(0,this._logPadding.length-1);return}if(!this._winLoaded)tinyMCE.log[tinyMCE.log.length]=m;else e.contentWindow.debug(m)},_debugEvents:function(s){var i,ld,inst,n,ev=['CheckboxStateChange','DOMAttrModified','DOMMenuItemActive','DOMMenuItemInactive','DOMMouseScroll','DOMNodeInserted','DOMNodeRemoved','RadioStateChange','blur','broadcast','change','click','close','command','commandupdate','contextmenu','dblclick','dragdrop','dragenter','dragexit','draggesture','dragover','focus','input','keydown','keypress','keyup','load','mousedown','mouseout','mouseover','mouseup','overflow','overflowchanged','popuphidden','popuphiding','popupshowing','popupshown','select','syncfrompreference','synctopreference','underflow','unload','abort','activate','afterprint','afterupdate','beforeactivate','beforecopy','beforecut','beforedeactivate','beforeeditfocus','beforepaste','beforeprint','beforeunload','beforeupdate','bounce','cellchange','controlselect','copy','cut','dataavailable','datasetchanged','datasetcomplete','deactivate','dragend','dragleave','dragstart','drop','error','errorupdate','filterchange','finish','focusin','focusout','help','layoutcomplete','losecapture','mouseenter','mouseleave','mousewheel','move','moveend','movestart','paste','propertychange','readystatechange','reset','resize','resizeend','resizestart','rowenter','rowexit','rowsdelete','rowsinserted','scroll','selectionchange','selectstart','start','stop','submit'];if(TinyMCE_DevKitPlugin._isDebugEvents==s)return;TinyMCE_DevKitPlugin._isDebugEvents=s;for(n in tinyMCE.instances){inst=tinyMCE.instances[n];if(!tinyMCE.isInstance(inst)||inst.getDoc()==ld)continue;ld=inst.getDoc();for(i=0;i<ev.length;i++){if(s)tinyMCE.addEvent(ld,ev[i],TinyMCE_DevKitPlugin._debugEvent);else tinyMCE.removeEvent(ld,ev[i],TinyMCE_DevKitPlugin._debugEvent)}}},_debugEvent:function(e){var t;e=e?e:tinyMCE.selectedInstance.getWin().event;t=e.srcElement?e.srcElement:e.target;tinyMCE.debug(e.type,t?t.nodeName:'')},_serialize:function(o){var i,v,s=TinyMCE_DevKitPlugin._serialize;if(o==null)return'null';switch(typeof o){case'string':v='\bb\tt\nn\ff\rr\""\'\'\\\\';return'"'+o.replace(new RegExp('([\u0080-\uFFFF\\x00-\\x1f\\"])','g'),function(a,b){i=v.indexOf(b);if(i+1)return'\\'+v.charAt(i+1);a=b.charCodeAt().toString(16);return'\\u'+'0000'.substring(a.length)+a})+'"';case'object':if(o instanceof Array){for(i=0,v='[';i<o.length;i++)v+=(i>0?',':'')+s(o[i]);return v+']'}v='{';for(i in o)v+=typeof o[i]!='function'?(v.length>1?',"':'"')+i+'":'+s(o[i]):'';return v+'}'}return''+o}};tinyMCE.__debug=tinyMCE.debug;tinyMCE.debug=function(){var a,i,m='',now=new Date().getTime(),start=TinyMCE_DevKitPlugin._startTime;if(!start)TinyMCE_DevKitPlugin._startTime=start=now;a=this.debug.arguments;for(i=0;i<a.length;i++){if(typeof(a[i])=='undefined')continue;if(i>0)m+=', ';m+=a[i]}TinyMCE_DevKitPlugin._log('debug',m)};tinyMCE.dump=function(o){tinyMCE.debug(TinyMCE_DevKitPlugin._serialize(o))};tinyMCE.sleep=function(t){var s=new Date().getTime(),b;while(new Date().getTime()-s<t)b=1};tinyMCE.__execCommand=tinyMCE.execCommand;tinyMCE.execCommand=function(command,user_interface,value){var r,st,dk=TinyMCE_DevKitPlugin;st=dk._start();dk._log('execCommand',command,user_interface,value);r=tinyMCE.__execCommand(command,user_interface,value);dk._end(st);return r};tinyMCE.__execInstanceCommand=tinyMCE.execInstanceCommand;tinyMCE.execInstanceCommand=function(editor_id,command,user_interface,value,focus){var r,st,dk=TinyMCE_DevKitPlugin;st=dk._start();dk._log('execInstanceCommand',editor_id,command,user_interface,value);r=tinyMCE.__execInstanceCommand(editor_id,command,user_interface,value);dk._end(st);return r};TinyMCE_Engine.prototype.__handleEvent=TinyMCE_Engine.prototype.handleEvent;TinyMCE_Engine.prototype.handleEvent=function(e){var r,st,dk=TinyMCE_DevKitPlugin;st=dk._start();dk._log('handleEvent',e.type);r=tinyMCE.__handleEvent(e);dk._end(st);return r};tinyMCE.__importCSS=tinyMCE.importCSS;tinyMCE.importCSS=function(doc,css){var r,st,dk=TinyMCE_DevKitPlugin;st=dk._start();dk._log('importCSS',doc,css);r=tinyMCE.__importCSS(doc,css);dk._end(st);return r};tinyMCE.__triggerNodeChange=tinyMCE.triggerNodeChange;tinyMCE.triggerNodeChange=function(focus,setup_content){var r,st,dk=TinyMCE_DevKitPlugin;st=dk._start();dk._log('triggerNodeChange',focus,setup_content);r=tinyMCE.__triggerNodeChange(focus,setup_content);dk._end(st);return r};tinyMCE.__dispatchCallback=tinyMCE.dispatchCallback;tinyMCE.dispatchCallback=function(i,p,n){var r,st,dk=TinyMCE_DevKitPlugin;st=dk._start();dk._log('dispatchCallback',i,p,n);r=tinyMCE.__dispatchCallback(i,p,n);dk._end(st);return r};tinyMCE.__executeCallback=tinyMCE.executeCallback;tinyMCE.executeCallback=function(i,p,n){var r,st,dk=TinyMCE_DevKitPlugin;st=dk._start();dk._log('executeCallback',i,p,n);r=tinyMCE.__executeCallback(i,p,n);dk._end(st);return r};tinyMCE.__execCommandCallback=tinyMCE.execCommandCallback;tinyMCE.execCommandCallback=function(i,p,n){var r,st,dk=TinyMCE_DevKitPlugin;st=dk._start();dk._log('execCommandCallback',i,p,n);r=tinyMCE.__execCommandCallback(i,p,n);dk._end(st);return r};tinyMCE.addPlugin("devkit",TinyMCE_DevKitPlugin);
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/devkit/editor_plugin_src.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,325 @@
+/**
+ * $Id: editor_plugin_src.js 42 2006-08-08 14:32:24Z spocke $
+ *
+ * @author Moxiecode
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+tinyMCE.importPluginLanguagePack('devkit');
+
+var TinyMCE_DevKitPlugin = {
+	_logFilter : '\\[(importCSS|execCommand|execInstanceCommand|debug)\\]',
+	_logPadding : '',
+	_startTime : null,
+	_benchMark : false,
+	_winLoaded : false,
+	_isDebugEvents : false,
+
+	getInfo : function() {
+		return {
+			longname : 'Development Kit',
+			author : 'Moxiecode Systems AB',
+			authorurl : 'http://tinymce.moxiecode.com',
+			infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/devkit',
+			version : tinyMCE.majorVersion + "." + tinyMCE.minorVersion
+		};
+	},
+
+	initInstance : function(inst) {
+		this._setup();
+	},
+
+	_setup : function() {
+		if (this._loaded)
+			return;
+
+		this._loaded = true;
+
+		// Register a document reference for more easy access in the FF DOM inspector
+		document.___TinyMCE = tinyMCE;
+
+		// Setup devkit by settings
+		this._logFilter = tinyMCE.getParam('devkit_log_filter', this._logFilter);
+		this._benchMark = tinyMCE.getParam('devkit_bench_mark', false);
+
+		var ifr = document.createElement('iframe');
+
+		ifr.setAttribute("id", "devkit");
+		ifr.setAttribute("frameBorder", "0");
+		ifr.setAttribute("src", tinyMCE.baseURL + '/plugins/devkit/devkit.htm');
+
+		document.body.appendChild(ifr);
+
+		// Workaround for strange IE reload bug
+		//if (tinyMCE.isRealIE)
+		//	document.getElementById('devkit').outerHTML = document.getElementById('devkit').outerHTML;
+
+		tinyMCE.importCSS(document, tinyMCE.baseURL + '/plugins/devkit/css/devkit_ui.css');
+	},
+
+	_start : function() {
+		this._logPadding += '\u00a0';
+
+		return new Date().getTime();
+	},
+
+	_end : function(st) {
+		if (this._logPadding.length > 0)
+			this._logPadding = this._logPadding.substring(0, this._logPadding.length - 1);
+
+		if (this._benchMark)
+			this._log("benchmark", "Execution time: " + (new Date().getTime() - st));
+	},
+
+	_log : function(t) {
+		var m, a, i, e = document.getElementById('devkit'), now = new Date().getTime();
+
+		if (!this._startTime)
+			this._startTime = now;
+
+		m = (this._logPadding.length > 1 ? this._logPadding : '') + '[' + (now - this._startTime) + '] [' + t + '] ';
+
+		a = this._log.arguments;
+		for (i=1; i<a.length; i++) {
+			if (typeof(a[i]) == 'undefined')
+				continue;
+
+			if (i > 1)
+				m += ', ';
+
+			m += a[i];
+		}
+
+		if (!new RegExp(this._logFilter, 'gi').test(m)) {
+			if (this._logPadding.length > 0)
+				this._logPadding = this._logPadding.substring(0, this._logPadding.length - 1);
+
+			return;
+		}
+
+		if (!this._winLoaded)
+			tinyMCE.log[tinyMCE.log.length] = m;
+		else
+			e.contentWindow.debug(m);
+	},
+
+	_debugEvents : function(s) {
+		var i, ld, inst, n, ev = ['CheckboxStateChange','DOMAttrModified','DOMMenuItemActive',
+				'DOMMenuItemInactive','DOMMouseScroll','DOMNodeInserted','DOMNodeRemoved',
+				'RadioStateChange','blur','broadcast','change','click','close','command',
+				'commandupdate','contextmenu','dblclick','dragdrop','dragenter','dragexit',
+				'draggesture','dragover','focus','input','keydown','keypress','keyup','load',
+				'mousedown','mouseout','mouseover','mouseup','overflow','overflowchanged','popuphidden',
+				'popuphiding','popupshowing','popupshown','select','syncfrompreference','synctopreference',
+				'underflow','unload','abort','activate','afterprint','afterupdate','beforeactivate',
+				'beforecopy','beforecut','beforedeactivate','beforeeditfocus','beforepaste','beforeprint',
+				'beforeunload','beforeupdate','bounce','cellchange','controlselect','copy','cut',
+				'dataavailable','datasetchanged','datasetcomplete','deactivate','dragend','dragleave',
+				'dragstart','drop','error','errorupdate','filterchange','finish','focusin','focusout',
+				'help','layoutcomplete','losecapture','mouseenter','mouseleave','mousewheel',
+				'move','moveend','movestart','paste','propertychange','readystatechange','reset','resize',
+				'resizeend','resizestart','rowenter','rowexit','rowsdelete','rowsinserted','scroll',
+				'selectionchange','selectstart','start','stop','submit'];
+		// mousemove
+
+		if (TinyMCE_DevKitPlugin._isDebugEvents == s)
+			return;
+
+		TinyMCE_DevKitPlugin._isDebugEvents = s;
+
+		for (n in tinyMCE.instances) {
+			inst = tinyMCE.instances[n];
+
+			if (!tinyMCE.isInstance(inst) || inst.getDoc() == ld)
+				continue;
+
+			ld = inst.getDoc();
+
+			for (i=0; i<ev.length; i++) {
+				if (s)
+					tinyMCE.addEvent(ld, ev[i], TinyMCE_DevKitPlugin._debugEvent);
+				else
+					tinyMCE.removeEvent(ld, ev[i], TinyMCE_DevKitPlugin._debugEvent);
+			}
+		}
+	},
+
+	_debugEvent : function(e) {
+		var t;
+
+		e = e ? e : tinyMCE.selectedInstance.getWin().event;
+		t = e.srcElement ? e.srcElement : e.target;
+
+		tinyMCE.debug(e.type, t ? t.nodeName : '');
+	},
+
+	_serialize : function(o) {
+		var i, v, s = TinyMCE_DevKitPlugin._serialize;
+
+		if (o == null)
+			return 'null';
+
+		switch (typeof o) {
+			case 'string':
+				v = '\bb\tt\nn\ff\rr\""\'\'\\\\';
+
+				return '"' + o.replace(new RegExp('([\u0080-\uFFFF\\x00-\\x1f\\"])', 'g'), function(a, b) {
+					i = v.indexOf(b);
+
+					if (i+1)
+						return '\\' + v.charAt(i + 1);
+
+					a = b.charCodeAt().toString(16);
+
+					return '\\u' + '0000'.substring(a.length) + a;
+				}) + '"';
+
+			case 'object':
+				if (o instanceof Array) {
+					for (i=0, v = '['; i<o.length; i++)
+						v += (i > 0 ? ',' : '') + s(o[i]);
+
+					return v + ']';
+				}
+
+				v = '{';
+
+				for (i in o)
+					v += typeof o[i] != 'function' ? (v.length > 1 ? ',"' : '"') + i + '":' + s(o[i]) : '';
+
+				return v + '}';
+		}
+
+		return '' + o;
+	}
+};
+
+// Patch and piggy back functions
+tinyMCE.__debug = tinyMCE.debug;
+tinyMCE.debug = function() {
+	var a, i, m = '', now = new Date().getTime(), start = TinyMCE_DevKitPlugin._startTime;
+
+	if (!start)
+		TinyMCE_DevKitPlugin._startTime = start = now;
+
+	a = this.debug.arguments;
+	for (i=0; i<a.length; i++) {
+		if (typeof(a[i]) == 'undefined')
+			continue;
+
+		if (i > 0)
+			m += ', ';
+
+		m += a[i];
+	}
+
+	TinyMCE_DevKitPlugin._log('debug', m);
+};
+
+tinyMCE.dump = function(o) {
+	tinyMCE.debug(TinyMCE_DevKitPlugin._serialize(o));
+};
+
+tinyMCE.sleep = function(t) {
+	var s = new Date().getTime(), b;
+
+	while (new Date().getTime() - s < t) b=1;
+};
+
+tinyMCE.__execCommand = tinyMCE.execCommand;
+tinyMCE.execCommand = function(command, user_interface, value) {
+	var r, st, dk = TinyMCE_DevKitPlugin;
+
+	st = dk._start();
+	dk._log('execCommand', command, user_interface, value);
+	r = tinyMCE.__execCommand(command, user_interface, value);
+	dk._end(st);
+
+	return r;
+};
+
+tinyMCE.__execInstanceCommand = tinyMCE.execInstanceCommand;
+tinyMCE.execInstanceCommand = function(editor_id, command, user_interface, value, focus) {
+	var r, st, dk = TinyMCE_DevKitPlugin;
+
+	st = dk._start();
+	dk._log('execInstanceCommand', editor_id, command, user_interface, value);
+	r = tinyMCE.__execInstanceCommand(editor_id, command, user_interface, value);
+	dk._end(st);
+
+	return r;
+};
+
+TinyMCE_Engine.prototype.__handleEvent = TinyMCE_Engine.prototype.handleEvent;
+TinyMCE_Engine.prototype.handleEvent = function(e) {
+	var r, st, dk = TinyMCE_DevKitPlugin;
+
+	st = dk._start();
+	dk._log('handleEvent', e.type);
+	r = tinyMCE.__handleEvent(e);
+	dk._end(st);
+
+	return r;
+};
+
+tinyMCE.__importCSS = tinyMCE.importCSS;
+tinyMCE.importCSS = function(doc, css) {
+	var r, st, dk = TinyMCE_DevKitPlugin;
+
+	st = dk._start();
+	dk._log('importCSS', doc, css);
+	r = tinyMCE.__importCSS(doc, css);
+	dk._end(st);
+
+	return r;
+};
+
+tinyMCE.__triggerNodeChange = tinyMCE.triggerNodeChange;
+tinyMCE.triggerNodeChange = function(focus, setup_content) {
+	var r, st, dk = TinyMCE_DevKitPlugin;
+
+	st = dk._start();
+	dk._log('triggerNodeChange', focus, setup_content);
+	r = tinyMCE.__triggerNodeChange(focus, setup_content);
+	dk._end(st);
+
+	return r;
+};
+
+tinyMCE.__dispatchCallback = tinyMCE.dispatchCallback;
+tinyMCE.dispatchCallback = function(i, p, n) {
+	var r, st, dk = TinyMCE_DevKitPlugin;
+
+	st = dk._start();
+	dk._log('dispatchCallback', i, p, n);
+	r = tinyMCE.__dispatchCallback(i, p, n);
+	dk._end(st);
+
+	return r;
+};
+
+tinyMCE.__executeCallback = tinyMCE.executeCallback;
+tinyMCE.executeCallback = function(i, p, n) {
+	var r, st, dk = TinyMCE_DevKitPlugin;
+
+	st = dk._start();
+	dk._log('executeCallback', i, p, n);
+	r = tinyMCE.__executeCallback(i, p, n);
+	dk._end(st);
+
+	return r;
+};
+
+tinyMCE.__execCommandCallback = tinyMCE.execCommandCallback;
+tinyMCE.execCommandCallback = function(i, p, n) {
+	var r, st, dk = TinyMCE_DevKitPlugin;
+
+	st = dk._start();
+	dk._log('execCommandCallback', i, p, n);
+	r = tinyMCE.__execCommandCallback(i, p, n);
+	dk._end(st);
+
+	return r;
+};
+
+tinyMCE.addPlugin("devkit", TinyMCE_DevKitPlugin);
Binary file includes/clientside/tinymce/plugins/devkit/images/flip_down.gif has changed
Binary file includes/clientside/tinymce/plugins/devkit/images/flip_up.gif has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/devkit/jscripts/devkit.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,331 @@
+var devkit = parent.tinyMCE.plugins['devkit'], logEnabled = true, flip = false, book = null;
+
+function init() {
+	var log, i, f = document.forms[0];
+
+	devkit._winLoaded = true;
+
+	log = tinyMCE.log;
+
+	for (i=0; i<log.length; i++)
+		debug(log[i]);
+
+	f.logfilter.value = devkit._logFilter;
+}
+
+function changeFilter(f) {
+	devkit._logFilter = f;
+}
+
+function toggleLog(s) {
+	logEnabled = s;
+}
+
+function toggleFlip() {
+	document.getElementById('flipbtn').src = flip ? 'images/flip_down.gif' : 'images/flip_up.gif';
+
+	if (flip)
+		parent.document.getElementById('devkit').className = 'devkitup';
+	else
+		parent.document.getElementById('devkit').className = 'devkitdown';
+
+	flip = !flip;
+}
+
+function debug(s) {
+	var d, l, n;
+
+	if (!logEnabled || !new RegExp(devkit._logFilter, 'gi').test(s))
+		return;
+
+	d = document;
+	l = d.getElementById('log');
+	n = d.createElement('span');
+
+	n.innerHTML = tinyMCE.xmlEncode(s);
+
+	l.appendChild(n);
+	l.scrollTop = l.scrollHeight;
+}
+
+function renderInfo() {
+	var se = document.getElementById('info'), n, sn, inst, h = '', sel, rng, instCount = 0, rc;
+
+	h += '<h2>Browser info:</h2>';
+
+	h += '<table border="0" cellpadding="0" cellspacing="0" class="data">';
+	h += addRenderInfo('navigator.userAgent', navigator.userAgent);
+	h += addRenderInfo('navigator.appName', navigator.appName);
+	h += addRenderInfo('navigator.platform', navigator.platform);
+	h += addRenderInfo('navigator.language', navigator.language, 'bspec');
+	h += addRenderInfo('navigator.browserLanguage', navigator.browserLanguage, 'bspec');
+	h += addRenderInfo('navigator.systemLanguage', navigator.systemLanguage, 'bspec');
+	h += addRenderInfo('navigator.userLanguage', navigator.userLanguage, 'bspec');
+	h += addRenderInfo('opera.buildNumber("inconspicuous")', typeof(opera) != 'undefined' && opera.buildNumber ? opera.buildNumber('inconspicuous') : null, 'bspec');
+	h += addRenderInfo('window.innerWidth', parent.window.innerWidth, 'bspec');
+	h += addRenderInfo('window.innerHeight', parent.window.innerHeight, 'bspec');
+	h += addRenderInfo('document.body.offsetWidth', parent.document.body.offsetWidth);
+	h += addRenderInfo('document.body.offsetHeight', parent.document.body.offsetHeight);
+	h += addRenderInfo('screen.width', screen.width);
+	h += addRenderInfo('screen.height', screen.height);
+	h += addRenderInfo('screen.availWidth', screen.availWidth);
+	h += addRenderInfo('screen.availHeight', screen.availHeight);
+	h += addRenderInfo('screen.colorDepth', screen.colorDepth);
+	h += addRenderInfo('screen.pixelDepth', screen.pixelDepth, 'bspec');
+	h += addRenderInfo('document.contentType', document.contentType, 'bspec');
+	h += '</table>';
+
+	h += '<h2>TinyMCE_Engine info:</h2>';
+
+	h += '<table border="0" cellpadding="0" cellspacing="0" class="data">';
+	h += addRenderInfo('baseURL', tinyMCE.baseURL);
+	h += addRenderInfo('selectedInstance.editorId', tinyMCE.selectedInstance ? tinyMCE.selectedInstance.editorId : null);
+	h += addRenderInfo('selectedElement.nodeName', tinyMCE.selectedElement ? tinyMCE.selectedElement.nodeName : null, 'dep');
+	h += addRenderInfo('loadedFiles',tinyMCE.loadedFiles.join(','));
+	h += addRenderInfo('isMSIE', tinyMCE.isMSIE);
+	h += addRenderInfo('isMSIE5', tinyMCE.isMSIE5);
+	h += addRenderInfo('isMSIE5_0', tinyMCE.isMSIE5_0);
+	h += addRenderInfo('isMSIE7', tinyMCE.isMSIE7);
+	h += addRenderInfo('isGecko', tinyMCE.isGecko);
+	h += addRenderInfo('isSafari', tinyMCE.isSafari);
+	h += addRenderInfo('isOpera', tinyMCE.isOpera);
+	h += addRenderInfo('isMac', tinyMCE.isMac);
+	h += addRenderInfo('isNS7', tinyMCE.isNS7);
+	h += addRenderInfo('isNS71', tinyMCE.isNS71);
+	h += addRenderInfo('idCounter', tinyMCE.idCounter);
+	h += addRenderInfo('currentConfig', tinyMCE.currentConfig);
+	h += addRenderInfo('majorVersion', tinyMCE.majorVersion);
+	h += addRenderInfo('minorVersion', tinyMCE.minorVersion);
+	h += addRenderInfo('releaseDate', tinyMCE.releaseDate);
+	h += addRenderInfo('documentBasePath', tinyMCE.documentBasePath);
+	h += addRenderInfo('documentURL', tinyMCE.documentURL);
+	h += '</table>';
+
+	for (n in tinyMCE.instances) {
+		inst = tinyMCE.instances[n];
+
+		if (!tinyMCE.isInstance(inst))
+			continue;
+
+		sel = inst.selection.getSel();
+		rng = inst.selection.getRng();
+
+		h += '<h2>TinyMCE_Control(' + (instCount++) + ') id: ' + inst.editorId + '</h2>';
+		h += '<table border="0" cellpadding="0" cellspacing="0" class="data">';
+
+		h += addRenderInfo('editorId', inst.editorId);
+		h += addRenderInfo('visualAid', inst.visualAid);
+		h += addRenderInfo('foreColor', inst.foreColor);
+		h += addRenderInfo('backColor', inst.backColor);
+		h += addRenderInfo('formTargetElementId', inst.formTargetElementId);
+		h += addRenderInfo('formElement', inst.formElement ? inst.formElement.nodeName : null);
+		h += addRenderInfo('oldTargetElement', inst.oldTargetElement ? inst.oldTargetElement.nodeName : null);
+		h += addRenderInfo('linkElement', inst.linkElement ? inst.linkElement.nodeName : null, 'dep');
+		h += addRenderInfo('imgElement', inst.imgElement ? inst.imgElement.nodeName : null, 'dep');
+		h += addRenderInfo('selectedNode', inst.selectedNode ? inst.selectedNode.nodeName : null, 'dep');
+		h += addRenderInfo('targetElement', inst.targetElement ? inst.targetElement.nodeName : null);
+		h += addRenderInfo('getBody().nodeName', inst.getBody() ? inst.getBody().nodeName : null);
+		h += addRenderInfo('getBody().getAttribute("id")', inst.getBody() ? inst.getBody().getAttribute("id") : null);
+		h += addRenderInfo('getDoc().location', inst.getDoc() ? inst.getDoc().location : null);
+		h += addRenderInfo('startContent', inst.startContent);
+		h += addRenderInfo('isHidden()', inst.isHidden());
+		h += addRenderInfo('isDirty()', inst.isDirty());
+		h += addRenderInfo('undoRedo.undoLevels.length', inst.undoRedo.undoLevels.length);
+		h += addRenderInfo('undoRedo.undoIndex', inst.undoRedo.undoIndex);
+		h += addRenderInfo('selection.getSelectedHTML()', inst.selection.getSelectedHTML());
+		h += addRenderInfo('selection.isCollapsed()', inst.selection.isCollapsed() || 'false');
+		h += addRenderInfo('selection.getSelectedText()', inst.selection.getSelectedText());
+		h += addRenderInfo('selection.getFocusElement().nodeName', inst.selection.getFocusElement().nodeName);
+		h += addRenderInfo('selection.getFocusElement().outerHTML', tinyMCE.getOuterHTML(inst.selection.getFocusElement()));
+
+		if ((tinyMCE.isGecko || tinyMCE.isOpera) && sel && rng) {
+			h += addRenderInfo('selection.getSel().anchorNode.nodeName', sel.anchorNode ? sel.anchorNode.nodeName : null, 'bspec');
+			h += addRenderInfo('selection.getSel().anchorOffset', sel.anchorOffset, 'bspec');
+			h += addRenderInfo('selection.getSel().focusNode.nodeName', sel.focusNode ? sel.focusNode.nodeName : null, 'bspec');
+			h += addRenderInfo('selection.getSel().focusOffset', sel.focusOffset, 'bspec');
+			h += addRenderInfo('selection.getRng().startContainer.nodeName', rng.startContainer ? rng.startContainer.nodeName : null, 'bspec');
+			h += addRenderInfo('selection.getRng().startOffset', rng.startOffset, 'bspec');
+			h += addRenderInfo('selection.getRng().endContainer.nodeName', rng.endContainer ? rng.endContainer.nodeName : null, 'bspec');
+			h += addRenderInfo('selection.getRng().endOffset', rng.endOffset, 'bspec');
+		}
+
+		if (typeof(rng.item) != 'undefined' || typeof(rng.htmlText) != 'undefined') {
+			if (!rng.item) {
+				h += addRenderInfo('selection.getSel().type', sel.type, 'bspec');
+				h += addRenderInfo('selection.getRng().htmlText', rng.htmlText, 'bspec');
+				h += addRenderInfo('selection.getRng().text', rng.text, 'bspec');
+			} else
+				h += addRenderInfo('selection.getRng().item(0).nodeName', rng.item(0).nodeName, 'bspec');
+		}
+
+		h += '</table>';
+	}
+
+	h += '<p>Fields marked in <strong class="bspec">gray</strong> is not cross browser and should be used with care.</p>';
+	h += '<p>Fields marked <strong class="dep">red</strong> are marked deprecated and will be removed in the future.</p><br />';
+
+	se.innerHTML = h;
+}
+
+function addRenderInfo(n, v, c) {
+	return '<tr><td' + (c ? ' class="' + c + '"' : '')+ '>' + n + '</td><td><input type="text" value="' + tinyMCE.xmlEncode(v != null ? ('' + v).replace(/[\r\n]/g, '') : 'null') + '" /></td></tr>';
+}
+
+function renderSettings() {
+	var se = document.getElementById('settings'), n, sn, inst, h = '', v;
+
+	for (n in tinyMCE.instances) {
+		inst = tinyMCE.instances[n];
+
+		if (!tinyMCE.isInstance(inst))
+			continue;
+
+		h += '<h2>Instance id: ' + inst.editorId + '</h2>';
+		h += '<table border="0" cellpadding="0" cellspacing="0" class="data">';
+
+		for (sn in inst.settings) {
+			v = inst.settings[sn];
+
+			h += '<tr><td class="col1">' + tinyMCE.xmlEncode(sn) + '</td><td><input type="text" value="' + tinyMCE.xmlEncode(v) + '" /></td></tr>';
+		}
+
+		h += '</table>';
+	}
+
+	se.innerHTML = h;
+}
+
+function renderContent() {
+	var se = document.getElementById('content'), n, inst, h = '';
+
+	for (n in tinyMCE.instances) {
+		inst = tinyMCE.instances[n];
+
+		if (!tinyMCE.isInstance(inst))
+			continue;
+
+		h += '<h2>Instance id: ' + inst.editorId + '</h2>';
+
+		h += '<h3>Start content - inst.startContent:</h3>';
+		h += '<div>' + tinyMCE.xmlEncode(inst.startContent) + '</div>';
+
+		h += '<h3>Raw content - inst.getBody().innerHTML or inst.getHTML(true):</h3>';
+		h += '<div>' + tinyMCE.xmlEncode(inst.getHTML(true)) + '</div>';
+
+		h += '<h3>Cleaned content - inst.getHTML():</h3>';
+		h += '<div>' + tinyMCE.xmlEncode(inst.getHTML()) + '</div>';
+
+		if (inst.serializedHTML) {
+			h += '<h3>Serialized HTML content - inst.serializedHTML:</h3>';
+			h += '<div>' + tinyMCE.xmlEncode(inst.serializedHTML) + '</div>';
+		}
+	}
+
+	se.innerHTML = h;
+}
+
+function renderCommandStates() {
+	var se = document.getElementById('command_states'), n, inst, h = '', v, ex;
+	var cmds = new Array('2D-Position','AbsolutePosition','BackColor','BlockDirLTR','BlockDirRTL','Bold','BrowseMode','Copy','CreateBookmark','CreateLink','Cut','Delete','DirLTR','DirRTL','EditMode','enableInlineTableEditing','enableObjectResizing','FontName','FontSize','ForeColor','FormatBlock','Indent','InsertButton','InsertFieldset','InsertHorizontalRule','InsertIFrame','InsertImage','InsertInputButton','InsertInputCheckbox','InsertInputFileUpload','InsertInputHidden','InsertInputImage','InsertInputPassword','InsertInputRadio','InsertInputReset','InsertInputSubmit','InsertInputText','InsertMarquee','InsertOrderedList','InsertParagraph','InsertSelectDropdown','InsertSelectListbox','InsertTextArea','InsertUnorderedList','Italic','JustifyCenter','JustifyFull','JustifyLeft','JustifyNone','JustifyRight','LiveResize','MultipleSelection','Open','Outdent','OverWrite','Paste','PlayImage','Redo','Refresh','RemoveFormat','SaveAs','SelectAll','SizeToControl','SizeToControlHeight','SizeToControlWidth','Stop','StopImage','StrikeThrough','styleWithCSS','Subscript','Superscript','UnBookmark','Underline','Undo','Unlink','Unselect'), i;
+
+	for (n in tinyMCE.instances) {
+		inst = tinyMCE.instances[n];
+
+		if (!tinyMCE.isInstance(inst))
+			continue;
+
+		h += '<h2>Instance id: ' + inst.editorId + '</h2>';
+		h += '<table border="0" cellpadding="0" cellspacing="0" class="data">';
+
+		for (i=0; i<cmds.length; i++) {
+			v = null;
+
+			try {
+				v = tinyMCE.isGecko || inst.getDoc().queryCommandSupported(cmds[i]);
+				v = v ? inst.queryCommandState(cmds[i]) : 'Not supported';
+			} catch (ex) {
+				v = 'Not supported';
+			}
+
+			h += '<tr><td><input type="text" value="' + tinyMCE.xmlEncode(cmds[i]) + '" /></td><td><input type="text" value="' + tinyMCE.xmlEncode(v) + '" /></td></tr>';
+		}
+
+		h += '</table>';
+	}
+
+	se.innerHTML = h;
+}
+
+function renderUndoRedo() {
+	var se = document.getElementById('undo_redo'), inst, n, h = '', i, le, id, d, ur;
+	var f = document.forms[0];	
+
+	if (tinyMCE.undoLevels) {
+		le = tinyMCE.undoLevels;
+
+		h += '<h2>Global undo/redo</h2>';
+		h += '<table border="0" cellpadding="0" cellspacing="0" width="50%" class="data">';
+		h += '<tr><td>undoLevels.length</td><td>' + le.length + '</td></tr>';
+		h += '<tr><td>undoIndex</td><td>' + tinyMCE.undoIndex + '</td></tr>';
+		h += '</table>';
+
+		for (i=0; i<le.length; i++)
+			h += '<h3>Level: ' + i + ', Instance: ' + (le[i] ? le[i].editorId : 'null') + '</h3>';
+	}
+
+	for (n in tinyMCE.instances) {
+		inst = tinyMCE.instances[n];
+
+		if (!tinyMCE.isInstance(inst))
+			continue;
+
+		ur = inst.undoRedo;
+		le = ur.undoLevels;
+
+		h += '<hr /><h2>Instance id: ' + inst.editorId + '</h2>';
+		h += '<table border="0" cellpadding="0" cellspacing="0" width="50%" class="data">';
+		h += '<tr><td>undoLevels.length</td><td>' + le.length + '</td></tr>';
+		h += '<tr><td>undoIndex</td><td>' + ur.undoIndex + '</td></tr>';
+		h += '<tr><td>typingUndoIndex</td><td>' + ur.typingUndoIndex + '</td></tr>';
+		h += '<tr><td>undoRedo</td><td>' + ur.undoRedo + '</td></tr>';
+		h += '</table>';
+
+		for (i=0; i<le.length; i++) {
+			h += '<h3>Level: ' + i + (!le[i].bookmark ? "" : " [bookmark]") + '</h3>';
+			h += '<div class="undodata">' + tinyMCE.xmlEncode(le[i].content) + '</div>';
+
+			if (i > 0 && f.undo_diff.checked) {
+				d = diff_main(i > 0 ? le[i-1].content.replace(/[\r\n]+/g, '') : null, le[i].content.replace(/[\r\n]+/g, ''), false);
+				diff_cleanup_semantic(d);
+				h += '<h3>Diff ' + (i-1) + ',' + i + '</h3><div class="undodata">' + diff_prettyhtml(d) + '</div>';
+			}
+		}
+	}
+
+	se.innerHTML = h;
+}
+
+function clearLog() {
+	document.getElementById('log').innerHTML = '';
+	devkit._startTime = null;
+}
+
+function cancelAction() {
+	parent.document.getElementById('devkit').style.display = 'none';
+}
+
+function toggleDebugEvents(s) {
+	devkit._debugEvents(s);
+}
+
+function storeSelection() {
+	book = tinyMCE.selectedInstance.selection.getBookmark();
+
+	return false;
+}
+
+function restoreSelection() {
+	tinyMCE.selectedInstance.selection.moveToBookmark(book);
+
+	return false;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/devkit/jscripts/diff.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1192 @@
+// Diff_Match_Patch v1.3
+// Computes the difference between two texts to create a patch.
+// Applies the patch onto another text, allowing for errors.
+// Copyright (C) 2006 Neil Fraser
+// http://neil.fraser.name/software/diff_match_patch/
+
+// 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.
+
+// 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 (www.gnu.org) for more details.
+
+
+// Constants.
+// Redefine these in your program to override the defaults.
+
+// Number of seconds to map a diff before giving up.  (0 for infinity)
+var DIFF_TIMEOUT = 1.0;
+// Cost of an empty edit operation in terms of edit characters.
+var DIFF_EDIT_COST = 4;
+// Tweak the relative importance (0.0 = accuracy, 1.0 = proximity)
+var MATCH_BALANCE = 0.5;
+// At what point is no match declared (0.0 = perfection, 1.0 = very loose)
+var MATCH_THRESHOLD = 0.5;
+// The min and max cutoffs used when computing text lengths.
+var MATCH_MINLENGTH = 100;
+var MATCH_MAXLENGTH = 1000;
+// Chunk size for context length.
+var PATCH_MARGIN = 4;
+
+
+  //////////////////////////////////////////////////////////////////////
+ //  Diff                                                            //
+//////////////////////////////////////////////////////////////////////
+
+// The data structure representing a diff is an array of tuples:
+// [[-1, "Hello"], [1, "Goodbye"], [0, " world."]]
+// which means: delete "Hello", add "Goodbye" and keep " world."
+
+
+function diff_main(text1, text2, checklines) {
+  // Find the differences between two texts.  Return an array of changes.
+  // If checklines is present and false, then don't run a line-level diff first to identify the changed areas.
+  // Check for equality (speedup)
+  if (text1 == text2)
+    return [[0, text1]];
+
+  if (typeof checklines == 'undefined')
+    checklines = true;
+
+  var a;
+  // Trim off common prefix (speedup)
+  a = diff_prefix(text1, text2);
+  text1 = a[0];
+  text2 = a[1];
+  var commonprefix = a[2];
+
+  // Trim off common suffix (speedup)
+  a = diff_suffix(text1, text2);
+  text1 = a[0];
+  text2 = a[1];
+  var commonsuffix = a[2];
+
+  var diff, i;
+  var longtext = text1.length > text2.length ? text1 : text2;
+  var shorttext = text1.length > text2.length ? text2 : text1;
+
+  if (!text1) {  // Just add some text (speedup)
+    diff = [[1, text2]];
+  } else if (!text2) { // Just delete some text (speedup)
+    diff = [[-1, text1]];
+  } else if ((i = longtext.indexOf(shorttext)) != -1) {
+    // Shorter text is inside the longer text (speedup)
+    diff = [[1, longtext.substring(0, i)], [0, shorttext], [1, longtext.substring(i+shorttext.length)]];
+    // Swap insertions for deletions if diff is reversed.
+    if (text1.length > text2.length)
+      diff[0][0] = diff[2][0] = -1;
+  } else {
+    longtext = shorttext = null; // Garbage collect
+    // Check to see if the problem can be split in two.
+    var hm = diff_halfmatch(text1, text2);
+    if (hm) {
+      // A half-match was found, sort out the return data.
+      var text1_a = hm[0];
+      var text1_b = hm[1];
+      var text2_a = hm[2];
+      var text2_b = hm[3];
+      var mid_common = hm[4];
+      // Send both pairs off for separate processing.
+      var diff_a = diff_main(text1_a, text2_a, checklines);
+      var diff_b = diff_main(text1_b, text2_b, checklines);
+      // Merge the results.
+      diff = diff_a.concat([[0, mid_common]], diff_b);
+    } else {
+      // Perform a real diff.
+      if (checklines && text1.length + text2.length < 250)
+        checklines = false; // Too trivial for the overhead.
+      if (checklines) {
+        // Scan the text on a line-by-line basis first.
+        a = diff_lines2chars(text1, text2);
+        text1 = a[0];
+        text2 = a[1];
+        var linearray = a[2];
+      }
+      diff = diff_map(text1, text2);
+      if (!diff) // No acceptable result.
+        diff = [[-1, text1], [1, text2]];
+      if (checklines) {
+        diff_chars2lines(diff, linearray); // Convert the diff back to original text.
+        diff_cleanup_semantic(diff); // Eliminate freak matches (e.g. blank lines)
+
+        // Rediff any replacement blocks, this time on character-by-character basis.
+        diff.push([0, '']);  // Add a dummy entry at the end.
+        var pointer = 0;
+        var count_delete = 0;
+        var count_insert = 0;
+        var text_delete = '';
+        var text_insert = '';
+        while(pointer < diff.length) {
+          if (diff[pointer][0] == 1) {
+            count_insert++;
+            text_insert += diff[pointer][1];
+          } else if (diff[pointer][0] == -1) {
+            count_delete++;
+            text_delete += diff[pointer][1];
+          } else {  // Upon reaching an equality, check for prior redundancies.
+            if (count_delete >= 1 && count_insert >= 1) {
+              // Delete the offending records and add the merged ones.
+              a = diff_main(text_delete, text_insert, false);
+              diff.splice(pointer - count_delete - count_insert, count_delete + count_insert);
+              pointer = pointer - count_delete - count_insert;
+              for (i=a.length-1; i>=0; i--)
+                diff.splice(pointer, 0, a[i]);
+              pointer = pointer + a.length;
+            }
+            count_insert = 0;
+            count_delete = 0;
+            text_delete = '';
+            text_insert = '';
+          }
+          pointer++;
+        }
+        diff.pop();  // Remove the dummy entry at the end.
+
+      }
+    }
+  }
+
+  if (commonprefix)
+    diff.unshift([0, commonprefix]);
+  if (commonsuffix)
+    diff.push([0, commonsuffix]);
+  diff_cleanup_merge(diff);
+  return diff;
+}
+
+
+function diff_lines2chars(text1, text2) {
+  // Split text into an array of strings.
+  // Reduce the texts to a string of hashes where each character represents one line.
+  var linearray = new Array();  // linearray[4] == "Hello\n"
+  var linehash = new Object();  // linehash["Hello\n"] == 4
+
+  // "\x00" is a valid JavaScript character, but the Venkman debugger doesn't like it (bug 335098)
+  // So we'll insert a junk entry to avoid generating a null character.
+  linearray.push('');
+
+  function diff_lines2chars_munge(text) {
+    // My first ever closure!
+    var i, line;
+    var chars = '';
+    while (text) {
+      i = text.indexOf('\n');
+      if (i == -1)
+        i = text.length;
+      line = text.substring(0, i+1);
+      text = text.substring(i+1);
+      if (linehash.hasOwnProperty ? linehash.hasOwnProperty(line) : (linehash[line] !== undefined)) {
+        chars += String.fromCharCode(linehash[line]);
+      } else {
+        linearray.push(line);
+        linehash[line] = linearray.length - 1;
+        chars += String.fromCharCode(linearray.length - 1);
+      }
+    }
+    return chars;
+  }
+
+  var chars1 = diff_lines2chars_munge(text1);
+  var chars2 = diff_lines2chars_munge(text2);
+  return [chars1, chars2, linearray];
+}
+
+
+function diff_chars2lines(diff, linearray) {
+  // Rehydrate the text in a diff from a string of line hashes to real lines of text.
+  var chars, text;
+  for (var x=0; x<diff.length; x++) {
+    chars = diff[x][1];
+    text = '';
+    for (var y=0; y<chars.length; y++)
+      text += linearray[chars.charCodeAt(y)];
+    diff[x][1] = text;
+  }
+}
+
+
+function diff_map(text1, text2) {
+  // Explore the intersection points between the two texts.
+  var now = new Date();
+  var ms_end = now.getTime() + DIFF_TIMEOUT * 1000; // Don't run for too long.
+  var max = (text1.length + text2.length) / 2;
+  var v_map1 = new Array();
+  var v_map2 = new Array();
+  var v1 = new Object();
+  var v2 = new Object();
+  v1[1] = 0;
+  v2[1] = 0;
+  var x, y;
+  var footstep; // Used to track overlapping paths.
+  var footsteps = new Object();
+  var done = false;
+  var hasOwnProperty = !!(footsteps.hasOwnProperty);
+  // If the total number of characters is odd, then the front path will collide with the reverse path.
+  var front = (text1.length + text2.length) % 2;
+  for (var d=0; d<max; d++) {
+    now = new Date();
+    if (DIFF_TIMEOUT > 0 && now.getTime() > ms_end) // Timeout reached
+      return null;
+
+    // Walk the front path one step.
+    v_map1[d] = new Object();
+    for (var k=-d; k<=d; k+=2) {
+      if (k == -d || k != d && v1[k-1] < v1[k+1])
+        x = v1[k+1];
+      else
+        x = v1[k-1]+1;
+      y = x - k;
+      footstep = x+","+y;
+      if (front && (hasOwnProperty ? footsteps.hasOwnProperty(footstep) : (footsteps[footstep] !== undefined)))
+        done = true;
+      if (!front)
+        footsteps[footstep] = d;
+      while (!done && x < text1.length && y < text2.length && text1.charAt(x) == text2.charAt(y)) {
+        x++; y++;
+        footstep = x+","+y;
+        if (front && (hasOwnProperty ? footsteps.hasOwnProperty(footstep) : (footsteps[footstep] !== undefined)))
+          done = true;
+        if (!front)
+          footsteps[footstep] = d;
+      }
+      v1[k] = x;
+      v_map1[d][x+","+y] = true;
+      if (done) {
+        // Front path ran over reverse path.
+        v_map2 = v_map2.slice(0, footsteps[footstep]+1);
+        var a = diff_path1(v_map1, text1.substring(0, x), text2.substring(0, y));
+        return a.concat(diff_path2(v_map2, text1.substring(x), text2.substring(y)));
+      }
+    }
+
+    // Walk the reverse path one step.
+    v_map2[d] = new Object();
+    for (var k=-d; k<=d; k+=2) {
+      if (k == -d || k != d && v2[k-1] < v2[k+1])
+        x = v2[k+1];
+      else
+        x = v2[k-1]+1;
+      y = x - k;
+      footstep = (text1.length-x)+","+(text2.length-y);
+      if (!front && (hasOwnProperty ? footsteps.hasOwnProperty(footstep) : (footsteps[footstep] !== undefined)))
+        done = true;
+      if (front)
+        footsteps[footstep] = d;
+      while (!done && x < text1.length && y < text2.length && text1.charAt(text1.length-x-1) == text2.charAt(text2.length-y-1)) {
+        x++; y++;
+        footstep = (text1.length-x)+","+(text2.length-y);
+        if (!front && (hasOwnProperty ? footsteps.hasOwnProperty(footstep) : (footsteps[footstep] !== undefined)))
+          done = true;
+        if (front)
+          footsteps[footstep] = d;
+      }
+      v2[k] = x;
+      v_map2[d][x+","+y] = true;
+      if (done) {
+        // Reverse path ran over front path.
+        v_map1 = v_map1.slice(0, footsteps[footstep]+1);
+        var a = diff_path1(v_map1, text1.substring(0, text1.length-x), text2.substring(0, text2.length-y));
+        return a.concat(diff_path2(v_map2, text1.substring(text1.length-x), text2.substring(text2.length-y)));
+      }
+    }
+  }
+  // Number of diffs equals number of characters, no commonality at all.
+  return null;
+}
+
+
+function diff_path1(v_map, text1, text2) {
+  // Work from the middle back to the start to determine the path.
+  var path = [];
+  var x = text1.length;
+  var y = text2.length;
+  var last_op = null;
+  for (var d=v_map.length-2; d>=0; d--) {
+    while(1) {
+      if (v_map[d].hasOwnProperty ? v_map[d].hasOwnProperty((x-1)+","+y) : (v_map[d][(x-1)+","+y] !== undefined)) {
+        x--;
+        if (last_op === -1)
+          path[0][1] = text1.charAt(x) + path[0][1];
+        else
+          path.unshift([-1, text1.charAt(x)]);
+        last_op = -1;
+        break;
+      } else if (v_map[d].hasOwnProperty ? v_map[d].hasOwnProperty(x+","+(y-1)) : (v_map[d][x+","+(y-1)] !== undefined)) {
+        y--;
+        if (last_op === 1)
+          path[0][1] = text2.charAt(y) + path[0][1];
+        else
+          path.unshift([1, text2.charAt(y)]);
+        last_op = 1;
+        break;
+      } else {
+        x--;
+        y--;
+        //if (text1.charAt(x) != text2.charAt(y))
+        //  return alert("No diagonal.  Can't happen. (diff_path1)");
+        if (last_op === 0)
+          path[0][1] = text1.charAt(x) + path[0][1];
+        else
+          path.unshift([0, text1.charAt(x)]);
+        last_op = 0;
+      }
+    }
+  }
+  return path;
+}
+
+
+function diff_path2(v_map, text1, text2) {
+  // Work from the middle back to the end to determine the path.
+  var path = [];
+  var x = text1.length;
+  var y = text2.length;
+  var last_op = null;
+  for (var d=v_map.length-2; d>=0; d--) {
+    while(1) {
+      if (v_map[d].hasOwnProperty ? v_map[d].hasOwnProperty((x-1)+","+y) : (v_map[d][(x-1)+","+y] !== undefined)) {
+        x--;
+        if (last_op === -1)
+          path[path.length-1][1] += text1.charAt(text1.length-x-1);
+        else
+          path.push([-1, text1.charAt(text1.length-x-1)]);
+        last_op = -1;
+        break;
+      } else if (v_map[d].hasOwnProperty ? v_map[d].hasOwnProperty(x+","+(y-1)) : (v_map[d][x+","+(y-1)] !== undefined)) {
+        y--;
+        if (last_op === 1)
+          path[path.length-1][1] += text2.charAt(text2.length-y-1);
+        else
+          path.push([1, text2.charAt(text2.length-y-1)]);
+        last_op = 1;
+        break;
+      } else {
+        x--;
+        y--;
+        //if (text1.charAt(text1.length-x-1) != text2.charAt(text2.length-y-1))
+        //  return alert("No diagonal.  Can't happen. (diff_path2)");
+        if (last_op === 0)
+          path[path.length-1][1] += text1.charAt(text1.length-x-1);
+        else
+          path.push([0, text1.charAt(text1.length-x-1)]);
+        last_op = 0;
+      }
+    }
+  }
+  return path;
+}
+
+
+function diff_prefix(text1, text2) {
+  // Trim off common prefix
+  var pointermin = 0;
+  var pointermax = Math.min(text1.length, text2.length);
+  var pointermid = pointermax;
+  while(pointermin < pointermid) {
+    if (text1.substring(0, pointermid) == text2.substring(0, pointermid))
+      pointermin = pointermid;
+    else
+      pointermax = pointermid;
+    pointermid = Math.floor((pointermax - pointermin) / 2 + pointermin);
+  }
+  var commonprefix = text1.substring(0, pointermid);
+  text1 = text1.substring(pointermid);
+  text2 = text2.substring(pointermid);
+  return [text1, text2, commonprefix];
+}
+
+
+function diff_suffix(text1, text2) {
+  // Trim off common suffix
+  var pointermin = 0;
+  var pointermax = Math.min(text1.length, text2.length);
+  var pointermid = pointermax;
+  while(pointermin < pointermid) {
+    if (text1.substring(text1.length-pointermid) == text2.substring(text2.length-pointermid))
+      pointermin = pointermid;
+    else
+      pointermax = pointermid;
+    pointermid = Math.floor((pointermax - pointermin) / 2 + pointermin);
+  }
+  var commonsuffix = text1.substring(text1.length-pointermid);
+  text1 = text1.substring(0, text1.length-pointermid);
+  text2 = text2.substring(0, text2.length-pointermid);
+  return [text1, text2, commonsuffix];
+}
+
+
+function diff_halfmatch(text1, text2) {
+  // Do the two texts share a substring which is at least half the length of the longer text?
+  var longtext = text1.length > text2.length ? text1 : text2;
+  var shorttext = text1.length > text2.length ? text2 : text1;
+  if (longtext.length < 10 || shorttext.length < 1)
+    return null; // Pointless.
+
+  function diff_halfmatch_i(longtext, shorttext, i) {
+    // Start with a 1/4 length substring at position i as a seed.
+    var seed = longtext.substring(i, i+Math.floor(longtext.length/4));
+    var j = -1;
+    var best_common = '';
+    var best_longtext_a, best_longtext_b, best_shorttext_a, best_shorttext_b;
+    while ((j = shorttext.indexOf(seed, j+1)) != -1) {
+      var my_prefix = diff_prefix(longtext.substring(i), shorttext.substring(j));
+      var my_suffix = diff_suffix(longtext.substring(0, i), shorttext.substring(0, j));
+      if (best_common.length < (my_suffix[2] + my_prefix[2]).length) {
+        best_common = my_suffix[2] + my_prefix[2];
+        best_longtext_a = my_suffix[0];
+        best_longtext_b = my_prefix[0];
+        best_shorttext_a = my_suffix[1];
+        best_shorttext_b = my_prefix[1];
+      }
+    }
+    if (best_common.length >= longtext.length/2)
+      return [best_longtext_a, best_longtext_b, best_shorttext_a, best_shorttext_b, best_common];
+    else
+      return null;
+  }
+
+  // First check if the second quarter is the seed for a half-match.
+  var hm1 = diff_halfmatch_i(longtext, shorttext, Math.ceil(longtext.length/4));
+  // Check again based on the third quarter.
+  var hm2 = diff_halfmatch_i(longtext, shorttext, Math.ceil(longtext.length/2));
+  var hm;
+  if (!hm1 && !hm2)
+    return null;
+  else if (!hm2)
+    hm = hm1;
+  else if (!hm1)
+    hm = hm2;
+  else // Both matched.  Select the longest.
+    hm = hm1[4].length > hm2[4].length ? hm1 : hm2;
+
+  // A half-match was found, sort out the return data.
+  if (text1.length > text2.length) {
+    var text1_a = hm[0];
+    var text1_b = hm[1];
+    var text2_a = hm[2];
+    var text2_b = hm[3];
+  } else {
+    var text2_a = hm[0];
+    var text2_b = hm[1];
+    var text1_a = hm[2];
+    var text1_b = hm[3];
+  }
+  var mid_common = hm[4];
+  return [text1_a, text1_b, text2_a, text2_b, mid_common];
+}
+
+
+function diff_cleanup_semantic(diff) {
+  // Reduce the number of edits by eliminating semantically trivial equalities.
+  var changes = false;
+  var equalities = []; // Stack of indices where equalities are found.
+  var lastequality = null; // Always equal to equalities[equalities.length-1][1]
+  var pointer = 0; // Index of current position.
+  var length_changes1 = 0; // Number of characters that changed prior to the equality.
+  var length_changes2 = 0; // Number of characters that changed after the equality.
+  while (pointer < diff.length) {
+    if (diff[pointer][0] == 0) { // equality found
+      equalities.push(pointer);
+      length_changes1 = length_changes2;
+      length_changes2 = 0;
+      lastequality = diff[pointer][1];
+    } else { // an insertion or deletion
+      length_changes2 += diff[pointer][1].length;
+      if (lastequality != null && (lastequality.length <= length_changes1) && (lastequality.length <= length_changes2)) {
+        //alert("Splitting: '"+lastequality+"'");
+        diff.splice(equalities[equalities.length-1], 0, [-1, lastequality]); // Duplicate record
+        diff[equalities[equalities.length-1]+1][0] = 1; // Change second copy to insert.
+        equalities.pop();  // Throw away the equality we just deleted;
+        equalities.pop();  // Throw away the previous equality;
+        pointer = equalities.length ? equalities[equalities.length-1] : -1;
+        length_changes1 = 0; // Reset the counters.
+        length_changes2 = 0;
+        lastequality = null;
+        changes = true;
+      }
+    }
+    pointer++;
+  }
+
+  if (changes)
+    diff_cleanup_merge(diff);
+}
+
+
+function diff_cleanup_efficiency(diff) {
+  // Reduce the number of edits by eliminating operationally trivial equalities.
+  var changes = false;
+  var equalities = []; // Stack of indices where equalities are found.
+  var lastequality = ''; // Always equal to equalities[equalities.length-1][1]
+  var pointer = 0; // Index of current position.
+  var pre_ins = false; // Is there an insertion operation before the last equality.
+  var pre_del = false; // Is there an deletion operation before the last equality.
+  var post_ins = false; // Is there an insertion operation after the last equality.
+  var post_del = false; // Is there an deletion operation after the last equality.
+  while (pointer < diff.length) {
+    if (diff[pointer][0] == 0) { // equality found
+      if (diff[pointer][1].length < DIFF_EDIT_COST && (post_ins || post_del)) {
+        // Candidate found.
+        equalities.push(pointer);
+        pre_ins = post_ins;
+        pre_del = post_del;
+        lastequality = diff[pointer][1];
+      } else {
+        // Not a candidate, and can never become one.
+        equalities = [];
+        lastequality = '';
+      }
+      post_ins = post_del = false;
+    } else { // an insertion or deletion
+      if (diff[pointer][0] == -1)
+        post_del = true;
+      else
+        post_ins = true;
+      // Five types to be split:
+      // <ins>A</ins><del>B</del>XY<ins>C</ins><del>D</del>
+      // <ins>A</ins>X<ins>C</ins><del>D</del>
+      // <ins>A</ins><del>B</del>X<ins>C</ins>
+      // <ins>A</del>X<ins>C</ins><del>D</del>
+      // <ins>A</ins><del>B</del>X<del>C</del>
+      if (lastequality && ((pre_ins && pre_del && post_ins && post_del) || ((lastequality.length < DIFF_EDIT_COST/2) && (pre_ins + pre_del + post_ins + post_del) == 3))) {
+        //alert("Splitting: '"+lastequality+"'");
+        diff.splice(equalities[equalities.length-1], 0, [-1, lastequality]); // Duplicate record
+        diff[equalities[equalities.length-1]+1][0] = 1; // Change second copy to insert.
+        equalities.pop();  // Throw away the equality we just deleted;
+        lastequality = '';
+        if (pre_ins && pre_del) {
+          // No changes made which could affect previous entry, keep going.
+          post_ins = post_del = true;
+          equalities = [];
+        } else {
+          equalities.pop();  // Throw away the previous equality;
+          pointer = equalities.length ? equalities[equalities.length-1] : -1;
+          post_ins = post_del = false;
+        }
+        changes = true;
+      }
+    }
+    pointer++;
+  }
+
+  if (changes)
+    diff_cleanup_merge(diff);
+}
+
+
+function diff_cleanup_merge(diff) {
+  // Reorder and merge like edit sections.  Merge equalities.
+  // Any edit section can move as long as it doesn't cross an equality.
+  diff.push([0, '']);  // Add a dummy entry at the end.
+  var pointer = 0;
+  var count_delete = 0;
+  var count_insert = 0;
+  var text_delete = '';
+  var text_insert = '';
+  var record_insert, record_delete;
+  var my_xfix;
+  while(pointer < diff.length) {
+    if (diff[pointer][0] == 1) {
+      count_insert++;
+      text_insert += diff[pointer][1];
+      pointer++;
+    } else if (diff[pointer][0] == -1) {
+      count_delete++;
+      text_delete += diff[pointer][1];
+      pointer++;
+    } else {  // Upon reaching an equality, check for prior redundancies.
+      if (count_delete > 1 || count_insert > 1) {
+        if (count_delete > 1 && count_insert > 1) {
+          // Factor out any common prefixies.
+          my_xfix = diff_prefix(text_insert, text_delete);
+          if (my_xfix[2] != '') {
+            if ((pointer - count_delete - count_insert) > 0 && diff[pointer - count_delete - count_insert - 1][0] == 0) {
+              text_insert = my_xfix[0];
+              text_delete = my_xfix[1];
+              diff[pointer - count_delete - count_insert - 1][1] += my_xfix[2];
+            }
+          }
+          // Factor out any common suffixies.
+          my_xfix = diff_suffix(text_insert, text_delete);
+          if (my_xfix[2] != '') {
+            text_insert = my_xfix[0];
+            text_delete = my_xfix[1];
+            diff[pointer][1] = my_xfix[2] + diff[pointer][1];
+          }
+        }
+        // Delete the offending records and add the merged ones.
+        if (count_delete == 0)
+          diff.splice(pointer - count_delete - count_insert, count_delete + count_insert, [1, text_insert]);
+        else if (count_insert == 0)
+          diff.splice(pointer - count_delete - count_insert, count_delete + count_insert, [-1, text_delete]);
+        else
+          diff.splice(pointer - count_delete - count_insert, count_delete + count_insert, [-1, text_delete], [1, text_insert]);
+        pointer = pointer - count_delete - count_insert + (count_delete ? 1 : 0) + (count_insert ? 1 : 0) + 1;
+      } else if (pointer != 0 && diff[pointer-1][0] == 0) {
+        // Merge this equality with the previous one.
+        diff[pointer-1][1] += diff[pointer][1];
+        diff.splice(pointer, 1);
+      } else {
+        pointer++;
+      }
+      count_insert = 0;
+      count_delete = 0;
+      text_delete = '';
+      text_insert = '';
+    }
+  }
+  if (diff[diff.length-1][1] == '')
+    diff.pop();  // Remove the dummy entry at the end.
+}
+
+
+function diff_addindex(diff) {
+  // Add an index to each tuple, represents where the tuple is located in text2.
+  // e.g. [[-1, 'h', 0], [1, 'c', 0], [0, 'at', 1]]
+  var i = 0;
+  for (var x=0; x<diff.length; x++) {
+    diff[x].push(i);
+    if (diff[x][0] != -1)
+      i += diff[x][1].length;
+  }
+}
+
+
+function diff_xindex(diff, loc) {
+  // loc is a location in text1, compute and return the equivalent location in text2.
+  // e.g. "The cat" vs "The big cat", 1->1, 5->8
+  var chars1 = 0;
+  var chars2 = 0;
+  var last_chars1 = 0;
+  var last_chars2 = 0;
+  for (var x=0; x<diff.length; x++) {
+    if (diff[x][0] != 1) // Equality or deletion.
+      chars1 += diff[x][1].length;
+    if (diff[x][0] != -1) // Equality or insertion.
+      chars2 += diff[x][1].length;
+    if (chars1 > loc) // Overshot the location.
+      break;
+    last_chars1 = chars1;
+    last_chars2 = chars2;
+  }
+  if (diff.length != x && diff[x][0] == -1) // The location was deleted.
+    return last_chars2;
+  // Add the remaining character length.
+  return last_chars2 + (loc - last_chars1);
+}
+
+
+function diff_prettyhtml(diff) {
+  // Convert a diff array into a pretty HTML report.
+  diff_addindex(diff);
+  var html = '';
+  for (var x=0; x<diff.length; x++) {
+    var m = diff[x][0]; // Mode (-1=delete, 0=copy, 1=add)
+    var t = diff[x][1]; // Text of change.
+    var i = diff[x][2]; // Index of change.
+    t = t.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
+    t = t.replace(/\n/g, "&para;<BR>");
+    if (m == -1)
+      html += "<DEL STYLE='background:#FFE6E6;' TITLE='i="+i+"'>"+t+"</DEL>";
+    else if (m == 1)
+      html += "<INS STYLE='background:#E6FFE6;' TITLE='i="+i+"'>"+t+"</INS>";
+    else
+      html += "<SPAN TITLE='i="+i+"'>"+t+"</SPAN>";
+  }
+  return html;
+}
+
+
+  //////////////////////////////////////////////////////////////////////
+ //  Match                                                           //
+//////////////////////////////////////////////////////////////////////
+
+
+function match_getmaxbits() {
+  // Compute the number of bits in an int.
+  // The normal answer for JavaScript is 32.
+  var maxbits = 0;
+  var oldi = 1;
+  var newi = 2;
+  while (oldi != newi) {
+    maxbits++;
+    oldi = newi;
+    newi = newi << 1;
+  }
+  return maxbits;
+}
+var MATCH_MAXBITS = match_getmaxbits();
+
+
+function match_main(text, pattern, loc) {
+  // Locate the best instance of 'pattern' in 'text' near 'loc'.
+  loc = Math.max(0, Math.min(loc, text.length-pattern.length));
+  if (text == pattern) {
+    // Shortcut (potentially not guaranteed by the algorithm)
+    return 0;
+  } else if (text.length == 0) {
+    // Nothing to match.
+    return null;
+  } else if (text.substring(loc, loc + pattern.length) == pattern) {
+    // Perfect match at the perfect spot!  (Includes case of null pattern)
+    return loc;
+  } else {
+    // Do a fuzzy compare.
+    var match = match_bitap(text, pattern, loc);
+    return match;
+  }
+}
+
+
+function match_bitap(text, pattern, loc) {
+  // Locate the best instance of 'pattern' in 'text' near 'loc' using the Bitap algorithm.
+  if (pattern.length > MATCH_MAXBITS)
+    return alert("Pattern too long for this browser.");
+
+  // Initialise the alphabet.
+  var s = match_alphabet(pattern);
+
+  var score_text_length = text.length;
+  // Coerce the text length between reasonable maximums and minimums.
+  score_text_length = Math.max(score_text_length, MATCH_MINLENGTH);
+  score_text_length = Math.min(score_text_length, MATCH_MAXLENGTH);
+
+  function match_bitap_score (e, x) {
+    // Compute and return the score for a match with e errors and x location.
+    var d = Math.abs(loc-x);
+    return (e / pattern.length / MATCH_BALANCE) + (d / score_text_length / (1.0 - MATCH_BALANCE));
+  }
+
+  // Highest score beyond which we give up.
+  var score_threshold = MATCH_THRESHOLD;
+  // Is there a nearby exact match? (speedup)
+  var best_loc = text.indexOf(pattern, loc);
+  if (best_loc != -1)
+    score_threshold = Math.min(match_bitap_score(0, best_loc), score_threshold);
+  // What about in the other direction? (speedup)
+  best_loc = text.lastIndexOf(pattern, loc+pattern.length);
+  if (best_loc != -1)
+    score_threshold = Math.min(match_bitap_score(0, best_loc), score_threshold);
+
+  // Initialise the bit arrays.
+  var r = Array();
+  var d = -1;
+  var matchmask = Math.pow(2, pattern.length-1);
+  best_loc = null;
+
+  var bin_min, bin_mid;
+  var bin_max = Math.max(loc+loc, text.length);
+  var last_rd;
+  for (var d=0; d<pattern.length; d++) {
+    // Scan for the best match; each iteration allows for one more error.
+    var rd = Array(text.length);
+
+    // Run a binary search to determine how far from 'loc' we can stray at this error level.
+    bin_min = loc;
+    bin_mid = bin_max;
+    while(bin_min < bin_mid) {
+      if (match_bitap_score(d, bin_mid) < score_threshold)
+        bin_min = bin_mid;
+      else
+        bin_max = bin_mid;
+      bin_mid = Math.floor((bin_max - bin_min) / 2 + bin_min);
+    }
+    bin_max = bin_mid; // Use the result from this iteration as the maximum for the next.
+    var start = Math.max(0, loc - (bin_mid - loc) - 1);
+    var finish = Math.min(text.length-1, pattern.length + bin_mid);
+
+    if (text.charAt(finish) == pattern.charAt(pattern.length-1))
+      rd[finish] = Math.pow(2, d+1)-1;
+    else
+      rd[finish] = Math.pow(2, d)-1;
+    for (var j=finish-1; j>=start; j--) {
+      // The alphabet (s) is a sparse hash, so the following lines generate warnings.
+      if (d == 0) // First pass: exact match.
+        rd[j] = ((rd[j+1] << 1) | 1) & s[text.charAt(j)];
+      else // Subsequent passes: fuzzy match.
+        rd[j] = ((rd[j+1] << 1) | 1) & s[text.charAt(j)] | ((last_rd[j+1] << 1) | 1) | ((last_rd[j] << 1) | 1) | last_rd[j+1];
+      if (rd[j] & matchmask) {
+        var score = match_bitap_score(d, j);
+        // This match will almost certainly be better than any existing match.  But check anyway.
+        if (score <= score_threshold) {
+          // Told you so.
+          score_threshold = score;
+          best_loc = j;
+          if (j > loc) {
+            // When passing loc, don't exceed our current distance from loc.
+            start = Math.max(0, loc - (j - loc));
+          } else {
+            // Already passed loc, downhill from here on in.
+            break;
+          }
+        }
+      }
+    }
+    if (match_bitap_score(d+1, loc) > score_threshold) // No hope for a (better) match at greater error levels.
+      break;
+    last_rd = rd;
+  }
+  return best_loc;
+}
+
+
+function match_alphabet(pattern) {
+  // Initialise the alphabet for the Bitap algorithm.
+  var s = Object();
+  for (var i=0; i<pattern.length; i++)
+    s[pattern.charAt(i)] = 0;
+  for (var i=0; i<pattern.length; i++)
+    s[pattern.charAt(i)] |= Math.pow(2, pattern.length-i-1);
+  return s;
+}
+
+
+  //////////////////////////////////////////////////////////////////////
+ //  Patch                                                           //
+//////////////////////////////////////////////////////////////////////
+
+
+function patch_obj() {
+  // Constructor for a patch object.
+  this.diffs = [];
+  this.start1 = null;
+  this.start2 = null;
+  this.length1 = 0;
+  this.length2 = 0;
+
+  this.toString = function() {
+    // Emmulate GNU diff's format.
+    // Header: @@ -382,8 +481,9 @@
+    // Indicies are printed as 1-based, not 0-based.
+    var coords1, coords2;
+    if (this.length1 == 0)
+      coords1 = this.start1+",0";
+    else if (this.length1 == 1)
+      coords1 = this.start1+1;
+    else
+      coords1 = (this.start1+1)+","+this.length1;
+    if (this.length2 == 0)
+      coords2 = this.start2+",0";
+    else if (this.length2 == 1)
+      coords2 = this.start2+1;
+    else
+      coords2 = (this.start2+1)+","+this.length2;
+    var txt = "@@ -"+coords1+" +"+coords2+" @@\n";
+    // Escape the body of the patch with %xx notation.
+    for (var x=0; x<this.diffs.length; x++)
+      txt += ("- +".charAt(this.diffs[x][0]+1)) + encodeURI(this.diffs[x][1]) + "\n";
+    return txt.replace(/%20/g, ' ');
+  }
+
+  this.text1 = function() {
+    // Compute and return the source text (all equalities and deletions).
+    var txt = '';
+    for (var x=0; x<this.diffs.length; x++)
+      if (this.diffs[x][0] == 0 || this.diffs[x][0] == -1)
+        txt += this.diffs[x][1];
+    return txt;
+  }
+
+  this.text2 = function() {
+    // Compute and return the destination text (all equalities and insertions).
+    var txt = '';
+    for (var x=0; x<this.diffs.length; x++)
+      if (this.diffs[x][0] == 0 || this.diffs[x][0] == 1)
+        txt += this.diffs[x][1];
+    return txt;
+  }
+}
+
+
+function patch_addcontext(patch, text) {
+  var pattern = text.substring(patch.start2, patch.start2+patch.length1);
+  var padding = 0;
+  // Increase the context until we're unique (but don't let the pattern expand beyond MATCH_MAXBITS).
+  while (text.indexOf(pattern) != text.lastIndexOf(pattern) && pattern.length < MATCH_MAXBITS-PATCH_MARGIN-PATCH_MARGIN) {
+    padding += PATCH_MARGIN;
+    pattern = text.substring(patch.start2 - padding, patch.start2+patch.length1 + padding);
+  }
+  // Add one chunk for good luck.
+  padding += PATCH_MARGIN;
+  // Add the prefix.
+  var prefix = text.substring(patch.start2 - padding, patch.start2);
+  if (prefix != '')
+    patch.diffs.unshift([0, prefix]);
+  // Add the suffix
+  var suffix = text.substring(patch.start2+patch.length1, patch.start2+patch.length1 + padding);
+  if (suffix != '')
+    patch.diffs.push([0, suffix]);
+
+  // Roll back the start points.
+  patch.start1 -= prefix.length;
+  patch.start2 -= prefix.length;
+  // Extend the lengths.
+  patch.length1 += prefix.length + suffix.length;
+  patch.length2 += prefix.length + suffix.length;
+}
+
+
+function patch_make(text1, text2, diff) {
+  // Compute a list of patches to turn text1 into text2.
+  // Use diff if provided, otherwise compute it ourselves.
+  if (typeof diff == 'undefined') {
+    diff = diff_main(text1, text2, true);
+    if (diff.length > 2) {
+      diff_cleanup_semantic(diff);
+      diff_cleanup_efficiency(diff);
+    }
+  }
+  if (diff.length == 0)
+    return []; // Get rid of the null case.
+  var patches = [];
+  var patch = new patch_obj();
+  var char_count1 = 0; // Number of characters into the text1 string.
+  var char_count2 = 0; // Number of characters into the text2 string.
+  var last_type = null;
+  var prepatch_text = text1; // Recreate the patches to determine context info.
+  var postpatch_text = text1;
+  for (var x=0; x<diff.length; x++) {
+    var diff_type = diff[x][0];
+    var diff_text = diff[x][1];
+
+    if (patch.diffs.length == 0 && diff_type != 0) {
+      // A new patch starts here.
+      patch.start1 = char_count1;
+      patch.start2 = char_count2;
+    }
+
+    if (diff_type == 1) {
+      // Insertion
+      patch.diffs.push(diff[x]);
+      patch.length2 += diff_text.length;
+      postpatch_text = postpatch_text.substring(0, char_count2) + diff_text + postpatch_text.substring(char_count2);
+    } else if (diff_type == -1) {
+      // Deletion.
+      patch.length1 += diff_text.length;
+      patch.diffs.push(diff[x]);
+      postpatch_text = postpatch_text.substring(0, char_count2) + postpatch_text.substring(char_count2 + diff_text.length);
+    } else if (diff_type == 0 && diff_text.length <= 2*PATCH_MARGIN && patch.diffs.length != 0 && diff.length != x+1) {
+      // Small equality inside a patch.
+      patch.diffs.push(diff[x]);
+      patch.length1 += diff_text.length;
+      patch.length2 += diff_text.length;
+    }
+
+    last_type = diff_type;
+    if (diff_type == 0 && diff_text.length >= 2*PATCH_MARGIN) {
+      // Time for a new patch.
+      if (patch.diffs.length != 0) {
+        patch_addcontext(patch, prepatch_text);
+        patches.push(patch);
+        var patch = new patch_obj();
+        last_type = null;
+        prepatch_text = postpatch_text;
+      }
+    }
+
+    // Update the current character count.
+    if (diff_type != 1)
+      char_count1 += diff_text.length;
+    if (diff_type != -1)
+      char_count2 += diff_text.length;
+  }
+  // Pick up the leftover patch if not empty.
+  if (patch.diffs.length != 0) {
+    patch_addcontext(patch, prepatch_text);
+    patches.push(patch);
+  }
+
+  return patches;
+}
+
+
+function patch_apply(patches, text) {
+  // Merge a set of patches onto the text.
+  // Return a patched text, as well as a list of true/false values indicating which patches were applied.
+  patch_splitmax(patches);
+  var results = [];
+  var delta = 0;
+  var expected_loc, start_loc;
+  var text1, text2;
+  var diff, mod, index1, index2;
+  for (var x=0; x<patches.length; x++) {
+    expected_loc = patches[x].start2 + delta;
+    text1 = patches[x].text1();
+    start_loc = match_main(text, text1, expected_loc);
+    if (start_loc == null) {
+      // No match found.  :(
+      results.push(false);
+    } else {
+      // Found a match.  :)
+      results.push(true);
+      delta = start_loc - expected_loc;
+      text2 = text.substring(start_loc, start_loc + text1.length);
+      if (text1 == text2) {
+        // Perfect match, just shove the replacement text in.
+        text = text.substring(0, start_loc) + patches[x].text2() + text.substring(start_loc + text1.length);
+      } else {
+        // Imperfect match.  Run a diff to get a framework of equivalent indicies.
+        diff = diff_main(text1, text2, false);
+        index1 = 0;
+        for (var y=0; y<patches[x].diffs.length; y++) {
+          mod = patches[x].diffs[y];
+          if (mod[0] != 0)
+            index2 = diff_xindex(diff, index1);
+          if (mod[0] == 1) // Insertion
+            text = text.substring(0, start_loc + index2) + mod[1] + text.substring(start_loc + index2);
+          else if (mod[0] == -1) // Deletion
+            text = text.substring(0, start_loc + index2) + text.substring(start_loc + diff_xindex(diff, index1 + mod[1].length));
+          if (mod[0] != -1)
+            index1 += mod[1].length;
+        }
+      }
+    }
+  }
+  return [text, results];
+}
+
+
+function patch_splitmax(patches) {
+  // Look through the patches and break up any which are longer than the maximum limit of the match algorithm.
+  var bigpatch, patch, patch_size, start1, start2, diff_type, diff_text, precontext, postcontext, empty;
+  for (var x=0; x<patches.length; x++) {
+    if (patches[x].length1 > MATCH_MAXBITS) {
+      bigpatch = patches[x];
+      // Remove the big old patch.
+      patches.splice(x, 1);
+      patch_size = MATCH_MAXBITS;
+      start1 = bigpatch.start1;
+      start2 = bigpatch.start2;
+      precontext = '';
+      while (bigpatch.diffs.length != 0) {
+        // Create one of several smaller patches.
+        patch = new patch_obj();
+        empty = true;
+        patch.start1 = start1 - precontext.length;
+        patch.start2 = start2 - precontext.length;
+        if (precontext  != '') {
+          patch.length1 = patch.length2 = precontext.length;
+          patch.diffs.push([0, precontext]);
+        }
+        while (bigpatch.diffs.length != 0 && patch.length1 < patch_size - PATCH_MARGIN) {
+          diff_type = bigpatch.diffs[0][0];
+          diff_text = bigpatch.diffs[0][1];
+          if (diff_type == 1) {
+            // Insertions are harmless.
+            patch.length2 += diff_text.length;
+            start2 += diff_text.length;
+            patch.diffs.push(bigpatch.diffs.shift());
+            empty = false;
+          } else {
+            // Deletion or equality.  Only take as much as we can stomach.
+            diff_text = diff_text.substring(0, patch_size - patch.length1 - PATCH_MARGIN);
+            patch.length1 += diff_text.length;
+            start1 += diff_text.length;
+            if (diff_type == 0) {
+              patch.length2 += diff_text.length;
+              start2 += diff_text.length;
+            } else {
+              empty = false;
+            }
+            patch.diffs.push([diff_type, diff_text]);
+            if (diff_text == bigpatch.diffs[0][1])
+              bigpatch.diffs.shift();
+            else
+              bigpatch.diffs[0][1] = bigpatch.diffs[0][1].substring(diff_text.length);
+          }
+        }
+        // Compute the head context for the next patch.
+        precontext = patch.text2();
+        precontext = precontext.substring(precontext.length - PATCH_MARGIN);
+        // Append the end context for this patch.
+        postcontext = bigpatch.text1().substring(0, PATCH_MARGIN);
+        if (postcontext  != '') {
+          patch.length1 += postcontext.length;
+          patch.length2 += postcontext.length;
+          if (patch.diffs.length > 0 && patch.diffs[patch.diffs.length-1][0] == 0)
+            patch.diffs[patch.diffs.length-1][1] += postcontext;
+          else
+            patch.diffs.push([0, postcontext]);
+        }
+        if (!empty)
+          patches.splice(x++, 0, patch);
+      }
+    }
+  }
+}
+
+
+function patch_totext(patches) {
+  // Take a list of patches and return a textual representation.
+  var text = '';
+  for (var x=0; x<patches.length; x++)
+    text += patches[x];
+  return text;
+}
+
+
+function patch_fromtext(text) {
+  // Take a textual representation of patches and return a list of patch objects.
+  var patches = [];
+  text = text.split('\n');
+  var patch, m, chars1, chars2, sign, line;
+  while (text.length != 0) {
+    m = text[0].match(/^@@ -(\d+),?(\d*) \+(\d+),?(\d*) @@$/);
+    if (!m)
+      return alert("Invalid patch string:\n"+text[0]);
+    patch = new patch_obj();
+    patches.push(patch);
+    patch.start1 = parseInt(m[1]);
+    if (m[2] == '') {
+      patch.start1--;
+      patch.length1 = 1;
+    } else if (m[2] == '0') {
+      patch.length1 = 0;
+    } else {
+      patch.start1--;
+      patch.length1 = parseInt(m[2]);
+    }
+
+    patch.start2 = parseInt(m[3]);
+    if (m[4] == '') {
+      patch.start2--;
+      patch.length2 = 1;
+    } else if (m[4] == '0') {
+      patch.length2 = 0;
+    } else {
+      patch.start2--;
+      patch.length2 = parseInt(m[4]);
+    }
+    text.shift();
+
+    while (text.length != 0) {
+      sign = text[0].charAt(0);
+      line = decodeURIComponent(text[0].substring(1));
+      if (sign == '-') {
+        // Deletion.
+        patch.diffs.push([-1, line]);
+      } else if (sign == '+') {
+        // Insertion.
+        patch.diffs.push([1, line]);
+      } else if (sign == ' ') {
+        // Minor equality.
+        patch.diffs.push([0, line]);
+      } else if (sign == '@') {
+        // Start of next patch.
+        break;
+      } else if (sign == '') {
+        // Blank line?  Whatever.
+      } else {
+        // WTF?
+        return alert("Invalid patch mode: '"+sign+"'\n"+line);
+      }
+      text.shift();
+    }
+  }
+  return patches;
+}
+
+// EOF
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/devkit/langs/en.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,23 @@
+// UK lang variables
+
+tinyMCE.addToLang('devkit',{
+title : 'TinyMCE Development Kit',
+info_tab : 'Info',
+settings_tab : 'Settings',
+log_tab : 'Log',
+content_tab : 'Content',
+command_states_tab : 'Commands',
+undo_redo_tab : 'Undo/Redo',
+misc_tab : 'Misc',
+filter : 'Filter:',
+clear_log : 'Clear log',
+refresh : 'Refresh',
+info_help : 'Press Refresh to view info.',
+settings_help : 'Press Refresh to display the settings array for each TinyMCE_Control instance.',
+content_help : 'Press Refresh to display the raw and cleaned HTML content for each TinyMCE_Control instance.',
+command_states_help : 'Press Refresh to display the current command states from inst.queryCommandState. This list will also mark unsupported commands.',
+undo_redo_help : 'Press Refresh to display the global and instance undo/redo levels.',
+misc_help : 'Here are various tools for debugging and development purposes.',
+debug_events : 'Debug events',
+undo_diff : 'Diff undo levels'
+});
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/directionality/editor_plugin.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+tinyMCE.importPluginLanguagePack('directionality');var TinyMCE_DirectionalityPlugin={getInfo:function(){return{longname:'Directionality',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/directionality',version:tinyMCE.majorVersion+"."+tinyMCE.minorVersion}},getControlHTML:function(cn){switch(cn){case"ltr":return tinyMCE.getButtonHTML(cn,'lang_directionality_ltr_desc','{$pluginurl}/images/ltr.gif','mceDirectionLTR');case"rtl":return tinyMCE.getButtonHTML(cn,'lang_directionality_rtl_desc','{$pluginurl}/images/rtl.gif','mceDirectionRTL')}return""},execCommand:function(editor_id,element,command,user_interface,value){switch(command){case"mceDirectionLTR":var inst=tinyMCE.getInstanceById(editor_id);var elm=tinyMCE.getParentElement(inst.getFocusElement(),"p,div,td,h1,h2,h3,h4,h5,h6,pre,address");if(elm)elm.setAttribute("dir","ltr");tinyMCE.triggerNodeChange(false);return true;case"mceDirectionRTL":var inst=tinyMCE.getInstanceById(editor_id);var elm=tinyMCE.getParentElement(inst.getFocusElement(),"p,div,td,h1,h2,h3,h4,h5,h6,pre,address");if(elm)elm.setAttribute("dir","rtl");tinyMCE.triggerNodeChange(false);return true}return false},handleNodeChange:function(editor_id,node,undo_index,undo_levels,visual_aid,any_selection){function getAttrib(elm,name){return elm.getAttribute(name)?elm.getAttribute(name):""}if(node==null)return;var elm=tinyMCE.getParentElement(node,"p,div,td,h1,h2,h3,h4,h5,h6,pre,address");if(!elm){tinyMCE.switchClass(editor_id+'_ltr','mceButtonDisabled');tinyMCE.switchClass(editor_id+'_rtl','mceButtonDisabled');return true}tinyMCE.switchClass(editor_id+'_ltr','mceButtonNormal');tinyMCE.switchClass(editor_id+'_rtl','mceButtonNormal');var dir=getAttrib(elm,"dir");if(dir=="ltr"||dir=="")tinyMCE.switchClass(editor_id+'_ltr','mceButtonSelected');else tinyMCE.switchClass(editor_id+'_rtl','mceButtonSelected');return true}};tinyMCE.addPlugin("directionality",TinyMCE_DirectionalityPlugin);
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/directionality/editor_plugin_src.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,90 @@
+/**
+ * $Id: editor_plugin_src.js 201 2007-02-12 15:56:56Z spocke $
+ *
+ * @author Moxiecode
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+/* Import plugin specific language pack */
+tinyMCE.importPluginLanguagePack('directionality');
+
+var TinyMCE_DirectionalityPlugin = {
+	getInfo : function() {
+		return {
+			longname : 'Directionality',
+			author : 'Moxiecode Systems AB',
+			authorurl : 'http://tinymce.moxiecode.com',
+			infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/directionality',
+			version : tinyMCE.majorVersion + "." + tinyMCE.minorVersion
+		};
+	},
+
+	getControlHTML : function(cn) {
+		switch (cn) {
+			case "ltr":
+				return tinyMCE.getButtonHTML(cn, 'lang_directionality_ltr_desc', '{$pluginurl}/images/ltr.gif', 'mceDirectionLTR');
+
+			case "rtl":
+				return tinyMCE.getButtonHTML(cn, 'lang_directionality_rtl_desc', '{$pluginurl}/images/rtl.gif', 'mceDirectionRTL');
+		}
+
+		return "";
+	},
+
+	execCommand : function(editor_id, element, command, user_interface, value) {
+		// Handle commands
+		switch (command) {
+			case "mceDirectionLTR":
+				var inst = tinyMCE.getInstanceById(editor_id);
+				var elm = tinyMCE.getParentElement(inst.getFocusElement(), "p,div,td,h1,h2,h3,h4,h5,h6,pre,address");
+
+				if (elm)
+					elm.setAttribute("dir", "ltr");
+
+				tinyMCE.triggerNodeChange(false);
+				return true;
+
+			case "mceDirectionRTL":
+				var inst = tinyMCE.getInstanceById(editor_id);
+				var elm = tinyMCE.getParentElement(inst.getFocusElement(), "p,div,td,h1,h2,h3,h4,h5,h6,pre,address");
+
+				if (elm)
+					elm.setAttribute("dir", "rtl");
+
+				tinyMCE.triggerNodeChange(false);
+				return true;
+		}
+
+		// Pass to next handler in chain
+		return false;
+	},
+
+	handleNodeChange : function(editor_id, node, undo_index, undo_levels, visual_aid, any_selection) {
+		function getAttrib(elm, name) {
+			return elm.getAttribute(name) ? elm.getAttribute(name) : "";
+		}
+
+		if (node == null)
+			return;
+
+		var elm = tinyMCE.getParentElement(node, "p,div,td,h1,h2,h3,h4,h5,h6,pre,address");
+		if (!elm) {
+			tinyMCE.switchClass(editor_id + '_ltr', 'mceButtonDisabled');
+			tinyMCE.switchClass(editor_id + '_rtl', 'mceButtonDisabled');
+			return true;
+		}
+
+		tinyMCE.switchClass(editor_id + '_ltr', 'mceButtonNormal');
+		tinyMCE.switchClass(editor_id + '_rtl', 'mceButtonNormal');
+
+		var dir = getAttrib(elm, "dir");
+		if (dir == "ltr" || dir == "")
+			tinyMCE.switchClass(editor_id + '_ltr', 'mceButtonSelected');
+		else
+			tinyMCE.switchClass(editor_id + '_rtl', 'mceButtonSelected');
+
+		return true;
+	}
+};
+
+tinyMCE.addPlugin("directionality", TinyMCE_DirectionalityPlugin);
Binary file includes/clientside/tinymce/plugins/directionality/images/ltr.gif has changed
Binary file includes/clientside/tinymce/plugins/directionality/images/rtl.gif has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/directionality/langs/en.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,6 @@
+// UK lang variables
+
+tinyMCE.addToLang('',{
+directionality_ltr_desc : 'Direction left to right',
+directionality_rtl_desc : 'Direction right to left'
+});
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/directionality/readme.txt	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+Check the TinyMCE documentation for details on this plugin.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/emotions/editor_plugin.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+tinyMCE.importPluginLanguagePack('emotions');var TinyMCE_EmotionsPlugin={getInfo:function(){return{longname:'Emotions',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/emotions',version:tinyMCE.majorVersion+"."+tinyMCE.minorVersion}},getControlHTML:function(cn){switch(cn){case"emotions":return tinyMCE.getButtonHTML(cn,'lang_emotions_desc','{$pluginurl}/images/emotions.gif','mceEmotion')}return""},execCommand:function(editor_id,element,command,user_interface,value){switch(command){case"mceEmotion":var template=new Array();template['file']='../../plugins/emotions/emotions.htm';template['width']=250;template['height']=160;template['width']+=tinyMCE.getLang('lang_emotions_delta_width',0);template['height']+=tinyMCE.getLang('lang_emotions_delta_height',0);tinyMCE.openWindow(template,{editor_id:editor_id,inline:"yes"});return true}return false}};tinyMCE.addPlugin('emotions',TinyMCE_EmotionsPlugin);
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/emotions/editor_plugin_src.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,63 @@
+/**
+ * $Id: editor_plugin_src.js 201 2007-02-12 15:56:56Z spocke $
+ *
+ * @author Moxiecode
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+/* Import plugin specific language pack */
+tinyMCE.importPluginLanguagePack('emotions');
+
+// Plucin static class
+var TinyMCE_EmotionsPlugin = {
+	getInfo : function() {
+		return {
+			longname : 'Emotions',
+			author : 'Moxiecode Systems AB',
+			authorurl : 'http://tinymce.moxiecode.com',
+			infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/emotions',
+			version : tinyMCE.majorVersion + "." + tinyMCE.minorVersion
+		};
+	},
+
+	/**
+	 * Returns the HTML contents of the emotions control.
+	 */
+	getControlHTML : function(cn) {
+		switch (cn) {
+			case "emotions":
+				return tinyMCE.getButtonHTML(cn, 'lang_emotions_desc', '{$pluginurl}/images/emotions.gif', 'mceEmotion');
+		}
+
+		return "";
+	},
+
+	/**
+	 * Executes the mceEmotion command.
+	 */
+	execCommand : function(editor_id, element, command, user_interface, value) {
+		// Handle commands
+		switch (command) {
+			case "mceEmotion":
+				var template = new Array();
+
+				template['file'] = '../../plugins/emotions/emotions.htm'; // Relative to theme
+				template['width'] = 250;
+				template['height'] = 160;
+
+				// Language specific width and height addons
+				template['width'] += tinyMCE.getLang('lang_emotions_delta_width', 0);
+				template['height'] += tinyMCE.getLang('lang_emotions_delta_height', 0);
+
+				tinyMCE.openWindow(template, {editor_id : editor_id, inline : "yes"});
+
+				return true;
+		}
+
+		// Pass to next handler in chain
+		return false;
+	}
+};
+
+// Register plugin
+tinyMCE.addPlugin('emotions', TinyMCE_EmotionsPlugin);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/emotions/emotions.htm	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,40 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>{$lang_emotions_title}</title>
+	<script language="javascript" type="text/javascript" src="../../tiny_mce_popup.js"></script>
+	<script language="javascript" type="text/javascript" src="jscripts/functions.js"></script>
+	<base target="_self" />
+</head>
+<body onload="tinyMCEPopup.executeOnLoad('init();');" style="display: none">
+	<div align="center">
+		<div class="title">{$lang_emotions_title}:<br /><br /></div>
+
+		<table border="0" cellspacing="0" cellpadding="4">
+		  <tr>
+			<td><a href="javascript:insertEmotion('smiley-cool.gif','lang_emotions_cool');"><img src="images/smiley-cool.gif" width="18" height="18" border="0" alt="{$lang_emotions_cool}" title="{$lang_emotions_cool}" /></a></td>
+			<td><a href="javascript:insertEmotion('smiley-cry.gif','lang_emotions_cry');"><img src="images/smiley-cry.gif" width="18" height="18" border="0" alt="{$lang_emotions_cry}" title="{$lang_emotions_cry}" /></a></td>
+			<td><a href="javascript:insertEmotion('smiley-embarassed.gif','lang_emotions_embarassed');"><img src="images/smiley-embarassed.gif" width="18" height="18" border="0" alt="{$lang_emotions_embarassed}" title="{$lang_emotions_embarassed}" /></a></td>
+			<td><a href="javascript:insertEmotion('smiley-foot-in-mouth.gif','lang_emotions_foot_in_mouth');"><img src="images/smiley-foot-in-mouth.gif" width="18" height="18" border="0" alt="{$lang_emotions_foot_in_mouth}" title="{$lang_emotions_foot_in_mouth}" /></a></td>
+		  </tr>
+		  <tr>
+			<td><a href="javascript:insertEmotion('smiley-frown.gif','lang_emotions_frown');"><img src="images/smiley-frown.gif" width="18" height="18" border="0" alt="{$lang_emotions_frown}" title="{$lang_emotions_frown}" /></a></td>
+			<td><a href="javascript:insertEmotion('smiley-innocent.gif','lang_emotions_innocent');"><img src="images/smiley-innocent.gif" width="18" height="18" border="0" alt="{$lang_emotions_innocent}" title="{$lang_emotions_innocent}" /></a></td>
+			<td><a href="javascript:insertEmotion('smiley-kiss.gif','lang_emotions_kiss');"><img src="images/smiley-kiss.gif" width="18" height="18" border="0" alt="{$lang_emotions_kiss}" title="{$lang_emotions_kiss}" /></a></td>
+			<td><a href="javascript:insertEmotion('smiley-laughing.gif','lang_emotions_laughing');"><img src="images/smiley-laughing.gif" width="18" height="18" border="0" alt="{$lang_emotions_laughing}" title="{$lang_emotions_laughing}" /></a></td>
+		  </tr>
+		  <tr>
+			<td><a href="javascript:insertEmotion('smiley-money-mouth.gif','lang_emotions_money_mouth');"><img src="images/smiley-money-mouth.gif" width="18" height="18" border="0" alt="{$lang_emotions_money_mouth}" title="{$lang_emotions_money_mouth}" /></a></td>
+			<td><a href="javascript:insertEmotion('smiley-sealed.gif','lang_emotions_sealed');"><img src="images/smiley-sealed.gif" width="18" height="18" border="0" alt="{$lang_emotions_sealed}" title="{$lang_emotions_sealed}" /></a></td>
+			<td><a href="javascript:insertEmotion('smiley-smile.gif','lang_emotions_smile');"><img src="images/smiley-smile.gif" width="18" height="18" border="0" alt="{$lang_emotions_smile}" title="{$lang_emotions_smile}" /></a></td>
+			<td><a href="javascript:insertEmotion('smiley-surprised.gif','lang_emotions_surprised');"><img src="images/smiley-surprised.gif" width="18" height="18" border="0" alt="{$lang_emotions_surprised}" title="{$lang_emotions_surprised}" /></a></td>
+		  </tr>
+		  <tr>
+			<td><a href="javascript:insertEmotion('smiley-tongue-out.gif','lang_emotions_tongue_out');"><img src="images/smiley-tongue-out.gif" width="18" height="18" border="0" alt="{$lang_emotions_tongue-out}" title="{$lang_emotions_tongue_out}" /></a></td>
+			<td><a href="javascript:insertEmotion('smiley-undecided.gif','lang_emotions_undecided');"><img src="images/smiley-undecided.gif" width="18" height="18" border="0" alt="{$lang_emotions_undecided}" title="{$lang_emotions_undecided}" /></a></td>
+			<td><a href="javascript:insertEmotion('smiley-wink.gif','lang_emotions_wink');"><img src="images/smiley-wink.gif" width="18" height="18" border="0" alt="{$lang_emotions_wink}" title="{$lang_emotions_wink}" /></a></td>
+			<td><a href="javascript:insertEmotion('smiley-yell.gif','lang_emotions_yell');"><img src="images/smiley-yell.gif" width="18" height="18" border="0" alt="{$lang_emotions_yell}" title="{$lang_emotions_yell}" /></a></td>
+		  </tr>
+		</table>
+	</div>
+</body>
+</html>
Binary file includes/clientside/tinymce/plugins/emotions/images/emotions.gif has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/emotions/images/readme.txt	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,2 @@
+These emotions where taken from Mozilla Thunderbird.
+I hope they don't get angry if I use them here after all this is a open source project aswell.
Binary file includes/clientside/tinymce/plugins/emotions/images/smiley-cool.gif has changed
Binary file includes/clientside/tinymce/plugins/emotions/images/smiley-cry.gif has changed
Binary file includes/clientside/tinymce/plugins/emotions/images/smiley-embarassed.gif has changed
Binary file includes/clientside/tinymce/plugins/emotions/images/smiley-foot-in-mouth.gif has changed
Binary file includes/clientside/tinymce/plugins/emotions/images/smiley-frown.gif has changed
Binary file includes/clientside/tinymce/plugins/emotions/images/smiley-innocent.gif has changed
Binary file includes/clientside/tinymce/plugins/emotions/images/smiley-kiss.gif has changed
Binary file includes/clientside/tinymce/plugins/emotions/images/smiley-laughing.gif has changed
Binary file includes/clientside/tinymce/plugins/emotions/images/smiley-money-mouth.gif has changed
Binary file includes/clientside/tinymce/plugins/emotions/images/smiley-sealed.gif has changed
Binary file includes/clientside/tinymce/plugins/emotions/images/smiley-smile.gif has changed
Binary file includes/clientside/tinymce/plugins/emotions/images/smiley-surprised.gif has changed
Binary file includes/clientside/tinymce/plugins/emotions/images/smiley-tongue-out.gif has changed
Binary file includes/clientside/tinymce/plugins/emotions/images/smiley-undecided.gif has changed
Binary file includes/clientside/tinymce/plugins/emotions/images/smiley-wink.gif has changed
Binary file includes/clientside/tinymce/plugins/emotions/images/smiley-yell.gif has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/emotions/jscripts/functions.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,21 @@
+function init() {
+	tinyMCEPopup.resizeToInnerSize();
+}
+
+function insertEmotion(file_name, title) {
+	title = tinyMCE.getLang(title);
+
+	if (title == null)
+		title = "";
+
+	// XML encode
+	title = title.replace(/&/g, '&amp;');
+	title = title.replace(/\"/g, '&quot;');
+	title = title.replace(/</g, '&lt;');
+	title = title.replace(/>/g, '&gt;');
+
+	var html = '<img src="' + tinyMCE.baseURL + "/plugins/emotions/images/" + file_name + '" mce_src="' + tinyMCE.baseURL + "/plugins/emotions/images/" + file_name + '" border="0" alt="' + title + '" title="' + title + '" />';
+
+	tinyMCE.execCommand('mceInsertContent', false, html);
+	tinyMCEPopup.close();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/emotions/langs/en.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,22 @@
+// UK lang variables
+
+tinyMCE.addToLang('emotions',{
+title : 'Insert emotion',
+desc : 'Emotions',
+cool : 'Cool',
+cry : 'Cry',
+embarassed : 'Embarassed',
+foot_in_mouth : 'Foot in mouth',
+frown : 'Frown',
+innocent : 'Innocent',
+kiss : 'Kiss',
+laughing : 'Laughing',
+money_mouth : 'Money mouth',
+sealed : 'Sealed',
+smile : 'Smile',
+surprised : 'Surprised',
+tongue_out : 'Tongue out',
+undecided : 'Undecided',
+wink : 'Wink',
+yell : 'Yell'
+});
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/emotions/readme.txt	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+Check the TinyMCE documentation for details on this plugin.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/flash/css/content.css	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,7 @@
+.mceItemFlash {
+	border: 1px dotted #cc0000;
+	background-image: url('../images/flash.gif');
+	background-position: center;
+	background-repeat: no-repeat;
+	background-color: #ffffcc;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/flash/css/flash.css	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,11 @@
+.panel_wrapper div.current {
+	height: 100px;
+}
+
+#width, #height {
+	width: 50px;
+}
+
+#file {
+	width: 250px;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/flash/editor_plugin.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+tinyMCE.importPluginLanguagePack('flash');var TinyMCE_FlashPlugin={getInfo:function(){return{longname:'Flash',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/flash',version:tinyMCE.majorVersion+"."+tinyMCE.minorVersion}},initInstance:function(inst){if(!tinyMCE.settings['flash_skip_plugin_css'])tinyMCE.importCSS(inst.getDoc(),tinyMCE.baseURL+"/plugins/flash/css/content.css")},getControlHTML:function(cn){switch(cn){case"flash":return tinyMCE.getButtonHTML(cn,'lang_flash_desc','{$pluginurl}/images/flash.gif','mceFlash')}return""},execCommand:function(editor_id,element,command,user_interface,value){switch(command){case"mceFlash":var name="",swffile="",swfwidth="",swfheight="",action="insert";var template=new Array();var inst=tinyMCE.getInstanceById(editor_id);var focusElm=inst.getFocusElement();template['file']='../../plugins/flash/flash.htm';template['width']=430;template['height']=175;template['width']+=tinyMCE.getLang('lang_flash_delta_width',0);template['height']+=tinyMCE.getLang('lang_flash_delta_height',0);if(focusElm!=null&&focusElm.nodeName.toLowerCase()=="img"){name=tinyMCE.getAttrib(focusElm,'class');if(name.indexOf('mceItemFlash')==-1)return true;swffile=tinyMCE.getAttrib(focusElm,'alt');if(tinyMCE.getParam('convert_urls'))swffile=eval(tinyMCE.settings['urlconverter_callback']+"(swffile, null, true);");swfwidth=tinyMCE.getAttrib(focusElm,'width');swfheight=tinyMCE.getAttrib(focusElm,'height');action="update"}tinyMCE.openWindow(template,{editor_id:editor_id,inline:"yes",swffile:swffile,swfwidth:swfwidth,swfheight:swfheight,action:action});return true}return false},cleanup:function(type,content){switch(type){case"insert_to_editor_dom":if(tinyMCE.getParam('convert_urls')){var imgs=content.getElementsByTagName("img");for(var i=0;i<imgs.length;i++){if(tinyMCE.getAttrib(imgs[i],"class")=="mceItemFlash"){var src=tinyMCE.getAttrib(imgs[i],"alt");if(tinyMCE.getParam('convert_urls'))src=eval(tinyMCE.settings['urlconverter_callback']+"(src, null, true);");imgs[i].setAttribute('alt',src);imgs[i].setAttribute('title',src)}}}break;case"get_from_editor_dom":var imgs=content.getElementsByTagName("img");for(var i=0;i<imgs.length;i++){if(tinyMCE.getAttrib(imgs[i],"class")=="mceItemFlash"){var src=tinyMCE.getAttrib(imgs[i],"alt");if(tinyMCE.getParam('convert_urls'))src=eval(tinyMCE.settings['urlconverter_callback']+"(src, null, true);");imgs[i].setAttribute('alt',src);imgs[i].setAttribute('title',src)}}break;case"insert_to_editor":var startPos=0;var embedList=new Array();content=content.replace(new RegExp('<[ ]*embed','gi'),'<embed');content=content.replace(new RegExp('<[ ]*/embed[ ]*>','gi'),'</embed>');content=content.replace(new RegExp('<[ ]*object','gi'),'<object');content=content.replace(new RegExp('<[ ]*/object[ ]*>','gi'),'</object>');while((startPos=content.indexOf('<embed',startPos+1))!=-1){var endPos=content.indexOf('>',startPos);var attribs=TinyMCE_FlashPlugin._parseAttributes(content.substring(startPos+6,endPos));embedList[embedList.length]=attribs}var index=0;while((startPos=content.indexOf('<object',startPos))!=-1){if(index>=embedList.length)break;var attribs=embedList[index];endPos=content.indexOf('</object>',startPos);endPos+=9;var contentAfter=content.substring(endPos);content=content.substring(0,startPos);content+='<img width="'+attribs["width"]+'" height="'+attribs["height"]+'"';content+=' src="'+(tinyMCE.getParam("theme_href")+'/images/spacer.gif')+'" title="'+attribs["src"]+'"';content+=' alt="'+attribs["src"]+'" class="mceItemFlash" />'+content.substring(endPos);content+=contentAfter;index++;startPos++}var index=0;while((startPos=content.indexOf('<embed',startPos))!=-1){if(index>=embedList.length)break;var attribs=embedList[index];endPos=content.indexOf('>',startPos);endPos+=9;var contentAfter=content.substring(endPos);content=content.substring(0,startPos);content+='<img width="'+attribs["width"]+'" height="'+attribs["height"]+'"';content+=' src="'+(tinyMCE.getParam("theme_href")+'/images/spacer.gif')+'" title="'+attribs["src"]+'"';content+=' alt="'+attribs["src"]+'" class="mceItemFlash" />'+content.substring(endPos);content+=contentAfter;index++;startPos++}break;case"get_from_editor":var startPos=-1;while((startPos=content.indexOf('<img',startPos+1))!=-1){var endPos=content.indexOf('/>',startPos);var attribs=TinyMCE_FlashPlugin._parseAttributes(content.substring(startPos+4,endPos));if(attribs['class']!="mceItemFlash")continue;endPos+=2;var embedHTML='';var wmode=tinyMCE.getParam("flash_wmode","");var quality=tinyMCE.getParam("flash_quality","high");var menu=tinyMCE.getParam("flash_menu","false");embedHTML+='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"';embedHTML+=' codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,29,0"';embedHTML+=' width="'+attribs["width"]+'" height="'+attribs["height"]+'">';embedHTML+='<param name="movie" value="'+attribs["title"]+'" />';embedHTML+='<param name="quality" value="'+quality+'" />';embedHTML+='<param name="menu" value="'+menu+'" />';embedHTML+='<param name="wmode" value="'+wmode+'" />';embedHTML+='<embed src="'+attribs["title"]+'" wmode="'+wmode+'" quality="'+quality+'" menu="'+menu+'" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" width="'+attribs["width"]+'" height="'+attribs["height"]+'"></embed></object>';chunkBefore=content.substring(0,startPos);chunkAfter=content.substring(endPos);content=chunkBefore+embedHTML+chunkAfter}break}return content},handleNodeChange:function(editor_id,node,undo_index,undo_levels,visual_aid,any_selection){if(node==null)return;do{if(node.nodeName=="IMG"&&tinyMCE.getAttrib(node,'class').indexOf('mceItemFlash')==0){tinyMCE.switchClass(editor_id+'_flash','mceButtonSelected');return true}}while((node=node.parentNode));tinyMCE.switchClass(editor_id+'_flash','mceButtonNormal');return true},_parseAttributes:function(attribute_string){var attributeName="";var attributeValue="";var withInName;var withInValue;var attributes=new Array();var whiteSpaceRegExp=new RegExp('^[ \n\r\t]+','g');if(attribute_string==null||attribute_string.length<2)return null;withInName=withInValue=false;for(var i=0;i<attribute_string.length;i++){var chr=attribute_string.charAt(i);if((chr=='"'||chr=="'")&&!withInValue)withInValue=true;else if((chr=='"'||chr=="'")&&withInValue){withInValue=false;var pos=attributeName.lastIndexOf(' ');if(pos!=-1)attributeName=attributeName.substring(pos+1);attributes[attributeName.toLowerCase()]=attributeValue.substring(1);attributeName="";attributeValue=""}else if(!whiteSpaceRegExp.test(chr)&&!withInName&&!withInValue)withInName=true;if(chr=='='&&withInName)withInName=false;if(withInName)attributeName+=chr;if(withInValue)attributeValue+=chr}return attributes}};tinyMCE.addPlugin("flash",TinyMCE_FlashPlugin);
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/flash/editor_plugin_src.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,285 @@
+/**
+ * $Id: editor_plugin_src.js 201 2007-02-12 15:56:56Z spocke $
+ *
+ * @author Moxiecode
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+/* Import plugin specific language pack */
+tinyMCE.importPluginLanguagePack('flash');
+
+var TinyMCE_FlashPlugin = {
+	getInfo : function() {
+		return {
+			longname : 'Flash',
+			author : 'Moxiecode Systems AB',
+			authorurl : 'http://tinymce.moxiecode.com',
+			infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/flash',
+			version : tinyMCE.majorVersion + "." + tinyMCE.minorVersion
+		};
+	},
+
+	initInstance : function(inst) {
+		if (!tinyMCE.settings['flash_skip_plugin_css'])
+			tinyMCE.importCSS(inst.getDoc(), tinyMCE.baseURL + "/plugins/flash/css/content.css");
+	},
+
+	getControlHTML : function(cn) {
+		switch (cn) {
+			case "flash":
+				return tinyMCE.getButtonHTML(cn, 'lang_flash_desc', '{$pluginurl}/images/flash.gif', 'mceFlash');
+		}
+
+		return "";
+	},
+
+	execCommand : function(editor_id, element, command, user_interface, value) {
+		// Handle commands
+		switch (command) {
+			case "mceFlash":
+				var name = "", swffile = "", swfwidth = "", swfheight = "", action = "insert";
+				var template = new Array();
+				var inst = tinyMCE.getInstanceById(editor_id);
+				var focusElm = inst.getFocusElement();
+
+				template['file']   = '../../plugins/flash/flash.htm'; // Relative to theme
+				template['width']  = 430;
+				template['height'] = 175;
+
+				template['width'] += tinyMCE.getLang('lang_flash_delta_width', 0);
+				template['height'] += tinyMCE.getLang('lang_flash_delta_height', 0);
+
+				// Is selection a image
+				if (focusElm != null && focusElm.nodeName.toLowerCase() == "img") {
+					name = tinyMCE.getAttrib(focusElm, 'class');
+
+					if (name.indexOf('mceItemFlash') == -1) // Not a Flash
+						return true;
+
+					// Get rest of Flash items
+					swffile = tinyMCE.getAttrib(focusElm, 'alt');
+
+					if (tinyMCE.getParam('convert_urls'))
+						swffile = eval(tinyMCE.settings['urlconverter_callback'] + "(swffile, null, true);");
+
+					swfwidth = tinyMCE.getAttrib(focusElm, 'width');
+					swfheight = tinyMCE.getAttrib(focusElm, 'height');
+					action = "update";
+				}
+
+				tinyMCE.openWindow(template, {editor_id : editor_id, inline : "yes", swffile : swffile, swfwidth : swfwidth, swfheight : swfheight, action : action});
+			return true;
+	   }
+
+	   // Pass to next handler in chain
+	   return false;
+	},
+
+	cleanup : function(type, content) {
+		switch (type) {
+			case "insert_to_editor_dom":
+				// Force relative/absolute
+				if (tinyMCE.getParam('convert_urls')) {
+					var imgs = content.getElementsByTagName("img");
+					for (var i=0; i<imgs.length; i++) {
+						if (tinyMCE.getAttrib(imgs[i], "class") == "mceItemFlash") {
+							var src = tinyMCE.getAttrib(imgs[i], "alt");
+
+							if (tinyMCE.getParam('convert_urls'))
+								src = eval(tinyMCE.settings['urlconverter_callback'] + "(src, null, true);");
+
+							imgs[i].setAttribute('alt', src);
+							imgs[i].setAttribute('title', src);
+						}
+					}
+				}
+				break;
+
+			case "get_from_editor_dom":
+				var imgs = content.getElementsByTagName("img");
+				for (var i=0; i<imgs.length; i++) {
+					if (tinyMCE.getAttrib(imgs[i], "class") == "mceItemFlash") {
+						var src = tinyMCE.getAttrib(imgs[i], "alt");
+
+						if (tinyMCE.getParam('convert_urls'))
+							src = eval(tinyMCE.settings['urlconverter_callback'] + "(src, null, true);");
+
+						imgs[i].setAttribute('alt', src);
+						imgs[i].setAttribute('title', src);
+					}
+				}
+				break;
+
+			case "insert_to_editor":
+				var startPos = 0;
+				var embedList = new Array();
+
+				// Fix the embed and object elements
+				content = content.replace(new RegExp('<[ ]*embed','gi'),'<embed');
+				content = content.replace(new RegExp('<[ ]*/embed[ ]*>','gi'),'</embed>');
+				content = content.replace(new RegExp('<[ ]*object','gi'),'<object');
+				content = content.replace(new RegExp('<[ ]*/object[ ]*>','gi'),'</object>');
+
+				// Parse all embed tags
+				while ((startPos = content.indexOf('<embed', startPos+1)) != -1) {
+					var endPos = content.indexOf('>', startPos);
+					var attribs = TinyMCE_FlashPlugin._parseAttributes(content.substring(startPos + 6, endPos));
+					embedList[embedList.length] = attribs;
+				}
+
+				// Parse all object tags and replace them with images from the embed data
+				var index = 0;
+				while ((startPos = content.indexOf('<object', startPos)) != -1) {
+					if (index >= embedList.length)
+						break;
+
+					var attribs = embedList[index];
+
+					// Find end of object
+					endPos = content.indexOf('</object>', startPos);
+					endPos += 9;
+
+					// Insert image
+					var contentAfter = content.substring(endPos);
+					content = content.substring(0, startPos);
+					content += '<img width="' + attribs["width"] + '" height="' + attribs["height"] + '"';
+					content += ' src="' + (tinyMCE.getParam("theme_href") + '/images/spacer.gif') + '" title="' + attribs["src"] + '"';
+					content += ' alt="' + attribs["src"] + '" class="mceItemFlash" />' + content.substring(endPos);
+					content += contentAfter;
+					index++;
+
+					startPos++;
+				}
+
+				// Parse all embed tags and replace them with images from the embed data
+				var index = 0;
+				while ((startPos = content.indexOf('<embed', startPos)) != -1) {
+					if (index >= embedList.length)
+						break;
+
+					var attribs = embedList[index];
+
+					// Find end of embed
+					endPos = content.indexOf('>', startPos);
+					endPos += 9;
+
+					// Insert image
+					var contentAfter = content.substring(endPos);
+					content = content.substring(0, startPos);
+					content += '<img width="' + attribs["width"] + '" height="' + attribs["height"] + '"';
+					content += ' src="' + (tinyMCE.getParam("theme_href") + '/images/spacer.gif') + '" title="' + attribs["src"] + '"';
+					content += ' alt="' + attribs["src"] + '" class="mceItemFlash" />' + content.substring(endPos);
+					content += contentAfter;
+					index++;
+
+					startPos++;
+				}
+
+				break;
+
+			case "get_from_editor":
+				// Parse all img tags and replace them with object+embed
+				var startPos = -1;
+
+				while ((startPos = content.indexOf('<img', startPos+1)) != -1) {
+					var endPos = content.indexOf('/>', startPos);
+					var attribs = TinyMCE_FlashPlugin._parseAttributes(content.substring(startPos + 4, endPos));
+
+					// Is not flash, skip it
+					if (attribs['class'] != "mceItemFlash")
+						continue;
+
+					endPos += 2;
+
+					var embedHTML = '';
+					var wmode = tinyMCE.getParam("flash_wmode", "");
+					var quality = tinyMCE.getParam("flash_quality", "high");
+					var menu = tinyMCE.getParam("flash_menu", "false");
+
+					// Insert object + embed
+					embedHTML += '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"';
+					embedHTML += ' codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,29,0"';
+					embedHTML += ' width="' + attribs["width"] + '" height="' + attribs["height"] + '">';
+					embedHTML += '<param name="movie" value="' + attribs["title"] + '" />';
+					embedHTML += '<param name="quality" value="' + quality + '" />';
+					embedHTML += '<param name="menu" value="' + menu + '" />';
+					embedHTML += '<param name="wmode" value="' + wmode + '" />';
+					embedHTML += '<embed src="' + attribs["title"] + '" wmode="' + wmode + '" quality="' + quality + '" menu="' + menu + '" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" width="' + attribs["width"] + '" height="' + attribs["height"] + '"></embed></object>';
+
+					// Insert embed/object chunk
+					chunkBefore = content.substring(0, startPos);
+					chunkAfter = content.substring(endPos);
+					content = chunkBefore + embedHTML + chunkAfter;
+				}
+				break;
+		}
+
+		// Pass through to next handler in chain
+		return content;
+	},
+
+	handleNodeChange : function(editor_id, node, undo_index, undo_levels, visual_aid, any_selection) {
+		if (node == null)
+			return;
+
+		do {
+			if (node.nodeName == "IMG" && tinyMCE.getAttrib(node, 'class').indexOf('mceItemFlash') == 0) {
+				tinyMCE.switchClass(editor_id + '_flash', 'mceButtonSelected');
+				return true;
+			}
+		} while ((node = node.parentNode));
+
+		tinyMCE.switchClass(editor_id + '_flash', 'mceButtonNormal');
+
+		return true;
+	},
+
+	// Private plugin internal functions
+
+	_parseAttributes : function(attribute_string) {
+		var attributeName = "";
+		var attributeValue = "";
+		var withInName;
+		var withInValue;
+		var attributes = new Array();
+		var whiteSpaceRegExp = new RegExp('^[ \n\r\t]+', 'g');
+
+		if (attribute_string == null || attribute_string.length < 2)
+			return null;
+
+		withInName = withInValue = false;
+
+		for (var i=0; i<attribute_string.length; i++) {
+			var chr = attribute_string.charAt(i);
+
+			if ((chr == '"' || chr == "'") && !withInValue)
+				withInValue = true;
+			else if ((chr == '"' || chr == "'") && withInValue) {
+				withInValue = false;
+
+				var pos = attributeName.lastIndexOf(' ');
+				if (pos != -1)
+					attributeName = attributeName.substring(pos+1);
+
+				attributes[attributeName.toLowerCase()] = attributeValue.substring(1);
+
+				attributeName = "";
+				attributeValue = "";
+			} else if (!whiteSpaceRegExp.test(chr) && !withInName && !withInValue)
+				withInName = true;
+
+			if (chr == '=' && withInName)
+				withInName = false;
+
+			if (withInName)
+				attributeName += chr;
+
+			if (withInValue)
+				attributeValue += chr;
+		}
+
+		return attributes;
+	}
+};
+
+tinyMCE.addPlugin("flash", TinyMCE_FlashPlugin);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/flash/flash.htm	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,70 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>{$lang_flash_title}</title>
+	<script language="javascript" type="text/javascript" src="../../tiny_mce_popup.js"></script>
+	<script language="javascript" type="text/javascript" src="jscripts/flash.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/mctabs.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/form_utils.js"></script>
+	<link href="css/flash.css" rel="stylesheet" type="text/css" />
+	<base target="_self" />
+</head>
+<body onload="tinyMCEPopup.executeOnLoad('init();');" style="display: none">
+    <form onsubmit="insertFlash();return false;" action="#">
+		<div class="tabs">
+			<ul>
+				<li id="general_tab" class="current"><span><a href="javascript:mcTabs.displayTab('general_tab','general_panel');" onmousedown="return false;">{$lang_flash_general}</a></span></li>
+			</ul>
+		</div>
+
+		<div class="panel_wrapper">
+			<div id="general_panel" class="panel current">
+				<fieldset>
+					<legend>{$lang_flash_general}</legend>
+
+					<table border="0" cellpadding="4" cellspacing="0">
+							<tr>
+							<td nowrap="nowrap"><label for="file">{$lang_flash_file}</label></td>
+							  <td nowrap="nowrap">
+									<table border="0" cellspacing="0" cellpadding="0">
+									  <tr>
+										<td><input id="file" name="file" type="text" value="" onfocus="this.select();" /></td>
+										<td id="filebrowsercontainer">&nbsp;</td>
+									  </tr>
+									</table>
+								</td>
+							</tr>
+							<tr id="linklistrow">
+								<td><label for="linklist">{$lang_flash_list}</label></td>
+								<td id="linklistcontainer">&nbsp;</td>
+							</tr>
+							<tr>
+								<td nowrap="nowrap"><label>{$lang_flash_size}</label></td>
+								<td nowrap="nowrap">
+									<input type="text" id="width" name="width" value="" onfocus="this.select();" />
+									<select name="width2" id="width2" style="width: 50px">
+										<option value="">px</option>
+										<option value="%">%</option>
+									</select>&nbsp;x&nbsp;<input id="height" name="height" type="text"  value="" onfocus="this.select();" />
+									<select name="height2" id="height2" style="width: 50px">
+										<option value="">px</option>
+										<option value="%">%</option>
+									</select>
+								</td>
+							</tr>
+					</table>
+				</fieldset>
+			</div>
+		</div>
+
+		<div class="mceActionPanel">
+			<div style="float: left">
+				<input type="button" id="insert" name="insert" value="{$lang_insert}" onclick="insertFlash();" />
+			</div>
+
+			<div style="float: right">
+				<input type="button" id="cancel" name="cancel" value="{$lang_cancel}" onclick="tinyMCEPopup.close();" />
+			</div>
+		</div>
+	</form>
+</body>
+</html>
Binary file includes/clientside/tinymce/plugins/flash/images/flash.gif has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/flash/jscripts/flash.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,107 @@
+var url = tinyMCE.getParam("flash_external_list_url");
+if (url != null) {
+	// Fix relative
+	if (url.charAt(0) != '/' && url.indexOf('://') == -1)
+		url = tinyMCE.documentBasePath + "/" + url;
+
+	document.write('<sc'+'ript language="javascript" type="text/javascript" src="' + url + '"></sc'+'ript>');
+}
+
+function init() {
+	tinyMCEPopup.resizeToInnerSize();
+
+	document.getElementById("filebrowsercontainer").innerHTML = getBrowserHTML('filebrowser','file','flash','flash');
+
+	// Image list outsrc
+	var html = getFlashListHTML('filebrowser','file','flash','flash');
+	if (html == "")
+		document.getElementById("linklistrow").style.display = 'none';
+	else
+		document.getElementById("linklistcontainer").innerHTML = html;
+
+	var formObj = document.forms[0];
+	var swffile   = tinyMCE.getWindowArg('swffile');
+	var swfwidth  = '' + tinyMCE.getWindowArg('swfwidth');
+	var swfheight = '' + tinyMCE.getWindowArg('swfheight');
+
+	if (swfwidth.indexOf('%')!=-1) {
+		formObj.width2.value = "%";
+		formObj.width.value  = swfwidth.substring(0,swfwidth.length-1);
+	} else {
+		formObj.width2.value = "px";
+		formObj.width.value  = swfwidth;
+	}
+
+	if (swfheight.indexOf('%')!=-1) {
+		formObj.height2.value = "%";
+		formObj.height.value  = swfheight.substring(0,swfheight.length-1);
+	} else {
+		formObj.height2.value = "px";
+		formObj.height.value  = swfheight;
+	}
+
+	formObj.file.value = swffile;
+	formObj.insert.value = tinyMCE.getLang('lang_' + tinyMCE.getWindowArg('action'), 'Insert', true);
+
+	selectByValue(formObj, 'linklist', swffile);
+
+	// Handle file browser
+	if (isVisible('filebrowser'))
+		document.getElementById('file').style.width = '230px';
+
+	// Auto select flash in list
+	if (typeof(tinyMCEFlashList) != "undefined" && tinyMCEFlashList.length > 0) {
+		for (var i=0; i<formObj.linklist.length; i++) {
+			if (formObj.linklist.options[i].value == tinyMCE.getWindowArg('swffile'))
+				formObj.linklist.options[i].selected = true;
+		}
+	}
+}
+
+function getFlashListHTML() {
+	if (typeof(tinyMCEFlashList) != "undefined" && tinyMCEFlashList.length > 0) {
+		var html = "";
+
+		html += '<select id="linklist" name="linklist" style="width: 250px" onfocus="tinyMCE.addSelectAccessibility(event, this, window);" onchange="this.form.file.value=this.options[this.selectedIndex].value;">';
+		html += '<option value="">---</option>';
+
+		for (var i=0; i<tinyMCEFlashList.length; i++)
+			html += '<option value="' + tinyMCEFlashList[i][1] + '">' + tinyMCEFlashList[i][0] + '</option>';
+
+		html += '</select>';
+
+		return html;
+	}
+
+	return "";
+}
+
+function insertFlash() {
+	var formObj = document.forms[0];
+	var html      = '';
+	var file      = formObj.file.value;
+	var width     = formObj.width.value;
+	var height    = formObj.height.value;
+	if (formObj.width2.value=='%') {
+		width = width + '%';
+	}
+	if (formObj.height2.value=='%') {
+		height = height + '%';
+	}
+
+	if (width == "")
+		width = 100;
+
+	if (height == "")
+		height = 100;
+
+	html += ''
+		+ '<img src="' + (tinyMCE.getParam("theme_href") + "/images/spacer.gif") + '" mce_src="' + (tinyMCE.getParam("theme_href") + "/images/spacer.gif") + '" '
+		+ 'width="' + width + '" height="' + height + '" '
+		+ 'border="0" alt="' + file + '" title="' + file + '" class="mceItemFlash" />';
+
+	tinyMCEPopup.execCommand("mceInsertContent", true, html);
+	tinyMCE.selectedInstance.repaint();
+
+	tinyMCEPopup.close();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/flash/langs/en.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,11 @@
+// UK lang variables
+
+tinyMCE.addToLang('flash',{
+title : 'Insert / edit Flash Movie',
+desc : 'Insert / edit Flash Movie',
+file : 'Flash-File (.swf)',
+size : 'Size',
+list : 'Flash files',
+props : 'Flash properties',
+general : 'General'
+});
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/flash/readme.txt	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+Check the TinyMCE documentation for details on this plugin.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/fullpage/blank.htm	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,9 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>blank_page</title>
+	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+</head>
+<body onload="parent.setupIframe(document);">
+
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/fullpage/css/fullpage.css	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,172 @@
+/* Hide the advanced tab */
+#advanced_tab {
+	display: none;
+}
+
+#metatitle, #metakeywords, #metadescription, #metaauthor, #metacopyright {
+	width: 280px;
+}
+
+#doctype, #docencoding {
+	width: 200px;
+}
+
+#langcode {
+	width: 30px;
+}
+
+#bgimage {
+	width: 220px;	
+}
+
+#fontface {
+	width: 240px;
+}
+
+#leftmargin, #rightmargin, #topmargin, #bottommargin {
+	width: 50px;
+}
+
+.panel_wrapper div.current {
+	height: 400px;
+}
+
+#stylesheet, #style {
+	width: 240px;
+}
+
+/* Head list classes */
+
+.headlistwrapper {
+	width: 100%;
+}
+
+.addbutton, .removebutton, .moveupbutton, .movedownbutton {
+	border-top: 1px solid;
+	border-left: 1px solid;
+	border-bottom: 1px solid;
+	border-right: 1px solid;
+	border-color: #F0F0EE;
+	cursor: default;
+	display: block;
+	width: 20px;
+	height: 20px;
+}
+
+.addbutton:hover, .removebutton:hover, .moveupbutton:hover, .movedownbutton:hover {
+	border: 1px solid #0A246A;
+	background-color: #B6BDD2;
+}
+
+.addbutton {
+	background-image: url('../images/add.gif');
+	float: left;
+	margin-right: 3px;
+}
+
+.removebutton {
+	background-image: url('../images/remove.gif');
+	float: left;
+}
+
+.moveupbutton {
+	background-image: url('../images/move_up.gif');
+	float: left;
+	margin-right: 3px;
+}
+
+.movedownbutton {
+	background-image: url('../images/move_down.gif');
+	float: left;
+}
+
+.selected {
+	border: 1px solid #0A246A;
+	background-color: #B6BDD2;
+}
+
+.toolbar {
+	width: 100%;
+}
+
+#headlist {
+	width: 100%;
+	margin-top: 3px;
+	font-size: 11px;
+}
+
+#info, #title_element, #meta_element, #script_element, #style_element, #base_element, #link_element, #comment_element, #unknown_element {
+	display: none;
+}
+
+#addmenu {
+	position: absolute;
+	border: 1px solid gray;
+	display: none;
+	z-index: 100;
+	background-color: white;
+}
+
+#addmenu a {
+	display: block;
+	width: 100%;
+	line-height: 20px;
+	text-decoration: none;
+	background-color: white;
+}
+
+#addmenu a:hover {
+	background-color: #B6BDD2;
+	color: black;
+}
+
+#addmenu span {
+	padding-left: 10px;
+	padding-right: 10px;
+}
+
+#updateElementPanel {
+	display: none;
+}
+
+#script_element .panel_wrapper div.current {
+	height: 108px;
+}
+
+#style_element .panel_wrapper div.current {
+	height: 108px;
+}
+
+#link_element  .panel_wrapper div.current {
+	height: 140px;
+}
+
+#element_script_value {
+	width: 100%;
+	height: 100px;
+}
+
+#element_comment_value {
+	width: 100%;
+	height: 120px;
+}
+
+#element_style_value {
+	width: 100%;
+	height: 100px;
+}
+
+#element_title, #element_script_src, #element_meta_name, #element_meta_content, #element_base_href, #element_link_href, #element_link_title {
+	width: 250px;
+}
+
+.updateElementButton {
+	margin-top: 3px;
+}
+
+/* MSIE specific styles */
+
+* html .addbutton, * html .removebutton, * html .moveupbutton, * html .movedownbutton {
+	width: 22px;
+	height: 22px;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/fullpage/editor_plugin.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+tinyMCE.importPluginLanguagePack('fullpage');var TinyMCE_FullPagePlugin={getInfo:function(){return{longname:'Fullpage',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/fullpage',version:tinyMCE.majorVersion+"."+tinyMCE.minorVersion}},getControlHTML:function(cn){switch(cn){case"fullpage":return tinyMCE.getButtonHTML(cn,'lang_fullpage_desc','{$pluginurl}/images/fullpage.gif','mceFullPageProperties')}return""},execCommand:function(editor_id,element,command,user_interface,value){switch(command){case"mceFullPageProperties":var template=new Array();template['file']='../../plugins/fullpage/fullpage.htm';template['width']=430;template['height']=485+(tinyMCE.isOpera?5:0);template['width']+=tinyMCE.getLang('lang_fullpage_delta_width',0);template['height']+=tinyMCE.getLang('lang_fullpage_delta_height',0);tinyMCE.openWindow(template,{editor_id:editor_id,inline:"yes"});return true;case"mceFullPageUpdate":TinyMCE_FullPagePlugin._addToHead(tinyMCE.getInstanceById(editor_id));return true}return false},cleanup:function(type,content,inst){switch(type){case"insert_to_editor":var tmp=content.toLowerCase();var pos=tmp.indexOf('<body'),pos2;if(pos!=-1){pos=tmp.indexOf('>',pos);pos2=tmp.lastIndexOf('</body>');inst.fullpageTopContent=content.substring(0,pos+1);content=content.substring(pos+1,pos2);}else{if(!inst.fullpageTopContent){var docType=tinyMCE.getParam("fullpage_default_doctype",'<!DOCTYPE html PUBLIC "-/'+'/W3C//DTD XHTML 1.0 Transitional/'+'/EN" "http:/'+'/www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">');var enc=tinyMCE.getParam("fullpage_default_encoding",'utf-8');var title=tinyMCE.getParam("fullpage_default_title",'Untitled document');var lang=tinyMCE.getParam("fullpage_default_langcode",'en');var pi=tinyMCE.getParam("fullpage_default_xml_pi",true);var ff=tinyMCE.getParam("fullpage_default_font_family","");var fz=tinyMCE.getParam("fullpage_default_font_size","");var ds=tinyMCE.getParam("fullpage_default_style","");var dtc=tinyMCE.getParam("fullpage_default_text_color","");title=title.replace(/&/g,'&amp;');title=title.replace(/\"/g,'&quot;');title=title.replace(/</g,'&lt;');title=title.replace(/>/g,'&gt;');tmp='';if(pi)tmp+='<?xml version="1.0" encoding="'+enc+'"?>\n';tmp+=docType+'\n';tmp+='<html xmlns="http:/'+'/www.w3.org/1999/xhtml" lang="'+lang+'" xml:lang="'+lang+'">\n';tmp+='<head>\n';tmp+='\t<title>'+title+'</title>\n';tmp+='\t<meta http-equiv="Content-Type" content="text/html; charset='+enc+'" />\n';tmp+='</head>\n';tmp+='<body';if(ff!=''||fz!=''){tmp+=' style="';if(ds!='')tmp+=ds+";";if(ff!='')tmp+='font-family: '+ff+";";if(fz!='')tmp+='font-size: '+fz+";";tmp+='"'}if(dtc!='')tmp+=' text="'+dtc+'"';tmp+='>\n';inst.fullpageTopContent=tmp}}this._addToHead(inst);break;case"get_from_editor":if(inst.fullpageTopContent)content=inst.fullpageTopContent+content+"\n</body>\n</html>";break}return content},_addToHead:function(inst){var doc=inst.getDoc();var head=doc.getElementsByTagName("head")[0];var body=doc.body;var h=inst.fullpageTopContent;var e=doc.createElement("body");var nl,i,le,tmp;h=h.replace(/(\r|\n)/gi,'');h=h.replace(/<\?[^\>]*\>/gi,'');h=h.replace(/<\/?(!DOCTYPE|head|html)[^\>]*\>/gi,'');h=h.replace(/<script(.*?)<\/script>/gi,'');h=h.replace(/<title(.*?)<\/title>/gi,'');h=h.replace(/<(meta|base)[^>]*>/gi,'');h=h.replace(/<link([^>]*)\/>/gi,'<pre mce_type="link" $1></pre>');h=h.replace(/<body/gi,'<div mce_type="body"');h+='</div>';e.innerHTML=h;body.vLink=body.aLink=body.link=body.text='';body.style.cssText='';nl=head.getElementsByTagName('link');for(i=0;i<nl.length;i++){if(tinyMCE.getAttrib(nl[i],'mce_head')=="true")nl[i].parentNode.removeChild(nl[i])}nl=e.getElementsByTagName('pre');for(i=0;i<nl.length;i++){tmp=tinyMCE.getAttrib(nl[i],'media');if(tinyMCE.getAttrib(nl[i],'mce_type')=="link"&&(tmp==""||tmp=="screen"||tmp=="all")&&tinyMCE.getAttrib(nl[i],'rel')=="stylesheet"){le=doc.createElement("link");le.rel="stylesheet";le.href=tinyMCE.getAttrib(nl[i],'href');le.setAttribute("mce_head","true");head.appendChild(le)}}nl=e.getElementsByTagName('div');if(nl.length>0){body.style.cssText=tinyMCE.getAttrib(nl[0],'style');if((tmp=tinyMCE.getAttrib(nl[0],'leftmargin'))!=''&&body.style.marginLeft=='')body.style.marginLeft=tmp+"px";if((tmp=tinyMCE.getAttrib(nl[0],'rightmargin'))!=''&&body.style.marginRight=='')body.style.marginRight=tmp+"px";if((tmp=tinyMCE.getAttrib(nl[0],'topmargin'))!=''&&body.style.marginTop=='')body.style.marginTop=tmp+"px";if((tmp=tinyMCE.getAttrib(nl[0],'bottommargin'))!=''&&body.style.marginBottom=='')body.style.marginBottom=tmp+"px";body.dir=tinyMCE.getAttrib(nl[0],'dir');body.vLink=tinyMCE.getAttrib(nl[0],'vlink');body.aLink=tinyMCE.getAttrib(nl[0],'alink');body.link=tinyMCE.getAttrib(nl[0],'link');body.text=tinyMCE.getAttrib(nl[0],'text');if((tmp=tinyMCE.getAttrib(nl[0],'background'))!='')body.style.backgroundImage="url('"+tmp+"')";if((tmp=tinyMCE.getAttrib(nl[0],'bgcolor'))!='')body.style.backgroundColor=tmp}}};tinyMCE.addPlugin("fullpage",TinyMCE_FullPagePlugin);
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/fullpage/editor_plugin_src.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,227 @@
+/**
+ * $Id: editor_plugin_src.js 201 2007-02-12 15:56:56Z spocke $
+ *
+ * @author Moxiecode
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+/* Import plugin specific language pack */
+tinyMCE.importPluginLanguagePack('fullpage');
+
+var TinyMCE_FullPagePlugin = {
+	getInfo : function() {
+		return {
+			longname : 'Fullpage',
+			author : 'Moxiecode Systems AB',
+			authorurl : 'http://tinymce.moxiecode.com',
+			infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/fullpage',
+			version : tinyMCE.majorVersion + "." + tinyMCE.minorVersion
+		};
+	},
+
+	getControlHTML : function(cn) {
+		switch (cn) {
+			case "fullpage":
+				return tinyMCE.getButtonHTML(cn, 'lang_fullpage_desc', '{$pluginurl}/images/fullpage.gif', 'mceFullPageProperties');
+		}
+
+		return "";
+	},
+
+	execCommand : function(editor_id, element, command, user_interface, value) {
+		// Handle commands
+		switch (command) {
+			case "mceFullPageProperties":
+				var template = new Array();
+
+				template['file']   = '../../plugins/fullpage/fullpage.htm';
+				template['width']  = 430;
+				template['height'] = 485 + (tinyMCE.isOpera ? 5 : 0);
+
+				template['width'] += tinyMCE.getLang('lang_fullpage_delta_width', 0);
+				template['height'] += tinyMCE.getLang('lang_fullpage_delta_height', 0);
+
+				tinyMCE.openWindow(template, {editor_id : editor_id, inline : "yes"});
+			return true;
+
+			case "mceFullPageUpdate":
+				TinyMCE_FullPagePlugin._addToHead(tinyMCE.getInstanceById(editor_id));
+				return true;
+	   }
+
+	   // Pass to next handler in chain
+	   return false;
+	},
+
+	cleanup : function(type, content, inst) {
+		switch (type) {
+			case "insert_to_editor":
+				var tmp = content.toLowerCase();
+				var pos = tmp.indexOf('<body'), pos2;
+
+				// Split page in header and body chunks
+				if (pos != -1) {
+					pos = tmp.indexOf('>', pos);
+					pos2 = tmp.lastIndexOf('</body>');
+					inst.fullpageTopContent = content.substring(0, pos + 1);
+					content = content.substring(pos + 1, pos2);
+					// tinyMCE.debug(inst.fullpageTopContent, content);
+				} else {
+					if (!inst.fullpageTopContent) {
+						var docType = tinyMCE.getParam("fullpage_default_doctype", '<!DOCTYPE html PUBLIC "-/'+'/W3C//DTD XHTML 1.0 Transitional/'+'/EN" "http:/'+'/www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">');
+						var enc = tinyMCE.getParam("fullpage_default_encoding", 'utf-8');
+						var title = tinyMCE.getParam("fullpage_default_title", 'Untitled document');
+						var lang = tinyMCE.getParam("fullpage_default_langcode", 'en');
+						var pi = tinyMCE.getParam("fullpage_default_xml_pi", true);
+						var ff = tinyMCE.getParam("fullpage_default_font_family", "");
+						var fz = tinyMCE.getParam("fullpage_default_font_size", "");
+						var ds = tinyMCE.getParam("fullpage_default_style", "");
+						var dtc = tinyMCE.getParam("fullpage_default_text_color", "");
+
+						// Xml encode it
+						title = title.replace(/&/g, '&amp;');
+						title = title.replace(/\"/g, '&quot;');
+						title = title.replace(/</g, '&lt;');
+						title = title.replace(/>/g, '&gt;');
+
+						tmp = '';
+
+						// Make default chunk
+						if (pi)
+							tmp += '<?xml version="1.0" encoding="' + enc + '"?>\n';
+
+						tmp += docType + '\n';
+						tmp += '<html xmlns="http:/'+'/www.w3.org/1999/xhtml" lang="' + lang + '" xml:lang="' + lang + '">\n';
+						tmp += '<head>\n';
+						tmp += '\t<title>' + title + '</title>\n';
+						tmp += '\t<meta http-equiv="Content-Type" content="text/html; charset=' + enc + '" />\n';
+						tmp += '</head>\n';
+						tmp += '<body';
+
+						if (ff != '' || fz != '') {
+							tmp += ' style="';
+
+							if (ds != '')
+								tmp += ds + ";";
+
+							if (ff != '')
+								tmp += 'font-family: ' + ff + ";";
+
+							if (fz != '')
+								tmp += 'font-size: ' + fz + ";";
+
+							tmp += '"';
+						}
+
+						if (dtc != '')
+							tmp += ' text="' + dtc + '"';
+
+						tmp += '>\n';
+
+						inst.fullpageTopContent = tmp;
+					}
+				}
+
+				this._addToHead(inst);
+
+				break;
+
+			case "get_from_editor":
+				if (inst.fullpageTopContent)
+					content = inst.fullpageTopContent + content + "\n</body>\n</html>";
+
+				break;
+		}
+
+		// Pass through to next handler in chain
+		return content;
+	},
+
+	// Private plugin internal methods
+
+	_addToHead : function(inst) {
+		var doc = inst.getDoc();
+		var head = doc.getElementsByTagName("head")[0];
+		var body = doc.body;
+		var h = inst.fullpageTopContent;
+		var e = doc.createElement("body");
+		var nl, i, le, tmp;
+
+		// Remove stuff we don't want
+		h = h.replace(/(\r|\n)/gi, '');
+		h = h.replace(/<\?[^\>]*\>/gi, '');
+		h = h.replace(/<\/?(!DOCTYPE|head|html)[^\>]*\>/gi, '');
+		h = h.replace(/<script(.*?)<\/script>/gi, '');
+		h = h.replace(/<title(.*?)<\/title>/gi, '');
+		h = h.replace(/<(meta|base)[^>]*>/gi, '');
+
+		// Make link and style elements into pre
+		h = h.replace(/<link([^>]*)\/>/gi, '<pre mce_type="link" $1></pre>');
+		//h = h.replace(/<style([^>]*)>(.*?)<\/style>/gi, '<pre mce_type="style" $1>$2</pre>');
+
+		// Make body a div
+		h = h.replace(/<body/gi, '<div mce_type="body"');
+		h += '</div>';
+
+		// Now crapy MSIE can parse it
+		e.innerHTML = h;
+
+		// Reset all body attributes
+		body.vLink = body.aLink = body.link = body.text = '';
+		body.style.cssText = '';
+
+		// Delete all old links
+		nl = head.getElementsByTagName('link');
+		for (i=0; i<nl.length; i++) {
+			if (tinyMCE.getAttrib(nl[i], 'mce_head') == "true")
+				nl[i].parentNode.removeChild(nl[i]);
+		}
+
+		// Add link elements
+		nl = e.getElementsByTagName('pre');
+		for (i=0; i<nl.length; i++) {
+			tmp = tinyMCE.getAttrib(nl[i], 'media');
+			if (tinyMCE.getAttrib(nl[i], 'mce_type') == "link" && (tmp == "" || tmp == "screen" || tmp == "all") && tinyMCE.getAttrib(nl[i], 'rel') == "stylesheet") {
+				le = doc.createElement("link");
+
+				le.rel = "stylesheet";
+				le.href = tinyMCE.getAttrib(nl[i], 'href');
+				le.setAttribute("mce_head", "true");
+
+				head.appendChild(le);
+			}
+		}
+
+		// Add body attributes
+		nl = e.getElementsByTagName('div');
+		if (nl.length > 0) {
+			body.style.cssText = tinyMCE.getAttrib(nl[0], 'style');
+
+			if ((tmp = tinyMCE.getAttrib(nl[0], 'leftmargin')) != '' && body.style.marginLeft == '')
+				body.style.marginLeft = tmp + "px";
+
+			if ((tmp = tinyMCE.getAttrib(nl[0], 'rightmargin')) != '' && body.style.marginRight == '')
+				body.style.marginRight = tmp + "px";
+
+			if ((tmp = tinyMCE.getAttrib(nl[0], 'topmargin')) != '' && body.style.marginTop == '')
+				body.style.marginTop = tmp + "px";
+
+			if ((tmp = tinyMCE.getAttrib(nl[0], 'bottommargin')) != '' && body.style.marginBottom == '')
+				body.style.marginBottom = tmp + "px";
+
+			body.dir = tinyMCE.getAttrib(nl[0], 'dir');
+			body.vLink = tinyMCE.getAttrib(nl[0], 'vlink');
+			body.aLink = tinyMCE.getAttrib(nl[0], 'alink');
+			body.link = tinyMCE.getAttrib(nl[0], 'link');
+			body.text = tinyMCE.getAttrib(nl[0], 'text');
+
+			if ((tmp = tinyMCE.getAttrib(nl[0], 'background')) != '')
+				body.style.backgroundImage = "url('" + tmp + "')";
+
+			if ((tmp = tinyMCE.getAttrib(nl[0], 'bgcolor')) != '')
+				body.style.backgroundColor = tmp;
+		}
+	}
+};
+
+tinyMCE.addPlugin("fullpage", TinyMCE_FullPagePlugin);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/fullpage/fullpage.htm	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,577 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>{$lang_fullpage_title}</title>
+	<script language="javascript" type="text/javascript" src="../../tiny_mce_popup.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/mctabs.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/mclayer.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/form_utils.js"></script>
+	<script language="javascript" type="text/javascript" src="jscripts/fullpage.js"></script>
+	<link href="css/fullpage.css" rel="stylesheet" type="text/css" />
+	<base target="_self" />
+</head>
+<body id="advlink" onload="tinyMCEPopup.executeOnLoad('init();');" style="display: none">
+    <form onsubmit="updateAction();return false;" name="fullpage" action="#">
+		<div class="tabs">
+			<ul>
+				<li id="meta_tab" class="current"><span><a href="javascript:mcTabs.displayTab('meta_tab','meta_panel');" onmousedown="return false;">{$lang_fullpage_meta_tab}</a></span></li>
+				<li id="appearance_tab"><span><a href="javascript:mcTabs.displayTab('appearance_tab','appearance_panel');" onmousedown="return false;">{$lang_fullpage_appearance_tab}</a></span></li>
+				<li id="advanced_tab"><span><a href="javascript:mcTabs.displayTab('advanced_tab','advanced_panel');" onmousedown="return false;">{$lang_fullpage_advanced_tab}</a></span></li>
+			</ul>
+		</div>
+
+		<div class="panel_wrapper">
+			<div id="meta_panel" class="panel current">
+				<fieldset>
+					<legend>{$lang_fullpage_meta_props}</legend>
+
+					<table border="0" cellpadding="4" cellspacing="0">
+						<tr>
+							<td nowrap="nowrap"><label for="metatitle">{$lang_fullpage_meta_title}</label>&nbsp;</td>
+							<td><input type="text" id="metatitle" name="metatitle" value="" /></td>
+						</tr>
+						<tr>
+							<td nowrap="nowrap"><label for="metakeywords">{$lang_fullpage_meta_keywords}</label>&nbsp;</td>
+							<td><textarea id="metakeywords" name="metakeywords" rows="3"></textarea></td>
+						</tr>
+						<tr>
+							<td nowrap="nowrap"><label for="metadescription">{$lang_fullpage_meta_description}</label>&nbsp;</td>
+							<td><textarea id="metadescription" name="metadescription" rows="3"></textarea></td>
+						</tr>
+						<tr>
+							<td nowrap="nowrap"><label for="metaauthor">{$lang_fullpage_author}</label>&nbsp;</td>
+							<td><input type="text" id="metaauthor" name="metaauthor" value="" /></td>
+						</tr>
+						<tr>
+							<td nowrap="nowrap"><label for="metacopyright">{$lang_fullpage_copyright}</label>&nbsp;</td>
+							<td><input type="text" id="metacopyright" name="metacopyright" value="" /></td>
+						</tr>
+						<tr>
+							<td nowrap="nowrap"><label for="metarobots">{$lang_fullpage_meta_robots}</label>&nbsp;</td>
+							<td>
+<select id="metarobots" name="metarobots">
+			<option value="">{$lang_not_set}</option> 
+			<option value="index,follow">{$lang_fullpage_meta_index_follow}</option>
+			<option value="index,nofollow">{$lang_fullpage_meta_index_nofollow}</option>
+			<option value="noindex,follow">{$lang_fullpage_meta_noindex_follow}</option>
+			<option value="noindex,nofollow">{$lang_fullpage_meta_noindex_nofollow}</option>
+</select>
+							</td>
+						</tr>
+					</table>
+				</fieldset>
+
+				<fieldset>
+					<legend>{$lang_fullpage_langprops}</legend>
+
+					<table border="0" cellpadding="4" cellspacing="0">
+						<tr>
+							<td class="column1"><label for="docencoding">{$lang_fullpage_encoding}</label></td> 
+							<td>
+								<select id="docencoding" name="docencoding"> 
+										<option value="">{$lang_not_set}</option>
+								</select>
+							</td> 
+						</tr>
+						<tr>
+							<td nowrap="nowrap"><label for="doctypes">{$lang_fullpage_doctypes}</label>&nbsp;</td>
+							<td>
+								<select id="doctypes" name="doctypes">
+										<option value="">{$lang_not_set}</option>
+								</select>
+							</td>
+						</tr>
+						<tr>
+							<td nowrap="nowrap"><label for="langcode">{$lang_fullpage_langcode}</label>&nbsp;</td>
+							<td><input type="text" id="langcode" name="langcode" value="" /></td>
+						</tr>
+						<tr>
+							<td class="column1"><label for="langdir">{$lang_fullpage_langdir}</label></td> 
+							<td>
+								<select id="langdir" name="langdir"> 
+										<option value="">{$lang_not_set}</option> 
+										<option value="ltr">{$lang_fullpage_ltr}</option> 
+										<option value="rtl">{$lang_fullpage_rtl}</option> 
+								</select>
+							</td> 
+						</tr>
+						<tr>
+							<td nowrap="nowrap"><label for="xml_pi">{$lang_fullpage_xml_pi}</label>&nbsp;</td>
+							<td><input type="checkbox" id="xml_pi" name="xml_pi" class="checkbox" /></td>
+						</tr>
+					</table>
+				</fieldset>
+			</div>
+
+			<div id="appearance_panel" class="panel">
+				<fieldset>
+					<legend>{$lang_fullpage_appearance_textprops}</legend>
+
+					<table border="0" cellpadding="4" cellspacing="0">
+						<tr>
+							<td class="column1"><label for="fontface">{$lang_fullpage_fontface}</label></td> 
+							<td>
+								<select id="fontface" name="fontface" onchange="changedStyleField(this);">
+										<option value="">{$lang_not_set}</option>
+								</select>
+							</td> 
+						</tr>
+
+						<tr>
+							<td class="column1"><label for="fontsize">{$lang_fullpage_fontsize}</label></td> 
+							<td>
+								<select id="fontsize" name="fontsize" onchange="changedStyleField(this);">
+										<option value="">{$lang_not_set}</option>
+								</select>
+							</td>
+						</tr>
+
+						<tr>
+							<td class="column1"><label for="textcolor">{$lang_fullpage_textcolor}</label></td> 
+							<td>
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input id="textcolor" name="textcolor" type="text" value="" size="9" onchange="updateColor('textcolor_pick','textcolor');changedStyleField(this);" /></td>
+										<td id="textcolor_pickcontainer">&nbsp;</td>
+									</tr>
+								</table>
+							</td>
+						</tr>
+					</table>
+				</fieldset>
+
+				<fieldset>
+					<legend>{$lang_fullpage_appearance_bgprops}</legend>
+
+					<table border="0" cellpadding="4" cellspacing="0">
+						<tr>
+							<td class="column1"><label for="bgimage">{$lang_fullpage_bgimage}</label></td> 
+							<td>
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input id="bgimage" name="bgimage" type="text" value="" onchange="changedStyleField(this);" /></td>
+										<td id="bgimage_pickcontainer">&nbsp;</td>
+									</tr>
+								</table>
+							</td>
+						</tr>
+						<tr>
+							<td class="column1"><label for="bgcolor">{$lang_fullpage_bgcolor}</label></td> 
+							<td>
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input id="bgcolor" name="bgcolor" type="text" value="" size="9" onchange="updateColor('bgcolor_pick','bgcolor');changedStyleField(this);" /></td>
+										<td id="bgcolor_pickcontainer">&nbsp;</td>
+									</tr>
+								</table>
+							</td> 
+						</tr>
+					</table>
+				</fieldset>
+
+				<fieldset>
+					<legend>{$lang_fullpage_appearance_marginprops}</legend>
+
+					<table border="0" cellpadding="4" cellspacing="0">
+						<tr>
+							<td class="column1"><label for="leftmargin">{$lang_fullpage_left_margin}</label></td> 
+							<td><input id="leftmargin" name="leftmargin" type="text" value="" onchange="changedStyleField(this);" /></td>
+							<td class="column1"><label for="rightmargin">{$lang_fullpage_right_margin}</label></td> 
+							<td><input id="rightmargin" name="rightmargin" type="text" value="" onchange="changedStyleField(this);" /></td>
+						</tr>
+						<tr>
+							<td class="column1"><label for="topmargin">{$lang_fullpage_top_margin}</label></td> 
+							<td><input id="topmargin" name="topmargin" type="text" value="" onchange="changedStyleField(this);" /></td>
+							<td class="column1"><label for="bottommargin">{$lang_fullpage_bottom_margin}</label></td> 
+							<td><input id="bottommargin" name="bottommargin" type="text" value="" onchange="changedStyleField(this);" /></td>
+						</tr>
+					</table>
+				</fieldset>
+
+				<fieldset>
+					<legend>{$lang_fullpage_appearance_linkprops}</legend>
+
+					<table border="0" cellpadding="4" cellspacing="0">
+						<tr>
+							<td class="column1"><label for="link_color">{$lang_fullpage_link_color}</label></td> 
+							<td>
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input id="link_color" name="link_color" type="text" value="" size="9" onchange="updateColor('link_color_pick','link_color');changedStyleField(this);" /></td>
+										<td id="link_color_pickcontainer">&nbsp;</td>
+									</tr>
+								</table>
+							</td>
+
+							<td class="column1"><label for="visited_color">{$lang_fullpage_visited_color}</label></td> 
+							<td>
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input id="visited_color" name="visited_color" type="text" value="" size="9" onchange="updateColor('visited_color_pick','visited_color');changedStyleField(this);" /></td>
+										<td id="visited_color_pickcontainer">&nbsp;</td>
+									</tr>
+								</table>
+							</td>
+						</tr>
+
+						<tr>
+							<td class="column1"><label for="active_color">{$lang_fullpage_active_color}</label></td> 
+							<td>
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input id="active_color" name="active_color" type="text" value="" size="9" onchange="updateColor('active_color_pick','active_color');changedStyleField(this);" /></td>
+										<td id="active_color_pickcontainer">&nbsp;</td>
+									</tr>
+								</table>
+							</td>
+
+							<td>&nbsp;</td>
+							<td>&nbsp;</td>
+
+<!--							<td class="column1"><label for="hover_color">{$lang_fullpage_hover_color}</label></td> 
+							<td>
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input id="hover_color" name="hover_color" type="text" value="" size="9" onchange="changedStyleField(this);" /></td>
+										<td id="hover_color_pickcontainer">&nbsp;</td>
+									</tr>
+								</table>
+							</td> -->
+						</tr>
+					</table>
+				</fieldset>
+
+				<fieldset>
+					<legend>{$lang_fullpage_appearance_style}</legend>
+
+					<table border="0" cellpadding="4" cellspacing="0">
+						<tr>
+							<td class="column1"><label for="stylesheet">{$lang_fullpage_stylesheet}</label></td> 
+							<td><table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input id="stylesheet" name="stylesheet" type="text" value="" /></td>
+										<td id="stylesheet_browsercontainer">&nbsp;</td>
+									</tr>
+								</table></td>
+						</tr>
+						<tr>
+							<td class="column1"><label for="style">{$lang_fullpage_style}</label></td> 
+							<td><input id="style" name="style" type="text" value="" onchange="changedStyleField(this);" /></td>
+						</tr>
+					</table>
+				</fieldset>
+			</div>
+
+			<div id="advanced_panel" class="panel">
+				<div id="addmenu">
+					<table border="0" cellpadding="0" cellspacing="0">
+						<tr><td><a href="javascript:addHeadElm('title');" onmousedown="return false;"><span>{$lang_fullpage_add_title}</span></a></td></tr>
+						<tr><td><a href="javascript:addHeadElm('meta');" onmousedown="return false;"><span>{$lang_fullpage_add_meta}</span></a></td></tr>
+						<tr><td><a href="javascript:addHeadElm('script');" onmousedown="return false;"><span>{$lang_fullpage_add_script}</span></a></td></tr>
+						<tr><td><a href="javascript:addHeadElm('style');" onmousedown="return false;"><span>{$lang_fullpage_add_style}</span></a></td></tr>
+						<tr><td><a href="javascript:addHeadElm('link');" onmousedown="return false;"><span>{$lang_fullpage_add_link}</span></a></td></tr>
+						<tr><td><a href="javascript:addHeadElm('base');" onmousedown="return false;"><span>{$lang_fullpage_add_base}</span></a></td></tr>
+						<tr><td><a href="javascript:addHeadElm('comment');" onmousedown="return false;"><span>{$lang_fullpage_add_comment}</span></a></td></tr>
+					</table>
+				</div>
+
+				<fieldset>
+					<legend>{$lang_fullpage_head_elements}</legend>
+
+					<div class="headlistwrapper">
+						<div class="toolbar">
+							<div style="float: left">
+								<a id="addbutton" href="javascript:showAddMenu();" onmousedown="return false;" class="addbutton" title="{$lang_fullpage_add}"></a>
+								<a href="#" onmousedown="return false;" class="removebutton" title="{$lang_fullpage_remove}"></a>
+							</div>
+							<div style="float: right">
+								<a href="#" onmousedown="return false;" class="moveupbutton" title="{$lang_fullpage_moveup}"></a>
+								<a href="#" onmousedown="return false;" class="movedownbutton" title="{$lang_fullpage_movedown}"></a>
+							</div>
+							<br style="clear: both" />
+						</div>
+						<select id="headlist" size="26" onchange="updateHeadElm(this.options[this.selectedIndex].value);">
+							<option value="title_0">&lt;title&gt;Some title bla bla bla&lt;/title&gt;</option>
+							<option value="meta_1">&lt;meta name="keywords"&gt;Some bla bla bla&lt;/meta&gt;</option>
+							<option value="meta_2">&lt;meta name="description"&gt;Some bla bla bla bla bla bla bla bla bla&lt;/meta&gt;</option>
+							<option value="script_3">&lt;script language=&quot;javascript&quot;&gt;...&lt;/script&gt;</option>
+							<option value="style_4">&lt;style&gt;...&lt;/style&gt;</option>
+							<option value="base_5">&lt;base href="." /&gt;</option>
+							<option value="comment_6">&lt;!-- ... --&gt;</option>
+							<option value="link_7">&lt;link href="." /&gt;</option>
+						</select>
+					</div>
+				</fieldset>
+
+				<fieldset id="meta_element">
+					<legend>{$lang_fullpage_meta_element}</legend>
+
+					<table border="0" cellpadding="4" cellspacing="0">
+						<tr>
+							<td class="column1"><label for="element_meta_type">{$lang_fullpage_type}</label></td> 
+							<td><select id="element_meta_type">
+										<option value="name">name</option>
+										<option value="http-equiv">http-equiv</option>
+								</select></td>
+						</tr>
+						<tr>
+							<td class="column1"><label for="element_meta_name">{$lang_fullpage_name}</label></td> 
+							<td><input id="element_meta_name" name="element_meta_name" type="text" value="" /></td>
+						</tr>
+						<tr>
+							<td class="column1"><label for="element_meta_content">{$lang_fullpage_content}</label></td> 
+							<td><input id="element_meta_content" name="element_meta_content" type="text" value="" /></td>
+						</tr>
+					</table>
+
+					<input type="button" id="meta_updateelement" class="updateElementButton" name="update" value="{$lang_update}" onclick="updateElement();" />
+				</fieldset>
+
+				<fieldset id="title_element">
+					<legend>{$lang_fullpage_title_element}</legend>
+
+					<table border="0" cellpadding="4" cellspacing="0">
+						<tr>
+							<td class="column1"><label for="element_title">{$lang_fullpage_meta_title}</label></td> 
+							<td><input id="element_title" name="element_title" type="text" value="" /></td>
+						</tr>
+					</table>
+
+					<input type="button" id="title_updateelement" class="updateElementButton" name="update" value="{$lang_update}" onclick="updateElement();" />
+				</fieldset>
+
+				<fieldset id="script_element">
+					<legend>{$lang_fullpage_script_element}</legend>
+
+					<div class="tabs">
+						<ul>
+							<li id="script_props_tab" class="current"><span><a href="javascript:mcTabs.displayTab('script_props_tab','script_props_panel');" onmousedown="return false;">{$lang_fullpage_properties}</a></span></li>
+							<li id="script_value_tab"><span><a href="javascript:mcTabs.displayTab('script_value_tab','script_value_panel');" onmousedown="return false;">{$lang_fullpage_value}</a></span></li>
+						</ul>
+					</div>
+
+					<br style="clear: both" />
+
+					<div class="panel_wrapper">
+						<div id="script_props_panel" class="panel current">
+							<table border="0" cellpadding="4" cellspacing="0">
+								<tr>
+									<td class="column1"><label for="element_script_type">{$lang_fullpage_type}</label></td> 
+									<td><select id="element_script_type">
+										<option value="text/javascript">text/javascript</option>
+										<option value="text/jscript">text/jscript</option>
+										<option value="text/vbscript">text/vbscript</option>
+										<option value="text/vbs">text/vbs</option>
+										<option value="text/ecmascript">text/ecmascript</option>
+										<option value="text/xml">text/xml</option>
+									</select></td>
+								</tr>
+								<tr>
+									<td class="column1"><label for="element_script_src">{$lang_fullpage_src}</label></td> 
+									<td><table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input id="element_script_src" name="element_script_src" type="text" value="" /></td>
+										<td id="script_src_pickcontainer">&nbsp;</td>
+									</tr>
+								</table></td>
+								</tr>
+								<tr>
+									<td class="column1"><label for="element_script_charset">{$lang_fullpage_charset}</label></td> 
+									<td><select id="element_script_charset"><option value="">{$lang_not_set}</option></select></td>
+								</tr>
+								<tr>
+									<td class="column1"><label for="element_script_defer">{$lang_fullpage_defer}</label></td> 
+									<td><input type="checkbox" id="element_script_defer" name="element_script_defer" class="checkbox" /></td>
+								</tr>
+							</table>
+						</div>
+
+						<div id="script_value_panel" class="panel">
+							<textarea id="element_script_value"></textarea>
+						</div>
+					</div>
+
+					<input type="button" id="script_updateelement" class="updateElementButton" name="update" value="{$lang_update}" onclick="updateElement();" />
+				</fieldset>
+
+				<fieldset id="style_element">
+					<legend>{$lang_fullpage_style_element}</legend>
+
+					<div class="tabs">
+						<ul>
+							<li id="style_props_tab" class="current"><span><a href="javascript:mcTabs.displayTab('style_props_tab','style_props_panel');" onmousedown="return false;">{$lang_fullpage_properties}</a></span></li>
+							<li id="style_value_tab"><span><a href="javascript:mcTabs.displayTab('style_value_tab','style_value_panel');" onmousedown="return false;">{$lang_fullpage_value}</a></span></li>
+						</ul>
+					</div>
+
+					<br style="clear: both" />
+
+					<div class="panel_wrapper">
+						<div id="style_props_panel" class="panel current">
+							<table border="0" cellpadding="4" cellspacing="0">
+								<tr>
+									<td class="column1"><label for="element_style_type">{$lang_fullpage_type}</label></td> 
+									<td><select id="element_style_type">
+										<option value="text/css">text/css</option>
+									</select></td>
+								</tr>
+								<tr>
+									<td class="column1"><label for="element_style_media">{$lang_fullpage_media}</label></td> 
+									<td><select id="element_style_media"></select></td>
+								</tr>
+							</table>
+						</div>
+
+						<div id="style_value_panel" class="panel">
+							<textarea id="element_style_value"></textarea>
+						</div>
+					</div>
+
+					<input type="button" id="style_updateelement" class="updateElementButton" name="update" value="{$lang_update}" onclick="updateElement();" />
+				</fieldset>
+
+				<fieldset id="base_element">
+					<legend>{$lang_fullpage_base_element}</legend>
+
+					<table border="0" cellpadding="4" cellspacing="0">
+						<tr>
+							<td class="column1"><label for="element_base_href">{$lang_fullpage_href}</label></td> 
+							<td><input id="element_base_href" name="element_base_href" type="text" value="" /></td>
+						</tr>
+						<tr>
+							<td class="column1"><label for="element_base_target">{$lang_fullpage_target}</label></td> 
+							<td><input id="element_base_target" name="element_base_target" type="text" value="" /></td>
+						</tr>
+					</table>
+
+					<input type="button" id="base_updateelement" class="updateElementButton" name="update" value="{$lang_update}" onclick="updateElement();" />
+				</fieldset>
+
+				<fieldset id="link_element">
+					<legend>{$lang_fullpage_link_element}</legend>
+
+					<div class="tabs">
+						<ul>
+							<li id="link_general_tab" class="current"><span><a href="javascript:mcTabs.displayTab('link_general_tab','link_general_panel');" onmousedown="return false;">{$lang_fullpage_general_props}</a></span></li>
+							<li id="link_advanced_tab"><span><a href="javascript:mcTabs.displayTab('link_advanced_tab','link_advanced_panel');" onmousedown="return false;">{$lang_fullpage_advanced_props}</a></span></li>
+						</ul>
+					</div>
+
+					<br style="clear: both" />
+
+					<div class="panel_wrapper">
+						<div id="link_general_panel" class="panel current">
+							<table border="0" cellpadding="4" cellspacing="0">
+								<tr>
+									<td class="column1"><label for="element_link_href">{$lang_fullpage_href}</label></td> 
+									<td><table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input id="element_link_href" name="element_link_href" type="text" value="" /></td>
+										<td id="link_href_pickcontainer">&nbsp;</td>
+									</tr>
+								</table></td>
+								</tr>
+								<tr>
+									<td class="column1"><label for="element_link_title">{$lang_fullpage_meta_title}</label></td> 
+									<td><input id="element_link_title" name="element_link_title" type="text" value="" /></td>
+								</tr>
+								<tr>
+									<td class="column1"><label for="element_link_type">{$lang_fullpage_type}</label></td> 
+									<td><select id="element_link_type" name="element_link_type">
+										<option value="text/css">text/css</option>
+										<option value="text/javascript">text/javascript</option>
+									</select></td>
+								</tr>
+								<tr>
+									<td class="column1"><label for="element_link_media">{$lang_fullpage_media}</label></td> 
+									<td><select id="element_link_media" name="element_link_media"></select></td>
+								</tr>
+								<tr>
+									<td><label for="element_style_rel">{$lang_fullpage_rel}</label></td>
+									<td><select id="element_style_rel" name="element_style_rel"> 
+											<option value="">{$lang_not_set}</option> 
+											<option value="stylesheet">Stylesheet</option>
+											<option value="alternate">Alternate</option>
+											<option value="designates">Designates</option>
+											<option value="start">Start</option>
+											<option value="next">Next</option>
+											<option value="prev">Prev</option>
+											<option value="contents">Contents</option>
+											<option value="index">Index</option>
+											<option value="glossary">Glossary</option>
+											<option value="copyright">Copyright</option>
+											<option value="chapter">Chapter</option>
+											<option value="subsection">Subsection</option>
+											<option value="appendix">Appendix</option>
+											<option value="help">Help</option>
+											<option value="bookmark">Bookmark</option>
+										</select> 
+									</td>
+								</tr>
+							</table>
+						</div>
+
+						<div id="link_advanced_panel" class="panel">
+							<table border="0" cellpadding="4" cellspacing="0">
+								<tr>
+									<td class="column1"><label for="element_link_charset">{$lang_fullpage_charset}</label></td> 
+									<td><select id="element_link_charset"><option value="">{$lang_not_set}</option></select></td>
+								</tr>
+								<tr>
+									<td class="column1"><label for="element_link_hreflang">{$lang_fullpage_hreflang}</label></td> 
+									<td><input id="element_link_hreflang" name="element_link_hreflang" type="text" value="" /></td>
+								</tr>
+								<tr>
+									<td class="column1"><label for="element_link_target">{$lang_fullpage_target}</label></td> 
+									<td><input id="element_link_target" name="element_link_target" type="text" value="" /></td>
+								</tr>
+								<tr>
+									<td><label for="element_style_rev">{$lang_fullpage_rev}</label></td>
+									<td><select id="element_style_rev" name="element_style_rev"> 
+											<option value="">{$lang_not_set}</option> 
+											<option value="alternate">Alternate</option> 
+											<option value="designates">Designates</option> 
+											<option value="stylesheet">Stylesheet</option> 
+											<option value="start">Start</option> 
+											<option value="next">Next</option> 
+											<option value="prev">Prev</option> 
+											<option value="contents">Contents</option> 
+											<option value="index">Index</option> 
+											<option value="glossary">Glossary</option> 
+											<option value="copyright">Copyright</option> 
+											<option value="chapter">Chapter</option> 
+											<option value="subsection">Subsection</option> 
+											<option value="appendix">Appendix</option> 
+											<option value="help">Help</option> 
+											<option value="bookmark">Bookmark</option> 
+										</select> 
+									</td>
+								</tr>
+							</table>
+						</div>
+					</div>
+
+					<input type="button" id="link_updateelement" class="updateElementButton" name="update" value="{$lang_update}" onclick="updateElement();" />
+				</fieldset>
+
+				<fieldset id="comment_element">
+					<legend>{$lang_fullpage_comment_element}</legend>
+
+					<textarea id="element_comment_value"></textarea>
+
+					<input type="button" id="comment_updateelement" class="updateElementButton" name="update" value="{$lang_update}" onclick="updateElement();" />
+				</fieldset>
+			</div>
+		</div>
+
+		<div class="mceActionPanel">
+			<div style="float: left">
+				<input type="button" id="insert" name="update" value="{$lang_update}" onclick="updateAction();" />
+			</div>
+
+			<div style="float: right">
+				<input type="button" id="cancel" name="cancel" value="{$lang_cancel}" onclick="tinyMCEPopup.close();" />
+			</div>
+		</div>
+    </form>
+</body>
+</html>
Binary file includes/clientside/tinymce/plugins/fullpage/images/add.gif has changed
Binary file includes/clientside/tinymce/plugins/fullpage/images/fullpage.gif has changed
Binary file includes/clientside/tinymce/plugins/fullpage/images/move_down.gif has changed
Binary file includes/clientside/tinymce/plugins/fullpage/images/move_up.gif has changed
Binary file includes/clientside/tinymce/plugins/fullpage/images/remove.gif has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/fullpage/jscripts/fullpage.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,580 @@
+//
+
+var defaultDocTypes = 
+	'XHTML 1.0 Transitional=<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">,' +
+	'XHTML 1.0 Frameset=<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">,' +
+	'XHTML 1.0 Strict=<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">,' +
+	'XHTML 1.1=<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">">,' +
+	'HTML 4.01 Transitional=<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">,' +
+	'HTML 4.01 Strict=<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">,' +
+	'HTML 4.01 Frameset=<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">';
+
+var defaultEncodings = 
+	'Western european (iso-8859-1)=iso-8859-1,' +
+	'Central European (iso-8859-2)=iso-8859-2,' +
+	'Unicode (UTF-8)=utf-8,' +
+	'Chinese traditional (Big5)=big5,' +
+	'Cyrillic (iso-8859-5)=iso-8859-5,' +
+	'Japanese (iso-2022-jp)=iso-2022-jp,' +
+	'Greek (iso-8859-7)=iso-8859-7,' +
+	'Korean (iso-2022-kr)=iso-2022-kr,' +
+	'ASCII (us-ascii)=us-ascii';
+
+var defaultMediaTypes = 
+	'all=all,' +
+	'screen=screen,' +
+	'print=print,' +
+	'tty=tty,' +
+	'tv=tv,' +
+	'projection=projection,' +
+	'handheld=handheld,' +
+	'braille=braille,' +
+	'aural=aural';
+
+var defaultFontNames = 'Arial=arial,helvetica,sans-serif;Courier New=courier new,courier,monospace;Georgia=georgia,times new roman,times,serif;Tahoma=tahoma,arial,helvetica,sans-serif;Times New Roman=times new roman,times,serif;Verdana=verdana,arial,helvetica,sans-serif;Impact=impact;WingDings=wingdings';
+var defaultFontSizes = '10px,11px,12px,13px,14px,15px,16px';
+
+var addMenuLayer = new MCLayer("addmenu");
+var lastElementType = null;
+var topDoc;
+
+function init() {
+	var f = document.forms['fullpage'];
+	var i, p, doctypes, encodings, mediaTypes, fonts;
+	var inst = tinyMCE.getInstanceById(tinyMCE.getWindowArg('editor_id'));
+
+	// Setup doctype select box
+	doctypes = tinyMCE.getParam("fullpage_doctypes", defaultDocTypes).split(',');
+	for (i=0; i<doctypes.length; i++) {
+		p = doctypes[i].split('=');
+
+		if (p.length > 1)
+			addSelectValue(f, 'doctypes', p[0], p[1]);
+	}
+
+	// Setup fonts select box
+	fonts = tinyMCE.getParam("fullpage_fonts", defaultFontNames).split(';');
+	for (i=0; i<fonts.length; i++) {
+		p = fonts[i].split('=');
+
+		if (p.length > 1)
+			addSelectValue(f, 'fontface', p[0], p[1]);
+	}
+
+	// Setup fontsize select box
+	fonts = tinyMCE.getParam("fullpage_fontsizes", defaultFontSizes).split(',');
+	for (i=0; i<fonts.length; i++)
+		addSelectValue(f, 'fontsize', fonts[i], fonts[i]);
+
+	// Setup mediatype select boxs
+	mediaTypes = tinyMCE.getParam("fullpage_media_types", defaultMediaTypes).split(',');
+	for (i=0; i<mediaTypes.length; i++) {
+		p = mediaTypes[i].split('=');
+
+		if (p.length > 1) {
+			addSelectValue(f, 'element_style_media', p[0], p[1]);
+			addSelectValue(f, 'element_link_media', p[0], p[1]);
+		}
+	}
+
+	// Setup encodings select box
+	encodings = tinyMCE.getParam("fullpage_encodings", defaultEncodings).split(',');
+	for (i=0; i<encodings.length; i++) {
+		p = encodings[i].split('=');
+
+		if (p.length > 1) {
+			addSelectValue(f, 'docencoding', p[0], p[1]);
+			addSelectValue(f, 'element_script_charset', p[0], p[1]);
+			addSelectValue(f, 'element_link_charset', p[0], p[1]);
+		}
+	}
+
+	document.getElementById('bgcolor_pickcontainer').innerHTML = getColorPickerHTML('bgcolor_pick','bgcolor');
+	document.getElementById('link_color_pickcontainer').innerHTML = getColorPickerHTML('link_color_pick','link_color');
+	//document.getElementById('hover_color_pickcontainer').innerHTML = getColorPickerHTML('hover_color_pick','hover_color');
+	document.getElementById('visited_color_pickcontainer').innerHTML = getColorPickerHTML('visited_color_pick','visited_color');
+	document.getElementById('active_color_pickcontainer').innerHTML = getColorPickerHTML('active_color_pick','active_color');
+	document.getElementById('textcolor_pickcontainer').innerHTML = getColorPickerHTML('textcolor_pick','textcolor');
+	document.getElementById('stylesheet_browsercontainer').innerHTML = getBrowserHTML('stylesheetbrowser','stylesheet','file','fullpage');
+	document.getElementById('link_href_pickcontainer').innerHTML = getBrowserHTML('link_href_browser','element_link_href','file','fullpage');
+	document.getElementById('script_src_pickcontainer').innerHTML = getBrowserHTML('script_src_browser','element_script_src','file','fullpage');
+	document.getElementById('bgimage_pickcontainer').innerHTML = getBrowserHTML('bgimage_browser','bgimage','image','fullpage');
+
+	// Resize some elements
+	if (isVisible('stylesheetbrowser'))
+		document.getElementById('stylesheet').style.width = '220px';
+
+	if (isVisible('link_href_browser'))
+		document.getElementById('element_link_href').style.width = '230px';
+
+	if (isVisible('bgimage_browser'))
+		document.getElementById('bgimage').style.width = '210px';
+
+	// Create iframe
+	var iframe = document.createElement('iframe');
+
+	iframe.id = 'tempFrame';
+	iframe.style.display = 'none';
+	iframe.src = tinyMCE.baseURL + "/plugins/fullpage/blank.htm";
+
+	document.body.appendChild(iframe);
+
+	tinyMCEPopup.resizeToInnerSize();
+}
+
+function setupIframe(doc) {
+	var inst = tinyMCE.getInstanceById(tinyMCE.getWindowArg('editor_id'));
+	var hc = inst.fullpageTopContent;
+	var f = document.forms[0];
+	var xmlVer, xmlEnc, docType;
+	var nodes, i, x, name, value, tmp, l;
+
+	// Keep it from not loading/executing stuff
+	hc = hc.replace(/<script>/gi, '<script type="text/javascript">');
+	hc = hc.replace(/\ssrc=/gi, " mce_src=");
+	hc = hc.replace(/\shref=/gi, " mce_href=");
+	hc = hc.replace(/\stype=/gi, " mce_type=");
+	hc = hc.replace(/<script/gi, '<script type="text/unknown" ');
+
+	// Add end to make it DOM parseable
+	hc += '</body></html>';
+
+	topDoc = doc;
+	doc.open();
+	doc.write(hc);
+	doc.close();
+
+	// ------- Setup options for genral tab
+
+	// Parse xml and doctype
+	xmlVer = getReItem(/<\?\s*?xml.*?version\s*?=\s*?"(.*?)".*?\?>/gi, hc, 1);
+	xmlEnc = getReItem(/<\?\s*?xml.*?encoding\s*?=\s*?"(.*?)".*?\?>/gi, hc, 1);
+	docType = getReItem(/<\!DOCTYPE.*?>/gi, hc, 0);
+	f.langcode.value = getReItem(/lang="(.*?)"/gi, hc, 1);
+
+	// Get title
+	f.metatitle.value = tinyMCE.entityDecode(getReItem(/<title>(.*?)<\/title>/gi, hc, 1));
+
+	// Check for meta encoding
+	nodes = doc.getElementsByTagName("meta");
+	for (i=0; i<nodes.length; i++) {
+		name = tinyMCE.getAttrib(nodes[i], 'name');
+		value = tinyMCE.getAttrib(nodes[i], 'content');
+		httpEquiv = tinyMCE.getAttrib(nodes[i], 'httpEquiv');
+
+		switch (name.toLowerCase()) {
+			case "keywords":
+				f.metakeywords.value = value;
+				break;
+
+			case "description":
+				f.metadescription.value = value;
+				break;
+
+			case "author":
+				f.metaauthor.value = value;
+				break;
+
+			case "copyright":
+				f.metacopyright.value = value;
+				break;
+
+			case "robots":
+				selectByValue(f, 'metarobots', value, true, true);
+				break;
+		}
+
+		switch (httpEquiv.toLowerCase()) {
+			case "content-type":
+				tmp = getReItem(/charset\s*=\s*(.*)\s*/gi, value, 1);
+
+				// Override XML encoding
+				if (tmp != "")
+					xmlEnc = tmp;
+
+				break;
+		}
+	}
+
+	selectByValue(f, 'doctypes', docType, true, true);
+	selectByValue(f, 'docencoding', xmlEnc, true, true);
+	selectByValue(f, 'langdir', tinyMCE.getAttrib(doc.body, 'dir'), true, true);
+
+	if (xmlVer != '')
+		f.xml_pi.checked = true;
+
+	// ------- Setup options for appearance tab
+
+	// Get primary stylesheet
+	nodes = doc.getElementsByTagName("link");
+	for (i=0; i<nodes.length; i++) {
+		l = nodes[i];
+		tmp = tinyMCE.getAttrib(l, 'media');
+
+		if (tinyMCE.getAttrib(l, 'mce_type') == "text/css" && (tmp == "" || tmp == "screen" || tmp == "all") && tinyMCE.getAttrib(l, 'rel') == "stylesheet") {
+			f.stylesheet.value = tinyMCE.getAttrib(l, 'mce_href');
+			break;
+		}
+	}
+
+	// Get from style elements
+	nodes = doc.getElementsByTagName("style");
+	for (i=0; i<nodes.length; i++) {
+		tmp = parseStyleElement(nodes[i]);
+
+		for (x=0; x<tmp.length; x++) {
+		//	if (tmp[x].rule.indexOf('a:hover') != -1 && tmp[x].data['color'])
+		//		f.hover_color.value = tmp[x].data['color'];
+
+			if (tmp[x].rule.indexOf('a:visited') != -1 && tmp[x].data['color'])
+				f.visited_color.value = tmp[x].data['color'];
+
+			if (tmp[x].rule.indexOf('a:link') != -1 && tmp[x].data['color'])
+				f.link_color.value = tmp[x].data['color'];
+
+			if (tmp[x].rule.indexOf('a:active') != -1 && tmp[x].data['color'])
+				f.active_color.value = tmp[x].data['color'];
+		}
+	}
+
+	// Get from body attribs
+
+/*	f.leftmargin.value = tinyMCE.getAttrib(doc.body, "leftmargin");
+	f.rightmargin.value = tinyMCE.getAttrib(doc.body, "rightmargin");
+	f.topmargin.value = tinyMCE.getAttrib(doc.body, "topmargin");
+	f.bottommargin.value = tinyMCE.getAttrib(doc.body, "bottommargin");*/
+	f.textcolor.value = convertRGBToHex(tinyMCE.getAttrib(doc.body, "text"));
+	f.active_color.value = convertRGBToHex(tinyMCE.getAttrib(doc.body, "alink"));
+	f.link_color.value = convertRGBToHex(tinyMCE.getAttrib(doc.body, "link"));
+	f.visited_color.value = convertRGBToHex(tinyMCE.getAttrib(doc.body, "vlink"));
+	f.bgcolor.value = convertRGBToHex(tinyMCE.getAttrib(doc.body, "bgcolor"));
+	f.bgimage.value = convertRGBToHex(tinyMCE.getAttrib(doc.body, "background"));
+
+	// Get from style info
+	var style = tinyMCE.parseStyle(tinyMCE.getAttrib(doc.body, 'style'));
+
+	if (style['font-family'])
+		selectByValue(f, 'fontface', style['font-family'], true, true);
+	else
+		selectByValue(f, 'fontface', tinyMCE.getParam("fullpage_default_fontface", ""), true, true);
+
+	if (style['font-size'])
+		selectByValue(f, 'fontsize', style['font-size'], true, true);
+	else
+		selectByValue(f, 'fontsize', tinyMCE.getParam("fullpage_default_fontsize", ""), true, true);
+
+	if (style['color'])
+		f.textcolor.value = convertRGBToHex(style['color']);
+
+	if (style['background-image'])
+		f.bgimage.value = style['background-image'].replace(new RegExp("url\\('?([^']*)'?\\)", 'gi'), "$1");
+
+	if (style['background-color'])
+		f.bgcolor.value = convertRGBToHex(style['background-color']);
+
+	if (style['margin']) {
+		tmp = style['margin'].replace(/[^0-9 ]/g, '');
+		tmp = tmp.split(/ +/);
+		f.topmargin.value = tmp.length > 0 ? tmp[0] : '';
+		f.rightmargin.value = tmp.length > 1 ? tmp[1] : tmp[0];
+		f.bottommargin.value = tmp.length > 2 ? tmp[2] : tmp[0];
+		f.leftmargin.value = tmp.length > 3 ? tmp[3] : tmp[0];
+	}
+
+	if (style['margin-left'])
+		f.leftmargin.value = style['margin-left'].replace(/[^0-9]/g, '');
+
+	if (style['margin-right'])
+		f.rightmargin.value = style['margin-right'].replace(/[^0-9]/g, '');
+
+	if (style['margin-top'])
+		f.topmargin.value = style['margin-top'].replace(/[^0-9]/g, '');
+
+	if (style['margin-bottom'])
+		f.bottommargin.value = style['margin-bottom'].replace(/[^0-9]/g, '');
+
+	f.style.value = tinyMCE.serializeStyle(style);
+
+	updateColor('textcolor_pick', 'textcolor');
+	updateColor('bgcolor_pick', 'bgcolor');
+	updateColor('visited_color_pick', 'visited_color');
+	updateColor('active_color_pick', 'active_color');
+	updateColor('link_color_pick', 'link_color');
+	//updateColor('hover_color_pick', 'hover_color');
+}
+
+function updateAction() {
+	var inst = tinyMCE.getInstanceById(tinyMCE.getWindowArg('editor_id'));
+	var f = document.forms[0];
+	var nl, i, h, v, s, head, html, l, tmp, addlink = true;
+
+	head = topDoc.getElementsByTagName('head')[0];
+
+	// Fix scripts without a type
+	nl = topDoc.getElementsByTagName('script');
+	for (i=0; i<nl.length; i++) {
+		if (tinyMCE.getAttrib(nl[i], 'mce_type') == '')
+			nl[i].setAttribute('mce_type', 'text/javascript');
+	}
+
+	// Get primary stylesheet
+	nl = topDoc.getElementsByTagName("link");
+	for (i=0; i<nl.length; i++) {
+		l = nl[i];
+
+		tmp = tinyMCE.getAttrib(l, 'media');
+
+		if (tinyMCE.getAttrib(l, 'mce_type') == "text/css" && (tmp == "" || tmp == "screen" || tmp == "all") && tinyMCE.getAttrib(l, 'rel') == "stylesheet") {
+			addlink = false;
+
+			if (f.stylesheet.value == '')
+				l.parentNode.removeChild(l);
+			else
+				l.setAttribute('mce_href', f.stylesheet.value);
+
+			break;
+		}
+	}
+
+	// Add new link
+	if (f.stylesheet.value != '') {
+		l = topDoc.createElement('link');
+
+		l.setAttribute('mce_type', 'text/css');
+		l.setAttribute('mce_href', f.stylesheet.value);
+		l.setAttribute('rel', 'stylesheet');
+
+		head.appendChild(l);
+	}
+
+	setMeta(head, 'keywords', f.metakeywords.value);
+	setMeta(head, 'description', f.metadescription.value);
+	setMeta(head, 'author', f.metaauthor.value);
+	setMeta(head, 'copyright', f.metacopyright.value);
+	setMeta(head, 'robots', getSelectValue(f, 'metarobots'));
+	setMeta(head, 'Content-Type', getSelectValue(f, 'docencoding'));
+
+	topDoc.body.dir = getSelectValue(f, 'langdir');
+	topDoc.body.style.cssText = f.style.value;
+
+	topDoc.body.setAttribute('vLink', f.visited_color.value);
+	topDoc.body.setAttribute('link', f.link_color.value);
+	topDoc.body.setAttribute('text', f.textcolor.value);
+	topDoc.body.setAttribute('aLink', f.active_color.value);
+
+	topDoc.body.style.fontFamily = getSelectValue(f, 'fontface');
+	topDoc.body.style.fontSize = getSelectValue(f, 'fontsize');
+	topDoc.body.style.backgroundColor = f.bgcolor.value;
+
+	if (f.leftmargin.value != '')
+		topDoc.body.style.marginLeft = f.leftmargin.value + 'px';
+
+	if (f.rightmargin.value != '')
+		topDoc.body.style.marginRight = f.rightmargin.value + 'px';
+
+	if (f.bottommargin.value != '')
+		topDoc.body.style.marginBottom = f.bottommargin.value + 'px';
+
+	if (f.topmargin.value != '')
+		topDoc.body.style.marginTop = f.topmargin.value + 'px';
+
+	html = topDoc.getElementsByTagName('html')[0];
+	html.setAttribute('lang', f.langcode.value);
+	html.setAttribute('xml:lang', f.langcode.value);
+
+	if (f.bgimage.value != '')
+		topDoc.body.style.backgroundImage = "url('" + f.bgimage.value + "')";
+	else
+		topDoc.body.style.backgroundImage = '';
+
+	inst.cleanup.addRuleStr('-title,meta[http-equiv|name|content],base[href|target],link[href|rel|type|title|media],style[type],script[type|language|src],html[lang|xml:lang|xmlns],body[style|dir|vlink|link|text|alink],head');
+
+	h = inst.cleanup.serializeNodeAsHTML(topDoc.documentElement);
+
+	h = h.substring(0, h.lastIndexOf('</body>'));
+
+	if (h.indexOf('<title>') == -1)
+		h = h.replace(/<head.*?>/, '$&\n' + '<title>' + inst.cleanup.xmlEncode(f.metatitle.value) + '</title>');
+	else
+		h = h.replace(/<title>(.*?)<\/title>/, '<title>' + inst.cleanup.xmlEncode(f.metatitle.value) + '</title>');
+
+	if ((v = getSelectValue(f, 'doctypes')) != '')
+		h = v + '\n' + h;
+
+	if (f.xml_pi.checked) {
+		s = '<?xml version="1.0"';
+
+		if ((v = getSelectValue(f, 'docencoding')) != '')
+			s += ' encoding="' + v + '"';
+
+		s += '?>\n';
+		h = s + h;
+	}
+
+	inst.fullpageTopContent = h;
+
+	tinyMCEPopup.execCommand('mceFullPageUpdate', false, '');
+	tinyMCEPopup.close();
+}
+
+function setMeta(he, k, v) {
+	var nl, i, m;
+
+	nl = he.getElementsByTagName('meta');
+	for (i=0; i<nl.length; i++) {
+		if (k == 'Content-Type' && tinyMCE.getAttrib(nl[i], 'http-equiv') == k) {
+			if (v == '')
+				nl[i].parentNode.removeChild(nl[i]);
+			else
+				nl[i].setAttribute('content', "text/html; charset=" + v);
+
+			return;
+		}
+
+		if (tinyMCE.getAttrib(nl[i], 'name') == k) {
+			if (v == '')
+				nl[i].parentNode.removeChild(nl[i]);
+			else
+				nl[i].setAttribute('content', v);
+			return;
+		}
+	}
+
+	if (v == '')
+		return;
+
+	m = topDoc.createElement('meta');
+
+	if (k == 'Content-Type')
+		m.httpEquiv = k;
+	else
+		m.setAttribute('name', k);
+
+	m.setAttribute('content', v);
+	he.appendChild(m);
+}
+
+function parseStyleElement(e) {
+	var v = e.innerHTML;
+	var p, i, r;
+
+	v = v.replace(/<!--/gi, '');
+	v = v.replace(/-->/gi, '');
+	v = v.replace(/[\n\r]/gi, '');
+	v = v.replace(/\s+/gi, ' ');
+
+	r = new Array();
+	p = v.split(/{|}/);
+
+	for (i=0; i<p.length; i+=2) {
+		if (p[i] != "")
+			r[r.length] = {rule : tinyMCE.trim(p[i]), data : tinyMCE.parseStyle(p[i+1])};
+	}
+
+	return r;
+}
+
+function serializeStyleElement(d) {
+	var i, s, st;
+
+	s = '<!--\n';
+
+	for (i=0; i<d.length; i++) {
+		s += d[i].rule + ' {\n';
+
+		st = tinyMCE.serializeStyle(d[i].data);
+
+		if (st != '')
+			st += ';';
+
+		s += st.replace(/;/g, ';\n');
+		s += '}\n';
+
+		if (i != d.length - 1)
+			s += '\n';
+	}
+
+	s += '\n-->';
+
+	return s;
+}
+
+function getReItem(r, s, i) {
+	var c = r.exec(s);
+
+	if (c && c.length > i)
+		return c[i];
+
+	return '';
+}
+
+function changedStyleField(field) {
+	//alert(field.id);
+}
+
+function showAddMenu() {
+	var re = document.getElementById('addbutton');
+
+	addMenuLayer.moveRelativeTo(re, 'tr');
+	if (addMenuLayer.isMSIE)
+		addMenuLayer.moveBy(2, 0);
+
+	addMenuLayer.show();
+	addMenuLayer.setAutoHide(true, hideAddMenu);
+	addMenuLayer.addCSSClass(re, 'selected');
+}
+
+function hideAddMenu(l, e, mx, my) {
+	var re = document.getElementById('addbutton');
+	addMenuLayer.removeCSSClass(re, 'selected');
+}
+
+function addHeadElm(type) {
+	var le = document.getElementById('headlist');
+	var re = document.getElementById('addbutton');
+	var te = document.getElementById(type + '_element');
+
+	if (lastElementType)
+		lastElementType.style.display = 'none';
+
+	te.style.display = 'block';
+
+	lastElementType = te;
+
+	addMenuLayer.hide();
+	addMenuLayer.removeCSSClass(re, 'selected');
+
+	document.getElementById(type + '_updateelement').value = tinyMCE.getLang('lang_insert', 'Insert', true);
+
+	le.size = 10;
+}
+
+function updateHeadElm(item) {
+	var type = item.substring(0, item.indexOf('_'));
+	var le = document.getElementById('headlist');
+	var re = document.getElementById('addbutton');
+	var te = document.getElementById(type + '_element');
+
+	if (lastElementType)
+		lastElementType.style.display = 'none';
+
+	te.style.display = 'block';
+
+	lastElementType = te;
+
+	addMenuLayer.hide();
+	addMenuLayer.removeCSSClass(re, 'selected');
+
+	document.getElementById(type + '_updateelement').value = tinyMCE.getLang('lang_update', 'Update', true);
+
+	le.size = 10;
+}
+
+function cancelElementUpdate() {
+	var le = document.getElementById('headlist');
+
+	if (lastElementType)
+		lastElementType.style.display = 'none';
+
+	le.size = 26;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/fullpage/langs/en.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,92 @@
+// UK lang variables
+
+tinyMCE.addToLang('fullpage',{
+	title : 'Document properties',
+	desc : 'Document properties',
+	meta_tab : 'General',
+	appearance_tab : 'Appearance',
+	advanced_tab : 'Advanced',
+	meta_props : 'Meta information',
+	langprops : 'Language and encoding',
+	meta_title : 'Title',
+	meta_keywords : 'Keywords',
+	meta_description : 'Description',
+	meta_robots : 'Robots',
+	doctypes : 'Doctype',
+	langcode : 'Language code',
+	langdir : 'Language direction',
+	ltr : 'Left to right',
+	rtl : 'Right to left',
+	xml_pi : 'XML declaration',
+	encoding : 'Character encoding',
+	appearance_bgprops : 'Background properties',
+	appearance_marginprops : 'Body margins',
+	appearance_linkprops : 'Link colors',
+	appearance_textprops : 'Text properties',
+	bgcolor : 'Background color',
+	bgimage : 'Background image',
+	left_margin : 'Left margin',
+	right_margin : 'Right margin',
+	top_margin : 'Top margin',
+	bottom_margin : 'Bottom margin',
+	text_color : 'Text color',
+	font_size : 'Font size',
+	font_face : 'Font face',
+	link_color : 'Link color',
+	hover_color : 'Hover color',
+	visited_color : 'Visited color',
+	active_color : 'Active color',
+	textcolor : 'Color',
+	fontsize : 'Font size',
+	fontface : 'Font family',
+	meta_index_follow : 'Index and follow the links',
+	meta_index_nofollow : 'Index and don\'t follow the links',
+	meta_noindex_follow : 'Do not index but follow the links',
+	meta_noindex_nofollow : 'Do not index and don\'t follow the links',
+	appearance_style : 'Stylesheet and style properties',
+	stylesheet : 'Stylesheet',
+	style : 'Style',
+	author : 'Author',
+	copyright : 'Copyright',
+	add : 'Add new element',
+	remove : 'Remove selected element',
+	moveup : 'Move selected element up',
+	movedown : 'Move selected element down',
+	head_elements : 'Head elements',
+	info : 'Information',
+	info_text : '',
+	add_title : 'Title element',
+	add_meta : 'Meta element',
+	add_script : 'Script element',
+	add_style : 'Style element',
+	add_link : 'Link element',
+	add_base : 'Base element',
+	add_comment : 'Comment node',
+	title_element : 'Title element',
+	script_element : 'Script element',
+	style_element : 'Style element',
+	base_element : 'Base element',
+	link_element : 'Link element',
+	meta_element : 'Meta element',
+	comment_element : 'Comment',
+	src : 'Src',
+	language : 'Language',
+	href : 'Href',
+	target : 'Target',
+	rel : 'Rel',
+	type : 'Type',
+	charset : 'Charset',
+	defer : 'Defer',
+	media : 'Media',
+	properties : 'Properties',
+	name : 'Name',
+	value : 'Value',
+	content : 'Content',
+	rel : 'Rel',
+	rev : 'Rev',
+	hreflang : 'Href lang',
+	general_props : 'General',
+	advanced_props : 'Advanced',
+	delta_width : 0,
+	delta_height : 0
+});
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/fullscreen/css/page.css	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,21 @@
+/* This class restores all CSS properties to that absolute positioning of fullscreen mode is correct */
+.mceFullscreenPos {
+	display: block !important;
+	position: static !important;
+	left: 0 !important;
+	top: 0 !important;
+	bottom: auto !important;
+	right: auto !important;
+	width: auto !important;
+	height: auto !important;
+	margin: 0 !important;
+	padding: 0 !important;
+	border: 0 !important;
+	overflow: visible;
+	z-index: 1 !important;
+	clear: both;
+}
+
+body.mceFullscreen {
+	overflow: hidden !important;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/fullscreen/editor_plugin.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+tinyMCE.importPluginLanguagePack('fullscreen');var TinyMCE_FullScreenPlugin={getInfo:function(){return{longname:'Fullscreen',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/fullscreen',version:tinyMCE.majorVersion+"."+tinyMCE.minorVersion}},initInstance:function(inst){if(!tinyMCE.settings['fullscreen_skip_plugin_css'])tinyMCE.importCSS(inst.getContainerWin().document,tinyMCE.baseURL+"/plugins/fullscreen/css/page.css")},getControlHTML:function(cn){switch(cn){case"fullscreen":return tinyMCE.getButtonHTML(cn,'lang_fullscreen_desc','{$pluginurl}/images/fullscreen.gif','mceFullScreen')}return""},execCommand:function(editor_id,element,command,user_interface,value){var inst;switch(command){case"mceFullScreen":inst=tinyMCE.getInstanceById(editor_id);if(tinyMCE.getParam('fullscreen_new_window'))this._toggleFullscreenWin(inst);else this._toggleFullscreen(inst);return true}return false},_toggleFullscreenWin:function(inst){if(tinyMCE.getParam('fullscreen_is_enabled')){window.opener.tinyMCE.execInstanceCommand(tinyMCE.getParam('fullscreen_editor_id'),'mceSetContent',false,tinyMCE.getContent(inst.editorId));top.close()}else{tinyMCE.setWindowArg('editor_id',inst.editorId);var win=window.open(tinyMCE.baseURL+"/plugins/fullscreen/fullscreen.htm","mceFullScreenPopup","fullscreen=yes,menubar=no,toolbar=no,scrollbars=no,resizable=yes,left=0,top=0,width="+screen.availWidth+",height="+screen.availHeight);try{win.resizeTo(screen.availWidth,screen.availHeight)}catch(e){}}},_toggleFullscreen:function(inst){var ds=inst.getData('fullscreen'),editorContainer,tableElm,iframe,vp,cw,cd,re,w,h,si,blo,delta=0,cell,row,fcml,bcml;cw=inst.getContainerWin();cd=cw.document;editorContainer=cd.getElementById(inst.editorId+'_parent');tableElm=editorContainer.firstChild;iframe=inst.iframeElement;re=cd.getElementById(inst.editorId+'_resize');blo=document.getElementById('mce_fullscreen_blocker');fcm=new TinyMCE_Layer(inst.editorId+'_fcMenu');fcml=new TinyMCE_Layer(inst.editorId+'_fcMenu');bcml=new TinyMCE_Layer(inst.editorId+'_bcMenu');if(fcml.exists()&&fcml.isVisible()){tinyMCE.switchClass(inst.editorId+'_forecolor','mceMenuButton');fcml.hide()}if(bcml.exists()&&bcml.isVisible()){tinyMCE.switchClass(inst.editorId+'_backcolor','mceMenuButton');bcml.hide()}if(!ds.enabled){if(inst.toolbarElement){delta+=inst.toolbarElement.offsetHeight;cell=tableElm.tBodies[0].insertRow(0).insertCell(-1);cell.className='mceToolbarTop';cell.nowrap=true;ds.oldToolbarParent=inst.toolbarElement.parentNode;ds.toolbarHolder=document.createTextNode('...');cell.appendChild(ds.oldToolbarParent.replaceChild(ds.toolbarHolder,inst.toolbarElement))}ds.parents=[];vp=tinyMCE.getViewPort(cw);ds.scrollX=vp.left;ds.scrollY=vp.top;if(!tinyMCE.isOpera)tinyMCE.addCSSClass(cd.body,'mceFullscreen');tinyMCE.getParentNode(tableElm.parentNode,function(n){if(n.nodeName=='BODY')return true;if(n.nodeType==1)tinyMCE.addCSSClass(n,'mceFullscreenPos');return false});if(re)re.style.display='none';vp=tinyMCE.getViewPort(cw);ds.oldWidth=iframe.style.width?iframe.style.width:iframe.offsetWidth;ds.oldHeight=iframe.style.height?iframe.style.height:iframe.offsetHeight;ds.oldTWidth=tableElm.style.width?tableElm.style.width:tableElm.offsetWidth;ds.oldTHeight=tableElm.style.height?tableElm.style.height:tableElm.offsetHeight;if(ds.oldWidth&&ds.oldWidth.indexOf)ds.oldTWidth=ds.oldWidth.indexOf('%')!=-1?ds.oldWidth:ds.oldTWidth;if(!blo&&tinyMCE.isRealIE){blo=tinyMCE.createTag(document,'iframe',{id:'mce_fullscreen_blocker',src:'about:blank',frameBorder:0,width:vp.width,height:vp.height,style:'display: block; position: absolute; left: 0; top: 0; z-index: 999; margin: 0; padding: 0;'});document.body.appendChild(blo)}tableElm.style.position='absolute';tableElm.style.zIndex=1000;tableElm.style.left=tableElm.style.top='0';tableElm.style.width=vp.width+'px';tableElm.style.height=vp.height+'px';if(tinyMCE.isRealIE){iframe.style.width=vp.width+'px';iframe.style.height=vp.height+'px';w=iframe.parentNode.clientWidth-(tableElm.offsetWidth-vp.width);h=iframe.parentNode.clientHeight-(tableElm.offsetHeight-vp.height)}else{w=iframe.parentNode.clientWidth;h=iframe.parentNode.clientHeight}iframe.style.width=w+"px";iframe.style.height=(h+delta)+"px";tinyMCE.switchClass(inst.editorId+'_fullscreen','mceButtonSelected');ds.enabled=true;inst.useCSS=false}else{if(inst.toolbarElement){row=inst.toolbarElement.parentNode.parentNode;row.parentNode.removeChild(row);ds.oldToolbarParent.replaceChild(inst.toolbarElement,ds.toolbarHolder);ds.oldToolbarParent=null;ds.toolbarHolder=null}if(blo)blo.parentNode.removeChild(blo);si=0;tinyMCE.getParentNode(tableElm.parentNode,function(n){if(n.nodeName=='BODY')return true;if(n.nodeType==1)tinyMCE.removeCSSClass(n,'mceFullscreenPos')});if(re&&tinyMCE.getParam("theme_advanced_resizing",false))re.style.display='block';tableElm.style.position='static';tableElm.style.zIndex='';tableElm.style.width='';tableElm.style.height='';tableElm.style.width=ds.oldTWidth?ds.oldTWidth:'';tableElm.style.height=ds.oldTHeight?ds.oldTHeight:'';iframe.style.width=ds.oldWidth?ds.oldWidth:'';iframe.style.height=ds.oldHeight?ds.oldHeight:'';tinyMCE.switchClass(inst.editorId+'_fullscreen','mceButtonNormal');ds.enabled=false;tinyMCE.removeCSSClass(cd.body,'mceFullscreen');cw.scrollTo(ds.scrollX,ds.scrollY);inst.useCSS=false}},handleNodeChange:function(editor_id,node,undo_index,undo_levels,visual_aid,any_selection){if(tinyMCE.getParam('fullscreen_is_enabled'))tinyMCE.switchClass(editor_id+'_fullscreen','mceButtonSelected');return true}};tinyMCE.addPlugin("fullscreen",TinyMCE_FullScreenPlugin);
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/fullscreen/editor_plugin_src.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,230 @@
+/**
+ * $Id: editor_plugin_src.js 201 2007-02-12 15:56:56Z spocke $
+ *
+ * @author Moxiecode
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+/* Import plugin specific language pack */
+tinyMCE.importPluginLanguagePack('fullscreen');
+
+var TinyMCE_FullScreenPlugin = {
+	getInfo : function() {
+		return {
+			longname : 'Fullscreen',
+			author : 'Moxiecode Systems AB',
+			authorurl : 'http://tinymce.moxiecode.com',
+			infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/fullscreen',
+			version : tinyMCE.majorVersion + "." + tinyMCE.minorVersion
+		};
+	},
+
+	initInstance : function(inst) {
+		if (!tinyMCE.settings['fullscreen_skip_plugin_css'])
+			tinyMCE.importCSS(inst.getContainerWin().document, tinyMCE.baseURL + "/plugins/fullscreen/css/page.css");
+	},
+
+	getControlHTML : function(cn) {
+		switch (cn) {
+			case "fullscreen":
+				return tinyMCE.getButtonHTML(cn, 'lang_fullscreen_desc', '{$pluginurl}/images/fullscreen.gif', 'mceFullScreen');
+		}
+
+		return "";
+	},
+
+	execCommand : function(editor_id, element, command, user_interface, value) {
+		var inst;
+
+		// Handle commands
+		switch (command) {
+			case "mceFullScreen":
+				inst = tinyMCE.getInstanceById(editor_id);
+
+				if (tinyMCE.getParam('fullscreen_new_window'))
+					this._toggleFullscreenWin(inst);
+				else
+					this._toggleFullscreen(inst);
+
+				return true;
+		}
+
+		// Pass to next handler in chain
+		return false;
+	},
+
+	_toggleFullscreenWin : function(inst) {
+		if (tinyMCE.getParam('fullscreen_is_enabled')) {
+			// In fullscreen mode
+			window.opener.tinyMCE.execInstanceCommand(tinyMCE.getParam('fullscreen_editor_id'), 'mceSetContent', false, tinyMCE.getContent(inst.editorId));
+			top.close();
+		} else {
+			tinyMCE.setWindowArg('editor_id', inst.editorId);
+
+			var win = window.open(tinyMCE.baseURL + "/plugins/fullscreen/fullscreen.htm", "mceFullScreenPopup", "fullscreen=yes,menubar=no,toolbar=no,scrollbars=no,resizable=yes,left=0,top=0,width=" + screen.availWidth + ",height=" + screen.availHeight);
+			try { win.resizeTo(screen.availWidth, screen.availHeight); } catch (e) {}
+		}
+	},
+
+	_toggleFullscreen : function(inst) {
+		var ds = inst.getData('fullscreen'), editorContainer, tableElm, iframe, vp, cw, cd, re, w, h, si, blo, delta = 0, cell, row, fcml, bcml;
+
+		cw = inst.getContainerWin();
+		cd = cw.document;
+		editorContainer = cd.getElementById(inst.editorId + '_parent');
+		tableElm = editorContainer.firstChild;
+		iframe = inst.iframeElement;
+		re = cd.getElementById(inst.editorId + '_resize');
+		blo = document.getElementById('mce_fullscreen_blocker');
+		fcm = new TinyMCE_Layer(inst.editorId + '_fcMenu');
+		fcml = new TinyMCE_Layer(inst.editorId + '_fcMenu');
+		bcml = new TinyMCE_Layer(inst.editorId + '_bcMenu');
+
+		if (fcml.exists() && fcml.isVisible()) {
+			tinyMCE.switchClass(inst.editorId + '_forecolor', 'mceMenuButton');
+			fcml.hide();
+		}
+
+		if (bcml.exists() && bcml.isVisible()) {
+			tinyMCE.switchClass(inst.editorId + '_backcolor', 'mceMenuButton');
+			bcml.hide();
+		}
+
+		if (!ds.enabled) {
+			// Handle External Toolbar
+			if (inst.toolbarElement) {
+				delta += inst.toolbarElement.offsetHeight;
+
+				cell = tableElm.tBodies[0].insertRow(0).insertCell(-1);
+				cell.className = 'mceToolbarTop';
+				cell.nowrap = true;
+
+				ds.oldToolbarParent = inst.toolbarElement.parentNode;
+				ds.toolbarHolder = document.createTextNode('...');
+
+				cell.appendChild(ds.oldToolbarParent.replaceChild(ds.toolbarHolder, inst.toolbarElement));
+			}
+
+			ds.parents = [];
+
+			vp = tinyMCE.getViewPort(cw);
+			ds.scrollX = vp.left;
+			ds.scrollY = vp.top;
+
+			// Opera has a bug restoring scrollbars
+			if (!tinyMCE.isOpera)
+				tinyMCE.addCSSClass(cd.body, 'mceFullscreen');
+
+			tinyMCE.getParentNode(tableElm.parentNode, function (n) {
+				if (n.nodeName == 'BODY')
+					return true;
+
+				if (n.nodeType == 1)
+					tinyMCE.addCSSClass(n, 'mceFullscreenPos');
+
+				return false;
+			});
+
+			if (re)
+				re.style.display = 'none';
+
+			vp = tinyMCE.getViewPort(cw);
+
+			ds.oldWidth = iframe.style.width ? iframe.style.width : iframe.offsetWidth;
+			ds.oldHeight = iframe.style.height ? iframe.style.height : iframe.offsetHeight;
+			ds.oldTWidth = tableElm.style.width ? tableElm.style.width : tableElm.offsetWidth;
+			ds.oldTHeight = tableElm.style.height ? tableElm.style.height : tableElm.offsetHeight;
+
+			// Handle % width
+			if (ds.oldWidth && ds.oldWidth.indexOf)
+				ds.oldTWidth = ds.oldWidth.indexOf('%') != -1 ? ds.oldWidth : ds.oldTWidth;
+
+			if (!blo && tinyMCE.isRealIE) {
+				blo = tinyMCE.createTag(document, 'iframe', {id : 'mce_fullscreen_blocker', src : 'about:blank', frameBorder : 0, width : vp.width, height : vp.height, style : 'display: block; position: absolute; left: 0; top: 0; z-index: 999; margin: 0; padding: 0;'});
+				document.body.appendChild(blo);
+			}
+
+			tableElm.style.position = 'absolute';
+			tableElm.style.zIndex = 1000;
+			tableElm.style.left = tableElm.style.top = '0';
+
+			tableElm.style.width = vp.width + 'px';
+			tableElm.style.height = vp.height + 'px';
+
+			if (tinyMCE.isRealIE) {
+				iframe.style.width = vp.width + 'px';
+				iframe.style.height = vp.height + 'px';
+
+				// Calc new width/height based on overflow
+				w = iframe.parentNode.clientWidth - (tableElm.offsetWidth - vp.width);
+				h = iframe.parentNode.clientHeight - (tableElm.offsetHeight - vp.height);
+			} else {
+				w = iframe.parentNode.clientWidth;
+				h = iframe.parentNode.clientHeight;
+			}
+
+			iframe.style.width = w + "px";
+			iframe.style.height = (h+delta) + "px";
+
+			tinyMCE.switchClass(inst.editorId + '_fullscreen', 'mceButtonSelected');
+			ds.enabled = true;
+
+			inst.useCSS = false;
+		} else {
+			// Handle External Toolbar
+			if (inst.toolbarElement) {
+				row = inst.toolbarElement.parentNode.parentNode;
+
+				row.parentNode.removeChild(row);
+
+				ds.oldToolbarParent.replaceChild(inst.toolbarElement, ds.toolbarHolder);
+
+				ds.oldToolbarParent = null;
+				ds.toolbarHolder = null;
+			}
+
+			if (blo)
+				blo.parentNode.removeChild(blo);
+
+			si = 0;
+			tinyMCE.getParentNode(tableElm.parentNode, function (n) {
+				if (n.nodeName == 'BODY')
+					return true;
+
+				if (n.nodeType == 1)
+					tinyMCE.removeCSSClass(n, 'mceFullscreenPos');
+			});
+
+			if (re && tinyMCE.getParam("theme_advanced_resizing", false))
+				re.style.display = 'block';
+
+			tableElm.style.position = 'static';
+			tableElm.style.zIndex = '';
+			tableElm.style.width = '';
+			tableElm.style.height = '';
+
+			tableElm.style.width = ds.oldTWidth ? ds.oldTWidth : '';
+			tableElm.style.height = ds.oldTHeight ? ds.oldTHeight : '';
+
+			iframe.style.width = ds.oldWidth ? ds.oldWidth : '';
+			iframe.style.height = ds.oldHeight ? ds.oldHeight : '';
+
+			tinyMCE.switchClass(inst.editorId + '_fullscreen', 'mceButtonNormal');
+			ds.enabled = false;
+
+			tinyMCE.removeCSSClass(cd.body, 'mceFullscreen');
+			cw.scrollTo(ds.scrollX, ds.scrollY);
+
+			inst.useCSS = false;
+		}
+	},
+
+	handleNodeChange : function(editor_id, node, undo_index, undo_levels, visual_aid, any_selection) {
+		if (tinyMCE.getParam('fullscreen_is_enabled'))
+			tinyMCE.switchClass(editor_id + '_fullscreen', 'mceButtonSelected');
+
+		return true;
+	}
+};
+
+tinyMCE.addPlugin("fullscreen", TinyMCE_FullScreenPlugin);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/fullscreen/fullscreen.htm	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,91 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>{$lang_fullscreen_title}</title>
+	<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+	<script language="javascript" type="text/javascript" src="../../tiny_mce.js"></script>
+	<script language="javascript" type="text/javascript">
+		function patchCallback(settings, key) {
+			if (settings[key])
+				settings[key] = "window.opener." + settings[key];
+		}
+
+		var settings = new Array();
+
+		// Clone array
+		for (var name in window.opener.tinyMCE.settings)
+			settings[name] = window.opener.tinyMCE.settings[name];
+
+		// Override options for fullscreen
+		for (var name in window.opener.tinyMCE.settings.fullscreen_settings)
+			settings[name] = window.opener.tinyMCE.settings.fullscreen_settings[name];
+
+		// Patch callbacks, make them point to window.opener
+		patchCallback(settings, 'urlconverter_callback');
+		patchCallback(settings, 'insertlink_callback');
+		patchCallback(settings, 'insertimage_callback');
+		patchCallback(settings, 'setupcontent_callback');
+		patchCallback(settings, 'save_callback');
+		patchCallback(settings, 'onchange_callback');
+		patchCallback(settings, 'init_instance_callback');
+		patchCallback(settings, 'file_browser_callback');
+		patchCallback(settings, 'cleanup_callback');
+		patchCallback(settings, 'execcommand_callback');
+		patchCallback(settings, 'oninit');
+
+		// Set options
+		settings['mode'] = 'exact';
+		settings['elements'] = 'fullscreenarea';
+		settings['ask'] = false;
+		settings['setupcontent_callback'] = 'setupContent';
+		settings['fullscreen_is_enabled'] = true;
+		settings['fullscreen_editor_id'] = window.opener.tinyMCE.getWindowArg("editor_id");
+		settings['theme_advanced_resizing'] = false;
+
+		// Init
+		tinyMCE.init(settings);
+		tinyMCE.documentBasePath = window.opener.tinyMCE.documentBasePath;
+
+		function setupContent(editor_id, body, doc) {
+			var inst = tinyMCE.getInstanceById(editor_id);
+			var content = window.opener.tinyMCE.getContent(tinyMCE.getParam('fullscreen_editor_id'));
+
+			// Setup title
+			var divElm = document.createElement("div");
+			divElm.innerHTML = tinyMCELang['lang_fullscreen_title'];
+			document.title = divElm.innerHTML;
+
+			// Get content
+			inst.execCommand('mceSetContent', false, content);
+		}
+
+		function unloadHandler(e) {
+			moveContent();
+		}
+
+		function moveContent() {
+			var doc = tinyMCE.isMSIE ? window.frames['mce_editor_0'].window.document : document.getElementById('mce_editor_0').contentDocument;
+			window.opener.tinyMCE.setInnerHTML(window.opener.tinyMCE.selectedInstance.getBody(), doc.body.innerHTML);
+		}
+
+		// Add onunload
+		tinyMCE.addEvent(window, "beforeunload", unloadHandler);
+
+		function doParentSubmit() {
+			moveContent();
+
+			if (window.opener.tinyMCE.selectedInstance.formElement.form)
+				window.opener.tinyMCE.selectedInstance.formElement.form.submit();
+
+			window.close();
+
+			return false;
+		}
+	</script>
+	<base target="_self" />
+</head>
+<body style="margin: 0; overflow: hidden; height: 100%" scrolling="no" scroll="no">
+<form onsubmit="doParentSubmit();" style="height: 100%">
+<textarea id="fullscreenarea" style="width: 100%; height: 100%"></textarea>
+</form>
+</body>
+</html>
Binary file includes/clientside/tinymce/plugins/fullscreen/images/fullscreen.gif has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/fullscreen/langs/en.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,5 @@
+// UK lang variables
+
+tinyMCE.addToLang('',{
+fullscreen_desc : 'Toggle fullscreen mode'
+});
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/fullscreen/readme.txt	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+Check the TinyMCE documentation for details on this plugin.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/iespell/editor_plugin.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+tinyMCE.importPluginLanguagePack('iespell');var TinyMCE_IESpellPlugin={getInfo:function(){return{longname:'IESpell (MSIE Only)',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/iespell',version:tinyMCE.majorVersion+"."+tinyMCE.minorVersion}},getControlHTML:function(cn){if(cn=="iespell"&&(tinyMCE.isMSIE&&!tinyMCE.isOpera))return tinyMCE.getButtonHTML(cn,'lang_iespell_desc','{$pluginurl}/images/iespell.gif','mceIESpell');return""},execCommand:function(editor_id,element,command,user_interface,value){if(command=="mceIESpell"){try{var ieSpell=new ActiveXObject("ieSpell.ieSpellExtension");ieSpell.CheckDocumentNode(tinyMCE.getInstanceById(editor_id).contentDocument.documentElement)}catch(e){if(e.number==-2146827859){if(confirm(tinyMCE.getLang("lang_iespell_download","",true)))window.open('http://www.iespell.com/download.php','ieSpellDownload','')}else alert("Error Loading ieSpell: Exception "+e.number)}return true}return false}};tinyMCE.addPlugin("iespell",TinyMCE_IESpellPlugin);
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/iespell/editor_plugin_src.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,58 @@
+/**
+ * $Id: editor_plugin_src.js 201 2007-02-12 15:56:56Z spocke $
+ *
+ * @author Moxiecode
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+/* Import plugin specific language pack */
+tinyMCE.importPluginLanguagePack('iespell');
+
+var TinyMCE_IESpellPlugin = {
+	getInfo : function() {
+		return {
+			longname : 'IESpell (MSIE Only)',
+			author : 'Moxiecode Systems AB',
+			authorurl : 'http://tinymce.moxiecode.com',
+			infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/iespell',
+			version : tinyMCE.majorVersion + "." + tinyMCE.minorVersion
+		};
+	},
+
+	/**
+	 * Returns the HTML contents of the iespell control.
+	 */
+	getControlHTML : function(cn) {
+		// Is it the iespell control and is the brower MSIE.
+		if (cn == "iespell" && (tinyMCE.isMSIE && !tinyMCE.isOpera))
+			return tinyMCE.getButtonHTML(cn, 'lang_iespell_desc', '{$pluginurl}/images/iespell.gif', 'mceIESpell');
+
+		return "";
+	},
+
+	/**
+	 * Executes the mceIESpell command.
+	 */
+	execCommand : function(editor_id, element, command, user_interface, value) {
+		// Handle ieSpellCommand
+		if (command == "mceIESpell") {
+			try {
+				var ieSpell = new ActiveXObject("ieSpell.ieSpellExtension");
+				ieSpell.CheckDocumentNode(tinyMCE.getInstanceById(editor_id).contentDocument.documentElement);
+			} catch (e) {
+				if (e.number == -2146827859) {
+					if (confirm(tinyMCE.getLang("lang_iespell_download", "", true)))
+						window.open('http://www.iespell.com/download.php', 'ieSpellDownload', '');
+				} else
+					alert("Error Loading ieSpell: Exception " + e.number);
+			}
+
+			return true;
+		}
+
+		// Pass to next handler in chain
+		return false;
+	}
+};
+
+tinyMCE.addPlugin("iespell", TinyMCE_IESpellPlugin);
Binary file includes/clientside/tinymce/plugins/iespell/images/iespell.gif has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/iespell/langs/en.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,7 @@
+// UK lang variables
+
+tinyMCE.addToLang('',{
+iespell_desc : 'Run spell checking',
+iespell_download : "ieSpell not detected. Click OK to go to download page."
+});
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/iespell/readme.txt	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+Check the TinyMCE documentation for details on this plugin.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/inlinepopups/css/inlinepopup.css	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,69 @@
+/* Window classes */
+
+.mceWindow {
+	position: absolute;
+	left: 0;
+	top: 0;
+	border: 1px solid black;
+	background-color: #D4D0C8;
+}
+
+.mceWindowHead {
+	background-color: #334F8D;
+	width: 100%;
+	height: 18px;
+	cursor: move;
+	overflow: hidden;
+}
+
+.mceWindowBody {
+	clear: both;
+	background-color: white;
+}
+
+.mceWindowStatusbar {
+	background-color: #D4D0C8;
+	height: 12px;
+	border-top: 1px solid black;
+}
+
+.mceWindowTitle {
+	float: left;
+	font-family: "MS Sans Serif";
+	font-size: 9pt;
+	font-weight: bold;
+	line-height: 18px;
+	color: white;
+	margin-left: 2px;
+	overflow: hidden;
+}
+
+.mceWindowHeadTools {
+	margin-right: 2px;
+}
+
+.mceWindowClose, .mceWindowMinimize, .mceWindowMaximize {
+	display: block;
+	float: right;
+	overflow: hidden;
+	margin-top: 2px;
+}
+
+.mceWindowClose {
+	margin-left: 2px;
+}
+
+.mceWindowMinimize {
+}
+
+.mceWindowMaximize {
+}
+
+.mceWindowResize {
+	display: block;
+	float: right;
+	overflow: hidden;
+	cursor: se-resize;
+	width: 12px;
+	height: 12px;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/inlinepopups/editor_plugin.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+var TinyMCE_InlinePopupsPlugin={getInfo:function(){return{longname:'Inline Popups',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/inlinepopups',version:tinyMCE.majorVersion+"."+tinyMCE.minorVersion}}};tinyMCE.addPlugin("inlinepopups",TinyMCE_InlinePopupsPlugin);TinyMCE_Engine.prototype.orgOpenWindow=TinyMCE_Engine.prototype.openWindow;TinyMCE_Engine.prototype.orgCloseWindow=TinyMCE_Engine.prototype.closeWindow;TinyMCE_Engine.prototype.openWindow=function(template,args){if(args['inline']!="yes"||tinyMCE.isOpera||tinyMCE.getParam("plugins").indexOf('inlinepopups')==-1){mcWindows.selectedWindow=null;args['mce_inside_iframe']=false;this.orgOpenWindow(template,args);return}var url,resizable,scrollbars;args['mce_inside_iframe']=true;tinyMCE.windowArgs=args;if(template['file'].charAt(0)!='/'&&template['file'].indexOf('://')==-1)url=tinyMCE.baseURL+"/themes/"+tinyMCE.getParam("theme")+"/"+template['file'];else url=template['file'];if(!(width=parseInt(template['width'])))width=320;if(!(height=parseInt(template['height'])))height=200;if(!(minWidth=parseInt(template['minWidth'])))minWidth=100;if(!(minHeight=parseInt(template['minHeight'])))minHeight=100;resizable=(args&&args['resizable'])?args['resizable']:"no";scrollbars=(args&&args['scrollbars'])?args['scrollbars']:"no";height+=18;for(var name in args){if(typeof(args[name])=='function')continue;url=tinyMCE.replaceVar(url,name,escape(args[name]))}var elm=document.getElementById(this.selectedInstance.editorId+'_parent');if(tinyMCE.hasPlugin('fullscreen')&&this.selectedInstance.getData('fullscreen').enabled)pos={absLeft:0,absTop:0};else pos=tinyMCE.getAbsPosition(elm);pos.absLeft+=Math.round((elm.firstChild.clientWidth/ 2) - (width /2));pos.absTop+=Math.round((elm.firstChild.clientHeight/ 2) - (height /2));mcWindows.open(url,mcWindows.idCounter++,"modal=yes,width="+width+",height="+height+",resizable="+resizable+",scrollbars="+scrollbars+",statusbar="+resizable+",left="+pos.absLeft+",top="+pos.absTop+",minWidth="+minWidth+",minHeight="+minHeight)};TinyMCE_Engine.prototype.closeWindow=function(win){var gotit=false,n,w;for(n in mcWindows.windows){w=mcWindows.windows[n];if(typeof(w)=='function')continue;if(win.name==w.id+'_iframe'){w.close();gotit=true}}if(!gotit)this.orgCloseWindow(win);tinyMCE.selectedInstance.getWin().focus()};TinyMCE_Engine.prototype.setWindowTitle=function(win_ref,title){for(var n in mcWindows.windows){var win=mcWindows.windows[n];if(typeof(win)=='function')continue;if(win_ref.name==win.id+"_iframe")window.frames[win.id+"_iframe"].document.getElementById(win.id+'_title').innerHTML=title}};function TinyMCE_Windows(){this.settings=new Array();this.windows=new Array();this.isMSIE=(navigator.appName=="Microsoft Internet Explorer");this.isGecko=navigator.userAgent.indexOf('Gecko')!=-1;this.isSafari=navigator.userAgent.indexOf('Safari')!=-1;this.isMac=navigator.userAgent.indexOf('Mac')!=-1;this.isMSIE5_0=this.isMSIE&&(navigator.userAgent.indexOf('MSIE 5.0')!=-1);this.action="none";this.selectedWindow=null;this.lastSelectedWindow=null;this.zindex=1001;this.mouseDownScreenX=0;this.mouseDownScreenY=0;this.mouseDownLayerX=0;this.mouseDownLayerY=0;this.mouseDownWidth=0;this.mouseDownHeight=0;this.idCounter=0};TinyMCE_Windows.prototype.init=function(settings){this.settings=settings;if(this.isMSIE)this.addEvent(document,"mousemove",mcWindows.eventDispatcher);else this.addEvent(window,"mousemove",mcWindows.eventDispatcher);this.addEvent(document,"mouseup",mcWindows.eventDispatcher);this.addEvent(window,"resize",mcWindows.eventDispatcher);this.addEvent(document,"scroll",mcWindows.eventDispatcher);this.doc=document};TinyMCE_Windows.prototype.getBounds=function(){if(!this.bounds){var vp=tinyMCE.getViewPort(window);var top,left,bottom,right,docEl=this.doc.documentElement;top=vp.top;left=vp.left;bottom=vp.height+top-2;right=vp.width+left-22;this.bounds=[left,top,right,bottom]}return this.bounds};TinyMCE_Windows.prototype.clampBoxPosition=function(x,y,w,h,minW,minH){var bounds=this.getBounds();x=Math.max(bounds[0],Math.min(bounds[2],x+w)-w);y=Math.max(bounds[1],Math.min(bounds[3],y+h)-h);return this.clampBoxSize(x,y,w,h,minW,minH)};TinyMCE_Windows.prototype.clampBoxSize=function(x,y,w,h,minW,minH){var bounds=this.getBounds();return[x,y,Math.max(minW,Math.min(bounds[2],x+w)-x),Math.max(minH,Math.min(bounds[3],y+h)-y)]};TinyMCE_Windows.prototype.getParam=function(name,default_value){var value=null;value=(typeof(this.settings[name])=="undefined")?default_value:this.settings[name];if(value=="true"||value=="false")return(value=="true");return value};TinyMCE_Windows.prototype.eventDispatcher=function(e){e=typeof(e)=="undefined"?window.event:e;if(mcWindows.selectedWindow==null)return;if(mcWindows.isGecko&&e.type=="mousedown"){var elm=e.currentTarget;for(var n in mcWindows.windows){var win=mcWindows.windows[n];if(win.headElement==elm||win.resizeElement==elm){win.focus();break}}}switch(e.type){case"mousemove":mcWindows.selectedWindow.onMouseMove(e);break;case"mouseup":mcWindows.selectedWindow.onMouseUp(e);break;case"mousedown":mcWindows.selectedWindow.onMouseDown(e);break;case"focus":mcWindows.selectedWindow.onFocus(e);break;case"scroll":case"resize":if(mcWindows.clampUpdateTimeout)clearTimeout(mcWindows.clampUpdateTimeout);mcWindows.clampEventType=e.type;mcWindows.clampUpdateTimeout=setTimeout(function(){mcWindows.updateClamping()},100);break}};TinyMCE_Windows.prototype.updateClamping=function(){var clamp,oversize,etype=mcWindows.clampEventType;this.bounds=null;this.clampUpdateTimeout=null;for(var n in this.windows){win=this.windows[n];if(typeof(win)=='function'||!win.winElement)continue;clamp=mcWindows.clampBoxPosition(win.left,win.top,win.winElement.scrollWidth,win.winElement.scrollHeight,win.features.minWidth,win.features.minHeight);oversize=(clamp[2]!=win.winElement.scrollWidth||clamp[3]!=win.winElement.scrollHeight)?true:false;if(!oversize||win.features.resizable=="yes"||etype!="scroll")win.moveTo(clamp[0],clamp[1]);if(oversize&&win.features.resizable=="yes")win.resizeTo(clamp[2],clamp[3])}};TinyMCE_Windows.prototype.addEvent=function(obj,name,handler){if(this.isMSIE)obj.attachEvent("on"+name,handler);else obj.addEventListener(name,handler,false)};TinyMCE_Windows.prototype.cancelEvent=function(e){if(this.isMSIE){e.returnValue=false;e.cancelBubble=true}else e.preventDefault()};TinyMCE_Windows.prototype.parseFeatures=function(opts){opts=opts.toLowerCase();opts=opts.replace(/;/g,",");opts=opts.replace(/[^0-9a-z=,]/g,"");var optionChunks=opts.split(',');var options=new Array();options['left']="10";options['top']="10";options['width']="300";options['height']="300";options['minwidth']="100";options['minheight']="100";options['resizable']="yes";options['minimizable']="yes";options['maximizable']="yes";options['close']="yes";options['movable']="yes";options['statusbar']="yes";options['scrollbars']="auto";options['modal']="no";if(opts=="")return options;for(var i=0;i<optionChunks.length;i++){var parts=optionChunks[i].split('=');if(parts.length==2)options[parts[0]]=parts[1]}options['left']=parseInt(options['left']);options['top']=parseInt(options['top']);options['width']=parseInt(options['width']);options['height']=parseInt(options['height']);options['minWidth']=parseInt(options['minwidth']);options['minHeight']=parseInt(options['minheight']);return options};TinyMCE_Windows.prototype.open=function(url,name,features){this.lastSelectedWindow=this.selectedWindow;var win=new TinyMCE_Window();var winDiv,html="",id;var imgPath=this.getParam("images_path");features=this.parseFeatures(features);var clamp=mcWindows.clampBoxPosition(features['left'],features['top'],features['width'],features['height'],features['minWidth'],features['minHeight']);features['left']=clamp[0];features['top']=clamp[1];if(features['resizable']=="yes"){features['width']=clamp[2];features['height']=clamp[3]}id="mcWindow_"+name;win.deltaHeight=18;if(features['statusbar']=="yes"){win.deltaHeight+=13;if(this.isMSIE)win.deltaHeight+=1}width=parseInt(features['width']);height=parseInt(features['height'])-win.deltaHeight;if(this.isMSIE)width-=2;win.id=id;win.url=url;win.name=name;win.features=features;this.windows[name]=win;iframeWidth=width;iframeHeight=height;html+='<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">';html+='<html>';html+='<head>';html+='<title>Wrapper iframe</title>';html+='<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">';html+='<link href="'+this.getParam("css_file")+'" rel="stylesheet" type="text/css" />';html+='</head>';html+='<body onload="parent.mcWindows.onLoad(\''+name+'\');">';html+='<div id="'+id+'_container" class="mceWindow">';html+='<div id="'+id+'_head" class="mceWindowHead" onmousedown="parent.mcWindows.windows[\''+name+'\'].focus();">';html+='  <div id="'+id+'_title" class="mceWindowTitle"';html+='  onselectstart="return false;" unselectable="on" style="-moz-user-select: none !important;"></div>';html+='    <div class="mceWindowHeadTools">';html+='      <a href="javascript:parent.mcWindows.windows[\''+name+'\'].close();" target="_self" onmousedown="return false;" class="mceWindowClose"><img border="0" src="'+imgPath+'/window_close.gif" /></a>';if(features['resizable']=="yes"&&features['maximizable']=="yes")html+='      <a href="javascript:parent.mcWindows.windows[\''+name+'\'].maximize();" target="_self" onmousedown="return false;" class="mceWindowMaximize"><img border="0" src="'+imgPath+'/window_maximize.gif" /></a>';html+='    </div>';html+='</div><div id="'+id+'_body" class="mceWindowBody" style="width: '+width+'px; height: '+height+'px;">';html+='<iframe id="'+id+'_iframe" name="'+id+'_iframe" frameborder="0" width="'+iframeWidth+'" height="'+iframeHeight+'" src="'+url+'" class="mceWindowBodyIframe" scrolling="'+features['scrollbars']+'"></iframe></div>';if(features['statusbar']=="yes"){html+='<div id="'+id+'_statusbar" class="mceWindowStatusbar" onmousedown="parent.mcWindows.windows[\''+name+'\'].focus();">';if(features['resizable']=="yes"){if(this.isGecko)html+='<div id="'+id+'_resize" class="mceWindowResize"><div style="background-image: url(\''+imgPath+'/window_resize.gif\'); width: 12px; height: 12px;"></div></div>';else html+='<div id="'+id+'_resize" class="mceWindowResize"><img onmousedown="parent.mcWindows.windows[\''+name+'\'].focus();" border="0" src="'+imgPath+'/window_resize.gif" /></div>'}html+='</div>'}html+='</div>';html+='</body>';html+='</html>';this.createFloatingIFrame(id,features['left'],features['top'],features['width'],features['height'],html)};TinyMCE_Windows.prototype.setDocumentLock=function(state){var elm=document.getElementById('mcWindowEventBlocker');if(state){if(elm==null){elm=document.createElement("div");elm.id="mcWindowEventBlocker";elm.style.position="absolute";elm.style.left="0";elm.style.top="0";document.body.appendChild(elm)}elm.style.display="none";var imgPath=this.getParam("images_path");var width=document.body.clientWidth;var height=document.body.clientHeight;elm.style.width=width;elm.style.height=height;elm.innerHTML='<img src="'+imgPath+'/spacer.gif" width="'+width+'" height="'+height+'" />';elm.style.zIndex=mcWindows.zindex-1;elm.style.display="block"}else if(elm!=null){if(mcWindows.windows.length==0)elm.parentNode.removeChild(elm);else elm.style.zIndex=mcWindows.zindex-1}};TinyMCE_Windows.prototype.onLoad=function(name){var win=mcWindows.windows[name];var id="mcWindow_"+name;var wrapperIframe=window.frames[id+"_iframe"].frames[0];var wrapperDoc=window.frames[id+"_iframe"].document;var doc=window.frames[id+"_iframe"].document;var winDiv=document.getElementById("mcWindow_"+name+"_div");var realIframe=window.frames[id+"_iframe"].frames[0];win.id="mcWindow_"+name;win.winElement=winDiv;win.bodyElement=doc.getElementById(id+'_body');win.iframeElement=doc.getElementById(id+'_iframe');win.headElement=doc.getElementById(id+'_head');win.titleElement=doc.getElementById(id+'_title');win.resizeElement=doc.getElementById(id+'_resize');win.containerElement=doc.getElementById(id+'_container');win.left=win.features['left'];win.top=win.features['top'];win.frame=window.frames[id+'_iframe'].frames[0];win.wrapperFrame=window.frames[id+'_iframe'];win.wrapperIFrameElement=document.getElementById(id+"_iframe");mcWindows.addEvent(win.headElement,"mousedown",mcWindows.eventDispatcher);if(win.resizeElement!=null)mcWindows.addEvent(win.resizeElement,"mousedown",mcWindows.eventDispatcher);if(mcWindows.isMSIE){mcWindows.addEvent(realIframe.document,"mousemove",mcWindows.eventDispatcher);mcWindows.addEvent(realIframe.document,"mouseup",mcWindows.eventDispatcher)}else{mcWindows.addEvent(realIframe,"mousemove",mcWindows.eventDispatcher);mcWindows.addEvent(realIframe,"mouseup",mcWindows.eventDispatcher);mcWindows.addEvent(realIframe,"focus",mcWindows.eventDispatcher)}for(var i=0;i<window.frames.length;i++){if(!window.frames[i]._hasMouseHandlers){if(mcWindows.isMSIE){mcWindows.addEvent(window.frames[i].document,"mousemove",mcWindows.eventDispatcher);mcWindows.addEvent(window.frames[i].document,"mouseup",mcWindows.eventDispatcher)}else{mcWindows.addEvent(window.frames[i],"mousemove",mcWindows.eventDispatcher);mcWindows.addEvent(window.frames[i],"mouseup",mcWindows.eventDispatcher)}window.frames[i]._hasMouseHandlers=true}}if(mcWindows.isMSIE){mcWindows.addEvent(win.frame.document,"mousemove",mcWindows.eventDispatcher);mcWindows.addEvent(win.frame.document,"mouseup",mcWindows.eventDispatcher)}else{mcWindows.addEvent(win.frame,"mousemove",mcWindows.eventDispatcher);mcWindows.addEvent(win.frame,"mouseup",mcWindows.eventDispatcher);mcWindows.addEvent(win.frame,"focus",mcWindows.eventDispatcher)}var func=this.getParam("on_open_window","");if(func!="")eval(func+"(win);");win.focus();if(win.features['modal']=="yes")mcWindows.setDocumentLock(true)};TinyMCE_Windows.prototype.createFloatingIFrame=function(id_prefix,left,top,width,height,html){var iframe=document.createElement("iframe");var div=document.createElement("div"),doc;width=parseInt(width);height=parseInt(height)+1;div.setAttribute("id",id_prefix+"_div");div.setAttribute("width",width);div.setAttribute("height",(height));div.style.position="absolute";div.style.left=left+"px";div.style.top=top+"px";div.style.width=width+"px";div.style.height=(height)+"px";div.style.backgroundColor="white";div.style.display="none";if(this.isGecko){iframeWidth=width+2;iframeHeight=height+2}else{iframeWidth=width;iframeHeight=height+1}iframe.setAttribute("id",id_prefix+"_iframe");iframe.setAttribute("name",id_prefix+"_iframe");iframe.setAttribute("border","0");iframe.setAttribute("frameBorder","0");iframe.setAttribute("marginWidth","0");iframe.setAttribute("marginHeight","0");iframe.setAttribute("leftMargin","0");iframe.setAttribute("topMargin","0");iframe.setAttribute("width",iframeWidth);iframe.setAttribute("height",iframeHeight);iframe.setAttribute("scrolling","no");iframe.style.width=iframeWidth+"px";iframe.style.height=iframeHeight+"px";iframe.style.backgroundColor="white";div.appendChild(iframe);document.body.appendChild(div);div.innerHTML=div.innerHTML;if(this.isSafari){window.setTimeout(function(){var doc=window.frames[id_prefix+'_iframe'].document;doc.open();doc.write(html);doc.close()},10)}else{doc=window.frames[id_prefix+'_iframe'].window.document;doc.open();doc.write(html);doc.close()}div.style.display="block";return div};function TinyMCE_Window(){};TinyMCE_Window.prototype.focus=function(){if(this!=mcWindows.selectedWindow){this.winElement.style.zIndex=++mcWindows.zindex;mcWindows.lastSelectedWindow=mcWindows.selectedWindow;mcWindows.selectedWindow=this}};TinyMCE_Window.prototype.minimize=function(){};TinyMCE_Window.prototype.maximize=function(){if(this.restoreSize){this.moveTo(this.restoreSize[0],this.restoreSize[1]);this.resizeTo(this.restoreSize[2],this.restoreSize[3]);this.updateClamping();this.restoreSize=null}else{var bounds=mcWindows.getBounds();this.restoreSize=[this.left,this.top,this.winElement.scrollWidth,this.winElement.scrollHeight];this.moveTo(bounds[0],bounds[1]);this.resizeTo(bounds[2]-bounds[0],bounds[3]-bounds[1])}};TinyMCE_Window.prototype.startResize=function(){mcWindows.action="resize"};TinyMCE_Window.prototype.startMove=function(e){mcWindows.action="move"};TinyMCE_Window.prototype.close=function(){if(this.frame&&this.frame['tinyMCEPopup'])this.frame['tinyMCEPopup'].restoreSelection();if(mcWindows.lastSelectedWindow!=null)mcWindows.lastSelectedWindow.focus();var mcWindowsNew=new Array();for(var n in mcWindows.windows){var win=mcWindows.windows[n];if(typeof(win)=='function')continue;if(win.name!=this.name)mcWindowsNew[n]=win}mcWindows.windows=mcWindowsNew;var e=mcWindows.doc.getElementById(this.id+"_iframe");e.parentNode.removeChild(e);var e=mcWindows.doc.getElementById(this.id+"_div");e.parentNode.removeChild(e);mcWindows.setDocumentLock(false)};TinyMCE_Window.prototype.onMouseMove=function(e){var clamp;var dx=e.screenX-mcWindows.mouseDownScreenX;var dy=e.screenY-mcWindows.mouseDownScreenY;switch(mcWindows.action){case"resize":clamp=mcWindows.clampBoxSize(this.left,this.top,mcWindows.mouseDownWidth+(e.screenX-mcWindows.mouseDownScreenX),mcWindows.mouseDownHeight+(e.screenY-mcWindows.mouseDownScreenY),this.features.minWidth,this.features.minHeight);this.resizeTo(clamp[2],clamp[3]);mcWindows.cancelEvent(e);break;case"move":this.left=mcWindows.mouseDownLayerX+(e.screenX-mcWindows.mouseDownScreenX);this.top=mcWindows.mouseDownLayerY+(e.screenY-mcWindows.mouseDownScreenY);this.updateClamping();mcWindows.cancelEvent(e);break}};TinyMCE_Window.prototype.moveTo=function(x,y){this.left=x;this.top=y;this.winElement.style.left=this.left+"px";this.winElement.style.top=this.top+"px"};TinyMCE_Window.prototype.resizeTo=function(width,height){this.wrapperIFrameElement.style.width=(width+2)+'px';this.wrapperIFrameElement.style.height=(height+2)+'px';this.wrapperIFrameElement.width=width+2;this.wrapperIFrameElement.height=height+2;this.winElement.style.width=width+'px';this.winElement.style.height=height+'px';height=height-this.deltaHeight;this.containerElement.style.width=width+'px';this.iframeElement.style.width=width+'px';this.iframeElement.style.height=height+'px';this.bodyElement.style.width=width+'px';this.bodyElement.style.height=height+'px';this.headElement.style.width=width+'px';};TinyMCE_Window.prototype.updateClamping=function(){var clamp,oversize;clamp=mcWindows.clampBoxPosition(this.left,this.top,this.winElement.scrollWidth,this.winElement.scrollHeight,this.features.minWidth,this.features.minHeight);oversize=(clamp[2]!=this.winElement.scrollWidth||clamp[3]!=this.winElement.scrollHeight)?true:false;this.moveTo(clamp[0],clamp[1]);if(this.features.resizable=="yes"&&oversize)this.resizeTo(clamp[2],clamp[3])};function debug(msg){document.getElementById('debug').value+=msg+"\n"}TinyMCE_Window.prototype.onMouseUp=function(e){mcWindows.action="none"};TinyMCE_Window.prototype.onFocus=function(e){var winRef=e.currentTarget;for(var n in mcWindows.windows){var win=mcWindows.windows[n];if(typeof(win)=='function')continue;if(winRef.name==win.id+"_iframe"){win.focus();return}}};TinyMCE_Window.prototype.onMouseDown=function(e){var elm=mcWindows.isMSIE?this.wrapperFrame.event.srcElement:e.target;mcWindows.mouseDownScreenX=e.screenX;mcWindows.mouseDownScreenY=e.screenY;mcWindows.mouseDownLayerX=this.left;mcWindows.mouseDownLayerY=this.top;mcWindows.mouseDownWidth=parseInt(this.winElement.style.width);mcWindows.mouseDownHeight=parseInt(this.winElement.style.height);if(this.resizeElement!=null&&elm==this.resizeElement.firstChild)this.startResize(e);else this.startMove(e);mcWindows.cancelEvent(e)};var mcWindows=new TinyMCE_Windows();mcWindows.init({images_path:tinyMCE.baseURL+"/plugins/inlinepopups/images",css_file:tinyMCE.baseURL+"/plugins/inlinepopups/css/inlinepopup.css"});
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/inlinepopups/editor_plugin_src.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,814 @@
+/**
+ * $Id: editor_plugin_src.js 201 2007-02-12 15:56:56Z spocke $
+ *
+ * Moxiecode DHTML Windows script.
+ *
+ * @author Moxiecode
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+// Patch openWindow, closeWindow TinyMCE functions
+
+var TinyMCE_InlinePopupsPlugin = {
+	getInfo : function() {
+		return {
+			longname : 'Inline Popups',
+			author : 'Moxiecode Systems AB',
+			authorurl : 'http://tinymce.moxiecode.com',
+			infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/inlinepopups',
+			version : tinyMCE.majorVersion + "." + tinyMCE.minorVersion
+		};
+	}
+};
+
+tinyMCE.addPlugin("inlinepopups", TinyMCE_InlinePopupsPlugin);
+
+// Patch openWindow, closeWindow TinyMCE functions
+
+TinyMCE_Engine.prototype.orgOpenWindow = TinyMCE_Engine.prototype.openWindow;
+TinyMCE_Engine.prototype.orgCloseWindow = TinyMCE_Engine.prototype.closeWindow;
+
+TinyMCE_Engine.prototype.openWindow = function(template, args) {
+	// Does the caller support inline
+	if (args['inline'] != "yes" || tinyMCE.isOpera || tinyMCE.getParam("plugins").indexOf('inlinepopups') == -1) {
+		mcWindows.selectedWindow = null;
+		args['mce_inside_iframe'] = false;
+		this.orgOpenWindow(template, args);
+		return;
+	}
+
+	var url, resizable, scrollbars;
+
+	args['mce_inside_iframe'] = true;
+	tinyMCE.windowArgs = args;
+
+	if (template['file'].charAt(0) != '/' && template['file'].indexOf('://') == -1)
+		url = tinyMCE.baseURL + "/themes/" + tinyMCE.getParam("theme") + "/" + template['file'];
+	else
+		url = template['file'];
+
+	if (!(width = parseInt(template['width'])))
+		width = 320;
+
+	if (!(height = parseInt(template['height'])))
+		height = 200;
+
+	if (!(minWidth = parseInt(template['minWidth'])))
+		minWidth = 100;
+
+	if (!(minHeight = parseInt(template['minHeight'])))
+		minHeight = 100;
+
+	resizable = (args && args['resizable']) ? args['resizable'] : "no";
+	scrollbars = (args && args['scrollbars']) ? args['scrollbars'] : "no";
+
+	height += 18;
+
+	// Replace all args as variables in URL
+	for (var name in args) {
+		if (typeof(args[name]) == 'function')
+			continue;
+
+		url = tinyMCE.replaceVar(url, name, escape(args[name]));
+	}
+
+	var elm = document.getElementById(this.selectedInstance.editorId + '_parent');
+
+	if (tinyMCE.hasPlugin('fullscreen') && this.selectedInstance.getData('fullscreen').enabled)
+		pos = { absLeft: 0, absTop: 0 };
+	else
+		pos = tinyMCE.getAbsPosition(elm);
+
+	// Center div in editor area
+	pos.absLeft += Math.round((elm.firstChild.clientWidth / 2) - (width / 2));
+	pos.absTop += Math.round((elm.firstChild.clientHeight / 2) - (height / 2));
+
+	mcWindows.open(url, mcWindows.idCounter++, "modal=yes,width=" + width+ ",height=" + height + ",resizable=" + resizable + ",scrollbars=" + scrollbars + ",statusbar=" + resizable + ",left=" + pos.absLeft + ",top=" + pos.absTop + ",minWidth=" + minWidth + ",minHeight=" + minHeight );
+};
+
+TinyMCE_Engine.prototype.closeWindow = function(win) {
+	var gotit = false, n, w;
+	for (n in mcWindows.windows) {
+		w = mcWindows.windows[n];
+		if (typeof(w) == 'function') continue;
+		if (win.name == w.id + '_iframe') {
+			w.close();
+			gotit = true;
+		}
+	}
+	if (!gotit)
+		this.orgCloseWindow(win);
+
+	tinyMCE.selectedInstance.getWin().focus(); 
+};
+
+TinyMCE_Engine.prototype.setWindowTitle = function(win_ref, title) {
+	for (var n in mcWindows.windows) {
+		var win = mcWindows.windows[n];
+		if (typeof(win) == 'function')
+			continue;
+
+		if (win_ref.name == win.id + "_iframe")
+			window.frames[win.id + "_iframe"].document.getElementById(win.id + '_title').innerHTML = title;
+	}
+};
+
+// * * * * * TinyMCE_Windows classes below
+
+// Windows handler
+function TinyMCE_Windows() {
+	this.settings = new Array();
+	this.windows = new Array();
+	this.isMSIE = (navigator.appName == "Microsoft Internet Explorer");
+	this.isGecko = navigator.userAgent.indexOf('Gecko') != -1;
+	this.isSafari = navigator.userAgent.indexOf('Safari') != -1;
+	this.isMac = navigator.userAgent.indexOf('Mac') != -1;
+	this.isMSIE5_0 = this.isMSIE && (navigator.userAgent.indexOf('MSIE 5.0') != -1);
+	this.action = "none";
+	this.selectedWindow = null;
+	this.lastSelectedWindow = null;
+	this.zindex = 1001;
+	this.mouseDownScreenX = 0;
+	this.mouseDownScreenY = 0;
+	this.mouseDownLayerX = 0;
+	this.mouseDownLayerY = 0;
+	this.mouseDownWidth = 0;
+	this.mouseDownHeight = 0;
+	this.idCounter = 0;
+};
+
+TinyMCE_Windows.prototype.init = function(settings) {
+	this.settings = settings;
+
+	if (this.isMSIE)
+		this.addEvent(document, "mousemove", mcWindows.eventDispatcher);
+	else
+		this.addEvent(window, "mousemove", mcWindows.eventDispatcher);
+
+	this.addEvent(document, "mouseup", mcWindows.eventDispatcher);
+
+	this.addEvent(window, "resize", mcWindows.eventDispatcher);
+	this.addEvent(document, "scroll", mcWindows.eventDispatcher);
+
+	this.doc = document;
+};
+
+TinyMCE_Windows.prototype.getBounds = function() {
+	if (!this.bounds) {
+		var vp = tinyMCE.getViewPort(window);
+		var top, left, bottom, right, docEl = this.doc.documentElement;
+
+		top    = vp.top;
+		left   = vp.left;
+		bottom = vp.height + top - 2;
+		right  = vp.width  + left - 22; // TODO this number is platform dependant
+		// x1, y1, x2, y2
+		this.bounds = [left, top, right, bottom];
+	}
+	return this.bounds;
+};
+
+TinyMCE_Windows.prototype.clampBoxPosition = function(x, y, w, h, minW, minH) {
+	var bounds = this.getBounds();
+
+	x = Math.max(bounds[0], Math.min(bounds[2], x + w) - w);
+	y = Math.max(bounds[1], Math.min(bounds[3], y + h) - h);
+
+	return this.clampBoxSize(x, y, w, h, minW, minH);
+};
+
+TinyMCE_Windows.prototype.clampBoxSize = function(x, y, w, h, minW, minH) {
+	var bounds = this.getBounds();
+
+	return [
+		x, y,
+		Math.max(minW, Math.min(bounds[2], x + w) - x),
+		Math.max(minH, Math.min(bounds[3], y + h) - y)
+	];
+};
+
+TinyMCE_Windows.prototype.getParam = function(name, default_value) {
+	var value = null;
+
+	value = (typeof(this.settings[name]) == "undefined") ? default_value : this.settings[name];
+
+	// Fix bool values
+	if (value == "true" || value == "false")
+		return (value == "true");
+
+	return value;
+};
+
+TinyMCE_Windows.prototype.eventDispatcher = function(e) {
+	e = typeof(e) == "undefined" ? window.event : e;
+
+	if (mcWindows.selectedWindow == null)
+		return;
+
+	// Switch focus
+	if (mcWindows.isGecko && e.type == "mousedown") {
+		var elm = e.currentTarget;
+
+		for (var n in mcWindows.windows) {
+			var win = mcWindows.windows[n];
+
+			if (win.headElement == elm || win.resizeElement == elm) {
+				win.focus();
+				break;
+			}
+		}
+	}
+
+	switch (e.type) {
+		case "mousemove":
+			mcWindows.selectedWindow.onMouseMove(e);
+			break;
+
+		case "mouseup":
+			mcWindows.selectedWindow.onMouseUp(e);
+			break;
+
+		case "mousedown":
+			mcWindows.selectedWindow.onMouseDown(e);
+			break;
+
+		case "focus":
+			mcWindows.selectedWindow.onFocus(e);
+			break;
+		case "scroll":
+		case "resize":
+			if (mcWindows.clampUpdateTimeout)
+				clearTimeout(mcWindows.clampUpdateTimeout);
+			mcWindows.clampEventType = e.type;
+			mcWindows.clampUpdateTimeout =
+				setTimeout(function () {mcWindows.updateClamping()}, 100);
+			break;
+	}
+};
+
+TinyMCE_Windows.prototype.updateClamping = function () {
+	var clamp, oversize, etype = mcWindows.clampEventType;
+
+	this.bounds = null; // Recalc window bounds on resize/scroll
+	this.clampUpdateTimeout = null;
+
+	for (var n in this.windows) {
+		win = this.windows[n];
+		if (typeof(win) == 'function' || ! win.winElement) continue;
+
+		clamp = mcWindows.clampBoxPosition(
+			win.left, win.top,
+			win.winElement.scrollWidth,
+			win.winElement.scrollHeight,
+			win.features.minWidth,
+			win.features.minHeight
+		);
+		oversize = (
+			clamp[2] != win.winElement.scrollWidth ||
+			clamp[3] != win.winElement.scrollHeight
+		) ? true : false;
+
+		if (!oversize || win.features.resizable == "yes" || etype != "scroll")
+			win.moveTo(clamp[0], clamp[1]);
+		if (oversize && win.features.resizable == "yes")
+			win.resizeTo(clamp[2], clamp[3]);
+	}
+};
+
+TinyMCE_Windows.prototype.addEvent = function(obj, name, handler) {
+	if (this.isMSIE)
+		obj.attachEvent("on" + name, handler);
+	else
+		obj.addEventListener(name, handler, false);
+};
+
+TinyMCE_Windows.prototype.cancelEvent = function(e) {
+	if (this.isMSIE) {
+		e.returnValue = false;
+		e.cancelBubble = true;
+	} else
+		e.preventDefault();
+};
+
+TinyMCE_Windows.prototype.parseFeatures = function(opts) {
+	// Cleanup the options
+	opts = opts.toLowerCase();
+	opts = opts.replace(/;/g, ",");
+	opts = opts.replace(/[^0-9a-z=,]/g, "");
+
+	var optionChunks = opts.split(',');
+	var options = new Array();
+
+	options['left'] = "10";
+	options['top'] = "10";
+	options['width'] = "300";
+	options['height'] = "300";
+	options['minwidth'] = "100";
+	options['minheight'] = "100";
+	options['resizable'] = "yes";
+	options['minimizable'] = "yes";
+	options['maximizable'] = "yes";
+	options['close'] = "yes";
+	options['movable'] = "yes";
+	options['statusbar'] = "yes";
+	options['scrollbars'] = "auto";
+	options['modal'] = "no";
+
+	if (opts == "")
+		return options;
+
+	for (var i=0; i<optionChunks.length; i++) {
+		var parts = optionChunks[i].split('=');
+
+		if (parts.length == 2)
+			options[parts[0]] = parts[1];
+	}
+
+	options['left'] = parseInt(options['left']);
+	options['top'] = parseInt(options['top']);
+	options['width'] = parseInt(options['width']);
+	options['height'] = parseInt(options['height']);
+	options['minWidth'] = parseInt(options['minwidth']);
+	options['minHeight'] = parseInt(options['minheight']);
+
+	return options;
+};
+
+TinyMCE_Windows.prototype.open = function(url, name, features) {
+	this.lastSelectedWindow = this.selectedWindow;
+
+	var win = new TinyMCE_Window();
+	var winDiv, html = "", id;
+	var imgPath = this.getParam("images_path");
+
+	features = this.parseFeatures(features);
+
+	// Clamp specified dimensions
+	var clamp = mcWindows.clampBoxPosition(
+		features['left'], features['top'],
+		features['width'], features['height'],
+		features['minWidth'], features['minHeight']
+	);
+
+	features['left'] = clamp[0];
+	features['top'] = clamp[1];
+
+	if (features['resizable'] == "yes") {
+		features['width'] = clamp[2];
+		features['height'] = clamp[3];
+	}
+
+	// Create div
+	id = "mcWindow_" + name;
+	win.deltaHeight = 18;
+
+	if (features['statusbar'] == "yes") {
+		win.deltaHeight += 13;
+
+		if (this.isMSIE)
+			win.deltaHeight += 1;
+	}
+
+	width = parseInt(features['width']);
+	height = parseInt(features['height'])-win.deltaHeight;
+
+	if (this.isMSIE)
+		width -= 2;
+
+	// Setup first part of window
+	win.id = id;
+	win.url = url;
+	win.name = name;
+	win.features = features;
+	this.windows[name] = win;
+
+	iframeWidth = width;
+	iframeHeight = height;
+
+	// Create inner content
+	html += '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">';
+	html += '<html>';
+	html += '<head>';
+	html += '<title>Wrapper iframe</title>';
+	html += '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">';
+	html += '<link href="' + this.getParam("css_file") + '" rel="stylesheet" type="text/css" />';
+	html += '</head>';
+	html += '<body onload="parent.mcWindows.onLoad(\'' + name + '\');">';
+
+	html += '<div id="' + id + '_container" class="mceWindow">';
+	html += '<div id="' + id + '_head" class="mceWindowHead" onmousedown="parent.mcWindows.windows[\'' + name + '\'].focus();">';
+	html += '  <div id="' + id + '_title" class="mceWindowTitle"';
+	html += '  onselectstart="return false;" unselectable="on" style="-moz-user-select: none !important;"></div>';
+	html += '    <div class="mceWindowHeadTools">';
+	html += '      <a href="javascript:parent.mcWindows.windows[\'' + name + '\'].close();" target="_self" onmousedown="return false;" class="mceWindowClose"><img border="0" src="' + imgPath + '/window_close.gif" /></a>';
+	if (features['resizable'] == "yes" && features['maximizable'] == "yes")
+		html += '      <a href="javascript:parent.mcWindows.windows[\'' + name + '\'].maximize();" target="_self" onmousedown="return false;" class="mceWindowMaximize"><img border="0" src="' + imgPath + '/window_maximize.gif" /></a>';
+	// html += '      <a href="javascript:mcWindows.windows[\'' + name + '\'].minimize();" target="_self" onmousedown="return false;" class="mceWindowMinimize"></a>';
+	html += '    </div>';
+	html += '</div><div id="' + id + '_body" class="mceWindowBody" style="width: ' + width + 'px; height: ' + height + 'px;">';
+	html += '<iframe id="' + id + '_iframe" name="' + id + '_iframe" frameborder="0" width="' + iframeWidth + '" height="' + iframeHeight + '" src="' + url + '" class="mceWindowBodyIframe" scrolling="' + features['scrollbars'] + '"></iframe></div>';
+
+	if (features['statusbar'] == "yes") {
+		html += '<div id="' + id + '_statusbar" class="mceWindowStatusbar" onmousedown="parent.mcWindows.windows[\'' + name + '\'].focus();">';
+
+		if (features['resizable'] == "yes") {
+			if (this.isGecko)
+				html += '<div id="' + id + '_resize" class="mceWindowResize"><div style="background-image: url(\'' + imgPath + '/window_resize.gif\'); width: 12px; height: 12px;"></div></div>';
+			else
+				html += '<div id="' + id + '_resize" class="mceWindowResize"><img onmousedown="parent.mcWindows.windows[\'' + name + '\'].focus();" border="0" src="' + imgPath + '/window_resize.gif" /></div>';
+		}
+
+		html += '</div>';
+	}
+
+	html += '</div>';
+
+	html += '</body>';
+	html += '</html>';
+
+	// Create iframe
+	this.createFloatingIFrame(id, features['left'], features['top'], features['width'], features['height'], html);
+};
+
+// Blocks the document events by placing a image over the whole document
+TinyMCE_Windows.prototype.setDocumentLock = function(state) {
+	var elm = document.getElementById('mcWindowEventBlocker');
+
+	if (state) {
+		if (elm == null) {
+			elm = document.createElement("div");
+
+			elm.id = "mcWindowEventBlocker";
+			elm.style.position = "absolute";
+			elm.style.left = "0";
+			elm.style.top = "0";
+
+			document.body.appendChild(elm);
+		}
+
+		elm.style.display = "none";
+
+		var imgPath = this.getParam("images_path");
+		var width = document.body.clientWidth;
+		var height = document.body.clientHeight;
+
+		elm.style.width = width;
+		elm.style.height = height;
+		elm.innerHTML = '<img src="' + imgPath + '/spacer.gif" width="' + width + '" height="' + height + '" />';
+
+		elm.style.zIndex = mcWindows.zindex-1;
+		elm.style.display = "block";
+	} else if (elm != null) {
+		if (mcWindows.windows.length == 0)
+			elm.parentNode.removeChild(elm);
+		else
+			elm.style.zIndex = mcWindows.zindex-1;
+	}
+};
+
+// Gets called when wrapper iframe is initialized
+TinyMCE_Windows.prototype.onLoad = function(name) {
+	var win = mcWindows.windows[name];
+	var id = "mcWindow_" + name;
+	var wrapperIframe = window.frames[id + "_iframe"].frames[0];
+	var wrapperDoc = window.frames[id + "_iframe"].document;
+	var doc = window.frames[id + "_iframe"].document;
+	var winDiv = document.getElementById("mcWindow_" + name + "_div");
+	var realIframe = window.frames[id + "_iframe"].frames[0];
+
+	// Set window data
+	win.id = "mcWindow_" + name;
+	win.winElement = winDiv;
+	win.bodyElement = doc.getElementById(id + '_body');
+	win.iframeElement = doc.getElementById(id + '_iframe');
+	win.headElement = doc.getElementById(id + '_head');
+	win.titleElement = doc.getElementById(id + '_title');
+	win.resizeElement = doc.getElementById(id + '_resize');
+	win.containerElement = doc.getElementById(id + '_container');
+	win.left = win.features['left'];
+	win.top = win.features['top'];
+	win.frame = window.frames[id + '_iframe'].frames[0];
+	win.wrapperFrame = window.frames[id + '_iframe'];
+	win.wrapperIFrameElement = document.getElementById(id + "_iframe");
+
+	// Add event handlers
+	mcWindows.addEvent(win.headElement, "mousedown", mcWindows.eventDispatcher);
+
+	if (win.resizeElement != null)
+		mcWindows.addEvent(win.resizeElement, "mousedown", mcWindows.eventDispatcher);
+
+	if (mcWindows.isMSIE) {
+		mcWindows.addEvent(realIframe.document, "mousemove", mcWindows.eventDispatcher);
+		mcWindows.addEvent(realIframe.document, "mouseup", mcWindows.eventDispatcher);
+	} else {
+		mcWindows.addEvent(realIframe, "mousemove", mcWindows.eventDispatcher);
+		mcWindows.addEvent(realIframe, "mouseup", mcWindows.eventDispatcher);
+		mcWindows.addEvent(realIframe, "focus", mcWindows.eventDispatcher);
+	}
+
+	for (var i=0; i<window.frames.length; i++) {
+		if (!window.frames[i]._hasMouseHandlers) {
+			if (mcWindows.isMSIE) {
+				mcWindows.addEvent(window.frames[i].document, "mousemove", mcWindows.eventDispatcher);
+				mcWindows.addEvent(window.frames[i].document, "mouseup", mcWindows.eventDispatcher);
+			} else {
+				mcWindows.addEvent(window.frames[i], "mousemove", mcWindows.eventDispatcher);
+				mcWindows.addEvent(window.frames[i], "mouseup", mcWindows.eventDispatcher);
+			}
+
+			window.frames[i]._hasMouseHandlers = true;
+		}
+	}
+
+	if (mcWindows.isMSIE) {
+		mcWindows.addEvent(win.frame.document, "mousemove", mcWindows.eventDispatcher);
+		mcWindows.addEvent(win.frame.document, "mouseup", mcWindows.eventDispatcher);
+	} else {
+		mcWindows.addEvent(win.frame, "mousemove", mcWindows.eventDispatcher);
+		mcWindows.addEvent(win.frame, "mouseup", mcWindows.eventDispatcher);
+		mcWindows.addEvent(win.frame, "focus", mcWindows.eventDispatcher);
+	}
+
+	// Dispatch open window event
+	var func = this.getParam("on_open_window", "");
+	if (func != "")
+		eval(func + "(win);");
+
+	win.focus();
+
+	if (win.features['modal'] == "yes")
+		mcWindows.setDocumentLock(true);
+};
+
+TinyMCE_Windows.prototype.createFloatingIFrame = function(id_prefix, left, top, width, height, html) {
+	var iframe = document.createElement("iframe");
+	var div = document.createElement("div"), doc;
+
+	width = parseInt(width);
+	height = parseInt(height)+1;
+
+	// Create wrapper div
+	div.setAttribute("id", id_prefix + "_div");
+	div.setAttribute("width", width);
+	div.setAttribute("height", (height));
+	div.style.position = "absolute";
+
+	div.style.left = left + "px";
+	div.style.top = top + "px";
+	div.style.width = width + "px";
+	div.style.height = (height) + "px";
+	div.style.backgroundColor = "white";
+	div.style.display = "none";
+
+	if (this.isGecko) {
+		iframeWidth = width + 2;
+		iframeHeight = height + 2;
+	} else {
+		iframeWidth = width;
+		iframeHeight = height + 1;
+	}
+
+	// Create iframe
+	iframe.setAttribute("id", id_prefix + "_iframe");
+	iframe.setAttribute("name", id_prefix + "_iframe");
+	iframe.setAttribute("border", "0");
+	iframe.setAttribute("frameBorder", "0");
+	iframe.setAttribute("marginWidth", "0");
+	iframe.setAttribute("marginHeight", "0");
+	iframe.setAttribute("leftMargin", "0");
+	iframe.setAttribute("topMargin", "0");
+	iframe.setAttribute("width", iframeWidth);
+	iframe.setAttribute("height", iframeHeight);
+	// iframe.setAttribute("src", "../jscripts/tiny_mce/blank.htm");
+	// iframe.setAttribute("allowtransparency", "false");
+	iframe.setAttribute("scrolling", "no");
+	iframe.style.width = iframeWidth + "px";
+	iframe.style.height = iframeHeight + "px";
+	iframe.style.backgroundColor = "white";
+	div.appendChild(iframe);
+
+	document.body.appendChild(div);
+
+	// Fixed MSIE 5.0 issue
+	div.innerHTML = div.innerHTML;
+
+	if (this.isSafari) {
+		// Give Safari some time to setup
+		window.setTimeout(function() {
+			var doc = window.frames[id_prefix + '_iframe'].document;
+			doc.open();
+			doc.write(html);
+			doc.close();
+		}, 10);
+	} else {
+		doc = window.frames[id_prefix + '_iframe'].window.document;
+		doc.open();
+		doc.write(html);
+		doc.close();
+	}
+
+	div.style.display = "block";
+
+	return div;
+};
+
+// Window instance
+function TinyMCE_Window() {
+};
+
+TinyMCE_Window.prototype.focus = function() {
+	if (this != mcWindows.selectedWindow) {
+		this.winElement.style.zIndex = ++mcWindows.zindex;
+		mcWindows.lastSelectedWindow = mcWindows.selectedWindow;
+		mcWindows.selectedWindow = this;
+	}
+};
+
+TinyMCE_Window.prototype.minimize = function() {
+};
+
+TinyMCE_Window.prototype.maximize = function() {
+	if (this.restoreSize) {
+		this.moveTo(this.restoreSize[0], this.restoreSize[1]);
+		this.resizeTo(this.restoreSize[2], this.restoreSize[3]);
+		this.updateClamping();
+		this.restoreSize = null;
+	} else {
+		var bounds = mcWindows.getBounds();
+		this.restoreSize = [
+			this.left, this.top,
+			this.winElement.scrollWidth,
+			this.winElement.scrollHeight
+		];
+		this.moveTo(bounds[0], bounds[1]);
+		this.resizeTo(
+			bounds[2] - bounds[0],
+			bounds[3] - bounds[1]
+		);
+	}
+};
+
+TinyMCE_Window.prototype.startResize = function() {
+	mcWindows.action = "resize";
+};
+
+TinyMCE_Window.prototype.startMove = function(e) {
+	mcWindows.action = "move";
+};
+
+TinyMCE_Window.prototype.close = function() {
+	if (this.frame && this.frame['tinyMCEPopup'])
+		this.frame['tinyMCEPopup'].restoreSelection();
+
+	if (mcWindows.lastSelectedWindow != null)
+		mcWindows.lastSelectedWindow.focus();
+
+	var mcWindowsNew = new Array();
+	for (var n in mcWindows.windows) {
+		var win = mcWindows.windows[n];
+		if (typeof(win) == 'function')
+			continue;
+
+		if (win.name != this.name)
+			mcWindowsNew[n] = win;
+	}
+
+	mcWindows.windows = mcWindowsNew;
+
+	// alert(mcWindows.doc.getElementById(this.id + "_iframe"));
+
+	var e = mcWindows.doc.getElementById(this.id + "_iframe");
+	e.parentNode.removeChild(e);
+
+	var e = mcWindows.doc.getElementById(this.id + "_div");
+	e.parentNode.removeChild(e);
+
+	mcWindows.setDocumentLock(false);
+};
+
+TinyMCE_Window.prototype.onMouseMove = function(e) {
+	var clamp;
+	// Calculate real X, Y
+	var dx = e.screenX - mcWindows.mouseDownScreenX;
+	var dy = e.screenY - mcWindows.mouseDownScreenY;
+
+	switch (mcWindows.action) {
+		case "resize":
+			clamp = mcWindows.clampBoxSize(
+				this.left, this.top,
+				mcWindows.mouseDownWidth + (e.screenX - mcWindows.mouseDownScreenX),
+				mcWindows.mouseDownHeight + (e.screenY - mcWindows.mouseDownScreenY),
+				this.features.minWidth, this.features.minHeight
+			);
+
+			this.resizeTo(clamp[2], clamp[3]);
+
+			mcWindows.cancelEvent(e);
+			break;
+
+		case "move":
+			this.left = mcWindows.mouseDownLayerX + (e.screenX - mcWindows.mouseDownScreenX);
+			this.top = mcWindows.mouseDownLayerY + (e.screenY - mcWindows.mouseDownScreenY);
+			this.updateClamping();
+
+			mcWindows.cancelEvent(e);
+			break;
+	}
+};
+
+TinyMCE_Window.prototype.moveTo = function (x, y) {
+	this.left = x;
+	this.top = y;
+
+	this.winElement.style.left = this.left + "px";
+	this.winElement.style.top = this.top + "px";
+};
+
+TinyMCE_Window.prototype.resizeTo = function (width, height) {
+	this.wrapperIFrameElement.style.width = (width+2) + 'px';
+	this.wrapperIFrameElement.style.height = (height+2) + 'px';
+	this.wrapperIFrameElement.width = width+2;
+	this.wrapperIFrameElement.height = height+2;
+	this.winElement.style.width = width + 'px';
+	this.winElement.style.height = height + 'px';
+
+	height = height - this.deltaHeight;
+
+	this.containerElement.style.width = width + 'px';
+	this.iframeElement.style.width = width + 'px';
+	this.iframeElement.style.height = height + 'px';
+	this.bodyElement.style.width = width + 'px';
+	this.bodyElement.style.height = height + 'px';
+	this.headElement.style.width = width + 'px';
+	//this.statusElement.style.width = width + 'px';
+};
+
+TinyMCE_Window.prototype.updateClamping = function () {
+	var clamp, oversize;
+
+	clamp = mcWindows.clampBoxPosition(
+		this.left, this.top,
+		this.winElement.scrollWidth,
+		this.winElement.scrollHeight,
+		this.features.minWidth, this.features.minHeight
+	);
+	oversize = (
+		clamp[2] != this.winElement.scrollWidth ||
+		clamp[3] != this.winElement.scrollHeight
+	) ? true : false;
+
+	this.moveTo(clamp[0], clamp[1]);
+	if (this.features.resizable == "yes" && oversize)
+		this.resizeTo(clamp[2], clamp[3]);
+};
+
+function debug(msg) {
+	document.getElementById('debug').value += msg + "\n";
+}
+
+TinyMCE_Window.prototype.onMouseUp = function(e) {
+	mcWindows.action = "none";
+};
+
+TinyMCE_Window.prototype.onFocus = function(e) {
+	// Gecko only handler
+	var winRef = e.currentTarget;
+
+	for (var n in mcWindows.windows) {
+		var win = mcWindows.windows[n];
+		if (typeof(win) == 'function')
+			continue;
+
+		if (winRef.name == win.id + "_iframe") {
+			win.focus();
+			return;
+		}
+	}
+};
+
+TinyMCE_Window.prototype.onMouseDown = function(e) {
+	var elm = mcWindows.isMSIE ? this.wrapperFrame.event.srcElement : e.target;
+
+	mcWindows.mouseDownScreenX = e.screenX;
+	mcWindows.mouseDownScreenY = e.screenY;
+	mcWindows.mouseDownLayerX = this.left;
+	mcWindows.mouseDownLayerY = this.top;
+	mcWindows.mouseDownWidth = parseInt(this.winElement.style.width);
+	mcWindows.mouseDownHeight = parseInt(this.winElement.style.height);
+
+	if (this.resizeElement != null && elm == this.resizeElement.firstChild)
+		this.startResize(e);
+	else
+		this.startMove(e);
+
+	mcWindows.cancelEvent(e);
+};
+
+// Global instance
+var mcWindows = new TinyMCE_Windows();
+
+// Initialize windows
+mcWindows.init({
+	images_path : tinyMCE.baseURL + "/plugins/inlinepopups/images",
+	css_file : tinyMCE.baseURL + "/plugins/inlinepopups/css/inlinepopup.css"
+});
Binary file includes/clientside/tinymce/plugins/inlinepopups/images/spacer.gif has changed
Binary file includes/clientside/tinymce/plugins/inlinepopups/images/window_close.gif has changed
Binary file includes/clientside/tinymce/plugins/inlinepopups/images/window_maximize.gif has changed
Binary file includes/clientside/tinymce/plugins/inlinepopups/images/window_minimize.gif has changed
Binary file includes/clientside/tinymce/plugins/inlinepopups/images/window_resize.gif has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/inlinepopups/jscripts/mcwindows.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,453 @@
+/**
+ * $Id: mcwindows.js 18 2006-06-29 14:11:23Z spocke $
+ *
+ * Moxiecode DHTML Windows script.
+ *
+ * @author Moxiecode
+ * @copyright Copyright © 2004, Moxiecode Systems AB, All rights reserved.
+ */
+
+// Windows handler
+function MCWindows() {
+	this.settings = new Array();
+	this.windows = new Array();
+	this.isMSIE = (navigator.appName == "Microsoft Internet Explorer");
+	this.isGecko = navigator.userAgent.indexOf('Gecko') != -1;
+	this.isSafari = navigator.userAgent.indexOf('Safari') != -1;
+	this.isMac = navigator.userAgent.indexOf('Mac') != -1;
+	this.isMSIE5_0 = this.isMSIE && (navigator.userAgent.indexOf('MSIE 5.0') != -1);
+	this.action = "none";
+	this.selectedWindow = null;
+	this.zindex = 100;
+	this.mouseDownScreenX = 0;
+	this.mouseDownScreenY = 0;
+	this.mouseDownLayerX = 0;
+	this.mouseDownLayerY = 0;
+	this.mouseDownWidth = 0;
+	this.mouseDownHeight = 0;
+};
+
+MCWindows.prototype.init = function(settings) {
+	this.settings = settings;
+
+	if (this.isMSIE)
+		this.addEvent(document, "mousemove", mcWindows.eventDispatcher);
+	else
+		this.addEvent(window, "mousemove", mcWindows.eventDispatcher);
+
+	this.addEvent(document, "mouseup", mcWindows.eventDispatcher);
+};
+
+MCWindows.prototype.getParam = function(name, default_value) {
+	var value = null;
+
+	value = (typeof(this.settings[name]) == "undefined") ? default_value : this.settings[name];
+
+	// Fix bool values
+	if (value == "true" || value == "false")
+		return (value == "true");
+
+	return value;
+};
+
+MCWindows.prototype.eventDispatcher = function(e) {
+	e = typeof(e) == "undefined" ? window.event : e;
+
+	if (mcWindows.selectedWindow == null)
+		return;
+
+	// Switch focus
+	if (mcWindows.isGecko && e.type == "mousedown") {
+		var elm = e.currentTarget;
+
+		for (var n in mcWindows.windows) {
+			var win = mcWindows.windows[n];
+			if (typeof(win) == 'function')
+				continue;
+
+			if (win.headElement == elm || win.resizeElement == elm) {
+				win.focus();
+				break;
+			}
+		}
+	}
+
+	switch (e.type) {
+		case "mousemove":
+			mcWindows.selectedWindow.onMouseMove(e);
+			break;
+
+		case "mouseup":
+			mcWindows.selectedWindow.onMouseUp(e);
+			break;
+
+		case "mousedown":
+			mcWindows.selectedWindow.onMouseDown(e);
+			break;
+
+		case "focus":
+			mcWindows.selectedWindow.onFocus(e);
+			break;
+	}
+}
+
+MCWindows.prototype.addEvent = function(obj, name, handler) {
+	if (this.isMSIE)
+		obj.attachEvent("on" + name, handler);
+	else
+		obj.addEventListener(name, handler, true);
+};
+
+MCWindows.prototype.cancelEvent = function(e) {
+	if (this.isMSIE) {
+		e.returnValue = false;
+		e.cancelBubble = true;
+	} else
+		e.preventDefault();
+};
+
+MCWindows.prototype.parseFeatures = function(opts) {
+	// Cleanup the options
+	opts = opts.toLowerCase();
+	opts = opts.replace(/;/g, ",");
+	opts = opts.replace(/[^0-9a-z=,]/g, "");
+
+	var optionChunks = opts.split(',');
+	var options = new Array();
+
+	options['left'] = 10;
+	options['top'] = 10;
+	options['width'] = 300;
+	options['height'] = 300;
+	options['resizable'] = true;
+	options['minimizable'] = true;
+	options['maximizable'] = true;
+	options['close'] = true;
+	options['movable'] = true;
+
+	if (opts == "")
+		return options;
+
+	for (var i=0; i<optionChunks.length; i++) {
+		var parts = optionChunks[i].split('=');
+
+		if (parts.length == 2)
+			options[parts[0]] = parts[1];
+	}
+
+	return options;
+};
+
+MCWindows.prototype.open = function(url, name, features) {
+	var win = new MCWindow();
+	var winDiv, html = "", id;
+
+	features = this.parseFeatures(features);
+
+	// Create div
+	id = "mcWindow_" + name;
+
+	width = parseInt(features['width']);
+	height = parseInt(features['height'])-12-19;
+
+	if (this.isMSIE)
+		width -= 2;
+
+	// Setup first part of window
+	win.id = id;
+	win.url = url;
+	win.name = name;
+	win.features = features;
+	this.windows[name] = win;
+
+	iframeWidth = width;
+	iframeHeight = height;
+
+	// Create inner content
+	html += '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">';
+	html += '<html>';
+	html += '<head>';
+	html += '<title>Wrapper iframe</title>';
+	html += '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">';
+	html += '<link href="../jscripts/tiny_mce/themes/advanced/css/editor_ui.css" rel="stylesheet" type="text/css" />';
+	html += '</head>';
+	html += '<body onload="parent.mcWindows.onLoad(\'' + name + '\');">';
+
+	html += '<div id="' + id + '_container" class="mceWindow">';
+	html += '<div id="' + id + '_head" class="mceWindowHead" onmousedown="parent.mcWindows.windows[\'' + name + '\'].focus();">';
+	html += '  <div id="' + id + '_title" class="mceWindowTitle"';
+	html += '  onselectstart="return false;" unselectable="on" style="-moz-user-select: none !important;">No name window</div>';
+	html += '    <div class="mceWindowHeadTools">';
+	html += '      <a href="javascript:parent.mcWindows.windows[\'' + name + '\'].close();" onmousedown="return false;" class="mceWindowClose"><img border="0" src="../jscripts/tiny_mce/themes/advanced/images/window_close.gif" /></a>';
+//	html += '      <a href="javascript:mcWindows.windows[\'' + name + '\'].maximize();" onmousedown="return false;" class="mceWindowMaximize"></a>';
+//	html += '      <a href="javascript:mcWindows.windows[\'' + name + '\'].minimize();" onmousedown="return false;" class="mceWindowMinimize"></a>';
+	html += '    </div>';
+	html += '</div><div id="' + id + '_body" class="mceWindowBody" style="width: ' + width + 'px; height: ' + height + 'px;">';
+	html += '<iframe id="' + id + '_iframe" name="' + id + '_iframe" onfocus="parent.mcWindows.windows[\'' + name + '\'].focus();" frameborder="0" width="' + iframeWidth + '" height="' + iframeHeight + '" src="' + url + '" class="mceWindowBodyIframe"></iframe></div>';
+	html += '<div id="' + id + '_statusbar" class="mceWindowStatusbar" onmousedown="parent.mcWindows.windows[\'' + name + '\'].focus();">';
+	html += '<div id="' + id + '_resize" class="mceWindowResize"><img onmousedown="parent.mcWindows.windows[\'' + name + '\'].focus();" border="0" src="../jscripts/tiny_mce/themes/advanced/images/window_resize.gif" /></div>';
+	html += '</div>';
+	html += '</div>';
+
+	html += '</body>';
+	html += '</html>';
+
+	// Create iframe
+	this.createFloatingIFrame(id, features['left'], features['top'], features['width'], features['height'], html);
+};
+
+// Gets called when wrapper iframe is initialized
+MCWindows.prototype.onLoad = function(name) {
+	var win = mcWindows.windows[name];
+	var id = "mcWindow_" + name;
+	var wrapperIframe = window.frames[id + "_iframe"].frames[0];
+	var wrapperDoc = window.frames[id + "_iframe"].document;
+	var doc = window.frames[id + "_iframe"].document;
+	var winDiv = document.getElementById("mcWindow_" + name + "_div");
+	var realIframe = window.frames[id + "_iframe"].frames[0];
+
+	// Set window data
+	win.id = "mcWindow_" + name + "_iframe";
+	win.winElement = winDiv;
+	win.bodyElement = doc.getElementById(id + '_body');
+	win.iframeElement = doc.getElementById(id + '_iframe');
+	win.headElement = doc.getElementById(id + '_head');
+	win.titleElement = doc.getElementById(id + '_title');
+	win.resizeElement = doc.getElementById(id + '_resize');
+	win.containerElement = doc.getElementById(id + '_container');
+	win.left = win.features['left'];
+	win.top = win.features['top'];
+	win.frame = window.frames[id + '_iframe'].frames[0];
+	win.wrapperFrame = window.frames[id + '_iframe'];
+	win.wrapperIFrameElement = document.getElementById(id + "_iframe");
+
+	// Add event handlers
+	mcWindows.addEvent(win.headElement, "mousedown", mcWindows.eventDispatcher);
+	mcWindows.addEvent(win.resizeElement, "mousedown", mcWindows.eventDispatcher);
+
+	if (mcWindows.isMSIE) {
+		mcWindows.addEvent(realIframe.document, "mousemove", mcWindows.eventDispatcher);
+		mcWindows.addEvent(realIframe.document, "mouseup", mcWindows.eventDispatcher);
+	} else {
+		mcWindows.addEvent(realIframe, "mousemove", mcWindows.eventDispatcher);
+		mcWindows.addEvent(realIframe, "mouseup", mcWindows.eventDispatcher);
+		mcWindows.addEvent(realIframe, "focus", mcWindows.eventDispatcher);
+	}
+
+	for (var i=0; i<window.frames.length; i++) {
+		if (!window.frames[i]._hasMouseHandlers) {
+			if (mcWindows.isMSIE) {
+				mcWindows.addEvent(window.frames[i].document, "mousemove", mcWindows.eventDispatcher);
+				mcWindows.addEvent(window.frames[i].document, "mouseup", mcWindows.eventDispatcher);
+			} else {
+				mcWindows.addEvent(window.frames[i], "mousemove", mcWindows.eventDispatcher);
+				mcWindows.addEvent(window.frames[i], "mouseup", mcWindows.eventDispatcher);
+			}
+
+			window.frames[i]._hasMouseHandlers = true;
+		}
+	}
+
+	if (mcWindows.isMSIE) {
+		mcWindows.addEvent(win.frame.document, "mousemove", mcWindows.eventDispatcher);
+		mcWindows.addEvent(win.frame.document, "mouseup", mcWindows.eventDispatcher);
+	} else {
+		mcWindows.addEvent(win.frame, "mousemove", mcWindows.eventDispatcher);
+		mcWindows.addEvent(win.frame, "mouseup", mcWindows.eventDispatcher);
+		mcWindows.addEvent(win.frame, "focus", mcWindows.eventDispatcher);
+	}
+
+	this.selectedWindow = win;
+};
+
+MCWindows.prototype.createFloatingIFrame = function(id_prefix, left, top, width, height, html) {
+	var iframe = document.createElement("iframe");
+	var div = document.createElement("div");
+
+	width = parseInt(width);
+	height = parseInt(height)+1;
+
+	// Create wrapper div
+	div.setAttribute("id", id_prefix + "_div");
+	div.setAttribute("width", width);
+	div.setAttribute("height", (height));
+	div.style.position = "absolute";
+	div.style.left = left + "px";
+	div.style.top = top + "px";
+	div.style.width = width + "px";
+	div.style.height = (height) + "px";
+	div.style.backgroundColor = "white";
+	div.style.display = "none";
+
+	if (this.isGecko) {
+		iframeWidth = width + 2;
+		iframeHeight = height + 2;
+	} else {
+		iframeWidth = width;
+		iframeHeight = height + 1;
+	}
+
+	// Create iframe
+	iframe.setAttribute("id", id_prefix + "_iframe");
+	iframe.setAttribute("name", id_prefix + "_iframe");
+	iframe.setAttribute("border", "0");
+	iframe.setAttribute("frameBorder", "0");
+	iframe.setAttribute("marginWidth", "0");
+	iframe.setAttribute("marginHeight", "0");
+	iframe.setAttribute("leftMargin", "0");
+	iframe.setAttribute("topMargin", "0");
+	iframe.setAttribute("width", iframeWidth);
+	iframe.setAttribute("height", iframeHeight);
+//	iframe.setAttribute("src", "../jscripts/tiny_mce/blank.htm");
+	// iframe.setAttribute("allowtransparency", "false");
+	iframe.setAttribute("scrolling", "no");
+	iframe.style.width = iframeWidth + "px";
+	iframe.style.height = iframeHeight + "px";
+	iframe.style.backgroundColor = "white";
+	div.appendChild(iframe);
+
+	document.body.appendChild(div);
+
+	// Fixed MSIE 5.0 issue
+	div.innerHTML = div.innerHTML;
+
+	if (this.isSafari) {
+		// Give Safari some time to setup
+		window.setTimeout(function() {
+			doc = window.frames[id_prefix + '_iframe'].document;
+			doc.open();
+			doc.write(html);
+			doc.close();
+		}, 10);
+	} else {
+		doc = window.frames[id_prefix + '_iframe'].window.document
+		doc.open();
+		doc.write(html);
+		doc.close();
+	}
+
+	div.style.display = "block";
+
+	return div;
+};
+
+// Window instance
+function MCWindow() {
+};
+
+MCWindow.prototype.focus = function() {
+	this.winElement.style.zIndex = mcWindows.zindex++;
+	mcWindows.selectedWindow = this;
+};
+
+MCWindow.prototype.minimize = function() {
+};
+
+MCWindow.prototype.maximize = function() {
+	
+};
+
+MCWindow.prototype.startResize = function() {
+	mcWindows.action = "resize";
+};
+
+MCWindow.prototype.startMove = function(e) {
+	mcWindows.action = "move";
+};
+
+MCWindow.prototype.close = function() {
+	document.body.removeChild(this.winElement);
+	mcWindows.windows[this.name] = null;
+};
+
+MCWindow.prototype.onMouseMove = function(e) {
+	var scrollX = 0;//this.doc.body.scrollLeft;
+	var scrollY = 0;//this.doc.body.scrollTop;
+
+	// Calculate real X, Y
+	var dx = e.screenX - mcWindows.mouseDownScreenX;
+	var dy = e.screenY - mcWindows.mouseDownScreenY;
+
+	switch (mcWindows.action) {
+		case "resize":
+			width = mcWindows.mouseDownWidth + (e.screenX - mcWindows.mouseDownScreenX);
+			height = mcWindows.mouseDownHeight + (e.screenY - mcWindows.mouseDownScreenY);
+
+			width = width < 100 ? 100 : width;
+			height = height < 100 ? 100 : height;
+
+			this.wrapperIFrameElement.style.width = width+2;
+			this.wrapperIFrameElement.style.height = height+2;
+			this.wrapperIFrameElement.width = width+2;
+			this.wrapperIFrameElement.height = height+2;
+			this.winElement.style.width = width;
+			this.winElement.style.height = height;
+
+			height = height-12-19;
+
+			this.containerElement.style.width = width;
+
+			this.iframeElement.style.width = width;
+			this.iframeElement.style.height = height;
+			this.bodyElement.style.width = width;
+			this.bodyElement.style.height = height;
+			this.headElement.style.width = width;
+			//this.statusElement.style.width = width;
+
+			mcWindows.cancelEvent(e);
+			break;
+
+		case "move":
+			this.left = mcWindows.mouseDownLayerX + (e.screenX - mcWindows.mouseDownScreenX);
+			this.top = mcWindows.mouseDownLayerY + (e.screenY - mcWindows.mouseDownScreenY);
+			this.winElement.style.left = this.left + "px";
+			this.winElement.style.top = this.top + "px";
+
+			mcWindows.cancelEvent(e);
+			break;
+	}
+};
+
+MCWindow.prototype.onMouseUp = function(e) {
+	mcWindows.action = "none";
+};
+
+MCWindow.prototype.onFocus = function(e) {
+	// Gecko only handler
+	var winRef = e.currentTarget;
+
+	for (var n in mcWindows.windows) {
+		var win = mcWindows.windows[n];
+		if (typeof(win) == 'function')
+			continue;
+
+		if (winRef.name == win.id) {
+			win.focus();
+			return;
+		}
+	}
+};
+
+MCWindow.prototype.onMouseDown = function(e) {
+	var elm = mcWindows.isMSIE ? this.wrapperFrame.event.srcElement : e.target;
+
+	var scrollX = 0;//this.doc.body.scrollLeft;
+	var scrollY = 0;//this.doc.body.scrollTop;
+
+	mcWindows.mouseDownScreenX = e.screenX;
+	mcWindows.mouseDownScreenY = e.screenY;
+	mcWindows.mouseDownLayerX = this.left;
+	mcWindows.mouseDownLayerY = this.top;
+	mcWindows.mouseDownWidth = parseInt(this.winElement.style.width);
+	mcWindows.mouseDownHeight = parseInt(this.winElement.style.height);
+
+	if (elm == this.resizeElement.firstChild)
+		this.startResize(e);
+	else
+		this.startMove(e);
+
+	mcWindows.cancelEvent(e);
+};
+
+// Global instance
+var mcWindows = new MCWindows();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/insertdatetime/editor_plugin.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+tinyMCE.importPluginLanguagePack('insertdatetime');var TinyMCE_InsertDateTimePlugin={getInfo:function(){return{longname:'Insert date/time',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/insertdatetime',version:tinyMCE.majorVersion+"."+tinyMCE.minorVersion}},getControlHTML:function(cn){switch(cn){case"insertdate":return tinyMCE.getButtonHTML(cn,'lang_insertdate_desc','{$pluginurl}/images/insertdate.gif','mceInsertDate');case"inserttime":return tinyMCE.getButtonHTML(cn,'lang_inserttime_desc','{$pluginurl}/images/inserttime.gif','mceInsertTime')}return""},execCommand:function(editor_id,element,command,user_interface,value){function addZeros(value,len){value=""+value;if(value.length<len){for(var i=0;i<(len-value.length);i++)value="0"+value}return value}function getDateTime(d,fmt){fmt=fmt.replace("%D","%m/%d/%y");fmt=fmt.replace("%r","%I:%M:%S %p");fmt=fmt.replace("%Y",""+d.getFullYear());fmt=fmt.replace("%y",""+d.getYear());fmt=fmt.replace("%m",addZeros(d.getMonth()+1,2));fmt=fmt.replace("%d",addZeros(d.getDate(),2));fmt=fmt.replace("%H",""+addZeros(d.getHours(),2));fmt=fmt.replace("%M",""+addZeros(d.getMinutes(),2));fmt=fmt.replace("%S",""+addZeros(d.getSeconds(),2));fmt=fmt.replace("%I",""+((d.getHours()+11)%12+1));fmt=fmt.replace("%p",""+(d.getHours()<12?"AM":"PM"));fmt=fmt.replace("%B",""+tinyMCE.getLang("lang_inserttime_months_long")[d.getMonth()]);fmt=fmt.replace("%b",""+tinyMCE.getLang("lang_inserttime_months_short")[d.getMonth()]);fmt=fmt.replace("%A",""+tinyMCE.getLang("lang_inserttime_day_long")[d.getDay()]);fmt=fmt.replace("%a",""+tinyMCE.getLang("lang_inserttime_day_short")[d.getDay()]);fmt=fmt.replace("%%","%");return fmt}switch(command){case"mceInsertDate":tinyMCE.execInstanceCommand(editor_id,'mceInsertContent',false,getDateTime(new Date(),tinyMCE.getParam("plugin_insertdate_dateFormat",tinyMCE.getLang('lang_insertdate_def_fmt'))));return true;case"mceInsertTime":tinyMCE.execInstanceCommand(editor_id,'mceInsertContent',false,getDateTime(new Date(),tinyMCE.getParam("plugin_insertdate_timeFormat",tinyMCE.getLang('lang_inserttime_def_fmt'))));return true}return false}};tinyMCE.addPlugin("insertdatetime",TinyMCE_InsertDateTimePlugin);
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/insertdatetime/editor_plugin_src.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,90 @@
+/**
+ * $Id: editor_plugin_src.js 201 2007-02-12 15:56:56Z spocke $
+ *
+ * @author Moxiecode
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+/* Import plugin specific language pack */
+tinyMCE.importPluginLanguagePack('insertdatetime');
+
+var TinyMCE_InsertDateTimePlugin = {
+	getInfo : function() {
+		return {
+			longname : 'Insert date/time',
+			author : 'Moxiecode Systems AB',
+			authorurl : 'http://tinymce.moxiecode.com',
+			infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/insertdatetime',
+			version : tinyMCE.majorVersion + "." + tinyMCE.minorVersion
+		};
+	},
+
+	/**
+	 * Returns the HTML contents of the insertdate, inserttime controls.
+	 */
+	getControlHTML : function(cn) {
+		switch (cn) {
+			case "insertdate":
+				return tinyMCE.getButtonHTML(cn, 'lang_insertdate_desc', '{$pluginurl}/images/insertdate.gif', 'mceInsertDate');
+
+			case "inserttime":
+				return tinyMCE.getButtonHTML(cn, 'lang_inserttime_desc', '{$pluginurl}/images/inserttime.gif', 'mceInsertTime');
+		}
+
+		return "";
+	},
+
+	/**
+	 * Executes the mceInsertDate command.
+	 */
+	execCommand : function(editor_id, element, command, user_interface, value) {
+		/* Adds zeros infront of value */
+		function addZeros(value, len) {
+			value = "" + value;
+
+			if (value.length < len) {
+				for (var i=0; i<(len-value.length); i++)
+					value = "0" + value;
+			}
+
+			return value;
+		}
+
+		function getDateTime(d, fmt) {
+			fmt = fmt.replace("%D", "%m/%d/%y");
+			fmt = fmt.replace("%r", "%I:%M:%S %p");
+			fmt = fmt.replace("%Y", "" + d.getFullYear());
+			fmt = fmt.replace("%y", "" + d.getYear());
+			fmt = fmt.replace("%m", addZeros(d.getMonth()+1, 2));
+			fmt = fmt.replace("%d", addZeros(d.getDate(), 2));
+			fmt = fmt.replace("%H", "" + addZeros(d.getHours(), 2));
+			fmt = fmt.replace("%M", "" + addZeros(d.getMinutes(), 2));
+			fmt = fmt.replace("%S", "" + addZeros(d.getSeconds(), 2));
+			fmt = fmt.replace("%I", "" + ((d.getHours() + 11) % 12 + 1));
+			fmt = fmt.replace("%p", "" + (d.getHours() < 12 ? "AM" : "PM"));
+			fmt = fmt.replace("%B", "" + tinyMCE.getLang("lang_inserttime_months_long")[d.getMonth()]);
+			fmt = fmt.replace("%b", "" + tinyMCE.getLang("lang_inserttime_months_short")[d.getMonth()]);
+			fmt = fmt.replace("%A", "" + tinyMCE.getLang("lang_inserttime_day_long")[d.getDay()]);
+			fmt = fmt.replace("%a", "" + tinyMCE.getLang("lang_inserttime_day_short")[d.getDay()]);
+			fmt = fmt.replace("%%", "%");
+
+			return fmt;
+		}
+
+		// Handle commands
+		switch (command) {
+			case "mceInsertDate":
+				tinyMCE.execInstanceCommand(editor_id, 'mceInsertContent', false, getDateTime(new Date(), tinyMCE.getParam("plugin_insertdate_dateFormat", tinyMCE.getLang('lang_insertdate_def_fmt'))));
+				return true;
+
+			case "mceInsertTime":
+				tinyMCE.execInstanceCommand(editor_id, 'mceInsertContent', false, getDateTime(new Date(), tinyMCE.getParam("plugin_insertdate_timeFormat", tinyMCE.getLang('lang_inserttime_def_fmt'))));
+				return true;
+		}
+
+		// Pass to next handler in chain
+		return false;
+	}
+};
+
+tinyMCE.addPlugin("insertdatetime", TinyMCE_InsertDateTimePlugin);
Binary file includes/clientside/tinymce/plugins/insertdatetime/images/insertdate.gif has changed
Binary file includes/clientside/tinymce/plugins/insertdatetime/images/inserttime.gif has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/insertdatetime/langs/en.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,12 @@
+// UK lang variables
+
+tinyMCE.addToLang('',{
+insertdate_def_fmt : '%Y-%m-%d',
+inserttime_def_fmt : '%H:%M:%S',
+insertdate_desc : 'Insert date',
+inserttime_desc : 'Insert time',
+inserttime_months_long : new Array("January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"),
+inserttime_months_short : new Array("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"),
+inserttime_day_long : new Array("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"),
+inserttime_day_short : new Array("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun")
+});
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/insertdatetime/readme.txt	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+Check the TinyMCE documentation for details on this plugin.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/layer/editor_plugin.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+tinyMCE.importPluginLanguagePack('layer');var TinyMCE_LayerPlugin={getInfo:function(){return{longname:'Layer',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/layer',version:tinyMCE.majorVersion+"."+tinyMCE.minorVersion}},initInstance:function(inst){if(tinyMCE.isMSIE&&!tinyMCE.isOpera)inst.getDoc().execCommand('2D-Position')},handleEvent:function(e){var inst=tinyMCE.selectedInstance;var w=inst.getWin(),le=inst._lastStyleElm,e;if(tinyMCE.isGecko){e=this._getParentLayer(inst.getFocusElement());if(e){if(!inst._lastStyleElm){e.style.overflow='auto';inst._lastStyleElm=e}}else if(le){le=inst._lastStyleElm;le.style.width=le.scrollWidth+'px';le.style.height=le.scrollHeight+'px';le.style.overflow='';inst._lastStyleElm=null}}return true},handleVisualAid:function(el,deep,state,inst){var nl=inst.getDoc().getElementsByTagName("div"),i;for(i=0;i<nl.length;i++){if(new RegExp('absolute|relative|static','gi').test(nl[i].style.position)){if(state)tinyMCE.addCSSClass(nl[i],'mceVisualAid');else tinyMCE.removeCSSClass(nl[i],'mceVisualAid')}}},getControlHTML:function(cn){switch(cn){case"moveforward":return tinyMCE.getButtonHTML(cn,'lang_layer_forward_desc','{$pluginurl}/images/moveforward.gif','mceMoveForward',true);case"movebackward":return tinyMCE.getButtonHTML(cn,'lang_layer_backward_desc','{$pluginurl}/images/movebackward.gif','mceMoveBackward',true);case"absolute":return tinyMCE.getButtonHTML(cn,'lang_layer_absolute_desc','{$pluginurl}/images/absolute.gif','mceMakeAbsolute',true);case"insertlayer":return tinyMCE.getButtonHTML(cn,'lang_layer_insertlayer_desc','{$pluginurl}/images/insertlayer.gif','mceInsertLayer',true)}return""},execCommand:function(editor_id,element,command,user_interface,value){switch(command){case"mceInsertLayer":this._insertLayer();return true;case"mceMoveForward":this._move(1);return true;case"mceMoveBackward":this._move(-1);return true;case"mceMakeAbsolute":this._toggleAbsolute();return true}return false},handleNodeChange:function(editor_id,node,undo_index,undo_levels,visual_aid,any_selection){var inst=tinyMCE.getInstanceById(editor_id);var le=this._getParentLayer(inst.getFocusElement());var p=tinyMCE.getParentElement(inst.getFocusElement(),'div,p,img');tinyMCE.switchClass(editor_id+'_absolute','mceButtonDisabled');tinyMCE.switchClass(editor_id+'_moveforward','mceButtonDisabled');tinyMCE.switchClass(editor_id+'_movebackward','mceButtonDisabled');if(p)tinyMCE.switchClass(editor_id+'_absolute','mceButtonNormal');if(le&&le.style.position.toLowerCase()=="absolute"){tinyMCE.switchClass(editor_id+'_absolute','mceButtonSelected');tinyMCE.switchClass(editor_id+'_moveforward','mceButtonNormal');tinyMCE.switchClass(editor_id+'_movebackward','mceButtonNormal')}},_move:function(d){var inst=tinyMCE.selectedInstance,i,z=new Array();var le=this._getParentLayer(inst.getFocusElement()),ci=-1,fi=-1;var nl=tinyMCE.selectNodes(inst.getBody(),function(n){return n.nodeType==1&&new RegExp('absolute|relative|static','gi').test(n.style.position)});for(i=0;i<nl.length;i++){z[i]=nl[i].style.zIndex?parseInt(nl[i].style.zIndex):0;if(ci<0&&nl[i]==le)ci=i}if(d<0){for(i=0;i<z.length;i++){if(z[i]<z[ci]){fi=i;break}}if(fi>-1){nl[ci].style.zIndex=z[fi];nl[fi].style.zIndex=z[ci]}else{if(z[ci]>0)nl[ci].style.zIndex=z[ci]-1}}else{for(i=0;i<z.length;i++){if(z[i]>z[ci]){fi=i;break}}if(fi>-1){nl[ci].style.zIndex=z[fi];nl[fi].style.zIndex=z[ci]}else nl[ci].style.zIndex=z[ci]+1}inst.repaint()},_getParentLayer:function(n){return tinyMCE.getParentNode(n,function(n){return n.nodeType==1&&new RegExp('absolute|relative|static','gi').test(n.style.position)})},_insertLayer:function(){var inst=tinyMCE.selectedInstance;var e=tinyMCE.getParentElement(inst.getFocusElement());var p=tinyMCE.getAbsPosition(e);var d=inst.getDoc();var ne=d.createElement('div');var h=inst.selection.getSelectedHTML();ne.style.position='absolute';ne.style.left=p.absLeft+'px';ne.style.top=(p.absTop>20?p.absTop:20)+'px';ne.style.width='100px';ne.style.height='100px';ne.className='mceVisualAid';if(!h)h=tinyMCE.getLang('lang_layer_content');ne.innerHTML=h;d.body.appendChild(ne)},_toggleAbsolute:function(){var inst=tinyMCE.selectedInstance;var le=this._getParentLayer(inst.getFocusElement());if(le==null)le=tinyMCE.getParentElement(inst.getFocusElement(),'div,p,img');if(le){if(le.style.position.toLowerCase()=="absolute"){le.style.position="";le.style.left="";le.style.top=""}else{le.style.position="absolute";if(le.style.left=="")le.style.left=20+'px';if(le.style.top=="")le.style.top=20+'px';if(le.style.width=="")le.style.width=le.width?(le.width+'px'):'100px';if(le.style.height=="")le.style.height=le.height?(le.height+'px'):'100px';tinyMCE.handleVisualAid(inst.getBody(),true,inst.visualAid,inst)}inst.repaint();tinyMCE.triggerNodeChange()}}};tinyMCE.addPlugin("layer",TinyMCE_LayerPlugin);
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/layer/editor_plugin_src.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,248 @@
+/**
+ * $Id: editor_plugin_src.js 201 2007-02-12 15:56:56Z spocke $
+ *
+ * @author Moxiecode
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+/* Import plugin specific language pack */
+tinyMCE.importPluginLanguagePack('layer');
+
+var TinyMCE_LayerPlugin = {
+	getInfo : function() {
+		return {
+			longname : 'Layer',
+			author : 'Moxiecode Systems AB',
+			authorurl : 'http://tinymce.moxiecode.com',
+			infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/layer',
+			version : tinyMCE.majorVersion + "." + tinyMCE.minorVersion
+		};
+	},
+
+	initInstance : function(inst) {
+		if (tinyMCE.isMSIE && !tinyMCE.isOpera)
+			inst.getDoc().execCommand('2D-Position');
+	},
+
+	handleEvent : function(e) {
+		var inst = tinyMCE.selectedInstance;
+		var w = inst.getWin(), le = inst._lastStyleElm, e;
+
+		if (tinyMCE.isGecko) {
+			e = this._getParentLayer(inst.getFocusElement());
+
+			if (e) {
+				if (!inst._lastStyleElm) {
+					e.style.overflow = 'auto';
+					inst._lastStyleElm = e;
+				}
+			} else if (le) {
+				le = inst._lastStyleElm;
+				le.style.width = le.scrollWidth + 'px';
+				le.style.height = le.scrollHeight + 'px';
+				le.style.overflow = '';
+				inst._lastStyleElm = null;
+			}
+		}
+
+		return true;
+	},
+
+	handleVisualAid : function(el, deep, state, inst) {
+		var nl = inst.getDoc().getElementsByTagName("div"), i;
+
+		for (i=0; i<nl.length; i++) {
+			if (new RegExp('absolute|relative|static', 'gi').test(nl[i].style.position)) {
+				if (state)
+					tinyMCE.addCSSClass(nl[i], 'mceVisualAid');
+				else
+					tinyMCE.removeCSSClass(nl[i], 'mceVisualAid');					
+			}
+		}
+	},
+
+	getControlHTML : function(cn) {
+		switch (cn) {
+			case "moveforward":
+				return tinyMCE.getButtonHTML(cn, 'lang_layer_forward_desc', '{$pluginurl}/images/moveforward.gif', 'mceMoveForward', true);
+
+			case "movebackward":
+				return tinyMCE.getButtonHTML(cn, 'lang_layer_backward_desc', '{$pluginurl}/images/movebackward.gif', 'mceMoveBackward', true);
+
+			case "absolute":
+				return tinyMCE.getButtonHTML(cn, 'lang_layer_absolute_desc', '{$pluginurl}/images/absolute.gif', 'mceMakeAbsolute', true);
+
+			case "insertlayer":
+				return tinyMCE.getButtonHTML(cn, 'lang_layer_insertlayer_desc', '{$pluginurl}/images/insertlayer.gif', 'mceInsertLayer', true);
+		}
+
+		return "";
+	},
+
+	execCommand : function(editor_id, element, command, user_interface, value) {
+		// Handle commands
+		switch (command) {
+			case "mceInsertLayer":
+				this._insertLayer();
+				return true;
+
+			case "mceMoveForward":
+				this._move(1);
+				return true;
+
+			case "mceMoveBackward":
+				this._move(-1);
+				return true;
+
+			case "mceMakeAbsolute":
+				this._toggleAbsolute();
+				return true;
+		}
+
+		// Pass to next handler in chain
+		return false;
+	},
+
+	handleNodeChange : function(editor_id, node, undo_index, undo_levels, visual_aid, any_selection) {
+		var inst = tinyMCE.getInstanceById(editor_id);
+		var le = this._getParentLayer(inst.getFocusElement());
+		var p = tinyMCE.getParentElement(inst.getFocusElement(), 'div,p,img');
+
+		tinyMCE.switchClass(editor_id + '_absolute', 'mceButtonDisabled');
+		tinyMCE.switchClass(editor_id + '_moveforward', 'mceButtonDisabled');
+		tinyMCE.switchClass(editor_id + '_movebackward', 'mceButtonDisabled');
+
+		if (p)
+			tinyMCE.switchClass(editor_id + '_absolute', 'mceButtonNormal');
+
+		if (le && le.style.position.toLowerCase() == "absolute") {
+			tinyMCE.switchClass(editor_id + '_absolute', 'mceButtonSelected');
+			tinyMCE.switchClass(editor_id + '_moveforward', 'mceButtonNormal');
+			tinyMCE.switchClass(editor_id + '_movebackward', 'mceButtonNormal');
+		}
+	},
+
+	// Private plugin specific methods
+
+	_move : function(d) {
+		var inst = tinyMCE.selectedInstance, i, z = new Array();
+		var le = this._getParentLayer(inst.getFocusElement()), ci = -1, fi = -1;
+		var nl = tinyMCE.selectNodes(inst.getBody(), function(n) {
+			return n.nodeType == 1 && new RegExp('absolute|relative|static', 'gi').test(n.style.position);
+		});
+
+		// Find z-indexes
+		for (i=0; i<nl.length; i++) {
+			z[i] = nl[i].style.zIndex ? parseInt(nl[i].style.zIndex) : 0;
+
+			if (ci < 0 && nl[i] == le)
+				ci = i;
+		}
+
+		if (d < 0) {
+			// Move back
+
+			// Try find a lower one
+			for (i=0; i<z.length; i++) {
+				if (z[i] < z[ci]) {
+					fi = i;
+					break;
+				}
+			}
+
+			if (fi > -1) {
+				nl[ci].style.zIndex = z[fi];
+				nl[fi].style.zIndex = z[ci];
+			} else {
+				if (z[ci] > 0)
+					nl[ci].style.zIndex = z[ci] - 1;
+			}
+		} else {
+			// Move forward
+
+			// Try find a higher one
+			for (i=0; i<z.length; i++) {
+				if (z[i] > z[ci]) {
+					fi = i;
+					break;
+				}
+			}
+
+			if (fi > -1) {
+				nl[ci].style.zIndex = z[fi];
+				nl[fi].style.zIndex = z[ci];
+			} else
+				nl[ci].style.zIndex = z[ci] + 1;
+		}
+
+		inst.repaint();
+	},
+
+	_getParentLayer : function(n) {
+		return tinyMCE.getParentNode(n, function(n) {
+			return n.nodeType == 1 && new RegExp('absolute|relative|static', 'gi').test(n.style.position);
+		});
+	},
+
+	_insertLayer : function() {
+		var inst = tinyMCE.selectedInstance;
+		var e = tinyMCE.getParentElement(inst.getFocusElement());
+		var p = tinyMCE.getAbsPosition(e);
+		var d = inst.getDoc();
+		var ne = d.createElement('div');
+		var h = inst.selection.getSelectedHTML();
+
+		// Move div
+		ne.style.position = 'absolute';
+		ne.style.left = p.absLeft + 'px';
+		ne.style.top = (p.absTop > 20 ? p.absTop : 20) + 'px';
+		ne.style.width = '100px';
+		ne.style.height = '100px';
+		ne.className = 'mceVisualAid';
+
+		if (!h)
+			h = tinyMCE.getLang('lang_layer_content');
+
+		ne.innerHTML = h;
+
+		// Add it
+		d.body.appendChild(ne);
+	},
+
+	_toggleAbsolute : function() {
+		var inst = tinyMCE.selectedInstance;
+		var le = this._getParentLayer(inst.getFocusElement());
+
+		if (le == null)
+			le = tinyMCE.getParentElement(inst.getFocusElement(), 'div,p,img');
+
+		if (le) {
+			if (le.style.position.toLowerCase() == "absolute") {
+				le.style.position = "";
+				le.style.left = "";
+				le.style.top = "";
+			} else {
+				le.style.position = "absolute";
+
+				if (le.style.left == "")
+					le.style.left = 20 + 'px';
+
+				if (le.style.top == "")
+					le.style.top = 20 + 'px';
+
+				if (le.style.width == "")
+					le.style.width = le.width ? (le.width + 'px') : '100px';
+
+				if (le.style.height == "")
+					le.style.height = le.height ? (le.height + 'px') : '100px';
+
+				tinyMCE.handleVisualAid(inst.getBody(), true, inst.visualAid, inst);
+			}
+
+			inst.repaint();
+			tinyMCE.triggerNodeChange();
+		}
+	}
+};
+
+tinyMCE.addPlugin("layer", TinyMCE_LayerPlugin);
Binary file includes/clientside/tinymce/plugins/layer/images/absolute.gif has changed
Binary file includes/clientside/tinymce/plugins/layer/images/backward.gif has changed
Binary file includes/clientside/tinymce/plugins/layer/images/forward.gif has changed
Binary file includes/clientside/tinymce/plugins/layer/images/insert_layer.gif has changed
Binary file includes/clientside/tinymce/plugins/layer/images/insertlayer.gif has changed
Binary file includes/clientside/tinymce/plugins/layer/images/movebackward.gif has changed
Binary file includes/clientside/tinymce/plugins/layer/images/moveforward.gif has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/layer/langs/en.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,9 @@
+// UK lang variables
+
+tinyMCE.addToLang('layer',{
+insertlayer_desc : 'Insert new layer',
+forward_desc : 'Move forward',
+backward_desc : 'Move backward',
+absolute_desc : 'Toggle absolute positioning',
+content : 'New layer...'
+});
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/layer/readme.txt	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+Check the TinyMCE documentation for details on this plugin.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/media/css/content.css	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,26 @@
+.mceItemFlash, .mceItemShockWave, .mceItemQuickTime, .mceItemWindowsMedia, .mceItemRealMedia {
+	border: 1px dotted #cc0000;
+	background-position: center;
+	background-repeat: no-repeat;
+	background-color: #ffffcc;
+}
+
+.mceItemShockWave {
+	background-image: url('../images/shockwave.gif');
+}
+
+.mceItemFlash {
+	background-image: url('../images/flash.gif');
+}
+
+.mceItemQuickTime {
+	background-image: url('../images/quicktime.gif');
+}
+
+.mceItemWindowsMedia {
+	background-image: url('../images/windowsmedia.gif');
+}
+
+.mceItemRealMedia {
+	background-image: url('../images/realmedia.gif');
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/media/css/media.css	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,68 @@
+#id, #name, #hspace, #vspace, #class_name, #align {
+	width: 100px;
+}
+
+#hspace, #vspace {
+	width: 50px;
+}
+
+#flash_quality, #flash_align, #flash_scale, #flash_salign, #flash_wmode {
+	width: 100px;
+}
+
+#flash_base, #flash_flashvars {
+	width: 240px;
+}
+
+#width, #height {
+	width: 40px;
+}
+
+#src, #media_type {
+	width: 250px;
+}
+
+#class {
+	width: 120px;
+}
+
+#prev {
+	margin: 0;
+	border: 1px solid black;
+	width: 99%;
+	height: 230px;
+	overflow: auto;
+}
+
+.panel_wrapper div.current {
+	height: 390px;
+	overflow: auto;
+}
+
+#flash_options, #shockwave_options, #qt_options, #wmp_options, #rmp_options {
+	display: none;
+}
+
+.mceAddSelectValue {
+	background-color: #DDDDDD;
+}
+
+#qt_starttime, #qt_endtime, #qt_fov, #qt_href, #qt_moveid, #qt_moviename, #qt_node, #qt_pan, #qt_qtsrc, #qt_qtsrcchokespeed, #qt_target, #qt_tilt, #qt_urlsubstituten, #qt_volume {
+	width: 70px;
+}
+
+#wmp_balance, #wmp_baseurl, #wmp_captioningid, #wmp_currentmarker, #wmp_currentposition, #wmp_defaultframe, #wmp_playcount, #wmp_rate, #wmp_uimode, #wmp_volume {
+	width: 70px;
+}
+
+#rmp_console, #rmp_numloop, #rmp_controls, #rmp_scriptcallbacks {
+	width: 70px;
+}
+
+#shockwave_swvolume, #shockwave_swframe, #shockwave_swurl, #shockwave_swstretchvalign, #shockwave_swstretchhalign, #shockwave_swstretchstyle {
+	width: 90px;
+}
+
+#qt_qtsrc {
+	width: 200px;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/media/editor_plugin.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+tinyMCE.importPluginLanguagePack('media');var TinyMCE_MediaPlugin={getInfo:function(){return{longname:'Media',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/media',version:tinyMCE.majorVersion+"."+tinyMCE.minorVersion}},initInstance:function(inst){if(inst.hasPlugin('flash')&&!tinyMCE.flashWarn){alert('Flash plugin is deprecated and should not be used together with the media plugin.');tinyMCE.flashWarn=true}if(!tinyMCE.settings['media_skip_plugin_css'])tinyMCE.importCSS(inst.getDoc(),tinyMCE.baseURL+"/plugins/media/css/content.css")},getControlHTML:function(cn){switch(cn){case"media":return tinyMCE.getButtonHTML(cn,'lang_media_desc','{$pluginurl}/images/media.gif','mceMedia')}return""},execCommand:function(editor_id,element,command,user_interface,value){switch(command){case"mceMedia":tinyMCE.openWindow({file:'../../plugins/media/media.htm',width:430+tinyMCE.getLang('lang_media_delta_width',0),height:470+tinyMCE.getLang('lang_media_delta_height',0)},{editor_id:editor_id,inline:"yes"});return true}return false},cleanup:function(type,content,inst){var nl,img,i,ne,d,s,ci;switch(type){case"insert_to_editor":img=tinyMCE.getParam("theme_href")+'/images/spacer.gif';content=content.replace(/<script[^>]*>\s*write(Flash|ShockWave|WindowsMedia|QuickTime|RealMedia)\(\{([^\)]*)\}\);\s*<\/script>/gi,'<img class="mceItem$1" title="$2" src="'+img+'" />');content=content.replace(/<object([^>]*)>/gi,'<div class="mceItemObject" $1>');content=content.replace(/<embed([^>]*)>/gi,'<div class="mceItemObjectEmbed" $1>');content=content.replace(/<\/(object|embed)([^>]*)>/gi,'</div>');content=content.replace(/<param([^>]*)>/gi,'<div $1 class="mceItemParam"></div>');content=content.replace(new RegExp('\\/ class="mceItemParam"><\\/div>','gi'),'class="mceItemParam"></div>');break;case"insert_to_editor_dom":d=inst.getDoc();nl=content.getElementsByTagName("img");for(i=0;i<nl.length;i++){if(/mceItem(Flash|ShockWave|WindowsMedia|QuickTime|RealMedia)/.test(nl[i].className)){nl[i].width=nl[i].title.replace(/.*width:[^0-9]?([0-9]+)%?.*/g,'$1');nl[i].height=nl[i].title.replace(/.*height:[^0-9]?([0-9]+)%?.*/g,'$1');}}nl=tinyMCE.selectElements(content,'DIV',function(n){return tinyMCE.hasCSSClass(n,'mceItemObject')});for(i=0;i<nl.length;i++){ci=tinyMCE.getAttrib(nl[i],"classid").toLowerCase().replace(/\s+/g,'');switch(ci){case'clsid:d27cdb6e-ae6d-11cf-96b8-444553540000':nl[i].parentNode.replaceChild(TinyMCE_MediaPlugin._createImg('mceItemFlash',d,nl[i]),nl[i]);break;case'clsid:166b1bca-3f9c-11cf-8075-444553540000':nl[i].parentNode.replaceChild(TinyMCE_MediaPlugin._createImg('mceItemShockWave',d,nl[i]),nl[i]);break;case'clsid:6bf52a52-394a-11d3-b153-00c04f79faa6':nl[i].parentNode.replaceChild(TinyMCE_MediaPlugin._createImg('mceItemWindowsMedia',d,nl[i]),nl[i]);break;case'clsid:02bf25d5-8c17-4b23-bc80-d3488abddc6b':nl[i].parentNode.replaceChild(TinyMCE_MediaPlugin._createImg('mceItemQuickTime',d,nl[i]),nl[i]);break;case'clsid:cfcdaa03-8be4-11cf-b84b-0020afbbccfa':case'clsid:22d6f312-b0f6-11d0-94ab-0080c74c7e95':case'clsid:05589fa1-c356-11ce-bf01-00aa0055595a':nl[i].parentNode.replaceChild(TinyMCE_MediaPlugin._createImg('mceItemRealMedia',d,nl[i]),nl[i]);break}}nl=tinyMCE.selectNodes(content,function(n){return n.className=='mceItemObjectEmbed'});for(i=0;i<nl.length;i++){switch(tinyMCE.getAttrib(nl[i],'type')){case'application/x-shockwave-flash':TinyMCE_MediaPlugin._createImgFromEmbed(nl[i],d,'mceItemFlash');break;case'application/x-director':TinyMCE_MediaPlugin._createImgFromEmbed(nl[i],d,'mceItemShockWave');break;case'application/x-mplayer2':TinyMCE_MediaPlugin._createImgFromEmbed(nl[i],d,'mceItemWindowsMedia');break;case'video/quicktime':TinyMCE_MediaPlugin._createImgFromEmbed(nl[i],d,'mceItemQuickTime');break;case'audio/x-pn-realaudio-plugin':TinyMCE_MediaPlugin._createImgFromEmbed(nl[i],d,'mceItemRealMedia');break}}break;case"get_from_editor":var startPos=-1,endPos,attribs,chunkBefore,chunkAfter,embedHTML,at,pl,cb,mt,ex;while((startPos=content.indexOf('<img',startPos+1))!=-1){endPos=content.indexOf('/>',startPos);attribs=TinyMCE_MediaPlugin._parseAttributes(content.substring(startPos+4,endPos));if(!/mceItem(Flash|ShockWave|WindowsMedia|QuickTime|RealMedia)/.test(attribs['class']))continue;endPos+=2;at=attribs['title'];if(at){at=at.replace(/&(#39|apos);/g,"'");at=at.replace(/&#quot;/g,'"');try{pl=eval('x={'+at+'};')}catch(ex){pl={}}}if(!tinyMCE.getParam('media_use_script',false)){switch(attribs['class']){case'mceItemFlash':ci='d27cdb6e-ae6d-11cf-96b8-444553540000';cb='http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0';mt='application/x-shockwave-flash';break;case'mceItemShockWave':ci='166B1BCA-3F9C-11CF-8075-444553540000';cb='http://download.macromedia.com/pub/shockwave/cabs/director/sw.cab#version=8,5,1,0';mt='application/x-director';break;case'mceItemWindowsMedia':ci=tinyMCE.getParam('media_wmp6_compatible')?'05589FA1-C356-11CE-BF01-00AA0055595A':'6BF52A52-394A-11D3-B153-00C04F79FAA6';cb='http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=5,1,52,701';mt='application/x-mplayer2';break;case'mceItemQuickTime':ci='02BF25D5-8C17-4B23-BC80-D3488ABDDC6B';cb='http://www.apple.com/qtactivex/qtplugin.cab#version=6,0,2,0';mt='video/quicktime';break;case'mceItemRealMedia':ci='CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA';cb='http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0';mt='audio/x-pn-realaudio-plugin';break}if(!tinyMCE.getParam("relative_urls"))pl.src=tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'],pl.src);embedHTML=TinyMCE_MediaPlugin._getEmbed(ci,cb,mt,pl,attribs)}else{switch(attribs['class']){case'mceItemFlash':s='writeFlash';break;case'mceItemShockWave':s='writeShockWave';break;case'mceItemWindowsMedia':s='writeWindowsMedia';break;case'mceItemQuickTime':s='writeQuickTime';break;case'mceItemRealMedia':s='writeRealMedia';break}if(attribs.width)at=at.replace(/width:[^0-9]?[0-9]+%?[^0-9]?/g,"width:'"+attribs.width+"'");if(attribs.height)at=at.replace(/height:[^0-9]?[0-9]+%?[^0-9]?/g,"height:'"+attribs.height+"'");if(!tinyMCE.getParam("relative_urls")){pl.src=tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'],pl.src);at=at.replace(new RegExp("src:'[^']*'","g"),"src:'"+pl.src+"'")}embedHTML='<script type="text/javascript">'+s+'({'+at+'});</script>'}chunkBefore=content.substring(0,startPos);chunkAfter=content.substring(endPos);content=chunkBefore+embedHTML+chunkAfter}break}return content},handleNodeChange:function(editor_id,node,undo_index,undo_levels,visual_aid,any_selection){if(node==null)return;do{if(node.nodeName=="IMG"&&/mceItem(Flash|ShockWave|WindowsMedia|QuickTime|RealMedia)/.test(tinyMCE.getAttrib(node,'class'))){tinyMCE.switchClass(editor_id+'_media','mceButtonSelected');return true}}while((node=node.parentNode));tinyMCE.switchClass(editor_id+'_media','mceButtonNormal');return true},_createImgFromEmbed:function(n,d,cl){var ne,at,i,ti='',an;ne=d.createElement('img');ne.src=tinyMCE.getParam("theme_href")+'/images/spacer.gif';ne.width=tinyMCE.getAttrib(n,'width');ne.height=tinyMCE.getAttrib(n,'height');ne.className=cl;at=n.attributes;for(i=0;i<at.length;i++){if(at[i].specified&&at[i].nodeValue){an=at[i].nodeName.toLowerCase();if(an=='src')continue;if(an=='mce_src')an='src';if(an.indexOf('mce_')==-1&&!new RegExp('^(class|type)$').test(an))ti+=an.toLowerCase()+':\''+at[i].nodeValue+"',"}}ti=ti.length>0?ti.substring(0,ti.length-1):ti;ne.title=ti;n.parentNode.replaceChild(ne,n)},_createImg:function(cl,d,n){var i,nl,ti="",an,av,al=new Array();ne=d.createElement('img');ne.src=tinyMCE.getParam("theme_href")+'/images/spacer.gif';ne.width=tinyMCE.getAttrib(n,'width');ne.height=tinyMCE.getAttrib(n,'height');ne.className=cl;al.id=tinyMCE.getAttrib(n,'id');al.name=tinyMCE.getAttrib(n,'name');al.width=tinyMCE.getAttrib(n,'width');al.height=tinyMCE.getAttrib(n,'height');al.bgcolor=tinyMCE.getAttrib(n,'bgcolor');al.align=tinyMCE.getAttrib(n,'align');al.class_name=tinyMCE.getAttrib(n,'mce_class');nl=n.getElementsByTagName('div');for(i=0;i<nl.length;i++){av=tinyMCE.getAttrib(nl[i],'value');av=av.replace(new RegExp('\\\\','g'),'\\\\');av=av.replace(new RegExp('"','g'),'\\"');av=av.replace(new RegExp("'",'g'),"\\'");an=tinyMCE.getAttrib(nl[i],'name');al[an]=av}if(al.movie){al.src=al.movie;al.movie=null}for(an in al){if(al[an]!=null&&typeof(al[an])!="function"&&al[an]!='')ti+=an.toLowerCase()+':\''+al[an]+"',"}ti=ti.length>0?ti.substring(0,ti.length-1):ti;ne.title=ti;return ne},_getEmbed:function(cls,cb,mt,p,at){var h='',n;p.width=at.width?at.width:p.width;p.height=at.height?at.height:p.height;h+='<object classid="clsid:'+cls+'" codebase="'+cb+'"';h+=typeof(p.id)!="undefined"?' id="'+p.id+'"':'';h+=typeof(p.name)!="undefined"?' name="'+p.name+'"':'';h+=typeof(p.width)!="undefined"?' width="'+p.width+'"':'';h+=typeof(p.height)!="undefined"?' height="'+p.height+'"':'';h+=typeof(p.align)!="undefined"?' align="'+p.align+'"':'';h+='>';for(n in p){if(p[n]&&typeof(p[n])!="function"){h+='<param name="'+n+'" value="'+p[n]+'" />';if(n=='src'&&p[n].indexOf('://')!=-1&&mt=='application/x-mplayer2')h+='<param name="url" value="'+p[n]+'" />'}}h+='<embed type="'+mt+'"';for(n in p){if(typeof(p[n])=="function")continue;if(!(n=='url'&&mt=='application/x-mplayer2'))h+=' '+n+'="'+p[n]+'"'}h+='></embed></object>';return h},_parseAttributes:function(attribute_string){var attributeName="",endChr='"';var attributeValue="";var withInName;var withInValue;var attributes=new Array();var whiteSpaceRegExp=new RegExp('^[ \n\r\t]+','g');if(attribute_string==null||attribute_string.length<2)return null;withInName=withInValue=false;for(var i=0;i<attribute_string.length;i++){var chr=attribute_string.charAt(i);if((chr=='"'||chr=="'")&&!withInValue){withInValue=true;endChr=chr}else if(chr==endChr&&withInValue){withInValue=false;var pos=attributeName.lastIndexOf(' ');if(pos!=-1)attributeName=attributeName.substring(pos+1);attributes[attributeName.toLowerCase()]=attributeValue.substring(1);attributeName="";attributeValue=""}else if(!whiteSpaceRegExp.test(chr)&&!withInName&&!withInValue)withInName=true;if(chr=='='&&withInName)withInName=false;if(withInName)attributeName+=chr;if(withInValue)attributeValue+=chr}return attributes}};tinyMCE.addPlugin("media",TinyMCE_MediaPlugin);
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/media/editor_plugin_src.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,435 @@
+/**
+ * $Id: editor_plugin_src.js 201 2007-02-12 15:56:56Z spocke $
+ *
+ * @author Moxiecode
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+/* Import plugin specific language pack */
+tinyMCE.importPluginLanguagePack('media');
+
+var TinyMCE_MediaPlugin = {
+	getInfo : function() {
+		return {
+			longname : 'Media',
+			author : 'Moxiecode Systems AB',
+			authorurl : 'http://tinymce.moxiecode.com',
+			infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/media',
+			version : tinyMCE.majorVersion + "." + tinyMCE.minorVersion
+		};
+	},
+
+	initInstance : function(inst) {
+		// Warn if user has flash plugin and media plugin at the same time
+		if (inst.hasPlugin('flash') && !tinyMCE.flashWarn) {
+			alert('Flash plugin is deprecated and should not be used together with the media plugin.');
+			tinyMCE.flashWarn = true;
+		}
+
+		if (!tinyMCE.settings['media_skip_plugin_css'])
+			tinyMCE.importCSS(inst.getDoc(), tinyMCE.baseURL + "/plugins/media/css/content.css");
+	},
+
+	getControlHTML : function(cn) {
+		switch (cn) {
+			case "media":
+				return tinyMCE.getButtonHTML(cn, 'lang_media_desc', '{$pluginurl}/images/media.gif', 'mceMedia');
+		}
+
+		return "";
+	},
+
+	execCommand : function(editor_id, element, command, user_interface, value) {
+		// Handle commands
+		switch (command) {
+			case "mceMedia":
+				tinyMCE.openWindow({
+						file : '../../plugins/media/media.htm',
+						width : 430 + tinyMCE.getLang('lang_media_delta_width', 0),
+						height : 470 + tinyMCE.getLang('lang_media_delta_height', 0)
+					}, {
+						editor_id : editor_id,
+						inline : "yes"
+				});
+
+				return true;
+	   }
+
+	   // Pass to next handler in chain
+	   return false;
+	},
+
+	cleanup : function(type, content, inst) {
+		var nl, img, i, ne, d, s, ci;
+
+		switch (type) {
+			case "insert_to_editor":
+				img = tinyMCE.getParam("theme_href") + '/images/spacer.gif';
+				content = content.replace(/<script[^>]*>\s*write(Flash|ShockWave|WindowsMedia|QuickTime|RealMedia)\(\{([^\)]*)\}\);\s*<\/script>/gi, '<img class="mceItem$1" title="$2" src="' + img + '" />');
+				content = content.replace(/<object([^>]*)>/gi, '<div class="mceItemObject" $1>');
+				content = content.replace(/<embed([^>]*)>/gi, '<div class="mceItemObjectEmbed" $1>');
+				content = content.replace(/<\/(object|embed)([^>]*)>/gi, '</div>');
+				content = content.replace(/<param([^>]*)>/gi, '<div $1 class="mceItemParam"></div>');
+				content = content.replace(new RegExp('\\/ class="mceItemParam"><\\/div>', 'gi'), 'class="mceItemParam"></div>');
+				break;
+
+			case "insert_to_editor_dom":
+				d = inst.getDoc();
+				nl = content.getElementsByTagName("img");
+				for (i=0; i<nl.length; i++) {
+					if (/mceItem(Flash|ShockWave|WindowsMedia|QuickTime|RealMedia)/.test(nl[i].className)) {
+						nl[i].width = nl[i].title.replace(/.*width:[^0-9]?([0-9]+)%?.*/g, '$1');
+						nl[i].height = nl[i].title.replace(/.*height:[^0-9]?([0-9]+)%?.*/g, '$1');
+						//nl[i].align = nl[i].title.replace(/.*align:([a-z]+).*/gi, '$1');
+					}
+				}
+
+				nl = tinyMCE.selectElements(content, 'DIV', function (n) {return tinyMCE.hasCSSClass(n, 'mceItemObject');});
+				for (i=0; i<nl.length; i++) {
+					ci = tinyMCE.getAttrib(nl[i], "classid").toLowerCase().replace(/\s+/g, '');
+
+					switch (ci) {
+						case 'clsid:d27cdb6e-ae6d-11cf-96b8-444553540000':
+							nl[i].parentNode.replaceChild(TinyMCE_MediaPlugin._createImg('mceItemFlash', d, nl[i]), nl[i]);
+							break;
+
+						case 'clsid:166b1bca-3f9c-11cf-8075-444553540000':
+							nl[i].parentNode.replaceChild(TinyMCE_MediaPlugin._createImg('mceItemShockWave', d, nl[i]), nl[i]);
+							break;
+
+						case 'clsid:6bf52a52-394a-11d3-b153-00c04f79faa6':
+							nl[i].parentNode.replaceChild(TinyMCE_MediaPlugin._createImg('mceItemWindowsMedia', d, nl[i]), nl[i]);
+							break;
+
+						case 'clsid:02bf25d5-8c17-4b23-bc80-d3488abddc6b':
+							nl[i].parentNode.replaceChild(TinyMCE_MediaPlugin._createImg('mceItemQuickTime', d, nl[i]), nl[i]);
+							break;
+
+						case 'clsid:cfcdaa03-8be4-11cf-b84b-0020afbbccfa':
+						case 'clsid:22d6f312-b0f6-11d0-94ab-0080c74c7e95':
+						case 'clsid:05589fa1-c356-11ce-bf01-00aa0055595a':
+							nl[i].parentNode.replaceChild(TinyMCE_MediaPlugin._createImg('mceItemRealMedia', d, nl[i]), nl[i]);
+							break;
+					}
+				}
+
+				// Handle embed (if any)
+				nl = tinyMCE.selectNodes(content, function (n) {return n.className == 'mceItemObjectEmbed';});
+				for (i=0; i<nl.length; i++) {
+					switch (tinyMCE.getAttrib(nl[i], 'type')) {
+						case 'application/x-shockwave-flash':
+							TinyMCE_MediaPlugin._createImgFromEmbed(nl[i], d, 'mceItemFlash');
+							break;
+
+						case 'application/x-director':
+							TinyMCE_MediaPlugin._createImgFromEmbed(nl[i], d, 'mceItemShockWave');
+							break;
+
+						case 'application/x-mplayer2':
+							TinyMCE_MediaPlugin._createImgFromEmbed(nl[i], d, 'mceItemWindowsMedia');
+							break;
+
+						case 'video/quicktime':
+							TinyMCE_MediaPlugin._createImgFromEmbed(nl[i], d, 'mceItemQuickTime');
+							break;
+
+						case 'audio/x-pn-realaudio-plugin':
+							TinyMCE_MediaPlugin._createImgFromEmbed(nl[i], d, 'mceItemRealMedia');
+							break;
+					}
+				}
+				break;
+
+			case "get_from_editor":
+				var startPos = -1, endPos, attribs, chunkBefore, chunkAfter, embedHTML, at, pl, cb, mt, ex;
+
+				while ((startPos = content.indexOf('<img', startPos+1)) != -1) {
+					endPos = content.indexOf('/>', startPos);
+					attribs = TinyMCE_MediaPlugin._parseAttributes(content.substring(startPos + 4, endPos));
+
+					// Is not flash, skip it
+					if (!/mceItem(Flash|ShockWave|WindowsMedia|QuickTime|RealMedia)/.test(attribs['class']))
+						continue;
+
+					endPos += 2;
+
+					// Parse attributes
+					at = attribs['title'];
+					if (at) {
+						at = at.replace(/&(#39|apos);/g, "'");
+						at = at.replace(/&#quot;/g, '"');
+
+						try {
+							pl = eval('x={' + at + '};');
+						} catch (ex) {
+							pl = {};
+						}
+					}
+
+					// Use object/embed
+					if (!tinyMCE.getParam('media_use_script', false)) {
+						switch (attribs['class']) {
+							case 'mceItemFlash':
+								ci = 'd27cdb6e-ae6d-11cf-96b8-444553540000';
+								cb = 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0';
+								mt = 'application/x-shockwave-flash';
+								break;
+
+							case 'mceItemShockWave':
+								ci = '166B1BCA-3F9C-11CF-8075-444553540000';
+								cb = 'http://download.macromedia.com/pub/shockwave/cabs/director/sw.cab#version=8,5,1,0';
+								mt = 'application/x-director';
+								break;
+
+							case 'mceItemWindowsMedia':
+								ci = tinyMCE.getParam('media_wmp6_compatible') ? '05589FA1-C356-11CE-BF01-00AA0055595A' : '6BF52A52-394A-11D3-B153-00C04F79FAA6';
+								cb = 'http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=5,1,52,701';
+								mt = 'application/x-mplayer2';
+								break;
+
+							case 'mceItemQuickTime':
+								ci = '02BF25D5-8C17-4B23-BC80-D3488ABDDC6B';
+								cb = 'http://www.apple.com/qtactivex/qtplugin.cab#version=6,0,2,0';
+								mt = 'video/quicktime';
+								break;
+
+							case 'mceItemRealMedia':
+								ci = 'CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA';
+								cb = 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0';
+								mt = 'audio/x-pn-realaudio-plugin';
+								break;
+						}
+
+						// Force absolute URL
+						if (!tinyMCE.getParam("relative_urls"))
+							pl.src = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], pl.src);
+
+						embedHTML = TinyMCE_MediaPlugin._getEmbed(ci, cb, mt, pl, attribs);
+					} else {
+						// Use script version
+						switch (attribs['class']) {
+							case 'mceItemFlash':
+								s = 'writeFlash';
+								break;
+
+							case 'mceItemShockWave':
+								s = 'writeShockWave';
+								break;
+
+							case 'mceItemWindowsMedia':
+								s = 'writeWindowsMedia';
+								break;
+
+							case 'mceItemQuickTime':
+								s = 'writeQuickTime';
+								break;
+
+							case 'mceItemRealMedia':
+								s = 'writeRealMedia';
+								break;
+						}
+
+						if (attribs.width)
+							at = at.replace(/width:[^0-9]?[0-9]+%?[^0-9]?/g, "width:'" + attribs.width + "'");
+
+						if (attribs.height)
+							at = at.replace(/height:[^0-9]?[0-9]+%?[^0-9]?/g, "height:'" + attribs.height + "'");
+
+						// Force absolute URL
+						if (!tinyMCE.getParam("relative_urls")) {
+							pl.src = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], pl.src);
+							at = at.replace(new RegExp("src:'[^']*'", "g"), "src:'" + pl.src + "'");
+						}
+
+						embedHTML = '<script type="text/javascript">' + s + '({' + at + '});</script>';
+					}
+
+					// Insert embed/object chunk
+					chunkBefore = content.substring(0, startPos);
+					chunkAfter = content.substring(endPos);
+					content = chunkBefore + embedHTML + chunkAfter;
+				}
+				break;
+		}
+
+		return content;
+	},
+
+	handleNodeChange : function(editor_id, node, undo_index, undo_levels, visual_aid, any_selection) {
+		if (node == null)
+			return;
+
+		do {
+			if (node.nodeName == "IMG" && /mceItem(Flash|ShockWave|WindowsMedia|QuickTime|RealMedia)/.test(tinyMCE.getAttrib(node, 'class'))) {
+				tinyMCE.switchClass(editor_id + '_media', 'mceButtonSelected');
+				return true;
+			}
+		} while ((node = node.parentNode));
+
+		tinyMCE.switchClass(editor_id + '_media', 'mceButtonNormal');
+
+		return true;
+	},
+
+	_createImgFromEmbed : function(n, d, cl) {
+		var ne, at, i, ti = '', an;
+
+		ne = d.createElement('img');
+		ne.src = tinyMCE.getParam("theme_href") + '/images/spacer.gif';
+		ne.width = tinyMCE.getAttrib(n, 'width');
+		ne.height = tinyMCE.getAttrib(n, 'height');
+		ne.className = cl;
+
+		at = n.attributes;
+		for (i=0; i<at.length; i++) {
+			if (at[i].specified && at[i].nodeValue) {
+				an = at[i].nodeName.toLowerCase();
+
+				if (an == 'src')
+					continue;
+
+				if (an == 'mce_src')
+					an = 'src';
+
+				if (an.indexOf('mce_') == -1 && !new RegExp('^(class|type)$').test(an))
+					ti += an.toLowerCase() + ':\'' + at[i].nodeValue + "',";
+			}
+		}
+
+		ti = ti.length > 0 ? ti.substring(0, ti.length - 1) : ti;
+		ne.title = ti;
+
+		n.parentNode.replaceChild(ne, n);
+	},
+
+	_createImg : function(cl, d, n) {
+		var i, nl, ti = "", an, av, al = new Array();
+
+		ne = d.createElement('img');
+		ne.src = tinyMCE.getParam("theme_href") + '/images/spacer.gif';
+		ne.width = tinyMCE.getAttrib(n, 'width');
+		ne.height = tinyMCE.getAttrib(n, 'height');
+		ne.className = cl;
+
+		al.id = tinyMCE.getAttrib(n, 'id');
+		al.name = tinyMCE.getAttrib(n, 'name');
+		al.width = tinyMCE.getAttrib(n, 'width');
+		al.height = tinyMCE.getAttrib(n, 'height');
+		al.bgcolor = tinyMCE.getAttrib(n, 'bgcolor');
+		al.align = tinyMCE.getAttrib(n, 'align');
+		al.class_name = tinyMCE.getAttrib(n, 'mce_class');
+
+		nl = n.getElementsByTagName('div');
+		for (i=0; i<nl.length; i++) {
+			av = tinyMCE.getAttrib(nl[i], 'value');
+			av = av.replace(new RegExp('\\\\', 'g'), '\\\\');
+			av = av.replace(new RegExp('"', 'g'), '\\"');
+			av = av.replace(new RegExp("'", 'g'), "\\'");
+			an = tinyMCE.getAttrib(nl[i], 'name');
+			al[an] = av;
+		}
+
+		if (al.movie) {
+			al.src = al.movie;
+			al.movie = null;
+		}
+
+		for (an in al) {
+			if (al[an] != null && typeof(al[an]) != "function" && al[an] != '')
+				ti += an.toLowerCase() + ':\'' + al[an] + "',";
+		}
+
+		ti = ti.length > 0 ? ti.substring(0, ti.length - 1) : ti;
+		ne.title = ti;
+
+		return ne;
+	},
+
+	_getEmbed : function(cls, cb, mt, p, at) {
+		var h = '', n;
+
+		p.width = at.width ? at.width : p.width;
+		p.height = at.height ? at.height : p.height;
+
+		h += '<object classid="clsid:' + cls + '" codebase="' + cb + '"';
+		h += typeof(p.id) != "undefined" ? ' id="' + p.id + '"' : '';
+		h += typeof(p.name) != "undefined" ? ' name="' + p.name + '"' : '';
+		h += typeof(p.width) != "undefined" ? ' width="' + p.width + '"' : '';
+		h += typeof(p.height) != "undefined" ? ' height="' + p.height + '"' : '';
+		h += typeof(p.align) != "undefined" ? ' align="' + p.align + '"' : '';
+		h += '>';
+
+		for (n in p) {
+			if (p[n] && typeof(p[n]) != "function") {
+				h += '<param name="' + n + '" value="' + p[n] + '" />';
+
+				// Add extra url parameter if it's an absolute URL on WMP
+				if (n == 'src' && p[n].indexOf('://') != -1 && mt == 'application/x-mplayer2')
+					h += '<param name="url" value="' + p[n] + '" />';
+			}
+		}
+
+		h += '<embed type="' + mt + '"';
+
+		for (n in p) {
+			if (typeof(p[n]) == "function")
+				continue;
+
+			// Skip url parameter for embed tag on WMP
+			if (!(n == 'url' && mt == 'application/x-mplayer2'))
+				h += ' ' + n + '="' + p[n] + '"';
+		}
+
+		h += '></embed></object>';
+
+		return h;
+	},
+
+	_parseAttributes : function(attribute_string) {
+		var attributeName = "", endChr = '"';
+		var attributeValue = "";
+		var withInName;
+		var withInValue;
+		var attributes = new Array();
+		var whiteSpaceRegExp = new RegExp('^[ \n\r\t]+', 'g');
+
+		if (attribute_string == null || attribute_string.length < 2)
+			return null;
+
+		withInName = withInValue = false;
+
+		for (var i=0; i<attribute_string.length; i++) {
+			var chr = attribute_string.charAt(i);
+
+			if ((chr == '"' || chr == "'") && !withInValue) {
+				withInValue = true;
+				endChr = chr;
+			} else if (chr == endChr && withInValue) {
+				withInValue = false;
+
+				var pos = attributeName.lastIndexOf(' ');
+				if (pos != -1)
+					attributeName = attributeName.substring(pos+1);
+
+				attributes[attributeName.toLowerCase()] = attributeValue.substring(1);
+
+				attributeName = "";
+				attributeValue = "";
+			} else if (!whiteSpaceRegExp.test(chr) && !withInName && !withInValue)
+				withInName = true;
+
+			if (chr == '=' && withInName)
+				withInName = false;
+
+			if (withInName)
+				attributeName += chr;
+
+			if (withInValue)
+				attributeValue += chr;
+		}
+
+		return attributes;
+	}
+};
+
+tinyMCE.addPlugin("media", TinyMCE_MediaPlugin);
Binary file includes/clientside/tinymce/plugins/media/images/flash.gif has changed
Binary file includes/clientside/tinymce/plugins/media/images/media.gif has changed
Binary file includes/clientside/tinymce/plugins/media/images/quicktime.gif has changed
Binary file includes/clientside/tinymce/plugins/media/images/realmedia.gif has changed
Binary file includes/clientside/tinymce/plugins/media/images/shockwave.gif has changed
Binary file includes/clientside/tinymce/plugins/media/images/windowsmedia.gif has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/media/jscripts/embed.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,73 @@
+/**
+ * This script contains embed functions for common plugins. This scripts are complety free to use for any purpose.
+ */
+
+function writeFlash(p) {
+	writeEmbed(
+		'D27CDB6E-AE6D-11cf-96B8-444553540000',
+		'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0',
+		'application/x-shockwave-flash',
+		p
+	);
+}
+
+function writeShockWave(p) {
+	writeEmbed(
+	'166B1BCA-3F9C-11CF-8075-444553540000',
+	'http://download.macromedia.com/pub/shockwave/cabs/director/sw.cab#version=8,5,1,0',
+	'application/x-director',
+		p
+	);
+}
+
+function writeQuickTime(p) {
+	writeEmbed(
+		'02BF25D5-8C17-4B23-BC80-D3488ABDDC6B',
+		'http://www.apple.com/qtactivex/qtplugin.cab#version=6,0,2,0',
+		'video/quicktime',
+		p
+	);
+}
+
+function writeRealMedia(p) {
+	writeEmbed(
+		'CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA',
+		'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0',
+		'audio/x-pn-realaudio-plugin',
+		p
+	);
+}
+
+function writeWindowsMedia(p) {
+	p.url = p.src;
+	writeEmbed(
+		'6BF52A52-394A-11D3-B153-00C04F79FAA6',
+		'http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=5,1,52,701',
+		'application/x-mplayer2',
+		p
+	);
+}
+
+function writeEmbed(cls, cb, mt, p) {
+	var h = '', n;
+
+	h += '<object classid="clsid:' + cls + '" codebase="' + cb + '"';
+	h += typeof(p.id) != "undefined" ? 'id="' + p.id + '"' : '';
+	h += typeof(p.name) != "undefined" ? 'name="' + p.name + '"' : '';
+	h += typeof(p.width) != "undefined" ? 'width="' + p.width + '"' : '';
+	h += typeof(p.height) != "undefined" ? 'height="' + p.height + '"' : '';
+	h += typeof(p.align) != "undefined" ? 'align="' + p.align + '"' : '';
+	h += '>';
+
+	for (n in p)
+		h += '<param name="' + n + '" value="' + p[n] + '">';
+
+	h += '<embed type="' + mt + '"';
+
+	for (n in p)
+		h += n + '="' + p[n] + '" ';
+
+	h += '></embed></object>';
+
+	document.write(h);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/media/jscripts/media.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,572 @@
+var oldWidth, oldHeight;
+var url = tinyMCE.getParam("media_external_list_url");
+if (url != null) {
+	// Fix relative
+	if (url.charAt(0) != '/' && url.indexOf('://') == -1)
+		url = tinyMCE.documentBasePath + "/" + url;
+
+	document.write('<sc'+'ript language="javascript" type="text/javascript" src="' + url + '"></sc'+'ript>');
+}
+
+function init() {
+	var pl = "", f, val;
+	var type = "flash", fe, i;
+
+	tinyMCEPopup.resizeToInnerSize();
+	f = document.forms[0]
+
+	fe = tinyMCE.selectedInstance.getFocusElement();
+	if (/mceItem(Flash|ShockWave|WindowsMedia|QuickTime|RealMedia)/.test(tinyMCE.getAttrib(fe, 'class'))) {
+		pl = "x={" + fe.title + "};";
+
+		switch (tinyMCE.getAttrib(fe, 'class')) {
+			case 'mceItemFlash':
+				type = 'flash';
+				break;
+
+			case 'mceItemShockWave':
+				type = 'shockwave';
+				break;
+
+			case 'mceItemWindowsMedia':
+				type = 'wmp';
+				break;
+
+			case 'mceItemQuickTime':
+				type = 'qt';
+				break;
+
+			case 'mceItemRealMedia':
+				type = 'rmp';
+				break;
+		}
+
+		document.forms[0].insert.value = tinyMCE.getLang('lang_update', 'Insert', true); 
+	}
+
+	document.getElementById('filebrowsercontainer').innerHTML = getBrowserHTML('filebrowser','src','media','media');
+	document.getElementById('qtsrcfilebrowsercontainer').innerHTML = getBrowserHTML('qtsrcfilebrowser','qt_qtsrc','media','media');
+	document.getElementById('bgcolor_pickcontainer').innerHTML = getColorPickerHTML('bgcolor_pick','bgcolor');
+
+	var html = getMediaListHTML('filebrowser','src','media','media');
+	if (html == "")
+		document.getElementById("linklistrow").style.display = 'none';
+	else
+		document.getElementById("linklistcontainer").innerHTML = html;
+
+	// Resize some elements
+	if (isVisible('filebrowsercontainer'))
+		document.getElementById('src').style.width = '230px';
+
+	// Setup form
+	if (pl != "") {
+		pl = eval(pl);
+
+		switch (type) {
+			case "flash":
+				setBool(pl, 'flash', 'play');
+				setBool(pl, 'flash', 'loop');
+				setBool(pl, 'flash', 'menu');
+				setBool(pl, 'flash', 'swliveconnect');
+				setStr(pl, 'flash', 'quality');
+				setStr(pl, 'flash', 'scale');
+				setStr(pl, 'flash', 'salign');
+				setStr(pl, 'flash', 'wmode');
+				setStr(pl, 'flash', 'base');
+				setStr(pl, 'flash', 'flashvars');
+			break;
+
+			case "qt":
+				setBool(pl, 'qt', 'loop');
+				setBool(pl, 'qt', 'autoplay');
+				setBool(pl, 'qt', 'cache');
+				setBool(pl, 'qt', 'controller');
+				setBool(pl, 'qt', 'correction');
+				setBool(pl, 'qt', 'enablejavascript');
+				setBool(pl, 'qt', 'kioskmode');
+				setBool(pl, 'qt', 'autohref');
+				setBool(pl, 'qt', 'playeveryframe');
+				setBool(pl, 'qt', 'tarsetcache');
+				setStr(pl, 'qt', 'scale');
+				setStr(pl, 'qt', 'starttime');
+				setStr(pl, 'qt', 'endtime');
+				setStr(pl, 'qt', 'tarset');
+				setStr(pl, 'qt', 'qtsrcchokespeed');
+				setStr(pl, 'qt', 'volume');
+				setStr(pl, 'qt', 'qtsrc');
+			break;
+
+			case "shockwave":
+				setBool(pl, 'shockwave', 'sound');
+				setBool(pl, 'shockwave', 'progress');
+				setBool(pl, 'shockwave', 'autostart');
+				setBool(pl, 'shockwave', 'swliveconnect');
+				setStr(pl, 'shockwave', 'swvolume');
+				setStr(pl, 'shockwave', 'swstretchstyle');
+				setStr(pl, 'shockwave', 'swstretchhalign');
+				setStr(pl, 'shockwave', 'swstretchvalign');
+			break;
+
+			case "wmp":
+				setBool(pl, 'wmp', 'autostart');
+				setBool(pl, 'wmp', 'enabled');
+				setBool(pl, 'wmp', 'enablecontextmenu');
+				setBool(pl, 'wmp', 'fullscreen');
+				setBool(pl, 'wmp', 'invokeurls');
+				setBool(pl, 'wmp', 'mute');
+				setBool(pl, 'wmp', 'stretchtofit');
+				setBool(pl, 'wmp', 'windowlessvideo');
+				setStr(pl, 'wmp', 'balance');
+				setStr(pl, 'wmp', 'baseurl');
+				setStr(pl, 'wmp', 'captioningid');
+				setStr(pl, 'wmp', 'currentmarker');
+				setStr(pl, 'wmp', 'currentposition');
+				setStr(pl, 'wmp', 'defaultframe');
+				setStr(pl, 'wmp', 'playcount');
+				setStr(pl, 'wmp', 'rate');
+				setStr(pl, 'wmp', 'uimode');
+				setStr(pl, 'wmp', 'volume');
+			break;
+
+			case "rmp":
+				setBool(pl, 'rmp', 'autostart');
+				setBool(pl, 'rmp', 'loop');
+				setBool(pl, 'rmp', 'autogotourl');
+				setBool(pl, 'rmp', 'center');
+				setBool(pl, 'rmp', 'imagestatus');
+				setBool(pl, 'rmp', 'maintainaspect');
+				setBool(pl, 'rmp', 'nojava');
+				setBool(pl, 'rmp', 'prefetch');
+				setBool(pl, 'rmp', 'shuffle');
+				setStr(pl, 'rmp', 'console');
+				setStr(pl, 'rmp', 'controls');
+				setStr(pl, 'rmp', 'numloop');
+				setStr(pl, 'rmp', 'scriptcallbacks');
+			break;
+		}
+
+		setStr(pl, null, 'src');
+		setStr(pl, null, 'id');
+		setStr(pl, null, 'name');
+		setStr(pl, null, 'vspace');
+		setStr(pl, null, 'hspace');
+		setStr(pl, null, 'bgcolor');
+		setStr(pl, null, 'align');
+		setStr(pl, null, 'width');
+		setStr(pl, null, 'height');
+
+		if ((val = tinyMCE.getAttrib(fe, "width")) != "")
+			pl.width = f.width.value = val;
+
+		if ((val = tinyMCE.getAttrib(fe, "height")) != "")
+			pl.height = f.height.value = val;
+
+		oldWidth = pl.width ? parseInt(pl.width) : 0;
+		oldHeight = pl.height ? parseInt(pl.height) : 0;
+	} else
+		oldWidth = oldHeight = 0;
+
+	selectByValue(f, 'media_type', type);
+	changedType(type);
+	updateColor('bgcolor_pick', 'bgcolor');
+
+	TinyMCE_EditableSelects.init();
+	generatePreview();
+}
+
+function insertMedia() {
+	var fe, f = document.forms[0], h;
+
+	if (!AutoValidator.validate(f)) {
+		alert(tinyMCE.getLang('lang_invalid_data'));
+		return false;
+	}
+
+	f.width.value = f.width.value == "" ? 100 : f.width.value;
+	f.height.value = f.height.value == "" ? 100 : f.height.value;
+
+	fe = tinyMCE.selectedInstance.getFocusElement();
+	if (fe != null && /mceItem(Flash|ShockWave|WindowsMedia|QuickTime|RealMedia)/.test(tinyMCE.getAttrib(fe, 'class'))) {
+		switch (f.media_type.options[f.media_type.selectedIndex].value) {
+			case "flash":
+				fe.className = "mceItemFlash";
+				break;
+
+			case "shockwave":
+				fe.className = "mceItemShockWave";
+				break;
+
+			case "qt":
+				fe.className = "mceItemQuickTime";
+				break;
+
+			case "wmp":
+				fe.className = "mceItemWindowsMedia";
+				break;
+
+			case "rmp":
+				fe.className = "mceItemRealMedia";
+				break;
+		}
+
+		if (fe.width != f.width.value || fe.height != f.width.height)
+			tinyMCE.selectedInstance.repaint();
+
+		fe.title = serializeParameters();
+		fe.width = f.width.value;
+		fe.height = f.height.value;
+		fe.style.width = f.width.value + (f.width.value.indexOf('%') == -1 ? 'px' : '');
+		fe.style.height = f.height.value + (f.height.value.indexOf('%') == -1 ? 'px' : '');
+		fe.align = f.align.options[f.align.selectedIndex].value;
+	} else {
+		h = '<img src="' + tinyMCE.getParam("theme_href") + '/images/spacer.gif"' ;
+
+		switch (f.media_type.options[f.media_type.selectedIndex].value) {
+			case "flash":
+				h += ' class="mceItemFlash"';
+				break;
+
+			case "shockwave":
+				h += ' class="mceItemShockWave"';
+				break;
+
+			case "qt":
+				h += ' class="mceItemQuickTime"';
+				break;
+
+			case "wmp":
+				h += ' class="mceItemWindowsMedia"';
+				break;
+
+			case "rmp":
+				h += ' class="mceItemRealMedia"';
+				break;
+		}
+
+		h += ' title="' + serializeParameters() + '"';
+		h += ' width="' + f.width.value + '"';
+		h += ' height="' + f.height.value + '"';
+		h += ' align="' + f.align.options[f.align.selectedIndex].value + '"';
+
+		h += ' />';
+
+		tinyMCE.selectedInstance.execCommand('mceInsertContent', false, h);
+	}
+
+	tinyMCEPopup.close();
+}
+
+function getMediaListHTML() {
+	if (typeof(tinyMCEMediaList) != "undefined" && tinyMCEMediaList.length > 0) {
+		var html = "";
+
+		html += '<select id="linklist" name="linklist" style="width: 250px" onfocus="tinyMCE.addSelectAccessibility(event, this, window);" onchange="this.form.src.value=this.options[this.selectedIndex].value;">';
+		html += '<option value="">---</option>';
+
+		for (var i=0; i<tinyMCEMediaList.length; i++)
+			html += '<option value="' + tinyMCEMediaList[i][1] + '">' + tinyMCEMediaList[i][0] + '</option>';
+
+		html += '</select>';
+
+		return html;
+	}
+
+	return "";
+}
+
+function getType(v) {
+	var fo = tinyMCE.getParam("media_types", "flash=swf;shockwave=dcr;qt=mov,qt,mpg,mp3,mp4,mpeg;shockwave=dcr;wmp=avi,wmv,wm,asf,asx,wmx,wvx;rmp=rm,ra,ram").split(';'), i, c, el, x;
+
+	for (i=0; i<fo.length; i++) {
+		c = fo[i].split('=');
+
+		el = c[1].split(',');
+		for (x=0; x<el.length; x++)
+		if (v.indexOf('.' + el[x]) != -1)
+			return c[0];
+	}
+
+	return null;
+}
+
+function switchType(v) {
+	var t = getType(v), d = document, f = d.forms[0];
+
+	if (!t)
+		return;
+
+	selectByValue(d.forms[0], 'media_type', t);
+	changedType(t);
+
+	// Update qtsrc also
+	if (t == 'qt' && f.src.value.toLowerCase().indexOf('rtsp://') != -1) {
+		alert(tinyMCE.getLang("lang_media_qt_stream_warn"));
+
+		if (f.qt_qtsrc.value == '')
+			f.qt_qtsrc.value = f.src.value;
+	}
+}
+
+function changedType(t) {
+	var d = document;
+
+	d.getElementById('flash_options').style.display = 'none';
+	d.getElementById('qt_options').style.display = 'none';
+	d.getElementById('shockwave_options').style.display = 'none';
+	d.getElementById('wmp_options').style.display = 'none';
+	d.getElementById('rmp_options').style.display = 'none';
+	d.getElementById(t + '_options').style.display = 'block';
+}
+
+function serializeParameters() {
+	var d = document, f = d.forms[0], s = '';
+
+	switch (f.media_type.options[f.media_type.selectedIndex].value) {
+		case "flash":
+			s += getBool('flash', 'play', true);
+			s += getBool('flash', 'loop', true);
+			s += getBool('flash', 'menu', true);
+			s += getBool('flash', 'swliveconnect', false);
+			s += getStr('flash', 'quality');
+			s += getStr('flash', 'scale');
+			s += getStr('flash', 'salign');
+			s += getStr('flash', 'wmode');
+			s += getStr('flash', 'base');
+			s += getStr('flash', 'flashvars');
+		break;
+
+		case "qt":
+			s += getBool('qt', 'loop', false);
+			s += getBool('qt', 'autoplay', false);
+			s += getBool('qt', 'cache', false);
+			s += getBool('qt', 'controller', true);
+			s += getBool('qt', 'correction', false, 'none', 'full');
+			s += getBool('qt', 'enablejavascript', false);
+			s += getBool('qt', 'kioskmode', false);
+			s += getBool('qt', 'autohref', false);
+			s += getBool('qt', 'playeveryframe', false);
+			s += getBool('qt', 'targetcache', false);
+			s += getStr('qt', 'scale');
+			s += getStr('qt', 'starttime');
+			s += getStr('qt', 'endtime');
+			s += getStr('qt', 'target');
+			s += getStr('qt', 'qtsrcchokespeed');
+			s += getStr('qt', 'volume');
+			s += getStr('qt', 'qtsrc');
+		break;
+
+		case "shockwave":
+			s += getBool('shockwave', 'sound');
+			s += getBool('shockwave', 'progress');
+			s += getBool('shockwave', 'autostart');
+			s += getBool('shockwave', 'swliveconnect');
+			s += getStr('shockwave', 'swvolume');
+			s += getStr('shockwave', 'swstretchstyle');
+			s += getStr('shockwave', 'swstretchhalign');
+			s += getStr('shockwave', 'swstretchvalign');
+		break;
+
+		case "wmp":
+			s += getBool('wmp', 'autostart', true);
+			s += getBool('wmp', 'enabled', false);
+			s += getBool('wmp', 'enablecontextmenu', true);
+			s += getBool('wmp', 'fullscreen', false);
+			s += getBool('wmp', 'invokeurls', true);
+			s += getBool('wmp', 'mute', false);
+			s += getBool('wmp', 'stretchtofit', false);
+			s += getBool('wmp', 'windowlessvideo', false);
+			s += getStr('wmp', 'balance');
+			s += getStr('wmp', 'baseurl');
+			s += getStr('wmp', 'captioningid');
+			s += getStr('wmp', 'currentmarker');
+			s += getStr('wmp', 'currentposition');
+			s += getStr('wmp', 'defaultframe');
+			s += getStr('wmp', 'playcount');
+			s += getStr('wmp', 'rate');
+			s += getStr('wmp', 'uimode');
+			s += getStr('wmp', 'volume');
+		break;
+
+		case "rmp":
+			s += getBool('rmp', 'autostart', false);
+			s += getBool('rmp', 'loop', false);
+			s += getBool('rmp', 'autogotourl', true);
+			s += getBool('rmp', 'center', false);
+			s += getBool('rmp', 'imagestatus', true);
+			s += getBool('rmp', 'maintainaspect', false);
+			s += getBool('rmp', 'nojava', false);
+			s += getBool('rmp', 'prefetch', false);
+			s += getBool('rmp', 'shuffle', false);
+			s += getStr('rmp', 'console');
+			s += getStr('rmp', 'controls');
+			s += getStr('rmp', 'numloop');
+			s += getStr('rmp', 'scriptcallbacks');
+		break;
+	}
+
+	s += getStr(null, 'id');
+	s += getStr(null, 'name');
+	s += getStr(null, 'src');
+	s += getStr(null, 'align');
+	s += getStr(null, 'bgcolor');
+	s += getInt(null, 'vspace');
+	s += getInt(null, 'hspace');
+	s += getStr(null, 'width');
+	s += getStr(null, 'height');
+
+	s = s.length > 0 ? s.substring(0, s.length - 1) : s;
+
+	return s;
+}
+
+function setBool(pl, p, n) {
+	if (typeof(pl[n]) == "undefined")
+		return;
+
+	document.forms[0].elements[p + "_" + n].checked = pl[n];
+}
+
+function setStr(pl, p, n) {
+	var f = document.forms[0], e = f.elements[(p != null ? p + "_" : '') + n];
+
+	if (typeof(pl[n]) == "undefined")
+		return;
+
+	if (e.type == "text")
+		e.value = pl[n];
+	else
+		selectByValue(f, (p != null ? p + "_" : '') + n, pl[n]);
+}
+
+function getBool(p, n, d, tv, fv) {
+	var v = document.forms[0].elements[p + "_" + n].checked;
+
+	tv = typeof(tv) == 'undefined' ? 'true' : "'" + jsEncode(tv) + "'";
+	fv = typeof(fv) == 'undefined' ? 'false' : "'" + jsEncode(fv) + "'";
+
+	return (v == d) ? '' : n + (v ? ':' + tv + ',' : ':' + fv + ',');
+}
+
+function getStr(p, n, d) {
+	var e = document.forms[0].elements[(p != null ? p + "_" : "") + n];
+	var v = e.type == "text" ? e.value : e.options[e.selectedIndex].value;
+
+	return ((n == d || v == '') ? '' : n + ":'" + jsEncode(v) + "',");
+}
+
+function getInt(p, n, d) {
+	var e = document.forms[0].elements[(p != null ? p + "_" : "") + n];
+	var v = e.type == "text" ? e.value : e.options[e.selectedIndex].value;
+
+	return ((n == d || v == '') ? '' : n + ":" + v.replace(/[^0-9]+/g, '') + ",");
+}
+
+function jsEncode(s) {
+	s = s.replace(new RegExp('\\\\', 'g'), '\\\\');
+	s = s.replace(new RegExp('"', 'g'), '\\"');
+	s = s.replace(new RegExp("'", 'g'), "\\'");
+
+	return s;
+}
+
+function generatePreview(c) {
+	var f = document.forms[0], p = document.getElementById('prev'), h = '', cls, pl, n, type, codebase, wp, hp, nw, nh;
+
+	p.innerHTML = '<!-- x --->';
+
+	nw = parseInt(f.width.value);
+	nh = parseInt(f.height.value);
+
+	if (f.width.value != "" && f.height.value != "") {
+		if (f.constrain.checked) {
+			if (c == 'width' && oldWidth != 0) {
+				wp = nw / oldWidth;
+				nh = Math.round(wp * nh);
+				f.height.value = nh;
+			} else if (c == 'height' && oldHeight != 0) {
+				hp = nh / oldHeight;
+				nw = Math.round(hp * nw);
+				f.width.value = nw;
+			}
+		}
+	}
+
+	if (f.width.value != "")
+		oldWidth = nw;
+
+	if (f.height.value != "")
+		oldHeight = nh;
+
+	// After constrain
+	pl = serializeParameters();
+
+	switch (f.media_type.options[f.media_type.selectedIndex].value) {
+		case "flash":
+			cls = 'clsid:D27CDB6E-AE6D-11cf-96B8-444553540000';
+			codebase = 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0';
+			type = 'application/x-shockwave-flash';
+			break;
+
+		case "shockwave":
+			cls = 'clsid:166B1BCA-3F9C-11CF-8075-444553540000';
+			codebase = 'http://download.macromedia.com/pub/shockwave/cabs/director/sw.cab#version=8,5,1,0';
+			type = 'application/x-director';
+			break;
+
+		case "qt":
+			cls = 'clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B';
+			codebase = 'http://www.apple.com/qtactivex/qtplugin.cab#version=6,0,2,0';
+			type = 'video/quicktime';
+			break;
+
+		case "wmp":
+			cls = tinyMCE.getParam('media_wmp6_compatible') ? 'clsid:05589FA1-C356-11CE-BF01-00AA0055595A' : 'clsid:6BF52A52-394A-11D3-B153-00C04F79FAA6';
+			codebase = 'http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=5,1,52,701';
+			type = 'application/x-mplayer2';
+			break;
+
+		case "rmp":
+			cls = 'clsid:CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA';
+			codebase = 'http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=5,1,52,701';
+			type = 'audio/x-pn-realaudio-plugin';
+			break;
+	}
+
+	if (pl == '') {
+		p.innerHTML = '';
+		return;
+	}
+
+	pl = eval('x={' + pl + '};');
+
+	if (!pl.src) {
+		p.innerHTML = '';
+		return;
+	}
+
+	pl.src = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], pl.src);
+	pl.width = !pl.width ? 100 : pl.width;
+	pl.height = !pl.height ? 100 : pl.height;
+	pl.id = !pl.id ? 'obj' : pl.id;
+	pl.name = !pl.name ? 'eobj' : pl.name;
+	pl.align = !pl.align ? '' : pl.align;
+
+	h += '<object classid="clsid:' + cls + '" codebase="' + codebase + '" width="' + pl.width + '" height="' + pl.height + '" id="' + pl.id + '" name="' + pl.name + '" align="' + pl.align + '">';
+
+	for (n in pl) {
+		h += '<param name="' + n + '" value="' + pl[n] + '">';
+
+		// Add extra url parameter if it's an absolute URL
+		if (n == 'src' && pl[n].indexOf('://') != -1)
+			h += '<param name="url" value="' + pl[n] + '" />';
+	}
+
+	h += '<embed type="' + type + '" ';
+
+	for (n in pl)
+		h += n + '="' + pl[n] + '" ';
+
+	h += '></embed></object>';
+
+	p.innerHTML = "<!-- x --->" + h;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/media/langs/en.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,94 @@
+// UK lang variables
+
+tinyMCE.addToLang('media',{
+title : 'Insert / edit embedded media',
+desc : 'Insert / edit embedded media',
+general : 'General',
+advanced : 'Advanced',
+file : 'File',
+list : 'List',
+size : 'Dimensions',
+preview : 'Preview',
+constrain_proportions : 'Constrain proportions',
+type : 'Type',
+id : 'Id',
+name : 'Name',
+class_name : 'Class',
+vspace : 'V-Space',
+hspace : 'H-Space',
+play : 'Auto play',
+loop : 'Loop',
+menu : 'Show menu',
+quality : 'Quality',
+scale : 'Scale',
+align : 'Align',
+salign : 'SAlign',
+wmode : 'WMode',
+bgcolor : 'Background',
+base : 'Base',
+flashvars : 'Flashvars',
+liveconnect : 'SWLiveConnect',
+autohref : 'AutoHREF',
+cache : 'Cache',
+hidden : 'Hidden',
+controller : 'Controller',
+kioskmode : 'Kiosk mode',
+playeveryframe : 'Play every frame',
+targetcache : 'Target cache',
+correction : 'No correction',
+enablejavascript : 'Enable JavaScript',
+starttime : 'Start time',
+endtime : 'End time',
+href : 'Href',
+qtsrcchokespeed : 'Choke speed',
+target : 'Target',
+volume : 'Volume',
+autostart : 'Auto start',
+enabled : 'Enabled',
+fullscreen : 'Fullscreen',
+invokeurls : 'Invoke URLs',
+mute : 'Mute',
+stretchtofit : 'Stretch to fit',
+windowlessvideo : 'Windowless video',
+balance : 'Balance',
+baseurl : 'Base URL',
+captioningid : 'Captioning id',
+currentmarker : 'Current marker',
+currentposition : 'Current position',
+defaultframe : 'Default frame',
+playcount : 'Play count',
+rate : 'Rate',
+uimode : 'UI Mode',
+flash_options : 'Flash options',
+qt_options : 'Quicktime options',
+wmp_options : 'Windows media player options',
+rmp_options : 'Real media player options',
+shockwave_options : 'Shockwave options',
+autogotourl : 'Auto goto URL',
+center : 'Center',
+imagestatus : 'Image status',
+maintainaspect : 'Maintain aspect',
+nojava : 'No java',
+prefetch : 'Prefetch',
+shuffle : 'Shuffle',
+console : 'Console',
+numloop : 'Num loops',
+controls : 'Controls',
+scriptcallbacks : 'Script callbacks',
+swstretchstyle : 'Stretch style',
+swstretchhalign : 'Stretch H-Align',
+swstretchvalign : 'Stretch V-Align',
+sound : 'Sound',
+progress : 'Progress',
+qtsrc : 'QT Src',
+qt_stream_warn : 'Streamed rtsp resources should be added to the QT Src field under the advanced tab.\nYou should also add a non streamed version to the Src field..',
+align_top : 'Top',
+align_right : 'Right',
+align_bottom : 'Bottom',
+align_left : 'Left',
+align_center : 'Center',
+align_top_left : 'Top left',
+align_top_right : 'Top right',
+align_bottom_left : 'Bottom left',
+align_bottom_right : 'Bottom right'
+});
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/media/media.htm	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,723 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>{$lang_media_title}</title>
+	<script language="javascript" type="text/javascript" src="../../tiny_mce_popup.js"></script>
+	<script language="javascript" type="text/javascript" src="jscripts/media.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/mctabs.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/validate.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/form_utils.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/editable_selects.js"></script>
+	<link href="css/media.css" rel="stylesheet" type="text/css" />
+	<base target="_self" />
+</head>
+<body onload="tinyMCEPopup.executeOnLoad('init();');" style="display: none">
+    <form onsubmit="insertMedia();return false;" action="#">
+		<div class="tabs">
+			<ul>
+				<li id="general_tab" class="current"><span><a href="javascript:mcTabs.displayTab('general_tab','general_panel');generatePreview();" onmousedown="return false;">{$lang_media_general}</a></span></li>
+				<li id="advanced_tab"><span><a href="javascript:mcTabs.displayTab('advanced_tab','advanced_panel');" onmousedown="return false;">{$lang_media_advanced}</a></span></li>
+			</ul>
+		</div>
+
+		<div class="panel_wrapper">
+			<div id="general_panel" class="panel current">
+				<fieldset>
+					<legend>{$lang_media_general}</legend>
+
+					<table border="0" cellpadding="4" cellspacing="0">
+							<tr>
+								<td><label for="media_type">{$lang_media_type}</label></td>
+								<td>
+									<select id="media_type" name="media_type" onchange="changedType(this.value);generatePreview();">
+										<option value="flash">Flash</option>
+										<option value="qt">Quicktime</option>
+										<option value="shockwave">Shockware</option>
+										<option value="wmp">Windows Media</option>
+										<option value="rmp">Real Media</option>
+									</select>
+								</td>
+							</tr>
+							<tr>
+							<td><label for="src">{$lang_media_file}</label></td>
+							  <td>
+									<table border="0" cellspacing="0" cellpadding="0">
+									  <tr>
+										<td><input id="src" name="src" type="text" value="" onchange="switchType(this.value);generatePreview();" /></td>
+										<td id="filebrowsercontainer">&nbsp;</td>
+									  </tr>
+									</table>
+								</td>
+							</tr>
+							<tr id="linklistrow">
+								<td><label for="linklist">{$lang_media_list}</label></td>
+								<td id="linklistcontainer">&nbsp;</td>
+							</tr>
+							<tr>
+								<td><label for="width">{$lang_media_size}</label></td>
+								<td>
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input type="text" id="width" name="width" value="" class="size" onchange="generatePreview('width');" /> x <input type="text" id="height" name="height" value="" class="size"  onchange="generatePreview('height');" /></td>
+										<td>&nbsp;&nbsp;<input id="constrain" type="checkbox" name="constrain" class="checkbox" /></td>
+										<td><label id="constrainlabel" for="constrain">{$lang_media_constrain_proportions}</label></td>
+									</tr>
+								</table>
+							</tr>
+					</table>
+				</fieldset>
+
+				<fieldset>
+					<legend>{$lang_media_preview}</legend>
+					<div id="prev"></div>
+				</fieldset>
+			</div>
+
+			<div id="advanced_panel" class="panel">
+				<fieldset>
+					<legend>{$lang_media_advanced}</legend>
+
+					<table border="0" cellpadding="4" cellspacing="0" width="100%">
+						<tr>
+							<td><label for="id">{$lang_media_id}</label></td>
+							<td><input type="text" id="id" name="id" onchange="generatePreview();" /></td>
+							<td><label for="name">{$lang_media_name}</label></td>
+							<td><input type="text" id="name" name="name" onchange="generatePreview();" /></td>
+						</tr>
+
+						<tr>
+							<td><label for="align">{$lang_media_align}</label></td>
+							<td>
+								<select id="align" name="align" onchange="generatePreview();">
+									<option value="">{$lang_not_set}</option> 
+									<option value="top">{$lang_media_align_top}</option>
+									<option value="right">{$lang_media_align_right}</option>
+									<option value="bottom">{$lang_media_align_bottom}</option>
+									<option value="left">{$lang_media_align_left}</option>
+								</select>
+							</td>
+
+							<td><label for="bgcolor">{$lang_media_bgcolor}</label></td>
+							<td>
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input id="bgcolor" name="bgcolor" type="text" value="" size="9" onchange="updateColor('bgcolor_pick','bgcolor');generatePreview();" /></td>
+										<td id="bgcolor_pickcontainer">&nbsp;</td>
+									</tr>
+								</table>
+							</td>
+						</tr>
+
+						<tr>
+							<td><label for="vspace">{$lang_media_vspace}</label></td>
+							<td><input type="text" id="vspace" name="vspace" class="number" onchange="generatePreview();" /></td>
+							<td><label for="hspace">{$lang_media_hspace}</label></td>
+							<td><input type="text" id="hspace" name="hspace" class="number" onchange="generatePreview();" /></td>
+						</tr>
+					</table>
+				</fieldset>
+
+				<fieldset id="flash_options">
+					<legend>{$lang_media_flash_options}</legend>
+
+					<table border="0" cellpadding="4" cellspacing="0">
+						<tr>
+							<td><label for="flash_quality">{$lang_media_quality}</label></td>
+							<td>
+								<select id="flash_quality" name="flash_quality" onchange="generatePreview();">
+									<option value="">{$lang_not_set}</option> 
+									<option value="high">high</option>
+									<option value="low">low</option>
+									<option value="autolow">autolow</option>
+									<option value="autohigh">autohigh</option>
+									<option value="best">best</option>
+								</select>
+							</td>
+
+							<td><label for="flash_scale">{$lang_media_scale}</label></td>
+							<td>
+								<select id="flash_scale" name="flash_scale" onchange="generatePreview();">
+									<option value="">{$lang_not_set}</option> 
+									<option value="showall">showall</option>
+									<option value="noborder">noborder</option>
+									<option value="exactfit">exactfit</option>
+								</select>
+							</td>
+						</tr>
+
+						<tr>
+							<td><label for="flash_wmode">{$lang_media_wmode}</label></td>
+							<td>
+								<select id="flash_wmode" name="flash_wmode" onchange="generatePreview();">
+									<option value="">{$lang_not_set}</option> 
+									<option value="window">window</option>
+									<option value="opaque">opaque</option>
+									<option value="transparent">transparent</option>
+								</select>
+							</td>
+
+							<td><label for="flash_salign">{$lang_media_salign}</label></td>
+							<td>
+								<select id="flash_salign" name="flash_salign" onchange="generatePreview();">
+									<option value="">{$lang_not_set}</option> 
+									<option value="l">{$lang_media_align_left}</option>
+									<option value="t">{$lang_media_align_top}</option>
+									<option value="r">{$lang_media_align_right}</option>
+									<option value="b">{$lang_media_align_bottom}</option>
+									<option value="tl">{$lang_media_align_top_left}</option>
+									<option value="tr">{$lang_media_align_top_right}</option>
+									<option value="bl">{$lang_media_align_bottom_left}</option>
+									<option value="br">{$lang_media_align_bottom_right}</option>
+								</select>
+							</td>
+						</tr>
+
+						<tr>
+							<td colspan="2">
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input type="checkbox" class="checkbox" id="flash_play" name="flash_play" checked="checked" onchange="generatePreview();" /></td>
+										<td><label for="flash_play">{$lang_media_play}</label></td>
+									</tr>
+								</table>
+							</td>
+
+							<td colspan="2">
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input type="checkbox" class="checkbox" id="flash_loop" name="flash_loop" checked="checked" onchange="generatePreview();" /></td>
+										<td><label for="flash_loop">{$lang_media_loop}</label></td>
+									</tr>
+								</table>
+							</td>
+						</tr>
+
+						<tr>
+							<td colspan="2">
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input type="checkbox" class="checkbox" id="flash_menu" name="flash_menu" checked="checked" onchange="generatePreview();" /></td>
+										<td><label for="flash_menu">{$lang_media_menu}</label></td>
+									</tr>
+								</table>
+							</td>
+
+							<td colspan="2">
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input type="checkbox" class="checkbox" id="flash_swliveconnect" name="flash_swliveconnect" onchange="generatePreview();" /></td>
+										<td><label for="flash_swliveconnect">{$lang_media_liveconnect}</label></td>
+									</tr>
+								</table>
+							</td>
+						</tr>
+					</table>
+
+					<table>
+						<tr>
+							<td><label for="flash_base">{$lang_media_base}</label></td>
+							<td><input type="text" id="flash_base" name="flash_base" onchange="generatePreview();" /></td>
+						</tr>
+
+						<tr>
+							<td><label for="flash_flashvars">{$lang_media_flashvars}</label></td>
+							<td><input type="text" id="flash_flashvars" name="flash_flashvars" onchange="generatePreview();" /></td>
+						</tr>
+					</table>
+				</fieldset>
+
+				<fieldset id="qt_options">
+					<legend>{$lang_media_qt_options}</legend>
+
+					<table border="0" cellpadding="4" cellspacing="0">
+						<tr>
+							<td colspan="2">
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input type="checkbox" class="checkbox" id="qt_loop" name="qt_loop" onchange="generatePreview();" /></td>
+										<td><label for="qt_loop">{$lang_media_loop}</label></td>
+									</tr>
+								</table>
+							</td>
+
+							<td colspan="2">
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input type="checkbox" class="checkbox" id="qt_autoplay" name="qt_autoplay" onchange="generatePreview();" /></td>
+										<td><label for="qt_autoplay">{$lang_media_play}</label></td>
+									</tr>
+								</table>
+							</td>
+						</tr>
+
+						<tr>
+							<td colspan="2">
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input type="checkbox" class="checkbox" id="qt_cache" name="qt_cache" onchange="generatePreview();" /></td>
+										<td><label for="qt_cache">{$lang_media_cache}</label></td>
+									</tr>
+								</table>
+							</td>
+
+							<td colspan="2">
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input type="checkbox" class="checkbox" id="qt_controller" name="qt_controller" checked="checked" onchange="generatePreview();" /></td>
+										<td><label for="qt_controller">{$lang_media_controller}</label></td>
+									</tr>
+								</table>
+							</td>
+						</tr>
+
+						<tr>
+							<td colspan="2">
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input type="checkbox" class="checkbox" id="qt_correction" name="qt_correction" onchange="generatePreview();" /></td>
+										<td><label for="qt_correction">{$lang_media_correction}</label></td>
+									</tr>
+								</table>
+							</td>
+
+							<td colspan="2">
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input type="checkbox" class="checkbox" id="qt_enablejavascript" name="qt_enablejavascript" onchange="generatePreview();" /></td>
+										<td><label for="qt_enablejavascript">{$lang_media_enablejavascript}</label></td>
+									</tr>
+								</table>
+							</td>
+						</tr>
+
+						<tr>
+							<td colspan="2">
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input type="checkbox" class="checkbox" id="qt_kioskmode" name="qt_kioskmode" onchange="generatePreview();" /></td>
+										<td><label for="qt_kioskmode">{$lang_media_kioskmode}</label></td>
+									</tr>
+								</table>
+							</td>
+
+							<td colspan="2">
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input type="checkbox" class="checkbox" id="qt_autohref" name="qt_autohref" onchange="generatePreview();" /></td>
+										<td><label for="qt_autohref">{$lang_media_autohref}</label></td>
+									</tr>
+								</table>
+							</td>
+						</tr>
+
+						<tr>
+							<td colspan="2">
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input type="checkbox" class="checkbox" id="qt_playeveryframe" name="qt_playeveryframe" onchange="generatePreview();" /></td>
+										<td><label for="qt_playeveryframe">{$lang_media_playeveryframe}</label></td>
+									</tr>
+								</table>
+							</td>
+
+							<td colspan="2">
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input type="checkbox" class="checkbox" id="qt_targetcache" name="qt_targetcache" onchange="generatePreview();" /></td>
+										<td><label for="qt_targetcache">{$lang_media_targetcache}</label></td>
+									</tr>
+								</table>
+							</td>
+						</tr>
+
+						<tr>
+							<td><label for="qt_scale">{$lang_media_scale}</label></td>
+							<td><select id="qt_scale" name="qt_scale" class="mceEditableSelect" onchange="generatePreview();">
+									<option value="">{$lang_not_set}</option> 
+									<option value="tofit">tofit</option>
+									<option value="aspect">aspect</option>
+								</select>
+							</td>
+
+							<td colspan="2">&nbsp;</td>
+						</tr>
+
+						<tr>
+							<td><label for="qt_starttime">{$lang_media_starttime}</label></td>
+							<td><input type="text" id="qt_starttime" name="qt_starttime" onchange="generatePreview();" /></td>
+
+							<td><label for="qt_endtime">{$lang_media_endtime}</label></td>
+							<td><input type="text" id="qt_endtime" name="qt_endtime" onchange="generatePreview();" /></td>
+						</tr>
+
+						<tr>
+							<td><label for="qt_target">{$lang_media_target}</label></td>
+							<td><input type="text" id="qt_target" name="qt_target" onchange="generatePreview();" /></td>
+
+							<td><label for="qt_href">{$lang_media_href}</label></td>
+							<td><input type="text" id="qt_href" name="qt_href" onchange="generatePreview();" /></td>
+						</tr>
+
+						<tr>
+							<td><label for="qt_qtsrcchokespeed">{$lang_media_qtsrcchokespeed}</label></td>
+							<td><input type="text" id="qt_qtsrcchokespeed" name="qt_qtsrcchokespeed" onchange="generatePreview();" /></td>
+
+							<td><label for="qt_volume">{$lang_media_volume}</label></td>
+							<td><input type="text" id="qt_volume" name="qt_volume" onchange="generatePreview();" /></td>
+						</tr>
+
+						<tr>
+							<td><label for="qt_qtsrc">{$lang_media_qtsrc}</label></td>
+							<td colspan="4">
+							<table border="0" cellspacing="0" cellpadding="0">
+								  <tr>
+									<td><input type="text" id="qt_qtsrc" name="qt_qtsrc" onchange="generatePreview();" /></td>
+									<td id="qtsrcfilebrowsercontainer">&nbsp;</td>
+								  </tr>
+							</table>
+							</td>
+						</tr>
+					</table>
+				</fieldset>
+
+				<fieldset id="wmp_options">
+					<legend>{$lang_media_wmp_options}</legend>
+
+					<table border="0" cellpadding="4" cellspacing="0">
+						<tr>
+							<td colspan="2">
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input type="checkbox" class="checkbox" id="wmp_autostart" name="wmp_autostart" checked="checked" onchange="generatePreview();" /></td>
+										<td><label for="wmp_autostart">{$lang_media_autostart}</label></td>
+									</tr>
+								</table>
+							</td>
+
+							<td colspan="2">
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input type="checkbox" class="checkbox" id="wmp_enabled" name="wmp_enabled" onchange="generatePreview();" /></td>
+										<td><label for="wmp_enabled">{$lang_media_enabled}</label></td>
+									</tr>
+								</table>
+							</td>
+						</tr>
+
+						<tr>
+							<td colspan="2">
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input type="checkbox" class="checkbox" id="wmp_enablecontextmenu" name="wmp_enablecontextmenu" checked="checked" onchange="generatePreview();" /></td>
+										<td><label for="wmp_enablecontextmenu">{$lang_media_menu}</label></td>
+									</tr>
+								</table>
+							</td>
+
+							<td colspan="2">
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input type="checkbox" class="checkbox" id="wmp_fullscreen" name="wmp_fullscreen" onchange="generatePreview();" /></td>
+										<td><label for="wmp_fullscreen">{$lang_media_fullscreen}</label></td>
+									</tr>
+								</table>
+							</td>
+						</tr>
+
+						<tr>
+							<td colspan="2">
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input type="checkbox" class="checkbox" id="wmp_invokeurls" name="wmp_invokeurls" checked="checked" onchange="generatePreview();" /></td>
+										<td><label for="wmp_invokeurls">{$lang_media_invokeurls}</label></td>
+									</tr>
+								</table>
+							</td>
+
+							<td colspan="2">
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input type="checkbox" class="checkbox" id="wmp_mute" name="wmp_mute" onchange="generatePreview();" /></td>
+										<td><label for="wmp_mute">{$lang_media_mute}</label></td>
+									</tr>
+								</table>
+							</td>
+						</tr>
+
+						<tr>
+							<td colspan="2">
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input type="checkbox" class="checkbox" id="wmp_stretchtofit" name="wmp_stretchtofit" onchange="generatePreview();" /></td>
+										<td><label for="wmp_stretchtofit">{$lang_media_stretchtofit}</label></td>
+									</tr>
+								</table>
+							</td>
+
+							<td colspan="2">
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input type="checkbox" class="checkbox" id="wmp_windowlessvideo" name="wmp_windowlessvideo" onchange="generatePreview();" /></td>
+										<td><label for="wmp_windowlessvideo">{$lang_media_windowlessvideo}</label></td>
+									</tr>
+								</table>
+							</td>
+						</tr>
+
+						<tr>
+							<td><label for="wmp_balance">{$lang_media_balance}</label></td>
+							<td><input type="text" id="wmp_balance" name="wmp_balance" onchange="generatePreview();" /></td>
+
+							<td><label for="wmp_baseurl">{$lang_media_baseurl}</label></td>
+							<td><input type="text" id="wmp_baseurl" name="wmp_baseurl" onchange="generatePreview();" /></td>
+						</tr>
+
+						<tr>
+							<td><label for="wmp_captioningid">{$lang_media_captioningid}</label></td>
+							<td><input type="text" id="wmp_captioningid" name="wmp_captioningid" onchange="generatePreview();" /></td>
+
+							<td><label for="wmp_currentmarker">{$lang_media_currentmarker}</label></td>
+							<td><input type="text" id="wmp_currentmarker" name="wmp_currentmarker" onchange="generatePreview();" /></td>
+						</tr>
+
+						<tr>
+							<td><label for="wmp_currentposition">{$lang_media_currentposition}</label></td>
+							<td><input type="text" id="wmp_currentposition" name="wmp_currentposition" onchange="generatePreview();" /></td>
+
+							<td><label for="wmp_defaultframe">{$lang_media_defaultframe}</label></td>
+							<td><input type="text" id="wmp_defaultframe" name="wmp_defaultframe" onchange="generatePreview();" /></td>
+						</tr>
+
+						<tr>
+							<td><label for="wmp_playcount">{$lang_media_playcount}</label></td>
+							<td><input type="text" id="wmp_playcount" name="wmp_playcount" onchange="generatePreview();" /></td>
+
+							<td><label for="wmp_rate">{$lang_media_rate}</label></td>
+							<td><input type="text" id="wmp_rate" name="wmp_rate" onchange="generatePreview();" /></td>
+						</tr>
+
+						<tr>
+							<td><label for="wmp_uimode">{$lang_media_uimode}</label></td>
+							<td><input type="text" id="wmp_uimode" name="wmp_uimode" onchange="generatePreview();" /></td>
+
+							<td><label for="wmp_volume">{$lang_media_volume}</label></td>
+							<td><input type="text" id="wmp_volume" name="wmp_volume" onchange="generatePreview();" /></td>
+						</tr>
+
+					</table>
+				</fieldset>
+
+				<fieldset id="rmp_options">
+					<legend>{$lang_media_rmp_options}</legend>
+
+					<table border="0" cellpadding="4" cellspacing="0">
+						<tr>
+							<td colspan="2">
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input type="checkbox" class="checkbox" id="rmp_autostart" name="rmp_autostart" onchange="generatePreview();" /></td>
+										<td><label for="rmp_autostart">{$lang_media_autostart}</label></td>
+									</tr>
+								</table>
+							</td>
+
+							<td colspan="2">
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input type="checkbox" class="checkbox" id="rmp_loop" name="rmp_loop" onchange="generatePreview();" /></td>
+										<td><label for="rmp_loop">{$lang_media_loop}</label></td>
+									</tr>
+								</table>
+							</td>
+						</tr>
+
+						<tr>
+							<td colspan="2">
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input type="checkbox" class="checkbox" id="rmp_autogotourl" name="rmp_autogotourl" checked="checked" onchange="generatePreview();" /></td>
+										<td><label for="rmp_autogotourl">{$lang_media_autogotourl}</label></td>
+									</tr>
+								</table>
+							</td>
+
+							<td colspan="2">
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input type="checkbox" class="checkbox" id="rmp_center" name="rmp_center" onchange="generatePreview();" /></td>
+										<td><label for="rmp_center">{$lang_media_center}</label></td>
+									</tr>
+								</table>
+							</td>
+						</tr>
+
+						<tr>
+							<td colspan="2">
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input type="checkbox" class="checkbox" id="rmp_imagestatus" name="rmp_imagestatus" checked="checked" onchange="generatePreview();" /></td>
+										<td><label for="rmp_imagestatus">{$lang_media_imagestatus}</label></td>
+									</tr>
+								</table>
+							</td>
+
+							<td colspan="2">
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input type="checkbox" class="checkbox" id="rmp_maintainaspect" name="rmp_maintainaspect" onchange="generatePreview();" /></td>
+										<td><label for="rmp_maintainaspect">{$lang_media_maintainaspect}</label></td>
+									</tr>
+								</table>
+							</td>
+						</tr>
+
+						<tr>
+							<td colspan="2">
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input type="checkbox" class="checkbox" id="rmp_nojava" name="rmp_nojava" onchange="generatePreview();" /></td>
+										<td><label for="rmp_nojava">{$lang_media_nojava}</label></td>
+									</tr>
+								</table>
+							</td>
+
+							<td colspan="2">
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input type="checkbox" class="checkbox" id="rmp_prefetch" name="rmp_prefetch" onchange="generatePreview();" /></td>
+										<td><label for="rmp_prefetch">{$lang_media_prefetch}</label></td>
+									</tr>
+								</table>
+							</td>
+						</tr>
+
+						<tr>
+							<td colspan="2">
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input type="checkbox" class="checkbox" id="rmp_shuffle" name="rmp_shuffle" onchange="generatePreview();" /></td>
+										<td><label for="rmp_shuffle">{$lang_media_shuffle}</label></td>
+									</tr>
+								</table>
+							</td>
+
+							<td colspan="2">
+								&nbsp;
+							</td>
+						</tr>
+
+						<tr>
+							<td><label for="rmp_console">{$lang_media_console}</label></td>
+							<td><input type="text" id="rmp_console" name="rmp_console" onchange="generatePreview();" /></td>
+
+							<td><label for="rmp_controls">{$lang_media_controls}</label></td>
+							<td><input type="text" id="rmp_controls" name="rmp_controls" onchange="generatePreview();" /></td>
+						</tr>
+
+						<tr>
+							<td><label for="rmp_numloop">{$lang_media_numloop}</label></td>
+							<td><input type="text" id="rmp_numloop" name="rmp_numloop" onchange="generatePreview();" /></td>
+
+							<td><label for="rmp_scriptcallbacks">{$lang_media_scriptcallbacks}</label></td>
+							<td><input type="text" id="rmp_scriptcallbacks" name="rmp_scriptcallbacks" onchange="generatePreview();" /></td>
+						</tr>
+					</table>
+				</fieldset>
+
+				<fieldset id="shockwave_options">
+					<legend>{$lang_media_shockwave_options}</legend>
+
+					<table border="0" cellpadding="4" cellspacing="0">
+						<tr>
+							<td><label for="shockwave_swstretchstyle">{$lang_media_swstretchstyle}</label></td>
+							<td>
+								<select id="shockwave_swstretchstyle" name="shockwave_swstretchstyle" onchange="generatePreview();">
+									<option value="none">{$lang_not_set}</option>
+									<option value="meet">Meet</option>
+									<option value="fill">Fill</option>
+									<option value="stage">Stage</option>
+								</select>
+							</td>
+
+							<td><label for="shockwave_swvolume">{$lang_media_volume}</label></td>
+							<td><input type="text" id="shockwave_swvolume" name="shockwave_swvolume" onchange="generatePreview();" /></td>
+						</tr>
+
+						<tr>
+							<td><label for="shockwave_swstretchhalign">{$lang_media_swstretchhalign}</label></td>
+							<td>
+								<select id="shockwave_swstretchhalign" name="shockwave_swstretchhalign" onchange="generatePreview();">
+									<option value="none">{$lang_not_set}</option>
+									<option value="left">{$lang_media_align_left}</option>
+									<option value="center">{$lang_media_align_center}</option>
+									<option value="right">{$lang_media_align_right}</option>
+								</select>
+							</td>
+
+							<td><label for="shockwave_swstretchvalign">{$lang_media_swstretchvalign}</label></td>
+							<td>
+								<select id="shockwave_swstretchvalign" name="shockwave_swstretchvalign" onchange="generatePreview();">
+									<option value="none">{$lang_not_set}</option>
+									<option value="meet">Meet</option>
+									<option value="fill">Fill</option>
+									<option value="stage">Stage</option>
+								</select>
+							</td>
+						</tr>
+
+						<tr>
+							<td colspan="2">
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input type="checkbox" class="checkbox" id="shockwave_autostart" name="shockwave_autostart" onchange="generatePreview();" checked="checked" /></td>
+										<td><label for="shockwave_autostart">{$lang_media_autostart}</label></td>
+									</tr>
+								</table>
+							</td>
+
+							<td colspan="2">
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input type="checkbox" class="checkbox" id="shockwave_sound" name="shockwave_sound" onchange="generatePreview();" checked="checked" /></td>
+										<td><label for="shockwave_sound">{$lang_media_sound}</label></td>
+									</tr>
+								</table>
+							</td>
+						</tr>
+
+
+						<tr>
+							<td colspan="2">
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input type="checkbox" class="checkbox" id="shockwave_swliveconnect" name="shockwave_swliveconnect" onchange="generatePreview();" /></td>
+										<td><label for="shockwave_swliveconnect">{$lang_media_liveconnect}</label></td>
+									</tr>
+								</table>
+							</td>
+
+							<td colspan="2">
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input type="checkbox" class="checkbox" id="shockwave_progress" name="shockwave_progress" onchange="generatePreview();" checked="checked" /></td>
+										<td><label for="shockwave_progress">{$lang_media_progress}</label></td>
+									</tr>
+								</table>
+							</td>
+						</tr>
+					</table>
+				</fieldset>
+			</div>
+		</div>
+
+		<div class="mceActionPanel">
+			<div style="float: left">
+				<input type="button" id="insert" name="insert" value="{$lang_insert}" onclick="insertMedia();" />
+			</div>
+
+			<div style="float: right">
+				<input type="button" id="cancel" name="cancel" value="{$lang_cancel}" onclick="tinyMCEPopup.close();" />
+			</div>
+		</div>
+	</form>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/nonbreaking/editor_plugin.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+tinyMCE.importPluginLanguagePack('nonbreaking');var TinyMCE_NonBreakingPlugin={getInfo:function(){return{longname:'Nonbreaking space',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/nonbreaking',version:tinyMCE.majorVersion+"."+tinyMCE.minorVersion}},getControlHTML:function(cn){switch(cn){case"nonbreaking":return tinyMCE.getButtonHTML(cn,'lang_nonbreaking_desc','{$pluginurl}/images/nonbreaking.gif','mceNonBreaking',false)}return""},execCommand:function(editor_id,element,command,user_interface,value){var inst=tinyMCE.getInstanceById(editor_id),h;switch(command){case"mceNonBreaking":h=(inst.visualChars&&inst.visualChars.state)?'<span class="mceItemHiddenVisualChar">&middot;</span>':'&nbsp;';tinyMCE.execInstanceCommand(editor_id,'mceInsertContent',false,h);return true}return false},handleEvent:function(e){var inst,h;if(!tinyMCE.isOpera&&e.type=='keydown'&&e.keyCode==9&&tinyMCE.getParam('nonbreaking_force_tab',false)){inst=tinyMCE.selectedInstance;h=(inst.visualChars&&inst.visualChars.state)?'<span class="mceItemHiddenVisualChar">&middot;&middot;&middot;</span>':'&nbsp;&nbsp;&nbsp;';tinyMCE.execInstanceCommand(inst.editorId,'mceInsertContent',false,h);tinyMCE.cancelEvent(e);return false}return true}};tinyMCE.addPlugin("nonbreaking",TinyMCE_NonBreakingPlugin);
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/nonbreaking/editor_plugin_src.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,62 @@
+/**
+ * $Id: editor_plugin_src.js 42 2006-08-08 14:32:24Z spocke $
+ *
+ * @author Moxiecode
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+/* Import plugin specific language pack */
+tinyMCE.importPluginLanguagePack('nonbreaking');
+
+var TinyMCE_NonBreakingPlugin = {
+	getInfo : function() {
+		return {
+			longname : 'Nonbreaking space',
+			author : 'Moxiecode Systems AB',
+			authorurl : 'http://tinymce.moxiecode.com',
+			infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/nonbreaking',
+			version : tinyMCE.majorVersion + "." + tinyMCE.minorVersion
+		};
+	},
+
+	getControlHTML : function(cn) {
+		switch (cn) {
+			case "nonbreaking":
+				return tinyMCE.getButtonHTML(cn, 'lang_nonbreaking_desc', '{$pluginurl}/images/nonbreaking.gif', 'mceNonBreaking', false);
+		}
+
+		return "";
+	},
+
+
+	execCommand : function(editor_id, element, command, user_interface, value) {
+		var inst = tinyMCE.getInstanceById(editor_id), h;
+
+		switch (command) {
+			case "mceNonBreaking":
+				h = (inst.visualChars && inst.visualChars.state) ? '<span class="mceItemHiddenVisualChar">&middot;</span>' : '&nbsp;';
+				tinyMCE.execInstanceCommand(editor_id, 'mceInsertContent', false, h);
+				return true;
+		}
+
+		return false;
+	},
+
+	handleEvent : function(e) {
+		var inst, h;
+
+		if (!tinyMCE.isOpera && e.type == 'keydown' && e.keyCode == 9 && tinyMCE.getParam('nonbreaking_force_tab', false)) {
+			inst = tinyMCE.selectedInstance;
+
+			h = (inst.visualChars && inst.visualChars.state) ? '<span class="mceItemHiddenVisualChar">&middot;&middot;&middot;</span>' : '&nbsp;&nbsp;&nbsp;';
+			tinyMCE.execInstanceCommand(inst.editorId, 'mceInsertContent', false, h);
+
+			tinyMCE.cancelEvent(e);
+			return false;
+		}
+
+		return true;
+	}
+};
+
+tinyMCE.addPlugin("nonbreaking", TinyMCE_NonBreakingPlugin);
Binary file includes/clientside/tinymce/plugins/nonbreaking/images/nonbreaking.gif has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/nonbreaking/langs/en.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,5 @@
+// UK lang variables
+
+tinyMCE.addToLang('nonbreaking',{
+desc : 'Insert non-breaking space character'
+});
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/noneditable/css/noneditable.css	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,9 @@
+/* This is the CSS file for the noneditable elements plugin */
+
+.mceEditable {
+	/*border: 1px dotted #0000cc;*/
+}
+
+.mceNonEditable {
+	/*border: 1px dotted #cc0000;*/
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/noneditable/editor_plugin.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+var TinyMCE_NonEditablePlugin={getInfo:function(){return{longname:'Non editable elements',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/noneditable',version:tinyMCE.majorVersion+"."+tinyMCE.minorVersion}},initInstance:function(inst){tinyMCE.importCSS(inst.getDoc(),tinyMCE.baseURL+"/plugins/noneditable/css/noneditable.css");if(tinyMCE.isMSIE5_0)tinyMCE.settings['plugins']=tinyMCE.settings['plugins'].replace(/noneditable/gi,'Noneditable')},handleEvent:function(e){return this._moveSelection(e,tinyMCE.selectedInstance)},cleanup:function(type,content,inst){switch(type){case"insert_to_editor_dom":var nodes,i,editClass,nonEditClass,editable,elm;if(tinyMCE.isGecko)return content;nodes=tinyMCE.getNodeTree(content,[],1);editClass=tinyMCE.getParam("noneditable_editable_class","mceEditable");nonEditClass=tinyMCE.getParam("noneditable_noneditable_class","mceNonEditable");for(i=0;i<nodes.length;i++){elm=nodes[i];editable=tinyMCE.getAttrib(elm,"contenteditable");if(new RegExp("true|false","gi").test(editable))TinyMCE_NonEditablePlugin._setEditable(elm,editable=="true");if(tinyMCE.isIE){if(tinyMCE.hasCSSClass(elm,editClass))elm.contentEditable=true;if(tinyMCE.hasCSSClass(elm,nonEditClass))elm.contentEditable=false}}break;case"insert_to_editor":var editClass=tinyMCE.getParam("noneditable_editable_class","mceEditable");var nonEditClass=tinyMCE.getParam("noneditable_noneditable_class","mceNonEditable");content=content.replace(/mceItemEditable/g,editClass);content=content.replace(/mceItemNonEditable/g,nonEditClass);if(tinyMCE.isIE&&(content.indexOf(editClass)!=-1||content.indexOf(nonEditClass)!=-1)){content=content.replace(new RegExp("class=\"(.+)("+editClass+")\"","gi"),'class="$1$2" contenteditable="true"');content=content.replace(new RegExp("class=\"(.+)("+nonEditClass+")\"","gi"),'class="$1$2" contenteditable="false"');content=content.replace(new RegExp("class=\"("+editClass+")([^\"]*)\"","gi"),'class="$1$2" contenteditable="true"');content=content.replace(new RegExp("class=\"("+nonEditClass+")([^\"]*)\"","gi"),'class="$1$2" contenteditable="false"');content=content.replace(new RegExp("class=\"(.+)("+editClass+")([^\"]*)\"","gi"),'class="$1$2$3" contenteditable="true"');content=content.replace(new RegExp("class=\"(.+)("+nonEditClass+")([^\"]*)\"","gi"),'class="$1$2$3" contenteditable="false"')}break;case"get_from_editor_dom":if(tinyMCE.isGecko)return content;if(tinyMCE.getParam("noneditable_leave_contenteditable",false)){var nodes=tinyMCE.getNodeTree(content,new Array(),1);for(var i=0;i<nodes.length;i++)nodes[i].removeAttribute("contenteditable")}break}return content},_moveSelection:function(e,inst){var s,r,sc,ec,el,c=tinyMCE.getParam('noneditable_editable_class','mceNonEditable');if(!inst)return true;if(tinyMCE.isGecko){s=inst.selection.getSel();r=s.getRangeAt(0);sc=tinyMCE.getParentNode(r.startContainer,function(n){return tinyMCE.hasCSSClass(n,c)});ec=tinyMCE.getParentNode(r.endContainer,function(n){return tinyMCE.hasCSSClass(n,c)});sc&&r.setStartBefore(sc);ec&&r.setEndAfter(ec);if(sc||ec){if(e.type=='keypress'&&e.keyCode==39){el=sc||ec;}s.removeAllRanges();s.addRange(r);return tinyMCE.cancelEvent(e)}}return true},_setEditable:function(elm,state){var editClass=tinyMCE.getParam("noneditable_editable_class","mceEditable");var nonEditClass=tinyMCE.getParam("noneditable_noneditable_class","mceNonEditable");var className=elm.className?elm.className:"";if(className.indexOf(editClass)!=-1||className.indexOf(nonEditClass)!=-1)return;if((className=tinyMCE.getAttrib(elm,"class"))!="")className+=" ";className+=state?editClass:nonEditClass;elm.setAttribute("class",className);elm.className=className}};tinyMCE.addPlugin("noneditable",TinyMCE_NonEditablePlugin);
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/noneditable/editor_plugin_src.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,153 @@
+/**
+ * $Id: editor_plugin_src.js 205 2007-02-12 18:58:29Z spocke $
+ *
+ * @author Moxiecode
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+var TinyMCE_NonEditablePlugin = {
+	getInfo : function() {
+		return {
+			longname : 'Non editable elements',
+			author : 'Moxiecode Systems AB',
+			authorurl : 'http://tinymce.moxiecode.com',
+			infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/noneditable',
+			version : tinyMCE.majorVersion + "." + tinyMCE.minorVersion
+		};
+	},
+
+	initInstance : function(inst) {
+		tinyMCE.importCSS(inst.getDoc(), tinyMCE.baseURL + "/plugins/noneditable/css/noneditable.css");
+
+		// Ugly hack
+		if (tinyMCE.isMSIE5_0)
+			tinyMCE.settings['plugins'] = tinyMCE.settings['plugins'].replace(/noneditable/gi, 'Noneditable');
+	},
+
+	handleEvent : function(e) {
+		return this._moveSelection(e, tinyMCE.selectedInstance);
+	},
+
+	cleanup : function(type, content, inst) {
+		switch (type) {
+			case "insert_to_editor_dom":
+				var nodes, i, editClass, nonEditClass, editable, elm;
+
+				// Pass through Gecko
+				if (tinyMCE.isGecko)
+					return content;
+
+				nodes = tinyMCE.getNodeTree(content, [], 1);
+
+				editClass = tinyMCE.getParam("noneditable_editable_class", "mceEditable");
+				nonEditClass = tinyMCE.getParam("noneditable_noneditable_class", "mceNonEditable");
+
+				for (i=0; i<nodes.length; i++) {
+					elm = nodes[i];
+
+					// Convert contenteditable to classes
+					editable = tinyMCE.getAttrib(elm, "contenteditable");
+					if (new RegExp("true|false","gi").test(editable))
+						TinyMCE_NonEditablePlugin._setEditable(elm, editable == "true");
+
+					if (tinyMCE.isIE) {
+						if (tinyMCE.hasCSSClass(elm, editClass))
+							elm.contentEditable = true;
+
+						if (tinyMCE.hasCSSClass(elm, nonEditClass))
+							elm.contentEditable = false;
+					}
+				}
+
+				break;
+
+			case "insert_to_editor":
+				var editClass = tinyMCE.getParam("noneditable_editable_class", "mceEditable");
+				var nonEditClass = tinyMCE.getParam("noneditable_noneditable_class", "mceNonEditable");
+
+				// Replace mceItem to new school
+				content = content.replace(/mceItemEditable/g, editClass);
+				content = content.replace(/mceItemNonEditable/g, nonEditClass);
+
+				if (tinyMCE.isIE && (content.indexOf(editClass) != -1 || content.indexOf(nonEditClass) != -1)) {
+					content = content.replace(new RegExp("class=\"(.+)(" + editClass + ")\"", "gi"), 'class="$1$2" contenteditable="true"');
+					content = content.replace(new RegExp("class=\"(.+)(" + nonEditClass + ")\"", "gi"), 'class="$1$2" contenteditable="false"');
+					content = content.replace(new RegExp("class=\"(" + editClass + ")([^\"]*)\"", "gi"), 'class="$1$2" contenteditable="true"');
+					content = content.replace(new RegExp("class=\"(" + nonEditClass + ")([^\"]*)\"", "gi"), 'class="$1$2" contenteditable="false"');
+					content = content.replace(new RegExp("class=\"(.+)(" + editClass + ")([^\"]*)\"", "gi"), 'class="$1$2$3" contenteditable="true"');
+					content = content.replace(new RegExp("class=\"(.+)(" + nonEditClass + ")([^\"]*)\"", "gi"), 'class="$1$2$3" contenteditable="false"');
+				}
+
+				break;
+
+			case "get_from_editor_dom":
+				// Pass through Gecko
+				if (tinyMCE.isGecko)
+					return content;
+
+				if (tinyMCE.getParam("noneditable_leave_contenteditable", false)) {
+					var nodes = tinyMCE.getNodeTree(content, new Array(), 1);
+
+					for (var i=0; i<nodes.length; i++)
+						nodes[i].removeAttribute("contenteditable");
+				}
+
+				break;
+		}
+
+		return content;
+	},
+
+	_moveSelection : function(e, inst) {
+		var s, r, sc, ec, el, c = tinyMCE.getParam('noneditable_editable_class', 'mceNonEditable');
+
+		if (!inst)
+			return true;
+
+		// Always select whole element
+		if (tinyMCE.isGecko) {
+			s = inst.selection.getSel();
+			r = s.getRangeAt(0);
+			sc = tinyMCE.getParentNode(r.startContainer, function (n) {return tinyMCE.hasCSSClass(n, c);});
+			ec = tinyMCE.getParentNode(r.endContainer, function (n) {return tinyMCE.hasCSSClass(n, c);});
+
+			sc && r.setStartBefore(sc);
+			ec && r.setEndAfter(ec);
+
+			if (sc || ec) {
+				if (e.type == 'keypress' && e.keyCode == 39) {
+					el = sc || ec;
+
+					// Try!!
+				}
+
+				s.removeAllRanges();
+				s.addRange(r);
+
+				return tinyMCE.cancelEvent(e);
+			}
+		}
+
+		return true;
+	},
+
+	_setEditable : function(elm, state) {
+		var editClass = tinyMCE.getParam("noneditable_editable_class", "mceEditable");
+		var nonEditClass = tinyMCE.getParam("noneditable_noneditable_class", "mceNonEditable");
+
+		var className = elm.className ? elm.className : "";
+
+		if (className.indexOf(editClass) != -1 || className.indexOf(nonEditClass) != -1)
+			return;
+
+		if ((className = tinyMCE.getAttrib(elm, "class")) != "")
+			className += " ";
+
+		className += state ? editClass : nonEditClass;
+
+		elm.setAttribute("class", className);
+		elm.className = className;
+	}
+};
+
+tinyMCE.addPlugin("noneditable", TinyMCE_NonEditablePlugin);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/noneditable/readme.txt	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+Check the TinyMCE documentation for details on this plugin.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/paste/blank.htm	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,19 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>blank_page</title>
+	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+	<script language="javascript">
+		function init() {
+			document.body.contentEditable = true;
+			document.designMode = 'on';
+			parent.initIframe(document);
+			window.focus();
+		}
+	</script>
+	<link href="css/blank.css" rel="stylesheet" type="text/css" />
+	<base target="_self" />
+</head>
+<body onload="init();">
+
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/paste/css/blank.css	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,13 @@
+body {
+	background-color: #FFFFFF;
+	font-family: Verdana, Arial, Helvetica, sans-serif;
+	font-size: 10px;
+	scrollbar-3dlight-color: #F0F0EE;
+	scrollbar-arrow-color: #676662;
+	scrollbar-base-color: #F0F0EE;
+	scrollbar-darkshadow-color: #DDDDDD;
+	scrollbar-face-color: #E0E0DD;
+	scrollbar-highlight-color: #F0F0EE;
+	scrollbar-shadow-color: #F0F0EE;
+	scrollbar-track-color: #F5F5F5;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/paste/css/pasteword.css	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,3 @@
+.sourceIframe {
+	border: 1px solid #808080;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/paste/editor_plugin.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+tinyMCE.importPluginLanguagePack('paste');var TinyMCE_PastePlugin={getInfo:function(){return{longname:'Paste text/word',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/paste',version:tinyMCE.majorVersion+"."+tinyMCE.minorVersion}},initInstance:function(inst){if(tinyMCE.isMSIE&&tinyMCE.getParam("paste_auto_cleanup_on_paste",false))tinyMCE.addEvent(inst.getBody(),"paste",TinyMCE_PastePlugin._handlePasteEvent)},handleEvent:function(e){if(!tinyMCE.isRealIE&&tinyMCE.getParam("paste_auto_cleanup_on_paste",false)&&e.ctrlKey&&e.keyCode==86&&e.type=="keydown"){window.setTimeout('tinyMCE.selectedInstance.execCommand("mcePasteText",true)',1);return tinyMCE.cancelEvent(e)}return true},getControlHTML:function(cn){switch(cn){case"pastetext":return tinyMCE.getButtonHTML(cn,'lang_paste_text_desc','{$pluginurl}/images/pastetext.gif','mcePasteText',true);case"pasteword":return tinyMCE.getButtonHTML(cn,'lang_paste_word_desc','{$pluginurl}/images/pasteword.gif','mcePasteWord',true);case"selectall":return tinyMCE.getButtonHTML(cn,'lang_selectall_desc','{$pluginurl}/images/selectall.gif','mceSelectAll',true)}return''},execCommand:function(editor_id,element,command,user_interface,value){switch(command){case"mcePasteText":if(user_interface){if((tinyMCE.isMSIE&&!tinyMCE.isOpera)&&!tinyMCE.getParam('paste_use_dialog',false))TinyMCE_PastePlugin._insertText(clipboardData.getData("Text"),true);else{var template=new Array();template['file']='../../plugins/paste/pastetext.htm';template['width']=450;template['height']=400;var plain_text="";tinyMCE.openWindow(template,{editor_id:editor_id,plain_text:plain_text,resizable:"yes",scrollbars:"no",inline:"yes",mceDo:'insert'})}}else TinyMCE_PastePlugin._insertText(value['html'],value['linebreaks']);return true;case"mcePasteWord":if(user_interface){if((tinyMCE.isMSIE&&!tinyMCE.isOpera)&&!tinyMCE.getParam('paste_use_dialog',false)){TinyMCE_PastePlugin._insertWordContent(TinyMCE_PastePlugin._clipboardHTML())}else{var template=new Array();template['file']='../../plugins/paste/pasteword.htm';template['width']=450;template['height']=400;var plain_text="";tinyMCE.openWindow(template,{editor_id:editor_id,plain_text:plain_text,resizable:"yes",scrollbars:"no",inline:"yes",mceDo:'insert'})}}else TinyMCE_PastePlugin._insertWordContent(value);return true;case"mceSelectAll":tinyMCE.execInstanceCommand(editor_id,'selectall');return true}return false},_handlePasteEvent:function(e){switch(e.type){case"paste":var html=TinyMCE_PastePlugin._clipboardHTML();var r,inst=tinyMCE.selectedInstance;if(inst&&(r=inst.getRng())&&r.text.length>0)tinyMCE.execCommand('delete');if(html&&html.length>0)tinyMCE.execCommand('mcePasteWord',false,html);tinyMCE.cancelEvent(e);return false}return true},_insertText:function(content,bLinebreaks){if(content&&content.length>0){if(bLinebreaks){if(tinyMCE.getParam("paste_create_paragraphs",true)){var rl=tinyMCE.getParam("paste_replace_list",'\u2122,<sup>TM</sup>,\u2026,...,\u201c|\u201d,",\u2019,\',\u2013|\u2014|\u2015|\u2212,-').split(',');for(var i=0;i<rl.length;i+=2)content=content.replace(new RegExp(rl[i],'gi'),rl[i+1]);content=tinyMCE.regexpReplace(content,"\r\n\r\n","</p><p>","gi");content=tinyMCE.regexpReplace(content,"\r\r","</p><p>","gi");content=tinyMCE.regexpReplace(content,"\n\n","</p><p>","gi");if((pos=content.indexOf('</p><p>'))!=-1){tinyMCE.execCommand("Delete");var node=tinyMCE.selectedInstance.getFocusElement();var breakElms=new Array();do{if(node.nodeType==1){if(node.nodeName=="TD"||node.nodeName=="BODY")break;breakElms[breakElms.length]=node}}while(node=node.parentNode);var before="",after="</p>";before+=content.substring(0,pos);for(var i=0;i<breakElms.length;i++){before+="</"+breakElms[i].nodeName+">";after+="<"+breakElms[(breakElms.length-1)-i].nodeName+">"}before+="<p>";content=before+content.substring(pos+7)+after}}if(tinyMCE.getParam("paste_create_linebreaks",true)){content=tinyMCE.regexpReplace(content,"\r\n","<br />","gi");content=tinyMCE.regexpReplace(content,"\r","<br />","gi");content=tinyMCE.regexpReplace(content,"\n","<br />","gi")}}tinyMCE.execCommand("mceInsertRawHTML",false,content)}},_insertWordContent:function(content){if(content&&content.length>0){var bull=String.fromCharCode(8226);var middot=String.fromCharCode(183);var cb;if((cb=tinyMCE.getParam("paste_insert_word_content_callback",""))!="")content=eval(cb+"('before', content)");var rl=tinyMCE.getParam("paste_replace_list",'\u2122,<sup>TM</sup>,\u2026,...,\u201c|\u201d,",\u2019,\',\u2013|\u2014|\u2015|\u2212,-').split(',');for(var i=0;i<rl.length;i+=2)content=content.replace(new RegExp(rl[i],'gi'),rl[i+1]);if(tinyMCE.getParam("paste_convert_headers_to_strong",false)){content=content.replace(new RegExp('<p class=MsoHeading.*?>(.*?)<\/p>','gi'),'<p><b>$1</b></p>')}content=content.replace(new RegExp('tab-stops: list [0-9]+.0pt">','gi'),'">'+"--list--");content=content.replace(new RegExp(bull+"(.*?)<BR>","gi"),"<p>"+middot+"$1</p>");content=content.replace(new RegExp('<SPAN style="mso-list: Ignore">','gi'),"<span>"+bull);content=content.replace(/<o:p><\/o:p>/gi,"");content=content.replace(new RegExp('<br style="page-break-before: always;.*>','gi'),'-- page break --');content=content.replace(new RegExp('<(!--)([^>]*)(--)>','g'),"");if(tinyMCE.getParam("paste_remove_spans",true))content=content.replace(/<\/?span[^>]*>/gi,"");if(tinyMCE.getParam("paste_remove_styles",true))content=content.replace(new RegExp('<(\\w[^>]*) style="([^"]*)"([^>]*)','gi'),"<$1$3");content=content.replace(/<\/?font[^>]*>/gi,"");switch(tinyMCE.getParam("paste_strip_class_attributes","all")){case"all":content=content.replace(/<(\w[^>]*) class=([^ |>]*)([^>]*)/gi,"<$1$3");break;case"mso":content=content.replace(new RegExp('<(\\w[^>]*) class="?mso([^ |>]*)([^>]*)','gi'),"<$1$3");break}content=content.replace(new RegExp('href="?'+TinyMCE_PastePlugin._reEscape(""+document.location)+'','gi'),'href="'+tinyMCE.settings['document_base_url']);content=content.replace(/<(\w[^>]*) lang=([^ |>]*)([^>]*)/gi,"<$1$3");content=content.replace(/<\\?\?xml[^>]*>/gi,"");content=content.replace(/<\/?\w+:[^>]*>/gi,"");content=content.replace(/-- page break --\s*<p>&nbsp;<\/p>/gi,"");content=content.replace(/-- page break --/gi,"");if(!tinyMCE.settings['force_p_newlines']){content=content.replace('','','gi');content=content.replace('</p>','<br /><br />','gi')}if(!tinyMCE.isMSIE&&!tinyMCE.settings['force_p_newlines']){content=content.replace(/<\/?p[^>]*>/gi,"")}content=content.replace(/<\/?div[^>]*>/gi,"");if(tinyMCE.getParam("paste_convert_middot_lists",true)){var div=document.createElement("div");div.innerHTML=content;var className=tinyMCE.getParam("paste_unindented_list_class","unIndentedList");while(TinyMCE_PastePlugin._convertMiddots(div,"--list--"));while(TinyMCE_PastePlugin._convertMiddots(div,middot,className));while(TinyMCE_PastePlugin._convertMiddots(div,bull));content=div.innerHTML}if(tinyMCE.getParam("paste_convert_headers_to_strong",false)){content=content.replace(/<h[1-6]>&nbsp;<\/h[1-6]>/gi,'<p>&nbsp;&nbsp;</p>');content=content.replace(/<h[1-6]>/gi,'<p><b>');content=content.replace(/<\/h[1-6]>/gi,'</b></p>');content=content.replace(/<b>&nbsp;<\/b>/gi,'<b>&nbsp;&nbsp;</b>');content=content.replace(/^(&nbsp;)*/gi,'')}content=content.replace(/--list--/gi,"");if((cb=tinyMCE.getParam("paste_insert_word_content_callback",""))!="")content=eval(cb+"('after', content)");tinyMCE.execCommand("mceInsertContent",false,content);if(tinyMCE.getParam('paste_force_cleanup_wordpaste',true))window.setTimeout('tinyMCE.execCommand("mceCleanup");',1);}},_reEscape:function(s){var l="?.\\*[](){}+^$:";var o="";for(var i=0;i<s.length;i++){var c=s.charAt(i);if(l.indexOf(c)!=-1)o+='\\'+c;else o+=c}return o},_convertMiddots:function(div,search,class_name){var mdot=String.fromCharCode(183);var bull=String.fromCharCode(8226);var nodes=div.getElementsByTagName("p");var prevul;for(var i=0;i<nodes.length;i++){var p=nodes[i];if(p.innerHTML.indexOf(search)==0){var ul=document.createElement("ul");if(class_name)ul.className=class_name;var li=document.createElement("li");li.innerHTML=p.innerHTML.replace(new RegExp(''+mdot+'|'+bull+'|--list--|&nbsp;',"gi"),'');ul.appendChild(li);var np=p.nextSibling;while(np){if(np.nodeType==3&&new RegExp('^\\s$','m').test(np.nodeValue)){np=np.nextSibling;continue}if(search==mdot){if(np.nodeType==1&&new RegExp('^o(\\s+|&nbsp;)').test(np.innerHTML)){if(!prevul){prevul=ul;ul=document.createElement("ul");prevul.appendChild(ul)}np.innerHTML=np.innerHTML.replace(/^o/,'')}else{if(prevul){ul=prevul;prevul=null}if(np.nodeType!=1||np.innerHTML.indexOf(search)!=0)break}}else{if(np.nodeType!=1||np.innerHTML.indexOf(search)!=0)break}var cp=np.nextSibling;var li=document.createElement("li");li.innerHTML=np.innerHTML.replace(new RegExp(''+mdot+'|'+bull+'|--list--|&nbsp;',"gi"),'');np.parentNode.removeChild(np);ul.appendChild(li);np=cp}p.parentNode.replaceChild(ul,p);return true}}return false},_clipboardHTML:function(){var div=document.getElementById('_TinyMCE_clipboardHTML');if(!div){var div=document.createElement('DIV');div.id='_TinyMCE_clipboardHTML';with(div.style){visibility='hidden';overflow='hidden';position='absolute';width=1;height=1}document.body.appendChild(div)}div.innerHTML='';var rng=document.body.createTextRange();rng.moveToElementText(div);rng.execCommand('Paste');var html=div.innerHTML;div.innerHTML='';return html}};tinyMCE.addPlugin("paste",TinyMCE_PastePlugin);
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/paste/editor_plugin_src.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,395 @@
+/**
+ * $Id: editor_plugin_src.js 201 2007-02-12 15:56:56Z spocke $
+ *
+ * @author Moxiecode
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+/* Import plugin specific language pack */ 
+tinyMCE.importPluginLanguagePack('paste');
+
+var TinyMCE_PastePlugin = {
+	getInfo : function() {
+		return {
+			longname : 'Paste text/word',
+			author : 'Moxiecode Systems AB',
+			authorurl : 'http://tinymce.moxiecode.com',
+			infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/paste',
+			version : tinyMCE.majorVersion + "." + tinyMCE.minorVersion
+		};
+	},
+
+	initInstance : function(inst) {
+		if (tinyMCE.isMSIE && tinyMCE.getParam("paste_auto_cleanup_on_paste", false))
+			tinyMCE.addEvent(inst.getBody(), "paste", TinyMCE_PastePlugin._handlePasteEvent);
+	},
+
+	handleEvent : function(e) {
+		// Force paste dialog if non IE browser
+		if (!tinyMCE.isRealIE && tinyMCE.getParam("paste_auto_cleanup_on_paste", false) && e.ctrlKey && e.keyCode == 86 && e.type == "keydown") {
+			window.setTimeout('tinyMCE.selectedInstance.execCommand("mcePasteText",true)', 1);
+			return tinyMCE.cancelEvent(e);
+		}
+
+		return true;
+	},
+
+	getControlHTML : function(cn) { 
+		switch (cn) { 
+			case "pastetext":
+				return tinyMCE.getButtonHTML(cn, 'lang_paste_text_desc', '{$pluginurl}/images/pastetext.gif', 'mcePasteText', true);
+
+			case "pasteword":
+				return tinyMCE.getButtonHTML(cn, 'lang_paste_word_desc', '{$pluginurl}/images/pasteword.gif', 'mcePasteWord', true);
+
+			case "selectall":
+				return tinyMCE.getButtonHTML(cn, 'lang_selectall_desc', '{$pluginurl}/images/selectall.gif', 'mceSelectAll', true);
+		} 
+
+		return ''; 
+	},
+
+	execCommand : function(editor_id, element, command, user_interface, value) { 
+		switch (command) { 
+			case "mcePasteText": 
+				if (user_interface) {
+					if ((tinyMCE.isMSIE && !tinyMCE.isOpera) && !tinyMCE.getParam('paste_use_dialog', false))
+						TinyMCE_PastePlugin._insertText(clipboardData.getData("Text"), true); 
+					else { 
+						var template = new Array(); 
+						template['file']	= '../../plugins/paste/pastetext.htm'; // Relative to theme 
+						template['width']  = 450; 
+						template['height'] = 400; 
+						var plain_text = ""; 
+						tinyMCE.openWindow(template, {editor_id : editor_id, plain_text: plain_text, resizable : "yes", scrollbars : "no", inline : "yes", mceDo : 'insert'}); 
+					}
+				} else
+					TinyMCE_PastePlugin._insertText(value['html'], value['linebreaks']);
+
+				return true;
+
+			case "mcePasteWord": 
+				if (user_interface) {
+					if ((tinyMCE.isMSIE && !tinyMCE.isOpera) && !tinyMCE.getParam('paste_use_dialog', false)) {
+						TinyMCE_PastePlugin._insertWordContent(TinyMCE_PastePlugin._clipboardHTML());
+					} else { 
+						var template = new Array(); 
+						template['file']	= '../../plugins/paste/pasteword.htm'; // Relative to theme 
+						template['width']  = 450; 
+						template['height'] = 400; 
+						var plain_text = ""; 
+						tinyMCE.openWindow(template, {editor_id : editor_id, plain_text: plain_text, resizable : "yes", scrollbars : "no", inline : "yes", mceDo : 'insert'});
+					}
+				} else
+					TinyMCE_PastePlugin._insertWordContent(value);
+
+				return true;
+
+			case "mceSelectAll":
+				tinyMCE.execInstanceCommand(editor_id, 'selectall'); 
+				return true; 
+
+		} 
+
+		// Pass to next handler in chain 
+		return false; 
+	},
+
+	// Private plugin internal methods
+
+	_handlePasteEvent : function(e) {
+		switch (e.type) {
+			case "paste":
+				var html = TinyMCE_PastePlugin._clipboardHTML();
+				var r, inst = tinyMCE.selectedInstance;
+
+				// Removes italic, strong etc, the if was needed due to bug #1437114
+				if (inst && (r = inst.getRng()) && r.text.length > 0)
+					tinyMCE.execCommand('delete');
+
+				if (html && html.length > 0)
+					tinyMCE.execCommand('mcePasteWord', false, html);
+
+				tinyMCE.cancelEvent(e);
+				return false;
+		}
+
+		return true;
+	},
+
+	_insertText : function(content, bLinebreaks) { 
+		if (content && content.length > 0) {
+			if (bLinebreaks) { 
+				// Special paragraph treatment 
+				if (tinyMCE.getParam("paste_create_paragraphs", true)) {
+					var rl = tinyMCE.getParam("paste_replace_list", '\u2122,<sup>TM</sup>,\u2026,...,\u201c|\u201d,",\u2019,\',\u2013|\u2014|\u2015|\u2212,-').split(',');
+					for (var i=0; i<rl.length; i+=2)
+						content = content.replace(new RegExp(rl[i], 'gi'), rl[i+1]);
+
+					content = tinyMCE.regexpReplace(content, "\r\n\r\n", "</p><p>", "gi"); 
+					content = tinyMCE.regexpReplace(content, "\r\r", "</p><p>", "gi"); 
+					content = tinyMCE.regexpReplace(content, "\n\n", "</p><p>", "gi"); 
+
+					// Has paragraphs 
+					if ((pos = content.indexOf('</p><p>')) != -1) { 
+						tinyMCE.execCommand("Delete"); 
+
+						var node = tinyMCE.selectedInstance.getFocusElement(); 
+
+						// Get list of elements to break 
+						var breakElms = new Array(); 
+
+						do { 
+							if (node.nodeType == 1) { 
+								// Don't break tables and break at body 
+								if (node.nodeName == "TD" || node.nodeName == "BODY") 
+									break; 
+		
+								breakElms[breakElms.length] = node; 
+							} 
+						} while(node = node.parentNode); 
+
+						var before = "", after = "</p>"; 
+						before += content.substring(0, pos); 
+
+						for (var i=0; i<breakElms.length; i++) { 
+							before += "</" + breakElms[i].nodeName + ">"; 
+							after += "<" + breakElms[(breakElms.length-1)-i].nodeName + ">"; 
+						} 
+
+						before += "<p>"; 
+						content = before + content.substring(pos+7) + after; 
+					} 
+				} 
+
+				if (tinyMCE.getParam("paste_create_linebreaks", true)) {
+					content = tinyMCE.regexpReplace(content, "\r\n", "<br />", "gi"); 
+					content = tinyMCE.regexpReplace(content, "\r", "<br />", "gi"); 
+					content = tinyMCE.regexpReplace(content, "\n", "<br />", "gi"); 
+				}
+			} 
+		
+			tinyMCE.execCommand("mceInsertRawHTML", false, content); 
+		}
+	},
+
+	_insertWordContent : function(content) { 
+		if (content && content.length > 0) {
+			// Cleanup Word content
+			var bull = String.fromCharCode(8226);
+			var middot = String.fromCharCode(183);
+			var cb;
+
+			if ((cb = tinyMCE.getParam("paste_insert_word_content_callback", "")) != "")
+				content = eval(cb + "('before', content)");
+
+			var rl = tinyMCE.getParam("paste_replace_list", '\u2122,<sup>TM</sup>,\u2026,...,\u201c|\u201d,",\u2019,\',\u2013|\u2014|\u2015|\u2212,-').split(',');
+			for (var i=0; i<rl.length; i+=2)
+				content = content.replace(new RegExp(rl[i], 'gi'), rl[i+1]);
+
+			if (tinyMCE.getParam("paste_convert_headers_to_strong", false)) {
+				content = content.replace(new RegExp('<p class=MsoHeading.*?>(.*?)<\/p>', 'gi'), '<p><b>$1</b></p>');
+			}
+
+			content = content.replace(new RegExp('tab-stops: list [0-9]+.0pt">', 'gi'), '">' + "--list--");
+			content = content.replace(new RegExp(bull + "(.*?)<BR>", "gi"), "<p>" + middot + "$1</p>");
+			content = content.replace(new RegExp('<SPAN style="mso-list: Ignore">', 'gi'), "<span>" + bull); // Covert to bull list
+			content = content.replace(/<o:p><\/o:p>/gi, "");
+			content = content.replace(new RegExp('<br style="page-break-before: always;.*>', 'gi'), '-- page break --'); // Replace pagebreaks
+			content = content.replace(new RegExp('<(!--)([^>]*)(--)>', 'g'), "");  // Word comments
+
+			if (tinyMCE.getParam("paste_remove_spans", true))
+				content = content.replace(/<\/?span[^>]*>/gi, "");
+
+			if (tinyMCE.getParam("paste_remove_styles", true))
+				content = content.replace(new RegExp('<(\\w[^>]*) style="([^"]*)"([^>]*)', 'gi'), "<$1$3");
+
+			content = content.replace(/<\/?font[^>]*>/gi, "");
+
+			// Strips class attributes.
+			switch (tinyMCE.getParam("paste_strip_class_attributes", "all")) {
+				case "all":
+					content = content.replace(/<(\w[^>]*) class=([^ |>]*)([^>]*)/gi, "<$1$3");
+					break;
+
+				case "mso":
+					content = content.replace(new RegExp('<(\\w[^>]*) class="?mso([^ |>]*)([^>]*)', 'gi'), "<$1$3");
+					break;
+			}
+
+			content = content.replace(new RegExp('href="?' + TinyMCE_PastePlugin._reEscape("" + document.location) + '', 'gi'), 'href="' + tinyMCE.settings['document_base_url']);
+			content = content.replace(/<(\w[^>]*) lang=([^ |>]*)([^>]*)/gi, "<$1$3");
+			content = content.replace(/<\\?\?xml[^>]*>/gi, "");
+			content = content.replace(/<\/?\w+:[^>]*>/gi, "");
+			content = content.replace(/-- page break --\s*<p>&nbsp;<\/p>/gi, ""); // Remove pagebreaks
+			content = content.replace(/-- page break --/gi, ""); // Remove pagebreaks
+
+	//		content = content.replace(/\/?&nbsp;*/gi, ""); &nbsp;
+	//		content = content.replace(/<p>&nbsp;<\/p>/gi, '');
+
+			if (!tinyMCE.settings['force_p_newlines']) {
+				content = content.replace('', '' ,'gi');
+				content = content.replace('</p>', '<br /><br />' ,'gi');
+			}
+
+			if (!tinyMCE.isMSIE && !tinyMCE.settings['force_p_newlines']) {
+				content = content.replace(/<\/?p[^>]*>/gi, "");
+			}
+
+			content = content.replace(/<\/?div[^>]*>/gi, "");
+
+			// Convert all middlot lists to UL lists
+			if (tinyMCE.getParam("paste_convert_middot_lists", true)) {
+				var div = document.createElement("div");
+				div.innerHTML = content;
+
+				// Convert all middot paragraphs to li elements
+				var className = tinyMCE.getParam("paste_unindented_list_class", "unIndentedList");
+
+				while (TinyMCE_PastePlugin._convertMiddots(div, "--list--")) ; // bull
+				while (TinyMCE_PastePlugin._convertMiddots(div, middot, className)) ; // Middot
+				while (TinyMCE_PastePlugin._convertMiddots(div, bull)) ; // bull
+
+				content = div.innerHTML;
+			}
+
+			// Replace all headers with strong and fix some other issues
+			if (tinyMCE.getParam("paste_convert_headers_to_strong", false)) {
+				content = content.replace(/<h[1-6]>&nbsp;<\/h[1-6]>/gi, '<p>&nbsp;&nbsp;</p>');
+				content = content.replace(/<h[1-6]>/gi, '<p><b>');
+				content = content.replace(/<\/h[1-6]>/gi, '</b></p>');
+				content = content.replace(/<b>&nbsp;<\/b>/gi, '<b>&nbsp;&nbsp;</b>');
+				content = content.replace(/^(&nbsp;)*/gi, '');
+			}
+
+			content = content.replace(/--list--/gi, ""); // Remove --list--
+
+			if ((cb = tinyMCE.getParam("paste_insert_word_content_callback", "")) != "")
+				content = eval(cb + "('after', content)");
+
+			// Insert cleaned content
+			tinyMCE.execCommand("mceInsertContent", false, content);
+
+			if (tinyMCE.getParam('paste_force_cleanup_wordpaste', true))
+				window.setTimeout('tinyMCE.execCommand("mceCleanup");', 1); // Do normal cleanup detached from this thread
+		}
+	},
+
+	_reEscape : function(s) {
+		var l = "?.\\*[](){}+^$:";
+		var o = "";
+
+		for (var i=0; i<s.length; i++) {
+			var c = s.charAt(i);
+
+			if (l.indexOf(c) != -1)
+				o += '\\' + c;
+			else
+				o += c;
+		}
+
+		return o;
+	},
+
+	_convertMiddots : function(div, search, class_name) {
+		var mdot = String.fromCharCode(183);
+		var bull = String.fromCharCode(8226);
+
+		var nodes = div.getElementsByTagName("p");
+		var prevul;
+		for (var i=0; i<nodes.length; i++) {
+			var p = nodes[i];
+
+			// Is middot
+			if (p.innerHTML.indexOf(search) == 0) {
+				var ul = document.createElement("ul");
+
+				if (class_name)
+					ul.className = class_name;
+
+				// Add the first one
+				var li = document.createElement("li");
+				li.innerHTML = p.innerHTML.replace(new RegExp('' + mdot + '|' + bull + '|--list--|&nbsp;', "gi"), '');
+				ul.appendChild(li);
+
+				// Add the rest
+				var np = p.nextSibling;
+				while (np) {
+			        // If the node is whitespace, then
+			        // ignore it and continue on.
+			        if (np.nodeType == 3 && new RegExp('^\\s$', 'm').test(np.nodeValue)) {
+			                np = np.nextSibling;
+			                continue;
+			        }
+
+					if (search == mdot) {
+					        if (np.nodeType == 1 && new RegExp('^o(\\s+|&nbsp;)').test(np.innerHTML)) {
+					                // Second level of nesting
+					                if (!prevul) {
+					                        prevul = ul;
+					                        ul = document.createElement("ul");
+					                        prevul.appendChild(ul);
+					                }
+					                np.innerHTML = np.innerHTML.replace(/^o/, '');
+					        } else {
+					                // Pop the stack if we're going back up to the first level
+					                if (prevul) {
+					                        ul = prevul;
+					                        prevul = null;
+					                }
+					                // Not element or middot paragraph
+					                if (np.nodeType != 1 || np.innerHTML.indexOf(search) != 0)
+					                        break;
+					        }
+					} else {
+					        // Not element or middot paragraph
+					        if (np.nodeType != 1 || np.innerHTML.indexOf(search) != 0)
+					                break;
+				        }
+
+					var cp = np.nextSibling;
+					var li = document.createElement("li");
+					li.innerHTML = np.innerHTML.replace(new RegExp('' + mdot + '|' + bull + '|--list--|&nbsp;', "gi"), '');
+					np.parentNode.removeChild(np);
+					ul.appendChild(li);
+					np = cp;
+				}
+
+				p.parentNode.replaceChild(ul, p);
+
+				return true;
+			}
+		}
+
+		return false;
+	},
+
+	_clipboardHTML : function() {
+		var div = document.getElementById('_TinyMCE_clipboardHTML');
+
+		if (!div) {
+			var div = document.createElement('DIV');
+			div.id = '_TinyMCE_clipboardHTML';
+
+			with (div.style) {
+				visibility = 'hidden';
+				overflow = 'hidden';
+				position = 'absolute';
+				width = 1;
+				height = 1;
+			}
+
+			document.body.appendChild(div);
+		}
+
+		div.innerHTML = '';
+		var rng = document.body.createTextRange();
+		rng.moveToElementText(div);
+		rng.execCommand('Paste');
+		var html = div.innerHTML;
+		div.innerHTML = '';
+		return html;
+	}
+};
+
+tinyMCE.addPlugin("paste", TinyMCE_PastePlugin);
Binary file includes/clientside/tinymce/plugins/paste/images/pastetext.gif has changed
Binary file includes/clientside/tinymce/plugins/paste/images/pasteword.gif has changed
Binary file includes/clientside/tinymce/plugins/paste/images/selectall.gif has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/paste/jscripts/pastetext.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,38 @@
+function saveContent() {
+	if (document.forms[0].htmlSource.value == '') {
+		tinyMCEPopup.close();
+		return false;
+	}
+
+	tinyMCEPopup.execCommand('mcePasteText', false, {
+		html : document.forms[0].htmlSource.value,
+		linebreaks : document.forms[0].linebreaks.checked
+	});
+
+	tinyMCEPopup.close();
+}
+
+function onLoadInit() {
+	tinyMCEPopup.resizeToInnerSize();
+
+	// Remove Gecko spellchecking
+	if (tinyMCE.isGecko)
+		document.body.spellcheck = tinyMCE.getParam("gecko_spellcheck");
+
+	resizeInputs();
+}
+
+var wHeight=0, wWidth=0, owHeight=0, owWidth=0;
+
+function resizeInputs() {
+	if (!tinyMCE.isMSIE) {
+		wHeight = self.innerHeight-80;
+		wWidth = self.innerWidth-17;
+	} else {
+		wHeight = document.body.clientHeight-80;
+		wWidth = document.body.clientWidth-17;
+	}
+
+	document.forms[0].htmlSource.style.height = Math.abs(wHeight) + 'px';
+	document.forms[0].htmlSource.style.width  = Math.abs(wWidth) + 'px';
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/paste/jscripts/pasteword.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,52 @@
+function saveContent() {
+	var html = document.getElementById("frmData").contentWindow.document.body.innerHTML;
+
+	if (html == ''){
+		tinyMCEPopup.close();
+		return false;
+	}
+
+	tinyMCEPopup.execCommand('mcePasteWord', false, html);
+	tinyMCEPopup.close();
+}
+
+function onLoadInit() {
+	tinyMCEPopup.resizeToInnerSize();
+
+	// Fix for endless reloading in FF
+	window.setTimeout('createIFrame();', 10);
+}
+
+function createIFrame() {
+	document.getElementById('iframecontainer').innerHTML = '<iframe id="frmData" name="frmData" class="sourceIframe" src="blank.htm" height="280" width="400" frameborder="0" style="background-color:#FFFFFF; width:100%;" dir="ltr" wrap="soft"></iframe>';
+}
+
+var wHeight=0, wWidth=0, owHeight=0, owWidth=0;
+
+function initIframe(doc) {
+	var dir = tinyMCE.selectedInstance.settings['directionality'];
+
+	doc.body.dir = dir;
+
+	// Remove Gecko spellchecking
+	if (tinyMCE.isGecko)
+		doc.body.spellcheck = tinyMCE.getParam("gecko_spellcheck");
+
+	resizeInputs();
+}
+
+function resizeInputs() {
+	if (!tinyMCE.isMSIE) {
+		wHeight = self.innerHeight - 80;
+		wWidth = self.innerWidth - 18;
+	} else {
+		wHeight = document.body.clientHeight - 80;
+		wWidth = document.body.clientWidth - 18;
+	}
+
+	var elm = document.getElementById('frmData');
+	if (elm) {
+		elm.style.height = Math.abs(wHeight) + 'px';
+		elm.style.width  = Math.abs(wWidth) + 'px';
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/paste/langs/en.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,10 @@
+// UK lang variables
+
+tinyMCE.addToLang('',{
+paste_text_desc : 'Paste as Plain Text',
+paste_text_title : 'Use CTRL+V on your keyboard to paste the text into the window.',
+paste_text_linebreaks : 'Keep linebreaks',
+paste_word_desc : 'Paste from Word',
+paste_word_title : 'Use CTRL+V on your keyboard to paste the text into the window.',
+selectall_desc : 'Select All'
+});
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/paste/pastetext.htm	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,34 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>{$lang_paste_text_desc}</title>
+	<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+	<script language="javascript" type="text/javascript" src="../../tiny_mce_popup.js"></script>
+	<script language="javascript" type="text/javascript" src="jscripts/pastetext.js"></script>
+	<base target="_self" />
+</head>
+<body onload="tinyMCEPopup.executeOnLoad('onLoadInit();');" onresize="resizeInputs();" style="display: none">
+<form name="source" onsubmit="saveContent();">
+	<div style="float: left" class="title">{$lang_paste_text_desc}</div>
+
+	<div style="float: right">
+		<input type="checkbox" name="linebreaks" id="linebreaks" class="wordWrapCode" checked="checked" /><label for="linebreaks">{$lang_paste_text_linebreaks}</label>
+	</div>
+
+	<br style="clear: both" />
+
+	<div>{$lang_paste_text_title}</div>
+
+	<textarea name="htmlSource" id="htmlSource" rows="15" cols="100" style="width: 100%; height: 100%; font-family: 'Courier New',Courier,mono; font-size: 12px;" dir="ltr" wrap="soft"></textarea>
+
+	<div class="mceActionPanel">
+		<div style="float: left">
+			<input type="button" name="insert" value="{$lang_insert}" onclick="saveContent();" id="insert" />
+		</div>
+
+		<div style="float: right">
+			<input type="button" name="cancel" value="{$lang_cancel}" onclick="tinyMCEPopup.close();" id="cancel" />
+		</div>
+	</div>
+</form>
+</body> 
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/paste/pasteword.htm	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,29 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+	<title>{$lang_paste_word_desc}</title>
+	<script language="javascript" type="text/javascript" src="../../tiny_mce_popup.js"></script>
+	<script language="javascript" type="text/javascript" src="jscripts/pasteword.js"></script>
+	<link href="css/pasteword.css" rel="stylesheet" type="text/css" />
+	<base target="_self" />
+</head>
+<body onload="tinyMCEPopup.executeOnLoad('onLoadInit();');" onresize="resizeInputs();" style="display: none">
+	<form name="source" onsubmit="saveContent();" action="#">
+		<div class="title">{$lang_paste_word_desc}</div>
+
+		<div>{$lang_paste_word_title}</div>
+
+		<div id="iframecontainer"></div>
+
+		<div class="mceActionPanel">
+			<div style="float: left">
+				<input type="button" id="insert" name="insert" value="{$lang_insert}" onclick="saveContent();" />
+			</div>
+
+			<div style="float: right">
+				<input type="button" id="cancel" name="cancel" value="{$lang_cancel}" onclick="tinyMCEPopup.close();" />
+			</div>
+		</div>
+	</form>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/paste/readme.txt	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+Check the TinyMCE documentation for details on this plugin.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/preview/editor_plugin.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+tinyMCE.importPluginLanguagePack('preview');var TinyMCE_PreviewPlugin={getInfo:function(){return{longname:'Preview',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/preview',version:tinyMCE.majorVersion+"."+tinyMCE.minorVersion}},getControlHTML:function(cn){switch(cn){case"preview":return tinyMCE.getButtonHTML(cn,'lang_preview_desc','{$pluginurl}/images/preview.gif','mcePreview')}return""},execCommand:function(editor_id,element,command,user_interface,value){switch(command){case"mcePreview":var previewPage=tinyMCE.getParam("plugin_preview_pageurl",null);var previewWidth=tinyMCE.getParam("plugin_preview_width","550");var previewHeight=tinyMCE.getParam("plugin_preview_height","600");if(previewPage){var template=new Array();template['file']=previewPage;template['width']=previewWidth;template['height']=previewHeight;tinyMCE.openWindow(template,{editor_id:editor_id,resizable:"yes",scrollbars:"yes",inline:"yes",content:tinyMCE.getContent(),content_css:tinyMCE.getParam("content_css")})}else{var win=window.open("","mcePreview","menubar=no,toolbar=no,scrollbars=yes,resizable=yes,left=20,top=20,width="+previewWidth+",height="+previewHeight);var html="",i;var c=tinyMCE.getContent();var pos=c.indexOf('<body'),pos2,css=tinyMCE.getParam("content_css").split(',');if(pos!=-1){pos=c.indexOf('>',pos);pos2=c.lastIndexOf('</body>');c=c.substring(pos+1,pos2)}html+=tinyMCE.getParam('doctype');html+='<html xmlns="http://www.w3.org/1999/xhtml">';html+='<head>';html+='<title>'+tinyMCE.getLang('lang_preview_desc')+'</title>';html+='<base href="'+tinyMCE.settings['base_href']+'" />';html+='<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />';for(i=0;i<css.length;i++)html+='<link href="'+css[i]+'" rel="stylesheet" type="text/css" />';html+='<script type="text/javascript">';html+='window.opener.TinyMCE_PreviewPlugin._setDoc(document);';html+='window.opener.TinyMCE_PreviewPlugin._setWin(window);';html+='writeFlash = window.opener.TinyMCE_PreviewPlugin._writeFlash;';html+='writeShockWave = window.opener.TinyMCE_PreviewPlugin._writeShockWave;';html+='writeQuickTime = window.opener.TinyMCE_PreviewPlugin._writeQuickTime;';html+='writeRealMedia = window.opener.TinyMCE_PreviewPlugin._writeRealMedia;';html+='writeWindowsMedia = window.opener.TinyMCE_PreviewPlugin._writeWindowsMedia;';html+='writeEmbed = window.opener.TinyMCE_PreviewPlugin._writeEmbed;';html+='</script>';html+='</head>';html+='<body dir="'+tinyMCE.getParam("directionality")+'" onload="window.opener.TinyMCE_PreviewPlugin._onLoad();">';html+=c;html+='</body>';html+='</html>';win.document.write(html);win.document.close()}return true}return false},_setDoc:function(d){TinyMCE_PreviewPlugin._doc=d;d._embeds=new Array()},_setWin:function(d){TinyMCE_PreviewPlugin._win=d},_onLoad:function(){var nl,i,el=new Array(),d=TinyMCE_PreviewPlugin._doc,sv,ne;nl=d.getElementsByTagName("script");for(i=0;i<nl.length;i++){sv=tinyMCE.isMSIE?nl[i].innerHTML:nl[i].firstChild.nodeValue;if(new RegExp('write(Flash|ShockWave|WindowsMedia|QuickTime|RealMedia)\\(.*','g').test(sv))el[el.length]=nl[i]}for(i=0;i<el.length;i++){ne=d.createElement("div");ne.innerHTML=d._embeds[i];el[i].parentNode.insertBefore(ne.firstChild,el[i])}},_writeFlash:function(p){p.src=tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'],p.src);TinyMCE_PreviewPlugin._writeEmbed('D27CDB6E-AE6D-11cf-96B8-444553540000','http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0','application/x-shockwave-flash',p)},_writeShockWave:function(p){p.src=tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'],p.src);TinyMCE_PreviewPlugin._writeEmbed('166B1BCA-3F9C-11CF-8075-444553540000','http://download.macromedia.com/pub/shockwave/cabs/director/sw.cab#version=8,5,1,0','application/x-director',p)},_writeQuickTime:function(p){p.src=tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'],p.src);TinyMCE_PreviewPlugin._writeEmbed('02BF25D5-8C17-4B23-BC80-D3488ABDDC6B','http://www.apple.com/qtactivex/qtplugin.cab#version=6,0,2,0','video/quicktime',p)},_writeRealMedia:function(p){p.src=tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'],p.src);TinyMCE_PreviewPlugin._writeEmbed('CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA','http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0','audio/x-pn-realaudio-plugin',p)},_writeWindowsMedia:function(p){p.src=tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'],p.src);p.url=p.src;TinyMCE_PreviewPlugin._writeEmbed('6BF52A52-394A-11D3-B153-00C04F79FAA6','http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=5,1,52,701','application/x-mplayer2',p)},_writeEmbed:function(cls,cb,mt,p){var h='',n,d=TinyMCE_PreviewPlugin._doc,ne,c;h+='<object classid="clsid:'+cls+'" codebase="'+cb+'"';h+=typeof(p.id)!="undefined"?'id="'+p.id+'"':'';h+=typeof(p.name)!="undefined"?'name="'+p.name+'"':'';h+=typeof(p.width)!="undefined"?'width="'+p.width+'"':'';h+=typeof(p.height)!="undefined"?'height="'+p.height+'"':'';h+=typeof(p.align)!="undefined"?'align="'+p.align+'"':'';h+='>';for(n in p)h+='<param name="'+n+'" value="'+p[n]+'">';h+='<embed type="'+mt+'"';for(n in p)h+=n+'="'+p[n]+'" ';h+='></embed></object>';d._embeds[d._embeds.length]=h}};tinyMCE.addPlugin("preview",TinyMCE_PreviewPlugin);
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/preview/editor_plugin_src.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,205 @@
+/**
+ * $Id: editor_plugin_src.js 201 2007-02-12 15:56:56Z spocke $
+ *
+ * @author Moxiecode
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+/* Import plugin specific language pack */
+tinyMCE.importPluginLanguagePack('preview');
+
+var TinyMCE_PreviewPlugin = {
+	getInfo : function() {
+		return {
+			longname : 'Preview',
+			author : 'Moxiecode Systems AB',
+			authorurl : 'http://tinymce.moxiecode.com',
+			infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/preview',
+			version : tinyMCE.majorVersion + "." + tinyMCE.minorVersion
+		};
+	},
+
+	/**
+	 * Returns the HTML contents of the preview control.
+	 */
+	getControlHTML : function(cn) {
+		switch (cn) {
+			case "preview":
+				return tinyMCE.getButtonHTML(cn, 'lang_preview_desc', '{$pluginurl}/images/preview.gif', 'mcePreview');
+		}
+
+		return "";
+	},
+
+	/**
+	 * Executes the mcePreview command.
+	 */
+	execCommand : function(editor_id, element, command, user_interface, value) {
+		// Handle commands
+		switch (command) {
+			case "mcePreview":
+				var previewPage = tinyMCE.getParam("plugin_preview_pageurl", null);
+				var previewWidth = tinyMCE.getParam("plugin_preview_width", "550");
+				var previewHeight = tinyMCE.getParam("plugin_preview_height", "600");
+
+				// Use a custom preview page
+				if (previewPage) {
+					var template = new Array();
+
+					template['file'] = previewPage;
+					template['width'] = previewWidth;
+					template['height'] = previewHeight;
+
+					tinyMCE.openWindow(template, {editor_id : editor_id, resizable : "yes", scrollbars : "yes", inline : "yes", content : tinyMCE.getContent(), content_css : tinyMCE.getParam("content_css")});
+				} else {
+					var win = window.open("", "mcePreview", "menubar=no,toolbar=no,scrollbars=yes,resizable=yes,left=20,top=20,width=" + previewWidth + ",height="  + previewHeight);
+					var html = "", i;
+					var c = tinyMCE.getContent();
+					var pos = c.indexOf('<body'), pos2, css = tinyMCE.getParam("content_css").split(',');
+
+					if (pos != -1) {
+						pos = c.indexOf('>', pos);
+						pos2 = c.lastIndexOf('</body>');
+						c = c.substring(pos + 1, pos2);
+					}
+
+					html += tinyMCE.getParam('doctype');
+					html += '<html xmlns="http://www.w3.org/1999/xhtml">';
+					html += '<head>';
+					html += '<title>' + tinyMCE.getLang('lang_preview_desc') + '</title>';
+					html += '<base href="' + tinyMCE.settings['base_href'] + '" />';
+					html += '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />';
+
+					for (i=0; i<css.length; i++)
+						html += '<link href="' + css[i] + '" rel="stylesheet" type="text/css" />';
+
+					html += '<script type="text/javascript">';
+					html += 'window.opener.TinyMCE_PreviewPlugin._setDoc(document);';
+					html += 'window.opener.TinyMCE_PreviewPlugin._setWin(window);';
+					html += 'writeFlash = window.opener.TinyMCE_PreviewPlugin._writeFlash;';
+					html += 'writeShockWave = window.opener.TinyMCE_PreviewPlugin._writeShockWave;';
+					html += 'writeQuickTime = window.opener.TinyMCE_PreviewPlugin._writeQuickTime;';
+					html += 'writeRealMedia = window.opener.TinyMCE_PreviewPlugin._writeRealMedia;';
+					html += 'writeWindowsMedia = window.opener.TinyMCE_PreviewPlugin._writeWindowsMedia;';
+					html += 'writeEmbed = window.opener.TinyMCE_PreviewPlugin._writeEmbed;';
+					html += '</script>';
+					html += '</head>';
+					html += '<body dir="' + tinyMCE.getParam("directionality") + '" onload="window.opener.TinyMCE_PreviewPlugin._onLoad();">';
+					html += c;
+					html += '</body>';
+					html += '</html>';
+
+					win.document.write(html);
+					win.document.close();
+				}
+
+				return true;
+		}
+
+		return false;
+	},
+
+	_setDoc : function(d) {
+		TinyMCE_PreviewPlugin._doc = d;
+		d._embeds = new Array();
+	},
+
+	_setWin : function(d) {
+		TinyMCE_PreviewPlugin._win = d;
+	},
+
+	_onLoad : function() {
+		var nl, i, el = new Array(), d = TinyMCE_PreviewPlugin._doc, sv, ne;
+
+		nl = d.getElementsByTagName("script");
+		for (i=0; i<nl.length; i++) {
+			sv = tinyMCE.isMSIE ? nl[i].innerHTML : nl[i].firstChild.nodeValue;
+
+			if (new RegExp('write(Flash|ShockWave|WindowsMedia|QuickTime|RealMedia)\\(.*', 'g').test(sv))
+				el[el.length] = nl[i];
+		}
+
+		for (i=0; i<el.length; i++) {
+			ne = d.createElement("div");
+			ne.innerHTML = d._embeds[i];
+			el[i].parentNode.insertBefore(ne.firstChild, el[i]);
+		}
+	},
+
+	_writeFlash : function(p) {
+		p.src = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], p.src);
+		TinyMCE_PreviewPlugin._writeEmbed(
+			'D27CDB6E-AE6D-11cf-96B8-444553540000',
+			'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0',
+			'application/x-shockwave-flash',
+			p
+		);
+	},
+
+	_writeShockWave : function(p) {
+		p.src = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], p.src);
+		TinyMCE_PreviewPlugin._writeEmbed(
+			'166B1BCA-3F9C-11CF-8075-444553540000',
+			'http://download.macromedia.com/pub/shockwave/cabs/director/sw.cab#version=8,5,1,0',
+			'application/x-director',
+			p
+		);
+	},
+
+	_writeQuickTime : function(p) {
+		p.src = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], p.src);
+		TinyMCE_PreviewPlugin._writeEmbed(
+			'02BF25D5-8C17-4B23-BC80-D3488ABDDC6B',
+			'http://www.apple.com/qtactivex/qtplugin.cab#version=6,0,2,0',
+			'video/quicktime',
+			p
+		);
+	},
+
+	_writeRealMedia : function(p) {
+		p.src = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], p.src);
+		TinyMCE_PreviewPlugin._writeEmbed(
+			'CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA',
+			'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0',
+			'audio/x-pn-realaudio-plugin',
+			p
+		);
+	},
+
+	_writeWindowsMedia : function(p) {
+		p.src = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], p.src);
+		p.url = p.src;
+		TinyMCE_PreviewPlugin._writeEmbed(
+			'6BF52A52-394A-11D3-B153-00C04F79FAA6',
+			'http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=5,1,52,701',
+			'application/x-mplayer2',
+			p
+		);
+	},
+
+	_writeEmbed : function(cls, cb, mt, p) {
+		var h = '', n, d = TinyMCE_PreviewPlugin._doc, ne, c;
+
+		h += '<object classid="clsid:' + cls + '" codebase="' + cb + '"';
+		h += typeof(p.id) != "undefined" ? 'id="' + p.id + '"' : '';
+		h += typeof(p.name) != "undefined" ? 'name="' + p.name + '"' : '';
+		h += typeof(p.width) != "undefined" ? 'width="' + p.width + '"' : '';
+		h += typeof(p.height) != "undefined" ? 'height="' + p.height + '"' : '';
+		h += typeof(p.align) != "undefined" ? 'align="' + p.align + '"' : '';
+		h += '>';
+
+		for (n in p)
+			h += '<param name="' + n + '" value="' + p[n] + '">';
+
+		h += '<embed type="' + mt + '"';
+
+		for (n in p)
+			h += n + '="' + p[n] + '" ';
+
+		h += '></embed></object>';
+
+		d._embeds[d._embeds.length] = h;
+	}
+};
+
+tinyMCE.addPlugin("preview", TinyMCE_PreviewPlugin);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/preview/example.html	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,14 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<script language="javascript" src="../../tiny_mce_popup.js"></script>
+<script type="text/javascript" src="jscripts/embed.js"></script>
+<title>Example of a custom preview page</title>
+<link href="{$content_css}" rel="stylesheet" type="text/css" />
+</head>
+<body>
+
+Editor contents: <br />
+{$content}
+
+</body>
+</html>
Binary file includes/clientside/tinymce/plugins/preview/images/preview.gif has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/preview/jscripts/embed.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,73 @@
+/**
+ * This script contains embed functions for common plugins. This scripts are complety free to use for any purpose.
+ */
+
+function writeFlash(p) {
+	writeEmbed(
+		'D27CDB6E-AE6D-11cf-96B8-444553540000',
+		'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0',
+		'application/x-shockwave-flash',
+		p
+	);
+}
+
+function writeShockWave(p) {
+	writeEmbed(
+	'166B1BCA-3F9C-11CF-8075-444553540000',
+	'http://download.macromedia.com/pub/shockwave/cabs/director/sw.cab#version=8,5,1,0',
+	'application/x-director',
+		p
+	);
+}
+
+function writeQuickTime(p) {
+	writeEmbed(
+		'02BF25D5-8C17-4B23-BC80-D3488ABDDC6B',
+		'http://www.apple.com/qtactivex/qtplugin.cab#version=6,0,2,0',
+		'video/quicktime',
+		p
+	);
+}
+
+function writeRealMedia(p) {
+	writeEmbed(
+		'CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA',
+		'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0',
+		'audio/x-pn-realaudio-plugin',
+		p
+	);
+}
+
+function writeWindowsMedia(p) {
+	p.url = p.src;
+	writeEmbed(
+		'6BF52A52-394A-11D3-B153-00C04F79FAA6',
+		'http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=5,1,52,701',
+		'application/x-mplayer2',
+		p
+	);
+}
+
+function writeEmbed(cls, cb, mt, p) {
+	var h = '', n;
+
+	h += '<object classid="clsid:' + cls + '" codebase="' + cb + '"';
+	h += typeof(p.id) != "undefined" ? 'id="' + p.id + '"' : '';
+	h += typeof(p.name) != "undefined" ? 'name="' + p.name + '"' : '';
+	h += typeof(p.width) != "undefined" ? 'width="' + p.width + '"' : '';
+	h += typeof(p.height) != "undefined" ? 'height="' + p.height + '"' : '';
+	h += typeof(p.align) != "undefined" ? 'align="' + p.align + '"' : '';
+	h += '>';
+
+	for (n in p)
+		h += '<param name="' + n + '" value="' + p[n] + '">';
+
+	h += '<embed type="' + mt + '"';
+
+	for (n in p)
+		h += n + '="' + p[n] + '" ';
+
+	h += '></embed></object>';
+
+	document.write(h);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/preview/langs/en.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,5 @@
+// UK lang variables
+
+tinyMCE.addToLang('',{
+preview_desc : 'Preview'
+});
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/preview/readme.txt	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+Check the TinyMCE documentation for details on this plugin.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/print/editor_plugin.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+tinyMCE.importPluginLanguagePack('print');var TinyMCE_PrintPlugin={getInfo:function(){return{longname:'Print',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/print',version:tinyMCE.majorVersion+"."+tinyMCE.minorVersion}},getControlHTML:function(cn){switch(cn){case"print":return tinyMCE.getButtonHTML(cn,'lang_print_desc','{$pluginurl}/images/print.gif','mcePrint')}return""},execCommand:function(editor_id,element,command,user_interface,value){switch(command){case"mcePrint":tinyMCE.getInstanceById(editor_id).contentWindow.print();return true}return false}};tinyMCE.addPlugin("print",TinyMCE_PrintPlugin);
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/print/editor_plugin_src.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,47 @@
+/**
+ * $Id: editor_plugin_src.js 201 2007-02-12 15:56:56Z spocke $
+ *
+ * @author Moxiecode
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+/* Import theme	specific language pack */
+tinyMCE.importPluginLanguagePack('print');
+
+var TinyMCE_PrintPlugin = {
+	getInfo : function() {
+		return {
+			longname : 'Print',
+			author : 'Moxiecode Systems AB',
+			authorurl : 'http://tinymce.moxiecode.com',
+			infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/print',
+			version : tinyMCE.majorVersion + "." + tinyMCE.minorVersion
+		};
+	},
+
+	getControlHTML : function(cn)	{
+		switch (cn) {
+			case "print":
+				return tinyMCE.getButtonHTML(cn, 'lang_print_desc', '{$pluginurl}/images/print.gif', 'mcePrint');
+		}
+
+		return "";
+	},
+
+	/**
+	 * Executes	the	search/replace commands.
+	 */
+	execCommand : function(editor_id, element, command,	user_interface,	value) {
+		// Handle commands
+		switch (command) {
+			case "mcePrint":
+				tinyMCE.getInstanceById(editor_id).contentWindow.print();
+				return true;
+		}
+
+		// Pass to next handler in chain
+		return false;
+	}
+};
+
+tinyMCE.addPlugin("print", TinyMCE_PrintPlugin);
Binary file includes/clientside/tinymce/plugins/print/images/print.gif has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/print/langs/en.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,5 @@
+// UK lang variables
+
+tinyMCE.addToLang('',{
+print_desc : 'Print'
+});
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/print/readme.txt	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+Check the TinyMCE documentation for details on this plugin.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/readme.txt	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+This is the location you place TinyMCE plugins.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/save/editor_plugin.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+tinyMCE.importPluginLanguagePack('save');var TinyMCE_SavePlugin={getInfo:function(){return{longname:'Save',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/save',version:tinyMCE.majorVersion+"."+tinyMCE.minorVersion}},initInstance:function(inst){inst.addShortcut('ctrl','s','lang_save_desc','mceSave')},getControlHTML:function(cn){switch(cn){case"save":return tinyMCE.getButtonHTML(cn,'lang_save_desc','{$pluginurl}/images/save.gif','mceSave')}return""},execCommand:function(editor_id,element,command,user_interface,value){switch(command){case"mceSave":if(tinyMCE.getParam("fullscreen_is_enabled"))return true;var inst=tinyMCE.selectedInstance;var formObj=inst.formElement.form;if(tinyMCE.getParam("save_enablewhendirty")&&!inst.isDirty())return true;if(formObj){tinyMCE.triggerSave();var os;if((os=tinyMCE.getParam("save_onsavecallback"))){if(eval(os+'(inst);')){inst.startContent=tinyMCE.trim(inst.getBody().innerHTML);tinyMCE.triggerNodeChange(false,true)}return true}for(var i=0;i<formObj.elements.length;i++){var elementId=formObj.elements[i].name?formObj.elements[i].name:formObj.elements[i].id;if(elementId.indexOf('mce_editor_')==0)formObj.elements[i].disabled=true}tinyMCE.isNotDirty=true;if(formObj.onsubmit==null||formObj.onsubmit()!=false)inst.formElement.form.submit()}else alert("Error: No form element found.");return true}return false},handleNodeChange:function(editor_id,node,undo_index,undo_levels,visual_aid,any_selection){if(tinyMCE.getParam("fullscreen_is_enabled")){tinyMCE.switchClass(editor_id+'_save','mceButtonDisabled');return true}if(tinyMCE.getParam("save_enablewhendirty")){var inst=tinyMCE.getInstanceById(editor_id);if(inst.isDirty()){tinyMCE.switchClass(editor_id+'_save','mceButtonNormal');return true}tinyMCE.switchClass(editor_id+'_save','mceButtonDisabled')}return true}};tinyMCE.addPlugin("save",TinyMCE_SavePlugin);
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/save/editor_plugin_src.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,115 @@
+/**
+ * $Id: editor_plugin_src.js 201 2007-02-12 15:56:56Z spocke $
+ *
+ * @author Moxiecode
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+/* Import plugin specific language pack */
+tinyMCE.importPluginLanguagePack('save');
+
+var TinyMCE_SavePlugin = {
+	getInfo : function() {
+		return {
+			longname : 'Save',
+			author : 'Moxiecode Systems AB',
+			authorurl : 'http://tinymce.moxiecode.com',
+			infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/save',
+			version : tinyMCE.majorVersion + "." + tinyMCE.minorVersion
+		};
+	},
+
+	initInstance : function(inst) {
+		inst.addShortcut('ctrl', 's', 'lang_save_desc', 'mceSave');
+	},
+
+	/**
+	 * Returns the HTML contents of the save control.
+	 */
+	getControlHTML : function(cn) {
+		switch (cn) {
+			case "save":
+				return tinyMCE.getButtonHTML(cn, 'lang_save_desc', '{$pluginurl}/images/save.gif', 'mceSave');
+		}
+
+		return "";
+	},
+
+	/**
+	 * Executes the save command.
+	 */
+	execCommand : function(editor_id, element, command, user_interface, value) {
+		// Handle commands
+		switch (command) {
+			case "mceSave":
+				if (tinyMCE.getParam("fullscreen_is_enabled"))
+					return true;
+
+				var inst = tinyMCE.selectedInstance;
+				var formObj = inst.formElement.form;
+
+				if (tinyMCE.getParam("save_enablewhendirty") && !inst.isDirty())
+					return true;
+
+				if (formObj) {
+					tinyMCE.triggerSave();
+
+					// Use callback instead
+					var os;
+					if ((os = tinyMCE.getParam("save_onsavecallback"))) {
+						if (eval(os + '(inst);')) {
+							inst.startContent = tinyMCE.trim(inst.getBody().innerHTML);
+							/*inst.undoLevels = new Array();
+							inst.undoIndex = 0;
+							inst.typingUndoIndex = -1;
+							inst.undoRedo = true;
+							inst.undoLevels[inst.undoLevels.length] = inst.startContent;*/
+							tinyMCE.triggerNodeChange(false, true);
+						}
+
+						return true;
+					}
+
+					// Disable all UI form elements that TinyMCE created
+					for (var i=0; i<formObj.elements.length; i++) {
+						var elementId = formObj.elements[i].name ? formObj.elements[i].name : formObj.elements[i].id;
+
+						if (elementId.indexOf('mce_editor_') == 0)
+							formObj.elements[i].disabled = true;
+					}
+
+					tinyMCE.isNotDirty = true;
+
+					if (formObj.onsubmit == null || formObj.onsubmit() != false)
+						inst.formElement.form.submit();
+				} else
+					alert("Error: No form element found.");
+
+				return true;
+		}
+		// Pass to next handler in chain
+		return false;
+	},
+
+	handleNodeChange : function(editor_id, node, undo_index, undo_levels, visual_aid, any_selection) {
+		if (tinyMCE.getParam("fullscreen_is_enabled")) {
+			tinyMCE.switchClass(editor_id + '_save', 'mceButtonDisabled');
+			return true;
+		}
+
+		if (tinyMCE.getParam("save_enablewhendirty")) {
+			var inst = tinyMCE.getInstanceById(editor_id);
+
+			if (inst.isDirty()) {
+				tinyMCE.switchClass(editor_id + '_save', 'mceButtonNormal');
+				return true;
+			}
+
+			tinyMCE.switchClass(editor_id + '_save', 'mceButtonDisabled');
+		}
+
+		return true;
+	}
+};
+
+tinyMCE.addPlugin("save", TinyMCE_SavePlugin);
Binary file includes/clientside/tinymce/plugins/save/images/save.gif has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/save/langs/en.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,5 @@
+// UK lang variables
+
+tinyMCE.addToLang('',{
+save_desc : 'Save'
+});
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/save/readme.txt	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+Check the TinyMCE documentation for details on this plugin.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/searchreplace/css/searchreplace.css	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,20 @@
+/* stylesheet for advsearchreplace plugin*/
+
+.panel_wrapper { height: 85px; }
+.panel_wrapper div.current { height: 85px; }
+
+/* MS IE only styles */
+* html .panel_wrapper { height: 100px; }
+* html .panel_wrapper div.current { height: 100px; }
+
+#replaceBtn, #replaceAllBtn {
+	padding-bottom: 2px;
+	font-weight: bold;
+	width: 90px;
+	height: 21px;
+	border: 0;
+	cursor: pointer;
+}
+
+#replaceBtn { background: url(../images/replace_button_bg.gif); }
+#replaceAllBtn { background: url(../images/replace_all_button_bg.gif); }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/searchreplace/editor_plugin.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+tinyMCE.importPluginLanguagePack('searchreplace');var TinyMCE_SearchReplacePlugin={getInfo:function(){return{longname:'Search/Replace',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/searchreplace',version:tinyMCE.majorVersion+"."+tinyMCE.minorVersion}},initInstance:function(inst){inst.addShortcut('ctrl','f','lang_searchreplace_search_desc','mceSearch',true);},getControlHTML:function(cn){switch(cn){case"search":return tinyMCE.getButtonHTML(cn,'lang_searchreplace_search_desc','{$pluginurl}/images/search.gif','mceSearch',true);case"replace":return tinyMCE.getButtonHTML(cn,'lang_searchreplace_replace_desc','{$pluginurl}/images/replace.gif','mceSearchReplace',true)}return""},execCommand:function(editor_id,element,command,user_interface,value){var inst=tinyMCE.getInstanceById(editor_id),selectedText=inst.selection.getSelectedText(),rng;function defValue(key,default_value){value[key]=typeof(value[key])=="undefined"?default_value:value[key]}function replaceSel(search_str,str,back){if(!inst.selection.isCollapsed()){if(tinyMCE.isRealIE)inst.selection.getRng().duplicate().pasteHTML(str);else inst.execCommand('mceInsertContent',false,str)}}if(!value)value=[];defValue("editor_id",editor_id);defValue("searchstring",selectedText);defValue("replacestring",null);defValue("replacemode","none");defValue("casesensitive",false);defValue("backwards",false);defValue("wrap",false);defValue("wholeword",false);defValue("inline","yes");defValue("resizable","no");switch(command){case"mceSearch":if(user_interface){var template=new Array();template['file']='../../plugins/searchreplace/searchreplace.htm';template['width']=380;template['height']=155+(tinyMCE.isNS7?20:0)+(tinyMCE.isMSIE?15:0);template['width']+=tinyMCE.getLang('lang_searchreplace_delta_width',0);template['height']+=tinyMCE.getLang('lang_searchreplace_delta_height',0);inst.selection.collapse(true);tinyMCE.openWindow(template,value)}else{var win=tinyMCE.getInstanceById(editor_id).contentWindow;var doc=tinyMCE.getInstanceById(editor_id).contentWindow.document;var body=tinyMCE.getInstanceById(editor_id).contentWindow.document.body;var awin=value.win,found;if(body.innerHTML==""){awin.alert(tinyMCE.getLang('lang_searchreplace_notfound'));return true}if(value['replacemode']=="current"){replaceSel(value['string'],value['replacestring'],value['backwards']);value['replacemode']="none";}inst.selection.collapse(value['backwards']);if(tinyMCE.isMSIE){var rng=inst.selection.getRng();var flags=0;if(value['wholeword'])flags=flags|2;if(value['casesensitive'])flags=flags|4;if(!rng.findText){awin.alert('This operation is currently not supported by this browser.');return true}if(value['replacemode']=="all"){found=false;while(rng.findText(value['string'],value['backwards']?-1:1,flags)){found=true;rng.scrollIntoView();rng.select();replaceSel(value['string'],value['replacestring'],value['backwards'])}if(found)awin.alert(tinyMCE.getLang('lang_searchreplace_allreplaced'));else awin.alert(tinyMCE.getLang('lang_searchreplace_notfound'));return true}if(rng.findText(value['string'],value['backwards']?-1:1,flags)){rng.scrollIntoView();rng.select()}else awin.alert(tinyMCE.getLang('lang_searchreplace_notfound'))}else{if(value['replacemode']=="all"){found=false;while(win.find(value['string'],value['casesensitive'],value['backwards'],value['wrap'],value['wholeword'],false,false)){found=true;replaceSel(value['string'],value['replacestring'],value['backwards'])}if(found)awin.alert(tinyMCE.getLang('lang_searchreplace_allreplaced'));else awin.alert(tinyMCE.getLang('lang_searchreplace_notfound'));return true}if(!win.find(value['string'],value['casesensitive'],value['backwards'],value['wrap'],value['wholeword'],false,false))awin.alert(tinyMCE.getLang('lang_searchreplace_notfound'))}}return true;case"mceSearchReplace":value['replacestring']="";tinyMCE.execInstanceCommand(editor_id,'mceSearch',user_interface,value,false);return true}return false}};tinyMCE.addPlugin("searchreplace",TinyMCE_SearchReplacePlugin);
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/searchreplace/editor_plugin_src.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,173 @@
+/**
+ * $Id: editor_plugin_src.js 201 2007-02-12 15:56:56Z spocke $
+ *
+ * @author Moxiecode
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+tinyMCE.importPluginLanguagePack('searchreplace');
+
+var TinyMCE_SearchReplacePlugin = {
+	getInfo : function() {
+		return {
+			longname : 'Search/Replace',
+			author : 'Moxiecode Systems AB',
+			authorurl : 'http://tinymce.moxiecode.com',
+			infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/searchreplace',
+			version : tinyMCE.majorVersion + "." + tinyMCE.minorVersion
+		};
+	},
+
+	initInstance : function (inst) {
+		inst.addShortcut('ctrl', 'f', 'lang_searchreplace_search_desc', 'mceSearch', true);
+		// No CTRL+R for "replace" because browsers will reload page instead of executing plugin
+	},
+
+	getControlHTML : function (cn) {
+		switch (cn) {
+			case "search" :
+				return tinyMCE.getButtonHTML(cn, 'lang_searchreplace_search_desc', '{$pluginurl}/images/search.gif','mceSearch', true);
+
+			case "replace" :
+				return tinyMCE.getButtonHTML(cn, 'lang_searchreplace_replace_desc', '{$pluginurl}/images/replace.gif', 'mceSearchReplace', true);
+		}
+
+		return "";
+	},
+
+	execCommand : function (editor_id, element, command, user_interface, value) {
+		var inst = tinyMCE.getInstanceById(editor_id), selectedText = inst.selection.getSelectedText(), rng;
+
+		function defValue(key, default_value) {
+			value[key] = typeof(value[key]) == "undefined" ? default_value : value[key];
+		}
+
+		function replaceSel(search_str, str, back) {
+			if (!inst.selection.isCollapsed()) {
+				if (tinyMCE.isRealIE)
+					inst.selection.getRng().duplicate().pasteHTML(str); // Needs to be duplicated due to selection bug in IE
+				else
+					inst.execCommand('mceInsertContent', false, str);
+			}
+		}
+
+		if (!value)
+			value = [];
+
+		defValue("editor_id", editor_id);
+		defValue("searchstring", selectedText);
+		defValue("replacestring", null);
+		defValue("replacemode", "none");
+		defValue("casesensitive", false);
+		defValue("backwards", false);
+		defValue("wrap", false);
+		defValue("wholeword", false);
+		defValue("inline", "yes");
+		defValue("resizable", "no");
+
+		switch (command) {
+			case "mceSearch" :
+				if (user_interface) {
+					var template = new Array();
+
+					template['file'] = '../../plugins/searchreplace/searchreplace.htm';
+					template['width'] = 380;
+					template['height'] = 155 + (tinyMCE.isNS7 ? 20 : 0) + (tinyMCE.isMSIE ? 15 : 0);
+					template['width'] += tinyMCE.getLang('lang_searchreplace_delta_width', 0);
+					template['height'] += tinyMCE.getLang('lang_searchreplace_delta_height', 0);
+
+					inst.selection.collapse(true);
+
+					tinyMCE.openWindow(template, value);
+				} else {
+					var win = tinyMCE.getInstanceById(editor_id).contentWindow;
+					var doc = tinyMCE.getInstanceById(editor_id).contentWindow.document;
+					var body = tinyMCE.getInstanceById(editor_id).contentWindow.document.body;
+					var awin = value.win, found;
+
+					if (body.innerHTML == "") {
+						awin.alert(tinyMCE.getLang('lang_searchreplace_notfound'));
+						return true;
+					}
+
+					if (value['replacemode'] == "current") {
+						replaceSel(value['string'], value['replacestring'], value['backwards']);
+						value['replacemode'] = "none";
+						//tinyMCE.execInstanceCommand(editor_id, 'mceSearch', user_interface, value);
+						//return true;
+					}
+
+					inst.selection.collapse(value['backwards']);
+
+					if (tinyMCE.isMSIE) {
+						var rng = inst.selection.getRng();
+						var flags = 0;
+						if (value['wholeword'])
+							flags = flags | 2;
+
+						if (value['casesensitive'])
+							flags = flags | 4;
+
+						if (!rng.findText) {
+							awin.alert('This operation is currently not supported by this browser.');
+							return true;
+						}
+
+						if (value['replacemode'] == "all") {
+							found = false;
+
+							while (rng.findText(value['string'], value['backwards'] ? -1 : 1, flags)) {
+								found = true;
+								rng.scrollIntoView();
+								rng.select();
+								replaceSel(value['string'], value['replacestring'], value['backwards']);
+							}
+
+							if (found)
+								awin.alert(tinyMCE.getLang('lang_searchreplace_allreplaced'));
+							else
+								awin.alert(tinyMCE.getLang('lang_searchreplace_notfound'));
+
+							return true;
+						}
+
+						if (rng.findText(value['string'], value['backwards'] ? -1 : 1, flags)) {
+							rng.scrollIntoView();
+							rng.select();
+						} else
+							awin.alert(tinyMCE.getLang('lang_searchreplace_notfound'));
+					} else {
+						if (value['replacemode'] == "all") {
+							found = false;
+
+							while (win.find(value['string'], value['casesensitive'], value['backwards'], value['wrap'], value['wholeword'], false, false)) {
+								found = true;
+								replaceSel(value['string'], value['replacestring'], value['backwards']);
+							}
+
+							if (found)
+								awin.alert(tinyMCE.getLang('lang_searchreplace_allreplaced'));
+							else
+								awin.alert(tinyMCE.getLang('lang_searchreplace_notfound'));
+
+							return true;
+						}
+
+						if (!win.find(value['string'], value['casesensitive'], value['backwards'], value['wrap'], value['wholeword'], false, false))
+							awin.alert(tinyMCE.getLang('lang_searchreplace_notfound'));
+					}
+				}
+
+				return true;
+
+			case "mceSearchReplace" :
+				value['replacestring'] = "";
+				tinyMCE.execInstanceCommand(editor_id, 'mceSearch', user_interface, value, false);
+				return true;
+		}
+
+		return false;
+	}
+};
+
+tinyMCE.addPlugin("searchreplace", TinyMCE_SearchReplacePlugin);
\ No newline at end of file
Binary file includes/clientside/tinymce/plugins/searchreplace/images/replace.gif has changed
Binary file includes/clientside/tinymce/plugins/searchreplace/images/replace_all_button_bg.gif has changed
Binary file includes/clientside/tinymce/plugins/searchreplace/images/replace_button_bg.gif has changed
Binary file includes/clientside/tinymce/plugins/searchreplace/images/search.gif has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/searchreplace/jscripts/searchreplace.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,86 @@
+function init() {
+	tinyMCEPopup.resizeToInnerSize();
+
+	// start with appropiate tab
+	var task = (tinyMCE.getWindowArg("replacestring") != null) ? "replace" : "search";
+	mcTabs.displayTab(task + '_tab', task +'_panel');
+	manageReplaceButtons();
+	
+	var formObj = document.forms[0];
+
+	formObj[task + "_panel_searchstring"].value = tinyMCE.getWindowArg("searchstring");
+	formObj["replace_panel_replacestring"].value = (tinyMCE.getWindowArg("replacestring") != null) ? tinyMCE.getWindowArg("replacestring") : "";
+	formObj[task + "_panel_casesensitivebox"].checked = tinyMCE.getWindowArg("casesensitive");
+	formObj[task + "_panel_backwardsu"].checked = tinyMCE.getWindowArg("backwards");
+	formObj[task + "_panel_backwardsd"].checked = !tinyMCE.getWindowArg("backwards");
+}
+
+function searchNext(replacemode) {
+	// "search" or "replace" mode of operation?
+	var task = (document.getElementById("search_tab").className == "current") ? "search" : "replace";
+
+	var formObj = document.forms[0];
+
+	if (task == "replace") {
+		// Whats the point?
+		if (formObj[task + "_panel_searchstring"].value == "" || formObj[task + "_panel_searchstring"].value == formObj[task + "_panel_replacestring"].value)
+			return false;
+	}
+
+	// Do search
+	tinyMCEPopup.execCommand('mceSearch', false, { 
+		string : formObj[task + "_panel_searchstring"].value,
+		replacestring : formObj["replace_panel_replacestring"].value,
+		replacemode : replacemode,
+		casesensitive : formObj[task + "_panel_casesensitivebox"].checked,
+		backwards : formObj[task + "_panel_backwardsu"].checked,
+		win : window
+		}, false);
+
+	window.focus();
+
+	return false;
+}
+
+function cancelAction() {
+	tinyMCEPopup.close();
+}
+
+function manageReplaceButtons() {
+	// "search" or "replace" mode of operation?
+	var task = (document.getElementById("search_tab").className == "current") ? "search" : "replace";
+	document.getElementById("replace_buttons").style.visibility = (task == "replace") ? "visible" : "hidden";
+}
+
+function copyValues(link) {
+	// check if tab is already active
+	var tab = link;
+	while (tab.tagName && tab.tagName.toLowerCase() != "li") tab = tab.parentNode;
+	if (tab.className) return false; // tab is already active -> no need to copy any values!
+
+	// copy values from one panel to the other (if they exist there)
+	var from_panel_name = tab.id.match(/^search/i) ? "replace_panel" : "search_panel";
+	var to_panel_name = (from_panel_name == "search_panel") ? "replace_panel" : "search_panel";
+
+	// find all elements with IDs to copy their values
+	var elms = document.getElementById(from_panel_name).getElementsByTagName("*");
+	for (var i = 0; i < elms.length; i++) {
+		if (elms[i].id && elms[i].id != "") {
+			var checked = "undefined";
+			if (elms[i].type.toLowerCase() == "checkbox" || elms[i].type.toLowerCase() == "radio")
+				checked = elms[i].checked;
+
+			// copy values if element exists in other panel
+			var to_elm_name = to_panel_name + elms[i].id.substring(from_panel_name.length, elms[i].id.length);
+			var to_elm = document.getElementById(to_elm_name);
+			if (to_elm) {
+				if (checked != "undefined")
+					to_elm.checked = checked;
+				else
+					to_elm.value = elms[i].value;
+			}
+		}
+	}
+
+	return false;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/searchreplace/langs/en.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,21 @@
+// UK lang variables
+
+tinyMCE.addToLang('',{
+searchreplace_search_desc : 'Find',
+searchreplace_searchnext_desc : 'Find again',
+searchreplace_replace_desc : 'Find/Replace',
+searchreplace_notfound : 'The search has been completed. The search string could not be found.',
+searchreplace_search_title : 'Find',
+searchreplace_replace_title : 'Find/Replace',
+searchreplace_allreplaced : 'All occurrences of the search string were replaced.',
+searchreplace_findwhat : 'Find what',
+searchreplace_replacewith : 'Replace with',
+searchreplace_direction : 'Direction',
+searchreplace_up : 'Up',
+searchreplace_down : 'Down',
+searchreplace_case : 'Match case',
+searchreplace_findnext : 'Find&nbsp;next',
+searchreplace_replace : 'Replace',
+searchreplace_replaceall : 'Replace&nbsp;all',
+searchreplace_cancel : 'Cancel'
+});
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/searchreplace/readme.txt	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+Check the TinyMCE documentation for details on this plugin.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/searchreplace/searchreplace.htm	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,107 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>{$lang_searchreplace_replace_title}</title>
+	<script language="javascript" type="text/javascript" src="../../tiny_mce_popup.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/mctabs.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/form_utils.js"></script>
+	<script language="javascript" type="text/javascript" src="jscripts/searchreplace.js"></script>
+	<link rel="stylesheet" type="text/css" href="css/searchreplace.css" />
+	<base target="_self" />
+</head>
+<body onload="tinyMCEPopup.executeOnLoad('init();');" style="display: none; margin: 4px;">
+<form onsubmit="return false;" action="#">
+	<div class="tabs">
+		<ul>
+			<li id="search_tab"><span><a href="javascript:mcTabs.displayTab('search_tab','search_panel');manageReplaceButtons();" onmousedown="return copyValues(this);">{$lang_searchreplace_search_desc}</a></span></li>
+			<li id="replace_tab"><span><a href="javascript:mcTabs.displayTab('replace_tab','replace_panel');manageReplaceButtons();" onmousedown="return copyValues(this);">{$lang_searchreplace_replace}</a></span></li>
+		</ul>
+	</div>
+
+	<div class="panel_wrapper">
+
+		<div id="search_panel" class="panel">
+			<table border="0" cellspacing="0" cellpadding="2">
+				<tr>
+					<td><label for="search_panel_searchstring">{$lang_searchreplace_findwhat}</label></td>
+					<td><input type="text" id="search_panel_searchstring" name="search_panel_searchstring" style="width: 200px" /></td>
+				</tr>
+				<tr>
+					<td colspan="2">
+						<table border="0" cellspacing="0" cellpadding="0" class="direction">
+							<tr>
+								<td><label>{$lang_searchreplace_direction}</label></td>
+								<td><input id="search_panel_backwardsu" name="search_panel_backwards" class="radio" type="radio" /></td>
+								<td><label for="search_panel_backwardsu">{$lang_searchreplace_up}</label></td>
+								<td><input id="search_panel_backwardsd" name="search_panel_backwards" class="radio" type="radio" /></td>
+								<td><label for="search_panel_backwardsd">{$lang_searchreplace_down}</label></td>
+							</tr>
+						</table>
+					</td>
+				</tr>
+				<tr>
+					<td colspan="2">
+						<table border="0" cellspacing="0" cellpadding="0">
+							<tr>
+								<td><input id="search_panel_casesensitivebox" name="search_panel_casesensitivebox" class="checkbox" type="checkbox" /></td>
+								<td><label for="search_panel_casesensitivebox">{$lang_searchreplace_case}</label></td>
+							</tr>
+						</table>
+					</td>
+				</tr>
+			</table>
+		</div>
+
+		<div id="replace_panel" class="panel">
+			<table border="0" cellspacing="0" cellpadding="2">
+				<tr>
+					<td><label for="replace_panel_searchstring">{$lang_searchreplace_findwhat}</label></td>
+					<td><input type="text" id="replace_panel_searchstring" name="replace_panel_searchstring" style="width: 200px" /></td>
+				</tr>
+				<tr>
+					<td><label for="replace_panel_replacestring">{$lang_searchreplace_replacewith}</label></td>
+					<td><input type="text" id="replace_panel_replacestring" name="replace_panel_replacestring" style="width: 200px" /></td>
+				</tr>
+				<tr>
+					<td colspan="2">
+						<table border="0" cellspacing="0" cellpadding="0" class="direction">
+							<tr>
+								<td><label>{$lang_searchreplace_direction}</label></td>
+								<td><input id="replace_panel_backwardsu" name="replace_panel_backwards" class="radio" type="radio" /></td>
+								<td><label for="replace_panel_backwardsu">{$lang_searchreplace_up}</label></td>
+								<td><input id="replace_panel_backwardsd" name="replace_panel_backwards" class="radio" type="radio" /></td>
+								<td><label for="replace_panel_backwardsd">{$lang_searchreplace_down}</label></td>
+							</tr>
+						</table>
+					</td>
+				</tr>
+				<tr>
+					<td colspan="2">
+						<table border="0" cellspacing="0" cellpadding="0">
+							<tr>
+								<td><input id="replace_panel_casesensitivebox" name="replace_panel_casesensitivebox" class="checkbox" type="checkbox" /></td>
+								<td><label for="replace_panel_casesensitivebox">{$lang_searchreplace_case}</label></td>
+							</tr>
+						</table>
+					</td>
+				</tr>
+			</table>
+		</div>
+
+	</div>
+
+	<div class="mceActionPanel">
+		<div style="float: left">
+			<input type="button" id="insert" name="insert" value="{$lang_searchreplace_findnext}" onclick="searchNext('none');" />
+			<span id="replace_buttons">
+				<input type="button" id="replaceBtn" name="replaceBtn" value="{$lang_searchreplace_replace}" onclick="searchNext('current');" />
+				<input type="button" id="replaceAllBtn" name="replaceAllBtn" value="{$lang_searchreplace_replaceall}" onclick="searchNext('all');;" />
+			</span>
+		</div>
+
+		<div style="float: right">	
+			<input type="button" id="cancel" name="cancel" value="{$lang_searchreplace_cancel}" onclick="tinyMCEPopup.close();" />
+		</div>
+	</div>
+</form>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/style/css/props.css	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,62 @@
+#text_font {
+	width: 250px;
+}
+
+#text_size {
+	width: 70px;
+}
+
+.mceAddSelectValue {
+	background-color: #DDDDDD;
+}
+
+select, #block_text_indent, #box_width, #box_height, #box_padding_top, #box_padding_right, #box_padding_bottom, #box_padding_left {
+	width: 70px;
+}
+
+#box_margin_top, #box_margin_right, #box_margin_bottom, #box_margin_left, #positioning_width, #positioning_height, #positioning_zindex {
+	width: 70px;
+}
+
+#positioning_placement_top, #positioning_placement_right, #positioning_placement_bottom, #positioning_placement_left {
+	width: 70px;
+}
+
+#positioning_clip_top, #positioning_clip_right, #positioning_clip_bottom, #positioning_clip_left {
+	width: 70px;
+}
+
+.panel_wrapper div.current {
+	padding-top: 10px;
+	height: 230px;
+}
+
+.delim {
+	border-left: 1px solid gray;
+}
+
+.tdelim {
+	border-bottom: 1px solid gray;	
+}
+
+#block_display {
+	width: 145px;
+}
+
+#list_type {
+	width: 115px;
+}
+
+.disabled {
+	background-color: #EEEEEE;
+}
+
+#apply {
+	font-weight: bold;
+	width: 78px;
+	height: 21px;
+	border: 0;
+	background-image: url('../images/apply_button_bg.gif');
+	cursor: pointer;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/style/editor_plugin.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+tinyMCE.importPluginLanguagePack('style');var TinyMCE_StylePlugin={getInfo:function(){return{longname:'Style',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/style',version:tinyMCE.majorVersion+"."+tinyMCE.minorVersion}},getControlHTML:function(cn){switch(cn){case"styleprops":return tinyMCE.getButtonHTML(cn,'lang_style_styleinfo_desc','{$pluginurl}/images/styleprops.gif','mceStyleProps',true)}return""},execCommand:function(editor_id,element,command,user_interface,value){var e,inst;switch(command){case"mceStyleProps":TinyMCE_StylePlugin._styleProps();return true;case"mceSetElementStyle":inst=tinyMCE.getInstanceById(editor_id);e=inst.selection.getFocusElement();if(e){e.style.cssText=value;inst.repaint()}return true}return false},handleNodeChange:function(editor_id,node,undo_index,undo_levels,visual_aid,any_selection){if(node.nodeName=='BODY')tinyMCE.switchClass(editor_id+'_styleprops','mceButtonDisabled');else tinyMCE.switchClass(editor_id+'_styleprops','mceButtonNormal')},_styleProps:function(){var e=tinyMCE.selectedInstance.selection.getFocusElement();if(!e||e.nodeName=='BODY')return;tinyMCE.openWindow({file:'../../plugins/style/props.htm',width:480+tinyMCE.getLang('lang_style_props_delta_width',0),height:320+tinyMCE.getLang('lang_style_props_delta_height',0)},{editor_id:tinyMCE.selectedInstance.editorId,inline:"yes",style_text:e.style.cssText})}};tinyMCE.addPlugin("style",TinyMCE_StylePlugin);
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/style/editor_plugin_src.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,83 @@
+/**
+ * $Id: editor_plugin_src.js 201 2007-02-12 15:56:56Z spocke $
+ *
+ * @author Moxiecode
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+/* Import plugin specific language pack */
+tinyMCE.importPluginLanguagePack('style');
+
+var TinyMCE_StylePlugin = {
+	getInfo : function() {
+		return {
+			longname : 'Style',
+			author : 'Moxiecode Systems AB',
+			authorurl : 'http://tinymce.moxiecode.com',
+			infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/style',
+			version : tinyMCE.majorVersion + "." + tinyMCE.minorVersion
+		};
+	},
+
+	getControlHTML : function(cn) {
+		switch (cn) {
+			case "styleprops":
+				return tinyMCE.getButtonHTML(cn, 'lang_style_styleinfo_desc', '{$pluginurl}/images/styleprops.gif', 'mceStyleProps', true);
+		}
+
+		return "";
+	},
+
+	execCommand : function(editor_id, element, command, user_interface, value) {
+		var e, inst;
+
+		// Handle commands
+		switch (command) {
+			case "mceStyleProps":
+				TinyMCE_StylePlugin._styleProps();
+				return true;
+
+			case "mceSetElementStyle":
+				inst = tinyMCE.getInstanceById(editor_id);
+				e = inst.selection.getFocusElement();
+
+				if (e) {
+					e.style.cssText = value;
+					inst.repaint();
+				}
+
+				return true;
+		}
+
+		// Pass to next handler in chain
+		return false;
+	},
+
+	handleNodeChange : function(editor_id, node, undo_index, undo_levels, visual_aid, any_selection) {
+		if (node.nodeName == 'BODY')
+			tinyMCE.switchClass(editor_id + '_styleprops', 'mceButtonDisabled');
+		else
+			tinyMCE.switchClass(editor_id + '_styleprops', 'mceButtonNormal');
+	},
+
+	// Private plugin specific methods
+
+	_styleProps : function() {
+		var e = tinyMCE.selectedInstance.selection.getFocusElement();
+
+		if (!e || e.nodeName == 'BODY')
+			return;
+
+		tinyMCE.openWindow({
+			file : '../../plugins/style/props.htm',
+			width : 480 + tinyMCE.getLang('lang_style_props_delta_width', 0),
+			height : 320 + tinyMCE.getLang('lang_style_props_delta_height', 0)
+		}, {
+			editor_id : tinyMCE.selectedInstance.editorId,
+			inline : "yes",
+			style_text : e.style.cssText
+		});
+	}
+};
+
+tinyMCE.addPlugin("style", TinyMCE_StylePlugin);
Binary file includes/clientside/tinymce/plugins/style/images/apply_button_bg.gif has changed
Binary file includes/clientside/tinymce/plugins/style/images/style_info.gif has changed
Binary file includes/clientside/tinymce/plugins/style/images/styleprops.gif has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/style/jscripts/props.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,633 @@
+var defaultFonts = "" + 
+	"Arial, Helvetica, sans-serif=Arial, Helvetica, sans-serif;" + 
+	"Times New Roman, Times, serif=Times New Roman, Times, serif;" + 
+	"Courier New, Courier, mono=Courier New, Courier, mono;" + 
+	"Times New Roman, Times, serif=Times New Roman, Times, serif;" + 
+	"Georgia, Times New Roman, Times, serif=Georgia, Times New Roman, Times, serif;" + 
+	"Verdana, Arial, Helvetica, sans-serif=Verdana, Arial, Helvetica, sans-serif;" + 
+	"Geneva, Arial, Helvetica, sans-serif=Geneva, Arial, Helvetica, sans-serif";
+
+var defaultSizes = "9;10;12;14;16;18;24;xx-small;x-small;small;medium;large;x-large;xx-large;smaller;larger";
+var defaultMeasurement = "+pixels=px;points=pt;in;cm;mm;picas;ems;exs;%";
+var defaultSpacingMeasurement = "pixels=px;points=pt;in;cm;mm;picas;+ems;exs;%";
+var defaultIndentMeasurement = "pixels=px;+points=pt;in;cm;mm;picas;ems;exs;%";
+var defaultWeight = "normal;bold;bolder;lighter;100;200;300;400;500;600;700;800;900";
+var defaultTextStyle = "normal;italic;oblique";
+var defaultVariant = "normal;small-caps";
+var defaultLineHeight = "normal";
+var defaultAttachment = "fixed;scroll";
+var defaultRepeat = "no-repeat;repeat;repeat-x;repeat-y";
+var defaultPosH = "left;center;right";
+var defaultPosV = "top;center;bottom";
+var defaultVAlign = "baseline;sub;super;top;text-top;middle;bottom;text-bottom";
+var defaultDisplay = "inline;block;list-item;run-in;compact;marker;table;inline-table;table-row-group;table-header-group;table-footer-group;table-row;table-column-group;table-column;table-cell;table-caption;none";
+var defaultBorderStyle = "none;solid;dashed;dotted;double;groove;ridge;inset;outset";
+var defaultBorderWidth = "thin;medium;thick";
+var defaultListType = "disc;circle;square;decimal;lower-roman;upper-roman;lower-alpha;upper-alpha;none";
+
+function init() {
+	var ce = document.getElementById('container'), h;
+
+	ce.style.cssText = tinyMCEPopup.getWindowArg('style_text');
+
+	h = getBrowserHTML('background_image_browser','background_image','image','advimage');
+	document.getElementById("background_image_browser").innerHTML = h;
+
+	tinyMCEPopup.resizeToInnerSize();
+
+	document.getElementById('text_color_pickcontainer').innerHTML = getColorPickerHTML('text_color_pick','text_color');
+	document.getElementById('background_color_pickcontainer').innerHTML = getColorPickerHTML('background_color_pick','background_color');
+	document.getElementById('border_color_top_pickcontainer').innerHTML = getColorPickerHTML('border_color_top_pick','border_color_top');
+	document.getElementById('border_color_right_pickcontainer').innerHTML = getColorPickerHTML('border_color_right_pick','border_color_right');
+	document.getElementById('border_color_bottom_pickcontainer').innerHTML = getColorPickerHTML('border_color_bottom_pick','border_color_bottom');
+	document.getElementById('border_color_left_pickcontainer').innerHTML = getColorPickerHTML('border_color_left_pick','border_color_left');
+
+	fillSelect(0, 'text_font', 'style_font', defaultFonts, ';', true);
+	fillSelect(0, 'text_size', 'style_font_size', defaultSizes, ';', true);
+	fillSelect(0, 'text_size_measurement', 'style_font_size_measurement', defaultMeasurement, ';', true);
+	fillSelect(0, 'text_case', 'style_text_case', "capitalize;uppercase;lowercase", ';', true);
+	fillSelect(0, 'text_weight', 'style_font_weight', defaultWeight, ';', true);
+	fillSelect(0, 'text_style', 'style_font_style', defaultTextStyle, ';', true);
+	fillSelect(0, 'text_variant', 'style_font_variant', defaultVariant, ';', true);
+	fillSelect(0, 'text_lineheight', 'style_font_line_height', defaultLineHeight, ';', true);
+	fillSelect(0, 'text_lineheight_measurement', 'style_font_line_height_measurement', defaultMeasurement, ';', true);
+
+	fillSelect(0, 'background_attachment', 'style_background_attachment', defaultAttachment, ';', true);
+	fillSelect(0, 'background_repeat', 'style_background_repeat', defaultRepeat, ';', true);
+
+	fillSelect(0, 'background_hpos_measurement', 'style_background_hpos_measurement', defaultMeasurement, ';', true);
+	fillSelect(0, 'background_vpos_measurement', 'style_background_vpos_measurement', defaultMeasurement, ';', true);
+
+	fillSelect(0, 'background_hpos', 'style_background_hpos', defaultPosH, ';', true);
+	fillSelect(0, 'background_vpos', 'style_background_vpos', defaultPosV, ';', true);
+
+	fillSelect(0, 'block_wordspacing', 'style_wordspacing', 'normal', ';', true);
+	fillSelect(0, 'block_wordspacing_measurement', 'style_wordspacing_measurement', defaultSpacingMeasurement, ';', true);
+	fillSelect(0, 'block_letterspacing', 'style_letterspacing', 'normal', ';', true);
+	fillSelect(0, 'block_letterspacing_measurement', 'style_letterspacing_measurement', defaultSpacingMeasurement, ';', true);
+	fillSelect(0, 'block_vertical_alignment', 'style_vertical_alignment', defaultVAlign, ';', true);
+	fillSelect(0, 'block_text_align', 'style_text_align', "left;right;center;justify", ';', true);
+	fillSelect(0, 'block_whitespace', 'style_whitespace', "normal;pre;nowrap", ';', true);
+	fillSelect(0, 'block_display', 'style_display', defaultDisplay, ';', true);
+	fillSelect(0, 'block_text_indent_measurement', 'style_text_indent_measurement', defaultIndentMeasurement, ';', true);
+
+	fillSelect(0, 'box_width_measurement', 'style_box_width_measurement', defaultMeasurement, ';', true);
+	fillSelect(0, 'box_height_measurement', 'style_box_height_measurement', defaultMeasurement, ';', true);
+	fillSelect(0, 'box_float', 'style_float', 'left;right;none', ';', true);
+	fillSelect(0, 'box_clear', 'style_clear', 'left;right;both;none', ';', true);
+	fillSelect(0, 'box_padding_left_measurement', 'style_padding_left_measurement', defaultMeasurement, ';', true);
+	fillSelect(0, 'box_padding_top_measurement', 'style_padding_top_measurement', defaultMeasurement, ';', true);
+	fillSelect(0, 'box_padding_bottom_measurement', 'style_padding_bottom_measurement', defaultMeasurement, ';', true);
+	fillSelect(0, 'box_padding_right_measurement', 'style_padding_right_measurement', defaultMeasurement, ';', true);
+	fillSelect(0, 'box_margin_left_measurement', 'style_margin_left_measurement', defaultMeasurement, ';', true);
+	fillSelect(0, 'box_margin_top_measurement', 'style_margin_top_measurement', defaultMeasurement, ';', true);
+	fillSelect(0, 'box_margin_bottom_measurement', 'style_margin_bottom_measurement', defaultMeasurement, ';', true);
+	fillSelect(0, 'box_margin_right_measurement', 'style_margin_right_measurement', defaultMeasurement, ';', true);
+
+	fillSelect(0, 'border_style_top', 'style_border_style_top', defaultBorderStyle, ';', true);
+	fillSelect(0, 'border_style_right', 'style_border_style_right', defaultBorderStyle, ';', true);
+	fillSelect(0, 'border_style_bottom', 'style_border_style_bottom', defaultBorderStyle, ';', true);
+	fillSelect(0, 'border_style_left', 'style_border_style_left', defaultBorderStyle, ';', true);
+
+	fillSelect(0, 'border_width_top', 'style_border_width_top', defaultBorderWidth, ';', true);
+	fillSelect(0, 'border_width_right', 'style_border_width_right', defaultBorderWidth, ';', true);
+	fillSelect(0, 'border_width_bottom', 'style_border_width_bottom', defaultBorderWidth, ';', true);
+	fillSelect(0, 'border_width_left', 'style_border_width_left', defaultBorderWidth, ';', true);
+
+	fillSelect(0, 'border_width_top_measurement', 'style_border_width_top_measurement', defaultMeasurement, ';', true);
+	fillSelect(0, 'border_width_right_measurement', 'style_border_width_right_measurement', defaultMeasurement, ';', true);
+	fillSelect(0, 'border_width_bottom_measurement', 'style_border_width_bottom_measurement', defaultMeasurement, ';', true);
+	fillSelect(0, 'border_width_left_measurement', 'style_border_width_left_measurement', defaultMeasurement, ';', true);
+
+	fillSelect(0, 'list_type', 'style_list_type', defaultListType, ';', true);
+	fillSelect(0, 'list_position', 'style_list_position', "inside;outside", ';', true);
+
+	fillSelect(0, 'positioning_type', 'style_positioning_type', "absolute;relative;static", ';', true);
+	fillSelect(0, 'positioning_visibility', 'style_positioning_visibility', "inherit;visible;hidden", ';', true);
+
+	fillSelect(0, 'positioning_width_measurement', 'style_positioning_width_measurement', defaultMeasurement, ';', true);
+	fillSelect(0, 'positioning_height_measurement', 'style_positioning_height_measurement', defaultMeasurement, ';', true);
+	fillSelect(0, 'positioning_overflow', 'style_positioning_overflow', "visible;hidden;scroll;auto", ';', true);
+
+	fillSelect(0, 'positioning_placement_top_measurement', 'style_positioning_placement_top_measurement', defaultMeasurement, ';', true);
+	fillSelect(0, 'positioning_placement_right_measurement', 'style_positioning_placement_right_measurement', defaultMeasurement, ';', true);
+	fillSelect(0, 'positioning_placement_bottom_measurement', 'style_positioning_placement_bottom_measurement', defaultMeasurement, ';', true);
+	fillSelect(0, 'positioning_placement_left_measurement', 'style_positioning_placement_left_measurement', defaultMeasurement, ';', true);
+
+	fillSelect(0, 'positioning_clip_top_measurement', 'style_positioning_clip_top_measurement', defaultMeasurement, ';', true);
+	fillSelect(0, 'positioning_clip_right_measurement', 'style_positioning_clip_right_measurement', defaultMeasurement, ';', true);
+	fillSelect(0, 'positioning_clip_bottom_measurement', 'style_positioning_clip_bottom_measurement', defaultMeasurement, ';', true);
+	fillSelect(0, 'positioning_clip_left_measurement', 'style_positioning_clip_left_measurement', defaultMeasurement, ';', true);
+
+	TinyMCE_EditableSelects.init();
+	setupFormData();
+	showDisabledControls();
+}
+
+function setupFormData() {
+	var ce = document.getElementById('container'), f = document.forms[0], s, b, i;
+
+	// Setup text fields
+
+	selectByValue(f, 'text_font', ce.style.fontFamily, true, true);
+	selectByValue(f, 'text_size', getNum(ce.style.fontSize), true, true);
+	selectByValue(f, 'text_size_measurement', getMeasurement(ce.style.fontSize));
+	selectByValue(f, 'text_weight', ce.style.fontWeight, true, true);
+	selectByValue(f, 'text_style', ce.style.fontStyle, true, true);
+	selectByValue(f, 'text_lineheight', getNum(ce.style.lineHeight), true, true);
+	selectByValue(f, 'text_lineheight_measurement', getMeasurement(ce.style.lineHeight));
+	selectByValue(f, 'text_case', ce.style.textTransform, true, true);
+	selectByValue(f, 'text_variant', ce.style.fontVariant, true, true);
+	f.text_color.value = ce.style.color;
+	updateColor('text_color_pick', 'text_color');
+	f.text_underline.checked = inStr(ce.style.textDecoration, 'underline');
+	f.text_overline.checked = inStr(ce.style.textDecoration, 'overline');
+	f.text_linethrough.checked = inStr(ce.style.textDecoration, 'line-through');
+	f.text_blink.checked = inStr(ce.style.textDecoration, 'blink');
+
+	// Setup background fields
+
+	f.background_color.value = ce.style.backgroundColor;
+	updateColor('background_color_pick', 'background_color');
+	f.background_image.value = ce.style.backgroundImage.replace(new RegExp("url\\('?([^']*)'?\\)", 'gi'), "$1");
+	selectByValue(f, 'background_repeat', ce.style.backgroundRepeat, true, true);
+	selectByValue(f, 'background_attachment', ce.style.backgroundAttachment, true, true);
+	selectByValue(f, 'background_hpos', getNum(getVal(ce.style.backgroundPosition, 0)), true, true);
+	selectByValue(f, 'background_hpos_measurement', getMeasurement(getVal(ce.style.backgroundPosition, 0)));
+	selectByValue(f, 'background_vpos', getNum(getVal(ce.style.backgroundPosition, 1)), true, true);
+	selectByValue(f, 'background_vpos_measurement', getMeasurement(getVal(ce.style.backgroundPosition, 1)));
+
+	// Setup block fields
+
+	selectByValue(f, 'block_wordspacing', getNum(ce.style.wordSpacing), true, true);
+	selectByValue(f, 'block_wordspacing_measurement', getMeasurement(ce.style.wordSpacing));
+	selectByValue(f, 'block_letterspacing', getNum(ce.style.letterSpacing), true, true);
+	selectByValue(f, 'block_letterspacing_measurement', getMeasurement(ce.style.letterSpacing));
+	selectByValue(f, 'block_vertical_alignment', ce.style.verticalAlign, true, true);
+	selectByValue(f, 'block_text_align', ce.style.textAlign, true, true);
+	f.block_text_indent.value = getNum(ce.style.textIndent);
+	selectByValue(f, 'block_text_indent_measurement', getMeasurement(ce.style.textIndent));
+	selectByValue(f, 'block_whitespace', ce.style.whiteSpace, true, true);
+	selectByValue(f, 'block_display', ce.style.display, true, true);
+
+	// Setup box fields
+
+	f.box_width.value = getNum(ce.style.width);
+	selectByValue(f, 'box_width_measurement', getMeasurement(ce.style.width));
+
+	f.box_height.value = getNum(ce.style.height);
+	selectByValue(f, 'box_height_measurement', getMeasurement(ce.style.height));
+
+	if (tinyMCE.isGecko)
+		selectByValue(f, 'box_float', ce.style.cssFloat, true, true);
+	else
+		selectByValue(f, 'box_float', ce.style.styleFloat, true, true);
+
+	selectByValue(f, 'box_clear', ce.style.clear, true, true);
+
+	setupBox(f, ce, 'box_padding', 'padding', '');
+	setupBox(f, ce, 'box_margin', 'margin', '');
+
+	// Setup border fields
+
+	setupBox(f, ce, 'border_style', 'border', 'Style');
+	setupBox(f, ce, 'border_width', 'border', 'Width');
+	setupBox(f, ce, 'border_color', 'border', 'Color');
+
+	updateColor('border_color_top_pick', 'border_color_top');
+	updateColor('border_color_right_pick', 'border_color_right');
+	updateColor('border_color_bottom_pick', 'border_color_bottom');
+	updateColor('border_color_left_pick', 'border_color_left');
+
+	// Setup list fields
+
+	selectByValue(f, 'list_type', ce.style.listStyleType, true, true);
+	selectByValue(f, 'list_position', ce.style.listStylePosition, true, true);
+	f.list_bullet_image.value = ce.style.listStyleImage.replace(new RegExp("url\\('?([^']*)'?\\)", 'gi'), "$1");
+
+	// Setup box fields
+
+	selectByValue(f, 'positioning_type', ce.style.position, true, true);
+	selectByValue(f, 'positioning_visibility', ce.style.visibility, true, true);
+	selectByValue(f, 'positioning_overflow', ce.style.overflow, true, true);
+	f.positioning_zindex.value = ce.style.zIndex ? ce.style.zIndex : "";
+
+	f.positioning_width.value = getNum(ce.style.width);
+	selectByValue(f, 'positioning_width_measurement', getMeasurement(ce.style.width));
+
+	f.positioning_height.value = getNum(ce.style.height);
+	selectByValue(f, 'positioning_height_measurement', getMeasurement(ce.style.height));
+
+	setupBox(f, ce, 'positioning_placement', '', '', new Array('top', 'right', 'bottom', 'left'));
+
+	s = ce.style.clip.replace(new RegExp("rect\\('?([^']*)'?\\)", 'gi'), "$1");
+	s = s.replace(/,/g, ' ');
+
+	if (!hasEqualValues(new Array(getVal(s, 0), getVal(s, 1), getVal(s, 2), getVal(s, 3)))) {
+		f.positioning_clip_top.value = getNum(getVal(s, 0));
+		selectByValue(f, 'positioning_clip_top_measurement', getMeasurement(getVal(s, 0)));
+		f.positioning_clip_right.value = getNum(getVal(s, 1));
+		selectByValue(f, 'positioning_clip_right_measurement', getMeasurement(getVal(s, 1)));
+		f.positioning_clip_bottom.value = getNum(getVal(s, 2));
+		selectByValue(f, 'positioning_clip_bottom_measurement', getMeasurement(getVal(s, 2)));
+		f.positioning_clip_left.value = getNum(getVal(s, 3));
+		selectByValue(f, 'positioning_clip_left_measurement', getMeasurement(getVal(s, 3)));
+	} else {
+		f.positioning_clip_top.value = getNum(getVal(s, 0));
+		selectByValue(f, 'positioning_clip_top_measurement', getMeasurement(getVal(s, 0)));
+		f.positioning_clip_right.value = f.positioning_clip_bottom.value = f.positioning_clip_left.value;
+	}
+
+//	setupBox(f, ce, '', 'border', 'Color');
+}
+
+function getMeasurement(s) {
+	return s.replace(/^([0-9]+)(.*)$/, "$2");
+}
+
+function getNum(s) {
+	if (new RegExp('^[0-9]+[a-z%]+$', 'gi').test(s))
+		return s.replace(/[^0-9]/g, '');
+
+	return s;
+}
+
+function inStr(s, n) {
+	return new RegExp(n, 'gi').test(s);
+}
+
+function getVal(s, i) {
+	var a = tinyMCE.explode(' ', s);
+
+	if (a.length > 1)
+		return a[i];
+
+	return "";
+}
+
+function setValue(f, n, v) {
+	if (f.elements[n].type == "text")
+		f.elements[n].value = v;
+	else
+		selectByValue(f, n, v, true, true);
+}
+
+function setupBox(f, ce, fp, pr, sf, b) {
+	if (typeof(b) == "undefined")
+		b = new Array('Top', 'Right', 'Bottom', 'Left');
+
+	if (isSame(ce, pr, sf, b)) {
+		f.elements[fp + "_same"].checked = true;
+
+		setValue(f, fp + "_top", getNum(ce.style[pr + b[0] + sf]));
+		f.elements[fp + "_top"].disabled = false;
+
+		f.elements[fp + "_right"].value = "";
+		f.elements[fp + "_right"].disabled = true;
+		f.elements[fp + "_bottom"].value = "";
+		f.elements[fp + "_bottom"].disabled = true;
+		f.elements[fp + "_left"].value = "";
+		f.elements[fp + "_left"].disabled = true;
+
+		if (f.elements[fp + "_top_measurement"]) {
+			selectByValue(f, fp + '_top_measurement', getMeasurement(ce.style[pr + b[0] + sf]));
+			f.elements[fp + "_left_measurement"].disabled = true;
+			f.elements[fp + "_bottom_measurement"].disabled = true;
+			f.elements[fp + "_right_measurement"].disabled = true;
+		}
+	} else {
+		f.elements[fp + "_same"].checked = false;
+
+		setValue(f, fp + "_top", getNum(ce.style[pr + b[0] + sf]));
+		f.elements[fp + "_top"].disabled = false;
+
+		setValue(f, fp + "_right", getNum(ce.style[pr + b[1] + sf]));
+		f.elements[fp + "_right"].disabled = false;
+
+		setValue(f, fp + "_bottom", getNum(ce.style[pr + b[2] + sf]));
+		f.elements[fp + "_bottom"].disabled = false;
+
+		setValue(f, fp + "_left", getNum(ce.style[pr + b[3] + sf]));
+		f.elements[fp + "_left"].disabled = false;
+
+		if (f.elements[fp + "_top_measurement"]) {
+			selectByValue(f, fp + '_top_measurement', getMeasurement(ce.style[pr + b[0] + sf]));
+			selectByValue(f, fp + '_right_measurement', getMeasurement(ce.style[pr + b[1] + sf]));
+			selectByValue(f, fp + '_bottom_measurement', getMeasurement(ce.style[pr + b[2] + sf]));
+			selectByValue(f, fp + '_left_measurement', getMeasurement(ce.style[pr + b[3] + sf]));
+			f.elements[fp + "_left_measurement"].disabled = false;
+			f.elements[fp + "_bottom_measurement"].disabled = false;
+			f.elements[fp + "_right_measurement"].disabled = false;
+		}
+	}
+}
+
+function isSame(e, pr, sf, b) {
+	var a = new Array(), i, x;
+
+	if (typeof(b) == "undefined")
+		b = new Array('Top', 'Right', 'Bottom', 'Left');
+
+	if (typeof(sf) == "undefined" || sf == null)
+		sf = "";
+
+	a[0] = e.style[pr + b[0] + sf];
+	a[1] = e.style[pr + b[1] + sf];
+	a[2] = e.style[pr + b[2] + sf];
+	a[3] = e.style[pr + b[3] + sf];
+
+	for (i=0; i<a.length; i++) {
+		if (a[i] == null)
+			return false;
+
+		for (x=0; x<a.length; x++) {
+			if (a[x] != a[i])
+				return false;
+		}
+	}
+
+	return true;
+};
+
+function hasEqualValues(a) {
+	var i, x;
+
+	for (i=0; i<a.length; i++) {
+		if (a[i] == null)
+			return false;
+
+		for (x=0; x<a.length; x++) {
+			if (a[x] != a[i])
+				return false;
+		}
+	}
+
+	return true;
+}
+
+function applyAction() {
+	var ce = document.getElementById('container');
+
+	generateCSS();
+
+	tinyMCEPopup.execCommand('mceSetElementStyle', false, tinyMCE.serializeStyle(tinyMCE.parseStyle(ce.style.cssText)));
+}
+
+function updateAction() {
+	applyAction();
+	tinyMCEPopup.close();
+}
+
+function generateCSS() {
+	var ce = document.getElementById('container'), f = document.forms[0], num = new RegExp('[0-9]+', 'g'), s, t;
+
+	ce.style.cssText = "";
+
+	// Build text styles
+	ce.style.fontFamily = f.text_font.value;
+	ce.style.fontSize = f.text_size.value + (isNum(f.text_size.value) ? f.text_size_measurement.value : "");
+	ce.style.fontStyle = f.text_style.value;
+	ce.style.lineHeight = f.text_lineheight.value + (isNum(f.text_lineheight.value) ? f.text_lineheight_measurement.value : "");
+	ce.style.textTransform = f.text_case.value;
+	ce.style.fontWeight = f.text_weight.value;
+	ce.style.fontVariant = f.text_variant.value;
+	ce.style.color = f.text_color.value;
+
+	s = "";
+	s += f.text_underline.checked ? " underline" : "";
+	s += f.text_overline.checked ? " overline" : "";
+	s += f.text_linethrough.checked ? " line-through" : "";
+	s += f.text_blink.checked ? " blink" : "";
+	s = s.length > 0 ? s.substring(1) : s;
+
+	if (f.text_none.checked)
+		s = "none";
+
+	ce.style.textDecoration = s;
+
+	// Build background styles
+
+	ce.style.backgroundColor = f.background_color.value;
+	ce.style.backgroundImage = f.background_image.value != "" ? "url(" + f.background_image.value + ")" : "";
+	ce.style.backgroundRepeat = f.background_repeat.value;
+	ce.style.backgroundAttachment = f.background_attachment.value;
+
+	if (f.background_hpos.value != "") {
+		s = "";
+		s += f.background_hpos.value + (isNum(f.background_hpos.value) ? f.background_hpos_measurement.value : "") + " ";
+		s += f.background_vpos.value + (isNum(f.background_vpos.value) ? f.background_vpos_measurement.value : "");
+		ce.style.backgroundPosition = s;
+	}
+
+	// Build block styles
+
+	ce.style.wordSpacing = f.block_wordspacing.value + (isNum(f.block_wordspacing.value) ? f.block_wordspacing_measurement.value : "");
+	ce.style.letterSpacing = f.block_letterspacing.value + (isNum(f.block_letterspacing.value) ? f.block_letterspacing_measurement.value : "");
+	ce.style.verticalAlign = f.block_vertical_alignment.value;
+	ce.style.textAlign = f.block_text_align.value;
+	ce.style.textIndent = f.block_text_indent.value + (isNum(f.block_text_indent.value) ? f.block_text_indent_measurement.value : "");
+	ce.style.whiteSpace = f.block_whitespace.value;
+	ce.style.display = f.block_display.value;
+
+	// Build box styles
+
+	ce.style.width = f.box_width.value + (isNum(f.box_width.value) ? f.box_width_measurement.value : "");
+	ce.style.height = f.box_height.value + (isNum(f.box_height.value) ? f.box_height_measurement.value : "");
+	ce.style.styleFloat = f.box_float.value;
+
+	if (tinyMCE.isGecko)
+		ce.style.cssFloat = f.box_float.value;
+
+	ce.style.clear = f.box_clear.value;
+
+	if (!f.box_padding_same.checked) {
+		ce.style.paddingTop = f.box_padding_top.value + (isNum(f.box_padding_top.value) ? f.box_padding_top_measurement.value : "");
+		ce.style.paddingRight = f.box_padding_right.value + (isNum(f.box_padding_right.value) ? f.box_padding_right_measurement.value : "");
+		ce.style.paddingBottom = f.box_padding_bottom.value + (isNum(f.box_padding_bottom.value) ? f.box_padding_bottom_measurement.value : "");
+		ce.style.paddingLeft = f.box_padding_left.value + (isNum(f.box_padding_left.value) ? f.box_padding_left_measurement.value : "");
+	} else
+		ce.style.padding = f.box_padding_top.value + (isNum(f.box_padding_top.value) ? f.box_padding_top_measurement.value : "");		
+
+	if (!f.box_margin_same.checked) {
+		ce.style.marginTop = f.box_margin_top.value + (isNum(f.box_margin_top.value) ? f.box_margin_top_measurement.value : "");
+		ce.style.marginRight = f.box_margin_right.value + (isNum(f.box_margin_right.value) ? f.box_margin_right_measurement.value : "");
+		ce.style.marginBottom = f.box_margin_bottom.value + (isNum(f.box_margin_bottom.value) ? f.box_margin_bottom_measurement.value : "");
+		ce.style.marginLeft = f.box_margin_left.value + (isNum(f.box_margin_left.value) ? f.box_margin_left_measurement.value : "");
+	} else
+		ce.style.margin = f.box_margin_top.value + (isNum(f.box_margin_top.value) ? f.box_margin_top_measurement.value : "");		
+
+	// Build border styles
+
+	if (!f.border_style_same.checked) {
+		ce.style.borderTopStyle = f.border_style_top.value;
+		ce.style.borderRightStyle = f.border_style_right.value;
+		ce.style.borderBottomStyle = f.border_style_bottom.value;
+		ce.style.borderLeftStyle = f.border_style_left.value;
+	} else
+		ce.style.borderStyle = f.border_style_top.value;
+
+	if (!f.border_width_same.checked) {
+		ce.style.borderTopWidth = f.border_width_top.value + (isNum(f.border_width_top.value) ? f.border_width_top_measurement.value : "");
+		ce.style.borderRightWidth = f.border_width_right.value + (isNum(f.border_width_right.value) ? f.border_width_right_measurement.value : "");
+		ce.style.borderBottomWidth = f.border_width_bottom.value + (isNum(f.border_width_bottom.value) ? f.border_width_bottom_measurement.value : "");
+		ce.style.borderLeftWidth = f.border_width_left.value + (isNum(f.border_width_left.value) ? f.border_width_left_measurement.value : "");
+	} else
+		ce.style.borderWidth = f.border_width_top.value;
+
+	if (!f.border_color_same.checked) {
+		ce.style.borderTopColor = f.border_color_top.value;
+		ce.style.borderRightColor = f.border_color_right.value;
+		ce.style.borderBottomColor = f.border_color_bottom.value;
+		ce.style.borderLeftColor = f.border_color_left.value;
+	} else
+		ce.style.borderColor = f.border_color_top.value;
+
+	// Build list styles
+
+	ce.style.listStyleType = f.list_type.value;
+	ce.style.listStylePosition = f.list_position.value;
+	ce.style.listStyleImage = f.list_bullet_image.value != "" ? "url(" + f.list_bullet_image.value + ")" : "";
+
+	// Build positioning styles
+
+	ce.style.position = f.positioning_type.value;
+	ce.style.visibility = f.positioning_visibility.value;
+
+	if (ce.style.width == "")
+		ce.style.width = f.positioning_width.value + (isNum(f.positioning_width.value) ? f.positioning_width_measurement.value : "");
+
+	if (ce.style.height == "")
+		ce.style.height = f.positioning_height.value + (isNum(f.positioning_height.value) ? f.positioning_height_measurement.value : "");
+
+	ce.style.zIndex = f.positioning_zindex.value;
+	ce.style.overflow = f.positioning_overflow.value;
+
+	if (!f.positioning_placement_same.checked) {
+		ce.style.top = f.positioning_placement_top.value + (isNum(f.positioning_placement_top.value) ? f.positioning_placement_top_measurement.value : "");
+		ce.style.right = f.positioning_placement_right.value + (isNum(f.positioning_placement_right.value) ? f.positioning_placement_right_measurement.value : "");
+		ce.style.bottom = f.positioning_placement_bottom.value + (isNum(f.positioning_placement_bottom.value) ? f.positioning_placement_bottom_measurement.value : "");
+		ce.style.left = f.positioning_placement_left.value + (isNum(f.positioning_placement_left.value) ? f.positioning_placement_left_measurement.value : "");
+	} else {
+		s = f.positioning_placement_top.value + (isNum(f.positioning_placement_top.value) ? f.positioning_placement_top_measurement.value : "");
+		ce.style.top = s;
+		ce.style.right = s;
+		ce.style.bottom = s;
+		ce.style.left = s;
+	}
+
+	if (!f.positioning_clip_same.checked) {
+		s = "rect(";
+		s += (isNum(f.positioning_clip_top.value) ? f.positioning_clip_top.value + f.positioning_clip_top_measurement.value : "auto") + " ";
+		s += (isNum(f.positioning_clip_right.value) ? f.positioning_clip_right.value + f.positioning_clip_right_measurement.value : "auto") + " ";
+		s += (isNum(f.positioning_clip_bottom.value) ? f.positioning_clip_bottom.value + f.positioning_clip_bottom_measurement.value : "auto") + " ";
+		s += (isNum(f.positioning_clip_left.value) ? f.positioning_clip_left.value + f.positioning_clip_left_measurement.value : "auto");
+		s += ")";
+
+		if (s != "rect(auto auto auto auto)")
+			ce.style.clip = s;
+	} else {
+		s = "rect(";
+		t = isNum(f.positioning_clip_top.value) ? f.positioning_clip_top.value + f.positioning_clip_top_measurement.value : "auto";
+		s += t + " ";
+		s += t + " ";
+		s += t + " ";
+		s += t + ")";
+
+		if (s != "rect(auto auto auto auto)")
+			ce.style.clip = s;
+	}
+
+	ce.style.cssText = tinyMCE.serializeStyle(tinyMCE.parseStyle(ce.style.cssText));
+}
+
+function isNum(s) {
+	return new RegExp('[0-9]+', 'g').test(s);
+}
+
+function showDisabledControls() {
+	var f = document.forms, i, a;
+
+	for (i=0; i<f.length; i++) {
+		for (a=0; a<f[i].elements.length; a++) {
+			if (f[i].elements[a].disabled)
+				tinyMCE.addCSSClass(f[i].elements[a], "disabled");
+			else
+				tinyMCE.removeCSSClass(f[i].elements[a], "disabled");
+		}
+	}
+}
+
+function fillSelect(f, s, param, dval, sep, em) {
+	var i, ar, p, se;
+
+	f = document.forms[f];
+	sep = typeof(sep) == "undefined" ? ";" : sep;
+
+	if (em)
+		addSelectValue(f, s, "", "");
+
+	ar = tinyMCE.getParam(param, dval).split(sep);
+	for (i=0; i<ar.length; i++) {
+		se = false;
+
+		if (ar[i].charAt(0) == '+') {
+			ar[i] = ar[i].substring(1);
+			se = true;
+		}
+
+		p = ar[i].split('=');
+
+		if (p.length > 1) {
+			addSelectValue(f, s, p[0], p[1]);
+
+			if (se)
+				selectByValue(f, s, p[1]);
+		} else {
+			addSelectValue(f, s, p[0], p[0]);
+
+			if (se)
+				selectByValue(f, s, p[0]);
+		}
+	}
+}
+
+function toggleSame(ce, pre) {
+	var el = document.forms[0].elements, i;
+
+	if (ce.checked) {
+		el[pre + "_top"].disabled = false;
+		el[pre + "_right"].disabled = true;
+		el[pre + "_bottom"].disabled = true;
+		el[pre + "_left"].disabled = true;
+
+		if (el[pre + "_top_measurement"]) {
+			el[pre + "_top_measurement"].disabled = false;
+			el[pre + "_right_measurement"].disabled = true;
+			el[pre + "_bottom_measurement"].disabled = true;
+			el[pre + "_left_measurement"].disabled = true;
+		}
+	} else {
+		el[pre + "_top"].disabled = false;
+		el[pre + "_right"].disabled = false;
+		el[pre + "_bottom"].disabled = false;
+		el[pre + "_left"].disabled = false;
+
+		if (el[pre + "_top_measurement"]) {
+			el[pre + "_top_measurement"].disabled = false;
+			el[pre + "_right_measurement"].disabled = false;
+			el[pre + "_bottom_measurement"].disabled = false;
+			el[pre + "_left_measurement"].disabled = false;
+		}
+	}
+
+	showDisabledControls();
+}
+
+function synch(fr, to) {
+	var f = document.forms[0];
+
+	f.elements[to].value = f.elements[fr].value;
+
+	if (f.elements[fr + "_measurement"])
+		selectByValue(f, to + "_measurement", f.elements[fr + "_measurement"].value);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/style/langs/en.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,66 @@
+// UK lang variables
+
+tinyMCE.addToLang('style',{
+title : 'Edit CSS Style',
+styleinfo_desc : 'Edit CSS Style',
+apply : 'Apply',
+text_tab : 'Text',
+background_tab : 'Background',
+block_tab : 'Block',
+box_tab : 'Box',
+border_tab : 'Border',
+list_tab : 'List',
+positioning_tab : 'Positioning',
+text_props : 'Text',
+text_font : 'Font',
+text_size : 'Size',
+text_weight : 'Weight',
+text_style : 'Style',
+text_variant : 'Variant',
+text_lineheight : 'Line height',
+text_case : 'Case',
+text_color : 'Color',
+text_decoration : 'Decoration',
+text_overline : 'overline',
+text_underline : 'underline',
+text_striketrough : 'strikethrough',
+text_blink : 'blink',
+text_none : 'none',
+background_color : 'Background color',
+background_image : 'Background image',
+background_repeat : 'Repeat',
+background_attachment : 'Attachment',
+background_hpos : 'Horizontal position',
+background_vpos : 'Vertical position',
+block_wordspacing : 'Word spacing',
+block_letterspacing : 'Letter spacing',
+block_vertical_alignment : 'Vertical alignment',
+block_text_align : 'Text align',
+block_text_indent : 'Text indent',
+block_whitespace : 'Whitespace',
+block_display : 'Display',
+box_width : 'Width',
+box_height : 'Height',
+box_float : 'Float',
+box_clear : 'Clear',
+padding : 'Padding',
+same : 'Same for all',
+top : 'Top',
+right : 'Right',
+bottom : 'Bottom',
+left : 'Left',
+margin : 'Margin',
+style : 'Style',
+width : 'Width',
+height : 'Height',
+color : 'Color',
+list_type : 'Type',
+bullet_image : 'Bullet image',
+position : 'Position',
+positioning_type : 'Type',
+visibility : 'Visibility',
+zindex : 'Z-index',
+overflow : 'Overflow',
+placement : 'Placement',
+clip : 'Clip'
+});
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/style/props.htm	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,729 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>{$lang_style_title}</title>
+	<script language="javascript" type="text/javascript" src="../../tiny_mce_popup.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/mctabs.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/editable_selects.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/form_utils.js"></script>
+	<script language="javascript" type="text/javascript" src="jscripts/props.js"></script>
+	<link href="css/props.css" rel="stylesheet" type="text/css" />
+	<base target="_self" />
+</head>
+
+<body id="styleprops" onLoad="tinyMCEPopup.executeOnLoad('init();');" style="display: none">
+<form onSubmit="updateAction();return false;" action="#">
+<div class="tabs">
+	<ul>
+		<li id="text_tab" class="current"><span><a href="javascript:mcTabs.displayTab('text_tab','text_panel');" onMouseDown="return false;">{$lang_style_text_tab}</a></span></li>
+		<li id="background_tab"><span><a href="javascript:mcTabs.displayTab('background_tab','background_panel');" onMouseDown="return false;">{$lang_style_background_tab}</a></span></li>
+		<li id="block_tab"><span><a href="javascript:mcTabs.displayTab('block_tab','block_panel');" onMouseDown="return false;">{$lang_style_block_tab}</a></span></li>
+		<li id="box_tab"><span><a href="javascript:mcTabs.displayTab('box_tab','box_panel');" onMouseDown="return false;">{$lang_style_box_tab}</a></span></li>
+		<li id="border_tab"><span><a href="javascript:mcTabs.displayTab('border_tab','border_panel');" onMouseDown="return false;">{$lang_style_border_tab}</a></span></li>
+		<li id="list_tab"><span><a href="javascript:mcTabs.displayTab('list_tab','list_panel');" onMouseDown="return false;">{$lang_style_list_tab}</a></span></li>
+		<li id="positioning_tab"><span><a href="javascript:mcTabs.displayTab('positioning_tab','positioning_panel');" onMouseDown="return false;">{$lang_style_positioning_tab}</a></span></li>
+	</ul>
+</div>
+
+<div class="panel_wrapper">
+<div id="text_panel" class="panel current">
+	<table border="0" width="100%">
+		<tr>
+			<td><label for="text_font">{$lang_style_text_font}</label></td>
+			<td colspan="3">
+				<select id="text_font" name="text_font" class="mceEditableSelect" onChange="alert(this.options[this.selectedIndex].value);"></select>
+			</td>
+		</tr>
+		<tr>
+			<td><label for="text_size">{$lang_style_text_size}</label></td>
+			<td>
+				<table border="0" cellspacing="0" cellpadding="0">
+					<tr>
+						<td><select id="text_size" name="text_size" class="mceEditableSelect"></select></td>
+						<td>&nbsp;</td>
+      <td><select id="text_size_measurement" name="text_size_measurement"></select></td>
+					</tr>
+				</table>
+			</td>
+			<td><label for="text_weight">{$lang_style_text_weight}</label></td>
+			<td>
+				<select id="text_weight" name="text_weight"></select>
+			</td>
+		</tr>
+		<tr>
+			<td><label for="text_style">{$lang_style_text_style}</label></td>
+			<td>
+				<select id="text_style" name="text_style" class="mceEditableSelect"></select>
+			</td>
+			<td><label for="text_variant">{$lang_style_text_variant}</label></td>
+			<td>
+				<select id="text_variant" name="text_variant"></select>
+			</td>
+		</tr>
+		<tr>
+			<td><label for="text_lineheight">{$lang_style_text_lineheight}</label></td>
+			<td>
+				<table border="0" cellspacing="0" cellpadding="0">
+					<tr>
+						<td>
+							<select id="text_lineheight" name="text_lineheight" class="mceEditableSelect"></select>
+						</td>
+						<td>&nbsp;</td>
+      <td><select id="text_lineheight_measurement" name="text_lineheight_measurement"></select></td>
+					</tr>
+				</table>
+			</td>
+			<td><label for="text_case">{$lang_style_text_case}</label></td>
+			<td>
+				<select id="text_case" name="text_case"></select>
+			</td>
+		</tr>
+		<tr>
+			<td><label for="text_color">{$lang_style_text_color}</label></td>
+			<td colspan="2">
+				<table border="0" cellpadding="0" cellspacing="0">
+					<tr>
+						<td><input id="text_color" name="text_color" type="text" value="" size="9" onChange="updateColor('text_color_pick','text_color');" /></td>
+						<td id="text_color_pickcontainer">&nbsp;</td>
+					</tr>
+				</table>
+			</td>
+		</tr>
+		<tr>
+			<td valign="top" style="vertical-align: top; padding-top: 3px;">{$lang_style_text_decoration}</td>
+			<td colspan="2">
+				<table border="0" cellspacing="0" cellpadding="0">
+					<tr>
+						<td><input id="text_underline" name="text_underline" class="checkbox" type="checkbox" /></td>
+						<td><label for="text_underline">{$lang_style_text_underline}</label></td>
+					</tr>
+					<tr>
+						<td><input id="text_overline" name="text_overline" class="checkbox" type="checkbox" /></td>
+						<td><label for="text_overline">{$lang_style_text_overline}</label></td>
+					</tr>
+					<tr>
+						<td><input id="text_linethrough" name="text_linethrough" class="checkbox" type="checkbox" /></td>
+						<td><label for="text_linethrough">{$lang_style_text_striketrough}</label></td>
+					</tr>
+					<tr>
+						<td><input id="text_blink" name="text_blink" class="checkbox" type="checkbox" /></td>
+						<td><label for="text_blink">{$lang_style_text_blink}</label></td>
+					</tr>
+					<tr>
+						<td><input id="text_none" name="text_none" class="checkbox" type="checkbox" /></td>
+						<td><label for="text_none">{$lang_style_text_none}</label></td>
+					</tr>
+				</table>
+			</td>
+		</tr>
+	</table>
+</div>
+
+<div id="background_panel" class="panel">
+	<table border="0">
+		<tr>
+			<td><label for="background_color">{$lang_style_background_color}</label></td>
+			<td>
+				<table border="0" cellpadding="0" cellspacing="0">
+					<tr>
+						<td><input id="background_color" name="background_color" type="text" value="" size="9" onChange="updateColor('background_color_pick','background_color');" /></td>
+						<td id="background_color_pickcontainer">&nbsp;</td>
+					</tr>
+				</table>
+			</td>
+		</tr>
+
+		<tr>
+			<td><label for="background_image">{$lang_style_background_image}</label></td>
+			<td><table border="0" cellspacing="0" cellpadding="0">
+				<tr> 
+				  <td><input id="background_image" name="background_image" type="text" /></td> 
+				  <td id="background_image_browser">&nbsp;</td>
+				</tr>
+				</table>
+			</td>
+		</tr>
+
+		<tr>
+			<td><label for="background_repeat">{$lang_style_background_repeat}</label></td>
+			<td><select id="background_repeat" name="background_repeat" class="mceEditableSelect"></select></td>
+		</tr>
+
+		<tr>
+			<td><label for="background_attachment">{$lang_style_background_attachment}</label></td>
+			<td><select id="background_attachment" name="background_attachment" class="mceEditableSelect"></select></td>
+		</tr>
+
+		<tr>
+			<td><label for="background_hpos">{$lang_style_background_hpos}</label></td>
+			<td>
+				<table border="0" cellspacing="0" cellpadding="0">
+					<tr>
+						<td><select id="background_hpos" name="background_hpos" class="mceEditableSelect"></select></td>
+						<td>&nbsp;</td>
+      <td><select id="background_hpos_measurement" name="background_hpos_measurement"></select></td>
+					</tr>
+				</table>
+			</td>
+		</tr>
+
+		<tr>
+			<td><label for="background_vpos">{$lang_style_background_vpos}</label></td>
+			<td>
+				<table border="0" cellspacing="0" cellpadding="0">
+					<tr>
+						<td><select id="background_vpos" name="background_vpos" class="mceEditableSelect"></select></td>
+						<td>&nbsp;</td>
+      <td><select id="background_vpos_measurement" name="background_vpos_measurement"></select></td>
+					</tr>
+				</table>
+			</td>
+		</tr>
+	</table>
+</div>
+
+<div id="block_panel" class="panel">
+	<table border="0">
+		<tr>
+			<td><label for="block_wordspacing">{$lang_style_block_wordspacing}</label></td>
+			<td>
+				<table border="0" cellspacing="0" cellpadding="0">
+					<tr>
+						<td><select id="block_wordspacing" name="block_wordspacing" class="mceEditableSelect"></select></td>
+						<td>&nbsp;</td>
+      <td><select id="block_wordspacing_measurement" name="block_wordspacing_measurement"></select></td>
+					</tr>
+				</table>
+			</td>
+		</tr>
+
+		<tr>
+			<td><label for="block_letterspacing">{$lang_style_block_letterspacing}</label></td>
+			<td>
+				<table border="0" cellspacing="0" cellpadding="0">
+					<tr>
+						<td><select id="block_letterspacing" name="block_letterspacing" class="mceEditableSelect"></select></td>
+						<td>&nbsp;</td>
+      <td><select id="block_letterspacing_measurement" name="block_letterspacing_measurement"></select></td>
+					</tr>
+				</table>
+			</td>
+		</tr>
+
+		<tr>
+			<td><label for="block_vertical_alignment">{$lang_style_block_vertical_alignment}</label></td>
+			<td><select id="block_vertical_alignment" name="block_vertical_alignment" class="mceEditableSelect"></select></td>
+		</tr>
+
+		<tr>
+			<td><label for="block_text_align">{$lang_style_block_text_align}</label></td>
+			<td><select id="block_text_align" name="block_text_align" class="mceEditableSelect"></select></td>
+		</tr>
+
+		<tr>
+			<td><label for="block_text_indent">{$lang_style_block_text_indent}</label></td>
+			<td>
+				<table border="0" cellspacing="0" cellpadding="0">
+					<tr>
+						<td><input type="text" id="block_text_indent" name="block_text_indent" /></td>
+						<td>&nbsp;</td>
+      <td><select id="block_text_indent_measurement" name="block_text_indent_measurement"></select></td>
+					</tr>
+				</table>
+			</td>
+		</tr>
+
+		<tr>
+			<td><label for="block_whitespace">{$lang_style_block_whitespace}</label></td>
+			<td><select id="block_whitespace" name="block_whitespace" class="mceEditableSelect"></select></td>
+		</tr>
+
+		<tr>
+			<td><label for="block_display">{$lang_style_block_display}</label></td>
+			<td><select id="block_display" name="block_display" class="mceEditableSelect"></select></td>
+		</tr>
+	</table>
+</div>
+
+<div id="box_panel" class="panel">
+<table border="0">
+	<tr>
+		<td><label for="box_width">{$lang_style_box_width}</label></td>
+		<td>
+			<table border="0" cellspacing="0" cellpadding="0">
+				<tr>
+					<td><input type="text" id="box_width" name="box_width" class="mceEditableSelect" onChange="synch('box_width','positioning_width');" /></td>
+					<td>&nbsp;</td>
+     <td><select id="box_width_measurement" name="box_width_measurement"></select></td>
+				</tr>
+			</table>
+		</td>
+		<td>&nbsp;&nbsp;&nbsp;<label for="box_float">{$lang_style_box_float}</label></td>
+		<td><select id="box_float" name="box_float" class="mceEditableSelect"></select></td>
+	</tr>
+
+	<tr>
+		<td><label for="box_height">{$lang_style_box_height}</label></td>
+		<td>
+			<table border="0" cellspacing="0" cellpadding="0">
+				<tr>
+					<td><input type="text" id="box_height" name="box_height" class="mceEditableSelect" onChange="synch('box_height','positioning_height');" /></td>
+					<td>&nbsp;</td>
+     <td><select id="box_height_measurement" name="box_height_measurement"></select></td>
+				</tr>
+			</table>
+		</td>
+		<td>&nbsp;&nbsp;&nbsp;<label for="box_clear">{$lang_style_box_clear}</label></td>
+		<td><select id="box_clear" name="box_clear" class="mceEditableSelect"></select></td>
+	</tr>
+</table>
+<div style="float: left; width: 49%">
+	<fieldset>
+		<legend>{$lang_style_padding}</legend>
+
+		<table border="0">
+			<tr>
+				<td>&nbsp;</td>
+				<td><input type="checkbox" id="box_padding_same" name="box_padding_same" class="checkbox" checked="checked" onClick="toggleSame(this,'box_padding');" /> <label for="box_padding_same">{$lang_style_same}</label></td>
+			</tr>
+			<tr>
+				<td><label for="box_padding_top">{$lang_style_top}</label></td>
+				<td>
+					<table border="0" cellspacing="0" cellpadding="0">
+						<tr>
+							<td><input type="text" id="box_padding_top" name="box_padding_top" class="mceEditableSelect" /></td>
+							<td>&nbsp;</td>
+       <td><select id="box_padding_top_measurement" name="box_padding_top_measurement"></select></td>
+						</tr>
+					</table>
+				</td>
+			</tr>
+			<tr>
+				<td><label for="box_padding_right">{$lang_style_right}</label></td>
+				<td>
+					<table border="0" cellspacing="0" cellpadding="0">
+						<tr>
+							<td><input type="text" id="box_padding_right" name="box_padding_right" class="mceEditableSelect" disabled="disabled" /></td>
+							<td>&nbsp;</td>
+       <td><select id="box_padding_right_measurement" name="box_padding_right_measurement" disabled="disabled"></select></td>
+						</tr>
+					</table>
+				</td>
+			</tr>
+			<tr>
+				<td><label for="box_padding_bottom">{$lang_style_bottom}</label></td>
+				<td>
+					<table border="0" cellspacing="0" cellpadding="0">
+						<tr>
+							<td><input type="text" id="box_padding_bottom" name="box_padding_bottom" class="mceEditableSelect" disabled="disabled" /></td>
+							<td>&nbsp;</td>
+       <td><select id="box_padding_bottom_measurement" name="box_padding_bottom_measurement" disabled="disabled"></select></td>
+						</tr>
+					</table>
+				</td>
+			</tr>
+			<tr>
+				<td><label for="box_padding_left">{$lang_style_left}</label></td>
+				<td>
+					<table border="0" cellspacing="0" cellpadding="0">
+						<tr>
+							<td><input type="text" id="box_padding_left" name="box_padding_left" class="mceEditableSelect" disabled="disabled" /></td>
+							<td>&nbsp;</td>
+       <td><select id="box_padding_left_measurement" name="box_padding_left_measurement" disabled="disabled"></select></td>
+						</tr>
+					</table>
+				</td>
+			</tr>
+		</table>
+	</fieldset>
+</div>
+
+<div style="float: right; width: 49%">
+	<fieldset>
+		<legend>{$lang_style_margin}</legend>
+
+		<table border="0">
+			<tr>
+				<td>&nbsp;</td>
+				<td><input type="checkbox" id="box_margin_same" name="box_margin_same" class="checkbox" checked="checked" onClick="toggleSame(this,'box_margin');" /> <label for="box_margin_same">{$lang_style_same}</label></td>
+			</tr>
+			<tr>
+				<td><label for="box_margin_top">{$lang_style_top}</label></td>
+				<td>
+					<table border="0" cellspacing="0" cellpadding="0">
+						<tr>
+							<td><input type="text" id="box_margin_top" name="box_margin_top" class="mceEditableSelect" /></td>
+							<td>&nbsp;</td>
+       <td><select id="box_margin_top_measurement" name="box_margin_top_measurement"></select></td>
+						</tr>
+					</table>
+				</td>
+			</tr>
+			<tr>
+				<td><label for="box_margin_right">{$lang_style_right}</label></td>
+				<td>
+					<table border="0" cellspacing="0" cellpadding="0">
+						<tr>
+							<td><input type="text" id="box_margin_right" name="box_margin_right" class="mceEditableSelect" disabled="disabled" /></td>
+							<td>&nbsp;</td>
+       <td><select id="box_margin_right_measurement" name="box_margin_right_measurement" disabled="disabled"></select></td>
+						</tr>
+					</table>
+				</td>
+			</tr>
+			<tr>
+				<td><label for="box_margin_bottom">{$lang_style_bottom}</label></td>
+				<td>
+					<table border="0" cellspacing="0" cellpadding="0">
+						<tr>
+							<td><input type="text" id="box_margin_bottom" name="box_margin_bottom" class="mceEditableSelect" disabled="disabled" /></td>
+							<td>&nbsp;</td>
+       <td><select id="box_margin_bottom_measurement" name="box_margin_bottom_measurement" disabled="disabled"></select></td>
+						</tr>
+					</table>
+				</td>
+			</tr>
+			<tr>
+				<td><label for="box_margin_left">{$lang_style_left}</label></td>
+				<td>
+					<table border="0" cellspacing="0" cellpadding="0">
+						<tr>
+							<td><input type="text" id="box_margin_left" name="box_margin_left" class="mceEditableSelect" disabled="disabled" /></td>
+							<td>&nbsp;</td>
+       <td><select id="box_margin_left_measurement" name="box_margin_left_measurement" disabled="disabled"></select></td>
+						</tr>
+					</table>
+				</td>
+			</tr>
+		</table>
+	</fieldset>
+</div>
+<br style="clear: both" />
+</div>
+
+<div id="border_panel" class="panel">
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+	<td class="tdelim">&nbsp;</td>
+	<td class="tdelim delim">&nbsp;</td>
+	<td class="tdelim">{$lang_style_style}</td>
+	<td class="tdelim delim">&nbsp;</td>
+	<td class="tdelim">{$lang_style_width}</td>
+	<td class="tdelim delim">&nbsp;</td>
+	<td class="tdelim">{$lang_style_color}</td>
+</tr>
+
+<tr>
+	<td>&nbsp;</td>
+	<td class="delim">&nbsp;</td>
+	<td><input type="checkbox" id="border_style_same" name="border_style_same" class="checkbox" checked="checked" onClick="toggleSame(this,'border_style');" /> <label for="border_style_same">{$lang_style_same}</label></td>
+	<td class="delim">&nbsp;</td>
+	<td><input type="checkbox" id="border_width_same" name="border_width_same" class="checkbox" checked="checked" onClick="toggleSame(this,'border_width');" /> <label for="border_width_same">{$lang_style_same}</label></td>
+	<td class="delim">&nbsp;</td>
+	<td><input type="checkbox" id="border_color_same" name="border_color_same" class="checkbox" checked="checked" onClick="toggleSame(this,'border_color');" /> <label for="border_color_same">{$lang_style_same}</label></td>
+</tr>
+
+<tr>
+	<td>{$lang_style_top}</td>
+	<td class="delim">&nbsp;</td>
+	<td><select id="border_style_top" name="border_style_top" class="mceEditableSelect"></select></td>
+	<td class="delim">&nbsp;</td>
+	<td>
+		<table border="0" cellspacing="0" cellpadding="0">
+			<tr>
+				<td><select id="border_width_top" name="border_width_top" class="mceEditableSelect"></select></td>
+				<td>&nbsp;</td>
+    <td><select id="border_width_top_measurement" name="border_width_top_measurement"></select></td>
+			</tr>
+		</table>
+	</td>
+	<td class="delim">&nbsp;</td>
+	<td>
+		<table border="0" cellpadding="0" cellspacing="0">
+			<tr>
+				<td><input id="border_color_top" name="border_color_top" type="text" value="" size="9" onChange="updateColor('border_color_top_pick','border_color_top');" /></td>
+				<td id="border_color_top_pickcontainer">&nbsp;</td>
+			</tr>
+		</table>
+	</td>
+</tr>
+
+<tr>
+	<td>{$lang_style_right}</td>
+	<td class="delim">&nbsp;</td>
+	<td><select id="border_style_right" name="border_style_right" class="mceEditableSelect" disabled="disabled"></select></td>
+	<td class="delim">&nbsp;</td>
+	<td>
+		<table border="0" cellspacing="0" cellpadding="0">
+			<tr>
+				<td><select id="border_width_right" name="border_width_right" class="mceEditableSelect" disabled="disabled"></select></td>
+				<td>&nbsp;</td>
+    <td><select id="border_width_right_measurement" name="border_width_right_measurement" disabled="disabled"></select></td>
+			</tr>
+		</table>
+	</td>
+	<td class="delim">&nbsp;</td>
+	<td>
+		<table border="0" cellpadding="0" cellspacing="0">
+			<tr>
+				<td><input id="border_color_right" name="border_color_right" type="text" value="" size="9" onChange="updateColor('border_color_right_pick','border_color_right');" disabled="disabled" /></td>
+				<td id="border_color_right_pickcontainer">&nbsp;</td>
+			</tr>
+		</table>
+	</td>
+</tr>
+
+<tr>
+	<td>{$lang_style_bottom}</td>
+	<td class="delim">&nbsp;</td>
+	<td><select id="border_style_bottom" name="border_style_bottom" class="mceEditableSelect" disabled="disabled"></select></td>
+	<td class="delim">&nbsp;</td>
+	<td>
+		<table border="0" cellspacing="0" cellpadding="0">
+			<tr>
+				<td><select id="border_width_bottom" name="border_width_bottom" class="mceEditableSelect" disabled="disabled"></select></td>
+				<td>&nbsp;</td>
+    <td><select id="border_width_bottom_measurement" name="border_width_bottom_measurement" disabled="disabled"></select></td>
+			</tr>
+		</table>
+	</td>
+	<td class="delim">&nbsp;</td>
+	<td>
+		<table border="0" cellpadding="0" cellspacing="0">
+			<tr>
+				<td><input id="border_color_bottom" name="border_color_bottom" type="text" value="" size="9" onChange="updateColor('border_color_bottom_pick','border_color_bottom');" disabled="disabled" /></td>
+				<td id="border_color_bottom_pickcontainer">&nbsp;</td>
+			</tr>
+		</table>
+	</td>
+</tr>
+
+<tr>
+	<td>{$lang_style_left}</td>
+	<td class="delim">&nbsp;</td>
+	<td><select id="border_style_left" name="border_style_left" class="mceEditableSelect" disabled="disabled"></select></td>
+	<td class="delim">&nbsp;</td>
+	<td>
+		<table border="0" cellspacing="0" cellpadding="0">
+			<tr>
+				<td><select id="border_width_left" name="border_width_left" class="mceEditableSelect" disabled="disabled"></select></td>
+				<td>&nbsp;</td>
+    <td><select id="border_width_left_measurement" name="border_width_left_measurement" disabled="disabled"></select></td>
+			</tr>
+		</table>
+	</td>
+	<td class="delim">&nbsp;</td>
+	<td>
+		<table border="0" cellpadding="0" cellspacing="0">
+			<tr>
+				<td><input id="border_color_left" name="border_color_left" type="text" value="" size="9" onChange="updateColor('border_color_left_pick','border_color_left');" disabled="disabled" /></td>
+				<td id="border_color_left_pickcontainer">&nbsp;</td>
+			</tr>
+		</table>
+	</td>
+</tr>
+</table>
+</div>
+
+<div id="list_panel" class="panel">
+	<table border="0">
+		<tr>
+			<td><label for="list_type">{$lang_style_list_type}</label></td>
+			<td><select id="list_type" name="list_type" class="mceEditableSelect"></select></td>
+		</tr>
+
+		<tr>
+			<td><label for="list_bullet_image">{$lang_style_bullet_image}</label></td>
+			<td><input id="list_bullet_image" name="list_bullet_image" type="text" /></td>
+		</tr>
+
+		<tr>
+			<td><label for="list_position">{$lang_style_position}</label></td>
+			<td><select id="list_position" name="list_position" class="mceEditableSelect"></select></td>
+		</tr>
+	</table>
+</div>
+
+<div id="positioning_panel" class="panel">
+<table border="0">
+	<tr>
+		<td><label for="positioning_type">{$lang_style_positioning_type}</label></td>
+		<td><select id="positioning_type" name="positioning_type" class="mceEditableSelect"></select></td>
+		<td>&nbsp;&nbsp;&nbsp;<label for="positioning_visibility">{$lang_style_visibility}</label></td>
+		<td><select id="positioning_visibility" name="positioning_visibility" class="mceEditableSelect"></select></td>
+	</tr>
+
+	<tr>
+		<td><label for="positioning_width">{$lang_style_width}</label></td>
+		<td>
+			<table border="0" cellspacing="0" cellpadding="0">
+				<tr>
+					<td><input type="text" id="positioning_width" name="positioning_width" onChange="synch('positioning_width','box_width');" /></td>
+					<td>&nbsp;</td>
+     <td><select id="positioning_width_measurement" name="positioning_width_measurement"></select></td>
+				</tr>
+			</table>
+		</td>
+		<td>&nbsp;&nbsp;&nbsp;<label for="positioning_zindex">{$lang_style_zindex}</label></td>
+		<td><input type="text" id="positioning_zindex" name="positioning_zindex" /></td>
+	</tr>
+
+	<tr>
+		<td><label for="positioning_height">{$lang_style_height}</label></td>
+		<td>
+			<table border="0" cellspacing="0" cellpadding="0">
+				<tr>
+					<td><input type="text" id="positioning_height" name="positioning_height" onChange="synch('positioning_height','box_height');" /></td>
+					<td>&nbsp;</td>
+     <td><select id="positioning_height_measurement" name="positioning_height_measurement"></select></td>
+				</tr>
+			</table>
+		</td>
+		<td>&nbsp;&nbsp;&nbsp;<label for="positioning_overflow">{$lang_style_overflow}</label></td>
+		<td><select id="positioning_overflow" name="positioning_overflow" class="mceEditableSelect"></select></td>
+	</tr>
+</table>
+
+<div style="float: left; width: 49%">
+	<fieldset>
+		<legend>{$lang_style_placement}</legend>
+
+		<table border="0">
+			<tr>
+				<td>&nbsp;</td>
+				<td><input type="checkbox" id="positioning_placement_same" name="positioning_placement_same" class="checkbox" checked="checked" onClick="toggleSame(this,'positioning_placement');" /> <label for="positioning_placement_same">{$lang_style_same}</label></td>
+			</tr>
+			<tr>
+				<td>{$lang_style_top}</td>
+				<td>
+					<table border="0" cellspacing="0" cellpadding="0">
+						<tr>
+							<td><input type="text" id="positioning_placement_top" name="positioning_placement_top" /></td>
+							<td>&nbsp;</td>
+       <td><select id="positioning_placement_top_measurement" name="positioning_placement_top_measurement"></select></td>
+						</tr>
+					</table>
+				</td>
+			</tr>
+			<tr>
+				<td>{$lang_style_right}</td>
+				<td>
+					<table border="0" cellspacing="0" cellpadding="0">
+						<tr>
+							<td><input type="text" id="positioning_placement_right" name="positioning_placement_right" disabled="disabled" /></td>
+							<td>&nbsp;</td>
+       <td><select id="positioning_placement_right_measurement" name="positioning_placement_right_measurement" disabled="disabled"></select></td>
+						</tr>
+					</table>
+				</td>
+			</tr>
+			<tr>
+				<td>{$lang_style_bottom}</td>
+				<td>
+					<table border="0" cellspacing="0" cellpadding="0">
+						<tr>
+							<td><input type="text" id="positioning_placement_bottom" name="positioning_placement_bottom" disabled="disabled" /></td>
+							<td>&nbsp;</td>
+       <td><select id="positioning_placement_bottom_measurement" name="positioning_placement_bottom_measurement" disabled="disabled"></select></td>
+						</tr>
+					</table>
+				</td>
+			</tr>
+			<tr>
+				<td>{$lang_style_left}</td>
+				<td>
+					<table border="0" cellspacing="0" cellpadding="0">
+						<tr>
+							<td><input type="text" id="positioning_placement_left" name="positioning_placement_left" disabled="disabled" /></td>
+							<td>&nbsp;</td>
+       <td><select id="positioning_placement_left_measurement" name="positioning_placement_left_measurement" disabled="disabled"></select></td>
+						</tr>
+					</table>
+				</td>
+			</tr>
+		</table>
+	</fieldset>
+</div>
+
+<div style="float: right; width: 49%">
+	<fieldset>
+		<legend>{$lang_style_clip}</legend>
+
+		<table border="0">
+			<tr>
+				<td>&nbsp;</td>
+				<td><input type="checkbox" id="positioning_clip_same" name="positioning_clip_same" class="checkbox" checked="checked" onClick="toggleSame(this,'positioning_clip');" /> <label for="positioning_clip_same">{$lang_style_same}</label></td>
+			</tr>
+			<tr>
+				<td>{$lang_style_top}</td>
+				<td>
+					<table border="0" cellspacing="0" cellpadding="0">
+						<tr>
+							<td><input type="text" id="positioning_clip_top" name="positioning_clip_top" /></td>
+							<td>&nbsp;</td>
+       <td><select id="positioning_clip_top_measurement" name="positioning_clip_top_measurement"></select></td>
+						</tr>
+					</table>
+				</td>
+			</tr>
+			<tr>
+				<td>{$lang_style_right}</td>
+				<td>
+					<table border="0" cellspacing="0" cellpadding="0">
+						<tr>
+							<td><input type="text" id="positioning_clip_right" name="positioning_clip_right" disabled="disabled" /></td>
+							<td>&nbsp;</td>
+       <td><select id="positioning_clip_right_measurement" name="positioning_clip_right_measurement" disabled="disabled"></select></td>
+						</tr>
+					</table>
+				</td>
+			</tr>
+			<tr>
+				<td>{$lang_style_bottom}</td>
+				<td>
+					<table border="0" cellspacing="0" cellpadding="0">
+						<tr>
+							<td><input type="text" id="positioning_clip_bottom" name="positioning_clip_bottom" disabled="disabled" /></td>
+							<td>&nbsp;</td>
+       <td><select id="positioning_clip_bottom_measurement" name="positioning_clip_bottom_measurement" disabled="disabled"></select></td>
+						</tr>
+					</table>
+				</td>
+			</tr>
+			<tr>
+				<td>{$lang_style_left}</td>
+				<td>
+					<table border="0" cellspacing="0" cellpadding="0">
+						<tr>
+							<td><input type="text" id="positioning_clip_left" name="positioning_clip_left" disabled="disabled" /></td>
+							<td>&nbsp;</td>
+       <td><select id="positioning_clip_left_measurement" name="positioning_clip_left_measurement" disabled="disabled"></select></td>
+						</tr>
+					</table>
+				</td>
+			</tr>
+		</table>
+	</fieldset>
+</div>
+<br style="clear: both" />
+</div>
+</div>
+
+<div class="mceActionPanel">
+	<div style="float: left">
+		<div style="float: left"><input type="button" id="insert" name="insert" value="{$lang_update}" onClick="updateAction();" /></div>
+
+		<div style="float: left">&nbsp;<input type="button" id="apply" name="apply" value="{$lang_style_apply}" onClick="applyAction();" class="updateButton" /></div>
+		<br style="clear: both" />
+	</div>
+
+	<div style="float: right">
+		<input type="button" id="cancel" name="cancel" value="{$lang_cancel}" onClick="tinyMCEPopup.close();" />
+	</div>
+</div>
+</form>
+
+<div style="display: none">
+	<div id="container"></div>
+</div>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/style/readme.txt	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+Check the TinyMCE documentation for details on this plugin.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/table/cell.htm	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,182 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>{$lang_table_cell_title}</title>
+	<script language="javascript" type="text/javascript" src="../../tiny_mce_popup.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/mctabs.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/form_utils.js"></script>
+	<script language="javascript" type="text/javascript" src="jscripts/cell.js"></script>
+	<link href="css/cell.css" rel="stylesheet" type="text/css" />
+	<base target="_self" />
+</head>
+<body id="tablecell" onload="tinyMCEPopup.executeOnLoad('init();');" style="display: none">
+	<form onsubmit="updateAction();return false;" action="#">
+		<div class="tabs">
+			<ul>
+				<li id="general_tab" class="current"><span><a href="javascript:mcTabs.displayTab('general_tab','general_panel');" onmousedown="return false;">{$lang_table_general_tab}</a></span></li>
+				<li id="advanced_tab"><span><a href="javascript:mcTabs.displayTab('advanced_tab','advanced_panel');" onmousedown="return false;">{$lang_table_advanced_tab}</a></span></li>
+			</ul>
+		</div>
+
+		<div class="panel_wrapper">
+			<div id="general_panel" class="panel current">
+				<fieldset>
+					<legend>{$lang_table_general_props}</legend>
+
+					<table border="0" cellpadding="4" cellspacing="0">
+						<tr>
+							<td><label for="align">{$lang_table_align}</label></td>
+							<td>
+								<select id="align" name="align">
+									<option value="">{$lang_not_set}</option>
+									<option value="center">{$lang_table_align_middle}</option>
+									<option value="left">{$lang_table_align_left}</option>
+									<option value="right">{$lang_table_align_right}</option>
+								</select>
+							</td>
+		
+							<td><label for="celltype">{$lang_table_cell_type}</label></td>
+							<td>
+								<select id="celltype" name="celltype">
+									<option value="td">{$lang_table_td}</option>
+									<option value="th">{$lang_table_th}</option>
+								</select>
+							</td>
+						</tr>
+
+						<tr>
+							<td><label for="valign">{$lang_table_valign}</label></td>
+							<td>
+								<select id="valign" name="valign">
+									<option value="">{$lang_not_set}</option>
+									<option value="top">{$lang_table_align_top}</option>
+									<option value="middle">{$lang_table_align_middle}</option>
+									<option value="bottom">{$lang_table_align_bottom}</option>
+								</select>
+							</td>
+
+							<td><label for="scope">{$lang_table_scope}</label></td>
+							<td>
+								<select id="scope" name="scope">
+									<option value="">{$lang_not_set}</option>
+									<option value="col">{$lang_table_col}</option>
+									<option value="row">{$lang_table_row}</option>
+									<option value="rowgroup">{$lang_table_rowgroup}</option>
+									<option value="colgroup">{$lang_table_colgroup}</option>
+								</select>
+							</td>
+
+						</tr>
+
+						<tr>
+							<td><label for="width">{$lang_table_width}</label></td>
+							<td><input id="width" name="width" type="text" value="" size="4" maxlength="4" onchange="changedSize();" /></td>
+
+							<td><label for="height">{$lang_table_height}</label></td>
+							<td><input id="height" name="height" type="text" value="" size="4" maxlength="4" onchange="changedSize();" /></td>
+						</tr>
+
+						<tr id="styleSelectRow">
+							<td><label for="class">{$lang_class_name}</label></td>
+							<td colspan="3">
+								<select id="class" name="class">
+									<option value="" selected="selected">{$lang_not_set}</option>
+								</select>
+							</td>
+						</tr>
+					</table>
+				</fieldset>
+			</div>
+
+			<div id="advanced_panel" class="panel">
+				<fieldset>
+					<legend>{$lang_table_advanced_props}</legend>
+
+					<table border="0" cellpadding="0" cellspacing="4">
+						<tr>
+							<td class="column1"><label for="id">{$lang_table_id}</label></td> 
+							<td><input id="id" name="id" type="text" value="" style="width: 200px" /></td> 
+						</tr>
+
+						<tr>
+							<td><label for="style">{$lang_table_style}</label></td>
+							<td><input type="text" id="style" name="style" value="" style="width: 200px;" onchange="changedStyle();" /></td>
+						</tr>
+
+						<tr>
+							<td class="column1"><label for="dir">{$lang_table_langdir}</label></td> 
+							<td>
+								<select id="dir" name="dir" style="width: 200px"> 
+										<option value="">{$lang_not_set}</option> 
+										<option value="ltr">{$lang_table_ltr}</option> 
+										<option value="rtl">{$lang_table_rtl}</option> 
+								</select>
+							</td> 
+						</tr>
+
+						<tr>
+							<td class="column1"><label for="lang">{$lang_table_langcode}</label></td> 
+							<td>
+								<input id="lang" name="lang" type="text" value="" style="width: 200px" />
+							</td> 
+						</tr>
+
+						<tr>
+							<td class="column1"><label for="backgroundimage">{$lang_table_bgimage}</label></td> 
+							<td>
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input id="backgroundimage" name="backgroundimage" type="text" value="" style="width: 200px" onchange="changedBackgroundImage();" /></td>
+										<td id="backgroundimagebrowsercontainer">&nbsp;</td>
+									</tr>
+								</table>
+							</td> 
+						</tr>
+
+						<tr>
+							<td class="column1"><label for="bordercolor">{$lang_table_bordercolor}</label></td> 
+							<td>
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input id="bordercolor" name="bordercolor" type="text" value="" size="9" onchange="updateColor('bordercolor_pick','bordercolor');changedColor();" /></td>
+										<td id="bordercolor_pickcontainer">&nbsp;</td>
+									</tr>
+								</table>
+							</td> 
+						</tr>
+
+						<tr>
+							<td class="column1"><label for="bgcolor">{$lang_table_bgcolor}</label></td> 
+							<td>
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input id="bgcolor" name="bgcolor" type="text" value="" size="9" onchange="updateColor('bgcolor_pick','bgcolor');changedColor();" /></td>
+										<td id="bgcolor_pickcontainer">&nbsp;</td>
+									</tr>
+								</table>
+							</td> 
+						</tr>
+					</table>
+				</fieldset>
+			</div>
+		</div>
+
+		<div class="mceActionPanel">
+			<div>
+				<select id="action" name="action">
+					<option value="cell">{$lang_table_cell_cell}</option>
+					<option value="row">{$lang_table_cell_row}</option>
+					<option value="all">{$lang_table_cell_all}</option>
+				</select>
+			</div>
+
+			<div style="float: left">
+				<div><input type="button" id="insert" name="insert" value="{$lang_update}" onclick="updateAction();" /></div>
+			</div>
+
+			<div style="float: right">
+				<input type="button" id="cancel" name="cancel" value="{$lang_cancel}" onclick="tinyMCEPopup.close();" />
+			</div>
+		</div>
+	</form>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/table/css/cell.css	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,17 @@
+/* CSS file for cell dialog in the table plugin */
+
+.panel_wrapper div.current {
+	height: 200px;
+}
+
+.advfield {
+	width: 200px;
+}
+
+#action {
+	margin-bottom: 3px;
+}
+
+#class {
+	width: 150px;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/table/css/row.css	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,25 @@
+/* CSS file for row dialog in the table plugin */
+
+.panel_wrapper div.current {
+	height: 200px;
+}
+
+.advfield {
+	width: 200px;
+}
+
+#action {
+	margin-bottom: 3px;
+}
+
+#rowtype,#align,#valign,#class,#height {
+	width: 150px;
+}
+
+#height {
+	width: 50px;	
+}
+
+.col2 {
+	padding-left: 20px;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/table/css/table.css	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,13 @@
+/* CSS file for table dialog in the table plugin */
+
+.panel_wrapper div.current {
+	height: 220px;
+}
+
+.advfield {
+	width: 200px;
+}
+
+#class {
+	width: 150px;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/table/editor_plugin.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+tinyMCE.importPluginLanguagePack('table');var TinyMCE_TablePlugin={getInfo:function(){return{longname:'Tables',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/table',version:tinyMCE.majorVersion+"."+tinyMCE.minorVersion}},initInstance:function(inst){if(tinyMCE.isGecko){var doc=inst.getDoc();tinyMCE.addEvent(doc,"mouseup",TinyMCE_TablePlugin._mouseDownHandler)}inst.tableRowClipboard=null},getControlHTML:function(control_name){var controls=new Array(['table','table.gif','lang_table_desc','mceInsertTable',true],['delete_table','table_delete.gif','lang_table_del','mceTableDelete'],['delete_col','table_delete_col.gif','lang_table_delete_col_desc','mceTableDeleteCol'],['delete_row','table_delete_row.gif','lang_table_delete_row_desc','mceTableDeleteRow'],['col_after','table_insert_col_after.gif','lang_table_col_after_desc','mceTableInsertColAfter'],['col_before','table_insert_col_before.gif','lang_table_col_before_desc','mceTableInsertColBefore'],['row_after','table_insert_row_after.gif','lang_table_row_after_desc','mceTableInsertRowAfter'],['row_before','table_insert_row_before.gif','lang_table_row_before_desc','mceTableInsertRowBefore'],['row_props','table_row_props.gif','lang_table_row_desc','mceTableRowProps',true],['cell_props','table_cell_props.gif','lang_table_cell_desc','mceTableCellProps',true],['split_cells','table_split_cells.gif','lang_table_split_cells_desc','mceTableSplitCells',true],['merge_cells','table_merge_cells.gif','lang_table_merge_cells_desc','mceTableMergeCells',true]);for(var i=0;i<controls.length;i++){var but=controls[i];var cmd='tinyMCE.execInstanceCommand(\'{$editor_id}\',\''+but[3]+'\', '+(but.length>4?but[4]:false)+(but.length>5?', \''+but[5]+'\'':'')+');return false;';if(but[0]==control_name)return tinyMCE.getButtonHTML(control_name,but[2],'{$pluginurl}/images/'+but[1],but[3],(but.length>4?but[4]:false))}if(control_name=="tablecontrols"){var html="";html+=tinyMCE.getControlHTML("table");html+=tinyMCE.getControlHTML("separator");html+=tinyMCE.getControlHTML("row_props");html+=tinyMCE.getControlHTML("cell_props");html+=tinyMCE.getControlHTML("separator");html+=tinyMCE.getControlHTML("row_before");html+=tinyMCE.getControlHTML("row_after");html+=tinyMCE.getControlHTML("delete_row");html+=tinyMCE.getControlHTML("separator");html+=tinyMCE.getControlHTML("col_before");html+=tinyMCE.getControlHTML("col_after");html+=tinyMCE.getControlHTML("delete_col");html+=tinyMCE.getControlHTML("separator");html+=tinyMCE.getControlHTML("split_cells");html+=tinyMCE.getControlHTML("merge_cells");return html}return""},execCommand:function(editor_id,element,command,user_interface,value){switch(command){case"mceInsertTable":case"mceTableRowProps":case"mceTableCellProps":case"mceTableSplitCells":case"mceTableMergeCells":case"mceTableInsertRowBefore":case"mceTableInsertRowAfter":case"mceTableDeleteRow":case"mceTableInsertColBefore":case"mceTableInsertColAfter":case"mceTableDeleteCol":case"mceTableCutRow":case"mceTableCopyRow":case"mceTablePasteRowBefore":case"mceTablePasteRowAfter":case"mceTableDelete":var inst=tinyMCE.getInstanceById(editor_id);inst.execCommand('mceBeginUndoLevel');TinyMCE_TablePlugin._doExecCommand(editor_id,element,command,user_interface,value);inst.execCommand('mceEndUndoLevel');return true}return false},handleNodeChange:function(editor_id,node,undo_index,undo_levels,visual_aid,any_selection){var colspan="1",rowspan="1",tdElm;var inst=tinyMCE.getInstanceById(editor_id);tinyMCE.switchClass(editor_id+'_table','mceButtonNormal');tinyMCE.switchClass(editor_id+'_delete_table','mceButtonDisabled');tinyMCE.switchClass(editor_id+'_row_props','mceButtonDisabled');tinyMCE.switchClass(editor_id+'_cell_props','mceButtonDisabled');tinyMCE.switchClass(editor_id+'_row_before','mceButtonDisabled');tinyMCE.switchClass(editor_id+'_row_after','mceButtonDisabled');tinyMCE.switchClass(editor_id+'_delete_row','mceButtonDisabled');tinyMCE.switchClass(editor_id+'_col_before','mceButtonDisabled');tinyMCE.switchClass(editor_id+'_col_after','mceButtonDisabled');tinyMCE.switchClass(editor_id+'_delete_col','mceButtonDisabled');tinyMCE.switchClass(editor_id+'_split_cells','mceButtonDisabled');tinyMCE.switchClass(editor_id+'_merge_cells','mceButtonDisabled');if(tdElm=tinyMCE.getParentElement(node,"td,th")){tinyMCE.switchClass(editor_id+'_cell_props','mceButtonSelected');tinyMCE.switchClass(editor_id+'_delete_table','mceButtonNormal');tinyMCE.switchClass(editor_id+'_row_before','mceButtonNormal');tinyMCE.switchClass(editor_id+'_row_after','mceButtonNormal');tinyMCE.switchClass(editor_id+'_delete_row','mceButtonNormal');tinyMCE.switchClass(editor_id+'_col_before','mceButtonNormal');tinyMCE.switchClass(editor_id+'_col_after','mceButtonNormal');tinyMCE.switchClass(editor_id+'_delete_col','mceButtonNormal');colspan=tinyMCE.getAttrib(tdElm,"colspan");rowspan=tinyMCE.getAttrib(tdElm,"rowspan");colspan=colspan==""?"1":colspan;rowspan=rowspan==""?"1":rowspan;if(colspan!="1"||rowspan!="1")tinyMCE.switchClass(editor_id+'_split_cells','mceButtonNormal')}if(tinyMCE.getParentElement(node,"tr"))tinyMCE.switchClass(editor_id+'_row_props','mceButtonSelected');if(tinyMCE.getParentElement(node,"table")){tinyMCE.switchClass(editor_id+'_table','mceButtonSelected');tinyMCE.switchClass(editor_id+'_merge_cells','mceButtonNormal')}},_mouseDownHandler:function(e){var elm=tinyMCE.isMSIE?event.srcElement:e.target;var focusElm=tinyMCE.selectedInstance.getFocusElement();if(elm.nodeName=="BODY"&&(focusElm.nodeName=="TD"||focusElm.nodeName=="TH"||(focusElm.parentNode&&focusElm.parentNode.nodeName=="TD")||(focusElm.parentNode&&focusElm.parentNode.nodeName=="TH"))){window.setTimeout(function(){var tableElm=tinyMCE.getParentElement(focusElm,"table");tinyMCE.handleVisualAid(tableElm,true,tinyMCE.settings['visual'],tinyMCE.selectedInstance)},10)}},_doExecCommand:function(editor_id,element,command,user_interface,value){var inst=tinyMCE.getInstanceById(editor_id);var focusElm=inst.getFocusElement();var trElm=tinyMCE.getParentElement(focusElm,"tr");var tdElm=tinyMCE.getParentElement(focusElm,"td,th");var tableElm=tinyMCE.getParentElement(focusElm,"table");var doc=inst.contentWindow.document;var tableBorder=tableElm?tableElm.getAttribute("border"):"";if(trElm&&tdElm==null)tdElm=trElm.cells[0];function inArray(ar,v){for(var i=0;i<ar.length;i++){if(ar[i].length>0&&inArray(ar[i],v))return true;if(ar[i]==v)return true}return false}function makeTD(){var newTD=doc.createElement("td");newTD.innerHTML="&nbsp;"}function getColRowSpan(td){var colspan=tinyMCE.getAttrib(td,"colspan");var rowspan=tinyMCE.getAttrib(td,"rowspan");colspan=colspan==""?1:parseInt(colspan);rowspan=rowspan==""?1:parseInt(rowspan);return{colspan:colspan,rowspan:rowspan}}function getCellPos(grid,td){var x,y;for(y=0;y<grid.length;y++){for(x=0;x<grid[y].length;x++){if(grid[y][x]==td)return{cellindex:x,rowindex:y}}}return null}function getCell(grid,row,col){if(grid[row]&&grid[row][col])return grid[row][col];return null}function getTableGrid(table){var grid=new Array(),rows=table.rows,x,y,td,sd,xstart,x2,y2;for(y=0;y<rows.length;y++){for(x=0;x<rows[y].cells.length;x++){td=rows[y].cells[x];sd=getColRowSpan(td);for(xstart=x;grid[y]&&grid[y][xstart];xstart++);for(y2=y;y2<y+sd['rowspan'];y2++){if(!grid[y2])grid[y2]=new Array();for(x2=xstart;x2<xstart+sd['colspan'];x2++)grid[y2][x2]=td}}}return grid}function trimRow(table,tr,td,new_tr){var grid=getTableGrid(table),cpos=getCellPos(grid,td);var cells,lastElm;if(new_tr.cells.length!=tr.childNodes.length){cells=tr.childNodes;lastElm=null;for(var x=0;td=getCell(grid,cpos.rowindex,x);x++){var remove=true;var sd=getColRowSpan(td);if(inArray(cells,td)){new_tr.childNodes[x]._delete=true}else if((lastElm==null||td!=lastElm)&&sd.colspan>1){for(var i=x;i<x+td.colSpan;i++)new_tr.childNodes[i]._delete=true}if((lastElm==null||td!=lastElm)&&sd.rowspan>1)td.rowSpan=sd.rowspan+1;lastElm=td}deleteMarked(tableElm)}}function prevElm(node,name){while((node=node.previousSibling)!=null){if(node.nodeName==name)return node}return null}function nextElm(node,names){var namesAr=names.split(',');while((node=node.nextSibling)!=null){for(var i=0;i<namesAr.length;i++){if(node.nodeName.toLowerCase()==namesAr[i].toLowerCase())return node}}return null}function deleteMarked(tbl){if(tbl.rows==0)return;var tr=tbl.rows[0];do{var next=nextElm(tr,"TR");if(tr._delete){tr.parentNode.removeChild(tr);continue}var td=tr.cells[0];if(td.cells>1){do{var nexttd=nextElm(td,"TD,TH");if(td._delete)td.parentNode.removeChild(td)}while((td=nexttd)!=null)}}while((tr=next)!=null)}function addRows(td_elm,tr_elm,rowspan){td_elm.rowSpan=1;var trNext=nextElm(tr_elm,"TR");for(var i=1;i<rowspan&&trNext;i++){var newTD=doc.createElement("td");newTD.innerHTML="&nbsp;";if(tinyMCE.isMSIE)trNext.insertBefore(newTD,trNext.cells(td_elm.cellIndex));else trNext.insertBefore(newTD,trNext.cells[td_elm.cellIndex]);trNext=nextElm(trNext,"TR")}}function copyRow(doc,table,tr){var grid=getTableGrid(table);var newTR=tr.cloneNode(false);var cpos=getCellPos(grid,tr.cells[0]);var lastCell=null;var tableBorder=tinyMCE.getAttrib(table,"border");var tdElm=null;for(var x=0;tdElm=getCell(grid,cpos.rowindex,x);x++){var newTD=null;if(lastCell!=tdElm){for(var i=0;i<tr.cells.length;i++){if(tdElm==tr.cells[i]){newTD=tdElm.cloneNode(true);break}}}if(newTD==null){newTD=doc.createElement("td");newTD.innerHTML="&nbsp;"}newTD.colSpan=1;newTD.rowSpan=1;newTR.appendChild(newTD);lastCell=tdElm}return newTR}switch(command){case"mceTableRowProps":if(trElm==null)return true;if(user_interface){var template=new Array();template['file']='../../plugins/table/row.htm';template['width']=380;template['height']=295;template['width']+=tinyMCE.getLang('lang_table_rowprops_delta_width',0);template['height']+=tinyMCE.getLang('lang_table_rowprops_delta_height',0);tinyMCE.openWindow(template,{editor_id:inst.editorId,inline:"yes"})}return true;case"mceTableCellProps":if(tdElm==null)return true;if(user_interface){var template=new Array();template['file']='../../plugins/table/cell.htm';template['width']=380;template['height']=295;template['width']+=tinyMCE.getLang('lang_table_cellprops_delta_width',0);template['height']+=tinyMCE.getLang('lang_table_cellprops_delta_height',0);tinyMCE.openWindow(template,{editor_id:inst.editorId,inline:"yes"})}return true;case"mceInsertTable":if(user_interface){var template=new Array();template['file']='../../plugins/table/table.htm';template['width']=380;template['height']=295;template['width']+=tinyMCE.getLang('lang_table_table_delta_width',0);template['height']+=tinyMCE.getLang('lang_table_table_delta_height',0);tinyMCE.openWindow(template,{editor_id:inst.editorId,inline:"yes",action:value})}return true;case"mceTableDelete":var table=tinyMCE.getParentElement(inst.getFocusElement(),"table");if(table){table.parentNode.removeChild(table);inst.repaint()}return true;case"mceTableSplitCells":case"mceTableMergeCells":case"mceTableInsertRowBefore":case"mceTableInsertRowAfter":case"mceTableDeleteRow":case"mceTableInsertColBefore":case"mceTableInsertColAfter":case"mceTableDeleteCol":case"mceTableCutRow":case"mceTableCopyRow":case"mceTablePasteRowBefore":case"mceTablePasteRowAfter":if(!tableElm)return true;if(trElm&&tableElm!=trElm.parentNode)tableElm=trElm.parentNode;if(tableElm&&trElm){switch(command){case"mceTableCutRow":if(!trElm||!tdElm)return true;inst.tableRowClipboard=copyRow(doc,tableElm,trElm);inst.execCommand("mceTableDeleteRow");break;case"mceTableCopyRow":if(!trElm||!tdElm)return true;inst.tableRowClipboard=copyRow(doc,tableElm,trElm);break;case"mceTablePasteRowBefore":if(!trElm||!tdElm)return true;var newTR=inst.tableRowClipboard.cloneNode(true);var prevTR=prevElm(trElm,"TR");if(prevTR!=null)trimRow(tableElm,prevTR,prevTR.cells[0],newTR);trElm.parentNode.insertBefore(newTR,trElm);break;case"mceTablePasteRowAfter":if(!trElm||!tdElm)return true;var nextTR=nextElm(trElm,"TR");var newTR=inst.tableRowClipboard.cloneNode(true);trimRow(tableElm,trElm,tdElm,newTR);if(nextTR==null)trElm.parentNode.appendChild(newTR);else nextTR.parentNode.insertBefore(newTR,nextTR);break;case"mceTableInsertRowBefore":if(!trElm||!tdElm)return true;var grid=getTableGrid(tableElm);var cpos=getCellPos(grid,tdElm);var newTR=doc.createElement("tr");var lastTDElm=null;cpos.rowindex--;if(cpos.rowindex<0)cpos.rowindex=0;for(var x=0;tdElm=getCell(grid,cpos.rowindex,x);x++){if(tdElm!=lastTDElm){var sd=getColRowSpan(tdElm);if(sd['rowspan']==1){var newTD=doc.createElement("td");newTD.innerHTML="&nbsp;";newTD.colSpan=tdElm.colSpan;newTR.appendChild(newTD)}else tdElm.rowSpan=sd['rowspan']+1;lastTDElm=tdElm}}trElm.parentNode.insertBefore(newTR,trElm);grid=getTableGrid(tableElm);inst.selection.selectNode(getCell(grid,cpos.rowindex+1,cpos.cellindex),tinyMCE.isGecko,true);break;case"mceTableInsertRowAfter":if(!trElm||!tdElm)return true;var grid=getTableGrid(tableElm);var cpos=getCellPos(grid,tdElm);var newTR=doc.createElement("tr");var lastTDElm=null;for(var x=0;tdElm=getCell(grid,cpos.rowindex,x);x++){if(tdElm!=lastTDElm){var sd=getColRowSpan(tdElm);if(sd['rowspan']==1){var newTD=doc.createElement("td");newTD.innerHTML="&nbsp;";newTD.colSpan=tdElm.colSpan;newTR.appendChild(newTD)}else tdElm.rowSpan=sd['rowspan']+1;lastTDElm=tdElm}}if(newTR.hasChildNodes()){var nextTR=nextElm(trElm,"TR");if(nextTR)nextTR.parentNode.insertBefore(newTR,nextTR);else tableElm.appendChild(newTR)}grid=getTableGrid(tableElm);inst.selection.selectNode(getCell(grid,cpos.rowindex,cpos.cellindex),tinyMCE.isGecko,true);break;case"mceTableDeleteRow":if(!trElm||!tdElm)return true;var grid=getTableGrid(tableElm);var cpos=getCellPos(grid,tdElm);if(grid.length==1){tableElm=tinyMCE.getParentElement(tableElm,"table");tableElm.parentNode.removeChild(tableElm);return true}var cells=trElm.cells;var nextTR=nextElm(trElm,"TR");for(var x=0;x<cells.length;x++){if(cells[x].rowSpan>1){var newTD=cells[x].cloneNode(true);var sd=getColRowSpan(cells[x]);newTD.rowSpan=sd.rowspan-1;var nextTD=nextTR.cells[x];if(nextTD==null)nextTR.appendChild(newTD);else nextTR.insertBefore(newTD,nextTD)}}var lastTDElm=null;for(var x=0;tdElm=getCell(grid,cpos.rowindex,x);x++){if(tdElm!=lastTDElm){var sd=getColRowSpan(tdElm);if(sd.rowspan>1){tdElm.rowSpan=sd.rowspan-1}else{trElm=tdElm.parentNode;if(trElm.parentNode)trElm._delete=true}lastTDElm=tdElm}}deleteMarked(tableElm);cpos.rowindex--;if(cpos.rowindex<0)cpos.rowindex=0;grid=getTableGrid(tableElm);inst.selection.selectNode(getCell(grid,cpos.rowindex,0),tinyMCE.isGecko,true);break;case"mceTableInsertColBefore":if(!trElm||!tdElm)return true;var grid=getTableGrid(tableElm);var cpos=getCellPos(grid,tdElm);var lastTDElm=null;for(var y=0;tdElm=getCell(grid,y,cpos.cellindex);y++){if(tdElm!=lastTDElm){var sd=getColRowSpan(tdElm);if(sd['colspan']==1){var newTD=doc.createElement(tdElm.nodeName);newTD.innerHTML="&nbsp;";newTD.rowSpan=tdElm.rowSpan;tdElm.parentNode.insertBefore(newTD,tdElm)}else tdElm.colSpan++;lastTDElm=tdElm}}grid=getTableGrid(tableElm);inst.selection.selectNode(getCell(grid,cpos.rowindex,cpos.cellindex+1),tinyMCE.isGecko,true);break;case"mceTableInsertColAfter":if(!trElm||!tdElm)return true;var grid=getTableGrid(tableElm);var cpos=getCellPos(grid,tdElm);var lastTDElm=null;for(var y=0;tdElm=getCell(grid,y,cpos.cellindex);y++){if(tdElm!=lastTDElm){var sd=getColRowSpan(tdElm);if(sd['colspan']==1){var newTD=doc.createElement(tdElm.nodeName);newTD.innerHTML="&nbsp;";newTD.rowSpan=tdElm.rowSpan;var nextTD=nextElm(tdElm,"TD,TH");if(nextTD==null)tdElm.parentNode.appendChild(newTD);else nextTD.parentNode.insertBefore(newTD,nextTD)}else tdElm.colSpan++;lastTDElm=tdElm}}grid=getTableGrid(tableElm);inst.selection.selectNode(getCell(grid,cpos.rowindex,cpos.cellindex),tinyMCE.isGecko,true);break;case"mceTableDeleteCol":if(!trElm||!tdElm)return true;var grid=getTableGrid(tableElm);var cpos=getCellPos(grid,tdElm);var lastTDElm=null;if(grid.length>1&&grid[0].length<=1){tableElm=tinyMCE.getParentElement(tableElm,"table");tableElm.parentNode.removeChild(tableElm);return true}for(var y=0;tdElm=getCell(grid,y,cpos.cellindex);y++){if(tdElm!=lastTDElm){var sd=getColRowSpan(tdElm);if(sd['colspan']>1)tdElm.colSpan=sd['colspan']-1;else{if(tdElm.parentNode)tdElm.parentNode.removeChild(tdElm)}lastTDElm=tdElm}}cpos.cellindex--;if(cpos.cellindex<0)cpos.cellindex=0;grid=getTableGrid(tableElm);inst.selection.selectNode(getCell(grid,cpos.rowindex,0),tinyMCE.isGecko,true);break;case"mceTableSplitCells":if(!trElm||!tdElm)return true;var spandata=getColRowSpan(tdElm);var colspan=spandata["colspan"];var rowspan=spandata["rowspan"];if(colspan>1||rowspan>1){tdElm.colSpan=1;for(var i=1;i<colspan;i++){var newTD=doc.createElement("td");newTD.innerHTML="&nbsp;";trElm.insertBefore(newTD,nextElm(tdElm,"TD,TH"));if(rowspan>1)addRows(newTD,trElm,rowspan)}addRows(tdElm,trElm,rowspan)}tableElm=tinyMCE.getParentElement(inst.getFocusElement(),"table");break;case"mceTableMergeCells":var rows=new Array();var sel=inst.getSel();var grid=getTableGrid(tableElm);if(tinyMCE.isMSIE||sel.rangeCount==1){if(user_interface){var template=new Array();var sp=getColRowSpan(tdElm);template['file']='../../plugins/table/merge_cells.htm';template['width']=250;template['height']=105+(tinyMCE.isNS7?25:0);template['width']+=tinyMCE.getLang('lang_table_merge_cells_delta_width',0);template['height']+=tinyMCE.getLang('lang_table_merge_cells_delta_height',0);tinyMCE.openWindow(template,{editor_id:inst.editorId,inline:"yes",action:"update",numcols:sp.colspan,numrows:sp.rowspan});return true}else{var numRows=parseInt(value['numrows']);var numCols=parseInt(value['numcols']);var cpos=getCellPos(grid,tdElm);if((""+numRows)=="NaN")numRows=1;if((""+numCols)=="NaN")numCols=1;var tRows=tableElm.rows;for(var y=cpos.rowindex;y<grid.length;y++){var rowCells=new Array();for(var x=cpos.cellindex;x<grid[y].length;x++){var td=getCell(grid,y,x);if(td&&!inArray(rows,td)&&!inArray(rowCells,td)){var cp=getCellPos(grid,td);if(cp.cellindex<cpos.cellindex+numCols&&cp.rowindex<cpos.rowindex+numRows)rowCells[rowCells.length]=td}}if(rowCells.length>0)rows[rows.length]=rowCells}}}else{var cells=new Array();var sel=inst.getSel();var lastTR=null;var curRow=null;var x1=-1,y1=-1,x2,y2;if(sel.rangeCount<2)return true;for(var i=0;i<sel.rangeCount;i++){var rng=sel.getRangeAt(i);var tdElm=rng.startContainer.childNodes[rng.startOffset];if(!tdElm)break;if(tdElm.nodeName=="TD")cells[cells.length]=tdElm}var tRows=tableElm.rows;for(var y=0;y<tRows.length;y++){var rowCells=new Array();for(var x=0;x<tRows[y].cells.length;x++){var td=tRows[y].cells[x];for(var i=0;i<cells.length;i++){if(td==cells[i]){rowCells[rowCells.length]=td}}}if(rowCells.length>0)rows[rows.length]=rowCells}var curRow=new Array();var lastTR=null;for(var y=0;y<grid.length;y++){for(var x=0;x<grid[y].length;x++){grid[y][x]._selected=false;for(var i=0;i<cells.length;i++){if(grid[y][x]==cells[i]){if(x1==-1){x1=x;y1=y}x2=x;y2=y;grid[y][x]._selected=true}}}}for(var y=y1;y<=y2;y++){for(var x=x1;x<=x2;x++){if(!grid[y][x]._selected){alert("Invalid selection for merge.");return true}}}}var rowSpan=1,colSpan=1;var lastRowSpan=-1;for(var y=0;y<rows.length;y++){var rowColSpan=0;for(var x=0;x<rows[y].length;x++){var sd=getColRowSpan(rows[y][x]);rowColSpan+=sd['colspan'];if(lastRowSpan!=-1&&sd['rowspan']!=lastRowSpan){alert("Invalid selection for merge.");return true}lastRowSpan=sd['rowspan']}if(rowColSpan>colSpan)colSpan=rowColSpan;lastRowSpan=-1}var lastColSpan=-1;for(var x=0;x<rows[0].length;x++){var colRowSpan=0;for(var y=0;y<rows.length;y++){var sd=getColRowSpan(rows[y][x]);colRowSpan+=sd['rowspan'];if(lastColSpan!=-1&&sd['colspan']!=lastColSpan){alert("Invalid selection for merge.");return true}lastColSpan=sd['colspan']}if(colRowSpan>rowSpan)rowSpan=colRowSpan;lastColSpan=-1}tdElm=rows[0][0];tdElm.rowSpan=rowSpan;tdElm.colSpan=colSpan;for(var y=0;y<rows.length;y++){for(var x=0;x<rows[y].length;x++){var html=rows[y][x].innerHTML;var chk=tinyMCE.regexpReplace(html,"[ \t\r\n]","");if(chk!="<br/>"&&chk!="<br>"&&chk!="&nbsp;"&&(x+y>0))tdElm.innerHTML+=html;if(rows[y][x]!=tdElm&&!rows[y][x]._deleted){var cpos=getCellPos(grid,rows[y][x]);var tr=rows[y][x].parentNode;tr.removeChild(rows[y][x]);rows[y][x]._deleted=true;if(!tr.hasChildNodes()){tr.parentNode.removeChild(tr);var lastCell=null;for(var x=0;cellElm=getCell(grid,cpos.rowindex,x);x++){if(cellElm!=lastCell&&cellElm.rowSpan>1)cellElm.rowSpan--;lastCell=cellElm}if(tdElm.rowSpan>1)tdElm.rowSpan--}}}}break}tableElm=tinyMCE.getParentElement(inst.getFocusElement(),"table");tinyMCE.handleVisualAid(tableElm,true,tinyMCE.settings['visual'],tinyMCE.selectedInstance);tinyMCE.triggerNodeChange();inst.repaint()}return true}return false}};tinyMCE.addPlugin("table",TinyMCE_TablePlugin);
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/table/editor_plugin_src.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1073 @@
+/**
+ * $Id: editor_plugin_src.js 201 2007-02-12 15:56:56Z spocke $
+ *
+ * @author Moxiecode
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+/* Import plugin specific language pack */
+tinyMCE.importPluginLanguagePack('table');
+
+var TinyMCE_TablePlugin = {
+	getInfo : function() {
+		return {
+			longname : 'Tables',
+			author : 'Moxiecode Systems AB',
+			authorurl : 'http://tinymce.moxiecode.com',
+			infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/table',
+			version : tinyMCE.majorVersion + "." + tinyMCE.minorVersion
+		};
+	},
+
+	initInstance : function(inst) {
+		if (tinyMCE.isGecko) {
+			var doc = inst.getDoc();
+			tinyMCE.addEvent(doc, "mouseup", TinyMCE_TablePlugin._mouseDownHandler);
+		}
+
+		inst.tableRowClipboard = null;
+	},
+
+	/**
+	 * Returns the HTML contents of the table control.
+	 */
+	getControlHTML : function(control_name) {
+		var controls = new Array(
+			['table', 'table.gif', 'lang_table_desc', 'mceInsertTable', true],
+			['delete_table', 'table_delete.gif', 'lang_table_del', 'mceTableDelete'],
+			['delete_col', 'table_delete_col.gif', 'lang_table_delete_col_desc', 'mceTableDeleteCol'],
+			['delete_row', 'table_delete_row.gif', 'lang_table_delete_row_desc', 'mceTableDeleteRow'],
+			['col_after', 'table_insert_col_after.gif', 'lang_table_col_after_desc', 'mceTableInsertColAfter'],
+			['col_before', 'table_insert_col_before.gif', 'lang_table_col_before_desc', 'mceTableInsertColBefore'],
+			['row_after', 'table_insert_row_after.gif', 'lang_table_row_after_desc', 'mceTableInsertRowAfter'],
+			['row_before', 'table_insert_row_before.gif', 'lang_table_row_before_desc', 'mceTableInsertRowBefore'],
+			['row_props', 'table_row_props.gif', 'lang_table_row_desc', 'mceTableRowProps', true],
+			['cell_props', 'table_cell_props.gif', 'lang_table_cell_desc', 'mceTableCellProps', true],
+			['split_cells', 'table_split_cells.gif', 'lang_table_split_cells_desc', 'mceTableSplitCells', true],
+			['merge_cells', 'table_merge_cells.gif', 'lang_table_merge_cells_desc', 'mceTableMergeCells', true]);
+
+		// Render table control
+		for (var i=0; i<controls.length; i++) {
+			var but = controls[i];
+			var cmd = 'tinyMCE.execInstanceCommand(\'{$editor_id}\',\'' + but[3] + '\', ' + (but.length > 4 ? but[4] : false) + (but.length > 5 ? ', \'' + but[5] + '\'' : '') + ');return false;';
+
+			if (but[0] == control_name)
+				return tinyMCE.getButtonHTML(control_name, but[2], '{$pluginurl}/images/'+ but[1], but[3], (but.length > 4 ? but[4] : false));
+		}
+
+		// Special tablecontrols
+		if (control_name == "tablecontrols") {
+			var html = "";
+
+			html += tinyMCE.getControlHTML("table");
+			html += tinyMCE.getControlHTML("separator");
+			html += tinyMCE.getControlHTML("row_props");
+			html += tinyMCE.getControlHTML("cell_props");
+			html += tinyMCE.getControlHTML("separator");
+			html += tinyMCE.getControlHTML("row_before");
+			html += tinyMCE.getControlHTML("row_after");
+			html += tinyMCE.getControlHTML("delete_row");
+			html += tinyMCE.getControlHTML("separator");
+			html += tinyMCE.getControlHTML("col_before");
+			html += tinyMCE.getControlHTML("col_after");
+			html += tinyMCE.getControlHTML("delete_col");
+			html += tinyMCE.getControlHTML("separator");
+			html += tinyMCE.getControlHTML("split_cells");
+			html += tinyMCE.getControlHTML("merge_cells");
+
+			return html;
+		}
+
+		return "";
+	},
+
+	/**
+	 * Executes the table commands.
+	 */
+	execCommand : function(editor_id, element, command, user_interface, value) {
+		// Is table command
+		switch (command) {
+			case "mceInsertTable":
+			case "mceTableRowProps":
+			case "mceTableCellProps":
+			case "mceTableSplitCells":
+			case "mceTableMergeCells":
+			case "mceTableInsertRowBefore":
+			case "mceTableInsertRowAfter":
+			case "mceTableDeleteRow":
+			case "mceTableInsertColBefore":
+			case "mceTableInsertColAfter":
+			case "mceTableDeleteCol":
+			case "mceTableCutRow":
+			case "mceTableCopyRow":
+			case "mceTablePasteRowBefore":
+			case "mceTablePasteRowAfter":
+			case "mceTableDelete":
+				var inst = tinyMCE.getInstanceById(editor_id);
+
+				inst.execCommand('mceBeginUndoLevel');
+				TinyMCE_TablePlugin._doExecCommand(editor_id, element, command, user_interface, value);
+				inst.execCommand('mceEndUndoLevel');
+
+				return true;
+		}
+
+		// Pass to next handler in chain
+		return false;
+	},
+
+	handleNodeChange : function(editor_id, node, undo_index, undo_levels, visual_aid, any_selection) {
+		var colspan = "1", rowspan = "1", tdElm;
+
+		var inst = tinyMCE.getInstanceById(editor_id);
+
+		// Reset table controls
+		tinyMCE.switchClass(editor_id + '_table', 'mceButtonNormal');
+		tinyMCE.switchClass(editor_id + '_delete_table', 'mceButtonDisabled');
+		tinyMCE.switchClass(editor_id + '_row_props', 'mceButtonDisabled');
+		tinyMCE.switchClass(editor_id + '_cell_props', 'mceButtonDisabled');
+		tinyMCE.switchClass(editor_id + '_row_before', 'mceButtonDisabled');
+		tinyMCE.switchClass(editor_id + '_row_after', 'mceButtonDisabled');
+		tinyMCE.switchClass(editor_id + '_delete_row', 'mceButtonDisabled');
+		tinyMCE.switchClass(editor_id + '_col_before', 'mceButtonDisabled');
+		tinyMCE.switchClass(editor_id + '_col_after', 'mceButtonDisabled');
+		tinyMCE.switchClass(editor_id + '_delete_col', 'mceButtonDisabled');
+		tinyMCE.switchClass(editor_id + '_split_cells', 'mceButtonDisabled');
+		tinyMCE.switchClass(editor_id + '_merge_cells', 'mceButtonDisabled');
+
+		// Within a td element
+		if (tdElm = tinyMCE.getParentElement(node, "td,th")) {
+			tinyMCE.switchClass(editor_id + '_cell_props', 'mceButtonSelected');
+			tinyMCE.switchClass(editor_id + '_delete_table', 'mceButtonNormal');
+			tinyMCE.switchClass(editor_id + '_row_before', 'mceButtonNormal');
+			tinyMCE.switchClass(editor_id + '_row_after', 'mceButtonNormal');
+			tinyMCE.switchClass(editor_id + '_delete_row', 'mceButtonNormal');
+			tinyMCE.switchClass(editor_id + '_col_before', 'mceButtonNormal');
+			tinyMCE.switchClass(editor_id + '_col_after', 'mceButtonNormal');
+			tinyMCE.switchClass(editor_id + '_delete_col', 'mceButtonNormal');
+
+			colspan = tinyMCE.getAttrib(tdElm, "colspan");
+			rowspan = tinyMCE.getAttrib(tdElm, "rowspan");
+
+			colspan = colspan == "" ? "1" : colspan;
+			rowspan = rowspan == "" ? "1" : rowspan;
+
+			if (colspan != "1" || rowspan != "1")
+				tinyMCE.switchClass(editor_id + '_split_cells', 'mceButtonNormal');
+		}
+
+		// Within a tr element
+		if (tinyMCE.getParentElement(node, "tr"))
+			tinyMCE.switchClass(editor_id + '_row_props', 'mceButtonSelected');
+
+		// Within table
+		if (tinyMCE.getParentElement(node, "table")) {
+			tinyMCE.switchClass(editor_id + '_table', 'mceButtonSelected');
+			tinyMCE.switchClass(editor_id + '_merge_cells', 'mceButtonNormal');
+		}
+	},
+
+	// Private plugin internal methods
+
+	_mouseDownHandler : function(e) {
+		var elm = tinyMCE.isMSIE ? event.srcElement : e.target;
+		var focusElm = tinyMCE.selectedInstance.getFocusElement();
+
+		// If press on special Mozilla create TD/TR thingie
+		if (elm.nodeName == "BODY" && (focusElm.nodeName == "TD" || focusElm.nodeName == "TH" || (focusElm.parentNode && focusElm.parentNode.nodeName == "TD") ||(focusElm.parentNode && focusElm.parentNode.nodeName == "TH") )) {
+			window.setTimeout(function() {
+				var tableElm = tinyMCE.getParentElement(focusElm, "table");
+				tinyMCE.handleVisualAid(tableElm, true, tinyMCE.settings['visual'], tinyMCE.selectedInstance);
+			}, 10);
+		}
+	},
+
+	/**
+	 * Executes the table commands.
+	 */
+	_doExecCommand : function(editor_id, element, command, user_interface, value) {
+		var inst = tinyMCE.getInstanceById(editor_id);
+		var focusElm = inst.getFocusElement();
+		var trElm = tinyMCE.getParentElement(focusElm, "tr");
+		var tdElm = tinyMCE.getParentElement(focusElm, "td,th");
+		var tableElm = tinyMCE.getParentElement(focusElm, "table");
+		var doc = inst.contentWindow.document;
+		var tableBorder = tableElm ? tableElm.getAttribute("border") : "";
+
+		// Get first TD if no TD found
+		if (trElm && tdElm == null)
+			tdElm = trElm.cells[0];
+
+		// ------- Inner functions ---------
+		function inArray(ar, v) {
+			for (var i=0; i<ar.length; i++) {
+				// Is array
+				if (ar[i].length > 0 && inArray(ar[i], v))
+					return true;
+
+				// Found value
+				if (ar[i] == v)
+					return true;
+			}
+
+			return false;
+		}
+
+		function makeTD() {
+			var newTD = doc.createElement("td");
+			newTD.innerHTML = "&nbsp;";
+		}
+
+		function getColRowSpan(td) {
+			var colspan = tinyMCE.getAttrib(td, "colspan");
+			var rowspan = tinyMCE.getAttrib(td, "rowspan");
+
+			colspan = colspan == "" ? 1 : parseInt(colspan);
+			rowspan = rowspan == "" ? 1 : parseInt(rowspan);
+
+			return {colspan : colspan, rowspan : rowspan};
+		}
+
+		function getCellPos(grid, td) {
+			var x, y;
+
+			for (y=0; y<grid.length; y++) {
+				for (x=0; x<grid[y].length; x++) {
+					if (grid[y][x] == td)
+						return {cellindex : x, rowindex : y};
+				}
+			}
+
+			return null;
+		}
+
+		function getCell(grid, row, col) {
+			if (grid[row] && grid[row][col])
+				return grid[row][col];
+
+			return null;
+		}
+
+		function getTableGrid(table) {
+			var grid = new Array(), rows = table.rows, x, y, td, sd, xstart, x2, y2;
+
+			for (y=0; y<rows.length; y++) {
+				for (x=0; x<rows[y].cells.length; x++) {
+					td = rows[y].cells[x];
+					sd = getColRowSpan(td);
+
+					// All ready filled
+					for (xstart = x; grid[y] && grid[y][xstart]; xstart++) ;
+
+					// Fill box
+					for (y2=y; y2<y+sd['rowspan']; y2++) {
+						if (!grid[y2])
+							grid[y2] = new Array();
+
+						for (x2=xstart; x2<xstart+sd['colspan']; x2++)
+							grid[y2][x2] = td;
+					}
+				}
+			}
+
+			return grid;
+		}
+
+		function trimRow(table, tr, td, new_tr) {
+			var grid = getTableGrid(table), cpos = getCellPos(grid, td);
+			var cells, lastElm;
+
+			// Time to crop away some
+			if (new_tr.cells.length != tr.childNodes.length) {
+				cells = tr.childNodes;
+				lastElm = null;
+
+				for (var x=0; td = getCell(grid, cpos.rowindex, x); x++) {
+					var remove = true;
+					var sd = getColRowSpan(td);
+
+					// Remove due to rowspan
+					if (inArray(cells, td)) {
+						new_tr.childNodes[x]._delete = true;
+					} else if ((lastElm == null || td != lastElm) && sd.colspan > 1) { // Remove due to colspan
+						for (var i=x; i<x+td.colSpan; i++)
+							new_tr.childNodes[i]._delete = true;
+					}
+
+					if ((lastElm == null || td != lastElm) && sd.rowspan > 1)
+						td.rowSpan = sd.rowspan + 1;
+
+					lastElm = td;
+				}
+
+				deleteMarked(tableElm);
+			}
+		}
+
+		function prevElm(node, name) {
+			while ((node = node.previousSibling) != null) {
+				if (node.nodeName == name)
+					return node;
+			}
+
+			return null;
+		}
+
+		function nextElm(node, names) {
+			var namesAr = names.split(',');
+
+			while ((node = node.nextSibling) != null) {
+				for (var i=0; i<namesAr.length; i++) {
+					if (node.nodeName.toLowerCase() == namesAr[i].toLowerCase() )
+						return node;
+				}
+			}
+
+			return null;
+		}
+
+		function deleteMarked(tbl) {
+			if (tbl.rows == 0)
+				return;
+
+			var tr = tbl.rows[0];
+			do {
+				var next = nextElm(tr, "TR");
+
+				// Delete row
+				if (tr._delete) {
+					tr.parentNode.removeChild(tr);
+					continue;
+				}
+
+				// Delete cells
+				var td = tr.cells[0];
+				if (td.cells > 1) {
+					do {
+						var nexttd = nextElm(td, "TD,TH");
+
+						if (td._delete)
+							td.parentNode.removeChild(td);
+					} while ((td = nexttd) != null);
+				}
+			} while ((tr = next) != null);
+		}
+
+		function addRows(td_elm, tr_elm, rowspan) {
+			// Add rows
+			td_elm.rowSpan = 1;
+			var trNext = nextElm(tr_elm, "TR");
+			for (var i=1; i<rowspan && trNext; i++) {
+				var newTD = doc.createElement("td");
+				newTD.innerHTML = "&nbsp;";
+
+				if (tinyMCE.isMSIE)
+					trNext.insertBefore(newTD, trNext.cells(td_elm.cellIndex));
+				else
+					trNext.insertBefore(newTD, trNext.cells[td_elm.cellIndex]);
+
+				trNext = nextElm(trNext, "TR");
+			}
+		}
+
+		function copyRow(doc, table, tr) {
+			var grid = getTableGrid(table);
+			var newTR = tr.cloneNode(false);
+			var cpos = getCellPos(grid, tr.cells[0]);
+			var lastCell = null;
+			var tableBorder = tinyMCE.getAttrib(table, "border");
+			var tdElm = null;
+
+			for (var x=0; tdElm = getCell(grid, cpos.rowindex, x); x++) {
+				var newTD = null;
+
+				if (lastCell != tdElm) {
+					for (var i=0; i<tr.cells.length; i++) {
+						if (tdElm == tr.cells[i]) {
+							newTD = tdElm.cloneNode(true);
+							break;
+						}
+					}
+				}
+
+				if (newTD == null) {
+					newTD = doc.createElement("td");
+					newTD.innerHTML = "&nbsp;";
+				}
+
+				// Reset col/row span
+				newTD.colSpan = 1;
+				newTD.rowSpan = 1;
+
+				newTR.appendChild(newTD);
+
+				lastCell = tdElm;
+			}
+
+			return newTR;
+		}
+
+		// ---- Commands -----
+
+		// Handle commands
+		switch (command) {
+			case "mceTableRowProps":
+				if (trElm == null)
+					return true;
+
+				if (user_interface) {
+					// Setup template
+					var template = new Array();
+
+					template['file'] = '../../plugins/table/row.htm';
+					template['width'] = 380;
+					template['height'] = 295;
+
+					// Language specific width and height addons
+					template['width'] += tinyMCE.getLang('lang_table_rowprops_delta_width', 0);
+					template['height'] += tinyMCE.getLang('lang_table_rowprops_delta_height', 0);
+
+					// Open window
+					tinyMCE.openWindow(template, {editor_id : inst.editorId, inline : "yes"});
+				}
+
+				return true;
+
+			case "mceTableCellProps":
+				if (tdElm == null)
+					return true;
+
+				if (user_interface) {
+					// Setup template
+					var template = new Array();
+
+					template['file'] = '../../plugins/table/cell.htm';
+					template['width'] = 380;
+					template['height'] = 295;
+
+					// Language specific width and height addons
+					template['width'] += tinyMCE.getLang('lang_table_cellprops_delta_width', 0);
+					template['height'] += tinyMCE.getLang('lang_table_cellprops_delta_height', 0);
+
+					// Open window
+					tinyMCE.openWindow(template, {editor_id : inst.editorId, inline : "yes"});
+				}
+
+				return true;
+
+			case "mceInsertTable":
+				if (user_interface) {
+					// Setup template
+					var template = new Array();
+
+					template['file'] = '../../plugins/table/table.htm';
+					template['width'] = 380;
+					template['height'] = 295;
+
+					// Language specific width and height addons
+					template['width'] += tinyMCE.getLang('lang_table_table_delta_width', 0);
+					template['height'] += tinyMCE.getLang('lang_table_table_delta_height', 0);
+
+					// Open window
+					tinyMCE.openWindow(template, {editor_id : inst.editorId, inline : "yes", action : value});
+				}
+
+				return true;
+
+			case "mceTableDelete":
+				var table = tinyMCE.getParentElement(inst.getFocusElement(), "table");
+				if (table) {
+					table.parentNode.removeChild(table);
+					inst.repaint();
+				}
+				return true;
+
+			case "mceTableSplitCells":
+			case "mceTableMergeCells":
+			case "mceTableInsertRowBefore":
+			case "mceTableInsertRowAfter":
+			case "mceTableDeleteRow":
+			case "mceTableInsertColBefore":
+			case "mceTableInsertColAfter":
+			case "mceTableDeleteCol":
+			case "mceTableCutRow":
+			case "mceTableCopyRow":
+			case "mceTablePasteRowBefore":
+			case "mceTablePasteRowAfter":
+				// No table just return (invalid command)
+				if (!tableElm)
+					return true;
+
+				// Table has a tbody use that reference
+				// Changed logic by ApTest 2005.07.12 (www.aptest.com)
+				// Now lookk at the focused element and take its parentNode.  That will be a tbody or a table.
+				if (trElm && tableElm != trElm.parentNode)
+					tableElm = trElm.parentNode;
+
+				if (tableElm && trElm) {
+					switch (command) {
+						case "mceTableCutRow":
+							if (!trElm || !tdElm)
+								return true;
+
+							inst.tableRowClipboard = copyRow(doc, tableElm, trElm);
+							inst.execCommand("mceTableDeleteRow");
+							break;
+
+						case "mceTableCopyRow":
+							if (!trElm || !tdElm)
+								return true;
+
+							inst.tableRowClipboard = copyRow(doc, tableElm, trElm);
+							break;
+
+						case "mceTablePasteRowBefore":
+							if (!trElm || !tdElm)
+								return true;
+
+							var newTR = inst.tableRowClipboard.cloneNode(true);
+
+							var prevTR = prevElm(trElm, "TR");
+							if (prevTR != null)
+								trimRow(tableElm, prevTR, prevTR.cells[0], newTR);
+
+							trElm.parentNode.insertBefore(newTR, trElm);
+							break;
+
+						case "mceTablePasteRowAfter":
+							if (!trElm || !tdElm)
+								return true;
+							
+							var nextTR = nextElm(trElm, "TR");
+							var newTR = inst.tableRowClipboard.cloneNode(true);
+
+							trimRow(tableElm, trElm, tdElm, newTR);
+
+							if (nextTR == null)
+								trElm.parentNode.appendChild(newTR);
+							else
+								nextTR.parentNode.insertBefore(newTR, nextTR);
+
+							break;
+
+						case "mceTableInsertRowBefore":
+							if (!trElm || !tdElm)
+								return true;
+
+							var grid = getTableGrid(tableElm);
+							var cpos = getCellPos(grid, tdElm);
+							var newTR = doc.createElement("tr");
+							var lastTDElm = null;
+
+							cpos.rowindex--;
+							if (cpos.rowindex < 0)
+								cpos.rowindex = 0;
+
+							// Create cells
+							for (var x=0; tdElm = getCell(grid, cpos.rowindex, x); x++) {
+								if (tdElm != lastTDElm) {
+									var sd = getColRowSpan(tdElm);
+
+									if (sd['rowspan'] == 1) {
+										var newTD = doc.createElement("td");
+
+										newTD.innerHTML = "&nbsp;";
+										newTD.colSpan = tdElm.colSpan;
+
+										newTR.appendChild(newTD);
+									} else
+										tdElm.rowSpan = sd['rowspan'] + 1;
+
+									lastTDElm = tdElm;
+								}
+							}
+
+							trElm.parentNode.insertBefore(newTR, trElm);
+
+							grid = getTableGrid(tableElm);
+							inst.selection.selectNode(getCell(grid, cpos.rowindex + 1, cpos.cellindex), tinyMCE.isGecko, true); // Only collape on gecko
+						break;
+
+						case "mceTableInsertRowAfter":
+							if (!trElm || !tdElm)
+								return true;
+
+							var grid = getTableGrid(tableElm);
+							var cpos = getCellPos(grid, tdElm);
+							var newTR = doc.createElement("tr");
+							var lastTDElm = null;
+
+							// Create cells
+							for (var x=0; tdElm = getCell(grid, cpos.rowindex, x); x++) {
+								if (tdElm != lastTDElm) {
+									var sd = getColRowSpan(tdElm);
+
+									if (sd['rowspan'] == 1) {
+										var newTD = doc.createElement("td");
+
+										newTD.innerHTML = "&nbsp;";
+										newTD.colSpan = tdElm.colSpan;
+
+										newTR.appendChild(newTD);
+									} else
+										tdElm.rowSpan = sd['rowspan'] + 1;
+
+									lastTDElm = tdElm;
+								}
+							}
+
+							if (newTR.hasChildNodes()) {
+								var nextTR = nextElm(trElm, "TR");
+								if (nextTR)
+									nextTR.parentNode.insertBefore(newTR, nextTR);
+								else
+									tableElm.appendChild(newTR);
+							}
+
+							grid = getTableGrid(tableElm);
+							inst.selection.selectNode(getCell(grid, cpos.rowindex, cpos.cellindex), tinyMCE.isGecko, true); // Only collape on gecko
+						break;
+
+						case "mceTableDeleteRow":
+							if (!trElm || !tdElm)
+								return true;
+
+							var grid = getTableGrid(tableElm);
+							var cpos = getCellPos(grid, tdElm);
+
+							// Only one row, remove whole table
+							if (grid.length == 1) {
+								tableElm = tinyMCE.getParentElement(tableElm, "table"); // Look for table instead of tbody
+								tableElm.parentNode.removeChild(tableElm);
+								return true;
+							}
+
+							// Move down row spanned cells
+							var cells = trElm.cells;
+							var nextTR = nextElm(trElm, "TR");
+							for (var x=0; x<cells.length; x++) {
+								if (cells[x].rowSpan > 1) {
+									var newTD = cells[x].cloneNode(true);
+									var sd = getColRowSpan(cells[x]);
+
+									newTD.rowSpan = sd.rowspan - 1;
+
+									var nextTD = nextTR.cells[x];
+
+									if (nextTD == null)
+										nextTR.appendChild(newTD);
+									else
+										nextTR.insertBefore(newTD, nextTD);
+								}
+							}
+
+							// Delete cells
+							var lastTDElm = null;
+							for (var x=0; tdElm = getCell(grid, cpos.rowindex, x); x++) {
+								if (tdElm != lastTDElm) {
+									var sd = getColRowSpan(tdElm);
+
+									if (sd.rowspan > 1) {
+										tdElm.rowSpan = sd.rowspan - 1;
+									} else {
+										trElm = tdElm.parentNode;
+
+										if (trElm.parentNode)
+											trElm._delete = true;
+									}
+
+									lastTDElm = tdElm;
+								}
+							}
+
+							deleteMarked(tableElm);
+
+							cpos.rowindex--;
+							if (cpos.rowindex < 0)
+								cpos.rowindex = 0;
+
+							// Recalculate grid and select
+							grid = getTableGrid(tableElm);
+							inst.selection.selectNode(getCell(grid, cpos.rowindex, 0), tinyMCE.isGecko, true); // Only collape on gecko
+						break;
+
+						case "mceTableInsertColBefore":
+							if (!trElm || !tdElm)
+								return true;
+
+							var grid = getTableGrid(tableElm);
+							var cpos = getCellPos(grid, tdElm);
+							var lastTDElm = null;
+
+							for (var y=0; tdElm = getCell(grid, y, cpos.cellindex); y++) {
+								if (tdElm != lastTDElm) {
+									var sd = getColRowSpan(tdElm);
+
+									if (sd['colspan'] == 1) {
+										var newTD = doc.createElement(tdElm.nodeName);
+
+										newTD.innerHTML = "&nbsp;";
+										newTD.rowSpan = tdElm.rowSpan;
+
+										tdElm.parentNode.insertBefore(newTD, tdElm);
+									} else
+										tdElm.colSpan++;
+
+									lastTDElm = tdElm;
+								}
+							}
+
+							grid = getTableGrid(tableElm);
+							inst.selection.selectNode(getCell(grid, cpos.rowindex, cpos.cellindex + 1), tinyMCE.isGecko, true); // Only collape on gecko
+						break;
+
+						case "mceTableInsertColAfter":
+							if (!trElm || !tdElm)
+								return true;
+
+							var grid = getTableGrid(tableElm);
+							var cpos = getCellPos(grid, tdElm);
+							var lastTDElm = null;
+
+							for (var y=0; tdElm = getCell(grid, y, cpos.cellindex); y++) {
+								if (tdElm != lastTDElm) {
+									var sd = getColRowSpan(tdElm);
+
+									if (sd['colspan'] == 1) {
+										var newTD = doc.createElement(tdElm.nodeName);
+
+										newTD.innerHTML = "&nbsp;";
+										newTD.rowSpan = tdElm.rowSpan;
+
+										var nextTD = nextElm(tdElm, "TD,TH");
+										if (nextTD == null)
+											tdElm.parentNode.appendChild(newTD);
+										else
+											nextTD.parentNode.insertBefore(newTD, nextTD);
+									} else
+										tdElm.colSpan++;
+
+									lastTDElm = tdElm;
+								}
+							}
+
+							grid = getTableGrid(tableElm);
+							inst.selection.selectNode(getCell(grid, cpos.rowindex, cpos.cellindex), tinyMCE.isGecko, true); // Only collape on gecko
+						break;
+
+						case "mceTableDeleteCol":
+							if (!trElm || !tdElm)
+								return true;
+
+							var grid = getTableGrid(tableElm);
+							var cpos = getCellPos(grid, tdElm);
+							var lastTDElm = null;
+
+							// Only one col, remove whole table
+							if (grid.length > 1 && grid[0].length <= 1) {
+								tableElm = tinyMCE.getParentElement(tableElm, "table"); // Look for table instead of tbody
+								tableElm.parentNode.removeChild(tableElm);
+								return true;
+							}
+
+							// Delete cells
+							for (var y=0; tdElm = getCell(grid, y, cpos.cellindex); y++) {
+								if (tdElm != lastTDElm) {
+									var sd = getColRowSpan(tdElm);
+
+									if (sd['colspan'] > 1)
+										tdElm.colSpan = sd['colspan'] - 1;
+									else {
+										if (tdElm.parentNode)
+											tdElm.parentNode.removeChild(tdElm);
+									}
+
+									lastTDElm = tdElm;
+								}
+							}
+
+							cpos.cellindex--;
+							if (cpos.cellindex < 0)
+								cpos.cellindex = 0;
+
+							// Recalculate grid and select
+							grid = getTableGrid(tableElm);
+							inst.selection.selectNode(getCell(grid, cpos.rowindex, 0), tinyMCE.isGecko, true); // Only collape on gecko
+						break;
+
+					case "mceTableSplitCells":
+						if (!trElm || !tdElm)
+							return true;
+
+						var spandata = getColRowSpan(tdElm);
+
+						var colspan = spandata["colspan"];
+						var rowspan = spandata["rowspan"];
+
+						// Needs splitting
+						if (colspan > 1 || rowspan > 1) {
+							// Generate cols
+							tdElm.colSpan = 1;
+							for (var i=1; i<colspan; i++) {
+								var newTD = doc.createElement("td");
+
+								newTD.innerHTML = "&nbsp;";
+
+								trElm.insertBefore(newTD, nextElm(tdElm, "TD,TH"));
+
+								if (rowspan > 1)
+									addRows(newTD, trElm, rowspan);
+							}
+
+							addRows(tdElm, trElm, rowspan);
+						}
+
+						// Apply visual aids
+						tableElm = tinyMCE.getParentElement(inst.getFocusElement(), "table");
+						break;
+
+					case "mceTableMergeCells":
+						var rows = new Array();
+						var sel = inst.getSel();
+						var grid = getTableGrid(tableElm);
+
+						if (tinyMCE.isMSIE || sel.rangeCount == 1) {
+							if (user_interface) {
+								// Setup template
+								var template = new Array();
+								var sp = getColRowSpan(tdElm);
+
+								template['file'] = '../../plugins/table/merge_cells.htm';
+								template['width'] = 250;
+								template['height'] = 105 + (tinyMCE.isNS7 ? 25 : 0);
+
+								// Language specific width and height addons
+								template['width'] += tinyMCE.getLang('lang_table_merge_cells_delta_width', 0);
+								template['height'] += tinyMCE.getLang('lang_table_merge_cells_delta_height', 0);
+
+								// Open window
+								tinyMCE.openWindow(template, {editor_id : inst.editorId, inline : "yes", action : "update", numcols : sp.colspan, numrows : sp.rowspan});
+
+								return true;
+							} else {
+								var numRows = parseInt(value['numrows']);
+								var numCols = parseInt(value['numcols']);
+								var cpos = getCellPos(grid, tdElm);
+
+								if (("" + numRows) == "NaN")
+									numRows = 1;
+
+								if (("" + numCols) == "NaN")
+									numCols = 1;
+
+								// Get rows and cells
+								var tRows = tableElm.rows;
+								for (var y=cpos.rowindex; y<grid.length; y++) {
+									var rowCells = new Array();
+
+									for (var x=cpos.cellindex; x<grid[y].length; x++) {
+										var td = getCell(grid, y, x);
+
+										if (td && !inArray(rows, td) && !inArray(rowCells, td)) {
+											var cp = getCellPos(grid, td);
+
+											// Within range
+											if (cp.cellindex < cpos.cellindex+numCols && cp.rowindex < cpos.rowindex+numRows)
+												rowCells[rowCells.length] = td;
+										}
+									}
+
+									if (rowCells.length > 0)
+										rows[rows.length] = rowCells;
+								}
+
+								//return true;
+							}
+						} else {
+							var cells = new Array();
+							var sel = inst.getSel();
+							var lastTR = null;
+							var curRow = null;
+							var x1 = -1, y1 = -1, x2, y2;
+
+							// Only one cell selected, whats the point?
+							if (sel.rangeCount < 2)
+								return true;
+
+							// Get all selected cells
+							for (var i=0; i<sel.rangeCount; i++) {
+								var rng = sel.getRangeAt(i);
+								var tdElm = rng.startContainer.childNodes[rng.startOffset];
+
+								if (!tdElm)
+									break;
+
+								if (tdElm.nodeName == "TD")
+									cells[cells.length] = tdElm;
+							}
+
+							// Get rows and cells
+							var tRows = tableElm.rows;
+							for (var y=0; y<tRows.length; y++) {
+								var rowCells = new Array();
+
+								for (var x=0; x<tRows[y].cells.length; x++) {
+									var td = tRows[y].cells[x];
+
+									for (var i=0; i<cells.length; i++) {
+										if (td == cells[i]) {
+											rowCells[rowCells.length] = td;
+										}
+									}
+								}
+
+								if (rowCells.length > 0)
+									rows[rows.length] = rowCells;
+							}
+
+							// Find selected cells in grid and box
+							var curRow = new Array();
+							var lastTR = null;
+							for (var y=0; y<grid.length; y++) {
+								for (var x=0; x<grid[y].length; x++) {
+									grid[y][x]._selected = false;
+
+									for (var i=0; i<cells.length; i++) {
+										if (grid[y][x] == cells[i]) {
+											// Get start pos
+											if (x1 == -1) {
+												x1 = x;
+												y1 = y;
+											}
+
+											// Get end pos
+											x2 = x;
+											y2 = y;
+
+											grid[y][x]._selected = true;
+										}
+									}
+								}
+							}
+
+							// Is there gaps, if so deny
+							for (var y=y1; y<=y2; y++) {
+								for (var x=x1; x<=x2; x++) {
+									if (!grid[y][x]._selected) {
+										alert("Invalid selection for merge.");
+										return true;
+									}
+								}
+							}
+						}
+
+						// Validate selection and get total rowspan and colspan
+						var rowSpan = 1, colSpan = 1;
+
+						// Validate horizontal and get total colspan
+						var lastRowSpan = -1;
+						for (var y=0; y<rows.length; y++) {
+							var rowColSpan = 0;
+
+							for (var x=0; x<rows[y].length; x++) {
+								var sd = getColRowSpan(rows[y][x]);
+
+								rowColSpan += sd['colspan'];
+
+								if (lastRowSpan != -1 && sd['rowspan'] != lastRowSpan) {
+									alert("Invalid selection for merge.");
+									return true;
+								}
+
+								lastRowSpan = sd['rowspan'];
+							}
+
+							if (rowColSpan > colSpan)
+								colSpan = rowColSpan;
+
+							lastRowSpan = -1;
+						}
+
+						// Validate vertical and get total rowspan
+						var lastColSpan = -1;
+						for (var x=0; x<rows[0].length; x++) {
+							var colRowSpan = 0;
+
+							for (var y=0; y<rows.length; y++) {
+								var sd = getColRowSpan(rows[y][x]);
+
+								colRowSpan += sd['rowspan'];
+
+								if (lastColSpan != -1 && sd['colspan'] != lastColSpan) {
+									alert("Invalid selection for merge.");
+									return true;
+								}
+
+								lastColSpan = sd['colspan'];
+							}
+
+							if (colRowSpan > rowSpan)
+								rowSpan = colRowSpan;
+
+							lastColSpan = -1;
+						}
+
+						// Setup td
+						tdElm = rows[0][0];
+						tdElm.rowSpan = rowSpan;
+						tdElm.colSpan = colSpan;
+
+						// Merge cells
+						for (var y=0; y<rows.length; y++) {
+							for (var x=0; x<rows[y].length; x++) {
+								var html = rows[y][x].innerHTML;
+								var chk = tinyMCE.regexpReplace(html, "[ \t\r\n]", "");
+
+								if (chk != "<br/>" && chk != "<br>" && chk != "&nbsp;" && (x+y > 0))
+									tdElm.innerHTML += html;
+
+								// Not current cell
+								if (rows[y][x] != tdElm && !rows[y][x]._deleted) {
+									var cpos = getCellPos(grid, rows[y][x]);
+									var tr = rows[y][x].parentNode;
+
+									tr.removeChild(rows[y][x]);
+									rows[y][x]._deleted = true;
+
+									// Empty TR, remove it
+									if (!tr.hasChildNodes()) {
+										tr.parentNode.removeChild(tr);
+
+										var lastCell = null;
+										for (var x=0; cellElm = getCell(grid, cpos.rowindex, x); x++) {
+											if (cellElm != lastCell && cellElm.rowSpan > 1)
+												cellElm.rowSpan--;
+
+											lastCell = cellElm;
+										}
+
+										if (tdElm.rowSpan > 1)
+											tdElm.rowSpan--;
+									}
+								}
+							}
+						}
+
+						break;
+					}
+
+					tableElm = tinyMCE.getParentElement(inst.getFocusElement(), "table");
+					tinyMCE.handleVisualAid(tableElm, true, tinyMCE.settings['visual'], tinyMCE.selectedInstance);
+					tinyMCE.triggerNodeChange();
+					inst.repaint();
+				}
+
+			return true;
+		}
+
+		// Pass to next handler in chain
+		return false;
+	}
+};
+
+tinyMCE.addPlugin("table", TinyMCE_TablePlugin);
Binary file includes/clientside/tinymce/plugins/table/images/buttons.gif has changed
Binary file includes/clientside/tinymce/plugins/table/images/table.gif has changed
Binary file includes/clientside/tinymce/plugins/table/images/table_cell_props.gif has changed
Binary file includes/clientside/tinymce/plugins/table/images/table_delete.gif has changed
Binary file includes/clientside/tinymce/plugins/table/images/table_delete_col.gif has changed
Binary file includes/clientside/tinymce/plugins/table/images/table_delete_row.gif has changed
Binary file includes/clientside/tinymce/plugins/table/images/table_insert_col_after.gif has changed
Binary file includes/clientside/tinymce/plugins/table/images/table_insert_col_before.gif has changed
Binary file includes/clientside/tinymce/plugins/table/images/table_insert_row_after.gif has changed
Binary file includes/clientside/tinymce/plugins/table/images/table_insert_row_before.gif has changed
Binary file includes/clientside/tinymce/plugins/table/images/table_merge_cells.gif has changed
Binary file includes/clientside/tinymce/plugins/table/images/table_row_props.gif has changed
Binary file includes/clientside/tinymce/plugins/table/images/table_split_cells.gif has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/table/jscripts/cell.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,249 @@
+function init() {
+	tinyMCEPopup.resizeToInnerSize();
+
+	document.getElementById('backgroundimagebrowsercontainer').innerHTML = getBrowserHTML('backgroundimagebrowser','backgroundimage','image','table');
+	document.getElementById('bordercolor_pickcontainer').innerHTML = getColorPickerHTML('bordercolor_pick','bordercolor');
+	document.getElementById('bgcolor_pickcontainer').innerHTML = getColorPickerHTML('bgcolor_pick','bgcolor')
+
+	var inst = tinyMCE.selectedInstance;
+	var tdElm = tinyMCE.getParentElement(inst.getFocusElement(), "td,th");
+	var formObj = document.forms[0];
+	var st = tinyMCE.parseStyle(tinyMCE.getAttrib(tdElm, "style"));
+
+	// Get table cell data
+	var celltype = tdElm.nodeName.toLowerCase();
+	var align = tinyMCE.getAttrib(tdElm, 'align');
+	var valign = tinyMCE.getAttrib(tdElm, 'valign');
+	var width = trimSize(getStyle(tdElm, 'width', 'width'));
+	var height = trimSize(getStyle(tdElm, 'height', 'height'));
+	var bordercolor = convertRGBToHex(getStyle(tdElm, 'bordercolor', 'borderLeftColor'));
+	var bgcolor = convertRGBToHex(getStyle(tdElm, 'bgcolor', 'backgroundColor'));
+	var className = tinyMCE.getVisualAidClass(tinyMCE.getAttrib(tdElm, 'class'), false);
+	var backgroundimage = getStyle(tdElm, 'background', 'backgroundImage').replace(new RegExp("url\\('?([^']*)'?\\)", 'gi'), "$1");;
+	var id = tinyMCE.getAttrib(tdElm, 'id');
+	var lang = tinyMCE.getAttrib(tdElm, 'lang');
+	var dir = tinyMCE.getAttrib(tdElm, 'dir');
+	var scope = tinyMCE.getAttrib(tdElm, 'scope');
+
+	// Setup form
+	addClassesToList('class', 'table_cell_styles');
+	formObj.bordercolor.value = bordercolor;
+	formObj.bgcolor.value = bgcolor;
+	formObj.backgroundimage.value = backgroundimage;
+	formObj.width.value = width;
+	formObj.height.value = height;
+	formObj.id.value = id;
+	formObj.lang.value = lang;
+	formObj.style.value = tinyMCE.serializeStyle(st);
+	selectByValue(formObj, 'align', align);
+	selectByValue(formObj, 'valign', valign);
+	selectByValue(formObj, 'class', className);
+	selectByValue(formObj, 'celltype', celltype);
+	selectByValue(formObj, 'dir', dir);
+	selectByValue(formObj, 'scope', scope);
+
+	// Resize some elements
+	if (isVisible('backgroundimagebrowser'))
+		document.getElementById('backgroundimage').style.width = '180px';
+
+	updateColor('bordercolor_pick', 'bordercolor');
+	updateColor('bgcolor_pick', 'bgcolor');
+}
+
+function updateAction() {
+	tinyMCEPopup.restoreSelection();
+
+	var inst = tinyMCE.selectedInstance;
+	var tdElm = tinyMCE.getParentElement(inst.getFocusElement(), "td,th");
+	var trElm = tinyMCE.getParentElement(inst.getFocusElement(), "tr");
+	var tableElm = tinyMCE.getParentElement(inst.getFocusElement(), "table");
+	var formObj = document.forms[0];
+
+	inst.execCommand('mceBeginUndoLevel');
+
+	switch (getSelectValue(formObj, 'action')) {
+		case "cell":
+			var celltype = getSelectValue(formObj, 'celltype');
+			var scope = getSelectValue(formObj, 'scope');
+
+			if (tinyMCE.getParam("accessibility_warnings")) {
+				if (celltype == "th" && scope == "")
+					var answer = confirm(tinyMCE.getLang('lang_table_missing_scope', '', true));
+				else
+					var answer = true;
+
+				if (!answer)
+					return;
+			}
+
+			updateCell(tdElm);
+			break;
+
+		case "row":
+			var cell = trElm.firstChild;
+
+			if (cell.nodeName != "TD" && cell.nodeName != "TH")
+				cell = nextCell(cell);
+
+			do {
+				cell = updateCell(cell, true);
+			} while ((cell = nextCell(cell)) != null);
+
+			break;
+
+		case "all":
+			var rows = tableElm.getElementsByTagName("tr");
+
+			for (var i=0; i<rows.length; i++) {
+				var cell = rows[i].firstChild;
+
+				if (cell.nodeName != "TD" && cell.nodeName != "TH")
+					cell = nextCell(cell);
+
+				do {
+					cell = updateCell(cell, true);
+				} while ((cell = nextCell(cell)) != null);
+			}
+
+			break;
+	}
+
+	tinyMCE.handleVisualAid(inst.getBody(), true, inst.visualAid, inst);
+	tinyMCE.triggerNodeChange();
+	inst.execCommand('mceEndUndoLevel');
+	tinyMCEPopup.close();
+}
+
+function nextCell(elm) {
+	while ((elm = elm.nextSibling) != null) {
+		if (elm.nodeName == "TD" || elm.nodeName == "TH")
+			return elm;
+	}
+
+	return null;
+}
+
+function updateCell(td, skip_id) {
+	var inst = tinyMCE.selectedInstance;
+	var formObj = document.forms[0];
+	var curCellType = td.nodeName.toLowerCase();
+	var celltype = getSelectValue(formObj, 'celltype');
+	var doc = inst.getDoc();
+
+	if (!skip_id)
+		td.setAttribute('id', formObj.id.value);
+
+	td.setAttribute('align', formObj.align.value);
+	td.setAttribute('vAlign', formObj.valign.value);
+	td.setAttribute('lang', formObj.lang.value);
+	td.setAttribute('dir', getSelectValue(formObj, 'dir'));
+	td.setAttribute('style', tinyMCE.serializeStyle(tinyMCE.parseStyle(formObj.style.value)));
+	td.setAttribute('scope', formObj.scope.value);
+	tinyMCE.setAttrib(td, 'class', getSelectValue(formObj, 'class'));
+
+	// Clear deprecated attributes
+	tinyMCE.setAttrib(td, 'width', '');
+	tinyMCE.setAttrib(td, 'height', '');
+	tinyMCE.setAttrib(td, 'bgColor', '');
+	tinyMCE.setAttrib(td, 'borderColor', '');
+	tinyMCE.setAttrib(td, 'background', '');
+
+	// Set styles
+	td.style.width = getCSSSize(formObj.width.value);
+	td.style.height = getCSSSize(formObj.height.value);
+	if (formObj.bordercolor.value != "") {
+		td.style.borderColor = formObj.bordercolor.value;
+		td.style.borderStyle = td.style.borderStyle == "" ? "solid" : td.style.borderStyle;
+		td.style.borderWidth = td.style.borderWidth == "" ? "1px" : td.style.borderWidth;
+	} else
+		td.style.borderColor = '';
+
+	td.style.backgroundColor = formObj.bgcolor.value;
+
+	if (formObj.backgroundimage.value != "")
+		td.style.backgroundImage = "url('" + formObj.backgroundimage.value + "')";
+	else
+		td.style.backgroundImage = '';
+
+	if (curCellType != celltype) {
+		// changing to a different node type
+		var newCell = doc.createElement(celltype);
+
+		for (var c=0; c<td.childNodes.length; c++)
+			newCell.appendChild(td.childNodes[c].cloneNode(1));
+
+		for (var a=0; a<td.attributes.length; a++) {
+			var attr = td.attributes[a];
+			newCell.setAttribute(attr.name, attr.value);
+		}
+
+		td.parentNode.replaceChild(newCell, td);
+		td = newCell;
+	}
+
+	return td;
+}
+
+function changedBackgroundImage() {
+	var formObj = document.forms[0];
+	var st = tinyMCE.parseStyle(formObj.style.value);
+
+	st['background-image'] = "url('" + formObj.backgroundimage.value + "')";
+
+	formObj.style.value = tinyMCE.serializeStyle(st);
+}
+
+function changedSize() {
+	var formObj = document.forms[0];
+	var st = tinyMCE.parseStyle(formObj.style.value);
+
+	var width = formObj.width.value;
+	if (width != "")
+		st['width'] = getCSSSize(width);
+	else
+		st['width'] = "";
+
+	var height = formObj.height.value;
+	if (height != "")
+		st['height'] = getCSSSize(height);
+	else
+		st['height'] = "";
+
+	formObj.style.value = tinyMCE.serializeStyle(st);
+}
+
+function changedColor() {
+	var formObj = document.forms[0];
+	var st = tinyMCE.parseStyle(formObj.style.value);
+
+	st['background-color'] = formObj.bgcolor.value;
+	st['border-color'] = formObj.bordercolor.value;
+
+	formObj.style.value = tinyMCE.serializeStyle(st);
+}
+
+function changedStyle() {
+	var formObj = document.forms[0];
+	var st = tinyMCE.parseStyle(formObj.style.value);
+
+	if (st['background-image'])
+		formObj.backgroundimage.value = st['background-image'].replace(new RegExp("url\\('?([^']*)'?\\)", 'gi'), "$1");
+	else
+		formObj.backgroundimage.value = '';
+
+	if (st['width'])
+		formObj.width.value = trimSize(st['width']);
+
+	if (st['height'])
+		formObj.height.value = trimSize(st['height']);
+
+	if (st['background-color']) {
+		formObj.bgcolor.value = st['background-color'];
+		updateColor('bgcolor_pick','bgcolor');
+	}
+
+	if (st['border-color']) {
+		formObj.bordercolor.value = st['border-color'];
+		updateColor('bordercolor_pick','bordercolor');
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/table/jscripts/merge_cells.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,24 @@
+function init() {
+	tinyMCEPopup.resizeToInnerSize();
+
+	var formObj = document.forms[0];
+
+	formObj.numcols.value = tinyMCE.getWindowArg('numcols', 1);
+	formObj.numrows.value = tinyMCE.getWindowArg('numrows', 1);
+}
+
+function mergeCells() {
+	var args = new Array();
+	var formObj = document.forms[0];
+
+	if (!AutoValidator.validate(formObj)) {
+		alert(tinyMCE.getLang('lang_invalid_data'));
+		return false;
+	}
+
+	args["numcols"] = formObj.numcols.value;
+	args["numrows"] = formObj.numrows.value;
+
+	tinyMCEPopup.execCommand("mceTableMergeCells", false, args);
+	tinyMCEPopup.close();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/table/jscripts/row.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,200 @@
+function init() {
+	tinyMCEPopup.resizeToInnerSize();
+
+	document.getElementById('backgroundimagebrowsercontainer').innerHTML = getBrowserHTML('backgroundimagebrowser','backgroundimage','image','table');
+	document.getElementById('bgcolor_pickcontainer').innerHTML = getColorPickerHTML('bgcolor_pick','bgcolor');
+
+	var inst = tinyMCE.selectedInstance;
+	var trElm = tinyMCE.getParentElement(inst.getFocusElement(), "tr");
+	var formObj = document.forms[0];
+	var st = tinyMCE.parseStyle(tinyMCE.getAttrib(trElm, "style"));
+
+	// Get table row data
+	var rowtype = trElm.parentNode.nodeName.toLowerCase();
+	var align = tinyMCE.getAttrib(trElm, 'align');
+	var valign = tinyMCE.getAttrib(trElm, 'valign');
+	var height = trimSize(getStyle(trElm, 'height', 'height'));
+	var className = tinyMCE.getVisualAidClass(tinyMCE.getAttrib(trElm, 'class'), false);
+	var bgcolor = convertRGBToHex(getStyle(trElm, 'bgcolor', 'backgroundColor'));
+	var backgroundimage = getStyle(trElm, 'background', 'backgroundImage').replace(new RegExp("url\\('?([^']*)'?\\)", 'gi'), "$1");;
+	var id = tinyMCE.getAttrib(trElm, 'id');
+	var lang = tinyMCE.getAttrib(trElm, 'lang');
+	var dir = tinyMCE.getAttrib(trElm, 'dir');
+
+	// Setup form
+	addClassesToList('class', 'table_row_styles');
+	formObj.bgcolor.value = bgcolor;
+	formObj.backgroundimage.value = backgroundimage;
+	formObj.height.value = height;
+	formObj.id.value = id;
+	formObj.lang.value = lang;
+	formObj.style.value = tinyMCE.serializeStyle(st);
+	selectByValue(formObj, 'align', align);
+	selectByValue(formObj, 'valign', valign);
+	selectByValue(formObj, 'class', className);
+	selectByValue(formObj, 'rowtype', rowtype);
+	selectByValue(formObj, 'dir', dir);
+
+	// Resize some elements
+	if (isVisible('backgroundimagebrowser'))
+		document.getElementById('backgroundimage').style.width = '180px';
+
+	updateColor('bgcolor_pick', 'bgcolor');
+}
+
+function updateAction() {
+	tinyMCEPopup.restoreSelection();
+
+	var inst = tinyMCE.selectedInstance;
+	var trElm = tinyMCE.getParentElement(inst.getFocusElement(), "tr");
+	var tableElm = tinyMCE.getParentElement(inst.getFocusElement(), "table");
+	var formObj = document.forms[0];
+	var action = getSelectValue(formObj, 'action');
+
+	inst.execCommand('mceBeginUndoLevel');
+
+	switch (action) {
+		case "row":
+			updateRow(trElm);
+			break;
+
+		case "all":
+			var rows = tableElm.getElementsByTagName("tr");
+
+			for (var i=0; i<rows.length; i++)
+				updateRow(rows[i], true);
+
+			break;
+
+		case "odd":
+		case "even":
+			var rows = tableElm.getElementsByTagName("tr");
+
+			for (var i=0; i<rows.length; i++) {
+				if ((i % 2 == 0 && action == "odd") || (i % 2 != 0 && action == "even"))
+					updateRow(rows[i], true, true);
+			}
+
+			break;
+	}
+
+	tinyMCE.handleVisualAid(inst.getBody(), true, inst.visualAid, inst);
+	tinyMCE.triggerNodeChange();
+	inst.execCommand('mceEndUndoLevel');
+	tinyMCEPopup.close();
+}
+
+function updateRow(tr_elm, skip_id, skip_parent) {
+	var inst = tinyMCE.selectedInstance;
+	var formObj = document.forms[0];
+	var curRowType = tr_elm.parentNode.nodeName.toLowerCase();
+	var rowtype = getSelectValue(formObj, 'rowtype');
+	var doc = inst.getDoc();
+
+	// Update row element
+	if (!skip_id)
+		tr_elm.setAttribute('id', formObj.id.value);
+
+	tr_elm.setAttribute('align', getSelectValue(formObj, 'align'));
+	tr_elm.setAttribute('vAlign', getSelectValue(formObj, 'valign'));
+	tr_elm.setAttribute('lang', formObj.lang.value);
+	tr_elm.setAttribute('dir', getSelectValue(formObj, 'dir'));
+	tr_elm.setAttribute('style', tinyMCE.serializeStyle(tinyMCE.parseStyle(formObj.style.value)));
+	tinyMCE.setAttrib(tr_elm, 'class', getSelectValue(formObj, 'class'));
+
+	// Clear deprecated attributes
+	tr_elm.setAttribute('background', '');
+	tr_elm.setAttribute('bgColor', '');
+	tr_elm.setAttribute('height', '');
+
+	// Set styles
+	tr_elm.style.height = getCSSSize(formObj.height.value);
+	tr_elm.style.backgroundColor = formObj.bgcolor.value;
+
+	if (formObj.backgroundimage.value != "")
+		tr_elm.style.backgroundImage = "url('" + formObj.backgroundimage.value + "')";
+	else
+		tr_elm.style.backgroundImage = '';
+
+	// Setup new rowtype
+	if (curRowType != rowtype && !skip_parent) {
+		// first, clone the node we are working on
+		var newRow = tr_elm.cloneNode(1);
+
+		// next, find the parent of its new destination (creating it if necessary)
+		var theTable = tinyMCE.getParentElement(tr_elm, "table");
+		var dest = rowtype;
+		var newParent = null;
+		for (var i = 0; i < theTable.childNodes.length; i++) {
+			if (theTable.childNodes[i].nodeName.toLowerCase() == dest)
+				newParent = theTable.childNodes[i];
+		}
+
+		if (newParent == null) {
+			newParent = doc.createElement(dest);
+
+			if (dest == "thead")
+				theTable.insertBefore(newParent, theTable.firstChild);
+			else
+				theTable.appendChild(newParent);
+		}
+
+		// append the row to the new parent
+		newParent.appendChild(newRow);
+
+		// remove the original
+		tr_elm.parentNode.removeChild(tr_elm);
+
+		// set tr_elm to the new node
+		tr_elm = newRow;
+	}
+}
+
+function changedBackgroundImage() {
+	var formObj = document.forms[0];
+	var st = tinyMCE.parseStyle(formObj.style.value);
+
+	st['background-image'] = "url('" + formObj.backgroundimage.value + "')";
+
+	formObj.style.value = tinyMCE.serializeStyle(st);
+}
+
+function changedStyle() {
+	var formObj = document.forms[0];
+	var st = tinyMCE.parseStyle(formObj.style.value);
+
+	if (st['background-image'])
+		formObj.backgroundimage.value = st['background-image'].replace(new RegExp("url\\('?([^']*)'?\\)", 'gi'), "$1");
+	else
+		formObj.backgroundimage.value = '';
+
+	if (st['height'])
+		formObj.height.value = trimSize(st['height']);
+
+	if (st['background-color']) {
+		formObj.bgcolor.value = st['background-color'];
+		updateColor('bgcolor_pick','bgcolor');
+	}
+}
+
+function changedSize() {
+	var formObj = document.forms[0];
+	var st = tinyMCE.parseStyle(formObj.style.value);
+
+	var height = formObj.height.value;
+	if (height != "")
+		st['height'] = getCSSSize(height);
+	else
+		st['height'] = "";
+
+	formObj.style.value = tinyMCE.serializeStyle(st);
+}
+
+function changedColor() {
+	var formObj = document.forms[0];
+	var st = tinyMCE.parseStyle(formObj.style.value);
+
+	st['background-color'] = formObj.bgcolor.value;
+
+	formObj.style.value = tinyMCE.serializeStyle(st);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/table/jscripts/table.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,364 @@
+var action, orgTableWidth, orgTableHeight;
+
+function insertTable() {
+	var formObj = document.forms[0];
+	var inst = tinyMCE.selectedInstance;
+	var cols = 2, rows = 2, border = 0, cellpadding = -1, cellspacing = -1, align, width, height, className, caption;
+	var html = '', capEl;
+	var elm = tinyMCE.tableElm;
+	var cellLimit, rowLimit, colLimit;
+
+	if (!AutoValidator.validate(formObj)) {
+		alert(tinyMCE.getLang('lang_invalid_data'));
+		return false;
+	}
+
+	tinyMCEPopup.restoreSelection();
+
+	// Get form data
+	cols = formObj.elements['cols'].value;
+	rows = formObj.elements['rows'].value;
+	border = formObj.elements['border'].value != "" ? formObj.elements['border'].value  : 0;
+	cellpadding = formObj.elements['cellpadding'].value != "" ? formObj.elements['cellpadding'].value : "";
+	cellspacing = formObj.elements['cellspacing'].value != "" ? formObj.elements['cellspacing'].value : "";
+	align = formObj.elements['align'].options[formObj.elements['align'].selectedIndex].value;
+	width = formObj.elements['width'].value;
+	height = formObj.elements['height'].value;
+	bordercolor = formObj.elements['bordercolor'].value;
+	bgcolor = formObj.elements['bgcolor'].value;
+	className = formObj.elements['class'].options[formObj.elements['class'].selectedIndex].value;
+	id = formObj.elements['id'].value;
+	summary = formObj.elements['summary'].value;
+	style = formObj.elements['style'].value;
+	dir = formObj.elements['dir'].value;
+	lang = formObj.elements['lang'].value;
+	background = formObj.elements['backgroundimage'].value;
+	caption = formObj.elements['caption'].checked;
+
+	cellLimit = tinyMCE.getParam('table_cell_limit', false);
+	rowLimit = tinyMCE.getParam('table_row_limit', false);
+	colLimit = tinyMCE.getParam('table_col_limit', false);
+
+	// Validate table size
+	if (colLimit && cols > colLimit) {
+		alert(tinyMCE.getLang('lang_table_col_limit', '', true, {cols : colLimit}));
+		return false;
+	} else if (rowLimit && rows > rowLimit) {
+		alert(tinyMCE.getLang('lang_table_row_limit', '', true, {rows : rowLimit}));
+		return false;
+	} else if (cellLimit && cols * rows > cellLimit) {
+		alert(tinyMCE.getLang('lang_table_cell_limit', '', true, {cells : cellLimit}));
+		return false;
+	}
+
+	// Update table
+	if (action == "update") {
+		inst.execCommand('mceBeginUndoLevel');
+
+		tinyMCE.setAttrib(elm, 'cellPadding', cellpadding, true);
+		tinyMCE.setAttrib(elm, 'cellSpacing', cellspacing, true);
+		tinyMCE.setAttrib(elm, 'border', border, true);
+		tinyMCE.setAttrib(elm, 'align', align);
+		tinyMCE.setAttrib(elm, 'class', className);
+		tinyMCE.setAttrib(elm, 'style', style);
+		tinyMCE.setAttrib(elm, 'id', id);
+		tinyMCE.setAttrib(elm, 'summary', summary);
+		tinyMCE.setAttrib(elm, 'dir', dir);
+		tinyMCE.setAttrib(elm, 'lang', lang);
+
+		capEl = elm.getElementsByTagName('caption')[0];
+
+		if (capEl && !caption)
+			capEl.parentNode.removeChild(capEl);
+
+		if (!capEl && caption) {
+			capEl = elm.ownerDocument.createElement('caption');
+			capEl.innerHTML = '&nbsp;';
+			elm.insertBefore(capEl, elm.firstChild);
+		}
+
+		// Not inline styles
+		if (!tinyMCE.getParam("inline_styles"))
+			tinyMCE.setAttrib(elm, 'width', width, true);
+
+		// Remove these since they are not valid XHTML
+		tinyMCE.setAttrib(elm, 'borderColor', '');
+		tinyMCE.setAttrib(elm, 'bgColor', '');
+		tinyMCE.setAttrib(elm, 'background', '');
+		tinyMCE.setAttrib(elm, 'height', '');
+
+		if (background != '')
+			elm.style.backgroundImage = "url('" + background + "')";
+		else
+			elm.style.backgroundImage = '';
+
+		if (tinyMCE.getParam("inline_styles"))
+			elm.style.borderWidth = border + "px";
+
+		if (tinyMCE.getParam("inline_styles")) {
+			if (width != '')
+				elm.style.width = getCSSSize(width);
+		}
+
+		if (bordercolor != "") {
+			elm.style.borderColor = bordercolor;
+			elm.style.borderStyle = elm.style.borderStyle == "" ? "solid" : elm.style.borderStyle;
+			elm.style.borderWidth = border == "" ? "1px" : border;
+		} else
+			elm.style.borderColor = '';
+
+		elm.style.backgroundColor = bgcolor;
+		elm.style.height = getCSSSize(height);
+
+		tinyMCE.handleVisualAid(tinyMCE.tableElm, false, inst.visualAid, inst);
+
+		// Fix for stange MSIE align bug
+		tinyMCE.tableElm.outerHTML = tinyMCE.tableElm.outerHTML;
+
+		tinyMCE.handleVisualAid(inst.getBody(), true, inst.visualAid, inst);
+		tinyMCE.triggerNodeChange();
+		inst.execCommand('mceEndUndoLevel');
+
+		// Repaint if dimensions changed
+		if (formObj.width.value != orgTableWidth || formObj.height.value != orgTableHeight)
+			inst.repaint();
+
+		tinyMCEPopup.close();
+		return true;
+	}
+
+	// Create new table
+	html += '<table';
+
+	html += makeAttrib('id', id);
+	html += makeAttrib('border', border);
+	html += makeAttrib('cellpadding', cellpadding);
+	html += makeAttrib('cellspacing', cellspacing);
+	html += makeAttrib('width', width);
+	//html += makeAttrib('height', height);
+	//html += makeAttrib('bordercolor', bordercolor);
+	//html += makeAttrib('bgcolor', bgcolor);
+	html += makeAttrib('align', align);
+	html += makeAttrib('class', tinyMCE.getVisualAidClass(className, border == 0));
+	html += makeAttrib('style', style);
+	html += makeAttrib('summary', summary);
+	html += makeAttrib('dir', dir);
+	html += makeAttrib('lang', lang);
+	html += '>';
+
+	if (caption)
+		html += '<caption>&nbsp;</caption>';
+
+	for (var y=0; y<rows; y++) {
+		html += "<tr>";
+
+		for (var x=0; x<cols; x++)
+			html += '<td>&nbsp;</td>';
+
+		html += "</tr>";
+	}
+
+	html += "</table>";
+
+	inst.execCommand('mceBeginUndoLevel');
+	inst.execCommand('mceInsertContent', false, html);
+	tinyMCE.handleVisualAid(inst.getBody(), true, tinyMCE.settings['visual']);
+	inst.execCommand('mceEndUndoLevel');
+
+	tinyMCEPopup.close();
+}
+
+function makeAttrib(attrib, value) {
+	var formObj = document.forms[0];
+	var valueElm = formObj.elements[attrib];
+
+	if (typeof(value) == "undefined" || value == null) {
+		value = "";
+
+		if (valueElm)
+			value = valueElm.value;
+	}
+
+	if (value == "")
+		return "";
+
+	// XML encode it
+	value = value.replace(/&/g, '&amp;');
+	value = value.replace(/\"/g, '&quot;');
+	value = value.replace(/</g, '&lt;');
+	value = value.replace(/>/g, '&gt;');
+
+	return ' ' + attrib + '="' + value + '"';
+}
+
+function init() {
+	tinyMCEPopup.resizeToInnerSize();
+
+	document.getElementById('backgroundimagebrowsercontainer').innerHTML = getBrowserHTML('backgroundimagebrowser','backgroundimage','image','table');
+	document.getElementById('backgroundimagebrowsercontainer').innerHTML = getBrowserHTML('backgroundimagebrowser','backgroundimage','image','table');
+	document.getElementById('bordercolor_pickcontainer').innerHTML = getColorPickerHTML('bordercolor_pick','bordercolor');
+	document.getElementById('bgcolor_pickcontainer').innerHTML = getColorPickerHTML('bgcolor_pick','bgcolor');
+
+	var cols = 2, rows = 2, border = tinyMCE.getParam('table_default_border', '0'), cellpadding = tinyMCE.getParam('table_default_cellpadding', ''), cellspacing = tinyMCE.getParam('table_default_cellspacing', '');
+	var align = "", width = "", height = "", bordercolor = "", bgcolor = "", className = "";
+	var id = "", summary = "", style = "", dir = "", lang = "", background = "", bgcolor = "", bordercolor = "";
+	var inst = tinyMCE.selectedInstance;
+	var formObj = document.forms[0];
+	var elm = tinyMCE.getParentElement(inst.getFocusElement(), "table");
+
+	tinyMCE.tableElm = elm;
+	action = tinyMCE.getWindowArg('action');
+	if (action == null)
+		action = tinyMCE.tableElm ? "update" : "insert";
+
+	if (tinyMCE.tableElm && action != "insert") {
+		var rowsAr = tinyMCE.tableElm.rows;
+		var cols = 0;
+		for (var i=0; i<rowsAr.length; i++)
+			if (rowsAr[i].cells.length > cols)
+				cols = rowsAr[i].cells.length;
+
+		cols = cols;
+		rows = rowsAr.length;
+
+		st = tinyMCE.parseStyle(tinyMCE.getAttrib(tinyMCE.tableElm, "style"));
+		border = trimSize(getStyle(elm, 'border', 'borderWidth'));
+		cellpadding = tinyMCE.getAttrib(tinyMCE.tableElm, 'cellpadding', "");
+		cellspacing = tinyMCE.getAttrib(tinyMCE.tableElm, 'cellspacing', "");
+		width = trimSize(getStyle(elm, 'width', 'width'));
+		height = trimSize(getStyle(elm, 'height', 'height'));
+		bordercolor = convertRGBToHex(getStyle(elm, 'bordercolor', 'borderLeftColor'));
+		bgcolor = convertRGBToHex(getStyle(elm, 'bgcolor', 'backgroundColor'));
+		align = tinyMCE.getAttrib(tinyMCE.tableElm, 'align', align);
+		className = tinyMCE.getVisualAidClass(tinyMCE.getAttrib(tinyMCE.tableElm, 'class'), false);
+		id = tinyMCE.getAttrib(tinyMCE.tableElm, 'id');
+		summary = tinyMCE.getAttrib(tinyMCE.tableElm, 'summary');
+		style = tinyMCE.serializeStyle(st);
+		dir = tinyMCE.getAttrib(tinyMCE.tableElm, 'dir');
+		lang = tinyMCE.getAttrib(tinyMCE.tableElm, 'lang');
+		background = getStyle(elm, 'background', 'backgroundImage').replace(new RegExp("url\\('?([^']*)'?\\)", 'gi'), "$1");
+		formObj.caption.checked = tinyMCE.tableElm.getElementsByTagName('caption').length > 0;
+
+		orgTableWidth = width;
+		orgTableHeight = height;
+
+		action = "update";
+	}
+
+	addClassesToList('class', "table_styles");
+
+	// Update form
+	selectByValue(formObj, 'align', align);
+	selectByValue(formObj, 'class', className);
+	formObj.cols.value = cols;
+	formObj.rows.value = rows;
+	formObj.border.value = border;
+	formObj.cellpadding.value = cellpadding;
+	formObj.cellspacing.value = cellspacing;
+	formObj.width.value = width;
+	formObj.height.value = height;
+	formObj.bordercolor.value = bordercolor;
+	formObj.bgcolor.value = bgcolor;
+	formObj.id.value = id;
+	formObj.summary.value = summary;
+	formObj.style.value = style;
+	formObj.dir.value = dir;
+	formObj.lang.value = lang;
+	formObj.backgroundimage.value = background;
+	formObj.insert.value = tinyMCE.getLang('lang_' + action, 'Insert', true); 
+
+	updateColor('bordercolor_pick', 'bordercolor');
+	updateColor('bgcolor_pick', 'bgcolor');
+
+	// Resize some elements
+	if (isVisible('backgroundimagebrowser'))
+		document.getElementById('backgroundimage').style.width = '180px';
+
+	// Disable some fields in update mode
+	if (action == "update") {
+		formObj.cols.disabled = true;
+		formObj.rows.disabled = true;
+	}
+}
+
+function changedSize() {
+	var formObj = document.forms[0];
+	var st = tinyMCE.parseStyle(formObj.style.value);
+
+	var width = formObj.width.value;
+	if (width != "")
+		st['width'] = tinyMCE.getParam("inline_styles") ? getCSSSize(width) : "";
+	else
+		st['width'] = "";
+
+	var height = formObj.height.value;
+	if (height != "")
+		st['height'] = getCSSSize(height);
+	else
+		st['height'] = "";
+
+	formObj.style.value = tinyMCE.serializeStyle(st);
+}
+
+function changedBackgroundImage() {
+	var formObj = document.forms[0];
+	var st = tinyMCE.parseStyle(formObj.style.value);
+
+	st['background-image'] = "url('" + formObj.backgroundimage.value + "')";
+
+	formObj.style.value = tinyMCE.serializeStyle(st);
+}
+
+function changedBorder() {
+	var formObj = document.forms[0];
+	var st = tinyMCE.parseStyle(formObj.style.value);
+
+	// Update border width if the element has a color
+	if (formObj.border.value != "" && formObj.bordercolor.value != "")
+		st['border-width'] = formObj.border.value + "px";
+
+	formObj.style.value = tinyMCE.serializeStyle(st);
+}
+
+function changedColor() {
+	var formObj = document.forms[0];
+	var st = tinyMCE.parseStyle(formObj.style.value);
+
+	st['background-color'] = formObj.bgcolor.value;
+
+	if (formObj.bordercolor.value != "") {
+		st['border-color'] = formObj.bordercolor.value;
+
+		// Add border-width if it's missing
+		if (!st['border-width'])
+			st['border-width'] = formObj.border.value == "" ? "1px" : formObj.border.value + "px";
+	}
+
+	formObj.style.value = tinyMCE.serializeStyle(st);
+}
+
+function changedStyle() {
+	var formObj = document.forms[0];
+	var st = tinyMCE.parseStyle(formObj.style.value);
+
+	if (st['background-image'])
+		formObj.backgroundimage.value = st['background-image'].replace(new RegExp("url\\('?([^']*)'?\\)", 'gi'), "$1");
+	else
+		formObj.backgroundimage.value = '';
+
+	if (st['width'])
+		formObj.width.value = trimSize(st['width']);
+
+	if (st['height'])
+		formObj.height.value = trimSize(st['height']);
+
+	if (st['background-color']) {
+		formObj.bgcolor.value = st['background-color'];
+		updateColor('bgcolor_pick','bgcolor');
+	}
+
+	if (st['border-color']) {
+		formObj.bordercolor.value = st['border-color'];
+		updateColor('bordercolor_pick','bordercolor');
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/table/langs/en.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,79 @@
+// UK lang variables
+
+tinyMCE.addToLang('table',{
+general_tab : 'General',
+advanced_tab : 'Advanced',
+general_props : 'General properties',
+advanced_props : 'Advanced properties',
+desc : 'Inserts a new table',
+row_before_desc : 'Insert row before',
+row_after_desc : 'Insert row after',
+delete_row_desc : 'Delete row',
+col_before_desc : 'Insert column before',
+col_after_desc : 'Insert column after',
+delete_col_desc : 'Remove column',
+rowtype : 'Row in table part',
+title : 'Insert/Modify table',
+width : 'Width',
+height : 'Height',
+cols : 'Columns',
+rows : 'Rows',
+cellspacing : 'Cellspacing',
+cellpadding : 'Cellpadding',
+border : 'Border',
+align : 'Alignment',
+align_default : 'Default',
+align_left : 'Left',
+align_right : 'Right',
+align_middle : 'Center',
+row_title : 'Table row properties',
+cell_title : 'Table cell properties',
+cell_type : 'Cell type',
+row_desc : 'Table row properties',
+cell_desc : 'Table cell properties',
+valign : 'Vertical alignment',
+align_top : 'Top',
+align_bottom : 'Bottom',
+props_desc : 'Table properties',
+bordercolor : 'Border color',
+bgcolor : 'Background color',
+merge_cells_title : 'Merge table cells',
+split_cells_desc : 'Split table cells',
+merge_cells_desc : 'Merge table cells',
+cut_row_desc : 'Cut table row',
+copy_row_desc : 'Copy table row',
+paste_row_before_desc : 'Paste table row before',
+paste_row_after_desc : 'Paste table row after',
+id : 'Id',
+style: 'Style',
+langdir : 'Language direction',
+langcode : 'Language code',
+mime : 'Target MIME type',
+ltr : 'Left to right',
+rtl : 'Right to left',
+bgimage : 'Background image',
+summary : 'Summary',
+td : "Data",
+th : "Header",
+cell_cell : 'Update current cell',
+cell_row : 'Update all cells in row',
+cell_all : 'Update all cells in table',
+row_row : 'Update current row',
+row_odd : 'Update odd rows in table',
+row_even : 'Update even rows in table',
+row_all : 'Update all rows in table',
+thead : 'Table Head',
+tbody : 'Table Body',
+tfoot : 'Table Foot',
+del : 'Delete table',
+scope : 'Scope',
+row : 'Row',
+col : 'Col',
+rowgroup : 'Row Group',
+colgroup : 'Col Group',
+col_limit : 'You\'ve exceeded the maximum number of columns of {$cols}.',
+row_limit : 'You\'ve exceeded the maximum number of rows of {$rows}.',
+cell_limit : 'You\'ve exceeded the maximum number of cells of {$cells}.',
+missing_scope: 'Are you sure you want to continue without specifying a scope for this table header cell. Without it, it may be difficult for some users with disabilities to understand the content or data displayed of the table.',
+caption : 'Table caption'
+});
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/table/merge_cells.htm	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,38 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>{$lang_table_merge_cells_title}</title>
+	<script language="javascript" type="text/javascript" src="../../tiny_mce_popup.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/mctabs.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/validate.js"></script>
+	<script language="javascript" type="text/javascript" src="jscripts/merge_cells.js"></script>
+	<base target="_self" />
+</head>
+<body onload="tinyMCEPopup.executeOnLoad('init();');" style="margin: 8px" style="display: none">
+<form onsubmit="insertTable();return false;" action="#">
+	<fieldset>
+		<legend>{$lang_table_merge_cells_title}</legend>
+		  <table border="0" cellpadding="0" cellspacing="3" width="100%">
+			  <tr>
+				<td>{$lang_table_cols}:</td>
+				<td align="right"><input type="text" name="numcols" value="" class="number min1" style="width: 30px" /></td>
+				<td>
+			  </tr>
+			  <tr>
+				<td>{$lang_table_rows}:</td>
+				<td align="right"><input type="text" name="numrows" value="" class="number min1" style="width: 30px" /></td>
+			  </tr>
+		  </table>
+	</fieldset>
+
+	<div class="mceActionPanel">
+		<div style="float: left">
+			<input type="button" id="insert" name="insert" value="{$lang_update}" onclick="mergeCells();" />
+		</div>
+
+		<div style="float: right">
+			<input type="button" id="cancel" name="cancel" value="{$lang_cancel}" onclick="tinyMCEPopup.close();" />
+		</div>
+	</div>
+</form>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/table/readme.txt	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+Check the TinyMCE documentation for details on this plugin.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/table/row.htm	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,159 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>{$lang_table_row_title}</title>
+	<script language="javascript" type="text/javascript" src="../../tiny_mce_popup.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/mctabs.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/form_utils.js"></script>
+	<script language="javascript" type="text/javascript" src="jscripts/row.js"></script>
+	<link href="css/row.css" rel="stylesheet" type="text/css" />
+	<base target="_self" />
+</head>
+<body id="tablerow" onload="tinyMCEPopup.executeOnLoad('init();');" style="display: none">
+	<form onsubmit="updateAction();return false;">
+		<div class="tabs">
+			<ul>
+				<li id="general_tab" class="current"><span><a href="javascript:mcTabs.displayTab('general_tab','general_panel');" onmousedown="return false;">{$lang_table_general_tab}</a></span></li>
+				<li id="advanced_tab"><span><a href="javascript:mcTabs.displayTab('advanced_tab','advanced_panel');" onmousedown="return false;">{$lang_table_advanced_tab}</a></span></li>
+			</ul>
+		</div>
+
+		<div class="panel_wrapper">
+			<div id="general_panel" class="panel current">
+				<fieldset>
+					<legend>{$lang_table_general_props}</legend>
+
+					<table border="0" cellpadding="4" cellspacing="0">
+						<tr>
+							<td><label for="rowtype">{$lang_table_rowtype}</label></td>
+							<td class="col2">
+								<select id="rowtype" name="rowtype">
+									<option value="thead">{$lang_table_thead}</option>
+									<option value="tbody">{$lang_table_tbody}</option>
+									<option value="tfoot">{$lang_table_tfoot}</option>
+								</select>
+							</td>
+						</tr>
+
+						<tr>
+							<td><label for="align">{$lang_table_align}</label></td>
+							<td class="col2">
+								<select id="align" name="align">
+									<option value="">{$lang_not_set}</option>
+									<option value="center">{$lang_table_align_middle}</option>
+									<option value="left">{$lang_table_align_left}</option>
+									<option value="right">{$lang_table_align_right}</option>
+								</select>
+							</td>
+						</tr>
+
+						<tr>
+							<td><label for="valign">{$lang_table_valign}</label></td>
+							<td class="col2">
+								<select id="valign" name="valign">
+									<option value="">{$lang_not_set}</option>
+									<option value="top">{$lang_table_align_top}</option>
+									<option value="middle">{$lang_table_align_middle}</option>
+									<option value="bottom">{$lang_table_align_bottom}</option>
+								</select>
+							</td>
+						</tr>
+
+						<tr id="styleSelectRow">
+							<td><label for="class">{$lang_class_name}</label></td>
+							<td class="col2">
+								<select id="class" name="class">
+									<option value="" selected="selected">{$lang_not_set}</option>
+								</select>
+							</td>
+						</tr>
+
+						<tr>
+							<td><label for="height">{$lang_table_height}</label></td>
+							<td class="col2"><input name="height" type="text" id="height" value="" size="4" maxlength="4" onchange="changedSize();" /></td>
+						</tr>
+					</table>
+				</fieldset>
+			</div>
+
+			<div id="advanced_panel" class="panel">
+				<fieldset>
+					<legend>{$lang_table_advanced_props}</legend>
+
+					<table border="0" cellpadding="0" cellspacing="4">
+						<tr>
+							<td class="column1"><label for="id">{$lang_table_id}</label></td> 
+							<td><input id="id" name="id" type="text" value="" style="width: 200px" /></td> 
+						</tr>
+
+						<tr>
+							<td><label for="style">{$lang_table_style}</label></td>
+							<td><input type="text" id="style" name="style" value="" style="width: 200px;" onchange="changedStyle();" /></td>
+						</tr>
+
+						<tr>
+							<td class="column1"><label for="dir">{$lang_table_langdir}</label></td> 
+							<td>
+								<select id="dir" name="dir" style="width: 200px"> 
+										<option value="">{$lang_not_set}</option> 
+										<option value="ltr">{$lang_table_ltr}</option> 
+										<option value="rtl">{$lang_table_rtl}</option> 
+								</select>
+							</td> 
+						</tr>
+
+						<tr>
+							<td class="column1"><label for="lang">{$lang_table_langcode}</label></td> 
+							<td>
+								<input id="lang" name="lang" type="text" value="" style="width: 200px" />
+							</td> 
+						</tr>
+
+						<tr>
+							<td class="column1"><label for="backgroundimage">{$lang_table_bgimage}</label></td> 
+							<td>
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input id="backgroundimage" name="backgroundimage" type="text" value="" style="width: 200px" onchange="changedBackgroundImage();" /></td>
+										<td id="backgroundimagebrowsercontainer">&nbsp;</td>
+									</tr>
+								</table>
+							</td> 
+						</tr>
+
+						<tr>
+							<td class="column1"><label for="bgcolor">{$lang_table_bgcolor}</label></td> 
+							<td>
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input id="bgcolor" name="bgcolor" type="text" value="" size="9" onchange="updateColor('bgcolor_pick','bgcolor');changedColor();" /></td>
+										<td id="bgcolor_pickcontainer">&nbsp;</td>
+									</tr>
+								</table>
+							</td> 
+						</tr>
+					</table>
+				</fieldset>
+			</div>
+		</div>
+
+		<div class="mceActionPanel">
+			<div>
+				<select id="action" name="action">
+					<option value="row">{$lang_table_row_row}</option>
+					<option value="odd">{$lang_table_row_odd}</option>
+					<option value="even">{$lang_table_row_even}</option>
+					<option value="all">{$lang_table_row_all}</option>
+				</select>
+			</div>
+
+			<div style="float: left">
+				<div><input type="button" id="insert" name="insert" value="{$lang_update}" onclick="updateAction();" /></div>
+			</div>
+
+			<div style="float: right">
+				<input type="button" id="cancel" name="cancel" value="{$lang_cancel}" onclick="tinyMCEPopup.close();" />
+			</div>
+		</div>
+	</form>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/table/table.htm	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,160 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>{$lang_table_title}</title>
+	<script language="javascript" type="text/javascript" src="../../tiny_mce_popup.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/mctabs.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/form_utils.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/validate.js"></script>
+	<script language="javascript" type="text/javascript" src="jscripts/table.js"></script>
+	<link href="css/table.css" rel="stylesheet" type="text/css" />
+	<base target="_self" />
+</head>
+<body id="table" onload="tinyMCEPopup.executeOnLoad('init();');" style="display: none">
+	<form onsubmit="insertTable();return false;" action="#">
+		<div class="tabs">
+			<ul>
+				<li id="general_tab" class="current"><span><a href="javascript:mcTabs.displayTab('general_tab','general_panel');" onmousedown="return false;">{$lang_table_general_tab}</a></span></li>
+				<li id="advanced_tab"><span><a href="javascript:mcTabs.displayTab('advanced_tab','advanced_panel');" onmousedown="return false;">{$lang_table_advanced_tab}</a></span></li>
+			</ul>
+		</div>
+
+		<div class="panel_wrapper">
+			<div id="general_panel" class="panel current">
+				<fieldset>
+					<legend>{$lang_table_general_props}</legend>
+
+					  <table border="0" cellpadding="4" cellspacing="0" width="100%">
+							  <tr>
+								<td><label id="colslabel" for="cols">{$lang_table_cols}</label></td>
+								<td><input id="cols" name="cols" type="text" value="" size="3" maxlength="3" class="required number min1" /></td>
+								<td><label id="rowslabel" for="rows">{$lang_table_rows}</label></td>
+								<td><input id="rows" name="rows" type="text" value="" size="3" maxlength="3" class="required number min1" /></td>
+							  </tr>
+							  <tr>
+								<td><label id="cellpaddinglabel" for="cellpadding">{$lang_table_cellpadding}</label></td>
+								<td><input id="cellpadding" name="cellpadding" type="text" value="" size="3" maxlength="3" class="number" /></td>
+								<td><label id="cellspacinglabel" for="cellspacing">{$lang_table_cellspacing}</label></td>
+								<td><input id="cellspacing" name="cellspacing" type="text" value="" size="3" maxlength="3" class="number" /></td>
+							  </tr>
+							  <tr>
+								<td><label id="alignlabel" for="align">{$lang_table_align}</label></td>
+								<td><select id="align" name="align">
+									<option value="">{$lang_not_set}</option>
+									<option value="center">{$lang_table_align_middle}</option>
+									<option value="left">{$lang_table_align_left}</option>
+									<option value="right">{$lang_table_align_right}</option>
+								  </select></td>
+								<td><label id="borderlabel" for="border">{$lang_table_border}</label></td>
+								<td><input id="border" name="border" type="text" value="" size="3" maxlength="3" onchange="changedBorder();" class="number" /></td>
+							  </tr>
+							  <tr id="width_row">
+								<td><label id="widthlabel" for="width">{$lang_table_width}</label></td>
+								<td><input name="width" type="text" id="width" value="" size="4" maxlength="4" onchange="changedSize();" class="size" /></td>
+								<td><label id="heightlabel" for="height">{$lang_table_height}</label></td>
+								<td><input name="height" type="text" id="height" value="" size="4" maxlength="4" onchange="changedSize();" class="size" /></td>
+							  </tr>
+							  <tr id="styleSelectRow">
+								<td><label id="classlabel" for="class">{$lang_class_name}</label></td>
+								<td colspan="3">
+								 <select id="class" name="class">
+									<option value="" selected>{$lang_not_set}</option>
+								 </select></td>
+							  </tr>
+							  <tr>
+								<td class="column1"><label for="caption">{$lang_table_caption}</label></td> 
+								<td><input id="caption" name="caption" type="checkbox" value="true" /></td> 
+							  </tr>
+							</table>
+				</fieldset>
+			</div>
+
+			<div id="advanced_panel" class="panel">
+				<fieldset>
+					<legend>{$lang_table_advanced_props}</legend>
+
+					<table border="0" cellpadding="0" cellspacing="4">
+						<tr>
+							<td class="column1"><label for="id">{$lang_table_id}</label></td> 
+							<td><input id="id" name="id" type="text" value="" class="advfield" /></td> 
+						</tr>
+
+						<tr>
+							<td class="column1"><label for="summary">{$lang_table_summary}</label></td> 
+							<td><input id="summary" name="summary" type="text" value="" class="advfield" /></td> 
+						</tr>
+
+						<tr>
+							<td><label for="style">{$lang_table_style}</label></td>
+							<td><input type="text" id="style" name="style" value="" class="advfield" onchange="changedStyle();" /></td>
+						</tr>
+
+						<tr>
+							<td class="column1"><label for="dir">{$lang_table_langdir}</label></td> 
+							<td>
+								<select id="dir" name="dir" class="advfield"> 
+										<option value="">{$lang_not_set}</option> 
+										<option value="ltr">{$lang_table_ltr}</option> 
+										<option value="rtl">{$lang_table_rtl}</option> 
+								</select>
+							</td> 
+						</tr>
+
+						<tr>
+							<td class="column1"><label id="langlabel" for="lang">{$lang_table_langcode}</label></td> 
+							<td>
+								<input id="lang" name="lang" type="text" value="" class="advfield" />
+							</td> 
+						</tr>
+
+						<tr>
+							<td class="column1"><label for="backgroundimage">{$lang_table_bgimage}</label></td> 
+							<td>
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input id="backgroundimage" name="backgroundimage" type="text" value="" class="advfield" onchange="changedBackgroundImage();" /></td>
+										<td id="backgroundimagebrowsercontainer">&nbsp;</td>
+									</tr>
+								</table>
+							</td> 
+						</tr>
+
+						<tr>
+							<td class="column1"><label for="bordercolor">{$lang_table_bordercolor}</label></td> 
+							<td>
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input id="bordercolor" name="bordercolor" type="text" value="" size="9" onchange="updateColor('bordercolor_pick','bordercolor');changedColor();" /></td>
+										<td id="bordercolor_pickcontainer">&nbsp;</td>
+									</tr>
+								</table>
+							</td> 
+						</tr>
+
+						<tr>
+							<td class="column1"><label for="bgcolor">{$lang_table_bgcolor}</label></td> 
+							<td>
+								<table border="0" cellpadding="0" cellspacing="0">
+									<tr>
+										<td><input id="bgcolor" name="bgcolor" type="text" value="" size="9" onchange="updateColor('bgcolor_pick','bgcolor');changedColor();" /></td>
+										<td id="bgcolor_pickcontainer">&nbsp;</td>
+									</tr>
+								</table>
+							</td> 
+						</tr>
+					</table>
+				</fieldset>
+			</div>
+		</div>
+
+		<div class="mceActionPanel">
+			<div style="float: left">
+				<input type="button" id="insert" name="insert" value="{$lang_insert}" onclick="insertTable();" />
+			</div>
+
+			<div style="float: right">
+				<input type="button" id="cancel" name="cancel" value="{$lang_cancel}" onclick="tinyMCEPopup.close();" />
+			</div>
+		</div>
+	</form>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/template/blank.htm	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,23 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>blank_page</title>
+	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+	<script type="text/javascript">
+		var tinyMCE = parent.tinyMCE, css = tinyMCE.getParam("content_css").split(','), i, u;
+
+		// Load content CSS files
+		for (i=0; i<css.length; i++) {
+			u = css[i];
+
+			// Fix relative
+			if (u.charAt(0) != '/' && u.indexOf('://') == -1)
+				u = tinyMCE.documentBasePath + "/" + u;
+
+			document.write('<link href="' + u + '" rel="stylesheet" type="text/css" />');
+		}
+	</script>
+</head>
+<body id="mceTemplatePreview">
+
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/template/css/template.css	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,23 @@
+#frmbody {
+	padding: 10px;
+	background-color: #FFF;
+	border: 1px solid #CCC;
+}
+
+.frmRow {
+	margin-bottom: 10px;
+}
+
+#templatesrc {
+	border: none;
+	width: 320px;
+	height: 240px;
+}
+
+.title {
+	padding-bottom: 5px;
+}
+
+.mceActionPanel {
+	padding-top: 5px;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/template/editor_plugin.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+tinyMCE.importPluginLanguagePack('template');var TinyMCE_TemplatePlugin={getInfo:function(){return{longname:'Template plugin',author:'Moxiecode Systems AB',authorurl:'http://www.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/template',version:tinyMCE.majorVersion+"."+tinyMCE.minorVersion}},initInstance:function(inst){var cdate,mdate,content,x=0,key,value,rvals,ds=inst.getData('template');cdate=tinyMCE.getParam("template_cdate_classes",'').split(/\s+/);mdate=tinyMCE.getParam("template_mdate_classes",'').split(/\s+/);content=tinyMCE.getParam("template_selected_content_classes",'').split(/\s+/);for(x=0;x<cdate.length;x++)TinyMCE_TemplatePlugin.functions[cdate[x]]=TinyMCE_TemplatePlugin.functions['cdate'];for(x=0;x<mdate.length;x++)TinyMCE_TemplatePlugin.functions[mdate[x]]=TinyMCE_TemplatePlugin.functions['mdate'];for(x=0;x<content.length;x++)TinyMCE_TemplatePlugin.functions[content[x]]=TinyMCE_TemplatePlugin.functions['selectedContent'];rvals=tinyMCE.getParam("template_replace_values",false);for(key in rvals){value=rvals[key];if(typeof value=="function")TinyMCE_TemplatePlugin.functions[key]=value;else TinyMCE_TemplatePlugin.functions[key]=TinyMCE_TemplatePlugin.functions['generateReplacer'](value)}rvals=tinyMCE.getParam("template_replace_values",false);ds.replace_items={};for(key in rvals)ds.replace_items[key]=rvals[key];inst.addShortcut('ctrl','t','lang_template_desc','mceTemplate');ds.currentAction="insert";ds.currentTmplNode=null},getControlHTML:function(cn){switch(cn){case"template":return tinyMCE.getButtonHTML(cn,'lang_template_desc','{$pluginurl}/images/template.gif','mceTemplate',true)}return""},execCommand:function(editor_id,element,command,user_interface,value){var nodeArray,current,newTmpl,x,inst=tinyMCE.getInstanceById(editor_id),ds=inst.getData('template'),telm;switch(command){case"mceTemplate":if(user_interface){tinyMCE.openWindow({file:'../../plugins/template/template.htm',width:tinyMCE.getParam('template_popup_width',750),height:tinyMCE.getParam('template_popup_height',600)},{editor_id:editor_id,resizable:"yes",scrollbars:"no",pluginObj:TinyMCE_TemplatePlugin})}else{telm=TinyMCE_TemplatePlugin._convertToNode(value.body);nodeArray=tinyMCE.selectElements(telm,'div',function(n){return tinyMCE.hasCSSClass(n,TinyMCE_TemplatePlugin.TMPL)});telm=nodeArray.length>0?nodeArray[0]:null;nodeArray=[];if(ds.currentAction=="insert"){if(telm){tinyMCE.execCommand('mceBeginUndoLevel');ds.currentAction="insert-new";TinyMCE_TemplatePlugin._insertTemplate(editor_id,telm,value.title,value.tsrc,true);ds.currentAction=="insert";tinyMCE.execCommand('mceEndUndoLevel');tinyMCE.execInstanceCommand(editor_id,'mceCleanup',false)}else tinyMCE.execCommand('mceInsertContent',false,this._replaceValues(value.body))}else{nodeArray=TinyMCE_TemplatePlugin._collectTemplateElements(ds.currentTmplNode);current=[];newTmpl=[];tinyMCE.getNodeTree(telm,newTmpl);for(x=0;x<nodeArray.length;x++)tinyMCE.getNodeTree(nodeArray[x],current);var _test=function(elm){var replaced=true;if(elm.className){var names=elm.className.split(/\s+/),c,n;for(c=0;c<names.length;c++){if(names[c].match(/^mce/i))continue;for(n=0;n<newTmpl.length;n++){replaced=false;if(newTmpl[n].className&&newTmpl[n].className.match(new RegExp(names[c],"gi"))){newTmpl[n].innerHTML=elm.innerHTML;replaced=true;break}}}}return replaced};var cont=true;var asked=false;for(x=0;x<current.length;x++){if(!_test(current[x])){cont=(asked||confirm("The new template has less elements than the currently selected content.\nIf you proceed you will loose content.\nAre you sure you want to proceed?","Proceed?"));asked=true;if(!cont)break}};if(cont){tinyMCE.execCommand('mceBeginUndoLevel');TinyMCE_TemplatePlugin._replaceTemplateContent(current[0],editor_id,telm,value.title,value.tsrc);tinyMCE.execCommand('mceEndUndoLevel');tinyMCE.execInstanceCommand(editor_id,'mceCleanup',false)}}tinyMCE.triggerNodeChange(true)}return true}return false},handleNodeChange:function(editor_id,node,undo_index,undo_levels,visual_aid,any_selection){var inst=tinyMCE.getInstanceById(editor_id),ds=inst.getData('template');if(tinyMCE.hasCSSClass(node,TinyMCE_TemplatePlugin.TMPL_ELEMENT)||tinyMCE.hasCSSClass(node.parentNode,TinyMCE_TemplatePlugin.TMPL_ELEMENT)){tinyMCE.switchClass(editor_id+'_template','mceButtonSelected');ds.currentAction="update";ds.currentTmplNode=node;return true}ds.currentAction="insert";ds.currentTmplNode=null;tinyMCE.switchClass(editor_id+'_template','mceButtonNormal');return false},cleanup:function(type,content,inst){var nodes=[];switch(type){case"get_from_editor":content=content.replace(new RegExp('<div class="'+TinyMCE_TemplatePlugin.TMPL+'">','gi'),'<!-- '+TinyMCE_TemplatePlugin.TMPL_BEGINS+' -->');content=content.replace(new RegExp('<div class="'+TinyMCE_TemplatePlugin.TMPL+'">(\s|&nbsp;|&#160;)?(<!-- '+TinyMCE_TemplatePlugin.TMPL_ENDS+' -->|\s)?</div>','gi'),'');content=content.replace(new RegExp('<!-- '+TinyMCE_TemplatePlugin.TMPL_ENDS+' --></div>','gi'),'<!-- '+TinyMCE_TemplatePlugin.TMPL_ENDS+' -->');break;case"insert_to_editor":content=content.replace(new RegExp('<!-- '+TinyMCE_TemplatePlugin.TMPL_BEGINS+' -->','gi'),'<div class="'+TinyMCE_TemplatePlugin.TMPL+'">');content=content.replace(new RegExp('<!-- '+TinyMCE_TemplatePlugin.TMPL_ENDS+' -->','gi'),'<!-- '+TinyMCE_TemplatePlugin.TMPL_ENDS+' --></div>');break;case"get_from_editor_dom":nodes=tinyMCE.selectNodes(content,function(n){return tinyMCE.hasCSSClass(n,TinyMCE_TemplatePlugin.TMPL_ELEMENT)});TinyMCE_TemplatePlugin._applyFunctions(nodes,type);break;case"insert_to_editor_dom":nodes=tinyMCE.selectNodes(content,function(n){return tinyMCE.hasCSSClass(n,TinyMCE_TemplatePlugin.TMPL_ELEMENT)});TinyMCE_TemplatePlugin._applyFunctions(nodes,type);break}return content},_convertToNode:function(html){var elm=document.createElement('div');elm.innerHTML=html;return elm},_prepareTemplateContent:function(elms){var x,n,nodes=[];if(!elms)return{};if(!elms.length)elms=[elms];for(x=0;x<elms.length;x++)tinyMCE.getNodeTree(elms[x],nodes,1);for(n=0;n<nodes.length;n++){tinyMCE.addCSSClass(nodes[n],TinyMCE_TemplatePlugin.TMPL_ELEMENT);TinyMCE_TemplatePlugin._applyFunctions(nodes[n],TinyMCE_TemplatePlugin.TMPL_TEMPLATE_EVENT)}return elms},_replaceValues:function(s){var t=this,ds=tinyMCE.selectedInstance.getData('template');return s.replace(/\{\$([^\}]+)\}/g,function(a,b){var it=ds.replace_items[b];if(it){if(typeof(it)!='function')return it}return b})},_applyFunctions:function(elms,editor_event){var x,elm,names,c,f;if(!elms)return{};if(!elms.length)elms=[elms];for(x=0;x<elms.length;x++){elm=elms[x];if(elm.className){names=elm.className.split(/\s+/);for(c=0;c<names.length;c++){if(names[c]==TinyMCE_TemplatePlugin.TMPL_ELEMENT)continue;f=(TinyMCE_TemplatePlugin.functions[names[c]]?TinyMCE_TemplatePlugin.functions[names[c]]:TinyMCE_TemplatePlugin.functions['blank']);f(elm,editor_event)}}}return elms},_collectTemplateElements:function(node){var nodeArray=[],p;p=tinyMCE.getParentElement(node,'DIV',function(n){return tinyMCE.hasCSSClass(n,TinyMCE_TemplatePlugin.TMPL)});if(p)tinyMCE.getNodeTree(p,nodeArray);return nodeArray},_replaceTemplateContent:function(currentNode,editor_id,newTemplate,title,tsrc){TinyMCE_TemplatePlugin._deleteTemplateContent(currentNode);TinyMCE_TemplatePlugin._insertTemplate(editor_id,newTemplate,title,tsrc,false)},_deleteTemplateContent:function(node){var p=tinyMCE.getParentElement(node,'DIV',function(n){return tinyMCE.hasCSSClass(n,TinyMCE_TemplatePlugin.TMPL)});if(p)p.parentNode.removeChild(p,true)},_insertTemplate:function(editor_id,elm,title,tsrc,incComments){var html;TinyMCE_TemplatePlugin._prepareTemplateContent(elm);html='<div class="'+TinyMCE_TemplatePlugin.TMPL+'">';html+=elm.innerHTML;html+='<!-- '+TinyMCE_TemplatePlugin.TMPL_ENDS+' --></div>';tinyMCE.execInstanceCommand(editor_id,'mceInsertContent',false,html)},functions:{blank:function(elm,editor_event){},cdate:function(elm,editor_event){var d,dsrc;if(editor_event!=TinyMCE_TemplatePlugin.TMPL_TEMPLATE_EVENT)return;d=new Date();dsrc=elm.innerHTML.match(new RegExp("<!-- "+TinyMCE_TemplatePlugin.TMPL_DATE_SRC_ATTR+":(.*)  -->","gi"));if(dsrc)d=new Date(RegExp.$1);elm.innerHTML=TinyMCE_TemplatePlugin._getDateTime(d,tinyMCE.getParam("template_cdate_format",tinyMCE.getLang("lang_template_def_date_format")));elm.innerHTML+="<!-- "+TinyMCE_TemplatePlugin.TMPL_DATE_SRC_ATTR+":"+d.toUTCString()+"  -->"},mdate:function(elm,editor_event){var d=new Date();elm.innerHTML=TinyMCE_TemplatePlugin._getDateTime(d,tinyMCE.getParam("template_mdate_format",tinyMCE.getLang("lang_template_def_date_format")))},selectedContent:function(elm,editor_event){var ds=tinyMCE.selectedInstance.getData('template');if(editor_event!=TinyMCE_TemplatePlugin.TMPL_TEMPLATE_EVENT)return;if(ds.currentAction=="insert-new"&&!tinyMCE.hasCSSClass(elm,TinyMCE_TemplatePlugin.TMPL_SEL_HTML_DONE)){elm.innerHTML=tinyMCE.selectedInstance.selection.getSelectedHTML();tinyMCE.addCSSClass(elm,TinyMCE_TemplatePlugin.TMPL_SEL_HTML_DONE)}},generateReplacer:function(s){return function(elm,editor_event){elm.innerHTML=""+s}}},_getDateTime:function(d,fmt){if(!fmt)return"";function addZeros(value,len){var i;value=""+value;if(value.length<len){for(i=0;i<(len-value.length);i++)value="0"+value}return value}fmt=fmt.replace("%D","%m/%d/%y");fmt=fmt.replace("%r","%I:%M:%S %p");fmt=fmt.replace("%Y",""+d.getFullYear());fmt=fmt.replace("%y",""+d.getYear());fmt=fmt.replace("%m",addZeros(d.getMonth()+1,2));fmt=fmt.replace("%d",addZeros(d.getDate(),2));fmt=fmt.replace("%H",""+addZeros(d.getHours(),2));fmt=fmt.replace("%M",""+addZeros(d.getMinutes(),2));fmt=fmt.replace("%S",""+addZeros(d.getSeconds(),2));fmt=fmt.replace("%I",""+((d.getHours()+11)%12+1));fmt=fmt.replace("%p",""+(d.getHours()<12?"AM":"PM"));fmt=fmt.replace("%B",""+tinyMCE.getLang("lang_template_months_long")[d.getMonth()]);fmt=fmt.replace("%b",""+tinyMCE.getLang("lang_template_months_short")[d.getMonth()]);fmt=fmt.replace("%A",""+tinyMCE.getLang("lang_template_day_long")[d.getDay()]);fmt=fmt.replace("%a",""+tinyMCE.getLang("lang_template_day_short")[d.getDay()]);fmt=fmt.replace("%%","%");return fmt},TMPL_ELEMENT:'mceTmplElm',TMPL:'mceTmpl',TMPL_BEGINS:'mceTmplBegins',TMPL_SEL_HTML_DONE:'mceSelHTMLDone',TMPL_ENDS:'mceTmplEnds',TMPL_DATE_SRC_ATTR:'mcetmpldtesrc',TMPL_TEMPLATE_EVENT:'prepare_template'};tinyMCE.addPlugin("template",TinyMCE_TemplatePlugin);
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/template/editor_plugin_src.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,551 @@
+/**
+ * $Id: editor_plugin_src.js 162 2007-01-03 16:16:52Z spocke $
+ *
+ * @author Moxiecode
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+tinyMCE.importPluginLanguagePack('template');
+
+var TinyMCE_TemplatePlugin = {
+	getInfo : function() {
+		return {
+			longname : 'Template plugin',
+			author : 'Moxiecode Systems AB',
+			authorurl : 'http://www.moxiecode.com',
+			infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/template',
+			version : tinyMCE.majorVersion + "." + tinyMCE.minorVersion
+		};
+	},
+
+	initInstance : function(inst) {
+		var cdate, mdate, content, x = 0, key, value, rvals, ds = inst.getData('template');
+
+		// ensure the required elements and sttributes are added
+		//inst.cleanup.addRuleStr('*[' + TinyMCE_TemplatePlugin.TMPL_DATE_SRC_ATTR + '],div[title,tsrc]');
+
+		//setup template content functions
+		// creation date and modified date classes
+		cdate = tinyMCE.getParam("template_cdate_classes", '').split(/\s+/);
+		mdate = tinyMCE.getParam("template_mdate_classes", '').split(/\s+/);
+
+		// classes that specify where selected content should go
+		content = tinyMCE.getParam("template_selected_content_classes", '').split(/\s+/);
+
+		for (x = 0; x < cdate.length; x++)
+			TinyMCE_TemplatePlugin.functions[cdate[x]] = TinyMCE_TemplatePlugin.functions['cdate'];	
+
+		for (x = 0; x < mdate.length; x++)
+			TinyMCE_TemplatePlugin.functions[mdate[x]] = TinyMCE_TemplatePlugin.functions['mdate'];
+
+		for (x = 0; x < content.length; x++)
+			TinyMCE_TemplatePlugin.functions[content[x]] = TinyMCE_TemplatePlugin.functions['selectedContent'];
+
+		// special template functions for replacing template content
+		rvals = tinyMCE.getParam("template_replace_values", false);
+		for (key in rvals) {
+			value = rvals[key];
+
+			if (typeof value == "function")
+				TinyMCE_TemplatePlugin.functions[key] = value;
+			else
+				TinyMCE_TemplatePlugin.functions[key] = TinyMCE_TemplatePlugin.functions['generateReplacer'](value);
+		}
+
+		// Setup replace_items
+		rvals = tinyMCE.getParam("template_replace_values", false);
+		ds.replace_items = {};
+
+		for (key in rvals)
+			ds.replace_items[key] = rvals[key];
+
+		inst.addShortcut('ctrl', 't', 'lang_template_desc', 'mceTemplate');
+
+		// Setup data storage
+		ds.currentAction = "insert";
+		ds.currentTmplNode = null;
+	},
+
+	getControlHTML : function(cn) {
+		switch (cn) {
+			case "template":
+				return tinyMCE.getButtonHTML(cn, 'lang_template_desc', '{$pluginurl}/images/template.gif', 'mceTemplate', true);
+		}
+
+		return "";
+	},
+
+	execCommand : function(editor_id, element, command, user_interface, value) {
+		var nodeArray, current, newTmpl, x, inst = tinyMCE.getInstanceById(editor_id), ds = inst.getData('template'), telm;
+
+		switch (command) {
+			case "mceTemplate":
+				if (user_interface) {
+					// called from toolbar button - show the popup
+					tinyMCE.openWindow({
+						file : '../../plugins/template/template.htm', // Relative to theme
+						width : tinyMCE.getParam('template_popup_width', 750),
+						height : tinyMCE.getParam('template_popup_height', 600)
+					}, {editor_id : editor_id, resizable : "yes", scrollbars : "no", pluginObj : TinyMCE_TemplatePlugin});
+				} else {
+					// internal command do the template stuff
+
+					// get the returned HTML string from the pop-up and appened it to a DIV element
+					telm = TinyMCE_TemplatePlugin._convertToNode(value.body);
+
+					// Find template body
+					nodeArray = tinyMCE.selectElements(telm, 'div', function(n) {
+						return tinyMCE.hasCSSClass(n, TinyMCE_TemplatePlugin.TMPL);
+					});
+
+					telm = nodeArray.length > 0 ? nodeArray[0] : null;
+					nodeArray = [];
+
+					if (ds.currentAction == "insert") {
+						//insert new template after applying all the template content functions
+
+						// Is it a template or snippet
+						if (telm) {
+							tinyMCE.execCommand('mceBeginUndoLevel');
+							ds.currentAction = "insert-new";
+							TinyMCE_TemplatePlugin._insertTemplate(editor_id, telm, value.title, value.tsrc, true);
+							ds.currentAction == "insert";
+							tinyMCE.execCommand('mceEndUndoLevel');
+							tinyMCE.execInstanceCommand(editor_id, 'mceCleanup', false);
+						} else
+							tinyMCE.execCommand('mceInsertContent', false, this._replaceValues(value.body));
+					} else {
+						// First collect the selected template in the editor
+						nodeArray = TinyMCE_TemplatePlugin._collectTemplateElements(ds.currentTmplNode);
+						current = [];
+						newTmpl = [];
+						tinyMCE.getNodeTree(telm, newTmpl);
+
+						for (x=0; x<nodeArray.length; x++)
+							tinyMCE.getNodeTree(nodeArray[x], current);
+
+						/** 
+						 * inner function used in the loop below.
+						 * compares the supplied HTML element to the new template to:
+						 * - find a match with the new template and copy the element's content over
+						 * - find no match and indicate content will be lost
+						 */
+						var _test = function(elm) {
+							var replaced = true;
+
+							if (elm.className) {
+								var names = elm.className.split(/\s+/), c, n;
+
+								for (c = 0; c<names.length; c++) {
+									if (names[c].match(/^mce/i))
+										continue; // ignore all internal class names
+
+									for (n=0; n<newTmpl.length; n++){
+										replaced = false;
+
+										if (newTmpl[n].className && newTmpl[n].className.match(new RegExp(names[c], "gi"))) {
+											newTmpl[n].innerHTML = elm.innerHTML;
+											//if(tinyMCE.getAttrib(elm,TinyMCE_TemplatePlugin.TMPL_DATE_SRC_ATTR,"") != "") {
+											//	tinyMCE.setAttrib(newTmpl[n], TinyMCE_TemplatePlugin.TMPL_DATE_SRC_ATTR, tinyMCE.getAttrib(elm,TinyMCE_TemplatePlugin.TMPL_DATE_SRC_ATTR)); 
+											//}
+											replaced = true;
+											break;
+										}
+
+									}
+								}
+							}
+	
+							return replaced;
+						};
+
+						// comparison loop - first mis-match alerts user for confirmation.
+						var cont = true;
+						var asked = false;
+
+						for (x = 0; x < current.length; x++) {
+							if(!_test(current[x])) {
+								cont = (asked || confirm("The new template has less elements than the currently selected content.\nIf you proceed you will loose content.\nAre you sure you want to proceed?", "Proceed?"));
+								asked = true;
+
+								if (!cont)
+									break;
+							}
+						};
+
+						// apply replacement if allowed to
+						if (cont) {
+							tinyMCE.execCommand('mceBeginUndoLevel');
+							TinyMCE_TemplatePlugin._replaceTemplateContent(current[0], editor_id, telm, value.title, value.tsrc);
+							tinyMCE.execCommand('mceEndUndoLevel');
+							tinyMCE.execInstanceCommand(editor_id, 'mceCleanup', false);
+						}
+					}
+
+					tinyMCE.triggerNodeChange(true);
+				}
+
+				return true;
+		}
+
+		return false;
+	},
+
+	handleNodeChange : function(editor_id, node, undo_index, undo_levels, visual_aid, any_selection) {
+		var inst = tinyMCE.getInstanceById(editor_id), ds = inst.getData('template');
+
+		if (tinyMCE.hasCSSClass(node, TinyMCE_TemplatePlugin.TMPL_ELEMENT) || tinyMCE.hasCSSClass(node.parentNode, TinyMCE_TemplatePlugin.TMPL_ELEMENT)) {
+			tinyMCE.switchClass(editor_id + '_template', 'mceButtonSelected');
+			ds.currentAction = "update";
+			ds.currentTmplNode = node;
+
+			return true;
+		}
+
+		ds.currentAction = "insert";
+		ds.currentTmplNode = null;
+		tinyMCE.switchClass(editor_id + '_template', 'mceButtonNormal');
+
+		return false;
+	},
+
+	cleanup : function(type, content, inst) {
+		var nodes = [];
+
+		switch (type) {
+			case "get_from_editor":
+				// replace the opening wrapper div tag with a HTML comment
+				content = content.replace(
+					new RegExp('<div class="' + TinyMCE_TemplatePlugin.TMPL + '">', 'gi'),
+					'<!-- ' + TinyMCE_TemplatePlugin.TMPL_BEGINS + ' -->'
+				);
+
+				// delete any empty template wrappers
+				content = content.replace(
+					new RegExp('<div class="' + TinyMCE_TemplatePlugin.TMPL + '">(\s|&nbsp;|&#160;)?(<!-- ' + TinyMCE_TemplatePlugin.TMPL_ENDS + ' -->|\s)?</div>', 'gi'),
+					''
+				);
+
+				// replace the closing wrapper tag
+				content = content.replace(
+					new RegExp('<!-- ' + TinyMCE_TemplatePlugin.TMPL_ENDS + ' --></div>', 'gi'),
+					'<!-- ' + TinyMCE_TemplatePlugin.TMPL_ENDS + ' -->'
+				);
+
+				break;
+
+			case "insert_to_editor":
+				// replace HTML comment with DIV wrapper
+				content = content.replace(
+					new RegExp('<!-- ' + TinyMCE_TemplatePlugin.TMPL_BEGINS + ' -->', 'gi'),
+					'<div class="' + TinyMCE_TemplatePlugin.TMPL + '">'
+				);
+
+				content = content.replace(
+					new RegExp('<!-- ' + TinyMCE_TemplatePlugin.TMPL_ENDS + ' -->', 'gi'),
+					'<!-- ' + TinyMCE_TemplatePlugin.TMPL_ENDS + ' --></div>'
+				);
+
+				break;
+
+			case "get_from_editor_dom":
+				// apply template content replacement functions
+				nodes = tinyMCE.selectNodes(content, function(n) {
+						return tinyMCE.hasCSSClass(n, TinyMCE_TemplatePlugin.TMPL_ELEMENT);
+					}
+				);
+
+				TinyMCE_TemplatePlugin._applyFunctions(nodes, type);
+
+				break;
+
+			case "insert_to_editor_dom":
+				// apply template content replacement functions
+				nodes = tinyMCE.selectNodes(content, function(n) {
+						return tinyMCE.hasCSSClass(n, TinyMCE_TemplatePlugin.TMPL_ELEMENT);
+					}
+				);
+
+				TinyMCE_TemplatePlugin._applyFunctions(nodes, type);
+
+				break;
+		}
+
+		return content;
+	},
+
+	// Private plugin internal methods
+
+	/**
+	 * Creates a HTML DIV element and sets the innerHTML to equal the temlate innerHTML so that the template can be manipulated as DOM nodes.
+	 *
+	 * @param {string} Template innerHTML
+	 * @return a HTML Element
+	 * @type HTMLElement
+	 */
+	_convertToNode : function(html) {
+		var elm = document.createElement('div');
+
+		elm.innerHTML = html;
+
+		return elm;
+	},
+
+	/**
+	 * pass an array of template html elements and they will have the template class name added and any template functions applied
+	 *
+	 * @param {array} template HTML elements
+	 * @return array of template HTML elements
+	 * @type array
+	 */
+	_prepareTemplateContent : function(elms) {
+		var x, n, nodes = [];
+
+		if (!elms)
+			return {};
+
+		if (!elms.length)
+			elms = [elms];
+
+		for (x = 0; x<elms.length; x++)
+			tinyMCE.getNodeTree(elms[x], nodes, 1);
+
+		for (n = 0; n<nodes.length; n++) {
+			tinyMCE.addCSSClass(nodes[n], TinyMCE_TemplatePlugin.TMPL_ELEMENT);
+			TinyMCE_TemplatePlugin._applyFunctions(nodes[n], TinyMCE_TemplatePlugin.TMPL_TEMPLATE_EVENT);
+		}
+
+		return elms;
+	},
+
+	_replaceValues : function(s) {
+		var t = this, ds = tinyMCE.selectedInstance.getData('template');
+
+		return s.replace(/\{\$([^\}]+)\}/g, function(a, b) {
+			var it = ds.replace_items[b];
+
+			if (it) {
+				// Only supports text for now
+				if (typeof(it) != 'function')
+					return it;
+			}
+
+			return b;
+		});
+	},
+
+	/**
+	 * Applies any special functions to the template elements
+	 *
+	 * @param {array} template HTML elements
+	 * @return array of template HTML elements
+	 * @type array
+	 */
+	_applyFunctions : function(elms, editor_event) {
+		var x, elm, names, c, f;
+
+		if (!elms)
+			return {};
+
+		if (!elms.length)
+			elms = [elms];
+
+		for(x = 0; x < elms.length; x++) {
+			elm = elms[x];
+
+			if (elm.className){
+				names = elm.className.split(/\s+/);
+
+				for (c = 0; c < names.length; c++){
+					if (names[c] == TinyMCE_TemplatePlugin.TMPL_ELEMENT)
+						continue;
+
+					f = (TinyMCE_TemplatePlugin.functions[names[c]] ? TinyMCE_TemplatePlugin.functions[names[c]] : TinyMCE_TemplatePlugin.functions['blank']);
+					f(elm, editor_event);
+				}
+			}
+		}
+
+		return elms;
+	},
+
+	/**
+	 * Given one node reference this function will collect all the nodes of the template to which it belongs.
+	 * It does this by finding the parent template wrapper DIV and returning all child nodes.
+	 *
+	 * @param {HTMLElement} a HTMLElement which is part of a template
+	 * @return array of template HTML elements
+	 * @type array
+	 */
+	_collectTemplateElements : function(node) {
+		var nodeArray = [], p;
+
+		p = tinyMCE.getParentElement(node, 'DIV', function(n) {
+			return tinyMCE.hasCSSClass(n, TinyMCE_TemplatePlugin.TMPL);
+		});
+
+		if (p)
+			tinyMCE.getNodeTree(p, nodeArray);
+
+		return nodeArray;
+	},
+
+	/**
+	 * Simply calls TinyMCE_TemplatePlugin._deleteTemplateContent and then TinyMCE_TemplatePlugin._insertTemplate
+	 *
+	 * @param {HTMLElement} currently selected template node in editor
+	 * @param {string} id of editor instance
+	 * @param {HTMLElement} template contents as a HTMLElement (the parent DIV wrapper)
+	 * @param {string} title of template (unused as yet)
+	 * @param {string} source URI of the template file (unused as yet)
+	 * @return array of template HTML elements
+	 * @type array
+	 */
+	_replaceTemplateContent : function(currentNode, editor_id, newTemplate, title, tsrc) {
+		TinyMCE_TemplatePlugin._deleteTemplateContent(currentNode);
+		TinyMCE_TemplatePlugin._insertTemplate(editor_id, newTemplate, title, tsrc, false);
+	},
+
+	/**
+	 * Deletes a template from the editor content
+	 * Finds the parent DIV wrapper and deletes it and all children
+	 * @param {HTMLElement} currently selected template node in editor
+	 */
+	_deleteTemplateContent : function(node) {
+		var p = tinyMCE.getParentElement(node, 'DIV', function(n) {
+			return tinyMCE.hasCSSClass(n, TinyMCE_TemplatePlugin.TMPL);
+		});
+
+		if (p)
+			p.parentNode.removeChild(p, true);
+	},
+
+	/**
+	 *  Inserts a template into the specified editor
+	 *
+	 * @param {string} id of editor instance
+	 * @param {HTMLElement} template contents as a HTMLElement (the parent DIV wrapper)
+	 * @param {string} title of template (unused as yet)
+	 * @param {string} source URI of the template file (unused as yet)
+	 */
+	_insertTemplate : function(editor_id, elm, title, tsrc, incComments) {
+		var html;
+
+		TinyMCE_TemplatePlugin._prepareTemplateContent(elm);
+
+		html = '<div class="' + TinyMCE_TemplatePlugin.TMPL + '">';
+		html += elm.innerHTML;
+		html += '<!-- ' + TinyMCE_TemplatePlugin.TMPL_ENDS + ' --></div>';
+
+		tinyMCE.execInstanceCommand(editor_id, 'mceInsertContent', false, html);
+	},
+
+	/**
+	 * template functions - functions for modifying template content
+	 */
+	functions : { 
+		blank : function(elm, editor_event) {},
+
+		cdate : function(elm, editor_event) {
+			var d, dsrc;
+
+			if (editor_event != TinyMCE_TemplatePlugin.TMPL_TEMPLATE_EVENT)
+				return;
+
+			d = new Date();
+			// find out if the creation date was previously stored
+			dsrc = elm.innerHTML.match(new RegExp("<!-- " + TinyMCE_TemplatePlugin.TMPL_DATE_SRC_ATTR + ":(.*)  -->", "gi"));
+
+			if (dsrc)
+				d = new Date(RegExp.$1);
+
+			elm.innerHTML = TinyMCE_TemplatePlugin._getDateTime(d, tinyMCE.getParam("template_cdate_format", tinyMCE.getLang("lang_template_def_date_format")));
+			//now we have to store the date value in a format easily read again, in case a future template change changes the date format...
+			elm.innerHTML += "<!-- " + TinyMCE_TemplatePlugin.TMPL_DATE_SRC_ATTR + ":" + d.toUTCString() + "  -->";
+		},
+
+		mdate : function(elm, editor_event) {
+			var d = new Date();
+			elm.innerHTML = TinyMCE_TemplatePlugin._getDateTime(d, tinyMCE.getParam("template_mdate_format", tinyMCE.getLang("lang_template_def_date_format")));
+		},
+
+		/**
+		 * This will insert the currently selected editor content into the template element.
+		 * It only does this if the template inserted is a new one and if the element does not have the special class.
+		 * The special class name prevents this from happening more than once.
+		 */
+		selectedContent : function(elm, editor_event) {
+			var ds = tinyMCE.selectedInstance.getData('template');
+	
+			if (editor_event != TinyMCE_TemplatePlugin.TMPL_TEMPLATE_EVENT)
+				return;
+
+			if (ds.currentAction == "insert-new" && !tinyMCE.hasCSSClass(elm, TinyMCE_TemplatePlugin.TMPL_SEL_HTML_DONE)) {
+				elm.innerHTML = tinyMCE.selectedInstance.selection.getSelectedHTML();
+				tinyMCE.addCSSClass(elm, TinyMCE_TemplatePlugin.TMPL_SEL_HTML_DONE);
+			}
+		},
+
+		/**
+		 * When the plugin is initialised this generates the functions that insert configured strings into template elements.
+		 */
+		generateReplacer : function(s) {
+			return function(elm, editor_event) {elm.innerHTML = "" + s;};
+		}
+	},
+
+	/**
+	 * formats a date according to the format string - straight from the 'insert date/time' plugin
+	 *
+	 * @param {Date} date object
+	 * @param {string} format string
+	 * @return formatted date
+	 * @type string
+	 */
+	_getDateTime : function(d,fmt) {
+			if (!fmt)
+				return "";
+
+			function addZeros(value, len) {
+				var i;
+
+				value = "" + value;
+
+				if (value.length < len) {
+					for (i=0; i<(len-value.length); i++)
+						value = "0" + value;
+				}
+
+				return value;
+			}
+
+			fmt = fmt.replace("%D", "%m/%d/%y");
+			fmt = fmt.replace("%r", "%I:%M:%S %p");
+			fmt = fmt.replace("%Y", "" + d.getFullYear());
+			fmt = fmt.replace("%y", "" + d.getYear());
+			fmt = fmt.replace("%m", addZeros(d.getMonth()+1, 2));
+			fmt = fmt.replace("%d", addZeros(d.getDate(), 2));
+			fmt = fmt.replace("%H", "" + addZeros(d.getHours(), 2));
+			fmt = fmt.replace("%M", "" + addZeros(d.getMinutes(), 2));
+			fmt = fmt.replace("%S", "" + addZeros(d.getSeconds(), 2));
+			fmt = fmt.replace("%I", "" + ((d.getHours() + 11) % 12 + 1));
+			fmt = fmt.replace("%p", "" + (d.getHours() < 12 ? "AM" : "PM"));
+			fmt = fmt.replace("%B", "" + tinyMCE.getLang("lang_template_months_long")[d.getMonth()]);
+			fmt = fmt.replace("%b", "" + tinyMCE.getLang("lang_template_months_short")[d.getMonth()]);
+			fmt = fmt.replace("%A", "" + tinyMCE.getLang("lang_template_day_long")[d.getDay()]);
+			fmt = fmt.replace("%a", "" + tinyMCE.getLang("lang_template_day_short")[d.getDay()]);
+			fmt = fmt.replace("%%", "%");
+
+			return fmt;
+	},
+
+	TMPL_ELEMENT : 'mceTmplElm',
+	TMPL : 'mceTmpl',
+	TMPL_BEGINS : 'mceTmplBegins',
+	TMPL_SEL_HTML_DONE : 'mceSelHTMLDone',
+	TMPL_ENDS : 'mceTmplEnds',
+	TMPL_DATE_SRC_ATTR : 'mcetmpldtesrc',
+	TMPL_TEMPLATE_EVENT : 'prepare_template'
+};
+
+tinyMCE.addPlugin("template", TinyMCE_TemplatePlugin);
Binary file includes/clientside/tinymce/plugins/template/images/template.gif has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/template/jscripts/template.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,143 @@
+// Import external list url javascript
+var url = tinyMCE.getParam("template_external_list_url");
+if (url != null) {
+	// Fix relative
+	if (url.charAt(0) != '/' && url.indexOf('://') == -1)
+		url = tinyMCE.documentBasePath + "/" + url;
+
+	document.write('<sc'+'ript language="javascript" type="text/javascript" src="' + url + '"></sc'+'ript>');
+}
+
+var TPU = { //Template Popup Utils
+	currentTemplateHTML : null,
+	templates : [],
+	inst : tinyMCE.getInstanceById(tinyMCE.getWindowArg('editor_id')),
+	plugin : tinyMCE.getWindowArg('pluginObj'),
+	data : tinyMCE.selectedInstance.getData('template'),
+
+ 	init : function() {
+ 		document.forms[0].insert.value = tinyMCE.getLang('lang_' + this.data.currentAction, 'Insert', true); 
+		TPU.loadTemplatePaths();
+
+		if (this.data.currentAction == "update")
+			document.getElementById('warning').innerHTML = tinyMCE.getLang('lang_template_warning');
+
+		this.resizeInputs();
+	},
+
+ 	loadTemplatePaths : function() {
+		var tsrc, sel, x, u;
+
+ 		tsrc = tinyMCE.getParam("template_templates", false);
+ 		sel = document.getElementById('tpath');
+
+		// Setup external template list
+		if (!tsrc && typeof(tinyMCETemplateList) != 'undefined') {
+			for (x=0, tsrc = []; x<tinyMCETemplateList.length; x++)
+				tsrc.push({title : tinyMCETemplateList[x][0], src : tinyMCETemplateList[x][1], description : tinyMCETemplateList[x][2]});
+		}
+
+		for (x=0; x<tsrc.length; x++) {
+			u = tsrc[x].src;
+
+			// Force absolute
+			if (u.indexOf('://') == -1 && u.indexOf('/') != 0)
+				u = tinyMCE.documentBasePath + "/" + u;
+
+			tsrc[x].src = u;
+		}
+
+		TPU.templates = tsrc;
+
+		for (x = 0; x < tsrc.length; x++)
+			sel.options[sel.options.length] = new Option(tsrc[x].title, tsrc[x].src);
+	},
+
+ 	selectTemplate : function(o) {
+		var x, d = window.frames['templatesrc'].document;
+
+		this.currentTemplateHTML = this.plugin._replaceValues(this.getFileContents(o.value));
+
+		// Force complete document
+		if (!/<body/gi.test(this.currentTemplateHTML)) {
+			this.currentTemplateHTML = '<html xmlns="http://www.w3.org/1999/xhtml">' + 
+				'<head>' + 
+					'<title>blank_page</title>' + 
+					'<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />' + 
+				'</head>' + 
+				'<body>' + 
+				this.currentTemplateHTML + 
+				'</body>' + 
+				'</html>';
+		}
+
+		// Write HTML to preview iframe
+		d.body.innerHTML = this.currentTemplateHTML;
+
+		// Display description
+ 		for (x = 0; x < TPU.templates.length; x++) {
+			if (TPU.templates[x].src == o.value) {
+				document.getElementById('tmpldesc').innerHTML = TPU.templates[x].description;
+				break;
+			}
+		}
+ 	},
+
+ 	insertTemplate : function() {
+		var sel, opt;
+
+		sel = document.getElementById('tpath');
+		opt = sel.options[sel.selectedIndex];
+
+		// Is it a template or snippet
+		if (TPU.currentTemplateHTML.indexOf('mceTmpl'))
+			tinyMCEPopup.execCommand('mceTemplate', false, {title : opt.text, tsrc : opt.value, body : TPU.currentTemplateHTML});
+		else
+			tinyMCEPopup.execCommand('mceInsertContent', false, TPU.currentTemplateHTML);
+
+		tinyMCEPopup.close();
+	},
+
+	getFileContents : function(u) {
+		var x, d, t = 'text/plain';
+
+		function g(s) {
+			x = 0;
+
+			try {
+				x = new ActiveXObject(s);
+			} catch (s) {
+			}
+
+			return x;
+		};
+
+		x = window.ActiveXObject ? g('Msxml2.XMLHTTP') || g('Microsoft.XMLHTTP') : new XMLHttpRequest();
+
+		// Synchronous AJAX load file
+		x.overrideMimeType && x.overrideMimeType(t);
+		x.open("GET", u, false);
+		x.send(null);
+
+		return x.responseText;
+	},
+
+	resizeInputs : function() {
+		var wHeight, wWidth, elm;
+
+		if (!self.innerWidth) {
+			wHeight = document.body.clientHeight - 160;
+			wWidth = document.body.clientWidth - 40;
+		} else {
+			wHeight = self.innerHeight - 160;
+			wWidth = self.innerWidth - 40;
+		}
+
+		elm = document.getElementById('templatesrc');
+
+		if (elm) {
+			elm.style.height = Math.abs(wHeight) + 'px';
+			elm.style.width  = Math.abs(wWidth - 5) + 'px';
+		}
+	}
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/template/langs/en.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,16 @@
+// UK lang variables
+
+tinyMCE.addToLang('template',{
+title : 'Templates',
+label : 'Template',
+desc_label : 'Description',
+desc : 'Insert predefined template content',
+select : 'Select a template',
+preview : 'Preview',
+warning : 'Warning: Updating a template with a different one may cause data loss.',
+def_date_format : '%Y-%m-%d %H:%M:%S',
+months_long : new Array("January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"),
+months_short : new Array("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"),
+day_long : new Array("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"),
+day_short : new Array("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun")
+});
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/template/template.htm	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,37 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>{$lang_template_title}</title>
+	<script language="javascript" type="text/javascript" src="../../tiny_mce_popup.js"></script>
+	<script language="javascript" type="text/javascript" src="jscripts/template.js"></script>
+	<link href="css/template.css" rel="stylesheet" type="text/css" />
+	<base target="_self" />
+</head>
+<body onload="tinyMCEPopup.executeOnLoad('TPU.init();');" onresize="TPU.resizeInputs();"> 
+	<form onsubmit="insert();return false;">
+		<div id="frmbody">
+			<div class="title">{$lang_template_desc}</div>
+			<div class="frmRow"><label for="tpath" title="{$lang_template_select}">{$lang_template_label}:</label>
+			<select id="tpath" name="tpath" onfocus="tinyMCE.addSelectAccessibility(event, this, window);" onchange="TPU.selectTemplate(this.options[this.selectedIndex]);">
+				<option value="">{$lang_template_select}...</option>
+			</select>
+			<span id="warning"></span></div>
+			<div class="frmRow"><label for="tdesc">{$lang_template_desc_label}:</label>
+			<span id="tmpldesc"></span></div>
+			<fieldset>
+				<legend>{$lang_template_preview}</legend>
+				<iframe id="templatesrc" name="templatesrc" src="blank.htm" width="690" height="400" frameborder="0"></iframe>
+			</fieldset>
+		</div>
+		
+		<div class="mceActionPanel">
+			<div style="float: left">
+				<input type="button" id="insert" name="insert" value="{$lang_insert}" onclick="TPU.insertTemplate();" />
+			</div>
+
+			<div style="float: right">
+				<input type="button" id="cancel" name="cancel" value="{$lang_cancel}" onclick="tinyMCEPopup.close();" />
+			</div>
+		</div>
+	</form>
+</body> 
+</html> 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/visualchars/editor_plugin.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+tinyMCE.importPluginLanguagePack('visualchars');var TinyMCE_VisualCharsPlugin={getInfo:function(){return{longname:'Visual characters',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/visualchars',version:tinyMCE.majorVersion+"."+tinyMCE.minorVersion}},initInstance:function(inst){inst.visualChars={state:false}},getControlHTML:function(cn){switch(cn){case"visualchars":return tinyMCE.getButtonHTML(cn,'lang_visualchars_desc','{$pluginurl}/images/visualchars.gif','mceVisualChars',false)}return""},execCommand:function(editor_id,element,command,user_interface,value){var inst=tinyMCE.getInstanceById(editor_id);switch(command){case"mceVisualChars":this._toggleVisualChars(editor_id,inst);return true}return false},cleanup:function(type,content,inst){if(type=="insert_to_editor_dom"||type=="get_from_editor_dom"){inst.visualChars.state=true;this._toggleVisualChars(inst.editorId,inst)}return content},_toggleVisualChars:function(editor_id,inst){var nl,i,h,d=inst.getDoc(),b=inst.getBody(),nv,s=inst.selection,bo;inst.visualChars.state=!inst.visualChars.state;bo=s.getBookmark(true);tinyMCE.switchClass(editor_id+'_visualchars',inst.visualChars.state?'mceButtonSelected':'mceButtonNormal');if(inst.visualChars.state){nl=tinyMCE.selectNodes(b,function(n){return n.nodeType==3&&n.nodeValue&&n.nodeValue.indexOf('\u00a0')!=-1});for(i=0;i<nl.length;i++){nv=nl[i].nodeValue;nv=nv.replace(/(\u00a0+)/g,'<span class="mceItemHiddenVisualChar">$1</span>');nv=nv.replace(/\u00a0/g,'\u00b7');tinyMCE.setOuterHTML(nl[i],nv,d)}}else{nl=tinyMCE.selectNodes(b,function(n){return n.nodeType==1&&n.nodeName=='SPAN'&&n.className=='mceItemHiddenVisualChar'});for(i=0;i<nl.length;i++)tinyMCE.setOuterHTML(nl[i],nl[i].innerHTML.replace(/(&middot;|\u00b7)/g,'&nbsp;'),d)}}};tinyMCE.addPlugin("visualchars",TinyMCE_VisualCharsPlugin);
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/visualchars/editor_plugin_src.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,89 @@
+/**
+ * $Id: editor_plugin_src.js 42 2006-08-08 14:32:24Z spocke $
+ *
+ * @author Moxiecode
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+/* Import plugin specific language pack */
+tinyMCE.importPluginLanguagePack('visualchars');
+
+var TinyMCE_VisualCharsPlugin = {
+	getInfo : function() {
+		return {
+			longname : 'Visual characters',
+			author : 'Moxiecode Systems AB',
+			authorurl : 'http://tinymce.moxiecode.com',
+			infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/visualchars',
+			version : tinyMCE.majorVersion + "." + tinyMCE.minorVersion
+		};
+	},
+
+	initInstance : function(inst) {
+		inst.visualChars = {
+			state : false
+		};
+	},
+
+	getControlHTML : function(cn) {
+		switch (cn) {
+			case "visualchars":
+				return tinyMCE.getButtonHTML(cn, 'lang_visualchars_desc', '{$pluginurl}/images/visualchars.gif', 'mceVisualChars', false);
+		}
+
+		return "";
+	},
+
+	execCommand : function(editor_id, element, command, user_interface, value) {
+		var inst = tinyMCE.getInstanceById(editor_id);
+
+		switch (command) {
+			case "mceVisualChars":
+				this._toggleVisualChars(editor_id, inst);
+				return true;
+		}
+
+		return false;
+	},
+
+	cleanup : function(type, content, inst) {
+		if (type == "insert_to_editor_dom" || type == "get_from_editor_dom") {
+			inst.visualChars.state = true;
+			this._toggleVisualChars(inst.editorId, inst);
+		}
+
+		return content;
+	},
+
+	// Private plugin internal methods
+
+	_toggleVisualChars : function(editor_id, inst) {
+		var nl, i, h, d = inst.getDoc(), b = inst.getBody(), nv, s = inst.selection, bo;
+
+		inst.visualChars.state = !inst.visualChars.state;
+
+		bo = s.getBookmark(true);
+
+		tinyMCE.switchClass(editor_id + '_visualchars', inst.visualChars.state ? 'mceButtonSelected' : 'mceButtonNormal');
+
+		if (inst.visualChars.state) {
+			nl = tinyMCE.selectNodes(b, function(n) {return n.nodeType == 3 && n.nodeValue && n.nodeValue.indexOf('\u00a0') != -1;});
+
+			for (i=0; i<nl.length; i++) {
+				nv = nl[i].nodeValue;
+				nv = nv.replace(/(\u00a0+)/g, '<span class="mceItemHiddenVisualChar">$1</span>');
+				nv = nv.replace(/\u00a0/g, '\u00b7');
+				tinyMCE.setOuterHTML(nl[i], nv, d);
+			}
+		} else {
+			nl = tinyMCE.selectNodes(b, function(n) {return n.nodeType == 1 && n.nodeName == 'SPAN' && n.className == 'mceItemHiddenVisualChar';});
+
+			for (i=0; i<nl.length; i++)
+				tinyMCE.setOuterHTML(nl[i], nl[i].innerHTML.replace(/(&middot;|\u00b7)/g, '&nbsp;'), d);
+		}
+
+		//s.moveToBookmark(bo);
+	}
+};
+
+tinyMCE.addPlugin("visualchars", TinyMCE_VisualCharsPlugin);
Binary file includes/clientside/tinymce/plugins/visualchars/images/visualchars.gif has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/visualchars/langs/en.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,5 @@
+// EN lang variables
+
+tinyMCE.addToLang('visualchars',{
+desc : 'Visual control characters on/off.'
+});
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/xhtmlxtras/abbr.htm	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,148 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>{$lang_xhtmlxtras_title_abbr_element}</title>
+	<script language="javascript" type="text/javascript" src="../../tiny_mce_popup.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/mctabs.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/form_utils.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/editable_selects.js"></script>
+	<script language="javascript" type="text/javascript" src="jscripts/element_common.js"></script>
+	<script language="javascript" type="text/javascript" src="jscripts/abbr.js"></script>
+	<link rel="stylesheet" type="text/css" href="css/popup.css" />
+	<base target="_self" />
+</head>
+<body onload="tinyMCEPopup.executeOnLoad('init();');" style="display: none">
+<form onsubmit="insertAbbr();return false;" action="#">
+	<div class="tabs">
+		<ul>
+			<li id="general_tab" class="current"><span><a href="javascript:mcTabs.displayTab('general_tab','general_panel');" onmousedown="return false;">{$lang_xhtmlxtras_general_tab}</a></span></li>
+			<!-- <li id="events_tab"><span><a href="javascript:mcTabs.displayTab('events_tab','events_panel');" onmousedown="return false;">{$lang_xhtmlxtras_events_tab}</a></span></li> -->
+		</ul>
+	</div>
+
+	<div class="panel_wrapper">
+		<div id="general_panel" class="panel current">
+			<fieldset>
+				<legend>{$lang_xhtmlxtras_fieldset_attrib_tab}</legend>
+				<table border="0" cellpadding="0" cellspacing="4">
+					<tr>
+						<td class="label"><label id="titlelabel" for="title">{$lang_xhtmlxtras_attribute_label_title}</label>:</td> 
+						<td><input id="title" name="title" type="text" value="" class="field" /></td> 
+					</tr>
+					<tr>
+						<td class="label"><label id="idlabel" for="id">{$lang_xhtmlxtras_attribute_label_id}</label>:</td> 
+						<td><input id="id" name="id" type="text" value="" class="field" /></td> 
+					</tr>
+					<tr>
+						<td class="label"><label id="classlabel" for="class">{$lang_xhtmlxtras_attribute_label_class}</label>:</td> 
+						<td>
+							<select id="class" name="class" class="field mceEditableSelect">
+								<option value="">{$lang_xhtmlxtras_not_set}</option> 
+							</select>
+						</td>
+					</tr>
+					<tr>
+						<td class="label"><label id="stylelabel" for="class">{$lang_xhtmlxtras_attribute_label_style}</label>:</td> 
+						<td><input id="style" name="style" type="text" value="" class="field" /></td> 
+					</tr>
+					<tr>
+						<td class="label"><label id="dirlabel" for="dir">{$lang_xhtmlxtras_attribute_label_langdir}</label>:</td> 
+						<td>
+							<select id="dir" name="dir" class="field"> 
+								<option value="">{$lang_xhtmlxtras_not_set}</option> 
+								<option value="ltr">{$lang_xhtmlxtras_attribute_option_ltr}</option> 
+								<option value="rtl">{$lang_xhtmlxtras_attribute_option_rtl}</option> 
+							</select>
+						</td> 
+					</tr>
+					<tr>
+						<td class="label"><label id="langlabel" for="lang">{$lang_xhtmlxtras_attribute_label_langcode}</label>:</td> 
+						<td>
+							<input id="lang" name="lang" type="text" value="" class="field" />
+						</td> 
+					</tr>
+				</table>
+			</fieldset>
+		</div>
+		<div id="events_panel" class="panel">
+			<fieldset>
+				<legend>{$lang_xhtmlxtras_fieldset_events_tab}</legend>
+
+				<table border="0" cellpadding="0" cellspacing="4">
+					<tr>
+						<td class="label"><label for="onfocus">onfocus</label>:</td> 
+						<td><input id="onfocus" name="onfocus" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onblur">onblur</label>:</td> 
+						<td><input id="onblur" name="onblur" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onclick">onclick</label>:</td> 
+						<td><input id="onclick" name="onclick" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="ondblclick">ondblclick</label>:</td> 
+						<td><input id="ondblclick" name="ondblclick" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onmousedown">onmousedown</label>:</td> 
+						<td><input id="onmousedown" name="onmousedown" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onmouseup">onmouseup</label>:</td> 
+						<td><input id="onmouseup" name="onmouseup" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onmouseover">onmouseover</label>:</td> 
+						<td><input id="onmouseover" name="onmouseover" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onmousemove">onmousemove</label>:</td> 
+						<td><input id="onmousemove" name="onmousemove" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onmouseout">onmouseout</label>:</td> 
+						<td><input id="onmouseout" name="onmouseout" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onkeypress">onkeypress</label>:</td> 
+						<td><input id="onkeypress" name="onkeypress" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onkeydown">onkeydown</label>:</td> 
+						<td><input id="onkeydown" name="onkeydown" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onkeyup">onkeyup</label>:</td> 
+						<td><input id="onkeyup" name="onkeyup" type="text" value="" class="field" /></td> 
+					</tr>
+				</table>
+			</fieldset>
+		</div>
+	</div>
+	<div class="mceActionPanel">
+		<div style="float: left">
+			<input type="button" id="insert" name="insert" value="{$lang_update}" onclick="insertAbbr();" />
+		</div>
+		<div style="float: left">
+			<input type="button" id="remove" name="remove" value="{$lang_xhtmlxtras_remove}" onclick="removeAbbr();" style="display: none;" />
+		</div>
+		<div style="float: right">
+			<input type="button" id="cancel" name="cancel" value="{$lang_cancel}" onclick="tinyMCEPopup.close();" />
+		</div>
+	</div>
+
+</form>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/xhtmlxtras/acronym.htm	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,148 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>{$lang_xhtmlxtras_title_acronym_element}</title>
+	<script language="javascript" type="text/javascript" src="../../tiny_mce_popup.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/mctabs.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/form_utils.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/editable_selects.js"></script>
+	<script language="javascript" type="text/javascript" src="jscripts/element_common.js"></script>
+	<script language="javascript" type="text/javascript" src="jscripts/acronym.js"></script>
+	<link rel="stylesheet" type="text/css" href="css/popup.css" />
+	<base target="_self" />
+</head>
+<body onload="tinyMCEPopup.executeOnLoad('init();');" style="display: none">
+<form onsubmit="insertAcronym();return false;" action="#">
+	<div class="tabs">
+		<ul>
+			<li id="general_tab" class="current"><span><a href="javascript:mcTabs.displayTab('general_tab','general_panel');" onmousedown="return false;">{$lang_xhtmlxtras_general_tab}</a></span></li>
+			<!-- <li id="events_tab"><span><a href="javascript:mcTabs.displayTab('events_tab','events_panel');" onmousedown="return false;">{$lang_xhtmlxtras_events_tab}</a></span></li> -->
+		</ul>
+	</div>
+
+	<div class="panel_wrapper">
+		<div id="general_panel" class="panel current">
+			<fieldset>
+				<legend>{$lang_xhtmlxtras_fieldset_attrib_tab}</legend>
+				<table border="0" cellpadding="0" cellspacing="4">
+					<tr>
+						<td class="label"><label id="titlelabel" for="title">{$lang_xhtmlxtras_attribute_label_title}</label>:</td> 
+						<td><input id="title" name="title" type="text" value="" class="field" /></td> 
+					</tr>
+					<tr>
+						<td class="label"><label id="idlabel" for="id">{$lang_xhtmlxtras_attribute_label_id}</label>:</td> 
+						<td><input id="id" name="id" type="text" value="" class="field" /></td> 
+					</tr>
+					<tr>
+						<td class="label"><label id="classlabel" for="class">{$lang_xhtmlxtras_attribute_label_class}</label>:</td> 
+						<td>
+							<select id="class" name="class" class="field mceEditableSelect">
+								<option value="">{$lang_xhtmlxtras_not_set}</option> 
+							</select>
+						</td>
+					</tr>
+					<tr>
+						<td class="label"><label id="stylelabel" for="class">{$lang_xhtmlxtras_attribute_label_style}</label>:</td> 
+						<td><input id="style" name="style" type="text" value="" class="field" /></td> 
+					</tr>
+					<tr>
+						<td class="label"><label id="dirlabel" for="dir">{$lang_xhtmlxtras_attribute_label_langdir}</label>:</td> 
+						<td>
+							<select id="dir" name="dir" class="field"> 
+								<option value="">{$lang_xhtmlxtras_not_set}</option> 
+								<option value="ltr">{$lang_xhtmlxtras_attribute_option_ltr}</option> 
+								<option value="rtl">{$lang_xhtmlxtras_attribute_option_rtl}</option> 
+							</select>
+						</td> 
+					</tr>
+					<tr>
+						<td class="label"><label id="langlabel" for="lang">{$lang_xhtmlxtras_attribute_label_langcode}</label>:</td> 
+						<td>
+							<input id="lang" name="lang" type="text" value="" class="field" />
+						</td> 
+					</tr>
+				</table>
+			</fieldset>
+		</div>
+		<div id="events_panel" class="panel">
+			<fieldset>
+				<legend>{$lang_xhtmlxtras_fieldset_events_tab}</legend>
+
+				<table border="0" cellpadding="0" cellspacing="4">
+					<tr>
+						<td class="label"><label for="onfocus">onfocus</label>:</td> 
+						<td><input id="onfocus" name="onfocus" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onblur">onblur</label>:</td> 
+						<td><input id="onblur" name="onblur" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onclick">onclick</label>:</td> 
+						<td><input id="onclick" name="onclick" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="ondblclick">ondblclick</label>:</td> 
+						<td><input id="ondblclick" name="ondblclick" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onmousedown">onmousedown</label>:</td> 
+						<td><input id="onmousedown" name="onmousedown" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onmouseup">onmouseup</label>:</td> 
+						<td><input id="onmouseup" name="onmouseup" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onmouseover">onmouseover</label>:</td> 
+						<td><input id="onmouseover" name="onmouseover" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onmousemove">onmousemove</label>:</td> 
+						<td><input id="onmousemove" name="onmousemove" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onmouseout">onmouseout</label>:</td> 
+						<td><input id="onmouseout" name="onmouseout" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onkeypress">onkeypress</label>:</td> 
+						<td><input id="onkeypress" name="onkeypress" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onkeydown">onkeydown</label>:</td> 
+						<td><input id="onkeydown" name="onkeydown" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onkeyup">onkeyup</label>:</td> 
+						<td><input id="onkeyup" name="onkeyup" type="text" value="" class="field" /></td> 
+					</tr>
+				</table>
+			</fieldset>
+		</div>
+	</div>
+	<div class="mceActionPanel">
+		<div style="float: left">
+			<input type="button" id="insert" name="insert" value="{$lang_update}" onclick="insertAcronym();" />
+		</div>
+		<div style="float: left">
+			<input type="button" id="remove" name="remove" value="{$lang_xhtmlxtras_remove}" onclick="removeAcronym();" style="display: none;" />
+		</div>
+		<div style="float: right">
+			<input type="button" id="cancel" name="cancel" value="{$lang_cancel}" onclick="tinyMCEPopup.close();" />
+		</div>
+	</div>
+
+</form>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/xhtmlxtras/attributes.htm	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,153 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>{$lang_xhtmlxtras_attribs_title}</title>
+	<script language="javascript" type="text/javascript" src="../../tiny_mce_popup.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/mctabs.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/editable_selects.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/form_utils.js"></script>
+	<script language="javascript" type="text/javascript" src="jscripts/attributes.js"></script>
+	<link rel="stylesheet" type="text/css" href="css/attributes.css" />
+	<base target="_self" />
+</head>
+<body onload="tinyMCEPopup.executeOnLoad('init();');" style="display: none">
+<form onsubmit="insertAction();return false;" action="#">
+	<div class="tabs">
+		<ul>
+			<li id="general_tab" class="current"><span><a href="javascript:mcTabs.displayTab('general_tab','general_panel');" onmousedown="return false;">{$lang_xhtmlxtras_attribute_attrib_tab}</a></span></li>
+			<li id="events_tab"><span><a href="javascript:mcTabs.displayTab('events_tab','events_panel');" onmousedown="return false;">{$lang_xhtmlxtras_attribute_events_tab}</a></span></li>
+		</ul>
+	</div>
+
+	<div class="panel_wrapper">
+		<div id="general_panel" class="panel current">
+			<fieldset>
+				<legend>{$lang_xhtmlxtras_attribute_attrib_tab}</legend>
+				<table border="0" cellpadding="0" cellspacing="4">
+					<tr>
+						<td class="label"><label id="titlelabel" for="title">{$lang_xhtmlxtras_attribute_label_title}</label>:</td> 
+						<td><input id="title" name="title" type="text" value="" /></td> 
+					</tr>
+					<tr>
+						<td class="label"><label id="idlabel" for="id">{$lang_xhtmlxtras_attribute_label_id}</label>:</td> 
+						<td><input id="id" name="id" type="text" value="" /></td> 
+					</tr>
+					<tr>
+						<td><label id="classlabel" for="classlist">{$lang_class_name}</label></td>
+						<td>
+							<select id="classlist" name="classlist" class="mceEditableSelect">
+								<option value="" selected>{$lang_not_set}</option>
+							</select>
+						</td>
+					</tr>
+					<tr>
+						<td class="label"><label id="stylelabel" for="class">{$lang_xhtmlxtras_attribute_label_style}</label>:</td> 
+						<td><input id="style" name="style" type="text" value="" /></td> 
+					</tr>
+					<tr>
+						<td class="label"><label id="dirlabel" for="dir">{$lang_xhtmlxtras_attribute_label_langdir}</label>:</td> 
+						<td>
+							<select id="dir" name="dir"> 
+								<option value="">{$lang_xhtmlxtras_not_set}</option> 
+								<option value="ltr">{$lang_xhtmlxtras_option_ltr}</option> 
+								<option value="rtl">{$lang_xhtmlxtras_option_rtl}</option> 
+							</select>
+						</td> 
+					</tr>
+					<tr>
+						<td class="label"><label id="langlabel" for="lang">{$lang_xhtmlxtras_attribute_label_langcode}</label>:</td> 
+						<td>
+							<input id="lang" name="lang" type="text" value="" />
+						</td> 
+					</tr>
+					<tr>
+							<td><label id="tabindexlabel" for="tabindex">{$lang_xhtmlxtras_attribute_label_tabindex}</label></td>
+							<td><input type="text" id="tabindex" name="tabindex" value="" /></td>
+						</tr>
+
+						<tr>
+							<td><label id="accesskeylabel" for="accesskey">{$lang_xhtmlxtras_attribute_label_accesskey}</label></td>
+							<td><input type="text" id="accesskey" name="accesskey" value="" /></td>
+						</tr>
+				</table>
+			</fieldset>
+		</div>
+		<div id="events_panel" class="panel">
+			<fieldset>
+				<legend>{$lang_xhtmlxtras_attribute_events_tab}</legend>
+
+				<table border="0" cellpadding="0" cellspacing="4">
+					<tr>
+						<td class="label"><label for="onfocus">onfocus</label>:</td> 
+						<td><input id="onfocus" name="onfocus" type="text" value="" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onblur">onblur</label>:</td> 
+						<td><input id="onblur" name="onblur" type="text" value="" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onclick">onclick</label>:</td> 
+						<td><input id="onclick" name="onclick" type="text" value="" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="ondblclick">ondblclick</label>:</td> 
+						<td><input id="ondblclick" name="ondblclick" type="text" value="" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onmousedown">onmousedown</label>:</td> 
+						<td><input id="onmousedown" name="onmousedown" type="text" value="" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onmouseup">onmouseup</label>:</td> 
+						<td><input id="onmouseup" name="onmouseup" type="text" value="" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onmouseover">onmouseover</label>:</td> 
+						<td><input id="onmouseover" name="onmouseover" type="text" value="" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onmousemove">onmousemove</label>:</td> 
+						<td><input id="onmousemove" name="onmousemove" type="text" value="" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onmouseout">onmouseout</label>:</td> 
+						<td><input id="onmouseout" name="onmouseout" type="text" value="" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onkeypress">onkeypress</label>:</td> 
+						<td><input id="onkeypress" name="onkeypress" type="text" value="" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onkeydown">onkeydown</label>:</td> 
+						<td><input id="onkeydown" name="onkeydown" type="text" value="" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onkeyup">onkeyup</label>:</td> 
+						<td><input id="onkeyup" name="onkeyup" type="text" value="" /></td> 
+					</tr>
+				</table>
+			</fieldset>
+		</div>
+	</div>
+	<div class="mceActionPanel">
+		<div style="float: left">
+			<input type="button" id="insert" name="insert" value="{$lang_insert}" onclick="insertAction();" />
+		</div>
+		<div style="float: right">
+			<input type="button" id="cancel" name="cancel" value="{$lang_cancel}" onclick="tinyMCEPopup.close();" />
+		</div>
+	</div>
+
+</form>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/xhtmlxtras/cite.htm	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,148 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>{$lang_xhtmlxtras_title_cite_element}</title>
+	<script language="javascript" type="text/javascript" src="../../tiny_mce_popup.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/mctabs.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/form_utils.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/editable_selects.js"></script>
+	<script language="javascript" type="text/javascript" src="jscripts/element_common.js"></script>
+	<script language="javascript" type="text/javascript" src="jscripts/cite.js"></script>
+	<link rel="stylesheet" type="text/css" href="css/popup.css" />
+	<base target="_self" />
+</head>
+<body onload="tinyMCEPopup.executeOnLoad('init();');" style="display: none">
+<form onsubmit="insertCite();return false;" action="#">
+	<div class="tabs">
+		<ul>
+			<li id="general_tab" class="current"><span><a href="javascript:mcTabs.displayTab('general_tab','general_panel');" onmousedown="return false;">{$lang_xhtmlxtras_general_tab}</a></span></li>
+			<!-- <li id="events_tab"><span><a href="javascript:mcTabs.displayTab('events_tab','events_panel');" onmousedown="return false;">{$lang_xhtmlxtras_events_tab}</a></span></li> -->
+		</ul>
+	</div>
+
+	<div class="panel_wrapper">
+		<div id="general_panel" class="panel current">
+			<fieldset>
+				<legend>{$lang_xhtmlxtras_fieldset_attrib_tab}</legend>
+				<table border="0" cellpadding="0" cellspacing="4">
+					<tr>
+						<td class="label"><label id="titlelabel" for="title">{$lang_xhtmlxtras_attribute_label_title}</label>:</td> 
+						<td><input id="title" name="title" type="text" value="" class="field" /></td> 
+					</tr>
+					<tr>
+						<td class="label"><label id="idlabel" for="id">{$lang_xhtmlxtras_attribute_label_id}</label>:</td> 
+						<td><input id="id" name="id" type="text" value="" class="field" /></td> 
+					</tr>
+					<tr>
+						<td class="label"><label id="classlabel" for="class">{$lang_xhtmlxtras_attribute_label_class}</label>:</td> 
+						<td>
+							<select id="class" name="class" class="field mceEditableSelect">
+								<option value="">{$lang_xhtmlxtras_not_set}</option> 
+							</select>
+						</td>
+					</tr>
+					<tr>
+						<td class="label"><label id="stylelabel" for="class">{$lang_xhtmlxtras_attribute_label_style}</label>:</td> 
+						<td><input id="style" name="style" type="text" value="" class="field" /></td> 
+					</tr>
+					<tr>
+						<td class="label"><label id="dirlabel" for="dir">{$lang_xhtmlxtras_attribute_label_langdir}</label>:</td> 
+						<td>
+							<select id="dir" name="dir" class="field"> 
+								<option value="">{$lang_xhtmlxtras_not_set}</option> 
+								<option value="ltr">{$lang_xhtmlxtras_attribute_option_ltr}</option> 
+								<option value="rtl">{$lang_xhtmlxtras_attribute_option_rtl}</option> 
+							</select>
+						</td> 
+					</tr>
+					<tr>
+						<td class="label"><label id="langlabel" for="lang">{$lang_xhtmlxtras_attribute_label_langcode}</label>:</td> 
+						<td>
+							<input id="lang" name="lang" type="text" value="" class="field" />
+						</td> 
+					</tr>
+				</table>
+			</fieldset>
+		</div>
+		<div id="events_panel" class="panel">
+			<fieldset>
+				<legend>{$lang_xhtmlxtras_fieldset_events_tab}</legend>
+
+				<table border="0" cellpadding="0" cellspacing="4">
+					<tr>
+						<td class="label"><label for="onfocus">onfocus</label>:</td> 
+						<td><input id="onfocus" name="onfocus" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onblur">onblur</label>:</td> 
+						<td><input id="onblur" name="onblur" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onclick">onclick</label>:</td> 
+						<td><input id="onclick" name="onclick" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="ondblclick">ondblclick</label>:</td> 
+						<td><input id="ondblclick" name="ondblclick" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onmousedown">onmousedown</label>:</td> 
+						<td><input id="onmousedown" name="onmousedown" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onmouseup">onmouseup</label>:</td> 
+						<td><input id="onmouseup" name="onmouseup" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onmouseover">onmouseover</label>:</td> 
+						<td><input id="onmouseover" name="onmouseover" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onmousemove">onmousemove</label>:</td> 
+						<td><input id="onmousemove" name="onmousemove" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onmouseout">onmouseout</label>:</td> 
+						<td><input id="onmouseout" name="onmouseout" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onkeypress">onkeypress</label>:</td> 
+						<td><input id="onkeypress" name="onkeypress" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onkeydown">onkeydown</label>:</td> 
+						<td><input id="onkeydown" name="onkeydown" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onkeyup">onkeyup</label>:</td> 
+						<td><input id="onkeyup" name="onkeyup" type="text" value="" class="field" /></td> 
+					</tr>
+				</table>
+			</fieldset>
+		</div>
+	</div>
+	<div class="mceActionPanel">
+		<div style="float: left">
+			<input type="button" id="insert" name="insert" value="{$lang_update}" onclick="insertCite();" />
+		</div>
+		<div style="float: left">
+			<input type="button" id="remove" name="remove" value="{$lang_xhtmlxtras_remove}" onclick="removeCite();" style="display: none;" />
+		</div>
+		<div style="float: right">
+			<input type="button" id="cancel" name="cancel" value="{$lang_cancel}" onclick="tinyMCEPopup.close();" />
+		</div>
+	</div>
+
+</form>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/xhtmlxtras/css/attributes.css	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,11 @@
+.panel_wrapper div.current {
+	height: 290px;
+}
+
+#id, #style, #title, #dir, #hreflang, #lang, #classlist, #tabindex, #accesskey {
+	width: 200px;
+}
+
+#events_panel input {
+	width: 200px;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/xhtmlxtras/css/popup.css	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,46 @@
+a.mceButtonNormal img, a.mceButtonSelected img {border: 1px solid #F0F0EE !important;}
+a.mceButtonNormal img:hover, a.mceButtonSelected img:hover {border: 1px solid #0A246A !important;  cursor: default;  background-color: #B6BDD2;}
+
+img {
+	border: 0;
+}
+
+input.field, select.field {
+	width: 200px;
+}
+
+input.picker {
+	width: 179px;
+	margin-left: 5px;
+}
+
+input.disabled {
+	border-color: #F2F2F2;
+}
+
+img.picker {
+	vertical-align: text-bottom;
+	cursor: pointer;
+}
+
+h1 {
+	padding: 0 0 5px 0;
+}
+
+#remove {
+	font-weight: bold;
+	width: 90px;
+	height: 21px;
+	border: 0px;
+	background-image: url('../images/remove_button_bg.gif');
+	cursor: pointer;
+	margin-left: 3px;
+}
+
+.panel_wrapper div.current {
+	height: 160px;
+}
+
+#xhtmlxtrasdel .panel_wrapper div.current, #xhtmlxtrasins .panel_wrapper div.current {
+	height: 220px;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/xhtmlxtras/css/xhtmlxtras.css	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,24 @@
+ins {
+	border-bottom: 1px solid green;
+	text-decoration: none;
+	color: green;
+}
+
+del {
+	color: Red;
+	text-decoration: line-through;
+}
+
+cite {
+	border-bottom: 1px dashed blue;
+}
+
+acronym {
+	border-bottom: 1px dotted #CCC;
+	cursor: help;
+}
+
+abbr, html\:abbr {
+	border-bottom: 1px dashed #CCC;
+	cursor: help;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/xhtmlxtras/del.htm	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,169 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>{$lang_xhtmlxtras_title_del_element}</title>
+	<script language="javascript" type="text/javascript" src="../../tiny_mce_popup.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/mctabs.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/form_utils.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/editable_selects.js"></script>
+	<script language="javascript" type="text/javascript" src="jscripts/element_common.js"></script>
+	<script language="javascript" type="text/javascript" src="jscripts/del.js"></script>
+	<link rel="stylesheet" type="text/css" href="css/popup.css" />
+	<base target="_self" />
+</head>
+<body id="xhtmlxtrasins" onload="tinyMCEPopup.executeOnLoad('init();');" style="display: none">
+<form onsubmit="insertDel();return false;" action="#">
+	<div class="tabs">
+		<ul>
+			<li id="general_tab" class="current"><span><a href="javascript:mcTabs.displayTab('general_tab','general_panel');" onmousedown="return false;">{$lang_xhtmlxtras_general_tab}</a></span></li>
+			<!-- <li id="events_tab"><span><a href="javascript:mcTabs.displayTab('events_tab','events_panel');" onmousedown="return false;">{$lang_xhtmlxtras_events_tab}</a></span></li> -->
+		</ul>
+	</div>
+
+	<div class="panel_wrapper">
+		<div id="general_panel" class="panel current">
+			<fieldset>
+				<legend>{$lang_xhtmlxtras_fieldset_general_tab}</legend>
+				<table border="0" cellpadding="0" cellspacing="4">
+					<tr>
+						<td class="label"><label id="datetimelabel" for="datetime">{$lang_xhtmlxtras_attribute_label_datetime}</label>:</td>
+						<td>
+							<table border="0" cellspacing="0" cellpadding="0">
+								<tr> 
+									<td><input id="datetime" name="datetime" type="text" value="" maxlength="19" class="field" /></td> 
+									<td><a href="javascript:insertDateTime('datetime');" class="mceButtonNormal"><img src="images/date_time.gif" class="picker" alt="{$lang_xhtmlxtras_insert_date}" title="{$lang_xhtmlxtras_insert_date}" /></a></td>
+								</tr>
+							</table>
+						</td>
+					</tr>
+					<tr>
+						<td class="label"><label id="citelabel" for="cite">{$lang_xhtmlxtras_attribute_label_cite}</label>:</td>
+						<td><input id="cite" name="cite" type="text" value="" class="field" /></td> 
+					</tr>
+				</table>
+			</fieldset>
+			<fieldset>
+				<legend>{$lang_xhtmlxtras_fieldset_attrib_tab}</legend>
+				<table border="0" cellpadding="0" cellspacing="4">
+					<tr>
+						<td class="label"><label id="titlelabel" for="title">{$lang_xhtmlxtras_attribute_label_title}</label>:</td> 
+						<td><input id="title" name="title" type="text" value="" class="field" /></td> 
+					</tr>
+					<tr>
+						<td class="label"><label id="idlabel" for="id">{$lang_xhtmlxtras_attribute_label_id}</label>:</td> 
+						<td><input id="id" name="id" type="text" value="" class="field" /></td> 
+					</tr>
+					<tr>
+						<td class="label"><label id="classlabel" for="class">{$lang_xhtmlxtras_attribute_label_class}</label>:</td> 
+						<td>
+							<select id="class" name="class" class="field mceEditableSelect">
+								<option value="">{$lang_xhtmlxtras_not_set}</option> 
+							</select>
+						</td>
+					</tr>
+					<tr>
+						<td class="label"><label id="stylelabel" for="class">{$lang_xhtmlxtras_attribute_label_style}</label>:</td> 
+						<td><input id="style" name="style" type="text" value="" class="field" /></td> 
+					</tr>
+					<tr>
+						<td class="label"><label id="dirlabel" for="dir">{$lang_xhtmlxtras_attribute_label_langdir}</label>:</td> 
+						<td>
+							<select id="dir" name="dir" class="field"> 
+								<option value="">{$lang_xhtmlxtras_not_set}</option> 
+								<option value="ltr">{$lang_xhtmlxtras_attribute_option_ltr}</option> 
+								<option value="rtl">{$lang_xhtmlxtras_attribute_option_rtl}</option> 
+							</select>
+						</td> 
+					</tr>
+					<tr>
+						<td class="label"><label id="langlabel" for="lang">{$lang_xhtmlxtras_attribute_label_langcode}</label>:</td> 
+						<td>
+							<input id="lang" name="lang" type="text" value="" class="field" />
+						</td> 
+					</tr>
+				</table>
+			</fieldset>
+		</div>
+		<div id="events_panel" class="panel">
+			<fieldset>
+				<legend>{$lang_xhtmlxtras_fieldset_events_tab}</legend>
+
+				<table border="0" cellpadding="0" cellspacing="4">
+					<tr>
+						<td class="label"><label for="onfocus">onfocus</label>:</td> 
+						<td><input id="onfocus" name="onfocus" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onblur">onblur</label>:</td> 
+						<td><input id="onblur" name="onblur" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onclick">onclick</label>:</td> 
+						<td><input id="onclick" name="onclick" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="ondblclick">ondblclick</label>:</td> 
+						<td><input id="ondblclick" name="ondblclick" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onmousedown">onmousedown</label>:</td> 
+						<td><input id="onmousedown" name="onmousedown" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onmouseup">onmouseup</label>:</td> 
+						<td><input id="onmouseup" name="onmouseup" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onmouseover">onmouseover</label>:</td> 
+						<td><input id="onmouseover" name="onmouseover" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onmousemove">onmousemove</label>:</td> 
+						<td><input id="onmousemove" name="onmousemove" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onmouseout">onmouseout</label>:</td> 
+						<td><input id="onmouseout" name="onmouseout" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onkeypress">onkeypress</label>:</td> 
+						<td><input id="onkeypress" name="onkeypress" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onkeydown">onkeydown</label>:</td> 
+						<td><input id="onkeydown" name="onkeydown" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onkeyup">onkeyup</label>:</td> 
+						<td><input id="onkeyup" name="onkeyup" type="text" value="" class="field" /></td> 
+					</tr>
+				</table>
+			</fieldset>
+		</div>
+	</div>
+	<div class="mceActionPanel">
+		<div style="float: left">
+			<input type="button" id="insert" name="insert" value="{$lang_update}" onclick="insertDel();" />
+		</div>
+		<div style="float: left">
+			<input type="button" id="remove" name="remove" value="{$lang_xhtmlxtras_remove}" onclick="removeDel();" style="display: none;" />
+		</div>
+		<div style="float: right">
+			<input type="button" id="cancel" name="cancel" value="{$lang_cancel}" onclick="tinyMCEPopup.close();" />
+		</div>
+	</div>
+
+</form>
+
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/xhtmlxtras/editor_plugin.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+tinyMCE.importPluginLanguagePack('xhtmlxtras');var TinyMCE_XHTMLXtrasPlugin={getInfo:function(){return{longname:'XHTML Xtras Plugin',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/xhtmlxtras',version:tinyMCE.majorVersion+"."+tinyMCE.minorVersion}},initInstance:function(inst){tinyMCE.importCSS(inst.getDoc(),tinyMCE.baseURL+"/plugins/xhtmlxtras/css/xhtmlxtras.css")},getControlHTML:function(cn){switch(cn){case"cite":return tinyMCE.getButtonHTML(cn,'lang_xhtmlxtras_cite_desc','{$pluginurl}/images/cite.gif','mceCite',true);case"acronym":return tinyMCE.getButtonHTML(cn,'lang_xhtmlxtras_acronym_desc','{$pluginurl}/images/acronym.gif','mceAcronym',true);case"abbr":return tinyMCE.getButtonHTML(cn,'lang_xhtmlxtras_abbr_desc','{$pluginurl}/images/abbr.gif','mceAbbr',true);case"del":return tinyMCE.getButtonHTML(cn,'lang_xhtmlxtras_del_desc','{$pluginurl}/images/del.gif','mceDel',true);case"ins":return tinyMCE.getButtonHTML(cn,'lang_xhtmlxtras_ins_desc','{$pluginurl}/images/ins.gif','mceIns',true);case"attribs":return tinyMCE.getButtonHTML(cn,'lang_xhtmlxtras_attribs_desc','{$pluginurl}/images/attribs.gif','mceAttributes',true)}return""},execCommand:function(editor_id,element,command,user_interface,value){var template,inst,elm;switch(command){case"mceCite":if(!this._anySel(editor_id))return true;template=new Array();template['file']='../../plugins/xhtmlxtras/cite.htm';template['width']=350;template['height']=250;tinyMCE.openWindow(template,{editor_id:editor_id});return true;case"mceAcronym":if(!this._anySel(editor_id))return true;template=new Array();template['file']='../../plugins/xhtmlxtras/acronym.htm';template['width']=350;template['height']=250;tinyMCE.openWindow(template,{editor_id:editor_id});return true;case"mceAbbr":if(!this._anySel(editor_id))return true;template=new Array();template['file']='../../plugins/xhtmlxtras/abbr.htm';template['width']=350;template['height']=250;tinyMCE.openWindow(template,{editor_id:editor_id});return true;case"mceIns":if(!this._anySel(editor_id))return true;template=new Array();template['file']='../../plugins/xhtmlxtras/ins.htm';template['width']=350;template['height']=310;tinyMCE.openWindow(template,{editor_id:editor_id});return true;case"mceDel":if(!this._anySel(editor_id))return true;template=new Array();template['file']='../../plugins/xhtmlxtras/del.htm';template['width']=350;template['height']=310;tinyMCE.openWindow(template,{editor_id:editor_id});return true;case"mceAttributes":inst=tinyMCE.getInstanceById(editor_id);elm=inst.getFocusElement();if(elm&&elm.nodeName!=='BODY'&&elm.className.indexOf('mceItem')==-1){tinyMCE.openWindow({file:'../../plugins/xhtmlxtras/attributes.htm',width:380,height:370},{editor_id:editor_id})}return true}return false},cleanup:function(type,content,inst){if(type=='insert_to_editor'&&tinyMCE.isIE&&!tinyMCE.isOpera){content=content.replace(/<abbr([^>]+)>/gi,'<html:ABBR $1>');content=content.replace(/<\/abbr>/gi,'</html:ABBR>')}return content},handleNodeChange:function(editor_id,node,undo_index,undo_levels,visual_aid,any_selection){var elm=tinyMCE.getParentElement(node);if(node==null)return;tinyMCE.switchClass(editor_id+'_attribs','mceButtonDisabled');if(!any_selection){tinyMCE.switchClass(editor_id+'_cite','mceButtonDisabled');tinyMCE.switchClass(editor_id+'_acronym','mceButtonDisabled');tinyMCE.switchClass(editor_id+'_abbr','mceButtonDisabled');tinyMCE.switchClass(editor_id+'_del','mceButtonDisabled');tinyMCE.switchClass(editor_id+'_ins','mceButtonDisabled')}else{tinyMCE.switchClass(editor_id+'_cite','mceButtonNormal');tinyMCE.switchClass(editor_id+'_acronym','mceButtonNormal');tinyMCE.switchClass(editor_id+'_abbr','mceButtonNormal');tinyMCE.switchClass(editor_id+'_del','mceButtonNormal');tinyMCE.switchClass(editor_id+'_ins','mceButtonNormal')}if(elm&&elm.nodeName!='BODY'&&elm.className.indexOf('mceItem')==-1)tinyMCE.switchClass(editor_id+'_attribs','mceButtonNormal');switch(node.nodeName){case"CITE":tinyMCE.switchClass(editor_id+'_cite','mceButtonSelected');return true;case"ACRONYM":tinyMCE.switchClass(editor_id+'_acronym','mceButtonSelected');return true;case"abbr":case"HTML:ABBR":case"ABBR":tinyMCE.switchClass(editor_id+'_abbr','mceButtonSelected');return true;case"DEL":tinyMCE.switchClass(editor_id+'_del','mceButtonSelected');return true;case"INS":tinyMCE.switchClass(editor_id+'_ins','mceButtonSelected');return true}return true},_anySel:function(editor_id){var inst=tinyMCE.getInstanceById(editor_id),t=inst.selection.getSelectedText(),pe;pe=tinyMCE.getParentElement(inst.getFocusElement(),'CITE,ACRONYM,ABBR,HTML:ABBR,DEL,INS');return pe||inst.getFocusElement().nodeName=="IMG"||(t&&t.length>0)}};tinyMCE.addPlugin("xhtmlxtras",TinyMCE_XHTMLXtrasPlugin);
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/xhtmlxtras/editor_plugin_src.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,199 @@
+ /**
+ * $Id: editor_plugin_src.js 42 2006-08-08 14:32:24Z spocke $
+ *
+ * @author Moxiecode - based on work by Andrew Tetlaw
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+/* Import plugin specific language pack */
+tinyMCE.importPluginLanguagePack('xhtmlxtras');
+
+var TinyMCE_XHTMLXtrasPlugin = {
+	getInfo : function() {
+		return {
+			longname : 'XHTML Xtras Plugin',
+			author : 'Moxiecode Systems AB',
+			authorurl : 'http://tinymce.moxiecode.com',
+			infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/xhtmlxtras',
+			version : tinyMCE.majorVersion + "." + tinyMCE.minorVersion
+		};
+	},
+
+	initInstance : function(inst) {
+		tinyMCE.importCSS(inst.getDoc(), tinyMCE.baseURL + "/plugins/xhtmlxtras/css/xhtmlxtras.css");
+	},
+
+	getControlHTML : function(cn) {
+		switch (cn) {
+			case "cite":
+				return tinyMCE.getButtonHTML(cn, 'lang_xhtmlxtras_cite_desc', '{$pluginurl}/images/cite.gif', 'mceCite', true);
+
+			case "acronym":
+				return tinyMCE.getButtonHTML(cn, 'lang_xhtmlxtras_acronym_desc', '{$pluginurl}/images/acronym.gif', 'mceAcronym', true);
+
+			case "abbr":
+				return tinyMCE.getButtonHTML(cn, 'lang_xhtmlxtras_abbr_desc', '{$pluginurl}/images/abbr.gif', 'mceAbbr', true);
+
+			case "del":
+				return tinyMCE.getButtonHTML(cn, 'lang_xhtmlxtras_del_desc', '{$pluginurl}/images/del.gif', 'mceDel', true);
+
+			case "ins":
+				return tinyMCE.getButtonHTML(cn, 'lang_xhtmlxtras_ins_desc', '{$pluginurl}/images/ins.gif', 'mceIns', true);
+
+			case "attribs":
+				return tinyMCE.getButtonHTML(cn, 'lang_xhtmlxtras_attribs_desc', '{$pluginurl}/images/attribs.gif', 'mceAttributes', true);
+		}
+
+		return "";
+	},
+
+	execCommand : function(editor_id, element, command, user_interface, value) {
+		var template, inst, elm;
+
+		switch (command) {
+			case "mceCite":
+				if (!this._anySel(editor_id))
+					return true;
+
+				template = new Array();
+				template['file'] = '../../plugins/xhtmlxtras/cite.htm';
+				template['width'] = 350;
+				template['height'] = 250;
+				tinyMCE.openWindow(template, {editor_id : editor_id});
+				return true;
+
+			case "mceAcronym":
+				if (!this._anySel(editor_id))
+					return true;
+
+				template = new Array();
+				template['file'] = '../../plugins/xhtmlxtras/acronym.htm';
+				template['width'] = 350;
+				template['height'] = 250;
+				tinyMCE.openWindow(template, {editor_id : editor_id});
+				return true;
+
+			case "mceAbbr":
+				if (!this._anySel(editor_id))
+					return true;
+
+				template = new Array();
+				template['file'] = '../../plugins/xhtmlxtras/abbr.htm';
+				template['width'] = 350;
+				template['height'] = 250;
+				tinyMCE.openWindow(template, {editor_id : editor_id});
+				return true;
+
+			case "mceIns":
+				if (!this._anySel(editor_id))
+					return true;
+
+				template = new Array();
+				template['file'] = '../../plugins/xhtmlxtras/ins.htm';
+				template['width'] = 350;
+				template['height'] = 310;
+				tinyMCE.openWindow(template, {editor_id : editor_id});
+				return true;
+
+			case "mceDel":
+				if (!this._anySel(editor_id))
+					return true;
+
+				template = new Array();
+				template['file'] = '../../plugins/xhtmlxtras/del.htm';
+				template['width'] = 350;
+				template['height'] = 310;
+				tinyMCE.openWindow(template, {editor_id : editor_id});
+				return true;
+
+			case "mceAttributes":
+				inst = tinyMCE.getInstanceById(editor_id);
+				elm = inst.getFocusElement();
+
+				if (elm && elm.nodeName !== 'BODY' && elm.className.indexOf('mceItem') == -1) {
+					tinyMCE.openWindow({
+						file : '../../plugins/xhtmlxtras/attributes.htm',
+						width : 380,
+						height : 370
+					}, {editor_id : editor_id});
+				}
+
+				return true;
+		}
+
+		return false;
+	},
+
+	cleanup : function(type, content, inst) {
+		if (type == 'insert_to_editor' && tinyMCE.isIE && !tinyMCE.isOpera) {
+			content = content.replace(/<abbr([^>]+)>/gi, '<html:ABBR $1>');
+			content = content.replace(/<\/abbr>/gi, '</html:ABBR>');
+		}
+
+		return content;
+	},
+
+	handleNodeChange : function(editor_id, node, undo_index,undo_levels, visual_aid, any_selection) {
+		var elm = tinyMCE.getParentElement(node);
+
+		if (node == null)
+			return;
+
+		tinyMCE.switchClass(editor_id + '_attribs', 'mceButtonDisabled');
+
+		if (!any_selection) {
+			// Disable the buttons
+			tinyMCE.switchClass(editor_id + '_cite', 'mceButtonDisabled');
+			tinyMCE.switchClass(editor_id + '_acronym', 'mceButtonDisabled');
+			tinyMCE.switchClass(editor_id + '_abbr', 'mceButtonDisabled');
+			tinyMCE.switchClass(editor_id + '_del', 'mceButtonDisabled');
+			tinyMCE.switchClass(editor_id + '_ins', 'mceButtonDisabled');
+		} else {
+			// A selection means the buttons should be active.
+			tinyMCE.switchClass(editor_id + '_cite', 'mceButtonNormal');
+			tinyMCE.switchClass(editor_id + '_acronym', 'mceButtonNormal');
+			tinyMCE.switchClass(editor_id + '_abbr', 'mceButtonNormal');
+			tinyMCE.switchClass(editor_id + '_del', 'mceButtonNormal');
+			tinyMCE.switchClass(editor_id + '_ins', 'mceButtonNormal');
+		}
+
+		if (elm && elm.nodeName != 'BODY' && elm.className.indexOf('mceItem') == -1)
+			tinyMCE.switchClass(editor_id + '_attribs', 'mceButtonNormal');
+
+		switch (node.nodeName) {
+			case "CITE":
+				tinyMCE.switchClass(editor_id + '_cite', 'mceButtonSelected');
+				return true;
+
+			case "ACRONYM":
+				tinyMCE.switchClass(editor_id + '_acronym', 'mceButtonSelected');
+				return true;
+
+			case "abbr": // IE
+			case "HTML:ABBR": // FF
+			case "ABBR":
+				tinyMCE.switchClass(editor_id + '_abbr', 'mceButtonSelected');
+				return true;
+
+			case "DEL":
+				tinyMCE.switchClass(editor_id + '_del', 'mceButtonSelected');
+				return true;
+
+			case "INS":
+				tinyMCE.switchClass(editor_id + '_ins', 'mceButtonSelected');
+				return true;
+		}
+
+		return true;
+	},
+
+	_anySel : function(editor_id) {
+		var inst = tinyMCE.getInstanceById(editor_id), t = inst.selection.getSelectedText(), pe;
+
+		pe = tinyMCE.getParentElement(inst.getFocusElement(), 'CITE,ACRONYM,ABBR,HTML:ABBR,DEL,INS');
+
+		return pe || inst.getFocusElement().nodeName == "IMG" || (t && t.length > 0);
+	}
+};
+
+tinyMCE.addPlugin("xhtmlxtras", TinyMCE_XHTMLXtrasPlugin);
Binary file includes/clientside/tinymce/plugins/xhtmlxtras/images/abbr.gif has changed
Binary file includes/clientside/tinymce/plugins/xhtmlxtras/images/acronym.gif has changed
Binary file includes/clientside/tinymce/plugins/xhtmlxtras/images/attribs.gif has changed
Binary file includes/clientside/tinymce/plugins/xhtmlxtras/images/cite.gif has changed
Binary file includes/clientside/tinymce/plugins/xhtmlxtras/images/date_time.gif has changed
Binary file includes/clientside/tinymce/plugins/xhtmlxtras/images/del.gif has changed
Binary file includes/clientside/tinymce/plugins/xhtmlxtras/images/ins.gif has changed
Binary file includes/clientside/tinymce/plugins/xhtmlxtras/images/remove_button_bg.gif has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/xhtmlxtras/ins.htm	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,169 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>{$lang_xhtmlxtras_title_ins_element}</title>
+	<script language="javascript" type="text/javascript" src="../../tiny_mce_popup.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/mctabs.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/form_utils.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/editable_selects.js"></script>
+	<script language="javascript" type="text/javascript" src="jscripts/element_common.js"></script>
+	<script language="javascript" type="text/javascript" src="jscripts/ins.js"></script>
+	<link rel="stylesheet" type="text/css" href="css/popup.css" />
+	<base target="_self" />
+</head>
+<body id="xhtmlxtrasins" onload="tinyMCEPopup.executeOnLoad('init();');" style="display: none">
+<form onsubmit="insertIns();return false;" action="#">
+	<div class="tabs">
+		<ul>
+			<li id="general_tab" class="current"><span><a href="javascript:mcTabs.displayTab('general_tab','general_panel');" onmousedown="return false;">{$lang_xhtmlxtras_general_tab}</a></span></li>
+			<!-- <li id="events_tab"><span><a href="javascript:mcTabs.displayTab('events_tab','events_panel');" onmousedown="return false;">{$lang_xhtmlxtras_events_tab}</a></span></li> -->
+		</ul>
+	</div>
+
+	<div class="panel_wrapper">
+		<div id="general_panel" class="panel current">
+			<fieldset>
+				<legend>{$lang_xhtmlxtras_fieldset_general_tab}</legend>
+				<table border="0" cellpadding="0" cellspacing="4">
+					<tr>
+						<td class="label"><label id="datetimelabel" for="datetime">{$lang_xhtmlxtras_attribute_label_datetime}</label>:</td> 
+						<td>
+							<table border="0" cellspacing="0" cellpadding="0">
+								<tr> 
+									<td><input id="datetime" name="datetime" type="text" value="" maxlength="19" class="field" /></td> 
+									<td><a href="javascript:insertDateTime('datetime');" class="mceButtonNormal"><img src="images/date_time.gif" class="picker" alt="{$lang_xhtmlxtras_insert_date}" title="{$lang_xhtmlxtras_insert_date}" /></a></td>
+								</tr>
+							</table>
+						</td>
+					</tr>
+					<tr>
+						<td class="label"><label id="citelabel" for="cite">{$lang_xhtmlxtras_attribute_label_cite}</label>:</td> 
+						<td><input id="cite" name="cite" type="text" value="" class="field" /></td> 
+					</tr>
+				</table>
+			</fieldset>
+			<fieldset>
+				<legend>{$lang_xhtmlxtras_fieldset_attrib_tab}</legend>
+				<table border="0" cellpadding="0" cellspacing="4">
+					<tr>
+						<td class="label"><label id="titlelabel" for="title">{$lang_xhtmlxtras_attribute_label_title}</label>:</td> 
+						<td><input id="title" name="title" type="text" value="" class="field" /></td> 
+					</tr>
+					<tr>
+						<td class="label"><label id="idlabel" for="id">{$lang_xhtmlxtras_attribute_label_id}</label>:</td> 
+						<td><input id="id" name="id" type="text" value="" class="field" /></td> 
+					</tr>
+					<tr>
+						<td class="label"><label id="classlabel" for="class">{$lang_xhtmlxtras_attribute_label_class}</label>:</td> 
+						<td>
+							<select id="class" name="class" class="field mceEditableSelect">
+								<option value="">{$lang_xhtmlxtras_not_set}</option> 
+							</select>
+						</td>
+					</tr>
+					<tr>
+						<td class="label"><label id="stylelabel" for="class">{$lang_xhtmlxtras_attribute_label_style}</label>:</td> 
+						<td><input id="style" name="style" type="text" value="" class="field" /></td> 
+					</tr>
+					<tr>
+						<td class="label"><label id="dirlabel" for="dir">{$lang_xhtmlxtras_attribute_label_langdir}</label>:</td> 
+						<td>
+							<select id="dir" name="dir" class="field"> 
+								<option value="">{$lang_xhtmlxtras_not_set}</option> 
+								<option value="ltr">{$lang_xhtmlxtras_attribute_option_ltr}</option> 
+								<option value="rtl">{$lang_xhtmlxtras_attribute_option_rtl}</option> 
+							</select>
+						</td> 
+					</tr>
+					<tr>
+						<td class="label"><label id="langlabel" for="lang">{$lang_xhtmlxtras_attribute_label_langcode}</label>:</td> 
+						<td>
+							<input id="lang" name="lang" type="text" value="" class="field" />
+						</td> 
+					</tr>
+				</table>
+			</fieldset>
+		</div>
+		<div id="events_panel" class="panel">
+			<fieldset>
+				<legend>{$lang_xhtmlxtras_fieldset_events_tab}</legend>
+
+				<table border="0" cellpadding="0" cellspacing="4">
+					<tr>
+						<td class="label"><label for="onfocus">onfocus</label>:</td> 
+						<td><input id="onfocus" name="onfocus" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onblur">onblur</label>:</td> 
+						<td><input id="onblur" name="onblur" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onclick">onclick</label>:</td> 
+						<td><input id="onclick" name="onclick" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="ondblclick">ondblclick</label>:</td> 
+						<td><input id="ondblclick" name="ondblclick" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onmousedown">onmousedown</label>:</td> 
+						<td><input id="onmousedown" name="onmousedown" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onmouseup">onmouseup</label>:</td> 
+						<td><input id="onmouseup" name="onmouseup" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onmouseover">onmouseover</label>:</td> 
+						<td><input id="onmouseover" name="onmouseover" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onmousemove">onmousemove</label>:</td> 
+						<td><input id="onmousemove" name="onmousemove" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onmouseout">onmouseout</label>:</td> 
+						<td><input id="onmouseout" name="onmouseout" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onkeypress">onkeypress</label>:</td> 
+						<td><input id="onkeypress" name="onkeypress" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onkeydown">onkeydown</label>:</td> 
+						<td><input id="onkeydown" name="onkeydown" type="text" value="" class="field" /></td> 
+					</tr>
+
+					<tr>
+						<td class="label"><label for="onkeyup">onkeyup</label>:</td> 
+						<td><input id="onkeyup" name="onkeyup" type="text" value="" class="field" /></td> 
+					</tr>
+				</table>
+			</fieldset>
+		</div>
+	</div>
+	<div class="mceActionPanel">
+		<div style="float: left">
+			<input type="button" id="insert" name="insert" value="{$lang_update}" onclick="insertIns();" />
+		</div>
+		<div style="float: left">
+			<input type="button" id="remove" name="remove" value="{$lang_xhtmlxtras_remove}" onclick="removeIns();" style="display: none;" />
+		</div>
+		<div style="float: right">
+			<input type="button" id="cancel" name="cancel" value="{$lang_cancel}" onclick="tinyMCEPopup.close();" />
+		</div>
+	</div>
+
+</form>
+
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/xhtmlxtras/jscripts/abbr.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,29 @@
+ /**
+ * $Id: editor_plugin_src.js 42 2006-08-08 14:32:24Z spocke $
+ *
+ * @author Moxiecode - based on work by Andrew Tetlaw
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+function preinit() {
+	// Initialize
+	tinyMCE.setWindowArg('mce_windowresize', false);
+}
+
+function init() {
+	tinyMCEPopup.resizeToInnerSize();
+	SXE.initElementDialog('abbr');
+	if (SXE.currentAction == "update") {
+		SXE.showRemoveButton();
+	}
+}
+
+function insertAbbr() {
+	SXE.insertElement(tinyMCE.isIE && !tinyMCE.isOpera ? 'html:ABBR' : 'abbr');
+	tinyMCEPopup.close();
+}
+
+function removeAbbr() {
+	SXE.removeElement('abbr');
+	tinyMCEPopup.close();
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/xhtmlxtras/jscripts/acronym.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,29 @@
+ /**
+ * $Id: editor_plugin_src.js 42 2006-08-08 14:32:24Z spocke $
+ *
+ * @author Moxiecode - based on work by Andrew Tetlaw
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+function preinit() {
+	// Initialize
+	tinyMCE.setWindowArg('mce_windowresize', false);
+}
+
+function init() {
+	tinyMCEPopup.resizeToInnerSize();
+	SXE.initElementDialog('acronym');
+	if (SXE.currentAction == "update") {
+		SXE.showRemoveButton();
+	}
+}
+
+function insertAcronym() {
+	SXE.insertElement('acronym');
+	tinyMCEPopup.close();
+}
+
+function removeAcronym() {
+	SXE.removeElement('acronym');
+	tinyMCEPopup.close();
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/xhtmlxtras/jscripts/attributes.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,130 @@
+ /**
+ * $Id: editor_plugin_src.js 42 2006-08-08 14:32:24Z spocke $
+ *
+ * @author Moxiecode - based on work by Andrew Tetlaw
+ * @copyright Copyright © 2004-2006, Moxiecode Systems AB, All rights reserved.
+ */
+
+function preinit() {
+	// Initialize
+	tinyMCE.setWindowArg('mce_windowresize', false);
+}
+
+function init() {
+	tinyMCEPopup.resizeToInnerSize();
+	var inst = tinyMCE.getInstanceById(tinyMCE.getWindowArg('editor_id'));
+	var elm = inst.getFocusElement();
+
+	var f = document.forms[0];
+	
+	var onclick = tinyMCE.cleanupEventStr(tinyMCE.getAttrib(elm, 'onclick'));
+
+	setFormValue('title', tinyMCE.getAttrib(elm, 'title'));
+	setFormValue('id', tinyMCE.getAttrib(elm, 'id'));
+	setFormValue('style', tinyMCE.serializeStyle(tinyMCE.parseStyle(tinyMCE.getAttrib(elm, "style"))));
+	setFormValue('dir', tinyMCE.getAttrib(elm, 'dir'));
+	setFormValue('lang', tinyMCE.getAttrib(elm, 'lang'));
+	setFormValue('tabindex', tinyMCE.getAttrib(elm, 'tabindex', typeof(elm.tabindex) != "undefined" ? elm.tabindex : ""));
+	setFormValue('accesskey', tinyMCE.getAttrib(elm, 'accesskey', typeof(elm.accesskey) != "undefined" ? elm.accesskey : ""));
+	setFormValue('onfocus', tinyMCE.cleanupEventStr(tinyMCE.getAttrib(elm, 'onfocus')));
+	setFormValue('onblur', tinyMCE.cleanupEventStr(tinyMCE.getAttrib(elm, 'onblur')));
+	setFormValue('onclick', onclick);
+	setFormValue('ondblclick', tinyMCE.cleanupEventStr(tinyMCE.getAttrib(elm, 'ondblclick')));
+	setFormValue('onmousedown', tinyMCE.cleanupEventStr(tinyMCE.getAttrib(elm, 'onmousedown')));
+	setFormValue('onmouseup', tinyMCE.cleanupEventStr(tinyMCE.getAttrib(elm, 'onmouseup')));
+	setFormValue('onmouseover', tinyMCE.cleanupEventStr(tinyMCE.getAttrib(elm, 'onmouseover')));
+	setFormValue('onmousemove', tinyMCE.cleanupEventStr(tinyMCE.getAttrib(elm, 'onmousemove')));
+	setFormValue('onmouseout', tinyMCE.cleanupEventStr(tinyMCE.getAttrib(elm, 'onmouseout')));
+	setFormValue('onkeypress', tinyMCE.cleanupEventStr(tinyMCE.getAttrib(elm, 'onkeypress')));
+	setFormValue('onkeydown', tinyMCE.cleanupEventStr(tinyMCE.getAttrib(elm, 'onkeydown')));
+	setFormValue('onkeyup', tinyMCE.cleanupEventStr(tinyMCE.getAttrib(elm, 'onkeyup')));
+	
+	className = tinyMCE.getVisualAidClass(tinyMCE.getAttrib(elm, 'class'), false);
+		
+	addClassesToList('classlist', 'advlink_styles');
+	selectByValue(f, 'classlist', className, true);
+	
+	TinyMCE_EditableSelects.init();
+}
+
+function setFormValue(name, value) {
+	if(value && document.forms[0].elements[name]){
+		document.forms[0].elements[name].value = value;
+	}
+}
+
+function insertAction() {
+	var inst = tinyMCE.getInstanceById(tinyMCE.getWindowArg('editor_id'));
+	var elm = inst.getFocusElement();
+
+	tinyMCEPopup.execCommand("mceBeginUndoLevel");	
+	tinyMCEPopup.restoreSelection();
+	
+	setAllAttribs(elm);
+	
+	tinyMCE.handleVisualAid(inst.getBody(), true, inst.visualAid, inst);
+	tinyMCE._setEventsEnabled(inst.getBody(), false);
+	tinyMCEPopup.execCommand("mceEndUndoLevel");
+	tinyMCEPopup.close();
+}
+
+function setAttrib(elm, attrib, value) {
+	var formObj = document.forms[0];
+	var valueElm = formObj.elements[attrib.toLowerCase()];
+
+	if (typeof(value) == "undefined" || value == null) {
+		value = "";
+
+		if (valueElm)
+			value = valueElm.value;
+	}
+
+	if (value != "") {
+		tinyMCE.setAttrib(elm, attrib.toLowerCase(), value);
+
+		if (attrib == "style")
+			attrib = "style.cssText";
+
+		if (attrib.substring(0, 2) == 'on')
+			value = 'return true;' + value;
+
+		if (attrib == "class")
+			attrib = "className";
+
+		eval('elm.' + attrib + "=value;");
+	} else
+		elm.removeAttribute(attrib);
+}
+
+function setAllAttribs(elm) {
+	var f = document.forms[0];
+
+	setAttrib(elm, 'title');
+	setAttrib(elm, 'id');
+	setAttrib(elm, 'style');
+	setAttrib(elm, 'class', getSelectValue(f, 'classlist'));
+	setAttrib(elm, 'dir');
+	setAttrib(elm, 'lang');
+	setAttrib(elm, 'tabindex');
+	setAttrib(elm, 'accesskey');
+	setAttrib(elm, 'onfocus');
+	setAttrib(elm, 'onblur');
+	setAttrib(elm, 'onclick');
+	setAttrib(elm, 'ondblclick');
+	setAttrib(elm, 'onmousedown');
+	setAttrib(elm, 'onmouseup');
+	setAttrib(elm, 'onmouseover');
+	setAttrib(elm, 'onmousemove');
+	setAttrib(elm, 'onmouseout');
+	setAttrib(elm, 'onkeypress');
+	setAttrib(elm, 'onkeydown');
+	setAttrib(elm, 'onkeyup');
+
+	// Refresh in old MSIE
+	if (tinyMCE.isMSIE5)
+		elm.outerHTML = elm.outerHTML;
+}
+
+function insertAttribute() {
+	tinyMCEPopup.close();
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/xhtmlxtras/jscripts/cite.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,29 @@
+ /**
+ * $Id: editor_plugin_src.js 42 2006-08-08 14:32:24Z spocke $
+ *
+ * @author Moxiecode - based on work by Andrew Tetlaw
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+function preinit() {
+	// Initialize
+	tinyMCE.setWindowArg('mce_windowresize', false);
+}
+
+function init() {
+	tinyMCEPopup.resizeToInnerSize();
+	SXE.initElementDialog('cite');
+	if (SXE.currentAction == "update") {
+		SXE.showRemoveButton();
+	}
+}
+
+function insertCite() {
+	SXE.insertElement('cite');
+	tinyMCEPopup.close();
+}
+
+function removeCite() {
+	SXE.removeElement('cite');
+	tinyMCEPopup.close();
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/xhtmlxtras/jscripts/del.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,54 @@
+ /**
+ * $Id: editor_plugin_src.js 42 2006-08-08 14:32:24Z spocke $
+ *
+ * @author Moxiecode - based on work by Andrew Tetlaw
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+function preinit() {
+	// Initialize
+	tinyMCE.setWindowArg('mce_windowresize', false);
+}
+
+function init() {
+	tinyMCEPopup.resizeToInnerSize();
+	SXE.initElementDialog('del');
+	if (SXE.currentAction == "update") {
+		setFormValue('datetime', tinyMCE.getAttrib(SXE.updateElement, 'datetime'));
+		setFormValue('cite', tinyMCE.getAttrib(SXE.updateElement, 'cite'));
+		SXE.showRemoveButton();
+	}
+}
+
+function setElementAttribs(elm) {
+	setAllCommonAttribs(elm);
+	setAttrib(elm, 'datetime');
+	setAttrib(elm, 'cite');
+}
+
+function insertDel() {
+	var elm = tinyMCE.getParentElement(SXE.focusElement, 'del');
+
+	tinyMCEPopup.execCommand('mceBeginUndoLevel');
+	if (elm == null) {
+		var s = SXE.inst.selection.getSelectedHTML();
+		if(s.length > 0) {
+			tinyMCEPopup.execCommand('mceInsertContent', false, '<del id="#sxe_temp_del#">' + s + '</del>');
+			var elementArray = tinyMCE.getElementsByAttributeValue(SXE.inst.getBody(), 'del', 'id', '#sxe_temp_del#');
+			for (var i=0; i<elementArray.length; i++) {
+				var elm = elementArray[i];
+				setElementAttribs(elm);
+			}
+		}
+	} else {
+		setElementAttribs(elm);
+	}
+	tinyMCE.triggerNodeChange();
+	tinyMCEPopup.execCommand('mceEndUndoLevel');
+	tinyMCEPopup.close();
+}
+
+function removeDel() {
+	SXE.removeElement('del');
+	tinyMCEPopup.close();
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/xhtmlxtras/jscripts/element_common.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,241 @@
+ /**
+ * $Id: editor_plugin_src.js 42 2006-08-08 14:32:24Z spocke $
+ *
+ * @author Moxiecode - based on work by Andrew Tetlaw
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+function initCommonAttributes(elm) {
+	var formObj = document.forms[0];
+
+	// Setup form data for common element attributes
+	setFormValue('title', tinyMCE.getAttrib(elm, 'title'));
+	setFormValue('id', tinyMCE.getAttrib(elm, 'id'));
+	selectByValue(formObj, 'class', tinyMCE.getAttrib(elm, 'class'), true);
+	setFormValue('style', tinyMCE.getAttrib(elm, 'style'));
+	selectByValue(formObj, 'dir', tinyMCE.getAttrib(elm, 'dir'));
+	setFormValue('lang', tinyMCE.getAttrib(elm, 'lang'));
+	setFormValue('onfocus', tinyMCE.getAttrib(elm, 'onfocus'));
+	setFormValue('onblur', tinyMCE.getAttrib(elm, 'onblur'));
+	setFormValue('onclick', tinyMCE.getAttrib(elm, 'onclick'));
+	setFormValue('ondblclick', tinyMCE.getAttrib(elm, 'ondblclick'));
+	setFormValue('onmousedown', tinyMCE.getAttrib(elm, 'onmousedown'));
+	setFormValue('onmouseup', tinyMCE.getAttrib(elm, 'onmouseup'));
+	setFormValue('onmouseover', tinyMCE.getAttrib(elm, 'onmouseover'));
+	setFormValue('onmousemove', tinyMCE.getAttrib(elm, 'onmousemove'));
+	setFormValue('onmouseout', tinyMCE.getAttrib(elm, 'onmouseout'));
+	setFormValue('onkeypress', tinyMCE.getAttrib(elm, 'onkeypress'));
+	setFormValue('onkeydown', tinyMCE.getAttrib(elm, 'onkeydown'));
+	setFormValue('onkeyup', tinyMCE.getAttrib(elm, 'onkeyup'));
+}
+
+function setFormValue(name, value) {
+	if(document.forms[0].elements[name]) document.forms[0].elements[name].value = value;
+}
+
+function insertDateTime(id) {
+	document.getElementById(id).value = getDateTime(new Date(), "%Y-%m-%dT%H:%M:%S");
+}
+
+function getDateTime(d, fmt) {
+	fmt = fmt.replace("%D", "%m/%d/%y");
+	fmt = fmt.replace("%r", "%I:%M:%S %p");
+	fmt = fmt.replace("%Y", "" + d.getFullYear());
+	fmt = fmt.replace("%y", "" + d.getYear());
+	fmt = fmt.replace("%m", addZeros(d.getMonth()+1, 2));
+	fmt = fmt.replace("%d", addZeros(d.getDate(), 2));
+	fmt = fmt.replace("%H", "" + addZeros(d.getHours(), 2));
+	fmt = fmt.replace("%M", "" + addZeros(d.getMinutes(), 2));
+	fmt = fmt.replace("%S", "" + addZeros(d.getSeconds(), 2));
+	fmt = fmt.replace("%I", "" + ((d.getHours() + 11) % 12 + 1));
+	fmt = fmt.replace("%p", "" + (d.getHours() < 12 ? "AM" : "PM"));
+	fmt = fmt.replace("%%", "%");
+
+	return fmt;
+}
+
+function addZeros(value, len) {
+	var i;
+
+	value = "" + value;
+
+	if (value.length < len) {
+		for (i=0; i<(len-value.length); i++)
+			value = "0" + value;
+	}
+
+	return value;
+}
+
+function selectByValue(form_obj, field_name, value, add_custom, ignore_case) {
+	if (!form_obj || !form_obj.elements[field_name])
+		return;
+
+	var sel = form_obj.elements[field_name];
+
+	var found = false;
+	for (var i=0; i<sel.options.length; i++) {
+		var option = sel.options[i];
+
+		if (option.value == value || (ignore_case && option.value.toLowerCase() == value.toLowerCase())) {
+			option.selected = true;
+			found = true;
+		} else
+			option.selected = false;
+	}
+
+	if (!found && add_custom && value != '') {
+		var option = new Option('Value: ' + value, value);
+		option.selected = true;
+		sel.options[sel.options.length] = option;
+	}
+
+	return found;
+}
+
+function setAttrib(elm, attrib, value) {
+	var formObj = document.forms[0];
+	var valueElm = formObj.elements[attrib.toLowerCase()];
+
+	if (typeof(value) == "undefined" || value == null) {
+		value = "";
+
+		if (valueElm)
+			value = valueElm.value;
+	}
+
+	if (value != "") {
+		if (attrib == "style")
+			attrib = "style.cssText";
+
+		if (attrib.substring(0, 2) == 'on')
+			value = 'return true;' + value;
+
+		if (attrib == "class") {
+			tinyMCE.addCSSClass(elm, value);
+			return;
+		}
+
+		elm.setAttribute(attrib.toLowerCase(), value);
+	} else
+		elm.removeAttribute(attrib);
+}
+
+function setAllCommonAttribs(elm) {
+	setAttrib(elm, 'title');
+	setAttrib(elm, 'id');
+	setAttrib(elm, 'class');
+	setAttrib(elm, 'style');
+	setAttrib(elm, 'dir');
+	setAttrib(elm, 'lang');
+	/*setAttrib(elm, 'onfocus');
+	setAttrib(elm, 'onblur');
+	setAttrib(elm, 'onclick');
+	setAttrib(elm, 'ondblclick');
+	setAttrib(elm, 'onmousedown');
+	setAttrib(elm, 'onmouseup');
+	setAttrib(elm, 'onmouseover');
+	setAttrib(elm, 'onmousemove');
+	setAttrib(elm, 'onmouseout');
+	setAttrib(elm, 'onkeypress');
+	setAttrib(elm, 'onkeydown');
+	setAttrib(elm, 'onkeyup');*/
+}
+
+SXE = {
+	currentAction : "insert",
+	inst : tinyMCE.getInstanceById(tinyMCE.getWindowArg('editor_id')),
+	updateElement : null
+}
+
+SXE.focusElement = SXE.inst.getFocusElement();
+
+SXE.initElementDialog = function(element_name) {
+	addClassesToList('class', 'xhtmlxtras_styles');
+	TinyMCE_EditableSelects.init();
+
+	element_name = element_name.toLowerCase();
+	var elm = tinyMCE.getParentElement(SXE.focusElement, element_name);
+	if (elm != null && elm.nodeName == element_name.toUpperCase()) {
+		SXE.currentAction = "update";
+	}
+
+	if (SXE.currentAction == "update") {
+		initCommonAttributes(elm);
+		SXE.updateElement = elm;
+	}
+
+	document.forms[0].insert.value = tinyMCE.getLang('lang_' + SXE.currentAction, 'Insert', true); 
+}
+
+SXE.insertElement = function(element_name) {
+	var elm = tinyMCE.getParentElement(SXE.focusElement, element_name), h, tagName;
+
+	tinyMCEPopup.execCommand('mceBeginUndoLevel');
+	if (elm == null) {
+		var s = SXE.inst.selection.getSelectedHTML();
+		if(s.length > 0) {
+			tagName = element_name;
+
+			if (tinyMCE.isIE && !tinyMCE.isOpera && element_name.indexOf('html:') == 0)
+				element_name = element_name.substring(5).toLowerCase();
+
+			h = '<' + tagName + ' id="#sxe_temp_' + element_name + '#">' + s + '</' + tagName + '>';
+
+			tinyMCEPopup.execCommand('mceInsertContent', false, h);
+
+			var elementArray = tinyMCE.getElementsByAttributeValue(SXE.inst.getBody(), element_name, 'id', '#sxe_temp_' + element_name + '#');
+			for (var i=0; i<elementArray.length; i++) {
+				var elm = elementArray[i];
+
+				elm.id = '';
+				elm.setAttribute('id', '');
+				elm.removeAttribute('id');
+
+				setAllCommonAttribs(elm);
+			}
+		}
+	} else {
+		setAllCommonAttribs(elm);
+	}
+	tinyMCE.triggerNodeChange();
+	tinyMCEPopup.execCommand('mceEndUndoLevel');
+}
+
+SXE.removeElement = function(element_name){
+	element_name = element_name.toLowerCase();
+	elm = tinyMCE.getParentElement(SXE.focusElement, element_name);
+	if(elm && elm.nodeName == element_name.toUpperCase()){
+		tinyMCEPopup.execCommand('mceBeginUndoLevel');
+		tinyMCE.execCommand('mceRemoveNode', false, elm);
+		tinyMCE.triggerNodeChange();
+		tinyMCEPopup.execCommand('mceEndUndoLevel');
+	}
+}
+
+SXE.showRemoveButton = function() {
+		document.getElementById("remove").style.display = 'block';
+}
+
+SXE.containsClass = function(elm,cl) {
+	return (elm.className.indexOf(cl) > -1) ? true : false;
+}
+
+SXE.removeClass = function(elm,cl) {
+	if(elm.className == null || elm.className == "" || !SXE.containsClass(elm,cl)) {
+		return true;
+	}
+	var classNames = elm.className.split(" ");
+	var newClassNames = "";
+	for (var x = 0, cnl = classNames.length; x < cnl; x++) {
+		if (classNames[x] != cl) {
+			newClassNames += (classNames[x] + " ");
+		}
+	}
+	elm.className = newClassNames.substring(0,newClassNames.length-1); //removes extra space at the end
+}
+
+SXE.addClass = function(elm,cl) {
+	if(!SXE.containsClass(elm,cl)) elm.className ? elm.className += " " + cl : elm.className = cl;
+	return true;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/xhtmlxtras/jscripts/ins.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,53 @@
+ /**
+ * $Id: editor_plugin_src.js 42 2006-08-08 14:32:24Z spocke $
+ *
+ * @author Moxiecode - based on work by Andrew Tetlaw
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+function preinit() {
+	// Initialize
+	tinyMCE.setWindowArg('mce_windowresize', false);
+}
+
+function init() {
+	tinyMCEPopup.resizeToInnerSize();
+	SXE.initElementDialog('ins');
+	if (SXE.currentAction == "update") {
+		setFormValue('datetime', tinyMCE.getAttrib(SXE.updateElement, 'datetime'));
+		setFormValue('cite', tinyMCE.getAttrib(SXE.updateElement, 'cite'));
+		SXE.showRemoveButton();
+	}
+}
+
+function setElementAttribs(elm) {
+	setAllCommonAttribs(elm);
+	setAttrib(elm, 'datetime');
+	setAttrib(elm, 'cite');
+}
+
+function insertIns() {
+	var elm = tinyMCE.getParentElement(SXE.focusElement, 'ins');
+	tinyMCEPopup.execCommand('mceBeginUndoLevel');
+	if (elm == null) {
+		var s = SXE.inst.selection.getSelectedHTML();
+		if(s.length > 0) {
+			tinyMCEPopup.execCommand('mceInsertContent', false, '<ins id="#sxe_temp_ins#">' + s + '</ins>');
+			var elementArray = tinyMCE.getElementsByAttributeValue(SXE.inst.getBody(), 'ins', 'id', '#sxe_temp_ins#');
+			for (var i=0; i<elementArray.length; i++) {
+				var elm = elementArray[i];
+				setElementAttribs(elm);
+			}
+		}
+	} else {
+		setElementAttribs(elm);
+	}
+	tinyMCE.triggerNodeChange();
+	tinyMCEPopup.execCommand('mceEndUndoLevel');
+	tinyMCEPopup.close();
+}
+
+function removeIns() {
+	SXE.removeElement('ins');
+	tinyMCEPopup.close();
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/xhtmlxtras/langs/en.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,42 @@
+// UK lang variables
+
+tinyMCE.addToLang('xhtmlxtras',{
+cite_desc : 'Citation',
+abbr_desc : 'Abbreviation',
+acronym_desc : 'Acronym',
+del_desc : 'Deletion',
+ins_desc : 'Insertion',
+attribute_label_title : 'Title',
+attribute_label_id : 'ID',
+attribute_label_class : 'Class',
+attribute_label_style : 'Style',
+attribute_label_cite : 'Cite',
+attribute_label_datetime : 'Date/Time',
+attribute_label_langdir : 'Text Direction',
+attribute_option_ltr : 'Left to right',
+attribute_option_rtl : 'Right to left',
+attribute_label_langcode : 'Language',
+attribute_label_tabindex : 'TabIndex',
+attribute_label_accesskey : 'AccessKey',
+attribute_label_cite : 'Cite',
+attribute_events_tab : 'Events',
+attribute_attrib_tab : 'Attributes',
+general_tab : 'General',
+attrib_tab : 'Attributes',
+events_tab : 'Events',
+fieldset_general_tab : 'General Settings',
+fieldset_attrib_tab : 'Element Attributes',
+fieldset_events_tab : 'Element Events',
+title_ins_element : 'Insertion Element',
+title_del_element : 'Deletion Element',
+title_acronym_element : 'Acronym Element',
+title_abbr_element : 'Abbreviation Element',
+title_cite_element : 'Citation Element',
+remove : 'Remove',
+not_set : '--not set--',
+insert_date : 'Insert current date/time',
+option_ltr : 'Left to right',
+option_rtl : 'Right to left',
+attribs_desc : 'Insert/Edit Attributes',
+attribs_title : 'Insert/Edit Attributes'
+});
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/zoom/editor_plugin.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+var TinyMCE_ZoomPlugin={getInfo:function(){return{longname:'Zoom',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/zoom',version:tinyMCE.majorVersion+"."+tinyMCE.minorVersion}},getControlHTML:function(control_name){if(!tinyMCE.isMSIE||tinyMCE.isMSIE5_0||tinyMCE.isOpera)return"";switch(control_name){case"zoom":return'<select id="{$editor_id}_zoomSelect" name="{$editor_id}_zoomSelect" onfocus="tinyMCE.addSelectAccessibility(event, this, window);" onchange="tinyMCE.execInstanceCommand(\'{$editor_id}\',\'mceZoom\',false,this.options[this.selectedIndex].value);" class="mceSelectList">'+'<option value="100%">+ 100%</option>'+'<option value="150%">+ 150%</option>'+'<option value="200%">+ 200%</option>'+'<option value="250%">+ 250%</option>'+'</select>'}return""},execCommand:function(editor_id,element,command,user_interface,value){switch(command){case"mceZoom":tinyMCE.getInstanceById(editor_id).contentDocument.body.style.zoom=value;tinyMCE.getInstanceById(editor_id).contentDocument.body.style.mozZoom=value;return true}return false}};tinyMCE.addPlugin("zoom",TinyMCE_ZoomPlugin);
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/zoom/editor_plugin_src.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,56 @@
+/**
+ * $Id: editor_plugin_src.js 201 2007-02-12 15:56:56Z spocke $
+ *
+ * @author Moxiecode
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+var TinyMCE_ZoomPlugin = {
+	getInfo : function() {
+		return {
+			longname : 'Zoom',
+			author : 'Moxiecode Systems AB',
+			authorurl : 'http://tinymce.moxiecode.com',
+			infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/zoom',
+			version : tinyMCE.majorVersion + "." + tinyMCE.minorVersion
+		};
+	},
+
+	/**
+	 * Returns the HTML contents of the zoom control.
+	 */
+	getControlHTML : function(control_name) {
+		if (!tinyMCE.isMSIE || tinyMCE.isMSIE5_0 || tinyMCE.isOpera)
+			return "";
+
+		switch (control_name) {
+			case "zoom":
+				return '<select id="{$editor_id}_zoomSelect" name="{$editor_id}_zoomSelect" onfocus="tinyMCE.addSelectAccessibility(event, this, window);" onchange="tinyMCE.execInstanceCommand(\'{$editor_id}\',\'mceZoom\',false,this.options[this.selectedIndex].value);" class="mceSelectList">' + 
+						'<option value="100%">+ 100%</option>' + 
+						'<option value="150%">+ 150%</option>' + 
+						'<option value="200%">+ 200%</option>' + 
+						'<option value="250%">+ 250%</option>' + 
+						'</select>';
+		}
+
+		return "";
+	},
+
+	/**
+	 * Executes the mceZoom command.
+	 */
+	execCommand : function(editor_id, element, command, user_interface, value) {
+		// Handle commands
+		switch (command) {
+			case "mceZoom":
+				tinyMCE.getInstanceById(editor_id).contentDocument.body.style.zoom = value;
+				tinyMCE.getInstanceById(editor_id).contentDocument.body.style.mozZoom = value;
+				return true;
+		}
+
+		// Pass to next handler in chain
+		return false;
+	}
+};
+
+tinyMCE.addPlugin("zoom", TinyMCE_ZoomPlugin);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/zoom/readme.txt	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+Check the TinyMCE documentation for details on this plugin.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/switcher.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,51 @@
+function readCookie(name) {var nameEQ = name + "=";var ca = document.cookie.split(';');for(var i=0;i < ca.length;i++){var c = ca[i];while (c.charAt(0)==' ') c = c.substring(1,c.length);if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);}return null;}
+function createCookie(name,value,days){if (days){var date = new Date();date.setTime(date.getTime()+(days*24*60*60*1000));var expires = "; expires="+date.toGMTString();}else var expires = "";document.cookie = name+"="+value+expires+"; path=/";}
+function eraseCookie(name) {createCookie(name,"",-1);}
+
+function initSwitcher()
+{
+  if(readCookie('tmce_demo_mode') == 'tinymce')
+  {
+    switchToMCE();
+  }
+}
+
+function switchToMCE()
+{
+  elem = document.getElementById('tMceEditor');
+  tinyMCE.addMCEControl(elem, 'content', document);
+  createCookie('tmce_demo_mode', 'tinymce', 365);
+}
+
+function switchToText()
+{
+  elem = document.getElementById('tMceEditor');
+  tinyMCE.removeMCEControl('content');
+  createCookie('tmce_demo_mode', 'text', 365);
+}
+
+function switchEditor()
+{
+  if(readCookie('tmce_demo_mode') == 'tinymce')
+  {
+    switchToText();
+  }
+  else
+  {
+    switchToMCE();
+  }
+}
+
+window.onload = initSwitcher;
+
+tinyMCE.init({
+      mode : "exact",
+      elements : '',
+      theme_advanced_resize_horizontal : false,
+      theme_advanced_resizing : true,
+      theme_advanced_toolbar_location : "top",
+      theme_advanced_toolbar_align : "left",
+      theme_advanced_buttons1_add : "fontselect,fontsizeselect",
+      theme_advanced_statusbar_location : 'bottom'
+  });
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/themes/advanced/about.htm	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,52 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>{$lang_about_title}</title>
+	<script language="javascript" type="text/javascript" src="../../tiny_mce_popup.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/mctabs.js"></script>
+	<script language="javascript" type="text/javascript" src="jscripts/about.js"></script>
+	<base target="_self" />
+</head>
+<body id="about" onload="tinyMCEPopup.executeOnLoad('init();');" style="display: none">
+		<div class="tabs">
+			<ul>
+				<li id="general_tab" class="current"><span><a href="javascript:mcTabs.displayTab('general_tab','general_panel');" onmousedown="return false;">{$lang_about}</a></span></li>
+				<li id="help_tab"><span><a href="javascript:mcTabs.displayTab('help_tab','help_panel');" onmousedown="return false;">{$lang_help}</a></span></li>
+				<li id="plugins_tab"><span><a href="javascript:mcTabs.displayTab('plugins_tab','plugins_panel');" onmousedown="return false;">{$lang_plugins}</a></span></li>
+			</ul>
+		</div>
+
+		<div class="panel_wrapper">
+			<div id="general_panel" class="panel current">
+				<h3>{$lang_about_title}</h3>
+				<p>Version: {$tinymce_version} ({$tinymce_releasedate})</p>
+				<p>TinyMCE is a platform independent web based Javascript HTML WYSIWYG editor control released as Open Source under <a href="../../license.txt" target="_blank">LGPL</a>
+				by Moxiecode Systems AB. It has the ability to convert HTML TEXTAREA fields or other HTML elements to editor instances.</p>
+				<p>Copyright &copy; 2003-2007, <a href="http://www.moxiecode.com" target="_blank">Moxiecode Systems AB</a>, All rights reserved.</p>
+				<p>For more information about this software visit the <a href="http://tinymce.moxiecode.com" target="_blank">TinyMCE website</a>.</p>
+
+				<div id="buttoncontainer"></div>
+			</div>
+
+			<div id="plugins_panel" class="panel">
+				<div id="pluginscontainer">
+					<h3>{$lang_loaded_plugins}</h3>
+
+					<div id="plugintablecontainer">
+					</div>
+
+					<p>&nbsp;</p>
+				</div>
+			</div>
+
+			<div id="help_panel" class="panel noscroll" style="overflow: visible;">
+				<div id="iframecontainer"></div>
+			</div>
+		</div>
+
+		<div class="mceActionPanel">
+			<div style="float: right">
+				<input type="button" id="cancel" name="cancel" value="{$lang_close}" onclick="tinyMCEPopup.close();" />
+			</div>
+		</div>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/themes/advanced/anchor.htm	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,33 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>{$lang_insert_anchor_title}</title>
+	<script language="javascript" type="text/javascript" src="../../tiny_mce_popup.js"></script>
+	<script language="javascript" type="text/javascript" src="jscripts/anchor.js"></script>
+	<base target="_self" />
+</head>
+<body onload="tinyMCEPopup.executeOnLoad('init();');" style="display: none">
+<form onsubmit="insertAnchor();return false;" action="#">
+
+	<table border="0" cellpadding="4" cellspacing="0">
+		<tr>
+			<td colspan="2" class="title">{$lang_insert_anchor_title}</td>
+		</tr>
+		<tr>
+			<td nowrap="nowrap">{$lang_insert_anchor_name}:</td>
+			<td><input name="anchorName" type="text" id="anchorName" value="" style="width: 200px" /></td>
+		</tr>
+	</table>
+
+	<div class="mceActionPanel">
+		<div style="float: left">
+			<input type="button" id="insert" name="insert" value="{$lang_update}" onclick="insertAnchor();" />
+		</div>
+
+		<div style="float: right">
+			<input type="button" id="cancel" name="cancel" value="{$lang_cancel}" onclick="tinyMCEPopup.close();" />
+		</div>
+	</div>
+
+</form>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/themes/advanced/charmap.htm	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,53 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>{$lang_theme_charmap_title}</title>
+	<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+	<script language="javascript" type="text/javascript" src="../../tiny_mce_popup.js"></script>
+	<script language="javascript" type="text/javascript" src="jscripts/charmap.js"></script>
+	<base target="_self" />
+</head>
+<body onload="tinyMCEPopup.executeOnLoad('init();');" style="display: none">
+<table align="center" border="0" cellspacing="0" cellpadding="2">
+    <tr>
+        <td colspan="2" class="title">{$lang_theme_charmap_title}</td>
+    </tr>
+    <tr>
+        <td rowspan="2" align="left" valign="top">
+            <script language="javascript" type="text/javascript">renderCharMapHTML();</script>
+        </td>
+        <td width="100" align="center" valign="top">
+            <table border="0" cellpadding="0" cellspacing="0" width="100" style="height: 100px">
+                <tr>
+                    <td class="charmapOver" style="font-size: 40px; height:80px;" id="codeV">&nbsp;</td>
+                </tr>
+                <tr>
+                    <td style="font-size: 10px; font-family: Arial, Helvetica, sans-serif; text-align:center;" id="codeN">&nbsp;</td>
+                </tr>
+            </table>
+        </td>
+    </tr>
+    <tr>
+        <td valign="bottom" style="padding-bottom: 3px;">
+            <table width="100" align="center" border="0" cellpadding="2" cellspacing="0">
+                <tr>
+                    <td align="center" style="border-left: 1px solid #666699; border-top: 1px solid #666699; border-right: 1px solid #666699;">HTML-Code</td>
+                </tr>
+                <tr>
+                    <td style="font-size: 16px; font-weight: bold; border-left: 1px solid #666699; border-bottom: 1px solid #666699; border-right: 1px solid #666699;" id="codeA" align="center">&nbsp;</td>
+                </tr>
+                <tr>
+                    <td style="font-size: 1px;">&nbsp;</td>
+                </tr>
+                <tr>
+                    <td align="center" style="border-left: 1px solid #666699; border-top: 1px solid #666699; border-right: 1px solid #666699;">NUM-Code</td>
+                </tr>
+                <tr>
+                    <td style="font-size: 16px; font-weight: bold; border-left: 1px solid #666699; border-bottom: 1px solid #666699; border-right: 1px solid #666699;" id="codeB" align="center">&nbsp;</td>
+                </tr>
+            </table>
+        </td>
+    </tr>
+</table>
+
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/themes/advanced/color_picker.htm	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,74 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>{$lang_theme_colorpicker_title}</title>
+	<script language="javascript" type="text/javascript" src="../../tiny_mce_popup.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/mctabs.js"></script>
+	<script language="javascript" type="text/javascript" src="jscripts/color_picker.js"></script>
+	<link href="css/colorpicker.css" rel="stylesheet" type="text/css" />
+	<base target="_self" />
+</head>
+<body onload="tinyMCEPopup.executeOnLoad('init();');" style="display: none">
+	<div class="tabs">
+		<ul>
+			<li id="picker_tab" class="current"><span><a href="javascript:mcTabs.displayTab('picker_tab','picker_panel');" onmousedown="return false;">{$lang_color_picker_tab}</a></span></li>
+			<li id="rgb_tab"><span><a href="#" onclick="generateWebColors();mcTabs.displayTab('rgb_tab','rgb_panel');" onmousedown="return false;">{$lang_web_colors_tab}</a></span></li>
+			<li id="named_tab"><span><a  href="#" onclick="generateNamedColors();javascript:mcTabs.displayTab('named_tab','named_panel');" onmousedown="return false;">{$lang_named_colors_tab}</a></span></li>
+		</ul>
+	</div>
+
+	<div class="panel_wrapper">
+		<div id="picker_panel" class="panel current">
+			<fieldset>
+				<legend>{$lang_color_picker}</legend>
+				<div id="picker">
+					<img id="colorpicker" src="images/colors.jpg" onclick="computeColor(event)" onmousedown="isMouseDown = true;return false;" onmouseup="isMouseDown = false;" onmousemove="if (isMouseDown && isMouseOver) computeColor(event); return false;" onmouseover="isMouseOver=true;" onmouseout="isMouseOver=false;" />
+
+					<div id="light">
+						<!-- Will be filled with divs -->
+					</div>
+
+					<br style="clear: both" />
+				</div>
+			</fieldset>
+		</div>
+
+		<div id="rgb_panel" class="panel">
+			<fieldset>
+				<legend>{$lang_web_colors}</legend>
+				<div id="webcolors">
+					<!-- Gets filled with web safe colors-->
+				</div>
+
+				<br style="clear: both" />
+			</fieldset>
+		</div>
+
+		<div id="named_panel" class="panel">
+			<fieldset>
+				<legend>{$lang_named_colors}</legend>
+				<div id="namedcolors">
+					<!-- Gets filled with named colors-->
+				</div>
+
+				<br style="clear: both" />
+
+				<div id="colornamecontainer">
+					{$lang_color_name} <span id="colorname"></span>
+				</div>
+			</fieldset>
+		</div>
+	</div>
+
+	<div class="mceActionPanel">
+		<div style="float: left">
+			<input type="button" id="insert" name="insert" value="{$lang_theme_colorpicker_apply}" onclick="insertAction();" />
+		</div>
+
+		<div id="preview"></div>
+
+		<div id="previewblock">
+			<label for="color">{$lang_color}</label> <input id="color" type="text" size="8" maxlength="8" class="text" />
+		</div>
+	</div>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/themes/advanced/css/colorpicker.css	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,53 @@
+/* Colorpicker dialog specific CSS */
+
+#preview {
+	float: right;
+	width: 50px;
+	height: 14px;
+	line-height: 1px;
+	border: 1px solid black;
+	margin-left: 5px;
+}
+
+#colorpicker {
+	float: left;
+	cursor: crosshair;
+}
+
+#light {
+	border: 1px solid gray;
+	margin-left: 5px;
+	float: left;
+	width: 15px;
+	cursor: crosshair;
+}
+
+#light div {
+	overflow: hidden;
+}
+
+#previewblock {
+	float: right;
+	padding-left: 10px;
+	height: 20px;
+}
+
+.panel_wrapper div.current {
+	height: 175px;
+}
+
+#namedcolors {
+	width: 150px;
+}
+
+#namedcolors a {
+	display: block;
+	float: left;
+	width: 10px; height: 10px;
+	margin: 1px 1px 0 0;
+	overflow: hidden;
+}
+
+#colornamecontainer {
+	margin-top: 5px;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/themes/advanced/css/editor_content.css	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,58 @@
+/* This file contains the CSS data for the editable area(iframe) of TinyMCE */
+/* You can extend this CSS by adding your own CSS file with the the content_css option */
+
+body, td, pre {
+	font-family: Verdana, Arial, Helvetica, sans-serif;
+	font-size: 10px;
+}
+
+body {
+	background-color: #FFFFFF;
+}
+
+.mceVisualAid {
+	border: 1px dashed #BBBBBB !important;
+}
+
+div.mceVisualAid {
+	background-image:url('../images/spacer.gif');
+	visibility: visible !important;
+}
+
+.mceItemAnchor {
+	width: 12px;
+	line-height: 6px;
+	overflow: hidden;
+	padding-left: 12px;
+	background-image: url('../images/anchor_symbol.gif');
+	background-position: bottom;
+	background-repeat: no-repeat;
+}
+
+/* Important is needed in Gecko browsers inorder to style links */
+/*
+a {
+	color: green !important;
+}
+*/
+
+/* Style selection range colors in Gecko browsers */
+/*
+::-moz-selection {
+	background-color: red;
+	color: green;
+}
+*/
+
+/* MSIE specific */
+
+* html body {
+	scrollbar-3dlight-color: #F0F0EE;
+	scrollbar-arrow-color: #676662;
+	scrollbar-base-color: #F0F0EE;
+	scrollbar-darkshadow-color: #DDDDDD;
+	scrollbar-face-color: #E0E0DD;
+	scrollbar-highlight-color: #F0F0EE;
+	scrollbar-shadow-color: #F0F0EE;
+	scrollbar-track-color: #F5F5F5;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/themes/advanced/css/editor_popup.css	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,331 @@
+/* This file contains the CSS data for all popups in TinyMCE */
+
+body {
+	background-color: #F0F0EE;
+	font-family: Verdana, Arial, Helvetica, sans-serif;
+	font-size: 11px;
+	scrollbar-3dlight-color: #F0F0EE;
+	scrollbar-arrow-color: #676662;
+	scrollbar-base-color: #F0F0EE;
+	scrollbar-darkshadow-color: #DDDDDD;
+	scrollbar-face-color: #E0E0DD;
+	scrollbar-highlight-color: #F0F0EE;
+	scrollbar-shadow-color: #F0F0EE;
+	scrollbar-track-color: #F5F5F5;
+	margin: 8px;
+}
+
+td {
+	font-family: Verdana, Arial, Helvetica, sans-serif;
+	font-size: 11px;
+}
+
+input {
+	background: #FFFFFF;
+	border: 1px solid #cccccc;
+}
+
+td, input, select, textarea {
+	font-family: Verdana, Arial, Helvetica, sans-serif;
+	font-size: 10px;
+}
+
+input, select, textarea {
+	border: 1px solid #808080;
+}
+
+.input_noborder {
+	border: 0;
+}
+
+#insert, .updateButton {
+   font-weight: bold;
+   width: 90px;
+   height: 21px;
+   border: 0;
+   background-image: url('../images/insert_button_bg.gif');
+   cursor: pointer;
+}
+
+#cancel {
+   font-weight: bold;
+   width: 90px;
+   height: 21px;
+   border: 0;
+   background-image: url('../images/cancel_button_bg.gif');
+   cursor: pointer;
+}
+
+/* Mozilla only style */
+html>body #insert, html>body #cancel {
+	padding-bottom: 2px;
+}
+
+.title {
+	font-size: 12px;
+	font-weight: bold;
+	color: #2B6FB6;
+}
+
+table.charmap {
+	border-style: solid;
+	border-width: 1px;
+	border-color: #AAAAAA;
+}
+
+td.charmap, td.charmapOver {
+	color: #000000;
+	border-color: #AAAAAA;
+	border-style: solid;
+	border-width: 1px;
+	text-align: center;
+	font-size: 12px;
+}
+
+td.charmapOver {
+	background-color: #CCCCCC;
+	cursor: default;
+}
+
+a.charmap {
+	color: #000000;
+	text-decoration: none
+}
+
+.wordWrapCode {
+	vertical-align: middle;
+	border: 1px none #000000;
+	background-color: transparent;
+}
+
+input.radio {
+	border: 1px none #000000;
+	background-color: transparent;
+	vertical-align: middle;
+}
+
+input.checkbox {
+	border: 1px none #000000;
+	background-color: transparent;
+	vertical-align: middle;
+}
+
+.mceButtonNormal, .mceButtonOver, .mceButtonDown, .mceSeparator, .mceButtonDisabled, .mceButtonSelected {
+	margin-left: 1px;
+}
+
+.mceButtonNormal {
+	border-top: 1px solid;
+	border-left: 1px solid;
+	border-bottom: 1px solid;
+	border-right: 1px solid;
+	border-color: #F0F0EE;
+	cursor: default;
+}
+
+.mceButtonOver {
+	border: 1px solid #0A246A;
+	cursor: default;
+	background-color: #B6BDD2;
+}
+
+.mceButtonDown {
+	cursor: default;
+	border: 1px solid #0A246A;
+	background-color: #8592B5;
+}
+
+.mceButtonDisabled {
+	filter:progid:DXImageTransform.Microsoft.Alpha(opacity=30);
+	-moz-opacity:0.3;
+	opacity: 0.3;
+	border-top: 1px solid;
+	border-left: 1px solid;
+	border-bottom: 1px solid;
+	border-right: 1px solid;
+	border-color: #F0F0EE;
+	cursor: default;
+}
+
+.mceActionPanel {
+	margin-top: 5px;
+}
+
+/* Tabs classes */
+
+.tabs {
+	float: left;
+	width: 100%;
+	line-height: normal;
+	background-image: url("../images/xp/tabs_bg.gif");
+}
+
+.tabs ul {
+	margin: 0;
+	padding: 0 0 0;
+	list-style: none;
+}
+
+.tabs li {
+	float: left;
+	background: url("../images/xp/tab_bg.gif") no-repeat left top;
+	margin: 0;
+	margin-left: 0;
+	margin-right: 2px;
+	padding: 0 0 0 10px;
+	line-height: 18px;
+}
+
+.tabs li.current {
+	background: url("../images/xp/tab_sel_bg.gif") no-repeat left top;
+	margin-right: 2px;
+}
+
+.tabs span {
+	float: left;
+	display: block;
+	background: url("../images/xp/tab_end.gif") no-repeat right top;
+	padding: 0px 10px 0 0;
+}
+
+.tabs .current span {
+	background: url("../images/xp/tab_sel_end.gif") no-repeat right top;
+}
+
+.tabs a {
+	text-decoration: none;
+	font-family: Verdana, Arial;
+	font-size: 10px;
+}
+
+.tabs a:link, .tabs a:visited, .tabs a:hover {
+	color: black;
+}
+
+.tabs a:hover {
+}
+
+.tabs .current {
+}
+
+.tabs .current a, .tabs .current a:link, .tabs .current a:visited {
+}
+
+.panel_wrapper div.panel {
+	display: none;
+}
+
+.panel_wrapper div.current {
+	display: block;
+	width: 100%;
+	height: 300px;
+	overflow: visible; /* Should be auto but that breaks Safari */
+}
+
+.panel_wrapper {
+	border: 1px solid #919B9C;
+	border-top: 0px;
+	padding: 10px;
+	padding-top: 5px;
+	clear: both;
+	background-color: white;
+}
+
+fieldset {
+	border: 1px solid #919B9C;
+	font-family: Verdana, Arial;
+	font-size: 10px;
+	padding: 0;
+	margin: 0;
+	padding: 4px;
+}
+
+legend {
+	color: #2B6FB6;
+	font-weight: bold;
+}
+
+.properties {
+	width: 100%;
+}
+
+.properties .column1 {
+}
+
+.properties .column2 {
+	text-align: left;
+}
+
+a:link, a:visited {
+	color: black;
+}
+
+a:hover {
+	color: #2B6FB6;
+}
+
+#plugintable thead {
+	font-weight: bold;
+	background-color: #DDDDDD;
+}
+
+#plugintable, #about #plugintable td {
+	border: 1px solid #919B9C;
+}
+
+#plugintable {
+	width: 99%;
+	margin-top: 10px;
+}
+
+#pluginscontainer {
+	height: 290px;
+	overflow: auto;
+}
+
+/* MSIE Specific styles */
+
+* html .panel_wrapper {
+	width: 100%;
+}
+
+.column {
+	float: left;
+}
+
+h1, h2, h3, h4 {
+	color: #2B6FB6;
+	margin: 0;
+	padding: 0;
+	padding-top: 5px;
+}
+
+h3 {
+	font-size: 14px;
+}
+
+#link .panel_wrapper, #link div.current {
+	height: 125px;
+}
+
+#image .panel_wrapper, #image div.current {
+	height: 190px;
+}
+
+label.msg { display: none; }
+label.invalid { color: #EE0000; display: inline; }
+input.invalid { border: 1px solid #EE0000; }
+
+/* Disables the advanced tab in the table plugin. */
+/*
+#table #advanced_tab {
+	display: none;
+}
+*/
+
+/* Disables the border input field and label in the table plugin. */
+/*
+#table #border, #table #borderlabel {
+	display: none;
+}
+*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/themes/advanced/css/editor_ui.css	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,97 @@
+/* This file contains the CSS data for the editor UI of TinyMCE instances */
+
+.mceToolbarTop a, .mceToolbarTop a:visited, .mceToolbarTop a:hover, .mceToolbarBottom a, .mceToolbarBottom a:visited, .mceToolbarBottom a:hover {border: 0; margin: 0; padding: 0; background: transparent;}
+.mceSeparatorLine {border: 0; padding: 0; margin-left: 4px; margin-right: 2px;}
+.mceSelectList {font-family: 'MS Sans Serif', sans-serif, Verdana, Arial; font-size: 7pt !important; font-weight: normal; margin-top: 3px; padding: 0; display: inline; vertical-align: top; background-color: #F0F0EE;}
+.mceLabel, .mceLabelDisabled {font-family: 'MS Sans Serif', sans-serif, Verdana, Arial; font-size: 9pt;}
+.mceLabel {color: #000000;}
+.mceLabelDisabled {cursor: text; color: #999999;}
+.mceEditor {background: #F0F0EE; border: 1px solid #cccccc; padding: 0; margin: 0;}
+.mceEditorArea { font-family: 'MS Sans Serif', sans-serif, Verdana, Arial; background: #FFFFFF; padding: 0; margin: 0; }
+.mceToolbarTop, .mceToolbarBottom {background: #F0F0EE; line-height: 1px; font-size: 1px;}
+.mceToolbarTop {border-bottom: 1px solid #cccccc; padding-bottom: 1px;}
+.mceToolbarBottom {border-top: 1px solid #cccccc;}
+.mceToolbarContainer {display: block; position: relative; left: 0; top: 0; width: 100%;}
+.mceStatusbarTop, .mceStatusbarBottom, .mceStatusbar {height: 20px;}
+.mceStatusbarTop .mceStatusbarPathText, .mceStatusbarBottom .mceStatusbarPathText, .mceStatusbar .mceStatusbarPathText {font-family: 'MS Sans Serif', sans-serif, Verdana, Arial; font-size: 9pt; padding: 2px; line-height: 16px; overflow: visible;}
+.mceStatusbarTop {border-bottom: 1px solid #cccccc;}
+.mceStatusbarBottom {border-top: 1px solid #cccccc;}
+.mceStatusbar {border-bottom: 1px solid #cccccc;}
+.mcePathItem, .mcePathItem:link, .mcePathItem:visited, .mcePathItem:hover {text-decoration: none; font-family: 'MS Sans Serif', sans-serif, Verdana, Arial; font-size: 9pt; color: #000000;}
+.mcePathItem:hover {text-decoration: underline;}
+.mceStatusbarPathText {float: left;}
+.mceStatusbarResize {float: right; background-image: url('../images/statusbar_resize.gif'); background-repeat: no-repeat; width: 11px; height: 20px; cursor: se-resize;}
+.mceResizeBox {width: 10px; height: 10px; display: none; border: 1px dotted gray; margin: 0; padding: 0;}
+.mceEditorIframe {border: 0;}
+
+/* Button CSS rules */
+
+a.mceButtonDisabled img, a.mceButtonNormal img, a.mceButtonSelected img {width: 20px; height: 20px; cursor: default; margin-top: 1px; margin-left: 1px;}
+a.mceButtonDisabled img {border: 0 !important;}
+a.mceButtonNormal img, a.mceButtonSelected img {border: 1px solid #F0F0EE !important;}
+a.mceButtonSelected img {border: 1px solid #6779AA !important; background-color: #D4D5D8;}
+a.mceButtonNormal img:hover, a.mceButtonSelected img:hover {border: 1px solid #0A246A !important; cursor: default; background-color: #B6BDD2;}
+a.mceButtonDisabled img {-moz-opacity:0.3; opacity: 0.3; border: 1px solid #F0F0EE !important; cursor: default;}
+a.mceTiledButton img {background-image: url('../images/buttons.gif'); background-repeat: no-repeat;}
+
+/* Menu button CSS rules */
+
+span.mceMenuButton img, span.mceMenuButtonSelected img {border: 1px solid #F0F0EE; margin-left: 1px;}
+span.mceMenuButtonSelected img {border: 1px solid #6779AA; background-color: #B6BDD2;}
+span.mceMenuButtonSelected img.mceMenuButton {border: 1px solid #F0F0EE; background-color: transparent;}
+span.mceMenuButton img.mceMenuButton, span.mceMenuButtonSelected img.mceMenuButton {border-left: 0; margin-left: 0;}
+span.mceMenuButton:hover img, span.mceMenuButtonSelected:hover img {border: 1px solid #0A246A; background-color: #B6BDD2;}
+span.mceMenuButton:hover img.mceMenuButton, span.mceMenuButtonSelected:hover img.mceMenuButton {border-left: 0;}
+span.mceMenuButtonFocus img {border: 1px solid gray; border-right: 0; margin-left: 1px; background-color: #F5F4F2;}
+span.mceMenuButtonFocus img.mceMenuButton {border: 1px solid gray; border-left: 1px solid #F5F4F2; margin-left: 0;}
+span.mceMenuHover img {border: 1px solid #0A246A; background-color: #B6BDD2;}
+span.mceMenuButtonSelected.mceMenuHover img.mceMenuButton {border: 1px solid #0A246A; background-color: #B6BDD2; border-left: 0;}
+
+/* Menu */
+
+.mceMenu {position: absolute; left: 0; top: 0; display: none; z-index: 1000; background-color: white; border: 1px solid gray; font-weight: normal;}
+.mceMenu a, .mceMenuTitle, .mceMenuDisabled {display: block; width: 100%; text-decoration: none; background-color: white; font-family: Tahoma, Verdana, Arial, Helvetica; font-size: 11px; line-height: 20px; color: black;}
+.mceMenu a:hover {background-color: #B6BDD2; color: black; text-decoration: none !important;}
+.mceMenu span {padding-left: 10px; padding-right: 10px; display: block; line-height: 20px;}
+.mceMenuSeparator {border-bottom: 1px solid gray; background-color: gray; height: 1px;}
+.mceMenuTitle span {padding-left: 5px;}
+.mceMenuTitle {background-color: #DDDDDD; font-weight: bold;}
+.mceMenuDisabled {color: gray;}
+span.mceMenuSelectedItem {background-image: url('../images/menu_check.gif'); background-repeat: no-repeat; background-position: 5px 8px; padding-left: 20px;}
+span.mceMenuCheckItem {padding-left: 20px;}
+span.mceMenuLine {display: block; position: absolute; left: 0; top: -1px; background-color: #F5F4F2; width: 30px; height: 1px; overflow: hidden; padding-left: 0; padding-right: 0;}
+.mceColors table, .mceColors td {margin: 0; padding: 2px;}
+a.mceMoreColors {width: auto; padding: 0; margin: 0 3px 3px 3px; text-align: center; border: 1px solid white; text-decoration: none !important;}
+.mceColorPreview {position: absolute; overflow:hidden; left: 0; top: 0; margin-left: 3px; margin-top: 15px; width: 16px; height: 4px; background-color: red;}
+a.mceMoreColors:hover {border: 1px solid #0A246A;}
+.mceColors td a {width: 9px; height: 9px; overflow: hidden; border: 1px solid #808080;}
+
+/* MSIE 6 specific rules */
+
+* html a.mceButtonNormal img, * html a.mceButtonSelected img, * html a.mceButtonDisabled img {border: 0 !important; margin-top: 2px; margin-bottom: 1px;}
+* html a.mceButtonDisabled img {filter:progid:DXImageTransform.Microsoft.Alpha(opacity=30); border: 0 !important;}
+* html a.mceButtonDisabled {border: 1px solid #F0F0EE !important;}
+* html a.mceButtonNormal, * html a.mceButtonSelected {border: 1px solid #F0F0EE !important; cursor: default;}
+* html a.mceButtonSelected {border: 1px solid #6779AA !important; background-color: #D4D5D8;}
+* html a.mceButtonNormal:hover, * html a.mceButtonSelected:hover {border: 1px solid #0A246A !important; background-color: #B6BDD2; cursor: default;}
+* html .mceSelectList {margin-top: 2px;}
+* html span.mceMenuButton, * html span.mceMenuButtonFocus {position: relative; left: 0; top: 0;}
+* html span.mceMenuButton img, * html span.mceMenuButtonSelected img, * html span.mceMenuButtonFocus img {position: relative; top: 1px;}
+* html a.mceMoreColors {width: auto;}
+* html .mceColors td a {width: 10px; height: 10px;}
+* html .mceColorPreview {margin-left: 2px; margin-top: 14px;}
+
+/* MSIE 7 specific rules */
+
+*:first-child+html a.mceButtonNormal img, *:first-child+html a.mceButtonSelected img, *:first-child+html a.mceButtonDisabled img {border: 0 !important; margin-top: 2px; margin-bottom: 1px;}
+*:first-child+html a.mceButtonDisabled img {filter:progid:DXImageTransform.Microsoft.Alpha(opacity=30); border: 0 !important;}
+*:first-child+html a.mceButtonDisabled {border: 1px solid #F0F0EE !important;}
+*:first-child+html a.mceButtonNormal, *:first-child+html a.mceButtonSelected {border: 1px solid #F0F0EE !important; cursor: default;}
+*:first-child+html a.mceButtonSelected {border: 1px solid #6779AA !important; background-color: #D4D5D8;}
+*:first-child+html a.mceButtonNormal:hover, *:first-child+html a.mceButtonSelected:hover {border: 1px solid #0A246A !important; background-color: #B6BDD2; cursor: default;}
+*:first-child+html .mceSelectList {margin-top: 2px;}
+*:first-child+html span.mceMenuButton, *:first-child+html span.mceMenuButtonFocus {position: relative; left: 0; top: 0;}
+*:first-child+html span.mceMenuButton img, *:first-child+html span.mceMenuButtonSelected img, *:first-child+html span.mceMenuButtonFocus img {position: relative; top: 1px;}
+*:first-child+html a.mceMoreColors {width: 137px;}
+*:first-child+html .mceColors td a {width: 10px; height: 10px;}
+*:first-child+html .mceColorPreview {margin: 0; padding-left: 4px; margin-top: 14px; width: 14px;}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/themes/advanced/docs/en/about.htm	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,31 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<HEAD>
+<TITLE>About TinyMCE</TITLE>
+<link href="style.css" rel="stylesheet" type="text/css">
+</HEAD>
+
+<BODY>
+
+<table width="100%" border="0" cellpadding="1" cellspacing="3" class="pageheader">
+  <tr> 
+    <td><span class="title">About TinyMCE</span></td>
+    <td align="right"><a href="index.htm"><acronym title="Table of contents">TOC</acronym></a></td>
+  </tr>
+</table>
+<hr noshade>
+<br>
+TinyMCE is a small WYSIWYG editor control for web browsers such as MSIE or Mozilla 
+that enables you to edit HTML contents in a more user friendly way. It has common 
+features that are found in most word processors and should not be difficult to 
+use.<br>
+<br>
+<hr noshade>
+<table width="100%" border="0" cellpadding="1" cellspacing="3" class="pagefooter">
+  <tr> 
+    <td>Go to: <a href="index.htm">Table of contents</a></td>
+    <td align="right"><a href="#">Top</a></td>
+  </tr>
+</table>
+<br>
+</BODY>
+</HTML>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/themes/advanced/docs/en/common_buttons.htm	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,162 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<HEAD>
+<TITLE>Common buttons</TITLE>
+<link href="style.css" rel="stylesheet" type="text/css">
+</HEAD>
+
+<BODY>
+
+<table width="100%" border="0" cellpadding="1" cellspacing="3" class="pageheader">
+  <tr> 
+    <td><span class="title">Common buttons</span></td>
+    <td align="right"><a href="index.htm"><acronym title="Table of contents">TOC</acronym></a></td>
+  </tr>
+</table>
+<hr noshade>
+<br>
+Below is a short description about each button.
+<br>
+<br>
+<table border="1" cellpadding="3" cellspacing="0">
+  <tr>
+    <td><img src="../../images/bold.gif" width="20" height="20" alt="Bold text icon" /></td>
+    <td>Bold text style (Ctrl+B).</td>
+  </tr>
+  <tr>
+    <td><img src="../../images/italic.gif" width="20" height="20" alt="Italic text icon" /></td>
+    <td>Italic text style (Ctrl+I).</td>
+  </tr>
+  <tr>
+    <td><img src="../../images/underline.gif" width="20" height="20" alt="Underline text icon." /></td>
+    <td>Underline text style (Ctrl+U).</td>
+  </tr>
+  <tr>
+    <td><img src="../../images/strikethrough.gif" width="20" height="20" alt="Strikethrough text icon." /></td>
+    <td>Strikethrough text style.</td>
+  </tr>
+  <tr>
+    <td><img src="../../images/justifyleft.gif" width="20" height="20" alt="Align left icon." /></td>
+    <td>Align left.</td>
+  </tr>
+  <tr>
+    <td><img src="../../images/justifycenter.gif" width="20" height="20" alt="Align center icon." /></td>
+    <td>Align center.</td>
+  </tr>
+  <tr>
+    <td><img src="../../images/justifyright.gif" width="20" height="20" alt="Align right icon." /></td>
+    <td>Align right.</td>
+  </tr>
+  <tr>
+    <td><img src="../../images/justifyfull.gif" width="20" height="20" alt="Align full icon." /></td>
+    <td>Align full.</td>
+  </tr>
+  <tr>
+    <td><img src="../../images/bullist.gif" width="20" height="20" alt="Unordered list/bullet list icon." /></td>
+    <td>Unordered list/bullet list.</td>
+  </tr>
+  <tr>
+    <td><img src="../../images/numlist.gif" width="20" height="20" alt="Ordered list/numbered list icon." /></td>
+    <td>Ordered list/numbered list</td>
+  </tr>
+  <tr>
+    <td><img src="../../images/outdent.gif" width="20" height="20" alt="Outdent/decrease indentation icon." /></td>
+    <td>Outdent/decrease indentation.</td>
+  </tr>
+  <tr>
+    <td><img src="../../images/indent.gif" width="20" height="20" alt="Indent/increase indentation icon." /></td>
+    <td>Indent/increase indentation.</td>
+  </tr>
+  <tr>
+    <td><img src="../../images/undo.gif" width="20" height="20" alt="Undo the last operation." /></td>
+    <td>Undo the last operation (Ctrl+Z).</td>
+  </tr>
+  <tr>
+    <td><img src="../../images/redo.gif" width="20" height="20" alt="Redo the last operation icon." /></td>
+    <td>Redo the last operation (Ctrl+Y).</td>
+  </tr>
+  <tr>
+    <td><img src="../../images/link.gif" width="20" height="20" alt="Insert a new link icon." /></td>
+    <td>Insert a new link, read more about this function in the <a href="insert_link_button.htm">Insert 
+      link section</a>.</td>
+  </tr>
+  <tr>
+    <td><img src="../../images/unlink.gif" width="20" height="20" alt="Unlinks the current selection icon." /></td>
+    <td>Unlinks the current selection/removes all selected links.</td>
+  </tr>
+  <tr>
+    <td><img src="../../images/anchor.gif" width="20" height="20" alt="Insert a new anchor icon." /></td>
+    <td>Insert a new anchor, read more about this function in the <a href="insert_anchor_button.htm">Insert anchor section.</a></td>
+  </tr>
+  <tr>
+    <td><img src="../../images/image.gif" width="20" height="20" alt="Insert a new image icon." /></td>
+    <td>Insert a new image, read more about this function in the <a href="insert_image_button.htm">Insert 
+      image section</a>.</td>
+  </tr>
+  <tr>
+    <td><img src="../../images/cleanup.gif" width="20" height="20" alt="Cleanup code icon." /></td>
+    <td>Cleanup code/Removes unwanted formating. This function is useful when 
+      you copy contents from for example a office product.</td>
+  </tr>
+  <tr>
+    <td><img src="../../images/help.gif" width="20" height="20" alt="Show help icon." /></td>
+    <td>Shows this help window.</td>
+  </tr>
+  <tr>
+    <td><img src="../../images/code.gif" width="20" height="20" alt="Source code editor icon." /></td>
+    <td>Opens HTML source code editor. </td>
+  </tr>
+  <tr>
+    <td><img src="../../../../plugins/table/images/table.gif" width="20" height="20" alt="Insert table icon." /></td>
+    <td>Inserts a new table at the current location. </td>
+  </tr>
+  <tr>
+    <td><img src="../../../../plugins/table/images/table_insert_row_before.gif" width="20" height="20" alt="Adds a row above icon." /></td>
+    <td>Adds a row above the current one. </td>
+  </tr>
+  <tr>
+    <td><img src="../../../../plugins/table/images/table_insert_row_after.gif" width="20" height="20" alt="Adds a row under icon." /></td>
+    <td>Adds a row under the current one. </td>
+  </tr>
+  <tr>
+    <td><img src="../../../../plugins/table/images/table_delete_row.gif" width="20" height="20" alt="Remove row icon." /></td>
+    <td>Removes the row. </td>
+  </tr>
+  <tr>
+    <td><img src="../../../../plugins/table/images/table_insert_col_before.gif" width="20" height="20" alt="Add column before icon." /></td>
+    <td>Adds a column before the current one.</td>
+  </tr>
+  <tr>
+    <td><img src="../../../../plugins/table/images/table_insert_col_after.gif" width="20" height="20" alt="Add column after icon." /></td>
+    <td>Adds a column after the current one.</td>
+  </tr>
+  <tr>
+    <td><img src="../../../../plugins/table/images/table_delete_col.gif" width="20" height="20" alt="Remove column icon." /></td>
+    <td>Removes the current column.</td>
+  </tr>
+  <tr>
+    <td><img src="../../images/hr.gif" width="20" height="20" alt="Insert horizontal ruler icon." /></td>
+    <td>Inserts a new horizontal ruler </td>
+  </tr>
+  <tr>
+    <td><img src="../../images/removeformat.gif" width="20" height="20" alt="Remove formatting icon." /></td>
+    <td>Removes formatting from the selection. </td>
+  </tr>
+  <tr>
+    <td><img src="../../images/sub.gif" width="20" height="20" alt="Subscript icon." /></td>
+    <td>Makes the selection to be subscript. </td>
+  </tr>
+  <tr>
+    <td><img src="../../images/sup.gif" width="20" height="20" alt="Superscript icon." /></td>
+    <td>Makes the selection to be superscripted. </td>
+  </tr>
+</table>
+<br>
+<hr noshade="noshade" />
+<table width="100%" border="0" cellpadding="1" cellspacing="3" class="pagefooter">
+  <tr> 
+    <td>Go to: <a href="index.htm">Table of contents</a></td>
+    <td align="right"><a href="#">Top</a></td>
+  </tr>
+</table>
+</BODY>
+</HTML>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/themes/advanced/docs/en/create_accessible_content.htm	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,45 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<HEAD>
+<TITLE>Insert table button</TITLE>
+<link href="style.css" rel="stylesheet" type="text/css">
+</HEAD>
+
+<BODY>
+
+<table width="100%" border="0" cellpadding="1" cellspacing="3" class="pageheader">
+  <tr> 
+    <td><span class="title">Create accessible content</span></td>
+    <td align="right"><a href="index.htm"><acronym title="Table of contents">TOC</acronym></a></td>
+  </tr>
+</table>
+<hr noshade>
+<p>TinyMCE can create HTML content that will be accessible to all users, including those with disabilities using assistive technologies, as well as those using text-based browsers, or those browsing the Web with images turned off. </p>
+
+<p><strong>Things you can do to make your content accessible:</strong></p>
+<ol>
+<li><strong>Include an Image Description:</strong> Blind users, or others who are unable to view images, will rely on the Image Description (or Alt text) to take the place of the image. If an image contains no meaning, such as a decoration or a spacer image, leave the Image Description empty. TinyMCE will then insert an empty Alt text attribute that will force assistive technologies to ignore the image. <br /><br /></li>
+
+<li> <strong>Add Scope to data table header cells:</strong> In the table cell editor dialog window, choose a Scope when creating Header cells so the column or row label in that cell becomes explicitely associated with its data cells. Table cell headers will then be announced with each data cell, making it easier for blind users using a screen reader to understand what the content of each cell represents. <br /><br /></li>
+
+<li><strong> Structure content with properly nested headings:</strong> In the format selection menu choose Heading 1 to Heading 6 to represent headings in your content,  rather than using other font formating options. Blind users using a screen reader can then extract the headings from the page to generate a summary of the content it contains, and use those headings to navigate quickly to subsections within the page.<br /><br /></li>
+
+<li><strong> Include alternate content:</strong> Create an alternate page for non-HTML content such as Flash, Java applets, or  embedded movies. This might be a static image, with a description of the image, and a description of the content that would have appeared in its place. An alternate HTML page could also be created, and a link to it included next to the non-HTML object. This will ensure that the content will be accessible to users of assistive technologies that can not view or play the content, and ensure the content will be available to those who do not have the appropriate plugin or helper application installed.<br /><br /></li>
+
+<li><strong> Check accessbility: </strong> When the AChecker plugin is installed with TinyMCE, click on the Check Accessibility button to generate a report of potential accessibility problems.<br /><br /></li>
+
+</ol>
+
+<p>See the <a href="http://checker.atrc.utoronto.ca" target="_new">AChecker Web Site</a> for further details about creating content that will be accessible to all users.<br />
+</p>
+
+<hr noshade>
+<table width="100%" border="0" cellpadding="1" cellspacing="3" class="pagefooter">
+  <tr> 
+    <td>Go to: <a href="index.htm">Table of contents</a></td>
+    <td align="right"><a href="#">Top</a></td>
+  </tr>
+</table>
+
+<br>
+</BODY>
+</HTML>
Binary file includes/clientside/tinymce/themes/advanced/docs/en/images/insert_anchor_window.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/docs/en/images/insert_image_window.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/docs/en/images/insert_link_window.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/docs/en/images/insert_table_window.gif has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/themes/advanced/docs/en/index.htm	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,27 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<HEAD>
+<TITLE>Help Index</TITLE>
+<link href="style.css" rel="stylesheet" type="text/css">
+</HEAD>
+<BODY onload="window.focus();">
+<table width="100%" border="0" cellpadding="1" cellspacing="3" class="pageheader">
+  <tr> 
+    <td><span class="title">Table of contents</span></td>
+    <td align="right">&nbsp;</td>
+  </tr>
+</table>
+<hr noshade>
+<br>
+Click the links below to go to the different help sections. 
+<ul class="toc_ul">
+  <li class="toc_li"><a href="about.htm">About TinyMCE</a></li>
+  <li class="toc_li"><a href="common_buttons.htm">Common buttons</a></li>
+  <li class="toc_li"><a href="insert_image_button.htm">Insert image button</a></li>
+  <li class="toc_li"><a href="insert_link_button.htm">Insert link button</a></li>
+  <li class="toc_li"><a href="insert_anchor_button.htm">Insert anchor button</a></li>
+  <li class="toc_li"><a href="insert_table_button.htm">Insert table button</a></li>
+ <li class="toc_li"><a href="create_accessible_content.htm">Create accessible content</a></li>
+</ul>
+<hr noshade>
+</BODY>
+</HTML>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/themes/advanced/docs/en/insert_anchor_button.htm	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,32 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<HEAD>
+<TITLE>Insert anchor button</TITLE>
+<link href="style.css" rel="stylesheet" type="text/css">
+</HEAD>
+
+<BODY>
+
+<table width="100%" border="0" cellpadding="1" cellspacing="3" class="pageheader">
+  <tr> 
+    <td><span class="title">Insert anchor button</span></td>
+    <td align="right"><a href="index.htm"><acronym title="Table of contents">TOC</acronym></a></td>
+  </tr>
+</table>
+<hr noshade>
+<br>
+This button opens a new window with the insert/edit anchor function.<br>
+<br>
+<img src="images/insert_anchor_window.gif" width="330" height="139" alt="Anchor dialog/window" /><br>
+<br>
+There are one field in this window, this is where you enter the name of you anchor point. Remember the anchor name needs to be unique. <br>
+<br>
+<hr noshade>
+<table width="100%" border="0" cellpadding="1" cellspacing="3" class="pagefooter">
+  <tr> 
+    <td>Go to: <a href="index.htm">Table of contents</a></td>
+    <td align="right"><a href="#">Top</a></td>
+  </tr>
+</table>
+<br>
+</BODY>
+</HTML>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/themes/advanced/docs/en/insert_image_button.htm	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,65 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<HEAD>
+<TITLE>Insert image button</TITLE>
+<link href="style.css" rel="stylesheet" type="text/css">
+</HEAD>
+
+<BODY>
+
+<table width="100%" border="0" cellpadding="1" cellspacing="3" class="pageheader">
+  <tr> 
+    <td><span class="title">Insert image button</span></td>
+    <td align="right"><a href="index.htm"><acronym title="Table of contents">TOC</acronym></a></td>
+  </tr>
+</table>
+<hr noshade>
+<br>
+The insert image button opens the window shown below.<br>
+<br>
+<img src="images/insert_image_window.gif" alt="Insert image dialog/window" /><br>
+<br>
+You simply enter a URL to the image you want to link to and enter a image description, 
+this is then displayed as an alternative text descripton of the image on the page.<br>
+<br>
+<strong>Field descriptions:</strong><br>
+<table border="1" cellspacing="0">
+  <tr>
+    <td width="150"><strong>Image URL </strong></td>
+    <td>URL/path to the image.</td>
+  </tr>
+  <tr>
+    <td width="150"><strong>Image description </strong></td>
+    <td>Alternative description of image contents.</td>
+  </tr>
+  <tr>
+    <td><strong>Dimentions</strong></td>
+    <td>Image width/height. </td>
+  </tr>
+  <tr>
+    <td><strong>Alignment</strong></td>
+    <td>Image alignment, useful when wrapping text around images.</td>
+  </tr>
+  <tr>
+    <td><strong>Border</strong></td>
+    <td>Border thickness. </td>
+  </tr>
+  <tr>
+    <td><strong>VSpace</strong></td>
+    <td>Vertical space, useful when wrapping text around images.</td>
+  </tr>
+  <tr>
+    <td><strong>HSpace</strong></td>
+    <td>Horizontal space, useful when wrapping text around images.</td>
+  </tr>
+</table>
+<br>
+<hr noshade>
+<table width="100%" border="0" cellpadding="1" cellspacing="3" class="pagefooter">
+  <tr> 
+    <td>Go to: <a href="index.htm">Table of contents</a></td>
+    <td align="right"><a href="#">Top</a></td>
+  </tr>
+</table>
+<br>
+</BODY>
+</HTML>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/themes/advanced/docs/en/insert_link_button.htm	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,33 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<HEAD>
+<TITLE>Insert link button</TITLE>
+<link href="style.css" rel="stylesheet" type="text/css">
+</HEAD>
+
+<BODY>
+
+<table width="100%" border="0" cellpadding="1" cellspacing="3" class="pageheader">
+  <tr> 
+    <td><span class="title">Insert link button</span></td>
+    <td align="right"><a href="index.htm"><acronym title="Table of contents">TOC</acronym></a></td>
+  </tr>
+</table>
+<hr noshade>
+<br>
+This button opens a new window with the insert/edit link function.<br>
+<br>
+<img src="images/insert_link_window.gif" width="330" height="159" alt="Insert link dialog/window" /><br>
+<br>
+There are two fields in this window the first one &quot;Link URL&quot; is the 
+URL of the link. The target enables you to select how the link is to be opened.<br>
+<br>
+<hr noshade>
+<table width="100%" border="0" cellpadding="1" cellspacing="3" class="pagefooter">
+  <tr> 
+    <td>Go to: <a href="index.htm">Table of contents</a></td>
+    <td align="right"><a href="#">Top</a></td>
+  </tr>
+</table>
+<br>
+</BODY>
+</HTML>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/themes/advanced/docs/en/insert_table_button.htm	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,71 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<HEAD>
+<TITLE>Insert table button</TITLE>
+<link href="style.css" rel="stylesheet" type="text/css">
+</HEAD>
+
+<BODY>
+
+<table width="100%" border="0" cellpadding="1" cellspacing="3" class="pageheader">
+  <tr> 
+    <td><span class="title">Insert table button</span></td>
+    <td align="right"><a href="index.htm"><acronym title="Table of contents">TOC</acronym></a></td>
+  </tr>
+</table>
+<hr noshade>
+<br>
+The insert table button opens the window shown below. This action enables you to create tables. <br>
+<br>
+<img src="images/insert_table_window.gif" width="340" height="229" alt="Image of table window" /><br>
+<br>
+<strong>Field descriptions:</strong><br>
+<table border="1" cellspacing="0">
+  <tr>
+    <td width="150"><strong>Columns</strong></td>
+    <td>Number of columns in the  table. </td>
+  </tr>
+  <tr>
+    <td width="150"><strong>Rows</strong></td>
+    <td>Number of rows in the new table.</td>
+  </tr>
+  <tr>
+    <td><strong>Cellpadding</strong></td>
+    <td>Cellpadding of the table . </td>
+  </tr>
+  <tr>
+    <td><strong>Cellspacing</strong></td>
+    <td>Cellspacing of the table .</td>
+  </tr>
+  <tr>
+    <td><strong>Alignment</strong></td>
+    <td>Table alignment . </td>
+  </tr>
+  <tr>
+    <td><strong>Border</strong></td>
+    <td>Border thinkness of table.</td>
+  </tr>
+  <tr>
+    <td><strong>Width</strong></td>
+    <td>Width in pixels of table .</td>
+  </tr>
+  <tr>
+    <td><strong>Height</strong></td>
+    <td>Height in pixels of table.</td>
+  </tr>
+  <tr>
+    <td><strong>Class</strong></td>
+    <td>Style or CSS class of table.</td>
+  </tr>
+</table>
+<br>
+<br>
+<hr noshade>
+<table width="100%" border="0" cellpadding="1" cellspacing="3" class="pagefooter">
+  <tr> 
+    <td>Go to: <a href="index.htm">Table of contents</a></td>
+    <td align="right"><a href="#">Top</a></td>
+  </tr>
+</table>
+<br>
+</BODY>
+</HTML>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/themes/advanced/docs/en/style.css	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,28 @@
+body { background-color: #FFFFFF; }
+body, td, .content { font-family: Verdana, Arial, helvetica, sans-serif; font-size: 12px; }
+.title { font-family: Verdana, Arial, helvetica, sans-serif; font-size: 16px; font-weight: bold; }
+.subtitle { font-size: 12px; font-weight: bold; }
+
+.toc_ul, .toc_li { margin-left: 8px; line-height: 16px; }
+.step_ol, .step_li { margin-left: 11px; line-height: 16px; }
+img { border: #000000 solid 1px; }
+
+a:visited { color: #666666; text-decoration: underline; }
+a:active { color: #666666; text-decoration: underline; }
+a:hover { color: #666666; text-decoration: underline; }
+a { color: #666666; text-decoration: underline; }
+
+.pageheader { border: #E0E0E0 solid 1px; }
+.pagefooter { border: #E0E0E0 solid 1px; }
+.sample { background-color: #FFFFFF; border: #000000 solid 1px; }
+.samplecontent { font-size: 10px; }
+
+.code { background-color: #FFFFFF; border: #000000 solid 1px; }
+.codecontent { font-size: 10px; }
+.codecontent a:visited { color: #666666; text-decoration: none; font-weight: bold }
+.codecontent a:active { color: #666666; text-decoration: none; font-weight: bold  }
+.codecontent a:hover { color: #666666; text-decoration: none; font-weight: bold  }
+.codecontent a { color: #666666; text-decoration: none; font-weight: bold  }
+
+hr { height: 1px; }
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/themes/advanced/editor_template.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+tinyMCE.importThemeLanguagePack('advanced');var TinyMCE_AdvancedTheme={_defColors:"000000,993300,333300,003300,003366,000080,333399,333333,800000,FF6600,808000,008000,008080,0000FF,666699,808080,FF0000,FF9900,99CC00,339966,33CCCC,3366FF,800080,999999,FF00FF,FFCC00,FFFF00,00FF00,00FFFF,00CCFF,993366,C0C0C0,FF99CC,FFCC99,FFFF99,CCFFCC,CCFFFF,99CCFF,CC99FF,FFFFFF",_autoImportCSSClasses:true,_resizer:{},_buttons:[['bold','{$lang_bold_img}','lang_bold_desc','Bold'],['italic','{$lang_italic_img}','lang_italic_desc','Italic'],['underline','{$lang_underline_img}','lang_underline_desc','Underline'],['strikethrough','strikethrough.gif','lang_striketrough_desc','Strikethrough'],['justifyleft','justifyleft.gif','lang_justifyleft_desc','JustifyLeft'],['justifycenter','justifycenter.gif','lang_justifycenter_desc','JustifyCenter'],['justifyright','justifyright.gif','lang_justifyright_desc','JustifyRight'],['justifyfull','justifyfull.gif','lang_justifyfull_desc','JustifyFull'],['bullist','bullist.gif','lang_bullist_desc','InsertUnorderedList'],['numlist','numlist.gif','lang_numlist_desc','InsertOrderedList'],['outdent','outdent.gif','lang_outdent_desc','Outdent'],['indent','indent.gif','lang_indent_desc','Indent'],['cut','cut.gif','lang_cut_desc','Cut'],['copy','copy.gif','lang_copy_desc','Copy'],['paste','paste.gif','lang_paste_desc','Paste'],['undo','undo.gif','lang_undo_desc','Undo'],['redo','redo.gif','lang_redo_desc','Redo'],['link','link.gif','lang_link_desc','mceLink',true],['unlink','unlink.gif','lang_unlink_desc','unlink'],['image','image.gif','lang_image_desc','mceImage',true],['cleanup','cleanup.gif','lang_cleanup_desc','mceCleanup'],['help','help.gif','lang_help_desc','mceHelp'],['code','code.gif','lang_theme_code_desc','mceCodeEditor'],['hr','hr.gif','lang_theme_hr_desc','inserthorizontalrule'],['removeformat','removeformat.gif','lang_theme_removeformat_desc','removeformat'],['sub','sub.gif','lang_theme_sub_desc','subscript'],['sup','sup.gif','lang_theme_sup_desc','superscript'],['forecolor','forecolor.gif','lang_theme_forecolor_desc','forecolor',true],['forecolorpicker','forecolor.gif','lang_theme_forecolor_desc','forecolorpicker',true],['backcolor','backcolor.gif','lang_theme_backcolor_desc','HiliteColor',true],['backcolorpicker','backcolor.gif','lang_theme_backcolor_desc','backcolorpicker',true],['charmap','charmap.gif','lang_theme_charmap_desc','mceCharMap'],['visualaid','visualaid.gif','lang_theme_visualaid_desc','mceToggleVisualAid'],['anchor','anchor.gif','lang_theme_anchor_desc','mceInsertAnchor'],['newdocument','newdocument.gif','lang_newdocument_desc','mceNewDocument']],_buttonMap:'anchor,backcolor,bold,bullist,charmap,cleanup,code,copy,cut,forecolor,help,hr,image,indent,italic,justifycenter,justifyfull,justifyleft,justifyright,link,newdocument,numlist,outdent,paste,redo,removeformat,strikethrough,sub,sup,underline,undo,unlink,visualaid,advhr,ltr,rtl,emotions,flash,fullpage,fullscreen,iespell,insertdate,inserttime,pastetext,pasteword,selectall,preview,print,save,replace,search,table,cell_props,delete_col,delete_row,col_after,col_before,row_after,row_before,merge_cells,row_props,split_cells,delete_table',getControlHTML:function(button_name){var i,x,but;for(i=0;i<TinyMCE_AdvancedTheme._buttons.length;i++){but=TinyMCE_AdvancedTheme._buttons[i];if(but[0]==button_name&&(button_name=="forecolor"||button_name=="backcolor"))return tinyMCE.getMenuButtonHTML(but[0],but[2],'{$themeurl}/images/'+but[1],but[3]+"Menu",but[3],(but.length>4?but[4]:false),(but.length>5?but[5]:null));if(but[0]==button_name)return tinyMCE.getButtonHTML(but[0],but[2],'{$themeurl}/images/'+but[1],but[3],(but.length>4?but[4]:false),(but.length>5?but[5]:null))}switch(button_name){case"formatselect":var html='<select id="{$editor_id}_formatSelect" name="{$editor_id}_formatSelect" onfocus="tinyMCE.addSelectAccessibility(event, this, window);" onchange="tinyMCE.execInstanceCommand(\'{$editor_id}\',\'FormatBlock\',false,this.options[this.selectedIndex].value);" class="mceSelectList">';var formats=tinyMCE.getParam("theme_advanced_blockformats","p,address,pre,h1,h2,h3,h4,h5,h6",true).split(',');var lookup=[['p','{$lang_theme_paragraph}'],['address','{$lang_theme_address}'],['pre','{$lang_theme_pre}'],['h1','{$lang_theme_h1}'],['h2','{$lang_theme_h2}'],['h3','{$lang_theme_h3}'],['h4','{$lang_theme_h4}'],['h5','{$lang_theme_h5}'],['h6','{$lang_theme_h6}'],['div','{$lang_theme_div}'],['blockquote','{$lang_theme_blockquote}'],['code','{$lang_theme_code}'],['dt','{$lang_theme_dt}'],['dd','{$lang_theme_dd}'],['samp','{$lang_theme_samp}']];html+='<option value="">{$lang_theme_block}</option>';for(var i=0;i<formats.length;i++){for(var x=0;x<lookup.length;x++){if(formats[i]==lookup[x][0])html+='<option value="&lt;'+lookup[x][0]+'&gt;">'+lookup[x][1]+'</option>'}}html+='</select>';return html;case"styleselect":return'<select id="{$editor_id}_styleSelect" onmousedown="tinyMCE.themes.advanced._setupCSSClasses(\'{$editor_id}\');" name="{$editor_id}_styleSelect" onfocus="tinyMCE.addSelectAccessibility(event,this,window);" onchange="tinyMCE.execInstanceCommand(\'{$editor_id}\',\'mceSetCSSClass\',false,this.options[this.selectedIndex].value);" class="mceSelectList">{$style_select_options}</select>';case"fontselect":var fontHTML='<select id="{$editor_id}_fontNameSelect" name="{$editor_id}_fontNameSelect" onfocus="tinyMCE.addSelectAccessibility(event, this, window);" onchange="tinyMCE.execInstanceCommand(\'{$editor_id}\',\'FontName\',false,this.options[this.selectedIndex].value);" class="mceSelectList"><option value="">{$lang_theme_fontdefault}</option>';var iFonts='Arial=arial,helvetica,sans-serif;Courier New=courier new,courier,monospace;Georgia=georgia,times new roman,times,serif;Tahoma=tahoma,arial,helvetica,sans-serif;Times New Roman=times new roman,times,serif;Verdana=verdana,arial,helvetica,sans-serif;Impact=impact;WingDings=wingdings';var nFonts='Andale Mono=andale mono,times;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;Comic Sans MS=comic sans ms,sand;Courier New=courier new,courier;Georgia=georgia,palatino;Helvetica=helvetica;Impact=impact,chicago;Symbol=symbol;Tahoma=tahoma,arial,helvetica,sans-serif;Terminal=terminal,monaco;Times New Roman=times new roman,times;Trebuchet MS=trebuchet ms,geneva;Verdana=verdana,geneva;Webdings=webdings;Wingdings=wingdings,zapf dingbats';var fonts=tinyMCE.getParam("theme_advanced_fonts",nFonts).split(';');for(i=0;i<fonts.length;i++){if(fonts[i]!=''){var parts=fonts[i].split('=');fontHTML+='<option value="'+parts[1]+'">'+parts[0]+'</option>'}}fontHTML+='</select>';return fontHTML;case"fontsizeselect":return'<select id="{$editor_id}_fontSizeSelect" name="{$editor_id}_fontSizeSelect" onfocus="tinyMCE.addSelectAccessibility(event, this, window);" onchange="tinyMCE.execInstanceCommand(\'{$editor_id}\',\'FontSize\',false,this.options[this.selectedIndex].value);" class="mceSelectList">'+'<option value="0">{$lang_theme_font_size}</option>'+'<option value="1">1 (8 pt)</option>'+'<option value="2">2 (10 pt)</option>'+'<option value="3">3 (12 pt)</option>'+'<option value="4">4 (14 pt)</option>'+'<option value="5">5 (18 pt)</option>'+'<option value="6">6 (24 pt)</option>'+'<option value="7">7 (36 pt)</option>'+'</select>';case"|":case"separator":return'<img src="{$themeurl}/images/separator.gif" width="2" height="20" class="mceSeparatorLine" />';case"spacer":return'<img src="{$themeurl}/images/separator.gif" width="2" height="15" border="0" class="mceSeparatorLine" style="vertical-align: middle" />';case"rowseparator":return'<br />'}return""},execCommand:function(editor_id,element,command,user_interface,value){switch(command){case'mceHelp':tinyMCE.openWindow({file:'about.htm',width:480,height:380},{tinymce_version:tinyMCE.majorVersion+"."+tinyMCE.minorVersion,tinymce_releasedate:tinyMCE.releaseDate,inline:"yes"});return true;case"mceLink":var inst=tinyMCE.getInstanceById(editor_id);var doc=inst.getDoc();var selectedText="";if(tinyMCE.isMSIE){var rng=doc.selection.createRange();selectedText=rng.text}else selectedText=inst.getSel().toString();if(!tinyMCE.linkElement){if((tinyMCE.selectedElement.nodeName.toLowerCase()!="img")&&(selectedText.length<=0))return true}var href="",target="",title="",onclick="",action="insert",style_class="";if(tinyMCE.selectedElement.nodeName.toLowerCase()=="a")tinyMCE.linkElement=tinyMCE.selectedElement;if(tinyMCE.linkElement!=null&&tinyMCE.getAttrib(tinyMCE.linkElement,'href')=="")tinyMCE.linkElement=null;if(tinyMCE.linkElement){href=tinyMCE.getAttrib(tinyMCE.linkElement,'href');target=tinyMCE.getAttrib(tinyMCE.linkElement,'target');title=tinyMCE.getAttrib(tinyMCE.linkElement,'title');onclick=tinyMCE.getAttrib(tinyMCE.linkElement,'onclick');style_class=tinyMCE.getAttrib(tinyMCE.linkElement,'class');if(onclick=="")onclick=tinyMCE.getAttrib(tinyMCE.linkElement,'onclick');onclick=tinyMCE.cleanupEventStr(onclick);href=eval(tinyMCE.settings['urlconverter_callback']+"(href, tinyMCE.linkElement, true);");mceRealHref=tinyMCE.getAttrib(tinyMCE.linkElement,'mce_href');if(mceRealHref!=""){href=mceRealHref;if(tinyMCE.getParam('convert_urls'))href=eval(tinyMCE.settings['urlconverter_callback']+"(href, tinyMCE.linkElement, true);")}action="update"}var template=new Array();template['file']='link.htm';template['width']=310;template['height']=200;template['width']+=tinyMCE.getLang('lang_insert_link_delta_width',0);template['height']+=tinyMCE.getLang('lang_insert_link_delta_height',0);if(inst.settings['insertlink_callback']){var returnVal=eval(inst.settings['insertlink_callback']+"(href, target, title, onclick, action, style_class);");if(returnVal&&returnVal['href'])TinyMCE_AdvancedTheme._insertLink(returnVal['href'],returnVal['target'],returnVal['title'],returnVal['onclick'],returnVal['style_class'])}else{tinyMCE.openWindow(template,{href:href,target:target,title:title,onclick:onclick,action:action,className:style_class,inline:"yes"})}return true;case"mceImage":var src="",alt="",border="",hspace="",vspace="",width="",height="",align="";var title="",onmouseover="",onmouseout="",action="insert";var img=tinyMCE.imgElement;var inst=tinyMCE.getInstanceById(editor_id);if(tinyMCE.selectedElement!=null&&tinyMCE.selectedElement.nodeName.toLowerCase()=="img"){img=tinyMCE.selectedElement;tinyMCE.imgElement=img}if(img){if(tinyMCE.getAttrib(img,'name').indexOf('mce_')==0)return true;src=tinyMCE.getAttrib(img,'src');alt=tinyMCE.getAttrib(img,'alt');if(alt=="")alt=tinyMCE.getAttrib(img,'title');if(tinyMCE.isGecko){var w=img.style.width;if(w!=null&&w!="")img.setAttribute("width",w);var h=img.style.height;if(h!=null&&h!="")img.setAttribute("height",h)}border=tinyMCE.getAttrib(img,'border');hspace=tinyMCE.getAttrib(img,'hspace');vspace=tinyMCE.getAttrib(img,'vspace');width=tinyMCE.getAttrib(img,'width');height=tinyMCE.getAttrib(img,'height');align=tinyMCE.getAttrib(img,'align');onmouseover=tinyMCE.getAttrib(img,'onmouseover');onmouseout=tinyMCE.getAttrib(img,'onmouseout');title=tinyMCE.getAttrib(img,'title');if(tinyMCE.isMSIE){width=img.attributes['width'].specified?width:"";height=img.attributes['height'].specified?height:""}src=eval(tinyMCE.settings['urlconverter_callback']+"(src, img, true);");mceRealSrc=tinyMCE.getAttrib(img,'mce_src');if(mceRealSrc!=""){src=mceRealSrc;if(tinyMCE.getParam('convert_urls'))src=eval(tinyMCE.settings['urlconverter_callback']+"(src, img, true);")}action="update"}var template=new Array();template['file']='image.htm?src={$src}';template['width']=355;template['height']=265+(tinyMCE.isMSIE?25:0);template['width']+=tinyMCE.getLang('lang_insert_image_delta_width',0);template['height']+=tinyMCE.getLang('lang_insert_image_delta_height',0);if(inst.settings['insertimage_callback']){var returnVal=eval(inst.settings['insertimage_callback']+"(src, alt, border, hspace, vspace, width, height, align, title, onmouseover, onmouseout, action);");if(returnVal&&returnVal['src'])TinyMCE_AdvancedTheme._insertImage(returnVal['src'],returnVal['alt'],returnVal['border'],returnVal['hspace'],returnVal['vspace'],returnVal['width'],returnVal['height'],returnVal['align'],returnVal['title'],returnVal['onmouseover'],returnVal['onmouseout'])}else tinyMCE.openWindow(template,{src:src,alt:alt,border:border,hspace:hspace,vspace:vspace,width:width,height:height,align:align,title:title,onmouseover:onmouseover,onmouseout:onmouseout,action:action,inline:"yes"});return true;case"forecolor":var fcp=new TinyMCE_Layer(editor_id+'_fcPreview',false),p,img,elm;TinyMCE_AdvancedTheme._hideMenus(editor_id);if(!fcp.exists()){fcp.create('div','mceColorPreview',document.getElementById(editor_id+'_toolbar'));elm=fcp.getElement();elm._editor_id=editor_id;elm._command="forecolor";elm._switchId=editor_id+"_forecolor";tinyMCE.addEvent(elm,'click',TinyMCE_AdvancedTheme._handleMenuEvent);tinyMCE.addEvent(elm,'mouseover',TinyMCE_AdvancedTheme._handleMenuEvent);tinyMCE.addEvent(elm,'mouseout',TinyMCE_AdvancedTheme._handleMenuEvent)}img=tinyMCE.selectNodes(document.getElementById(editor_id+"_forecolor"),function(n){return n.nodeName=="IMG"})[0];p=tinyMCE.getAbsPosition(img,document.getElementById(editor_id+'_toolbar'));fcp.moveTo(p.absLeft,p.absTop);fcp.getElement().style.backgroundColor=value!=null?value:tinyMCE.getInstanceById(editor_id).foreColor;fcp.show();return false;case"forecolorpicker":this._pickColor(editor_id,'forecolor');return true;case"forecolorMenu":TinyMCE_AdvancedTheme._hideMenus(editor_id);var ml=new TinyMCE_Layer(editor_id+'_fcMenu');if(!ml.exists())ml.create('div','mceMenu',document.body,TinyMCE_AdvancedTheme._getColorHTML(editor_id,'theme_advanced_text_colors','forecolor'));tinyMCE.switchClass(editor_id+'_forecolor','mceMenuButtonFocus');ml.moveRelativeTo(document.getElementById(editor_id+"_forecolor"),'bl');ml.moveBy(tinyMCE.isMSIE&&!tinyMCE.isOpera?-1:1,-1);if(tinyMCE.isOpera)ml.moveBy(0,-2);ml.show();return true;case"HiliteColor":var bcp=new TinyMCE_Layer(editor_id+'_bcPreview',false),p,img;TinyMCE_AdvancedTheme._hideMenus(editor_id);if(!bcp.exists()){bcp.create('div','mceColorPreview',document.getElementById(editor_id+'_toolbar'));elm=bcp.getElement();elm._editor_id=editor_id;elm._command="HiliteColor";elm._switchId=editor_id+"_backcolor";tinyMCE.addEvent(elm,'click',TinyMCE_AdvancedTheme._handleMenuEvent);tinyMCE.addEvent(elm,'mouseover',TinyMCE_AdvancedTheme._handleMenuEvent);tinyMCE.addEvent(elm,'mouseout',TinyMCE_AdvancedTheme._handleMenuEvent)}img=tinyMCE.selectNodes(document.getElementById(editor_id+"_backcolor"),function(n){return n.nodeName=="IMG"})[0];p=tinyMCE.getAbsPosition(img,document.getElementById(editor_id+'_toolbar'));bcp.moveTo(p.absLeft,p.absTop);bcp.getElement().style.backgroundColor=value!=null?value:tinyMCE.getInstanceById(editor_id).backColor;bcp.show();return false;case"HiliteColorMenu":TinyMCE_AdvancedTheme._hideMenus(editor_id);var ml=new TinyMCE_Layer(editor_id+'_bcMenu');if(!ml.exists())ml.create('div','mceMenu',document.body,TinyMCE_AdvancedTheme._getColorHTML(editor_id,'theme_advanced_background_colors','HiliteColor'));tinyMCE.switchClass(editor_id+'_backcolor','mceMenuButtonFocus');ml.moveRelativeTo(document.getElementById(editor_id+"_backcolor"),'bl');ml.moveBy(tinyMCE.isMSIE&&!tinyMCE.isOpera?-1:1,-1);if(tinyMCE.isOpera)ml.moveBy(0,-2);ml.show();return true;case"backcolorpicker":this._pickColor(editor_id,'HiliteColor');return true;case"mceColorPicker":if(user_interface){var template=[];if(!value['callback']&&!value['color'])value['color']=value['document'].getElementById(value['element_id']).value;template['file']='color_picker.htm';template['width']=380;template['height']=250;template['close_previous']="no";template['width']+=tinyMCE.getLang('lang_theme_advanced_colorpicker_delta_width',0);template['height']+=tinyMCE.getLang('lang_theme_advanced_colorpicker_delta_height',0);if(typeof(value['store_selection'])=="undefined")value['store_selection']=true;tinyMCE.lastColorPickerValue=value;tinyMCE.openWindow(template,{editor_id:editor_id,mce_store_selection:value['store_selection'],inline:"yes",command:"mceColorPicker",input_color:value['color']})}else{var savedVal=tinyMCE.lastColorPickerValue,elm;if(savedVal['callback']){savedVal['callback'](value);return true}elm=savedVal['document'].getElementById(savedVal['element_id']);elm.value=value;if(elm.onchange!=null&&elm.onchange!='')eval('elm.onchange();')}return true;case"mceCodeEditor":var template=new Array();template['file']='source_editor.htm';template['width']=parseInt(tinyMCE.getParam("theme_advanced_source_editor_width",720));template['height']=parseInt(tinyMCE.getParam("theme_advanced_source_editor_height",580));tinyMCE.openWindow(template,{editor_id:editor_id,resizable:"yes",scrollbars:"no",inline:"yes"});return true;case"mceCharMap":var template=new Array();template['file']='charmap.htm';template['width']=550+(tinyMCE.isOpera?40:0);template['height']=250;template['width']+=tinyMCE.getLang('lang_theme_advanced_charmap_delta_width',0);template['height']+=tinyMCE.getLang('lang_theme_advanced_charmap_delta_height',0);tinyMCE.openWindow(template,{editor_id:editor_id,inline:"yes"});return true;case"mceInsertAnchor":var template=new Array();template['file']='anchor.htm';template['width']=320;template['height']=90+(tinyMCE.isNS7?30:0);template['width']+=tinyMCE.getLang('lang_theme_advanced_anchor_delta_width',0);template['height']+=tinyMCE.getLang('lang_theme_advanced_anchor_delta_height',0);tinyMCE.openWindow(template,{editor_id:editor_id,inline:"yes"});return true;case"mceNewDocument":if(confirm(tinyMCE.getLang('lang_newdocument')))tinyMCE.execInstanceCommand(editor_id,'mceSetContent',false,' ');return true}return false},getEditorTemplate:function(settings,editorId){function removeFromArray(in_array,remove_array){var outArray=new Array(),skip;for(var i=0;i<in_array.length;i++){skip=false;for(var j=0;j<remove_array.length;j++){if(in_array[i]==remove_array[j]){skip=true}}if(!skip){outArray[outArray.length]=in_array[i]}}return outArray}function addToArray(in_array,add_array){for(var i=0;i<add_array.length;i++){in_array[in_array.length]=add_array[i]}return in_array}var template=new Array();var deltaHeight=0;var resizing=tinyMCE.getParam("theme_advanced_resizing",false);var path=tinyMCE.getParam("theme_advanced_path",true);var statusbarHTML='<div id="{$editor_id}_path" class="mceStatusbarPathText" style="display: '+(path?"block":"none")+'">&#160;</div><div id="{$editor_id}_resize" class="mceStatusbarResize" style="display: '+(resizing?"block":"none")+'" onmousedown="tinyMCE.themes.advanced._setResizing(event,\'{$editor_id}\',true);"></div><br style="clear: both" />';var layoutManager=tinyMCE.getParam("theme_advanced_layout_manager","SimpleLayout");var styleSelectHTML='<option value="">{$lang_theme_style_select}</option>';if(settings['theme_advanced_styles']){var stylesAr=settings['theme_advanced_styles'].split(';');for(var i=0;i<stylesAr.length;i++){var key,value;key=stylesAr[i].split('=')[0];value=stylesAr[i].split('=')[1];styleSelectHTML+='<option value="'+value+'">'+key+'</option>'}TinyMCE_AdvancedTheme._autoImportCSSClasses=false}switch(layoutManager){case"SimpleLayout":var toolbarHTML="";var toolbarLocation=tinyMCE.getParam("theme_advanced_toolbar_location","bottom");var toolbarAlign=tinyMCE.getParam("theme_advanced_toolbar_align","center");var pathLocation=tinyMCE.getParam("theme_advanced_path_location","none");var statusbarLocation=tinyMCE.getParam("theme_advanced_statusbar_location",pathLocation);var defVals={theme_advanced_buttons1:"bold,italic,underline,strikethrough,separator,justifyleft,justifycenter,justifyright,justifyfull,separator,styleselect,formatselect",theme_advanced_buttons2:"bullist,numlist,separator,outdent,indent,separator,undo,redo,separator,link,unlink,anchor,image,cleanup,help,code",theme_advanced_buttons3:"hr,removeformat,visualaid,separator,sub,sup,separator,charmap"};toolbarHTML+='<a href="#" accesskey="q" title="'+tinyMCE.getLang("lang_toolbar_focus")+'"';if(!tinyMCE.getParam("accessibility_focus"))toolbarHTML+=' onfocus="tinyMCE.getInstanceById(\''+editorId+'\').getWin().focus();"';toolbarHTML+='></a>';for(var i=1;i<100;i++){var def=defVals["theme_advanced_buttons"+i];var buttons=tinyMCE.getParam("theme_advanced_buttons"+i,def==null?'':def,true,',');if(buttons.length==0)break;buttons=removeFromArray(buttons,tinyMCE.getParam("theme_advanced_disable","",true,','));buttons=addToArray(buttons,tinyMCE.getParam("theme_advanced_buttons"+i+"_add","",true,','));buttons=addToArray(tinyMCE.getParam("theme_advanced_buttons"+i+"_add_before","",true,','),buttons);for(var b=0;b<buttons.length;b++)toolbarHTML+=tinyMCE.getControlHTML(buttons[b]);if(buttons.length>0){toolbarHTML+="<br />";deltaHeight-=23}}toolbarHTML+='<a href="#" accesskey="z" onfocus="tinyMCE.getInstanceById(\''+editorId+'\').getWin().focus();"></a>';template['html']='<table class="mceEditor" border="0" cellpadding="0" cellspacing="0" width="{$width}" height="{$height}" style="width:{$width_style};height:{$height_style}"><tbody>';if(toolbarLocation=="top")template['html']+='<tr><td dir="ltr" class="mceToolbarTop" align="'+toolbarAlign+'" height="1" nowrap="nowrap"><span id="'+editorId+'_toolbar" class="mceToolbarContainer">'+toolbarHTML+'</span></td></tr>';if(statusbarLocation=="top"){template['html']+='<tr><td class="mceStatusbarTop" height="1">'+statusbarHTML+'</td></tr>';deltaHeight-=23}template['html']+='<tr><td align="center"><span id="{$editor_id}"></span></td></tr>';if(toolbarLocation=="bottom")template['html']+='<tr><td dir="ltr" class="mceToolbarBottom" align="'+toolbarAlign+'" height="1"><span id="'+editorId+'_toolbar" class="mceToolbarContainer">'+toolbarHTML+'</span></td></tr>';if(toolbarLocation=="external"){var bod=document.body;var elm=document.createElement("div");toolbarHTML=tinyMCE.replaceVar(toolbarHTML,'style_select_options',styleSelectHTML);toolbarHTML=tinyMCE.applyTemplate(toolbarHTML,{editor_id:editorId});elm.className="mceToolbarExternal";elm.id=editorId+"_toolbar";elm.innerHTML='<table width="100%" border="0" align="center"><tr><td align="center">'+toolbarHTML+'</td></tr></table>';bod.appendChild(elm);deltaHeight=0;tinyMCE.getInstanceById(editorId).toolbarElement=elm;}else{tinyMCE.getInstanceById(editorId).toolbarElement=null}if(statusbarLocation=="bottom"){template['html']+='<tr><td class="mceStatusbarBottom" height="1">'+statusbarHTML+'</td></tr>';deltaHeight-=23}template['html']+='</tbody></table>';break;case"RowLayout":template['html']='<table class="mceEditor" border="0" cellpadding="0" cellspacing="0" width="{$width}" height="{$height}" style="width:{$width}px;height:{$height}px"><tbody>';var containers=tinyMCE.getParam("theme_advanced_containers","",true,",");var defaultContainerCSS=tinyMCE.getParam("theme_advanced_containers_default_class","container");var defaultContainerAlign=tinyMCE.getParam("theme_advanced_containers_default_align","center");for(var i=0;i<containers.length;i++){if(containers[i]=="mceEditor")template['html']+='<tr><td align="center" class="mceEditor_border"><span id="{$editor_id}"></span></td></tr>';else if(containers[i]=="mceElementpath"||containers[i]=="mceStatusbar"){var pathClass="mceStatusbar";if(i==containers.length-1){pathClass="mceStatusbarBottom"}else if(i==0){pathClass="mceStatusbar"}else{deltaHeight-=2}template['html']+='<tr><td class="'+pathClass+'" height="1">'+statusbarHTML+'</td></tr>';deltaHeight-=22}else{var curContainer=tinyMCE.getParam("theme_advanced_container_"+containers[i],"",true,',');var curContainerHTML="";var curAlign=tinyMCE.getParam("theme_advanced_container_"+containers[i]+"_align",defaultContainerAlign);var curCSS=tinyMCE.getParam("theme_advanced_container_"+containers[i]+"_class",defaultContainerCSS);curContainer=removeFromArray(curContainer,tinyMCE.getParam("theme_advanced_disable","",true,','));for(var j=0;j<curContainer.length;j++)curContainerHTML+=tinyMCE.getControlHTML(curContainer[j]);if(curContainer.length>0){curContainerHTML+="<br />";deltaHeight-=23}template['html']+='<tr><td class="'+curCSS+'" align="'+curAlign+'" height="1">'+curContainerHTML+'</td></tr>'}}template['html']+='</tbody></table>';break;case"CustomLayout":var customLayout=tinyMCE.getParam("theme_advanced_custom_layout","");if(customLayout!=""&&eval("typeof("+customLayout+")")!="undefined"){template=eval(customLayout+"(template);")}break}if(resizing)template['html']+='<span id="{$editor_id}_resize_box" class="mceResizeBox"></span>';template['html']=tinyMCE.replaceVar(template['html'],'style_select_options',styleSelectHTML);if(!template['delta_width'])template['delta_width']=0;if(!template['delta_height'])template['delta_height']=deltaHeight;return template},initInstance:function(inst){if(tinyMCE.getParam("theme_advanced_resizing",false)){if(tinyMCE.getParam("theme_advanced_resizing_use_cookie",true)){var w=TinyMCE_AdvancedTheme._getCookie("TinyMCE_"+inst.editorId+"_width");var h=TinyMCE_AdvancedTheme._getCookie("TinyMCE_"+inst.editorId+"_height");TinyMCE_AdvancedTheme._resizeTo(inst,w,h,tinyMCE.getParam("theme_advanced_resize_horizontal",true))}}inst.addShortcut('ctrl','k','lang_link_desc','mceLink')},removeInstance:function(inst){new TinyMCE_Layer(inst.editorId+'_fcMenu').remove();new TinyMCE_Layer(inst.editorId+'_bcMenu').remove()},hideInstance:function(inst){TinyMCE_AdvancedTheme._hideMenus(inst.editorId)},_handleMenuEvent:function(e){var te=tinyMCE.isMSIE?window.event.srcElement:e.target;tinyMCE._menuButtonEvent(e.type=="mouseover"?"over":"out",document.getElementById(te._switchId));if(e.type=="click")tinyMCE.execInstanceCommand(te._editor_id,te._command)},_hideMenus:function(id){var fcml=new TinyMCE_Layer(id+'_fcMenu'),bcml=new TinyMCE_Layer(id+'_bcMenu');if(fcml.exists()&&fcml.isVisible()){tinyMCE.switchClass(id+'_forecolor','mceMenuButton');fcml.hide()}if(bcml.exists()&&bcml.isVisible()){tinyMCE.switchClass(id+'_backcolor','mceMenuButton');bcml.hide()}},handleNodeChange:function(editor_id,node,undo_index,undo_levels,visual_aid,any_selection,setup_content){var alignNode,breakOut,classNode;function selectByValue(select_elm,value,first_index){first_index=typeof(first_index)=="undefined"?false:true;if(select_elm){for(var i=0;i<select_elm.options.length;i++){var ov=""+select_elm.options[i].value;if(first_index&&ov.toLowerCase().indexOf(value.toLowerCase())==0){select_elm.selectedIndex=i;return true}if(ov==value){select_elm.selectedIndex=i;return true}}}return false};if(node==null)return;var pathElm=document.getElementById(editor_id+"_path");var inst=tinyMCE.getInstanceById(editor_id);var doc=inst.getDoc();TinyMCE_AdvancedTheme._hideMenus(editor_id);if(pathElm){var parentNode=node;var path=new Array();while(parentNode!=null){if(parentNode.nodeName.toUpperCase()=="BODY"){break}if(parentNode.nodeType==1&&tinyMCE.getAttrib(parentNode,"class").indexOf('mceItemHidden')==-1){path[path.length]=parentNode}parentNode=parentNode.parentNode}var html="";for(var i=path.length-1;i>=0;i--){var nodeName=path[i].nodeName.toLowerCase();var nodeData="";if(nodeName.indexOf("html:")==0)nodeName=nodeName.substring(5);if(nodeName=="b"){nodeName="strong"}if(nodeName=="i"){nodeName="em"}if(nodeName=="span"){var cn=tinyMCE.getAttrib(path[i],"class");if(cn!=""&&cn.indexOf('mceItem')==-1)nodeData+="class: "+cn+" ";var st=tinyMCE.getAttrib(path[i],"style");if(st!=""){st=tinyMCE.serializeStyle(tinyMCE.parseStyle(st));nodeData+="style: "+tinyMCE.xmlEncode(st)+" "}}if(nodeName=="font"){if(tinyMCE.getParam("convert_fonts_to_spans"))nodeName="span";var face=tinyMCE.getAttrib(path[i],"face");if(face!="")nodeData+="font: "+tinyMCE.xmlEncode(face)+" ";var size=tinyMCE.getAttrib(path[i],"size");if(size!="")nodeData+="size: "+tinyMCE.xmlEncode(size)+" ";var color=tinyMCE.getAttrib(path[i],"color");if(color!="")nodeData+="color: "+tinyMCE.xmlEncode(color)+" "}if(tinyMCE.getAttrib(path[i],'id')!=""){nodeData+="id: "+path[i].getAttribute('id')+" "}var className=tinyMCE.getVisualAidClass(tinyMCE.getAttrib(path[i],"class"),false);if(className!=""&&className.indexOf('mceItem')==-1)nodeData+="class: "+className+" ";if(tinyMCE.getAttrib(path[i],'src')!=""){var src=tinyMCE.getAttrib(path[i],"mce_src");if(src=="")src=tinyMCE.getAttrib(path[i],"src");nodeData+="src: "+tinyMCE.xmlEncode(src)+" "}if(path[i].nodeName=='A'&&tinyMCE.getAttrib(path[i],'href')!=""){var href=tinyMCE.getAttrib(path[i],"mce_href");if(href=="")href=tinyMCE.getAttrib(path[i],"href");nodeData+="href: "+tinyMCE.xmlEncode(href)+" "}className=tinyMCE.getAttrib(path[i],"class");if((nodeName=="img"||nodeName=="span")&&className.indexOf('mceItem')!=-1){nodeName=className.replace(/mceItem([a-z]+)/gi,'$1').toLowerCase();nodeData=path[i].getAttribute('title')}if(nodeName=="a"&&(anchor=tinyMCE.getAttrib(path[i],"name"))!=""){nodeName="a";nodeName+="#"+tinyMCE.xmlEncode(anchor);nodeData=""}if(tinyMCE.getAttrib(path[i],'name').indexOf("mce_")!=0){var className=tinyMCE.getVisualAidClass(tinyMCE.getAttrib(path[i],"class"),false);if(className!=""&&className.indexOf('mceItem')==-1){nodeName+="."+className}}var cmd='tinyMCE.execInstanceCommand(\''+editor_id+'\',\'mceSelectNodeDepth\',false,\''+i+'\');';html+='<a title="'+nodeData+'" href="javascript:'+cmd+'" onclick="'+cmd+'return false;" onmousedown="return false;" target="_self" class="mcePathItem">'+nodeName+'</a>';if(i>0){html+=" &raquo; "}}pathElm.innerHTML='<a href="#" accesskey="x"></a>'+tinyMCE.getLang('lang_theme_path')+": "+html+'&#160;'}tinyMCE.switchClass(editor_id+'_justifyleft','mceButtonNormal');tinyMCE.switchClass(editor_id+'_justifyright','mceButtonNormal');tinyMCE.switchClass(editor_id+'_justifycenter','mceButtonNormal');tinyMCE.switchClass(editor_id+'_justifyfull','mceButtonNormal');tinyMCE.switchClass(editor_id+'_bold','mceButtonNormal');tinyMCE.switchClass(editor_id+'_italic','mceButtonNormal');tinyMCE.switchClass(editor_id+'_underline','mceButtonNormal');tinyMCE.switchClass(editor_id+'_strikethrough','mceButtonNormal');tinyMCE.switchClass(editor_id+'_bullist','mceButtonNormal');tinyMCE.switchClass(editor_id+'_numlist','mceButtonNormal');tinyMCE.switchClass(editor_id+'_sub','mceButtonNormal');tinyMCE.switchClass(editor_id+'_sup','mceButtonNormal');tinyMCE.switchClass(editor_id+'_anchor','mceButtonNormal');tinyMCE.switchClass(editor_id+'_link','mceButtonDisabled');tinyMCE.switchClass(editor_id+'_unlink','mceButtonDisabled');tinyMCE.switchClass(editor_id+'_outdent','mceButtonDisabled');tinyMCE.switchClass(editor_id+'_image','mceButtonNormal');tinyMCE.switchClass(editor_id+'_hr','mceButtonNormal');if(node.nodeName=="A"&&tinyMCE.getAttrib(node,"class").indexOf('mceItemAnchor')!=-1)tinyMCE.switchClass(editor_id+'_anchor','mceButtonSelected');var anchorLink=tinyMCE.getParentElement(node,"a","href");if(anchorLink||any_selection){tinyMCE.switchClass(editor_id+'_link',anchorLink?'mceButtonSelected':'mceButtonNormal');tinyMCE.switchClass(editor_id+'_unlink',anchorLink?'mceButtonSelected':'mceButtonNormal')}tinyMCE.switchClass(editor_id+'_visualaid',visual_aid?'mceButtonSelected':'mceButtonNormal');if(undo_levels!=-1){tinyMCE.switchClass(editor_id+'_undo','mceButtonDisabled');tinyMCE.switchClass(editor_id+'_redo','mceButtonDisabled')}if(tinyMCE.getParentElement(node,"li,blockquote"))tinyMCE.switchClass(editor_id+'_outdent','mceButtonNormal');if(undo_index!=-1&&(undo_index<undo_levels-1&&undo_levels>0))tinyMCE.switchClass(editor_id+'_redo','mceButtonNormal');if(undo_index!=-1&&(undo_index>0&&undo_levels>0))tinyMCE.switchClass(editor_id+'_undo','mceButtonNormal');var selectElm=document.getElementById(editor_id+"_styleSelect");if(selectElm){TinyMCE_AdvancedTheme._setupCSSClasses(editor_id);classNode=node;breakOut=false;var index=0;do{if(classNode&&classNode.className){for(var i=0;i<selectElm.options.length;i++){if(selectElm.options[i].value==classNode.className){index=i;breakOut=true;break}}}}while(!breakOut&&classNode!=null&&(classNode=classNode.parentNode)!=null);selectElm.selectedIndex=index}var selectElm=document.getElementById(editor_id+"_formatSelect");if(selectElm){var elm=tinyMCE.getParentElement(node,"p,div,h1,h2,h3,h4,h5,h6,pre,address");if(elm)selectByValue(selectElm,"<"+elm.nodeName.toLowerCase()+">");else selectByValue(selectElm,"")}var selectElm=document.getElementById(editor_id+"_fontNameSelect");if(selectElm){if(!tinyMCE.isSafari&&!(tinyMCE.isMSIE&&!tinyMCE.isOpera)){var face=inst.queryCommandValue('FontName');face=face==null||face==""?"":face;selectByValue(selectElm,face,face!="")}else{var elm=tinyMCE.getParentElement(node,"font","face");if(elm){var family=tinyMCE.getAttrib(elm,"face");if(family=='')family=''+elm.style.fontFamily;if(!selectByValue(selectElm,family,family!=""))selectByValue(selectElm,"")}else selectByValue(selectElm,"")}}var selectElm=document.getElementById(editor_id+"_fontSizeSelect");if(selectElm){if(!tinyMCE.isSafari&&!tinyMCE.isOpera){var size=inst.queryCommandValue('FontSize');selectByValue(selectElm,size==null||size==""?"0":size)}else{var elm=tinyMCE.getParentElement(node,"font","size");if(elm){var size=tinyMCE.getAttrib(elm,"size");if(size==''){var sizes=new Array('','8px','10px','12px','14px','18px','24px','36px');size=''+elm.style.fontSize;for(var i=0;i<sizes.length;i++){if((''+sizes[i])==size){size=i;break}}}if(!selectByValue(selectElm,size))selectByValue(selectElm,"")}else selectByValue(selectElm,"0")}}alignNode=node;breakOut=false;do{if(!alignNode.getAttribute||!alignNode.getAttribute('align'))continue;switch(alignNode.getAttribute('align').toLowerCase()){case"left":tinyMCE.switchClass(editor_id+'_justifyleft','mceButtonSelected');breakOut=true;break;case"right":tinyMCE.switchClass(editor_id+'_justifyright','mceButtonSelected');breakOut=true;break;case"middle":case"center":tinyMCE.switchClass(editor_id+'_justifycenter','mceButtonSelected');breakOut=true;break;case"justify":tinyMCE.switchClass(editor_id+'_justifyfull','mceButtonSelected');breakOut=true;break}}while(!breakOut&&(alignNode=alignNode.parentNode)!=null);var div=tinyMCE.getParentElement(node,"div");if(div&&div.style.textAlign=="center")tinyMCE.switchClass(editor_id+'_justifycenter','mceButtonSelected');if(!setup_content){var ar=new Array("Bold","_bold","Italic","_italic","Strikethrough","_strikethrough","superscript","_sup","subscript","_sub");for(var i=0;i<ar.length;i+=2){if(inst.queryCommandState(ar[i]))tinyMCE.switchClass(editor_id+ar[i+1],'mceButtonSelected')}if(inst.queryCommandState("Underline")&&(node.parentNode==null||node.parentNode.nodeName!="A"))tinyMCE.switchClass(editor_id+'_underline','mceButtonSelected')}do{switch(node.nodeName){case"UL":tinyMCE.switchClass(editor_id+'_bullist','mceButtonSelected');break;case"OL":tinyMCE.switchClass(editor_id+'_numlist','mceButtonSelected');break;case"HR":tinyMCE.switchClass(editor_id+'_hr','mceButtonSelected');break;case"IMG":if(tinyMCE.getAttrib(node,'name').indexOf('mce_')!=0&&tinyMCE.getAttrib(node,'class').indexOf('mceItem')==-1){tinyMCE.switchClass(editor_id+'_image','mceButtonSelected')}break}}while((node=node.parentNode)!=null)},_setupCSSClasses:function(editor_id){var i,selectElm;if(!TinyMCE_AdvancedTheme._autoImportCSSClasses)return;selectElm=document.getElementById(editor_id+'_styleSelect');if(selectElm&&selectElm.getAttribute('cssImported')!='true'){var csses=tinyMCE.getCSSClasses(editor_id);if(csses&&selectElm){for(i=0;i<csses.length;i++)selectElm.options[selectElm.options.length]=new Option(csses[i],csses[i])}if(csses!=null&&csses.length>0)selectElm.setAttribute('cssImported','true')}},_setCookie:function(name,value,expires,path,domain,secure){var curCookie=name+"="+escape(value)+((expires)?"; expires="+expires.toGMTString():"")+((path)?"; path="+escape(path):"")+((domain)?"; domain="+domain:"")+((secure)?"; secure":"");document.cookie=curCookie},_getCookie:function(name){var dc=document.cookie;var prefix=name+"=";var begin=dc.indexOf("; "+prefix);if(begin==-1){begin=dc.indexOf(prefix);if(begin!=0)return null}else begin+=2;var end=document.cookie.indexOf(";",begin);if(end==-1)end=dc.length;return unescape(dc.substring(begin+prefix.length,end))},_resizeTo:function(inst,w,h,set_w){var editorContainer=document.getElementById(inst.editorId+'_parent');var tableElm=editorContainer.firstChild;var iframe=inst.iframeElement;if(w==null||w=="null"){set_w=false;w=0}if(h==null||h=="null")return;w=parseInt(w);h=parseInt(h);if(tinyMCE.isGecko){w+=2;h+=2}var dx=w-tableElm.clientWidth;var dy=h-tableElm.clientHeight;w=w<1?30:w;h=h<1?30:h;if(set_w)tableElm.style.width=w+"px";tableElm.style.height=h+"px";iw=iframe.clientWidth+dx;ih=iframe.clientHeight+dy;iw=iw<1?30:iw;ih=ih<1?30:ih;if(tinyMCE.isGecko){iw-=2;ih-=2}if(set_w)iframe.style.width=iw+"px";iframe.style.height=ih+"px";if(set_w){var tableBodyElm=tableElm.firstChild;var minIframeWidth=tableBodyElm.scrollWidth;if(inst.iframeElement.clientWidth<minIframeWidth){dx=minIframeWidth-inst.iframeElement.clientWidth;inst.iframeElement.style.width=(iw+dx)+"px"}}inst.useCSS=false},_resizeEventHandler:function(e){var resizer=TinyMCE_AdvancedTheme._resizer;if(!resizer.resizing)return;e=typeof(e)=="undefined"?window.event:e;var dx=e.screenX-resizer.downX;var dy=e.screenY-resizer.downY;var resizeBox=resizer.resizeBox;var editorId=resizer.editorId;switch(e.type){case"mousemove":var w,h;w=resizer.width+dx;h=resizer.height+dy;w=w<1?1:w;h=h<1?1:h;if(resizer.horizontal)resizeBox.style.width=w+"px";resizeBox.style.height=h+"px";break;case"mouseup":TinyMCE_AdvancedTheme._setResizing(e,editorId,false);TinyMCE_AdvancedTheme._resizeTo(tinyMCE.getInstanceById(editorId),resizer.width+dx,resizer.height+dy,resizer.horizontal);if(tinyMCE.getParam("theme_advanced_resizing_use_cookie",true)){var expires=new Date();expires.setTime(expires.getTime()+3600000*24*30);TinyMCE_AdvancedTheme._setCookie("TinyMCE_"+editorId+"_width",""+(resizer.horizontal?resizer.width+dx:""),expires);TinyMCE_AdvancedTheme._setCookie("TinyMCE_"+editorId+"_height",""+(resizer.height+dy),expires)}break}},_setResizing:function(e,editor_id,state){e=typeof(e)=="undefined"?window.event:e;var resizer=TinyMCE_AdvancedTheme._resizer;var editorContainer=document.getElementById(editor_id+'_parent');var editorArea=document.getElementById(editor_id+'_parent').firstChild;var resizeBox=document.getElementById(editor_id+'_resize_box');var inst=tinyMCE.getInstanceById(editor_id);if(state){var width=editorArea.clientWidth;var height=editorArea.clientHeight;resizeBox.style.width=width+"px";resizeBox.style.height=height+"px";resizer.iframeWidth=inst.iframeElement.clientWidth;resizer.iframeHeight=inst.iframeElement.clientHeight;editorArea.style.display="none";resizeBox.style.display="block";if(!resizer.eventHandlers){if(tinyMCE.isMSIE)tinyMCE.addEvent(document,"mousemove",TinyMCE_AdvancedTheme._resizeEventHandler);else tinyMCE.addEvent(window,"mousemove",TinyMCE_AdvancedTheme._resizeEventHandler);tinyMCE.addEvent(document,"mouseup",TinyMCE_AdvancedTheme._resizeEventHandler);resizer.eventHandlers=true}resizer.resizing=true;resizer.downX=e.screenX;resizer.downY=e.screenY;resizer.width=parseInt(resizeBox.style.width);resizer.height=parseInt(resizeBox.style.height);resizer.editorId=editor_id;resizer.resizeBox=resizeBox;resizer.horizontal=tinyMCE.getParam("theme_advanced_resize_horizontal",true)}else{resizer.resizing=false;resizeBox.style.display="none";editorArea.style.display=tinyMCE.isMSIE&&!tinyMCE.isOpera?"block":"table";tinyMCE.execCommand('mceResetDesignMode')}},_getColorHTML:function(id,n,cm){var i,h,cl;h='<span class="mceMenuLine"></span>';cl=tinyMCE.getParam(n,TinyMCE_AdvancedTheme._defColors).split(',');h+='<table class="mceColors"><tr>';for(i=0;i<cl.length;i++){c='tinyMCE.execInstanceCommand(\''+id+'\', \''+cm+'\', false, \'#'+cl[i]+'\');';h+='<td><a href="javascript:'+c+'" style="background-color: #'+cl[i]+'" onclick="'+c+';return false;"></a></td>';if((i+1)%8==0)h+='</tr><tr>'}h+='</tr></table>';if(tinyMCE.getParam("theme_advanced_more_colors",true))h+='<a href="#" onclick="TinyMCE_AdvancedTheme._pickColor(\''+id+'\',\''+cm+'\');" class="mceMoreColors">'+tinyMCE.getLang('lang_more_colors')+'</a>';return h},_pickColor:function(id,cm){var inputColor,inst=tinyMCE.selectedInstance;if(cm=='forecolor'&&inst)inputColor=inst.foreColor;if((cm=='backcolor'||cm=='HiliteColor')&&inst)inputColor=inst.backColor;tinyMCE.execCommand('mceColorPicker',true,{color:inputColor,callback:function(c){tinyMCE.execInstanceCommand(id,cm,false,c)}})},_insertImage:function(src,alt,border,hspace,vspace,width,height,align,title,onmouseover,onmouseout){tinyMCE.execCommand('mceBeginUndoLevel');if(src=="")return;if(!tinyMCE.imgElement&&tinyMCE.isSafari){var html="";html+='<img src="'+src+'" alt="'+alt+'"';html+=' border="'+border+'" hspace="'+hspace+'"';html+=' vspace="'+vspace+'" width="'+width+'"';html+=' height="'+height+'" align="'+align+'" title="'+title+'" onmouseover="'+onmouseover+'" onmouseout="'+onmouseout+'" />';tinyMCE.execCommand("mceInsertContent",false,html)}else{if(!tinyMCE.imgElement&&tinyMCE.selectedInstance){if(tinyMCE.isSafari)tinyMCE.execCommand("mceInsertContent",false,'<img src="'+tinyMCE.uniqueURL+'" />');else tinyMCE.selectedInstance.contentDocument.execCommand("insertimage",false,tinyMCE.uniqueURL);tinyMCE.imgElement=tinyMCE.getElementByAttributeValue(tinyMCE.selectedInstance.contentDocument.body,"img","src",tinyMCE.uniqueURL)}}if(tinyMCE.imgElement){var needsRepaint=false;var msrc=src;src=eval(tinyMCE.settings['urlconverter_callback']+"(src, tinyMCE.imgElement);");if(tinyMCE.getParam('convert_urls'))msrc=src;if(onmouseover&&onmouseover!="")onmouseover="this.src='"+eval(tinyMCE.settings['urlconverter_callback']+"(onmouseover, tinyMCE.imgElement);")+"';";if(onmouseout&&onmouseout!="")onmouseout="this.src='"+eval(tinyMCE.settings['urlconverter_callback']+"(onmouseout, tinyMCE.imgElement);")+"';";if(typeof(title)=="undefined")title=alt;if(width!=tinyMCE.imgElement.getAttribute("width")||height!=tinyMCE.imgElement.getAttribute("height")||align!=tinyMCE.imgElement.getAttribute("align"))needsRepaint=true;tinyMCE.setAttrib(tinyMCE.imgElement,'src',src);tinyMCE.setAttrib(tinyMCE.imgElement,'mce_src',msrc);tinyMCE.setAttrib(tinyMCE.imgElement,'alt',alt);tinyMCE.setAttrib(tinyMCE.imgElement,'title',title);tinyMCE.setAttrib(tinyMCE.imgElement,'align',align);tinyMCE.setAttrib(tinyMCE.imgElement,'border',border,true);tinyMCE.setAttrib(tinyMCE.imgElement,'hspace',hspace,true);tinyMCE.setAttrib(tinyMCE.imgElement,'vspace',vspace,true);tinyMCE.setAttrib(tinyMCE.imgElement,'width',width,true);tinyMCE.setAttrib(tinyMCE.imgElement,'height',height,true);tinyMCE.setAttrib(tinyMCE.imgElement,'onmouseover',onmouseover);tinyMCE.setAttrib(tinyMCE.imgElement,'onmouseout',onmouseout);if(width&&width!="")tinyMCE.imgElement.style.pixelWidth=width;if(height&&height!="")tinyMCE.imgElement.style.pixelHeight=height;if(needsRepaint)tinyMCE.selectedInstance.repaint()}tinyMCE.execCommand('mceEndUndoLevel')},_insertLink:function(href,target,title,onclick,style_class){tinyMCE.execCommand('mceBeginUndoLevel');if(tinyMCE.selectedInstance&&tinyMCE.selectedElement&&tinyMCE.selectedElement.nodeName.toLowerCase()=="img"){var doc=tinyMCE.selectedInstance.getDoc();var linkElement=tinyMCE.getParentElement(tinyMCE.selectedElement,"a");var newLink=false;if(!linkElement){linkElement=doc.createElement("a");newLink=true}var mhref=href;var thref=eval(tinyMCE.settings['urlconverter_callback']+"(href, linkElement);");mhref=tinyMCE.getParam('convert_urls')?href:mhref;tinyMCE.setAttrib(linkElement,'href',thref);tinyMCE.setAttrib(linkElement,'mce_href',mhref);tinyMCE.setAttrib(linkElement,'target',target);tinyMCE.setAttrib(linkElement,'title',title);tinyMCE.setAttrib(linkElement,'onclick',onclick);tinyMCE.setAttrib(linkElement,'class',style_class);if(newLink){linkElement.appendChild(tinyMCE.selectedElement.cloneNode(true));tinyMCE.selectedElement.parentNode.replaceChild(linkElement,tinyMCE.selectedElement)}return}if(!tinyMCE.linkElement&&tinyMCE.selectedInstance){if(tinyMCE.isSafari){tinyMCE.execCommand("mceInsertContent",false,'<a href="'+tinyMCE.uniqueURL+'">'+tinyMCE.selectedInstance.selection.getSelectedHTML()+'</a>')}else tinyMCE.selectedInstance.contentDocument.execCommand("createlink",false,tinyMCE.uniqueURL);tinyMCE.linkElement=tinyMCE.getElementByAttributeValue(tinyMCE.selectedInstance.contentDocument.body,"a","href",tinyMCE.uniqueURL);var elementArray=tinyMCE.getElementsByAttributeValue(tinyMCE.selectedInstance.contentDocument.body,"a","href",tinyMCE.uniqueURL);for(var i=0;i<elementArray.length;i++){var mhref=href;var thref=eval(tinyMCE.settings['urlconverter_callback']+"(href, elementArray[i]);");mhref=tinyMCE.getParam('convert_urls')?href:mhref;tinyMCE.setAttrib(elementArray[i],'href',thref);tinyMCE.setAttrib(elementArray[i],'mce_href',mhref);tinyMCE.setAttrib(elementArray[i],'target',target);tinyMCE.setAttrib(elementArray[i],'title',title);tinyMCE.setAttrib(elementArray[i],'onclick',onclick);tinyMCE.setAttrib(elementArray[i],'class',style_class)}tinyMCE.linkElement=elementArray[0]}if(tinyMCE.linkElement){var mhref=href;href=eval(tinyMCE.settings['urlconverter_callback']+"(href, tinyMCE.linkElement);");mhref=tinyMCE.getParam('convert_urls')?href:mhref;tinyMCE.setAttrib(tinyMCE.linkElement,'href',href);tinyMCE.setAttrib(tinyMCE.linkElement,'mce_href',mhref);tinyMCE.setAttrib(tinyMCE.linkElement,'target',target);tinyMCE.setAttrib(tinyMCE.linkElement,'title',title);tinyMCE.setAttrib(tinyMCE.linkElement,'onclick',onclick);tinyMCE.setAttrib(tinyMCE.linkElement,'class',style_class)}tinyMCE.execCommand('mceEndUndoLevel')}};tinyMCE.addTheme("advanced",TinyMCE_AdvancedTheme);tinyMCE.addButtonMap(TinyMCE_AdvancedTheme._buttonMap);
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/themes/advanced/editor_template_src.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1574 @@
+/**
+ * $Id: editor_template_src.js 218 2007-02-13 11:08:01Z spocke $
+ *
+ * @author Moxiecode
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+/* Import theme specific language pack */
+tinyMCE.importThemeLanguagePack('advanced');
+
+var TinyMCE_AdvancedTheme = {
+	// Private theme fields
+	_defColors : "000000,993300,333300,003300,003366,000080,333399,333333,800000,FF6600,808000,008000,008080,0000FF,666699,808080,FF0000,FF9900,99CC00,339966,33CCCC,3366FF,800080,999999,FF00FF,FFCC00,FFFF00,00FF00,00FFFF,00CCFF,993366,C0C0C0,FF99CC,FFCC99,FFFF99,CCFFCC,CCFFFF,99CCFF,CC99FF,FFFFFF",
+	_autoImportCSSClasses : true,
+	_resizer : {},
+	_buttons : [
+		// Control id, button img, button title, command, user_interface, value
+		['bold', '{$lang_bold_img}', 'lang_bold_desc', 'Bold'],
+		['italic', '{$lang_italic_img}', 'lang_italic_desc', 'Italic'],
+		['underline', '{$lang_underline_img}', 'lang_underline_desc', 'Underline'],
+		['strikethrough', 'strikethrough.gif', 'lang_striketrough_desc', 'Strikethrough'],
+		['justifyleft', 'justifyleft.gif', 'lang_justifyleft_desc', 'JustifyLeft'],
+		['justifycenter', 'justifycenter.gif', 'lang_justifycenter_desc', 'JustifyCenter'],
+		['justifyright', 'justifyright.gif', 'lang_justifyright_desc', 'JustifyRight'],
+		['justifyfull', 'justifyfull.gif', 'lang_justifyfull_desc', 'JustifyFull'],
+		['bullist', 'bullist.gif', 'lang_bullist_desc', 'InsertUnorderedList'],
+		['numlist', 'numlist.gif', 'lang_numlist_desc', 'InsertOrderedList'],
+		['outdent', 'outdent.gif', 'lang_outdent_desc', 'Outdent'],
+		['indent', 'indent.gif', 'lang_indent_desc', 'Indent'],
+		['cut', 'cut.gif', 'lang_cut_desc', 'Cut'],
+		['copy', 'copy.gif', 'lang_copy_desc', 'Copy'],
+		['paste', 'paste.gif', 'lang_paste_desc', 'Paste'],
+		['undo', 'undo.gif', 'lang_undo_desc', 'Undo'],
+		['redo', 'redo.gif', 'lang_redo_desc', 'Redo'],
+		['link', 'link.gif', 'lang_link_desc', 'mceLink', true],
+		['unlink', 'unlink.gif', 'lang_unlink_desc', 'unlink'],
+		['image', 'image.gif', 'lang_image_desc', 'mceImage', true],
+		['cleanup', 'cleanup.gif', 'lang_cleanup_desc', 'mceCleanup'],
+		['help', 'help.gif', 'lang_help_desc', 'mceHelp'],
+		['code', 'code.gif', 'lang_theme_code_desc', 'mceCodeEditor'],
+		['hr', 'hr.gif', 'lang_theme_hr_desc', 'inserthorizontalrule'],
+		['removeformat', 'removeformat.gif', 'lang_theme_removeformat_desc', 'removeformat'],
+		['sub', 'sub.gif', 'lang_theme_sub_desc', 'subscript'],
+		['sup', 'sup.gif', 'lang_theme_sup_desc', 'superscript'],
+		['forecolor', 'forecolor.gif', 'lang_theme_forecolor_desc', 'forecolor', true],
+		['forecolorpicker', 'forecolor.gif', 'lang_theme_forecolor_desc', 'forecolorpicker', true],
+		['backcolor', 'backcolor.gif', 'lang_theme_backcolor_desc', 'HiliteColor', true],
+		['backcolorpicker', 'backcolor.gif', 'lang_theme_backcolor_desc', 'backcolorpicker', true],
+		['charmap', 'charmap.gif', 'lang_theme_charmap_desc', 'mceCharMap'],
+		['visualaid', 'visualaid.gif', 'lang_theme_visualaid_desc', 'mceToggleVisualAid'],
+		['anchor', 'anchor.gif', 'lang_theme_anchor_desc', 'mceInsertAnchor'],
+		['newdocument', 'newdocument.gif', 'lang_newdocument_desc', 'mceNewDocument']
+	],
+
+	_buttonMap : 'anchor,backcolor,bold,bullist,charmap,cleanup,code,copy,cut,forecolor,help,hr,image,indent,italic,justifycenter,justifyfull,justifyleft,justifyright,link,newdocument,numlist,outdent,paste,redo,removeformat,strikethrough,sub,sup,underline,undo,unlink,visualaid,advhr,ltr,rtl,emotions,flash,fullpage,fullscreen,iespell,insertdate,inserttime,pastetext,pasteword,selectall,preview,print,save,replace,search,table,cell_props,delete_col,delete_row,col_after,col_before,row_after,row_before,merge_cells,row_props,split_cells,delete_table',
+
+	/**
+	 * Returns HTML code for the specificed control.
+	 */
+	getControlHTML : function(button_name) {
+		var i, x, but;
+
+		// Lookup button in button list
+		for (i=0; i<TinyMCE_AdvancedTheme._buttons.length; i++) {
+			but = TinyMCE_AdvancedTheme._buttons[i];
+
+			if (but[0] == button_name && (button_name == "forecolor" || button_name == "backcolor"))
+				return tinyMCE.getMenuButtonHTML(but[0], but[2], '{$themeurl}/images/' + but[1], but[3] + "Menu", but[3], (but.length > 4 ? but[4] : false), (but.length > 5 ? but[5] : null));
+
+			if (but[0] == button_name)
+				return tinyMCE.getButtonHTML(but[0], but[2], '{$themeurl}/images/' + but[1], but[3], (but.length > 4 ? but[4] : false), (but.length > 5 ? but[5] : null));
+		}
+
+		// Custom controlls other than buttons
+		switch (button_name) {
+			case "formatselect":
+				var html = '<select id="{$editor_id}_formatSelect" name="{$editor_id}_formatSelect" onfocus="tinyMCE.addSelectAccessibility(event, this, window);" onchange="tinyMCE.execInstanceCommand(\'{$editor_id}\',\'FormatBlock\',false,this.options[this.selectedIndex].value);" class="mceSelectList">';
+				var formats = tinyMCE.getParam("theme_advanced_blockformats", "p,address,pre,h1,h2,h3,h4,h5,h6", true).split(',');
+				var lookup = [
+					['p', '{$lang_theme_paragraph}'],
+					['address', '{$lang_theme_address}'],
+					['pre', '{$lang_theme_pre}'],
+					['h1', '{$lang_theme_h1}'],
+					['h2', '{$lang_theme_h2}'],
+					['h3', '{$lang_theme_h3}'],
+					['h4', '{$lang_theme_h4}'],
+					['h5', '{$lang_theme_h5}'],
+					['h6', '{$lang_theme_h6}'],
+					['div', '{$lang_theme_div}'],
+					['blockquote', '{$lang_theme_blockquote}'],
+					['code', '{$lang_theme_code}'],
+					['dt', '{$lang_theme_dt}'],
+					['dd', '{$lang_theme_dd}'],
+					['samp', '{$lang_theme_samp}']
+				];
+
+				html += '<option value="">{$lang_theme_block}</option>';
+
+				// Build format select
+				for (var i=0; i<formats.length; i++) {
+					for (var x=0; x<lookup.length; x++) {
+						if (formats[i] == lookup[x][0])
+							html += '<option value="&lt;' + lookup[x][0] + '&gt;">' + lookup[x][1] + '</option>';
+					}
+				}
+
+				html += '</select>';
+
+				return html;
+
+			case "styleselect":
+				return '<select id="{$editor_id}_styleSelect" onmousedown="tinyMCE.themes.advanced._setupCSSClasses(\'{$editor_id}\');" name="{$editor_id}_styleSelect" onfocus="tinyMCE.addSelectAccessibility(event,this,window);" onchange="tinyMCE.execInstanceCommand(\'{$editor_id}\',\'mceSetCSSClass\',false,this.options[this.selectedIndex].value);" class="mceSelectList">{$style_select_options}</select>';
+
+			case "fontselect":
+				var fontHTML = '<select id="{$editor_id}_fontNameSelect" name="{$editor_id}_fontNameSelect" onfocus="tinyMCE.addSelectAccessibility(event, this, window);" onchange="tinyMCE.execInstanceCommand(\'{$editor_id}\',\'FontName\',false,this.options[this.selectedIndex].value);" class="mceSelectList"><option value="">{$lang_theme_fontdefault}</option>';
+				var iFonts = 'Arial=arial,helvetica,sans-serif;Courier New=courier new,courier,monospace;Georgia=georgia,times new roman,times,serif;Tahoma=tahoma,arial,helvetica,sans-serif;Times New Roman=times new roman,times,serif;Verdana=verdana,arial,helvetica,sans-serif;Impact=impact;WingDings=wingdings';
+				var nFonts = 'Andale Mono=andale mono,times;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;Comic Sans MS=comic sans ms,sand;Courier New=courier new,courier;Georgia=georgia,palatino;Helvetica=helvetica;Impact=impact,chicago;Symbol=symbol;Tahoma=tahoma,arial,helvetica,sans-serif;Terminal=terminal,monaco;Times New Roman=times new roman,times;Trebuchet MS=trebuchet ms,geneva;Verdana=verdana,geneva;Webdings=webdings;Wingdings=wingdings,zapf dingbats';
+				var fonts = tinyMCE.getParam("theme_advanced_fonts", nFonts).split(';');
+				for (i=0; i<fonts.length; i++) {
+					if (fonts[i] != '') {
+						var parts = fonts[i].split('=');
+						fontHTML += '<option value="' + parts[1] + '">' + parts[0] + '</option>';
+					}
+				}
+
+				fontHTML += '</select>';
+				return fontHTML;
+
+			case "fontsizeselect":
+				return '<select id="{$editor_id}_fontSizeSelect" name="{$editor_id}_fontSizeSelect" onfocus="tinyMCE.addSelectAccessibility(event, this, window);" onchange="tinyMCE.execInstanceCommand(\'{$editor_id}\',\'FontSize\',false,this.options[this.selectedIndex].value);" class="mceSelectList">'+
+						'<option value="0">{$lang_theme_font_size}</option>'+
+						'<option value="1">1 (8 pt)</option>'+
+						'<option value="2">2 (10 pt)</option>'+
+						'<option value="3">3 (12 pt)</option>'+
+						'<option value="4">4 (14 pt)</option>'+
+						'<option value="5">5 (18 pt)</option>'+
+						'<option value="6">6 (24 pt)</option>'+
+						'<option value="7">7 (36 pt)</option>'+
+						'</select>';
+
+			case "|":
+			case "separator":
+				return '<img src="{$themeurl}/images/separator.gif" width="2" height="20" class="mceSeparatorLine" />';
+
+			case "spacer":
+				return '<img src="{$themeurl}/images/separator.gif" width="2" height="15" border="0" class="mceSeparatorLine" style="vertical-align: middle" />';
+
+			case "rowseparator":
+				return '<br />';
+		}
+
+		return "";
+	},
+
+	/**
+	 * Theme specific execcommand handling.
+	 */
+	execCommand : function(editor_id, element, command, user_interface, value) {
+		switch (command) {
+			case 'mceHelp':
+				tinyMCE.openWindow({
+					file : 'about.htm',
+					width : 480,
+					height : 380
+				}, {
+					tinymce_version : tinyMCE.majorVersion + "." + tinyMCE.minorVersion,
+					tinymce_releasedate : tinyMCE.releaseDate,
+					inline : "yes"
+				});
+			return true;
+
+			case "mceLink":
+				var inst = tinyMCE.getInstanceById(editor_id);
+				var doc = inst.getDoc();
+				var selectedText = "";
+
+				if (tinyMCE.isMSIE) {
+					var rng = doc.selection.createRange();
+					selectedText = rng.text;
+				} else
+					selectedText = inst.getSel().toString();
+
+				if (!tinyMCE.linkElement) {
+					if ((tinyMCE.selectedElement.nodeName.toLowerCase() != "img") && (selectedText.length <= 0))
+						return true;
+				}
+
+				var href = "", target = "", title = "", onclick = "", action = "insert", style_class = "";
+
+				if (tinyMCE.selectedElement.nodeName.toLowerCase() == "a")
+					tinyMCE.linkElement = tinyMCE.selectedElement;
+
+				// Is anchor not a link
+				if (tinyMCE.linkElement != null && tinyMCE.getAttrib(tinyMCE.linkElement, 'href') == "")
+					tinyMCE.linkElement = null;
+
+				if (tinyMCE.linkElement) {
+					href = tinyMCE.getAttrib(tinyMCE.linkElement, 'href');
+					target = tinyMCE.getAttrib(tinyMCE.linkElement, 'target');
+					title = tinyMCE.getAttrib(tinyMCE.linkElement, 'title');
+					onclick = tinyMCE.getAttrib(tinyMCE.linkElement, 'onclick');
+					style_class = tinyMCE.getAttrib(tinyMCE.linkElement, 'class');
+
+					// Try old onclick to if copy/pasted content
+					if (onclick == "")
+						onclick = tinyMCE.getAttrib(tinyMCE.linkElement, 'onclick');
+
+					onclick = tinyMCE.cleanupEventStr(onclick);
+
+					href = eval(tinyMCE.settings['urlconverter_callback'] + "(href, tinyMCE.linkElement, true);");
+
+					// Use mce_href if defined
+					mceRealHref = tinyMCE.getAttrib(tinyMCE.linkElement, 'mce_href');
+					if (mceRealHref != "") {
+						href = mceRealHref;
+
+						if (tinyMCE.getParam('convert_urls'))
+							href = eval(tinyMCE.settings['urlconverter_callback'] + "(href, tinyMCE.linkElement, true);");
+					}
+
+					action = "update";
+				}
+
+				var template = new Array();
+
+				template['file'] = 'link.htm';
+				template['width'] = 310;
+				template['height'] = 200;
+
+				// Language specific width and height addons
+				template['width'] += tinyMCE.getLang('lang_insert_link_delta_width', 0);
+				template['height'] += tinyMCE.getLang('lang_insert_link_delta_height', 0);
+
+				if (inst.settings['insertlink_callback']) {
+					var returnVal = eval(inst.settings['insertlink_callback'] + "(href, target, title, onclick, action, style_class);");
+					if (returnVal && returnVal['href'])
+						TinyMCE_AdvancedTheme._insertLink(returnVal['href'], returnVal['target'], returnVal['title'], returnVal['onclick'], returnVal['style_class']);
+				} else {
+					tinyMCE.openWindow(template, {href : href, target : target, title : title, onclick : onclick, action : action, className : style_class, inline : "yes"});
+				}
+
+				return true;
+
+			case "mceImage":
+				var src = "", alt = "", border = "", hspace = "", vspace = "", width = "", height = "", align = "";
+				var title = "", onmouseover = "", onmouseout = "", action = "insert";
+				var img = tinyMCE.imgElement;
+				var inst = tinyMCE.getInstanceById(editor_id);
+
+				if (tinyMCE.selectedElement != null && tinyMCE.selectedElement.nodeName.toLowerCase() == "img") {
+					img = tinyMCE.selectedElement;
+					tinyMCE.imgElement = img;
+				}
+
+				if (img) {
+					// Is it a internal MCE visual aid image, then skip this one.
+					if (tinyMCE.getAttrib(img, 'name').indexOf('mce_') == 0)
+						return true;
+
+					src = tinyMCE.getAttrib(img, 'src');
+					alt = tinyMCE.getAttrib(img, 'alt');
+
+					// Try polling out the title
+					if (alt == "")
+						alt = tinyMCE.getAttrib(img, 'title');
+
+					// Fix width/height attributes if the styles is specified
+					if (tinyMCE.isGecko) {
+						var w = img.style.width;
+						if (w != null && w != "")
+							img.setAttribute("width", w);
+
+						var h = img.style.height;
+						if (h != null && h != "")
+							img.setAttribute("height", h);
+					}
+
+					border = tinyMCE.getAttrib(img, 'border');
+					hspace = tinyMCE.getAttrib(img, 'hspace');
+					vspace = tinyMCE.getAttrib(img, 'vspace');
+					width = tinyMCE.getAttrib(img, 'width');
+					height = tinyMCE.getAttrib(img, 'height');
+					align = tinyMCE.getAttrib(img, 'align');
+					onmouseover = tinyMCE.getAttrib(img, 'onmouseover');
+					onmouseout = tinyMCE.getAttrib(img, 'onmouseout');
+					title = tinyMCE.getAttrib(img, 'title');
+
+					// Is realy specified?
+					if (tinyMCE.isMSIE) {
+						width = img.attributes['width'].specified ? width : "";
+						height = img.attributes['height'].specified ? height : "";
+					}
+
+					//onmouseover = tinyMCE.getImageSrc(tinyMCE.cleanupEventStr(onmouseover));
+					//onmouseout = tinyMCE.getImageSrc(tinyMCE.cleanupEventStr(onmouseout));
+
+					src = eval(tinyMCE.settings['urlconverter_callback'] + "(src, img, true);");
+
+					// Use mce_src if defined
+					mceRealSrc = tinyMCE.getAttrib(img, 'mce_src');
+					if (mceRealSrc != "") {
+						src = mceRealSrc;
+
+						if (tinyMCE.getParam('convert_urls'))
+							src = eval(tinyMCE.settings['urlconverter_callback'] + "(src, img, true);");
+					}
+
+					//if (onmouseover != "")
+					//	onmouseover = eval(tinyMCE.settings['urlconverter_callback'] + "(onmouseover, img, true);");
+
+					//if (onmouseout != "")
+					//	onmouseout = eval(tinyMCE.settings['urlconverter_callback'] + "(onmouseout, img, true);");
+
+					action = "update";
+				}
+
+				var template = new Array();
+
+				template['file'] = 'image.htm?src={$src}';
+				template['width'] = 355;
+				template['height'] = 265 + (tinyMCE.isMSIE ? 25 : 0);
+
+				// Language specific width and height addons
+				template['width'] += tinyMCE.getLang('lang_insert_image_delta_width', 0);
+				template['height'] += tinyMCE.getLang('lang_insert_image_delta_height', 0);
+
+				if (inst.settings['insertimage_callback']) {
+					var returnVal = eval(inst.settings['insertimage_callback'] + "(src, alt, border, hspace, vspace, width, height, align, title, onmouseover, onmouseout, action);");
+					if (returnVal && returnVal['src'])
+						TinyMCE_AdvancedTheme._insertImage(returnVal['src'], returnVal['alt'], returnVal['border'], returnVal['hspace'], returnVal['vspace'], returnVal['width'], returnVal['height'], returnVal['align'], returnVal['title'], returnVal['onmouseover'], returnVal['onmouseout']);
+				} else
+					tinyMCE.openWindow(template, {src : src, alt : alt, border : border, hspace : hspace, vspace : vspace, width : width, height : height, align : align, title : title, onmouseover : onmouseover, onmouseout : onmouseout, action : action, inline : "yes"});
+
+				return true;
+
+			case "forecolor":
+				var fcp = new TinyMCE_Layer(editor_id + '_fcPreview', false), p, img, elm;
+
+				TinyMCE_AdvancedTheme._hideMenus(editor_id);
+
+				if (!fcp.exists()) {
+					fcp.create('div', 'mceColorPreview', document.getElementById(editor_id + '_toolbar'));
+					elm = fcp.getElement();
+					elm._editor_id = editor_id;
+					elm._command = "forecolor";
+					elm._switchId = editor_id + "_forecolor";
+					tinyMCE.addEvent(elm, 'click', TinyMCE_AdvancedTheme._handleMenuEvent);
+					tinyMCE.addEvent(elm, 'mouseover', TinyMCE_AdvancedTheme._handleMenuEvent);
+					tinyMCE.addEvent(elm, 'mouseout', TinyMCE_AdvancedTheme._handleMenuEvent);
+				}
+
+				img = tinyMCE.selectNodes(document.getElementById(editor_id + "_forecolor"), function(n) {return n.nodeName == "IMG";})[0];
+				p = tinyMCE.getAbsPosition(img, document.getElementById(editor_id + '_toolbar'));
+
+				fcp.moveTo(p.absLeft, p.absTop);
+				fcp.getElement().style.backgroundColor = value != null ? value : tinyMCE.getInstanceById(editor_id).foreColor;
+				fcp.show();
+
+				return false;
+
+			case "forecolorpicker":
+				this._pickColor(editor_id, 'forecolor');
+				return true;
+
+			case "forecolorMenu":
+				TinyMCE_AdvancedTheme._hideMenus(editor_id);
+
+				// Create color layer
+				var ml = new TinyMCE_Layer(editor_id + '_fcMenu');
+
+				if (!ml.exists())
+					ml.create('div', 'mceMenu', document.body, TinyMCE_AdvancedTheme._getColorHTML(editor_id, 'theme_advanced_text_colors', 'forecolor'));
+
+				tinyMCE.switchClass(editor_id + '_forecolor', 'mceMenuButtonFocus');
+				ml.moveRelativeTo(document.getElementById(editor_id + "_forecolor"), 'bl');
+
+				ml.moveBy(tinyMCE.isMSIE && !tinyMCE.isOpera ? -1 : 1, -1);
+
+				if (tinyMCE.isOpera)
+					ml.moveBy(0, -2);
+
+				ml.show();
+			return true;
+
+			case "HiliteColor":
+				var bcp = new TinyMCE_Layer(editor_id + '_bcPreview', false), p, img;
+
+				TinyMCE_AdvancedTheme._hideMenus(editor_id);
+
+				if (!bcp.exists()) {
+					bcp.create('div', 'mceColorPreview', document.getElementById(editor_id + '_toolbar'));
+					elm = bcp.getElement();
+					elm._editor_id = editor_id;
+					elm._command = "HiliteColor";
+					elm._switchId = editor_id + "_backcolor";
+					tinyMCE.addEvent(elm, 'click', TinyMCE_AdvancedTheme._handleMenuEvent);
+					tinyMCE.addEvent(elm, 'mouseover', TinyMCE_AdvancedTheme._handleMenuEvent);
+					tinyMCE.addEvent(elm, 'mouseout', TinyMCE_AdvancedTheme._handleMenuEvent);
+				}
+
+				img = tinyMCE.selectNodes(document.getElementById(editor_id + "_backcolor"), function(n) {return n.nodeName == "IMG";})[0];
+				p = tinyMCE.getAbsPosition(img, document.getElementById(editor_id + '_toolbar'));
+
+				bcp.moveTo(p.absLeft, p.absTop);
+				bcp.getElement().style.backgroundColor = value != null ? value : tinyMCE.getInstanceById(editor_id).backColor;
+				bcp.show();
+
+				return false;
+
+			case "HiliteColorMenu":
+				TinyMCE_AdvancedTheme._hideMenus(editor_id);
+
+				// Create color layer
+				var ml = new TinyMCE_Layer(editor_id + '_bcMenu');
+
+				if (!ml.exists())
+					ml.create('div', 'mceMenu', document.body, TinyMCE_AdvancedTheme._getColorHTML(editor_id, 'theme_advanced_background_colors', 'HiliteColor'));
+
+				tinyMCE.switchClass(editor_id + '_backcolor', 'mceMenuButtonFocus');
+				ml.moveRelativeTo(document.getElementById(editor_id + "_backcolor"), 'bl');
+
+				ml.moveBy(tinyMCE.isMSIE && !tinyMCE.isOpera ? -1 : 1, -1);
+
+				if (tinyMCE.isOpera)
+					ml.moveBy(0, -2);
+
+				ml.show();
+			return true;
+	
+			case "backcolorpicker":
+				this._pickColor(editor_id, 'HiliteColor');
+				return true;
+
+			case "mceColorPicker":
+				if (user_interface) {
+					var template = [];
+	
+					if (!value['callback'] && !value['color'])
+						value['color'] = value['document'].getElementById(value['element_id']).value;
+
+					template['file'] = 'color_picker.htm';
+					template['width'] = 380;
+					template['height'] = 250;
+					template['close_previous'] = "no";
+
+					template['width'] += tinyMCE.getLang('lang_theme_advanced_colorpicker_delta_width', 0);
+					template['height'] += tinyMCE.getLang('lang_theme_advanced_colorpicker_delta_height', 0);
+
+					if (typeof(value['store_selection']) == "undefined")
+						value['store_selection'] = true;
+
+					tinyMCE.lastColorPickerValue = value;
+					tinyMCE.openWindow(template, {editor_id : editor_id, mce_store_selection : value['store_selection'], inline : "yes", command : "mceColorPicker", input_color : value['color']});
+				} else {
+					var savedVal = tinyMCE.lastColorPickerValue, elm;
+
+					if (savedVal['callback']) {
+						savedVal['callback'](value);
+						return true;
+					}
+
+					elm = savedVal['document'].getElementById(savedVal['element_id']);
+					elm.value = value;
+
+					if (elm.onchange != null && elm.onchange != '')
+						eval('elm.onchange();');
+				}
+			return true;
+
+			case "mceCodeEditor":
+				var template = new Array();
+
+				template['file'] = 'source_editor.htm';
+				template['width'] = parseInt(tinyMCE.getParam("theme_advanced_source_editor_width", 720));
+				template['height'] = parseInt(tinyMCE.getParam("theme_advanced_source_editor_height", 580));
+
+				tinyMCE.openWindow(template, {editor_id : editor_id, resizable : "yes", scrollbars : "no", inline : "yes"});
+				return true;
+
+			case "mceCharMap":
+				var template = new Array();
+
+				template['file'] = 'charmap.htm';
+				template['width'] = 550 + (tinyMCE.isOpera ? 40 : 0);
+				template['height'] = 250;
+
+				template['width'] += tinyMCE.getLang('lang_theme_advanced_charmap_delta_width', 0);
+				template['height'] += tinyMCE.getLang('lang_theme_advanced_charmap_delta_height', 0);
+
+				tinyMCE.openWindow(template, {editor_id : editor_id, inline : "yes"});
+				return true;
+
+			case "mceInsertAnchor":
+				var template = new Array();
+
+				template['file'] = 'anchor.htm';
+				template['width'] = 320;
+				template['height'] = 90 + (tinyMCE.isNS7 ? 30 : 0);
+
+				template['width'] += tinyMCE.getLang('lang_theme_advanced_anchor_delta_width', 0);
+				template['height'] += tinyMCE.getLang('lang_theme_advanced_anchor_delta_height', 0);
+
+				tinyMCE.openWindow(template, {editor_id : editor_id, inline : "yes"});
+				return true;
+
+			case "mceNewDocument":
+				if (confirm(tinyMCE.getLang('lang_newdocument')))
+					tinyMCE.execInstanceCommand(editor_id, 'mceSetContent', false, ' ');
+
+				return true;
+		}
+
+		return false;
+	},
+
+	/**
+	 * Editor instance template function.
+	 */
+	getEditorTemplate : function(settings, editorId) {
+		function removeFromArray(in_array, remove_array) {
+			var outArray = new Array(), skip;
+			
+			for (var i=0; i<in_array.length; i++) {
+				skip = false;
+
+				for (var j=0; j<remove_array.length; j++) {
+					if (in_array[i] == remove_array[j]) {
+						skip = true;
+					}
+				}
+
+				if (!skip) {
+					outArray[outArray.length] = in_array[i];
+				}
+			}
+
+			return outArray;
+		}
+
+		function addToArray(in_array, add_array) {
+			for (var i=0; i<add_array.length; i++) {
+				in_array[in_array.length] = add_array[i];
+			}
+
+			return in_array;
+		}
+
+		var template = new Array();
+		var deltaHeight = 0;
+		var resizing = tinyMCE.getParam("theme_advanced_resizing", false);
+		var path = tinyMCE.getParam("theme_advanced_path", true);
+		var statusbarHTML = '<div id="{$editor_id}_path" class="mceStatusbarPathText" style="display: ' + (path ? "block" : "none") + '">&#160;</div><div id="{$editor_id}_resize" class="mceStatusbarResize" style="display: ' + (resizing ? "block" : "none") + '" onmousedown="tinyMCE.themes.advanced._setResizing(event,\'{$editor_id}\',true);"></div><br style="clear: both" />';
+		var layoutManager = tinyMCE.getParam("theme_advanced_layout_manager", "SimpleLayout");
+
+		// Setup style select options -- MOVED UP FOR EXTERNAL TOOLBAR COMPATABILITY!
+		var styleSelectHTML = '<option value="">{$lang_theme_style_select}</option>';
+		if (settings['theme_advanced_styles']) {
+			var stylesAr = settings['theme_advanced_styles'].split(';');
+			
+			for (var i=0; i<stylesAr.length; i++) {
+				var key, value;
+
+				key = stylesAr[i].split('=')[0];
+				value = stylesAr[i].split('=')[1];
+
+				styleSelectHTML += '<option value="' + value + '">' + key + '</option>';
+			}
+
+			TinyMCE_AdvancedTheme._autoImportCSSClasses = false;
+		}
+
+		switch(layoutManager) {
+			case "SimpleLayout" : //the default TinyMCE Layout (for backwards compatibility)...
+				var toolbarHTML = "";
+				var toolbarLocation = tinyMCE.getParam("theme_advanced_toolbar_location", "bottom");
+				var toolbarAlign = tinyMCE.getParam("theme_advanced_toolbar_align", "center");
+				var pathLocation = tinyMCE.getParam("theme_advanced_path_location", "none"); // Compatiblity
+				var statusbarLocation = tinyMCE.getParam("theme_advanced_statusbar_location", pathLocation);
+				var defVals = {
+					theme_advanced_buttons1 : "bold,italic,underline,strikethrough,separator,justifyleft,justifycenter,justifyright,justifyfull,separator,styleselect,formatselect",
+					theme_advanced_buttons2 : "bullist,numlist,separator,outdent,indent,separator,undo,redo,separator,link,unlink,anchor,image,cleanup,help,code",
+					theme_advanced_buttons3 : "hr,removeformat,visualaid,separator,sub,sup,separator,charmap"
+				};
+
+				// Add accessibility control
+				toolbarHTML += '<a href="#" accesskey="q" title="' + tinyMCE.getLang("lang_toolbar_focus") + '"';
+
+				if (!tinyMCE.getParam("accessibility_focus"))
+					toolbarHTML += ' onfocus="tinyMCE.getInstanceById(\'' + editorId + '\').getWin().focus();"';
+
+				toolbarHTML += '></a>';
+
+				// Render rows
+				for (var i=1; i<100; i++) {
+					var def = defVals["theme_advanced_buttons" + i];
+
+					var buttons = tinyMCE.getParam("theme_advanced_buttons" + i, def == null ? '' : def, true, ',');
+					if (buttons.length == 0)
+						break;
+
+					buttons = removeFromArray(buttons, tinyMCE.getParam("theme_advanced_disable", "", true, ','));
+					buttons = addToArray(buttons, tinyMCE.getParam("theme_advanced_buttons" + i + "_add", "", true, ','));
+					buttons = addToArray(tinyMCE.getParam("theme_advanced_buttons" + i + "_add_before", "", true, ','), buttons);
+
+					for (var b=0; b<buttons.length; b++)
+						toolbarHTML += tinyMCE.getControlHTML(buttons[b]);
+
+					if (buttons.length > 0) {
+						toolbarHTML += "<br />";
+						deltaHeight -= 23;
+					}
+				}
+
+				// Add accessibility control
+				toolbarHTML += '<a href="#" accesskey="z" onfocus="tinyMCE.getInstanceById(\'' + editorId + '\').getWin().focus();"></a>';
+
+				// Setup template html
+				template['html'] = '<table class="mceEditor" border="0" cellpadding="0" cellspacing="0" width="{$width}" height="{$height}" style="width:{$width_style};height:{$height_style}"><tbody>';
+
+				if (toolbarLocation == "top")
+					template['html'] += '<tr><td dir="ltr" class="mceToolbarTop" align="' + toolbarAlign + '" height="1" nowrap="nowrap"><span id="' + editorId + '_toolbar" class="mceToolbarContainer">' + toolbarHTML + '</span></td></tr>';
+
+				if (statusbarLocation == "top") {
+					template['html'] += '<tr><td class="mceStatusbarTop" height="1">' + statusbarHTML + '</td></tr>';
+					deltaHeight -= 23;
+				}
+
+				template['html'] += '<tr><td align="center"><span id="{$editor_id}"></span></td></tr>';
+
+				if (toolbarLocation == "bottom")
+					template['html'] += '<tr><td dir="ltr" class="mceToolbarBottom" align="' + toolbarAlign + '" height="1"><span id="' + editorId + '_toolbar" class="mceToolbarContainer">' + toolbarHTML + '</span></td></tr>';
+
+				// External toolbar changes
+				if (toolbarLocation == "external") {
+					var bod = document.body;
+					var elm = document.createElement ("div");
+
+					toolbarHTML = tinyMCE.replaceVar(toolbarHTML, 'style_select_options', styleSelectHTML);
+					toolbarHTML = tinyMCE.applyTemplate(toolbarHTML, {editor_id : editorId});
+
+					elm.className = "mceToolbarExternal";
+					elm.id = editorId+"_toolbar";
+					elm.innerHTML = '<table width="100%" border="0" align="center"><tr><td align="center">'+toolbarHTML+'</td></tr></table>';
+					bod.appendChild (elm);
+					// bod.style.marginTop = elm.offsetHeight + "px";
+
+					deltaHeight = 0;
+					tinyMCE.getInstanceById(editorId).toolbarElement = elm;
+
+					//template['html'] = '<div id="mceExternalToolbar" align="center" class="mceToolbarExternal"><table width="100%" border="0" align="center"><tr><td align="center">'+toolbarHTML+'</td></tr></table></div>' + template["html"];
+				} else {
+					tinyMCE.getInstanceById(editorId).toolbarElement = null;
+				}
+
+				if (statusbarLocation == "bottom") {
+					template['html'] += '<tr><td class="mceStatusbarBottom" height="1">' + statusbarHTML + '</td></tr>';
+					deltaHeight -= 23;
+				}
+
+				template['html'] += '</tbody></table>';
+				//"SimpleLayout"
+			break;
+
+			case "RowLayout" : //Container Layout - containers defined in "theme_advanced_containers" are rendered from top to bottom.
+				template['html'] = '<table class="mceEditor" border="0" cellpadding="0" cellspacing="0" width="{$width}" height="{$height}" style="width:{$width}px;height:{$height}px"><tbody>';
+
+				var containers = tinyMCE.getParam("theme_advanced_containers", "", true, ",");
+				var defaultContainerCSS = tinyMCE.getParam("theme_advanced_containers_default_class", "container");
+				var defaultContainerAlign = tinyMCE.getParam("theme_advanced_containers_default_align", "center");
+
+				//Render Containers:
+				for (var i = 0; i < containers.length; i++)
+				{
+					if (containers[i] == "mceEditor") //Exceptions for mceEditor and ...
+						template['html'] += '<tr><td align="center" class="mceEditor_border"><span id="{$editor_id}"></span></td></tr>';
+					else if (containers[i] == "mceElementpath" || containers[i] == "mceStatusbar") // ... mceElementpath:
+					{
+						var pathClass = "mceStatusbar";
+
+						if (i == containers.length-1)
+						{
+							pathClass = "mceStatusbarBottom";
+						}
+						else if (i == 0)
+						{
+							pathClass = "mceStatusbar";
+						}
+						else
+						{
+							deltaHeight-=2;
+						}
+
+						template['html'] += '<tr><td class="' + pathClass + '" height="1">' + statusbarHTML + '</td></tr>';
+						deltaHeight -= 22;
+					} else { // Render normal Container
+						var curContainer = tinyMCE.getParam("theme_advanced_container_"+containers[i], "", true, ',');
+						var curContainerHTML = "";
+						var curAlign = tinyMCE.getParam("theme_advanced_container_"+containers[i]+"_align", defaultContainerAlign);
+						var curCSS = tinyMCE.getParam("theme_advanced_container_"+containers[i]+"_class", defaultContainerCSS);
+
+						curContainer = removeFromArray(curContainer, tinyMCE.getParam("theme_advanced_disable", "", true, ','));
+
+						for (var j=0; j<curContainer.length; j++)
+							curContainerHTML += tinyMCE.getControlHTML(curContainer[j]);
+
+						if (curContainer.length > 0) {
+							curContainerHTML += "<br />";
+							deltaHeight -= 23;
+						}
+
+						template['html'] += '<tr><td class="' + curCSS + '" align="' + curAlign + '" height="1">' + curContainerHTML + '</td></tr>';
+					}
+				}
+
+				template['html'] += '</tbody></table>';
+				//RowLayout
+			break;
+
+			case "CustomLayout" : //User defined layout callback...
+				var customLayout = tinyMCE.getParam("theme_advanced_custom_layout","");
+
+				if (customLayout != "" && eval("typeof(" + customLayout + ")") != "undefined") {
+					template = eval(customLayout + "(template);");
+				}
+			break;
+		}
+
+		if (resizing)
+			template['html'] += '<span id="{$editor_id}_resize_box" class="mceResizeBox"></span>';
+
+		template['html'] = tinyMCE.replaceVar(template['html'], 'style_select_options', styleSelectHTML);
+
+		// Set to default values
+		if (!template['delta_width'])
+			template['delta_width'] = 0;
+
+		if (!template['delta_height'])
+			template['delta_height'] = deltaHeight;
+
+		return template;
+	},
+
+	initInstance : function(inst) {
+		if (tinyMCE.getParam("theme_advanced_resizing", false)) {
+			if (tinyMCE.getParam("theme_advanced_resizing_use_cookie", true)) {
+				var w = TinyMCE_AdvancedTheme._getCookie("TinyMCE_" + inst.editorId + "_width");
+				var h = TinyMCE_AdvancedTheme._getCookie("TinyMCE_" + inst.editorId + "_height");
+
+				TinyMCE_AdvancedTheme._resizeTo(inst, w, h, tinyMCE.getParam("theme_advanced_resize_horizontal", true));
+			}
+		}
+
+		inst.addShortcut('ctrl', 'k', 'lang_link_desc', 'mceLink');
+	},
+
+	removeInstance : function(inst) {
+		new TinyMCE_Layer(inst.editorId + '_fcMenu').remove();
+		new TinyMCE_Layer(inst.editorId + '_bcMenu').remove();
+	},
+
+	hideInstance : function(inst) {
+		TinyMCE_AdvancedTheme._hideMenus(inst.editorId);
+	},
+
+	_handleMenuEvent : function(e) {
+		var te = tinyMCE.isMSIE ? window.event.srcElement : e.target;
+		tinyMCE._menuButtonEvent(e.type == "mouseover" ? "over" : "out", document.getElementById(te._switchId));
+
+		if (e.type == "click")
+			tinyMCE.execInstanceCommand(te._editor_id, te._command);
+	},
+
+	_hideMenus : function(id) {
+		var fcml = new TinyMCE_Layer(id + '_fcMenu'), bcml = new TinyMCE_Layer(id + '_bcMenu');
+
+		if (fcml.exists() && fcml.isVisible()) {
+			tinyMCE.switchClass(id + '_forecolor', 'mceMenuButton');
+			fcml.hide();
+		}
+
+		if (bcml.exists() && bcml.isVisible()) {
+			tinyMCE.switchClass(id + '_backcolor', 'mceMenuButton');
+			bcml.hide();
+		}
+	},
+
+	/**
+	 * Node change handler.
+	 */
+	handleNodeChange : function(editor_id, node, undo_index, undo_levels, visual_aid, any_selection, setup_content) {
+		var alignNode, breakOut, classNode;
+
+		function selectByValue(select_elm, value, first_index) {
+			first_index = typeof(first_index) == "undefined" ? false : true;
+
+			if (select_elm) {
+				for (var i=0; i<select_elm.options.length; i++) {
+					var ov = "" + select_elm.options[i].value;
+
+					if (first_index && ov.toLowerCase().indexOf(value.toLowerCase()) == 0) {
+						select_elm.selectedIndex = i;
+						return true;
+					}
+
+					if (ov == value) {
+						select_elm.selectedIndex = i;
+						return true;
+					}
+				}
+			}
+
+			return false;
+		};
+
+		// No node provided
+		if (node == null)
+			return;
+
+		// Update path
+		var pathElm = document.getElementById(editor_id + "_path");
+		var inst = tinyMCE.getInstanceById(editor_id);
+		var doc = inst.getDoc();
+		TinyMCE_AdvancedTheme._hideMenus(editor_id);
+
+		if (pathElm) {
+			// Get node path
+			var parentNode = node;
+			var path = new Array();
+			
+			while (parentNode != null) {
+				if (parentNode.nodeName.toUpperCase() == "BODY") {
+					break;
+				}
+
+				// Only append element nodes to path
+				if (parentNode.nodeType == 1 && tinyMCE.getAttrib(parentNode, "class").indexOf('mceItemHidden') == -1) {
+					path[path.length] = parentNode;
+				}
+
+				parentNode = parentNode.parentNode;
+			}
+
+			// Setup HTML
+			var html = "";
+			for (var i=path.length-1; i>=0; i--) {
+				var nodeName = path[i].nodeName.toLowerCase();
+				var nodeData = "";
+
+				if (nodeName.indexOf("html:") == 0)
+					nodeName = nodeName.substring(5);
+
+				if (nodeName == "b") {
+					nodeName = "strong";
+				}
+
+				if (nodeName == "i") {
+					nodeName = "em";
+				}
+
+				if (nodeName == "span") {
+					var cn = tinyMCE.getAttrib(path[i], "class");
+					if (cn != "" && cn.indexOf('mceItem') == -1)
+						nodeData += "class: " + cn + " ";
+
+					var st = tinyMCE.getAttrib(path[i], "style");
+					if (st != "") {
+						st = tinyMCE.serializeStyle(tinyMCE.parseStyle(st));
+						nodeData += "style: " + tinyMCE.xmlEncode(st) + " ";
+					}
+				}
+
+				if (nodeName == "font") {
+					if (tinyMCE.getParam("convert_fonts_to_spans"))
+						nodeName = "span";
+
+					var face = tinyMCE.getAttrib(path[i], "face");
+					if (face != "")
+						nodeData += "font: " + tinyMCE.xmlEncode(face) + " ";
+
+					var size = tinyMCE.getAttrib(path[i], "size");
+					if (size != "")
+						nodeData += "size: " + tinyMCE.xmlEncode(size) + " ";
+
+					var color = tinyMCE.getAttrib(path[i], "color");
+					if (color != "")
+						nodeData += "color: " + tinyMCE.xmlEncode(color) + " ";
+				}
+
+				if (tinyMCE.getAttrib(path[i], 'id') != "") {
+					nodeData += "id: " + path[i].getAttribute('id') + " ";
+				}
+
+				var className = tinyMCE.getVisualAidClass(tinyMCE.getAttrib(path[i], "class"), false);
+				if (className != "" && className.indexOf('mceItem') == -1)
+					nodeData += "class: " + className + " ";
+
+				if (tinyMCE.getAttrib(path[i], 'src') != "") {
+					var src = tinyMCE.getAttrib(path[i], "mce_src");
+
+					if (src == "")
+						 src = tinyMCE.getAttrib(path[i], "src");
+
+					nodeData += "src: " + tinyMCE.xmlEncode(src) + " ";
+				}
+
+				if (path[i].nodeName == 'A' && tinyMCE.getAttrib(path[i], 'href') != "") {
+					var href = tinyMCE.getAttrib(path[i], "mce_href");
+
+					if (href == "")
+						 href = tinyMCE.getAttrib(path[i], "href");
+
+					nodeData += "href: " + tinyMCE.xmlEncode(href) + " ";
+				}
+
+				className = tinyMCE.getAttrib(path[i], "class");
+				if ((nodeName == "img" || nodeName == "span") && className.indexOf('mceItem') != -1) {
+					nodeName = className.replace(/mceItem([a-z]+)/gi, '$1').toLowerCase();
+					nodeData = path[i].getAttribute('title');
+				}
+
+				if (nodeName == "a" && (anchor = tinyMCE.getAttrib(path[i], "name")) != "") {
+					nodeName = "a";
+					nodeName += "#" + tinyMCE.xmlEncode(anchor);
+					nodeData = "";
+				}
+
+				if (tinyMCE.getAttrib(path[i], 'name').indexOf("mce_") != 0) {
+					var className = tinyMCE.getVisualAidClass(tinyMCE.getAttrib(path[i], "class"), false);
+					if (className != "" && className.indexOf('mceItem') == -1) {
+						nodeName += "." + className;
+					}
+				}
+
+				var cmd = 'tinyMCE.execInstanceCommand(\'' + editor_id + '\',\'mceSelectNodeDepth\',false,\'' + i + '\');';
+				html += '<a title="' + nodeData + '" href="javascript:' + cmd + '" onclick="' + cmd + 'return false;" onmousedown="return false;" target="_self" class="mcePathItem">' + nodeName + '</a>';
+
+				if (i > 0) {
+					html += " &raquo; ";
+				}
+			}
+
+			pathElm.innerHTML = '<a href="#" accesskey="x"></a>' + tinyMCE.getLang('lang_theme_path') + ": " + html + '&#160;';
+		}
+
+		// Reset old states
+		tinyMCE.switchClass(editor_id + '_justifyleft', 'mceButtonNormal');
+		tinyMCE.switchClass(editor_id + '_justifyright', 'mceButtonNormal');
+		tinyMCE.switchClass(editor_id + '_justifycenter', 'mceButtonNormal');
+		tinyMCE.switchClass(editor_id + '_justifyfull', 'mceButtonNormal');
+		tinyMCE.switchClass(editor_id + '_bold', 'mceButtonNormal');
+		tinyMCE.switchClass(editor_id + '_italic', 'mceButtonNormal');
+		tinyMCE.switchClass(editor_id + '_underline', 'mceButtonNormal');
+		tinyMCE.switchClass(editor_id + '_strikethrough', 'mceButtonNormal');
+		tinyMCE.switchClass(editor_id + '_bullist', 'mceButtonNormal');
+		tinyMCE.switchClass(editor_id + '_numlist', 'mceButtonNormal');
+		tinyMCE.switchClass(editor_id + '_sub', 'mceButtonNormal');
+		tinyMCE.switchClass(editor_id + '_sup', 'mceButtonNormal');
+		tinyMCE.switchClass(editor_id + '_anchor', 'mceButtonNormal');
+		tinyMCE.switchClass(editor_id + '_link', 'mceButtonDisabled');
+		tinyMCE.switchClass(editor_id + '_unlink', 'mceButtonDisabled');
+		tinyMCE.switchClass(editor_id + '_outdent', 'mceButtonDisabled');
+		tinyMCE.switchClass(editor_id + '_image', 'mceButtonNormal');
+		tinyMCE.switchClass(editor_id + '_hr', 'mceButtonNormal');
+
+		if (node.nodeName == "A" && tinyMCE.getAttrib(node, "class").indexOf('mceItemAnchor') != -1)
+			tinyMCE.switchClass(editor_id + '_anchor', 'mceButtonSelected');
+
+		// Get link
+		var anchorLink = tinyMCE.getParentElement(node, "a", "href");
+
+		if (anchorLink || any_selection) {
+			tinyMCE.switchClass(editor_id + '_link', anchorLink ? 'mceButtonSelected' : 'mceButtonNormal');
+			tinyMCE.switchClass(editor_id + '_unlink', anchorLink ? 'mceButtonSelected' : 'mceButtonNormal');
+		}
+
+		// Handle visual aid
+		tinyMCE.switchClass(editor_id + '_visualaid', visual_aid ? 'mceButtonSelected' : 'mceButtonNormal');
+
+		if (undo_levels != -1) {
+			tinyMCE.switchClass(editor_id + '_undo', 'mceButtonDisabled');
+			tinyMCE.switchClass(editor_id + '_redo', 'mceButtonDisabled');
+		}
+
+		// Within li, blockquote
+		if (tinyMCE.getParentElement(node, "li,blockquote"))
+			tinyMCE.switchClass(editor_id + '_outdent', 'mceButtonNormal');
+
+		// Has redo levels
+		if (undo_index != -1 && (undo_index < undo_levels-1 && undo_levels > 0))
+			tinyMCE.switchClass(editor_id + '_redo', 'mceButtonNormal');
+
+		// Has undo levels
+		if (undo_index != -1 && (undo_index > 0 && undo_levels > 0))
+			tinyMCE.switchClass(editor_id + '_undo', 'mceButtonNormal');
+
+		// Select class in select box
+		var selectElm = document.getElementById(editor_id + "_styleSelect");
+		
+		if (selectElm) {
+			TinyMCE_AdvancedTheme._setupCSSClasses(editor_id);
+
+			classNode = node;
+			breakOut = false;
+			var index = 0;
+
+			do {
+				if (classNode && classNode.className) {
+					for (var i=0; i<selectElm.options.length; i++) {
+						if (selectElm.options[i].value == classNode.className) {
+							index = i;
+							breakOut = true;
+							break;
+						}
+					}
+				}
+			} while (!breakOut && classNode != null && (classNode = classNode.parentNode) != null);
+
+			selectElm.selectedIndex = index;
+		}
+
+		// Select formatblock
+		var selectElm = document.getElementById(editor_id + "_formatSelect");
+		if (selectElm) {
+			var elm = tinyMCE.getParentElement(node, "p,div,h1,h2,h3,h4,h5,h6,pre,address");
+
+			if (elm)
+				selectByValue(selectElm, "<" + elm.nodeName.toLowerCase() + ">");
+			else
+				selectByValue(selectElm, "");
+		}
+
+		// Select fontselect
+		var selectElm = document.getElementById(editor_id + "_fontNameSelect");
+		if (selectElm) {
+			if (!tinyMCE.isSafari && !(tinyMCE.isMSIE && !tinyMCE.isOpera)) {
+				var face = inst.queryCommandValue('FontName');
+
+				face = face == null || face == "" ? "" : face;
+
+				selectByValue(selectElm, face, face != "");
+			} else {
+				var elm = tinyMCE.getParentElement(node, "font", "face");
+
+				if (elm) {
+					var family = tinyMCE.getAttrib(elm, "face");
+
+					if (family == '')
+						family = '' + elm.style.fontFamily;
+
+					if (!selectByValue(selectElm, family, family != ""))
+						selectByValue(selectElm, "");
+				} else
+					selectByValue(selectElm, "");
+			}
+		}
+
+		// Select fontsize
+		var selectElm = document.getElementById(editor_id + "_fontSizeSelect");
+		if (selectElm) {
+			if (!tinyMCE.isSafari && !tinyMCE.isOpera) {
+				var size = inst.queryCommandValue('FontSize');
+				selectByValue(selectElm, size == null || size == "" ? "0" : size);
+			} else {
+				var elm = tinyMCE.getParentElement(node, "font", "size");
+				if (elm) {
+					var size = tinyMCE.getAttrib(elm, "size");
+
+					if (size == '') {
+						var sizes = new Array('', '8px', '10px', '12px', '14px', '18px', '24px', '36px');
+
+						size = '' + elm.style.fontSize;
+
+						for (var i=0; i<sizes.length; i++) {
+							if (('' + sizes[i]) == size) {
+								size = i;
+								break;
+							}
+						}
+					}
+
+					if (!selectByValue(selectElm, size))
+						selectByValue(selectElm, "");
+				} else
+					selectByValue(selectElm, "0");
+			}
+		}
+
+		// Handle align attributes
+		alignNode = node;
+		breakOut = false;
+		do {
+			if (!alignNode.getAttribute || !alignNode.getAttribute('align'))
+				continue;
+
+			switch (alignNode.getAttribute('align').toLowerCase()) {
+				case "left":
+					tinyMCE.switchClass(editor_id + '_justifyleft', 'mceButtonSelected');
+					breakOut = true;
+				break;
+
+				case "right":
+					tinyMCE.switchClass(editor_id + '_justifyright', 'mceButtonSelected');
+					breakOut = true;
+				break;
+
+				case "middle":
+				case "center":
+					tinyMCE.switchClass(editor_id + '_justifycenter', 'mceButtonSelected');
+					breakOut = true;
+				break;
+
+				case "justify":
+					tinyMCE.switchClass(editor_id + '_justifyfull', 'mceButtonSelected');
+					breakOut = true;
+				break;
+			}
+		} while (!breakOut && (alignNode = alignNode.parentNode) != null);
+
+		// Div justification
+		var div = tinyMCE.getParentElement(node, "div");
+		if (div && div.style.textAlign == "center")
+			tinyMCE.switchClass(editor_id + '_justifycenter', 'mceButtonSelected');
+
+		// Do special text
+		if (!setup_content) {
+			// , "JustifyLeft", "_justifyleft", "JustifyCenter", "justifycenter", "JustifyRight", "justifyright", "JustifyFull", "justifyfull", "InsertUnorderedList", "bullist", "InsertOrderedList", "numlist", "InsertUnorderedList", "bullist", "Outdent", "outdent", "Indent", "indent", "subscript", "sub"
+			var ar = new Array("Bold", "_bold", "Italic", "_italic", "Strikethrough", "_strikethrough", "superscript", "_sup", "subscript", "_sub");
+			for (var i=0; i<ar.length; i+=2) {
+				if (inst.queryCommandState(ar[i]))
+					tinyMCE.switchClass(editor_id + ar[i+1], 'mceButtonSelected');
+			}
+
+			if (inst.queryCommandState("Underline") && (node.parentNode == null || node.parentNode.nodeName != "A"))
+				tinyMCE.switchClass(editor_id + '_underline', 'mceButtonSelected');
+		}
+
+		// Handle elements
+		do {
+			switch (node.nodeName) {
+				case "UL":
+					tinyMCE.switchClass(editor_id + '_bullist', 'mceButtonSelected');
+				break;
+
+				case "OL":
+					tinyMCE.switchClass(editor_id + '_numlist', 'mceButtonSelected');
+				break;
+
+				case "HR":
+					 tinyMCE.switchClass(editor_id + '_hr', 'mceButtonSelected');
+				break;
+
+				case "IMG":
+				if (tinyMCE.getAttrib(node, 'name').indexOf('mce_') != 0 && tinyMCE.getAttrib(node, 'class').indexOf('mceItem') == -1) {
+					tinyMCE.switchClass(editor_id + '_image', 'mceButtonSelected');
+				}
+				break;
+			}
+		} while ((node = node.parentNode) != null);
+	},
+
+	// Private theme internal functions
+
+	// This function auto imports CSS classes into the class selection droplist
+	_setupCSSClasses : function(editor_id) {
+		var i, selectElm;
+
+		if (!TinyMCE_AdvancedTheme._autoImportCSSClasses)
+			return;
+
+		selectElm = document.getElementById(editor_id + '_styleSelect');
+
+		if (selectElm && selectElm.getAttribute('cssImported') != 'true') {
+			var csses = tinyMCE.getCSSClasses(editor_id);
+			if (csses && selectElm)	{
+				for (i=0; i<csses.length; i++)
+					selectElm.options[selectElm.options.length] = new Option(csses[i], csses[i]);
+			}
+
+			// Only do this once
+			if (csses != null && csses.length > 0)
+				selectElm.setAttribute('cssImported', 'true');
+		}
+	},
+
+	_setCookie : function(name, value, expires, path, domain, secure) {
+		var curCookie = name + "=" + escape(value) +
+			((expires) ? "; expires=" + expires.toGMTString() : "") +
+			((path) ? "; path=" + escape(path) : "") +
+			((domain) ? "; domain=" + domain : "") +
+			((secure) ? "; secure" : "");
+
+		document.cookie = curCookie;
+	},
+
+	_getCookie : function(name) {
+		var dc = document.cookie;
+		var prefix = name + "=";
+		var begin = dc.indexOf("; " + prefix);
+
+		if (begin == -1) {
+			begin = dc.indexOf(prefix);
+
+			if (begin != 0)
+				return null;
+		} else
+			begin += 2;
+
+		var end = document.cookie.indexOf(";", begin);
+
+		if (end == -1)
+			end = dc.length;
+
+		return unescape(dc.substring(begin + prefix.length, end));
+	},
+
+	_resizeTo : function(inst, w, h, set_w) {
+		var editorContainer = document.getElementById(inst.editorId + '_parent');
+		var tableElm = editorContainer.firstChild;
+		var iframe = inst.iframeElement;
+
+		if (w == null || w == "null") {
+			set_w = false;
+			w = 0;
+		}
+
+		if (h == null || h == "null")
+			return;
+
+		w = parseInt(w);
+		h = parseInt(h);
+
+		if (tinyMCE.isGecko) {
+			w += 2;
+			h += 2;
+		}
+
+		var dx = w - tableElm.clientWidth;
+		var dy = h - tableElm.clientHeight;
+
+		w = w < 1 ? 30 : w;
+		h = h < 1 ? 30 : h;
+
+		if (set_w)
+			tableElm.style.width = w + "px";
+
+		tableElm.style.height = h + "px";
+
+		iw = iframe.clientWidth + dx;
+		ih = iframe.clientHeight + dy;
+
+		iw = iw < 1 ? 30 : iw;
+		ih = ih < 1 ? 30 : ih;
+
+		if (tinyMCE.isGecko) {
+			iw -= 2;
+			ih -= 2;
+		}
+
+		if (set_w)
+			iframe.style.width = iw + "px";
+
+		iframe.style.height = ih + "px";
+
+		// Is it to small, make it bigger again
+		if (set_w) {
+			var tableBodyElm = tableElm.firstChild;
+			var minIframeWidth = tableBodyElm.scrollWidth;
+			if (inst.iframeElement.clientWidth < minIframeWidth) {
+				dx = minIframeWidth - inst.iframeElement.clientWidth;
+
+				inst.iframeElement.style.width = (iw + dx) + "px";
+			}
+		}
+
+		// Remove pesky table controls
+		inst.useCSS = false;
+	},
+
+	/**
+	 * Handles resizing events.
+	 */
+	_resizeEventHandler : function(e) {
+		var resizer = TinyMCE_AdvancedTheme._resizer;
+
+		// Do nothing
+		if (!resizer.resizing)
+			return;
+
+		e = typeof(e) == "undefined" ? window.event : e;
+
+		var dx = e.screenX - resizer.downX;
+		var dy = e.screenY - resizer.downY;
+		var resizeBox = resizer.resizeBox;
+		var editorId = resizer.editorId;
+
+		switch (e.type) {
+			case "mousemove":
+				var w, h;
+
+				w = resizer.width + dx;
+				h = resizer.height + dy;
+
+				w = w < 1 ? 1 : w;
+				h = h < 1 ? 1 : h;
+
+				if (resizer.horizontal)
+					resizeBox.style.width = w + "px";
+
+				resizeBox.style.height = h + "px";
+				break;
+
+			case "mouseup":
+				TinyMCE_AdvancedTheme._setResizing(e, editorId, false);
+				TinyMCE_AdvancedTheme._resizeTo(tinyMCE.getInstanceById(editorId), resizer.width + dx, resizer.height + dy, resizer.horizontal);
+
+				// Expire in a month
+				if (tinyMCE.getParam("theme_advanced_resizing_use_cookie", true)) {
+					var expires = new Date();
+					expires.setTime(expires.getTime() + 3600000 * 24 * 30);
+
+					// Set the cookies
+					TinyMCE_AdvancedTheme._setCookie("TinyMCE_" + editorId + "_width", "" + (resizer.horizontal ? resizer.width + dx : ""), expires);
+					TinyMCE_AdvancedTheme._setCookie("TinyMCE_" + editorId + "_height", "" + (resizer.height + dy), expires);
+				}
+				break;
+		}
+	},
+
+	/**
+	 * Starts/stops the editor resizing.
+	 */
+	_setResizing : function(e, editor_id, state) {
+		e = typeof(e) == "undefined" ? window.event : e;
+
+		var resizer = TinyMCE_AdvancedTheme._resizer;
+		var editorContainer = document.getElementById(editor_id + '_parent');
+		var editorArea = document.getElementById(editor_id + '_parent').firstChild;
+		var resizeBox = document.getElementById(editor_id + '_resize_box');
+		var inst = tinyMCE.getInstanceById(editor_id);
+
+		if (state) {
+			// Place box over editor area
+			var width = editorArea.clientWidth;
+			var height = editorArea.clientHeight;
+
+			resizeBox.style.width = width + "px";
+			resizeBox.style.height = height + "px";
+
+			resizer.iframeWidth = inst.iframeElement.clientWidth;
+			resizer.iframeHeight = inst.iframeElement.clientHeight;
+
+			// Hide editor and show resize box
+			editorArea.style.display = "none";
+			resizeBox.style.display = "block";
+
+			// Add event handlers, only once
+			if (!resizer.eventHandlers) {
+				if (tinyMCE.isMSIE)
+					tinyMCE.addEvent(document, "mousemove", TinyMCE_AdvancedTheme._resizeEventHandler);
+				else
+					tinyMCE.addEvent(window, "mousemove", TinyMCE_AdvancedTheme._resizeEventHandler);
+
+				tinyMCE.addEvent(document, "mouseup", TinyMCE_AdvancedTheme._resizeEventHandler);
+
+				resizer.eventHandlers = true;
+			}
+
+			resizer.resizing = true;
+			resizer.downX = e.screenX;
+			resizer.downY = e.screenY;
+			resizer.width = parseInt(resizeBox.style.width);
+			resizer.height = parseInt(resizeBox.style.height);
+			resizer.editorId = editor_id;
+			resizer.resizeBox = resizeBox;
+			resizer.horizontal = tinyMCE.getParam("theme_advanced_resize_horizontal", true);
+		} else {
+			resizer.resizing = false;
+			resizeBox.style.display = "none";
+			editorArea.style.display = tinyMCE.isMSIE && !tinyMCE.isOpera ? "block" : "table";
+			tinyMCE.execCommand('mceResetDesignMode');
+		}
+	},
+
+	_getColorHTML : function(id, n, cm) {
+		var i, h, cl;
+
+		h = '<span class="mceMenuLine"></span>';
+		cl = tinyMCE.getParam(n, TinyMCE_AdvancedTheme._defColors).split(',');
+
+		h += '<table class="mceColors"><tr>';
+		for (i=0; i<cl.length; i++) {
+			c = 'tinyMCE.execInstanceCommand(\'' + id + '\', \'' + cm + '\', false, \'#' + cl[i] + '\');';
+			h += '<td><a href="javascript:' + c + '" style="background-color: #' + cl[i] + '" onclick="' + c + ';return false;"></a></td>';
+
+			if ((i+1) % 8 == 0)
+				h += '</tr><tr>';
+		}
+
+		h += '</tr></table>';
+
+		if (tinyMCE.getParam("theme_advanced_more_colors", true))
+			h += '<a href="#" onclick="TinyMCE_AdvancedTheme._pickColor(\'' + id + '\',\'' + cm + '\');" class="mceMoreColors">' + tinyMCE.getLang('lang_more_colors') + '</a>';
+
+		return h;
+	},
+
+	_pickColor : function(id, cm) {
+		var inputColor, inst = tinyMCE.selectedInstance;
+
+		if (cm == 'forecolor' && inst)
+			inputColor = inst.foreColor;
+
+		if ((cm == 'backcolor' || cm == 'HiliteColor') && inst)
+			inputColor = inst.backColor;
+
+		tinyMCE.execCommand('mceColorPicker', true, {color : inputColor, callback : function(c) {
+			tinyMCE.execInstanceCommand(id, cm, false, c);
+		}});
+	},
+
+	_insertImage : function(src, alt, border, hspace, vspace, width, height, align, title, onmouseover, onmouseout) {
+		tinyMCE.execCommand('mceBeginUndoLevel');
+
+		if (src == "")
+			return;
+
+		if (!tinyMCE.imgElement && tinyMCE.isSafari) {
+			var html = "";
+
+			html += '<img src="' + src + '" alt="' + alt + '"';
+			html += ' border="' + border + '" hspace="' + hspace + '"';
+			html += ' vspace="' + vspace + '" width="' + width + '"';
+			html += ' height="' + height + '" align="' + align + '" title="' + title + '" onmouseover="' + onmouseover + '" onmouseout="' + onmouseout + '" />';
+
+			tinyMCE.execCommand("mceInsertContent", false, html);
+		} else {
+			if (!tinyMCE.imgElement && tinyMCE.selectedInstance) {
+				if (tinyMCE.isSafari)
+					tinyMCE.execCommand("mceInsertContent", false, '<img src="' + tinyMCE.uniqueURL + '" />');
+				else
+					tinyMCE.selectedInstance.contentDocument.execCommand("insertimage", false, tinyMCE.uniqueURL);
+
+				tinyMCE.imgElement = tinyMCE.getElementByAttributeValue(tinyMCE.selectedInstance.contentDocument.body, "img", "src", tinyMCE.uniqueURL);
+			}
+		}
+
+		if (tinyMCE.imgElement) {
+			var needsRepaint = false;
+			var msrc = src;
+
+			src = eval(tinyMCE.settings['urlconverter_callback'] + "(src, tinyMCE.imgElement);");
+
+			if (tinyMCE.getParam('convert_urls'))
+				msrc = src;
+
+			if (onmouseover && onmouseover != "")
+				onmouseover = "this.src='" + eval(tinyMCE.settings['urlconverter_callback'] + "(onmouseover, tinyMCE.imgElement);") + "';";
+
+			if (onmouseout && onmouseout != "")
+				onmouseout = "this.src='" + eval(tinyMCE.settings['urlconverter_callback'] + "(onmouseout, tinyMCE.imgElement);") + "';";
+
+			// Use alt as title if it's undefined
+			if (typeof(title) == "undefined")
+				title = alt;
+
+			if (width != tinyMCE.imgElement.getAttribute("width") || height != tinyMCE.imgElement.getAttribute("height") || align != tinyMCE.imgElement.getAttribute("align"))
+				needsRepaint = true;
+
+			tinyMCE.setAttrib(tinyMCE.imgElement, 'src', src);
+			tinyMCE.setAttrib(tinyMCE.imgElement, 'mce_src', msrc);
+			tinyMCE.setAttrib(tinyMCE.imgElement, 'alt', alt);
+			tinyMCE.setAttrib(tinyMCE.imgElement, 'title', title);
+			tinyMCE.setAttrib(tinyMCE.imgElement, 'align', align);
+			tinyMCE.setAttrib(tinyMCE.imgElement, 'border', border, true);
+			tinyMCE.setAttrib(tinyMCE.imgElement, 'hspace', hspace, true);
+			tinyMCE.setAttrib(tinyMCE.imgElement, 'vspace', vspace, true);
+			tinyMCE.setAttrib(tinyMCE.imgElement, 'width', width, true);
+			tinyMCE.setAttrib(tinyMCE.imgElement, 'height', height, true);
+			tinyMCE.setAttrib(tinyMCE.imgElement, 'onmouseover', onmouseover);
+			tinyMCE.setAttrib(tinyMCE.imgElement, 'onmouseout', onmouseout);
+
+			// Fix for bug #989846 - Image resize bug
+			if (width && width != "")
+				tinyMCE.imgElement.style.pixelWidth = width;
+
+			if (height && height != "")
+				tinyMCE.imgElement.style.pixelHeight = height;
+
+			if (needsRepaint)
+				tinyMCE.selectedInstance.repaint();
+		}
+
+		tinyMCE.execCommand('mceEndUndoLevel');
+	},
+
+	_insertLink : function(href, target, title, onclick, style_class) {
+		tinyMCE.execCommand('mceBeginUndoLevel');
+
+		if (tinyMCE.selectedInstance && tinyMCE.selectedElement && tinyMCE.selectedElement.nodeName.toLowerCase() == "img") {
+			var doc = tinyMCE.selectedInstance.getDoc();
+			var linkElement = tinyMCE.getParentElement(tinyMCE.selectedElement, "a");
+			var newLink = false;
+
+			if (!linkElement) {
+				linkElement = doc.createElement("a");
+				newLink = true;
+			}
+
+			var mhref = href;
+			var thref = eval(tinyMCE.settings['urlconverter_callback'] + "(href, linkElement);");
+			mhref = tinyMCE.getParam('convert_urls') ? href : mhref;
+
+			tinyMCE.setAttrib(linkElement, 'href', thref);
+			tinyMCE.setAttrib(linkElement, 'mce_href', mhref);
+			tinyMCE.setAttrib(linkElement, 'target', target);
+			tinyMCE.setAttrib(linkElement, 'title', title);
+			tinyMCE.setAttrib(linkElement, 'onclick', onclick);
+			tinyMCE.setAttrib(linkElement, 'class', style_class);
+
+			if (newLink) {
+				linkElement.appendChild(tinyMCE.selectedElement.cloneNode(true));
+				tinyMCE.selectedElement.parentNode.replaceChild(linkElement, tinyMCE.selectedElement);
+			}
+
+			return;
+		}
+
+		if (!tinyMCE.linkElement && tinyMCE.selectedInstance) {
+			if (tinyMCE.isSafari) {
+				tinyMCE.execCommand("mceInsertContent", false, '<a href="' + tinyMCE.uniqueURL + '">' + tinyMCE.selectedInstance.selection.getSelectedHTML() + '</a>');
+			} else
+				tinyMCE.selectedInstance.contentDocument.execCommand("createlink", false, tinyMCE.uniqueURL);
+
+			tinyMCE.linkElement = tinyMCE.getElementByAttributeValue(tinyMCE.selectedInstance.contentDocument.body, "a", "href", tinyMCE.uniqueURL);
+
+			var elementArray = tinyMCE.getElementsByAttributeValue(tinyMCE.selectedInstance.contentDocument.body, "a", "href", tinyMCE.uniqueURL);
+
+			for (var i=0; i<elementArray.length; i++) {
+				var mhref = href;
+				var thref = eval(tinyMCE.settings['urlconverter_callback'] + "(href, elementArray[i]);");
+				mhref = tinyMCE.getParam('convert_urls') ? href : mhref;
+
+				tinyMCE.setAttrib(elementArray[i], 'href', thref);
+				tinyMCE.setAttrib(elementArray[i], 'mce_href', mhref);
+				tinyMCE.setAttrib(elementArray[i], 'target', target);
+				tinyMCE.setAttrib(elementArray[i], 'title', title);
+				tinyMCE.setAttrib(elementArray[i], 'onclick', onclick);
+				tinyMCE.setAttrib(elementArray[i], 'class', style_class);
+			}
+
+			tinyMCE.linkElement = elementArray[0];
+		}
+
+		if (tinyMCE.linkElement) {
+			var mhref = href;
+			href = eval(tinyMCE.settings['urlconverter_callback'] + "(href, tinyMCE.linkElement);");
+			mhref = tinyMCE.getParam('convert_urls') ? href : mhref;
+
+			tinyMCE.setAttrib(tinyMCE.linkElement, 'href', href);
+			tinyMCE.setAttrib(tinyMCE.linkElement, 'mce_href', mhref);
+			tinyMCE.setAttrib(tinyMCE.linkElement, 'target', target);
+			tinyMCE.setAttrib(tinyMCE.linkElement, 'title', title);
+			tinyMCE.setAttrib(tinyMCE.linkElement, 'onclick', onclick);
+			tinyMCE.setAttrib(tinyMCE.linkElement, 'class', style_class);
+		}
+
+		tinyMCE.execCommand('mceEndUndoLevel');
+	}
+};
+
+tinyMCE.addTheme("advanced", TinyMCE_AdvancedTheme);
+
+// Add default buttons maps for advanced theme and all internal plugins
+tinyMCE.addButtonMap(TinyMCE_AdvancedTheme._buttonMap);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/themes/advanced/image.htm	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,100 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>{$lang_insert_image_title}</title>
+	<script language="javascript" type="text/javascript" src="../../tiny_mce_popup.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/mctabs.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/form_utils.js"></script>
+	<script language="javascript" type="text/javascript" src="jscripts/image.js"></script>
+	<base target="_self" />
+</head>
+<body id="image" onload="tinyMCEPopup.executeOnLoad('init();');" style="display: none">
+<form onsubmit="insertImage();return false;" action="#">
+	<div class="tabs">
+		<ul>
+			<li id="general_tab" class="current"><span><a href="javascript:mcTabs.displayTab('general_tab','general_panel');" onmousedown="return false;">{$lang_insert_image_title}</a></span></li>
+		</ul>
+	</div>
+
+	<div class="panel_wrapper">
+		<div id="general_panel" class="panel current">
+     <table border="0" cellpadding="4" cellspacing="0">
+          <tr>
+            <td nowrap="nowrap"><label for="src">{$lang_insert_image_src}</label></td>
+            <td><table border="0" cellspacing="0" cellpadding="0">
+                <tr>
+                  <td><input id="src" name="src" type="text" value="" style="width: 200px" onchange="getImageData();"></td>
+                  <td id="srcbrowsercontainer">&nbsp;</td>
+                </tr>
+              </table></td>
+          </tr>
+		  <!-- Image list -->
+		  <script language="javascript">
+			if (typeof(tinyMCEImageList) != "undefined" && tinyMCEImageList.length > 0) {
+				var html = "";
+
+				html += '<tr><td><label for="image_list">{$lang_image_list}</label></td>';
+				html += '<td><select id="image_list" name="image_list" style="width: 200px" onchange="this.form.src.value=this.options[this.selectedIndex].value;resetImageData();getImageData();">';
+				html += '<option value="">---</option>';
+
+				for (var i=0; i<tinyMCEImageList.length; i++)
+					html += '<option value="' + tinyMCEImageList[i][1] + '">' + tinyMCEImageList[i][0] + '</option>';
+
+				html += '</select></td></tr>';
+
+				document.write(html);
+			}
+		  </script>
+		  <!-- /Image list -->
+          <tr>
+            <td nowrap="nowrap"><label for="alt">{$lang_insert_image_alt}</label></td>
+            <td><input id="alt" name="alt" type="text" value="" style="width: 200px"></td>
+          </tr>
+          <tr>
+            <td nowrap="nowrap"><label for="align">{$lang_insert_image_align}</label></td>
+            <td><select id="align" name="align">
+                <option value="">{$lang_insert_image_align_default}</option>
+                <option value="baseline">{$lang_insert_image_align_baseline}</option>
+                <option value="top">{$lang_insert_image_align_top}</option>
+                <option value="middle">{$lang_insert_image_align_middle}</option>
+                <option value="bottom">{$lang_insert_image_align_bottom}</option>
+                <option value="texttop">{$lang_insert_image_align_texttop}</option>
+                <option value="absmiddle">{$lang_insert_image_align_absmiddle}</option>
+                <option value="absbottom">{$lang_insert_image_align_absbottom}</option>
+                <option value="left">{$lang_insert_image_align_left}</option>
+                <option value="right">{$lang_insert_image_align_right}</option>
+              </select></td>
+          </tr>
+          <tr>
+            <td nowrap="nowrap"><label for="width">{$lang_insert_image_dimensions}</label></td>
+            <td><input id="width" name="width" type="text" value="" size="3" maxlength="3">
+              x
+              <input id="height" name="height" type="text" value="" size="3" maxlength="3"></td>
+          </tr>
+          <tr>
+            <td nowrap="nowrap"><label for="border">{$lang_insert_image_border}</label></td>
+            <td><input id="border" name="border" type="text" value="" size="3" maxlength="3"></td>
+          </tr>
+          <tr>
+            <td nowrap="nowrap"><label for="vspace">{$lang_insert_image_vspace}</label></td>
+            <td><input id="vspace" name="vspace" type="text" value="" size="3" maxlength="3"></td>
+          </tr>
+          <tr>
+            <td nowrap="nowrap"><label for="hspace">{$lang_insert_image_hspace}</label></td>
+            <td><input id="hspace" name="hspace" type="text" value="" size="3" maxlength="3"></td>
+          </tr>
+        </table>
+		</div>
+	</div>
+
+	<div class="mceActionPanel">
+		<div style="float: left">
+			<input type="button" id="insert" name="insert" value="{$lang_insert}" onclick="insertImage();" />
+		</div>
+
+		<div style="float: right">
+			<input type="button" id="cancel" name="cancel" value="{$lang_cancel}" onclick="tinyMCEPopup.close();" />
+		</div>
+	</div>
+</form>
+</body>
+</html>
Binary file includes/clientside/tinymce/themes/advanced/images/anchor.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/anchor_symbol.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/backcolor.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/bold.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/bold_de_se.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/bold_es.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/bold_fr.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/bold_ru.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/bold_tw.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/browse.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/bullist.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/button_menu.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/buttons.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/cancel_button_bg.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/charmap.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/cleanup.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/close.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/code.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/color.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/colors.jpg has changed
Binary file includes/clientside/tinymce/themes/advanced/images/copy.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/custom_1.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/cut.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/forecolor.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/help.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/hr.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/image.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/indent.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/insert_button_bg.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/italic.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/italic_de_se.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/italic_es.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/italic_ru.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/italic_tw.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/justifycenter.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/justifyfull.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/justifyleft.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/justifyright.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/link.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/menu_check.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/newdocument.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/numlist.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/opacity.png has changed
Binary file includes/clientside/tinymce/themes/advanced/images/outdent.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/paste.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/redo.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/removeformat.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/separator.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/spacer.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/statusbar_resize.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/strikethrough.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/sub.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/sup.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/underline.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/underline_es.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/underline_fr.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/underline_ru.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/underline_tw.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/undo.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/unlink.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/visualaid.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/xp/tab_bg.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/xp/tab_end.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/xp/tab_sel_bg.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/xp/tab_sel_end.gif has changed
Binary file includes/clientside/tinymce/themes/advanced/images/xp/tabs_bg.gif has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/themes/advanced/jscripts/about.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,75 @@
+function init() {
+	var inst;
+
+	tinyMCEPopup.resizeToInnerSize();
+	inst = tinyMCE.selectedInstance;
+
+	// Give FF some time
+	window.setTimeout('insertHelpIFrame();', 10);
+
+	var tcont = document.getElementById('plugintablecontainer');
+	var plugins = tinyMCE.getParam('plugins', '', true, ',');
+	if (plugins.length == 0)
+		document.getElementById('plugins_tab').style.display = 'none';
+
+	var html = "";
+	html += '<table id="plugintable">';
+	html += '<thead>';
+	html += '<tr>';
+	html += '<td>' + tinyMCE.getLang('lang_plugin') + '</td>';
+	html += '<td>' + tinyMCE.getLang('lang_author') + '</td>';
+	html += '<td>' + tinyMCE.getLang('lang_version') + '</td>';
+	html += '</tr>';
+	html += '</thead>';
+	html += '<tbody>';
+
+	for (var i=0; i<inst.plugins.length; i++) {
+		var info = getPluginInfo(inst.plugins[i]);
+
+		html += '<tr>';
+
+		if (info.infourl != null && info.infourl != '')
+			html += '<td width="50%" title="' + plugins[i] + '"><a href="' + info.infourl + '" target="mceplugin">' + info.longname + '</a></td>';
+		else
+			html += '<td width="50%" title="' + plugins[i] + '">' + info.longname + '</td>';
+
+		if (info.authorurl != null && info.authorurl != '')
+			html += '<td width="35%"><a href="' + info.authorurl + '" target="mceplugin">' + info.author + '</a></td>';
+		else
+			html += '<td width="35%">' + info.author + '</td>';
+
+		html += '<td width="15%">' + info.version + '</td>';
+		html += '</tr>';
+	}
+
+	html += '</tbody>';
+	html += '</table>';
+
+	tcont.innerHTML = html;
+}
+
+function getPluginInfo(name) {
+	if (tinyMCE.plugins[name].getInfo)
+		return tinyMCE.plugins[name].getInfo();
+
+	return {
+		longname : name,
+		authorurl : '',
+		infourl : '',
+		author : '--',
+		version : '--'
+	};
+}
+
+function insertHelpIFrame() {
+	var html = '<iframe width="100%" height="300" src="' + tinyMCE.themeURL + "/docs/" + tinyMCE.settings['docs_language'] + "/index.htm" + '"></iframe>';
+
+	document.getElementById('iframecontainer').innerHTML = html;
+
+	html = '';
+	html += '<a href="http://www.moxiecode.com" target="_blank"><img src="http://tinymce.moxiecode.com/images/gotmoxie.png" alt="Got Moxie?" border="0" /></a> ';
+	html += '<a href="http://sourceforge.net/projects/tinymce/" target="_blank"><img src="http://sourceforge.net/sflogo.php?group_id=103281" alt="Hosted By Sourceforge" border="0" /></a> ';
+	html += '<a href="http://www.freshmeat.net/projects/tinymce" target="_blank"><img src="http://tinymce.moxiecode.com/images/fm.gif" alt="Also on freshmeat" border="0" /></a> ';
+
+	document.getElementById('buttoncontainer').innerHTML = html;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/themes/advanced/jscripts/anchor.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,74 @@
+var action, element;
+
+function init() {
+	tinyMCEPopup.resizeToInnerSize();
+
+	var inst = tinyMCE.getInstanceById(tinyMCE.getWindowArg('editor_id'));
+	var anchor = tinyMCE.getParentElement(inst.getFocusElement(), "a", "name");
+	var img = inst.getFocusElement();
+	action = 'insert';
+
+	if (anchor != null) {
+		element = anchor;
+		action = "update";
+	}
+
+	if (tinyMCE.getAttrib(img, "class") == "mceItemAnchor") {
+		element = img;
+		action = "update";
+	}
+
+	if (action == "update")
+		document.forms[0].anchorName.value = element.nodeName == "IMG" ? element.getAttribute("title") : element.getAttribute("name");
+
+	document.forms[0].insert.value = tinyMCE.getLang('lang_' + action, 'Insert', true);
+}
+
+function insertAnchor() {
+	var inst = tinyMCE.getInstanceById(tinyMCE.getWindowArg('editor_id'));
+	var name = document.forms[0].anchorName.value, e;
+
+	tinyMCEPopup.execCommand("mceBeginUndoLevel");
+
+	if (action == "update") {
+		if (element.nodeName == "IMG")
+			element.setAttribute("title", name);
+		else
+			element.setAttribute("name", name);
+	} else {
+		var rng = inst.getRng();
+
+		if (rng.collapse)
+			rng.collapse(false);
+
+		name = name.replace(/&/g, '&amp;');
+		name = name.replace(/\"/g, '&quot;');
+		name = name.replace(/</g, '&lt;');
+		name = name.replace(/>/g, '&gt;');
+
+		// Fix for bug #1447335
+		if (tinyMCE.isGecko)
+			html = '<a id="mceNewAnchor" name="' + name + '"></a>';
+		else
+			html = '<a name="' + name + '"></a>';
+
+		tinyMCEPopup.execCommand("mceInsertContent", false, html);
+
+		// Fix for bug #1447335 force cursor after the anchor element
+		if (tinyMCE.isGecko) {
+			e = inst.getDoc().getElementById('mceNewAnchor');
+
+			if (e) {
+				inst.selection.selectNode(e, true, false, false);
+				e.removeAttribute('id');
+			}
+		}
+
+		tinyMCE.handleVisualAid(inst.getBody(), true, inst.visualAid, inst);
+	}
+
+	tinyMCEPopup.execCommand("mceEndUndoLevel");
+
+	tinyMCE.triggerNodeChange();
+	tinyMCEPopup.close();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/themes/advanced/jscripts/charmap.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,326 @@
+function init() {
+	tinyMCEPopup.resizeToInnerSize();
+}
+
+var charmap = new Array();
+
+// for mor details please see w3c.org
+// now here is the complete list ;)
+
+charmap = [
+	['&nbsp;',    '&#160;',  true, 'no-break space'],
+	['&amp;',     '&#38;',   true, 'ampersand'],
+	['&quot;',    '&#34;',   true, 'quotation mark'],
+// finance
+	['&cent;',    '&#162;',  true, 'cent sign'],
+	['&euro;',    '&#8364;', true, 'euro sign'],
+	['&pound;',   '&#163;',  true, 'pound sign'],
+	['&yen;',     '&#165;',  true, 'yen sign'],
+// signs
+	['&copy;',    '&#169;',  true, 'copyright sign'],
+	['&reg;',     '&#174;',  true, 'registered sign'],
+	['&trade;',   '&#8482;', true, 'trade mark sign'],
+	['&permil;',  '&#8240;', true, 'per mille sign'],
+	['&micro;',   '&#181;',  true, 'micro sign'],
+	['&middot;',  '&#183;',  true, 'middle dot'],
+	['&bull;',    '&#8226;', true, 'bullet'],
+	['&hellip;',  '&#8230;', true, 'three dot leader'],
+	['&prime;',   '&#8242;', true, 'minutes / feet'],
+	['&Prime;',   '&#8243;', true, 'seconds / inches'],
+	['&sect;',    '&#167;',  true, 'section sign'],
+	['&para;',    '&#182;',  true, 'paragraph sign'],
+	['&szlig;',   '&#223;',  true, 'sharp s / ess-zed'],
+// quotations
+	['&lsaquo;',  '&#8249;', true, 'single left-pointing angle quotation mark'],
+	['&rsaquo;',  '&#8250;', true, 'single right-pointing angle quotation mark'],
+	['&laquo;',   '&#171;',  true, 'left pointing guillemet'],
+	['&raquo;',   '&#187;',  true, 'right pointing guillemet'],
+	['&lsquo;',   '&#8216;', true, 'left single quotation mark'],
+	['&rsquo;',   '&#8217;', true, 'right single quotation mark'],
+	['&ldquo;',   '&#8220;', true, 'left double quotation mark'],
+	['&rdquo;',   '&#8221;', true, 'right double quotation mark'],
+	['&sbquo;',   '&#8218;', true, 'single low-9 quotation mark'],
+	['&bdquo;',   '&#8222;', true, 'double low-9 quotation mark'],
+	['&lt;',      '&#60;',   true, 'less-than sign'],
+	['&gt;',      '&#62;',   true, 'greater-than sign'],
+	['&le;',      '&#8804;', true, 'less-than or equal to'],
+	['&ge;',      '&#8805;', true, 'greater-than or equal to'],
+	['&ndash;',   '&#8211;', true, 'en dash'],
+	['&mdash;',   '&#8212;', true, 'em dash'],
+	['&macr;',    '&#175;',  true, 'macron'],
+	['&oline;',   '&#8254;', true, 'overline'],
+	['&curren;',  '&#164;',  true, 'currency sign'],
+	['&brvbar;',  '&#166;',  true, 'broken bar'],
+	['&uml;',     '&#168;',  true, 'diaeresis'],
+	['&iexcl;',   '&#161;',  true, 'inverted exclamation mark'],
+	['&iquest;',  '&#191;',  true, 'turned question mark'],
+	['&circ;',    '&#710;',  true, 'circumflex accent'],
+	['&tilde;',   '&#732;',  true, 'small tilde'],
+	['&deg;',     '&#176;',  true, 'degree sign'],
+	['&minus;',   '&#8722;', true, 'minus sign'],
+	['&plusmn;',  '&#177;',  true, 'plus-minus sign'],
+	['&divide;',  '&#247;',  true, 'division sign'],
+	['&frasl;',   '&#8260;', true, 'fraction slash'],
+	['&times;',   '&#215;',  true, 'multiplication sign'],
+	['&sup1;',    '&#185;',  true, 'superscript one'],
+	['&sup2;',    '&#178;',  true, 'superscript two'],
+	['&sup3;',    '&#179;',  true, 'superscript three'],
+	['&frac14;',  '&#188;',  true, 'fraction one quarter'],
+	['&frac12;',  '&#189;',  true, 'fraction one half'],
+	['&frac34;',  '&#190;',  true, 'fraction three quarters'],
+// math / logical
+	['&fnof;',    '&#402;',  true, 'function / florin'],
+	['&int;',     '&#8747;', true, 'integral'],
+	['&sum;',     '&#8721;', true, 'n-ary sumation'],
+	['&infin;',   '&#8734;', true, 'infinity'],
+	['&radic;',   '&#8730;', true, 'square root'],
+	['&sim;',     '&#8764;', false,'similar to'],
+	['&cong;',    '&#8773;', false,'approximately equal to'],
+	['&asymp;',   '&#8776;', true, 'almost equal to'],
+	['&ne;',      '&#8800;', true, 'not equal to'],
+	['&equiv;',   '&#8801;', true, 'identical to'],
+	['&isin;',    '&#8712;', false,'element of'],
+	['&notin;',   '&#8713;', false,'not an element of'],
+	['&ni;',      '&#8715;', false,'contains as member'],
+	['&prod;',    '&#8719;', true, 'n-ary product'],
+	['&and;',     '&#8743;', false,'logical and'],
+	['&or;',      '&#8744;', false,'logical or'],
+	['&not;',     '&#172;',  true, 'not sign'],
+	['&cap;',     '&#8745;', true, 'intersection'],
+	['&cup;',     '&#8746;', false,'union'],
+	['&part;',    '&#8706;', true, 'partial differential'],
+	['&forall;',  '&#8704;', false,'for all'],
+	['&exist;',   '&#8707;', false,'there exists'],
+	['&empty;',   '&#8709;', false,'diameter'],
+	['&nabla;',   '&#8711;', false,'backward difference'],
+	['&lowast;',  '&#8727;', false,'asterisk operator'],
+	['&prop;',    '&#8733;', false,'proportional to'],
+	['&ang;',     '&#8736;', false,'angle'],
+// undefined
+	['&acute;',   '&#180;',  true, 'acute accent'],
+	['&cedil;',   '&#184;',  true, 'cedilla'],
+	['&ordf;',    '&#170;',  true, 'feminine ordinal indicator'],
+	['&ordm;',    '&#186;',  true, 'masculine ordinal indicator'],
+	['&dagger;',  '&#8224;', true, 'dagger'],
+	['&Dagger;',  '&#8225;', true, 'double dagger'],
+// alphabetical special chars
+	['&Agrave;',  '&#192;',  true, 'A - grave'],
+	['&Aacute;',  '&#193;',  true, 'A - acute'],
+	['&Acirc;',   '&#194;',  true, 'A - circumflex'],
+	['&Atilde;',  '&#195;',  true, 'A - tilde'],
+	['&Auml;',    '&#196;',  true, 'A - diaeresis'],
+	['&Aring;',   '&#197;',  true, 'A - ring above'],
+	['&AElig;',   '&#198;',  true, 'ligature AE'],
+	['&Ccedil;',  '&#199;',  true, 'C - cedilla'],
+	['&Egrave;',  '&#200;',  true, 'E - grave'],
+	['&Eacute;',  '&#201;',  true, 'E - acute'],
+	['&Ecirc;',   '&#202;',  true, 'E - circumflex'],
+	['&Euml;',    '&#203;',  true, 'E - diaeresis'],
+	['&Igrave;',  '&#204;',  true, 'I - grave'],
+	['&Iacute;',  '&#205;',  true, 'I - acute'],
+	['&Icirc;',   '&#206;',  true, 'I - circumflex'],
+	['&Iuml;',    '&#207;',  true, 'I - diaeresis'],
+	['&ETH;',     '&#208;',  true, 'ETH'],
+	['&Ntilde;',  '&#209;',  true, 'N - tilde'],
+	['&Ograve;',  '&#210;',  true, 'O - grave'],
+	['&Oacute;',  '&#211;',  true, 'O - acute'],
+	['&Ocirc;',   '&#212;',  true, 'O - circumflex'],
+	['&Otilde;',  '&#213;',  true, 'O - tilde'],
+	['&Ouml;',    '&#214;',  true, 'O - diaeresis'],
+	['&Oslash;',  '&#216;',  true, 'O - slash'],
+	['&OElig;',   '&#338;',  true, 'ligature OE'],
+	['&Scaron;',  '&#352;',  true, 'S - caron'],
+	['&Ugrave;',  '&#217;',  true, 'U - grave'],
+	['&Uacute;',  '&#218;',  true, 'U - acute'],
+	['&Ucirc;',   '&#219;',  true, 'U - circumflex'],
+	['&Uuml;',    '&#220;',  true, 'U - diaeresis'],
+	['&Yacute;',  '&#221;',  true, 'Y - acute'],
+	['&Yuml;',    '&#376;',  true, 'Y - diaeresis'],
+	['&THORN;',   '&#222;',  true, 'THORN'],
+	['&agrave;',  '&#224;',  true, 'a - grave'],
+	['&aacute;',  '&#225;',  true, 'a - acute'],
+	['&acirc;',   '&#226;',  true, 'a - circumflex'],
+	['&atilde;',  '&#227;',  true, 'a - tilde'],
+	['&auml;',    '&#228;',  true, 'a - diaeresis'],
+	['&aring;',   '&#229;',  true, 'a - ring above'],
+	['&aelig;',   '&#230;',  true, 'ligature ae'],
+	['&ccedil;',  '&#231;',  true, 'c - cedilla'],
+	['&egrave;',  '&#232;',  true, 'e - grave'],
+	['&eacute;',  '&#233;',  true, 'e - acute'],
+	['&ecirc;',   '&#234;',  true, 'e - circumflex'],
+	['&euml;',    '&#235;',  true, 'e - diaeresis'],
+	['&igrave;',  '&#236;',  true, 'i - grave'],
+	['&iacute;',  '&#237;',  true, 'i - acute'],
+	['&icirc;',   '&#238;',  true, 'i - circumflex'],
+	['&iuml;',    '&#239;',  true, 'i - diaeresis'],
+	['&eth;',     '&#240;',  true, 'eth'],
+	['&ntilde;',  '&#241;',  true, 'n - tilde'],
+	['&ograve;',  '&#242;',  true, 'o - grave'],
+	['&oacute;',  '&#243;',  true, 'o - acute'],
+	['&ocirc;',   '&#244;',  true, 'o - circumflex'],
+	['&otilde;',  '&#245;',  true, 'o - tilde'],
+	['&ouml;',    '&#246;',  true, 'o - diaeresis'],
+	['&oslash;',  '&#248;',  true, 'o slash'],
+	['&oelig;',   '&#339;',  true, 'ligature oe'],
+	['&scaron;',  '&#353;',  true, 's - caron'],
+	['&ugrave;',  '&#249;',  true, 'u - grave'],
+	['&uacute;',  '&#250;',  true, 'u - acute'],
+	['&ucirc;',   '&#251;',  true, 'u - circumflex'],
+	['&uuml;',    '&#252;',  true, 'u - diaeresis'],
+	['&yacute;',  '&#253;',  true, 'y - acute'],
+	['&thorn;',   '&#254;',  true, 'thorn'],
+	['&yuml;',    '&#255;',  true, 'y - diaeresis'],
+    ['&Alpha;',   '&#913;',  true, 'Alpha'],
+	['&Beta;',    '&#914;',  true, 'Beta'],
+	['&Gamma;',   '&#915;',  true, 'Gamma'],
+	['&Delta;',   '&#916;',  true, 'Delta'],
+	['&Epsilon;', '&#917;',  true, 'Epsilon'],
+	['&Zeta;',    '&#918;',  true, 'Zeta'],
+	['&Eta;',     '&#919;',  true, 'Eta'],
+	['&Theta;',   '&#920;',  true, 'Theta'],
+	['&Iota;',    '&#921;',  true, 'Iota'],
+	['&Kappa;',   '&#922;',  true, 'Kappa'],
+	['&Lambda;',  '&#923;',  true, 'Lambda'],
+	['&Mu;',      '&#924;',  true, 'Mu'],
+	['&Nu;',      '&#925;',  true, 'Nu'],
+	['&Xi;',      '&#926;',  true, 'Xi'],
+	['&Omicron;', '&#927;',  true, 'Omicron'],
+	['&Pi;',      '&#928;',  true, 'Pi'],
+	['&Rho;',     '&#929;',  true, 'Rho'],
+	['&Sigma;',   '&#931;',  true, 'Sigma'],
+	['&Tau;',     '&#932;',  true, 'Tau'],
+	['&Upsilon;', '&#933;',  true, 'Upsilon'],
+	['&Phi;',     '&#934;',  true, 'Phi'],
+	['&Chi;',     '&#935;',  true, 'Chi'],
+	['&Psi;',     '&#936;',  true, 'Psi'],
+	['&Omega;',   '&#937;',  true, 'Omega'],
+	['&alpha;',   '&#945;',  true, 'alpha'],
+	['&beta;',    '&#946;',  true, 'beta'],
+	['&gamma;',   '&#947;',  true, 'gamma'],
+	['&delta;',   '&#948;',  true, 'delta'],
+	['&epsilon;', '&#949;',  true, 'epsilon'],
+	['&zeta;',    '&#950;',  true, 'zeta'],
+	['&eta;',     '&#951;',  true, 'eta'],
+	['&theta;',   '&#952;',  true, 'theta'],
+	['&iota;',    '&#953;',  true, 'iota'],
+	['&kappa;',   '&#954;',  true, 'kappa'],
+	['&lambda;',  '&#955;',  true, 'lambda'],
+	['&mu;',      '&#956;',  true, 'mu'],
+	['&nu;',      '&#957;',  true, 'nu'],
+	['&xi;',      '&#958;',  true, 'xi'],
+	['&omicron;', '&#959;',  true, 'omicron'],
+	['&pi;',      '&#960;',  true, 'pi'],
+	['&rho;',     '&#961;',  true, 'rho'],
+	['&sigmaf;',  '&#962;',  true, 'final sigma'],
+	['&sigma;',   '&#963;',  true, 'sigma'],
+	['&tau;',     '&#964;',  true, 'tau'],
+	['&upsilon;', '&#965;',  true, 'upsilon'],
+	['&phi;',     '&#966;',  true, 'phi'],
+	['&chi;',     '&#967;',  true, 'chi'],
+	['&psi;',     '&#968;',  true, 'psi'],
+	['&omega;',   '&#969;',  true, 'omega'],
+// symbols
+	['&alefsym;', '&#8501;', false,'alef symbol'],
+	['&piv;',     '&#982;',  false,'pi symbol'],
+	['&real;',    '&#8476;', false,'real part symbol'],
+	['&thetasym;','&#977;',  false,'theta symbol'],
+	['&upsih;',   '&#978;',  false,'upsilon - hook symbol'],
+	['&weierp;',  '&#8472;', false,'Weierstrass p'],
+	['&image;',   '&#8465;', false,'imaginary part'],
+// arrows
+	['&larr;',    '&#8592;', true, 'leftwards arrow'],
+	['&uarr;',    '&#8593;', true, 'upwards arrow'],
+	['&rarr;',    '&#8594;', true, 'rightwards arrow'],
+	['&darr;',    '&#8595;', true, 'downwards arrow'],
+	['&harr;',    '&#8596;', true, 'left right arrow'],
+	['&crarr;',   '&#8629;', false,'carriage return'],
+	['&lArr;',    '&#8656;', false,'leftwards double arrow'],
+	['&uArr;',    '&#8657;', false,'upwards double arrow'],
+	['&rArr;',    '&#8658;', false,'rightwards double arrow'],
+	['&dArr;',    '&#8659;', false,'downwards double arrow'],
+	['&hArr;',    '&#8660;', false,'left right double arrow'],
+	['&there4;',  '&#8756;', false,'therefore'],
+	['&sub;',     '&#8834;', false,'subset of'],
+	['&sup;',     '&#8835;', false,'superset of'],
+	['&nsub;',    '&#8836;', false,'not a subset of'],
+	['&sube;',    '&#8838;', false,'subset of or equal to'],
+	['&supe;',    '&#8839;', false,'superset of or equal to'],
+	['&oplus;',   '&#8853;', false,'circled plus'],
+	['&otimes;',  '&#8855;', false,'circled times'],
+	['&perp;',    '&#8869;', false,'perpendicular'],
+	['&sdot;',    '&#8901;', false,'dot operator'],
+	['&lceil;',   '&#8968;', false,'left ceiling'],
+	['&rceil;',   '&#8969;', false,'right ceiling'],
+	['&lfloor;',  '&#8970;', false,'left floor'],
+	['&rfloor;',  '&#8971;', false,'right floor'],
+	['&lang;',    '&#9001;', false,'left-pointing angle bracket'],
+	['&rang;',    '&#9002;', false,'right-pointing angle bracket'],
+	['&loz;',     '&#9674;', true,'lozenge'],
+	['&spades;',  '&#9824;', false,'black spade suit'],
+	['&clubs;',   '&#9827;', true, 'black club suit'],
+	['&hearts;',  '&#9829;', true, 'black heart suit'],
+	['&diams;',   '&#9830;', true, 'black diamond suit'],
+	['&ensp;',    '&#8194;', false,'en space'],
+	['&emsp;',    '&#8195;', false,'em space'],
+	['&thinsp;',  '&#8201;', false,'thin space'],
+	['&zwnj;',    '&#8204;', false,'zero width non-joiner'],
+	['&zwj;',     '&#8205;', false,'zero width joiner'],
+	['&lrm;',     '&#8206;', false,'left-to-right mark'],
+	['&rlm;',     '&#8207;', false,'right-to-left mark'],
+	['&shy;',     '&#173;',  false,'soft hyphen']
+];
+
+function renderCharMapHTML() {
+	var charsPerRow = 20, tdWidth=20, tdHeight=20;
+	var html = '<table border="0" cellspacing="1" cellpadding="0" width="' + (tdWidth*charsPerRow) + '"><tr height="' + tdHeight + '">';
+	var cols=-1;
+	for (var i=0; i<charmap.length; i++) {
+		if (charmap[i][2]==true) {
+			cols++;
+			html += ''
+				+ '<td width="' + tdWidth + '" height="' + tdHeight + '" class="charmap"'
+				+ ' onmouseover="this.className=\'charmapOver\';'
+				+ 'previewChar(\'' + charmap[i][1].substring(1,charmap[i][1].length) + '\',\'' + charmap[i][0].substring(1,charmap[i][0].length) + '\',\'' + charmap[i][3] + '\');"'
+				+ ' onmouseout="this.className=\'charmap\';"'
+				+ ' nowrap="nowrap" onclick="insertChar(\'' + charmap[i][1].substring(2,charmap[i][1].length-1) + '\');"><a style="text-decoration: none;" onfocus="previewChar(\'' + charmap[i][1].substring(1,charmap[i][1].length) + '\',\'' + charmap[i][0].substring(1,charmap[i][0].length) + '\',\'' + charmap[i][3] + '\');" href="javascript:insertChar(\'' + charmap[i][1].substring(2,charmap[i][1].length-1) + '\');" onclick="return false;" onmousedown="return false;" title="' + charmap[i][3] + '">'
+				+ charmap[i][1]
+				+ '</a></td>';
+			if ((cols+1) % charsPerRow == 0)
+				html += '</tr><tr height="' + tdHeight + '">';
+		}
+	 }
+	if (cols % charsPerRow > 0) {
+		var padd = charsPerRow - (cols % charsPerRow);
+		for (var i=0; i<padd-1; i++)
+			html += '<td width="' + tdWidth + '" height="' + tdHeight + '" class="charmap">&nbsp;</td>';
+	}
+	html += '</tr></table>';
+	document.write(html);
+}
+
+function insertChar(chr) {
+	tinyMCEPopup.execCommand('mceInsertContent', false, '&#' + chr + ';');
+
+	// Refocus in window
+	if (tinyMCEPopup.isWindow)
+		window.focus();
+
+	tinyMCEPopup.close();
+}
+
+function previewChar(codeA, codeB, codeN) {
+	var elmA = document.getElementById('codeA');
+	var elmB = document.getElementById('codeB');
+	var elmV = document.getElementById('codeV');
+	var elmN = document.getElementById('codeN');
+
+	if (codeA=='#160;') {
+		elmV.innerHTML = '__';
+	} else {
+		elmV.innerHTML = '&' + codeA;
+	}
+
+	elmB.innerHTML = '&amp;' + codeA;
+	elmA.innerHTML = '&amp;' + codeB;
+	elmN.innerHTML = codeN;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/themes/advanced/jscripts/color_picker.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,249 @@
+var detail = 50, strhex = "0123456789abcdef", i, isMouseDown = false, isMouseOver = false;
+
+var colors = new Array(
+	"#000000","#000033","#000066","#000099","#0000cc","#0000ff","#330000","#330033",
+	"#330066","#330099","#3300cc","#3300ff","#660000","#660033","#660066","#660099",
+	"#6600cc","#6600ff","#990000","#990033","#990066","#990099","#9900cc","#9900ff",
+	"#cc0000","#cc0033","#cc0066","#cc0099","#cc00cc","#cc00ff","#ff0000","#ff0033",
+	"#ff0066","#ff0099","#ff00cc","#ff00ff","#003300","#003333","#003366","#003399",
+	"#0033cc","#0033ff","#333300","#333333","#333366","#333399","#3333cc","#3333ff",
+	"#663300","#663333","#663366","#663399","#6633cc","#6633ff","#993300","#993333",
+	"#993366","#993399","#9933cc","#9933ff","#cc3300","#cc3333","#cc3366","#cc3399",
+	"#cc33cc","#cc33ff","#ff3300","#ff3333","#ff3366","#ff3399","#ff33cc","#ff33ff",
+	"#006600","#006633","#006666","#006699","#0066cc","#0066ff","#336600","#336633",
+	"#336666","#336699","#3366cc","#3366ff","#666600","#666633","#666666","#666699",
+	"#6666cc","#6666ff","#996600","#996633","#996666","#996699","#9966cc","#9966ff",
+	"#cc6600","#cc6633","#cc6666","#cc6699","#cc66cc","#cc66ff","#ff6600","#ff6633",
+	"#ff6666","#ff6699","#ff66cc","#ff66ff","#009900","#009933","#009966","#009999",
+	"#0099cc","#0099ff","#339900","#339933","#339966","#339999","#3399cc","#3399ff",
+	"#669900","#669933","#669966","#669999","#6699cc","#6699ff","#999900","#999933",
+	"#999966","#999999","#9999cc","#9999ff","#cc9900","#cc9933","#cc9966","#cc9999",
+	"#cc99cc","#cc99ff","#ff9900","#ff9933","#ff9966","#ff9999","#ff99cc","#ff99ff",
+	"#00cc00","#00cc33","#00cc66","#00cc99","#00cccc","#00ccff","#33cc00","#33cc33",
+	"#33cc66","#33cc99","#33cccc","#33ccff","#66cc00","#66cc33","#66cc66","#66cc99",
+	"#66cccc","#66ccff","#99cc00","#99cc33","#99cc66","#99cc99","#99cccc","#99ccff",
+	"#cccc00","#cccc33","#cccc66","#cccc99","#cccccc","#ccccff","#ffcc00","#ffcc33",
+	"#ffcc66","#ffcc99","#ffcccc","#ffccff","#00ff00","#00ff33","#00ff66","#00ff99",
+	"#00ffcc","#00ffff","#33ff00","#33ff33","#33ff66","#33ff99","#33ffcc","#33ffff",
+	"#66ff00","#66ff33","#66ff66","#66ff99","#66ffcc","#66ffff","#99ff00","#99ff33",
+	"#99ff66","#99ff99","#99ffcc","#99ffff","#ccff00","#ccff33","#ccff66","#ccff99",
+	"#ccffcc","#ccffff","#ffff00","#ffff33","#ffff66","#ffff99","#ffffcc","#ffffff"
+);
+
+var named = {
+	'#F0F8FF':'AliceBlue','#FAEBD7':'AntiqueWhite','#00FFFF':'Aqua','#7FFFD4':'Aquamarine','#F0FFFF':'Azure','#F5F5DC':'Beige',
+	'#FFE4C4':'Bisque','#000000':'Black','#FFEBCD':'BlanchedAlmond','#0000FF':'Blue','#8A2BE2':'BlueViolet','#A52A2A':'Brown',
+	'#DEB887':'BurlyWood','#5F9EA0':'CadetBlue','#7FFF00':'Chartreuse','#D2691E':'Chocolate','#FF7F50':'Coral','#6495ED':'CornflowerBlue',
+	'#FFF8DC':'Cornsilk','#DC143C':'Crimson','#00FFFF':'Cyan','#00008B':'DarkBlue','#008B8B':'DarkCyan','#B8860B':'DarkGoldenRod',
+	'#A9A9A9':'DarkGray','#A9A9A9':'DarkGrey','#006400':'DarkGreen','#BDB76B':'DarkKhaki','#8B008B':'DarkMagenta','#556B2F':'DarkOliveGreen',
+	'#FF8C00':'Darkorange','#9932CC':'DarkOrchid','#8B0000':'DarkRed','#E9967A':'DarkSalmon','#8FBC8F':'DarkSeaGreen','#483D8B':'DarkSlateBlue',
+	'#2F4F4F':'DarkSlateGray','#2F4F4F':'DarkSlateGrey','#00CED1':'DarkTurquoise','#9400D3':'DarkViolet','#FF1493':'DeepPink','#00BFFF':'DeepSkyBlue',
+	'#696969':'DimGray','#696969':'DimGrey','#1E90FF':'DodgerBlue','#B22222':'FireBrick','#FFFAF0':'FloralWhite','#228B22':'ForestGreen',
+	'#FF00FF':'Fuchsia','#DCDCDC':'Gainsboro','#F8F8FF':'GhostWhite','#FFD700':'Gold','#DAA520':'GoldenRod','#808080':'Gray','#808080':'Grey',
+	'#008000':'Green','#ADFF2F':'GreenYellow','#F0FFF0':'HoneyDew','#FF69B4':'HotPink','#CD5C5C':'IndianRed','#4B0082':'Indigo','#FFFFF0':'Ivory',
+	'#F0E68C':'Khaki','#E6E6FA':'Lavender','#FFF0F5':'LavenderBlush','#7CFC00':'LawnGreen','#FFFACD':'LemonChiffon','#ADD8E6':'LightBlue',
+	'#F08080':'LightCoral','#E0FFFF':'LightCyan','#FAFAD2':'LightGoldenRodYellow','#D3D3D3':'LightGray','#D3D3D3':'LightGrey','#90EE90':'LightGreen',
+	'#FFB6C1':'LightPink','#FFA07A':'LightSalmon','#20B2AA':'LightSeaGreen','#87CEFA':'LightSkyBlue','#778899':'LightSlateGray','#778899':'LightSlateGrey',
+	'#B0C4DE':'LightSteelBlue','#FFFFE0':'LightYellow','#00FF00':'Lime','#32CD32':'LimeGreen','#FAF0E6':'Linen','#FF00FF':'Magenta','#800000':'Maroon',
+	'#66CDAA':'MediumAquaMarine','#0000CD':'MediumBlue','#BA55D3':'MediumOrchid','#9370D8':'MediumPurple','#3CB371':'MediumSeaGreen','#7B68EE':'MediumSlateBlue',
+	'#00FA9A':'MediumSpringGreen','#48D1CC':'MediumTurquoise','#C71585':'MediumVioletRed','#191970':'MidnightBlue','#F5FFFA':'MintCream','#FFE4E1':'MistyRose','#FFE4B5':'Moccasin',
+	'#FFDEAD':'NavajoWhite','#000080':'Navy','#FDF5E6':'OldLace','#808000':'Olive','#6B8E23':'OliveDrab','#FFA500':'Orange','#FF4500':'OrangeRed','#DA70D6':'Orchid',
+	'#EEE8AA':'PaleGoldenRod','#98FB98':'PaleGreen','#AFEEEE':'PaleTurquoise','#D87093':'PaleVioletRed','#FFEFD5':'PapayaWhip','#FFDAB9':'PeachPuff',
+	'#CD853F':'Peru','#FFC0CB':'Pink','#DDA0DD':'Plum','#B0E0E6':'PowderBlue','#800080':'Purple','#FF0000':'Red','#BC8F8F':'RosyBrown','#4169E1':'RoyalBlue',
+	'#8B4513':'SaddleBrown','#FA8072':'Salmon','#F4A460':'SandyBrown','#2E8B57':'SeaGreen','#FFF5EE':'SeaShell','#A0522D':'Sienna','#C0C0C0':'Silver',
+	'#87CEEB':'SkyBlue','#6A5ACD':'SlateBlue','#708090':'SlateGray','#708090':'SlateGrey','#FFFAFA':'Snow','#00FF7F':'SpringGreen',
+	'#4682B4':'SteelBlue','#D2B48C':'Tan','#008080':'Teal','#D8BFD8':'Thistle','#FF6347':'Tomato','#40E0D0':'Turquoise','#EE82EE':'Violet',
+	'#F5DEB3':'Wheat','#FFFFFF':'White','#F5F5F5':'WhiteSmoke','#FFFF00':'Yellow','#9ACD32':'YellowGreen'
+};
+
+function init() {
+	var inputColor = convertRGBToHex(tinyMCE.getWindowArg('input_color'));
+
+	if (tinyMCE.isMSIE)
+		tinyMCEPopup.resizeToInnerSize();
+
+	generatePicker();
+
+	if (inputColor) {
+		changeFinalColor(inputColor);
+
+		col = convertHexToRGB(inputColor);
+
+		if (col)
+			updateLight(col.r, col.g, col.b);
+	}
+}
+
+function insertAction() {
+	var color = document.getElementById("color").value;
+
+	tinyMCEPopup.execCommand(tinyMCE.getWindowArg('command'), false, color);
+	tinyMCEPopup.close();
+}
+
+function showColor(color, name) {
+	if (name)
+		document.getElementById("colorname").innerHTML = name;
+
+	document.getElementById("preview").style.backgroundColor = color;
+	document.getElementById("color").value = color;
+}
+
+function convertRGBToHex(col) {
+	var re = new RegExp("rgb\\s*\\(\\s*([0-9]+).*,\\s*([0-9]+).*,\\s*([0-9]+).*\\)", "gi");
+
+	if (!col)
+		return col;
+
+	var rgb = col.replace(re, "$1,$2,$3").split(',');
+	if (rgb.length == 3) {
+		r = parseInt(rgb[0]).toString(16);
+		g = parseInt(rgb[1]).toString(16);
+		b = parseInt(rgb[2]).toString(16);
+
+		r = r.length == 1 ? '0' + r : r;
+		g = g.length == 1 ? '0' + g : g;
+		b = b.length == 1 ? '0' + b : b;
+
+		return "#" + r + g + b;
+	}
+
+	return col;
+}
+
+function convertHexToRGB(col) {
+	if (col.indexOf('#') != -1) {
+		col = col.replace(new RegExp('[^0-9A-F]', 'gi'), '');
+
+		r = parseInt(col.substring(0, 2), 16);
+		g = parseInt(col.substring(2, 4), 16);
+		b = parseInt(col.substring(4, 6), 16);
+
+		return {r : r, g : g, b : b};
+	}
+
+	return null;
+}
+
+function generatePicker() {
+	var el = document.getElementById('light'), h = '', i;
+
+	for (i = 0; i < detail; i++){
+		h += '<div id="gs'+i+'" style="background-color:#000000; width:15px; height:3px; border-style:none; border-width:0px;"'
+		+ ' onclick="changeFinalColor(this.style.backgroundColor)"'
+		+ ' onmousedown="isMouseDown = true; return false;"'
+		+ ' onmouseup="isMouseDown = false;"'
+		+ ' onmousemove="if (isMouseDown && isMouseOver) changeFinalColor(this.style.backgroundColor); return false;"'
+		+ ' onmouseover="isMouseOver = true;"'
+		+ ' onmouseout="isMouseOver = false;"'
+		+ '></div>';
+	}
+
+	el.innerHTML = h;
+}
+
+function generateWebColors() {
+	var el = document.getElementById('webcolors'), h = '', i;
+
+	if (el.className == 'generated')
+		return;
+
+	h += '<table border="0" cellspacing="1" cellpadding="0">'
+		+ '<tr>';
+
+	for (i=0; i<colors.length; i++) {
+		h += '<td bgcolor="' + colors[i] + '">'
+			+ '<a href="javascript:selectColor();" onfocus="showColor(\'' + colors[i] +  '\');" onmouseover="showColor(\'' + colors[i] +  '\');">'
+			+ '<img border="0" src="images/spacer.gif" width="10" height="10" title="' + colors[i] +  '" alt="' + colors[i] +  '" /></a></td>';
+		if ((i+1) % 18 == 0)
+			h += '</tr><tr>';
+	}
+
+	h += '</table>';
+
+	el.innerHTML = h;
+	el.className = 'generated';
+}
+
+function generateNamedColors() {
+	var el = document.getElementById('namedcolors'), h = '', n, v, i = 0;
+
+	if (el.className == 'generated')
+		return;
+
+	for (n in named) {
+		v = named[n];
+		h += '<a href="javascript:selectColor();" onmouseover="showColor(\'' + n +  '\',\'' + v + '\');" style="background-color: ' + n + '"><!-- IE --></a>'
+	}
+
+	el.innerHTML = h;
+	el.className = 'generated';
+}
+
+function selectColor() {
+	var color = document.getElementById("color").value;
+
+	if(window.opener)
+		window.opener.tinyMCE.execInstanceCommand(tinyMCE.getWindowArg('editor_id'),tinyMCE.getWindowArg('command'),false,color);
+
+	window.close();
+}
+
+function dechex(n) {
+	return strhex.charAt(Math.floor(n / 16)) + strhex.charAt(n % 16);
+}
+
+function computeColor(e) {
+	var x, y, partWidth, partDetail, imHeight, r, g, b, coef, i, finalCoef, finalR, finalG, finalB;
+
+	x = e.offsetX ? e.offsetX : (e.target ? e.clientX - e.target.x : 0);
+	y = e.offsetY ? e.offsetY : (e.target ? e.clientY - e.target.y : 0);
+
+	partWidth = document.getElementById('colorpicker').width / 6;
+	partDetail = detail / 2;
+	imHeight = document.getElementById('colorpicker').height;
+
+	r = (x >= 0)*(x < partWidth)*255 + (x >= partWidth)*(x < 2*partWidth)*(2*255 - x * 255 / partWidth) + (x >= 4*partWidth)*(x < 5*partWidth)*(-4*255 + x * 255 / partWidth) + (x >= 5*partWidth)*(x < 6*partWidth)*255;
+	g = (x >= 0)*(x < partWidth)*(x * 255 / partWidth) + (x >= partWidth)*(x < 3*partWidth)*255	+ (x >= 3*partWidth)*(x < 4*partWidth)*(4*255 - x * 255 / partWidth);
+	b = (x >= 2*partWidth)*(x < 3*partWidth)*(-2*255 + x * 255 / partWidth) + (x >= 3*partWidth)*(x < 5*partWidth)*255 + (x >= 5*partWidth)*(x < 6*partWidth)*(6*255 - x * 255 / partWidth);
+
+	coef = (imHeight - y) / imHeight;
+	r = 128 + (r - 128) * coef;
+	g = 128 + (g - 128) * coef;
+	b = 128 + (b - 128) * coef;
+
+	changeFinalColor('#' + dechex(r) + dechex(g) + dechex(b));
+	updateLight(r, g, b);
+}
+
+function updateLight(r, g, b) {
+	var i, partDetail = detail / 2, finalCoef, finalR, finalG, finalB, color;
+
+	for (i=0; i<detail; i++) {
+		if ((i>=0) && (i<partDetail)) {
+			finalCoef = i / partDetail;
+			finalR = dechex(255 - (255 - r) * finalCoef);
+			finalG = dechex(255 - (255 - g) * finalCoef);
+			finalB = dechex(255 - (255 - b) * finalCoef);
+		} else {
+			finalCoef = 2 - i / partDetail;
+			finalR = dechex(r * finalCoef);
+			finalG = dechex(g * finalCoef);
+			finalB = dechex(b * finalCoef);
+		}
+
+		color = finalR + finalG + finalB;
+
+		document.getElementById('gs' + i).style.backgroundColor = '#'+color;
+	}
+}
+
+function changeFinalColor(color) {
+	if (color.indexOf('#') == -1)
+		color = convertRGBToHex(color);
+
+	document.getElementById('preview').style.backgroundColor = color;
+	document.getElementById('color').value = color;
+}
+
+window.focus();
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/themes/advanced/jscripts/image.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,81 @@
+var url = tinyMCE.getParam("external_image_list_url");
+if (url != null) {
+	// Fix relative
+	if (url.charAt(0) != '/' && url.indexOf('://') == -1)
+		url = tinyMCE.documentBasePath + "/" + url;
+
+	document.write('<sc'+'ript language="javascript" type="text/javascript" src="' + url + '"></sc'+'ript>');
+}
+
+function insertImage() {
+	var src = document.forms[0].src.value;
+	var alt = document.forms[0].alt.value;
+	var border = document.forms[0].border.value;
+	var vspace = document.forms[0].vspace.value;
+	var hspace = document.forms[0].hspace.value;
+	var width = document.forms[0].width.value;
+	var height = document.forms[0].height.value;
+	var align = document.forms[0].align.options[document.forms[0].align.selectedIndex].value;
+
+	tinyMCEPopup.restoreSelection();
+	tinyMCE.themes['advanced']._insertImage(src, alt, border, hspace, vspace, width, height, align);
+	tinyMCEPopup.close();
+}
+
+function init() {
+	tinyMCEPopup.resizeToInnerSize();
+
+	document.getElementById('srcbrowsercontainer').innerHTML = getBrowserHTML('srcbrowser','src','image','theme_advanced_image');
+
+	var formObj = document.forms[0];
+
+	for (var i=0; i<document.forms[0].align.options.length; i++) {
+		if (document.forms[0].align.options[i].value == tinyMCE.getWindowArg('align'))
+			document.forms[0].align.options.selectedIndex = i;
+	}
+
+	formObj.src.value = tinyMCE.getWindowArg('src');
+	formObj.alt.value = tinyMCE.getWindowArg('alt');
+	formObj.border.value = tinyMCE.getWindowArg('border');
+	formObj.vspace.value = tinyMCE.getWindowArg('vspace');
+	formObj.hspace.value = tinyMCE.getWindowArg('hspace');
+	formObj.width.value = tinyMCE.getWindowArg('width');
+	formObj.height.value = tinyMCE.getWindowArg('height');
+	formObj.insert.value = tinyMCE.getLang('lang_' + tinyMCE.getWindowArg('action'), 'Insert', true); 
+
+	// Handle file browser
+	if (isVisible('srcbrowser'))
+		document.getElementById('src').style.width = '180px';
+
+	// Auto select image in list
+	if (typeof(tinyMCEImageList) != "undefined" && tinyMCEImageList.length > 0) {
+		for (var i=0; i<formObj.image_list.length; i++) {
+			if (formObj.image_list.options[i].value == tinyMCE.getWindowArg('src'))
+				formObj.image_list.options[i].selected = true;
+		}
+	}
+}
+
+var preloadImg = new Image();
+
+function resetImageData() {
+	var formObj = document.forms[0];
+	formObj.width.value = formObj.height.value = "";	
+}
+
+function updateImageData() {
+	var formObj = document.forms[0];
+
+	if (formObj.width.value == "")
+		formObj.width.value = preloadImg.width;
+
+	if (formObj.height.value == "")
+		formObj.height.value = preloadImg.height;
+}
+
+function getImageData() {
+	preloadImg = new Image();
+	tinyMCE.addEvent(preloadImg, "load", updateImageData);
+	tinyMCE.addEvent(preloadImg, "error", function () {var formObj = document.forms[0];formObj.width.value = formObj.height.value = "";});
+	preloadImg.src = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], document.forms[0].src.value);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/themes/advanced/jscripts/link.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,66 @@
+var url = tinyMCE.getParam("external_link_list_url");
+if (url != null) {
+	// Fix relative
+	if (url.charAt(0) != '/' && url.indexOf('://') == -1)
+		url = tinyMCE.documentBasePath + "/" + url;
+
+	document.write('<sc'+'ript language="javascript" type="text/javascript" src="' + url + '"></sc'+'ript>');
+}
+
+function init() {
+	tinyMCEPopup.resizeToInnerSize();
+
+	document.getElementById('hrefbrowsercontainer').innerHTML = getBrowserHTML('hrefbrowser','href','file','theme_advanced_link');
+
+	// Handle file browser
+	if (isVisible('hrefbrowser'))
+		document.getElementById('href').style.width = '180px';
+
+	var formObj = document.forms[0];
+
+	for (var i=0; i<document.forms[0].target.options.length; i++) {
+		var option = document.forms[0].target.options[i];
+
+		if (option.value == tinyMCE.getWindowArg('target'))
+			option.selected = true;
+	}
+
+	document.forms[0].href.value = tinyMCE.getWindowArg('href');
+	document.forms[0].linktitle.value = tinyMCE.getWindowArg('title');
+	document.forms[0].insert.value = tinyMCE.getLang('lang_' + tinyMCE.getWindowArg('action'), 'Insert', true); 
+
+	addClassesToList('styleSelect', 'theme_advanced_link_styles');
+	selectByValue(formObj, 'styleSelect', tinyMCE.getWindowArg('className'), true);
+
+	// Hide css select row if no CSS classes
+	if (formObj.styleSelect && formObj.styleSelect.options.length <= 1) {
+		var sr = document.getElementById('styleSelectRow');
+		sr.style.display = 'none';
+		sr.parentNode.removeChild(sr);
+	}
+
+	// Auto select link in list
+	if (typeof(tinyMCELinkList) != "undefined" && tinyMCELinkList.length > 0) {
+		var formObj = document.forms[0];
+
+		for (var i=0; i<formObj.link_list.length; i++) {
+			if (formObj.link_list.options[i].value == tinyMCE.getWindowArg('href'))
+				formObj.link_list.options[i].selected = true;
+		}
+	}
+}
+
+function insertLink() {
+	var href = document.forms[0].href.value;
+	var target = document.forms[0].target.options[document.forms[0].target.selectedIndex].value;
+	var title = document.forms[0].linktitle.value;
+	var style_class = document.forms[0].styleSelect ? document.forms[0].styleSelect.value : "";
+	var dummy;
+
+	if (target == '_self')
+		target = '';
+
+	tinyMCEPopup.restoreSelection();
+	tinyMCE.themes['advanced']._insertLink(href, target, title, dummy, style_class);
+	tinyMCEPopup.close();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/themes/advanced/jscripts/source_editor.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,59 @@
+function saveContent() {
+	tinyMCE.setContent(document.getElementById('htmlSource').value);
+	tinyMCE.closeWindow(window);
+}
+
+function onLoadInit() {
+	tinyMCEPopup.resizeToInnerSize();
+
+	// Remove Gecko spellchecking
+	if (tinyMCE.isGecko)
+		document.body.spellcheck = tinyMCE.getParam("gecko_spellcheck");
+
+	document.getElementById('htmlSource').value = tinyMCE.getContent(tinyMCE.getWindowArg('editor_id'));
+
+	resizeInputs();
+
+	if (tinyMCE.getParam("theme_advanced_source_editor_wrap", true)) {
+		setWrap('soft');
+		document.getElementById('wraped').checked = true;
+	}
+}
+
+function setWrap(val) {
+	var s = document.getElementById('htmlSource');
+
+	s.wrap = val;
+
+	if (tinyMCE.isGecko || tinyMCE.isOpera) {
+		var v = s.value;
+		var n = s.cloneNode(false);
+		n.setAttribute("wrap", val);
+		s.parentNode.replaceChild(n, s);
+		n.value = v;
+	}
+}
+
+function toggleWordWrap(elm) {
+	if (elm.checked)
+		setWrap('soft');
+	else
+		setWrap('off');
+}
+
+var wHeight=0, wWidth=0, owHeight=0, owWidth=0;
+
+function resizeInputs() {
+	var el = document.getElementById('htmlSource');
+
+	if (!tinyMCE.isMSIE) {
+		 wHeight = self.innerHeight - 60;
+		 wWidth = self.innerWidth - 16;
+	} else {
+		 wHeight = document.body.clientHeight - 60;
+		 wWidth = document.body.clientWidth - 16;
+	}
+
+	el.style.height = Math.abs(wHeight) + 'px';
+	el.style.width  = Math.abs(wWidth) + 'px';
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/themes/advanced/langs/en.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,91 @@
+// UK lang variables
+
+tinyMCE.addToLang('',{
+theme_style_select : '-- Styles --',
+theme_code_desc : 'Edit HTML Source',
+theme_code_title : 'HTML Source Editor',
+theme_code_wordwrap : 'Word wrap',
+theme_sub_desc : 'Subscript',
+theme_sup_desc : 'Superscript',
+theme_hr_desc : 'Insert horizontal ruler',
+theme_removeformat_desc : 'Remove formatting',
+theme_custom1_desc : 'Your custom description here',
+insert_image_border : 'Border',
+insert_image_dimensions : 'Dimensions',
+insert_image_vspace : 'Vertical space',
+insert_image_hspace : 'Horizontal space',
+insert_image_align : 'Alignment',
+insert_image_align_default : '-- Not set --',
+insert_image_align_baseline : 'Baseline',
+insert_image_align_top : 'Top',
+insert_image_align_middle : 'Middle',
+insert_image_align_bottom : 'Bottom',
+insert_image_align_texttop : 'TextTop',
+insert_image_align_absmiddle : 'Absolute Middle',
+insert_image_align_absbottom : 'Absolute Bottom',
+insert_image_align_left : 'Left',
+insert_image_align_right : 'Right',
+theme_font_size : '-- Font size --',
+theme_fontdefault : '-- Font family --',
+theme_block : '-- Format --',
+theme_paragraph : 'Paragraph',
+theme_div : 'Div',
+theme_address : 'Address',
+theme_pre : 'Preformatted',
+theme_h1 : 'Heading 1',
+theme_h2 : 'Heading 2',
+theme_h3 : 'Heading 3',
+theme_h4 : 'Heading 4',
+theme_h5 : 'Heading 5',
+theme_h6 : 'Heading 6',
+theme_blockquote : 'Blockquote',
+theme_code : 'Code',
+theme_samp : 'Code sample',
+theme_dt : 'Definition term ',
+theme_dd : 'Definition description',
+theme_colorpicker_title : 'Select a color',
+theme_colorpicker_apply : 'Apply',
+theme_forecolor_desc : 'Select text color',
+theme_backcolor_desc : 'Select background color',
+theme_charmap_title : 'Select custom character',
+theme_charmap_desc : 'Insert custom character',
+theme_visualaid_desc : 'Toggle guidelines/invisible elements',
+insert_anchor_title : 'Insert/edit anchor',
+insert_anchor_name : 'Anchor name',
+theme_anchor_desc : 'Insert/edit anchor',
+theme_insert_link_titlefield : 'Title',
+theme_clipboard_msg : 'Copy/Cut/Paste is not available in Mozilla and Firefox.\nDo you want more information about this issue?',
+theme_path : 'Path',
+cut_desc : 'Cut',
+copy_desc : 'Copy',
+paste_desc : 'Paste',
+link_list : 'Link list',
+image_list : 'Image list',
+browse : 'Browse',
+image_props_desc : 'Image properties',
+newdocument_desc : 'New document',
+class_name : 'Class',
+newdocument : 'Are you sure you want clear all contents?',
+about_title : 'About TinyMCE',
+about : 'About',
+license : 'License',
+plugins : 'Plugins',
+plugin : 'Plugin',
+author : 'Author',
+version : 'Version',
+loaded_plugins : 'Loaded plugins',
+help : 'Help',
+not_set : '-- Not set --',
+close : 'Close',
+toolbar_focus : 'Jump to tool buttons - Alt+Q, Jump to editor - Alt-Z, Jump to element path - Alt-X',
+invalid_data : 'Error: Invalid values entered, these are marked in red.',
+more_colors : 'More colors',
+color_picker_tab : 'Picker',
+color_picker : 'Color picker',
+web_colors_tab : 'Web safe',
+web_colors : 'Web safe colors',
+named_colors_tab : 'Named',
+named_colors : 'Named colors',
+color : 'Color:',
+color_name : 'Name:'
+});
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/themes/advanced/link.htm	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,100 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>{$lang_insert_link_title}</title>
+	<script language="javascript" type="text/javascript" src="../../tiny_mce_popup.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/mctabs.js"></script>
+	<script language="javascript" type="text/javascript" src="../../utils/form_utils.js"></script>
+	<script language="javascript" type="text/javascript" src="jscripts/link.js"></script>
+	<base target="_self" />
+</head>
+<body id="link" onload="tinyMCEPopup.executeOnLoad('init();');" style="display: none">
+<form onsubmit="insertLink();return false;" action="#">
+	<div class="tabs">
+		<ul>
+			<li id="general_tab" class="current"><span><a href="javascript:mcTabs.displayTab('general_tab','general_panel');" onmousedown="return false;">{$lang_insert_link_title}</a></span></li>
+		</ul>
+	</div>
+
+	<div class="panel_wrapper">
+		<div id="general_panel" class="panel current">
+
+		<table border="0" cellpadding="4" cellspacing="0">
+          <tr>
+            <td nowrap="nowrap"><label for="href">{$lang_insert_link_url}</label></td>
+            <td><table border="0" cellspacing="0" cellpadding="0"> 
+				  <tr> 
+					<td><input id="href" name="href" type="text" value="" style="width: 200px" /></td> 
+					<td id="hrefbrowsercontainer">&nbsp;</td>
+				  </tr> 
+				</table></td>
+          </tr>
+		  <!-- Link list -->
+		  <script language="javascript">
+			if (typeof(tinyMCELinkList) != "undefined" && tinyMCELinkList.length > 0) {
+				var html = "";
+
+				html += '<tr><td><label for="link_list">{$lang_link_list}</label></td>';
+				html += '<td><select id="link_list" name="link_list" style="width: 200px" onchange="this.form.href.value=this.options[this.selectedIndex].value;">';
+				html += '<option value="">---</option>';
+
+				for (var i=0; i<tinyMCELinkList.length; i++)
+					html += '<option value="' + tinyMCELinkList[i][1] + '">' + tinyMCELinkList[i][0] + '</option>';
+
+				html += '</select></td></tr>';
+
+				document.write(html);
+			}
+		  </script>
+		  <!-- /Link list -->
+          <tr>
+            <td nowrap="nowrap"><label for="target">{$lang_insert_link_target}</label></td>
+            <td><select id="target" name="target" style="width: 200px">
+                <option value="_self">{$lang_insert_link_target_same}</option>
+                <option value="_blank">{$lang_insert_link_target_blank}</option>
+				<script language="javascript">
+					var html = "";
+					var targets = tinyMCE.getParam('theme_advanced_link_targets', '').split(';');
+
+					for (var i=0; i<targets.length; i++) {
+						var key, value;
+
+						if (targets[i] == "")
+							continue;
+
+						key = targets[i].split('=')[0];
+						value = targets[i].split('=')[1];
+
+						html += '<option value="' + value + '">' + key + '</option>';
+					}
+
+					document.write(html);
+				</script>
+            </select></td>
+          </tr>
+          <tr>
+            <td nowrap="nowrap"><label for="linktitle">{$lang_theme_insert_link_titlefield}</label></td>
+            <td><input id="linktitle" name="linktitle" type="text" value="" style="width: 200px"></td>
+          </tr>
+          <tr id="styleSelectRow">
+            <td><label for="styleSelect">{$lang_class_name}</label></td>
+            <td>
+			 <select id="styleSelect" name="styleSelect">
+                <option value="" selected>{$lang_theme_style_select}</option>
+             </select></td>
+          </tr>
+        </table>
+		</div>
+	</div>
+
+	<div class="mceActionPanel">
+		<div style="float: left">
+			<input type="button" id="insert" name="insert" value="{$lang_insert}" onclick="insertLink();" />
+		</div>
+
+		<div style="float: right">
+			<input type="button" id="cancel" name="cancel" value="{$lang_cancel}" onclick="tinyMCEPopup.close();" />
+		</div>
+	</div>
+</form>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/themes/advanced/source_editor.htm	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,32 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+	<title>{$lang_theme_code_title}</title>
+	<script language="javascript" type="text/javascript" src="../../tiny_mce_popup.js"></script>
+	<script language="javascript" type="text/javascript" src="jscripts/source_editor.js"></script>
+	<base target="_self" />
+</head>
+<body onload="tinyMCEPopup.executeOnLoad('onLoadInit();');" onresize="resizeInputs();" style="display: none">
+	<form name="source" onsubmit="saveContent();" action="#">
+		<div style="float: left" class="title">{$lang_theme_code_title}</div>
+
+		<div id="wrapline" style="float: right">
+			<input type="checkbox" name="wraped" id="wraped" onclick="toggleWordWrap(this);" class="wordWrapCode" /><label for="wraped">{$lang_theme_code_wordwrap}</label>
+		</div>
+
+		<br style="clear: both" />
+
+		<textarea name="htmlSource" id="htmlSource" rows="15" cols="100" style="width: 100%; height: 100%; font-family: 'Courier New',Courier,mono; font-size: 12px" dir="ltr" wrap="off"></textarea>
+
+		<div class="mceActionPanel">
+			<div style="float: left">
+				<input type="button" name="insert" value="{$lang_update}" onclick="saveContent();" id="insert" />
+			</div>
+
+			<div style="float: right">
+				<input type="button" name="cancel" value="{$lang_cancel}" onclick="tinyMCEPopup.close();" id="cancel" />
+			</div>
+		</div>
+	</form>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/themes/simple/css/editor_content.css	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,25 @@
+body, td, pre {
+	font-family: Verdana, Arial, Helvetica, sans-serif;
+	font-size: 10px;
+}
+
+body {
+	background-color: #FFFFFF;
+}
+
+.mceVisualAid {
+	border: 1px dashed #BBBBBB;
+}
+
+/* MSIE specific */
+
+* html body {
+	scrollbar-3dlight-color: #F0F0EE;
+	scrollbar-arrow-color: #676662;
+	scrollbar-base-color: #F0F0EE;
+	scrollbar-darkshadow-color: #DDDDDD;
+	scrollbar-face-color: #E0E0DD;
+	scrollbar-highlight-color: #F0F0EE;
+	scrollbar-shadow-color: #F0F0EE;
+	scrollbar-track-color: #F5F5F5;	
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/themes/simple/css/editor_popup.css	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,41 @@
+body {
+	background-color: #F0F0EE;
+	font-family: Verdana, Arial, Helvetica, sans-serif;
+	font-size: 11px;
+	scrollbar-3dlight-color: #F0F0EE;
+	scrollbar-arrow-color: #676662;
+	scrollbar-base-color: #F0F0EE;
+	scrollbar-darkshadow-color: #DDDDDD;
+	scrollbar-face-color: #E0E0DD;
+	scrollbar-highlight-color: #F0F0EE;
+	scrollbar-shadow-color: #F0F0EE;
+	scrollbar-track-color: #F5F5F5;
+}
+
+td {
+	font-family: Verdana, Arial, Helvetica, sans-serif;
+	font-size: 11px;
+}
+
+input {
+	background: #FFFFFF;
+	border: 1px solid #cccccc;
+}
+
+td, input, select, textarea {
+	font-family: Verdana, Arial, Helvetica, sans-serif;
+	font-size: 10px;
+}
+
+input, select, textarea {
+	border: 1px solid #808080;
+}
+
+.input_noborder {
+	border: 0;
+}
+
+.title {
+	font-size: 12px;
+	font-weight: bold;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/themes/simple/css/editor_ui.css	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,125 @@
+.mceSeparatorLine {
+	border: 0;
+	padding: 0;
+	margin-left: 4px;
+	margin-right: 2px;
+}
+
+.mceSelectList {
+	font-family: "MS Sans Serif";
+	font-size: 7pt;
+	font-weight: normal;
+	margin-top: 2px;
+}
+
+.mceLabel, .mceLabelDisabled {
+	font-family: "MS Sans Serif";
+	font-size: 9pt;
+}
+
+.mceLabel {
+	color: #000000;
+}
+
+.mceLabelDisabled {
+	cursor: text;
+	color: #999999;
+}
+
+.mceEditor {
+	background: #F0F0EE;
+	border: 1px solid #cccccc;
+}
+
+.mceEditorArea {
+	font-family: "MS Sans Serif";
+	background: #FFFFFF;
+}
+
+.mceToolbar {
+	background: #F0F0EE;
+	border-top: 1px solid #cccccc;
+	line-height: 1px;
+	font-size: 1px;
+	padding-bottom: 1px;
+}
+
+.mceEditorIframe {
+	border: 0;
+}
+
+/* Button CSS rules */
+
+a.mceButtonDisabled img, a.mceButtonNormal img, a.mceButtonSelected img {
+	width: 20px;
+	height: 20px;
+	cursor: default;
+	margin-top: 1px;
+	margin-left: 1px;
+}
+
+a.mceButtonDisabled img {
+	border: 0 !important;
+}
+
+a.mceButtonNormal img, a.mceButtonSelected img {
+	border: 1px solid #F0F0EE !important;
+}
+
+a.mceButtonSelected img {
+	border: 1px solid #C0C0BB !important;
+}
+
+a.mceButtonNormal img:hover, a.mceButtonSelected img:hover {
+	border: 1px solid #0A246A !important;
+	cursor: default;
+	background-color: #B6BDD2;
+}
+
+a.mceButtonDisabled img {
+	-moz-opacity:0.3;
+	opacity: 0.3;
+	border: 1px solid #F0F0EE !important;
+	cursor: default;
+}
+
+a.mceTiledButton img {
+	background-image: url('../images/buttons.gif');
+	background-repeat: no-repeat;
+}
+
+/* MSIE specific rules */
+
+* html a.mceButtonNormal img, * html a.mceButtonSelected img, * html a.mceButtonDisabled img {
+	border: 0px !important;
+	margin-top: 2px;
+	margin-bottom: 1px;
+}
+
+* html a.mceButtonDisabled img {
+	filter:progid:DXImageTransform.Microsoft.Alpha(opacity=30);
+	border: 0px !important;
+}
+
+* html a.mceButtonDisabled {
+	border: 1px solid #F0F0EE !important;
+}
+
+* html a.mceButtonNormal, * html a.mceButtonSelected {
+	border: 1px solid #F0F0EE;
+	cursor: default;
+}
+
+* html a.mceButtonSelected {
+	border: 1px solid #C0C0BB;
+}
+
+* html a.mceButtonNormal:hover, * html a.mceButtonSelected:hover {
+	border: 1px solid #0A246A;
+	cursor: default;
+	background-color: #B6BDD2;
+}
+
+* html .mceSelectList {
+	margin-top: 2px;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/themes/simple/editor_template.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+var TinyMCE_SimpleTheme={_buttonMap:'bold,bullist,cleanup,italic,numlist,redo,strikethrough,underline,undo',getEditorTemplate:function(){var html='';html+='<table class="mceEditor" border="0" cellpadding="0" cellspacing="0" width="{$width}" height="{$height}">';html+='<tr><td align="center">';html+='<span id="{$editor_id}">IFRAME</span>';html+='</td></tr>';html+='<tr><td class="mceToolbar" align="center" height="1">';html+=tinyMCE.getButtonHTML('bold','lang_bold_desc','{$themeurl}/images/{$lang_bold_img}','Bold');html+=tinyMCE.getButtonHTML('italic','lang_italic_desc','{$themeurl}/images/{$lang_italic_img}','Italic');html+=tinyMCE.getButtonHTML('underline','lang_underline_desc','{$themeurl}/images/{$lang_underline_img}','Underline');html+=tinyMCE.getButtonHTML('strikethrough','lang_striketrough_desc','{$themeurl}/images/strikethrough.gif','Strikethrough');html+='<img src="{$themeurl}/images/separator.gif" width="2" height="20" class="mceSeparatorLine" />';html+=tinyMCE.getButtonHTML('undo','lang_undo_desc','{$themeurl}/images/undo.gif','Undo');html+=tinyMCE.getButtonHTML('redo','lang_redo_desc','{$themeurl}/images/redo.gif','Redo');html+='<img src="{$themeurl}/images/separator.gif" width="2" height="20" class="mceSeparatorLine" />';html+=tinyMCE.getButtonHTML('cleanup','lang_cleanup_desc','{$themeurl}/images/cleanup.gif','mceCleanup');html+='<img src="{$themeurl}/images/separator.gif" width="2" height="20" class="mceSeparatorLine" />';html+=tinyMCE.getButtonHTML('bullist','lang_bullist_desc','{$themeurl}/images/bullist.gif','InsertUnorderedList');html+=tinyMCE.getButtonHTML('numlist','lang_numlist_desc','{$themeurl}/images/numlist.gif','InsertOrderedList');html+='</td></tr></table>';return{delta_width:0,delta_height:20,html:html}},handleNodeChange:function(editor_id,node){tinyMCE.switchClass(editor_id+'_bold','mceButtonNormal');tinyMCE.switchClass(editor_id+'_italic','mceButtonNormal');tinyMCE.switchClass(editor_id+'_underline','mceButtonNormal');tinyMCE.switchClass(editor_id+'_strikethrough','mceButtonNormal');tinyMCE.switchClass(editor_id+'_bullist','mceButtonNormal');tinyMCE.switchClass(editor_id+'_numlist','mceButtonNormal');do{switch(node.nodeName.toLowerCase()){case"b":case"strong":tinyMCE.switchClass(editor_id+'_bold','mceButtonSelected');break;case"i":case"em":tinyMCE.switchClass(editor_id+'_italic','mceButtonSelected');break;case"u":tinyMCE.switchClass(editor_id+'_underline','mceButtonSelected');break;case"strike":tinyMCE.switchClass(editor_id+'_strikethrough','mceButtonSelected');break;case"ul":tinyMCE.switchClass(editor_id+'_bullist','mceButtonSelected');break;case"ol":tinyMCE.switchClass(editor_id+'_numlist','mceButtonSelected');break}}while((node=node.parentNode)!=null)}};tinyMCE.addTheme("simple",TinyMCE_SimpleTheme);tinyMCE.addButtonMap(TinyMCE_SimpleTheme._buttonMap);
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/themes/simple/editor_template_src.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,84 @@
+/**
+ * $Id: editor_template_src.js 162 2007-01-03 16:16:52Z spocke $
+ *
+ * @author Moxiecode
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+var TinyMCE_SimpleTheme = {
+	// List of button ids in tile map
+	_buttonMap : 'bold,bullist,cleanup,italic,numlist,redo,strikethrough,underline,undo',
+
+	getEditorTemplate : function() {
+		var html = '';
+
+		html += '<table class="mceEditor" border="0" cellpadding="0" cellspacing="0" width="{$width}" height="{$height}">';
+		html += '<tr><td align="center">';
+		html += '<span id="{$editor_id}">IFRAME</span>';
+		html += '</td></tr>';
+		html += '<tr><td class="mceToolbar" align="center" height="1">';
+		html += tinyMCE.getButtonHTML('bold', 'lang_bold_desc', '{$themeurl}/images/{$lang_bold_img}', 'Bold');
+		html += tinyMCE.getButtonHTML('italic', 'lang_italic_desc', '{$themeurl}/images/{$lang_italic_img}', 'Italic');
+		html += tinyMCE.getButtonHTML('underline', 'lang_underline_desc', '{$themeurl}/images/{$lang_underline_img}', 'Underline');
+		html += tinyMCE.getButtonHTML('strikethrough', 'lang_striketrough_desc', '{$themeurl}/images/strikethrough.gif', 'Strikethrough');
+		html += '<img src="{$themeurl}/images/separator.gif" width="2" height="20" class="mceSeparatorLine" />';
+		html += tinyMCE.getButtonHTML('undo', 'lang_undo_desc', '{$themeurl}/images/undo.gif', 'Undo');
+		html += tinyMCE.getButtonHTML('redo', 'lang_redo_desc', '{$themeurl}/images/redo.gif', 'Redo');
+		html += '<img src="{$themeurl}/images/separator.gif" width="2" height="20" class="mceSeparatorLine" />';
+		html += tinyMCE.getButtonHTML('cleanup', 'lang_cleanup_desc', '{$themeurl}/images/cleanup.gif', 'mceCleanup');
+		html += '<img src="{$themeurl}/images/separator.gif" width="2" height="20" class="mceSeparatorLine" />';
+		html += tinyMCE.getButtonHTML('bullist', 'lang_bullist_desc', '{$themeurl}/images/bullist.gif', 'InsertUnorderedList');
+		html += tinyMCE.getButtonHTML('numlist', 'lang_numlist_desc', '{$themeurl}/images/numlist.gif', 'InsertOrderedList');
+		html += '</td></tr></table>';
+
+		return {
+			delta_width : 0,
+			delta_height : 20,
+			html : html
+		};
+	},
+
+	handleNodeChange : function(editor_id, node) {
+		// Reset old states
+		tinyMCE.switchClass(editor_id + '_bold', 'mceButtonNormal');
+		tinyMCE.switchClass(editor_id + '_italic', 'mceButtonNormal');
+		tinyMCE.switchClass(editor_id + '_underline', 'mceButtonNormal');
+		tinyMCE.switchClass(editor_id + '_strikethrough', 'mceButtonNormal');
+		tinyMCE.switchClass(editor_id + '_bullist', 'mceButtonNormal');
+		tinyMCE.switchClass(editor_id + '_numlist', 'mceButtonNormal');
+
+		// Handle elements
+		do {
+			switch (node.nodeName.toLowerCase()) {
+				case "b":
+				case "strong":
+					tinyMCE.switchClass(editor_id + '_bold', 'mceButtonSelected');
+				break;
+
+				case "i":
+				case "em":
+					tinyMCE.switchClass(editor_id + '_italic', 'mceButtonSelected');
+				break;
+
+				case "u":
+					tinyMCE.switchClass(editor_id + '_underline', 'mceButtonSelected');
+				break;
+
+				case "strike":
+					tinyMCE.switchClass(editor_id + '_strikethrough', 'mceButtonSelected');
+				break;
+				
+				case "ul":
+					tinyMCE.switchClass(editor_id + '_bullist', 'mceButtonSelected');
+				break;
+
+				case "ol":
+					tinyMCE.switchClass(editor_id + '_numlist', 'mceButtonSelected');
+				break;
+			}
+		} while ((node = node.parentNode) != null);
+	}
+};
+
+tinyMCE.addTheme("simple", TinyMCE_SimpleTheme);
+tinyMCE.addButtonMap(TinyMCE_SimpleTheme._buttonMap);
Binary file includes/clientside/tinymce/themes/simple/images/bold.gif has changed
Binary file includes/clientside/tinymce/themes/simple/images/bold_de_se.gif has changed
Binary file includes/clientside/tinymce/themes/simple/images/bold_fr.gif has changed
Binary file includes/clientside/tinymce/themes/simple/images/bold_ru.gif has changed
Binary file includes/clientside/tinymce/themes/simple/images/bold_tw.gif has changed
Binary file includes/clientside/tinymce/themes/simple/images/bullist.gif has changed
Binary file includes/clientside/tinymce/themes/simple/images/buttons.gif has changed
Binary file includes/clientside/tinymce/themes/simple/images/cleanup.gif has changed
Binary file includes/clientside/tinymce/themes/simple/images/italic.gif has changed
Binary file includes/clientside/tinymce/themes/simple/images/italic_de_se.gif has changed
Binary file includes/clientside/tinymce/themes/simple/images/italic_ru.gif has changed
Binary file includes/clientside/tinymce/themes/simple/images/italic_tw.gif has changed
Binary file includes/clientside/tinymce/themes/simple/images/numlist.gif has changed
Binary file includes/clientside/tinymce/themes/simple/images/redo.gif has changed
Binary file includes/clientside/tinymce/themes/simple/images/separator.gif has changed
Binary file includes/clientside/tinymce/themes/simple/images/spacer.gif has changed
Binary file includes/clientside/tinymce/themes/simple/images/strikethrough.gif has changed
Binary file includes/clientside/tinymce/themes/simple/images/underline.gif has changed
Binary file includes/clientside/tinymce/themes/simple/images/underline_fr.gif has changed
Binary file includes/clientside/tinymce/themes/simple/images/underline_ru.gif has changed
Binary file includes/clientside/tinymce/themes/simple/images/underline_tw.gif has changed
Binary file includes/clientside/tinymce/themes/simple/images/undo.gif has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/tiny_mce.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1 @@
+function TinyMCE_Engine(){var ua;this.majorVersion="2";this.minorVersion="1.0";this.releaseDate="2007-02-13";this.instances=new Array();this.switchClassCache=new Array();this.windowArgs=new Array();this.loadedFiles=new Array();this.pendingFiles=new Array();this.loadingIndex=0;this.configs=new Array();this.currentConfig=0;this.eventHandlers=new Array();this.log=new Array();this.undoLevels=[];this.undoIndex=0;this.typingUndoIndex=-1;ua=navigator.userAgent;this.isMSIE=(navigator.appName=="Microsoft Internet Explorer");this.isMSIE5=this.isMSIE&&(ua.indexOf('MSIE 5')!=-1);this.isMSIE5_0=this.isMSIE&&(ua.indexOf('MSIE 5.0')!=-1);this.isMSIE7=this.isMSIE&&(ua.indexOf('MSIE 7')!=-1);this.isGecko=ua.indexOf('Gecko')!=-1;this.isSafari=ua.indexOf('Safari')!=-1;this.isOpera=ua.indexOf('Opera')!=-1;this.isMac=ua.indexOf('Mac')!=-1;this.isNS7=ua.indexOf('Netscape/7')!=-1;this.isNS71=ua.indexOf('Netscape/7.1')!=-1;this.dialogCounter=0;this.plugins=new Array();this.themes=new Array();this.menus=new Array();this.loadedPlugins=new Array();this.buttonMap=new Array();this.isLoaded=false;if(this.isOpera){this.isMSIE=true;this.isGecko=false;this.isSafari=false}this.isIE=this.isMSIE;this.isRealIE=this.isMSIE&&!this.isOpera;this.idCounter=0};TinyMCE_Engine.prototype={init:function(settings){var theme,nl,baseHREF="",i;if(this.isMSIE5_0)return;this.settings=settings;if(typeof(document.execCommand)=='undefined')return;if(!tinyMCE.baseURL){var elements=document.getElementsByTagName('script');nl=document.getElementsByTagName('base');for(i=0;i<nl.length;i++){if(nl[i].href)baseHREF=nl[i].href}for(var i=0;i<elements.length;i++){if(elements[i].src&&(elements[i].src.indexOf("tiny_mce.js")!=-1||elements[i].src.indexOf("tiny_mce_dev.js")!=-1||elements[i].src.indexOf("tiny_mce_src.js")!=-1||elements[i].src.indexOf("tiny_mce_gzip")!=-1)){var src=elements[i].src;tinyMCE.srcMode=(src.indexOf('_src')!=-1||src.indexOf('_dev')!=-1)?'_src':'';tinyMCE.gzipMode=src.indexOf('_gzip')!=-1;src=src.substring(0,src.lastIndexOf('/'));if(settings.exec_mode=="src"||settings.exec_mode=="normal")tinyMCE.srcMode=settings.exec_mode=="src"?'_src':'';if(baseHREF!=""&&src.indexOf('://')==-1)tinyMCE.baseURL=baseHREF+src;else tinyMCE.baseURL=src;break}}}this.documentBasePath=document.location.href;if(this.documentBasePath.indexOf('?')!=-1)this.documentBasePath=this.documentBasePath.substring(0,this.documentBasePath.indexOf('?'));this.documentURL=this.documentBasePath;this.documentBasePath=this.documentBasePath.substring(0,this.documentBasePath.lastIndexOf('/'));if(tinyMCE.baseURL.indexOf('://')==-1&&tinyMCE.baseURL.charAt(0)!='/'){tinyMCE.baseURL=this.documentBasePath+"/"+tinyMCE.baseURL}this._def("mode","none");this._def("theme","advanced");this._def("plugins","",true);this._def("language","en");this._def("docs_language",this.settings['language']);this._def("elements","");this._def("textarea_trigger","mce_editable");this._def("editor_selector","");this._def("editor_deselector","mceNoEditor");this._def("valid_elements","+a[id|style|rel|rev|charset|hreflang|dir|lang|tabindex|accesskey|type|name|href|target|title|class|onfocus|onblur|onclick|ondblclick|onmousedown|onmouseup|onmouseover|onmousemove|onmouseout|onkeypress|onkeydown|onkeyup],-strong/-b[class|style],-em/-i[class|style],-strike[class|style],-u[class|style],#p[id|style|dir|class|align],-ol[class|style],-ul[class|style],-li[class|style],br,img[id|dir|lang|longdesc|usemap|style|class|src|onmouseover|onmouseout|border|alt=|title|hspace|vspace|width|height|align],-sub[style|class],-sup[style|class],-blockquote[dir|style],-table[border=0|cellspacing|cellpadding|width|height|class|align|summary|style|dir|id|lang|bgcolor|background|bordercolor],-tr[id|lang|dir|class|rowspan|width|height|align|valign|style|bgcolor|background|bordercolor],tbody[id|class],thead[id|class],tfoot[id|class],#td[id|lang|dir|class|colspan|rowspan|width|height|align|valign|style|bgcolor|background|bordercolor|scope],-th[id|lang|dir|class|colspan|rowspan|width|height|align|valign|style|scope],caption[id|lang|dir|class|style],-div[id|dir|class|align|style],-span[style|class|align],-pre[class|align|style],address[class|align|style],-h1[id|style|dir|class|align],-h2[id|style|dir|class|align],-h3[id|style|dir|class|align],-h4[id|style|dir|class|align],-h5[id|style|dir|class|align],-h6[id|style|dir|class|align],hr[class|style],-font[face|size|style|id|class|dir|color],dd[id|class|title|style|dir|lang],dl[id|class|title|style|dir|lang],dt[id|class|title|style|dir|lang],cite[title|id|class|style|dir|lang],abbr[title|id|class|style|dir|lang],acronym[title|id|class|style|dir|lang],del[title|id|class|style|dir|lang|datetime|cite],ins[title|id|class|style|dir|lang|datetime|cite]");this._def("extended_valid_elements","");this._def("invalid_elements","");this._def("encoding","");this._def("urlconverter_callback",tinyMCE.getParam("urlconvertor_callback","TinyMCE_Engine.prototype.convertURL"));this._def("save_callback","");this._def("debug",false);this._def("force_br_newlines",false);this._def("force_p_newlines",true);this._def("add_form_submit_trigger",true);this._def("relative_urls",true);this._def("remove_script_host",true);this._def("focus_alert",true);this._def("document_base_url",this.documentURL);this._def("visual",true);this._def("visual_table_class","mceVisualAid");this._def("setupcontent_callback","");this._def("fix_content_duplication",true);this._def("custom_undo_redo",true);this._def("custom_undo_redo_levels",-1);this._def("custom_undo_redo_keyboard_shortcuts",true);this._def("custom_undo_redo_restore_selection",true);this._def("custom_undo_redo_global",false);this._def("verify_html",true);this._def("apply_source_formatting",false);this._def("directionality","ltr");this._def("cleanup_on_startup",false);this._def("inline_styles",false);this._def("convert_newlines_to_brs",false);this._def("auto_reset_designmode",true);this._def("entities","39,#39,160,nbsp,161,iexcl,162,cent,163,pound,164,curren,165,yen,166,brvbar,167,sect,168,uml,169,copy,170,ordf,171,laquo,172,not,173,shy,174,reg,175,macr,176,deg,177,plusmn,178,sup2,179,sup3,180,acute,181,micro,182,para,183,middot,184,cedil,185,sup1,186,ordm,187,raquo,188,frac14,189,frac12,190,frac34,191,iquest,192,Agrave,193,Aacute,194,Acirc,195,Atilde,196,Auml,197,Aring,198,AElig,199,Ccedil,200,Egrave,201,Eacute,202,Ecirc,203,Euml,204,Igrave,205,Iacute,206,Icirc,207,Iuml,208,ETH,209,Ntilde,210,Ograve,211,Oacute,212,Ocirc,213,Otilde,214,Ouml,215,times,216,Oslash,217,Ugrave,218,Uacute,219,Ucirc,220,Uuml,221,Yacute,222,THORN,223,szlig,224,agrave,225,aacute,226,acirc,227,atilde,228,auml,229,aring,230,aelig,231,ccedil,232,egrave,233,eacute,234,ecirc,235,euml,236,igrave,237,iacute,238,icirc,239,iuml,240,eth,241,ntilde,242,ograve,243,oacute,244,ocirc,245,otilde,246,ouml,247,divide,248,oslash,249,ugrave,250,uacute,251,ucirc,252,uuml,253,yacute,254,thorn,255,yuml,402,fnof,913,Alpha,914,Beta,915,Gamma,916,Delta,917,Epsilon,918,Zeta,919,Eta,920,Theta,921,Iota,922,Kappa,923,Lambda,924,Mu,925,Nu,926,Xi,927,Omicron,928,Pi,929,Rho,931,Sigma,932,Tau,933,Upsilon,934,Phi,935,Chi,936,Psi,937,Omega,945,alpha,946,beta,947,gamma,948,delta,949,epsilon,950,zeta,951,eta,952,theta,953,iota,954,kappa,955,lambda,956,mu,957,nu,958,xi,959,omicron,960,pi,961,rho,962,sigmaf,963,sigma,964,tau,965,upsilon,966,phi,967,chi,968,psi,969,omega,977,thetasym,978,upsih,982,piv,8226,bull,8230,hellip,8242,prime,8243,Prime,8254,oline,8260,frasl,8472,weierp,8465,image,8476,real,8482,trade,8501,alefsym,8592,larr,8593,uarr,8594,rarr,8595,darr,8596,harr,8629,crarr,8656,lArr,8657,uArr,8658,rArr,8659,dArr,8660,hArr,8704,forall,8706,part,8707,exist,8709,empty,8711,nabla,8712,isin,8713,notin,8715,ni,8719,prod,8721,sum,8722,minus,8727,lowast,8730,radic,8733,prop,8734,infin,8736,ang,8743,and,8744,or,8745,cap,8746,cup,8747,int,8756,there4,8764,sim,8773,cong,8776,asymp,8800,ne,8801,equiv,8804,le,8805,ge,8834,sub,8835,sup,8836,nsub,8838,sube,8839,supe,8853,oplus,8855,otimes,8869,perp,8901,sdot,8968,lceil,8969,rceil,8970,lfloor,8971,rfloor,9001,lang,9002,rang,9674,loz,9824,spades,9827,clubs,9829,hearts,9830,diams,34,quot,38,amp,60,lt,62,gt,338,OElig,339,oelig,352,Scaron,353,scaron,376,Yuml,710,circ,732,tilde,8194,ensp,8195,emsp,8201,thinsp,8204,zwnj,8205,zwj,8206,lrm,8207,rlm,8211,ndash,8212,mdash,8216,lsquo,8217,rsquo,8218,sbquo,8220,ldquo,8221,rdquo,8222,bdquo,8224,dagger,8225,Dagger,8240,permil,8249,lsaquo,8250,rsaquo,8364,euro",true);this._def("entity_encoding","named");this._def("cleanup_callback","");this._def("add_unload_trigger",true);this._def("ask",false);this._def("nowrap",false);this._def("auto_resize",false);this._def("auto_focus",false);this._def("cleanup",true);this._def("remove_linebreaks",true);this._def("button_tile_map",false);this._def("submit_patch",true);this._def("browsers","msie,safari,gecko,opera",true);this._def("dialog_type","window");this._def("accessibility_warnings",true);this._def("accessibility_focus",true);this._def("merge_styles_invalid_parents","");this._def("force_hex_style_colors",true);this._def("trim_span_elements",true);this._def("convert_fonts_to_spans",false);this._def("doctype",'<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">');this._def("font_size_classes",'');this._def("font_size_style_values",'xx-small,x-small,small,medium,large,x-large,xx-large',true);this._def("event_elements",'a,img',true);this._def("convert_urls",true);this._def("table_inline_editing",false);this._def("object_resizing",true);this._def("custom_shortcuts",true);this._def("convert_on_click",false);this._def("content_css",'');this._def("fix_list_elements",true);this._def("fix_table_elements",false);this._def("strict_loading_mode",document.contentType=='application/xhtml+xml');this._def("hidden_tab_class",'');this._def("display_tab_class",'');this._def("gecko_spellcheck",false);this._def("hide_selects_on_submit",true);if(this.isMSIE&&!this.isOpera)this.settings.strict_loading_mode=false;if(this.isMSIE&&this.settings['browsers'].indexOf('msie')==-1)return;if(this.isGecko&&this.settings['browsers'].indexOf('gecko')==-1)return;if(this.isSafari&&this.settings['browsers'].indexOf('safari')==-1)return;if(this.isOpera&&this.settings['browsers'].indexOf('opera')==-1)return;baseHREF=tinyMCE.settings['document_base_url'];var h=document.location.href;var p=h.indexOf('://');if(p>0&&document.location.protocol!="file:"){p=h.indexOf('/',p+3);h=h.substring(0,p);if(baseHREF.indexOf('://')==-1)baseHREF=h+baseHREF;tinyMCE.settings['document_base_url']=baseHREF;tinyMCE.settings['document_base_prefix']=h}if(baseHREF.indexOf('?')!=-1)baseHREF=baseHREF.substring(0,baseHREF.indexOf('?'));this.settings['base_href']=baseHREF.substring(0,baseHREF.lastIndexOf('/'))+"/";theme=this.settings['theme'];this.inlineStrict='A|BR|SPAN|BDO|MAP|OBJECT|IMG|TT|I|B|BIG|SMALL|EM|STRONG|DFN|CODE|Q|SAMP|KBD|VAR|CITE|ABBR|ACRONYM|SUB|SUP|#text|#comment';this.inlineTransitional='A|BR|SPAN|BDO|OBJECT|APPLET|IMG|MAP|IFRAME|TT|I|B|U|S|STRIKE|BIG|SMALL|FONT|BASEFONT|EM|STRONG|DFN|CODE|Q|SAMP|KBD|VAR|CITE|ABBR|ACRONYM|SUB|SUP|INPUT|SELECT|TEXTAREA|LABEL|BUTTON|#text|#comment';this.blockElms='H[1-6]|P|DIV|ADDRESS|PRE|FORM|TABLE|LI|OL|UL|TD|BLOCKQUOTE|CENTER|DL|DT|DD|DIR|FIELDSET|FORM|NOSCRIPT|NOFRAMES|MENU|ISINDEX|SAMP';this.blockRegExp=new RegExp("^("+this.blockElms+")$","i");this.posKeyCodes=new Array(13,45,36,35,33,34,37,38,39,40);this.uniqueURL='javascript:void(091039730);';this.uniqueTag='<div id="mceTMPElement" style="display: none">TMP</div>';this.callbacks=new Array('onInit','getInfo','getEditorTemplate','setupContent','onChange','onPageLoad','handleNodeChange','initInstance','execCommand','getControlHTML','handleEvent','cleanup','removeInstance');this.settings['theme_href']=tinyMCE.baseURL+"/themes/"+theme;if(!tinyMCE.isIE||tinyMCE.isOpera)this.settings['force_br_newlines']=false;if(tinyMCE.getParam("popups_css",false)){var cssPath=tinyMCE.getParam("popups_css","");if(cssPath.indexOf('://')==-1&&cssPath.charAt(0)!='/')this.settings['popups_css']=this.documentBasePath+"/"+cssPath;else this.settings['popups_css']=cssPath}else this.settings['popups_css']=tinyMCE.baseURL+"/themes/"+theme+"/css/editor_popup.css";if(tinyMCE.getParam("editor_css",false)){var cssPath=tinyMCE.getParam("editor_css","");if(cssPath.indexOf('://')==-1&&cssPath.charAt(0)!='/')this.settings['editor_css']=this.documentBasePath+"/"+cssPath;else this.settings['editor_css']=cssPath}else{if(this.settings.editor_css!='')this.settings['editor_css']=tinyMCE.baseURL+"/themes/"+theme+"/css/editor_ui.css"}if(tinyMCE.settings['debug']){var msg="Debug: \n";msg+="baseURL: "+this.baseURL+"\n";msg+="documentBasePath: "+this.documentBasePath+"\n";msg+="content_css: "+this.settings['content_css']+"\n";msg+="popups_css: "+this.settings['popups_css']+"\n";msg+="editor_css: "+this.settings['editor_css']+"\n";alert(msg)}if(this.configs.length==0){if(typeof(TinyMCECompressed)=="undefined"){tinyMCE.addEvent(window,"DOMContentLoaded",TinyMCE_Engine.prototype.onLoad);if(tinyMCE.isRealIE){if(document.body)tinyMCE.addEvent(document.body,"readystatechange",TinyMCE_Engine.prototype.onLoad);else tinyMCE.addEvent(document,"readystatechange",TinyMCE_Engine.prototype.onLoad)}tinyMCE.addEvent(window,"load",TinyMCE_Engine.prototype.onLoad);tinyMCE._addUnloadEvents()}}this.loadScript(tinyMCE.baseURL+'/themes/'+this.settings['theme']+'/editor_template'+tinyMCE.srcMode+'.js');this.loadScript(tinyMCE.baseURL+'/langs/'+this.settings['language']+'.js');this.loadCSS(this.settings['editor_css']);var p=tinyMCE.getParam('plugins','',true,',');if(p.length>0){for(var i=0;i<p.length;i++){if(p[i].charAt(0)!='-')this.loadScript(tinyMCE.baseURL+'/plugins/'+p[i]+'/editor_plugin'+tinyMCE.srcMode+'.js')}}if(tinyMCE.getParam('entity_encoding')=='named'){settings['cleanup_entities']=new Array();var entities=tinyMCE.getParam('entities','',true,',');for(var i=0;i<entities.length;i+=2)settings['cleanup_entities']['c'+entities[i]]=entities[i+1]}settings['index']=this.configs.length;this.configs[this.configs.length]=settings;this.loadNextScript();if(this.isIE&&!this.isOpera){try{document.execCommand('BackgroundImageCache',false,true)}catch(e){}}this.xmlEncodeAposRe=new RegExp('[<>&"\']','g');this.xmlEncodeRe=new RegExp('[<>&"]','g');},_addUnloadEvents:function(){if(tinyMCE.isIE){if(tinyMCE.settings['add_unload_trigger']){tinyMCE.addEvent(window,"unload",TinyMCE_Engine.prototype.unloadHandler);tinyMCE.addEvent(window.document,"beforeunload",TinyMCE_Engine.prototype.unloadHandler)}}else{if(tinyMCE.settings['add_unload_trigger'])tinyMCE.addEvent(window,"unload",function(){tinyMCE.triggerSave(true,true)})}},_def:function(key,def_val,t){var v=tinyMCE.getParam(key,def_val);v=t?v.replace(/\s+/g,""):v;this.settings[key]=v},hasPlugin:function(n){return typeof(this.plugins[n])!="undefined"&&this.plugins[n]!=null},addPlugin:function(n,p){var op=this.plugins[n];p.baseURL=op?op.baseURL:tinyMCE.baseURL+"/plugins/"+n;this.plugins[n]=p;this.loadNextScript()},setPluginBaseURL:function(n,u){var op=this.plugins[n];if(op)op.baseURL=u;else this.plugins[n]={baseURL:u}},loadPlugin:function(n,u){u=u.indexOf('.js')!=-1?u.substring(0,u.lastIndexOf('/')):u;u=u.charAt(u.length-1)=='/'?u.substring(0,u.length-1):u;this.plugins[n]={baseURL:u};this.loadScript(u+"/editor_plugin"+(tinyMCE.srcMode?'_src':'')+".js")},hasTheme:function(n){return typeof(this.themes[n])!="undefined"&&this.themes[n]!=null},addTheme:function(n,t){this.themes[n]=t;this.loadNextScript()},addMenu:function(n,m){this.menus[n]=m},hasMenu:function(n){return typeof(this.plugins[n])!="undefined"&&this.plugins[n]!=null},loadScript:function(url){var i;for(i=0;i<this.loadedFiles.length;i++){if(this.loadedFiles[i]==url)return}if(tinyMCE.settings.strict_loading_mode)this.pendingFiles[this.pendingFiles.length]=url;else document.write('<sc'+'ript language="javascript" type="text/javascript" src="'+url+'"></script>');this.loadedFiles[this.loadedFiles.length]=url},loadNextScript:function(){var d=document,se;if(!tinyMCE.settings.strict_loading_mode)return;if(this.loadingIndex<this.pendingFiles.length){se=d.createElementNS('http://www.w3.org/1999/xhtml','script');se.setAttribute('language','javascript');se.setAttribute('type','text/javascript');se.setAttribute('src',this.pendingFiles[this.loadingIndex++]);d.getElementsByTagName("head")[0].appendChild(se)}else this.loadingIndex=-1;},loadCSS:function(url){var ar=url.replace(/\s+/,'').split(',');var lflen=0,csslen=0;var skip=false;var x=0,i=0,nl,le;for(x=0,csslen=ar.length;x<csslen;x++){if(ar[x]!=null&&ar[x]!='null'&&ar[x].length>0){for(i=0,lflen=this.loadedFiles.length;i<lflen;i++){if(this.loadedFiles[i]==ar[x]){skip=true;break}}if(!skip){if(tinyMCE.settings.strict_loading_mode){nl=document.getElementsByTagName("head");le=document.createElement('link');le.setAttribute('href',ar[x]);le.setAttribute('rel','stylesheet');le.setAttribute('type','text/css');nl[0].appendChild(le)}else document.write('<link href="'+ar[x]+'" rel="stylesheet" type="text/css" />');this.loadedFiles[this.loadedFiles.length]=ar[x]}}}},importCSS:function(doc,css){var css_ary=css.replace(/\s+/,'').split(',');var csslen,elm,headArr,x,css_file;for(x=0,csslen=css_ary.length;x<csslen;x++){css_file=css_ary[x];if(css_file!=null&&css_file!='null'&&css_file.length>0){if(css_file.indexOf('://')==-1&&css_file.charAt(0)!='/')css_file=this.documentBasePath+"/"+css_file;if(typeof(doc.createStyleSheet)=="undefined"){elm=doc.createElement("link");elm.rel="stylesheet";elm.href=css_file;if((headArr=doc.getElementsByTagName("head"))!=null&&headArr.length>0)headArr[0].appendChild(elm)}else doc.createStyleSheet(css_file)}}},confirmAdd:function(e,settings){var elm=tinyMCE.isIE?event.srcElement:e.target;var elementId=elm.name?elm.name:elm.id;tinyMCE.settings=settings;if(tinyMCE.settings['convert_on_click']||(!elm.getAttribute('mce_noask')&&confirm(tinyMCELang['lang_edit_confirm'])))tinyMCE.addMCEControl(elm,elementId);elm.setAttribute('mce_noask','true')},updateContent:function(form_element_name){var formElement=document.getElementById(form_element_name);for(var n in tinyMCE.instances){var inst=tinyMCE.instances[n];if(!tinyMCE.isInstance(inst))continue;inst.switchSettings();if(inst.formElement==formElement){var doc=inst.getDoc();tinyMCE._setHTML(doc,inst.formElement.value);if(!tinyMCE.isIE)doc.body.innerHTML=tinyMCE._cleanupHTML(inst,doc,this.settings,doc.body,inst.visualAid)}}},addMCEControl:function(replace_element,form_element_name,target_document){var id="mce_editor_"+tinyMCE.idCounter++;var inst=new TinyMCE_Control(tinyMCE.settings);inst.editorId=id;this.instances[id]=inst;inst._onAdd(replace_element,form_element_name,target_document)},removeInstance:function(ti){var t=[],n,i;for(n in tinyMCE.instances){i=tinyMCE.instances[n];if(tinyMCE.isInstance(i)&&ti!=i)t[n]=i}tinyMCE.instances=t;n=[];t=tinyMCE.undoLevels;for(i=0;i<t.length;i++){if(t[i]!=ti)n.push(t[i])}tinyMCE.undoLevels=n;tinyMCE.undoIndex=n.length;tinyMCE.dispatchCallback(ti,'remove_instance_callback','removeInstance',ti);return ti},removeMCEControl:function(editor_id){var inst=tinyMCE.getInstanceById(editor_id),h,re,ot,tn;if(inst){inst.switchSettings();editor_id=inst.editorId;h=tinyMCE.getContent(editor_id);this.removeInstance(inst);tinyMCE.selectedElement=null;tinyMCE.selectedInstance=null;re=document.getElementById(editor_id+"_parent");ot=inst.oldTargetElement;tn=ot.nodeName.toLowerCase();if(tn=="textarea"||tn=="input"){re.parentNode.removeChild(re);ot.style.display="inline";ot.value=h}else{ot.innerHTML=h;ot.style.display='block';re.parentNode.insertBefore(ot,re);re.parentNode.removeChild(re)}}},triggerSave:function(skip_cleanup,skip_callback){var inst,n;if(typeof(skip_cleanup)=="undefined")skip_cleanup=false;if(typeof(skip_callback)=="undefined")skip_callback=false;for(n in tinyMCE.instances){inst=tinyMCE.instances[n];if(!tinyMCE.isInstance(inst))continue;inst.triggerSave(skip_cleanup,skip_callback)}},resetForm:function(form_index){var i,inst,n,formObj=document.forms[form_index];for(n in tinyMCE.instances){inst=tinyMCE.instances[n];if(!tinyMCE.isInstance(inst))continue;inst.switchSettings();for(i=0;i<formObj.elements.length;i++){if(inst.formTargetElementId==formObj.elements[i].name)inst.getBody().innerHTML=inst.startContent}}},execInstanceCommand:function(editor_id,command,user_interface,value,focus){var inst=tinyMCE.getInstanceById(editor_id),r;if(inst){r=inst.selection.getRng();if(typeof(focus)=="undefined")focus=true;if(focus&&(!r||!r.item))inst.contentWindow.focus();inst.autoResetDesignMode();this.selectedElement=inst.getFocusElement();inst.select();tinyMCE.execCommand(command,user_interface,value);if(tinyMCE.isIE&&window.event!=null)tinyMCE.cancelEvent(window.event)}},execCommand:function(command,user_interface,value){var inst=tinyMCE.selectedInstance;user_interface=user_interface?user_interface:false;value=value?value:null;if(inst)inst.switchSettings();switch(command){case"Undo":if(this.getParam('custom_undo_redo_global')){if(this.undoIndex>0){tinyMCE.nextUndoRedoAction='Undo';inst=this.undoLevels[--this.undoIndex];inst.select();if(!tinyMCE.nextUndoRedoInstanceId)inst.execCommand('Undo')}}else inst.execCommand('Undo');return true;case"Redo":if(this.getParam('custom_undo_redo_global')){if(this.undoIndex<=this.undoLevels.length-1){tinyMCE.nextUndoRedoAction='Redo';inst=this.undoLevels[this.undoIndex++];inst.select();if(!tinyMCE.nextUndoRedoInstanceId)inst.execCommand('Redo')}}else inst.execCommand('Redo');return true;case'mceFocus':var inst=tinyMCE.getInstanceById(value);if(inst)inst.getWin().focus();return;case"mceAddControl":case"mceAddEditor":tinyMCE.addMCEControl(tinyMCE._getElementById(value),value);return;case"mceAddFrameControl":tinyMCE.addMCEControl(tinyMCE._getElementById(value['element'],value['document']),value['element'],value['document']);return;case"mceRemoveControl":case"mceRemoveEditor":tinyMCE.removeMCEControl(value);return;case"mceToggleEditor":var inst=tinyMCE.getInstanceById(value),pe,te;if(inst){pe=document.getElementById(inst.editorId+'_parent');te=inst.oldTargetElement;if(typeof(inst.enabled)=='undefined')inst.enabled=true;inst.enabled=!inst.enabled;if(!inst.enabled){pe.style.display='none';te.value=inst.getHTML();te.style.display=inst.oldTargetDisplay;tinyMCE.dispatchCallback(inst,'hide_instance_callback','hideInstance',inst)}else{pe.style.display='block';te.style.display='none';inst.setHTML(te.value);inst.useCSS=false;tinyMCE.dispatchCallback(inst,'show_instance_callback','showInstance',inst)}}else tinyMCE.addMCEControl(tinyMCE._getElementById(value),value);return;case"mceResetDesignMode":if(!tinyMCE.isIE){for(var n in tinyMCE.instances){if(!tinyMCE.isInstance(tinyMCE.instances[n]))continue;try{tinyMCE.instances[n].getDoc().designMode="on"}catch(e){}}}return}if(inst){inst.execCommand(command,user_interface,value)}else if(tinyMCE.settings['focus_alert'])alert(tinyMCELang['lang_focus_alert'])},_createIFrame:function(replace_element,doc,win){var iframe,id=replace_element.getAttribute("id");var aw,ah;if(typeof(doc)=="undefined")doc=document;if(typeof(win)=="undefined")win=window;iframe=doc.createElement("iframe");aw=""+tinyMCE.settings['area_width'];ah=""+tinyMCE.settings['area_height'];if(aw.indexOf('%')==-1){aw=parseInt(aw);aw=(isNaN(aw)||aw<0)?300:aw;aw=aw+"px"}if(ah.indexOf('%')==-1){ah=parseInt(ah);ah=(isNaN(ah)||ah<0)?240:ah;ah=ah+"px"}iframe.setAttribute("id",id);iframe.setAttribute("name",id);iframe.setAttribute("class","mceEditorIframe");iframe.setAttribute("border","0");iframe.setAttribute("frameBorder","0");iframe.setAttribute("marginWidth","0");iframe.setAttribute("marginHeight","0");iframe.setAttribute("leftMargin","0");iframe.setAttribute("topMargin","0");iframe.setAttribute("width",aw);iframe.setAttribute("height",ah);iframe.setAttribute("allowtransparency","true");iframe.className='mceEditorIframe';if(tinyMCE.settings["auto_resize"])iframe.setAttribute("scrolling","no");if(tinyMCE.isRealIE)iframe.setAttribute("src",this.settings['default_document']);iframe.style.width=aw;iframe.style.height=ah;if(tinyMCE.settings.strict_loading_mode)iframe.style.marginBottom='-5px';if(tinyMCE.isRealIE)replace_element.outerHTML=iframe.outerHTML;else replace_element.parentNode.replaceChild(iframe,replace_element);if(tinyMCE.isRealIE)return win.frames[id];else return iframe},setupContent:function(editor_id){var inst=tinyMCE.instances[editor_id],i;var doc=inst.getDoc();var head=doc.getElementsByTagName('head').item(0);var content=inst.startContent;if(tinyMCE.settings.strict_loading_mode){content=content.replace(/&lt;/g,'<');content=content.replace(/&gt;/g,'>');content=content.replace(/&quot;/g,'"');content=content.replace(/&amp;/g,'&')}tinyMCE.selectedInstance=inst;inst.switchSettings();if(!tinyMCE.isIE&&tinyMCE.getParam("setupcontent_reload",false)&&doc.title!="blank_page"){try{doc.location.href=tinyMCE.baseURL+"/blank.htm"}catch(ex){}window.setTimeout("tinyMCE.setupContent('"+editor_id+"');",1000);return}if(!head){window.setTimeout("tinyMCE.setupContent('"+editor_id+"');",10);return}tinyMCE.importCSS(inst.getDoc(),tinyMCE.baseURL+"/themes/"+inst.settings['theme']+"/css/editor_content.css");tinyMCE.importCSS(inst.getDoc(),inst.settings['content_css']);tinyMCE.dispatchCallback(inst,'init_instance_callback','initInstance',inst);if(tinyMCE.getParam('custom_undo_redo_keyboard_shortcuts')){inst.addShortcut('ctrl','z','lang_undo_desc','Undo');inst.addShortcut('ctrl','y','lang_redo_desc','Redo')}for(i=1;i<=6;i++)inst.addShortcut('ctrl',''+i,'','FormatBlock',false,'<h'+i+'>');inst.addShortcut('ctrl','7','','FormatBlock',false,'<p>');inst.addShortcut('ctrl','8','','FormatBlock',false,'<div>');inst.addShortcut('ctrl','9','','FormatBlock',false,'<address>');if(tinyMCE.isGecko){inst.addShortcut('ctrl','b','lang_bold_desc','Bold');inst.addShortcut('ctrl','i','lang_italic_desc','Italic');inst.addShortcut('ctrl','u','lang_underline_desc','Underline')}if(tinyMCE.getParam("convert_fonts_to_spans"))inst.getBody().setAttribute('id','mceSpanFonts');if(tinyMCE.settings['nowrap'])doc.body.style.whiteSpace="nowrap";doc.body.dir=this.settings['directionality'];doc.editorId=editor_id;if(!tinyMCE.isIE)doc.documentElement.editorId=editor_id;inst.setBaseHREF(tinyMCE.settings['base_href']);if(tinyMCE.settings['convert_newlines_to_brs']){content=tinyMCE.regexpReplace(content,"\r\n","<br />","gi");content=tinyMCE.regexpReplace(content,"\r","<br />","gi");content=tinyMCE.regexpReplace(content,"\n","<br />","gi")}content=tinyMCE.storeAwayURLs(content);content=tinyMCE._customCleanup(inst,"insert_to_editor",content);if(tinyMCE.isIE){window.setInterval('try{tinyMCE.getCSSClasses(tinyMCE.instances["'+editor_id+'"].getDoc(), "'+editor_id+'");}catch(e){}',500);if(tinyMCE.settings["force_br_newlines"])doc.styleSheets[0].addRule("p","margin: 0;");var body=inst.getBody();body.editorId=editor_id}content=tinyMCE.cleanupHTMLCode(content);if(!tinyMCE.isIE){var contentElement=inst.getDoc().createElement("body");var doc=inst.getDoc();contentElement.innerHTML=content;if(tinyMCE.isGecko&&tinyMCE.settings['remove_lt_gt'])content=content.replace(new RegExp('&lt;&gt;','g'),"");if(tinyMCE.settings['cleanup_on_startup'])tinyMCE.setInnerHTML(inst.getBody(),tinyMCE._cleanupHTML(inst,doc,this.settings,contentElement));else tinyMCE.setInnerHTML(inst.getBody(),content);tinyMCE.convertAllRelativeURLs(inst.getBody())}else{if(tinyMCE.settings['cleanup_on_startup']){tinyMCE._setHTML(inst.getDoc(),content);eval('try {tinyMCE.setInnerHTML(inst.getBody(), tinyMCE._cleanupHTML(inst, inst.contentDocument, this.settings, inst.getBody()));} catch(e) {}')}else tinyMCE._setHTML(inst.getDoc(),content)}tinyMCE.handleVisualAid(inst.getBody(),true,tinyMCE.settings['visual'],inst);tinyMCE.dispatchCallback(inst,'setupcontent_callback','setupContent',editor_id,inst.getBody(),inst.getDoc());if(!tinyMCE.isIE)tinyMCE.addEventHandlers(inst);if(tinyMCE.isIE){tinyMCE.addEvent(inst.getBody(),"blur",TinyMCE_Engine.prototype._eventPatch);tinyMCE.addEvent(inst.getBody(),"beforedeactivate",TinyMCE_Engine.prototype._eventPatch);if(!tinyMCE.isOpera){tinyMCE.addEvent(doc.body,"mousemove",TinyMCE_Engine.prototype.onMouseMove);tinyMCE.addEvent(doc.body,"beforepaste",TinyMCE_Engine.prototype._eventPatch);tinyMCE.addEvent(doc.body,"drop",TinyMCE_Engine.prototype._eventPatch)}}inst.select();tinyMCE.selectedElement=inst.contentWindow.document.body;tinyMCE._customCleanup(inst,"insert_to_editor_dom",inst.getBody());tinyMCE._customCleanup(inst,"setup_content_dom",inst.getBody());tinyMCE._setEventsEnabled(inst.getBody(),false);tinyMCE.cleanupAnchors(inst.getDoc());if(tinyMCE.getParam("convert_fonts_to_spans"))tinyMCE.convertSpansToFonts(inst.getDoc());inst.startContent=tinyMCE.trim(inst.getBody().innerHTML);inst.undoRedo.add({content:inst.startContent});if(tinyMCE.isGecko){tinyMCE.selectNodes(inst.getBody(),function(n){if(n.nodeType==3||n.nodeType==8)n.nodeValue=n.nodeValue.replace(new RegExp('\\s(mce_src|mce_href)=\"[^\"]*\"','gi'),"");return false})}if(tinyMCE.isGecko)inst.getBody().spellcheck=tinyMCE.getParam("gecko_spellcheck");tinyMCE._removeInternal(inst.getBody());inst.select();tinyMCE.triggerNodeChange(false,true)},storeAwayURLs:function(s){if(!s.match(/(mce_src|mce_href)/gi,s)){s=s.replace(new RegExp('src\\s*=\\s*\"([^ >\"]*)\"','gi'),'src="$1" mce_src="$1"');s=s.replace(new RegExp('href\\s*=\\s*\"([^ >\"]*)\"','gi'),'href="$1" mce_href="$1"')}return s},_removeInternal:function(n){if(tinyMCE.isGecko){tinyMCE.selectNodes(n,function(n){if(n.nodeType==3||n.nodeType==8)n.nodeValue=n.nodeValue.replace(new RegExp('\\s(mce_src|mce_href)=\"[^\"]*\"','gi'),"");return false})}},removeTinyMCEFormElements:function(form_obj){var i,elementId;if(!tinyMCE.getParam('hide_selects_on_submit'))return;if(typeof(form_obj)=="undefined"||form_obj==null)return;if(form_obj.nodeName!="FORM"){if(form_obj.form)form_obj=form_obj.form;else form_obj=tinyMCE.getParentElement(form_obj,"form")}if(form_obj==null)return;for(i=0;i<form_obj.elements.length;i++){elementId=form_obj.elements[i].name?form_obj.elements[i].name:form_obj.elements[i].id;if(elementId.indexOf('mce_editor_')==0)form_obj.elements[i].disabled=true}},handleEvent:function(e){var inst=tinyMCE.selectedInstance;if(typeof(tinyMCE)=="undefined")return true;if(tinyMCE.executeCallback(tinyMCE.selectedInstance,'handle_event_callback','handleEvent',e))return false;switch(e.type){case"beforedeactivate":case"blur":if(tinyMCE.selectedInstance)tinyMCE.selectedInstance.execCommand('mceEndTyping');tinyMCE.hideMenus();return;case"drop":case"beforepaste":if(tinyMCE.selectedInstance)tinyMCE.selectedInstance.setBaseHREF(null);if(tinyMCE.isRealIE){var ife=tinyMCE.selectedInstance.iframeElement;if(ife.style.height.indexOf('%')!=-1){ife._oldHeight=ife.style.height;ife.style.height=ife.clientHeight}}window.setTimeout("tinyMCE.selectedInstance.setBaseHREF(tinyMCE.settings['base_href']);tinyMCE._resetIframeHeight();",1);return;case"submit":tinyMCE.removeTinyMCEFormElements(tinyMCE.isMSIE?window.event.srcElement:e.target);tinyMCE.triggerSave();tinyMCE.isNotDirty=true;return;case"reset":var formObj=tinyMCE.isIE?window.event.srcElement:e.target;for(var i=0;i<document.forms.length;i++){if(document.forms[i]==formObj)window.setTimeout('tinyMCE.resetForm('+i+');',10)}return;case"keypress":if(inst&&inst.handleShortcut(e))return false;if(e.target.editorId){tinyMCE.instances[e.target.editorId].select()}else{if(e.target.ownerDocument.editorId)tinyMCE.instances[e.target.ownerDocument.editorId].select()}if(tinyMCE.selectedInstance)tinyMCE.selectedInstance.switchSettings();if((tinyMCE.isGecko||tinyMCE.isOpera||tinyMCE.isSafari)&&tinyMCE.settings['force_p_newlines']&&e.keyCode==13&&!e.shiftKey){if(TinyMCE_ForceParagraphs._insertPara(tinyMCE.selectedInstance,e)){tinyMCE.execCommand("mceAddUndoLevel");return tinyMCE.cancelEvent(e)}}if((tinyMCE.isGecko&&!tinyMCE.isSafari)&&tinyMCE.settings['force_p_newlines']&&(e.keyCode==8||e.keyCode==46)&&!e.shiftKey){if(TinyMCE_ForceParagraphs._handleBackSpace(tinyMCE.selectedInstance,e.type)){tinyMCE.execCommand("mceAddUndoLevel");return tinyMCE.cancelEvent(e)}}if(tinyMCE.isIE&&tinyMCE.settings['force_br_newlines']&&e.keyCode==13){if(e.target.editorId)tinyMCE.instances[e.target.editorId].select();if(tinyMCE.selectedInstance){var sel=tinyMCE.selectedInstance.getDoc().selection;var rng=sel.createRange();if(tinyMCE.getParentElement(rng.parentElement(),"li")!=null)return false;e.returnValue=false;e.cancelBubble=true;rng.pasteHTML("<br />");rng.collapse(false);rng.select();tinyMCE.execCommand("mceAddUndoLevel");tinyMCE.triggerNodeChange(false);return false}}if(e.keyCode==8||e.keyCode==46){tinyMCE.selectedElement=e.target;tinyMCE.linkElement=tinyMCE.getParentElement(e.target,"a");tinyMCE.imgElement=tinyMCE.getParentElement(e.target,"img");tinyMCE.triggerNodeChange(false)}return false;break;case"keyup":case"keydown":tinyMCE.hideMenus();tinyMCE.hasMouseMoved=false;if(inst&&inst.handleShortcut(e))return false;if(e.target.editorId)tinyMCE.instances[e.target.editorId].select();if(tinyMCE.selectedInstance)tinyMCE.selectedInstance.switchSettings();var inst=tinyMCE.selectedInstance;if(tinyMCE.isGecko&&tinyMCE.settings['force_p_newlines']&&(e.keyCode==8||e.keyCode==46)&&!e.shiftKey){if(TinyMCE_ForceParagraphs._handleBackSpace(tinyMCE.selectedInstance,e.type)){tinyMCE.execCommand("mceAddUndoLevel");e.preventDefault();return false}}tinyMCE.selectedElement=null;tinyMCE.selectedNode=null;var elm=tinyMCE.selectedInstance.getFocusElement();tinyMCE.linkElement=tinyMCE.getParentElement(elm,"a");tinyMCE.imgElement=tinyMCE.getParentElement(elm,"img");tinyMCE.selectedElement=elm;if(tinyMCE.isGecko&&e.type=="keyup"&&e.keyCode==9)tinyMCE.handleVisualAid(tinyMCE.selectedInstance.getBody(),true,tinyMCE.settings['visual'],tinyMCE.selectedInstance);if(tinyMCE.isIE&&e.type=="keydown"&&e.keyCode==13)tinyMCE.enterKeyElement=tinyMCE.selectedInstance.getFocusElement();if(tinyMCE.isIE&&e.type=="keyup"&&e.keyCode==13){var elm=tinyMCE.enterKeyElement;if(elm){var re=new RegExp('^HR|IMG|BR$','g');var dre=new RegExp('^H[1-6]$','g');if(!elm.hasChildNodes()&&!re.test(elm.nodeName)){if(dre.test(elm.nodeName))elm.innerHTML="&nbsp;&nbsp;";else elm.innerHTML="&nbsp;"}}}var keys=tinyMCE.posKeyCodes;var posKey=false;for(var i=0;i<keys.length;i++){if(keys[i]==e.keyCode){posKey=true;break}}if(tinyMCE.isIE&&tinyMCE.settings['custom_undo_redo']){var keys=new Array(8,46);for(var i=0;i<keys.length;i++){if(keys[i]==e.keyCode){if(e.type=="keyup")tinyMCE.triggerNodeChange(false)}}}if(e.keyCode==17)return true;if(tinyMCE.isGecko){if(!posKey&&e.type=="keyup"&&!e.ctrlKey||(e.ctrlKey&&(e.keyCode==86||e.keyCode==88)))tinyMCE.execCommand("mceStartTyping")}else{if(!posKey&&e.type=="keyup")tinyMCE.execCommand("mceStartTyping")}if(e.type=="keydown"&&(posKey||e.ctrlKey)&&inst)inst.undoBookmark=inst.selection.getBookmark();if(e.type=="keyup"&&(posKey||e.ctrlKey))tinyMCE.execCommand("mceEndTyping");if(posKey&&e.type=="keyup")tinyMCE.triggerNodeChange(false);if(tinyMCE.isIE&&e.ctrlKey)window.setTimeout('tinyMCE.triggerNodeChange(false);',1);break;case"mousedown":case"mouseup":case"click":case"dblclick":case"focus":tinyMCE.hideMenus();if(tinyMCE.selectedInstance){tinyMCE.selectedInstance.switchSettings();tinyMCE.selectedInstance.isFocused=true}var targetBody=tinyMCE.getParentElement(e.target,"html");for(var instanceName in tinyMCE.instances){if(!tinyMCE.isInstance(tinyMCE.instances[instanceName]))continue;var inst=tinyMCE.instances[instanceName];inst.autoResetDesignMode();if(inst.getBody().parentNode==targetBody){inst.select();tinyMCE.selectedElement=e.target;tinyMCE.linkElement=tinyMCE.getParentElement(tinyMCE.selectedElement,"a");tinyMCE.imgElement=tinyMCE.getParentElement(tinyMCE.selectedElement,"img");break}}if(!tinyMCE.selectedInstance.undoRedo.undoLevels[0].bookmark&&(e.type=="mouseup"||e.type=="dblclick"))tinyMCE.selectedInstance.undoRedo.undoLevels[0].bookmark=tinyMCE.selectedInstance.selection.getBookmark();if(e.type!="focus")tinyMCE.selectedNode=null;tinyMCE.triggerNodeChange(false);tinyMCE.execCommand("mceEndTyping");if(e.type=="mouseup")tinyMCE.execCommand("mceAddUndoLevel");if(!tinyMCE.selectedInstance&&e.target.editorId)tinyMCE.instances[e.target.editorId].select();return false;break}},getButtonHTML:function(id,lang,img,cmd,ui,val){var h='',m,x,io='';cmd='tinyMCE.execInstanceCommand(\'{$editor_id}\',\''+cmd+'\'';if(typeof(ui)!="undefined"&&ui!=null)cmd+=','+ui;if(typeof(val)!="undefined"&&val!=null)cmd+=",'"+val+"'";cmd+=');';if(tinyMCE.isRealIE)io='onmouseover="tinyMCE.lastHover = this;"';if(tinyMCE.getParam('button_tile_map')&&(!tinyMCE.isIE||tinyMCE.isOpera)&&(m=this.buttonMap[id])!=null&&(tinyMCE.getParam("language")=="en"||img.indexOf('$lang')==-1)){x=0-(m*20)==0?'0':0-(m*20);h+='<a id="{$editor_id}_'+id+'" href="javascript:'+cmd+'" onclick="'+cmd+'return false;" onmousedown="return false;" '+io+' class="mceTiledButton mceButtonNormal" target="_self">';h+='<img src="{$themeurl}/images/spacer.gif" style="background-position: '+x+'px 0" title="{$'+lang+'}" />';h+='</a>'}else{h+='<a id="{$editor_id}_'+id+'" href="javascript:'+cmd+'" onclick="'+cmd+'return false;" onmousedown="return false;" '+io+' class="mceButtonNormal" target="_self">';h+='<img src="'+img+'" title="{$'+lang+'}" />';h+='</a>'}return h},getMenuButtonHTML:function(id,lang,img,mcmd,cmd,ui,val){var h='',m,x;mcmd='tinyMCE.execInstanceCommand(\'{$editor_id}\',\''+mcmd+'\');';cmd='tinyMCE.execInstanceCommand(\'{$editor_id}\',\''+cmd+'\'';if(typeof(ui)!="undefined"&&ui!=null)cmd+=','+ui;if(typeof(val)!="undefined"&&val!=null)cmd+=",'"+val+"'";cmd+=');';if(tinyMCE.getParam('button_tile_map')&&(!tinyMCE.isIE||tinyMCE.isOpera)&&(m=tinyMCE.buttonMap[id])!=null&&(tinyMCE.getParam("language")=="en"||img.indexOf('$lang')==-1)){x=0-(m*20)==0?'0':0-(m*20);if(tinyMCE.isRealIE)h+='<span id="{$editor_id}_'+id+'" class="mceMenuButton" onmouseover="tinyMCE._menuButtonEvent(\'over\',this);tinyMCE.lastHover = this;" onmouseout="tinyMCE._menuButtonEvent(\'out\',this);">';else h+='<span id="{$editor_id}_'+id+'" class="mceMenuButton">';h+='<a href="javascript:'+cmd+'" onclick="'+cmd+'return false;" onmousedown="return false;" class="mceTiledButton mceMenuButtonNormal" target="_self">';h+='<img src="{$themeurl}/images/spacer.gif" style="width: 20px; height: 20px; background-position: '+x+'px 0" title="{$'+lang+'}" /></a>';h+='<a href="javascript:'+mcmd+'" onclick="'+mcmd+'return false;" onmousedown="return false;"><img src="{$themeurl}/images/button_menu.gif" title="{$'+lang+'}" class="mceMenuButton" />';h+='</a></span>'}else{if(tinyMCE.isRealIE)h+='<span id="{$editor_id}_'+id+'" dir="ltr" class="mceMenuButton" onmouseover="tinyMCE._menuButtonEvent(\'over\',this);tinyMCE.lastHover = this;" onmouseout="tinyMCE._menuButtonEvent(\'out\',this);">';else h+='<span id="{$editor_id}_'+id+'" dir="ltr" class="mceMenuButton">';h+='<a href="javascript:'+cmd+'" onclick="'+cmd+'return false;" onmousedown="return false;" class="mceMenuButtonNormal" target="_self">';h+='<img src="'+img+'" title="{$'+lang+'}" /></a>';h+='<a href="javascript:'+mcmd+'" onclick="'+mcmd+'return false;" onmousedown="return false;"><img src="{$themeurl}/images/button_menu.gif" title="{$'+lang+'}" class="mceMenuButton" />';h+='</a></span>'}return h},_menuButtonEvent:function(e,o){if(o.className=='mceMenuButtonFocus')return;if(e=='over')o.className=o.className+' mceMenuHover';else o.className=o.className.replace(/\s.*$/,'')},addButtonMap:function(m){var i,a=m.replace(/\s+/,'').split(',');for(i=0;i<a.length;i++)this.buttonMap[a[i]]=i},submitPatch:function(){tinyMCE.removeTinyMCEFormElements(this);tinyMCE.triggerSave();tinyMCE.isNotDirty=true;this.mceOldSubmit()},onLoad:function(){var r;if(tinyMCE.settings.strict_loading_mode&&this.loadingIndex!=-1){window.setTimeout('tinyMCE.onLoad();',1);return}if(tinyMCE.isRealIE&&window.event.type=="readystatechange"&&document.readyState!="complete")return true;if(tinyMCE.isLoaded)return true;tinyMCE.isLoaded=true;if(tinyMCE.isRealIE&&document.body){r=document.body.createTextRange();r.collapse(true);r.select()}tinyMCE.dispatchCallback(null,'onpageload','onPageLoad');for(var c=0;c<tinyMCE.configs.length;c++){tinyMCE.settings=tinyMCE.configs[c];var selector=tinyMCE.getParam("editor_selector");var deselector=tinyMCE.getParam("editor_deselector");var elementRefAr=new Array();if(document.forms&&tinyMCE.settings['add_form_submit_trigger']&&!tinyMCE.submitTriggers){for(var i=0;i<document.forms.length;i++){var form=document.forms[i];tinyMCE.addEvent(form,"submit",TinyMCE_Engine.prototype.handleEvent);tinyMCE.addEvent(form,"reset",TinyMCE_Engine.prototype.handleEvent);tinyMCE.submitTriggers=true;if(tinyMCE.settings['submit_patch']){try{form.mceOldSubmit=form.submit;form.submit=TinyMCE_Engine.prototype.submitPatch}catch(e){}}}}var mode=tinyMCE.settings['mode'];switch(mode){case"exact":var elements=tinyMCE.getParam('elements','',true,',');for(var i=0;i<elements.length;i++){var element=tinyMCE._getElementById(elements[i]);var trigger=element?element.getAttribute(tinyMCE.settings['textarea_trigger']):"";if(new RegExp('\\b'+deselector+'\\b').test(tinyMCE.getAttrib(element,"class")))continue;if(trigger=="false")continue;if((tinyMCE.settings['ask']||tinyMCE.settings['convert_on_click'])&&element){elementRefAr[elementRefAr.length]=element;continue}if(element)tinyMCE.addMCEControl(element,elements[i]);else if(tinyMCE.settings['debug'])alert("Error: Could not find element by id or name: "+elements[i])}break;case"specific_textareas":case"textareas":var nodeList=document.getElementsByTagName("textarea");for(var i=0;i<nodeList.length;i++){var elm=nodeList.item(i);var trigger=elm.getAttribute(tinyMCE.settings['textarea_trigger']);if(selector!=''&&!new RegExp('\\b'+selector+'\\b').test(tinyMCE.getAttrib(elm,"class")))continue;if(selector!='')trigger=selector!=""?"true":"";if(new RegExp('\\b'+deselector+'\\b').test(tinyMCE.getAttrib(elm,"class")))continue;if((mode=="specific_textareas"&&trigger=="true")||(mode=="textareas"&&trigger!="false"))elementRefAr[elementRefAr.length]=elm}break}for(var i=0;i<elementRefAr.length;i++){var element=elementRefAr[i];var elementId=element.name?element.name:element.id;if(tinyMCE.settings['ask']||tinyMCE.settings['convert_on_click']){if(tinyMCE.isGecko){var settings=tinyMCE.settings;tinyMCE.addEvent(element,"focus",function(e){window.setTimeout(function(){TinyMCE_Engine.prototype.confirmAdd(e,settings)},10)});if(element.nodeName!="TEXTAREA"&&element.nodeName!="INPUT")tinyMCE.addEvent(element,"click",function(e){window.setTimeout(function(){TinyMCE_Engine.prototype.confirmAdd(e,settings)},10)});}else{var settings=tinyMCE.settings;tinyMCE.addEvent(element,"focus",function(){TinyMCE_Engine.prototype.confirmAdd(null,settings)});tinyMCE.addEvent(element,"click",function(){TinyMCE_Engine.prototype.confirmAdd(null,settings)});}}else tinyMCE.addMCEControl(element,elementId)}if(tinyMCE.settings['auto_focus']){window.setTimeout(function(){var inst=tinyMCE.getInstanceById(tinyMCE.settings['auto_focus']);inst.selection.selectNode(inst.getBody(),true,true);inst.contentWindow.focus()},100)}tinyMCE.dispatchCallback(null,'oninit','onInit')}},isInstance:function(o){return o!=null&&typeof(o)=="object"&&o.isTinyMCE_Control},getParam:function(name,default_value,strip_whitespace,split_chr){var value=(typeof(this.settings[name])=="undefined")?default_value:this.settings[name];if(value=="true"||value=="false")return(value=="true");if(strip_whitespace)value=tinyMCE.regexpReplace(value,"[ \t\r\n]","");if(typeof(split_chr)!="undefined"&&split_chr!=null){value=value.split(split_chr);var outArray=new Array();for(var i=0;i<value.length;i++){if(value[i]&&value[i]!="")outArray[outArray.length]=value[i]}value=outArray}return value},getLang:function(name,default_value,parse_entities,va){var v=(typeof(tinyMCELang[name])=="undefined")?default_value:tinyMCELang[name],n;if(parse_entities)v=tinyMCE.entityDecode(v);if(va){for(n in va)v=this.replaceVar(v,n,va[n])}return v},entityDecode:function(s){var e=document.createElement("div");e.innerHTML=s;return e.firstChild.nodeValue},addToLang:function(prefix,ar){for(var key in ar){if(typeof(ar[key])=='function')continue;tinyMCELang[(key.indexOf('lang_')==-1?'lang_':'')+(prefix!=''?(prefix+"_"):'')+key]=ar[key]}this.loadNextScript();},triggerNodeChange:function(focus,setup_content){var elm,inst,editorId,undoIndex=-1,undoLevels=-1,doc,anySelection=false,st;if(tinyMCE.selectedInstance){inst=tinyMCE.selectedInstance;elm=(typeof(setup_content)!="undefined"&&setup_content)?tinyMCE.selectedElement:inst.getFocusElement();editorId=inst.editorId;st=inst.selection.getSelectedText();if(tinyMCE.settings.auto_resize)inst.resizeToContent();if(setup_content&&tinyMCE.isGecko&&inst.isHidden())elm=inst.getBody();inst.switchSettings();if(tinyMCE.selectedElement)anySelection=(tinyMCE.selectedElement.nodeName.toLowerCase()=="img")||(st&&st.length>0);if(tinyMCE.settings['custom_undo_redo']){undoIndex=inst.undoRedo.undoIndex;undoLevels=inst.undoRedo.undoLevels.length}tinyMCE.dispatchCallback(inst,'handle_node_change_callback','handleNodeChange',editorId,elm,undoIndex,undoLevels,inst.visualAid,anySelection,setup_content)}if(this.selectedInstance&&(typeof(focus)=="undefined"||focus))this.selectedInstance.contentWindow.focus()},_customCleanup:function(inst,type,content){var pl,po,i;var customCleanup=tinyMCE.settings['cleanup_callback'];if(customCleanup!=""&&eval("typeof("+customCleanup+")")!="undefined")content=eval(customCleanup+"(type, content, inst);");po=tinyMCE.themes[tinyMCE.settings['theme']];if(po&&po.cleanup)content=po.cleanup(type,content,inst);pl=inst.plugins;for(i=0;i<pl.length;i++){po=tinyMCE.plugins[pl[i]];if(po&&po.cleanup)content=po.cleanup(type,content,inst)}return content},setContent:function(h){if(tinyMCE.selectedInstance){tinyMCE.selectedInstance.execCommand('mceSetContent',false,h);tinyMCE.selectedInstance.repaint()}},importThemeLanguagePack:function(name){if(typeof(name)=="undefined")name=tinyMCE.settings['theme'];tinyMCE.loadScript(tinyMCE.baseURL+'/themes/'+name+'/langs/'+tinyMCE.settings['language']+'.js')},importPluginLanguagePack:function(name){var b=tinyMCE.baseURL+'/plugins/'+name;if(this.plugins[name])b=this.plugins[name].baseURL;tinyMCE.loadScript(b+'/langs/'+tinyMCE.settings['language']+'.js')},applyTemplate:function(h,as){return h.replace(new RegExp('\\{\\$([a-z0-9_]+)\\}','gi'),function(m,s){if(s.indexOf('lang_')==0&&tinyMCELang[s])return tinyMCELang[s];if(as&&as[s])return as[s];if(tinyMCE.settings[s])return tinyMCE.settings[s];if(m=='themeurl')return tinyMCE.themeURL;return m})},replaceVar:function(h,r,v){return h.replace(new RegExp('{\\\$'+r+'}','g'),v)},openWindow:function(template,args){var html,width,height,x,y,resizable,scrollbars,url;args=!args?{}:args;args['mce_template_file']=template['file'];args['mce_width']=template['width'];args['mce_height']=template['height'];tinyMCE.windowArgs=args;html=template['html'];if(!(width=parseInt(template['width'])))width=320;if(!(height=parseInt(template['height'])))height=200;if(tinyMCE.isIE)height+=40;else height+=20;x=parseInt(screen.width/ 2.0) - (width /2.0);y=parseInt(screen.height/ 2.0) - (height /2.0);resizable=(args&&args['resizable'])?args['resizable']:"no";scrollbars=(args&&args['scrollbars'])?args['scrollbars']:"no";if(template['file'].charAt(0)!='/'&&template['file'].indexOf('://')==-1)url=tinyMCE.baseURL+"/themes/"+tinyMCE.getParam("theme")+"/"+template['file'];else url=template['file'];for(var name in args){if(typeof(args[name])=='function')continue;url=tinyMCE.replaceVar(url,name,escape(args[name]))}if(html){html=tinyMCE.replaceVar(html,"css",this.settings['popups_css']);html=tinyMCE.applyTemplate(html,args);var win=window.open("","mcePopup"+new Date().getTime(),"top="+y+",left="+x+",scrollbars="+scrollbars+",dialog=yes,minimizable="+resizable+",modal=yes,width="+width+",height="+height+",resizable="+resizable);if(win==null){alert(tinyMCELang['lang_popup_blocked']);return}win.document.write(html);win.document.close();win.resizeTo(width,height);win.focus()}else{if((tinyMCE.isRealIE)&&resizable!='yes'&&tinyMCE.settings["dialog_type"]=="modal"){height+=10;var features="resizable:"+resizable+";scroll:"+scrollbars+";status:yes;center:yes;help:no;dialogWidth:"+width+"px;dialogHeight:"+height+"px;";window.showModalDialog(url,window,features)}else{var modal=(resizable=="yes")?"no":"yes";if(tinyMCE.isGecko&&tinyMCE.isMac)modal="no";if(template['close_previous']!="no")try{tinyMCE.lastWindow.close()}catch(ex){}var win=window.open(url,"mcePopup"+new Date().getTime(),"top="+y+",left="+x+",scrollbars="+scrollbars+",dialog="+modal+",minimizable="+resizable+",modal="+modal+",width="+width+",height="+height+",resizable="+resizable);if(win==null){alert(tinyMCELang['lang_popup_blocked']);return}if(template['close_previous']!="no")tinyMCE.lastWindow=win;eval('try { win.resizeTo(width, height); } catch(e) { }');if(tinyMCE.isGecko){if(win.document.defaultView.statusbar.visible)win.resizeBy(0,tinyMCE.isMac?10:24)}win.focus()}}},closeWindow:function(win){win.close()},getVisualAidClass:function(class_name,state){var aidClass=tinyMCE.settings['visual_table_class'];if(typeof(state)=="undefined")state=tinyMCE.settings['visual'];var classNames=new Array();var ar=class_name.split(' ');for(var i=0;i<ar.length;i++){if(ar[i]==aidClass)ar[i]="";if(ar[i]!="")classNames[classNames.length]=ar[i]}if(state)classNames[classNames.length]=aidClass;var className="";for(var i=0;i<classNames.length;i++){if(i>0)className+=" ";className+=classNames[i]}return className},handleVisualAid:function(el,deep,state,inst,skip_dispatch){if(!el)return;if(!skip_dispatch)tinyMCE.dispatchCallback(inst,'handle_visual_aid_callback','handleVisualAid',el,deep,state,inst);var tableElement=null;switch(el.nodeName){case"TABLE":var oldW=el.style.width;var oldH=el.style.height;var bo=tinyMCE.getAttrib(el,"border");bo=bo==""||bo=="0"?true:false;tinyMCE.setAttrib(el,"class",tinyMCE.getVisualAidClass(tinyMCE.getAttrib(el,"class"),state&&bo));el.style.width=oldW;el.style.height=oldH;for(var y=0;y<el.rows.length;y++){for(var x=0;x<el.rows[y].cells.length;x++){var cn=tinyMCE.getVisualAidClass(tinyMCE.getAttrib(el.rows[y].cells[x],"class"),state&&bo);tinyMCE.setAttrib(el.rows[y].cells[x],"class",cn)}}break;case"A":var anchorName=tinyMCE.getAttrib(el,"name");if(anchorName!=''&&state){el.title=anchorName;tinyMCE.addCSSClass(el,'mceItemAnchor')}else if(anchorName!=''&&!state)el.className='';break}if(deep&&el.hasChildNodes()){for(var i=0;i<el.childNodes.length;i++)tinyMCE.handleVisualAid(el.childNodes[i],deep,state,inst,true)}},fixGeckoBaseHREFBug:function(m,e,h){var xsrc,xhref;if(tinyMCE.isGecko){if(m==1){h=h.replace(/\ssrc=/gi," mce_tsrc=");h=h.replace(/\shref=/gi," mce_thref=");return h}else{if(!new RegExp('(src|href)=','g').test(h))return h;tinyMCE.selectElements(e,'A,IMG,SELECT,AREA,IFRAME,BASE,INPUT,SCRIPT,EMBED,OBJECT,LINK',function(n){xsrc=tinyMCE.getAttrib(n,"mce_tsrc");xhref=tinyMCE.getAttrib(n,"mce_thref");if(xsrc!=""){try{n.src=tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'],xsrc)}catch(e){}n.removeAttribute("mce_tsrc")}if(xhref!=""){try{n.href=tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'],xhref)}catch(e){}n.removeAttribute("mce_thref")}return false});tinyMCE.selectNodes(e,function(n){if(n.nodeType==3||n.nodeType==8){n.nodeValue=n.nodeValue.replace(/\smce_tsrc=/gi," src=");n.nodeValue=n.nodeValue.replace(/\smce_thref=/gi," href=")}return false})}}return h},_setHTML:function(doc,html_content){html_content=tinyMCE.cleanupHTMLCode(html_content);try{tinyMCE.setInnerHTML(doc.body,html_content)}catch(e){if(this.isMSIE)doc.body.createTextRange().pasteHTML(html_content)}if(tinyMCE.isIE&&tinyMCE.settings['fix_content_duplication']){var paras=doc.getElementsByTagName("P");for(var i=0;i<paras.length;i++){var node=paras[i];while((node=node.parentNode)!=null){if(node.nodeName=="P")node.outerHTML=node.innerHTML}}var html=doc.body.innerHTML;tinyMCE.setInnerHTML(doc.body,html)}tinyMCE.cleanupAnchors(doc);if(tinyMCE.getParam("convert_fonts_to_spans"))tinyMCE.convertSpansToFonts(doc)},getEditorId:function(form_element){var inst=this.getInstanceById(form_element);if(!inst)return null;return inst.editorId},getInstanceById:function(editor_id){var inst=this.instances[editor_id];if(!inst){for(var n in tinyMCE.instances){var instance=tinyMCE.instances[n];if(!tinyMCE.isInstance(instance))continue;if(instance.formTargetElementId==editor_id){inst=instance;break}}}return inst},queryInstanceCommandValue:function(editor_id,command){var inst=tinyMCE.getInstanceById(editor_id);if(inst)return inst.queryCommandValue(command);return false},queryInstanceCommandState:function(editor_id,command){var inst=tinyMCE.getInstanceById(editor_id);if(inst)return inst.queryCommandState(command);return null},setWindowArg:function(n,v){this.windowArgs[n]=v},getWindowArg:function(n,d){return(typeof(this.windowArgs[n])=="undefined")?d:this.windowArgs[n]},getCSSClasses:function(editor_id,doc){var inst=tinyMCE.getInstanceById(editor_id);if(inst&&inst.cssClasses.length>0)return inst.cssClasses;if(typeof(editor_id)=="undefined"&&typeof(doc)=="undefined"){var instance;for(var instanceName in tinyMCE.instances){instance=tinyMCE.instances[instanceName];if(!tinyMCE.isInstance(instance))continue;break}doc=instance.getDoc()}if(typeof(doc)=="undefined"){var instance=tinyMCE.getInstanceById(editor_id);doc=instance.getDoc()}if(doc){var styles=doc.styleSheets;if(styles&&styles.length>0){for(var x=0;x<styles.length;x++){var csses=null;eval("try {var csses = tinyMCE.isIE ? doc.styleSheets("+x+").rules : styles["+x+"].cssRules;} catch(e) {}");if(!csses)return new Array();for(var i=0;i<csses.length;i++){var selectorText=csses[i].selectorText;if(selectorText){var rules=selectorText.split(',');for(var c=0;c<rules.length;c++){var rule=rules[c];while(rule.indexOf(' ')==0)rule=rule.substring(1);if(rule.indexOf(' ')!=-1||rule.indexOf(':')!=-1||rule.indexOf('mceItem')!=-1)continue;if(rule.indexOf(tinyMCE.settings['visual_table_class'])!=-1||rule.indexOf('mceEditable')!=-1||rule.indexOf('mceNonEditable')!=-1)continue;if(rule.indexOf('.')!=-1){var cssClass=rule.substring(rule.indexOf('.')+1);var addClass=true;for(var p=0;p<inst.cssClasses.length&&addClass;p++){if(inst.cssClasses[p]==cssClass)addClass=false}if(addClass)inst.cssClasses[inst.cssClasses.length]=cssClass}}}}}}}return inst.cssClasses},regexpReplace:function(in_str,reg_exp,replace_str,opts){if(in_str==null)return in_str;if(typeof(opts)=="undefined")opts='g';var re=new RegExp(reg_exp,opts);return in_str.replace(re,replace_str)},trim:function(s){return s.replace(/^\s*|\s*$/g,"")},cleanupEventStr:function(s){s=""+s;s=s.replace('function anonymous()\n{\n','');s=s.replace('\n}','');s=s.replace(/^return true;/gi,'');return s},getControlHTML:function(c){var i,l,n,o,v,rtl=tinyMCE.getLang('lang_dir')=='rtl';l=tinyMCE.plugins;for(n in l){o=l[n];if(o.getControlHTML&&(v=o.getControlHTML(c))!=''){if(rtl)return'<span dir="rtl">'+tinyMCE.replaceVar(v,"pluginurl",o.baseURL)+'</span>';return tinyMCE.replaceVar(v,"pluginurl",o.baseURL)}}o=tinyMCE.themes[tinyMCE.settings['theme']];if(o.getControlHTML&&(v=o.getControlHTML(c))!=''){if(rtl)return'<span dir="rtl">'+v+'</span>';return v}return''},evalFunc:function(f,idx,a,o){o=!o?window:o;f=typeof(f)=='function'?f:o[f];return f.apply(o,Array.prototype.slice.call(a,idx))},dispatchCallback:function(i,p,n){return this.callFunc(i,p,n,0,this.dispatchCallback.arguments)},executeCallback:function(i,p,n){return this.callFunc(i,p,n,1,this.executeCallback.arguments)},execCommandCallback:function(i,p,n){return this.callFunc(i,p,n,2,this.execCommandCallback.arguments)},callFunc:function(ins,p,n,m,a){var l,i,on,o,s,v;s=m==2;l=tinyMCE.getParam(p,'');if(l!=''&&(v=tinyMCE.evalFunc(l,3,a))==s&&m>0)return true;if(ins!=null){for(i=0,l=ins.plugins;i<l.length;i++){o=tinyMCE.plugins[l[i]];if(o[n]&&(v=tinyMCE.evalFunc(n,3,a,o))==s&&m>0)return true}}l=tinyMCE.themes;for(on in l){o=l[on];if(o[n]&&(v=tinyMCE.evalFunc(n,3,a,o))==s&&m>0)return true}return false},xmlEncode:function(s,skip_apos){return s?(''+s).replace(!skip_apos?this.xmlEncodeAposRe:this.xmlEncodeRe,function(c,b){switch(c){case'&':return'&amp;';case'"':return'&quot;';case'\'':return'&#39;';case'<':return'&lt;';case'>':return'&gt;'}return c}):s},extend:function(p,np){var o={};o.parent=p;for(n in p)o[n]=p[n];for(n in np)o[n]=np[n];return o},hideMenus:function(){var e=tinyMCE.lastSelectedMenuBtn;if(tinyMCE.lastMenu){tinyMCE.lastMenu.hide();tinyMCE.lastMenu=null}if(e){tinyMCE.switchClass(e,tinyMCE.lastMenuBtnClass);tinyMCE.lastSelectedMenuBtn=null}}};var TinyMCE=TinyMCE_Engine;var tinyMCE=new TinyMCE_Engine();var tinyMCELang={};function TinyMCE_Control(settings){var t,i,to,fu,p,x,fn,fu,pn,s=settings;this.undoRedoLevel=true;this.isTinyMCE_Control=true;this.settings=s;this.settings['theme']=tinyMCE.getParam("theme","default");this.settings['width']=tinyMCE.getParam("width",-1);this.settings['height']=tinyMCE.getParam("height",-1);this.selection=new TinyMCE_Selection(this);this.undoRedo=new TinyMCE_UndoRedo(this);this.cleanup=new TinyMCE_Cleanup();this.shortcuts=new Array();this.hasMouseMoved=false;this.foreColor=this.backColor="#999999";this.data={};this.cssClasses=[];this.cleanup.init({valid_elements:s.valid_elements,extended_valid_elements:s.extended_valid_elements,valid_child_elements:s.valid_child_elements,entities:s.entities,entity_encoding:s.entity_encoding,debug:s.cleanup_debug,indent:s.apply_source_formatting,invalid_elements:s.invalid_elements,verify_html:s.verify_html,fix_content_duplication:s.fix_content_duplication,convert_fonts_to_spans:s.convert_fonts_to_spans});t=this.settings['theme'];if(!tinyMCE.hasTheme(t)){fn=tinyMCE.callbacks;to={};for(i=0;i<fn.length;i++){if((fu=window['TinyMCE_'+t+"_"+fn[i]]))to[fn[i]]=fu}tinyMCE.addTheme(t,to)}this.plugins=new Array();p=tinyMCE.getParam('plugins','',true,',');if(p.length>0){for(i=0;i<p.length;i++){pn=p[i];if(pn.charAt(0)=='-')pn=pn.substring(1);if(!tinyMCE.hasPlugin(pn)){fn=tinyMCE.callbacks;to={};for(x=0;x<fn.length;x++){if((fu=window['TinyMCE_'+pn+"_"+fn[x]]))to[fn[x]]=fu}tinyMCE.addPlugin(pn,to)}this.plugins[this.plugins.length]=pn}}};TinyMCE_Control.prototype={selection:null,settings:null,cleanup:null,getData:function(na){var o=this.data[na];if(!o)o=this.data[na]={};return o},hasPlugin:function(n){var i;for(i=0;i<this.plugins.length;i++){if(this.plugins[i]==n)return true}return false},addPlugin:function(n,p){if(!this.hasPlugin(n)){tinyMCE.addPlugin(n,p);this.plugins[this.plugins.length]=n}},repaint:function(){var s,b,ex;if(tinyMCE.isRealIE)return;try{s=this.selection;b=s.getBookmark(true);this.getBody().style.display='none';this.getDoc().execCommand('selectall',false,null);this.getSel().collapseToStart();this.getBody().style.display='block';s.moveToBookmark(b)}catch(ex){}},switchSettings:function(){if(tinyMCE.configs.length>1&&tinyMCE.currentConfig!=this.settings['index']){tinyMCE.settings=this.settings;tinyMCE.currentConfig=this.settings['index']}},select:function(){var oldInst=tinyMCE.selectedInstance;if(oldInst!=this){if(oldInst)oldInst.execCommand('mceEndTyping');tinyMCE.dispatchCallback(this,'select_instance_callback','selectInstance',this,oldInst);tinyMCE.selectedInstance=this}},getBody:function(){return this.contentBody?this.contentBody:this.getDoc().body},getDoc:function(){return this.contentWindow.document},getWin:function(){return this.contentWindow},getContainerWin:function(){return this.containerWindow?this.containerWindow:window},getViewPort:function(){return tinyMCE.getViewPort(this.getWin())},getParentNode:function(n,f){return tinyMCE.getParentNode(n,f,this.getBody())},getParentElement:function(n,na,f){return tinyMCE.getParentElement(n,na,f,this.getBody())},getParentBlockElement:function(n){return tinyMCE.getParentBlockElement(n,this.getBody())},resizeToContent:function(){var d=this.getDoc(),b=d.body,de=d.documentElement;this.iframeElement.style.height=(tinyMCE.isRealIE)?b.scrollHeight:de.offsetHeight+'px'},addShortcut:function(m,k,d,cmd,ui,va){var n=typeof(k)=="number",ie=tinyMCE.isIE,c,sc,i,scl=this.shortcuts;if(!tinyMCE.getParam('custom_shortcuts'))return false;m=m.toLowerCase();k=ie&&!n?k.toUpperCase():k;c=n?null:k.charCodeAt(0);d=d&&d.indexOf('lang_')==0?tinyMCE.getLang(d):d;sc={alt:m.indexOf('alt')!=-1,ctrl:m.indexOf('ctrl')!=-1,shift:m.indexOf('shift')!=-1,charCode:c,keyCode:n?k:(ie?c:null),desc:d,cmd:cmd,ui:ui,val:va};for(i=0;i<scl.length;i++){if(sc.alt==scl[i].alt&&sc.ctrl==scl[i].ctrl&&sc.shift==scl[i].shift&&sc.charCode==scl[i].charCode&&sc.keyCode==scl[i].keyCode){return false}}scl[scl.length]=sc;return true},handleShortcut:function(e){var i,s,o;if(!e.altKey&&!e.ctrlKey)return false;s=this.shortcuts;for(i=0;i<s.length;i++){o=s[i];if(o.alt==e.altKey&&o.ctrl==e.ctrlKey&&(o.keyCode==e.keyCode||o.charCode==e.charCode)){if(o.cmd&&(e.type=="keydown"||(e.type=="keypress"&&!tinyMCE.isOpera)))tinyMCE.execCommand(o.cmd,o.ui,o.val);tinyMCE.cancelEvent(e);return true}}return false},autoResetDesignMode:function(){if(!tinyMCE.isIE&&this.isHidden()&&tinyMCE.getParam('auto_reset_designmode'))eval('try { this.getDoc().designMode = "On"; this.useCSS = false; } catch(e) {}')},isHidden:function(){var s;if(tinyMCE.isIE)return false;s=this.getSel();return(!s||!s.rangeCount||s.rangeCount==0)},isDirty:function(){return tinyMCE.trim(this.startContent)!=tinyMCE.trim(this.getBody().innerHTML)&&!tinyMCE.isNotDirty},_mergeElements:function(scmd,pa,ch,override){if(scmd=="removeformat"){pa.className="";pa.style.cssText="";ch.className="";ch.style.cssText="";return}var st=tinyMCE.parseStyle(tinyMCE.getAttrib(pa,"style"));var stc=tinyMCE.parseStyle(tinyMCE.getAttrib(ch,"style"));var className=tinyMCE.getAttrib(pa,"class");className=tinyMCE.getAttrib(ch,"class");if(override){for(var n in st){if(typeof(st[n])=='function')continue;stc[n]=st[n]}}else{for(var n in stc){if(typeof(stc[n])=='function')continue;st[n]=stc[n]}}tinyMCE.setAttrib(pa,"style",tinyMCE.serializeStyle(st));tinyMCE.setAttrib(pa,"class",tinyMCE.trim(className));ch.className="";ch.style.cssText="";ch.removeAttribute("class");ch.removeAttribute("style")},_setUseCSS:function(b){var d=this.getDoc();try{d.execCommand("useCSS",false,!b)}catch(ex){}try{d.execCommand("styleWithCSS",false,b)}catch(ex){}if(!tinyMCE.getParam("table_inline_editing"))try{d.execCommand('enableInlineTableEditing',false,"false")}catch(ex){}if(!tinyMCE.getParam("object_resizing"))try{d.execCommand('enableObjectResizing',false,"false")}catch(ex){}},execCommand:function(command,user_interface,value){var doc=this.getDoc(),win=this.getWin(),focusElm=this.getFocusElement();if(!new RegExp('mceStartTyping|mceEndTyping|mceBeginUndoLevel|mceEndUndoLevel|mceAddUndoLevel','gi').test(command))this.undoBookmark=null;if(!tinyMCE.isIE&&!this.useCSS){this._setUseCSS(false);this.useCSS=true}this.contentDocument=doc;if(!/mceStartTyping|mceEndTyping/.test(command)){if(tinyMCE.execCommandCallback(this,'execcommand_callback','execCommand',this.editorId,this.getBody(),command,user_interface,value))return}if(focusElm&&focusElm.nodeName=="IMG"){var align=focusElm.getAttribute('align');var img=command=="JustifyCenter"?focusElm.cloneNode(false):focusElm;switch(command){case"JustifyLeft":if(align=='left')img.removeAttribute('align');else img.setAttribute('align','left');var div=focusElm.parentNode;if(div&&div.nodeName=="DIV"&&div.childNodes.length==1&&div.parentNode)div.parentNode.replaceChild(img,div);this.selection.selectNode(img);this.repaint();tinyMCE.triggerNodeChange();return;case"JustifyCenter":img.removeAttribute('align');var div=tinyMCE.getParentElement(focusElm,"div");if(div&&div.style.textAlign=="center"){if(div.nodeName=="DIV"&&div.childNodes.length==1&&div.parentNode)div.parentNode.replaceChild(img,div)}else{var div=this.getDoc().createElement("div");div.style.textAlign='center';div.appendChild(img);focusElm.parentNode.replaceChild(div,focusElm)}this.selection.selectNode(img);this.repaint();tinyMCE.triggerNodeChange();return;case"JustifyRight":if(align=='right')img.removeAttribute('align');else img.setAttribute('align','right');var div=focusElm.parentNode;if(div&&div.nodeName=="DIV"&&div.childNodes.length==1&&div.parentNode)div.parentNode.replaceChild(img,div);this.selection.selectNode(img);this.repaint();tinyMCE.triggerNodeChange();return}}if(tinyMCE.settings['force_br_newlines']){var alignValue="";if(doc.selection.type!="Control"){switch(command){case"JustifyLeft":alignValue="left";break;case"JustifyCenter":alignValue="center";break;case"JustifyFull":alignValue="justify";break;case"JustifyRight":alignValue="right";break}if(alignValue!=""){var rng=doc.selection.createRange();if((divElm=tinyMCE.getParentElement(rng.parentElement(),"div"))!=null)divElm.setAttribute("align",alignValue);else if(rng.pasteHTML&&rng.htmlText.length>0)rng.pasteHTML('<div align="'+alignValue+'">'+rng.htmlText+"</div>");tinyMCE.triggerNodeChange();return}}}switch(command){case"mceRepaint":this.repaint();return true;case"unlink":if(tinyMCE.isGecko&&this.getSel().isCollapsed){focusElm=tinyMCE.getParentElement(focusElm,'A');if(focusElm)this.selection.selectNode(focusElm,false)}this.getDoc().execCommand(command,user_interface,value);tinyMCE.isGecko&&this.getSel().collapseToEnd();tinyMCE.triggerNodeChange();return true;case"InsertUnorderedList":case"InsertOrderedList":this.getDoc().execCommand(command,user_interface,value);tinyMCE.triggerNodeChange();break;case"Strikethrough":this.getDoc().execCommand(command,user_interface,value);tinyMCE.triggerNodeChange();break;case"mceSelectNode":this.selection.selectNode(value);tinyMCE.triggerNodeChange();tinyMCE.selectedNode=value;break;case"FormatBlock":if(value==null||value==""){var elm=tinyMCE.getParentElement(this.getFocusElement(),"p,div,h1,h2,h3,h4,h5,h6,pre,address,blockquote,dt,dl,dd,samp");if(elm)this.execCommand("mceRemoveNode",false,elm)}else{if(!this.cleanup.isValid(value))return true;if(tinyMCE.isGecko&&new RegExp('<(div|blockquote|code|dt|dd|dl|samp)>','gi').test(value))value=value.replace(/[^a-z]/gi,'');if(tinyMCE.isIE&&new RegExp('blockquote|code|samp','gi').test(value)){var b=this.selection.getBookmark();this.getDoc().execCommand("FormatBlock",false,'<p>');tinyMCE.renameElement(tinyMCE.getParentBlockElement(this.getFocusElement()),value);this.selection.moveToBookmark(b)}else this.getDoc().execCommand("FormatBlock",false,value)}tinyMCE.triggerNodeChange();break;case"mceRemoveNode":if(!value)value=tinyMCE.getParentElement(this.getFocusElement());if(tinyMCE.isIE){value.outerHTML=value.innerHTML}else{var rng=value.ownerDocument.createRange();rng.setStartBefore(value);rng.setEndAfter(value);rng.deleteContents();rng.insertNode(rng.createContextualFragment(value.innerHTML))}tinyMCE.triggerNodeChange();break;case"mceSelectNodeDepth":var parentNode=this.getFocusElement();for(var i=0;parentNode;i++){if(parentNode.nodeName.toLowerCase()=="body")break;if(parentNode.nodeName.toLowerCase()=="#text"){i--;parentNode=parentNode.parentNode;continue}if(i==value){this.selection.selectNode(parentNode,false);tinyMCE.triggerNodeChange();tinyMCE.selectedNode=parentNode;return}parentNode=parentNode.parentNode}break;case"mceSetStyleInfo":case"SetStyleInfo":var rng=this.getRng();var sel=this.getSel();var scmd=value['command'];var sname=value['name'];var svalue=value['value']==null?'':value['value'];var wrapper=value['wrapper']?value['wrapper']:"span";var parentElm=null;var invalidRe=new RegExp("^BODY|HTML$","g");var invalidParentsRe=tinyMCE.settings['merge_styles_invalid_parents']!=''?new RegExp(tinyMCE.settings['merge_styles_invalid_parents'],"gi"):null;if(tinyMCE.isIE){if(rng.item)parentElm=rng.item(0);else{var pelm=rng.parentElement();var prng=doc.selection.createRange();prng.moveToElementText(pelm);if(rng.htmlText==prng.htmlText||rng.boundingWidth==0){if(invalidParentsRe==null||!invalidParentsRe.test(pelm.nodeName))parentElm=pelm}}}else{var felm=this.getFocusElement();if(sel.isCollapsed||(new RegExp('td|tr|tbody|table','gi').test(felm.nodeName)&&sel.anchorNode==felm.parentNode))parentElm=felm}if(parentElm&&!invalidRe.test(parentElm.nodeName)){if(scmd=="setstyle")tinyMCE.setStyleAttrib(parentElm,sname,svalue);if(scmd=="setattrib")tinyMCE.setAttrib(parentElm,sname,svalue);if(scmd=="removeformat"){parentElm.style.cssText='';tinyMCE.setAttrib(parentElm,'class','')}var ch=tinyMCE.getNodeTree(parentElm,new Array(),1);for(var z=0;z<ch.length;z++){if(ch[z]==parentElm)continue;if(scmd=="setstyle")tinyMCE.setStyleAttrib(ch[z],sname,'');if(scmd=="setattrib")tinyMCE.setAttrib(ch[z],sname,'');if(scmd=="removeformat"){ch[z].style.cssText='';tinyMCE.setAttrib(ch[z],'class','')}}}else{this._setUseCSS(false);doc.execCommand("FontName",false,"#mce_temp_font#");var elementArray=tinyMCE.getElementsByAttributeValue(this.getBody(),"font","face","#mce_temp_font#");for(var x=0;x<elementArray.length;x++){elm=elementArray[x];if(elm){var spanElm=doc.createElement(wrapper);if(scmd=="setstyle")tinyMCE.setStyleAttrib(spanElm,sname,svalue);if(scmd=="setattrib")tinyMCE.setAttrib(spanElm,sname,svalue);if(scmd=="removeformat"){spanElm.style.cssText='';tinyMCE.setAttrib(spanElm,'class','')}if(elm.hasChildNodes()){for(var i=0;i<elm.childNodes.length;i++)spanElm.appendChild(elm.childNodes[i].cloneNode(true))}spanElm.setAttribute("mce_new","true");elm.parentNode.replaceChild(spanElm,elm);var ch=tinyMCE.getNodeTree(spanElm,new Array(),1);for(var z=0;z<ch.length;z++){if(ch[z]==spanElm)continue;if(scmd=="setstyle")tinyMCE.setStyleAttrib(ch[z],sname,'');if(scmd=="setattrib")tinyMCE.setAttrib(ch[z],sname,'');if(scmd=="removeformat"){ch[z].style.cssText='';tinyMCE.setAttrib(ch[z],'class','')}}}}}var nodes=doc.getElementsByTagName(wrapper);for(var i=nodes.length-1;i>=0;i--){var elm=nodes[i];var isNew=tinyMCE.getAttrib(elm,"mce_new")=="true";elm.removeAttribute("mce_new");if(elm.childNodes&&elm.childNodes.length==1&&elm.childNodes[0].nodeType==1){this._mergeElements(scmd,elm,elm.childNodes[0],isNew);continue}if(elm.parentNode.childNodes.length==1&&!invalidRe.test(elm.nodeName)&&!invalidRe.test(elm.parentNode.nodeName)){if(invalidParentsRe==null||!invalidParentsRe.test(elm.parentNode.nodeName))this._mergeElements(scmd,elm.parentNode,elm,false)}}var nodes=doc.getElementsByTagName(wrapper);for(var i=nodes.length-1;i>=0;i--){var elm=nodes[i];var isEmpty=true;var tmp=doc.createElement("body");tmp.appendChild(elm.cloneNode(false));tmp.innerHTML=tmp.innerHTML.replace(new RegExp('style=""|class=""','gi'),'');if(new RegExp('<span>','gi').test(tmp.innerHTML)){for(var x=0;x<elm.childNodes.length;x++){if(elm.parentNode!=null)elm.parentNode.insertBefore(elm.childNodes[x].cloneNode(true),elm)}elm.parentNode.removeChild(elm)}}if(scmd=="removeformat")tinyMCE.handleVisualAid(this.getBody(),true,this.visualAid,this);tinyMCE.triggerNodeChange();break;case"FontName":if(value==null){var s=this.getSel();if(tinyMCE.isGecko&&s.isCollapsed){var f=tinyMCE.getParentElement(this.getFocusElement(),"font");if(f!=null)this.selection.selectNode(f,false)}this.getDoc().execCommand("RemoveFormat",false,null);if(f!=null&&tinyMCE.isGecko){var r=this.getRng().cloneRange();r.collapse(true);s.removeAllRanges();s.addRange(r)}}else this.getDoc().execCommand('FontName',false,value);if(tinyMCE.isGecko)window.setTimeout('tinyMCE.triggerNodeChange(false);',1);return;case"FontSize":this.getDoc().execCommand('FontSize',false,value);if(tinyMCE.isGecko)window.setTimeout('tinyMCE.triggerNodeChange(false);',1);return;case"forecolor":value=value==null?this.foreColor:value;value=tinyMCE.trim(value);value=value.charAt(0)!='#'?(isNaN('0x'+value)?value:'#'+value):value;this.foreColor=value;this.getDoc().execCommand('forecolor',false,value);break;case"HiliteColor":value=value==null?this.backColor:value;value=tinyMCE.trim(value);value=value.charAt(0)!='#'?(isNaN('0x'+value)?value:'#'+value):value;this.backColor=value;if(tinyMCE.isGecko){this._setUseCSS(true);this.getDoc().execCommand('hilitecolor',false,value);this._setUseCSS(false)}else this.getDoc().execCommand('BackColor',false,value);break;case"Cut":case"Copy":case"Paste":var cmdFailed=false;eval('try {this.getDoc().execCommand(command, user_interface, value);} catch (e) {cmdFailed = true;}');if(tinyMCE.isOpera&&cmdFailed)alert('Currently not supported by your browser, use keyboard shortcuts instead.');if(tinyMCE.isGecko&&cmdFailed){if(confirm(tinyMCE.entityDecode(tinyMCE.getLang('lang_clipboard_msg'))))window.open('http://www.mozilla.org/editor/midasdemo/securityprefs.html','mceExternal');return}else tinyMCE.triggerNodeChange();break;case"mceSetContent":if(!value)value="";value=tinyMCE.storeAwayURLs(value);value=tinyMCE._customCleanup(this,"insert_to_editor",value);if(this.getBody().nodeName=='BODY')tinyMCE._setHTML(doc,value);else this.getBody().innerHTML=value;tinyMCE.setInnerHTML(this.getBody(),tinyMCE._cleanupHTML(this,doc,this.settings,this.getBody(),false,false,false,true));tinyMCE.convertAllRelativeURLs(this.getBody());tinyMCE._removeInternal(this.getBody());if(tinyMCE.getParam("convert_fonts_to_spans"))tinyMCE.convertSpansToFonts(doc);tinyMCE.handleVisualAid(this.getBody(),true,this.visualAid,this);tinyMCE._setEventsEnabled(this.getBody(),false);return true;case"mceCleanup":var b=this.selection.getBookmark();tinyMCE._setHTML(this.contentDocument,this.getBody().innerHTML);tinyMCE.setInnerHTML(this.getBody(),tinyMCE._cleanupHTML(this,this.contentDocument,this.settings,this.getBody(),this.visualAid));tinyMCE.convertAllRelativeURLs(doc.body);if(tinyMCE.getParam("convert_fonts_to_spans"))tinyMCE.convertSpansToFonts(doc);tinyMCE.handleVisualAid(this.getBody(),true,this.visualAid,this);tinyMCE._setEventsEnabled(this.getBody(),false);this.repaint();this.selection.moveToBookmark(b);tinyMCE.triggerNodeChange();break;case"mceReplaceContent":if(!value)value='';this.getWin().focus();var selectedText="";if(tinyMCE.isIE){var rng=doc.selection.createRange();selectedText=rng.text}else selectedText=this.getSel().toString();if(selectedText.length>0){value=tinyMCE.replaceVar(value,"selection",selectedText);tinyMCE.execCommand('mceInsertContent',false,value)}tinyMCE.triggerNodeChange();break;case"mceSetAttribute":if(typeof(value)=='object'){var targetElms=(typeof(value['targets'])=="undefined")?"p,img,span,div,td,h1,h2,h3,h4,h5,h6,pre,address":value['targets'];var targetNode=tinyMCE.getParentElement(this.getFocusElement(),targetElms);if(targetNode){targetNode.setAttribute(value['name'],value['value']);tinyMCE.triggerNodeChange()}}break;case"mceSetCSSClass":this.execCommand("mceSetStyleInfo",false,{command:"setattrib",name:"class",value:value});break;case"mceInsertRawHTML":var key='tiny_mce_marker';this.execCommand('mceBeginUndoLevel');this.execCommand('mceInsertContent',false,key);var scrollX=this.getBody().scrollLeft+this.getDoc().documentElement.scrollLeft;var scrollY=this.getBody().scrollTop+this.getDoc().documentElement.scrollTop;var html=this.getBody().innerHTML;if((pos=html.indexOf(key))!=-1)tinyMCE.setInnerHTML(this.getBody(),html.substring(0,pos)+value+html.substring(pos+key.length));this.contentWindow.scrollTo(scrollX,scrollY);this.execCommand('mceEndUndoLevel');break;case"mceInsertContent":if(!value)value='';var insertHTMLFailed=false;if(tinyMCE.isGecko||tinyMCE.isOpera){try{if(value.indexOf('<')==-1&&!value.match(/(&#38;|&#160;|&#60;|&#62;)/g)){var r=this.getRng();var n=this.getDoc().createTextNode(tinyMCE.entityDecode(value));var s=this.getSel();var r2=r.cloneRange();s.removeAllRanges();r.deleteContents();r.insertNode(n);r2.selectNode(n);r2.collapse(false);s.removeAllRanges();s.addRange(r2)}else{value=tinyMCE.fixGeckoBaseHREFBug(1,this.getDoc(),value);this.getDoc().execCommand('inserthtml',false,value);tinyMCE.fixGeckoBaseHREFBug(2,this.getDoc(),value)}}catch(ex){insertHTMLFailed=true}if(!insertHTMLFailed){tinyMCE.triggerNodeChange();return}}if(!tinyMCE.isIE){var isHTML=value.indexOf('<')!=-1;var sel=this.getSel();var rng=this.getRng();if(isHTML){if(tinyMCE.isSafari){var tmpRng=this.getDoc().createRange();tmpRng.setStart(this.getBody(),0);tmpRng.setEnd(this.getBody(),0);value=tmpRng.createContextualFragment(value)}else value=rng.createContextualFragment(value)}else{var el=document.createElement("div");el.innerHTML=value;value=el.firstChild.nodeValue;value=doc.createTextNode(value)}if(tinyMCE.isSafari&&!isHTML){this.execCommand('InsertText',false,value.nodeValue);tinyMCE.triggerNodeChange();return true}else if(tinyMCE.isSafari&&isHTML){rng.deleteContents();rng.insertNode(value);tinyMCE.triggerNodeChange();return true}rng.deleteContents();if(rng.startContainer.nodeType==3){var node=rng.startContainer.splitText(rng.startOffset);node.parentNode.insertBefore(value,node)}else rng.insertNode(value);if(!isHTML){sel.selectAllChildren(doc.body);sel.removeAllRanges();var rng=doc.createRange();rng.selectNode(value);rng.collapse(false);sel.addRange(rng)}else rng.collapse(false);tinyMCE.fixGeckoBaseHREFBug(2,this.getDoc(),value)}else{var rng=doc.selection.createRange(),tmpRng=null;var c=value.indexOf('<!--')!=-1;if(c)value=tinyMCE.uniqueTag+value;if(rng.item)rng.item(0).outerHTML=value;else rng.pasteHTML(value);if(c){var e=this.getDoc().getElementById('mceTMPElement');e.parentNode.removeChild(e)}}tinyMCE.execCommand("mceAddUndoLevel");tinyMCE.triggerNodeChange();break;case"mceStartTyping":if(tinyMCE.settings['custom_undo_redo']&&this.undoRedo.typingUndoIndex==-1){this.undoRedo.typingUndoIndex=this.undoRedo.undoIndex;tinyMCE.typingUndoIndex=tinyMCE.undoIndex;this.execCommand('mceAddUndoLevel')}break;case"mceEndTyping":if(tinyMCE.settings['custom_undo_redo']&&this.undoRedo.typingUndoIndex!=-1){this.execCommand('mceAddUndoLevel');this.undoRedo.typingUndoIndex=-1}tinyMCE.typingUndoIndex=-1;break;case"mceBeginUndoLevel":this.undoRedoLevel=false;break;case"mceEndUndoLevel":this.undoRedoLevel=true;this.execCommand('mceAddUndoLevel');break;case"mceAddUndoLevel":if(tinyMCE.settings['custom_undo_redo']&&this.undoRedoLevel){if(this.undoRedo.add())tinyMCE.triggerNodeChange(false)}break;case"Undo":if(tinyMCE.settings['custom_undo_redo']){tinyMCE.execCommand("mceEndTyping");this.undoRedo.undo();tinyMCE.triggerNodeChange()}else this.getDoc().execCommand(command,user_interface,value);break;case"Redo":if(tinyMCE.settings['custom_undo_redo']){tinyMCE.execCommand("mceEndTyping");this.undoRedo.redo();tinyMCE.triggerNodeChange()}else this.getDoc().execCommand(command,user_interface,value);break;case"mceToggleVisualAid":this.visualAid=!this.visualAid;tinyMCE.handleVisualAid(this.getBody(),true,this.visualAid,this);tinyMCE.triggerNodeChange();break;case"Indent":this.getDoc().execCommand(command,user_interface,value);tinyMCE.triggerNodeChange();if(tinyMCE.isIE){var n=tinyMCE.getParentElement(this.getFocusElement(),"blockquote");do{if(n&&n.nodeName=="BLOCKQUOTE"){n.removeAttribute("dir");n.removeAttribute("style")}}while(n!=null&&(n=n.parentNode)!=null)}break;case"RemoveFormat":case"removeformat":var text=this.selection.getSelectedText();if(tinyMCE.isOpera){this.getDoc().execCommand("RemoveFormat",false,null);return}if(tinyMCE.isIE){try{var rng=doc.selection.createRange();rng.execCommand("RemoveFormat",false,null)}catch(e){}this.execCommand("mceSetStyleInfo",false,{command:"removeformat"})}else{this.getDoc().execCommand(command,user_interface,value);this.execCommand("mceSetStyleInfo",false,{command:"removeformat"})}if(text.length==0)this.execCommand("mceSetCSSClass",false,"");tinyMCE.triggerNodeChange();break;default:this.getDoc().execCommand(command,user_interface,value);if(tinyMCE.isGecko)window.setTimeout('tinyMCE.triggerNodeChange(false);',1);else tinyMCE.triggerNodeChange()}if(command!="mceAddUndoLevel"&&command!="Undo"&&command!="Redo"&&command!="mceStartTyping"&&command!="mceEndTyping")tinyMCE.execCommand("mceAddUndoLevel")},queryCommandValue:function(c){try{return this.getDoc().queryCommandValue(c)}catch(e){return null}},queryCommandState:function(c){return this.getDoc().queryCommandState(c)},_onAdd:function(replace_element,form_element_name,target_document){var hc,th,to,editorTemplate;th=this.settings['theme'];to=tinyMCE.themes[th];var targetDoc=target_document?target_document:document;this.targetDoc=targetDoc;tinyMCE.themeURL=tinyMCE.baseURL+"/themes/"+this.settings['theme'];this.settings['themeurl']=tinyMCE.themeURL;if(!replace_element){alert("Error: Could not find the target element.");return false}if(to.getEditorTemplate)editorTemplate=to.getEditorTemplate(this.settings,this.editorId);var deltaWidth=editorTemplate['delta_width']?editorTemplate['delta_width']:0;var deltaHeight=editorTemplate['delta_height']?editorTemplate['delta_height']:0;var html='<span id="'+this.editorId+'_parent" class="mceEditorContainer">'+editorTemplate['html'];html=tinyMCE.replaceVar(html,"editor_id",this.editorId);this.settings['default_document']=tinyMCE.baseURL+"/blank.htm";this.settings['old_width']=this.settings['width'];this.settings['old_height']=this.settings['height'];if(this.settings['width']==-1)this.settings['width']=replace_element.offsetWidth;if(this.settings['height']==-1)this.settings['height']=replace_element.offsetHeight;if(this.settings['width']==0)this.settings['width']=replace_element.style.width;if(this.settings['height']==0)this.settings['height']=replace_element.style.height;if(this.settings['width']==0)this.settings['width']=320;if(this.settings['height']==0)this.settings['height']=240;this.settings['area_width']=parseInt(this.settings['width']);this.settings['area_height']=parseInt(this.settings['height']);this.settings['area_width']+=deltaWidth;this.settings['area_height']+=deltaHeight;this.settings['width_style']=""+this.settings['width'];this.settings['height_style']=""+this.settings['height'];if((""+this.settings['width']).indexOf('%')!=-1)this.settings['area_width']="100%";else this.settings['width_style']+='px';if((""+this.settings['height']).indexOf('%')!=-1)this.settings['area_height']="100%";else this.settings['height_style']+='px';if((""+replace_element.style.width).indexOf('%')!=-1){this.settings['width']=replace_element.style.width;this.settings['area_width']="100%";this.settings['width_style']="100%"}if((""+replace_element.style.height).indexOf('%')!=-1){this.settings['height']=replace_element.style.height;this.settings['area_height']="100%";this.settings['height_style']="100%"}html=tinyMCE.applyTemplate(html);this.settings['width']=this.settings['old_width'];this.settings['height']=this.settings['old_height'];this.visualAid=this.settings['visual'];this.formTargetElementId=form_element_name;if(replace_element.nodeName=="TEXTAREA"||replace_element.nodeName=="INPUT")this.startContent=replace_element.value;else this.startContent=replace_element.innerHTML;if(replace_element.nodeName!="TEXTAREA"&&replace_element.nodeName!="INPUT"){this.oldTargetElement=replace_element;if(tinyMCE.settings['debug']){hc='<textarea wrap="off" id="'+form_element_name+'" name="'+form_element_name+'" cols="100" rows="15"></textarea>'}else{hc='<input type="hidden" id="'+form_element_name+'" name="'+form_element_name+'" />';this.oldTargetDisplay=tinyMCE.getStyle(this.oldTargetElement,'display','inline');this.oldTargetElement.style.display="none"}html+='</span>';if(tinyMCE.isGecko)html=hc+html;else html+=hc;if(tinyMCE.isGecko){var rng=replace_element.ownerDocument.createRange();rng.setStartBefore(replace_element);var fragment=rng.createContextualFragment(html);tinyMCE.insertAfter(fragment,replace_element)}else replace_element.insertAdjacentHTML("beforeBegin",html)}else{html+='</span>';this.oldTargetElement=replace_element;if(!tinyMCE.settings['debug']){this.oldTargetDisplay=tinyMCE.getStyle(this.oldTargetElement,'display','inline');this.oldTargetElement.style.display="none"}if(tinyMCE.isGecko){var rng=replace_element.ownerDocument.createRange();rng.setStartBefore(replace_element);var fragment=rng.createContextualFragment(html);tinyMCE.insertAfter(fragment,replace_element)}else replace_element.insertAdjacentHTML("beforeBegin",html)}var dynamicIFrame=false;var tElm=targetDoc.getElementById(this.editorId);if(!tinyMCE.isIE){if(tElm&&(tElm.nodeName=="SPAN"||tElm.nodeName=="span")){tElm=tinyMCE._createIFrame(tElm,targetDoc);dynamicIFrame=true}this.targetElement=tElm;this.iframeElement=tElm;this.contentDocument=tElm.contentDocument;this.contentWindow=tElm.contentWindow;}else{if(tElm&&tElm.nodeName=="SPAN")tElm=tinyMCE._createIFrame(tElm,targetDoc,targetDoc.parentWindow);else tElm=targetDoc.frames[this.editorId];this.targetElement=tElm;this.iframeElement=targetDoc.getElementById(this.editorId);if(tinyMCE.isOpera){this.contentDocument=this.iframeElement.contentDocument;this.contentWindow=this.iframeElement.contentWindow;dynamicIFrame=true}else{this.contentDocument=tElm.window.document;this.contentWindow=tElm.window}this.getDoc().designMode="on"}var doc=this.contentDocument;if(dynamicIFrame){var html=tinyMCE.getParam('doctype')+'<html><head xmlns="http://www.w3.org/1999/xhtml"><base href="'+tinyMCE.settings['base_href']+'" /><title>blank_page</title><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></head><body class="mceContentBody"></body></html>';try{if(!this.isHidden())this.getDoc().designMode="on";doc.open();doc.write(html);doc.close()}catch(e){this.getDoc().location.href=tinyMCE.baseURL+"/blank.htm"}}if(tinyMCE.isIE)window.setTimeout("tinyMCE.addEventHandlers(tinyMCE.instances[\""+this.editorId+"\"]);",1);var parentElm=this.targetDoc.getElementById(this.editorId+'_parent');this.formElement=tinyMCE.isGecko?parentElm.previousSibling:parentElm.nextSibling;tinyMCE.setupContent(this.editorId,true);return true},setBaseHREF:function(u){var h,b,d,nl;d=this.getDoc();nl=d.getElementsByTagName("base");b=nl.length>0?nl[0]:null;if(!b){nl=d.getElementsByTagName("head");h=nl.length>0?nl[0]:null;b=d.createElement("base");b.setAttribute('href',u);h.appendChild(b)}else{if(u==""||u==null)b.parentNode.removeChild(b);else b.setAttribute('href',u)}},getHTML:function(r){var h,d=this.getDoc(),b=this.getBody();if(r)return b.innerHTML;h=tinyMCE._cleanupHTML(this,d,this.settings,b,false,true,false,true);if(tinyMCE.getParam("convert_fonts_to_spans"))tinyMCE.convertSpansToFonts(d);return h},setHTML:function(h){this.execCommand('mceSetContent',false,h);this.repaint()},getFocusElement:function(){return this.selection.getFocusElement()},getSel:function(){return this.selection.getSel()},getRng:function(){return this.selection.getRng()},triggerSave:function(skip_cleanup,skip_callback){var e,nl=[],i,s;this.switchSettings();s=tinyMCE.settings;if(tinyMCE.isRealIE){e=this.iframeElement;do{if(e.style&&e.style.display=='none'){e.style.display='block';nl[nl.length]={elm:e,type:'style'}}if(e.style&&s.hidden_tab_class.length>0&&e.className.indexOf(s.hidden_tab_class)!=-1){e.className=s.display_tab_class;nl[nl.length]={elm:e,type:'class'}}}while((e=e.parentNode)!=null)}tinyMCE.settings['preformatted']=false;if(typeof(skip_cleanup)=="undefined")skip_cleanup=false;if(typeof(skip_callback)=="undefined")skip_callback=false;tinyMCE._setHTML(this.getDoc(),this.getBody().innerHTML);if(this.settings['cleanup']==false){tinyMCE.handleVisualAid(this.getBody(),true,false,this);tinyMCE._setEventsEnabled(this.getBody(),true)}tinyMCE._customCleanup(this,"submit_content_dom",this.contentWindow.document.body);var htm=skip_cleanup?this.getBody().innerHTML:tinyMCE._cleanupHTML(this,this.getDoc(),this.settings,this.getBody(),tinyMCE.visualAid,true,true);htm=tinyMCE._customCleanup(this,"submit_content",htm);if(!skip_callback&&tinyMCE.settings['save_callback']!="")var content=eval(tinyMCE.settings['save_callback']+"(this.formTargetElementId,htm,this.getBody());");if((typeof(content)!="undefined")&&content!=null)htm=content;htm=tinyMCE.regexpReplace(htm,"&#40;","(","gi");htm=tinyMCE.regexpReplace(htm,"&#41;",")","gi");htm=tinyMCE.regexpReplace(htm,"&#59;",";","gi");htm=tinyMCE.regexpReplace(htm,"&#34;","&quot;","gi");htm=tinyMCE.regexpReplace(htm,"&#94;","^","gi");if(this.formElement)this.formElement.value=htm;if(tinyMCE.isSafari&&this.formElement)this.formElement.innerText=htm;for(i=0;i<nl.length;i++){if(nl[i].type=='style')nl[i].elm.style.display='none';else nl[i].elm.className=s.hidden_tab_class}}};TinyMCE_Engine.prototype.cleanupHTMLCode=function(s){s=s.replace(new RegExp('<p \\/>','gi'),'<p>&nbsp;</p>');s=s.replace(new RegExp('<p>\\s*<\\/p>','gi'),'<p>&nbsp;</p>');s=s.replace(new RegExp('<br>\\s*<\\/br>','gi'),'<br />');s=s.replace(new RegExp('<(h[1-6]|p|div|address|pre|form|table|li|ol|ul|td|b|font|em|strong|i|strike|u|span|a|ul|ol|li|blockquote)([a-z]*)([^\\\\|>]*)\\/>','gi'),'<$1$2$3></$1$2>');s=s.replace(new RegExp('\\s+></','gi'),'></');s=s.replace(new RegExp('<(img|br|hr)([^>]*)><\\/(img|br|hr)>','gi'),'<$1$2 />');if(tinyMCE.isIE)s=s.replace(new RegExp('<p><hr \\/><\\/p>','gi'),"<hr>");if(tinyMCE.isIE)s=s.replace(/<!(\s*)\/>/g,'');return s};TinyMCE_Engine.prototype.parseStyle=function(str){var ar=new Array();if(str==null)return ar;var st=str.split(';');tinyMCE.clearArray(ar);for(var i=0;i<st.length;i++){if(st[i]=='')continue;var re=new RegExp('^\\s*([^:]*):\\s*(.*)\\s*$');var pa=st[i].replace(re,'$1||$2').split('||');if(pa.length==2)ar[pa[0].toLowerCase()]=pa[1]}return ar};TinyMCE_Engine.prototype.compressStyle=function(ar,pr,sf,res){var box=new Array();box[0]=ar[pr+'-top'+sf];box[1]=ar[pr+'-left'+sf];box[2]=ar[pr+'-right'+sf];box[3]=ar[pr+'-bottom'+sf];for(var i=0;i<box.length;i++){if(box[i]==null)return;for(var a=0;a<box.length;a++){if(box[a]!=box[i])return}}ar[res]=box[0];ar[pr+'-top'+sf]=null;ar[pr+'-left'+sf]=null;ar[pr+'-right'+sf]=null;ar[pr+'-bottom'+sf]=null};TinyMCE_Engine.prototype.serializeStyle=function(ar){var str="";tinyMCE.compressStyle(ar,"border","","border");tinyMCE.compressStyle(ar,"border","-width","border-width");tinyMCE.compressStyle(ar,"border","-color","border-color");tinyMCE.compressStyle(ar,"border","-style","border-style");tinyMCE.compressStyle(ar,"padding","","padding");tinyMCE.compressStyle(ar,"margin","","margin");for(var key in ar){var val=ar[key];if(typeof(val)=='function')continue;if(key.indexOf('mso-')==0)continue;if(val!=null&&val!=''){val=''+val;val=val.replace(new RegExp("url\\(\\'?([^\\']*)\\'?\\)",'gi'),"url('$1')");if(val.indexOf('url(')!=-1&&tinyMCE.getParam('convert_urls')){var m=new RegExp("url\\('(.*?)'\\)").exec(val);if(m.length>1)val="url('"+eval(tinyMCE.getParam('urlconverter_callback')+"(m[1], null, true);")+"')"}if(tinyMCE.getParam("force_hex_style_colors"))val=tinyMCE.convertRGBToHex(val,true);val=val.replace(/\"/g,'\'');if(val!="url('')")str+=key.toLowerCase()+": "+val+"; "}}if(new RegExp('; $').test(str))str=str.substring(0,str.length-2);return str};TinyMCE_Engine.prototype.convertRGBToHex=function(s,k){if(s.toLowerCase().indexOf('rgb')!=-1){var re=new RegExp("(.*?)rgb\\s*?\\(\\s*?([0-9]+).*?,\\s*?([0-9]+).*?,\\s*?([0-9]+).*?\\)(.*?)","gi");var rgb=s.replace(re,"$1,$2,$3,$4,$5").split(',');if(rgb.length==5){r=parseInt(rgb[1]).toString(16);g=parseInt(rgb[2]).toString(16);b=parseInt(rgb[3]).toString(16);r=r.length==1?'0'+r:r;g=g.length==1?'0'+g:g;b=b.length==1?'0'+b:b;s="#"+r+g+b;if(k)s=rgb[0]+s+rgb[4]}}return s};TinyMCE_Engine.prototype.convertHexToRGB=function(s){if(s.indexOf('#')!=-1){s=s.replace(new RegExp('[^0-9A-F]','gi'),'');return"rgb("+parseInt(s.substring(0,2),16)+","+parseInt(s.substring(2,4),16)+","+parseInt(s.substring(4,6),16)+")"}return s};TinyMCE_Engine.prototype.convertSpansToFonts=function(doc){var sizes=tinyMCE.getParam('font_size_style_values').replace(/\s+/,'').split(',');var s=tinyMCE.selectElements(doc,'span,font');for(var i=0;i<s.length;i++){var size=tinyMCE.trim(s[i].style.fontSize).toLowerCase();var fSize=0;for(var x=0;x<sizes.length;x++){if(sizes[x]==size){fSize=x+1;break}}if(fSize>0){tinyMCE.setAttrib(s[i],'size',fSize);s[i].style.fontSize=''}var fFace=s[i].style.fontFamily;if(fFace!=null&&fFace!=""){tinyMCE.setAttrib(s[i],'face',fFace);s[i].style.fontFamily=''}var fColor=s[i].style.color;if(fColor!=null&&fColor!=""){tinyMCE.setAttrib(s[i],'color',tinyMCE.convertRGBToHex(fColor));s[i].style.color=''}}};TinyMCE_Engine.prototype.convertFontsToSpans=function(doc){var sizes=tinyMCE.getParam('font_size_style_values').replace(/\s+/,'').split(',');var fsClasses=tinyMCE.getParam('font_size_classes');if(fsClasses!='')fsClasses=fsClasses.replace(/\s+/,'').split(',');else fsClasses=null;var s=tinyMCE.selectElements(doc,'span,font');for(var i=0;i<s.length;i++){var fSize,fFace,fColor;fSize=tinyMCE.getAttrib(s[i],'size');fFace=tinyMCE.getAttrib(s[i],'face');fColor=tinyMCE.getAttrib(s[i],'color');if(fSize!=""){fSize=parseInt(fSize);if(fSize>0&&fSize<8){if(fsClasses!=null)tinyMCE.setAttrib(s[i],'class',fsClasses[fSize-1]);else s[i].style.fontSize=sizes[fSize-1]}s[i].removeAttribute('size')}if(fFace!=""){s[i].style.fontFamily=fFace;s[i].removeAttribute('face')}if(fColor!=""){s[i].style.color=fColor;s[i].removeAttribute('color')}}};TinyMCE_Engine.prototype.cleanupAnchors=function(doc){var i,cn,x,an=doc.getElementsByTagName("a");for(i=an.length-1;i>=0;i--){if(tinyMCE.getAttrib(an[i],"name")!=""&&tinyMCE.getAttrib(an[i],"href")==""){cn=an[i].childNodes;for(x=cn.length-1;x>=0;x--)tinyMCE.insertAfter(cn[x],an[i])}}};TinyMCE_Engine.prototype.getContent=function(editor_id){if(typeof(editor_id)!="undefined")tinyMCE.getInstanceById(editor_id).select();if(tinyMCE.selectedInstance)return tinyMCE.selectedInstance.getHTML();return null};TinyMCE_Engine.prototype._fixListElements=function(d){var nl,x,a=['ol','ul'],i,n,p,r=new RegExp('^(OL|UL)$'),np;for(x=0;x<a.length;x++){nl=d.getElementsByTagName(a[x]);for(i=0;i<nl.length;i++){n=nl[i];p=n.parentNode;if(r.test(p.nodeName)){np=tinyMCE.prevNode(n,'LI');if(!np){np=d.createElement('li');np.innerHTML='&nbsp;';np.appendChild(n);p.insertBefore(np,p.firstChild)}else np.appendChild(n)}}}};TinyMCE_Engine.prototype._fixTables=function(d){var nl,i,n,p,np,x,t;nl=d.getElementsByTagName('table');for(i=0;i<nl.length;i++){n=nl[i];if((p=tinyMCE.getParentElement(n,'p,h1,h2,h3,h4,h5,h6'))!=null){np=p.cloneNode(false);np.removeAttribute('id');t=n;while((n=n.nextSibling))np.appendChild(n);tinyMCE.insertAfter(np,p);tinyMCE.insertAfter(t,p)}}};TinyMCE_Engine.prototype._cleanupHTML=function(inst,doc,config,elm,visual,on_save,on_submit,inn){var h,d,t1,t2,t3,t4,t5,c,s,nb;if(!tinyMCE.getParam('cleanup'))return elm.innerHTML;on_save=typeof(on_save)=='undefined'?false:on_save;c=inst.cleanup;s=inst.settings;d=c.settings.debug;if(d)t1=new Date().getTime();if(tinyMCE.getParam("convert_fonts_to_spans"))tinyMCE.convertFontsToSpans(doc);if(tinyMCE.getParam("fix_list_elements"))tinyMCE._fixListElements(doc);if(tinyMCE.getParam("fix_table_elements"))tinyMCE._fixTables(doc);tinyMCE._customCleanup(inst,on_save?"get_from_editor_dom":"insert_to_editor_dom",doc.body);if(d)t2=new Date().getTime();c.settings.on_save=on_save;c.idCount=0;c.serializationId++;c.serializedNodes=new Array();c.sourceIndex=-1;if(s.cleanup_serializer=="xml")h=c.serializeNodeAsXML(elm,inn);else h=c.serializeNodeAsHTML(elm,inn);if(d)t3=new Date().getTime();nb=tinyMCE.getParam('entity_encoding')=='numeric'?'&#160;':'&nbsp;';h=h.replace(/<\/?(body|head|html)[^>]*>/gi,'');h=h.replace(new RegExp(' (rowspan="1"|colspan="1")','g'),'');h=h.replace(/<p><hr \/><\/p>/g,'<hr />');h=h.replace(/<p>(&nbsp;|&#160;)<\/p><hr \/><p>(&nbsp;|&#160;)<\/p>/g,'<hr />');h=h.replace(/<td>\s*<br \/>\s*<\/td>/g,'<td>'+nb+'</td>');h=h.replace(/<p>\s*<br \/>\s*<\/p>/g,'<p>'+nb+'</p>');h=h.replace(/<br \/>$/,'');h=h.replace(/<br \/><\/p>/g,'</p>');h=h.replace(/<p>\s*(&nbsp;|&#160;)\s*<br \/>\s*(&nbsp;|&#160;)\s*<\/p>/g,'<p>'+nb+'</p>');h=h.replace(/<p>\s*(&nbsp;|&#160;)\s*<br \/>\s*<\/p>/g,'<p>'+nb+'</p>');h=h.replace(/<p>\s*<br \/>\s*&nbsp;\s*<\/p>/g,'<p>'+nb+'</p>');h=h.replace(new RegExp('<a>(.*?)<\\/a>','g'),'$1');h=h.replace(/<p([^>]*)>\s*<\/p>/g,'<p$1>'+nb+'</p>');if(/^\s*(<br \/>|<p>&nbsp;<\/p>|<p>&#160;<\/p>|<p><\/p>)\s*$/.test(h))h='';if(s.preformatted){h=h.replace(/^<pre>/,'');h=h.replace(/<\/pre>$/,'');h='<pre>'+h+'</pre>'}if(tinyMCE.isGecko){h=h.replace(/<o:p _moz-userdefined="" \/>/g,'');h=h.replace(/<td([^>]*)>\s*<br \/>\s*<\/td>/g,'<td$1>'+nb+'</td>')}if(s.force_br_newlines)h=h.replace(/<p>(&nbsp;|&#160;)<\/p>/g,'<br />');h=tinyMCE._customCleanup(inst,on_save?"get_from_editor":"insert_to_editor",h);if(on_save){h=h.replace(new RegExp(' ?(mceItem[a-zA-Z0-9]*|'+s.visual_table_class+')','g'),'');h=h.replace(new RegExp(' ?class=""','g'),'')}if(s.remove_linebreaks&&!c.settings.indent)h=h.replace(/\n|\r/g,' ');if(d)t4=new Date().getTime();if(on_save&&c.settings.indent)h=c.formatHTML(h);if(on_submit&&(s.encoding=="xml"||s.encoding=="html"))h=c.xmlEncode(h);if(d)t5=new Date().getTime();if(c.settings.debug)tinyMCE.debug("Cleanup in ms: Pre="+(t2-t1)+", Serialize: "+(t3-t2)+", Post: "+(t4-t3)+", Format: "+(t5-t4)+", Sum: "+(t5-t1)+".");return h};function TinyMCE_Cleanup(){this.isIE=(navigator.appName=="Microsoft Internet Explorer");this.rules=tinyMCE.clearArray(new Array());this.settings={indent_elements:'head,table,tbody,thead,tfoot,form,tr,ul,ol,blockquote,object',newline_before_elements:'h1,h2,h3,h4,h5,h6,pre,address,div,ul,ol,li,meta,option,area,title,link,base,script,td',newline_after_elements:'br,hr,p,pre,address,div,ul,ol,meta,option,area,link,base,script',newline_before_after_elements:'html,head,body,table,thead,tbody,tfoot,tr,form,ul,ol,blockquote,p,object,param,hr,div',indent_char:'\t',indent_levels:1,entity_encoding:'raw',valid_elements:'*[*]',entities:'',url_converter:'',invalid_elements:'',verify_html:false};this.vElements=tinyMCE.clearArray(new Array());this.vElementsRe='';this.closeElementsRe=/^(IMG|BR|HR|LINK|META|BASE|INPUT|AREA)$/;this.codeElementsRe=/^(SCRIPT|STYLE)$/;this.serializationId=0;this.mceAttribs={href:'mce_href',src:'mce_src',type:'mce_type'}}TinyMCE_Cleanup.prototype={init:function(s){var n,a,i,ir,or,st;for(n in s)this.settings[n]=s[n];s=this.settings;this.inRe=this._arrayToRe(s.indent_elements.split(','),'','^<(',')[^>]*');this.ouRe=this._arrayToRe(s.indent_elements.split(','),'','^<\\/(',')[^>]*');this.nlBeforeRe=this._arrayToRe(s.newline_before_elements.split(','),'gi','<(',')([^>]*)>');this.nlAfterRe=this._arrayToRe(s.newline_after_elements.split(','),'gi','<(',')([^>]*)>');this.nlBeforeAfterRe=this._arrayToRe(s.newline_before_after_elements.split(','),'gi','<(\\/?)(',')([^>]*)>');this.serializedNodes=[];if(s.invalid_elements!='')this.iveRe=this._arrayToRe(s.invalid_elements.toUpperCase().split(','),'g','^(',')$');else this.iveRe=null;st='';for(i=0;i<s.indent_levels;i++)st+=s.indent_char;this.inStr=st;if(!s.verify_html){s.valid_elements='*[*]';s.extended_valid_elements=''}this.fillStr=s.entity_encoding=="named"?"&nbsp;":"&#160;";this.idCount=0;this.xmlEncodeRe=new RegExp('[\u007F-\uFFFF<>&"]','g');this.xmlEncodeAposRe=new RegExp('[\u007F-\uFFFF<>&"\']','g')},addRuleStr:function(s){var r=this.parseRuleStr(s);var n;for(n in r){if(r[n])this.rules[n]=r[n]}this.vElements=tinyMCE.clearArray(new Array());for(n in this.rules){if(this.rules[n])this.vElements[this.vElements.length]=this.rules[n].tag}this.vElementsRe=this._arrayToRe(this.vElements,'')},isValid:function(n){this._setupRules();if(!n)return true;n=n.replace(/[^a-z0-9]+/gi,'').toUpperCase();return!tinyMCE.getParam('cleanup')||this.vElementsRe.test(n)},addChildRemoveRuleStr:function(s){var x,y,p,i,t,tn,ta,cl,r;if(!s)return;ta=s.split(',');for(x=0;x<ta.length;x++){s=ta[x];p=this.split(/\[|\]/,s);if(p==null||p.length<1)t=s.toUpperCase();else t=p[0].toUpperCase();tn=this.split('/',t);for(y=0;y<tn.length;y++){r="^(";cl=this.split(/\|/,p[1]);for(i=0;i<cl.length;i++){if(cl[i]=='%istrict')r+=tinyMCE.inlineStrict;else if(cl[i]=='%itrans')r+=tinyMCE.inlineTransitional;else if(cl[i]=='%istrict_na')r+=tinyMCE.inlineStrict.substring(2);else if(cl[i]=='%itrans_na')r+=tinyMCE.inlineTransitional.substring(2);else if(cl[i]=='%btrans')r+=tinyMCE.blockElms;else if(cl[i]=='%strict')r+=tinyMCE.blockStrict;else r+=(cl[i].charAt(0)!='#'?cl[i].toUpperCase():cl[i]);r+=(i!=cl.length-1?'|':'')}r+=')$';if(this.childRules==null)this.childRules=tinyMCE.clearArray(new Array());this.childRules[tn[y]]=new RegExp(r);if(p.length>1)this.childRules[tn[y]].wrapTag=p[2]}}},parseRuleStr:function(s){var ta,p,r,a,i,x,px,t,tn,y,av,or=tinyMCE.clearArray(new Array()),dv;if(s==null||s.length==0)return or;ta=s.split(',');for(x=0;x<ta.length;x++){s=ta[x];if(s.length==0)continue;p=this.split(/\[|\]/,s);if(p==null||p.length<1)t=s.toUpperCase();else t=p[0].toUpperCase();tn=this.split('/',t);for(y=0;y<tn.length;y++){r={};r.tag=tn[y];r.forceAttribs=null;r.defaultAttribs=null;r.validAttribValues=null;px=r.tag.charAt(0);r.forceOpen=px=='+';r.removeEmpty=px=='-';r.fill=px=='#';r.tag=r.tag.replace(/\+|-|#/g,'');r.oTagName=tn[0].replace(/\+|-|#/g,'').toLowerCase();r.isWild=new RegExp('\\*|\\?|\\+','g').test(r.tag);r.validRe=new RegExp(this._wildcardToRe('^'+r.tag+'$'));if(p.length>1){r.vAttribsRe='^(';a=this.split(/\|/,p[1]);for(i=0;i<a.length;i++){t=a[i];if(t.charAt(0)=='!'){a[i]=t=t.substring(1);if(!r.reqAttribsRe)r.reqAttribsRe='\\s+('+t;else r.reqAttribsRe+='|'+t}av=new RegExp('(=|:|<)(.*?)$').exec(t);t=t.replace(new RegExp('(=|:|<).*?$'),'');if(av&&av.length>0){if(av[0].charAt(0)==':'){if(!r.forceAttribs)r.forceAttribs=tinyMCE.clearArray(new Array());r.forceAttribs[t.toLowerCase()]=av[0].substring(1)}else if(av[0].charAt(0)=='='){if(!r.defaultAttribs)r.defaultAttribs=tinyMCE.clearArray(new Array());dv=av[0].substring(1);r.defaultAttribs[t.toLowerCase()]=dv==""?"mce_empty":dv}else if(av[0].charAt(0)=='<'){if(!r.validAttribValues)r.validAttribValues=tinyMCE.clearArray(new Array());r.validAttribValues[t.toLowerCase()]=this._arrayToRe(this.split('?',av[0].substring(1)),'i')}}r.vAttribsRe+=''+t.toLowerCase()+(i!=a.length-1?'|':'');a[i]=t.toLowerCase()}if(r.reqAttribsRe)r.reqAttribsRe=new RegExp(r.reqAttribsRe+')=\"','g');r.vAttribsRe+=')$';r.vAttribsRe=this._wildcardToRe(r.vAttribsRe);r.vAttribsReIsWild=new RegExp('\\*|\\?|\\+','g').test(r.vAttribsRe);r.vAttribsRe=new RegExp(r.vAttribsRe);r.vAttribs=a.reverse();}else{r.vAttribsRe='';r.vAttribs=tinyMCE.clearArray(new Array());r.vAttribsReIsWild=false}or[r.tag]=r}}return or},serializeNodeAsXML:function(n){var s,b;if(!this.xmlDoc){if(this.isIE){try{this.xmlDoc=new ActiveXObject('MSXML2.DOMDocument')}catch(e){}if(!this.xmlDoc)try{this.xmlDoc=new ActiveXObject('Microsoft.XmlDom')}catch(e){}}else this.xmlDoc=document.implementation.createDocument('','',null);if(!this.xmlDoc)alert("Error XML Parser could not be found.")}if(this.xmlDoc.firstChild)this.xmlDoc.removeChild(this.xmlDoc.firstChild);b=this.xmlDoc.createElement("html");b=this.xmlDoc.appendChild(b);this._convertToXML(n,b);if(this.isIE)return this.xmlDoc.xml;else return new XMLSerializer().serializeToString(this.xmlDoc)},_convertToXML:function(n,xn){var xd,el,i,l,cn,at,no,hc=false;if(tinyMCE.isRealIE&&this._isDuplicate(n))return;xd=this.xmlDoc;switch(n.nodeType){case 1:hc=n.hasChildNodes();el=xd.createElement(n.nodeName.toLowerCase());at=n.attributes;for(i=at.length-1;i>-1;i--){no=at[i];if(no.specified&&no.nodeValue)el.setAttribute(no.nodeName.toLowerCase(),no.nodeValue)}if(!hc&&!this.closeElementsRe.test(n.nodeName))el.appendChild(xd.createTextNode(""));xn=xn.appendChild(el);break;case 3:xn.appendChild(xd.createTextNode(n.nodeValue));return;case 8:xn.appendChild(xd.createComment(n.nodeValue));return}if(hc){cn=n.childNodes;for(i=0,l=cn.length;i<l;i++)this._convertToXML(cn[i],xn)}},serializeNodeAsHTML:function(n,inn){var en,no,h='',i,l,t,st,r,cn,va=false,f=false,at,hc,cr,nn;this._setupRules();if(tinyMCE.isRealIE&&this._isDuplicate(n))return'';if(n.parentNode&&this.childRules!=null){cr=this.childRules[n.parentNode.nodeName];if(typeof(cr)!="undefined"&&!cr.test(n.nodeName)){st=true;t=null}}switch(n.nodeType){case 1:hc=n.hasChildNodes();if(st)break;if((tinyMCE.isRealIE)&&n.nodeName.indexOf('/')!=-1)break;nn=n.nodeName;if(this.settings.convert_fonts_to_spans){if(this.settings.on_save&&nn=='FONT')nn='SPAN';if(!this.settings.on_save&&nn=='SPAN')nn='FONT'}if(this.vElementsRe.test(nn)&&(!this.iveRe||!this.iveRe.test(nn))&&!inn){va=true;r=this.rules[nn];if(!r){at=this.rules;for(no in at){if(at[no]&&at[no].validRe.test(nn)){r=at[no];break}}}en=r.isWild?nn.toLowerCase():r.oTagName;f=r.fill;if(r.removeEmpty&&!hc)return"";t='<'+en;if(r.vAttribsReIsWild){at=n.attributes;for(i=at.length-1;i>-1;i--){no=at[i];if(no.specified&&r.vAttribsRe.test(no.nodeName))t+=this._serializeAttribute(n,r,no.nodeName)}}else{for(i=r.vAttribs.length-1;i>-1;i--)t+=this._serializeAttribute(n,r,r.vAttribs[i])}if(!this.settings.on_save){at=this.mceAttribs;for(no in at){if(at[no])t+=this._serializeAttribute(n,r,at[no])}}if(r.reqAttribsRe&&!t.match(r.reqAttribsRe))t=null;if(t!=null&&this.closeElementsRe.test(nn))return t+' />';if(t!=null)h+=t+'>';if(this.isIE&&this.codeElementsRe.test(nn))h+=n.innerHTML}break;case 3:if(st)break;if(n.parentNode&&this.codeElementsRe.test(n.parentNode.nodeName))return this.isIE?'':n.nodeValue;return this.xmlEncode(n.nodeValue);case 8:if(st)break;return"<!--"+this._trimComment(n.nodeValue)+"-->"}if(hc){cn=n.childNodes;for(i=0,l=cn.length;i<l;i++)h+=this.serializeNodeAsHTML(cn[i])}if(f&&!hc)h+=this.fillStr;if(t!=null&&va)h+='</'+en+'>';return h},_serializeAttribute:function(n,r,an){var av='',t,os=this.settings.on_save;if(os&&(an.indexOf('mce_')==0||an.indexOf('_moz')==0))return'';if(os&&this.mceAttribs[an])av=this._getAttrib(n,this.mceAttribs[an]);if(av.length==0)av=this._getAttrib(n,an);if(av.length==0&&r.defaultAttribs&&(t=r.defaultAttribs[an])){av=t;if(av=="mce_empty")return" "+an+'=""'}if(r.forceAttribs&&(t=r.forceAttribs[an]))av=t;if(os&&av.length!=0&&/^(src|href|longdesc)$/.test(an))av=this._urlConverter(this,n,av);if(av.length!=0&&r.validAttribValues&&r.validAttribValues[an]&&!r.validAttribValues[an].test(av))return"";if(av.length!=0&&av=="{$uid}")av="uid_"+(this.idCount++);if(av.length!=0){if(an.indexOf('on')!=0)av=this.xmlEncode(av,1);return" "+an+"="+'"'+av+'"'}return""},formatHTML:function(h){var s=this.settings,p='',i=0,li=0,o='',l;h=h.replace(/<pre([^>]*)>(.*?)<\/pre>/gi,function(a,b,c){c=c.replace(/<br\s*\/>/gi,'\n');return'<pre'+b+'>'+c+'</pre>'});h=h.replace(/\r/g,'');h='\n'+h;h=h.replace(new RegExp('\\n\\s+','gi'),'\n');h=h.replace(this.nlBeforeRe,'\n<$1$2>');h=h.replace(this.nlAfterRe,'<$1$2>\n');h=h.replace(this.nlBeforeAfterRe,'\n<$1$2$3>\n');h+='\n';while((i=h.indexOf('\n',i+1))!=-1){if((l=h.substring(li+1,i)).length!=0){if(this.ouRe.test(l)&&p.length>=s.indent_levels)p=p.substring(s.indent_levels);o+=p+l+'\n';if(this.inRe.test(l))p+=this.inStr}li=i}return o},xmlEncode:function(s,skip_apos){var cl=this,re=!skip_apos?this.xmlEncodeAposRe:this.xmlEncodeRe;this._setupEntities();switch(this.settings.entity_encoding){case"raw":return tinyMCE.xmlEncode(s,skip_apos);case"named":return s.replace(re,function(c,b){b=cl.entities[c.charCodeAt(0)];return b?'&'+b+';':c});case"numeric":return s.replace(re,function(c,b){return b?'&#'+c.charCodeAt(0)+';':c})}return s},split:function(re,s){var c=s.split(re);var i,l,o=new Array();for(i=0,l=c.length;i<l;i++){if(c[i]!='')o[i]=c[i]}return o},_trimComment:function(s){s=s.replace(new RegExp('\\smce_src=\"[^\"]*\"','gi'),"");s=s.replace(new RegExp('\\smce_href=\"[^\"]*\"','gi'),"");return s},_getAttrib:function(e,n,d){var v,ex,nn;if(typeof(d)=="undefined")d="";if(!e||e.nodeType!=1)return d;try{v=e.getAttribute(n,0)}catch(ex){v=e.getAttribute(n,2)}if(n=="class"&&!v)v=e.className;if(this.isIE){if(n=="http-equiv")v=e.httpEquiv;nn=e.nodeName;if(nn=="FORM"&&n=="enctype"&&v=="application/x-www-form-urlencoded")v="";if(nn=="INPUT"&&n=="size"&&v=="20")v="";if(nn=="INPUT"&&n=="maxlength"&&v=="2147483647")v=""}if(n=='style'&&v){if(!tinyMCE.isOpera)v=e.style.cssText;v=tinyMCE.serializeStyle(tinyMCE.parseStyle(v))}if(this.settings.on_save&&n.indexOf('on')!=-1&&this.settings.on_save&&v&&v!="")v=tinyMCE.cleanupEventStr(v);return(v&&v!="")?''+v:d},_urlConverter:function(c,n,v){if(!c.settings.on_save)return tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings.base_href,v);else if(tinyMCE.getParam('convert_urls')){if(!this.urlConverter)this.urlConverter=eval(tinyMCE.settings.urlconverter_callback);return this.urlConverter(v,n,true)}return v},_arrayToRe:function(a,op,be,af){var i,r;op=typeof(op)=="undefined"?"gi":op;be=typeof(be)=="undefined"?"^(":be;af=typeof(af)=="undefined"?")$":af;r=be;for(i=0;i<a.length;i++)r+=this._wildcardToRe(a[i])+(i!=a.length-1?"|":"");r+=af;return new RegExp(r,op)},_wildcardToRe:function(s){s=s.replace(/\?/g,'(\\S?)');s=s.replace(/\+/g,'(\\S+)');s=s.replace(/\*/g,'(\\S*)');return s},_setupEntities:function(){var n,a,i,s=this.settings;if(!this.entitiesDone){if(s.entity_encoding=="named"){n=tinyMCE.clearArray(new Array());a=this.split(',',s.entities);for(i=0;i<a.length;i+=2)n[a[i]]=a[i+1];this.entities=n}this.entitiesDone=true}},_setupRules:function(){var s=this.settings;if(!this.rulesDone){this.addRuleStr(s.valid_elements);this.addRuleStr(s.extended_valid_elements);this.addChildRemoveRuleStr(s.valid_child_elements);this.rulesDone=true}},_isDuplicate:function(n){var i;if(!this.settings.fix_content_duplication)return false;if(tinyMCE.isRealIE&&n.nodeType==1){if(n.mce_serialized==this.serializationId)return true;n.setAttribute('mce_serialized',this.serializationId)}else{for(i=0;i<this.serializedNodes.length;i++){if(this.serializedNodes[i]==n)return true}this.serializedNodes[this.serializedNodes.length]=n}return false}};TinyMCE_Engine.prototype.createTagHTML=function(tn,a,h){var o='',f=tinyMCE.xmlEncode;o='<'+tn;if(a){for(n in a){if(typeof(a[n])!='function'&&a[n]!=null)o+=' '+f(n)+'="'+f(''+a[n])+'"'}}o+=!h?' />':'>'+h+'</'+tn+'>';return o};TinyMCE_Engine.prototype.createTag=function(d,tn,a,h){var o=d.createElement(tn);if(a){for(n in a){if(typeof(a[n])!='function'&&a[n]!=null)tinyMCE.setAttrib(o,n,a[n])}}if(h)o.innerHTML=h;return o};TinyMCE_Engine.prototype.getElementByAttributeValue=function(n,e,a,v){return(n=this.getElementsByAttributeValue(n,e,a,v)).length==0?null:n[0]};TinyMCE_Engine.prototype.getElementsByAttributeValue=function(n,e,a,v){var i,nl=n.getElementsByTagName(e),o=new Array();for(i=0;i<nl.length;i++){if(tinyMCE.getAttrib(nl[i],a).indexOf(v)!=-1)o[o.length]=nl[i]}return o};TinyMCE_Engine.prototype.isBlockElement=function(n){return n!=null&&n.nodeType==1&&this.blockRegExp.test(n.nodeName)};TinyMCE_Engine.prototype.getParentBlockElement=function(n,r){return this.getParentNode(n,function(n){return tinyMCE.isBlockElement(n)},r);return null};TinyMCE_Engine.prototype.insertAfter=function(n,r){if(r.nextSibling)r.parentNode.insertBefore(n,r.nextSibling);else r.parentNode.appendChild(n)};TinyMCE_Engine.prototype.setInnerHTML=function(e,h){var i,nl,n;if(tinyMCE.isGecko){h=h.replace(/<embed([^>]*)>/gi,'<tmpembed$1>');h=h.replace(/<em([^>]*)>/gi,'<i$1>');h=h.replace(/<tmpembed([^>]*)>/gi,'<embed$1>');h=h.replace(/<strong([^>]*)>/gi,'<b$1>');h=h.replace(/<\/strong>/gi,'</b>');h=h.replace(/<\/em>/gi,'</i>')}if(tinyMCE.isRealIE){h=h.replace(/\s\/>/g,'>');h=h.replace(/<p([^>]*)>\u00A0?<\/p>/gi,'<p$1 mce_keep="true">&nbsp;</p>');h=h.replace(/<p([^>]*)>\s*&nbsp;\s*<\/p>/gi,'<p$1 mce_keep="true">&nbsp;</p>');h=h.replace(/<p([^>]*)>\s+<\/p>/gi,'<p$1 mce_keep="true">&nbsp;</p>');e.innerHTML=tinyMCE.uniqueTag+h;e.firstChild.removeNode(true);nl=e.getElementsByTagName("p");for(i=nl.length-1;i>=0;i--){n=nl[i];if(n.nodeName=='P'&&!n.hasChildNodes()&&!n.mce_keep)n.parentNode.removeChild(n)}}else{h=this.fixGeckoBaseHREFBug(1,e,h);e.innerHTML=h;this.fixGeckoBaseHREFBug(2,e,h)}};TinyMCE_Engine.prototype.getOuterHTML=function(e){if(tinyMCE.isIE)return e.outerHTML;var d=e.ownerDocument.createElement("body");d.appendChild(e.cloneNode(true));return d.innerHTML};TinyMCE_Engine.prototype.setOuterHTML=function(e,h,d){var d=typeof(d)=="undefined"?e.ownerDocument:d,i,nl,t;if(tinyMCE.isIE&&e.nodeType==1)e.outerHTML=h;else{t=d.createElement("body");t.innerHTML=h;for(i=0,nl=t.childNodes;i<nl.length;i++)e.parentNode.insertBefore(nl[i].cloneNode(true),e);e.parentNode.removeChild(e)}};TinyMCE_Engine.prototype._getElementById=function(id,d){var e,i,j,f;if(typeof(d)=="undefined")d=document;e=d.getElementById(id);if(!e){f=d.forms;for(i=0;i<f.length;i++){for(j=0;j<f[i].elements.length;j++){if(f[i].elements[j].name==id){e=f[i].elements[j];break}}}}return e};TinyMCE_Engine.prototype.getNodeTree=function(n,na,t,nn){return this.selectNodes(n,function(n){return(!t||n.nodeType==t)&&(!nn||n.nodeName==nn)},na?na:new Array())};TinyMCE_Engine.prototype.getParentElement=function(n,na,f,r){var re=na?new RegExp('^('+na.toUpperCase().replace(/,/g,'|')+')$'):0,v;if(f&&typeof(f)=='string')return this.getParentElement(n,na,function(no){return tinyMCE.getAttrib(no,f)!=''});return this.getParentNode(n,function(n){return((n.nodeType==1&&!re)||(re&&re.test(n.nodeName)))&&(!f||f(n))},r)};TinyMCE_Engine.prototype.getParentNode=function(n,f,r){while(n){if(n==r)return null;if(f(n))return n;n=n.parentNode}return null};TinyMCE_Engine.prototype.getAttrib=function(elm,name,dv){var v;if(typeof(dv)=="undefined")dv="";if(!elm||elm.nodeType!=1)return dv;try{v=elm.getAttribute(name,0)}catch(ex){v=elm.getAttribute(name,2)}if(name=="class"&&!v)v=elm.className;if(tinyMCE.isGecko&&name=="src"&&elm.src!=null&&elm.src!="")v=elm.src;if(tinyMCE.isGecko&&name=="href"&&elm.href!=null&&elm.href!="")v=elm.href;if(name=="http-equiv"&&tinyMCE.isIE)v=elm.httpEquiv;if(name=="style"&&!tinyMCE.isOpera)v=elm.style.cssText;return(v&&v!="")?v:dv};TinyMCE_Engine.prototype.setAttrib=function(el,name,va,fix){if(typeof(va)=="number"&&va!=null)va=""+va;if(fix){if(va==null)va="";va=va.replace(/[^0-9%]/g,'')}if(name=="style")el.style.cssText=va;if(name=="class")el.className=va;if(va!=null&&va!=""&&va!=-1)el.setAttribute(name,va);else el.removeAttribute(name)};TinyMCE_Engine.prototype.setStyleAttrib=function(e,n,v){e.style[n]=v;if(tinyMCE.isIE&&v==null||v==''){v=tinyMCE.serializeStyle(tinyMCE.parseStyle(e.style.cssText));e.style.cssText=v;e.setAttribute("style",v)}};TinyMCE_Engine.prototype.switchClass=function(ei,c){var e;if(tinyMCE.switchClassCache[ei])e=tinyMCE.switchClassCache[ei];else e=tinyMCE.switchClassCache[ei]=document.getElementById(ei);if(e){if(tinyMCE.settings.button_tile_map&&e.className&&e.className.indexOf('mceTiledButton')==0)c='mceTiledButton '+c;e.className=c}};TinyMCE_Engine.prototype.getAbsPosition=function(n,cn){var l=0,t=0;while(n&&n!=cn){l+=n.offsetLeft;t+=n.offsetTop;n=n.offsetParent}return{absLeft:l,absTop:t}};TinyMCE_Engine.prototype.prevNode=function(e,n){var a=n.split(','),i;while((e=e.previousSibling)!=null){for(i=0;i<a.length;i++){if(e.nodeName==a[i])return e}}return null};TinyMCE_Engine.prototype.nextNode=function(e,n){var a=n.split(','),i;while((e=e.nextSibling)!=null){for(i=0;i<a.length;i++){if(e.nodeName==a[i])return e}}return null};TinyMCE_Engine.prototype.selectElements=function(n,na,f){var i,a=[],nl,x;for(x=0,na=na.split(',');x<na.length;x++)for(i=0,nl=n.getElementsByTagName(na[x]);i<nl.length;i++)(!f||f(nl[i]))&&a.push(nl[i]);return a};TinyMCE_Engine.prototype.selectNodes=function(n,f,a){var i;if(!a)a=new Array();if(f(n))a[a.length]=n;if(n.hasChildNodes()){for(i=0;i<n.childNodes.length;i++)tinyMCE.selectNodes(n.childNodes[i],f,a)}return a};TinyMCE_Engine.prototype.addCSSClass=function(e,c,b){var o=this.removeCSSClass(e,c);return e.className=b?c+(o!=''?(' '+o):''):(o!=''?(o+' '):'')+c};TinyMCE_Engine.prototype.removeCSSClass=function(e,c){c=e.className.replace(new RegExp("(^|\\s+)"+c+"(\\s+|$)"),' ');return e.className=c!=' '?c:''};TinyMCE_Engine.prototype.hasCSSClass=function(n,c){return new RegExp('\\b'+c+'\\b','g').test(n.className)};TinyMCE_Engine.prototype.renameElement=function(e,n,d){var ne,i,ar;d=typeof(d)=="undefined"?tinyMCE.selectedInstance.getDoc():d;if(e){ne=d.createElement(n);ar=e.attributes;for(i=ar.length-1;i>-1;i--){if(ar[i].specified&&ar[i].nodeValue)ne.setAttribute(ar[i].nodeName.toLowerCase(),ar[i].nodeValue)}ar=e.childNodes;for(i=0;i<ar.length;i++)ne.appendChild(ar[i].cloneNode(true));e.parentNode.replaceChild(ne,e)}};TinyMCE_Engine.prototype.getViewPort=function(w){var d=w.document,m=d.compatMode=='CSS1Compat',b=d.body,de=d.documentElement;return{left:w.pageXOffset||(m?de.scrollLeft:b.scrollLeft),top:w.pageYOffset||(m?de.scrollTop:b.scrollTop),width:w.innerWidth||(m?de.clientWidth:b.clientWidth),height:w.innerHeight||(m?de.clientHeight:b.clientHeight)}};TinyMCE_Engine.prototype.getStyle=function(n,na,d){if(!n)return false;if(tinyMCE.isGecko&&n.ownerDocument.defaultView){try{return n.ownerDocument.defaultView.getComputedStyle(n,null).getPropertyValue(na)}catch(n){return null}}na=na.replace(/-(\D)/g,function(a,b){return b.toUpperCase()});if(n.currentStyle)return n.currentStyle[na];return false};TinyMCE_Engine.prototype.parseURL=function(url_str){var urlParts=new Array();if(url_str){var pos,lastPos;pos=url_str.indexOf('://');if(pos!=-1){urlParts['protocol']=url_str.substring(0,pos);lastPos=pos+3}for(var i=lastPos;i<url_str.length;i++){var chr=url_str.charAt(i);if(chr==':')break;if(chr=='/')break}pos=i;urlParts['host']=url_str.substring(lastPos,pos);urlParts['port']="";lastPos=pos;if(url_str.charAt(pos)==':'){pos=url_str.indexOf('/',lastPos);urlParts['port']=url_str.substring(lastPos+1,pos)}lastPos=pos;pos=url_str.indexOf('?',lastPos);if(pos==-1)pos=url_str.indexOf('#',lastPos);if(pos==-1)pos=url_str.length;urlParts['path']=url_str.substring(lastPos,pos);lastPos=pos;if(url_str.charAt(pos)=='?'){pos=url_str.indexOf('#');pos=(pos==-1)?url_str.length:pos;urlParts['query']=url_str.substring(lastPos+1,pos)}lastPos=pos;if(url_str.charAt(pos)=='#'){pos=url_str.length;urlParts['anchor']=url_str.substring(lastPos+1,pos)}}return urlParts};TinyMCE_Engine.prototype.serializeURL=function(up){var o="";if(up['protocol'])o+=up['protocol']+"://";if(up['host'])o+=up['host'];if(up['port'])o+=":"+up['port'];if(up['path'])o+=up['path'];if(up['query'])o+="?"+up['query'];if(up['anchor'])o+="#"+up['anchor'];return o};TinyMCE_Engine.prototype.convertAbsoluteURLToRelativeURL=function(base_url,url_to_relative){var baseURL=this.parseURL(base_url);var targetURL=this.parseURL(url_to_relative);var strTok1;var strTok2;var breakPoint=0;var outPath="";var forceSlash=false;if(targetURL.path=="")targetURL.path="/";else forceSlash=true;base_url=baseURL.path.substring(0,baseURL.path.lastIndexOf('/'));strTok1=base_url.split('/');strTok2=targetURL.path.split('/');if(strTok1.length>=strTok2.length){for(var i=0;i<strTok1.length;i++){if(i>=strTok2.length||strTok1[i]!=strTok2[i]){breakPoint=i+1;break}}}if(strTok1.length<strTok2.length){for(var i=0;i<strTok2.length;i++){if(i>=strTok1.length||strTok1[i]!=strTok2[i]){breakPoint=i+1;break}}}if(breakPoint==1)return targetURL.path;for(var i=0;i<(strTok1.length-(breakPoint-1));i++)outPath+="../";for(var i=breakPoint-1;i<strTok2.length;i++){if(i!=(breakPoint-1))outPath+="/"+strTok2[i];else outPath+=strTok2[i]}targetURL.protocol=null;targetURL.host=null;targetURL.port=null;targetURL.path=outPath==""&&forceSlash?"/":outPath;var fileName=baseURL.path;var pos;if((pos=fileName.lastIndexOf('/'))!=-1)fileName=fileName.substring(pos+1);if(fileName==targetURL.path&&targetURL.anchor!="")targetURL.path="";if(targetURL.path==""&&!targetURL.anchor)targetURL.path=fileName!=""?fileName:"/";return this.serializeURL(targetURL)};TinyMCE_Engine.prototype.convertRelativeToAbsoluteURL=function(base_url,relative_url){var baseURL=this.parseURL(base_url),baseURLParts,relURLParts;var relURL=this.parseURL(relative_url);if(relative_url==""||relative_url.indexOf('://')!=-1||/^(mailto:|javascript:|#|\/)/.test(relative_url))return relative_url;baseURLParts=baseURL['path'].split('/');relURLParts=relURL['path'].split('/');var newBaseURLParts=new Array();for(var i=baseURLParts.length-1;i>=0;i--){if(baseURLParts[i].length==0)continue;newBaseURLParts[newBaseURLParts.length]=baseURLParts[i]}baseURLParts=newBaseURLParts.reverse();var newRelURLParts=new Array();var numBack=0;for(var i=relURLParts.length-1;i>=0;i--){if(relURLParts[i].length==0||relURLParts[i]==".")continue;if(relURLParts[i]=='..'){numBack++;continue}if(numBack>0){numBack--;continue}newRelURLParts[newRelURLParts.length]=relURLParts[i]}relURLParts=newRelURLParts.reverse();var len=baseURLParts.length-numBack;var absPath=(len<=0?"":"/")+baseURLParts.slice(0,len).join('/')+"/"+relURLParts.join('/');var start="",end="";relURL.protocol=baseURL.protocol;relURL.host=baseURL.host;relURL.port=baseURL.port;if(relURL.path.charAt(relURL.path.length-1)=="/")absPath+="/";relURL.path=absPath;return this.serializeURL(relURL)};TinyMCE_Engine.prototype.convertURL=function(url,node,on_save){var prot=document.location.protocol;var host=document.location.hostname;var port=document.location.port;if(prot=="file:")return url;url=tinyMCE.regexpReplace(url,'(http|https):///','/');if(url.indexOf('mailto:')!=-1||url.indexOf('javascript:')!=-1||tinyMCE.regexpReplace(url,'[ \t\r\n\+]|%20','').charAt(0)=="#")return url;if(!tinyMCE.isIE&&!on_save&&url.indexOf("://")==-1&&url.charAt(0)!='/')return tinyMCE.settings['base_href']+url;if(on_save&&tinyMCE.getParam('relative_urls')){var curl=tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'],url);if(curl.charAt(0)=='/')curl=tinyMCE.settings['document_base_prefix']+curl;var urlParts=tinyMCE.parseURL(curl);var tmpUrlParts=tinyMCE.parseURL(tinyMCE.settings['document_base_url']);if(urlParts['host']==tmpUrlParts['host']&&(urlParts['port']==tmpUrlParts['port']))return tinyMCE.convertAbsoluteURLToRelativeURL(tinyMCE.settings['document_base_url'],curl)}if(!tinyMCE.getParam('relative_urls')){var urlParts=tinyMCE.parseURL(url);var baseUrlParts=tinyMCE.parseURL(tinyMCE.settings['base_href']);url=tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'],url);if(urlParts['anchor']&&urlParts['path']==baseUrlParts['path'])return"#"+urlParts['anchor']}if(tinyMCE.getParam('remove_script_host')){var start="",portPart="";if(port!="")portPart=":"+port;start=prot+"//"+host+portPart+"/";if(url.indexOf(start)==0)url=url.substring(start.length-1)}return url};TinyMCE_Engine.prototype.convertAllRelativeURLs=function(body){var i,elms,src,href,mhref,msrc;elms=body.getElementsByTagName("img");for(i=0;i<elms.length;i++){src=tinyMCE.getAttrib(elms[i],'src');msrc=tinyMCE.getAttrib(elms[i],'mce_src');if(msrc!="")src=msrc;if(src!=""){src=tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'],src);elms[i].setAttribute("src",src)}}elms=body.getElementsByTagName("a");for(i=0;i<elms.length;i++){href=tinyMCE.getAttrib(elms[i],'href');mhref=tinyMCE.getAttrib(elms[i],'mce_href');if(mhref!="")href=mhref;if(href&&href!=""){href=tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'],href);elms[i].setAttribute("href",href)}}};TinyMCE_Engine.prototype.clearArray=function(a){var n;for(n in a)a[n]=null;return a};TinyMCE_Engine.prototype.explode=function(d,s){var ar=s.split(d),oar=new Array(),i;for(i=0;i<ar.length;i++){if(ar[i]!="")oar[oar.length]=ar[i]}return oar};TinyMCE_Engine.prototype._setEventsEnabled=function(node,state){var evs,x,y,elms,i,event;var events=['onfocus','onblur','onclick','ondblclick','onmousedown','onmouseup','onmouseover','onmousemove','onmouseout','onkeypress','onkeydown','onkeydown','onkeyup'];evs=tinyMCE.settings['event_elements'].split(',');for(y=0;y<evs.length;y++){elms=node.getElementsByTagName(evs[y]);for(i=0;i<elms.length;i++){event="";for(x=0;x<events.length;x++){if((event=tinyMCE.getAttrib(elms[i],events[x]))!=''){event=tinyMCE.cleanupEventStr(""+event);if(!state)event="return true;"+event;else event=event.replace(/^return true;/gi,'');elms[i].removeAttribute(events[x]);elms[i].setAttribute(events[x],event)}}}}};TinyMCE_Engine.prototype._eventPatch=function(editor_id){var n,inst,win,e;if(typeof(tinyMCE)=="undefined")return true;try{if(tinyMCE.selectedInstance){win=tinyMCE.selectedInstance.getWin();if(win&&win.event){e=win.event;if(!e.target)e.target=e.srcElement;TinyMCE_Engine.prototype.handleEvent(e);return}}for(n in tinyMCE.instances){inst=tinyMCE.instances[n];if(!tinyMCE.isInstance(inst))continue;inst.select();win=inst.getWin();if(win&&win.event){e=win.event;if(!e.target)e.target=e.srcElement;TinyMCE_Engine.prototype.handleEvent(e);return}}}catch(ex){}};TinyMCE_Engine.prototype.findEvent=function(e){var n,inst;if(e)return e;for(n in tinyMCE.instances){inst=tinyMCE.instances[n];if(tinyMCE.isInstance(inst)&&inst.getWin().event)return inst.getWin().event}return null};TinyMCE_Engine.prototype.unloadHandler=function(){tinyMCE.triggerSave(true,true)};TinyMCE_Engine.prototype.addEventHandlers=function(inst){this.setEventHandlers(inst,1)};TinyMCE_Engine.prototype.setEventHandlers=function(inst,s){var doc=inst.getDoc(),ie,ot,i,f=s?tinyMCE.addEvent:tinyMCE.removeEvent;ie=['keypress','keyup','keydown','click','mouseup','mousedown','controlselect','dblclick'];ot=['keypress','keyup','keydown','click','mouseup','mousedown','focus','blur','dragdrop'];inst.switchSettings();if(tinyMCE.isIE){for(i=0;i<ie.length;i++)f(doc,ie[i],TinyMCE_Engine.prototype._eventPatch)}else{for(i=0;i<ot.length;i++)f(doc,ot[i],tinyMCE.handleEvent);try{doc.designMode="On"}catch(e){}}};TinyMCE_Engine.prototype.onMouseMove=function(){var inst,lh;if(tinyMCE.lastHover){lh=tinyMCE.lastHover;if(lh.className.indexOf('mceMenu')!=-1)tinyMCE._menuButtonEvent('out',lh);else lh.className=lh.className;tinyMCE.lastHover=null}if(!tinyMCE.hasMouseMoved){inst=tinyMCE.selectedInstance;if(inst.isFocused){inst.undoBookmark=inst.selection.getBookmark();tinyMCE.hasMouseMoved=true}}};TinyMCE_Engine.prototype.cancelEvent=function(e){if(!e)return false;if(tinyMCE.isIE){e.returnValue=false;e.cancelBubble=true}else{e.preventDefault();e.stopPropagation&&e.stopPropagation()}return false};TinyMCE_Engine.prototype.addEvent=function(o,n,h){if(n!='unload'){function clean(){var ex;try{tinyMCE.removeEvent(o,n,h);tinyMCE.removeEvent(window,'unload',clean);o=n=h=null}catch(ex){}}tinyMCE.addEvent(window,'unload',clean)}if(o.attachEvent)o.attachEvent("on"+n,h);else o.addEventListener(n,h,false)};TinyMCE_Engine.prototype.removeEvent=function(o,n,h){if(o.detachEvent)o.detachEvent("on"+n,h);else o.removeEventListener(n,h,false)};TinyMCE_Engine.prototype.addSelectAccessibility=function(e,s,w){if(!s._isAccessible){s.onkeydown=tinyMCE.accessibleEventHandler;s.onblur=tinyMCE.accessibleEventHandler;s._isAccessible=true;s._win=w}return false};TinyMCE_Engine.prototype.accessibleEventHandler=function(e){var win=this._win;e=tinyMCE.isIE?win.event:e;var elm=tinyMCE.isIE?e.srcElement:e.target;if(e.type=="blur"){if(elm.oldonchange){elm.onchange=elm.oldonchange;elm.oldonchange=null}return true}if(elm.nodeName=="SELECT"&&!elm.oldonchange){elm.oldonchange=elm.onchange;elm.onchange=null}if(e.keyCode==13||e.keyCode==32){elm.onchange=elm.oldonchange;elm.onchange();elm.oldonchange=null;tinyMCE.cancelEvent(e);return false}return true};TinyMCE_Engine.prototype._resetIframeHeight=function(){var ife;if(tinyMCE.isRealIE){ife=tinyMCE.selectedInstance.iframeElement;if(ife._oldHeight){ife.style.height=ife._oldHeight;ife.height=ife._oldHeight}}};function TinyMCE_Selection(inst){this.instance=inst};TinyMCE_Selection.prototype={getSelectedHTML:function(){var inst=this.instance;var e,r=this.getRng(),h;if(!r)return null;e=document.createElement("body");if(r.cloneContents)e.appendChild(r.cloneContents());else if(typeof(r.item)!='undefined'||typeof(r.htmlText)!='undefined')e.innerHTML=r.item?r.item(0).outerHTML:r.htmlText;else e.innerHTML=r.toString();h=tinyMCE._cleanupHTML(inst,inst.contentDocument,inst.settings,e,e,false,true,false);return h},getSelectedText:function(){var inst=this.instance;var d,r,s,t;if(tinyMCE.isIE){d=inst.getDoc();if(d.selection.type=="Text"){r=d.selection.createRange();t=r.text}else t=''}else{s=this.getSel();if(s&&s.toString)t=s.toString();else t=''}return t},getBookmark:function(simple){var inst=this.instance;var rng=this.getRng();var doc=inst.getDoc(),b=inst.getBody();var sp,le,s,e,nl,i,si,ei,w;var trng,sx,sy,xx=-999999999,vp=inst.getViewPort();sx=vp.left;sy=vp.top;if(tinyMCE.isSafari||tinyMCE.isOpera||simple)return{rng:rng,scrollX:sx,scrollY:sy};if(tinyMCE.isIE){if(rng.item){e=rng.item(0);nl=b.getElementsByTagName(e.nodeName);for(i=0;i<nl.length;i++){if(e==nl[i]){sp=i;break}}return{tag:e.nodeName,index:sp,scrollX:sx,scrollY:sy}}else{trng=doc.body.createTextRange();trng.moveToElementText(inst.getBody());trng.collapse(true);bp=Math.abs(trng.move('character',xx));trng=rng.duplicate();trng.collapse(true);sp=Math.abs(trng.move('character',xx));trng=rng.duplicate();trng.collapse(false);le=Math.abs(trng.move('character',xx))-sp;return{start:sp-bp,length:le,scrollX:sx,scrollY:sy}}}if(tinyMCE.isGecko){s=this.getSel();e=this.getFocusElement();if(!s)return null;if(e&&e.nodeName=='IMG'){return{start:-1,end:-1,index:sp,scrollX:sx,scrollY:sy}}if(s.anchorNode==s.focusNode&&s.anchorOffset==s.focusOffset){e=this._getPosText(b,s.anchorNode,s.focusNode);if(!e)return{scrollX:sx,scrollY:sy};return{start:e.start+s.anchorOffset,end:e.end+s.focusOffset,scrollX:sx,scrollY:sy}}else{e=this._getPosText(b,rng.startContainer,rng.endContainer);if(!e)return{scrollX:sx,scrollY:sy};return{start:e.start+rng.startOffset,end:e.end+rng.endOffset,scrollX:sx,scrollY:sy}}}return null},moveToBookmark:function(bookmark){var inst=this.instance;var rng,nl,i,ex,b=inst.getBody(),sd;var doc=inst.getDoc();var win=inst.getWin();var sel=this.getSel();if(!bookmark)return false;if(tinyMCE.isSafari){sel.setBaseAndExtent(bookmark.rng.startContainer,bookmark.rng.startOffset,bookmark.rng.endContainer,bookmark.rng.endOffset);return true}if(tinyMCE.isRealIE){if(bookmark.rng){try{bookmark.rng.select()}catch(ex){}return true}win.focus();if(bookmark.tag){rng=b.createControlRange();nl=b.getElementsByTagName(bookmark.tag);if(nl.length>bookmark.index){try{rng.addElement(nl[bookmark.index])}catch(ex){}}}else{try{if(bookmark.start<0)return true;rng=inst.getSel().createRange();rng.moveToElementText(inst.getBody());rng.collapse(true);rng.moveStart('character',bookmark.start);rng.moveEnd('character',bookmark.length)}catch(ex){return true}}rng.select();win.scrollTo(bookmark.scrollX,bookmark.scrollY);return true}if(tinyMCE.isGecko||tinyMCE.isOpera){if(!sel)return false;if(bookmark.rng){sel.removeAllRanges();sel.addRange(bookmark.rng)}if(bookmark.start!=-1&&bookmark.end!=-1){try{sd=this._getTextPos(b,bookmark.start,bookmark.end);rng=doc.createRange();rng.setStart(sd.startNode,sd.startOffset);rng.setEnd(sd.endNode,sd.endOffset);sel.removeAllRanges();sel.addRange(rng);win.focus()}catch(ex){}}win.scrollTo(bookmark.scrollX,bookmark.scrollY);return true}return false},_getPosText:function(r,sn,en){var w=document.createTreeWalker(r,NodeFilter.SHOW_TEXT,null,false),n,p=0,d={};while((n=w.nextNode())!=null){if(n==sn)d.start=p;if(n==en){d.end=p;return d}p+=n.nodeValue?n.nodeValue.length:0}return null},_getTextPos:function(r,sp,ep){var w=document.createTreeWalker(r,NodeFilter.SHOW_TEXT,null,false),n,p=0,d={};while((n=w.nextNode())!=null){p+=n.nodeValue?n.nodeValue.length:0;if(p>=sp&&!d.startNode){d.startNode=n;d.startOffset=sp-(p-n.nodeValue.length)}if(p>=ep){d.endNode=n;d.endOffset=ep-(p-n.nodeValue.length);return d}}return null},selectNode:function(node,collapse,select_text_node,to_start){var inst=this.instance,sel,rng,nodes;if(!node)return;if(typeof(collapse)=="undefined")collapse=true;if(typeof(select_text_node)=="undefined")select_text_node=false;if(typeof(to_start)=="undefined")to_start=true;if(inst.settings.auto_resize)inst.resizeToContent();if(tinyMCE.isRealIE){rng=inst.getDoc().body.createTextRange();try{rng.moveToElementText(node);if(collapse)rng.collapse(to_start);rng.select()}catch(e){}}else{sel=this.getSel();if(!sel)return;if(tinyMCE.isSafari){sel.setBaseAndExtent(node,0,node,node.innerText.length);if(collapse){if(to_start)sel.collapseToStart();else sel.collapseToEnd()}this.scrollToNode(node);return}rng=inst.getDoc().createRange();if(select_text_node){nodes=tinyMCE.getNodeTree(node,new Array(),3);if(nodes.length>0)rng.selectNodeContents(nodes[0]);else rng.selectNodeContents(node)}else rng.selectNode(node);if(collapse){if(!to_start&&node.nodeType==3){rng.setStart(node,node.nodeValue.length);rng.setEnd(node,node.nodeValue.length)}else rng.collapse(to_start)}sel.removeAllRanges();sel.addRange(rng)}this.scrollToNode(node);tinyMCE.selectedElement=null;if(node.nodeType==1)tinyMCE.selectedElement=node},scrollToNode:function(node){var inst=this.instance,w=inst.getWin(),vp=inst.getViewPort(),pos=tinyMCE.getAbsPosition(node),cvp,p,cwin;if(pos.absLeft<vp.left||pos.absLeft>vp.left+vp.width||pos.absTop<vp.top||pos.absTop>vp.top+(vp.height-25))w.scrollTo(pos.absLeft,pos.absTop-vp.height+25);if(inst.settings.auto_resize){cwin=inst.getContainerWin();cvp=tinyMCE.getViewPort(cwin);p=this.getAbsPosition(node);if(p.absLeft<cvp.left||p.absLeft>cvp.left+cvp.width||p.absTop<cvp.top||p.absTop>cvp.top+cvp.height)cwin.scrollTo(p.absLeft,p.absTop-cvp.height+25)}},getAbsPosition:function(n){var pos=tinyMCE.getAbsPosition(n),ipos=tinyMCE.getAbsPosition(this.instance.iframeElement);return{absLeft:ipos.absLeft+pos.absLeft,absTop:ipos.absTop+pos.absTop}},getSel:function(){var inst=this.instance;if(tinyMCE.isRealIE)return inst.getDoc().selection;return inst.contentWindow.getSelection()},getRng:function(){var s=this.getSel();if(s==null)return null;if(tinyMCE.isRealIE)return s.createRange();if(tinyMCE.isSafari&&!s.getRangeAt)return''+window.getSelection();if(s.rangeCount>0)return s.getRangeAt(0);return null},isCollapsed:function(){var r=this.getRng();if(r.item)return false;return r.boundingWidth==0||this.getSel().isCollapsed},collapse:function(b){var r=this.getRng(),s=this.getSel();if(r.select){r.collapse(b);r.select()}else{if(b)s.collapseToStart();else s.collapseToEnd()}},getFocusElement:function(){var inst=this.instance,doc,rng,sel,elm;if(tinyMCE.isRealIE){doc=inst.getDoc();rng=doc.selection.createRange();elm=rng.item?rng.item(0):rng.parentElement()}else{if(!tinyMCE.isSafari&&inst.isHidden())return inst.getBody();sel=this.getSel();rng=this.getRng();if(!sel||!rng)return null;elm=rng.commonAncestorContainer;if(!rng.collapsed){if(rng.startContainer==rng.endContainer){if(rng.startOffset-rng.endOffset<2){if(rng.startContainer.hasChildNodes())elm=rng.startContainer.childNodes[rng.startOffset]}}}elm=tinyMCE.getParentElement(elm);}return elm}};function TinyMCE_UndoRedo(inst){this.instance=inst;this.undoLevels=new Array();this.undoIndex=0;this.typingUndoIndex=-1;this.undoRedo=true};TinyMCE_UndoRedo.prototype={add:function(l){var b,customUndoLevels,newHTML,inst=this.instance,i,ul,ur;if(l){this.undoLevels[this.undoLevels.length]=l;return true}if(this.typingUndoIndex!=-1){this.undoIndex=this.typingUndoIndex;if(tinyMCE.typingUndoIndex!=-1)tinyMCE.undoIndex=tinyMCE.typingUndoIndex}newHTML=tinyMCE.trim(inst.getBody().innerHTML);if(this.undoLevels[this.undoIndex]&&newHTML!=this.undoLevels[this.undoIndex].content){tinyMCE.dispatchCallback(inst,'onchange_callback','onChange',inst);customUndoLevels=tinyMCE.settings['custom_undo_redo_levels'];if(customUndoLevels!=-1&&this.undoLevels.length>customUndoLevels){for(i=0;i<this.undoLevels.length-1;i++)this.undoLevels[i]=this.undoLevels[i+1];this.undoLevels.length--;this.undoIndex--;}b=inst.undoBookmark;if(!b)b=inst.selection.getBookmark();this.undoIndex++;this.undoLevels[this.undoIndex]={content:newHTML,bookmark:b};ul=tinyMCE.undoLevels;for(i=tinyMCE.undoIndex+1;i<ul.length;i++){ur=ul[i].undoRedo;if(ur.undoIndex==ur.undoLevels.length-1)ur.undoIndex--;ur.undoLevels.length--}tinyMCE.undoLevels[tinyMCE.undoIndex++]=inst;tinyMCE.undoLevels.length=tinyMCE.undoIndex;this.undoLevels.length=this.undoIndex+1;return true}return false},undo:function(){var inst=this.instance;if(this.undoIndex>0){this.undoIndex--;tinyMCE.setInnerHTML(inst.getBody(),this.undoLevels[this.undoIndex].content);inst.repaint();if(inst.settings.custom_undo_redo_restore_selection)inst.selection.moveToBookmark(this.undoLevels[this.undoIndex].bookmark)}},redo:function(){var inst=this.instance;tinyMCE.execCommand("mceEndTyping");if(this.undoIndex<(this.undoLevels.length-1)){this.undoIndex++;tinyMCE.setInnerHTML(inst.getBody(),this.undoLevels[this.undoIndex].content);inst.repaint();if(inst.settings.custom_undo_redo_restore_selection)inst.selection.moveToBookmark(this.undoLevels[this.undoIndex].bookmark)}tinyMCE.triggerNodeChange()}};var TinyMCE_ForceParagraphs={_insertPara:function(inst,e){var doc=inst.getDoc(),sel=inst.getSel(),body=inst.getBody(),win=inst.contentWindow,rng=sel.getRangeAt(0);var rootElm=doc.documentElement,blockName="P",startNode,endNode,startBlock,endBlock;var rngBefore,rngAfter,direct,startNode,startOffset,endNode,endOffset,b=tinyMCE.isOpera?inst.selection.getBookmark():null;var paraBefore,paraAfter,startChop,endChop,contents;function isEmpty(para){function isEmptyHTML(html){return html.replace(new RegExp('[ \t\r\n]+','g'),'').toLowerCase()==""}if(para.getElementsByTagName("img").length>0)return false;if(para.getElementsByTagName("table").length>0)return false;if(para.getElementsByTagName("hr").length>0)return false;var nodes=tinyMCE.getNodeTree(para,new Array(),3);for(var i=0;i<nodes.length;i++){if(!isEmptyHTML(nodes[i].nodeValue))return false}return true}rngBefore=doc.createRange();rngBefore.setStart(sel.anchorNode,sel.anchorOffset);rngBefore.collapse(true);rngAfter=doc.createRange();rngAfter.setStart(sel.focusNode,sel.focusOffset);rngAfter.collapse(true);direct=rngBefore.compareBoundaryPoints(rngBefore.START_TO_END,rngAfter)<0;startNode=direct?sel.anchorNode:sel.focusNode;startOffset=direct?sel.anchorOffset:sel.focusOffset;endNode=direct?sel.focusNode:sel.anchorNode;endOffset=direct?sel.focusOffset:sel.anchorOffset;startNode=startNode.nodeName=="BODY"?startNode.firstChild:startNode;endNode=endNode.nodeName=="BODY"?endNode.firstChild:endNode;startBlock=inst.getParentBlockElement(startNode);endBlock=inst.getParentBlockElement(endNode);if(startBlock&&new RegExp('absolute|relative|static','gi').test(startBlock.style.position))startBlock=null;if(endBlock&&new RegExp('absolute|relative|static','gi').test(endBlock.style.position))endBlock=null;if(startBlock!=null){blockName=startBlock.nodeName;if(blockName=="TD"||blockName=="TABLE"||(blockName=="DIV"&&new RegExp('left|right','gi').test(startBlock.style.cssFloat)))blockName="P"}if(tinyMCE.getParentElement(startBlock,"OL,UL",null,body)!=null)return false;if((startBlock!=null&&startBlock.nodeName=="TABLE")||(endBlock!=null&&endBlock.nodeName=="TABLE"))startBlock=endBlock=null;paraBefore=(startBlock!=null&&startBlock.nodeName==blockName)?startBlock.cloneNode(false):doc.createElement(blockName);paraAfter=(endBlock!=null&&endBlock.nodeName==blockName)?endBlock.cloneNode(false):doc.createElement(blockName);if(/^(H[1-6])$/.test(blockName))paraAfter=doc.createElement("p");startChop=startNode;endChop=endNode;node=startChop;do{if(node==body||node.nodeType==9||tinyMCE.isBlockElement(node))break;startChop=node}while((node=node.previousSibling?node.previousSibling:node.parentNode));node=endChop;do{if(node==body||node.nodeType==9||tinyMCE.isBlockElement(node))break;endChop=node}while((node=node.nextSibling?node.nextSibling:node.parentNode));if(startChop.nodeName=="TD")startChop=startChop.firstChild;if(endChop.nodeName=="TD")endChop=endChop.lastChild;if(startBlock==null){rng.deleteContents();if(!tinyMCE.isSafari)sel.removeAllRanges();if(startChop!=rootElm&&endChop!=rootElm){rngBefore=rng.cloneRange();if(startChop==body)rngBefore.setStart(startChop,0);else rngBefore.setStartBefore(startChop);paraBefore.appendChild(rngBefore.cloneContents());if(endChop.parentNode.nodeName==blockName)endChop=endChop.parentNode;rng.setEndAfter(endChop);if(endChop.nodeName!="#text"&&endChop.nodeName!="BODY")rngBefore.setEndAfter(endChop);contents=rng.cloneContents();if(contents.firstChild&&(contents.firstChild.nodeName==blockName||contents.firstChild.nodeName=="BODY"))paraAfter.innerHTML=contents.firstChild.innerHTML;else paraAfter.appendChild(contents);if(isEmpty(paraBefore))paraBefore.innerHTML="&nbsp;";if(isEmpty(paraAfter))paraAfter.innerHTML="&nbsp;";rng.deleteContents();rngAfter.deleteContents();rngBefore.deleteContents();if(tinyMCE.isOpera){paraBefore.normalize();rngBefore.insertNode(paraBefore);paraAfter.normalize();rngBefore.insertNode(paraAfter)}else{paraAfter.normalize();rngBefore.insertNode(paraAfter);paraBefore.normalize();rngBefore.insertNode(paraBefore)}}else{body.innerHTML="<"+blockName+">&nbsp;</"+blockName+"><"+blockName+">&nbsp;</"+blockName+">";paraAfter=body.childNodes[1]}inst.selection.moveToBookmark(b);inst.selection.selectNode(paraAfter,true,true);return true}if(startChop.nodeName==blockName)rngBefore.setStart(startChop,0);else rngBefore.setStartBefore(startChop);rngBefore.setEnd(startNode,startOffset);paraBefore.appendChild(rngBefore.cloneContents());rngAfter.setEndAfter(endChop);rngAfter.setStart(endNode,endOffset);contents=rngAfter.cloneContents();if(contents.firstChild&&contents.firstChild.nodeName==blockName){paraAfter.innerHTML=contents.firstChild.innerHTML}else paraAfter.appendChild(contents);if(isEmpty(paraBefore))paraBefore.innerHTML="&nbsp;";if(isEmpty(paraAfter))paraAfter.innerHTML="&nbsp;";rng=doc.createRange();if(!startChop.previousSibling&&startChop.parentNode.nodeName.toUpperCase()==blockName){rng.setStartBefore(startChop.parentNode)}else{if(rngBefore.startContainer.nodeName.toUpperCase()==blockName&&rngBefore.startOffset==0)rng.setStartBefore(rngBefore.startContainer);else rng.setStart(rngBefore.startContainer,rngBefore.startOffset)}if(!endChop.nextSibling&&endChop.parentNode.nodeName.toUpperCase()==blockName)rng.setEndAfter(endChop.parentNode);else rng.setEnd(rngAfter.endContainer,rngAfter.endOffset);rng.deleteContents();if(tinyMCE.isOpera){rng.insertNode(paraBefore);rng.insertNode(paraAfter)}else{rng.insertNode(paraAfter);rng.insertNode(paraBefore)}paraAfter.normalize();paraBefore.normalize();inst.selection.moveToBookmark(b);inst.selection.selectNode(paraAfter,true,true);return true},_handleBackSpace:function(inst){var r=inst.getRng(),sn=r.startContainer,nv,s=false;if(sn&&sn.nextSibling&&sn.nextSibling.nodeName=="BR"&&sn.parentNode.nodeName!="BODY"){nv=sn.nodeValue;if(nv!=null&&r.startOffset==nv.length)sn.nextSibling.parentNode.removeChild(sn.nextSibling)}if(inst.settings.auto_resize)inst.resizeToContent();return s}};function TinyMCE_Layer(id,bm){this.id=id;this.blockerElement=null;this.events=false;this.element=null;this.blockMode=typeof(bm)!='undefined'?bm:true;this.doc=document};TinyMCE_Layer.prototype={moveRelativeTo:function(re,p){var rep=this.getAbsPosition(re);var w=parseInt(re.offsetWidth);var h=parseInt(re.offsetHeight);var e=this.getElement();var ew=parseInt(e.offsetWidth);var eh=parseInt(e.offsetHeight);var x,y;switch(p){case"tl":x=rep.absLeft;y=rep.absTop;break;case"tr":x=rep.absLeft+w;y=rep.absTop;break;case"bl":x=rep.absLeft;y=rep.absTop+h;break;case"br":x=rep.absLeft+w;y=rep.absTop+h;break;case"cc":x=rep.absLeft+(w/ 2) - (ew /2);y=rep.absTop+(h/ 2) - (eh /2);break}this.moveTo(x,y)},moveBy:function(x,y){var e=this.getElement();this.moveTo(parseInt(e.style.left)+x,parseInt(e.style.top)+y)},moveTo:function(x,y){var e=this.getElement();e.style.left=x+"px";e.style.top=y+"px";this.updateBlocker()},resizeBy:function(w,h){var e=this.getElement();this.resizeTo(parseInt(e.style.width)+w,parseInt(e.style.height)+h)},resizeTo:function(w,h){var e=this.getElement();if(w!=null)e.style.width=w+"px";if(h!=null)e.style.height=h+"px";this.updateBlocker()},show:function(){var el=this.getElement();if(el){el.style.display='block';this.updateBlocker()}},hide:function(){var el=this.getElement();if(el){el.style.display='none';this.updateBlocker()}},isVisible:function(){return this.getElement().style.display=='block'},getElement:function(){if(!this.element)this.element=this.doc.getElementById(this.id);return this.element},setBlockMode:function(s){this.blockMode=s},updateBlocker:function(){var e,b,x,y,w,h;b=this.getBlocker();if(b){if(this.blockMode){e=this.getElement();x=this.parseInt(e.style.left);y=this.parseInt(e.style.top);w=this.parseInt(e.offsetWidth);h=this.parseInt(e.offsetHeight);b.style.left=x+'px';b.style.top=y+'px';b.style.width=w+'px';b.style.height=h+'px';b.style.display=e.style.display}else b.style.display='none'}},getBlocker:function(){var d,b;if(!this.blockerElement&&this.blockMode){d=this.doc;b=d.getElementById(this.id+"_blocker");if(!b){b=d.createElement("iframe");b.setAttribute('id',this.id+"_blocker");b.style.cssText='display: none; position: absolute; left: 0; top: 0';b.src='javascript:false;';b.frameBorder='0';b.scrolling='no';d.body.appendChild(b)}this.blockerElement=b}return this.blockerElement},getAbsPosition:function(n){var p={absLeft:0,absTop:0};while(n){p.absLeft+=n.offsetLeft;p.absTop+=n.offsetTop;n=n.offsetParent}return p},create:function(n,c,p,h){var d=this.doc,e=d.createElement(n);e.setAttribute('id',this.id);if(c)e.className=c;if(!p)p=d.body;if(h)e.innerHTML=h;p.appendChild(e);return this.element=e},exists:function(){return this.doc.getElementById(this.id)!=null},parseInt:function(s){if(s==null||s=='')return 0;return parseInt(s)},remove:function(){var e=this.getElement(),b=this.getBlocker();if(e)e.parentNode.removeChild(e);if(b)b.parentNode.removeChild(b)}};function TinyMCE_Menu(){var id;if(typeof(tinyMCE.menuCounter)=="undefined")tinyMCE.menuCounter=0;id="mc_menu_"+tinyMCE.menuCounter++;TinyMCE_Layer.call(this,id,true);this.id=id;this.items=new Array();this.needsUpdate=true};TinyMCE_Menu.prototype=tinyMCE.extend(TinyMCE_Layer.prototype,{init:function(s){var n;this.settings={separator_class:'mceMenuSeparator',title_class:'mceMenuTitle',disabled_class:'mceMenuDisabled',menu_class:'mceMenu',drop_menu:true};for(n in s)this.settings[n]=s[n];this.create('div',this.settings.menu_class)},clear:function(){this.items=new Array()},addTitle:function(t){this.add({type:'title',text:t})},addDisabled:function(t){this.add({type:'disabled',text:t})},addSeparator:function(){this.add({type:'separator'})},addItem:function(t,js){this.add({text:t,js:js})},add:function(mi){this.items[this.items.length]=mi;this.needsUpdate=true},update:function(){var e=this.getElement(),h='',i,t,m=this.items,s=this.settings;if(this.settings.drop_menu)h+='<span class="mceMenuLine"></span>';h+='<table border="0" cellpadding="0" cellspacing="0">';for(i=0;i<m.length;i++){t=tinyMCE.xmlEncode(m[i].text);c=m[i].class_name?' class="'+m[i].class_name+'"':'';switch(m[i].type){case'separator':h+='<tr class="'+s.separator_class+'"><td>';break;case'title':h+='<tr class="'+s.title_class+'"><td><span'+c+'>'+t+'</span>';break;case'disabled':h+='<tr class="'+s.disabled_class+'"><td><span'+c+'>'+t+'</span>';break;default:h+='<tr><td><a href="'+tinyMCE.xmlEncode(m[i].js)+'" onmousedown="'+tinyMCE.xmlEncode(m[i].js)+';return tinyMCE.cancelEvent(event);" onclick="return tinyMCE.cancelEvent(event);" onmouseup="return tinyMCE.cancelEvent(event);"><span'+c+'>'+t+'</span></a>'}h+='</td></tr>'}h+='</table>';e.innerHTML=h;this.needsUpdate=false;this.updateBlocker()},show:function(){var nl,i;if(tinyMCE.lastMenu==this)return;if(this.needsUpdate)this.update();if(tinyMCE.lastMenu&&tinyMCE.lastMenu!=this)tinyMCE.lastMenu.hide();TinyMCE_Layer.prototype.show.call(this);if(!tinyMCE.isOpera){}tinyMCE.lastMenu=this}});if(!Function.prototype.call){Function.prototype.call=function(){var a=arguments,s=a[0],i,as='',r,o;for(i=1;i<a.length;i++)as+=(i>1?',':'')+'a['+i+']';o=s._fu;s._fu=this;r=eval('s._fu('+as+')');s._fu=o;return r}};TinyMCE_Engine.prototype.debug=function(){var m="",a,i,l=tinyMCE.log.length;for(i=0,a=this.debug.arguments;i<a.length;i++){m+=a[i];if(i<a.length-1)m+=', '}if(l<1000)tinyMCE.log[l]="[debug] "+m};
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/tiny_mce_popup.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,288 @@
+// Some global instances, this will be filled later
+var tinyMCE = null, tinyMCELang = null;
+
+function TinyMCE_Popup() {
+};
+
+TinyMCE_Popup.prototype = {
+	findWin : function(w) {
+		var c;
+
+		// Check parents
+		c = w;
+		while (c && (c = c.parent) != null) {
+			if (typeof(c.tinyMCE) != "undefined")
+				return c;
+		}
+
+		// Check openers
+		c = w;
+		while (c && (c = c.opener) != null) {
+			if (typeof(c.tinyMCE) != "undefined")
+				return c;
+		}
+
+		// Try top
+		if (typeof(top.tinyMCE) != "undefined")
+			return top;
+
+		return null;
+	},
+
+	init : function() {
+		var win = window.opener ? window.opener : window.dialogArguments, c;
+		var inst;
+
+		if (!win)
+			win = this.findWin(window);
+
+		if (!win) {
+			alert("tinyMCE object reference not found from popup.");
+			return;
+		}
+
+		window.opener = win;
+		this.windowOpener = win;
+		this.onLoadEval = "";
+
+		// Setup parent references
+		tinyMCE = win.tinyMCE;
+		tinyMCELang = win.tinyMCELang;
+
+		inst = tinyMCE.selectedInstance;
+		this.isWindow = tinyMCE.getWindowArg('mce_inside_iframe', false) == false;
+		this.storeSelection = (tinyMCE.isRealIE) && !this.isWindow && tinyMCE.getWindowArg('mce_store_selection', true);
+
+		if (this.isWindow)
+			window.focus();
+
+		// Store selection
+		if (this.storeSelection)
+			inst.selectionBookmark = inst.selection.getBookmark(true);
+
+		// Setup dir
+		if (tinyMCELang['lang_dir'])
+			document.dir = tinyMCELang['lang_dir'];
+
+		// Setup title
+		var re = new RegExp('{|\\\$|}', 'g');
+		var title = document.title.replace(re, "");
+		if (typeof tinyMCELang[title] != "undefined") {
+			var divElm = document.createElement("div");
+			divElm.innerHTML = tinyMCELang[title];
+			document.title = divElm.innerHTML;
+
+			if (tinyMCE.setWindowTitle != null)
+				tinyMCE.setWindowTitle(window, divElm.innerHTML);
+		}
+
+		// Output Popup CSS class
+		document.write('<link href="' + tinyMCE.getParam("popups_css") + '" rel="stylesheet" type="text/css">');
+
+		if (tinyMCE.getParam("popups_css_add")) {
+			c = tinyMCE.getParam("popups_css_add");
+
+			// Is relative
+			if (c.indexOf('://') == -1 && c.charAt(0) != '/')
+				c = tinyMCE.documentBasePath + "/" + c;
+
+			document.write('<link href="' + c + '" rel="stylesheet" type="text/css">');
+		}
+
+		tinyMCE.addEvent(window, "load", this.onLoad);
+	},
+
+	onLoad : function() {
+		var dir, i, elms, body = document.body;
+
+		if (tinyMCE.getWindowArg('mce_replacevariables', true))
+			body.innerHTML = tinyMCE.applyTemplate(body.innerHTML, tinyMCE.windowArgs);
+
+		dir = tinyMCE.selectedInstance.settings['directionality'];
+		if (dir == "rtl" && document.forms && document.forms.length > 0) {
+			elms = document.forms[0].elements;
+			for (i=0; i<elms.length; i++) {
+				if ((elms[i].type == "text" || elms[i].type == "textarea") && elms[i].getAttribute("dir") != "ltr")
+					elms[i].dir = dir;
+			}
+		}
+
+		if (body.style.display == 'none')
+			body.style.display = 'block';
+
+		// Execute real onload (Opera fix)
+		if (tinyMCEPopup.onLoadEval != "")
+			eval(tinyMCEPopup.onLoadEval);
+	},
+
+	executeOnLoad : function(str) {
+		if (tinyMCE.isOpera)
+			this.onLoadEval = str;
+		else
+			eval(str);
+	},
+
+	resizeToInnerSize : function() {
+		// Netscape 7.1 workaround
+		if (this.isWindow && tinyMCE.isNS71) {
+			window.resizeBy(0, 10);
+			return;
+		}
+
+		if (this.isWindow) {
+			var doc = document;
+			var body = doc.body;
+			var oldMargin, wrapper, iframe, nodes, dx, dy;
+
+			if (body.style.display == 'none')
+				body.style.display = 'block';
+
+			// Remove margin
+			oldMargin = body.style.margin;
+			body.style.margin = '0';
+
+			// Create wrapper
+			wrapper = doc.createElement("div");
+			wrapper.id = 'mcBodyWrapper';
+			wrapper.style.display = 'none';
+			wrapper.style.margin = '0';
+
+			// Wrap body elements
+			nodes = doc.body.childNodes;
+			for (var i=nodes.length-1; i>=0; i--) {
+				if (wrapper.hasChildNodes())
+					wrapper.insertBefore(nodes[i].cloneNode(true), wrapper.firstChild);
+				else
+					wrapper.appendChild(nodes[i].cloneNode(true));
+
+				nodes[i].parentNode.removeChild(nodes[i]);
+			}
+
+			// Add wrapper
+			doc.body.appendChild(wrapper);
+
+			// Create iframe
+			iframe = document.createElement("iframe");
+			iframe.id = "mcWinIframe";
+			iframe.src = document.location.href.toLowerCase().indexOf('https') == -1 ? "about:blank" : tinyMCE.settings['default_document'];
+			iframe.width = "100%";
+			iframe.height = "100%";
+			iframe.style.margin = '0';
+
+			// Add iframe
+			doc.body.appendChild(iframe);
+
+			// Measure iframe
+			iframe = document.getElementById('mcWinIframe');
+			dx = tinyMCE.getWindowArg('mce_width') - iframe.clientWidth;
+			dy = tinyMCE.getWindowArg('mce_height') - iframe.clientHeight;
+
+			// Resize window
+			// tinyMCE.debug(tinyMCE.getWindowArg('mce_width') + "," + tinyMCE.getWindowArg('mce_height') + " - " + dx + "," + dy);
+			window.resizeBy(dx, dy);
+
+			// Hide iframe and show wrapper
+			body.style.margin = oldMargin;
+			iframe.style.display = 'none';
+			wrapper.style.display = 'block';
+		}
+	},
+
+	resizeToContent : function() {
+		var isMSIE = (navigator.appName == "Microsoft Internet Explorer");
+		var isOpera = (navigator.userAgent.indexOf("Opera") != -1);
+
+		if (isOpera)
+			return;
+
+		if (isMSIE) {
+			try { window.resizeTo(10, 10); } catch (e) {}
+
+			var elm = document.body;
+			var width = elm.offsetWidth;
+			var height = elm.offsetHeight;
+			var dx = (elm.scrollWidth - width) + 4;
+			var dy = elm.scrollHeight - height;
+
+			try { window.resizeBy(dx, dy); } catch (e) {}
+		} else {
+			window.scrollBy(1000, 1000);
+			if (window.scrollX > 0 || window.scrollY > 0) {
+				window.resizeBy(window.innerWidth * 2, window.innerHeight * 2);
+				window.sizeToContent();
+				window.scrollTo(0, 0);
+				var x = parseInt(screen.width / 2.0) - (window.outerWidth / 2.0);
+				var y = parseInt(screen.height / 2.0) - (window.outerHeight / 2.0);
+				window.moveTo(x, y);
+			}
+		}
+	},
+
+	getWindowArg : function(name, default_value) {
+		return tinyMCE.getWindowArg(name, default_value);
+	},
+
+	restoreSelection : function() {
+		if (this.storeSelection) {
+			var inst = tinyMCE.selectedInstance;
+
+			inst.getWin().focus();
+
+			if (inst.selectionBookmark)
+				inst.selection.moveToBookmark(inst.selectionBookmark);
+		}
+	},
+
+	execCommand : function(command, user_interface, value) {
+		var inst = tinyMCE.selectedInstance;
+
+		this.restoreSelection();
+		inst.execCommand(command, user_interface, value);
+
+		// Store selection
+		if (this.storeSelection)
+			inst.selectionBookmark = inst.selection.getBookmark(true);
+	},
+
+	close : function() {
+		tinyMCE.closeWindow(window);
+	},
+
+	pickColor : function(e, element_id) {
+		tinyMCE.selectedInstance.execCommand('mceColorPicker', true, {
+			element_id : element_id,
+			document : document,
+			window : window,
+			store_selection : false
+		});
+	},
+
+	openBrowser : function(element_id, type, option) {
+		var cb = tinyMCE.getParam(option, tinyMCE.getParam("file_browser_callback"));
+		var url = document.getElementById(element_id).value;
+
+		tinyMCE.setWindowArg("window", window);
+		tinyMCE.setWindowArg("document", document);
+
+		// Call to external callback
+		if (eval('typeof(tinyMCEPopup.windowOpener.' + cb + ')') == "undefined")
+			alert("Callback function: " + cb + " could not be found.");
+		else
+			eval("tinyMCEPopup.windowOpener." + cb + "(element_id, url, type, window);");
+	},
+
+	importClass : function(c) {
+		window[c] = function() {};
+
+		for (var n in window.opener[c].prototype)
+			window[c].prototype[n] = window.opener[c].prototype[n];
+
+		window[c].constructor = window.opener[c].constructor;
+	}
+
+	};
+
+// Setup global instance
+var tinyMCEPopup = new TinyMCE_Popup();
+
+tinyMCEPopup.init();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/tiny_mce_src.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,7498 @@
+
+/* file:jscripts/tiny_mce/classes/TinyMCE_Engine.class.js */
+
+function TinyMCE_Engine() {
+	var ua;
+
+	this.majorVersion = "2";
+	this.minorVersion = "1.0";
+	this.releaseDate = "2007-02-13";
+
+	this.instances = new Array();
+	this.switchClassCache = new Array();
+	this.windowArgs = new Array();
+	this.loadedFiles = new Array();
+	this.pendingFiles = new Array();
+	this.loadingIndex = 0;
+	this.configs = new Array();
+	this.currentConfig = 0;
+	this.eventHandlers = new Array();
+	this.log = new Array();
+	this.undoLevels = [];
+	this.undoIndex = 0;
+	this.typingUndoIndex = -1;
+
+	// Browser check
+	ua = navigator.userAgent;
+	this.isMSIE = (navigator.appName == "Microsoft Internet Explorer");
+	this.isMSIE5 = this.isMSIE && (ua.indexOf('MSIE 5') != -1);
+	this.isMSIE5_0 = this.isMSIE && (ua.indexOf('MSIE 5.0') != -1);
+	this.isMSIE7 = this.isMSIE && (ua.indexOf('MSIE 7') != -1);
+	this.isGecko = ua.indexOf('Gecko') != -1;
+	this.isSafari = ua.indexOf('Safari') != -1;
+	this.isOpera = ua.indexOf('Opera') != -1;
+	this.isMac = ua.indexOf('Mac') != -1;
+	this.isNS7 = ua.indexOf('Netscape/7') != -1;
+	this.isNS71 = ua.indexOf('Netscape/7.1') != -1;
+	this.dialogCounter = 0;
+	this.plugins = new Array();
+	this.themes = new Array();
+	this.menus = new Array();
+	this.loadedPlugins = new Array();
+	this.buttonMap = new Array();
+	this.isLoaded = false;
+
+	// Fake MSIE on Opera and if Opera fakes IE, Gecko or Safari cancel those
+	if (this.isOpera) {
+		this.isMSIE = true;
+		this.isGecko = false;
+		this.isSafari =  false;
+	}
+
+	this.isIE = this.isMSIE;
+	this.isRealIE = this.isMSIE && !this.isOpera;
+
+	// TinyMCE editor id instance counter
+	this.idCounter = 0;
+};
+
+TinyMCE_Engine.prototype = {
+	init : function(settings) {
+		var theme, nl, baseHREF = "", i;
+
+		// IE 5.0x is no longer supported since 5.5, 6.0 and 7.0 now exists. We can't support old browsers forever, sorry.
+		if (this.isMSIE5_0)
+			return;
+
+		this.settings = settings;
+
+		// Check if valid browser has execcommand support
+		if (typeof(document.execCommand) == 'undefined')
+			return;
+
+		// Get script base path
+		if (!tinyMCE.baseURL) {
+			var elements = document.getElementsByTagName('script');
+
+			// If base element found, add that infront of baseURL
+			nl = document.getElementsByTagName('base');
+			for (i=0; i<nl.length; i++) {
+				if (nl[i].href)
+					baseHREF = nl[i].href;
+			}
+
+			for (var i=0; i<elements.length; i++) {
+				if (elements[i].src && (elements[i].src.indexOf("tiny_mce.js") != -1 || elements[i].src.indexOf("tiny_mce_dev.js") != -1 || elements[i].src.indexOf("tiny_mce_src.js") != -1 || elements[i].src.indexOf("tiny_mce_gzip") != -1)) {
+					var src = elements[i].src;
+
+					tinyMCE.srcMode = (src.indexOf('_src') != -1 || src.indexOf('_dev') != -1) ? '_src' : '';
+					tinyMCE.gzipMode = src.indexOf('_gzip') != -1;
+					src = src.substring(0, src.lastIndexOf('/'));
+
+					if (settings.exec_mode == "src" || settings.exec_mode == "normal")
+						tinyMCE.srcMode = settings.exec_mode == "src" ? '_src' : '';
+
+					// Force it absolute if page has a base href
+					if (baseHREF != "" && src.indexOf('://') == -1)
+						tinyMCE.baseURL = baseHREF + src;
+					else
+						tinyMCE.baseURL = src;
+
+					break;
+				}
+			}
+		}
+
+		// Get document base path
+		this.documentBasePath = document.location.href;
+		if (this.documentBasePath.indexOf('?') != -1)
+			this.documentBasePath = this.documentBasePath.substring(0, this.documentBasePath.indexOf('?'));
+		this.documentURL = this.documentBasePath;
+		this.documentBasePath = this.documentBasePath.substring(0, this.documentBasePath.lastIndexOf('/'));
+
+		// If not HTTP absolute
+		if (tinyMCE.baseURL.indexOf('://') == -1 && tinyMCE.baseURL.charAt(0) != '/') {
+			// If site absolute
+			tinyMCE.baseURL = this.documentBasePath + "/" + tinyMCE.baseURL;
+		}
+
+		// Set default values on settings
+		this._def("mode", "none");
+		this._def("theme", "advanced");
+		this._def("plugins", "", true);
+		this._def("language", "en");
+		this._def("docs_language", this.settings['language']);
+		this._def("elements", "");
+		this._def("textarea_trigger", "mce_editable");
+		this._def("editor_selector", "");
+		this._def("editor_deselector", "mceNoEditor");
+		this._def("valid_elements", "+a[id|style|rel|rev|charset|hreflang|dir|lang|tabindex|accesskey|type|name|href|target|title|class|onfocus|onblur|onclick|ondblclick|onmousedown|onmouseup|onmouseover|onmousemove|onmouseout|onkeypress|onkeydown|onkeyup],-strong/-b[class|style],-em/-i[class|style],-strike[class|style],-u[class|style],#p[id|style|dir|class|align],-ol[class|style],-ul[class|style],-li[class|style],br,img[id|dir|lang|longdesc|usemap|style|class|src|onmouseover|onmouseout|border|alt=|title|hspace|vspace|width|height|align],-sub[style|class],-sup[style|class],-blockquote[dir|style],-table[border=0|cellspacing|cellpadding|width|height|class|align|summary|style|dir|id|lang|bgcolor|background|bordercolor],-tr[id|lang|dir|class|rowspan|width|height|align|valign|style|bgcolor|background|bordercolor],tbody[id|class],thead[id|class],tfoot[id|class],#td[id|lang|dir|class|colspan|rowspan|width|height|align|valign|style|bgcolor|background|bordercolor|scope],-th[id|lang|dir|class|colspan|rowspan|width|height|align|valign|style|scope],caption[id|lang|dir|class|style],-div[id|dir|class|align|style],-span[style|class|align],-pre[class|align|style],address[class|align|style],-h1[id|style|dir|class|align],-h2[id|style|dir|class|align],-h3[id|style|dir|class|align],-h4[id|style|dir|class|align],-h5[id|style|dir|class|align],-h6[id|style|dir|class|align],hr[class|style],-font[face|size|style|id|class|dir|color],dd[id|class|title|style|dir|lang],dl[id|class|title|style|dir|lang],dt[id|class|title|style|dir|lang],cite[title|id|class|style|dir|lang],abbr[title|id|class|style|dir|lang],acronym[title|id|class|style|dir|lang],del[title|id|class|style|dir|lang|datetime|cite],ins[title|id|class|style|dir|lang|datetime|cite]");
+		this._def("extended_valid_elements", "");
+		this._def("invalid_elements", "");
+		this._def("encoding", "");
+		this._def("urlconverter_callback", tinyMCE.getParam("urlconvertor_callback", "TinyMCE_Engine.prototype.convertURL"));
+		this._def("save_callback", "");
+		this._def("debug", false);
+		this._def("force_br_newlines", false);
+		this._def("force_p_newlines", true);
+		this._def("add_form_submit_trigger", true);
+		this._def("relative_urls", true);
+		this._def("remove_script_host", true);
+		this._def("focus_alert", true);
+		this._def("document_base_url", this.documentURL);
+		this._def("visual", true);
+		this._def("visual_table_class", "mceVisualAid");
+		this._def("setupcontent_callback", "");
+		this._def("fix_content_duplication", true);
+		this._def("custom_undo_redo", true);
+		this._def("custom_undo_redo_levels", -1);
+		this._def("custom_undo_redo_keyboard_shortcuts", true);
+		this._def("custom_undo_redo_restore_selection", true);
+		this._def("custom_undo_redo_global", false);
+		this._def("verify_html", true);
+		this._def("apply_source_formatting", false);
+		this._def("directionality", "ltr");
+		this._def("cleanup_on_startup", false);
+		this._def("inline_styles", false);
+		this._def("convert_newlines_to_brs", false);
+		this._def("auto_reset_designmode", true);
+		this._def("entities", "39,#39,160,nbsp,161,iexcl,162,cent,163,pound,164,curren,165,yen,166,brvbar,167,sect,168,uml,169,copy,170,ordf,171,laquo,172,not,173,shy,174,reg,175,macr,176,deg,177,plusmn,178,sup2,179,sup3,180,acute,181,micro,182,para,183,middot,184,cedil,185,sup1,186,ordm,187,raquo,188,frac14,189,frac12,190,frac34,191,iquest,192,Agrave,193,Aacute,194,Acirc,195,Atilde,196,Auml,197,Aring,198,AElig,199,Ccedil,200,Egrave,201,Eacute,202,Ecirc,203,Euml,204,Igrave,205,Iacute,206,Icirc,207,Iuml,208,ETH,209,Ntilde,210,Ograve,211,Oacute,212,Ocirc,213,Otilde,214,Ouml,215,times,216,Oslash,217,Ugrave,218,Uacute,219,Ucirc,220,Uuml,221,Yacute,222,THORN,223,szlig,224,agrave,225,aacute,226,acirc,227,atilde,228,auml,229,aring,230,aelig,231,ccedil,232,egrave,233,eacute,234,ecirc,235,euml,236,igrave,237,iacute,238,icirc,239,iuml,240,eth,241,ntilde,242,ograve,243,oacute,244,ocirc,245,otilde,246,ouml,247,divide,248,oslash,249,ugrave,250,uacute,251,ucirc,252,uuml,253,yacute,254,thorn,255,yuml,402,fnof,913,Alpha,914,Beta,915,Gamma,916,Delta,917,Epsilon,918,Zeta,919,Eta,920,Theta,921,Iota,922,Kappa,923,Lambda,924,Mu,925,Nu,926,Xi,927,Omicron,928,Pi,929,Rho,931,Sigma,932,Tau,933,Upsilon,934,Phi,935,Chi,936,Psi,937,Omega,945,alpha,946,beta,947,gamma,948,delta,949,epsilon,950,zeta,951,eta,952,theta,953,iota,954,kappa,955,lambda,956,mu,957,nu,958,xi,959,omicron,960,pi,961,rho,962,sigmaf,963,sigma,964,tau,965,upsilon,966,phi,967,chi,968,psi,969,omega,977,thetasym,978,upsih,982,piv,8226,bull,8230,hellip,8242,prime,8243,Prime,8254,oline,8260,frasl,8472,weierp,8465,image,8476,real,8482,trade,8501,alefsym,8592,larr,8593,uarr,8594,rarr,8595,darr,8596,harr,8629,crarr,8656,lArr,8657,uArr,8658,rArr,8659,dArr,8660,hArr,8704,forall,8706,part,8707,exist,8709,empty,8711,nabla,8712,isin,8713,notin,8715,ni,8719,prod,8721,sum,8722,minus,8727,lowast,8730,radic,8733,prop,8734,infin,8736,ang,8743,and,8744,or,8745,cap,8746,cup,8747,int,8756,there4,8764,sim,8773,cong,8776,asymp,8800,ne,8801,equiv,8804,le,8805,ge,8834,sub,8835,sup,8836,nsub,8838,sube,8839,supe,8853,oplus,8855,otimes,8869,perp,8901,sdot,8968,lceil,8969,rceil,8970,lfloor,8971,rfloor,9001,lang,9002,rang,9674,loz,9824,spades,9827,clubs,9829,hearts,9830,diams,34,quot,38,amp,60,lt,62,gt,338,OElig,339,oelig,352,Scaron,353,scaron,376,Yuml,710,circ,732,tilde,8194,ensp,8195,emsp,8201,thinsp,8204,zwnj,8205,zwj,8206,lrm,8207,rlm,8211,ndash,8212,mdash,8216,lsquo,8217,rsquo,8218,sbquo,8220,ldquo,8221,rdquo,8222,bdquo,8224,dagger,8225,Dagger,8240,permil,8249,lsaquo,8250,rsaquo,8364,euro", true);
+		this._def("entity_encoding", "named");
+		this._def("cleanup_callback", "");
+		this._def("add_unload_trigger", true);
+		this._def("ask", false);
+		this._def("nowrap", false);
+		this._def("auto_resize", false);
+		this._def("auto_focus", false);
+		this._def("cleanup", true);
+		this._def("remove_linebreaks", true);
+		this._def("button_tile_map", false);
+		this._def("submit_patch", true);
+		this._def("browsers", "msie,safari,gecko,opera", true);
+		this._def("dialog_type", "window");
+		this._def("accessibility_warnings", true);
+		this._def("accessibility_focus", true);
+		this._def("merge_styles_invalid_parents", "");
+		this._def("force_hex_style_colors", true);
+		this._def("trim_span_elements", true);
+		this._def("convert_fonts_to_spans", false);
+		this._def("doctype", '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">');
+		this._def("font_size_classes", '');
+		this._def("font_size_style_values", 'xx-small,x-small,small,medium,large,x-large,xx-large', true);
+		this._def("event_elements", 'a,img', true);
+		this._def("convert_urls", true);
+		this._def("table_inline_editing", false);
+		this._def("object_resizing", true);
+		this._def("custom_shortcuts", true);
+		this._def("convert_on_click", false);
+		this._def("content_css", '');
+		this._def("fix_list_elements", true);
+		this._def("fix_table_elements", false);
+		this._def("strict_loading_mode", ( ( IE ) ? true : true ) ); // document.contentType == 'application/xhtml+xml');
+		this._def("hidden_tab_class", '');
+		this._def("display_tab_class", '');
+		this._def("gecko_spellcheck", false);
+		this._def("hide_selects_on_submit", true);
+
+		// Force strict loading mode to false on non Gecko browsers
+		//if (this.isMSIE && !this.isOpera)
+		//	this.settings.strict_loading_mode = false;
+
+		// Browser check IE
+		if (this.isMSIE && this.settings['browsers'].indexOf('msie') == -1)
+			return;
+
+		// Browser check Gecko
+		if (this.isGecko && this.settings['browsers'].indexOf('gecko') == -1)
+			return;
+
+		// Browser check Safari
+		if (this.isSafari && this.settings['browsers'].indexOf('safari') == -1)
+			return;
+
+		// Browser check Opera
+		if (this.isOpera && this.settings['browsers'].indexOf('opera') == -1)
+			return;
+
+		// If not super absolute make it so
+		baseHREF = tinyMCE.settings['document_base_url'];
+		var h = document.location.href;
+		var p = h.indexOf('://');
+		if (p > 0 && document.location.protocol != "file:") {
+			p = h.indexOf('/', p + 3);
+			h = h.substring(0, p);
+
+			if (baseHREF.indexOf('://') == -1)
+				baseHREF = h + baseHREF;
+
+			tinyMCE.settings['document_base_url'] = baseHREF;
+			tinyMCE.settings['document_base_prefix'] = h;
+		}
+
+		// Trim away query part
+		if (baseHREF.indexOf('?') != -1)
+			baseHREF = baseHREF.substring(0, baseHREF.indexOf('?'));
+
+		this.settings['base_href'] = baseHREF.substring(0, baseHREF.lastIndexOf('/')) + "/";
+
+		theme = this.settings['theme'];
+		this.inlineStrict = 'A|BR|SPAN|BDO|MAP|OBJECT|IMG|TT|I|B|BIG|SMALL|EM|STRONG|DFN|CODE|Q|SAMP|KBD|VAR|CITE|ABBR|ACRONYM|SUB|SUP|#text|#comment';
+		this.inlineTransitional = 'A|BR|SPAN|BDO|OBJECT|APPLET|IMG|MAP|IFRAME|TT|I|B|U|S|STRIKE|BIG|SMALL|FONT|BASEFONT|EM|STRONG|DFN|CODE|Q|SAMP|KBD|VAR|CITE|ABBR|ACRONYM|SUB|SUP|INPUT|SELECT|TEXTAREA|LABEL|BUTTON|#text|#comment';
+		this.blockElms = 'H[1-6]|P|DIV|ADDRESS|PRE|FORM|TABLE|LI|OL|UL|TD|BLOCKQUOTE|CENTER|DL|DT|DD|DIR|FIELDSET|FORM|NOSCRIPT|NOFRAMES|MENU|ISINDEX|SAMP';
+		this.blockRegExp = new RegExp("^(" + this.blockElms + ")$", "i");
+		this.posKeyCodes = new Array(13,45,36,35,33,34,37,38,39,40);
+		this.uniqueURL = 'javascript:void(091039730);'; // Make unique URL non real URL
+		this.uniqueTag = '<div id="mceTMPElement" style="display: none">TMP</div>';
+		this.callbacks = new Array('onInit', 'getInfo', 'getEditorTemplate', 'setupContent', 'onChange', 'onPageLoad', 'handleNodeChange', 'initInstance', 'execCommand', 'getControlHTML', 'handleEvent', 'cleanup', 'removeInstance');
+
+		// Theme url
+		this.settings['theme_href'] = tinyMCE.baseURL + "/themes/" + theme;
+
+		if (!tinyMCE.isIE || tinyMCE.isOpera)
+			this.settings['force_br_newlines'] = false;
+
+		if (tinyMCE.getParam("popups_css", false)) {
+			var cssPath = tinyMCE.getParam("popups_css", "");
+
+			// Is relative
+			if (cssPath.indexOf('://') == -1 && cssPath.charAt(0) != '/')
+				this.settings['popups_css'] = this.documentBasePath + "/" + cssPath;
+			else
+				this.settings['popups_css'] = cssPath;
+		} else
+			this.settings['popups_css'] = tinyMCE.baseURL + "/themes/" + theme + "/css/editor_popup.css";
+
+		if (tinyMCE.getParam("editor_css", false)) {
+			var cssPath = tinyMCE.getParam("editor_css", "");
+
+			// Is relative
+			if (cssPath.indexOf('://') == -1 && cssPath.charAt(0) != '/')
+				this.settings['editor_css'] = this.documentBasePath + "/" + cssPath;
+			else
+				this.settings['editor_css'] = cssPath;
+		} else {
+			if (this.settings.editor_css != '')
+				this.settings['editor_css'] = tinyMCE.baseURL + "/themes/" + theme + "/css/editor_ui.css";
+		}
+
+		if (tinyMCE.settings['debug']) {
+			var msg = "Debug: \n";
+
+			msg += "baseURL: " + this.baseURL + "\n";
+			msg += "documentBasePath: " + this.documentBasePath + "\n";
+			msg += "content_css: " + this.settings['content_css'] + "\n";
+			msg += "popups_css: " + this.settings['popups_css'] + "\n";
+			msg += "editor_css: " + this.settings['editor_css'] + "\n";
+
+			alert(msg);
+		}
+
+		// Only do this once
+		if (this.configs.length == 0) {
+			if (typeof(TinyMCECompressed) == "undefined") {
+				tinyMCE.addEvent(window, "DOMContentLoaded", TinyMCE_Engine.prototype.onLoad);
+
+				if (tinyMCE.isRealIE) {
+					if (document.body)
+						tinyMCE.addEvent(document.body, "readystatechange", TinyMCE_Engine.prototype.onLoad);
+					else
+						tinyMCE.addEvent(document, "readystatechange", TinyMCE_Engine.prototype.onLoad);
+				}
+
+				tinyMCE.addEvent(window, "load", TinyMCE_Engine.prototype.onLoad);
+				tinyMCE._addUnloadEvents();
+			}
+		}
+
+		this.loadScript(tinyMCE.baseURL + '/themes/' + this.settings['theme'] + '/editor_template' + tinyMCE.srcMode + '.js');
+		this.loadScript(tinyMCE.baseURL + '/langs/' + this.settings['language'] +  '.js');
+		this.loadCSS(this.settings['editor_css']);
+
+		// Add plugins
+		var p = tinyMCE.getParam('plugins', '', true, ',');
+		if (p.length > 0) {
+			for (var i=0; i<p.length; i++) {
+				if (p[i].charAt(0) != '-')
+					this.loadScript(tinyMCE.baseURL + '/plugins/' + p[i] + '/editor_plugin' + tinyMCE.srcMode + '.js');
+			}
+		}
+
+		// Setup entities
+		if (tinyMCE.getParam('entity_encoding') == 'named') {
+			settings['cleanup_entities'] = new Array();
+			var entities = tinyMCE.getParam('entities', '', true, ',');
+			for (var i=0; i<entities.length; i+=2)
+				settings['cleanup_entities']['c' + entities[i]] = entities[i+1];
+		}
+
+		// Save away this config
+		settings['index'] = this.configs.length;
+		this.configs[this.configs.length] = settings;
+
+		// Start loading first one in chain
+		this.loadNextScript();
+
+		// Force flicker free CSS backgrounds in IE
+		if (this.isIE && !this.isOpera) {
+			try {
+				document.execCommand('BackgroundImageCache', false, true);
+			} catch (e) {
+			}
+		}
+
+		// Setup XML encoding regexps
+		this.xmlEncodeAposRe = new RegExp('[<>&"\']', 'g');
+		this.xmlEncodeRe = new RegExp('[<>&"]', 'g');
+//		this.xmlEncodeEnts = {'&':'&amp;','"':'&quot;',"'":'&#39;','<':'&lt;','>':'&gt;'};
+	},
+
+	_addUnloadEvents : function() {
+		if (tinyMCE.isIE) {
+			if (tinyMCE.settings['add_unload_trigger']) {
+				tinyMCE.addEvent(window, "unload", TinyMCE_Engine.prototype.unloadHandler);
+				tinyMCE.addEvent(window.document, "beforeunload", TinyMCE_Engine.prototype.unloadHandler);
+			}
+		} else {
+			if (tinyMCE.settings['add_unload_trigger'])
+				tinyMCE.addEvent(window, "unload", function () {tinyMCE.triggerSave(true, true);});
+		}
+	},
+
+	_def : function(key, def_val, t) {
+		var v = tinyMCE.getParam(key, def_val);
+
+		v = t ? v.replace(/\s+/g, "") : v;
+
+		this.settings[key] = v;
+	},
+
+	hasPlugin : function(n) {
+		return typeof(this.plugins[n]) != "undefined" && this.plugins[n] != null;
+	},
+
+	addPlugin : function(n, p) {
+		var op = this.plugins[n];
+
+		// Use the previous plugin object base URL used when loading external plugins
+		p.baseURL = op ? op.baseURL : tinyMCE.baseURL + "/plugins/" + n;
+		this.plugins[n] = p;
+
+		this.loadNextScript();
+	},
+
+	setPluginBaseURL : function(n, u) {
+		var op = this.plugins[n];
+
+		if (op)
+			op.baseURL = u;
+		else
+			this.plugins[n] = {baseURL : u};
+	},
+
+	loadPlugin : function(n, u) {
+		u = u.indexOf('.js') != -1 ? u.substring(0, u.lastIndexOf('/')) : u;
+		u = u.charAt(u.length-1) == '/' ? u.substring(0, u.length-1) : u;
+		this.plugins[n] = {baseURL : u};
+		this.loadScript(u + "/editor_plugin" + (tinyMCE.srcMode ? '_src' : '') + ".js");
+	},
+
+	hasTheme : function(n) {
+		return typeof(this.themes[n]) != "undefined" && this.themes[n] != null;
+	},
+
+	addTheme : function(n, t) {
+		this.themes[n] = t;
+
+		this.loadNextScript();
+	},
+
+	addMenu : function(n, m) {
+		this.menus[n] = m;
+	},
+
+	hasMenu : function(n) {
+		return typeof(this.plugins[n]) != "undefined" && this.plugins[n] != null;
+	},
+
+	loadScript : function(url) {
+		var i;
+
+		for (i=0; i<this.loadedFiles.length; i++) {
+			if (this.loadedFiles[i] == url)
+				return;
+		}
+
+		if (tinyMCE.settings.strict_loading_mode)
+			this.pendingFiles[this.pendingFiles.length] = url;
+		else
+    {
+      document.write('<sc'+'ript language="javascript" type="text/javascript" src="' + url + '"></script>');
+    }
+
+		this.loadedFiles[this.loadedFiles.length] = url;
+	},
+
+	loadNextScript : function() {
+		var d = document, se;
+
+		if (!tinyMCE.settings.strict_loading_mode)
+			return;
+
+		if (this.loadingIndex < this.pendingFiles.length) {
+			se = d.createElementNS('http://www.w3.org/1999/xhtml', 'script');
+			se.setAttribute('language', 'javascript');
+			se.setAttribute('type', 'text/javascript');
+			se.setAttribute('src', this.pendingFiles[this.loadingIndex++]);
+
+			d.getElementsByTagName("head")[0].appendChild(se);
+		} else
+			this.loadingIndex = -1; // Done with loading
+	},
+
+	loadCSS : function(url) {
+		var ar = url.replace(/\s+/, '').split(',');
+		var lflen = 0, csslen = 0;
+		var skip = false;
+		var x = 0, i = 0, nl, le;
+
+		for (x = 0,csslen = ar.length; x<csslen; x++) {
+			if (ar[x] != null && ar[x] != 'null' && ar[x].length > 0) {
+				/* Make sure it doesn't exist. */
+				for (i=0, lflen=this.loadedFiles.length; i<lflen; i++) {
+					if (this.loadedFiles[i] == ar[x]) {
+						skip = true;
+						break;
+					}
+				}
+
+				if (!skip) {
+					if (tinyMCE.settings.strict_loading_mode) {
+						nl = document.getElementsByTagName("head");
+
+						le = document.createElement('link');
+						le.setAttribute('href', ar[x]);
+						le.setAttribute('rel', 'stylesheet');
+						le.setAttribute('type', 'text/css');
+
+						nl[0].appendChild(le);			
+					} else
+          {
+            document.write('<link href="' + ar[x] + '" rel="stylesheet" type="text/css" />');
+          }
+
+					this.loadedFiles[this.loadedFiles.length] = ar[x];
+				}
+			}
+		}
+	},
+
+	importCSS : function(doc, css) {
+		var css_ary = css.replace(/\s+/, '').split(',');
+		var csslen, elm, headArr, x, css_file;
+
+		for (x = 0, csslen = css_ary.length; x<csslen; x++) {
+			css_file = css_ary[x];
+
+			if (css_file != null && css_file != 'null' && css_file.length > 0) {
+				// Is relative, make absolute
+				if (css_file.indexOf('://') == -1 && css_file.charAt(0) != '/')
+					css_file = this.documentBasePath + "/" + css_file;
+
+				if (typeof(doc.createStyleSheet) == "undefined") {
+					elm = doc.createElement("link");
+
+					elm.rel = "stylesheet";
+					elm.href = css_file;
+
+					if ((headArr = doc.getElementsByTagName("head")) != null && headArr.length > 0)
+						headArr[0].appendChild(elm);
+				} else
+					doc.createStyleSheet(css_file);
+			}
+		}
+	},
+
+	confirmAdd : function(e, settings) {
+		var elm = tinyMCE.isIE ? event.srcElement : e.target;
+		var elementId = elm.name ? elm.name : elm.id;
+
+		tinyMCE.settings = settings;
+
+		if (tinyMCE.settings['convert_on_click'] || (!elm.getAttribute('mce_noask') && confirm(tinyMCELang['lang_edit_confirm'])))
+			tinyMCE.addMCEControl(elm, elementId);
+
+		elm.setAttribute('mce_noask', 'true');
+	},
+
+	updateContent : function(form_element_name) {
+		// Find MCE instance linked to given form element and copy it's value
+		var formElement = document.getElementById(form_element_name);
+		for (var n in tinyMCE.instances) {
+			var inst = tinyMCE.instances[n];
+			if (!tinyMCE.isInstance(inst))
+				continue;
+
+			inst.switchSettings();
+
+			if (inst.formElement == formElement) {
+				var doc = inst.getDoc();
+		
+				tinyMCE._setHTML(doc, inst.formElement.value);
+
+				if (!tinyMCE.isIE)
+					doc.body.innerHTML = tinyMCE._cleanupHTML(inst, doc, this.settings, doc.body, inst.visualAid);
+			}
+		}
+	},
+
+	addMCEControl : function(replace_element, form_element_name, target_document) {
+		var id = "mce_editor_" + tinyMCE.idCounter++;
+		var inst = new TinyMCE_Control(tinyMCE.settings);
+
+		inst.editorId = id;
+		this.instances[id] = inst;
+
+		inst._onAdd(replace_element, form_element_name, target_document);
+	},
+
+	removeInstance : function(ti) {
+		var t = [], n, i;
+
+		// Remove from instances
+		for (n in tinyMCE.instances) {
+			i = tinyMCE.instances[n];
+
+			if (tinyMCE.isInstance(i) && ti != i)
+					t[n] = i;
+		}
+
+		tinyMCE.instances = t;
+
+		// Remove from global undo/redo
+		n = [];
+		t = tinyMCE.undoLevels;
+
+		for (i=0; i<t.length; i++) {
+			if (t[i] != ti)
+				n.push(t[i]);
+		}
+
+		tinyMCE.undoLevels = n;
+		tinyMCE.undoIndex = n.length;
+
+		// Dispatch remove instance call
+		tinyMCE.dispatchCallback(ti, 'remove_instance_callback', 'removeInstance', ti);
+
+		return ti;
+	},
+
+	removeMCEControl : function(editor_id) {
+		var inst = tinyMCE.getInstanceById(editor_id), h, re, ot, tn;
+
+		if (inst) {
+			inst.switchSettings();
+
+			editor_id = inst.editorId;
+			h = tinyMCE.getContent(editor_id);
+
+			this.removeInstance(inst);
+
+			tinyMCE.selectedElement = null;
+			tinyMCE.selectedInstance = null;
+
+			// Remove element
+			re = document.getElementById(editor_id + "_parent");
+			ot = inst.oldTargetElement;
+			tn = ot.nodeName.toLowerCase();
+
+			if (tn == "textarea" || tn == "input") {
+				re.parentNode.removeChild(re);
+				ot.style.display = "inline";
+				ot.value = h;
+			} else {
+				ot.innerHTML = h;
+				ot.style.display = 'block';
+				re.parentNode.insertBefore(ot, re);
+				re.parentNode.removeChild(re);
+			}
+		}
+	},
+
+	triggerSave : function(skip_cleanup, skip_callback) {
+		var inst, n;
+
+		// Default to false
+		if (typeof(skip_cleanup) == "undefined")
+			skip_cleanup = false;
+
+		// Default to false
+		if (typeof(skip_callback) == "undefined")
+			skip_callback = false;
+
+		// Cleanup and set all form fields
+		for (n in tinyMCE.instances) {
+			inst = tinyMCE.instances[n];
+
+			if (!tinyMCE.isInstance(inst))
+				continue;
+
+			inst.triggerSave(skip_cleanup, skip_callback);
+		}
+	},
+
+	resetForm : function(form_index) {
+		var i, inst, n, formObj = document.forms[form_index];
+
+		for (n in tinyMCE.instances) {
+			inst = tinyMCE.instances[n];
+
+			if (!tinyMCE.isInstance(inst))
+				continue;
+
+			inst.switchSettings();
+
+			for (i=0; i<formObj.elements.length; i++) {
+				if (inst.formTargetElementId == formObj.elements[i].name)
+					inst.getBody().innerHTML = inst.startContent;
+			}
+		}
+	},
+
+	execInstanceCommand : function(editor_id, command, user_interface, value, focus) {
+		var inst = tinyMCE.getInstanceById(editor_id), r;
+
+		if (inst) {
+			r = inst.selection.getRng();
+
+			if (typeof(focus) == "undefined")
+				focus = true;
+
+			// IE bug lost focus on images in absolute divs Bug #1534575
+			if (focus && (!r || !r.item))
+				inst.contentWindow.focus();
+
+			// Reset design mode if lost
+			inst.autoResetDesignMode();
+
+			this.selectedElement = inst.getFocusElement();
+			inst.select();
+			tinyMCE.execCommand(command, user_interface, value);
+
+			// Cancel event so it doesn't call onbeforeonunlaod
+			if (tinyMCE.isIE && window.event != null)
+				tinyMCE.cancelEvent(window.event);
+		}
+	},
+
+	execCommand : function(command, user_interface, value) {
+		var inst = tinyMCE.selectedInstance;
+
+		// Default input
+		user_interface = user_interface ? user_interface : false;
+		value = value ? value : null;
+
+		if (inst)
+			inst.switchSettings();
+
+		switch (command) {
+			case "Undo":
+				if (this.getParam('custom_undo_redo_global')) {
+					if (this.undoIndex > 0) {
+						tinyMCE.nextUndoRedoAction = 'Undo';
+						inst = this.undoLevels[--this.undoIndex];
+						inst.select();
+
+						if (!tinyMCE.nextUndoRedoInstanceId)
+							inst.execCommand('Undo');
+					}
+				} else
+					inst.execCommand('Undo');
+				return true;
+
+			case "Redo":
+				if (this.getParam('custom_undo_redo_global')) {
+					if (this.undoIndex <= this.undoLevels.length - 1) {
+						tinyMCE.nextUndoRedoAction = 'Redo';
+						inst = this.undoLevels[this.undoIndex++];
+						inst.select();
+
+						if (!tinyMCE.nextUndoRedoInstanceId)
+							inst.execCommand('Redo');
+					}
+				} else
+					inst.execCommand('Redo');
+
+				return true;
+
+			case 'mceFocus':
+				var inst = tinyMCE.getInstanceById(value);
+				if (inst)
+					inst.getWin().focus();
+			return;
+
+			case "mceAddControl":
+			case "mceAddEditor":
+				tinyMCE.addMCEControl(tinyMCE._getElementById(value), value);
+				return;
+
+			case "mceAddFrameControl":
+				tinyMCE.addMCEControl(tinyMCE._getElementById(value['element'], value['document']), value['element'], value['document']);
+				return;
+
+			case "mceRemoveControl":
+			case "mceRemoveEditor":
+				tinyMCE.removeMCEControl(value);
+				return;
+
+			case "mceToggleEditor":
+				var inst = tinyMCE.getInstanceById(value), pe, te;
+
+				if (inst) {
+					pe = document.getElementById(inst.editorId + '_parent');
+					te = inst.oldTargetElement;
+
+					if (typeof(inst.enabled) == 'undefined')
+						inst.enabled = true;
+
+					inst.enabled = !inst.enabled;
+
+					if (!inst.enabled) {
+						pe.style.display = 'none';
+						te.value = inst.getHTML();
+						te.style.display = inst.oldTargetDisplay;
+						tinyMCE.dispatchCallback(inst, 'hide_instance_callback', 'hideInstance', inst);
+					} else {
+						pe.style.display = 'block';
+						te.style.display = 'none';
+						inst.setHTML(te.value);
+						inst.useCSS = false;
+						tinyMCE.dispatchCallback(inst, 'show_instance_callback', 'showInstance', inst);
+					}
+				} else
+					tinyMCE.addMCEControl(tinyMCE._getElementById(value), value);
+
+				return;
+
+			case "mceResetDesignMode":
+				// Resets the designmode state of the editors in Gecko
+				if (!tinyMCE.isIE) {
+					for (var n in tinyMCE.instances) {
+						if (!tinyMCE.isInstance(tinyMCE.instances[n]))
+							continue;
+
+						try {
+							tinyMCE.instances[n].getDoc().designMode = "on";
+						} catch (e) {
+							// Ignore any errors
+						}
+					}
+				}
+
+				return;
+		}
+
+		if (inst) {
+			inst.execCommand(command, user_interface, value);
+		} else if (tinyMCE.settings['focus_alert'])
+			alert(tinyMCELang['lang_focus_alert']);
+	},
+
+	_createIFrame : function(replace_element, doc, win) {
+		var iframe, id = replace_element.getAttribute("id");
+		var aw, ah;
+
+		if (typeof(doc) == "undefined")
+			doc = document;
+
+		if (typeof(win) == "undefined")
+			win = window;
+
+		iframe = doc.createElement("iframe");
+
+		aw = "" + tinyMCE.settings['area_width'];
+		ah = "" + tinyMCE.settings['area_height'];
+
+		if (aw.indexOf('%') == -1) {
+			aw = parseInt(aw);
+			aw = (isNaN(aw) || aw < 0) ? 300 : aw;
+			aw = aw + "px";
+		}
+
+		if (ah.indexOf('%') == -1) {
+			ah = parseInt(ah);
+			ah = (isNaN(ah) || ah < 0) ? 240 : ah;
+			ah = ah + "px";
+		}
+
+		iframe.setAttribute("id", id);
+		iframe.setAttribute("name", id);
+		iframe.setAttribute("class", "mceEditorIframe");
+		iframe.setAttribute("border", "0");
+		iframe.setAttribute("frameBorder", "0");
+		iframe.setAttribute("marginWidth", "0");
+		iframe.setAttribute("marginHeight", "0");
+		iframe.setAttribute("leftMargin", "0");
+		iframe.setAttribute("topMargin", "0");
+		iframe.setAttribute("width", aw);
+		iframe.setAttribute("height", ah);
+		iframe.setAttribute("allowtransparency", "true");
+		iframe.className = 'mceEditorIframe';
+
+		if (tinyMCE.settings["auto_resize"])
+			iframe.setAttribute("scrolling", "no");
+
+		// Must have a src element in MSIE HTTPs breaks aswell as absoute URLs
+		if (tinyMCE.isRealIE)
+			iframe.setAttribute("src", this.settings['default_document']);
+
+		iframe.style.width = aw;
+		iframe.style.height = ah;
+
+		// Ugly hack for Gecko problem in strict mode
+		if (tinyMCE.settings.strict_loading_mode)
+			iframe.style.marginBottom = '-5px';
+
+		// MSIE 5.0 issue
+		if (tinyMCE.isRealIE)
+			replace_element.outerHTML = iframe.outerHTML;
+		else
+			replace_element.parentNode.replaceChild(iframe, replace_element);
+
+		if (tinyMCE.isRealIE)
+			return win.frames[id];
+		else
+			return iframe;
+	},
+
+	setupContent : function(editor_id) {
+		var inst = tinyMCE.instances[editor_id], i;
+		var doc = inst.getDoc();
+		var head = doc.getElementsByTagName('head').item(0);
+		var content = inst.startContent;
+
+		// HTML values get XML encoded in strict mode
+		if (tinyMCE.settings.strict_loading_mode) {
+			content = content.replace(/&lt;/g, '<');
+			content = content.replace(/&gt;/g, '>');
+			content = content.replace(/&quot;/g, '"');
+			content = content.replace(/&amp;/g, '&');
+		}
+
+		tinyMCE.selectedInstance = inst;
+		inst.switchSettings();
+
+		// Not loaded correctly hit it again, Mozilla bug #997860
+		if (!tinyMCE.isIE && tinyMCE.getParam("setupcontent_reload", false) && doc.title != "blank_page") {
+			// This part will remove the designMode status
+			// Failes first time in Firefox 1.5b2 on Mac
+			try {doc.location.href = tinyMCE.baseURL + "/blank.htm";} catch (ex) {}
+			window.setTimeout("tinyMCE.setupContent('" + editor_id + "');", 1000);
+			return;
+		}
+
+		if (!head) {
+			window.setTimeout("tinyMCE.setupContent('" + editor_id + "');", 10);
+			return;
+		}
+
+		// Import theme specific content CSS the user specific
+		tinyMCE.importCSS(inst.getDoc(), tinyMCE.baseURL + "/themes/" + inst.settings['theme'] + "/css/editor_content.css");
+		tinyMCE.importCSS(inst.getDoc(), inst.settings['content_css']);
+		tinyMCE.dispatchCallback(inst, 'init_instance_callback', 'initInstance', inst);
+
+		// Setup keyboard shortcuts
+		if (tinyMCE.getParam('custom_undo_redo_keyboard_shortcuts')) {
+			inst.addShortcut('ctrl', 'z', 'lang_undo_desc', 'Undo');
+			inst.addShortcut('ctrl', 'y', 'lang_redo_desc', 'Redo');
+		}
+
+		// BlockFormat shortcuts keys
+		for (i=1; i<=6; i++)
+			inst.addShortcut('ctrl', '' + i, '', 'FormatBlock', false, '<h' + i + '>');
+
+		inst.addShortcut('ctrl', '7', '', 'FormatBlock', false, '<p>');
+		inst.addShortcut('ctrl', '8', '', 'FormatBlock', false, '<div>');
+		inst.addShortcut('ctrl', '9', '', 'FormatBlock', false, '<address>');
+
+		// Add default shortcuts for gecko
+		if (tinyMCE.isGecko) {
+			inst.addShortcut('ctrl', 'b', 'lang_bold_desc', 'Bold');
+			inst.addShortcut('ctrl', 'i', 'lang_italic_desc', 'Italic');
+			inst.addShortcut('ctrl', 'u', 'lang_underline_desc', 'Underline');
+		}
+
+		// Setup span styles
+		if (tinyMCE.getParam("convert_fonts_to_spans"))
+			inst.getBody().setAttribute('id', 'mceSpanFonts');
+
+		if (tinyMCE.settings['nowrap'])
+			doc.body.style.whiteSpace = "nowrap";
+
+		doc.body.dir = this.settings['directionality'];
+		doc.editorId = editor_id;
+
+		// Add on document element in Mozilla
+		if (!tinyMCE.isIE)
+			doc.documentElement.editorId = editor_id;
+
+		inst.setBaseHREF(tinyMCE.settings['base_href']);
+
+		// Replace new line characters to BRs
+		if (tinyMCE.settings['convert_newlines_to_brs']) {
+			content = tinyMCE.regexpReplace(content, "\r\n", "<br />", "gi");
+			content = tinyMCE.regexpReplace(content, "\r", "<br />", "gi");
+			content = tinyMCE.regexpReplace(content, "\n", "<br />", "gi");
+		}
+
+		// Open closed anchors
+	//	content = content.replace(new RegExp('<a(.*?)/>', 'gi'), '<a$1></a>');
+
+		// Call custom cleanup code
+		content = tinyMCE.storeAwayURLs(content);
+		content = tinyMCE._customCleanup(inst, "insert_to_editor", content);
+
+		if (tinyMCE.isIE) {
+			// Ugly!!!
+			window.setInterval('try{tinyMCE.getCSSClasses(tinyMCE.instances["' + editor_id + '"].getDoc(), "' + editor_id + '");}catch(e){}', 500);
+
+			if (tinyMCE.settings["force_br_newlines"])
+				doc.styleSheets[0].addRule("p", "margin: 0;");
+
+			var body = inst.getBody();
+			body.editorId = editor_id;
+		}
+
+		content = tinyMCE.cleanupHTMLCode(content);
+
+		// Fix for bug #958637
+		if (!tinyMCE.isIE) {
+			var contentElement = inst.getDoc().createElement("body");
+			var doc = inst.getDoc();
+
+			contentElement.innerHTML = content;
+
+			// Remove weridness!
+			if (tinyMCE.isGecko && tinyMCE.settings['remove_lt_gt'])
+				content = content.replace(new RegExp('&lt;&gt;', 'g'), "");
+
+			if (tinyMCE.settings['cleanup_on_startup'])
+				tinyMCE.setInnerHTML(inst.getBody(), tinyMCE._cleanupHTML(inst, doc, this.settings, contentElement));
+			else
+				tinyMCE.setInnerHTML(inst.getBody(), content);
+
+			tinyMCE.convertAllRelativeURLs(inst.getBody());
+		} else {
+			if (tinyMCE.settings['cleanup_on_startup']) {
+				tinyMCE._setHTML(inst.getDoc(), content);
+
+				// Produces permission denied error in MSIE 5.5
+				eval('try {tinyMCE.setInnerHTML(inst.getBody(), tinyMCE._cleanupHTML(inst, inst.contentDocument, this.settings, inst.getBody()));} catch(e) {}');
+			} else
+				tinyMCE._setHTML(inst.getDoc(), content);
+		}
+
+		// Fix for bug #957681
+		//inst.getDoc().designMode = inst.getDoc().designMode;
+
+		tinyMCE.handleVisualAid(inst.getBody(), true, tinyMCE.settings['visual'], inst);
+		tinyMCE.dispatchCallback(inst, 'setupcontent_callback', 'setupContent', editor_id, inst.getBody(), inst.getDoc());
+
+		// Re-add design mode on mozilla
+		if (!tinyMCE.isIE)
+			tinyMCE.addEventHandlers(inst);
+
+		// Add blur handler
+		if (tinyMCE.isIE) {
+			tinyMCE.addEvent(inst.getBody(), "blur", TinyMCE_Engine.prototype._eventPatch);
+			tinyMCE.addEvent(inst.getBody(), "beforedeactivate", TinyMCE_Engine.prototype._eventPatch); // Bug #1439953
+
+			// Workaround for drag drop/copy paste base href bug
+			if (!tinyMCE.isOpera) {
+				tinyMCE.addEvent(doc.body, "mousemove", TinyMCE_Engine.prototype.onMouseMove);
+				tinyMCE.addEvent(doc.body, "beforepaste", TinyMCE_Engine.prototype._eventPatch);
+				tinyMCE.addEvent(doc.body, "drop", TinyMCE_Engine.prototype._eventPatch);
+			}
+		}
+
+		// Trigger node change, this call locks buttons for tables and so forth
+		inst.select();
+		tinyMCE.selectedElement = inst.contentWindow.document.body;
+
+		// Call custom DOM cleanup
+		tinyMCE._customCleanup(inst, "insert_to_editor_dom", inst.getBody());
+		tinyMCE._customCleanup(inst, "setup_content_dom", inst.getBody());
+		tinyMCE._setEventsEnabled(inst.getBody(), false);
+		tinyMCE.cleanupAnchors(inst.getDoc());
+
+		if (tinyMCE.getParam("convert_fonts_to_spans"))
+			tinyMCE.convertSpansToFonts(inst.getDoc());
+
+		inst.startContent = tinyMCE.trim(inst.getBody().innerHTML);
+		inst.undoRedo.add({ content : inst.startContent });
+
+		// Cleanup any mess left from storyAwayURLs
+		if (tinyMCE.isGecko) {
+			// Remove mce_src from textnodes and comments
+			tinyMCE.selectNodes(inst.getBody(), function(n) {
+				if (n.nodeType == 3 || n.nodeType == 8)
+					n.nodeValue = n.nodeValue.replace(new RegExp('\\s(mce_src|mce_href)=\"[^\"]*\"', 'gi'), "");
+
+				return false;
+			});
+		}
+
+		// Remove Gecko spellchecking
+		if (tinyMCE.isGecko)
+			inst.getBody().spellcheck = tinyMCE.getParam("gecko_spellcheck");
+
+		// Cleanup any mess left from storyAwayURLs
+		tinyMCE._removeInternal(inst.getBody());
+
+		inst.select();
+		tinyMCE.triggerNodeChange(false, true);
+	},
+
+	storeAwayURLs : function(s) {
+		// Remove all mce_src, mce_href and replace them with new ones
+		// s = s.replace(new RegExp('mce_src\\s*=\\s*\"[^ >\"]*\"', 'gi'), '');
+		// s = s.replace(new RegExp('mce_href\\s*=\\s*\"[^ >\"]*\"', 'gi'), '');
+
+		if (!s.match(/(mce_src|mce_href)/gi, s)) {
+			s = s.replace(new RegExp('src\\s*=\\s*\"([^ >\"]*)\"', 'gi'), 'src="$1" mce_src="$1"');
+			s = s.replace(new RegExp('href\\s*=\\s*\"([^ >\"]*)\"', 'gi'), 'href="$1" mce_href="$1"');
+		}
+
+		return s;
+	},
+
+	_removeInternal : function(n) {
+		if (tinyMCE.isGecko) {
+			// Remove mce_src from textnodes and comments
+			tinyMCE.selectNodes(n, function(n) {
+				if (n.nodeType == 3 || n.nodeType == 8)
+					n.nodeValue = n.nodeValue.replace(new RegExp('\\s(mce_src|mce_href)=\"[^\"]*\"', 'gi'), "");
+
+				return false;
+			});
+		}
+	},
+
+	removeTinyMCEFormElements : function(form_obj) {
+		var i, elementId;
+
+		// Skip form element removal
+		if (!tinyMCE.getParam('hide_selects_on_submit'))
+			return;
+
+		// Check if form is valid
+		if (typeof(form_obj) == "undefined" || form_obj == null)
+			return;
+
+		// If not a form, find the form
+		if (form_obj.nodeName != "FORM") {
+			if (form_obj.form)
+				form_obj = form_obj.form;
+			else
+				form_obj = tinyMCE.getParentElement(form_obj, "form");
+		}
+
+		// Still nothing
+		if (form_obj == null)
+			return;
+
+		// Disable all UI form elements that TinyMCE created
+		for (i=0; i<form_obj.elements.length; i++) {
+			elementId = form_obj.elements[i].name ? form_obj.elements[i].name : form_obj.elements[i].id;
+
+			if (elementId.indexOf('mce_editor_') == 0)
+				form_obj.elements[i].disabled = true;
+		}
+	},
+
+	handleEvent : function(e) {
+		var inst = tinyMCE.selectedInstance;
+
+		// Remove odd, error
+		if (typeof(tinyMCE) == "undefined")
+			return true;
+
+		//tinyMCE.debug(e.type + " " + e.target.nodeName + " " + (e.relatedTarget ? e.relatedTarget.nodeName : ""));
+
+		if (tinyMCE.executeCallback(tinyMCE.selectedInstance, 'handle_event_callback', 'handleEvent', e))
+			return false;
+
+		switch (e.type) {
+			case "beforedeactivate": // Was added due to bug #1439953
+			case "blur":
+				if (tinyMCE.selectedInstance)
+					tinyMCE.selectedInstance.execCommand('mceEndTyping');
+
+				tinyMCE.hideMenus();
+
+				return;
+
+			// Workaround for drag drop/copy paste base href bug
+			case "drop":
+			case "beforepaste":
+				if (tinyMCE.selectedInstance)
+					tinyMCE.selectedInstance.setBaseHREF(null);
+
+				// Fixes odd MSIE bug where drag/droping elements in a iframe with height 100% breaks
+				// This logic forces the width/height to be in pixels while the user is drag/dropping
+				if (tinyMCE.isRealIE) {
+					var ife = tinyMCE.selectedInstance.iframeElement;
+
+					/*if (ife.style.width.indexOf('%') != -1) {
+						ife._oldWidth = ife.width.height;
+						ife.style.width = ife.clientWidth;
+					}*/
+
+					if (ife.style.height.indexOf('%') != -1) {
+						ife._oldHeight = ife.style.height;
+						ife.style.height = ife.clientHeight;
+					}
+				}
+
+				window.setTimeout("tinyMCE.selectedInstance.setBaseHREF(tinyMCE.settings['base_href']);tinyMCE._resetIframeHeight();", 1);
+				return;
+
+			case "submit":
+				tinyMCE.removeTinyMCEFormElements(tinyMCE.isMSIE ? window.event.srcElement : e.target);
+				tinyMCE.triggerSave();
+				tinyMCE.isNotDirty = true;
+				return;
+
+			case "reset":
+				var formObj = tinyMCE.isIE ? window.event.srcElement : e.target;
+
+				for (var i=0; i<document.forms.length; i++) {
+					if (document.forms[i] == formObj)
+						window.setTimeout('tinyMCE.resetForm(' + i + ');', 10);
+				}
+
+				return;
+
+			case "keypress":
+				if (inst && inst.handleShortcut(e))
+					return false;
+
+				if (e.target.editorId) {
+					tinyMCE.instances[e.target.editorId].select();
+				} else {
+					if (e.target.ownerDocument.editorId)
+						tinyMCE.instances[e.target.ownerDocument.editorId].select();
+				}
+
+				if (tinyMCE.selectedInstance)
+					tinyMCE.selectedInstance.switchSettings();
+
+				// Insert P element
+				if ((tinyMCE.isGecko || tinyMCE.isOpera || tinyMCE.isSafari) && tinyMCE.settings['force_p_newlines'] && e.keyCode == 13 && !e.shiftKey) {
+					// Insert P element instead of BR
+					if (TinyMCE_ForceParagraphs._insertPara(tinyMCE.selectedInstance, e)) {
+						// Cancel event
+						tinyMCE.execCommand("mceAddUndoLevel");
+						return tinyMCE.cancelEvent(e);
+					}
+				}
+
+				// Handle backspace
+				if ((tinyMCE.isGecko && !tinyMCE.isSafari) && tinyMCE.settings['force_p_newlines'] && (e.keyCode == 8 || e.keyCode == 46) && !e.shiftKey) {
+					// Insert P element instead of BR
+					if (TinyMCE_ForceParagraphs._handleBackSpace(tinyMCE.selectedInstance, e.type)) {
+						// Cancel event
+						tinyMCE.execCommand("mceAddUndoLevel");
+						return tinyMCE.cancelEvent(e);
+					}
+				}
+
+				// Return key pressed
+				if (tinyMCE.isIE && tinyMCE.settings['force_br_newlines'] && e.keyCode == 13) {
+					if (e.target.editorId)
+						tinyMCE.instances[e.target.editorId].select();
+
+					if (tinyMCE.selectedInstance) {
+						var sel = tinyMCE.selectedInstance.getDoc().selection;
+						var rng = sel.createRange();
+
+						if (tinyMCE.getParentElement(rng.parentElement(), "li") != null)
+							return false;
+
+						// Cancel event
+						e.returnValue = false;
+						e.cancelBubble = true;
+
+						// Insert BR element
+						rng.pasteHTML("<br />");
+						rng.collapse(false);
+						rng.select();
+
+						tinyMCE.execCommand("mceAddUndoLevel");
+						tinyMCE.triggerNodeChange(false);
+						return false;
+					}
+				}
+
+				// Backspace or delete
+				if (e.keyCode == 8 || e.keyCode == 46) {
+					tinyMCE.selectedElement = e.target;
+					tinyMCE.linkElement = tinyMCE.getParentElement(e.target, "a");
+					tinyMCE.imgElement = tinyMCE.getParentElement(e.target, "img");
+					tinyMCE.triggerNodeChange(false);
+				}
+
+				return false;
+			break;
+
+			case "keyup":
+			case "keydown":
+				tinyMCE.hideMenus();
+				tinyMCE.hasMouseMoved = false;
+
+				if (inst && inst.handleShortcut(e))
+					return false;
+
+				if (e.target.editorId)
+					tinyMCE.instances[e.target.editorId].select();
+
+				if (tinyMCE.selectedInstance)
+					tinyMCE.selectedInstance.switchSettings();
+
+				var inst = tinyMCE.selectedInstance;
+
+				// Handle backspace
+				if (tinyMCE.isGecko && tinyMCE.settings['force_p_newlines'] && (e.keyCode == 8 || e.keyCode == 46) && !e.shiftKey) {
+					// Insert P element instead of BR
+					if (TinyMCE_ForceParagraphs._handleBackSpace(tinyMCE.selectedInstance, e.type)) {
+						// Cancel event
+						tinyMCE.execCommand("mceAddUndoLevel");
+						e.preventDefault();
+						return false;
+					}
+				}
+
+				tinyMCE.selectedElement = null;
+				tinyMCE.selectedNode = null;
+				var elm = tinyMCE.selectedInstance.getFocusElement();
+				tinyMCE.linkElement = tinyMCE.getParentElement(elm, "a");
+				tinyMCE.imgElement = tinyMCE.getParentElement(elm, "img");
+				tinyMCE.selectedElement = elm;
+
+				// Update visualaids on tabs
+				if (tinyMCE.isGecko && e.type == "keyup" && e.keyCode == 9)
+					tinyMCE.handleVisualAid(tinyMCE.selectedInstance.getBody(), true, tinyMCE.settings['visual'], tinyMCE.selectedInstance);
+
+				// Fix empty elements on return/enter, check where enter occured
+				if (tinyMCE.isIE && e.type == "keydown" && e.keyCode == 13)
+					tinyMCE.enterKeyElement = tinyMCE.selectedInstance.getFocusElement();
+
+				// Fix empty elements on return/enter
+				if (tinyMCE.isIE && e.type == "keyup" && e.keyCode == 13) {
+					var elm = tinyMCE.enterKeyElement;
+					if (elm) {
+						var re = new RegExp('^HR|IMG|BR$','g'); // Skip these
+						var dre = new RegExp('^H[1-6]$','g'); // Add double on these
+
+						if (!elm.hasChildNodes() && !re.test(elm.nodeName)) {
+							if (dre.test(elm.nodeName))
+								elm.innerHTML = "&nbsp;&nbsp;";
+							else
+								elm.innerHTML = "&nbsp;";
+						}
+					}
+				}
+
+				// Check if it's a position key
+				var keys = tinyMCE.posKeyCodes;
+				var posKey = false;
+				for (var i=0; i<keys.length; i++) {
+					if (keys[i] == e.keyCode) {
+						posKey = true;
+						break;
+					}
+				}
+
+				// MSIE custom key handling
+				if (tinyMCE.isIE && tinyMCE.settings['custom_undo_redo']) {
+					var keys = new Array(8,46); // Backspace,Delete
+
+					for (var i=0; i<keys.length; i++) {
+						if (keys[i] == e.keyCode) {
+							if (e.type == "keyup")
+								tinyMCE.triggerNodeChange(false);
+						}
+					}
+				}
+
+				// If Ctrl key
+				if (e.keyCode == 17)
+					return true;
+
+				// Handle Undo/Redo when typing content
+
+				if (tinyMCE.isGecko) {
+					// Start typing (not a position key or ctrl key, but ctrl+x and ctrl+p is ok)
+					if (!posKey && e.type == "keyup" && !e.ctrlKey || (e.ctrlKey && (e.keyCode == 86 || e.keyCode == 88)))
+						tinyMCE.execCommand("mceStartTyping");
+				} else {
+					// IE seems to be working better with this setting
+					if (!posKey && e.type == "keyup")
+						tinyMCE.execCommand("mceStartTyping");
+				}
+
+				// Store undo bookmark
+				if (e.type == "keydown" && (posKey || e.ctrlKey) && inst)
+					inst.undoBookmark = inst.selection.getBookmark();
+
+				// End typing (position key) or some Ctrl event
+				if (e.type == "keyup" && (posKey || e.ctrlKey))
+					tinyMCE.execCommand("mceEndTyping");
+
+				if (posKey && e.type == "keyup")
+					tinyMCE.triggerNodeChange(false);
+
+				if (tinyMCE.isIE && e.ctrlKey)
+					window.setTimeout('tinyMCE.triggerNodeChange(false);', 1);
+			break;
+
+			case "mousedown":
+			case "mouseup":
+			case "click":
+			case "dblclick":
+			case "focus":
+				tinyMCE.hideMenus();
+
+				if (tinyMCE.selectedInstance) {
+					tinyMCE.selectedInstance.switchSettings();
+					tinyMCE.selectedInstance.isFocused = true;
+				}
+
+				// Check instance event trigged on
+				var targetBody = tinyMCE.getParentElement(e.target, "html");
+				for (var instanceName in tinyMCE.instances) {
+					if (!tinyMCE.isInstance(tinyMCE.instances[instanceName]))
+						continue;
+
+					var inst = tinyMCE.instances[instanceName];
+
+					// Reset design mode if lost (on everything just in case)
+					inst.autoResetDesignMode();
+
+					// Use HTML element since users might click outside of body element
+					if (inst.getBody().parentNode == targetBody) {
+						inst.select();
+						tinyMCE.selectedElement = e.target;
+						tinyMCE.linkElement = tinyMCE.getParentElement(tinyMCE.selectedElement, "a");
+						tinyMCE.imgElement = tinyMCE.getParentElement(tinyMCE.selectedElement, "img");
+						break;
+					}
+				}
+
+				// Add first bookmark location
+				if (!tinyMCE.selectedInstance.undoRedo.undoLevels[0].bookmark && (e.type == "mouseup" || e.type == "dblclick"))
+					tinyMCE.selectedInstance.undoRedo.undoLevels[0].bookmark = tinyMCE.selectedInstance.selection.getBookmark();
+
+				// Reset selected node
+				if (e.type != "focus")
+					tinyMCE.selectedNode = null;
+
+				tinyMCE.triggerNodeChange(false);
+				tinyMCE.execCommand("mceEndTyping");
+
+				if (e.type == "mouseup")
+					tinyMCE.execCommand("mceAddUndoLevel");
+
+				// Just in case
+				if (!tinyMCE.selectedInstance && e.target.editorId)
+					tinyMCE.instances[e.target.editorId].select();
+
+				return false;
+			break;
+		}
+	},
+
+	getButtonHTML : function(id, lang, img, cmd, ui, val) {
+		var h = '', m, x, io = '';
+
+		cmd = 'tinyMCE.execInstanceCommand(\'{$editor_id}\',\'' + cmd + '\'';
+
+		if (typeof(ui) != "undefined" && ui != null)
+			cmd += ',' + ui;
+
+		if (typeof(val) != "undefined" && val != null)
+			cmd += ",'" + val + "'";
+
+		cmd += ');';
+
+		// Patch for IE7 bug with hover out not restoring correctly
+		if (tinyMCE.isRealIE)
+			io = 'onmouseover="tinyMCE.lastHover = this;"';
+
+		// Use tilemaps when enabled and found and never in MSIE since it loads the tile each time from cache if cahce is disabled
+		if (tinyMCE.getParam('button_tile_map') && (!tinyMCE.isIE || tinyMCE.isOpera) && (m = this.buttonMap[id]) != null && (tinyMCE.getParam("language") == "en" || img.indexOf('$lang') == -1)) {
+			// Tiled button
+			x = 0 - (m * 20) == 0 ? '0' : 0 - (m * 20);
+			h += '<a id="{$editor_id}_' + id + '" href="javascript:' + cmd + '" onclick="' + cmd + 'return false;" onmousedown="return false;" ' + io + ' class="mceTiledButton mceButtonNormal" target="_self">';
+			h += '<img src="{$themeurl}/images/spacer.gif" style="background-position: ' + x + 'px 0" title="{$' + lang + '}" />';
+			h += '</a>';
+		} else {
+			// Normal button
+			h += '<a id="{$editor_id}_' + id + '" href="javascript:' + cmd + '" onclick="' + cmd + 'return false;" onmousedown="return false;" ' + io + ' class="mceButtonNormal" target="_self">';
+			h += '<img src="' + img + '" title="{$' + lang + '}" />';
+			h += '</a>';
+		}
+
+		return h;
+	},
+
+	getMenuButtonHTML : function(id, lang, img, mcmd, cmd, ui, val) {
+		var h = '', m, x;
+
+		mcmd = 'tinyMCE.execInstanceCommand(\'{$editor_id}\',\'' + mcmd + '\');';
+		cmd = 'tinyMCE.execInstanceCommand(\'{$editor_id}\',\'' + cmd + '\'';
+
+		if (typeof(ui) != "undefined" && ui != null)
+			cmd += ',' + ui;
+
+		if (typeof(val) != "undefined" && val != null)
+			cmd += ",'" + val + "'";
+
+		cmd += ');';
+
+		// Use tilemaps when enabled and found and never in MSIE since it loads the tile each time from cache if cahce is disabled
+		if (tinyMCE.getParam('button_tile_map') && (!tinyMCE.isIE || tinyMCE.isOpera) && (m = tinyMCE.buttonMap[id]) != null && (tinyMCE.getParam("language") == "en" || img.indexOf('$lang') == -1)) {
+			x = 0 - (m * 20) == 0 ? '0' : 0 - (m * 20);
+
+			if (tinyMCE.isRealIE)
+				h += '<span id="{$editor_id}_' + id + '" class="mceMenuButton" onmouseover="tinyMCE._menuButtonEvent(\'over\',this);tinyMCE.lastHover = this;" onmouseout="tinyMCE._menuButtonEvent(\'out\',this);">';
+			else
+				h += '<span id="{$editor_id}_' + id + '" class="mceMenuButton">';
+
+			h += '<a href="javascript:' + cmd + '" onclick="' + cmd + 'return false;" onmousedown="return false;" class="mceTiledButton mceMenuButtonNormal" target="_self">';
+			h += '<img src="{$themeurl}/images/spacer.gif" style="width: 20px; height: 20px; background-position: ' + x + 'px 0" title="{$' + lang + '}" /></a>';
+			h += '<a href="javascript:' + mcmd + '" onclick="' + mcmd + 'return false;" onmousedown="return false;"><img src="{$themeurl}/images/button_menu.gif" title="{$' + lang + '}" class="mceMenuButton" />';
+			h += '</a></span>';
+		} else {
+			if (tinyMCE.isRealIE)
+				h += '<span id="{$editor_id}_' + id + '" dir="ltr" class="mceMenuButton" onmouseover="tinyMCE._menuButtonEvent(\'over\',this);tinyMCE.lastHover = this;" onmouseout="tinyMCE._menuButtonEvent(\'out\',this);">';
+			else
+				h += '<span id="{$editor_id}_' + id + '" dir="ltr" class="mceMenuButton">';
+
+			h += '<a href="javascript:' + cmd + '" onclick="' + cmd + 'return false;" onmousedown="return false;" class="mceMenuButtonNormal" target="_self">';
+			h += '<img src="' + img + '" title="{$' + lang + '}" /></a>';
+			h += '<a href="javascript:' + mcmd + '" onclick="' + mcmd + 'return false;" onmousedown="return false;"><img src="{$themeurl}/images/button_menu.gif" title="{$' + lang + '}" class="mceMenuButton" />';
+			h += '</a></span>';
+		}
+
+		return h;
+	},
+
+	_menuButtonEvent : function(e, o) {
+		if (o.className == 'mceMenuButtonFocus')
+			return;
+
+		if (e == 'over')
+			o.className = o.className + ' mceMenuHover';
+		else
+			o.className = o.className.replace(/\s.*$/, '');
+	},
+
+	addButtonMap : function(m) {
+		var i, a = m.replace(/\s+/, '').split(',');
+
+		for (i=0; i<a.length; i++)
+			this.buttonMap[a[i]] = i;
+	},
+
+	submitPatch : function() {
+		tinyMCE.removeTinyMCEFormElements(this);
+		tinyMCE.triggerSave();
+		tinyMCE.isNotDirty = true;
+		this.mceOldSubmit();
+	},
+
+	onLoad : function() {
+		var r;
+
+		// Wait for everything to be loaded first
+		if (tinyMCE.settings.strict_loading_mode && this.loadingIndex != -1) {
+			window.setTimeout('tinyMCE.onLoad();', 1);
+			return;
+		}
+
+		if (tinyMCE.isRealIE && window.event.type == "readystatechange" && document.readyState != "complete")
+			return true;
+
+		if (tinyMCE.isLoaded)
+			return true;
+
+		tinyMCE.isLoaded = true;
+
+		// IE produces JS error if TinyMCE is placed in a frame
+		// It seems to have something to do with the selection not beeing
+		// correctly initialized in IE so this hack solves the problem
+		if (tinyMCE.isRealIE && document.body) {
+			r = document.body.createTextRange();
+			r.collapse(true);
+			r.select();
+		}
+
+		tinyMCE.dispatchCallback(null, 'onpageload', 'onPageLoad');
+
+		for (var c=0; c<tinyMCE.configs.length; c++) {
+			tinyMCE.settings = tinyMCE.configs[c];
+
+			var selector = tinyMCE.getParam("editor_selector");
+			var deselector = tinyMCE.getParam("editor_deselector");
+			var elementRefAr = new Array();
+
+			// Add submit triggers
+			if (document.forms && tinyMCE.settings['add_form_submit_trigger'] && !tinyMCE.submitTriggers) {
+				for (var i=0; i<document.forms.length; i++) {
+					var form = document.forms[i];
+
+					tinyMCE.addEvent(form, "submit", TinyMCE_Engine.prototype.handleEvent);
+					tinyMCE.addEvent(form, "reset", TinyMCE_Engine.prototype.handleEvent);
+					tinyMCE.submitTriggers = true; // Do it only once
+
+					// Patch the form.submit function
+					if (tinyMCE.settings['submit_patch']) {
+						try {
+							form.mceOldSubmit = form.submit;
+							form.submit = TinyMCE_Engine.prototype.submitPatch;
+						} catch (e) {
+							// Do nothing
+						}
+					}
+				}
+			}
+
+			// Add editor instances based on mode
+			var mode = tinyMCE.settings['mode'];
+			switch (mode) {
+				case "exact":
+					var elements = tinyMCE.getParam('elements', '', true, ',');
+
+					for (var i=0; i<elements.length; i++) {
+						var element = tinyMCE._getElementById(elements[i]);
+						var trigger = element ? element.getAttribute(tinyMCE.settings['textarea_trigger']) : "";
+
+						if (new RegExp('\\b' + deselector + '\\b').test(tinyMCE.getAttrib(element, "class")))
+							continue;
+
+						if (trigger == "false")
+							continue;
+
+						if ((tinyMCE.settings['ask'] || tinyMCE.settings['convert_on_click']) && element) {
+							elementRefAr[elementRefAr.length] = element;
+							continue;
+						}
+
+						if (element)
+							tinyMCE.addMCEControl(element, elements[i]);
+						else if (tinyMCE.settings['debug'])
+							alert("Error: Could not find element by id or name: " + elements[i]);
+					}
+				break;
+
+				case "specific_textareas":
+				case "textareas":
+					var nodeList = document.getElementsByTagName("textarea");
+
+					for (var i=0; i<nodeList.length; i++) {
+						var elm = nodeList.item(i);
+						var trigger = elm.getAttribute(tinyMCE.settings['textarea_trigger']);
+
+						if (selector != '' && !new RegExp('\\b' + selector + '\\b').test(tinyMCE.getAttrib(elm, "class")))
+							continue;
+
+						if (selector != '')
+							trigger = selector != "" ? "true" : "";
+
+						if (new RegExp('\\b' + deselector + '\\b').test(tinyMCE.getAttrib(elm, "class")))
+							continue;
+
+						if ((mode == "specific_textareas" && trigger == "true") || (mode == "textareas" && trigger != "false"))
+							elementRefAr[elementRefAr.length] = elm;
+					}
+				break;
+			}
+
+			for (var i=0; i<elementRefAr.length; i++) {
+				var element = elementRefAr[i];
+				var elementId = element.name ? element.name : element.id;
+
+				if (tinyMCE.settings['ask'] || tinyMCE.settings['convert_on_click']) {
+					// Focus breaks in Mozilla
+					if (tinyMCE.isGecko) {
+						var settings = tinyMCE.settings;
+
+						tinyMCE.addEvent(element, "focus", function (e) {window.setTimeout(function() {TinyMCE_Engine.prototype.confirmAdd(e, settings);}, 10);});
+
+						if (element.nodeName != "TEXTAREA" && element.nodeName != "INPUT")
+							tinyMCE.addEvent(element, "click", function (e) {window.setTimeout(function() {TinyMCE_Engine.prototype.confirmAdd(e, settings);}, 10);});
+						// tinyMCE.addEvent(element, "mouseover", function (e) {window.setTimeout(function() {TinyMCE_Engine.prototype.confirmAdd(e, settings);}, 10);});
+					} else {
+						var settings = tinyMCE.settings;
+
+						tinyMCE.addEvent(element, "focus", function () { TinyMCE_Engine.prototype.confirmAdd(null, settings); });
+						tinyMCE.addEvent(element, "click", function () { TinyMCE_Engine.prototype.confirmAdd(null, settings); });
+						// tinyMCE.addEvent(element, "mouseenter", function () { TinyMCE_Engine.prototype.confirmAdd(null, settings); });
+					}
+				} else
+					tinyMCE.addMCEControl(element, elementId);
+			}
+
+			// Handle auto focus
+			if (tinyMCE.settings['auto_focus']) {
+				window.setTimeout(function () {
+					var inst = tinyMCE.getInstanceById(tinyMCE.settings['auto_focus']);
+					inst.selection.selectNode(inst.getBody(), true, true);
+					inst.contentWindow.focus();
+				}, 100);
+			}
+
+			tinyMCE.dispatchCallback(null, 'oninit', 'onInit');
+		}
+	},
+
+	isInstance : function(o) {
+		return o != null && typeof(o) == "object" && o.isTinyMCE_Control;
+	},
+
+	getParam : function(name, default_value, strip_whitespace, split_chr) {
+		var value = (typeof(this.settings[name]) == "undefined") ? default_value : this.settings[name];
+
+		// Fix bool values
+		if (value == "true" || value == "false")
+			return (value == "true");
+
+		if (strip_whitespace)
+			value = tinyMCE.regexpReplace(value, "[ \t\r\n]", "") + '';
+
+		if (typeof(split_chr) != "undefined" && split_chr != null) {
+			value = value.split(split_chr);
+			var outArray = new Array();
+
+			for (var i=0; i<value.length; i++) {
+				if (value[i] && value[i] != "")
+					outArray[outArray.length] = value[i];
+			}
+
+			value = outArray;
+		}
+
+		return value;
+	},
+
+	getLang : function(name, default_value, parse_entities, va) {
+		var v = (typeof(tinyMCELang[name]) == "undefined") ? default_value : tinyMCELang[name], n;
+
+		if (parse_entities)
+			v = tinyMCE.entityDecode(v);
+
+		if (va) {
+			for (n in va)
+				v = this.replaceVar(v, n, va[n]);
+		}
+
+		return v;
+	},
+
+	entityDecode : function(s) {
+		var e = document.createElement("div");
+
+		e.innerHTML = s;
+
+		return e.firstChild.nodeValue;
+	},
+
+	addToLang : function(prefix, ar) {
+		for (var key in ar) {
+			if (typeof(ar[key]) == 'function')
+				continue;
+
+			tinyMCELang[(key.indexOf('lang_') == -1 ? 'lang_' : '') + (prefix != '' ? (prefix + "_") : '') + key] = ar[key];
+		}
+
+		this.loadNextScript();
+
+	//	for (var key in ar)
+	//		tinyMCELang[(key.indexOf('lang_') == -1 ? 'lang_' : '') + (prefix != '' ? (prefix + "_") : '') + key] = "|" + ar[key] + "|";
+	},
+
+	triggerNodeChange : function(focus, setup_content) {
+		var elm, inst, editorId, undoIndex = -1, undoLevels = -1, doc, anySelection = false, st;
+
+		if (tinyMCE.selectedInstance) {
+			inst = tinyMCE.selectedInstance;
+			elm = (typeof(setup_content) != "undefined" && setup_content) ? tinyMCE.selectedElement : inst.getFocusElement();
+
+/*			if (elm == inst.lastTriggerEl)
+				return;
+
+			inst.lastTriggerEl = elm;*/
+
+			editorId = inst.editorId;
+			st = inst.selection.getSelectedText();
+
+			if (tinyMCE.settings.auto_resize)
+				inst.resizeToContent();
+
+			if (setup_content && tinyMCE.isGecko && inst.isHidden())
+				elm = inst.getBody();
+
+			inst.switchSettings();
+
+			if (tinyMCE.selectedElement)
+				anySelection = (tinyMCE.selectedElement.nodeName.toLowerCase() == "img") || (st && st.length > 0);
+
+			if (tinyMCE.settings['custom_undo_redo']) {
+				undoIndex = inst.undoRedo.undoIndex;
+				undoLevels = inst.undoRedo.undoLevels.length;
+			}
+
+			tinyMCE.dispatchCallback(inst, 'handle_node_change_callback', 'handleNodeChange', editorId, elm, undoIndex, undoLevels, inst.visualAid, anySelection, setup_content);
+		}
+
+		if (this.selectedInstance && (typeof(focus) == "undefined" || focus))
+			this.selectedInstance.contentWindow.focus();
+	},
+
+	_customCleanup : function(inst, type, content) {
+		var pl, po, i;
+
+		// Call custom cleanup
+		var customCleanup = tinyMCE.settings['cleanup_callback'];
+		if (customCleanup != "" && eval("typeof(" + customCleanup + ")") != "undefined")
+			content = eval(customCleanup + "(type, content, inst);");
+
+		// Trigger theme cleanup
+		po = tinyMCE.themes[tinyMCE.settings['theme']];
+		if (po && po.cleanup)
+			content = po.cleanup(type, content, inst);
+
+		// Trigger plugin cleanups
+		pl = inst.plugins;
+		for (i=0; i<pl.length; i++) {
+			po = tinyMCE.plugins[pl[i]];
+
+			if (po && po.cleanup)
+				content = po.cleanup(type, content, inst);
+		}
+
+		return content;
+	},
+
+	setContent : function(h) {
+		if (tinyMCE.selectedInstance) {
+			tinyMCE.selectedInstance.execCommand('mceSetContent', false, h);
+			tinyMCE.selectedInstance.repaint();
+		}
+	},
+
+	importThemeLanguagePack : function(name) {
+		if (typeof(name) == "undefined")
+			name = tinyMCE.settings['theme'];
+
+		tinyMCE.loadScript(tinyMCE.baseURL + '/themes/' + name + '/langs/' + tinyMCE.settings['language'] + '.js');
+	},
+
+	importPluginLanguagePack : function(name) {
+		var b = tinyMCE.baseURL + '/plugins/' + name;
+
+		if (this.plugins[name])
+			b = this.plugins[name].baseURL;
+
+		tinyMCE.loadScript(b + '/langs/' + tinyMCE.settings['language'] +  '.js');
+	},
+
+	applyTemplate : function(h, as) {
+		return h.replace(new RegExp('\\{\\$([a-z0-9_]+)\\}', 'gi'), function(m, s) {
+			if (s.indexOf('lang_') == 0 && tinyMCELang[s])
+				return tinyMCELang[s];
+
+			if (as && as[s])
+				return as[s];
+
+			if (tinyMCE.settings[s])
+				return tinyMCE.settings[s];
+
+			if (m == 'themeurl')
+				return tinyMCE.themeURL;
+
+			return m;
+		});
+	},
+
+	replaceVar : function(h, r, v) {
+		return h.replace(new RegExp('{\\\$' + r + '}', 'g'), v);
+	},
+
+	openWindow : function(template, args) {
+		var html, width, height, x, y, resizable, scrollbars, url;
+
+		args = !args ? {} : args;
+
+		args['mce_template_file'] = template['file'];
+		args['mce_width'] = template['width'];
+		args['mce_height'] = template['height'];
+		tinyMCE.windowArgs = args;
+
+		html = template['html'];
+		if (!(width = parseInt(template['width'])))
+			width = 320;
+
+		if (!(height = parseInt(template['height'])))
+			height = 200;
+
+		// Add to height in M$ due to SP2 WHY DON'T YOU GUYS IMPLEMENT innerWidth of windows!!
+		if (tinyMCE.isIE)
+			height += 40;
+		else
+			height += 20;
+
+		x = parseInt(screen.width / 2.0) - (width / 2.0);
+		y = parseInt(screen.height / 2.0) - (height / 2.0);
+
+		resizable = (args && args['resizable']) ? args['resizable'] : "no";
+		scrollbars = (args && args['scrollbars']) ? args['scrollbars'] : "no";
+
+		if (template['file'].charAt(0) != '/' && template['file'].indexOf('://') == -1)
+			url = tinyMCE.baseURL + "/themes/" + tinyMCE.getParam("theme") + "/" + template['file'];
+		else
+			url = template['file'];
+
+		// Replace all args as variables in URL
+		for (var name in args) {
+			if (typeof(args[name]) == 'function')
+				continue;
+
+			url = tinyMCE.replaceVar(url, name, escape(args[name]));
+		}
+
+		if (html) {
+			html = tinyMCE.replaceVar(html, "css", this.settings['popups_css']);
+			html = tinyMCE.applyTemplate(html, args);
+
+			var win = window.open("", "mcePopup" + new Date().getTime(), "top=" + y + ",left=" + x + ",scrollbars=" + scrollbars + ",dialog=yes,minimizable=" + resizable + ",modal=yes,width=" + width + ",height=" + height + ",resizable=" + resizable);
+			if (win == null) {
+				alert(tinyMCELang['lang_popup_blocked']);
+				return;
+			}
+
+      //alert('docwrite 2');
+			win.document.write(html);
+			win.document.close();
+			win.resizeTo(width, height);
+			win.focus();
+		} else {
+			if ((tinyMCE.isRealIE) && resizable != 'yes' && tinyMCE.settings["dialog_type"] == "modal") {
+				height += 10;
+
+				var features = "resizable:" + resizable 
+					+ ";scroll:"
+					+ scrollbars + ";status:yes;center:yes;help:no;dialogWidth:"
+					+ width + "px;dialogHeight:" + height + "px;";
+
+				window.showModalDialog(url, window, features);
+			} else {
+				var modal = (resizable == "yes") ? "no" : "yes";
+
+				if (tinyMCE.isGecko && tinyMCE.isMac)
+					modal = "no";
+
+				if (template['close_previous'] != "no")
+					try {tinyMCE.lastWindow.close();} catch (ex) {}
+
+				var win = window.open(url, "mcePopup" + new Date().getTime(), "top=" + y + ",left=" + x + ",scrollbars=" + scrollbars + ",dialog=" + modal + ",minimizable=" + resizable + ",modal=" + modal + ",width=" + width + ",height=" + height + ",resizable=" + resizable);
+				if (win == null) {
+					alert(tinyMCELang['lang_popup_blocked']);
+					return;
+				}
+
+				if (template['close_previous'] != "no")
+					tinyMCE.lastWindow = win;
+
+				eval('try { win.resizeTo(width, height); } catch(e) { }');
+
+				// Make it bigger if statusbar is forced
+				if (tinyMCE.isGecko) {
+					if (win.document.defaultView.statusbar.visible)
+						win.resizeBy(0, tinyMCE.isMac ? 10 : 24);
+				}
+
+				win.focus();
+			}
+		}
+	},
+
+	closeWindow : function(win) {
+		win.close();
+	},
+
+	getVisualAidClass : function(class_name, state) {
+		var aidClass = tinyMCE.settings['visual_table_class'];
+
+		if (typeof(state) == "undefined")
+			state = tinyMCE.settings['visual'];
+
+		// Split
+		var classNames = new Array();
+		var ar = class_name.split(' ');
+		for (var i=0; i<ar.length; i++) {
+			if (ar[i] == aidClass)
+				ar[i] = "";
+
+			if (ar[i] != "")
+				classNames[classNames.length] = ar[i];
+		}
+
+		if (state)
+			classNames[classNames.length] = aidClass;
+
+		// Glue
+		var className = "";
+		for (var i=0; i<classNames.length; i++) {
+			if (i > 0)
+				className += " ";
+
+			className += classNames[i];
+		}
+
+		return className;
+	},
+
+	handleVisualAid : function(el, deep, state, inst, skip_dispatch) {
+		if (!el)
+			return;
+
+		if (!skip_dispatch)
+			tinyMCE.dispatchCallback(inst, 'handle_visual_aid_callback', 'handleVisualAid', el, deep, state, inst);
+
+		var tableElement = null;
+
+		switch (el.nodeName) {
+			case "TABLE":
+				var oldW = el.style.width;
+				var oldH = el.style.height;
+				var bo = tinyMCE.getAttrib(el, "border");
+
+				bo = bo == "" || bo == "0" ? true : false;
+
+				tinyMCE.setAttrib(el, "class", tinyMCE.getVisualAidClass(tinyMCE.getAttrib(el, "class"), state && bo));
+
+				el.style.width = oldW;
+				el.style.height = oldH;
+
+				for (var y=0; y<el.rows.length; y++) {
+					for (var x=0; x<el.rows[y].cells.length; x++) {
+						var cn = tinyMCE.getVisualAidClass(tinyMCE.getAttrib(el.rows[y].cells[x], "class"), state && bo);
+						tinyMCE.setAttrib(el.rows[y].cells[x], "class", cn);
+					}
+				}
+
+				break;
+
+			case "A":
+				var anchorName = tinyMCE.getAttrib(el, "name");
+
+				if (anchorName != '' && state) {
+					el.title = anchorName;
+					tinyMCE.addCSSClass(el, 'mceItemAnchor');
+				} else if (anchorName != '' && !state)
+					el.className = '';
+
+				break;
+		}
+
+		if (deep && el.hasChildNodes()) {
+			for (var i=0; i<el.childNodes.length; i++)
+				tinyMCE.handleVisualAid(el.childNodes[i], deep, state, inst, true);
+		}
+	},
+
+	/*
+	applyClassesToFonts : function(doc, size) {
+		var f = doc.getElementsByTagName("font");
+		for (var i=0; i<f.length; i++) {
+			var s = tinyMCE.getAttrib(f[i], "size");
+
+			if (s != "")
+				tinyMCE.setAttrib(f[i], 'class', "mceItemFont" + s);
+		}
+
+		if (typeof(size) != "undefined") {
+			var css = "";
+
+			for (var x=0; x<doc.styleSheets.length; x++) {
+				for (var i=0; i<doc.styleSheets[x].rules.length; i++) {
+					if (doc.styleSheets[x].rules[i].selectorText == '#mceSpanFonts .mceItemFont' + size) {
+						css = doc.styleSheets[x].rules[i].style.cssText;
+						break;
+					}
+				}
+
+				if (css != "")
+					break;
+			}
+
+			if (doc.styleSheets[0].rules[0].selectorText == "FONT")
+				doc.styleSheets[0].removeRule(0);
+
+			doc.styleSheets[0].addRule("FONT", css, 0);
+		}
+	},
+	*/
+
+	fixGeckoBaseHREFBug : function(m, e, h) {
+		var xsrc, xhref;
+
+		if (tinyMCE.isGecko) {
+			if (m == 1) {
+				h = h.replace(/\ssrc=/gi, " mce_tsrc=");
+				h = h.replace(/\shref=/gi, " mce_thref=");
+
+				return h;
+			} else {
+				// Why bother if there is no src or href broken
+				if (!new RegExp('(src|href)=', 'g').test(h))
+					return h;
+
+				// Restore src and href that gets messed up by Gecko
+				tinyMCE.selectElements(e, 'A,IMG,SELECT,AREA,IFRAME,BASE,INPUT,SCRIPT,EMBED,OBJECT,LINK', function (n) {
+					xsrc = tinyMCE.getAttrib(n, "mce_tsrc");
+					xhref = tinyMCE.getAttrib(n, "mce_thref");
+
+					if (xsrc != "") {
+						try {
+							n.src = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], xsrc);
+						} catch (e) {
+							// Ignore, Firefox cast exception if local file wasn't found
+						}
+
+						n.removeAttribute("mce_tsrc");
+					}
+
+					if (xhref != "") {
+						try {
+							n.href = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], xhref);
+						} catch (e) {
+							// Ignore, Firefox cast exception if local file wasn't found
+						}
+
+						n.removeAttribute("mce_thref");
+					}
+
+					return false;
+				});
+
+				// Restore text/comment nodes
+				tinyMCE.selectNodes(e, function(n) {
+					if (n.nodeType == 3 || n.nodeType == 8) {
+						n.nodeValue = n.nodeValue.replace(/\smce_tsrc=/gi, " src=");
+						n.nodeValue = n.nodeValue.replace(/\smce_thref=/gi, " href=");
+					}
+
+					return false;
+				});
+			}
+		}
+
+		return h;
+	},
+
+	_setHTML : function(doc, html_content) {
+		// Force closed anchors open
+		//html_content = html_content.replace(new RegExp('<a(.*?)/>', 'gi'), '<a$1></a>');
+
+		html_content = tinyMCE.cleanupHTMLCode(html_content);
+
+		// Try innerHTML if it fails use pasteHTML in MSIE
+		try {
+			tinyMCE.setInnerHTML(doc.body, html_content);
+		} catch (e) {
+			if (this.isMSIE)
+				doc.body.createTextRange().pasteHTML(html_content);
+		}
+
+		// Content duplication bug fix
+		if (tinyMCE.isIE && tinyMCE.settings['fix_content_duplication']) {
+			// Remove P elements in P elements
+			var paras = doc.getElementsByTagName("P");
+			for (var i=0; i<paras.length; i++) {
+				var node = paras[i];
+				while ((node = node.parentNode) != null) {
+					if (node.nodeName == "P")
+						node.outerHTML = node.innerHTML;
+				}
+			}
+
+			// Content duplication bug fix (Seems to be word crap)
+			var html = doc.body.innerHTML;
+/*
+			if (html.indexOf('="mso') != -1) {
+				for (var i=0; i<doc.body.all.length; i++) {
+					var el = doc.body.all[i];
+					el.removeAttribute("className","",0);
+					el.removeAttribute("style","",0);
+				}
+
+				html = doc.body.innerHTML;
+				html = tinyMCE.regexpReplace(html, "<o:p><\/o:p>", "<br />");
+				html = tinyMCE.regexpReplace(html, "<o:p>&nbsp;<\/o:p>", "");
+				html = tinyMCE.regexpReplace(html, "<st1:.*?>", "");
+				html = tinyMCE.regexpReplace(html, "<p><\/p>", "");
+				html = tinyMCE.regexpReplace(html, "<p><\/p>\r\n<p><\/p>", "");
+				html = tinyMCE.regexpReplace(html, "<p>&nbsp;<\/p>", "<br />");
+				html = tinyMCE.regexpReplace(html, "<p>\s*(<p>\s*)?", "<p>");
+				html = tinyMCE.regexpReplace(html, "<\/p>\s*(<\/p>\s*)?", "</p>");
+			}*/
+
+			// Always set the htmlText output
+			tinyMCE.setInnerHTML(doc.body, html);
+		}
+
+		tinyMCE.cleanupAnchors(doc);
+
+		if (tinyMCE.getParam("convert_fonts_to_spans"))
+			tinyMCE.convertSpansToFonts(doc);
+	},
+
+	getEditorId : function(form_element) {
+		var inst = this.getInstanceById(form_element);
+		if (!inst)
+			return null;
+
+		return inst.editorId;
+	},
+
+	getInstanceById : function(editor_id) {
+		var inst = this.instances[editor_id];
+		if (!inst) {
+			for (var n in tinyMCE.instances) {
+				var instance = tinyMCE.instances[n];
+				if (!tinyMCE.isInstance(instance))
+					continue;
+
+				if (instance.formTargetElementId == editor_id) {
+					inst = instance;
+					break;
+				}
+			}
+		}
+
+		return inst;
+	},
+
+	queryInstanceCommandValue : function(editor_id, command) {
+		var inst = tinyMCE.getInstanceById(editor_id);
+		if (inst)
+			return inst.queryCommandValue(command);
+
+		return false;
+	},
+
+	queryInstanceCommandState : function(editor_id, command) {
+		var inst = tinyMCE.getInstanceById(editor_id);
+		if (inst)
+			return inst.queryCommandState(command);
+
+		return null;
+	},
+
+	setWindowArg : function(n, v) {
+		this.windowArgs[n] = v;
+	},
+
+	getWindowArg : function(n, d) {
+		return (typeof(this.windowArgs[n]) == "undefined") ? d : this.windowArgs[n];
+	},
+
+	getCSSClasses : function(editor_id, doc) {
+		var inst = tinyMCE.getInstanceById(editor_id);
+
+		// Is cached, use that
+		if (inst && inst.cssClasses.length > 0)
+			return inst.cssClasses;
+
+		if (typeof(editor_id) == "undefined" && typeof(doc) == "undefined") {
+			var instance;
+
+			for (var instanceName in tinyMCE.instances) {
+				instance = tinyMCE.instances[instanceName];
+				if (!tinyMCE.isInstance(instance))
+					continue;
+
+				break;
+			}
+
+			doc = instance.getDoc();
+		}
+
+		if (typeof(doc) == "undefined") {
+			var instance = tinyMCE.getInstanceById(editor_id);
+			doc = instance.getDoc();
+		}
+
+		if (doc) {
+			var styles = doc.styleSheets;
+
+			if (styles && styles.length > 0) {
+				for (var x=0; x<styles.length; x++) {
+					var csses = null;
+
+					// Just ignore any errors
+					eval("try {var csses = tinyMCE.isIE ? doc.styleSheets(" + x + ").rules : styles[" + x + "].cssRules;} catch(e) {}");
+					if (!csses)
+						return new Array();
+
+					for (var i=0; i<csses.length; i++) {
+						var selectorText = csses[i].selectorText;
+
+						// Can be multiple rules per selector
+						if (selectorText) {
+							var rules = selectorText.split(',');
+							for (var c=0; c<rules.length; c++) {
+								var rule = rules[c];
+
+								// Strip spaces between selectors
+								while (rule.indexOf(' ') == 0)
+									rule = rule.substring(1);
+
+								// Invalid rule
+								if (rule.indexOf(' ') != -1 || rule.indexOf(':') != -1 || rule.indexOf('mceItem') != -1)
+									continue;
+
+								if (rule.indexOf(tinyMCE.settings['visual_table_class']) != -1 || rule.indexOf('mceEditable') != -1 || rule.indexOf('mceNonEditable') != -1)
+									continue;
+
+								// Is class rule
+								if (rule.indexOf('.') != -1) {
+									var cssClass = rule.substring(rule.indexOf('.') + 1);
+									var addClass = true;
+
+									for (var p=0; p<inst.cssClasses.length && addClass; p++) {
+										if (inst.cssClasses[p] == cssClass)
+											addClass = false;
+									}
+
+									if (addClass)
+										inst.cssClasses[inst.cssClasses.length] = cssClass;
+								}
+							}
+						}
+					}
+				}
+			}
+		}
+
+		return inst.cssClasses;
+	},
+
+	regexpReplace : function(in_str, reg_exp, replace_str, opts) {
+		if (in_str == null)
+			return in_str;
+
+		if (typeof(opts) == "undefined")
+			opts = 'g';
+
+		var re = new RegExp(reg_exp, opts);
+		return in_str.replace(re, replace_str);
+	},
+
+	trim : function(s) {
+		return s.replace(/^\s*|\s*$/g, "");
+	},
+
+	cleanupEventStr : function(s) {
+		s = "" + s;
+		s = s.replace('function anonymous()\n{\n', '');
+		s = s.replace('\n}', '');
+		s = s.replace(/^return true;/gi, ''); // Remove event blocker
+
+		return s;
+	},
+
+	getControlHTML : function(c) {
+		var i, l, n, o, v, rtl = tinyMCE.getLang('lang_dir') == 'rtl';
+
+		l = tinyMCE.plugins;
+		for (n in l) {
+			o = l[n];
+
+			if (o.getControlHTML && (v = o.getControlHTML(c)) != '') {
+				if (rtl)
+					return '<span dir="rtl">' + tinyMCE.replaceVar(v, "pluginurl", o.baseURL) + '</span>';
+
+				return tinyMCE.replaceVar(v, "pluginurl", o.baseURL);
+			}
+		}
+
+		o = tinyMCE.themes[tinyMCE.settings['theme']];
+		if (o.getControlHTML && (v = o.getControlHTML(c)) != '') {
+			if (rtl)
+				return '<span dir="rtl">' + v + '</span>';
+
+			return v;
+		}
+
+		return '';
+	},
+
+	evalFunc : function(f, idx, a, o) {
+		o = !o ? window : o;
+		f = typeof(f) == 'function' ? f : o[f];
+
+		return f.apply(o, Array.prototype.slice.call(a, idx));
+	},
+
+	dispatchCallback : function(i, p, n) {
+		return this.callFunc(i, p, n, 0, this.dispatchCallback.arguments);
+	},
+
+	executeCallback : function(i, p, n) {
+		return this.callFunc(i, p, n, 1, this.executeCallback.arguments);
+	},
+
+	execCommandCallback : function(i, p, n) {
+		return this.callFunc(i, p, n, 2, this.execCommandCallback.arguments);
+	},
+
+	callFunc : function(ins, p, n, m, a) {
+		var l, i, on, o, s, v;
+
+		s = m == 2;
+
+		l = tinyMCE.getParam(p, '');
+
+		if (l != '' && (v = tinyMCE.evalFunc(l, 3, a)) == s && m > 0)
+			return true;
+
+		if (ins != null) {
+			for (i=0, l = ins.plugins; i<l.length; i++) {
+				o = tinyMCE.plugins[l[i]];
+
+				if (o[n] && (v = tinyMCE.evalFunc(n, 3, a, o)) == s && m > 0)
+					return true;
+			}
+		}
+
+		l = tinyMCE.themes;
+		for (on in l) {
+			o = l[on];
+
+			if (o[n] && (v = tinyMCE.evalFunc(n, 3, a, o)) == s && m > 0)
+				return true;
+		}
+
+		return false;
+	},
+
+	xmlEncode : function(s, skip_apos) {
+		return s ? ('' + s).replace(!skip_apos ? this.xmlEncodeAposRe : this.xmlEncodeRe, function (c, b) {
+			switch (c) {
+				case '&':
+					return '&amp;';
+
+				case '"':
+					return '&quot;';
+
+				case '\'':
+					return '&#39;'; // &apos; is not working in MSIE
+
+				case '<':
+					return '&lt;';
+
+				case '>':
+					return '&gt;';
+			}
+
+			return c;
+		}) : s;
+	},
+
+	extend : function(p, np) {
+		var o = {};
+
+		o.parent = p;
+
+		for (n in p)
+			o[n] = p[n];
+
+		for (n in np)
+			o[n] = np[n];
+
+		return o;
+	},
+
+	hideMenus : function() {
+		var e = tinyMCE.lastSelectedMenuBtn;
+
+		if (tinyMCE.lastMenu) {
+			tinyMCE.lastMenu.hide();
+			tinyMCE.lastMenu = null;
+		}
+
+		if (e) {
+			tinyMCE.switchClass(e, tinyMCE.lastMenuBtnClass);
+			tinyMCE.lastSelectedMenuBtn = null;
+		}
+	}
+
+	};
+
+// Global instances
+var TinyMCE = TinyMCE_Engine; // Compatiblity with gzip compressors
+var tinyMCE = new TinyMCE_Engine();
+var tinyMCELang = {};
+
+/* file:jscripts/tiny_mce/classes/TinyMCE_Control.class.js */
+
+function TinyMCE_Control(settings) {
+	var t, i, to, fu, p, x, fn, fu, pn, s = settings;
+
+	this.undoRedoLevel = true;
+	this.isTinyMCE_Control = true;
+
+	// Default settings
+	this.settings = s;
+	this.settings['theme'] = tinyMCE.getParam("theme", "default");
+	this.settings['width'] = tinyMCE.getParam("width", -1);
+	this.settings['height'] = tinyMCE.getParam("height", -1);
+	this.selection = new TinyMCE_Selection(this);
+	this.undoRedo = new TinyMCE_UndoRedo(this);
+	this.cleanup = new TinyMCE_Cleanup();
+	this.shortcuts = new Array();
+	this.hasMouseMoved = false;
+	this.foreColor = this.backColor = "#999999";
+	this.data = {};
+	this.cssClasses = [];
+
+	this.cleanup.init({
+		valid_elements : s.valid_elements,
+		extended_valid_elements : s.extended_valid_elements,
+		valid_child_elements : s.valid_child_elements,
+		entities : s.entities,
+		entity_encoding : s.entity_encoding,
+		debug : s.cleanup_debug,
+		indent : s.apply_source_formatting,
+		invalid_elements : s.invalid_elements,
+		verify_html : s.verify_html,
+		fix_content_duplication : s.fix_content_duplication,
+		convert_fonts_to_spans : s.convert_fonts_to_spans
+	});
+
+	// Wrap old theme
+	t = this.settings['theme'];
+	if (!tinyMCE.hasTheme(t)) {
+		fn = tinyMCE.callbacks;
+		to = {};
+
+		for (i=0; i<fn.length; i++) {
+			if ((fu = window['TinyMCE_' + t + "_" + fn[i]]))
+				to[fn[i]] = fu;
+		}
+
+		tinyMCE.addTheme(t, to);
+	}
+
+	// Wrap old plugins
+	this.plugins = new Array();
+	p = tinyMCE.getParam('plugins', '', true, ',');
+	if (p.length > 0) {
+		for (i=0; i<p.length; i++) {
+			pn = p[i];
+
+			if (pn.charAt(0) == '-')
+				pn = pn.substring(1);
+
+			if (!tinyMCE.hasPlugin(pn)) {
+				fn = tinyMCE.callbacks;
+				to = {};
+
+				for (x=0; x<fn.length; x++) {
+					if ((fu = window['TinyMCE_' + pn + "_" + fn[x]]))
+						to[fn[x]] = fu;
+				}
+
+				tinyMCE.addPlugin(pn, to);
+			}
+
+			this.plugins[this.plugins.length] = pn; 
+		}
+	}
+};
+
+TinyMCE_Control.prototype = {
+	selection : null,
+
+	settings : null,
+
+	cleanup : null,
+
+	getData : function(na) {
+		var o = this.data[na];
+
+		if (!o)
+			o = this.data[na] = {};
+
+		return o;
+	},
+
+	hasPlugin : function(n) {
+		var i;
+
+		for (i=0; i<this.plugins.length; i++) {
+			if (this.plugins[i] == n)
+				return true;
+		}
+
+		return false;
+	},
+
+	addPlugin : function(n, p) {
+		if (!this.hasPlugin(n)) {
+			tinyMCE.addPlugin(n, p);
+			this.plugins[this.plugins.length] = n;
+		}
+	},
+
+	repaint : function() {
+		var s, b, ex;
+
+		if (tinyMCE.isRealIE)
+			return;
+
+		try {
+			s = this.selection;
+			b = s.getBookmark(true);
+			this.getBody().style.display = 'none';
+			this.getDoc().execCommand('selectall', false, null);
+			this.getSel().collapseToStart();
+			this.getBody().style.display = 'block';
+			s.moveToBookmark(b);
+		} catch (ex) {
+			// Ignore
+		}
+	},
+
+	switchSettings : function() {
+		if (tinyMCE.configs.length > 1 && tinyMCE.currentConfig != this.settings['index']) {
+			tinyMCE.settings = this.settings;
+			tinyMCE.currentConfig = this.settings['index'];
+		}
+	},
+
+	select : function() {
+		var oldInst = tinyMCE.selectedInstance;
+
+		if (oldInst != this) {
+			if (oldInst)
+				oldInst.execCommand('mceEndTyping');
+
+			tinyMCE.dispatchCallback(this, 'select_instance_callback', 'selectInstance', this, oldInst);
+			tinyMCE.selectedInstance = this;
+		}
+	},
+
+	getBody : function() {
+		return this.contentBody ? this.contentBody : this.getDoc().body;
+	},
+
+	getDoc : function() {
+//		return this.contentDocument ? this.contentDocument : this.contentWindow.document; // Removed due to IE 5.5 ?
+		return this.contentWindow.document;
+	},
+
+	getWin : function() {
+		return this.contentWindow;
+	},
+
+	getContainerWin : function() {
+		return this.containerWindow ? this.containerWindow : window;
+	},
+
+	getViewPort : function() {
+		return tinyMCE.getViewPort(this.getWin());
+	},
+
+	getParentNode : function(n, f) {
+		return tinyMCE.getParentNode(n, f, this.getBody());
+	},
+
+	getParentElement : function(n, na, f) {
+		return tinyMCE.getParentElement(n, na, f, this.getBody());
+	},
+
+	getParentBlockElement : function(n) {
+		return tinyMCE.getParentBlockElement(n, this.getBody());
+	},
+
+	resizeToContent : function() {
+		var d = this.getDoc(), b = d.body, de = d.documentElement;
+
+		this.iframeElement.style.height = (tinyMCE.isRealIE) ? b.scrollHeight : de.offsetHeight + 'px';
+	},
+
+	addShortcut : function(m, k, d, cmd, ui, va) {
+		var n = typeof(k) == "number", ie = tinyMCE.isIE, c, sc, i, scl = this.shortcuts;
+
+		if (!tinyMCE.getParam('custom_shortcuts'))
+			return false;
+
+		m = m.toLowerCase();
+		k = ie && !n ? k.toUpperCase() : k;
+		c = n ? null : k.charCodeAt(0);
+		d = d && d.indexOf('lang_') == 0 ? tinyMCE.getLang(d) : d;
+
+		sc = {
+			alt : m.indexOf('alt') != -1,
+			ctrl : m.indexOf('ctrl') != -1,
+			shift : m.indexOf('shift') != -1,
+			charCode : c,
+			keyCode : n ? k : (ie ? c : null),
+			desc : d,
+			cmd : cmd,
+			ui : ui,
+			val : va
+		};
+
+		for (i=0; i<scl.length; i++) {
+			if (sc.alt == scl[i].alt && sc.ctrl == scl[i].ctrl && sc.shift == scl[i].shift
+				&& sc.charCode == scl[i].charCode && sc.keyCode == scl[i].keyCode) {
+				return false;
+			}
+		}
+
+		scl[scl.length] = sc;
+
+		return true;
+	},
+
+	handleShortcut : function(e) {
+		var i, s, o;
+
+		// Normal key press, then ignore it
+		if (!e.altKey && !e.ctrlKey)
+			return false;
+
+		s = this.shortcuts;
+
+		for (i=0; i<s.length; i++) {
+			o = s[i];
+
+			if (o.alt == e.altKey && o.ctrl == e.ctrlKey && (o.keyCode == e.keyCode || o.charCode == e.charCode)) {
+				if (o.cmd && (e.type == "keydown" || (e.type == "keypress" && !tinyMCE.isOpera)))
+					tinyMCE.execCommand(o.cmd, o.ui, o.val);
+
+				tinyMCE.cancelEvent(e);
+				return true;
+			}
+		}
+
+		return false;
+	},
+
+	autoResetDesignMode : function() {
+		// Add fix for tab/style.display none/block problems in Gecko
+		if (!tinyMCE.isIE && this.isHidden() && tinyMCE.getParam('auto_reset_designmode'))
+			eval('try { this.getDoc().designMode = "On"; this.useCSS = false; } catch(e) {}');
+	},
+
+	isHidden : function() {
+		var s;
+
+		if (tinyMCE.isIE)
+			return false;
+
+		s = this.getSel();
+
+		// Weird, wheres that cursor selection?
+		return (!s || !s.rangeCount || s.rangeCount == 0);
+	},
+
+	isDirty : function() {
+		// Is content modified and not in a submit procedure
+		return tinyMCE.trim(this.startContent) != tinyMCE.trim(this.getBody().innerHTML) && !tinyMCE.isNotDirty;
+	},
+
+	_mergeElements : function(scmd, pa, ch, override) {
+		if (scmd == "removeformat") {
+			pa.className = "";
+			pa.style.cssText = "";
+			ch.className = "";
+			ch.style.cssText = "";
+			return;
+		}
+
+		var st = tinyMCE.parseStyle(tinyMCE.getAttrib(pa, "style"));
+		var stc = tinyMCE.parseStyle(tinyMCE.getAttrib(ch, "style"));
+		var className = tinyMCE.getAttrib(pa, "class");
+
+		// Removed class adding due to bug #1478272
+		className = tinyMCE.getAttrib(ch, "class");
+
+		if (override) {
+			for (var n in st) {
+				if (typeof(st[n]) == 'function')
+					continue;
+
+				stc[n] = st[n];
+			}
+		} else {
+			for (var n in stc) {
+				if (typeof(stc[n]) == 'function')
+					continue;
+
+				st[n] = stc[n];
+			}
+		}
+
+		tinyMCE.setAttrib(pa, "style", tinyMCE.serializeStyle(st));
+		tinyMCE.setAttrib(pa, "class", tinyMCE.trim(className));
+		ch.className = "";
+		ch.style.cssText = "";
+		ch.removeAttribute("class");
+		ch.removeAttribute("style");
+	},
+
+	_setUseCSS : function(b) {
+		var d = this.getDoc();
+
+		try {d.execCommand("useCSS", false, !b);} catch (ex) {}
+		try {d.execCommand("styleWithCSS", false, b);} catch (ex) {}
+
+		if (!tinyMCE.getParam("table_inline_editing"))
+			try {d.execCommand('enableInlineTableEditing', false, "false");} catch (ex) {}
+
+		if (!tinyMCE.getParam("object_resizing"))
+			try {d.execCommand('enableObjectResizing', false, "false");} catch (ex) {}
+	},
+
+	execCommand : function(command, user_interface, value) {
+		var doc = this.getDoc(), win = this.getWin(), focusElm = this.getFocusElement();
+
+		// Is not a undo specific command
+		if (!new RegExp('mceStartTyping|mceEndTyping|mceBeginUndoLevel|mceEndUndoLevel|mceAddUndoLevel', 'gi').test(command))
+			this.undoBookmark = null;
+
+		// Mozilla issue
+		if (!tinyMCE.isIE && !this.useCSS) {
+			this._setUseCSS(false);
+			this.useCSS = true;
+		}
+
+		//debug("command: " + command + ", user_interface: " + user_interface + ", value: " + value);
+		this.contentDocument = doc; // <-- Strange, unless this is applied Mozilla 1.3 breaks
+
+		// Don't dispatch key commands
+		if (!/mceStartTyping|mceEndTyping/.test(command)) {
+			if (tinyMCE.execCommandCallback(this, 'execcommand_callback', 'execCommand', this.editorId, this.getBody(), command, user_interface, value))
+				return;
+		}
+
+		// Fix align on images
+		if (focusElm && focusElm.nodeName == "IMG") {
+			var align = focusElm.getAttribute('align');
+			var img = command == "JustifyCenter" ? focusElm.cloneNode(false) : focusElm;
+
+			switch (command) {
+				case "JustifyLeft":
+					if (align == 'left')
+						img.removeAttribute('align');
+					else
+						img.setAttribute('align', 'left');
+
+					// Remove the div
+					var div = focusElm.parentNode;
+					if (div && div.nodeName == "DIV" && div.childNodes.length == 1 && div.parentNode)
+						div.parentNode.replaceChild(img, div);
+
+					this.selection.selectNode(img);
+					this.repaint();
+					tinyMCE.triggerNodeChange();
+					return;
+
+				case "JustifyCenter":
+					img.removeAttribute('align');
+
+					// Is centered
+					var div = tinyMCE.getParentElement(focusElm, "div");
+					if (div && div.style.textAlign == "center") {
+						// Remove div
+						if (div.nodeName == "DIV" && div.childNodes.length == 1 && div.parentNode)
+							div.parentNode.replaceChild(img, div);
+					} else {
+						// Add div
+						var div = this.getDoc().createElement("div");
+						div.style.textAlign = 'center';
+						div.appendChild(img);
+						focusElm.parentNode.replaceChild(div, focusElm);
+					}
+
+					this.selection.selectNode(img);
+					this.repaint();
+					tinyMCE.triggerNodeChange();
+					return;
+
+				case "JustifyRight":
+					if (align == 'right')
+						img.removeAttribute('align');
+					else
+						img.setAttribute('align', 'right');
+
+					// Remove the div
+					var div = focusElm.parentNode;
+					if (div && div.nodeName == "DIV" && div.childNodes.length == 1 && div.parentNode)
+						div.parentNode.replaceChild(img, div);
+
+					this.selection.selectNode(img);
+					this.repaint();
+					tinyMCE.triggerNodeChange();
+					return;
+			}
+		}
+
+		if (tinyMCE.settings['force_br_newlines']) {
+			var alignValue = "";
+
+			if (doc.selection.type != "Control") {
+				switch (command) {
+						case "JustifyLeft":
+							alignValue = "left";
+							break;
+
+						case "JustifyCenter":
+							alignValue = "center";
+							break;
+
+						case "JustifyFull":
+							alignValue = "justify";
+							break;
+
+						case "JustifyRight":
+							alignValue = "right";
+							break;
+				}
+
+				if (alignValue != "") {
+					var rng = doc.selection.createRange();
+
+					if ((divElm = tinyMCE.getParentElement(rng.parentElement(), "div")) != null)
+						divElm.setAttribute("align", alignValue);
+					else if (rng.pasteHTML && rng.htmlText.length > 0)
+						rng.pasteHTML('<div align="' + alignValue + '">' + rng.htmlText + "</div>");
+
+					tinyMCE.triggerNodeChange();
+					return;
+				}
+			}
+		}
+
+		switch (command) {
+			case "mceRepaint":
+				this.repaint();
+				return true;
+
+			case "unlink":
+				// Unlink if caret is inside link
+				if (tinyMCE.isGecko && this.getSel().isCollapsed) {
+					focusElm = tinyMCE.getParentElement(focusElm, 'A');
+
+					if (focusElm)
+						this.selection.selectNode(focusElm, false);
+				}
+
+				this.getDoc().execCommand(command, user_interface, value);
+
+				tinyMCE.isGecko && this.getSel().collapseToEnd();
+
+				tinyMCE.triggerNodeChange();
+
+				return true;
+
+			case "InsertUnorderedList":
+			case "InsertOrderedList":
+				this.getDoc().execCommand(command, user_interface, value);
+				tinyMCE.triggerNodeChange();
+				break;
+
+			case "Strikethrough":
+				this.getDoc().execCommand(command, user_interface, value);
+				tinyMCE.triggerNodeChange();
+				break;
+
+			case "mceSelectNode":
+				this.selection.selectNode(value);
+				tinyMCE.triggerNodeChange();
+				tinyMCE.selectedNode = value;
+				break;
+
+			case "FormatBlock":
+				if (value == null || value == "") {
+					var elm = tinyMCE.getParentElement(this.getFocusElement(), "p,div,h1,h2,h3,h4,h5,h6,pre,address,blockquote,dt,dl,dd,samp");
+
+					if (elm)
+						this.execCommand("mceRemoveNode", false, elm);
+				} else {
+					if (!this.cleanup.isValid(value))
+						return true;
+
+					if (tinyMCE.isGecko && new RegExp('<(div|blockquote|code|dt|dd|dl|samp)>', 'gi').test(value))
+						value = value.replace(/[^a-z]/gi, '');
+
+					if (tinyMCE.isIE && new RegExp('blockquote|code|samp', 'gi').test(value)) {
+						var b = this.selection.getBookmark();
+						this.getDoc().execCommand("FormatBlock", false, '<p>');
+						tinyMCE.renameElement(tinyMCE.getParentBlockElement(this.getFocusElement()), value);
+						this.selection.moveToBookmark(b);
+					} else
+						this.getDoc().execCommand("FormatBlock", false, value);
+				}
+
+				tinyMCE.triggerNodeChange();
+
+				break;
+
+			case "mceRemoveNode":
+				if (!value)
+					value = tinyMCE.getParentElement(this.getFocusElement());
+
+				if (tinyMCE.isIE) {
+					value.outerHTML = value.innerHTML;
+				} else {
+					var rng = value.ownerDocument.createRange();
+					rng.setStartBefore(value);
+					rng.setEndAfter(value);
+					rng.deleteContents();
+					rng.insertNode(rng.createContextualFragment(value.innerHTML));
+				}
+
+				tinyMCE.triggerNodeChange();
+
+				break;
+
+			case "mceSelectNodeDepth":
+				var parentNode = this.getFocusElement();
+				for (var i=0; parentNode; i++) {
+					if (parentNode.nodeName.toLowerCase() == "body")
+						break;
+
+					if (parentNode.nodeName.toLowerCase() == "#text") {
+						i--;
+						parentNode = parentNode.parentNode;
+						continue;
+					}
+
+					if (i == value) {
+						this.selection.selectNode(parentNode, false);
+						tinyMCE.triggerNodeChange();
+						tinyMCE.selectedNode = parentNode;
+						return;
+					}
+
+					parentNode = parentNode.parentNode;
+				}
+
+				break;
+
+			case "mceSetStyleInfo":
+			case "SetStyleInfo":
+				var rng = this.getRng();
+				var sel = this.getSel();
+				var scmd = value['command'];
+				var sname = value['name'];
+				var svalue = value['value'] == null ? '' : value['value'];
+				//var svalue = value['value'] == null ? '' : value['value'];
+				var wrapper = value['wrapper'] ? value['wrapper'] : "span";
+				var parentElm = null;
+				var invalidRe = new RegExp("^BODY|HTML$", "g");
+				var invalidParentsRe = tinyMCE.settings['merge_styles_invalid_parents'] != '' ? new RegExp(tinyMCE.settings['merge_styles_invalid_parents'], "gi") : null;
+
+				// Whole element selected check
+				if (tinyMCE.isIE) {
+					// Control range
+					if (rng.item)
+						parentElm = rng.item(0);
+					else {
+						var pelm = rng.parentElement();
+						var prng = doc.selection.createRange();
+						prng.moveToElementText(pelm);
+
+						if (rng.htmlText == prng.htmlText || rng.boundingWidth == 0) {
+							if (invalidParentsRe == null || !invalidParentsRe.test(pelm.nodeName))
+								parentElm = pelm;
+						}
+					}
+				} else {
+					var felm = this.getFocusElement();
+					if (sel.isCollapsed || (new RegExp('td|tr|tbody|table', 'gi').test(felm.nodeName) && sel.anchorNode == felm.parentNode))
+						parentElm = felm;
+				}
+
+				// Whole element selected
+				if (parentElm && !invalidRe.test(parentElm.nodeName)) {
+					if (scmd == "setstyle")
+						tinyMCE.setStyleAttrib(parentElm, sname, svalue);
+
+					if (scmd == "setattrib")
+						tinyMCE.setAttrib(parentElm, sname, svalue);
+
+					if (scmd == "removeformat") {
+						parentElm.style.cssText = '';
+						tinyMCE.setAttrib(parentElm, 'class', '');
+					}
+
+					// Remove style/attribs from all children
+					var ch = tinyMCE.getNodeTree(parentElm, new Array(), 1);
+					for (var z=0; z<ch.length; z++) {
+						if (ch[z] == parentElm)
+							continue;
+
+						if (scmd == "setstyle")
+							tinyMCE.setStyleAttrib(ch[z], sname, '');
+
+						if (scmd == "setattrib")
+							tinyMCE.setAttrib(ch[z], sname, '');
+
+						if (scmd == "removeformat") {
+							ch[z].style.cssText = '';
+							tinyMCE.setAttrib(ch[z], 'class', '');
+						}
+					}
+				} else {
+					this._setUseCSS(false); // Bug in FF when running in fullscreen
+					doc.execCommand("FontName", false, "#mce_temp_font#");
+					var elementArray = tinyMCE.getElementsByAttributeValue(this.getBody(), "font", "face", "#mce_temp_font#");
+
+					// Change them all
+					for (var x=0; x<elementArray.length; x++) {
+						elm = elementArray[x];
+						if (elm) {
+							var spanElm = doc.createElement(wrapper);
+
+							if (scmd == "setstyle")
+								tinyMCE.setStyleAttrib(spanElm, sname, svalue);
+
+							if (scmd == "setattrib")
+								tinyMCE.setAttrib(spanElm, sname, svalue);
+
+							if (scmd == "removeformat") {
+								spanElm.style.cssText = '';
+								tinyMCE.setAttrib(spanElm, 'class', '');
+							}
+
+							if (elm.hasChildNodes()) {
+								for (var i=0; i<elm.childNodes.length; i++)
+									spanElm.appendChild(elm.childNodes[i].cloneNode(true));
+							}
+
+							spanElm.setAttribute("mce_new", "true");
+							elm.parentNode.replaceChild(spanElm, elm);
+
+							// Remove style/attribs from all children
+							var ch = tinyMCE.getNodeTree(spanElm, new Array(), 1);
+							for (var z=0; z<ch.length; z++) {
+								if (ch[z] == spanElm)
+									continue;
+
+								if (scmd == "setstyle")
+									tinyMCE.setStyleAttrib(ch[z], sname, '');
+
+								if (scmd == "setattrib")
+									tinyMCE.setAttrib(ch[z], sname, '');
+
+								if (scmd == "removeformat") {
+									ch[z].style.cssText = '';
+									tinyMCE.setAttrib(ch[z], 'class', '');
+								}
+							}
+						}
+					}
+				}
+
+				// Cleaup wrappers
+				var nodes = doc.getElementsByTagName(wrapper);
+				for (var i=nodes.length-1; i>=0; i--) {
+					var elm = nodes[i];
+					var isNew = tinyMCE.getAttrib(elm, "mce_new") == "true";
+
+					elm.removeAttribute("mce_new");
+
+					// Is only child a element
+					if (elm.childNodes && elm.childNodes.length == 1 && elm.childNodes[0].nodeType == 1) {
+						//tinyMCE.debug("merge1" + isNew);
+						this._mergeElements(scmd, elm, elm.childNodes[0], isNew);
+						continue;
+					}
+
+					// Is I the only child
+					if (elm.parentNode.childNodes.length == 1 && !invalidRe.test(elm.nodeName) && !invalidRe.test(elm.parentNode.nodeName)) {
+						//tinyMCE.debug("merge2" + isNew + "," + elm.nodeName + "," + elm.parentNode.nodeName);
+						if (invalidParentsRe == null || !invalidParentsRe.test(elm.parentNode.nodeName))
+							this._mergeElements(scmd, elm.parentNode, elm, false);
+					}
+				}
+
+				// Remove empty wrappers
+				var nodes = doc.getElementsByTagName(wrapper);
+				for (var i=nodes.length-1; i>=0; i--) {
+					var elm = nodes[i];
+					var isEmpty = true;
+
+					// Check if it has any attribs
+					var tmp = doc.createElement("body");
+					tmp.appendChild(elm.cloneNode(false));
+
+					// Is empty span, remove it
+					tmp.innerHTML = tmp.innerHTML.replace(new RegExp('style=""|class=""', 'gi'), '');
+					//tinyMCE.debug(tmp.innerHTML);
+					if (new RegExp('<span>', 'gi').test(tmp.innerHTML)) {
+						for (var x=0; x<elm.childNodes.length; x++) {
+							if (elm.parentNode != null)
+								elm.parentNode.insertBefore(elm.childNodes[x].cloneNode(true), elm);
+						}
+
+						elm.parentNode.removeChild(elm);
+					}
+				}
+
+				// Re add the visual aids
+				if (scmd == "removeformat")
+					tinyMCE.handleVisualAid(this.getBody(), true, this.visualAid, this);
+
+				tinyMCE.triggerNodeChange();
+
+				break;
+
+			case "FontName":
+				if (value == null) {
+					var s = this.getSel();
+
+					// Find font and select it
+					if (tinyMCE.isGecko && s.isCollapsed) {
+						var f = tinyMCE.getParentElement(this.getFocusElement(), "font");
+
+						if (f != null)
+							this.selection.selectNode(f, false);
+					}
+
+					// Remove format
+					this.getDoc().execCommand("RemoveFormat", false, null);
+
+					// Collapse range if font was found
+					if (f != null && tinyMCE.isGecko) {
+						var r = this.getRng().cloneRange();
+						r.collapse(true);
+						s.removeAllRanges();
+						s.addRange(r);
+					}
+				} else
+					this.getDoc().execCommand('FontName', false, value);
+
+				if (tinyMCE.isGecko)
+					window.setTimeout('tinyMCE.triggerNodeChange(false);', 1);
+
+				return;
+
+			case "FontSize":
+				this.getDoc().execCommand('FontSize', false, value);
+
+				if (tinyMCE.isGecko)
+					window.setTimeout('tinyMCE.triggerNodeChange(false);', 1);
+
+				return;
+
+			case "forecolor":
+				value = value == null ? this.foreColor : value;
+				value = tinyMCE.trim(value);
+				value = value.charAt(0) != '#' ? (isNaN('0x' + value) ? value : '#' + value) : value;
+
+				this.foreColor = value;
+				this.getDoc().execCommand('forecolor', false, value);
+				break;
+
+			case "HiliteColor":
+				value = value == null ? this.backColor : value;
+				value = tinyMCE.trim(value);
+				value = value.charAt(0) != '#' ? (isNaN('0x' + value) ? value : '#' + value) : value;
+				this.backColor = value;
+
+				if (tinyMCE.isGecko) {
+					this._setUseCSS(true);
+					this.getDoc().execCommand('hilitecolor', false, value);
+					this._setUseCSS(false);
+				} else
+					this.getDoc().execCommand('BackColor', false, value);
+				break;
+
+			case "Cut":
+			case "Copy":
+			case "Paste":
+				var cmdFailed = false;
+
+				// Try executing command
+				eval('try {this.getDoc().execCommand(command, user_interface, value);} catch (e) {cmdFailed = true;}');
+
+				if (tinyMCE.isOpera && cmdFailed)
+					alert('Currently not supported by your browser, use keyboard shortcuts instead.');
+
+				// Alert error in gecko if command failed
+				if (tinyMCE.isGecko && cmdFailed) {
+					// Confirm more info
+					if (confirm(tinyMCE.entityDecode(tinyMCE.getLang('lang_clipboard_msg'))))
+						window.open('http://www.mozilla.org/editor/midasdemo/securityprefs.html', 'mceExternal');
+
+					return;
+				} else
+					tinyMCE.triggerNodeChange();
+			break;
+
+			case "mceSetContent":
+				if (!value)
+					value = "";
+
+				// Call custom cleanup code
+				value = tinyMCE.storeAwayURLs(value);
+				value = tinyMCE._customCleanup(this, "insert_to_editor", value);
+
+				if (this.getBody().nodeName == 'BODY')
+					tinyMCE._setHTML(doc, value);
+				else
+					this.getBody().innerHTML = value;
+
+				tinyMCE.setInnerHTML(this.getBody(), tinyMCE._cleanupHTML(this, doc, this.settings, this.getBody(), false, false, false, true));
+				tinyMCE.convertAllRelativeURLs(this.getBody());
+
+				// Cleanup any mess left from storyAwayURLs
+				tinyMCE._removeInternal(this.getBody());
+
+				// When editing always use fonts internaly
+				if (tinyMCE.getParam("convert_fonts_to_spans"))
+					tinyMCE.convertSpansToFonts(doc);
+
+				tinyMCE.handleVisualAid(this.getBody(), true, this.visualAid, this);
+				tinyMCE._setEventsEnabled(this.getBody(), false);
+				return true;
+
+			case "mceCleanup":
+				var b = this.selection.getBookmark();
+				tinyMCE._setHTML(this.contentDocument, this.getBody().innerHTML);
+				tinyMCE.setInnerHTML(this.getBody(), tinyMCE._cleanupHTML(this, this.contentDocument, this.settings, this.getBody(), this.visualAid));
+				tinyMCE.convertAllRelativeURLs(doc.body);
+
+				// When editing always use fonts internaly
+				if (tinyMCE.getParam("convert_fonts_to_spans"))
+					tinyMCE.convertSpansToFonts(doc);
+
+				tinyMCE.handleVisualAid(this.getBody(), true, this.visualAid, this);
+				tinyMCE._setEventsEnabled(this.getBody(), false);
+				this.repaint();
+				this.selection.moveToBookmark(b);
+				tinyMCE.triggerNodeChange();
+			break;
+
+			case "mceReplaceContent":
+				// Force empty string
+				if (!value)
+					value = '';
+
+				this.getWin().focus();
+
+				var selectedText = "";
+
+				if (tinyMCE.isIE) {
+					var rng = doc.selection.createRange();
+					selectedText = rng.text;
+				} else
+					selectedText = this.getSel().toString();
+
+				if (selectedText.length > 0) {
+					value = tinyMCE.replaceVar(value, "selection", selectedText);
+					tinyMCE.execCommand('mceInsertContent', false, value);
+				}
+
+				tinyMCE.triggerNodeChange();
+			break;
+
+			case "mceSetAttribute":
+				if (typeof(value) == 'object') {
+					var targetElms = (typeof(value['targets']) == "undefined") ? "p,img,span,div,td,h1,h2,h3,h4,h5,h6,pre,address" : value['targets'];
+					var targetNode = tinyMCE.getParentElement(this.getFocusElement(), targetElms);
+
+					if (targetNode) {
+						targetNode.setAttribute(value['name'], value['value']);
+						tinyMCE.triggerNodeChange();
+					}
+				}
+			break;
+
+			case "mceSetCSSClass":
+				this.execCommand("mceSetStyleInfo", false, {command : "setattrib", name : "class", value : value});
+			break;
+
+			case "mceInsertRawHTML":
+				var key = 'tiny_mce_marker';
+
+				this.execCommand('mceBeginUndoLevel');
+
+				// Insert marker key
+				this.execCommand('mceInsertContent', false, key);
+
+				// Store away scroll pos
+				var scrollX = this.getBody().scrollLeft + this.getDoc().documentElement.scrollLeft;
+				var scrollY = this.getBody().scrollTop + this.getDoc().documentElement.scrollTop;
+
+				// Find marker and replace with RAW HTML
+				var html = this.getBody().innerHTML;
+				if ((pos = html.indexOf(key)) != -1)
+					tinyMCE.setInnerHTML(this.getBody(), html.substring(0, pos) + value + html.substring(pos + key.length));
+
+				// Restore scoll pos
+				this.contentWindow.scrollTo(scrollX, scrollY);
+
+				this.execCommand('mceEndUndoLevel');
+
+				break;
+
+			case "mceInsertContent":
+				// Force empty string
+				if (!value)
+					value = '';
+
+				var insertHTMLFailed = false;
+
+				// Removed since it produced problems in IE
+				// this.getWin().focus();
+
+				if (tinyMCE.isGecko || tinyMCE.isOpera) {
+					try {
+						// Is plain text or HTML, &amp;, &nbsp; etc will be encoded wrong in FF
+						if (value.indexOf('<') == -1 && !value.match(/(&#38;|&#160;|&#60;|&#62;)/g)) {
+							var r = this.getRng();
+							var n = this.getDoc().createTextNode(tinyMCE.entityDecode(value));
+							var s = this.getSel();
+							var r2 = r.cloneRange();
+
+							// Insert text at cursor position
+							s.removeAllRanges();
+							r.deleteContents();
+							r.insertNode(n);
+
+							// Move the cursor to the end of text
+							r2.selectNode(n);
+							r2.collapse(false);
+							s.removeAllRanges();
+							s.addRange(r2);
+						} else {
+							value = tinyMCE.fixGeckoBaseHREFBug(1, this.getDoc(), value);
+							this.getDoc().execCommand('inserthtml', false, value);
+							tinyMCE.fixGeckoBaseHREFBug(2, this.getDoc(), value);
+						}
+					} catch (ex) {
+						insertHTMLFailed = true;
+					}
+
+					if (!insertHTMLFailed) {
+						tinyMCE.triggerNodeChange();
+						return;
+					}
+				}
+
+				if (!tinyMCE.isIE) {
+					var isHTML = value.indexOf('<') != -1;
+					var sel = this.getSel();
+					var rng = this.getRng();
+
+					if (isHTML) {
+						if (tinyMCE.isSafari) {
+							var tmpRng = this.getDoc().createRange();
+
+							tmpRng.setStart(this.getBody(), 0);
+							tmpRng.setEnd(this.getBody(), 0);
+
+							value = tmpRng.createContextualFragment(value);
+						} else
+							value = rng.createContextualFragment(value);
+					} else {
+						// Setup text node
+						var el = document.createElement("div");
+						el.innerHTML = value;
+						value = el.firstChild.nodeValue;
+						value = doc.createTextNode(value);
+					}
+
+					// Insert plain text in Safari
+					if (tinyMCE.isSafari && !isHTML) {
+						this.execCommand('InsertText', false, value.nodeValue);
+						tinyMCE.triggerNodeChange();
+						return true;
+					} else if (tinyMCE.isSafari && isHTML) {
+						rng.deleteContents();
+						rng.insertNode(value);
+						tinyMCE.triggerNodeChange();
+						return true;
+					}
+
+					rng.deleteContents();
+
+					// If target node is text do special treatment, (Mozilla 1.3 fix)
+					if (rng.startContainer.nodeType == 3) {
+						var node = rng.startContainer.splitText(rng.startOffset);
+						node.parentNode.insertBefore(value, node); 
+					} else
+						rng.insertNode(value);
+
+					if (!isHTML) {
+						// Removes weird selection trails
+						sel.selectAllChildren(doc.body);
+						sel.removeAllRanges();
+
+						// Move cursor to end of content
+						var rng = doc.createRange();
+
+						rng.selectNode(value);
+						rng.collapse(false);
+
+						sel.addRange(rng);
+					} else
+						rng.collapse(false);
+
+					tinyMCE.fixGeckoBaseHREFBug(2, this.getDoc(), value);
+				} else {
+					var rng = doc.selection.createRange(), tmpRng = null;
+					var c = value.indexOf('<!--') != -1;
+
+					// Fix comment bug, add tag before comments
+					if (c)
+						value = tinyMCE.uniqueTag + value;
+
+					//	tmpRng = rng.duplicate(); // Store away range (Fixes Undo bookmark bug in IE)
+
+					if (rng.item)
+						rng.item(0).outerHTML = value;
+					else
+						rng.pasteHTML(value);
+
+					//if (tmpRng)
+					//	tmpRng.select(); // Restore range  (Fixes Undo bookmark bug in IE)
+
+					// Remove unique tag
+					if (c) {
+						var e = this.getDoc().getElementById('mceTMPElement');
+						e.parentNode.removeChild(e);
+					}
+				}
+
+				tinyMCE.execCommand("mceAddUndoLevel");
+				tinyMCE.triggerNodeChange();
+			break;
+
+			case "mceStartTyping":
+				if (tinyMCE.settings['custom_undo_redo'] && this.undoRedo.typingUndoIndex == -1) {
+					this.undoRedo.typingUndoIndex = this.undoRedo.undoIndex;
+					tinyMCE.typingUndoIndex = tinyMCE.undoIndex;
+					this.execCommand('mceAddUndoLevel');
+				}
+				break;
+
+			case "mceEndTyping":
+				if (tinyMCE.settings['custom_undo_redo'] && this.undoRedo.typingUndoIndex != -1) {
+					this.execCommand('mceAddUndoLevel');
+					this.undoRedo.typingUndoIndex = -1;
+				}
+
+				tinyMCE.typingUndoIndex = -1;
+				break;
+
+			case "mceBeginUndoLevel":
+				this.undoRedoLevel = false;
+				break;
+
+			case "mceEndUndoLevel":
+				this.undoRedoLevel = true;
+				this.execCommand('mceAddUndoLevel');
+				break;
+
+			case "mceAddUndoLevel":
+				if (tinyMCE.settings['custom_undo_redo'] && this.undoRedoLevel) {
+					if (this.undoRedo.add())
+						tinyMCE.triggerNodeChange(false);
+				}
+				break;
+
+			case "Undo":
+				if (tinyMCE.settings['custom_undo_redo']) {
+					tinyMCE.execCommand("mceEndTyping");
+					this.undoRedo.undo();
+					tinyMCE.triggerNodeChange();
+				} else
+					this.getDoc().execCommand(command, user_interface, value);
+				break;
+
+			case "Redo":
+				if (tinyMCE.settings['custom_undo_redo']) {
+					tinyMCE.execCommand("mceEndTyping");
+					this.undoRedo.redo();
+					tinyMCE.triggerNodeChange();
+				} else
+					this.getDoc().execCommand(command, user_interface, value);
+				break;
+
+			case "mceToggleVisualAid":
+				this.visualAid = !this.visualAid;
+				tinyMCE.handleVisualAid(this.getBody(), true, this.visualAid, this);
+				tinyMCE.triggerNodeChange();
+				break;
+
+			case "Indent":
+				this.getDoc().execCommand(command, user_interface, value);
+				tinyMCE.triggerNodeChange();
+
+				if (tinyMCE.isIE) {
+					var n = tinyMCE.getParentElement(this.getFocusElement(), "blockquote");
+					do {
+						if (n && n.nodeName == "BLOCKQUOTE") {
+							n.removeAttribute("dir");
+							n.removeAttribute("style");
+						}
+					} while (n != null && (n = n.parentNode) != null);
+				}
+				break;
+
+			case "RemoveFormat":
+			case "removeformat":
+				var text = this.selection.getSelectedText();
+
+				if (tinyMCE.isOpera) {
+					this.getDoc().execCommand("RemoveFormat", false, null);
+					return;
+				}
+
+				if (tinyMCE.isIE) {
+					try {
+						var rng = doc.selection.createRange();
+						rng.execCommand("RemoveFormat", false, null);
+					} catch (e) {
+						// Do nothing
+					}
+
+					this.execCommand("mceSetStyleInfo", false, {command : "removeformat"});
+				} else {
+					this.getDoc().execCommand(command, user_interface, value);
+
+					this.execCommand("mceSetStyleInfo", false, {command : "removeformat"});
+				}
+
+				// Remove class
+				if (text.length == 0)
+					this.execCommand("mceSetCSSClass", false, "");
+
+				tinyMCE.triggerNodeChange();
+				break;
+
+			default:
+				this.getDoc().execCommand(command, user_interface, value);
+
+				if (tinyMCE.isGecko)
+					window.setTimeout('tinyMCE.triggerNodeChange(false);', 1);
+				else
+					tinyMCE.triggerNodeChange();
+		}
+
+		// Add undo level after modification
+		if (command != "mceAddUndoLevel" && command != "Undo" && command != "Redo" && command != "mceStartTyping" && command != "mceEndTyping")
+			tinyMCE.execCommand("mceAddUndoLevel");
+	},
+
+	queryCommandValue : function(c) {
+		try {
+			return this.getDoc().queryCommandValue(c);
+		} catch (e) {
+			return null;
+		}
+	},
+
+	queryCommandState : function(c) {
+		return this.getDoc().queryCommandState(c);
+	},
+
+	_onAdd : function(replace_element, form_element_name, target_document) {
+		var hc, th, to, editorTemplate;
+
+		th = this.settings['theme'];
+		to = tinyMCE.themes[th];
+
+		var targetDoc = target_document ? target_document : document;
+
+		this.targetDoc = targetDoc;
+
+		tinyMCE.themeURL = tinyMCE.baseURL + "/themes/" + this.settings['theme'];
+		this.settings['themeurl'] = tinyMCE.themeURL;
+
+		if (!replace_element) {
+			alert("Error: Could not find the target element.");
+			return false;
+		}
+
+		if (to.getEditorTemplate)
+			editorTemplate = to.getEditorTemplate(this.settings, this.editorId);
+
+		var deltaWidth = editorTemplate['delta_width'] ? editorTemplate['delta_width'] : 0;
+		var deltaHeight = editorTemplate['delta_height'] ? editorTemplate['delta_height'] : 0;
+		var html = '<span id="' + this.editorId + '_parent" class="mceEditorContainer">' + editorTemplate['html'];
+
+		html = tinyMCE.replaceVar(html, "editor_id", this.editorId);
+		this.settings['default_document'] = tinyMCE.baseURL + "/blank.htm";
+
+		this.settings['old_width'] = this.settings['width'];
+		this.settings['old_height'] = this.settings['height'];
+
+		// Set default width, height
+		if (this.settings['width'] == -1)
+			this.settings['width'] = replace_element.offsetWidth;
+
+		if (this.settings['height'] == -1)
+			this.settings['height'] = replace_element.offsetHeight;
+
+		// Try the style width
+		if (this.settings['width'] == 0)
+			this.settings['width'] = replace_element.style.width;
+
+		// Try the style height
+		if (this.settings['height'] == 0)
+			this.settings['height'] = replace_element.style.height; 
+
+		// If no width/height then default to 320x240, better than nothing
+		if (this.settings['width'] == 0)
+			this.settings['width'] = 320;
+
+		if (this.settings['height'] == 0)
+			this.settings['height'] = 240;
+
+		this.settings['area_width'] = parseInt(this.settings['width']);
+		this.settings['area_height'] = parseInt(this.settings['height']);
+		this.settings['area_width'] += deltaWidth;
+		this.settings['area_height'] += deltaHeight;
+
+		this.settings['width_style'] = "" + this.settings['width'];
+		this.settings['height_style'] = "" + this.settings['height'];
+
+		// Special % handling
+		if (("" + this.settings['width']).indexOf('%') != -1)
+			this.settings['area_width'] = "100%";
+		else
+			this.settings['width_style'] += 'px';
+
+		if (("" + this.settings['height']).indexOf('%') != -1)
+			this.settings['area_height'] = "100%";
+		else
+			this.settings['height_style'] += 'px';
+
+		if (("" + replace_element.style.width).indexOf('%') != -1) {
+			this.settings['width'] = replace_element.style.width;
+			this.settings['area_width'] = "100%";
+			this.settings['width_style'] = "100%";
+		}
+
+		if (("" + replace_element.style.height).indexOf('%') != -1) {
+			this.settings['height'] = replace_element.style.height;
+			this.settings['area_height'] = "100%";
+			this.settings['height_style'] = "100%";
+		}
+
+		html = tinyMCE.applyTemplate(html);
+
+		this.settings['width'] = this.settings['old_width'];
+		this.settings['height'] = this.settings['old_height'];
+
+		this.visualAid = this.settings['visual'];
+		this.formTargetElementId = form_element_name;
+
+		// Get replace_element contents
+		if (replace_element.nodeName == "TEXTAREA" || replace_element.nodeName == "INPUT")
+			this.startContent = replace_element.value;
+		else
+			this.startContent = replace_element.innerHTML;
+
+		// If not text area or input
+		if (replace_element.nodeName != "TEXTAREA" && replace_element.nodeName != "INPUT") {
+			this.oldTargetElement = replace_element;
+
+			// Debug mode
+			if (tinyMCE.settings['debug']) {
+				hc = '<textarea wrap="off" id="' + form_element_name + '" name="' + form_element_name + '" cols="100" rows="15"></textarea>';
+			} else {
+				hc = '<input type="hidden" id="' + form_element_name + '" name="' + form_element_name + '" />';
+				this.oldTargetDisplay = tinyMCE.getStyle(this.oldTargetElement, 'display', 'inline');
+				this.oldTargetElement.style.display = "none";
+			}
+
+			html += '</span>';
+
+			if (tinyMCE.isGecko)
+				html = hc + html;
+			else
+				html += hc;
+
+			// Output HTML and set editable
+			if (tinyMCE.isGecko) {
+				var rng = replace_element.ownerDocument.createRange();
+				rng.setStartBefore(replace_element);
+
+				var fragment = rng.createContextualFragment(html);
+				tinyMCE.insertAfter(fragment, replace_element);
+			} else
+				replace_element.insertAdjacentHTML("beforeBegin", html);
+		} else {
+			html += '</span>';
+
+			// Just hide the textarea element
+			this.oldTargetElement = replace_element;
+
+			if (!tinyMCE.settings['debug']) {
+				this.oldTargetDisplay = tinyMCE.getStyle(this.oldTargetElement, 'display', 'inline');
+				this.oldTargetElement.style.display = "none";
+			}
+
+			// Output HTML and set editable
+			if (tinyMCE.isGecko) {
+				var rng = replace_element.ownerDocument.createRange();
+				rng.setStartBefore(replace_element);
+
+				var fragment = rng.createContextualFragment(html);
+				tinyMCE.insertAfter(fragment, replace_element);
+			} else
+				replace_element.insertAdjacentHTML("beforeBegin", html);
+		}
+
+		// Setup iframe
+		var dynamicIFrame = false;
+		var tElm = targetDoc.getElementById(this.editorId);
+
+		if (!tinyMCE.isIE) {
+			// Node case is preserved in XML strict mode
+			if (tElm && (tElm.nodeName == "SPAN" || tElm.nodeName == "span")) {
+				tElm = tinyMCE._createIFrame(tElm, targetDoc);
+				dynamicIFrame = true;
+			}
+
+			this.targetElement = tElm;
+			this.iframeElement = tElm;
+			this.contentDocument = tElm.contentDocument;
+			this.contentWindow = tElm.contentWindow;
+
+			//this.getDoc().designMode = "on";
+		} else {
+			if (tElm && tElm.nodeName == "SPAN")
+				tElm = tinyMCE._createIFrame(tElm, targetDoc, targetDoc.parentWindow);
+			else
+				tElm = targetDoc.frames[this.editorId];
+
+			this.targetElement = tElm;
+			this.iframeElement = targetDoc.getElementById(this.editorId);
+
+			if (tinyMCE.isOpera) {
+				this.contentDocument = this.iframeElement.contentDocument;
+				this.contentWindow = this.iframeElement.contentWindow;
+				dynamicIFrame = true;
+			} else {
+				this.contentDocument = tElm.window.document;
+				this.contentWindow = tElm.window;
+			}
+
+			this.getDoc().designMode = "on";
+		}
+
+		// Setup base HTML
+		var doc = this.contentDocument;
+		if (dynamicIFrame) {
+			var html = tinyMCE.getParam('doctype') + '<html><head xmlns="http://www.w3.org/1999/xhtml"><base href="' + tinyMCE.settings['base_href'] + '" /><title>blank_page</title><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></head><body class="mceContentBody"></body></html>';
+
+			try {
+				if (!this.isHidden())
+					this.getDoc().designMode = "on";
+
+				doc.open();
+        //alert('docwrite 3');
+				doc.write(html);
+				doc.close();
+			} catch (e) {
+				// Failed Mozilla 1.3
+				this.getDoc().location.href = tinyMCE.baseURL + "/blank.htm";
+			}
+		}
+
+		// This timeout is needed in MSIE 5.5 for some odd reason
+		// it seems that the document.frames isn't initialized yet?
+		if (tinyMCE.isIE)
+			window.setTimeout("tinyMCE.addEventHandlers(tinyMCE.instances[\"" + this.editorId + "\"]);", 1);
+
+		// Setup element references
+		var parentElm = this.targetDoc.getElementById(this.editorId + '_parent');
+		this.formElement = tinyMCE.isGecko ? parentElm.previousSibling : parentElm.nextSibling;
+
+		tinyMCE.setupContent(this.editorId, true);
+
+		return true;
+	},
+
+	setBaseHREF : function(u) {
+		var h, b, d, nl;
+
+		d = this.getDoc();
+		nl = d.getElementsByTagName("base");
+		b = nl.length > 0 ? nl[0] : null;
+
+		if (!b) {
+			nl = d.getElementsByTagName("head");
+			h = nl.length > 0 ? nl[0] : null;
+
+			b = d.createElement("base");
+			b.setAttribute('href', u);
+			h.appendChild(b);
+		} else {
+			if (u == "" || u == null)
+				b.parentNode.removeChild(b);
+			else
+				b.setAttribute('href', u);
+		}
+	},
+
+	getHTML : function(r) {
+		var h, d = this.getDoc(), b = this.getBody();
+
+		if (r)
+			return b.innerHTML;
+
+		h = tinyMCE._cleanupHTML(this, d, this.settings, b, false, true, false, true);
+
+		if (tinyMCE.getParam("convert_fonts_to_spans"))
+			tinyMCE.convertSpansToFonts(d);
+
+		return h;
+	},
+
+	setHTML : function(h) {
+		this.execCommand('mceSetContent', false, h);
+		this.repaint();
+	},
+
+	getFocusElement : function() {
+		return this.selection.getFocusElement();
+	},
+
+	getSel : function() {
+		return this.selection.getSel();
+	},
+
+	getRng : function() {
+		return this.selection.getRng();
+	},
+
+	triggerSave : function(skip_cleanup, skip_callback) {
+		var e, nl = [], i, s;
+
+		this.switchSettings();
+		s = tinyMCE.settings;
+
+		// Force hidden tabs visible while serializing
+		if (tinyMCE.isRealIE) {
+			e = this.iframeElement;
+
+			do {
+				if (e.style && e.style.display == 'none') {
+					e.style.display = 'block';
+					nl[nl.length] = {elm : e, type : 'style'};
+				}
+
+				if (e.style && s.hidden_tab_class.length > 0 && e.className.indexOf(s.hidden_tab_class) != -1) {
+					e.className = s.display_tab_class;
+					nl[nl.length] = {elm : e, type : 'class'};
+				}
+			} while ((e = e.parentNode) != null)
+		}
+
+		tinyMCE.settings['preformatted'] = false;
+
+		// Default to false
+		if (typeof(skip_cleanup) == "undefined")
+			skip_cleanup = false;
+
+		// Default to false
+		if (typeof(skip_callback) == "undefined")
+			skip_callback = false;
+
+		tinyMCE._setHTML(this.getDoc(), this.getBody().innerHTML);
+
+		// Remove visual aids when cleanup is disabled
+		if (this.settings['cleanup'] == false) {
+			tinyMCE.handleVisualAid(this.getBody(), true, false, this);
+			tinyMCE._setEventsEnabled(this.getBody(), true);
+		}
+
+		tinyMCE._customCleanup(this, "submit_content_dom", this.contentWindow.document.body);
+		var htm = skip_cleanup ? this.getBody().innerHTML : tinyMCE._cleanupHTML(this, this.getDoc(), this.settings, this.getBody(), tinyMCE.visualAid, true, true);
+		htm = tinyMCE._customCleanup(this, "submit_content", htm);
+
+		if (!skip_callback && tinyMCE.settings['save_callback'] != "")
+			var content = eval(tinyMCE.settings['save_callback'] + "(this.formTargetElementId,htm,this.getBody());");
+
+		// Use callback content if available
+		if ((typeof(content) != "undefined") && content != null)
+			htm = content;
+
+		// Replace some weird entities (Bug: #1056343)
+		htm = tinyMCE.regexpReplace(htm, "&#40;", "(", "gi");
+		htm = tinyMCE.regexpReplace(htm, "&#41;", ")", "gi");
+		htm = tinyMCE.regexpReplace(htm, "&#59;", ";", "gi");
+		htm = tinyMCE.regexpReplace(htm, "&#34;", "&quot;", "gi");
+		htm = tinyMCE.regexpReplace(htm, "&#94;", "^", "gi");
+
+		if (this.formElement)
+			this.formElement.value = htm;
+
+		if (tinyMCE.isSafari && this.formElement)
+			this.formElement.innerText = htm;
+
+		// Hide them again (tabs in MSIE)
+		for (i=0; i<nl.length; i++) {
+			if (nl[i].type == 'style')
+				nl[i].elm.style.display = 'none';
+			else
+				nl[i].elm.className = s.hidden_tab_class;
+		}
+	}
+
+	};
+
+/* file:jscripts/tiny_mce/classes/TinyMCE_Cleanup.class.js */
+
+TinyMCE_Engine.prototype.cleanupHTMLCode = function(s) {
+	s = s.replace(new RegExp('<p \\/>', 'gi'), '<p>&nbsp;</p>');
+	s = s.replace(new RegExp('<p>\\s*<\\/p>', 'gi'), '<p>&nbsp;</p>');
+
+	// Fix close BR elements
+	s = s.replace(new RegExp('<br>\\s*<\\/br>', 'gi'), '<br />');
+
+	// Open closed tags like <b/> to <b></b>
+	s = s.replace(new RegExp('<(h[1-6]|p|div|address|pre|form|table|li|ol|ul|td|b|font|em|strong|i|strike|u|span|a|ul|ol|li|blockquote)([a-z]*)([^\\\\|>]*)\\/>', 'gi'), '<$1$2$3></$1$2>');
+
+	// Remove trailing space <b > to <b>
+	s = s.replace(new RegExp('\\s+></', 'gi'), '></');
+
+	// Close tags <img></img> to <img/>
+	s = s.replace(new RegExp('<(img|br|hr)([^>]*)><\\/(img|br|hr)>', 'gi'), '<$1$2 />');
+
+	// Weird MSIE bug, <p><hr /></p> breaks runtime?
+	if (tinyMCE.isIE)
+		s = s.replace(new RegExp('<p><hr \\/><\\/p>', 'gi'), "<hr>");
+
+	// Weird tags will make IE error #bug: 1538495
+	if (tinyMCE.isIE)
+		s = s.replace(/<!(\s*)\/>/g, '');
+
+	// Convert relative anchors to absolute URLs ex: #something to file.htm#something
+	// Removed: Since local document anchors should never be forced absolute example edit.php?id=something
+	//if (tinyMCE.getParam('convert_urls'))
+	//	s = s.replace(new RegExp('(href=\"{0,1})(\\s*#)', 'gi'), '$1' + tinyMCE.settings['document_base_url'] + "#");
+
+	return s;
+};
+
+TinyMCE_Engine.prototype.parseStyle = function(str) {
+	var ar = new Array();
+
+	if (str == null)
+		return ar;
+
+	var st = str.split(';');
+
+	tinyMCE.clearArray(ar);
+
+	for (var i=0; i<st.length; i++) {
+		if (st[i] == '')
+			continue;
+
+		var re = new RegExp('^\\s*([^:]*):\\s*(.*)\\s*$');
+		var pa = st[i].replace(re, '$1||$2').split('||');
+//tinyMCE.debug(str, pa[0] + "=" + pa[1], st[i].replace(re, '$1||$2'));
+		if (pa.length == 2)
+			ar[pa[0].toLowerCase()] = pa[1];
+	}
+
+	return ar;
+};
+
+TinyMCE_Engine.prototype.compressStyle = function(ar, pr, sf, res) {
+	var box = new Array();
+
+	box[0] = ar[pr + '-top' + sf];
+	box[1] = ar[pr + '-left' + sf];
+	box[2] = ar[pr + '-right' + sf];
+	box[3] = ar[pr + '-bottom' + sf];
+
+	for (var i=0; i<box.length; i++) {
+		if (box[i] == null)
+			return;
+
+		for (var a=0; a<box.length; a++) {
+			if (box[a] != box[i])
+				return;
+		}
+	}
+
+	// They are all the same
+	ar[res] = box[0];
+	ar[pr + '-top' + sf] = null;
+	ar[pr + '-left' + sf] = null;
+	ar[pr + '-right' + sf] = null;
+	ar[pr + '-bottom' + sf] = null;
+};
+
+TinyMCE_Engine.prototype.serializeStyle = function(ar) {
+	var str = "";
+
+	// Compress box
+	tinyMCE.compressStyle(ar, "border", "", "border");
+	tinyMCE.compressStyle(ar, "border", "-width", "border-width");
+	tinyMCE.compressStyle(ar, "border", "-color", "border-color");
+	tinyMCE.compressStyle(ar, "border", "-style", "border-style");
+	tinyMCE.compressStyle(ar, "padding", "", "padding");
+	tinyMCE.compressStyle(ar, "margin", "", "margin");
+
+	for (var key in ar) {
+		var val = ar[key];
+
+		if (typeof(val) == 'function')
+			continue;
+
+		if (key.indexOf('mso-') == 0)
+			continue;
+
+		if (val != null && val != '') {
+			val = '' + val; // Force string
+
+			// Fix style URL
+			val = val.replace(new RegExp("url\\(\\'?([^\\']*)\\'?\\)", 'gi'), "url('$1')");
+
+			// Convert URL
+			if (val.indexOf('url(') != -1 && tinyMCE.getParam('convert_urls')) {
+				var m = new RegExp("url\\('(.*?)'\\)").exec(val);
+
+				if (m.length > 1)
+					val = "url('" + eval(tinyMCE.getParam('urlconverter_callback') + "(m[1], null, true);") + "')";
+			}
+
+			// Force HEX colors
+			if (tinyMCE.getParam("force_hex_style_colors"))
+				val = tinyMCE.convertRGBToHex(val, true);
+
+			val = val.replace(/\"/g, '\'');
+
+			if (val != "url('')")
+				str += key.toLowerCase() + ": " + val + "; ";
+		}
+	}
+
+	if (new RegExp('; $').test(str))
+		str = str.substring(0, str.length - 2);
+
+	return str;
+};
+
+TinyMCE_Engine.prototype.convertRGBToHex = function(s, k) {
+	if (s.toLowerCase().indexOf('rgb') != -1) {
+		var re = new RegExp("(.*?)rgb\\s*?\\(\\s*?([0-9]+).*?,\\s*?([0-9]+).*?,\\s*?([0-9]+).*?\\)(.*?)", "gi");
+		var rgb = s.replace(re, "$1,$2,$3,$4,$5").split(',');
+		if (rgb.length == 5) {
+			r = parseInt(rgb[1]).toString(16);
+			g = parseInt(rgb[2]).toString(16);
+			b = parseInt(rgb[3]).toString(16);
+
+			r = r.length == 1 ? '0' + r : r;
+			g = g.length == 1 ? '0' + g : g;
+			b = b.length == 1 ? '0' + b : b;
+
+			s = "#" + r + g + b;
+
+			if (k)
+				s = rgb[0] + s + rgb[4];
+		}
+	}
+
+	return s;
+};
+
+TinyMCE_Engine.prototype.convertHexToRGB = function(s) {
+	if (s.indexOf('#') != -1) {
+		s = s.replace(new RegExp('[^0-9A-F]', 'gi'), '');
+		return "rgb(" + parseInt(s.substring(0, 2), 16) + "," + parseInt(s.substring(2, 4), 16) + "," + parseInt(s.substring(4, 6), 16) + ")";
+	}
+
+	return s;
+};
+
+TinyMCE_Engine.prototype.convertSpansToFonts = function(doc) {
+	var sizes = tinyMCE.getParam('font_size_style_values').replace(/\s+/, '').split(',');
+
+	/*var h = doc.body.innerHTML;
+	h = h.replace(/<span/gi, '<font');
+	h = h.replace(/<\/span/gi, '</font');
+	tinyMCE.setInnerHTML(doc.body, h);*/
+
+	var s = tinyMCE.selectElements(doc, 'span,font');
+	for (var i=0; i<s.length; i++) {
+		var size = tinyMCE.trim(s[i].style.fontSize).toLowerCase();
+		var fSize = 0;
+
+		for (var x=0; x<sizes.length; x++) {
+			if (sizes[x] == size) {
+				fSize = x + 1;
+				break;
+			}
+		}
+
+		if (fSize > 0) {
+			tinyMCE.setAttrib(s[i], 'size', fSize);
+			s[i].style.fontSize = '';
+		}
+
+		var fFace = s[i].style.fontFamily;
+		if (fFace != null && fFace != "") {
+			tinyMCE.setAttrib(s[i], 'face', fFace);
+			s[i].style.fontFamily = '';
+		}
+
+		var fColor = s[i].style.color;
+		if (fColor != null && fColor != "") {
+			tinyMCE.setAttrib(s[i], 'color', tinyMCE.convertRGBToHex(fColor));
+			s[i].style.color = '';
+		}
+	}
+};
+
+TinyMCE_Engine.prototype.convertFontsToSpans = function(doc) {
+	var sizes = tinyMCE.getParam('font_size_style_values').replace(/\s+/, '').split(',');
+
+/*	var h = doc.body.innerHTML;
+	h = h.replace(/<font/gi, '<span');
+	h = h.replace(/<\/font/gi, '</span');
+	tinyMCE.setInnerHTML(doc.body, h);*/
+
+	var fsClasses = tinyMCE.getParam('font_size_classes');
+	if (fsClasses != '')
+		fsClasses = fsClasses.replace(/\s+/, '').split(',');
+	else
+		fsClasses = null;
+
+	var s = tinyMCE.selectElements(doc, 'span,font');
+	for (var i=0; i<s.length; i++) {
+		var fSize, fFace, fColor;
+
+		fSize = tinyMCE.getAttrib(s[i], 'size');
+		fFace = tinyMCE.getAttrib(s[i], 'face');
+		fColor = tinyMCE.getAttrib(s[i], 'color');
+
+		if (fSize != "") {
+			fSize = parseInt(fSize);
+
+			if (fSize > 0 && fSize < 8) {
+				if (fsClasses != null)
+					tinyMCE.setAttrib(s[i], 'class', fsClasses[fSize-1]);
+				else
+					s[i].style.fontSize = sizes[fSize-1];
+			}
+
+			s[i].removeAttribute('size');
+		}
+
+		if (fFace != "") {
+			s[i].style.fontFamily = fFace;
+			s[i].removeAttribute('face');
+		}
+
+		if (fColor != "") {
+			s[i].style.color = fColor;
+			s[i].removeAttribute('color');
+		}
+	}
+};
+
+TinyMCE_Engine.prototype.cleanupAnchors = function(doc) {
+	var i, cn, x, an = doc.getElementsByTagName("a");
+
+	// Loops backwards due to bug #1467987
+	for (i=an.length-1; i>=0; i--) {
+		if (tinyMCE.getAttrib(an[i], "name") != "" && tinyMCE.getAttrib(an[i], "href") == "") {
+			cn = an[i].childNodes;
+
+			for (x=cn.length-1; x>=0; x--)
+				tinyMCE.insertAfter(cn[x], an[i]);
+		}
+	}
+};
+
+TinyMCE_Engine.prototype.getContent = function(editor_id) {
+	if (typeof(editor_id) != "undefined")
+		 tinyMCE.getInstanceById(editor_id).select();
+
+	if (tinyMCE.selectedInstance)
+		return tinyMCE.selectedInstance.getHTML();
+
+	return null;
+};
+
+TinyMCE_Engine.prototype._fixListElements = function(d) {
+	var nl, x, a = ['ol', 'ul'], i, n, p, r = new RegExp('^(OL|UL)$'), np;
+
+	for (x=0; x<a.length; x++) {
+		nl = d.getElementsByTagName(a[x]);
+
+		for (i=0; i<nl.length; i++) {
+			n = nl[i];
+			p = n.parentNode;
+
+			if (r.test(p.nodeName)) {
+				np = tinyMCE.prevNode(n, 'LI');
+
+				if (!np) {
+					np = d.createElement('li');
+					np.innerHTML = '&nbsp;';
+					np.appendChild(n);
+					p.insertBefore(np, p.firstChild);
+				} else
+					np.appendChild(n);
+			}
+		}
+	}
+};
+
+TinyMCE_Engine.prototype._fixTables = function(d) {
+	var nl, i, n, p, np, x, t;
+
+	nl = d.getElementsByTagName('table');
+	for (i=0; i<nl.length; i++) {
+		n = nl[i];
+
+		if ((p = tinyMCE.getParentElement(n, 'p,h1,h2,h3,h4,h5,h6')) != null) {
+			np = p.cloneNode(false);
+			np.removeAttribute('id');
+
+			t = n;
+
+			while ((n = n.nextSibling))
+				np.appendChild(n);
+
+			tinyMCE.insertAfter(np, p);
+			tinyMCE.insertAfter(t, p);
+		}
+	}
+};
+
+TinyMCE_Engine.prototype._cleanupHTML = function(inst, doc, config, elm, visual, on_save, on_submit, inn) {
+	var h, d, t1, t2, t3, t4, t5, c, s, nb;
+
+	if (!tinyMCE.getParam('cleanup'))
+		return elm.innerHTML;
+
+	on_save = typeof(on_save) == 'undefined' ? false : on_save;
+
+	c = inst.cleanup;
+	s = inst.settings;
+	d = c.settings.debug;
+
+	if (d)
+		t1 = new Date().getTime();
+
+	if (tinyMCE.getParam("convert_fonts_to_spans"))
+		tinyMCE.convertFontsToSpans(doc);
+
+	if (tinyMCE.getParam("fix_list_elements"))
+		tinyMCE._fixListElements(doc);
+
+	if (tinyMCE.getParam("fix_table_elements"))
+		tinyMCE._fixTables(doc);
+
+	// Call custom cleanup code
+	tinyMCE._customCleanup(inst, on_save ? "get_from_editor_dom" : "insert_to_editor_dom", doc.body);
+
+	if (d)
+		t2 = new Date().getTime();
+
+	c.settings.on_save = on_save;
+	//for (var i=0; i<100; i++)
+
+	c.idCount = 0;
+	c.serializationId++;
+	c.serializedNodes = new Array();
+	c.sourceIndex = -1;
+
+	if (s.cleanup_serializer == "xml")
+		h = c.serializeNodeAsXML(elm, inn);
+	else
+		h = c.serializeNodeAsHTML(elm, inn);
+
+	if (d)
+		t3 = new Date().getTime();
+
+	// Post processing
+	nb = tinyMCE.getParam('entity_encoding') == 'numeric' ? '&#160;' : '&nbsp;';
+	h = h.replace(/<\/?(body|head|html)[^>]*>/gi, '');
+	h = h.replace(new RegExp(' (rowspan="1"|colspan="1")', 'g'), '');
+	h = h.replace(/<p><hr \/><\/p>/g, '<hr />');
+	h = h.replace(/<p>(&nbsp;|&#160;)<\/p><hr \/><p>(&nbsp;|&#160;)<\/p>/g, '<hr />');
+	h = h.replace(/<td>\s*<br \/>\s*<\/td>/g, '<td>' + nb + '</td>');
+	h = h.replace(/<p>\s*<br \/>\s*<\/p>/g, '<p>' + nb + '</p>');
+	h = h.replace(/<br \/>$/, ''); // Remove last BR for Gecko
+	h = h.replace(/<br \/><\/p>/g, '</p>'); // Remove last BR in P tags for Gecko
+	h = h.replace(/<p>\s*(&nbsp;|&#160;)\s*<br \/>\s*(&nbsp;|&#160;)\s*<\/p>/g, '<p>' + nb + '</p>');
+	h = h.replace(/<p>\s*(&nbsp;|&#160;)\s*<br \/>\s*<\/p>/g, '<p>' + nb + '</p>');
+	h = h.replace(/<p>\s*<br \/>\s*&nbsp;\s*<\/p>/g, '<p>' + nb + '</p>');
+	h = h.replace(new RegExp('<a>(.*?)<\\/a>', 'g'), '$1');
+	h = h.replace(/<p([^>]*)>\s*<\/p>/g, '<p$1>' + nb + '</p>');
+
+	// Clean body
+	if (/^\s*(<br \/>|<p>&nbsp;<\/p>|<p>&#160;<\/p>|<p><\/p>)\s*$/.test(h))
+		h = '';
+
+	// If preformatted
+	if (s.preformatted) {
+		h = h.replace(/^<pre>/, '');
+		h = h.replace(/<\/pre>$/, '');
+		h = '<pre>' + h + '</pre>';
+	}
+
+	// Gecko specific processing
+	if (tinyMCE.isGecko) {
+		h = h.replace(/<o:p _moz-userdefined="" \/>/g, '');
+		h = h.replace(/<td([^>]*)>\s*<br \/>\s*<\/td>/g, '<td$1>' + nb + '</td>');
+	}
+
+	if (s.force_br_newlines)
+		h = h.replace(/<p>(&nbsp;|&#160;)<\/p>/g, '<br />');
+
+	// Call custom cleanup code
+	h = tinyMCE._customCleanup(inst, on_save ? "get_from_editor" : "insert_to_editor", h);
+
+	// Remove internal classes
+	if (on_save) {
+		h = h.replace(new RegExp(' ?(mceItem[a-zA-Z0-9]*|' + s.visual_table_class + ')', 'g'), '');
+		h = h.replace(new RegExp(' ?class=""', 'g'), '');
+	}
+
+	if (s.remove_linebreaks && !c.settings.indent)
+		h = h.replace(/\n|\r/g, ' ');
+
+	if (d)
+		t4 = new Date().getTime();
+
+	if (on_save && c.settings.indent)
+		h = c.formatHTML(h);
+
+	// If encoding (not recommended option)
+	if (on_submit && (s.encoding == "xml" || s.encoding == "html"))
+		h = c.xmlEncode(h);
+
+	if (d)
+		t5 = new Date().getTime();
+
+	if (c.settings.debug)
+		tinyMCE.debug("Cleanup in ms: Pre=" + (t2-t1) + ", Serialize: " + (t3-t2) + ", Post: " + (t4-t3) + ", Format: " + (t5-t4) + ", Sum: " + (t5-t1) + ".");
+
+	return h;
+};
+
+function TinyMCE_Cleanup() {
+	this.isIE = (navigator.appName == "Microsoft Internet Explorer");
+	this.rules = tinyMCE.clearArray(new Array());
+
+	// Default config
+	this.settings = {
+		indent_elements : 'head,table,tbody,thead,tfoot,form,tr,ul,ol,blockquote,object',
+		newline_before_elements : 'h1,h2,h3,h4,h5,h6,pre,address,div,ul,ol,li,meta,option,area,title,link,base,script,td',
+		newline_after_elements : 'br,hr,p,pre,address,div,ul,ol,meta,option,area,link,base,script',
+		newline_before_after_elements : 'html,head,body,table,thead,tbody,tfoot,tr,form,ul,ol,blockquote,p,object,param,hr,div',
+		indent_char : '\t',
+		indent_levels : 1,
+		entity_encoding : 'raw',
+		valid_elements : '*[*]',
+		entities : '',
+		url_converter : '',
+		invalid_elements : '',
+		verify_html : false
+	};
+
+	this.vElements = tinyMCE.clearArray(new Array());
+	this.vElementsRe = '';
+	this.closeElementsRe = /^(IMG|BR|HR|LINK|META|BASE|INPUT|AREA)$/;
+	this.codeElementsRe = /^(SCRIPT|STYLE)$/;
+	this.serializationId = 0;
+	this.mceAttribs = {
+		href : 'mce_href',
+		src : 'mce_src',
+		type : 'mce_type'
+	};
+}
+
+TinyMCE_Cleanup.prototype = {
+	init : function(s) {
+		var n, a, i, ir, or, st;
+
+		for (n in s)
+			this.settings[n] = s[n];
+
+		// Setup code formating
+		s = this.settings;
+
+		// Setup regexps
+		this.inRe = this._arrayToRe(s.indent_elements.split(','), '', '^<(', ')[^>]*');
+		this.ouRe = this._arrayToRe(s.indent_elements.split(','), '', '^<\\/(', ')[^>]*');
+		this.nlBeforeRe = this._arrayToRe(s.newline_before_elements.split(','), 'gi', '<(',  ')([^>]*)>');
+		this.nlAfterRe = this._arrayToRe(s.newline_after_elements.split(','), 'gi', '<(',  ')([^>]*)>');
+		this.nlBeforeAfterRe = this._arrayToRe(s.newline_before_after_elements.split(','), 'gi', '<(\\/?)(', ')([^>]*)>');
+		this.serializedNodes = [];
+
+		if (s.invalid_elements != '')
+			this.iveRe = this._arrayToRe(s.invalid_elements.toUpperCase().split(','), 'g', '^(', ')$');
+		else
+			this.iveRe = null;
+
+		// Setup separator
+		st = '';
+		for (i=0; i<s.indent_levels; i++)
+			st += s.indent_char;
+
+		this.inStr = st;
+
+		// If verify_html if false force *[*]
+		if (!s.verify_html) {
+			s.valid_elements = '*[*]';
+			s.extended_valid_elements = '';
+		}
+
+		this.fillStr = s.entity_encoding == "named" ? "&nbsp;" : "&#160;";
+		this.idCount = 0;
+		this.xmlEncodeRe = new RegExp('[\u007F-\uFFFF<>&"]', 'g');
+		this.xmlEncodeAposRe = new RegExp('[\u007F-\uFFFF<>&"\']', 'g');
+	},
+
+	addRuleStr : function(s) {
+		var r = this.parseRuleStr(s);
+		var n;
+
+		for (n in r) {
+			if (r[n])
+				this.rules[n] = r[n];
+		}
+
+		this.vElements = tinyMCE.clearArray(new Array());
+
+		for (n in this.rules) {
+			if (this.rules[n])
+				this.vElements[this.vElements.length] = this.rules[n].tag;
+		}
+
+		this.vElementsRe = this._arrayToRe(this.vElements, '');
+	},
+
+	isValid : function(n) {
+		this._setupRules(); // Will initialize cleanup rules
+
+		// Empty is true since it removes formatting
+		if (!n)
+			return true;
+
+		// Clean the name up a bit
+		n = n.replace(/[^a-z0-9]+/gi, '').toUpperCase();
+
+		return !tinyMCE.getParam('cleanup') || this.vElementsRe.test(n);
+	},
+
+	addChildRemoveRuleStr : function(s) {
+		var x, y, p, i, t, tn, ta, cl, r;
+
+		if (!s)
+			return;
+
+		ta = s.split(',');
+		for (x=0; x<ta.length; x++) {
+			s = ta[x];
+
+			// Split tag/children
+			p = this.split(/\[|\]/, s);
+			if (p == null || p.length < 1)
+				t = s.toUpperCase();
+			else
+				t = p[0].toUpperCase();
+
+			// Handle all tag names
+			tn = this.split('/', t);
+			for (y=0; y<tn.length; y++) {
+				r = "^(";
+
+				// Build regex
+				cl = this.split(/\|/, p[1]);
+				for (i=0; i<cl.length; i++) {
+					if (cl[i] == '%istrict')
+						r += tinyMCE.inlineStrict;
+					else if (cl[i] == '%itrans')
+						r += tinyMCE.inlineTransitional;
+					else if (cl[i] == '%istrict_na')
+						r += tinyMCE.inlineStrict.substring(2);
+					else if (cl[i] == '%itrans_na')
+						r += tinyMCE.inlineTransitional.substring(2);
+					else if (cl[i] == '%btrans')
+						r += tinyMCE.blockElms;
+					else if (cl[i] == '%strict')
+						r += tinyMCE.blockStrict;
+					else
+						r += (cl[i].charAt(0) != '#' ? cl[i].toUpperCase() : cl[i]);
+
+					r += (i != cl.length - 1 ? '|' : '');
+				}
+
+				r += ')$';
+//tinyMCE.debug(t + "=" + r);
+				if (this.childRules == null)
+					this.childRules = tinyMCE.clearArray(new Array());
+
+				this.childRules[tn[y]] = new RegExp(r);
+
+				if (p.length > 1)
+					this.childRules[tn[y]].wrapTag = p[2];
+			}
+		}
+	},
+
+	parseRuleStr : function(s) {
+		var ta, p, r, a, i, x, px, t, tn, y, av, or = tinyMCE.clearArray(new Array()), dv;
+
+		if (s == null || s.length == 0)
+			return or;
+
+		ta = s.split(',');
+		for (x=0; x<ta.length; x++) {
+			s = ta[x];
+			if (s.length == 0)
+				continue;
+
+			// Split tag/attrs
+			p = this.split(/\[|\]/, s);
+			if (p == null || p.length < 1)
+				t = s.toUpperCase();
+			else
+				t = p[0].toUpperCase();
+
+			// Handle all tag names
+			tn = this.split('/', t);
+			for (y=0; y<tn.length; y++) {
+				r = {};
+
+				r.tag = tn[y];
+				r.forceAttribs = null;
+				r.defaultAttribs = null;
+				r.validAttribValues = null;
+
+				// Handle prefixes
+				px = r.tag.charAt(0);
+				r.forceOpen = px == '+';
+				r.removeEmpty = px == '-';
+				r.fill = px == '#';
+				r.tag = r.tag.replace(/\+|-|#/g, '');
+				r.oTagName = tn[0].replace(/\+|-|#/g, '').toLowerCase();
+				r.isWild = new RegExp('\\*|\\?|\\+', 'g').test(r.tag);
+				r.validRe = new RegExp(this._wildcardToRe('^' + r.tag + '$'));
+
+				// Setup valid attributes
+				if (p.length > 1) {
+					r.vAttribsRe = '^(';
+					a = this.split(/\|/, p[1]);
+
+					for (i=0; i<a.length; i++) {
+						t = a[i];
+
+						if (t.charAt(0) == '!') {
+							a[i] = t = t.substring(1);
+
+							if (!r.reqAttribsRe)
+								r.reqAttribsRe = '\\s+(' + t;
+							else
+								r.reqAttribsRe += '|' + t;
+						}
+
+						av = new RegExp('(=|:|<)(.*?)$').exec(t);
+						t = t.replace(new RegExp('(=|:|<).*?$'), '');
+						if (av && av.length > 0) {
+							if (av[0].charAt(0) == ':') {
+								if (!r.forceAttribs)
+									r.forceAttribs = tinyMCE.clearArray(new Array());
+
+								r.forceAttribs[t.toLowerCase()] = av[0].substring(1);
+							} else if (av[0].charAt(0) == '=') {
+								if (!r.defaultAttribs)
+									r.defaultAttribs = tinyMCE.clearArray(new Array());
+
+								dv = av[0].substring(1);
+
+								r.defaultAttribs[t.toLowerCase()] = dv == "" ? "mce_empty" : dv;
+							} else if (av[0].charAt(0) == '<') {
+								if (!r.validAttribValues)
+									r.validAttribValues = tinyMCE.clearArray(new Array());
+
+								r.validAttribValues[t.toLowerCase()] = this._arrayToRe(this.split('?', av[0].substring(1)), 'i');
+							}
+						}
+
+						r.vAttribsRe += '' + t.toLowerCase() + (i != a.length - 1 ? '|' : '');
+
+						a[i] = t.toLowerCase();
+					}
+
+					if (r.reqAttribsRe)
+						r.reqAttribsRe = new RegExp(r.reqAttribsRe + ')=\"', 'g');
+
+					r.vAttribsRe += ')$';
+					r.vAttribsRe = this._wildcardToRe(r.vAttribsRe);
+					r.vAttribsReIsWild = new RegExp('\\*|\\?|\\+', 'g').test(r.vAttribsRe);
+					r.vAttribsRe = new RegExp(r.vAttribsRe);
+					r.vAttribs = a.reverse();
+
+					//tinyMCE.debug(r.tag, r.oTagName, r.vAttribsRe, r.vAttribsReWC);
+				} else {
+					r.vAttribsRe = '';
+					r.vAttribs = tinyMCE.clearArray(new Array());
+					r.vAttribsReIsWild = false;
+				}
+
+				or[r.tag] = r;
+			}
+		}
+
+		return or;
+	},
+
+	serializeNodeAsXML : function(n) {
+		var s, b;
+
+		if (!this.xmlDoc) {
+			if (this.isIE) {
+				try {this.xmlDoc = new ActiveXObject('MSXML2.DOMDocument');} catch (e) {}
+
+				if (!this.xmlDoc)
+					try {this.xmlDoc = new ActiveXObject('Microsoft.XmlDom');} catch (e) {}
+			} else
+				this.xmlDoc = document.implementation.createDocument('', '', null);
+
+			if (!this.xmlDoc)
+				alert("Error XML Parser could not be found.");
+		}
+
+		if (this.xmlDoc.firstChild)
+			this.xmlDoc.removeChild(this.xmlDoc.firstChild);
+
+		b = this.xmlDoc.createElement("html");
+		b = this.xmlDoc.appendChild(b);
+
+		this._convertToXML(n, b);
+
+		if (this.isIE)
+			return this.xmlDoc.xml;
+		else
+			return new XMLSerializer().serializeToString(this.xmlDoc);
+	},
+
+	_convertToXML : function(n, xn) {
+		var xd, el, i, l, cn, at, no, hc = false;
+
+		if (tinyMCE.isRealIE && this._isDuplicate(n))
+			return;
+
+		xd = this.xmlDoc;
+
+		switch (n.nodeType) {
+			case 1: // Element
+				hc = n.hasChildNodes();
+
+				el = xd.createElement(n.nodeName.toLowerCase());
+
+				at = n.attributes;
+				for (i=at.length-1; i>-1; i--) {
+					no = at[i];
+
+					if (no.specified && no.nodeValue)
+						el.setAttribute(no.nodeName.toLowerCase(), no.nodeValue);
+				}
+
+				if (!hc && !this.closeElementsRe.test(n.nodeName))
+					el.appendChild(xd.createTextNode(""));
+
+				xn = xn.appendChild(el);
+				break;
+
+			case 3: // Text
+				xn.appendChild(xd.createTextNode(n.nodeValue));
+				return;
+
+			case 8: // Comment
+				xn.appendChild(xd.createComment(n.nodeValue));
+				return;
+		}
+
+		if (hc) {
+			cn = n.childNodes;
+
+			for (i=0, l=cn.length; i<l; i++)
+				this._convertToXML(cn[i], xn);
+		}
+	},
+
+	serializeNodeAsHTML : function(n, inn) {
+		var en, no, h = '', i, l, t, st, r, cn, va = false, f = false, at, hc, cr, nn;
+
+		this._setupRules(); // Will initialize cleanup rules
+
+		if (tinyMCE.isRealIE && this._isDuplicate(n))
+			return '';
+
+		// Skip non valid child elements
+		if (n.parentNode && this.childRules != null) {
+			cr = this.childRules[n.parentNode.nodeName];
+
+			if (typeof(cr) != "undefined" && !cr.test(n.nodeName)) {
+				st = true;
+				t = null;
+			}
+		}
+
+		switch (n.nodeType) {
+			case 1: // Element
+				hc = n.hasChildNodes();
+
+				if (st)
+					break;
+
+				// MSIE sometimes produces <//tag>
+				if ((tinyMCE.isRealIE) && n.nodeName.indexOf('/') != -1)
+					break;
+
+				nn = n.nodeName;
+
+				// Convert fonts to spans
+				if (this.settings.convert_fonts_to_spans) {
+					// On get content FONT -> SPAN
+					if (this.settings.on_save && nn == 'FONT')
+						nn = 'SPAN';
+
+					// On insert content SPAN -> FONT
+					if (!this.settings.on_save && nn == 'SPAN')
+						nn = 'FONT';
+				}
+
+				if (this.vElementsRe.test(nn) && (!this.iveRe || !this.iveRe.test(nn)) && !inn) {
+					va = true;
+
+					r = this.rules[nn];
+					if (!r) {
+						at = this.rules;
+						for (no in at) {
+							if (at[no] && at[no].validRe.test(nn)) {
+								r = at[no];
+								break;
+							}
+						}
+					}
+
+					en = r.isWild ? nn.toLowerCase() : r.oTagName;
+					f = r.fill;
+
+					if (r.removeEmpty && !hc)
+						return "";
+
+					t = '<' + en;
+
+					if (r.vAttribsReIsWild) {
+						// Serialize wildcard attributes
+						at = n.attributes;
+						for (i=at.length-1; i>-1; i--) {
+							no = at[i];
+							if (no.specified && r.vAttribsRe.test(no.nodeName))
+								t += this._serializeAttribute(n, r, no.nodeName);
+						}
+					} else {
+						// Serialize specific attributes
+						for (i=r.vAttribs.length-1; i>-1; i--)
+							t += this._serializeAttribute(n, r, r.vAttribs[i]);
+					}
+
+					// Serialize mce_ atts
+					if (!this.settings.on_save) {
+						at = this.mceAttribs;
+
+						for (no in at) {
+							if (at[no])
+								t += this._serializeAttribute(n, r, at[no]);
+						}
+					}
+
+					// Check for required attribs
+					if (r.reqAttribsRe && !t.match(r.reqAttribsRe))
+						t = null;
+
+					// Close these
+					if (t != null && this.closeElementsRe.test(nn))
+						return t + ' />';
+
+					if (t != null)
+						h += t + '>';
+
+					if (this.isIE && this.codeElementsRe.test(nn))
+						h += n.innerHTML;
+				}
+			break;
+
+			case 3: // Text
+				if (st)
+					break;
+
+				if (n.parentNode && this.codeElementsRe.test(n.parentNode.nodeName))
+					return this.isIE ? '' : n.nodeValue;
+
+				return this.xmlEncode(n.nodeValue);
+
+			case 8: // Comment
+				if (st)
+					break;
+
+				return "<!--" + this._trimComment(n.nodeValue) + "-->";
+		}
+
+		if (hc) {
+			cn = n.childNodes;
+
+			for (i=0, l=cn.length; i<l; i++)
+				h += this.serializeNodeAsHTML(cn[i]);
+		}
+
+		// Fill empty nodes
+		if (f && !hc)
+			h += this.fillStr;
+
+		// End element
+		if (t != null && va)
+			h += '</' + en + '>';
+
+		return h;
+	},
+
+	_serializeAttribute : function(n, r, an) {
+		var av = '', t, os = this.settings.on_save;
+
+		if (os && (an.indexOf('mce_') == 0 || an.indexOf('_moz') == 0))
+			return '';
+
+		if (os && this.mceAttribs[an])
+			av = this._getAttrib(n, this.mceAttribs[an]);
+
+		if (av.length == 0)
+			av = this._getAttrib(n, an);
+
+		if (av.length == 0 && r.defaultAttribs && (t = r.defaultAttribs[an])) {
+			av = t;
+
+			if (av == "mce_empty")
+				return " " + an + '=""';
+		}
+
+		if (r.forceAttribs && (t = r.forceAttribs[an]))
+			av = t;
+
+		if (os && av.length != 0 && /^(src|href|longdesc)$/.test(an))
+			av = this._urlConverter(this, n, av);
+
+		if (av.length != 0 && r.validAttribValues && r.validAttribValues[an] && !r.validAttribValues[an].test(av))
+			return "";
+
+		if (av.length != 0 && av == "{$uid}")
+			av = "uid_" + (this.idCount++);
+
+		if (av.length != 0) {
+			if (an.indexOf('on') != 0)
+				av = this.xmlEncode(av, 1);
+
+			return " " + an + "=" + '"' + av + '"';
+		}
+
+		return "";
+	},
+
+	formatHTML : function(h) {
+		var s = this.settings, p = '', i = 0, li = 0, o = '', l;
+
+		// Replace BR in pre elements to \n
+		h = h.replace(/<pre([^>]*)>(.*?)<\/pre>/gi, function (a, b, c) {
+			c = c.replace(/<br\s*\/>/gi, '\n');
+			return '<pre' + b + '>' + c + '</pre>';
+		});
+
+		h = h.replace(/\r/g, ''); // Windows sux, isn't carriage return a thing of the past :)
+		h = '\n' + h;
+		h = h.replace(new RegExp('\\n\\s+', 'gi'), '\n'); // Remove previous formatting
+		h = h.replace(this.nlBeforeRe, '\n<$1$2>');
+		h = h.replace(this.nlAfterRe, '<$1$2>\n');
+		h = h.replace(this.nlBeforeAfterRe, '\n<$1$2$3>\n');
+		h += '\n';
+
+		//tinyMCE.debug(h);
+
+		while ((i = h.indexOf('\n', i + 1)) != -1) {
+			if ((l = h.substring(li + 1, i)).length != 0) {
+				if (this.ouRe.test(l) && p.length >= s.indent_levels)
+					p = p.substring(s.indent_levels);
+
+				o += p + l + '\n';
+	
+				if (this.inRe.test(l))
+					p += this.inStr;
+			}
+
+			li = i;
+		}
+
+		//tinyMCE.debug(h);
+
+		return o;
+	},
+
+	xmlEncode : function(s, skip_apos) {
+		var cl = this, re = !skip_apos ? this.xmlEncodeAposRe : this.xmlEncodeRe;
+
+		this._setupEntities(); // Will intialize lookup table
+
+		switch (this.settings.entity_encoding) {
+			case "raw":
+				return tinyMCE.xmlEncode(s, skip_apos);
+
+			case "named":
+				return s.replace(re, function (c, b) {
+					b = cl.entities[c.charCodeAt(0)];
+
+					return b ? '&' + b + ';' : c;
+				});
+
+			case "numeric":
+				return s.replace(re, function (c, b) {
+					return b ? '&#' + c.charCodeAt(0) + ';' : c;
+				});
+		}
+
+		return s;
+	},
+
+	split : function(re, s) {
+		var c = s.split(re);
+		var i, l, o = new Array();
+
+		for (i=0, l=c.length; i<l; i++) {
+			if (c[i] != '')
+				o[i] = c[i];
+		}
+
+		return o;
+	},
+
+	_trimComment : function(s) {
+		// Remove mce_src, mce_href
+		s = s.replace(new RegExp('\\smce_src=\"[^\"]*\"', 'gi'), "");
+		s = s.replace(new RegExp('\\smce_href=\"[^\"]*\"', 'gi'), "");
+
+		return s;
+	},
+
+	_getAttrib : function(e, n, d) {
+		var v, ex, nn;
+
+		if (typeof(d) == "undefined")
+			d = "";
+
+		if (!e || e.nodeType != 1)
+			return d;
+
+		try {
+			v = e.getAttribute(n, 0);
+		} catch (ex) {
+			// IE 7 may cast exception on invalid attributes
+			v = e.getAttribute(n, 2);
+		}
+
+		if (n == "class" && !v)
+			v = e.className;
+
+		if (this.isIE) {
+			if (n == "http-equiv")
+				v = e.httpEquiv;
+
+			nn = e.nodeName;
+
+			// Skip the default values that IE returns
+			if (nn == "FORM" && n == "enctype" && v == "application/x-www-form-urlencoded")
+				v = "";
+
+			if (nn == "INPUT" && n == "size" && v == "20")
+				v = "";
+
+			if (nn == "INPUT" && n == "maxlength" && v == "2147483647")
+				v = "";
+		}
+
+		if (n == 'style' && v) {
+			if (!tinyMCE.isOpera)
+				v = e.style.cssText;
+
+			v = tinyMCE.serializeStyle(tinyMCE.parseStyle(v));
+		}
+
+		if (this.settings.on_save && n.indexOf('on') != -1 && this.settings.on_save && v && v != "")
+			v = tinyMCE.cleanupEventStr(v);
+
+		return (v && v != "") ? '' + v : d;
+	},
+
+	_urlConverter : function(c, n, v) {
+		if (!c.settings.on_save)
+			return tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings.base_href, v);
+		else if (tinyMCE.getParam('convert_urls')) {
+			if (!this.urlConverter)
+				this.urlConverter = eval(tinyMCE.settings.urlconverter_callback);
+
+			return this.urlConverter(v, n, true);
+		}
+
+		return v;
+	},
+
+	_arrayToRe : function(a, op, be, af) {
+		var i, r;
+
+		op = typeof(op) == "undefined" ? "gi" : op;
+		be = typeof(be) == "undefined" ? "^(" : be;
+		af = typeof(af) == "undefined" ? ")$" : af;
+
+		r = be;
+
+		for (i=0; i<a.length; i++)
+			r += this._wildcardToRe(a[i]) + (i != a.length-1 ? "|" : "");
+
+		r += af;
+
+		return new RegExp(r, op);
+	},
+
+	_wildcardToRe : function(s) {
+		s = s.replace(/\?/g, '(\\S?)');
+		s = s.replace(/\+/g, '(\\S+)');
+		s = s.replace(/\*/g, '(\\S*)');
+
+		return s;
+	},
+
+	_setupEntities : function() {
+		var n, a, i, s = this.settings;
+
+		// Setup entities
+		if (!this.entitiesDone) {
+			if (s.entity_encoding == "named") {
+				n = tinyMCE.clearArray(new Array());
+				a = this.split(',', s.entities);
+				for (i=0; i<a.length; i+=2)
+					n[a[i]] = a[i+1];
+
+				this.entities = n;
+			}
+
+			this.entitiesDone = true;
+		}
+	},
+
+	_setupRules : function() {
+		var s = this.settings;
+
+		// Setup default rule
+		if (!this.rulesDone) {
+			this.addRuleStr(s.valid_elements);
+			this.addRuleStr(s.extended_valid_elements);
+			this.addChildRemoveRuleStr(s.valid_child_elements);
+
+			this.rulesDone = true;
+		}
+	},
+
+	_isDuplicate : function(n) {
+		var i;
+
+		if (!this.settings.fix_content_duplication)
+			return false;
+
+		if (tinyMCE.isRealIE && n.nodeType == 1) {
+			// Mark elements
+			if (n.mce_serialized == this.serializationId)
+				return true;
+
+			n.setAttribute('mce_serialized', this.serializationId);
+		} else {
+			// Search lookup table for text nodes  and comments
+			for (i=0; i<this.serializedNodes.length; i++) {
+				if (this.serializedNodes[i] == n)
+					return true;
+			}
+
+			this.serializedNodes[this.serializedNodes.length] = n;
+		}
+
+		return false;
+	}
+
+	};
+
+/* file:jscripts/tiny_mce/classes/TinyMCE_DOMUtils.class.js */
+
+TinyMCE_Engine.prototype.createTagHTML = function(tn, a, h) {
+	var o = '', f = tinyMCE.xmlEncode;
+
+	o = '<' + tn;
+
+	if (a) {
+		for (n in a) {
+			if (typeof(a[n]) != 'function' && a[n] != null)
+				o += ' ' + f(n) + '="' + f('' + a[n]) + '"';
+		}
+	}
+
+	o += !h ? ' />' : '>' + h + '</' + tn + '>';
+
+	return o;
+};
+
+TinyMCE_Engine.prototype.createTag = function(d, tn, a, h) {
+	var o = d.createElement(tn);
+
+	if (a) {
+		for (n in a) {
+			if (typeof(a[n]) != 'function' && a[n] != null)
+				tinyMCE.setAttrib(o, n, a[n]);
+		}
+	}
+
+	if (h)
+		o.innerHTML = h;
+
+	return o;
+};
+
+TinyMCE_Engine.prototype.getElementByAttributeValue = function(n, e, a, v) {
+	return (n = this.getElementsByAttributeValue(n, e, a, v)).length == 0 ? null : n[0];
+};
+
+TinyMCE_Engine.prototype.getElementsByAttributeValue = function(n, e, a, v) {
+	var i, nl = n.getElementsByTagName(e), o = new Array();
+
+	for (i=0; i<nl.length; i++) {
+		if (tinyMCE.getAttrib(nl[i], a).indexOf(v) != -1)
+			o[o.length] = nl[i];
+	}
+
+	return o;
+};
+
+TinyMCE_Engine.prototype.isBlockElement = function(n) {
+	return n != null && n.nodeType == 1 && this.blockRegExp.test(n.nodeName);
+};
+
+TinyMCE_Engine.prototype.getParentBlockElement = function(n, r) {
+	return this.getParentNode(n, function(n) {
+		return tinyMCE.isBlockElement(n);
+	}, r);
+
+	return null;
+};
+
+TinyMCE_Engine.prototype.insertAfter = function(n, r){
+	if (r.nextSibling)
+		r.parentNode.insertBefore(n, r.nextSibling);
+	else
+		r.parentNode.appendChild(n);
+};
+
+TinyMCE_Engine.prototype.setInnerHTML = function(e, h) {
+	var i, nl, n;
+
+	// Convert all strong/em to b/i in Gecko
+	if (tinyMCE.isGecko) {
+		h = h.replace(/<embed([^>]*)>/gi, '<tmpembed$1>');
+		h = h.replace(/<em([^>]*)>/gi, '<i$1>');
+		h = h.replace(/<tmpembed([^>]*)>/gi, '<embed$1>');
+		h = h.replace(/<strong([^>]*)>/gi, '<b$1>');
+		h = h.replace(/<\/strong>/gi, '</b>');
+		h = h.replace(/<\/em>/gi, '</i>');
+	}
+
+	if (tinyMCE.isRealIE) {
+		// Since MSIE handles invalid HTML better that valid XHTML we
+		// need to make some things invalid. <hr /> gets converted to <hr>.
+		h = h.replace(/\s\/>/g, '>');
+
+		// Since MSIE auto generated emtpy P tags some times we must tell it to keep the real ones
+		h = h.replace(/<p([^>]*)>\u00A0?<\/p>/gi, '<p$1 mce_keep="true">&nbsp;</p>'); // Keep empty paragraphs
+		h = h.replace(/<p([^>]*)>\s*&nbsp;\s*<\/p>/gi, '<p$1 mce_keep="true">&nbsp;</p>'); // Keep empty paragraphs
+		h = h.replace(/<p([^>]*)>\s+<\/p>/gi, '<p$1 mce_keep="true">&nbsp;</p>'); // Keep empty paragraphs
+
+		// Remove first comment
+		e.innerHTML = tinyMCE.uniqueTag + h;
+		e.firstChild.removeNode(true);
+
+		// Remove weird auto generated empty paragraphs unless it's supposed to be there
+		nl = e.getElementsByTagName("p");
+		for (i=nl.length-1; i>=0; i--) {
+			n = nl[i];
+
+			if (n.nodeName == 'P' && !n.hasChildNodes() && !n.mce_keep)
+				n.parentNode.removeChild(n);
+		}
+	} else {
+		h = this.fixGeckoBaseHREFBug(1, e, h);
+		e.innerHTML = h;
+		this.fixGeckoBaseHREFBug(2, e, h);
+	}
+};
+
+TinyMCE_Engine.prototype.getOuterHTML = function(e) {
+	if (tinyMCE.isIE)
+		return e.outerHTML;
+
+	var d = e.ownerDocument.createElement("body");
+	d.appendChild(e.cloneNode(true));
+	return d.innerHTML;
+};
+
+TinyMCE_Engine.prototype.setOuterHTML = function(e, h, d) {
+	var d = typeof(d) == "undefined" ? e.ownerDocument : d, i, nl, t;
+
+	if (tinyMCE.isIE && e.nodeType == 1)
+		e.outerHTML = h;
+	else {
+		t = d.createElement("body");
+		t.innerHTML = h;
+
+		for (i=0, nl=t.childNodes; i<nl.length; i++)
+			e.parentNode.insertBefore(nl[i].cloneNode(true), e);
+
+		e.parentNode.removeChild(e);
+	}
+};
+
+TinyMCE_Engine.prototype._getElementById = function(id, d) {
+	var e, i, j, f;
+
+	if (typeof(d) == "undefined")
+		d = document;
+
+	e = d.getElementById(id);
+	if (!e) {
+		f = d.forms;
+
+		for (i=0; i<f.length; i++) {
+			for (j=0; j<f[i].elements.length; j++) {
+				if (f[i].elements[j].name == id) {
+					e = f[i].elements[j];
+					break;
+				}
+			}
+		}
+	}
+
+	return e;
+};
+
+TinyMCE_Engine.prototype.getNodeTree = function(n, na, t, nn) {
+	return this.selectNodes(n, function(n) {
+		return (!t || n.nodeType == t) && (!nn || n.nodeName == nn);
+	}, na ? na : new Array());
+};
+
+TinyMCE_Engine.prototype.getParentElement = function(n, na, f, r) {
+	var re = na ? new RegExp('^(' + na.toUpperCase().replace(/,/g, '|') + ')$') : 0, v;
+
+	// Compatiblity with old scripts where f param was a attribute string
+	if (f && typeof(f) == 'string')
+		return this.getParentElement(n, na, function(no) {return tinyMCE.getAttrib(no, f) != '';});
+
+	return this.getParentNode(n, function(n) {
+		return ((n.nodeType == 1 && !re) || (re && re.test(n.nodeName))) && (!f || f(n));
+	}, r);
+};
+
+TinyMCE_Engine.prototype.getParentNode = function(n, f, r) {
+	while (n) {
+		if (n == r)
+			return null;
+
+		if (f(n))
+			return n;
+
+		n = n.parentNode;
+	}
+
+	return null;
+};
+
+TinyMCE_Engine.prototype.getAttrib = function(elm, name, dv) {
+	var v;
+
+	if (typeof(dv) == "undefined")
+		dv = "";
+
+	// Not a element
+	if (!elm || elm.nodeType != 1)
+		return dv;
+
+	try {
+		v = elm.getAttribute(name, 0);
+	} catch (ex) {
+		// IE 7 may cast exception on invalid attributes
+		v = elm.getAttribute(name, 2);
+	}
+
+	// Try className for class attrib
+	if (name == "class" && !v)
+		v = elm.className;
+
+	// Workaround for a issue with Firefox 1.5rc2+
+	if (tinyMCE.isGecko && name == "src" && elm.src != null && elm.src != "")
+		v = elm.src;
+
+	// Workaround for a issue with Firefox 1.5rc2+
+	if (tinyMCE.isGecko && name == "href" && elm.href != null && elm.href != "")
+		v = elm.href;
+
+	if (name == "http-equiv" && tinyMCE.isIE)
+		v = elm.httpEquiv;
+
+	if (name == "style" && !tinyMCE.isOpera)
+		v = elm.style.cssText;
+
+	return (v && v != "") ? v : dv;
+};
+
+TinyMCE_Engine.prototype.setAttrib = function(el, name, va, fix) {
+	if (typeof(va) == "number" && va != null)
+		va = "" + va;
+
+	if (fix) {
+		if (va == null)
+			va = "";
+
+		va = va.replace(/[^0-9%]/g, '');
+	}
+
+	if (name == "style")
+		el.style.cssText = va;
+
+	if (name == "class")
+		el.className = va;
+
+	if (va != null && va != "" && va != -1)
+		el.setAttribute(name, va);
+	else
+		el.removeAttribute(name);
+};
+
+TinyMCE_Engine.prototype.setStyleAttrib = function(e, n, v) {
+	e.style[n] = v;
+
+	// Style attrib deleted in IE
+	if (tinyMCE.isIE && v == null || v == '') {
+		v = tinyMCE.serializeStyle(tinyMCE.parseStyle(e.style.cssText));
+		e.style.cssText = v;
+		e.setAttribute("style", v);
+	}
+};
+
+TinyMCE_Engine.prototype.switchClass = function(ei, c) {
+	var e;
+
+	if (tinyMCE.switchClassCache[ei])
+		e = tinyMCE.switchClassCache[ei];
+	else
+		e = tinyMCE.switchClassCache[ei] = document.getElementById(ei);
+
+	if (e) {
+		// Keep tile mode
+		if (tinyMCE.settings.button_tile_map && e.className && e.className.indexOf('mceTiledButton') == 0)
+			c = 'mceTiledButton ' + c;
+
+		e.className = c;
+	}
+};
+
+TinyMCE_Engine.prototype.getAbsPosition = function(n, cn) {
+	var l = 0, t = 0;
+
+	while (n && n != cn) {
+		l += n.offsetLeft;
+		t += n.offsetTop;
+		n = n.offsetParent;
+	}
+
+	return {absLeft : l, absTop : t};
+};
+
+TinyMCE_Engine.prototype.prevNode = function(e, n) {
+	var a = n.split(','), i;
+
+	while ((e = e.previousSibling) != null) {
+		for (i=0; i<a.length; i++) {
+			if (e.nodeName == a[i])
+				return e;
+		}
+	}
+
+	return null;
+};
+
+TinyMCE_Engine.prototype.nextNode = function(e, n) {
+	var a = n.split(','), i;
+
+	while ((e = e.nextSibling) != null) {
+		for (i=0; i<a.length; i++) {
+			if (e.nodeName == a[i])
+				return e;
+		}
+	}
+
+	return null;
+};
+
+TinyMCE_Engine.prototype.selectElements = function(n, na, f) {
+	var i, a = [], nl, x;
+
+	for (x=0, na = na.split(','); x<na.length; x++)
+		for (i=0, nl = n.getElementsByTagName(na[x]); i<nl.length; i++)
+			(!f || f(nl[i])) && a.push(nl[i]);
+
+	return a;
+};
+
+TinyMCE_Engine.prototype.selectNodes = function(n, f, a) {
+	var i;
+
+	if (!a)
+		a = new Array();
+
+	if (f(n))
+		a[a.length] = n;
+
+	if (n.hasChildNodes()) {
+		for (i=0; i<n.childNodes.length; i++)
+			tinyMCE.selectNodes(n.childNodes[i], f, a);
+	}
+
+	return a;
+};
+
+TinyMCE_Engine.prototype.addCSSClass = function(e, c, b) {
+	var o = this.removeCSSClass(e, c);
+	return e.className = b ? c + (o != '' ? (' ' + o) : '') : (o != '' ? (o + ' ') : '') + c;
+};
+
+TinyMCE_Engine.prototype.removeCSSClass = function(e, c) {
+	c = e.className.replace(new RegExp("(^|\\s+)" + c + "(\\s+|$)"), ' ');
+	return e.className = c != ' ' ? c : '';
+};
+
+TinyMCE_Engine.prototype.hasCSSClass = function(n, c) {
+	return new RegExp('\\b' + c + '\\b', 'g').test(n.className);
+};
+
+TinyMCE_Engine.prototype.renameElement = function(e, n, d) {
+	var ne, i, ar;
+
+	d = typeof(d) == "undefined" ? tinyMCE.selectedInstance.getDoc() : d;
+
+	if (e) {
+		ne = d.createElement(n);
+
+		ar = e.attributes;
+		for (i=ar.length-1; i>-1; i--) {
+			if (ar[i].specified && ar[i].nodeValue)
+				ne.setAttribute(ar[i].nodeName.toLowerCase(), ar[i].nodeValue);
+		}
+
+		ar = e.childNodes;
+		for (i=0; i<ar.length; i++)
+			ne.appendChild(ar[i].cloneNode(true));
+
+		e.parentNode.replaceChild(ne, e);
+	}
+};
+
+TinyMCE_Engine.prototype.getViewPort = function(w) {
+	var d = w.document, m = d.compatMode == 'CSS1Compat', b = d.body, de = d.documentElement;
+
+	return {
+		left : w.pageXOffset || (m ? de.scrollLeft : b.scrollLeft),
+		top : w.pageYOffset || (m ? de.scrollTop : b.scrollTop),
+		width : w.innerWidth || (m ? de.clientWidth : b.clientWidth),
+		height : w.innerHeight || (m ? de.clientHeight : b.clientHeight)
+	};
+};
+
+TinyMCE_Engine.prototype.getStyle = function(n, na, d) {
+	if (!n)
+		return false;
+
+	// Gecko
+	if (tinyMCE.isGecko && n.ownerDocument.defaultView) {
+		try {
+			return n.ownerDocument.defaultView.getComputedStyle(n, null).getPropertyValue(na);
+		} catch (n) {
+			// Old safari might fail
+			return null;
+		}
+	}
+
+	// Camelcase it, if needed
+	na = na.replace(/-(\D)/g, function(a, b){
+		return b.toUpperCase();
+	});
+
+	// IE & Opera
+	if (n.currentStyle)
+		return n.currentStyle[na];
+
+	return false;
+};
+
+/* file:jscripts/tiny_mce/classes/TinyMCE_URL.class.js */
+
+TinyMCE_Engine.prototype.parseURL = function(url_str) {
+	var urlParts = new Array();
+
+	if (url_str) {
+		var pos, lastPos;
+
+		// Parse protocol part
+		pos = url_str.indexOf('://');
+		if (pos != -1) {
+			urlParts['protocol'] = url_str.substring(0, pos);
+			lastPos = pos + 3;
+		}
+
+		// Find port or path start
+		for (var i=lastPos; i<url_str.length; i++) {
+			var chr = url_str.charAt(i);
+
+			if (chr == ':')
+				break;
+
+			if (chr == '/')
+				break;
+		}
+		pos = i;
+
+		// Get host
+		urlParts['host'] = url_str.substring(lastPos, pos);
+
+		// Get port
+		urlParts['port'] = "";
+		lastPos = pos;
+		if (url_str.charAt(pos) == ':') {
+			pos = url_str.indexOf('/', lastPos);
+			urlParts['port'] = url_str.substring(lastPos+1, pos);
+		}
+
+		// Get path
+		lastPos = pos;
+		pos = url_str.indexOf('?', lastPos);
+
+		if (pos == -1)
+			pos = url_str.indexOf('#', lastPos);
+
+		if (pos == -1)
+			pos = url_str.length;
+
+		urlParts['path'] = url_str.substring(lastPos, pos);
+
+		// Get query
+		lastPos = pos;
+		if (url_str.charAt(pos) == '?') {
+			pos = url_str.indexOf('#');
+			pos = (pos == -1) ? url_str.length : pos;
+			urlParts['query'] = url_str.substring(lastPos+1, pos);
+		}
+
+		// Get anchor
+		lastPos = pos;
+		if (url_str.charAt(pos) == '#') {
+			pos = url_str.length;
+			urlParts['anchor'] = url_str.substring(lastPos+1, pos);
+		}
+	}
+
+	return urlParts;
+};
+
+TinyMCE_Engine.prototype.serializeURL = function(up) {
+	var o = "";
+
+	if (up['protocol'])
+		o += up['protocol'] + "://";
+
+	if (up['host'])
+		o += up['host'];
+
+	if (up['port'])
+		o += ":" + up['port'];
+
+	if (up['path'])
+		o += up['path'];
+
+	if (up['query'])
+		o += "?" + up['query'];
+
+	if (up['anchor'])
+		o += "#" + up['anchor'];
+
+	return o;
+};
+
+TinyMCE_Engine.prototype.convertAbsoluteURLToRelativeURL = function(base_url, url_to_relative) {
+	var baseURL = this.parseURL(base_url);
+	var targetURL = this.parseURL(url_to_relative);
+	var strTok1;
+	var strTok2;
+	var breakPoint = 0;
+	var outPath = "";
+	var forceSlash = false;
+
+	if (targetURL.path == "")
+		targetURL.path = "/";
+	else
+		forceSlash = true;
+
+	// Crop away last path part
+	base_url = baseURL.path.substring(0, baseURL.path.lastIndexOf('/'));
+	strTok1 = base_url.split('/');
+	strTok2 = targetURL.path.split('/');
+
+	if (strTok1.length >= strTok2.length) {
+		for (var i=0; i<strTok1.length; i++) {
+			if (i >= strTok2.length || strTok1[i] != strTok2[i]) {
+				breakPoint = i + 1;
+				break;
+			}
+		}
+	}
+
+	if (strTok1.length < strTok2.length) {
+		for (var i=0; i<strTok2.length; i++) {
+			if (i >= strTok1.length || strTok1[i] != strTok2[i]) {
+				breakPoint = i + 1;
+				break;
+			}
+		}
+	}
+
+	if (breakPoint == 1)
+		return targetURL.path;
+
+	for (var i=0; i<(strTok1.length-(breakPoint-1)); i++)
+		outPath += "../";
+
+	for (var i=breakPoint-1; i<strTok2.length; i++) {
+		if (i != (breakPoint-1))
+			outPath += "/" + strTok2[i];
+		else
+			outPath += strTok2[i];
+	}
+
+	targetURL.protocol = null;
+	targetURL.host = null;
+	targetURL.port = null;
+	targetURL.path = outPath == "" && forceSlash ? "/" : outPath;
+
+	// Remove document prefix from local anchors
+	var fileName = baseURL.path;
+	var pos;
+
+	if ((pos = fileName.lastIndexOf('/')) != -1)
+		fileName = fileName.substring(pos + 1);
+
+	// Is local anchor
+	if (fileName == targetURL.path && targetURL.anchor != "")
+		targetURL.path = "";
+
+	// If empty and not local anchor force filename or slash
+	if (targetURL.path == "" && !targetURL.anchor)
+		targetURL.path = fileName != "" ? fileName : "/";
+
+	return this.serializeURL(targetURL);
+};
+
+TinyMCE_Engine.prototype.convertRelativeToAbsoluteURL = function(base_url, relative_url) {
+	var baseURL = this.parseURL(base_url), baseURLParts, relURLParts;
+	var relURL = this.parseURL(relative_url);
+
+	if (relative_url == "" || relative_url.indexOf('://') != -1 || /^(mailto:|javascript:|#|\/)/.test(relative_url))
+		return relative_url;
+
+	// Split parts
+	baseURLParts = baseURL['path'].split('/');
+	relURLParts = relURL['path'].split('/');
+
+	// Remove empty chunks
+	var newBaseURLParts = new Array();
+	for (var i=baseURLParts.length-1; i>=0; i--) {
+		if (baseURLParts[i].length == 0)
+			continue;
+
+		newBaseURLParts[newBaseURLParts.length] = baseURLParts[i];
+	}
+	baseURLParts = newBaseURLParts.reverse();
+
+	// Merge relURLParts chunks
+	var newRelURLParts = new Array();
+	var numBack = 0;
+	for (var i=relURLParts.length-1; i>=0; i--) {
+		if (relURLParts[i].length == 0 || relURLParts[i] == ".")
+			continue;
+
+		if (relURLParts[i] == '..') {
+			numBack++;
+			continue;
+		}
+
+		if (numBack > 0) {
+			numBack--;
+			continue;
+		}
+
+		newRelURLParts[newRelURLParts.length] = relURLParts[i];
+	}
+
+	relURLParts = newRelURLParts.reverse();
+
+	// Remove end from absolute path
+	var len = baseURLParts.length-numBack;
+	var absPath = (len <= 0 ? "" : "/") + baseURLParts.slice(0, len).join('/') + "/" + relURLParts.join('/');
+	var start = "", end = "";
+
+	// Build output URL
+	relURL.protocol = baseURL.protocol;
+	relURL.host = baseURL.host;
+	relURL.port = baseURL.port;
+
+	// Re-add trailing slash if it's removed
+	if (relURL.path.charAt(relURL.path.length-1) == "/")
+		absPath += "/";
+
+	relURL.path = absPath;
+
+	return this.serializeURL(relURL);
+};
+
+TinyMCE_Engine.prototype.convertURL = function(url, node, on_save) {
+	var prot = document.location.protocol;
+	var host = document.location.hostname;
+	var port = document.location.port;
+
+	// Pass through file protocol
+	if (prot == "file:")
+		return url;
+
+	// Something is wrong, remove weirdness
+	url = tinyMCE.regexpReplace(url, '(http|https):///', '/');
+
+	// Mailto link or anchor (Pass through)
+	if (url.indexOf('mailto:') != -1 || url.indexOf('javascript:') != -1 || tinyMCE.regexpReplace(url,'[ \t\r\n\+]|%20','').charAt(0) == "#")
+		return url;
+
+	// Fix relative/Mozilla
+	if (!tinyMCE.isIE && !on_save && url.indexOf("://") == -1 && url.charAt(0) != '/')
+		return tinyMCE.settings['base_href'] + url;
+
+	// Handle relative URLs
+	if (on_save && tinyMCE.getParam('relative_urls')) {
+		var curl = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], url);
+		if (curl.charAt(0) == '/')
+			curl = tinyMCE.settings['document_base_prefix'] + curl;
+
+		var urlParts = tinyMCE.parseURL(curl);
+		var tmpUrlParts = tinyMCE.parseURL(tinyMCE.settings['document_base_url']);
+
+		// Force relative
+		if (urlParts['host'] == tmpUrlParts['host'] && (urlParts['port'] == tmpUrlParts['port']))
+			return tinyMCE.convertAbsoluteURLToRelativeURL(tinyMCE.settings['document_base_url'], curl);
+	}
+
+	// Handle absolute URLs
+	if (!tinyMCE.getParam('relative_urls')) {
+		var urlParts = tinyMCE.parseURL(url);
+		var baseUrlParts = tinyMCE.parseURL(tinyMCE.settings['base_href']);
+
+		// Force absolute URLs from relative URLs
+		url = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], url);
+
+		// If anchor and path is the same page
+		if (urlParts['anchor'] && urlParts['path'] == baseUrlParts['path'])
+			return "#" + urlParts['anchor'];
+	}
+
+	// Remove current domain
+	if (tinyMCE.getParam('remove_script_host')) {
+		var start = "", portPart = "";
+
+		if (port != "")
+			portPart = ":" + port;
+
+		start = prot + "//" + host + portPart + "/";
+
+		if (url.indexOf(start) == 0)
+			url = url.substring(start.length-1);
+	}
+
+	return url;
+};
+
+TinyMCE_Engine.prototype.convertAllRelativeURLs = function(body) {
+	var i, elms, src, href, mhref, msrc;
+
+	// Convert all image URL:s to absolute URL
+	elms = body.getElementsByTagName("img");
+	for (i=0; i<elms.length; i++) {
+		src = tinyMCE.getAttrib(elms[i], 'src');
+
+		msrc = tinyMCE.getAttrib(elms[i], 'mce_src');
+		if (msrc != "")
+			src = msrc;
+
+		if (src != "") {
+			src = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], src);
+			elms[i].setAttribute("src", src);
+		}
+	}
+
+	// Convert all link URL:s to absolute URL
+	elms = body.getElementsByTagName("a");
+	for (i=0; i<elms.length; i++) {
+		href = tinyMCE.getAttrib(elms[i], 'href');
+
+		mhref = tinyMCE.getAttrib(elms[i], 'mce_href');
+		if (mhref != "")
+			href = mhref;
+
+		if (href && href != "") {
+			href = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], href);
+			elms[i].setAttribute("href", href);
+		}
+	}
+};
+
+/* file:jscripts/tiny_mce/classes/TinyMCE_Array.class.js */
+
+TinyMCE_Engine.prototype.clearArray = function(a) {
+	var n;
+
+	for (n in a)
+		a[n] = null;
+
+	return a;
+};
+
+TinyMCE_Engine.prototype.explode = function(d, s) {
+	var ar = s.split(d), oar = new Array(), i;
+
+	for (i = 0; i<ar.length; i++) {
+		if (ar[i] != "")
+			oar[oar.length] = ar[i];
+	}
+
+	return oar;
+};
+
+/* file:jscripts/tiny_mce/classes/TinyMCE_Event.class.js */
+
+TinyMCE_Engine.prototype._setEventsEnabled = function(node, state) {
+	var evs, x, y, elms, i, event;
+	var events = ['onfocus','onblur','onclick','ondblclick',
+				'onmousedown','onmouseup','onmouseover','onmousemove',
+				'onmouseout','onkeypress','onkeydown','onkeydown','onkeyup'];
+
+	evs = tinyMCE.settings['event_elements'].split(',');
+	for (y=0; y<evs.length; y++){
+		elms = node.getElementsByTagName(evs[y]);
+		for (i=0; i<elms.length; i++) {
+			event = "";
+
+			for (x=0; x<events.length; x++) {
+				if ((event = tinyMCE.getAttrib(elms[i], events[x])) != '') {
+					event = tinyMCE.cleanupEventStr("" + event);
+
+					if (!state)
+						event = "return true;" + event;
+					else
+						event = event.replace(/^return true;/gi, '');
+
+					elms[i].removeAttribute(events[x]);
+					elms[i].setAttribute(events[x], event);
+				}
+			}
+		}
+	}
+};
+
+TinyMCE_Engine.prototype._eventPatch = function(editor_id) {
+	var n, inst, win, e;
+
+	// Remove odd, error
+	if (typeof(tinyMCE) == "undefined")
+		return true;
+
+	try {
+		// Try selected instance first
+		if (tinyMCE.selectedInstance) {
+			win = tinyMCE.selectedInstance.getWin();
+
+			if (win && win.event) {
+				e = win.event;
+
+				if (!e.target)
+					e.target = e.srcElement;
+
+				TinyMCE_Engine.prototype.handleEvent(e);
+				return;
+			}
+		}
+
+		// Search for it
+		for (n in tinyMCE.instances) {
+			inst = tinyMCE.instances[n];
+
+			if (!tinyMCE.isInstance(inst))
+				continue;
+
+			inst.select();
+			win = inst.getWin();
+
+			if (win && win.event) {
+				e = win.event;
+
+				if (!e.target)
+					e.target = e.srcElement;
+
+				TinyMCE_Engine.prototype.handleEvent(e);
+				return;
+			}
+		}
+	} catch (ex) {
+		// Ignore error if iframe is pointing to external URL
+	}
+};
+
+TinyMCE_Engine.prototype.findEvent = function(e) {
+	var n, inst;
+
+	if (e)
+		return e;
+
+	for (n in tinyMCE.instances) {
+		inst = tinyMCE.instances[n];
+
+		if (tinyMCE.isInstance(inst) && inst.getWin().event)
+			return inst.getWin().event;
+	}
+
+	return null;
+};
+
+TinyMCE_Engine.prototype.unloadHandler = function() {
+	tinyMCE.triggerSave(true, true);
+};
+
+TinyMCE_Engine.prototype.addEventHandlers = function(inst) {
+	this.setEventHandlers(inst, 1);
+};
+
+TinyMCE_Engine.prototype.setEventHandlers = function(inst, s) {
+	var doc = inst.getDoc(), ie, ot, i, f = s ? tinyMCE.addEvent : tinyMCE.removeEvent;
+
+	ie = ['keypress', 'keyup', 'keydown', 'click', 'mouseup', 'mousedown', 'controlselect', 'dblclick'];
+	ot = ['keypress', 'keyup', 'keydown', 'click', 'mouseup', 'mousedown', 'focus', 'blur', 'dragdrop'];
+
+	inst.switchSettings();
+
+	if (tinyMCE.isIE) {
+		for (i=0; i<ie.length; i++)
+			f(doc, ie[i], TinyMCE_Engine.prototype._eventPatch);
+	} else {
+		for (i=0; i<ot.length; i++)
+			f(doc, ot[i], tinyMCE.handleEvent);
+
+		// Force designmode
+		try {
+			doc.designMode = "On";
+		} catch (e) {
+			// Ignore
+		}
+	}
+};
+
+TinyMCE_Engine.prototype.onMouseMove = function() {
+	var inst, lh;
+
+	// Fix for IE7 bug where it's not restoring hover on anchors correctly
+	if (tinyMCE.lastHover) {
+		lh = tinyMCE.lastHover;
+
+		// Call out on menus and refresh class on normal buttons
+		if (lh.className.indexOf('mceMenu') != -1)
+			tinyMCE._menuButtonEvent('out', lh);
+		else
+			lh.className = lh.className;
+
+		tinyMCE.lastHover = null;
+	}
+
+	if (!tinyMCE.hasMouseMoved) {
+		inst = tinyMCE.selectedInstance;
+
+		// Workaround for bug #1437457 (Odd MSIE bug)
+		if (inst.isFocused) {
+			inst.undoBookmark = inst.selection.getBookmark();
+			tinyMCE.hasMouseMoved = true;
+		}
+	}
+
+//	tinyMCE.cancelEvent(inst.getWin().event);
+//	return false;
+};
+
+TinyMCE_Engine.prototype.cancelEvent = function(e) {
+	if (!e)
+		return false;
+
+	if (tinyMCE.isIE) {
+		e.returnValue = false;
+		e.cancelBubble = true;
+	} else {
+		e.preventDefault();
+		e.stopPropagation && e.stopPropagation();
+	}
+
+	return false;
+};
+
+TinyMCE_Engine.prototype.addEvent = function(o, n, h) {
+	// Add cleanup for all non unload events
+	if (n != 'unload') {
+		function clean() {
+			var ex;
+
+			try {
+				tinyMCE.removeEvent(o, n, h);
+				tinyMCE.removeEvent(window, 'unload', clean);
+				o = n = h = null;
+			} catch (ex) {
+				// IE may produce access denied exception on unload
+			}
+		}
+
+		// Add memory cleaner
+		tinyMCE.addEvent(window, 'unload', clean);
+	}
+
+	if (o.attachEvent)
+		o.attachEvent("on" + n, h);
+	else
+		o.addEventListener(n, h, false);
+};
+
+TinyMCE_Engine.prototype.removeEvent = function(o, n, h) {
+	if (o.detachEvent)
+		o.detachEvent("on" + n, h);
+	else
+		o.removeEventListener(n, h, false);
+};
+
+TinyMCE_Engine.prototype.addSelectAccessibility = function(e, s, w) {
+	// Add event handlers 
+	if (!s._isAccessible) {
+		s.onkeydown = tinyMCE.accessibleEventHandler;
+		s.onblur = tinyMCE.accessibleEventHandler;
+		s._isAccessible = true;
+		s._win = w;
+	}
+
+	return false;
+};
+
+TinyMCE_Engine.prototype.accessibleEventHandler = function(e) {
+	var win = this._win;
+	e = tinyMCE.isIE ? win.event : e;
+	var elm = tinyMCE.isIE ? e.srcElement : e.target;
+
+	// Unpiggyback onchange on blur
+	if (e.type == "blur") {
+		if (elm.oldonchange) {
+			elm.onchange = elm.oldonchange;
+			elm.oldonchange = null;
+		}
+
+		return true;
+	}
+
+	// Piggyback onchange
+	if (elm.nodeName == "SELECT" && !elm.oldonchange) {
+		elm.oldonchange = elm.onchange;
+		elm.onchange = null;
+	}
+
+	// Execute onchange and remove piggyback
+	if (e.keyCode == 13 || e.keyCode == 32) {
+		elm.onchange = elm.oldonchange;
+		elm.onchange();
+		elm.oldonchange = null;
+
+		tinyMCE.cancelEvent(e);
+		return false;
+	}
+
+	return true;
+};
+
+TinyMCE_Engine.prototype._resetIframeHeight = function() {
+	var ife;
+
+	if (tinyMCE.isRealIE) {
+		ife = tinyMCE.selectedInstance.iframeElement;
+
+/*		if (ife._oldWidth) {
+			ife.style.width = ife._oldWidth;
+			ife.width = ife._oldWidth;
+		}*/
+
+		if (ife._oldHeight) {
+			ife.style.height = ife._oldHeight;
+			ife.height = ife._oldHeight;
+		}
+	}
+};
+
+/* file:jscripts/tiny_mce/classes/TinyMCE_Selection.class.js */
+
+function TinyMCE_Selection(inst) {
+	this.instance = inst;
+};
+
+TinyMCE_Selection.prototype = {
+	getSelectedHTML : function() {
+		var inst = this.instance;
+		var e, r = this.getRng(), h;
+
+		if (!r)
+			return null;
+
+		e = document.createElement("body");
+
+		if (r.cloneContents)
+			e.appendChild(r.cloneContents());
+		else if (typeof(r.item) != 'undefined' || typeof(r.htmlText) != 'undefined')
+			e.innerHTML = r.item ? r.item(0).outerHTML : r.htmlText;
+		else
+			e.innerHTML = r.toString(); // Failed, use text for now
+
+		h = tinyMCE._cleanupHTML(inst, inst.contentDocument, inst.settings, e, e, false, true, false);
+
+		// When editing always use fonts internaly
+		//if (tinyMCE.getParam("convert_fonts_to_spans"))
+		//	tinyMCE.convertSpansToFonts(inst.getDoc());
+
+		return h;
+	},
+
+	getSelectedText : function() {
+		var inst = this.instance;
+		var d, r, s, t;
+
+		if (tinyMCE.isIE) {
+			d = inst.getDoc();
+
+			if (d.selection.type == "Text") {
+				r = d.selection.createRange();
+				t = r.text;
+			} else
+				t = '';
+		} else {
+			s = this.getSel();
+
+			if (s && s.toString)
+				t = s.toString();
+			else
+				t = '';
+		}
+
+		return t;
+	},
+
+	getBookmark : function(simple) {
+		var inst = this.instance;
+		var rng = this.getRng();
+		var doc = inst.getDoc(), b = inst.getBody();
+		var sp, le, s, e, nl, i, si, ei, w;
+		var trng, sx, sy, xx = -999999999, vp = inst.getViewPort();
+
+		sx = vp.left;
+		sy = vp.top;
+
+		if (tinyMCE.isSafari || tinyMCE.isOpera || simple)
+			return {rng : rng, scrollX : sx, scrollY : sy};
+
+		if (tinyMCE.isIE) {
+			if (rng.item) {
+				e = rng.item(0);
+
+				nl = b.getElementsByTagName(e.nodeName);
+				for (i=0; i<nl.length; i++) {
+					if (e == nl[i]) {
+						sp = i;
+						break;
+					}
+				}
+
+				return {
+					tag : e.nodeName,
+					index : sp,
+					scrollX : sx,
+					scrollY : sy
+				};
+			} else {
+				trng = doc.body.createTextRange();
+				trng.moveToElementText(inst.getBody());
+				trng.collapse(true);
+				bp = Math.abs(trng.move('character', xx));
+
+				trng = rng.duplicate();
+				trng.collapse(true);
+				sp = Math.abs(trng.move('character', xx));
+
+				trng = rng.duplicate();
+				trng.collapse(false);
+				le = Math.abs(trng.move('character', xx)) - sp;
+
+				return {
+					start : sp - bp,
+					length : le,
+					scrollX : sx,
+					scrollY : sy
+				};
+			}
+		}
+
+		if (tinyMCE.isGecko) {
+			s = this.getSel();
+			e = this.getFocusElement();
+
+			if (!s)
+				return null;
+
+			if (e && e.nodeName == 'IMG') {
+				/*nl = b.getElementsByTagName('IMG');
+				for (i=0; i<nl.length; i++) {
+					if (e == nl[i]) {
+						sp = i;
+						break;
+					}
+				}*/
+
+				return {
+					start : -1,
+					end : -1,
+					index : sp,
+					scrollX : sx,
+					scrollY : sy
+				};
+			}
+
+			// Caret or selection
+			if (s.anchorNode == s.focusNode && s.anchorOffset == s.focusOffset) {
+				e = this._getPosText(b, s.anchorNode, s.focusNode);
+
+				if (!e)
+					return {scrollX : sx, scrollY : sy};
+
+				return {
+					start : e.start + s.anchorOffset,
+					end : e.end + s.focusOffset,
+					scrollX : sx,
+					scrollY : sy
+				};
+			} else {
+				e = this._getPosText(b, rng.startContainer, rng.endContainer);
+
+				if (!e)
+					return {scrollX : sx, scrollY : sy};
+
+				return {
+					start : e.start + rng.startOffset,
+					end : e.end + rng.endOffset,
+					scrollX : sx,
+					scrollY : sy
+				};
+			}
+		}
+
+		return null;
+	},
+
+	moveToBookmark : function(bookmark) {
+		var inst = this.instance;
+		var rng, nl, i, ex, b = inst.getBody(), sd;
+		var doc = inst.getDoc();
+		var win = inst.getWin();
+		var sel = this.getSel();
+
+		if (!bookmark)
+			return false;
+
+		if (tinyMCE.isSafari) {
+			sel.setBaseAndExtent(bookmark.rng.startContainer, bookmark.rng.startOffset, bookmark.rng.endContainer, bookmark.rng.endOffset);
+			return true;
+		}
+
+		if (tinyMCE.isRealIE) {
+			if (bookmark.rng) {
+				try {
+					bookmark.rng.select();
+				} catch (ex) {
+					// Ignore
+				}
+
+				return true;
+			}
+
+			win.focus();
+
+			if (bookmark.tag) {
+				rng = b.createControlRange();
+
+				nl = b.getElementsByTagName(bookmark.tag);
+
+				if (nl.length > bookmark.index) {
+					try {
+						rng.addElement(nl[bookmark.index]);
+					} catch (ex) {
+						// Might be thrown if the node no longer exists
+					}
+				}
+			} else {
+				// Try/catch needed since this operation breaks when TinyMCE is placed in hidden divs/tabs
+				try {
+					// Incorrect bookmark
+					if (bookmark.start < 0)
+						return true;
+
+					rng = inst.getSel().createRange();
+					rng.moveToElementText(inst.getBody());
+					rng.collapse(true);
+					rng.moveStart('character', bookmark.start);
+					rng.moveEnd('character', bookmark.length);
+				} catch (ex) {
+					return true;
+				}
+			}
+
+			rng.select();
+
+			win.scrollTo(bookmark.scrollX, bookmark.scrollY);
+			return true;
+		}
+
+		if (tinyMCE.isGecko || tinyMCE.isOpera) {
+			if (!sel)
+				return false;
+
+			if (bookmark.rng) {
+				sel.removeAllRanges();
+				sel.addRange(bookmark.rng);
+			}
+
+			if (bookmark.start != -1 && bookmark.end != -1) {
+				try {
+					sd = this._getTextPos(b, bookmark.start, bookmark.end);
+					rng = doc.createRange();
+					rng.setStart(sd.startNode, sd.startOffset);
+					rng.setEnd(sd.endNode, sd.endOffset);
+					sel.removeAllRanges();
+					sel.addRange(rng);
+					win.focus();
+				} catch (ex) {
+					// Ignore
+				}
+			}
+
+			/*
+			if (typeof(bookmark.index) != 'undefined') {
+				tinyMCE.selectElements(b, 'IMG', function (n) {
+					if (bookmark.index-- == 0) {
+						// Select image in Gecko here
+					}
+
+					return false;
+				});
+			}
+			*/
+
+			win.scrollTo(bookmark.scrollX, bookmark.scrollY);
+			return true;
+		}
+
+		return false;
+	},
+
+	_getPosText : function(r, sn, en) {
+		var w = document.createTreeWalker(r, NodeFilter.SHOW_TEXT, null, false), n, p = 0, d = {};
+
+		while ((n = w.nextNode()) != null) {
+			if (n == sn)
+				d.start = p;
+
+			if (n == en) {
+				d.end = p;
+				return d;
+			}
+
+			p += n.nodeValue ? n.nodeValue.length : 0;
+		}
+
+		return null;
+	},
+
+	_getTextPos : function(r, sp, ep) {
+		var w = document.createTreeWalker(r, NodeFilter.SHOW_TEXT, null, false), n, p = 0, d = {};
+
+		while ((n = w.nextNode()) != null) {
+			p += n.nodeValue ? n.nodeValue.length : 0;
+
+			if (p >= sp && !d.startNode) {
+				d.startNode = n;
+				d.startOffset = sp - (p - n.nodeValue.length);
+			}
+
+			if (p >= ep) {
+				d.endNode = n;
+				d.endOffset = ep - (p - n.nodeValue.length);
+
+				return d;
+			}
+		}
+
+		return null;
+	},
+
+	selectNode : function(node, collapse, select_text_node, to_start) {
+		var inst = this.instance, sel, rng, nodes;
+
+		if (!node)
+			return;
+
+		if (typeof(collapse) == "undefined")
+			collapse = true;
+
+		if (typeof(select_text_node) == "undefined")
+			select_text_node = false;
+
+		if (typeof(to_start) == "undefined")
+			to_start = true;
+
+		if (inst.settings.auto_resize)
+			inst.resizeToContent();
+
+		if (tinyMCE.isRealIE) {
+			rng = inst.getDoc().body.createTextRange();
+
+			try {
+				rng.moveToElementText(node);
+
+				if (collapse)
+					rng.collapse(to_start);
+
+				rng.select();
+			} catch (e) {
+				// Throws illigal agrument in MSIE some times
+			}
+		} else {
+			sel = this.getSel();
+
+			if (!sel)
+				return;
+
+			if (tinyMCE.isSafari) {
+				sel.setBaseAndExtent(node, 0, node, node.innerText.length);
+
+				if (collapse) {
+					if (to_start)
+						sel.collapseToStart();
+					else
+						sel.collapseToEnd();
+				}
+
+				this.scrollToNode(node);
+
+				return;
+			}
+
+			rng = inst.getDoc().createRange();
+
+			if (select_text_node) {
+				// Find first textnode in tree
+				nodes = tinyMCE.getNodeTree(node, new Array(), 3);
+				if (nodes.length > 0)
+					rng.selectNodeContents(nodes[0]);
+				else
+					rng.selectNodeContents(node);
+			} else
+				rng.selectNode(node);
+
+			if (collapse) {
+				// Special treatment of textnode collapse
+				if (!to_start && node.nodeType == 3) {
+					rng.setStart(node, node.nodeValue.length);
+					rng.setEnd(node, node.nodeValue.length);
+				} else
+					rng.collapse(to_start);
+			}
+
+			sel.removeAllRanges();
+			sel.addRange(rng);
+		}
+
+		this.scrollToNode(node);
+
+		// Set selected element
+		tinyMCE.selectedElement = null;
+		if (node.nodeType == 1)
+			tinyMCE.selectedElement = node;
+	},
+
+	scrollToNode : function(node) {
+		var inst = this.instance, w = inst.getWin(), vp = inst.getViewPort(), pos = tinyMCE.getAbsPosition(node), cvp, p, cwin;
+
+		// Only scroll if out of visible area
+		if (pos.absLeft < vp.left || pos.absLeft > vp.left + vp.width || pos.absTop < vp.top || pos.absTop > vp.top + (vp.height-25))
+			w.scrollTo(pos.absLeft, pos.absTop - vp.height + 25);
+
+		// Scroll container window
+		if (inst.settings.auto_resize) {
+			cwin = inst.getContainerWin();
+			cvp = tinyMCE.getViewPort(cwin);
+			p = this.getAbsPosition(node);
+
+			if (p.absLeft < cvp.left || p.absLeft > cvp.left + cvp.width || p.absTop < cvp.top || p.absTop > cvp.top + cvp.height)
+				cwin.scrollTo(p.absLeft, p.absTop - cvp.height + 25);
+		}
+	},
+
+	getAbsPosition : function(n) {
+		var pos = tinyMCE.getAbsPosition(n), ipos = tinyMCE.getAbsPosition(this.instance.iframeElement);
+
+		return {
+			absLeft : ipos.absLeft + pos.absLeft,
+			absTop : ipos.absTop + pos.absTop
+		};
+	},
+
+	getSel : function() {
+		var inst = this.instance;
+
+		if (tinyMCE.isRealIE)
+			return inst.getDoc().selection;
+
+		return inst.contentWindow.getSelection();
+	},
+
+	getRng : function() {
+		var s = this.getSel();
+
+		if (s == null)
+			return null;
+
+		if (tinyMCE.isRealIE)
+			return s.createRange();
+
+		if (tinyMCE.isSafari && !s.getRangeAt)
+			return '' + window.getSelection();
+
+		if (s.rangeCount > 0)
+			return s.getRangeAt(0);
+
+		return null;
+	},
+
+	isCollapsed : function() {
+		var r = this.getRng();
+
+		if (r.item)
+			return false;
+
+		return r.boundingWidth == 0 || this.getSel().isCollapsed;
+	},
+
+	collapse : function(b) {
+		var r = this.getRng(), s = this.getSel();
+
+		if (r.select) {
+			r.collapse(b);
+			r.select();
+		} else {
+			if (b)
+				s.collapseToStart();
+			else
+				s.collapseToEnd();
+		}
+	},
+
+	getFocusElement : function() {
+		var inst = this.instance, doc, rng, sel, elm;
+
+		if (tinyMCE.isRealIE) {
+			doc = inst.getDoc();
+			rng = doc.selection.createRange();
+
+	//		if (rng.collapse)
+	//			rng.collapse(true);
+
+			elm = rng.item ? rng.item(0) : rng.parentElement();
+		} else {
+			if (!tinyMCE.isSafari && inst.isHidden())
+				return inst.getBody();
+
+			sel = this.getSel();
+			rng = this.getRng();
+
+			if (!sel || !rng)
+				return null;
+
+			elm = rng.commonAncestorContainer;
+			//elm = (sel && sel.anchorNode) ? sel.anchorNode : null;
+
+			// Handle selection a image or other control like element such as anchors
+			if (!rng.collapsed) {
+				// Is selection small
+				if (rng.startContainer == rng.endContainer) {
+					if (rng.startOffset - rng.endOffset < 2) {
+						if (rng.startContainer.hasChildNodes())
+							elm = rng.startContainer.childNodes[rng.startOffset];
+					}
+				}
+			}
+
+			// Get the element parent of the node
+			elm = tinyMCE.getParentElement(elm);
+
+			//if (tinyMCE.selectedElement != null && tinyMCE.selectedElement.nodeName.toLowerCase() == "img")
+			//	elm = tinyMCE.selectedElement;
+		}
+
+		return elm;
+	}
+
+	};
+
+/* file:jscripts/tiny_mce/classes/TinyMCE_UndoRedo.class.js */
+
+function TinyMCE_UndoRedo(inst) {
+	this.instance = inst;
+	this.undoLevels = new Array();
+	this.undoIndex = 0;
+	this.typingUndoIndex = -1;
+	this.undoRedo = true;
+};
+
+TinyMCE_UndoRedo.prototype = {
+	add : function(l) {
+		var b, customUndoLevels, newHTML, inst = this.instance, i, ul, ur;
+
+		if (l) {
+			this.undoLevels[this.undoLevels.length] = l;
+			return true;
+		}
+
+		if (this.typingUndoIndex != -1) {
+			this.undoIndex = this.typingUndoIndex;
+
+			if (tinyMCE.typingUndoIndex != -1)
+				tinyMCE.undoIndex = tinyMCE.typingUndoIndex;
+		}
+
+		newHTML = tinyMCE.trim(inst.getBody().innerHTML);
+		if (this.undoLevels[this.undoIndex] && newHTML != this.undoLevels[this.undoIndex].content) {
+			//tinyMCE.debug(newHTML, this.undoLevels[this.undoIndex].content);
+
+			tinyMCE.dispatchCallback(inst, 'onchange_callback', 'onChange', inst);
+
+			// Time to compress
+			customUndoLevels = tinyMCE.settings['custom_undo_redo_levels'];
+			if (customUndoLevels != -1 && this.undoLevels.length > customUndoLevels) {
+				for (i=0; i<this.undoLevels.length-1; i++)
+					this.undoLevels[i] = this.undoLevels[i+1];
+
+				this.undoLevels.length--;
+				this.undoIndex--;
+
+				// Todo: Implement global undo/redo logic here
+			}
+
+			b = inst.undoBookmark;
+
+			if (!b)
+				b = inst.selection.getBookmark();
+
+			this.undoIndex++;
+			this.undoLevels[this.undoIndex] = {
+				content : newHTML,
+				bookmark : b
+			};
+
+			// Remove all above from global undo/redo
+			ul = tinyMCE.undoLevels;
+			for (i=tinyMCE.undoIndex + 1; i<ul.length; i++) {
+				ur = ul[i].undoRedo;
+
+				if (ur.undoIndex == ur.undoLevels.length -1)
+					ur.undoIndex--;
+
+				ur.undoLevels.length--;
+			}
+
+			// Add global undo level
+			tinyMCE.undoLevels[tinyMCE.undoIndex++] = inst;
+			tinyMCE.undoLevels.length = tinyMCE.undoIndex;
+
+			this.undoLevels.length = this.undoIndex + 1;
+
+			return true;
+		}
+
+		return false;
+	},
+
+	undo : function() {
+		var inst = this.instance;
+
+		// Do undo
+		if (this.undoIndex > 0) {
+			this.undoIndex--;
+
+			tinyMCE.setInnerHTML(inst.getBody(), this.undoLevels[this.undoIndex].content);
+			inst.repaint();
+
+			if (inst.settings.custom_undo_redo_restore_selection)
+				inst.selection.moveToBookmark(this.undoLevels[this.undoIndex].bookmark);
+		}
+	},
+
+	redo : function() {
+		var inst = this.instance;
+
+		tinyMCE.execCommand("mceEndTyping");
+
+		if (this.undoIndex < (this.undoLevels.length-1)) {
+			this.undoIndex++;
+
+			tinyMCE.setInnerHTML(inst.getBody(), this.undoLevels[this.undoIndex].content);
+			inst.repaint();
+
+			if (inst.settings.custom_undo_redo_restore_selection)
+				inst.selection.moveToBookmark(this.undoLevels[this.undoIndex].bookmark);
+		}
+
+		tinyMCE.triggerNodeChange();
+	}
+
+	};
+
+/* file:jscripts/tiny_mce/classes/TinyMCE_ForceParagraphs.class.js */
+
+var TinyMCE_ForceParagraphs = {
+	_insertPara : function(inst, e) {
+		var doc = inst.getDoc(), sel = inst.getSel(), body = inst.getBody(), win = inst.contentWindow, rng = sel.getRangeAt(0);
+		var rootElm = doc.documentElement, blockName = "P", startNode, endNode, startBlock, endBlock;
+		var rngBefore, rngAfter, direct, startNode, startOffset, endNode, endOffset, b = tinyMCE.isOpera ? inst.selection.getBookmark() : null;
+		var paraBefore, paraAfter, startChop, endChop, contents;
+
+		function isEmpty(para) {
+			function isEmptyHTML(html) {
+				return html.replace(new RegExp('[ \t\r\n]+', 'g'), '').toLowerCase() == "";
+			}
+
+			// Check for images
+			if (para.getElementsByTagName("img").length > 0)
+				return false;
+
+			// Check for tables
+			if (para.getElementsByTagName("table").length > 0)
+				return false;
+
+			// Check for HRs
+			if (para.getElementsByTagName("hr").length > 0)
+				return false;
+
+			// Check all textnodes
+			var nodes = tinyMCE.getNodeTree(para, new Array(), 3);
+			for (var i=0; i<nodes.length; i++) {
+				if (!isEmptyHTML(nodes[i].nodeValue))
+					return false;
+			}
+
+			// No images, no tables, no hrs, no text content then it's empty
+			return true;
+		}
+
+	//	tinyMCE.debug(body.innerHTML);
+
+	//	debug(e.target, sel.anchorNode.nodeName, sel.focusNode.nodeName, rng.startContainer, rng.endContainer, rng.commonAncestorContainer, sel.anchorOffset, sel.focusOffset, rng.toString());
+
+		// Setup before range
+		rngBefore = doc.createRange();
+		rngBefore.setStart(sel.anchorNode, sel.anchorOffset);
+		rngBefore.collapse(true);
+
+		// Setup after range
+		rngAfter = doc.createRange();
+		rngAfter.setStart(sel.focusNode, sel.focusOffset);
+		rngAfter.collapse(true);
+
+		// Setup start/end points
+		direct = rngBefore.compareBoundaryPoints(rngBefore.START_TO_END, rngAfter) < 0;
+		startNode = direct ? sel.anchorNode : sel.focusNode;
+		startOffset = direct ? sel.anchorOffset : sel.focusOffset;
+		endNode = direct ? sel.focusNode : sel.anchorNode;
+		endOffset = direct ? sel.focusOffset : sel.anchorOffset;
+
+		startNode = startNode.nodeName == "BODY" ? startNode.firstChild : startNode;
+		endNode = endNode.nodeName == "BODY" ? endNode.firstChild : endNode;
+
+		// Get block elements
+		startBlock = inst.getParentBlockElement(startNode);
+		endBlock = inst.getParentBlockElement(endNode);
+
+		// If absolute force paragraph generation within
+		if (startBlock && new RegExp('absolute|relative|static', 'gi').test(startBlock.style.position))
+			startBlock = null;
+
+		if (endBlock && new RegExp('absolute|relative|static', 'gi').test(endBlock.style.position))
+			endBlock = null;
+
+		// Use current block name
+		if (startBlock != null) {
+			blockName = startBlock.nodeName;
+
+			// Use P instead
+			if (blockName == "TD" || blockName == "TABLE" || (blockName == "DIV" && new RegExp('left|right', 'gi').test(startBlock.style.cssFloat)))
+				blockName = "P";
+		}
+
+		// Within a list use normal behaviour
+		if (tinyMCE.getParentElement(startBlock, "OL,UL", null, body) != null)
+			return false;
+
+		// Within a table create new paragraphs
+		if ((startBlock != null && startBlock.nodeName == "TABLE") || (endBlock != null && endBlock.nodeName == "TABLE"))
+			startBlock = endBlock = null;
+
+		// Setup new paragraphs
+		paraBefore = (startBlock != null && startBlock.nodeName == blockName) ? startBlock.cloneNode(false) : doc.createElement(blockName);
+		paraAfter = (endBlock != null && endBlock.nodeName == blockName) ? endBlock.cloneNode(false) : doc.createElement(blockName);
+
+		// Is header, then force paragraph under
+		if (/^(H[1-6])$/.test(blockName))
+			paraAfter = doc.createElement("p");
+
+		// Setup chop nodes
+		startChop = startNode;
+		endChop = endNode;
+
+		// Get startChop node
+		node = startChop;
+		do {
+			if (node == body || node.nodeType == 9 || tinyMCE.isBlockElement(node))
+				break;
+
+			startChop = node;
+		} while ((node = node.previousSibling ? node.previousSibling : node.parentNode));
+
+		// Get endChop node
+		node = endChop;
+		do {
+			if (node == body || node.nodeType == 9 || tinyMCE.isBlockElement(node))
+				break;
+
+			endChop = node;
+		} while ((node = node.nextSibling ? node.nextSibling : node.parentNode));
+
+		// Fix when only a image is within the TD
+		if (startChop.nodeName == "TD")
+			startChop = startChop.firstChild;
+
+		if (endChop.nodeName == "TD")
+			endChop = endChop.lastChild;
+
+		// If not in a block element
+		if (startBlock == null) {
+			// Delete selection
+			rng.deleteContents();
+
+			if (!tinyMCE.isSafari)
+				sel.removeAllRanges();
+
+			if (startChop != rootElm && endChop != rootElm) {
+				// Insert paragraph before
+				rngBefore = rng.cloneRange();
+
+				if (startChop == body)
+					rngBefore.setStart(startChop, 0);
+				else
+					rngBefore.setStartBefore(startChop);
+
+				paraBefore.appendChild(rngBefore.cloneContents());
+
+				// Insert paragraph after
+				if (endChop.parentNode.nodeName == blockName)
+					endChop = endChop.parentNode;
+
+				// If not after image
+				//if (rng.startContainer.nodeName != "BODY" && rng.endContainer.nodeName != "BODY")
+					rng.setEndAfter(endChop);
+
+				if (endChop.nodeName != "#text" && endChop.nodeName != "BODY")
+					rngBefore.setEndAfter(endChop);
+
+				contents = rng.cloneContents();
+				if (contents.firstChild && (contents.firstChild.nodeName == blockName || contents.firstChild.nodeName == "BODY"))
+					paraAfter.innerHTML = contents.firstChild.innerHTML;
+				else
+					paraAfter.appendChild(contents);
+
+				// Check if it's a empty paragraph
+				if (isEmpty(paraBefore))
+					paraBefore.innerHTML = "&nbsp;";
+
+				// Check if it's a empty paragraph
+				if (isEmpty(paraAfter))
+					paraAfter.innerHTML = "&nbsp;";
+
+				// Delete old contents
+				rng.deleteContents();
+				rngAfter.deleteContents();
+				rngBefore.deleteContents();
+
+				// Insert new paragraphs
+				if (tinyMCE.isOpera) {
+					paraBefore.normalize();
+					rngBefore.insertNode(paraBefore);
+					paraAfter.normalize();
+					rngBefore.insertNode(paraAfter);
+				} else {
+					paraAfter.normalize();
+					rngBefore.insertNode(paraAfter);
+					paraBefore.normalize();
+					rngBefore.insertNode(paraBefore);
+				}
+
+				//tinyMCE.debug("1: ", paraBefore.innerHTML, paraAfter.innerHTML);
+			} else {
+				body.innerHTML = "<" + blockName + ">&nbsp;</" + blockName + "><" + blockName + ">&nbsp;</" + blockName + ">";
+				paraAfter = body.childNodes[1];
+			}
+
+			inst.selection.moveToBookmark(b);
+			inst.selection.selectNode(paraAfter, true, true);
+
+			return true;
+		}
+
+		// Place first part within new paragraph
+		if (startChop.nodeName == blockName)
+			rngBefore.setStart(startChop, 0);
+		else
+			rngBefore.setStartBefore(startChop);
+
+		rngBefore.setEnd(startNode, startOffset);
+		paraBefore.appendChild(rngBefore.cloneContents());
+
+		// Place secound part within new paragraph
+		rngAfter.setEndAfter(endChop);
+		rngAfter.setStart(endNode, endOffset);
+		contents = rngAfter.cloneContents();
+
+		if (contents.firstChild && contents.firstChild.nodeName == blockName) {
+	/*		var nodes = contents.firstChild.childNodes;
+			for (var i=0; i<nodes.length; i++) {
+				//tinyMCE.debug(nodes[i].nodeName);
+				if (nodes[i].nodeName != "BODY")
+					paraAfter.appendChild(nodes[i]);
+			}
+	*/
+			paraAfter.innerHTML = contents.firstChild.innerHTML;
+		} else
+			paraAfter.appendChild(contents);
+
+		// Check if it's a empty paragraph
+		if (isEmpty(paraBefore))
+			paraBefore.innerHTML = "&nbsp;";
+
+		// Check if it's a empty paragraph
+		if (isEmpty(paraAfter))
+			paraAfter.innerHTML = "&nbsp;";
+
+		// Create a range around everything
+		rng = doc.createRange();
+
+		if (!startChop.previousSibling && startChop.parentNode.nodeName.toUpperCase() == blockName) {
+			rng.setStartBefore(startChop.parentNode);
+		} else {
+			if (rngBefore.startContainer.nodeName.toUpperCase() == blockName && rngBefore.startOffset == 0)
+				rng.setStartBefore(rngBefore.startContainer);
+			else
+				rng.setStart(rngBefore.startContainer, rngBefore.startOffset);
+		}
+
+		if (!endChop.nextSibling && endChop.parentNode.nodeName.toUpperCase() == blockName)
+			rng.setEndAfter(endChop.parentNode);
+		else
+			rng.setEnd(rngAfter.endContainer, rngAfter.endOffset);
+
+		// Delete all contents and insert new paragraphs
+		rng.deleteContents();
+
+		if (tinyMCE.isOpera) {
+			rng.insertNode(paraBefore);
+			rng.insertNode(paraAfter);
+		} else {
+			rng.insertNode(paraAfter);
+			rng.insertNode(paraBefore);
+		}
+
+		//tinyMCE.debug("2", paraBefore.innerHTML, paraAfter.innerHTML);
+
+		// Normalize
+		paraAfter.normalize();
+		paraBefore.normalize();
+
+		inst.selection.moveToBookmark(b);
+		inst.selection.selectNode(paraAfter, true, true);
+
+		return true;
+	},
+
+	_handleBackSpace : function(inst) {
+		var r = inst.getRng(), sn = r.startContainer, nv, s = false;
+
+		// Added body check for bug #1527787
+		if (sn && sn.nextSibling && sn.nextSibling.nodeName == "BR" && sn.parentNode.nodeName != "BODY") {
+			nv = sn.nodeValue;
+
+			// Handle if a backspace is pressed after a space character #bug 1466054 removed since fix for #1527787
+			/*if (nv != null && nv.length >= r.startOffset && nv.charAt(r.startOffset - 1) == ' ')
+				s = true;*/
+
+			// Only remove BRs if we are at the end of line #bug 1464152
+			if (nv != null && r.startOffset == nv.length)
+				sn.nextSibling.parentNode.removeChild(sn.nextSibling);
+		}
+
+		if (inst.settings.auto_resize)
+			inst.resizeToContent();
+
+		return s;
+	}
+
+	};
+
+/* file:jscripts/tiny_mce/classes/TinyMCE_Layer.class.js */
+
+function TinyMCE_Layer(id, bm) {
+	this.id = id;
+	this.blockerElement = null;
+	this.events = false;
+	this.element = null;
+	this.blockMode = typeof(bm) != 'undefined' ? bm : true;
+	this.doc = document;
+};
+
+TinyMCE_Layer.prototype = {
+	moveRelativeTo : function(re, p) {
+		var rep = this.getAbsPosition(re);
+		var w = parseInt(re.offsetWidth);
+		var h = parseInt(re.offsetHeight);
+		var e = this.getElement();
+		var ew = parseInt(e.offsetWidth);
+		var eh = parseInt(e.offsetHeight);
+		var x, y;
+
+		switch (p) {
+			case "tl":
+				x = rep.absLeft;
+				y = rep.absTop;
+				break;
+
+			case "tr":
+				x = rep.absLeft + w;
+				y = rep.absTop;
+				break;
+
+			case "bl":
+				x = rep.absLeft;
+				y = rep.absTop + h;
+				break;
+
+			case "br":
+				x = rep.absLeft + w;
+				y = rep.absTop + h;
+				break;
+
+			case "cc":
+				x = rep.absLeft + (w / 2) - (ew / 2);
+				y = rep.absTop + (h / 2) - (eh / 2);
+				break;
+		}
+
+		this.moveTo(x, y);
+	},
+
+	moveBy : function(x, y) {
+		var e = this.getElement();
+		this.moveTo(parseInt(e.style.left) + x, parseInt(e.style.top) + y);
+	},
+
+	moveTo : function(x, y) {
+		var e = this.getElement();
+
+		e.style.left = x + "px";
+		e.style.top = y + "px";
+
+		this.updateBlocker();
+	},
+
+	resizeBy : function(w, h) {
+		var e = this.getElement();
+		this.resizeTo(parseInt(e.style.width) + w, parseInt(e.style.height) + h);
+	},
+
+	resizeTo : function(w, h) {
+		var e = this.getElement();
+
+		if (w != null)
+			e.style.width = w + "px";
+
+		if (h != null)
+			e.style.height = h + "px";
+
+		this.updateBlocker();
+	},
+
+	show : function() {
+		var el = this.getElement();
+
+		if (el) {
+			el.style.display = 'block';
+			this.updateBlocker();
+		}
+	},
+
+	hide : function() {
+		var el = this.getElement();
+
+		if (el) {
+			el.style.display = 'none';
+			this.updateBlocker();
+		}
+	},
+
+	isVisible : function() {
+		return this.getElement().style.display == 'block';
+	},
+
+	getElement : function() {
+		if (!this.element)
+			this.element = this.doc.getElementById(this.id);
+
+		return this.element;
+	},
+
+	setBlockMode : function(s) {
+		this.blockMode = s;
+	},
+
+	updateBlocker : function() {
+		var e, b, x, y, w, h;
+
+		b = this.getBlocker();
+		if (b) {
+			if (this.blockMode) {
+				e = this.getElement();
+				x = this.parseInt(e.style.left);
+				y = this.parseInt(e.style.top);
+				w = this.parseInt(e.offsetWidth);
+				h = this.parseInt(e.offsetHeight);
+
+				b.style.left = x + 'px';
+				b.style.top = y + 'px';
+				b.style.width = w + 'px';
+				b.style.height = h + 'px';
+				b.style.display = e.style.display;
+			} else
+				b.style.display = 'none';
+		}
+	},
+
+	getBlocker : function() {
+		var d, b;
+
+		if (!this.blockerElement && this.blockMode) {
+			d = this.doc;
+			b = d.getElementById(this.id + "_blocker");
+
+			if (!b) {
+				b = d.createElement("iframe");
+
+				b.setAttribute('id', this.id + "_blocker");
+				b.style.cssText = 'display: none; position: absolute; left: 0; top: 0';
+				b.src = 'javascript:false;';
+				b.frameBorder = '0';
+				b.scrolling = 'no';
+	
+				d.body.appendChild(b);
+			}
+
+			this.blockerElement = b;
+		}
+
+		return this.blockerElement;
+	},
+
+	getAbsPosition : function(n) {
+		var p = {absLeft : 0, absTop : 0};
+
+		while (n) {
+			p.absLeft += n.offsetLeft;
+			p.absTop += n.offsetTop;
+			n = n.offsetParent;
+		}
+
+		return p;
+	},
+
+	create : function(n, c, p, h) {
+		var d = this.doc, e = d.createElement(n);
+
+		e.setAttribute('id', this.id);
+
+		if (c)
+			e.className = c;
+
+		if (!p)
+			p = d.body;
+
+		if (h)
+			e.innerHTML = h;
+
+		p.appendChild(e);
+
+		return this.element = e;
+	},
+
+	exists : function() {
+		return this.doc.getElementById(this.id) != null;
+	},
+
+	parseInt : function(s) {
+		if (s == null || s == '')
+			return 0;
+
+		return parseInt(s);
+	},
+
+	remove : function() {
+		var e = this.getElement(), b = this.getBlocker();
+
+		if (e)
+			e.parentNode.removeChild(e);
+
+		if (b)
+			b.parentNode.removeChild(b);
+	}
+
+	};
+
+/* file:jscripts/tiny_mce/classes/TinyMCE_Menu.class.js */
+
+function TinyMCE_Menu() {
+	var id;
+
+	if (typeof(tinyMCE.menuCounter) == "undefined")
+		tinyMCE.menuCounter = 0;
+
+	id = "mc_menu_" + tinyMCE.menuCounter++;
+
+	TinyMCE_Layer.call(this, id, true);
+
+	this.id = id;
+	this.items = new Array();
+	this.needsUpdate = true;
+};
+
+TinyMCE_Menu.prototype = tinyMCE.extend(TinyMCE_Layer.prototype, {
+	init : function(s) {
+		var n;
+
+		// Default params
+		this.settings = {
+			separator_class : 'mceMenuSeparator',
+			title_class : 'mceMenuTitle',
+			disabled_class : 'mceMenuDisabled',
+			menu_class : 'mceMenu',
+			drop_menu : true
+		};
+
+		for (n in s)
+			this.settings[n] = s[n];
+
+		this.create('div', this.settings.menu_class);
+	},
+
+	clear : function() {
+		this.items = new Array();
+	},
+
+	addTitle : function(t) {
+		this.add({type : 'title', text : t});
+	},
+
+	addDisabled : function(t) {
+		this.add({type : 'disabled', text : t});
+	},
+
+	addSeparator : function() {
+		this.add({type : 'separator'});
+	},
+
+	addItem : function(t, js) {
+		this.add({text : t, js : js});
+	},
+
+	add : function(mi) {
+		this.items[this.items.length] = mi;
+		this.needsUpdate = true;
+	},
+
+	update : function() {
+		var e = this.getElement(), h = '', i, t, m = this.items, s = this.settings;
+
+		if (this.settings.drop_menu)
+			h += '<span class="mceMenuLine"></span>';
+
+		h += '<table border="0" cellpadding="0" cellspacing="0">';
+
+		for (i=0; i<m.length; i++) {
+			t = tinyMCE.xmlEncode(m[i].text);
+			c = m[i].class_name ? ' class="' + m[i].class_name + '"' : '';
+
+			switch (m[i].type) {
+				case 'separator':
+					h += '<tr class="' + s.separator_class + '"><td>';
+					break;
+
+				case 'title':
+					h += '<tr class="' + s.title_class + '"><td><span' + c +'>' + t + '</span>';
+					break;
+
+				case 'disabled':
+					h += '<tr class="' + s.disabled_class + '"><td><span' + c +'>' + t + '</span>';
+					break;
+
+				default:
+					h += '<tr><td><a href="' + tinyMCE.xmlEncode(m[i].js) + '" onmousedown="' + tinyMCE.xmlEncode(m[i].js) + ';return tinyMCE.cancelEvent(event);" onclick="return tinyMCE.cancelEvent(event);" onmouseup="return tinyMCE.cancelEvent(event);"><span' + c +'>' + t + '</span></a>';
+			}
+
+			h += '</td></tr>';
+		}
+
+		h += '</table>';
+
+		e.innerHTML = h;
+
+		this.needsUpdate = false;
+		this.updateBlocker();
+	},
+
+	show : function() {
+		var nl, i;
+
+		if (tinyMCE.lastMenu == this)
+			return;
+
+		if (this.needsUpdate)
+			this.update();
+
+		if (tinyMCE.lastMenu && tinyMCE.lastMenu != this)
+			tinyMCE.lastMenu.hide();
+
+		TinyMCE_Layer.prototype.show.call(this);
+
+		if (!tinyMCE.isOpera) {
+			// Accessibility stuff
+/*			nl = this.getElement().getElementsByTagName("a");
+			if (nl.length > 0)
+				nl[0].focus();*/
+		}
+
+		tinyMCE.lastMenu = this;
+	}
+
+	});
+
+/* file:jscripts/tiny_mce/classes/TinyMCE_Compatibility.class.js */
+
+if (!Function.prototype.call) {
+	Function.prototype.call = function() {
+		var a = arguments, s = a[0], i, as = '', r, o;
+
+		for (i=1; i<a.length; i++)
+			as += (i > 1 ? ',' : '') + 'a[' + i + ']';
+
+		o = s._fu;
+		s._fu = this;
+		r = eval('s._fu(' + as + ')');
+		s._fu = o;
+
+		return r;
+	};
+};
+
+/* file:jscripts/tiny_mce/classes/TinyMCE_Debug.class.js */
+
+TinyMCE_Engine.prototype.debug = function() {
+	var m = "", a, i, l = tinyMCE.log.length;
+
+	for (i=0, a = this.debug.arguments; i<a.length; i++) {
+		m += a[i];
+
+		if (i<a.length-1)
+			m += ', ';
+	}
+
+	if (l < 1000)
+		tinyMCE.log[l] = "[debug] " + m;
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/utils/editable_selects.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,61 @@
+/**
+ * $Id: editable_selects.js 162 2007-01-03 16:16:52Z spocke $
+ *
+ * Makes select boxes editable.
+ *
+ * @author Moxiecode
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+var TinyMCE_EditableSelects = {
+	editSelectElm : null,
+
+	init : function() {
+		var nl = document.getElementsByTagName("select"), i, d = document, o;
+
+		for (i=0; i<nl.length; i++) {
+			if (nl[i].className.indexOf('mceEditableSelect') != -1) {
+				o = new Option('(value)', '__mce_add_custom__');
+
+				o.className = 'mceAddSelectValue';
+
+				nl[i].options[nl[i].options.length] = o;
+				nl[i].setAttribute('onchange', 'TinyMCE_EditableSelects.onChangeEditableSelect(this);');
+			}
+		}
+	},
+
+	onChangeEditableSelect : function(se) {
+		var d = document, ne;
+
+		if (se.options[se.selectedIndex].value == '__mce_add_custom__') {
+			ne = d.createElement("input");
+			ne.id = se.id + "_custom";
+			ne.name = se.name + "_custom";
+			ne.type = "text";
+
+			ne.style.width = se.clientWidth;
+			se.parentNode.insertBefore(ne, se);
+			se.style.display = 'none';
+			ne.focus();
+			ne.onblur = TinyMCE_EditableSelects.onBlurEditableSelectInput;
+			TinyMCE_EditableSelects.editSelectElm = se;
+		}
+	},
+
+	onBlurEditableSelectInput : function() {
+		var se = TinyMCE_EditableSelects.editSelectElm;
+
+		if (se) {
+			if (se.previousSibling.value != '') {
+				addSelectValue(document.forms[0], se.id, se.previousSibling.value, se.previousSibling.value);
+				selectByValue(document.forms[0], se.id, se.previousSibling.value);
+			} else
+				selectByValue(document.forms[0], se.id, '');
+
+			se.style.display = 'inline';
+			se.parentNode.removeChild(se.previousSibling);
+			TinyMCE_EditableSelects.editSelectElm = null;
+		}
+	}
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/utils/form_utils.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,210 @@
+/**
+ * $Id: form_utils.js 162 2007-01-03 16:16:52Z spocke $
+ *
+ * Various form utilitiy functions.
+ *
+ * @author Moxiecode
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+var themeBaseURL = tinyMCE.baseURL + '/themes/' + tinyMCE.getParam("theme");
+
+function getColorPickerHTML(id, target_form_element) {
+	var h = "";
+
+	h += '<a id="' + id + '_link" href="javascript:void(0);" onkeydown="pickColor(event,\'' + target_form_element +'\');" onmousedown="pickColor(event,\'' + target_form_element +'\');return false;">';
+	h += '<img id="' + id + '" src="' + themeBaseURL + '/images/color.gif"';
+	h += ' onmouseover="this.className=\'mceButtonOver\'"';
+	h += ' onmouseout="this.className=\'mceButtonNormal\'"';
+	h += ' onmousedown="this.className=\'mceButtonDown\'"';
+	h += ' width="20" height="16" border="0" title="' + tinyMCE.getLang('lang_browse') + '"';
+	h += ' class="mceButtonNormal" alt="' + tinyMCE.getLang('lang_browse') + '" /></a>';
+
+	return h;
+}
+
+function pickColor(e, target_form_element) {
+	if ((e.keyCode == 32 || e.keyCode == 13) || e.type == "mousedown")
+		tinyMCEPopup.pickColor(e, target_form_element);
+}
+
+function updateColor(img_id, form_element_id) {
+	document.getElementById(img_id).style.backgroundColor = document.forms[0].elements[form_element_id].value;
+}
+
+function setBrowserDisabled(id, state) {
+	var img = document.getElementById(id);
+	var lnk = document.getElementById(id + "_link");
+
+	if (lnk) {
+		if (state) {
+			lnk.setAttribute("realhref", lnk.getAttribute("href"));
+			lnk.removeAttribute("href");
+			tinyMCE.switchClass(img, 'mceButtonDisabled', true);
+		} else {
+			lnk.setAttribute("href", lnk.getAttribute("realhref"));
+			tinyMCE.switchClass(img, 'mceButtonNormal', false);
+		}
+	}
+}
+
+function getBrowserHTML(id, target_form_element, type, prefix) {
+	var option = prefix + "_" + type + "_browser_callback";
+	var cb = tinyMCE.getParam(option, tinyMCE.getParam("file_browser_callback"));
+	if (cb == null)
+		return "";
+
+	var html = "";
+
+	html += '<a id="' + id + '_link" href="javascript:openBrower(\'' + id + '\',\'' + target_form_element + '\', \'' + type + '\',\'' + option + '\');" onmousedown="return false;">';
+	html += '<img id="' + id + '" src="' + themeBaseURL + '/images/browse.gif"';
+	html += ' onmouseover="this.className=\'mceButtonOver\';"';
+	html += ' onmouseout="this.className=\'mceButtonNormal\';"';
+	html += ' onmousedown="this.className=\'mceButtonDown\';"';
+	html += ' width="20" height="18" border="0" title="' + tinyMCE.getLang('lang_browse') + '"';
+	html += ' class="mceButtonNormal" alt="' + tinyMCE.getLang('lang_browse') + '" /></a>';
+
+	return html;
+}
+
+function openBrower(img_id, target_form_element, type, option) {
+	var img = document.getElementById(img_id);
+
+	if (img.className != "mceButtonDisabled")
+		tinyMCEPopup.openBrowser(target_form_element, type, option);
+}
+
+function selectByValue(form_obj, field_name, value, add_custom, ignore_case) {
+	if (!form_obj || !form_obj.elements[field_name])
+		return;
+
+	var sel = form_obj.elements[field_name];
+
+	var found = false;
+	for (var i=0; i<sel.options.length; i++) {
+		var option = sel.options[i];
+
+		if (option.value == value || (ignore_case && option.value.toLowerCase() == value.toLowerCase())) {
+			option.selected = true;
+			found = true;
+		} else
+			option.selected = false;
+	}
+
+	if (!found && add_custom && value != '') {
+		var option = new Option(value, value);
+		option.selected = true;
+		sel.options[sel.options.length] = option;
+		sel.selectedIndex = sel.options.length - 1;
+	}
+
+	return found;
+}
+
+function getSelectValue(form_obj, field_name) {
+	var elm = form_obj.elements[field_name];
+
+	if (elm == null || elm.options == null)
+		return "";
+
+	return elm.options[elm.selectedIndex].value;
+}
+
+function addSelectValue(form_obj, field_name, name, value) {
+	var s = form_obj.elements[field_name];
+	var o = new Option(name, value);
+	s.options[s.options.length] = o;
+}
+
+function addClassesToList(list_id, specific_option) {
+	// Setup class droplist
+	var styleSelectElm = document.getElementById(list_id);
+	var styles = tinyMCE.getParam('theme_advanced_styles', false);
+	styles = tinyMCE.getParam(specific_option, styles);
+
+	if (styles) {
+		var stylesAr = styles.split(';');
+
+		for (var i=0; i<stylesAr.length; i++) {
+			if (stylesAr != "") {
+				var key, value;
+
+				key = stylesAr[i].split('=')[0];
+				value = stylesAr[i].split('=')[1];
+
+				styleSelectElm.options[styleSelectElm.length] = new Option(key, value);
+			}
+		}
+	} else {
+		// Use auto impored classes
+		var csses = tinyMCE.getCSSClasses(tinyMCE.getWindowArg('editor_id'));
+		for (var i=0; i<csses.length; i++)
+			styleSelectElm.options[styleSelectElm.length] = new Option(csses[i], csses[i]);
+	}
+}
+
+function isVisible(element_id) {
+	var elm = document.getElementById(element_id);
+
+	return elm && elm.style.display != "none";
+}
+
+function convertRGBToHex(col) {
+	var re = new RegExp("rgb\\s*\\(\\s*([0-9]+).*,\\s*([0-9]+).*,\\s*([0-9]+).*\\)", "gi");
+
+	var rgb = col.replace(re, "$1,$2,$3").split(',');
+	if (rgb.length == 3) {
+		r = parseInt(rgb[0]).toString(16);
+		g = parseInt(rgb[1]).toString(16);
+		b = parseInt(rgb[2]).toString(16);
+
+		r = r.length == 1 ? '0' + r : r;
+		g = g.length == 1 ? '0' + g : g;
+		b = b.length == 1 ? '0' + b : b;
+
+		return "#" + r + g + b;
+	}
+
+	return col;
+}
+
+function convertHexToRGB(col) {
+	if (col.indexOf('#') != -1) {
+		col = col.replace(new RegExp('[^0-9A-F]', 'gi'), '');
+
+		r = parseInt(col.substring(0, 2), 16);
+		g = parseInt(col.substring(2, 4), 16);
+		b = parseInt(col.substring(4, 6), 16);
+
+		return "rgb(" + r + "," + g + "," + b + ")";
+	}
+
+	return col;
+}
+
+function trimSize(size) {
+	return size.replace(new RegExp('[^0-9%]', 'gi'), '');
+}
+
+function getCSSSize(size) {
+	size = trimSize(size);
+
+	if (size == "")
+		return "";
+
+	return size.indexOf('%') != -1 ? size : size + "px";
+}
+
+function getStyle(elm, attrib, style) {
+	var val = tinyMCE.getAttrib(elm, attrib);
+
+	if (val != '')
+		return '' + val;
+
+	if (typeof(style) == 'undefined')
+		style = attrib;
+
+	val = eval('elm.style.' + style);
+
+	return val == null ? '' : '' + val;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/utils/mclayer.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,210 @@
+/**
+ * $Id: mclayer.js 162 2007-01-03 16:16:52Z spocke $
+ *
+ * Moxiecode floating layer script.
+ *
+ * @author Moxiecode
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+function MCLayer(id) {
+	this.id = id;
+	this.settings = new Array();
+	this.blockerElement = null;
+	this.isMSIE = navigator.appName == "Microsoft Internet Explorer";
+	this.events = false;
+	this.autoHideCallback = null;
+}
+
+MCLayer.prototype = {
+	moveRelativeTo : function(re, p, a) {
+		var rep = this.getAbsPosition(re);
+		var w = parseInt(re.offsetWidth);
+		var h = parseInt(re.offsetHeight);
+		var x, y;
+
+		switch (p) {
+			case "tl":
+				break;
+
+			case "tr":
+				x = rep.absLeft + w;
+				y = rep.absTop;
+				break;
+
+			case "bl":
+				break;
+
+			case "br":
+				break;
+		}
+
+		this.moveTo(x, y);
+	},
+
+	moveBy : function(dx, dy) {
+		var e = this.getElement();
+		var x = parseInt(e.style.left);
+		var y = parseInt(e.style.top);
+
+		e.style.left = (x + dx) + "px";
+		e.style.top = (y + dy) + "px";
+
+		this.updateBlocker();
+	},
+
+	moveTo : function(x, y) {
+		var e = this.getElement();
+
+		e.style.left = x + "px";
+		e.style.top = y + "px";
+
+		this.updateBlocker();
+	},
+
+	show : function() {
+		MCLayer.visibleLayer = this;
+
+		this.getElement().style.display = 'block';
+		this.updateBlocker();
+	},
+
+	hide : function() {
+		this.getElement().style.display = 'none';
+		this.updateBlocker();
+	},
+
+	setAutoHide : function(s, cb) {
+		this.autoHideCallback = cb;
+		this.registerEventHandlers();
+	},
+
+	getElement : function() {
+		return document.getElementById(this.id);
+	},
+
+	updateBlocker : function() {
+		if (!this.isMSIE)
+			return;
+
+		var e = this.getElement();
+		var b = this.getBlocker();
+		var x = this.parseInt(e.style.left);
+		var y = this.parseInt(e.style.top);
+		var w = this.parseInt(e.offsetWidth);
+		var h = this.parseInt(e.offsetHeight);
+
+		b.style.left = x + 'px';
+		b.style.top = y + 'px';
+		b.style.width = w + 'px';
+		b.style.height = h + 'px';
+		b.style.display = e.style.display;
+	},
+
+	getBlocker : function() {
+		if (!this.blockerElement) {
+			var d = document, b = d.createElement("iframe");
+
+			b.style.cssText = 'display: none; left: 0px; position: absolute; top: 0';
+			b.src = 'javascript:false;';
+			b.frameBorder = '0';
+			b.scrolling = 'no';
+
+			d.body.appendChild(b);
+			this.blockerElement = b;
+		}
+
+		return this.blockerElement;
+	},
+
+	getAbsPosition : function(n) {
+		var p = {absLeft : 0, absTop : 0};
+
+		while (n) {
+			p.absLeft += n.offsetLeft;
+			p.absTop += n.offsetTop;
+			n = n.offsetParent;
+		}
+
+		return p;
+	},
+
+	registerEventHandlers : function() {
+		if (!this.events) {
+			var d = document;
+
+			this.addEvent(d, 'mousedown', MCLayer.prototype.onMouseDown);
+
+			this.events = true;
+		}
+	},
+
+	addEvent : function(o, n, h) {
+		if (o.attachEvent)
+			o.attachEvent("on" + n, h);
+		else
+			o.addEventListener(n, h, false);
+	},
+
+	onMouseDown : function(e) {
+		e = typeof(e) == "undefined" ? window.event : e;
+		var b = document.body;
+		var l = MCLayer.visibleLayer;
+
+		if (l) {
+			var mx = l.isMSIE ? e.clientX + b.scrollLeft : e.pageX;
+			var my = l.isMSIE ? e.clientY + b.scrollTop : e.pageY;
+			var el = l.getElement();
+			var x = parseInt(el.style.left);
+			var y = parseInt(el.style.top);
+			var w = parseInt(el.offsetWidth);
+			var h = parseInt(el.offsetHeight);
+
+			if (!(mx > x && mx < x + w && my > y && my < y + h)) {
+				MCLayer.visibleLayer = null;
+
+				if (l.autoHideCallback && l.autoHideCallback(l, e, mx, my))
+					return true;
+
+				l.hide();
+			}
+		}
+	},
+
+	addCSSClass : function(e, c) {
+		this.removeCSSClass(e, c);
+		var a = this.explode(' ', e.className);
+		a[a.length] = c;
+		e.className = a.join(' ');
+	},
+
+	removeCSSClass : function(e, c) {
+		var a = this.explode(' ', e.className), i;
+
+		for (i=0; i<a.length; i++) {
+			if (a[i] == c)
+				a[i] = '';
+		}
+
+		e.className = a.join(' ');
+	},
+
+	explode : function(d, s) {
+		var ar = s.split(d);
+		var oar = new Array();
+
+		for (var i = 0; i<ar.length; i++) {
+			if (ar[i] != "")
+				oar[oar.length] = ar[i];
+		}
+
+		return oar;
+	},
+
+	parseInt : function(s) {
+		if (s == null || s == '')
+			return 0;
+
+		return parseInt(s);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/utils/mctabs.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,74 @@
+/**
+ * $Id: mctabs.js 162 2007-01-03 16:16:52Z spocke $
+ *
+ * Moxiecode DHTML Tabs script.
+ *
+ * @author Moxiecode
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+function MCTabs() {
+	this.settings = new Array();
+};
+
+MCTabs.prototype.init = function(settings) {
+	this.settings = settings;
+};
+
+MCTabs.prototype.getParam = function(name, default_value) {
+	var value = null;
+
+	value = (typeof(this.settings[name]) == "undefined") ? default_value : this.settings[name];
+
+	// Fix bool values
+	if (value == "true" || value == "false")
+		return (value == "true");
+
+	return value;
+};
+
+MCTabs.prototype.displayTab = function(tab_id, panel_id) {
+	var panelElm = document.getElementById(panel_id);
+	var panelContainerElm = panelElm ? panelElm.parentNode : null;
+	var tabElm = document.getElementById(tab_id);
+	var tabContainerElm = tabElm ? tabElm.parentNode : null;
+	var selectionClass = this.getParam('selection_class', 'current');
+
+	if (tabElm && tabContainerElm) {
+		var nodes = tabContainerElm.childNodes;
+
+		// Hide all other tabs
+		for (var i=0; i<nodes.length; i++) {
+			if (nodes[i].nodeName == "LI")
+				nodes[i].className = '';
+		}
+
+		// Show selected tab
+		tabElm.className = 'current';
+	}
+
+	if (panelElm && panelContainerElm) {
+		var nodes = panelContainerElm.childNodes;
+
+		// Hide all other panels
+		for (var i=0; i<nodes.length; i++) {
+			if (nodes[i].nodeName == "DIV")
+				nodes[i].className = 'panel';
+		}
+
+		// Show selected panel
+		panelElm.className = 'current';
+	}
+};
+
+MCTabs.prototype.getAnchor = function() {
+	var pos, url = document.location.href;
+
+	if ((pos = url.lastIndexOf('#')) != -1)
+		return url.substring(pos + 1);
+
+	return "";
+};
+
+// Global instance
+var mcTabs = new MCTabs();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/utils/validate.js	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,219 @@
+/**
+ * $Id: validate.js 162 2007-01-03 16:16:52Z spocke $
+ *
+ * Various form validation methods.
+ *
+ * @author Moxiecode
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+/**
+	// String validation:
+
+	if (!Validator.isEmail('myemail'))
+		alert('Invalid email.');
+
+	// Form validation:
+
+	var f = document.forms['myform'];
+
+	if (!Validator.isEmail(f.myemail))
+		alert('Invalid email.');
+*/
+
+var Validator = {
+	isEmail : function(s) {
+		return this.test(s, '^[-!#$%&\'*+\\./0-9=?A-Z^_`a-z{|}~]+@[-!#$%&\'*+\\/0-9=?A-Z^_`a-z{|}~]+\.[-!#$%&\'*+\\./0-9=?A-Z^_`a-z{|}~]+$');
+	},
+
+	isAbsUrl : function(s) {
+		return this.test(s, '^(news|telnet|nttp|file|http|ftp|https)://[-A-Za-z0-9\\.]+\\/?.*$');
+	},
+
+	isSize : function(s) {
+		return this.test(s, '^[0-9]+(px|%)?$');
+	},
+
+	isId : function(s) {
+		return this.test(s, '^[A-Za-z_]([A-Za-z0-9_])*$');
+	},
+
+	isEmpty : function(s) {
+		var nl, i;
+
+		if (s.nodeName == 'SELECT' && s.selectedIndex < 1)
+			return true;
+
+		if (s.type == 'checkbox' && !s.checked)
+			return true;
+
+		if (s.type == 'radio') {
+			for (i=0, nl = s.form.elements; i<nl.length; i++) {
+				if (nl[i].type == "radio" && nl[i].name == s.name && nl[i].checked)
+					return false;
+			}
+
+			return true;
+		}
+
+		return new RegExp('^\\s*$').test(s.nodeType == 1 ? s.value : s);
+	},
+
+	isNumber : function(s, d) {
+		return !isNaN(s.nodeType == 1 ? s.value : s) && (!d || !this.test(s, '^-?[0-9]*\\.[0-9]*$'));
+	},
+
+	test : function(s, p) {
+		s = s.nodeType == 1 ? s.value : s;
+
+		return s == '' || new RegExp(p).test(s);
+	}
+};
+
+var AutoValidator = {
+	settings : {
+		id_cls : 'id',
+		int_cls : 'int',
+		url_cls : 'url',
+		number_cls : 'number',
+		email_cls : 'email',
+		size_cls : 'size',
+		required_cls : 'required',
+		invalid_cls : 'invalid',
+		min_cls : 'min',
+		max_cls : 'max'
+	},
+
+	init : function(s) {
+		var n;
+
+		for (n in s)
+			this.settings[n] = s[n];
+	},
+
+	validate : function(f) {
+		var i, nl, s = this.settings, c = 0;
+
+		nl = this.tags(f, 'label');
+		for (i=0; i<nl.length; i++)
+			this.removeClass(nl[i], s.invalid_cls);
+
+		c += this.validateElms(f, 'input');
+		c += this.validateElms(f, 'select');
+		c += this.validateElms(f, 'textarea');
+
+		return c == 3;
+	},
+
+	invalidate : function(n) {
+		this.mark(n.form, n);
+	},
+
+	reset : function(e) {
+		var t = new Array('label', 'input', 'select', 'textarea');
+		var i, j, nl, s = this.settings;
+
+		if (e == null)
+			return;
+
+		for (i=0; i<t.length; i++) {
+			nl = this.tags(e.form ? e.form : e, t[i]);
+			for (j=0; j<nl.length; j++)
+				this.removeClass(nl[j], s.invalid_cls);
+		}
+	},
+
+	validateElms : function(f, e) {
+		var nl, i, n, s = this.settings, st = true, va = Validator, v;
+
+		nl = this.tags(f, e);
+		for (i=0; i<nl.length; i++) {
+			n = nl[i];
+
+			this.removeClass(n, s.invalid_cls);
+
+			if (this.hasClass(n, s.required_cls) && va.isEmpty(n))
+				st = this.mark(f, n);
+
+			if (this.hasClass(n, s.number_cls) && !va.isNumber(n))
+				st = this.mark(f, n);
+
+			if (this.hasClass(n, s.int_cls) && !va.isNumber(n, true))
+				st = this.mark(f, n);
+
+			if (this.hasClass(n, s.url_cls) && !va.isAbsUrl(n))
+				st = this.mark(f, n);
+
+			if (this.hasClass(n, s.email_cls) && !va.isEmail(n))
+				st = this.mark(f, n);
+
+			if (this.hasClass(n, s.size_cls) && !va.isSize(n))
+				st = this.mark(f, n);
+
+			if (this.hasClass(n, s.id_cls) && !va.isId(n))
+				st = this.mark(f, n);
+
+			if (this.hasClass(n, s.min_cls, true)) {
+				v = this.getNum(n, s.min_cls);
+
+				if (isNaN(v) || parseInt(n.value) < parseInt(v))
+					st = this.mark(f, n);
+			}
+
+			if (this.hasClass(n, s.max_cls, true)) {
+				v = this.getNum(n, s.max_cls);
+
+				if (isNaN(v) || parseInt(n.value) > parseInt(v))
+					st = this.mark(f, n);
+			}
+		}
+
+		return st;
+	},
+
+	hasClass : function(n, c, d) {
+		return new RegExp('\\b' + c + (d ? '[0-9]+' : '') + '\\b', 'g').test(n.className);
+	},
+
+	getNum : function(n, c) {
+		c = n.className.match(new RegExp('\\b' + c + '([0-9]+)\\b', 'g'))[0];
+		c = c.replace(/[^0-9]/g, '');
+
+		return c;
+	},
+
+	addClass : function(n, c, b) {
+		var o = this.removeClass(n, c);
+		n.className = b ? c + (o != '' ? (' ' + o) : '') : (o != '' ? (o + ' ') : '') + c;
+	},
+
+	removeClass : function(n, c) {
+		c = n.className.replace(new RegExp("(^|\\s+)" + c + "(\\s+|$)"), ' ');
+		return n.className = c != ' ' ? c : '';
+	},
+
+	tags : function(f, s) {
+		return f.getElementsByTagName(s);
+	},
+
+	mark : function(f, n) {
+		var s = this.settings;
+
+		this.addClass(n, s.invalid_cls);
+		this.markLabels(f, n, s.invalid_cls);
+
+		return false;
+	},
+
+	markLabels : function(f, n, ic) {
+		var nl, i;
+
+		nl = this.tags(f, "label");
+		for (i=0; i<nl.length; i++) {
+			if (nl[i].getAttribute("for") == n.id || nl[i].htmlFor == n.id)
+				this.addClass(nl[i], ic);
+		}
+
+		return null;
+	}
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/comment.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,363 @@
+<?php
+
+/*
+ * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
+ * Version 1.0 (Banshee)
+ * Copyright (C) 2006-2007 Dan Fuhry
+ *
+ * This program is Free Software; you can redistribute 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 details.
+ */
+
+/**
+ * Class that handles comments. Has HTML/Javascript frontend support.
+ * @package Enano CMS
+ * @subpackage Comment manager
+ * @license GNU General Public License <http://www.gnu.org/licenses/gpl.html>
+ */
+
+class Comments
+{
+  #
+  # VARIABLES
+  #
+  
+  /**
+   * Current list of comments.
+   * @var array
+   */
+  
+  var $comments = Array();
+  
+  /**
+   * Object to track permissions.
+   * @var object
+   */
+  
+  var $perms;
+  
+  #
+  # METHODS
+  #
+  
+  /**
+   * Constructor.
+   * @param string Page ID of the page to load comments for
+   * @param string Namespace of the page to load comments for
+   */
+  
+  function __construct($page_id, $namespace)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    // Initialize permissions
+    if ( $page_id == $paths->cpage['urlname_nons'] && $namespace == $paths->namespace )
+      $this->perms =& $GLOBALS['session'];
+    else
+      $this->perms = $session->fetch_page_acl($page_id, $namespace);
+    
+    $this->page_id = $db->escape($page_id);
+    $this->namespace = $db->escape($namespace);
+  }
+  
+  /**
+   * PHP 4 constructor.
+   * @see Comments::__construct
+   */
+  function Comments($page_id, $namespace)
+  {
+    $this->__construct($page_id, $namespace);
+  }
+  
+  /**
+   * Processes a command in JSON format.
+   * @param string The JSON-encoded input, probably something sent from the Javascript/AJAX frontend
+   */
+   
+  function process_json($json)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $parser = new Services_JSON(SERVICES_JSON_LOOSE_TYPE);
+    $data = $parser->decode($json);
+    if ( !isset($data['mode']) )
+    {
+      return $parser->encode(Array('mode'=>'error','error'=>'No mode defined!'));
+    }
+    $ret = Array();
+    $ret['mode'] = $data['mode'];
+    switch ( $data['mode'] )
+    {
+      case 'fetch':
+        if ( !$template->theme_loaded )
+          $template->load_theme();
+        if ( !isset($data['have_template']) )
+        {
+          $ret['template'] = file_get_contents(ENANO_ROOT . '/themes/' . $template->theme . '/comment.tpl');
+        }
+        $q = $db->sql_query('SELECT c.comment_id,c.name,c.subject,c.comment_data,c.time,c.approved,u.user_level,u.user_id,u.signature FROM '.table_prefix.'comments AS c
+                               LEFT JOIN '.table_prefix.'users AS u
+                                 ON (u.user_id=c.user_id)
+                               WHERE page_id=\'' . $this->page_id . '\'
+                                 AND namespace=\'' . $this->namespace . '\';');
+        $count_appr = 0;
+        $count_total = 0;
+        $count_unappr = 0;
+        $ret['comments'] = Array();
+        if (!$q)
+          $db->die_json();
+        if ( $row = $db->fetchrow() )
+        {
+          do {
+            
+            // Increment counters
+            $count_total++;
+            ( $row['approved'] == 1 ) ? $count_appr++ : $count_unappr++;
+            
+            if ( !$this->perms->get_permissions('mod_comments') && $row['approved'] == 0 )
+              continue;
+            
+            // Send the source
+            $row['comment_source'] = $row['comment_data'];
+            
+            // Format text
+            $row['comment_data'] = RenderMan::render($row['comment_data']);
+            
+            // Format date
+            $row['time'] = date('F d, Y h:i a', $row['time']);
+            
+            // Format signature
+            $row['signature'] = ( !empty($row['signature']) ) ? RenderMan::render($row['signature']) : '';
+            
+            // Add the comment to the list
+            $ret['comments'][] = $row;
+            
+          } while ( $row = $db->fetchrow() );
+        }
+        $db->free_result();
+        $ret['count_appr'] = $count_appr;
+        $ret['count_total'] = $count_total;
+        $ret['count_unappr'] = $count_unappr;
+        $ret['auth_mod_comments'] = $this->perms->get_permissions('mod_comments');
+        $ret['auth_post_comments'] = $this->perms->get_permissions('post_comments');
+        $ret['auth_edit_comments'] = $this->perms->get_permissions('edit_comments');
+        $ret['user_id'] = $session->user_id;
+        $ret['username'] = $session->username;
+        $ret['logged_in'] = $session->user_logged_in;
+        
+        $ret['user_level'] = Array();
+        $ret['user_level']['guest'] = USER_LEVEL_GUEST;
+        $ret['user_level']['member'] = USER_LEVEL_MEMBER;
+        $ret['user_level']['mod'] = USER_LEVEL_MOD;
+        $ret['user_level']['admin'] = USER_LEVEL_ADMIN;
+        
+        $ret['approval_needed'] = ( getConfig('approve_comments') == '1' );
+        $ret['guest_posting'] = getConfig('comments_need_login');
+        
+        if ( $ret['guest_posting'] == '1' && !$session->user_logged_in )
+        {
+          $session->kill_captcha();
+          $ret['captcha'] = $session->make_captcha();
+        }
+        break;
+      case 'edit':
+        $cid = (string)$data['id'];
+        if ( !preg_match('#^([0-9]+)$#i', $cid) || intval($cid) < 1 )
+        {
+          echo '{"mode":"error","error":"HACKING ATTEMPT"}';
+          return false;
+        }
+        $cid = intval($cid);
+        $q = $db->sql_query('SELECT c.user_id,c.approved FROM '.table_prefix.'comments c LEFT JOIN '.table_prefix.'users u ON (u.user_id=c.user_id) WHERE comment_id='.$cid.';');
+        if(!$q)
+          $db->die_json();
+        $row = $db->fetchrow();
+        $uid = intval($row['user_id']);
+        $can_edit = ( ( $uid == $session->user_id && $uid != 1 && $this->perms->get_permissions('edit_comments') ) || ( $this->perms->get_permissions('mod_comments') ) );
+        if(!$can_edit)
+        {
+          echo '{"mode":"error","error":"HACKING ATTEMPT"}';
+          return false;
+        }
+        $data['data'] = str_replace("\r", '', $data['data']); // Windows compatibility
+        $text = RenderMan::preprocess_text($data['data'], true, false);
+        $text2 = $db->escape($text);
+        $subj = $db->escape(htmlspecialchars($data['subj']));
+        $q = $db->sql_query('UPDATE '.table_prefix.'comments SET subject=\'' . $subj . '\',comment_data=\'' . $text2 . '\' WHERE comment_id=' . $cid . ';');
+        if(!$q)
+          $db->die_json();
+        $ret = Array(
+            'mode' => 'redraw',
+            'id'   => $data['local_id'],
+            'subj' => htmlspecialchars($data['subj']),
+            'text' => RenderMan::render($text),
+            'src'  => $text,
+            'approved' => $row['approved']
+          );
+        break;
+      case 'delete':
+        $cid = (string)$data['id'];
+        if ( !preg_match('#^([0-9]+)$#i', $cid) || intval($cid) < 1 )
+        {
+          echo '{"mode":"error","error":"HACKING ATTEMPT"}';
+          return false;
+        }
+        $cid = intval($cid);
+        $q = $db->sql_query('SELECT c.user_id FROM '.table_prefix.'comments c LEFT JOIN '.table_prefix.'users u ON (u.user_id=c.user_id) WHERE comment_id='.$cid.';');
+        if(!$q)
+          $db->die_json();
+        $row = $db->fetchrow();
+        $uid = intval($row['user_id']);
+        $can_edit = ( ( $uid == $session->user_id && $uid != 1 && $this->perms->get_permissions('edit_comments') ) || ( $this->perms->get_permissions('mod_comments') ) );
+        if(!$can_edit)
+        {
+          echo '{"mode":"error","error":"HACKING ATTEMPT"}';
+          return false;
+        }
+        $q = $db->sql_query('DELETE FROM '.table_prefix.'comments WHERE comment_id='.$cid.';');
+        if(!$q)
+          $db->die_json();
+        $ret = Array(
+            'mode' => 'annihilate',
+            'id'   => $data['local_id']
+          );
+        break;
+      case 'submit':
+        
+        // Now for a huge round of security checks...
+        
+        $errors = Array();
+        
+        // Authorization
+        // Like the rest of the ACL system, this call is a one-stop check for ALL ACL entries.
+        if ( !$this->perms->get_permissions('post_comments') )
+          $errors[] = 'An ACL entry is preventing the comment from being posted.';
+        
+        // Guest authorization
+        if ( getConfig('comments_need_login') == '2' && !$session->user_logged_in )
+          $errors[] = 'You need to log in before posting comments.';
+        
+        // CAPTCHA code
+        if ( getConfig('comments_need_login') == '1' && !$session->user_logged_in )
+        {
+          $real_code = $session->get_captcha($data['captcha_id']);
+          if ( $real_code != $data['captcha_code'] )
+            $errors[] = 'The confirmation code you entered was incorrect.';
+        }
+        
+        if ( count($errors) > 0 )
+        {
+          $ret = Array(
+            'mode' => 'error',
+            'error' => implode("\n", $errors)
+            );
+        }
+        else
+        {
+          // We're authorized!
+          
+          // Preprocess
+          $name = ( $session->user_logged_in ) ? htmlspecialchars($session->username) : htmlspecialchars($data['name']);
+          $subj = htmlspecialchars($data['subj']);
+          $text = RenderMan::preprocess_text($data['text'], true, false);
+          $src = $text;
+          $sql_text = $db->escape($text);
+          $text = RenderMan::render($text);
+          $appr = ( getConfig('approve_comments') == '1' ) ? '0' : '1';
+          $time = time();
+          $date = date('F d, Y h:i a', $time);
+          
+          // Send it to the database
+          $q = $db->sql_query('INSERT INTO '.table_prefix.'comments(page_id,namespace,name,subject,comment_data,approved, time, user_id) VALUES' .
+                              "('$this->page_id', '$this->namespace', '$name', '$subj', '$sql_text', $appr, $time, $session->user_id);");
+          if(!$q)
+            $db->die_json();
+          
+          // Re-fetch
+          $q = $db->sql_query('SELECT c.comment_id,c.name,c.subject,c.comment_data,c.time,c.approved,u.user_level,u.user_id,u.signature FROM '.table_prefix.'comments AS c
+                               LEFT JOIN '.table_prefix.'users AS u
+                                 ON (u.user_id=c.user_id)
+                               WHERE page_id=\'' . $this->page_id . '\'
+                                 AND namespace=\'' . $this->namespace . '\'
+                                 AND time='.$time.' ORDER BY comment_id DESC LIMIT 1;');
+          if(!$q)
+            $db->die_json();
+          
+          $row = $db->fetchrow();
+          $db->free_result();
+          $row['time'] = $date;
+          $row['comment_data'] = $text;
+          $row['comment_source'] = $src;
+          $ret = Array(
+              'mode' => 'materialize'
+            );
+          $ret = enano_safe_array_merge($ret, $row);
+          
+          $ret['auth_mod_comments'] = $this->perms->get_permissions('mod_comments');
+          $ret['auth_post_comments'] = $this->perms->get_permissions('post_comments');
+          $ret['auth_edit_comments'] = $this->perms->get_permissions('edit_comments');
+          $ret['user_id'] = $session->user_id;
+          $ret['username'] = $session->username;
+          $ret['logged_in'] = $session->user_logged_in;
+          $ret['signature'] = RenderMan::render($row['signature']);
+          
+          $ret['user_level_list'] = Array();
+          $ret['user_level_list']['guest'] = USER_LEVEL_GUEST;
+          $ret['user_level_list']['member'] = USER_LEVEL_MEMBER;
+          $ret['user_level_list']['mod'] = USER_LEVEL_MOD;
+          $ret['user_level_list']['admin'] = USER_LEVEL_ADMIN;
+          
+        }
+        
+        break;
+      case 'approve':
+        if ( !$this->perms->get_permissions('mod_comments') )
+        {
+          $ret = Array(
+          'mode' => 'error', 
+          'error' => 'You are not authorized to moderate comments.'
+          );
+          echo $parser->encode($ret);
+          return $ret;
+        }
+        
+        $cid = (string)$data['id'];
+        if ( !preg_match('#^([0-9]+)$#i', $cid) || intval($cid) < 1 )
+        {
+          echo '{"mode":"error","error":"HACKING ATTEMPT"}';
+          return false;
+        }
+        $cid = intval($cid);
+        $q = $db->sql_query('SELECT subject,approved FROM '.table_prefix.'comments WHERE comment_id='.$cid.';');
+        if(!$q || $db->numrows() < 1)
+          $db->die_json();
+        $row = $db->fetchrow();
+        $db->free_result();
+        $appr = ( $row['approved'] == '1' ) ? '0' : '1';
+        $q = $db->sql_query('UPDATE '.table_prefix."comments SET approved=$appr WHERE comment_id=$cid;");
+        if (!$q)
+          $db->die_json();
+        
+        $ret = Array(
+            'mode' => 'redraw',
+            'approved' => $appr,
+            'subj' => $row['subject'],
+            'id'   => $data['local_id']
+          );
+        
+        break;
+      default:
+        $ret = Array(
+          'mode' => 'error', 
+          'error' => $data['mode'] . ' is not a valid request mode'
+          );
+        break;
+    }
+    echo $parser->encode($ret);
+    return $ret;
+  }
+  
+} // class Comments
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/common.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,228 @@
+<?php
+
+/*
+ * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
+ * Version 1.0 (Banshee)
+ * Copyright (C) 2006-2007 Dan Fuhry
+ *
+ * This program is Free Software; you can redistribute 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 details.
+ */
+
+if(isset($_REQUEST['GLOBALS']))
+{
+  ?>
+  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"><html><head><title>Hacking Attempt</title><meta http-equiv="Content-type" content="text/html; charset=utf-8" /></head><style type="text/css">body{background-color:#000;color:#CCC;font-family:trebuchet ms,sans-serif;font-size:9pt;}a{color:#FFF;}</style><body><p>Hacking attempt using <a href="http://www.hardened-php.net/index.76.html">PHP $GLOBALS overwrite vulnerability</a> detected, reported to admin</p><p>You're worse than this guy! Unless you are this guy...</p><p id="billp"><img alt=" " src="about:blank" id="billi" /></p><script type="text/javascript">// <![CDATA[
+  window.onload=function(){counter();setInterval('counter();', 1000);};var text=false;var cnt=10;function counter(){if(!text){text=document.createElement('span');text.id='billc';text.innerHTML=cnt;text.style.fontSize='96pt';text.style.color='#FF0000';p=document.getElementById('billp');p.appendChild(text);}else{if(cnt==1){document.getElementById('billi').src='http://upload.wikimedia.org/wikipedia/commons/7/7f/Bill_Gates_2004_cr.jpg';document.getElementById('billc').innerHTML='';return;}cnt--;document.getElementById('billc').innerHTML=cnt+' ';}}
+  // ]]>
+  </script><p><span style="color:black;">Powered by Enano and valid XHTML 1.1</span></p></body></html>
+  <?php
+  exit;
+}
+
+$version = '1.0';
+
+function microtime_float()
+{
+  list($usec, $sec) = explode(" ", microtime());
+  return ((float)$usec + (float)$sec);
+}
+
+global $_starttime;
+$_starttime = microtime_float();
+
+error_reporting(E_ALL);
+
+if(!defined('ENANO_ROOT')) // ENANO_ROOT is sometimes defined by plugins like AjIM that need the constant before the Enano API is initialized
+  define('ENANO_ROOT', dirname(dirname(__FILE__)));
+
+if(defined('ENANO_DEBUG') && version_compare(PHP_VERSION, '5.0.0') < 0)
+{
+  die(__FILE__.':'.__LINE__.': The debugConsole requires PHP 5.x.x or greater. Please comment out the ENANO_DEBUG constant in your index.php.');
+}
+
+if(defined('ENANO_DEBUG'))
+{
+  require_once(ENANO_ROOT.'/includes/debugger/debugConsole.php');
+} else {
+  function dc_here($m)     { return false; }
+  function dc_dump($a, $g) { return false; }
+  function dc_watch($n)    { return false; }
+  function dc_start_timer($u) { return false; }
+  function dc_stop_timer($m) { return false; }
+}
+
+if ( file_exists( ENANO_ROOT . '/_nightly.php') )
+  require(ENANO_ROOT.'/_nightly.php');
+
+// Start including files. LOTS of files. Yeah!
+require_once(ENANO_ROOT.'/includes/constants.php');
+dc_here('Enano CMS '.$version.' (dev) - debug window<br />Powered by debugConsole');
+dc_here('common: including files');
+require_once(ENANO_ROOT.'/includes/functions.php');
+require_once(ENANO_ROOT.'/includes/dbal.php');
+require_once(ENANO_ROOT.'/includes/paths.php');
+require_once(ENANO_ROOT.'/includes/sessions.php');
+require_once(ENANO_ROOT.'/includes/template.php');
+require_once(ENANO_ROOT.'/includes/plugins.php');
+require_once(ENANO_ROOT.'/includes/comment.php');
+require_once(ENANO_ROOT.'/includes/wikiformat.php');
+require_once(ENANO_ROOT.'/includes/diff.php');
+require_once(ENANO_ROOT.'/includes/render.php');
+require_once(ENANO_ROOT.'/includes/stats.php');
+require_once(ENANO_ROOT.'/includes/pageutils.php');
+require_once(ENANO_ROOT.'/includes/js-compressor.php');
+require_once(ENANO_ROOT.'/includes/rijndael.php');
+require_once(ENANO_ROOT.'/includes/email.php');
+require_once(ENANO_ROOT.'/includes/search.php');
+require_once(ENANO_ROOT.'/includes/json.php');
+require_once(ENANO_ROOT.'/includes/wikiengine/Tables.php');
+require_once(ENANO_ROOT.'/includes/pageprocess.php');
+
+strip_magic_quotes_gpc();
+
+// Enano has five parts: the database abstraction layer (DBAL), the session manager, the path/URL manager, the template engine, and the plugin manager.
+// Each part has its own class and a global var; nearly all Enano functions are handled by one of these five components.
+
+global $db, $session, $paths, $template, $plugins; // Common objects
+global $enano_config; // A global used to cache config information without making loads of queries ;-)
+                      // In addition, $enano_config is used to fetch config information if die_semicritical() is called.
+                      
+global $email;
+
+if(!isset($_SERVER['HTTP_HOST'])) grinding_halt('Cannot get hostname', '<p>Your web browser did not provide the HTTP Host: field. This site requires a modern browser that supports the HTTP 1.1 standard.</p>');
+                     
+$db = new mysql();
+dc_here('common: calling $db->connect();');
+$db->connect(); // Redirects to install.php if an installation is not detected
+
+if(strstr(contentPath, '?')) $sep = '&';
+else $sep = '?';
+define('urlSeparator', $sep);
+unset($sep); // save 10 bytes of memory...
+
+// See if any diagnostic actions have been requested
+if ( isset($_GET['do']) && $_GET['do'] == 'diag' && isset($_GET['sub']) )
+{
+  switch($_GET['sub'])
+  {
+    case 'cookie_destroy':
+      unset($_COOKIE['sid']);
+      setcookie('sid', '', time()-3600*24, scriptPath);
+      setcookie('sid', '', time()-3600*24, scriptPath.'/');
+      die('Session cookie cleared. <a href="'.$_SERVER['PHP_SELF'].'">Continue</a>');
+      break;
+  }
+}
+
+// Select and fetch the site configuration
+dc_here('common: selecting global config data');
+$e = $db->sql_query('SELECT config_name, config_value FROM '.table_prefix.'config;');
+if(!$e) $db->_die('Some critical configuration information could not be selected.');
+else define('ENANO_CONFIG_FETCHED', ''); // Used in die_semicritical to figure out whether to call getConfig() or not
+
+dc_here('common: fetching $enano_config');
+$enano_config = Array();
+while($r = $db->fetchrow())
+{
+  $enano_config[$r['config_name']] = $r['config_value'];
+}
+
+$db->free_result();
+
+if(enano_version(false, true) != $version)
+{
+  grinding_halt('Version mismatch', '<p>It seems that the Enano release we\'re trying to run ('.$version.') is different from the version specified in your database ('.enano_version().'). Perhaps you need to <a href="'.scriptPath.'/upgrade.php">upgrade</a>?</p>');
+}
+
+// Our list of tables included in Enano
+$system_table_list = Array(
+    table_prefix.'categories',
+    table_prefix.'comments',
+    table_prefix.'config',
+    table_prefix.'logs',
+    table_prefix.'page_text',
+    table_prefix.'session_keys',
+    table_prefix.'pages',
+    table_prefix.'users',
+    table_prefix.'themes',
+    table_prefix.'buddies',
+    table_prefix.'banlist',
+    table_prefix.'files',
+    table_prefix.'privmsgs',
+    table_prefix.'sidebar',
+    table_prefix.'hits',
+    table_prefix.'search_index',
+    table_prefix.'groups',
+    table_prefix.'group_members',
+    table_prefix.'acl',
+    table_prefix.'search_cache'
+  );
+
+dc_here('common: initializing base classes');
+$plugins = new pluginLoader();
+
+// So where does the majority of Enano get executed? How about the next nine lines of code :)
+dc_here('common: ok, we\'re set up, starting mainstream execution');
+
+$plugins->loadAll();
+dc_here('common: loading plugins');
+  global $plugins;
+  foreach($plugins->load_list as $f) { include_once $f; } // Can't be in object context when this is done
+
+$session = new sessionManager();
+$paths = new pathManager();
+$template = new template();
+$email = new EmailEncryptor();
+
+define('ENANO_BASE_CLASSES_INITIALIZED', '');
+
+$code = $plugins->setHook('base_classes_initted');
+foreach ( $code as $cmd )
+{
+  eval($cmd);
+}
+  
+$p = RenderMan::strToPageId($paths->get_pageid_from_url());
+if( ( $p[1] == 'Admin' || $p[1] == 'Special' ) && function_exists('page_'.$p[1].'_'.$p[0].'_preloader'))
+{
+  @call_user_func('page_'.$p[1].'_'.$p[0].'_preloader');
+}
+
+$session->start();
+$paths->init();
+
+define('ENANO_MAINSTREAM', '');
+
+// If the site is disabled, bail out, unless we're trying to log in or administer the site
+if(getConfig('site_disabled') == '1')
+{
+  if ( $paths->namespace == 'Admin' || ( $paths->namespace == 'Special' && ( $paths->cpage['urlname_nons'] == 'CSS' || $paths->cpage['urlname_nons'] == 'Administration' || $paths->cpage['urlname_nons'] == 'Login' ) ) )
+  {
+    // do nothing; allow execution to continue
+  }
+  else
+  {
+    if(!$n = getConfig('site_disabled_notice')) $n = 'The administrator has disabled the site. Please check back later.';
+    
+    $text = RenderMan::render($n) . '
+    <div class="info-box">
+      If you have an administrative account, you may <a href="'.makeUrlNS('Special', 'Login').'">log in</a> to the site or <a href="'.makeUrlNS('Special', 'Administration').'">use the administration panel</a>.
+    </div>';
+    $paths->wiki_mode = 0;
+    die_semicritical('Site disabled', $text);
+  }
+}
+
+$code = $plugins->setHook('session_started');
+foreach ( $code as $cmd )
+{
+  eval($cmd);
+}
+
+if(isset($_GET['noheaders'])) $template->no_headers = true;
+
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/common.php~	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,227 @@
+<?php
+
+/*
+ * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
+ * Version 1.0 (Banshee)
+ * Copyright (C) 2006-2007 Dan Fuhry
+ *
+ * This program is Free Software; you can redistribute 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 details.
+ */
+
+if(isset($_REQUEST['GLOBALS']))
+{
+  ?>
+  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"><html><head><title>Hacking Attempt</title><meta http-equiv="Content-type" content="text/html; charset=utf-8" /></head><style type="text/css">body{background-color:#000;color:#CCC;font-family:trebuchet ms,sans-serif;font-size:9pt;}a{color:#FFF;}</style><body><p>Hacking attempt using <a href="http://www.hardened-php.net/index.76.html">PHP $GLOBALS overwrite vulnerability</a> detected, reported to admin</p><p>You're worse than this guy! Unless you are this guy...</p><p id="billp"><img alt=" " src="about:blank" id="billi" /></p><script type="text/javascript">// <![CDATA[
+  window.onload=function(){counter();setInterval('counter();', 1000);};var text=false;var cnt=10;function counter(){if(!text){text=document.createElement('span');text.id='billc';text.innerHTML=cnt;text.style.fontSize='96pt';text.style.color='#FF0000';p=document.getElementById('billp');p.appendChild(text);}else{if(cnt==1){document.getElementById('billi').src='http://upload.wikimedia.org/wikipedia/commons/7/7f/Bill_Gates_2004_cr.jpg';document.getElementById('billc').innerHTML='';return;}cnt--;document.getElementById('billc').innerHTML=cnt+' ';}}
+  // ]]>
+  </script><p><span style="color:black;">Powered by Enano and valid XHTML 1.1</span></p></body></html>
+  <?php
+  exit;
+}
+
+$version = '1.0';
+
+function microtime_float()
+{
+  list($usec, $sec) = explode(" ", microtime());
+  return ((float)$usec + (float)$sec);
+}
+
+global $_starttime;
+$_starttime = microtime_float();
+
+error_reporting(E_ALL);
+
+if(!defined('ENANO_ROOT')) // ENANO_ROOT is sometimes defined by plugins like AjIM that need the constant before the Enano API is initialized
+  define('ENANO_ROOT', dirname(dirname(__FILE__)));
+
+if(defined('ENANO_DEBUG') && version_compare(PHP_VERSION, '5.0.0') < 0)
+{
+  die(__FILE__.':'.__LINE__.': The debugConsole requires PHP 5.x.x or greater. Please comment out the ENANO_DEBUG constant in your index.php.');
+}
+
+if(defined('ENANO_DEBUG'))
+{
+  require_once(ENANO_ROOT.'/includes/debugger/debugConsole.php');
+} else {
+  function dc_here($m)     { return false; }
+  function dc_dump($a, $g) { return false; }
+  function dc_watch($n)    { return false; }
+  function dc_start_timer($u) { return false; }
+  function dc_stop_timer($m) { return false; }
+}
+
+if ( file_exists( ENANO_ROOT . '/_nightly.php') )
+  require(ENANO_ROOT.'/_nightly.php');
+
+// Start including files. LOTS of files. Yeah!
+require_once(ENANO_ROOT.'/includes/constants.php');
+dc_here('Enano CMS '.$version.' (dev) - debug window<br />Powered by debugConsole');
+dc_here('common: including files');
+require_once(ENANO_ROOT.'/includes/functions.php');
+require_once(ENANO_ROOT.'/includes/dbal.php');
+require_once(ENANO_ROOT.'/includes/paths.php');
+require_once(ENANO_ROOT.'/includes/sessions.php');
+require_once(ENANO_ROOT.'/includes/template.php');
+require_once(ENANO_ROOT.'/includes/plugins.php');
+require_once(ENANO_ROOT.'/includes/comment.php');
+require_once(ENANO_ROOT.'/includes/wikiformat.php');
+require_once(ENANO_ROOT.'/includes/diff.php');
+require_once(ENANO_ROOT.'/includes/render.php');
+require_once(ENANO_ROOT.'/includes/stats.php');
+require_once(ENANO_ROOT.'/includes/pageutils.php');
+require_once(ENANO_ROOT.'/includes/js-compressor.php');
+require_once(ENANO_ROOT.'/includes/rijndael.php');
+require_once(ENANO_ROOT.'/includes/email.php');
+require_once(ENANO_ROOT.'/includes/search.php');
+require_once(ENANO_ROOT.'/includes/json.php');
+require_once(ENANO_ROOT.'/includes/wikiengine/Tables.php');
+
+strip_magic_quotes_gpc();
+
+// Enano has five parts: the database abstraction layer (DBAL), the session manager, the path/URL manager, the template engine, and the plugin manager.
+// Each part has its own class and a global var; nearly all Enano functions are handled by one of these five components.
+
+global $db, $session, $paths, $template, $plugins; // Common objects
+global $enano_config; // A global used to cache config information without making loads of queries ;-)
+                      // In addition, $enano_config is used to fetch config information if die_semicritical() is called.
+                      
+global $email;
+
+if(!isset($_SERVER['HTTP_HOST'])) grinding_halt('Cannot get hostname', '<p>Your web browser did not provide the HTTP Host: field. This site requires a modern browser that supports the HTTP 1.1 standard.</p>');
+                     
+$db = new mysql();
+dc_here('common: calling $db->connect();');
+$db->connect(); // Redirects to install.php if an installation is not detected
+
+if(strstr(contentPath, '?')) $sep = '&';
+else $sep = '?';
+define('urlSeparator', $sep);
+unset($sep); // save 10 bytes of memory...
+
+// See if any diagnostic actions have been requested
+if ( isset($_GET['do']) && $_GET['do'] == 'diag' && isset($_GET['sub']) )
+{
+  switch($_GET['sub'])
+  {
+    case 'cookie_destroy':
+      unset($_COOKIE['sid']);
+      setcookie('sid', '', time()-3600*24, scriptPath);
+      setcookie('sid', '', time()-3600*24, scriptPath.'/');
+      die('Session cookie cleared. <a href="'.$_SERVER['PHP_SELF'].'">Continue</a>');
+      break;
+  }
+}
+
+// Select and fetch the site configuration
+dc_here('common: selecting global config data');
+$e = $db->sql_query('SELECT config_name, config_value FROM '.table_prefix.'config;');
+if(!$e) $db->_die('Some critical configuration information could not be selected.');
+else define('ENANO_CONFIG_FETCHED', ''); // Used in die_semicritical to figure out whether to call getConfig() or not
+
+dc_here('common: fetching $enano_config');
+$enano_config = Array();
+while($r = $db->fetchrow())
+{
+  $enano_config[$r['config_name']] = $r['config_value'];
+}
+
+$db->free_result();
+
+if(enano_version(false, true) != $version)
+{
+  grinding_halt('Version mismatch', '<p>It seems that the Enano release we\'re trying to run ('.$version.') is different from the version specified in your database ('.enano_version().'). Perhaps you need to <a href="'.scriptPath.'/upgrade.php">upgrade</a>?</p>');
+}
+
+// Our list of tables included in Enano
+$system_table_list = Array(
+    table_prefix.'categories',
+    table_prefix.'comments',
+    table_prefix.'config',
+    table_prefix.'logs',
+    table_prefix.'page_text',
+    table_prefix.'session_keys',
+    table_prefix.'pages',
+    table_prefix.'users',
+    table_prefix.'themes',
+    table_prefix.'buddies',
+    table_prefix.'banlist',
+    table_prefix.'files',
+    table_prefix.'privmsgs',
+    table_prefix.'sidebar',
+    table_prefix.'hits',
+    table_prefix.'search_index',
+    table_prefix.'groups',
+    table_prefix.'group_members',
+    table_prefix.'acl',
+    table_prefix.'search_cache'
+  );
+
+dc_here('common: initializing base classes');
+$plugins = new pluginLoader();
+
+// So where does the majority of Enano get executed? How about the next nine lines of code :)
+dc_here('common: ok, we\'re set up, starting mainstream execution');
+
+$plugins->loadAll();
+dc_here('common: loading plugins');
+  global $plugins;
+  foreach($plugins->load_list as $f) { include_once $f; } // Can't be in object context when this is done
+
+$session = new sessionManager();
+$paths = new pathManager();
+$template = new template();
+$email = new EmailEncryptor();
+
+define('ENANO_BASE_CLASSES_INITIALIZED', '');
+
+$code = $plugins->setHook('base_classes_initted');
+foreach ( $code as $cmd )
+{
+  eval($cmd);
+}
+  
+$p = RenderMan::strToPageId($paths->get_pageid_from_url());
+if( ( $p[1] == 'Admin' || $p[1] == 'Special' ) && function_exists('page_'.$p[1].'_'.$p[0].'_preloader'))
+{
+  @call_user_func('page_'.$p[1].'_'.$p[0].'_preloader');
+}
+
+$session->start();
+$paths->init();
+
+define('ENANO_MAINSTREAM', '');
+
+// If the site is disabled, bail out, unless we're trying to log in or administer the site
+if(getConfig('site_disabled') == '1')
+{
+  if ( $paths->namespace == 'Admin' || ( $paths->namespace == 'Special' && ( $paths->cpage['urlname_nons'] == 'CSS' || $paths->cpage['urlname_nons'] == 'Administration' || $paths->cpage['urlname_nons'] == 'Login' ) ) )
+  {
+    // do nothing; allow execution to continue
+  }
+  else
+  {
+    if(!$n = getConfig('site_disabled_notice')) $n = 'The administrator has disabled the site. Please check back later.';
+    
+    $text = RenderMan::render($n) . '
+    <div class="info-box">
+      If you have an administrative account, you may <a href="'.makeUrlNS('Special', 'Login').'">log in</a> to the site or <a href="'.makeUrlNS('Special', 'Administration').'">use the administration panel</a>.
+    </div>';
+    $paths->wiki_mode = 0;
+    die_semicritical('Site disabled', $text);
+  }
+}
+
+$code = $plugins->setHook('session_started');
+foreach ( $code as $cmd )
+{
+  eval($cmd);
+}
+
+if(isset($_GET['noheaders'])) $template->no_headers = true;
+
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/constants.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,420 @@
+<?php
+
+/*
+ * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
+ * Version 1.0 (Banshee)
+ * Copyright (C) 2006-2007 Dan Fuhry
+ * constants.php - important defines used Enano-wide
+ *
+ * This program is Free Software; you can redistribute 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 details.
+ */
+
+// Ban types
+
+define('BAN_IP', 1);
+define('BAN_USER', 2);
+define('BAN_EMAIL', 3);
+
+// ACL permission types
+define('AUTH_ALLOW', 4);
+define('AUTH_WIKIMODE', 3); // User can do this if wiki mode is enabled
+define('AUTH_DISALLOW', 2);
+define('AUTH_DENY', 1);     // A Deny setting overrides *everything*
+
+define('ACL_TYPE_GROUP', 1);
+define('ACL_TYPE_USER', 2);
+define('ACL_TYPE_PRESET', 3);
+
+// System groups
+define('GROUP_ID_ADMIN', 2);
+define('GROUP_ID_MOD', 3);
+
+//
+// User types - don't touch these
+//
+
+// User can do absolutely everything
+define('USER_LEVEL_ADMIN', 9);
+
+// User can edit/[un]approve comments and do some basic administration
+define('USER_LEVEL_MOD', 5);
+
+// Default for members. When authed at this level, the user can change his/her password.
+define('USER_LEVEL_CHPREF', 3);
+
+// The level that you will be running at most of the time
+define('USER_LEVEL_MEMBER', 2);
+
+// Special level for guests
+define('USER_LEVEL_GUEST', 1);
+
+// Group status
+
+define('GROUP_CLOSED', 1);
+define('GROUP_REQUEST', 2);
+define('GROUP_HIDDEN', 3);
+define('GROUP_OPEN', 4);
+
+// Other stuff
+
+define('MAX_PMS_PER_BATCH', 7); // The maximum number of users that users can send PMs to in one go; restriction does not apply to users with mod_misc rights
+define('SEARCH_RESULTS_PER_PAGE', 10);
+define('MYSQL_MAX_PACKET_SIZE', 1048576); // 1MB; this is the default in MySQL 4.x I think
+define('SEARCH_MODE', 'FULLTEXT'); // Can be FULLTEXT or BUILTIN
+
+// Sidebar
+
+define('BLOCK_WIKIFORMAT', 0);
+define('BLOCK_TEMPLATEFORMAT', 1);
+define('BLOCK_HTML', 2);
+define('BLOCK_PHP', 3);
+define('BLOCK_PLUGIN', 4);
+define('SIDEBAR_LEFT', 1);
+define('SIDEBAR_RIGHT', 2);
+
+define('GENERAL_ERROR', 'General error');
+define('GENERAL_NOTICE', 'Information');
+define('CRITICAL_ERROR', 'Critical error');
+
+// You can un-comment the next line to require database backups to be encrypted using the site's unique key.
+// This keeps the file safe in transit, but also prevents any type of editing to the file. This is NOT
+// recommended except for tiny sites because encrypting an average of 2MB of data will take a while.
+// define('SQL_BACKUP_CRYPT', '');
+
+// Security
+
+define('AES_BITS', 192); // AES cipher strength - defaults to 192 and cannot be changed after installation
+
+// Define this to enable Mcrypt support which makes encryption work faster. This is only triggered if Mcrypt support is detected.
+// THIS IS DISABLED BECAUSE MCRYPT DOES NOT SEEM TO SUPPORT THE AES BLOCK SIZES THAT ENANO USES.
+//define('MCRYPT_ACCEL', '');
+
+//if(defined('MCRYPT_RIJNDAEL_' . AES_BITS))
+//{
+//  eval('$bs = MCRYPT_RIJNDAEL_' . AES_BITS . ';');
+//  $bs = mcrypt_module_get_algo_block_size($bs);
+//  $bs = $bs * 8;
+//  define('AES_BLOCKSIZE', $bs);
+//}
+// else
+// {
+//   define('AES_BLOCKSIZE', AES_BITS);
+// }
+
+define('AES_BLOCKSIZE', 128);
+
+/*
+ * MIMETYPES
+ *
+ * This array defines the 166 known MIME types used by the Enano file-extension filter. Whether extensions are allowed or not is
+ * determined by a bitfield in the config table.
+ */
+
+global $mime_types, $mimetype_exps, $mimetype_extlist;
+
+// IMPORTANT: this array can NEVER have items removed from it or key indexes changed
+$mime_types = Array (
+  'ai'      => 'application/postscript',
+  'aif'     => 'audio/x-aiff',
+  'aifc'    => 'audio/x-aiff',
+  'aiff'    => 'audio/x-aiff',
+  'au'      => 'audio/basic',
+  'avi'     => 'video/x-msvideo',
+  'bcpio'   => 'application/x-bcpio',
+  'bin'     => 'application/octet-stream',
+  'bmp'     => 'image/bmp',
+  'bz2'     => 'application/x-bzip',
+  'cdf'     => 'application/x-netcdf',
+  'cgm'     => 'image/cgm',
+  'class'   => 'application/octet-stream',
+  'cpio'    => 'application/x-cpio',
+  'cpt'     => 'application/mac-compactpro',
+  'csh'     => 'application/x-csh',
+  'css'     => 'text/css',
+  'dcr'     => 'application/x-director',
+  'dir'     => 'application/x-director',
+  'djv'     => 'image/vnd.djvu',
+  'djvu'    => 'image/vnd.djvu',
+  'dll'     => 'application/octet-stream',
+  'dms'     => 'application/octet-stream',
+  'doc'     => 'application/msword',
+  'dtd'     => 'application/xml-dtd',
+  'dvi'     => 'application/x-dvi',
+  'dxr'     => 'application/x-director',
+  'eps'     => 'application/postscript',
+  'etx'     => 'text/x-setext',
+  'exe'     => 'application/octet-stream',
+  'ez'      => 'application/andrew-inset',
+  'gif'     => 'image/gif',
+  'gram'    => 'application/srgs',
+  'grxml'   => 'application/srgs+xml',
+  'gtar'    => 'application/x-gtar',
+  'gz'      => 'application/x-gzip',
+  'hdf'     => 'application/x-hdf',
+  'hqx'     => 'application/mac-binhex40',
+  'htm'     => 'text/html',
+  'html'    => 'text/html',
+  'ice'     => 'x-conference/x-cooltalk',
+  'ico'     => 'image/x-icon',
+  'ics'     => 'text/calendar',
+  'ief'     => 'image/ief',
+  'ifb'     => 'text/calendar',
+  'iges'    => 'model/iges',
+  'igs'     => 'model/iges',
+  'jar'     => 'application/zip',
+  'jpe'     => 'image/jpeg',
+  'jpeg'    => 'image/jpeg',
+  'jpg'     => 'image/jpeg',
+  'js'      => 'application/x-javascript',
+  'kar'     => 'audio/midi',
+  'latex'   => 'application/x-latex',
+  'lha'     => 'application/octet-stream',
+  'lzh'     => 'application/octet-stream',
+  'm3u'     => 'audio/x-mpegurl',
+  'man'     => 'application/x-troff-man',
+  'mathml'  => 'application/mathml+xml',
+  'me'      => 'application/x-troff-me',
+  'mesh'    => 'model/mesh',
+  'mid'     => 'audio/midi',
+  'midi'    => 'audio/midi',
+  'mif'     => 'application/vnd.mif',
+  'mov'     => 'video/quicktime',
+  'movie'   => 'video/x-sgi-movie',
+  'mp2'     => 'audio/mpeg',
+  'mp3'     => 'audio/mpeg',
+  'mpe'     => 'video/mpeg',
+  'mpeg'    => 'video/mpeg',
+  'mpg'     => 'video/mpeg',
+  'mpga'    => 'audio/mpeg',
+  'ms'      => 'application/x-troff-ms',
+  'msh'     => 'model/mesh',
+  'mxu'     => 'video/vnd.mpegurl',
+  'nc'      => 'application/x-netcdf',
+  'oda'     => 'application/oda',
+  'ogg'     => 'application/ogg',
+  'ogm'     => 'application/ogg',
+  'pbm'     => 'image/x-portable-bitmap',
+  'pdb'     => 'chemical/x-pdb',
+  'pdf'     => 'application/pdf',
+  'pgm'     => 'image/x-portable-graymap',
+  'pgn'     => 'application/x-chess-pgn',
+  'png'     => 'image/png',
+  'pnm'     => 'image/x-portable-anymap',
+  'ppm'     => 'image/x-portable-pixmap',
+  'ppt'     => 'application/vnd.ms-powerpoint',
+  'ps'      => 'application/postscript',
+  'psd'     => 'image/x-photoshop',
+  'qt'      => 'video/quicktime',
+  'ra'      => 'audio/x-realaudio',
+  'ram'     => 'audio/x-pn-realaudio',
+  'ras'     => 'image/x-cmu-raster',
+  'rdf'     => 'text/xml',
+  'rgb'     => 'image/x-rgb',
+  'rm'      => 'audio/x-pn-realaudio',
+  'roff'    => 'application/x-troff',
+  'rpm'     => 'audio/x-pn-realaudio-plugin',
+  'rss'     => 'text/xml',
+  'rtf'     => 'text/rtf',
+  'rtx'     => 'text/richtext',
+  'sgm'     => 'text/sgml',
+  'sgml'    => 'text/sgml',
+  'sh'      => 'application/x-sh',
+  'shar'    => 'application/x-shar',
+  'silo'    => 'model/mesh',
+  'sit'     => 'application/x-stuffit',
+  'skd'     => 'application/x-koan',
+  'skm'     => 'application/x-koan',
+  'skp'     => 'application/x-koan',
+  'skt'     => 'application/x-koan',
+  'smi'     => 'application/smil',
+  'smil'    => 'application/smil',
+  'snd'     => 'audio/basic',
+  'so'      => 'application/octet-stream',
+  'spl'     => 'application/x-futuresplash',
+  'src'     => 'application/x-wais-source',
+  'stc'     => 'application/zip',
+  'std'     => 'application/zip',
+  'sti'     => 'application/zip',
+  'stm'     => 'application/zip',
+  'stw'     => 'application/zip',
+  'sv4cpio' => 'application/x-sv4cpio',
+  'sv4crc'  => 'application/x-sv4crc',
+  'svg'     => 'image/svg+xml',
+  'swf'     => 'application/x-shockwave-flash',
+  'sxc'     => 'application/zip',
+  'sxd'     => 'application/zip',
+  'sxi'     => 'application/zip',
+  'sxm'     => 'application/zip',
+  'sxw'     => 'application/zip',
+  't'       => 'application/x-troff',
+  'tar'     => 'application/x-tar',
+  'tcl'     => 'application/x-tcl',
+  'tex'     => 'application/x-tex',
+  'texi'    => 'application/x-texinfo',
+  'texinfo' => 'application/x-texinfo',
+  'tif'     => 'image/tiff',
+  'tiff'    => 'image/tiff',
+  'tr'      => 'application/x-troff',
+  'tsv'     => 'text/tab-separated-values',
+  'txt'     => 'text/plain',
+  'ustar'   => 'application/x-ustar',
+  'vcd'     => 'application/x-cdlink',
+  'vrml'    => 'model/vrml',
+  'vxml'    => 'application/voicexml+xml',
+  'wav'     => 'audio/x-wav',
+  'wbmp'    => 'image/vnd.wap.wbmp',
+  'wbxml'   => 'application/vnd.wap.wbxml',
+  'wml'     => 'text/vnd.wap.wml',
+  'wmlc'    => 'application/vnd.wap.wmlc',
+  'wmls'    => 'text/vnd.wap.wmlscript',
+  'wmlsc'   => 'application/vnd.wap.wmlscriptc',
+  'wrl'     => 'model/vrml',
+  'xbm'     => 'image/x-xbitmap',
+  'xcf'     => 'image/xcf',
+  'xht'     => 'application/xhtml+xml',
+  'xhtml'   => 'application/xhtml+xml',
+  'xls'     => 'application/vnd.ms-excel',
+  'xml'     => 'text/xml',
+  'xpi'     => 'application/zip',
+  'xpm'     => 'image/x-xpixmap',
+  'xsl'     => 'text/xml',
+  'xslt'    => 'text/xml',
+  'xwd'     => 'image/x-xwindowdump',
+  'xyz'     => 'chemical/x-xyz',
+  'zip'     => 'application/zip',
+);
+
+$mimetype_extlist = Array(
+  'application/andrew-inset'=>'ez',
+  'application/mac-binhex40'=>'hqx',
+  'application/mac-compactpro'=>'cpt',
+  'application/mathml+xml'=>'mathml',
+  'application/msword'=>'doc',
+  'application/octet-stream'=>'bin dms lha lzh exe class so dll',
+  'application/oda'=>'oda',
+  'application/ogg'=>'ogg ogm',
+  'application/pdf'=>'pdf',
+  'application/postscript'=>'ai eps ps',
+  'application/rdf+xml'=>'rdf',
+  'application/smil'=>'smi smil',
+  'application/srgs'=>'gram',
+  'application/srgs+xml'=>'grxml',
+  'application/vnd.mif'=>'mif',
+  'application/vnd.ms-excel'=>'xls',
+  'application/vnd.ms-powerpoint'=>'ppt',
+  'application/vnd.wap.wbxml'=>'wbxml',
+  'application/vnd.wap.wmlc'=>'wmlc',
+  'application/vnd.wap.wmlscriptc'=>'wmlsc',
+  'application/voicexml+xml'=>'vxml',
+  'application/x-bcpio'=>'bcpio',
+  'application/x-bzip'=>'gz bz2',
+  'application/x-cdlink'=>'vcd',
+  'application/x-chess-pgn'=>'pgn',
+  'application/x-cpio'=>'cpio',
+  'application/x-csh'=>'csh',
+  'application/x-director'=>'dcr dir dxr',
+  'application/x-dvi'=>'dvi',
+  'application/x-futuresplash'=>'spl',
+  'application/x-gtar'=>'gtar tar',
+  'application/x-gzip'=>'gz',
+  'application/x-hdf'=>'hdf',
+  'application/x-jar'=>'jar',
+  'application/x-javascript'=>'js',
+  'application/x-koan'=>'skp skd skt skm',
+  'application/x-latex'=>'latex',
+  'application/x-netcdf'=>'nc cdf',
+  'application/x-sh'=>'sh',
+  'application/x-shar'=>'shar',
+  'application/x-shockwave-flash'=>'swf',
+  'application/x-stuffit'=>'sit',
+  'application/x-sv4cpio'=>'sv4cpio',
+  'application/x-sv4crc'=>'sv4crc',
+  'application/x-tar'=>'tar',
+  'application/x-tcl'=>'tcl',
+  'application/x-tex'=>'tex',
+  'application/x-texinfo'=>'texinfo texi',
+  'application/x-troff'=>'t tr roff',
+  'application/x-troff-man'=>'man',
+  'application/x-troff-me'=>'me',
+  'application/x-troff-ms'=>'ms',
+  'application/x-ustar'=>'ustar',
+  'application/x-wais-source'=>'src',
+  'application/x-xpinstall'=>'xpi',
+  'application/xhtml+xml'=>'xhtml xht',
+  'application/xslt+xml'=>'xslt',
+  'application/xml'=>'xml xsl',
+  'application/xml-dtd'=>'dtd',
+  'application/zip'=>'zip jar xpi  sxc stc  sxd std   sxi sti   sxm stm   sxw stw  ',
+  'audio/basic'=>'au snd',
+  'audio/midi'=>'mid midi kar',
+  'audio/mpeg'=>'mpga mp2 mp3',
+  'audio/ogg'=>'ogg ',
+  'audio/x-aiff'=>'aif aiff aifc',
+  'audio/x-mpegurl'=>'m3u',
+  'audio/x-ogg'=>'ogg ',
+  'audio/x-pn-realaudio'=>'ram rm',
+  'audio/x-pn-realaudio-plugin'=>'rpm',
+  'audio/x-realaudio'=>'ra',
+  'audio/x-wav'=>'wav',
+  'chemical/x-pdb'=>'pdb',
+  'chemical/x-xyz'=>'xyz',
+  'image/bmp'=>'bmp',
+  'image/cgm'=>'cgm',
+  'image/gif'=>'gif',
+  'image/ief'=>'ief',
+  'image/jpeg'=>'jpeg jpg jpe',
+  'image/png'=>'png',
+  'image/svg+xml'=>'svg',
+  'image/tiff'=>'tiff tif',
+  'image/vnd.djvu'=>'djvu djv',
+  'image/vnd.wap.wbmp'=>'wbmp',
+  'image/x-cmu-raster'=>'ras',
+  'image/x-icon'=>'ico',
+  'image/x-portable-anymap'=>'pnm',
+  'image/x-portable-bitmap'=>'pbm',
+  'image/x-portable-graymap'=>'pgm',
+  'image/x-portable-pixmap'=>'ppm',
+  'image/x-rgb'=>'rgb',
+  'image/x-photoshop'=>'psd',
+  'image/x-xbitmap'=>'xbm',
+  'image/x-xpixmap'=>'xpm',
+  'image/x-xwindowdump'=>'xwd',
+  'model/iges'=>'igs iges',
+  'model/mesh'=>'msh mesh silo',
+  'model/vrml'=>'wrl vrml',
+  'text/calendar'=>'ics ifb',
+  'text/css'=>'css',
+  'text/html'=>'html htm',
+  'text/plain'=>'txt',
+  'text/richtext'=>'rtx',
+  'text/rtf'=>'rtf',
+  'text/sgml'=>'sgml sgm',
+  'text/tab-separated-values'=>'tsv',
+  'text/vnd.wap.wml'=>'wml',
+  'text/vnd.wap.wmlscript'=>'wmls',
+  'text/xml'=>'xml xsl xslt rss rdf',
+  'text/x-setext'=>'etx',
+  'video/mpeg'=>'mpeg mpg mpe',
+  'video/ogg'=>'ogm ogg',
+  'video/quicktime'=>'qt mov',
+  'video/vnd.mpegurl'=>'mxu',
+  'video/x-msvideo'=>'avi',
+  'video/x-ogg'=>'ogm ogg',
+  'video/x-sgi-movie'=>'movie',
+  'x-conference/x-cooltalk'=>'ice',
+  // Added for Enano
+  'image/xcf' => 'xcf xcfbz2 xcf.bz2',
+);
+
+$k = array_keys($mime_types);
+$mimetype_exps = Array();
+foreach($k as $s => $x)
+{
+  $mimetype_exps[$x] = pow(2, $s);
+}
+
+unset($k, $s, $x);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/dbal.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,598 @@
+<?php
+
+/*
+ * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
+ * Version 1.0 (Banshee)
+ * Copyright (C) 2006-2007 Dan Fuhry
+ *
+ * This program is Free Software; you can redistribute 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 details.
+ */
+ 
+function db_error_handler($errno, $errstr, $errfile = false, $errline = false, $errcontext = Array() )
+{
+  if ( !defined('ENANO_DEBUG') )
+    return;
+  $e = error_reporting(0);
+  error_reporting($e);
+  if ( $e < $errno )
+    return;
+  $errtype = 'Notice';
+  switch ( $errno )
+  {
+    case E_ERROR: case E_USER_ERROR: case E_CORE_ERROR: case E_COMPILE_ERROR: $errtype = 'Error'; break;
+    case E_WARNING: case E_USER_WARNING: case E_CORE_WARNING: case E_COMPILE_WARNING: $errtype = 'Warning'; break;
+  }
+  $debug = debug_backtrace();
+  $debug = $debug[2]['file'] . ', line ' . $debug[2]['line'];
+  echo "<b>$errtype:</b> $errstr<br />Error source:<pre>$debug</pre>";
+}
+ 
+class mysql {
+  var $num_queries, $query_backtrace, $latest_result, $latest_query, $_conn, $sql_stack_fields, $sql_stack_values;
+  var $row = array();
+	var $rowset = array();
+  var $errhandler;
+  
+  function enable_errorhandler()
+  {
+    if ( function_exists('debug_backtrace') )
+    {
+      $this->errhandler = set_error_handler('db_error_handler');
+    }
+  }
+  
+  function disable_errorhandler()
+  {
+    if ( $this->errhandler )
+    {
+      set_error_handler($this->errhandler);
+    }
+    else
+    {
+      restore_error_handler();
+    }
+  }
+  
+  function sql_backtrace() {
+    $qb = explode("\n", $this->query_backtrace);
+    $bt = '';
+    //for($i=sizeof($qb)-1;$i>=0;$i--) {
+    for($i=0;$i<sizeof($qb);$i++) {
+      $bt .= $qb[$i]."\n";
+    }
+    return $bt;
+  }
+  
+  function ensure_connection()
+  {
+    if(!$this->_conn)
+    {
+      $this->connect();
+    }
+  }
+  
+  function _die($t = '') {
+    if(defined('ENANO_HEADERS_SENT')) {
+      ob_clean();
+    }
+    header('HTTP/1.1 500 Internal Server Error');
+    $bt = $this->sql_backtrace();
+    $e = htmlspecialchars(mysql_error());
+    if($e=='') $e='&lt;none&gt;';
+    if(defined('ENANO_CONFIG_FETCHED')) die_semicritical('Database error', '<h3>An error occurred during a database query.</h3><p>'.$t.'<br />Error returned by MySQL: '.$e.'<br />SQL Backtrace:</p><pre>'.$bt.'</pre>');
+    else                                   grinding_halt('Database error', '<h3>An error occurred during a database query.</h3><p>'.$t.'<br />Error returned by MySQL: '.$e.'<br />SQL Backtrace:</p><pre>'.$bt.'</pre>');
+    exit;
+  }
+  
+  function die_json()
+  {
+    $e = addslashes(htmlspecialchars(mysql_error()));
+    $q = addslashes($this->latest_query);
+    $t = "{'mode':'error','error':'An error occurred during database query.\nQuery was:\n  $q\n\nError returned by MySQL: $e'}";
+    die($t);
+  }
+  
+  function get_error($t = '') {
+    header('HTTP/1.1 500 Internal Server Error');
+    $bt = $this->sql_backtrace();
+    $e = htmlspecialchars(mysql_error());
+    if($e=='') $e='&lt;none&gt;';
+    $text = '<h3>An error occurred during a database query.</h3><p>'.$t.'<br />Error returned by MySQL: '.$e.'<br />SQL Backtrace:</p><pre>'.$bt.'</pre>';
+    return $text;
+  }
+  
+  function connect() {
+    $this->enable_errorhandler();
+    dc_here('dbal: trying to connect....');
+    @include(ENANO_ROOT.'/config.php');
+    if(isset($crypto_key))
+      unset($crypto_key); // Get this sucker out of memory fast
+    if(!defined('ENANO_INSTALLED') && !defined('MIDGET_INSTALLED') && !defined('IN_ENANO_INSTALL') )
+    {
+      dc_here('dbal: oops, looks like Enano isn\'t set up. Constants ENANO_INSTALLED, MIDGET_INSTALLED, and IN_ENANO_INSTALL are all undefined.');
+      header('Location: install.php'); 
+      exit;
+    }
+    $this->_conn = @mysql_connect($dbhost, $dbuser, $dbpasswd);
+    unset($dbuser);
+    unset($dbpasswd); // Security
+    if(!$this->_conn) { dc_here('dbal: uhoh!<br />'.mysql_error()); grinding_halt('Enano is having a problem', '<p>Error: couldn\'t connect to MySQL.<br />'.mysql_error().'</p>'); }
+    $this->query_backtrace = '';
+    $this->num_queries = 0;
+    dc_here('dbal: we\'re in, selecting database...');
+    $q = $this->sql_query('USE '.$dbname.';');
+    if(!$q) $this->_die('The database could not be selected.');
+    dc_here('dbal: connected to MySQL');
+    $this->disable_errorhandler();
+  }
+  
+  function sql_query($q) {
+    $this->enable_errorhandler();
+    $this->num_queries++;
+    $this->query_backtrace .= $q."\n";
+    $this->latest_query = $q;
+    dc_here('dbal: making SQL query:<br /><tt>'.$q.'</tt>');
+    if(!$this->_conn) $this->_die('A database connection has not yet been established.');
+    if(!$this->check_query($q))
+    {
+      $this->report_query($q);
+      grinding_halt('SQL Injection attempt', '<p>Enano has caught and prevented an SQL injection attempt. Your IP address has been recorded and the administrator has been notified.</p><p>Query was:</p><pre>'.htmlspecialchars($q).'</pre>');
+    }
+    $r = mysql_query($q, $this->_conn);
+    $this->latest_result = $r;
+    $this->disable_errorhandler();
+    return $r;
+  }
+  
+  function sql_unbuffered_query($q) {
+    $this->enable_errorhandler();
+    $this->num_queries++;
+    $this->query_backtrace .= '(UNBUFFERED) ' . $q."\n";
+    $this->latest_query = $q;
+    dc_here('dbal: making SQL query:<br /><tt>'.$q.'</tt>');
+    if(!$this->_conn) $this->_die('A database connection has not yet been established.');
+    if(!$this->check_query($q))
+    {
+      $this->report_query($q);
+      grinding_halt('SQL Injection attempt', '<p>Enano has caught and prevented an SQL injection attempt. Your IP address has been recorded and the administrator has been notified.</p><p>Query was:</p><pre>'.htmlspecialchars($q).'</pre>');
+    }
+    $r = mysql_unbuffered_query($q, $this->_conn);
+    $this->latest_result = $r;
+    $this->disable_errorhandler();
+    return $r;
+  }
+  
+  /**
+   * Checks a SQL query for possible signs of injection attempts
+   * @param string $q the query to check
+   * @return bool true if query passed check, otherwise false
+   */
+  
+  function check_query($q, $debug = false)
+  {
+    if($debug) echo "\$db-&gt;check_query(): checking query: ".htmlspecialchars($q).'<br />'."\n";
+    $sz = strlen($q);
+    $quotechar = false;
+    $quotepos  = 0;
+    $prev_is_quote = false;
+    $just_started = false;
+    for($i=0;$i<strlen($q);$i++,$c=substr($q, $i, 1))
+    {
+      $next = substr($q, $i+1, 1);
+      $next2 = substr($q, $i+2, 1);
+      $prev = substr($q, $i-1, 1);
+      $prev2 = substr($q, $i-2, 1);
+      if(isset($c) && in_array($c, Array('"', "'", '`')))
+      {
+        if($quotechar)
+        {
+          if(
+              ( $quotechar == $c && $quotechar != $next && ( $quotechar != $prev || $just_entered ) && $prev != '\\') ||
+              ( $prev2 == '\\' && $prev == $quotechar && $quotechar == $c )
+            )
+          {
+            $quotechar = false;
+            if($debug) echo('$db-&gt;check_query(): just finishing a quote section, quoted string: '.htmlspecialchars(substr($q, $quotepos, $i - $quotepos + 1)) . '<br />');
+            $q = substr($q, 0, $quotepos) . 'SAFE_QUOTE' . substr($q, $i + 1, strlen($q));
+            if($debug) echo('$db-&gt;check_query(): Filtered query: '.$q.'<br />');
+            $i = $quotepos;
+          }
+        }
+        else
+        {
+          $quotechar = $c;
+          $quotepos  = $i;
+          $just_entered = true;
+        }
+        if($debug) echo '$db-&gt;check_query(): found quote char as pos: '.$i.'<br />';
+        continue;
+      }
+      $just_entered = false;
+    }
+    if(substr(trim($q), strlen(trim($q))-1, 1) == ';') $q = substr(trim($q), 0, strlen(trim($q))-1);
+    for($i=0;$i<strlen($q);$i++,$c=substr($q, $i, 1))
+    {
+      if( ( $c == ';' && $i != $sz-1 ) || $c . substr($q, $i+1, 1) == '--') // Don't permit semicolons in mid-query, and never allow comments
+      {
+        // Injection attempt!
+        if($debug)
+        {
+          $e = '';
+          for($j=$i-5;$j<$i+5;$j++)
+          {
+            if($j == $i) $e .= '<span style="color: red; text-decoration: underline;">' . $c . '</span>';
+            else $e .= $c;
+          }
+          echo 'Injection attempt caught at pos: '.$i.'<br />';
+        }
+        return false;
+      }
+    }
+    return true;
+  }
+  
+  /**
+   * Set the internal result pointer to X
+   * @param int $pos The number of the row
+   * @param resource $result The MySQL result resource - if not given, the latest cached query is assumed
+   * @return true on success, false on failure
+   */
+   
+  function sql_data_seek($pos, $result = false)
+  {
+    $this->enable_errorhandler();
+    if(!$result)
+      $result = $this->latest_result;
+    if(!$result)
+    {
+      $this->disable_errorhandler();
+      return false;
+    }
+    if(mysql_data_seek($result, $pos))
+    {
+      $this->disable_errorhandler();
+      return true;
+    }
+    else
+    {
+      $this->disable_errorhandler();
+      return false;
+    }
+  }
+  
+  /**
+   * Reports a bad query to the admin
+   * @param string $query the naughty query
+   * @access private
+   */
+   
+  function report_query($query)
+  {
+    global $session;
+    if(is_object($session) && defined('ENANO_MAINSTREAM'))
+      $username = $session->username;
+    else
+      $username = 'Unavailable';
+    $query = $this->escape($query);
+    $q = $this->sql_query('INSERT INTO '.table_prefix.'logs(log_type,     action,         time_id,    date_string, page_text,      author,            edit_summary)
+                                                     VALUES(\'security\', \'sql_inject\', '.time().', \'\',        \''.$query.'\', \''.$username.'\', \''.$_SERVER['REMOTE_ADDR'].'\');');
+  }
+  
+  function fetchrow($r = false) {
+    $this->enable_errorhandler();
+    if(!$this->_conn) return false;
+    if(!$r) $r = $this->latest_result;
+    if(!$r) $this->_die('$db->fetchrow(): an invalid MySQL resource was passed.');
+    $row = mysql_fetch_assoc($r);
+    $this->disable_errorhandler();
+    return $row;
+  }
+  
+  function fetchrow_num($r = false) {
+    $this->enable_errorhandler();
+    if(!$r) $r = $this->latest_result;
+    if(!$r) $this->_die('$db->fetchrow(): an invalid MySQL resource was passed.');
+    $row = mysql_fetch_row($r);
+    $this->disable_errorhandler();
+    return $row;
+  }
+  
+  function numrows($r = false) {
+    $this->enable_errorhandler();
+    if(!$r) $r = $this->latest_result;
+    if(!$r) $this->_die('$db->fetchrow(): an invalid MySQL resource was passed.');
+    $n = mysql_num_rows($r);
+    $this->disable_errorhandler();
+    return $n;
+  }
+  
+  function escape($str)
+  {
+    $this->enable_errorhandler();
+    $str = mysql_real_escape_string($str);
+    $this->disable_errorhandler();
+    return $str;
+  }
+  
+  function free_result($result = false)
+  {
+    $this->enable_errorhandler();
+    if(!$result)
+      $result = $this->latest_result;
+    if(!$result)
+    {
+      $this->disable_errorhandler();
+      return null;
+    }
+    mysql_free_result($result);
+    $this->disable_errorhandler();
+    return null;
+  }
+  
+  function close() {
+    dc_here('dbal: closing MySQL connection');
+    mysql_close($this->_conn);
+    unset($this->_conn);
+  }
+  
+  // phpBB DBAL compatibility
+  function sql_fetchrow($r = false)
+  {
+    return $this->fetchrow($r);
+  }
+  function sql_freeresult($r = false)
+  {
+    if(!$this->_conn) return false;
+    if(!$r) $r = $this->latest_result;
+    if(!$r) $this->_die('$db->fetchrow(): an invalid MySQL resource was passed.');
+    mysql_free_result($r);
+  }
+  function sql_numrows($r = false)
+  {
+    if(!$this->_conn) return false;
+    if(!$r) $r = $this->latest_result;
+    if(!$r) $this->_die('$db->fetchrow(): an invalid MySQL resource was passed.');
+    return mysql_num_rows($r);
+  }
+  function sql_affectedrows($r = false, $f, $n)
+  {
+    if(!$this->_conn) return false;
+    if(!$r) $r = $this->latest_result;
+    if(!$r) $this->_die('$db->fetchrow(): an invalid MySQL resource was passed.');
+    return mysql_affected_rows();
+  }
+  
+  function sql_type_cast(&$value)
+	{
+		if ( is_float($value) )
+		{
+			return doubleval($value);
+		}
+		if ( is_integer($value) || is_bool($value) )
+		{
+			return intval($value);
+		}
+		if ( is_string($value) || empty($value) )
+		{
+			return '\'' . $this->sql_escape_string($value) . '\'';
+		}
+		// uncastable var : let's do a basic protection on it to prevent sql injection attempt
+		return '\'' . $this->sql_escape_string(htmlspecialchars($value)) . '\'';
+	}
+
+	function sql_statement(&$fields, $fields_inc='')
+	{
+		// init result
+		$this->sql_fields = $this->sql_values = $this->sql_update = '';
+		if ( empty($fields) && empty($fields_inc) )
+		{
+			return;
+		}
+
+		// process
+		if ( !empty($fields) )
+		{
+			$first = true;
+			foreach ( $fields as $field => $value )
+			{
+				// field must contain a field name
+				if ( !empty($field) && is_string($field) )
+				{
+					$value = $this->sql_type_cast($value);
+					$this->sql_fields .= ( $first ? '' : ', ' ) . $field;
+					$this->sql_values .= ( $first ? '' : ', ' ) . $value;
+					$this->sql_update .= ( $first ? '' : ', ' ) . $field . ' = ' . $value;
+					$first = false;
+				}
+			}
+		}
+		if ( !empty($fields_inc) )
+		{
+			foreach ( $fields_inc as $field => $indent )
+			{
+				if ( $indent != 0 )
+				{
+					$this->sql_update .= (empty($this->sql_update) ? '' : ', ') . $field . ' = ' . $field . ($indent < 0 ? ' - ' : ' + ') . abs($indent);
+				}
+			}
+		}
+	}
+
+	function sql_stack_reset($id='')
+	{
+		if ( empty($id) )
+		{
+			$this->sql_stack_fields = array();
+			$this->sql_stack_values = array();
+		}
+		else
+		{
+			$this->sql_stack_fields[$id] = array();
+			$this->sql_stack_values[$id] = array();
+		}
+	}
+
+	function sql_stack_statement(&$fields, $id='')
+	{
+		$this->sql_statement($fields);
+		if ( empty($id) )
+		{
+			$this->sql_stack_fields = $this->sql_fields;
+			$this->sql_stack_values[] = '(' . $this->sql_values . ')';
+		}
+		else
+		{
+			$this->sql_stack_fields[$id] = $this->sql_fields;
+			$this->sql_stack_values[$id][] = '(' . $this->sql_values . ')';
+		}
+	}
+
+	function sql_stack_insert($table, $transaction=false, $line='', $file='', $break_on_error=true, $id='')
+	{
+		if ( (empty($id) && empty($this->sql_stack_values)) || (!empty($id) && empty($this->sql_stack_values[$id])) )
+		{
+			return false;
+		}
+		switch( SQL_LAYER )
+		{
+			case 'mysql':
+			case 'mysql4':
+				if ( empty($id) )
+				{
+					$sql = 'INSERT INTO ' . $table . '
+								(' . $this->sql_stack_fields . ') VALUES ' . implode(",\n", $this->sql_stack_values);
+				}
+				else
+				{
+					$sql = 'INSERT INTO ' . $table . '
+								(' . $this->sql_stack_fields[$id] . ') VALUES ' . implode(",\n", $this->sql_stack_values[$id]);
+				}
+				$this->sql_stack_reset($id);
+				return $this->sql_query($sql, $transaction, $line, $file, $break_on_error);
+				break;
+			default:
+				$count_sql_stack_values = empty($id) ? count($this->sql_stack_values) : count($this->sql_stack_values[$id]);
+				$result = !empty($count_sql_stack_values);
+				for ( $i = 0; $i < $count_sql_stack_values; $i++ )
+				{
+					if ( empty($id) )
+					{
+						$sql = 'INSERT INTO ' . $table . '
+									(' . $this->sql_stack_fields . ') VALUES ' . $this->sql_stack_values[$i];
+					}
+					else
+					{
+						$sql = 'INSERT INTO ' . $table . '
+									(' . $this->sql_stack_fields[$id] . ') VALUES ' . $this->sql_stack_values[$id][$i];
+					}
+					$result &= $this->sql_query($sql, $transaction, $line, $file, $break_on_error);
+				}
+				$this->sql_stack_reset($id);
+				return $result;
+				break;
+		}
+	}
+
+	function sql_subquery($field, $sql, $line='', $file='', $break_on_error=true, $type=TYPE_INT)
+	{
+		// sub-queries doable
+		$this->sql_get_version();
+		if ( !in_array(SQL_LAYER, array('mysql', 'mysql4')) || (($this->sql_version[0] + ($this->sql_version[1] / 100)) >= 4.01) )
+		{
+			return $sql;
+		}
+
+		// no sub-queries
+		$ids = array();
+		$result = $this->sql_query(trim($sql), false, $line, $file, $break_on_error);
+		while ( $row = $this->sql_fetchrow($result) )
+		{
+			$ids[] = $type == TYPE_INT ? intval($row[$field]) : '\'' . $this->sql_escape_string($row[$field]) . '\'';
+		}
+		$this->sql_freeresult($result);
+		return empty($ids) ? 'NULL' : implode(', ', $ids);
+	}
+
+	function sql_col_id($expr, $alias)
+	{
+		$this->sql_get_version();
+		return in_array(SQL_LAYER, array('mysql', 'mysql4')) && (($this->sql_version[0] + ($this->sql_version[1] / 100)) <= 4.01) ? $alias : $expr;
+	}
+
+	function sql_get_version()
+	{
+		if ( empty($this->sql_version) )
+		{
+			$this->sql_version = array(0, 0, 0);
+			switch ( SQL_LAYER )
+			{
+				case 'mysql':
+				case 'mysql4':
+					if ( function_exists('mysql_get_server_info') )
+					{
+						$lo_version = explode('-', mysql_get_server_info());
+						$this->sql_version = explode('.', $lo_version[0]);
+						$this->sql_version = array(intval($this->sql_version[0]), intval($this->sql_version[1]), intval($this->sql_version[2]), $lo_version[1]);
+					}
+					break;
+
+				case 'postgresql':
+				case 'mssql':
+				case 'mssql-odbc':
+				default:
+					break;
+			}
+		}
+		return $this->sql_version;
+	}
+
+	function sql_error()
+	{
+		if ( $this->_conn )
+		{
+			return mysql_error();
+		}
+		else
+		{
+			return array();
+		}
+	}
+  function sql_escape_string($t) 
+  {
+    return mysql_real_escape_string($t);
+  }
+  function sql_close()
+  {
+    $this->close();
+  }
+  function sql_fetchrowset($query_id = 0)
+	{
+		if( !$query_id )
+		{
+			$query_id = $this->query_result;
+		}
+
+		if( $query_id )
+		{
+			unset($this->rowset[$query_id]);
+			unset($this->row[$query_id]);
+
+			while($this->rowset[$query_id] = mysql_fetch_array($query_id, MYSQL_ASSOC))
+			{
+				$result[] = $this->rowset[$query_id];
+			}
+
+			return $result;
+		}
+		else
+		{
+			return false;
+		}
+	}
+}
+
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/debugger/debugConsole.class.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,479 @@
+<?php
+/**
+ * debugConsole class
+ *
+ * This class allows opening an external JavaScript
+ * window for debugging purposes.
+ *
+ * @author Andreas Demmer <info@debugconsole.de>
+ * @see <http://www.debugconsole.de>
+ * @version 1.2.1
+ * @package debugConsole_1.2.1
+ */
+class debugConsole {
+	/**
+	 * events which are shown in debug console
+	 *
+	 * @var array
+	 */
+	protected $filters;
+	
+	/**
+	 * all watched variables with their current content
+	 *
+	 * @var array
+	 */
+	protected $watches;
+	
+	/**
+	 * debugConsole configuration values
+	 *
+	 * @var array
+	 */
+	protected $config;
+	
+	/**
+	 * URL where template can be found
+	 *
+	 * @var string
+	 */
+	protected $template;
+
+	/**
+	 * javascripts to control popup
+	 *
+	 * @var array
+	 */
+	protected $javascripts;
+
+	/**
+	 * html for popup
+	 *
+	 * @var array
+	 */
+	protected $html;
+
+	/**
+	 * time of debugrun start in milliseconds
+	 *
+	 * @var string
+	 */
+	protected $starttime;
+
+	/**
+	 * time of timer start in milliseconds
+	 *
+	 * @var array
+	 */
+	protected $timers;
+
+	/**
+	 * constructor, opens popup window
+	 */
+	public function __construct () {
+		/* initialize class vars */
+		$this->starttime = $this->getMicrotime();
+		$this->watches = array ();
+		$this->config = $GLOBALS['_debugConsoleConfig'];
+		$this->html = $this->config['html'];
+		$this->html['header'] = str_replace("\n\r", NULL, $this->html['header']);
+		$this->html['header'] = str_replace("\n", NULL, $this->html['header']);
+		$this->javascripts = $this->config['javascripts'];
+		
+		/* replace PHP's errorhandler */
+		$errorhandler = array (
+			$this,
+			'errorHandlerCallback'
+		);
+		
+		set_error_handler($errorhandler);
+		
+		/* open popup */
+		$popupOptions = "', 'debugConsole', 'width=" . $this->config['dimensions']['width'] . ",height=" . $this->config['dimensions']['height'] . ',scrollbars=yes';
+		
+		$this->sendCommand('openPopup', $popupOptions);
+		$this->sendCommand('write', $this->html['header']);
+		
+		$this->startDebugRun();
+	}
+	
+	/**
+	 * destructor, shows runtime and finishes html document in popup window
+	 */
+	public function __destruct () {
+		$runtime = $this->getMicrotime() - $this->starttime;
+		$runtime = number_format((float)$runtime, 4, '.', NULL);
+		
+		$info = '<p class="runtime">This debug-run took ' . $runtime . ' seconds to complete.</p>';
+
+		$this->sendCommand('write', $info);
+		$this->sendCommand('write', '</div>');
+		$this->sendCommand('scroll', "0','100000");
+		$this->sendCommand('write', $this->html['footer']);
+		
+		if ($this->config['focus']) {
+			$this->sendCommand('focus');
+		}
+	}
+	
+	/**
+	 * show new debug run header in console
+	 */
+	
+	protected function startDebugRun () {
+		$info = '<h1>new debug-run (' . date('H:i') . ' hours)</h1>';
+		$this->sendCommand('write', '<div>');
+		$this->sendCommand('write', $info);
+	}
+
+	/**
+	 * adds a variable to the watchlist
+	 * 
+	 * Watched variables must be in a declare(ticks=n)
+	 * block so that every n ticks the watched variables
+	 * are checked for changes. If any changes were made,
+	 * the new value of the variable is shown in the
+	 * debugConsole with additional information where the
+	 * changes happened.
+	 *
+	 * @param string $variableName
+	 */
+	public function watchVariable ($variableName) {
+		if (count($this->watches) === 0) {
+			$watchMethod = array (
+				$this,
+				'watchesCallback'
+			);
+			
+			register_tick_function($watchMethod);
+		}
+		
+		if (isset($GLOBALS[$variableName])) {
+			$this->watches[$variableName] = $GLOBALS[$variableName];
+		} else {
+			$this->watches[$variableName] = NULL;
+		}
+	}
+	
+	/**
+	 * tick callback: process watches and show changes
+	 */
+	public function watchesCallback () {
+		if ($this->config['filters']['watches']) {
+			foreach ($this->watches as $variableName => $variableValue) {
+				if ($GLOBALS[$variableName] !== $this->watches[$variableName]) {
+					$info = '<p class="watch"><strong>$' . $variableName;
+					$info .= '</strong> changed from "';
+					$info .= $this->watches[$variableName];
+					$info .= '" (' . gettype($this->watches[$variableName]) . ')';
+					$info .= ' to "' . $GLOBALS[$variableName] . '" (';
+					$info .= gettype($GLOBALS[$variableName]) . ')';
+					$info .= $this->getTraceback() . '</p>';
+					
+					$this->watches[$variableName] = $GLOBALS[$variableName];
+					$this->sendCommand('write', $info);
+				}
+			}
+		}
+	}
+	
+	/**
+	 * sends a javascript command to browser
+	 *
+	 * @param string $command
+	 * @param string $value
+	 */
+	protected function sendCommand ($command, $value = FALSE) {
+    if($command == 'write') $value = '\'+unescape(\''.rawurlencode($value).'\')+\'';
+		$value = str_replace('\\', '\\\\', $value);
+    $value = nl2br($value);
+		
+		if ((bool)$value) { 
+			/* write optionally logfile */
+			$this->writeLogfileEntry($command, $value);
+			
+			$command = $this->javascripts[$command] . "('" . $value . "');";
+		} else {
+			$command = $this->javascripts[$command] . ';';
+		}
+		
+		$command = str_replace("\n\r", NULL, $command);
+		$command = str_replace("\n", NULL, $command);
+		
+		if (!$this->config['logfile']['disablePopup']) {
+			echo $this->javascripts['openTag'], "\n";
+			echo $command, "\n";
+			echo $this->javascripts['closeTag'], "\n";
+		}
+		
+		flush();
+	}
+	
+	/**
+	 * writes html output as text entry into logfile
+	 *
+	 * @param string $command
+	 * @param string $value
+	 */
+	protected function writeLogfileEntry ($command, $value) {
+		if ($this->config['logfile']['enable']) {
+			$logfile = $this->config['logfile']['path'] . $this->config['logfile']['filename'];
+			/* log only useful entries, no html header and footer */
+			if (
+				$command === 'write'
+				&& !strpos($value, '<html>')
+				&&  !strpos($value, '</html>')
+			) {
+				/* convert html to text */
+				$value = html_entity_decode($value);
+				$value = str_replace('>', '> ', $value);
+				$value = strip_tags($value);
+				
+				$fp = fopen($logfile, 'a+');
+				fputs($fp, $value . "\n\n");
+				fclose($fp);
+			} elseif (strpos($value, '</html>')) {
+				$fp = fopen($logfile, 'a+');
+				fputs($fp, "-----------\n");
+				fclose($fp);
+			}
+		}
+	}
+
+	/**
+	 * shows in console that a checkpoint has been passed,
+	 * additional info is the file and line which triggered
+	 * the output
+	 *
+	 * @param string $message
+	 */	
+	public function passedCheckpoint ($message = NULL) {
+		if ($this->config['filters']['checkpoints']) {
+			$message = (bool)$message ? $message : 'Checkpoint passed!';
+	
+			$info = '<p class="checkpoint"><strong>' . $message . '</strong>';
+			$info .= $this->getTraceback() . '</p>';
+			
+			$this->sendCommand('write', $info);
+		}
+	}
+	
+	/**
+	 * returns microtime as float value
+	 *
+	 * @return float
+	 */
+	protected function getMicrotime () {
+		list($usec, $sec) = explode(' ', microtime()); 
+    	return ((float)$usec + (float)$sec);
+	}
+	
+	/**
+	 * returns all possible filter events for debugConsole::setFilter() method
+	 *
+	 * @return array
+	 */
+	public function getFilters () {
+		$filters = array_keys($this->config['filters']);
+		
+		ksort($filters);
+		reset($filters);
+		
+		return $filters; 
+	}
+	
+	/**
+	 * shows or hides an event-type in debugConsole,
+	 * returns previous setting of the given event-type
+	 *
+	 * @param string $event
+	 * @param bool $isShown
+	 * @return bool
+	 */
+	public function setFilter ($event, $isShown) {
+		if (array_key_exists($event, $this->config['filters'])) {
+			$oldValue = $this->config['filters'][$event];
+			$this->config['filters'][$event] = $isShown;
+		} else {
+			throw new Exception ('debugConsole: unknown event "' . $event . '" in debugConsole::filter()');
+		}
+		
+		return $oldValue;
+	}
+	
+	/**
+	 * show debug info for variable in debugConsole,
+	 * added by custom text for documentation and hints
+	 *
+	 * @param mixed $variable
+	 * @param string $text
+	 */
+	public function dump ($variable, $text) {
+		if ($this->config['filters']['debug']) {
+			@ob_start();
+			
+			/* grab current ob content */
+			$obContents = ob_get_contents();
+			ob_clean();
+			
+			/* grap var dump from ob */
+			var_dump($variable);
+			$variableDebug = ob_get_contents();
+			ob_end_clean();
+			
+			/* restore previous ob content */
+			if ((bool)$obContents) echo $obContents;
+			
+			/* render debug */
+			$variableDebug = htmlspecialchars($variableDebug);			
+			$infos = '<p class="dump">' . $text . '<br />';
+			
+			if (is_array($variable)) {
+				$variableDebug = str_replace(' ', '&nbsp;', $variableDebug);
+				$infos .= '<span class="source">' . $variableDebug . '</span>';
+			} else {
+				$infos .= '<strong>' . $variableDebug . '</strong>';
+			}
+			
+			$infos .= $this->getTraceback() . '</p>';
+			$this->sendCommand('write', $infos);
+		}
+	}
+	
+	/**
+	 * callback method for PHP errorhandling
+	 * 
+	 * @todo implement more errorlevels
+	 */
+	public function errorHandlerCallback () {
+		$details = func_get_args();
+		$details[1] = str_replace("'", '"', $details[1]);
+		$details[1] = str_replace('href="function.', 'target="_blank" href="http://www.php.net/', $details[1]);
+		
+		
+		/* determine error level */
+		switch ($details[0]) {
+			case 2:
+				if (!$this->config['filters']['php_warnings']) return;
+				$errorlevel = 'warning';
+				break;
+			case 8:
+				if (!$this->config['filters']['php_notices']) return;
+				$errorlevel = 'notice';
+				break;
+			case 2048:
+				if (!$this->config['filters']['php_suggestions']) return;
+				$errorlevel = 'suggestion';
+				break;
+		}
+
+		$file = $this->cropScriptPath($details[2]);
+		
+		$infos = '<p class="' . $errorlevel . '"><strong>';
+		$infos .= 'PHP ' . strtoupper($errorlevel) . '</strong>';
+		$infos .= $details[1] . '<span class="backtrace">';
+		$infos .= $file . ' on line ';
+		$infos .= $details[3] . '</span></p>';		
+		
+		$this->sendCommand('write', $infos);
+	}
+	
+	/**
+	 * start timer clock, returns timer handle
+	 * 
+	 * @return mixed
+	 * @param string $comment
+	 */
+	public function startTimer ($comment) {
+		if ($this->config['filters']['timers']) {
+			$timerHandle = md5(microtime());
+			
+			$this->timers[$timerHandle] = array (
+				'starttime' => $this->getMicrotime(),
+				'comment' => $comment
+			);
+		} else {		
+			$timerHandle = FALSE;		
+		}
+		
+		return $timerHandle;
+	}
+	
+	/**
+	 * stop timer clock
+	 * 
+	 * @return bool
+	 * @param string $timerHandle
+	 */
+	public function stopTimer ($timerHandle) {
+		if ($this->config['filters']['timers']) {
+			if (array_key_exists($timerHandle, $this->timers)) {
+				$timerExists = TRUE;
+				$timespan = $this->getMicrotime() - $this->timers[$timerHandle]['starttime'];
+			
+				$info = '<p class="timer"><strong>' . $this->timers[$timerHandle]['comment'];
+				$info .= '</strong><br />The timer ran ';
+				$info .= '<strong>' . number_format ($timespan, 4, '.', NULL) . '</strong>';
+				$info .= ' seconds.' . $this->getTraceback() . '</p>';
+			
+				$this->sendCommand('write', $info);
+			} else {
+				$timerExists = FALSE;
+			}
+		} else {
+			$timerExists = FALSE;
+		}
+		
+		return $timerExists;
+	}
+	
+	/**
+	 * returns a formatted traceback string
+	 *
+	 * @return string
+	 */
+	public function getTraceback () {
+		$callStack = debug_backtrace();
+
+		$debugConsoleFiles = array(
+			'debugConsole.class.php',
+			'debugConsole.functions.php'
+		);
+		
+		$call = array (
+			'file' => 'debugConsole.class.php'
+		);
+		
+		while(in_array(basename($call['file']), $debugConsoleFiles)) {
+			$call = array_shift($callStack);
+		}
+
+		$call['file'] = $this->cropScriptPath($call['file']);
+		
+		$traceback = '<span class="backtrace">';
+		$traceback .= $call['file'] . ' on line ';
+		$traceback .= $call['line'] . '</span>';
+		
+		return $traceback;
+	}
+	
+	/**
+	 * crops long script path, shows only the last $maxLength chars
+	 *
+	 * @param string $path
+	 * @param int $maxLength
+	 * @return string
+	 */
+	protected function cropScriptPath ($path, $maxLength = 30) {
+		if (strlen($path) > $maxLength) {
+			$startPos = strlen($path) - $maxLength - 2;
+			
+			if ($startPos > 0) {
+				$path = '...' . substr($path, $startPos);
+			}
+		}
+
+		return $path;
+	}
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/debugger/debugConsole.config.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,196 @@
+<?php
+/**
+ * debugConsole configuration
+ *
+ * @author Andreas Demmer <info@debugconsole.de>
+ * @see <http://www.debugconsole.de>
+ * @version 1.2.1
+ * @package debugConsole_1.2.1
+ */
+
+/**
+ * config container for debugConsole
+ *
+ * @var array
+ */
+$_debugConsoleConfig = array();
+
+/**
+ * use debugConsole
+ */
+$_debugConsoleConfig['active'] = TRUE;
+
+/**
+ * restrict access
+ */
+$_debugConsoleConfig['restrictions'] = array (
+	'restrictAccess' => FALSE,
+	'allowedClientAdresses' => array('127.0.0.1')
+);
+
+/**
+ * set timezone, used for PHP >= 5.1.x
+ */
+putenv ('TZ=America/New_York');
+
+/**
+ * focus debugConsole at end of debug-run
+ */
+$_debugConsoleConfig['focus'] = TRUE;
+
+
+/**
+ * logfile configuration
+ */
+$_debugConsoleConfig['logfile'] = array (
+	'enable' => FALSE,
+	'path' => './',
+	'filename' => 'log.txt',
+	'disablePopup' => FALSE
+);
+
+/**
+ * show or hide certain events
+ */
+$_debugConsoleConfig['filters'] = array (
+	'debug' => TRUE,
+	'watches' => TRUE,
+	'checkpoints' => TRUE,
+	'timers' => TRUE,
+	'php_notices' => TRUE,
+	'php_warnings' => TRUE,
+	'php_errors' => TRUE,
+	'php_suggestions' => FALSE
+);
+
+/**
+ * popup dimensions in px
+ */
+$_debugConsoleConfig['dimensions'] = array (
+	'width' => 300,
+	'height' => 525
+);
+
+/**
+ * javascript snippets, do not touch!
+ */
+$_debugConsoleConfig['javascripts'] = array (
+	'openTag' => '<script language="JavaScript" type="text/javascript">',
+	'closeTag' => '</script>',
+	'openPopup' => 'debugConsole = window.open',
+	'closePopup' => 'debugConsole.close()',
+	'write' => 'debugConsole.document.write',
+	'scroll' => 'debugConsole.scrollBy',
+	'focus' => 'debugConsole.focus()'
+);
+
+/**
+ * html snippets, do not touch!
+ */
+$_debugConsoleConfig['html'] = array (
+	'header' => '
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+  <html>
+    <head>
+      <title>debugConsole</title>
+      <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+      <meta name="language" content="en" />
+      <style type="text/css">
+        * {
+        	margin: 0px; 
+        	padding: 0px;
+        }
+        
+        body {
+        	font-family: arial, sans-serif;
+        	font-size: 0.7em;
+        	color: black;
+        	background-color: white;
+        	padding: 5px;
+        }
+        
+        h1 {
+        	background-color: #888;
+        	color: white;
+        	font-size: 100%;
+        	padding: 3px;
+        	margin: 0px 0px 5px 0px;
+        	border: 0px;
+        	border-bottom: 4px solid #ccc;
+        }
+        
+        p {
+        	border: 1px solid #888;
+        	border-left: 5px solid #888;
+        	background-color: white;
+        	padding: 3px;
+        	margin: 5px 3px;
+        }
+        
+        div {
+            background-color: #eee;
+            border: 1px solid #888;
+            margin: 0px 0px 25px 0px;
+        }
+        
+        .dump {
+        }
+        
+        .dump .source {
+            font-family: courier, sans-serif;
+        }
+                
+        .backtrace {
+        	display: block;
+			color: #aaa;
+        }
+        
+        .watch {
+        	border-color: #BF1CBF;
+        }
+
+        .checkpoint {
+        	border-color: #00E600;
+        } 
+        
+        .timer {
+        	border-color: blue;
+        } 
+        
+        .notice, .suggestion {
+        	border-color: orange;
+        }
+        
+        .warning {
+        	border-color: red;
+        }
+
+        .notice strong, .warning strong, .suggestion strong {
+        	font-weight: bold;
+        	display: block;
+        }
+    
+        .notice strong, .suggestion strong {
+        	color: orange;
+        }
+    
+        .warning strong {
+        	color: red;
+        }
+        
+        .runtime {
+            margin: 0px;
+            padding: 0px;
+            border: 0px;
+            width: 100%;
+            text-align: center;
+            background-color: transparent;
+            color: #666;
+        }
+               
+      </style>
+    </head>
+  <body>',
+	'footer' => '</body></html>'
+);
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/debugger/debugConsole.functions.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,126 @@
+<?php
+/**
+ * debugConsole functions
+ *
+ * @author Andreas Demmer <info@debugconsole.de>
+ * @see <http://www.debugconsole.de>
+ * @version 1.0.0
+ * @package debugConsole_1.2.1
+ */
+
+/**
+ * show debug info of a variable in debugConsole,
+ * add own text for documentation or hints
+ * 
+ * @param mixed $variable
+ * @param string $text
+ */
+function dc_dump($variable, $text) {
+  if(!defined('ENANO_DEBUG')) return false;
+	$debugConsole = debugConsoleLoader();
+	
+	if (is_object($debugConsole)) {
+		$debugConsole->dump($variable, $text);
+	}
+}
+
+/**
+ * watch value changes of a variable in debugConsole
+ *
+ * @param string $variableName
+ */
+function dc_watch($variableName) {
+  if(!defined('ENANO_DEBUG')) return false;
+	$debugConsole = debugConsoleLoader();
+	
+	if (is_object($debugConsole)) {
+		$debugConsole->watchVariable($variableName);
+	}
+}
+
+/**
+ * show checkpoint info in debugConsole to make sure
+ * that a certain program line has been passed
+ *
+ * @param string $message
+ */
+function dc_here($message = NULL) {
+  if(!defined('ENANO_DEBUG')) return false;
+	$debugConsole = debugConsoleLoader();
+	
+	if (is_object($debugConsole)) {
+		(bool)$message ? $debugConsole->passedCheckpoint($message) : $debugConsole->passedCheckpoint();
+	}
+}
+
+/**
+ * starts a new timer clock and returns its handle
+ *
+ * @return mixed
+ * @param string $comment
+ */
+function dc_start_timer($comment) {
+  if(!defined('ENANO_DEBUG')) return false;
+	$debugConsole = debugConsoleLoader();
+	
+	if (is_object($debugConsole)) {
+		return $debugConsole->startTimer($comment);
+	}
+}
+
+/**
+ * stops and shows a certain timer clock in debugConsole
+ *
+ * @return bool
+ * @param string $timerHandle
+ */
+function dc_stop_timer($timerHandle) {
+  if(!defined('ENANO_DEBUG')) return false;
+	$debugConsole = debugConsoleLoader();
+	
+	if (is_object($debugConsole)) {
+		return $debugConsole->stopTimer($timerHandle);
+	}
+}
+
+/**
+ * singleton loader for debugConsole
+ * DO NOT USE, private to debugConsole functions
+ *
+ * @return mixed
+ */
+function debugConsoleLoader() {
+	static $debugConsole;
+	static $access = 'unset';
+
+	$config = $GLOBALS['_debugConsoleConfig'];
+	
+	/* obey access restrictions */
+	if (gettype($access) != 'bool') {
+		if ($config['active']) {
+			if ($config['restrictions']['restrictAccess']) {
+				if (in_array($_SERVER['REMOTE_ADDR'], $config['restrictions']['allowedClientAdresses'])) {
+					$access = TRUE;
+				} else {
+					$access = FALSE;
+				}
+			} else {
+				$access = TRUE;
+			}
+		} else {
+			$access = FALSE;
+		}
+	}
+	
+	/* access granted */
+	if ($access) {
+		if (!is_object($debugConsole)) {
+			$debugConsole = new debugConsole();
+		}
+	} else {
+		$debugConsole = FALSE;
+	}
+	
+	return $debugConsole;
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/debugger/debugConsole.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,16 @@
+<?php
+/**
+ * debugConsole includes
+ *
+ * @author Andreas Demmer <info@debugconsole.de>
+ * @see <http://www.debugconsole.de>
+ * @version 1.0.0
+ * @package debugConsole_1.2.1
+ */
+
+$path = dirname(__FILE__) . '/';
+
+require_once $path . 'debugConsole.config.php';
+require_once $path . 'debugConsole.class.php';
+require_once $path . 'debugConsole.functions.php';
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/diff.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1153 @@
+<?php
+
+// A PHP diff engine for phpwiki. (Taken from phpwiki-1.3.3)
+//
+// Copyright (C) 2000, 2001 Geoffrey T. Dairiki <dairiki@dairiki.org>
+// You may copy this code freely under the conditions of the GPL.
+//
+
+define('USE_ASSERTS', function_exists('assert'));
+
+/**
+ * @todo document
+ * @package Enano
+ * @subpackage DifferenceEngine
+ */
+class _DiffOp {
+	var $type;
+	var $orig;
+	var $closing;
+
+	function reverse() {
+		trigger_error('pure virtual', E_USER_ERROR);
+	}
+
+	function norig() {
+		return $this->orig ? sizeof($this->orig) : 0;
+	}
+
+	function nclosing() {
+		return $this->closing ? sizeof($this->closing) : 0;
+	}
+}
+
+/**
+ * @todo document
+ * @package Enano
+ * @subpackage DifferenceEngine
+ */
+class _DiffOp_Copy extends _DiffOp {
+	var $type = 'copy';
+
+	function _DiffOp_Copy ($orig, $closing = false) {
+		if (!is_array($closing))
+			$closing = $orig;
+		$this->orig = $orig;
+		$this->closing = $closing;
+	}
+
+	function reverse() {
+		return new _DiffOp_Copy($this->closing, $this->orig);
+	}
+}
+
+/**
+ * @todo document
+ * @package Enano
+ * @subpackage DifferenceEngine
+ */
+class _DiffOp_Delete extends _DiffOp {
+	var $type = 'delete';
+
+	function _DiffOp_Delete ($lines) {
+		$this->orig = $lines;
+		$this->closing = false;
+	}
+
+	function reverse() {
+		return new _DiffOp_Add($this->orig);
+	}
+}
+
+/**
+ * @todo document
+ * @package Enano
+ * @subpackage DifferenceEngine
+ */
+class _DiffOp_Add extends _DiffOp {
+	var $type = 'add';
+
+	function _DiffOp_Add ($lines) {
+		$this->closing = $lines;
+		$this->orig = false;
+	}
+
+	function reverse() {
+		return new _DiffOp_Delete($this->closing);
+	}
+}
+
+/**
+ * @todo document
+ * @package Enano
+ * @subpackage DifferenceEngine
+ */
+class _DiffOp_Change extends _DiffOp {
+	var $type = 'change';
+
+	function _DiffOp_Change ($orig, $closing) {
+		$this->orig = $orig;
+		$this->closing = $closing;
+	}
+
+	function reverse() {
+		return new _DiffOp_Change($this->closing, $this->orig);
+	}
+}
+
+
+/**
+ * Class used internally by Diff to actually compute the diffs.
+ *
+ * The algorithm used here is mostly lifted from the perl module
+ * Algorithm::Diff (version 1.06) by Ned Konz, which is available at:
+ *	 http://www.perl.com/CPAN/authors/id/N/NE/NEDKONZ/Algorithm-Diff-1.06.zip
+ *
+ * More ideas are taken from:
+ *	 http://www.ics.uci.edu/~eppstein/161/960229.html
+ *
+ * Some ideas are (and a bit of code) are from from analyze.c, from GNU
+ * diffutils-2.7, which can be found at:
+ *	 ftp://gnudist.gnu.org/pub/gnu/diffutils/diffutils-2.7.tar.gz
+ *
+ * closingly, some ideas (subdivision by NCHUNKS > 2, and some optimizations)
+ * are my own.
+ *
+ * Line length limits for robustness added by Tim Starling, 2005-08-31
+ *
+ * @author Geoffrey T. Dairiki, Tim Starling
+ * @package Enano
+ * @subpackage DifferenceEngine
+ */
+define('MAX_XREF_LENGTH', 10000);
+class _DiffEngine
+{
+	function diff ($from_lines, $to_lines) {
+		$fname = '_DiffEngine::diff';
+		// wfProfileIn( $fname );
+
+		$n_from = sizeof($from_lines);
+		$n_to = sizeof($to_lines);
+
+		$this->xchanged = $this->ychanged = array();
+		$this->xv = $this->yv = array();
+		$this->xind = $this->yind = array();
+		unset($this->seq);
+		unset($this->in_seq);
+		unset($this->lcs);
+
+		// Skip leading common lines.
+		for ($skip = 0; $skip < $n_from && $skip < $n_to; $skip++) {
+			if ($from_lines[$skip] !== $to_lines[$skip])
+				break;
+			$this->xchanged[$skip] = $this->ychanged[$skip] = false;
+		}
+		// Skip trailing common lines.
+		$xi = $n_from; $yi = $n_to;
+		for ($endskip = 0; --$xi > $skip && --$yi > $skip; $endskip++) {
+			if ($from_lines[$xi] !== $to_lines[$yi])
+				break;
+			$this->xchanged[$xi] = $this->ychanged[$yi] = false;
+		}
+
+		// Ignore lines which do not exist in both files.
+		for ($xi = $skip; $xi < $n_from - $endskip; $xi++) {
+			$xhash[$this->_line_hash($from_lines[$xi])] = 1;
+		}
+
+		for ($yi = $skip; $yi < $n_to - $endskip; $yi++) {
+			$line = $to_lines[$yi];
+			if ( ($this->ychanged[$yi] = empty($xhash[$this->_line_hash($line)])) )
+				continue;
+			$yhash[$this->_line_hash($line)] = 1;
+			$this->yv[] = $line;
+			$this->yind[] = $yi;
+		}
+		for ($xi = $skip; $xi < $n_from - $endskip; $xi++) {
+			$line = $from_lines[$xi];
+			if ( ($this->xchanged[$xi] = empty($yhash[$this->_line_hash($line)])) )
+				continue;
+			$this->xv[] = $line;
+			$this->xind[] = $xi;
+		}
+
+		// Find the LCS.
+		$this->_compareseq(0, sizeof($this->xv), 0, sizeof($this->yv));
+
+		// Merge edits when possible
+		$this->_shift_boundaries($from_lines, $this->xchanged, $this->ychanged);
+		$this->_shift_boundaries($to_lines, $this->ychanged, $this->xchanged);
+
+		// Compute the edit operations.
+		$edits = array();
+		$xi = $yi = 0;
+		while ($xi < $n_from || $yi < $n_to) {
+			USE_ASSERTS && assert($yi < $n_to || $this->xchanged[$xi]);
+			USE_ASSERTS && assert($xi < $n_from || $this->ychanged[$yi]);
+
+			// Skip matching "snake".
+			$copy = array();
+			while ( $xi < $n_from && $yi < $n_to
+					&& !$this->xchanged[$xi] && !$this->ychanged[$yi]) {
+				$copy[] = $from_lines[$xi++];
+				++$yi;
+			}
+			if ($copy)
+				$edits[] = new _DiffOp_Copy($copy);
+
+			// Find deletes & adds.
+			$delete = array();
+			while ($xi < $n_from && $this->xchanged[$xi])
+				$delete[] = $from_lines[$xi++];
+
+			$add = array();
+			while ($yi < $n_to && $this->ychanged[$yi])
+				$add[] = $to_lines[$yi++];
+
+			if ($delete && $add)
+				$edits[] = new _DiffOp_Change($delete, $add);
+			elseif ($delete)
+				$edits[] = new _DiffOp_Delete($delete);
+			elseif ($add)
+				$edits[] = new _DiffOp_Add($add);
+		}
+		// wfProfileOut( $fname );
+		return $edits;
+	}
+
+	/**
+	 * Returns the whole line if it's small enough, or the MD5 hash otherwise
+	 */
+	function _line_hash( $line ) {
+		if ( strlen( $line ) > MAX_XREF_LENGTH ) {
+			return md5( $line );
+		} else {
+			return $line;
+		}
+	}
+
+
+	/* Divide the Largest Common Subsequence (LCS) of the sequences
+	 * [XOFF, XLIM) and [YOFF, YLIM) into NCHUNKS approximately equally
+	 * sized segments.
+	 *
+	 * Returns (LCS, PTS).	LCS is the length of the LCS. PTS is an
+	 * array of NCHUNKS+1 (X, Y) indexes giving the diving points between
+	 * sub sequences.  The first sub-sequence is contained in [X0, X1),
+	 * [Y0, Y1), the second in [X1, X2), [Y1, Y2) and so on.  Note
+	 * that (X0, Y0) == (XOFF, YOFF) and
+	 * (X[NCHUNKS], Y[NCHUNKS]) == (XLIM, YLIM).
+	 *
+	 * This function assumes that the first lines of the specified portions
+	 * of the two files do not match, and likewise that the last lines do not
+	 * match.  The caller must trim matching lines from the beginning and end
+	 * of the portions it is going to specify.
+	 */
+	function _diag ($xoff, $xlim, $yoff, $ylim, $nchunks) {
+		$fname = '_DiffEngine::_diag';
+		// wfProfileIn( $fname );
+		$flip = false;
+
+		if ($xlim - $xoff > $ylim - $yoff) {
+			// Things seems faster (I'm not sure I understand why)
+				// when the shortest sequence in X.
+				$flip = true;
+			list ($xoff, $xlim, $yoff, $ylim)
+			= array( $yoff, $ylim, $xoff, $xlim);
+		}
+
+		if ($flip)
+			for ($i = $ylim - 1; $i >= $yoff; $i--)
+				$ymatches[$this->xv[$i]][] = $i;
+		else
+			for ($i = $ylim - 1; $i >= $yoff; $i--)
+				$ymatches[$this->yv[$i]][] = $i;
+
+		$this->lcs = 0;
+		$this->seq[0]= $yoff - 1;
+		$this->in_seq = array();
+		$ymids[0] = array();
+
+		$numer = $xlim - $xoff + $nchunks - 1;
+		$x = $xoff;
+		for ($chunk = 0; $chunk < $nchunks; $chunk++) {
+			// wfProfileIn( "$fname-chunk" );
+			if ($chunk > 0)
+				for ($i = 0; $i <= $this->lcs; $i++)
+					$ymids[$i][$chunk-1] = $this->seq[$i];
+
+			$x1 = $xoff + (int)(($numer + ($xlim-$xoff)*$chunk) / $nchunks);
+			for ( ; $x < $x1; $x++) {
+				$line = $flip ? $this->yv[$x] : $this->xv[$x];
+					if (empty($ymatches[$line]))
+						continue;
+				$matches = $ymatches[$line];
+				reset($matches);
+				while (list ($junk, $y) = each($matches))
+					if (empty($this->in_seq[$y])) {
+						$k = $this->_lcs_pos($y);
+						USE_ASSERTS && assert($k > 0);
+						$ymids[$k] = $ymids[$k-1];
+						break;
+					}
+				while (list ($junk, $y) = each($matches)) {
+					if ($y > $this->seq[$k-1]) {
+						USE_ASSERTS && assert($y < $this->seq[$k]);
+						// Optimization: this is a common case:
+						//	next match is just replacing previous match.
+						$this->in_seq[$this->seq[$k]] = false;
+						$this->seq[$k] = $y;
+						$this->in_seq[$y] = 1;
+					} else if (empty($this->in_seq[$y])) {
+						$k = $this->_lcs_pos($y);
+						USE_ASSERTS && assert($k > 0);
+						$ymids[$k] = $ymids[$k-1];
+					}
+				}
+			}
+			// wfProfileOut( "$fname-chunk" );
+		}
+
+		$seps[] = $flip ? array($yoff, $xoff) : array($xoff, $yoff);
+		$ymid = $ymids[$this->lcs];
+		for ($n = 0; $n < $nchunks - 1; $n++) {
+			$x1 = $xoff + (int)(($numer + ($xlim - $xoff) * $n) / $nchunks);
+			$y1 = $ymid[$n] + 1;
+			$seps[] = $flip ? array($y1, $x1) : array($x1, $y1);
+		}
+		$seps[] = $flip ? array($ylim, $xlim) : array($xlim, $ylim);
+
+		// wfProfileOut( $fname );
+		return array($this->lcs, $seps);
+	}
+
+	function _lcs_pos ($ypos) {
+		$fname = '_DiffEngine::_lcs_pos';
+		// wfProfileIn( $fname );
+
+		$end = $this->lcs;
+		if ($end == 0 || $ypos > $this->seq[$end]) {
+			$this->seq[++$this->lcs] = $ypos;
+			$this->in_seq[$ypos] = 1;
+			// wfProfileOut( $fname );
+			return $this->lcs;
+		}
+
+		$beg = 1;
+		while ($beg < $end) {
+			$mid = (int)(($beg + $end) / 2);
+			if ( $ypos > $this->seq[$mid] )
+				$beg = $mid + 1;
+			else
+				$end = $mid;
+		}
+
+		USE_ASSERTS && assert($ypos != $this->seq[$end]);
+
+		$this->in_seq[$this->seq[$end]] = false;
+		$this->seq[$end] = $ypos;
+		$this->in_seq[$ypos] = 1;
+		// wfProfileOut( $fname );
+		return $end;
+	}
+
+	/* Find LCS of two sequences.
+	 *
+	 * The results are recorded in the vectors $this->{x,y}changed[], by
+	 * storing a 1 in the element for each line that is an insertion
+	 * or deletion (ie. is not in the LCS).
+	 *
+	 * The subsequence of file 0 is [XOFF, XLIM) and likewise for file 1.
+	 *
+	 * Note that XLIM, YLIM are exclusive bounds.
+	 * All line numbers are origin-0 and discarded lines are not counted.
+	 */
+	function _compareseq ($xoff, $xlim, $yoff, $ylim) {
+		$fname = '_DiffEngine::_compareseq';
+		// wfProfileIn( $fname );
+
+		// Slide down the bottom initial diagonal.
+		while ($xoff < $xlim && $yoff < $ylim
+			   && $this->xv[$xoff] == $this->yv[$yoff]) {
+			++$xoff;
+			++$yoff;
+		}
+
+		// Slide up the top initial diagonal.
+		while ($xlim > $xoff && $ylim > $yoff
+			   && $this->xv[$xlim - 1] == $this->yv[$ylim - 1]) {
+			--$xlim;
+			--$ylim;
+		}
+
+		if ($xoff == $xlim || $yoff == $ylim)
+			$lcs = 0;
+		else {
+			// This is ad hoc but seems to work well.
+			//$nchunks = sqrt(min($xlim - $xoff, $ylim - $yoff) / 2.5);
+			//$nchunks = max(2,min(8,(int)$nchunks));
+			$nchunks = min(7, $xlim - $xoff, $ylim - $yoff) + 1;
+			list ($lcs, $seps)
+			= $this->_diag($xoff,$xlim,$yoff, $ylim,$nchunks);
+		}
+
+		if ($lcs == 0) {
+			// X and Y sequences have no common subsequence:
+			// mark all changed.
+			while ($yoff < $ylim)
+				$this->ychanged[$this->yind[$yoff++]] = 1;
+			while ($xoff < $xlim)
+				$this->xchanged[$this->xind[$xoff++]] = 1;
+		} else {
+			// Use the partitions to split this problem into subproblems.
+			reset($seps);
+			$pt1 = $seps[0];
+			while ($pt2 = next($seps)) {
+				$this->_compareseq ($pt1[0], $pt2[0], $pt1[1], $pt2[1]);
+				$pt1 = $pt2;
+			}
+		}
+		// wfProfileOut( $fname );
+	}
+
+	/* Adjust inserts/deletes of identical lines to join changes
+	 * as much as possible.
+	 *
+	 * We do something when a run of changed lines include a
+	 * line at one end and has an excluded, identical line at the other.
+	 * We are free to choose which identical line is included.
+	 * `compareseq' usually chooses the one at the beginning,
+	 * but usually it is cleaner to consider the following identical line
+	 * to be the "change".
+	 *
+	 * This is extracted verbatim from analyze.c (GNU diffutils-2.7).
+	 */
+	function _shift_boundaries ($lines, &$changed, $other_changed) {
+		$fname = '_DiffEngine::_shift_boundaries';
+		// wfProfileIn( $fname );
+		$i = 0;
+		$j = 0;
+
+		USE_ASSERTS && assert('sizeof($lines) == sizeof($changed)');
+		$len = sizeof($lines);
+		$other_len = sizeof($other_changed);
+
+		while (1) {
+			/*
+			 * Scan forwards to find beginning of another run of changes.
+			 * Also keep track of the corresponding point in the other file.
+			 *
+			 * Throughout this code, $i and $j are adjusted together so that
+			 * the first $i elements of $changed and the first $j elements
+			 * of $other_changed both contain the same number of zeros
+			 * (unchanged lines).
+			 * Furthermore, $j is always kept so that $j == $other_len or
+			 * $other_changed[$j] == false.
+			 */
+			while ($j < $other_len && $other_changed[$j])
+				$j++;
+
+			while ($i < $len && ! $changed[$i]) {
+				USE_ASSERTS && assert('$j < $other_len && ! $other_changed[$j]');
+				$i++; $j++;
+				while ($j < $other_len && $other_changed[$j])
+					$j++;
+			}
+
+			if ($i == $len)
+				break;
+
+			$start = $i;
+
+			// Find the end of this run of changes.
+			while (++$i < $len && $changed[$i])
+				continue;
+
+			do {
+				/*
+				 * Record the length of this run of changes, so that
+				 * we can later determine whether the run has grown.
+				 */
+				$runlength = $i - $start;
+
+				/*
+				 * Move the changed region back, so long as the
+				 * previous unchanged line matches the last changed one.
+				 * This merges with previous changed regions.
+				 */
+				while ($start > 0 && $lines[$start - 1] == $lines[$i - 1]) {
+					$changed[--$start] = 1;
+					$changed[--$i] = false;
+					while ($start > 0 && $changed[$start - 1])
+						$start--;
+					USE_ASSERTS && assert('$j > 0');
+					while ($other_changed[--$j])
+						continue;
+					USE_ASSERTS && assert('$j >= 0 && !$other_changed[$j]');
+				}
+
+				/*
+				 * Set CORRESPONDING to the end of the changed run, at the last
+				 * point where it corresponds to a changed run in the other file.
+				 * CORRESPONDING == LEN means no such point has been found.
+				 */
+				$corresponding = $j < $other_len ? $i : $len;
+
+				/*
+				 * Move the changed region forward, so long as the
+				 * first changed line matches the following unchanged one.
+				 * This merges with following changed regions.
+				 * Do this second, so that if there are no merges,
+				 * the changed region is moved forward as far as possible.
+				 */
+				while ($i < $len && $lines[$start] == $lines[$i]) {
+					$changed[$start++] = false;
+					$changed[$i++] = 1;
+					while ($i < $len && $changed[$i])
+						$i++;
+
+					USE_ASSERTS && assert('$j < $other_len && ! $other_changed[$j]');
+					$j++;
+					if ($j < $other_len && $other_changed[$j]) {
+						$corresponding = $i;
+						while ($j < $other_len && $other_changed[$j])
+							$j++;
+					}
+				}
+			} while ($runlength != $i - $start);
+
+			/*
+			 * If possible, move the fully-merged run of changes
+			 * back to a corresponding run in the other file.
+			 */
+			while ($corresponding < $i) {
+				$changed[--$start] = 1;
+				$changed[--$i] = 0;
+				USE_ASSERTS && assert('$j > 0');
+				while ($other_changed[--$j])
+					continue;
+				USE_ASSERTS && assert('$j >= 0 && !$other_changed[$j]');
+			}
+		}
+		// wfProfileOut( $fname );
+	}
+}
+
+/**
+ * Class representing a 'diff' between two sequences of strings.
+ * @todo document
+ * @package Enano
+ * @subpackage DifferenceEngine
+ */
+class Diff
+{
+	var $edits;
+
+	/**
+	 * Constructor.
+	 * Computes diff between sequences of strings.
+	 *
+	 * @param $from_lines array An array of strings.
+	 *		  (Typically these are lines from a file.)
+	 * @param $to_lines array An array of strings.
+	 */
+	function Diff($from_lines, $to_lines) {
+		$eng = new _DiffEngine;
+		$this->edits = $eng->diff($from_lines, $to_lines);
+		//$this->_check($from_lines, $to_lines);
+	}
+
+	/**
+	 * Compute reversed Diff.
+	 *
+	 * SYNOPSIS:
+	 *
+	 *	$diff = new Diff($lines1, $lines2);
+	 *	$rev = $diff->reverse();
+	 * @return object A Diff object representing the inverse of the
+	 *				  original diff.
+	 */
+	function reverse () {
+		$rev = $this;
+		$rev->edits = array();
+		foreach ($this->edits as $edit) {
+			$rev->edits[] = $edit->reverse();
+		}
+		return $rev;
+	}
+
+	/**
+	 * Check for empty diff.
+	 *
+	 * @return bool True iff two sequences were identical.
+	 */
+	function isEmpty () {
+		foreach ($this->edits as $edit) {
+			if ($edit->type != 'copy')
+				return false;
+		}
+		return true;
+	}
+
+	/**
+	 * Compute the length of the Longest Common Subsequence (LCS).
+	 *
+	 * This is mostly for diagnostic purposes.
+	 *
+	 * @return int The length of the LCS.
+	 */
+	function lcs () {
+		$lcs = 0;
+		foreach ($this->edits as $edit) {
+			if ($edit->type == 'copy')
+				$lcs += sizeof($edit->orig);
+		}
+		return $lcs;
+	}
+
+	/**
+	 * Get the original set of lines.
+	 *
+	 * This reconstructs the $from_lines parameter passed to the
+	 * constructor.
+	 *
+	 * @return array The original sequence of strings.
+	 */
+	function orig() {
+		$lines = array();
+
+		foreach ($this->edits as $edit) {
+			if ($edit->orig)
+				array_splice($lines, sizeof($lines), 0, $edit->orig);
+		}
+		return $lines;
+	}
+
+	/**
+	 * Get the closing set of lines.
+	 *
+	 * This reconstructs the $to_lines parameter passed to the
+	 * constructor.
+	 *
+	 * @return array The sequence of strings.
+	 */
+	function closing() {
+		$lines = array();
+
+		foreach ($this->edits as $edit) {
+			if ($edit->closing)
+				array_splice($lines, sizeof($lines), 0, $edit->closing);
+		}
+		return $lines;
+	}
+
+	/**
+	 * Check a Diff for validity.
+	 *
+	 * This is here only for debugging purposes.
+	 */
+	function _check ($from_lines, $to_lines) {
+		$fname = 'Diff::_check';
+		// wfProfileIn( $fname );
+		if (serialize($from_lines) != serialize($this->orig()))
+			trigger_error("Reconstructed original doesn't match", E_USER_ERROR);
+		if (serialize($to_lines) != serialize($this->closing()))
+			trigger_error("Reconstructed closing doesn't match", E_USER_ERROR);
+
+		$rev = $this->reverse();
+		if (serialize($to_lines) != serialize($rev->orig()))
+			trigger_error("Reversed original doesn't match", E_USER_ERROR);
+		if (serialize($from_lines) != serialize($rev->closing()))
+			trigger_error("Reversed closing doesn't match", E_USER_ERROR);
+
+
+		$prevtype = 'none';
+		foreach ($this->edits as $edit) {
+			if ( $prevtype == $edit->type )
+				trigger_error("Edit sequence is non-optimal", E_USER_ERROR);
+			$prevtype = $edit->type;
+		}
+
+		$lcs = $this->lcs();
+		trigger_error('Diff okay: LCS = '.$lcs, E_USER_NOTICE);
+		// wfProfileOut( $fname );
+	}
+}
+
+/**
+ * FIXME: bad name.
+ * @todo document
+ * @package Enano
+ * @subpackage DifferenceEngine
+ */
+class MappedDiff extends Diff
+{
+	/**
+	 * Constructor.
+	 *
+	 * Computes diff between sequences of strings.
+	 *
+	 * This can be used to compute things like
+	 * case-insensitve diffs, or diffs which ignore
+	 * changes in white-space.
+	 *
+	 * @param $from_lines array An array of strings.
+	 *	(Typically these are lines from a file.)
+	 *
+	 * @param $to_lines array An array of strings.
+	 *
+	 * @param $mapped_from_lines array This array should
+	 *	have the same size number of elements as $from_lines.
+	 *	The elements in $mapped_from_lines and
+	 *	$mapped_to_lines are what is actually compared
+	 *	when computing the diff.
+	 *
+	 * @param $mapped_to_lines array This array should
+	 *	have the same number of elements as $to_lines.
+	 */
+	function MappedDiff($from_lines, $to_lines,
+						$mapped_from_lines, $mapped_to_lines) {
+		$fname = 'MappedDiff::MappedDiff';
+		// wfProfileIn( $fname );
+
+		assert(sizeof($from_lines) == sizeof($mapped_from_lines));
+		assert(sizeof($to_lines) == sizeof($mapped_to_lines));
+
+		$this->Diff($mapped_from_lines, $mapped_to_lines);
+
+		$xi = $yi = 0;
+		for ($i = 0; $i < sizeof($this->edits); $i++) {
+			$orig = &$this->edits[$i]->orig;
+			if (is_array($orig)) {
+				$orig = array_slice($from_lines, $xi, sizeof($orig));
+				$xi += sizeof($orig);
+			}
+
+			$closing = &$this->edits[$i]->closing;
+			if (is_array($closing)) {
+				$closing = array_slice($to_lines, $yi, sizeof($closing));
+				$yi += sizeof($closing);
+			}
+		}
+		// wfProfileOut( $fname );
+	}
+}
+
+/**
+ * A class to format Diffs
+ *
+ * This class formats the diff in classic diff format.
+ * It is intended that this class be customized via inheritance,
+ * to obtain fancier outputs.
+ * @todo document
+ * @package Enano
+ * @subpackage DifferenceEngine
+ */
+class DiffFormatter
+{
+	/**
+	 * Number of leading context "lines" to preserve.
+	 *
+	 * This should be left at zero for this class, but subclasses
+	 * may want to set this to other values.
+	 */
+	var $leading_context_lines = 0;
+
+	/**
+	 * Number of trailing context "lines" to preserve.
+	 *
+	 * This should be left at zero for this class, but subclasses
+	 * may want to set this to other values.
+	 */
+	var $trailing_context_lines = 0;
+
+	/**
+	 * Format a diff.
+	 *
+	 * @param $diff object A Diff object.
+	 * @return string The formatted output.
+	 */
+	function format($diff) {
+		$fname = 'DiffFormatter::format';
+		// wfProfileIn( $fname );
+
+		$xi = $yi = 1;
+		$block = false;
+		$context = array();
+
+		$nlead = $this->leading_context_lines;
+		$ntrail = $this->trailing_context_lines;
+
+		$this->_start_diff();
+
+		foreach ($diff->edits as $edit) {
+			if ($edit->type == 'copy') {
+				if (is_array($block)) {
+					if (sizeof($edit->orig) <= $nlead + $ntrail) {
+						$block[] = $edit;
+					}
+					else{
+						if ($ntrail) {
+							$context = array_slice($edit->orig, 0, $ntrail);
+							$block[] = new _DiffOp_Copy($context);
+						}
+						$this->_block($x0, $ntrail + $xi - $x0,
+									  $y0, $ntrail + $yi - $y0,
+									  $block);
+						$block = false;
+					}
+				}
+				$context = $edit->orig;
+			}
+			else {
+				if (! is_array($block)) {
+					$context = array_slice($context, sizeof($context) - $nlead);
+					$x0 = $xi - sizeof($context);
+					$y0 = $yi - sizeof($context);
+					$block = array();
+					if ($context)
+						$block[] = new _DiffOp_Copy($context);
+				}
+				$block[] = $edit;
+			}
+
+			if ($edit->orig)
+				$xi += sizeof($edit->orig);
+			if ($edit->closing)
+				$yi += sizeof($edit->closing);
+		}
+
+		if (is_array($block))
+			$this->_block($x0, $xi - $x0,
+						  $y0, $yi - $y0,
+						  $block);
+
+		$end = $this->_end_diff();
+		// wfProfileOut( $fname );
+		return $end;
+	}
+
+	function _block($xbeg, $xlen, $ybeg, $ylen, &$edits) {
+		$fname = 'DiffFormatter::_block';
+		// wfProfileIn( $fname );
+		$this->_start_block($this->_block_header($xbeg, $xlen, $ybeg, $ylen));
+		foreach ($edits as $edit) {
+			if ($edit->type == 'copy')
+				$this->_context($edit->orig);
+			elseif ($edit->type == 'add')
+				$this->_added($edit->closing);
+			elseif ($edit->type == 'delete')
+				$this->_deleted($edit->orig);
+			elseif ($edit->type == 'change')
+				$this->_changed($edit->orig, $edit->closing);
+			else
+				trigger_error('Unknown edit type', E_USER_ERROR);
+		}
+		$this->_end_block();
+		// wfProfileOut( $fname );
+	}
+
+	function _start_diff() {
+		ob_start();
+	}
+
+	function _end_diff() {
+		$val = ob_get_contents();
+		ob_end_clean();
+		return $val;
+	}
+
+	function _block_header($xbeg, $xlen, $ybeg, $ylen) {
+		if ($xlen > 1)
+			$xbeg .= "," . ($xbeg + $xlen - 1);
+		if ($ylen > 1)
+			$ybeg .= "," . ($ybeg + $ylen - 1);
+
+		return $xbeg . ($xlen ? ($ylen ? 'c' : 'd') : 'a') . $ybeg;
+	}
+
+	function _start_block($header) {
+		echo $header;
+	}
+
+	function _end_block() {
+	}
+
+	function _lines($lines, $prefix = ' ') {
+		foreach ($lines as $line)
+			echo "$prefix $line\n";
+	}
+
+	function _context($lines) {
+		$this->_lines($lines);
+	}
+
+	function _added($lines) {
+		$this->_lines($lines, '>');
+	}
+	function _deleted($lines) {
+		$this->_lines($lines, '<');
+	}
+
+	function _changed($orig, $closing) {
+		$this->_deleted($orig);
+		echo "---\n";
+		$this->_added($closing);
+	}
+}
+
+
+/**
+ *	Additions by Axel Boldt follow, partly taken from diff.php, phpwiki-1.3.3
+ *
+ */
+
+define('NBSP', '&#160;');			// iso-8859-x non-breaking space.
+
+/**
+ * @todo document
+ * @package Enano
+ * @subpackage DifferenceEngine
+ */
+class _HWLDF_WordAccumulator {
+	function _HWLDF_WordAccumulator () {
+		$this->_lines = array();
+		$this->_line = '';
+		$this->_group = '';
+		$this->_tag = '';
+	}
+
+	function _flushGroup ($new_tag) {
+		if ($this->_group !== '') {
+			if ($this->_tag == 'mark')
+				$this->_line .= '<span class="diffchange">' .
+					htmlspecialchars ( $this->_group ) . '</span>';
+			else
+				$this->_line .= htmlspecialchars ( $this->_group );
+		}
+		$this->_group = '';
+		$this->_tag = $new_tag;
+	}
+
+	function _flushLine ($new_tag) {
+		$this->_flushGroup($new_tag);
+		if ($this->_line != '')
+			array_push ( $this->_lines, $this->_line );
+		else
+			# make empty lines visible by inserting an NBSP
+			array_push ( $this->_lines, NBSP );
+		$this->_line = '';
+	}
+
+	function addWords ($words, $tag = '') {
+		if ($tag != $this->_tag)
+			$this->_flushGroup($tag);
+
+		foreach ($words as $word) {
+			// new-line should only come as first char of word.
+			if ($word == '')
+				continue;
+			if ($word[0] == "\n") {
+				$this->_flushLine($tag);
+				$word = substr($word, 1);
+			}
+			assert(!strstr($word, "\n"));
+			$this->_group .= $word;
+		}
+	}
+
+	function getLines() {
+		$this->_flushLine('~done');
+		return $this->_lines;
+	}
+}
+
+/**
+ * @todo document
+ * @package Enano
+ * @subpackage DifferenceEngine
+ */
+define('MAX_LINE_LENGTH', 10000);
+class WordLevelDiff extends MappedDiff
+{
+	function WordLevelDiff ($orig_lines, $closing_lines) {
+		$fname = 'WordLevelDiff::WordLevelDiff';
+		// wfProfileIn( $fname );
+
+		list ($orig_words, $orig_stripped) = $this->_split($orig_lines);
+		list ($closing_words, $closing_stripped) = $this->_split($closing_lines);
+
+		$this->MappedDiff($orig_words, $closing_words,
+						  $orig_stripped, $closing_stripped);
+		// wfProfileOut( $fname );
+	}
+
+	function _split($lines) {
+		$fname = 'WordLevelDiff::_split';
+		// wfProfileIn( $fname );
+
+		$words = array();
+		$stripped = array();
+		$first = true;
+		foreach ( $lines as $line ) {
+			# If the line is too long, just pretend the entire line is one big word
+			# This prevents resource exhaustion problems
+			if ( $first ) {
+				$first = false;
+			} else {
+				$words[] = "\n";
+				$stripped[] = "\n";
+			}
+			if ( strlen( $line ) > MAX_LINE_LENGTH ) {
+				$words[] = $line;
+				$stripped[] = $line;
+			} else {
+				if (preg_match_all('/ ( [^\S\n]+ | [0-9_A-Za-z\x80-\xff]+ | . ) (?: (?!< \n) [^\S\n])? /xs',
+					$line, $m))
+				{
+					$words = array_merge( $words, $m[0] );
+					$stripped = array_merge( $stripped, $m[1] );
+				}
+			}
+		}
+		// wfProfileOut( $fname );
+		return array($words, $stripped);
+	}
+
+	function orig () {
+		$fname = 'WordLevelDiff::orig';
+		// wfProfileIn( $fname );
+		$orig = new _HWLDF_WordAccumulator;
+
+		foreach ($this->edits as $edit) {
+			if ($edit->type == 'copy')
+				$orig->addWords($edit->orig);
+			elseif ($edit->orig)
+				$orig->addWords($edit->orig, 'mark');
+		}
+		$lines = $orig->getLines();
+		// wfProfileOut( $fname );
+		return $lines;
+	}
+
+	function closing () {
+		$fname = 'WordLevelDiff::closing';
+		// wfProfileIn( $fname );
+		$closing = new _HWLDF_WordAccumulator;
+
+		foreach ($this->edits as $edit) {
+			if ($edit->type == 'copy')
+				$closing->addWords($edit->closing);
+			elseif ($edit->closing)
+				$closing->addWords($edit->closing, 'mark');
+		}
+		$lines = $closing->getLines();
+		// wfProfileOut( $fname );
+		return $lines;
+	}
+}
+
+/**
+ *	Wikipedia Table style diff formatter.
+ * @todo document
+ * @package Enano
+ * @subpackage DifferenceEngine
+ */
+class TableDiffFormatter extends DiffFormatter
+{
+	function TableDiffFormatter() {
+		$this->leading_context_lines = 2;
+		$this->trailing_context_lines = 2;
+	}
+
+	function _block_header( $xbeg, $xlen, $ybeg, $ylen ) {
+		$r = '<tr><td colspan="2" align="left"><strong><!--LINE '.$xbeg."--></strong></td>\n" .
+		  '<td colspan="2" align="left"><strong><!--LINE '.$ybeg."--></strong></td></tr>\n";
+		return $r;
+	}
+
+	function _start_block( $header ) {
+		echo $header;
+	}
+
+	function _end_block() {
+	}
+
+	function _lines( $lines, $prefix=' ', $color='white' ) {
+	}
+
+	# HTML-escape parameter before calling this
+	function addedLine( $line ) {
+		return "<td>+</td><td class='diff-addedline'>{$line}</td>";
+	}
+
+	# HTML-escape parameter before calling this
+	function deletedLine( $line ) {
+		return "<td>-</td><td class='diff-deletedline'>{$line}</td>";
+	}
+
+	# HTML-escape parameter before calling this
+	function contextLine( $line ) {
+		return "<td> </td><td class='diff-context'>{$line}</td>";
+	}
+
+	function emptyLine() {
+		return '<td colspan="2">&nbsp;</td>';
+	}
+
+	function _added( $lines ) {
+		foreach ($lines as $line) {
+			echo '<tr>' . $this->emptyLine() .
+				$this->addedLine( htmlspecialchars ( $line ) ) . "</tr>\n";
+		}
+	}
+
+	function _deleted($lines) {
+		foreach ($lines as $line) {
+			echo '<tr>' . $this->deletedLine( htmlspecialchars ( $line ) ) .
+			  $this->emptyLine() . "</tr>\n";
+		}
+	}
+
+	function _context( $lines ) {
+		foreach ($lines as $line) {
+			echo '<tr>' .
+				$this->contextLine( htmlspecialchars ( $line ) ) .
+				$this->contextLine( htmlspecialchars ( $line ) ) . "</tr>\n";
+		}
+	}
+
+	function _changed( $orig, $closing ) {
+		$fname = 'TableDiffFormatter::_changed';
+		// wfProfileIn( $fname );
+
+		$diff = new WordLevelDiff( $orig, $closing );
+		$del = $diff->orig();
+		$add = $diff->closing();
+
+		# Notice that WordLevelDiff returns HTML-escaped output.
+		# Hence, we will be calling addedLine/deletedLine without HTML-escaping.
+
+		while ( $line = array_shift( $del ) ) {
+			$aline = array_shift( $add );
+			echo '<tr>' . $this->deletedLine( $line ) .
+				$this->addedLine( $aline ) . "</tr>\n";
+		}
+		foreach ($add as $line) {	# If any leftovers
+			echo '<tr>' . $this->emptyLine() .
+				$this->addedLine( $line ) . "</tr>\n";
+		}
+		// wfProfileOut( $fname );
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/diffengine/Engine/native.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,435 @@
+<?php
+/**
+ * Class used internally by Diff to actually compute the diffs.  This class is
+ * implemented using native PHP code.
+ *
+ * The algorithm used here is mostly lifted from the perl module
+ * Algorithm::Diff (version 1.06) by Ned Konz, which is available at:
+ * http://www.perl.com/CPAN/authors/id/N/NE/NEDKONZ/Algorithm-Diff-1.06.zip
+ *
+ * More ideas are taken from:
+ * http://www.ics.uci.edu/~eppstein/161/960229.html
+ *
+ * Some ideas (and a bit of code) are taken from analyze.c, of GNU
+ * diffutils-2.7, which can be found at:
+ * ftp://gnudist.gnu.org/pub/gnu/diffutils/diffutils-2.7.tar.gz
+ *
+ * Some ideas (subdivision by NCHUNKS > 2, and some optimizations) are from
+ * Geoffrey T. Dairiki <dairiki@dairiki.org>. The original PHP version of this
+ * code was written by him, and is used/adapted with his permission.
+ *
+ * $Horde: framework/Text_Diff/Diff/Engine/native.php,v 1.3 2006/01/06 15:56:52 jan Exp $
+ *
+ * @author  Geoffrey T. Dairiki <dairiki@dairiki.org>
+ * @package Text_Diff
+ *
+ * @access private
+ */
+class Text_Diff_Engine_native {
+
+    function diff($from_lines, $to_lines)
+    {
+        array_walk($from_lines, array('Text_Diff', 'trimNewlines'));
+        array_walk($to_lines, array('Text_Diff', 'trimNewlines'));
+
+        $n_from = count($from_lines);
+        $n_to = count($to_lines);
+
+        $this->xchanged = $this->ychanged = array();
+        $this->xv = $this->yv = array();
+        $this->xind = $this->yind = array();
+        unset($this->seq);
+        unset($this->in_seq);
+        unset($this->lcs);
+
+        // Skip leading common lines.
+        for ($skip = 0; $skip < $n_from && $skip < $n_to; $skip++) {
+            if ($from_lines[$skip] !== $to_lines[$skip]) {
+                break;
+            }
+            $this->xchanged[$skip] = $this->ychanged[$skip] = false;
+        }
+
+        // Skip trailing common lines.
+        $xi = $n_from; $yi = $n_to;
+        for ($endskip = 0; --$xi > $skip && --$yi > $skip; $endskip++) {
+            if ($from_lines[$xi] !== $to_lines[$yi]) {
+                break;
+            }
+            $this->xchanged[$xi] = $this->ychanged[$yi] = false;
+        }
+
+        // Ignore lines which do not exist in both files.
+        for ($xi = $skip; $xi < $n_from - $endskip; $xi++) {
+            $xhash[$from_lines[$xi]] = 1;
+        }
+        for ($yi = $skip; $yi < $n_to - $endskip; $yi++) {
+            $line = $to_lines[$yi];
+            if (($this->ychanged[$yi] = empty($xhash[$line]))) {
+                continue;
+            }
+            $yhash[$line] = 1;
+            $this->yv[] = $line;
+            $this->yind[] = $yi;
+        }
+        for ($xi = $skip; $xi < $n_from - $endskip; $xi++) {
+            $line = $from_lines[$xi];
+            if (($this->xchanged[$xi] = empty($yhash[$line]))) {
+                continue;
+            }
+            $this->xv[] = $line;
+            $this->xind[] = $xi;
+        }
+
+        // Find the LCS.
+        $this->_compareseq(0, count($this->xv), 0, count($this->yv));
+
+        // Merge edits when possible.
+        $this->_shiftBoundaries($from_lines, $this->xchanged, $this->ychanged);
+        $this->_shiftBoundaries($to_lines, $this->ychanged, $this->xchanged);
+
+        // Compute the edit operations.
+        $edits = array();
+        $xi = $yi = 0;
+        while ($xi < $n_from || $yi < $n_to) {
+            assert($yi < $n_to || $this->xchanged[$xi]);
+            assert($xi < $n_from || $this->ychanged[$yi]);
+
+            // Skip matching "snake".
+            $copy = array();
+            while ($xi < $n_from && $yi < $n_to
+                   && !$this->xchanged[$xi] && !$this->ychanged[$yi]) {
+                $copy[] = $from_lines[$xi++];
+                ++$yi;
+            }
+            if ($copy) {
+                $edits[] = &new Text_Diff_Op_copy($copy);
+            }
+
+            // Find deletes & adds.
+            $delete = array();
+            while ($xi < $n_from && $this->xchanged[$xi]) {
+                $delete[] = $from_lines[$xi++];
+            }
+
+            $add = array();
+            while ($yi < $n_to && $this->ychanged[$yi]) {
+                $add[] = $to_lines[$yi++];
+            }
+
+            if ($delete && $add) {
+                $edits[] = &new Text_Diff_Op_change($delete, $add);
+            } elseif ($delete) {
+                $edits[] = &new Text_Diff_Op_delete($delete);
+            } elseif ($add) {
+                $edits[] = &new Text_Diff_Op_add($add);
+            }
+        }
+
+        return $edits;
+    }
+
+    /**
+     * Divides the Largest Common Subsequence (LCS) of the sequences (XOFF,
+     * XLIM) and (YOFF, YLIM) into NCHUNKS approximately equally sized
+     * segments.
+     *
+     * Returns (LCS, PTS).  LCS is the length of the LCS. PTS is an array of
+     * NCHUNKS+1 (X, Y) indexes giving the diving points between sub
+     * sequences.  The first sub-sequence is contained in (X0, X1), (Y0, Y1),
+     * the second in (X1, X2), (Y1, Y2) and so on.  Note that (X0, Y0) ==
+     * (XOFF, YOFF) and (X[NCHUNKS], Y[NCHUNKS]) == (XLIM, YLIM).
+     *
+     * This function assumes that the first lines of the specified portions of
+     * the two files do not match, and likewise that the last lines do not
+     * match.  The caller must trim matching lines from the beginning and end
+     * of the portions it is going to specify.
+     */
+    function _diag ($xoff, $xlim, $yoff, $ylim, $nchunks)
+    {
+        $flip = false;
+
+        if ($xlim - $xoff > $ylim - $yoff) {
+            /* Things seems faster (I'm not sure I understand why) when the
+             * shortest sequence is in X. */
+            $flip = true;
+            list ($xoff, $xlim, $yoff, $ylim)
+                = array($yoff, $ylim, $xoff, $xlim);
+        }
+
+        if ($flip) {
+            for ($i = $ylim - 1; $i >= $yoff; $i--) {
+                $ymatches[$this->xv[$i]][] = $i;
+            }
+        } else {
+            for ($i = $ylim - 1; $i >= $yoff; $i--) {
+                $ymatches[$this->yv[$i]][] = $i;
+            }
+        }
+
+        $this->lcs = 0;
+        $this->seq[0]= $yoff - 1;
+        $this->in_seq = array();
+        $ymids[0] = array();
+
+        $numer = $xlim - $xoff + $nchunks - 1;
+        $x = $xoff;
+        for ($chunk = 0; $chunk < $nchunks; $chunk++) {
+            if ($chunk > 0) {
+                for ($i = 0; $i <= $this->lcs; $i++) {
+                    $ymids[$i][$chunk - 1] = $this->seq[$i];
+                }
+            }
+
+            $x1 = $xoff + (int)(($numer + ($xlim-$xoff)*$chunk) / $nchunks);
+            for (; $x < $x1; $x++) {
+                $line = $flip ? $this->yv[$x] : $this->xv[$x];
+                if (empty($ymatches[$line])) {
+                    continue;
+                }
+                $matches = $ymatches[$line];
+                foreach ($matches as $y) {
+                    if (empty($this->in_seq[$y])) {
+                        $k = $this->_lcsPos($y);
+                        assert($k > 0);
+                        $ymids[$k] = $ymids[$k - 1];
+                        break;
+                    }
+                }
+
+                while (list($junk, $y) = each($matches)) {
+                    if ($y > $this->seq[$k - 1]) {
+                        assert($y < $this->seq[$k]);
+                        /* Optimization: this is a common case: next match is
+                         * just replacing previous match. */
+                        $this->in_seq[$this->seq[$k]] = false;
+                        $this->seq[$k] = $y;
+                        $this->in_seq[$y] = 1;
+                    } elseif (empty($this->in_seq[$y])) {
+                        $k = $this->_lcsPos($y);
+                        assert($k > 0);
+                        $ymids[$k] = $ymids[$k - 1];
+                    }
+                }
+            }
+        }
+
+        $seps[] = $flip ? array($yoff, $xoff) : array($xoff, $yoff);
+        $ymid = $ymids[$this->lcs];
+        for ($n = 0; $n < $nchunks - 1; $n++) {
+            $x1 = $xoff + (int)(($numer + ($xlim - $xoff) * $n) / $nchunks);
+            $y1 = $ymid[$n] + 1;
+            $seps[] = $flip ? array($y1, $x1) : array($x1, $y1);
+        }
+        $seps[] = $flip ? array($ylim, $xlim) : array($xlim, $ylim);
+
+        return array($this->lcs, $seps);
+    }
+
+    function _lcsPos($ypos)
+    {
+        $end = $this->lcs;
+        if ($end == 0 || $ypos > $this->seq[$end]) {
+            $this->seq[++$this->lcs] = $ypos;
+            $this->in_seq[$ypos] = 1;
+            return $this->lcs;
+        }
+
+        $beg = 1;
+        while ($beg < $end) {
+            $mid = (int)(($beg + $end) / 2);
+            if ($ypos > $this->seq[$mid]) {
+                $beg = $mid + 1;
+            } else {
+                $end = $mid;
+            }
+        }
+
+        assert($ypos != $this->seq[$end]);
+
+        $this->in_seq[$this->seq[$end]] = false;
+        $this->seq[$end] = $ypos;
+        $this->in_seq[$ypos] = 1;
+        return $end;
+    }
+
+    /**
+     * Finds LCS of two sequences.
+     *
+     * The results are recorded in the vectors $this->{x,y}changed[], by
+     * storing a 1 in the element for each line that is an insertion or
+     * deletion (ie. is not in the LCS).
+     *
+     * The subsequence of file 0 is (XOFF, XLIM) and likewise for file 1.
+     *
+     * Note that XLIM, YLIM are exclusive bounds.  All line numbers are
+     * origin-0 and discarded lines are not counted.
+     */
+    function _compareseq ($xoff, $xlim, $yoff, $ylim)
+    {
+        /* Slide down the bottom initial diagonal. */
+        while ($xoff < $xlim && $yoff < $ylim
+               && $this->xv[$xoff] == $this->yv[$yoff]) {
+            ++$xoff;
+            ++$yoff;
+        }
+
+        /* Slide up the top initial diagonal. */
+        while ($xlim > $xoff && $ylim > $yoff
+               && $this->xv[$xlim - 1] == $this->yv[$ylim - 1]) {
+            --$xlim;
+            --$ylim;
+        }
+
+        if ($xoff == $xlim || $yoff == $ylim) {
+            $lcs = 0;
+        } else {
+            /* This is ad hoc but seems to work well.  $nchunks =
+             * sqrt(min($xlim - $xoff, $ylim - $yoff) / 2.5); $nchunks =
+             * max(2,min(8,(int)$nchunks)); */
+            $nchunks = min(7, $xlim - $xoff, $ylim - $yoff) + 1;
+            list($lcs, $seps)
+                = $this->_diag($xoff, $xlim, $yoff, $ylim, $nchunks);
+        }
+
+        if ($lcs == 0) {
+            /* X and Y sequences have no common subsequence: mark all
+             * changed. */
+            while ($yoff < $ylim) {
+                $this->ychanged[$this->yind[$yoff++]] = 1;
+            }
+            while ($xoff < $xlim) {
+                $this->xchanged[$this->xind[$xoff++]] = 1;
+            }
+        } else {
+            /* Use the partitions to split this problem into subproblems. */
+            reset($seps);
+            $pt1 = $seps[0];
+            while ($pt2 = next($seps)) {
+                $this->_compareseq ($pt1[0], $pt2[0], $pt1[1], $pt2[1]);
+                $pt1 = $pt2;
+            }
+        }
+    }
+
+    /**
+     * Adjusts inserts/deletes of identical lines to join changes as much as
+     * possible.
+     *
+     * We do something when a run of changed lines include a line at one end
+     * and has an excluded, identical line at the other.  We are free to
+     * choose which identical line is included.  `compareseq' usually chooses
+     * the one at the beginning, but usually it is cleaner to consider the
+     * following identical line to be the "change".
+     *
+     * This is extracted verbatim from analyze.c (GNU diffutils-2.7).
+     */
+    function _shiftBoundaries($lines, &$changed, $other_changed)
+    {
+        $i = 0;
+        $j = 0;
+
+        assert('count($lines) == count($changed)');
+        $len = count($lines);
+        $other_len = count($other_changed);
+
+        while (1) {
+            /* Scan forward to find the beginning of another run of
+             * changes. Also keep track of the corresponding point in the
+             * other file.
+             *
+             * Throughout this code, $i and $j are adjusted together so that
+             * the first $i elements of $changed and the first $j elements of
+             * $other_changed both contain the same number of zeros (unchanged
+             * lines).
+             *
+             * Furthermore, $j is always kept so that $j == $other_len or
+             * $other_changed[$j] == false. */
+            while ($j < $other_len && $other_changed[$j]) {
+                $j++;
+            }
+
+            while ($i < $len && ! $changed[$i]) {
+                assert('$j < $other_len && ! $other_changed[$j]');
+                $i++; $j++;
+                while ($j < $other_len && $other_changed[$j]) {
+                    $j++;
+                }
+            }
+
+            if ($i == $len) {
+                break;
+            }
+
+            $start = $i;
+
+            /* Find the end of this run of changes. */
+            while (++$i < $len && $changed[$i]) {
+                continue;
+            }
+
+            do {
+                /* Record the length of this run of changes, so that we can
+                 * later determine whether the run has grown. */
+                $runlength = $i - $start;
+
+                /* Move the changed region back, so long as the previous
+                 * unchanged line matches the last changed one.  This merges
+                 * with previous changed regions. */
+                while ($start > 0 && $lines[$start - 1] == $lines[$i - 1]) {
+                    $changed[--$start] = 1;
+                    $changed[--$i] = false;
+                    while ($start > 0 && $changed[$start - 1]) {
+                        $start--;
+                    }
+                    assert('$j > 0');
+                    while ($other_changed[--$j]) {
+                        continue;
+                    }
+                    assert('$j >= 0 && !$other_changed[$j]');
+                }
+
+                /* Set CORRESPONDING to the end of the changed run, at the
+                 * last point where it corresponds to a changed run in the
+                 * other file. CORRESPONDING == LEN means no such point has
+                 * been found. */
+                $corresponding = $j < $other_len ? $i : $len;
+
+                /* Move the changed region forward, so long as the first
+                 * changed line matches the following unchanged one.  This
+                 * merges with following changed regions.  Do this second, so
+                 * that if there are no merges, the changed region is moved
+                 * forward as far as possible. */
+                while ($i < $len && $lines[$start] == $lines[$i]) {
+                    $changed[$start++] = false;
+                    $changed[$i++] = 1;
+                    while ($i < $len && $changed[$i]) {
+                        $i++;
+                    }
+
+                    assert('$j < $other_len && ! $other_changed[$j]');
+                    $j++;
+                    if ($j < $other_len && $other_changed[$j]) {
+                        $corresponding = $i;
+                        while ($j < $other_len && $other_changed[$j]) {
+                            $j++;
+                        }
+                    }
+                }
+            } while ($runlength != $i - $start);
+
+            /* If possible, move the fully-merged run of changes back to a
+             * corresponding run in the other file. */
+            while ($corresponding < $i) {
+                $changed[--$start] = 1;
+                $changed[--$i] = 0;
+                assert('$j > 0');
+                while ($other_changed[--$j]) {
+                    continue;
+                }
+                assert('$j >= 0 && !$other_changed[$j]');
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/diffengine/Engine/string.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,216 @@
+<?php
+/**
+ * Parses unified or context diffs output from eg. the diff utility.
+ *
+ * Example:
+ * <code>
+ * $patch = file_get_contents('example.patch');
+ * $diff = &new Text_Diff('string', array($patch));
+ * $renderer = &new Text_Diff_Renderer_inline();
+ * echo $renderer->render($diff);
+ * </code>
+ *
+ * @author    �rjan Persson <o@42mm.org>
+ * @copyright Copyright 2005 �rjan Persson
+ * @package   Text_Diff
+ * @since     0.2.0
+ * @access    private
+ */
+class Text_Diff_Engine_string {
+
+    /**
+     * Parses a unified or context diff.
+     *
+     * First param contains the whole diff and the second can be used to force 
+     * a specific diff type. If the second parameter is 'autodetect', the 
+     * diff will be examined to find out which type of diff this is.
+     * 
+     * @param string $diff  The diff content.
+     * @param string $mode  The diff mode of the content in $diff. One of
+     *                      'context', 'unified', or 'autodetect'.
+     *
+     * @return array  List of all diff operations.
+     */
+    function diff($diff, $mode = 'autodetect')
+    {
+        if ($mode != 'autodetect' && $mode != 'context' && $mode != 'unified') {
+            die_friendly('Text_Diff', '<p>Type of diff is unsupported</p>');
+        }
+
+        if ($mode == 'autodetect') {
+            $context = strpos($diff, '***');
+            $unified = strpos($diff, '---');
+            if ($context === $unified) {
+                die_friendly('Text_Diff', '<p>Type of diff could not be detected</p>');
+            } elseif ($context === false || $context === false) {
+                $mode = $context !== false ? 'context' : 'unified';
+            } else {
+                $mode = $context < $unified ? 'context' : 'unified';
+            }
+        }
+
+        // split by new line and remove the diff header
+        $diff = explode("\n", $diff);
+        array_shift($diff);
+        array_shift($diff);
+
+        if ($mode == 'context') {
+            return $this->parseContextDiff($diff);
+        } else {
+            return $this->parseUnifiedDiff($diff);
+        }
+    }
+
+    /**
+     * Parses an array containing the unified diff.
+     *
+     * @param array $diff  Array of lines.
+     *
+     * @return array  List of all diff operations.
+     */
+    function parseUnifiedDiff($diff)
+    {
+        $edits = array();
+        $end = count($diff) - 1;
+        for ($i = 0; $i < $end;) {
+            $diff1 = array();
+            switch (substr($diff[$i], 0, 1)) {
+            case ' ':
+                do {
+                    $diff1[] = substr($diff[$i], 1);
+                } while (++$i < $end && substr($diff[$i], 0, 1) == ' ');
+                $edits[] = &new Text_Diff_Op_copy($diff1);
+                break;
+            case '+':
+                // get all new lines
+                do {
+                    $diff1[] = substr($diff[$i], 1);
+                } while (++$i < $end && substr($diff[$i], 0, 1) == '+');
+                $edits[] = &new Text_Diff_Op_add($diff1);
+                break;
+            case '-':
+                // get changed or removed lines
+                $diff2 = array();
+                do {
+                    $diff1[] = substr($diff[$i], 1);
+                } while (++$i < $end && substr($diff[$i], 0, 1) == '-');
+                while ($i < $end && substr($diff[$i], 0, 1) == '+') {
+                    $diff2[] = substr($diff[$i++], 1);
+                }
+                if (count($diff2) == 0) {
+                    $edits[] = &new Text_Diff_Op_delete($diff1);
+                } else {
+                    $edits[] = &new Text_Diff_Op_change($diff1, $diff2);
+                }
+                break;
+            default:
+                $i++;
+                break;
+            }
+        }
+        return $edits;
+    }
+
+    /**
+     * Parses an array containing the context diff.
+     *
+     * @param array $diff  Array of lines.
+     *
+     * @return array  List of all diff operations.
+     */
+    function parseContextDiff(&$diff)
+    {
+        $edits = array();
+        $i = $max_i = $j = $max_j = 0;
+        $end = count($diff) - 1;
+        while ($i < $end && $j < $end) {
+            while ($i >= $max_i && $j >= $max_j) {
+                // find the boundaries of the diff output of the two files
+                for ($i = $j;
+                     $i < $end && substr($diff[$i], 0, 3) == '***';
+                     $i++);
+                for ($max_i = $i;
+                     $max_i < $end && substr($diff[$max_i], 0, 3) != '---';
+                     $max_i++);
+                for ($j = $max_i;
+                     $j < $end && substr($diff[$j], 0, 3) == '---';
+                     $j++);
+                for ($max_j = $j;
+                     $max_j < $end && substr($diff[$max_j], 0, 3) != '***';
+                     $max_j++);
+            }
+
+            // find what hasn't been changed
+            $array = array();
+            while ($i < $max_i &&
+                   $j < $max_j &&
+                   strcmp($diff[$i], $diff[$j]) == 0) {
+                $array[] = substr($diff[$i], 2);
+                $i++;
+                $j++;
+            }
+            while ($i < $max_i && ($max_j-$j) <= 1) {
+                if ($diff[$i] != '' && substr($diff[$i], 0, 1) != ' ') {
+                    break;
+                }
+                $array[] = substr($diff[$i++], 2);
+            }
+            while ($j < $max_j && ($max_i-$i) <= 1) {
+                if ($diff[$j] != '' && substr($diff[$j], 0, 1) != ' ') {
+                    break;
+                }
+                $array[] = substr($diff[$j++], 2);
+            }
+            if (count($array) > 0) {
+                $edits[] = &new Text_Diff_Op_copy($array);
+            }
+
+            if ($i < $max_i) {
+                $diff1 = array();
+                switch (substr($diff[$i], 0, 1)) {
+                case '!':
+                    $diff2 = array();
+                    do {
+                        $diff1[] = substr($diff[$i], 2);
+                        if ($j < $max_j && substr($diff[$j], 0, 1) == '!') {
+                            $diff2[] = substr($diff[$j++], 2);
+                        }
+                    } while (++$i < $max_i && substr($diff[$i], 0, 1) == '!');
+                    $edits[] = &new Text_Diff_Op_change($diff1, $diff2);
+                    break;
+                case '+':
+                    do {
+                        $diff1[] = substr($diff[$i], 2);
+                    } while (++$i < $max_i && substr($diff[$i], 0, 1) == '+');
+                    $edits[] = &new Text_Diff_Op_add($diff1);
+                    break;
+                case '-':
+                    do {
+                        $diff1[] = substr($diff[$i], 2);
+                    } while (++$i < $max_i && substr($diff[$i], 0, 1) == '-');
+                    $edits[] = &new Text_Diff_Op_delete($diff1);
+                    break;
+                }
+            }
+
+            if ($j < $max_j) {
+                $diff2 = array();
+                switch (substr($diff[$j], 0, 1)) {
+                case '+':
+                    do {
+                        $diff2[] = substr($diff[$j++], 2);
+                    } while ($j < $max_j && substr($diff[$j], 0, 1) == '+');
+                    $edits[] = &new Text_Diff_Op_add($diff2);
+                    break;
+                case '-':
+                    do {
+                        $diff2[] = substr($diff[$j++], 2);
+                    } while ($j < $max_j && substr($diff[$j], 0, 1) == '-');
+                    $edits[] = &new Text_Diff_Op_delete($diff2);
+                    break;
+                }
+            }
+        }
+        return $edits;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/diffengine/Engine/xdiff.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,55 @@
+<?php
+/**
+ * Class used internally by Diff to actually compute the diffs.  This class
+ * uses the xdiff PECL package (http://pecl.php.net/package/xdiff) to compute
+ * the differences between the two input arrays.
+ *
+ * @author  Jon Parise <jon@horde.org>
+ * @package Text_Diff
+ *
+ * @access private
+ */
+class Text_Diff_Engine_xdiff {
+
+    function diff($from_lines, $to_lines)
+    {
+        array_walk($from_lines, array('Text_Diff', 'trimNewlines'));
+        array_walk($to_lines, array('Text_Diff', 'trimNewlines'));
+
+        /* Convert the two input arrays into strings for xdiff processing. */
+        $from_string = implode("\n", $from_lines);
+        $to_string = implode("\n", $to_lines);
+
+        /* Diff the two strings and convert the result to an array. */
+        $diff = xdiff_string_diff($from_string, $to_string, count($to_lines));
+        $diff = explode("\n", $diff);
+
+        /* Walk through the diff one line at a time.  We build the $edits
+         * array of diff operations by reading the first character of the
+         * xdiff output (which is in the "unified diff" format).
+         *
+         * Note that we don't have enough information to detect "changed"
+         * lines using this approach, so we can't add Text_Diff_Op_changed
+         * instances to the $edits array.  The result is still perfectly
+         * valid, albeit a little less descriptive and efficient. */
+        $edits = array();
+        foreach ($diff as $line) {
+            switch ($line[0]) {
+            case ' ':
+                $edits[] = &new Text_Diff_Op_copy(array(substr($line, 1)));
+                break;
+
+            case '+':
+                $edits[] = &new Text_Diff_Op_add(array(substr($line, 1)));
+                break;
+
+            case '-':
+                $edits[] = &new Text_Diff_Op_delete(array(substr($line, 1)));
+                break;
+            }
+        }
+
+        return $edits;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/diffengine/Renderer.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,211 @@
+<?php
+/**
+ * A class to render Diffs in different formats.
+ *
+ * This class renders the diff in classic diff format. It is intended that
+ * this class be customized via inheritance, to obtain fancier outputs.
+ *
+ * $Horde: framework/Text_Diff/Diff/Renderer.php,v 1.12 2005/12/16 11:07:33 jan Exp $
+ *
+ * @package Text_Diff
+ */
+class Text_Diff_Renderer {
+
+    /**
+     * Number of leading context "lines" to preserve.
+     *
+     * This should be left at zero for this class, but subclasses may want to
+     * set this to other values.
+     */
+    var $_leading_context_lines = 0;
+
+    /**
+     * Number of trailing context "lines" to preserve.
+     *
+     * This should be left at zero for this class, but subclasses may want to
+     * set this to other values.
+     */
+    var $_trailing_context_lines = 0;
+
+    /**
+     * Constructor.
+     */
+    function Text_Diff_Renderer($params = array())
+    {
+        foreach ($params as $param => $value) {
+            $v = '_' . $param;
+            if (isset($this->$v)) {
+                $this->$v = $value;
+            }
+        }
+    }
+
+    /**
+     * Get any renderer parameters.
+     *
+     * @return array  All parameters of this renderer object.
+     */
+    function getParams()
+    {
+        $params = array();
+        foreach (get_object_vars($this) as $k => $v) {
+            if ($k[0] == '_') {
+                $params[substr($k, 1)] = $v;
+            }
+        }
+
+        return $params;
+    }
+
+    /**
+     * Renders a diff.
+     *
+     * @param Text_Diff $diff  A Text_Diff object.
+     *
+     * @return string  The formatted output.
+     */
+    function render($diff)
+    {
+        $xi = $yi = 1;
+        $block = false;
+        $context = array();
+
+        $nlead = $this->_leading_context_lines;
+        $ntrail = $this->_trailing_context_lines;
+
+        $output = $this->_startDiff();
+
+        $diffs = $diff->getDiff();
+        foreach ($diffs as $i => $edit) {
+            if (is_a($edit, 'Text_Diff_Op_copy')) {
+                if (is_array($block)) {
+                    $keep = $i == count($diffs) - 1 ? $ntrail : $nlead + $ntrail;
+                    if (count($edit->orig) <= $keep) {
+                        $block[] = $edit;
+                    } else {
+                        if ($ntrail) {
+                            $context = array_slice($edit->orig, 0, $ntrail);
+                            $block[] = &new Text_Diff_Op_copy($context);
+                        }
+                        $output .= $this->_block($x0, $ntrail + $xi - $x0,
+                                                 $y0, $ntrail + $yi - $y0,
+                                                 $block);
+                        $block = false;
+                    }
+                }
+                $context = $edit->orig;
+            } else {
+                if (!is_array($block)) {
+                    $context = array_slice($context, count($context) - $nlead);
+                    $x0 = $xi - count($context);
+                    $y0 = $yi - count($context);
+                    $block = array();
+                    if ($context) {
+                        $block[] = &new Text_Diff_Op_copy($context);
+                    }
+                }
+                $block[] = $edit;
+            }
+
+            if ($edit->orig) {
+                $xi += count($edit->orig);
+            }
+            if ($edit->final) {
+                $yi += count($edit->final);
+            }
+        }
+
+        if (is_array($block)) {
+            $output .= $this->_block($x0, $xi - $x0,
+                                     $y0, $yi - $y0,
+                                     $block);
+        }
+
+        return $output . $this->_endDiff();
+    }
+
+    function _block($xbeg, $xlen, $ybeg, $ylen, &$edits)
+    {
+        $output = $this->_startBlock($this->_blockHeader($xbeg, $xlen, $ybeg, $ylen));
+
+        foreach ($edits as $edit) {
+            switch (strtolower(get_class($edit))) {
+            case 'text_diff_op_copy':
+                $output .= $this->_context($edit->orig);
+                break;
+
+            case 'text_diff_op_add':
+                $output .= $this->_added($edit->final);
+                break;
+
+            case 'text_diff_op_delete':
+                $output .= $this->_deleted($edit->orig);
+                break;
+
+            case 'text_diff_op_change':
+                $output .= $this->_changed($edit->orig, $edit->final);
+                break;
+            }
+        }
+
+        return $output . $this->_endBlock();
+    }
+
+    function _startDiff()
+    {
+        return '';
+    }
+
+    function _endDiff()
+    {
+        return '';
+    }
+
+    function _blockHeader($xbeg, $xlen, $ybeg, $ylen)
+    {
+        if ($xlen > 1) {
+            $xbeg .= ',' . ($xbeg + $xlen - 1);
+        }
+        if ($ylen > 1) {
+            $ybeg .= ',' . ($ybeg + $ylen - 1);
+        }
+
+        return $xbeg . ($xlen ? ($ylen ? 'c' : 'd') : 'a') . $ybeg;
+    }
+
+    function _startBlock($header)
+    {
+        return $header . "\n";
+    }
+
+    function _endBlock()
+    {
+        return '';
+    }
+
+    function _lines($lines, $prefix = ' ')
+    {
+        return $prefix . implode("\n$prefix", $lines) . "\n";
+    }
+
+    function _context($lines)
+    {
+        return $this->_lines($lines);
+    }
+
+    function _added($lines)
+    {
+        return $this->_lines($lines, '>');
+    }
+
+    function _deleted($lines)
+    {
+        return $this->_lines($lines, '<');
+    }
+
+    function _changed($orig, $final)
+    {
+        return $this->_deleted($orig) . "---\n" . $this->_added($final);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/diffengine/Renderer/inline.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,158 @@
+<?php
+
+/**
+ * "Inline" diff renderer.
+ *
+ * This class renders diffs in the Wiki-style "inline" format.
+ *
+ * $Horde: framework/Text_Diff/Diff/Renderer/inline.php,v 1.16 2006/01/08 00:06:57 jan Exp $
+ *
+ * @author  Ciprian Popovici
+ * @package Text_Diff
+ */
+class Text_Diff_Renderer_inline extends Text_Diff_Renderer {
+
+    /**
+     * Number of leading context "lines" to preserve.
+     */
+    var $_leading_context_lines = 10000;
+
+    /**
+     * Number of trailing context "lines" to preserve.
+     */
+    var $_trailing_context_lines = 10000;
+
+    /**
+     * Prefix for inserted text.
+     */
+    var $_ins_prefix = '<ins>';
+
+    /**
+     * Suffix for inserted text.
+     */
+    var $_ins_suffix = '</ins>';
+
+    /**
+     * Prefix for deleted text.
+     */
+    var $_del_prefix = '<del>';
+
+    /**
+     * Suffix for deleted text.
+     */
+    var $_del_suffix = '</del>';
+
+    /**
+     * Header for each change block.
+     */
+    var $_block_header = '';
+
+    /**
+     * What are we currently splitting on? Used to recurse to show word-level
+     * changes.
+     */
+    var $_split_level = 'words';
+
+    function _blockHeader($xbeg, $xlen, $ybeg, $ylen)
+    {
+        return $this->_block_header;
+    }
+
+    function _startBlock($header)
+    {
+        return $header;
+    }
+
+    function _lines($lines, $prefix = ' ', $encode = true)
+    {
+        if ($encode) {
+            array_walk($lines, array(&$this, '_encode'));
+        }
+
+        if ($this->_split_level == 'words') {
+            return implode('', $lines);
+        } else {
+            return implode("\n", $lines) . "\n";
+        }
+    }
+
+    function _added($lines)
+    {
+        array_walk($lines, array(&$this, '_encode'));
+        $lines[0] = $this->_ins_prefix . $lines[0];
+        $lines[count($lines) - 1] .= $this->_ins_suffix;
+        return $this->_lines($lines, ' ', false);
+    }
+
+    function _deleted($lines, $words = false)
+    {
+        array_walk($lines, array(&$this, '_encode'));
+        $lines[0] = $this->_del_prefix . $lines[0];
+        $lines[count($lines) - 1] .= $this->_del_suffix;
+        return $this->_lines($lines, ' ', false);
+    }
+    
+    function _context($lines)
+    {
+        return "<!-- Start context -->\n<tr><td></td><td class=\"diff-context\">".$this->_lines($lines).'</td></tr>'."\n<!-- End context -->\n\n";
+    }
+
+    function _changed($orig, $final)
+    {
+        /* If we've already split on words, don't try to do so again - just
+         * display. */
+        if ($this->_split_level == 'words') {
+            $prefix = '';
+            while ($orig[0] !== false && $final[0] !== false &&
+                   substr($orig[0], 0, 1) == ' ' &&
+                   substr($final[0], 0, 1) == ' ') {
+                $prefix .= substr($orig[0], 0, 1);
+                $orig[0] = substr($orig[0], 1);
+                $final[0] = substr($final[0], 1);
+            }
+            return $prefix . $this->_deleted($orig) . $this->_added($final);
+        }
+
+        $text1 = implode("\n", $orig);
+        $text2 = implode("\n", $final);
+
+        /* Non-printing newline marker. */
+        $nl = "\0";
+
+        /* We want to split on word boundaries, but we need to
+         * preserve whitespace as well. Therefore we split on words,
+         * but include all blocks of whitespace in the wordlist. */
+        $diff = &new Text_Diff($this->_splitOnWords($text1, $nl),
+                               $this->_splitOnWords($text2, $nl));
+
+        /* Get the diff in inline format. */
+        $renderer = &new Text_Diff_Renderer_inline(array_merge($this->getParams(),
+                                                               array('split_level' => 'words')));
+
+        /* Run the diff and get the output. */
+        return str_replace($nl, "\n", $renderer->render($diff)) . "\n";
+    }
+
+    function _splitOnWords($string, $newlineEscape = "\n")
+    {
+        $words = array();
+        $length = strlen($string);
+        $pos = 0;
+
+        while ($pos < $length) {
+            // Eat a word with any preceding whitespace.
+            $spaces = strspn(substr($string, $pos), " \n");
+            $nextpos = strcspn(substr($string, $pos + $spaces), " \n");
+            $words[] = str_replace("\n", $newlineEscape, substr($string, $pos, $spaces + $nextpos));
+            $pos += $spaces + $nextpos;
+        }
+
+        return $words;
+    }
+
+    function _encode(&$string)
+    {
+        $string = htmlspecialchars($string);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/diffengine/Renderer/unified.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,50 @@
+<?php
+
+/**
+ * "Unified" diff renderer.
+ *
+ * This class renders the diff in classic "unified diff" format.
+ *
+ * $Horde: framework/Text_Diff/Diff/Renderer/unified.php,v 1.5 2006/01/08 00:06:57 jan Exp $
+ *
+ * @package Text_Diff
+ */
+class Text_Diff_Renderer_unified extends Text_Diff_Renderer {
+
+    /**
+     * Number of leading context "lines" to preserve.
+     */
+    var $_leading_context_lines = 4;
+
+    /**
+     * Number of trailing context "lines" to preserve.
+     */
+    var $_trailing_context_lines = 4;
+
+    function _blockHeader($xbeg, $xlen, $ybeg, $ylen)
+    {
+        if ($xlen != 1) {
+            $xbeg .= ',' . $xlen;
+        }
+        if ($ylen != 1) {
+            $ybeg .= ',' . $ylen;
+        }
+        return "@@ -$xbeg +$ybeg @@";
+    }
+
+    function _added($lines)
+    {
+        return $this->_lines($lines, '+');
+    }
+
+    function _deleted($lines)
+    {
+        return $this->_lines($lines, '-');
+    }
+
+    function _changed($orig, $final)
+    {
+        return $this->_deleted($orig) . $this->_added($final);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/diffengine/Renderer/xhtml.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,262 @@
+<?php
+
+/**
+ * XHTML diff renderer.
+ *
+ * This class renders diffs in XHTML format.
+ *
+ * $Horde: framework/Text_Diff/Diff/Renderer/inline.php,v 1.16 2006/01/08 00:06:57 jan Exp $
+ *
+ * @author  Ciprian Popovici
+ * @author  Dan Fuhry
+ * @package Text_Diff
+ */
+class Text_Diff_Renderer_xhtml extends Text_Diff_Renderer {
+
+    /**
+     * Number of leading context "lines" to preserve.
+     */
+    var $_leading_context_lines = 5;
+
+    /**
+     * Number of trailing context "lines" to preserve.
+     */
+    var $_trailing_context_lines = 3;
+
+    /**
+     * Prefix for inserted text.
+     */
+    var $_ins_prefix = "<!-- Start added text -->\n<tr><td style='width: 0px;'>+</td><td class=\"diff-added\" style='width: 100%;'>";
+
+    /**
+     * Suffix for inserted text.
+     */
+    var $_ins_suffix = "</td></tr>\n<!-- End added text -->\n\n";
+
+    /**
+     * Prefix for deleted text.
+     */
+    var $_del_prefix = "<!-- Start deleted text -->\n<tr><td style='width: 0px;'>-</td><td class=\"diff-deleted\" style='width: 100%;'>";
+
+    /**
+     * Suffix for deleted text.
+     */
+    var $_del_suffix = "</td></tr>\n<!-- End deleted text -->\n\n";
+
+    /**
+     * Header for each change block.
+     */
+    var $_block_header = '';
+
+    /**
+     * What are we currently splitting on? Used to recurse to show word-level
+     * changes.
+     */
+    var $_split_level = 'lines';
+    
+    function _blockHeader($xbeg, $xlen, $ybeg, $ylen)
+    {
+      return "<!-- Start block -->\n<tr><td colspan='2' class='diff-block'>Line $xbeg: {$this->_block_header}</td></tr>";
+    }
+
+    function _startBlock($header)
+    {
+        return $header;
+    }
+
+    function _lines($lines, $prefix = ' ', $encode = true)
+    {
+        if ($encode) {
+            array_walk($lines, array(&$this, '_encode'));
+        }
+
+        if ($this->_split_level == 'words') {
+            return implode('', $lines);
+        } else {
+            return implode("<br />", $lines) . "\n";
+        }
+    }
+
+    function _added($lines)
+    {
+        array_walk($lines, array(&$this, '_encode'));
+        $lines[0] = $this->_ins_prefix . $lines[0];
+        $lines[count($lines) - 1] .= $this->_ins_suffix;
+        return $this->_lines($lines, ' ', false);
+    }
+
+    function _deleted($lines, $words = false)
+    {
+        array_walk($lines, array(&$this, '_encode'));
+        $lines[0] = $this->_del_prefix . $lines[0];
+        $lines[count($lines) - 1] .= $this->_del_suffix;
+        return $this->_lines($lines, ' ', false);
+    }
+    
+    function _context($lines)
+    {
+        return "<!-- Start context -->\n<tr><td></td><td class=\"diff-context\">".$this->_lines($lines).'</td></tr>'."\n<!-- End context -->\n\n";
+    }
+
+    function _changed($orig, $final)
+    {
+        /* If we've already split on words, don't try to do so again - just display. */ 
+        if ($this->_split_level == 'words') {
+            $prefix = '';
+            while ($orig[0] !== false && $final[0] !== false &&
+                   substr($orig[0], 0, 1) == ' ' &&
+                   substr($final[0], 0, 1) == ' ') {
+                $prefix .= substr($orig[0], 0, 1);
+                $orig[0] = substr($orig[0], 1);
+                $final[0] = substr($final[0], 1);
+            }
+            $ret = $prefix . $this->_deleted($orig) . $this->_added($final) . "\n";
+            //echo 'DEBUG:<pre>'.htmlspecialchars($ret).'</pre>';
+            return $ret;
+        }
+
+        $text1 = implode("\n", $orig);
+        $text2 = implode("\n", $final);
+
+        /* Non-printing newline marker. */
+        $nl = "\0";
+
+        /* We want to split on word boundaries, but we need to
+         * preserve whitespace as well. Therefore we split on words,
+         * but include all blocks of whitespace in the wordlist. */
+        $diff = &new Text_Diff($this->_splitOnWords($text1, $nl),
+                               $this->_splitOnWords($text2, $nl));
+
+        /* Get the diff in inline format. */
+        $renderer = &new Text_Diff_Renderer_inline(array_merge($this->getParams(),
+                                                               array('split_level' => 'words')));
+
+        /* Run the diff and get the output. */
+        $ret = str_replace($nl, "<br />", $renderer->render($diff));
+        //echo 'DEBUG:<pre>'.htmlspecialchars($ret).'</pre>';
+        return $ret . "\n";
+    }
+
+    function _splitOnWords($string, $newlineEscape = "<br />")
+    {
+        $words = array();
+        $length = strlen($string);
+        $pos = 0;
+
+        while ($pos < $length) {
+            // Eat a word with any preceding whitespace.
+            $spaces = strspn(substr($string, $pos), " \n");
+            $nextpos = strcspn(substr($string, $pos + $spaces), " \n");
+            $words[] = str_replace("\n", $newlineEscape, substr($string, $pos, $spaces + $nextpos));
+            $pos += $spaces + $nextpos;
+        }
+
+        return $words;
+    }
+
+    function _encode(&$string)
+    {
+        $string = htmlspecialchars($string);
+    }
+    
+    /**
+     * Renders a diff.
+     *
+     * @param Text_Diff $diff  A Text_Diff object.
+     *
+     * @return string  The formatted output.
+     */
+    
+    function render($diff)
+    {
+        $xi = $yi = 1;
+        $block = false;
+        $context = array();
+
+        $nlead = $this->_leading_context_lines;
+        $ntrail = $this->_trailing_context_lines;
+
+        $output = $this->_startDiff();
+
+        $diffs = $diff->getDiff();
+        foreach ($diffs as $i => $edit) {
+            if (is_a($edit, 'Text_Diff_Op_copy')) {
+                if (is_array($block)) {
+                    $keep = $i == count($diffs) - 1 ? $ntrail : $nlead + $ntrail;
+                    if (count($edit->orig) <= $keep) {
+                        $block[] = $edit;
+                    } else {
+                        if ($ntrail) {
+                            $context = array_slice($edit->orig, 0, $ntrail);
+                            $block[] = &new Text_Diff_Op_copy($context);
+                        }
+                        $bk = $this->_block($x0, $ntrail + $xi - $x0,
+                                            $y0, $ntrail + $yi - $y0,
+                                            $block);
+                        $output .= $bk;
+                        $block = false;
+                    }
+                }
+                $context = $edit->orig;
+            } else {
+                if (!is_array($block)) {
+                    $context = array_slice($context, count($context) - $nlead);
+                    $x0 = $xi - count($context);
+                    $y0 = $yi - count($context);
+                    $block = array();
+                    if ($context) {
+                        $block[] = &new Text_Diff_Op_copy($context);
+                    }
+                }
+                $block[] = $edit;
+            }
+
+            if ($edit->orig) {
+                $xi += count($edit->orig);
+            }
+            if ($edit->final) {
+                $yi += count($edit->final);
+            }
+        }
+
+        if (is_array($block)) {
+            $bk = $this->_block($x0, $xi - $x0,
+                                $y0, $yi - $y0,
+                                $block);
+            $output .= $bk;
+        }
+
+        $final = $output . $this->_endDiff();
+        if ($final == '') $final = '<tr><td class="diff-block">No differences.</td></tr>';
+        //$final = preg_replace('#('.preg_quote($this->_ins_suffix).'|'.preg_quote($this->_del_suffix).')(.+?)('.preg_quote($this->_ins_prefix).'|'.preg_quote($this->_ins_suffix).')#', '\\1<tr><td></td><td class="diff-context>\\2</td></tr>\\3', $final);
+        return '<table class="diff">'.$final.'</table>'."\n\n";
+    }
+    
+    function _block($xbeg, $xlen, $ybeg, $ylen, &$edits)
+    {
+        $output = $this->_startBlock($this->_blockHeader($xbeg, $xlen, $ybeg, $ylen));
+
+        foreach ($edits as $edit) {
+            switch (strtolower(get_class($edit))) {
+            case 'text_diff_op_copy':
+                $output .= $this->_context($edit->orig);
+                break;
+
+            case 'text_diff_op_add':
+                $output .= $this->_added($edit->final);
+                break;
+
+            case 'text_diff_op_delete':
+                $output .= $this->_deleted($edit->orig);
+                break;
+
+            case 'text_diff_op_change':
+                $output .= $this->_changed($edit->orig, $edit->final);
+                break;
+            }
+        }
+
+        return $output . $this->_endBlock();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/email.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,622 @@
+<?php
+
+/*
+ * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
+ * Version 1.0 (Banshee)
+ * Copyright (C) 2006-2007 Dan Fuhry
+ *
+ * This program is Free Software; you can redistribute 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 details.
+ * 
+ * The "emailer" class was ported from phpBB 2.0. Copyright (C) 2002-2006 phpBB Group. phpBB is licensed under the GPLv2.
+ */
+ 
+//
+// The emailer class has support for attaching files, that isn't implemented
+// in the 2.0 release but we can probable find some way of using it in a future
+// release
+//
+class emailer
+{
+  var $msg, $subject, $extra_headers;
+  var $addresses, $reply_to, $from;
+  var $use_smtp;
+
+  var $tpl_msg;
+
+  function emailer($use_smtp)
+  {
+    $this->reset();
+    $this->use_smtp = $use_smtp;
+    $this->reply_to = $this->from = '';
+  }
+
+  // Resets all the data (address, template file, etc etc to default
+  function reset()
+  {
+    $this->addresses = array();
+    $this->vars = $this->msg = $this->extra_headers = '';
+  }
+
+  // Sets an email address to send to
+  function email_address($address)
+  {
+    $this->addresses['to'] = trim($address);
+  }
+
+  function cc($address)
+  {
+    $this->addresses['cc'][] = trim($address);
+  }
+
+  function bcc($address)
+  {
+    $this->addresses['bcc'][] = trim($address);
+  }
+
+  function replyto($address)
+  {
+    $this->reply_to = trim($address);
+  }
+
+  function from($address)
+  {
+    $this->from = trim($address);
+  }
+
+  // set up subject for mail
+  function set_subject($subject = '')
+  {
+    $this->subject = trim(preg_replace('#[\n\r]+#s', '', $subject));
+  }
+
+  // set up extra mail headers
+  function extra_headers($headers)
+  {
+    $this->extra_headers .= trim($headers) . "\n";
+  }
+
+  function use_template($template_code)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    $this->tpl_msg = $template->makeParserText($template_code);
+
+    return true;
+  }
+
+  // assign variables
+  function assign_vars($vars)
+  {
+    if ( is_object($this->tpl_msg) )
+    {
+      $this->tpl_msg->assign_vars($vars);
+    }
+    else
+    {
+      die_friendly(GENERAL_ERROR, 'Can\'t set vars, the template is not set');
+    }
+  }
+
+  // Send the mail out to the recipients set previously in var $this->address
+  function send()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    $this->msg = $this->tpl_msg->run();
+    if ( empty($this->msg) )
+    {
+      die_friendly(GENERAL_ERROR, 'Template for e-mail message returned a blank');
+    }
+
+    // We now try and pull a subject from the email body ... if it exists,
+    // do this here because the subject may contain a variable
+    $drop_header = '';
+    $match = array();
+    if (preg_match('#^(Subject:(.*?))$#m', $this->msg, $match))
+    {
+      $this->subject = (trim($match[2]) != '') ? trim($match[2]) : (($this->subject != '') ? $this->subject : 'No Subject');
+      $drop_header .= '[\r\n]*?' . preg_quote($match[1], '#');
+    }
+    else
+    {
+      $this->subject = (($this->subject != '') ? $this->subject : 'No Subject');
+    }
+
+    if (preg_match('#^(Charset:(.*?))$#m', $this->msg, $match))
+    {
+      $this->encoding = (trim($match[2]) != '') ? trim($match[2]) : trim('iso-8859-1');
+      $drop_header .= '[\r\n]*?' . preg_quote($match[1], '#');
+    }
+    else
+    {
+      $this->encoding = trim('iso-8859-1');
+    }
+
+    if ($drop_header != '')
+    {
+      $this->msg = trim(preg_replace('#' . $drop_header . '#s', '', $this->msg));
+    }
+
+    $to = $this->addresses['to'];
+
+    $cc = (count($this->addresses['cc'])) ? implode(', ', $this->addresses['cc']) : '';
+    $bcc = (count($this->addresses['bcc'])) ? implode(', ', $this->addresses['bcc']) : '';
+
+    // Build header
+    $this->extra_headers = (($this->reply_to != '') ? "Reply-to: $this->reply_to\n" : '') .
+                           (($this->from != '') ? "From: $this->from\n" : "From: " . getConfig('contact_email') . "\n") .
+                           "Return-Path: " . getConfig('contact_email') .
+                           "\nMessage-ID: <" . md5(uniqid(time())) . "@" . $_SERVER['SERVER_NAME'] . ">\nMIME-Version: 1.0\nContent-type: text/plain; charset=" . $this->encoding .
+                           "\nContent-transfer-encoding: 8bit\nDate: " . date('r', time()) .
+                           "\nX-Priority: 3\nX-MSMail-Priority: Normal\nX-Mailer: PHP\nX-MimeOLE: Produced By Enano CMS\n" .
+                           $this->extra_headers .
+                           (($cc != '') ? "Cc: $cc\n" : '')  .
+                           (($bcc != '') ? "Bcc: $bcc\n" : '');
+    
+    //die('<pre>'.print_r($this,true).'</pre>');
+
+    // Send message ... removed $this->encode() from subject for time being
+    if ( $this->use_smtp )
+    {
+      $result = smtp_send_email_core($to, $this->subject, $this->msg, $this->extra_headers);
+    }
+    else
+    {
+      $empty_to_header = ($to == '') ? TRUE : FALSE;
+      $to = ($to == '') ? ((getConfig('sendmail_fix')=='1') ? ' ' : 'Undisclosed-recipients:;') : $to;
+  
+      $result = @mail($to, $this->subject, preg_replace("#(?<!\r)\n#s", "\n", $this->msg), $this->extra_headers);
+      
+      if (!$result && !getConfig('sendmail_fix') && $empty_to_header)
+      {
+        $to = ' ';
+
+        setConfig('sendmail_fix', '1');
+        
+        $result = @mail($to, $this->subject, preg_replace("#(?<!\r)\n#s", "\n", $this->msg), $this->extra_headers);
+      }
+    }
+
+    // Did it work?
+    if (!$result || ( $this->use_smtp && $result != 'success' ))
+    {
+      die_friendly(GENERAL_ERROR, 'Failed sending email :: ' . (($this->use_smtp) ? 'SMTP' : 'PHP') . ' :: ' . $result);
+    }
+
+    return true;
+  }
+
+  // Encodes the given string for proper display for this encoding ... nabbed 
+  // from php.net and modified. There is an alternative encoding method which 
+  // may produce lesd output but it's questionable as to its worth in this 
+  // scenario IMO
+  function encode($str)
+  {
+    if ($this->encoding == '')
+    {
+      return $str;
+    }
+
+    // define start delimimter, end delimiter and spacer
+    $end = "?=";
+    $start = "=?$this->encoding?B?";
+    $spacer = "$end\r\n $start";
+
+    // determine length of encoded text within chunks and ensure length is even
+    $length = 75 - strlen($start) - strlen($end);
+    $length = floor($length / 2) * 2;
+
+    // encode the string and split it into chunks with spacers after each chunk
+    $str = chunk_split(base64_encode($str), $length, $spacer);
+
+    // remove trailing spacer and add start and end delimiters
+    $str = preg_replace('#' . preg_quote($spacer, '#') . '$#', '', $str);
+
+    return $start . $str . $end;
+  }
+
+  //
+  // Attach files via MIME.
+  //
+  function attachFile($filename, $mimetype = "application/octet-stream", $szFromAddress, $szFilenameToDisplay)
+  {
+    global $lang;
+    $mime_boundary = "--==================_846811060==_";
+
+    $this->msg = '--' . $mime_boundary . "\nContent-Type: text/plain;\n\tcharset=".'"' . $lang['ENCODING'] . '"'."\n\n" . $this->msg;
+
+    if ($mime_filename)
+    {
+      $filename = $mime_filename;
+      $encoded = $this->encode_file($filename);
+    }
+
+    $fd = fopen($filename, "r");
+    $contents = fread($fd, filesize($filename));
+
+    $this->mimeOut = "--" . $mime_boundary . "\n";
+    $this->mimeOut .= "Content-Type: " . $mimetype . ";\n\tname=".'"'."$szFilenameToDisplay".'"'."\n";
+    $this->mimeOut .= "Content-Transfer-Encoding: quoted-printable\n";
+    $this->mimeOut .= "Content-Disposition: attachment;\n\tfilename=".'"'."$szFilenameToDisplay".'"'."\n\n";
+
+    if ( $mimetype == "message/rfc822" )
+    {
+      $this->mimeOut .= "From: ".$szFromAddress."\n";
+      $this->mimeOut .= "To: ".$this->emailAddress."\n";
+      $this->mimeOut .= "Date: ".date("D, d M Y H:i:s") . " UT\n";
+      $this->mimeOut .= "Reply-To:".$szFromAddress."\n";
+      $this->mimeOut .= "Subject: ".$this->mailSubject."\n";
+      $this->mimeOut .= "X-Mailer: PHP/".phpversion()."\n";
+      $this->mimeOut .= "MIME-Version: 1.0\n";
+    }
+
+    $this->mimeOut .= $contents."\n";
+    $this->mimeOut .= "--" . $mime_boundary . "--" . "\n";
+
+    return $out;
+    // added -- to notify email client attachment is done
+  }
+
+  function getMimeHeaders($filename, $mime_filename="")
+  {
+    $mime_boundary = "--==================_846811060==_";
+
+    if ($mime_filename)
+    {
+      $filename = $mime_filename;
+    }
+
+    $out = "MIME-Version: 1.0\n";
+    $out .= "Content-Type: multipart/mixed;\n\tboundary=".'"'."$mime_boundary".'"'."\n\n";
+    $out .= "This message is in MIME format. Since your mail reader does not understand\n";
+    $out .= "this format, some or all of this message may not be legible.";
+
+    return $out;
+  }
+
+  //
+   // Split string by RFC 2045 semantics (76 chars per line, end with \r\n).
+  //
+  function myChunkSplit($str)
+  {
+    $stmp = $str;
+    $len = strlen($stmp);
+    $out = "";
+
+    while ($len > 0)
+    {
+      if ($len >= 76)
+      {
+        $out .= substr($stmp, 0, 76) . "\r\n";
+        $stmp = substr($stmp, 76);
+        $len = $len - 76;
+      }
+      else
+      {
+        $out .= $stmp . "\r\n";
+        $stmp = "";
+        $len = 0;
+      }
+    }
+    return $out;
+  }
+
+  //
+   // Split the specified file up into a string and return it
+  //
+  function encode_file($sourcefile)
+  {
+    if (is_readable(@realpath($sourcefile)))
+    {
+      $fd = fopen($sourcefile, "r");
+      $contents = fread($fd, filesize($sourcefile));
+        $encoded = $this->myChunkSplit(base64_encode($contents));
+        fclose($fd);
+    }
+
+    return $encoded;
+  }
+
+} // class emailer
+
+
+/**
+ * This code is copyright (C) 2004 Jim Tucek
+ * PHP version ported from Javascript by Dan Fuhry
+ * All rights reserved.
+ * @link http://www.jracademy.com/~jtucek/email/
+ * @license GNU General Public License v2, permission obtained specifically for Enano
+ */
+
+class EmailEncryptor
+{
+ 
+  var $primes = Array(2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199);
+  
+  function __construct()
+  {
+    $i = 0;
+    $this->p = 0;
+    $this->q = 0;
+    while($this->p * $this->q < 255 || $this->p == $this->q)
+    {
+      $this->p = $this->primes[mt_rand(0, sizeof($this->primes)-1)];
+      $this->q = $this->primes[mt_rand(0, sizeof($this->primes)-1)];
+    }
+  }
+  
+  function EmailEncryptor()
+  {
+    $this->__construct();
+  }
+  
+  function testAll() {
+    $size = sizeof($this->primes);
+    
+    $allCharacters = "";
+    for($c = 33; $c <= 126; $c++)
+      $allCharacters = $allCharacters . $this->fromCharCode($c);
+    
+    for($i = 0; $i < $size - 1; $i++) {
+      for($j = $i + 1; $j < $size; $j++) {
+        $this->p = $this->primes[$i];
+        $this->q = $this->primes[$j];
+        if($this->p*$this->q < 255)
+          break;
+        $k = $this->makeKey($allCharacters);
+        die('<pre>'.print_r($k, true).'</pre>');
+        $encrypted = $k['X'];
+        $decrypted = $this->goForth($encrypted,$this->p*$this->q,$k['D']);
+        if($decrypted != $allCharacters) {
+          die('Test failed');
+        }
+      }
+    }
+    return 'GOOD';
+  }
+  
+  function charCodeAt($str, $i)
+  {
+    return ord(substr($str, $i, 1));
+  }
+  
+  function fromCharCode($str)
+  {
+    return chr($str);
+  }
+  
+  function MakeArray($l) {
+    $a = Array();
+    $i=0;
+    do {
+      $a[$i]=null;
+      $i++;
+    } while($i < $l);
+    return $a;
+  }
+  
+  function makeKey($addr,$subj = '',$body = '') {
+    $value = "";
+    
+    if($this->p * $this->q < 255)
+    {
+      return("P*Q must be greater than 255! P*Q = " . $this->p*$this->q);
+    }
+    elseif($this->p == $this->q)
+    {
+      return("P cannot be equal to Q!");
+    }
+    elseif($addr == "")
+    {
+      return("You must enter an address to encrypt!");
+    }
+    else
+    {
+      // Make the key
+      $c = 0;
+      $z = ($this->p-1)*($this->q-1);
+      $e = 0;
+      $n = $this->p*$this->q;
+      $d = 0;
+    
+      do {
+        $e++;
+        $d = $this->getKey($this->primes[$e],$z);
+      } while($d==1);
+      $e = $this->primes[$e];
+      
+      // Turn the string into an array of numbers < 255
+      $m = $addr;
+      $emailLength = strlen($m);
+      $justEmail = "";
+      $sep = ( strstr('?', $m) ) ? '&' : '?';
+      if($subj != "") {
+        $m = $m . "{$sep}subject=" . $subj;
+      }
+      $sep = ( strstr($m, '?') ) ? '&' : '?';
+      if($body != "") {
+        $m = $m . "{$sep}body=" . $body;
+      }
+    
+      $length = strlen($m);
+      $theString = $this->MakeArray($length);
+      for($i = 0; $i < $length; $i++) {
+        $theString[$i] = $this->charCodeAt($m, $i);
+      }
+      
+      // Encrypt each of the numbers
+      $theCode = $this->MakeArray($length);
+      $c = "";
+      $temp = 0;
+      for($i = 0; $i < $length; $i++) {
+        if($i != 0)
+          $c .= " ";
+        $temp = $this->myMod($theString[$i],$e,$n);
+        $theCode[$i] = $temp;
+        $c .= $temp;
+        if($i == $emailLength - 1)
+          $justEmail = $c;
+      }
+    }
+    return Array('X'=>$justEmail, 'N'=>$n, 'D'=>$d, 'E'=>$e, 'C'=>$c, 'M'=>$m);
+  }
+    
+  // Finds x^e % y for large values of (x^e)
+  function myMod($x,$e,$y) {
+    if ($e % 2 == 0) {
+      $answer = 1;
+      for($i = 1; $i <= e/2; $i++) {
+        $temp = ($x*$x) % $y;
+        $answer = ($temp*$answer) % $y;
+      }
+    } else {
+      $answer = $x;
+      for($i = 1; $i <= $e/2; $i++) {
+        $temp = ($x*$x) % $y;
+        $answer = ($temp*$answer) % $y;
+      }
+    }
+    return $answer;
+  }
+  
+  
+  function getKey($e,$z) {
+    $A = 1;
+    $B = 0;
+    $C = $z;
+    $F = 0;
+    $G = 1;
+    $bar = $e;    
+    // Euclid's Algorithm:
+    while ($bar != 0) {
+      $foo = floor($C/$bar);
+      $K = $A - $foo * $F;
+      $L = $B - $foo * $G;
+      $M = $C - $foo * $bar;
+      $A = $F;
+      $B = $G;
+      $C = $bar;
+      $F = $K;
+      $G = $L;
+      $bar = $M;
+    }
+    if ($B < 0)
+    {
+      return ($B + $z);
+    }
+    else
+    {
+      return ($B);
+    }
+  }
+  
+  function goForth($c,$n,$d) {
+    $c .= " "; 
+    $length = strlen($c);
+    $number = 0;
+    $bar = 0;
+    $answer = "";
+  
+    for($i = 0; $i < $length; $i++) {
+      $number = 0;
+      $bar = 0;
+      while($this->charCodeAt($c, $i) != 32) { 
+        $number = $number * 10;
+        $number = $number + $this->charCodeAt($c, $i)-48;
+        $i++;
+      }
+      $answer .= $this->fromCharCode($this->decrypt($number,$n,$d));
+    }
+    return $answer;
+  }
+  
+  function decrypt($c,$n,$d) {
+    // Split exponents up
+    if ($d % 2== 0) {
+      $bar = 1;
+      for($i = 1; $i <= $d/2; $i++) {
+        $foo = ($c*$c) % $n;
+        $bar = ($foo*$bar) % $n;
+      }
+    } else {
+      $bar = $c;
+      for($i = 1; $i <= $d/2; $i++) {
+        $foo = ($c*$c) % $n;
+        $bar = ($foo*$bar) % $n;
+      }
+    }
+    return $bar;
+  }
+  
+  function writeOptions() {
+    $size = sizeof($this->primes);
+    for($i = 0; $i < $size; $i++)
+      echo("<option value=".'"'.""+$this->primes[$i]+"".'"'.">"+$this->primes[$i]+"</option>");
+  }
+  
+  function jscode() {
+    return "<script type='text/javascript'>\n// <![CDATA[\nfunction dive(absorption,alchemy,friendship) { absorption += ' '; var file = absorption.length; var sand = 0; var closet = ''; for(var assistant = 0; assistant < file; assistant++) { sand = 0; while(absorption.charCodeAt(assistant) != 32) { sand = sand * 10; sand = sand + absorption.charCodeAt(assistant)-48; assistant++; } closet += String.fromCharCode(say(sand,alchemy,friendship)); } parent.location = 'm'+'a'+'i'+'l'+'t'+'o'+':'+closet; }; function forbid(landing,atmosphere,aviation) { landing += ' '; var kiss = landing.length; var coordinated = 0; for(var day = 0; day < kiss; day++) { coordinated = 0; while(landing.charCodeAt(day) != 32) { coordinated = coordinated * 10; coordinated = coordinated + landing.charCodeAt(day)-48; day++; } document.write(String.fromCharCode(say(coordinated,atmosphere,aviation))); }; }; function say(scene,photograph,fraction) { if (fraction % 2 == 0) { integrity = 1; for(var male = 1; male <= fraction/2; male++) { moon = (scene*scene) % photograph; integrity = (moon*integrity) % photograph; } } else { integrity = scene; for(var night = 1; night <= fraction/2; night++) { moon = (scene*scene) % photograph; integrity = (moon*integrity) % photograph; }; }; return integrity; };\n// ]]>\n</script>";
+  }
+  
+  /**
+   * Wrapper - spits out ready-to-use HTML
+   * @param string $address The e-mail address
+   * @param string $subject The subject of the e-mail. OPTIONAL.
+   * @param string $body The main content of the e-mail. OPTIONAL and doesn't work in many e-mail clients.
+   * @param string $text The text to be shown on the e-mail link. Leave as false to make the e-mail address be shown in the link (but still fully encrypted)
+   */
+  
+  function encryptEmail($address, $subject = '', $body = '', $text = false)
+  {
+    $key = $this->makeKey($address, $subject, $body);
+    if ( $text )
+    {
+      if(preg_match('/^(mailto:)?(?:[\w\d]+\.?)+@(?:(?:[\w\d]\-?)+\.)+\w{2,4}$/', $text))
+      {
+        // This is a mailto link and normal obfuscation should be used
+        $text = false;
+      }
+    }
+    $text1 = ( $text ) ? '<script type="text/javascript">document.write(unescape(\''.rawurlencode($text).'\'));</script>' : '<script type=\'text/javascript\'>forbid("'.$key['X'].'",'.$key['N'].','.$key['D'].')</script>';
+    $text2 = ( $text ) ? "$text &lt;".$this->obfuscate_text($this->mask_address($address))."&gt;" : $this->obfuscate_text($this->mask_address($address));
+    $email = '<a href="#" onclick=\'dive("'.$key['C'].'",'.$key['N'].','.$key['D'].'); return false;\' onmouseover="self.status=\'\'; return true;" onmouseout="self.status=\' \'; return true;">'.$text1.'</a><noscript><div style="display: inline">'.$text2.'</div></noscript>';
+    return $email;
+  }
+  
+  /** 
+   * Replace @ symbols with " <AT> " and dots with " <DOT> ".
+   * @param string $email An e-mail address.
+   * @return string
+   */
+   
+  function mask_address($email)
+  {
+    return str_replace('.', ' <DOT> ', str_replace('@', ' <AT> ', $email));
+  }
+  
+  /**
+   * Turn a string of text into hex-encoded HTML entities
+   * @param string $text the text to encode
+   * @return string
+   */
+
+  function obfuscate_text($text)
+  {
+    $a = enano_str_split($text, 1);
+    $s = '';
+    foreach($a as $k => $c)
+    {
+      $ch = (string)dechex(ord($a[$k]));
+      if(strlen($ch) < 2) $ch = '0' . $ch;
+      $s .= '&#x'.$ch.';';
+    }
+    return $s;
+  }
+
+}
+
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/functions.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1903 @@
+<?php
+
+/*
+ * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
+ * Version 1.0 (Banshee)
+ * Copyright (C) 2006-2007 Dan Fuhry
+ *
+ * This program is Free Software; you can redistribute 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 details.
+ */
+ 
+function getConfig($n) {
+  global $enano_config;
+  if(isset($enano_config[$n])) return $enano_config[$n];
+  else                         return false;
+}
+
+function setConfig($n, $v) {
+  global $enano_config, $db;
+  $enano_config[$n] = $v;
+  $v = $db->escape($v);
+  $e=$db->sql_query('DELETE FROM '.table_prefix.'config WHERE config_name=\''.$n.'\';');
+  if(!$e) $db->_die('Error during generic setConfig() call row deletion.');
+  $e=$db->sql_query('INSERT INTO '.table_prefix.'config(config_name, config_value) VALUES(\''.$n.'\', \''.$v.'\')');
+  if(!$e) $db->_die('Error during generic setConfig() call row insertion.');
+}
+
+function makeUrl($t, $query = false, $escape = false)
+{
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  $flags = '';
+  $sep = urlSeparator;
+  if(isset($_GET['printable'])) { $flags .= $sep.'printable'; $sep = '&'; }
+  if(isset($_GET['theme'])) { $flags .= $sep.'theme='.$session->theme; $sep = '&'; }
+  if(isset($_GET['style'])) { $flags .= $sep.'style='.$session->style; $sep = '&'; }
+  $url = $session->append_sid(contentPath.$t.$flags);
+  if($query)
+  {
+    $sep = strstr($url, '?') ? '&' : '?';
+    $url = $url . $sep . $query;
+  }
+  return ($escape) ? htmlspecialchars($url) : $url;
+}
+
+function makeUrlNS($n, $t, $query = false, $escape = false)
+{
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  $flags = '';
+  if(defined('ENANO_BASE_CLASSES_INITIALIZED')) $sep = urlSeparator;
+  else $sep = (strstr($_SERVER['REQUEST_URI'], '?')) ? '&' : '?';
+  if(isset($_GET['printable'])) { $flags .= $sep.'printable';              $sep = '&'; }
+  if(isset($_GET['theme']))     { $flags .= $sep.'theme='.$session->theme; $sep = '&'; }
+  if(isset($_GET['style']))     { $flags .= $sep.'style='.$session->style; $sep = '&'; }
+  
+  if(defined('ENANO_BASE_CLASSES_INITIALIZED'))
+  {
+    $url = contentPath.$paths->nslist[$n].$t.$flags;
+  }
+  else
+  {
+    $url = contentPath.$n.':'.$t.$flags;
+  }
+  
+  if($query)
+  {
+    if(strstr($url, '?')) $sep =  '&';
+    else $sep = '?';
+    $url = $url . $sep . $query . $flags;
+  }
+  
+  if(defined('ENANO_BASE_CLASSES_INITIALIZED'))
+  {
+    $url = $session->append_sid($url);
+  }
+  
+  return ($escape) ? htmlspecialchars($url) : $url;
+}
+
+function makeUrlComplete($n, $t, $query = false, $escape = false)
+{
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  $flags = '';
+  if(defined('ENANO_BASE_CLASSES_INITIALIZED')) $sep = urlSeparator;
+  else $sep = (strstr($_SERVER['REQUEST_URI'], '?')) ? '&' : '?';
+  if(isset($_GET['printable'])) { $flags .= $sep.'printable';              $sep = '&'; }
+  if(isset($_GET['theme']))     { $flags .= $sep.'theme='.$session->theme; $sep = '&'; }
+  if(isset($_GET['style']))     { $flags .= $sep.'style='.$session->style; $sep = '&'; }
+  if(defined('ENANO_BASE_CLASSES_INITIALIZED')) $url = $session->append_sid(contentPath.$paths->nslist[$n].$t.$flags);
+  else $url = contentPath.$n.':'.$t.$flags;
+  if($query)
+  {
+    if(strstr($url, '?')) $sep =  '&';
+    else $sep = '?';
+    $url = $url . $sep . $query . $flags;
+  }
+  $baseprot = 'http' . ( isset($_SERVER['HTTPS']) ? 's' : '' ) . '://' . $_SERVER['HTTP_HOST'];
+  $url = $baseprot . $url;
+  return ($escape) ? htmlspecialchars($url) : $url;
+}
+
+/**
+ * Redirect the user to the specified URL.
+ * @param string $url The URL, either relative or absolute.
+ * @param string $title The title of the message
+ * @param string $message A short message to show to the user
+ * @param string $timeout Timeout, in seconds, to delay the redirect. Defaults to 3.
+ */
+ 
+function redirect($url, $title = 'Redirecting...', $message = 'Please wait while you are redirected.', $timeout = 3)
+{
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  
+  if ( $timeout == 0 )
+  {
+    header('Location: ' . $url);
+    header('HTTP/1.1 307 Temporary Redirect');
+  }
+  
+  $template->add_header('<meta http-equiv="refresh" content="' . $timeout . '; url=' . str_replace('"', '\\"', $url) . '" />');
+  $template->add_header('<script type="text/javascript">
+      function __r() {
+        // FUNCTION AUTOMATICALLY GENERATED
+        window.location="' . str_replace('"', '\\"', $url) . '";
+      }
+      setTimeout(\'__r();\', ' . $timeout . '000);
+    </script>
+    ');
+  
+  $template->tpl_strings['PAGE_NAME'] = $title;
+  $template->header(true);
+  echo '<p>' . $message . '</p><p>If you are not redirected within ' . ( $timeout + 1 ) . ' seconds, <a href="' . str_replace('"', '\\"', $url) . '">please click here</a>.</p>';
+  $template->footer(true);
+  
+  $db->close();
+  exit(0);
+  
+}
+
+// Removed wikiFormat() from here, replaced with RenderMan::render
+
+function isPage($p) {
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  if(isset($paths->pages[$p])) return true;
+  $d = RenderMan::strToPageID($p);
+  if($d[1] != 'Special' && $d[1] != 'Template' && $d[1] != 'Admin') return false;
+  $a = explode('/', $p);
+  if(isset($paths->pages[$a[0]])) return true;
+  else return false;
+}
+
+function arrayItemUp($arr, $keyname) {
+  $keylist = array_keys($arr);
+  $keyflop = array_flip($keylist);
+  $idx = $keyflop[$keyname];
+  $idxm = $idx - 1;
+  $temp = $arr[$keylist[$idxm]];
+  if($arr[$keylist[0]] == $arr[$keyname]) return $arr;
+  $arr[$keylist[$idxm]] = $arr[$keylist[$idx]];
+  $arr[$keylist[$idx]] = $temp;
+  return $arr;
+}
+
+function arrayItemDown($arr, $keyname) {
+  $keylist = array_keys($arr);
+  $keyflop = array_flip($keylist);
+  $idx = $keyflop[$keyname];
+  $idxm = $idx + 1;
+  $temp = $arr[$keylist[$idxm]];
+  $sz = sizeof($arr); $sz--;
+  if($arr[$keylist[$sz]] == $arr[$keyname]) return $arr;
+  $arr[$keylist[$idxm]]  =  $arr[$keylist[$idx]];
+  $arr[$keylist[$idx]]   =  $temp;
+  return $arr;
+}
+
+function arrayItemTop($arr, $keyname) {
+  $keylist = array_keys($arr);
+  $keyflop = array_flip($keylist);
+  $idx = $keyflop[$keyname];
+  while( $orig != $arr[$keylist[0]] ) {
+    // echo 'Keyname: '.$keylist[$idx] . '<br />'; flush(); ob_flush(); // Debugger
+    if($idx < 0) return $arr;
+    if($keylist[$idx] == '' || $keylist[$idx] < 0 || !$keylist[$idx]) {
+      /* echo 'Infinite loop caught in arrayItemTop(<br /><pre>';
+      print_r($arr);
+      echo '</pre><br />, '.$keyname.');<br /><br />EnanoCMS: Critical error during function call, exiting to prevent excessive server load.';
+      exit; */
+      return $arr;
+    }
+    $arr = arrayItemUp($arr, $keylist[$idx]);
+    $idx--;
+  }
+  return $arr;
+}
+
+function arrayItemBottom($arr, $keyname) {
+  $keylist = array_keys($arr);
+  $keyflop = array_flip($keylist);
+  $idx = $keyflop[$keyname];
+  $sz = sizeof($arr); $sz--;
+  while( $orig != $arr[$keylist[$sz]] ) {
+    // echo 'Keyname: '.$keylist[$idx] . '<br />'; flush(); ob_flush(); // Debugger
+    if($idx > $sz) return $arr;
+    if($keylist[$idx] == '' || $keylist[$idx] < 0 || !$keylist[$idx]) {
+      echo 'Infinite loop caught in arrayItemBottom(<br /><pre>';
+      print_r($arr);
+      echo '</pre><br />, '.$keyname.');<br /><br />EnanoCMS: Critical error during function call, exiting to prevent excessive server load.';
+      exit;
+    }
+    $arr = arrayItemDown($arr, $keylist[$idx]);
+    $idx++;
+  }
+  return $arr;
+}
+
+// Convert IP address to hex string
+// Input:  127.0.0.1  (string)
+// Output: 0x7f000001 (string)
+// Updated 12/8/06 to work with PHP4 and not use eval() (blech)
+function ip2hex($ip) {
+  if ( preg_match('/^([0-9a-f:]+)$/', $ip) )
+  {
+    // this is an ipv6 address
+    return str_replace(':', '', $ip);
+  }
+  $nums = explode('.', $ip);
+  if(sizeof($nums) != 4) return false;
+  $str = '0x';
+  foreach($nums as $n)
+  {
+    $str .= (string)dechex($n);
+  }
+  return $str;
+}
+
+// Convert DWord to IP address
+// Input:  0x7f000001
+// Output: 127.0.0.1
+// Updated 12/8/06 to work with PHP4 and not use eval() (blech)
+function hex2ip($in) {
+  if(substr($in, 0, 2) == '0x') $ip = substr($in, 2, 8);
+  else $ip = substr($in, 0, 8);
+  $octets = enano_str_split($ip, 2);
+  $str = '';
+  $newoct = Array();
+  foreach($octets as $o)
+  {
+    $o = (int)hexdec($o);
+    $newoct[] = $o;
+  }
+  return implode('.', $newoct);
+}
+
+// Function strip_php moved to RenderMan class
+
+function die_semicritical($t, $p)
+{
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  $db->close();
+  
+  if ( ob_get_status() )
+    ob_end_clean();
+  
+  dc_here('functions: <span style="color: red">calling die_semicritical</span>');
+  
+  $tpl = new template_nodb();
+  $tpl->load_theme('oxygen', 'bleu');
+  $tpl->tpl_strings['SITE_NAME'] = getConfig('site_name');
+  $tpl->tpl_strings['SITE_DESC'] = getConfig('site_desc');
+  $tpl->tpl_strings['COPYRIGHT'] = getConfig('copyright_notice');
+  $tpl->tpl_strings['PAGE_NAME'] = $t;
+  $tpl->header();
+  echo $p;
+  $tpl->footer();
+  
+  exit;
+}
+
+function die_friendly($t, $p)
+{
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  
+  if ( ob_get_status() )
+    ob_end_clean();
+  
+  dc_here('functions: <span style="color: red">calling die_friendly</span>');
+  $paths->cpage['name'] = $t;
+  $template->tpl_strings['PAGE_NAME'] = $t;
+  $template->header();
+  echo $p;
+  $template->footer();
+  $db->close();
+  
+  exit;
+}
+
+function grinding_halt($t, $p)
+{
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  
+  $db->close();
+  
+  if ( ob_get_status() )
+    ob_end_clean();
+  
+  dc_here('functions: <span style="color: red">calling grinding_halt</span>');
+  $tpl = new template_nodb();
+  $tpl->load_theme('oxygen', 'bleu');
+  $tpl->tpl_strings['SITE_NAME'] = 'Critical error';
+  $tpl->tpl_strings['SITE_DESC'] = 'This website is experiencing a serious error and cannot load.';
+  $tpl->tpl_strings['COPYRIGHT'] = 'Unable to retrieve copyright information';
+  $tpl->tpl_strings['PAGE_NAME'] = $t;
+  $tpl->header();
+  echo $p;
+  $tpl->footer();
+  exit;
+}
+
+function show_category_info() {
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  dc_here('functions: showing category info');
+  if($template->no_headers && !strpos($_SERVER['REQUEST_URI'], 'ajax.php')) return '';
+  if($paths->namespace=='Category')
+  {
+    $q = $db->sql_query('SELECT page_id,namespace FROM '.table_prefix.'categories WHERE category_id=\''.$paths->cpage['urlname_nons'].'\' AND namespace=\'Category\' ORDER BY page_id;');
+    if(!$q) $db->_die('The category information could not be selected.');
+    $ticker = -1;
+    echo '<h3>Subcategories</h3>';
+    if($db->numrows() < 1) echo '<p>There are no subcategories in this category.</p>';
+    echo '<table border="0" cellspacing="1" cellpadding="4">';
+    while($row = $db->fetchrow())
+    {
+      $ticker++;if($ticker==3) $ticker=0;
+      if($ticker==0) echo '<tr>';
+      echo '<td style="width: 200px;"><a href="'.makeUrlNS($row['namespace'], $row['page_id']).'">'.$paths->pages[$paths->nslist[$row['namespace']].$row['page_id']]['name'].'</a></td>';
+      if($ticker==2) echo '</tr>';
+    }
+    $db->free_result();
+    if($ticker) echo '</tr>';
+    echo '</table>';
+    
+    $q = $db->sql_query('SELECT page_id,namespace FROM '.table_prefix.'categories WHERE category_id=\''.$paths->cpage['urlname_nons'].'\' AND namespace!=\'Category\' ORDER BY page_id;');
+    if(!$q) $db->_die('The category information could not be selected.');
+    $ticker = -1;
+    echo '<h3>Pages</h3>';
+    if($db->numrows() < 1) echo '<p>There are no pages in this category.</p>';
+    echo '<table border="0" cellspacing="1" cellpadding="4">';
+    while($row = $db->fetchrow())
+    {
+      $ticker++;if($ticker==3) $ticker=0;
+      if($ticker==0) echo '<tr>';
+      echo '<td style="width: 200px;"><a href="'.makeUrlNS($row['namespace'], $row['page_id']).'">'.$paths->pages[$paths->nslist[$row['namespace']].$row['page_id']]['name'].'</a></td>';
+      if($ticker==2) echo '</tr>';
+    }
+    $db->free_result();
+    if($ticker) echo '</tr>';
+    echo '</table><br /><br />';
+  }
+  $q = $db->sql_query('SELECT category_id FROM '.table_prefix.'categories WHERE page_id=\''.$paths->cpage['urlname_nons'].'\' AND namespace=\''.$paths->namespace.'\'');
+  if(!$q) $db->_die('The error seems to have occurred during selection of category data.');
+  if($db->numrows() > 0) {
+    echo '<div class="mdg-comment" style="margin-left: 0;">Categories: ';
+    $i=0;
+    while($r = $db->fetchrow())
+    {
+      if($i>0) echo ', ';
+      $i++;
+      echo '<a href="'.makeUrlNS('Category', $r['category_id']).'">'.$paths->pages[$paths->nslist['Category'].$r['category_id']]['name'].'</a>';
+    }
+    if( ( $paths->wiki_mode && !$paths->page_protected ) || ( $session->get_permissions('edit_cat') && $session->get_permissions('even_when_protected') ) ) echo ' [ <a href="'.makeUrl($paths->page, 'do=catedit', true).'" onclick="ajaxCatEdit(); return false;">edit categorization</a> ]</div>';
+  } else {
+    echo '<div class="mdg-comment" style="margin-left: 0;">Categories: ';
+    echo '(Uncategorized)';
+    if( ( $paths->wiki_mode && !$paths->page_protected ) || ( $session->get_permissions('edit_cat') && $session->get_permissions('even_when_protected') ) ) echo ' [ <a href="'.makeUrl($paths->page, 'do=catedit', true).'" onclick="ajaxCatEdit(); return false;">edit categorization</a> ]</div>';
+    else echo '</div>';
+  }
+  $db->free_result();
+}
+
+function show_file_info()
+{
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  if($paths->namespace != 'File') return null; // Prevent unnecessary work
+  $selfn = $paths->cpage['urlname_nons']; // substr($paths->page, strlen($paths->nslist['File']), strlen($paths->cpage));
+  if(substr($paths->cpage['name'], 0, strlen($paths->nslist['File']))==$paths->nslist['File']) $selfn = substr($paths->cpage['urlname_nons'], strlen($paths->nslist['File']), strlen($paths->cpage['urlname_nons']));
+  $q = $db->sql_query('SELECT mimetype,time_id,size FROM '.table_prefix.'files WHERE page_id=\''.$selfn.'\' ORDER BY time_id DESC;');
+  if(!$q) $db->_die('The file type could not be fetched.');
+  if($db->numrows() < 1) { echo '<div class="mdg-comment" style="margin-left: 0;"><h3>Uploaded file</h3><p>There are no files uploaded with this name yet. <a href="'.makeUrlNS('Special', 'UploadFile/'.$paths->cpage['urlname_nons']).'">Upload a file...</a></p></div><br />'; return; }
+  $r = $db->fetchrow();
+  $mimetype = $r['mimetype'];
+  $datestring = date('F d, Y h:i a', (int)$r['time_id']);
+  echo '<div class="mdg-comment" style="margin-left: 0;"><p><h3>Uploaded file</h3></p><p>Type: '.$r['mimetype'].'<br />Size: ';
+  $fs = $r['size'];
+  echo $fs.' bytes';
+  $fs = (int)$fs;
+  if($fs >= 1048576)
+  {
+    $fs = round($fs / 1048576, 1);
+    echo ' ('.$fs.' MB)';
+  } elseif($fs >= 1024) {
+    $fs = round($fs / 1024, 1);
+    echo ' ('.$fs.' KB)';
+  }
+  echo '<br />Uploaded: '.$datestring.'</p>';
+  if(substr($mimetype, 0, 6)!='image/' && ( substr($mimetype, 0, 5) != 'text/' || $mimetype == 'text/html' || $mimetype == 'text/javascript' ))
+  {
+    echo '<div class="warning-box">This file type may contain viruses or other code that could harm your computer. You should exercise caution if you download it.</div>';
+  }
+  if(substr($mimetype, 0, 6)=='image/')
+  {
+    echo '<p><a href="'.makeUrlNS('Special', 'DownloadFile'.'/'.$selfn).'"><img style="border: 0;" alt="'.$paths->page.'" src="'.makeUrlNS('Special', 'DownloadFile'.'/'.$selfn.htmlspecialchars(urlSeparator).'preview').'" /></a></p>';
+  }
+  echo '<p><a href="'.makeUrlNS('Special', 'DownloadFile'.'/'.$selfn.'/'.$r['time_id'].htmlspecialchars(urlSeparator).'download').'">Download this file</a>';
+  if(!$paths->page_protected && ( $paths->wiki_mode || $session->get_permissions('upload_new_version') ))
+  {
+    echo '  |  <a href="'.makeUrlNS('Special', 'UploadFile'.'/'.$selfn).'">Upload new version</a>';
+  }
+  echo '</p>';
+  if($db->numrows() > 1)
+  {
+    echo '<h3>File history</h3><p>';
+    while($r = $db->fetchrow())
+    {
+      echo '(<a href="'.makeUrlNS('Special', 'DownloadFile'.'/'.$selfn.'/'.$r['time_id'].htmlspecialchars(urlSeparator).'download').'">this ver</a>) ';
+      if($session->get_permissions('history_rollback'))
+        echo ' (<a href="#" onclick="ajaxRollback(\''.$r['time_id'].'\'); return false;">revert</a>) ';
+      $mimetype = $r['mimetype'];
+      $datestring = date('F d, Y h:i a', (int)$r['time_id']);
+      echo $datestring.': '.$r['mimetype'].', ';
+      $fs = $r['size'];
+      $fs = (int)$fs;
+      if($fs >= 1048576)
+      {
+        $fs = round($fs / 1048576, 1);
+        echo ' '.$fs.' MB';
+      } elseif($fs >= 1024) {
+        $fs = round($fs / 1024, 1);
+        echo ' '.$fs.' KB';
+      } else {
+        echo ' '.$fs.' bytes';
+      }
+      echo '<br />';
+    }
+    echo '</p>';
+  }
+  $db->free_result();
+  echo '</div><br />';
+}
+
+function display_page_headers()
+{
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  if($session->get_permissions('vote_reset') && $paths->cpage['delvotes'] > 0)
+  {
+    $hr = implode(', ', explode('|', $paths->cpage['delvote_ips']));
+    $is = 'is';
+    $s = '';
+    $s2 = 's';
+    if ( $paths->cpage['delvotes'] > 1)
+    {
+      $is = 'are';
+      $s = 's';
+      $s2 = '';
+    }
+    echo '<div class="info-box" style="margin-left: 0; margin-top: 5px;" id="mdgDeleteVoteNoticeBox">
+            <b>Notice:</b> There '.$is.' '.$paths->cpage['delvotes'].' user'.$s.' that think'.$s2.' this page should be deleted.<br />
+            <b>Users that voted:</b> ' . $hr . '<br />
+            <a href="'.makeUrl($paths->page, 'do=deletepage').'" onclick="ajaxDeletePage(); return false;">Delete page</a>  |  <a href="'.makeUrl($paths->page, 'do=resetvotes').'" onclick="ajaxResetDelVotes(); return false;">Reset votes</a>
+          </div>';
+  }
+}
+
+function display_page_footers()
+{
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  if(isset($_GET['nofooters'])) return;
+  $code = $plugins->setHook('send_page_footers');
+  foreach ( $code as $cmd )
+  {
+    eval($cmd);
+  }
+  show_file_info();
+  show_category_info();
+}
+
+function password_prompt($id = false)
+{
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  if(!$id) $id = $paths->page;
+  if(isset($paths->pages[$id]['password']) && strlen($paths->pages[$id]['password']) == 40 && !isset($_REQUEST['pagepass']))
+  {
+    die_friendly('Password required', '<p>You must supply a password to access this page.</p><form action="'.makeUrl($paths->pages[$id]['urlname']).'" method="post"><p>Password: <input name="pagepass" type="password" /></p><p><input type="submit" value="Submit" /></p>');
+  } elseif(isset($_REQUEST['pagepass'])) {
+    $p = (preg_match('#^([a-f0-9]*){40}$#', $_REQUEST['pagepass'])) ? $_REQUEST['pagepass'] : sha1($_REQUEST['pagepass']);
+    if($p != $paths->pages[$id]['password']) die_friendly('Password required', '<p style="color: red;">The password you entered is incorrect.</p><form action="'.makeUrl($paths->page).'" method="post"><p>Password: <input name="pagepass" type="password" /></p><p><input type="submit" value="Submit" /></p>');
+  }
+}
+
+function str_hex($string){
+    $hex='';
+    for ($i=0; $i < strlen($string); $i++){
+        $hex .= ' '.dechex(ord($string[$i]));
+    }
+    return substr($hex, 1, strlen($hex));
+}
+
+// Function pulled from phpBB's smtp.php
+function smtp_get_response($socket, $response, $line = __LINE__) 
+{
+	$server_response = '';
+	while (substr($server_response, 3, 1) != ' ') 
+	{
+		if (!($server_response = fgets($socket, 256))) 
+		{
+      die_friendly('SMTP Error', "<p>Couldn't get mail server response codes</p>");
+		}
+	} 
+
+	if (!(substr($server_response, 0, 3) == $response)) 
+	{ 
+    die_friendly('SMTP Error', "<p>Ran into problems sending mail. Response: $server_response</p>");
+	} 
+}
+
+function smtp_send_email($to, $subject, $message, $from)
+{
+  return smtp_send_email_core($to, $subject, $message, "From: <$from>\n");
+}
+
+// Replacement or substitute for PHP's mail command
+// Ported from phpBB - copyright (C) phpBB group, GPL.
+function smtp_send_email_core($mail_to, $subject, $message, $headers = '')
+{
+	global $board_config;
+
+	// Fix any bare linefeeds in the message to make it RFC821 Compliant.
+	$message = preg_replace("#(?<!\r)\n#si", "\r\n", $message);
+
+	if ($headers != '')
+	{
+		if (is_array($headers))
+		{
+			if (sizeof($headers) > 1)
+			{
+				$headers = join("\n", $headers);
+			}
+			else
+			{
+				$headers = $headers[0];
+			}
+		}
+		$headers = chop($headers);
+
+		// Make sure there are no bare linefeeds in the headers
+		$headers = preg_replace('#(?<!\r)\n#si', "\r\n", $headers);
+
+		// Ok this is rather confusing all things considered,
+		// but we have to grab bcc and cc headers and treat them differently
+		// Something we really didn't take into consideration originally
+		$header_array = explode("\r\n", $headers);
+		@reset($header_array);
+
+		$headers = '';
+		while(list(, $header) = each($header_array))
+		{
+			if (preg_match('#^cc:#si', $header))
+			{
+				$cc = preg_replace('#^cc:(.*)#si', '\1', $header);
+			}
+			else if (preg_match('#^bcc:#si', $header))
+			{
+				$bcc = preg_replace('#^bcc:(.*)#si', '\1', $header);
+				$header = '';
+			}
+			$headers .= ($header != '') ? $header . "\r\n" : '';
+		}
+
+		$headers = chop($headers);
+		$cc = explode(', ', $cc);
+		$bcc = explode(', ', $bcc);
+	}
+
+	if (trim($subject) == '')
+	{
+		die_friendly(GENERAL_ERROR, "No email Subject specified");
+	}
+
+	if (trim($message) == '')
+	{
+		die_friendly(GENERAL_ERROR, "Email message was blank");
+	}
+  
+  // setup SMTP
+  $host = getConfig('smtp_server');
+  if ( empty($host) )
+    return 'No smtp_host in config';
+  if ( strstr($host, ':' ) )
+  {
+    $n = explode(':', $host);
+    $smtp_host = $n[0];
+    $port = intval($n[1]);
+  }
+  else
+  {
+    $smtp_host = $host;
+    $port = 25;
+  }
+  
+  $smtp_user = getConfig('smtp_user');
+  $smtp_pass = getConfig('smtp_password');
+  
+	// Ok we have error checked as much as we can to this point let's get on
+	// it already.
+	if( !$socket = @fsockopen($smtp_host, $port, $errno, $errstr, 20) )
+	{
+		die_friendly(GENERAL_ERROR, "Could not connect to smtp host : $errno : $errstr");
+	}
+
+	// Wait for reply
+	smtp_get_response($socket, "220", __LINE__);
+
+	// Do we want to use AUTH?, send RFC2554 EHLO, else send RFC821 HELO
+	// This improved as provided by SirSir to accomodate
+	if( !empty($smtp_user) && !empty($smtp_pass) )
+	{ 
+		enano_fputs($socket, "EHLO " . $smtp_host . "\r\n");
+		smtp_get_response($socket, "250", __LINE__);
+
+		enano_fputs($socket, "AUTH LOGIN\r\n");
+		smtp_get_response($socket, "334", __LINE__);
+
+		enano_fputs($socket, base64_encode($smtp_user) . "\r\n");
+		smtp_get_response($socket, "334", __LINE__);
+
+		enano_fputs($socket, base64_encode($smtp_pass) . "\r\n");
+		smtp_get_response($socket, "235", __LINE__);
+	}
+	else
+	{
+		enano_fputs($socket, "HELO " . $smtp_host . "\r\n");
+		smtp_get_response($socket, "250", __LINE__);
+	}
+
+	// From this point onward most server response codes should be 250
+	// Specify who the mail is from....
+	enano_fputs($socket, "MAIL FROM: <" . getConfig('contact_email') . ">\r\n");
+	smtp_get_response($socket, "250", __LINE__);
+
+	// Specify each user to send to and build to header.
+	$to_header = '';
+
+	// Add an additional bit of error checking to the To field.
+	$mail_to = (trim($mail_to) == '') ? 'Undisclosed-recipients:;' : trim($mail_to);
+	if (preg_match('#[^ ]+\@[^ ]+#', $mail_to))
+	{
+		enano_fputs($socket, "RCPT TO: <$mail_to>\r\n");
+		smtp_get_response($socket, "250", __LINE__);
+	}
+
+	// Ok now do the CC and BCC fields...
+	@reset($bcc);
+	while(list(, $bcc_address) = each($bcc))
+	{
+		// Add an additional bit of error checking to bcc header...
+		$bcc_address = trim($bcc_address);
+		if (preg_match('#[^ ]+\@[^ ]+#', $bcc_address))
+		{
+			enano_fputs($socket, "RCPT TO: <$bcc_address>\r\n");
+			smtp_get_response($socket, "250", __LINE__);
+		}
+	}
+
+	@reset($cc);
+	while(list(, $cc_address) = each($cc))
+	{
+		// Add an additional bit of error checking to cc header
+		$cc_address = trim($cc_address);
+		if (preg_match('#[^ ]+\@[^ ]+#', $cc_address))
+		{
+			enano_fputs($socket, "RCPT TO: <$cc_address>\r\n");
+			smtp_get_response($socket, "250", __LINE__);
+		}
+	}
+
+	// Ok now we tell the server we are ready to start sending data
+	enano_fputs($socket, "DATA\r\n");
+
+	// This is the last response code we look for until the end of the message.
+	smtp_get_response($socket, "354", __LINE__);
+
+	// Send the Subject Line...
+	enano_fputs($socket, "Subject: $subject\r\n");
+
+	// Now the To Header.
+	enano_fputs($socket, "To: $mail_to\r\n");
+
+	// Now any custom headers....
+	enano_fputs($socket, "$headers\r\n\r\n");
+
+	// Ok now we are ready for the message...
+	enano_fputs($socket, "$message\r\n");
+
+	// Ok the all the ingredients are mixed in let's cook this puppy...
+	enano_fputs($socket, ".\r\n");
+	smtp_get_response($socket, "250", __LINE__);
+
+	// Now tell the server we are done and close the socket...
+	enano_fputs($socket, "QUIT\r\n");
+	fclose($socket);
+
+	return TRUE;
+}
+
+/**
+ * Tell which version of Enano we're running.
+ * @param bool $long if true, uses English version names (e.g. alpha, beta, release candidate). If false (default) uses abbreviations (1.0a1, 1.0b3, 1.0RC2, etc.)
+ * @return string
+ */
+
+function enano_version($long = false, $no_nightly = false)
+{
+  $r = getConfig('enano_version');
+  $rc = ( $long ) ? ' release candidate ' : 'RC';
+  $b = ( $long ) ? ' beta ' : 'b';
+  $a = ( $long ) ? ' alpha ' : 'a';
+  if($v = getConfig('enano_rc_version')) $r .= $rc.$v;
+  if($v = getConfig('enano_beta_version')) $r .= $b.$v;
+  if($v = getConfig('enano_alpha_version')) $r .= $a.$v;
+  if ( defined('ENANO_NIGHTLY') && !$no_nightly )
+  {
+    $nightlytag  = ENANO_NIGHTLY_MONTH . '-' . ENANO_NIGHTLY_DAY . '-' . ENANO_NIGHTLY_YEAR;
+    $nightlylong = ' nightly; build date: ' . ENANO_NIGHTLY_MONTH . '-' . ENANO_NIGHTLY_DAY . '-' . ENANO_NIGHTLY_YEAR;
+    $r = ( $long ) ? $r . $nightlylong : $r . '-nightly-' . $nightlytag;
+  }
+  return $r;
+}
+
+function _dualurlenc($t) {
+  return rawurlencode(rawurlencode($t));
+}
+  
+function _die($t) {
+  $_ob = 'document.getElementById("ajaxEditContainer").innerHTML = unescape(\'' . rawurlencode('' . $t . '') . '\')';
+  die($_ob);
+}
+
+function jsdie($text) {
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  $text = rawurlencode($text . "\n\nSQL Backtrace:\n" . $db->sql_backtrace());
+  echo 'document.getElementById("ajaxEditContainer").innerHTML = unescape(\''.$text.'\');';
+}
+
+// HTML sanitizing function - written by Kallahar
+// Original function at: http://quickwired.com/kallahar/smallprojects/php_xss_filter_function.php
+
+// UNUSED - todo: remove this in gold or put it to use
+
+function RemoveXSS($val) {
+  // remove all non-printable characters. CR(0a) and LF(0b) and TAB(9) are allowed
+  // this prevents some character re-spacing such as <java\0script>
+  // note that you have to handle splits with \n, \r, and \t later since they *are* allowed in some inputs
+  $val = preg_replace('/([\x00-\x08][\x0b-\x0c][\x0e-\x20])/', '', $val);
+  
+  // straight replacements, the user should never need these since they're normal characters
+  // this prevents like <IMG SRC=&#X40&#X61&#X76&#X61&#X73&#X63&#X72&#X69&#X70&#X74&#X3A&#X61&#X6C&#X65&#X72&#X74&#X28&#X27&#X58&#X53&#X53&#X27&#X29>
+  $search  = 'abcdefghijklmnopqrstuvwxyz';
+  $search .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
+  $search .= '1234567890!@#$%^&*()';
+  $search .= '~`";:?+/={}[]-_|\'\\';
+  for ($i = 0; $i < strlen($search); $i++) {
+    // ;? matches the ;, which is optional
+    // 0{0,7} matches any padded zeros, which are optional and go up to 8 chars
+  
+    // &#x0040 @ search for the hex values
+    $val = preg_replace('/(&#[x|X]0{0,8}'.dechex(ord($search[$i])).';?)/i', $search[$i], $val); // with a ;
+    // &#00064 @ 0{0,7} matches '0' zero to seven times
+    $val = preg_replace('/(&#0{0,8}'.ord($search[$i]).';?)/', $search[$i], $val); // with a ;
+  }
+  
+  // now the only remaining whitespace attacks are \t, \n, and \r
+  $ra1 = Array('javascript', 'vbscript', 'expression', 'applet', 'meta', 'xml', 'blink', 'link', 'script', 'embed', 'object', 'iframe', 'frame', 'frameset', 'ilayer', 'layer', 'bgsound', 'title', 'base');
+  $ra2 = Array('onabort', 'onactivate', 'onafterprint', 'onafterupdate', 'onbeforeactivate', 'onbeforecopy', 'onbeforecut', 'onbeforedeactivate', 'onbeforeeditfocus', 'onbeforepaste', 'onbeforeprint', 'onbeforeunload', 'onbeforeupdate', 'onblur', 'onbounce', 'oncellchange', 'onchange', 'onclick', 'oncontextmenu', 'oncontrolselect', 'oncopy', 'oncut', 'ondataavailable', 'ondatasetchanged', 'ondatasetcomplete', 'ondblclick', 'ondeactivate', 'ondrag', 'ondragend', 'ondragenter', 'ondragleave', 'ondragover', 'ondragstart', 'ondrop', 'onerror', 'onerrorupdate', 'onfilterchange', 'onfinish', 'onfocus', 'onfocusin', 'onfocusout', 'onhelp', 'onkeydown', 'onkeypress', 'onkeyup', 'onlayoutcomplete', 'onload', 'onlosecapture', 'onmousedown', 'onmouseenter', 'onmouseleave', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onmousewheel', 'onmove', 'onmoveend', 'onmovestart', 'onpaste', 'onpropertychange', 'onreadystatechange', 'onreset', 'onresize', 'onresizeend', 'onresizestart', 'onrowenter', 'onrowexit', 'onrowsdelete', 'onrowsinserted', 'onscroll', 'onselect', 'onselectionchange', 'onselectstart', 'onstart', 'onstop', 'onsubmit', 'onunload');
+  $ra = array_merge($ra1, $ra2);
+  
+  $found = true; // keep replacing as long as the previous round replaced something
+  while ($found == true) {
+    $val_before = $val;
+    for ($i = 0; $i < sizeof($ra); $i++) {
+      $pattern = '/';
+      for ($j = 0; $j < strlen($ra[$i]); $j++) {
+        if ($j > 0) {
+          $pattern .= '(';
+          $pattern .= '(&#[x|X]0{0,8}([9][a][b]);?)?';
+          $pattern .= '|(&#0{0,8}([9][10][13]);?)?';
+          $pattern .= ')?';
+        }
+        $pattern .= $ra[$i][$j];
+      }
+      $pattern .= '/i';
+      $replacement = substr($ra[$i], 0, 2).'<b></b>'.substr($ra[$i], 2); // add in <> to nerf the tag
+      $val = preg_replace($pattern, $replacement, $val); // filter out the hex tags
+      if ($val_before == $val) {
+        // no replacements were made, so exit the loop
+        $found = false;
+      }
+    }
+  }
+  return $val;
+}
+
+/**
+ * Capitalizes the first letter of a string
+ * @param $text string the text to be transformed
+ * @return string
+ */
+ 
+function capitalize_first_letter($text)
+{
+  return strtoupper(substr($text, 0, 1)) . substr($text, 1);
+}
+
+/**
+ * Checks if a value in a bitfield is on or off
+ * @param $bitfield int the bit-field value
+ * @param $value int the value to switch off
+ * @return bool
+ */
+ 
+function is_bit($bitfield, $value)
+{
+  return ( $bitfield & $value ) ? true : false;
+}
+
+/**
+ * Trims spaces/newlines from the beginning and end of a string
+ * @param $text the text to process
+ * @return string
+ */
+ 
+function trim_spaces($text)
+{
+  $d = true;
+  while($d)
+  {
+    $c = substr($text, 0, 1);
+    $a = substr($text, strlen($text)-1, strlen($text));
+    if($c == "\n" || $c == "\r" || $c == "\t" || $c == ' ') $text = substr($text, 1, strlen($text));
+    elseif($a == "\n" || $a == "\r" || $a == "\t" || $a == ' ') $text = substr($text, 0, strlen($text)-1);
+    else $d = false;
+  }
+  return $text;
+}
+
+/**
+ * Enano-ese equivalent of str_split() which is only found in PHP5
+ * @param $text string the text to split
+ * @param $inc int size of each block
+ * @return array
+ */
+ 
+function enano_str_split($text, $inc = 1)
+{
+  if($inc < 1) return false;
+  if($inc >= strlen($text)) return Array($text);
+  $len = ceil(strlen($text) / $inc);
+  $ret = Array();
+  for($i=0;$i<strlen($text);$i=$i+$inc)
+  {
+    $ret[] = substr($text, $i, $inc);
+  }
+  return $ret;
+}
+
+/**
+ * Converts a hexadecimal number to a binary string.
+ * @param text string hexadecimal number
+ * @return string
+ */
+function hex2bin($text)
+{
+  $arr = enano_str_split($text, 2);
+  $ret = '';
+  for ($i=0; $i<sizeof($arr); $i++)
+  {
+    $ret .= chr(hexdec($arr[$i]));
+  }
+  return $ret;
+}
+
+/**
+ * Generates and/or prints a human-readable backtrace
+ * @param bool $return - if true, this function returns a string, otherwise returns null
+ * @return mixed
+ */
+ 
+function enano_debug_print_backtrace($return = false)
+{
+  ob_start();
+  echo '<pre>';
+  debug_print_backtrace();
+  echo '</pre>';
+  $c = ob_get_contents();
+  ob_end_clean();
+  if($return) return $c;
+  else echo $c;
+  return null;
+}
+
+/**
+ * Like rawurlencode(), but encodes all characters
+ * @param string $text the text to encode
+ * @param optional string $prefix text before each hex character
+ * @param optional string $suffix text after each hex character
+ * @return string
+ */
+ 
+function hexencode($text, $prefix = '%', $suffix = '')
+{
+  $arr = enano_str_split($text);
+  $r = '';
+  foreach($arr as $a)
+  {
+    $nibble = (string)dechex(ord($a));
+    if(strlen($nibble) == 1) $nibble = '0' . $nibble;
+    $r .= $prefix . $nibble . $suffix;
+  }
+  return $r;
+}
+
+/**
+ * Enano-ese equivalent of get_magic_quotes_gpc()
+ * @return bool
+ */
+ 
+function enano_get_magic_quotes_gpc()
+{
+  if(function_exists('get_magic_quotes_gpc'))
+  {
+    return ( get_magic_quotes_gpc() == 1 );
+  }
+  else
+  {
+    return ( strtolower(@ini_get('magic_quotes_gpc')) == '1' );
+  }
+}
+
+/**
+ * Recursive stripslashes()
+ * @param array
+ * @return array
+ */
+ 
+function stripslashes_recurse($arr)
+{
+  foreach($arr as $k => $xxxx)
+  {
+    $val =& $arr[$k];
+    if(is_string($val))
+      $val = stripslashes($val);
+    elseif(is_array($val))
+      $val = stripslashes_recurse($val);
+  }
+  return $arr;
+}
+
+/**
+ * If magic_quotes_gpc is on, calls stripslashes() on everything in $_GET/$_POST/$_COOKIE
+ * @ignore - this doesn't work
+ * @todo port version from the PHP manual
+ * @return void
+ */
+function strip_magic_quotes_gpc()
+{
+  if(enano_get_magic_quotes_gpc())
+  {
+    $_POST   = stripslashes_recurse($_POST);
+    $_GET    = stripslashes_recurse($_GET);
+    $_COOKIE = stripslashes_recurse($_COOKIE);
+  }
+}
+
+/**
+ * A very basic single-character compression algorithm for binary strings/bitfields
+ * @param string $bits the text to compress
+ * @return string
+ */
+ 
+function compress_bitfield($bits)
+{
+  $crc32 = crc32($bits);
+  $bits .= '0';
+  $start_pos = 0;
+  $current = substr($bits, 1, 1);
+  $last    = substr($bits, 0, 1);
+  $chunk_size = 1;
+  $len = strlen($bits);
+  $crc = $len;
+  $crcval = 0;
+  for ( $i = 1; $i < $len; $i++ )
+  {
+    $current = substr($bits, $i, 1);
+    $last    = substr($bits, $i - 1, 1);
+    $next    = substr($bits, $i + 1, 1);
+    // Are we on the last character?
+    if($current == $last && $i+1 < $len)
+      $chunk_size++;
+    else
+    {
+      if($i+1 == $len && $current == $next)
+      {
+        // This character completes a chunk
+        $chunk_size++;
+        $i++;
+        $chunk = substr($bits, $start_pos, $chunk_size);
+        $chunklen = strlen($chunk);
+        $newchunk = $last . '[' . $chunklen . ']';
+        $newlen   = strlen($newchunk);
+        $bits = substr($bits, 0, $start_pos) . $newchunk . substr($bits, $i, $len);
+        $chunk_size = 1;
+        $i = $start_pos + $newlen;
+        $start_pos = $i;
+        $len = strlen($bits);
+        $crcval = $crcval + $chunklen;
+      }
+      else
+      {
+        // Last character completed a chunk
+        $chunk = substr($bits, $start_pos, $chunk_size);
+        $chunklen = strlen($chunk);
+        $newchunk = $last . '[' . $chunklen . '],';
+        $newlen   = strlen($newchunk);
+        $bits = substr($bits, 0, $start_pos) . $newchunk . substr($bits, $i, $len);
+        $chunk_size = 1;
+        $i = $start_pos + $newlen;
+        $start_pos = $i;
+        $len = strlen($bits);
+        $crcval = $crcval + $chunklen;
+      }
+    }
+  }
+  if($crc != $crcval)
+  {
+    echo __FUNCTION__.'(): ERROR: length check failed, this is a bug in the algorithm<br />Debug info: aiming for a CRC val of '.$crc.', got '.$crcval;
+    return false;
+  }
+  $compressed = 'cbf:len='.$crc.';crc='.dechex($crc32).';data='.$bits.'|end';
+  return $compressed;
+}
+
+/**
+ * Uncompresses a bitfield compressed with compress_bitfield()
+ * @param string $bits the compressed bitfield
+ * @return string the uncompressed, original (we hope) bitfield OR bool false on error
+ */
+ 
+function uncompress_bitfield($bits)
+{
+  if(substr($bits, 0, 4) != 'cbf:')
+  {
+    echo __FUNCTION__.'(): ERROR: Invalid stream';
+    return false;
+  }
+  $len = intval(substr($bits, strpos($bits, 'len=')+4, strpos($bits, ';')-strpos($bits, 'len=')-4));
+  $crc = substr($bits, strpos($bits, 'crc=')+4, 8);
+  $data = substr($bits, strpos($bits, 'data=')+5, strpos($bits, '|end')-strpos($bits, 'data=')-5);
+  $data = explode(',', $data);
+  foreach($data as $a => $b)
+  {
+    $d =& $data[$a];
+    $char = substr($d, 0, 1);
+    $dlen = intval(substr($d, 2, strlen($d)-1));
+    $s = '';
+    for($i=0;$i<$dlen;$i++,$s.=$char);
+    $d = $s;
+    unset($s, $dlen, $char);
+  }
+  $decompressed = implode('', $data);
+  $decompressed = substr($decompressed, 0, -1);
+  $dcrc = (string)dechex(crc32($decompressed));
+  if($dcrc != $crc)
+  {
+    echo __FUNCTION__.'(): ERROR: CRC check failed<br />debug info:<br />original crc: '.$crc.'<br />decomp\'ed crc: '.$dcrc.'<br />';
+    return false;
+  }
+  return $decompressed;
+}
+
+/**
+ * Exports a MySQL table into a SQL string.
+ * @param string $table The name of the table to export
+ * @param bool $structure If true, include a CREATE TABLE command
+ * @param bool $data If true, include the contents of the table
+ * @param bool $compact If true, omits newlines between parts of SQL statements, use in Enano database exporter
+ * @return string
+ */
+
+function export_table($table, $structure = true, $data = true, $compact = false)
+{
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  $struct_keys = '';
+  $divider   = (!$compact) ? "\n" : "\n";
+  $spacer1   = (!$compact) ? "\n" : " ";
+  $spacer2   = (!$compact) ? "  " : " ";
+  $rowspacer = (!$compact) ? "\n  " : " ";
+  $index_list = Array();
+  $cols = $db->sql_query('SHOW COLUMNS IN '.$table.';');
+  if(!$cols)
+  {
+    echo 'export_table(): Error getting column list: '.$db->get_error_text().'<br />';
+    return false;
+  }
+  $col = Array();
+  $sqlcol = Array();
+  $collist = Array();
+  $pri_keys = Array();
+  // Using fetchrow_num() here to compensate for MySQL l10n
+  while( $row = $db->fetchrow_num() )
+  {
+    $field =& $row[0];
+    $type  =& $row[1];
+    $null  =& $row[2];
+    $key   =& $row[3];
+    $def   =& $row[4];
+    $extra =& $row[5];
+    $col[] = Array(
+      'name'=>$field,
+      'type'=>$type,
+      'null'=>$null,
+      'key'=>$key,
+      'default'=>$def,
+      'extra'=>$extra,
+      );
+    $collist[] = $field;
+  }
+  
+  if ( $structure )
+  {
+    $db->sql_query('SET SQL_QUOTE_SHOW_CREATE = 0;');
+    $struct = $db->sql_query('SHOW CREATE TABLE '.$table.';');
+    if ( !$struct )
+      $db->_die();
+    $row = $db->fetchrow_num();
+    $db->free_result();
+    $struct = $row[1];
+    $struct = preg_replace("/\n\) ENGINE=(.+)$/", "\n);", $struct);
+    unset($row);
+    if ( $compact )
+    {
+      $struct_arr = explode("\n", $struct);
+      foreach ( $struct_arr as $i => $leg )
+      {
+        if ( $i == 0 )
+          continue;
+        $test = trim($leg);
+        if ( empty($test) )
+        {
+          unset($struct_arr[$i]);
+          continue;
+        }
+        $struct_arr[$i] = preg_replace('/^([\s]*)/', ' ', $leg);
+      }
+      $struct = implode("", $struct_arr);
+    }
+  }
+  
+  // Structuring complete
+  if($data)
+  {
+    $datq = $db->sql_query('SELECT * FROM '.$table.';');
+    if(!$datq)
+    {
+      echo 'export_table(): Error getting column list: '.$db->get_error_text().'<br />';
+      return false;
+    }
+    if($db->numrows() < 1)
+    {
+      if($structure) return $struct;
+      else return '';
+    }
+    $rowdata = Array();
+    $dataqs = Array();
+    $insert_strings = Array();
+    $z = false;
+    while($row = $db->fetchrow_num())
+    {
+      $z = false;
+      foreach($row as $i => $cell)
+      {
+        $str = mysql_encode_column($cell, $col[$i]['type']);
+        $rowdata[] = $str;
+      }
+      $dataqs2 = implode(",$rowspacer", $dataqs) . ",$rowspacer" . '( ' . implode(', ', $rowdata) . ' )';
+      $ins = 'INSERT INTO '.$table.'( '.implode(',', $collist).' ) VALUES' . $dataqs2 . ";";
+      if ( strlen( $ins ) > MYSQL_MAX_PACKET_SIZE )
+      {
+        // We've exceeded the maximum allowed packet size for MySQL - separate this into a different query
+        $insert_strings[] = 'INSERT INTO '.$table.'( '.implode(',', $collist).' ) VALUES' . implode(",$rowspacer", $dataqs) . ";";;
+        $dataqs = Array('( ' . implode(', ', $rowdata) . ' )');
+        $z = true;
+      }
+      else
+      {
+        $dataqs[] = '( ' . implode(', ', $rowdata) . ' )';
+      }
+      $rowdata = Array();
+    }
+    if ( !$z )
+    {
+      $insert_strings[] = 'INSERT INTO '.$table.'( '.implode(',', $collist).' ) VALUES' . implode(",$rowspacer", $dataqs) . ";";;
+      $dataqs = Array();
+    }
+    $datstring = implode($divider, $insert_strings);
+  }
+  if($structure && !$data) return $struct;
+  elseif(!$structure && $data) return $datstring;
+  elseif($structure && $data) return $struct . $divider . $datstring;
+  elseif(!$structure && !$data) return '';
+}
+
+/**
+ * Encodes a string value for use in an INSERT statement for given column type $type.
+ * @access private
+ */
+ 
+function mysql_encode_column($input, $type)
+{
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  // Decide whether to quote the string or not
+  if(substr($type, 0, 7) == 'varchar' || $type == 'datetime' || $type == 'text' || $type == 'tinytext' || $type == 'smalltext' || $type == 'longtext' || substr($type, 0, 4) == 'char')
+  {
+    $str = "'" . $db->escape($input) . "'";
+  }
+  elseif(in_array($type, Array('blob', 'longblob', 'mediumblob', 'smallblob')) || substr($type, 0, 6) == 'binary' || substr($type, 0, 9) == 'varbinary')
+  {
+    $str = '0x' . hexencode($input, '', '');
+  }
+  elseif(is_null($input))
+  {
+    $str = 'NULL';
+  }
+  else
+  {
+    $str = (string)$input;
+  }
+  return $str;
+}
+
+/**
+ * Creates an associative array defining which file extensions are allowed and which ones aren't
+ * @return array keyname will be a file extension, value will be true or false
+ */
+
+function fetch_allowed_extensions()
+{
+  global $mime_types;
+  $bits = getConfig('allowed_mime_types');
+  if(!$bits) return Array(false);
+  $bits = uncompress_bitfield($bits);
+  if(!$bits) return Array(false);
+  $bits = enano_str_split($bits, 1);
+  $ret = Array();
+  $mt = array_keys($mime_types);
+  foreach($bits as $i => $b)
+  {
+    $ret[$mt[$i]] = ( $b == '1' ) ? true : false;
+  }
+  return $ret;
+}
+
+/**
+ * Generates a random key suitable for encryption
+ * @param int $len the length of the key
+ * @return string a BINARY key
+ */
+
+function randkey($len = 32)
+{
+  $key = '';
+  for($i=0;$i<$len;$i++)
+  {
+    $key .= chr(mt_rand(0, 255));
+  }
+  return $key;
+}
+
+/**
+ * Decodes a hex string.
+ * @param string $hex The hex code to decode
+ * @return string
+ */
+
+function hexdecode($hex)
+{
+  $hex = enano_str_split($hex, 2);
+  $bin_key = '';
+  foreach($hex as $nibble)
+  {
+    $byte = chr(hexdec($nibble));
+    $bin_key .= $byte;
+  }
+  return $bin_key;
+}
+
+/**
+ * Enano's own (almost) bulletproof HTML sanitizer.
+ * @param string $html The input HTML
+ * @return string cleaned HTML
+ */
+
+function sanitize_html($html, $filter_php = true)
+{
+  
+  $html = preg_replace('#<([a-z]+)([\s]+)([^>]+?)'.htmlalternatives('javascript:').'(.+?)>(.*?)</\\1>#is', '&lt;\\1\\2\\3javascript:\\59&gt;\\60&lt;/\\1&gt;', $html);
+  $html = preg_replace('#<([a-z]+)([\s]+)([^>]+?)'.htmlalternatives('javascript:').'(.+?)>#is', '&lt;\\1\\2\\3javascript:\\59&gt;', $html);
+  
+  if($filter_php)
+    $html = str_replace(
+      Array('<?php',    '<?',    '<%',    '?>',    '%>'),
+      Array('&lt;?php', '&lt;?', '&lt;%', '?&gt;', '%&gt;'),
+      $html);
+  
+  $tag_whitelist = array_keys ( setupAttributeWhitelist() );
+  if ( !$filter_php )
+    $tag_whitelist[] = '?php';
+  $len = strlen($html);
+  $in_quote = false;
+  $quote_char = '';
+  $tag_start = 0;
+  $tag_name = '';
+  $in_tag = false;
+  $trk_name = false;
+  for ( $i = 0; $i < $len; $i++ )
+  {
+    $chr = $html{$i};
+    $prev = ( $i == 0 ) ? '' : $html{ $i - 1 };
+    $next = ( ( $i + 1 ) == $len ) ? '' : $html { $i + 1 };
+    if ( $in_quote && $in_tag )
+    {
+      if ( $quote_char == $chr && $prev != '\\' )
+        $in_quote = false;
+    }
+    elseif ( ( $chr == '"' || $chr == "'" ) && $prev != '\\' && $in_tag )
+    {
+      $in_quote = true;
+      $quote_char = $chr;
+    }
+    if ( $chr == '<' && !$in_tag && $next != '/' )
+    {                                          
+      // start of a tag
+      $tag_start = $i;
+      $in_tag = true;
+      $trk_name = true;
+    }
+    elseif ( !$in_quote && $in_tag && $chr == '>' )
+    {
+      $full_tag = substr($html, $tag_start, ( $i - $tag_start ) + 1 );
+      $l = strlen($tag_name) + 2;
+      $attribs_only = trim( substr($full_tag, $l, ( strlen($full_tag) - $l - 1 ) ) );
+      
+      // Debugging message
+      // echo htmlspecialchars($full_tag) . '<br />';
+      
+      if ( !in_array($tag_name, $tag_whitelist) )
+      {
+        // Illegal tag
+        //echo $tag_name . ' ';
+        
+        $s = ( empty($attribs_only) ) ? '' : ' ';
+        
+        $sanitized = '&lt;' . $tag_name . $s . $attribs_only . '&gt;';
+        
+        $html = substr($html, 0, $tag_start) . $sanitized . substr($html, $i + 1);
+        $html = str_replace('</' . $tag_name . '>', '&lt;/' . $tag_name . '&gt;', $html);
+        $new_i = $tag_start + strlen($sanitized);
+        
+        $len = strlen($html);
+        $i = $new_i;
+        
+        $in_tag = false;
+        $tag_name = '';
+        continue;
+      }
+      else
+      {
+        if ( $tag_name == '?php' && !$filter_php )
+          continue;
+        $f = fixTagAttributes( $attribs_only, $tag_name );
+        $s = ( empty($f) ) ? '' : ' ';
+        
+        $sanitized = '<' . $tag_name . $f . '>';
+        $new_i = $tag_start + strlen($sanitized);
+        
+        $html = substr($html, 0, $tag_start) . $sanitized . substr($html, $i + 1);
+        $len = strlen($html);
+        $i = $new_i;
+        
+        $in_tag = false;
+        $tag_name = '';
+        continue;
+      }
+    }
+    elseif ( $in_tag && $trk_name )
+    {
+      $is_alphabetical = ( strtolower($chr) != strtoupper($chr) || in_array($chr, array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9')) || $chr == '?' );
+      if ( $is_alphabetical )
+        $tag_name .= $chr;
+      else
+      {
+        $trk_name = false;
+      }
+    }
+    
+  }
+  
+  return $html;
+  
+}
+
+function htmlalternatives($string)
+{
+  $ret = '';
+  for ( $i = 0; $i < strlen($string); $i++ )
+  {
+    $chr = $string{$i};
+    $ch1 = ord($chr);
+    $ch2 = dechex($ch1);
+    $byte = '(&\\#([0]*){0,7}' . $ch1 . ';|\\\\([0]*){0,7}' . $ch1 . ';|\\\\([0]*){0,7}' . $ch2 . ';|&\\#x([0]*){0,7}' . $ch2 . ';|%([0]*){0,7}' . $ch2 . '|' . preg_quote($chr) . ')';
+    $ret .= $byte;
+    $ret .= '([\s]){0,2}';
+  }
+  return $ret;
+}
+
+/**
+ * Paginates (breaks into multiple pages) a MySQL result resource, which is treated as unbuffered.
+ * @param resource The MySQL result resource. This should preferably be an unbuffered query.
+ * @param string A template, with variables being named after the column name
+ * @param int The number of total results. This should be determined by a second query.
+ * @param string sprintf-style formatting string for URLs for result pages. First parameter will be start offset.
+ * @param int Optional. Start offset in individual results. Defaults to 0.
+ * @param int Optional. The number of results per page. Defualts to 10.
+ * @param int Optional. An associative array of functions to call, with key names being column names, and values being function names. Values can also be an array with key 0 being either an object or a string(class name) and key 1 being a [static] method.
+ * @param string Optional. The text to be sent before the result list, only if there are any results. Possibly the start of a table.
+ * @param string Optional. The text to be sent after the result list, only if there are any results. Possibly the end of a table.
+ * @return string
+ */
+
+function paginate($q, $tpl_text, $num_results, $result_url, $start = 0, $perpage = 10, $callers = Array(), $header = '', $footer = '')
+{
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  $parser = $template->makeParserText($tpl_text);
+  $num_pages = ceil ( $num_results / $perpage );
+  $out = '';
+  $i = 0;
+  $this_page = ceil ( $start / $perpage );
+  
+  // Build paginator
+  $begin = '<div class="tblholder" style="display: table; margin: 10px 0 0 auto;">
+    <table border="0" cellspacing="1" cellpadding="4">
+      <tr><th>Page:</th>';
+  $block = '<td class="row1" style="text-align: center;">{LINK}</td>';
+  $end = '</tr></table></div>';
+  $blk = $template->makeParserText($block);
+  $inner = '';
+  $cls = 'row2';
+  if ( $num_pages < 5 )
+  {
+    for ( $i = 0; $i < $num_pages; $i++ )
+    {
+      $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
+      $offset = strval($i * $perpage);
+      $url = sprintf($result_url, $offset);
+      $j = $i + 1;
+      $link = ( $offset == strval($start) ) ? "<b>$j</b>" : "<a href=".'"'."$url".'"'." style='text-decoration: none;'>$j</a>";
+      $blk->assign_vars(array(
+        'CLASS'=>$cls,
+        'LINK'=>$link
+        ));
+      $inner .= $blk->run();
+    }
+  }
+  else
+  {
+    if ( $this_page + 5 > $num_pages )
+    {
+      $list = Array();
+      $tp = $this_page;
+      if ( $this_page + 0 == $num_pages ) $tp = $tp - 3;
+      if ( $this_page + 1 == $num_pages ) $tp = $tp - 2;
+      if ( $this_page + 2 == $num_pages ) $tp = $tp - 1;
+      for ( $i = $tp - 1; $i <= $tp + 1; $i++ )
+      {
+        $list[] = $i;
+      }
+    }
+    else
+    {
+      $list = Array();
+      $current = $this_page;
+      $lower = ( $current < 3 ) ? 1 : $current - 1;
+      for ( $i = 0; $i < 3; $i++ )
+      {
+        $list[] = $lower + $i;
+      }
+    }
+    $url = sprintf($result_url, '0');
+    $link = ( 0 == $start ) ? "<b>First</b>" : "<a href=".'"'."$url".'"'." style='text-decoration: none;'>&laquo; First</a>";
+    $blk->assign_vars(array(
+      'CLASS'=>$cls,
+      'LINK'=>$link
+      ));
+    $inner .= $blk->run();
+    
+    // if ( !in_array(1, $list) )
+    // {
+    //   $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
+    //   $blk->assign_vars(array('CLASS'=>$cls,'LINK'=>'...'));
+    //   $inner .= $blk->run();
+    // }
+    
+    foreach ( $list as $i )
+    {
+      if ( $i == $num_pages )
+        break;
+      $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
+      $offset = strval($i * $perpage);
+      $url = sprintf($result_url, $offset);
+      $j = $i + 1;
+      $link = ( $offset == strval($start) ) ? "<b>$j</b>" : "<a href=".'"'."$url".'"'." style='text-decoration: none;'>$j</a>";
+      $blk->assign_vars(array(
+        'CLASS'=>$cls,
+        'LINK'=>$link
+        ));
+      $inner .= $blk->run();
+    }
+    
+    $total = $num_pages * $perpage - $perpage;
+    
+    if ( $this_page < $num_pages )
+    {
+      // $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
+      // $blk->assign_vars(array('CLASS'=>$cls,'LINK'=>'...'));
+      // $inner .= $blk->run();
+    
+      $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
+      $offset = strval($total);
+      $url = sprintf($result_url, $offset);
+      $j = $i + 1;
+      $link = ( $offset == strval($start) ) ? "<b>Last</b>" : "<a href=".'"'."$url".'"'." style='text-decoration: none;'>Last &raquo;</a>";
+      $blk->assign_vars(array(
+        'CLASS'=>$cls,
+        'LINK'=>$link
+        ));
+      $inner .= $blk->run();
+    }
+    
+  }
+  
+  $inner .= '<td class="row2" style="cursor: pointer;" onclick="paginator_goto(this, '.$this_page.', '.$num_pages.', '.$perpage.', unescape(\'' . rawurlencode($result_url) . '\'));">&darr;</td>';
+  
+  $paginator = "\n$begin$inner$end\n";
+  $out .= $paginator;
+  
+  $cls = 'row2';
+  
+  if ( $row = $db->fetchrow($q) )
+  {
+    $i = 0;
+    $out .= $header;
+    do {
+      $i++;
+      if ( $i <= $start )
+      {
+        continue;
+      }
+      if ( ( $i - $start ) > $perpage )
+      {
+        break;
+      }
+      $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
+      foreach ( $row as $j => $val )
+      {
+        if ( isset($callers[$j]) )
+        {
+          $tmp = ( is_callable($callers[$j]) ) ? @call_user_func($callers[$j], $val, $row) : $v;
+          
+          if ( $tmp )
+          {
+            $row[$j] = $tmp;
+          }
+        }
+      }
+      $parser->assign_vars($row);
+      $parser->assign_vars(array('_css_class' => $cls));
+      $out .= $parser->run();
+    } while ( $row = $db->fetchrow($q) );
+    $out .= $footer;
+  }
+  
+  $out .= $paginator;
+  
+  return $out;
+}
+
+/**
+ * This is the same as paginate(), but it processes an array instead of a MySQL result resource.
+ * @param array The results. Each value is simply echoed.
+ * @param int The number of total results. This should be determined by a second query.
+ * @param string sprintf-style formatting string for URLs for result pages. First parameter will be start offset.
+ * @param int Optional. Start offset in individual results. Defaults to 0.
+ * @param int Optional. The number of results per page. Defualts to 10.
+ * @param string Optional. The text to be sent before the result list, only if there are any results. Possibly the start of a table.
+ * @param string Optional. The text to be sent after the result list, only if there are any results. Possibly the end of a table.
+ * @return string
+ */
+
+function paginate_array($q, $num_results, $result_url, $start = 0, $perpage = 10, $header = '', $footer = '')
+{
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  $parser = $template->makeParserText($tpl_text);
+  $num_pages = ceil ( $num_results / $perpage );
+  $out = '';
+  $i = 0;
+  $this_page = ceil ( $start / $perpage );
+  
+  // Build paginator
+  $begin = '<div class="tblholder" style="display: table; margin: 10px 0 0 auto;">
+    <table border="0" cellspacing="1" cellpadding="4">
+      <tr><th>Page:</th>';
+  $block = '<td class="row1" style="text-align: center;">{LINK}</td>';
+  $end = '</tr></table></div>';
+  $blk = $template->makeParserText($block);
+  $inner = '';
+  $cls = 'row2';
+  if ( $start > 0 )
+  {
+    $url = sprintf($result_url, abs($start - $perpage));
+    $link = "<a href=".'"'."$url".'"'." style='text-decoration: none;'>&laquo; Prev</a>";
+    $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
+    $blk->assign_vars(array(
+      'CLASS'=>$cls,
+      'LINK'=>$link
+      ));
+    $inner .= $blk->run();
+  }
+  if ( $num_pages < 5 )
+  {
+    for ( $i = 0; $i < $num_pages; $i++ )
+    {
+      $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
+      $offset = strval($i * $perpage);
+      $url = sprintf($result_url, $offset);
+      $j = $i + 1;
+      $link = ( $offset == strval($start) ) ? "<b>$j</b>" : "<a href=".'"'."$url".'"'." style='text-decoration: none;'>$j</a>";
+      $blk->assign_vars(array(
+        'CLASS'=>$cls,
+        'LINK'=>$link
+        ));
+      $inner .= $blk->run();
+    }
+  }
+  else
+  {
+    if ( $this_page + 5 > $num_pages )
+    {
+      $list = Array();
+      $tp = $this_page;
+      if ( $this_page + 0 == $num_pages ) $tp = $tp - 3;
+      if ( $this_page + 1 == $num_pages ) $tp = $tp - 2;
+      if ( $this_page + 2 == $num_pages ) $tp = $tp - 1;
+      for ( $i = $tp - 1; $i <= $tp + 1; $i++ )
+      {
+        $list[] = $i;
+      }
+    }
+    else
+    {
+      $list = Array();
+      $current = $this_page;
+      $lower = ( $current < 3 ) ? 1 : $current - 1;
+      for ( $i = 0; $i < 3; $i++ )
+      {
+        $list[] = $lower + $i;
+      }
+    }
+    $url = sprintf($result_url, '0');
+    $link = ( 0 == $start ) ? "<b>First</b>" : "<a href=".'"'."$url".'"'." style='text-decoration: none;'>&laquo; First</a>";
+    $blk->assign_vars(array(
+      'CLASS'=>$cls,
+      'LINK'=>$link
+      ));
+    $inner .= $blk->run();
+    
+    // if ( !in_array(1, $list) )
+    // {
+    //   $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
+    //   $blk->assign_vars(array('CLASS'=>$cls,'LINK'=>'...'));
+    //   $inner .= $blk->run();
+    // }
+    
+    foreach ( $list as $i )
+    {
+      if ( $i == $num_pages )
+        break;
+      $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
+      $offset = strval($i * $perpage);
+      $url = sprintf($result_url, $offset);
+      $j = $i + 1;
+      $link = ( $offset == strval($start) ) ? "<b>$j</b>" : "<a href=".'"'."$url".'"'." style='text-decoration: none;'>$j</a>";
+      $blk->assign_vars(array(
+        'CLASS'=>$cls,
+        'LINK'=>$link
+        ));
+      $inner .= $blk->run();
+    }
+    
+    $total = $num_pages * $perpage - $perpage;
+    
+    if ( $this_page < $num_pages )
+    {
+      // $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
+      // $blk->assign_vars(array('CLASS'=>$cls,'LINK'=>'...'));
+      // $inner .= $blk->run();
+    
+      $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
+      $offset = strval($total);
+      $url = sprintf($result_url, $offset);
+      $j = $i + 1;
+      $link = ( $offset == strval($start) ) ? "<b>Last</b>" : "<a href=".'"'."$url".'"'." style='text-decoration: none;'>Last &raquo;</a>";
+      $blk->assign_vars(array(
+        'CLASS'=>$cls,
+        'LINK'=>$link
+        ));
+      $inner .= $blk->run();
+    }
+    
+  }
+  
+  if ( $start < $total )
+  {
+    $url = sprintf($result_url, abs($start + $perpage));
+    $link = "<a href=".'"'."$url".'"'." style='text-decoration: none;'>Next &raquo;</a>";
+    $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
+    $blk->assign_vars(array(
+      'CLASS'=>$cls,
+      'LINK'=>$link
+      ));
+    $inner .= $blk->run();
+  }
+  
+  $inner .= '<td class="row2" style="cursor: pointer;" onclick="paginator_goto(this, '.$this_page.', '.$num_pages.', '.$perpage.', unescape(\'' . rawurlencode($result_url) . '\'));">&darr;</td>';
+  
+  $paginator = "\n$begin$inner$end\n";
+  if ( $total > 1 )
+    $out .= $paginator;
+  
+  $cls = 'row2';
+  
+  if ( sizeof($q) > 0 )
+  {
+    $i = 0;
+    $out .= $header;
+    foreach ( $q as $val ) {
+      $i++;
+      if ( $i <= $start )
+      {
+        continue;
+      }
+      if ( ( $i - $start ) > $perpage )
+      {
+        break;
+      }
+      $out .= $val;
+    }
+    $out .= $footer;
+  }
+  
+  if ( $total > 1 )
+    $out .= $paginator;
+  
+  return $out;
+}
+
+/** 
+ * Enano version of fputs for debugging
+ */
+
+function enano_fputs($socket, $data)
+{
+  // echo '<pre>' . htmlspecialchars($data) . '</pre>';
+  // flush();
+  // ob_flush();
+  // ob_end_flush();
+  return fputs($socket, $data);
+}
+
+/**
+ * Sanitizes a page URL string so that it can safely be stored in the database.
+ * @param string Page ID to sanitize
+ * @return string Cleaned text
+ */
+
+function sanitize_page_id($page_id)
+{
+  
+  // First, replace spaces with underscores  
+  $page_id = str_replace(' ', '_', $page_id);
+  
+  preg_match_all('/\.[A-Fa-f0-9][A-Fa-f0-9]/', $page_id, $matches);
+  
+  foreach ( $matches[0] as $id => $char )
+  {
+    $char = substr($char, 1);
+    $char = strtolower($char);
+    $char = intval(hexdec($char));
+    $char = chr($char);
+    $page_id = str_replace($matches[0][$id], $char, $page_id);
+  }
+  
+  $pid_clean = preg_replace('/[\w\/:;\(\)@\[\]_-]/', 'X', $page_id);
+  $pid_dirty = enano_str_split($pid_clean, 1);
+  
+  foreach ( $pid_dirty as $id => $char )
+  {
+    if ( $char == 'X' )
+      continue;
+    $cid = ord($char);
+    $cid = dechex($cid);
+    $cid = strval($cid);
+    if ( strlen($cid) < 2 )
+    {
+      $cid = strtoupper("0$cid");
+    }
+    $pid_dirty[$id] = ".$cid";
+  }
+  
+  $pid_chars = enano_str_split($page_id, 1);
+  $page_id_cleaned = '';
+  
+  foreach ( $pid_chars as $id => $char )
+  {
+    if ( $pid_dirty[$id] == 'X' )
+      $page_id_cleaned .= $char;
+    else
+      $page_id_cleaned .= $pid_dirty[$id];
+  }
+  
+  global $mime_types;
+          
+  $exts = array_keys($mime_types);
+  $exts = '(' . implode('|', $exts) . ')';
+  
+  $page_id_cleaned = preg_replace('/\.2e' . $exts . '$/', '.\\1', $page_id_cleaned);
+  
+  return $page_id_cleaned;
+}
+
+/**
+ * Inserts commas into a number to make it more human-readable. Floating point-safe.
+ * @param int The number to process
+ * @return string Input number with commas added
+ */
+
+function commatize($num)
+{
+  $num = (string)$num;
+  if ( strpos($num, '.') )
+  {
+    $whole = explode('.', $num);
+    $num = $whole[0];
+    $dec = $whole[1];
+  }
+  else
+  {
+    $whole = $num;
+  }
+  $offset = ( strlen($num) ) % 3;
+  $len = strlen($num);
+  $offset = ( $offset == 0 )
+    ? 3
+    : $offset;
+  for ( $i = $offset; $i < $len; $i=$i+3 )
+  {
+    $num = substr($num, 0, $i) . ',' . substr($num, $i, $len);
+    $len = strlen($num);
+    $i++;
+  }
+  if ( isset($dec) )
+  {
+    return $num . '.' . $dec;
+  }
+  else
+  {
+    return $num;
+  }
+}
+
+//die('<pre>Original:  01010101010100101010100101010101011010'."\nProcessed: ".uncompress_bitfield(compress_bitfield('01010101010100101010100101010101011010')).'</pre>');
+
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/functions.php~	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1863 @@
+<?php
+
+/*
+ * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
+ * Version 1.0 (Banshee)
+ * Copyright (C) 2006-2007 Dan Fuhry
+ *
+ * This program is Free Software; you can redistribute 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 details.
+ */
+ 
+function getConfig($n) {
+  global $enano_config;
+  if(isset($enano_config[$n])) return $enano_config[$n];
+  else                         return false;
+}
+
+function setConfig($n, $v) {
+  global $enano_config, $db;
+  $enano_config[$n] = $v;
+  $v = $db->escape($v);
+  $e=$db->sql_query('DELETE FROM '.table_prefix.'config WHERE config_name=\''.$n.'\';');
+  if(!$e) $db->_die('Error during generic setConfig() call row deletion.');
+  $e=$db->sql_query('INSERT INTO '.table_prefix.'config(config_name, config_value) VALUES(\''.$n.'\', \''.$v.'\')');
+  if(!$e) $db->_die('Error during generic setConfig() call row insertion.');
+}
+
+function makeUrl($t, $query = false, $escape = false)
+{
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  $flags = '';
+  $sep = urlSeparator;
+  if(isset($_GET['printable'])) { $flags .= $sep.'printable'; $sep = '&'; }
+  if(isset($_GET['theme'])) { $flags .= $sep.'theme='.$session->theme; $sep = '&'; }
+  if(isset($_GET['style'])) { $flags .= $sep.'style='.$session->style; $sep = '&'; }
+  $url = $session->append_sid(contentPath.$t.$flags);
+  if($query)
+  {
+    $sep = strstr($url, '?') ? '&' : '?';
+    $url = $url . $sep . $query;
+  }
+  return ($escape) ? htmlspecialchars($url) : $url;
+}
+
+function makeUrlNS($n, $t, $query = false, $escape = false)
+{
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  $flags = '';
+  if(defined('ENANO_BASE_CLASSES_INITIALIZED')) $sep = urlSeparator;
+  else $sep = (strstr($_SERVER['REQUEST_URI'], '?')) ? '&' : '?';
+  if(isset($_GET['printable'])) { $flags .= $sep.'printable';              $sep = '&'; }
+  if(isset($_GET['theme']))     { $flags .= $sep.'theme='.$session->theme; $sep = '&'; }
+  if(isset($_GET['style']))     { $flags .= $sep.'style='.$session->style; $sep = '&'; }
+  
+  if(defined('ENANO_BASE_CLASSES_INITIALIZED'))
+  {
+    $url = contentPath.$paths->nslist[$n].$t.$flags;
+  }
+  else
+  {
+    $url = contentPath.$n.':'.$t.$flags;
+  }
+  
+  if($query)
+  {
+    if(strstr($url, '?')) $sep =  '&';
+    else $sep = '?';
+    $url = $url . $sep . $query . $flags;
+  }
+  
+  if(defined('ENANO_BASE_CLASSES_INITIALIZED'))
+  {
+    $url = $session->append_sid($url);
+  }
+  
+  return ($escape) ? htmlspecialchars($url) : $url;
+}
+
+function makeUrlComplete($n, $t, $query = false, $escape = false)
+{
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  $flags = '';
+  if(defined('ENANO_BASE_CLASSES_INITIALIZED')) $sep = urlSeparator;
+  else $sep = (strstr($_SERVER['REQUEST_URI'], '?')) ? '&' : '?';
+  if(isset($_GET['printable'])) { $flags .= $sep.'printable';              $sep = '&'; }
+  if(isset($_GET['theme']))     { $flags .= $sep.'theme='.$session->theme; $sep = '&'; }
+  if(isset($_GET['style']))     { $flags .= $sep.'style='.$session->style; $sep = '&'; }
+  if(defined('ENANO_BASE_CLASSES_INITIALIZED')) $url = $session->append_sid(contentPath.$paths->nslist[$n].$t.$flags);
+  else $url = contentPath.$n.':'.$t.$flags;
+  if($query)
+  {
+    if(strstr($url, '?')) $sep =  '&';
+    else $sep = '?';
+    $url = $url . $sep . $query . $flags;
+  }
+  $baseprot = 'http' . ( isset($_SERVER['HTTPS']) ? 's' : '' ) . '://' . $_SERVER['HTTP_HOST'];
+  $url = $baseprot . $url;
+  return ($escape) ? htmlspecialchars($url) : $url;
+}
+
+/**
+ * Redirect the user to the specified URL.
+ * @param string $url The URL, either relative or absolute.
+ * @param string $title The title of the message
+ * @param string $message A short message to show to the user
+ * @param string $timeout Timeout, in seconds, to delay the redirect. Defaults to 3.
+ */
+ 
+function redirect($url, $title = 'Redirecting...', $message = 'Please wait while you are redirected.', $timeout = 3)
+{
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  
+  if ( $timeout == 0 )
+  {
+    header('Location: ' . $url);
+    header('HTTP/1.1 307 Temporary Redirect');
+  }
+  
+  $template->add_header('<meta http-equiv="refresh" content="' . $timeout . '; url=' . str_replace('"', '\\"', $url) . '" />');
+  $template->add_header('<script type="text/javascript">
+      function __r() {
+        // FUNCTION AUTOMATICALLY GENERATED
+        window.location="' . str_replace('"', '\\"', $url) . '";
+      }
+      setTimeout(\'__r();\', ' . $timeout . '000);
+    </script>
+    ');
+  
+  $template->tpl_strings['PAGE_NAME'] = $title;
+  $template->header(true);
+  echo '<p>' . $message . '</p><p>If you are not redirected within ' . ( $timeout + 1 ) . ' seconds, <a href="' . str_replace('"', '\\"', $url) . '">please click here</a>.</p>';
+  $template->footer(true);
+  
+  $db->close();
+  exit(0);
+  
+}
+
+// Removed wikiFormat() from here, replaced with RenderMan::render
+
+function isPage($p) {
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  if(isset($paths->pages[$p])) return true;
+  $d = RenderMan::strToPageID($p);
+  if($d[1] != 'Special' && $d[1] != 'Template' && $d[1] != 'Admin') return false;
+  $a = explode('/', $p);
+  if(isset($paths->pages[$a[0]])) return true;
+  else return false;
+}
+
+function arrayItemUp($arr, $keyname) {
+  $keylist = array_keys($arr);
+  $keyflop = array_flip($keylist);
+  $idx = $keyflop[$keyname];
+  $idxm = $idx - 1;
+  $temp = $arr[$keylist[$idxm]];
+  if($arr[$keylist[0]] == $arr[$keyname]) return $arr;
+  $arr[$keylist[$idxm]] = $arr[$keylist[$idx]];
+  $arr[$keylist[$idx]] = $temp;
+  return $arr;
+}
+
+function arrayItemDown($arr, $keyname) {
+  $keylist = array_keys($arr);
+  $keyflop = array_flip($keylist);
+  $idx = $keyflop[$keyname];
+  $idxm = $idx + 1;
+  $temp = $arr[$keylist[$idxm]];
+  $sz = sizeof($arr); $sz--;
+  if($arr[$keylist[$sz]] == $arr[$keyname]) return $arr;
+  $arr[$keylist[$idxm]]  =  $arr[$keylist[$idx]];
+  $arr[$keylist[$idx]]   =  $temp;
+  return $arr;
+}
+
+function arrayItemTop($arr, $keyname) {
+  $keylist = array_keys($arr);
+  $keyflop = array_flip($keylist);
+  $idx = $keyflop[$keyname];
+  while( $orig != $arr[$keylist[0]] ) {
+    // echo 'Keyname: '.$keylist[$idx] . '<br />'; flush(); ob_flush(); // Debugger
+    if($idx < 0) return $arr;
+    if($keylist[$idx] == '' || $keylist[$idx] < 0 || !$keylist[$idx]) {
+      /* echo 'Infinite loop caught in arrayItemTop(<br /><pre>';
+      print_r($arr);
+      echo '</pre><br />, '.$keyname.');<br /><br />EnanoCMS: Critical error during function call, exiting to prevent excessive server load.';
+      exit; */
+      return $arr;
+    }
+    $arr = arrayItemUp($arr, $keylist[$idx]);
+    $idx--;
+  }
+  return $arr;
+}
+
+function arrayItemBottom($arr, $keyname) {
+  $keylist = array_keys($arr);
+  $keyflop = array_flip($keylist);
+  $idx = $keyflop[$keyname];
+  $sz = sizeof($arr); $sz--;
+  while( $orig != $arr[$keylist[$sz]] ) {
+    // echo 'Keyname: '.$keylist[$idx] . '<br />'; flush(); ob_flush(); // Debugger
+    if($idx > $sz) return $arr;
+    if($keylist[$idx] == '' || $keylist[$idx] < 0 || !$keylist[$idx]) {
+      echo 'Infinite loop caught in arrayItemBottom(<br /><pre>';
+      print_r($arr);
+      echo '</pre><br />, '.$keyname.');<br /><br />EnanoCMS: Critical error during function call, exiting to prevent excessive server load.';
+      exit;
+    }
+    $arr = arrayItemDown($arr, $keylist[$idx]);
+    $idx++;
+  }
+  return $arr;
+}
+
+// Convert IP address to hex string
+// Input:  127.0.0.1  (string)
+// Output: 0x7f000001 (string)
+// Updated 12/8/06 to work with PHP4 and not use eval() (blech)
+function ip2hex($ip) {
+  if ( preg_match('/^([0-9a-f:]+)$/', $ip) )
+  {
+    // this is an ipv6 address
+    return str_replace(':', '', $ip);
+  }
+  $nums = explode('.', $ip);
+  if(sizeof($nums) != 4) return false;
+  $str = '0x';
+  foreach($nums as $n)
+  {
+    $str .= (string)dechex($n);
+  }
+  return $str;
+}
+
+// Convert DWord to IP address
+// Input:  0x7f000001
+// Output: 127.0.0.1
+// Updated 12/8/06 to work with PHP4 and not use eval() (blech)
+function hex2ip($in) {
+  if(substr($in, 0, 2) == '0x') $ip = substr($in, 2, 8);
+  else $ip = substr($in, 0, 8);
+  $octets = enano_str_split($ip, 2);
+  $str = '';
+  $newoct = Array();
+  foreach($octets as $o)
+  {
+    $o = (int)hexdec($o);
+    $newoct[] = $o;
+  }
+  return implode('.', $newoct);
+}
+
+// Function strip_php moved to RenderMan class
+
+function die_semicritical($t, $p)
+{
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  $db->close();
+  
+  if ( ob_get_status() )
+    ob_end_clean();
+  
+  dc_here('functions: <span style="color: red">calling die_semicritical</span>');
+  
+  $tpl = new template_nodb();
+  $tpl->load_theme('oxygen', 'bleu');
+  $tpl->tpl_strings['SITE_NAME'] = getConfig('site_name');
+  $tpl->tpl_strings['SITE_DESC'] = getConfig('site_desc');
+  $tpl->tpl_strings['COPYRIGHT'] = getConfig('copyright_notice');
+  $tpl->tpl_strings['PAGE_NAME'] = $t;
+  $tpl->header();
+  echo $p;
+  $tpl->footer();
+  
+  exit;
+}
+
+function die_friendly($t, $p)
+{
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  
+  if ( ob_get_status() )
+    ob_end_clean();
+  
+  dc_here('functions: <span style="color: red">calling die_friendly</span>');
+  $paths->cpage['name'] = $t;
+  $template->tpl_strings['PAGE_NAME'] = $t;
+  $template->header();
+  echo $p;
+  $template->footer();
+  $db->close();
+  
+  exit;
+}
+
+function grinding_halt($t, $p)
+{
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  
+  $db->close();
+  
+  if ( ob_get_status() )
+    ob_end_clean();
+  
+  dc_here('functions: <span style="color: red">calling grinding_halt</span>');
+  $tpl = new template_nodb();
+  $tpl->load_theme('oxygen', 'bleu');
+  $tpl->tpl_strings['SITE_NAME'] = 'Critical error';
+  $tpl->tpl_strings['SITE_DESC'] = 'This website is experiencing a serious error and cannot load.';
+  $tpl->tpl_strings['COPYRIGHT'] = 'Unable to retrieve copyright information';
+  $tpl->tpl_strings['PAGE_NAME'] = $t;
+  $tpl->header();
+  echo $p;
+  $tpl->footer();
+  exit;
+}
+
+function show_category_info() {
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  dc_here('functions: showing category info');
+  if($template->no_headers && !strpos($_SERVER['REQUEST_URI'], 'ajax.php')) return '';
+  if($paths->namespace=='Category')
+  {
+    $q = $db->sql_query('SELECT page_id,namespace FROM '.table_prefix.'categories WHERE category_id=\''.$paths->cpage['urlname_nons'].'\' AND namespace=\'Category\' ORDER BY page_id;');
+    if(!$q) $db->_die('The category information could not be selected.');
+    $ticker = -1;
+    echo '<h3>Subcategories</h3>';
+    if($db->numrows() < 1) echo '<p>There are no subcategories in this category.</p>';
+    echo '<table border="0" cellspacing="1" cellpadding="4">';
+    while($row = $db->fetchrow())
+    {
+      $ticker++;if($ticker==3) $ticker=0;
+      if($ticker==0) echo '<tr>';
+      echo '<td style="width: 200px;"><a href="'.makeUrlNS($row['namespace'], $row['page_id']).'">'.$paths->pages[$paths->nslist[$row['namespace']].$row['page_id']]['name'].'</a></td>';
+      if($ticker==2) echo '</tr>';
+    }
+    $db->free_result();
+    if($ticker) echo '</tr>';
+    echo '</table>';
+    
+    $q = $db->sql_query('SELECT page_id,namespace FROM '.table_prefix.'categories WHERE category_id=\''.$paths->cpage['urlname_nons'].'\' AND namespace!=\'Category\' ORDER BY page_id;');
+    if(!$q) $db->_die('The category information could not be selected.');
+    $ticker = -1;
+    echo '<h3>Pages</h3>';
+    if($db->numrows() < 1) echo '<p>There are no pages in this category.</p>';
+    echo '<table border="0" cellspacing="1" cellpadding="4">';
+    while($row = $db->fetchrow())
+    {
+      $ticker++;if($ticker==3) $ticker=0;
+      if($ticker==0) echo '<tr>';
+      echo '<td style="width: 200px;"><a href="'.makeUrlNS($row['namespace'], $row['page_id']).'">'.$paths->pages[$paths->nslist[$row['namespace']].$row['page_id']]['name'].'</a></td>';
+      if($ticker==2) echo '</tr>';
+    }
+    $db->free_result();
+    if($ticker) echo '</tr>';
+    echo '</table><br /><br />';
+  }
+  $q = $db->sql_query('SELECT category_id FROM '.table_prefix.'categories WHERE page_id=\''.$paths->cpage['urlname_nons'].'\' AND namespace=\''.$paths->namespace.'\'');
+  if(!$q) $db->_die('The error seems to have occurred during selection of category data.');
+  if($db->numrows() > 0) {
+    echo '<div class="mdg-comment" style="margin-left: 0;">Categories: ';
+    $i=0;
+    while($r = $db->fetchrow())
+    {
+      if($i>0) echo ', ';
+      $i++;
+      echo '<a href="'.makeUrlNS('Category', $r['category_id']).'">'.$paths->pages[$paths->nslist['Category'].$r['category_id']]['name'].'</a>';
+    }
+    if( ( $paths->wiki_mode && !$paths->page_protected ) || ( $session->get_permissions('edit_cat') && $session->get_permissions('even_when_protected') ) ) echo ' [ <a href="'.makeUrl($paths->page, 'do=catedit', true).'" onclick="ajaxCatEdit(); return false;">edit categorization</a> ]</div>';
+  } else {
+    echo '<div class="mdg-comment" style="margin-left: 0;">Categories: ';
+    echo '(Uncategorized)';
+    if( ( $paths->wiki_mode && !$paths->page_protected ) || ( $session->get_permissions('edit_cat') && $session->get_permissions('even_when_protected') ) ) echo ' [ <a href="'.makeUrl($paths->page, 'do=catedit', true).'" onclick="ajaxCatEdit(); return false;">edit categorization</a> ]</div>';
+    else echo '</div>';
+  }
+  $db->free_result();
+}
+
+function show_file_info()
+{
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  if($paths->namespace != 'File') return null; // Prevent unnecessary work
+  $selfn = $paths->cpage['urlname_nons']; // substr($paths->page, strlen($paths->nslist['File']), strlen($paths->cpage));
+  if(substr($paths->cpage['name'], 0, strlen($paths->nslist['File']))==$paths->nslist['File']) $selfn = substr($paths->cpage['urlname_nons'], strlen($paths->nslist['File']), strlen($paths->cpage['urlname_nons']));
+  $q = $db->sql_query('SELECT mimetype,time_id,size FROM '.table_prefix.'files WHERE page_id=\''.$selfn.'\' ORDER BY time_id DESC;');
+  if(!$q) $db->_die('The file type could not be fetched.');
+  if($db->numrows() < 1) { echo '<div class="mdg-comment" style="margin-left: 0;"><h3>Uploaded file</h3><p>There are no files uploaded with this name yet. <a href="'.makeUrlNS('Special', 'UploadFile/'.$paths->cpage['urlname_nons']).'">Upload a file...</a></p></div><br />'; return; }
+  $r = $db->fetchrow();
+  $mimetype = $r['mimetype'];
+  $datestring = date('F d, Y h:i a', (int)$r['time_id']);
+  echo '<div class="mdg-comment" style="margin-left: 0;"><p><h3>Uploaded file</h3></p><p>Type: '.$r['mimetype'].'<br />Size: ';
+  $fs = $r['size'];
+  echo $fs.' bytes';
+  $fs = (int)$fs;
+  if($fs >= 1048576)
+  {
+    $fs = round($fs / 1048576, 1);
+    echo ' ('.$fs.' MB)';
+  } elseif($fs >= 1024) {
+    $fs = round($fs / 1024, 1);
+    echo ' ('.$fs.' KB)';
+  }
+  echo '<br />Uploaded: '.$datestring.'</p>';
+  if(substr($mimetype, 0, 6)!='image/' && ( substr($mimetype, 0, 5) != 'text/' || $mimetype == 'text/html' || $mimetype == 'text/javascript' ))
+  {
+    echo '<div class="warning-box">This file type may contain viruses or other code that could harm your computer. You should exercise caution if you download it.</div>';
+  }
+  if(substr($mimetype, 0, 6)=='image/')
+  {
+    echo '<p><a href="'.makeUrlNS('Special', 'DownloadFile'.'/'.$selfn).'"><img style="border: 0;" alt="'.$paths->page.'" src="'.makeUrlNS('Special', 'DownloadFile'.'/'.$selfn.htmlspecialchars(urlSeparator).'preview').'" /></a></p>';
+  }
+  echo '<p><a href="'.makeUrlNS('Special', 'DownloadFile'.'/'.$selfn.'/'.$r['time_id'].htmlspecialchars(urlSeparator).'download').'">Download this file</a>';
+  if(!$paths->page_protected && ( $paths->wiki_mode || $session->get_permissions('upload_new_version') ))
+  {
+    echo '  |  <a href="'.makeUrlNS('Special', 'UploadFile'.'/'.$selfn).'">Upload new version</a>';
+  }
+  echo '</p>';
+  if($db->numrows() > 1)
+  {
+    echo '<h3>File history</h3><p>';
+    while($r = $db->fetchrow())
+    {
+      echo '(<a href="'.makeUrlNS('Special', 'DownloadFile'.'/'.$selfn.'/'.$r['time_id'].htmlspecialchars(urlSeparator).'download').'">this ver</a>) ';
+      if($session->get_permissions('history_rollback'))
+        echo ' (<a href="#" onclick="ajaxRollback(\''.$r['time_id'].'\'); return false;">revert</a>) ';
+      $mimetype = $r['mimetype'];
+      $datestring = date('F d, Y h:i a', (int)$r['time_id']);
+      echo $datestring.': '.$r['mimetype'].', ';
+      $fs = $r['size'];
+      $fs = (int)$fs;
+      if($fs >= 1048576)
+      {
+        $fs = round($fs / 1048576, 1);
+        echo ' '.$fs.' MB';
+      } elseif($fs >= 1024) {
+        $fs = round($fs / 1024, 1);
+        echo ' '.$fs.' KB';
+      } else {
+        echo ' '.$fs.' bytes';
+      }
+      echo '<br />';
+    }
+    echo '</p>';
+  }
+  $db->free_result();
+  echo '</div><br />';
+}
+
+function display_page_headers()
+{
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  if($session->get_permissions('vote_reset') && $paths->cpage['delvotes'] > 0)
+  {
+    $hr = implode(', ', explode('|', $paths->cpage['delvote_ips']));
+    $is = 'is';
+    $s = '';
+    $s2 = 's';
+    if ( $paths->cpage['delvotes'] > 1)
+    {
+      $is = 'are';
+      $s = 's';
+      $s2 = '';
+    }
+    echo '<div class="info-box" style="margin-left: 0; margin-top: 5px;" id="mdgDeleteVoteNoticeBox">
+            <b>Notice:</b> There '.$is.' '.$paths->cpage['delvotes'].' user'.$s.' that think'.$s2.' this page should be deleted.<br />
+            <b>Users that voted:</b> ' . $hr . '<br />
+            <a href="'.makeUrl($paths->page, 'do=deletepage').'" onclick="ajaxDeletePage(); return false;">Delete page</a>  |  <a href="'.makeUrl($paths->page, 'do=resetvotes').'" onclick="ajaxResetDelVotes(); return false;">Reset votes</a>
+          </div>';
+  }
+}
+
+function display_page_footers()
+{
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  if(isset($_GET['nofooters'])) return;
+  $code = $plugins->setHook('send_page_footers');
+  foreach ( $code as $cmd )
+  {
+    eval($cmd);
+  }
+  show_file_info();
+  show_category_info();
+}
+
+function password_prompt($id = false)
+{
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  if(!$id) $id = $paths->page;
+  if(isset($paths->pages[$id]['password']) && strlen($paths->pages[$id]['password']) == 40 && !isset($_REQUEST['pagepass']))
+  {
+    die_friendly('Password required', '<p>You must supply a password to access this page.</p><form action="'.makeUrl($paths->pages[$id]['urlname']).'" method="post"><p>Password: <input name="pagepass" type="password" /></p><p><input type="submit" value="Submit" /></p>');
+  } elseif(isset($_REQUEST['pagepass'])) {
+    $p = (preg_match('#^([a-f0-9]*){40}$#', $_REQUEST['pagepass'])) ? $_REQUEST['pagepass'] : sha1($_REQUEST['pagepass']);
+    if($p != $paths->pages[$id]['password']) die_friendly('Password required', '<p style="color: red;">The password you entered is incorrect.</p><form action="'.makeUrl($paths->page).'" method="post"><p>Password: <input name="pagepass" type="password" /></p><p><input type="submit" value="Submit" /></p>');
+  }
+}
+
+function str_hex($string){
+    $hex='';
+    for ($i=0; $i < strlen($string); $i++){
+        $hex .= ' '.dechex(ord($string[$i]));
+    }
+    return substr($hex, 1, strlen($hex));
+}
+
+// Function pulled from phpBB's smtp.php
+function smtp_get_response($socket, $response, $line = __LINE__) 
+{
+	$server_response = '';
+	while (substr($server_response, 3, 1) != ' ') 
+	{
+		if (!($server_response = fgets($socket, 256))) 
+		{
+      die_friendly('SMTP Error', "<p>Couldn't get mail server response codes</p>");
+		}
+	} 
+
+	if (!(substr($server_response, 0, 3) == $response)) 
+	{ 
+    die_friendly('SMTP Error', "<p>Ran into problems sending mail. Response: $server_response</p>");
+	} 
+}
+
+function smtp_send_email($to, $subject, $message, $from)
+{
+  return smtp_send_email_core($to, $subject, $message, "From: <$from>\n");
+}
+
+// Replacement or substitute for PHP's mail command
+// Ported from phpBB - copyright (C) phpBB group, GPL.
+function smtp_send_email_core($mail_to, $subject, $message, $headers = '')
+{
+	global $board_config;
+
+	// Fix any bare linefeeds in the message to make it RFC821 Compliant.
+	$message = preg_replace("#(?<!\r)\n#si", "\r\n", $message);
+
+	if ($headers != '')
+	{
+		if (is_array($headers))
+		{
+			if (sizeof($headers) > 1)
+			{
+				$headers = join("\n", $headers);
+			}
+			else
+			{
+				$headers = $headers[0];
+			}
+		}
+		$headers = chop($headers);
+
+		// Make sure there are no bare linefeeds in the headers
+		$headers = preg_replace('#(?<!\r)\n#si', "\r\n", $headers);
+
+		// Ok this is rather confusing all things considered,
+		// but we have to grab bcc and cc headers and treat them differently
+		// Something we really didn't take into consideration originally
+		$header_array = explode("\r\n", $headers);
+		@reset($header_array);
+
+		$headers = '';
+		while(list(, $header) = each($header_array))
+		{
+			if (preg_match('#^cc:#si', $header))
+			{
+				$cc = preg_replace('#^cc:(.*)#si', '\1', $header);
+			}
+			else if (preg_match('#^bcc:#si', $header))
+			{
+				$bcc = preg_replace('#^bcc:(.*)#si', '\1', $header);
+				$header = '';
+			}
+			$headers .= ($header != '') ? $header . "\r\n" : '';
+		}
+
+		$headers = chop($headers);
+		$cc = explode(', ', $cc);
+		$bcc = explode(', ', $bcc);
+	}
+
+	if (trim($subject) == '')
+	{
+		die_friendly(GENERAL_ERROR, "No email Subject specified");
+	}
+
+	if (trim($message) == '')
+	{
+		die_friendly(GENERAL_ERROR, "Email message was blank");
+	}
+  
+  // setup SMTP
+  $host = getConfig('smtp_server');
+  if ( empty($host) )
+    return 'No smtp_host in config';
+  if ( strstr($host, ':' ) )
+  {
+    $n = explode(':', $host);
+    $smtp_host = $n[0];
+    $port = intval($n[1]);
+  }
+  else
+  {
+    $smtp_host = $host;
+    $port = 25;
+  }
+  
+  $smtp_user = getConfig('smtp_user');
+  $smtp_pass = getConfig('smtp_password');
+  
+	// Ok we have error checked as much as we can to this point let's get on
+	// it already.
+	if( !$socket = @fsockopen($smtp_host, $port, $errno, $errstr, 20) )
+	{
+		die_friendly(GENERAL_ERROR, "Could not connect to smtp host : $errno : $errstr");
+	}
+
+	// Wait for reply
+	smtp_get_response($socket, "220", __LINE__);
+
+	// Do we want to use AUTH?, send RFC2554 EHLO, else send RFC821 HELO
+	// This improved as provided by SirSir to accomodate
+	if( !empty($smtp_user) && !empty($smtp_pass) )
+	{ 
+		enano_fputs($socket, "EHLO " . $smtp_host . "\r\n");
+		smtp_get_response($socket, "250", __LINE__);
+
+		enano_fputs($socket, "AUTH LOGIN\r\n");
+		smtp_get_response($socket, "334", __LINE__);
+
+		enano_fputs($socket, base64_encode($smtp_user) . "\r\n");
+		smtp_get_response($socket, "334", __LINE__);
+
+		enano_fputs($socket, base64_encode($smtp_pass) . "\r\n");
+		smtp_get_response($socket, "235", __LINE__);
+	}
+	else
+	{
+		enano_fputs($socket, "HELO " . $smtp_host . "\r\n");
+		smtp_get_response($socket, "250", __LINE__);
+	}
+
+	// From this point onward most server response codes should be 250
+	// Specify who the mail is from....
+	enano_fputs($socket, "MAIL FROM: <" . getConfig('contact_email') . ">\r\n");
+	smtp_get_response($socket, "250", __LINE__);
+
+	// Specify each user to send to and build to header.
+	$to_header = '';
+
+	// Add an additional bit of error checking to the To field.
+	$mail_to = (trim($mail_to) == '') ? 'Undisclosed-recipients:;' : trim($mail_to);
+	if (preg_match('#[^ ]+\@[^ ]+#', $mail_to))
+	{
+		enano_fputs($socket, "RCPT TO: <$mail_to>\r\n");
+		smtp_get_response($socket, "250", __LINE__);
+	}
+
+	// Ok now do the CC and BCC fields...
+	@reset($bcc);
+	while(list(, $bcc_address) = each($bcc))
+	{
+		// Add an additional bit of error checking to bcc header...
+		$bcc_address = trim($bcc_address);
+		if (preg_match('#[^ ]+\@[^ ]+#', $bcc_address))
+		{
+			enano_fputs($socket, "RCPT TO: <$bcc_address>\r\n");
+			smtp_get_response($socket, "250", __LINE__);
+		}
+	}
+
+	@reset($cc);
+	while(list(, $cc_address) = each($cc))
+	{
+		// Add an additional bit of error checking to cc header
+		$cc_address = trim($cc_address);
+		if (preg_match('#[^ ]+\@[^ ]+#', $cc_address))
+		{
+			enano_fputs($socket, "RCPT TO: <$cc_address>\r\n");
+			smtp_get_response($socket, "250", __LINE__);
+		}
+	}
+
+	// Ok now we tell the server we are ready to start sending data
+	enano_fputs($socket, "DATA\r\n");
+
+	// This is the last response code we look for until the end of the message.
+	smtp_get_response($socket, "354", __LINE__);
+
+	// Send the Subject Line...
+	enano_fputs($socket, "Subject: $subject\r\n");
+
+	// Now the To Header.
+	enano_fputs($socket, "To: $mail_to\r\n");
+
+	// Now any custom headers....
+	enano_fputs($socket, "$headers\r\n\r\n");
+
+	// Ok now we are ready for the message...
+	enano_fputs($socket, "$message\r\n");
+
+	// Ok the all the ingredients are mixed in let's cook this puppy...
+	enano_fputs($socket, ".\r\n");
+	smtp_get_response($socket, "250", __LINE__);
+
+	// Now tell the server we are done and close the socket...
+	enano_fputs($socket, "QUIT\r\n");
+	fclose($socket);
+
+	return TRUE;
+}
+
+/**
+ * Tell which version of Enano we're running.
+ * @param bool $long if true, uses English version names (e.g. alpha, beta, release candidate). If false (default) uses abbreviations (1.0a1, 1.0b3, 1.0RC2, etc.)
+ * @return string
+ */
+
+function enano_version($long = false, $no_nightly = false)
+{
+  $r = getConfig('enano_version');
+  $rc = ( $long ) ? ' release candidate ' : 'RC';
+  $b = ( $long ) ? ' beta ' : 'b';
+  $a = ( $long ) ? ' alpha ' : 'a';
+  if($v = getConfig('enano_rc_version')) $r .= $rc.$v;
+  if($v = getConfig('enano_beta_version')) $r .= $b.$v;
+  if($v = getConfig('enano_alpha_version')) $r .= $a.$v;
+  if ( defined('ENANO_NIGHTLY') && !$no_nightly )
+  {
+    $nightlytag  = ENANO_NIGHTLY_MONTH . '-' . ENANO_NIGHTLY_DAY . '-' . ENANO_NIGHTLY_YEAR;
+    $nightlylong = ' nightly; build date: ' . ENANO_NIGHTLY_MONTH . '-' . ENANO_NIGHTLY_DAY . '-' . ENANO_NIGHTLY_YEAR;
+    $r = ( $long ) ? $r . $nightlylong : $r . '-nightly-' . $nightlytag;
+  }
+  return $r;
+}
+
+function _dualurlenc($t) {
+  return rawurlencode(rawurlencode($t));
+}
+  
+function _die($t) {
+  $_ob = 'document.getElementById("ajaxEditContainer").innerHTML = unescape(\'' . rawurlencode('' . $t . '') . '\')';
+  die($_ob);
+}
+
+function jsdie($text) {
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  $text = rawurlencode($text . "\n\nSQL Backtrace:\n" . $db->sql_backtrace());
+  echo 'document.getElementById("ajaxEditContainer").innerHTML = unescape(\''.$text.'\');';
+}
+
+// HTML sanitizing function - written by Kallahar
+// Original function at: http://quickwired.com/kallahar/smallprojects/php_xss_filter_function.php
+
+// UNUSED - todo: remove this in gold or put it to use
+
+function RemoveXSS($val) {
+  // remove all non-printable characters. CR(0a) and LF(0b) and TAB(9) are allowed
+  // this prevents some character re-spacing such as <java\0script>
+  // note that you have to handle splits with \n, \r, and \t later since they *are* allowed in some inputs
+  $val = preg_replace('/([\x00-\x08][\x0b-\x0c][\x0e-\x20])/', '', $val);
+  
+  // straight replacements, the user should never need these since they're normal characters
+  // this prevents like <IMG SRC=&#X40&#X61&#X76&#X61&#X73&#X63&#X72&#X69&#X70&#X74&#X3A&#X61&#X6C&#X65&#X72&#X74&#X28&#X27&#X58&#X53&#X53&#X27&#X29>
+  $search  = 'abcdefghijklmnopqrstuvwxyz';
+  $search .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
+  $search .= '1234567890!@#$%^&*()';
+  $search .= '~`";:?+/={}[]-_|\'\\';
+  for ($i = 0; $i < strlen($search); $i++) {
+    // ;? matches the ;, which is optional
+    // 0{0,7} matches any padded zeros, which are optional and go up to 8 chars
+  
+    // &#x0040 @ search for the hex values
+    $val = preg_replace('/(&#[x|X]0{0,8}'.dechex(ord($search[$i])).';?)/i', $search[$i], $val); // with a ;
+    // &#00064 @ 0{0,7} matches '0' zero to seven times
+    $val = preg_replace('/(&#0{0,8}'.ord($search[$i]).';?)/', $search[$i], $val); // with a ;
+  }
+  
+  // now the only remaining whitespace attacks are \t, \n, and \r
+  $ra1 = Array('javascript', 'vbscript', 'expression', 'applet', 'meta', 'xml', 'blink', 'link', 'script', 'embed', 'object', 'iframe', 'frame', 'frameset', 'ilayer', 'layer', 'bgsound', 'title', 'base');
+  $ra2 = Array('onabort', 'onactivate', 'onafterprint', 'onafterupdate', 'onbeforeactivate', 'onbeforecopy', 'onbeforecut', 'onbeforedeactivate', 'onbeforeeditfocus', 'onbeforepaste', 'onbeforeprint', 'onbeforeunload', 'onbeforeupdate', 'onblur', 'onbounce', 'oncellchange', 'onchange', 'onclick', 'oncontextmenu', 'oncontrolselect', 'oncopy', 'oncut', 'ondataavailable', 'ondatasetchanged', 'ondatasetcomplete', 'ondblclick', 'ondeactivate', 'ondrag', 'ondragend', 'ondragenter', 'ondragleave', 'ondragover', 'ondragstart', 'ondrop', 'onerror', 'onerrorupdate', 'onfilterchange', 'onfinish', 'onfocus', 'onfocusin', 'onfocusout', 'onhelp', 'onkeydown', 'onkeypress', 'onkeyup', 'onlayoutcomplete', 'onload', 'onlosecapture', 'onmousedown', 'onmouseenter', 'onmouseleave', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onmousewheel', 'onmove', 'onmoveend', 'onmovestart', 'onpaste', 'onpropertychange', 'onreadystatechange', 'onreset', 'onresize', 'onresizeend', 'onresizestart', 'onrowenter', 'onrowexit', 'onrowsdelete', 'onrowsinserted', 'onscroll', 'onselect', 'onselectionchange', 'onselectstart', 'onstart', 'onstop', 'onsubmit', 'onunload');
+  $ra = array_merge($ra1, $ra2);
+  
+  $found = true; // keep replacing as long as the previous round replaced something
+  while ($found == true) {
+    $val_before = $val;
+    for ($i = 0; $i < sizeof($ra); $i++) {
+      $pattern = '/';
+      for ($j = 0; $j < strlen($ra[$i]); $j++) {
+        if ($j > 0) {
+          $pattern .= '(';
+          $pattern .= '(&#[x|X]0{0,8}([9][a][b]);?)?';
+          $pattern .= '|(&#0{0,8}([9][10][13]);?)?';
+          $pattern .= ')?';
+        }
+        $pattern .= $ra[$i][$j];
+      }
+      $pattern .= '/i';
+      $replacement = substr($ra[$i], 0, 2).'<b></b>'.substr($ra[$i], 2); // add in <> to nerf the tag
+      $val = preg_replace($pattern, $replacement, $val); // filter out the hex tags
+      if ($val_before == $val) {
+        // no replacements were made, so exit the loop
+        $found = false;
+      }
+    }
+  }
+  return $val;
+}
+
+/**
+ * Capitalizes the first letter of a string
+ * @param $text string the text to be transformed
+ * @return string
+ */
+ 
+function capitalize_first_letter($text)
+{
+  return strtoupper(substr($text, 0, 1)) . substr($text, 1);
+}
+
+/**
+ * Checks if a value in a bitfield is on or off
+ * @param $bitfield int the bit-field value
+ * @param $value int the value to switch off
+ * @return bool
+ */
+ 
+function is_bit($bitfield, $value)
+{
+  return ( $bitfield & $value ) ? true : false;
+}
+
+/**
+ * Trims spaces/newlines from the beginning and end of a string
+ * @param $text the text to process
+ * @return string
+ */
+ 
+function trim_spaces($text)
+{
+  $d = true;
+  while($d)
+  {
+    $c = substr($text, 0, 1);
+    $a = substr($text, strlen($text)-1, strlen($text));
+    if($c == "\n" || $c == "\r" || $c == "\t" || $c == ' ') $text = substr($text, 1, strlen($text));
+    elseif($a == "\n" || $a == "\r" || $a == "\t" || $a == ' ') $text = substr($text, 0, strlen($text)-1);
+    else $d = false;
+  }
+  return $text;
+}
+
+/**
+ * Enano-ese equivalent of str_split() which is only found in PHP5
+ * @param $text string the text to split
+ * @param $inc int size of each block
+ * @return array
+ */
+ 
+function enano_str_split($text, $inc = 1)
+{
+  if($inc < 1) return false;
+  if($inc >= strlen($text)) return Array($text);
+  $len = ceil(strlen($text) / $inc);
+  $ret = Array();
+  for($i=0;$i<strlen($text);$i=$i+$inc)
+  {
+    $ret[] = substr($text, $i, $inc);
+  }
+  return $ret;
+}
+
+/**
+ * Converts a hexadecimal number to a binary string.
+ * @param text string hexadecimal number
+ * @return string
+ */
+function hex2bin($text)
+{
+  $arr = enano_str_split($text, 2);
+  $ret = '';
+  for ($i=0; $i<sizeof($arr); $i++)
+  {
+    $ret .= chr(hexdec($arr[$i]));
+  }
+  return $ret;
+}
+
+/**
+ * Generates and/or prints a human-readable backtrace
+ * @param bool $return - if true, this function returns a string, otherwise returns null
+ * @return mixed
+ */
+ 
+function enano_debug_print_backtrace($return = false)
+{
+  ob_start();
+  echo '<pre>';
+  debug_print_backtrace();
+  echo '</pre>';
+  $c = ob_get_contents();
+  ob_end_clean();
+  if($return) return $c;
+  else echo $c;
+  return null;
+}
+
+/**
+ * Like rawurlencode(), but encodes all characters
+ * @param string $text the text to encode
+ * @param optional string $prefix text before each hex character
+ * @param optional string $suffix text after each hex character
+ * @return string
+ */
+ 
+function hexencode($text, $prefix = '%', $suffix = '')
+{
+  $arr = enano_str_split($text);
+  $r = '';
+  foreach($arr as $a)
+  {
+    $nibble = (string)dechex(ord($a));
+    if(strlen($nibble) == 1) $nibble = '0' . $nibble;
+    $r .= $prefix . $nibble . $suffix;
+  }
+  return $r;
+}
+
+/**
+ * Enano-ese equivalent of get_magic_quotes_gpc()
+ * @return bool
+ */
+ 
+function enano_get_magic_quotes_gpc()
+{
+  if(function_exists('get_magic_quotes_gpc'))
+  {
+    return ( get_magic_quotes_gpc() == 1 );
+  }
+  else
+  {
+    return ( strtolower(@ini_get('magic_quotes_gpc')) == '1' );
+  }
+}
+
+/**
+ * Recursive stripslashes()
+ * @param array
+ * @return array
+ */
+ 
+function stripslashes_recurse($arr)
+{
+  foreach($arr as $k => $xxxx)
+  {
+    $val =& $arr[$k];
+    if(is_string($val))
+      $val = stripslashes($val);
+    elseif(is_array($val))
+      $val = stripslashes_recurse($val);
+  }
+  return $arr;
+}
+
+/**
+ * If magic_quotes_gpc is on, calls stripslashes() on everything in $_GET/$_POST/$_COOKIE
+ * @ignore - this doesn't work
+ * @todo port version from the PHP manual
+ * @return void
+ */
+function strip_magic_quotes_gpc()
+{
+  if(enano_get_magic_quotes_gpc())
+  {
+    $_POST   = stripslashes_recurse($_POST);
+    $_GET    = stripslashes_recurse($_GET);
+    $_COOKIE = stripslashes_recurse($_COOKIE);
+  }
+}
+
+/**
+ * A very basic single-character compression algorithm for binary strings/bitfields
+ * @param string $bits the text to compress
+ * @return string
+ */
+ 
+function compress_bitfield($bits)
+{
+  $crc32 = crc32($bits);
+  $bits .= '0';
+  $start_pos = 0;
+  $current = substr($bits, 1, 1);
+  $last    = substr($bits, 0, 1);
+  $chunk_size = 1;
+  $len = strlen($bits);
+  $crc = $len;
+  $crcval = 0;
+  for ( $i = 1; $i < $len; $i++ )
+  {
+    $current = substr($bits, $i, 1);
+    $last    = substr($bits, $i - 1, 1);
+    $next    = substr($bits, $i + 1, 1);
+    // Are we on the last character?
+    if($current == $last && $i+1 < $len)
+      $chunk_size++;
+    else
+    {
+      if($i+1 == $len && $current == $next)
+      {
+        // This character completes a chunk
+        $chunk_size++;
+        $i++;
+        $chunk = substr($bits, $start_pos, $chunk_size);
+        $chunklen = strlen($chunk);
+        $newchunk = $last . '[' . $chunklen . ']';
+        $newlen   = strlen($newchunk);
+        $bits = substr($bits, 0, $start_pos) . $newchunk . substr($bits, $i, $len);
+        $chunk_size = 1;
+        $i = $start_pos + $newlen;
+        $start_pos = $i;
+        $len = strlen($bits);
+        $crcval = $crcval + $chunklen;
+      }
+      else
+      {
+        // Last character completed a chunk
+        $chunk = substr($bits, $start_pos, $chunk_size);
+        $chunklen = strlen($chunk);
+        $newchunk = $last . '[' . $chunklen . '],';
+        $newlen   = strlen($newchunk);
+        $bits = substr($bits, 0, $start_pos) . $newchunk . substr($bits, $i, $len);
+        $chunk_size = 1;
+        $i = $start_pos + $newlen;
+        $start_pos = $i;
+        $len = strlen($bits);
+        $crcval = $crcval + $chunklen;
+      }
+    }
+  }
+  if($crc != $crcval)
+  {
+    echo __FUNCTION__.'(): ERROR: length check failed, this is a bug in the algorithm<br />Debug info: aiming for a CRC val of '.$crc.', got '.$crcval;
+    return false;
+  }
+  $compressed = 'cbf:len='.$crc.';crc='.dechex($crc32).';data='.$bits.'|end';
+  return $compressed;
+}
+
+/**
+ * Uncompresses a bitfield compressed with compress_bitfield()
+ * @param string $bits the compressed bitfield
+ * @return string the uncompressed, original (we hope) bitfield OR bool false on error
+ */
+ 
+function uncompress_bitfield($bits)
+{
+  if(substr($bits, 0, 4) != 'cbf:')
+  {
+    echo __FUNCTION__.'(): ERROR: Invalid stream';
+    return false;
+  }
+  $len = intval(substr($bits, strpos($bits, 'len=')+4, strpos($bits, ';')-strpos($bits, 'len=')-4));
+  $crc = substr($bits, strpos($bits, 'crc=')+4, 8);
+  $data = substr($bits, strpos($bits, 'data=')+5, strpos($bits, '|end')-strpos($bits, 'data=')-5);
+  $data = explode(',', $data);
+  foreach($data as $a => $b)
+  {
+    $d =& $data[$a];
+    $char = substr($d, 0, 1);
+    $dlen = intval(substr($d, 2, strlen($d)-1));
+    $s = '';
+    for($i=0;$i<$dlen;$i++,$s.=$char);
+    $d = $s;
+    unset($s, $dlen, $char);
+  }
+  $decompressed = implode('', $data);
+  $decompressed = substr($decompressed, 0, -1);
+  $dcrc = (string)dechex(crc32($decompressed));
+  if($dcrc != $crc)
+  {
+    echo __FUNCTION__.'(): ERROR: CRC check failed<br />debug info:<br />original crc: '.$crc.'<br />decomp\'ed crc: '.$dcrc.'<br />';
+    return false;
+  }
+  return $decompressed;
+}
+
+/**
+ * Exports a MySQL table into a SQL string.
+ * @param string $table The name of the table to export
+ * @param bool $structure If true, include a CREATE TABLE command
+ * @param bool $data If true, include the contents of the table
+ * @param bool $compact If true, omits newlines between parts of SQL statements, use in Enano database exporter
+ * @return string
+ */
+
+function export_table($table, $structure = true, $data = true, $compact = false)
+{
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  $struct_keys = '';
+  $divider   = (!$compact) ? "\n" : "\n";
+  $spacer1   = (!$compact) ? "\n" : " ";
+  $spacer2   = (!$compact) ? "  " : " ";
+  $rowspacer = (!$compact) ? "\n  " : " ";
+  $index_list = Array();
+  $cols = $db->sql_query('SHOW COLUMNS IN '.$table.';');
+  if(!$cols)
+  {
+    echo 'export_table(): Error getting column list: '.$db->get_error_text().'<br />';
+    return false;
+  }
+  $col = Array();
+  $sqlcol = Array();
+  $collist = Array();
+  $pri_keys = Array();
+  // Using fetchrow_num() here to compensate for MySQL l10n
+  while( $row = $db->fetchrow_num() )
+  {
+    $field =& $row[0];
+    $type  =& $row[1];
+    $null  =& $row[2];
+    $key   =& $row[3];
+    $def   =& $row[4];
+    $extra =& $row[5];
+    $col[] = Array(
+      'name'=>$field,
+      'type'=>$type,
+      'null'=>$null,
+      'key'=>$key,
+      'default'=>$def,
+      'extra'=>$extra,
+      );
+    $collist[] = $field;
+  }
+  
+  if ( $structure )
+  {
+    $db->sql_query('SET SQL_QUOTE_SHOW_CREATE = 0;');
+    $struct = $db->sql_query('SHOW CREATE TABLE '.$table.';');
+    if ( !$struct )
+      $db->_die();
+    $row = $db->fetchrow_num();
+    $db->free_result();
+    $struct = $row[1];
+    $struct = preg_replace("/\n\) ENGINE=(.+)$/", "\n);", $struct);
+    unset($row);
+    if ( $compact )
+    {
+      $struct_arr = explode("\n", $struct);
+      foreach ( $struct_arr as $i => $leg )
+      {
+        if ( $i == 0 )
+          continue;
+        $test = trim($leg);
+        if ( empty($test) )
+        {
+          unset($struct_arr[$i]);
+          continue;
+        }
+        $struct_arr[$i] = preg_replace('/^([\s]*)/', ' ', $leg);
+      }
+      $struct = implode("", $struct_arr);
+    }
+  }
+  
+  // Structuring complete
+  if($data)
+  {
+    $datq = $db->sql_query('SELECT * FROM '.$table.';');
+    if(!$datq)
+    {
+      echo 'export_table(): Error getting column list: '.$db->get_error_text().'<br />';
+      return false;
+    }
+    if($db->numrows() < 1)
+    {
+      if($structure) return $struct;
+      else return '';
+    }
+    $rowdata = Array();
+    $dataqs = Array();
+    $insert_strings = Array();
+    $z = false;
+    while($row = $db->fetchrow_num())
+    {
+      $z = false;
+      foreach($row as $i => $cell)
+      {
+        $str = mysql_encode_column($cell, $col[$i]['type']);
+        $rowdata[] = $str;
+      }
+      $dataqs2 = implode(",$rowspacer", $dataqs) . ",$rowspacer" . '( ' . implode(', ', $rowdata) . ' )';
+      $ins = 'INSERT INTO '.$table.'( '.implode(',', $collist).' ) VALUES' . $dataqs2 . ";";
+      if ( strlen( $ins ) > MYSQL_MAX_PACKET_SIZE )
+      {
+        // We've exceeded the maximum allowed packet size for MySQL - separate this into a different query
+        $insert_strings[] = 'INSERT INTO '.$table.'( '.implode(',', $collist).' ) VALUES' . implode(",$rowspacer", $dataqs) . ";";;
+        $dataqs = Array('( ' . implode(', ', $rowdata) . ' )');
+        $z = true;
+      }
+      else
+      {
+        $dataqs[] = '( ' . implode(', ', $rowdata) . ' )';
+      }
+      $rowdata = Array();
+    }
+    if ( !$z )
+    {
+      $insert_strings[] = 'INSERT INTO '.$table.'( '.implode(',', $collist).' ) VALUES' . implode(",$rowspacer", $dataqs) . ";";;
+      $dataqs = Array();
+    }
+    $datstring = implode($divider, $insert_strings);
+  }
+  if($structure && !$data) return $struct;
+  elseif(!$structure && $data) return $datstring;
+  elseif($structure && $data) return $struct . $divider . $datstring;
+  elseif(!$structure && !$data) return '';
+}
+
+/**
+ * Encodes a string value for use in an INSERT statement for given column type $type.
+ * @access private
+ */
+ 
+function mysql_encode_column($input, $type)
+{
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  // Decide whether to quote the string or not
+  if(substr($type, 0, 7) == 'varchar' || $type == 'datetime' || $type == 'text' || $type == 'tinytext' || $type == 'smalltext' || $type == 'longtext' || substr($type, 0, 4) == 'char')
+  {
+    $str = "'" . $db->escape($input) . "'";
+  }
+  elseif(in_array($type, Array('blob', 'longblob', 'mediumblob', 'smallblob')) || substr($type, 0, 6) == 'binary' || substr($type, 0, 9) == 'varbinary')
+  {
+    $str = '0x' . hexencode($input, '', '');
+  }
+  elseif(is_null($input))
+  {
+    $str = 'NULL';
+  }
+  else
+  {
+    $str = (string)$input;
+  }
+  return $str;
+}
+
+/**
+ * Creates an associative array defining which file extensions are allowed and which ones aren't
+ * @return array keyname will be a file extension, value will be true or false
+ */
+
+function fetch_allowed_extensions()
+{
+  global $mime_types;
+  $bits = getConfig('allowed_mime_types');
+  if(!$bits) return Array(false);
+  $bits = uncompress_bitfield($bits);
+  if(!$bits) return Array(false);
+  $bits = enano_str_split($bits, 1);
+  $ret = Array();
+  $mt = array_keys($mime_types);
+  foreach($bits as $i => $b)
+  {
+    $ret[$mt[$i]] = ( $b == '1' ) ? true : false;
+  }
+  return $ret;
+}
+
+/**
+ * Generates a random key suitable for encryption
+ * @param int $len the length of the key
+ * @return string a BINARY key
+ */
+
+function randkey($len = 32)
+{
+  $key = '';
+  for($i=0;$i<$len;$i++)
+  {
+    $key .= chr(mt_rand(0, 255));
+  }
+  return $key;
+}
+
+/**
+ * Decodes a hex string.
+ * @param string $hex The hex code to decode
+ * @return string
+ */
+
+function hexdecode($hex)
+{
+  $hex = enano_str_split($hex, 2);
+  $bin_key = '';
+  foreach($hex as $nibble)
+  {
+    $byte = chr(hexdec($nibble));
+    $bin_key .= $byte;
+  }
+  return $bin_key;
+}
+
+/**
+ * Enano's own (almost) bulletproof HTML sanitizer.
+ * @param string $html The input HTML
+ * @return string cleaned HTML
+ */
+
+function sanitize_html($html, $filter_php = true)
+{
+  
+  $html = preg_replace('#<([a-z]+)([\s]+)([^>]+?)'.htmlalternatives('javascript:').'(.+?)>(.*?)</\\1>#is', '&lt;\\1\\2\\3javascript:\\59&gt;\\60&lt;/\\1&gt;', $html);
+  $html = preg_replace('#<([a-z]+)([\s]+)([^>]+?)'.htmlalternatives('javascript:').'(.+?)>#is', '&lt;\\1\\2\\3javascript:\\59&gt;', $html);
+  
+  if($filter_php)
+    $html = str_replace(
+      Array('<?php',    '<?',    '<%',    '?>',    '%>'),
+      Array('&lt;?php', '&lt;?', '&lt;%', '?&gt;', '%&gt;'),
+      $html);
+  
+  $tag_whitelist = array_keys ( setupAttributeWhitelist() );
+  if ( !$filter_php )
+    $tag_whitelist[] = '?php';
+  $len = strlen($html);
+  $in_quote = false;
+  $quote_char = '';
+  $tag_start = 0;
+  $tag_name = '';
+  $in_tag = false;
+  $trk_name = false;
+  for ( $i = 0; $i < $len; $i++ )
+  {
+    $chr = $html{$i};
+    $prev = ( $i == 0 ) ? '' : $html{ $i - 1 };
+    $next = ( ( $i + 1 ) == $len ) ? '' : $html { $i + 1 };
+    if ( $in_quote && $in_tag )
+    {
+      if ( $quote_char == $chr && $prev != '\\' )
+        $in_quote = false;
+    }
+    elseif ( ( $chr == '"' || $chr == "'" ) && $prev != '\\' && $in_tag )
+    {
+      $in_quote = true;
+      $quote_char = $chr;
+    }
+    if ( $chr == '<' && !$in_tag && $next != '/' )
+    {                                          
+      // start of a tag
+      $tag_start = $i;
+      $in_tag = true;
+      $trk_name = true;
+    }
+    elseif ( !$in_quote && $in_tag && $chr == '>' )
+    {
+      $full_tag = substr($html, $tag_start, ( $i - $tag_start ) + 1 );
+      $l = strlen($tag_name) + 2;
+      $attribs_only = trim( substr($full_tag, $l, ( strlen($full_tag) - $l - 1 ) ) );
+      
+      // Debugging message
+      // echo htmlspecialchars($full_tag) . '<br />';
+      
+      if ( !in_array($tag_name, $tag_whitelist) )
+      {
+        // Illegal tag
+        //echo $tag_name . ' ';
+        
+        $s = ( empty($attribs_only) ) ? '' : ' ';
+        
+        $sanitized = '&lt;' . $tag_name . $s . $attribs_only . '&gt;';
+        
+        $html = substr($html, 0, $tag_start) . $sanitized . substr($html, $i + 1);
+        $html = str_replace('</' . $tag_name . '>', '&lt;/' . $tag_name . '&gt;', $html);
+        $new_i = $tag_start + strlen($sanitized);
+        
+        $len = strlen($html);
+        $i = $new_i;
+        
+        $in_tag = false;
+        $tag_name = '';
+        continue;
+      }
+      else
+      {
+        if ( $tag_name == '?php' && !$filter_php )
+          continue;
+        $f = fixTagAttributes( $attribs_only, $tag_name );
+        $s = ( empty($f) ) ? '' : ' ';
+        
+        $sanitized = '<' . $tag_name . $f . '>';
+        $new_i = $tag_start + strlen($sanitized);
+        
+        $html = substr($html, 0, $tag_start) . $sanitized . substr($html, $i + 1);
+        $len = strlen($html);
+        $i = $new_i;
+        
+        $in_tag = false;
+        $tag_name = '';
+        continue;
+      }
+    }
+    elseif ( $in_tag && $trk_name )
+    {
+      $is_alphabetical = ( strtolower($chr) != strtoupper($chr) || in_array($chr, array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9')) || $chr == '?' );
+      if ( $is_alphabetical )
+        $tag_name .= $chr;
+      else
+      {
+        $trk_name = false;
+      }
+    }
+    
+  }
+  
+  return $html;
+  
+}
+
+function htmlalternatives($string)
+{
+  $ret = '';
+  for ( $i = 0; $i < strlen($string); $i++ )
+  {
+    $chr = $string{$i};
+    $ch1 = ord($chr);
+    $ch2 = dechex($ch1);
+    $byte = '(&\\#([0]*){0,7}' . $ch1 . ';|\\\\([0]*){0,7}' . $ch1 . ';|\\\\([0]*){0,7}' . $ch2 . ';|&\\#x([0]*){0,7}' . $ch2 . ';|%([0]*){0,7}' . $ch2 . '|' . preg_quote($chr) . ')';
+    $ret .= $byte;
+    $ret .= '([\s]){0,2}';
+  }
+  return $ret;
+}
+
+/**
+ * Paginates (breaks into multiple pages) a MySQL result resource, which is treated as unbuffered.
+ * @param resource The MySQL result resource. This should preferably be an unbuffered query.
+ * @param string A template, with variables being named after the column name
+ * @param int The number of total results. This should be determined by a second query.
+ * @param string sprintf-style formatting string for URLs for result pages. First parameter will be start offset.
+ * @param int Optional. Start offset in individual results. Defaults to 0.
+ * @param int Optional. The number of results per page. Defualts to 10.
+ * @param int Optional. An associative array of functions to call, with key names being column names, and values being function names. Values can also be an array with key 0 being either an object or a string(class name) and key 1 being a [static] method.
+ * @param string Optional. The text to be sent before the result list, only if there are any results. Possibly the start of a table.
+ * @param string Optional. The text to be sent after the result list, only if there are any results. Possibly the end of a table.
+ * @return string
+ */
+
+function paginate($q, $tpl_text, $num_results, $result_url, $start = 0, $perpage = 10, $callers = Array(), $header = '', $footer = '')
+{
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  $parser = $template->makeParserText($tpl_text);
+  $num_pages = ceil ( $num_results / $perpage );
+  $out = '';
+  $i = 0;
+  $this_page = ceil ( $start / $perpage );
+  
+  // Build paginator
+  $begin = '<div class="tblholder" style="display: table; margin: 10px 0 0 auto;">
+    <table border="0" cellspacing="1" cellpadding="4">
+      <tr><th>Page:</th>';
+  $block = '<td class="row1" style="text-align: center;">{LINK}</td>';
+  $end = '</tr></table></div>';
+  $blk = $template->makeParserText($block);
+  $inner = '';
+  $cls = 'row2';
+  if ( $num_pages < 5 )
+  {
+    for ( $i = 0; $i < $num_pages; $i++ )
+    {
+      $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
+      $offset = strval($i * $perpage);
+      $url = sprintf($result_url, $offset);
+      $j = $i + 1;
+      $link = ( $offset == strval($start) ) ? "<b>$j</b>" : "<a href=".'"'."$url".'"'." style='text-decoration: none;'>$j</a>";
+      $blk->assign_vars(array(
+        'CLASS'=>$cls,
+        'LINK'=>$link
+        ));
+      $inner .= $blk->run();
+    }
+  }
+  else
+  {
+    if ( $this_page + 5 > $num_pages )
+    {
+      $list = Array();
+      $tp = $this_page;
+      if ( $this_page + 0 == $num_pages ) $tp = $tp - 3;
+      if ( $this_page + 1 == $num_pages ) $tp = $tp - 2;
+      if ( $this_page + 2 == $num_pages ) $tp = $tp - 1;
+      for ( $i = $tp - 1; $i <= $tp + 1; $i++ )
+      {
+        $list[] = $i;
+      }
+    }
+    else
+    {
+      $list = Array();
+      $current = $this_page;
+      $lower = ( $current < 3 ) ? 1 : $current - 1;
+      for ( $i = 0; $i < 3; $i++ )
+      {
+        $list[] = $lower + $i;
+      }
+    }
+    $url = sprintf($result_url, '0');
+    $link = ( 0 == $start ) ? "<b>First</b>" : "<a href=".'"'."$url".'"'." style='text-decoration: none;'>&laquo; First</a>";
+    $blk->assign_vars(array(
+      'CLASS'=>$cls,
+      'LINK'=>$link
+      ));
+    $inner .= $blk->run();
+    
+    // if ( !in_array(1, $list) )
+    // {
+    //   $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
+    //   $blk->assign_vars(array('CLASS'=>$cls,'LINK'=>'...'));
+    //   $inner .= $blk->run();
+    // }
+    
+    foreach ( $list as $i )
+    {
+      if ( $i == $num_pages )
+        break;
+      $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
+      $offset = strval($i * $perpage);
+      $url = sprintf($result_url, $offset);
+      $j = $i + 1;
+      $link = ( $offset == strval($start) ) ? "<b>$j</b>" : "<a href=".'"'."$url".'"'." style='text-decoration: none;'>$j</a>";
+      $blk->assign_vars(array(
+        'CLASS'=>$cls,
+        'LINK'=>$link
+        ));
+      $inner .= $blk->run();
+    }
+    
+    $total = $num_pages * $perpage - $perpage;
+    
+    if ( $this_page < $num_pages )
+    {
+      // $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
+      // $blk->assign_vars(array('CLASS'=>$cls,'LINK'=>'...'));
+      // $inner .= $blk->run();
+    
+      $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
+      $offset = strval($total);
+      $url = sprintf($result_url, $offset);
+      $j = $i + 1;
+      $link = ( $offset == strval($start) ) ? "<b>Last</b>" : "<a href=".'"'."$url".'"'." style='text-decoration: none;'>Last &raquo;</a>";
+      $blk->assign_vars(array(
+        'CLASS'=>$cls,
+        'LINK'=>$link
+        ));
+      $inner .= $blk->run();
+    }
+    
+  }
+  
+  $inner .= '<td class="row2" style="cursor: pointer;" onclick="paginator_goto(this, '.$this_page.', '.$num_pages.', '.$perpage.', unescape(\'' . rawurlencode($result_url) . '\'));">&darr;</td>';
+  
+  $paginator = "\n$begin$inner$end\n";
+  $out .= $paginator;
+  
+  $cls = 'row2';
+  
+  if ( $row = $db->fetchrow($q) )
+  {
+    $i = 0;
+    $out .= $header;
+    do {
+      $i++;
+      if ( $i <= $start )
+      {
+        continue;
+      }
+      if ( ( $i - $start ) > $perpage )
+      {
+        break;
+      }
+      $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
+      foreach ( $row as $j => $val )
+      {
+        if ( isset($callers[$j]) )
+        {
+          $tmp = ( is_callable($callers[$j]) ) ? @call_user_func($callers[$j], $val, $row) : $v;
+          
+          if ( $tmp )
+          {
+            $row[$j] = $tmp;
+          }
+        }
+      }
+      $parser->assign_vars($row);
+      $parser->assign_vars(array('_css_class' => $cls));
+      $out .= $parser->run();
+    } while ( $row = $db->fetchrow($q) );
+    $out .= $footer;
+  }
+  
+  $out .= $paginator;
+  
+  return $out;
+}
+
+/**
+ * This is the same as paginate(), but it processes an array instead of a MySQL result resource.
+ * @param array The results. Each value is simply echoed.
+ * @param int The number of total results. This should be determined by a second query.
+ * @param string sprintf-style formatting string for URLs for result pages. First parameter will be start offset.
+ * @param int Optional. Start offset in individual results. Defaults to 0.
+ * @param int Optional. The number of results per page. Defualts to 10.
+ * @param string Optional. The text to be sent before the result list, only if there are any results. Possibly the start of a table.
+ * @param string Optional. The text to be sent after the result list, only if there are any results. Possibly the end of a table.
+ * @return string
+ */
+
+function paginate_array($q, $num_results, $result_url, $start = 0, $perpage = 10, $header = '', $footer = '')
+{
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  $parser = $template->makeParserText($tpl_text);
+  $num_pages = ceil ( $num_results / $perpage );
+  $out = '';
+  $i = 0;
+  $this_page = ceil ( $start / $perpage );
+  
+  // Build paginator
+  $begin = '<div class="tblholder" style="display: table; margin: 10px 0 0 auto;">
+    <table border="0" cellspacing="1" cellpadding="4">
+      <tr><th>Page:</th>';
+  $block = '<td class="row1" style="text-align: center;">{LINK}</td>';
+  $end = '</tr></table></div>';
+  $blk = $template->makeParserText($block);
+  $inner = '';
+  $cls = 'row2';
+  if ( $start > 0 )
+  {
+    $url = sprintf($result_url, abs($start - $perpage));
+    $link = "<a href=".'"'."$url".'"'." style='text-decoration: none;'>&laquo; Prev</a>";
+    $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
+    $blk->assign_vars(array(
+      'CLASS'=>$cls,
+      'LINK'=>$link
+      ));
+    $inner .= $blk->run();
+  }
+  if ( $num_pages < 5 )
+  {
+    for ( $i = 0; $i < $num_pages; $i++ )
+    {
+      $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
+      $offset = strval($i * $perpage);
+      $url = sprintf($result_url, $offset);
+      $j = $i + 1;
+      $link = ( $offset == strval($start) ) ? "<b>$j</b>" : "<a href=".'"'."$url".'"'." style='text-decoration: none;'>$j</a>";
+      $blk->assign_vars(array(
+        'CLASS'=>$cls,
+        'LINK'=>$link
+        ));
+      $inner .= $blk->run();
+    }
+  }
+  else
+  {
+    if ( $this_page + 5 > $num_pages )
+    {
+      $list = Array();
+      $tp = $this_page;
+      if ( $this_page + 0 == $num_pages ) $tp = $tp - 3;
+      if ( $this_page + 1 == $num_pages ) $tp = $tp - 2;
+      if ( $this_page + 2 == $num_pages ) $tp = $tp - 1;
+      for ( $i = $tp - 1; $i <= $tp + 1; $i++ )
+      {
+        $list[] = $i;
+      }
+    }
+    else
+    {
+      $list = Array();
+      $current = $this_page;
+      $lower = ( $current < 3 ) ? 1 : $current - 1;
+      for ( $i = 0; $i < 3; $i++ )
+      {
+        $list[] = $lower + $i;
+      }
+    }
+    $url = sprintf($result_url, '0');
+    $link = ( 0 == $start ) ? "<b>First</b>" : "<a href=".'"'."$url".'"'." style='text-decoration: none;'>&laquo; First</a>";
+    $blk->assign_vars(array(
+      'CLASS'=>$cls,
+      'LINK'=>$link
+      ));
+    $inner .= $blk->run();
+    
+    // if ( !in_array(1, $list) )
+    // {
+    //   $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
+    //   $blk->assign_vars(array('CLASS'=>$cls,'LINK'=>'...'));
+    //   $inner .= $blk->run();
+    // }
+    
+    foreach ( $list as $i )
+    {
+      if ( $i == $num_pages )
+        break;
+      $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
+      $offset = strval($i * $perpage);
+      $url = sprintf($result_url, $offset);
+      $j = $i + 1;
+      $link = ( $offset == strval($start) ) ? "<b>$j</b>" : "<a href=".'"'."$url".'"'." style='text-decoration: none;'>$j</a>";
+      $blk->assign_vars(array(
+        'CLASS'=>$cls,
+        'LINK'=>$link
+        ));
+      $inner .= $blk->run();
+    }
+    
+    $total = $num_pages * $perpage - $perpage;
+    
+    if ( $this_page < $num_pages )
+    {
+      // $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
+      // $blk->assign_vars(array('CLASS'=>$cls,'LINK'=>'...'));
+      // $inner .= $blk->run();
+    
+      $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
+      $offset = strval($total);
+      $url = sprintf($result_url, $offset);
+      $j = $i + 1;
+      $link = ( $offset == strval($start) ) ? "<b>Last</b>" : "<a href=".'"'."$url".'"'." style='text-decoration: none;'>Last &raquo;</a>";
+      $blk->assign_vars(array(
+        'CLASS'=>$cls,
+        'LINK'=>$link
+        ));
+      $inner .= $blk->run();
+    }
+    
+  }
+  
+  if ( $start < $total )
+  {
+    $url = sprintf($result_url, abs($start + $perpage));
+    $link = "<a href=".'"'."$url".'"'." style='text-decoration: none;'>Next &raquo;</a>";
+    $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
+    $blk->assign_vars(array(
+      'CLASS'=>$cls,
+      'LINK'=>$link
+      ));
+    $inner .= $blk->run();
+  }
+  
+  $inner .= '<td class="row2" style="cursor: pointer;" onclick="paginator_goto(this, '.$this_page.', '.$num_pages.', '.$perpage.', unescape(\'' . rawurlencode($result_url) . '\'));">&darr;</td>';
+  
+  $paginator = "\n$begin$inner$end\n";
+  if ( $total > 1 )
+    $out .= $paginator;
+  
+  $cls = 'row2';
+  
+  if ( sizeof($q) > 0 )
+  {
+    $i = 0;
+    $out .= $header;
+    foreach ( $q as $val ) {
+      $i++;
+      if ( $i <= $start )
+      {
+        continue;
+      }
+      if ( ( $i - $start ) > $perpage )
+      {
+        break;
+      }
+      $out .= $val;
+    }
+    $out .= $footer;
+  }
+  
+  if ( $total > 1 )
+    $out .= $paginator;
+  
+  return $out;
+}
+
+/** 
+ * Enano version of fputs for debugging
+ */
+
+function enano_fputs($socket, $data)
+{
+  // echo '<pre>' . htmlspecialchars($data) . '</pre>';
+  // flush();
+  // ob_flush();
+  // ob_end_flush();
+  return fputs($socket, $data);
+}
+
+/**
+ * Sanitizes a page URL string so that it can safely be stored in the database.
+ * @param string Page ID to sanitize
+ * @return string Cleaned text
+ */
+
+function sanitize_page_id($page_id)
+{
+  
+  // First, replace spaces with underscores  
+  $page_id = str_replace(' ', '_', $page_id);
+  
+  preg_match_all('/\.[A-Fa-f0-9][A-Fa-f0-9]/', $page_id, $matches);
+  
+  foreach ( $matches[0] as $id => $char )
+  {
+    $char = substr($char, 1);
+    $char = strtolower($char);
+    $char = intval(hexdec($char));
+    $char = chr($char);
+    $page_id = str_replace($matches[0][$id], $char, $page_id);
+  }
+  
+  $pid_clean = preg_replace('/[\w\/:;\(\)@\[\]_-]/', 'X', $page_id);
+  $pid_dirty = enano_str_split($pid_clean, 1);
+  
+  foreach ( $pid_dirty as $id => $char )
+  {
+    if ( $char == 'X' )
+      continue;
+    $cid = ord($char);
+    $cid = dechex($cid);
+    $cid = strval($cid);
+    if ( strlen($cid) < 2 )
+    {
+      $cid = strtoupper("0$cid");
+    }
+    $pid_dirty[$id] = ".$cid";
+  }
+  
+  $pid_chars = enano_str_split($page_id, 1);
+  $page_id_cleaned = '';
+  
+  foreach ( $pid_chars as $id => $char )
+  {
+    if ( $pid_dirty[$id] == 'X' )
+      $page_id_cleaned .= $char;
+    else
+      $page_id_cleaned .= $pid_dirty[$id];
+  }
+  
+  global $mime_types;
+          
+  $exts = array_keys($mime_types);
+  $exts = '(' . implode('|', $exts) . ')';
+  
+  $page_id_cleaned = preg_replace('/\.2e' . $exts . '$/', '.\\1', $page_id_cleaned);
+  
+  return $page_id_cleaned;
+}
+
+//die('<pre>Original:  01010101010100101010100101010101011010'."\nProcessed: ".uncompress_bitfield(compress_bitfield('01010101010100101010100101010101011010')).'</pre>');
+
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/graphs.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,937 @@
+<?php
+
+/*
+ * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
+ * Version 1.0 (Banshee)
+ * Copyright (C) 2006-2007 Dan Fuhry
+ *
+ * This program is Free Software; you can redistribute 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 details.
+ */
+
+// BarGraph for PHP
+// Source: http://www.phpclasses.org/browse/package/1567.html
+// License: PHP license, see licenses/phplic.html included with this package
+
+class GraphMaker {
+  /**
+   * GraphMaker::bar_width
+   * Width of bars
+   */
+  var $bar_width = 32;
+  /**
+   * GraphMaker::bar_height
+   * Height of bars
+   */
+  var $bar_height = 8;
+  /**
+   * GraphMaker::bar_data
+   * Data of all bars
+   */
+  var $bar_data = array('a' => 7, 'b' => 3, 'c' => 6, 'd' => 0, 'e' => 2);
+  /**
+   * GraphMaker::bar_padding
+   * Padding of bars
+   */
+  var $bar_padding = 5;
+  /**
+   * GraphMaker::bar_bordercolor
+   * Border color of bars
+   */
+  var $bar_bordercolor = array(39, 78, 120);
+  /**
+   * GraphMaker::bar_bgcolor
+   * Background color of bars
+   */
+  var $bar_bgcolor = array(69, 129, 194);
+  //---------------------------------------------
+  /**
+   * GraphMaker::graph_areaheight
+   * Height of graphic area
+   */
+  var $graph_areaheight = 100;
+  /**
+   * GraphMaker::graph_padding
+   * Paddings of graph
+   */
+  var $graph_padding = array('left' => 50, 'top' => 20, 'right'  => 20, 'bottom' => 20);
+  /**
+   * GraphMaker::graph_title
+   * Title text of graph
+   */
+  var $graph_title = "";
+  /**
+   * GraphMaker::graph_bgcolor
+   * Background color of graph
+   */
+  var $graph_bgcolor = array(255, 255, 255);
+  /**
+   * GraphMaker::graph_bgtransparent
+   * Boolean for background transparency
+   */
+  var $graph_bgtransparent = 0;
+  /**
+   * GraphMaker::graph_transparencylevel
+   * Transparency level (0=opaque, 127=transparent)
+   */
+  var $graph_transparencylevel = 0;
+  /**
+   * GraphMaker::graph_borderwidth
+   * Width of graph border
+   */
+  var $graph_borderwidth = 1;
+  /**
+   * GraphMaker::graph_bordercolor
+   * Border color of graph
+   */
+  var $graph_bordercolor = array(218, 218, 239);
+  /**
+   * GraphMaker::graph_titlecolor
+   * Color of title text of graph
+   */
+  var $graph_titlecolor = array(99, 88, 78);
+  //---------------------------------------------
+  /**
+   * GraphMaker::axis_step
+   * Scale step of axis
+   */
+  var $axis_step = 2;
+  /**
+   * GraphMaker::axis_bordercolor
+   * Border color of axis
+   */
+  var $axis_bordercolor = array(99, 88, 78);
+  /**
+   * GraphMaker::axis_bgcolor
+   * Background color of axis
+   */
+  var $axis_bgcolor = array(152, 137, 124);
+
+  /****************************************************************
+                              GRAPH
+  ****************************************************************/
+
+  /**
+   * GraphMaker::SetGraphAreaHeight()
+   * Sets graph height (not counting top and bottom margins)
+   **/
+  function SetGraphAreaHeight($height) {
+    if ($height > 0) $this->graph_areaheight = $height;
+  }
+
+  /**
+   * GraphMaker::SetGraphPadding()
+   * Sets graph padding (margins)
+   **/
+  function SetGraphPadding($left, $top, $right, $bottom) {
+    $this->graph_padding = array('left'   => (int) $left,
+                                 'top'    => (int) $top,
+                                 'right'  => (int) $right,
+                                 'bottom' => (int) $bottom);
+  }
+
+  /**
+   * GraphMaker::SetGraphTitle()
+   * Set title text
+   **/
+  function SetGraphTitle($title) {
+    $this->graph_title = $title;
+  }
+
+  /**
+   * GraphMaker::SetGraphBorderColor()
+   * Sets border color for graph
+   **/
+  function SetGraphBorderColor($red, $green, $blue) {
+    $this->graph_bordercolor = array($red, $green, $blue);
+  }
+
+  /**
+   * GraphMaker::SetGraphBorderWidth()
+   * Set width of border. 0 disables border
+   **/
+  function SetGraphBorderWidth($width = 0) {
+    $this->graph_borderwidth = $width;
+  }
+
+  /**
+   * GraphMaker::SetGraphBackgroundColor()
+   * Sets background color for graph
+   **/
+  function SetGraphBackgroundColor($red, $green, $blue) {
+    $this->graph_bgcolor = array($red, $green, $blue);
+  }
+
+  /**
+   * GraphMaker::SetGraphBackgroundTransparent()
+   * Sets background color for graph (and set it transparent)
+   **/
+  function SetGraphBackgroundTransparent($red, $green, $blue, $addtransparency = 1) {
+    $this->graph_bgcolor = array($red, $green, $blue);
+    $this->graph_bgtransparent = ($addtransparency ? 1 : 0);
+  }
+
+  /**
+   * GraphMaker::SetGraphTitleColor()
+   * Sets title color for graph
+   **/
+  function SetGraphTitleColor($red, $green, $blue) {
+    $this->graph_titlecolor = array($red, $green, $blue);
+  }
+
+  /**
+   * GraphMaker::SetGraphTransparency()
+   * Sets transparency for graph
+   **/
+  function SetGraphTransparency($percent) {
+    if ($percent < 0) $percent = 0;
+    elseif ($percent > 100) $percent = 127;
+    else $percent = $percent * 1.27;
+    $this->graph_transparencylevel = $percent;
+  }
+
+  /****************************************************************
+                               BAR
+  ****************************************************************/
+
+  /**
+   * GraphMaker::SetBarBorderColor()
+   * Sets border color for bars
+   **/
+  function SetBarBorderColor($red, $green, $blue) {
+    $this->bar_bordercolor = array($red, $green, $blue);
+  }
+
+  /**
+   * GraphMaker::SetBarBackgroundColor()
+   * Sets background color for bars
+   **/
+  function SetBarBackgroundColor($red, $green, $blue) {
+    $this->bar_bgcolor = array($red, $green, $blue);
+  }
+
+  /**
+   * GraphMaker::SetBarData()
+   * Sets data of graph (parameter should be an array with key
+   * being the name of the bar and the value the value of the bar.
+   **/
+  function SetBarData($data) {
+    if (is_array($data)) $this->bar_data = $data;
+  }
+
+  /**
+   * GraphMaker::SetBarDimensions()
+   * Sets with and height of each bar
+   **/
+  function SetBarDimensions($width, $height) {
+    if ($width > 0) $this->bar_width = $width;
+    if ($height > 0) $this->bar_height = $height;
+  }
+
+  /**
+   * GraphMaker::SetBarPadding()
+   * Sets padding (border) around each bar
+   **/
+  function SetBarPadding($padding) {
+    if ($padding > 0) $this->bar_padding = $padding;
+  }
+
+  /****************************************************************
+                               AXIS
+  ****************************************************************/
+
+  /**
+   * GraphMaker::SetAxisBorderColor()
+   * Sets border color for axis
+   **/
+  function SetAxisBorderColor($red, $green, $blue) {
+    $this->axis_bordercolor = array($red, $green, $blue);
+  }
+
+  /**
+   * GraphMaker::SetAxisBackgroundColor()
+   * Sets background color for axis
+   **/
+  function SetAxisBackgroundColor($red, $green, $blue) {
+    $this->axis_bgcolor = array($red, $green, $blue);
+  }
+
+  /**
+   * GraphMaker::SetAxisStep()
+   * Sets axis scale step
+   **/
+  function SetAxisStep($step) {
+    if ($step > 0) $this->axis_step = $step;
+  }
+
+  /**
+   * GraphMaker::GetFinalGraphDimensions()
+   * From the values already setted, it calculates image
+   * width and height
+   **/
+  function GetFinalGraphDimensions() {
+    $w = $this->graph_padding['left'] +
+         (count($this->bar_data) * ($this->bar_width + ($this->bar_padding * 2))) +
+         $this->graph_padding['right'];
+    $h = $this->graph_padding['top'] +
+         $this->graph_areaheight +
+         $this->graph_padding['bottom'];
+    return array($w, $h);
+  }
+
+  /**
+   * GraphMaker::LoadGraph()
+   * Loads definitions from a file
+   **/
+  function LoadGraph($path) {
+    if (($fp = @fopen($path, "r")) !== false) {
+      $content = "";
+      while (!feof($fp)) {              // I do not use filesize() here
+        $content .= fread($fp, 4096);   // because of remote files. If
+      }                                 // there is no problem with them
+      fclose($fp);                      // please let me know
+      $this->__LoadGraphDefinitions($content);
+      return true;
+    } else return false;
+  }
+
+  /**
+   * GraphMaker::DrawGraph()
+   * Draw all the graph: bg, axis, bars, text.. and output it
+   * Optional file parameter turns output to file, and bool on success
+   **/
+  function DrawGraph($file = "") {
+    list($w, $h) = $this->GetFinalGraphDimensions();
+    $this->graph_width = $w;
+    $this->graph_height = $h;
+
+    $this->im = imagecreatetruecolor($w, $h);
+    if ($this->graph_transparencylevel) {
+      imagealphablending($this->im, true);
+    }
+
+    $this->__PaintBackground();
+    $this->__DrawAxis();
+
+    $p = 0;
+    foreach ($this->bar_data as $name => $value) {
+      $p++;
+      $this->__DrawBarText($p, $name);
+      $this->__DrawBar($p, $value);
+    }
+
+    if (strlen($this->graph_title)) {
+      $this->__AllocateColor("im_graph_titlecolor",
+                             $this->graph_titlecolor,
+                             $this->graph_transparencylevel);
+      $this->__DrawText($this->graph_title,
+                        floor($this->graph_width / 2),
+                        $this->graph_borderwidth + 2,
+                        $this->im_graph_titlecolor,
+                        2,
+                        1);
+    }
+
+    if (strlen($file)) {
+      $ret = imagepng($this->im, $file);
+    } else {
+      header('Content-Type: image/png');
+      imagepng($this->im);
+      $ret = true;
+    }
+    imagedestroy($this->im);
+    return $ret;
+  }
+
+  /**
+   * GraphMaker::PaintBackground()
+   * Draw all the graph: bg, axis, bars, text.. and output it
+   * Optional file parameter turns output to file, and bool on success
+   **/
+  function __PaintBackground() {
+    $this->__AllocateColor("im_graph_bgcolor",
+                           $this->graph_bgcolor,
+                           0);
+    imagefilledrectangle($this->im,
+                         0,
+                         0,
+                         $this->graph_width,
+                         $this->graph_height,
+                         $this->im_graph_bgcolor);
+    if ($this->graph_bgtransparent) {
+      imagecolortransparent($this->im, $this->im_graph_bgcolor);
+    }
+    if ($this->graph_borderwidth) {
+      $this->__AllocateColor("im_graph_bordercolor",
+                             $this->graph_bordercolor,
+                             $this->graph_transparencylevel);
+      for ($i = 0; $i < $this->graph_borderwidth; $i++) {
+        imagerectangle($this->im,
+                       $i,
+                       $i,
+                       $this->graph_width - 1 - $i,
+                       $this->graph_height - 1 - $i,
+                       $this->im_graph_bordercolor);
+      }
+    }
+  }
+
+  /**
+   * GraphMaker::__DrawAxis()
+   * Draws all the axis stuff (and scale steps)
+   **/
+  function __DrawAxis() {
+    $this->__AllocateColor("im_axis_bordercolor",
+                           $this->axis_bordercolor,
+                           $this->graph_transparencylevel);
+    $this->__AllocateColor("im_axis_bgcolor",
+                           $this->axis_bgcolor,
+                           $this->graph_transparencylevel);
+    $this->__DrawPolygon($this->graph_padding['left'], $this->graph_height - $this->graph_padding['bottom'],
+                         $this->graph_padding['left'], $this->graph_padding['top'],
+                         $this->graph_padding['left'] + $this->bar_height - 1, $this->graph_padding['top'] - $this->bar_height + 1,
+                         $this->graph_padding['left'] + $this->bar_height - 1, $this->graph_height - $this->graph_padding['bottom'] - $this->bar_height + 1,
+                         $this->im_axis_bgcolor, true);
+    $this->__DrawPolygon($this->graph_padding['left'], $this->graph_height - $this->graph_padding['bottom'],
+                         $this->graph_padding['left'], $this->graph_padding['top'],
+                         $this->graph_padding['left'] + $this->bar_height - 1, $this->graph_padding['top'] - $this->bar_height + 1,
+                         $this->graph_padding['left'] + $this->bar_height - 1, $this->graph_height - $this->graph_padding['bottom'] - $this->bar_height + 1,
+                         $this->im_axis_bordercolor);
+
+    $this->__DrawPolygon($this->graph_padding['left'], $this->graph_height - $this->graph_padding['bottom'],
+                         $this->graph_padding['left'] + $this->bar_height - 1, $this->graph_height - $this->graph_padding['bottom'] - $this->bar_height + 1,
+                         $this->graph_width - $this->graph_padding['right'] + $this->bar_height - 1, $this->graph_height - $this->graph_padding['bottom'] - $this->bar_height + 1,
+                         $this->graph_width - $this->graph_padding['right'], $this->graph_height - $this->graph_padding['bottom'],
+                         $this->im_axis_bgcolor, true);
+    $this->__DrawPolygon($this->graph_padding['left'], $this->graph_height - $this->graph_padding['bottom'],
+                         $this->graph_padding['left'] + $this->bar_height - 1, $this->graph_height - $this->graph_padding['bottom'] - $this->bar_height + 1,
+                         $this->graph_width - $this->graph_padding['right'] + $this->bar_height - 1, $this->graph_height - $this->graph_padding['bottom'] - $this->bar_height + 1,
+                         $this->graph_width - $this->graph_padding['right'], $this->graph_height - $this->graph_padding['bottom'],
+                         $this->im_axis_bordercolor);
+
+    // draw lines that separate bars
+    $total_bars = count($this->bar_data);
+    for ($i = 1; $i < $total_bars; $i++) {
+      $offset = $this->graph_padding['left'] +
+                (($this->bar_width + ($this->bar_padding * 2)) * $i);
+      imageline($this->im,
+                $offset,
+                $this->graph_height - $this->graph_padding['bottom'],
+                $offset + $this->bar_height - 1,
+                $this->graph_height - $this->graph_padding['bottom'] - $this->bar_height + 1,
+                $this->im_axis_bordercolor);
+    }
+
+    // draw scale steps
+    $max_value = $this->__GetMaxGraphValue();
+    if (($max_value % 10) > 0) {
+      $max_value = $max_value + (10 - ($max_value % 10));
+    }
+    $this->axis_max = $max_value;
+    $y = 0;
+    $style = array($this->im_axis_bordercolor, $this->im_graph_bgcolor);
+    imagesetstyle($this->im, $style);
+    while ($y <= $max_value) {
+      if ($max_value == 0) { $max_value=1; } // corrected by Marcelo Trenkenchu
+      $offset = floor($this->graph_height - $this->graph_padding['bottom'] -
+                ($y * $this->graph_areaheight / $max_value));
+      imageline($this->im,
+                $this->graph_padding['left'],
+                $offset,
+                $this->graph_padding['left'] + $this->bar_height - 1,
+                $offset - $this->bar_height + 1,
+                $this->im_axis_bordercolor);
+      $this->__DrawText($y,
+                        $this->graph_padding['left'],
+                        $offset,
+                        $this->im_axis_bordercolor,
+                        1,
+                        2,
+                        1);
+      // gridline
+      if ($y > 0) {
+        imageline($this->im,
+                  $this->graph_padding['left'] + $this->bar_height,
+                  $offset - $this->bar_height + 1,
+                  $this->graph_width - $this->graph_padding['right'] + $this->bar_height - 1,
+                  $offset - $this->bar_height + 1,
+                  IMG_COLOR_STYLED);
+      }
+      $y += $this->axis_step;
+    }
+
+    imageline($this->im,
+              $this->graph_width - $this->graph_padding['right'] + $this->bar_height - 1,
+              $this->graph_padding['top'] - $this->bar_height + 1,
+              $this->graph_width - $this->graph_padding['right'] + $this->bar_height - 1,
+              $this->graph_height - $this->graph_padding['bottom'] - $this->bar_height,
+              IMG_COLOR_STYLED);
+  }
+
+  /**
+   * GraphMaker::__DrawText()
+   * Draws text on image with color, size and alignment options
+   **/
+  function __DrawText($text, $x, $y, $color, $size = 1, $align = 0, $valign = 0) {
+    /*
+     * Align: 0=left | 1=center | 2=right
+     */
+    if ($align == 1) $x -= floor(strlen($text) * imagefontwidth($size) / 2);
+    elseif ($align == 2) $x -= (strlen($text) * imagefontwidth($size));
+    if ($valign == 1) $y -= floor(imagefontheight($size) / 2);
+    elseif ($valign == 2) $y -= imagefontheight($size);
+    imagestring($this->im,
+                $size,
+                $x,
+                $y,
+                $text,
+                $color);
+  }
+
+  /**
+   * GraphMaker::__GetMaxGraphValue()
+   * Returns max bar value
+   **/
+  function __GetMaxGraphValue() {
+    $max_value = 0;
+    foreach ($this->bar_data as $name => $value) {
+      if ($value > $max_value) $max_value = $value;
+    }
+    return $max_value;
+  }
+
+  /**
+   * GraphMaker::__DrawBarText()
+   * Determines top and left to draw text to a choosen bar
+   **/
+  function __DrawBarText($bar, $text) {
+    $this->__DrawText($text,
+                      $this->graph_padding['left'] + (($this->bar_width + ($this->bar_padding * 2)) * ($bar - 0.5)),
+                      $this->graph_height - $this->graph_padding['bottom'] + 1,
+                      $this->axis_bordercolor,
+                      1,
+                      1);
+  }
+
+  /**
+   * GraphMaker::__DrawBar()
+   * Draws a choosen bar with it's value
+   **/
+  function __DrawBar($bar, $value) {
+    $x = $this->graph_padding['left'] +
+         (($this->bar_width + ($this->bar_padding * 2)) * ($bar - 1)) +
+         $this->bar_padding;
+    if ($this->axis_max == 0) { $this->axis_max = 1; } // corrected by Marcelo Trenkenchu
+    $y = $value * $this->graph_areaheight / $this->axis_max;
+    $this->____DrawBar($x,
+                       $this->graph_height - $this->graph_padding['bottom'] - $y,
+                       $x + $this->bar_width,
+                       $this->graph_height - $this->graph_padding['bottom']);
+  }
+
+  /**
+   * GraphMaker::____DrawBar()
+   * Draws the actual rectangles that form a bar
+   **/
+  function ____DrawBar($x1, $y1, $x2, $y2) {
+    $this->__AllocateColor("im_bar_bordercolor",
+                           $this->bar_bordercolor,
+                           $this->graph_transparencylevel);
+    $this->__AllocateColor("im_bar_bgcolor",
+                           $this->bar_bgcolor,
+                           $this->graph_transparencylevel);
+    $this->__DrawPolygon($x1,                         $y1,
+                         $x2,                         $y1,
+                         $x2,                         $y2,
+                         $x1,                         $y2,
+                         $this->im_bar_bgcolor,       true);
+    $this->__DrawPolygon($x1,                         $y1,
+                         $x2,                         $y1,
+                         $x2,                         $y2,
+                         $x1,                         $y2,
+                         $this->im_bar_bordercolor);
+    $this->__DrawPolygon($x1,                         $y1,
+                         $x2,                         $y1,
+                         $x2 + $this->bar_height - 1, $y1 - $this->bar_height + 1,
+                         $x1 + $this->bar_height - 1, $y1 - $this->bar_height + 1,
+                         $this->im_bar_bgcolor,       true);
+    $this->__DrawPolygon($x1,                         $y1,
+                         $x2,                         $y1,
+                         $x2 + $this->bar_height - 1, $y1 - $this->bar_height + 1,
+                         $x1 + $this->bar_height - 1, $y1 - $this->bar_height + 1,
+                         $this->im_bar_bordercolor);
+    $this->__DrawPolygon($x2,                         $y2,
+                         $x2,                         $y1,
+                         $x2 + $this->bar_height - 1, $y1 - $this->bar_height + 1,
+                         $x2 + $this->bar_height - 1, $y2 - $this->bar_height + 1,
+                         $this->im_bar_bgcolor,       true);
+    $this->__DrawPolygon($x2,                         $y2,
+                         $x2,                         $y1,
+                         $x2 + $this->bar_height - 1, $y1 - $this->bar_height + 1,
+                         $x2 + $this->bar_height - 1, $y2 - $this->bar_height + 1,
+                         $this->im_bar_bordercolor);
+  }
+
+  /**
+   * GraphMaker::__DrawPolygon()
+   * Draws a (filled) (ir)regular polygon
+   **/
+  function __DrawPolygon($x1, $y1, $x2, $y2, $x3, $y3, $x4, $y4, $color, $filled = false) {
+    if ($filled) {
+      imagefilledpolygon($this->im, array($x1, $y1, $x2, $y2, $x3, $y3, $x4, $y4), 4, $color);
+    } else {
+      imagepolygon($this->im, array($x1, $y1, $x2, $y2, $x3, $y3, $x4, $y4), 4, $color);
+    }
+  }
+
+  /**
+   * GraphMaker::__LoadGraphDefinitions()
+   * Loads definitions to a graph from text lines (normaly
+   * they come from a file). This function is called by
+   * GraphMaker::LoadGraph()
+   **/
+  function __LoadGraphDefinitions($text) {
+    $text = preg_split("/\r?\n/", $text);
+    $data = array();
+    $section = '';
+    for ($i = 0; $i < count($text); $i++) {
+      if (preg_match("/^\s*#/", $text[$i])) {
+        //ignore.. it's just a comment
+      } elseif (preg_match("/^\s*\}\s*/", $text[$i])) {
+        $section = '';
+      } elseif (preg_match("/^\s*(\w+)\s*\{\s*$/", $text[$i], $r)) {
+        $section = $r[1];
+      } else {
+        $p = strpos($text[$i], "=");
+        if ($p !== false) {
+          $data[$section][trim(substr($text[$i], 0, $p))] = trim(substr($text[$i], $p + 1));
+        }
+      }
+    }
+    if (is_array($data['graph'])) {
+      $this->__LoadGraphValues($data['graph']);
+    }
+    if (is_array($data['bar'])) {
+      $this->__LoadBarValues($data['bar']);
+    }
+    if (is_array($data['axis'])) {
+      $this->__LoadAxisValues($data['axis']);
+    }
+    if (is_array($data['data'])) {
+      $this->bar_data = $data['data'];
+    }
+  }
+
+  /**
+   * GraphMaker::__LoadGraphValues()
+   * Loads definitions to main graph settings
+   **/
+  function __LoadGraphValues($data) {
+    foreach ($data as $name => $value) {
+      $name = strtolower($name);
+      switch ($name) {
+        case 'background-color':
+          $this->__SetColorToValue("graph_bgcolor", $value);
+          break;
+        case 'border-color':
+          $this->__SetColorToValue("graph_bordercolor", $value);
+          break;
+        case 'title-color':
+          $this->__SetColorToValue("graph_titlecolor", $value);
+          break;
+        case 'background-transparent':
+          $this->graph_bgtransparent = ($value == 1 || $value == 'yes' ? 1 : 0);
+          break;
+        case 'transparency':
+          $this->SetGraphTransparency(str_replace('%', '', $value));
+          break;
+        case 'title':
+          $this->graph_title = $value;
+          break;
+        case 'border-width':
+          $this->graph_borderwidth = (int) $value;
+          break;
+        case 'area-height':
+          $this->graph_areaheight = (int) $value;
+          break;
+        default:
+          if (substr($name, 0, 8) == 'padding-' && strlen($name) > 8) {
+            $this->graph_padding[substr($name, 8)] = $value;
+          }
+      }
+    }
+  }
+
+  /**
+   * GraphMaker::__LoadBarValues()
+   * Loads definitions to bar settings
+   **/
+  function __LoadBarValues($data) {
+    foreach ($data as $name => $value) {
+      $name = strtolower($name);
+      switch ($name) {
+        case 'background-color':
+          $this->__SetColorToValue("bar_bgcolor", $value);
+          break;
+        case 'border-color':
+          $this->__SetColorToValue("bar_bordercolor", $value);
+          break;
+        case 'padding':
+          $this->bar_padding = $value;
+          break;
+        case 'width':
+          $this->bar_width = (int) $value;
+          break;
+        case 'height':
+          $this->bar_height = (int) $value;
+          break;
+      }
+    }
+  }
+
+  /**
+   * GraphMaker::__LoadAxisValues()
+   * Loads definitions to axis settings
+   **/
+  function __LoadAxisValues($data) {
+    foreach ($data as $name => $value) {
+      switch (strtolower($name)) {
+        case 'step':
+          $this->SetAxisStep($value);
+          break;
+        case 'background-color':
+          $this->__SetColorToValue("axis_bgcolor", $value);
+          break;
+        case 'border-color':
+          $this->__SetColorToValue("axis_bordercolor", $value);
+      }
+    }
+  }
+
+  /**
+   * GraphMaker::__SetColorToValue()
+   * Sets a color (rgb or in html format) to a variable
+   **/
+  function __SetColorToValue($varname, $color) {
+    if ($color[0] == "#") { // if it's hex (html format), change to rgb array
+      if (strlen($color) == 4) {
+        // if only 3 hex values (I assume it's a shade of grey: #ddd)
+        $color .= substr($color, -3);
+      }
+      $color = array(hexdec($color[1].$color[2]),
+                     hexdec($color[3].$color[4]),
+                     hexdec($color[5].$color[6]));
+    }
+    $this->$varname = $color;
+  }
+
+  function __AllocateColor($varname, $color, $alpha) {
+    $this->$varname = imagecolorallocatealpha($this->im,
+                                              $color[0],
+                                              $color[1],
+                                              $color[2],
+                                              $alpha);
+  }
+}
+
+// Graph Generator for PHP
+// Originally located at http://szewo.com/php/graph, but link was broken, so this file was retrieved from:
+// http://web.archive.org/web/20030130065944/szewo.com/php/graph/graph.class.php3.txt
+// License unknown
+
+class GraphMaker_compat {
+ var $_values;
+ var $_ShowLabels;
+ var $_ShowCounts;
+ var $_ShowCountsMode;
+
+ var $_BarWidth;
+ var $_GraphWidth;
+ var $_BarImg;
+ var $_BarBorderWidth;
+ var $_BarBorderColor;
+ var $_RowSortMode;
+ var $_TDClassHead;
+ var $_TDClassLabel;
+ var $_TDClassCount;
+ var $_GraphTitle;
+
+ function __construct() {
+  $this->_values = array();
+  $this->_ShowLabels = true;
+  $this->_BarWidth = 16;
+  $this->_GraphWidth = 360;
+  $this->_BarImg = "NULL";
+  $this->_BarBorderWidth = 0;
+  $this->_BarBorderColor = "red";
+  $this->_ShowCountsMode = 2;
+  $this->_RowSortMode = 1;
+  $this->_TDClassHead = "grphh";
+  $this->_TDClassLabel = "grph";
+  $this->_TDClassCount = "grphc";
+  $this->_GraphTitle="Graph title";
+ }
+ 
+ function GraphMaker_compat() {
+  $this->__construct();
+ }
+
+ function SetBarBorderWidth($width) {
+  $this->_BarBorderWidth = $width;
+ }
+ function SetBorderColor($color) {
+  $this->_BarBorderColor = $color;
+ }
+
+//  mode = 1 labels asc, 2 label desc
+ function SetSortMode($mode) {
+  switch ($mode) {
+   case 1:
+    asort($this->_values);
+    break;
+   case 2:
+    arsort($this->_values);
+    break;
+   default:
+    break;
+   }
+
+ }
+
+ function AddValue($labelName, $theValue) {
+  array_push($this->_values, array("label" => $labelName, "value" => $theValue));
+
+ }
+ function SetBarWidth($width) {
+  $this->_BarWidth = $width;
+ }
+ function SetBarImg($img) {
+  $this->_BarImg = $img;
+ }
+ function SetShowLabels($lables) {
+  $this->_ShowLabels = $labels;
+ }
+ function SetGraphWidth($width) {
+  $this->_GraphWidth = $width;
+ }
+ function SetGraphTitle($title) {
+  $this->_GraphTitle = $title;
+ }
+ //mode = percentage or counts
+ function SetShowCountsMode($mode) {
+  $this->_ShowCountsMode = $mode;
+ }
+ //mode = none(0) label(1) or count(2)
+ function SetRowSortMode($sortmode) {
+  $this->_RowSortMode = $sortmode;
+ }
+
+ function SetTDClassHead($class) {
+  $this->_TDClassHead = $class;
+ }
+ function SetTDClassLabel($class) {
+  $this->_TDClassLabel = $class;
+ }
+ function SetTDClassCount($class) {
+  $this->_TDClassCount = $class;
+ }
+ function GetMaxVal() {
+  $maxval = 0;
+  foreach($this->_values as $value) if($maxval<$value["value"]) $maxval = $value["value"];
+  return $maxval;
+ }
+ function BarGraphVert() {
+  $maxval = $this->GetMaxVal();
+  foreach($this->_values as $value) $sumval += $value["value"];
+  $this->SetSortMode($this->_RowSortMode);
+  echo "<table>";
+  if (strlen($this->_GraphTitle)>0)  echo "<tr><td colspan=".count($this->_values)." class=\"".$this->_TDClassHead."\">".$this->_GraphTitle."</td></tr>";
+   echo "<tr>";
+   foreach($this->_values as $value) {
+    echo "<td valign=bottom align=center>";
+    $height = $this->_BarWidth;
+    $width=ceil($value["value"]*$this->_GraphWidth/$maxval);
+    echo "<div ";
+    echo "  style=\"background-color: #666666; border: ".$this->_BarBorderWidth."px solid ".$this->_BarBorderColor."\"";
+    echo ">";
+    echo "</td>";
+   }
+   echo "</tr>";
+   if ($this->_ShowCountsMode>0) {
+   	echo "<tr>";
+    foreach($this->_values as $value) {
+     switch ($this->_ShowCountsMode) {
+     case 1:
+      $count = round(100*$value["value"]/$sumval)."%";
+      break;
+     case 2:
+      $count = $value["value"];
+      break;  /* Exit the switch and the while. */
+     default:
+      break;
+     }
+     echo "<td align=center class=".$this->_TDClassCount.">$count</td>";
+   	}
+	echo "</tr>";
+   }
+
+   if ($this->_ShowLabels) {
+    echo "<tr>";
+    foreach($this->_values as $value) {
+     echo "<td align=center class=".$this->_TDClassLabel;
+	 echo ">".$value["label"]."</td>";
+	}
+	echo "</tr>";
+   }	
+
+  echo "</table>";
+ }
+
+
+
+ function BarGraphHoriz() {
+  $maxval = $this->GetMaxVal();
+  foreach($this->_values as $value) $sumval += $value["value"];
+  $this->SetSortMode($this->_RowSortMode);
+  echo "<table border=0>";
+  if (strlen($this->_GraphTitle)>0)  {
+    echo "<tr><td ";
+   if ($this->_ShowCountsMode>0) echo " colspan=2";
+    echo " class=\"".$this->_TDClassHead."\">".$this->_GraphTitle."</TD></TR>";
+  }
+  foreach($this->_values as $value) {
+   if ($this->_ShowLabels) {
+    echo "<tr>";
+    echo "<td class=".$this->_TDClassLabel;
+    if ($this->_ShowCountsMode>0) echo " colspan=2";
+	echo ">".$value["label"]."</TD></TR>";
+   }	
+   echo "<tr>";
+   if ($this->_ShowCountsMode>0) {
+    switch ($this->_ShowCountsMode) {
+    case 1:
+     $count = round(100*$value["value"]/$sumval)."%";
+     break;
+    case 2:
+     $count = $value["value"];
+     break;  /* Exit the switch and the while. */
+    default:
+     break;
+    }
+   echo "<td class=".$this->_TDClassCount.">$count</TD>";
+   }
+   echo "<td>";
+   $height = $this->_BarWidth;
+    $width=ceil($value["value"]*$this->_GraphWidth/$maxval);
+   echo "<img SRC=\"".$this->_BarImg."\" height=$height width=$width ";
+   echo "  style=\"border: ".$this->_BarBorderWidth."px solid ".$this->_BarBorderColor."\"";
+   echo ">";
+   echo "</TD></TR>";
+  }
+  echo "</TABLE>";
+ }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/index.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,13 @@
+<?php
+
+$_GET['title'] = 'Enano:Access_denied';
+require('../includes/common.php');
+header('HTTP/1.1 403 Forbidden');
+$session->perms['edit_page'] = AUTH_DENY;
+$session->perms['view_source'] = AUTH_DENY;
+$template->tpl_strings['PAGE_NAME'] = 'Access denied';
+
+$template->header();
+echo '<p>The administrator has flagged the page "' . $_SERVER['REQUEST_URI'] . '" so that it cannot be accessed from the web. Perhaps this is because this is a cache or includes directory and only needs to be accessed by scripts.</p><p>HTTP error: 403 Forbidden</p>';
+$template->footer();
+$db->close();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/js-compressor.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,496 @@
+<?php
+
+/*
+ * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
+ * Version 1.0 (Banshee)
+ * Copyright (C) 2006-2007 Dan Fuhry
+ * Javascript compression library - used to compact the client-side Javascript code (all 72KB of it!) to save some bandwidth
+ *
+ * This program is Free Software; you can redistribute 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 details.
+ *
+ * This class was written by Andrea Giammarchi and was downloaded from PHPClasses.org. The information page stated that
+ * this class is licensed under the GNU General Public License, the terms of which can be found by reading the file
+ * "GPL" included with the Enano package.
+ */
+
+/**
+ * JavaScriptCompressor class,
+ *	removes comments or pack JavaScript source[s] code.
+ * ______________________________________________________________
+ * JavaScriptCompressor (just 2 public methods)
+ *    |
+ *    |________ getClean(jsSource:mixed):string
+ *    |         	returns one or more JavaScript code without comments,
+ *    |         	by default removes some spaces too
+ *    |
+ *    |________ getPacked(jsSource:mixed):string
+ *              	returns one or more JavaScript code packed,
+ *	        	using getClean and obfuscating output
+ * --------------------------------------------------------------
+ * Note about $jsSource input varible:
+ * 	this var should be a string (i.e. $jsSource = file_get_contents("myFile.js");)
+ *      should be an array of strings (i.e. array(file_get_contents("1.js"), file_get_contents("2.js"), ... ))
+ *      should be an array with 1 or 2 keys:
+ *      	(i.e. array('code'=>file_get_contents("mySource.js")))
+ *              (i.e. array('code'=>file_get_contents("mySource.js"), 'name'=>'mySource'))
+ *      ... and should be an array of arrays created with theese rules
+ *      array(
+ *		file_get_contents("secret.js"),
+ *              array('code'=>$anotherJS),
+ *              array('code'=>$myJSapplication, 'name'=>'JSApplication V 1.0')
+ *      )
+ *
+ *      The name used on dedicated key, will be write on parsed source header
+ * --------------------------------------------------------------
+ * Note about returned strings:
+ * 	Your browser should wrap very long strings, then don't use
+ *      cut and paste from your browser, save output into your database or directly
+ *      in a file or print them only inside <script> and </script> tags
+ * --------------------------------------------------------------
+ * Note about parser performance:
+ * 	With pure PHP embed code this class should be slow and not really safe
+ *      for your server performance then don't parse JavaScript runtime for each
+ *      file you need and create some "parsed" caching system
+ *      (at least while i've not created a compiled version of theese class functions).
+ *      Here there's a caching system example: http://www.phpclasses.org/browse/package/3158.html
+ * --------------------------------------------------------------
+ * Note about JavaScript packed compatibility:
+ * 	To be sure about compatibility include before every script JSL Library:
+ *      http://www.devpro.it/JSL/
+ * JSL library add some features for old or buggy browsers, one of
+ * those functions is String.replace with function as second argument,
+ * used by JavaScript generated packed code to rebuild original code.
+ *
+ * Remember that KDE 3.5, Safari and IE5 will not work correctly with packed version
+ * if you'll not include JSL.
+ * --------------------------------------------------------------
+ * @Compatibility	>= PHP 4
+ * @Author		Andrea Giammarchi
+ * @see       http://www.devpro.it/
+ * @since	    2006/05/31
+ * @since		  2006/08/01 [requires SourceMap.class.php to parse source faster and better (dojo.js.uncompressed.js file (211Kb) successfull cleaned or packed)]
+ * @version		0.8
+ * Dependencies:
+ *      Server: BaseConvert.class.php
+ *			Server: SourceMap.class.php
+ *			Client: JSL.js (http://www.devpro.it/JSL/)
+ * Convertion is supported by every browser with JSL Library (FF 1+ Opera 8+ and IE5.5+ are supported without JSL too)
+ * @copyright Dean Edwards for his originally idea [dean.edwards.name] and his JavaScript packer
+ */
+class JavaScriptCompressor {
+
+	/**
+	 * public variables
+         * 	stats:string		after every compression has some informations
+         *      version:string		version of this class
+	 */
+	var	$stats = '',
+		$version = '0.8';
+
+	/** 'private' variables, any comment sorry */
+	var	$__startTime = 0,
+		$__sourceLength = 0,
+		$__sourceNewLength = 0,
+		$__totalSources = 0,
+		$__sources = array(),
+		$__delimeter = array(),
+		$__cleanFinder = array("/(\n|\r)+/", "/( |\t)+/", "/(\n )|( \n)|( \n )/", "/[[:space:]]+(\)|})/", "/(\(|{)[[:space:]]+/", "/[[:space:]]*(;|,|:|<|>|\&|\||\=|\?|\+|\-|\%)[[:space:]]*/", "/\)[[:space:]]+{/", "/}[[:space:]]+\(/"),
+		$__cleanReplacer = array("\n", " ", "\n", "\\1", "\\1", "\\1", "){", "}("),
+		$__BC = null,
+		$__SourceMap = null;
+
+	/**
+	 * public constructor
+         * 	creates a new BaseConvert class variable (base 36)
+	 */
+	function JavaScriptCompressor() {
+		$this->__SourceMap = new SourceMap();
+		$this->__BC = new BaseConvert('0123456789abcdefghijklmnopqrstuvwxyz');
+		$this->__delimeter = array(
+			array('name'=>'doublequote', 'start'=>'"', 'end'=>'"', 'noslash'=>true),
+			array('name'=>'singlequote', 'start'=>"'", 'end'=>"'", 'noslash'=>true),
+			array('name'=>'singlelinecomment', 'start'=>'//', 'end'=>array("\n", "\r")),
+			array('name'=>'multilinecomment', 'start'=>'/*', 'end'=>'*/'),
+			array('name'=>'regexp', 'start'=>'/', 'end'=>'/', 'match'=>"/^\/[^\n\r]+\/$/", 'noslash'=>true)
+		);
+	}
+
+	/**
+	 * public method
+         * 	getClean(mixed [, bool]):string
+         *      compress JavaScript removing comments and somespaces (on by default)
+         * @param	mixed		view example and notes on class comments
+	 */
+	function getClean($jsSource) {
+		return $this->__commonInitMethods($jsSource, false);
+	}
+	
+	/**
+	 * public method
+         * 	getPacked(mixed):string
+         *      compress JavaScript replaceing words and removing comments and some spaces
+         * @param	mixed		view example and notes on class comments
+	 */
+	function getPacked($jsSource) {
+		return $this->__commonInitMethods($jsSource, true);
+	}
+	
+	/** 'private' methods, any comment sorry */
+	function __addCleanCode($str) {
+		return preg_replace($this->__cleanFinder, $this->__cleanReplacer, trim($str));
+	}
+	function __addClean(&$arr, &$str, &$start, &$end, $clean) {
+		if($clean)
+			array_push($arr, $this->__addCleanCode(substr($str, $start, $end - $start)));
+		else
+			array_push($arr, substr($str, $start, $end - $start));
+	}
+	function __clean(&$str) {
+		$len = strlen($str);
+		$type = '';
+		$clean = array();
+		$map = $this->__SourceMap->getMap($str, $this->__delimeter);
+		for($a = 0, $b = 0, $c = count($map); $a < $c; $a++) {
+			$type = &$map[$a]['name'];
+			switch($type) {
+				case 'code':
+				case 'regexp':
+				case 'doublequote':
+				case 'singlequote':
+					$this->__addClean($clean, $str, $map[$a]['start'], $map[$a]['end'], ($type === 'code'));
+					if($type !== 'regexp')
+						array_push($clean, "\n");	
+					break;
+			}
+ 		}
+		return preg_replace("/(\n)+/", "\n", trim(implode('', $clean)));
+	}
+	function __commonInitMethods(&$jsSource, $packed) { 
+		$header = '';
+		$this->__startTime = $this->__getTime();
+		$this->__sourceLength = 0;
+		$this->__sourceManager($jsSource);
+		for($a = 0, $b = $this->__totalSources; $a < $b; $a++)
+			$this->__sources[$a]['code'] = $this->__clean($this->__sources[$a]['code']);
+		$header = $this->__getHeader();
+		for($a = 0, $b = $this->__totalSources; $a < $b; $a++)
+			$this->__sources[$a] = &$this->__sources[$a]['code'];
+		$this->__sources = implode(';', $this->__sources);
+		if($packed)
+			$this->__sources = $this->__pack($this->__sources);
+		$this->__sourceNewLength = strlen($this->__sources);
+		$this->__setStats();
+		return $header.$this->__sources;
+	}
+	function __getHeader() {
+		return implode('', array(
+			'/* ',$this->__getScriptNames(),'JavaScriptCompressor ',$this->version,' [www.devpro.it], ',
+			'thanks to Dean Edwards for idea [dean.edwards.name]',
+			" */\r\n"		
+		));
+	}
+	function __getScriptNames() {
+		$a = 0;
+		$result = array();
+		for($b = $this->__totalSources; $a < $b; $a++) {
+			if($this->__sources[$a]['name'] !== '')
+				array_push($result, $this->__sources[$a]['name']);
+		}
+		$a = count($result);
+		if($a-- > 0)
+			$result[$a] .= ' with ';
+		return $a < 0 ? '' : implode(', ', $result);
+	}
+	function __getSize($size, $dec = 2) {
+		$toEval = '';
+		$type = array('bytes', 'Kb', 'Mb', 'Gb');
+		$nsize = $size;
+		$times = 0;
+		while($nsize > 1024) {
+			$nsize = $nsize / 1024;
+			$toEval .= '/1024';
+			$times++;
+		}
+		if($times === 0)
+			$fSize = $size.' '.$type[$times];
+		else {
+			eval('$size=($size'.$toEval.');');
+			$fSize =  number_format($size, $dec, '.', '').' '.$type[$times];
+		}
+		return $fSize;
+	}
+	function __getTime($startTime = null) {
+		list($usec, $sec) = explode(' ', microtime());
+		$newtime = (float)$usec + (float)$sec;
+		if($startTime !== null)
+			$newtime = number_format(($newtime - $startTime), 3);
+		return $newtime;
+	}
+	function __pack(&$str) {
+		$container = array();
+		$str = preg_replace("/(\w+)/e", '$this->__BC->toBase($this->__wordsParser("\\1",$container));', $this->__clean($str));
+		$str = str_replace("\n", '\n', addslashes($str));
+		return 'eval(function(A,G){return A.replace(/(\\w+)/g,function(a,b){return G[parseInt(b,36)]})}("'.$str.'","'.implode(',', $container).'".split(",")));';
+	}
+	function __setStats() {
+		$this->stats = implode(' ', array(
+			$this->__getSize($this->__sourceLength),
+			'to',
+			$this->__getSize($this->__sourceNewLength),
+			'in',
+			$this->__getTime($this->__startTime),
+			'seconds'
+		));
+	}
+	function __sourceManager(&$jsSource) {
+		$b = count($jsSource);
+		$this->__sources = array();
+		if(is_string($jsSource))
+			$this->__sourcePusher($jsSource, '');
+		elseif(is_array($jsSource) && $b > 0) {
+			if(isset($jsSource['code']))
+				$this->__sourcePusher($jsSource['code'], (isset($jsSource['name']) ? $jsSource['name'] : ''));
+			else {
+				for($a = 0; $a < $b; $a++) {
+					if(is_array($jsSource[$a]) && isset($jsSource[$a]['code'], $jsSource[$a]['name']))
+						$this->__sourcePusher($jsSource[$a]['code'], trim($jsSource[$a]['name']));
+					elseif(is_string($jsSource[$a]))
+						$this->__sourcePusher($jsSource[$a], '');
+				}
+			}
+		}
+		$this->__totalSources = count($this->__sources);
+	}
+	function __sourcePusher(&$code, $name) {
+		$this->__sourceLength += strlen($code);
+		array_push($this->__sources, array('code'=>$code, 'name'=>$name));
+	}
+	function __wordsParser($str, &$d) {
+		if(is_null($key = array_shift($key = array_keys($d,$str))))
+			$key = array_push($d, $str) - 1;
+		return $key;
+	}
+}
+
+/**
+ * BaseConvert class,
+ *	converts an unsigned base 10 integer to a different base and vice versa.
+ * ______________________________________________________________
+ * BaseConvert
+ *    |
+ *    |________ constructor(newBase:string)
+ *    |         	uses newBase string var for convertion
+ *    |                 [i.e. "0123456789abcdef" for an hex convertion]
+ *    |
+ *    |________ toBase(unsignedInteger:uint):string
+ *    |         	return base value of input
+ *    |
+ *    |________ fromBase(baseString:string):uint
+ *              	return base 10 integer value of base input
+ * --------------------------------------------------------------
+ * REMEMBER: PHP < 6 doesn't work correctly with integer greater than 2147483647 (2^31 - 1)
+ * --------------------------------------------------------------
+ * @Compatibility	>= PHP 4
+ * @Author		Andrea Giammarchi
+ * @Site		http://www.devpro.it/
+ * @Date		2006/06/05
+ * @Version		1.0
+ */
+
+class BaseConvert {
+	
+	var	$base, $baseLength;
+	
+	function BaseConvert($base) {
+		$this->base = &$base;
+		$this->baseLength = strlen($base);
+	}
+	
+	function toBase($num) {
+		$module = 0; $result = '';
+		while($num) {
+			$result = $this->base{($module = $num % $this->baseLength)}.$result;
+			$num = (int)(($num - $module) / $this->baseLength);
+		}
+		return $result !== '' ? $result : $this->base{0};
+	}
+	
+	function fromBase($str) {
+		$pos = 0; $len = strlen($str) - 1; $result = 0;
+		while($pos < $len)
+			$result += pow($this->baseLength, ($len - $pos)) * strpos($this->base, $str{($pos++)});
+		return $len >= 0 ? $result + strpos($this->base, $str{($pos)}) : null;
+	}
+}
+
+/**
+* SourceMap class,
+*    reads a generic language source code and returns its map.
+* ______________________________________________________________
+* The SourceMap goals is to create a map of a generic script/program language.
+* The getMap method returns an array/list of arrays/dictionary/objects
+* of source map using delimeters variable to map correctly:
+*  - multi line comments
+*  - single line comments
+*  - double quoted strings
+*  - single quoted strings
+*  - pure code
+*  - everything else (for example regexp [/re/] with javascript), just adding a correct delimeter
+* --------------------------------------------------------------
+* What about the delimeter
+*     It's an array/list of arrays/dictionary/obects with some properties to find what you're looking for.
+*
+* parameters are:
+*  - name, the name of the delimeter (i.e. "doublequote")
+*  - start, one or mode chars to find as start delimeter (i.e. " for double quoted string)
+*  - end, one or mode chars to find as end delimeter (i.e. " for double quoted string) [end should be an array/list too]
+*
+* optional parameters are:
+*  - noslash, if true find the end of the delimeter only if last char is not slashed (i.e. "string\"test" find " after test)
+*  - match, if choosed language has regexp, verify if string from start to end matches used regexp (i.e. /^\/[^\n\r]+\/$/ for JavaScript regexp)
+*
+* If end parameter is an array, match and noslash are not supported (i.e. ["\n", "\r"] for end delimeter of a single line comment)
+* --------------------------------------------------------------
+* What about SourceMap usage
+*     It should be a good solution to create sintax highlighter, parser,
+*     verifier or some other source code parsing procedure
+* --------------------------------------------------------------
+* What about SourceMap performance script/languages
+*     I've created different version of this class to test each script/program language performance too.
+* Python with or without Psyco is actually the faster parser.
+* However with this PHP version this class has mapped "dojo.js.uncompressed.js" file (about 211Kb) in less than 0.5 second.
+* Test has been done with embed class and PHP as module, any accelerator was used for this PHP test.
+* --------------------------------------------------------------
+* @Compatibility    >= PHP 4
+* @Author        Andrea Giammarchi
+* @Site        http://www.devpro.it/
+* @Date        2006/08/01
+* @LastMOd        2006/08/01
+* @Version        0.1
+* @Application        Last version of JavaScriptCompressor class use this one to map source code.
+*/
+class SourceMap {
+    
+    /**
+     * public method
+         *     getMap(&$source:string, &$delimeters:array):array
+     * Maps the source code using $delimeters rules and returns map as an array
+         * NOTE: read comments to know more about map and delimeter
+         *
+         * @param    string        generic source code
+         * @param    array        array with nested array with code rules
+     */
+    function getMap(&$source, &$delimeters) {
+        
+        # "unsigned" integer variables
+        $sourcePosition = 0;
+        $delimetersPosition = 0;
+        $findLength = 0;
+        $len = 0;
+        $tempIndex = 0;
+        $sourceLength = strlen($source);
+        $delimetersLength = count($delimeters);
+        
+        # integer variables
+        $tempPosition = -1;
+        $endPosition = -1;
+        
+        # array variables
+        $map = array();
+        $tempMap = array();
+        $tempDelimeter = array();
+        
+        while($sourcePosition < $sourceLength) {
+            $endPosition = -1;
+            for($delimetersPosition = 0; $delimetersPosition < $delimetersLength; $delimetersPosition++) {
+                $tempPosition = strpos($source, $delimeters[$delimetersPosition]['start'], $sourcePosition);
+                if($tempPosition !== false && ($tempPosition < $endPosition || $endPosition === -1)) {
+                    $endPosition = $tempPosition;
+                    $tempIndex = $delimetersPosition;
+                }
+            }
+            if($endPosition !== -1) {
+                $sourcePosition = $endPosition;
+                $tempDelimeter = &$delimeters[$tempIndex];
+                $findLength = strlen($tempDelimeter['start']);
+                if(is_array($tempDelimeter['end'])) {
+                    $delimetersPosition = 0;
+                    $endPosition = -1;
+                    for($len = count($tempDelimeter['end']); $delimetersPosition < $len; $delimetersPosition++) {
+                        $tempPosition = strpos($source, $tempDelimeter['end'][$delimetersPosition], $sourcePosition + $findLength);
+                        if($tempPosition !== false && ($tempPosition < $endPosition || $endPosition === -1)) {
+                            $endPosition = $tempPosition;
+                            $tempIndex = $delimetersPosition;
+                        }    
+                    }
+                    if($endPosition !== -1)
+                        $endPosition = $endPosition + strlen($tempDelimeter['end'][$tempIndex]);
+                    else
+                        $endPosition = $sourceLength;
+                    array_push($map, array('name'=>$tempDelimeter['name'], 'start'=>$sourcePosition, 'end'=>$endPosition));
+                    $sourcePosition = $endPosition - 1;
+                }
+                elseif(isset($tempDelimeter['match'])) {
+                    $tempPosition = strpos($source, $tempDelimeter['end'], $sourcePosition + $findLength);
+                    $len = strlen($tempDelimeter['end']);
+                    if($tempPosition !== false && preg_match($tempDelimeter['match'], substr($source, $sourcePosition, $tempPosition - $sourcePosition + $len))) {
+                        $endPosition = isset($tempDelimeter['noslash']) ? $this->__endCharNoSlash($source, $sourcePosition, $tempDelimeter['end'], $sourceLength) : $tempPosition + $len;
+                        array_push($map, array('name'=>$tempDelimeter['name'], 'start'=>$sourcePosition, 'end'=>$endPosition));
+                        $sourcePosition = $endPosition - 1;
+                    }
+                }
+                else {
+                    if(isset($tempDelimeter['noslash']))
+                        $endPosition = $this->__endCharNoSlash($source, $sourcePosition, $tempDelimeter['end'], $sourceLength);
+                    else {
+                        $tempPosition = strpos($source, $tempDelimeter['end'], $sourcePosition + $findLength);
+                        if($tempPosition !== false)
+                            $endPosition = $tempPosition + strlen($tempDelimeter['end']);
+                        else
+                            $endPosition = $sourceLength;
+                    }
+                    array_push($map, array('name'=>$tempDelimeter['name'], 'start'=>$sourcePosition, 'end'=>$endPosition));
+                    $sourcePosition = $endPosition - 1;
+                }
+            }
+            else
+                $sourcePosition = $sourceLength - 1;
+            ++$sourcePosition;
+        }
+        $len = count($map);
+        if($len === 0)
+            array_push($tempMap, array('name'=>'code', 'start'=>0, 'end'=>$sourceLength));
+        else {
+            for($tempIndex = 0; $tempIndex < $len; $tempIndex++) {
+                if($tempIndex === 0 && $map[$tempIndex]['start'] > 0)
+                    array_push($tempMap, array('name'=>'code', 'start'=>0, 'end'=>$map[$tempIndex]['start']));
+                elseif($tempIndex > 0 && $map[$tempIndex]['start'] > $map[$tempIndex-1]['end'])
+                    array_push($tempMap, array('name'=>'code', 'start'=>$map[$tempIndex-1]['end'], 'end'=>$map[$tempIndex]['start']));
+                array_push($tempMap, array('name'=>$map[$tempIndex]['name'], 'start'=>$map[$tempIndex]['start'], 'end'=>$map[$tempIndex]['end']));
+                if($tempIndex + 1 === $len && $map[$tempIndex]['end'] < $sourceLength)
+                    array_push($tempMap, array('name'=>'code', 'start'=>$map[$tempIndex]['end'], 'end'=>$sourceLength));
+            }
+        }
+        return $tempMap;
+    }
+    
+    function __endCharNoSlash(&$source, $position, &$find, &$len) {
+        $temp = strlen($find);
+        do {
+            $position = strpos($source, $find, $position + 1);
+        }while($position !== false && !$this->__charNoSlash($source, $position));
+        if($position === false) $position = $len - $temp;
+        return $position + $temp;
+    }
+    
+    function __charNoSlash(&$source, &$position) {
+        $next = 1; $len = $position - $next;
+        while($len > 0 && $source{$len} === '\\') $len = $position - (++$next);
+        return (($next - 1) % 2 === 0);
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/json.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,806 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+* Converts to and from JSON format.
+*
+* JSON (JavaScript Object Notation) is a lightweight data-interchange
+* format. It is easy for humans to read and write. It is easy for machines
+* to parse and generate. It is based on a subset of the JavaScript
+* Programming Language, Standard ECMA-262 3rd Edition - December 1999.
+* This feature can also be found in  Python. JSON is a text format that is
+* completely language independent but uses conventions that are familiar
+* to programmers of the C-family of languages, including C, C++, C#, Java,
+* JavaScript, Perl, TCL, and many others. These properties make JSON an
+* ideal data-interchange language.
+*
+* This package provides a simple encoder and decoder for JSON notation. It
+* is intended for use with client-side Javascript applications that make
+* use of HTTPRequest to perform server communication functions - data can
+* be encoded into JSON notation for use in a client-side javascript, or
+* decoded from incoming Javascript requests. JSON format is native to
+* Javascript, and can be directly eval()'ed with no further parsing
+* overhead
+*
+* All strings should be in ASCII or UTF-8 format!
+*
+* LICENSE: Redistribution and use in source and binary forms, with or
+* without modification, are permitted provided that the following
+* conditions are met: Redistributions of source code must retain the
+* above copyright notice, this list of conditions and the following
+* disclaimer. 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 ``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 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.
+*
+* @category
+* @package     Services_JSON
+* @author      Michal Migurski <mike-json@teczno.com>
+* @author      Matt Knapp <mdknapp[at]gmail[dot]com>
+* @author      Brett Stimmerman <brettstimmerman[at]gmail[dot]com>
+* @copyright   2005 Michal Migurski
+* @version     CVS: $Id: JSON.php,v 1.31 2006/06/28 05:54:17 migurski Exp $
+* @license     http://www.opensource.org/licenses/bsd-license.php
+* @link        http://pear.php.net/pepr/pepr-proposal-show.php?id=198
+*/
+
+/**
+* Marker constant for Services_JSON::decode(), used to flag stack state
+*/
+define('SERVICES_JSON_SLICE',   1);
+
+/**
+* Marker constant for Services_JSON::decode(), used to flag stack state
+*/
+define('SERVICES_JSON_IN_STR',  2);
+
+/**
+* Marker constant for Services_JSON::decode(), used to flag stack state
+*/
+define('SERVICES_JSON_IN_ARR',  3);
+
+/**
+* Marker constant for Services_JSON::decode(), used to flag stack state
+*/
+define('SERVICES_JSON_IN_OBJ',  4);
+
+/**
+* Marker constant for Services_JSON::decode(), used to flag stack state
+*/
+define('SERVICES_JSON_IN_CMT', 5);
+
+/**
+* Behavior switch for Services_JSON::decode()
+*/
+define('SERVICES_JSON_LOOSE_TYPE', 16);
+
+/**
+* Behavior switch for Services_JSON::decode()
+*/
+define('SERVICES_JSON_SUPPRESS_ERRORS', 32);
+
+/**
+ * Converts to and from JSON format.
+ *
+ * Brief example of use:
+ *
+ * <code>
+   // create a new instance of Services_JSON
+   $json = new Services_JSON();
+  
+   // convert a complexe value to JSON notation, and send it to the browser
+   $value = array('foo', 'bar', array(1, 2, 'baz'), array(3, array(4)));
+   $output = $json->encode($value);
+  
+   print($output);
+   // prints: ["foo","bar",[1,2,"baz"],[3,[4]]]
+  
+   // accept incoming POST data, assumed to be in JSON notation
+   $input = file_get_contents('php://input', 1000000);
+   $value = $json->decode($input);
+   </code>
+ */
+class Services_JSON
+{
+   /**
+    * constructs a new JSON instance
+    *
+    * @param    int     $use    object behavior flags; combine with boolean-OR
+    *
+    *                           possible values:
+    *                           - SERVICES_JSON_LOOSE_TYPE:  loose typing.
+    *                                   "{...}" syntax creates associative arrays
+    *                                   instead of objects in decode().
+    *                           - SERVICES_JSON_SUPPRESS_ERRORS:  error suppression.
+    *                                   Values which can't be encoded (e.g. resources)
+    *                                   appear as NULL instead of throwing errors.
+    *                                   By default, a deeply-nested resource will
+    *                                   bubble up with an error, so all return values
+    *                                   from encode() should be checked with isError()
+    */
+    function Services_JSON($use = 0)
+    {
+        $this->use = $use;
+    }
+
+   /**
+    * convert a string from one UTF-16 char to one UTF-8 char
+    *
+    * Normally should be handled by mb_convert_encoding, but
+    * provides a slower PHP-only method for installations
+    * that lack the multibye string extension.
+    *
+    * @param    string  $utf16  UTF-16 character
+    * @return   string  UTF-8 character
+    * @access   private
+    */
+    function utf162utf8($utf16)
+    {
+        // oh please oh please oh please oh please oh please
+        if(function_exists('mb_convert_encoding')) {
+            return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16');
+        }
+
+        $bytes = (ord($utf16{0}) << 8) | ord($utf16{1});
+
+        switch(true) {
+            case ((0x7F & $bytes) == $bytes):
+                // this case should never be reached, because we are in ASCII range
+                // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                return chr(0x7F & $bytes);
+
+            case (0x07FF & $bytes) == $bytes:
+                // return a 2-byte UTF-8 character
+                // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                return chr(0xC0 | (($bytes >> 6) & 0x1F))
+                     . chr(0x80 | ($bytes & 0x3F));
+
+            case (0xFFFF & $bytes) == $bytes:
+                // return a 3-byte UTF-8 character
+                // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                return chr(0xE0 | (($bytes >> 12) & 0x0F))
+                     . chr(0x80 | (($bytes >> 6) & 0x3F))
+                     . chr(0x80 | ($bytes & 0x3F));
+        }
+
+        // ignoring UTF-32 for now, sorry
+        return '';
+    }
+
+   /**
+    * convert a string from one UTF-8 char to one UTF-16 char
+    *
+    * Normally should be handled by mb_convert_encoding, but
+    * provides a slower PHP-only method for installations
+    * that lack the multibye string extension.
+    *
+    * @param    string  $utf8   UTF-8 character
+    * @return   string  UTF-16 character
+    * @access   private
+    */
+    function utf82utf16($utf8)
+    {
+        // oh please oh please oh please oh please oh please
+        if(function_exists('mb_convert_encoding')) {
+            return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
+        }
+
+        switch(strlen($utf8)) {
+            case 1:
+                // this case should never be reached, because we are in ASCII range
+                // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                return $utf8;
+
+            case 2:
+                // return a UTF-16 character from a 2-byte UTF-8 char
+                // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                return chr(0x07 & (ord($utf8{0}) >> 2))
+                     . chr((0xC0 & (ord($utf8{0}) << 6))
+                         | (0x3F & ord($utf8{1})));
+
+            case 3:
+                // return a UTF-16 character from a 3-byte UTF-8 char
+                // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                return chr((0xF0 & (ord($utf8{0}) << 4))
+                         | (0x0F & (ord($utf8{1}) >> 2)))
+                     . chr((0xC0 & (ord($utf8{1}) << 6))
+                         | (0x7F & ord($utf8{2})));
+        }
+
+        // ignoring UTF-32 for now, sorry
+        return '';
+    }
+
+   /**
+    * encodes an arbitrary variable into JSON format
+    *
+    * @param    mixed   $var    any number, boolean, string, array, or object to be encoded.
+    *                           see argument 1 to Services_JSON() above for array-parsing behavior.
+    *                           if var is a strng, note that encode() always expects it
+    *                           to be in ASCII or UTF-8 format!
+    *
+    * @return   mixed   JSON string representation of input var or an error if a problem occurs
+    * @access   public
+    */
+    function encode($var)
+    {
+        switch (gettype($var)) {
+            case 'boolean':
+                return $var ? 'true' : 'false';
+
+            case 'NULL':
+                return 'null';
+
+            case 'integer':
+                return (int) $var;
+
+            case 'double':
+            case 'float':
+                return (float) $var;
+
+            case 'string':
+                // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
+                $ascii = '';
+                $strlen_var = strlen($var);
+
+               /*
+                * Iterate over every character in the string,
+                * escaping with a slash or encoding to UTF-8 where necessary
+                */
+                for ($c = 0; $c < $strlen_var; ++$c) {
+
+                    $ord_var_c = ord($var{$c});
+
+                    switch (true) {
+                        case $ord_var_c == 0x08:
+                            $ascii .= '\b';
+                            break;
+                        case $ord_var_c == 0x09:
+                            $ascii .= '\t';
+                            break;
+                        case $ord_var_c == 0x0A:
+                            $ascii .= '\n';
+                            break;
+                        case $ord_var_c == 0x0C:
+                            $ascii .= '\f';
+                            break;
+                        case $ord_var_c == 0x0D:
+                            $ascii .= '\r';
+                            break;
+
+                        case $ord_var_c == 0x22:
+                        case $ord_var_c == 0x2F:
+                        case $ord_var_c == 0x5C:
+                            // double quote, slash, slosh
+                            $ascii .= '\\'.$var{$c};
+                            break;
+
+                        case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
+                            // characters U-00000000 - U-0000007F (same as ASCII)
+                            $ascii .= $var{$c};
+                            break;
+
+                        case (($ord_var_c & 0xE0) == 0xC0):
+                            // characters U-00000080 - U-000007FF, mask 110XXXXX
+                            // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                            $char = pack('C*', $ord_var_c, ord($var{$c + 1}));
+                            $c += 1;
+                            $utf16 = $this->utf82utf16($char);
+                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
+                            break;
+
+                        case (($ord_var_c & 0xF0) == 0xE0):
+                            // characters U-00000800 - U-0000FFFF, mask 1110XXXX
+                            // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                            $char = pack('C*', $ord_var_c,
+                                         ord($var{$c + 1}),
+                                         ord($var{$c + 2}));
+                            $c += 2;
+                            $utf16 = $this->utf82utf16($char);
+                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
+                            break;
+
+                        case (($ord_var_c & 0xF8) == 0xF0):
+                            // characters U-00010000 - U-001FFFFF, mask 11110XXX
+                            // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                            $char = pack('C*', $ord_var_c,
+                                         ord($var{$c + 1}),
+                                         ord($var{$c + 2}),
+                                         ord($var{$c + 3}));
+                            $c += 3;
+                            $utf16 = $this->utf82utf16($char);
+                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
+                            break;
+
+                        case (($ord_var_c & 0xFC) == 0xF8):
+                            // characters U-00200000 - U-03FFFFFF, mask 111110XX
+                            // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                            $char = pack('C*', $ord_var_c,
+                                         ord($var{$c + 1}),
+                                         ord($var{$c + 2}),
+                                         ord($var{$c + 3}),
+                                         ord($var{$c + 4}));
+                            $c += 4;
+                            $utf16 = $this->utf82utf16($char);
+                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
+                            break;
+
+                        case (($ord_var_c & 0xFE) == 0xFC):
+                            // characters U-04000000 - U-7FFFFFFF, mask 1111110X
+                            // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                            $char = pack('C*', $ord_var_c,
+                                         ord($var{$c + 1}),
+                                         ord($var{$c + 2}),
+                                         ord($var{$c + 3}),
+                                         ord($var{$c + 4}),
+                                         ord($var{$c + 5}));
+                            $c += 5;
+                            $utf16 = $this->utf82utf16($char);
+                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
+                            break;
+                    }
+                }
+
+                return '"'.$ascii.'"';
+
+            case 'array':
+               /*
+                * As per JSON spec if any array key is not an integer
+                * we must treat the the whole array as an object. We
+                * also try to catch a sparsely populated associative
+                * array with numeric keys here because some JS engines
+                * will create an array with empty indexes up to
+                * max_index which can cause memory issues and because
+                * the keys, which may be relevant, will be remapped
+                * otherwise.
+                *
+                * As per the ECMA and JSON specification an object may
+                * have any string as a property. Unfortunately due to
+                * a hole in the ECMA specification if the key is a
+                * ECMA reserved word or starts with a digit the
+                * parameter is only accessible using ECMAScript's
+                * bracket notation.
+                */
+
+                // treat as a JSON object
+                if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
+                    $properties = array_map(array($this, 'name_value'),
+                                            array_keys($var),
+                                            array_values($var));
+
+                    foreach($properties as $property) {
+                        if(Services_JSON::isError($property)) {
+                            return $property;
+                        }
+                    }
+
+                    return '{' . join(',', $properties) . '}';
+                }
+
+                // treat it like a regular array
+                $elements = array_map(array($this, 'encode'), $var);
+
+                foreach($elements as $element) {
+                    if(Services_JSON::isError($element)) {
+                        return $element;
+                    }
+                }
+
+                return '[' . join(',', $elements) . ']';
+
+            case 'object':
+                $vars = get_object_vars($var);
+
+                $properties = array_map(array($this, 'name_value'),
+                                        array_keys($vars),
+                                        array_values($vars));
+
+                foreach($properties as $property) {
+                    if(Services_JSON::isError($property)) {
+                        return $property;
+                    }
+                }
+
+                return '{' . join(',', $properties) . '}';
+
+            default:
+                return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS)
+                    ? 'null'
+                    : new Services_JSON_Error(gettype($var)." can not be encoded as JSON string");
+        }
+    }
+
+   /**
+    * array-walking function for use in generating JSON-formatted name-value pairs
+    *
+    * @param    string  $name   name of key to use
+    * @param    mixed   $value  reference to an array element to be encoded
+    *
+    * @return   string  JSON-formatted name-value pair, like '"name":value'
+    * @access   private
+    */
+    function name_value($name, $value)
+    {
+        $encoded_value = $this->encode($value);
+
+        if(Services_JSON::isError($encoded_value)) {
+            return $encoded_value;
+        }
+
+        return $this->encode(strval($name)) . ':' . $encoded_value;
+    }
+
+   /**
+    * reduce a string by removing leading and trailing comments and whitespace
+    *
+    * @param    $str    string      string value to strip of comments and whitespace
+    *
+    * @return   string  string value stripped of comments and whitespace
+    * @access   private
+    */
+    function reduce_string($str)
+    {
+        $str = preg_replace(array(
+
+                // eliminate single line comments in '// ...' form
+                '#^\s*//(.+)$#m',
+
+                // eliminate multi-line comments in '/* ... */' form, at start of string
+                '#^\s*/\*(.+)\*/#Us',
+
+                // eliminate multi-line comments in '/* ... */' form, at end of string
+                '#/\*(.+)\*/\s*$#Us'
+
+            ), '', $str);
+
+        // eliminate extraneous space
+        return trim($str);
+    }
+
+   /**
+    * decodes a JSON string into appropriate variable
+    *
+    * @param    string  $str    JSON-formatted string
+    *
+    * @return   mixed   number, boolean, string, array, or object
+    *                   corresponding to given JSON input string.
+    *                   See argument 1 to Services_JSON() above for object-output behavior.
+    *                   Note that decode() always returns strings
+    *                   in ASCII or UTF-8 format!
+    * @access   public
+    */
+    function decode($str)
+    {
+        $str = $this->reduce_string($str);
+
+        switch (strtolower($str)) {
+            case 'true':
+                return true;
+
+            case 'false':
+                return false;
+
+            case 'null':
+                return null;
+
+            default:
+                $m = array();
+
+                if (is_numeric($str)) {
+                    // Lookie-loo, it's a number
+
+                    // This would work on its own, but I'm trying to be
+                    // good about returning integers where appropriate:
+                    // return (float)$str;
+
+                    // Return float or int, as appropriate
+                    return ((float)$str == (integer)$str)
+                        ? (integer)$str
+                        : (float)$str;
+
+                } elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) {
+                    // STRINGS RETURNED IN UTF-8 FORMAT
+                    $delim = substr($str, 0, 1);
+                    $chrs = substr($str, 1, -1);
+                    $utf8 = '';
+                    $strlen_chrs = strlen($chrs);
+
+                    for ($c = 0; $c < $strlen_chrs; ++$c) {
+
+                        $substr_chrs_c_2 = substr($chrs, $c, 2);
+                        $ord_chrs_c = ord($chrs{$c});
+
+                        switch (true) {
+                            case $substr_chrs_c_2 == '\b':
+                                $utf8 .= chr(0x08);
+                                ++$c;
+                                break;
+                            case $substr_chrs_c_2 == '\t':
+                                $utf8 .= chr(0x09);
+                                ++$c;
+                                break;
+                            case $substr_chrs_c_2 == '\n':
+                                $utf8 .= chr(0x0A);
+                                ++$c;
+                                break;
+                            case $substr_chrs_c_2 == '\f':
+                                $utf8 .= chr(0x0C);
+                                ++$c;
+                                break;
+                            case $substr_chrs_c_2 == '\r':
+                                $utf8 .= chr(0x0D);
+                                ++$c;
+                                break;
+
+                            case $substr_chrs_c_2 == '\\"':
+                            case $substr_chrs_c_2 == '\\\'':
+                            case $substr_chrs_c_2 == '\\\\':
+                            case $substr_chrs_c_2 == '\\/':
+                                if (($delim == '"' && $substr_chrs_c_2 != '\\\'') ||
+                                   ($delim == "'" && $substr_chrs_c_2 != '\\"')) {
+                                    $utf8 .= $chrs{++$c};
+                                }
+                                break;
+
+                            case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)):
+                                // single, escaped unicode character
+                                $utf16 = chr(hexdec(substr($chrs, ($c + 2), 2)))
+                                       . chr(hexdec(substr($chrs, ($c + 4), 2)));
+                                $utf8 .= $this->utf162utf8($utf16);
+                                $c += 5;
+                                break;
+
+                            case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F):
+                                $utf8 .= $chrs{$c};
+                                break;
+
+                            case ($ord_chrs_c & 0xE0) == 0xC0:
+                                // characters U-00000080 - U-000007FF, mask 110XXXXX
+                                //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                                $utf8 .= substr($chrs, $c, 2);
+                                ++$c;
+                                break;
+
+                            case ($ord_chrs_c & 0xF0) == 0xE0:
+                                // characters U-00000800 - U-0000FFFF, mask 1110XXXX
+                                // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                                $utf8 .= substr($chrs, $c, 3);
+                                $c += 2;
+                                break;
+
+                            case ($ord_chrs_c & 0xF8) == 0xF0:
+                                // characters U-00010000 - U-001FFFFF, mask 11110XXX
+                                // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                                $utf8 .= substr($chrs, $c, 4);
+                                $c += 3;
+                                break;
+
+                            case ($ord_chrs_c & 0xFC) == 0xF8:
+                                // characters U-00200000 - U-03FFFFFF, mask 111110XX
+                                // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                                $utf8 .= substr($chrs, $c, 5);
+                                $c += 4;
+                                break;
+
+                            case ($ord_chrs_c & 0xFE) == 0xFC:
+                                // characters U-04000000 - U-7FFFFFFF, mask 1111110X
+                                // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                                $utf8 .= substr($chrs, $c, 6);
+                                $c += 5;
+                                break;
+
+                        }
+
+                    }
+
+                    return $utf8;
+
+                } elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) {
+                    // array, or object notation
+
+                    if ($str{0} == '[') {
+                        $stk = array(SERVICES_JSON_IN_ARR);
+                        $arr = array();
+                    } else {
+                        if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
+                            $stk = array(SERVICES_JSON_IN_OBJ);
+                            $obj = array();
+                        } else {
+                            $stk = array(SERVICES_JSON_IN_OBJ);
+                            $obj = new stdClass();
+                        }
+                    }
+
+                    array_push($stk, array('what'  => SERVICES_JSON_SLICE,
+                                           'where' => 0,
+                                           'delim' => false));
+
+                    $chrs = substr($str, 1, -1);
+                    $chrs = $this->reduce_string($chrs);
+
+                    if ($chrs == '') {
+                        if (reset($stk) == SERVICES_JSON_IN_ARR) {
+                            return $arr;
+
+                        } else {
+                            return $obj;
+
+                        }
+                    }
+
+                    //print("\nparsing {$chrs}\n");
+
+                    $strlen_chrs = strlen($chrs);
+
+                    for ($c = 0; $c <= $strlen_chrs; ++$c) {
+
+                        $top = end($stk);
+                        $substr_chrs_c_2 = substr($chrs, $c, 2);
+
+                        if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) {
+                            // found a comma that is not inside a string, array, etc.,
+                            // OR we've reached the end of the character list
+                            $slice = substr($chrs, $top['where'], ($c - $top['where']));
+                            array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false));
+                            //print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
+
+                            if (reset($stk) == SERVICES_JSON_IN_ARR) {
+                                // we are in an array, so just push an element onto the stack
+                                array_push($arr, $this->decode($slice));
+
+                            } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
+                                // we are in an object, so figure
+                                // out the property name and set an
+                                // element in an associative array,
+                                // for now
+                                $parts = array();
+                                
+                                if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
+                                    // "name":value pair
+                                    $key = $this->decode($parts[1]);
+                                    $val = $this->decode($parts[2]);
+
+                                    if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
+                                        $obj[$key] = $val;
+                                    } else {
+                                        $obj->$key = $val;
+                                    }
+                                } elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
+                                    // name:value pair, where name is unquoted
+                                    $key = $parts[1];
+                                    $val = $this->decode($parts[2]);
+
+                                    if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
+                                        $obj[$key] = $val;
+                                    } else {
+                                        $obj->$key = $val;
+                                    }
+                                }
+
+                            }
+
+                        } elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) {
+                            // found a quote, and we are not inside a string
+                            array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c}));
+                            //print("Found start of string at {$c}\n");
+
+                        } elseif (($chrs{$c} == $top['delim']) &&
+                                 ($top['what'] == SERVICES_JSON_IN_STR) &&
+                                 ((strlen(substr($chrs, 0, $c)) - strlen(rtrim(substr($chrs, 0, $c), '\\'))) % 2 != 1)) {
+                            // found a quote, we're in a string, and it's not escaped
+                            // we know that it's not escaped becase there is _not_ an
+                            // odd number of backslashes at the end of the string so far
+                            array_pop($stk);
+                            //print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n");
+
+                        } elseif (($chrs{$c} == '[') &&
+                                 in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
+                            // found a left-bracket, and we are in an array, object, or slice
+                            array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false));
+                            //print("Found start of array at {$c}\n");
+
+                        } elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) {
+                            // found a right-bracket, and we're in an array
+                            array_pop($stk);
+                            //print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
+
+                        } elseif (($chrs{$c} == '{') &&
+                                 in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
+                            // found a left-brace, and we are in an array, object, or slice
+                            array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false));
+                            //print("Found start of object at {$c}\n");
+
+                        } elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) {
+                            // found a right-brace, and we're in an object
+                            array_pop($stk);
+                            //print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
+
+                        } elseif (($substr_chrs_c_2 == '/*') &&
+                                 in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
+                            // found a comment start, and we are in an array, object, or slice
+                            array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false));
+                            $c++;
+                            //print("Found start of comment at {$c}\n");
+
+                        } elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) {
+                            // found a comment end, and we're in one now
+                            array_pop($stk);
+                            $c++;
+
+                            for ($i = $top['where']; $i <= $c; ++$i)
+                                $chrs = substr_replace($chrs, ' ', $i, 1);
+
+                            //print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
+
+                        }
+
+                    }
+
+                    if (reset($stk) == SERVICES_JSON_IN_ARR) {
+                        return $arr;
+
+                    } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
+                        return $obj;
+
+                    }
+
+                }
+        }
+    }
+
+    /**
+     * @todo Ultimately, this should just call PEAR::isError()
+     */
+    function isError($data, $code = null)
+    {
+        if (class_exists('pear')) {
+            return PEAR::isError($data, $code);
+        } elseif (is_object($data) && (get_class($data) == 'services_json_error' ||
+                                 is_subclass_of($data, 'services_json_error'))) {
+            return true;
+        }
+
+        return false;
+    }
+}
+
+if (class_exists('PEAR_Error')) {
+
+    class Services_JSON_Error extends PEAR_Error
+    {
+        function Services_JSON_Error($message = 'unknown error', $code = null,
+                                     $mode = null, $options = null, $userinfo = null)
+        {
+            parent::PEAR_Error($message, $code, $mode, $options, $userinfo);
+        }
+    }
+
+} else {
+
+    /**
+     * @todo Ultimately, this class shall be descended from PEAR_Error
+     */
+    class Services_JSON_Error
+    {
+        function Services_JSON_Error($message = 'unknown error', $code = null,
+                                     $mode = null, $options = null, $userinfo = null)
+        {
+
+        }
+    }
+
+}
+    
+?>
\ No newline at end of file
Binary file includes/magic.mime.mgc has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/pageprocess.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,457 @@
+<?php
+/*
+ * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
+ * Version 1.0 (Banshee)
+ * pageprocess.php - intelligent retrieval of pages
+ * Copyright (C) 2006-2007 Dan Fuhry
+ *
+ * This program is Free Software; you can redistribute 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 details.
+ */
+
+/**
+ * Class to handle fetching page text (possibly from a cache) and formatting it.
+ * @package Enano
+ * @subpackage UI
+ * @copyright 2007 Dan Fuhry
+ * @license GNU General Public License <http://www.gnu.org/licenses/gpl.html>
+ */
+
+class PageProcessor
+{
+  
+  /**
+   * Page ID and namespace of the page handled by this instance
+   * @var string
+   */
+  
+  var $page_id;
+  var $namespace;
+  
+  /**
+   * Tracks if the page we're loading exists in the database or not.
+   * @var bool
+   */
+  
+  var $page_exists = false;
+  
+  /**
+   * Permissions!
+   * @var object
+   */
+  
+  var $perms = null;
+  
+  /**
+   * Switch to track if redirects are allowed. Defaults to true.
+   * @var bool
+   */
+  
+  var $allow_redir = true;
+  
+  /**
+   * If this is set to true, this will call the header and footer funcs on $template when render() is called.
+   * @var bool
+   */
+  
+  var $send_headers = false;
+  
+  /**
+   * Cache the fetched text so we don't fetch it from the DB twice.
+   * @var string
+   */
+  
+  var $text_cache = '';
+  
+  /**
+   * Debugging information to track errors. You can set enable to false to disable sending debug information.
+   * @var array
+   */
+  
+  var $debug = array(
+      'enable' => true,
+      'works'  => false
+    );
+  
+  /**
+   * Constructor.
+   * @param string The page ID (urlname) of the page
+   * @param string The namespace of the page
+   */
+  
+  function __construct( $page_id, $namespace )
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    // See if we can get some debug info
+    if ( function_exists('debug_backtrace') && $this->debug['enable'] )
+    {
+      $this->debug['works'] = true;
+      $this->debug['backtrace'] = enano_debug_print_backtrace(true);
+    }
+    
+    // First things first - check page existence and permissions
+    
+    if ( !isset($paths->nslist[$namespace]) )
+    {
+      $this->send_error('The namespace "' . htmlspecialchars($namespace) . '" does not exist.');
+    }
+    
+    $this->_setup( $page_id, $namespace );
+    
+  }
+  
+  /**
+   * The main method to send the page content. Also responsible for checking permissions.
+   */
+  
+  function send()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if ( !$this->perms->get_permissions('read') )
+    {
+      $this->err_access_denied();
+      return false;
+    }
+    if ( $this->namespace == 'Special' || $this->namespace == 'Admin' )
+    {
+      if ( !$this->page_exists )
+      {
+        redirect( makeUrl(getConfig('main_page')), 'Can\'t find special page', 'The special or administration page you requested does not exist. You will now be transferred to the main page.', 2 );
+      }
+      $func_name = "page_{$this->namespace}_{$this->page_id}";
+      if ( function_exists($func_name) )
+      {
+        return @call_user_func($func_name);
+      }
+      else
+      {
+        $title = 'Page backend not found';
+        $message = "The administration page you are looking for was properly registered using the page API, but the backend function
+                    (<tt>$fname</tt>) was not found. If this is a plugin page, then this is almost certainly a bug with the plugin.";
+                    
+        if ( $this->send_headers )
+        {
+          $template->tpl_strings['PAGE_NAME'] = $title;
+          $template->header();
+          echo "<p>$message</p>";
+          $template->footer();
+        }
+        else
+        {
+          echo "<h2>$title</h2>
+                <p>$message</p>";
+        }
+        return false;
+      }
+    }
+    else if ( in_array($this->namespace, array('Article', 'User', 'Project', 'Help', 'File', 'Category')) && $this->page_exists )
+    {
+      // Send as regular page
+      $text = $this->fetch_text();
+      if ( $text == 'err_no_text_rows' )
+      {
+        $this->err_no_rows();
+        return false;
+      }
+      else
+      {
+        $this->render();
+      }
+    }
+    else if ( ( $this->namespace == 'Template' || $this->namespace == 'System' ) && $this->page_exists )
+    {
+      $this->header();
+      
+      $text = $this->fetch_text();
+      $text = preg_replace('/<noinclude>(.*?)<\/noinclude>/is', '\\1', $text);
+      $text = preg_replace('/<nodisplay>(.*?)<\/nodisplay>/is', '', $text);
+      
+      $text = RenderMan::render( $text );
+      
+      echo $text;
+      
+      $this->footer();
+      
+    }
+    else if ( !$this->page_exists )
+    {
+      // Perhaps this is hooked?
+      ob_start();
+      
+      $code = $plugins->setHook('page_not_found');
+      foreach ( $code as $cmd )
+      {
+        eval($cmd);
+      }
+      
+      $ob = ob_get_contents();
+      
+      if ( empty($ob) )
+      {
+        $this->err_page_not_existent();
+      }
+      
+    }
+    
+  }
+  
+  /**
+   * Sets internal variables.
+   * @access private
+   */
+  
+  function _setup($page_id, $namespace)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    $page_id_cleaned = sanitize_page_id($page_id);
+    
+    $this->page_id = $page_id_cleaned;
+    $this->namespace = $namespace;
+    
+    $this->perms = $session->fetch_page_acl( $page_id, $namespace );
+    
+    // Exception for Admin: pages
+    if ( $this->namespace == 'Admin' )
+    {
+      $fname = "page_Admin_{$this->page_id}";
+    }
+    
+    // Does the page "exist"?
+    if ( $paths->cpage['urlname_nons'] == $page_id && $paths->namespace == $namespace && !$paths->page_exists && ( $this->namespace == 'Admin' && !function_exists($fname) ) )
+    {
+      $this->page_exists = false;
+    }
+    else if ( !isset( $paths->pages[ $paths->nslist[$namespace] . $page_id ] ) && ( $this->namespace == 'Admin' && !function_exists($fname) ) )
+    {
+      $this->page_exists = false;
+    }
+    else
+    {
+      $this->page_exists = true;
+    }
+  }
+  
+  /**
+   * Renders it all in one go, and echoes it out. This assumes that the text is in the DB.
+   * @access private
+   */
+  
+  function render()
+  {
+    $text = $this->fetch_text();
+    
+    $this->header();
+    display_page_headers();
+    echo RenderMan::render($text);
+    display_page_footers();
+    $this->footer();
+  }
+  
+  /**
+   * Sends the page header, dependent on, of course, whether we're supposed to.
+   */
+  
+  function header()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if ( $this->send_headers )
+      $template->header();
+  }
+  
+  /**
+   * Sends the page footer, dependent on, of course, whether we're supposed to.
+   */
+  
+  function footer()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if ( $this->send_headers )
+      $template->footer();
+  }
+  
+  /**
+   * Fetches the raw, unfiltered page text.
+   * @access public
+   */
+  
+  function fetch_text()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    if ( !empty($this->text_cache) )
+    {
+      return $this->text_cache;
+    }
+    
+    $q = $db->sql_query('SELECT page_text, char_tag FROM '.table_prefix.'page_text WHERE page_id=\'' . $this->page_id . '\' AND namespace=\'' . $this->namespace . '\';');
+    if ( !$q )
+    {
+      $this->send_error('Error during SQL query.', true);
+    }
+    if ( $db->numrows() < 1 )
+    {
+      $this->page_exists = false;
+      return 'err_no_text_rows';
+    }
+    
+    $row = $db->fetchrow();
+    $db->free_result();
+    
+    if ( !empty($row['char_tag']) )
+    {
+      // This page text entry uses the old text-escaping format
+      $from = array(
+          "{APOS:{$row['char_tag']}}",
+          "{QUOT:{$row['char_tag']}}",
+          "{SLASH:{$row['char_tag']}}"
+        );
+      $to = array("'", '"',  '\\');
+      $row['page_text'] = str_replace($from, $to, $row['page_text']);
+    }
+    
+    $this->text_cache = $row['page_text'];
+    
+    return $row['page_text'];
+    
+  }
+  
+  /**
+   * Send the error message to the user that the access to this page is denied.
+   * @access private
+   */
+  
+  function err_access_denied()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    $ob = '';
+    $template->tpl_strings['PAGE_NAME'] = 'Access denied';
+      
+    if ( $this->send_headers )
+    {
+      $ob .= $template->getHeader();
+    }
+    
+    $ob .= '<div class="error-box"><b>Access to this page is denied.</b><br />This may be because you are not logged in or you have not met certain criteria for viewing this page.</div>';
+    
+    if ( $this->send_headers )
+    {
+      $ob .= $template->getFooter();
+    }
+    echo $ob;
+  }
+  
+  /**
+   * Send the error message to the user complaining that there weren't any rows.
+   * @access private
+   */
+  
+  function err_no_rows()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    $title = 'No text rows';
+    $message = 'While the page\'s existence was verified, there were no rows in the database that matched the query for the text. This may indicate a bug with the software; ask the webmaster for more information. The offending query was:<pre>' . $db->latest_query . '</pre>';
+    if ( $this->send_headers )
+    {
+      $template->tpl_strings['PAGE_NAME'] = $title;
+      $template->header();
+      echo "<p>$message</p>";
+      $template->footer();
+    }
+    else
+    {
+      echo "<h2>$title</h2>
+            <p>$message</p>";
+    }
+  }
+  
+  /**
+   * Tell the user the page doesn't exist, and present them with their options.
+   * @access private
+   */
+   
+  function err_page_not_existent()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    $this->header();
+    header('HTTP/1.1 404 Not Found');
+    echo '<h3>There is no page with this title yet.</h3>
+           <p>You have requested a page that doesn\'t exist yet.';
+    if ( $session->get_permissions('create_page') )
+    {
+      echo ' You can <a href="'.makeUrlNS($this->namespace, $this->page_id, 'do=edit', true).'" onclick="ajaxEditor(); return false;">create this page</a>, or return to the <a href="'.makeUrl(getConfig('main_page')).'">homepage</a>.';
+    }
+    else
+    {
+      echo ' Return to the <a href="'.makeUrl(getConfig('main_page')).'">homepage</a>.</p>';
+    }
+    if ( $session->get_permissions('history_rollback') )
+    {
+      $e = $db->sql_query('SELECT * FROM ' . table_prefix . 'logs WHERE action=\'delete\' AND page_id=\'' . $this->page_id . '\' AND namespace=\'' . $this->namespace . '\' ORDER BY time_id DESC;');
+      if ( !$e )
+      {
+        $db->_die('The deletion log could not be selected.');
+      }
+      if ( $db->numrows() > 0 )
+      {
+        $r = $db->fetchrow();
+        echo '<p>This page also appears to have some log entries in the database - it seems that it was deleted on ' . $r['date_string'] . '. You can probably <a href="'.makeUrl($paths->page, 'do=rollback&amp;id='.$r['time_id']).'" onclick="ajaxRollback(\''.$r['time_id'].'\'); return false;">roll back</a> the deletion.</p>';
+      }
+      $db->free_result();
+    }
+    echo '<p>
+            HTTP Error: 404 Not Found
+          </p>';
+    $this->footer();
+  }
+  
+  /**
+   * PHP 4 constructor.
+   * @see PageProcessor::__construct()
+   */
+  
+  function PageProcessor( $page_id, $namespace )
+  {
+    $this->__construct($page_id, $namespace);
+  }
+  
+  /**
+   * Send an error message and die
+   * @var string Error message
+   * @var bool If true, send DBAL's debugging information as well
+   */
+   
+  function send_error($message, $sql = false)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    $content = "<p>$message</p>";
+    $template->tpl_strings['PAGE_NAME'] = 'General error in page fetcher';
+    
+    if ( $this->debug['works'] )
+    {
+      $content .= $this->debug['backtrace'];
+    }
+    
+    header('HTTP/1.1 500 Internal Server Error');
+    
+    $template->header();
+    echo $content;
+    $template->footer();
+    
+    $db->close();
+    
+    exit;
+    
+  }
+  
+} // class PageProcessor
+
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/pageprocess.php~	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,455 @@
+<?php
+/*
+ * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
+ * Version 1.0 (Banshee)
+ * pageprocess.php - intelligent retrieval of pages
+ * Copyright (C) 2006-2007 Dan Fuhry
+ *
+ * This program is Free Software; you can redistribute 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 details.
+ */
+
+/**
+ * Class to handle fetching page text (possibly from a cache) and formatting it.
+ * @package Enano
+ * @subpackage UI
+ * @copyright 2007 Dan Fuhry
+ * @license GNU General Public License <http://www.gnu.org/licenses/gpl.html>
+ */
+
+class PageProcessor
+{
+  
+  /**
+   * Page ID and namespace of the page handled by this instance
+   * @var string
+   */
+  
+  var $page_id;
+  var $namespace;
+  
+  /**
+   * Tracks if the page we're loading exists in the database or not.
+   * @var bool
+   */
+  
+  var $page_exists = false;
+  
+  /**
+   * Permissions!
+   * @var object
+   */
+  
+  var $perms = null;
+  
+  /**
+   * Switch to track if redirects are allowed. Defaults to true.
+   * @var bool
+   */
+  
+  var $allow_redir = true;
+  
+  /**
+   * If this is set to true, this will call the header and footer funcs on $template when render() is called.
+   * @var bool
+   */
+  
+  var $send_headers = false;
+  
+  /**
+   * Cache the fetched text so we don't fetch it from the DB twice.
+   * @var string
+   */
+  
+  var $text_cache = '';
+  
+  /**
+   * Debugging information to track errors. You can set enable to false to disable sending debug information.
+   * @var array
+   */
+  
+  var $debug = array(
+      'enable' => true,
+      'works'  => false
+    );
+  
+  /**
+   * Constructor.
+   * @param string The page ID (urlname) of the page
+   * @param string The namespace of the page
+   */
+  
+  function __construct( $page_id, $namespace )
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    // See if we can get some debug info
+    if ( function_exists('debug_backtrace') && $this->debug['enable'] )
+    {
+      $this->debug['works'] = true;
+      $this->debug['backtrace'] = enano_debug_print_backtrace(true);
+    }
+    
+    // First things first - check page existence and permissions
+    
+    if ( !isset($paths->nslist[$namespace]) )
+    {
+      $this->send_error('The namespace "' . htmlspecialchars($namespace) . '" does not exist.');
+    }
+    
+    $this->_setup( $page_id, $namespace );
+    
+  }
+  
+  /**
+   * The main method to send the page content. Also responsible for checking permissions.
+   */
+  
+  function send()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if ( !$this->perms->get_permissions('read') )
+    {
+      $this->err_access_denied();
+      return false;
+    }
+    if ( $this->namespace == 'Special' || $this->namespace == 'Admin' )
+    {
+      if ( !$this->page_exists )
+      {
+        redirect( makeUrl(getConfig('main_page')), 'Can\'t find special page', 'The special or administration page you requested does not exist. You will now be transferred to the main page.', 2 );
+      }
+      $func_name = "page_{$this->namespace}_{$this->page_id}";
+      if ( function_exists($func_name) )
+      {
+        return @call_user_func($func_name);
+      }
+      else
+      {
+        $title = 'Page backend not found';
+        $message = "The administration page you are looking for was properly registered using the page API, but the backend function
+                    (<tt>$fname</tt>) was not found. If this is a plugin page, then this is almost certainly a bug with the plugin.";
+                    
+        if ( $this->send_headers )
+        {
+          $template->tpl_strings['PAGE_NAME'] = $title;
+          $template->header();
+          echo "<p>$message</p>";
+          $template->footer();
+        }
+        else
+        {
+          echo "<h2>$title</h2>
+                <p>$message</p>";
+        }
+        return false;
+      }
+    }
+    else if ( in_array($this->namespace, array('Article', 'User', 'Project', 'Help', 'File', 'Category')) && $this->page_exists )
+    {
+      // Send as regular page
+      $text = $this->fetch_text();
+      if ( $text == 'err_no_text_rows' )
+      {
+        $this->err_no_rows();
+        return false;
+      }
+      else
+      {
+        $this->render();
+      }
+    }
+    else if ( ( $this->namespace == 'Template' || $this->namespace == 'System' ) && $this->page_exists )
+    {
+      $this->header();
+      
+      $text = $this->fetch_text();
+      $text = preg_replace('/<noinclude>(.*?)<\/noinclude>/is', '\\1', $text);
+      $text = preg_replace('/<nodisplay>(.*?)<\/nodisplay>/is', '', $text);
+      
+      $text = RenderMan::render( $text );
+      
+      echo $text;
+      
+      $this->footer();
+      
+    }
+    else if ( !$this->page_exists )
+    {
+      // Perhaps this is hooked?
+      ob_start();
+      
+      $code = $plugins->setHook('page_not_found');
+      foreach ( $code as $cmd )
+      {
+        eval($cmd);
+      }
+      
+      $ob = ob_get_contents();
+      
+      if ( empty($ob) )
+      {
+        $this->err_page_not_existent();
+      }
+      
+    }
+    
+  }
+  
+  /**
+   * Sets internal variables.
+   * @access private
+   */
+  
+  function _setup($page_id, $namespace)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    $page_id_cleaned = sanitize_page_id($page_id);
+    
+    $this->page_id = $page_id_cleaned;
+    $this->namespace = $namespace;
+    
+    $this->perms = $session->fetch_page_acl( $page_id, $namespace );
+    
+    // Exception for Admin: pages
+    if ( $this->namespace == 'Admin' )
+    {
+      $fname = "page_Admin_{$this->page_id}";
+    }
+    
+    // Does the page "exist"?
+    if ( $paths->cpage['urlname_nons'] == $page_id && $paths->namespace == $namespace && !$paths->page_exists && ( $this->namespace == 'Admin' && !function_exists($fname) ) )
+    {
+      $this->page_exists = false;
+    }
+    else if ( !isset( $paths->pages[ $paths->nslist[$namespace] . $page_id ] ) && ( $this->namespace == 'Admin' && !function_exists($fname) ) )
+    {
+      $this->page_exists = false;
+    }
+    else
+    {
+      $this->page_exists = true;
+    }
+  }
+  
+  /**
+   * Renders it all in one go, and echoes it out. This assumes that the text is in the DB.
+   * @access private
+   */
+  
+  function render()
+  {
+    $text = $this->fetch_text();
+    
+    $this->header();
+    echo RenderMan::render($text);
+    $this->footer();
+  }
+  
+  /**
+   * Sends the page header, dependent on, of course, whether we're supposed to.
+   */
+  
+  function header()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if ( $this->send_headers )
+      $template->header();
+  }
+  
+  /**
+   * Sends the page footer, dependent on, of course, whether we're supposed to.
+   */
+  
+  function footer()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if ( $this->send_headers )
+      $template->footer();
+  }
+  
+  /**
+   * Fetches the raw, unfiltered page text.
+   * @access public
+   */
+  
+  function fetch_text()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    if ( !empty($this->text_cache) )
+    {
+      return $this->text_cache;
+    }
+    
+    $q = $db->sql_query('SELECT page_text, char_tag FROM '.table_prefix.'page_text WHERE page_id=\'' . $this->page_id . '\' AND namespace=\'' . $this->namespace . '\';');
+    if ( !$q )
+    {
+      $this->send_error('Error during SQL query.', true);
+    }
+    if ( $db->numrows() < 1 )
+    {
+      $this->page_exists = false;
+      return 'err_no_text_rows';
+    }
+    
+    $row = $db->fetchrow();
+    $db->free_result();
+    
+    if ( !empty($row['char_tag']) )
+    {
+      // This page text entry uses the old text-escaping format
+      $from = array(
+          "{APOS:{$row['char_tag']}}",
+          "{QUOT:{$row['char_tag']}}",
+          "{SLASH:{$row['char_tag']}}"
+        );
+      $to = array("'", '"',  '\\');
+      $row['page_text'] = str_replace($from, $to, $row['page_text']);
+    }
+    
+    $this->text_cache = $row['page_text'];
+    
+    return $row['page_text'];
+    
+  }
+  
+  /**
+   * Send the error message to the user that the access to this page is denied.
+   * @access private
+   */
+  
+  function err_access_denied()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    $ob = '';
+    $template->tpl_strings['PAGE_NAME'] = 'Access denied';
+      
+    if ( $this->send_headers )
+    {
+      $ob .= $template->getHeader();
+    }
+    
+    $ob .= '<div class="error-box"><b>Access to this page is denied.</b><br />This may be because you are not logged in or you have not met certain criteria for viewing this page.</div>';
+    
+    if ( $this->send_headers )
+    {
+      $ob .= $template->getFooter();
+    }
+    echo $ob;
+  }
+  
+  /**
+   * Send the error message to the user complaining that there weren't any rows.
+   * @access private
+   */
+  
+  function err_no_rows()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    $title = 'No text rows';
+    $message = 'While the page\'s existence was verified, there were no rows in the database that matched the query for the text. This may indicate a bug with the software; ask the webmaster for more information.';
+    if ( $this->send_headers )
+    {
+      $template->tpl_strings['PAGE_NAME'] = $title;
+      $template->header();
+      echo "<p>$message</p>";
+      $template->footer();
+    }
+    else
+    {
+      echo "<h2>$title</h2>
+            <p>$message</p>";
+    }
+  }
+  
+  /**
+   * Tell the user the page doesn't exist, and present them with their options.
+   * @access private
+   */
+   
+  function err_page_not_existent()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    $this->header();
+    header('HTTP/1.1 404 Not Found');
+    echo '<h3>There is no page with this title yet.</h3>
+           <p>You have requested a page that doesn\'t exist yet.';
+    if ( $session->get_permissions('create_page') )
+    {
+      echo ' You can <a href="'.makeUrlNS($this->namespace, $this->page_id, 'do=edit', true).'" onclick="ajaxEditor(); return false;">create this page</a>, or return to the <a href="'.makeUrl(getConfig('main_page')).'">homepage</a>.';
+    }
+    else
+    {
+      echo ' Return to the <a href="'.makeUrl(getConfig('main_page')).'">homepage</a>.</p>';
+    }
+    if ( $session->get_permissions('history_rollback') )
+    {
+      $e = $db->sql_query('SELECT * FROM ' . table_prefix . 'logs WHERE action=\'delete\' AND page_id=\'' . $this->page_id . '\' AND namespace=\'' . $this->namespace . '\' ORDER BY time_id DESC;');
+      if ( !$e )
+      {
+        $db->_die('The deletion log could not be selected.');
+      }
+      if ( $db->numrows() > 0 )
+      {
+        $r = $db->fetchrow();
+        echo '<p>This page also appears to have some log entries in the database - it seems that it was deleted on ' . $r['date_string'] . '. You can probably <a href="'.makeUrl($paths->page, 'do=rollback&amp;id='.$r['time_id']).'" onclick="ajaxRollback(\''.$r['time_id'].'\'); return false;">roll back</a> the deletion.</p>';
+      }
+      $db->free_result();
+    }
+    echo '<p>
+            HTTP Error: 404 Not Found
+          </p>';
+    $this->footer();
+  }
+  
+  /**
+   * PHP 4 constructor.
+   * @see PageProcessor::__construct()
+   */
+  
+  function PageProcessor( $page_id, $namespace )
+  {
+    $this->__construct($page_id, $namespace);
+  }
+  
+  /**
+   * Send an error message and die
+   * @var string Error message
+   * @var bool If true, send DBAL's debugging information as well
+   */
+   
+  function send_error($message, $sql = false)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    $content = "<p>$message</p>";
+    $template->tpl_strings['PAGE_NAME'] = 'General error in page fetcher';
+    
+    if ( $this->debug['works'] )
+    {
+      $content .= $this->debug['backtrace'];
+    }
+    
+    header('HTTP/1.1 500 Internal Server Error');
+    
+    $template->header();
+    echo $content;
+    $template->footer();
+    
+    $db->close();
+    
+    exit;
+    
+  }
+  
+} // class PageProcessor
+
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/pageutils.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,2060 @@
+<?php
+/*
+ * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
+ * Version 1.0 (Banshee)
+ * Copyright (C) 2006-2007 Dan Fuhry
+ * pageutils.php - a class that handles raw page manipulations, used mostly by AJAX requests or their old-fashioned form-based counterparts
+ *
+ * This program is Free Software; you can redistribute 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 details.
+ */
+ 
+class PageUtils {
+  
+  /**
+   * List possible username completions
+   * @param $name the name to check for
+   * @return array
+   */
+  
+  function checkusername($name)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $q = $db->sql_query('SELECT username FROM '.table_prefix.'users WHERE username=\''.$db->escape(rawurldecode($name)).'\'');
+    if(!$q) die(mysql_error());
+    if($db->numrows() < 1) { $db->free_result(); return('good'); }
+    else { $db->free_result(); return('bad'); }
+  }
+  
+  /**
+   * Get the wiki formatting source for a page
+   * @param $page the full page id (Namespace:Pagename)
+   * @return string
+   * @todo (DONE) Make it require a password (just for security purposes)
+   */
+   
+  function getsource($page, $password = false)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(!isset($paths->pages[$page]))
+    {
+      return '';
+    }
+    
+    if(strlen($paths->pages[$page]['password']) == 40)
+    {
+      if(!$password || ( $password != $paths->pages[$page]['password']))
+      {
+        return 'invalid_password';
+      }
+    }
+    
+    if(!$session->get_permissions('view_source')) // Dependencies handle this for us - this also checks for read privileges
+      return 'access_denied';
+    $pid = RenderMan::strToPageID($page);
+    if($pid[1] == 'Special' || $pid[1] == 'Admin')
+    {
+      die('This type of page ('.$paths->nslist[$pid[1]].') cannot be edited because the page source code is not stored in the database.');
+    }
+    
+    $e = $db->sql_query('SELECT page_text,char_tag FROM '.table_prefix.'page_text WHERE page_id=\''.$pid[0].'\' AND namespace=\''.$pid[1].'\'');
+    if ( !$e )
+    {
+      $db->_die('The page text could not be selected.');
+    }
+    if( $db->numrows() < 1 )
+    {
+      return ''; //$db->_die('There were no rows in the text table that matched the page text query.');
+    }
+    
+    $r = $db->fetchrow();
+    $db->free_result();
+    $message = $r['page_text'];
+    
+    return htmlspecialchars($message);
+  }
+  
+  /**
+   * Basically a frontend to RenderMan::getPage(), with the ability to send valid data for nonexistent pages
+   * @param $page the full page id (Namespace:Pagename)
+   * @param $send_headers true if the theme headers should be sent (still dependent on current page settings), false otherwise
+   * @return string
+   */
+  
+  function getpage($page, $send_headers = false, $hist_id = false)
+  {
+    die('PageUtils->getpage is deprecated.');
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    ob_start();
+    $pid = RenderMan::strToPageID($page);
+    //die('<pre>'.print_r($pid, true).'</pre>');
+    if(isset($paths->pages[$page]['password']) && strlen($paths->pages[$page]['password']) == 40)
+    {
+      password_prompt($page);
+    }
+    if(isset($paths->pages[$page]))
+    {
+      doStats($pid[0], $pid[1]);
+    }
+    if($paths->custom_page || $pid[1] == 'Special')
+    {
+      // If we don't have access to the page, get out and quick!
+      if(!$session->get_permissions('read') && $pid[0] != 'Login' && $pid[0] != 'Register')
+      {
+        $template->tpl_strings['PAGE_NAME'] = 'Access denied';
+        
+        if ( $send_headers )
+        {
+          $template->header();
+        }
+        
+        echo '<div class="error-box"><b>Access to this page is denied.</b><br />This may be because you are not logged in or you have not met certain criteria for viewing this page.</div>';
+        
+        if ( $send_headers )
+        {
+          $template->footer();
+        }
+        
+        $r = ob_get_contents();
+        ob_end_clean();
+        return $r;
+      }
+      
+      $fname = 'page_'.$pid[1].'_'.$paths->pages[$page]['urlname_nons'];
+      @call_user_func($fname);
+      
+    }
+    else if ( $pid[1] == 'Admin' )
+    {
+      // If we don't have access to the page, get out and quick!
+      if(!$session->get_permissions('read'))
+      {
+        $template->tpl_strings['PAGE_NAME'] = 'Access denied';
+        if ( $send_headers )
+        {
+          $template->header();
+        }
+        echo '<div class="error-box"><b>Access to this page is denied.</b><br />This may be because you are not logged in or you have not met certain criteria for viewing this page.</div>';
+        if ( $send_headers )
+        {
+          $template->footer();
+        }
+        $r = ob_get_contents();
+        ob_end_clean();
+        return $r;
+      }
+      
+      $fname = 'page_'.$pid[1].'_'.$pid[0];
+      if ( !function_exists($fname) )
+      {
+        $title = 'Page backend not found';
+        $message = "The administration page you are looking for was properly registered using the page API, but the backend function
+                    (<tt>$fname</tt>) was not found. If this is a plugin page, then this is almost certainly a bug with the plugin.";
+        if ( $send_headers )
+        {
+          die_friendly($title, "<p>$message</p>");
+        }
+        else
+        {
+          echo "<h2>$title</h2>\n<p>$message</p>";
+        }
+      }
+      @call_user_func($fname);
+    }
+    else if ( !isset( $paths->pages[$page] ) )
+    {
+      ob_start();
+      $code = $plugins->setHook('page_not_found');
+      foreach ( $code as $cmd )
+      {
+        eval($cmd);
+      }
+      $text = ob_get_contents();
+      if ( $text != '' )
+      {
+        ob_end_clean();
+        return $text;
+      }
+      $template->header();
+      if($m = $paths->sysmsg('Page_not_found'))
+      {
+        eval('?>'.RenderMan::render($m));
+      }
+      else
+      {
+        header('HTTP/1.1 404 Not Found');
+        echo '<h3>There is no page with this title yet.</h3>
+               <p>You have requested a page that doesn\'t exist yet.';
+        if($session->get_permissions('create_page')) echo ' You can <a href="'.makeUrl($paths->page, 'do=edit', true).'" onclick="ajaxEditor(); return false;">create this page</a>, or return to the <a href="'.makeUrl(getConfig('main_page')).'">homepage</a>.';
+        else echo ' Return to the <a href="'.makeUrl(getConfig('main_page')).'">homepage</a>.</p>';
+        if($session->get_permissions('history_rollback')) {
+          $e = $db->sql_query('SELECT * FROM '.table_prefix.'logs WHERE action=\'delete\' AND page_id=\''.$paths->cpage['urlname_nons'].'\' AND namespace=\''.$pid[1].'\' ORDER BY time_id DESC;');
+          if(!$e) $db->_die('The deletion log could not be selected.');
+          if($db->numrows() > 0) {
+            $r = $db->fetchrow();
+            echo '<p>This page also appears to have some log entries in the database - it seems that it was deleted on '.$r['date_string'].'. You can probably <a href="'.makeUrl($paths->page, 'do=rollback&amp;id='.$r['time_id']).'" onclick="ajaxRollback(\''.$r['time_id'].'\'); return false;">roll back</a> the deletion.</p>';
+          }
+          $db->free_result();
+        }
+        echo '<p>
+                HTTP Error: 404 Not Found
+              </p>';
+      }
+      $template->footer();
+    }
+    else
+    {
+      
+      // If we don't have access to the page, get out and quick!
+      if(!$session->get_permissions('read'))
+      {
+        $template->tpl_strings['PAGE_NAME'] = 'Access denied';
+        if($send_headers) $template->header();
+        echo '<div class="error-box"><b>Access to this page is denied.</b><br />This may be because you are not logged in or you have not met certain criteria for viewing this page.</div>';
+        if($send_headers) $template->footer();
+        $r = ob_get_contents();
+        ob_end_clean();
+        return $r;
+      }
+      
+      ob_start();
+      $code = $plugins->setHook('page_custom_handler');
+      foreach ( $code as $cmd )
+      {
+        eval($cmd);
+      }
+      $text = ob_get_contents();
+      if ( $text != '' )
+      {
+        ob_end_clean();
+        return $text;
+      }
+      
+      if($hist_id) {
+        $e = $db->sql_query('SELECT page_text,date_string,char_tag FROM '.table_prefix.'logs WHERE page_id=\''.$paths->pages[$page]['urlname_nons'].'\' AND namespace=\''.$pid[1].'\' AND log_type=\'page\' AND action=\'edit\' AND time_id='.$db->escape($hist_id).'');
+        if($db->numrows() < 1)
+        {
+          $db->_die('There were no rows in the text table that matched the page text query.');
+        }
+        $r = $db->fetchrow();
+        $db->free_result();
+        $message = '<div class="info-box" style="margin-left: 0; margin-top: 5px;"><b>Notice:</b><br />The page you are viewing was archived on '.$r['date_string'].'.<br /><a href="'.makeUrl($page).'" onclick="ajaxReset(); return false;">View current version</a>  |  <a href="'.makeUrl($page, 'do=rollback&amp;id='.$hist_id).'" onclick="ajaxRollback(\''.$hist_id.'\')">Restore this version</a></div><br />'.RenderMan::render($r['page_text']);
+        
+        if( !$paths->pages[$page]['special'] )
+        {
+          if($send_headers)
+          {
+            $template->header(); 
+          }
+          display_page_headers();
+        }
+        
+        eval('?>'.$message);
+        
+        if( !$paths->pages[$page]['special'] )
+        {
+          display_page_footers();
+          if($send_headers)
+          {
+            $template->footer();
+          }
+        }
+        
+      } else {
+        if(!$paths->pages[$page]['special'])
+        {
+          $message = RenderMan::getPage($paths->pages[$page]['urlname_nons'], $pid[1]);
+        }
+        else
+        {
+          $message = RenderMan::getPage($paths->pages[$page]['urlname_nons'], $pid[1], 0, false, false, false, false);
+        }
+        // This line is used to debug wikiformatted code
+        // die('<pre>'.htmlspecialchars($message).'</pre>');
+        
+        if( !$paths->pages[$page]['special'] )
+        {
+          if($send_headers)
+          {
+            $template->header(); 
+          }
+          display_page_headers();
+        }
+
+        // This is it, this is what all of Enano has been working up to...
+        
+        eval('?>'.$message);
+        
+        if( !$paths->pages[$page]['special'] )
+        {
+          display_page_footers();
+          if($send_headers)
+          {
+            $template->footer();
+          }
+        }
+      }
+    }
+    $ret = ob_get_contents();
+    ob_end_clean();
+    return $ret;
+  }
+  
+  /**
+   * Writes page data to the database, after verifying permissions and running the XSS filter
+   * @param $page_id the page ID
+   * @param $namespace the namespace
+   * @param $message the text to save
+   * @return string
+   */
+   
+  function savepage($page_id, $namespace, $message, $summary = 'No edit summary given', $minor = false)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $uid = sha1(microtime());
+    $pname = $paths->nslist[$namespace] . $page_id;
+    
+    if(!$session->get_permissions('edit_page'))
+      return 'Access to edit pages is denied.';
+    
+    if(!isset($paths->pages[$pname]))
+    {
+      if(!PageUtils::createPage($page_id, $namespace))
+        return 'The page did not exist, and I was not able to create it. Permissions problem?';
+    }
+    
+    $prot = ( ( $paths->pages[$pname]['protected'] == 2 && $session->user_logged_in && $session->reg_time + 60*60*24*4 < time() ) || $paths->pages[$pname]['protected'] == 1) ? true : false;
+    $wiki = ( ( $paths->pages[$pname]['wiki_mode'] == 2 && getConfig('wiki_mode') == '1') || $paths->pages[$pname]['wiki_mode'] == 1) ? true : false;
+    if(($prot || !$wiki) && $session->user_level < USER_LEVEL_ADMIN ) return('You are not authorized to edit this page.');
+    
+    // Strip potentially harmful tags and PHP from the message, if we are in wiki mode and the user is not an administrator
+    $message = RenderMan::preprocess_text($message, false, false);
+    
+    $msg=$db->escape($message);
+    
+    $minor = $minor ? 'true' : 'false';
+    $q='INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,page_id,namespace,page_text,char_tag,author,edit_summary,minor_edit) VALUES(\'page\', \'edit\', '.time().', \''.date('d M Y h:i a').'\', \''.$paths->cpage['urlname_nons'].'\', \''.$paths->namespace.'\', \''.$msg.'\', \''.$uid.'\', \''.$session->username.'\', \''.$db->escape(htmlspecialchars($summary)).'\', '.$minor.');';
+    if(!$db->sql_query($q)) $db->_die('The history (log) entry could not be inserted into the logs table.');
+    
+    $q = 'UPDATE '.table_prefix.'page_text SET page_text=\''.$msg.'\',char_tag=\''.$uid.'\' WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\';';
+    $e = $db->sql_query($q);
+    if(!$e) $db->_die('Enano was unable to save the page contents. Your changes have been lost <tt>:\'(</tt>.');
+      
+    $paths->rebuild_page_index($page_id, $namespace);
+      
+    return 'good';
+  }
+  
+  /**
+   * Creates a page, both in memory and in the database.
+   * @param string $page_id
+   * @param string $namespace
+   * @return bool true on success, false on failure
+   */
+  
+  function createPage($page_id, $namespace, $name = false, $visible = 1)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(in_array($namespace, Array('Special', 'Admin')))
+    {
+      // echo '<b>Notice:</b> PageUtils::createPage: You can\'t create a special page in the database<br />';
+      return false; // Can't create a special page
+    }
+    
+    if(!isset($paths->nslist[$namespace]))
+    {
+      // echo '<b>Notice:</b> PageUtils::createPage: Couldn\'t look up the namespace<br />';
+      return false; // Couldn't look up namespace
+    }
+    
+    $pname = $paths->nslist[$namespace] . $page_id;
+    if(isset($paths->pages[$pname]))
+    {
+      // echo '<b>Notice:</b> PageUtils::createPage: Page already exists<br />';
+      return false; // Page already exists
+    }
+    
+    if(!$session->get_permissions('create_page'))
+    {
+      // echo '<b>Notice:</b> PageUtils::createPage: Not authorized to create pages<br />';
+      return false; // Access denied
+    }
+    
+    if($session->user_level < USER_LEVEL_ADMIN && $namespace == 'System')
+    {
+      // echo '<b>Notice:</b> PageUtils::createPage: Not authorized to create system messages<br />';
+      return false; // Not authorized to create system messages
+    }
+    
+    if ( !$name )
+      $name = str_replace('_', ' ', $page_id);
+    $page = str_replace(' ', '_', $page_id);
+    $regex = '#^([A-z0-9 _\-\.\/\!\@\(\)]*)$#is';
+    if(!preg_match($regex, $page))
+    {
+      //echo '<b>Notice:</b> PageUtils::createPage: Name contains invalid characters<br />';
+      return false; // Name contains invalid characters
+    }
+    
+    $prot = ( $namespace == 'System' ) ? 1 : 0;
+    
+    $paths->add_page(Array(
+      'name'=>$name,
+      'urlname'=>$page,
+      'namespace'=>$namespace,
+      'special'=>0,'visible'=>1,'comments_on'=>0,'protected'=>$prot,'delvotes'=>0,'delvote_ips'=>'','wiki_mode'=>2,
+    ));
+    
+    $qa = $db->sql_query('INSERT INTO '.table_prefix.'pages(name,urlname,namespace,visible,protected) VALUES(\''.$db->escape($name).'\', \''.$db->escape($page).'\', \''.$namespace.'\', '. ( $visible ? '1' : '0' ) .', '.$prot.');');
+    $qb = $db->sql_query('INSERT INTO '.table_prefix.'page_text(page_id,namespace) VALUES(\''.$db->escape($page).'\', \''.$namespace.'\');');
+    $qc = $db->sql_query('INSERT INTO '.table_prefix.'logs(time_id,date_string,log_type,action,author,page_id,namespace) VALUES('.time().', \''.date('d M Y h:i a').'\', \'page\', \'create\', \''.$session->username.'\', \''.$db->escape($page).'\', \''.$namespace.'\');');
+    
+    if($qa && $qb && $qc)
+      return true;
+    else
+    {
+      echo $db->get_error();
+      return false;
+    }
+  }
+  
+  /**
+   * Sets the protection level on a page.
+   * @param $page_id string the page ID
+   * @param $namespace string the namespace
+   * @param $level int level of protection - 0 is off, 1 is full, 2 is semi
+   * @param $reason string why the page is being (un)protected
+   * @return string - "good" on success, in all other cases, an error string (on query failure, calls $db->_die() )
+   */
+  function protect($page_id, $namespace, $level, $reason)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    $pname = $paths->nslist[$namespace] . $page_id;
+    $wiki = ( ( $paths->pages[$pname]['wiki_mode'] == 2 && getConfig('wiki_mode') == '1') || $paths->pages[$pname]['wiki_mode'] == 1) ? true : false;
+    $prot = ( ( $paths->pages[$pname]['protected'] == 2 && $session->user_logged_in && $session->reg_time + 60*60*24*4 < time() ) || $paths->pages[$pname]['protected'] == 1) ? true : false;
+    
+    if(!$session->get_permissions('protect')) return('Insufficient access rights');
+    if(!$wiki) return('Page protection only has an effect when Wiki Mode is enabled.');
+    if(!preg_match('#^([0-9]+){1}$#', (string)$level)) return('Invalid $level parameter.');
+    
+    if($reason!='NO_REASON') {
+      switch($level)
+      {
+        case 0:
+          $q = 'INSERT INTO '.table_prefix.'logs(time_id,date_string,log_type,action,author,page_id,namespace,edit_summary) VALUES('.time().', \''.date('d M Y h:i a').'\', \'page\', \'unprot\', \''.$session->username.'\', \''.$page_id.'\', \''.$namespace.'\', \''.$db->escape(htmlspecialchars($reason)).'\');';
+          break;
+        case 1:
+          $q = 'INSERT INTO '.table_prefix.'logs(time_id,date_string,log_type,action,author,page_id,namespace,edit_summary) VALUES('.time().', \''.date('d M Y h:i a').'\', \'page\', \'prot\', \''.$session->username.'\', \''.$page_id.'\', \''.$namespace.'\', \''.$db->escape(htmlspecialchars($reason)).'\');';
+          break;
+        case 2:
+          $q = 'INSERT INTO '.table_prefix.'logs(time_id,date_string,log_type,action,author,page_id,namespace,edit_summary) VALUES('.time().', \''.date('d M Y h:i a').'\', \'page\', \'semiprot\', \''.$session->username.'\', \''.$page_id.'\', \''.$namespace.'\', \''.$db->escape(htmlspecialchars($reason)).'\');';
+          break;
+        default:
+          return 'PageUtils::protect(): Invalid value for $level';
+          break;
+      }
+      if(!$db->sql_query($q)) $db->_die('The log entry for the page protection could not be inserted.');
+    }
+    
+    $q = $db->sql_query('UPDATE '.table_prefix.'pages SET protected='.$_POST['level'].' WHERE urlname=\''.$page_id.'\' AND namespace=\''.$namespace.'\';');
+    if(!$q) $db->_die('The pages table was not updated.');
+    
+    return('good');
+  }
+  
+  /**
+   * Generates an HTML table with history information in it.
+   * @param $page_id the page ID
+   * @param $namespace the namespace
+   * @return string
+   */
+  
+  function histlist($page_id, $namespace)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    if(!$session->get_permissions('history_view'))
+      return 'Access denied';
+    
+    ob_start();
+    
+    $pname = $paths->nslist[$namespace] . $page_id;
+    $wiki = ( ( $paths->pages[$pname]['wiki_mode'] == 2 && getConfig('wiki_mode') == '1') || $paths->pages[$pname]['wiki_mode'] == 1) ? true : false;
+    $prot = ( ( $paths->pages[$pname]['protected'] == 2 && $session->user_logged_in && $session->reg_time + 60*60*24*4 < time() ) || $paths->pages[$pname]['protected'] == 1) ? true : false;
+    
+    $q = 'SELECT time_id,date_string,page_id,namespace,author,edit_summary,minor_edit FROM '.table_prefix.'logs WHERE log_type=\'page\' AND action=\'edit\' AND page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' ORDER BY time_id DESC;';
+    if(!$db->sql_query($q)) $db->_die('The history data for the page "'.$paths->cpage['name'].'" could not be selected.');
+    echo 'History of edits and actions<h3>Edits:</h3>';
+    $numrows = $db->numrows();
+    if($numrows < 1) echo 'No history entries in this category.';
+    else
+    {
+      
+      echo '<form action="'.makeUrlNS($namespace, $page_id, 'do=diff').'" onsubmit="ajaxHistDiff(); return false;" method="get">
+            <input type="submit" value="Compare selected revisions" />
+            <br /><span>&nbsp;</span>
+            <div class="tblholder">
+            <table border="0" width="100%" cellspacing="1" cellpadding="4">
+            <tr>
+              <th colspan="2">Diff</th>
+              <th>Date/time</th>
+              <th>User</th>
+              <th>Edit summary</th>
+              <th>Minor</th>
+              <th colspan="3">Actions</th>
+            </tr>'."\n"."\n";
+      $cls = 'row2';
+      $ticker = 0;
+      
+      while($r = $db->fetchrow()) {
+        
+        $ticker++;
+        
+        if($cls == 'row2') $cls = 'row1';
+        else $cls = 'row2';
+        
+        echo '<tr>'."\n";
+        
+        // Diff selection
+        if($ticker == 1)
+        {
+          $s1 = '';
+          $s2 = 'checked="checked" ';
+        }
+        elseif($ticker == 2)
+        {
+          $s1 = 'checked="checked" ';
+          $s2 = '';
+        }
+        else
+        {
+          $s1 = '';
+          $s2 = '';
+        }
+        if($ticker > 1)        echo '<td class="'.$cls.'" style="padding: 0;"><input '.$s1.'name="diff1" type="radio" value="'.$r['time_id'].'" id="diff1_'.$r['time_id'].'" class="clsDiff1Radio" onclick="selectDiff1Button(this);" /></td>'."\n"; else echo '<td class="'.$cls.'"></td>';
+        if($ticker < $numrows) echo '<td class="'.$cls.'" style="padding: 0;"><input '.$s2.'name="diff2" type="radio" value="'.$r['time_id'].'" id="diff2_'.$r['time_id'].'" class="clsDiff2Radio" onclick="selectDiff2Button(this);" /></td>'."\n"; else echo '<td class="'.$cls.'"></td>';
+        
+        // Date and time
+        echo '<td class="'.$cls.'">'.$r['date_string'].'</td class="'.$cls.'">'."\n";
+        
+        // User
+        if($session->get_permissions('mod_misc') && preg_match('#^([0-9]*){1,3}\.([0-9]*){1,3}\.([0-9]*){1,3}\.([0-9]*){1,3}$#', $r['author'])) $rc = ' style="cursor: pointer;" title="Click cell background for reverse DNS info" onclick="ajaxReverseDNS(this, \''.$r['author'].'\');"';
+        else $rc = '';
+        echo '<td class="'.$cls.'"'.$rc.'><a href="'.makeUrlNS('User', $r['author']).'" ';
+        if(!isPage($paths->nslist['User'] . $r['author'])) echo 'class="wikilink-nonexistent"';
+        echo '>'.$r['author'].'</a></td class="'.$cls.'">'."\n";
+        
+        // Edit summary
+        echo '<td class="'.$cls.'">'.$r['edit_summary'].'</td>'."\n";
+        
+        // Minor edit
+        echo '<td class="'.$cls.'" style="text-align: center;">'. (( $r['minor_edit'] ) ? 'M' : '' ) .'</td>'."\n";
+        
+        // Actions!
+        echo '<td class="'.$cls.'" style="text-align: center;"><a href="'.makeUrlNS($namespace, $page_id, 'oldid='.$r['time_id']).'" onclick="ajaxHistView(\''.$r['time_id'].'\'); return false;">View revision</a></td>'."\n";
+        echo '<td class="'.$cls.'" style="text-align: center;"><a href="'.makeUrl($paths->nslist['Special'].'Contributions/'.$r['author']).'">View user contribs</a></td>'."\n";
+        echo '<td class="'.$cls.'" style="text-align: center;"><a href="'.makeUrlNS($namespace, $page_id, 'do=rollback&amp;id='.$r['time_id']).'" onclick="ajaxRollback(\''.$r['time_id'].'\'); return false;">Revert to this revision</a></td>'."\n";
+        
+        echo '</tr>'."\n"."\n";
+        
+      }
+      echo '</table>
+            </div>
+            <br />
+            <input type="hidden" name="do" value="diff" />
+            <input type="submit" value="Compare selected revisions" />
+            </form>
+            <script type="text/javascript">buildDiffList();</script>';
+    }
+    $db->free_result();
+    echo '<h3>Other changes:</h3>';
+    $q = 'SELECT time_id,action,date_string,page_id,namespace,author,edit_summary,minor_edit FROM '.table_prefix.'logs WHERE log_type=\'page\' AND action!=\'edit\' AND page_id=\''.$paths->cpage['urlname_nons'].'\' AND namespace=\''.$paths->namespace.'\' ORDER BY time_id DESC;';
+    if(!$db->sql_query($q)) $db->_die('The history data for the page "'.$paths->cpage['name'].'" could not be selected.');
+    if($db->numrows() < 1) echo 'No history entries in this category.';
+    else {
+      
+      echo '<div class="tblholder"><table border="0" width="100%" cellspacing="1" cellpadding="4"><tr><th>Date/time</th><th>User</th><th>Minor</th><th>Action taken</th><th>Extra info</th><th colspan="2"></th></tr>';
+      $cls = 'row2';
+      while($r = $db->fetchrow()) {
+        
+        if($cls == 'row2') $cls = 'row1';
+        else $cls = 'row2';
+        
+        echo '<tr>';
+        
+        // Date and time
+        echo '<td class="'.$cls.'">'.$r['date_string'].'</td class="'.$cls.'">';
+        
+        // User
+        echo '<td class="'.$cls.'"><a href="'.makeUrlNS('User', $r['author']).'" ';
+        if(!isPage($paths->nslist['User'] . $r['author'])) echo 'class="wikilink-nonexistent"';
+        echo '>'.$r['author'].'</a></td class="'.$cls.'">';
+        
+        
+        // Minor edit
+        echo '<td class="'.$cls.'" style="text-align: center;">'. (( $r['minor_edit'] ) ? 'M' : '' ) .'</td>';
+        
+        // Action taken
+        echo '<td class="'.$cls.'">';
+        if    ($r['action']=='prot')     echo 'Protected page</td><td class="'.$cls.'">Reason: '.$r['edit_summary'];
+        elseif($r['action']=='unprot')   echo 'Unprotected page</td><td class="'.$cls.'">Reason: '.$r['edit_summary'];
+        elseif($r['action']=='semiprot') echo 'Semi-protected page</td><td class="'.$cls.'">Reason: '.$r['edit_summary'];
+        elseif($r['action']=='rename')   echo 'Renamed page</td><td class="'.$cls.'">Old title: '.$r['edit_summary'];
+        elseif($r['action']=='create')   echo 'Created page</td><td class="'.$cls.'">';
+        elseif($r['action']=='delete')   echo 'Deleted page</td><td class="'.$cls.'">';
+        elseif($r['action']=='reupload') echo 'Uploaded new file version</td><td class="'.$cls.'">Reason: '.$r['edit_summary'];
+        echo '</td>';
+        
+        // Actions!
+        echo '<td class="'.$cls.'" style="text-align: center;"><a href="'.makeUrl($paths->nslist['Special'].'Contributions/'.$r['author']).'">View user contribs</a></td>';
+        echo '<td class="'.$cls.'" style="text-align: center;"><a href="'.makeUrlNS($namespace, $page_id, 'do=rollback&amp;id='.$r['time_id']).'" onclick="ajaxRollback(\''.$r['time_id'].'\'); return false;">Revert action</a></td>';
+        
+        //echo '(<a href="#" onclick="ajaxRollback(\''.$r['time_id'].'\'); return false;">rollback</a>) <i>'.$r['date_string'].'</i> '.$r['author'].' (<a href="'.makeUrl($paths->nslist['User'].$r['author']).'">Userpage</a>, <a href="'.makeUrl($paths->nslist['Special'].'Contributions/'.$r['author']).'">Contrib</a>): ';
+        
+        if($r['minor_edit']) echo '<b> - minor edit</b>';
+        echo '<br />';
+        
+        echo '</tr>';
+      }
+      echo '</table></div>';
+    }
+    $db->free_result();
+    $ret = ob_get_contents();
+    ob_end_clean();
+    return $ret;
+  }
+  
+  /**
+   * Rolls back a logged action
+   * @param $id the time ID, a.k.a. the primary key in the logs table
+   * @return string
+   */
+   
+  function rollback($id)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(!$session->get_permissions('history_rollback')) return('You are not authorized to perform rollbacks.');
+    if(!preg_match('#^([0-9]+)$#', (string)$id)) return('The value "id" on the query string must be an integer.');
+    $e = $db->sql_query('SELECT log_type,action,date_string,page_id,namespace,page_text,char_tag,author,edit_summary FROM '.table_prefix.'logs WHERE time_id='.$id.';');
+    if(!$e) $db->_die('The rollback data could not be selected.');
+    $rb = $db->fetchrow();
+    $db->free_result();
+    switch($rb['log_type']) {
+      case "page":
+        switch($rb['action']) {
+          case "edit":
+            $t = $db->escape($rb['page_text']);
+            $e = $db->sql_query('UPDATE '.table_prefix.'page_text SET page_text=\''.$t.'\',char_tag=\''.$rb['char_tag'].'\' WHERE page_id=\''.$rb['page_id'].'\' AND namespace=\''.$rb['namespace'].'\'');
+            if(!$e) return("An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace());
+            else return('The page "'.$paths->pages[$paths->nslist[$rb['namespace']].$rb['page_id']]['name'].'" has been rolled back to the state it was in on '.$rb['date_string'].'.');
+            break;
+          case "rename":
+            $t = $db->escape($rb['edit_summary']);
+            $e = $db->sql_query('UPDATE '.table_prefix.'pages SET name=\''.$t.'\' WHERE urlname=\''.$rb['page_id'].'\' AND namespace=\''.$rb['namespace'].'\'');
+            if(!$e) return("An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace());
+            else return('The page "'.$paths->pages[$paths->nslist[$rb['namespace']].$rb['page_id']]['name'].'" has been rolled back to the name it had ("'.$rb['edit_summary'].'") before '.$rb['date_string'].'.');
+            break;
+          case "prot":
+            $e = $db->sql_query('UPDATE '.table_prefix.'pages SET protected=0 WHERE urlname=\''.$rb['page_id'].'\' AND namespace=\''.$rb['namespace'].'\'');
+            if(!$e) return("An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace());
+            else return('The page "'.$paths->pages[$paths->nslist[$rb['namespace']].$rb['page_id']]['name'].'" has been unprotected according to the log created at '.$rb['date_string'].'.');
+            break;
+          case "semiprot":
+            $e = $db->sql_query('UPDATE '.table_prefix.'pages SET protected=0 WHERE urlname=\''.$rb['page_id'].'\' AND namespace=\''.$rb['namespace'].'\'');
+            if(!$e) return("An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace());
+            else return('The page "'.$paths->pages[$paths->nslist[$rb['namespace']].$rb['page_id']]['name'].'" has been unprotected according to the log created at '.$rb['date_string'].'.');
+            break;
+          case "unprot":
+            $e = $db->sql_query('UPDATE '.table_prefix.'pages SET protected=1 WHERE urlname=\''.$rb['page_id'].'\' AND namespace=\''.$rb['namespace'].'\'');
+            if(!$e) return("An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace());
+            else return('The page "'.$paths->pages[$paths->nslist[$rb['namespace']].$rb['page_id']]['name'].'" has been protected according to the log created at '.$rb['date_string'].'.');
+            break;
+          case "delete":
+            if(!$session->get_permissions('history_rollback_extra')) return('Administrative privileges are required for page undeletion.');
+            if(isset($paths->pages[$paths->cpage['urlname']])) return('You cannot raise a dead page that is alive.');
+            $name = str_replace('_', ' ', $rb['page_id']);
+            $e = $db->sql_query('INSERT INTO '.table_prefix.'pages(name,urlname,namespace) VALUES( \''.$name.'\', \''.$rb['page_id'].'\',\''.$rb['namespace'].'\' )');if(!$e) return("An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace());
+            $e = $db->sql_query('SELECT page_text,char_tag FROM '.table_prefix.'logs WHERE page_id=\''.$rb['page_id'].'\' AND namespace=\''.$rb['namespace'].'\' AND log_type=\'page\' AND action=\'edit\' ORDER BY time_id DESC;'); if(!$e) return("An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace());
+            $r = $db->fetchrow();
+            $e = $db->sql_query('INSERT INTO '.table_prefix.'page_text(page_id,namespace,page_text,char_tag) VALUES(\''.$rb['page_id'].'\',\''.$rb['namespace'].'\',\''.$db->escape($r['page_text']).'\',\''.$r['char_tag'].'\')'); if(!$e) return("An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace());
+            return('The page "'.$name.'" has been undeleted according to the log created at '.$rb['date_string'].'.');
+            break;
+          case "reupload":
+            if(!$session->get_permissions('history_rollbacks_extra')) return('Administrative privileges are required for file rollbacks.');
+            $newtime = time();
+            $newdate = date('d M Y h:i a');
+            if(!$db->sql_query('UPDATE '.table_prefix.'logs SET time_id='.$newtime.',date_string=\''.$newdate.'\' WHERE time_id='.$id)) return('Error during query: '.mysql_error());
+            if(!$db->sql_query('UPDATE '.table_prefix.'files SET time_id='.$newtime.' WHERE time_id='.$id)) return('Error during query: '.mysql_error());
+            return('The file has been rolled back to the version uploaded on '.date('d M Y h:i a', (int)$id).'.');
+            break;
+          default:
+            return('Rollback of the action "'.$rb['action'].'" is not yet supported.');
+            break;
+        }
+        break;
+      case "security":
+      case "login":
+        return('A '.$rb['log_type'].'-related log entry cannot be rolled back.');
+        break;
+      default:
+        return('Unknown log entry type: "'.$rb['log_type'].'"');
+    }
+  }
+  
+  /**
+   * Posts a comment.
+   * @param $page_id the page ID
+   * @param $namespace the namespace
+   * @param $name the name of the person posting, defaults to current username/IP
+   * @param $subject the subject line of the comment
+   * @param $text the comment text
+   * @return string javascript code
+   */
+   
+  function addcomment($page_id, $namespace, $name, $subject, $text, $captcha_code = false, $captcha_id = false)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $_ob = '';
+    if(!$session->get_permissions('post_comments'))
+      return 'Access denied';
+    if(getConfig('comments_need_login') == '2' && !$session->user_logged_in) _die('Access denied to post comments: you need to be logged in first.');
+    if(getConfig('comments_need_login') == '1' && !$session->user_logged_in)
+    {
+      if(!$captcha_code || !$captcha_id) _die('BUG: PageUtils::addcomment: no CAPTCHA data passed to method');
+      $result = $session->get_captcha($captcha_id);
+      if($captcha_code != $result) _die('The confirmation code you entered was incorrect.');
+    }
+    $text = RenderMan::preprocess_text($text);
+    $name = $session->user_logged_in ? RenderMan::preprocess_text($session->username) : RenderMan::preprocess_text($name);
+    $subj = RenderMan::preprocess_text($subject);
+    if(getConfig('approve_comments')=='1') $appr = '0'; else $appr = '1';
+    $q = 'INSERT INTO '.table_prefix.'comments(page_id,namespace,subject,comment_data,name,user_id,approved,time) VALUES(\''.$page_id.'\',\''.$namespace.'\',\''.$subj.'\',\''.$text.'\',\''.$name.'\','.$session->user_id.','.$appr.','.time().')';
+    $e = $db->sql_query($q);
+    if(!$e) die('alert(unescape(\''.rawurlencode('Error inserting comment data: '.mysql_error().'\n\nQuery:\n'.$q).'\'))');
+    else $_ob .= '<div class="info-box">Your comment has been posted.</div>';
+    return PageUtils::comments($page_id, $namespace, false, Array(), $_ob);
+  }
+  
+  /**
+   * Generates partly-compiled HTML/Javascript code to be eval'ed by the user's browser to display comments
+   * @param $page_id the page ID
+   * @param $namespace the namespace
+   * @param $action administrative action to perform, default is false
+   * @param $flags additional info for $action, shouldn't be used except when deleting/approving comments, etc.
+   * @param $_ob text to prepend to output, used by PageUtils::addcomment
+   * @return array
+   * @access private
+   */
+   
+  function comments_raw($page_id, $namespace, $action = false, $flags = Array(), $_ob = '')
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    $pname = $paths->nslist[$namespace] . $page_id;
+    
+    ob_start();
+    
+    if($action && $session->get_permissions('mod_comments')) // Nip hacking attempts in the bud
+    {
+      switch($action) {
+      case "delete":
+        if(isset($flags['id']))
+        {
+          $q = 'DELETE FROM '.table_prefix.'comments WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND comment_id='.intval($flags['id']).' LIMIT 1;';
+        } else {
+          $n = $db->escape($flags['name']);
+          $s = $db->escape($flags['subj']);
+          $t = $db->escape($flags['text']);
+          $q = 'DELETE FROM '.table_prefix.'comments WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND name=\''.$n.'\' AND subject=\''.$s.'\' AND comment_data=\''.$t.'\' LIMIT 1;';
+        }
+        $e=$db->sql_query($q);
+        if(!$e) die('alert(unesape(\''.rawurlencode('Error during query: '.mysql_error().'\n\nQuery:\n'.$q).'\'));');
+        break;
+      case "approve":
+        if(isset($flags['id']))
+        {
+          $where = 'comment_id='.intval($flags['id']);
+        } else {
+          $n = $db->escape($flags['name']);
+          $s = $db->escape($flags['subj']);
+          $t = $db->escape($flags['text']);
+          $where = 'name=\''.$n.'\' AND subject=\''.$s.'\' AND comment_data=\''.$t.'\'';
+        }
+        $q = 'SELECT approved FROM '.table_prefix.'comments WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND '.$where.' LIMIT 1;';
+        $e = $db->sql_query($q);
+        if(!$e) die('alert(unesape(\''.rawurlencode('Error selecting approval status: '.mysql_error().'\n\nQuery:\n'.$q).'\'));');
+        $r = $db->fetchrow();
+        $db->free_result();
+        $a = ( $r['approved'] ) ? '0' : '1';
+        $q = 'UPDATE '.table_prefix.'comments SET approved='.$a.' WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND '.$where.';';
+        $e=$db->sql_query($q);
+        if(!$e) die('alert(unesape(\''.rawurlencode('Error during query: '.mysql_error().'\n\nQuery:\n'.$q).'\'));');
+        if($a=='1') $v = 'Unapprove';
+        else $v = 'Approve';
+        echo 'document.getElementById("mdgApproveLink'.$_GET['id'].'").innerHTML="'.$v.'";';
+        break;
+      }
+    }
+    
+    if(!defined('ENANO_TEMPLATE_LOADED'))
+    {
+      $template->load_theme($session->theme, $session->style);
+    }
+    
+    $tpl = $template->makeParser('comment.tpl');
+    
+    $e = $db->sql_query('SELECT * FROM '.table_prefix.'comments WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND approved=0;');
+    if(!$e) $db->_die('The comment text data could not be selected.');
+    $num_unapp = $db->numrows();
+    $db->free_result();
+    $e = $db->sql_query('SELECT * FROM '.table_prefix.'comments WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND approved=1;');
+    if(!$e) $db->_die('The comment text data could not be selected.');
+    $num_app = $db->numrows();
+    $db->free_result();
+    $lq = $db->sql_query('SELECT c.comment_id,c.subject,c.name,c.comment_data,c.approved,c.time,c.user_id,u.user_level,u.signature
+                  FROM '.table_prefix.'comments AS c
+                  LEFT JOIN '.table_prefix.'users AS u
+                    ON c.user_id=u.user_id
+                  WHERE page_id=\''.$page_id.'\'
+                  AND namespace=\''.$namespace.'\' ORDER BY c.time ASC;');
+    if(!$lq) _die('The comment text data could not be selected. '.mysql_error());
+    $_ob .= '<h3>Article Comments</h3>';
+    $n = ( $session->get_permissions('mod_comments')) ? $db->numrows() : $num_app;
+    if($n==1) $s = 'is '.$n.' comment'; else $s = 'are '.$n.' comments';
+    if($n < 1)
+    {
+      $_ob .= '<p>There are currently no comments on this '.strtolower($namespace).'';
+      if($namespace != 'Article') $_ob .= ' page';
+      $_ob .= '.</p>';
+    } else $_ob .= '<p>There '.$s.' on this article.</p>';
+    if($session->get_permissions('mod_comments') && $num_unapp > 0) $_ob .= ' <span style="color: #D84308">'.$num_unapp.' of those are unapproved.</span>';
+    elseif(!$session->get_permissions('mod_comments') && $num_unapp > 0) { $u = ($num_unapp == 1) ? "is $num_unapp comment" : "are $num_unapp comments"; $_ob .= ' However, there ' . $u . ' awating approval.'; }
+    $list = 'list = { ';
+    // _die(htmlspecialchars($ttext));
+    $i = -1;
+    while($row = $db->fetchrow($lq))
+    {
+      $i++;
+      $strings = Array();
+      $bool = Array();
+      if($session->get_permissions('mod_comments') || $row['approved']) {
+        $list .= $i . ' : { \'comment\' : unescape(\''.rawurlencode($row['comment_data']).'\'), \'name\' : unescape(\''.rawurlencode($row['name']).'\'), \'subject\' : unescape(\''.rawurlencode($row['subject']).'\'), }, ';
+        
+        // Comment ID (used in the Javascript apps)
+        $strings['ID'] = (string)$i;
+        
+        // Determine the name, and whether to link to the user page or not
+        $name = '';
+        if($row['user_id'] > 0) $name .= '<a href="'.makeUrlNS('User', str_replace(' ', '_', $row['name'])).'">';
+        $name .= $row['name'];
+        if($row['user_id'] > 0) $name .= '</a>';
+        $strings['NAME'] = $name; unset($name);
+        
+        // Subject
+        $s = $row['subject'];
+        if(!$row['approved']) $s .= ' <span style="color: #D84308">(Unapproved)</span>';
+        $strings['SUBJECT'] = $s;
+        
+        // Date and time
+        $strings['DATETIME'] = date('F d, Y h:i a', $row['time']);
+        
+        // User level
+        switch($row['user_level'])
+        {
+          default:
+          case USER_LEVEL_GUEST:
+            $l = 'Guest';
+            break;
+          case USER_LEVEL_MEMBER:
+            $l = 'Member';
+            break;
+          case USER_LEVEL_MOD:
+            $l = 'Moderator';
+            break;
+          case USER_LEVEL_ADMIN:
+            $l = 'Administrator';
+            break;
+        }
+        $strings['USER_LEVEL'] = $l; unset($l);
+        
+        // The actual comment data
+        $strings['DATA'] = RenderMan::render($row['comment_data']);
+        
+        if($session->get_permissions('edit_comments'))
+        {
+          // Edit link
+          $strings['EDIT_LINK'] = '<a href="'.makeUrlNS($namespace, $page_id, 'do=comments&amp;sub=editcomment&amp;id='.$row['comment_id']).'" onclick="editComment(\''.$i.'\'); return false;" id="editbtn_'.$i.'">edit</a>';
+        
+          // Delete link
+          $strings['DELETE_LINK'] = '<a href="'.makeUrlNS($namespace, $page_id, 'do=comments&amp;sub=deletecomment&amp;id='.$row['comment_id']).'" onclick="ajaxDeleteComment(\''.$i.'\'); return false;">delete</a>';
+        }
+        else
+        {
+          // Edit link
+          $strings['EDIT_LINK'] = '';
+        
+          // Delete link
+          $strings['DELETE_LINK'] = '';
+        }
+        
+        // Send PM link
+        $strings['SEND_PM_LINK'] = ( $session->user_logged_in && $row['user_id'] > 0 ) ? '<a href="'.makeUrlNS('Special', 'PrivateMessages/Compose/To/'.$row['name']).'">Send private message</a><br />' : '';
+        
+        // Add Buddy link
+        $strings['ADD_BUDDY_LINK'] = ( $session->user_logged_in && $row['user_id'] > 0 ) ? '<a href="'.makeUrlNS('Special', 'PrivateMessages/FriendList/Add/'.$row['name']).'">Add to buddy list</a>' : '';
+        
+        // Mod links
+        $applink = '';
+        $applink .= '<a href="'.makeUrlNS($namespace, $page_id, 'do=comments&amp;sub=admin&amp;action=approve&amp;id='.$row['comment_id']).'" onclick="ajaxCommentAdmin(\'approve\', \''.$i.'\'); return false;" id="mdgApproveLink'.$i.'">';
+        if($row['approved']) $applink .= 'Unapprove';
+        else $applink .= 'Approve';
+        $applink .= '</a>';
+        $strings['MOD_APPROVE_LINK'] = $applink; unset($applink);
+        $strings['MOD_DELETE_LINK'] = '<a href="'.makeUrlNS($namespace, $page_id, 'do=comments&amp;sub=admin&amp;action=delete&amp;id='.$row['comment_id']).'" onclick="ajaxCommentAdmin(\'delete\', \''.$i.'\'); return false;">Delete</a>';
+        
+        // Signature
+        $strings['SIGNATURE'] = '';
+        if($row['signature'] != '') $strings['SIGNATURE'] = RenderMan::render($row['signature']);
+        
+        $bool['auth_mod'] = ($session->get_permissions('mod_comments')) ? true : false;
+        $bool['can_edit'] = ( ( $session->user_logged_in && $row['name'] == $session->username && $session->get_permissions('edit_comments') ) || $session->get_permissions('mod_comments') ) ? true : false;
+        $bool['signature'] = ( $strings['SIGNATURE'] == '' ) ? false : true;
+        
+        // Done processing and compiling, now let's cook it into HTML
+        $tpl->assign_vars($strings);
+        $tpl->assign_bool($bool);
+        $_ob .= $tpl->run();
+      }
+    }
+    if(getConfig('comments_need_login') != '2' || $session->user_logged_in)
+    {
+      if(!$session->get_permissions('post_comments'))
+      {
+        $_ob .= '<h3>Got something to say?</h3><p>Access to post comments on this page is denied.</p>';
+      }
+      else
+      {
+        $_ob .= '<h3>Got something to say?</h3>If you have comments or suggestions on this article, you can shout it out here.';
+        if(getConfig('approve_comments')=='1') $_ob .= '  Before your comment will be visible to the public, a moderator will have to approve it.';
+        if(getConfig('comments_need_login') == '1' && !$session->user_logged_in) $_ob .= ' Because you are not logged in, you will need to enter a visual confirmation before your comment will be posted.';
+        $sn = $session->user_logged_in ? $session->username . '<input name="name" id="mdgScreenName" type="hidden" value="'.$session->username.'" />' : '<input name="name" id="mdgScreenName" type="text" size="35" />';
+        $_ob .= '  <a href="#" id="mdgCommentFormLink" style="display: none;" onclick="document.getElementById(\'mdgCommentForm\').style.display=\'block\';this.style.display=\'none\';return false;">Leave a comment...</a>
+        <div id="mdgCommentForm">
+        <h3>Comment form</h3>
+        <form action="'.makeUrlNS($namespace, $page_id, 'do=comments&amp;sub=postcomment').'" method="post" style="margin-left: 1em">
+        <table border="0">
+        <tr><td>Your name or screen name:</td><td>'.$sn.'</td></tr>
+        <tr><td>Comment subject:</td><td><input name="subj" id="mdgSubject" type="text" size="35" /></td></tr>';
+        if(getConfig('comments_need_login') == '1' && !$session->user_logged_in)
+        {
+          $session->kill_captcha();
+          $captcha = $session->make_captcha();
+          $_ob .= '<tr><td>Visual confirmation:<br /><small>Please enter the code you see on the right.</small></td><td><img src="'.makeUrlNS('Special', 'Captcha/'.$captcha).'" alt="Visual confirmation" style="cursor: pointer;" onclick="this.src = \''.makeUrlNS("Special", "Captcha/".$captcha).'/\'+Math.floor(Math.random() * 100000);" /><input name="captcha_id" id="mdgCaptchaID" type="hidden" value="'.$captcha.'" /><br />Code: <input name="captcha_input" id="mdgCaptchaInput" type="text" size="10" /><br /><small><script type="text/javascript">document.write("If you can\'t read the code, click on the image to generate a new one.");</script><noscript>If you can\'t read the code, please refresh this page to generate a new one.</noscript></small></td></tr>';
+        }
+        $_ob .= '
+        <tr><td valign="top">Comment text:<br />(most HTML will be stripped)</td><td><textarea name="text" id="mdgCommentArea" rows="10" cols="40"></textarea></td></tr>
+        <tr><td colspan="2" style="text-align: center;"><input type="submit" value="Submit Comment" /></td></tr>
+        </table>
+        </form>
+        </div>';
+      }
+    } else {
+      $_ob .= '<h3>Got something to say?</h3><p>You need to be logged in to post comments. <a href="'.makeUrlNS('Special', 'Login/'.$pname.'%2523comments').'">Log in</a></p>';
+    }
+    $list .= '};';
+    echo 'document.getElementById(\'ajaxEditContainer\').innerHTML = unescape(\''. rawurlencode($_ob) .'\');
+    ' . $list;
+    echo 'Fat.fade_all(); document.getElementById(\'mdgCommentForm\').style.display = \'none\'; document.getElementById(\'mdgCommentFormLink\').style.display="inline";';
+    
+    $ret = ob_get_contents();
+    ob_end_clean();
+    return Array($ret, $_ob);
+    
+  }
+  
+  /**
+   * Generates ready-to-execute Javascript code to be eval'ed by the user's browser to display comments
+   * @param $page_id the page ID
+   * @param $namespace the namespace
+   * @param $action administrative action to perform, default is false
+   * @param $flags additional info for $action, shouldn't be used except when deleting/approving comments, etc.
+   * @param $_ob text to prepend to output, used by PageUtils::addcomment
+   * @return string
+   */
+   
+  function comments($page_id, $namespace, $action = false, $id = -1, $_ob = '')
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $r = PageUtils::comments_raw($page_id, $namespace, $action, $id, $_ob);
+    return $r[0];
+  }
+  
+  /**
+   * Generates HTML code for comments - used in browser compatibility mode
+   * @param $page_id the page ID
+   * @param $namespace the namespace
+   * @param $action administrative action to perform, default is false
+   * @param $flags additional info for $action, shouldn't be used except when deleting/approving comments, etc.
+   * @param $_ob text to prepend to output, used by PageUtils::addcomment
+   * @return string
+   */
+  
+  function comments_html($page_id, $namespace, $action = false, $id = -1, $_ob = '')
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $r = PageUtils::comments_raw($page_id, $namespace, $action, $id, $_ob);
+    return $r[1];
+  }
+  
+  /**
+   * Updates comment data.
+   * @param $page_id the page ID
+   * @param $namespace the namespace
+   * @param $subject new subject
+   * @param $text new text
+   * @param $old_subject the old subject, unprocessed and identical to the value in the DB
+   * @param $old_text the old text, unprocessed and identical to the value in the DB
+   * @param $id the javascript list ID, used internally by the client-side app
+   * @return string
+   */
+  
+  function savecomment($page_id, $namespace, $subject, $text, $old_subject, $old_text, $id = -1)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(!$session->get_permissions('edit_comments'))
+      return 'result="BAD";error="Access denied"';
+    // Avoid SQL injection
+    $old_text    = $db->escape($old_text);
+    $old_subject = $db->escape($old_subject);
+    // Safety check - username/login
+    if(!$session->get_permissions('mod_comments')) // allow mods to edit comments
+    {
+      if(!$session->user_logged_in) _die('AJAX comment save safety check failed because you are not logged in. Sometimes this can happen because you are using a browser that does not send cookies as part of AJAX requests.<br /><br />Please log in and try again.');
+      $q = 'SELECT c.name FROM '.table_prefix.'comments c, '.table_prefix.'users u WHERE comment_data=\''.$old_text.'\' AND subject=\''.$old_subject.'\' AND page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND u.user_id=c.user_id;';
+      $s = $db->sql_query($q);
+      if(!$s) _die('SQL error during safety check: '.mysql_error().'<br /><br />Attempted SQL:<br /><pre>'.htmlspecialchars($q).'</pre>');
+      $r = $db->fetchrow($s);
+      $db->free_result();
+      if($db->numrows() < 1 || $r['name'] != $session->username) _die('Safety check failed, probably due to a hacking attempt.');
+    }
+    $s = RenderMan::preprocess_text($subject);
+    $t = RenderMan::preprocess_text($text);
+    $sql  = 'UPDATE '.table_prefix.'comments SET subject=\''.$s.'\',comment_data=\''.$t.'\' WHERE comment_data=\''.$old_text.'\' AND subject=\''.$old_subject.'\' AND page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\'';
+    $result = $db->sql_query($sql);
+    if($result)
+    {
+      return 'result="GOOD";
+                      list['.$id.'][\'subject\'] = unescape(\''.str_replace('%5Cn', '%0A', rawurlencode(str_replace('{{EnAnO:Newline}}', '\\n', stripslashes(str_replace('\\n', '{{EnAnO:Newline}}', $s))))).'\');
+                      list['.$id.'][\'comment\'] = unescape(\''.str_replace('%5Cn', '%0A', rawurlencode(str_replace('{{EnAnO:Newline}}', '\\n', stripslashes(str_replace('\\n', '{{EnAnO:Newline}}', $t))))).'\'); id = '.$id.';
+      s = unescape(\''.rawurlencode($s).'\');
+      t = unescape(\''.str_replace('%5Cn', '<br \\/>', rawurlencode(RenderMan::render(str_replace('{{EnAnO:Newline}}', "\n", stripslashes(str_replace('\\n', '{{EnAnO:Newline}}', $t)))))).'\');';
+    }
+    else
+    {
+      return 'result="BAD"; error=unescape("'.rawurlencode('Enano encountered a problem whilst saving the comment.
+      Performed SQL:
+      '.$sql.'
+    
+      Error returned by MySQL: '.mysql_error()).'");';
+    }
+  }
+  
+  /**
+   * Updates comment data using the comment_id column instead of the old, messy way
+   * @param $page_id the page ID
+   * @param $namespace the namespace
+   * @param $subject new subject
+   * @param $text new text
+   * @param $id the comment ID (primary key in enano_comments table)
+   * @return string
+   */
+  
+  function savecomment_neater($page_id, $namespace, $subject, $text, $id)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(!is_int($id)) die('PageUtils::savecomment: $id is not an integer, aborting for safety');
+    if(!$session->get_permissions('edit_comments'))
+      return 'Access denied';
+    // Safety check - username/login
+    if(!$session->get_permissions('mod_comments')) // allow mods to edit comments
+    {
+      if(!$session->user_logged_in) _die('AJAX comment save safety check failed because you are not logged in. Sometimes this can happen because you are using a browser that does not send cookies as part of AJAX requests.<br /><br />Please log in and try again.');
+      $q = 'SELECT c.name FROM '.table_prefix.'comments c, '.table_prefix.'users u WHERE comment_id='.$id.' AND page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND u.user_id=c.user_id;';
+      $s = $db->sql_query($q);
+      if(!$s) _die('SQL error during safety check: '.mysql_error().'<br /><br />Attempted SQL:<br /><pre>'.htmlspecialchars($q).'</pre>');
+      $r = $db->fetchrow($s);
+      if($db->numrows() < 1 || $r['name'] != $session->username) _die('Safety check failed, probably due to a hacking attempt.');
+      $db->free_result();
+    }
+    $s = RenderMan::preprocess_text($subject);
+    $t = RenderMan::preprocess_text($text);
+    $sql  = 'UPDATE '.table_prefix.'comments SET subject=\''.$s.'\',comment_data=\''.$t.'\' WHERE comment_id='.$id.' AND page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\'';
+    $result = $db->sql_query($sql);
+    if($result)
+    return 'good';
+    else return 'Enano encountered a problem whilst saving the comment.
+    Performed SQL:
+    '.$sql.'
+    
+    Error returned by MySQL: '.mysql_error();
+  }
+  
+  /**
+   * Deletes a comment.
+   * @param $page_id the page ID
+   * @param $namespace the namespace
+   * @param $name the name the user posted under
+   * @param $subj the subject of the comment to be deleted
+   * @param $text the text of the comment to be deleted
+   * @param $id the javascript list ID, used internally by the client-side app
+   * @return string
+   */
+  
+  function deletecomment($page_id, $namespace, $name, $subj, $text, $id)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    if(!$session->get_permissions('edit_comments'))
+      return 'alert("Access to delete/edit comments is denied");';
+    
+    if(!preg_match('#^([0-9]+)$#', (string)$id)) die('$_GET[id] is improperly formed.');
+    $n = $db->escape($name);
+    $s = $db->escape($subj);
+    $t = $db->escape($text);
+    
+    // Safety check - username/login
+    if(!$session->get_permissions('mod_comments')) // allows mods to delete comments
+    {
+      if(!$session->user_logged_in) _die('AJAX comment save safety check failed because you are not logged in. Sometimes this can happen because you are using a browser that does not send cookies as part of AJAX requests.<br /><br />Please log in and try again.');
+      $q = 'SELECT c.name FROM '.table_prefix.'comments c, '.table_prefix.'users u WHERE comment_data=\''.$t.'\' AND subject=\''.$s.'\' AND page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND u.user_id=c.user_id;';
+      $s = $db->sql_query($q);
+      if(!$s) _die('SQL error during safety check: '.mysql_error().'<br /><br />Attempted SQL:<br /><pre>'.htmlspecialchars($q).'</pre>');
+      $r = $db->fetchrow($s);
+      if($db->numrows() < 1 || $r['name'] != $session->username) _die('Safety check failed, probably due to a hacking attempt.');
+      $db->free_result();
+    }
+    $q = 'DELETE FROM '.table_prefix.'comments WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND name=\''.$n.'\' AND subject=\''.$s.'\' AND comment_data=\''.$t.'\' LIMIT 1;';
+    $e=$db->sql_query($q);
+    if(!$e) return('alert(unesape(\''.rawurlencode('Error during query: '.mysql_error().'\n\nQuery:\n'.$q).'\'));');
+    return('good');
+  }
+  
+  /**
+   * Deletes a comment in a cleaner fashion.
+   * @param $page_id the page ID
+   * @param $namespace the namespace
+   * @param $id the comment ID (primary key)
+   * @return string
+   */
+  
+  function deletecomment_neater($page_id, $namespace, $id)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    if(!preg_match('#^([0-9]+)$#', (string)$id)) die('$_GET[id] is improperly formed.');
+    
+    if(!$session->get_permissions('edit_comments'))
+      return 'alert("Access to delete/edit comments is denied");';
+    
+    // Safety check - username/login
+    if(!$session->get_permissions('mod_comments')) // allows mods to delete comments
+    {
+      if(!$session->user_logged_in) _die('AJAX comment save safety check failed because you are not logged in. Sometimes this can happen because you are using a browser that does not send cookies as part of AJAX requests.<br /><br />Please log in and try again.');
+      $q = 'SELECT c.name FROM '.table_prefix.'comments c, '.table_prefix.'users u WHERE comment_id='.$id.' AND page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND u.user_id=c.user_id;';
+      $s = $db->sql_query($q);
+      if(!$s) _die('SQL error during safety check: '.mysql_error().'<br /><br />Attempted SQL:<br /><pre>'.htmlspecialchars($q).'</pre>');
+      $r = $db->fetchrow($s);
+      if($db->numrows() < 1 || $r['name'] != $session->username) _die('Safety check failed, probably due to a hacking attempt.');
+      $db->free_result();
+    }
+    $q = 'DELETE FROM '.table_prefix.'comments WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND comment_id='.$id.' LIMIT 1;';
+    $e=$db->sql_query($q);
+    if(!$e) return('alert(unesape(\''.rawurlencode('Error during query: '.mysql_error().'\n\nQuery:\n'.$q).'\'));');
+    return('good');
+  }
+  
+  /**
+   * Renames a page.
+   * @param $page_id the page ID
+   * @param $namespace the namespace
+   * @param $name the new name for the page
+   * @return string error string or success message
+   */
+   
+  function rename($page_id, $namespace, $name)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    $pname = $paths->nslist[$namespace] . $page_id;
+    
+    $prot = ( ( $paths->pages[$pname]['protected'] == 2 && $session->user_logged_in && $session->reg_time + 60*60*24*4 < time() ) || $paths->pages[$pname]['protected'] == 1) ? true : false;
+    $wiki = ( ( $paths->pages[$pname]['wiki_mode'] == 2 && getConfig('wiki_mode') == '1') || $paths->pages[$pname]['wiki_mode'] == 1) ? true : false;
+    
+    if( empty($name)) die('Name is too short');
+    if( ( $session->get_permissions('rename') && ( ( $prot && $session->get_permissions('even_when_protected') ) || !$prot ) ) && ( $paths->namespace != 'Special' && $paths->namespace != 'Admin' )) {
+      $e = $db->sql_query('INSERT INTO '.table_prefix.'logs(time_id,date_string,log_type,action,page_id,namespace,author,edit_summary) VALUES('.time().', \''.date('d M Y h:i a').'\', \'page\', \'rename\', \''.$paths->cpage['urlname_nons'].'\', \''.$paths->namespace.'\', \''.$session->username.'\', \''.$paths->cpage['name'].'\')');
+      if(!$e) $db->_die('The page title could not be updated.');
+      $e = $db->sql_query('UPDATE '.table_prefix.'pages SET name=\''.$db->escape($name).'\' WHERE urlname=\''.$page_id.'\' AND namespace=\''.$namespace.'\';');
+      if(!$e) $db->_die('The page title could not be updated.');
+      else return('The page "'.$paths->pages[$pname]['name'].'" has been renamed to "'.$name.'". You are encouraged to leave a comment explaining your action.
+
+You will see the change take effect the next time you reload this page.');
+    } else {
+      return('Access is denied.');
+    }
+  }
+  
+  /**
+   * Flushes (clears) the action logs for a given page
+   * @param $page_id the page ID
+   * @param $namespace the namespace
+   * @return string error/success string
+   */
+   
+  function flushlogs($page_id, $namespace)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(!$session->get_permissions('clear_logs')) die('Administrative privileges are required to flush logs, you loser.');
+    $e = $db->sql_query('DELETE FROM '.table_prefix.'logs WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\';');
+    if(!$e) $db->_die('The log entries could not be deleted.');
+    $e = $db->sql_query('SELECT page_text,char_tag FROM '.table_prefix.'page_text WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\';');
+    if(!$e) $db->_die('The current page text could not be selected; as a result, creating the backup of the page failed. Please make a backup copy of the page by clicking Edit this page and then clicking Save Changes.');
+    $row = $db->fetchrow();
+    $db->free_result();
+    $q='INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,page_id,namespace,page_text,char_tag,author,edit_summary,minor_edit) VALUES(\'page\', \'edit\', '.time().', \''.date('d M Y h:i a').'\', \''.$page_id.'\', \''.$namespace.'\', \''.$db->escape($row['page_text']).'\', \''.$row['char_tag'].'\', \''.$session->username.'\', \''."Automatic backup created when logs were purged".'\', '.'false'.');';
+    if(!$db->sql_query($q)) $db->_die('The history (log) entry could not be inserted into the logs table.');
+    return('The logs for this page have been cleared. A backup of this page has been added to the logs table so that this page can be restored in case of vandalism or spam later.');
+  }
+  
+  /**
+   * Deletes a page.
+   * @param $page_id the condemned page ID
+   * @param $namespace the condemned namespace
+   * @return string
+   */
+   
+  function deletepage($page_id, $namespace)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $perms = $session->fetch_page_acl($page_id, $namespace);
+    if(!$perms->get_permissions('delete_page')) die('Administrative privileges are required to delete pages, you loser.');
+    $e = $db->sql_query('INSERT INTO '.table_prefix.'logs(time_id,date_string,log_type,action,page_id,namespace,author) VALUES('.time().', \''.date('d M Y h:i a').'\', \'page\', \'delete\', \''.$page_id.'\', \''.$namespace.'\', \''.$session->username.'\')');
+    if(!$e) $db->_die('The page log entry could not be inserted.');
+    $e = $db->sql_query('DELETE FROM '.table_prefix.'categories WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\'');
+    if(!$e) $db->_die('The page categorization entries could not be deleted.');
+    $e = $db->sql_query('DELETE FROM '.table_prefix.'comments WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\'');
+    if(!$e) $db->_die('The page comments could not be deleted.');
+    $e = $db->sql_query('DELETE FROM '.table_prefix.'page_text WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\'');
+    if(!$e) $db->_die('The page text entry could not be deleted.');
+    $e = $db->sql_query('DELETE FROM '.table_prefix.'pages WHERE urlname=\''.$page_id.'\' AND namespace=\''.$namespace.'\'');
+    if(!$e) $db->_die('The page entry could not be deleted.');
+    $e = $db->sql_query('DELETE FROM '.table_prefix.'files WHERE page_id=\''.$page_id.'\'');
+    if(!$e) $db->_die('The file entry could not be deleted.');
+    return('This page has been deleted. Note that there is still a log of edits and actions in the database, and anyone with admin rights can raise this page from the dead unless the log is cleared. If the deleted file is an image, there may still be cached thumbnails of it in the cache/ directory, which is inaccessible to users.');
+  }
+  
+  /**
+   * Increments the deletion votes for a page by 1, and adds the current username/IP to the list of users that have voted for the page to prevent dual-voting
+   * @param $page_id the page ID
+   * @param $namespace the namespace
+   * @return string
+   */
+   
+  function delvote($page_id, $namespace)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(!$session->get_permissions('vote_delete'))
+      return 'Access denied';
+    $pname = $paths->nslist[$namespace] . $page_id;
+    $cv = $paths->pages[$pname]['delvotes'];
+    $ips = $paths->pages[$pname]['delvote_ips'];
+    $ips = explode('|', $ips);
+    if(in_array($_SERVER['REMOTE_ADDR'], $ips)) return('It appears that you have already voted to have this page deleted.');
+    if($session->user_logged_in)
+      if(in_array($session->username, $ips))
+        return('It appears that you have already voted to have this page deleted.');
+    $ips[] = $_SERVER['REMOTE_ADDR'];
+    if($session->user_logged_in) $ips[] = $session->username;
+    $ips = implode('|', $ips);
+    $ips = substr($ips, 1, strlen($ips));
+    $cv++;
+    $q = 'UPDATE '.table_prefix.'pages SET delvotes='.$cv.',delvote_ips=\''.$ips.'\' WHERE urlname=\''.$page_id.'\' AND namespace=\''.$namespace.'\'';
+    $w = $db->sql_query($q);
+    if(!$w) return("Error updating pages table: ".mysql_error()."\n\nAttemped SQL:\n".$q);
+    return('Your vote to have this page deleted has been cast.'."\nYou are encouraged to leave a comment explaining the reason for your vote.");
+  }
+  
+  /**
+   * Resets the number of votes against a page to 0.
+   * @param $page_id the page ID
+   * @param $namespace the namespace
+   * @return string
+   */
+  
+  function resetdelvotes($page_id, $namespace)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(!$session->get_permissions('vote_reset')) die('You need moderator rights in order to do this, stinkin\' hacker.');
+    $q = 'UPDATE '.table_prefix.'pages SET delvotes=0,delvote_ips=\'\' WHERE urlname=\''.$page_id.'\' AND namespace=\''.$namespace.'\'';
+    $e = $db->sql_query($q);
+    if(!$e) $db->_die('The number of delete votes was not reset.');
+    else return('The number of votes for having this page deleted has been reset to zero.');
+  }
+  
+  /**
+   * Gets a list of styles for a given theme name.
+   * @param $id the name of the directory for the theme
+   * @return string Javascript code
+   */
+   
+  function getstyles()
+  {
+    $dir = './themes/'.$_GET['id'].'/css/';
+    $list = Array();
+    // Open a known directory, and proceed to read its contents
+    if (is_dir($dir)) {
+      if ($dh = opendir($dir)) {
+        while (($file = readdir($dh)) !== false) {
+          if(preg_match('#^(.*?)\.css$#is', $file) && $file != '_printable.css') { // _printable.css should be included with every theme
+                                                                                    // it should be a copy of the original style, but
+                                                                                    // mostly black and white
+                                                                                    // Note to self: document this
+            $list[] = substr($file, 0, strlen($file)-4);
+          }
+        }
+        closedir($dh);
+      }
+    } else return($dir.' is not a dir');
+    $l = 'var list = new Array();';
+    $i = -1;
+    foreach($list as $li) {
+      $i++;
+      $l .= "list[$i] = '$li';";
+    }
+    return $l;
+  }
+  
+  /**
+   * Assembles a Javascript app with category information
+   * @param $page_id the page ID
+   * @param $namespace the namespace
+   * @return string Javascript code
+   */
+   
+  function catedit($page_id, $namespace)
+  {
+    $d = PageUtils::catedit_raw($page_id, $namespace);
+    return $d[0] . ' /* BEGIN CONTENT */ document.getElementById("ajaxEditContainer").innerHTML = unescape(\''.rawurlencode($d[1]).'\');';
+  }
+  
+  /**
+   * Does the actual HTML/javascript generation for cat editing, but returns an array
+   * @access private
+   */
+   
+  function catedit_raw($page_id, $namespace)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    ob_start();
+    $_ob = '';
+    $e = $db->sql_query('SELECT category_id FROM '.table_prefix.'categories WHERE page_id=\''.$paths->cpage['urlname_nons'].'\' AND namespace=\''.$paths->namespace.'\'');
+    if(!$e) jsdie('Error selecting category information for current page: '.mysql_error());
+    $cat_current = Array();
+    while($r = $db->fetchrow())
+    {
+      $cat_current[] = $r;
+    }
+    $db->free_result();
+    $cat_all = Array();
+    for($i=0;$i<sizeof($paths->pages)/2;$i++)
+    {
+      if($paths->pages[$i]['namespace']=='Category') $cat_all[] = $paths->pages[$i];
+    }
+    
+    // Make $cat_all an associative array, like $paths->pages
+    $sz = sizeof($cat_all);
+    for($i=0;$i<$sz;$i++)
+    {
+      $cat_all[$cat_all[$i]['urlname_nons']] = $cat_all[$i];
+    }
+    // Now, the "zipper" function - join the list of categories with the list of cats that this page is a part of
+    $cat_info = $cat_all;
+    for($i=0;$i<sizeof($cat_current);$i++)
+    {
+      $un = $cat_current[$i]['category_id'];
+      $cat_info[$un]['member'] = true;
+    }
+    // Now copy the information we just set into the numerically named keys
+    for($i=0;$i<sizeof($cat_info)/2;$i++)
+    {
+      $un = $cat_info[$i]['urlname_nons'];
+      $cat_info[$i] = $cat_info[$un];
+    }
+    
+    echo 'catlist = new Array();'; // Initialize the client-side category list
+    $_ob .= '<h3>Select which categories this page should be included in.</h3>
+             <form name="mdgCatForm" action="'.makeUrlNS($namespace, $page_id, 'do=catedit').'" method="post">';
+    if ( sizeof($cat_info) < 1 )
+    {
+      $_ob .= '<p>There are no categories on this site yet.</p>';
+    }
+    for ( $i = 0; $i < sizeof($cat_info) / 2; $i++ )
+    {
+      // Protection code added 1/3/07
+      // Updated 3/4/07
+      $is_prot = false;
+      $perms = $session->fetch_page_acl($cat_info[$i]['urlname_nons'], 'Category');
+      if ( !$session->get_permissions('edit_cat') || !$perms->get_permissions('edit_cat') ||
+         ( $cat_info[$i]['really_protected'] && !$perms->get_permissions('even_when_protected') ) )
+         $is_prot = true;
+      $prot = ( $is_prot ) ? ' disabled="disabled" ' : '';
+      $prottext = ( $is_prot ) ? ' <img alt="(protected)" width="16" height="16" src="'.scriptPath.'/images/lock16.png" />' : '';
+      echo 'catlist['.$i.'] = \''.$cat_info[$i]['urlname_nons'].'\';';
+      $_ob .= '<span class="catCheck"><input '.$prot.' name="'.$cat_info[$i]['urlname_nons'].'" id="mdgCat_'.$cat_info[$i]['urlname_nons'].'" type="checkbox"';
+      if(isset($cat_info[$i]['member'])) $_ob .= ' checked="checked"';
+      $_ob .= '/>  <label for="mdgCat_'.$cat_info[$i]['urlname_nons'].'">'.$cat_info[$i]['name'].$prottext.'</label></span><br />';
+    }
+    
+    $disabled = ( sizeof($cat_info) < 1 ) ? 'disabled="disabled"' : '';
+      
+    $_ob .= '<div style="border-top: 1px solid #CCC; padding-top: 5px; margin-top: 10px;"><input name="__enanoSaveButton" ' . $disabled . ' style="font-weight: bold;" type="submit" onclick="ajaxCatSave(); return false;" value="Save changes" /> <input name="__enanoCatCancel" type="submit" onclick="ajaxReset(); return false;" value="Cancel" /></div></form>';
+    
+    $cont = ob_get_contents();
+    ob_end_clean();
+    return Array($cont, $_ob);
+  }
+  
+  /**
+   * Saves category information
+   * WARNING: If $which_cats is empty, all the category information for the selected page will be nuked!
+   * @param $page_id string the page ID
+   * @param $namespace string the namespace
+   * @param $which_cats array associative array of categories to put the page in
+   * @return string "GOOD" on success, error string on failure
+   */
+  
+  function catsave($page_id, $namespace, $which_cats)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(!$session->get_permissions('edit_cat')) return('Insufficient privileges to change category information');
+    
+    $page_perms = $session->fetch_page_acl($page_id, $namespace);
+    $page_data =& $paths->pages[$paths->nslist[$namespace].$page_id];
+    
+    $cat_all = Array();
+    for($i=0;$i<sizeof($paths->pages)/2;$i++)
+    {
+      if($paths->pages[$i]['namespace']=='Category') $cat_all[] = $paths->pages[$i];
+    }
+    
+    // Make $cat_all an associative array, like $paths->pages
+    $sz = sizeof($cat_all);
+    for($i=0;$i<$sz;$i++)
+    {
+      $cat_all[$cat_all[$i]['urlname_nons']] = $cat_all[$i];
+    }
+    
+    $rowlist = Array();
+    
+    for($i=0;$i<sizeof($cat_all)/2;$i++)
+    {
+      $auth = true;
+      $perms = $session->fetch_page_acl($cat_all[$i]['urlname_nons'], 'Category');
+      if ( !$session->get_permissions('edit_cat') || !$perms->get_permissions('edit_cat') ||
+         ( $cat_all[$i]['really_protected'] && !$perms->get_permissions('even_when_protected') ) ||
+         ( !$page_perms->get_permissions('even_when_protected') && $page_data['protected'] == '1' ) )
+         $auth = false;
+      if(!$auth)
+      {
+        // Find out if the page is currently in the category
+        $q = $db->sql_query('SELECT * FROM '.table_prefix.'categories WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\';');
+        if(!$q)
+          return 'MySQL error: '.$db->get_error();
+        if($db->numrows() > 0)
+        {
+          $auth = true;
+          $which_cats[$cat_all[$i]['urlname_nons']] = true; // Force the category to stay in its current state
+        }
+        $db->free_result();
+      }
+      if(isset($which_cats[$cat_all[$i]['urlname_nons']]) && $which_cats[$cat_all[$i]['urlname_nons']] == true /* for clarity ;-) */ && $auth ) $rowlist[] = '(\''.$page_id.'\', \''.$namespace.'\', \''.$cat_all[$i]['urlname_nons'].'\')';
+    }
+    if(sizeof($rowlist) > 0)
+    {
+      $val = implode(',', $rowlist);
+      $q = 'INSERT INTO '.table_prefix.'categories(page_id,namespace,category_id) VALUES' . $val . ';';
+      $e = $db->sql_query('DELETE FROM '.table_prefix.'categories WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\';');
+      if(!$e) $db->_die('The old category data could not be deleted.');
+      $e = $db->sql_query($q);
+      if(!$e) $db->_die('The new category data could not be inserted.');
+      return('GOOD');
+    }
+    else
+    {
+      $e = $db->sql_query('DELETE FROM '.table_prefix.'categories WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\';');
+      if(!$e) $db->_die('The old category data could not be deleted.');
+      return('GOOD');
+    }
+  }
+  
+  /**
+   * Sets the wiki mode level for a page.
+   * @param $page_id string the page ID
+   * @param $namespace string the namespace
+   * @param $level int 0 for off, 1 for on, 2 for use global setting
+   * @return string "GOOD" on success, error string on failure
+   */
+  
+  function setwikimode($page_id, $namespace, $level)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(!$session->get_permissions('set_wiki_mode')) return('Insufficient access rights');
+    if(!isset($level) || (isset($level) && !preg_match('#^([0-2]){1}$#', (string)$level))) return('Invalid mode string');
+    $q = $db->sql_query('UPDATE '.table_prefix.'pages SET wiki_mode='.$level.' WHERE urlname=\''.$page_id.'\' AND namespace=\''.$namespace.'\';');
+    if(!$q) return('Error during update query: '.mysql_error()."\n\nSQL Backtrace:\n".$db->sql_backtrace());
+    return('GOOD');
+  }
+  
+  /**
+   * Sets the access password for a page.
+   * @param $page_id string the page ID
+   * @param $namespace string the namespace
+   * @param $pass string the SHA1 hash of the password - if the password doesn't match the regex ^([0-9a-f]*){40,40}$ it will be sha1'ed
+   * @return string
+   */
+  
+  function setpass($page_id, $namespace, $pass)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    // Determine permissions
+    if($paths->pages[$paths->nslist[$namespace].$page_id]['password'] != '')
+      $a = $session->get_permissions('password_reset');
+    else
+      $a = $session->get_permissions('password_set');
+    if(!$a)
+      return 'Access is denied';
+    if(!isset($pass)) return('Password was not set on URL');
+    $p = $pass;
+    if(!preg_match('#([0-9a-f]){40,40}#', $p)) $p = sha1($p);
+    if($p=='da39a3ee5e6b4b0d3255bfef95601890afd80709') $p = '';
+    $e = $db->sql_query('UPDATE '.table_prefix.'pages SET password=\''.$p.'\' WHERE urlname=\''.$page_id.'\' AND namespace=\''.$namespace.'\';');
+    if(!$e) die('PageUtils::setpass(): Error during update query: '.mysql_error()."\n\nSQL Backtrace:\n".$db->sql_backtrace());
+    if($p=='') return('The password for this page has been disabled.');
+    else return('The password for this page has been set.');
+  }
+  
+  /**
+   * Generates some preview HTML
+   * @param $text string the wikitext to use
+   * @return string
+   */
+   
+  function genPreview($text)
+  {
+    return '<div class="info-box"><b>Reminder:</b> This is only a preview - your changes to this page have not yet been saved.</div><div style="background-color: #F8F8F8; padding: 10px; border: 1px dashed #406080; max-height: 250px; overflow: auto; margin: 1em 0 1em 1em;">'.RenderMan::render(RenderMan::preprocess_text($text, false, false)).'</div>';
+  }
+  
+  /**
+   * Makes a scrollable box
+   * @param string $text the inner HTML
+   * @param int $height Optional - the maximum height. Defaults to 250.
+   * @return string
+   */
+   
+  function scrollBox($text, $height = 250)
+  {
+    return '<div style="background-color: #F8F8F8; padding: 10px; border: 1px dashed #406080; max-height: '.(string)intval($height).'px; overflow: auto; margin: 1em 0 1em 1em;">'.$text.'</div>';
+  }
+  
+  /**
+   * Generates a diff summary between two page revisions.
+   * @param $page_id the page ID
+   * @param $namespace the namespace
+   * @param $id1 the time ID of the first revision
+   * @param $id2 the time ID of the second revision
+   * @return string XHTML-formatted diff
+   */
+   
+  function pagediff($page_id, $namespace, $id1, $id2)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(!$session->get_permissions('history_view'))
+      return 'Access denied';
+    if(!preg_match('#^([0-9]+)$#', (string)$id1) ||
+       !preg_match('#^([0-9]+)$#', (string)$id2  )) return 'SQL injection attempt';
+    // OK we made it through security
+    // Safest way to make sure we don't end up with the revisions in wrong columns is to make 2 queries
+    if(!$q1 = $db->sql_query('SELECT page_text,char_tag,author,edit_summary FROM '.table_prefix.'logs WHERE time_id='.$id1.' AND log_type=\'page\' AND action=\'edit\' AND page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\';')) return 'MySQL error: '.mysql_error();
+    if(!$q2 = $db->sql_query('SELECT page_text,char_tag,author,edit_summary FROM '.table_prefix.'logs WHERE time_id='.$id2.' AND log_type=\'page\' AND action=\'edit\' AND page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\';')) return 'MySQL error: '.mysql_error();
+    $row1 = $db->fetchrow($q1);
+    $db->free_result($q1);
+    $row2 = $db->fetchrow($q2);
+    $db->free_result($q2);
+    if(sizeof($row1) < 1 || sizeof($row2) < 2) return 'Couldn\'t find any rows that matched the query. The time ID probably doesn\'t exist in the logs table.';
+    $text1 = $row1['page_text'];
+    $text2 = $row2['page_text'];
+    $time1 = date('F d, Y h:i a', $id1);
+    $time2 = date('F d, Y h:i a', $id2);
+    $_ob = "
+    <p>Comparing revisions: {$time1} &rarr; {$time2}</p>
+    ";
+    // Free some memory
+    unset($row1, $row2, $q1, $q2);
+    
+    $_ob .= RenderMan::diff($text1, $text2);
+    return $_ob;
+  }
+  
+  /**
+   * Gets ACL information about the selected page for target type X and target ID Y.
+   * @param string $page_id The page ID
+   * @param string $namespace The namespace
+   * @param array $parms What to select. This is an array purely for JSON compatibility. It should be an associative array with keys target_type and target_id.
+   * @return array
+   */
+   
+  function acl_editor($parms = Array())
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(!$session->get_permissions('edit_acl') && $session->user_level < USER_LEVEL_ADMIN)
+      return 'Access is denied.';
+    $parms['page_id'] = ( isset($parms['page_id']) ) ? $parms['page_id'] : false;
+    $parms['namespace'] = ( isset($parms['namespace']) ) ? $parms['namespace'] : false;
+    $page_id =& $parms['page_id'];
+    $namespace =& $parms['namespace'];
+    $page_where_clause      = ( empty($page_id) || empty($namespace) ) ? 'AND a.page_id IS NULL AND a.namespace IS NULL' : 'AND a.page_id=\''.$db->escape($page_id).'\' AND a.namespace=\''.$db->escape($namespace).'\'';
+    $page_where_clause_lite = ( empty($page_id) || empty($namespace) ) ? 'AND page_id IS NULL AND namespace IS NULL' : 'AND page_id=\''.$db->escape($page_id).'\' AND namespace=\''.$db->escape($namespace).'\'';
+    //die(print_r($page_id,true));
+    $template->load_theme();
+    // $perms_obj = $session->fetch_page_acl($page_id, $namespace);
+    $perms_obj =& $session;
+    $return = Array();
+    if ( !file_exists(ENANO_ROOT . '/themes/' . $session->theme . '/acledit.tpl') )
+    {
+      return Array(
+        'mode' => 'error',
+        'error' => 'It seems that (a) the file acledit.tpl is missing from these theme, and (b) the JSON response is working.',
+      );
+    }
+    $return['template'] = $template->extract_vars('acledit.tpl');
+    $return['page_id'] = $page_id;
+    $return['namespace'] = $namespace;
+    if(isset($parms['mode']))
+    {
+      switch($parms['mode'])
+      {
+        case 'listgroups':
+          $return['groups'] = Array();
+          $q = $db->sql_query('SELECT group_id,group_name FROM '.table_prefix.'groups ORDER BY group_name ASC;');
+          while($row = $db->fetchrow())
+          {
+            $return['groups'][] = Array(
+              'id' => $row['group_id'],
+              'name' => $row['group_name'],
+              );
+          }
+          $db->free_result();
+          break;
+        case 'seltarget':
+          $return['mode'] = 'seltarget';
+          $return['acl_types'] = $perms_obj->acl_types;
+          $return['acl_deps'] = $perms_obj->acl_deps;
+          $return['acl_descs'] = $perms_obj->acl_descs;
+          $return['target_type'] = $parms['target_type'];
+          $return['target_id'] = $parms['target_id'];
+          switch($parms['target_type'])
+          {
+            case ACL_TYPE_USER:
+              $q = $db->sql_query('SELECT a.rules,u.user_id FROM '.table_prefix.'users AS u
+                  LEFT JOIN '.table_prefix.'acl AS a
+                    ON a.target_id=u.user_id
+                  WHERE a.target_type='.ACL_TYPE_USER.'
+                    AND u.username=\''.$db->escape($parms['target_id']).'\'
+                    '.$page_where_clause.';');
+              if(!$q)
+                return(Array('mode'=>'error','error'=>mysql_error()));
+              if($db->numrows() < 1)
+              {
+                $return['type'] = 'new';
+                $q = $db->sql_query('SELECT user_id FROM '.table_prefix.'users WHERE username=\''.$db->escape($parms['target_id']).'\';');
+                if(!$q)
+                  return(Array('mode'=>'error','error'=>mysql_error()));
+                if($db->numrows() < 1)
+                  return Array('mode'=>'error','error'=>'The username you entered was not found.');
+                $row = $db->fetchrow();
+                $return['target_name'] = $return['target_id'];
+                $return['target_id'] = intval($row['user_id']);
+                $return['current_perms'] = $session->acl_types;
+              }
+              else
+              {
+                $return['type'] = 'edit';
+                $row = $db->fetchrow();
+                $return['target_name'] = $return['target_id'];
+                $return['target_id'] = intval($row['user_id']);
+                $return['current_perms'] = $session->acl_merge($perms_obj->acl_types, $session->string_to_perm($row['rules']));
+              }
+              $db->free_result();
+              // Eliminate types that don't apply to this namespace
+              if ( $namespace )
+              {
+                foreach ( $return['current_perms'] AS $i => $perm )
+                {
+                  if ( ( $page_id != null && $namespace != null ) && ( !in_array ( $namespace, $session->acl_scope[$i] ) && !in_array('All', $session->acl_scope[$i]) ) )
+                  {
+                    // echo "// SCOPE CONTROL: eliminating: $i\n";
+                    unset($return['current_perms'][$i]);
+                    unset($return['acl_types'][$i]);
+                    unset($return['acl_descs'][$i]);
+                    unset($return['acl_deps'][$i]);
+                  }
+                }
+              }
+              break;
+            case ACL_TYPE_GROUP:
+              $q = $db->sql_query('SELECT a.rules,g.group_name,g.group_id FROM '.table_prefix.'groups AS g
+                  LEFT JOIN '.table_prefix.'acl AS a
+                    ON a.target_id=g.group_id
+                  WHERE a.target_type='.ACL_TYPE_GROUP.'
+                    AND g.group_id=\''.intval($parms['target_id']).'\'
+                    '.$page_where_clause.';');
+              if(!$q)
+                return(Array('mode'=>'error','error'=>mysql_error()));
+              if($db->numrows() < 1)
+              {
+                $return['type'] = 'new';
+                $q = $db->sql_query('SELECT group_id,group_name FROM '.table_prefix.'groups WHERE group_id=\''.intval($parms['target_id']).'\';');
+                if(!$q)
+                  return(Array('mode'=>'error','error'=>mysql_error()));
+                if($db->numrows() < 1)
+                  return Array('mode'=>'error','error'=>'The group ID you submitted is not valid.');
+                $row = $db->fetchrow();
+                $return['target_name'] = $row['group_name'];
+                $return['target_id'] = intval($row['group_id']);
+                $return['current_perms'] = $session->acl_types;
+              }
+              else
+              {
+                $return['type'] = 'edit';
+                $row = $db->fetchrow();
+                $return['target_name'] = $row['group_name'];
+                $return['target_id'] = intval($row['group_id']);
+                $return['current_perms'] = $session->acl_merge($session->acl_types, $session->string_to_perm($row['rules']));
+              }
+              $db->free_result();
+              // Eliminate types that don't apply to this namespace
+              if ( $namespace )
+              {
+                foreach ( $return['current_perms'] AS $i => $perm )
+                {
+                  if ( ( $page_id != false && $namespace != false ) && ( !in_array ( $namespace, $session->acl_scope[$i] ) && !in_array('All', $session->acl_scope[$i]) ) )
+                  {
+                    // echo "// SCOPE CONTROL: eliminating: $i\n"; //; ".print_r($namespace,true).":".print_r($page_id,true)."\n";
+                    unset($return['current_perms'][$i]);
+                    unset($return['acl_types'][$i]);
+                    unset($return['acl_descs'][$i]);
+                    unset($return['acl_deps'][$i]);
+                  }
+                }
+              }
+              //return Array('mode'=>'debug','text'=>print_r($return, true));
+              break;
+            default:
+              return Array('mode'=>'error','error','Invalid ACL type ID');
+              break;
+          }
+          return $return;
+          break;
+        case 'save_new':
+        case 'save_edit':
+          $q = $db->sql_query('DELETE FROM '.table_prefix.'acl WHERE target_type='.intval($parms['target_type']).' AND target_id='.intval($parms['target_id']).'
+            '.$page_where_clause_lite.';');
+          if(!$q)
+            return Array('mode'=>'error','error'=>mysql_error());
+          $rules = $session->perm_to_string($parms['perms']);
+          if ( sizeof ( $rules ) < 1 )
+          {
+            return array(
+                'mode' => 'error', 
+                'error' => 'Supplied rule list has a length of zero'
+              );
+          }
+          $q = ($page_id && $namespace) ? 'INSERT INTO '.table_prefix.'acl ( target_type, target_id, page_id, namespace, rules )
+                                             VALUES( '.intval($parms['target_type']).', '.intval($parms['target_id']).', \''.$db->escape($page_id).'\', \''.$db->escape($namespace).'\', \''.$db->escape($rules).'\' )' :
+                                          'INSERT INTO '.table_prefix.'acl ( target_type, target_id, rules )
+                                             VALUES( '.intval($parms['target_type']).', '.intval($parms['target_id']).', \''.$db->escape($rules).'\' )';
+          if(!$db->sql_query($q)) return Array('mode'=>'error','error'=>mysql_error());
+          return Array(
+              'mode' => 'success',
+              'target_type' => $parms['target_type'],
+              'target_id' => $parms['target_id'],
+              'target_name' => $parms['target_name'],
+              'page_id' => $page_id,
+              'namespace' => $namespace,
+            );
+          break;
+        case 'delete':
+          $q = $db->sql_query('DELETE FROM '.table_prefix.'acl WHERE target_type='.intval($parms['target_type']).' AND target_id='.intval($parms['target_id']).'
+            '.$page_where_clause_lite.';');
+          if(!$q)
+            return Array('mode'=>'error','error'=>mysql_error());
+          return Array(
+              'mode' => 'delete',
+              'target_type' => $parms['target_type'],
+              'target_id' => $parms['target_id'],
+              'target_name' => $parms['target_name'],
+              'page_id' => $page_id,
+              'namespace' => $namespace,
+            );
+          break;
+        default:
+          return Array('mode'=>'error','error'=>'Hacking attempt');
+          break;
+      }
+    }
+    return $return;
+  }
+  
+  /**
+   * Same as PageUtils::acl_editor(), but the parms are a JSON string instead of an array. This also returns a JSON string.
+   * @param string $parms Same as PageUtils::acl_editor/$parms, but should be a valid JSON string.
+   * @return string
+   */
+   
+  function acl_json($parms = '{ }')
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $json = new Services_JSON(SERVICES_JSON_LOOSE_TYPE);
+    $parms = $json->decode($parms);
+    $ret = PageUtils::acl_editor($parms);
+    $ret = $json->encode($ret);
+    return $ret;
+  }
+  
+  /**
+   * A non-Javascript frontend for the ACL API.
+   * @param array The request data, if any, this should be in the format required by PageUtils::acl_editor()
+   */
+   
+  function aclmanager($parms)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    ob_start();
+    // Convenience
+    $formstart = '<form 
+                    action="' . makeUrl($paths->page, 'do=aclmanager', true) . '"
+                    method="post" enctype="multipart/form-data"
+                    onsubmit="if(!submitAuthorized) return false;"
+                    >';
+    $formend   = '</form>';
+    $parms    = PageUtils::acl_preprocess($parms);
+    $response = PageUtils::acl_editor($parms);
+    $response = PageUtils::acl_postprocess($response);
+    
+    //die('<pre>' . htmlspecialchars(print_r($response, true)) . '</pre>');
+    
+    switch($response['mode'])
+    {
+      case 'debug':
+        echo '<pre>' . htmlspecialchars($response['text']) . '</pre>';
+        break;
+      case 'stage1':
+        echo '<h3>Manage page access</h3>
+              <p>Please select who should be affected by this access rule.</p>';
+        echo $formstart;
+        echo '<p><label><input type="radio" name="data[target_type]" value="' . ACL_TYPE_GROUP . '" checked="checked" /> A usergroup</label></p>
+              <p><select name="data[target_id_grp]">';
+        foreach ( $response['groups'] as $group )
+        {
+          echo '<option value="' . $group['id'] . '">' . $group['name'] . '</option>';
+        }
+        echo '</select></p>
+              <p><label><input type="radio" name="data[target_type]" value="' . ACL_TYPE_USER . '" /> A specific user</label></p>
+              <p>' . $template->username_field('data[target_id_user]') . '</p>
+              <p>What should this access rule control?</p>
+              <p><label><input name="data[scope]" value="only_this" type="radio" checked="checked" /> Only this page</p>
+              <p><label><input name="data[scope]" value="entire_site" type="radio" /> The entire site</p>
+              <div style="margin: 0 auto 0 0; text-align: right;">
+                <input name="data[mode]" value="seltarget" type="hidden" />
+                <input type="hidden" name="data[page_id]" value="' . $paths->cpage['urlname_nons'] . '" />
+                <input type="hidden" name="data[namespace]" value="' . $paths->namespace . '" />
+                <input type="submit" value="Next &gt;" />
+              </div>';
+        echo $formend;
+        break;
+      case 'success':
+        echo '<div class="info-box">
+                <b>Permissions updated</b><br />
+                The permissions for ' . $response['target_name'] . ' on this page have been updated successfully.<br />
+                ' . $formstart . '
+                <input type="hidden" name="data[mode]" value="seltarget" />
+                <input type="hidden" name="data[target_type]" value="' . $response['target_type'] . '" />
+                <input type="hidden" name="data[target_id_user]" value="' . ( ( intval($response['target_type']) == ACL_TYPE_USER ) ? $response['target_name'] : $response['target_id'] ) .'" />
+                <input type="hidden" name="data[target_id_grp]"  value="' . ( ( intval($response['target_type']) == ACL_TYPE_USER ) ? $response['target_name'] : $response['target_id'] ) .'" />
+                <input type="hidden" name="data[scope]" value="' . ( ( $response['page_id'] ) ? 'only_this' : 'entire_site' ) . '" />
+                <input type="hidden" name="data[page_id]" value="' . ( ( $response['page_id'] ) ? $response['page_id'] : 'false' ) . '" />
+                <input type="hidden" name="data[namespace]" value="' . ( ( $response['namespace'] ) ? $response['namespace'] : 'false' ) . '" />
+                <input type="submit" value="Return to ACL editor" /> <input type="submit" name="data[act_go_stage1]" value="Return to user/scope selection" />
+                ' . $formend . '
+              </div>';
+        break;
+      case 'delete':
+        echo '<div class="info-box">
+                <b>Rule deleted</b><br />
+                The selected access rule has been successfully deleted.<br />
+                ' . $formstart . '
+                <input type="hidden" name="data[mode]" value="seltarget" />
+                <input type="hidden" name="data[target_type]" value="' . $response['target_type'] . '" />
+                <input type="hidden" name="data[target_id_user]" value="' . ( ( intval($response['target_type']) == ACL_TYPE_USER ) ? $response['target_name'] : $response['target_id'] ) .'" />
+                <input type="hidden" name="data[target_id_grp]"  value="' . ( ( intval($response['target_type']) == ACL_TYPE_USER ) ? $response['target_name'] : $response['target_id'] ) .'" />
+                <input type="hidden" name="data[scope]" value="' . ( ( $response['page_id'] ) ? 'only_this' : 'entire_site' ) . '" />
+                <input type="hidden" name="data[page_id]" value="' . ( ( $response['page_id'] ) ? $response['page_id'] : 'false' ) . '" />
+                <input type="hidden" name="data[namespace]" value="' . ( ( $response['namespace'] ) ? $response['namespace'] : 'false' ) . '" />
+                <input type="submit" value="Return to ACL editor" /> <input type="submit" name="data[act_go_stage1]" value="Return to user/scope selection" />
+                ' . $formend . '
+              </div>';
+        break;
+      case 'seltarget':
+        if ( $response['type'] == 'edit' )
+        {
+          echo '<h3>Editing permissions</h3>';
+        }
+        else
+        {
+          echo '<h3>Create new rule</h3>';
+        }
+        $type  = ( $response['target_type'] == ACL_TYPE_GROUP ) ? 'group' : 'user';
+        $scope = ( $response['page_id'] ) ? 'this page' : 'this entire site';
+        echo 'This panel allows you to edit what the '.$type.' "'.$response['target_name'].'" can do on <b>'.$scope.'</b>. Unless you set a permission to "Deny", these permissions may be overridden by other rules.';
+        echo $formstart;
+        $parser = $template->makeParserText( $response['template']['acl_field_begin'] );
+        echo $parser->run();
+        $parser = $template->makeParserText( $response['template']['acl_field_item'] );
+        $cls = 'row2';
+        foreach ( $response['acl_types'] as $acl_type => $value )
+        {
+          $vars = Array(
+              'FIELD_DENY_CHECKED' => '',
+              'FIELD_DISALLOW_CHECKED' => '',
+              'FIELD_WIKIMODE_CHECKED' => '',
+              'FIELD_ALLOW_CHECKED' => '',
+            );
+          $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
+          $vars['ROW_CLASS'] = $cls;
+          
+          switch ( $response['current_perms'][$acl_type] )
+          {
+            case AUTH_ALLOW:
+              $vars['FIELD_ALLOW_CHECKED'] = 'checked="checked"';
+              break;
+            case AUTH_WIKIMODE:
+              $vars['FIELD_WIKIMODE_CHECKED'] = 'checked="checked"';
+              break;
+            case AUTH_DISALLOW:
+            default:
+              $vars['FIELD_DISALLOW_CHECKED'] = 'checked="checked"';
+              break;
+             case AUTH_DENY:
+              $vars['FIELD_DENY_CHECKED'] = 'checked="checked"';
+              break;
+          }
+          $vars['FIELD_NAME'] = 'data[perms][' . $acl_type . ']';
+          $vars['FIELD_DESC'] = $response['acl_descs'][$acl_type];
+          $parser->assign_vars($vars);
+          echo $parser->run();
+        }
+        $parser = $template->makeParserText( $response['template']['acl_field_end'] );
+        echo $parser->run();
+        echo '<div style="margin: 10px auto 0 0; text-align: right;">
+                <input name="data[mode]" value="save_' . $response['type'] . '" type="hidden" />
+                <input type="hidden" name="data[page_id]" value="'   . (( $response['page_id']   ) ? $response['page_id']   : 'false') . '" />
+                <input type="hidden" name="data[namespace]" value="' . (( $response['namespace'] ) ? $response['namespace'] : 'false') . '" />
+                <input type="hidden" name="data[target_type]" value="' . $response['target_type'] . '" />
+                <input type="hidden" name="data[target_id]" value="' . $response['target_id'] . '" />
+                <input type="hidden" name="data[target_name]" value="' . $response['target_name'] . '" />
+                <input type="submit" value="Save changes" />&nbsp;&nbsp;<input type="submit" name="data[act_delete_rule]" value="Delete rule" style="color: #AA0000;" onclick="return confirm(\'Do you really want to delete this ACL rule?\');" />
+              </div>';
+        echo $formend;
+        break;
+      case 'error':
+        ob_end_clean();
+        die_friendly('Error occurred', '<p>Error returned by permissions API:</p><pre>' . htmlspecialchars($response['error']) . '</pre>');
+        break;
+    }
+    $ret = ob_get_contents();
+    ob_end_clean();
+    echo
+      $template->getHeader() .
+      $ret .
+      $template->getFooter();
+  }
+  
+  /**
+   * Preprocessor to turn the form-submitted data from the ACL editor into something the backend can handle
+   * @param array The posted data
+   * @return array
+   * @access private
+   */
+   
+  function acl_preprocess($parms)
+  {
+    if ( !isset($parms['mode']) )
+      // Nothing to do
+      return $parms;
+    switch ( $parms['mode'] )
+    {
+      case 'seltarget':
+        
+        // Who's affected?
+        $parms['target_type'] = intval( $parms['target_type'] );
+        $parms['target_id'] = ( $parms['target_type'] == ACL_TYPE_GROUP ) ? $parms['target_id_grp'] : $parms['target_id_user'];
+        
+      case 'save_edit':
+      case 'save_new':
+        if ( isset($parms['act_delete_rule']) )
+        {
+          $parms['mode'] = 'delete';
+        }
+        
+        // Scope (just this page or entire site?)
+        if ( $parms['scope'] == 'entire_site' || ( $parms['page_id'] == 'false' && $parms['namespace'] == 'false' ) )
+        {
+          $parms['page_id']   = false;
+          $parms['namespace'] = false;
+        }
+        
+        break;
+    }
+    
+    if ( isset($parms['act_go_stage1']) )
+    {
+      $parms = array(
+          'mode' => 'listgroups'
+        );
+    }
+    
+    return $parms;
+  }
+  
+  function acl_postprocess($response)
+  {
+    if(!isset($response['mode']))
+    {
+      if ( isset($response['groups']) )
+        $response['mode'] = 'stage1';
+      else
+        $response = Array(
+            'mode' => 'error',
+            'error' => 'Invalid action passed by API backend.',
+          );
+    }
+    return $response;
+  }
+   
+}
+
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/pageutils.php~	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,2059 @@
+<?php
+/*
+ * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
+ * Version 1.0 (Banshee)
+ * Copyright (C) 2006-2007 Dan Fuhry
+ * pageutils.php - a class that handles raw page manipulations, used mostly by AJAX requests or their old-fashioned form-based counterparts
+ *
+ * This program is Free Software; you can redistribute 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 details.
+ */
+ 
+class PageUtils {
+  
+  /**
+   * List possible username completions
+   * @param $name the name to check for
+   * @return array
+   */
+  
+  function checkusername($name)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $q = $db->sql_query('SELECT username FROM '.table_prefix.'users WHERE username=\''.$db->escape(rawurldecode($name)).'\'');
+    if(!$q) die(mysql_error());
+    if($db->numrows() < 1) { $db->free_result(); return('good'); }
+    else { $db->free_result(); return('bad'); }
+  }
+  
+  /**
+   * Get the wiki formatting source for a page
+   * @param $page the full page id (Namespace:Pagename)
+   * @return string
+   * @todo (DONE) Make it require a password (just for security purposes)
+   */
+   
+  function getsource($page, $password = false)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(!isset($paths->pages[$page]))
+    {
+      return '';
+    }
+    
+    if(strlen($paths->pages[$page]['password']) == 40)
+    {
+      if(!$password || ( $password != $paths->pages[$page]['password']))
+      {
+        return 'invalid_password';
+      }
+    }
+    
+    if(!$session->get_permissions('view_source')) // Dependencies handle this for us - this also checks for read privileges
+      return 'access_denied';
+    $pid = RenderMan::strToPageID($page);
+    if($pid[1] == 'Special' || $pid[1] == 'Admin')
+    {
+      die('This type of page ('.$paths->nslist[$pid[1]].') cannot be edited because the page source code is not stored in the database.');
+    }
+    
+    $e = $db->sql_query('SELECT page_text,char_tag FROM '.table_prefix.'page_text WHERE page_id=\''.$pid[0].'\' AND namespace=\''.$pid[1].'\'');
+    if ( !$e )
+    {
+      $db->_die('The page text could not be selected.');
+    }
+    if( $db->numrows() < 1 )
+    {
+      return ''; //$db->_die('There were no rows in the text table that matched the page text query.');
+    }
+    
+    $r = $db->fetchrow();
+    $db->free_result();
+    $message = $r['page_text'];
+    
+    return htmlspecialchars($message);
+  }
+  
+  /**
+   * Basically a frontend to RenderMan::getPage(), with the ability to send valid data for nonexistent pages
+   * @param $page the full page id (Namespace:Pagename)
+   * @param $send_headers true if the theme headers should be sent (still dependent on current page settings), false otherwise
+   * @return string
+   */
+  
+  function getpage($page, $send_headers = false, $hist_id = false)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    ob_start();
+    $pid = RenderMan::strToPageID($page);
+    //die('<pre>'.print_r($pid, true).'</pre>');
+    if(isset($paths->pages[$page]['password']) && strlen($paths->pages[$page]['password']) == 40)
+    {
+      password_prompt($page);
+    }
+    if(isset($paths->pages[$page]))
+    {
+      doStats($pid[0], $pid[1]);
+    }
+    if($paths->custom_page || $pid[1] == 'Special')
+    {
+      // If we don't have access to the page, get out and quick!
+      if(!$session->get_permissions('read') && $pid[0] != 'Login' && $pid[0] != 'Register')
+      {
+        $template->tpl_strings['PAGE_NAME'] = 'Access denied';
+        
+        if ( $send_headers )
+        {
+          $template->header();
+        }
+        
+        echo '<div class="error-box"><b>Access to this page is denied.</b><br />This may be because you are not logged in or you have not met certain criteria for viewing this page.</div>';
+        
+        if ( $send_headers )
+        {
+          $template->footer();
+        }
+        
+        $r = ob_get_contents();
+        ob_end_clean();
+        return $r;
+      }
+      
+      $fname = 'page_'.$pid[1].'_'.$paths->pages[$page]['urlname_nons'];
+      @call_user_func($fname);
+      
+    }
+    else if ( $pid[1] == 'Admin' )
+    {
+      // If we don't have access to the page, get out and quick!
+      if(!$session->get_permissions('read'))
+      {
+        $template->tpl_strings['PAGE_NAME'] = 'Access denied';
+        if ( $send_headers )
+        {
+          $template->header();
+        }
+        echo '<div class="error-box"><b>Access to this page is denied.</b><br />This may be because you are not logged in or you have not met certain criteria for viewing this page.</div>';
+        if ( $send_headers )
+        {
+          $template->footer();
+        }
+        $r = ob_get_contents();
+        ob_end_clean();
+        return $r;
+      }
+      
+      $fname = 'page_'.$pid[1].'_'.$pid[0];
+      if ( !function_exists($fname) )
+      {
+        $title = 'Page backend not found';
+        $message = "The administration page you are looking for was properly registered using the page API, but the backend function
+                    (<tt>$fname</tt>) was not found. If this is a plugin page, then this is almost certainly a bug with the plugin.";
+        if ( $send_headers )
+        {
+          die_friendly($title, "<p>$message</p>");
+        }
+        else
+        {
+          echo "<h2>$title</h2>\n<p>$message</p>";
+        }
+      }
+      @call_user_func($fname);
+    }
+    else if ( !isset( $paths->pages[$page] ) )
+    {
+      ob_start();
+      $code = $plugins->setHook('page_not_found');
+      foreach ( $code as $cmd )
+      {
+        eval($cmd);
+      }
+      $text = ob_get_contents();
+      if ( $text != '' )
+      {
+        ob_end_clean();
+        return $text;
+      }
+      $template->header();
+      if($m = $paths->sysmsg('Page_not_found'))
+      {
+        eval('?>'.RenderMan::render($m));
+      }
+      else
+      {
+        header('HTTP/1.1 404 Not Found');
+        echo '<h3>There is no page with this title yet.</h3>
+               <p>You have requested a page that doesn\'t exist yet.';
+        if($session->get_permissions('create_page')) echo ' You can <a href="'.makeUrl($paths->page, 'do=edit', true).'" onclick="ajaxEditor(); return false;">create this page</a>, or return to the <a href="'.makeUrl(getConfig('main_page')).'">homepage</a>.';
+        else echo ' Return to the <a href="'.makeUrl(getConfig('main_page')).'">homepage</a>.</p>';
+        if($session->get_permissions('history_rollback')) {
+          $e = $db->sql_query('SELECT * FROM '.table_prefix.'logs WHERE action=\'delete\' AND page_id=\''.$paths->cpage['urlname_nons'].'\' AND namespace=\''.$pid[1].'\' ORDER BY time_id DESC;');
+          if(!$e) $db->_die('The deletion log could not be selected.');
+          if($db->numrows() > 0) {
+            $r = $db->fetchrow();
+            echo '<p>This page also appears to have some log entries in the database - it seems that it was deleted on '.$r['date_string'].'. You can probably <a href="'.makeUrl($paths->page, 'do=rollback&amp;id='.$r['time_id']).'" onclick="ajaxRollback(\''.$r['time_id'].'\'); return false;">roll back</a> the deletion.</p>';
+          }
+          $db->free_result();
+        }
+        echo '<p>
+                HTTP Error: 404 Not Found
+              </p>';
+      }
+      $template->footer();
+    }
+    else
+    {
+      
+      // If we don't have access to the page, get out and quick!
+      if(!$session->get_permissions('read'))
+      {
+        $template->tpl_strings['PAGE_NAME'] = 'Access denied';
+        if($send_headers) $template->header();
+        echo '<div class="error-box"><b>Access to this page is denied.</b><br />This may be because you are not logged in or you have not met certain criteria for viewing this page.</div>';
+        if($send_headers) $template->footer();
+        $r = ob_get_contents();
+        ob_end_clean();
+        return $r;
+      }
+      
+      ob_start();
+      $code = $plugins->setHook('page_custom_handler');
+      foreach ( $code as $cmd )
+      {
+        eval($cmd);
+      }
+      $text = ob_get_contents();
+      if ( $text != '' )
+      {
+        ob_end_clean();
+        return $text;
+      }
+      
+      if($hist_id) {
+        $e = $db->sql_query('SELECT page_text,date_string,char_tag FROM '.table_prefix.'logs WHERE page_id=\''.$paths->pages[$page]['urlname_nons'].'\' AND namespace=\''.$pid[1].'\' AND log_type=\'page\' AND action=\'edit\' AND time_id='.$db->escape($hist_id).'');
+        if($db->numrows() < 1)
+        {
+          $db->_die('There were no rows in the text table that matched the page text query.');
+        }
+        $r = $db->fetchrow();
+        $db->free_result();
+        $message = '<div class="info-box" style="margin-left: 0; margin-top: 5px;"><b>Notice:</b><br />The page you are viewing was archived on '.$r['date_string'].'.<br /><a href="'.makeUrl($page).'" onclick="ajaxReset(); return false;">View current version</a>  |  <a href="'.makeUrl($page, 'do=rollback&amp;id='.$hist_id).'" onclick="ajaxRollback(\''.$hist_id.'\')">Restore this version</a></div><br />'.RenderMan::render($r['page_text']);
+        
+        if( !$paths->pages[$page]['special'] )
+        {
+          if($send_headers)
+          {
+            $template->header(); 
+          }
+          display_page_headers();
+        }
+        
+        eval('?>'.$message);
+        
+        if( !$paths->pages[$page]['special'] )
+        {
+          display_page_footers();
+          if($send_headers)
+          {
+            $template->footer();
+          }
+        }
+        
+      } else {
+        if(!$paths->pages[$page]['special'])
+        {
+          $message = RenderMan::getPage($paths->pages[$page]['urlname_nons'], $pid[1]);
+        }
+        else
+        {
+          $message = RenderMan::getPage($paths->pages[$page]['urlname_nons'], $pid[1], 0, false, false, false, false);
+        }
+        // This line is used to debug wikiformatted code
+        // die('<pre>'.htmlspecialchars($message).'</pre>');
+        
+        if( !$paths->pages[$page]['special'] )
+        {
+          if($send_headers)
+          {
+            $template->header(); 
+          }
+          display_page_headers();
+        }
+
+        // This is it, this is what all of Enano has been working up to...
+        
+        eval('?>'.$message);
+        
+        if( !$paths->pages[$page]['special'] )
+        {
+          display_page_footers();
+          if($send_headers)
+          {
+            $template->footer();
+          }
+        }
+      }
+    }
+    $ret = ob_get_contents();
+    ob_end_clean();
+    return $ret;
+  }
+  
+  /**
+   * Writes page data to the database, after verifying permissions and running the XSS filter
+   * @param $page_id the page ID
+   * @param $namespace the namespace
+   * @param $message the text to save
+   * @return string
+   */
+   
+  function savepage($page_id, $namespace, $message, $summary = 'No edit summary given', $minor = false)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $uid = sha1(microtime());
+    $pname = $paths->nslist[$namespace] . $page_id;
+    
+    if(!$session->get_permissions('edit_page'))
+      return 'Access to edit pages is denied.';
+    
+    if(!isset($paths->pages[$pname]))
+    {
+      if(!PageUtils::createPage($page_id, $namespace))
+        return 'The page did not exist, and I was not able to create it. Permissions problem?';
+    }
+    
+    $prot = ( ( $paths->pages[$pname]['protected'] == 2 && $session->user_logged_in && $session->reg_time + 60*60*24*4 < time() ) || $paths->pages[$pname]['protected'] == 1) ? true : false;
+    $wiki = ( ( $paths->pages[$pname]['wiki_mode'] == 2 && getConfig('wiki_mode') == '1') || $paths->pages[$pname]['wiki_mode'] == 1) ? true : false;
+    if(($prot || !$wiki) && $session->user_level < USER_LEVEL_ADMIN ) return('You are not authorized to edit this page.');
+    
+    // Strip potentially harmful tags and PHP from the message, if we are in wiki mode and the user is not an administrator
+    $message = RenderMan::preprocess_text($message, false, false);
+    
+    $msg=$db->escape($message);
+    
+    $minor = $minor ? 'true' : 'false';
+    $q='INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,page_id,namespace,page_text,char_tag,author,edit_summary,minor_edit) VALUES(\'page\', \'edit\', '.time().', \''.date('d M Y h:i a').'\', \''.$paths->cpage['urlname_nons'].'\', \''.$paths->namespace.'\', \''.$msg.'\', \''.$uid.'\', \''.$session->username.'\', \''.$db->escape(htmlspecialchars($summary)).'\', '.$minor.');';
+    if(!$db->sql_query($q)) $db->_die('The history (log) entry could not be inserted into the logs table.');
+    
+    $q = 'UPDATE '.table_prefix.'page_text SET page_text=\''.$msg.'\',char_tag=\''.$uid.'\' WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\';';
+    $e = $db->sql_query($q);
+    if(!$e) $db->_die('Enano was unable to save the page contents. Your changes have been lost <tt>:\'(</tt>.');
+      
+    $paths->rebuild_page_index($page_id, $namespace);
+      
+    return 'good';
+  }
+  
+  /**
+   * Creates a page, both in memory and in the database.
+   * @param string $page_id
+   * @param string $namespace
+   * @return bool true on success, false on failure
+   */
+  
+  function createPage($page_id, $namespace, $name = false, $visible = 1)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(in_array($namespace, Array('Special', 'Admin')))
+    {
+      // echo '<b>Notice:</b> PageUtils::createPage: You can\'t create a special page in the database<br />';
+      return false; // Can't create a special page
+    }
+    
+    if(!isset($paths->nslist[$namespace]))
+    {
+      // echo '<b>Notice:</b> PageUtils::createPage: Couldn\'t look up the namespace<br />';
+      return false; // Couldn't look up namespace
+    }
+    
+    $pname = $paths->nslist[$namespace] . $page_id;
+    if(isset($paths->pages[$pname]))
+    {
+      // echo '<b>Notice:</b> PageUtils::createPage: Page already exists<br />';
+      return false; // Page already exists
+    }
+    
+    if(!$session->get_permissions('create_page'))
+    {
+      // echo '<b>Notice:</b> PageUtils::createPage: Not authorized to create pages<br />';
+      return false; // Access denied
+    }
+    
+    if($session->user_level < USER_LEVEL_ADMIN && $namespace == 'System')
+    {
+      // echo '<b>Notice:</b> PageUtils::createPage: Not authorized to create system messages<br />';
+      return false; // Not authorized to create system messages
+    }
+    
+    if ( !$name )
+      $name = str_replace('_', ' ', $page_id);
+    $page = str_replace(' ', '_', $page_id);
+    $regex = '#^([A-z0-9 _\-\.\/\!\@\(\)]*)$#is';
+    if(!preg_match($regex, $page))
+    {
+      //echo '<b>Notice:</b> PageUtils::createPage: Name contains invalid characters<br />';
+      return false; // Name contains invalid characters
+    }
+    
+    $prot = ( $namespace == 'System' ) ? 1 : 0;
+    
+    $paths->add_page(Array(
+      'name'=>$name,
+      'urlname'=>$page,
+      'namespace'=>$namespace,
+      'special'=>0,'visible'=>1,'comments_on'=>0,'protected'=>$prot,'delvotes'=>0,'delvote_ips'=>'','wiki_mode'=>2,
+    ));
+    
+    $qa = $db->sql_query('INSERT INTO '.table_prefix.'pages(name,urlname,namespace,visible,protected) VALUES(\''.$db->escape($name).'\', \''.$db->escape($page).'\', \''.$namespace.'\', '. ( $visible ? '1' : '0' ) .', '.$prot.');');
+    $qb = $db->sql_query('INSERT INTO '.table_prefix.'page_text(page_id,namespace) VALUES(\''.$db->escape($page).'\', \''.$namespace.'\');');
+    $qc = $db->sql_query('INSERT INTO '.table_prefix.'logs(time_id,date_string,log_type,action,author,page_id,namespace) VALUES('.time().', \''.date('d M Y h:i a').'\', \'page\', \'create\', \''.$session->username.'\', \''.$db->escape($page).'\', \''.$namespace.'\');');
+    
+    if($qa && $qb && $qc)
+      return true;
+    else
+    {
+      echo $db->get_error();
+      return false;
+    }
+  }
+  
+  /**
+   * Sets the protection level on a page.
+   * @param $page_id string the page ID
+   * @param $namespace string the namespace
+   * @param $level int level of protection - 0 is off, 1 is full, 2 is semi
+   * @param $reason string why the page is being (un)protected
+   * @return string - "good" on success, in all other cases, an error string (on query failure, calls $db->_die() )
+   */
+  function protect($page_id, $namespace, $level, $reason)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    $pname = $paths->nslist[$namespace] . $page_id;
+    $wiki = ( ( $paths->pages[$pname]['wiki_mode'] == 2 && getConfig('wiki_mode') == '1') || $paths->pages[$pname]['wiki_mode'] == 1) ? true : false;
+    $prot = ( ( $paths->pages[$pname]['protected'] == 2 && $session->user_logged_in && $session->reg_time + 60*60*24*4 < time() ) || $paths->pages[$pname]['protected'] == 1) ? true : false;
+    
+    if(!$session->get_permissions('protect')) return('Insufficient access rights');
+    if(!$wiki) return('Page protection only has an effect when Wiki Mode is enabled.');
+    if(!preg_match('#^([0-9]+){1}$#', (string)$level)) return('Invalid $level parameter.');
+    
+    if($reason!='NO_REASON') {
+      switch($level)
+      {
+        case 0:
+          $q = 'INSERT INTO '.table_prefix.'logs(time_id,date_string,log_type,action,author,page_id,namespace,edit_summary) VALUES('.time().', \''.date('d M Y h:i a').'\', \'page\', \'unprot\', \''.$session->username.'\', \''.$page_id.'\', \''.$namespace.'\', \''.$db->escape(htmlspecialchars($reason)).'\');';
+          break;
+        case 1:
+          $q = 'INSERT INTO '.table_prefix.'logs(time_id,date_string,log_type,action,author,page_id,namespace,edit_summary) VALUES('.time().', \''.date('d M Y h:i a').'\', \'page\', \'prot\', \''.$session->username.'\', \''.$page_id.'\', \''.$namespace.'\', \''.$db->escape(htmlspecialchars($reason)).'\');';
+          break;
+        case 2:
+          $q = 'INSERT INTO '.table_prefix.'logs(time_id,date_string,log_type,action,author,page_id,namespace,edit_summary) VALUES('.time().', \''.date('d M Y h:i a').'\', \'page\', \'semiprot\', \''.$session->username.'\', \''.$page_id.'\', \''.$namespace.'\', \''.$db->escape(htmlspecialchars($reason)).'\');';
+          break;
+        default:
+          return 'PageUtils::protect(): Invalid value for $level';
+          break;
+      }
+      if(!$db->sql_query($q)) $db->_die('The log entry for the page protection could not be inserted.');
+    }
+    
+    $q = $db->sql_query('UPDATE '.table_prefix.'pages SET protected='.$_POST['level'].' WHERE urlname=\''.$page_id.'\' AND namespace=\''.$namespace.'\';');
+    if(!$q) $db->_die('The pages table was not updated.');
+    
+    return('good');
+  }
+  
+  /**
+   * Generates an HTML table with history information in it.
+   * @param $page_id the page ID
+   * @param $namespace the namespace
+   * @return string
+   */
+  
+  function histlist($page_id, $namespace)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    if(!$session->get_permissions('history_view'))
+      return 'Access denied';
+    
+    ob_start();
+    
+    $pname = $paths->nslist[$namespace] . $page_id;
+    $wiki = ( ( $paths->pages[$pname]['wiki_mode'] == 2 && getConfig('wiki_mode') == '1') || $paths->pages[$pname]['wiki_mode'] == 1) ? true : false;
+    $prot = ( ( $paths->pages[$pname]['protected'] == 2 && $session->user_logged_in && $session->reg_time + 60*60*24*4 < time() ) || $paths->pages[$pname]['protected'] == 1) ? true : false;
+    
+    $q = 'SELECT time_id,date_string,page_id,namespace,author,edit_summary,minor_edit FROM '.table_prefix.'logs WHERE log_type=\'page\' AND action=\'edit\' AND page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' ORDER BY time_id DESC;';
+    if(!$db->sql_query($q)) $db->_die('The history data for the page "'.$paths->cpage['name'].'" could not be selected.');
+    echo 'History of edits and actions<h3>Edits:</h3>';
+    $numrows = $db->numrows();
+    if($numrows < 1) echo 'No history entries in this category.';
+    else
+    {
+      
+      echo '<form action="'.makeUrlNS($namespace, $page_id, 'do=diff').'" onsubmit="ajaxHistDiff(); return false;" method="get">
+            <input type="submit" value="Compare selected revisions" />
+            <br /><span>&nbsp;</span>
+            <div class="tblholder">
+            <table border="0" width="100%" cellspacing="1" cellpadding="4">
+            <tr>
+              <th colspan="2">Diff</th>
+              <th>Date/time</th>
+              <th>User</th>
+              <th>Edit summary</th>
+              <th>Minor</th>
+              <th colspan="3">Actions</th>
+            </tr>'."\n"."\n";
+      $cls = 'row2';
+      $ticker = 0;
+      
+      while($r = $db->fetchrow()) {
+        
+        $ticker++;
+        
+        if($cls == 'row2') $cls = 'row1';
+        else $cls = 'row2';
+        
+        echo '<tr>'."\n";
+        
+        // Diff selection
+        if($ticker == 1)
+        {
+          $s1 = '';
+          $s2 = 'checked="checked" ';
+        }
+        elseif($ticker == 2)
+        {
+          $s1 = 'checked="checked" ';
+          $s2 = '';
+        }
+        else
+        {
+          $s1 = '';
+          $s2 = '';
+        }
+        if($ticker > 1)        echo '<td class="'.$cls.'" style="padding: 0;"><input '.$s1.'name="diff1" type="radio" value="'.$r['time_id'].'" id="diff1_'.$r['time_id'].'" class="clsDiff1Radio" onclick="selectDiff1Button(this);" /></td>'."\n"; else echo '<td class="'.$cls.'"></td>';
+        if($ticker < $numrows) echo '<td class="'.$cls.'" style="padding: 0;"><input '.$s2.'name="diff2" type="radio" value="'.$r['time_id'].'" id="diff2_'.$r['time_id'].'" class="clsDiff2Radio" onclick="selectDiff2Button(this);" /></td>'."\n"; else echo '<td class="'.$cls.'"></td>';
+        
+        // Date and time
+        echo '<td class="'.$cls.'">'.$r['date_string'].'</td class="'.$cls.'">'."\n";
+        
+        // User
+        if($session->get_permissions('mod_misc') && preg_match('#^([0-9]*){1,3}\.([0-9]*){1,3}\.([0-9]*){1,3}\.([0-9]*){1,3}$#', $r['author'])) $rc = ' style="cursor: pointer;" title="Click cell background for reverse DNS info" onclick="ajaxReverseDNS(this, \''.$r['author'].'\');"';
+        else $rc = '';
+        echo '<td class="'.$cls.'"'.$rc.'><a href="'.makeUrlNS('User', $r['author']).'" ';
+        if(!isPage($paths->nslist['User'] . $r['author'])) echo 'class="wikilink-nonexistent"';
+        echo '>'.$r['author'].'</a></td class="'.$cls.'">'."\n";
+        
+        // Edit summary
+        echo '<td class="'.$cls.'">'.$r['edit_summary'].'</td>'."\n";
+        
+        // Minor edit
+        echo '<td class="'.$cls.'" style="text-align: center;">'. (( $r['minor_edit'] ) ? 'M' : '' ) .'</td>'."\n";
+        
+        // Actions!
+        echo '<td class="'.$cls.'" style="text-align: center;"><a href="'.makeUrlNS($namespace, $page_id, 'oldid='.$r['time_id']).'" onclick="ajaxHistView(\''.$r['time_id'].'\'); return false;">View revision</a></td>'."\n";
+        echo '<td class="'.$cls.'" style="text-align: center;"><a href="'.makeUrl($paths->nslist['Special'].'Contributions/'.$r['author']).'">View user contribs</a></td>'."\n";
+        echo '<td class="'.$cls.'" style="text-align: center;"><a href="'.makeUrlNS($namespace, $page_id, 'do=rollback&amp;id='.$r['time_id']).'" onclick="ajaxRollback(\''.$r['time_id'].'\'); return false;">Revert to this revision</a></td>'."\n";
+        
+        echo '</tr>'."\n"."\n";
+        
+      }
+      echo '</table>
+            </div>
+            <br />
+            <input type="hidden" name="do" value="diff" />
+            <input type="submit" value="Compare selected revisions" />
+            </form>
+            <script type="text/javascript">buildDiffList();</script>';
+    }
+    $db->free_result();
+    echo '<h3>Other changes:</h3>';
+    $q = 'SELECT time_id,action,date_string,page_id,namespace,author,edit_summary,minor_edit FROM '.table_prefix.'logs WHERE log_type=\'page\' AND action!=\'edit\' AND page_id=\''.$paths->cpage['urlname_nons'].'\' AND namespace=\''.$paths->namespace.'\' ORDER BY time_id DESC;';
+    if(!$db->sql_query($q)) $db->_die('The history data for the page "'.$paths->cpage['name'].'" could not be selected.');
+    if($db->numrows() < 1) echo 'No history entries in this category.';
+    else {
+      
+      echo '<div class="tblholder"><table border="0" width="100%" cellspacing="1" cellpadding="4"><tr><th>Date/time</th><th>User</th><th>Minor</th><th>Action taken</th><th>Extra info</th><th colspan="2"></th></tr>';
+      $cls = 'row2';
+      while($r = $db->fetchrow()) {
+        
+        if($cls == 'row2') $cls = 'row1';
+        else $cls = 'row2';
+        
+        echo '<tr>';
+        
+        // Date and time
+        echo '<td class="'.$cls.'">'.$r['date_string'].'</td class="'.$cls.'">';
+        
+        // User
+        echo '<td class="'.$cls.'"><a href="'.makeUrlNS('User', $r['author']).'" ';
+        if(!isPage($paths->nslist['User'] . $r['author'])) echo 'class="wikilink-nonexistent"';
+        echo '>'.$r['author'].'</a></td class="'.$cls.'">';
+        
+        
+        // Minor edit
+        echo '<td class="'.$cls.'" style="text-align: center;">'. (( $r['minor_edit'] ) ? 'M' : '' ) .'</td>';
+        
+        // Action taken
+        echo '<td class="'.$cls.'">';
+        if    ($r['action']=='prot')     echo 'Protected page</td><td class="'.$cls.'">Reason: '.$r['edit_summary'];
+        elseif($r['action']=='unprot')   echo 'Unprotected page</td><td class="'.$cls.'">Reason: '.$r['edit_summary'];
+        elseif($r['action']=='semiprot') echo 'Semi-protected page</td><td class="'.$cls.'">Reason: '.$r['edit_summary'];
+        elseif($r['action']=='rename')   echo 'Renamed page</td><td class="'.$cls.'">Old title: '.$r['edit_summary'];
+        elseif($r['action']=='create')   echo 'Created page</td><td class="'.$cls.'">';
+        elseif($r['action']=='delete')   echo 'Deleted page</td><td class="'.$cls.'">';
+        elseif($r['action']=='reupload') echo 'Uploaded new file version</td><td class="'.$cls.'">Reason: '.$r['edit_summary'];
+        echo '</td>';
+        
+        // Actions!
+        echo '<td class="'.$cls.'" style="text-align: center;"><a href="'.makeUrl($paths->nslist['Special'].'Contributions/'.$r['author']).'">View user contribs</a></td>';
+        echo '<td class="'.$cls.'" style="text-align: center;"><a href="'.makeUrlNS($namespace, $page_id, 'do=rollback&amp;id='.$r['time_id']).'" onclick="ajaxRollback(\''.$r['time_id'].'\'); return false;">Revert action</a></td>';
+        
+        //echo '(<a href="#" onclick="ajaxRollback(\''.$r['time_id'].'\'); return false;">rollback</a>) <i>'.$r['date_string'].'</i> '.$r['author'].' (<a href="'.makeUrl($paths->nslist['User'].$r['author']).'">Userpage</a>, <a href="'.makeUrl($paths->nslist['Special'].'Contributions/'.$r['author']).'">Contrib</a>): ';
+        
+        if($r['minor_edit']) echo '<b> - minor edit</b>';
+        echo '<br />';
+        
+        echo '</tr>';
+      }
+      echo '</table></div>';
+    }
+    $db->free_result();
+    $ret = ob_get_contents();
+    ob_end_clean();
+    return $ret;
+  }
+  
+  /**
+   * Rolls back a logged action
+   * @param $id the time ID, a.k.a. the primary key in the logs table
+   * @return string
+   */
+   
+  function rollback($id)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(!$session->get_permissions('history_rollback')) return('You are not authorized to perform rollbacks.');
+    if(!preg_match('#^([0-9]+)$#', (string)$id)) return('The value "id" on the query string must be an integer.');
+    $e = $db->sql_query('SELECT log_type,action,date_string,page_id,namespace,page_text,char_tag,author,edit_summary FROM '.table_prefix.'logs WHERE time_id='.$id.';');
+    if(!$e) $db->_die('The rollback data could not be selected.');
+    $rb = $db->fetchrow();
+    $db->free_result();
+    switch($rb['log_type']) {
+      case "page":
+        switch($rb['action']) {
+          case "edit":
+            $t = $db->escape($rb['page_text']);
+            $e = $db->sql_query('UPDATE '.table_prefix.'page_text SET page_text=\''.$t.'\',char_tag=\''.$rb['char_tag'].'\' WHERE page_id=\''.$rb['page_id'].'\' AND namespace=\''.$rb['namespace'].'\'');
+            if(!$e) return("An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace());
+            else return('The page "'.$paths->pages[$paths->nslist[$rb['namespace']].$rb['page_id']]['name'].'" has been rolled back to the state it was in on '.$rb['date_string'].'.');
+            break;
+          case "rename":
+            $t = $db->escape($rb['edit_summary']);
+            $e = $db->sql_query('UPDATE '.table_prefix.'pages SET name=\''.$t.'\' WHERE urlname=\''.$rb['page_id'].'\' AND namespace=\''.$rb['namespace'].'\'');
+            if(!$e) return("An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace());
+            else return('The page "'.$paths->pages[$paths->nslist[$rb['namespace']].$rb['page_id']]['name'].'" has been rolled back to the name it had ("'.$rb['edit_summary'].'") before '.$rb['date_string'].'.');
+            break;
+          case "prot":
+            $e = $db->sql_query('UPDATE '.table_prefix.'pages SET protected=0 WHERE urlname=\''.$rb['page_id'].'\' AND namespace=\''.$rb['namespace'].'\'');
+            if(!$e) return("An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace());
+            else return('The page "'.$paths->pages[$paths->nslist[$rb['namespace']].$rb['page_id']]['name'].'" has been unprotected according to the log created at '.$rb['date_string'].'.');
+            break;
+          case "semiprot":
+            $e = $db->sql_query('UPDATE '.table_prefix.'pages SET protected=0 WHERE urlname=\''.$rb['page_id'].'\' AND namespace=\''.$rb['namespace'].'\'');
+            if(!$e) return("An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace());
+            else return('The page "'.$paths->pages[$paths->nslist[$rb['namespace']].$rb['page_id']]['name'].'" has been unprotected according to the log created at '.$rb['date_string'].'.');
+            break;
+          case "unprot":
+            $e = $db->sql_query('UPDATE '.table_prefix.'pages SET protected=1 WHERE urlname=\''.$rb['page_id'].'\' AND namespace=\''.$rb['namespace'].'\'');
+            if(!$e) return("An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace());
+            else return('The page "'.$paths->pages[$paths->nslist[$rb['namespace']].$rb['page_id']]['name'].'" has been protected according to the log created at '.$rb['date_string'].'.');
+            break;
+          case "delete":
+            if(!$session->get_permissions('history_rollback_extra')) return('Administrative privileges are required for page undeletion.');
+            if(isset($paths->pages[$paths->cpage['urlname']])) return('You cannot raise a dead page that is alive.');
+            $name = str_replace('_', ' ', $rb['page_id']);
+            $e = $db->sql_query('INSERT INTO '.table_prefix.'pages(name,urlname,namespace) VALUES( \''.$name.'\', \''.$rb['page_id'].'\',\''.$rb['namespace'].'\' )');if(!$e) return("An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace());
+            $e = $db->sql_query('SELECT page_text,char_tag FROM '.table_prefix.'logs WHERE page_id=\''.$rb['page_id'].'\' AND namespace=\''.$rb['namespace'].'\' AND log_type=\'page\' AND action=\'edit\' ORDER BY time_id DESC;'); if(!$e) return("An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace());
+            $r = $db->fetchrow();
+            $e = $db->sql_query('INSERT INTO '.table_prefix.'page_text(page_id,namespace,page_text,char_tag) VALUES(\''.$rb['page_id'].'\',\''.$rb['namespace'].'\',\''.$db->escape($r['page_text']).'\',\''.$r['char_tag'].'\')'); if(!$e) return("An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace());
+            return('The page "'.$name.'" has been undeleted according to the log created at '.$rb['date_string'].'.');
+            break;
+          case "reupload":
+            if(!$session->get_permissions('history_rollbacks_extra')) return('Administrative privileges are required for file rollbacks.');
+            $newtime = time();
+            $newdate = date('d M Y h:i a');
+            if(!$db->sql_query('UPDATE '.table_prefix.'logs SET time_id='.$newtime.',date_string=\''.$newdate.'\' WHERE time_id='.$id)) return('Error during query: '.mysql_error());
+            if(!$db->sql_query('UPDATE '.table_prefix.'files SET time_id='.$newtime.' WHERE time_id='.$id)) return('Error during query: '.mysql_error());
+            return('The file has been rolled back to the version uploaded on '.date('d M Y h:i a', (int)$id).'.');
+            break;
+          default:
+            return('Rollback of the action "'.$rb['action'].'" is not yet supported.');
+            break;
+        }
+        break;
+      case "security":
+      case "login":
+        return('A '.$rb['log_type'].'-related log entry cannot be rolled back.');
+        break;
+      default:
+        return('Unknown log entry type: "'.$rb['log_type'].'"');
+    }
+  }
+  
+  /**
+   * Posts a comment.
+   * @param $page_id the page ID
+   * @param $namespace the namespace
+   * @param $name the name of the person posting, defaults to current username/IP
+   * @param $subject the subject line of the comment
+   * @param $text the comment text
+   * @return string javascript code
+   */
+   
+  function addcomment($page_id, $namespace, $name, $subject, $text, $captcha_code = false, $captcha_id = false)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $_ob = '';
+    if(!$session->get_permissions('post_comments'))
+      return 'Access denied';
+    if(getConfig('comments_need_login') == '2' && !$session->user_logged_in) _die('Access denied to post comments: you need to be logged in first.');
+    if(getConfig('comments_need_login') == '1' && !$session->user_logged_in)
+    {
+      if(!$captcha_code || !$captcha_id) _die('BUG: PageUtils::addcomment: no CAPTCHA data passed to method');
+      $result = $session->get_captcha($captcha_id);
+      if($captcha_code != $result) _die('The confirmation code you entered was incorrect.');
+    }
+    $text = RenderMan::preprocess_text($text);
+    $name = $session->user_logged_in ? RenderMan::preprocess_text($session->username) : RenderMan::preprocess_text($name);
+    $subj = RenderMan::preprocess_text($subject);
+    if(getConfig('approve_comments')=='1') $appr = '0'; else $appr = '1';
+    $q = 'INSERT INTO '.table_prefix.'comments(page_id,namespace,subject,comment_data,name,user_id,approved,time) VALUES(\''.$page_id.'\',\''.$namespace.'\',\''.$subj.'\',\''.$text.'\',\''.$name.'\','.$session->user_id.','.$appr.','.time().')';
+    $e = $db->sql_query($q);
+    if(!$e) die('alert(unescape(\''.rawurlencode('Error inserting comment data: '.mysql_error().'\n\nQuery:\n'.$q).'\'))');
+    else $_ob .= '<div class="info-box">Your comment has been posted.</div>';
+    return PageUtils::comments($page_id, $namespace, false, Array(), $_ob);
+  }
+  
+  /**
+   * Generates partly-compiled HTML/Javascript code to be eval'ed by the user's browser to display comments
+   * @param $page_id the page ID
+   * @param $namespace the namespace
+   * @param $action administrative action to perform, default is false
+   * @param $flags additional info for $action, shouldn't be used except when deleting/approving comments, etc.
+   * @param $_ob text to prepend to output, used by PageUtils::addcomment
+   * @return array
+   * @access private
+   */
+   
+  function comments_raw($page_id, $namespace, $action = false, $flags = Array(), $_ob = '')
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    $pname = $paths->nslist[$namespace] . $page_id;
+    
+    ob_start();
+    
+    if($action && $session->get_permissions('mod_comments')) // Nip hacking attempts in the bud
+    {
+      switch($action) {
+      case "delete":
+        if(isset($flags['id']))
+        {
+          $q = 'DELETE FROM '.table_prefix.'comments WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND comment_id='.intval($flags['id']).' LIMIT 1;';
+        } else {
+          $n = $db->escape($flags['name']);
+          $s = $db->escape($flags['subj']);
+          $t = $db->escape($flags['text']);
+          $q = 'DELETE FROM '.table_prefix.'comments WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND name=\''.$n.'\' AND subject=\''.$s.'\' AND comment_data=\''.$t.'\' LIMIT 1;';
+        }
+        $e=$db->sql_query($q);
+        if(!$e) die('alert(unesape(\''.rawurlencode('Error during query: '.mysql_error().'\n\nQuery:\n'.$q).'\'));');
+        break;
+      case "approve":
+        if(isset($flags['id']))
+        {
+          $where = 'comment_id='.intval($flags['id']);
+        } else {
+          $n = $db->escape($flags['name']);
+          $s = $db->escape($flags['subj']);
+          $t = $db->escape($flags['text']);
+          $where = 'name=\''.$n.'\' AND subject=\''.$s.'\' AND comment_data=\''.$t.'\'';
+        }
+        $q = 'SELECT approved FROM '.table_prefix.'comments WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND '.$where.' LIMIT 1;';
+        $e = $db->sql_query($q);
+        if(!$e) die('alert(unesape(\''.rawurlencode('Error selecting approval status: '.mysql_error().'\n\nQuery:\n'.$q).'\'));');
+        $r = $db->fetchrow();
+        $db->free_result();
+        $a = ( $r['approved'] ) ? '0' : '1';
+        $q = 'UPDATE '.table_prefix.'comments SET approved='.$a.' WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND '.$where.';';
+        $e=$db->sql_query($q);
+        if(!$e) die('alert(unesape(\''.rawurlencode('Error during query: '.mysql_error().'\n\nQuery:\n'.$q).'\'));');
+        if($a=='1') $v = 'Unapprove';
+        else $v = 'Approve';
+        echo 'document.getElementById("mdgApproveLink'.$_GET['id'].'").innerHTML="'.$v.'";';
+        break;
+      }
+    }
+    
+    if(!defined('ENANO_TEMPLATE_LOADED'))
+    {
+      $template->load_theme($session->theme, $session->style);
+    }
+    
+    $tpl = $template->makeParser('comment.tpl');
+    
+    $e = $db->sql_query('SELECT * FROM '.table_prefix.'comments WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND approved=0;');
+    if(!$e) $db->_die('The comment text data could not be selected.');
+    $num_unapp = $db->numrows();
+    $db->free_result();
+    $e = $db->sql_query('SELECT * FROM '.table_prefix.'comments WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND approved=1;');
+    if(!$e) $db->_die('The comment text data could not be selected.');
+    $num_app = $db->numrows();
+    $db->free_result();
+    $lq = $db->sql_query('SELECT c.comment_id,c.subject,c.name,c.comment_data,c.approved,c.time,c.user_id,u.user_level,u.signature
+                  FROM '.table_prefix.'comments AS c
+                  LEFT JOIN '.table_prefix.'users AS u
+                    ON c.user_id=u.user_id
+                  WHERE page_id=\''.$page_id.'\'
+                  AND namespace=\''.$namespace.'\' ORDER BY c.time ASC;');
+    if(!$lq) _die('The comment text data could not be selected. '.mysql_error());
+    $_ob .= '<h3>Article Comments</h3>';
+    $n = ( $session->get_permissions('mod_comments')) ? $db->numrows() : $num_app;
+    if($n==1) $s = 'is '.$n.' comment'; else $s = 'are '.$n.' comments';
+    if($n < 1)
+    {
+      $_ob .= '<p>There are currently no comments on this '.strtolower($namespace).'';
+      if($namespace != 'Article') $_ob .= ' page';
+      $_ob .= '.</p>';
+    } else $_ob .= '<p>There '.$s.' on this article.</p>';
+    if($session->get_permissions('mod_comments') && $num_unapp > 0) $_ob .= ' <span style="color: #D84308">'.$num_unapp.' of those are unapproved.</span>';
+    elseif(!$session->get_permissions('mod_comments') && $num_unapp > 0) { $u = ($num_unapp == 1) ? "is $num_unapp comment" : "are $num_unapp comments"; $_ob .= ' However, there ' . $u . ' awating approval.'; }
+    $list = 'list = { ';
+    // _die(htmlspecialchars($ttext));
+    $i = -1;
+    while($row = $db->fetchrow($lq))
+    {
+      $i++;
+      $strings = Array();
+      $bool = Array();
+      if($session->get_permissions('mod_comments') || $row['approved']) {
+        $list .= $i . ' : { \'comment\' : unescape(\''.rawurlencode($row['comment_data']).'\'), \'name\' : unescape(\''.rawurlencode($row['name']).'\'), \'subject\' : unescape(\''.rawurlencode($row['subject']).'\'), }, ';
+        
+        // Comment ID (used in the Javascript apps)
+        $strings['ID'] = (string)$i;
+        
+        // Determine the name, and whether to link to the user page or not
+        $name = '';
+        if($row['user_id'] > 0) $name .= '<a href="'.makeUrlNS('User', str_replace(' ', '_', $row['name'])).'">';
+        $name .= $row['name'];
+        if($row['user_id'] > 0) $name .= '</a>';
+        $strings['NAME'] = $name; unset($name);
+        
+        // Subject
+        $s = $row['subject'];
+        if(!$row['approved']) $s .= ' <span style="color: #D84308">(Unapproved)</span>';
+        $strings['SUBJECT'] = $s;
+        
+        // Date and time
+        $strings['DATETIME'] = date('F d, Y h:i a', $row['time']);
+        
+        // User level
+        switch($row['user_level'])
+        {
+          default:
+          case USER_LEVEL_GUEST:
+            $l = 'Guest';
+            break;
+          case USER_LEVEL_MEMBER:
+            $l = 'Member';
+            break;
+          case USER_LEVEL_MOD:
+            $l = 'Moderator';
+            break;
+          case USER_LEVEL_ADMIN:
+            $l = 'Administrator';
+            break;
+        }
+        $strings['USER_LEVEL'] = $l; unset($l);
+        
+        // The actual comment data
+        $strings['DATA'] = RenderMan::render($row['comment_data']);
+        
+        if($session->get_permissions('edit_comments'))
+        {
+          // Edit link
+          $strings['EDIT_LINK'] = '<a href="'.makeUrlNS($namespace, $page_id, 'do=comments&amp;sub=editcomment&amp;id='.$row['comment_id']).'" onclick="editComment(\''.$i.'\'); return false;" id="editbtn_'.$i.'">edit</a>';
+        
+          // Delete link
+          $strings['DELETE_LINK'] = '<a href="'.makeUrlNS($namespace, $page_id, 'do=comments&amp;sub=deletecomment&amp;id='.$row['comment_id']).'" onclick="ajaxDeleteComment(\''.$i.'\'); return false;">delete</a>';
+        }
+        else
+        {
+          // Edit link
+          $strings['EDIT_LINK'] = '';
+        
+          // Delete link
+          $strings['DELETE_LINK'] = '';
+        }
+        
+        // Send PM link
+        $strings['SEND_PM_LINK'] = ( $session->user_logged_in && $row['user_id'] > 0 ) ? '<a href="'.makeUrlNS('Special', 'PrivateMessages/Compose/To/'.$row['name']).'">Send private message</a><br />' : '';
+        
+        // Add Buddy link
+        $strings['ADD_BUDDY_LINK'] = ( $session->user_logged_in && $row['user_id'] > 0 ) ? '<a href="'.makeUrlNS('Special', 'PrivateMessages/FriendList/Add/'.$row['name']).'">Add to buddy list</a>' : '';
+        
+        // Mod links
+        $applink = '';
+        $applink .= '<a href="'.makeUrlNS($namespace, $page_id, 'do=comments&amp;sub=admin&amp;action=approve&amp;id='.$row['comment_id']).'" onclick="ajaxCommentAdmin(\'approve\', \''.$i.'\'); return false;" id="mdgApproveLink'.$i.'">';
+        if($row['approved']) $applink .= 'Unapprove';
+        else $applink .= 'Approve';
+        $applink .= '</a>';
+        $strings['MOD_APPROVE_LINK'] = $applink; unset($applink);
+        $strings['MOD_DELETE_LINK'] = '<a href="'.makeUrlNS($namespace, $page_id, 'do=comments&amp;sub=admin&amp;action=delete&amp;id='.$row['comment_id']).'" onclick="ajaxCommentAdmin(\'delete\', \''.$i.'\'); return false;">Delete</a>';
+        
+        // Signature
+        $strings['SIGNATURE'] = '';
+        if($row['signature'] != '') $strings['SIGNATURE'] = RenderMan::render($row['signature']);
+        
+        $bool['auth_mod'] = ($session->get_permissions('mod_comments')) ? true : false;
+        $bool['can_edit'] = ( ( $session->user_logged_in && $row['name'] == $session->username && $session->get_permissions('edit_comments') ) || $session->get_permissions('mod_comments') ) ? true : false;
+        $bool['signature'] = ( $strings['SIGNATURE'] == '' ) ? false : true;
+        
+        // Done processing and compiling, now let's cook it into HTML
+        $tpl->assign_vars($strings);
+        $tpl->assign_bool($bool);
+        $_ob .= $tpl->run();
+      }
+    }
+    if(getConfig('comments_need_login') != '2' || $session->user_logged_in)
+    {
+      if(!$session->get_permissions('post_comments'))
+      {
+        $_ob .= '<h3>Got something to say?</h3><p>Access to post comments on this page is denied.</p>';
+      }
+      else
+      {
+        $_ob .= '<h3>Got something to say?</h3>If you have comments or suggestions on this article, you can shout it out here.';
+        if(getConfig('approve_comments')=='1') $_ob .= '  Before your comment will be visible to the public, a moderator will have to approve it.';
+        if(getConfig('comments_need_login') == '1' && !$session->user_logged_in) $_ob .= ' Because you are not logged in, you will need to enter a visual confirmation before your comment will be posted.';
+        $sn = $session->user_logged_in ? $session->username . '<input name="name" id="mdgScreenName" type="hidden" value="'.$session->username.'" />' : '<input name="name" id="mdgScreenName" type="text" size="35" />';
+        $_ob .= '  <a href="#" id="mdgCommentFormLink" style="display: none;" onclick="document.getElementById(\'mdgCommentForm\').style.display=\'block\';this.style.display=\'none\';return false;">Leave a comment...</a>
+        <div id="mdgCommentForm">
+        <h3>Comment form</h3>
+        <form action="'.makeUrlNS($namespace, $page_id, 'do=comments&amp;sub=postcomment').'" method="post" style="margin-left: 1em">
+        <table border="0">
+        <tr><td>Your name or screen name:</td><td>'.$sn.'</td></tr>
+        <tr><td>Comment subject:</td><td><input name="subj" id="mdgSubject" type="text" size="35" /></td></tr>';
+        if(getConfig('comments_need_login') == '1' && !$session->user_logged_in)
+        {
+          $session->kill_captcha();
+          $captcha = $session->make_captcha();
+          $_ob .= '<tr><td>Visual confirmation:<br /><small>Please enter the code you see on the right.</small></td><td><img src="'.makeUrlNS('Special', 'Captcha/'.$captcha).'" alt="Visual confirmation" style="cursor: pointer;" onclick="this.src = \''.makeUrlNS("Special", "Captcha/".$captcha).'/\'+Math.floor(Math.random() * 100000);" /><input name="captcha_id" id="mdgCaptchaID" type="hidden" value="'.$captcha.'" /><br />Code: <input name="captcha_input" id="mdgCaptchaInput" type="text" size="10" /><br /><small><script type="text/javascript">document.write("If you can\'t read the code, click on the image to generate a new one.");</script><noscript>If you can\'t read the code, please refresh this page to generate a new one.</noscript></small></td></tr>';
+        }
+        $_ob .= '
+        <tr><td valign="top">Comment text:<br />(most HTML will be stripped)</td><td><textarea name="text" id="mdgCommentArea" rows="10" cols="40"></textarea></td></tr>
+        <tr><td colspan="2" style="text-align: center;"><input type="submit" value="Submit Comment" /></td></tr>
+        </table>
+        </form>
+        </div>';
+      }
+    } else {
+      $_ob .= '<h3>Got something to say?</h3><p>You need to be logged in to post comments. <a href="'.makeUrlNS('Special', 'Login/'.$pname.'%2523comments').'">Log in</a></p>';
+    }
+    $list .= '};';
+    echo 'document.getElementById(\'ajaxEditContainer\').innerHTML = unescape(\''. rawurlencode($_ob) .'\');
+    ' . $list;
+    echo 'Fat.fade_all(); document.getElementById(\'mdgCommentForm\').style.display = \'none\'; document.getElementById(\'mdgCommentFormLink\').style.display="inline";';
+    
+    $ret = ob_get_contents();
+    ob_end_clean();
+    return Array($ret, $_ob);
+    
+  }
+  
+  /**
+   * Generates ready-to-execute Javascript code to be eval'ed by the user's browser to display comments
+   * @param $page_id the page ID
+   * @param $namespace the namespace
+   * @param $action administrative action to perform, default is false
+   * @param $flags additional info for $action, shouldn't be used except when deleting/approving comments, etc.
+   * @param $_ob text to prepend to output, used by PageUtils::addcomment
+   * @return string
+   */
+   
+  function comments($page_id, $namespace, $action = false, $id = -1, $_ob = '')
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $r = PageUtils::comments_raw($page_id, $namespace, $action, $id, $_ob);
+    return $r[0];
+  }
+  
+  /**
+   * Generates HTML code for comments - used in browser compatibility mode
+   * @param $page_id the page ID
+   * @param $namespace the namespace
+   * @param $action administrative action to perform, default is false
+   * @param $flags additional info for $action, shouldn't be used except when deleting/approving comments, etc.
+   * @param $_ob text to prepend to output, used by PageUtils::addcomment
+   * @return string
+   */
+  
+  function comments_html($page_id, $namespace, $action = false, $id = -1, $_ob = '')
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $r = PageUtils::comments_raw($page_id, $namespace, $action, $id, $_ob);
+    return $r[1];
+  }
+  
+  /**
+   * Updates comment data.
+   * @param $page_id the page ID
+   * @param $namespace the namespace
+   * @param $subject new subject
+   * @param $text new text
+   * @param $old_subject the old subject, unprocessed and identical to the value in the DB
+   * @param $old_text the old text, unprocessed and identical to the value in the DB
+   * @param $id the javascript list ID, used internally by the client-side app
+   * @return string
+   */
+  
+  function savecomment($page_id, $namespace, $subject, $text, $old_subject, $old_text, $id = -1)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(!$session->get_permissions('edit_comments'))
+      return 'result="BAD";error="Access denied"';
+    // Avoid SQL injection
+    $old_text    = $db->escape($old_text);
+    $old_subject = $db->escape($old_subject);
+    // Safety check - username/login
+    if(!$session->get_permissions('mod_comments')) // allow mods to edit comments
+    {
+      if(!$session->user_logged_in) _die('AJAX comment save safety check failed because you are not logged in. Sometimes this can happen because you are using a browser that does not send cookies as part of AJAX requests.<br /><br />Please log in and try again.');
+      $q = 'SELECT c.name FROM '.table_prefix.'comments c, '.table_prefix.'users u WHERE comment_data=\''.$old_text.'\' AND subject=\''.$old_subject.'\' AND page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND u.user_id=c.user_id;';
+      $s = $db->sql_query($q);
+      if(!$s) _die('SQL error during safety check: '.mysql_error().'<br /><br />Attempted SQL:<br /><pre>'.htmlspecialchars($q).'</pre>');
+      $r = $db->fetchrow($s);
+      $db->free_result();
+      if($db->numrows() < 1 || $r['name'] != $session->username) _die('Safety check failed, probably due to a hacking attempt.');
+    }
+    $s = RenderMan::preprocess_text($subject);
+    $t = RenderMan::preprocess_text($text);
+    $sql  = 'UPDATE '.table_prefix.'comments SET subject=\''.$s.'\',comment_data=\''.$t.'\' WHERE comment_data=\''.$old_text.'\' AND subject=\''.$old_subject.'\' AND page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\'';
+    $result = $db->sql_query($sql);
+    if($result)
+    {
+      return 'result="GOOD";
+                      list['.$id.'][\'subject\'] = unescape(\''.str_replace('%5Cn', '%0A', rawurlencode(str_replace('{{EnAnO:Newline}}', '\\n', stripslashes(str_replace('\\n', '{{EnAnO:Newline}}', $s))))).'\');
+                      list['.$id.'][\'comment\'] = unescape(\''.str_replace('%5Cn', '%0A', rawurlencode(str_replace('{{EnAnO:Newline}}', '\\n', stripslashes(str_replace('\\n', '{{EnAnO:Newline}}', $t))))).'\'); id = '.$id.';
+      s = unescape(\''.rawurlencode($s).'\');
+      t = unescape(\''.str_replace('%5Cn', '<br \\/>', rawurlencode(RenderMan::render(str_replace('{{EnAnO:Newline}}', "\n", stripslashes(str_replace('\\n', '{{EnAnO:Newline}}', $t)))))).'\');';
+    }
+    else
+    {
+      return 'result="BAD"; error=unescape("'.rawurlencode('Enano encountered a problem whilst saving the comment.
+      Performed SQL:
+      '.$sql.'
+    
+      Error returned by MySQL: '.mysql_error()).'");';
+    }
+  }
+  
+  /**
+   * Updates comment data using the comment_id column instead of the old, messy way
+   * @param $page_id the page ID
+   * @param $namespace the namespace
+   * @param $subject new subject
+   * @param $text new text
+   * @param $id the comment ID (primary key in enano_comments table)
+   * @return string
+   */
+  
+  function savecomment_neater($page_id, $namespace, $subject, $text, $id)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(!is_int($id)) die('PageUtils::savecomment: $id is not an integer, aborting for safety');
+    if(!$session->get_permissions('edit_comments'))
+      return 'Access denied';
+    // Safety check - username/login
+    if(!$session->get_permissions('mod_comments')) // allow mods to edit comments
+    {
+      if(!$session->user_logged_in) _die('AJAX comment save safety check failed because you are not logged in. Sometimes this can happen because you are using a browser that does not send cookies as part of AJAX requests.<br /><br />Please log in and try again.');
+      $q = 'SELECT c.name FROM '.table_prefix.'comments c, '.table_prefix.'users u WHERE comment_id='.$id.' AND page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND u.user_id=c.user_id;';
+      $s = $db->sql_query($q);
+      if(!$s) _die('SQL error during safety check: '.mysql_error().'<br /><br />Attempted SQL:<br /><pre>'.htmlspecialchars($q).'</pre>');
+      $r = $db->fetchrow($s);
+      if($db->numrows() < 1 || $r['name'] != $session->username) _die('Safety check failed, probably due to a hacking attempt.');
+      $db->free_result();
+    }
+    $s = RenderMan::preprocess_text($subject);
+    $t = RenderMan::preprocess_text($text);
+    $sql  = 'UPDATE '.table_prefix.'comments SET subject=\''.$s.'\',comment_data=\''.$t.'\' WHERE comment_id='.$id.' AND page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\'';
+    $result = $db->sql_query($sql);
+    if($result)
+    return 'good';
+    else return 'Enano encountered a problem whilst saving the comment.
+    Performed SQL:
+    '.$sql.'
+    
+    Error returned by MySQL: '.mysql_error();
+  }
+  
+  /**
+   * Deletes a comment.
+   * @param $page_id the page ID
+   * @param $namespace the namespace
+   * @param $name the name the user posted under
+   * @param $subj the subject of the comment to be deleted
+   * @param $text the text of the comment to be deleted
+   * @param $id the javascript list ID, used internally by the client-side app
+   * @return string
+   */
+  
+  function deletecomment($page_id, $namespace, $name, $subj, $text, $id)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    if(!$session->get_permissions('edit_comments'))
+      return 'alert("Access to delete/edit comments is denied");';
+    
+    if(!preg_match('#^([0-9]+)$#', (string)$id)) die('$_GET[id] is improperly formed.');
+    $n = $db->escape($name);
+    $s = $db->escape($subj);
+    $t = $db->escape($text);
+    
+    // Safety check - username/login
+    if(!$session->get_permissions('mod_comments')) // allows mods to delete comments
+    {
+      if(!$session->user_logged_in) _die('AJAX comment save safety check failed because you are not logged in. Sometimes this can happen because you are using a browser that does not send cookies as part of AJAX requests.<br /><br />Please log in and try again.');
+      $q = 'SELECT c.name FROM '.table_prefix.'comments c, '.table_prefix.'users u WHERE comment_data=\''.$t.'\' AND subject=\''.$s.'\' AND page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND u.user_id=c.user_id;';
+      $s = $db->sql_query($q);
+      if(!$s) _die('SQL error during safety check: '.mysql_error().'<br /><br />Attempted SQL:<br /><pre>'.htmlspecialchars($q).'</pre>');
+      $r = $db->fetchrow($s);
+      if($db->numrows() < 1 || $r['name'] != $session->username) _die('Safety check failed, probably due to a hacking attempt.');
+      $db->free_result();
+    }
+    $q = 'DELETE FROM '.table_prefix.'comments WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND name=\''.$n.'\' AND subject=\''.$s.'\' AND comment_data=\''.$t.'\' LIMIT 1;';
+    $e=$db->sql_query($q);
+    if(!$e) return('alert(unesape(\''.rawurlencode('Error during query: '.mysql_error().'\n\nQuery:\n'.$q).'\'));');
+    return('good');
+  }
+  
+  /**
+   * Deletes a comment in a cleaner fashion.
+   * @param $page_id the page ID
+   * @param $namespace the namespace
+   * @param $id the comment ID (primary key)
+   * @return string
+   */
+  
+  function deletecomment_neater($page_id, $namespace, $id)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    if(!preg_match('#^([0-9]+)$#', (string)$id)) die('$_GET[id] is improperly formed.');
+    
+    if(!$session->get_permissions('edit_comments'))
+      return 'alert("Access to delete/edit comments is denied");';
+    
+    // Safety check - username/login
+    if(!$session->get_permissions('mod_comments')) // allows mods to delete comments
+    {
+      if(!$session->user_logged_in) _die('AJAX comment save safety check failed because you are not logged in. Sometimes this can happen because you are using a browser that does not send cookies as part of AJAX requests.<br /><br />Please log in and try again.');
+      $q = 'SELECT c.name FROM '.table_prefix.'comments c, '.table_prefix.'users u WHERE comment_id='.$id.' AND page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND u.user_id=c.user_id;';
+      $s = $db->sql_query($q);
+      if(!$s) _die('SQL error during safety check: '.mysql_error().'<br /><br />Attempted SQL:<br /><pre>'.htmlspecialchars($q).'</pre>');
+      $r = $db->fetchrow($s);
+      if($db->numrows() < 1 || $r['name'] != $session->username) _die('Safety check failed, probably due to a hacking attempt.');
+      $db->free_result();
+    }
+    $q = 'DELETE FROM '.table_prefix.'comments WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND comment_id='.$id.' LIMIT 1;';
+    $e=$db->sql_query($q);
+    if(!$e) return('alert(unesape(\''.rawurlencode('Error during query: '.mysql_error().'\n\nQuery:\n'.$q).'\'));');
+    return('good');
+  }
+  
+  /**
+   * Renames a page.
+   * @param $page_id the page ID
+   * @param $namespace the namespace
+   * @param $name the new name for the page
+   * @return string error string or success message
+   */
+   
+  function rename($page_id, $namespace, $name)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    $pname = $paths->nslist[$namespace] . $page_id;
+    
+    $prot = ( ( $paths->pages[$pname]['protected'] == 2 && $session->user_logged_in && $session->reg_time + 60*60*24*4 < time() ) || $paths->pages[$pname]['protected'] == 1) ? true : false;
+    $wiki = ( ( $paths->pages[$pname]['wiki_mode'] == 2 && getConfig('wiki_mode') == '1') || $paths->pages[$pname]['wiki_mode'] == 1) ? true : false;
+    
+    if( empty($name)) die('Name is too short');
+    if( ( $session->get_permissions('rename') && ( ( $prot && $session->get_permissions('even_when_protected') ) || !$prot ) ) && ( $paths->namespace != 'Special' && $paths->namespace != 'Admin' )) {
+      $e = $db->sql_query('INSERT INTO '.table_prefix.'logs(time_id,date_string,log_type,action,page_id,namespace,author,edit_summary) VALUES('.time().', \''.date('d M Y h:i a').'\', \'page\', \'rename\', \''.$paths->cpage['urlname_nons'].'\', \''.$paths->namespace.'\', \''.$session->username.'\', \''.$paths->cpage['name'].'\')');
+      if(!$e) $db->_die('The page title could not be updated.');
+      $e = $db->sql_query('UPDATE '.table_prefix.'pages SET name=\''.$db->escape($name).'\' WHERE urlname=\''.$page_id.'\' AND namespace=\''.$namespace.'\';');
+      if(!$e) $db->_die('The page title could not be updated.');
+      else return('The page "'.$paths->pages[$pname]['name'].'" has been renamed to "'.$name.'". You are encouraged to leave a comment explaining your action.
+
+You will see the change take effect the next time you reload this page.');
+    } else {
+      return('Access is denied.');
+    }
+  }
+  
+  /**
+   * Flushes (clears) the action logs for a given page
+   * @param $page_id the page ID
+   * @param $namespace the namespace
+   * @return string error/success string
+   */
+   
+  function flushlogs($page_id, $namespace)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(!$session->get_permissions('clear_logs')) die('Administrative privileges are required to flush logs, you loser.');
+    $e = $db->sql_query('DELETE FROM '.table_prefix.'logs WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\';');
+    if(!$e) $db->_die('The log entries could not be deleted.');
+    $e = $db->sql_query('SELECT page_text,char_tag FROM '.table_prefix.'page_text WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\';');
+    if(!$e) $db->_die('The current page text could not be selected; as a result, creating the backup of the page failed. Please make a backup copy of the page by clicking Edit this page and then clicking Save Changes.');
+    $row = $db->fetchrow();
+    $db->free_result();
+    $q='INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,page_id,namespace,page_text,char_tag,author,edit_summary,minor_edit) VALUES(\'page\', \'edit\', '.time().', \''.date('d M Y h:i a').'\', \''.$page_id.'\', \''.$namespace.'\', \''.$db->escape($row['page_text']).'\', \''.$row['char_tag'].'\', \''.$session->username.'\', \''."Automatic backup created when logs were purged".'\', '.'false'.');';
+    if(!$db->sql_query($q)) $db->_die('The history (log) entry could not be inserted into the logs table.');
+    return('The logs for this page have been cleared. A backup of this page has been added to the logs table so that this page can be restored in case of vandalism or spam later.');
+  }
+  
+  /**
+   * Deletes a page.
+   * @param $page_id the condemned page ID
+   * @param $namespace the condemned namespace
+   * @return string
+   */
+   
+  function deletepage($page_id, $namespace)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $perms = $session->fetch_page_acl($page_id, $namespace);
+    if(!$perms->get_permissions('delete_page')) die('Administrative privileges are required to delete pages, you loser.');
+    $e = $db->sql_query('INSERT INTO '.table_prefix.'logs(time_id,date_string,log_type,action,page_id,namespace,author) VALUES('.time().', \''.date('d M Y h:i a').'\', \'page\', \'delete\', \''.$page_id.'\', \''.$namespace.'\', \''.$session->username.'\')');
+    if(!$e) $db->_die('The page log entry could not be inserted.');
+    $e = $db->sql_query('DELETE FROM '.table_prefix.'categories WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\'');
+    if(!$e) $db->_die('The page categorization entries could not be deleted.');
+    $e = $db->sql_query('DELETE FROM '.table_prefix.'comments WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\'');
+    if(!$e) $db->_die('The page comments could not be deleted.');
+    $e = $db->sql_query('DELETE FROM '.table_prefix.'page_text WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\'');
+    if(!$e) $db->_die('The page text entry could not be deleted.');
+    $e = $db->sql_query('DELETE FROM '.table_prefix.'pages WHERE urlname=\''.$page_id.'\' AND namespace=\''.$namespace.'\'');
+    if(!$e) $db->_die('The page entry could not be deleted.');
+    $e = $db->sql_query('DELETE FROM '.table_prefix.'files WHERE page_id=\''.$page_id.'\'');
+    if(!$e) $db->_die('The file entry could not be deleted.');
+    return('This page has been deleted. Note that there is still a log of edits and actions in the database, and anyone with admin rights can raise this page from the dead unless the log is cleared. If the deleted file is an image, there may still be cached thumbnails of it in the cache/ directory, which is inaccessible to users.');
+  }
+  
+  /**
+   * Increments the deletion votes for a page by 1, and adds the current username/IP to the list of users that have voted for the page to prevent dual-voting
+   * @param $page_id the page ID
+   * @param $namespace the namespace
+   * @return string
+   */
+   
+  function delvote($page_id, $namespace)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(!$session->get_permissions('vote_delete'))
+      return 'Access denied';
+    $pname = $paths->nslist[$namespace] . $page_id;
+    $cv = $paths->pages[$pname]['delvotes'];
+    $ips = $paths->pages[$pname]['delvote_ips'];
+    $ips = explode('|', $ips);
+    if(in_array($_SERVER['REMOTE_ADDR'], $ips)) return('It appears that you have already voted to have this page deleted.');
+    if($session->user_logged_in)
+      if(in_array($session->username, $ips))
+        return('It appears that you have already voted to have this page deleted.');
+    $ips[] = $_SERVER['REMOTE_ADDR'];
+    if($session->user_logged_in) $ips[] = $session->username;
+    $ips = implode('|', $ips);
+    $ips = substr($ips, 1, strlen($ips));
+    $cv++;
+    $q = 'UPDATE '.table_prefix.'pages SET delvotes='.$cv.',delvote_ips=\''.$ips.'\' WHERE urlname=\''.$page_id.'\' AND namespace=\''.$namespace.'\'';
+    $w = $db->sql_query($q);
+    if(!$w) return("Error updating pages table: ".mysql_error()."\n\nAttemped SQL:\n".$q);
+    return('Your vote to have this page deleted has been cast.'."\nYou are encouraged to leave a comment explaining the reason for your vote.");
+  }
+  
+  /**
+   * Resets the number of votes against a page to 0.
+   * @param $page_id the page ID
+   * @param $namespace the namespace
+   * @return string
+   */
+  
+  function resetdelvotes($page_id, $namespace)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(!$session->get_permissions('vote_reset')) die('You need moderator rights in order to do this, stinkin\' hacker.');
+    $q = 'UPDATE '.table_prefix.'pages SET delvotes=0,delvote_ips=\'\' WHERE urlname=\''.$page_id.'\' AND namespace=\''.$namespace.'\'';
+    $e = $db->sql_query($q);
+    if(!$e) $db->_die('The number of delete votes was not reset.');
+    else return('The number of votes for having this page deleted has been reset to zero.');
+  }
+  
+  /**
+   * Gets a list of styles for a given theme name.
+   * @param $id the name of the directory for the theme
+   * @return string Javascript code
+   */
+   
+  function getstyles()
+  {
+    $dir = './themes/'.$_GET['id'].'/css/';
+    $list = Array();
+    // Open a known directory, and proceed to read its contents
+    if (is_dir($dir)) {
+      if ($dh = opendir($dir)) {
+        while (($file = readdir($dh)) !== false) {
+          if(preg_match('#^(.*?)\.css$#is', $file) && $file != '_printable.css') { // _printable.css should be included with every theme
+                                                                                    // it should be a copy of the original style, but
+                                                                                    // mostly black and white
+                                                                                    // Note to self: document this
+            $list[] = substr($file, 0, strlen($file)-4);
+          }
+        }
+        closedir($dh);
+      }
+    } else return($dir.' is not a dir');
+    $l = 'var list = new Array();';
+    $i = -1;
+    foreach($list as $li) {
+      $i++;
+      $l .= "list[$i] = '$li';";
+    }
+    return $l;
+  }
+  
+  /**
+   * Assembles a Javascript app with category information
+   * @param $page_id the page ID
+   * @param $namespace the namespace
+   * @return string Javascript code
+   */
+   
+  function catedit($page_id, $namespace)
+  {
+    $d = PageUtils::catedit_raw($page_id, $namespace);
+    return $d[0] . ' /* BEGIN CONTENT */ document.getElementById("ajaxEditContainer").innerHTML = unescape(\''.rawurlencode($d[1]).'\');';
+  }
+  
+  /**
+   * Does the actual HTML/javascript generation for cat editing, but returns an array
+   * @access private
+   */
+   
+  function catedit_raw($page_id, $namespace)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    ob_start();
+    $_ob = '';
+    $e = $db->sql_query('SELECT category_id FROM '.table_prefix.'categories WHERE page_id=\''.$paths->cpage['urlname_nons'].'\' AND namespace=\''.$paths->namespace.'\'');
+    if(!$e) jsdie('Error selecting category information for current page: '.mysql_error());
+    $cat_current = Array();
+    while($r = $db->fetchrow())
+    {
+      $cat_current[] = $r;
+    }
+    $db->free_result();
+    $cat_all = Array();
+    for($i=0;$i<sizeof($paths->pages)/2;$i++)
+    {
+      if($paths->pages[$i]['namespace']=='Category') $cat_all[] = $paths->pages[$i];
+    }
+    
+    // Make $cat_all an associative array, like $paths->pages
+    $sz = sizeof($cat_all);
+    for($i=0;$i<$sz;$i++)
+    {
+      $cat_all[$cat_all[$i]['urlname_nons']] = $cat_all[$i];
+    }
+    // Now, the "zipper" function - join the list of categories with the list of cats that this page is a part of
+    $cat_info = $cat_all;
+    for($i=0;$i<sizeof($cat_current);$i++)
+    {
+      $un = $cat_current[$i]['category_id'];
+      $cat_info[$un]['member'] = true;
+    }
+    // Now copy the information we just set into the numerically named keys
+    for($i=0;$i<sizeof($cat_info)/2;$i++)
+    {
+      $un = $cat_info[$i]['urlname_nons'];
+      $cat_info[$i] = $cat_info[$un];
+    }
+    
+    echo 'catlist = new Array();'; // Initialize the client-side category list
+    $_ob .= '<h3>Select which categories this page should be included in.</h3>
+             <form name="mdgCatForm" action="'.makeUrlNS($namespace, $page_id, 'do=catedit').'" method="post">';
+    if ( sizeof($cat_info) < 1 )
+    {
+      $_ob .= '<p>There are no categories on this site yet.</p>';
+    }
+    for ( $i = 0; $i < sizeof($cat_info) / 2; $i++ )
+    {
+      // Protection code added 1/3/07
+      // Updated 3/4/07
+      $is_prot = false;
+      $perms = $session->fetch_page_acl($cat_info[$i]['urlname_nons'], 'Category');
+      if ( !$session->get_permissions('edit_cat') || !$perms->get_permissions('edit_cat') ||
+         ( $cat_info[$i]['really_protected'] && !$perms->get_permissions('even_when_protected') ) )
+         $is_prot = true;
+      $prot = ( $is_prot ) ? ' disabled="disabled" ' : '';
+      $prottext = ( $is_prot ) ? ' <img alt="(protected)" width="16" height="16" src="'.scriptPath.'/images/lock16.png" />' : '';
+      echo 'catlist['.$i.'] = \''.$cat_info[$i]['urlname_nons'].'\';';
+      $_ob .= '<span class="catCheck"><input '.$prot.' name="'.$cat_info[$i]['urlname_nons'].'" id="mdgCat_'.$cat_info[$i]['urlname_nons'].'" type="checkbox"';
+      if(isset($cat_info[$i]['member'])) $_ob .= ' checked="checked"';
+      $_ob .= '/>  <label for="mdgCat_'.$cat_info[$i]['urlname_nons'].'">'.$cat_info[$i]['name'].$prottext.'</label></span><br />';
+    }
+    
+    $disabled = ( sizeof($cat_info) < 1 ) ? 'disabled="disabled"' : '';
+      
+    $_ob .= '<div style="border-top: 1px solid #CCC; padding-top: 5px; margin-top: 10px;"><input name="__enanoSaveButton" ' . $disabled . ' style="font-weight: bold;" type="submit" onclick="ajaxCatSave(); return false;" value="Save changes" /> <input name="__enanoCatCancel" type="submit" onclick="ajaxReset(); return false;" value="Cancel" /></div></form>';
+    
+    $cont = ob_get_contents();
+    ob_end_clean();
+    return Array($cont, $_ob);
+  }
+  
+  /**
+   * Saves category information
+   * WARNING: If $which_cats is empty, all the category information for the selected page will be nuked!
+   * @param $page_id string the page ID
+   * @param $namespace string the namespace
+   * @param $which_cats array associative array of categories to put the page in
+   * @return string "GOOD" on success, error string on failure
+   */
+  
+  function catsave($page_id, $namespace, $which_cats)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(!$session->get_permissions('edit_cat')) return('Insufficient privileges to change category information');
+    
+    $page_perms = $session->fetch_page_acl($page_id, $namespace);
+    $page_data =& $paths->pages[$paths->nslist[$namespace].$page_id];
+    
+    $cat_all = Array();
+    for($i=0;$i<sizeof($paths->pages)/2;$i++)
+    {
+      if($paths->pages[$i]['namespace']=='Category') $cat_all[] = $paths->pages[$i];
+    }
+    
+    // Make $cat_all an associative array, like $paths->pages
+    $sz = sizeof($cat_all);
+    for($i=0;$i<$sz;$i++)
+    {
+      $cat_all[$cat_all[$i]['urlname_nons']] = $cat_all[$i];
+    }
+    
+    $rowlist = Array();
+    
+    for($i=0;$i<sizeof($cat_all)/2;$i++)
+    {
+      $auth = true;
+      $perms = $session->fetch_page_acl($cat_all[$i]['urlname_nons'], 'Category');
+      if ( !$session->get_permissions('edit_cat') || !$perms->get_permissions('edit_cat') ||
+         ( $cat_all[$i]['really_protected'] && !$perms->get_permissions('even_when_protected') ) ||
+         ( !$page_perms->get_permissions('even_when_protected') && $page_data['protected'] == '1' ) )
+         $auth = false;
+      if(!$auth)
+      {
+        // Find out if the page is currently in the category
+        $q = $db->sql_query('SELECT * FROM '.table_prefix.'categories WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\';');
+        if(!$q)
+          return 'MySQL error: '.$db->get_error();
+        if($db->numrows() > 0)
+        {
+          $auth = true;
+          $which_cats[$cat_all[$i]['urlname_nons']] = true; // Force the category to stay in its current state
+        }
+        $db->free_result();
+      }
+      if(isset($which_cats[$cat_all[$i]['urlname_nons']]) && $which_cats[$cat_all[$i]['urlname_nons']] == true /* for clarity ;-) */ && $auth ) $rowlist[] = '(\''.$page_id.'\', \''.$namespace.'\', \''.$cat_all[$i]['urlname_nons'].'\')';
+    }
+    if(sizeof($rowlist) > 0)
+    {
+      $val = implode(',', $rowlist);
+      $q = 'INSERT INTO '.table_prefix.'categories(page_id,namespace,category_id) VALUES' . $val . ';';
+      $e = $db->sql_query('DELETE FROM '.table_prefix.'categories WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\';');
+      if(!$e) $db->_die('The old category data could not be deleted.');
+      $e = $db->sql_query($q);
+      if(!$e) $db->_die('The new category data could not be inserted.');
+      return('GOOD');
+    }
+    else
+    {
+      $e = $db->sql_query('DELETE FROM '.table_prefix.'categories WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\';');
+      if(!$e) $db->_die('The old category data could not be deleted.');
+      return('GOOD');
+    }
+  }
+  
+  /**
+   * Sets the wiki mode level for a page.
+   * @param $page_id string the page ID
+   * @param $namespace string the namespace
+   * @param $level int 0 for off, 1 for on, 2 for use global setting
+   * @return string "GOOD" on success, error string on failure
+   */
+  
+  function setwikimode($page_id, $namespace, $level)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(!$session->get_permissions('set_wiki_mode')) return('Insufficient access rights');
+    if(!isset($level) || (isset($level) && !preg_match('#^([0-2]){1}$#', (string)$level))) return('Invalid mode string');
+    $q = $db->sql_query('UPDATE '.table_prefix.'pages SET wiki_mode='.$level.' WHERE urlname=\''.$page_id.'\' AND namespace=\''.$namespace.'\';');
+    if(!$q) return('Error during update query: '.mysql_error()."\n\nSQL Backtrace:\n".$db->sql_backtrace());
+    return('GOOD');
+  }
+  
+  /**
+   * Sets the access password for a page.
+   * @param $page_id string the page ID
+   * @param $namespace string the namespace
+   * @param $pass string the SHA1 hash of the password - if the password doesn't match the regex ^([0-9a-f]*){40,40}$ it will be sha1'ed
+   * @return string
+   */
+  
+  function setpass($page_id, $namespace, $pass)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    // Determine permissions
+    if($paths->pages[$paths->nslist[$namespace].$page_id]['password'] != '')
+      $a = $session->get_permissions('password_reset');
+    else
+      $a = $session->get_permissions('password_set');
+    if(!$a)
+      return 'Access is denied';
+    if(!isset($pass)) return('Password was not set on URL');
+    $p = $pass;
+    if(!preg_match('#([0-9a-f]){40,40}#', $p)) $p = sha1($p);
+    if($p=='da39a3ee5e6b4b0d3255bfef95601890afd80709') $p = '';
+    $e = $db->sql_query('UPDATE '.table_prefix.'pages SET password=\''.$p.'\' WHERE urlname=\''.$page_id.'\' AND namespace=\''.$namespace.'\';');
+    if(!$e) die('PageUtils::setpass(): Error during update query: '.mysql_error()."\n\nSQL Backtrace:\n".$db->sql_backtrace());
+    if($p=='') return('The password for this page has been disabled.');
+    else return('The password for this page has been set.');
+  }
+  
+  /**
+   * Generates some preview HTML
+   * @param $text string the wikitext to use
+   * @return string
+   */
+   
+  function genPreview($text)
+  {
+    return '<div class="info-box"><b>Reminder:</b> This is only a preview - your changes to this page have not yet been saved.</div><div style="background-color: #F8F8F8; padding: 10px; border: 1px dashed #406080; max-height: 250px; overflow: auto; margin: 1em 0 1em 1em;">'.RenderMan::render(RenderMan::preprocess_text($text, false, false)).'</div>';
+  }
+  
+  /**
+   * Makes a scrollable box
+   * @param string $text the inner HTML
+   * @param int $height Optional - the maximum height. Defaults to 250.
+   * @return string
+   */
+   
+  function scrollBox($text, $height = 250)
+  {
+    return '<div style="background-color: #F8F8F8; padding: 10px; border: 1px dashed #406080; max-height: '.(string)intval($height).'px; overflow: auto; margin: 1em 0 1em 1em;">'.$text.'</div>';
+  }
+  
+  /**
+   * Generates a diff summary between two page revisions.
+   * @param $page_id the page ID
+   * @param $namespace the namespace
+   * @param $id1 the time ID of the first revision
+   * @param $id2 the time ID of the second revision
+   * @return string XHTML-formatted diff
+   */
+   
+  function pagediff($page_id, $namespace, $id1, $id2)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(!$session->get_permissions('history_view'))
+      return 'Access denied';
+    if(!preg_match('#^([0-9]+)$#', (string)$id1) ||
+       !preg_match('#^([0-9]+)$#', (string)$id2  )) return 'SQL injection attempt';
+    // OK we made it through security
+    // Safest way to make sure we don't end up with the revisions in wrong columns is to make 2 queries
+    if(!$q1 = $db->sql_query('SELECT page_text,char_tag,author,edit_summary FROM '.table_prefix.'logs WHERE time_id='.$id1.' AND log_type=\'page\' AND action=\'edit\' AND page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\';')) return 'MySQL error: '.mysql_error();
+    if(!$q2 = $db->sql_query('SELECT page_text,char_tag,author,edit_summary FROM '.table_prefix.'logs WHERE time_id='.$id2.' AND log_type=\'page\' AND action=\'edit\' AND page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\';')) return 'MySQL error: '.mysql_error();
+    $row1 = $db->fetchrow($q1);
+    $db->free_result($q1);
+    $row2 = $db->fetchrow($q2);
+    $db->free_result($q2);
+    if(sizeof($row1) < 1 || sizeof($row2) < 2) return 'Couldn\'t find any rows that matched the query. The time ID probably doesn\'t exist in the logs table.';
+    $text1 = $row1['page_text'];
+    $text2 = $row2['page_text'];
+    $time1 = date('F d, Y h:i a', $id1);
+    $time2 = date('F d, Y h:i a', $id2);
+    $_ob = "
+    <p>Comparing revisions: {$time1} &rarr; {$time2}</p>
+    ";
+    // Free some memory
+    unset($row1, $row2, $q1, $q2);
+    
+    $_ob .= RenderMan::diff($text1, $text2);
+    return $_ob;
+  }
+  
+  /**
+   * Gets ACL information about the selected page for target type X and target ID Y.
+   * @param string $page_id The page ID
+   * @param string $namespace The namespace
+   * @param array $parms What to select. This is an array purely for JSON compatibility. It should be an associative array with keys target_type and target_id.
+   * @return array
+   */
+   
+  function acl_editor($parms = Array())
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(!$session->get_permissions('edit_acl') && $session->user_level < USER_LEVEL_ADMIN)
+      return 'Access is denied.';
+    $parms['page_id'] = ( isset($parms['page_id']) ) ? $parms['page_id'] : false;
+    $parms['namespace'] = ( isset($parms['namespace']) ) ? $parms['namespace'] : false;
+    $page_id =& $parms['page_id'];
+    $namespace =& $parms['namespace'];
+    $page_where_clause      = ( empty($page_id) || empty($namespace) ) ? 'AND a.page_id IS NULL AND a.namespace IS NULL' : 'AND a.page_id=\''.$db->escape($page_id).'\' AND a.namespace=\''.$db->escape($namespace).'\'';
+    $page_where_clause_lite = ( empty($page_id) || empty($namespace) ) ? 'AND page_id IS NULL AND namespace IS NULL' : 'AND page_id=\''.$db->escape($page_id).'\' AND namespace=\''.$db->escape($namespace).'\'';
+    //die(print_r($page_id,true));
+    $template->load_theme();
+    // $perms_obj = $session->fetch_page_acl($page_id, $namespace);
+    $perms_obj =& $session;
+    $return = Array();
+    if ( !file_exists(ENANO_ROOT . '/themes/' . $session->theme . '/acledit.tpl') )
+    {
+      return Array(
+        'mode' => 'error',
+        'error' => 'It seems that (a) the file acledit.tpl is missing from these theme, and (b) the JSON response is working.',
+      );
+    }
+    $return['template'] = $template->extract_vars('acledit.tpl');
+    $return['page_id'] = $page_id;
+    $return['namespace'] = $namespace;
+    if(isset($parms['mode']))
+    {
+      switch($parms['mode'])
+      {
+        case 'listgroups':
+          $return['groups'] = Array();
+          $q = $db->sql_query('SELECT group_id,group_name FROM '.table_prefix.'groups ORDER BY group_name ASC;');
+          while($row = $db->fetchrow())
+          {
+            $return['groups'][] = Array(
+              'id' => $row['group_id'],
+              'name' => $row['group_name'],
+              );
+          }
+          $db->free_result();
+          break;
+        case 'seltarget':
+          $return['mode'] = 'seltarget';
+          $return['acl_types'] = $perms_obj->acl_types;
+          $return['acl_deps'] = $perms_obj->acl_deps;
+          $return['acl_descs'] = $perms_obj->acl_descs;
+          $return['target_type'] = $parms['target_type'];
+          $return['target_id'] = $parms['target_id'];
+          switch($parms['target_type'])
+          {
+            case ACL_TYPE_USER:
+              $q = $db->sql_query('SELECT a.rules,u.user_id FROM '.table_prefix.'users AS u
+                  LEFT JOIN '.table_prefix.'acl AS a
+                    ON a.target_id=u.user_id
+                  WHERE a.target_type='.ACL_TYPE_USER.'
+                    AND u.username=\''.$db->escape($parms['target_id']).'\'
+                    '.$page_where_clause.';');
+              if(!$q)
+                return(Array('mode'=>'error','error'=>mysql_error()));
+              if($db->numrows() < 1)
+              {
+                $return['type'] = 'new';
+                $q = $db->sql_query('SELECT user_id FROM '.table_prefix.'users WHERE username=\''.$db->escape($parms['target_id']).'\';');
+                if(!$q)
+                  return(Array('mode'=>'error','error'=>mysql_error()));
+                if($db->numrows() < 1)
+                  return Array('mode'=>'error','error'=>'The username you entered was not found.');
+                $row = $db->fetchrow();
+                $return['target_name'] = $return['target_id'];
+                $return['target_id'] = intval($row['user_id']);
+                $return['current_perms'] = $session->acl_types;
+              }
+              else
+              {
+                $return['type'] = 'edit';
+                $row = $db->fetchrow();
+                $return['target_name'] = $return['target_id'];
+                $return['target_id'] = intval($row['user_id']);
+                $return['current_perms'] = $session->acl_merge($perms_obj->acl_types, $session->string_to_perm($row['rules']));
+              }
+              $db->free_result();
+              // Eliminate types that don't apply to this namespace
+              if ( $namespace )
+              {
+                foreach ( $return['current_perms'] AS $i => $perm )
+                {
+                  if ( ( $page_id != null && $namespace != null ) && ( !in_array ( $namespace, $session->acl_scope[$i] ) && !in_array('All', $session->acl_scope[$i]) ) )
+                  {
+                    // echo "// SCOPE CONTROL: eliminating: $i\n";
+                    unset($return['current_perms'][$i]);
+                    unset($return['acl_types'][$i]);
+                    unset($return['acl_descs'][$i]);
+                    unset($return['acl_deps'][$i]);
+                  }
+                }
+              }
+              break;
+            case ACL_TYPE_GROUP:
+              $q = $db->sql_query('SELECT a.rules,g.group_name,g.group_id FROM '.table_prefix.'groups AS g
+                  LEFT JOIN '.table_prefix.'acl AS a
+                    ON a.target_id=g.group_id
+                  WHERE a.target_type='.ACL_TYPE_GROUP.'
+                    AND g.group_id=\''.intval($parms['target_id']).'\'
+                    '.$page_where_clause.';');
+              if(!$q)
+                return(Array('mode'=>'error','error'=>mysql_error()));
+              if($db->numrows() < 1)
+              {
+                $return['type'] = 'new';
+                $q = $db->sql_query('SELECT group_id,group_name FROM '.table_prefix.'groups WHERE group_id=\''.intval($parms['target_id']).'\';');
+                if(!$q)
+                  return(Array('mode'=>'error','error'=>mysql_error()));
+                if($db->numrows() < 1)
+                  return Array('mode'=>'error','error'=>'The group ID you submitted is not valid.');
+                $row = $db->fetchrow();
+                $return['target_name'] = $row['group_name'];
+                $return['target_id'] = intval($row['group_id']);
+                $return['current_perms'] = $session->acl_types;
+              }
+              else
+              {
+                $return['type'] = 'edit';
+                $row = $db->fetchrow();
+                $return['target_name'] = $row['group_name'];
+                $return['target_id'] = intval($row['group_id']);
+                $return['current_perms'] = $session->acl_merge($session->acl_types, $session->string_to_perm($row['rules']));
+              }
+              $db->free_result();
+              // Eliminate types that don't apply to this namespace
+              if ( $namespace )
+              {
+                foreach ( $return['current_perms'] AS $i => $perm )
+                {
+                  if ( ( $page_id != false && $namespace != false ) && ( !in_array ( $namespace, $session->acl_scope[$i] ) && !in_array('All', $session->acl_scope[$i]) ) )
+                  {
+                    // echo "// SCOPE CONTROL: eliminating: $i\n"; //; ".print_r($namespace,true).":".print_r($page_id,true)."\n";
+                    unset($return['current_perms'][$i]);
+                    unset($return['acl_types'][$i]);
+                    unset($return['acl_descs'][$i]);
+                    unset($return['acl_deps'][$i]);
+                  }
+                }
+              }
+              //return Array('mode'=>'debug','text'=>print_r($return, true));
+              break;
+            default:
+              return Array('mode'=>'error','error','Invalid ACL type ID');
+              break;
+          }
+          return $return;
+          break;
+        case 'save_new':
+        case 'save_edit':
+          $q = $db->sql_query('DELETE FROM '.table_prefix.'acl WHERE target_type='.intval($parms['target_type']).' AND target_id='.intval($parms['target_id']).'
+            '.$page_where_clause_lite.';');
+          if(!$q)
+            return Array('mode'=>'error','error'=>mysql_error());
+          $rules = $session->perm_to_string($parms['perms']);
+          if ( sizeof ( $rules ) < 1 )
+          {
+            return array(
+                'mode' => 'error', 
+                'error' => 'Supplied rule list has a length of zero'
+              );
+          }
+          $q = ($page_id && $namespace) ? 'INSERT INTO '.table_prefix.'acl ( target_type, target_id, page_id, namespace, rules )
+                                             VALUES( '.intval($parms['target_type']).', '.intval($parms['target_id']).', \''.$db->escape($page_id).'\', \''.$db->escape($namespace).'\', \''.$db->escape($rules).'\' )' :
+                                          'INSERT INTO '.table_prefix.'acl ( target_type, target_id, rules )
+                                             VALUES( '.intval($parms['target_type']).', '.intval($parms['target_id']).', \''.$db->escape($rules).'\' )';
+          if(!$db->sql_query($q)) return Array('mode'=>'error','error'=>mysql_error());
+          return Array(
+              'mode' => 'success',
+              'target_type' => $parms['target_type'],
+              'target_id' => $parms['target_id'],
+              'target_name' => $parms['target_name'],
+              'page_id' => $page_id,
+              'namespace' => $namespace,
+            );
+          break;
+        case 'delete':
+          $q = $db->sql_query('DELETE FROM '.table_prefix.'acl WHERE target_type='.intval($parms['target_type']).' AND target_id='.intval($parms['target_id']).'
+            '.$page_where_clause_lite.';');
+          if(!$q)
+            return Array('mode'=>'error','error'=>mysql_error());
+          return Array(
+              'mode' => 'delete',
+              'target_type' => $parms['target_type'],
+              'target_id' => $parms['target_id'],
+              'target_name' => $parms['target_name'],
+              'page_id' => $page_id,
+              'namespace' => $namespace,
+            );
+          break;
+        default:
+          return Array('mode'=>'error','error'=>'Hacking attempt');
+          break;
+      }
+    }
+    return $return;
+  }
+  
+  /**
+   * Same as PageUtils::acl_editor(), but the parms are a JSON string instead of an array. This also returns a JSON string.
+   * @param string $parms Same as PageUtils::acl_editor/$parms, but should be a valid JSON string.
+   * @return string
+   */
+   
+  function acl_json($parms = '{ }')
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $json = new Services_JSON(SERVICES_JSON_LOOSE_TYPE);
+    $parms = $json->decode($parms);
+    $ret = PageUtils::acl_editor($parms);
+    $ret = $json->encode($ret);
+    return $ret;
+  }
+  
+  /**
+   * A non-Javascript frontend for the ACL API.
+   * @param array The request data, if any, this should be in the format required by PageUtils::acl_editor()
+   */
+   
+  function aclmanager($parms)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    ob_start();
+    // Convenience
+    $formstart = '<form 
+                    action="' . makeUrl($paths->page, 'do=aclmanager', true) . '"
+                    method="post" enctype="multipart/form-data"
+                    onsubmit="if(!submitAuthorized) return false;"
+                    >';
+    $formend   = '</form>';
+    $parms    = PageUtils::acl_preprocess($parms);
+    $response = PageUtils::acl_editor($parms);
+    $response = PageUtils::acl_postprocess($response);
+    
+    //die('<pre>' . htmlspecialchars(print_r($response, true)) . '</pre>');
+    
+    switch($response['mode'])
+    {
+      case 'debug':
+        echo '<pre>' . htmlspecialchars($response['text']) . '</pre>';
+        break;
+      case 'stage1':
+        echo '<h3>Manage page access</h3>
+              <p>Please select who should be affected by this access rule.</p>';
+        echo $formstart;
+        echo '<p><label><input type="radio" name="data[target_type]" value="' . ACL_TYPE_GROUP . '" checked="checked" /> A usergroup</label></p>
+              <p><select name="data[target_id_grp]">';
+        foreach ( $response['groups'] as $group )
+        {
+          echo '<option value="' . $group['id'] . '">' . $group['name'] . '</option>';
+        }
+        echo '</select></p>
+              <p><label><input type="radio" name="data[target_type]" value="' . ACL_TYPE_USER . '" /> A specific user</label></p>
+              <p>' . $template->username_field('data[target_id_user]') . '</p>
+              <p>What should this access rule control?</p>
+              <p><label><input name="data[scope]" value="only_this" type="radio" checked="checked" /> Only this page</p>
+              <p><label><input name="data[scope]" value="entire_site" type="radio" /> The entire site</p>
+              <div style="margin: 0 auto 0 0; text-align: right;">
+                <input name="data[mode]" value="seltarget" type="hidden" />
+                <input type="hidden" name="data[page_id]" value="' . $paths->cpage['urlname_nons'] . '" />
+                <input type="hidden" name="data[namespace]" value="' . $paths->namespace . '" />
+                <input type="submit" value="Next &gt;" />
+              </div>';
+        echo $formend;
+        break;
+      case 'success':
+        echo '<div class="info-box">
+                <b>Permissions updated</b><br />
+                The permissions for ' . $response['target_name'] . ' on this page have been updated successfully.<br />
+                ' . $formstart . '
+                <input type="hidden" name="data[mode]" value="seltarget" />
+                <input type="hidden" name="data[target_type]" value="' . $response['target_type'] . '" />
+                <input type="hidden" name="data[target_id_user]" value="' . ( ( intval($response['target_type']) == ACL_TYPE_USER ) ? $response['target_name'] : $response['target_id'] ) .'" />
+                <input type="hidden" name="data[target_id_grp]"  value="' . ( ( intval($response['target_type']) == ACL_TYPE_USER ) ? $response['target_name'] : $response['target_id'] ) .'" />
+                <input type="hidden" name="data[scope]" value="' . ( ( $response['page_id'] ) ? 'only_this' : 'entire_site' ) . '" />
+                <input type="hidden" name="data[page_id]" value="' . ( ( $response['page_id'] ) ? $response['page_id'] : 'false' ) . '" />
+                <input type="hidden" name="data[namespace]" value="' . ( ( $response['namespace'] ) ? $response['namespace'] : 'false' ) . '" />
+                <input type="submit" value="Return to ACL editor" /> <input type="submit" name="data[act_go_stage1]" value="Return to user/scope selection" />
+                ' . $formend . '
+              </div>';
+        break;
+      case 'delete':
+        echo '<div class="info-box">
+                <b>Rule deleted</b><br />
+                The selected access rule has been successfully deleted.<br />
+                ' . $formstart . '
+                <input type="hidden" name="data[mode]" value="seltarget" />
+                <input type="hidden" name="data[target_type]" value="' . $response['target_type'] . '" />
+                <input type="hidden" name="data[target_id_user]" value="' . ( ( intval($response['target_type']) == ACL_TYPE_USER ) ? $response['target_name'] : $response['target_id'] ) .'" />
+                <input type="hidden" name="data[target_id_grp]"  value="' . ( ( intval($response['target_type']) == ACL_TYPE_USER ) ? $response['target_name'] : $response['target_id'] ) .'" />
+                <input type="hidden" name="data[scope]" value="' . ( ( $response['page_id'] ) ? 'only_this' : 'entire_site' ) . '" />
+                <input type="hidden" name="data[page_id]" value="' . ( ( $response['page_id'] ) ? $response['page_id'] : 'false' ) . '" />
+                <input type="hidden" name="data[namespace]" value="' . ( ( $response['namespace'] ) ? $response['namespace'] : 'false' ) . '" />
+                <input type="submit" value="Return to ACL editor" /> <input type="submit" name="data[act_go_stage1]" value="Return to user/scope selection" />
+                ' . $formend . '
+              </div>';
+        break;
+      case 'seltarget':
+        if ( $response['type'] == 'edit' )
+        {
+          echo '<h3>Editing permissions</h3>';
+        }
+        else
+        {
+          echo '<h3>Create new rule</h3>';
+        }
+        $type  = ( $response['target_type'] == ACL_TYPE_GROUP ) ? 'group' : 'user';
+        $scope = ( $response['page_id'] ) ? 'this page' : 'this entire site';
+        echo 'This panel allows you to edit what the '.$type.' "'.$response['target_name'].'" can do on <b>'.$scope.'</b>. Unless you set a permission to "Deny", these permissions may be overridden by other rules.';
+        echo $formstart;
+        $parser = $template->makeParserText( $response['template']['acl_field_begin'] );
+        echo $parser->run();
+        $parser = $template->makeParserText( $response['template']['acl_field_item'] );
+        $cls = 'row2';
+        foreach ( $response['acl_types'] as $acl_type => $value )
+        {
+          $vars = Array(
+              'FIELD_DENY_CHECKED' => '',
+              'FIELD_DISALLOW_CHECKED' => '',
+              'FIELD_WIKIMODE_CHECKED' => '',
+              'FIELD_ALLOW_CHECKED' => '',
+            );
+          $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
+          $vars['ROW_CLASS'] = $cls;
+          
+          switch ( $response['current_perms'][$acl_type] )
+          {
+            case AUTH_ALLOW:
+              $vars['FIELD_ALLOW_CHECKED'] = 'checked="checked"';
+              break;
+            case AUTH_WIKIMODE:
+              $vars['FIELD_WIKIMODE_CHECKED'] = 'checked="checked"';
+              break;
+            case AUTH_DISALLOW:
+            default:
+              $vars['FIELD_DISALLOW_CHECKED'] = 'checked="checked"';
+              break;
+             case AUTH_DENY:
+              $vars['FIELD_DENY_CHECKED'] = 'checked="checked"';
+              break;
+          }
+          $vars['FIELD_NAME'] = 'data[perms][' . $acl_type . ']';
+          $vars['FIELD_DESC'] = $response['acl_descs'][$acl_type];
+          $parser->assign_vars($vars);
+          echo $parser->run();
+        }
+        $parser = $template->makeParserText( $response['template']['acl_field_end'] );
+        echo $parser->run();
+        echo '<div style="margin: 10px auto 0 0; text-align: right;">
+                <input name="data[mode]" value="save_' . $response['type'] . '" type="hidden" />
+                <input type="hidden" name="data[page_id]" value="'   . (( $response['page_id']   ) ? $response['page_id']   : 'false') . '" />
+                <input type="hidden" name="data[namespace]" value="' . (( $response['namespace'] ) ? $response['namespace'] : 'false') . '" />
+                <input type="hidden" name="data[target_type]" value="' . $response['target_type'] . '" />
+                <input type="hidden" name="data[target_id]" value="' . $response['target_id'] . '" />
+                <input type="hidden" name="data[target_name]" value="' . $response['target_name'] . '" />
+                <input type="submit" value="Save changes" />&nbsp;&nbsp;<input type="submit" name="data[act_delete_rule]" value="Delete rule" style="color: #AA0000;" onclick="return confirm(\'Do you really want to delete this ACL rule?\');" />
+              </div>';
+        echo $formend;
+        break;
+      case 'error':
+        ob_end_clean();
+        die_friendly('Error occurred', '<p>Error returned by permissions API:</p><pre>' . htmlspecialchars($response['error']) . '</pre>');
+        break;
+    }
+    $ret = ob_get_contents();
+    ob_end_clean();
+    echo
+      $template->getHeader() .
+      $ret .
+      $template->getFooter();
+  }
+  
+  /**
+   * Preprocessor to turn the form-submitted data from the ACL editor into something the backend can handle
+   * @param array The posted data
+   * @return array
+   * @access private
+   */
+   
+  function acl_preprocess($parms)
+  {
+    if ( !isset($parms['mode']) )
+      // Nothing to do
+      return $parms;
+    switch ( $parms['mode'] )
+    {
+      case 'seltarget':
+        
+        // Who's affected?
+        $parms['target_type'] = intval( $parms['target_type'] );
+        $parms['target_id'] = ( $parms['target_type'] == ACL_TYPE_GROUP ) ? $parms['target_id_grp'] : $parms['target_id_user'];
+        
+      case 'save_edit':
+      case 'save_new':
+        if ( isset($parms['act_delete_rule']) )
+        {
+          $parms['mode'] = 'delete';
+        }
+        
+        // Scope (just this page or entire site?)
+        if ( $parms['scope'] == 'entire_site' || ( $parms['page_id'] == 'false' && $parms['namespace'] == 'false' ) )
+        {
+          $parms['page_id']   = false;
+          $parms['namespace'] = false;
+        }
+        
+        break;
+    }
+    
+    if ( isset($parms['act_go_stage1']) )
+    {
+      $parms = array(
+          'mode' => 'listgroups'
+        );
+    }
+    
+    return $parms;
+  }
+  
+  function acl_postprocess($response)
+  {
+    if(!isset($response['mode']))
+    {
+      if ( isset($response['groups']) )
+        $response['mode'] = 'stage1';
+      else
+        $response = Array(
+            'mode' => 'error',
+            'error' => 'Invalid action passed by API backend.',
+          );
+    }
+    return $response;
+  }
+   
+}
+
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/paths.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,812 @@
+<?php
+
+/**
+ * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
+ * Version 1.0 (Banshee)
+ * Copyright (C) 2006-2007 Dan Fuhry
+ * paths.php - The part of Enano that actually manages content. Everything related to page handling and namespaces is in here.
+ *
+ * This program is Free Software; you can redistribute 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 details.
+ *
+ * @package Enano
+ * @subpackage PathManager
+ * @see http://enano.homelinux.org/Help:API_Documentation
+ */
+ 
+class pathManager {
+  var $pages, $custom_page, $cpage, $page, $fullpage, $page_exists, $namespace, $nslist, $admin_tree, $wiki_mode, $page_protected, $template_cache;
+  function __construct()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    $GLOBALS['paths'] =& $this;
+    $this->pages = Array();
+    
+    dc_here('paths: setting up namespaces, admin nodes');
+    
+    // DEFINE NAMESPACES HERE
+    // The key names should NOT EVER be changed, or Enano will be very broken
+    $this->nslist = Array(
+      'Article' =>'',
+      'User'    =>'User:',
+      'File'    =>'File:',
+      'Help'    =>'Help:',
+      'Admin'   =>'Admin:',
+      'Special' =>'Special:',
+      'System'  =>'Enano:',
+      'Template'=>'Template:',
+      'Category'=>'Category:',
+      'Project' =>str_replace(' ', '_', getConfig('site_name')).':',
+      );
+    
+    // ACL types
+    // Note: you can set any of these to AUTH_DENY to universally and unconditionally deny access to the selected action.
+    // These can also be added from within plugins
+    
+    $session->register_acl_type('read',                   AUTH_ALLOW,    'Read page(s)');
+    $session->register_acl_type('post_comments',          AUTH_ALLOW,    'Post comments',                                                                                            Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
+    $session->register_acl_type('edit_comments',          AUTH_ALLOW,    'Edit own comments',                                                                                        Array('post_comments'),                                   'Article|User|Project|Template|File|Help|System|Category');
+    $session->register_acl_type('edit_page',              AUTH_WIKIMODE, 'Edit page',                                                                                                Array('view_source'),                                     'Article|User|Project|Template|File|Help|System|Category');
+    $session->register_acl_type('view_source',            AUTH_WIKIMODE, 'View source',                                                                                              Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category'); // Only used if the page is protected
+    $session->register_acl_type('mod_comments',           AUTH_DISALLOW, 'Moderate comments',                                                                                        Array('edit_comments'),                                   'Article|User|Project|Template|File|Help|System|Category');
+    $session->register_acl_type('history_view',           AUTH_WIKIMODE, 'View history/diffs',                                                                                       Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
+    $session->register_acl_type('history_rollback',       AUTH_DISALLOW, 'Rollback history',                                                                                         Array('history_view'),                                    'Article|User|Project|Template|File|Help|System|Category');
+    $session->register_acl_type('history_rollback_extra', AUTH_DISALLOW, 'Undelete page(s)',                                                                                         Array('history_rollback'),                                'Article|User|Project|Template|File|Help|System|Category');
+    $session->register_acl_type('protect',                AUTH_DISALLOW, 'Protect page(s)',                                                                                          Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
+    $session->register_acl_type('rename',                 AUTH_WIKIMODE, 'Rename page(s)',                                                                                           Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
+    $session->register_acl_type('clear_logs',             AUTH_DISALLOW, 'Clear page logs (dangerous)',                                                                              Array('read', 'protect', 'even_when_protected'),          'Article|User|Project|Template|File|Help|System|Category');
+    $session->register_acl_type('vote_delete',            AUTH_ALLOW,    'Vote to delete',                                                                                           Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
+    $session->register_acl_type('vote_reset',             AUTH_DISALLOW, 'Reset delete votes',                                                                                       Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
+    $session->register_acl_type('delete_page',            AUTH_DISALLOW, 'Delete page(s)',                                                                                           Array(),                                                  'Article|User|Project|Template|File|Help|System|Category');
+    $session->register_acl_type('set_wiki_mode',          AUTH_DISALLOW, 'Set per-page wiki mode',                                                                                   Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
+    $session->register_acl_type('password_set',           AUTH_DISALLOW, 'Set password',                                                                                             Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
+    $session->register_acl_type('password_reset',         AUTH_DISALLOW, 'Disable/reset password',                                                                                   Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
+    $session->register_acl_type('mod_misc',               AUTH_DISALLOW, 'Super moderator (generate SQL backtraces, view IP addresses, and send large numbers of private messages)', Array(),                                                  'All');
+    $session->register_acl_type('edit_cat',               AUTH_WIKIMODE, 'Edit categorization',                                                                                      Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
+    $session->register_acl_type('even_when_protected',    AUTH_DISALLOW, 'Allow editing, renaming, and categorization even when protected',                                          Array('edit_page', 'rename', 'mod_comments', 'edit_cat'), 'Article|User|Project|Template|File|Help|System|Category');
+    $session->register_acl_type('upload_files',           AUTH_DISALLOW, 'Upload files',                                                                                             Array('create_page'),                                     'Article|User|Project|Template|File|Help|System|Category|Special');
+    $session->register_acl_type('upload_new_version',     AUTH_WIKIMODE, 'Upload new versions of files',                                                                             Array('upload_files'),                                    'Article|User|Project|Template|File|Help|System|Category|Special');
+    $session->register_acl_type('create_page',            AUTH_WIKIMODE, 'Create pages',                                                                                             Array(),                                                  'Article|User|Project|Template|File|Help|System|Category|Special');
+    $session->register_acl_type('php_in_pages',           AUTH_DISALLOW, 'Embed PHP code in pages',                                                                                  Array('edit_page'),                                       'Article|User|Project|Template|File|Help|System|Category');
+    $session->register_acl_type('edit_acl',               AUTH_DISALLOW, 'Edit access control lists', Array('read', 'post_comments', 'edit_comments', 'edit_page', 'view_source', 'mod_comments', 'history_view', 'history_rollback', 'history_rollback_extra', 'protect', 'rename', 'clear_logs', 'vote_delete', 'vote_reset', 'delete_page', 'set_wiki_mode', 'password_set', 'password_reset', 'mod_misc', 'edit_cat', 'even_when_protected', 'upload_files', 'upload_new_version', 'create_page', 'php_in_pages'));
+    
+    // DO NOT add new admin pages here! Use a plugin to call $paths->addAdminNode();
+    $this->addAdminNode('General', 'General Configuration', 'GeneralConfig');
+    $this->addAdminNode('General', 'File uploads', 'UploadConfig');
+    $this->addAdminNode('General', 'Allowed file types', 'UploadAllowedMimeTypes');
+    $this->addAdminNode('General', 'Manage Plugins', 'PluginManager');
+    $this->addAdminNode('General', 'Backup database', 'DBBackup');
+    $this->addAdminNode('Content', 'Manage Pages', 'PageManager');
+    $this->addAdminNode('Content', 'Edit page content', 'PageEditor');
+    $this->addAdminNode('Appearance', 'Manage themes', 'ThemeManager');
+    $this->addAdminNode('Users', 'Manage users', 'UserManager');
+    $this->addAdminNode('Users', 'Edit groups', 'GroupManager');
+    $this->addAdminNode('Users', 'Ban control', 'BanControl');
+    $this->addAdminNode('Users', 'Mass e-mail', 'MassEmail');
+    
+    $code = $plugins->setHook('acl_rule_init');
+    foreach ( $code as $cmd )
+    {
+      eval($cmd);
+    }
+    
+    $this->wiki_mode = (int)getConfig('wiki_mode')=='1';
+    $this->template_cache = Array();
+  }
+  function pathManager()
+  {
+    $this->__construct();
+  }
+  function init()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    dc_here('paths: selecting master page data');
+    
+    $code = $plugins->setHook('paths_init_before');
+    foreach ( $code as $cmd )
+    {
+      eval($cmd);
+    }
+    
+    $e = $db->sql_query('SELECT name,urlname,namespace,special,visible,comments_on,protected,delvotes,delvote_ips,wiki_mode,password FROM '.table_prefix.'pages ORDER BY name;');
+    if( !$e )
+    {
+      $db->_die('The error seems to have occured while selecting the page information. File: includes/paths.php; line: '.__LINE__);
+    }
+    while($r = $db->fetchrow())
+    {
+      
+      $r['urlname_nons'] = $r['urlname'];
+      $r['urlname'] = $this->nslist[$r['namespace']] . $r['urlname']; // Applies the User:/File:/etc prefixes to the URL names
+      
+      if ( $r['delvotes'] == null)
+      {
+        $r['delvotes'] = 0;
+      }
+      if ( $r['protected'] == 0 || $r['protected'] == 1 )
+      {
+        $r['really_protected'] = (int)$r['protected'];
+      }
+      else if ( $r['protected'] == 2 && getConfig('wiki_mode') == '1')
+      {
+        $r['really_protected'] = 1;
+      }
+      else if ( $r['protected'] == 2 && getConfig('wiki_mode') == '0' )
+      {
+        $r['really_protected'] = 0;
+      }
+      
+      $this->pages[$r['urlname']] = $r;
+      $this->pages[] =& $this->pages[$r['urlname']];
+      
+    }
+    $db->free_result();
+    dc_here('paths: determining page ID');
+    if( isset($_GET['title']) )
+    {
+      if ( $_GET['title'] == '' && getConfig('main_page') != '' )
+      {
+        $this->main_page();
+      }
+      if(strstr($_GET['title'], ' '))
+      {
+        $loc = urldecode(rawurldecode($_SERVER['REQUEST_URI']));
+        $loc = str_replace(' ', '_', $loc);
+        $loc = str_replace('+', '_', $loc);
+        $loc = str_replace('%20', '_', $loc);
+        redirect($loc, 'Redirecting...', 'Space detected in the URL, please wait whilst you are redirected', 0);
+        exit;
+      }
+      $url_namespace_special = substr($_GET['title'], 0, strlen($this->nslist['Special']) );
+      $url_namespace_template = substr($_GET['title'], 0, strlen($this->nslist['Template']) );
+      if($url_namespace_special == $this->nslist['Special'] || $url_namespace_template == $this->nslist['Template'] )
+      {
+        $ex = explode('/', $_GET['title']);
+        $this->page = $ex[0];
+      }
+      else
+      {
+        $this->page = $_GET['title'];
+      }
+      $this->fullpage = $_GET['title'];
+    }
+    elseif( isset($_SERVER['PATH_INFO']) )
+    {
+      $pi = explode('/', $_SERVER['PATH_INFO']);
+      
+      if( !isset($pi[1]) || (isset($pi[1]) && $pi[1] == '' && getConfig('main_page') != '') )
+      {
+        $this->main_page();
+      }
+      if( strstr($pi[1], ' ') )
+      {
+        $loc = str_replace(' ', '_', urldecode(rawurldecode($_SERVER['REQUEST_URI'])));
+        $loc = str_replace('+', '_', $loc);
+        $loc = str_replace('%20', '_', $loc);
+        redirect($loc, 'Redirecting...', 'Please wait whilst you are redirected', 3);
+        exit;
+      }
+      unset($pi[0]);
+      if( substr($pi[1], 0, strlen($this->nslist['Special'])) == $this->nslist['Special'] || substr($pi[1], 0, strlen($this->nslist['Template'])) == $this->nslist['Template'] )
+      {
+        $pi2 = $pi[1];
+      }
+      else
+      {
+        $pi2 = implode('/', $pi);
+      }
+      $this->page = $pi2;
+      $this->fullpage = implode('/', $pi);
+    }
+    else
+    {
+      $k = array_keys($_GET);
+      foreach($k as $c)
+      {
+        if(substr($c, 0, 1) == '/')
+        {
+          $this->page = substr($c, 1, strlen($c));
+          
+          // Bugfix for apache somehow passing dots as underscores
+          global $mime_types;
+          
+          $exts = array_keys($mime_types);
+          $exts = '(' . implode('|', $exts) . ')';
+          
+          if ( preg_match( '#_'.$exts.'#i', $this->page ) )
+          {
+            $this->page = preg_replace( '#_'.$exts.'#i', '.\\1', $this->page );
+          }
+          
+          $this->fullpage = $this->page;
+          
+          if(substr($this->page, 0, strlen($this->nslist['Special']))==$this->nslist['Special'] || substr($this->page, 0, strlen($this->nslist['Template']))==$this->nslist['Template'])
+          {
+            $ex = explode('/', $this->page);
+            $this->page = $ex[0];
+          }
+          if(strstr($this->page, ' '))
+          {
+            $loc = str_replace(' ', '_', urldecode(rawurldecode($_SERVER['REQUEST_URI'])));
+            $loc = str_replace('+', '_', $loc);
+            $loc = str_replace('%20', '_', $loc);
+            redirect($loc, 'Redirecting...', 'Space in the URL detected, please wait whilst you are redirected', 0);
+            exit;
+          }
+          break;
+        }
+      }
+      if(!$this->page && !($this->page == '' && getConfig('main_page') == ''))
+      {
+        $this->main_page();
+      }
+    }
+    
+    dc_here('paths: setting $paths->cpage');
+    
+    if(isset($this->pages[$this->page]))
+    {
+      dc_here('paths: page existence verified, our page ID is: '.$this->page);
+      $this->page_exists = true;
+      $this->cpage = $this->pages[$this->page];
+      $this->namespace = $this->cpage['namespace'];
+      if(!isset($this->cpage['wiki_mode'])) $this->cpage['wiki_mode'] = 2;
+      
+      // Determine the wiki mode for this page, now that we have this->cpage established
+      if($this->cpage['wiki_mode'] == 2)
+      {
+        $this->wiki_mode = (int)getConfig('wiki_mode');
+      }
+      else
+      {
+        $this->wiki_mode = $this->cpage['wiki_mode'];
+      }
+      // Allow the user to create/modify his user page uncondtionally (admins can still protect the page)
+      if($this->page == $this->nslist['User'].str_replace(' ', '_', $session->username))
+      {
+        $this->wiki_mode = true;
+      }
+      // And above all, if the site requires wiki mode to be off for non-logged-in users, disable it now
+      if(getConfig('wiki_mode_require_login')=='1' && !$session->user_logged_in)
+      {
+        $this->wiki_mode = false;
+      }
+      if($this->cpage['protected'] == 2)
+      {
+        // The page is semi-protected, determine permissions
+        if($session->user_logged_in && $session->reg_time + 60*60*24*4 < time()) 
+        {
+          $this->page_protected = 0;
+        }
+        else
+        {
+          $this->page_protected = 1;
+        }
+      }
+      else
+      {
+        $this->page_protected = $this->cpage['protected'];
+      }
+    }
+    else
+    {
+      dc_here('paths: page doesn\'t exist, creating new page in memory<br />our page ID is: '.$this->page);
+      $this->page_exists = false;
+      $this->cpage = Array(
+        'name'=>str_replace('_', ' ', $this->page),
+        'urlname'=>$this->page,
+        'namespace'=>'Article',
+        'special'=>0,
+        'visible'=>0,
+        'comments_on'=>1,
+        'protected'=>0,
+        'delvotes'=>0,
+        'delvote_ips'=>'',
+        'wiki_mode'=>2,
+        );
+      // Look for a namespace prefix in the urlname, and assign a different namespace, if necessary
+      $k = array_keys($this->nslist);
+      for($i=0;$i<sizeof($this->nslist);$i++)
+      {
+        $ln = strlen($this->nslist[$k[$i]]);
+        if( substr($this->page, 0, $ln) == $this->nslist[$k[$i]] )
+        {
+          $this->cpage['namespace'] = $k[$i];
+          $this->cpage['urlname_nons'] = substr($this->page, strlen($this->nslist[$this->cpage['namespace']]), strlen($this->page));
+          if(!isset($this->cpage['wiki_mode'])) 
+          {
+            $this->cpage['wiki_mode'] = 2;
+          }
+        }
+      }
+      $this->namespace = $this->cpage['namespace'];
+      
+      if($this->namespace=='System') 
+      {
+        $this->cpage['protected'] = 1;
+      }
+      if($this->namespace=='Special')
+      {
+        // Can't load nonexistent pages
+        $this->main_page();
+      }
+      // Allow the user to create/modify his user page uncondtionally (admins can still protect the page)
+      if($this->page == $this->nslist['User'].str_replace(' ', '_', $session->username)) 
+      {
+        $this->wiki_mode = true;
+      }
+    }
+    // This is used in the admin panel to keep track of form submission targets
+    $this->cpage['module'] = $this->cpage['urlname'];
+    
+    // Page is set up, call any hooks
+    $code = $plugins->setHook('page_set');
+    foreach ( $code as $cmd )
+    {
+      eval($cmd);
+    }
+    
+    $session->init_permissions();
+  }
+  
+  function add_page($flags)
+  {
+    //dc_dump($flags, 'paths: page added by plugin:');
+    $flags['urlname_nons'] = $flags['urlname'];
+    $flags['urlname'] = $this->nslist[$flags['namespace']] . $flags['urlname']; // Applies the User:/File:/etc prefixes to the URL names
+    $pages_len = sizeof($this->pages)/2;
+    $this->pages[$pages_len] = $flags;
+    $this->pages[$flags['urlname']] =& $this->pages[$pages_len];
+  }
+  
+  function main_page()
+  {
+    if( is_string(getConfig('main_page')) )
+    {
+      header('Location: '.makeUrl(getConfig('main_page')));
+      die('If you aren\'t redirected, <a href="' . makeUrl(getConfig('main_page')) . '">click here</a>.');
+    }
+    else
+    {
+      header('Location: '.makeUrl($this->pages[0]['urlname']));
+      die('If you aren\'t redirected, <a href="' . makeUrl($this->pages[0]['urlname']) . '">click here</a>.');
+    }
+    exit;
+  }
+  
+  function sysmsg($n)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    dc_here('paths: system message requested: '.$n);
+    $q = $db->sql_query('SELECT page_text, char_tag FROM '.table_prefix.'page_text WHERE page_id=\''.$db->escape($n).'\' AND namespace=\'System\'');
+    if( !$q )
+    {
+      $db->_die('Error during generic selection of system page data.');
+    }
+    if($db->numrows() < 1)
+    {
+      return false;
+      //$db->_die('Error during generic selection of system page data: there were no rows in the text table that matched the page text query.');
+    }
+    $r = $db->fetchrow();
+    $db->free_result();
+    $message = $r['page_text'];
+    
+    $message = preg_replace('/<noinclude>(.*?)<\/noinclude>/is', '', $message);
+    
+    return $message;
+  }
+  function get_pageid_from_url()
+  {
+    if(isset($_GET['title']))
+    {
+      if( $_GET['title'] == '' && getConfig('main_page') != '' )
+      {
+        $this->main_page();
+      }
+      if(strstr($_GET['title'], ' '))
+      {
+        $loc = urldecode(rawurldecode($_SERVER['REQUEST_URI']));
+        $loc = str_replace(' ', '_', $loc);
+        $loc = str_replace('+', '_', $loc);
+        header('Location: '.$loc);
+        exit;
+      }
+      $ret = $_GET['title'];
+    }
+    elseif(isset($_SERVER['PATH_INFO']))
+    {
+      $pi = explode('/', $_SERVER['PATH_INFO']);
+      
+      if(!isset($pi[1]) || (isset($pi[1]) && $pi[1] == ''))
+      {
+        return false;
+      }
+      
+      if(strstr($pi[1], ' '))
+      {
+        $loc = urldecode(rawurldecode($_SERVER['REQUEST_URI']));
+        $loc = str_replace(' ', '_', $loc);
+        $loc = str_replace('+', '_', $loc);
+        header('Location: '.$loc);
+        exit;
+      }
+      if( !( substr($pi[1], 0, strlen($this->nslist['Special'])) == $this->nslist['Special'] ) )
+      {
+        unset($pi[0]);
+        $pi[1] = implode('/', $pi);
+      }
+      $ret = $pi[1];
+    }
+    else
+    {
+      $k = array_keys($_GET);
+      foreach($k as $c)
+      {
+        if(substr($c, 0, 1) == '/')
+        {
+          $ret = substr($c, 1, strlen($c));
+          if(substr($ret, 0, strlen($this->nslist['Special'])) == $this->nslist['Special'] ||
+             substr($ret, 0, strlen($this->nslist['Admin'])) == $this->nslist['Admin'])
+          {
+            $ret = explode('/', $ret);
+            $ret = $ret[0];
+          }
+          break;
+        }
+      }
+    }
+    
+    return ( isset($ret) ) ? $ret : false;
+  }
+  // Parses a (very carefully formed) array into Javascript code compatible with the Tigra Tree Menu used in the admin menu
+  function parseAdminTree() 
+  {
+    $k = array_keys($this->admin_tree);
+    $i = 0;
+    $ret = '';
+    $ret .= "var TREE_ITEMS = [\n  ['Administration panel home', 'javascript:ajaxPage(\'".$this->nslist['Admin']."Home\');',\n    ";
+    foreach($k as $key)
+    {
+      $i++;
+      $ret .= "['".$key."', 'javascript:trees[0].toggle($i)', \n";
+      foreach($this->admin_tree[$key] as $c)
+      {
+        $i++;
+        $ret .= "        ['".$c['name']."', 'javascript:ajaxPage(\\'".$this->nslist['Admin'].$c['pageid']."\\');'],\n";
+      }
+      $ret .= "      ],\n";
+    }
+    $ret .= "    ['Log out of admin panel', 'javascript:ajaxPage(\\'".$this->nslist['Admin']."AdminLogout\\');'],\n";
+    // I used this while I painstakingly wrote the Runt code that auto-expands certain nodes based on the value of a bitfield stored in a cookie. *shudders*
+    // $ret .= "    ['(debug) Clear menu bitfield', 'javascript:createCookie(\\'admin_menu_state\\', \\'1\\', 365);'],\n";
+    $ret .= "]\n];";
+    return $ret;
+  }
+  function addAdminNode($section, $page_title, $url)
+  {
+    if(!isset($this->admin_tree[$section]))
+    {
+      $this->admin_tree[$section] = Array();
+    }
+    $this->admin_tree[$section][] = Array(
+        'name'=>$page_title,
+        'pageid'=>$url
+      );
+  }
+  function getParam($id = 0)
+  {
+    if(isset($_SERVER['PATH_INFO']))
+    {
+      $pi = explode('/', $_SERVER['PATH_INFO']);
+      $id = $id + 2;
+      return isset($pi[$id]) ? $pi[$id] : false;
+    }
+    else if( isset($_GET['title']) )
+    {
+      $pi = explode('/', $_GET['title']);
+      $id = $id + 1;
+      return isset($pi[$id]) ? $pi[$id] : false;
+    }
+    else
+    {
+      $k = array_keys($_GET);
+      foreach($k as $c)
+      {
+        if(substr($c, 0, 1) == '/')
+        {
+          
+          // Bugfix for apache somehow passing dots as underscores
+          global $mime_types;
+          $exts = array_keys($mime_types);
+          $exts = '(' . implode('|', $exts) . ')';
+          if ( preg_match( '#_'.$exts.'#i', $c ) )
+            $c = preg_replace( '#_'.$exts.'#i', '.\\1', $c );
+          
+          $pi = explode('/', $c);
+          $id = $id + 2;
+          return isset($pi[$id]) ? $pi[$id] : false;
+        }
+      }
+      return false;
+    }
+  }
+  
+  function getAllParams()
+  {
+    if(isset($_SERVER['PATH_INFO']))
+    {
+      $pi = explode('/', $_SERVER['PATH_INFO']);
+      unset($pi[0], $pi[1]);
+      return implode('/', $pi);
+    }
+    else if( isset($_GET['title']) )
+    {
+      $pi = explode('/', $_GET['title']);
+      unset($pi[0]);
+      return implode('/', $pi);
+    }
+    else
+    {
+      $k = array_keys($_GET);
+      foreach($k as $c)
+      {
+        if(substr($c, 0, 1) == '/')
+        {
+          // Bugfix for apache somehow passing dots as underscores
+          global $mime_types;
+          $exts = array_keys($mime_types);
+          $exts = '(' . implode('|', $exts) . ')';
+          if ( preg_match( '#_'.$exts.'#i', $c ) )
+            $c = preg_replace( '#_'.$exts.'#i', '.\\1', $c );
+          
+          $pi = explode('/', $c);
+          unset($pi[0], $pi[1]);
+          return implode('/', $pi);
+        }
+      }
+      return false;
+    }
+  }
+  
+  /**
+   * Creates a new namespace in memory
+   * @param string $id the namespace ID
+   * @param string $prefix the URL prefix, must not be blank or already used
+   * @return bool true on success false on failure
+   */
+  
+  function create_namespace($id, $prefix)
+  {
+    if(in_array($prefix, $this->nslist))
+    {
+      // echo '<b>Warning:</b> pathManager::create_namespace: Prefix "'.$prefix.'" is already taken<br />';
+      return false;
+    }
+    if( isset($this->nslist[$id]) )
+    {
+      // echo '<b>Warning:</b> pathManager::create_namespace: Namespace ID "'.$prefix.'" is already taken<br />';
+      return false;
+    }
+    $this->nslist[$id] = $prefix;
+  }
+  
+  /**
+   * Fetches the page texts for searching
+   */
+   
+  function fetch_page_search_texts()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $texts = Array();
+    $q = $db->sql_query('SELECT t.page_id,t.namespace,t.page_text,t.char_tag FROM '.table_prefix.'page_text AS t
+                           LEFT JOIN '.table_prefix.'pages AS p
+                             ON t.page_id=p.urlname
+                           WHERE p.namespace=t.namespace
+                             AND ( p.password=\'\' OR p.password=\'da39a3ee5e6b4b0d3255bfef95601890afd80709\' )
+                             AND p.visible=1;'); // Only indexes "visible" pages
+    
+    if( !$q )
+    {
+      return false;
+    }
+    while($row = $db->fetchrow())
+    {
+      $pid = $this->nslist[$row['namespace']] . $row['page_id'];
+      $texts[$pid] = $row['page_text'];
+    }
+    $db->free_result();
+    
+    return $texts;
+  }
+  
+  /**
+   * Fetches a MySQL search query to use for Searcher::searchMySQL()
+   */
+   
+  function fetch_page_search_resource()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    // sha1('') returns "da39a3ee5e6b4b0d3255bfef95601890afd80709"
+    $texts = 'SELECT t.page_text,CONCAT(\'ns=\',t.namespace,\';pid=\',t.page_id) FROM '.table_prefix.'page_text AS t
+                           LEFT JOIN '.table_prefix.'pages AS p
+                             ON ( t.page_id=p.urlname AND t.namespace=p.namespace )
+                           WHERE p.namespace=t.namespace
+                             AND ( p.password=\'\' OR p.password=\'da39a3ee5e6b4b0d3255bfef95601890afd80709\' )
+                             AND p.visible=1;'; // Only indexes "visible" pages
+    return $texts;
+  }
+  
+  /**
+   * Rebuilds the search index
+   */
+   
+  function rebuild_search_index()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $search = new Searcher();
+    $texts = Array();
+    $textq = $db->sql_unbuffered_query($this->fetch_page_search_resource());
+    if(!$textq) $db->_die('');
+    while($row = $db->fetchrow_num())
+    {
+      $texts[(string)$row[1]] = $row[0];
+    }
+    $search->buildIndex($texts);
+    // echo '<pre>'.print_r($search->index, true).'</pre>';
+    // return;
+    $q = $db->sql_query('DELETE FROM '.table_prefix.'search_index');
+    if(!$q) return false;
+    $secs = Array();
+    $q = 'INSERT INTO '.table_prefix.'search_index(word,page_names) VALUES';
+    foreach($search->index as $word => $pages)
+    {
+      $secs[] = '(\''.$db->escape($word).'\', \''.$db->escape($pages).'\')';
+    }
+    $q .= implode(',', $secs);
+    unset($secs);
+    $q .= ';';
+    $result = $db->sql_query($q);
+    $db->free_result();
+    if($result)
+      return true;
+    else
+      $db->_die('The search index was trying to rebuild itself when the error occured.');
+  }
+  
+  /**
+   * Partially rebuilds the search index, removing/inserting entries only for the current page
+   * @param string $page_id
+   * @param string $namespace
+   */
+  
+  function rebuild_page_index($page_id, $namespace)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(!$db->sql_query('SELECT page_text FROM '.table_prefix.'page_text
+      WHERE page_id=\''.$db->escape($page_id).'\' AND namespace=\''.$db->escape($namespace).'\';'))
+    {
+      return $db->get_error();
+    }
+    $row = $db->fetchrow();
+    $db->free_result();
+    $search = new Searcher();
+    $search->buildIndex(Array("ns={$namespace};pid={$page_id}"=>$row['page_text']));
+    $new_index = $search->index;
+    
+    $keys = array_keys($search->index);
+    foreach($keys as $i => $k)
+    {
+      $c =& $keys[$i];
+      $c = hexencode($c, '', '');
+    }
+    $keys = "word=0x" . implode ( " OR word=0x", $keys ) . "";
+    
+    // Zap the cache
+    $cache = array_keys($search->index);
+    if ( count($cache) < 1 )
+    {
+      return false;
+    }
+    $cache = "query LIKE '%" . implode ( "%' OR query LIKE '%", $cache ) . "%'";
+    $db->sql_query('DELETE FROM '.table_prefix.'search_cache WHERE '.$cache);
+    
+    $query = $db->sql_query('SELECT word,page_names FROM '.table_prefix.'search_index WHERE '.$keys.';');
+    
+    while($row = $db->fetchrow())
+    {
+      $row['word'] = rtrim($row['word'], "\0");
+      $new_index[ $row['word'] ] = $row['page_names'] . ',' . $search->index[ $row['word'] ];
+    }
+    $db->free_result();
+    
+    $db->sql_query('DELETE FROM '.table_prefix.'search_index WHERE '.$keys.';');
+    
+    $secs = Array();
+    $q = 'INSERT INTO '.table_prefix.'search_index(word,page_names) VALUES';
+    foreach($new_index as $word => $pages)
+    {
+      $secs[] = '(\''.$db->escape($word).'\', \''.$db->escape($pages).'\')';
+    }
+    $q .= implode(',', $secs);
+    unset($secs);
+    $q .= ';';
+    if(!$db->check_query($q))
+    {
+      die('BUG: PathManager::rebuild_page_index: Query rejected by SQL parser:<pre>'.$q.'</pre>');
+    }
+    $result = $db->sql_query($q);
+    if($result)
+      return true;
+    else
+      $db->_die('The search index was trying to rebuild itself when the error occured.');
+    
+  }
+  
+  /**
+   * Creates an instance of the Searcher class, including index info
+   * @return object
+   */
+   
+  function makeSearcher($match_case = false)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $search = new Searcher();
+    $q = $db->sql_query('SELECT word,page_names FROM '.table_prefix.'search_index;');
+    if(!$q)
+    {
+      echo $db->get_error();
+      return false;
+    }
+    $idx = Array();
+    while($row = $db->fetchrow($q))
+    {
+      $row['word'] = rtrim($row['word'], "\0");
+      $idx[$row['word']] = $row['page_names'];
+    }
+    $db->free_result();
+    $search->index = $idx;
+    if($match_case)
+      $search->match_case = true;
+    return $search;
+  }
+  
+  /**
+   * Creates an associative array filled with the values of all the page titles
+   * @return array
+   */
+   
+  function get_page_titles()
+  {
+    $texts = Array();
+    for ( $i = 0; $i < sizeof($this->pages) / 2; $i++ )
+    {
+      $texts[$this->pages[$i]['urlname']] = $this->pages[$i]['name'];
+    }
+    return $texts;
+  }
+  
+  /**
+   * Creates an instance of the Searcher class, including index info for page titles
+   * @return object
+   */
+   
+  function makeTitleSearcher($match_case = false)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $search = new Searcher();
+    $texts = $this->get_page_titles();
+    $search->buildIndex($texts);
+    if($match_case)
+      $search->match_case = true;
+    return $search;
+  }
+  
+}
+  
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/paths.php~	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,808 @@
+<?php
+
+/**
+ * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
+ * Version 1.0 (Banshee)
+ * Copyright (C) 2006-2007 Dan Fuhry
+ * paths.php - The part of Enano that actually manages content. Everything related to page handling and namespaces is in here.
+ *
+ * This program is Free Software; you can redistribute 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 details.
+ *
+ * @package Enano
+ * @subpackage PathManager
+ * @see http://enano.homelinux.org/Help:API_Documentation
+ */
+ 
+class pathManager {
+  var $pages, $custom_page, $cpage, $page, $fullpage, $page_exists, $namespace, $nslist, $admin_tree, $wiki_mode, $page_protected, $template_cache;
+  function __construct()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    $GLOBALS['paths'] =& $this;
+    $this->pages = Array();
+    
+    dc_here('paths: setting up namespaces, admin nodes');
+    
+    // DEFINE NAMESPACES HERE
+    // The key names should NOT EVER be changed, or Enano will be very broken
+    $this->nslist = Array(
+      'Article' =>'',
+      'User'    =>'User:',
+      'File'    =>'File:',
+      'Help'    =>'Help:',
+      'Admin'   =>'Admin:',
+      'Special' =>'Special:',
+      'System'  =>'Enano:',
+      'Template'=>'Template:',
+      'Category'=>'Category:',
+      'Project' =>str_replace(' ', '_', getConfig('site_name')).':',
+      );
+    
+    // ACL types
+    // Note: you can set any of these to AUTH_DENY to universally and unconditionally deny access to the selected action.
+    // These can also be added from within plugins
+    
+    $session->register_acl_type('read',                   AUTH_ALLOW,    'Read page(s)');
+    $session->register_acl_type('post_comments',          AUTH_ALLOW,    'Post comments',                                                                                            Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
+    $session->register_acl_type('edit_comments',          AUTH_ALLOW,    'Edit own comments',                                                                                        Array('post_comments'),                                   'Article|User|Project|Template|File|Help|System|Category');
+    $session->register_acl_type('edit_page',              AUTH_WIKIMODE, 'Edit page',                                                                                                Array('view_source'),                                     'Article|User|Project|Template|File|Help|System|Category');
+    $session->register_acl_type('view_source',            AUTH_WIKIMODE, 'View source',                                                                                              Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category'); // Only used if the page is protected
+    $session->register_acl_type('mod_comments',           AUTH_DISALLOW, 'Moderate comments',                                                                                        Array('edit_comments'),                                   'Article|User|Project|Template|File|Help|System|Category');
+    $session->register_acl_type('history_view',           AUTH_WIKIMODE, 'View history/diffs',                                                                                       Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
+    $session->register_acl_type('history_rollback',       AUTH_DISALLOW, 'Rollback history',                                                                                         Array('history_view'),                                    'Article|User|Project|Template|File|Help|System|Category');
+    $session->register_acl_type('history_rollback_extra', AUTH_DISALLOW, 'Undelete page(s)',                                                                                         Array('history_rollback'),                                'Article|User|Project|Template|File|Help|System|Category');
+    $session->register_acl_type('protect',                AUTH_DISALLOW, 'Protect page(s)',                                                                                          Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
+    $session->register_acl_type('rename',                 AUTH_WIKIMODE, 'Rename page(s)',                                                                                           Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
+    $session->register_acl_type('clear_logs',             AUTH_DISALLOW, 'Clear page logs (dangerous)',                                                                              Array('read', 'protect', 'even_when_protected'),          'Article|User|Project|Template|File|Help|System|Category');
+    $session->register_acl_type('vote_delete',            AUTH_ALLOW,    'Vote to delete',                                                                                           Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
+    $session->register_acl_type('vote_reset',             AUTH_DISALLOW, 'Reset delete votes',                                                                                       Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
+    $session->register_acl_type('delete_page',            AUTH_DISALLOW, 'Delete page(s)',                                                                                           Array(),                                                  'Article|User|Project|Template|File|Help|System|Category');
+    $session->register_acl_type('set_wiki_mode',          AUTH_DISALLOW, 'Set per-page wiki mode',                                                                                   Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
+    $session->register_acl_type('password_set',           AUTH_DISALLOW, 'Set password',                                                                                             Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
+    $session->register_acl_type('password_reset',         AUTH_DISALLOW, 'Disable/reset password',                                                                                   Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
+    $session->register_acl_type('mod_misc',               AUTH_DISALLOW, 'Super moderator (generate SQL backtraces, view IP addresses, and send large numbers of private messages)', Array(),                                                  'All');
+    $session->register_acl_type('edit_cat',               AUTH_WIKIMODE, 'Edit categorization',                                                                                      Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
+    $session->register_acl_type('even_when_protected',    AUTH_DISALLOW, 'Allow editing, renaming, and categorization even when protected',                                          Array('edit_page', 'rename', 'mod_comments', 'edit_cat'), 'Article|User|Project|Template|File|Help|System|Category');
+    $session->register_acl_type('upload_files',           AUTH_DISALLOW, 'Upload files',                                                                                             Array('create_page'),                                     'Article|User|Project|Template|File|Help|System|Category|Special');
+    $session->register_acl_type('upload_new_version',     AUTH_WIKIMODE, 'Upload new versions of files',                                                                             Array('upload_files'),                                    'Article|User|Project|Template|File|Help|System|Category|Special');
+    $session->register_acl_type('create_page',            AUTH_WIKIMODE, 'Create pages',                                                                                             Array(),                                                  'Article|User|Project|Template|File|Help|System|Category|Special');
+    $session->register_acl_type('php_in_pages',           AUTH_DISALLOW, 'Embed PHP code in pages',                                                                                  Array('edit_page'),                                       'Article|User|Project|Template|File|Help|System|Category');
+    $session->register_acl_type('edit_acl',               AUTH_DISALLOW, 'Edit access control lists', Array('read', 'post_comments', 'edit_comments', 'edit_page', 'view_source', 'mod_comments', 'history_view', 'history_rollback', 'history_rollback_extra', 'protect', 'rename', 'clear_logs', 'vote_delete', 'vote_reset', 'delete_page', 'set_wiki_mode', 'password_set', 'password_reset', 'mod_misc', 'edit_cat', 'even_when_protected', 'upload_files', 'upload_new_version', 'create_page', 'php_in_pages'));
+    
+    // DO NOT add new admin pages here! Use a plugin to call $paths->addAdminNode();
+    $this->addAdminNode('General', 'General Configuration', 'GeneralConfig');
+    $this->addAdminNode('General', 'File uploads', 'UploadConfig');
+    $this->addAdminNode('General', 'Allowed file types', 'UploadAllowedMimeTypes');
+    $this->addAdminNode('General', 'Manage Plugins', 'PluginManager');
+    $this->addAdminNode('General', 'Backup database', 'DBBackup');
+    $this->addAdminNode('Content', 'Manage Pages', 'PageManager');
+    $this->addAdminNode('Content', 'Edit page content', 'PageEditor');
+    $this->addAdminNode('Appearance', 'Manage themes', 'ThemeManager');
+    $this->addAdminNode('Users', 'Manage users', 'UserManager');
+    $this->addAdminNode('Users', 'Edit groups', 'GroupManager');
+    $this->addAdminNode('Users', 'Ban control', 'BanControl');
+    $this->addAdminNode('Users', 'Mass e-mail', 'MassEmail');
+    
+    $code = $plugins->setHook('acl_rule_init');
+    foreach ( $code as $cmd )
+    {
+      eval($cmd);
+    }
+    
+    $this->wiki_mode = (int)getConfig('wiki_mode')=='1';
+    $this->template_cache = Array();
+  }
+  function pathManager()
+  {
+    $this->__construct();
+  }
+  function init()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    dc_here('paths: selecting master page data');
+    
+    $code = $plugins->setHook('paths_init_before');
+    foreach ( $code as $cmd )
+    {
+      eval($cmd);
+    }
+    
+    $e = $db->sql_query('SELECT name,urlname,namespace,special,visible,comments_on,protected,delvotes,delvote_ips,wiki_mode,password FROM '.table_prefix.'pages ORDER BY name;');
+    if( !$e )
+    {
+      $db->_die('The error seems to have occured while selecting the page information. File: includes/paths.php; line: '.__LINE__);
+    }
+    while($r = $db->fetchrow())
+    {
+      
+      $r['urlname_nons'] = $r['urlname'];
+      $r['urlname'] = $this->nslist[$r['namespace']] . $r['urlname']; // Applies the User:/File:/etc prefixes to the URL names
+      
+      if ( $r['delvotes'] == null)
+      {
+        $r['delvotes'] = 0;
+      }
+      if ( $r['protected'] == 0 || $r['protected'] == 1 )
+      {
+        $r['really_protected'] = (int)$r['protected'];
+      }
+      else if ( $r['protected'] == 2 && getConfig('wiki_mode') == '1')
+      {
+        $r['really_protected'] = 1;
+      }
+      else if ( $r['protected'] == 2 && getConfig('wiki_mode') == '0' )
+      {
+        $r['really_protected'] = 0;
+      }
+      
+      $this->pages[$r['urlname']] = $r;
+      $this->pages[] =& $this->pages[$r['urlname']];
+      
+    }
+    $db->free_result();
+    dc_here('paths: determining page ID');
+    if( isset($_GET['title']) )
+    {
+      if ( $_GET['title'] == '' && getConfig('main_page') != '' )
+      {
+        $this->main_page();
+      }
+      if(strstr($_GET['title'], ' '))
+      {
+        $loc = urldecode(rawurldecode($_SERVER['REQUEST_URI']));
+        $loc = str_replace(' ', '_', $loc);
+        $loc = str_replace('+', '_', $loc);
+        $loc = str_replace('%20', '_', $loc);
+        redirect($loc, 'Redirecting...', 'Space detected in the URL, please wait whilst you are redirected', 0);
+        exit;
+      }
+      $url_namespace_special = substr($_GET['title'], 0, strlen($this->nslist['Special']) );
+      $url_namespace_template = substr($_GET['title'], 0, strlen($this->nslist['Template']) );
+      if($url_namespace_special == $this->nslist['Special'] || $url_namespace_template == $this->nslist['Template'] )
+      {
+        $ex = explode('/', $_GET['title']);
+        $this->page = $ex[0];
+      }
+      else
+      {
+        $this->page = $_GET['title'];
+      }
+      $this->fullpage = $_GET['title'];
+    }
+    elseif( isset($_SERVER['PATH_INFO']) )
+    {
+      $pi = explode('/', $_SERVER['PATH_INFO']);
+      
+      if( !isset($pi[1]) || (isset($pi[1]) && $pi[1] == '' && getConfig('main_page') != '') )
+      {
+        $this->main_page();
+      }
+      if( strstr($pi[1], ' ') )
+      {
+        $loc = str_replace(' ', '_', urldecode(rawurldecode($_SERVER['REQUEST_URI'])));
+        $loc = str_replace('+', '_', $loc);
+        $loc = str_replace('%20', '_', $loc);
+        redirect($loc, 'Redirecting...', 'Please wait whilst you are redirected', 3);
+        exit;
+      }
+      unset($pi[0]);
+      if( substr($pi[1], 0, strlen($this->nslist['Special'])) == $this->nslist['Special'] || substr($pi[1], 0, strlen($this->nslist['Template'])) == $this->nslist['Template'] )
+      {
+        $pi2 = $pi[1];
+      }
+      else
+      {
+        $pi2 = implode('/', $pi);
+      }
+      $this->page = $pi2;
+      $this->fullpage = implode('/', $pi);
+    }
+    else
+    {
+      $k = array_keys($_GET);
+      foreach($k as $c)
+      {
+        if(substr($c, 0, 1) == '/')
+        {
+          $this->page = substr($c, 1, strlen($c));
+          
+          // Bugfix for apache somehow passing dots as underscores
+          global $mime_types;
+          $exts = array_keys($mime_types);
+          $exts = '(' . implode('|', $exts) . ')';
+          if ( preg_match( '#_'.$exts.'#i', $this->page ) )
+            $this->page = preg_replace( '#_'.$exts.'#i', '.\\1', $this->page );
+          
+          $this->fullpage = $this->page;
+          
+          if(substr($this->page, 0, strlen($this->nslist['Special']))==$this->nslist['Special'] || substr($this->page, 0, strlen($this->nslist['Template']))==$this->nslist['Template'])
+          {
+            $ex = explode('/', $this->page);
+            $this->page = $ex[0];
+          }
+          if(strstr($this->page, ' '))
+          {
+            $loc = str_replace(' ', '_', urldecode(rawurldecode($_SERVER['REQUEST_URI'])));
+            $loc = str_replace('+', '_', $loc);
+            $loc = str_replace('%20', '_', $loc);
+            redirect($loc, 'Redirecting...', 'Space in the URL detected, please wait whilst you are redirected', 0);
+            exit;
+          }
+          break;
+        }
+      }
+      if(!$this->page && !($this->page == '' && getConfig('main_page') == ''))
+      {
+        $this->main_page();
+      }
+    }
+    
+    dc_here('paths: setting $paths->cpage');
+    
+    if(isset($this->pages[$this->page]))
+    {
+      dc_here('paths: page existence verified, our page ID is: '.$this->page);
+      $this->page_exists = true;
+      $this->cpage = $this->pages[$this->page];
+      $this->namespace = $this->cpage['namespace'];
+      if(!isset($this->cpage['wiki_mode'])) $this->cpage['wiki_mode'] = 2;
+      
+      // Determine the wiki mode for this page, now that we have this->cpage established
+      if($this->cpage['wiki_mode'] == 2)
+      {
+        $this->wiki_mode = (int)getConfig('wiki_mode');
+      }
+      else
+      {
+        $this->wiki_mode = $this->cpage['wiki_mode'];
+      }
+      // Allow the user to create/modify his user page uncondtionally (admins can still protect the page)
+      if($this->page == $this->nslist['User'].str_replace(' ', '_', $session->username))
+      {
+        $this->wiki_mode = true;
+      }
+      // And above all, if the site requires wiki mode to be off for non-logged-in users, disable it now
+      if(getConfig('wiki_mode_require_login')=='1' && !$session->user_logged_in)
+      {
+        $this->wiki_mode = false;
+      }
+      if($this->cpage['protected'] == 2)
+      {
+        // The page is semi-protected, determine permissions
+        if($session->user_logged_in && $session->reg_time + 60*60*24*4 < time()) 
+        {
+          $this->page_protected = 0;
+        }
+        else
+        {
+          $this->page_protected = 1;
+        }
+      }
+      else
+      {
+        $this->page_protected = $this->cpage['protected'];
+      }
+    }
+    else
+    {
+      dc_here('paths: page doesn\'t exist, creating new page in memory<br />our page ID is: '.$this->page);
+      $this->page_exists = false;
+      $this->cpage = Array(
+        'name'=>str_replace('_', ' ', $this->page),
+        'urlname'=>$this->page,
+        'namespace'=>'Article',
+        'special'=>0,
+        'visible'=>0,
+        'comments_on'=>1,
+        'protected'=>0,
+        'delvotes'=>0,
+        'delvote_ips'=>'',
+        'wiki_mode'=>2,
+        );
+      // Look for a namespace prefix in the urlname, and assign a different namespace, if necessary
+      $k = array_keys($this->nslist);
+      for($i=0;$i<sizeof($this->nslist);$i++)
+      {
+        $ln = strlen($this->nslist[$k[$i]]);
+        if( substr($this->page, 0, $ln) == $this->nslist[$k[$i]] )
+        {
+          $this->cpage['namespace'] = $k[$i];
+          $this->cpage['urlname_nons'] = substr($this->page, strlen($this->nslist[$this->cpage['namespace']]), strlen($this->page));
+          if(!isset($this->cpage['wiki_mode'])) 
+          {
+            $this->cpage['wiki_mode'] = 2;
+          }
+        }
+      }
+      $this->namespace = $this->cpage['namespace'];
+      
+      if($this->namespace=='System') 
+      {
+        $this->cpage['protected'] = 1;
+      }
+      if($this->namespace=='Special')
+      {
+        // Can't load nonexistent pages
+        $this->main_page();
+      }
+      // Allow the user to create/modify his user page uncondtionally (admins can still protect the page)
+      if($this->page == $this->nslist['User'].str_replace(' ', '_', $session->username)) 
+      {
+        $this->wiki_mode = true;
+      }
+    }
+    // This is used in the admin panel to keep track of form submission targets
+    $this->cpage['module'] = $this->cpage['urlname'];
+    
+    // Page is set up, call any hooks
+    $code = $plugins->setHook('page_set');
+    foreach ( $code as $cmd )
+    {
+      eval($cmd);
+    }
+    
+    $session->init_permissions();
+  }
+  
+  function add_page($flags)
+  {
+    //dc_dump($flags, 'paths: page added by plugin:');
+    $flags['urlname_nons'] = $flags['urlname'];
+    $flags['urlname'] = $this->nslist[$flags['namespace']] . $flags['urlname']; // Applies the User:/File:/etc prefixes to the URL names
+    $pages_len = sizeof($this->pages)/2;
+    $this->pages[$pages_len] = $flags;
+    $this->pages[$flags['urlname']] =& $this->pages[$pages_len];
+  }
+  
+  function main_page()
+  {
+    if( is_string(getConfig('main_page')) )
+    {
+      header('Location: '.makeUrl(getConfig('main_page')));
+      die('If you aren\'t redirected, <a href="' . makeUrl(getConfig('main_page')) . '">click here</a>.');
+    }
+    else
+    {
+      header('Location: '.makeUrl($this->pages[0]['urlname']));
+      die('If you aren\'t redirected, <a href="' . makeUrl($this->pages[0]['urlname']) . '">click here</a>.');
+    }
+    exit;
+  }
+  
+  function sysmsg($n)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    dc_here('paths: system message requested: '.$n);
+    $q = $db->sql_query('SELECT page_text, char_tag FROM '.table_prefix.'page_text WHERE page_id=\''.$db->escape($n).'\' AND namespace=\'System\'');
+    if( !$q )
+    {
+      $db->_die('Error during generic selection of system page data.');
+    }
+    if($db->numrows() < 1)
+    {
+      return false;
+      //$db->_die('Error during generic selection of system page data: there were no rows in the text table that matched the page text query.');
+    }
+    $r = $db->fetchrow();
+    $db->free_result();
+    $message = $r['page_text'];
+    
+    $message = preg_replace('/<noinclude>(.*?)<\/noinclude>/is', '', $message);
+    
+    return $message;
+  }
+  function get_pageid_from_url()
+  {
+    if(isset($_GET['title']))
+    {
+      if( $_GET['title'] == '' && getConfig('main_page') != '' )
+      {
+        $this->main_page();
+      }
+      if(strstr($_GET['title'], ' '))
+      {
+        $loc = urldecode(rawurldecode($_SERVER['REQUEST_URI']));
+        $loc = str_replace(' ', '_', $loc);
+        $loc = str_replace('+', '_', $loc);
+        header('Location: '.$loc);
+        exit;
+      }
+      $ret = $_GET['title'];
+    }
+    elseif(isset($_SERVER['PATH_INFO']))
+    {
+      $pi = explode('/', $_SERVER['PATH_INFO']);
+      
+      if(!isset($pi[1]) || (isset($pi[1]) && $pi[1] == ''))
+      {
+        return false;
+      }
+      
+      if(strstr($pi[1], ' '))
+      {
+        $loc = urldecode(rawurldecode($_SERVER['REQUEST_URI']));
+        $loc = str_replace(' ', '_', $loc);
+        $loc = str_replace('+', '_', $loc);
+        header('Location: '.$loc);
+        exit;
+      }
+      if( !( substr($pi[1], 0, strlen($this->nslist['Special'])) == $this->nslist['Special'] ) )
+      {
+        unset($pi[0]);
+        $pi[1] = implode('/', $pi);
+      }
+      $ret = $pi[1];
+    }
+    else
+    {
+      $k = array_keys($_GET);
+      foreach($k as $c)
+      {
+        if(substr($c, 0, 1) == '/')
+        {
+          $ret = substr($c, 1, strlen($c));
+          if(substr($ret, 0, strlen($this->nslist['Special'])) == $this->nslist['Special'] ||
+             substr($ret, 0, strlen($this->nslist['Admin'])) == $this->nslist['Admin'])
+          {
+            $ret = explode('/', $ret);
+            $ret = $ret[0];
+          }
+          break;
+        }
+      }
+    }
+    
+    return ( isset($ret) ) ? $ret : false;
+  }
+  // Parses a (very carefully formed) array into Javascript code compatible with the Tigra Tree Menu used in the admin menu
+  function parseAdminTree() 
+  {
+    $k = array_keys($this->admin_tree);
+    $i = 0;
+    $ret = '';
+    $ret .= "var TREE_ITEMS = [\n  ['Administration panel home', 'javascript:ajaxPage(\'".$this->nslist['Admin']."Home\');',\n    ";
+    foreach($k as $key)
+    {
+      $i++;
+      $ret .= "['".$key."', 'javascript:trees[0].toggle($i)', \n";
+      foreach($this->admin_tree[$key] as $c)
+      {
+        $i++;
+        $ret .= "        ['".$c['name']."', 'javascript:ajaxPage(\\'".$this->nslist['Admin'].$c['pageid']."\\');'],\n";
+      }
+      $ret .= "      ],\n";
+    }
+    $ret .= "    ['Log out of admin panel', 'javascript:ajaxPage(\\'".$this->nslist['Admin']."AdminLogout\\');'],\n";
+    // I used this while I painstakingly wrote the Runt code that auto-expands certain nodes based on the value of a bitfield stored in a cookie. *shudders*
+    // $ret .= "    ['(debug) Clear menu bitfield', 'javascript:createCookie(\\'admin_menu_state\\', \\'1\\', 365);'],\n";
+    $ret .= "]\n];";
+    return $ret;
+  }
+  function addAdminNode($section, $page_title, $url)
+  {
+    if(!isset($this->admin_tree[$section]))
+    {
+      $this->admin_tree[$section] = Array();
+    }
+    $this->admin_tree[$section][] = Array(
+        'name'=>$page_title,
+        'pageid'=>$url
+      );
+  }
+  function getParam($id = 0)
+  {
+    if(isset($_SERVER['PATH_INFO']))
+    {
+      $pi = explode('/', $_SERVER['PATH_INFO']);
+      $id = $id + 2;
+      return isset($pi[$id]) ? $pi[$id] : false;
+    }
+    else if( isset($_GET['title']) )
+    {
+      $pi = explode('/', $_GET['title']);
+      $id = $id + 1;
+      return isset($pi[$id]) ? $pi[$id] : false;
+    }
+    else
+    {
+      $k = array_keys($_GET);
+      foreach($k as $c)
+      {
+        if(substr($c, 0, 1) == '/')
+        {
+          
+          // Bugfix for apache somehow passing dots as underscores
+          global $mime_types;
+          $exts = array_keys($mime_types);
+          $exts = '(' . implode('|', $exts) . ')';
+          if ( preg_match( '#_'.$exts.'#i', $c ) )
+            $c = preg_replace( '#_'.$exts.'#i', '.\\1', $c );
+          
+          $pi = explode('/', $c);
+          $id = $id + 2;
+          return isset($pi[$id]) ? $pi[$id] : false;
+        }
+      }
+      return false;
+    }
+  }
+  
+  function getAllParams()
+  {
+    if(isset($_SERVER['PATH_INFO']))
+    {
+      $pi = explode('/', $_SERVER['PATH_INFO']);
+      unset($pi[0], $pi[1]);
+      return implode('/', $pi);
+    }
+    else if( isset($_GET['title']) )
+    {
+      $pi = explode('/', $_GET['title']);
+      unset($pi[0]);
+      return implode('/', $pi);
+    }
+    else
+    {
+      $k = array_keys($_GET);
+      foreach($k as $c)
+      {
+        if(substr($c, 0, 1) == '/')
+        {
+          // Bugfix for apache somehow passing dots as underscores
+          global $mime_types;
+          $exts = array_keys($mime_types);
+          $exts = '(' . implode('|', $exts) . ')';
+          if ( preg_match( '#_'.$exts.'#i', $c ) )
+            $c = preg_replace( '#_'.$exts.'#i', '.\\1', $c );
+          
+          $pi = explode('/', $c);
+          unset($pi[0], $pi[1]);
+          return implode('/', $pi);
+        }
+      }
+      return false;
+    }
+  }
+  
+  /**
+   * Creates a new namespace in memory
+   * @param string $id the namespace ID
+   * @param string $prefix the URL prefix, must not be blank or already used
+   * @return bool true on success false on failure
+   */
+  
+  function create_namespace($id, $prefix)
+  {
+    if(in_array($prefix, $this->nslist))
+    {
+      // echo '<b>Warning:</b> pathManager::create_namespace: Prefix "'.$prefix.'" is already taken<br />';
+      return false;
+    }
+    if( isset($this->nslist[$id]) )
+    {
+      // echo '<b>Warning:</b> pathManager::create_namespace: Namespace ID "'.$prefix.'" is already taken<br />';
+      return false;
+    }
+    $this->nslist[$id] = $prefix;
+  }
+  
+  /**
+   * Fetches the page texts for searching
+   */
+   
+  function fetch_page_search_texts()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $texts = Array();
+    $q = $db->sql_query('SELECT t.page_id,t.namespace,t.page_text,t.char_tag FROM '.table_prefix.'page_text AS t
+                           LEFT JOIN '.table_prefix.'pages AS p
+                             ON t.page_id=p.urlname
+                           WHERE p.namespace=t.namespace
+                             AND ( p.password=\'\' OR p.password=\'da39a3ee5e6b4b0d3255bfef95601890afd80709\' )
+                             AND p.visible=1;'); // Only indexes "visible" pages
+    
+    if( !$q )
+    {
+      return false;
+    }
+    while($row = $db->fetchrow())
+    {
+      $pid = $this->nslist[$row['namespace']] . $row['page_id'];
+      $texts[$pid] = $row['page_text'];
+    }
+    $db->free_result();
+    
+    return $texts;
+  }
+  
+  /**
+   * Fetches a MySQL search query to use for Searcher::searchMySQL()
+   */
+   
+  function fetch_page_search_resource()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    // sha1('') returns "da39a3ee5e6b4b0d3255bfef95601890afd80709"
+    $texts = 'SELECT t.page_text,CONCAT(\'ns=\',t.namespace,\';pid=\',t.page_id) FROM '.table_prefix.'page_text AS t
+                           LEFT JOIN '.table_prefix.'pages AS p
+                             ON ( t.page_id=p.urlname AND t.namespace=p.namespace )
+                           WHERE p.namespace=t.namespace
+                             AND ( p.password=\'\' OR p.password=\'da39a3ee5e6b4b0d3255bfef95601890afd80709\' )
+                             AND p.visible=1;'; // Only indexes "visible" pages
+    return $texts;
+  }
+  
+  /**
+   * Rebuilds the search index
+   */
+   
+  function rebuild_search_index()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $search = new Searcher();
+    $texts = Array();
+    $textq = $db->sql_unbuffered_query($this->fetch_page_search_resource());
+    if(!$textq) $db->_die('');
+    while($row = $db->fetchrow_num())
+    {
+      $texts[(string)$row[1]] = $row[0];
+    }
+    $search->buildIndex($texts);
+    // echo '<pre>'.print_r($search->index, true).'</pre>';
+    // return;
+    $q = $db->sql_query('DELETE FROM '.table_prefix.'search_index');
+    if(!$q) return false;
+    $secs = Array();
+    $q = 'INSERT INTO '.table_prefix.'search_index(word,page_names) VALUES';
+    foreach($search->index as $word => $pages)
+    {
+      $secs[] = '(\''.$db->escape($word).'\', \''.$db->escape($pages).'\')';
+    }
+    $q .= implode(',', $secs);
+    unset($secs);
+    $q .= ';';
+    $result = $db->sql_query($q);
+    $db->free_result();
+    if($result)
+      return true;
+    else
+      $db->_die('The search index was trying to rebuild itself when the error occured.');
+  }
+  
+  /**
+   * Partially rebuilds the search index, removing/inserting entries only for the current page
+   * @param string $page_id
+   * @param string $namespace
+   */
+  
+  function rebuild_page_index($page_id, $namespace)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(!$db->sql_query('SELECT page_text FROM '.table_prefix.'page_text
+      WHERE page_id=\''.$db->escape($page_id).'\' AND namespace=\''.$db->escape($namespace).'\';'))
+    {
+      return $db->get_error();
+    }
+    $row = $db->fetchrow();
+    $db->free_result();
+    $search = new Searcher();
+    $search->buildIndex(Array("ns={$namespace};pid={$page_id}"=>$row['page_text']));
+    $new_index = $search->index;
+    
+    $keys = array_keys($search->index);
+    foreach($keys as $i => $k)
+    {
+      $c =& $keys[$i];
+      $c = hexencode($c, '', '');
+    }
+    $keys = "word=0x" . implode ( " OR word=0x", $keys ) . "";
+    
+    // Zap the cache
+    $cache = array_keys($search->index);
+    if ( count($cache) < 1 )
+    {
+      return false;
+    }
+    $cache = "query LIKE '%" . implode ( "%' OR query LIKE '%", $cache ) . "%'";
+    $db->sql_query('DELETE FROM '.table_prefix.'search_cache WHERE '.$cache);
+    
+    $query = $db->sql_query('SELECT word,page_names FROM '.table_prefix.'search_index WHERE '.$keys.';');
+    
+    while($row = $db->fetchrow())
+    {
+      $row['word'] = rtrim($row['word'], "\0");
+      $new_index[ $row['word'] ] = $row['page_names'] . ',' . $search->index[ $row['word'] ];
+    }
+    $db->free_result();
+    
+    $db->sql_query('DELETE FROM '.table_prefix.'search_index WHERE '.$keys.';');
+    
+    $secs = Array();
+    $q = 'INSERT INTO '.table_prefix.'search_index(word,page_names) VALUES';
+    foreach($new_index as $word => $pages)
+    {
+      $secs[] = '(\''.$db->escape($word).'\', \''.$db->escape($pages).'\')';
+    }
+    $q .= implode(',', $secs);
+    unset($secs);
+    $q .= ';';
+    if(!$db->check_query($q))
+    {
+      die('BUG: PathManager::rebuild_page_index: Query rejected by SQL parser:<pre>'.$q.'</pre>');
+    }
+    $result = $db->sql_query($q);
+    if($result)
+      return true;
+    else
+      $db->_die('The search index was trying to rebuild itself when the error occured.');
+    
+  }
+  
+  /**
+   * Creates an instance of the Searcher class, including index info
+   * @return object
+   */
+   
+  function makeSearcher($match_case = false)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $search = new Searcher();
+    $q = $db->sql_query('SELECT word,page_names FROM '.table_prefix.'search_index;');
+    if(!$q)
+    {
+      echo $db->get_error();
+      return false;
+    }
+    $idx = Array();
+    while($row = $db->fetchrow($q))
+    {
+      $row['word'] = rtrim($row['word'], "\0");
+      $idx[$row['word']] = $row['page_names'];
+    }
+    $db->free_result();
+    $search->index = $idx;
+    if($match_case)
+      $search->match_case = true;
+    return $search;
+  }
+  
+  /**
+   * Creates an associative array filled with the values of all the page titles
+   * @return array
+   */
+   
+  function get_page_titles()
+  {
+    $texts = Array();
+    for ( $i = 0; $i < sizeof($this->pages) / 2; $i++ )
+    {
+      $texts[$this->pages[$i]['urlname']] = $this->pages[$i]['name'];
+    }
+    return $texts;
+  }
+  
+  /**
+   * Creates an instance of the Searcher class, including index info for page titles
+   * @return object
+   */
+   
+  function makeTitleSearcher($match_case = false)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $search = new Searcher();
+    $texts = $this->get_page_titles();
+    $search->buildIndex($texts);
+    if($match_case)
+      $search->match_case = true;
+    return $search;
+  }
+  
+}
+  
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/plugins.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,105 @@
+<?php
+
+/*
+ * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
+ * Version 1.0 (Banshee)
+ * Copyright (C) 2006-2007 Dan Fuhry
+ *
+ * This program is Free Software; you can redistribute 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 details.
+ */
+ 
+class pluginLoader {
+  var $hook_list;
+  var $load_list;
+  var $loaded_plugins;
+  var $system_plugins = Array('SpecialUserFuncs.php','SpecialUserPrefs.php','SpecialPageFuncs.php','SpecialAdmin.php','SpecialCSS.php','SpecialUpdownload.php','SpecialSearch.php','PrivateMessages.php','SpecialGroups.php');
+  function loadAll() 
+  {
+    dc_here('plugins: building file list');
+    
+    $dir = ENANO_ROOT.'/plugins/';
+    
+    $this->load_list = Array();
+    
+    $plugins = Array();
+    
+    // Open a known directory, and proceed to read its contents
+    
+    if (is_dir($dir))
+    {
+      if ($dh = opendir($dir))
+      {
+        while (($file = readdir($dh)) !== false)
+        {
+          if(preg_match('#^(.*?)\.php$#is', $file))
+          {
+            if(getConfig('plugin_'.$file) == '1' || in_array($file, $this->system_plugins))
+            {
+              $this->load_list[] = $dir . $file;
+              $plugid = substr($file, 0, strlen($file)-4);
+              $f = file_get_contents($dir . $file);
+              $f = explode("\n", $f);
+              $f = array_slice($f, 2, 7);
+              $f[0] = substr($f[0], 13);
+              $f[1] = substr($f[1], 12);
+              $f[2] = substr($f[2], 13);
+              $f[3] = substr($f[3], 8 );
+              $f[4] = substr($f[4], 9 );
+              $f[5] = substr($f[5], 12);
+              $plugins[$plugid] = Array();
+              $plugins[$plugid]['name'] = $f[0];
+              $plugins[$plugid]['uri']  = $f[1];
+              $plugins[$plugid]['desc'] = $f[2];
+              $plugins[$plugid]['auth'] = $f[3];
+              $plugins[$plugid]['vers'] = $f[4];
+              $plugins[$plugid]['aweb'] = $f[5];
+            }
+          }
+        }
+        closedir($dh);
+      }
+    }
+    $this->loaded_plugins = $plugins;
+    //die('<pre>'.htmlspecialchars(print_r($plugins, true)).'</pre>');
+  }
+  function setHook($name, $opts = Array()) {
+    dc_dump($name, 'plugins: hook added: ');
+    /*
+    $r = Array();
+    if(isset($this->hook_list[$name])) {
+      for($i=0;$i<sizeof($this->hook_list[$name]);$i++) {
+        $ret = eval($this->hook_list[$name][$i]);
+        if($ret !== null) $r[] = $ret;
+      }
+    }
+    if(sizeof($r) > 0) return $r;
+    else return false;
+    */
+    if(isset($this->hook_list[$name]) && is_array($this->hook_list[$name]))
+    {
+      return $this->hook_list[$name];
+    }
+    else
+    {
+      return Array();
+    }
+  }
+  function attachHook($name, $code) {
+    dc_dump($code, 'plugins: hook attached: '.$name.'<br />code:');
+    if(!isset($this->hook_list[$name]))
+    {
+      $this->hook_list[$name] = Array();
+    }
+    $this->hook_list[$name][] = $code;
+  }
+  function loaded($plugid)
+  {
+    return isset( $this->loaded_plugins[$plugid] );
+  }
+}
+
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/render.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,792 @@
+<?php
+/*
+ * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
+ * Version 1.0 (Banshee)
+ * render.php - handles fetching pages and parsing them into HTML
+ * Copyright (C) 2006-2007 Dan Fuhry
+ *
+ * This program is Free Software; you can redistribute 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 details.
+ */
+ 
+class RenderMan {
+  
+  function strToPageID($string)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $k = array_keys($paths->nslist);
+    for($i=0;$i<sizeof($paths->nslist);$i++)
+    {
+      $ln = strlen($paths->nslist[$k[$i]]);
+      if(substr($string, 0, $ln) == $paths->nslist[$k[$i]])
+      {
+        $ns = $k[$i];
+        $pg = substr($string, strlen($paths->nslist[$ns]), strlen($string));
+      }
+    }
+    return Array($pg, $ns);
+  }
+  
+  function getPage($page_id, $namespace, $wiki = 1, $smilies = true, $filter_links = true, $redir = true, $render = true)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    dc_here('render: page requested<br />ID/namespace: '."$page_id, $namespace<br />Wiki mode: $wiki<br />Smilies: ".(string)$smilies."<br />Allow redirects: ".(string)$redir);
+    
+    $perms =& $session;
+    
+    if ( $page_id != $paths->cpage['urlname_nons'] || $namespace != $paths->namespace )
+    {
+      unset($perms);
+      unset($perms); // PHP <5.1.5 Zend bug
+      $perms = $session->fetch_page_acl($page_id, $namespace);
+    }
+    
+    if(!$perms->get_permissions('read'))
+      return 'Access denied ('.$paths->nslist[$namespace].$page_id.')';
+    
+    if($wiki == 0 || $render == false)
+    {
+      if(!$perms->get_permissions('view_source'))
+      {
+        return 'Access denied ('.$paths->nslist[$namespace].$page_id.')';
+      }
+    }
+    
+    $q = $db->sql_query('SELECT page_text,char_tag FROM '.table_prefix.'page_text WHERE page_id=\''.$db->escape($page_id).'\' AND namespace=\''.$db->escape($namespace).'\';');
+    if ( !$q )
+    {
+      $db->_die('Method called was: RenderMan::getPage(\''.$page_id.'\', \''.$namespace.'\');.');
+    }
+    if ( $db->numrows() < 1 )
+    {
+      return false;
+    }
+    $row = $db->fetchrow();
+    $db->free_result();
+    
+    $message = $row['page_text'];
+    $chartag = $row['char_tag'];
+    unset($row); // Free some memory
+    
+    if ( preg_match('#^\#redirect \[\[(.+?)\]\]#', $message, $m) && $redir && !isset($_GET['redirect']) || ( isset($_GET['redirect']) && $_GET['redirect'] != 'no' ) )
+    {
+      dc_here('render: looks like a redirect page to me...');
+      $old = $paths->cpage;
+      $a = RenderMan::strToPageID($m[1]);
+      $a[0] = str_replace(' ', '_', $a[0]);
+      
+      $pageid = str_replace(' ', '_', $paths->nslist[$a[1]] . $a[0]);
+      $paths->page = $pageid;
+      $paths->cpage = $paths->pages[$pageid];
+      //die('<pre>'.print_r($paths->cpage,true).'</pre>');
+      
+      dc_here('render: wreckin\' $template, and reloading the theme vars to match the new page<br />This might get messy!');
+      
+      unset($template);
+      unset($GLOBALS['template']);
+      
+      $GLOBALS['template'] = new template();
+      global $template;
+      
+      $template->template(); // Tear down and rebuild the template parser
+      $template->load_theme($session->theme, $session->style);
+      
+      $data = '<div><small>(Redirected from <a href="'.makeUrlNS($old['namespace'], $old['urlname_nons'], 'redirect=no', true).'">'.$old['name'].'</a>)</small></div>'.RenderMan::getPage($a[0], $a[1], $wiki, $smilies, $filter_links, false /* Enforces a maximum of one redirect */);
+      
+      return $data;
+    }
+    else if(preg_match('#^\#redirect \[\[(.+?)\]\]#', $message, $m) && isset($_GET['redirect']) && $_GET['redirect'] == 'no')
+    {
+      dc_here('render: looks like a redirect page to me...');
+      dc_here('render: skipping redirect as requested on URI');
+      preg_match('#^\#redirect \[\[(.+)\]\]#', $message, $m);
+      $m[1] = str_replace(' ', '_', $m[1]);
+      $message = preg_replace('#\#redirect \[\[(.+)\]\]#', '<nowiki><div class="mdg-infobox"><table border="0" width="100%" cellspacing="0" cellpadding="0"><tr><td valign="top"><img alt="Cute wet-floor icon" src="'.scriptPath.'/images/redirector.png" /></td><td valign="top" style="padding-left: 10px;"><b>This page is a <i>redirector</i>.</b><br />This means that this page will not show its own content by default. Instead it will display the contents of the page it redirects to.<br /><br />To create a redirect page, make the <i>first characters</i> in the page content <tt>#redirect [[Page_ID]]</tt>. For more information, see the Enano <a href="http://enanocms.org/Help:Wiki_formatting">Wiki formatting guide</a>.<br /><br />This page redirects to <a href="'.makeUrl($m[1]).'">'.$paths->pages[$m[1]]['name'].'</a>.</td></tr></table></div><br /><hr style="margin-left: 1em; width: 200px;" /></nowiki>', $message);
+    }
+    $session->disallow_password_grab();
+    dc_here('render: alright, got the text, formatting...');
+    return ($render) ? RenderMan::render($message, $wiki, $smilies, $filter_links) : $message;
+  }
+  
+  function getTemplate($id, $parms)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    dc_here('render: template requested: '.$id);
+    if(!isset($paths->pages[$paths->nslist['Template'].$id])) 
+    {
+      return '[['.$paths->nslist['Template'].$id.']]';
+    }
+    if(isset($paths->template_cache[$id]))
+    {
+      $text = $paths->template_cache[$id];
+    }
+    else
+    {
+      $text = RenderMan::getPage($id, 'Template', 0, true, true, 0);
+      $paths->template_cache[$id] = $text;
+    }
+    
+    $text = preg_replace('/<noinclude>(.*?)<\/noinclude>/is', '', $text);
+    $text = preg_replace('/<nodisplay>(.*?)<\/nodisplay>/is', '\\1', $text);
+    
+    preg_match_all('#\(_([0-9]+)_\)#', $text, $matchlist);
+    
+    foreach($matchlist[1] as $m)
+    {
+      if(isset($parms[((int)$m)+1])) 
+      {
+        $p = $parms[((int)$m)+1];
+      }
+      else
+      {
+        $p = '<b>Notice:</b> RenderMan::getTemplate(): Parameter '.$m.' is not set';
+      }
+      $text = str_replace('(_'.$m.'_)', $p, $text);
+    }
+    $text = RenderMan::include_templates($text);
+    return $text;
+  }
+  
+  function fetch_template_text($id)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    dc_here('render: template raw data requested: '.$id);
+    if(!isset($paths->pages[$paths->nslist['Template'].$id])) 
+    {
+      return '[['.$paths->nslist['Template'].$id.']]';
+    }
+    if(isset($paths->template_cache[$id]))
+    {
+      $text = $paths->template_cache[$id];
+    }
+    else
+    {
+      $text = RenderMan::getPage($id, 'Template', 0, false, false, false, false);
+      $paths->template_cache[$id] = $text;
+    }
+    
+    if ( is_string($text) )
+    {
+      $text = preg_replace('/<noinclude>(.*?)<\/noinclude>/is', '', $text);
+      $text = preg_replace('/<nodisplay>(.*?)<\/nodisplay>/is', '\\1', $text);
+    }
+    
+    return $text;
+  }
+  
+  function render($text, $wiki = 1, $smilies = true, $filter_links = true)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if($smilies)
+    {
+      $text = RenderMan::smilieyize($text);
+    }
+    if($wiki == 1)
+    {
+      $text = RenderMan::next_gen_wiki_format($text);
+    }
+    elseif($wiki == 2)
+    {
+      $text = $template->tplWikiFormat($text);
+    }
+    return $text;
+  }
+  
+  function PlainTextRender($text, $wiki = 1, $smilies = false, $filter_links = true)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if($smilies)
+    {
+      $text = RenderMan::smilieyize($text);
+    }
+    if($wiki == 1)
+    {
+      $text = RenderMan::next_gen_wiki_format($text, true);
+    }
+    elseif($wiki == 2)
+    {
+      $text = $template->tplWikiFormat($text);
+    }
+    return $text;
+  }
+  
+  function next_gen_wiki_format($text, $plaintext = false, $filter_links = true, $do_params = false)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $random_id = md5( time() . mt_rand() );
+    
+    // Strip out <nowiki> sections and PHP code
+    
+    $php = preg_match_all('#<\?php(.*?)\?>#is', $text, $phpsec);
+    
+    for($i=0;$i<sizeof($phpsec[1]);$i++)
+    {
+      $text = str_replace('<?php'.$phpsec[1][$i].'?>', '{PHP:'.$random_id.':'.$i.'}', $text);
+    }
+    
+    $nw = preg_match_all('#<nowiki>(.*?)<\/nowiki>#is', $text, $nowiki);
+    
+    for($i=0;$i<sizeof($nowiki[1]);$i++)
+    {
+      $text = str_replace('<nowiki>'.$nowiki[1][$i].'</nowiki>', '{NOWIKI:'.$random_id.':'.$i.'}', $text);
+    }
+    
+    $text = preg_replace('/<noinclude>(.*?)<\/noinclude>/is', '\\1', $text);
+    if ( $paths->namespace == 'Template' )
+    {
+      $text = preg_replace('/<nodisplay>(.*?)<\/nodisplay>/is', '', $text);
+    }
+    
+    if ( !$plaintext )
+    {
+      // Process images
+      
+      $j = preg_match_all('#\[\[:'.$paths->nslist['File'].'([\w\s0-9_\(\)!@%\^\+\|\.-]+?)\|([0-9]+)\|([0-9]+)\]\]#is', $text, $matchlist);
+      $matches = Array();
+      $matches['images']  =& $matchlist[1];
+      $matches['widths']  =& $matchlist[2];
+      $matches['heights'] =& $matchlist[3];
+      for($i=0;$i<sizeof($matchlist[1]);$i++)
+      {
+        if(isPage($paths->nslist['File'].$matches['images'][$i])) $text = str_replace('[[:'.$paths->nslist['File'].$matches['images'][$i].'|'.$matches['widths'][$i].'|'.$matches['heights'][$i].']]',
+          '<nowiki><a href="'.makeUrlNS('File', $matches['images'][$i]).'"><img alt="'.$matches['images'][$i].'" style="border: 0" src="'.makeUrlNS('Special', 'DownloadFile/'.$matches['images'][$i], 'preview&amp;width='.$matches['widths'][$i].'&amp;height='.$matches['heights'][$i]).'" /></a></nowiki>',
+          $text);
+      }
+      
+      $j = preg_match_all('#\[\[:'.$paths->nslist['File'].'([\w\s0-9_\(\)!@%\^\+\|\.-]+?)\]\]#is', $text, $matchlist);
+      $matches = Array();
+      $matches['images'] = $matchlist[1];
+      for($i=0;$i<sizeof($matchlist[1]);$i++)
+      {
+        if(isPage($paths->nslist['File'].$matches['images'][$i])) $text = str_replace('[[:'.$paths->nslist['File'].$matches['images'][$i].']]',
+          '<nowiki><a href="'.makeUrlNS('File', $matches['images'][$i]).'"><img alt="'.$matches['images'][$i].'" style="border: 0" src="'.makeUrlNS('Special', 'DownloadFile/'.$matches['images'][$i]).'" /></a></nowiki>',
+          $text);
+      }
+      
+    }
+    
+    if($do_params)
+    {
+      preg_match_all('#\(_([0-9]+)_\)#', $text, $matchlist);
+      foreach($matchlist[1] as $m)
+      {
+        $text = str_replace('(_'.$m.'_)', $paths->getParam((int)$m), $text);
+      }
+    }
+    
+    $text = RenderMan::include_templates($text);
+    
+    $text = process_tables($text);
+    
+    $wiki =& Text_Wiki::singleton('Mediawiki');
+    if($plaintext)
+    {
+      $wiki->setRenderConf('Plain', 'wikilink', 'view_url', contentPath);
+      $result = $wiki->transform($text, 'Plain');
+    }
+    else
+    {
+      $wiki->setRenderConf('Xhtml', 'wikilink', 'view_url', contentPath);
+      $wiki->setRenderConf('Xhtml', 'Url', 'css_descr', 'external');
+      $result = $wiki->transform($text, 'Xhtml');
+    }
+    
+    // Reinsert <nowiki> sections
+    for($i=0;$i<$nw;$i++)
+    {
+      $result = str_replace('{NOWIKI:'.$random_id.':'.$i.'}', $nowiki[1][$i], $result);
+    }
+    
+    // Reinsert PHP
+    for($i=0;$i<$php;$i++)
+    {
+      $result = str_replace('{PHP:'.$random_id.':'.$i.'}', '<?php'.$phpsec[1][$i].'?>', $result);
+    }
+    
+    return $result;
+    
+  }
+  
+  function wikiFormat($message, $filter_links = true, $do_params = false, $plaintext = false) {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    return RenderMan::next_gen_wiki_format($message, $plaintext, $filter_links, $do_params);
+    
+    $random_id = md5( time() . mt_rand() );
+    
+    // Strip out <nowiki> sections
+    $nw = preg_match_all('#<nowiki>(.*?)<\/nowiki>#is', $message, $nowiki);
+    
+    if(!$plaintext)
+    {
+    
+      //return '<pre>'.print_r($nowiki,true).'</pre>';
+      
+      for($i=0;$i<sizeof($nowiki[1]);$i++)
+      {
+        $message = str_replace('<nowiki>'.$nowiki[1][$i].'</nowiki>', '{NOWIKI:'.$random_id.':'.$i.'}', $message);
+      }
+      
+      $message = preg_replace('/<noinclude>(.*?)<\/noinclude>/is', '\\1', $message);
+      
+      //return '<pre>'.htmlspecialchars($message).'</pre>';
+      
+      $j = preg_match_all('#\[\[:'.$paths->nslist['File'].'([\w\s0-9_\(\)!@%\^\+\|\.-]+?)\|([0-9]+)\|([0-9]+)\]\]#is', $message, $matchlist);
+      $matches = Array();
+      $matches['images'] = $matchlist[1];
+      $matches['widths'] = $matchlist[2];
+      $matches['heights'] = $matchlist[3];
+      for($i=0;$i<sizeof($matchlist[1]);$i++)
+      {
+        if(isPage($paths->nslist['File'].$matches['images'][$i])) $message = str_replace('[[:'.$paths->nslist['File'].$matches['images'][$i].'|'.$matches['widths'][$i].'|'.$matches['heights'][$i].']]',
+          '<nowiki><a href="'.makeUrlNS('File', $matches['images'][$i]).'"><img alt="'.$matches['images'][$i].'" style="border: 0" src="'.makeUrlNS('Special', 'DownloadFile/'.$matches['images'][$i], 'preview&amp;width='.$matches['widths'][$i].'&amp;height='.$matches['heights'][$i]).'" /></a></nowiki>',
+          $message);
+      }
+      
+      $j = preg_match_all('#\[\[:'.$paths->nslist['File'].'([\w\s0-9_\(\)!@%\^\+\|\.-]+?)\]\]#is', $message, $matchlist);
+      $matches = Array();
+      $matches['images'] = $matchlist[1];
+      for($i=0;$i<sizeof($matchlist[1]);$i++)
+      {
+        if(isPage($paths->nslist['File'].$matches['images'][$i])) $message = str_replace('[[:'.$paths->nslist['File'].$matches['images'][$i].']]',
+          '<nowiki><a href="'.makeUrlNS('File', $matches['images'][$i]).'"><img alt="'.$matches['images'][$i].'" style="border: 0" src="'.makeUrlNS('Special', 'DownloadFile/'.$matches['images'][$i]).'" /></a></nowiki>',
+          $message);
+      }
+    
+    }
+    
+    if($do_params)
+    {
+      preg_match_all('#\(_([0-9]+)_\)#', $message, $matchlist);
+      foreach($matchlist[1] as $m)
+      {
+        $message = str_replace('(_'.$m.'_)', $paths->getParam((int)$m), $message);
+      }
+    }
+    
+    $message = RenderMan::include_templates($message);
+    
+    // Reinsert <nowiki> sections
+    for($i=0;$i<$nw;$i++)
+    {
+      $message = str_replace('{NOWIKI:'.$random_id.':'.$i.'}', '<nowiki>'.$nowiki[1][$i].'</nowiki>', $message);
+    }
+    
+    $message = process_tables($message);
+    //if($message2 != $message) return '<pre>'.htmlspecialchars($message2).'</pre>';
+    //$message = str_replace(array('<table>', '</table>'), array('<nowiki><table>', '</table></nowiki>'), $message);
+    
+    $wiki =& Text_Wiki::singleton('Mediawiki');
+    if($plaintext)
+    {
+      $wiki->setRenderConf('Plain', 'wikilink', 'view_url', contentPath);
+      $result = $wiki->transform($message, 'Plain');
+    } else {
+      $wiki->setRenderConf('Xhtml', 'wikilink', 'view_url', contentPath);
+      $wiki->setRenderConf('Xhtml', 'Url', 'css_descr', 'external');
+      $result = $wiki->transform($message, 'Xhtml');
+    }
+    
+    // HTML fixes
+    $result = preg_replace('#<tr>([\s]*?)<\/tr>#is', '', $result);
+    $result = preg_replace('#<p>([\s]*?)<\/p>#is', '', $result);
+    $result = preg_replace('#<br />([\s]*?)<table#is', '<table', $result);
+    $result = str_replace("<pre><code>\n", "<pre><code>", $result);
+    $result = preg_replace("/<p><table([^>]*?)><\/p>/", "<table\\1>", $result);
+    $result = str_replace("<br />\n</td>", "\n</td>", $result);
+    $result = str_replace("<p><tr>", "<tr>", $result);
+    $result = str_replace("<tr><br />", "<tr>", $result);
+    $result = str_replace("</tr><br />", "</tr>", $result);
+    $result = str_replace("</table></p>", "</table>", $result);
+    $result = str_replace("</table><br />", "</table>", $result);
+    $result = preg_replace('/<\/table>$/', "</table><br /><br />", $result);
+    
+    $result = str_replace('<nowiki>',  '&lt;nowiki&gt;',  $result);
+    $result = str_replace('</nowiki>', '&lt;/nowiki&gt;', $result);
+    
+    return $result;
+  }
+  
+  function destroy_javascript($message, $_php = false)
+  {
+    $message = preg_replace('#<(script|object|applet|embed|iframe|frame|form|input|select)(.*?)>#is', '&lt;\\1\\2&gt;', $message);
+    $message = preg_replace('#</(script|object|applet|embed|iframe|frame|form|input|select)(.*?)>#is', '&lt;/\\1\\2&gt;', $message);
+    $message = preg_replace('#(javascript|script|activex|chrome|about|applet):#is', '\\1&#058;', $message);
+    if ( $_php )
+    {
+      // Left in only for compatibility
+      $message = preg_replace('#&lt;(.*?)>#is', '<\\1>', $message);
+      $message = preg_replace('#<(.*?)&gt;#is', '<\\1>', $message);
+      $message = preg_replace('#<(\?|\?php|%)(.*?)(\?|%)>#is', '&lt;\\1\\2\\3&gt;', $message);
+      // strip <a href="foo" onclick="bar();">-type attacks
+      $message = preg_replace('#<([a-zA-Z:\-]+) (.*?)on([A-Za-z]*)=(.*?)>#is', '&lt;\\1\\2on\\3=\\4&gt;', $message);
+    }
+    return $message;
+  }
+  
+  function strip_php($message)
+  {
+    return RenderMan::destroy_javascript($message, true);
+  }
+  
+  function sanitize_html($text)
+  {
+    $text = htmlspecialchars($text);
+    $allowed_tags = Array('b', 'i', 'u', 'pre', 'code', 'tt', 'br', 'p', 'nowiki', '!--([^.]+)--');
+    foreach($allowed_tags as $t)
+    {
+      $text = preg_replace('#&lt;'.$t.'&gt;(.*?)&lt;/'.$t.'&gt;#is', '<'.$t.'>\\1</'.$t.'>', $text);
+      $text = preg_replace('#&lt;'.$t.' /&gt;#is', '<'.$t.' />', $text);
+      $text = preg_replace('#&lt;'.$t.'&gt;#is', '<'.$t.'>', $text);
+    }
+    return $text;
+  }
+  
+  /* *
+   * Replaces template inclusions with the templates
+   * @param string $message The text to format
+   * @return string
+   * /
+   
+  function old_include_templates($message)
+  {
+    $random_id = md5( time() . mt_rand() );
+    preg_match_all('#\{\{(.+?)\}\}#s', $message, $matchlist);
+    foreach($matchlist[1] as $m)
+    {
+      $mn = $m;
+      // Strip out wikilinks and re-add them after the explosion (because of the "|")
+      preg_match_all('#\[\[(.+?)\]\]#i', $m, $linklist);
+      //echo '<pre>'.print_r($linklist, true).'</pre>';
+      for($i=0;$i<sizeof($linklist[1]);$i++)
+      {
+        $mn = str_replace('[['.$linklist[1][$i].']]', '{WIKILINK:'.$random_id.':'.$i.'}', $mn);
+      }
+      
+      $ar = explode('|', $mn);
+      
+      for($j=0;$j<sizeof($ar);$j++)
+      {
+        for($i=0;$i<sizeof($linklist[1]);$i++)
+        {
+          $ar[$j] = str_replace('{WIKILINK:'.$random_id.':'.$i.'}', '[['.$linklist[1][$i].']]', $ar[$j]);
+        }
+      }
+      
+      $tp = $ar[0];
+      unset($ar[0]);
+      $tp = str_replace(' ', '_', $tp);
+      $message = str_replace('{{'.$m.'}}', RenderMan::getTemplate($tp, $ar), $message);
+    }
+    return $message;
+  }
+  */
+  
+  /**
+   * Parses a partial template tag in wikitext, and return an array with the parameters.
+   * @param string The portion of the template tag that contains the parameters. Example:
+   * <code>
+   * foo = lorem ipsum
+   * bar = dolor sit amet
+   * </code>
+   * @return array Example:
+   * [foo] => lorem ipsum
+   * [bar] => dolor sit amet
+   */
+  
+  function parse_template_vars($input)
+  {
+    $input = explode("\n", trim( $input ));
+    $parms = Array();
+    $current_line = '';
+    $current_parm = '';
+    foreach ( $input as $num => $line )
+    {
+      if ( preg_match('/^([ ]*?)([A-z0-9_]+?)([ ]*?)=([ ]*?)(.+?)$/i', $line, $matches) )
+      {
+        $parm =& $matches[2];
+        $text =& $matches[5];
+        if ( $parm == $current_parm )
+        {
+          $current_line .= $text;
+        }
+        else
+        {
+          // New parameter
+          if ( $current_parm != '' )
+            $parms[$current_parm] = $current_line;
+          $current_line = $text;
+          $current_parm = $parm;
+        }
+      }
+      else if ( $num == 0 )
+      {
+        // Syntax error
+        return false;
+      }
+      else
+      {
+        $current_line .= "\n$line";
+      }
+    }
+    if ( !empty($current_parm) && !empty($current_line) )
+    {
+      $parms[$current_parm] = $current_line;
+    }
+    return $parms;
+  }
+  
+  /**
+   * Processes all template tags within a block of wikitext.
+   * @param string The text to process
+   * @return string Formatted text
+   * @example
+   * <code>
+   $text = '{{Template
+     parm1 = Foo
+     parm2 = Bar
+     }}';
+   $text = include_templates($text);
+   * </code>
+   */
+  
+  function include_templates($text)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $template_regex = "/\{\{([A-z0-9_-]+?)((\n([ ]*?)[A-z0-9]+([ ]*?)=([ ]*?)(.+?))*)\}\}/is";
+    if ( $count = preg_match_all($template_regex, $text, $matches) )
+    {
+      for ( $i = 0; $i < $count; $i++ )
+      {
+        $parmsection = trim($matches[2][$i]);
+        if ( !empty($parmsection) )
+        {
+          $parms = RenderMan::parse_template_vars($parmsection);
+          foreach ( $parms as $j => $parm )
+          {
+            $parms[$j] = $parm;
+          }
+        }
+        else
+        {
+          $parms = Array();
+        }
+        if ( $tpl_code = RenderMan::fetch_template_text($matches[1][$i]) )
+        {
+          $parser = $template->makeParserText($tpl_code);
+          $parser->assign_vars($parms);
+          $text = str_replace($matches[0][$i], $parser->run(), $text);
+        }
+      }
+    }
+    return $text;
+  }
+  
+  /**
+   * Preprocesses an HTML text string prior to being sent to MySQL.
+   * @param string $text
+   * @param bool $strip_all_php - if true, strips all PHP regardless of user permissions. Else, strips PHP only if user level < USER_LEVEL_ADMIN.
+   */
+  function preprocess_text($text, $strip_all_php = true, $sqlescape = true)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $random_id = md5( time() . mt_rand() );
+    
+    $can_do_php = ( $session->get_permissions('php_in_pages') && !$strip_all_php );
+    
+    $text = sanitize_html($text, ( !$can_do_php ));
+    
+    if ( !$can_do_php )
+    {
+      // If we can't do PHP, we can't do Javascript either.
+      $text = RenderMan::destroy_javascript($text);
+    }
+    
+    // Strip out <nowiki> sections and PHP code
+    
+    $php = preg_match_all('#(<|&lt;)\?php(.*?)\?(>|&gt;)#is', $text, $phpsec);
+    
+    //die('<pre>'.htmlspecialchars(print_r($phpsec, true))."\n".htmlspecialchars(print_r($text, true)).'</pre>');
+    
+    for($i=0;$i<sizeof($phpsec[1]);$i++)
+    {
+      $text = str_replace($phpsec[0][$i], '{PHP:'.$random_id.':'.$i.'}', $text);
+    }
+    
+    $nw = preg_match_all('#<nowiki>(.*?)<\/nowiki>#is', $text, $nowiki);
+    
+    for($i=0;$i<sizeof($nowiki[1]);$i++)
+    {
+      $text = str_replace('<nowiki>'.$nowiki[1][$i].'</nowiki>', '{NOWIKI:'.$random_id.':'.$i.'}', $text);
+    }
+    
+    $text = str_replace('~~~~~', date('G:i, j F Y (T)'), $text);
+    $text = str_replace('~~~~', "[[User:$session->username|$session->username]] ".date('G:i, j F Y (T)'), $text);
+    $text = str_replace('~~~', "[[User:$session->username|$session->username]] ", $text);
+    
+    // Reinsert <nowiki> sections
+    for($i=0;$i<$nw;$i++)
+    {
+      $text = str_replace('{NOWIKI:'.$random_id.':'.$i.'}', '<nowiki>'.$nowiki[1][$i].'</nowiki>', $text);
+    }
+    // Reinsert PHP
+    for($i=0;$i<$php;$i++)
+    {
+      $phsec = ''.$phpsec[1][$i].'?php'.$phpsec[2][$i].'?'.$phpsec[3][$i].'';
+      if ( $strip_all_php )
+        $phsec = htmlspecialchars($phsec);
+      $text = str_replace('{PHP:'.$random_id.':'.$i.'}', $phsec, $text);
+    }
+    
+    $text = ( $sqlescape ) ? $db->escape($text) : $text;
+    
+    return $text;
+  }
+  
+  function smilieyize($text, $complete_urls = false)
+  {
+    
+    $random_id = md5( time() . mt_rand() );
+    
+    // Smileys array - eventually this will be fetched from the database by
+    // RenderMan::initSmileys during initialization, but it will all be hardcoded for beta 2
+    
+    $smileys = Array(
+      'O:-)'    => 'face-angel.png',
+      'O:)'     => 'face-angel.png',
+      'O=)'     => 'face-angel.png',
+      ':-)'     => 'face-smile.png',
+      ':)'      => 'face-smile.png',
+      '=)'      => 'face-smile-big.png',
+      ':-('     => 'face-sad.png',
+      ':('      => 'face-sad.png',
+      ';('      => 'face-sad.png',
+      ':-O'     => 'face-surprise.png',
+      ';-)'     => 'face-wink.png',
+      ';)'      => 'face-wink.png',
+      '8-)'     => 'face-glasses.png',
+      '8)'      => 'face-glasses.png',
+      ':-D'     => 'face-grin.png',
+      ':D'      => 'face-grin.png',
+      '=D'      => 'face-grin.png',
+      ':-*'     => 'face-kiss.png',
+      ':*'      => 'face-kiss.png',
+      '=*'      => 'face-kiss.png',
+      ':\'('    => 'face-crying.png',
+      ':-|'     => 'face-plain.png',
+      ':-\\'    => 'face-plain.png',
+      ':-/'     => 'face-plain.png',
+      ':joke:'  => 'face-plain.png',
+      ']:-&gt;' => 'face-devil-grin.png',
+      ':kiss:'  => 'face-kiss.png',
+      ':-P'     => 'face-tongue-out.png',
+      ':P'      => 'face-tongue-out.png',
+      ':-p'     => 'face-tongue-out.png',
+      ':p'      => 'face-tongue-out.png',
+      ':-X'     => 'face-sick.png',
+      ':X'      => 'face-sick.png',
+      ':sick:'  => 'face-sick.png',
+      ':-]'     => 'face-oops.png',
+      ':]'      => 'face-oops.png',
+      ':oops:'  => 'face-oops.png',
+      ':-['     => 'face-embarassed.png',
+      ':['      => 'face-embarassed.png'
+      );
+    /*
+    $keys = array_keys($smileys);
+    foreach($keys as $k)
+    {
+      $regex1 = '#([\W]+)'.preg_quote($k).'([\s\n\r\.]+)#s';
+      $regex2 = '\\1<img alt="'.$k.'" title="'.$k.'" src="'.scriptPath.'/images/smilies/'.$smileys[$k].'" style="border: 0;" />\\2';
+      $text = preg_replace($regex1, $regex2, $text);
+    }                                                                      
+    */
+    
+    // Strip out <nowiki> sections
+    //return '<pre>'.htmlspecialchars($text).'</pre>';
+    $nw = preg_match_all('#<nowiki>(.*?)<\/nowiki>#is', $text, $nowiki);
+    
+    for($i=0;$i<sizeof($nowiki[1]);$i++)
+    {
+      $text = str_replace('<nowiki>'.$nowiki[1][$i].'</nowiki>', '{NOWIKI:'.$random_id.':'.$i.'}', $text);
+    }
+    
+    $keys = array_keys($smileys);
+    foreach($keys as $k)
+    {
+      $t = str_hex($k);
+      $t = explode(' ', $t);
+      $s = '';
+      foreach($t as $b)
+      {
+        $s.='&#x'.$b.';';
+      }
+      $pfx = ( $complete_urls ) ? 'http' . ( isset($_SERVER['HTTPS']) ? 's' : '' ) . '://'.$_SERVER['HTTP_HOST'] : '';
+      $text = str_replace(' '.$k, ' <nowiki><img title="'.$s.'" alt="'.$s.'" src="'.$pfx.scriptPath.'/images/smilies/'.$smileys[$k].'" style="border: 0;" /></nowiki>', $text);
+    }
+    //*/
+    
+    // Reinsert <nowiki> sections
+    for($i=0;$i<$nw;$i++)
+    {
+      $text = str_replace('{NOWIKI:'.$random_id.':'.$i.'}', '<nowiki>'.$nowiki[1][$i].'</nowiki>', $text);
+    }
+    
+    return $text;
+  }
+  
+  /*
+   * **** DEPRECATED ****
+   * Replaces some critical characters in a string with MySQL-safe equivalents
+   * @param $text string the text to escape
+   * @return array key 0 is the escaped text, key 1 is the character tag
+   * /
+   
+  function escape_page_text($text)
+  {
+    $char_tag = md5(microtime() . mt_rand());
+    $text = str_replace("'",  "{APOS:$char_tag}",  $text);
+    $text = str_replace('"',  "{QUOT:$char_tag}",  $text);
+    $text = str_replace("\\", "{SLASH:$char_tag}", $text);
+    return Array($text, $char_tag);
+  }
+  */
+  
+  /* **** DEPRECATED ****
+   * Reverses the result of RenderMan::escape_page_text().
+   * @param $text string the text to unescape
+   * @param $char_tag string the character tag
+   * @return string
+   * /
+   
+  function unescape_page_text($text, $char_tag)
+  {
+    $text = str_replace("{APOS:$char_tag}",  "'",  $text);
+    $text = str_replace("{QUOT:$char_tag}",  '"',  $text);
+    $text = str_replace("{SLASH:$char_tag}", "\\", $text);
+    return $text;
+  }
+  */
+  
+  /**
+   * Generates a summary of the differences between two texts, and formats it as XHTML.
+   * @param $str1 string the first block of text
+   * @param $str2 string the second block of text
+   * @return string
+   */
+  function diff($str1, $str2)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $str1 = explode("\n", $str1);
+    $str2 = explode("\n", $str2);
+    $diff = new Diff($str1, $str2);
+    $renderer = new TableDiffFormatter();
+    return '<table class="diff">'.$renderer->format($diff).'</table>';
+  }
+  
+}
+ 
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/render.php~	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,792 @@
+<?php
+/*
+ * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
+ * Version 1.0 (Banshee)
+ * render.php - handles fetching pages and parsing them into HTML
+ * Copyright (C) 2006-2007 Dan Fuhry
+ *
+ * This program is Free Software; you can redistribute 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 details.
+ */
+ 
+class RenderMan {
+  
+  function strToPageID($string)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $k = array_keys($paths->nslist);
+    for($i=0;$i<sizeof($paths->nslist);$i++)
+    {
+      $ln = strlen($paths->nslist[$k[$i]]);
+      if(substr($string, 0, $ln) == $paths->nslist[$k[$i]])
+      {
+        $ns = $k[$i];
+        $pg = substr($string, strlen($paths->nslist[$ns]), strlen($string));
+      }
+    }
+    return Array($pg, $ns);
+  }
+  
+  function getPage($page_id, $namespace, $wiki = 1, $smilies = true, $filter_links = true, $redir = true, $render = true)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    dc_here('render: page requested<br />ID/namespace: '."$page_id, $namespace<br />Wiki mode: $wiki<br />Smilies: ".(string)$smilies."<br />Allow redirects: ".(string)$redir);
+    
+    $perms =& $session;
+    
+    if ( $page_id != $paths->cpage['urlname_nons'] || $namespace != $paths->namespace )
+    {
+      unset($perms);
+      unset($perms); // PHP <5.1.5 Zend bug
+      $perms = $session->fetch_page_acl($page_id, $namespace);
+    }
+    
+    if(!$perms->get_permissions('read'))
+      return 'Access denied ('.$paths->nslist[$namespace].$page_id.')';
+    
+    if($wiki == 0 || $render == false)
+    {
+      if(!$perms->get_permissions('view_source'))
+      {
+        return 'Access denied ('.$paths->nslist[$namespace].$page_id.')';
+      }
+    }
+    
+    $q = $db->sql_query('SELECT page_text,char_tag FROM '.table_prefix.'page_text WHERE page_id=\''.$db->escape($page_id).'\' AND namespace=\''.$db->escape($namespace).'\';');
+    if ( !$q )
+    {
+      $db->_die('Method called was: RenderMan::getPage(\''.$page_id.'\', \''.$namespace.'\');.');
+    }
+    if ( $db->numrows() < 1 )
+    {
+      return false;
+    }
+    $row = $db->fetchrow();
+    $db->free_result();
+    
+    $message = $row['page_text'];
+    $chartag = $row['char_tag'];
+    unset($row); // Free some memory
+    
+    if ( preg_match('#^\#redirect \[\[(.+?)\]\]#', $message, $m) && $redir && !isset($_GET['redirect']) || ( isset($_GET['redirect']) && $_GET['redirect'] != 'no' ) )
+    {
+      dc_here('render: looks like a redirect page to me...');
+      $old = $paths->cpage;
+      $a = RenderMan::strToPageID($m[1]);
+      $a[0] = str_replace(' ', '_', $a[0]);
+      
+      $pageid = str_replace(' ', '_', $paths->nslist[$a[1]] . $a[0]);
+      $paths->page = $pageid;
+      $paths->cpage = $paths->pages[$pageid];
+      //die('<pre>'.print_r($paths->cpage,true).'</pre>');
+      
+      dc_here('render: wreckin\' $template, and reloading the theme vars to match the new page<br />This might get messy!');
+      
+      unset($template);
+      unset($GLOBALS['template']);
+      
+      $GLOBALS['template'] = new template();
+      global $template;
+      
+      $template->template(); // Tear down and rebuild the template parser
+      $template->load_theme($session->theme, $session->style);
+      
+      $data = '<div><small>(Redirected from <a href="'.makeUrlNS($old['namespace'], $old['urlname_nons'], 'redirect=no', true).'">'.$old['name'].'</a>)</small></div>'.RenderMan::getPage($a[0], $a[1], $wiki, $smilies, $filter_links, false /* Enforces a maximum of one redirect */);
+      
+      return $data;
+    }
+    else if(preg_match('#^\#redirect \[\[(.+?)\]\]#', $message, $m) && isset($_GET['redirect']) && $_GET['redirect'] == 'no')
+    {
+      dc_here('render: looks like a redirect page to me...');
+      dc_here('render: skipping redirect as requested on URI');
+      preg_match('#^\#redirect \[\[(.+)\]\]#', $message, $m);
+      $m[1] = str_replace(' ', '_', $m[1]);
+      $message = preg_replace('#\#redirect \[\[(.+)\]\]#', '<nowiki><div class="mdg-infobox"><table border="0" width="100%" cellspacing="0" cellpadding="0"><tr><td valign="top"><img alt="Cute wet-floor icon" src="'.scriptPath.'/images/redirector.png" /></td><td valign="top" style="padding-left: 10px;"><b>This page is a <i>redirector</i>.</b><br />This means that this page will not show its own content by default. Instead it will display the contents of the page it redirects to.<br /><br />To create a redirect page, make the <i>first characters</i> in the page content <tt>#redirect [[Page_ID]]</tt>. For more information, see the Enano <a href="http://enanocms.org/Help:Wiki_formatting">Wiki formatting guide</a>.<br /><br />This page redirects to <a href="'.makeUrl($m[1]).'">'.$paths->pages[$m[1]]['name'].'</a>.</td></tr></table></div><br /><hr style="margin-left: 1em; width: 200px;" /></nowiki>', $message);
+    }
+    $session->disallow_password_grab();
+    dc_here('render: alright, got the text, formatting...');
+    return ($render) ? RenderMan::render($message, $wiki, $smilies, $filter_links) : $message;
+  }
+  
+  function getTemplate($id, $parms)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    dc_here('render: template requested: '.$id);
+    if(!isset($paths->pages[$paths->nslist['Template'].$id])) 
+    {
+      return '[['.$paths->nslist['Template'].$id.']]';
+    }
+    if(isset($paths->template_cache[$id]))
+    {
+      $text = $paths->template_cache[$id];
+    }
+    else
+    {
+      $text = RenderMan::getPage($id, 'Template', 0, true, true, 0);
+      $paths->template_cache[$id] = $text;
+    }
+    
+    $text = preg_replace('/<noinclude>(.*?)<\/noinclude>/is', '', $text);
+    $text = preg_replace('/<nodisplay>(.*?)<\/nodisplay>/is', '\\1', $text);
+    
+    preg_match_all('#\(_([0-9]+)_\)#', $text, $matchlist);
+    
+    foreach($matchlist[1] as $m)
+    {
+      if(isset($parms[((int)$m)+1])) 
+      {
+        $p = $parms[((int)$m)+1];
+      }
+      else
+      {
+        $p = '<b>Notice:</b> RenderMan::getTemplate(): Parameter '.$m.' is not set';
+      }
+      $text = str_replace('(_'.$m.'_)', $p, $text);
+    }
+    $text = RenderMan::include_templates($text);
+    return $text;
+  }
+  
+  function fetch_template_text($id)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    dc_here('render: template raw data requested: '.$id);
+    if(!isset($paths->pages[$paths->nslist['Template'].$id])) 
+    {
+      return '[['.$paths->nslist['Template'].$id.']]';
+    }
+    if(isset($paths->template_cache[$id]))
+    {
+      $text = $paths->template_cache[$id];
+    }
+    else
+    {
+      $text = RenderMan::getPage($id, 'Template', 0, false, false, false, false);
+      $paths->template_cache[$id] = $text;
+    }
+    
+    if ( is_string($text) )
+    {
+      $text = preg_replace('/<noinclude>(.*?)<\/noinclude>/is', '', $text);
+      $text = preg_replace('/<nodisplay>(.*?)<\/nodisplay>/is', '\\1', $text);
+    }
+    
+    return $text;
+  }
+  
+  function render($text, $wiki = 1, $smilies = true, $filter_links = true)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if($smilies)
+    {
+      $text = RenderMan::smilieyize($text);
+    }
+    if($wiki == 1)
+    {
+      $text = RenderMan::next_gen_wiki_format($text);
+    }
+    elseif($wiki == 2)
+    {
+      $text = $template->tplWikiFormat($text);
+    }
+    return $text;
+  }
+  
+  function PlainTextRender($text, $wiki = 1, $smilies = false, $filter_links = true)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if($smilies)
+    {
+      $text = RenderMan::smilieyize($text);
+    }
+    if($wiki == 1)
+    {
+      $text = RenderMan::next_gen_wiki_format($text, true);
+    }
+    elseif($wiki == 2)
+    {
+      $text = $template->tplWikiFormat($text);
+    }
+    return $text;
+  }
+  
+  function next_gen_wiki_format($text, $plaintext = false, $filter_links = true, $do_params = false)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $random_id = md5( time() . mt_rand() );
+    
+    // Strip out <nowiki> sections and PHP code
+    
+    $php = preg_match_all('#<\?php(.*?)\?>#is', $text, $phpsec);
+    
+    for($i=0;$i<sizeof($phpsec[1]);$i++)
+    {
+      $text = str_replace('<?php'.$phpsec[1][$i].'?>', '{PHP:'.$random_id.':'.$i.'}', $text);
+    }
+    
+    $nw = preg_match_all('#<nowiki>(.*?)<\/nowiki>#is', $text, $nowiki);
+    
+    for($i=0;$i<sizeof($nowiki[1]);$i++)
+    {
+      $text = str_replace('<nowiki>'.$nowiki[1][$i].'</nowiki>', '{NOWIKI:'.$random_id.':'.$i.'}', $text);
+    }
+    
+    $text = preg_replace('/<noinclude>(.*?)<\/noinclude>/is', '\\1', $text);
+    if ( $paths->namespace == 'Template' )
+    {
+      $text = preg_replace('/<nodisplay>(.*?)<\/nodisplay>/is', '', $text);
+    }
+    
+    if ( !$plaintext )
+    {
+      // Process images
+      
+      $j = preg_match_all('#\[\[:'.$paths->nslist['File'].'([\w\s0-9_\(\)!@%\^\+\|\.-]+?)\|([0-9]+)\|([0-9]+)\]\]#is', $text, $matchlist);
+      $matches = Array();
+      $matches['images']  =& $matchlist[1];
+      $matches['widths']  =& $matchlist[2];
+      $matches['heights'] =& $matchlist[3];
+      for($i=0;$i<sizeof($matchlist[1]);$i++)
+      {
+        if(isPage($paths->nslist['File'].$matches['images'][$i])) $text = str_replace('[[:'.$paths->nslist['File'].$matches['images'][$i].'|'.$matches['widths'][$i].'|'.$matches['heights'][$i].']]',
+          '<nowiki><a href="'.makeUrlNS('File', $matches['images'][$i]).'"><img alt="'.$matches['images'][$i].'" style="border: 0" src="'.makeUrlNS('Special', 'DownloadFile/'.$matches['images'][$i], 'preview&amp;width='.$matches['widths'][$i].'&amp;height='.$matches['heights'][$i]).'" /></a></nowiki>',
+          $text);
+      }
+      
+      $j = preg_match_all('#\[\[:'.$paths->nslist['File'].'([\w\s0-9_\(\)!@%\^\+\|\.-]+?)\]\]#is', $text, $matchlist);
+      $matches = Array();
+      $matches['images'] = $matchlist[1];
+      for($i=0;$i<sizeof($matchlist[1]);$i++)
+      {
+        if(isPage($paths->nslist['File'].$matches['images'][$i])) $text = str_replace('[[:'.$paths->nslist['File'].$matches['images'][$i].']]',
+          '<nowiki><a href="'.makeUrlNS('File', $matches['images'][$i]).'"><img alt="'.$matches['images'][$i].'" style="border: 0" src="'.makeUrlNS('Special', 'DownloadFile/'.$matches['images'][$i]).'" /></a></nowiki>',
+          $text);
+      }
+      
+    }
+    
+    if($do_params)
+    {
+      preg_match_all('#\(_([0-9]+)_\)#', $text, $matchlist);
+      foreach($matchlist[1] as $m)
+      {
+        $text = str_replace('(_'.$m.'_)', $paths->getParam((int)$m), $text);
+      }
+    }
+    
+    $text = RenderMan::include_templates($text);
+    
+    $text = process_tables($text);
+    
+    $wiki =& Text_Wiki::singleton('Mediawiki');
+    if($plaintext)
+    {
+      $wiki->setRenderConf('Plain', 'wikilink', 'view_url', contentPath);
+      $result = $wiki->transform($text, 'Plain');
+    }
+    else
+    {
+      $wiki->setRenderConf('Xhtml', 'wikilink', 'view_url', contentPath);
+      $wiki->setRenderConf('Xhtml', 'Url', 'css_descr', 'external');
+      $result = $wiki->transform($text, 'Xhtml');
+    }
+    
+    // Reinsert <nowiki> sections
+    for($i=0;$i<$nw;$i++)
+    {
+      $result = str_replace('{NOWIKI:'.$random_id.':'.$i.'}', $nowiki[1][$i], $result);
+    }
+    
+    // Reinsert PHP
+    for($i=0;$i<$php;$i++)
+    {
+      $result = str_replace('{PHP:'.$random_id.':'.$i.'}', '<?php'.$phpsec[1][$i].'?>', $result);
+    }
+    
+    return $result;
+    
+  }
+  
+  function wikiFormat($message, $filter_links = true, $do_params = false, $plaintext = false) {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    return RenderMan::next_gen_wiki_format($message, $plaintext, $filter_links, $do_params);
+    
+    $random_id = md5( time() . mt_rand() );
+    
+    // Strip out <nowiki> sections
+    $nw = preg_match_all('#<nowiki>(.*?)<\/nowiki>#is', $message, $nowiki);
+    
+    if(!$plaintext)
+    {
+    
+      //return '<pre>'.print_r($nowiki,true).'</pre>';
+      
+      for($i=0;$i<sizeof($nowiki[1]);$i++)
+      {
+        $message = str_replace('<nowiki>'.$nowiki[1][$i].'</nowiki>', '{NOWIKI:'.$random_id.':'.$i.'}', $message);
+      }
+      
+      $message = preg_replace('/<noinclude>(.*?)<\/noinclude>/is', '\\1', $message);
+      
+      //return '<pre>'.htmlspecialchars($message).'</pre>';
+      
+      $j = preg_match_all('#\[\[:'.$paths->nslist['File'].'([\w\s0-9_\(\)!@%\^\+\|\.-]+?)\|([0-9]+)\|([0-9]+)\]\]#is', $message, $matchlist);
+      $matches = Array();
+      $matches['images'] = $matchlist[1];
+      $matches['widths'] = $matchlist[2];
+      $matches['heights'] = $matchlist[3];
+      for($i=0;$i<sizeof($matchlist[1]);$i++)
+      {
+        if(isPage($paths->nslist['File'].$matches['images'][$i])) $message = str_replace('[[:'.$paths->nslist['File'].$matches['images'][$i].'|'.$matches['widths'][$i].'|'.$matches['heights'][$i].']]',
+          '<nowiki><a href="'.makeUrlNS('File', $matches['images'][$i]).'"><img alt="'.$matches['images'][$i].'" style="border: 0" src="'.makeUrlNS('Special', 'DownloadFile/'.$matches['images'][$i], 'preview&amp;width='.$matches['widths'][$i].'&amp;height='.$matches['heights'][$i]).'" /></a></nowiki>',
+          $message);
+      }
+      
+      $j = preg_match_all('#\[\[:'.$paths->nslist['File'].'([\w\s0-9_\(\)!@%\^\+\|\.-]+?)\]\]#is', $message, $matchlist);
+      $matches = Array();
+      $matches['images'] = $matchlist[1];
+      for($i=0;$i<sizeof($matchlist[1]);$i++)
+      {
+        if(isPage($paths->nslist['File'].$matches['images'][$i])) $message = str_replace('[[:'.$paths->nslist['File'].$matches['images'][$i].']]',
+          '<nowiki><a href="'.makeUrlNS('File', $matches['images'][$i]).'"><img alt="'.$matches['images'][$i].'" style="border: 0" src="'.makeUrlNS('Special', 'DownloadFile/'.$matches['images'][$i]).'" /></a></nowiki>',
+          $message);
+      }
+    
+    }
+    
+    if($do_params)
+    {
+      preg_match_all('#\(_([0-9]+)_\)#', $message, $matchlist);
+      foreach($matchlist[1] as $m)
+      {
+        $message = str_replace('(_'.$m.'_)', $paths->getParam((int)$m), $message);
+      }
+    }
+    
+    $message = RenderMan::include_templates($message);
+    
+    // Reinsert <nowiki> sections
+    for($i=0;$i<$nw;$i++)
+    {
+      $message = str_replace('{NOWIKI:'.$random_id.':'.$i.'}', '<nowiki>'.$nowiki[1][$i].'</nowiki>', $message);
+    }
+    
+    $message = process_tables($message);
+    //if($message2 != $message) return '<pre>'.htmlspecialchars($message2).'</pre>';
+    //$message = str_replace(array('<table>', '</table>'), array('<nowiki><table>', '</table></nowiki>'), $message);
+    
+    $wiki =& Text_Wiki::singleton('Mediawiki');
+    if($plaintext)
+    {
+      $wiki->setRenderConf('Plain', 'wikilink', 'view_url', contentPath);
+      $result = $wiki->transform($message, 'Plain');
+    } else {
+      $wiki->setRenderConf('Xhtml', 'wikilink', 'view_url', contentPath);
+      $wiki->setRenderConf('Xhtml', 'Url', 'css_descr', 'external');
+      $result = $wiki->transform($message, 'Xhtml');
+    }
+    
+    // HTML fixes
+    $result = preg_replace('#<tr>([\s]*?)<\/tr>#is', '', $result);
+    $result = preg_replace('#<p>([\s]*?)<\/p>#is', '', $result);
+    $result = preg_replace('#<br />([\s]*?)<table#is', '<table', $result);
+    $result = str_replace("<pre><code>\n", "<pre><code>", $result);
+    $result = preg_replace("/<p><table([^>]*?)><\/p>/", "<table\\1>", $result);
+    $result = str_replace("<br />\n</td>", "\n</td>", $result);
+    $result = str_replace("<p><tr>", "<tr>", $result);
+    $result = str_replace("<tr><br />", "<tr>", $result);
+    $result = str_replace("</tr><br />", "</tr>", $result);
+    $result = str_replace("</table></p>", "</table>", $result);
+    $result = str_replace("</table><br />", "</table>", $result);
+    $result = preg_replace('/<\/table>$/', "</table><br /><br />", $result);
+    
+    $result = str_replace('<nowiki>',  '&lt;nowiki&gt;',  $result);
+    $result = str_replace('</nowiki>', '&lt;/nowiki&gt;', $result);
+    
+    return $result;
+  }
+  
+  function destroy_javascript($message, $_php = false)
+  {
+    $message = preg_replace('#<(script|object|applet|embed|iframe|frame|form|input|select)(.*?)>#is', '&lt;\\1\\2&gt;', $message);
+    $message = preg_replace('#</(script|object|applet|embed|iframe|frame|form|input|select)(.*?)>#is', '&lt;/\\1\\2&gt;', $message);
+    $message = preg_replace('#(javascript|script|activex|chrome|about|applet):#is', '\\1&#058;', $message);
+    if ( $_php )
+    {
+      // Left in only for compatibility
+      $message = preg_replace('#&lt;(.*?)>#is', '<\\1>', $message);
+      $message = preg_replace('#<(.*?)&gt;#is', '<\\1>', $message);
+      $message = preg_replace('#<(\?|\?php|%)(.*?)(\?|%)>#is', '&lt;\\1\\2\\3&gt;', $message);
+      // strip <a href="foo" onclick="bar();">-type attacks
+      $message = preg_replace('#<([a-zA-Z:\-]+) (.*?)on([A-Za-z]*)=(.*?)>#is', '&lt;\\1\\2on\\3=\\4&gt;', $message);
+    }
+    return $message;
+  }
+  
+  function strip_php($message)
+  {
+    return RenderMan::destroy_javascript($message, true);
+  }
+  
+  function sanitize_html($text)
+  {
+    $text = htmlspecialchars($text);
+    $allowed_tags = Array('b', 'i', 'u', 'pre', 'code', 'tt', 'br', 'p', 'nowiki', '!--([^.]+)--');
+    foreach($allowed_tags as $t)
+    {
+      $text = preg_replace('#&lt;'.$t.'&gt;(.*?)&lt;/'.$t.'&gt;#is', '<'.$t.'>\\1</'.$t.'>', $text);
+      $text = preg_replace('#&lt;'.$t.' /&gt;#is', '<'.$t.' />', $text);
+      $text = preg_replace('#&lt;'.$t.'&gt;#is', '<'.$t.'>', $text);
+    }
+    return $text;
+  }
+  
+  /* *
+   * Replaces template inclusions with the templates
+   * @param string $message The text to format
+   * @return string
+   * /
+   
+  function old_include_templates($message)
+  {
+    $random_id = md5( time() . mt_rand() );
+    preg_match_all('#\{\{(.+?)\}\}#s', $message, $matchlist);
+    foreach($matchlist[1] as $m)
+    {
+      $mn = $m;
+      // Strip out wikilinks and re-add them after the explosion (because of the "|")
+      preg_match_all('#\[\[(.+?)\]\]#i', $m, $linklist);
+      //echo '<pre>'.print_r($linklist, true).'</pre>';
+      for($i=0;$i<sizeof($linklist[1]);$i++)
+      {
+        $mn = str_replace('[['.$linklist[1][$i].']]', '{WIKILINK:'.$random_id.':'.$i.'}', $mn);
+      }
+      
+      $ar = explode('|', $mn);
+      
+      for($j=0;$j<sizeof($ar);$j++)
+      {
+        for($i=0;$i<sizeof($linklist[1]);$i++)
+        {
+          $ar[$j] = str_replace('{WIKILINK:'.$random_id.':'.$i.'}', '[['.$linklist[1][$i].']]', $ar[$j]);
+        }
+      }
+      
+      $tp = $ar[0];
+      unset($ar[0]);
+      $tp = str_replace(' ', '_', $tp);
+      $message = str_replace('{{'.$m.'}}', RenderMan::getTemplate($tp, $ar), $message);
+    }
+    return $message;
+  }
+  */
+  
+  /**
+   * Parses a partial template tag in wikitext, and return an array with the parameters.
+   * @param string The portion of the template tag that contains the parameters. Example:
+   * <code>
+   * foo = lorem ipsum
+   * bar = dolor sit amet
+   * </code>
+   * @return array Example:
+   * [foo] => lorem ipsum
+   * [bar] => dolor sit amet
+   */
+  
+  function parse_template_vars($input)
+  {
+    $input = explode("\n", trim( $input ));
+    $parms = Array();
+    $current_line = '';
+    $current_parm = '';
+    foreach ( $input as $num => $line )
+    {
+      if ( preg_match('/^([ ]*?)([A-z0-9_]+?)([ ]*?)=([ ]*?)(.+?)$/i', $line, $matches) )
+      {
+        $parm =& $matches[2];
+        $text =& $matches[5];
+        if ( $parm == $current_parm )
+        {
+          $current_line .= $text;
+        }
+        else
+        {
+          // New parameter
+          if ( $current_parm != '' )
+            $parms[$current_parm] = $current_line;
+          $current_line = $text;
+          $current_parm = $parm;
+        }
+      }
+      else if ( $num == 0 )
+      {
+        // Syntax error
+        return false;
+      }
+      else
+      {
+        $current_line .= "\n$line";
+      }
+    }
+    if ( !empty($current_parm) && !empty($current_line) )
+    {
+      $parms[$current_parm] = $current_line;
+    }
+    return $parms;
+  }
+  
+  /**
+   * Processes all template tags within a block of wikitext.
+   * @param string The text to process
+   * @return string Formatted text
+   * @example
+   * <code>
+   $text = '{{Template
+     parm1 = Foo
+     parm2 = Bar
+     }}';
+   $text = include_templates($text);
+   * </code>
+   */
+  
+  function include_templates($text)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $template_regex = "/\{\{([A-z0-9_-]+?)((\n([ ]*?)[A-z0-9]+([ ]*?)=([ ]*?)(.+?))*)\}\}/is";
+    if ( $count = preg_match_all($template_regex, $text, $matches) )
+    {
+      for ( $i = 0; $i < $count; $i++ )
+      {
+        $parmsection = trim($matches[2][$i]);
+        if ( !empty($parmsection) )
+        {
+          $parms = parse_template_vars($parmsection);
+          foreach ( $parms as $j => $parm )
+          {
+            $parms[$j] = $parm;
+          }
+        }
+        else
+        {
+          $parms = Array();
+        }
+        if ( $tpl_code = RenderMan::fetch_template_text($matches[1][$i]) )
+        {
+          $parser = $template->makeParserText($tpl_code);
+          $parser->assign_vars($parms);
+          $text = str_replace($matches[0][$i], $parser->run(), $text);
+        }
+      }
+    }
+    return $text;
+  }
+  
+  /**
+   * Preprocesses an HTML text string prior to being sent to MySQL.
+   * @param string $text
+   * @param bool $strip_all_php - if true, strips all PHP regardless of user permissions. Else, strips PHP only if user level < USER_LEVEL_ADMIN.
+   */
+  function preprocess_text($text, $strip_all_php = true, $sqlescape = true)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $random_id = md5( time() . mt_rand() );
+    
+    $can_do_php = ( $session->get_permissions('php_in_pages') && !$strip_all_php );
+    
+    $text = sanitize_html($text, ( !$can_do_php ));
+    
+    if ( !$can_do_php )
+    {
+      // If we can't do PHP, we can't do Javascript either.
+      $text = RenderMan::destroy_javascript($text);
+    }
+    
+    // Strip out <nowiki> sections and PHP code
+    
+    $php = preg_match_all('#(<|&lt;)\?php(.*?)\?(>|&gt;)#is', $text, $phpsec);
+    
+    //die('<pre>'.htmlspecialchars(print_r($phpsec, true))."\n".htmlspecialchars(print_r($text, true)).'</pre>');
+    
+    for($i=0;$i<sizeof($phpsec[1]);$i++)
+    {
+      $text = str_replace($phpsec[0][$i], '{PHP:'.$random_id.':'.$i.'}', $text);
+    }
+    
+    $nw = preg_match_all('#<nowiki>(.*?)<\/nowiki>#is', $text, $nowiki);
+    
+    for($i=0;$i<sizeof($nowiki[1]);$i++)
+    {
+      $text = str_replace('<nowiki>'.$nowiki[1][$i].'</nowiki>', '{NOWIKI:'.$random_id.':'.$i.'}', $text);
+    }
+    
+    $text = str_replace('~~~~~', date('G:i, j F Y (T)'), $text);
+    $text = str_replace('~~~~', "[[User:$session->username|$session->username]] ".date('G:i, j F Y (T)'), $text);
+    $text = str_replace('~~~', "[[User:$session->username|$session->username]] ", $text);
+    
+    // Reinsert <nowiki> sections
+    for($i=0;$i<$nw;$i++)
+    {
+      $text = str_replace('{NOWIKI:'.$random_id.':'.$i.'}', '<nowiki>'.$nowiki[1][$i].'</nowiki>', $text);
+    }
+    // Reinsert PHP
+    for($i=0;$i<$php;$i++)
+    {
+      $phsec = ''.$phpsec[1][$i].'?php'.$phpsec[2][$i].'?'.$phpsec[3][$i].'';
+      if ( $strip_all_php )
+        $phsec = htmlspecialchars($phsec);
+      $text = str_replace('{PHP:'.$random_id.':'.$i.'}', $phsec, $text);
+    }
+    
+    $text = ( $sqlescape ) ? $db->escape($text) : $text;
+    
+    return $text;
+  }
+  
+  function smilieyize($text, $complete_urls = false)
+  {
+    
+    $random_id = md5( time() . mt_rand() );
+    
+    // Smileys array - eventually this will be fetched from the database by
+    // RenderMan::initSmileys during initialization, but it will all be hardcoded for beta 2
+    
+    $smileys = Array(
+      'O:-)'    => 'face-angel.png',
+      'O:)'     => 'face-angel.png',
+      'O=)'     => 'face-angel.png',
+      ':-)'     => 'face-smile.png',
+      ':)'      => 'face-smile.png',
+      '=)'      => 'face-smile-big.png',
+      ':-('     => 'face-sad.png',
+      ':('      => 'face-sad.png',
+      ';('      => 'face-sad.png',
+      ':-O'     => 'face-surprise.png',
+      ';-)'     => 'face-wink.png',
+      ';)'      => 'face-wink.png',
+      '8-)'     => 'face-glasses.png',
+      '8)'      => 'face-glasses.png',
+      ':-D'     => 'face-grin.png',
+      ':D'      => 'face-grin.png',
+      '=D'      => 'face-grin.png',
+      ':-*'     => 'face-kiss.png',
+      ':*'      => 'face-kiss.png',
+      '=*'      => 'face-kiss.png',
+      ':\'('    => 'face-crying.png',
+      ':-|'     => 'face-plain.png',
+      ':-\\'    => 'face-plain.png',
+      ':-/'     => 'face-plain.png',
+      ':joke:'  => 'face-plain.png',
+      ']:-&gt;' => 'face-devil-grin.png',
+      ':kiss:'  => 'face-kiss.png',
+      ':-P'     => 'face-tongue-out.png',
+      ':P'      => 'face-tongue-out.png',
+      ':-p'     => 'face-tongue-out.png',
+      ':p'      => 'face-tongue-out.png',
+      ':-X'     => 'face-sick.png',
+      ':X'      => 'face-sick.png',
+      ':sick:'  => 'face-sick.png',
+      ':-]'     => 'face-oops.png',
+      ':]'      => 'face-oops.png',
+      ':oops:'  => 'face-oops.png',
+      ':-['     => 'face-embarassed.png',
+      ':['      => 'face-embarassed.png'
+      );
+    /*
+    $keys = array_keys($smileys);
+    foreach($keys as $k)
+    {
+      $regex1 = '#([\W]+)'.preg_quote($k).'([\s\n\r\.]+)#s';
+      $regex2 = '\\1<img alt="'.$k.'" title="'.$k.'" src="'.scriptPath.'/images/smilies/'.$smileys[$k].'" style="border: 0;" />\\2';
+      $text = preg_replace($regex1, $regex2, $text);
+    }                                                                      
+    */
+    
+    // Strip out <nowiki> sections
+    //return '<pre>'.htmlspecialchars($text).'</pre>';
+    $nw = preg_match_all('#<nowiki>(.*?)<\/nowiki>#is', $text, $nowiki);
+    
+    for($i=0;$i<sizeof($nowiki[1]);$i++)
+    {
+      $text = str_replace('<nowiki>'.$nowiki[1][$i].'</nowiki>', '{NOWIKI:'.$random_id.':'.$i.'}', $text);
+    }
+    
+    $keys = array_keys($smileys);
+    foreach($keys as $k)
+    {
+      $t = str_hex($k);
+      $t = explode(' ', $t);
+      $s = '';
+      foreach($t as $b)
+      {
+        $s.='&#x'.$b.';';
+      }
+      $pfx = ( $complete_urls ) ? 'http' . ( isset($_SERVER['HTTPS']) ? 's' : '' ) . '://'.$_SERVER['HTTP_HOST'] : '';
+      $text = str_replace(' '.$k, ' <nowiki><img title="'.$s.'" alt="'.$s.'" src="'.$pfx.scriptPath.'/images/smilies/'.$smileys[$k].'" style="border: 0;" /></nowiki>', $text);
+    }
+    //*/
+    
+    // Reinsert <nowiki> sections
+    for($i=0;$i<$nw;$i++)
+    {
+      $text = str_replace('{NOWIKI:'.$random_id.':'.$i.'}', '<nowiki>'.$nowiki[1][$i].'</nowiki>', $text);
+    }
+    
+    return $text;
+  }
+  
+  /*
+   * **** DEPRECATED ****
+   * Replaces some critical characters in a string with MySQL-safe equivalents
+   * @param $text string the text to escape
+   * @return array key 0 is the escaped text, key 1 is the character tag
+   * /
+   
+  function escape_page_text($text)
+  {
+    $char_tag = md5(microtime() . mt_rand());
+    $text = str_replace("'",  "{APOS:$char_tag}",  $text);
+    $text = str_replace('"',  "{QUOT:$char_tag}",  $text);
+    $text = str_replace("\\", "{SLASH:$char_tag}", $text);
+    return Array($text, $char_tag);
+  }
+  */
+  
+  /* **** DEPRECATED ****
+   * Reverses the result of RenderMan::escape_page_text().
+   * @param $text string the text to unescape
+   * @param $char_tag string the character tag
+   * @return string
+   * /
+   
+  function unescape_page_text($text, $char_tag)
+  {
+    $text = str_replace("{APOS:$char_tag}",  "'",  $text);
+    $text = str_replace("{QUOT:$char_tag}",  '"',  $text);
+    $text = str_replace("{SLASH:$char_tag}", "\\", $text);
+    return $text;
+  }
+  */
+  
+  /**
+   * Generates a summary of the differences between two texts, and formats it as XHTML.
+   * @param $str1 string the first block of text
+   * @param $str2 string the second block of text
+   * @return string
+   */
+  function diff($str1, $str2)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $str1 = explode("\n", $str1);
+    $str2 = explode("\n", $str2);
+    $diff = new Diff($str1, $str2);
+    $renderer = new TableDiffFormatter();
+    return '<table class="diff">'.$renderer->format($diff).'</table>';
+  }
+  
+}
+ 
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/rijndael.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1052 @@
+<?php
+
+/**
+ * Phijndael - an implementation of the AES encryption standard in PHP
+ * Originally written by Fritz Schneider <fritz AT cd DOT ucsd DOT edu>
+ * Ported to PHP by Dan Fuhry <dan AT enano DOT homelinux DOT org>
+ * @package phijndael
+ * @author Fritz Schneider
+ * @author Dan Fuhry
+ * @license BSD-style license
+ */
+
+error_reporting(E_ALL);
+
+define ('ENC_HEX', 201);
+define ('ENC_BASE64', 202);
+define ('ENC_BINARY', 203);
+
+class AESCrypt {
+  
+  var $debug = false;
+  var $mcrypt = false;
+
+  // Rijndael parameters --  Valid values are 128, 192, or 256
+  
+  var $keySizeInBits = 128;
+  var $blockSizeInBits = 128;
+  
+  ///////  You shouldn't have to modify anything below this line except for
+  ///////  the function getRandomBytes().
+  //
+  // Note: in the following code the two dimensional arrays are indexed as
+  //       you would probably expect, as array[row][column]. The state arrays
+  //       are 2d arrays of the form state[4][Nb].
+  
+  
+  // The number of rounds for the cipher, indexed by [Nk][Nb]
+  var $roundsArray = Array(0,0,0,0,Array(0,0,0,0,10,0, 12,0, 14),0, 
+                               Array(0,0,0,0,12,0, 12,0, 14),0, 
+                               Array(0,0,0,0,14,0, 14,0, 14) );
+  
+  // The number of bytes to shift by in shiftRow, indexed by [Nb][row]
+  var $shiftOffsets = Array(0,0,0,0,Array(0,1, 2, 3),0,Array(0,1, 2, 3),0,Array(0,1, 3, 4) );
+  
+  // The round constants used in subkey expansion
+  var $Rcon = Array( 
+  0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 
+  0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 
+  0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 
+  0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 
+  0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 );
+  
+  // Precomputed lookup table for the SBox
+  var $SBox = Array(
+   99, 124, 119, 123, 242, 107, 111, 197,  48,   1, 103,  43, 254, 215, 171, 
+  118, 202, 130, 201, 125, 250,  89,  71, 240, 173, 212, 162, 175, 156, 164, 
+  114, 192, 183, 253, 147,  38,  54,  63, 247, 204,  52, 165, 229, 241, 113, 
+  216,  49,  21,   4, 199,  35, 195,  24, 150,   5, 154,   7,  18, 128, 226, 
+  235,  39, 178, 117,   9, 131,  44,  26,  27, 110,  90, 160,  82,  59, 214, 
+  179,  41, 227,  47, 132,  83, 209,   0, 237,  32, 252, 177,  91, 106, 203, 
+  190,  57,  74,  76,  88, 207, 208, 239, 170, 251,  67,  77,  51, 133,  69, 
+  249,   2, 127,  80,  60, 159, 168,  81, 163,  64, 143, 146, 157,  56, 245, 
+  188, 182, 218,  33,  16, 255, 243, 210, 205,  12,  19, 236,  95, 151,  68,  
+  23,  196, 167, 126,  61, 100,  93,  25, 115,  96, 129,  79, 220,  34,  42, 
+  144, 136,  70, 238, 184,  20, 222,  94,  11, 219, 224,  50,  58,  10,  73,
+    6,  36,  92, 194, 211, 172,  98, 145, 149, 228, 121, 231, 200,  55, 109, 
+  141, 213,  78, 169, 108,  86, 244, 234, 101, 122, 174,   8, 186, 120,  37,  
+   46,  28, 166, 180, 198, 232, 221, 116,  31,  75, 189, 139, 138, 112,  62, 
+  181, 102,  72,   3, 246,  14,  97,  53,  87, 185, 134, 193,  29, 158, 225,
+  248, 152,  17, 105, 217, 142, 148, 155,  30, 135, 233, 206,  85,  40, 223,
+  140, 161, 137,  13, 191, 230,  66, 104,  65, 153,  45,  15, 176,  84, 187,  
+   22 );
+  
+  // Precomputed lookup table for the inverse SBox
+  var $SBoxInverse = Array(
+   82,   9, 106, 213,  48,  54, 165,  56, 191,  64, 163, 158, 129, 243, 215, 
+  251, 124, 227,  57, 130, 155,  47, 255, 135,  52, 142,  67,  68, 196, 222, 
+  233, 203,  84, 123, 148,  50, 166, 194,  35,  61, 238,  76, 149,  11,  66, 
+  250, 195,  78,   8,  46, 161, 102,  40, 217,  36, 178, 118,  91, 162,  73, 
+  109, 139, 209,  37, 114, 248, 246, 100, 134, 104, 152,  22, 212, 164,  92, 
+  204,  93, 101, 182, 146, 108, 112,  72,  80, 253, 237, 185, 218,  94,  21,  
+   70,  87, 167, 141, 157, 132, 144, 216, 171,   0, 140, 188, 211,  10, 247, 
+  228,  88,   5, 184, 179,  69,   6, 208,  44,  30, 143, 202,  63,  15,   2, 
+  193, 175, 189,   3,   1,  19, 138, 107,  58, 145,  17,  65,  79, 103, 220, 
+  234, 151, 242, 207, 206, 240, 180, 230, 115, 150, 172, 116,  34, 231, 173,
+   53, 133, 226, 249,  55, 232,  28, 117, 223, 110,  71, 241,  26, 113,  29, 
+   41, 197, 137, 111, 183,  98,  14, 170,  24, 190,  27, 252,  86,  62,  75, 
+  198, 210, 121,  32, 154, 219, 192, 254, 120, 205,  90, 244,  31, 221, 168,
+   51, 136,   7, 199,  49, 177,  18,  16,  89,  39, 128, 236,  95,  96,  81,
+  127, 169,  25, 181,  74,  13,  45, 229, 122, 159, 147, 201, 156, 239, 160,
+  224,  59,  77, 174,  42, 245, 176, 200, 235, 187,  60, 131,  83, 153,  97, 
+   23,  43,   4, 126, 186, 119, 214,  38, 225, 105,  20,  99,  85,  33,  12,
+  125 );
+  
+  function AESCrypt($ks = 128, $bs = 128, $debug = false)
+  {
+    $this->__construct($ks, $bs, $debug);
+  }
+  
+  function __construct($ks = 128, $bs = 128, $debug = false)
+  {
+    $this->keySizeInBits = $ks;
+    $this->blockSizeInBits = $bs;
+    
+    // Use the Mcrypt library? This speeds things up dramatically.
+    if(defined('MCRYPT_RIJNDAEL_' . $ks) && defined('MCRYPT_ACCEL'))
+    {
+      eval('$mcb = MCRYPT_RIJNDAEL_' . $ks.';');
+      $bks = mcrypt_module_get_algo_block_size($mcb);
+      $bks = $bks * 8;
+      if ( $bks != $bs )
+      {
+        $mcb = false;
+        echo (string)$bks;
+      }
+    }
+    else
+    {
+      $mcb = false;
+    }
+      
+    $this->mcrypt = $mcb;
+    
+    // Cipher parameters ... do not change these
+    $this->Nk = $this->keySizeInBits / 32;
+    $this->Nb = $this->blockSizeInBits / 32;
+    $this->Nr = $this->roundsArray[$this->Nk][$this->Nb];
+    $this->debug = $debug;
+  }
+  
+  // Error handler
+  
+  function trigger_error($text, $level = E_USER_NOTICE)
+  {
+    $bt = debug_backtrace();
+    $lastfunc =& $bt[1];
+    switch($level)
+    {
+      case E_USER_NOTICE:
+      default:
+        $desc = 'Notice';
+        break;
+      case E_USER_WARNING:
+        $desc = 'Warning';
+        break;
+      case E_USER_ERROR:
+        $desc = 'Fatal';
+        break;
+    }
+    ob_start();
+    if($this->debug || $level == E_USER_ERROR) echo "AES encryption: <b>{$desc}:</b> $text in {$lastfunc['file']} on line {$lastfunc['line']} in function {$lastfunc['function']}<br />";
+    if($this->debug)
+    {
+      //echo '<pre>'.enano_debug_print_backtrace(true).'</pre>';
+    }
+    ob_end_flush();
+    if($level == E_USER_ERROR)
+    {
+      echo '<p><b>This can sometimes happen if you are upgrading Enano to a new version and did not log out first.</b> <a href="'.$_SERVER['PHP_SELF'].'?do=diag&amp;sub=cookie_destroy">Click here</a> to force cookies to clear and try again. You will be logged out.</p>';
+      exit;
+    }
+  }
+  
+  function array_slice_js_compat($array, $start, $finish = 0)
+  {
+    $len = $finish - $start;
+    if($len < 0) $len = 0 - $len;
+    //if($this->debug) echo (string)$len . ' ';
+    //if(count($array) < $start + $len)
+    //  $this->trigger_error('Index out of range', E_USER_WARNING);
+    return array_slice($array, $start, $len);
+  }
+  
+  function concat($s1, $s2)
+  {
+    if(is_array($s1) && is_array($s2))
+      return array_merge($s1, $s2);
+    elseif( ( is_array($s1) && !is_array($s2) ) || ( !is_array($s1) && is_array($s2) ) )
+    {
+      $this->trigger_error('incompatible types - you can\'t combine a non-array with an array', E_USER_WARNING);
+      return false;
+    }
+    else
+      return $s1 . $s2;
+  }
+  
+  // This method circularly shifts the array left by the number of elements
+  // given in its parameter. It returns the resulting array and is used for 
+  // the ShiftRow step. Note that shift() and push() could be used for a more 
+  // elegant solution, but they require IE5.5+, so I chose to do it manually. 
+  
+  function cyclicShiftLeft($theArray, $positions) {
+    if(!is_int($positions))
+    {
+      $this->trigger_error('$positions is not an integer! Backtrace:<br /><pre>'.print_r(debug_backtrace(), true).'</pre>', E_USER_WARNING);
+      return false;
+    }
+    $second = array_slice($theArray, 0, $positions);
+    $first = array_slice($theArray, $positions);
+    $theArray = array_merge($first, $second);
+    return $theArray;
+  }
+  
+  // Multiplies the element "poly" of GF(2^8) by x. See the Rijndael spec.
+  
+  function xtime($poly) {
+    $poly <<= 1;
+    return (($poly & 0x100) ? ($poly ^ 0x11B) : ($poly));
+  }
+  
+  // Multiplies the two elements of GF(2^8) together and returns the result.
+  // See the Rijndael spec, but should be straightforward: for each power of
+  // the indeterminant that has a 1 coefficient in x, add y times that power
+  // to the result. x and y should be bytes representing elements of GF(2^8)
+  
+  function mult_GF256($x, $y) {
+    $result = 0;
+    
+    for ($bit = 1; $bit < 256; $bit *= 2, $y = $this->xtime($y)) {
+      if ($x & $bit) 
+        $result ^= $y;
+    }
+    return $result;
+  }
+  
+  // Performs the substitution step of the cipher. State is the 2d array of
+  // state information (see spec) and direction is string indicating whether
+  // we are performing the forward substitution ("encrypt") or inverse 
+  // substitution (anything else)
+  
+  function byteSub(&$state, $direction) {
+    //global $this->SBox, $this->SBoxInverse, $this->Nb;
+    if ($direction == "encrypt")           // Point S to the SBox we're using
+      $S =& $this->SBox;
+    else
+      $S =& $this->SBoxInverse;
+    for ($i = 0; $i < 4; $i++)           // Substitute for every byte in state
+      for ($j = 0; $j < $this->Nb; $j++)
+         $state[$i][$j] = $S[$state[$i][$j]];
+  }
+  
+  // Performs the row shifting step of the cipher.
+  
+  function shiftRow(&$state, $direction) {
+    //global $this->Nb, $this->shiftOffsets;
+    for ($i=1; $i<4; $i++)               // Row 0 never shifts
+      if ($direction == "encrypt")
+         $state[$i] = $this->cyclicShiftLeft($state[$i], $this->shiftOffsets[$this->Nb][$i]);
+      else
+         $state[$i] = $this->cyclicShiftLeft($state[$i], $this->Nb - $this->shiftOffsets[$this->Nb][$i]);
+  
+  }
+  
+  // Performs the column mixing step of the cipher. Most of these steps can
+  // be combined into table lookups on 32bit values (at least for encryption)
+  // to greatly increase the speed. 
+  
+  function mixColumn(&$state, $direction) {
+    //global $this->Nb;
+    $b = Array();                                  // Result of matrix multiplications
+    for ($j = 0; $j < $this->Nb; $j++) {                 // Go through each column...
+      for ($i = 0; $i < 4; $i++) {                 // and for each row in the column...
+        if ($direction == "encrypt")
+          $b[$i] = $this->mult_GF256($state[$i][$j], 2) ^ // perform mixing
+                   $this->mult_GF256($state[($i+1)%4][$j], 3) ^ 
+                   $state[($i+2)%4][$j] ^ 
+                   $state[($i+3)%4][$j];
+        else 
+          $b[$i] = $this->mult_GF256($state[$i][$j], 0xE) ^ 
+                   $this->mult_GF256($state[($i+1)%4][$j], 0xB) ^
+                   $this->mult_GF256($state[($i+2)%4][$j], 0xD) ^
+                   $this->mult_GF256($state[($i+3)%4][$j], 9);
+      }
+      for ($i = 0; $i < 4; $i++)          // Place result back into column
+        $state[$i][$j] = $b[$i];
+    }
+  }
+  
+  // Adds the current round key to the state information. Straightforward.
+  
+  function addRoundKey(&$state, $roundKey) {
+    //global $this->Nb;
+    for ($j = 0; $j < $this->Nb; $j++) {                      // Step through columns...
+      $state[0][$j] ^= ( $roundKey[$j] & 0xFF);         // and XOR
+      $state[1][$j] ^= (($roundKey[$j]>>8) & 0xFF);
+      $state[2][$j] ^= (($roundKey[$j]>>16) & 0xFF);
+      $state[3][$j] ^= (($roundKey[$j]>>24) & 0xFF);
+    }
+  }
+  
+  // This function creates the expanded key from the input (128/192/256-bit)
+  // key. The parameter key is an array of bytes holding the value of the key.
+  // The returned value is an array whose elements are the 32-bit words that 
+  // make up the expanded key.
+  
+  function keyExpansion($key) {
+    //global $this->keySizeInBits, $this->blockSizeInBits, $this->roundsArray, $this->Nk, $this->Nb, $this->Nr, $this->Nk, $this->SBox, $this->Rcon;
+    $expandedKey = Array();
+  
+    // in case the key size or parameters were changed...
+    $this->Nk = $this->keySizeInBits / 32;                   
+    $this->Nb = $this->blockSizeInBits / 32;
+    $this->Nr = $this->roundsArray[$this->Nk][$this->Nb];
+  
+    for ($j=0; $j < $this->Nk; $j++)     // Fill in input key first
+      $expandedKey[$j] = 
+        ($key[4*$j]) | ($key[4*$j+1]<<8) | ($key[4*$j+2]<<16) | ($key[4*$j+3]<<24);
+  
+    // Now walk down the rest of the array filling in expanded key bytes as
+    // per Rijndael's spec
+    for ($j = $this->Nk; $j < $this->Nb * ($this->Nr + 1); $j++) {    // For each word of expanded key
+      $temp = $expandedKey[$j - 1];
+      if ($j % $this->Nk == 0) 
+        $temp = ( ($this->SBox[($temp>>8) & 0xFF]) |
+                  ($this->SBox[($temp>>16) & 0xFF]<<8) |
+                  ($this->SBox[($temp>>24) & 0xFF]<<16) |
+                  ($this->SBox[$temp & 0xFF]<<24) ) ^ $this->Rcon[floor($j / $this->Nk) - 1];
+      elseif  ($this->Nk > 6 && $j % $this->Nk == 4)
+        $temp = ($this->SBox[($temp>>24) & 0xFF]<<24) |
+               ($this->SBox[($temp>>16) & 0xFF]<<16) |
+               ($this->SBox[($temp>>8) & 0xFF]<<8) |
+               ($this->SBox[ $temp & 0xFF]);
+      $expandedKey[$j] = $expandedKey[$j-$this->Nk] ^ $temp;
+    }
+    return $expandedKey;
+  }
+  
+  // Rijndael's round functions... 
+  
+  function RijndaelRound(&$state, $roundKey) {
+    $this->byteSub($state, "encrypt");
+    $this->shiftRow($state, "encrypt");
+    $this->mixColumn($state, "encrypt");
+    $this->addRoundKey($state, $roundKey);
+  }
+  
+  function InverseRijndaelRound(&$state, $roundKey) {
+    $this->addRoundKey($state, $roundKey);
+    $this->mixColumn($state, "decrypt");
+    $this->shiftRow($state, "decrypt");
+    $this->byteSub($state, "decrypt");
+  }
+  
+  function FinalRijndaelRound(&$state, $roundKey) {
+    $this->byteSub($state, "encrypt");
+    $this->shiftRow($state, "encrypt");
+    $this->addRoundKey($state, $roundKey);
+  }
+  
+  function InverseFinalRijndaelRound(&$state, $roundKey){
+    $this->addRoundKey($state, $roundKey);
+    $this->shiftRow($state, "decrypt");
+    $this->byteSub($state, "decrypt");  
+  }
+  
+  // encrypt is the basic encryption function. It takes parameters
+  // block, an array of bytes representing a plaintext block, and expandedKey,
+  // an array of words representing the expanded key previously returned by
+  // keyExpansion(). The ciphertext block is returned as an array of bytes.
+  
+  function cryptBlock($block, $expandedKey) {
+    //global $this->blockSizeInBits, $this->Nb, $this->Nr;
+    $t=count($block)*8;
+    if (!is_array($block) || count($block)*8 != $this->blockSizeInBits)
+    {
+      $this->trigger_error('block is bad or block size is wrong<pre>'.print_r($block, true).'</pre><p>Aiming for size '.$this->blockSizeInBits.', got '.$t.'.', E_USER_WARNING); 
+      return false;
+    }
+    if (!$expandedKey)
+      return;
+  
+    $block = $this->packBytes($block);
+    $this->addRoundKey($block, $expandedKey);
+    for ($i=1; $i<$this->Nr; $i++) 
+      $this->RijndaelRound($block, $this->array_slice_js_compat($expandedKey, $this->Nb*$i, $this->Nb*($i+1)));
+    $this->FinalRijndaelRound($block, $this->array_slice_js_compat($expandedKey, $this->Nb*$this->Nr));
+    $ret = $this->unpackBytes($block);
+    return $ret;
+  }
+  
+  // decrypt is the basic decryption function. It takes parameters
+  // block, an array of bytes representing a ciphertext block, and expandedKey,
+  // an array of words representing the expanded key previously returned by
+  // keyExpansion(). The decrypted block is returned as an array of bytes.
+  
+  function unCryptBlock($block, $expandedKey) {
+    $t = count($block)*8;
+    if (!is_array($block) || count($block)*8 != $this->blockSizeInBits)
+    {
+      $this->trigger_error('$block is not a valid rijndael-block array: '.$this->byteArrayToHex($block).'<pre>'.print_r($block, true).'</pre><p>Block size is '.$t.', should be '.$this->blockSizeInBits.'</p>', E_USER_WARNING);
+      return false;
+    }
+    if (!$expandedKey)
+    {
+      $this->trigger_error('$expandedKey is invalid', E_USER_WARNING);
+      return false;
+    }
+  
+    $block = $this->packBytes($block);
+    $this->InverseFinalRijndaelRound($block, $this->array_slice_js_compat($expandedKey, $this->Nb*$this->Nr)); 
+    for ($i = $this->Nr - 1; $i>0; $i--) 
+    {
+      $this->InverseRijndaelRound($block, $this->array_slice_js_compat($expandedKey, $this->Nb*$i, $this->Nb*($i+1)));
+    }
+    $this->addRoundKey($block, $expandedKey);
+    $ret = $this->unpackBytes($block);
+    if(!is_array($ret))
+    {
+      $this->trigger_error('$ret is not an array', E_USER_WARNING);
+    }
+    return $ret;
+  }
+  
+  // This method takes a byte array (byteArray) and converts it to a string by
+  // applying String.fromCharCode() to each value and concatenating the result.
+  // The resulting string is returned. Note that this function SKIPS zero bytes
+  // under the assumption that they are padding added in formatPlaintext().
+  // Obviously, do not invoke this method on raw data that can contain zero
+  // bytes. It is really only appropriate for printable ASCII/Latin-1 
+  // values. Roll your own function for more robust functionality :)
+  
+  function byteArrayToString($byteArray) {
+    $result = "";
+    for($i=0; $i<count($byteArray); $i++)
+      if ($byteArray[$i] != 0) 
+        $result .= chr($byteArray[$i]);
+    return $result;
+  }
+  
+  // This function takes an array of bytes (byteArray) and converts them
+  // to a hexadecimal string. Array element 0 is found at the beginning of 
+  // the resulting string, high nibble first. Consecutive elements follow
+  // similarly, for example [16, 255] --> "10ff". The function returns a 
+  // string.
+  
+  /*
+  function byteArrayToHex($byteArray) {
+    $result = "";
+    if (!$byteArray)
+      return;
+    for ($i=0; $i<count($byteArray); $i++)
+      $result .= (($byteArray[$i]<16) ? "0" : "") + toString($byteArray[$i]); // magic number here is 16, not sure how to handle this...
+  
+    return $result;
+  }
+  */
+  function byteArrayToHex($arr)
+  {
+    $ret = '';
+    foreach($arr as $a)
+    {
+      $nibble = (string)dechex(intval($a));
+      if(strlen($nibble) == 1) $nibble = '0' . $nibble;
+      $ret .= $nibble;
+    }
+    return $ret;
+  }
+  
+  // PHP equivalent of Javascript's toString()
+  function toString($bool)
+  {
+    if(is_bool($bool))
+      return ($bool) ? 'true' : 'false';
+    elseif(is_array($bool))
+      return implode(',', $bool);
+    else
+      return (string)$bool;
+  }
+  
+  // This function converts a string containing hexadecimal digits to an 
+  // array of bytes. The resulting byte array is filled in the order the
+  // values occur in the string, for example "10FF" --> [16, 255]. This
+  // function returns an array. 
+  
+  /*
+  function hexToByteArray($hexString) {
+    $byteArray = Array();
+    if (strlen($hexString) % 2)             // must have even length
+      return;
+    if (strstr($hexString, "0x") == $hexString || strstr($hexString, "0X") == $hexString)
+      $hexString = substr($hexString, 2);
+    for ($i = 0; $i<strlen($hexString); $i++,$i++) 
+      $byteArray[floor($i/2)] = intval(substr($hexString, $i, 2)); // again, that strange magic number: 16
+    return $byteArray;
+  }
+  */
+  function hexToByteArray($str)
+  {
+    if(substr($str, 0, 2) == '0x' || substr($str, 0, 2) == '0X')
+      $str = substr($str, 2);
+    $arr = Array();
+    $str = $this->enano_str_split($str, 2);
+    foreach($str as $s)
+    {
+      $arr[] = intval(hexdec($s));
+    }
+    return $arr;
+  }
+  
+  // This function packs an array of bytes into the four row form defined by
+  // Rijndael. It assumes the length of the array of bytes is divisible by
+  // four. Bytes are filled in according to the Rijndael spec (starting with
+  // column 0, row 0 to 3). This function returns a 2d array.
+  
+  function packBytes($octets) {
+    $state = Array();
+    if (!$octets || count($octets) % 4)
+      return;
+  
+    $state[0] = Array(); $state[1] = Array(); 
+    $state[2] = Array(); $state[3] = Array();
+    for ($j=0; $j<count($octets); $j = $j+4) {
+       $state[0][$j/4] = $octets[$j];
+       $state[1][$j/4] = $octets[$j+1];
+       $state[2][$j/4] = $octets[$j+2];
+       $state[3][$j/4] = $octets[$j+3];
+    }
+    return $state;
+  }
+  
+  // This function unpacks an array of bytes from the four row format preferred
+  // by Rijndael into a single 1d array of bytes. It assumes the input "packed"
+  // is a packed array. Bytes are filled in according to the Rijndael spec. 
+  // This function returns a 1d array of bytes.
+  
+  function unpackBytes($packed) {
+    $result = Array();
+    for ($j=0; $j<count($packed[0]); $j++) {
+      $result[] = $packed[0][$j];
+      $result[] = $packed[1][$j];
+      $result[] = $packed[2][$j];
+      $result[] = $packed[3][$j];
+    }
+    return $result;
+  }
+  
+  function charCodeAt($str, $i)
+  {
+    return ord(substr($str, $i, 1));
+  }
+  
+  function fromCharCode($str)
+  {
+    return chr($str);
+  }
+  
+  // This function takes a prospective plaintext (string or array of bytes)
+  // and pads it with zero bytes if its length is not a multiple of the block 
+  // size. If plaintext is a string, it is converted to an array of bytes
+  // in the process. The type checking can be made much nicer using the 
+  // instanceof operator, but this operator is not available until IE5.0 so I 
+  // chose to use the heuristic below. 
+  
+  function formatPlaintext($plaintext) {
+    //global $this->blockSizeInBits;
+    $bpb = $this->blockSizeInBits / 8;               // bytes per block
+  
+    // if primitive string or String instance
+    if (is_string($plaintext)) {
+      $plaintext = $this->enano_str_split($plaintext);
+      // Unicode issues here (ignoring high byte)
+      for ($i=0; $i<sizeof($plaintext); $i++)
+        $plaintext[$i] = $this->charCodeAt($plaintext[$i], 0) & 0xFF;
+    } 
+  
+    for ($i = $bpb - (sizeof($plaintext) % $bpb); $i > 0 && $i < $bpb; $i--) 
+      $plaintext[] = 0;
+    
+    return $plaintext;
+  }
+  
+  // Returns an array containing "howMany" random bytes. YOU SHOULD CHANGE THIS
+  // TO RETURN HIGHER QUALITY RANDOM BYTES IF YOU ARE USING THIS FOR A "REAL"
+  // APPLICATION. (edit: done, mt_rand() is relatively secure)
+  
+  function getRandomBytes($howMany) {
+    $bytes = Array();
+    for ($i=0; $i<$howMany; $i++)
+      $bytes[$i] = mt_rand(0, 255);
+    return $bytes;
+  }
+  
+  // rijndaelEncrypt(plaintext, key, mode)
+  // Encrypts the plaintext using the given key and in the given mode. 
+  // The parameter "plaintext" can either be a string or an array of bytes. 
+  // The parameter "key" must be an array of key bytes. If you have a hex 
+  // string representing the key, invoke hexToByteArray() on it to convert it 
+  // to an array of bytes. The third parameter "mode" is a string indicating
+  // the encryption mode to use, either "ECB" or "CBC". If the parameter is
+  // omitted, ECB is assumed.
+  // 
+  // An array of bytes representing the cihpertext is returned. To convert 
+  // this array to hex, invoke byteArrayToHex() on it. If you are using this 
+  // "for real" it is a good idea to change the function getRandomBytes() to 
+  // something that returns truly random bits.
+  
+  function rijndaelEncrypt($plaintext, $key, $mode = 'ECB') {
+    //global $this->blockSizeInBits, $this->keySizeInBits;
+    $bpb = $this->blockSizeInBits / 8;          // bytes per block
+    // var ct;                                 // ciphertext
+  
+    if($mode == 'CBC')
+    {
+      if (!is_string($plaintext) || !is_array($key))
+      {
+        $this->trigger_error('In CBC mode the first and second parameters should be strings', E_USER_WARNING);
+        return false;
+      }
+    } else {
+      if (!is_array($plaintext) || !is_array($key))
+      {
+        $this->trigger_error('In ECB mode the first and second parameters should be byte arrays', E_USER_WARNING);
+        return false;
+      }
+    }
+    if (sizeof($key)*8 != $this->keySizeInBits)
+    {
+      $this->trigger_error('The key needs to be '. ( $this->keySizeInBits / 8 ) .' bytes in length', E_USER_WARNING);
+      return false;
+    }
+    if ($mode == "CBC")
+      $ct = $this->getRandomBytes($bpb);             // get IV
+    else {
+      $mode = "ECB";
+      $ct = Array();
+    }
+    
+    // convert plaintext to byte array and pad with zeros if necessary. 
+    $plaintext = $this->formatPlaintext($plaintext);
+    
+    $expandedKey = $this->keyExpansion($key);
+    
+    for ($block=0; $block<sizeof($plaintext) / $bpb; $block++) {
+      $aBlock = $this->array_slice_js_compat($plaintext, $block*$bpb, ($block+1)*$bpb);
+      if ($mode == "CBC")
+      {
+        for ($i=0; $i<$bpb; $i++)
+        {
+          $aBlock[$i] ^= $ct[$block*$bpb + $i];
+        }
+      }
+      $cp = $this->cryptBlock($aBlock, $expandedKey);
+      $ct = $this->concat($ct, $cp);
+    }
+  
+    return $ct;
+  }
+  
+  // rijndaelDecrypt(ciphertext, key, mode)
+  // Decrypts the using the given key and mode. The parameter "ciphertext" 
+  // must be an array of bytes. The parameter "key" must be an array of key 
+  // bytes. If you have a hex string representing the ciphertext or key, 
+  // invoke hexToByteArray() on it to convert it to an array of bytes. The
+  // parameter "mode" is a string, either "CBC" or "ECB".
+  // 
+  // An array of bytes representing the plaintext is returned. To convert 
+  // this array to a hex string, invoke byteArrayToHex() on it. To convert it 
+  // to a string of characters, you can use byteArrayToString().
+  
+  function rijndaelDecrypt($ciphertext, $key, $mode = 'ECB') {
+    //global $this->blockSizeInBits, $this->keySizeInBits;
+    $bpb = $this->blockSizeInBits / 8;          // bytes per block
+    $pt = Array();                   // plaintext array
+    // $aBlock;                             // a decrypted block
+    // $block;                              // current block number
+  
+    if (!$ciphertext)
+    {
+      $this->trigger_error('$ciphertext should be a byte array', E_USER_WARNING);
+      return false;
+    }
+    if(  !is_array($key) )
+    {
+      $this->trigger_error('$key should be a byte array', E_USER_WARNING);
+      return false;
+    }
+    if( is_string($ciphertext) )
+    {
+      $this->trigger_error('$ciphertext should be a byte array', E_USER_WARNING);
+      return false;
+    }
+    if (sizeof($key)*8 != $this->keySizeInBits)
+    {
+      $this->trigger_error('Encryption key is the wrong length', E_USER_WARNING);
+      return false;
+    }
+    if (!$mode)
+      $mode = "ECB";                         // assume ECB if mode omitted
+  
+    $expandedKey = $this->keyExpansion($key);
+   
+    // work backwards to accomodate CBC mode 
+    for ($block=(sizeof($ciphertext) / $bpb)-1; $block>0; $block--)
+    {
+      if( ( $block*$bpb ) + ( ($block+1)*$bpb ) > count($ciphertext) )
+      {
+        //$this->trigger_error('$ciphertext index out of bounds', E_USER_ERROR);
+      }
+      $current_block = $this->array_slice_js_compat($ciphertext, $block*$bpb, ($block+1)*$bpb);
+      if(count($current_block) * 8 != $this->blockSizeInBits)
+      {
+        // $c=count($current_block)*8;
+        // $this->trigger_error('We got a '.$c.'-bit block, instead of '.$this->blockSizeInBits.'', E_USER_ERROR);
+      }
+      $aBlock = $this->uncryptBlock($current_block, $expandedKey);
+      if(!$aBlock)
+      {
+        $this->trigger_error('Shared block decryption routine returned false', E_USER_WARNING);
+        return false;
+      }
+      if ($mode == "CBC")
+        for ($i=0; $i<$bpb; $i++) 
+          $pt[($block-1)*$bpb + $i] = $aBlock[$i] ^ $ciphertext[($block-1)*$bpb + $i];
+      else
+        $pt = $this->concat($aBlock, $pt);
+    }
+  
+    // do last block if ECB (skips the IV in CBC)
+    if ($mode == "ECB")
+    {
+      $x = $this->uncryptBlock($this->array_slice_js_compat($ciphertext, 0, $bpb), $expandedKey);
+      if(!$x)
+      {
+        $this->trigger_error('ECB block decryption routine returned false', E_USER_WARNING);
+        return false;
+      }
+      $pt = $this->concat($x, $pt);
+      if(!$pt)
+      {
+        $this->trigger_error('ECB concatenation routine returned false', E_USER_WARNING);
+        return false;
+      }
+    }
+  
+    return $pt;
+  }
+  
+  /**
+   * Wrapper for encryption.
+   * @param string $text the text to encrypt
+   * @param string $key the raw binary key to encrypt with
+   * @param int $return_encoding optional - can be ENC_BINARY, ENC_HEX or ENC_BASE64
+   */
+   
+  function encrypt($text, $key, $return_encoding = ENC_HEX)
+  {
+    if ( $this->mcrypt && $this->blockSizeInBits == mcrypt_module_get_algo_block_size(eval('return MCRYPT_RIJNDAEL_'.$this->keySizeInBits.';')) )
+    {
+      $iv_size = mcrypt_get_iv_size($this->mcrypt, MCRYPT_MODE_ECB);
+      $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
+      $cryptext = mcrypt_encrypt($this->mcrypt, $key, $text, MCRYPT_MODE_ECB, $iv);
+      switch($return_encoding)
+      {
+        case ENC_HEX:
+        default:
+          $cryptext = $this->strtohex($cryptext);
+          break;
+        case ENC_BINARY:
+          $cryptext = $cryptext;
+          break;
+        case ENC_BASE64:
+          $cryptext = base64_encode($cryptext);
+          break;
+      }
+    }
+    else
+    {
+      $key = $this->prepare_string($key);
+      $text = $this->prepare_string($text);
+      $cryptext = $this->rijndaelEncrypt($text, $key, 'ECB');
+      if(!is_array($cryptext))
+      {
+        echo 'Warning: encryption failed for string: '.$text.'<br />';
+        return false;
+      }
+      switch($return_encoding)
+      {
+        case ENC_HEX:
+        default:
+          $cryptext = $this->byteArrayToHex($cryptext);
+          break;
+        case ENC_BINARY:
+          $cryptext = $this->byteArrayToString($cryptext);
+          break;
+        case ENC_BASE64:
+          $cryptext = base64_encode($this->byteArrayToString($cryptext));
+          break;
+      }
+    }
+    return $cryptext;
+  }
+  
+  /**
+   * Wrapper for decryption.
+   * @param string $text the encrypted text
+   * @param string $key the raw binary key used to encrypt the text
+   * @param int $input_encoding the encoding used for the encrypted string. Can be ENC_BINARY, ENC_HEX, or ENC_BASE64.
+   * @return string
+   */
+   
+  function decrypt($text, $key, $input_encoding = ENC_HEX)
+  {
+    switch($input_encoding)
+    {
+      case ENC_BINARY:
+      default:
+        break;
+      case ENC_HEX:
+        $text = $this->hextostring($text);
+        break;
+      case ENC_BASE64:
+        $text = base64_decode($text);
+        break;
+    }
+    //$mod = strlen($text) % $this->blockSizeInBits;
+    //if($mod != 96)
+      //die('modulus check failed: '.$mod);
+    if ( $this->mcrypt )
+    {
+      $iv_size = mcrypt_get_iv_size($this->mcrypt, MCRYPT_MODE_ECB);
+      $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
+      $dypt = mcrypt_decrypt($this->mcrypt, $key, $text, MCRYPT_MODE_ECB, $iv);
+    }
+    else
+    {
+      $etext = $this->prepare_string($text);
+      $ekey  = $this->prepare_string($key);
+      $mod = count($etext) % $this->blockSizeInBits;
+      $dypt = $this->rijndaelDecrypt($etext, $ekey, 'ECB');
+      if(!$dypt)
+      {
+        echo '<pre>'.print_r($dypt, true).'</pre>';
+        $this->trigger_error('Rijndael main decryption routine failed', E_USER_ERROR);
+      }
+      $dypt = $this->byteArrayToString($dypt);
+    }
+    return $dypt;
+  }
+  
+  /**
+   * Enano-ese equivalent of str_split() which is only found in PHP5
+   * @param $text string the text to split
+   * @param $inc int size of each block
+   * @return array
+   */
+   
+  function enano_str_split($text, $inc = 1)
+  {
+    if($inc < 1) return false;
+    if($inc >= strlen($text)) return Array($text);
+    $len = ceil(strlen($text) / $inc);
+    $ret = Array();
+    for($i=0;$i<strlen($text);$i=$i+$inc)
+    {
+      $ret[] = substr($text, $i, $inc);
+    }
+    return $ret;
+  }
+  
+  /**
+   * Generates a random key suitable for encryption
+   * @param int $len the length of the key, in bytes
+   * @return string a BINARY key
+   */
+  
+  function randkey($len = 32)
+  {
+    $key = '';
+    for($i=0;$i<$len;$i++)
+    {
+      $key .= chr(mt_rand(0, 255));
+    }
+    return $key;
+  }
+  
+  /*
+  function byteArrayToString($arr)
+  {
+    if(!is_array($arr))
+    {
+      $this->trigger_error('First parameter should be an array', E_USER_WARNING);
+      return false;
+    }
+    $ret = '';
+    foreach($arr as $a)
+    {
+      if($a != 0) $ret .= chr($a);
+    }
+    return $ret;
+  }
+  */
+  
+  function strtohex($str)
+  {
+    $str = $this->enano_str_split($str);
+    $ret = '';
+    foreach($str as $s)
+    {
+      $chr = dechex(ord($s));
+      if(strlen($chr) < 2) $chr = '0' . $chr;
+      $ret .= $chr;
+    }
+    return $ret;
+  }
+  
+  function gen_readymade_key()
+  {
+    $key = $this->strtohex($this->randkey($this->keySizeInBits / 8));
+    return $key;
+  }
+  
+  function prepare_string($text)
+  {
+    $ret = $this->hexToByteArray($this->strtohex($text));
+    if(count($ret) != strlen($text))
+      die('problem seems to be the hex conversion');
+    return $ret;
+  }
+  
+  /**
+   * Decodes a hex string.
+   * @param string $hex The hex code to decode
+   * @return string
+   */
+  
+  function hextostring($hex)
+  {
+    $hex = $this->enano_str_split($hex, 2);
+    $bin_key = '';
+    foreach($hex as $nibble)
+    {
+      $byte = chr(hexdec($nibble));
+      $bin_key .= $byte;
+    }
+    return $bin_key;
+  }
+}
+
+/**
+ * XXTEA encryption arithmetic library.
+ *
+ * Copyright (C) 2006 Ma Bingyao <andot@ujn.edu.cn>
+ * Version:      1.5
+ * LastModified: Dec 5, 2006
+ * This library is free.  You can redistribute it and/or modify it.
+ * 
+ * From dandaman32: I am treating this code as GPL, as implied by the license statement above.
+ */
+class TEACrypt extends AESCrypt {
+  function long2str($v, $w) {
+      $len = count($v);
+      $n = ($len - 1) << 2;
+      if ($w) {
+          $m = $v[$len - 1];
+          if (($m < $n - 3) || ($m > $n)) return false;
+          $n = $m;
+      }
+      $s = array();
+      for ($i = 0; $i < $len; $i++) {
+          $s[$i] = pack("V", $v[$i]);
+      }
+      if ($w) {
+          return substr(join('', $s), 0, $n);
+      }
+      else {
+          return join('', $s);
+      }
+  }
+   
+  function str2long($s, $w) {
+      $v = unpack("V*", $s. str_repeat("\0", (4 - strlen($s) % 4) & 3));
+      $v = array_values($v);
+      if ($w) {
+          $v[count($v)] = strlen($s);
+      }
+      return $v;
+  }
+   
+  function int32($n) {
+      while ($n >= 2147483648) $n -= 4294967296;
+      while ($n <= -2147483649) $n += 4294967296;
+      return (int)$n;
+  }
+   
+  function encrypt($str, $key) {
+      if ($str == "") {
+          return "";
+      }
+      $v = $this->str2long($str, true);
+      $k = $this->str2long($key, false);
+      if (count($k) < 4) {
+          for ($i = count($k); $i < 4; $i++) {
+              $k[$i] = 0;
+          }
+      }
+      $n = count($v) - 1;
+   
+      $z = $v[$n];
+      $y = $v[0];
+      $delta = 0x9E3779B9;
+      $q = floor(6 + 52 / ($n + 1));
+      $sum = 0;
+      while (0 < $q--) {
+          $sum = $this->int32($sum + $delta);
+          $e = $sum >> 2 & 3;
+          for ($p = 0; $p < $n; $p++) {
+              $y = $v[$p + 1];
+              $mx = $this->int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ $this->int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z));
+              $z = $v[$p] = $this->int32($v[$p] + $mx);
+          }
+          $y = $v[0];
+          $mx = $this->int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ $this->int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z));
+          $z = $v[$n] = $this->int32($v[$n] + $mx);
+      }
+      return $this->long2str($v, false);
+  }
+   
+  function decrypt($str, $key) {
+      if ($str == "") {
+          return "";
+      }
+      $v = $this->str2long($str, false);
+      $k = $this->str2long($key, false);
+      if (count($k) < 4) {
+          for ($i = count($k); $i < 4; $i++) {
+              $k[$i] = 0;
+          }
+      }
+      $n = count($v) - 1;
+   
+      $z = $v[$n];
+      $y = $v[0];
+      $delta = 0x9E3779B9;
+      $q = floor(6 + 52 / ($n + 1));
+      $sum = $this->int32($q * $delta);
+      while ($sum != 0) {
+          $e = $sum >> 2 & 3;
+          for ($p = $n; $p > 0; $p--) {
+              $z = $v[$p - 1];
+              $mx = $this->int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ $this->int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z));
+              $y = $v[$p] = $this->int32($v[$p] - $mx);
+          }
+          $z = $v[$n];
+          $mx = $this->int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ $this->int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z));
+          $y = $v[0] = $this->int32($v[0] - $mx);
+          $sum = $this->int32($sum - $delta);
+      }
+      return $this->long2str($v, true);
+  }
+}
+
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/search.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,636 @@
+<?php
+
+/*
+ * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
+ * Version 1.0 (Banshee)
+ * Copyright (C) 2006-2007 Dan Fuhry
+ * search.php - algorithm used to search pages
+ *
+ * This program is Free Software; you can redistribute 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 details.
+ */
+
+/**
+ * Implementation of array_merge() that preserves key names. $arr2 takes precedence over $arr1.
+ * @param array $arr1
+ * @param array $arr2
+ * @return array
+ */
+ 
+function enano_safe_array_merge($arr1, $arr2)
+{
+  $arr3 = $arr1;
+  foreach($arr2 as $k => $v)
+  {
+    $arr3[$k] = $v;
+  }
+  return $arr3;
+}
+
+/**
+ * Algorithm to actually do the searching. This system usually works pretty fast (tested and developed on a site with 22 pages) but one
+ * caveat of this algorithm is that it has to load the entire index into memory. It also requires manual parsing of the search query
+ * which can be quite CPU-intensive. On the flip side this algorithm is extremely flexible and can be adapted for other uses very easily.
+ * 
+ * Most of the time, this system is disabled. It is only used when MySQL can't or won't allow FULLTEXT indices.
+ *
+ * @package Enano
+ * @subpackage Page management frontend
+ * @license GNU General Public License http://www.enanocms.org/Special:GNU_General_Public_License
+ */
+
+class Searcher
+{
+  
+  var $results;
+  var $index;
+  var $warnings;
+  var $match_case = false;
+  
+  function __construct()
+  {
+    $this->warnings = Array();
+  }
+  
+  function Searcher()
+  {
+    $this->__construct();
+  }
+  
+  function warn($t)
+  {
+    if(!in_array($t, $this->warnings)) $this->warnings[] = $t;
+  }
+  
+  function convertCase($text)
+  {
+    return ( $this->match_case ) ? $text : strtolower($text);
+  }
+  
+  function buildIndex($texts)
+  {
+    $this->index = Array();
+
+    foreach($texts as $i => $l)
+    {
+      $seed = md5(microtime(true) . mt_rand());
+      $texts[$i] = str_replace("'", 'xxxApoS'.$seed.'xxx', $texts[$i]);
+      $texts[$i] = preg_replace('#([\W_]+)#i', ' ', $texts[$i]);
+      $texts[$i] = preg_replace('#([ ]+?)#', ' ', $texts[$i]);
+      $texts[$i] = preg_replace('#([\']*){2,}#s', '', $texts[$i]);
+      $texts[$i] = str_replace('xxxApoS'.$seed.'xxx', "'", $texts[$i]);
+      $l = $texts[$i];
+      $words = Array();
+      $good_chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\' ';
+      $good_chars = enano_str_split($good_chars, 1);
+      $letters = enano_str_split($l, 1);
+      foreach($letters as $x => $t)
+      {
+        if(!in_array($t, $good_chars))
+          unset($letters[$x]);
+      }
+      $letters = implode('', $letters);
+      $words = explode(' ', $letters);
+      foreach($words as $c => $w)
+      {
+        if(strlen($w) < 4)
+          unset($words[$c]);
+        else
+          $words[$c] = $w;
+      }
+      $words = array_values($words);
+      foreach($words as $c => $w)
+      {
+        if(isset($this->index[$w]))
+        {
+          if(!in_array($i, $this->index[$w]))
+            $this->index[$w][] = $i;
+        }
+        else
+        {
+          $this->index[$w] = Array();
+          $this->index[$w][] = $i;
+        }
+      }
+    }
+    foreach($this->index as $k => $v)
+    {
+      $this->index[$k] = implode(',', $this->index[$k]);
+    }
+  }
+  
+  function search($query, $texts)
+  {
+    
+    // OK, let's establish some basics here. Here is the procedure for performing the search:
+    //   * search for items that matches all the terms in the correct order.
+    //   * search for items that match in any order
+    //   * eliminate one term and do the loop all over
+    
+    $this->results = Array();
+    $query = $this->parseQuery($query);
+    $querybak = $query;
+    for($i = sizeof($query['any'])-1; $i >= 0; $i--)
+    {
+      $res = $this->performCoreSearch($query, $texts, true);
+      $this->results = enano_safe_array_merge($this->results, $res);
+      $res = $this->performCoreSearch($query, $texts, false);
+      $this->results = enano_safe_array_merge($this->results, $res);
+      unset($query['any'][$i]);
+    }
+    
+    // Last resort - search for any of the terms instead of all of 'em
+    $res = $this->performCoreSearch($querybak, $texts, false, true);
+    $this->results = enano_safe_array_merge($this->results, $res);
+    
+    $this->highlightResults($querybak);
+  }
+  
+  // $texts should be a textual MySQL query!
+  // @todo document
+  function searchMySQL($query, $texts)
+  {
+    global $db;
+    // OK, let's establish some basics here. Here is the procedure for performing the search:
+    //   * search for items that matches all the terms in the correct order.
+    //   * search for items that match in any order
+    //   * eliminate one term and do the loop all over
+    
+    $this->results = Array();
+    $query = $this->parseQuery($query);
+    $querytmp = $query;
+    $querybak = $query;
+    for($i = sizeof($querytmp['any'])-1; $i >= 0; $i--)
+    {
+      $res = $this->performCoreSearchMySQL($querytmp, $texts, true);
+      $this->results = enano_safe_array_merge($this->results, $res);
+      $res = $this->performCoreSearchMySQL($querytmp, $texts, false);
+      $this->results = enano_safe_array_merge($this->results, $res);
+      unset($querytmp['any'][$i]);
+    }
+    
+    // Last resort - search for any of the terms instead of all of 'em
+    $res = $this->performCoreSearchMySQL($querybak, $texts, false, true);
+    $this->results = enano_safe_array_merge($this->results, $res);
+    
+    $this->highlightResults($querybak);
+  }
+  
+  /**
+   * This method assumes that $query is already parsed and $texts is an (associative) array of possible results
+   * @param array $query A search query parsed with Searcher::parseQuery()
+   * @param array $texts The list of possible results
+   * @param bool $exact_order If true, only matches results with the terms in the same order as the terms in the query
+   * @return array An associative array of results
+   * @access private
+   */
+  function performCoreSearch($query, $texts, $exact_order = false, $any = false)
+  {
+    $textkeys = array_keys($texts);
+    $results = Array();
+    if($exact_order)
+    {
+      $query = $this->concatQueryTerms($query);
+    }
+    $query['trm'] = array_merge($query['any'], $query['req']);
+    # Find all remotely possible results first
+    // Single-word terms
+    foreach($this->index as $term => $keys)
+    {
+      foreach($query['trm'] as $userterm)
+      {
+        if($this->convertCase($userterm) == $this->convertCase($term))
+        {
+          $k = explode(',', $keys);
+          foreach($k as $idxkey)
+          {
+            if(isset($texts[$idxkey])) 
+            {
+              $results[$idxkey] = $texts[$idxkey];
+            }
+            else
+            {
+              if(preg_match('#^([0-9]+)$#', $idxkey))
+              {
+                $idxkey = intval($idxkey);
+                if(isset($texts[$idxkey])) $results[$idxkey] = $texts[$idxkey];
+              }
+            }
+          }
+        }
+      }
+    }
+    // Quoted terms
+    foreach($query['trm'] as $userterm)
+    {
+      if(!preg_match('/[\s"\'~`!@#\$%\^&\*\(\)\{\}:;<>,.\/\?_-]/', $userterm)) continue;
+      foreach($texts as $k => $t)
+      {
+        if(strstr($this->convertCase($t), $this->convertCase($userterm)))
+        {
+          // We have a match!
+          if(!isset($results[$k])) $results[$k] = $t;
+        }
+      }
+    }
+    // Remove excluded terms
+    foreach($results as $k => $r)
+    {
+      foreach($query['not'] as $not)
+      {
+        if(strstr($this->convertCase($r), $this->convertCase($not))) unset($results[$k]);
+      }
+    }
+    if(!$any)
+    {
+      // Remove results not containing all terms
+      foreach($results as $k => $r)
+      {
+        foreach($query['any'] as $term)
+        {
+          if(!strstr($this->convertCase($r), $this->convertCase($term))) unset($results[$k]);
+        }
+      }
+    }
+    // Remove results not containing all required terms
+    foreach($results as $k => $r)
+    {
+      foreach($query['req'] as $term)
+      {
+        if(!strstr($this->convertCase($r), $this->convertCase($term))) unset($results[$k]);
+      }
+    }
+    return $results;
+  }
+  
+  /**
+   * This is the same as performCoreSearch, but $texts should be a MySQL result resource. This can save tremendous amounts of memory on large sites.
+   * @param array $query A search query parsed with Searcher::parseQuery()
+   * @param string $texts A text MySQL query that selects the text as the first column and the index key as the second column
+   * @param bool $exact_order If true, only matches results with the terms in the same order as the terms in the query
+   * @return array An associative array of results
+   * @access private
+   */
+  function performCoreSearchMySQL($query, $texts, $exact_order = false, $any = false)
+  {
+    global $db;
+    $results = Array();
+    if($exact_order)
+    {
+      $query = $this->concatQueryTerms($query);
+    }
+    $query['trm'] = array_merge($query['any'], $query['req']);
+    # Find all remotely possible results first
+    $texts = $db->sql_query($texts);
+    if ( !$texts )
+      $db->_die('The error is in the search engine.');
+    if ( $r = $db->fetchrow_num($texts) )
+    {
+      do
+      {
+        foreach($this->index as $term => $keys)
+        {
+          foreach($query['trm'] as $userterm)
+          {
+            if($this->convertCase($userterm) == $this->convertCase($term))
+            {
+              $k = explode(',', $keys);
+              foreach($k as $idxkey)
+              {
+                $row[0] = $r[0];
+                $row[1] = $r[1];
+                if(!isset($row[1]))
+                {
+                  echo('PHP PARSER BUG: $row[1] is set but not set... includes/search.php:'.__LINE__);
+                  $GLOBALS['template']->footer();
+                  exit;
+                }
+                if($row[1] == $idxkey)
+                  $results[$idxkey] = $row[0];
+                else
+                {
+                  if(preg_match('#^([0-9]+)$#', $idxkey))
+                  {
+                    $idxkey = intval($idxkey);
+                    if($row[1] == $idxkey) $results[$idxkey] = $row[0];
+                  }
+                }
+              }
+            }
+          }
+        }
+        // Quoted terms
+        foreach($query['trm'] as $userterm)
+        {
+          if(!preg_match('/[\s"\'~`!@#\$%\^&\*\(\)\{\}:;<>,.\/\?_-]/', $userterm)) continue;
+          if(strstr($this->convertCase($r[0]), $this->convertCase($userterm)))
+          {
+            // We have a match!
+            if(!isset($results[$r[1]])) $results[$r[1]] = $r[0];
+          }
+        }
+      } while( $r = $db->fetchrow_num($texts) );
+    }
+    // Remove excluded terms
+    foreach($results as $k => $r)
+    {
+      foreach($query['not'] as $not)
+      {
+        if(strstr($this->convertCase($r), $this->convertCase($not))) unset($results[$k]);
+      }
+    }
+    if(!$any)
+    {
+      // Remove results not containing all terms
+      foreach($results as $k => $r)
+      {
+        foreach($query['any'] as $term)
+        {
+          if(!strstr($this->convertCase($r), $this->convertCase($term))) unset($results[$k]);
+        }
+      }
+    }
+    // Remove results not containing all terms
+    foreach($results as $k => $r)
+    {
+      foreach($query['req'] as $term)
+      {
+        if(!strstr($this->convertCase($r), $this->convertCase($term))) unset($results[$k]);
+      }
+    }
+    return $results;
+  }
+  
+  function concatQueryTerms($query)
+  {
+    $tmp = implode(' ', $query['any']);
+    unset($query['any']);
+    $query['any'] = Array(0 => $tmp);
+    return $query;
+  }
+  
+  /**
+   * Builds a basic assoc array with a more organized version of the query
+   */
+  
+  function parseQuery($query)
+  {
+    $ret = array(
+      'any' => array(),
+      'req' => array(),
+      'not' => array()
+      );
+    $terms = array();
+    $in_quote = false;
+    $start_term = 0;
+    $just_finished = false;
+    for ( $i = 0; $i < strlen($query); $i++ )
+    {
+      $chr = $query{$i};
+      $prev = ( $i > 0 ) ? $query{ $i - 1 } : '';
+      $next = ( ( $i + 1 ) < strlen($query) ) ? $query{ $i + 1 } : '';
+      
+      if ( ( $chr == ' ' && !$in_quote ) || ( $i + 1 == strlen ( $query ) ) )
+      {
+        $len = ( $next == '' ) ? $i + 1 : $i - $start_term;
+        $word = substr ( $query, $start_term, $len );
+        $terms[] = $word;
+        $start_term = $i + 1;
+      }
+      
+      elseif ( $chr == '"' && $in_quote && $prev != '\\' )
+      {
+        $word = substr ( $query, $start_term, $i - $start_term + 1 );
+        $start_pos = ( $next == ' ' ) ? $i + 2 : $i + 1;
+        $in_quote = false;
+      }
+      
+      elseif ( $chr == '"' && !$in_quote )
+      {
+        $in_quote = true;
+        $start_pos = $i;
+      }
+      
+    }
+    
+    $ticker = 0;
+    
+    foreach ( $terms as $element => $__unused )
+    {
+      $atom =& $terms[$element];
+      
+      $ticker++;
+      
+      if ( $ticker == 20 )
+      {
+        $this->warn('Some of your search terms were excluded because searches are limited to 20 terms to prevent excessive server load.');
+        break;
+      }
+      
+      if ( substr ( $atom, 0, 2 ) == '+"' && substr ( $atom, ( strlen ( $atom ) - 1 ), 1 ) == '"' )
+      {
+        $word = substr ( $atom, 2, ( strlen( $atom ) - 3 ) );
+        if ( strlen ( $word ) < 4 )
+        {
+          $this->warn('One or more of your search terms was excluded because terms must be at least 4 characters in length.');
+          $ticker--;
+          continue;
+        }
+        if(in_array($word, $ret['req']))
+        {
+          $this->warn('One or more of your search terms was excluded because duplicate terms were encountered.');
+          $ticker--;
+          continue;
+        }
+        $ret['req'][] = $word;
+      }
+      elseif ( substr ( $atom, 0, 2 ) == '-"' && substr ( $atom, ( strlen ( $atom ) - 1 ), 1 ) == '"' )
+      {
+        $word = substr ( $atom, 2, ( strlen( $atom ) - 3 ) );
+        if ( strlen ( $word ) < 4 )
+        {
+          $this->warn('One or more of your search terms was excluded because terms must be at least 4 characters in length.');
+          $ticker--;
+          continue;
+        }
+        if(in_array($word, $ret['not']))
+        {
+          $this->warn('One or more of your search terms was excluded because duplicate terms were encountered.');
+          $ticker--;
+          continue;
+        }
+        $ret['not'][] = $word;
+      }
+      elseif ( substr ( $atom, 0, 1 ) == '+' )
+      {
+        $word = substr ( $atom, 1 );
+        if ( strlen ( $word ) < 4 )
+        {
+          $this->warn('One or more of your search terms was excluded because terms must be at least 4 characters in length.');
+          $ticker--;
+          continue;
+        }
+        if(in_array($word, $ret['req']))
+        {
+          $this->warn('One or more of your search terms was excluded because duplicate terms were encountered.');
+          $ticker--;
+          continue;
+        }
+        $ret['req'][] = $word;
+      }
+      elseif ( substr ( $atom, 0, 1 ) == '-' )
+      {
+        $word = substr ( $atom, 1 );
+        if ( strlen ( $word ) < 4 )
+        {
+          $this->warn('One or more of your search terms was excluded because terms must be at least 4 characters in length.');
+          $ticker--;
+          continue;
+        }
+        if(in_array($word, $ret['not']))
+        {
+          $this->warn('One or more of your search terms was excluded because duplicate terms were encountered.');
+          $ticker--;
+          continue;
+        }
+        $ret['not'][] = $word;
+      }
+      elseif ( substr ( $atom, 0, 1 ) == '"' && substr ( $atom, ( strlen($atom) - 1 ), 1 ) == '"' )
+      {
+        $word = substr ( $atom, 1, ( strlen ( $atom ) - 2 ) );
+        if ( strlen ( $word ) < 4 )
+        {
+          $this->warn('One or more of your search terms was excluded because terms must be at least 4 characters in length.');
+          $ticker--;
+          continue;
+        }
+        if(in_array($word, $ret['any']))
+        {
+          $this->warn('One or more of your search terms was excluded because duplicate terms were encountered.');
+          $ticker--;
+          continue;
+        }
+        $ret['any'][] = $word;
+      }
+      else
+      {
+        $word = $atom;
+        if ( strlen ( $word ) < 4 )
+        {
+          $this->warn('One or more of your search terms was excluded because terms must be at least 4 characters in length.');
+          $ticker--;
+          continue;
+        }
+        if(in_array($word, $ret['any']))
+        {
+          $this->warn('One or more of your search terms was excluded because duplicate terms were encountered.');
+          $ticker--;
+          continue;
+        }
+        $ret['any'][] = $word;
+      }
+    }
+    return $ret;
+  }
+  
+  function highlightResults($query, $starttag = '<b>', $endtag = '</b>')
+  {
+    $query['trm'] = array_merge($query['any'], $query['req']);
+    //die('<pre>'.print_r($query, true).'</pre>');
+    foreach($query['trm'] as $q)
+    {
+      foreach($this->results as $k => $r)
+      {
+        $startplace = 0;
+        //$this->results[$k] = htmlspecialchars($this->results[$k]);
+        for($i = 0; $i < strlen($r); $i++)
+        {
+          $word = substr($r, $i, strlen($q));
+          if($this->convertCase($word) == $this->convertCase($q))
+          {
+            $word = $starttag . $word . $endtag;
+            $this->results[$k] = substr($r, 0, $i) . $word . substr($r, $i + strlen($q), strlen($r)+999999);
+            $startplace = $i - 75;
+            if($startplace < 0) $startplace = 0;
+            $this->results[$k] = '...'.trim(substr($this->results[$k], $startplace, strlen($word) + 150)).'...';
+            continue 2;
+          }
+        }
+      }
+    }
+  }
+  
+}
+
+/**
+ * Developer-friendly way to do searches. :-) Uses the MySQL FULLTEXT index type.
+ * @package Enano
+ * @subpackage Search
+ */
+
+class MySQL_Fulltext_Search {
+  
+  /**
+   * Performs a search.
+   * @param string The search query
+   * @return resource MySQL result resource - this is an UNBUFFERED query.
+   */
+  
+  function search($query)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    $fulltext_col = 'MATCH(t.page_id,t.namespace,p.name,t.page_text) AGAINST (\'' . $db->escape($query) . '\' IN BOOLEAN MODE)';
+    $sql = "SELECT t.page_text,CONCAT('ns=',t.namespace,';pid=',t.page_id) AS page_identifier, $fulltext_col AS score, CHAR_LENGTH(t.page_text) AS length FROM ".table_prefix."page_text AS t
+              LEFT JOIN ".table_prefix."pages AS p
+                ON ( p.urlname=t.page_id AND p.namespace=t.namespace)
+              WHERE $fulltext_col > 0
+                AND p.visible=1
+              ORDER BY score DESC;";
+    $q = $db->sql_unbuffered_query($sql);
+    if ( !$q )
+      $db->_die();
+    
+    return $q;
+  }
+  
+  function highlight_result($query, $result)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $search = new Searcher();
+    $parsed_query = $search->parseQuery($query);
+    return $this->highlight_result_inner($query, $result);
+  }
+  
+  function highlight_result_inner($query, $fulltext, $starttag = '<b>', $endtag = '</b>')
+  {
+    $result = false;
+    $query['trm'] = array_merge($query['any'], $query['req']);
+    //die('<pre>'.print_r($query, true).'</pre>');
+    foreach($query['trm'] as $q)
+    {
+      $startplace = 0;
+      //$this->results[$k] = htmlspecialchars($this->results[$k]);
+      for($i = 0; $i < strlen($r); $i++)
+      {
+        $word = substr($r, $i, strlen($q));
+        if($this->convertCase($word) == $this->convertCase($q))
+        {
+          $word = $starttag . $word . $endtag;
+          $result = substr($fulltext, 0, $i) . $word . substr($r, $i + strlen($q), strlen($r)+99999999);
+          $startplace = $i - 75;
+          if($startplace < 0) $startplace = 0;
+          $result = '...'.trim(substr($result, $startplace, strlen($word) + 150)).'...';
+          continue 2;
+        }
+      }
+    }
+    return $result;
+  }
+  
+}
+
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/sessions.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,2439 @@
+<?php
+
+/*
+ * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
+ * Version 1.0 (Banshee)
+ * Copyright (C) 2006-2007 Dan Fuhry
+ * sessions.php - everything related to security and user management
+ *
+ * This program is Free Software; you can redistribute 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 details.
+ */
+ 
+// Prepare a string for insertion into a MySQL database
+function filter($str) { return $db->escape($str); }
+
+/**
+ * Anything and everything related to security and user management. This includes AES encryption, which is illegal in some countries.
+ * Documenting the API was not easy - I hope you folks enjoy it.
+ * @package Enano
+ * @subpackage Session manager
+ * @category security, user management, logins, etc.
+ */
+
+class sessionManager {
+  
+  # Variables
+  
+  /**
+   * Whether we're logged in or not
+   * @var bool
+   */
+   
+  var $user_logged_in = false;
+  
+  /**
+   * Our current low-privilege session key
+   * @var string
+   */
+  
+  var $sid;
+  
+  /**
+   * Username of currently logged-in user, or IP address if not logged in
+   * @var string
+   */
+  
+  var $username;
+  
+  /**
+   * User ID of currently logged-in user, or -1 if not logged in
+   * @var int
+   */
+  
+  var $user_id;
+  
+  /**
+   * Real name of currently logged-in user, or blank if not logged in
+   * @var string
+   */
+  
+  var $real_name;
+  
+  /**
+   * E-mail address of currently logged-in user, or blank if not logged in
+   * @var string
+   */
+  
+  var $email;
+  
+  /**
+   * User level of current user
+   * USER_LEVEL_GUEST: guest
+   * USER_LEVEL_MEMBER: regular user
+   * USER_LEVEL_CHPREF: default - pseudo-level that allows changing password and e-mail address (requires re-authentication)
+   * USER_LEVEL_MOD: moderator
+   * USER_LEVEL_ADMIN: administrator
+   * @var int
+   */
+  
+  var $user_level;
+  
+  /**
+   * High-privilege session key
+   * @var string or false if not running on high-level authentication
+   */
+  
+  var $sid_super;
+  
+  /**
+   * The user's theme preference, defaults to $template->default_theme
+   * @var string
+   */
+  
+  var $theme;
+  
+  /**
+   * The user's style preference, or style auto-detected based on theme if not logged in
+   * @var string
+   */
+  
+  var $style;
+  
+  /**
+   * Signature of current user - appended to comments, etc.
+   * @var string
+   */
+  
+  var $signature;
+  
+  /**
+   * UNIX timestamp of when we were registered, or 0 if not logged in
+   * @var int
+   */
+  
+  var $reg_time;
+  
+  /**
+   * MD5 hash of the current user's password, if applicable
+   * @var string OR bool false
+   */
+   
+  var $password_hash;
+  
+  /**
+   * The number of unread private messages this user has.
+   * @var int
+   */
+  
+  var $unread_pms = 0;
+  
+  /**
+   * AES key used to encrypt passwords and session key info - irreversibly destroyed when disallow_password_grab() is called
+   * @var string
+   */
+   
+  var $private_key;
+  
+  /**
+   * Regex that defines a valid username, minus the ^ and $, these are added later
+   * @var string
+   */
+   
+   var $valid_username = '([A-Za-z0-9 \!\@\(\)-]+)';
+   
+  /**
+   * What we're allowed to do as far as permissions go. This changes based on the value of the "auth" URI param.
+   * @var string
+   */
+   
+  var $auth_level = -1;
+  
+  /**
+   * State variable to track if a session timed out
+   * @var bool
+   */
+  
+  var $sw_timed_out = false;
+  
+  /**
+   * Switch to track if we're started or not.
+   * @access private
+   * @var bool
+   */
+   
+  var $started = false;
+  
+  /**
+   * Switch to control compatibility mode (for older Enano websites being upgraded)
+   * @access private
+   * @var bool
+   */
+   
+  var $compat = false;
+  
+  /**
+   * Our list of permission types.
+   * @access private
+   * @var array
+   */
+   
+  var $acl_types = Array();
+  
+  /**
+   * The list of descriptions for the permission types
+   * @var array
+   */
+   
+  var $acl_descs = Array();
+  
+  /**
+   * A list of dependencies for ACL types.
+   * @var array
+   */
+   
+  var $acl_deps = Array();
+  
+  /**
+   * Our tell-all list of permissions.
+   * @access private - or, preferably, protected
+   * @var array
+   */
+   
+  var $perms = Array();
+  
+  /**
+   * A cache variable - saved after sitewide permissions are checked but before page-specific permissions.
+   * @var array
+   * @access private
+   */
+  
+  var $acl_base_cache = Array();
+  
+  /**
+   * Stores the scope information for ACL types.
+   * @var array
+   * @access private
+   */
+   
+  var $acl_scope = Array();
+  
+  /**
+   * Array to track which default permissions are being used
+   * @var array
+   * @access private
+   */
+   
+  var $acl_defaults_used = Array();
+  
+  /**
+   * Array to track group membership.
+   * @var array
+   */
+   
+  var $groups = Array();
+  
+  /**
+   * Associative array to track group modship.
+   * @var array
+   */
+   
+  var $group_mod = Array();
+  
+  # Basic functions
+   
+  /**
+   * Constructor.
+   */
+   
+  function __construct()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    include(ENANO_ROOT.'/config.php');
+    unset($dbhost, $dbname, $dbuser, $dbpasswd);
+    if(isset($crypto_key))
+    {
+      $this->private_key = $crypto_key;
+      $this->private_key = hexdecode($this->private_key);
+    }
+    else
+    {
+      if(is_writable(ENANO_ROOT.'/config.php'))
+      {
+        // Generate and stash a private key
+        // This should only happen during an automated silent gradual migration to the new encryption platform.
+        $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
+        $this->private_key = $aes->gen_readymade_key();
+        
+        $config = file_get_contents(ENANO_ROOT.'/config.php');
+        if(!$config)
+        {
+          die('$session->__construct(): can\'t get the contents of config.php');
+        }
+        
+        $config = str_replace("?>", "\$crypto_key = '{$this->private_key}';\n?>", $config);
+        // And while we're at it...
+        $config = str_replace('MIDGET_INSTALLED', 'ENANO_INSTALLED', $config);
+        $fh = @fopen(ENANO_ROOT.'/config.php', 'w');
+        if ( !$fh ) 
+        {
+          die('$session->__construct(): Couldn\'t open config file for writing to store the private key, I tried to avoid something like this...');
+        }
+        
+        fwrite($fh, $config);
+        fclose($fh);
+      }
+      else
+      {
+        die_semicritical('Crypto error', '<p>No private key was found in the config file, and we can\'t generate one because we don\'t have write access to the config file. Please CHMOD config.php to 666 or 777 and reload this page.</p>');
+      }
+    }
+    // Check for compatibility mode
+    if(defined('IN_ENANO_INSTALL'))
+    {
+      $q = $db->sql_query('SELECT old_encryption FROM '.table_prefix.'users LIMIT 1;');
+      if(!$q)
+      {
+        $error = mysql_error();
+        if(strstr($error, "Unknown column 'old_encryption'"))
+          $this->compat = true;
+        else
+          $db->_die('This should never happen and is a bug - the only error that was supposed to happen here didn\'t happen. (sessions.php in constructor, during compat mode check)');
+      }
+      $db->free_result();
+    }
+  }
+  
+  /**
+   * PHP 4 compatible constructor.
+   */
+   
+  function sessionManager()
+  {
+    $this->__construct();
+  }
+  
+  /**
+   * Wrapper function to sanitize strings for MySQL and HTML
+   * @param string $text The text to sanitize
+   * @return string
+   */
+  
+  function prepare_text($text)
+  {
+    global $db;
+    return $db->escape(htmlspecialchars($text));
+  }
+  
+  /**
+   * Makes a SQL query and handles error checking
+   * @param string $query The SQL query to make
+   * @return resource
+   */
+  
+  function sql($query)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $result = $db->sql_query($query);
+    if(!$result)
+    {
+      $db->_die('The error seems to have occurred somewhere in the session management code.');
+    }
+    return $result;
+  }
+  
+  # Session restoration and permissions
+  
+  /**
+   * Initializes the basic state of things, including most user prefs, login data, cookie stuff
+   */
+  
+  function start()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if($this->started) return;
+    $this->started = true;
+    $user = false;
+    if(isset($_COOKIE['sid']))
+    {
+      if($this->compat)
+      {
+        $userdata = $this->compat_validate_session($_COOKIE['sid']);
+      }
+      else
+      {
+        $userdata = $this->validate_session($_COOKIE['sid']);
+      }
+      if(is_array($userdata))
+      {
+        $data = RenderMan::strToPageID($paths->get_pageid_from_url());
+        
+        if(!$this->compat && $userdata['account_active'] != 1 && $data[1] != 'Special' && $data[1] != 'Admin')
+        {
+          $this->logout();
+          $a = getConfig('account_activation');
+          switch($a)
+          {
+            case 'none':
+            default:
+              $solution = 'Your account was most likely deactivated by an administrator. Please contact the site administration for further assistance.';
+              break;
+            case 'user':
+              $solution = 'Please check your e-mail; you should have been sent a message with instructions on how to activate your account. If you do not receive an e-mail from this site within 24 hours, please contact the site administration for further assistance.';
+              break;
+            case 'admin':
+              $solution = 'This website has been configured so that all user accounts must be activated by the administrator before they can be used, so your account will most likely be activated the next time the one of the administrators visits the site.';
+              break;
+          }
+          die_semicritical('Account error', '<p>It appears that your user account has not yet been activated. '.$solution.'</p>');
+        }
+        
+        $this->sid = $_COOKIE['sid'];
+        $this->user_logged_in = true;
+        $this->user_id =       intval($userdata['user_id']);
+        $this->username =      $userdata['username'];
+        $this->password_hash = $userdata['password'];
+        $this->user_level =    intval($userdata['user_level']);
+        $this->real_name =     $userdata['real_name'];
+        $this->email =         $userdata['email'];
+        $this->unread_pms =    $userdata['num_pms'];
+        if(!$this->compat)
+        {
+          $this->theme =         $userdata['theme'];
+          $this->style =         $userdata['style'];
+          $this->signature =     $userdata['signature'];
+          $this->reg_time =      $userdata['reg_time'];
+        }
+        // Small security risk here - it allows someone who has already authenticated as an administrator to store the "super" key in
+        // the cookie. Change this to USER_LEVEL_MEMBER to override that. The same 15-minute restriction applies to this "exploit".
+        $this->auth_level =    $userdata['auth_level'];
+        if(!isset($template->named_theme_list[$this->theme]))
+        {
+          if($this->compat || !is_object($template))
+          {
+            $this->theme = 'oxygen';
+            $this->style = 'bleu';
+          }
+          else
+          {
+            $this->theme = $template->default_theme;
+            $this->style = $template->default_style;
+          }
+        }
+        $user = true;
+        
+        if(isset($_REQUEST['auth']) && !$this->sid_super)
+        {
+          // Now he thinks he's a moderator. Or maybe even an administrator. Let's find out if he's telling the truth.
+          if($this->compat)
+          {
+            $key = $_REQUEST['auth'];
+            $super = $this->compat_validate_session($key);
+          }
+          else
+          {
+            $key = strrev($_REQUEST['auth']);
+            $super = $this->validate_session($key);
+          }
+          if(is_array($super))
+          {
+            $this->auth_level = intval($super['auth_level']);
+            $this->sid_super = $_REQUEST['auth'];
+          }
+        }
+      }
+    }
+    if(!$user)
+    {
+      //exit;
+      $this->register_guest_session();
+    }
+    if(!$this->compat)
+    {
+      // init groups
+      $q = $this->sql('SELECT g.group_name,g.group_id,m.is_mod FROM '.table_prefix.'groups AS g
+          LEFT JOIN '.table_prefix.'group_members AS m
+            ON g.group_id=m.group_id
+          WHERE ( m.user_id='.$this->user_id.' 
+            OR g.group_name=\'Everyone\')
+            ' . ( enano_version() == '1.0RC1' ? '' : 'AND ( m.pending != 1 OR m.pending IS NULL )' ) . '
+          ORDER BY group_id ASC;'); // Make sure "Everyone" comes first so the permissions can be overridden
+      if($row = $db->fetchrow())
+      {
+        do {
+          $this->groups[$row['group_id']] = $row['group_name'];
+          $this->group_mod[$row['group_id']] = ( intval($row['is_mod']) == 1 );
+        } while($row = $db->fetchrow());
+      }
+      else
+      {
+        die('No group info');
+      }
+    }
+    $this->check_banlist();
+    
+    if ( isset ( $_GET['printable'] ) )
+    {
+      $this->theme = 'printable';
+      $this->style = 'default';
+    }
+    
+  }
+  
+  # Logins
+  
+  /**
+   * Attempts to perform a login using crypto functions
+   * @param string $username The username
+   * @param string $aes_data The encrypted password, hex-encoded
+   * @param string $aes_key The MD5 hash of the encryption key, hex-encoded
+   * @param string $challenge The 256-bit MD5 challenge string - first 128 bits should be the hash, the last 128 should be the challenge salt
+   * @param int $level The privilege level we're authenticating for, defaults to 0
+   * @return string 'success' on success, or error string on failure
+   */
+   
+  function login_with_crypto($username, $aes_data, $aes_key, $challenge, $level = USER_LEVEL_MEMBER)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    $privcache = $this->private_key;
+    
+    // Instanciate the Rijndael encryption object
+    $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
+    
+    // Fetch our decryption key
+    
+    $aes_key = $this->fetch_public_key($aes_key);
+    if(!$aes_key)
+      return 'Couldn\'t look up public key "'.$aes_key.'" for decryption';
+    
+    // Convert the key to a binary string
+    $bin_key = hexdecode($aes_key);
+    
+    if(strlen($bin_key) != AES_BITS / 8)
+      return 'The decryption key is the wrong length';
+    
+    // Decrypt our password
+    $password = $aes->decrypt($aes_data, $bin_key, ENC_HEX);
+    
+    // Initialize our success switch
+    $success = false;
+    
+    // Select the user data from the table, and decrypt that so we can verify the password
+    $this->sql('SELECT password,old_encryption,user_id,user_level,theme,style,temp_password,temp_password_time FROM '.table_prefix.'users WHERE lcase(username)=\''.$this->prepare_text(strtolower($username)).'\';');
+    if($db->numrows() < 1)
+      return 'The username and/or password is incorrect.';
+    $row = $db->fetchrow();
+    
+    // Check to see if we're logging in using a temporary password
+    
+    if((intval($row['temp_password_time']) + 3600*24) > time() )
+    {
+      $temp_pass = $aes->decrypt( $row['temp_password'], $this->private_key, ENC_HEX );
+      if( $temp_pass == $password )
+      {
+        $url = makeUrlComplete('Special', 'PasswordReset/stage2/' . $row['user_id'] . '/' . $row['temp_password']);
+        
+        $code = $plugins->setHook('login_password_reset');
+        foreach ( $code as $cmd )
+        {
+          eval($cmd);
+        }
+        
+        redirect($url, 'Login sucessful', 'Please wait while you are transferred to the Password Reset form.');
+        exit;
+      }
+    }
+    
+    if($row['old_encryption'] == 1)
+    {
+      // The user's password is stored using the obsolete and insecure MD5 algorithm, so we'll update the field with the new password
+      if(md5($password) == $row['password'])
+      {
+        $pass_stashed = $aes->encrypt($password, $this->private_key, ENC_HEX);
+        $this->sql('UPDATE '.table_prefix.'users SET password=\''.$pass_stashed.'\',old_encryption=0 WHERE user_id='.$row['user_id'].';');
+        $success = true;
+      }
+    }
+    else
+    {
+      // Our password field is up-to-date with the >=1.0RC1 encryption standards, so decrypt the password in the table and see if we have a match; if so then do challenge authentication
+      $real_pass = $aes->decrypt(hexdecode($row['password']), $this->private_key, ENC_BINARY);
+      if($password == $real_pass)
+      {
+        // Yay! We passed AES authentication, now do an MD5 challenge check to make sure we weren't spoofed
+        $chal = substr($challenge, 0, 32);
+        $salt = substr($challenge, 32, 32);
+        $correct_challenge = md5( $real_pass . $salt );
+        if($chal == $correct_challenge)
+          $success = true;
+      }
+    }
+    if($success)
+    {
+      if($level > $row['user_level'])
+        return 'You are not authorized for this level of access.';
+      
+      $sess = $this->register_session(intval($row['user_id']), $username, $password, $level);
+      if($sess)
+      {
+        $this->username = $username;
+        $this->user_id = intval($row['user_id']);
+        $this->theme = $row['theme'];
+        $this->style = $row['style'];
+        
+        if($level > USER_LEVEL_MEMBER)
+          $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary,page_text) VALUES(\'security\', \'admin_auth_good\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\', ' . intval($level) . ')');
+        else
+          $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary) VALUES(\'security\', \'auth_good\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\')');
+        
+        $code = $plugins->setHook('login_success');
+        foreach ( $code as $cmd )
+        {
+          eval($cmd);
+        }
+        return 'success';
+      }
+      else
+        return 'Your login credentials were correct, but an internal error occurred while registering the session key in the database.';
+    }
+    else
+    {
+      if($level > USER_LEVEL_MEMBER)
+        $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary,page_text) VALUES(\'security\', \'admin_auth_bad\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\', ' . intval($level) . ')');
+      else
+        $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary) VALUES(\'security\', \'auth_bad\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\')');
+        
+      return 'The username and/or password is incorrect.';
+    }
+  }
+  
+  /**
+   * Attempts to login without using crypto stuff, mainly for use when the other side doesn't like Javascript
+   * This method of authentication is inherently insecure, there's really nothing we can do about it except hope and pray that everyone moves to Firefox
+   * Technically it still uses crypto, but it only decrypts the password already stored, which is (obviously) required for authentication
+   * @param string $username The username
+   * @param string $password The password -OR- the MD5 hash of the password if $already_md5ed is true
+   * @param bool $already_md5ed This should be set to true if $password is an MD5 hash, and should be false if it's plaintext. Defaults to false.
+   * @param int $level The privilege level we're authenticating for, defaults to 0
+   */
+  
+  function login_without_crypto($username, $password, $already_md5ed = false, $level = USER_LEVEL_MEMBER)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    $pass_hashed = ( $already_md5ed ) ? $password : md5($password);
+    
+    // Perhaps we're upgrading Enano?
+    if($this->compat)
+    {
+      return $this->login_compat($username, $pass_hashed, $level);
+    }
+    
+    // Instanciate the Rijndael encryption object
+    $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
+    
+    // Initialize our success switch
+    $success = false;
+    
+    // Retrieve the real password from the database
+    $this->sql('SELECT password,old_encryption,user_id,user_level,temp_password,temp_password_time FROM '.table_prefix.'users WHERE lcase(username)=\''.$this->prepare_text(strtolower($username)).'\';');
+    if($db->numrows() < 1)
+      return 'The username and/or password is incorrect.';
+    $row = $db->fetchrow();
+    
+    // Check to see if we're logging in using a temporary password
+    
+    if((intval($row['temp_password_time']) + 3600*24) > time() )
+    {
+      $temp_pass = $aes->decrypt( $row['temp_password'], $this->private_key, ENC_HEX );
+      if( md5($temp_pass) == $pass_hashed )
+      {
+        $code = $plugins->setHook('login_password_reset');
+        foreach ( $code as $cmd )
+        {
+          eval($cmd);
+        }
+        
+        header('Location: ' . makeUrlComplete('Special', 'PasswordReset/stage2/' . $row['user_id'] . '/' . $row['temp_password']) );
+        
+        exit;
+      }
+    }
+    
+    if($row['old_encryption'] == 1)
+    {
+      // The user's password is stored using the obsolete and insecure MD5 algorithm - we'll update the field with the new password
+      if($pass_hashed == $row['password'] && !$already_md5ed)
+      {
+        $pass_stashed = $aes->encrypt($password, $this->private_key, ENC_HEX);
+        $this->sql('UPDATE '.table_prefix.'users SET password=\''.$pass_stashed.'\',old_encryption=0 WHERE user_id='.$row['user_id'].';');
+        $success = true;
+      }
+      elseif($pass_hashed == $row['password'] && $already_md5ed)
+      {
+        // We don't have the real password so don't bother with encrypting it, just call it success and get out of here
+        $success = true;
+      }
+    }
+    else
+    {
+      // Our password field is up-to-date with the >=1.0RC1 encryption standards, so decrypt the password in the table and see if we have a match
+      $real_pass = $aes->decrypt($row['password'], $this->private_key);
+      if($pass_hashed == md5($real_pass))
+      {
+        $success = true;
+      }
+    }
+    if($success)
+    {
+      if((int)$level > (int)$row['user_level'])
+        return 'You are not authorized for this level of access.';
+      $sess = $this->register_session(intval($row['user_id']), $username, $real_pass, $level);
+      if($sess)
+      {
+        if($level > USER_LEVEL_MEMBER)
+          $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary,page_text) VALUES(\'security\', \'admin_auth_good\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\', ' . intval($level) . ')');
+        else
+          $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary) VALUES(\'security\', \'auth_good\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\')');
+        
+        $code = $plugins->setHook('login_success');
+        foreach ( $code as $cmd )
+        {
+          eval($cmd);
+        }
+        return 'success';
+      }
+      else
+        return 'Your login credentials were correct, but an internal error occured while registering the session key in the database.';
+    }
+    else
+    {
+      if($level > USER_LEVEL_MEMBER)
+        $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary,page_text) VALUES(\'security\', \'admin_auth_bad\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\', ' . intval($level) . ')');
+      else
+        $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary) VALUES(\'security\', \'auth_bad\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\')');
+        
+      return 'The username and/or password is incorrect.';
+    }
+  }
+  
+  /**
+   * Attempts to log in using the old table structure and algorithm.
+   * @param string $username
+   * @param string $password This should be an MD5 hash
+   * @return string 'success' if successful, or error message on failure
+   */
+  
+  function login_compat($username, $password, $level = 0)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $pass_hashed =& $password;
+    $this->sql('SELECT password,user_id,user_level FROM '.table_prefix.'users WHERE username=\''.$this->prepare_text($username).'\';');
+    if($db->numrows() < 1)
+      return 'The username and/or password is incorrect.';
+    $row = $db->fetchrow();
+    if($row['password'] == $password)
+    {
+      if((int)$level > (int)$row['user_level'])
+        return 'You are not authorized for this level of access.';
+      $sess = $this->register_session_compat(intval($row['user_id']), $username, $password, $level);
+      if($sess)
+        return 'success';
+      else
+        return 'Your login credentials were correct, but an internal error occured while registering the session key in the database.';
+    }
+    else
+    {
+      return 'The username and/or password is incorrect.';
+    }
+  }
+  
+  /**
+   * Registers a session key in the database. This function *ASSUMES* that the username and password have already been validated!
+   * Basically the session key is a base64-encoded cookie (encrypted with the site's private key) that says "u=[username];p=[sha1 of password]"
+   * @param int $user_id
+   * @param string $username
+   * @param string $password
+   * @param int $level The level of access to grant, defaults to USER_LEVEL_MEMBER
+   * @return bool
+   */
+   
+  function register_session($user_id, $username, $password, $level = USER_LEVEL_MEMBER)
+  {
+    $salt = md5(microtime() . mt_rand());
+    $passha1 = sha1($password);
+    $session_key = "u=$username;p=$passha1;s=$salt";
+    $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
+    $session_key = $aes->encrypt($session_key, $this->private_key, ENC_HEX);
+    if($level > USER_LEVEL_MEMBER)
+    {
+      $hexkey = strrev($session_key);
+      $this->sid_super = $hexkey;
+      $_GET['auth'] = $hexkey;
+    }
+    else
+    {
+      setcookie( 'sid', $session_key, time()+315360000, scriptPath.'/' );
+      $_COOKIE['sid'] = $session_key;
+    }
+    $keyhash = md5($session_key);
+    $ip = ip2hex($_SERVER['REMOTE_ADDR']);
+    if(!$ip)
+      die('$session->register_session: Remote-Addr was spoofed');
+    $time = time();
+    if(!is_int($user_id))
+      die('Somehow an SQL injection attempt crawled into our session registrar! (1)');
+    if(!is_int($level))
+      die('Somehow an SQL injection attempt crawled into our session registrar! (2)');
+    
+    $query = $this->sql('INSERT INTO '.table_prefix.'session_keys(session_key, salt, user_id, auth_level, source_ip, time) VALUES(\''.$keyhash.'\', \''.$salt.'\', '.$user_id.', '.$level.', \''.$ip.'\', '.$time.');');
+    return true;
+  }
+  
+  /**
+   * Identical to register_session in nature, but uses the old login/table structure. DO NOT use this.
+   * @see sessionManager::register_session()
+   * @access private
+   */
+  
+  function register_session_compat($user_id, $username, $password, $level = 0)
+  {
+    $salt = md5(microtime() . mt_rand());
+    $thekey = md5($password . $salt);
+    if($level > 0)
+    {
+      $this->sid_super = $thekey;
+    }
+    else
+    {
+      setcookie( 'sid', $thekey, time()+315360000, scriptPath.'/' );
+      $_COOKIE['sid'] = $thekey;
+    }
+    $ip = ip2hex($_SERVER['REMOTE_ADDR']);
+    if(!$ip)
+      die('$session->register_session: Remote-Addr was spoofed');
+    $time = time();
+    if(!is_int($user_id))
+      die('Somehow an SQL injection attempt crawled into our session registrar! (1)');
+    if(!is_int($level))
+      die('Somehow an SQL injection attempt crawled into our session registrar! (2)');
+    $query = $this->sql('INSERT INTO '.table_prefix.'session_keys(session_key, salt, user_id, auth_level, source_ip, time) VALUES(\''.$thekey.'\', \''.$salt.'\', '.$user_id.', '.$level.', \''.$ip.'\', '.$time.');');
+    return true;
+  }
+  
+  /**
+   * Creates/restores a guest session
+   * @todo implement real session management for guests
+   */
+   
+  function register_guest_session()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $this->username = $_SERVER['REMOTE_ADDR'];
+    $this->user_level = USER_LEVEL_GUEST;
+    if($this->compat || defined('IN_ENANO_INSTALL'))
+    {
+      $this->theme = 'oxygen';
+      $this->style = 'bleu';
+    }
+    else
+    {
+      $this->theme = ( isset($_GET['theme']) && isset($template->named_theme_list[$_GET['theme']])) ? $_GET['theme'] : $template->default_theme;
+      $this->style = ( isset($_GET['style']) && file_exists(ENANO_ROOT.'/themes/'.$this->theme . '/css/'.$_GET['style'].'.css' )) ? $_GET['style'] : substr($template->named_theme_list[$this->theme]['default_style'], 0, strlen($template->named_theme_list[$this->theme]['default_style'])-4);
+    }
+    $this->user_id = 1;
+  }
+  
+  /**
+   * Validates a session key, and returns the userdata associated with the key or false
+   * @param string $key The session key to validate
+   * @return array Keys are 'user_id', 'username', 'email', 'real_name', 'user_level', 'theme', 'style', 'signature', 'reg_time', 'account_active', 'activation_key', and 'auth_level' or bool false if validation failed. The key 'auth_level' is the maximum authorization level that this key provides.
+   */
+   
+  function validate_session($key)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE, true);
+    $decrypted_key = $aes->decrypt($key, $this->private_key, ENC_HEX);
+    
+    if ( !$decrypted_key )
+    {
+      die_semicritical('AES encryption error', '<p>Something went wrong during the AES decryption process.</p><pre>'.print_r($decrypted_key, true).'</pre>');
+    }
+    
+    $n = preg_match('/^u='.$this->valid_username.';p=([A-Fa-f0-9]+?);s=([A-Fa-f0-9]+?)$/', $decrypted_key, $keydata);
+    if($n < 1)
+    {
+      // echo '(debug) $session->validate_session: Key does not match regex<br />Decrypted key: '.$decrypted_key;
+      return false;
+    }
+    $keyhash = md5($key);
+    $salt = $db->escape($keydata[3]);
+    $query = $this->sql('SELECT u.user_id AS uid,u.username,u.password,u.email,u.real_name,u.user_level,u.theme,u.style,u.signature,u.reg_time,u.account_active,u.activation_key,k.source_ip,k.time,k.auth_level,COUNT(p.message_id) AS num_pms,x.* FROM '.table_prefix.'session_keys AS k
+                           LEFT JOIN '.table_prefix.'users AS u
+                             ON ( u.user_id=k.user_id )
+                           LEFT JOIN '.table_prefix.'users_extra AS x
+                             ON ( u.user_id=x.user_id OR x.user_id IS NULL )
+                           LEFT JOIN '.table_prefix.'privmsgs AS p
+                             ON ( p.message_to=u.username AND p.message_read=0 )
+                           WHERE k.session_key=\''.$keyhash.'\'
+                             AND k.salt=\''.$salt.'\'
+                           GROUP BY u.user_id;');
+    if($db->numrows() < 1)
+    {
+      // echo '(debug) $session->validate_session: Key was not found in database<br />';
+      return false;
+    }
+    $row = $db->fetchrow();
+    $row['user_id'] =& $row['uid'];
+    $ip = ip2hex($_SERVER['REMOTE_ADDR']);
+    if($row['auth_level'] > $row['user_level'])
+    {
+      // Failed authorization check
+      // echo '(debug) $session->validate_session: access to this auth level denied<br />';
+      return false;
+    }
+    if($ip != $row['source_ip'])
+    {
+      // Failed IP address check
+      // echo '(debug) $session->validate_session: IP address mismatch<br />';
+      return false;
+    }
+    
+    // Do the password validation
+    $real_pass = $aes->decrypt($row['password'], $this->private_key, ENC_HEX);
+    
+    //die('<pre>'.print_r($keydata, true).'</pre>');
+    if(sha1($real_pass) != $keydata[2])
+    {
+      // Failed password check
+      // echo '(debug) $session->validate_session: encrypted password is wrong<br />Real password: '.$real_pass.'<br />Real hash: '.sha1($real_pass).'<br />User hash: '.$keydata[2];
+      return false;
+    }
+    
+    $time_now = time();
+    $time_key = $row['time'] + 900;
+    if($time_now > $time_key && $row['auth_level'] > USER_LEVEL_MEMBER)
+    {
+      // Session timed out
+      // echo '(debug) $session->validate_session: super session timed out<br />';
+      $this->sw_timed_out = true;
+      return false;
+    }
+    
+    // If this is an elevated-access session key, update the time
+    if( $row['auth_level'] > USER_LEVEL_MEMBER )
+    {
+      $this->sql('UPDATE '.table_prefix.'session_keys SET time='.time().' WHERE session_key=\''.$keyhash.'\';');
+    }
+    
+    $row['password'] = md5($real_pass);
+    return $row;
+  }
+  
+  /**
+   * Validates a session key, and returns the userdata associated with the key or false. Optimized for compatibility with the old MD5-based auth system.
+   * @param string $key The session key to validate
+   * @return array Keys are 'user_id', 'username', 'email', 'real_name', 'user_level', 'theme', 'style', 'signature', 'reg_time', 'account_active', 'activation_key', and 'auth_level' or bool false if validation failed. The key 'auth_level' is the maximum authorization level that this key provides.
+   */
+   
+  function compat_validate_session($key)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $key = $db->escape($key);
+    
+    $query = $this->sql('SELECT u.user_id,u.username,u.password,u.email,u.real_name,u.user_level,k.source_ip,k.salt,k.time,k.auth_level FROM '.table_prefix.'session_keys AS k
+                           LEFT JOIN '.table_prefix.'users AS u
+                             ON u.user_id=k.user_id
+                           WHERE k.session_key=\''.$key.'\';');
+    if($db->numrows() < 1)
+    {
+      // echo '(debug) $session->validate_session: Key '.$key.' was not found in database<br />';
+      return false;
+    }
+    $row = $db->fetchrow();
+    $ip = ip2hex($_SERVER['REMOTE_ADDR']);
+    if($row['auth_level'] > $row['user_level'])
+    {
+      // Failed authorization check
+      // echo '(debug) $session->validate_session: user not authorized for this access level';
+      return false;
+    }
+    if($ip != $row['source_ip'])
+    {
+      // Failed IP address check
+      // echo '(debug) $session->validate_session: IP address mismatch; IP in table: '.$row['source_ip'].'; reported IP: '.$ip.'';
+      return false;
+    }
+    
+    // Do the password validation
+    $real_key = md5($row['password'] . $row['salt']);
+    
+    //die('<pre>'.print_r($keydata, true).'</pre>');
+    if($real_key != $key)
+    {
+      // Failed password check
+      // echo '(debug) $session->validate_session: supplied password is wrong<br />Real key: '.$real_key.'<br />User key: '.$key;
+      return false;
+    }
+    
+    $time_now = time();
+    $time_key = $row['time'] + 900;
+    if($time_now > $time_key && $row['auth_level'] >= 1)
+    {
+      $this->sw_timed_out = true;
+      // Session timed out
+      // echo '(debug) $session->validate_session: super session timed out<br />';
+      return false;
+    }
+    
+    return $row;
+  }
+   
+  /**
+   * Demotes us to one less than the specified auth level. AKA destroys elevated authentication and/or logs out the user, depending on $level
+   * @param int $level How low we should go - USER_LEVEL_MEMBER means demote to USER_LEVEL_GUEST, and anything more powerful than USER_LEVEL_MEMBER means demote to USER_LEVEL_MEMBER
+   * @return string 'success' if successful, or error on failure
+   */
+   
+  function logout($level = USER_LEVEL_MEMBER)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $ou = $this->username;
+    $oid = $this->user_id;
+    if($level > USER_LEVEL_CHPREF)
+    {
+      $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
+      if(!$this->user_logged_in || $this->auth_level < USER_LEVEL_MOD) return 'success';
+      // Destroy elevated privileges
+      $keyhash = md5(strrev($this->sid_super));
+      $this->sql('DELETE FROM '.table_prefix.'session_keys WHERE session_key=\''.$keyhash.'\' AND user_id=\'' . $this->user_id . '\';');
+      $this->sid_super = false;
+      $this->auth_level = USER_LEVEL_MEMBER;
+    }
+    else
+    {
+      if($this->user_logged_in)
+      {
+        // Completely destroy our session
+        if($this->auth_level > USER_LEVEL_CHPREF)
+        {
+          $this->logout(USER_LEVEL_ADMIN);
+        }
+        $this->sql('DELETE FROM '.table_prefix.'session_keys WHERE session_key=\''.md5($this->sid).'\';');
+        setcookie( 'sid', '', time()-(3600*24), scriptPath.'/' );
+      }
+    }
+    $code = $plugins->setHook('logout_success'); // , Array('level'=>$level,'old_username'=>$ou,'old_user_id'=>$oid));
+    foreach ( $code as $cmd )
+    {
+      eval($cmd);
+    }
+    return 'success';
+  }
+  
+  # Miscellaneous stuff
+  
+  /**
+   * Appends the high-privilege session key to the URL if we are authorized to do high-privilege stuff
+   * @param string $url The URL to add session data to
+   * @return string
+   */
+  
+  function append_sid($url)
+  {
+    $sep = ( strstr($url, '?') ) ? '&' : '?';
+    if ( $this->sid_super )
+    {
+      $url = $url . $sep . 'auth=' . urlencode($this->sid_super);
+      // echo($this->sid_super.'<br/>');
+    }
+    return $url;
+  }
+  
+  /**
+   * Grabs the user's password MD5
+   * @return string, or bool false if access denied
+   */
+   
+  function grab_password_hash()
+  {
+    if(!$this->password_hash) return false;
+    return $this->password_hash;
+  }
+  
+  /**
+   * Destroys the user's password MD5 in memory
+   */
+  
+  function disallow_password_grab()
+  {
+    $this->password_hash = false;
+    return false;
+  }
+  
+  /**
+   * Generates an AES key and stashes it in the database
+   * @return string Hex-encoded AES key
+   */
+   
+  function rijndael_genkey()
+  {
+    $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
+    $key = $aes->gen_readymade_key();
+    $keys = getConfig('login_key_cache');
+    if(is_string($keys))
+      $keys .= $key;
+    else
+      $keys = $key;
+    setConfig('login_key_cache', $keys);
+    return $key;
+  }
+  
+  /**
+   * Generate a totally random 128-bit value for MD5 challenges
+   * @return string
+   */
+   
+  function dss_rand()
+  {
+    $aes = new AESCrypt();
+    $random = $aes->randkey(128);
+    unset($aes);
+    return md5(microtime() . $random);
+  }
+  
+  /**
+   * Fetch a cached login public key using the MD5sum as an identifier. Each key can only be fetched once before it is destroyed.
+   * @param string $md5 The MD5 sum of the key
+   * @return string, or bool false on failure
+   */
+   
+  function fetch_public_key($md5)
+  {
+    $keys = getConfig('login_key_cache');
+    $keys = enano_str_split($keys, AES_BITS / 4);
+    
+    foreach($keys as $i => $k)
+    {
+      if(md5($k) == $md5)
+      {
+        unset($keys[$i]);
+        if(count($keys) > 0)
+        {
+          if ( strlen(getConfig('login_key_cache') ) > 64000 )
+          {
+            // This should only need to be done once every month or so for an average-size site
+            setConfig('login_key_cache', '');
+          }
+          else
+          {
+            $keys = implode('', array_values($keys));
+            setConfig('login_key_cache', $keys);
+          }
+        }
+        else
+        {
+          setConfig('login_key_cache', '');
+        }
+        return $k;
+      }
+    }
+    // Couldn't find the key...
+    return false;
+  }
+  
+  /**
+   * Adds a user to a group.
+   * @param int User ID
+   * @param int Group ID
+   * @param bool Group moderator - defaults to false
+   * @return bool True on success, false on failure
+   */
+  
+  function add_user_to_group($user_id, $group_id, $is_mod = false)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    // Validation
+    if ( !is_int($user_id) || !is_int($group_id) || !is_bool($is_mod) )
+      return false;
+    if ( $user_id < 1 || $group_id < 1 )
+      return false;
+    
+    $mod_switch = ( $is_mod ) ? '1' : '0';
+    $q = $this->sql('SELECT member_id,is_mod FROM '.table_prefix.'group_members WHERE user_id=' . $user_id . ' AND group_id=' . $group_id . ';');
+    if ( !$q )
+      $db->_die();
+    if ( $db->numrows() < 1 )
+    {
+      // User is not in group
+      $this->sql('INSERT INTO '.table_prefix.'group_members(user_id,group_id,is_mod) VALUES(' . $user_id . ', ' . $group_id . ', ' . $mod_switch . ');');
+      return true;
+    }
+    else
+    {
+      $row = $db->fetchrow();
+      // Update modship status
+      if ( strval($row['is_mod']) == $mod_switch )
+      {
+        // Modship unchanged
+        return true;
+      }
+      else
+      {
+        // Modship changed
+        $this->sql('UPDATE '.table_prefix.'group_members SET is_mod=' . $mod_switch . ' WHERE member_id=' . $row['member_id'] . ';');
+        return true;
+      }
+    }
+    return false;
+  }
+  
+  /**
+   * Removes a user from a group.
+   * @param int User ID
+   * @param int Group ID
+   * @return bool True on success, false on failure
+   * @todo put a little more error checking in...
+   */
+  
+  function remove_user_from_group($user_id, $group_id)
+  {
+    if ( !is_int($user_id) || !is_int($group_id) )
+      return false;
+    $this->sql('DELETE FROM '.table_prefix."group_members WHERE user_id=$user_id AND group_id=$group_id;");
+    return true;
+  }
+  
+  /**
+   * Checks the banlist to ensure that we're an allowed user. Doesn't return anything because it dies if the user is banned.
+   */
+   
+  function check_banlist()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if($this->compat)
+      $q = $this->sql('SELECT ban_id,ban_type,ban_value,is_regex FROM '.table_prefix.'banlist ORDER BY ban_type;');
+    else
+      $q = $this->sql('SELECT ban_id,ban_type,ban_value,is_regex,reason FROM '.table_prefix.'banlist ORDER BY ban_type;');
+    if(!$q) $db->_die('The banlist data could not be selected.');
+    $banned = false;
+    while($row = $db->fetchrow())
+    {
+      if($this->compat)
+        $row['reason'] = 'None available - session manager is in compatibility mode';
+      switch($row['ban_type'])
+      {
+      case BAN_IP:
+        if(intval($row['is_regex'])==1) {
+          if(preg_match('#'.$row['ban_value'].'#i', $_SERVER['REMOTE_ADDR']))
+          {
+            $banned = true;
+            $reason = $row['reason'];
+          }
+        }
+        else {
+          if($row['ban_value']==$_SERVER['REMOTE_ADDR']) { $banned = true; $reason = $row['reason']; }
+        }
+        break;
+      case BAN_USER:
+        if(intval($row['is_regex'])==1) {
+          if(preg_match('#'.$row['ban_value'].'#i', $this->username))
+          {
+            $banned = true;
+            $reason = $row['reason'];
+          }
+        }
+        else {
+          if($row['ban_value']==$this->username) { $banned = true; $reason = $row['reason']; }
+        }
+        break;
+      case BAN_EMAIL:
+        if(intval($row['is_regex'])==1) {
+          if(preg_match('#'.$row['ban_value'].'#i', $this->email))
+          {
+            $banned = true;
+            $reason = $row['reason'];
+          }
+        }
+        else {
+          if($row['ban_value']==$this->email) { $banned = true; $reason = $row['reason']; }
+        }
+        break;
+      default:
+        die('Ban error: rule "'.$row['ban_value'].'" has an invalid type ('.$row['ban_type'].')');
+      }
+    }
+    if($banned && $paths->get_pageid_from_url() != $paths->nslist['Special'].'CSS')
+    {
+      // This guy is banned - kill the session, kill the database connection, bail out, and be pretty about it
+      die_semicritical('Ban notice', '<div class="error-box">You have been banned from this website. Please contact the site administrator for more information.<br /><br />Reason:<br />'.$reason.'</div>');
+      exit;
+    }
+  }
+  
+  # Registration
+  
+  /**
+   * Registers a user. This does not perform any type of login.
+   * @param string $username
+   * @param string $password This should be unencrypted.
+   * @param string $email
+   * @param string $real_name Optional, defaults to ''.
+   */
+   
+  function create_user($username, $password, $email, $real_name = '') {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    // Initialize AES
+    $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
+    
+    if(!preg_match('#^'.$this->valid_username.'$#', $username)) return 'The username you chose contains invalid characters.';
+    $username = $this->prepare_text($username);
+    $email = $this->prepare_text($email);
+    $real_name = $this->prepare_text($real_name);
+    $password = $aes->encrypt($password, $this->private_key, ENC_HEX);
+    
+    $nameclause = ( $real_name != '' ) ? ' OR real_name=\''.$real_name.'\'' : '';
+    $q = $this->sql('SELECT * FROM '.table_prefix.'users WHERE lcase(username)=\''.strtolower($username).'\' OR email=\''.$email.'\''.$nameclause.';');
+    if($db->numrows() > 0) {
+      $r = 'The ';
+      $i=0;
+      $row = $db->fetchrow();
+      // Wow! An error checker that actually speaks English with the properest grammar! :-P
+      if($row['username'] == $username) { $r .= 'username'; $i++; }
+      if($row['email'] == $email) { if($i) $r.=', '; $r .= 'e-mail address'; $i++; }
+      if($row['real_name'] == $real_name && $real_name != '') { if($i) $r.=', and '; $r .= 'real name'; $i++; }
+      $r .= ' that you entered ';
+      $r .= ( $i == 1 ) ? 'is' : 'are';
+      $r .= ' already in use by another user.';
+      return $r;
+    }
+    
+    // Require the account to be activated?
+    switch(getConfig('account_activation'))
+    {
+      case 'none':
+      default:
+        $active = '1';
+        break;
+      case 'user':
+        $active = '0';
+        break;
+      case 'admin':
+        $active = '0';
+        break;
+    }
+    
+    // Generate a totally random activation key
+    $actkey = sha1 ( microtime() . mt_rand() );
+
+    // We good, create the user    
+    $this->sql('INSERT INTO '.table_prefix.'users ( username, password, email, real_name, theme, style, reg_time, account_active, activation_key, user_level ) VALUES ( \''.$username.'\', \''.$password.'\', \''.$email.'\', \''.$real_name.'\', \''.$template->default_theme.'\', \''.$template->default_style.'\', '.time().', '.$active.', \''.$actkey.'\', '.USER_LEVEL_CHPREF.' )');
+    
+    // Require the account to be activated?
+    switch(getConfig('account_activation'))
+    {
+      case 'none':
+      default:
+        break;
+      case 'user':
+        $a = $this->send_activation_mail($username);
+        if(!$a)
+        {
+          $this->admin_activation_request($username);
+          return 'The activation e-mail could not be sent due to an internal error. This could possibly be due to an incorrect SMTP configuration. A request has been sent to the administrator to activate your account for you. ' . $a;
+        }
+        break;
+      case 'admin':
+        $this->admin_activation_request($username);
+        break;
+    }
+    
+    // Leave some data behind for the hook
+    $code = $plugins->setHook('user_registered'); // , Array('username'=>$username));
+    foreach ( $code as $cmd )
+    {
+      eval($cmd);
+    }
+    
+    // $this->register_session($username, $password);
+    return 'success';
+  }
+  
+  /**
+   * Attempts to send an e-mail to the specified user with activation instructions.
+   * @param string $u The usernamd of the user requesting activation
+   * @return bool true on success, false on failure
+   */
+   
+  function send_activation_mail($u, $actkey = false)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $q = $this->sql('SELECT username,email FROM '.table_prefix.'users WHERE user_id=1 OR user_level=' . USER_LEVEL_ADMIN . ' ORDER BY user_id ASC;');
+    $un = $db->fetchrow();
+    $admin_user = $un['username'];
+    $q = $this->sql('SELECT username,activation_key,account_active,email FROM '.table_prefix.'users WHERE username=\''.$db->escape($u).'\';');
+    $r = $db->fetchrow();
+    if ( empty($r['email']) )
+      $db->_die('BUG: $session->send_activation_mail(): no e-mail address in row');
+    $message = 'Dear '.$u.',
+Thank you for registering on '.getConfig('site_name').'. Your account creation is almost complete. To complete the registration process, please click the following link or paste it into your web browser:
+    
+';
+    if(isset($_SERVER['HTTPS'])) $prot = 'https';
+    else $prot = 'http';                                                                           
+    if($_SERVER['SERVER_PORT'] == '80') $p = '';
+    else $p = ':'.$_SERVER['SERVER_PORT'];
+    $sidbak = false;
+    if($this->sid_super)
+      $sidbak = $this->sid_super;
+    $this->sid_super = false;
+    $aklink = makeUrlNS('Special', 'ActivateAccount/'.str_replace(' ', '_', $u).'/'. ( ( is_string($actkey) ) ? $actkey : $r['activation_key'] ) );
+    if($sidbak)
+      $this->sid_super = $sidbak;
+    unset($sidbak);
+    $message .= "$prot://".$_SERVER['HTTP_HOST'].$p.$aklink;
+      $message .= "\n\nSincerely yours, \n$admin_user and the ".$_SERVER['HTTP_HOST']." administration team";
+    error_reporting(E_ALL);
+    dc_dump($r, 'session: about to send activation e-mail to '.$r['email']);
+    if(getConfig('smtp_enabled') == '1')
+    {
+      $result = smtp_send_email($r['email'], getConfig('site_name').' website account activation', preg_replace("#(?<!\r)\n#s", "\n", $message), getConfig('contact_email'));
+      if($result == 'success') $result = true;
+      else { echo $result; $result = false; }
+    } else {
+      $result = mail($r['email'], getConfig('site_name').' website account activation', preg_replace("#(?<!\r)\n#s", "\n", $message), 'From: '.getConfig('contact_email'));
+    }
+    return $result;
+  }
+  
+  /**
+   * Sends an e-mail to a user so they can reset their password.
+   * @param int $user The user ID, or username if it's a string
+   * @return bool true on success, false on failure
+   */
+   
+  function mail_password_reset($user)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(is_int($user))
+    {
+      $q = $this->sql('SELECT user_id,username,email FROM '.table_prefix.'users WHERE user_id='.$user.';'); // This is SAFE! This is only called if $user is an integer
+    }
+    elseif(is_string($user))
+    {
+      $q = $this->sql('SELECT user_id,username,email FROM '.table_prefix.'users WHERE username=\''.$db->escape($user).'\';');
+    }
+    else
+    {
+      return false;
+    }
+    
+    $row = $db->fetchrow();
+    $temp_pass = $this->random_pass();
+    
+    $this->register_temp_password($row['user_id'], $temp_pass);
+    
+    $site_name = getConfig('site_name');
+    
+    $message = "Dear {$row['username']},
+    
+Someone (hopefully you) on the {$site_name} website requested that a new password be created.
+
+The request was sent from the IP address {$_SERVER['REMOTE_ADDR']}.
+
+If you did not request the new password, then you do not need to do anything; the password will be invalidated after 24 hours.
+
+If you did request this password, then please log in using the password shown below:
+
+  Password: {$temp_pass}
+  
+After you log in using this password, you will be able to reset your real password. You can only log in using this temporary password once.
+
+Sincerely yours,
+The {$site_name} administration team
+";
+    
+    if(getConfig('smtp_enabled') == '1')
+    {
+      $result = smtp_send_email($row['email'], getConfig('site_name').' password reset', preg_replace("#(?<!\r)\n#s", "\n", $message), getConfig('contact_email'));
+      if($result == 'success')
+      {
+        $result = true;
+      }
+      else
+      {
+        echo '<p>'.$result.'</p>';
+        $result = false;
+      }
+    } else {
+      $result = mail($row['email'], getConfig('site_name').' password reset', preg_replace("#(?<!\r)\n#s", "\n", $message), 'From: '.getConfig('contact_email'));
+    }
+    return $result;
+  }
+  
+  /**
+   * Sets the temporary password for the specified user to whatever is specified.
+   * @param int $user_id
+   * @param string $password
+   * @return bool
+   */
+   
+  function register_temp_password($user_id, $password)
+  {
+    $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
+    $temp_pass = $aes->encrypt($password, $this->private_key, ENC_HEX);
+    $this->sql('UPDATE '.table_prefix.'users SET temp_password=\'' . $temp_pass . '\',temp_password_time='.time().' WHERE user_id='.intval($user_id).';');
+  }
+  
+  /**
+   * Sends a request to the admin panel to have the username $u activated.
+   * @param string $u The username of the user requesting activation
+   */
+  
+  function admin_activation_request($u)
+  {
+    global $db;
+    $this->sql('INSERT INTO '.table_prefix.'logs(log_type, action, time_id, date_string, author, edit_summary) VALUES(\'admin\', \'activ_req\', '.time().', \''.date('d M Y h:i a').'\', \''.$this->username.'\', \''.$db->escape($u).'\');');
+  }
+  
+  /**
+   * Activates a user account. If the action fails, a report is sent to the admin.
+   * @param string $user The username of the user requesting activation
+   * @param string $key The activation key
+   */
+  
+  function activate_account($user, $key)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $this->sql('UPDATE '.table_prefix.'users SET account_active=1 WHERE username=\''.$db->escape($user).'\' AND activation_key=\''.$db->escape($key).'\';');
+    $r = mysql_affected_rows();
+    if ( $r > 0 )
+    {
+      $e = $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary) VALUES(\'security\', \'activ_good\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($user).'\', \''.$_SERVER['REMOTE_ADDR'].'\')');
+    }
+    else
+    {
+      $e = $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary) VALUES(\'security\', \'activ_bad\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($user).'\', \''.$_SERVER['REMOTE_ADDR'].'\')');
+    }
+    return $r;
+  }
+  
+  /**
+   * For a given user level identifier (USER_LEVEL_*), returns a string describing that user level.
+   * @param int User level
+   * @return string
+   */
+  
+  function userlevel_to_string($user_level)
+  {
+    switch ( $user_level )
+    {
+      case USER_LEVEL_GUEST:
+        return 'Low - guest privileges';
+      case USER_LEVEL_MEMBER:
+        return 'Standard - normal member level';
+      case USER_LEVEL_CHPREF:
+        return 'Medium - user can change his/her own e-mail address and password';
+      case USER_LEVEL_MOD:
+        return 'High - moderator privileges';
+      case USER_LEVEL_ADMIN:
+        return 'Highest - administrative privileges';
+      default:
+        return "Unknown ($user_level)";
+    }
+  }
+  
+  /**
+   * Updates a user's information in the database. Note that any of the values except $user_id can be false if you want to preserve the old values.
+   * @param int $user_id The user ID of the user to update - this cannot be changed
+   * @param string $username The new username
+   * @param string $old_pass The current password - only required if sessionManager::$user_level < USER_LEVEL_ADMIN. This should usually be an UNENCRYPTED string. This can also be an array - if it is, key 0 is treated as data AES-encrypted with key 1
+   * @param string $password The new password
+   * @param string $email The new e-mail address
+   * @param string $realname The new real name
+   * @param string $signature The updated forum/comment signature
+   * @param int $user_level The updated user level
+   * @return string 'success' if successful, or array of error strings on failure
+   */
+   
+  function update_user($user_id, $username = false, $old_pass = false, $password = false, $email = false, $realname = false, $signature = false, $user_level = false)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    // Create some arrays
+    
+    $errors = Array(); // Used to hold error strings
+    $strs = Array();   // Sub-query statements
+    
+    // Scan the user ID for problems
+    if(intval($user_id) < 1) $errors[] = 'SQL injection attempt';
+    
+    // Instanciate the AES encryption class
+    $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
+    
+    // If all of our input vars are false, then we've effectively done our job so get out of here
+    if($username === false && $password === false && $email === false && $realname === false && $signature === false && $user_level === false)
+    {
+   // echo 'debug: $session->update_user(): success (no changes requested)';
+      return 'success';
+    }
+    
+    // Initialize our authentication check
+    $authed = false;
+    
+    // Verify the inputted password
+    if(is_string($old_pass))
+    {
+      $q = $this->sql('SELECT password FROM '.table_prefix.'users WHERE user_id='.$user_id.';');
+      if($db->numrows() < 1)
+      {
+        $errors[] = 'The password data could not be selected for verification.';
+      }
+      else
+      {
+        $row = $db->fetchrow();
+        $real = $aes->decrypt($row['password'], $this->private_key, ENC_HEX);
+        if($real == $old_pass)
+          $authed = true;
+      }
+    }
+    
+    elseif(is_array($old_pass))
+    {
+      $old_pass = $aes->decrypt($old_pass[0], $old_pass[1]);
+      $q = $this->sql('SELECT password FROM '.table_prefix.'users WHERE user_id='.$user_id.';');
+      if($db->numrows() < 1)
+      {
+        $errors[] = 'The password data could not be selected for verification.';
+      }
+      else
+      {
+        $row = $db->fetchrow();
+        $real = $aes->decrypt($row['password'], $this->private_key, ENC_HEX);
+        if($real == $old_pass)
+          $authed = true;
+      }
+    }
+    
+    // Initialize our query
+    $q = 'UPDATE '.table_prefix.'users SET ';
+    
+    if($this->auth_level >= USER_LEVEL_ADMIN || $authed) // Need the current password in order to update the e-mail address, change the username, or reset the password
+    {
+      // Username
+      if(is_string($username))
+      {
+        // Check the username for problems
+        if(!preg_match('#^'.$this->valid_username.'$#', $username))
+          $errors[] = 'The username you entered contains invalid characters.';
+        $strs[] = 'username=\''.$db->escape($username).'\'';
+      }
+      // Password
+      if(is_string($password) && strlen($password) >= 6)
+      {
+        // Password needs to be encrypted before being stashed
+        $encpass = $aes->encrypt($password, $this->private_key, ENC_HEX);
+        if(!$encpass)
+          $errors[] = 'The password could not be encrypted due to an internal error.';
+        $strs[] = 'password=\''.$encpass.'\'';
+      }
+      // E-mail addy
+      if(is_string($email))
+      {
+        // I didn't write this regex.
+        if(!preg_match('/^(?:[\w\d]+\.?)+@(?:(?:[\w\d]\-?)+\.)+\w{2,4}$/', $email))
+          $errors[] = 'The e-mail address you entered is invalid.';
+        $strs[] = 'email=\''.$db->escape($email).'\'';
+      }
+    }
+    // Real name
+    if(is_string($realname))
+    {
+      $strs[] = 'real_name=\''.$db->escape($realname).'\'';
+    }
+    // Forum/comment signature
+    if(is_string($signature))
+    {
+      $strs[] = 'signature=\''.$db->escape($signature).'\'';
+    }
+    // User level
+    if(is_int($user_level))
+    {
+      $strs[] = 'user_level='.$user_level;
+    }
+    
+    // Add our generated query to the query string
+    $q .= implode(',', $strs);
+    
+    // One last error check
+    if(sizeof($strs) < 1) $errors[] = 'An internal error occured building the SQL query, this is a bug';
+    if(sizeof($errors) > 0) return $errors;
+    
+    // Free our temp arrays
+    unset($strs, $errors);
+    
+    // Finalize the query and run it
+    $q .= ' WHERE user_id='.$user_id.';';
+    $this->sql($q);
+    
+    // We also need to trigger re-activation.
+    if ( is_string($email) )
+    {
+      switch(getConfig('account_activation'))
+      {
+        case 'user':
+        case 'admin':
+          
+          if ( $session->user_level >= USER_LEVEL_MOD && getConfig('account_activation') == 'admin' )
+            // Don't require re-activation by admins for admins
+            break;
+          
+          // retrieve username
+          if ( !$username )
+          {
+            $q = $this->sql('SELECT username FROM '.table_prefix.'users WHERE user_id='.$user_id.';');
+            if($db->numrows() < 1)
+            {
+              $errors[] = 'The username could not be selected.';
+            }
+            else
+            {
+              $row = $db->fetchrow();
+              $username = $row['username'];
+            }
+          }
+          if ( !$username )
+            return $errors;
+          
+          // Generate a totally random activation key
+          $actkey = sha1 ( microtime() . mt_rand() );
+          $a = $this->send_activation_mail($username, $actkey);
+          if(!$a)
+          {
+            $this->admin_activation_request($username);
+          }
+          // Deactivate the account until e-mail is confirmed
+          $q = $db->sql_query('UPDATE '.table_prefix.'users SET account_active=0,activation_key=\'' . $actkey . '\' WHERE user_id=' . $user_id . ';');
+          break;
+      }
+    }
+    
+    // Yay! We're done
+    return 'success';
+  }
+  
+  #
+  # Access Control Lists
+  #
+  
+  /**
+   * Creates a new permission field in memory. If the permissions are set in the database, they are used. Otherwise, $default_perm is used.
+   * @param string $acl_type An identifier for this field
+   * @param int $default_perm Whether permission should be granted or not if it's not specified in the ACLs.
+   * @param string $desc A human readable name for the permission type
+   * @param array $deps The list of dependencies - this should be an array of ACL types
+   * @param string $scope Which namespaces this field should apply to. This should be either a pipe-delimited list of namespace IDs or just "All".
+   */
+   
+  function register_acl_type($acl_type, $default_perm = AUTH_DISALLOW, $desc = false, $deps = Array(), $scope = 'All')
+  {
+    if(isset($this->acl_types[$acl_type]))
+      return false;
+    else
+    {
+      if(!$desc)
+      {
+        $desc = capitalize_first_letter(str_replace('_', ' ', $acl_type));
+      }
+      $this->acl_types[$acl_type] = $default_perm;
+      $this->acl_descs[$acl_type] = $desc;
+      $this->acl_deps[$acl_type] = $deps;
+      $this->acl_scope[$acl_type] = explode('|', $scope);
+    }
+    return true;
+  }
+  
+  /**
+   * Tells us whether permission $type is allowed or not based on the current rules.
+   * @param string $type The permission identifier ($acl_type passed to sessionManager::register_acl_type())
+   * @param bool $no_deps If true, disables dependency checking
+   * @return bool True if allowed, false if denied or if an error occured
+   */
+   
+  function get_permissions($type, $no_deps = false)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if ( isset( $this->perms[$type] ) )
+    {
+      if ( $this->perms[$type] == AUTH_DENY )
+        $ret = false;
+      else if ( $this->perms[$type] == AUTH_WIKIMODE && $paths->wiki_mode )
+        $ret = true;
+      else if ( $this->perms[$type] == AUTH_WIKIMODE && !$paths->wiki_mode )
+        $ret = false;
+      else if ( $this->perms[$type] == AUTH_ALLOW )
+        $ret = true;
+      else if ( $this->perms[$type] == AUTH_DISALLOW )
+        $ret = false;
+    }
+    else if(isset($this->acl_types[$type]))
+    {
+      if ( $this->acl_types[$type] == AUTH_DENY )
+        $ret = false;
+      else if ( $this->acl_types[$type] == AUTH_WIKIMODE && $paths->wiki_mode )
+        $ret = true;
+      else if ( $this->acl_types[$type] == AUTH_WIKIMODE && !$paths->wiki_mode )
+        $ret = false;
+      else if ( $this->acl_types[$type] == AUTH_ALLOW )
+        $ret = true;
+      else if ( $this->acl_types[$type] == AUTH_DISALLOW )
+        $ret = false;
+    }
+    else
+    {
+      // ACL type is undefined
+      trigger_error('Unknown access type "' . $type . '"', E_USER_WARNING);
+      return false; // Be on the safe side and deny access
+    }
+    if ( !$no_deps )
+    {
+      if ( !$this->acl_check_deps($type) )
+        return false;
+    }
+    return $ret;
+  }
+  
+  /**
+   * Fetch the permissions that apply to the current user for the page specified. The object you get will have the get_permissions method
+   * and several other abilities.
+   * @param string $page_id
+   * @param string $namespace
+   * @return object
+   */
+   
+  function fetch_page_acl($page_id, $namespace)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    if ( count ( $this->acl_base_cache ) < 1 )
+    {
+      // Permissions table not yet initialized
+      return false;
+    }
+    
+    //if ( !isset( $paths->pages[$paths->nslist[$namespace] . $page_id] ) )
+    //{
+    //  // Page does not exist
+    //  return false;
+    //}
+    
+    $object = new Session_ACLPageInfo( $page_id, $namespace, $this->acl_types, $this->acl_descs, $this->acl_deps, $this->acl_base_cache );
+    
+    return $object;
+    
+  }
+  
+  /**
+   * Read all of our permissions from the database and process/apply them. This should be called after the page is determined.
+   * @access private
+   */
+  
+  function init_permissions()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    // Initialize the permissions list with some defaults
+    $this->perms = $this->acl_types;
+    $this->acl_defaults_used = $this->perms;
+    
+    // Fetch sitewide defaults from the permissions table
+    $bs = 'SELECT rules FROM '.table_prefix.'acl WHERE page_id IS NULL AND namespace IS NULL AND ( ';
+    
+    $q = Array();
+    $q[] = '( target_type='.ACL_TYPE_USER.' AND target_id='.$this->user_id.' )';
+    if(count($this->groups) > 0)
+    {
+      foreach($this->groups as $g_id => $g_name)
+      {
+        $q[] = '( target_type='.ACL_TYPE_GROUP.' AND target_id='.intval($g_id).' )';
+      }
+    }
+    $bs .= implode(' OR ', $q) . ' ) ORDER BY target_type ASC, target_id ASC;';
+    $q = $this->sql($bs);
+    if ( $row = $db->fetchrow() )
+    {
+      do {
+        $rules = $this->string_to_perm($row['rules']);
+        $is_everyone = ( $row['target_type'] == ACL_TYPE_GROUP && $row['target_id'] == 1 );
+        $this->acl_merge_with_current($rules, $is_everyone);
+      } while ( $row = $db->fetchrow() );
+    }
+    
+    // Eliminate types that don't apply to this namespace
+    foreach ( $this->perms AS $i => $perm )
+    {
+      if ( !in_array ( $paths->namespace, $this->acl_scope[$i] ) && !in_array('All', $this->acl_scope[$i]) )
+      {
+        unset($this->perms[$i]);
+      }
+    }
+    
+    // Cache the sitewide permissions for later use
+    $this->acl_base_cache = $this->perms;
+    
+    // Build a query to grab ACL info
+    $bs = 'SELECT rules,target_type,target_id FROM '.table_prefix.'acl WHERE ( ';
+    $q = Array();
+    $q[] = '( target_type='.ACL_TYPE_USER.' AND target_id='.$this->user_id.' )';
+    if(count($this->groups) > 0)
+    {
+      foreach($this->groups as $g_id => $g_name)
+      {
+        $q[] = '( target_type='.ACL_TYPE_GROUP.' AND target_id='.intval($g_id).' )';
+      }
+    }
+    // The reason we're using an ORDER BY statement here is because ACL_TYPE_GROUP is less than ACL_TYPE_USER, causing the user's individual
+    // permissions to override group permissions.
+    $bs .= implode(' OR ', $q) . ' ) AND ( page_id=\''.$db->escape($paths->cpage['urlname_nons']).'\' AND namespace=\''.$db->escape($paths->namespace).'\' )     
+      ORDER BY target_type ASC, page_id ASC, namespace ASC;';
+    $q = $this->sql($bs);
+    if ( $row = $db->fetchrow() )
+    {
+      do {
+        $rules = $this->string_to_perm($row['rules']);
+        $is_everyone = ( $row['target_type'] == ACL_TYPE_GROUP && $row['target_id'] == 1 );
+        $this->acl_merge_with_current($rules, $is_everyone);
+      } while ( $row = $db->fetchrow() );
+    }
+    
+  }
+  
+  /**
+   * Extends the scope of a permission type.
+   * @param string The name of the permission type
+   * @param string The namespace(s) that should be covered. This can be either one namespace ID or a pipe-delimited list.
+   * @param object Optional - the current $paths object, in case we're doing this from the acl_rule_init hook
+   */
+   
+  function acl_extend_scope($perm_type, $namespaces, &$p_in)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $p_obj = ( is_object($p_in) ) ? $p_in : $paths;
+    $nslist = explode('|', $namespaces);
+    foreach ( $nslist as $i => $ns )
+    {
+      if ( !isset($p_obj->nslist[$ns]) )
+      {
+        unset($nslist[$i]);
+      }
+      else
+      {
+        $this->acl_scope[$perm_type][] = $ns;
+        if ( isset($this->acl_types[$perm_type]) && !isset($this->perms[$perm_type]) )
+        {
+          $this->perms[$perm_type] = $this->acl_types[$perm_type];
+        }
+      }
+    }
+  }
+  
+  /**
+   * Converts a permissions field into a string for database insertion. Similar in spirit to serialize().
+   * @param array $perms An associative array with only integers as values
+   * @return string
+   */
+   
+  function perm_to_string($perms)
+  {
+    $s = '';
+    foreach($perms as $perm => $ac)
+    {
+      $s .= "$perm=$ac;";
+    }
+    return $s;
+  }
+  
+  /**
+   * Converts a permissions string back to an array.
+   * @param string $perms The result from sessionManager::perm_to_string()
+   * @return array
+   */
+   
+  function string_to_perm($perms)
+  {
+    $ret = Array();
+    preg_match_all('#([a-z0-9_-]+)=([0-9]+);#i', $perms, $matches);
+    foreach($matches[1] as $i => $t)
+    {
+      $ret[$t] = intval($matches[2][$i]);
+    }
+    return $ret;
+  }
+  
+  /**
+   * Merges two ACL arrays. Both parameters should be permission list arrays. The second group takes precedence over the first, but AUTH_DENY always prevails.
+   * @param array $perm1 The first set of permissions
+   * @param array $perm2 The second set of permissions
+   * @return array
+   */
+   
+  function acl_merge($perm1, $perm2)
+  {
+    $ret = $perm1;
+    foreach ( $perm2 as $type => $level )
+    {
+      if ( isset( $ret[$type] ) )
+      {
+        if ( $ret[$type] != AUTH_DENY )
+          $ret[$type] = $level;
+      }
+      // else
+      // {
+      //   $ret[$type] = $level;
+      // }
+    }
+    return $ret;
+  }
+  
+  /**
+   * Merges the ACL array sent with the current permissions table, deciding precedence based on whether defaults are in effect or not.
+   * @param array The array to merge into the master ACL list
+   * @param bool If true, $perm is treated as the "new default"
+   * @param int 1 if this is a site-wide ACL, 2 if page-specific. Defaults to 2.
+   */
+  
+  function acl_merge_with_current($perm, $is_everyone = false, $scope = 2)
+  {
+    foreach ( $this->perms as $i => $p )
+    {
+      if ( isset($perm[$i]) )
+      {
+        if ( $is_everyone && !$this->acl_defaults_used[$i] )
+          continue;
+        // Decide precedence
+        if ( isset($this->acl_defaults_used[$i]) )
+        {
+          //echo "$i: default in use, overriding to: {$perm[$i]}<br />";
+          // Defaults are in use, override
+          $this->perms[$i] = $perm[$i];
+          $this->acl_defaults_used[$i] = ( $is_everyone );
+        }
+        else
+        {
+          //echo "$i: default NOT in use";
+          // Defaults are not in use, merge as normal
+          if ( $this->perms[$i] != AUTH_DENY )
+          {
+            //echo ", but overriding";
+            $this->perms[$i] = $perm[$i];
+          }
+          //echo "<br />";
+        }
+      }
+    }
+  }
+  
+  /**
+   * Merges two ACL arrays. Both parameters should be permission list arrays. The second group takes precedence
+   * over the first, without exceptions. This is used to merge the hardcoded defaults with admin-specified
+   * defaults, which take precedence.
+   * @param array $perm1 The first set of permissions
+   * @param array $perm2 The second set of permissions
+   * @return array
+   */
+   
+  function acl_merge_complete($perm1, $perm2)
+  {
+    $ret = $perm1;
+    foreach ( $perm2 as $type => $level )
+    {
+      $ret[$type] = $level;
+    }
+    return $ret;
+  }
+  
+  /**
+   * Tell us if the dependencies for a given permission are met.
+   * @param string The ACL permission ID
+   * @return bool
+   */
+   
+  function acl_check_deps($type)
+  {
+    if(!isset($this->acl_deps[$type])) // This will only happen if the permissions table is hacked or improperly accessed
+      return true;
+    if(sizeof($this->acl_deps[$type]) < 1)
+      return true;
+    $deps = $this->acl_deps[$type];
+    while(true)
+    {
+      $full_resolved = true;
+      $j = sizeof($deps);
+      for ( $i = 0; $i < $j; $i++ )
+      {
+        $b = $deps;
+        $deps = array_merge($deps, $this->acl_deps[$deps[$i]]);
+        if( $b == $deps )
+        {
+          break 2;
+        }
+        $j = sizeof($deps);
+      }
+    }
+    //die('<pre>'.print_r($deps, true).'</pre>');
+    foreach($deps as $d)
+    {
+      if ( !$this->get_permissions($d) )
+      {
+        return false;
+      }
+    }
+    return true;
+  }
+  
+  /**
+   * Makes a CAPTCHA code and caches the code in the database
+   * @param int $len The length of the code, in bytes
+   * @return string A unique identifier assigned to the code. This hash should be passed to sessionManager::getCaptcha() to retrieve the code.
+   */
+  
+  function make_captcha($len = 7)
+  {
+    $chars = array('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '1', '2', '3', '4', '5', '6', '7', '8', '9');
+    $s = '';
+    for($i=0;$i<$len;$i++) $s .= $chars[mt_rand(0, count($chars)-1)];
+    $hash = md5(microtime() . mt_rand());
+    $this->sql('INSERT INTO '.table_prefix.'session_keys(session_key,salt,auth_level,source_ip,user_id) VALUES(\''.$hash.'\', \''.$s.'\', -1, \''.ip2hex($_SERVER['REMOTE_ADDR']).'\', -2);');
+    return $hash;
+  }
+  
+  /**
+   * For the given code ID, returns the correct CAPTCHA code, or false on failure
+   * @param string $hash The unique ID assigned to the code
+   * @return string The correct confirmation code
+   */
+  
+  function get_captcha($hash)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $s = $this->sql('SELECT salt FROM '.table_prefix.'session_keys WHERE session_key=\''.$db->escape($hash).'\' AND source_ip=\''.ip2hex($_SERVER['REMOTE_ADDR']).'\';');
+    if($db->numrows() < 1) return false;
+    $r = $db->fetchrow();
+    return $r['salt'];
+  }
+  
+  /**
+   * Deletes all CAPTCHA codes cached in the DB for this user.
+   */
+  
+  function kill_captcha()
+  {
+    $this->sql('DELETE FROM '.table_prefix.'session_keys WHERE user_id=-2 AND source_ip=\''.ip2hex($_SERVER['REMOTE_ADDR']).'\';');
+  }
+  
+  /**
+   * Generates a random password.
+   * @param int $length Optional - length of password
+   * @return string
+   */
+   
+  function random_pass($length = 10)
+  {
+    $valid_chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_+@#%&<>';
+    $valid_chars = enano_str_split($valid_chars);
+    $ret = '';
+    for ( $i = 0; $i < $length; $i++ )
+    {
+      $ret .= $valid_chars[mt_rand(0, count($valid_chars)-1)];
+    }
+    return $ret;
+  }
+  
+  /**
+   * Generates some Javascript that calls the AES encryption library.
+   * @param string The name of the form
+   * @param string The name of the password field
+   * @param string The name of the field that switches encryption on or off
+   * @param string The name of the field that contains the encryption key
+   * @param string The name of the field that will contain the encrypted password
+   * @param string The name of the field that handles MD5 challenge data
+   * @return string
+   */
+   
+  function aes_javascript($form_name, $pw_field, $use_crypt, $crypt_key, $crypt_data, $challenge)
+  {
+    $code = '
+      <script type="text/javascript">
+        disableJSONExts();
+          str = \'\';
+          for(i=0;i<keySizeInBits/4;i++) str+=\'0\';
+          var key = hexToByteArray(str);
+          var pt = hexToByteArray(str);
+          var ct = rijndaelEncrypt(pt, key, \'ECB\');
+          var ct = byteArrayToHex(ct);
+          switch(keySizeInBits)
+          {
+            case 128:
+              v = \'66e94bd4ef8a2c3b884cfa59ca342b2e\';
+              break;
+            case 192:
+              v = \'aae06992acbf52a3e8f4a96ec9300bd7aae06992acbf52a3e8f4a96ec9300bd7\';
+              break;
+            case 256:
+              v = \'dc95c078a2408989ad48a21492842087dc95c078a2408989ad48a21492842087\';
+              break;
+          }
+          var testpassed = ' . ( ( isset($_GET['use_crypt']) && $_GET['use_crypt']=='0') ? 'false; // CRYPTO-AUTH DISABLED ON USER REQUEST // ' : '' ) . '( ct == v && md5_vm_test() );
+          var frm = document.forms.'.$form_name.';
+          if(testpassed)
+          {
+            frm.'.$use_crypt.'.value = \'yes\';
+            var cryptkey = frm.'.$crypt_key.'.value;
+            frm.'.$crypt_key.'.value = hex_md5(cryptkey);
+            cryptkey = hexToByteArray(cryptkey);
+            if(!cryptkey || ( ( typeof cryptkey == \'string\' || typeof cryptkey == \'object\' ) ) && cryptkey.length != keySizeInBits / 8 )
+            {
+              if ( frm._login ) frm._login.disabled = true;
+              len = ( typeof cryptkey == \'string\' || typeof cryptkey == \'object\' ) ? \'\\nLen: \'+cryptkey.length : \'\';
+              alert(\'The key is messed up\\nType: \'+typeof(cryptkey)+len);
+            }
+          }
+          if(frm.username) frm.username.focus();
+          function runEncryption()
+          {
+            if(testpassed)
+            {
+              pass = frm.'.$pw_field.'.value;
+              chal = frm.'.$challenge.'.value;
+              challenge = hex_md5(pass + chal) + chal;
+              frm.'.$challenge.'.value = challenge;
+              pass = stringToByteArray(pass);
+              cryptstring = rijndaelEncrypt(pass, cryptkey, \'ECB\');
+              if(!cryptstring)
+              {
+                return false;
+              }
+              cryptstring = byteArrayToHex(cryptstring);
+              frm.'.$crypt_data.'.value = cryptstring;
+              frm.'.$pw_field.'.value = \'\';
+            }
+            return false;
+          }
+        </script>
+        ';
+    return $code;
+  }
+  
+}
+
+/**
+ * Class used to fetch permissions for a specific page. Used internally by SessionManager.
+ * @package Enano
+ * @subpackage Session manager
+ * @license http://www.gnu.org/copyleft/gpl.html
+ * @access private
+ */
+ 
+class Session_ACLPageInfo {
+  
+  /**
+   * The page ID of this ACL info package
+   * @var string
+   */
+   
+  var $page_id;
+  
+  /**
+   * The namespace of the page being checked
+   * @var string
+   */
+   
+  var $namespace;
+  
+  /**
+   * Our list of permission types.
+   * @access private
+   * @var array
+   */
+   
+  var $acl_types = Array();
+  
+  /**
+   * The list of descriptions for the permission types
+   * @var array
+   */
+   
+  var $acl_descs = Array();
+  
+  /**
+   * A list of dependencies for ACL types.
+   * @var array
+   */
+   
+  var $acl_deps = Array();
+  
+  /**
+   * Our tell-all list of permissions.
+   * @access private - or, preferably, protected...too bad this has to be PHP4 compatible
+   * @var array
+   */
+   
+  var $perms = Array();
+  
+  /**
+   * Constructor.
+   * @param string $page_id The ID of the page to check
+   * @param string $namespace The namespace of the page to check.
+   * @param array $acl_types List of ACL types
+   * @param array $acl_descs List of human-readable descriptions for permissions (associative)
+   * @param array $acl_deps List of dependencies for permissions. For example, viewing history/diffs depends on the ability to read the page.
+   * @param array $base What to start with - this is an attempt to reduce the number of SQL queries.
+   */
+   
+  function Session_ACLPageInfo($page_id, $namespace, $acl_types, $acl_descs, $acl_deps, $base)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    $this->perms = $session->acl_merge_complete($acl_types, $base);
+    $this->acl_deps = $acl_deps;
+    $this->acl_types = $acl_types;
+    $this->acl_descs = $acl_descs;
+    
+    // Build a query to grab ACL info
+    $bs = 'SELECT rules FROM '.table_prefix.'acl WHERE ( ';
+    $q = Array();
+    $q[] = '( target_type='.ACL_TYPE_USER.' AND target_id='.$session->user_id.' )';
+    if(count($session->groups) > 0)
+    {
+      foreach($session->groups as $g_id => $g_name)
+      {
+        $q[] = '( target_type='.ACL_TYPE_GROUP.' AND target_id='.intval($g_id).' )';
+      }
+    }
+    // The reason we're using an ORDER BY statement here is because ACL_TYPE_GROUP is less than ACL_TYPE_USER, causing the user's individual
+    // permissions to override group permissions.
+    $bs .= implode(' OR ', $q) . ' ) AND ( page_id=\''.$db->escape($page_id).'\' AND namespace=\''.$db->escape($namespace).'\' )     
+      ORDER BY target_type ASC, page_id ASC, namespace ASC;';
+    $q = $session->sql($bs);
+    if ( $row = $db->fetchrow() )
+    {
+      do {
+        $rules = $session->string_to_perm($row['rules']);
+        $this->perms = $session->acl_merge($this->perms, $rules);
+      } while ( $row = $db->fetchrow() );
+    }
+    
+    $this->page_id = $page_id;
+    $this->namespace = $namespace;
+  }
+  
+  /**
+   * Tells us whether permission $type is allowed or not based on the current rules.
+   * @param string $type The permission identifier ($acl_type passed to sessionManager::register_acl_type())
+   * @param bool $no_deps If true, disables dependency checking
+   * @return bool True if allowed, false if denied or if an error occured
+   */
+   
+  function get_permissions($type, $no_deps = false)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if ( isset( $this->perms[$type] ) )
+    {
+      if ( $this->perms[$type] == AUTH_DENY )
+        $ret = false;
+      else if ( $this->perms[$type] == AUTH_WIKIMODE &&
+        ( isset($paths->pages[$paths->nslist[$this->namespace].$this->page_id]) && 
+          ( $paths->pages[$paths->nslist[$this->namespace].$this->page_id]['wiki_mode'] == '1' ||
+            ( $paths->pages[$paths->nslist[$this->namespace].$this->page_id]['wiki_mode'] == '2'
+              && getConfig('wiki_mode') == '1'
+          ) ) ) )
+        $ret = true;
+      else if ( $this->perms[$type] == AUTH_WIKIMODE && (
+        !isset($paths->pages[$paths->nslist[$this->namespace].$this->page_id])
+        || (
+          isset($paths->pages[$paths->nslist[$this->namespace].$this->page_id]) && (
+            $paths->pages[$paths->nslist[$this->namespace].$this->page_id]['wiki_mode'] == '0'
+            || (
+              $paths->pages[$paths->nslist[$this->namespace].$this->page_id]['wiki_mode'] == '2' && getConfig('wiki_mode') != '1'
+          ) ) ) ) )
+        $ret = false;
+      else if ( $this->perms[$type] == AUTH_ALLOW )
+        $ret = true;
+      else if ( $this->perms[$type] == AUTH_DISALLOW )
+        $ret = false;
+    }
+    else if(isset($this->acl_types[$type]))
+    {
+      if ( $this->acl_types[$type] == AUTH_DENY )
+        $ret = false;
+      else if ( $this->acl_types[$type] == AUTH_WIKIMODE && $paths->wiki_mode )
+        $ret = true;
+      else if ( $this->acl_types[$type] == AUTH_WIKIMODE && !$paths->wiki_mode )
+        $ret = false;
+      else if ( $this->acl_types[$type] == AUTH_ALLOW )
+        $ret = true;
+      else if ( $this->acl_types[$type] == AUTH_DISALLOW )
+        $ret = false;
+    }
+    else
+    {
+      // ACL type is undefined
+      trigger_error('Unknown access type "' . $type . '"', E_USER_WARNING);
+      return false; // Be on the safe side and deny access
+    }
+    if ( !$no_deps )
+    {
+      if ( !$this->acl_check_deps($type) )
+        return false;
+    }
+    return $ret;
+  }
+  
+  /**
+   * Tell us if the dependencies for a given permission are met.
+   * @param string The ACL permission ID
+   * @return bool
+   */
+   
+  function acl_check_deps($type)
+  {
+    if(!isset($this->acl_deps[$type])) // This will only happen if the permissions table is hacked or improperly accessed
+      return true;
+    if(sizeof($this->acl_deps[$type]) < 1)
+      return true;
+    $deps = $this->acl_deps[$type];
+    while(true)
+    {
+      $full_resolved = true;
+      $j = sizeof($deps);
+      for ( $i = 0; $i < $j; $i++ )
+      {
+        $b = $deps;
+        $deps = array_merge($deps, $this->acl_deps[$deps[$i]]);
+        if( $b == $deps )
+        {
+          break 2;
+        }
+        $j = sizeof($deps);
+      }
+    }
+    //die('<pre>'.print_r($deps, true).'</pre>');
+    foreach($deps as $d)
+    {
+      if ( !$this->get_permissions($d) )
+      {
+        return false;
+      }
+    }
+    return true;
+  }
+  
+}
+
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/sessions.php~	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,2425 @@
+<?php
+
+/*
+ * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
+ * Version 1.0 (Banshee)
+ * Copyright (C) 2006-2007 Dan Fuhry
+ * sessions.php - everything related to security and user management
+ *
+ * This program is Free Software; you can redistribute 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 details.
+ */
+ 
+// Prepare a string for insertion into a MySQL database
+function filter($str) { return $db->escape($str); }
+
+/**
+ * Anything and everything related to security and user management. This includes AES encryption, which is illegal in some countries.
+ * Documenting the API was not easy - I hope you folks enjoy it.
+ * @package Enano
+ * @subpackage Session manager
+ * @category security, user management, logins, etc.
+ */
+
+class sessionManager {
+  
+  # Variables
+  
+  /**
+   * Whether we're logged in or not
+   * @var bool
+   */
+   
+  var $user_logged_in = false;
+  
+  /**
+   * Our current low-privilege session key
+   * @var string
+   */
+  
+  var $sid;
+  
+  /**
+   * Username of currently logged-in user, or IP address if not logged in
+   * @var string
+   */
+  
+  var $username;
+  
+  /**
+   * User ID of currently logged-in user, or -1 if not logged in
+   * @var int
+   */
+  
+  var $user_id;
+  
+  /**
+   * Real name of currently logged-in user, or blank if not logged in
+   * @var string
+   */
+  
+  var $real_name;
+  
+  /**
+   * E-mail address of currently logged-in user, or blank if not logged in
+   * @var string
+   */
+  
+  var $email;
+  
+  /**
+   * User level of current user
+   * USER_LEVEL_GUEST: guest
+   * USER_LEVEL_MEMBER: regular user
+   * USER_LEVEL_CHPREF: default - pseudo-level that allows changing password and e-mail address (requires re-authentication)
+   * USER_LEVEL_MOD: moderator
+   * USER_LEVEL_ADMIN: administrator
+   * @var int
+   */
+  
+  var $user_level;
+  
+  /**
+   * High-privilege session key
+   * @var string or false if not running on high-level authentication
+   */
+  
+  var $sid_super;
+  
+  /**
+   * The user's theme preference, defaults to $template->default_theme
+   * @var string
+   */
+  
+  var $theme;
+  
+  /**
+   * The user's style preference, or style auto-detected based on theme if not logged in
+   * @var string
+   */
+  
+  var $style;
+  
+  /**
+   * Signature of current user - appended to comments, etc.
+   * @var string
+   */
+  
+  var $signature;
+  
+  /**
+   * UNIX timestamp of when we were registered, or 0 if not logged in
+   * @var int
+   */
+  
+  var $reg_time;
+  
+  /**
+   * MD5 hash of the current user's password, if applicable
+   * @var string OR bool false
+   */
+   
+  var $password_hash;
+  
+  /**
+   * The number of unread private messages this user has.
+   * @var int
+   */
+  
+  var $unread_pms = 0;
+  
+  /**
+   * AES key used to encrypt passwords and session key info - irreversibly destroyed when disallow_password_grab() is called
+   * @var string
+   */
+   
+  var $private_key;
+  
+  /**
+   * Regex that defines a valid username, minus the ^ and $, these are added later
+   * @var string
+   */
+   
+   var $valid_username = '([A-Za-z0-9 \!\@\(\)-]+)';
+   
+  /**
+   * What we're allowed to do as far as permissions go. This changes based on the value of the "auth" URI param.
+   * @var string
+   */
+   
+  var $auth_level = -1;
+  
+  /**
+   * State variable to track if a session timed out
+   * @var bool
+   */
+  
+  var $sw_timed_out = false;
+  
+  /**
+   * Switch to track if we're started or not.
+   * @access private
+   * @var bool
+   */
+   
+  var $started = false;
+  
+  /**
+   * Switch to control compatibility mode (for older Enano websites being upgraded)
+   * @access private
+   * @var bool
+   */
+   
+  var $compat = false;
+  
+  /**
+   * Our list of permission types.
+   * @access private
+   * @var array
+   */
+   
+  var $acl_types = Array();
+  
+  /**
+   * The list of descriptions for the permission types
+   * @var array
+   */
+   
+  var $acl_descs = Array();
+  
+  /**
+   * A list of dependencies for ACL types.
+   * @var array
+   */
+   
+  var $acl_deps = Array();
+  
+  /**
+   * Our tell-all list of permissions.
+   * @access private - or, preferably, protected
+   * @var array
+   */
+   
+  var $perms = Array();
+  
+  /**
+   * A cache variable - saved after sitewide permissions are checked but before page-specific permissions.
+   * @var array
+   * @access private
+   */
+  
+  var $acl_base_cache = Array();
+  
+  /**
+   * Stores the scope information for ACL types.
+   * @var array
+   * @access private
+   */
+   
+  var $acl_scope = Array();
+  
+  /**
+   * Array to track which default permissions are being used
+   * @var array
+   * @access private
+   */
+   
+  var $acl_defaults_used = Array();
+  
+  /**
+   * Array to track group membership.
+   * @var array
+   */
+   
+  var $groups = Array();
+  
+  /**
+   * Associative array to track group modship.
+   * @var array
+   */
+   
+  var $group_mod = Array();
+  
+  # Basic functions
+   
+  /**
+   * Constructor.
+   */
+   
+  function __construct()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    include(ENANO_ROOT.'/config.php');
+    unset($dbhost, $dbname, $dbuser, $dbpasswd);
+    if(isset($crypto_key))
+    {
+      $this->private_key = $crypto_key;
+      $this->private_key = hexdecode($this->private_key);
+    }
+    else
+    {
+      if(is_writable(ENANO_ROOT.'/config.php'))
+      {
+        // Generate and stash a private key
+        // This should only happen during an automated silent gradual migration to the new encryption platform.
+        $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
+        $this->private_key = $aes->gen_readymade_key();
+        
+        $config = file_get_contents(ENANO_ROOT.'/config.php');
+        if(!$config)
+        {
+          die('$session->__construct(): can\'t get the contents of config.php');
+        }
+        
+        $config = str_replace("?>", "\$crypto_key = '{$this->private_key}';\n?>", $config);
+        // And while we're at it...
+        $config = str_replace('MIDGET_INSTALLED', 'ENANO_INSTALLED', $config);
+        $fh = @fopen(ENANO_ROOT.'/config.php', 'w');
+        if ( !$fh ) 
+        {
+          die('$session->__construct(): Couldn\'t open config file for writing to store the private key, I tried to avoid something like this...');
+        }
+        
+        fwrite($fh, $config);
+        fclose($fh);
+      }
+      else
+      {
+        die_semicritical('Crypto error', '<p>No private key was found in the config file, and we can\'t generate one because we don\'t have write access to the config file. Please CHMOD config.php to 666 or 777 and reload this page.</p>');
+      }
+    }
+    // Check for compatibility mode
+    if(defined('IN_ENANO_INSTALL'))
+    {
+      $q = $db->sql_query('SELECT old_encryption FROM '.table_prefix.'users LIMIT 1;');
+      if(!$q)
+      {
+        $error = mysql_error();
+        if(strstr($error, "Unknown column 'old_encryption'"))
+          $this->compat = true;
+        else
+          $db->_die('This should never happen and is a bug - the only error that was supposed to happen here didn\'t happen. (sessions.php in constructor, during compat mode check)');
+      }
+      $db->free_result();
+    }
+  }
+  
+  /**
+   * PHP 4 compatible constructor.
+   */
+   
+  function sessionManager()
+  {
+    $this->__construct();
+  }
+  
+  /**
+   * Wrapper function to sanitize strings for MySQL and HTML
+   * @param string $text The text to sanitize
+   * @return string
+   */
+  
+  function prepare_text($text)
+  {
+    global $db;
+    return $db->escape(htmlspecialchars($text));
+  }
+  
+  /**
+   * Makes a SQL query and handles error checking
+   * @param string $query The SQL query to make
+   * @return resource
+   */
+  
+  function sql($query)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $result = $db->sql_query($query);
+    if(!$result)
+    {
+      $db->_die('The error seems to have occurred somewhere in the session management code.');
+    }
+    return $result;
+  }
+  
+  # Session restoration and permissions
+  
+  /**
+   * Initializes the basic state of things, including most user prefs, login data, cookie stuff
+   */
+  
+  function start()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if($this->started) return;
+    $this->started = true;
+    $user = false;
+    if(isset($_COOKIE['sid']))
+    {
+      if($this->compat)
+      {
+        $userdata = $this->compat_validate_session($_COOKIE['sid']);
+      }
+      else
+      {
+        $userdata = $this->validate_session($_COOKIE['sid']);
+      }
+      if(is_array($userdata))
+      {
+        $data = RenderMan::strToPageID($paths->get_pageid_from_url());
+        
+        if(!$this->compat && $userdata['account_active'] != 1 && $data[1] != 'Special' && $data[1] != 'Admin')
+        {
+          $this->logout();
+          $a = getConfig('account_activation');
+          switch($a)
+          {
+            case 'none':
+            default:
+              $solution = 'Your account was most likely deactivated by an administrator. Please contact the site administration for further assistance.';
+              break;
+            case 'user':
+              $solution = 'Please check your e-mail; you should have been sent a message with instructions on how to activate your account. If you do not receive an e-mail from this site within 24 hours, please contact the site administration for further assistance.';
+              break;
+            case 'admin':
+              $solution = 'This website has been configured so that all user accounts must be activated by the administrator before they can be used, so your account will most likely be activated the next time the one of the administrators visits the site.';
+              break;
+          }
+          die_semicritical('Account error', '<p>It appears that your user account has not yet been activated. '.$solution.'</p>');
+        }
+        
+        $this->sid = $_COOKIE['sid'];
+        $this->user_logged_in = true;
+        $this->user_id =       intval($userdata['user_id']);
+        $this->username =      $userdata['username'];
+        $this->password_hash = $userdata['password'];
+        $this->user_level =    intval($userdata['user_level']);
+        $this->real_name =     $userdata['real_name'];
+        $this->email =         $userdata['email'];
+        $this->unread_pms =    $userdata['num_pms'];
+        if(!$this->compat)
+        {
+          $this->theme =         $userdata['theme'];
+          $this->style =         $userdata['style'];
+          $this->signature =     $userdata['signature'];
+          $this->reg_time =      $userdata['reg_time'];
+        }
+        // Small security risk here - it allows someone who has already authenticated as an administrator to store the "super" key in
+        // the cookie. Change this to USER_LEVEL_MEMBER to override that. The same 15-minute restriction applies to this "exploit".
+        $this->auth_level =    $userdata['auth_level'];
+        if(!isset($template->named_theme_list[$this->theme]))
+        {
+          if($this->compat || !is_object($template))
+          {
+            $this->theme = 'oxygen';
+            $this->style = 'bleu';
+          }
+          else
+          {
+            $this->theme = $template->default_theme;
+            $this->style = $template->default_style;
+          }
+        }
+        $user = true;
+        
+        if(isset($_REQUEST['auth']) && !$this->sid_super)
+        {
+          // Now he thinks he's a moderator. Or maybe even an administrator. Let's find out if he's telling the truth.
+          if($this->compat)
+          {
+            $key = $_REQUEST['auth'];
+            $super = $this->compat_validate_session($key);
+          }
+          else
+          {
+            $key = strrev($_REQUEST['auth']);
+            $super = $this->validate_session($key);
+          }
+          if(is_array($super))
+          {
+            $this->auth_level = intval($super['auth_level']);
+            $this->sid_super = $_REQUEST['auth'];
+          }
+        }
+      }
+    }
+    if(!$user)
+    {
+      //exit;
+      $this->register_guest_session();
+    }
+    if(!$this->compat)
+    {
+      // init groups
+      $q = $this->sql('SELECT g.group_name,g.group_id,m.is_mod FROM '.table_prefix.'groups AS g
+          LEFT JOIN '.table_prefix.'group_members AS m
+            ON g.group_id=m.group_id
+          WHERE ( m.user_id='.$this->user_id.' 
+            OR g.group_name=\'Everyone\')
+            ' . ( enano_version() == '1.0RC1' ? '' : 'AND ( m.pending != 1 OR m.pending IS NULL )' ) . '
+          ORDER BY group_id ASC;'); // Make sure "Everyone" comes first so the permissions can be overridden
+      if($row = $db->fetchrow())
+      {
+        do {
+          $this->groups[$row['group_id']] = $row['group_name'];
+          $this->group_mod[$row['group_id']] = ( intval($row['is_mod']) == 1 );
+        } while($row = $db->fetchrow());
+      }
+      else
+      {
+        die('No group info');
+      }
+    }
+    $this->check_banlist();
+    
+    if ( isset ( $_GET['printable'] ) )
+    {
+      $this->theme = 'printable';
+      $this->style = 'default';
+    }
+    
+  }
+  
+  # Logins
+  
+  /**
+   * Attempts to perform a login using crypto functions
+   * @param string $username The username
+   * @param string $aes_data The encrypted password, hex-encoded
+   * @param string $aes_key The MD5 hash of the encryption key, hex-encoded
+   * @param string $challenge The 256-bit MD5 challenge string - first 128 bits should be the hash, the last 128 should be the challenge salt
+   * @param int $level The privilege level we're authenticating for, defaults to 0
+   * @return string 'success' on success, or error string on failure
+   */
+   
+  function login_with_crypto($username, $aes_data, $aes_key, $challenge, $level = USER_LEVEL_MEMBER)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    $privcache = $this->private_key;
+    
+    // Instanciate the Rijndael encryption object
+    $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
+    
+    // Fetch our decryption key
+    
+    $aes_key = $this->fetch_public_key($aes_key);
+    if(!$aes_key)
+      return 'Couldn\'t look up public key "'.$aes_key.'" for decryption';
+    
+    // Convert the key to a binary string
+    $bin_key = hexdecode($aes_key);
+    
+    if(strlen($bin_key) != AES_BITS / 8)
+      return 'The decryption key is the wrong length';
+    
+    // Decrypt our password
+    $password = $aes->decrypt($aes_data, $bin_key, ENC_HEX);
+    
+    // Initialize our success switch
+    $success = false;
+    
+    // Select the user data from the table, and decrypt that so we can verify the password
+    $this->sql('SELECT password,old_encryption,user_id,user_level,theme,style,temp_password,temp_password_time FROM '.table_prefix.'users WHERE lcase(username)=\''.$this->prepare_text(strtolower($username)).'\';');
+    if($db->numrows() < 1)
+      return 'The username and/or password is incorrect.';
+    $row = $db->fetchrow();
+    
+    // Check to see if we're logging in using a temporary password
+    
+    if((intval($row['temp_password_time']) + 3600*24) > time() )
+    {
+      $temp_pass = $aes->decrypt( $row['temp_password'], $this->private_key, ENC_HEX );
+      if( $temp_pass == $password )
+      {
+        $url = makeUrlComplete('Special', 'PasswordReset/stage2/' . $row['user_id'] . '/' . $row['temp_password']);
+        redirect($url, 'Login sucessful', 'Please wait while you are transferred to the Password Reset form.');
+        exit;
+      }
+    }
+    
+    if($row['old_encryption'] == 1)
+    {
+      // The user's password is stored using the obsolete and insecure MD5 algorithm, so we'll update the field with the new password
+      if(md5($password) == $row['password'])
+      {
+        $pass_stashed = $aes->encrypt($password, $this->private_key, ENC_HEX);
+        $this->sql('UPDATE '.table_prefix.'users SET password=\''.$pass_stashed.'\',old_encryption=0 WHERE user_id='.$row['user_id'].';');
+        $success = true;
+      }
+    }
+    else
+    {
+      // Our password field is up-to-date with the >=1.0RC1 encryption standards, so decrypt the password in the table and see if we have a match; if so then do challenge authentication
+      $real_pass = $aes->decrypt(hexdecode($row['password']), $this->private_key, ENC_BINARY);
+      if($password == $real_pass)
+      {
+        // Yay! We passed AES authentication, now do an MD5 challenge check to make sure we weren't spoofed
+        $chal = substr($challenge, 0, 32);
+        $salt = substr($challenge, 32, 32);
+        $correct_challenge = md5( $real_pass . $salt );
+        if($chal == $correct_challenge)
+          $success = true;
+      }
+    }
+    if($success)
+    {
+      if($level > $row['user_level'])
+        return 'You are not authorized for this level of access.';
+      
+      $sess = $this->register_session(intval($row['user_id']), $username, $password, $level);
+      if($sess)
+      {
+        $this->username = $username;
+        $this->user_id = intval($row['user_id']);
+        $this->theme = $row['theme'];
+        $this->style = $row['style'];
+        
+        if($level > USER_LEVEL_MEMBER)
+          $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary,page_text) VALUES(\'security\', \'admin_auth_good\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\', ' . intval($level) . ')');
+        else
+          $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary) VALUES(\'security\', \'auth_good\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\')');
+        
+        $code = $plugins->setHook('login_success');
+        foreach ( $code as $cmd )
+        {
+          eval($cmd);
+        }
+        return 'success';
+      }
+      else
+        return 'Your login credentials were correct, but an internal error occurred while registering the session key in the database.';
+    }
+    else
+    {
+      if($level > USER_LEVEL_MEMBER)
+        $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary,page_text) VALUES(\'security\', \'admin_auth_bad\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\', ' . intval($level) . ')');
+      else
+        $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary) VALUES(\'security\', \'auth_bad\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\')');
+        
+      return 'The username and/or password is incorrect.';
+    }
+  }
+  
+  /**
+   * Attempts to login without using crypto stuff, mainly for use when the other side doesn't like Javascript
+   * This method of authentication is inherently insecure, there's really nothing we can do about it except hope and pray that everyone moves to Firefox
+   * Technically it still uses crypto, but it only decrypts the password already stored, which is (obviously) required for authentication
+   * @param string $username The username
+   * @param string $password The password -OR- the MD5 hash of the password if $already_md5ed is true
+   * @param bool $already_md5ed This should be set to true if $password is an MD5 hash, and should be false if it's plaintext. Defaults to false.
+   * @param int $level The privilege level we're authenticating for, defaults to 0
+   */
+  
+  function login_without_crypto($username, $password, $already_md5ed = false, $level = USER_LEVEL_MEMBER)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    $pass_hashed = ( $already_md5ed ) ? $password : md5($password);
+    
+    // Perhaps we're upgrading Enano?
+    if($this->compat)
+    {
+      return $this->login_compat($username, $pass_hashed, $level);
+    }
+    
+    // Instanciate the Rijndael encryption object
+    $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
+    
+    // Initialize our success switch
+    $success = false;
+    
+    // Retrieve the real password from the database
+    $this->sql('SELECT password,old_encryption,user_id,user_level,temp_password,temp_password_time FROM '.table_prefix.'users WHERE lcase(username)=\''.$this->prepare_text(strtolower($username)).'\';');
+    if($db->numrows() < 1)
+      return 'The username and/or password is incorrect.';
+    $row = $db->fetchrow();
+    
+    // Check to see if we're logging in using a temporary password
+    
+    if((intval($row['temp_password_time']) + 3600*24) > time() )
+    {
+      $temp_pass = $aes->decrypt( $row['temp_password'], $this->private_key, ENC_HEX );
+      if( md5($temp_pass) == $pass_hashed )
+      {
+        header('Location: ' . makeUrlComplete('Special', 'PasswordReset/stage2/' . $row['user_id'] . '/' . $row['temp_password']) );
+        exit;
+      }
+    }
+    
+    if($row['old_encryption'] == 1)
+    {
+      // The user's password is stored using the obsolete and insecure MD5 algorithm - we'll update the field with the new password
+      if($pass_hashed == $row['password'] && !$already_md5ed)
+      {
+        $pass_stashed = $aes->encrypt($password, $this->private_key, ENC_HEX);
+        $this->sql('UPDATE '.table_prefix.'users SET password=\''.$pass_stashed.'\',old_encryption=0 WHERE user_id='.$row['user_id'].';');
+        $success = true;
+      }
+      elseif($pass_hashed == $row['password'] && $already_md5ed)
+      {
+        // We don't have the real password so don't bother with encrypting it, just call it success and get out of here
+        $success = true;
+      }
+    }
+    else
+    {
+      // Our password field is up-to-date with the >=1.0RC1 encryption standards, so decrypt the password in the table and see if we have a match
+      $real_pass = $aes->decrypt($row['password'], $this->private_key);
+      if($pass_hashed == md5($real_pass))
+      {
+        $success = true;
+      }
+    }
+    if($success)
+    {
+      if((int)$level > (int)$row['user_level'])
+        return 'You are not authorized for this level of access.';
+      $sess = $this->register_session(intval($row['user_id']), $username, $real_pass, $level);
+      if($sess)
+      {
+        if($level > USER_LEVEL_MEMBER)
+          $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary,page_text) VALUES(\'security\', \'admin_auth_good\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\', ' . intval($level) . ')');
+        else
+          $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary) VALUES(\'security\', \'auth_good\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\')');
+        
+        $code = $plugins->setHook('login_success');
+        foreach ( $code as $cmd )
+        {
+          eval($cmd);
+        }
+        return 'success';
+      }
+      else
+        return 'Your login credentials were correct, but an internal error occured while registering the session key in the database.';
+    }
+    else
+    {
+      if($level > USER_LEVEL_MEMBER)
+        $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary,page_text) VALUES(\'security\', \'admin_auth_bad\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\', ' . intval($level) . ')');
+      else
+        $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary) VALUES(\'security\', \'auth_bad\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\')');
+        
+      return 'The username and/or password is incorrect.';
+    }
+  }
+  
+  /**
+   * Attempts to log in using the old table structure and algorithm.
+   * @param string $username
+   * @param string $password This should be an MD5 hash
+   * @return string 'success' if successful, or error message on failure
+   */
+  
+  function login_compat($username, $password, $level = 0)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $pass_hashed =& $password;
+    $this->sql('SELECT password,user_id,user_level FROM '.table_prefix.'users WHERE username=\''.$this->prepare_text($username).'\';');
+    if($db->numrows() < 1)
+      return 'The username and/or password is incorrect.';
+    $row = $db->fetchrow();
+    if($row['password'] == $password)
+    {
+      if((int)$level > (int)$row['user_level'])
+        return 'You are not authorized for this level of access.';
+      $sess = $this->register_session_compat(intval($row['user_id']), $username, $password, $level);
+      if($sess)
+        return 'success';
+      else
+        return 'Your login credentials were correct, but an internal error occured while registering the session key in the database.';
+    }
+    else
+    {
+      return 'The username and/or password is incorrect.';
+    }
+  }
+  
+  /**
+   * Registers a session key in the database. This function *ASSUMES* that the username and password have already been validated!
+   * Basically the session key is a base64-encoded cookie (encrypted with the site's private key) that says "u=[username];p=[sha1 of password]"
+   * @param int $user_id
+   * @param string $username
+   * @param string $password
+   * @param int $level The level of access to grant, defaults to USER_LEVEL_MEMBER
+   * @return bool
+   */
+   
+  function register_session($user_id, $username, $password, $level = USER_LEVEL_MEMBER)
+  {
+    $salt = md5(microtime() . mt_rand());
+    $passha1 = sha1($password);
+    $session_key = "u=$username;p=$passha1;s=$salt";
+    $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
+    $session_key = $aes->encrypt($session_key, $this->private_key, ENC_HEX);
+    if($level > USER_LEVEL_MEMBER)
+    {
+      $hexkey = strrev($session_key);
+      $this->sid_super = $hexkey;
+      $_GET['auth'] = $hexkey;
+    }
+    else
+    {
+      setcookie( 'sid', $session_key, time()+315360000, scriptPath.'/' );
+      $_COOKIE['sid'] = $session_key;
+    }
+    $keyhash = md5($session_key);
+    $ip = ip2hex($_SERVER['REMOTE_ADDR']);
+    if(!$ip)
+      die('$session->register_session: Remote-Addr was spoofed');
+    $time = time();
+    if(!is_int($user_id))
+      die('Somehow an SQL injection attempt crawled into our session registrar! (1)');
+    if(!is_int($level))
+      die('Somehow an SQL injection attempt crawled into our session registrar! (2)');
+    
+    $query = $this->sql('INSERT INTO '.table_prefix.'session_keys(session_key, salt, user_id, auth_level, source_ip, time) VALUES(\''.$keyhash.'\', \''.$salt.'\', '.$user_id.', '.$level.', \''.$ip.'\', '.$time.');');
+    return true;
+  }
+  
+  /**
+   * Identical to register_session in nature, but uses the old login/table structure. DO NOT use this.
+   * @see sessionManager::register_session()
+   * @access private
+   */
+  
+  function register_session_compat($user_id, $username, $password, $level = 0)
+  {
+    $salt = md5(microtime() . mt_rand());
+    $thekey = md5($password . $salt);
+    if($level > 0)
+    {
+      $this->sid_super = $thekey;
+    }
+    else
+    {
+      setcookie( 'sid', $thekey, time()+315360000, scriptPath.'/' );
+      $_COOKIE['sid'] = $thekey;
+    }
+    $ip = ip2hex($_SERVER['REMOTE_ADDR']);
+    if(!$ip)
+      die('$session->register_session: Remote-Addr was spoofed');
+    $time = time();
+    if(!is_int($user_id))
+      die('Somehow an SQL injection attempt crawled into our session registrar! (1)');
+    if(!is_int($level))
+      die('Somehow an SQL injection attempt crawled into our session registrar! (2)');
+    $query = $this->sql('INSERT INTO '.table_prefix.'session_keys(session_key, salt, user_id, auth_level, source_ip, time) VALUES(\''.$thekey.'\', \''.$salt.'\', '.$user_id.', '.$level.', \''.$ip.'\', '.$time.');');
+    return true;
+  }
+  
+  /**
+   * Creates/restores a guest session
+   * @todo implement real session management for guests
+   */
+   
+  function register_guest_session()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $this->username = $_SERVER['REMOTE_ADDR'];
+    $this->user_level = USER_LEVEL_GUEST;
+    if($this->compat || defined('IN_ENANO_INSTALL'))
+    {
+      $this->theme = 'oxygen';
+      $this->style = 'bleu';
+    }
+    else
+    {
+      $this->theme = ( isset($_GET['theme']) && isset($template->named_theme_list[$_GET['theme']])) ? $_GET['theme'] : $template->default_theme;
+      $this->style = ( isset($_GET['style']) && file_exists(ENANO_ROOT.'/themes/'.$this->theme . '/css/'.$_GET['style'].'.css' )) ? $_GET['style'] : substr($template->named_theme_list[$this->theme]['default_style'], 0, strlen($template->named_theme_list[$this->theme]['default_style'])-4);
+    }
+    $this->user_id = 1;
+  }
+  
+  /**
+   * Validates a session key, and returns the userdata associated with the key or false
+   * @param string $key The session key to validate
+   * @return array Keys are 'user_id', 'username', 'email', 'real_name', 'user_level', 'theme', 'style', 'signature', 'reg_time', 'account_active', 'activation_key', and 'auth_level' or bool false if validation failed. The key 'auth_level' is the maximum authorization level that this key provides.
+   */
+   
+  function validate_session($key)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE, true);
+    $decrypted_key = $aes->decrypt($key, $this->private_key, ENC_HEX);
+    
+    if ( !$decrypted_key )
+    {
+      die_semicritical('AES encryption error', '<p>Something went wrong during the AES decryption process.</p><pre>'.print_r($decrypted_key, true).'</pre>');
+    }
+    
+    $n = preg_match('/^u='.$this->valid_username.';p=([A-Fa-f0-9]+?);s=([A-Fa-f0-9]+?)$/', $decrypted_key, $keydata);
+    if($n < 1)
+    {
+      // echo '(debug) $session->validate_session: Key does not match regex<br />Decrypted key: '.$decrypted_key;
+      return false;
+    }
+    $keyhash = md5($key);
+    $salt = $db->escape($keydata[3]);
+    $query = $this->sql('SELECT u.user_id AS uid,u.username,u.password,u.email,u.real_name,u.user_level,u.theme,u.style,u.signature,u.reg_time,u.account_active,u.activation_key,k.source_ip,k.time,k.auth_level,COUNT(p.message_id) AS num_pms,x.* FROM '.table_prefix.'session_keys AS k
+                           LEFT JOIN '.table_prefix.'users AS u
+                             ON ( u.user_id=k.user_id )
+                           LEFT JOIN '.table_prefix.'users_extra AS x
+                             ON ( u.user_id=x.user_id OR x.user_id IS NULL )
+                           LEFT JOIN '.table_prefix.'privmsgs AS p
+                             ON ( p.message_to=u.username AND p.message_read=0 )
+                           WHERE k.session_key=\''.$keyhash.'\'
+                             AND k.salt=\''.$salt.'\'
+                           GROUP BY u.user_id;');
+    if($db->numrows() < 1)
+    {
+      // echo '(debug) $session->validate_session: Key was not found in database<br />';
+      return false;
+    }
+    $row = $db->fetchrow();
+    $row['user_id'] =& $row['uid'];
+    $ip = ip2hex($_SERVER['REMOTE_ADDR']);
+    if($row['auth_level'] > $row['user_level'])
+    {
+      // Failed authorization check
+      // echo '(debug) $session->validate_session: access to this auth level denied<br />';
+      return false;
+    }
+    if($ip != $row['source_ip'])
+    {
+      // Failed IP address check
+      // echo '(debug) $session->validate_session: IP address mismatch<br />';
+      return false;
+    }
+    
+    // Do the password validation
+    $real_pass = $aes->decrypt($row['password'], $this->private_key, ENC_HEX);
+    
+    //die('<pre>'.print_r($keydata, true).'</pre>');
+    if(sha1($real_pass) != $keydata[2])
+    {
+      // Failed password check
+      // echo '(debug) $session->validate_session: encrypted password is wrong<br />Real password: '.$real_pass.'<br />Real hash: '.sha1($real_pass).'<br />User hash: '.$keydata[2];
+      return false;
+    }
+    
+    $time_now = time();
+    $time_key = $row['time'] + 900;
+    if($time_now > $time_key && $row['auth_level'] > USER_LEVEL_MEMBER)
+    {
+      // Session timed out
+      // echo '(debug) $session->validate_session: super session timed out<br />';
+      $this->sw_timed_out = true;
+      return false;
+    }
+    
+    // If this is an elevated-access session key, update the time
+    if( $row['auth_level'] > USER_LEVEL_MEMBER )
+    {
+      $this->sql('UPDATE '.table_prefix.'session_keys SET time='.time().' WHERE session_key=\''.$keyhash.'\';');
+    }
+    
+    $row['password'] = md5($real_pass);
+    return $row;
+  }
+  
+  /**
+   * Validates a session key, and returns the userdata associated with the key or false. Optimized for compatibility with the old MD5-based auth system.
+   * @param string $key The session key to validate
+   * @return array Keys are 'user_id', 'username', 'email', 'real_name', 'user_level', 'theme', 'style', 'signature', 'reg_time', 'account_active', 'activation_key', and 'auth_level' or bool false if validation failed. The key 'auth_level' is the maximum authorization level that this key provides.
+   */
+   
+  function compat_validate_session($key)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $key = $db->escape($key);
+    
+    $query = $this->sql('SELECT u.user_id,u.username,u.password,u.email,u.real_name,u.user_level,k.source_ip,k.salt,k.time,k.auth_level FROM '.table_prefix.'session_keys AS k
+                           LEFT JOIN '.table_prefix.'users AS u
+                             ON u.user_id=k.user_id
+                           WHERE k.session_key=\''.$key.'\';');
+    if($db->numrows() < 1)
+    {
+      // echo '(debug) $session->validate_session: Key '.$key.' was not found in database<br />';
+      return false;
+    }
+    $row = $db->fetchrow();
+    $ip = ip2hex($_SERVER['REMOTE_ADDR']);
+    if($row['auth_level'] > $row['user_level'])
+    {
+      // Failed authorization check
+      // echo '(debug) $session->validate_session: user not authorized for this access level';
+      return false;
+    }
+    if($ip != $row['source_ip'])
+    {
+      // Failed IP address check
+      // echo '(debug) $session->validate_session: IP address mismatch; IP in table: '.$row['source_ip'].'; reported IP: '.$ip.'';
+      return false;
+    }
+    
+    // Do the password validation
+    $real_key = md5($row['password'] . $row['salt']);
+    
+    //die('<pre>'.print_r($keydata, true).'</pre>');
+    if($real_key != $key)
+    {
+      // Failed password check
+      // echo '(debug) $session->validate_session: supplied password is wrong<br />Real key: '.$real_key.'<br />User key: '.$key;
+      return false;
+    }
+    
+    $time_now = time();
+    $time_key = $row['time'] + 900;
+    if($time_now > $time_key && $row['auth_level'] >= 1)
+    {
+      $this->sw_timed_out = true;
+      // Session timed out
+      // echo '(debug) $session->validate_session: super session timed out<br />';
+      return false;
+    }
+    
+    return $row;
+  }
+   
+  /**
+   * Demotes us to one less than the specified auth level. AKA destroys elevated authentication and/or logs out the user, depending on $level
+   * @param int $level How low we should go - USER_LEVEL_MEMBER means demote to USER_LEVEL_GUEST, and anything more powerful than USER_LEVEL_MEMBER means demote to USER_LEVEL_MEMBER
+   * @return string 'success' if successful, or error on failure
+   */
+   
+  function logout($level = USER_LEVEL_MEMBER)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $ou = $this->username;
+    $oid = $this->user_id;
+    if($level > USER_LEVEL_CHPREF)
+    {
+      $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
+      if(!$this->user_logged_in || $this->auth_level < USER_LEVEL_MOD) return 'success';
+      // Destroy elevated privileges
+      $keyhash = md5(strrev($this->sid_super));
+      $this->sql('DELETE FROM '.table_prefix.'session_keys WHERE session_key=\''.$keyhash.'\' AND user_id=\'' . $this->user_id . '\';');
+      $this->sid_super = false;
+      $this->auth_level = USER_LEVEL_MEMBER;
+    }
+    else
+    {
+      if($this->user_logged_in)
+      {
+        // Completely destroy our session
+        if($this->auth_level > USER_LEVEL_CHPREF)
+        {
+          $this->logout(USER_LEVEL_ADMIN);
+        }
+        $this->sql('DELETE FROM '.table_prefix.'session_keys WHERE session_key=\''.md5($this->sid).'\';');
+        setcookie( 'sid', '', time()-(3600*24), scriptPath.'/' );
+      }
+    }
+    $code = $plugins->setHook('logout_success'); // , Array('level'=>$level,'old_username'=>$ou,'old_user_id'=>$oid));
+    foreach ( $code as $cmd )
+    {
+      eval($cmd);
+    }
+    return 'success';
+  }
+  
+  # Miscellaneous stuff
+  
+  /**
+   * Appends the high-privilege session key to the URL if we are authorized to do high-privilege stuff
+   * @param string $url The URL to add session data to
+   * @return string
+   */
+  
+  function append_sid($url)
+  {
+    $sep = ( strstr($url, '?') ) ? '&' : '?';
+    if ( $this->sid_super )
+    {
+      $url = $url . $sep . 'auth=' . urlencode($this->sid_super);
+      // echo($this->sid_super.'<br/>');
+    }
+    return $url;
+  }
+  
+  /**
+   * Grabs the user's password MD5
+   * @return string, or bool false if access denied
+   */
+   
+  function grab_password_hash()
+  {
+    if(!$this->password_hash) return false;
+    return $this->password_hash;
+  }
+  
+  /**
+   * Destroys the user's password MD5 in memory
+   */
+  
+  function disallow_password_grab()
+  {
+    $this->password_hash = false;
+    return false;
+  }
+  
+  /**
+   * Generates an AES key and stashes it in the database
+   * @return string Hex-encoded AES key
+   */
+   
+  function rijndael_genkey()
+  {
+    $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
+    $key = $aes->gen_readymade_key();
+    $keys = getConfig('login_key_cache');
+    if(is_string($keys))
+      $keys .= $key;
+    else
+      $keys = $key;
+    setConfig('login_key_cache', $keys);
+    return $key;
+  }
+  
+  /**
+   * Generate a totally random 128-bit value for MD5 challenges
+   * @return string
+   */
+   
+  function dss_rand()
+  {
+    $aes = new AESCrypt();
+    $random = $aes->randkey(128);
+    unset($aes);
+    return md5(microtime() . $random);
+  }
+  
+  /**
+   * Fetch a cached login public key using the MD5sum as an identifier. Each key can only be fetched once before it is destroyed.
+   * @param string $md5 The MD5 sum of the key
+   * @return string, or bool false on failure
+   */
+   
+  function fetch_public_key($md5)
+  {
+    $keys = getConfig('login_key_cache');
+    $keys = enano_str_split($keys, AES_BITS / 4);
+    
+    foreach($keys as $i => $k)
+    {
+      if(md5($k) == $md5)
+      {
+        unset($keys[$i]);
+        if(count($keys) > 0)
+        {
+          if ( strlen(getConfig('login_key_cache') ) > 64000 )
+          {
+            // This should only need to be done once every month or so for an average-size site
+            setConfig('login_key_cache', '');
+          }
+          else
+          {
+            $keys = implode('', array_values($keys));
+            setConfig('login_key_cache', $keys);
+          }
+        }
+        else
+        {
+          setConfig('login_key_cache', '');
+        }
+        return $k;
+      }
+    }
+    // Couldn't find the key...
+    return false;
+  }
+  
+  /**
+   * Adds a user to a group.
+   * @param int User ID
+   * @param int Group ID
+   * @param bool Group moderator - defaults to false
+   * @return bool True on success, false on failure
+   */
+  
+  function add_user_to_group($user_id, $group_id, $is_mod = false)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    // Validation
+    if ( !is_int($user_id) || !is_int($group_id) || !is_bool($is_mod) )
+      return false;
+    if ( $user_id < 1 || $group_id < 1 )
+      return false;
+    
+    $mod_switch = ( $is_mod ) ? '1' : '0';
+    $q = $this->sql('SELECT member_id,is_mod FROM '.table_prefix.'group_members WHERE user_id=' . $user_id . ' AND group_id=' . $group_id . ';');
+    if ( !$q )
+      $db->_die();
+    if ( $db->numrows() < 1 )
+    {
+      // User is not in group
+      $this->sql('INSERT INTO '.table_prefix.'group_members(user_id,group_id,is_mod) VALUES(' . $user_id . ', ' . $group_id . ', ' . $mod_switch . ');');
+      return true;
+    }
+    else
+    {
+      $row = $db->fetchrow();
+      // Update modship status
+      if ( strval($row['is_mod']) == $mod_switch )
+      {
+        // Modship unchanged
+        return true;
+      }
+      else
+      {
+        // Modship changed
+        $this->sql('UPDATE '.table_prefix.'group_members SET is_mod=' . $mod_switch . ' WHERE member_id=' . $row['member_id'] . ';');
+        return true;
+      }
+    }
+    return false;
+  }
+  
+  /**
+   * Removes a user from a group.
+   * @param int User ID
+   * @param int Group ID
+   * @return bool True on success, false on failure
+   * @todo put a little more error checking in...
+   */
+  
+  function remove_user_from_group($user_id, $group_id)
+  {
+    if ( !is_int($user_id) || !is_int($group_id) )
+      return false;
+    $this->sql('DELETE FROM '.table_prefix."group_members WHERE user_id=$user_id AND group_id=$group_id;");
+    return true;
+  }
+  
+  /**
+   * Checks the banlist to ensure that we're an allowed user. Doesn't return anything because it dies if the user is banned.
+   */
+   
+  function check_banlist()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if($this->compat)
+      $q = $this->sql('SELECT ban_id,ban_type,ban_value,is_regex FROM '.table_prefix.'banlist ORDER BY ban_type;');
+    else
+      $q = $this->sql('SELECT ban_id,ban_type,ban_value,is_regex,reason FROM '.table_prefix.'banlist ORDER BY ban_type;');
+    if(!$q) $db->_die('The banlist data could not be selected.');
+    $banned = false;
+    while($row = $db->fetchrow())
+    {
+      if($this->compat)
+        $row['reason'] = 'None available - session manager is in compatibility mode';
+      switch($row['ban_type'])
+      {
+      case BAN_IP:
+        if(intval($row['is_regex'])==1) {
+          if(preg_match('#'.$row['ban_value'].'#i', $_SERVER['REMOTE_ADDR']))
+          {
+            $banned = true;
+            $reason = $row['reason'];
+          }
+        }
+        else {
+          if($row['ban_value']==$_SERVER['REMOTE_ADDR']) { $banned = true; $reason = $row['reason']; }
+        }
+        break;
+      case BAN_USER:
+        if(intval($row['is_regex'])==1) {
+          if(preg_match('#'.$row['ban_value'].'#i', $this->username))
+          {
+            $banned = true;
+            $reason = $row['reason'];
+          }
+        }
+        else {
+          if($row['ban_value']==$this->username) { $banned = true; $reason = $row['reason']; }
+        }
+        break;
+      case BAN_EMAIL:
+        if(intval($row['is_regex'])==1) {
+          if(preg_match('#'.$row['ban_value'].'#i', $this->email))
+          {
+            $banned = true;
+            $reason = $row['reason'];
+          }
+        }
+        else {
+          if($row['ban_value']==$this->email) { $banned = true; $reason = $row['reason']; }
+        }
+        break;
+      default:
+        die('Ban error: rule "'.$row['ban_value'].'" has an invalid type ('.$row['ban_type'].')');
+      }
+    }
+    if($banned && $paths->get_pageid_from_url() != $paths->nslist['Special'].'CSS')
+    {
+      // This guy is banned - kill the session, kill the database connection, bail out, and be pretty about it
+      die_semicritical('Ban notice', '<div class="error-box">You have been banned from this website. Please contact the site administrator for more information.<br /><br />Reason:<br />'.$reason.'</div>');
+      exit;
+    }
+  }
+  
+  # Registration
+  
+  /**
+   * Registers a user. This does not perform any type of login.
+   * @param string $username
+   * @param string $password This should be unencrypted.
+   * @param string $email
+   * @param string $real_name Optional, defaults to ''.
+   */
+   
+  function create_user($username, $password, $email, $real_name = '') {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    // Initialize AES
+    $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
+    
+    if(!preg_match('#^'.$this->valid_username.'$#', $username)) return 'The username you chose contains invalid characters.';
+    $username = $this->prepare_text($username);
+    $email = $this->prepare_text($email);
+    $real_name = $this->prepare_text($real_name);
+    $password = $aes->encrypt($password, $this->private_key, ENC_HEX);
+    
+    $nameclause = ( $real_name != '' ) ? ' OR real_name=\''.$real_name.'\'' : '';
+    $q = $this->sql('SELECT * FROM '.table_prefix.'users WHERE lcase(username)=\''.strtolower($username).'\' OR email=\''.$email.'\''.$nameclause.';');
+    if($db->numrows() > 0) {
+      $r = 'The ';
+      $i=0;
+      $row = $db->fetchrow();
+      // Wow! An error checker that actually speaks English with the properest grammar! :-P
+      if($row['username'] == $username) { $r .= 'username'; $i++; }
+      if($row['email'] == $email) { if($i) $r.=', '; $r .= 'e-mail address'; $i++; }
+      if($row['real_name'] == $real_name && $real_name != '') { if($i) $r.=', and '; $r .= 'real name'; $i++; }
+      $r .= ' that you entered ';
+      $r .= ( $i == 1 ) ? 'is' : 'are';
+      $r .= ' already in use by another user.';
+      return $r;
+    }
+    
+    // Require the account to be activated?
+    switch(getConfig('account_activation'))
+    {
+      case 'none':
+      default:
+        $active = '1';
+        break;
+      case 'user':
+        $active = '0';
+        break;
+      case 'admin':
+        $active = '0';
+        break;
+    }
+    
+    // Generate a totally random activation key
+    $actkey = sha1 ( microtime() . mt_rand() );
+
+    // We good, create the user    
+    $this->sql('INSERT INTO '.table_prefix.'users ( username, password, email, real_name, theme, style, reg_time, account_active, activation_key, user_level ) VALUES ( \''.$username.'\', \''.$password.'\', \''.$email.'\', \''.$real_name.'\', \''.$template->default_theme.'\', \''.$template->default_style.'\', '.time().', '.$active.', \''.$actkey.'\', '.USER_LEVEL_CHPREF.' )');
+    
+    // Require the account to be activated?
+    switch(getConfig('account_activation'))
+    {
+      case 'none':
+      default:
+        break;
+      case 'user':
+        $a = $this->send_activation_mail($username);
+        if(!$a)
+        {
+          $this->admin_activation_request($username);
+          return 'The activation e-mail could not be sent due to an internal error. This could possibly be due to an incorrect SMTP configuration. A request has been sent to the administrator to activate your account for you. ' . $a;
+        }
+        break;
+      case 'admin':
+        $this->admin_activation_request($username);
+        break;
+    }
+    
+    // Leave some data behind for the hook
+    $code = $plugins->setHook('user_registered'); // , Array('username'=>$username));
+    foreach ( $code as $cmd )
+    {
+      eval($cmd);
+    }
+    
+    // $this->register_session($username, $password);
+    return 'success';
+  }
+  
+  /**
+   * Attempts to send an e-mail to the specified user with activation instructions.
+   * @param string $u The usernamd of the user requesting activation
+   * @return bool true on success, false on failure
+   */
+   
+  function send_activation_mail($u, $actkey = false)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $q = $this->sql('SELECT username,email FROM '.table_prefix.'users WHERE user_id=1 OR user_level=' . USER_LEVEL_ADMIN . ' ORDER BY user_id ASC;');
+    $un = $db->fetchrow();
+    $admin_user = $un['username'];
+    $q = $this->sql('SELECT username,activation_key,account_active,email FROM '.table_prefix.'users WHERE username=\''.$db->escape($u).'\';');
+    $r = $db->fetchrow();
+    if ( empty($r['email']) )
+      $db->_die('BUG: $session->send_activation_mail(): no e-mail address in row');
+    $message = 'Dear '.$u.',
+Thank you for registering on '.getConfig('site_name').'. Your account creation is almost complete. To complete the registration process, please click the following link or paste it into your web browser:
+    
+';
+    if(isset($_SERVER['HTTPS'])) $prot = 'https';
+    else $prot = 'http';                                                                           
+    if($_SERVER['SERVER_PORT'] == '80') $p = '';
+    else $p = ':'.$_SERVER['SERVER_PORT'];
+    $sidbak = false;
+    if($this->sid_super)
+      $sidbak = $this->sid_super;
+    $this->sid_super = false;
+    $aklink = makeUrlNS('Special', 'ActivateAccount/'.str_replace(' ', '_', $u).'/'. ( ( is_string($actkey) ) ? $actkey : $r['activation_key'] ) );
+    if($sidbak)
+      $this->sid_super = $sidbak;
+    unset($sidbak);
+    $message .= "$prot://".$_SERVER['HTTP_HOST'].$p.$aklink;
+      $message .= "\n\nSincerely yours, \n$admin_user and the ".$_SERVER['HTTP_HOST']." administration team";
+    error_reporting(E_ALL);
+    dc_dump($r, 'session: about to send activation e-mail to '.$r['email']);
+    if(getConfig('smtp_enabled') == '1')
+    {
+      $result = smtp_send_email($r['email'], getConfig('site_name').' website account activation', preg_replace("#(?<!\r)\n#s", "\n", $message), getConfig('contact_email'));
+      if($result == 'success') $result = true;
+      else { echo $result; $result = false; }
+    } else {
+      $result = mail($r['email'], getConfig('site_name').' website account activation', preg_replace("#(?<!\r)\n#s", "\n", $message), 'From: '.getConfig('contact_email'));
+    }
+    return $result;
+  }
+  
+  /**
+   * Sends an e-mail to a user so they can reset their password.
+   * @param int $user The user ID, or username if it's a string
+   * @return bool true on success, false on failure
+   */
+   
+  function mail_password_reset($user)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(is_int($user))
+    {
+      $q = $this->sql('SELECT user_id,username,email FROM '.table_prefix.'users WHERE user_id='.$user.';'); // This is SAFE! This is only called if $user is an integer
+    }
+    elseif(is_string($user))
+    {
+      $q = $this->sql('SELECT user_id,username,email FROM '.table_prefix.'users WHERE username=\''.$db->escape($user).'\';');
+    }
+    else
+    {
+      return false;
+    }
+    
+    $row = $db->fetchrow();
+    $temp_pass = $this->random_pass();
+    
+    $this->register_temp_password($row['user_id'], $temp_pass);
+    
+    $site_name = getConfig('site_name');
+    
+    $message = "Dear {$row['username']},
+    
+Someone (hopefully you) on the {$site_name} website requested that a new password be created.
+
+The request was sent from the IP address {$_SERVER['REMOTE_ADDR']}.
+
+If you did not request the new password, then you do not need to do anything; the password will be invalidated after 24 hours.
+
+If you did request this password, then please log in using the password shown below:
+
+  Password: {$temp_pass}
+  
+After you log in using this password, you will be able to reset your real password. You can only log in using this temporary password once.
+
+Sincerely yours,
+The {$site_name} administration team
+";
+    
+    if(getConfig('smtp_enabled') == '1')
+    {
+      $result = smtp_send_email($row['email'], getConfig('site_name').' password reset', preg_replace("#(?<!\r)\n#s", "\n", $message), getConfig('contact_email'));
+      if($result == 'success')
+      {
+        $result = true;
+      }
+      else
+      {
+        echo '<p>'.$result.'</p>';
+        $result = false;
+      }
+    } else {
+      $result = mail($row['email'], getConfig('site_name').' password reset', preg_replace("#(?<!\r)\n#s", "\n", $message), 'From: '.getConfig('contact_email'));
+    }
+    return $result;
+  }
+  
+  /**
+   * Sets the temporary password for the specified user to whatever is specified.
+   * @param int $user_id
+   * @param string $password
+   * @return bool
+   */
+   
+  function register_temp_password($user_id, $password)
+  {
+    $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
+    $temp_pass = $aes->encrypt($password, $this->private_key, ENC_HEX);
+    $this->sql('UPDATE '.table_prefix.'users SET temp_password=\'' . $temp_pass . '\',temp_password_time='.time().' WHERE user_id='.intval($user_id).';');
+  }
+  
+  /**
+   * Sends a request to the admin panel to have the username $u activated.
+   * @param string $u The username of the user requesting activation
+   */
+  
+  function admin_activation_request($u)
+  {
+    global $db;
+    $this->sql('INSERT INTO '.table_prefix.'logs(log_type, action, time_id, date_string, author, edit_summary) VALUES(\'admin\', \'activ_req\', '.time().', \''.date('d M Y h:i a').'\', \''.$this->username.'\', \''.$db->escape($u).'\');');
+  }
+  
+  /**
+   * Activates a user account. If the action fails, a report is sent to the admin.
+   * @param string $user The username of the user requesting activation
+   * @param string $key The activation key
+   */
+  
+  function activate_account($user, $key)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $this->sql('UPDATE '.table_prefix.'users SET account_active=1 WHERE username=\''.$db->escape($user).'\' AND activation_key=\''.$db->escape($key).'\';');
+    $r = mysql_affected_rows();
+    if ( $r > 0 )
+    {
+      $e = $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary) VALUES(\'security\', \'activ_good\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($user).'\', \''.$_SERVER['REMOTE_ADDR'].'\')');
+    }
+    else
+    {
+      $e = $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary) VALUES(\'security\', \'activ_bad\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($user).'\', \''.$_SERVER['REMOTE_ADDR'].'\')');
+    }
+    return $r;
+  }
+  
+  /**
+   * For a given user level identifier (USER_LEVEL_*), returns a string describing that user level.
+   * @param int User level
+   * @return string
+   */
+  
+  function userlevel_to_string($user_level)
+  {
+    switch ( $user_level )
+    {
+      case USER_LEVEL_GUEST:
+        return 'Low - guest privileges';
+      case USER_LEVEL_MEMBER:
+        return 'Standard - normal member level';
+      case USER_LEVEL_CHPREF:
+        return 'Medium - user can change his/her own e-mail address and password';
+      case USER_LEVEL_MOD:
+        return 'High - moderator privileges';
+      case USER_LEVEL_ADMIN:
+        return 'Highest - administrative privileges';
+      default:
+        return "Unknown ($user_level)";
+    }
+  }
+  
+  /**
+   * Updates a user's information in the database. Note that any of the values except $user_id can be false if you want to preserve the old values.
+   * @param int $user_id The user ID of the user to update - this cannot be changed
+   * @param string $username The new username
+   * @param string $old_pass The current password - only required if sessionManager::$user_level < USER_LEVEL_ADMIN. This should usually be an UNENCRYPTED string. This can also be an array - if it is, key 0 is treated as data AES-encrypted with key 1
+   * @param string $password The new password
+   * @param string $email The new e-mail address
+   * @param string $realname The new real name
+   * @param string $signature The updated forum/comment signature
+   * @param int $user_level The updated user level
+   * @return string 'success' if successful, or array of error strings on failure
+   */
+   
+  function update_user($user_id, $username = false, $old_pass = false, $password = false, $email = false, $realname = false, $signature = false, $user_level = false)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    // Create some arrays
+    
+    $errors = Array(); // Used to hold error strings
+    $strs = Array();   // Sub-query statements
+    
+    // Scan the user ID for problems
+    if(intval($user_id) < 1) $errors[] = 'SQL injection attempt';
+    
+    // Instanciate the AES encryption class
+    $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
+    
+    // If all of our input vars are false, then we've effectively done our job so get out of here
+    if($username === false && $password === false && $email === false && $realname === false && $signature === false && $user_level === false)
+    {
+   // echo 'debug: $session->update_user(): success (no changes requested)';
+      return 'success';
+    }
+    
+    // Initialize our authentication check
+    $authed = false;
+    
+    // Verify the inputted password
+    if(is_string($old_pass))
+    {
+      $q = $this->sql('SELECT password FROM '.table_prefix.'users WHERE user_id='.$user_id.';');
+      if($db->numrows() < 1)
+      {
+        $errors[] = 'The password data could not be selected for verification.';
+      }
+      else
+      {
+        $row = $db->fetchrow();
+        $real = $aes->decrypt($row['password'], $this->private_key, ENC_HEX);
+        if($real == $old_pass)
+          $authed = true;
+      }
+    }
+    
+    elseif(is_array($old_pass))
+    {
+      $old_pass = $aes->decrypt($old_pass[0], $old_pass[1]);
+      $q = $this->sql('SELECT password FROM '.table_prefix.'users WHERE user_id='.$user_id.';');
+      if($db->numrows() < 1)
+      {
+        $errors[] = 'The password data could not be selected for verification.';
+      }
+      else
+      {
+        $row = $db->fetchrow();
+        $real = $aes->decrypt($row['password'], $this->private_key, ENC_HEX);
+        if($real == $old_pass)
+          $authed = true;
+      }
+    }
+    
+    // Initialize our query
+    $q = 'UPDATE '.table_prefix.'users SET ';
+    
+    if($this->auth_level >= USER_LEVEL_ADMIN || $authed) // Need the current password in order to update the e-mail address, change the username, or reset the password
+    {
+      // Username
+      if(is_string($username))
+      {
+        // Check the username for problems
+        if(!preg_match('#^'.$this->valid_username.'$#', $username))
+          $errors[] = 'The username you entered contains invalid characters.';
+        $strs[] = 'username=\''.$db->escape($username).'\'';
+      }
+      // Password
+      if(is_string($password) && strlen($password) >= 6)
+      {
+        // Password needs to be encrypted before being stashed
+        $encpass = $aes->encrypt($password, $this->private_key, ENC_HEX);
+        if(!$encpass)
+          $errors[] = 'The password could not be encrypted due to an internal error.';
+        $strs[] = 'password=\''.$encpass.'\'';
+      }
+      // E-mail addy
+      if(is_string($email))
+      {
+        // I didn't write this regex.
+        if(!preg_match('/^(?:[\w\d]+\.?)+@(?:(?:[\w\d]\-?)+\.)+\w{2,4}$/', $email))
+          $errors[] = 'The e-mail address you entered is invalid.';
+        $strs[] = 'email=\''.$db->escape($email).'\'';
+      }
+    }
+    // Real name
+    if(is_string($realname))
+    {
+      $strs[] = 'real_name=\''.$db->escape($realname).'\'';
+    }
+    // Forum/comment signature
+    if(is_string($signature))
+    {
+      $strs[] = 'signature=\''.$db->escape($signature).'\'';
+    }
+    // User level
+    if(is_int($user_level))
+    {
+      $strs[] = 'user_level='.$user_level;
+    }
+    
+    // Add our generated query to the query string
+    $q .= implode(',', $strs);
+    
+    // One last error check
+    if(sizeof($strs) < 1) $errors[] = 'An internal error occured building the SQL query, this is a bug';
+    if(sizeof($errors) > 0) return $errors;
+    
+    // Free our temp arrays
+    unset($strs, $errors);
+    
+    // Finalize the query and run it
+    $q .= ' WHERE user_id='.$user_id.';';
+    $this->sql($q);
+    
+    // We also need to trigger re-activation.
+    if ( is_string($email) )
+    {
+      switch(getConfig('account_activation'))
+      {
+        case 'user':
+        case 'admin':
+          
+          if ( $session->user_level >= USER_LEVEL_MOD && getConfig('account_activation') == 'admin' )
+            // Don't require re-activation by admins for admins
+            break;
+          
+          // retrieve username
+          if ( !$username )
+          {
+            $q = $this->sql('SELECT username FROM '.table_prefix.'users WHERE user_id='.$user_id.';');
+            if($db->numrows() < 1)
+            {
+              $errors[] = 'The username could not be selected.';
+            }
+            else
+            {
+              $row = $db->fetchrow();
+              $username = $row['username'];
+            }
+          }
+          if ( !$username )
+            return $errors;
+          
+          // Generate a totally random activation key
+          $actkey = sha1 ( microtime() . mt_rand() );
+          $a = $this->send_activation_mail($username, $actkey);
+          if(!$a)
+          {
+            $this->admin_activation_request($username);
+          }
+          // Deactivate the account until e-mail is confirmed
+          $q = $db->sql_query('UPDATE '.table_prefix.'users SET account_active=0,activation_key=\'' . $actkey . '\' WHERE user_id=' . $user_id . ';');
+          break;
+      }
+    }
+    
+    // Yay! We're done
+    return 'success';
+  }
+  
+  #
+  # Access Control Lists
+  #
+  
+  /**
+   * Creates a new permission field in memory. If the permissions are set in the database, they are used. Otherwise, $default_perm is used.
+   * @param string $acl_type An identifier for this field
+   * @param int $default_perm Whether permission should be granted or not if it's not specified in the ACLs.
+   * @param string $desc A human readable name for the permission type
+   * @param array $deps The list of dependencies - this should be an array of ACL types
+   * @param string $scope Which namespaces this field should apply to. This should be either a pipe-delimited list of namespace IDs or just "All".
+   */
+   
+  function register_acl_type($acl_type, $default_perm = AUTH_DISALLOW, $desc = false, $deps = Array(), $scope = 'All')
+  {
+    if(isset($this->acl_types[$acl_type]))
+      return false;
+    else
+    {
+      if(!$desc)
+      {
+        $desc = capitalize_first_letter(str_replace('_', ' ', $acl_type));
+      }
+      $this->acl_types[$acl_type] = $default_perm;
+      $this->acl_descs[$acl_type] = $desc;
+      $this->acl_deps[$acl_type] = $deps;
+      $this->acl_scope[$acl_type] = explode('|', $scope);
+    }
+    return true;
+  }
+  
+  /**
+   * Tells us whether permission $type is allowed or not based on the current rules.
+   * @param string $type The permission identifier ($acl_type passed to sessionManager::register_acl_type())
+   * @param bool $no_deps If true, disables dependency checking
+   * @return bool True if allowed, false if denied or if an error occured
+   */
+   
+  function get_permissions($type, $no_deps = false)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if ( isset( $this->perms[$type] ) )
+    {
+      if ( $this->perms[$type] == AUTH_DENY )
+        $ret = false;
+      else if ( $this->perms[$type] == AUTH_WIKIMODE && $paths->wiki_mode )
+        $ret = true;
+      else if ( $this->perms[$type] == AUTH_WIKIMODE && !$paths->wiki_mode )
+        $ret = false;
+      else if ( $this->perms[$type] == AUTH_ALLOW )
+        $ret = true;
+      else if ( $this->perms[$type] == AUTH_DISALLOW )
+        $ret = false;
+    }
+    else if(isset($this->acl_types[$type]))
+    {
+      if ( $this->acl_types[$type] == AUTH_DENY )
+        $ret = false;
+      else if ( $this->acl_types[$type] == AUTH_WIKIMODE && $paths->wiki_mode )
+        $ret = true;
+      else if ( $this->acl_types[$type] == AUTH_WIKIMODE && !$paths->wiki_mode )
+        $ret = false;
+      else if ( $this->acl_types[$type] == AUTH_ALLOW )
+        $ret = true;
+      else if ( $this->acl_types[$type] == AUTH_DISALLOW )
+        $ret = false;
+    }
+    else
+    {
+      // ACL type is undefined
+      trigger_error('Unknown access type "' . $type . '"', E_USER_WARNING);
+      return false; // Be on the safe side and deny access
+    }
+    if ( !$no_deps )
+    {
+      if ( !$this->acl_check_deps($type) )
+        return false;
+    }
+    return $ret;
+  }
+  
+  /**
+   * Fetch the permissions that apply to the current user for the page specified. The object you get will have the get_permissions method
+   * and several other abilities.
+   * @param string $page_id
+   * @param string $namespace
+   * @return object
+   */
+   
+  function fetch_page_acl($page_id, $namespace)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    if ( count ( $this->acl_base_cache ) < 1 )
+    {
+      // Permissions table not yet initialized
+      return false;
+    }
+    
+    //if ( !isset( $paths->pages[$paths->nslist[$namespace] . $page_id] ) )
+    //{
+    //  // Page does not exist
+    //  return false;
+    //}
+    
+    $object = new Session_ACLPageInfo( $page_id, $namespace, $this->acl_types, $this->acl_descs, $this->acl_deps, $this->acl_base_cache );
+    
+    return $object;
+    
+  }
+  
+  /**
+   * Read all of our permissions from the database and process/apply them. This should be called after the page is determined.
+   * @access private
+   */
+  
+  function init_permissions()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    // Initialize the permissions list with some defaults
+    $this->perms = $this->acl_types;
+    $this->acl_defaults_used = $this->perms;
+    
+    // Fetch sitewide defaults from the permissions table
+    $bs = 'SELECT rules FROM '.table_prefix.'acl WHERE page_id IS NULL AND namespace IS NULL AND ( ';
+    
+    $q = Array();
+    $q[] = '( target_type='.ACL_TYPE_USER.' AND target_id='.$this->user_id.' )';
+    if(count($this->groups) > 0)
+    {
+      foreach($this->groups as $g_id => $g_name)
+      {
+        $q[] = '( target_type='.ACL_TYPE_GROUP.' AND target_id='.intval($g_id).' )';
+      }
+    }
+    $bs .= implode(' OR ', $q) . ' ) ORDER BY target_type ASC, target_id ASC;';
+    $q = $this->sql($bs);
+    if ( $row = $db->fetchrow() )
+    {
+      do {
+        $rules = $this->string_to_perm($row['rules']);
+        $is_everyone = ( $row['target_type'] == ACL_TYPE_GROUP && $row['target_id'] == 1 );
+        $this->acl_merge_with_current($rules, $is_everyone);
+      } while ( $row = $db->fetchrow() );
+    }
+    
+    // Eliminate types that don't apply to this namespace
+    foreach ( $this->perms AS $i => $perm )
+    {
+      if ( !in_array ( $paths->namespace, $this->acl_scope[$i] ) && !in_array('All', $this->acl_scope[$i]) )
+      {
+        unset($this->perms[$i]);
+      }
+    }
+    
+    // Cache the sitewide permissions for later use
+    $this->acl_base_cache = $this->perms;
+    
+    // Build a query to grab ACL info
+    $bs = 'SELECT rules,target_type,target_id FROM '.table_prefix.'acl WHERE ( ';
+    $q = Array();
+    $q[] = '( target_type='.ACL_TYPE_USER.' AND target_id='.$this->user_id.' )';
+    if(count($this->groups) > 0)
+    {
+      foreach($this->groups as $g_id => $g_name)
+      {
+        $q[] = '( target_type='.ACL_TYPE_GROUP.' AND target_id='.intval($g_id).' )';
+      }
+    }
+    // The reason we're using an ORDER BY statement here is because ACL_TYPE_GROUP is less than ACL_TYPE_USER, causing the user's individual
+    // permissions to override group permissions.
+    $bs .= implode(' OR ', $q) . ' ) AND ( page_id=\''.$db->escape($paths->cpage['urlname_nons']).'\' AND namespace=\''.$db->escape($paths->namespace).'\' )     
+      ORDER BY target_type ASC, page_id ASC, namespace ASC;';
+    $q = $this->sql($bs);
+    if ( $row = $db->fetchrow() )
+    {
+      do {
+        $rules = $this->string_to_perm($row['rules']);
+        $is_everyone = ( $row['target_type'] == ACL_TYPE_GROUP && $row['target_id'] == 1 );
+        $this->acl_merge_with_current($rules, $is_everyone);
+      } while ( $row = $db->fetchrow() );
+    }
+    
+  }
+  
+  /**
+   * Extends the scope of a permission type.
+   * @param string The name of the permission type
+   * @param string The namespace(s) that should be covered. This can be either one namespace ID or a pipe-delimited list.
+   * @param object Optional - the current $paths object, in case we're doing this from the acl_rule_init hook
+   */
+   
+  function acl_extend_scope($perm_type, $namespaces, &$p_in)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $p_obj = ( is_object($p_in) ) ? $p_in : $paths;
+    $nslist = explode('|', $namespaces);
+    foreach ( $nslist as $i => $ns )
+    {
+      if ( !isset($p_obj->nslist[$ns]) )
+      {
+        unset($nslist[$i]);
+      }
+      else
+      {
+        $this->acl_scope[$perm_type][] = $ns;
+        if ( isset($this->acl_types[$perm_type]) && !isset($this->perms[$perm_type]) )
+        {
+          $this->perms[$perm_type] = $this->acl_types[$perm_type];
+        }
+      }
+    }
+  }
+  
+  /**
+   * Converts a permissions field into a string for database insertion. Similar in spirit to serialize().
+   * @param array $perms An associative array with only integers as values
+   * @return string
+   */
+   
+  function perm_to_string($perms)
+  {
+    $s = '';
+    foreach($perms as $perm => $ac)
+    {
+      $s .= "$perm=$ac;";
+    }
+    return $s;
+  }
+  
+  /**
+   * Converts a permissions string back to an array.
+   * @param string $perms The result from sessionManager::perm_to_string()
+   * @return array
+   */
+   
+  function string_to_perm($perms)
+  {
+    $ret = Array();
+    preg_match_all('#([a-z0-9_-]+)=([0-9]+);#i', $perms, $matches);
+    foreach($matches[1] as $i => $t)
+    {
+      $ret[$t] = intval($matches[2][$i]);
+    }
+    return $ret;
+  }
+  
+  /**
+   * Merges two ACL arrays. Both parameters should be permission list arrays. The second group takes precedence over the first, but AUTH_DENY always prevails.
+   * @param array $perm1 The first set of permissions
+   * @param array $perm2 The second set of permissions
+   * @return array
+   */
+   
+  function acl_merge($perm1, $perm2)
+  {
+    $ret = $perm1;
+    foreach ( $perm2 as $type => $level )
+    {
+      if ( isset( $ret[$type] ) )
+      {
+        if ( $ret[$type] != AUTH_DENY )
+          $ret[$type] = $level;
+      }
+      // else
+      // {
+      //   $ret[$type] = $level;
+      // }
+    }
+    return $ret;
+  }
+  
+  /**
+   * Merges the ACL array sent with the current permissions table, deciding precedence based on whether defaults are in effect or not.
+   * @param array The array to merge into the master ACL list
+   * @param bool If true, $perm is treated as the "new default"
+   * @param int 1 if this is a site-wide ACL, 2 if page-specific. Defaults to 2.
+   */
+  
+  function acl_merge_with_current($perm, $is_everyone = false, $scope = 2)
+  {
+    foreach ( $this->perms as $i => $p )
+    {
+      if ( isset($perm[$i]) )
+      {
+        if ( $is_everyone && !$this->acl_defaults_used[$i] )
+          continue;
+        // Decide precedence
+        if ( isset($this->acl_defaults_used[$i]) )
+        {
+          //echo "$i: default in use, overriding to: {$perm[$i]}<br />";
+          // Defaults are in use, override
+          $this->perms[$i] = $perm[$i];
+          $this->acl_defaults_used[$i] = ( $is_everyone );
+        }
+        else
+        {
+          //echo "$i: default NOT in use";
+          // Defaults are not in use, merge as normal
+          if ( $this->perms[$i] != AUTH_DENY )
+          {
+            //echo ", but overriding";
+            $this->perms[$i] = $perm[$i];
+          }
+          //echo "<br />";
+        }
+      }
+    }
+  }
+  
+  /**
+   * Merges two ACL arrays. Both parameters should be permission list arrays. The second group takes precedence
+   * over the first, without exceptions. This is used to merge the hardcoded defaults with admin-specified
+   * defaults, which take precedence.
+   * @param array $perm1 The first set of permissions
+   * @param array $perm2 The second set of permissions
+   * @return array
+   */
+   
+  function acl_merge_complete($perm1, $perm2)
+  {
+    $ret = $perm1;
+    foreach ( $perm2 as $type => $level )
+    {
+      $ret[$type] = $level;
+    }
+    return $ret;
+  }
+  
+  /**
+   * Tell us if the dependencies for a given permission are met.
+   * @param string The ACL permission ID
+   * @return bool
+   */
+   
+  function acl_check_deps($type)
+  {
+    if(!isset($this->acl_deps[$type])) // This will only happen if the permissions table is hacked or improperly accessed
+      return true;
+    if(sizeof($this->acl_deps[$type]) < 1)
+      return true;
+    $deps = $this->acl_deps[$type];
+    while(true)
+    {
+      $full_resolved = true;
+      $j = sizeof($deps);
+      for ( $i = 0; $i < $j; $i++ )
+      {
+        $b = $deps;
+        $deps = array_merge($deps, $this->acl_deps[$deps[$i]]);
+        if( $b == $deps )
+        {
+          break 2;
+        }
+        $j = sizeof($deps);
+      }
+    }
+    //die('<pre>'.print_r($deps, true).'</pre>');
+    foreach($deps as $d)
+    {
+      if ( !$this->get_permissions($d) )
+      {
+        return false;
+      }
+    }
+    return true;
+  }
+  
+  /**
+   * Makes a CAPTCHA code and caches the code in the database
+   * @param int $len The length of the code, in bytes
+   * @return string A unique identifier assigned to the code. This hash should be passed to sessionManager::getCaptcha() to retrieve the code.
+   */
+  
+  function make_captcha($len = 7)
+  {
+    $chars = array('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '1', '2', '3', '4', '5', '6', '7', '8', '9');
+    $s = '';
+    for($i=0;$i<$len;$i++) $s .= $chars[mt_rand(0, count($chars)-1)];
+    $hash = md5(microtime() . mt_rand());
+    $this->sql('INSERT INTO '.table_prefix.'session_keys(session_key,salt,auth_level,source_ip,user_id) VALUES(\''.$hash.'\', \''.$s.'\', -1, \''.ip2hex($_SERVER['REMOTE_ADDR']).'\', -2);');
+    return $hash;
+  }
+  
+  /**
+   * For the given code ID, returns the correct CAPTCHA code, or false on failure
+   * @param string $hash The unique ID assigned to the code
+   * @return string The correct confirmation code
+   */
+  
+  function get_captcha($hash)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $s = $this->sql('SELECT salt FROM '.table_prefix.'session_keys WHERE session_key=\''.$db->escape($hash).'\' AND source_ip=\''.ip2hex($_SERVER['REMOTE_ADDR']).'\';');
+    if($db->numrows() < 1) return false;
+    $r = $db->fetchrow();
+    return $r['salt'];
+  }
+  
+  /**
+   * Deletes all CAPTCHA codes cached in the DB for this user.
+   */
+  
+  function kill_captcha()
+  {
+    $this->sql('DELETE FROM '.table_prefix.'session_keys WHERE user_id=-2 AND source_ip=\''.ip2hex($_SERVER['REMOTE_ADDR']).'\';');
+  }
+  
+  /**
+   * Generates a random password.
+   * @param int $length Optional - length of password
+   * @return string
+   */
+   
+  function random_pass($length = 10)
+  {
+    $valid_chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_+@#%&<>';
+    $valid_chars = enano_str_split($valid_chars);
+    $ret = '';
+    for ( $i = 0; $i < $length; $i++ )
+    {
+      $ret .= $valid_chars[mt_rand(0, count($valid_chars)-1)];
+    }
+    return $ret;
+  }
+  
+  /**
+   * Generates some Javascript that calls the AES encryption library.
+   * @param string The name of the form
+   * @param string The name of the password field
+   * @param string The name of the field that switches encryption on or off
+   * @param string The name of the field that contains the encryption key
+   * @param string The name of the field that will contain the encrypted password
+   * @param string The name of the field that handles MD5 challenge data
+   * @return string
+   */
+   
+  function aes_javascript($form_name, $pw_field, $use_crypt, $crypt_key, $crypt_data, $challenge)
+  {
+    $code = '
+      <script type="text/javascript">
+        disableJSONExts();
+          str = \'\';
+          for(i=0;i<keySizeInBits/4;i++) str+=\'0\';
+          var key = hexToByteArray(str);
+          var pt = hexToByteArray(str);
+          var ct = rijndaelEncrypt(pt, key, \'ECB\');
+          var ct = byteArrayToHex(ct);
+          switch(keySizeInBits)
+          {
+            case 128:
+              v = \'66e94bd4ef8a2c3b884cfa59ca342b2e\';
+              break;
+            case 192:
+              v = \'aae06992acbf52a3e8f4a96ec9300bd7aae06992acbf52a3e8f4a96ec9300bd7\';
+              break;
+            case 256:
+              v = \'dc95c078a2408989ad48a21492842087dc95c078a2408989ad48a21492842087\';
+              break;
+          }
+          var testpassed = ' . ( ( isset($_GET['use_crypt']) && $_GET['use_crypt']=='0') ? 'false; // CRYPTO-AUTH DISABLED ON USER REQUEST // ' : '' ) . '( ct == v && md5_vm_test() );
+          var frm = document.forms.'.$form_name.';
+          if(testpassed)
+          {
+            frm.'.$use_crypt.'.value = \'yes\';
+            var cryptkey = frm.'.$crypt_key.'.value;
+            frm.'.$crypt_key.'.value = hex_md5(cryptkey);
+            cryptkey = hexToByteArray(cryptkey);
+            if(!cryptkey || ( ( typeof cryptkey == \'string\' || typeof cryptkey == \'object\' ) ) && cryptkey.length != keySizeInBits / 8 )
+            {
+              if ( frm._login ) frm._login.disabled = true;
+              len = ( typeof cryptkey == \'string\' || typeof cryptkey == \'object\' ) ? \'\\nLen: \'+cryptkey.length : \'\';
+              alert(\'The key is messed up\\nType: \'+typeof(cryptkey)+len);
+            }
+          }
+          if(frm.username) frm.username.focus();
+          function runEncryption()
+          {
+            if(testpassed)
+            {
+              pass = frm.'.$pw_field.'.value;
+              chal = frm.'.$challenge.'.value;
+              challenge = hex_md5(pass + chal) + chal;
+              frm.'.$challenge.'.value = challenge;
+              pass = stringToByteArray(pass);
+              cryptstring = rijndaelEncrypt(pass, cryptkey, \'ECB\');
+              if(!cryptstring)
+              {
+                return false;
+              }
+              cryptstring = byteArrayToHex(cryptstring);
+              frm.'.$crypt_data.'.value = cryptstring;
+              frm.'.$pw_field.'.value = \'\';
+            }
+            return false;
+          }
+        </script>
+        ';
+    return $code;
+  }
+  
+}
+
+/**
+ * Class used to fetch permissions for a specific page. Used internally by SessionManager.
+ * @package Enano
+ * @subpackage Session manager
+ * @license http://www.gnu.org/copyleft/gpl.html
+ * @access private
+ */
+ 
+class Session_ACLPageInfo {
+  
+  /**
+   * The page ID of this ACL info package
+   * @var string
+   */
+   
+  var $page_id;
+  
+  /**
+   * The namespace of the page being checked
+   * @var string
+   */
+   
+  var $namespace;
+  
+  /**
+   * Our list of permission types.
+   * @access private
+   * @var array
+   */
+   
+  var $acl_types = Array();
+  
+  /**
+   * The list of descriptions for the permission types
+   * @var array
+   */
+   
+  var $acl_descs = Array();
+  
+  /**
+   * A list of dependencies for ACL types.
+   * @var array
+   */
+   
+  var $acl_deps = Array();
+  
+  /**
+   * Our tell-all list of permissions.
+   * @access private - or, preferably, protected...too bad this has to be PHP4 compatible
+   * @var array
+   */
+   
+  var $perms = Array();
+  
+  /**
+   * Constructor.
+   * @param string $page_id The ID of the page to check
+   * @param string $namespace The namespace of the page to check.
+   * @param array $acl_types List of ACL types
+   * @param array $acl_descs List of human-readable descriptions for permissions (associative)
+   * @param array $acl_deps List of dependencies for permissions. For example, viewing history/diffs depends on the ability to read the page.
+   * @param array $base What to start with - this is an attempt to reduce the number of SQL queries.
+   */
+   
+  function Session_ACLPageInfo($page_id, $namespace, $acl_types, $acl_descs, $acl_deps, $base)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    $this->perms = $session->acl_merge_complete($acl_types, $base);
+    $this->acl_deps = $acl_deps;
+    $this->acl_types = $acl_types;
+    $this->acl_descs = $acl_descs;
+    
+    // Build a query to grab ACL info
+    $bs = 'SELECT rules FROM '.table_prefix.'acl WHERE ( ';
+    $q = Array();
+    $q[] = '( target_type='.ACL_TYPE_USER.' AND target_id='.$session->user_id.' )';
+    if(count($session->groups) > 0)
+    {
+      foreach($session->groups as $g_id => $g_name)
+      {
+        $q[] = '( target_type='.ACL_TYPE_GROUP.' AND target_id='.intval($g_id).' )';
+      }
+    }
+    // The reason we're using an ORDER BY statement here is because ACL_TYPE_GROUP is less than ACL_TYPE_USER, causing the user's individual
+    // permissions to override group permissions.
+    $bs .= implode(' OR ', $q) . ' ) AND ( page_id=\''.$db->escape($page_id).'\' AND namespace=\''.$db->escape($namespace).'\' )     
+      ORDER BY target_type ASC, page_id ASC, namespace ASC;';
+    $q = $session->sql($bs);
+    if ( $row = $db->fetchrow() )
+    {
+      do {
+        $rules = $session->string_to_perm($row['rules']);
+        $this->perms = $session->acl_merge($this->perms, $rules);
+      } while ( $row = $db->fetchrow() );
+    }
+    
+    $this->page_id = $page_id;
+    $this->namespace = $namespace;
+  }
+  
+  /**
+   * Tells us whether permission $type is allowed or not based on the current rules.
+   * @param string $type The permission identifier ($acl_type passed to sessionManager::register_acl_type())
+   * @param bool $no_deps If true, disables dependency checking
+   * @return bool True if allowed, false if denied or if an error occured
+   */
+   
+  function get_permissions($type, $no_deps = false)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if ( isset( $this->perms[$type] ) )
+    {
+      if ( $this->perms[$type] == AUTH_DENY )
+        $ret = false;
+      else if ( $this->perms[$type] == AUTH_WIKIMODE &&
+        ( isset($paths->pages[$paths->nslist[$this->namespace].$this->page_id]) && 
+          ( $paths->pages[$paths->nslist[$this->namespace].$this->page_id]['wiki_mode'] == '1' ||
+            ( $paths->pages[$paths->nslist[$this->namespace].$this->page_id]['wiki_mode'] == '2'
+              && getConfig('wiki_mode') == '1'
+          ) ) ) )
+        $ret = true;
+      else if ( $this->perms[$type] == AUTH_WIKIMODE && (
+        !isset($paths->pages[$paths->nslist[$this->namespace].$this->page_id])
+        || (
+          isset($paths->pages[$paths->nslist[$this->namespace].$this->page_id]) && (
+            $paths->pages[$paths->nslist[$this->namespace].$this->page_id]['wiki_mode'] == '0'
+            || (
+              $paths->pages[$paths->nslist[$this->namespace].$this->page_id]['wiki_mode'] == '2' && getConfig('wiki_mode') != '1'
+          ) ) ) ) )
+        $ret = false;
+      else if ( $this->perms[$type] == AUTH_ALLOW )
+        $ret = true;
+      else if ( $this->perms[$type] == AUTH_DISALLOW )
+        $ret = false;
+    }
+    else if(isset($this->acl_types[$type]))
+    {
+      if ( $this->acl_types[$type] == AUTH_DENY )
+        $ret = false;
+      else if ( $this->acl_types[$type] == AUTH_WIKIMODE && $paths->wiki_mode )
+        $ret = true;
+      else if ( $this->acl_types[$type] == AUTH_WIKIMODE && !$paths->wiki_mode )
+        $ret = false;
+      else if ( $this->acl_types[$type] == AUTH_ALLOW )
+        $ret = true;
+      else if ( $this->acl_types[$type] == AUTH_DISALLOW )
+        $ret = false;
+    }
+    else
+    {
+      // ACL type is undefined
+      trigger_error('Unknown access type "' . $type . '"', E_USER_WARNING);
+      return false; // Be on the safe side and deny access
+    }
+    if ( !$no_deps )
+    {
+      if ( !$this->acl_check_deps($type) )
+        return false;
+    }
+    return $ret;
+  }
+  
+  /**
+   * Tell us if the dependencies for a given permission are met.
+   * @param string The ACL permission ID
+   * @return bool
+   */
+   
+  function acl_check_deps($type)
+  {
+    if(!isset($this->acl_deps[$type])) // This will only happen if the permissions table is hacked or improperly accessed
+      return true;
+    if(sizeof($this->acl_deps[$type]) < 1)
+      return true;
+    $deps = $this->acl_deps[$type];
+    while(true)
+    {
+      $full_resolved = true;
+      $j = sizeof($deps);
+      for ( $i = 0; $i < $j; $i++ )
+      {
+        $b = $deps;
+        $deps = array_merge($deps, $this->acl_deps[$deps[$i]]);
+        if( $b == $deps )
+        {
+          break 2;
+        }
+        $j = sizeof($deps);
+      }
+    }
+    //die('<pre>'.print_r($deps, true).'</pre>');
+    foreach($deps as $d)
+    {
+      if ( !$this->get_permissions($d) )
+      {
+        return false;
+      }
+    }
+    return true;
+  }
+  
+}
+
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/stats.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,83 @@
+<?php
+/*
+ * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
+ * Version 1.0 (Banshee)
+ * Copyright (C) 2006-2007 Dan Fuhry
+ * stats.php - handles statistics for pages (disablable in the admin CP)
+ *
+ *   ***** UNFINISHED ***** 
+ *
+ * This program is Free Software; you can redistribute 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 details.
+ */
+
+function doStats( $page_id = false, $namespace = false )
+{
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  if(getConfig('log_hits') == '1')
+  {
+    if(!$page_id || !$namespace)
+    {
+      $page_id = $paths->cpage['urlname_nons'];
+      $namespace = $paths->namespace;
+    }
+    if($namespace == 'Special' || $namespace == 'Admin') return false;
+    static $stats_done = false;
+    static $stats_data = Array();
+    if(!$stats_done)
+    {
+      $q = $db->sql_query('INSERT INTO '.table_prefix.'hits (username,time,page_id,namespace) VALUES(\''.$db->escape($session->username).'\', '.time().', \''.$db->escape($page_id).'\', \''.$db->escape($namespace).'\')');
+      if(!$q)
+      {
+        echo $db->get_error();
+        return false;
+      }
+      $db->free_result();
+      $stats_done = true;
+      return true;
+    }
+  }
+}
+
+/**
+ * Fetch a list of the most-viewed pages
+ * @param int the number of pages to return, send -1 to get all pages (suicide for large sites)
+ * @return array key names are a string set to the page ID/namespace, and values are an int with the number of hits
+ */
+
+function stats_top_pages($num = 5)
+{
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  if(!is_int($num)) return false;
+  $q = $db->sql_query('SELECT page_id,namespace FROM '.table_prefix.'hits ORDER BY page_id ASC, namespace ASC;');
+  if(!$q)
+  {
+    echo $db->get_error();
+    return false;
+  }
+  $counter = Array();
+  while ( $row = $db->fetchrow() )
+  {
+    $kname = $paths->nslist[$row['namespace']] . $row['page_id'];
+    if(isset($counter[$kname])) $counter[$kname]++;
+    else $counter[$kname] = 1;
+  }
+  $db->free_result();
+  // Pure magic! At least I don't have to do the work...
+  arsort($counter);
+  // Can't use array_slice here because key names are only preserved in PHP5
+  $k = array_keys($counter);
+  $final = Array();
+  if(sizeof($counter) < $num || $num == -1) $num = sizeof($counter);
+  for ( $i = 0; $i < $num; $i++ )
+  {
+    $final[$k[$i]] = $counter[$k[$i]];
+  }
+  unset($counter, $k, $row);
+  return $final;
+}
+
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/template.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1788 @@
+<?php
+
+/*
+ * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
+ * Version 1.0 (Banshee)
+ * Copyright (C) 2006-2007 Dan Fuhry
+ *
+ * This program is Free Software; you can redistribute 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 details.
+ */
+ 
+class template {
+  var $tpl_strings, $tpl_bool, $theme, $style, $no_headers, $additional_headers, $sidebar_extra, $sidebar_widgets, $toolbar_menu, $theme_list, $named_theme_list, $default_theme, $default_style, $plugin_blocks, $namespace_string, $style_list, $theme_loaded;
+  function __construct()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    dc_here('template: initializing all class variables');
+    $this->tpl_bool    = Array();
+    $this->tpl_strings = Array();
+    $this->sidebar_extra = '';
+    $this->toolbar_menu = '';
+    $this->additional_headers = '';
+    $this->plugin_blocks = Array();
+    $this->theme_loaded = false;
+    
+    $this->theme_list = Array();
+    $this->named_theme_list = Array();
+    $e = $db->sql_query('SELECT theme_id,theme_name,enabled,default_style FROM '.table_prefix.'themes WHERE enabled=1 ORDER BY theme_order;');
+    if(!$e) $db->_die('The list of themes could not be selected.');
+    for($i=0;$i < $db->numrows(); $i++)
+    {
+      $this->theme_list[$i] = $db->fetchrow();
+      $this->named_theme_list[$this->theme_list[$i]['theme_id']] = $this->theme_list[$i];
+    }
+    $db->free_result();
+    $this->default_theme = $this->theme_list[0]['theme_id'];
+    $dir = ENANO_ROOT.'/themes/'.$this->default_theme.'/css/';
+    $list = Array();
+    // Open a known directory, and proceed to read its contents
+    if (is_dir($dir)) {
+      if ($dh = opendir($dir)) {
+        while (($file = readdir($dh)) !== false) {
+          if(preg_match('#^(.*?)\.css$#i', $file) && $file != '_printable.css') {
+            $list[] = substr($file, 0, strlen($file)-4);
+          }
+        }
+        closedir($dh);
+      }
+    }
+    
+    $def = ENANO_ROOT.'/themes/'.$this->default_theme.'/css/'.$this->named_theme_list[$this->default_theme]['default_style'];
+    if(file_exists($def))
+    {
+      $this->default_style = substr($this->named_theme_list[$this->default_theme]['default_style'], 0, strlen($this->named_theme_list[$this->default_theme]['default_style'])-4);
+    } else {
+      $this->default_style = $list[0];
+    }
+    
+    $this->style_list = $list;
+    
+  }
+  function template()
+  {
+    $this->__construct();
+  }
+  function sidebar_widget($t, $h)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(!defined('ENANO_TEMPLATE_LOADED'))
+    {
+      $this->load_theme($session->theme, $session->style);
+    }
+    if(!$this->sidebar_widgets)
+      $this->sidebar_widgets = '';
+    $tplvars = $this->extract_vars('elements.tpl');
+    $parser = $this->makeParserText($tplvars['sidebar_section_raw']);
+    $parser->assign_vars(Array('TITLE'=>$t,'CONTENT'=>$h));
+    $this->plugin_blocks[$t] = $h;
+    $this->sidebar_widgets .= $parser->run();
+  }
+  function add_header($html)
+  {
+    $this->additional_headers .= "\n" . $html;
+  }
+  function get_css($s = false)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(!defined('ENANO_TEMPLATE_LOADED'))
+      $this->load_theme($session->theme, $session->style);
+    $path = ( $s ) ? 'css/'.$s : 'css/'.$this->style.'.css';
+    if ( !file_exists(ENANO_ROOT . '/themes/' . $this->theme . '/' . $path) )
+    {
+      echo "/* WARNING: Falling back to default file because file $path does not exist */\n";
+      $path = 'css/' . $this->style_list[0] . '.css';
+    }
+    return $this->process_template($path);
+  }
+  function load_theme($name = false, $css = false)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $this->theme = ( $name ) ? $name : $session->theme;
+    $this->style = ( $css ) ? $css : $session->style;
+    if ( !$this->theme )
+    {
+      $this->theme = $this->theme_list[0]['theme_id'];
+      $this->style = substr($this->theme_list[0]['default_style'], 0, strlen($this->theme_list[0]['default_style'])-4);
+    }
+    $this->theme_loaded = true;
+  }
+  
+  function init_vars()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    global $email;
+    
+    dc_here("template: initializing all variables");
+    
+    if(!$this->theme || !$this->style)
+    {
+      $this->load_theme();
+    }
+    
+    if(defined('ENANO_TEMPLATE_LOADED'))
+    {
+      dc_here('template: access denied to call template::init_vars(), bailing out');
+      die_semicritical('Illegal call', '<p>$template->load_theme was called multiple times, this is not supposed to happen. Exiting with fatal error.</p>');
+    }
+    
+    define('ENANO_TEMPLATE_LOADED', '');
+    
+    $tplvars = $this->extract_vars('elements.tpl');
+    
+    dc_here('template: setting all template vars');
+    
+    if(isset($_SERVER['HTTP_USER_AGENT']) && strstr($_SERVER['HTTP_USER_AGENT'], 'MSIE'))
+    {
+      $this->add_header('
+        <!--[if lt IE 7]>
+        <script language="JavaScript">
+        function correctPNG() // correctly handle PNG transparency in Win IE 5.5 & 6.
+        {
+           var arVersion = navigator.appVersion.split("MSIE")
+           var version = parseFloat(arVersion[1])
+           if (version >= 5.5 && typeof(document.body.filters) == "object")
+           {
+              for(var i=0; i<document.images.length; i++)
+              {
+                 var img = document.images[i];
+                 continue;
+                 var imgName = img.src.toUpperCase();
+                 if (imgName.substring(imgName.length-3, imgName.length) == "PNG")
+                 {
+                    var imgID = (img.id) ? "id=\'" + img.id + "\' " : "";
+                    var imgClass = (img.className) ? "class=\'" + img.className + "\' " : "";
+                    var imgTitle = (img.title) ? "title=\'" + img.title + "\' " : "title=\'" + img.alt + "\' ";
+                    var imgStyle = "display:inline-block;" + img.style.cssText;
+                    if (img.align == "left") imgStyle = "float:left;" + imgStyle;
+                    if (img.align == "right") imgStyle = "float:right;" + imgStyle;
+                    if (img.parentElement.href) imgStyle = "cursor:hand;" + imgStyle;
+                    var strNewHTML = "<span " + imgID + imgClass + imgTitle + " style=\\"" + "width:" + img.width + "px; height:" + img.height + "px;" + imgStyle + ";" + "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader" + "(src=\\\'" + img.src + "\\\', sizingMethod=\'scale\');\\"></span>";
+                    img.outerHTML = strNewHTML;
+                    i = i-1;
+                 }
+              }
+           }   
+        }
+        window.attachEvent("onload", correctPNG);
+        </script>
+        <![endif]-->
+        ');
+    }
+    
+    // Get the "article" button text (depends on namespace)
+    switch($paths->namespace) {
+      case "Article":
+      default:
+        $ns = 'article';
+        break;
+      case "Admin":
+        $ns = 'administration page';
+        break;
+      case "System":
+        $ns = 'system message';
+        break;
+      case "File":
+        $ns = 'uploaded file';
+        break;
+      case "Help":
+        $ns = 'documentation page';
+        break;
+      case "User":
+        $ns = 'user page';
+        break;
+      case "Special":
+        $ns = 'special page';
+        break;
+      case "Template":
+        $ns = 'template';
+        break;
+      case "Project":
+        $ns = 'project page';
+        break;
+      case "Category":
+        $ns = 'category';
+        break;
+    }
+    $this->namespace_string = $ns;
+    $code = $plugins->setHook('page_type_string_set');
+    foreach ( $code as $cmd )
+    {
+      eval($cmd);
+    }
+    $ns =& $this->namespace_string;
+    
+    // Initialize the toolbar
+    $tb = '';
+    
+    // Create "xx page" button
+    
+    $btn_selected = ( isset($tplvars['toolbar_button_selected'])) ? $tplvars['toolbar_button_selected'] : $tplvars['toolbar_button'];
+    $parser = $this->makeParserText($btn_selected);
+    
+    $parser->assign_vars(array(
+        'FLAGS' => 'onclick="void(ajaxReset()); return false;" title="View the page contents, all of the page contents, and nothing but the page contents (alt-a)" accesskey="a"',
+        'PARENTFLAGS' => 'id="mdgToolbar_article"',
+        'HREF' => makeUrl($paths->page, null, true),
+        'TEXT' => $this->namespace_string
+      ));
+    
+    $tb .= $parser->run();
+    
+    $button = $this->makeParserText($tplvars['toolbar_button']);
+    
+    // Page toolbar
+    // Comments button
+    if ( $session->get_permissions('read') && getConfig('enable_comments')=='1' && $paths->namespace != 'Special' && $paths->namespace != 'Admin' && $paths->cpage['comments_on'] == 1 )
+    {
+      
+      $e = $db->sql_query('SELECT approved FROM '.table_prefix.'comments WHERE page_id=\''.$paths->cpage['urlname_nons'].'\' AND namespace=\''.$paths->namespace.'\';');
+      if ( !$e )
+      {
+        $db->_die();
+      }
+      $nc = $db->numrows();
+      $nu = 0;
+      $na = 0;
+      
+      while ( $r = $db->fetchrow() )
+      {  
+        if ( !$r['approved'] )
+        {
+          $nu++;
+        }
+        else
+        {
+          $na++;
+        }
+      }
+      
+      $db->free_result();
+      $n = ( $session->get_permissions('mod_comments') ) ? (string)$nc : (string)$na;
+      if ( $session->get_permissions('mod_comments') && $nu > 0 )
+      {
+        $n .= ' total/'.$nu.' unapp.';
+      }
+      
+      $button->assign_vars(array(
+          'FLAGS' => 'onclick="void(ajaxComments()); return false;" title="View the comments that other users have posted about this page (alt-c)" accesskey="c"',
+          'PARENTFLAGS' => 'id="mdgToolbar_discussion"',
+          'HREF' => makeUrl($paths->page, 'do=comments', true),
+          'TEXT' => 'discussion ('.$n.')',
+        ));
+      
+      $tb .= $button->run();
+    }
+    // Edit button
+    if($session->get_permissions('read') && ($paths->namespace != 'Special' && $paths->namespace != 'Admin') && ( $session->get_permissions('edit_page') && ( ( $paths->page_protected && $session->get_permissions('even_when_protected') ) || !$paths->page_protected ) ) )
+    {
+      $button->assign_vars(array(
+        'FLAGS' => 'onclick="void(ajaxEditor()); return false;" title="Edit the contents of this page (alt-e)" accesskey="e"',
+        'PARENTFLAGS' => 'id="mdgToolbar_edit"',
+        'HREF' => makeUrl($paths->page, 'do=edit', true),
+        'TEXT' => 'edit this page'
+        ));
+      $tb .= $button->run();
+    // View source button
+    }
+    else if($session->get_permissions('view_source') && ( !$session->get_permissions('edit_page') || !$session->get_permissions('even_when_protected') && $paths->page_protected ) && $paths->namespace != 'Special' && $paths->namespace != 'Admin') 
+    {
+      $button->assign_vars(array(
+        'FLAGS' => 'onclick="void(ajaxViewSource()); return false;" title="View the source code (wiki markup) that this page uses (alt-e)" accesskey="e"',
+        'PARENTFLAGS' => 'id="mdgToolbar_edit"',
+        'HREF' => makeUrl($paths->page, 'do=viewsource', true),
+        'TEXT' => 'view source'
+        ));
+      $tb .= $button->run();
+    }
+    // History button
+    if ( $session->get_permissions('read') /* && $paths->wiki_mode */ && $paths->page_exists && $paths->namespace != 'Special' && $paths->namespace != 'Admin' && $session->get_permissions('history_view') )
+    {
+      $button->assign_vars(array(
+        'FLAGS'       => 'onclick="void(ajaxHistory()); return false;" title="View a log of actions taken on this page (alt-h)" accesskey="h"',
+        'PARENTFLAGS' => 'id="mdgToolbar_history"',
+        'HREF'        => makeUrl($paths->page, 'do=history', true),
+        'TEXT'        => 'history'
+        ));
+      $tb .= $button->run();
+    }
+    
+    $menubtn = $this->makeParserText($tplvars['toolbar_menu_button']);
+    
+    // Additional actions menu
+    // Rename button
+    if ( $session->get_permissions('read') && $paths->page_exists && ( $session->get_permissions('rename') && ( $paths->page_protected && $session->get_permissions('even_when_protected') || !$paths->page_protected ) ) && $paths->namespace != 'Special' && $paths->namespace != 'Admin' )
+    {
+      $menubtn->assign_vars(array(
+          'FLAGS' => 'onclick="void(ajaxRename()); return false;" title="Change the display name of this page (alt-r)" accesskey="r"',
+          'HREF'  => makeUrl($paths->page, 'do=rename', true),
+          'TEXT'  => 'rename',
+        ));
+      $this->toolbar_menu .= $menubtn->run();
+    }
+    
+    // Vote-to-delete button
+    if ( $paths->wiki_mode && $session->get_permissions('vote_delete') && $paths->page_exists && $paths->namespace != 'Special' && $paths->namespace != 'Admin')
+    {
+      $menubtn->assign_vars(array(
+          'FLAGS' => 'onclick="void(ajaxDelVote()); return false;" title="Vote to have this page deleted (alt-d)" accesskey="d"',
+          'HREF'  => makeUrl($paths->page, 'do=delvote', true),
+          'TEXT'  => 'vote to delete this page',
+        ));
+      $this->toolbar_menu .= $menubtn->run();
+    }
+    
+    // Clear-votes button
+    if ( $session->get_permissions('read') && $paths->wiki_mode && $paths->page_exists && $paths->namespace != 'Special' && $paths->namespace != 'Admin' && $session->get_permissions('vote_reset') && $paths->cpage['delvotes'] > 0)
+    {
+      $menubtn->assign_vars(array(
+          'FLAGS' => 'onclick="void(ajaxResetDelVotes()); return false;" title="Vote to have this page deleted (alt-y)" accesskey="y"',
+          'HREF'  => makeUrl($paths->page, 'do=resetvotes', true),
+          'TEXT'  => 'reset deletion votes',
+        ));
+      $this->toolbar_menu .= $menubtn->run();
+    }
+    
+    // Printable page button
+    if ( $paths->page_exists && $paths->namespace != 'Special' && $paths->namespace != 'Admin' )
+    {
+      $menubtn->assign_vars(array(
+          'FLAGS' => 'title="View a version of this page that is suitable for printing"',
+          'HREF'  => makeUrl($paths->page, 'printable=yes', true),
+          'TEXT'  => 'view printable version',
+        ));
+      $this->toolbar_menu .= $menubtn->run();
+    }
+    
+    // Protect button
+    if($session->get_permissions('read') && $paths->wiki_mode && $paths->page_exists && $paths->namespace != 'Special' && $paths->namespace != 'Admin' && $session->get_permissions('protect'))
+    {
+      
+      $label = $this->makeParserText($tplvars['toolbar_label']);
+      $label->assign_vars(array('TEXT' => 'protection:'));
+      $t0 = $label->run();
+      
+      $ctmp = ''; 
+      if ( $paths->cpage['protected'] == 1 )
+      {
+        $ctmp=' style="text-decoration: underline;"';
+      }
+      $menubtn->assign_vars(array(
+          'FLAGS' => 'accesskey="i" onclick="ajaxProtect(1); return false;" id="protbtn_1" title="Prevents all non-administrators from editing this page. [alt-i]"'.$ctmp,
+          'HREF'  => makeUrl($paths->page, 'do=protect&level=1', true),
+          'TEXT'  => 'on'
+        ));
+      $t1 = $menubtn->run();
+      
+      $ctmp = '';
+      if ( $paths->cpage['protected'] == 0 )
+      {
+        $ctmp=' style="text-decoration: underline;"';
+      }
+      $menubtn->assign_vars(array(
+          'FLAGS' => 'accesskey="o" onclick="ajaxProtect(0); return false;" id="protbtn_0" title="Allows everyone to edit this page. [alt-o]"'.$ctmp,
+          'HREF'  => makeUrl($paths->page, 'do=protect&level=0', true),
+          'TEXT'  => 'off'
+        ));
+      $t2 = $menubtn->run();
+      
+      $ctmp = '';
+      if ( $paths->cpage['protected'] == 2 )
+      {
+        $ctmp = ' style="text-decoration: underline;"';
+      }
+      $menubtn->assign_vars(array(
+          'FLAGS' => 'accesskey="p" onclick="ajaxProtect(2); return false;" id="protbtn_2" title="Allows only users who have been registered for 4 days to edit this page. [alt-p]"'.$ctmp,
+          'HREF'  => makeUrl($paths->page, 'do=protect&level=2', true),
+          'TEXT'  => 'semi'
+        ));
+      $t3 = $menubtn->run();
+      
+      $this->toolbar_menu .= '        <table border="0" cellspacing="0" cellpadding="0">
+          <tr>
+            <td>'.$t0.'</td>
+            <td>'.$t1.'</td>
+            <td>'.$t2.'</td>
+            <td>'.$t3.'</td>
+          </tr>
+        </table>';
+    }
+    
+    // Wiki mode button
+    if($session->get_permissions('read') && $paths->page_exists && $session->get_permissions('set_wiki_mode') && $paths->namespace != 'Special' && $paths->namespace != 'Admin')
+    {
+      // label at start
+      $label = $this->makeParserText($tplvars['toolbar_label']);
+      $label->assign_vars(array('TEXT' => 'page wiki mode:'));
+      $t0 = $label->run();
+      
+      // on button
+      $ctmp = '';
+      if ( $paths->cpage['wiki_mode'] == 1 )
+      {
+        $ctmp = ' style="text-decoration: underline;"';
+      }
+      $menubtn->assign_vars(array(
+          'FLAGS' => 'onclick="ajaxSetWikiMode(1); return false;" id="wikibtn_1" title="Forces wiki functions to be allowed on this page."'.$ctmp,
+          'HREF' => makeUrl($paths->page, 'do=setwikimode&level=1', true),
+          'TEXT' => 'on'
+        ));
+      $t1 = $menubtn->run();
+      
+      // off button
+      $ctmp = '';
+      if ( $paths->cpage['wiki_mode'] == 0 )
+      {
+        $ctmp=' style="text-decoration: underline;"';
+      }
+      $menubtn->assign_vars(array(
+          'FLAGS' => 'onclick="ajaxSetWikiMode(0); return false;" id="wikibtn_0" title="Forces wiki functions to be disabled on this page."'.$ctmp,
+          'HREF' => makeUrl($paths->page, 'do=setwikimode&level=0', true),
+          'TEXT' => 'off'
+        ));
+      $t2 = $menubtn->run();
+      
+      // global button
+      $ctmp = ''; 
+      if ( $paths->cpage['wiki_mode'] == 2 )
+      {
+        $ctmp=' style="text-decoration: underline;"';
+      }
+      $menubtn->assign_vars(array(
+          'FLAGS' => 'onclick="ajaxSetWikiMode(2); return false;" id="wikibtn_2" title="Causes this page to use the global wiki mode setting (default)"'.$ctmp,
+          'HREF' => makeUrl($paths->page, 'do=setwikimode&level=2', true),
+          'TEXT' => 'global'
+        ));
+      $t3 = $menubtn->run();
+      
+      // Tack it onto the list of buttons that are already there...
+      $this->toolbar_menu .= '        <table border="0" cellspacing="0" cellpadding="0">
+          <tr>
+            <td>'.$t0.'</td>
+            <td>'.$t1.'</td>
+            <td>'.$t2.'</td>
+            <td>'.$t3.'</td>
+          </tr>
+        </table>';
+    }
+    
+    // Clear logs button
+    if ( $session->get_permissions('read') && $session->get_permissions('clear_logs') && $paths->wiki_mode && $paths->namespace != 'Special' && $paths->namespace != 'Admin' )
+    {
+      $menubtn->assign_vars(array(
+          'FLAGS' => 'onclick="void(ajaxClearLogs()); return false;" title="Remove all edit and action logs for this page from the database. IRREVERSIBLE! (alt-l)" accesskey="l"',
+          'HREF'  => makeUrl($paths->page, 'do=flushlogs', true),
+          'TEXT'  => 'clear page logs',
+        ));
+      $this->toolbar_menu .= $menubtn->run();
+    }
+    
+    // Delete page button
+    if ( $session->get_permissions('read') && $session->get_permissions('delete_page') && $paths->page_exists && $paths->namespace != 'Special' && $paths->namespace != 'Admin' )
+    {
+      $s = 'delete this page';
+      if ( $paths->cpage['delvotes'] == 1 )
+      {
+        $s .= ' (<b>'.$paths->cpage['delvotes'].'</b> vote)';
+      }
+      else if ( $paths->cpage['delvotes'] > 1 )
+      {
+        $s .= ' (<b>'.$paths->cpage['delvotes'].'</b> votes)';
+      }
+      
+      $menubtn->assign_vars(array(
+          'FLAGS' => 'onclick="void(ajaxDeletePage()); return false;" title="Delete this page. This is always reversible unless the logs are cleared. (alt-k)" accesskey="k"',
+          'HREF'  => makeUrl($paths->page, 'do=deletepage', true),
+          'TEXT'  => $s,
+        ));
+      $this->toolbar_menu .= $menubtn->run();
+      
+    }
+    
+    // Password-protect button
+    if(isset($paths->cpage['password']))
+    {
+      if ( $paths->cpage['password'] == '' )
+      {
+        $a = $session->get_permissions('password_set');
+      }
+      else
+      {
+        $a = $session->get_permissions('password_reset');
+      }
+    }
+    else
+    {
+      $a = $session->get_permissions('password_set');
+    }
+    if ( $a && $session->get_permissions('read') && $paths->page_exists && $paths->namespace != 'Special' && $paths->namespace != 'Admin' )
+    {
+      // label at start
+      $label = $this->makeParserText($tplvars['toolbar_label']);
+      $label->assign_vars(array('TEXT' => 'password:'));
+      $t0 = $label->run();
+      
+      $menubtn->assign_vars(array(
+          'FLAGS' => 'onclick="void(ajaxSetPassword()); return false;" title="Require a password in order for this page to be viewed"',
+          'HREF'  => '#',
+          'TEXT'  => 'set',
+        ));
+      $t = $menubtn->run();
+      
+      $this->toolbar_menu .= '<table border="0" cellspacing="0" cellpadding="0"><tr><td>'.$t0.'</td><td><input type="password" id="mdgPassSetField" size="10" /></td><td>'.$t.'</td></tr></table>';
+    }
+    
+    // Manage ACLs button
+    if($session->get_permissions('edit_acl') || $session->user_level >= USER_LEVEL_ADMIN)
+    {
+      $menubtn->assign_vars(array(
+          'FLAGS' => 'onclick="return ajaxOpenACLManager();" title="Manage who can do what with this page (alt-m)" accesskey="m"',
+          'HREF'  => makeUrl($paths->page, 'do=aclmanager', true),
+          'TEXT'  => 'manage page access',
+        ));
+      $this->toolbar_menu .= $menubtn->run();
+    }
+    
+    // Administer page button
+    if ( $session->user_level >= USER_LEVEL_ADMIN && $paths->page_exists && $paths->namespace != 'Special' && $paths->namespace != 'Admin' )
+    {
+      $menubtn->assign_vars(array(
+          'FLAGS' => 'onclick="void(ajaxAdminPage()); return false;" title="Administrative options for this page" accesskey="g"',
+          'HREF'  => makeUrlNS('Special', 'Administration', 'module='.$paths->nslist['Admin'].'PageManager', true),
+          'TEXT'  => 'administrative options',
+        ));
+      $this->toolbar_menu .= $menubtn->run();
+    }
+    
+    if ( strlen($this->toolbar_menu) > 0 )
+    {
+      $button->assign_vars(array(
+        'FLAGS'       => 'id="mdgToolbar_moreoptions" onclick="return false;" title="Additional options for working with this page"',
+        'PARENTFLAGS' => '',
+        'HREF'        => makeUrl($paths->page, 'do=moreoptions', true),
+        'TEXT'        => 'more options'
+        ));
+      $tb .= $button->run();
+    }
+    
+    $is_opera = (isset($_SERVER['HTTP_USER_AGENT']) && strstr($_SERVER['HTTP_USER_AGENT'], 'Opera')) ? true : false;
+    
+    $this->tpl_bool = Array(
+      'auth_admin'=>$session->user_level >= USER_LEVEL_ADMIN ? true : false,
+      'user_logged_in'=>$session->user_logged_in,
+      'opera'=>$is_opera,
+      );
+    
+    if($session->sid_super) { $ash = '&amp;auth='.$session->sid_super; $asq = "?auth=".$session->sid_super; $asa = "&auth=".$session->sid_super; $as2 = htmlspecialchars(urlSeparator).'auth='.$session->sid_super; }
+    else { $asq=''; $asa=''; $as2 = ''; $ash = ''; }
+    
+    $code = $plugins->setHook('compile_template');
+    foreach ( $code as $cmd )
+    {
+      eval($cmd);
+    }
+    
+    // Some additional sidebar processing
+    if($this->sidebar_extra != '') {
+      $se = $this->sidebar_extra;
+      $parser = $this->makeParserText($tplvars['sidebar_section_raw']);
+      $parser->assign_vars(Array('TITLE'=>'Links','CONTENT'=>$se));
+      $this->sidebar_extra = $parser->run();
+    }
+    
+    $this->sidebar_extra = $this->sidebar_extra.$this->sidebar_widgets;
+    
+    $this->tpl_bool['fixed_menus'] = false;
+    /* if($this->sidebar_extra == '') $this->tpl_bool['right_sidebar'] = false;
+    else */ $this->tpl_bool['right_sidebar'] = true;
+    
+    $this->tpl_bool['auth_rename'] = ( $paths->page_exists && ( $session->get_permissions('rename') && ( $paths->page_protected && $session->get_permissions('even_when_protected') || !$paths->page_protected ) ) && $paths->namespace != 'Special' && $paths->namespace != 'Admin');
+    
+    $this->tpl_bool['enable_uploads'] = ( getConfig('enable_uploads') == '1' && $session->get_permissions('upload_files') ) ? true : false;
+    
+    $this->tpl_bool['stupid_mode'] = false;
+    
+    if($paths->page == $paths->nslist['Special'].'Administration') $this->tpl_bool['in_admin'] = true;
+    else $this->tpl_bool['in_admin'] = false;
+    
+    $p = ( isset($_GET['printable']) ) ? '/printable' : '';
+    
+    // Add the e-mail address client code to the header
+    $this->add_header($email->jscode());
+    
+    // Generate the code for the Log out and Change theme sidebar buttons
+    // Once again, the new template parsing system can be used here
+    
+    $parser = $this->makeParserText($tplvars['sidebar_button']);
+    
+    $parser->assign_vars(Array(
+        'HREF'=>makeUrlNS('Special', 'Logout'),
+        'FLAGS'=>'onclick="mb_logout(); return false;"',
+        'TEXT'=>'Log out',
+      ));
+    
+    $logout_link = $parser->run();
+    
+    $parser->assign_vars(Array(
+        'HREF'=>makeUrlNS('Special', 'Login/' . $paths->page),
+        'FLAGS'=>'onclick="ajaxStartLogin(); return false;"',
+        'TEXT'=>'Log in',
+      ));
+    
+    $login_link = $parser->run();
+    
+    $parser->assign_vars(Array(
+        'HREF'=>makeUrlNS('Special', 'ChangeStyle/'.$paths->page),
+        'FLAGS'=>'onclick="ajaxChangeStyle(); return false;"',
+        'TEXT'=>'Change theme',
+      ));
+    
+    $theme_link = $parser->run();
+    
+    $SID = ($session->sid_super) ? $session->sid_super : '';
+    
+    // Generate the dynamic javascript vars
+    $js_dynamic = '    <script type="text/javascript">// <![CDATA[
+      // This section defines some basic and very important variables that are used later in the static Javascript library.
+      // SKIN DEVELOPERS: The template variable for this code block is {JS_DYNAMIC_VARS}. This MUST be inserted BEFORE the tag that links to the main Javascript lib.
+      var title=\''. str_replace('\'', '\\\'', str_replace('\\', '\\\\', $paths->fullpage)) .'\';
+      var page_exists='. ( ( $paths->page_exists) ? 'true' : 'false' ) .';
+      var scriptPath=\''. scriptPath .'\';
+      var contentPath=\''.contentPath.'\';
+      var ENANO_SID =\'' . $SID . '\';
+      var auth_level=' . $session->auth_level . ';
+      var USER_LEVEL_GUEST = ' . USER_LEVEL_GUEST . ';
+      var USER_LEVEL_MEMBER = ' . USER_LEVEL_MEMBER . ';
+      var USER_LEVEL_CHPREF = ' . USER_LEVEL_CHPREF . ';
+      var USER_LEVEL_MOD = ' . USER_LEVEL_MOD . ';
+      var USER_LEVEL_ADMIN = ' . USER_LEVEL_ADMIN . ';
+      var editNotice = \'' . ( (getConfig('wiki_edit_notice')=='1') ? str_replace("\n", "\\\n", RenderMan::render(getConfig('wiki_edit_notice_text'))) : '' ) . '\';
+      var prot = ' . ( ($paths->page_protected && !$session->get_permissions('even_when_protected')) ? 'true' : 'false' ) .'; // No, hacking this var won\'t work, it\'s re-checked on the server
+      var ENANO_SPECIAL_CREATEPAGE = \''. makeUrl($paths->nslist['Special'].'CreatePage') .'\';
+      var ENANO_CREATEPAGE_PARAMS = \'_do=&pagename='. addslashes($paths->cpage['name']) .'&namespace=' . $paths->namespace . '\';
+      var ENANO_SPECIAL_CHANGESTYLE = \''. makeUrlNS('Special', 'ChangeStyle') .'\';
+      var namespace_list = new Array();
+      var AES_BITS = '.AES_BITS.';
+      var AES_BLOCKSIZE = '.AES_BLOCKSIZE.';
+      var pagepass = \''. ( ( isset($_REQUEST['pagepass']) ) ? sha1($_REQUEST['pagepass']) : '' ) .'\';
+      var ENANO_THEME_LIST = \'';
+          foreach($this->theme_list as $t) {
+            if($t['enabled'])
+            {
+              $js_dynamic .= '<option value="'.$t['theme_id'].'"';
+              if($t['theme_id'] == $session->theme) $js_dynamic .= ' selected="selected"';
+              $js_dynamic .= '>'.$t['theme_name'].'</option>';
+            }
+          }
+      $js_dynamic .= '\';
+      var ENANO_CURRENT_THEME = \''. $session->theme .'\';';
+      foreach($paths->nslist as $k => $c)
+      {
+        $js_dynamic .= "namespace_list['{$k}'] = '$c';";
+      }
+      $js_dynamic .= "\n    //]]>\n    </script>";
+    
+    $tpl_strings = Array(
+      'PAGE_NAME'=>$paths->cpage['name'],
+      'PAGE_URLNAME'=>$paths->cpage['urlname'],
+      'SITE_NAME'=>getConfig('site_name'),
+      'USERNAME'=>$session->username,
+      'SITE_DESC'=>getConfig('site_desc'),
+      'TOOLBAR'=>$tb,
+      'SCRIPTPATH'=>scriptPath,
+      'CONTENTPATH'=>contentPath,
+      'ADMIN_SID_QUES'=>$asq,
+      'ADMIN_SID_AMP'=>$asa,
+      'ADMIN_SID_AMP_HTML'=>$ash,
+      'ADMIN_SID_AUTO'=>$as2,
+      'ADDITIONAL_HEADERS'=>$this->additional_headers,
+      'COPYRIGHT'=>getConfig('copyright_notice'),
+      'TOOLBAR_EXTRAS'=>$this->toolbar_menu,
+      'REQUEST_URI'=>$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'],
+      'STYLE_LINK'=>makeUrlNS('Special', 'CSS'.$p, null, true), //contentPath.$paths->nslist['Special'].'CSS' . $p,
+      'LOGIN_LINK'=>$login_link,
+      'LOGOUT_LINK'=>$logout_link,
+      'THEME_LINK'=>$theme_link,
+      'TEMPLATE_DIR'=>scriptPath.'/themes/'.$this->theme,
+      'THEME_ID'=>$this->theme,
+      'STYLE_ID'=>$this->style,
+      'JS_DYNAMIC_VARS'=>$js_dynamic,
+      'UNREAD_PMS'=>$session->unread_pms
+      );
+    
+    foreach ( $paths->nslist as $ns_id => $ns_prefix )
+    {
+      $tpl_strings[ 'NS_' . strtoupper($ns_id) ] = $ns_prefix;
+    }
+    
+    $this->tpl_strings = array_merge($tpl_strings, $this->tpl_strings);
+    list($this->tpl_strings['SIDEBAR_LEFT'], $this->tpl_strings['SIDEBAR_RIGHT'], $min) = $this->fetch_sidebar();
+    $this->tpl_bool['sidebar_left']  = ( $this->tpl_strings['SIDEBAR_LEFT']  != $min) ? true : false;
+    $this->tpl_bool['sidebar_right'] = ( $this->tpl_strings['SIDEBAR_RIGHT'] != $min) ? true : false;
+    $this->tpl_bool['right_sidebar'] = $this->tpl_bool['sidebar_right']; // backward compatibility
+  }
+  
+  function header($simple = false) 
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    ob_start();
+    
+    if(!$this->theme_loaded)
+    {
+      $this->load_theme($session->theme, $session->style);
+    }
+    
+    $headers_sent = true;
+    dc_here('template: generating and sending the page header');
+    if(!defined('ENANO_HEADERS_SENT'))
+      define('ENANO_HEADERS_SENT', '');
+    if(!$this->no_headers) echo ( $simple ) ? $this->process_template('simple-header.tpl') : $this->process_template('header.tpl');
+    if ( !$simple && $session->user_logged_in && $session->unread_pms > 0 )
+    {
+      echo $this->notify_unread_pms();
+    }
+    if ( !$simple && $session->sw_timed_out )
+    {
+      $login_link = makeUrlNS('Special', 'Login/' . $paths->fullpage, 'level=' . $session->user_level, true);
+      echo '<div class="usermessage">';
+      echo '<b>Your administrative session has timed out.</b> <a href="' . $login_link . '">Log in again</a>';
+      echo '</div>';
+    }
+  }
+  function footer($simple = false)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    dc_here('template: generating and sending the page footer');
+    if(!$this->no_headers) {
+      
+      if(!defined('ENANO_HEADERS_SENT'))
+        $this->header();
+      
+      global $_starttime;
+      if(isset($_GET['sqldbg']) && $session->get_permissions('mod_misc'))
+      {
+        echo '<h3>Query list as requested on URI</h3><pre style="margin-left: 1em">';
+        echo $db->sql_backtrace();
+        echo '</pre>';
+      }
+      
+      $f = microtime_float();
+      $f = $f - $_starttime;
+      $f = round($f, 4);
+      $dbg = 'Time: '.$f.'s  |  Queries: '.$db->num_queries;
+      $t = ( $simple ) ? $this->process_template('simple-footer.tpl') : $this->process_template('footer.tpl');
+      $t = str_replace('[[Stats]]', $dbg, $t);
+      $t = str_replace('[[NumQueries]]', (string)$db->num_queries, $t);
+      $t = str_replace('[[GenTime]]', (string)$f, $t);
+      echo $t;
+      
+      ob_end_flush();
+    }
+    else return '';
+  }
+  function getHeader()
+  {
+    $headers_sent = true;
+    dc_here('template: generating and sending the page header');
+    if(!defined('ENANO_HEADERS_SENT'))
+      define('ENANO_HEADERS_SENT', '');
+    if(!$this->no_headers) return $this->process_template('header.tpl');
+  }
+  function getFooter()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    dc_here('template: generating and sending the page footer');
+    if(!$this->no_headers) {
+      global $_starttime;
+      $t = '';
+      
+      if(isset($_GET['sqldbg']) && $session->get_permissions('mod_misc'))
+      {
+        $t .= '<h3>Query list as requested on URI</h3><pre style="margin-left: 1em">';
+        $t .= $db->sql_backtrace();
+        $t .= '</pre>';
+      }
+      
+      $f = microtime_float();
+      $f = $f - $_starttime;
+      $f = round($f, 4);
+      $dbg = 'Time: '.$f.'s  |  Queries: '.$db->num_queries;
+      $t.= $this->process_template('footer.tpl');
+      $t = str_replace('[[Stats]]', $dbg, $t);
+      $t = str_replace('[[NumQueries]]', (string)$db->num_queries, $t);
+      $t = str_replace('[[GenTime]]', (string)$f, $t);
+      return $t;
+    }
+    else return '';
+  }
+  
+  function process_template($file) {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(!defined('ENANO_TEMPLATE_LOADED'))
+    {
+      $this->load_theme();
+      $this->init_vars();
+    }
+    eval($this->compile_template($file));
+    return $tpl_code;
+  }
+  
+  function extract_vars($file) {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(!$this->theme)
+    {
+      die('$template->extract_vars(): theme not yet loaded, so we can\'t open template files yet...this is a bug and should be reported.<br /><br />Backtrace, most recent call first:<pre>'.enano_debug_print_backtrace(true).'</pre>');
+    }
+    if(!is_file(ENANO_ROOT . '/themes/'.$this->theme.'/'.$file)) die('Cannot find '.$file.' file for style "'.$this->theme.'", exiting');
+    $text = file_get_contents(ENANO_ROOT . '/themes/'.$this->theme.'/'.$file);
+    preg_match_all('#<\!-- VAR ([A-z0-9_-]*) -->(.*?)<\!-- ENDVAR \\1 -->#is', $text, $matches);
+    $tplvars = Array();
+    for($i=0;$i<sizeof($matches[1]);$i++)
+    {
+      $tplvars[$matches[1][$i]] = $matches[2][$i];
+    }
+    return $tplvars;
+  }
+  function compile_template($text) {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(!is_file(ENANO_ROOT . '/themes/'.$this->theme.'/'.$text)) die('Cannot find '.$text.' file for style, exiting');
+    $n = $text;
+    $tpl_filename = ENANO_ROOT . '/cache/' . $this->theme . '-' . str_replace('/', '-', $n) . '.php';
+    if(!is_file(ENANO_ROOT . '/themes/'.$this->theme.'/'.$text)) die('Cannot find '.$text.' file for style, exiting');
+    if(file_exists($tpl_filename) && getConfig('cache_thumbs')=='1')
+    {
+      include($tpl_filename);
+      $text = file_get_contents(ENANO_ROOT . '/themes/'.$this->theme.'/'.$text);
+      if(isset($md5) && $md5 == md5($text)) {
+        return str_replace('\\"', '"', $tpl_text);
+      }
+    }
+    $text = file_get_contents(ENANO_ROOT . '/themes/'.$this->theme.'/'.$n);
+    
+    $md5 = md5($text);
+    
+    $seed = md5 ( microtime() . mt_rand() );
+    preg_match_all("/<\?php(.*?)\?>/is", $text, $m);
+    //die('<pre>'.htmlspecialchars(print_r($m, true)).'</pre>');
+    for($i = 0; $i < sizeof($m[1]); $i++)
+    {
+      $text = str_replace("<?php{$m[1][$i]}?>", "{PHPCODE:{$i}:{$seed}}", $text);
+    }
+    //die('<pre>'.htmlspecialchars($text).'</pre>');
+    $text = 'ob_start(); echo \''.str_replace('\'', '\\\'', $text).'\'; $tpl_code = ob_get_contents(); ob_end_clean();';
+    $text = preg_replace('#<!-- BEGIN (.*?) -->#is', '\'; if(isset($this->tpl_bool[\'\\1\']) && $this->tpl_bool[\'\\1\']) { echo \'', $text);
+    $text = preg_replace('#<!-- IFSET (.*?) -->#is', '\'; if(isset($this->tpl_strings[\'\\1\'])) { echo \'', $text);
+    $text = preg_replace('#<!-- IFPLUGIN (.*?) -->#is', '\'; if(getConfig(\'plugin_\\1\')==\'1\') { echo \'', $text);
+    $text = preg_replace('#<!-- SYSMSG (.*?) -->#is', '\'; echo $template->tplWikiFormat($paths->sysMsg(\'\\1\')); echo \'', $text);
+    $text = preg_replace('#<!-- BEGINNOT (.*?) -->#is', '\'; if(!$this->tpl_bool[\'\\1\']) { echo \'', $text);
+    $text = preg_replace('#<!-- BEGINELSE (.*?) -->#is', '\'; } else { echo \'', $text);
+    $text = preg_replace('#<!-- END (.*?) -->#is', '\'; } echo \'', $text);
+    $text = preg_replace('#\{([A-z0-9]*)\}#is', '\'.$this->tpl_strings[\'\\1\'].\'', $text);
+    for($i = 0; $i < sizeof($m[1]); $i++)
+    {
+      $text = str_replace("{PHPCODE:{$i}:{$seed}}", "'; {$m[1][$i]} echo '", $text);
+    }
+    if(is_writable(ENANO_ROOT.'/cache/') && getConfig('cache_thumbs')=='1')
+    {
+      //die($tpl_filename);
+      $h = fopen($tpl_filename, 'w');
+      if(!$h) return $text;
+      $t = addslashes($text);
+      fwrite($h, '<?php $md5 = \''.$md5.'\'; $tpl_text = \''.$t.'\'; ?>');
+      fclose($h);
+    }
+    return $text; //('<pre>'.htmlspecialchars($text).'</pre>');
+  }
+  
+  function compile_template_text($text) {
+    $seed = md5 ( microtime() . mt_rand() );
+    preg_match_all("/<\?php(.*?)\?>/is", $text, $m);
+    //die('<pre>'.htmlspecialchars(print_r($m, true)).'</pre>');
+    for($i = 0; $i < sizeof($m[1]); $i++)
+    {
+      $text = str_replace("<?php{$m[1][$i]}?>", "{PHPCODE:{$i}:{$seed}}", $text);
+    }
+    //die('<pre>'.htmlspecialchars($text).'</pre>');
+    $text = 'ob_start(); echo \''.str_replace('\'', '\\\'', $text).'\'; $tpl_code = ob_get_contents(); ob_end_clean(); return $tpl_code;';
+    $text = preg_replace('#<!-- BEGIN (.*?) -->#is', '\'; if(isset($this->tpl_bool[\'\\1\']) && $this->tpl_bool[\'\\1\']) { echo \'', $text);
+    $text = preg_replace('#<!-- IFSET (.*?) -->#is', '\'; if(isset($this->tpl_strings[\'\\1\'])) { echo \'', $text);
+    $text = preg_replace('#<!-- IFPLUGIN (.*?) -->#is', '\'; if(getConfig(\'plugin_\\1\')==\'1\') { echo \'', $text);
+    $text = preg_replace('#<!-- SYSMSG (.*?) -->#is', '\'; echo $template->tplWikiFormat($paths->sysMsg(\'\\1\')); echo \'', $text);
+    $text = preg_replace('#<!-- BEGINNOT (.*?) -->#is', '\'; if(!$this->tpl_bool[\'\\1\']) { echo \'', $text);
+    $text = preg_replace('#<!-- BEGINELSE (.*?) -->#is', '\'; } else { echo \'', $text);
+    $text = preg_replace('#<!-- END (.*?) -->#is', '\'; } echo \'', $text);
+    $text = preg_replace('#\{([A-z0-9]*)\}#is', '\'.$this->tpl_strings[\'\\1\'].\'', $text);
+    for($i = 0; $i < sizeof($m[1]); $i++)
+    {
+      $text = str_replace("{PHPCODE:{$i}:{$seed}}", "'; {$m[1][$i]} echo '", $text);
+    }
+    return $text; //('<pre>'.htmlspecialchars($text).'</pre>');
+  }
+  
+  function parse($text)
+  {
+    $text = $this->compile_template_text($text);
+    return eval($text);
+  }
+  
+  // Steps to turn this:
+  //   [[Project:Community Portal]]
+  // into this:
+  //   <a href="/Project:Community_Portal">Community Portal</a>
+  // Must be done WITHOUT creating eval'ed code!!!
+  
+  // 1. preg_replace \[\[([a-zA-Z0-9 -_:]*?)\]\] with <a href="'.contentPath.'\\1">\\1</a>
+  // 2. preg_match_all <a href="'.preg_quote(contentPath).'([a-zA-Z0-9 -_:]*?)">
+  // 3. For each match, replace matches with identifiers
+  // 4. For each match, str_replace ' ' with '_'
+  // 5. For each match, str_replace match_id:random_val with $matches[$match_id]
+  
+  // The template language is really a miniature programming language; with variables, conditionals, everything!
+  // So you can implement custom logic into your sidebar if you wish.
+  // "Real" PHP support coming soon :-D
+  
+  function tplWikiFormat($message, $filter_links = false, $filename = 'elements.tpl') {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $filter_links = false;
+    $tplvars = $this->extract_vars($filename);
+    if($session->sid_super) $as = htmlspecialchars(urlSeparator).'auth='.$session->sid_super;
+    else $as = '';
+    error_reporting(E_ALL);
+    $random_id = sha1(microtime().''); // A temp value
+    
+    /*
+     * PREPROCESSOR
+     */
+    
+    // Variables
+    
+    preg_match_all('#\$([A-Z_-]+)\$#', $message, $links);
+    $links = $links[1];
+    
+    for($i=0;$i<sizeof($links);$i++)
+    {
+      $message = str_replace('$'.$links[$i].'$', $this->tpl_strings[$links[$i]], $message);
+    }
+    
+    // Conditionals
+    
+    preg_match_all('#\{if ([A-Za-z0-9_ &\|\!-]*)\}(.*?)\{\/if\}#is', $message, $links);
+    
+    for($i=0;$i<sizeof($links[1]);$i++)
+    {
+      $message = str_replace('{if '.$links[1][$i].'}'.$links[2][$i].'{/if}', '{CONDITIONAL:'.$i.':'.$random_id.'}', $message);
+      
+      // Time for some manual parsing...
+      $chk = false;
+      $current_id = '';
+      $prn_level = 0;
+      // Used to keep track of where we are in the conditional
+      // Object of the game: turn {if this && ( that OR !something_else )} ... {/if} into if( ( isset($this->tpl_bool['that']) && $this->tpl_bool['that'] ) && ...
+      // Method of attack: escape all variables, ignore all else. Non-valid code is filtered out by a regex above.
+      $in_var_now = true;
+      $in_var_last = false;
+      $current_var = '';
+      $current_var_start_pos = 0;
+      $current_var_end_pos   = 0;
+      $j = -1;
+      $links[1][$i] = $links[1][$i] . ' ';
+      $d = strlen($links[1][$i]);
+      while($j < $d)
+      {
+        $j++;
+        $in_var_last = $in_var_now;
+        
+        $char = substr($links[1][$i], $j, 1);
+        $in_var_now = ( preg_match('#^([A-z0-9_]*){1}$#', $char) ) ? true : false;
+        if(!$in_var_last && $in_var_now)
+        {
+          $current_var_start_pos = $j;
+        }
+        if($in_var_last && !$in_var_now)
+        {
+          $current_var_end_pos = $j;
+        }
+        if($in_var_now)
+        {
+          $current_var .= $char;
+          continue;
+        }
+        // OK we are not inside of a variable. That means that we JUST hit the end because the counter ($j) will be advanced to the beginning of the next variable once processing here is complete.
+        if($char != ' ' && $char != '(' && $char != ')' && $char != 'A' && $char != 'N' && $char != 'D' && $char != 'O' && $char != 'R' && $char != '&' && $char != '|' && $char != '!' && $char != '<' && $char != '>' && $char != '0' && $char != '1' && $char != '2' && $char != '3' && $char != '4' && $char != '5' && $char != '6' && $char != '7' && $char != '8' && $char != '9')
+        {
+          // XSS attack! Bail out
+          echo '<p><b>Error:</b> Syntax error (possibly XSS attack) caught in template code:</p>';
+          echo '<pre>';
+          echo '{if '.$links[1][$i].'}';
+          echo "\n    ";
+          for($k=0;$k<$j;$k++) echo " ";
+          echo '<span style="color: red;">^</span>';
+          echo '</pre>';
+          continue 2;
+        }
+        if($current_var != '')
+        {
+          $cd = '( isset($this->tpl_bool[\''.$current_var.'\']) && $this->tpl_bool[\''.$current_var.'\'] )';
+          $cvt = substr($links[1][$i], 0, $current_var_start_pos) . $cd . substr($links[1][$i], $current_var_end_pos, strlen($links[1][$i]));
+          $j = $j + strlen($cd) - strlen($current_var);
+          $current_var = '';
+          $links[1][$i] = $cvt;
+          $d = strlen($links[1][$i]);
+        }
+      }
+      $links[1][$i] = substr($links[1][$i], 0, strlen($links[1][$i])-1);
+      $links[1][$i] = '$chk = ( '.$links[1][$i].' ) ? true : false;';
+      eval($links[1][$i]);
+      
+      if($chk) { // isset($this->tpl_bool[$links[1][$i]]) && $this->tpl_bool[$links[1][$i]]
+        if(strstr($links[2][$i], '{else}')) $c = substr($links[2][$i], 0, strpos($links[2][$i], '{else}'));
+        else $c = $links[2][$i];
+        $message = str_replace('{CONDITIONAL:'.$i.':'.$random_id.'}', $c, $message);
+      } else {
+        if(strstr($links[2][$i], '{else}')) $c = substr($links[2][$i], strpos($links[2][$i], '{else}')+6, strlen($links[2][$i]));
+        else $c = '';
+        $message = str_replace('{CONDITIONAL:'.$i.':'.$random_id.'}', $c, $message);
+      }
+    }
+    
+    preg_match_all('#\{!if ([A-Za-z_-]*)\}(.*?)\{\/if\}#is', $message, $links);
+    
+    for($i=0;$i<sizeof($links[1]);$i++)
+    {
+      $message = str_replace('{!if '.$links[1][$i].'}'.$links[2][$i].'{/if}', '{CONDITIONAL:'.$i.':'.$random_id.'}', $message);
+      if(isset($this->tpl_bool[$links[1][$i]]) && $this->tpl_bool[$links[1][$i]]) {
+        if(strstr($links[2][$i], '{else}')) $c = substr($links[2][$i], strpos($links[2][$i], '{else}')+6, strlen($links[2][$i]));
+        else $c = '';
+        $message = str_replace('{CONDITIONAL:'.$i.':'.$random_id.'}', $c, $message);
+      } else {
+        if(strstr($links[2][$i], '{else}')) $c = substr($links[2][$i], 0, strpos($links[2][$i], '{else}'));
+        else $c = $links[2][$i];
+        $message = str_replace('{CONDITIONAL:'.$i.':'.$random_id.'}', $c, $message);
+      }
+    }
+    
+    /*
+     * HTML RENDERER
+     */
+     
+    // Images
+    $j = preg_match_all('#\[\[:'.$paths->nslist['File'].'([\w\s0-9_\(\)!@%\^\+\|\.-]+?)\]\]#is', $message, $matchlist);
+    $matches = Array();
+    $matches['images'] = $matchlist[1];
+    for($i=0;$i<sizeof($matchlist[1]);$i++)
+    {
+      if(isPage($paths->nslist['File'].$matches['images'][$i]))
+      {
+        $message = str_replace('[[:'.$paths->nslist['File'].$matches['images'][$i].']]',
+                               '<img alt="'.$matches['images'][$i].'" style="border: 0" src="'.makeUrlNS('Special', 'DownloadFile/'.$matches['images'][$i]).'" />',
+                               $message);
+      }
+    }
+    
+    // Internal links
+    
+    $text_parser = $this->makeParserText($tplvars['sidebar_button']);
+    
+    preg_match_all('#\[\[([a-zA-Z0-9 -_]*?)\]\]#is', $message, $il);
+    for($i=0;$i<sizeof($il[1]);$i++)
+    {
+      $href = makeUrl(str_replace(' ', '_', $il[1][$i]), null, true);
+      $text_parser->assign_vars(Array(
+          'HREF'  => $href,
+          'FLAGS' => '',
+          'TEXT'  => $il[1][$i]
+        ));
+      $message = str_replace("[[{$il[1][$i]}]]", $text_parser->run(), $message);
+    }
+    
+    preg_match_all('#\[\[([a-zA-Z0-9 -_]*?)\|([a-zA-Z0-9!@\#\$%\^&\*\(\)\{\} -_]*?)\]\]#is', $message, $il);
+    for($i=0;$i<sizeof($il[1]);$i++)
+    {
+      $href = makeUrl(str_replace(' ', '_', $il[1][$i]), null, true);
+      $text_parser->assign_vars(Array(
+          'HREF'  => $href,
+          'FLAGS' => '',
+          'TEXT'  => $il[2][$i]
+        ));
+      $message = str_replace("[[{$il[1][$i]}|{$il[2][$i]}]]", $text_parser->run(), $message);
+    }
+    
+    // External links
+    $message = preg_replace('#\[(http|ftp|irc):\/\/([a-z0-9\/:_\.\?&%\#@_\\\\-]+?)\\ ([^\]]+)]#', '<a href="\\1://\\2">\\3</a><br style="display: none;" />', $message);
+    $message = preg_replace('#\[(http|ftp|irc):\/\/([a-z0-9\/:_\.\?&%\#@_\\\\-]+?)\\]#', '<a href="\\1://\\2">\\1://\\2</a><br style="display: none;" />', $message);
+    
+    $parser1 = $this->makeParserText($tplvars['sidebar_section']);
+    $parser2 = $this->makeParserText($tplvars['sidebar_section_raw']);
+                            
+    preg_match_all('#\{slider(2|)=(.*?)\}(.*?)\{\/slider(2|)\}#is',  $message, $sb);
+    
+    // Modified to support the sweet new template var system
+    for($i=0;$i<sizeof($sb[1]);$i++)
+    {
+      $p = ($sb[1][$i] == '2') ? $parser2 : $parser1;
+      $p->assign_vars(Array('TITLE'=>$sb[2][$i],'CONTENT'=>$sb[3][$i]));
+      $message = str_replace("{slider{$sb[1][$i]}={$sb[2][$i]}}{$sb[3][$i]}{/slider{$sb[4][$i]}}", $p->run(), $message);
+    }
+    
+    /*
+    Extras ;-)
+    $message = preg_replace('##is', '', $message);
+    $message = preg_replace('##is', '', $message);
+    $message = preg_replace('##is', '', $message);
+    $message = preg_replace('##is', '', $message);
+    $message = preg_replace('##is', '', $message);
+    */
+    
+    //die('<pre>'.htmlspecialchars($message).'</pre>');
+    //eval($message); exit;
+    return $message;
+  }
+  
+  /**
+   * Print a text field that auto-completes a username entered into it.
+   * @param string $name - the name of the form field
+   * @return string
+   */
+   
+  function username_field($name, $value = false)
+  {
+    $randomid = md5( time() . microtime() . mt_rand() );
+    $text = '<input name="'.$name.'" onkeyup="ajaxUserNameComplete(this)" autocomplete="off" type="text" size="30" id="userfield_'.$randomid.'"';
+    if($value) $text .= ' value="'.$value.'"';
+    $text .= ' />';
+    return $text;
+  }
+  
+  /**
+   * Print a text field that auto-completes a page name entered into it.
+   * @param string $name - the name of the form field
+   * @return string
+   */
+   
+  function pagename_field($name, $value = false)
+  {
+    $randomid = md5( time() . microtime() . mt_rand() );
+    $text = '<input name="'.$name.'" onkeyup="ajaxPageNameComplete(this)" type="text" size="30" id="pagefield_'.$randomid.'"';
+    if($value) $text .= ' value="'.$value.'"';
+    $text .= ' />';
+    $text .= '<script type="text/javascript">
+        var inp = document.getElementById(\'pagefield_' . $randomid . '\');
+        var f = get_parent_form(inp);
+        if ( f )
+        {
+          if ( typeof(f.onsubmit) != \'function\' )
+          {
+            f.onsubmit = function() {
+              if ( !submitAuthorized )
+              {
+                return false;
+              }
+            }
+          }
+        }</script>';
+    return $text;
+  }
+  
+  /**
+   * Sends a textarea that can be converted to and from a TinyMCE widget on the fly.
+   * @param string The name of the form element
+   * @param string The initial content. Optional, defaults to blank
+   * @param int Rows in textarea
+   * @param int Columns in textarea
+   * @return string HTML and Javascript code.
+   */
+  
+  function tinymce_textarea($name, $content = '', $rows = 20, $cols = 60)
+  {
+    $randomid = md5(microtime() . mt_rand());
+    $html = '';
+    $html .= '<textarea name="' . $name . '" rows="'.$rows.'" cols="'.$cols.'" style="width: 100%;" id="toggleMCEroot_'.$randomid.'">' . $content . '</textarea>';
+    $html .= '<div style="float: right; display: table;" id="mceSwitchAgent_' . $randomid . '">text editor&nbsp;&nbsp;|&nbsp;&nbsp;<a href="#" onclick="toggleMCE_'.$randomid.'(); return false;">graphical editor</a></div>';
+    $html .= '<script type="text/javascript">
+                // <![CDATA[
+                function toggleMCE_'.$randomid.'()
+                {
+                  var the_obj = document.getElementById(\'toggleMCEroot_' . $randomid . '\');
+                  var panel = document.getElementById(\'mceSwitchAgent_' . $randomid . '\');
+                  if ( the_obj.dnIsMCE == "yes" )
+                  {
+                    $dynano(the_obj).destroyMCE();
+                    panel.innerHTML = \'text editor&nbsp;&nbsp;|&nbsp;&nbsp;<a href="#" onclick="toggleMCE_'.$randomid.'(); return false;">graphical editor</a>\';
+                  }
+                  else
+                  {
+                    $dynano(the_obj).switchToMCE();
+                    panel.innerHTML = \'<a href="#" onclick="toggleMCE_'.$randomid.'(); return false;">text editor</a>&nbsp;&nbsp;|&nbsp;&nbsp;graphical editor\';
+                  }
+                }
+                // ]]>
+              </script>';
+    return $html;
+  }
+  
+  /**
+   * Allows individual parsing of template files. Similar to phpBB but follows the spirit of object-oriented programming ;)
+   * Returns on object of class templateIndividual. Usage instructions can be found in the inline docs for that class.
+   * @param $filename the filename of the template to be parsed
+   * @return object
+   */
+   
+  function makeParser($filename)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $filename = ENANO_ROOT.'/themes/'.$template->theme.'/'.$filename;
+    if(!file_exists($filename)) die('templateIndividual: file '.$filename.' does not exist');
+    $code = file_get_contents($filename);
+    $parser = new templateIndividual($code);
+    return $parser;
+  }
+  
+  /**
+   * Same as $template->makeParser(), but takes a string instead of a filename.
+   * @param $text the text to parse
+   * @return object
+   */
+   
+  function makeParserText($code)
+  {
+    $parser = new templateIndividual($code);
+    return $parser;
+  }
+  
+  /**
+   * Fetch the HTML for a plugin-added sidebar block
+   * @param $name the plugin name
+   * @return string
+   */
+   
+  function fetch_block($id)
+  {
+    if(isset($this->plugin_blocks[$id])) return $this->plugin_blocks[$id];
+    else return false;
+  }
+  
+  /**
+   * Fetches the contents of both sidebars.
+   * @return array - key 0 is left, key 1 is right
+   * @example list($left, $right) = $template->fetch_sidebar();
+   */
+   
+  function fetch_sidebar()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    $left = '';
+    $right = '';
+    
+    if ( !$this->fetch_block('Links') )
+      $this->initLinksWidget();
+    
+    $q = $db->sql_query('SELECT item_id,sidebar_id,block_name,block_type,block_content FROM '.table_prefix.'sidebar WHERE item_enabled=1 ORDER BY sidebar_id ASC, item_order ASC;');
+    if(!$q) $db->_die('The sidebar text data could not be selected.');
+    
+    $vars = $this->extract_vars('elements.tpl');
+    
+    if(isset($vars['sidebar_top'])) 
+    {
+      $left  .= $this->parse($vars['sidebar_top']);
+      $right .= $this->parse($vars['sidebar_top']);
+    }
+    while($row = $db->fetchrow())
+    {
+      switch($row['block_type'])
+      {
+        case BLOCK_WIKIFORMAT:
+        default:
+          $parser = $this->makeParserText($vars['sidebar_section']);
+          $c = RenderMan::render($row['block_content']);
+          break;
+        case BLOCK_TEMPLATEFORMAT:
+          $parser = $this->makeParserText($vars['sidebar_section']);
+          $c = $this->tplWikiFormat($row['block_content']);
+          break;
+        case BLOCK_HTML:
+          $parser = $this->makeParserText($vars['sidebar_section_raw']);
+          $c = $row['block_content'];
+          break;
+        case BLOCK_PHP:
+          $parser = $this->makeParserText($vars['sidebar_section_raw']);
+          ob_start();
+          @eval($row['block_content']);
+          $c = ob_get_contents();
+          ob_end_clean();
+          break;
+        case BLOCK_PLUGIN:
+          $parser = $this->makeParserText($vars['sidebar_section_raw']);
+          $c = (gettype($this->fetch_block($row['block_content'])) == 'string') ? $this->fetch_block($row['block_content']) : 'Can\'t find plugin block';
+          break;
+      }
+      $parser->assign_vars(Array( 'TITLE'=>$this->tplWikiFormat($row['block_name']), 'CONTENT'=>$c ));
+      if    ($row['sidebar_id'] == SIDEBAR_LEFT ) $left  .= $parser->run();
+      elseif($row['sidebar_id'] == SIDEBAR_RIGHT) $right .= $parser->run();
+      unset($parser);
+    }
+    $db->free_result();
+    if(isset($vars['sidebar_bottom'])) 
+    {
+      $left  .= $this->parse($vars['sidebar_bottom']);
+      $right .= $this->parse($vars['sidebar_bottom']);
+    }
+    $min = '';
+    if(isset($vars['sidebar_top'])) 
+    {
+      $min .= $this->parse($vars['sidebar_top']);
+    }
+    if(isset($vars['sidebar_bottom']))
+    {
+      $min .= $this->parse($vars['sidebar_bottom']);
+    }
+    return Array($left, $right, $min);
+  }
+  
+  function initLinksWidget()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    // SourceForge/W3C buttons
+    $ob = Array();
+    if(getConfig('powered_btn') =='1') $ob[] = '<a style="text-align: center;" href="http://www.enanocms.org/"                  onclick="window.open(this.href);return false;"><img alt="Powered by Enano" src="'.scriptPath.'/images/about-powered-enano.png" onmouseover="this.src=\''.scriptPath.'/images/about-powered-enano-hover.png\';" onmouseout="this.src=\''.scriptPath.'/images/about-powered-enano.png\';" style="border-width: 0px;" width="88" height="31" /></a>';
+    if(getConfig('sflogo_enabled')=='1')
+    {
+      $ob[] = '<a style="text-align: center;" href="http://sourceforge.net/" onclick="window.open(this.href);return false;"><img style="border-width: 0px;" alt="SourceForge.net Logo" src="http://sflogo.sourceforge.net/sflogo.php?group_id='.getConfig('sflogo_groupid').'&amp;type='.getConfig('sflogo_type').'" /></a>';
+    }
+    if(getConfig('w3c_v32')     =='1') $ob[] = '<a style="text-align: center;" href="http://validator.w3.org/check?uri=referer" onclick="window.open(this.href);return false;"><img style="border: 0px solid #FFFFFF;" alt="Valid HTML 3.2"  src="http://www.w3.org/Icons/valid-html32" /></a>';
+    if(getConfig('w3c_v40')     =='1') $ob[] = '<a style="text-align: center;" href="http://validator.w3.org/check?uri=referer" onclick="window.open(this.href);return false;"><img style="border: 0px solid #FFFFFF;" alt="Valid HTML 4.0"  src="http://www.w3.org/Icons/valid-html40" /></a>';
+    if(getConfig('w3c_v401')    =='1') $ob[] = '<a style="text-align: center;" href="http://validator.w3.org/check?uri=referer" onclick="window.open(this.href);return false;"><img style="border: 0px solid #FFFFFF;" alt="Valid HTML 4.01" src="http://www.w3.org/Icons/valid-html401" /></a>';
+    if(getConfig('w3c_vxhtml10')=='1') $ob[] = '<a style="text-align: center;" href="http://validator.w3.org/check?uri=referer" onclick="window.open(this.href);return false;"><img style="border: 0px solid #FFFFFF;" alt="Valid XHTML 1.0" src="http://www.w3.org/Icons/valid-xhtml10" /></a>';
+    if(getConfig('w3c_vxhtml11')=='1') $ob[] = '<a style="text-align: center;" href="http://validator.w3.org/check?uri=referer" onclick="window.open(this.href);return false;"><img style="border: 0px solid #FFFFFF;" alt="Valid XHTML 1.1" src="http://www.w3.org/Icons/valid-xhtml11" /></a>';
+    if(getConfig('w3c_vcss')    =='1') $ob[] = '<a style="text-align: center;" href="http://validator.w3.org/check?uri=referer" onclick="window.open(this.href);return false;"><img style="border: 0px solid #FFFFFF;" alt="Valid CSS"       src="http://www.w3.org/Icons/valid-css" /></a>';
+    if(getConfig('dbd_button')  =='1') $ob[] = '<a style="text-align: center;" href="http://www.defectivebydesign.org/join/button" onclick="window.open(this.href);return false;"><img style="border: 0px solid #FFFFFF;" alt="DRM technology restricts what you can do with your computer" src="http://defectivebydesign.org/sites/nodrm.civicactions.net/files/images/dbd_sm_btn.gif" /><br /><small>Protect your freedom >></small></a>';
+    
+    $code = $plugins->setHook('links_widget');
+    foreach ( $code as $cmd )
+    {
+      eval($cmd);
+    }
+    
+    if(count($ob) > 0) $sb_links = '<div style="text-align: center; padding: 5px 0;">'.implode('<br />', $ob).'</div>';
+    else $sb_links = '';
+    
+    $this->sidebar_widget('Links', $sb_links);
+  }
+  
+  /**
+   * Builds a box showing unread private messages.
+   */
+  
+  function notify_unread_pms()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if ( ( $paths->cpage['urlname_nons'] == 'PrivateMessages' || $paths->cpage['urlname_nons'] == 'Preferences' ) && $paths->namespace == 'Special' )
+    {
+      return '';
+    }
+    $ob = '<div class="usermessage">'."\n";
+    $s = ( $session->unread_pms == 1 ) ? '' : 's';
+    $ob .= "  <b>You have $session->unread_pms <a href=" . '"' . makeUrlNS('Special', 'PrivateMessages' ) . '"' . ">unread private message$s</a>.</b><br />\n  Messages: ";
+    $q = $db->sql_query('SELECT message_id,message_from,subject,date FROM '.table_prefix.'privmsgs WHERE message_to=\'' . $session->username . '\' AND message_read=0 ORDER BY date DESC;');
+    if ( !$q )
+      $db->_die();
+    $messages = array();
+    while ( $row = $db->fetchrow() )
+    {
+      $messages[] = '<a href="' . makeUrlNS('Special', 'PrivateMessages/View/' . $row['message_id']) . '" title="Sent ' . date('F d, Y h:i a', $row['date']) . ' by ' . $row['message_from'] . '">' . $row['subject'] . '</a>';
+    }
+    $ob .= implode(",\n    " , $messages)."\n";
+    $ob .= '</div>'."\n";
+    return $ob;
+  }
+  
+} // class template
+
+/**
+ * Handles parsing of an individual template file. Instances should only be created through $template->makeParser(). To use:
+ *   - Call $template->makeParser(template file name) - file name should be something.tpl, css/whatever.css, etc.
+ *   - Make an array of strings you want the template to access. $array['STRING'] would be referenced in the template like {STRING}
+ *   - Make an array of boolean values. These can be used for conditionals in the template (<!-- IF something --> whatever <!-- ENDIF something -->)
+ *   - Call assign_vars() to pass the strings to the template parser. Same thing with assign_bool().
+ *   - Call run() to parse the template and get your fully compiled HTML.
+ * @access private
+ */
+
+class templateIndividual extends template {
+  var $tpl_strings, $tpl_bool, $tpl_code;
+  var $compiled = false;
+  /**
+   * Constructor.
+   */
+  function __construct($text)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $this->tpl_code = $text;
+    $this->tpl_strings = $template->tpl_strings;
+    $this->tpl_bool = $template->tpl_bool;
+  }
+  /**
+   * PHP 4 constructor.
+   */
+  function templateIndividual($text)
+  {
+    $this->__construct($text);
+  }
+  /**
+   * Assigns an array of string values to the template. Strings can be accessed from the template by inserting {KEY_NAME} in the template file.
+   * @param $vars array
+   */
+  function assign_vars($vars)
+  {
+    $this->tpl_strings = array_merge($this->tpl_strings, $vars);
+  }
+  /**
+   * Assigns an array of boolean values to the template. These can be used for <!-- IF ... --> statements.
+   * @param $vars array
+   */
+  function assign_bool($vars)
+  {
+    $this->tpl_bool = array_merge($this->tpl_bool, $vars);
+  }
+  /**
+   * Compiles and executes the template code.
+   * @return string
+   */
+  function run()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(!$this->compiled)
+    {
+      $this->tpl_code = $this->compile_template_text($this->tpl_code);
+      $this->compiled = true;
+    }
+    return eval($this->tpl_code);
+  }
+}
+
+/**
+ * A version of the template compiler that does not rely at all on the other parts of Enano. Used during installation and for showing
+ * "critical error" messages. ** REQUIRES ** the Oxygen theme.
+ */
+
+class template_nodb {
+  var $tpl_strings, $tpl_bool, $theme, $style, $no_headers, $additional_headers, $sidebar_extra, $sidebar_widgets, $toolbar_menu, $theme_list;
+  function __construct() {
+    
+    $this->tpl_bool    = Array();
+    $this->tpl_strings = Array();
+    $this->sidebar_extra = '';
+    $this->sidebar_widgets = '';
+    $this->toolbar_menu = '';
+    $this->additional_headers = '';
+    
+    $this->theme_list = Array(Array(
+      'theme_id'=>'oxygen',
+      'theme_name'=>'Oxygen',
+      'theme_order'=>1,
+      'enabled'=>1,
+      ));
+  }
+  function template() {
+    $this->__construct();
+  }
+  function get_css($s = false) {
+    if($s)
+      return $this->process_template('css/'.$s);
+    else
+      return $this->process_template('css/'.$this->style.'.css');
+  }
+  function load_theme($name, $css, $auto_init = true) {
+    $this->theme = $name;
+    $this->style = $css;
+    
+    $this->tpl_strings['SCRIPTPATH'] = scriptPath;
+    if ( $auto_init )
+      $this->init_vars();
+  }
+  function init_vars()
+  {
+    global $sideinfo;
+    global $this_page;
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $tplvars = $this->extract_vars('elements.tpl');
+    $tb = '';
+    // Get the "article" button text (depends on namespace)
+    if(defined('IN_ENANO_INSTALL')) $ns = 'installation page';
+    else $ns = 'system error page';
+    $t = str_replace('{FLAGS}', 'onclick="return false;" title="Hey! A button that doesn\'t do anything. Clever..." accesskey="a"', $tplvars['toolbar_button']);
+    $t = str_replace('{HREF}', '#', $t);
+    $t = str_replace('{TEXT}', $ns, $t);
+    $tb .= $t;
+    
+    // Page toolbar
+    
+    $this->tpl_bool = Array(
+      'auth_admin'=>true,
+      'user_logged_in'=>true,
+      'right_sidebar'=>false,
+      );
+    $this->tpl_bool['in_sidebar_admin'] = false;
+    
+    $this->tpl_bool['auth_rename'] = false;
+    
+    $asq = $asa = '';
+    
+    $this->tpl_bool['fixed_menus'] = false;
+    $slink = defined('IN_ENANO_INSTALL') ? scriptPath.'/install.php?mode=css' : makeUrlNS('Special', 'CSS');
+    
+    $title = ( is_object($paths) ) ? $paths->page : 'Critical error';
+    
+    // The rewritten template engine will process all required vars during the load_template stage instead of (cough) re-processing everything each time around.
+    $tpl_strings = Array(
+      'PAGE_NAME'=>$this_page,
+      'PAGE_URLNAME'=>'Null',
+      'SITE_NAME'=>'Enano Installation',
+      'USERNAME'=>'admin',
+      'SITE_DESC'=>'Install Enano on your server.',
+      'TOOLBAR'=>$tb,
+      'SCRIPTPATH'=>scriptPath,
+      'CONTENTPATH'=>contentPath,
+      'ADMIN_SID_QUES'=>$asq,
+      'ADMIN_SID_AMP'=>$asa,
+      'ADMIN_SID_AMP_HTML'=>'',
+      'ADDITIONAL_HEADERS'=>'<style type="text/css">div.pagenav { border-top: 1px solid #CCC; padding-top: 7px; margin-top: 10px; }</style>',
+      'SIDEBAR_EXTRA'=>'',
+      'COPYRIGHT'=>'Enano and all of its code, graphics, and more code is copyright &copy; 2006 Dan Fuhry.<br />This program is Free Software; see the file "GPL" included with this package for details.',
+      'TOOLBAR_EXTRAS'=>'',
+      'REQUEST_URI'=>$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'],
+      'STYLE_LINK'=>$slink,
+      'LOGOUT_LINK'=>'',
+      'THEME_LINK'=>'',
+      'TEMPLATE_DIR'=>scriptPath.'/themes/'.$this->theme,
+      'THEME_ID'=>$this->theme,
+      'STYLE_ID'=>$this->style,
+      'JS_DYNAMIC_VARS'=>'<script type="text/javascript">var title="'. $title .'"; var scriptPath="'.scriptPath.'"; var ENANO_SID=""; var AES_BITS='.AES_BITS.'; var AES_BLOCKSIZE=' . AES_BLOCKSIZE . '; var pagepass=\'\';</script>',
+      'SIDEBAR_RIGHT'=>'',
+      );
+    $this->tpl_strings = array_merge($tpl_strings, $this->tpl_strings);
+    
+    $sidebar = ( gettype($sideinfo) == 'string' ) ? $sideinfo : '';
+    if($sidebar != '')
+    {
+      if(isset($tplvars['sidebar_top']))
+      {
+        $text = $this->makeParserText($tplvars['sidebar_top']);
+        $top = $text->run();
+      } else {
+        $top = '';
+      }
+      $p = $this->makeParserText($tplvars['sidebar_section']);
+      $p->assign_vars(Array(
+          'TITLE'=>'Installation progress',
+          'CONTENT'=>$sidebar,
+        ));
+      $sidebar = $p->run();
+      if(isset($tplvars['sidebar_bottom']))
+      {
+        $text = $this->makeParserText($tplvars['sidebar_bottom']);
+        $bottom = $text->run();
+      } else {
+        $bottom = '';
+      }
+      $sidebar = $top . $sidebar . $bottom;
+    }
+    $this->tpl_strings['SIDEBAR_LEFT'] = $sidebar;
+    
+    $this->tpl_bool['sidebar_left']  = ( $this->tpl_strings['SIDEBAR_LEFT']  != '') ? true : false;
+    $this->tpl_bool['sidebar_right'] = ( $this->tpl_strings['SIDEBAR_RIGHT'] != '') ? true : false;
+    $this->tpl_bool['right_sidebar'] = $this->tpl_bool['sidebar_right']; // backward compatibility
+    $this->tpl_bool['stupid_mode'] = true;
+  }
+  function header() 
+  {
+    if(!$this->no_headers) echo $this->process_template('header.tpl');
+  }
+  function footer()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(!$this->no_headers) {
+      global $_starttime;
+      $f = microtime(true);
+      $f = $f - $_starttime;
+      $f = round($f, 4);
+      if(defined('IN_ENANO_INSTALL')) $nq = 'N/A';
+      else $nq = $db->num_queries;
+      if($nq == 0) $nq = 'N/A';
+      $dbg = 'Time: '.$f.'s  |  Queries: '.$nq;
+      $t = $this->process_template('footer.tpl');
+      $t = str_replace('[[Stats]]', $dbg, $t);
+      echo $t;
+    }
+    else return '';
+  }
+  function getHeader()
+  {
+    if(!$this->no_headers) return $this->process_template('header.tpl');
+    else return '';
+  }
+  function getFooter()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(!$this->no_headers) {
+      global $_starttime;
+      $f = microtime(true);
+      $f = $f - $_starttime;
+      $f = round($f, 4);
+      if(defined('IN_ENANO_INSTALL')) $nq = 'N/A';
+      else $nq = $db->num_queries;
+      if($nq == 0) $nq = 'N/A';
+      $dbg = 'Time: '.$f.'s  |  Queries: '.$nq;
+      if($nq == 0) $nq = 'N/A';
+      $t = $this->process_template('footer.tpl');
+      $t = str_replace('[[Stats]]', $dbg, $t);
+      return $t;
+    }
+    else return '';
+  }
+  
+  function process_template($file) {
+    
+    eval($this->compile_template($file));
+    return $tpl_code;
+  }
+  
+  function extract_vars($file) {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(!is_file(ENANO_ROOT . '/themes/'.$this->theme.'/'.$file)) die('Cannot find '.$file.' file for style "'.$this->theme.'", exiting');
+    $text = file_get_contents(ENANO_ROOT . '/themes/'.$this->theme.'/'.$file);
+    preg_match_all('#<\!-- VAR ([A-z0-9_-]*) -->(.*?)<\!-- ENDVAR \\1 -->#is', $text, $matches);
+    $tplvars = Array();
+    for($i=0;$i<sizeof($matches[1]);$i++)
+    {
+      $tplvars[$matches[1][$i]] = $matches[2][$i];
+    }
+    return $tplvars;
+  }
+  function compile_template($text) {
+    global $sideinfo;
+    $text = file_get_contents(ENANO_ROOT . '/themes/'.$this->theme.'/'.$text);
+    $text = str_replace('<script type="text/javascript" src="{SCRIPTPATH}/ajax.php?title={PAGE_URLNAME}&amp;_mode=jsres"></script>', '', $text); // Remove the AJAX code - we don't need it, and it requires a database connection
+    $text = '$tpl_code = \''.str_replace('\'', '\\\'', $text).'\'; return $tpl_code;';
+    $text = preg_replace('#<!-- BEGIN (.*?) -->#is', '\'; if($this->tpl_bool[\'\\1\']) { $tpl_code .= \'', $text);
+    $text = preg_replace('#<!-- IFPLUGIN (.*?) -->#is', '\'; if(getConfig(\'plugin_\\1\')==\'1\') { $tpl_code .= \'', $text);
+    if(defined('IN_ENANO_INSTALL')) $text = str_replace('<!-- SYSMSG Sidebar -->', '<div class="slider"><div class="heading"><a class="head">Installation progress</a></div><div class="slideblock">'.$sideinfo.'</div></div>', $text);
+    else $text = str_replace('<!-- SYSMSG Sidebar -->', '<div class="slider"><div class="heading"><a class="head">System error</a></div><div class="slideblock"><a href="#" onclick="return false;">Enano critical error page</a></div></div>', $text);
+    $text = preg_replace('#<!-- SYSMSG (.*?) -->#is', '', $text);
+    $text = preg_replace('#<!-- BEGINNOT (.*?) -->#is', '\'; if(!$this->tpl_bool[\'\\1\']) { $tpl_code .= \'', $text);
+    $text = preg_replace('#<!-- BEGINELSE (.*?) -->#is', '\'; } else { $tpl_code .= \'', $text);
+    $text = preg_replace('#<!-- END (.*?) -->#is', '\'; } $tpl_code .= \'', $text);
+    $text = preg_replace('#{([A-z0-9]*)}#is', '\'.$this->tpl_strings[\'\\1\'].\'', $text);
+    return $text; //('<pre>'.htmlspecialchars($text).'</pre>');
+  }
+  
+  function compile_template_text($text) {
+    global $sideinfo;
+    $text = str_replace('<script type="text/javascript" src="{SCRIPTPATH}/ajax.php?title={PAGE_URLNAME}&amp;_mode=jsres"></script>', '', $text); // Remove the AJAX code - we don't need it, and it requires a database connection
+    $text = '$tpl_code = \''.str_replace('\'', '\\\'', $text).'\'; return $tpl_code;';
+    $text = preg_replace('#<!-- BEGIN (.*?) -->#is', '\'; if($this->tpl_bool[\'\\1\']) { $tpl_code .= \'', $text);
+    $text = preg_replace('#<!-- IFPLUGIN (.*?) -->#is', '\'; if(getConfig(\'plugin_\\1\')==\'1\') { $tpl_code .= \'', $text);
+    if(defined('IN_ENANO_INSTALL')) $text = str_replace('<!-- SYSMSG Sidebar -->', '<div class="slider"><div class="heading"><a class="head">Installation progress</a></div><div class="slideblock">'.$sideinfo.'</div></div>', $text);
+    else $text = str_replace('<!-- SYSMSG Sidebar -->', '<div class="slider"><div class="heading"><a class="head">System error</a></div><div class="slideblock"><a href="#" onclick="return false;">Enano critical error page</a></div></div>', $text);
+    $text = preg_replace('#<!-- SYSMSG (.*?) -->#is', '', $text);
+    $text = preg_replace('#<!-- BEGINNOT (.*?) -->#is', '\'; if(!$this->tpl_bool[\'\\1\']) { $tpl_code .= \'', $text);
+    $text = preg_replace('#<!-- BEGINELSE (.*?) -->#is', '\'; } else { $tpl_code .= \'', $text);
+    $text = preg_replace('#<!-- END (.*?) -->#is', '\'; } $tpl_code .= \'', $text);
+    $text = preg_replace('#{([A-z0-9]*)}#is', '\'.$this->tpl_strings[\'\\1\'].\'', $text);
+    return $text; //('<pre>'.htmlspecialchars($text).'</pre>');
+  }
+  
+  /**
+   * Allows individual parsing of template files. Similar to phpBB but follows the spirit of object-oriented programming ;)
+   * Returns on object of class templateIndividual. Usage instructions can be found in the inline docs for that class.
+   * @param $filename the filename of the template to be parsed
+   * @return object
+   */
+   
+  function makeParser($filename)
+  {
+    $filename = ENANO_ROOT.'/themes/'.$this->theme.'/'.$filename;
+    if(!file_exists($filename)) die('templateIndividual: file '.$filename.' does not exist');
+    $code = file_get_contents($filename);
+    $parser = new templateIndividualSafe($code, $this);
+    return $parser;
+  }
+  
+  /**
+   * Same as $template->makeParser(), but takes a string instead of a filename.
+   * @param $text the text to parse
+   * @return object
+   */
+   
+  function makeParserText($code)
+  {
+    $parser = new templateIndividualSafe($code, $this);
+    return $parser;
+  }
+   
+} // class template_nodb
+
+/**
+ * Identical to templateIndividual, except extends template_nodb instead of template
+ * @see class template
+ */
+ 
+class templateIndividualSafe extends template_nodb {
+  var $tpl_strings, $tpl_bool, $tpl_code;
+  var $compiled = false;
+  /**
+   * Constructor.
+   */
+  function __construct($text, $parent)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $this->tpl_code = $text;
+    $this->tpl_strings = $parent->tpl_strings;
+    $this->tpl_bool = $parent->tpl_bool;
+  }
+  /**
+   * PHP 4 constructor.
+   */
+  function templateIndividual($text)
+  {
+    $this->__construct($text);
+  }
+  /**
+   * Assigns an array of string values to the template. Strings can be accessed from the template by inserting {KEY_NAME} in the template file.
+   * @param $vars array
+   */
+  function assign_vars($vars)
+  {
+    if(is_array($this->tpl_strings))
+      $this->tpl_strings = array_merge($this->tpl_strings, $vars);
+    else
+      $this->tpl_strings = $vars;
+  }
+  /**
+   * Assigns an array of boolean values to the template. These can be used for <!-- IF ... --> statements.
+   * @param $vars array
+   */
+  function assign_bool($vars)
+  {
+    $this->tpl_bool = array_merge($this->tpl_bool, $vars);
+  }
+  /**
+   * Compiles and executes the template code.
+   * @return string
+   */
+  function run()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(!$this->compiled)
+    {
+      $this->tpl_code = $this->compile_template_text($this->tpl_code);
+      $this->compiled = true;
+    }
+    return eval($this->tpl_code);
+  }
+}
+
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/template.php~	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,1785 @@
+<?php
+
+/*
+ * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
+ * Version 1.0 (Banshee)
+ * Copyright (C) 2006-2007 Dan Fuhry
+ *
+ * This program is Free Software; you can redistribute 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 details.
+ */
+ 
+class template {
+  var $tpl_strings, $tpl_bool, $theme, $style, $no_headers, $additional_headers, $sidebar_extra, $sidebar_widgets, $toolbar_menu, $theme_list, $named_theme_list, $default_theme, $default_style, $plugin_blocks, $namespace_string, $style_list, $theme_loaded;
+  function __construct()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    dc_here('template: initializing all class variables');
+    $this->tpl_bool    = Array();
+    $this->tpl_strings = Array();
+    $this->sidebar_extra = '';
+    $this->toolbar_menu = '';
+    $this->additional_headers = '';
+    $this->plugin_blocks = Array();
+    $this->theme_loaded = false;
+    
+    $this->theme_list = Array();
+    $this->named_theme_list = Array();
+    $e = $db->sql_query('SELECT theme_id,theme_name,enabled,default_style FROM '.table_prefix.'themes WHERE enabled=1 ORDER BY theme_order;');
+    if(!$e) $db->_die('The list of themes could not be selected.');
+    for($i=0;$i < $db->numrows(); $i++)
+    {
+      $this->theme_list[$i] = $db->fetchrow();
+      $this->named_theme_list[$this->theme_list[$i]['theme_id']] = $this->theme_list[$i];
+    }
+    $db->free_result();
+    $this->default_theme = $this->theme_list[0]['theme_id'];
+    $dir = ENANO_ROOT.'/themes/'.$this->default_theme.'/css/';
+    $list = Array();
+    // Open a known directory, and proceed to read its contents
+    if (is_dir($dir)) {
+      if ($dh = opendir($dir)) {
+        while (($file = readdir($dh)) !== false) {
+          if(preg_match('#^(.*?)\.css$#i', $file) && $file != '_printable.css') {
+            $list[] = substr($file, 0, strlen($file)-4);
+          }
+        }
+        closedir($dh);
+      }
+    }
+    
+    $def = ENANO_ROOT.'/themes/'.$this->default_theme.'/css/'.$this->named_theme_list[$this->default_theme]['default_style'];
+    if(file_exists($def))
+    {
+      $this->default_style = substr($this->named_theme_list[$this->default_theme]['default_style'], 0, strlen($this->named_theme_list[$this->default_theme]['default_style'])-4);
+    } else {
+      $this->default_style = $list[0];
+    }
+    
+    $this->style_list = $list;
+    
+  }
+  function template()
+  {
+    $this->__construct();
+  }
+  function sidebar_widget($t, $h)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(!defined('ENANO_TEMPLATE_LOADED'))
+    {
+      $this->load_theme($session->theme, $session->style);
+    }
+    if(!$this->sidebar_widgets)
+      $this->sidebar_widgets = '';
+    $tplvars = $this->extract_vars('elements.tpl');
+    $parser = $this->makeParserText($tplvars['sidebar_section_raw']);
+    $parser->assign_vars(Array('TITLE'=>$t,'CONTENT'=>$h));
+    $this->plugin_blocks[$t] = $h;
+    $this->sidebar_widgets .= $parser->run();
+  }
+  function add_header($html)
+  {
+    $this->additional_headers .= "\n" . $html;
+  }
+  function get_css($s = false)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(!defined('ENANO_TEMPLATE_LOADED'))
+      $this->load_theme($session->theme, $session->style);
+    $path = ( $s ) ? 'css/'.$s : 'css/'.$this->style.'.css';
+    if ( !file_exists(ENANO_ROOT . '/themes/' . $this->theme . '/' . $path) )
+    {
+      echo "/* WARNING: Falling back to default file because file $path does not exist */\n";
+      $path = 'css/' . $this->style_list[0] . '.css';
+    }
+    return $this->process_template($path);
+  }
+  function load_theme($name = false, $css = false)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $this->theme = ( $name ) ? $name : $session->theme;
+    $this->style = ( $css ) ? $css : $session->style;
+    if ( !$this->theme )
+    {
+      $this->theme = $this->theme_list[0]['theme_id'];
+      $this->style = substr($this->theme_list[0]['default_style'], 0, strlen($this->theme_list[0]['default_style'])-4);
+    }
+    $this->theme_loaded = true;
+  }
+  
+  function init_vars()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    global $email;
+    
+    dc_here("template: initializing all variables");
+    
+    if(!$this->theme || !$this->style)
+    {
+      $this->load_theme();
+    }
+    
+    if(defined('ENANO_TEMPLATE_LOADED'))
+    {
+      dc_here('template: access denied to call template::init_vars(), bailing out');
+      die_semicritical('Illegal call', '<p>$template->load_theme was called multiple times, this is not supposed to happen. Exiting with fatal error.</p>');
+    }
+    
+    define('ENANO_TEMPLATE_LOADED', '');
+    
+    $tplvars = $this->extract_vars('elements.tpl');
+    
+    dc_here('template: setting all template vars');
+    
+    if(isset($_SERVER['HTTP_USER_AGENT']) && strstr($_SERVER['HTTP_USER_AGENT'], 'MSIE'))
+    {
+      $this->add_header('
+        <!--[if lt IE 7]>
+        <script language="JavaScript">
+        function correctPNG() // correctly handle PNG transparency in Win IE 5.5 & 6.
+        {
+           var arVersion = navigator.appVersion.split("MSIE")
+           var version = parseFloat(arVersion[1])
+           if (version >= 5.5 && typeof(document.body.filters) == "object")
+           {
+              for(var i=0; i<document.images.length; i++)
+              {
+                 var img = document.images[i];
+                 continue;
+                 var imgName = img.src.toUpperCase();
+                 if (imgName.substring(imgName.length-3, imgName.length) == "PNG")
+                 {
+                    var imgID = (img.id) ? "id=\'" + img.id + "\' " : "";
+                    var imgClass = (img.className) ? "class=\'" + img.className + "\' " : "";
+                    var imgTitle = (img.title) ? "title=\'" + img.title + "\' " : "title=\'" + img.alt + "\' ";
+                    var imgStyle = "display:inline-block;" + img.style.cssText;
+                    if (img.align == "left") imgStyle = "float:left;" + imgStyle;
+                    if (img.align == "right") imgStyle = "float:right;" + imgStyle;
+                    if (img.parentElement.href) imgStyle = "cursor:hand;" + imgStyle;
+                    var strNewHTML = "<span " + imgID + imgClass + imgTitle + " style=\\"" + "width:" + img.width + "px; height:" + img.height + "px;" + imgStyle + ";" + "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader" + "(src=\\\'" + img.src + "\\\', sizingMethod=\'scale\');\\"></span>";
+                    img.outerHTML = strNewHTML;
+                    i = i-1;
+                 }
+              }
+           }   
+        }
+        window.attachEvent("onload", correctPNG);
+        </script>
+        <![endif]-->
+        ');
+    }
+    
+    // Get the "article" button text (depends on namespace)
+    switch($paths->namespace) {
+      case "Article":
+      default:
+        $ns = 'article';
+        break;
+      case "Admin":
+        $ns = 'administration page';
+        break;
+      case "System":
+        $ns = 'system message';
+        break;
+      case "File":
+        $ns = 'uploaded file';
+        break;
+      case "Help":
+        $ns = 'documentation page';
+        break;
+      case "User":
+        $ns = 'user page';
+        break;
+      case "Special":
+        $ns = 'special page';
+        break;
+      case "Template":
+        $ns = 'template';
+        break;
+      case "Project":
+        $ns = 'project page';
+        break;
+      case "Category":
+        $ns = 'category';
+        break;
+    }
+    $this->namespace_string = $ns;
+    $code = $plugins->setHook('page_type_string_set');
+    foreach ( $code as $cmd )
+    {
+      eval($cmd);
+    }
+    $ns =& $this->namespace_string;
+    
+    // Initialize the toolbar
+    $tb = '';
+    
+    // Create "xx page" button
+    
+    $btn_selected = ( isset($tplvars['toolbar_button_selected'])) ? $tplvars['toolbar_button_selected'] : $tplvars['toolbar_button'];
+    $parser = $this->makeParserText($btn_selected);
+    
+    $parser->assign_vars(array(
+        'FLAGS' => 'onclick="void(ajaxReset()); return false;" title="View the page contents, all of the page contents, and nothing but the page contents (alt-a)" accesskey="a"',
+        'PARENTFLAGS' => 'id="mdgToolbar_article"',
+        'HREF' => makeUrl($paths->page, null, true),
+        'TEXT' => $this->namespace_string
+      ));
+    
+    $tb .= $parser->run();
+    
+    $button = $this->makeParserText($tplvars['toolbar_button']);
+    
+    // Page toolbar
+    // Comments button
+    if ( $session->get_permissions('read') && getConfig('enable_comments')=='1' && $paths->namespace != 'Special' && $paths->namespace != 'Admin' && $paths->cpage['comments_on'] == 1 )
+    {
+      
+      $e = $db->sql_query('SELECT approved FROM '.table_prefix.'comments WHERE page_id=\''.$paths->cpage['urlname_nons'].'\' AND namespace=\''.$paths->namespace.'\';');
+      if ( !$e )
+      {
+        $db->_die();
+      }
+      $nc = $db->numrows();
+      $nu = 0;
+      $na = 0;
+      
+      while ( $r = $db->fetchrow() )
+      {  
+        if ( !$r['approved'] )
+        {
+          $nu++;
+        }
+        else
+        {
+          $na++;
+        }
+      }
+      
+      $db->free_result();
+      $n = ( $session->get_permissions('mod_comments') ) ? (string)$nc : (string)$na;
+      if ( $session->get_permissions('mod_comments') && $nu > 0 )
+      {
+        $n .= ' total/'.$nu.' unapp.';
+      }
+      
+      $button->assign_vars(array(
+          'FLAGS' => 'onclick="void(ajaxComments()); return false;" title="View the comments that other users have posted about this page (alt-c)" accesskey="c"',
+          'PARENTFLAGS' => 'id="mdgToolbar_discussion"',
+          'HREF' => makeUrl($paths->page, 'do=comments', true),
+          'TEXT' => 'discussion ('.$n.')',
+        ));
+      
+      $tb .= $button->run();
+    }
+    // Edit button
+    if($session->get_permissions('read') && ($paths->namespace != 'Special' && $paths->namespace != 'Admin') && ( $session->get_permissions('edit_page') && ( ( $paths->page_protected && $session->get_permissions('even_when_protected') ) || !$paths->page_protected ) ) )
+    {
+      $button->assign_vars(array(
+        'FLAGS' => 'onclick="void(ajaxEditor()); return false;" title="Edit the contents of this page (alt-e)" accesskey="e"',
+        'PARENTFLAGS' => 'id="mdgToolbar_edit"',
+        'HREF' => makeUrl($paths->page, 'do=edit', true),
+        'TEXT' => 'edit this page'
+        ));
+      $tb .= $button->run();
+    // View source button
+    }
+    else if($session->get_permissions('view_source') && ( !$session->get_permissions('edit_page') || !$session->get_permissions('even_when_protected') && $paths->page_protected ) && $paths->namespace != 'Special' && $paths->namespace != 'Admin') 
+    {
+      $button->assign_vars(array(
+        'FLAGS' => 'onclick="void(ajaxViewSource()); return false;" title="View the source code (wiki markup) that this page uses (alt-e)" accesskey="e"',
+        'PARENTFLAGS' => 'id="mdgToolbar_edit"',
+        'HREF' => makeUrl($paths->page, 'do=viewsource', true),
+        'TEXT' => 'view source'
+        ));
+      $tb .= $button->run();
+    }
+    // History button
+    if ( $session->get_permissions('read') /* && $paths->wiki_mode */ && $paths->page_exists && $paths->namespace != 'Special' && $paths->namespace != 'Admin' && $session->get_permissions('history_view') )
+    {
+      $button->assign_vars(array(
+        'FLAGS'       => 'onclick="void(ajaxHistory()); return false;" title="View a log of actions taken on this page (alt-h)" accesskey="h"',
+        'PARENTFLAGS' => 'id="mdgToolbar_history"',
+        'HREF'        => makeUrl($paths->page, 'do=history', true),
+        'TEXT'        => 'history'
+        ));
+      $tb .= $button->run();
+    }
+    
+    $menubtn = $this->makeParserText($tplvars['toolbar_menu_button']);
+    
+    // Additional actions menu
+    // Rename button
+    if ( $session->get_permissions('read') && $paths->page_exists && ( $session->get_permissions('rename') && ( $paths->page_protected && $session->get_permissions('even_when_protected') || !$paths->page_protected ) ) && $paths->namespace != 'Special' && $paths->namespace != 'Admin' )
+    {
+      $menubtn->assign_vars(array(
+          'FLAGS' => 'onclick="void(ajaxRename()); return false;" title="Change the display name of this page (alt-r)" accesskey="r"',
+          'HREF'  => makeUrl($paths->page, 'do=rename', true),
+          'TEXT'  => 'rename',
+        ));
+      $this->toolbar_menu .= $menubtn->run();
+    }
+    
+    // Vote-to-delete button
+    if ( $paths->wiki_mode && $session->get_permissions('vote_delete') && $paths->page_exists && $paths->namespace != 'Special' && $paths->namespace != 'Admin')
+    {
+      $menubtn->assign_vars(array(
+          'FLAGS' => 'onclick="void(ajaxDelVote()); return false;" title="Vote to have this page deleted (alt-d)" accesskey="d"',
+          'HREF'  => makeUrl($paths->page, 'do=delvote', true),
+          'TEXT'  => 'vote to delete this page',
+        ));
+      $this->toolbar_menu .= $menubtn->run();
+    }
+    
+    // Clear-votes button
+    if ( $session->get_permissions('read') && $paths->wiki_mode && $paths->page_exists && $paths->namespace != 'Special' && $paths->namespace != 'Admin' && $session->get_permissions('vote_reset') && $paths->cpage['delvotes'] > 0)
+    {
+      $menubtn->assign_vars(array(
+          'FLAGS' => 'onclick="void(ajaxResetDelVotes()); return false;" title="Vote to have this page deleted (alt-y)" accesskey="y"',
+          'HREF'  => makeUrl($paths->page, 'do=resetvotes', true),
+          'TEXT'  => 'reset deletion votes',
+        ));
+      $this->toolbar_menu .= $menubtn->run();
+    }
+    
+    // Printable page button
+    if ( $paths->page_exists && $paths->namespace != 'Special' && $paths->namespace != 'Admin' )
+    {
+      $menubtn->assign_vars(array(
+          'FLAGS' => 'title="View a version of this page that is suitable for printing"',
+          'HREF'  => makeUrl($paths->page, 'printable=yes', true),
+          'TEXT'  => 'view printable version',
+        ));
+      $this->toolbar_menu .= $menubtn->run();
+    }
+    
+    // Protect button
+    if($session->get_permissions('read') && $paths->wiki_mode && $paths->page_exists && $paths->namespace != 'Special' && $paths->namespace != 'Admin' && $session->get_permissions('protect'))
+    {
+      
+      $label = $this->makeParserText($tplvars['toolbar_label']);
+      $label->assign_vars(array('TEXT' => 'protection:'));
+      $t0 = $label->run();
+      
+      $ctmp = ''; 
+      if ( $paths->cpage['protected'] == 1 )
+      {
+        $ctmp=' style="text-decoration: underline;"';
+      }
+      $menubtn->assign_vars(array(
+          'FLAGS' => 'accesskey="i" onclick="ajaxProtect(1); return false;" id="protbtn_1" title="Prevents all non-administrators from editing this page. [alt-i]"'.$ctmp,
+          'HREF'  => makeUrl($paths->page, 'do=protect&level=1', true),
+          'TEXT'  => 'on'
+        ));
+      $t1 = $menubtn->run();
+      
+      $ctmp = '';
+      if ( $paths->cpage['protected'] == 0 )
+      {
+        $ctmp=' style="text-decoration: underline;"';
+      }
+      $menubtn->assign_vars(array(
+          'FLAGS' => 'accesskey="o" onclick="ajaxProtect(0); return false;" id="protbtn_0" title="Allows everyone to edit this page. [alt-o]"'.$ctmp,
+          'HREF'  => makeUrl($paths->page, 'do=protect&level=0', true),
+          'TEXT'  => 'off'
+        ));
+      $t2 = $menubtn->run();
+      
+      $ctmp = '';
+      if ( $paths->cpage['protected'] == 2 )
+      {
+        $ctmp = ' style="text-decoration: underline;"';
+      }
+      $menubtn->assign_vars(array(
+          'FLAGS' => 'accesskey="p" onclick="ajaxProtect(2); return false;" id="protbtn_2" title="Allows only users who have been registered for 4 days to edit this page. [alt-p]"'.$ctmp,
+          'HREF'  => makeUrl($paths->page, 'do=protect&level=2', true),
+          'TEXT'  => 'semi'
+        ));
+      $t3 = $menubtn->run();
+      
+      $this->toolbar_menu .= '        <table border="0" cellspacing="0" cellpadding="0">
+          <tr>
+            <td>'.$t0.'</td>
+            <td>'.$t1.'</td>
+            <td>'.$t2.'</td>
+            <td>'.$t3.'</td>
+          </tr>
+        </table>';
+    }
+    
+    // Wiki mode button
+    if($session->get_permissions('read') && $paths->page_exists && $session->get_permissions('set_wiki_mode') && $paths->namespace != 'Special' && $paths->namespace != 'Admin')
+    {
+      // label at start
+      $label = $this->makeParserText($tplvars['toolbar_label']);
+      $label->assign_vars(array('TEXT' => 'page wiki mode:'));
+      $t0 = $label->run();
+      
+      // on button
+      $ctmp = '';
+      if ( $paths->cpage['wiki_mode'] == 1 )
+      {
+        $ctmp = ' style="text-decoration: underline;"';
+      }
+      $menubtn->assign_vars(array(
+          'FLAGS' => 'onclick="ajaxSetWikiMode(1); return false;" id="wikibtn_1" title="Forces wiki functions to be allowed on this page."'.$ctmp,
+          'HREF' => makeUrl($paths->page, 'do=setwikimode&level=1', true),
+          'TEXT' => 'on'
+        ));
+      $t1 = $menubtn->run();
+      
+      // off button
+      $ctmp = '';
+      if ( $paths->cpage['wiki_mode'] == 0 )
+      {
+        $ctmp=' style="text-decoration: underline;"';
+      }
+      $menubtn->assign_vars(array(
+          'FLAGS' => 'onclick="ajaxSetWikiMode(0); return false;" id="wikibtn_0" title="Forces wiki functions to be disabled on this page."'.$ctmp,
+          'HREF' => makeUrl($paths->page, 'do=setwikimode&level=0', true),
+          'TEXT' => 'off'
+        ));
+      $t2 = $menubtn->run();
+      
+      // global button
+      $ctmp = ''; 
+      if ( $paths->cpage['wiki_mode'] == 2 )
+      {
+        $ctmp=' style="text-decoration: underline;"';
+      }
+      $menubtn->assign_vars(array(
+          'FLAGS' => 'onclick="ajaxSetWikiMode(2); return false;" id="wikibtn_2" title="Causes this page to use the global wiki mode setting (default)"'.$ctmp,
+          'HREF' => makeUrl($paths->page, 'do=setwikimode&level=2', true),
+          'TEXT' => 'global'
+        ));
+      $t3 = $menubtn->run();
+      
+      // Tack it onto the list of buttons that are already there...
+      $this->toolbar_menu .= '        <table border="0" cellspacing="0" cellpadding="0">
+          <tr>
+            <td>'.$t0.'</td>
+            <td>'.$t1.'</td>
+            <td>'.$t2.'</td>
+            <td>'.$t3.'</td>
+          </tr>
+        </table>';
+    }
+    
+    // Clear logs button
+    if ( $session->get_permissions('read') && $session->get_permissions('clear_logs') && $paths->wiki_mode && $paths->namespace != 'Special' && $paths->namespace != 'Admin' )
+    {
+      $menubtn->assign_vars(array(
+          'FLAGS' => 'onclick="void(ajaxClearLogs()); return false;" title="Remove all edit and action logs for this page from the database. IRREVERSIBLE! (alt-l)" accesskey="l"',
+          'HREF'  => makeUrl($paths->page, 'do=flushlogs', true),
+          'TEXT'  => 'clear page logs',
+        ));
+      $this->toolbar_menu .= $menubtn->run();
+    }
+    
+    // Delete page button
+    if ( $session->get_permissions('read') && $session->get_permissions('delete_page') && $paths->page_exists && $paths->namespace != 'Special' && $paths->namespace != 'Admin' )
+    {
+      $s = 'delete this page';
+      if ( $paths->cpage['delvotes'] == 1 )
+      {
+        $s .= ' (<b>'.$paths->cpage['delvotes'].'</b> vote)';
+      }
+      else if ( $paths->cpage['delvotes'] > 1 )
+      {
+        $s .= ' (<b>'.$paths->cpage['delvotes'].'</b> votes)';
+      }
+      
+      $menubtn->assign_vars(array(
+          'FLAGS' => 'onclick="void(ajaxDeletePage()); return false;" title="Delete this page. This is always reversible unless the logs are cleared. (alt-k)" accesskey="k"',
+          'HREF'  => makeUrl($paths->page, 'do=deletepage', true),
+          'TEXT'  => $s,
+        ));
+      $this->toolbar_menu .= $menubtn->run();
+      
+    }
+    
+    // Password-protect button
+    if(isset($paths->cpage['password']))
+    {
+      if ( $paths->cpage['password'] == '' )
+      {
+        $a = $session->get_permissions('password_set');
+      }
+      else
+      {
+        $a = $session->get_permissions('password_reset');
+      }
+    }
+    else
+    {
+      $a = $session->get_permissions('password_set');
+    }
+    if ( $a && $session->get_permissions('read') && $paths->page_exists && $paths->namespace != 'Special' && $paths->namespace != 'Admin' )
+    {
+      // label at start
+      $label = $this->makeParserText($tplvars['toolbar_label']);
+      $label->assign_vars(array('TEXT' => 'password:'));
+      $t0 = $label->run();
+      
+      $menubtn->assign_vars(array(
+          'FLAGS' => 'onclick="void(ajaxSetPassword()); return false;" title="Require a password in order for this page to be viewed"',
+          'HREF'  => '#',
+          'TEXT'  => 'set',
+        ));
+      $t = $menubtn->run();
+      
+      $this->toolbar_menu .= '<table border="0" cellspacing="0" cellpadding="0"><tr><td>'.$t0.'</td><td><input type="password" id="mdgPassSetField" size="10" /></td><td>'.$t.'</td></tr></table>';
+    }
+    
+    // Manage ACLs button
+    if($session->get_permissions('edit_acl') || $session->user_level >= USER_LEVEL_ADMIN)
+    {
+      $menubtn->assign_vars(array(
+          'FLAGS' => 'onclick="return ajaxOpenACLManager();" title="Manage who can do what with this page (alt-m)" accesskey="m"',
+          'HREF'  => makeUrl($paths->page, 'do=aclmanager', true),
+          'TEXT'  => 'manage page access',
+        ));
+      $this->toolbar_menu .= $menubtn->run();
+    }
+    
+    // Administer page button
+    if ( $session->user_level >= USER_LEVEL_ADMIN && $paths->page_exists && $paths->namespace != 'Special' && $paths->namespace != 'Admin' )
+    {
+      $menubtn->assign_vars(array(
+          'FLAGS' => 'onclick="void(ajaxAdminPage()); return false;" title="Administrative options for this page" accesskey="g"',
+          'HREF'  => makeUrlNS('Special', 'Administration', 'module='.$paths->nslist['Admin'].'PageManager', true),
+          'TEXT'  => 'administrative options',
+        ));
+      $this->toolbar_menu .= $menubtn->run();
+    }
+    
+    if ( strlen($this->toolbar_menu) > 0 )
+    {
+      $button->assign_vars(array(
+        'FLAGS'       => 'id="mdgToolbar_moreoptions" onclick="return false;" title="Additional options for working with this page"',
+        'PARENTFLAGS' => '',
+        'HREF'        => makeUrl($paths->page, 'do=moreoptions', true),
+        'TEXT'        => 'more options'
+        ));
+      $tb .= $button->run();
+    }
+    
+    $is_opera = (isset($_SERVER['HTTP_USER_AGENT']) && strstr($_SERVER['HTTP_USER_AGENT'], 'Opera')) ? true : false;
+    
+    $this->tpl_bool = Array(
+      'auth_admin'=>$session->user_level >= USER_LEVEL_ADMIN ? true : false,
+      'user_logged_in'=>$session->user_logged_in,
+      'opera'=>$is_opera,
+      );
+    
+    if($session->sid_super) { $ash = '&amp;auth='.$session->sid_super; $asq = "?auth=".$session->sid_super; $asa = "&auth=".$session->sid_super; $as2 = htmlspecialchars(urlSeparator).'auth='.$session->sid_super; }
+    else { $asq=''; $asa=''; $as2 = ''; $ash = ''; }
+    
+    $code = $plugins->setHook('compile_template');
+    foreach ( $code as $cmd )
+    {
+      eval($cmd);
+    }
+    
+    // Some additional sidebar processing
+    if($this->sidebar_extra != '') {
+      $se = $this->sidebar_extra;
+      $parser = $this->makeParserText($tplvars['sidebar_section_raw']);
+      $parser->assign_vars(Array('TITLE'=>'Links','CONTENT'=>$se));
+      $this->sidebar_extra = $parser->run();
+    }
+    
+    $this->sidebar_extra = $this->sidebar_extra.$this->sidebar_widgets;
+    
+    $this->tpl_bool['fixed_menus'] = false;
+    /* if($this->sidebar_extra == '') $this->tpl_bool['right_sidebar'] = false;
+    else */ $this->tpl_bool['right_sidebar'] = true;
+    
+    $this->tpl_bool['auth_rename'] = ( $paths->page_exists && ( $session->get_permissions('rename') && ( $paths->page_protected && $session->get_permissions('even_when_protected') || !$paths->page_protected ) ) && $paths->namespace != 'Special' && $paths->namespace != 'Admin');
+    
+    $this->tpl_bool['enable_uploads'] = ( getConfig('enable_uploads') == '1' && $session->get_permissions('upload_files') ) ? true : false;
+    
+    $this->tpl_bool['stupid_mode'] = false;
+    
+    if($paths->page == $paths->nslist['Special'].'Administration') $this->tpl_bool['in_admin'] = true;
+    else $this->tpl_bool['in_admin'] = false;
+    
+    $p = ( isset($_GET['printable']) ) ? '/printable' : '';
+    
+    // Add the e-mail address client code to the header
+    $this->add_header($email->jscode());
+    
+    // Generate the code for the Log out and Change theme sidebar buttons
+    // Once again, the new template parsing system can be used here
+    
+    $parser = $this->makeParserText($tplvars['sidebar_button']);
+    
+    $parser->assign_vars(Array(
+        'HREF'=>makeUrlNS('Special', 'Logout'),
+        'FLAGS'=>'onclick="mb_logout(); return false;"',
+        'TEXT'=>'Log out',
+      ));
+    
+    $logout_link = $parser->run();
+    
+    $parser->assign_vars(Array(
+        'HREF'=>makeUrlNS('Special', 'Login/' . $paths->page),
+        'FLAGS'=>'onclick="ajaxStartLogin(); return false;"',
+        'TEXT'=>'Log in',
+      ));
+    
+    $login_link = $parser->run();
+    
+    $parser->assign_vars(Array(
+        'HREF'=>makeUrlNS('Special', 'ChangeStyle/'.$paths->page),
+        'FLAGS'=>'onclick="ajaxChangeStyle(); return false;"',
+        'TEXT'=>'Change theme',
+      ));
+    
+    $theme_link = $parser->run();
+    
+    $SID = ($session->sid_super) ? $session->sid_super : '';
+    
+    // Generate the dynamic javascript vars
+    $js_dynamic = '    <script type="text/javascript">// <![CDATA[
+      // This section defines some basic and very important variables that are used later in the static Javascript library.
+      // SKIN DEVELOPERS: The template variable for this code block is {JS_DYNAMIC_VARS}. This MUST be inserted BEFORE the tag that links to the main Javascript lib.
+      var title=\''. str_replace('\'', '\\\'', str_replace('\\', '\\\\', $paths->fullpage)) .'\';
+      var page_exists='. ( ( $paths->page_exists) ? 'true' : 'false' ) .';
+      var scriptPath=\''. scriptPath .'\';
+      var contentPath=\''.contentPath.'\';
+      var ENANO_SID =\'' . $SID . '\';
+      var auth_level=' . $session->auth_level . ';
+      var USER_LEVEL_GUEST = ' . USER_LEVEL_GUEST . ';
+      var USER_LEVEL_MEMBER = ' . USER_LEVEL_MEMBER . ';
+      var USER_LEVEL_CHPREF = ' . USER_LEVEL_CHPREF . ';
+      var USER_LEVEL_MOD = ' . USER_LEVEL_MOD . ';
+      var USER_LEVEL_ADMIN = ' . USER_LEVEL_ADMIN . ';
+      var editNotice = \'' . ( (getConfig('wiki_edit_notice')=='1') ? str_replace("\n", "\\\n", RenderMan::render(getConfig('wiki_edit_notice_text'))) : '' ) . '\';
+      var prot = ' . ( ($paths->page_protected && !$session->get_permissions('even_when_protected')) ? 'true' : 'false' ) .'; // No, hacking this var won\'t work, it\'s re-checked on the server
+      var ENANO_SPECIAL_CREATEPAGE = \''. makeUrl($paths->nslist['Special'].'CreatePage') .'\';
+      var ENANO_CREATEPAGE_PARAMS = \'_do=&pagename='. addslashes($paths->cpage['name']) .'&namespace=' . $paths->namespace . '\';
+      var ENANO_SPECIAL_CHANGESTYLE = \''. makeUrlNS('Special', 'ChangeStyle') .'\';
+      var namespace_list = new Array();
+      var AES_BITS = '.AES_BITS.';
+      var AES_BLOCKSIZE = '.AES_BLOCKSIZE.';
+      var pagepass = \''. ( ( isset($_REQUEST['pagepass']) ) ? sha1($_REQUEST['pagepass']) : '' ) .'\';
+      var ENANO_THEME_LIST = \'';
+          foreach($this->theme_list as $t) {
+            if($t['enabled'])
+            {
+              $js_dynamic .= '<option value="'.$t['theme_id'].'"';
+              if($t['theme_id'] == $session->theme) $js_dynamic .= ' selected="selected"';
+              $js_dynamic .= '>'.$t['theme_name'].'</option>';
+            }
+          }
+      $js_dynamic .= '\';
+      var ENANO_CURRENT_THEME = \''. $session->theme .'\';';
+      foreach($paths->nslist as $k => $c)
+      {
+        $js_dynamic .= "namespace_list['{$k}'] = '$c';";
+      }
+      $js_dynamic .= "\n    //]]>\n    </script>";
+    
+    $tpl_strings = Array(
+      'PAGE_NAME'=>$paths->cpage['name'],
+      'PAGE_URLNAME'=>$paths->cpage['urlname'],
+      'SITE_NAME'=>getConfig('site_name'),
+      'USERNAME'=>$session->username,
+      'SITE_DESC'=>getConfig('site_desc'),
+      'TOOLBAR'=>$tb,
+      'SCRIPTPATH'=>scriptPath,
+      'CONTENTPATH'=>contentPath,
+      'ADMIN_SID_QUES'=>$asq,
+      'ADMIN_SID_AMP'=>$asa,
+      'ADMIN_SID_AMP_HTML'=>$ash,
+      'ADMIN_SID_AUTO'=>$as2,
+      'ADDITIONAL_HEADERS'=>$this->additional_headers,
+      'COPYRIGHT'=>getConfig('copyright_notice'),
+      'TOOLBAR_EXTRAS'=>$this->toolbar_menu,
+      'REQUEST_URI'=>$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'],
+      'STYLE_LINK'=>makeUrlNS('Special', 'CSS'.$p, null, true), //contentPath.$paths->nslist['Special'].'CSS' . $p,
+      'LOGIN_LINK'=>$login_link,
+      'LOGOUT_LINK'=>$logout_link,
+      'THEME_LINK'=>$theme_link,
+      'TEMPLATE_DIR'=>scriptPath.'/themes/'.$this->theme,
+      'THEME_ID'=>$this->theme,
+      'STYLE_ID'=>$this->style,
+      'JS_DYNAMIC_VARS'=>$js_dynamic,
+      'UNREAD_PMS'=>$session->unread_pms
+      );
+    
+    foreach ( $paths->nslist as $ns_id => $ns_prefix )
+    {
+      $tpl_strings[ 'NS_' . strtoupper($ns_id) ] = $ns_prefix;
+    }
+    
+    $this->tpl_strings = array_merge($tpl_strings, $this->tpl_strings);
+    list($this->tpl_strings['SIDEBAR_LEFT'], $this->tpl_strings['SIDEBAR_RIGHT'], $min) = $this->fetch_sidebar();
+    $this->tpl_bool['sidebar_left']  = ( $this->tpl_strings['SIDEBAR_LEFT']  != $min) ? true : false;
+    $this->tpl_bool['sidebar_right'] = ( $this->tpl_strings['SIDEBAR_RIGHT'] != $min) ? true : false;
+    $this->tpl_bool['right_sidebar'] = $this->tpl_bool['sidebar_right']; // backward compatibility
+  }
+  
+  function header($simple = false) 
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    ob_start();
+    
+    if(!$this->theme_loaded)
+    {
+      $this->load_theme($session->theme, $session->style);
+    }
+    
+    $headers_sent = true;
+    dc_here('template: generating and sending the page header');
+    if(!defined('ENANO_HEADERS_SENT'))
+      define('ENANO_HEADERS_SENT', '');
+    if(!$this->no_headers) echo ( $simple ) ? $this->process_template('simple-header.tpl') : $this->process_template('header.tpl');
+    if ( !$simple && $session->user_logged_in && $session->unread_pms > 0 )
+    {
+      echo $this->notify_unread_pms();
+    }
+    if ( !$simple && $session->sw_timed_out )
+    {
+      $login_link = makeUrlNS('Special', 'Login/' . $paths->fullpage, 'level=' . $session->user_level, true);
+      echo '<div class="usermessage">';
+      echo '<b>Your administrative session has timed out.</b> <a href="' . $login_link . '">Log in again</a>';
+      echo '</div>';
+    }
+  }
+  function footer($simple = false)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    dc_here('template: generating and sending the page footer');
+    if(!$this->no_headers) {
+      
+      if(!defined('ENANO_HEADERS_SENT'))
+        $this->header();
+      
+      global $_starttime;
+      if(isset($_GET['sqldbg']) && $session->get_permissions('mod_misc'))
+      {
+        echo '<h3>Query list as requested on URI</h3><pre style="margin-left: 1em">';
+        echo $db->sql_backtrace();
+        echo '</pre>';
+      }
+      
+      $f = microtime_float();
+      $f = $f - $_starttime;
+      $f = round($f, 4);
+      $dbg = 'Time: '.$f.'s  |  Queries: '.$db->num_queries;
+      $t = ( $simple ) ? $this->process_template('simple-footer.tpl') : $this->process_template('footer.tpl');
+      $t = str_replace('[[Stats]]', $dbg, $t);
+      $t = str_replace('[[NumQueries]]', (string)$db->num_queries, $t);
+      $t = str_replace('[[GenTime]]', (string)$f, $t);
+      echo $t;
+      
+      ob_end_flush();
+    }
+    else return '';
+  }
+  function getHeader()
+  {
+    $headers_sent = true;
+    dc_here('template: generating and sending the page header');
+    if(!defined('ENANO_HEADERS_SENT'))
+      define('ENANO_HEADERS_SENT', '');
+    if(!$this->no_headers) return $this->process_template('header.tpl');
+  }
+  function getFooter()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    dc_here('template: generating and sending the page footer');
+    if(!$this->no_headers) {
+      global $_starttime;
+      $t = '';
+      
+      if(isset($_GET['sqldbg']) && $session->get_permissions('mod_misc'))
+      {
+        $t .= '<h3>Query list as requested on URI</h3><pre style="margin-left: 1em">';
+        $t .= $db->sql_backtrace();
+        $t .= '</pre>';
+      }
+      
+      $f = microtime_float();
+      $f = $f - $_starttime;
+      $f = round($f, 4);
+      $dbg = 'Time: '.$f.'s  |  Queries: '.$db->num_queries;
+      $t.= $this->process_template('footer.tpl');
+      $t = str_replace('[[Stats]]', $dbg, $t);
+      $t = str_replace('[[NumQueries]]', (string)$db->num_queries, $t);
+      $t = str_replace('[[GenTime]]', (string)$f, $t);
+      return $t;
+    }
+    else return '';
+  }
+  
+  function process_template($file) {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(!defined('ENANO_TEMPLATE_LOADED'))
+    {
+      $this->load_theme();
+      $this->init_vars();
+    }
+    eval($this->compile_template($file));
+    return $tpl_code;
+  }
+  
+  function extract_vars($file) {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(!$this->theme)
+    {
+      die('$template->extract_vars(): theme not yet loaded, so we can\'t open template files yet...this is a bug and should be reported.<br /><br />Backtrace, most recent call first:<pre>'.enano_debug_print_backtrace(true).'</pre>');
+    }
+    if(!is_file(ENANO_ROOT . '/themes/'.$this->theme.'/'.$file)) die('Cannot find '.$file.' file for style "'.$this->theme.'", exiting');
+    $text = file_get_contents(ENANO_ROOT . '/themes/'.$this->theme.'/'.$file);
+    preg_match_all('#<\!-- VAR ([A-z0-9_-]*) -->(.*?)<\!-- ENDVAR \\1 -->#is', $text, $matches);
+    $tplvars = Array();
+    for($i=0;$i<sizeof($matches[1]);$i++)
+    {
+      $tplvars[$matches[1][$i]] = $matches[2][$i];
+    }
+    return $tplvars;
+  }
+  function compile_template($text) {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(!is_file(ENANO_ROOT . '/themes/'.$this->theme.'/'.$text)) die('Cannot find '.$text.' file for style, exiting');
+    $n = $text;
+    $tpl_filename = ENANO_ROOT . '/cache/' . $this->theme . '-' . str_replace('/', '-', $n) . '.php';
+    if(!is_file(ENANO_ROOT . '/themes/'.$this->theme.'/'.$text)) die('Cannot find '.$text.' file for style, exiting');
+    if(file_exists($tpl_filename) && getConfig('cache_thumbs')=='1')
+    {
+      include($tpl_filename);
+      $text = file_get_contents(ENANO_ROOT . '/themes/'.$this->theme.'/'.$text);
+      if(isset($md5) && $md5 == md5($text)) {
+        return str_replace('\\"', '"', $tpl_text);
+      }
+    }
+    $text = file_get_contents(ENANO_ROOT . '/themes/'.$this->theme.'/'.$n);
+    
+    $md5 = md5($text);
+    
+    $seed = md5 ( microtime() . mt_rand() );
+    preg_match_all("/<\?php(.*?)\?>/is", $text, $m);
+    //die('<pre>'.htmlspecialchars(print_r($m, true)).'</pre>');
+    for($i = 0; $i < sizeof($m[1]); $i++)
+    {
+      $text = str_replace("<?php{$m[1][$i]}?>", "{PHPCODE:{$i}:{$seed}}", $text);
+    }
+    //die('<pre>'.htmlspecialchars($text).'</pre>');
+    $text = 'ob_start(); echo \''.str_replace('\'', '\\\'', $text).'\'; $tpl_code = ob_get_contents(); ob_end_clean();';
+    $text = preg_replace('#<!-- BEGIN (.*?) -->#is', '\'; if(isset($this->tpl_bool[\'\\1\']) && $this->tpl_bool[\'\\1\']) { echo \'', $text);
+    $text = preg_replace('#<!-- IFSET (.*?) -->#is', '\'; if(isset($this->tpl_strings[\'\\1\'])) { echo \'', $text);
+    $text = preg_replace('#<!-- IFPLUGIN (.*?) -->#is', '\'; if(getConfig(\'plugin_\\1\')==\'1\') { echo \'', $text);
+    $text = preg_replace('#<!-- SYSMSG (.*?) -->#is', '\'; echo $template->tplWikiFormat($paths->sysMsg(\'\\1\')); echo \'', $text);
+    $text = preg_replace('#<!-- BEGINNOT (.*?) -->#is', '\'; if(!$this->tpl_bool[\'\\1\']) { echo \'', $text);
+    $text = preg_replace('#<!-- BEGINELSE (.*?) -->#is', '\'; } else { echo \'', $text);
+    $text = preg_replace('#<!-- END (.*?) -->#is', '\'; } echo \'', $text);
+    $text = preg_replace('#\{([A-z0-9]*)\}#is', '\'.$this->tpl_strings[\'\\1\'].\'', $text);
+    for($i = 0; $i < sizeof($m[1]); $i++)
+    {
+      $text = str_replace("{PHPCODE:{$i}:{$seed}}", "'; {$m[1][$i]} echo '", $text);
+    }
+    if(is_writable(ENANO_ROOT.'/cache/') && getConfig('cache_thumbs')=='1')
+    {
+      //die($tpl_filename);
+      $h = fopen($tpl_filename, 'w');
+      if(!$h) return $text;
+      $t = addslashes($text);
+      fwrite($h, '<?php $md5 = \''.$md5.'\'; $tpl_text = \''.$t.'\'; ?>');
+      fclose($h);
+    }
+    return $text; //('<pre>'.htmlspecialchars($text).'</pre>');
+  }
+  
+  function compile_template_text($text) {
+    $seed = md5 ( microtime() . mt_rand() );
+    preg_match_all("/<\?php(.*?)\?>/is", $text, $m);
+    //die('<pre>'.htmlspecialchars(print_r($m, true)).'</pre>');
+    for($i = 0; $i < sizeof($m[1]); $i++)
+    {
+      $text = str_replace("<?php{$m[1][$i]}?>", "{PHPCODE:{$i}:{$seed}}", $text);
+    }
+    //die('<pre>'.htmlspecialchars($text).'</pre>');
+    $text = 'ob_start(); echo \''.str_replace('\'', '\\\'', $text).'\'; $tpl_code = ob_get_contents(); ob_end_clean(); return $tpl_code;';
+    $text = preg_replace('#<!-- BEGIN (.*?) -->#is', '\'; if(isset($this->tpl_bool[\'\\1\']) && $this->tpl_bool[\'\\1\']) { echo \'', $text);
+    $text = preg_replace('#<!-- IFSET (.*?) -->#is', '\'; if(isset($this->tpl_strings[\'\\1\'])) { echo \'', $text);
+    $text = preg_replace('#<!-- IFPLUGIN (.*?) -->#is', '\'; if(getConfig(\'plugin_\\1\')==\'1\') { echo \'', $text);
+    $text = preg_replace('#<!-- SYSMSG (.*?) -->#is', '\'; echo $template->tplWikiFormat($paths->sysMsg(\'\\1\')); echo \'', $text);
+    $text = preg_replace('#<!-- BEGINNOT (.*?) -->#is', '\'; if(!$this->tpl_bool[\'\\1\']) { echo \'', $text);
+    $text = preg_replace('#<!-- BEGINELSE (.*?) -->#is', '\'; } else { echo \'', $text);
+    $text = preg_replace('#<!-- END (.*?) -->#is', '\'; } echo \'', $text);
+    $text = preg_replace('#\{([A-z0-9]*)\}#is', '\'.$this->tpl_strings[\'\\1\'].\'', $text);
+    for($i = 0; $i < sizeof($m[1]); $i++)
+    {
+      $text = str_replace("{PHPCODE:{$i}:{$seed}}", "'; {$m[1][$i]} echo '", $text);
+    }
+    return $text; //('<pre>'.htmlspecialchars($text).'</pre>');
+  }
+  
+  function parse($text)
+  {
+    $text = $this->compile_template_text($text);
+    return eval($text);
+  }
+  
+  // Steps to turn this:
+  //   [[Project:Community Portal]]
+  // into this:
+  //   <a href="/Project:Community_Portal">Community Portal</a>
+  // Must be done WITHOUT creating eval'ed code!!!
+  
+  // 1. preg_replace \[\[([a-zA-Z0-9 -_:]*?)\]\] with <a href="'.contentPath.'\\1">\\1</a>
+  // 2. preg_match_all <a href="'.preg_quote(contentPath).'([a-zA-Z0-9 -_:]*?)">
+  // 3. For each match, replace matches with identifiers
+  // 4. For each match, str_replace ' ' with '_'
+  // 5. For each match, str_replace match_id:random_val with $matches[$match_id]
+  
+  // The template language is really a miniature programming language; with variables, conditionals, everything!
+  // So you can implement custom logic into your sidebar if you wish.
+  // "Real" PHP support coming soon :-D
+  
+  function tplWikiFormat($message, $filter_links = false, $filename = 'elements.tpl') {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $filter_links = false;
+    $tplvars = $this->extract_vars($filename);
+    if($session->sid_super) $as = htmlspecialchars(urlSeparator).'auth='.$session->sid_super;
+    else $as = '';
+    error_reporting(E_ALL);
+    $random_id = sha1(microtime().''); // A temp value
+    
+    /*
+     * PREPROCESSOR
+     */
+    
+    // Variables
+    
+    preg_match_all('#\$([A-Z_-]+)\$#', $message, $links);
+    $links = $links[1];
+    
+    for($i=0;$i<sizeof($links);$i++)
+    {
+      $message = str_replace('$'.$links[$i].'$', $this->tpl_strings[$links[$i]], $message);
+    }
+    
+    // Conditionals
+    
+    preg_match_all('#\{if ([A-Za-z0-9_ &\|\!-]*)\}(.*?)\{\/if\}#is', $message, $links);
+    
+    for($i=0;$i<sizeof($links[1]);$i++)
+    {
+      $message = str_replace('{if '.$links[1][$i].'}'.$links[2][$i].'{/if}', '{CONDITIONAL:'.$i.':'.$random_id.'}', $message);
+      
+      // Time for some manual parsing...
+      $chk = false;
+      $current_id = '';
+      $prn_level = 0;
+      // Used to keep track of where we are in the conditional
+      // Object of the game: turn {if this && ( that OR !something_else )} ... {/if} into if( ( isset($this->tpl_bool['that']) && $this->tpl_bool['that'] ) && ...
+      // Method of attack: escape all variables, ignore all else. Non-valid code is filtered out by a regex above.
+      $in_var_now = true;
+      $in_var_last = false;
+      $current_var = '';
+      $current_var_start_pos = 0;
+      $current_var_end_pos   = 0;
+      $j = -1;
+      $links[1][$i] = $links[1][$i] . ' ';
+      $d = strlen($links[1][$i]);
+      while($j < $d)
+      {
+        $j++;
+        $in_var_last = $in_var_now;
+        
+        $char = substr($links[1][$i], $j, 1);
+        $in_var_now = ( preg_match('#^([A-z0-9_]*){1}$#', $char) ) ? true : false;
+        if(!$in_var_last && $in_var_now)
+        {
+          $current_var_start_pos = $j;
+        }
+        if($in_var_last && !$in_var_now)
+        {
+          $current_var_end_pos = $j;
+        }
+        if($in_var_now)
+        {
+          $current_var .= $char;
+          continue;
+        }
+        // OK we are not inside of a variable. That means that we JUST hit the end because the counter ($j) will be advanced to the beginning of the next variable once processing here is complete.
+        if($char != ' ' && $char != '(' && $char != ')' && $char != 'A' && $char != 'N' && $char != 'D' && $char != 'O' && $char != 'R' && $char != '&' && $char != '|' && $char != '!' && $char != '<' && $char != '>' && $char != '0' && $char != '1' && $char != '2' && $char != '3' && $char != '4' && $char != '5' && $char != '6' && $char != '7' && $char != '8' && $char != '9')
+        {
+          // XSS attack! Bail out
+          echo '<p><b>Error:</b> Syntax error (possibly XSS attack) caught in template code:</p>';
+          echo '<pre>';
+          echo '{if '.$links[1][$i].'}';
+          echo "\n    ";
+          for($k=0;$k<$j;$k++) echo " ";
+          echo '<span style="color: red;">^</span>';
+          echo '</pre>';
+          continue 2;
+        }
+        if($current_var != '')
+        {
+          $cd = '( isset($this->tpl_bool[\''.$current_var.'\']) && $this->tpl_bool[\''.$current_var.'\'] )';
+          $cvt = substr($links[1][$i], 0, $current_var_start_pos) . $cd . substr($links[1][$i], $current_var_end_pos, strlen($links[1][$i]));
+          $j = $j + strlen($cd) - strlen($current_var);
+          $current_var = '';
+          $links[1][$i] = $cvt;
+          $d = strlen($links[1][$i]);
+        }
+      }
+      $links[1][$i] = substr($links[1][$i], 0, strlen($links[1][$i])-1);
+      $links[1][$i] = '$chk = ( '.$links[1][$i].' ) ? true : false;';
+      eval($links[1][$i]);
+      
+      if($chk) { // isset($this->tpl_bool[$links[1][$i]]) && $this->tpl_bool[$links[1][$i]]
+        if(strstr($links[2][$i], '{else}')) $c = substr($links[2][$i], 0, strpos($links[2][$i], '{else}'));
+        else $c = $links[2][$i];
+        $message = str_replace('{CONDITIONAL:'.$i.':'.$random_id.'}', $c, $message);
+      } else {
+        if(strstr($links[2][$i], '{else}')) $c = substr($links[2][$i], strpos($links[2][$i], '{else}')+6, strlen($links[2][$i]));
+        else $c = '';
+        $message = str_replace('{CONDITIONAL:'.$i.':'.$random_id.'}', $c, $message);
+      }
+    }
+    
+    preg_match_all('#\{!if ([A-Za-z_-]*)\}(.*?)\{\/if\}#is', $message, $links);
+    
+    for($i=0;$i<sizeof($links[1]);$i++)
+    {
+      $message = str_replace('{!if '.$links[1][$i].'}'.$links[2][$i].'{/if}', '{CONDITIONAL:'.$i.':'.$random_id.'}', $message);
+      if(isset($this->tpl_bool[$links[1][$i]]) && $this->tpl_bool[$links[1][$i]]) {
+        if(strstr($links[2][$i], '{else}')) $c = substr($links[2][$i], strpos($links[2][$i], '{else}')+6, strlen($links[2][$i]));
+        else $c = '';
+        $message = str_replace('{CONDITIONAL:'.$i.':'.$random_id.'}', $c, $message);
+      } else {
+        if(strstr($links[2][$i], '{else}')) $c = substr($links[2][$i], 0, strpos($links[2][$i], '{else}'));
+        else $c = $links[2][$i];
+        $message = str_replace('{CONDITIONAL:'.$i.':'.$random_id.'}', $c, $message);
+      }
+    }
+    
+    /*
+     * HTML RENDERER
+     */
+     
+    // Images
+    $j = preg_match_all('#\[\[:'.$paths->nslist['File'].'([\w\s0-9_\(\)!@%\^\+\|\.-]+?)\]\]#is', $message, $matchlist);
+    $matches = Array();
+    $matches['images'] = $matchlist[1];
+    for($i=0;$i<sizeof($matchlist[1]);$i++)
+    {
+      if(isPage($paths->nslist['File'].$matches['images'][$i]))
+      {
+        $message = str_replace('[[:'.$paths->nslist['File'].$matches['images'][$i].']]',
+                               '<img alt="'.$matches['images'][$i].'" style="border: 0" src="'.makeUrlNS('Special', 'DownloadFile/'.$matches['images'][$i]).'" />',
+                               $message);
+      }
+    }
+    
+    // Internal links
+    
+    $text_parser = $this->makeParserText($tplvars['sidebar_button']);
+    
+    preg_match_all('#\[\[([a-zA-Z0-9 -_]*?)\]\]#is', $message, $il);
+    for($i=0;$i<sizeof($il[1]);$i++)
+    {
+      $href = makeUrl(str_replace(' ', '_', $il[1][$i]), null, true);
+      $text_parser->assign_vars(Array(
+          'HREF'  => $href,
+          'FLAGS' => '',
+          'TEXT'  => $il[1][$i]
+        ));
+      $message = str_replace("[[{$il[1][$i]}]]", $text_parser->run(), $message);
+    }
+    
+    preg_match_all('#\[\[([a-zA-Z0-9 -_]*?)\|([a-zA-Z0-9!@\#\$%\^&\*\(\)\{\} -_]*?)\]\]#is', $message, $il);
+    for($i=0;$i<sizeof($il[1]);$i++)
+    {
+      $href = makeUrl(str_replace(' ', '_', $il[1][$i]), null, true);
+      $text_parser->assign_vars(Array(
+          'HREF'  => $href,
+          'FLAGS' => '',
+          'TEXT'  => $il[2][$i]
+        ));
+      $message = str_replace("[[{$il[1][$i]}|{$il[2][$i]}]]", $text_parser->run(), $message);
+    }
+    
+    // External links
+    $message = preg_replace('#\[(http|ftp|irc):\/\/([a-z0-9\/:_\.\?&%\#@_\\\\-]+?)\\ ([^\]]+)]#', '<a href="\\1://\\2">\\3</a><br style="display: none;" />', $message);
+    $message = preg_replace('#\[(http|ftp|irc):\/\/([a-z0-9\/:_\.\?&%\#@_\\\\-]+?)\\]#', '<a href="\\1://\\2">\\1://\\2</a><br style="display: none;" />', $message);
+    
+    $parser1 = $this->makeParserText($tplvars['sidebar_section']);
+    $parser2 = $this->makeParserText($tplvars['sidebar_section_raw']);
+                            
+    preg_match_all('#\{slider(2|)=(.*?)\}(.*?)\{\/slider(2|)\}#is',  $message, $sb);
+    
+    // Modified to support the sweet new template var system
+    for($i=0;$i<sizeof($sb[1]);$i++)
+    {
+      $p = ($sb[1][$i] == '2') ? $parser2 : $parser1;
+      $p->assign_vars(Array('TITLE'=>$sb[2][$i],'CONTENT'=>$sb[3][$i]));
+      $message = str_replace("{slider{$sb[1][$i]}={$sb[2][$i]}}{$sb[3][$i]}{/slider{$sb[4][$i]}}", $p->run(), $message);
+    }
+    
+    /*
+    Extras ;-)
+    $message = preg_replace('##is', '', $message);
+    $message = preg_replace('##is', '', $message);
+    $message = preg_replace('##is', '', $message);
+    $message = preg_replace('##is', '', $message);
+    $message = preg_replace('##is', '', $message);
+    */
+    
+    //die('<pre>'.htmlspecialchars($message).'</pre>');
+    //eval($message); exit;
+    return $message;
+  }
+  
+  /**
+   * Print a text field that auto-completes a username entered into it.
+   * @param string $name - the name of the form field
+   * @return string
+   */
+   
+  function username_field($name, $value = false)
+  {
+    $randomid = md5( time() . microtime() . mt_rand() );
+    $text = '<input name="'.$name.'" onkeyup="ajaxUserNameComplete(this)" autocomplete="off" type="text" size="30" id="userfield_'.$randomid.'"';
+    if($value) $text .= ' value="'.$value.'"';
+    $text .= ' />';
+    return $text;
+  }
+  
+  /**
+   * Print a text field that auto-completes a page name entered into it.
+   * @param string $name - the name of the form field
+   * @return string
+   */
+   
+  function pagename_field($name, $value = false)
+  {
+    $randomid = md5( time() . microtime() . mt_rand() );
+    $text = '<input name="'.$name.'" onkeyup="ajaxPageNameComplete(this)" type="text" size="30" id="pagefield_'.$randomid.'"';
+    if($value) $text .= ' value="'.$value.'"';
+    $text .= ' />';
+    $text .= '<script type="text/javascript">
+        var inp = document.getElementById(\'pagefield_' . $randomid . '\');
+        var f = get_parent_form(inp);
+        if ( f )
+        {
+          if ( typeof(f.onsubmit) != \'function\' )
+          {
+            f.onsubmit = function() {
+              if ( !submitAuthorized )
+              {
+                return false;
+              }
+            }
+          }
+        }</script>';
+    return $text;
+  }
+  
+  /**
+   * Sends a textarea that can be converted to and from a TinyMCE widget on the fly.
+   * @param string The name of the form element
+   * @param string The initial content. Optional, defaults to blank
+   * @param int Rows in textarea
+   * @param int Columns in textarea
+   * @return string HTML and Javascript code.
+   */
+  
+  function tinymce_textarea($name, $content = '', $rows = 20, $cols = 60)
+  {
+    $randomid = md5(microtime() . mt_rand());
+    $html = '';
+    $html .= '<textarea name="' . $name . '" rows="'.$rows.'" cols="'.$cols.'" style="width: 100%;" id="toggleMCEroot_'.$randomid.'">' . $content . '</textarea>';
+    $html .= '<div style="float: right; display: table;">text editor&nbsp;&nbsp;|&nbsp;&nbsp;<a href="#" onclick="toggleMCE_'.$randomid.'(); return false;">graphical editor</a></div>';
+    $html .= '<script type="text/javascript">
+                function toggleMCE_'.$randomid.'()
+                {
+                  var the_obj = document.getElementById(\'toggleMCEroot_' . $randomid . '\');
+                  if ( the_obj.dnIsMCE == "yes" )
+                  {
+                    $dynano(the_obj).destroyMCE();
+                    the_obj.nextSibling.innerHTML = \'text editor&nbsp;&nbsp;|&nbsp;&nbsp;<a href="#" onclick="toggleMCE_'.$randomid.'(); return false;">graphical editor</a>\';
+                  }
+                  else
+                  {
+                    $dynano(the_obj).switchToMCE();
+                    the_obj.nextSibling.nextSibling.innerHTML = \'<a href="#" onclick="toggleMCE_'.$randomid.'(); return false;">text editor</a>&nbsp;&nbsp;|&nbsp;&nbsp;graphical editor\';
+                  }
+                }
+              </script>';
+    return $html;
+  }
+  
+  /**
+   * Allows individual parsing of template files. Similar to phpBB but follows the spirit of object-oriented programming ;)
+   * Returns on object of class templateIndividual. Usage instructions can be found in the inline docs for that class.
+   * @param $filename the filename of the template to be parsed
+   * @return object
+   */
+   
+  function makeParser($filename)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $filename = ENANO_ROOT.'/themes/'.$template->theme.'/'.$filename;
+    if(!file_exists($filename)) die('templateIndividual: file '.$filename.' does not exist');
+    $code = file_get_contents($filename);
+    $parser = new templateIndividual($code);
+    return $parser;
+  }
+  
+  /**
+   * Same as $template->makeParser(), but takes a string instead of a filename.
+   * @param $text the text to parse
+   * @return object
+   */
+   
+  function makeParserText($code)
+  {
+    $parser = new templateIndividual($code);
+    return $parser;
+  }
+  
+  /**
+   * Fetch the HTML for a plugin-added sidebar block
+   * @param $name the plugin name
+   * @return string
+   */
+   
+  function fetch_block($id)
+  {
+    if(isset($this->plugin_blocks[$id])) return $this->plugin_blocks[$id];
+    else return false;
+  }
+  
+  /**
+   * Fetches the contents of both sidebars.
+   * @return array - key 0 is left, key 1 is right
+   * @example list($left, $right) = $template->fetch_sidebar();
+   */
+   
+  function fetch_sidebar()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    $left = '';
+    $right = '';
+    
+    if ( !$this->fetch_block('Links') )
+      $this->initLinksWidget();
+    
+    $q = $db->sql_query('SELECT item_id,sidebar_id,block_name,block_type,block_content FROM '.table_prefix.'sidebar WHERE item_enabled=1 ORDER BY sidebar_id ASC, item_order ASC;');
+    if(!$q) $db->_die('The sidebar text data could not be selected.');
+    
+    $vars = $this->extract_vars('elements.tpl');
+    
+    if(isset($vars['sidebar_top'])) 
+    {
+      $left  .= $this->parse($vars['sidebar_top']);
+      $right .= $this->parse($vars['sidebar_top']);
+    }
+    while($row = $db->fetchrow())
+    {
+      switch($row['block_type'])
+      {
+        case BLOCK_WIKIFORMAT:
+        default:
+          $parser = $this->makeParserText($vars['sidebar_section']);
+          $c = RenderMan::render($row['block_content']);
+          break;
+        case BLOCK_TEMPLATEFORMAT:
+          $parser = $this->makeParserText($vars['sidebar_section']);
+          $c = $this->tplWikiFormat($row['block_content']);
+          break;
+        case BLOCK_HTML:
+          $parser = $this->makeParserText($vars['sidebar_section_raw']);
+          $c = $row['block_content'];
+          break;
+        case BLOCK_PHP:
+          $parser = $this->makeParserText($vars['sidebar_section_raw']);
+          ob_start();
+          @eval($row['block_content']);
+          $c = ob_get_contents();
+          ob_end_clean();
+          break;
+        case BLOCK_PLUGIN:
+          $parser = $this->makeParserText($vars['sidebar_section_raw']);
+          $c = (gettype($this->fetch_block($row['block_content'])) == 'string') ? $this->fetch_block($row['block_content']) : 'Can\'t find plugin block';
+          break;
+      }
+      $parser->assign_vars(Array( 'TITLE'=>$this->tplWikiFormat($row['block_name']), 'CONTENT'=>$c ));
+      if    ($row['sidebar_id'] == SIDEBAR_LEFT ) $left  .= $parser->run();
+      elseif($row['sidebar_id'] == SIDEBAR_RIGHT) $right .= $parser->run();
+      unset($parser);
+    }
+    $db->free_result();
+    if(isset($vars['sidebar_bottom'])) 
+    {
+      $left  .= $this->parse($vars['sidebar_bottom']);
+      $right .= $this->parse($vars['sidebar_bottom']);
+    }
+    $min = '';
+    if(isset($vars['sidebar_top'])) 
+    {
+      $min .= $this->parse($vars['sidebar_top']);
+    }
+    if(isset($vars['sidebar_bottom']))
+    {
+      $min .= $this->parse($vars['sidebar_bottom']);
+    }
+    return Array($left, $right, $min);
+  }
+  
+  function initLinksWidget()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    // SourceForge/W3C buttons
+    $ob = Array();
+    if(getConfig('powered_btn') =='1') $ob[] = '<a style="text-align: center;" href="http://www.enanocms.org/"                  onclick="window.open(this.href);return false;"><img alt="Powered by Enano" src="'.scriptPath.'/images/about-powered-enano.png" onmouseover="this.src=\''.scriptPath.'/images/about-powered-enano-hover.png\';" onmouseout="this.src=\''.scriptPath.'/images/about-powered-enano.png\';" style="border-width: 0px;" width="88" height="31" /></a>';
+    if(getConfig('sflogo_enabled')=='1')
+    {
+      $ob[] = '<a style="text-align: center;" href="http://sourceforge.net/" onclick="window.open(this.href);return false;"><img style="border-width: 0px;" alt="SourceForge.net Logo" src="http://sflogo.sourceforge.net/sflogo.php?group_id='.getConfig('sflogo_groupid').'&amp;type='.getConfig('sflogo_type').'" /></a>';
+    }
+    if(getConfig('w3c_v32')     =='1') $ob[] = '<a style="text-align: center;" href="http://validator.w3.org/check?uri=referer" onclick="window.open(this.href);return false;"><img style="border: 0px solid #FFFFFF;" alt="Valid HTML 3.2"  src="http://www.w3.org/Icons/valid-html32" /></a>';
+    if(getConfig('w3c_v40')     =='1') $ob[] = '<a style="text-align: center;" href="http://validator.w3.org/check?uri=referer" onclick="window.open(this.href);return false;"><img style="border: 0px solid #FFFFFF;" alt="Valid HTML 4.0"  src="http://www.w3.org/Icons/valid-html40" /></a>';
+    if(getConfig('w3c_v401')    =='1') $ob[] = '<a style="text-align: center;" href="http://validator.w3.org/check?uri=referer" onclick="window.open(this.href);return false;"><img style="border: 0px solid #FFFFFF;" alt="Valid HTML 4.01" src="http://www.w3.org/Icons/valid-html401" /></a>';
+    if(getConfig('w3c_vxhtml10')=='1') $ob[] = '<a style="text-align: center;" href="http://validator.w3.org/check?uri=referer" onclick="window.open(this.href);return false;"><img style="border: 0px solid #FFFFFF;" alt="Valid XHTML 1.0" src="http://www.w3.org/Icons/valid-xhtml10" /></a>';
+    if(getConfig('w3c_vxhtml11')=='1') $ob[] = '<a style="text-align: center;" href="http://validator.w3.org/check?uri=referer" onclick="window.open(this.href);return false;"><img style="border: 0px solid #FFFFFF;" alt="Valid XHTML 1.1" src="http://www.w3.org/Icons/valid-xhtml11" /></a>';
+    if(getConfig('w3c_vcss')    =='1') $ob[] = '<a style="text-align: center;" href="http://validator.w3.org/check?uri=referer" onclick="window.open(this.href);return false;"><img style="border: 0px solid #FFFFFF;" alt="Valid CSS"       src="http://www.w3.org/Icons/valid-css" /></a>';
+    if(getConfig('dbd_button')  =='1') $ob[] = '<a style="text-align: center;" href="http://www.defectivebydesign.org/join/button" onclick="window.open(this.href);return false;"><img style="border: 0px solid #FFFFFF;" alt="DRM technology restricts what you can do with your computer" src="http://defectivebydesign.org/sites/nodrm.civicactions.net/files/images/dbd_sm_btn.gif" /><br /><small>Protect your freedom >></small></a>';
+    
+    $code = $plugins->setHook('links_widget');
+    foreach ( $code as $cmd )
+    {
+      eval($cmd);
+    }
+    
+    if(count($ob) > 0) $sb_links = '<div style="text-align: center; padding: 5px 0;">'.implode('<br />', $ob).'</div>';
+    else $sb_links = '';
+    
+    $this->sidebar_widget('Links', $sb_links);
+  }
+  
+  /**
+   * Builds a box showing unread private messages.
+   */
+  
+  function notify_unread_pms()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if ( ( $paths->cpage['urlname_nons'] == 'PrivateMessages' || $paths->cpage['urlname_nons'] == 'Preferences' ) && $paths->namespace == 'Special' )
+    {
+      return '';
+    }
+    $ob = '<div class="usermessage">'."\n";
+    $s = ( $session->unread_pms == 1 ) ? '' : 's';
+    $ob .= "  <b>You have $session->unread_pms <a href=" . '"' . makeUrlNS('Special', 'PrivateMessages' ) . '"' . ">unread private message$s</a>.</b><br />\n  Messages: ";
+    $q = $db->sql_query('SELECT message_id,message_from,subject,date FROM '.table_prefix.'privmsgs WHERE message_to=\'' . $session->username . '\' AND message_read=0 ORDER BY date DESC;');
+    if ( !$q )
+      $db->_die();
+    $messages = array();
+    while ( $row = $db->fetchrow() )
+    {
+      $messages[] = '<a href="' . makeUrlNS('Special', 'PrivateMessages/View/' . $row['message_id']) . '" title="Sent ' . date('F d, Y h:i a', $row['date']) . ' by ' . $row['message_from'] . '">' . $row['subject'] . '</a>';
+    }
+    $ob .= implode(",\n    " , $messages)."\n";
+    $ob .= '</div>'."\n";
+    return $ob;
+  }
+  
+} // class template
+
+/**
+ * Handles parsing of an individual template file. Instances should only be created through $template->makeParser(). To use:
+ *   - Call $template->makeParser(template file name) - file name should be something.tpl, css/whatever.css, etc.
+ *   - Make an array of strings you want the template to access. $array['STRING'] would be referenced in the template like {STRING}
+ *   - Make an array of boolean values. These can be used for conditionals in the template (<!-- IF something --> whatever <!-- ENDIF something -->)
+ *   - Call assign_vars() to pass the strings to the template parser. Same thing with assign_bool().
+ *   - Call run() to parse the template and get your fully compiled HTML.
+ * @access private
+ */
+
+class templateIndividual extends template {
+  var $tpl_strings, $tpl_bool, $tpl_code;
+  var $compiled = false;
+  /**
+   * Constructor.
+   */
+  function __construct($text)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $this->tpl_code = $text;
+    $this->tpl_strings = $template->tpl_strings;
+    $this->tpl_bool = $template->tpl_bool;
+  }
+  /**
+   * PHP 4 constructor.
+   */
+  function templateIndividual($text)
+  {
+    $this->__construct($text);
+  }
+  /**
+   * Assigns an array of string values to the template. Strings can be accessed from the template by inserting {KEY_NAME} in the template file.
+   * @param $vars array
+   */
+  function assign_vars($vars)
+  {
+    $this->tpl_strings = array_merge($this->tpl_strings, $vars);
+  }
+  /**
+   * Assigns an array of boolean values to the template. These can be used for <!-- IF ... --> statements.
+   * @param $vars array
+   */
+  function assign_bool($vars)
+  {
+    $this->tpl_bool = array_merge($this->tpl_bool, $vars);
+  }
+  /**
+   * Compiles and executes the template code.
+   * @return string
+   */
+  function run()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(!$this->compiled)
+    {
+      $this->tpl_code = $this->compile_template_text($this->tpl_code);
+      $this->compiled = true;
+    }
+    return eval($this->tpl_code);
+  }
+}
+
+/**
+ * A version of the template compiler that does not rely at all on the other parts of Enano. Used during installation and for showing
+ * "critical error" messages. ** REQUIRES ** the Oxygen theme.
+ */
+
+class template_nodb {
+  var $tpl_strings, $tpl_bool, $theme, $style, $no_headers, $additional_headers, $sidebar_extra, $sidebar_widgets, $toolbar_menu, $theme_list;
+  function __construct() {
+    
+    $this->tpl_bool    = Array();
+    $this->tpl_strings = Array();
+    $this->sidebar_extra = '';
+    $this->sidebar_widgets = '';
+    $this->toolbar_menu = '';
+    $this->additional_headers = '';
+    
+    $this->theme_list = Array(Array(
+      'theme_id'=>'oxygen',
+      'theme_name'=>'Oxygen',
+      'theme_order'=>1,
+      'enabled'=>1,
+      ));
+  }
+  function template() {
+    $this->__construct();
+  }
+  function get_css($s = false) {
+    if($s)
+      return $this->process_template('css/'.$s);
+    else
+      return $this->process_template('css/'.$this->style.'.css');
+  }
+  function load_theme($name, $css, $auto_init = true) {
+    $this->theme = $name;
+    $this->style = $css;
+    
+    $this->tpl_strings['SCRIPTPATH'] = scriptPath;
+    if ( $auto_init )
+      $this->init_vars();
+  }
+  function init_vars()
+  {
+    global $sideinfo;
+    global $this_page;
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $tplvars = $this->extract_vars('elements.tpl');
+    $tb = '';
+    // Get the "article" button text (depends on namespace)
+    if(defined('IN_ENANO_INSTALL')) $ns = 'installation page';
+    else $ns = 'system error page';
+    $t = str_replace('{FLAGS}', 'onclick="return false;" title="Hey! A button that doesn\'t do anything. Clever..." accesskey="a"', $tplvars['toolbar_button']);
+    $t = str_replace('{HREF}', '#', $t);
+    $t = str_replace('{TEXT}', $ns, $t);
+    $tb .= $t;
+    
+    // Page toolbar
+    
+    $this->tpl_bool = Array(
+      'auth_admin'=>true,
+      'user_logged_in'=>true,
+      'right_sidebar'=>false,
+      );
+    $this->tpl_bool['in_sidebar_admin'] = false;
+    
+    $this->tpl_bool['auth_rename'] = false;
+    
+    $asq = $asa = '';
+    
+    $this->tpl_bool['fixed_menus'] = false;
+    $slink = defined('IN_ENANO_INSTALL') ? scriptPath.'/install.php?mode=css' : makeUrlNS('Special', 'CSS');
+    
+    $title = ( is_object($paths) ) ? $paths->page : 'Critical error';
+    
+    // The rewritten template engine will process all required vars during the load_template stage instead of (cough) re-processing everything each time around.
+    $tpl_strings = Array(
+      'PAGE_NAME'=>$this_page,
+      'PAGE_URLNAME'=>'Null',
+      'SITE_NAME'=>'Enano Installation',
+      'USERNAME'=>'admin',
+      'SITE_DESC'=>'Install Enano on your server.',
+      'TOOLBAR'=>$tb,
+      'SCRIPTPATH'=>scriptPath,
+      'CONTENTPATH'=>contentPath,
+      'ADMIN_SID_QUES'=>$asq,
+      'ADMIN_SID_AMP'=>$asa,
+      'ADMIN_SID_AMP_HTML'=>'',
+      'ADDITIONAL_HEADERS'=>'<style type="text/css">div.pagenav { border-top: 1px solid #CCC; padding-top: 7px; margin-top: 10px; }</style>',
+      'SIDEBAR_EXTRA'=>'',
+      'COPYRIGHT'=>'Enano and all of its code, graphics, and more code is copyright &copy; 2006 Dan Fuhry.<br />This program is Free Software; see the file "GPL" included with this package for details.',
+      'TOOLBAR_EXTRAS'=>'',
+      'REQUEST_URI'=>$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'],
+      'STYLE_LINK'=>$slink,
+      'LOGOUT_LINK'=>'',
+      'THEME_LINK'=>'',
+      'TEMPLATE_DIR'=>scriptPath.'/themes/'.$this->theme,
+      'THEME_ID'=>$this->theme,
+      'STYLE_ID'=>$this->style,
+      'JS_DYNAMIC_VARS'=>'<script type="text/javascript">var title="'. $title .'"; var scriptPath="'.scriptPath.'"; var ENANO_SID=""; var AES_BITS='.AES_BITS.'; var AES_BLOCKSIZE=' . AES_BLOCKSIZE . '; var pagepass=\'\';</script>',
+      'SIDEBAR_RIGHT'=>'',
+      );
+    $this->tpl_strings = array_merge($tpl_strings, $this->tpl_strings);
+    
+    $sidebar = ( gettype($sideinfo) == 'string' ) ? $sideinfo : '';
+    if($sidebar != '')
+    {
+      if(isset($tplvars['sidebar_top']))
+      {
+        $text = $this->makeParserText($tplvars['sidebar_top']);
+        $top = $text->run();
+      } else {
+        $top = '';
+      }
+      $p = $this->makeParserText($tplvars['sidebar_section']);
+      $p->assign_vars(Array(
+          'TITLE'=>'Installation progress',
+          'CONTENT'=>$sidebar,
+        ));
+      $sidebar = $p->run();
+      if(isset($tplvars['sidebar_bottom']))
+      {
+        $text = $this->makeParserText($tplvars['sidebar_bottom']);
+        $bottom = $text->run();
+      } else {
+        $bottom = '';
+      }
+      $sidebar = $top . $sidebar . $bottom;
+    }
+    $this->tpl_strings['SIDEBAR_LEFT'] = $sidebar;
+    
+    $this->tpl_bool['sidebar_left']  = ( $this->tpl_strings['SIDEBAR_LEFT']  != '') ? true : false;
+    $this->tpl_bool['sidebar_right'] = ( $this->tpl_strings['SIDEBAR_RIGHT'] != '') ? true : false;
+    $this->tpl_bool['right_sidebar'] = $this->tpl_bool['sidebar_right']; // backward compatibility
+    $this->tpl_bool['stupid_mode'] = true;
+  }
+  function header() 
+  {
+    if(!$this->no_headers) echo $this->process_template('header.tpl');
+  }
+  function footer()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(!$this->no_headers) {
+      global $_starttime;
+      $f = microtime(true);
+      $f = $f - $_starttime;
+      $f = round($f, 4);
+      if(defined('IN_ENANO_INSTALL')) $nq = 'N/A';
+      else $nq = $db->num_queries;
+      if($nq == 0) $nq = 'N/A';
+      $dbg = 'Time: '.$f.'s  |  Queries: '.$nq;
+      $t = $this->process_template('footer.tpl');
+      $t = str_replace('[[Stats]]', $dbg, $t);
+      echo $t;
+    }
+    else return '';
+  }
+  function getHeader()
+  {
+    if(!$this->no_headers) return $this->process_template('header.tpl');
+    else return '';
+  }
+  function getFooter()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(!$this->no_headers) {
+      global $_starttime;
+      $f = microtime(true);
+      $f = $f - $_starttime;
+      $f = round($f, 4);
+      if(defined('IN_ENANO_INSTALL')) $nq = 'N/A';
+      else $nq = $db->num_queries;
+      if($nq == 0) $nq = 'N/A';
+      $dbg = 'Time: '.$f.'s  |  Queries: '.$nq;
+      if($nq == 0) $nq = 'N/A';
+      $t = $this->process_template('footer.tpl');
+      $t = str_replace('[[Stats]]', $dbg, $t);
+      return $t;
+    }
+    else return '';
+  }
+  
+  function process_template($file) {
+    
+    eval($this->compile_template($file));
+    return $tpl_code;
+  }
+  
+  function extract_vars($file) {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(!is_file(ENANO_ROOT . '/themes/'.$this->theme.'/'.$file)) die('Cannot find '.$file.' file for style "'.$this->theme.'", exiting');
+    $text = file_get_contents(ENANO_ROOT . '/themes/'.$this->theme.'/'.$file);
+    preg_match_all('#<\!-- VAR ([A-z0-9_-]*) -->(.*?)<\!-- ENDVAR \\1 -->#is', $text, $matches);
+    $tplvars = Array();
+    for($i=0;$i<sizeof($matches[1]);$i++)
+    {
+      $tplvars[$matches[1][$i]] = $matches[2][$i];
+    }
+    return $tplvars;
+  }
+  function compile_template($text) {
+    global $sideinfo;
+    $text = file_get_contents(ENANO_ROOT . '/themes/'.$this->theme.'/'.$text);
+    $text = str_replace('<script type="text/javascript" src="{SCRIPTPATH}/ajax.php?title={PAGE_URLNAME}&amp;_mode=jsres"></script>', '', $text); // Remove the AJAX code - we don't need it, and it requires a database connection
+    $text = '$tpl_code = \''.str_replace('\'', '\\\'', $text).'\'; return $tpl_code;';
+    $text = preg_replace('#<!-- BEGIN (.*?) -->#is', '\'; if($this->tpl_bool[\'\\1\']) { $tpl_code .= \'', $text);
+    $text = preg_replace('#<!-- IFPLUGIN (.*?) -->#is', '\'; if(getConfig(\'plugin_\\1\')==\'1\') { $tpl_code .= \'', $text);
+    if(defined('IN_ENANO_INSTALL')) $text = str_replace('<!-- SYSMSG Sidebar -->', '<div class="slider"><div class="heading"><a class="head">Installation progress</a></div><div class="slideblock">'.$sideinfo.'</div></div>', $text);
+    else $text = str_replace('<!-- SYSMSG Sidebar -->', '<div class="slider"><div class="heading"><a class="head">System error</a></div><div class="slideblock"><a href="#" onclick="return false;">Enano critical error page</a></div></div>', $text);
+    $text = preg_replace('#<!-- SYSMSG (.*?) -->#is', '', $text);
+    $text = preg_replace('#<!-- BEGINNOT (.*?) -->#is', '\'; if(!$this->tpl_bool[\'\\1\']) { $tpl_code .= \'', $text);
+    $text = preg_replace('#<!-- BEGINELSE (.*?) -->#is', '\'; } else { $tpl_code .= \'', $text);
+    $text = preg_replace('#<!-- END (.*?) -->#is', '\'; } $tpl_code .= \'', $text);
+    $text = preg_replace('#{([A-z0-9]*)}#is', '\'.$this->tpl_strings[\'\\1\'].\'', $text);
+    return $text; //('<pre>'.htmlspecialchars($text).'</pre>');
+  }
+  
+  function compile_template_text($text) {
+    global $sideinfo;
+    $text = str_replace('<script type="text/javascript" src="{SCRIPTPATH}/ajax.php?title={PAGE_URLNAME}&amp;_mode=jsres"></script>', '', $text); // Remove the AJAX code - we don't need it, and it requires a database connection
+    $text = '$tpl_code = \''.str_replace('\'', '\\\'', $text).'\'; return $tpl_code;';
+    $text = preg_replace('#<!-- BEGIN (.*?) -->#is', '\'; if($this->tpl_bool[\'\\1\']) { $tpl_code .= \'', $text);
+    $text = preg_replace('#<!-- IFPLUGIN (.*?) -->#is', '\'; if(getConfig(\'plugin_\\1\')==\'1\') { $tpl_code .= \'', $text);
+    if(defined('IN_ENANO_INSTALL')) $text = str_replace('<!-- SYSMSG Sidebar -->', '<div class="slider"><div class="heading"><a class="head">Installation progress</a></div><div class="slideblock">'.$sideinfo.'</div></div>', $text);
+    else $text = str_replace('<!-- SYSMSG Sidebar -->', '<div class="slider"><div class="heading"><a class="head">System error</a></div><div class="slideblock"><a href="#" onclick="return false;">Enano critical error page</a></div></div>', $text);
+    $text = preg_replace('#<!-- SYSMSG (.*?) -->#is', '', $text);
+    $text = preg_replace('#<!-- BEGINNOT (.*?) -->#is', '\'; if(!$this->tpl_bool[\'\\1\']) { $tpl_code .= \'', $text);
+    $text = preg_replace('#<!-- BEGINELSE (.*?) -->#is', '\'; } else { $tpl_code .= \'', $text);
+    $text = preg_replace('#<!-- END (.*?) -->#is', '\'; } $tpl_code .= \'', $text);
+    $text = preg_replace('#{([A-z0-9]*)}#is', '\'.$this->tpl_strings[\'\\1\'].\'', $text);
+    return $text; //('<pre>'.htmlspecialchars($text).'</pre>');
+  }
+  
+  /**
+   * Allows individual parsing of template files. Similar to phpBB but follows the spirit of object-oriented programming ;)
+   * Returns on object of class templateIndividual. Usage instructions can be found in the inline docs for that class.
+   * @param $filename the filename of the template to be parsed
+   * @return object
+   */
+   
+  function makeParser($filename)
+  {
+    $filename = ENANO_ROOT.'/themes/'.$this->theme.'/'.$filename;
+    if(!file_exists($filename)) die('templateIndividual: file '.$filename.' does not exist');
+    $code = file_get_contents($filename);
+    $parser = new templateIndividualSafe($code, $this);
+    return $parser;
+  }
+  
+  /**
+   * Same as $template->makeParser(), but takes a string instead of a filename.
+   * @param $text the text to parse
+   * @return object
+   */
+   
+  function makeParserText($code)
+  {
+    $parser = new templateIndividualSafe($code, $this);
+    return $parser;
+  }
+   
+} // class template_nodb
+
+/**
+ * Identical to templateIndividual, except extends template_nodb instead of template
+ * @see class template
+ */
+ 
+class templateIndividualSafe extends template_nodb {
+  var $tpl_strings, $tpl_bool, $tpl_code;
+  var $compiled = false;
+  /**
+   * Constructor.
+   */
+  function __construct($text, $parent)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    $this->tpl_code = $text;
+    $this->tpl_strings = $parent->tpl_strings;
+    $this->tpl_bool = $parent->tpl_bool;
+  }
+  /**
+   * PHP 4 constructor.
+   */
+  function templateIndividual($text)
+  {
+    $this->__construct($text);
+  }
+  /**
+   * Assigns an array of string values to the template. Strings can be accessed from the template by inserting {KEY_NAME} in the template file.
+   * @param $vars array
+   */
+  function assign_vars($vars)
+  {
+    if(is_array($this->tpl_strings))
+      $this->tpl_strings = array_merge($this->tpl_strings, $vars);
+    else
+      $this->tpl_strings = $vars;
+  }
+  /**
+   * Assigns an array of boolean values to the template. These can be used for <!-- IF ... --> statements.
+   * @param $vars array
+   */
+  function assign_bool($vars)
+  {
+    $this->tpl_bool = array_merge($this->tpl_bool, $vars);
+  }
+  /**
+   * Compiles and executes the template code.
+   * @return string
+   */
+  function run()
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    if(!$this->compiled)
+    {
+      $this->tpl_code = $this->compile_template_text($this->tpl_code);
+      $this->compiled = true;
+    }
+    return eval($this->tpl_code);
+  }
+}
+
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Default.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,27 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Parse structured wiki text and render into arbitrary formats such as XHTML.
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Justin Patrin <justinpatrin@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Default.php,v 1.1 2006/03/01 16:58:17 justinpatrin Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+require_once('Text/Wiki.php');
+
+/**
+ * This is the parser for the Default ruleset. For now, this simply extends Text_Wiki.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @version    Release: @package_version@
+ * @author     Justin Patrin <justinpatrin@php.net>
+ */
+class Text_Wiki_Default extends Text_Wiki {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Mediawiki.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,93 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Parse structured wiki text and render into arbitrary formats such as XHTML.
+ * This is the Text_Wiki extension for Mediawiki markup
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Bertrand Gugger <bertrand@toggg.com>
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Mediawiki.php,v 1.8 2006/02/25 09:59:34 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * "master" class for handling the management and convenience
+ */
+require_once(ENANO_ROOT.'/includes/wikiformat.php');
+
+/**
+ * Base Text_Wiki handler class extension for Mediawiki markup
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Bertrand Gugger <bertrand@toggg.com>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ * @see        Text_Wiki::Text_Wiki()
+ */
+class Text_Wiki_Mediawiki extends Text_Wiki {
+    var $rules = array(
+        'Prefilter',
+        'Delimiter',
+        'Code',
+//        'Plugin',
+//        'Function',
+//        'Html',
+        'Raw',
+//        'Preformatted',
+//        'Include',
+//        'Embed',
+//        'Page',
+//        'Anchor',
+        'Heading',
+        'Toc',
+//        'Titlebar',
+        'Horiz',
+        'Break',
+        'Blockquote',
+        'List',
+        'Deflist',
+//        'Table',
+//        'Box',
+//        'Image', // done by Wikilink but still possible to disable/configure
+//        'Phplookup',
+        'Center',
+        'Newline',
+        'Paragraph',
+        'Url',
+//        'Freelink',
+//        'Colortext',
+        'Wikilink',
+//        'Strong',  ** will be only fake inserted by Emphasis if needed for render
+        'Bold',
+        'Emphasis',
+        'Italic',
+        'Underline',
+        'Tt',
+        'Superscript',
+        'Subscript',
+//        'Specialchar',
+        'Revise',
+//        'Interwiki', // done by Wikilink but still possible to disable/configure
+        'Tighten'
+    );
+
+	/**
+     * Constructor: just adds the path to Mediawiki rules
+     *
+     * @access public
+     * @param array $rules The set of rules to load for this object.
+     */
+    function Text_Wiki_Mediawiki($rules = null) {
+        parent::Text_Wiki($rules);
+        $this->addPath('parse', $this->fixPath(dirname(__FILE__)).'Parse/Mediawiki');
+    }
+}
+
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,264 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Baseline rule class for extension into a "real" parser component.
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Parse.php,v 1.5 2005/07/29 08:57:29 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * Baseline rule class for extension into a "real" parser component.
+ *
+ * Text_Wiki_Rule classes do not stand on their own; they are called by a
+ * Text_Wiki object, typcially in the transform() method. Each rule class
+ * performs three main activities: parse, process, and render.
+ *
+ * The parse() method takes a regex and applies it to the whole block of
+ * source text at one time. Each match is sent as $matches to the
+ * process() method.
+ *
+ * The process() method acts on the matched text from the source, and
+ * then processes the source text is some way.  This may mean the
+ * creation of a delimited token using addToken().  In every case, the
+ * process() method returns the text that should replace the matched text
+ * from parse().
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Parse {
+
+
+    /**
+    *
+    * Configuration options for this parser rule.
+    *
+    * @access public
+    *
+    * @var string
+    *
+    */
+
+    var $conf = array();
+
+
+    /**
+    *
+    * Regular expression to find matching text for this rule.
+    *
+    * @access public
+    *
+    * @var string
+    *
+    * @see parse()
+    *
+    */
+
+    var $regex = null;
+
+
+    /**
+    *
+    * The name of this rule for new token array elements.
+    *
+    * @access public
+    *
+    * @var string
+    *
+    */
+
+    var $rule = null;
+
+
+    /**
+    *
+    * A reference to the calling Text_Wiki object.
+    *
+    * This is needed so that each rule has access to the same source
+    * text, token set, URLs, interwiki maps, page names, etc.
+    *
+    * @access public
+    *
+    * @var object
+    */
+
+    var $wiki = null;
+
+
+    /**
+    *
+    * Constructor for this parser rule.
+    *
+    * @access public
+    *
+    * @param object &$obj The calling "parent" Text_Wiki object.
+    *
+    */
+
+    function Text_Wiki_Parse(&$obj)
+    {
+        // set the reference to the calling Text_Wiki object;
+        // this allows us access to the shared source text, token
+        // array, etc.
+        $this->wiki =& $obj;
+
+        // set the name of this rule; generally used when adding
+        // to the tokens array. strip off the Text_Wiki_Parse_ portion.
+        // text_wiki_parse_
+        // 0123456789012345
+        $tmp = substr(get_class($this), 16);
+        $this->rule = ucwords(strtolower($tmp));
+
+        // override config options for the rule if specified
+        if (isset($this->wiki->parseConf[$this->rule]) &&
+            is_array($this->wiki->parseConf[$this->rule])) {
+
+            $this->conf = array_merge(
+                $this->conf,
+                $this->wiki->parseConf[$this->rule]
+            );
+
+        }
+    }
+
+
+    /**
+    *
+    * Abstrct method to parse source text for matches.
+    *
+    * Applies the rule's regular expression to the source text, passes
+    * every match to the process() method, and replaces the matched text
+    * with the results of the processing.
+    *
+    * @access public
+    *
+    * @see Text_Wiki_Parse::process()
+    *
+    */
+
+    function parse()
+    {
+        $this->wiki->source = preg_replace_callback(
+            $this->regex,
+            array(&$this, 'process'),
+            $this->wiki->source
+        );
+    }
+
+
+    /**
+    *
+    * Abstract method to generate replacements for matched text.
+    *
+    * @access public
+    *
+    * @param array $matches An array of matches from the parse() method
+    * as generated by preg_replace_callback.  $matches[0] is the full
+    * matched string, $matches[1] is the first matched pattern,
+    * $matches[2] is the second matched pattern, and so on.
+    *
+    * @return string The processed text replacement; defaults to the
+    * full matched string (i.e., no changes to the text).
+    *
+    * @see Text_Wiki_Parse::parse()
+    *
+    */
+
+    function process(&$matches)
+    {
+        return $matches[0];
+    }
+
+
+    /**
+    *
+    * Simple method to safely get configuration key values.
+    *
+    * @access public
+    *
+    * @param string $key The configuration key.
+    *
+    * @param mixed $default If the key does not exist, return this value
+    * instead.
+    *
+    * @return mixed The configuration key value (if it exists) or the
+    * default value (if not).
+    *
+    */
+
+    function getConf($key, $default = null)
+    {
+        if (isset($this->conf[$key])) {
+            return $this->conf[$key];
+        } else {
+            return $default;
+        }
+    }
+
+
+    /**
+    *
+    * Extract 'attribute="value"' portions of wiki markup.
+    *
+    * This kind of markup is typically used only in macros, but is useful
+    * anywhere.
+    *
+    * The syntax is pretty strict; there can be no spaces between the
+    * option name, the equals, and the first double-quote; the value
+    * must be surrounded by double-quotes.  You can escape characters in
+    * the value with a backslash, and the backslash will be stripped for
+    * you.
+    *
+    * @access public
+    *
+    * @param string $text The "attributes" portion of markup.
+    *
+    * @return array An associative array of key-value pairs where the
+    * key is the option name and the value is the option value.
+    *
+    */
+
+    function getAttrs($text)
+    {
+        // find the =" sections;
+        $tmp = explode('="', trim($text));
+
+        // basic setup
+        $k = count($tmp) - 1;
+        $attrs = array();
+        $key = null;
+
+        // loop through the sections
+        foreach ($tmp as $i => $val) {
+
+            // first element is always the first key
+            if ($i == 0) {
+                $key = trim($val);
+                continue;
+            }
+
+            // find the last double-quote in the value.
+            // the part to the left is the value for the last key,
+            // the part to the right is the next key name
+            $pos = strrpos($val, '"');
+            $attrs[$key] = stripslashes(substr($val, 0, $pos));
+            $key = trim(substr($val, $pos+1));
+
+        }
+
+        return $attrs;
+
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Default/Anchor.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,87 @@
+<?php
+
+/**
+* 
+* Parses for anchor targets.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Manuel Holtgrewe <purestorm at ggnore dot net>
+*
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Anchor.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* This class implements a Text_Wiki_Parse to add an anchor target name
+* in the wiki page.
+*
+* @author Manuel Holtgrewe <purestorm at ggnore dot net>
+*
+* @author Paul M. Jones <pmjones at ciaweb dot net>
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+*/
+
+class Text_Wiki_Parse_Anchor extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * The regular expression used to find source text matching this
+    * rule.  Looks like a macro: [[# anchor_name]]
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    */
+    
+    var $regex = '/(\[\[# )([-_A-Za-z0-9.]+?)( .+)?(\]\])/i';
+    
+    
+    /**
+    * 
+    * Generates a token entry for the matched text.  Token options are:
+    * 
+    * 'text' => The full matched text, not including the <code></code> tags.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return A delimited token number to be used as a placeholder in
+    * the source text.
+    *
+    */
+    
+    function process(&$matches) {
+    
+        $name = $matches[2];
+        $text = $matches[3];
+        
+        $start = $this->wiki->addToken(
+            $this->rule,
+            array('type' => 'start', 'name' => $name)
+        );
+        
+        $end = $this->wiki->addToken(
+            $this->rule,
+            array('type' => 'end', 'name' => $name)
+        );
+        
+        // done, place the script output directly in the source
+        return $start . trim($text) . $end;
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Default/Blockquote.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,179 @@
+<?php
+
+/**
+* 
+* Parse for block-quoted text.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Blockquote.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Parse for block-quoted text.
+* 
+* Find source text marked as a blockquote, identified by any number of
+* greater-than signs '>' at the start of the line, followed by a space,
+* and then the quote text; each '>' indicates an additional level of
+* quoting.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Blockquote extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * Regex for parsing the source text.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    * @see parse()
+    * 
+    */
+    
+    var $regex = '/\n((\>).*\n)(?!(\>))/Us';
+    
+    
+    /**
+    * 
+    * Generates a replacement for the matched text.
+    * 
+    * Token options are:
+    * 
+    * 'type' =>
+    *     'start' : the start of a blockquote
+    *     'end'   : the end of a blockquote
+    *
+    * 'level' => the indent level (0 for the first level, 1 for the
+    * second, etc)
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return A series of text and delimited tokens marking the different
+    * list text and list elements.
+    *
+    */
+    
+    function process(&$matches)
+    {
+        // the replacement text we will return to parse()
+        $return = '';
+        
+        // the list of post-processing matches
+        $list = array();
+        
+        // $matches[1] is the text matched as a list set by parse();
+        // create an array called $list that contains a new set of
+        // matches for the various list-item elements.
+        preg_match_all(
+            '=^(\>+) (.*\n)=Ums',
+            $matches[1],
+            $list,
+            PREG_SET_ORDER
+        );
+        
+        // a stack of starts and ends; we keep this so that we know what
+        // indent level we're at.
+        $stack = array();
+        
+        // loop through each list-item element.
+        foreach ($list as $key => $val) {
+            
+            // $val[0] is the full matched list-item line
+            // $val[1] is the number of initial '>' chars (indent level)
+            // $val[2] is the quote text
+            
+            // we number levels starting at 1, not zero
+            $level = strlen($val[1]);
+            
+            // get the text of the line
+            $text = $val[2];
+            
+            // add a level to the list?
+            while ($level > count($stack)) {
+                
+                // the current indent level is greater than the number
+                // of stack elements, so we must be starting a new
+                // level.  push the new level onto the stack with a 
+                // dummy value (boolean true)...
+                array_push($stack, true);
+                
+                $return .= "\n";
+                
+                // ...and add a start token to the return.
+                $return .= $this->wiki->addToken(
+                    $this->rule, 
+                    array(
+                        'type' => 'start',
+                        'level' => $level - 1
+                    )
+                );
+                
+                $return .= "\n\n";
+            }
+            
+            // remove a level?
+            while (count($stack) > $level) {
+                
+                // as long as the stack count is greater than the
+                // current indent level, we need to end list types.
+                // continue adding end-list tokens until the stack count
+                // and the indent level are the same.
+                array_pop($stack);
+                
+                $return .= "\n\n";
+                
+                $return .= $this->wiki->addToken(
+                    $this->rule, 
+                    array (
+                        'type' => 'end',
+                        'level' => count($stack)
+                    )
+                );
+                
+                $return .= "\n";
+            }
+            
+            // add the line text.
+            $return .= $text;
+        }
+        
+        // the last line may have been indented.  go through the stack
+        // and create end-tokens until the stack is empty.
+        $return .= "\n";
+        
+        while (count($stack) > 0) {
+            array_pop($stack);
+            $return .= $this->wiki->addToken(
+                $this->rule, 
+                array (
+                    'type' => 'end',
+                    'level' => count($stack)
+                )
+            );
+        }
+        
+        // we're done!  send back the replacement text.
+        return "\n$return\n\n";
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Default/Bold.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,79 @@
+<?php
+
+/**
+* 
+* Parses for bold text.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Bold.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Parses for bold text.
+* 
+* This class implements a Text_Wiki_Rule to find source text marked for
+* strong emphasis (bold) as defined by text surrounded by three
+* single-quotes. On parsing, the text itself is left in place, but the
+* starting and ending instances of three single-quotes are replaced with
+* tokens.
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Bold extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * The regular expression used to parse the source text and find
+    * matches conforming to this rule.  Used by the parse() method.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    * @see parse()
+    * 
+    */
+    
+    var $regex =  "/'''(()|[^'].*)'''/U";
+    
+    
+    /**
+    * 
+    * Generates a replacement for the matched text.  Token options are:
+    * 
+    * 'type' => ['start'|'end'] The starting or ending point of the
+    * emphasized text.  The text itself is left in the source.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return A pair of delimited tokens to be used as a placeholder in
+    * the source text surrounding the text to be emphasized.
+    *
+    */
+    
+    function process(&$matches)
+    {
+        $start = $this->wiki->addToken($this->rule, array('type' => 'start'));
+        $end = $this->wiki->addToken($this->rule, array('type' => 'end'));
+        return $start . $matches[1] . $end;
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Default/Break.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,72 @@
+<?php
+
+/**
+* 
+* Parses for explicit line breaks.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Break.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Parses for explicit line breaks.
+* 
+* This class implements a Text_Wiki_Parse to mark forced line breaks in the
+* source text.
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Break extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * The regular expression used to parse the source text and find
+    * matches conforming to this rule.  Used by the parse() method.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    * @see parse()
+    * 
+    */
+    
+    var $regex = '/ _\n/';
+    
+    
+    /**
+    * 
+    * Generates a replacement token for the matched text.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return string A delimited token to be used as a placeholder in
+    * the source text.
+    *
+    */
+    
+    function process(&$matches)
+    {    
+        return $this->wiki->addToken($this->rule);
+    }
+}
+
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Default/Center.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,78 @@
+<?php
+
+/**
+* 
+* Parses for centered lines of text.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Center.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Parses for centered lines of text.
+* 
+* This class implements a Text_Wiki_Parse to find lines marked for centering.
+* The line must start with "= " (i.e., an equal-sign followed by a space).
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Center extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * The regular expression used to find source text matching this
+    * rule.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    */
+    
+    var $regex = '/\n\= (.*?)\n/';
+    
+    /**
+    * 
+    * Generates a token entry for the matched text.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return A delimited token number to be used as a placeholder in
+    * the source text.
+    *
+    */
+    
+    function process(&$matches)
+    {
+        $start = $this->wiki->addToken(
+            $this->rule,
+            array('type' => 'start')
+        );
+        
+        $end = $this->wiki->addToken(
+            $this->rule,
+            array('type' => 'end')
+        );
+        
+        return "\n" . $start . $matches[1] . $end . "\n";
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Default/Code.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,99 @@
+<?php
+
+/**
+* 
+* Parses for text marked as a code example block.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Code.php,v 1.10 2006/02/21 14:33:53 toggg Exp $
+* 
+*/
+
+/**
+* 
+* Parses for text marked as a code example block.
+* 
+* This class implements a Text_Wiki_Parse to find sections marked as code
+* examples.  Blocks are marked as the string <code> on a line by itself,
+* followed by the inline code example, and terminated with the string
+* </code> on a line by itself.  The code example is run through the
+* native PHP highlight_string() function to colorize it, then surrounded
+* with <pre>...</pre> tags when rendered as XHTML.
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Code extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * The regular expression used to find source text matching this
+    * rule.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    */
+    
+/*    var $regex = '/^(\<code( .+)?\>)\n(.+)\n(\<\/code\>)(\s|$)/Umsi';*/
+    var $regex = ';^<code(\s[^>]*)?>((?:(?R)|.)*?)\n</code>(\s|$);msi';
+    
+    /**
+    * 
+    * Generates a token entry for the matched text.  Token options are:
+    * 
+    * 'text' => The full matched text, not including the <code></code> tags.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return A delimited token number to be used as a placeholder in
+    * the source text.
+    *
+    */
+    
+    function process(&$matches)
+    {
+        // are there additional attribute arguments?
+        $args = trim($matches[1]);
+        
+        if ($args == '') {
+            $options = array(
+                'text' => $matches[2],
+                'attr' => array('type' => '')
+            );
+        } else {
+        	// get the attributes...
+        	$attr = $this->getAttrs($args);
+        	
+        	// ... and make sure we have a 'type'
+        	if (! isset($attr['type'])) {
+        		$attr['type'] = '';
+        	}
+        	
+        	// retain the options
+            $options = array(
+                'text' => $matches[2],
+                'attr' => $attr
+            );
+        }
+        
+        return $this->wiki->addToken($this->rule, $options) . $matches[3];
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Default/Colortext.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,89 @@
+<?php
+
+/**
+* 
+* Parses for colorized text.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Colortext.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Parses for colorized text.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Colortext extends Text_Wiki_Parse {
+    
+    /**
+    * 
+    * The regular expression used to parse the source text and find
+    * matches conforming to this rule.  Used by the parse() method.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    * @see parse()
+    * 
+    */
+    
+    var $regex = "/\#\#(.+?)\|(.+?)\#\#/";
+    
+    
+    /**
+    * 
+    * Generates a replacement for the matched text.  Token options are:
+    * 
+    * 'type' => ['start'|'end'] The starting or ending point of the
+    * emphasized text.  The text itself is left in the source.
+    * 
+    * 'color' => the color indicator
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return string A pair of delimited tokens to be used as a
+    * placeholder in the source text surrounding the text to be
+    * emphasized.
+    *
+    */
+    
+    function process(&$matches)
+    {
+        $start = $this->wiki->addToken(
+            $this->rule, 
+            array(
+                'type' => 'start',
+                'color' => $matches[1]
+            )
+        );
+        
+        $end = $this->wiki->addToken(
+            $this->rule, 
+            array(
+                'type' => 'end',
+                'color' => $matches[1]
+            )
+        );
+        
+        return $start . $matches[2] . $end;
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Default/Deflist.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,122 @@
+<?php
+
+/**
+* 
+* Parses for definition lists.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Deflist.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Parses for definition lists.
+* 
+* This class implements a Text_Wiki_Parse to find source text marked as a
+* definition list.  In short, if a line starts with ':' then it is a
+* definition list item; another ':' on the same line indicates the end
+* of the definition term and the beginning of the definition narrative.
+* The list items must be on sequential lines (no blank lines between
+* them) -- a blank line indicates the beginning of a new list.
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Deflist extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * The regular expression used to parse the source text and find
+    * matches conforming to this rule.  Used by the parse() method.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    * @see parse()
+    * 
+    */
+    
+    var $regex = '/\n((: ).*\n)(?!(: |\n))/Us';
+    
+    
+    /**
+    * 
+    * Generates a replacement for the matched text.  Token options are:
+    * 
+    * 'type' =>
+    *     'list_start'    : the start of a definition list
+    *     'list_end'      : the end of a definition list
+    *     'term_start'    : the start of a definition term
+    *     'term_end'      : the end of a definition term
+    *     'narr_start'    : the start of definition narrative
+    *     'narr_end'      : the end of definition narrative
+    *     'unknown'       : unknown type of definition portion
+    *
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return A series of text and delimited tokens marking the different
+    * list text and list elements.
+    *
+    */
+    
+    function process(&$matches)
+    {
+        // the replacement text we will return to parse()
+        $return = '';
+        
+        // the list of post-processing matches
+        $list = array();
+        
+        // start the deflist
+        $options = array('type' => 'list_start');
+        $return .= $this->wiki->addToken($this->rule, $options);
+        
+        // $matches[1] is the text matched as a list set by parse();
+        // create an array called $list that contains a new set of
+        // matches for the various definition-list elements.
+        preg_match_all(
+            '/^(: )(.*)?( : )(.*)?$/Ums',
+            $matches[1],
+            $list,
+            PREG_SET_ORDER
+        );
+        
+        // add each term and narrative
+        foreach ($list as $key => $val) {
+            $return .= (
+                $this->wiki->addToken($this->rule, array('type' => 'term_start')) .
+                trim($val[2]) .
+                $this->wiki->addToken($this->rule, array('type' => 'term_end')) .
+                $this->wiki->addToken($this->rule, array('type' => 'narr_start')) .
+                trim($val[4]) . 
+                $this->wiki->addToken($this->rule, array('type' => 'narr_end'))
+            );
+        }
+        
+        
+        // end the deflist
+        $options = array('type' => 'list_end');
+        $return .= $this->wiki->addToken($this->rule, $options);
+        
+        // done!
+        return "\n" . $return . "\n\n";
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Default/Delimiter.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,80 @@
+<?php
+
+/**
+* 
+* Parses for Text_Wiki delimiter characters already in the source text.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Delimiter.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Parses for Text_Wiki delimiter characters already in the source text.
+* 
+* This class implements a Text_Wiki_Parse to find instances of the delimiter
+* character already embedded in the source text; it extracts them and replaces
+* them with a delimited token, then renders them as the delimiter itself
+* when the target format is XHTML.
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Delimiter extends Text_Wiki_Parse {
+    
+    /**
+    * 
+    * Constructor.  Overrides the Text_Wiki_Parse constructor so that we
+    * can set the $regex property dynamically (we need to include the
+    * Text_Wiki $delim character.
+    * 
+    * @param object &$obj The calling "parent" Text_Wiki object.
+    * 
+    * @param string $name The token name to use for this rule.
+    * 
+    */
+    
+    function Text_Wiki_Parse_delimiter(&$obj)
+    {
+        parent::Text_Wiki_Parse($obj);
+        $this->regex = '/' . $this->wiki->delim . '/';
+    }
+    
+    
+    /**
+    * 
+    * Generates a token entry for the matched text.  Token options are:
+    * 
+    * 'text' => The full matched text.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return A delimited token number to be used as a placeholder in
+    * the source text.
+    *
+    */
+    
+    function process(&$matches)
+    {    
+        return $this->wiki->addToken(
+            $this->rule,
+            array('text' => $this->wiki->delim)
+        );
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Default/Embed.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,106 @@
+<?php
+
+/**
+* 
+* Embeds the results of a PHP script at render-time.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Embed.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Embeds the results of a PHP script at render-time.
+* 
+* This class implements a Text_Wiki_Parse to embed the contents of a URL
+* inside the page at render-time.  Typically used to get script output.
+* This differs from the 'include' rule, which incorporates results at
+* parse-time; 'embed' output does not get parsed by Text_Wiki, while
+* 'include' ouput does.
+*
+* This rule is inherently not secure; it allows cross-site scripting to
+* occur if the embedded output has <script> or other similar tags.  Be
+* careful.
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Embed extends Text_Wiki_Parse {
+    
+    var $conf = array(
+        'base' => '/path/to/scripts/'
+    );
+    
+    var $file = null;
+
+    var $output = null;
+
+    var $vars = null;
+
+
+    /**
+    * 
+    * The regular expression used to find source text matching this
+    * rule.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    */
+    
+    var $regex = '/(\[\[embed )(.+?)( .+?)?(\]\])/i';
+    
+    
+    /**
+    * 
+    * Generates a token entry for the matched text.  Token options are:
+    * 
+    * 'text' => The full matched text, not including the <code></code> tags.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return A delimited token number to be used as a placeholder in
+    * the source text.
+    *
+    */
+    
+    function process(&$matches)
+    {    
+        // save the file location
+        $this->file = $this->getConf('base', './') . $matches[2];
+        
+        // extract attribs as variables in the local space
+        $this->vars = $this->getAttrs($matches[3]);
+        unset($this->vars['this']);
+        extract($this->vars);
+        
+        // run the script
+        ob_start();
+        include($this->file);
+        $this->output = ob_get_contents();
+        ob_end_clean();
+        
+        // done, place the script output directly in the source
+        return $this->wiki->addToken(
+            $this->rule,
+            array('text' => $this->output)
+        );
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Default/Emphasis.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,85 @@
+<?php
+
+/**
+* 
+* Parses for emphasized text.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Emphasis.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Parses for emphasized text.
+* 
+* This class implements a Text_Wiki_Parse to find source text marked for
+* emphasis (italics) as defined by text surrounded by two single-quotes.
+* On parsing, the text itself is left in place, but the starting and ending
+* instances of two single-quotes are replaced with tokens.
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_emphasis extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * The regular expression used to parse the source text and find
+    * matches conforming to this rule.  Used by the parse() method.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    * @see parse()
+    * 
+    */
+    
+    var $regex = "/\/\/(.*?)\/\//";
+    
+    
+    /**
+    * 
+    * Generates a replacement for the matched text.  Token options are:
+    * 
+    * 'type' => ['start'|'end'] The starting or ending point of the
+    * emphasized text.  The text itself is left in the source.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return string A pair of delimited tokens to be used as a
+    * placeholder in the source text surrounding the text to be
+    * emphasized.
+    *
+    */
+    
+    function process(&$matches)
+    {
+        $start = $this->wiki->addToken(
+            $this->rule, array('type' => 'start')
+        );
+        
+        $end = $this->wiki->addToken(
+            $this->rule, array('type' => 'end')
+        );
+        
+        return $start . $matches[1] . $end;
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Default/Freelink.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,127 @@
+<?php
+
+/**
+* 
+* Parses for wiki freelink text.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Freelink.php,v 1.4 2005/10/19 23:43:53 toggg Exp $
+* 
+*/
+
+/**
+* 
+* Parses for freelinked page links.
+* 
+* This class implements a Text_Wiki_Parse to find source text marked as a
+* wiki freelink, and automatically create a link to that page.
+* 
+* A freelink is any page name not conforming to the standard
+* StudlyCapsStyle for a wiki page name.  For example, a page normally
+* named MyHomePage can be renamed and referred to as ((My Home Page)) --
+* note the spaces in the page name.  You can also make a "nice-looking"
+* link without renaming the target page; e.g., ((MyHomePage|My Home
+* Page)).  Finally, you can use named anchors on the target page:
+* ((MyHomePage|My Home Page#Section1)).
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Freelink extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * Constructor.  We override the Text_Wiki_Parse constructor so we can
+    * explicitly comment each part of the $regex property.
+    * 
+    * @access public
+    * 
+    * @param object &$obj The calling "parent" Text_Wiki object.
+    * 
+    */
+    
+    function Text_Wiki_Parse_Freelink(&$obj)
+    {
+        parent::Text_Wiki_Parse($obj);
+        
+        $this->regex =
+            '/' .                                                   // START regex
+            "\\(\\(" .                                               // double open-parens
+            "(" .                                                   // START freelink page patter
+            "[-A-Za-z0-9 _+\\/.,;:!?'\"\\[\\]\\{\\}&\xc0-\xff]+" . // 1 or more of just about any character
+            ")" .                                                   // END  freelink page pattern
+            "(" .                                                   // START display-name
+            "\|" .                                                   // a pipe to start the display name
+            "[-A-Za-z0-9 _+\\/.,;:!?'\"\\[\\]\\{\\}&\xc0-\xff]+" . // 1 or more of just about any character
+            ")?" .                                                   // END display-name pattern 0 or 1
+            "(" .                                                   // START pattern for named anchors
+            "\#" .                                                   // a hash mark
+            "[A-Za-z]" .                                           // 1 alpha
+            "[-A-Za-z0-9_:.]*" .                                   // 0 or more alpha, digit, underscore
+            ")?" .                                                   // END named anchors pattern 0 or 1
+            "()\\)\\)" .                                           // double close-parens
+            '/';                                                   // END regex
+    }
+    
+    
+    /**
+    * 
+    * Generates a replacement for the matched text.  Token options are:
+    * 
+    * 'page' => the wiki page name (e.g., HomePage).
+    * 
+    * 'text' => alternative text to be displayed in place of the wiki
+    * page name.
+    * 
+    * 'anchor' => a named anchor on the target wiki page
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return A delimited token to be used as a placeholder in
+    * the source text, plus any text priot to the match.
+    *
+    */
+    
+    function process(&$matches)
+    {
+        // use nice variable names
+        $page = $matches[1];
+        $text = $matches[2];
+        $anchor = $matches[3];
+        
+        // is the page given a new text appearance?
+        if (trim($text) == '') {
+            // no
+            $text = $page;
+        } else {
+            // yes, strip the leading | character
+            $text = substr($text, 1);
+        }
+        
+        // set the options
+        $options = array(
+            'page'   => $page,
+            'text'   => $text,
+            'anchor' => $anchor
+        );
+        
+        // return a token placeholder
+        return $this->wiki->addToken($this->rule, $options);
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Default/Function.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,141 @@
+<?php
+
+/**
+* 
+* Parses for an API function documentation block.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Function.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Parses for an API function documentation block.
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Function extends Text_Wiki_Parse {
+
+    var $regex = '/^(\<function\>)\n(.+)\n(\<\/function\>)(\s|$)/Umsi';
+    
+    function process(&$matches)
+    {
+        // default options
+        $opts = array(
+            'name' => null,
+            'access' => null,
+            'return' => null,
+            'params' => array(),
+            'throws' => array()
+        );
+        
+        // split apart the markup lines and loop through them
+        $lines = explode("\n", $matches[2]);
+        foreach ($lines as $line) {
+            
+            // skip blank lines
+            if (trim($line) == '') {
+                continue;
+            }
+            
+            // find the first ':' on the line; the left part is the 
+            // type, the right part is the value. skip lines without
+            // a ':' on them.
+            $pos = strpos($line, ':');
+            if ($pos === false) {
+                continue;
+            }
+            
+            // $type is the line type: name, access, return, param, throws
+            // 012345678901234
+            // name: something
+            $type = trim(substr($line, 0, $pos));
+            $val = trim(substr($line, $pos+1));
+            
+            switch($type) {
+            
+            case 'a':
+            case 'access':
+                $opts['access'] = $val;
+                break;
+                
+            case 'n':
+            case 'name':
+                $opts['name'] = $val;
+                break;
+                
+            case 'p':
+            case 'param':
+                $tmp = explode(',', $val);
+                $k = count($tmp);
+                if ($k == 1) {
+                    $opts['params'][] = array(
+                        'type' => $tmp[0],
+                        'descr' => null,
+                        'default' => null
+                    );
+                } elseif ($k == 2) {
+                    $opts['params'][] = array(
+                        'type' => $tmp[0],
+                        'descr' => $tmp[1],
+                        'default' => null
+                    );
+                } else {
+                    $opts['params'][] = array(
+                        'type' => $tmp[0],
+                        'descr' => $tmp[1],
+                        'default' => $tmp[2]
+                    );
+                }
+                break;
+            
+            case 'r':
+            case 'return':
+            case 'returns':
+                $opts['return'] = $val;
+                break;
+            
+            case 't':
+            case 'throws':
+                $tmp = explode(',', $val);
+                $k = count($tmp);
+                if ($k == 1) {
+                    $opts['throws'][] = array(
+                        'type' => $tmp[0],
+                        'descr' => null
+                    );
+                } else {
+                    $opts['throws'][] = array(
+                        'type' => $tmp[0],
+                        'descr' => $tmp[1]
+                    );
+                }
+                break;
+        
+            default:
+                $opts[$type] = $val;
+                break;
+            
+            }
+        }
+        
+        // add the token back in place
+        return $this->wiki->addToken($this->rule, $opts) . $matches[4];
+    }
+}
+
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Default/Heading.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,107 @@
+<?php
+
+/**
+* 
+* Parses for heading text.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Heading.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Parses for heading text.
+* 
+* This class implements a Text_Wiki_Parse to find source text marked to
+* be a heading element, as defined by text on a line by itself prefixed
+* with a number of plus signs (+). The heading text itself is left in
+* the source, but is prefixed and suffixed with delimited tokens marking
+* the start and end of the heading.
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Heading extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * The regular expression used to parse the source text and find
+    * matches conforming to this rule.  Used by the parse() method.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    * @see parse()
+    * 
+    */
+    
+    var $regex = '/^(\+{1,6}) (.*)/m';
+    
+    var $conf = array(
+        'id_prefix' => 'toc'
+    );
+    
+    /**
+    * 
+    * Generates a replacement for the matched text.  Token options are:
+    * 
+    * 'type' => ['start'|'end'] The starting or ending point of the
+    * heading text.  The text itself is left in the source.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return string A pair of delimited tokens to be used as a
+    * placeholder in the source text surrounding the heading text.
+    *
+    */
+    
+    function process(&$matches)
+    {
+        // keep a running count for header IDs.  we use this later
+        // when constructing TOC entries, etc.
+        static $id;
+        if (! isset($id)) {
+            $id = 0;
+        }
+        
+        $prefix = htmlspecialchars($this->getConf('id_prefix'));
+        
+        $start = $this->wiki->addToken(
+            $this->rule, 
+            array(
+                'type' => 'start',
+                'level' => strlen($matches[1]),
+                'text' => $matches[2],
+                'id' => $prefix . $id ++
+            )
+        );
+        
+        $end = $this->wiki->addToken(
+            $this->rule, 
+            array(
+                'type' => 'end',
+                'level' => strlen($matches[1])
+            )
+        );
+        
+        return $start . $matches[2] . $end . "\n";
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Default/Horiz.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,70 @@
+<?php
+
+/**
+* 
+* Parses for horizontal ruling lines.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Horiz.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Parses for horizontal ruling lines.
+* 
+* This class implements a Text_Wiki_Parse to find source text marked to
+* be a horizontal rule, as defined by four dashed on their own line.
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Horiz extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * The regular expression used to parse the source text and find
+    * matches conforming to this rule.  Used by the parse() method.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    * @see parse()
+    * 
+    */
+    
+    var $regex = '/^([-]{4,})$/m';
+    
+    
+    /**
+    * 
+    * Generates a replacement token for the matched text.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return string A token marking the horizontal rule.
+    *
+    */
+    
+    function process(&$matches)
+    {    
+        return $this->wiki->addToken($this->rule);
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Default/Html.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,75 @@
+<?php
+
+/**
+* 
+* Parses for blocks of HTML code.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Html.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Parses for blocks of HTML code.
+* 
+* This class implements a Text_Wiki_Parse to find source text marked as
+* HTML to be redndred as-is.  The block start is marked by <html> on its
+* own line, and the block end is marked by </html> on its own line.
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Html extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * The regular expression used to parse the source text and find
+    * matches conforming to this rule.  Used by the parse() method.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    * @see parse()
+    * 
+    */
+    
+    var $regex = '/^\<html\>\n(.+)\n\<\/html\>(\s|$)/Umsi';
+    
+    
+    /**
+    * 
+    * Generates a replacement for the matched text.  Token options are:
+    * 
+    * 'text' => The text of the HTML to be rendered as-is.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return A delimited token to be used as a placeholder in
+    * the source text, plus any text following the HTML block.
+    *
+    */
+    
+    function process(&$matches)
+    {    
+        $options = array('text' => $matches[1]);
+        return $this->wiki->addToken($this->rule, $options) . $matches[2];
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Default/Image.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,136 @@
+<?php
+
+/**
+*
+* Parses for image placement.
+*
+* @category Text
+*
+* @package Text_Wiki
+*
+* @author Paul M. Jones <pmjones@php.net>
+*
+* @license LGPL
+*
+* @version $Id: Image.php,v 1.5 2005/09/12 11:34:44 toggg Exp $
+*
+*/
+
+/**
+*
+* Parses for image placement.
+*
+* @category Text
+*
+* @package Text_Wiki
+*
+* @author Paul M. Jones <pmjones@php.net>
+*
+*/
+
+class Text_Wiki_Parse_Image extends Text_Wiki_Parse {
+
+    /**
+     * URL schemes recognized by this rule.
+     *
+     * @access public
+     * @var array
+    */
+    var $conf = array(
+        'schemes' => 'http|https|ftp|gopher|news',
+        'host_regexp' => '(?:[^.\s/"\'<\\\#delim#\ca-\cz]+\.)*[a-z](?:[-a-z0-9]*[a-z0-9])?\.?',
+        'path_regexp' => '(?:/[^\s"<\\\#delim#\ca-\cz]*)?'
+    );
+
+    /**
+    *
+    * The regular expression used to find source text matching this
+    * rule.
+    *
+    * @access public
+    *
+    * @var string
+    *
+    */
+
+    var $regex = '/(\[\[image\s+)(.+?)(\]\])/i';
+
+
+    /**
+     * The regular expressions used to check ecternal urls
+     *
+     * @access public
+     * @var string
+     * @see parse()
+     */
+    var $url = '';
+
+     /**
+     * Constructor.
+     * We override the constructor to build up the url regex from config
+     *
+     * @param object &$obj the base conversion handler
+     * @return The parser object
+     * @access public
+     */
+    function Text_Wiki_Parse_Image(&$obj)
+    {
+        $default = $this->conf;
+        parent::Text_Wiki_Parse($obj);
+
+        // convert the list of recognized schemes to a regex OR,
+        $schemes = $this->getConf('schemes', $default['schemes']);
+        $this->url = str_replace( '#delim#', $this->wiki->delim,
+           '#(?:' . (is_array($schemes) ? implode('|', $schemes) : $schemes) . ')://'
+           . $this->getConf('host_regexp', $default['host_regexp'])
+           . $this->getConf('path_regexp', $default['path_regexp']) .'#');
+    }
+
+    /**
+    *
+    * Generates a token entry for the matched text.  Token options are:
+    *
+    * 'src' => The image source, typically a relative path name.
+    *
+    * 'opts' => Any macro options following the source.
+    *
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return A delimited token number to be used as a placeholder in
+    * the source text.
+    *
+    */
+
+    function process(&$matches)
+    {
+        $pos = strpos($matches[2], ' ');
+
+        if ($pos === false) {
+            $options = array(
+                'src' => $matches[2],
+                'attr' => array());
+        } else {
+            // everything after the space is attribute arguments
+            $options = array(
+                'src' => substr($matches[2], 0, $pos),
+                'attr' => $this->getAttrs(substr($matches[2], $pos+1))
+            );
+            // check the scheme case of external link
+            if (array_key_exists('link', $options['attr'])) {
+                // external url ?
+                if (($pos = strpos($options['attr']['link'], '://')) !== false) {
+                    if (!preg_match($this->url, $options['attr']['link'])) {
+                        return $matches[0];
+                    }
+                } elseif (in_array('Wikilink', $this->wiki->disable)) {
+                        return $matches[0]; // Wikilink disabled
+                }
+            }
+        }
+
+        return $this->wiki->addToken($this->rule, $options);
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Default/Include.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,100 @@
+<?php
+
+/**
+* 
+* Includes the contents of another PHP script into the source text.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Include.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* This class implements a Text_Wiki_Parse to include the results of a
+* script directly into the source at parse-time; thus, the output of the
+* script will be parsed by Text_Wiki.  This differs from the 'embed'
+* rule, which incorporates the results at render-time, meaning that the
+* 'embed' content is not parsed by Text_Wiki.
+*
+* DANGER!
+* 
+* This rule is inherently not secure; it allows cross-site scripting to
+* occur if the embedded output has <script> or other similar tags.  Be
+* careful.
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Include extends Text_Wiki_Parse {
+    
+    var $conf = array(
+        'base' => '/path/to/scripts/'
+    );
+    
+    var $file = null;
+    
+    var $output = null;
+    
+    var $vars = null;
+
+    /**
+    * 
+    * The regular expression used to find source text matching this
+    * rule.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    */
+    
+    var $regex = '/(\[\[include )(.+?)( .+?)?(\]\])/i';
+    
+    
+    /**
+    * 
+    * Includes the results of the script directly into the source; the output
+    * will subsequently be parsed by the remaining Text_Wiki rules.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return The results of the included script.
+    *
+    */
+    
+    function process(&$matches)
+    {
+        // save the file location
+        $this->file = $this->getConf('base', './') . $matches[2];
+
+        // extract attribs as variables in the local space
+        $this->vars = $this->getAttrs($matches[3]);
+        unset($this->vars['this']);
+        extract($this->vars);
+
+        // run the script
+        ob_start();
+        include($this->file);
+        $this->output = ob_get_contents();
+        ob_end_clean();
+    
+        // done, place the script output directly in the source
+        return $this->output;
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Default/Interwiki.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,138 @@
+<?php
+
+/**
+* 
+* Parses for interwiki links.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Interwiki.php,v 1.4 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Parses for interwiki links.
+* 
+* This class implements a Text_Wiki_Parse to find source text marked as
+* an Interwiki link.  See the regex for a detailed explanation of the
+* text matching procedure; e.g., "InterWikiName:PageName".
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Interwiki extends Text_Wiki_Parse {
+    
+    // double-colons wont trip up now
+    var $regex = '([A-Za-z0-9_]+):((?!:)[A-Za-z0-9_\/=&~#.:;-]+)';
+    
+    
+    /**
+    * 
+    * Parser.  We override the standard parser so we can
+    * find both described interwiki links and standalone links.
+    * 
+    * @access public
+    * 
+    * @return void
+    * 
+    */
+    
+    function parse()
+    {
+        // described interwiki links
+        $tmp_regex = '/\[' . $this->regex . ' (.+?)\]/';
+        $this->wiki->source = preg_replace_callback(
+            $tmp_regex,
+            array(&$this, 'processDescr'),
+            $this->wiki->source
+        );
+        
+        // standalone interwiki links
+        $tmp_regex = '/' . $this->regex . '/';
+        $this->wiki->source = preg_replace_callback(
+            $tmp_regex,
+            array(&$this, 'process'),
+            $this->wiki->source
+        );
+       
+    }
+    
+    
+    /**
+    * 
+    * Generates a replacement for the matched standalone interwiki text.
+    * Token options are:
+    * 
+    * 'site' => The key name for the Text_Wiki interwiki array map,
+    * usually the name of the interwiki site.
+    * 
+    * 'page' => The page on the target interwiki to link to.
+    * 
+    * 'text' => The text to display as the link.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return A delimited token to be used as a placeholder in
+    * the source text, plus any text priot to the match.
+    *
+    */
+    
+    function process(&$matches)
+    {
+        $options = array(
+            'site' => $matches[1],
+            'page' => $matches[2],
+            'text' => $matches[0]
+        );
+        
+        return $this->wiki->addToken($this->rule, $options);
+    }
+    
+    
+    /**
+    * 
+    * Generates a replacement for described interwiki links. Token
+    * options are:
+    * 
+    * 'site' => The key name for the Text_Wiki interwiki array map,
+    * usually the name of the interwiki site.
+    * 
+    * 'page' => The page on the target interwiki to link to.
+    * 
+    * 'text' => The text to display as the link.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return A delimited token to be used as a placeholder in
+    * the source text, plus any text priot to the match.
+    *
+    */
+    
+    function processDescr(&$matches)
+    {
+        $options = array(
+            'site' => $matches[1],
+            'page' => $matches[2],
+            'text' => $matches[3]
+        );
+        
+        return $this->wiki->addToken($this->rule, $options);
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Default/Italic.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,85 @@
+<?php
+
+/**
+* 
+* Parses for italic text.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Italic.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Parses for italic text.
+* 
+* This class implements a Text_Wiki_Parse to find source text marked for
+* emphasis (italics) as defined by text surrounded by two single-quotes.
+* On parsing, the text itself is left in place, but the starting and ending
+* instances of two single-quotes are replaced with tokens.
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Italic extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * The regular expression used to parse the source text and find
+    * matches conforming to this rule.  Used by the parse() method.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    * @see parse()
+    * 
+    */
+    
+    var $regex = "/''(()|[^'].*)''/U";
+    
+    
+    /**
+    * 
+    * Generates a replacement for the matched text.  Token options are:
+    * 
+    * 'type' => ['start'|'end'] The starting or ending point of the
+    * emphasized text.  The text itself is left in the source.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return string A pair of delimited tokens to be used as a
+    * placeholder in the source text surrounding the text to be
+    * emphasized.
+    *
+    */
+    
+    function process(&$matches)
+    {
+        $start = $this->wiki->addToken(
+            $this->rule, array('type' => 'start')
+        );
+        
+        $end = $this->wiki->addToken(
+            $this->rule, array('type' => 'end')
+        );
+        
+        return $start . $matches[1] . $end;
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Default/List.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,248 @@
+<?php
+
+/**
+*
+* Parses for bulleted and numbered lists.
+*
+* @category Text
+*
+* @package Text_Wiki
+*
+* @author Paul M. Jones <pmjones@php.net>
+*
+* @license LGPL
+*
+* @version $Id: List.php,v 1.7 2005/11/06 20:44:09 toggg Exp $
+*
+*/
+
+/**
+*
+* Parses for bulleted and numbered lists.
+*
+* This class implements a Text_Wiki_Parse to find source text marked as
+* a bulleted or numbered list.  In short, if a line starts with '* ' then
+* it is a bullet list item; if a line starts with '# ' then it is a
+* number list item.  Spaces in front of the * or # indicate an indented
+* sub-list.  The list items must be on sequential lines, and may be
+* separated by blank lines to improve readability.  Using a non-* non-#
+* non-whitespace character at the beginning of a line ends the list.
+*
+* @category Text
+*
+* @package Text_Wiki
+*
+* @author Paul M. Jones <pmjones@php.net>
+*
+*/
+
+class Text_Wiki_Parse_List extends Text_Wiki_Parse {
+
+
+    /**
+    *
+    * The regular expression used to parse the source text and find
+    * matches conforming to this rule.  Used by the parse() method.
+    *
+    * @access public
+    *
+    * @var string
+    *
+    * @see parse()
+    *
+    */
+
+    var $regex = '/^((\*|#) .*\n)(?!\2 |(?: {1,}((?:\*|#) |\n)))/Usm';
+
+
+    /**
+    *
+    * Generates a replacement for the matched text.  Token options are:
+    *
+    * 'type' =>
+    *     'bullet_start' : the start of a bullet list
+    *     'bullet_end'   : the end of a bullet list
+    *     'number_start' : the start of a number list
+    *     'number_end'   : the end of a number list
+    *     'item_start'   : the start of item text (bullet or number)
+    *     'item_end'     : the end of item text (bullet or number)
+    *     'unknown'      : unknown type of list or item
+    *
+    * 'level' => the indent level (0 for the first level, 1 for the
+    * second, etc)
+    *
+    * 'count' => the list item number at this level. not needed for
+    * xhtml, but very useful for PDF and RTF.
+    *
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return A series of text and delimited tokens marking the different
+    * list text and list elements.
+    *
+    */
+
+    function process(&$matches)
+    {
+        // the replacement text we will return
+        $return = '';
+
+        // the list of post-processing matches
+        $list = array();
+
+        // a stack of list-start and list-end types; we keep this
+        // so that we know what kind of list we're working with
+        // (bullet or number) and what indent level we're at.
+        $stack = array();
+
+        // the item count is the number of list items for any
+        // given list-type on the stack
+        $itemcount = array();
+
+        // have we processed the very first list item?
+        $pastFirst = false;
+
+        // populate $list with this set of matches. $matches[1] is the
+        // text matched as a list set by parse().
+        preg_match_all(
+            '=^( {0,})(\*|#) (.*)$=Ums',
+            $matches[1],
+            $list,
+            PREG_SET_ORDER
+        );
+
+        // loop through each list-item element.
+        foreach ($list as $key => $val) {
+
+            // $val[0] is the full matched list-item line
+            // $val[1] is the number of initial spaces (indent level)
+            // $val[2] is the list item type (* or #)
+            // $val[3] is the list item text
+
+            // how many levels are we indented? (1 means the "root"
+            // list level, no indenting.)
+            $level = strlen($val[1]) + 1;
+
+            // get the list item type
+            if ($val[2] == '*') {
+                $type = 'bullet';
+            } elseif ($val[2] == '#') {
+                $type = 'number';
+            } else {
+                $type = 'unknown';
+            }
+
+            // get the text of the list item
+            $text = $val[3];
+
+            // add a level to the list?
+            if ($level > count($stack)) {
+
+                // the current indent level is greater than the
+                // number of stack elements, so we must be starting
+                // a new list.  push the new list type onto the
+                // stack...
+                array_push($stack, $type);
+
+                // ...and add a list-start token to the return.
+                $return .= $this->wiki->addToken(
+                    $this->rule,
+                    array(
+                        'type' => $type . '_list_start',
+                        'level' => $level - 1
+                    )
+                );
+            }
+
+            // remove a level from the list?
+            while (count($stack) > $level) {
+
+                // so we don't keep counting the stack, we set up a temp
+                // var for the count.  -1 becuase we're going to pop the
+                // stack in the next command.  $tmp will then equal the
+                // current level of indent.
+                $tmp = count($stack) - 1;
+
+                // as long as the stack count is greater than the
+                // current indent level, we need to end list types.
+                // continue adding end-list tokens until the stack count
+                // and the indent level are the same.
+                $return .= $this->wiki->addToken(
+                    $this->rule,
+                    array (
+                        'type' => array_pop($stack) . '_list_end',
+                        'level' => $tmp
+                    )
+                );
+
+                // reset to the current (previous) list type so that
+                // the new list item matches the proper list type.
+                $type = $stack[$tmp - 1];
+
+                // reset the item count for the popped indent level
+                unset($itemcount[$tmp + 1]);
+            }
+
+            // add to the item count for this list (taking into account
+            // which level we are at).
+            if (! isset($itemcount[$level])) {
+                // first count
+                $itemcount[$level] = 0;
+            } else {
+                // increment count
+                $itemcount[$level]++;
+            }
+
+            // is this the very first item in the list?
+            if (! $pastFirst) {
+                $first = true;
+                $pastFirst = true;
+            } else {
+                $first = false;
+            }
+
+            // create a list-item starting token.
+            $start = $this->wiki->addToken(
+                $this->rule,
+                array(
+                    'type' => $type . '_item_start',
+                    'level' => $level,
+                    'count' => $itemcount[$level],
+                    'first' => $first
+                )
+            );
+
+            // create a list-item ending token.
+            $end = $this->wiki->addToken(
+                $this->rule,
+                array(
+                    'type' => $type . '_item_end',
+                    'level' => $level,
+                    'count' => $itemcount[$level]
+                )
+            );
+
+            // add the starting token, list-item text, and ending token
+            // to the return.
+            $return .= $start . $val[3] . $end;
+        }
+
+        // the last list-item may have been indented.  go through the
+        // list-type stack and create end-list tokens until the stack
+        // is empty.
+        while (count($stack) > 0) {
+            $return .= $this->wiki->addToken(
+                $this->rule,
+                array (
+                    'type' => array_pop($stack) . '_list_end',
+                    'level' => count($stack)
+                )
+            );
+        }
+
+        // we're done!  send back the replacement text.
+        return "\n\n" . $return . "\n\n";
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Default/Newline.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,75 @@
+<?php
+
+/**
+* 
+* Parses for implied line breaks indicated by newlines.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Newline.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Parses for implied line breaks indicated by newlines.
+* 
+* This class implements a Text_Wiki_Parse to mark implied line breaks in the
+* source text, usually a single carriage return in the middle of a paragraph
+* or block-quoted text.
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Newline extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * The regular expression used to parse the source text and find
+    * matches conforming to this rule.  Used by the parse() method.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    * @see parse()
+    * 
+    */
+    
+    var $regex = '/([^\n])\n([^\n])/m';
+    
+    
+    /**
+    * 
+    * Generates a replacement token for the matched text.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return string A delimited token to be used as a placeholder in
+    * the source text.
+    *
+    */
+    
+    function process(&$matches)
+    {    
+        return $matches[1] .
+            $this->wiki->addToken($this->rule) .
+            $matches[2];
+    }
+}
+
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Default/Paragraph.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,146 @@
+<?php
+
+/**
+* 
+* Parses for paragraph blocks.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Paragraph.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Parses for paragraph blocks.
+* 
+* This class implements a Text_Wiki rule to find sections of the source
+* text that are paragraphs.  A para is any line not starting with a token
+* delimiter, followed by two newlines.
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Paragraph extends Text_Wiki_Parse {
+    
+    /**
+    * 
+    * The regular expression used to find source text matching this
+    * rule.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    */
+    
+    var $regex = "/^.*?\n\n/m";
+    
+    var $conf = array(
+        'skip' => array(
+            'blockquote', // are we sure about this one?
+            'code',
+            'heading',
+            'horiz',
+            'deflist',
+            'table',
+            'list',
+            'toc'
+        )
+    );
+    
+    
+    /**
+    * 
+    * Generates a token entry for the matched text.  Token options are:
+    * 
+    * 'start' => The starting point of the paragraph.
+    * 
+    * 'end' => The ending point of the paragraph.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return A delimited token number to be used as a placeholder in
+    * the source text.
+    *
+    */
+    
+    function process(&$matches)
+    {
+        $delim = $this->wiki->delim;
+        
+        // was anything there?
+        if (trim($matches[0]) == '') {
+            return '';
+        }
+        
+        // does the match start with a delimiter?
+        if (substr($matches[0], 0, 1) != $delim) { 
+            // no.
+            
+            $start = $this->wiki->addToken(
+                $this->rule, array('type' => 'start')
+            );
+            
+            $end = $this->wiki->addToken(
+                $this->rule, array('type' => 'end')
+            );
+            
+            return $start . trim($matches[0]) . $end;
+        }
+        
+        // the line starts with a delimiter.  read in the delimited
+        // token number, check the token, and see if we should
+        // skip it.
+        
+        // loop starting at the second character (we already know
+        // the first is a delimiter) until we find another
+        // delimiter; the text between them is a token key number.
+        $key = '';
+        $len = strlen($matches[0]);
+        for ($i = 1; $i < $len; $i++) {
+            $char = $matches[0]{$i};
+            if ($char == $delim) {
+                break;
+            } else {
+                $key .= $char;
+            }
+        }
+        
+        // look at the token and see if it's skippable (if we skip,
+        // it will not be marked as a paragraph)
+        $token_type = strtolower($this->wiki->tokens[$key][0]);
+        $skip = $this->getConf('skip', array());
+        
+        if (in_array($token_type, $skip)) {
+            // this type of token should not have paragraphs applied to it.
+            // return the entire matched text.
+            return $matches[0];
+        } else {
+            
+            $start = $this->wiki->addToken(
+                $this->rule, array('type' => 'start')
+            );
+            
+            $end = $this->wiki->addToken(
+                $this->rule, array('type' => 'end')
+            );
+            
+            return $start . trim($matches[0]) . $end;
+        }
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Default/Phplookup.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,73 @@
+<?php
+
+/**
+* 
+* Find source text marked for lookup in the PHP online manual.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Phplookup.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Find source text marked for lookup in the PHP online manual.
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Phplookup extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * The regular expression used to parse the source text and find
+    * matches conforming to this rule.  Used by the parse() method.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    * @see parse()
+    * 
+    */
+    
+    var $regex = "/\[\[php (.+?)\]\]/";
+    
+    
+    /**
+    * 
+    * Generates a replacement for the matched text.  Token options are:
+    * 
+    * 'type' => ['start'|'end'] The starting or ending point of the
+    * teletype text.  The text itself is left in the source.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return string A pair of delimited tokens to be used as a
+    * placeholder in the source text surrounding the teletype text.
+    *
+    */
+    
+    function process(&$matches)
+    {
+        return $this->wiki->addToken(
+            $this->rule, array('text' => $matches[1])
+        );
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Default/Prefilter.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,78 @@
+<?php
+
+/**
+* 
+* "Pre-filter" the source text.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Prefilter.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* "Pre-filter" the source text.
+* 
+* Convert DOS and Mac line endings to Unix, concat lines ending in a
+* backslash \ with the next line, convert tabs to 4-spaces, add newlines
+* to the top and end of the source text, compress 3 or more newlines to
+* 2 newlines.
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Prefilter extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * Simple parsing method.
+    *
+    * @access public
+    * 
+    */
+    
+    function parse()
+    {
+        // convert DOS line endings
+        $this->wiki->source = str_replace("\r\n", "\n",
+            $this->wiki->source);
+        
+        // convert Macintosh line endings
+        $this->wiki->source = str_replace("\r", "\n",
+            $this->wiki->source);
+        
+        // concat lines ending in a backslash
+        $this->wiki->source = str_replace("\\\n", "",
+            $this->wiki->source);
+        
+        // convert tabs to four-spaces
+        $this->wiki->source = str_replace("\t", "    ",
+            $this->wiki->source);
+           
+        // add extra newlines at the top and end; this
+        // seems to help many rules.
+        $this->wiki->source = "\n" . $this->wiki->source . "\n\n";
+        
+        // finally, compress all instances of 3 or more newlines
+        // down to two newlines.
+        $find = "/\n{3,}/m";
+        $replace = "\n\n";
+        $this->wiki->source = preg_replace($find, $replace,
+            $this->wiki->source);
+    }
+
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Default/Raw.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,73 @@
+<?php
+
+/**
+* 
+* Parses for text marked as "raw" (i.e., to be rendered as-is).
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Raw.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Parses for text marked as "raw" (i.e., to be rendered as-is).
+* 
+* This class implements a Text_Wiki rule to find sections of the source
+* text that are not to be processed by Text_Wiki.  These blocks of "raw"
+* text will be rendered as they were found.
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Raw extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * The regular expression used to find source text matching this
+    * rule.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    */
+    
+    var $regex = "/``(.*)``/U";
+    
+    
+    /**
+    * 
+    * Generates a token entry for the matched text.  Token options are:
+    * 
+    * 'text' => The full matched text.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return A delimited token number to be used as a placeholder in
+    * the source text.
+    *
+    */
+    
+    function process(&$matches)
+    {
+        $options = array('text' => $matches[1]);
+        return $this->wiki->addToken($this->rule, $options);
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Default/Revise.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,145 @@
+<?php
+
+/**
+* 
+* Parses for text marked as revised (insert/delete).
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Revise.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Parses for text marked as revised (insert/delete).
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Revise extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * The regular expression used to parse the source text and find
+    * matches conforming to this rule.  Used by the parse() method.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    * @see parse()
+    * 
+    */
+    
+    var $regex = "/\@\@({*?.*}*?)\@\@/U";
+    
+    
+    /**
+    * 
+    * Config options.
+    * 
+    * @access public
+    * 
+    * @var array
+    *
+    */
+    
+    var $conf = array(
+        'delmark' => '---',
+        'insmark' => '+++'
+    );
+    
+    
+    /**
+    * 
+    * Generates a replacement for the matched text.  Token options are:
+    * 
+    * 'type' => ['start'|'end'] The starting or ending point of the
+    * inserted text.  The text itself is left in the source.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return string A pair of delimited tokens to be used as a
+    * placeholder in the source text surrounding the teletype text.
+    *
+    */
+    
+    function process(&$matches)
+    {
+        $output = '';
+        $src = $matches[1];
+        $delmark = $this->getConf('delmark'); // ---
+        $insmark = $this->getConf('insmark'); // +++
+        
+        // '---' must be before '+++' (if they both appear)
+        $del = strpos($src, $delmark);
+        $ins = strpos($src, $insmark);
+        
+        // if neither is found, return right away
+        if ($del === false && $ins === false) {
+            return $matches[0];
+        }
+        
+        // handle text to be deleted
+        if ($del !== false) {
+            
+            // move forward to the end of the deletion mark
+            $del += strlen($delmark);
+            
+            if ($ins === false) {
+                // there is no insertion text following
+                $text = substr($src, $del);
+            } else {
+                // there is insertion text following,
+                // mitigate the length
+                $text = substr($src, $del, $ins - $del);
+            }
+            
+            $output .= $this->wiki->addToken(
+                $this->rule, array('type' => 'del_start')
+            );
+            
+            $output .= $text;
+            
+            $output .= $this->wiki->addToken(
+                $this->rule, array('type' => 'del_end')
+            );
+        }
+        
+        // handle text to be inserted
+        if ($ins !== false) {
+            
+            // move forward to the end of the insert mark
+            $ins += strlen($insmark);
+            $text = substr($src, $ins);
+            
+            $output .= $this->wiki->addToken(
+                $this->rule, array('type' => 'ins_start')
+            );
+            
+            $output .= $text;
+            
+            $output .= $this->wiki->addToken(
+                $this->rule, array('type' => 'ins_end')
+            );
+        }
+        
+        return $output;
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Default/Smiley.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,157 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Default: Parses for smileys / emoticons tags
+ *
+ * This class implements a Text_Wiki_Rule to find source text marked as
+ * smileys defined by symbols as ':)' , ':-)' or ':smile:'
+ * The symbol is replaced with a token.
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Bertrand Gugger <bertrand@toggg.com>
+ * @copyright  2005 bertrand Gugger
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Smiley.php,v 1.6 2005/10/04 08:17:51 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * Smiley rule parser class for Default.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Bertrand Gugger <bertrand@toggg.com>
+ * @copyright  2005 bertrand Gugger
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ * @see        Text_Wiki_Parse::Text_Wiki_Parse()
+ */
+class Text_Wiki_Parse_Smiley extends Text_Wiki_Parse {
+
+    /**
+     * Configuration keys for this rule
+     * 'smileys' => array Smileys recognized by this rule, symbols key definitions:
+     *              'symbol' => array ( 'name', 'description' [, 'variante', ...] ) as
+     *                  ':)'  => array('smile', 'Smile'),
+     *                  ':D'  => array('biggrin', 'Very Happy',':grin:'),
+     *              the eventual elements after symbol and description are variantes
+     *
+     * 'auto_nose' => boolean enabling the auto nose feature:
+     *                auto build a variante for 2 chars symbols by inserting a '-' as ':)' <=> ':-)'
+     *
+     * @access public
+     * @var array 'config-key' => mixed config-value
+     */
+    var $conf = array(
+        'smileys' => array(
+            ':D'        => array('biggrin', 'Very Happy', ':grin:'),
+            ':)'        => array('smile', 'Smile', '(:'),
+            ':('        => array('sad', 'Sad', '):'),
+            ':o'        => array('surprised', 'Surprised', ':eek:', 'o:'),
+            ':shock:'   => array('eek', 'Shocked'),
+            ':?'        => array('confused', 'Confused', ':???:'),
+            '8)'        => array('cool', 'Cool', '(8'),
+            ':lol:'     => array('lol', 'Laughing'),
+            ':x'        => array('mad', 'Mad'),
+            ':P'        => array('razz', 'Razz'),
+            ':oops:'    => array('redface', 'Embarassed'),
+            ':cry:'     => array('cry', 'Crying or Very sad'),
+            ':evil:'    => array('evil', 'Evil or Very Mad'),
+            ':twisted:' => array('twisted', 'Twisted Evil'),
+            ':roll:'    => array('rolleyes', 'Rolling Eyes'),
+            ';)'        => array('wink', 'Wink', '(;'),
+            ':!:'       => array('exclaim', 'Exclamation'),
+            ':?:'       => array('question', 'Question'),
+            ':idea:'    => array('idea', 'Idea'),
+            ':arrow:'   => array('arrow', 'Arrow'),
+            ':|'        => array('neutral', 'Neutral', '|:'),
+            ':mrgreen:' => array('mrgreen', 'Mr. Green'),
+        ),
+        'auto_nose' => true
+    );
+
+    /**
+     * Definition array of smileys, variantes references their model
+     * 'symbol' => array ( 'name', 'description')
+     *
+     * @access private
+     * @var array 'config-key' => mixed config-value
+     */
+    var $_smileys = array();
+
+     /**
+     * Constructor.
+     * We override the constructor to build up the regex from config
+     *
+     * @param object &$obj the base conversion handler
+     * @return The parser object
+     * @access public
+     */
+    function Text_Wiki_Parse_Smiley(&$obj)
+    {
+        $default = $this->conf;
+        parent::Text_Wiki_Parse($obj);
+
+        // read the list of smileys to sort out variantes and :xxx: while building the regexp
+        $this->_smileys = $this->getConf('smileys', $default['smileys']);
+        $autoNose = $this->getConf('auto_nose', $default['auto_nose']);
+        $reg1 = $reg2 = '';
+        $sep1 = ':(?:';
+        $sep2 = '';
+        foreach ($this->_smileys as $smiley => $def) {
+            for ($i = 1; $i < count($def); $i++) {
+                if ($i > 1) {
+                    $cur = $def[$i];
+                    $this->_smileys[$cur] = &$this->_smileys[$smiley];
+                } else {
+                    $cur = $smiley;
+                }
+                $len = strlen($cur);
+                if (($cur{0} == ':') && ($len > 2) && ($cur{$len - 1} == ':')) {
+                    $reg1 .= $sep1 . preg_quote(substr($cur, 1, -1), '#');
+                    $sep1 = '|';
+                    continue;
+                }
+                if ($autoNose && ($len === 2)) {
+                    $variante = $cur{0} . '-' . $cur{1};
+                    $this->_smileys[$variante] = &$this->_smileys[$smiley];
+                    $cur = preg_quote($cur{0}, '#') . '-?' . preg_quote($cur{1}, '#');
+                } else {
+                    $cur = preg_quote($cur, '#');
+                }
+                $reg2 .= $sep2 . $cur;
+                $sep2 = '|';
+            }
+        }
+        $delim = '[\n\r\s' . $this->wiki->delim . '$^]';
+        $this->regex = '#(?<=' . $delim .
+             ')(' . ($reg1 ? $reg1 . '):' . ($reg2 ? '|' : '') : '') . $reg2 .
+             ')(?=' . $delim . ')#i';
+    }
+
+    /**
+     * Generates a replacement token for the matched text.  Token options are:
+     *     'symbol' => the original marker
+     *     'name' => the name of the smiley
+     *     'desc' => the description of the smiley
+     *
+     * @param array &$matches The array of matches from parse().
+     * @return string Delimited token representing the smiley
+     * @access public
+     */
+    function process(&$matches)
+    {
+        // tokenize
+        return $this->wiki->addToken($this->rule,
+            array(
+                'symbol' => $matches[1],
+                'name'   => $this->_smileys[$matches[1]][0],
+                'desc'   => $this->_smileys[$matches[1]][1]
+            ));
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Default/Strong.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,86 @@
+<?php
+
+/**
+* 
+* Parses for strongly-emphasized text.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Strong.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+
+/**
+* 
+* Parses for strongly-emphasized text.
+* 
+* This class implements a Text_Wiki_Parse to find source text marked for
+* strong emphasis (bold) as defined by text surrounded by three
+* single-quotes. On parsing, the text itself is left in place, but the
+* starting and ending instances of three single-quotes are replaced with
+* tokens.
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Strong extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * The regular expression used to parse the source text and find
+    * matches conforming to this rule.  Used by the parse() method.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    * @see parse()
+    * 
+    */
+    
+    var $regex =  "/\*\*(.*?)\*\*/";
+    
+    
+    /**
+    * 
+    * Generates a replacement for the matched text.  Token options are:
+    * 
+    * 'type' => ['start'|'end'] The starting or ending point of the
+    * emphasized text.  The text itself is left in the source.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return A pair of delimited tokens to be used as a placeholder in
+    * the source text surrounding the text to be emphasized.
+    *
+    */
+    
+    function process(&$matches)
+    {
+        $start = $this->wiki->addToken(
+            $this->rule, array('type' => 'start')
+        );
+        
+        $end = $this->wiki->addToken(
+            $this->rule, array('type' => 'end')
+        );
+        
+        return $start . $matches[1] . $end;
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Default/Subscript.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,79 @@
+<?php
+
+/**
+* 
+* Parses for subscripted text.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Subscript.php,v 1.1 2005/02/24 17:24:56 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Parses for subscripted text.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Subscript extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * The regular expression used to parse the source text and find
+    * matches conforming to this rule.  Used by the parse() method.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    * @see parse()
+    * 
+    */
+    
+    var $regex =  "/,,(()|.*),,/U";
+    
+    
+    /**
+    * 
+    * Generates a replacement for the matched text.  Token options are:
+    * 
+    * 'type' => ['start'|'end'] The starting or ending point of the
+    * emphasized text.  The text itself is left in the source.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return A pair of delimited tokens to be used as a placeholder in
+    * the source text surrounding the text to be emphasized.
+    *
+    */
+    
+    function process(&$matches)
+    {
+        $start = $this->wiki->addToken(
+            $this->rule, array('type' => 'start')
+        );
+        
+        $end = $this->wiki->addToken(
+            $this->rule, array('type' => 'end')
+        );
+        
+        return $start . $matches[1] . $end;
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Default/Superscript.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,79 @@
+<?php
+
+/**
+* 
+* Parses for superscripted text.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Superscript.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Parses for superscripted text.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Superscript extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * The regular expression used to parse the source text and find
+    * matches conforming to this rule.  Used by the parse() method.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    * @see parse()
+    * 
+    */
+    
+    var $regex =  "/\^\^(()|.*)\^\^/U";
+    
+    
+    /**
+    * 
+    * Generates a replacement for the matched text.  Token options are:
+    * 
+    * 'type' => ['start'|'end'] The starting or ending point of the
+    * emphasized text.  The text itself is left in the source.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return A pair of delimited tokens to be used as a placeholder in
+    * the source text surrounding the text to be emphasized.
+    *
+    */
+    
+    function process(&$matches)
+    {
+        $start = $this->wiki->addToken(
+            $this->rule, array('type' => 'start')
+        );
+        
+        $end = $this->wiki->addToken(
+            $this->rule, array('type' => 'end')
+        );
+        
+        return $start . $matches[1] . $end;
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Default/Table.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,226 @@
+<?php
+
+/**
+* 
+* Parses for table markup.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Table.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Parses for table markup.
+* 
+* This class implements a Text_Wiki_Parse to find source text marked as a
+* set of table rows, where a line start and ends with double-pipes (||)
+* and uses double-pipes to separate table cells.  The rows must be on
+* sequential lines (no blank lines between them) -- a blank line
+* indicates the beginning of a new table.
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Table extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * The regular expression used to parse the source text and find
+    * matches conforming to this rule.  Used by the parse() method.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    * @see parse()
+    * 
+    */
+    
+    var $regex = '/\n((\|\|).*)(\n)(?!(\|\|))/Us';
+    
+    
+    /**
+    * 
+    * Generates a replacement for the matched text.
+    * 
+    * Token options are:
+    * 
+    * 'type' =>
+    *     'table_start' : the start of a bullet list
+    *     'table_end'   : the end of a bullet list
+    *     'row_start' : the start of a number list
+    *     'row_end'   : the end of a number list
+    *     'cell_start'   : the start of item text (bullet or number)
+    *     'cell_end'     : the end of item text (bullet or number)
+    * 
+    * 'cols' => the number of columns in the table (for 'table_start')
+    * 
+    * 'rows' => the number of rows in the table (for 'table_start')
+    * 
+    * 'span' => column span (for 'cell_start')
+    * 
+    * 'attr' => column attribute flag (for 'cell_start')
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return A series of text and delimited tokens marking the different
+    * table elements and cell text.
+    *
+    */
+    
+    function process(&$matches)
+    {
+        // our eventual return value
+        $return = '';
+        
+        // the number of columns in the table
+        $num_cols = 0;
+        
+        // the number of rows in the table
+        $num_rows = 0;
+        
+        // rows are separated by newlines in the matched text
+        $rows = explode("\n", $matches[1]);
+        
+        // loop through each row
+        foreach ($rows as $row) {
+            
+            // increase the row count
+            $num_rows ++;
+            
+            // start a new row
+            $return .= $this->wiki->addToken(
+                $this->rule,
+                array('type' => 'row_start')
+            );
+            
+            // cells are separated by double-pipes
+            $cell = explode("||", $row);
+            
+            // get the number of cells (columns) in this row
+            $last = count($cell) - 1;
+            
+            // is this more than the current column count?
+            // (we decrease by 1 because we never use cell zero)
+            if ($last - 1 > $num_cols) {
+                // increase the column count
+                $num_cols = $last - 1;
+            }
+            
+            // by default, cells span only one column (their own)
+            $span = 1;
+            
+            // ignore cell zero, and ignore the "last" cell; cell zero
+            // is before the first double-pipe, and the "last" cell is
+            // after the last double-pipe. both are always empty.
+            for ($i = 1; $i < $last; $i ++) {
+                
+                // if there is no content at all, then it's an instance
+                // of two sets of || next to each other, indicating a
+                // span.
+                if ($cell[$i] == '') {
+                    
+                    // add to the span and loop to the next cell
+                    $span += 1;
+                    continue;
+                    
+                } else {
+                    
+                    // this cell has content.
+                    
+                    // find any special "attr"ibute cell markers
+                    if (substr($cell[$i], 0, 2) == '> ') {
+                        // right-align
+                        $attr = 'right';
+                        $cell[$i] = substr($cell[$i], 2);
+                    } elseif (substr($cell[$i], 0, 2) == '= ') {
+                        // center-align
+                        $attr = 'center';
+                        $cell[$i] = substr($cell[$i], 2);
+                    } elseif (substr($cell[$i], 0, 2) == '< ') {
+                        // left-align
+                        $attr = 'left';
+                        $cell[$i] = substr($cell[$i], 2);
+                    } elseif (substr($cell[$i], 0, 2) == '~ ') {
+                        $attr = 'header';
+                        $cell[$i] = substr($cell[$i], 2);
+                    } else {
+                        $attr = null;
+                    }
+                    
+                    // start a new cell...
+                    $return .= $this->wiki->addToken(
+                        $this->rule, 
+                        array (
+                            'type' => 'cell_start',
+                            'attr' => $attr,
+                            'span' => $span
+                        )
+                    );
+                    
+                    // ...add the content...
+                    $return .= trim($cell[$i]);
+                    
+                    // ...and end the cell.
+                    $return .= $this->wiki->addToken(
+                        $this->rule, 
+                        array (
+                            'type' => 'cell_end',
+                            'attr' => $attr,
+                            'span' => $span
+                        )
+                    );
+                    
+                    // reset the span.
+                    $span = 1;
+                }
+                    
+            }
+            
+            // end the row
+            $return .= $this->wiki->addToken(
+                $this->rule,
+                array('type' => 'row_end')
+            );
+            
+        }
+        
+        // wrap the return value in start and end tokens 
+        $return =
+            $this->wiki->addToken(
+                $this->rule,
+                array(
+                    'type' => 'table_start',
+                    'rows' => $num_rows,
+                    'cols' => $num_cols
+                )
+            )
+            . $return .
+            $this->wiki->addToken(
+                $this->rule,
+                array(
+                    'type' => 'table_end'
+                )
+            );
+        
+        // we're done!
+        return "\n$return\n\n";
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Default/Tighten.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,49 @@
+<?php
+
+/**
+* 
+* The rule removes all remaining newlines.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Tighten.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+
+/**
+* 
+* The rule removes all remaining newlines.
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Tighten extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * Apply tightening directly to the source text.
+    *
+    * @access public
+    * 
+    */
+    
+    function parse()
+    {
+        $this->wiki->source = str_replace("\n", '',
+            $this->wiki->source);
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Default/Toc.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,130 @@
+<?php
+
+/**
+* 
+* Looks through parsed text and builds a table of contents.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Toc.php,v 1.4 2005/05/28 21:33:02 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Looks through parsed text and builds a table of contents.
+* 
+* This class implements a Text_Wiki_Parse to find all heading tokens and
+* build a table of contents.  The [[toc]] tag gets replaced with a list
+* of all the level-2 through level-6 headings.
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+
+class Text_Wiki_Parse_Toc extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * The regular expression used to parse the source text and find
+    * matches conforming to this rule.  Used by the parse() method.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    * @see parse()
+    * 
+    */
+    
+    var $regex = "/\n\[\[toc( .*)?\]\]\n/m";
+    
+    
+    /**
+    * 
+    * Generates a replacement for the matched text.
+    *  
+    * Token options are:
+    * 
+    * 'type' => ['list_start'|'list_end'|'item_start'|'item_end'|'target']
+    *
+    * 'level' => The heading level (1-6).
+    *
+    * 'count' => Which entry number this is in the list.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return string A token indicating the TOC collection point.
+    *
+    */
+    
+    function process(&$matches)
+    {
+        $count = 0;
+        
+        if (isset($matches[1])) {
+            $attr = $this->getAttrs(trim($matches[1]));
+        } else {
+            $attr = array();
+        }
+        
+        $output = $this->wiki->addToken(
+            $this->rule,
+            array(
+                'type' => 'list_start',
+                'level' => 0,
+                'attr' => $attr
+            )
+        );
+        
+        foreach ($this->wiki->getTokens('Heading') as $key => $val) {
+            
+            if ($val[1]['type'] != 'start') {
+                continue;
+            }
+            
+            $options = array(
+                'type'  => 'item_start',
+                'id'    => $val[1]['id'],
+                'level' => $val[1]['level'],
+                'count' => $count ++
+            );
+            
+            $output .= $this->wiki->addToken($this->rule, $options);
+            
+            $output .= $val[1]['text'];
+            
+            $output .= $this->wiki->addToken(
+                $this->rule,
+                array(
+                    'type' => 'item_end',
+                    'level' => $val[1]['level']
+                )
+            );
+        }
+        
+        $output .= $this->wiki->addToken(
+            $this->rule, array(
+                'type' => 'list_end',
+                'level' => 0
+            )
+        );
+        
+        return "\n$output\n";
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Default/Tt.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,84 @@
+<?php
+
+/**
+* 
+* Find source text marked for teletype (monospace).
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Tt.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Find source text marked for teletype (monospace).
+* 
+* Defined by text surrounded by two curly braces. On parsing, the text
+* itself is left in place, but the starting and ending instances of
+* curly braces are replaced with tokens.
+* 
+* Token options are:
+* 
+* 'type' => ['start'|'end'] The starting or ending point of the
+* teletype text.  The text itself is left in the source.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Tt extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * The regular expression used to parse the source text.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    * @see parse()
+    * 
+    */
+    
+    var $regex = "/{{({*?.*}*?)}}/U";
+    
+    
+    /**
+    * 
+    * Generates a replacement for the matched text. 
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return string A pair of delimited tokens to be used as a
+    * placeholder in the source text surrounding the teletype text.
+    *
+    */
+    
+    function process(&$matches)
+    {
+        $start = $this->wiki->addToken(
+            $this->rule, array('type' => 'start')
+        );
+        
+        $end = $this->wiki->addToken(
+            $this->rule, array('type' => 'end')
+        );
+        
+        return $start . $matches[1] . $end;
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Default/Underline.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,79 @@
+<?php
+
+/**
+* 
+* Parses for bold text.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Underline.php,v 1.1 2005/07/10 20:40:20 justinpatrin Exp $
+* 
+*/
+
+/**
+* 
+* Parses for bold text.
+* 
+* This class implements a Text_Wiki_Rule to find source text marked for
+* strong emphasis (bold) as defined by text surrounded by three
+* single-quotes. On parsing, the text itself is left in place, but the
+* starting and ending instances of three single-quotes are replaced with
+* tokens.
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Underline extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * The regular expression used to parse the source text and find
+    * matches conforming to this rule.  Used by the parse() method.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    * @see parse()
+    * 
+    */
+    
+    var $regex =  "/__(()|[^_].*)__/U";
+    
+    
+    /**
+    * 
+    * Generates a replacement for the matched text.  Token options are:
+    * 
+    * 'type' => ['start'|'end'] The starting or ending point of the
+    * emphasized text.  The text itself is left in the source.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return A pair of delimited tokens to be used as a placeholder in
+    * the source text surrounding the text to be emphasized.
+    *
+    */
+    
+    function process(&$matches)
+    {
+        $start = $this->wiki->addToken($this->rule, array('type' => 'start'));
+        $end = $this->wiki->addToken($this->rule, array('type' => 'end'));
+        return $start . $matches[1] . $end;
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Default/Url.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,281 @@
+<?php
+
+/**
+* 
+* Parse for URLS in the source text.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Url.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Parse for URLS in the source text.
+* 
+* Various URL markings are supported: inline (the URL by itself),
+* numbered or footnote reference (where the URL is enclosed in square
+* brackets), and named reference (where the URL is enclosed in square
+* brackets and has a name included inside the brackets).  E.g.:
+*
+* inline    -- http://example.com
+* numbered  -- [http://example.com]
+* described -- [http://example.com Example Description]
+*
+* When rendering a URL token, this will convert URLs pointing to a .gif,
+* .jpg, or .png image into an inline <img /> tag (for the 'xhtml'
+* format).
+*
+* Token options are:
+* 
+* 'type' => ['inline'|'footnote'|'descr'] the type of URL
+* 
+* 'href' => the URL link href portion
+* 
+* 'text' => the displayed text of the URL link
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Url extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * Keeps a running count of numbered-reference URLs.
+    * 
+    * @access public
+    * 
+    * @var int
+    * 
+    */
+    
+    var $footnoteCount = 0;
+    
+    
+    /**
+    * 
+    * URL schemes recognized by this rule.
+    * 
+    * @access public
+    * 
+    * @var array
+    * 
+    */
+    
+    var $conf = array(
+        'schemes' => array(
+            'http://',
+            'https://',
+            'ftp://',
+            'gopher://',
+            'news://',
+            'mailto:'
+        )
+    );
+    
+    
+    /**
+    * 
+    * Constructor.
+    * 
+    * We override the constructor so we can comment the regex nicely.
+    * 
+    * @access public
+    * 
+    */
+    
+    function Text_Wiki_Parse_Url(&$obj)
+    {
+        parent::Text_Wiki_Parse($obj);
+        
+        // convert the list of recognized schemes to a regex-safe string,
+        // where the pattern delim is a slash
+        $tmp = array();
+        $list = $this->getConf('schemes', array());
+        foreach ($list as $val) {
+            $tmp[] = preg_quote($val, '/');
+        }
+        $schemes = implode('|', $tmp);
+        
+        // build the regex
+        $this->regex =
+            "($schemes)" . // allowed schemes
+            "(" . // start pattern
+            "[^ \\/".'"'."\'{$this->wiki->delim}]*\\/" . // no spaces, backslashes, slashes, double-quotes, single quotes, or delimiters;
+            ")*" . // end pattern
+            "[^ \\t\\n\\/".'"'."\'{$this->wiki->delim}]*" .
+            "[A-Za-z0-9\\/?=&~_]";
+    }
+    
+    
+    /**
+    * 
+    * Find three different kinds of URLs in the source text.
+    *
+    * @access public
+    * 
+    */
+    
+    function parse()
+    {
+        // -------------------------------------------------------------
+        // 
+        // Described-reference (named) URLs.
+        // 
+        
+        // the regular expression for this kind of URL
+        $tmp_regex = '/\[(' . $this->regex . ') ([^\]]+)\]/';
+        
+        // use a custom callback processing method to generate
+        // the replacement text for matches.
+        $this->wiki->source = preg_replace_callback(
+            $tmp_regex,
+            array(&$this, 'processDescr'),
+            $this->wiki->source
+        );
+        
+        
+        // -------------------------------------------------------------
+        // 
+        // Numbered-reference (footnote-style) URLs.
+        // 
+        
+        // the regular expression for this kind of URL
+        $tmp_regex = '/\[(' . $this->regex . ')\]/U';
+        
+        // use a custom callback processing method to generate
+        // the replacement text for matches.
+        $this->wiki->source = preg_replace_callback(
+            $tmp_regex,
+            array(&$this, 'processFootnote'),
+            $this->wiki->source
+        );
+        
+        
+        // -------------------------------------------------------------
+        // 
+        // Normal inline URLs.
+        // 
+        
+        // the regular expression for this kind of URL
+        
+        $tmp_regex = '/(^|[^A-Za-z])(' . $this->regex . ')(.*?)/';
+        
+        // use the standard callback for inline URLs
+        $this->wiki->source = preg_replace_callback(
+            $tmp_regex,
+            array(&$this, 'process'),
+            $this->wiki->source
+        );
+    }
+    
+    
+    /**
+    * 
+    * Process inline URLs.
+    * 
+    * @param array &$matches
+    * 
+    * @param array $matches An array of matches from the parse() method
+    * as generated by preg_replace_callback.  $matches[0] is the full
+    * matched string, $matches[1] is the first matched pattern,
+    * $matches[2] is the second matched pattern, and so on.
+    * 
+    * @return string The processed text replacement.
+    * 
+    */ 
+    
+    function process(&$matches)
+    {
+        // set options
+        $options = array(
+            'type' => 'inline',
+            'href' => $matches[2],
+            'text' => $matches[2]
+        );
+        
+        // tokenize
+        return $matches[1] . $this->wiki->addToken($this->rule, $options) . $matches[5];
+    }
+    
+    
+    /**
+    * 
+    * Process numbered (footnote) URLs.
+    * 
+    * Token options are:
+    * @param array &$matches
+    * 
+    * @param array $matches An array of matches from the parse() method
+    * as generated by preg_replace_callback.  $matches[0] is the full
+    * matched string, $matches[1] is the first matched pattern,
+    * $matches[2] is the second matched pattern, and so on.
+    * 
+    * @return string The processed text replacement.
+    * 
+    */ 
+    
+    function processFootnote(&$matches)
+    {
+        // keep a running count for footnotes 
+        $this->footnoteCount++;
+        
+        // set options
+        $options = array(
+            'type' => 'footnote',
+            'href' => $matches[1],
+            'text' => $this->footnoteCount
+        );
+        
+        // tokenize
+        return $this->wiki->addToken($this->rule, $options);
+    }
+    
+    
+    /**
+    * 
+    * Process described-reference (named-reference) URLs.
+    * 
+    * Token options are:
+    *     'type' => ['inline'|'footnote'|'descr'] the type of URL
+    *     'href' => the URL link href portion
+    *     'text' => the displayed text of the URL link
+    * 
+    * @param array &$matches
+    * 
+    * @param array $matches An array of matches from the parse() method
+    * as generated by preg_replace_callback.  $matches[0] is the full
+    * matched string, $matches[1] is the first matched pattern,
+    * $matches[2] is the second matched pattern, and so on.
+    * 
+    * @return string The processed text replacement.
+    * 
+    */ 
+    
+    function processDescr(&$matches)
+    {
+        // set options
+        $options = array(
+            'type' => 'descr',
+            'href' => $matches[1],
+            'text' => $matches[4]
+        );
+        
+        // tokenize
+        return $this->wiki->addToken($this->rule, $options);
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Default/Wikilink.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,197 @@
+<?php
+
+/**
+*
+* Parse for links to wiki pages.
+*
+* @category Text
+*
+* @package Text_Wiki
+*
+* @author Paul M. Jones <pmjones@php.net>
+*
+* @license LGPL
+*
+* @version $Id: Wikilink.php,v 1.5 2005/09/14 14:29:38 toggg Exp $
+*
+*/
+
+/**
+*
+* Parse for links to wiki pages.
+*
+* Wiki page names are typically in StudlyCapsStyle made of
+* WordsSmashedTogether.
+*
+* You can also create described links to pages in this style:
+* [WikiPageName nice text link to use for display]
+*
+* The token options for this rule are:
+*
+* 'page' => the wiki page name.
+*
+* 'text' => the displayed link text.
+*
+* 'anchor' => a named anchor on the target wiki page.
+*
+* @category Text
+*
+* @package Text_Wiki
+*
+* @author Paul M. Jones <pmjones@php.net>
+*
+*/
+
+class Text_Wiki_Parse_Wikilink extends Text_Wiki_Parse {
+
+    var $conf = array (
+    	'ext_chars' => false
+    );
+
+    /**
+    *
+    * Constructor.
+    *
+    * We override the Text_Wiki_Parse constructor so we can
+    * explicitly comment each part of the $regex property.
+    *
+    * @access public
+    *
+    * @param object &$obj The calling "parent" Text_Wiki object.
+    *
+    */
+
+    function Text_Wiki_Parse_Wikilink(&$obj)
+    {
+        parent::Text_Wiki_Parse($obj);
+
+        if ($this->getConf('ext_chars')) {
+        	// use an extended character set; this should
+        	// allow for umlauts and so on.  taken from the
+        	// Tavi project defaults.php file.
+			$upper = "A-Z\xc0-\xde";
+			$lower = "a-z0-9\xdf-\xfe";
+			$either = "A-Za-z0-9\xc0-\xfe";
+		} else {
+			// the default character set, should be fine
+			// for most purposes.
+			$upper = "A-Z";
+			$lower = "a-z0-9";
+			$either = "A-Za-z0-9";
+		}
+
+        // build the regular expression for finding WikiPage names.
+        $this->regex =
+            "(!?" .            // START WikiPage pattern (1)
+            "[$upper]" .       // 1 upper
+            "[$either]*" .     // 0+ alpha or digit
+            "[$lower]+" .      // 1+ lower or digit
+            "[$upper]" .       // 1 upper
+            "[$either]*" .     // 0+ or more alpha or digit
+            ")" .              // END WikiPage pattern (/1)
+            "((\#" .           // START Anchor pattern (2)(3)
+            "[$either]" .      // 1 alpha
+            "(" .              // start sub pattern (4)
+            "[-_$either:.]*" . // 0+ dash, alpha, digit, underscore, colon, dot
+            "[-_$either]" .    // 1 dash, alpha, digit, or underscore
+            ")?)?)";           // end subpatterns (/4)(/3)(/2)
+    }
+
+
+    /**
+    *
+    * First parses for described links, then for standalone links.
+    *
+    * @access public
+    *
+    * @return void
+    *
+    */
+
+    function parse()
+    {
+        // described wiki links
+        $tmp_regex = '/\[' . $this->regex . ' (.+?)\]/';
+        $this->wiki->source = preg_replace_callback(
+            $tmp_regex,
+            array(&$this, 'processDescr'),
+            $this->wiki->source
+        );
+
+        // standalone wiki links
+        if ($this->getConf('ext_chars')) {
+			$either = "A-Za-z0-9\xc0-\xfe";
+		} else {
+			$either = "A-Za-z0-9";
+		}
+
+        $tmp_regex = "/(^|[^{$either}\-_]){$this->regex}/";
+        $this->wiki->source = preg_replace_callback(
+            $tmp_regex,
+            array(&$this, 'process'),
+            $this->wiki->source
+        );
+    }
+
+
+    /**
+    *
+    * Generate a replacement for described links.
+    *
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return A delimited token to be used as a placeholder in
+    * the source text, plus any text priot to the match.
+    *
+    */
+
+    function processDescr(&$matches)
+    {
+        // set the options
+        $options = array(
+            'page'   => $matches[1],
+            'text'   => $matches[5],
+            'anchor' => $matches[3]
+        );
+
+        // create and return the replacement token and preceding text
+        return $this->wiki->addToken($this->rule, $options); // . $matches[7];
+    }
+
+
+    /**
+    *
+    * Generate a replacement for standalone links.
+    *
+    *
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return A delimited token to be used as a placeholder in
+    * the source text, plus any text prior to the match.
+    *
+    */
+
+    function process(&$matches)
+    {
+        // when prefixed with !, it's explicitly not a wiki link.
+        // return everything as it was.
+        if ($matches[2]{0} == '!') {
+            return $matches[1] . substr($matches[2], 1) . $matches[3];
+        }
+
+        // set the options
+        $options = array(
+            'page' => $matches[2],
+            'text' => $matches[2] . $matches[3],
+            'anchor' => $matches[3]
+        );
+
+        // create and return the replacement token and preceding text
+        return $matches[1] . $this->wiki->addToken($this->rule, $options);
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Mediawiki/Anchor.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,87 @@
+<?php
+
+/**
+* 
+* Parses for anchor targets.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Manuel Holtgrewe <purestorm at ggnore dot net>
+*
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Anchor.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* This class implements a Text_Wiki_Parse to add an anchor target name
+* in the wiki page.
+*
+* @author Manuel Holtgrewe <purestorm at ggnore dot net>
+*
+* @author Paul M. Jones <pmjones at ciaweb dot net>
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+*/
+
+class Text_Wiki_Parse_Anchor extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * The regular expression used to find source text matching this
+    * rule.  Looks like a macro: [[# anchor_name]]
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    */
+    
+    var $regex = '/(\[\[# )([-_A-Za-z0-9.]+?)( .+)?(\]\])/i';
+    
+    
+    /**
+    * 
+    * Generates a token entry for the matched text.  Token options are:
+    * 
+    * 'text' => The full matched text, not including the <code></code> tags.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return A delimited token number to be used as a placeholder in
+    * the source text.
+    *
+    */
+    
+    function process(&$matches) {
+    
+        $name = $matches[2];
+        $text = $matches[3];
+        
+        $start = $this->wiki->addToken(
+            $this->rule,
+            array('type' => 'start', 'name' => $name)
+        );
+        
+        $end = $this->wiki->addToken(
+            $this->rule,
+            array('type' => 'end', 'name' => $name)
+        );
+        
+        // done, place the script output directly in the source
+        return $start . trim($text) . $end;
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Mediawiki/Blockquote.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,179 @@
+<?php
+
+/**
+* 
+* Parse for block-quoted text.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Blockquote.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Parse for block-quoted text.
+* 
+* Find source text marked as a blockquote, identified by any number of
+* greater-than signs '>' at the start of the line, followed by a space,
+* and then the quote text; each '>' indicates an additional level of
+* quoting.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Blockquote extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * Regex for parsing the source text.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    * @see parse()
+    * 
+    */
+    
+    var $regex = '/\n((\>).*\n)(?!(\>))/Us';
+    
+    
+    /**
+    * 
+    * Generates a replacement for the matched text.
+    * 
+    * Token options are:
+    * 
+    * 'type' =>
+    *     'start' : the start of a blockquote
+    *     'end'   : the end of a blockquote
+    *
+    * 'level' => the indent level (0 for the first level, 1 for the
+    * second, etc)
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return A series of text and delimited tokens marking the different
+    * list text and list elements.
+    *
+    */
+    
+    function process(&$matches)
+    {
+        // the replacement text we will return to parse()
+        $return = '';
+        
+        // the list of post-processing matches
+        $list = array();
+        
+        // $matches[1] is the text matched as a list set by parse();
+        // create an array called $list that contains a new set of
+        // matches for the various list-item elements.
+        preg_match_all(
+            '=^(\>+) (.*\n)=Ums',
+            $matches[1],
+            $list,
+            PREG_SET_ORDER
+        );
+        
+        // a stack of starts and ends; we keep this so that we know what
+        // indent level we're at.
+        $stack = array();
+        
+        // loop through each list-item element.
+        foreach ($list as $key => $val) {
+            
+            // $val[0] is the full matched list-item line
+            // $val[1] is the number of initial '>' chars (indent level)
+            // $val[2] is the quote text
+            
+            // we number levels starting at 1, not zero
+            $level = strlen($val[1]);
+            
+            // get the text of the line
+            $text = $val[2];
+            
+            // add a level to the list?
+            while ($level > count($stack)) {
+                
+                // the current indent level is greater than the number
+                // of stack elements, so we must be starting a new
+                // level.  push the new level onto the stack with a 
+                // dummy value (boolean true)...
+                array_push($stack, true);
+                
+                $return .= "\n";
+                
+                // ...and add a start token to the return.
+                $return .= $this->wiki->addToken(
+                    $this->rule, 
+                    array(
+                        'type' => 'start',
+                        'level' => $level - 1
+                    )
+                );
+                
+                $return .= "\n\n";
+            }
+            
+            // remove a level?
+            while (count($stack) > $level) {
+                
+                // as long as the stack count is greater than the
+                // current indent level, we need to end list types.
+                // continue adding end-list tokens until the stack count
+                // and the indent level are the same.
+                array_pop($stack);
+                
+                $return .= "\n\n";
+                
+                $return .= $this->wiki->addToken(
+                    $this->rule, 
+                    array (
+                        'type' => 'end',
+                        'level' => count($stack)
+                    )
+                );
+                
+                $return .= "\n";
+            }
+            
+            // add the line text.
+            $return .= $text;
+        }
+        
+        // the last line may have been indented.  go through the stack
+        // and create end-tokens until the stack is empty.
+        $return .= "\n";
+        
+        while (count($stack) > 0) {
+            array_pop($stack);
+            $return .= $this->wiki->addToken(
+                $this->rule, 
+                array (
+                    'type' => 'end',
+                    'level' => count($stack)
+                )
+            );
+        }
+        
+        // we're done!  send back the replacement text.
+        return "\n$return\n\n";
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Mediawiki/Bold.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,79 @@
+<?php
+
+/**
+* 
+* Parses for bold text.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Bold.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Parses for bold text.
+* 
+* This class implements a Text_Wiki_Rule to find source text marked for
+* strong emphasis (bold) as defined by text surrounded by three
+* single-quotes. On parsing, the text itself is left in place, but the
+* starting and ending instances of three single-quotes are replaced with
+* tokens.
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Bold extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * The regular expression used to parse the source text and find
+    * matches conforming to this rule.  Used by the parse() method.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    * @see parse()
+    * 
+    */
+    
+    var $regex =  "/'''(()|[^'].*)'''/U";
+    
+    
+    /**
+    * 
+    * Generates a replacement for the matched text.  Token options are:
+    * 
+    * 'type' => ['start'|'end'] The starting or ending point of the
+    * emphasized text.  The text itself is left in the source.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return A pair of delimited tokens to be used as a placeholder in
+    * the source text surrounding the text to be emphasized.
+    *
+    */
+    
+    function process(&$matches)
+    {
+        $start = $this->wiki->addToken($this->rule, array('type' => 'start'));
+        $end = $this->wiki->addToken($this->rule, array('type' => 'end'));
+        return $start . $matches[1] . $end;
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Mediawiki/Break.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,72 @@
+<?php
+
+/**
+* 
+* Parses for explicit line breaks.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Break.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Parses for explicit line breaks.
+* 
+* This class implements a Text_Wiki_Parse to mark forced line breaks in the
+* source text.
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Break extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * The regular expression used to parse the source text and find
+    * matches conforming to this rule.  Used by the parse() method.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    * @see parse()
+    * 
+    */
+    
+    var $regex = '/ _\n/';
+    
+    
+    /**
+    * 
+    * Generates a replacement token for the matched text.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return string A delimited token to be used as a placeholder in
+    * the source text.
+    *
+    */
+    
+    function process(&$matches)
+    {    
+        return $this->wiki->addToken($this->rule);
+    }
+}
+
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Mediawiki/Center.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,78 @@
+<?php
+
+/**
+* 
+* Parses for centered lines of text.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Center.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Parses for centered lines of text.
+* 
+* This class implements a Text_Wiki_Parse to find lines marked for centering.
+* The line must start with "= " (i.e., an equal-sign followed by a space).
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Center extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * The regular expression used to find source text matching this
+    * rule.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    */
+    
+    var $regex = '/\n\= (.*?)\n/';
+    
+    /**
+    * 
+    * Generates a token entry for the matched text.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return A delimited token number to be used as a placeholder in
+    * the source text.
+    *
+    */
+    
+    function process(&$matches)
+    {
+        $start = $this->wiki->addToken(
+            $this->rule,
+            array('type' => 'start')
+        );
+        
+        $end = $this->wiki->addToken(
+            $this->rule,
+            array('type' => 'end')
+        );
+        
+        return "\n" . $start . $matches[1] . $end . "\n";
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Mediawiki/Code.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,99 @@
+<?php
+
+/**
+* 
+* Parses for text marked as a code example block.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Code.php,v 1.10 2006/02/21 14:33:53 toggg Exp $
+* 
+*/
+
+/**
+* 
+* Parses for text marked as a code example block.
+* 
+* This class implements a Text_Wiki_Parse to find sections marked as code
+* examples.  Blocks are marked as the string <code> on a line by itself,
+* followed by the inline code example, and terminated with the string
+* </code> on a line by itself.  The code example is run through the
+* native PHP highlight_string() function to colorize it, then surrounded
+* with <pre>...</pre> tags when rendered as XHTML.
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Code extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * The regular expression used to find source text matching this
+    * rule.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    */
+    
+/*    var $regex = '/^(\<code( .+)?\>)\n(.+)\n(\<\/code\>)(\s|$)/Umsi';*/
+    var $regex = ';^<code(\s[^>]*)?>((?:(?R)|.)*?)\n</code>(\s|$);msi';
+    
+    /**
+    * 
+    * Generates a token entry for the matched text.  Token options are:
+    * 
+    * 'text' => The full matched text, not including the <code></code> tags.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return A delimited token number to be used as a placeholder in
+    * the source text.
+    *
+    */
+    
+    function process(&$matches)
+    {
+        // are there additional attribute arguments?
+        $args = trim($matches[1]);
+        
+        if ($args == '') {
+            $options = array(
+                'text' => $matches[2],
+                'attr' => array('type' => '')
+            );
+        } else {
+        	// get the attributes...
+        	$attr = $this->getAttrs($args);
+        	
+        	// ... and make sure we have a 'type'
+        	if (! isset($attr['type'])) {
+        		$attr['type'] = '';
+        	}
+        	
+        	// retain the options
+            $options = array(
+                'text' => $matches[2],
+                'attr' => $attr
+            );
+        }
+        
+        return $this->wiki->addToken($this->rule, $options) . $matches[3];
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Mediawiki/Colortext.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,89 @@
+<?php
+
+/**
+* 
+* Parses for colorized text.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Colortext.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Parses for colorized text.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Colortext extends Text_Wiki_Parse {
+    
+    /**
+    * 
+    * The regular expression used to parse the source text and find
+    * matches conforming to this rule.  Used by the parse() method.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    * @see parse()
+    * 
+    */
+    
+    var $regex = "/\#\#(.+?)\|(.+?)\#\#/";
+    
+    
+    /**
+    * 
+    * Generates a replacement for the matched text.  Token options are:
+    * 
+    * 'type' => ['start'|'end'] The starting or ending point of the
+    * emphasized text.  The text itself is left in the source.
+    * 
+    * 'color' => the color indicator
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return string A pair of delimited tokens to be used as a
+    * placeholder in the source text surrounding the text to be
+    * emphasized.
+    *
+    */
+    
+    function process(&$matches)
+    {
+        $start = $this->wiki->addToken(
+            $this->rule, 
+            array(
+                'type' => 'start',
+                'color' => $matches[1]
+            )
+        );
+        
+        $end = $this->wiki->addToken(
+            $this->rule, 
+            array(
+                'type' => 'end',
+                'color' => $matches[1]
+            )
+        );
+        
+        return $start . $matches[2] . $end;
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Mediawiki/Deflist.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,277 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+* 
+* Mediawiki: Parse for definition lists.
+* 
+* @category Text
+* @package Text_Wiki
+* @author Justin Patrin <papercrane@reversefold.com>
+* @author Paul M. Jones <pmjones@php.net>
+* @author Moritz Venn <ritzmo@php.net>
+* @license LGPL
+* @version $Id: Deflist.php,v 1.1 2006/03/29 18:41:43 ritzmo Exp $
+* 
+*/
+
+/**
+* 
+* Parses for definition lists.
+*
+* This class implements a Text_Wiki_Parse to find source text marked as a
+* definition list.
+* If a line starts with ';' or ':' it is considered a part of a definition
+* list. ';' indicates the term to be defined and ':' indicates its definition.
+* As in Mediawiki we also allow definition lists to only consist of one
+* item-type.
+*
+* @category Text
+* @package Text_Wiki
+* 
+* @author Justin Patrin <papercrane@reversefold.com>
+* @author Paul M. Jones <pmjones@php.net>
+* @author Moritz Venn <ritzmo@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Deflist extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * The regular expression used to parse the source text and find
+    * matches conforming to this rule.  Used by the parse() method.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    * @see parse()
+    * 
+    */
+
+    var $regex = '/\n((?:\;|\:)+.*?\n(?!(?:\;|\:)+))/s';
+ 
+   /**
+    *
+    * Generates a replacement for the matched text.  Token options are:
+    *
+    * 'type' =>
+    *     'list_start'    : the start of a definition list
+    *     'list_end'      : the end of a definition list
+    *     'term_start'    : the start of a definition term
+    *     'term_end'      : the end of a definition term
+    *     'narr_start'    : the start of definition narrative
+    *     'narr_end'      : the end of definition narrative
+    *     'unknown'       : unknown type of definition portion
+    *
+    * 'level' => the indent level (0 for the first level, 1 for the
+    * second, etc)
+    *
+    * 'count' => the list item number at this level. not needed for
+    * xhtml, but very useful for PDF and RTF.
+    *
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return A series of text and delimited tokens marking the different
+    * list text and list elements.
+    *
+    */ 
+    function process(&$matches)
+    {
+        // the replacement text we will return
+        $return = '';
+        
+        // the list of post-processing matches
+        $list = array();
+        
+        // a stack of list-start and list-end types; we keep this
+        // so that we know what kind of list we're working with
+        // (bullet or number) and what indent level we're at.
+        $stack = array();
+        
+        // the item count is the number of list items for any
+        // given list-type on the stack
+        $itemcount = array();
+        
+        // have we processed the very first list item?
+        $pastFirst = false;
+        
+        // populate $list with this set of matches. $matches[1] is the
+        // text matched as a list set by parse().
+        preg_match_all(
+            '/^((;|:)+)(.*?)$/ms',
+            $matches[1],
+            $list,
+            PREG_SET_ORDER
+        );
+
+	// loop through each list-item element.
+        foreach ($list as $key => $val) {
+            // $val[0] is the full matched list-item line
+            // $val[1] is the type (* or #)
+            // $val[2] is the level (number)
+            // $val[3] is the list item text
+            
+            // how many levels are we indented? (1 means the "root"
+            // list level, no indenting.)
+            $level = strlen($val[1]);
+            
+            // get the list item type
+            if ($val[2] == ';') {
+                $type = 'term';
+            } elseif ($val[2] == ':') {
+                $type = 'narr';
+            } else {
+                $type = 'unknown';
+            }
+            
+            // get the text of the list item
+            $text = $val[3];
+
+            // add a level to the list?
+            if ($level > count($stack)) {
+
+                // the current indent level is greater than the
+                // number of stack elements, so we must be starting
+                // a new list.  push the new list type onto the
+                // stack...
+                array_push($stack, $type);
+
+		// The new list has to be opened in an item (use current type)
+		if ($level > 1) {
+		$return .= $this->wiki->addToken(
+		    $this->rule,
+		    array(
+		        'type' => $type . '_start',
+		        'level' => $level - 1
+                    )
+                );
+		}
+		// ...and add a list-start token to the return.
+                $return .= $this->wiki->addToken(
+                    $this->rule, 
+                    array(
+                        'type' => 'list_start',
+                        'level' => $level - 1
+                    )
+                );
+            }
+
+	    // remove a level from the list?
+	    while (count($stack) > $level) {
+                // so we don't keep counting the stack, we set up a temp
+                // var for the count.  -1 becuase we're going to pop the
+                // stack in the next command.  $tmp will then equal the
+                // current level of indent.
+                $tmp = count($stack) - 1;
+                
+                // as long as the stack count is greater than the
+                // current indent level, we need to end list types. 
+                // continue adding end-list tokens until the stack count
+                // and the indent level are the same.
+                $return .= $this->wiki->addToken(
+                    $this->rule, 
+                    array (
+                        'type' => 'list_end',
+                        'level' => $tmp
+                    )
+                );
+
+                array_pop($stack);
+
+		// reset to the current (previous) list type so that
+                // the new list item matches the proper list type.
+		$type = $stack[$tmp - 1];
+
+		// Close the previously opened List item
+		$return .= $this->wiki->addToken(
+                    $this->rule,
+                    array (
+                        'type' => $type . '_end',
+                        'level' => $tmp
+                    )
+                );
+                
+                // reset the item count for the popped indent level
+                unset($itemcount[$tmp + 1]);
+            }
+            
+            // add to the item count for this list (taking into account
+            // which level we are at).
+            if (! isset($itemcount[$level])) {
+                // first count
+                $itemcount[$level] = 0;
+            } else {
+                // increment count
+                $itemcount[$level]++;
+            }
+            
+            // is this the very first item in the list?
+            if (! $pastFirst) {
+                $first = true;
+                $pastFirst = true;
+            } else {
+                $first = false;
+            }
+            
+            // create a list-item starting token.
+            $start = $this->wiki->addToken(
+                $this->rule, 
+                array(
+                    'type' => $type . '_start',
+                    'level' => $level,
+                    'count' => $itemcount[$level],
+                    'first' => $first
+                )
+            );
+            
+            // create a list-item ending token.
+            $end = $this->wiki->addToken(
+                $this->rule, 
+                array(
+                    'type' => $type . '_end',
+                    'level' => $level,
+                    'count' => $itemcount[$level]
+                )
+            );
+            
+            // add the starting token, list-item text, and ending token
+            // to the return.
+            $return .= $start . $text . $end;
+        }
+        
+        // the last list-item may have been indented.  go through the
+        // list-type stack and create end-list tokens until the stack
+	// is empty.
+	$level = count($stack);
+	while ($level > 0) {
+	    array_pop($stack);
+            $return .= $this->wiki->addToken(
+                $this->rule, 
+                array (
+                    'type' => 'list_end',
+                    'level' => $level - 1
+                )
+            );
+
+            // if we are higher than level 1 we need to close fake items
+            if ($level > 1) {
+		$return .= $this->wiki->addToken(
+                $this->rule,
+                array (
+                    'type' => $stack[$level - 2] . '_end',
+                    'level' => $level - 2
+                )
+                );
+	    }
+	    $level = count($stack);
+	}
+        
+        // we're done!  send back the replacement text.
+        return "\n" . $return . "\n\n";
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Mediawiki/Delimiter.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,80 @@
+<?php
+
+/**
+* 
+* Parses for Text_Wiki delimiter characters already in the source text.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Delimiter.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Parses for Text_Wiki delimiter characters already in the source text.
+* 
+* This class implements a Text_Wiki_Parse to find instances of the delimiter
+* character already embedded in the source text; it extracts them and replaces
+* them with a delimited token, then renders them as the delimiter itself
+* when the target format is XHTML.
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Delimiter extends Text_Wiki_Parse {
+    
+    /**
+    * 
+    * Constructor.  Overrides the Text_Wiki_Parse constructor so that we
+    * can set the $regex property dynamically (we need to include the
+    * Text_Wiki $delim character.
+    * 
+    * @param object &$obj The calling "parent" Text_Wiki object.
+    * 
+    * @param string $name The token name to use for this rule.
+    * 
+    */
+    
+    function Text_Wiki_Parse_delimiter(&$obj)
+    {
+        parent::Text_Wiki_Parse($obj);
+        $this->regex = '/' . $this->wiki->delim . '/';
+    }
+    
+    
+    /**
+    * 
+    * Generates a token entry for the matched text.  Token options are:
+    * 
+    * 'text' => The full matched text.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return A delimited token number to be used as a placeholder in
+    * the source text.
+    *
+    */
+    
+    function process(&$matches)
+    {    
+        return $this->wiki->addToken(
+            $this->rule,
+            array('text' => $this->wiki->delim)
+        );
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Mediawiki/Embed.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,106 @@
+<?php
+
+/**
+* 
+* Embeds the results of a PHP script at render-time.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Embed.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Embeds the results of a PHP script at render-time.
+* 
+* This class implements a Text_Wiki_Parse to embed the contents of a URL
+* inside the page at render-time.  Typically used to get script output.
+* This differs from the 'include' rule, which incorporates results at
+* parse-time; 'embed' output does not get parsed by Text_Wiki, while
+* 'include' ouput does.
+*
+* This rule is inherently not secure; it allows cross-site scripting to
+* occur if the embedded output has <script> or other similar tags.  Be
+* careful.
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Embed extends Text_Wiki_Parse {
+    
+    var $conf = array(
+        'base' => '/path/to/scripts/'
+    );
+    
+    var $file = null;
+
+    var $output = null;
+
+    var $vars = null;
+
+
+    /**
+    * 
+    * The regular expression used to find source text matching this
+    * rule.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    */
+    
+    var $regex = '/(\[\[embed )(.+?)( .+?)?(\]\])/i';
+    
+    
+    /**
+    * 
+    * Generates a token entry for the matched text.  Token options are:
+    * 
+    * 'text' => The full matched text, not including the <code></code> tags.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return A delimited token number to be used as a placeholder in
+    * the source text.
+    *
+    */
+    
+    function process(&$matches)
+    {    
+        // save the file location
+        $this->file = $this->getConf('base', './') . $matches[2];
+        
+        // extract attribs as variables in the local space
+        $this->vars = $this->getAttrs($matches[3]);
+        unset($this->vars['this']);
+        extract($this->vars);
+        
+        // run the script
+        ob_start();
+        include($this->file);
+        $this->output = ob_get_contents();
+        ob_end_clean();
+        
+        // done, place the script output directly in the source
+        return $this->wiki->addToken(
+            $this->rule,
+            array('text' => $this->output)
+        );
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Mediawiki/Emphasis.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,86 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Mediawiki: Parses for emphazised text.
+ *
+ * Text_Wiki rule parser to find source text emphazised
+ * as defined by text surrounded by repeated single quotes  ''...'' and more
+ * Translated are ''emphasis'' , '''strong''' or '''''both''''' ...
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Bertrand Gugger <bertrand@toggg.com>
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @copyright  2005 bertrand Gugger
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Emphasis.php,v 1.4 2006/02/15 12:27:40 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * Emphazised text rule parser class for Mediawiki. Makes Emphasis, Strong or both
+ * This class implements a Text_Wiki_Parse to find source text marked for
+ * emphasis, stronger and very as defined by text surrounded by 2,3 or 5 single-quotes.
+ * On parsing, the text itself is left in place, but the starting and ending
+ * instances of the single-quotes are replaced with tokens.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Bertrand Gugger <bertrand@toggg.com>
+ * @copyright  2005 bertrand Gugger
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ * @see        Text_Wiki_Parse::Text_Wiki_Parse()
+ */
+class Text_Wiki_Parse_Emphasis extends Text_Wiki_Parse {
+
+    /**
+     * The regular expression used to parse the source text and find
+     * matches conforming to this rule.  Used by the parse() method.
+     * We match '' , ''' or ''''' embeded texts
+     *
+     * @access public
+     * @var string
+     * @see Text_Wiki_Parse::parse()
+     */
+    var $regex = "/(?<!')'('{1,4})(.*?)\\1'(?!')/";
+
+    /**
+     * Generates a replacement for the matched text.  Token options are:
+     * - 'type' => ['start'|'end'] The starting or ending point of the emphasized text.
+     * Generated tokens are Emphasis (this rule), Strong or Emphasis / Strong
+     * The text itself is left in the source but may content bested blocks
+     *
+     * @access public
+     * @param array &$matches The array of matches from parse().
+     * @return string Delimited by start/end tokens to be used as
+     * placeholder in the source text surrounding the text to be emphasized.
+     */
+    function process(&$matches)
+    {
+        $embeded = $matches[2];
+        switch (strlen($matches[1])) {
+            case 1:
+                $start = $this->wiki->addToken($this->rule, array('type' => 'start'));
+                $end   = $this->wiki->addToken($this->rule, array('type' => 'end'));
+            break;
+            case 3:
+                $embeded = "'" . $embeded . "'";
+            case 2:
+                $start = $this->wiki->addToken('Strong',    array('type' => 'start'));
+                $end   = $this->wiki->addToken('Strong',    array('type' => 'end'));
+            break;
+            case 4:
+                $start = $this->wiki->addToken($this->rule, array('type' => 'start'))
+                       . $this->wiki->addToken('Strong',    array('type' => 'start'));
+                $end   = $this->wiki->addToken('Strong',    array('type' => 'end'))
+                       . $this->wiki->addToken($this->rule, array('type' => 'end'));
+            break;
+        }
+        return $start . $embeded . $end;
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Mediawiki/Freelink.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,127 @@
+<?php
+
+/**
+* 
+* Parses for wiki freelink text.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Freelink.php,v 1.4 2005/10/19 23:43:53 toggg Exp $
+* 
+*/
+
+/**
+* 
+* Parses for freelinked page links.
+* 
+* This class implements a Text_Wiki_Parse to find source text marked as a
+* wiki freelink, and automatically create a link to that page.
+* 
+* A freelink is any page name not conforming to the standard
+* StudlyCapsStyle for a wiki page name.  For example, a page normally
+* named MyHomePage can be renamed and referred to as ((My Home Page)) --
+* note the spaces in the page name.  You can also make a "nice-looking"
+* link without renaming the target page; e.g., ((MyHomePage|My Home
+* Page)).  Finally, you can use named anchors on the target page:
+* ((MyHomePage|My Home Page#Section1)).
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Freelink extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * Constructor.  We override the Text_Wiki_Parse constructor so we can
+    * explicitly comment each part of the $regex property.
+    * 
+    * @access public
+    * 
+    * @param object &$obj The calling "parent" Text_Wiki object.
+    * 
+    */
+    
+    function Text_Wiki_Parse_Freelink(&$obj)
+    {
+        parent::Text_Wiki_Parse($obj);
+        
+        $this->regex =
+            '/' .                                                   // START regex
+            "\\(\\(" .                                               // double open-parens
+            "(" .                                                   // START freelink page patter
+            "[-A-Za-z0-9 _+\\/.,;:!?'\"\\[\\]\\{\\}&\xc0-\xff]+" . // 1 or more of just about any character
+            ")" .                                                   // END  freelink page pattern
+            "(" .                                                   // START display-name
+            "\|" .                                                   // a pipe to start the display name
+            "[-A-Za-z0-9 _+\\/.,;:!?'\"\\[\\]\\{\\}&\xc0-\xff]+" . // 1 or more of just about any character
+            ")?" .                                                   // END display-name pattern 0 or 1
+            "(" .                                                   // START pattern for named anchors
+            "\#" .                                                   // a hash mark
+            "[A-Za-z]" .                                           // 1 alpha
+            "[-A-Za-z0-9_:.]*" .                                   // 0 or more alpha, digit, underscore
+            ")?" .                                                   // END named anchors pattern 0 or 1
+            "()\\)\\)" .                                           // double close-parens
+            '/';                                                   // END regex
+    }
+    
+    
+    /**
+    * 
+    * Generates a replacement for the matched text.  Token options are:
+    * 
+    * 'page' => the wiki page name (e.g., HomePage).
+    * 
+    * 'text' => alternative text to be displayed in place of the wiki
+    * page name.
+    * 
+    * 'anchor' => a named anchor on the target wiki page
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return A delimited token to be used as a placeholder in
+    * the source text, plus any text priot to the match.
+    *
+    */
+    
+    function process(&$matches)
+    {
+        // use nice variable names
+        $page = $matches[1];
+        $text = $matches[2];
+        $anchor = $matches[3];
+        
+        // is the page given a new text appearance?
+        if (trim($text) == '') {
+            // no
+            $text = $page;
+        } else {
+            // yes, strip the leading | character
+            $text = substr($text, 1);
+        }
+        
+        // set the options
+        $options = array(
+            'page'   => $page,
+            'text'   => $text,
+            'anchor' => $anchor
+        );
+        
+        // return a token placeholder
+        return $this->wiki->addToken($this->rule, $options);
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Mediawiki/Function.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,141 @@
+<?php
+
+/**
+* 
+* Parses for an API function documentation block.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Function.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Parses for an API function documentation block.
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Function extends Text_Wiki_Parse {
+
+    var $regex = '/^(\<function\>)\n(.+)\n(\<\/function\>)(\s|$)/Umsi';
+    
+    function process(&$matches)
+    {
+        // default options
+        $opts = array(
+            'name' => null,
+            'access' => null,
+            'return' => null,
+            'params' => array(),
+            'throws' => array()
+        );
+        
+        // split apart the markup lines and loop through them
+        $lines = explode("\n", $matches[2]);
+        foreach ($lines as $line) {
+            
+            // skip blank lines
+            if (trim($line) == '') {
+                continue;
+            }
+            
+            // find the first ':' on the line; the left part is the 
+            // type, the right part is the value. skip lines without
+            // a ':' on them.
+            $pos = strpos($line, ':');
+            if ($pos === false) {
+                continue;
+            }
+            
+            // $type is the line type: name, access, return, param, throws
+            // 012345678901234
+            // name: something
+            $type = trim(substr($line, 0, $pos));
+            $val = trim(substr($line, $pos+1));
+            
+            switch($type) {
+            
+            case 'a':
+            case 'access':
+                $opts['access'] = $val;
+                break;
+                
+            case 'n':
+            case 'name':
+                $opts['name'] = $val;
+                break;
+                
+            case 'p':
+            case 'param':
+                $tmp = explode(',', $val);
+                $k = count($tmp);
+                if ($k == 1) {
+                    $opts['params'][] = array(
+                        'type' => $tmp[0],
+                        'descr' => null,
+                        'default' => null
+                    );
+                } elseif ($k == 2) {
+                    $opts['params'][] = array(
+                        'type' => $tmp[0],
+                        'descr' => $tmp[1],
+                        'default' => null
+                    );
+                } else {
+                    $opts['params'][] = array(
+                        'type' => $tmp[0],
+                        'descr' => $tmp[1],
+                        'default' => $tmp[2]
+                    );
+                }
+                break;
+            
+            case 'r':
+            case 'return':
+            case 'returns':
+                $opts['return'] = $val;
+                break;
+            
+            case 't':
+            case 'throws':
+                $tmp = explode(',', $val);
+                $k = count($tmp);
+                if ($k == 1) {
+                    $opts['throws'][] = array(
+                        'type' => $tmp[0],
+                        'descr' => null
+                    );
+                } else {
+                    $opts['throws'][] = array(
+                        'type' => $tmp[0],
+                        'descr' => $tmp[1]
+                    );
+                }
+                break;
+        
+            default:
+                $opts[$type] = $val;
+                break;
+            
+            }
+        }
+        
+        // add the token back in place
+        return $this->wiki->addToken($this->rule, $opts) . $matches[4];
+    }
+}
+
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Mediawiki/Heading.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,109 @@
+<?php
+
+/**
+* 
+* Parses for heading text.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @author Moritz Venn <moritz.venn@freaque.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Heading.php,v 1.3 2006/02/03 19:47:02 toggg Exp $
+* 
+*/
+
+/**
+* 
+* Parses for heading text.
+* 
+* This class implements a Text_Wiki_Parse to find source text marked to
+* be a heading element, as defined by text on a line by itself prefixed
+* with a number of plus signs (+). The heading text itself is left in
+* the source, but is prefixed and suffixed with delimited tokens marking
+* the start and end of the heading.
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Moritz Venn <moritz.venn@freaque.net>
+* 
+*/
+
+class Text_Wiki_Parse_Heading extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * The regular expression used to parse the source text and find
+    * matches conforming to this rule.  Used by the parse() method.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    * @see parse()
+    * 
+    */
+    
+    var $regex = '/^(={2,6})(.*?)\1(?:\s|$)/m';
+    
+    var $conf = array(
+        'id_prefix' => 'toc'
+    );
+    
+    /**
+    * 
+    * Generates a replacement for the matched text.  Token options are:
+    * 
+    * 'type' => ['start'|'end'] The starting or ending point of the
+    * heading text.  The text itself is left in the source.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return string A pair of delimited tokens to be used as a
+    * placeholder in the source text surrounding the heading text.
+    *
+    */
+    
+    function process(&$matches)
+    {
+        // keep a running count for header IDs.  we use this later
+        // when constructing TOC entries, etc.
+        static $id;
+        if (! isset($id)) {
+            $id = 0;
+        }
+        
+        $prefix = htmlspecialchars($this->getConf('id_prefix'));
+        
+        $start = $this->wiki->addToken(
+            $this->rule, 
+            array(
+                'type' => 'start',
+                'level' => strlen($matches[1]),
+                'text' => trim($matches[2]),
+                'id' => $prefix . $id ++
+            )
+        );
+        
+        $end = $this->wiki->addToken(
+            $this->rule, 
+            array(
+                'type' => 'end',
+                'level' => strlen($matches[1])
+            )
+        );
+        
+        return $start . trim($matches[2]) . $end . "\n";
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Mediawiki/Horiz.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,70 @@
+<?php
+
+/**
+* 
+* Parses for horizontal ruling lines.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Horiz.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Parses for horizontal ruling lines.
+* 
+* This class implements a Text_Wiki_Parse to find source text marked to
+* be a horizontal rule, as defined by four dashed on their own line.
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Horiz extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * The regular expression used to parse the source text and find
+    * matches conforming to this rule.  Used by the parse() method.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    * @see parse()
+    * 
+    */
+    
+    var $regex = '/^([-]{4,})$/m';
+    
+    
+    /**
+    * 
+    * Generates a replacement token for the matched text.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return string A token marking the horizontal rule.
+    *
+    */
+    
+    function process(&$matches)
+    {    
+        return $this->wiki->addToken($this->rule);
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Mediawiki/Html.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,75 @@
+<?php
+
+/**
+* 
+* Parses for blocks of HTML code.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Html.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Parses for blocks of HTML code.
+* 
+* This class implements a Text_Wiki_Parse to find source text marked as
+* HTML to be redndred as-is.  The block start is marked by <html> on its
+* own line, and the block end is marked by </html> on its own line.
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Html extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * The regular expression used to parse the source text and find
+    * matches conforming to this rule.  Used by the parse() method.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    * @see parse()
+    * 
+    */
+    
+    var $regex = '/^\<html\>\n(.+)\n\<\/html\>(\s|$)/Umsi';
+    
+    
+    /**
+    * 
+    * Generates a replacement for the matched text.  Token options are:
+    * 
+    * 'text' => The text of the HTML to be rendered as-is.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return A delimited token to be used as a placeholder in
+    * the source text, plus any text following the HTML block.
+    *
+    */
+    
+    function process(&$matches)
+    {    
+        $options = array('text' => $matches[1]);
+        return $this->wiki->addToken($this->rule, $options) . $matches[2];
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Mediawiki/Image.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,136 @@
+<?php
+
+/**
+*
+* Parses for image placement.
+*
+* @category Text
+*
+* @package Text_Wiki
+*
+* @author Paul M. Jones <pmjones@php.net>
+*
+* @license LGPL
+*
+* @version $Id: Image.php,v 1.5 2005/09/12 11:34:44 toggg Exp $
+*
+*/
+
+/**
+*
+* Parses for image placement.
+*
+* @category Text
+*
+* @package Text_Wiki
+*
+* @author Paul M. Jones <pmjones@php.net>
+*
+*/
+
+class Text_Wiki_Parse_Image extends Text_Wiki_Parse {
+
+    /**
+     * URL schemes recognized by this rule.
+     *
+     * @access public
+     * @var array
+    */
+    var $conf = array(
+        'schemes' => 'http|https|ftp|gopher|news',
+        'host_regexp' => '(?:[^.\s/"\'<\\\#delim#\ca-\cz]+\.)*[a-z](?:[-a-z0-9]*[a-z0-9])?\.?',
+        'path_regexp' => '(?:/[^\s"<\\\#delim#\ca-\cz]*)?'
+    );
+
+    /**
+    *
+    * The regular expression used to find source text matching this
+    * rule.
+    *
+    * @access public
+    *
+    * @var string
+    *
+    */
+
+    var $regex = '/(\[\[image\s+)(.+?)(\]\])/i';
+
+
+    /**
+     * The regular expressions used to check ecternal urls
+     *
+     * @access public
+     * @var string
+     * @see parse()
+     */
+    var $url = '';
+
+    /**
+     * Constructor.
+     * We override the constructor to build up the url regex from config
+     *
+     * @param object &$obj the base conversion handler
+     * @return The parser object
+     * @access public
+     */
+    function Text_Wiki_Parse_Image(&$obj)
+    {
+        $default = $this->conf;
+        parent::Text_Wiki_Parse($obj);
+
+        // convert the list of recognized schemes to a regex OR,
+        $schemes = $this->getConf('schemes', $default['schemes']);
+        $this->url = str_replace( '#delim#', $this->wiki->delim,
+           '#(?:' . (is_array($schemes) ? implode('|', $schemes) : $schemes) . ')://'
+           . $this->getConf('host_regexp', $default['host_regexp'])
+           . $this->getConf('path_regexp', $default['path_regexp']) .'#');
+    }
+
+    /**
+    *
+    * Generates a token entry for the matched text.  Token options are:
+    *
+    * 'src' => The image source, typically a relative path name.
+    *
+    * 'opts' => Any macro options following the source.
+    *
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return A delimited token number to be used as a placeholder in
+    * the source text.
+    *
+    */
+
+    function process(&$matches)
+    {
+        $pos = strpos($matches[2], ' ');
+
+        if ($pos === false) {
+            $options = array(
+                'src' => $matches[2],
+                'attr' => array());
+        } else {
+            // everything after the space is attribute arguments
+            $options = array(
+                'src' => substr($matches[2], 0, $pos),
+                'attr' => $this->getAttrs(substr($matches[2], $pos+1))
+            );
+            // check the scheme case of external link
+            if (array_key_exists('link', $options['attr'])) {
+                // external url ?
+                if (($pos = strpos($options['attr']['link'], '://')) !== false) {
+                    if (!preg_match($this->url, $options['attr']['link'])) {
+                        return $matches[0];
+                    }
+                } elseif (in_array('Wikilink', $this->wiki->disable)) {
+                        return $matches[0]; // Wikilink disabled
+                }
+            }
+        }
+
+        return $this->wiki->addToken($this->rule, $options);
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Mediawiki/Include.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,100 @@
+<?php
+
+/**
+* 
+* Includes the contents of another PHP script into the source text.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Include.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* This class implements a Text_Wiki_Parse to include the results of a
+* script directly into the source at parse-time; thus, the output of the
+* script will be parsed by Text_Wiki.  This differs from the 'embed'
+* rule, which incorporates the results at render-time, meaning that the
+* 'embed' content is not parsed by Text_Wiki.
+*
+* DANGER!
+* 
+* This rule is inherently not secure; it allows cross-site scripting to
+* occur if the embedded output has <script> or other similar tags.  Be
+* careful.
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Include extends Text_Wiki_Parse {
+    
+    var $conf = array(
+        'base' => '/path/to/scripts/'
+    );
+    
+    var $file = null;
+    
+    var $output = null;
+    
+    var $vars = null;
+
+    /**
+    * 
+    * The regular expression used to find source text matching this
+    * rule.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    */
+    
+    var $regex = '/(\[\[include )(.+?)( .+?)?(\]\])/i';
+    
+    
+    /**
+    * 
+    * Includes the results of the script directly into the source; the output
+    * will subsequently be parsed by the remaining Text_Wiki rules.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return The results of the included script.
+    *
+    */
+    
+    function process(&$matches)
+    {
+        // save the file location
+        $this->file = $this->getConf('base', './') . $matches[2];
+
+        // extract attribs as variables in the local space
+        $this->vars = $this->getAttrs($matches[3]);
+        unset($this->vars['this']);
+        extract($this->vars);
+
+        // run the script
+        ob_start();
+        include($this->file);
+        $this->output = ob_get_contents();
+        ob_end_clean();
+    
+        // done, place the script output directly in the source
+        return $this->output;
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Mediawiki/Interwiki.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,138 @@
+<?php
+
+/**
+* 
+* Parses for interwiki links.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Interwiki.php,v 1.4 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Parses for interwiki links.
+* 
+* This class implements a Text_Wiki_Parse to find source text marked as
+* an Interwiki link.  See the regex for a detailed explanation of the
+* text matching procedure; e.g., "InterWikiName:PageName".
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Interwiki extends Text_Wiki_Parse {
+    
+    // double-colons wont trip up now
+    var $regex = '([A-Za-z0-9_]+):((?!:)[A-Za-z0-9_\/=&~#.:;-]+)';
+    
+    
+    /**
+    * 
+    * Parser.  We override the standard parser so we can
+    * find both described interwiki links and standalone links.
+    * 
+    * @access public
+    * 
+    * @return void
+    * 
+    */
+    
+    function parse()
+    {
+        // described interwiki links
+        $tmp_regex = '/\[' . $this->regex . ' (.+?)\]/';
+        $this->wiki->source = preg_replace_callback(
+            $tmp_regex,
+            array(&$this, 'processDescr'),
+            $this->wiki->source
+        );
+        
+        // standalone interwiki links
+        $tmp_regex = '/' . $this->regex . '/';
+        $this->wiki->source = preg_replace_callback(
+            $tmp_regex,
+            array(&$this, 'process'),
+            $this->wiki->source
+        );
+       
+    }
+    
+    
+    /**
+    * 
+    * Generates a replacement for the matched standalone interwiki text.
+    * Token options are:
+    * 
+    * 'site' => The key name for the Text_Wiki interwiki array map,
+    * usually the name of the interwiki site.
+    * 
+    * 'page' => The page on the target interwiki to link to.
+    * 
+    * 'text' => The text to display as the link.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return A delimited token to be used as a placeholder in
+    * the source text, plus any text priot to the match.
+    *
+    */
+    
+    function process(&$matches)
+    {
+        $options = array(
+            'site' => $matches[1],
+            'page' => $matches[2],
+            'text' => $matches[0]
+        );
+        
+        return $this->wiki->addToken($this->rule, $options);
+    }
+    
+    
+    /**
+    * 
+    * Generates a replacement for described interwiki links. Token
+    * options are:
+    * 
+    * 'site' => The key name for the Text_Wiki interwiki array map,
+    * usually the name of the interwiki site.
+    * 
+    * 'page' => The page on the target interwiki to link to.
+    * 
+    * 'text' => The text to display as the link.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return A delimited token to be used as a placeholder in
+    * the source text, plus any text priot to the match.
+    *
+    */
+    
+    function processDescr(&$matches)
+    {
+        $options = array(
+            'site' => $matches[1],
+            'page' => $matches[2],
+            'text' => $matches[3]
+        );
+        
+        return $this->wiki->addToken($this->rule, $options);
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Mediawiki/Italic.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,85 @@
+<?php
+
+/**
+* 
+* Parses for italic text.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Italic.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Parses for italic text.
+* 
+* This class implements a Text_Wiki_Parse to find source text marked for
+* emphasis (italics) as defined by text surrounded by two single-quotes.
+* On parsing, the text itself is left in place, but the starting and ending
+* instances of two single-quotes are replaced with tokens.
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Italic extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * The regular expression used to parse the source text and find
+    * matches conforming to this rule.  Used by the parse() method.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    * @see parse()
+    * 
+    */
+    
+    var $regex = "/''(()|[^'].*)''/U";
+    
+    
+    /**
+    * 
+    * Generates a replacement for the matched text.  Token options are:
+    * 
+    * 'type' => ['start'|'end'] The starting or ending point of the
+    * emphasized text.  The text itself is left in the source.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return string A pair of delimited tokens to be used as a
+    * placeholder in the source text surrounding the text to be
+    * emphasized.
+    *
+    */
+    
+    function process(&$matches)
+    {
+        $start = $this->wiki->addToken(
+            $this->rule, array('type' => 'start')
+        );
+        
+        $end = $this->wiki->addToken(
+            $this->rule, array('type' => 'end')
+        );
+        
+        return $start . $matches[1] . $end;
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Mediawiki/List.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,250 @@
+<?php
+
+/**
+* 
+* Parses for bulleted and numbered lists.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Justin Patrin <papercrane@reversefold.com>
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: List.php,v 1.1 2006/03/28 04:46:09 ritzmo Exp $
+* 
+*/
+
+/**
+* 
+* Parses for bulleted and numbered lists.
+* 
+* This class implements a Text_Wiki_Parse to find source text marked as
+* a bulleted or numbered list.  In short, if a line starts with '* ' then
+* it is a bullet list item; if a line starts with '# ' then it is a 
+* number list item.  Spaces in front of the * or # indicate an indented
+* sub-list.  The list items must be on sequential lines, and may be 
+* separated by blank lines to improve readability.  Using a non-* non-#
+* non-whitespace character at the beginning of a line ends the list.
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Justin Patrin <papercrane@reversefold.com>
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_List extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * The regular expression used to parse the source text and find
+    * matches conforming to this rule.  Used by the parse() method.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    * @see parse()
+    * 
+    */
+
+    //TODO: add text continuations (any number of + signs) and expandable areas (- after *s ot #s)
+    
+    var $regex = '/\n((?:\*|#)+.*?\n(?!(?:\*|#)+))/s';
+
+    /**
+    * 
+    * Generates a replacement for the matched text.  Token options are:
+    * 
+    * 'type' =>
+    *     'bullet_start' : the start of a bullet list
+    *     'bullet_end'   : the end of a bullet list
+    *     'number_start' : the start of a number list
+    *     'number_end'   : the end of a number list
+    *     'item_start'   : the start of item text (bullet or number)
+    *     'item_end'     : the end of item text (bullet or number)
+    *     'unknown'      : unknown type of list or item
+    *
+    * 'level' => the indent level (0 for the first level, 1 for the
+    * second, etc)
+    *
+    * 'count' => the list item number at this level. not needed for
+    * xhtml, but very useful for PDF and RTF.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return A series of text and delimited tokens marking the different
+    * list text and list elements.
+    *
+    */
+    
+    function process(&$matches)
+    {
+        // the replacement text we will return
+        $return = '';
+        
+        // the list of post-processing matches
+        $list = array();
+        
+        // a stack of list-start and list-end types; we keep this
+        // so that we know what kind of list we're working with
+        // (bullet or number) and what indent level we're at.
+        $stack = array();
+        
+        // the item count is the number of list items for any
+        // given list-type on the stack
+        $itemcount = array();
+        
+        // have we processed the very first list item?
+        $pastFirst = false;
+        
+        // populate $list with this set of matches. $matches[1] is the
+        // text matched as a list set by parse().
+        preg_match_all(
+            '/^((\*|#)+)(.*?)$/ms',
+            $matches[1],
+            $list,
+            PREG_SET_ORDER
+        );
+        
+        // loop through each list-item element.
+        foreach ($list as $key => $val) {
+            // $val[0] is the full matched list-item line
+            // $val[1] is the type (* or #)
+            // $val[2] is the level (number)
+            // $val[3] is the list item text
+            
+            // how many levels are we indented? (1 means the "root"
+            // list level, no indenting.)
+            $level = strlen($val[1]);
+            
+            // get the list item type
+            if ($val[2] == '*') {
+                $type = 'bullet';
+            } elseif ($val[2] == '#') {
+                $type = 'number';
+            } else {
+                $type = 'unknown';
+            }
+            
+            // get the text of the list item
+            $text = $val[3];
+
+            // add a level to the list?
+            if ($level > count($stack)) {
+                
+                // the current indent level is greater than the
+                // number of stack elements, so we must be starting
+                // a new list.  push the new list type onto the
+                // stack...
+                array_push($stack, $type);
+                
+                // ...and add a list-start token to the return.
+                $return .= $this->wiki->addToken(
+                    $this->rule, 
+                    array(
+                        'type' => $type . '_list_start',
+                        'level' => $level - 1
+                    )
+                );
+            }
+            
+            // remove a level from the list?
+            while (count($stack) > $level) {
+                
+                // so we don't keep counting the stack, we set up a temp
+                // var for the count.  -1 becuase we're going to pop the
+                // stack in the next command.  $tmp will then equal the
+                // current level of indent.
+                $tmp = count($stack) - 1;
+                
+                // as long as the stack count is greater than the
+                // current indent level, we need to end list types. 
+                // continue adding end-list tokens until the stack count
+                // and the indent level are the same.
+                $return .= $this->wiki->addToken(
+                    $this->rule, 
+                    array (
+                        'type' => array_pop($stack) . '_list_end',
+                        'level' => $tmp
+                    )
+                );
+                
+                // reset to the current (previous) list type so that
+                // the new list item matches the proper list type.
+                $type = $stack[$tmp - 1];
+                
+                // reset the item count for the popped indent level
+                unset($itemcount[$tmp + 1]);
+            }
+            
+            // add to the item count for this list (taking into account
+            // which level we are at).
+            if (! isset($itemcount[$level])) {
+                // first count
+                $itemcount[$level] = 0;
+            } else {
+                // increment count
+                $itemcount[$level]++;
+            }
+            
+            // is this the very first item in the list?
+            if (! $pastFirst) {
+                $first = true;
+                $pastFirst = true;
+            } else {
+                $first = false;
+            }
+            
+            // create a list-item starting token.
+            $start = $this->wiki->addToken(
+                $this->rule, 
+                array(
+                    'type' => $type . '_item_start',
+                    'level' => $level,
+                    'count' => $itemcount[$level],
+                    'first' => $first
+                )
+            );
+            
+            // create a list-item ending token.
+            $end = $this->wiki->addToken(
+                $this->rule, 
+                array(
+                    'type' => $type . '_item_end',
+                    'level' => $level,
+                    'count' => $itemcount[$level]
+                )
+            );
+            
+            // add the starting token, list-item text, and ending token
+            // to the return.
+            $return .= $start . $text . $end;
+        }
+        
+        // the last list-item may have been indented.  go through the
+        // list-type stack and create end-list tokens until the stack
+        // is empty.
+        while (count($stack) > 0) {
+            $return .= $this->wiki->addToken(
+                $this->rule, 
+                array (
+                    'type' => array_pop($stack) . '_list_end',
+                    'level' => count($stack)
+                )
+            );
+        }
+        
+        // we're done!  send back the replacement text.
+        return "\n" . $return . "\n\n";
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Mediawiki/Newline.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,75 @@
+<?php
+
+/**
+* 
+* Parses for implied line breaks indicated by newlines.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Newline.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Parses for implied line breaks indicated by newlines.
+* 
+* This class implements a Text_Wiki_Parse to mark implied line breaks in the
+* source text, usually a single carriage return in the middle of a paragraph
+* or block-quoted text.
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Newline extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * The regular expression used to parse the source text and find
+    * matches conforming to this rule.  Used by the parse() method.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    * @see parse()
+    * 
+    */
+    
+    var $regex = '/([^\n])\n([^\n])/m';
+    
+    
+    /**
+    * 
+    * Generates a replacement token for the matched text.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return string A delimited token to be used as a placeholder in
+    * the source text.
+    *
+    */
+    
+    function process(&$matches)
+    {    
+        return $matches[1] .
+            $this->wiki->addToken($this->rule) .
+            $matches[2];
+    }
+}
+
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Mediawiki/Paragraph.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,146 @@
+<?php
+
+/**
+* 
+* Parses for paragraph blocks.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Paragraph.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Parses for paragraph blocks.
+* 
+* This class implements a Text_Wiki rule to find sections of the source
+* text that are paragraphs.  A para is any line not starting with a token
+* delimiter, followed by two newlines.
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Paragraph extends Text_Wiki_Parse {
+    
+    /**
+    * 
+    * The regular expression used to find source text matching this
+    * rule.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    */
+    
+    var $regex = "/^.*?\n\n/m";
+    
+    var $conf = array(
+        'skip' => array(
+            'blockquote', // are we sure about this one?
+            'code',
+            'heading',
+            'horiz',
+            'deflist',
+            'table',
+            'list',
+            'toc'
+        )
+    );
+    
+    
+    /**
+    * 
+    * Generates a token entry for the matched text.  Token options are:
+    * 
+    * 'start' => The starting point of the paragraph.
+    * 
+    * 'end' => The ending point of the paragraph.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return A delimited token number to be used as a placeholder in
+    * the source text.
+    *
+    */
+    
+    function process(&$matches)
+    {
+        $delim = $this->wiki->delim;
+        
+        // was anything there?
+        if (trim($matches[0]) == '') {
+            return '';
+        }
+        
+        // does the match start with a delimiter?
+        if (substr($matches[0], 0, 1) != $delim) { 
+            // no.
+            
+            $start = $this->wiki->addToken(
+                $this->rule, array('type' => 'start')
+            );
+            
+            $end = $this->wiki->addToken(
+                $this->rule, array('type' => 'end')
+            );
+            
+            return $start . trim($matches[0]) . $end;
+        }
+        
+        // the line starts with a delimiter.  read in the delimited
+        // token number, check the token, and see if we should
+        // skip it.
+        
+        // loop starting at the second character (we already know
+        // the first is a delimiter) until we find another
+        // delimiter; the text between them is a token key number.
+        $key = '';
+        $len = strlen($matches[0]);
+        for ($i = 1; $i < $len; $i++) {
+            $char = $matches[0]{$i};
+            if ($char == $delim) {
+                break;
+            } else {
+                $key .= $char;
+            }
+        }
+        
+        // look at the token and see if it's skippable (if we skip,
+        // it will not be marked as a paragraph)
+        $token_type = strtolower($this->wiki->tokens[$key][0]);
+        $skip = $this->getConf('skip', array());
+        
+        if (in_array($token_type, $skip)) {
+            // this type of token should not have paragraphs applied to it.
+            // return the entire matched text.
+            return $matches[0];
+        } else {
+            
+            $start = $this->wiki->addToken(
+                $this->rule, array('type' => 'start')
+            );
+            
+            $end = $this->wiki->addToken(
+                $this->rule, array('type' => 'end')
+            );
+            
+            return $start . trim($matches[0]) . $end;
+        }
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Mediawiki/Phplookup.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,73 @@
+<?php
+
+/**
+* 
+* Find source text marked for lookup in the PHP online manual.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Phplookup.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Find source text marked for lookup in the PHP online manual.
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Phplookup extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * The regular expression used to parse the source text and find
+    * matches conforming to this rule.  Used by the parse() method.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    * @see parse()
+    * 
+    */
+    
+    var $regex = "/\[\[php (.+?)\]\]/";
+    
+    
+    /**
+    * 
+    * Generates a replacement for the matched text.  Token options are:
+    * 
+    * 'type' => ['start'|'end'] The starting or ending point of the
+    * teletype text.  The text itself is left in the source.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return string A pair of delimited tokens to be used as a
+    * placeholder in the source text surrounding the teletype text.
+    *
+    */
+    
+    function process(&$matches)
+    {
+        return $this->wiki->addToken(
+            $this->rule, array('text' => $matches[1])
+        );
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Mediawiki/Prefilter.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,78 @@
+<?php
+
+/**
+* 
+* "Pre-filter" the source text.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Prefilter.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* "Pre-filter" the source text.
+* 
+* Convert DOS and Mac line endings to Unix, concat lines ending in a
+* backslash \ with the next line, convert tabs to 4-spaces, add newlines
+* to the top and end of the source text, compress 3 or more newlines to
+* 2 newlines.
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Prefilter extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * Simple parsing method.
+    *
+    * @access public
+    * 
+    */
+    
+    function parse()
+    {
+        // convert DOS line endings
+        $this->wiki->source = str_replace("\r\n", "\n",
+            $this->wiki->source);
+        
+        // convert Macintosh line endings
+        $this->wiki->source = str_replace("\r", "\n",
+            $this->wiki->source);
+        
+        // concat lines ending in a backslash
+        $this->wiki->source = str_replace("\\\n", "",
+            $this->wiki->source);
+        
+        // convert tabs to four-spaces
+        $this->wiki->source = str_replace("\t", "    ",
+            $this->wiki->source);
+           
+        // add extra newlines at the top and end; this
+        // seems to help many rules.
+        $this->wiki->source = "\n" . $this->wiki->source . "\n\n";
+        
+        // finally, compress all instances of 3 or more newlines
+        // down to two newlines.
+        $find = "/\n{3,}/m";
+        $replace = "\n\n";
+        $this->wiki->source = preg_replace($find, $replace,
+            $this->wiki->source);
+    }
+
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Mediawiki/Raw.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,73 @@
+<?php
+
+/**
+* 
+* Parses for text marked as "raw" (i.e., to be rendered as-is).
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Raw.php,v 1.2 2006/02/15 10:20:08 toggg Exp $
+* 
+*/
+
+/**
+* 
+* Parses for text marked as "raw" (i.e., to be rendered as-is).
+* 
+* This class implements a Text_Wiki rule to find sections of the source
+* text that are not to be processed by Text_Wiki.  These blocks of "raw"
+* text will be rendered as they were found.
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Raw extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * The regular expression used to find source text matching this
+    * rule.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    */
+    
+    var $regex = "/<nowiki>(.*)<\/nowiki>/Ums";
+    
+    
+    /**
+    * 
+    * Generates a token entry for the matched text.  Token options are:
+    * 
+    * 'text' => The full matched text.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return A delimited token number to be used as a placeholder in
+    * the source text.
+    *
+    */
+    
+    function process(&$matches)
+    {
+        $options = array('text' => $matches[1]);
+        return $this->wiki->addToken($this->rule, $options);
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Mediawiki/Revise.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,145 @@
+<?php
+
+/**
+* 
+* Parses for text marked as revised (insert/delete).
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Revise.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Parses for text marked as revised (insert/delete).
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Revise extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * The regular expression used to parse the source text and find
+    * matches conforming to this rule.  Used by the parse() method.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    * @see parse()
+    * 
+    */
+    
+    var $regex = "/\@\@({*?.*}*?)\@\@/U";
+    
+    
+    /**
+    * 
+    * Config options.
+    * 
+    * @access public
+    * 
+    * @var array
+    *
+    */
+    
+    var $conf = array(
+        'delmark' => '---',
+        'insmark' => '+++'
+    );
+    
+    
+    /**
+    * 
+    * Generates a replacement for the matched text.  Token options are:
+    * 
+    * 'type' => ['start'|'end'] The starting or ending point of the
+    * inserted text.  The text itself is left in the source.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return string A pair of delimited tokens to be used as a
+    * placeholder in the source text surrounding the teletype text.
+    *
+    */
+    
+    function process(&$matches)
+    {
+        $output = '';
+        $src = $matches[1];
+        $delmark = $this->getConf('delmark'); // ---
+        $insmark = $this->getConf('insmark'); // +++
+        
+        // '---' must be before '+++' (if they both appear)
+        $del = strpos($src, $delmark);
+        $ins = strpos($src, $insmark);
+        
+        // if neither is found, return right away
+        if ($del === false && $ins === false) {
+            return $matches[0];
+        }
+        
+        // handle text to be deleted
+        if ($del !== false) {
+            
+            // move forward to the end of the deletion mark
+            $del += strlen($delmark);
+            
+            if ($ins === false) {
+                // there is no insertion text following
+                $text = substr($src, $del);
+            } else {
+                // there is insertion text following,
+                // mitigate the length
+                $text = substr($src, $del, $ins - $del);
+            }
+            
+            $output .= $this->wiki->addToken(
+                $this->rule, array('type' => 'del_start')
+            );
+            
+            $output .= $text;
+            
+            $output .= $this->wiki->addToken(
+                $this->rule, array('type' => 'del_end')
+            );
+        }
+        
+        // handle text to be inserted
+        if ($ins !== false) {
+            
+            // move forward to the end of the insert mark
+            $ins += strlen($insmark);
+            $text = substr($src, $ins);
+            
+            $output .= $this->wiki->addToken(
+                $this->rule, array('type' => 'ins_start')
+            );
+            
+            $output .= $text;
+            
+            $output .= $this->wiki->addToken(
+                $this->rule, array('type' => 'ins_end')
+            );
+        }
+        
+        return $output;
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Mediawiki/Smiley.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,157 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Default: Parses for smileys / emoticons tags
+ *
+ * This class implements a Text_Wiki_Rule to find source text marked as
+ * smileys defined by symbols as ':)' , ':-)' or ':smile:'
+ * The symbol is replaced with a token.
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Bertrand Gugger <bertrand@toggg.com>
+ * @copyright  2005 bertrand Gugger
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Smiley.php,v 1.6 2005/10/04 08:17:51 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * Smiley rule parser class for Default.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Bertrand Gugger <bertrand@toggg.com>
+ * @copyright  2005 bertrand Gugger
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ * @see        Text_Wiki_Parse::Text_Wiki_Parse()
+ */
+class Text_Wiki_Parse_Smiley extends Text_Wiki_Parse {
+
+    /**
+     * Configuration keys for this rule
+     * 'smileys' => array Smileys recognized by this rule, symbols key definitions:
+     *              'symbol' => array ( 'name', 'description' [, 'variante', ...] ) as
+     *                  ':)'  => array('smile', 'Smile'),
+     *                  ':D'  => array('biggrin', 'Very Happy',':grin:'),
+     *              the eventual elements after symbol and description are variantes
+     *
+     * 'auto_nose' => boolean enabling the auto nose feature:
+     *                auto build a variante for 2 chars symbols by inserting a '-' as ':)' <=> ':-)'
+     *
+     * @access public
+     * @var array 'config-key' => mixed config-value
+     */
+    var $conf = array(
+        'smileys' => array(
+            ':D'        => array('biggrin', 'Very Happy', ':grin:'),
+            ':)'        => array('smile', 'Smile', '(:'),
+            ':('        => array('sad', 'Sad', '):'),
+            ':o'        => array('surprised', 'Surprised', ':eek:', 'o:'),
+            ':shock:'   => array('eek', 'Shocked'),
+            ':?'        => array('confused', 'Confused', ':???:'),
+            '8)'        => array('cool', 'Cool', '(8'),
+            ':lol:'     => array('lol', 'Laughing'),
+            ':x'        => array('mad', 'Mad'),
+            ':P'        => array('razz', 'Razz'),
+            ':oops:'    => array('redface', 'Embarassed'),
+            ':cry:'     => array('cry', 'Crying or Very sad'),
+            ':evil:'    => array('evil', 'Evil or Very Mad'),
+            ':twisted:' => array('twisted', 'Twisted Evil'),
+            ':roll:'    => array('rolleyes', 'Rolling Eyes'),
+            ';)'        => array('wink', 'Wink', '(;'),
+            ':!:'       => array('exclaim', 'Exclamation'),
+            ':?:'       => array('question', 'Question'),
+            ':idea:'    => array('idea', 'Idea'),
+            ':arrow:'   => array('arrow', 'Arrow'),
+            ':|'        => array('neutral', 'Neutral', '|:'),
+            ':mrgreen:' => array('mrgreen', 'Mr. Green'),
+        ),
+        'auto_nose' => true
+    );
+
+    /**
+     * Definition array of smileys, variantes references their model
+     * 'symbol' => array ( 'name', 'description')
+     *
+     * @access private
+     * @var array 'config-key' => mixed config-value
+     */
+    var $_smileys = array();
+
+     /**
+     * Constructor.
+     * We override the constructor to build up the regex from config
+     *
+     * @param object &$obj the base conversion handler
+     * @return The parser object
+     * @access public
+     */
+    function Text_Wiki_Parse_Smiley(&$obj)
+    {
+        $default = $this->conf;
+        parent::Text_Wiki_Parse($obj);
+
+        // read the list of smileys to sort out variantes and :xxx: while building the regexp
+        $this->_smileys = $this->getConf('smileys', $default['smileys']);
+        $autoNose = $this->getConf('auto_nose', $default['auto_nose']);
+        $reg1 = $reg2 = '';
+        $sep1 = ':(?:';
+        $sep2 = '';
+        foreach ($this->_smileys as $smiley => $def) {
+            for ($i = 1; $i < count($def); $i++) {
+                if ($i > 1) {
+                    $cur = $def[$i];
+                    $this->_smileys[$cur] = &$this->_smileys[$smiley];
+                } else {
+                    $cur = $smiley;
+                }
+                $len = strlen($cur);
+                if (($cur{0} == ':') && ($len > 2) && ($cur{$len - 1} == ':')) {
+                    $reg1 .= $sep1 . preg_quote(substr($cur, 1, -1), '#');
+                    $sep1 = '|';
+                    continue;
+                }
+                if ($autoNose && ($len === 2)) {
+                    $variante = $cur{0} . '-' . $cur{1};
+                    $this->_smileys[$variante] = &$this->_smileys[$smiley];
+                    $cur = preg_quote($cur{0}, '#') . '-?' . preg_quote($cur{1}, '#');
+                } else {
+                    $cur = preg_quote($cur, '#');
+                }
+                $reg2 .= $sep2 . $cur;
+                $sep2 = '|';
+            }
+        }
+        $delim = '[\n\r\s' . $this->wiki->delim . '$^]';
+        $this->regex = '#(?<=' . $delim .
+             ')(' . ($reg1 ? $reg1 . '):' . ($reg2 ? '|' : '') : '') . $reg2 .
+             ')(?=' . $delim . ')#i';
+    }
+
+    /**
+     * Generates a replacement token for the matched text.  Token options are:
+     *     'symbol' => the original marker
+     *     'name' => the name of the smiley
+     *     'desc' => the description of the smiley
+     *
+     * @param array &$matches The array of matches from parse().
+     * @return string Delimited token representing the smiley
+     * @access public
+     */
+    function process(&$matches)
+    {
+        // tokenize
+        return $this->wiki->addToken($this->rule,
+            array(
+                'symbol' => $matches[1],
+                'name'   => $this->_smileys[$matches[1]][0],
+                'desc'   => $this->_smileys[$matches[1]][1]
+            ));
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Mediawiki/Strong.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,86 @@
+<?php
+
+/**
+* 
+* Parses for strongly-emphasized text.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Strong.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+
+/**
+* 
+* Parses for strongly-emphasized text.
+* 
+* This class implements a Text_Wiki_Parse to find source text marked for
+* strong emphasis (bold) as defined by text surrounded by three
+* single-quotes. On parsing, the text itself is left in place, but the
+* starting and ending instances of three single-quotes are replaced with
+* tokens.
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Strong extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * The regular expression used to parse the source text and find
+    * matches conforming to this rule.  Used by the parse() method.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    * @see parse()
+    * 
+    */
+    
+    var $regex =  "/\*\*(.*?)\*\*/";
+    
+    
+    /**
+    * 
+    * Generates a replacement for the matched text.  Token options are:
+    * 
+    * 'type' => ['start'|'end'] The starting or ending point of the
+    * emphasized text.  The text itself is left in the source.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return A pair of delimited tokens to be used as a placeholder in
+    * the source text surrounding the text to be emphasized.
+    *
+    */
+    
+    function process(&$matches)
+    {
+        $start = $this->wiki->addToken(
+            $this->rule, array('type' => 'start')
+        );
+        
+        $end = $this->wiki->addToken(
+            $this->rule, array('type' => 'end')
+        );
+        
+        return $start . $matches[1] . $end;
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Mediawiki/Subscript.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,79 @@
+<?php
+
+/**
+* 
+* Parses for subscripted text.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Subscript.php,v 1.1 2005/02/24 17:24:56 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Parses for subscripted text.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Subscript extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * The regular expression used to parse the source text and find
+    * matches conforming to this rule.  Used by the parse() method.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    * @see parse()
+    * 
+    */
+    
+    var $regex =  "/,,(()|.*),,/U";
+    
+    
+    /**
+    * 
+    * Generates a replacement for the matched text.  Token options are:
+    * 
+    * 'type' => ['start'|'end'] The starting or ending point of the
+    * emphasized text.  The text itself is left in the source.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return A pair of delimited tokens to be used as a placeholder in
+    * the source text surrounding the text to be emphasized.
+    *
+    */
+    
+    function process(&$matches)
+    {
+        $start = $this->wiki->addToken(
+            $this->rule, array('type' => 'start')
+        );
+        
+        $end = $this->wiki->addToken(
+            $this->rule, array('type' => 'end')
+        );
+        
+        return $start . $matches[1] . $end;
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Mediawiki/Superscript.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,79 @@
+<?php
+
+/**
+* 
+* Parses for superscripted text.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Superscript.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Parses for superscripted text.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Superscript extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * The regular expression used to parse the source text and find
+    * matches conforming to this rule.  Used by the parse() method.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    * @see parse()
+    * 
+    */
+    
+    var $regex =  "/\^\^(()|.*)\^\^/U";
+    
+    
+    /**
+    * 
+    * Generates a replacement for the matched text.  Token options are:
+    * 
+    * 'type' => ['start'|'end'] The starting or ending point of the
+    * emphasized text.  The text itself is left in the source.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return A pair of delimited tokens to be used as a placeholder in
+    * the source text surrounding the text to be emphasized.
+    *
+    */
+    
+    function process(&$matches)
+    {
+        $start = $this->wiki->addToken(
+            $this->rule, array('type' => 'start')
+        );
+        
+        $end = $this->wiki->addToken(
+            $this->rule, array('type' => 'end')
+        );
+        
+        return $start . $matches[1] . $end;
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Mediawiki/Table.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,286 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Mediawiki: Parses for tables.
+ *
+ * This class implements a Text_Wiki_Rule to find tables in pipe syntax
+ * {| ... |- ... | ... |}
+ * On parsing, the text itself is left in place, but the starting and ending
+ * tags for table, rows and cells are replaced with tokens. (nested tables enabled)
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Bertrand Gugger <bertrand@toggg.com>
+ * @copyright  2005 bertrand Gugger
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Table.php,v 1.7 2005/12/06 15:54:56 ritzmo Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * Table rule parser class for Mediawiki.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Bertrand Gugger <bertrand@toggg.com>
+ * @copyright  2005 bertrand Gugger
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ * @see        Text_Wiki_Parse::Text_Wiki_Parse()
+ */
+class Text_Wiki_Parse_Table extends Text_Wiki_Parse {
+
+    /**
+     * The regular expression used to parse the source text and find
+     * matches conforming to this rule.  Used by the parse() method.
+     *
+     * @access public
+     * @var string
+     * @see parse()
+     */
+    var $regex = '#^\{\|(.*?)(?:^\|\+(.*?))?(^(?:((?R))|.)*?)^\|}#msi';
+
+    /**
+     * The regular expression used in second stage to find table's rows
+     * used by process() to call back processRows()
+     *
+     * @access public
+     * @var string
+     * @see process()
+     * @see processRows()
+     */
+    var $regexRows = '#(?:^(\||!)-|\G)(.*?)^(.*?)(?=^(?:\|-|!-|\z))#msi';
+
+    /**
+     * The regular expression used in third stage to find rows's cells
+     * used by processRows() to call back processCells()
+     *
+     * @access public
+     * @var string
+     * @see process()
+     * @see processCells()
+     */
+    var $regexCells =
+    '#((?:^\||^!|\|\||!!|\G))(?:([^|\n]*?) \|(?!\|))?(.+?)(?=^\||^!|\|\||!!|\z)#msi';
+
+    /**
+     * The current table nesting depth, starts by zero
+     *
+     * @access private
+     * @var int
+     */
+    var $_level = 0;
+
+    /**
+     * The count of rows for this level
+     *
+     * @access private
+     * @var array of int
+     */
+    var $_countRows = array();
+
+    /**
+     * The max count of cells for this level
+     *
+     * @access private
+     * @var array of int
+     */
+    var $_maxCells = array();
+
+    /**
+     * The count of cells for each row
+     *
+     * @access private
+     * @var array of int
+     */
+    var $_countCells = array();
+
+    /**
+     * The count of spanned cells from previous rowspans for each column
+     *
+     * @access private
+     * @var array of int
+     */
+    var $_spanCells = array();
+
+    /**
+     * Generates a replacement for the matched text. Returned token options are:
+     * 'type' =>
+     *     'table_start'   : the start of a bullet list
+     *     'table_end'     : the end of a bullet list
+     *     'row_start'     : the start of a number list
+     *     'row_end'       : the end of a number list
+     *     'cell_start'    : the start of item text (bullet or number)
+     *     'cell_end'      : the end of item text (bullet or number)
+     *     'caption_start' : the start of associated caption
+     *     'caption_end'   : the end of associated caption
+     *
+     * 'level' => the table nesting level (starting zero) ('table_start')
+     *
+     * 'rows' => the number of rows in the table ('table_start')
+     *
+     * 'cols' => the number of columns in the table or rows
+     *           ('table_start' and 'row_start')
+     *
+     * 'span' => column span ('cell_start')
+     *
+     * 'row_span' => row span ('cell_start')
+     *
+     * 'attr' => header optional attribute flag ('row_start' or 'cell_start')
+     *
+     * 'format' => table, row or cell optional styling ('xxx_start')
+     *
+     * @param array &$matches The array of matches from parse().
+     * @return string the original text with tags replaced by delimited tokens
+     * which point to the the token array containing their type and definition
+     * @access public
+     */
+    function process(&$matches)
+    {
+        if (array_key_exists(4, $matches)) {
+            $this->_level++;
+            $expsub = preg_replace_callback(
+                $this->regex,
+                array(&$this, 'process'),
+                $matches[3]
+            );
+            $this->_level--;
+        } else {
+            $expsub = $matches[3];
+        }
+        $this->_countRows[$this->_level] = $this->_maxCells[$this->_level] = 0;
+        $this->_countCells[$this->_level] = $this->_spanCells[$this->_level] = array();
+        $sub = preg_replace_callback(
+            $this->regexRows,
+            array(&$this, 'processRows'),
+            $expsub
+        );
+        $param = array(
+                'type'  => 'table_start',
+                'level' => $this->_level,
+                'rows' => $this->_countRows[$this->_level],
+                'cols' => $this->_maxCells[$this->_level]
+        );
+        if ($format = trim($matches[1])) {
+            $param['format'] = $format;
+        }
+        $ret = $this->wiki->addToken($this->rule, $param );
+        if ($matches[2]) {
+            $ret .= $this->wiki->addToken($this->rule, array(
+                'type'  => 'caption_start',
+                'level' => $this->_level ) ) . $matches[2] .
+                    $this->wiki->addToken($this->rule, array(
+                'type'  => 'caption_end',
+                'level' => $this->_level ) );
+        }
+        $param['type'] = 'table_end';
+        return $ret . $sub . $this->wiki->addToken($this->rule, $param );
+    }
+
+    /**
+     * Generates a replacement for the matched rows. Token options are:
+     * 'type' =>
+     *     'row_start'   : the start of a row
+     *     'row_end'     : the end of a row
+     *
+     * 'order' => the row order in the table
+     *
+     * 'cols' => the count of cells in the row
+     *
+     * 'attr' => header optional attribute flag
+     *
+     * 'format' => row optional styling
+     *
+     * @param array &$matches The array of matches from process() callback.
+     * @return string 2 delimited tokens pointing the row params
+     * and containing the cells-parsed block of text between the tags
+     * @access public
+     */
+    function processRows(&$matches)
+    {
+        $this->_countCells[$this->_level][$this->_countRows[$this->_level]] = 0;
+        $sub = preg_replace_callback(
+            $this->regexCells,
+            array(&$this, 'processCells'),
+            $matches[3]
+        );
+        $param = array(
+                'type'  => 'row_start',
+                'order' => $this->_countRows[$this->_level],
+                'cols' => $this->_countCells[$this->_level][$this->_countRows[$this->_level]++]
+        );
+        if ($matches[1] == '!') {
+            $param['attr'] = 'header';
+        }
+        if ($format = trim($matches[2])) {
+            $param['format'] = $format;
+        }
+        if ($this->_maxCells[$this->_level] < $param['cols']) {
+            $this->_maxCells[$this->_level] = $param['cols'];
+        }
+        $ret = $this->wiki->addToken($this->rule, $param );
+        $param['type'] = 'row_end';
+        return $ret . $sub . $this->wiki->addToken($this->rule, $param );
+    }
+
+    /**
+     * Generates a replacement for the matched cells. Token options are:
+     * 'type' =>
+     *     'cell_start'   : the start of a row
+     *     'cell_end'     : the end of a row
+     *
+     * 'order' => the cell order in the row
+     *
+     * 'cols' => the count of cells in the row
+     *
+     * 'span' => column span
+     *
+     * 'row_span' => row span
+     *
+     * 'attr' => header optional attribute flag
+     *
+     * 'format' => cell optional styling
+     *
+     * @param array &$matches The array of matches from processRows() callback.
+     * @return string 2 delimited tokens pointing the cell params
+     * and containing the block of text between the tags
+     * @access public
+     */
+    function processCells(&$matches)
+    {
+        $order = & $this->_countCells[$this->_level][$this->_countRows[$this->_level]];
+        while (isset($this->_spanCells[$this->_level][$order])) {
+            if (--$this->_spanCells[$this->_level][$order] < 2) {
+                unset($this->_spanCells[$this->_level][$order]);
+            }
+            $order++;
+        }
+        $param = array(
+                'type'  => 'cell_start',
+                'attr'  => $matches[1] && ($matches[1]{0} == '!') ? 'header': null,
+                'span'  => 1,
+                'rowspan'  => 1,
+                'order' => $order
+        );
+        if ($format = trim($matches[2])) {
+            if (preg_match('#(.*)colspan=("|\')?(\d+)(?(2)\2)(.*)#i', $format, $pieces)) {
+                $param['span'] = (int)$pieces[3];
+                $format = $pieces[1] . $pieces[4];
+            }
+            if (preg_match('#(.*)rowspan=("|\')?(\d+)(?(2)\2)(.*)#i', $format, $pieces)) {
+                $this->_spanCells[$this->_level][$order] =
+                                    $param['rowspan'] = (int)$pieces[3];
+                $format = $pieces[1] . $pieces[4];
+            }
+            $param['format'] = $format;
+        }
+        $this->_countCells[$this->_level][$this->_countRows[$this->_level]] += $param['span'];
+        $ret = $this->wiki->addToken($this->rule, $param);
+        $param['type'] = 'cell_end';
+        return $ret . $matches[3] . $this->wiki->addToken($this->rule, $param );
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Mediawiki/Tighten.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,49 @@
+<?php
+
+/**
+* 
+* The rule removes all remaining newlines.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Tighten.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+
+/**
+* 
+* The rule removes all remaining newlines.
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Tighten extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * Apply tightening directly to the source text.
+    *
+    * @access public
+    * 
+    */
+    
+    function parse()
+    {
+        $this->wiki->source = str_replace("\n", '',
+            $this->wiki->source);
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Mediawiki/Toc.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,130 @@
+<?php
+
+/**
+* 
+* Looks through parsed text and builds a table of contents.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Toc.php,v 1.4 2005/05/28 21:33:02 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Looks through parsed text and builds a table of contents.
+* 
+* This class implements a Text_Wiki_Parse to find all heading tokens and
+* build a table of contents.  The [[toc]] tag gets replaced with a list
+* of all the level-2 through level-6 headings.
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+
+class Text_Wiki_Parse_Toc extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * The regular expression used to parse the source text and find
+    * matches conforming to this rule.  Used by the parse() method.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    * @see parse()
+    * 
+    */
+    
+    var $regex = "/\n\[\[toc( .*)?\]\]\n/m";
+    
+    
+    /**
+    * 
+    * Generates a replacement for the matched text.
+    *  
+    * Token options are:
+    * 
+    * 'type' => ['list_start'|'list_end'|'item_start'|'item_end'|'target']
+    *
+    * 'level' => The heading level (1-6).
+    *
+    * 'count' => Which entry number this is in the list.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return string A token indicating the TOC collection point.
+    *
+    */
+    
+    function process(&$matches)
+    {
+        $count = 0;
+        
+        if (isset($matches[1])) {
+            $attr = $this->getAttrs(trim($matches[1]));
+        } else {
+            $attr = array();
+        }
+        
+        $output = $this->wiki->addToken(
+            $this->rule,
+            array(
+                'type' => 'list_start',
+                'level' => 0,
+                'attr' => $attr
+            )
+        );
+        
+        foreach ($this->wiki->getTokens('Heading') as $key => $val) {
+            
+            if ($val[1]['type'] != 'start') {
+                continue;
+            }
+            
+            $options = array(
+                'type'  => 'item_start',
+                'id'    => $val[1]['id'],
+                'level' => $val[1]['level'],
+                'count' => $count ++
+            );
+            
+            $output .= $this->wiki->addToken($this->rule, $options);
+            
+            $output .= $val[1]['text'];
+            
+            $output .= $this->wiki->addToken(
+                $this->rule,
+                array(
+                    'type' => 'item_end',
+                    'level' => $val[1]['level']
+                )
+            );
+        }
+        
+        $output .= $this->wiki->addToken(
+            $this->rule, array(
+                'type' => 'list_end',
+                'level' => 0
+            )
+        );
+        
+        return "\n$output\n";
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Mediawiki/Tt.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,84 @@
+<?php
+
+/**
+* 
+* Find source text marked for teletype (monospace).
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Tt.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
+* 
+*/
+
+/**
+* 
+* Find source text marked for teletype (monospace).
+* 
+* Defined by text surrounded by two curly braces. On parsing, the text
+* itself is left in place, but the starting and ending instances of
+* curly braces are replaced with tokens.
+* 
+* Token options are:
+* 
+* 'type' => ['start'|'end'] The starting or ending point of the
+* teletype text.  The text itself is left in the source.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Tt extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * The regular expression used to parse the source text.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    * @see parse()
+    * 
+    */
+    
+    var $regex = "/{{({*?.*}*?)}}/U";
+    
+    
+    /**
+    * 
+    * Generates a replacement for the matched text. 
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return string A pair of delimited tokens to be used as a
+    * placeholder in the source text surrounding the teletype text.
+    *
+    */
+    
+    function process(&$matches)
+    {
+        $start = $this->wiki->addToken(
+            $this->rule, array('type' => 'start')
+        );
+        
+        $end = $this->wiki->addToken(
+            $this->rule, array('type' => 'end')
+        );
+        
+        return $start . $matches[1] . $end;
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Mediawiki/Underline.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,79 @@
+<?php
+
+/**
+* 
+* Parses for bold text.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Underline.php,v 1.1 2005/07/10 20:40:20 justinpatrin Exp $
+* 
+*/
+
+/**
+* 
+* Parses for bold text.
+* 
+* This class implements a Text_Wiki_Rule to find source text marked for
+* strong emphasis (bold) as defined by text surrounded by three
+* single-quotes. On parsing, the text itself is left in place, but the
+* starting and ending instances of three single-quotes are replaced with
+* tokens.
+*
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+*/
+
+class Text_Wiki_Parse_Underline extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * The regular expression used to parse the source text and find
+    * matches conforming to this rule.  Used by the parse() method.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    * @see parse()
+    * 
+    */
+    
+    var $regex =  "/__(()|[^_].*)__/U";
+    
+    
+    /**
+    * 
+    * Generates a replacement for the matched text.  Token options are:
+    * 
+    * 'type' => ['start'|'end'] The starting or ending point of the
+    * emphasized text.  The text itself is left in the source.
+    * 
+    * @access public
+    *
+    * @param array &$matches The array of matches from parse().
+    *
+    * @return A pair of delimited tokens to be used as a placeholder in
+    * the source text surrounding the text to be emphasized.
+    *
+    */
+    
+    function process(&$matches)
+    {
+        $start = $this->wiki->addToken($this->rule, array('type' => 'start'));
+        $end = $this->wiki->addToken($this->rule, array('type' => 'end'));
+        return $start . $matches[1] . $end;
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Mediawiki/Url.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,355 @@
+<?php
+
+/**
+* 
+* Parse for URLS in the source text.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @author Moritz Venn <moritz.venn@freaque.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Url.php,v 1.1 2005/12/06 15:54:56 ritzmo Exp $
+* 
+*/
+
+/**
+* 
+* Parse for URLS in the source text.
+* 
+* Various URL markings are supported: inline (the URL by itself),
+* inline (where the URL is enclosed in square brackets), and named
+* reference (where the URL is enclosed in square brackets and has a
+* name included inside the brackets).  E.g.:
+*
+* inline      -- http://example.com
+* undescribed -- [http://example.com]
+* described   -- [http://example.com Example Description]
+* described   -- [http://www.example.com|Example Description]
+*
+* When rendering a URL token, this will convert URLs pointing to a .gif,
+* .jpg, or .png image into an inline <img /> tag (for the 'xhtml'
+* format).
+*
+* Token options are:
+* 
+* 'type' => ['inline'|'footnote'|'descr'] the type of URL
+* 
+* 'href' => the URL link href portion
+* 
+* 'text' => the displayed text of the URL link
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @author Moritz Venn <moritz.venn@freaque.net>
+* 
+*/
+
+class Text_Wiki_Parse_Url extends Text_Wiki_Parse {
+    
+    
+    /**
+    * 
+    * Keeps a running count of numbered-reference URLs.
+    * 
+    * @access public
+    * 
+    * @var int
+    * 
+    */
+    
+    var $footnoteCount = 0;
+    
+    
+    /**
+    * 
+    * URL schemes recognized by this rule.
+    * 
+    * @access public
+    * 
+    * @var array
+    * 
+    */
+    
+    var $conf = array(
+        'schemes' => array(
+            'http://',
+            'https://',
+            'ftp://',
+            'gopher://',
+            'news://',
+            'mailto:',
+            'irc://'
+        )
+    );
+    
+    
+    /**
+    * 
+    * Constructor.
+    * 
+    * We override the constructor so we can comment the regex nicely.
+    * 
+    * @access public
+    * 
+    */
+    
+    function Text_Wiki_Parse_Url(&$obj)
+    {
+        parent::Text_Wiki_Parse($obj);
+        
+        // convert the list of recognized schemes to a regex-safe string,
+        // where the pattern delim is a slash
+        $tmp = array();
+        $list = $this->getConf('schemes', array());
+        foreach ($list as $val) {
+            $tmp[] = preg_quote($val, '/');
+        }
+        $schemes = implode('|', $tmp);
+        
+        // build the regex
+        $this->regex =
+            "($schemes)" . // allowed schemes
+            "(" . // start pattern
+            "[^ \\/\"\'{$this->wiki->delim}]*\\/" . // no spaces, backslashes, slashes, double-quotes, single quotes, or delimiters;
+            ")*" . // end pattern
+            "[^ \\t\\n\\/\"\'{$this->wiki->delim}]*" .
+            "[A-Za-z0-9\\/?=&~_]";
+            // fix for jEdit syntax highlighting bug: \"
+    }
+    
+    
+    /**
+    * 
+    * Find three different kinds of URLs in the source text.
+    *
+    * @access public
+    * 
+    */
+    
+    function parse()
+    {
+        // -------------------------------------------------------------
+        // 
+        // Described-reference (named) URLs.
+        // 
+
+        // the regular expression for this kind of URL
+        $tmp_regex = '/\[(' . $this->regex . ')[ |]([^\]]+)\]/';
+
+        // use a custom callback processing method to generate
+        // the replacement text for matches.
+        $this->wiki->source = preg_replace_callback(
+            $tmp_regex,
+            array(&$this, 'processDescr'),
+            $this->wiki->source
+        );
+
+        
+        // -------------------------------------------------------------
+        // 
+        // Unnamed-reference ('Ordinary'-style) URLs.
+        // 
+        
+        // the regular expression for this kind of URL
+        $tmp_regex = '/\[(' . $this->regex . ')\]/U';
+        
+        // use a custom callback processing method to generate
+        // the replacement text for matches.
+        $this->wiki->source = preg_replace_callback(
+            $tmp_regex,
+            //array(&$this, 'processFootnote'),
+            array(&$this, 'processOrdinary'),
+            $this->wiki->source
+        );
+        
+        
+        // -------------------------------------------------------------
+        // 
+        // Normal inline URLs.
+        // 
+        
+        /*
+        
+        ## DISABLED FOR ENANO
+        ## This messes up HTML links.
+        
+        // the regular expression for this kind of URL
+        
+        $tmp_regex = '/(^|[^A-Za-z])(' . $this->regex . ')(.*?)/';
+        
+        // use the standard callback for inline URLs
+        $this->wiki->source = preg_replace_callback(
+            $tmp_regex,
+            array(&$this, 'process'),
+            $this->wiki->source
+        );
+
+        //$tmp_regex = '/(^|[^A-Za-z])([a-zA-Z])(.*?)/';
+        $tmp_regex = '/(^|\s)([a-zA-Z0-9\-]+\.[a-zA-Z0-9\-]+(\.[a-zA-Z0-9\-]+)+)($|\s)/';
+        
+        // use the standard callback for inline URLs
+        $this->wiki->source = preg_replace_callback(
+            $tmp_regex,
+            array(&$this, 'processWithoutProtocol'),
+            $this->wiki->source
+        );
+
+        $tmp_regex = '/(^|\s|'.$this->wiki->delim.')<([a-zA-Z0-9\-\.%_\+\!\*\'\(\)\,]+@[a-zA-Z0-9\-]+(\.[a-zA-Z0-9\-]+)+)>(\s|'.$this->wiki->delim.'|$)/';
+        
+        // use the standard callback for inline URLs
+        $this->wiki->source = preg_replace_callback(
+            $tmp_regex,
+            array(&$this, 'processInlineEmail'),
+            $this->wiki->source
+        );
+        */
+    }
+    
+    
+    /**
+    * 
+    * Process inline URLs.
+    * 
+    * @param array &$matches
+    * 
+    * @param array $matches An array of matches from the parse() method
+    * as generated by preg_replace_callback.  $matches[0] is the full
+    * matched string, $matches[1] is the first matched pattern,
+    * $matches[2] is the second matched pattern, and so on.
+    * 
+    * @return string The processed text replacement.
+    * 
+    */ 
+    
+    function process(&$matches)
+    {
+        // set options
+        $options = array(
+            'type' => 'inline',
+            'href' => $matches[2],
+            'text' => $matches[2]
+        );
+        
+        // tokenize
+        return $matches[1] . $this->wiki->addToken($this->rule, $options) . $matches[5];
+    }
+
+    function processWithoutProtocol(&$matches)
+    {
+        // set options
+        $options = array(
+            'type' => 'inline',
+            'href' => 'http://'.$matches[2],
+            'text' => $matches[2]
+        );
+        
+        // tokenize
+        return $matches[1] . $this->wiki->addToken($this->rule, $options) . $matches[4];
+    }
+
+    function processInlineEmail(&$matches)
+    {
+        // set options
+        $options = array(
+            'type' => 'inline',
+            'href' => 'mailto://'.$matches[2],
+            'text' => $matches[2]
+        );
+        
+        // tokenize
+        return $matches[1] . $this->wiki->addToken($this->rule, $options) . $matches[4];
+    }    
+    
+    /**
+    * 
+    * Process numbered (footnote) URLs.
+    * 
+    * Token options are:
+    * @param array &$matches
+    * 
+    * @param array $matches An array of matches from the parse() method
+    * as generated by preg_replace_callback.  $matches[0] is the full
+    * matched string, $matches[1] is the first matched pattern,
+    * $matches[2] is the second matched pattern, and so on.
+    * 
+    * @return string The processed text replacement.
+    * 
+    */ 
+    
+    function processFootnote(&$matches)
+    {
+        // keep a running count for footnotes 
+        $this->footnoteCount++;
+        
+        // set options
+        $options = array(
+            'type' => 'footnote',
+            'href' => $matches[1],
+            'text' => $this->footnoteCount
+        );
+        
+        // tokenize
+        return $this->wiki->addToken($this->rule, $options);
+    }
+    
+     function processOrdinary(&$matches)
+    {
+    	// keep a running count for footnotes 
+        $this->footnoteCount++;
+        
+        // set options
+        $options = array(
+            'type' => 'descr',
+            'href' => $matches[1],
+            'text' => $matches[1]
+        );
+        
+        // tokenize
+        return $this->wiki->addToken($this->rule, $options);
+    }
+    
+    
+    /**
+    * 
+    * Process described-reference (named-reference) URLs.
+    * 
+    * Token options are:
+    *     'type' => ['inline'|'footnote'|'descr'] the type of URL
+    *     'href' => the URL link href portion
+    *     'text' => the displayed text of the URL link
+    * 
+    * @param array &$matches
+    * 
+    * @param array $matches An array of matches from the parse() method
+    * as generated by preg_replace_callback.  $matches[0] is the full
+    * matched string, $matches[1] is the first matched pattern,
+    * $matches[2] is the second matched pattern, and so on.
+    * 
+    * @return string The processed text replacement.
+    * 
+    */ 
+    
+    function processDescr(&$matches)
+    {
+        // set options
+        $options = array(
+            'type' => 'descr',
+            'href' => $matches[1],
+            'text' => $matches[4]
+        );
+
+        // tokenize
+        return $this->wiki->addToken($this->rule, $options);
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Parse/Mediawiki/Wikilink.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,302 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Mediawiki: Parses for links to (inter)wiki pages or images.
+ *
+ * Text_Wiki rule parser to find links, it groups the 3 rules:
+ * # Wikilink: links to internal Wiki pages
+ * # Interwiki: links to external Wiki pages (sister projects, interlangage)
+ * # Image: Images
+ * as defined by text surrounded by double brackets [[]]
+ * Translated are the link itself, the section (anchor) and alternate text
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Bertrand Gugger <bertrand@toggg.com>
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @copyright  2005 bertrand Gugger
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Wikilink.php,v 1.7 2006/02/25 13:34:50 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * Wikilink, Interwiki and Image rules parser class for Mediawiki.
+ * This class implements a Text_Wiki_Parse to find links marked
+ * in source by text surrounded by 2 opening/closing brackets as 
+ * [[Wiki page name#Section|Alternate text]]
+ * On parsing, the link is replaced with a token.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Bertrand Gugger <bertrand@toggg.com>
+ * @copyright  2005 bertrand Gugger
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ * @see        Text_Wiki_Parse::Text_Wiki_Parse()
+ */
+class Text_Wiki_Parse_Wikilink extends Text_Wiki_Parse {
+
+    /**
+     * Configuration for this rule (Wikilink)
+     *
+     * @access public
+     * @var array
+    */
+    var $conf = array(
+        'spaceUnderscore' => true,
+        'project' => array('demo', 'd'),
+        'url' => 'http://example.com/en/page=%s',
+        'langage' => 'en'
+    );
+
+    /**
+     * Configuration for the Image rule
+     *
+     * @access public
+     * @var array
+    */
+    var $imageConf = array(
+        'prefix' => array('Image', 'image')
+    );
+
+    /**
+     * Configuration for the Interwiki rule
+     *
+     * @access public
+     * @var array
+    */
+    var $interwikiConf = array(
+        'sites' => array(
+            'manual' => 'http://www.php.net/manual/en/%s',
+            'pear'   => 'http://pear.php.net/package/%s',
+            'bugs'   => 'http://pear.php.net/package/%s/bugs'
+        ),
+        'interlangage' => array('en', 'de', 'fr')
+    );
+
+    /**
+     * The regular expression used to parse the source text and find
+     * matches conforming to this rule.  Used by the parse() method.
+     *
+     * @access public
+     * @var string
+     * @see Text_Wiki_Parse::parse()
+     */
+    var $regex = '/(?<!\[)\[\[(?!\[)\s*(:?)((?:[^:]+:)+)?([^:]+)(?:#(.*))?\s*(?:\|(((?R))|.*))?]]/msU';
+
+     /**
+     * Constructor.
+     * We override the constructor to get Image and Interwiki config
+     *
+     * @param object &$obj the base conversion handler
+     * @return The parser object
+     * @access public
+     */
+    function Text_Wiki_Parse_Wikilink(&$obj)
+    {
+        $default = $this->conf;
+        parent::Text_Wiki_Parse($obj);
+
+        // override config options for image if specified
+        if (in_array('Image', $this->wiki->disable)) {
+            $this->imageConf['prefix'] = array();
+        } else {
+            if (isset($this->wiki->parseConf['Image']) &&
+                is_array($this->wiki->parseConf['Image'])) {
+                $this->imageConf = array_merge(
+                    $this->imageConf,
+                    $this->wiki->parseConf['Image']
+                );
+            }
+        }
+
+        // override config options for interwiki if specified
+        if (in_array('Interwiki', $this->wiki->disable)) {
+            $this->interwikiConf['sites'] = array();
+            $this->interwikiConf['interlangage'] = array();
+        } else {
+            if (isset($this->wiki->parseConf['Interwiki']) &&
+                is_array($this->wiki->parseConf['Interwiki'])) {
+                $this->interwikiConf = array_merge(
+                    $this->interwikiConf,
+                    $this->wiki->parseConf['Interwiki']
+                );
+            }
+            if (empty($this->conf['langage'])) {
+                $this->interwikiConf['interlangage'] = array();
+            }
+        }
+        // convert the list of recognized schemes to a regex OR,
+/*        $schemes = $this->getConf('schemes', $default['schemes']);
+        $this->url = str_replace( '#delim#', $this->wiki->delim,
+           '#(?:' . (is_array($schemes) ? implode('|', $schemes) : $schemes) . ')://'
+           . $this->getConf('host_regexp', $default['host_regexp'])
+           . $this->getConf('path_regexp', $default['path_regexp']) .'#'); */
+    }
+
+    /**
+     * Generates a replacement for the matched text.  Token options are:
+     * - 'page' => the name of the target wiki page
+     * -'anchor' => the optional section in it
+     * - 'text' => the optional alternate link text
+     *
+     * @access public
+     * @param array &$matches The array of matches from parse().
+     * @return string token to be used as replacement 
+     */
+    function process(&$matches)
+    {
+        // Starting colon ?
+        $colon = !empty($matches[1]);
+        $auto = $interlang = $interwiki = $image = $site = '';
+        // Prefix ?
+        if (!empty($matches[2])) {
+            $prefix = explode(':', substr($matches[2], 0, -1));
+            $count = count($prefix);
+            $i = -1;
+            // Autolink
+            if (isset($this->conf['project']) &&
+                    in_array(trim($prefix[0]), $this->conf['project'])) {
+                $auto = trim($prefix[0]);
+                unset($prefix[0]);
+                $i = 0;
+            }
+            while (++$i < $count) {
+                $prefix[$i] = trim($prefix[$i]);
+                // interlangage
+                if (!$interlang &&
+                    in_array($prefix[$i], $this->interwikiConf['interlangage'])) {
+                    $interlang = $prefix[$i];
+                    unset($prefix[$i]);
+                    continue;
+                }
+                // image
+                if (!$image && in_array($prefix[$i], $this->imageConf['prefix'])) {
+                    $image = $prefix[$i];
+                    unset($prefix[$i]);
+                    break;
+                }
+                // interwiki
+                if (isset($this->interwikiConf['sites'][$prefix[$i]])) {
+                    $interwiki = $this->interwikiConf['sites'][$prefix[$i]];
+                    $site = $prefix[$i];
+                    unset($prefix[$i]);
+                }
+                break;
+            }
+            if ($prefix) {
+                $matches[3] = implode(':', $prefix) . ':' . $matches[3];
+            }
+        }
+        $text = empty($matches[5]) ? $matches[3] : $matches[5];
+        $matches[3] = trim($matches[3]);
+        $matches[4] = empty($matches[4]) ? '' : trim($matches[4]);
+        if ($this->conf['spaceUnderscore']) {
+            $matches[3] = preg_replace('/\s+/', '_', $matches[3]);
+            $matches[4] = preg_replace('/\s+/', '_', $matches[4]);
+        }
+        if ($image) {
+            return $this->image($matches[3] . (empty($matches[4]) ? '' : '#' . $matches[4]),
+                                $text, $interlang, $colon);
+        }
+        if (!$interwiki && $interlang && isset($this->conf['url'])) {
+            if ($interlang == $this->conf['langage']) {
+                $interlang = '';
+            } else {
+                $interwiki = $this->conf['url'];
+                $site = isset($this->conf['project']) ? $this->conf['project'][0] : '';
+            }
+        }
+        if ($interwiki) {
+            return $this->interwiki($site, $interwiki,
+                $matches[3] . (empty($matches[4]) ? '' : '#' . $matches[4]),
+                $text, $interlang, $colon);
+        }
+        if ($interlang) {
+            $matches[3] = $interlang . ':' . $matches[3];
+            $text = (empty($matches[5]) ? $interlang . ':' : '') . $text;
+        }
+        // set the options
+        $options = array(
+            'page'   => $matches[3],
+            'anchor' => (empty($matches[4]) ? '' : $matches[4]),
+            'text'   => $text
+        );
+
+        // create and return the replacement token
+        return $this->wiki->addToken($this->rule, $options);
+    }
+
+    /**
+     * Generates an image token.  Token options are:
+     * - 'src' => the name of the image file
+     * - 'attr' => an array of attributes for the image:
+     * | - 'alt' => the optional alternate image text
+     * | - 'align => 'left', 'center' or 'right'
+     *
+     * @access public
+     * @param array &$matches The array of matches from parse().
+     * @return string token to be used as replacement 
+     */
+    function image($name, $text, $interlang, $colon)
+    {
+        $attr = array('alt' => '');
+        // scan text for supplementary attibutes
+        if (strpos($text, '|') !== false) {
+            $splits = explode('|', $text);
+            $sep = '';
+            foreach ($splits as $split) {
+                switch (strtolower($split)) {
+                    case 'left': case 'center': case 'right':
+                        $attr['align'] = strtolower($split);
+                        break;
+                    default:
+                        $attr['alt'] .= $sep . $split;
+                        $sep = '|';
+                }
+            }
+        } else {
+            $attr['alt'] = $text;
+        }
+        $options = array(
+            'src' => ($interlang ? $interlang . ':' : '') . $name,
+            'attr' => $attr);
+
+        // create and return the replacement token
+        return $this->wiki->addToken('Image', $options);
+    }
+
+    /**
+     * Generates an interwiki token.  Token options are:
+     * - 'page' => the name of the target wiki page
+     * - 'site' => the key for external site
+     * - 'url'  => the full target url
+     * - 'text' => the optional alternate link text
+     *
+     * @access public
+     * @param array &$matches The array of matches from parse().
+     * @return string token to be used as replacement 
+     */
+    function interwiki($site, $interwiki, $page, $text, $interlang, $colon)
+    {
+        if ($interlang) {
+            $interwiki = preg_replace('/\b' . $this->conf['langage'] . '\b/i',
+                            $interlang, $interwiki);
+        }
+        // set the options
+        $options = array(
+            'page' => $page,
+            'site' => $site,
+            'url'  => sprintf($interwiki, $page),
+            'text' => $text
+        );
+
+        // create and return the replacement token
+        return $this->wiki->addToken('Interwiki', $options);
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,217 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Base rendering class for parsed and tokenized text.
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Render.php,v 1.9 2006/02/17 05:42:55 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * Base rendering class for parsed and tokenized text.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render {
+
+
+    /**
+    *
+    * Configuration options for this render rule.
+    *
+    * @access public
+    *
+    * @var string
+    *
+    */
+
+    var $conf = array();
+
+
+    /**
+    *
+    * The name of this rule's format.
+    *
+    * @access public
+    *
+    * @var string
+    *
+    */
+
+    var $format = null;
+
+
+    /**
+    *
+    * The name of this rule's token array elements.
+    *
+    * @access public
+    *
+    * @var string
+    *
+    */
+
+    var $rule = null;
+
+
+    /**
+    *
+    * A reference to the calling Text_Wiki object.
+    *
+    * This is needed so that each rule has access to the same source
+    * text, token set, URLs, interwiki maps, page names, etc.
+    *
+    * @access public
+    *
+    * @var object
+    */
+
+    var $wiki = null;
+
+
+    /**
+    *
+    * Constructor for this render format or rule.
+    *
+    * @access public
+    *
+    * @param object &$obj The calling "parent" Text_Wiki object.
+    *
+    */
+
+    function Text_Wiki_Render(&$obj)
+    {
+        // keep a reference to the calling Text_Wiki object
+        $this->wiki =& $obj;
+
+        // get the config-key-name for this object,
+        // strip the Text_Wiki_Render_ part
+        //           01234567890123456
+        $tmp = get_class($this);
+        $tmp = substr($tmp, 17);
+
+        // split into pieces at the _ mark.
+        // first part is format, second part is rule.
+        $part   = explode('_', $tmp);
+        $this->format = isset($part[0]) ? ucwords(strtolower($part[0])) : null;
+        $this->rule   = isset($part[1]) ? ucwords(strtolower($part[1])) : null;
+
+        // is there a format but no rule?
+        // then this is the "main" render object, with
+        // pre() and post() methods.
+        if ($this->format && ! $this->rule &&
+            isset($this->wiki->formatConf[$this->format]) &&
+            is_array($this->wiki->formatConf[$this->format])) {
+
+            // this is a format render object
+            $this->conf = array_merge(
+                $this->conf,
+                $this->wiki->formatConf[$this->format]
+            );
+
+        }
+
+        // is there a format and a rule?
+        if ($this->format && $this->rule &&
+            isset($this->wiki->renderConf[$this->format][$this->rule]) &&
+            is_array($this->wiki->renderConf[$this->format][$this->rule])) {
+
+            // this is a rule render object
+            $this->conf = array_merge(
+                $this->conf,
+                $this->wiki->renderConf[$this->format][$this->rule]
+            );
+        }
+    }
+
+
+    /**
+    *
+    * Simple method to safely get configuration key values.
+    *
+    * @access public
+    *
+    * @param string $key The configuration key.
+    *
+    * @param mixed $default If the key does not exist, return this value
+    * instead.
+    *
+    * @return mixed The configuration key value (if it exists) or the
+    * default value (if not).
+    *
+    */
+
+    function getConf($key, $default = null)
+    {
+        if (isset($this->conf[$key])) {
+            return $this->conf[$key];
+        } else {
+            return $default;
+        }
+    }
+
+
+    /**
+    *
+    * Simple method to wrap a configuration in an sprintf() format.
+    *
+    * @access public
+    *
+    * @param string $key The configuration key.
+    *
+    * @param string $format The sprintf() format string.
+    *
+    * @return mixed The formatted configuration key value (if it exists)
+    * or null (if it does not).
+    *
+    */
+
+    function formatConf($format, $key)
+    {
+        if (isset($this->conf[$key])) {
+            return sprintf($format, $this->conf[$key]);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+    * Default method to render url
+    *
+    * @access public
+    * @param string $urlChunk a part of an url to render
+    * @return rendered url
+    *
+    */
+
+    function urlEncode($urlChunk)
+    {
+        return rawurlencode($urlChunk);
+    }
+
+    /**
+    * Default method to render text (htmlspecialchars)
+    *
+    * @access public
+    * @param string $text the text to render
+    * @return rendered text
+    *
+    */
+
+    function textEncode($text)
+    {
+        return htmlspecialchars($text);
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,16 @@
+<?php
+
+class Text_Wiki_Render_Plain extends Text_Wiki_Render {
+    
+    function pre()
+    {
+        return;
+    }
+    
+    function post()
+    {
+        return;
+    }
+    
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain/Anchor.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,23 @@
+<?php
+
+/**
+* 
+* This class renders an anchor target name in XHTML.
+*
+* @author Manuel Holtgrewe <purestorm at ggnore dot net>
+*
+* @author Paul M. Jones <pmjones at ciaweb dot net>
+*
+* @package Text_Wiki
+*
+*/
+
+class Text_Wiki_Render_Plain_Anchor extends Text_Wiki_Render {
+    
+    function token($options)
+    {
+        return $options['name'];
+    }
+}
+
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain/Blockquote.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,39 @@
+<?php
+
+class Text_Wiki_Render_Plain_Blockquote extends Text_Wiki_Render {
+    
+    /**
+    * 
+    * Renders a token into text matching the requested format.
+    * 
+    * @access public
+    * 
+    * @param array $options The "options" portion of the token (second
+    * element).
+    * 
+    * @return string The text rendered from the token options.
+    * 
+    */
+    
+    function token($options)
+    {
+        $type = $options['type'];
+        $level = $options['level'];
+    
+        // set up indenting so that the results look nice; we do this
+        // in two steps to avoid str_pad mathematics.  ;-)
+        $pad = str_pad('', $level + 1, "\t");
+        $pad = str_replace("\t", '    ', $pad);
+        
+        // starting
+        if ($type == 'start') {
+            return "\n$pad";
+        }
+        
+        // ending
+        if ($type == 'end') {
+            return "\n$pad";
+        }
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain/Bold.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,23 @@
+<?php
+
+class Text_Wiki_Render_Plain_Bold extends Text_Wiki_Render {
+
+    /**
+    * 
+    * Renders a token into text matching the requested format.
+    * 
+    * @access public
+    * 
+    * @param array $options The "options" portion of the token (second
+    * element).
+    * 
+    * @return string The text rendered from the token options.
+    * 
+    */
+    
+    function token($options)
+    {
+        return;
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain/Box.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,48 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Box rule end renderer for Plain
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Bertrand Gugger <bertrand@toggg.com>
+ * @copyright  2005 bertrand Gugger
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Box.php,v 1.1 2005/08/15 09:50:57 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class renders a box drawn in Plain.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Bertrand Gugger <bertrand@toggg.com>
+ * @copyright  2005 bertrand Gugger
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Plain_Box extends Text_Wiki_Render {
+
+    /**
+    *
+    * Renders a token into text matching the requested format.
+    *
+    * @access public
+    *
+    * @param array $options The "options" portion of the token (second
+    * element).
+    *
+    * @return string The text rendered from the token options.
+    *
+    */
+
+    function token($options)
+    {
+        return '';
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain/Break.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,24 @@
+<?php
+
+class Text_Wiki_Render_Plain_Break extends Text_Wiki_Render {
+
+    /**
+    * 
+    * Renders a token into text matching the requested format.
+    * 
+    * @access public
+    * 
+    * @param array $options The "options" portion of the token (second
+    * element).
+    * 
+    * @return string The text rendered from the token options.
+    * 
+    */
+    
+    function token($options)
+    {
+        return "\n";
+    }
+}
+
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain/Center.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,23 @@
+<?php
+
+class Text_Wiki_Render_Plain_Center extends Text_Wiki_Render {
+
+    /**
+    * 
+    * Renders a token into text matching the requested format.
+    * 
+    * @access public
+    * 
+    * @param array $options The "options" portion of the token (second
+    * element).
+    * 
+    * @return string The text rendered from the token options.
+    * 
+    */
+    
+    function token($options)
+    {
+        return;
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain/Code.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,24 @@
+<?php
+
+class Text_Wiki_Render_Plain_Code extends Text_Wiki_Render {
+    
+    
+    /**
+    * 
+    * Renders a token into text matching the requested format.
+    * 
+    * @access public
+    * 
+    * @param array $options The "options" portion of the token (second
+    * element).
+    * 
+    * @return string The text rendered from the token options.
+    * 
+    */
+    
+    function token($options)
+    {
+        return "\n" . $options['text'] . "\n\n";
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain/Colortext.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,23 @@
+<?php
+
+class Text_Wiki_Render_Plain_Colortext extends Text_Wiki_Render {
+    
+    /**
+    * 
+    * Renders a token into text matching the requested format.
+    * 
+    * @access public
+    * 
+    * @param array $options The "options" portion of the token (second
+    * element).
+    * 
+    * @return string The text rendered from the token options.
+    * 
+    */
+    
+    function token($options)
+    {
+        return;
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain/Deflist.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,59 @@
+<?php
+
+class Text_Wiki_Render_Plain_Deflist extends Text_Wiki_Render {
+    
+    /**
+    * 
+    * Renders a token into text matching the requested format.
+    * 
+    * @access public
+    * 
+    * @param array $options The "options" portion of the token (second
+    * element).
+    * 
+    * @return string The text rendered from the token options.
+    * 
+    */
+    
+    function token($options)
+    {
+        $type = $options['type'];
+        $pad = "    ";
+        
+        switch ($type) {
+        
+        case 'list_start':
+            return "\n";
+            break;
+        
+        case 'list_end':
+            return "\n\n";
+            break;
+        
+        case 'term_start':
+        
+            // done!
+            return $pad;
+            break;
+        
+        case 'term_end':
+            return "\n";
+            break;
+        
+        case 'narr_start':
+        
+            // done!
+            return $pad . $pad;
+            break;
+        
+        case 'narr_end':
+            return "\n";
+            break;
+        
+        default:
+            return '';
+        
+        }
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain/Delimiter.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,23 @@
+<?php
+
+class Text_Wiki_Render_Plain_Delimiter extends Text_Wiki_Render {
+    
+    /**
+    * 
+    * Renders a token into text matching the requested format.
+    * 
+    * @access public
+    * 
+    * @param array $options The "options" portion of the token (second
+    * element).
+    * 
+    * @return string The text rendered from the token options.
+    * 
+    */
+    
+    function token($options)
+    {
+        return;
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain/Embed.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,23 @@
+<?php
+
+class Text_Wiki_Render_Plain_Embed extends Text_Wiki_Render {
+    
+    /**
+    * 
+    * Renders a token into text matching the requested format.
+    * 
+    * @access public
+    * 
+    * @param array $options The "options" portion of the token (second
+    * element).
+    * 
+    * @return string The text rendered from the token options.
+    * 
+    */
+    
+    function token($options)
+    {
+        return strip_tags($options['text']);
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain/Emphasis.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,23 @@
+<?php
+
+class Text_Wiki_Render_Plain_Emphasis extends Text_Wiki_Render {
+    
+    /**
+    * 
+    * Renders a token into text matching the requested format.
+    * 
+    * @access public
+    * 
+    * @param array $options The "options" portion of the token (second
+    * element).
+    * 
+    * @return string The text rendered from the token options.
+    * 
+    */
+    
+    function token($options)
+    {
+        return;
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain/Font.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,44 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * BBCode: extra Font rules renderer to size the text
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Bertrand Gugger <bertrand@toggg.com>
+ * @copyright  2005 bertrand Gugger
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Font.php,v 1.1 2005/08/06 11:35:32 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * Font rule render class (used for BBCode)
+ * 
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Bertrand Gugger <bertrand@toggg.com>
+ * @copyright  2005 bertrand Gugger
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ * @see        Text_Wiki::Text_Wiki_Render()
+ */
+class Text_Wiki_Render_Plain_Font extends Text_Wiki_Render {
+    
+    /**
+      * Renders a token into text matching the requested format.
+      * process the font size option 
+      *
+      * @access public
+      * @param array $options The "options" portion of the token (second element).
+      * @return string The text rendered from the token options.
+      */
+    function token($options)
+    {
+        return;
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain/Freelink.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,23 @@
+<?php
+
+class Text_Wiki_Render_Plain_Freelink extends Text_Wiki_Render {
+    
+    /**
+    * 
+    * Renders a token into text matching the requested format.
+    * 
+    * @access public
+    * 
+    * @param array $options The "options" portion of the token (second
+    * element).
+    * 
+    * @return string The text rendered from the token options.
+    * 
+    */
+    
+    function token($options)
+    {
+        return $options['text'];
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain/Function.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,39 @@
+<?php
+
+// $Id: Function.php,v 1.3 2004/10/08 17:46:47 pmjones Exp $
+
+class Text_Wiki_Render_Plain_Function extends Text_Wiki_Render {
+    
+    /**
+    * 
+    * Renders a token into text matching the requested format.
+    * 
+    * @access public
+    * 
+    * @param array $options The "options" portion of the token (second
+    * element).
+    * 
+    * @return string The text rendered from the token options.
+    * 
+    */
+    
+    function token($options)
+    {
+        extract($options); // access, return, name, params, throws
+        
+        $output = "$access $return $name ( ";
+        
+        foreach ($params as $key => $val) {
+            $output .= "{$val['type']} {$val['descr']} {$val['default']} ";
+        }
+        
+        $output .= ') ';
+        
+        foreach ($throws as $key => $val) {
+            $output .= "{$val['type']} {$val['descr']} ";
+        }
+        
+        return $output;
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain/Heading.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,14 @@
+<?php
+
+class Text_Wiki_Render_Plain_Heading extends Text_Wiki_Render {
+    
+    function token($options)
+    {
+        if ($options['type'] == 'end') {
+            return "\n\n";
+        } else {
+            return "\n";
+        }
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain/Horiz.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,23 @@
+<?php
+
+class Text_Wiki_Render_Plain_Horiz extends Text_Wiki_Render {
+    
+    /**
+    * 
+    * Renders a token into text matching the requested format.
+    * 
+    * @access public
+    * 
+    * @param array $options The "options" portion of the token (second
+    * element).
+    * 
+    * @return string The text rendered from the token options.
+    * 
+    */
+    
+    function token($options)
+    {
+        return "\n";
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain/Html.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,24 @@
+<?php
+
+class Text_Wiki_Render_Plain_Html extends Text_Wiki_Render {
+    
+    
+    /**
+    * 
+    * Renders a token into text matching the requested format.
+    * 
+    * @access public
+    * 
+    * @param array $options The "options" portion of the token (second
+    * element).
+    * 
+    * @return string The text rendered from the token options.
+    * 
+    */
+    
+    function token($options)
+    {
+        return strip_tags($options['text']);
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain/Image.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,22 @@
+<?php
+class Text_Wiki_Render_Plain_Image extends Text_Wiki_Render {
+
+    /**
+    * 
+    * Renders a token into text matching the requested format.
+    * 
+    * @access public
+    * 
+    * @param array $options The "options" portion of the token (second
+    * element).
+    * 
+    * @return string The text rendered from the token options.
+    * 
+    */
+    
+    function token($options)
+    {
+        return;
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain/Include.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,8 @@
+<?php
+class Text_Wiki_Render_Plain_Include extends Text_Wiki_Render {    
+    function token()
+    {
+        return '';
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain/Interwiki.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,29 @@
+<?php
+
+class Text_Wiki_Render_Plain_Interwiki extends Text_Wiki_Render {
+    
+    /**
+    * 
+    * Renders a token into text matching the requested format.
+    * 
+    * @access public
+    * 
+    * @param array $options The "options" portion of the token (second
+    * element).
+    * 
+    * @return string The text rendered from the token options.
+    * 
+    */
+    
+    function token($options)
+    {
+        if (isset($options['url'])) {
+            // calculated by the parser (e.g. Mediawiki)
+            $href = $options['url'];
+        } else {
+            $href = $options['site'] . ':' . $options['page'];
+        }
+        return $options['text'] . ' (' . $href . ')';
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain/Italic.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,23 @@
+<?php
+
+class Text_Wiki_Render_Plain_Italic extends Text_Wiki_Render {
+    
+    /**
+    * 
+    * Renders a token into text matching the requested format.
+    * 
+    * @access public
+    * 
+    * @param array $options The "options" portion of the token (second
+    * element).
+    * 
+    * @return string The text rendered from the token options.
+    * 
+    */
+    
+    function token($options)
+    {
+        return;
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain/List.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,68 @@
+<?php
+
+
+class Text_Wiki_Render_Plain_List extends Text_Wiki_Render {
+    
+    /**
+    * 
+    * Renders a token into text matching the requested format.
+    * 
+    * This rendering method is syntactically and semantically compliant
+    * with XHTML 1.1 in that sub-lists are part of the previous list item.
+    * 
+    * @access public
+    * 
+    * @param array $options The "options" portion of the token (second
+    * element).
+    * 
+    * @return string The text rendered from the token options.
+    * 
+    */
+    
+    function token($options)
+    {
+        // make nice variables (type, level, count)
+        extract($options);
+        
+        // set up indenting so that the results look nice; we do this
+        // in two steps to avoid str_pad mathematics.  ;-)
+        $pad = str_pad('', $level, "\t");
+        $pad = str_replace("\t", '    ', $pad);
+                
+        switch ($type) {
+        
+        case 'bullet_list_start':
+            break;
+        
+        case 'bullet_list_end':
+            if ($level == 0) {
+                return "\n\n";
+            }
+            break;
+        
+        case 'number_list_start':
+            break;
+        
+        case 'number_list_end':
+            if ($level == 0) {
+                return "\n\n";
+            }
+            break;
+        
+        case 'bullet_item_start':
+        case 'number_item_start':
+            return "\n$pad";
+            break;
+        
+        case 'bullet_item_end':
+        case 'number_item_end':
+        default:
+            // ignore item endings and all other types.
+            // item endings are taken care of by the other types
+            // depending on their place in the list.
+            return;
+            break;
+        }
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain/Newline.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,12 @@
+<?php
+
+class Text_Wiki_Render_Plain_Newline extends Text_Wiki_Render {
+    
+    
+    function token($options)
+    {
+        return "\n";
+    }
+}
+
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain/Page.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,48 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Page rule end renderer for Plain
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Bertrand Gugger <bertrand@toggg.com>
+ * @copyright  2005 bertrand Gugger
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Page.php,v 1.1 2005/08/15 15:27:19 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class renders page markers in Plain.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Bertrand Gugger <bertrand@toggg.com>
+ * @copyright  2005 bertrand Gugger
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Plain_Page extends Text_Wiki_Render {
+
+    /**
+    *
+    * Renders a token into text matching the requested format.
+    *
+    * @access public
+    *
+    * @param array $options The "options" portion of the token (second
+    * element).
+    *
+    * @return string The text rendered from the token options.
+    *
+    */
+
+    function token($options)
+    {
+        return "\x0C";
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain/Paragraph.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,31 @@
+<?php
+
+class Text_Wiki_Render_Plain_Paragraph extends Text_Wiki_Render {
+    
+    /**
+    * 
+    * Renders a token into text matching the requested format.
+    * 
+    * @access public
+    * 
+    * @param array $options The "options" portion of the token (second
+    * element).
+    * 
+    * @return string The text rendered from the token options.
+    * 
+    */
+    
+    function token($options)
+    {
+        extract($options); //type
+        
+        if ($type == 'start') {
+            return '';
+        }
+        
+        if ($type == 'end') {
+            return "\n\n";
+        }
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain/Phplookup.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,25 @@
+<?php
+
+class Text_Wiki_Render_Plain_Phplookup extends Text_Wiki_Render {
+    
+    var $conf = array('target' => '_blank');
+    
+    /**
+    * 
+    * Renders a token into text matching the requested format.
+    * 
+    * @access public
+    * 
+    * @param array $options The "options" portion of the token (second
+    * element).
+    * 
+    * @return string The text rendered from the token options.
+    * 
+    */
+    
+    function token($options)
+    {
+        return trim($options['text']);
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain/Plugin.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,49 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Plugin rule end renderer for Plain
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Bertrand Gugger <bertrand@toggg.com>
+ * @copyright  2005 bertrand Gugger
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Plugin.php,v 1.1 2005/08/17 09:16:36 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class renders wiki plugins in Plain. (empty)
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Bertrand Gugger <bertrand@toggg.com>
+ * @copyright  2005 bertrand Gugger
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Plain_Plugin extends Text_Wiki_Render {
+
+    /**
+    *
+    * Renders a token into text matching the requested format.
+    * Plugins produce wiki markup so are processed by parsing, no tokens produced
+    *
+    * @access public
+    *
+    * @param array $options The "options" portion of the token (second
+    * element).
+    *
+    * @return string The text rendered from the token options.
+    *
+    */
+
+    function token($options)
+    {
+        return '';
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain/Prefilter.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,40 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+// +----------------------------------------------------------------------+
+// | PHP version 4                                                        |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1997-2003 The PHP Group                                |
+// +----------------------------------------------------------------------+
+// | This source file is subject to version 2.0 of the PHP license,       |
+// | that is bundled with this package in the file LICENSE, and is        |
+// | available through the world-wide-web at                              |
+// | http://www.php.net/license/2_02.txt.                                 |
+// | If you did not receive a copy of the PHP license and are unable to   |
+// | obtain it through the world-wide-web, please send a note to          |
+// | license@php.net so we can mail you a copy immediately.               |
+// +----------------------------------------------------------------------+
+// | Authors: Paul M. Jones <pmjones@php.net>                          |
+// +----------------------------------------------------------------------+
+//
+// $Id: Prefilter.php,v 1.3 2005/02/22 19:12:58 pmjones Exp $
+
+
+/**
+* 
+* This class implements a Text_Wiki_Render_Xhtml to "pre-filter" source text so
+* that line endings are consistently \n, lines ending in a backslash \
+* are concatenated with the next line, and tabs are converted to spaces.
+*
+* @author Paul M. Jones <pmjones@php.net>
+*
+* @package Text_Wiki
+*
+*/
+
+class Text_Wiki_Render_Plain_Prefilter extends Text_Wiki_Render {
+    function token()
+    {
+        return '';
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain/Preformatted.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,48 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Preformatted rule end renderer for Plain
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Bertrand Gugger <bertrand@toggg.com>
+ * @copyright  2005 bertrand Gugger
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Preformatted.php,v 1.1 2005/08/15 06:15:41 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class renders preformated text in Plain.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Bertrand Gugger <bertrand@toggg.com>
+ * @copyright  2005 bertrand Gugger
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Plain_Preformatted extends Text_Wiki_Render {
+
+    /**
+    *
+    * Renders a token into text matching the requested format.
+    *
+    * @access public
+    *
+    * @param array $options The "options" portion of the token (second
+    * element).
+    *
+    * @return string The text rendered from the token options.
+    *
+    */
+
+    function token($options)
+    {
+        return $options['text'];
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain/Raw.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,23 @@
+<?php
+
+class Text_Wiki_Render_Plain_Raw extends Text_Wiki_Render {
+    
+    /**
+    * 
+    * Renders a token into text matching the requested format.
+    * 
+    * @access public
+    * 
+    * @param array $options The "options" portion of the token (second
+    * element).
+    * 
+    * @return string The text rendered from the token options.
+    * 
+    */
+    
+    function token($options)
+    {
+        return $options['text'];
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain/Revise.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,24 @@
+<?php
+
+class Text_Wiki_Render_Plain_Revise extends Text_Wiki_Render {
+    
+    
+    /**
+    * 
+    * Renders a token into text matching the requested format.
+    * 
+    * @access public
+    * 
+    * @param array $options The "options" portion of the token (second
+    * element).
+    * 
+    * @return string The text rendered from the token options.
+    * 
+    */
+    
+    function token($options)
+    {
+        return;
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain/Smiley.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,44 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Smiley rule Plain renderer
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Bertrand Gugger <bertrand@toggg.com>
+ * @copyright  2005 bertrand Gugger
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Smiley.php,v 1.2 2005/08/10 11:42:08 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * Smiley rule Plain render class
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Bertrand Gugger <bertrand@toggg.com>
+ * @copyright  2005 bertrand Gugger
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ * @see        Text_Wiki::Text_Wiki_Render()
+ */
+class Text_Wiki_Render_Plain_Smiley extends Text_Wiki_Render {
+
+    /**
+      * Renders a token into text matching the requested format.
+      * process the Smileys
+      *
+      * @access public
+      * @param array $options The "options" portion of the token (second element).
+      * @return string The text rendered from the token options.
+      */
+    function token($options)
+    {
+        return $options['symbol'];
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain/Specialchar.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,54 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Specialchar rule end renderer for Plain
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Bertrand Gugger <bertrand@toggg.com>
+ * @copyright  2005 bertrand Gugger
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Specialchar.php,v 1.1 2005/08/15 11:10:38 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class renders special characters in Plain.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Bertrand Gugger <bertrand@toggg.com>
+ * @copyright  2005 bertrand Gugger
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Plain_SpecialChar extends Text_Wiki_Render {
+
+    var $types = array('~bs~' => '\\',
+                       '~hs~' => ' ',
+                       '~amp~' => '&',
+                       '~ldq~' => '"',
+                       '~rdq~' => '"',
+                       '~lsq~' => "'",
+                       '~rsq~' => "'",
+                       '~c~' => '©',
+                       '~--~' => '-',
+                       '" -- "' => '-',
+                       '&quot; -- &quot;' => '-',
+                       '~lt~' => '<',
+                       '~gt~' => '>');
+
+    function token($options)
+    {
+        if (isset($this->types[$options['char']])) {
+            return $this->types[$options['char']];
+        } else {
+            return $options['char'];
+        }
+    }
+}
+
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain/Strong.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,24 @@
+<?php
+
+class Text_Wiki_Render_Plain_Strong extends Text_Wiki_Render {
+    
+    
+    /**
+    * 
+    * Renders a token into text matching the requested format.
+    * 
+    * @access public
+    * 
+    * @param array $options The "options" portion of the token (second
+    * element).
+    * 
+    * @return string The text rendered from the token options.
+    * 
+    */
+    
+    function token($options)
+    {
+        return;
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain/Subscript.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,48 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Subscript rule end renderer for Plain
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Bertrand Gugger <bertrand@toggg.com>
+ * @copyright  2005 bertrand Gugger
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Subscript.php,v 1.1 2005/08/15 10:09:06 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class renders subscript text in Plain.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Bertrand Gugger <bertrand@toggg.com>
+ * @copyright  2005 bertrand Gugger
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Plain_Subscript extends Text_Wiki_Render {
+
+    /**
+    *
+    * Renders a token into text matching the requested format.
+    *
+    * @access public
+    *
+    * @param array $options The "options" portion of the token (second
+    * element).
+    *
+    * @return string The text rendered from the token options.
+    *
+    */
+
+    function token($options)
+    {
+        return '';
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain/Superscript.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,23 @@
+<?php
+
+class Text_Wiki_Render_Plain_Superscript extends Text_Wiki_Render {
+    
+    /**
+    * 
+    * Renders a token into text matching the requested format.
+    * 
+    * @access public
+    * 
+    * @param array $options The "options" portion of the token (second
+    * element).
+    * 
+    * @return string The text rendered from the token options.
+    * 
+    */
+    
+    function token($options)
+    {
+        return;
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain/Table.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,65 @@
+<?php
+
+class Text_Wiki_Render_Plain_Table extends Text_Wiki_Render {
+
+    /**
+    *
+    * Renders a token into text matching the requested format.
+    *
+    * @access public
+    *
+    * @param array $options The "options" portion of the token (second
+    * element).
+    *
+    * @return string The text rendered from the token options.
+    *
+    */
+
+    function token($options)
+    {
+        // make nice variable names (type, attr, span)
+        extract($options);
+
+        $pad = '    ';
+
+        switch ($type) {
+
+        case 'table_start':
+            return;
+            break;
+
+        case 'table_end':
+            return;
+            break;
+
+        case 'caption_start':
+            return;
+            break;
+
+        case 'caption_end':
+            return "\n";
+            break;
+
+        case 'row_start':
+            return;
+            break;
+
+        case 'row_end':
+            return " ||\n";
+            break;
+
+        case 'cell_start':
+            return " || ";
+            break;
+
+        case 'cell_end':
+            return;
+            break;
+
+        default:
+            return '';
+
+        }
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain/Tighten.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,10 @@
+<?php
+class Text_Wiki_Render_Plain_Tighten extends Text_Wiki_Render {
+    
+    
+    function token()
+    {
+        return '';
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain/Titlebar.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,54 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Titlebar rule end renderer for Plain
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Bertrand Gugger <bertrand@toggg.com>
+ * @copyright  2005 bertrand Gugger
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Titlebar.php,v 1.1 2005/08/15 11:36:55 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class renders a title bar in Plain.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Bertrand Gugger <bertrand@toggg.com>
+ * @copyright  2005 bertrand Gugger
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Plain_Titlebar extends Text_Wiki_Render {
+
+    /**
+    *
+    * Renders a token into text matching the requested format.
+    *
+    * @access public
+    *
+    * @param array $options The "options" portion of the token (second
+    * element).
+    *
+    * @return string The text rendered from the token options.
+    *
+    */
+
+    function token($options)
+    {
+        if ($options['type'] == 'start') {
+            return '***** ';
+        }
+
+        if ($options['type'] == 'end') {
+            return " *****\n";
+        }
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain/Toc.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,39 @@
+<?php
+
+class Text_Wiki_Render_Plain_Toc extends Text_Wiki_Render {
+    
+    
+    
+    /**
+    * 
+    * Renders a token into text matching the requested format.
+    * 
+    * @access public
+    * 
+    * @param array $options The "options" portion of the token (second
+    * element).
+    * 
+    * @return string The text rendered from the token options.
+    * 
+    */
+    
+    function token($options)
+    {
+        // type, count, level
+        extract($options);
+        
+        if ($type == 'item_start') {
+            
+            // build some indenting spaces for the text
+            $indent = ($level - 2) * 4;
+            $pad = str_pad('', $indent);
+            return $pad;
+        }
+        
+        if ($type == 'item_end') {
+            return "\n";
+        }
+    }
+
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain/Tt.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,24 @@
+<?php
+
+class Text_Wiki_Render_Plain_tt extends Text_Wiki_Render {
+    
+    
+    /**
+    * 
+    * Renders a token into text matching the requested format.
+    * 
+    * @access public
+    * 
+    * @param array $options The "options" portion of the token (second
+    * element).
+    * 
+    * @return string The text rendered from the token options.
+    * 
+    */
+    
+    function token($options)
+    {
+        return;
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain/Underline.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,23 @@
+<?php
+
+class Text_Wiki_Render_Plain_Underline extends Text_Wiki_Render {
+
+    /**
+    * 
+    * Renders a token into text matching the requested format.
+    * 
+    * @access public
+    * 
+    * @param array $options The "options" portion of the token (second
+    * element).
+    * 
+    * @return string The text rendered from the token options.
+    * 
+    */
+    
+    function token($options)
+    {
+        return;
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain/Url.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,25 @@
+<?php
+
+
+class Text_Wiki_Render_Plain_Url extends Text_Wiki_Render {
+    
+    
+    /**
+    * 
+    * Renders a token into text matching the requested format.
+    * 
+    * @access public
+    * 
+    * @param array $options The "options" portion of the token (second
+    * element).
+    * 
+    * @return string The text rendered from the token options.
+    * 
+    */
+    
+    function token($options)
+    {
+        return $options['text'];
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Plain/Wikilink.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,24 @@
+<?php
+
+class Text_Wiki_Render_Plain_Wikilink extends Text_Wiki_Render {
+    
+    
+    /**
+    * 
+    * Renders a token into plain text.
+    * 
+    * @access public
+    * 
+    * @param array $options The "options" portion of the token (second
+    * element).
+    * 
+    * @return string The text rendered from the token options.
+    * 
+    */
+    
+    function token($options)
+    {
+        return $options['text'];
+    }
+}
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,112 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Format class for the Xhtml rendering
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Xhtml.php,v 1.9 2006/02/10 22:31:50 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * Format class for the Xhtml rendering
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Xhtml extends Text_Wiki_Render {
+
+    var $conf = array(
+    	'translate' => HTML_ENTITIES,
+    	'quotes'    => ENT_COMPAT,
+    	'charset'   => 'ISO-8859-1'
+    );
+
+    function pre()
+    {
+        $this->wiki->source = $this->textEncode($this->wiki->source);
+    }
+
+    function post()
+    {
+        return;
+    }
+
+
+    /**
+    * Method to render text
+    *
+    * @access public
+    * @param string $text the text to render
+    * @return rendered text
+    *
+    */
+
+    function textEncode($text)
+    {
+        // attempt to translate HTML entities in the source.
+        // get the config options.
+        $type = $this->getConf('translate', HTML_ENTITIES);
+        $quotes = $this->getConf('quotes', ENT_COMPAT);
+        $charset = $this->getConf('charset', 'ISO-8859-1');
+
+        // have to check null and false because HTML_ENTITIES is a zero
+        if ($type === HTML_ENTITIES) {
+
+            // keep a copy of the translated version of the delimiter
+            // so we can convert it back.
+            $new_delim = htmlentities($this->wiki->delim, $quotes, $charset);
+      
+            // convert the entities.  we silence the call here so that
+            // errors about charsets don't pop up, per counsel from
+            // Jan at Horde.  (http://pear.php.net/bugs/bug.php?id=4474)
+            $text = @htmlentities(
+              $text,
+              $quotes,
+              $charset
+            );
+            
+            // Mod for Enano: undo any HTML cleaning - we will take care of this ourselves
+            $text = str_replace(Array('&lt;', '&gt;', '&quot;', '&amp;', '&#039;'),
+                                Array('<',    '>',    '"',      '&',     "'"     ),
+                                $text);
+            
+            // re-convert the delimiter
+            $text = str_replace(
+              $new_delim, $this->wiki->delim, $text
+            );
+
+        } elseif ($type === HTML_SPECIALCHARS) {
+    
+          // keep a copy of the translated version of the delimiter
+          // so we can convert it back.
+          $new_delim = htmlspecialchars($this->wiki->delim, $quotes,
+              $charset);
+    
+          // convert the entities.  we silence the call here so that
+          // errors about charsets don't pop up, per counsel from
+          // Jan at Horde.  (http://pear.php.net/bugs/bug.php?id=4474)
+          $text = @htmlspecialchars(
+            $text,
+            $quotes,
+            $charset
+          );
+    
+          // re-convert the delimiter
+          $text = str_replace(
+            $new_delim, $this->wiki->delim, $text
+          );
+        }
+        return $text;
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml/Anchor.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,48 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Anchor rule end renderer for Xhtml
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Anchor.php,v 1.10 2006/02/10 23:07:03 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class renders an anchor target name in XHTML.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Xhtml_Anchor extends Text_Wiki_Render {
+
+    var $conf = array(
+        'css' => null
+    );
+
+    function token($options)
+    {
+        extract($options); // $type, $name
+
+        if ($type == 'start') {
+            $css = $this->formatConf(' class="%s"', 'css');
+            $format = "<a$css id=\"%s\">";
+            return sprintf($format, $this->textEncode($name));
+        }
+
+        if ($type == 'end') {
+            return '</a>';
+        }
+    }
+}
+
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml/Blockquote.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,69 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Blockquote rule end renderer for Xhtml
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Blockquote.php,v 1.7 2005/07/30 08:03:28 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class renders a blockquote in XHTML.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Xhtml_Blockquote extends Text_Wiki_Render {
+
+    var $conf = array(
+        'css' => null
+    );
+
+    /**
+    *
+    * Renders a token into text matching the requested format.
+    *
+    * @access public
+    *
+    * @param array $options The "options" portion of the token (second
+    * element).
+    *
+    * @return string The text rendered from the token options.
+    *
+    */
+
+    function token($options)
+    {
+        $type = $options['type'];
+        $level = $options['level'];
+
+        // set up indenting so that the results look nice; we do this
+        // in two steps to avoid str_pad mathematics.  ;-)
+        $pad = str_pad('', $level, "\t");
+        $pad = str_replace("\t", '    ', $pad);
+
+        // pick the css type
+        $css = $this->formatConf(' class="%s"', 'css');
+
+        // starting
+        if ($type == 'start') {
+            return "$pad<blockquote$css>";
+        }
+
+        // ending
+        if ($type == 'end') {
+            return $pad . "</blockquote>\n";
+        }
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml/Bold.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,57 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Bold rule end renderer for Xhtml
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Bold.php,v 1.7 2005/07/30 08:03:28 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class renders bold text in XHTML.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Xhtml_Bold extends Text_Wiki_Render {
+
+    var $conf = array(
+        'css' => null
+    );
+
+    /**
+    *
+    * Renders a token into text matching the requested format.
+    *
+    * @access public
+    *
+    * @param array $options The "options" portion of the token (second
+    * element).
+    *
+    * @return string The text rendered from the token options.
+    *
+    */
+
+    function token($options)
+    {
+        if ($options['type'] == 'start') {
+            $css = $this->formatConf(' class="%s"', 'css');
+            return "<b$css>";
+        }
+
+        if ($options['type'] == 'end') {
+            return '</b>';
+        }
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml/Box.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,57 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Box rule end renderer for Xhtml
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Box.php,v 1.2 2005/07/30 08:03:28 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class renders a box drawn in XHTML.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Xhtml_Box extends Text_Wiki_Render {
+
+    var $conf = array(
+        'css' => null
+    );
+
+    /**
+    *
+    * Renders a token into text matching the requested format.
+    *
+    * @access public
+    *
+    * @param array $options The "options" portion of the token (second
+    * element).
+    *
+    * @return string The text rendered from the token options.
+    *
+    */
+
+    function token($options)
+    {
+        if ($options['type'] == 'start') {
+            $css = $this->formatConf(' class="%s"', 'css');
+            return "<div class='simplebox'$css>";
+        }
+
+        if ($options['type'] == 'end') {
+            return '</div>';
+        }
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml/Break.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,52 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Break rule end renderer for Xhtml
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Break.php,v 1.7 2005/07/30 08:03:28 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class renders line breaks in XHTML.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Xhtml_Break extends Text_Wiki_Render {
+
+    var $conf = array(
+        'css' => null
+    );
+
+    /**
+    *
+    * Renders a token into text matching the requested format.
+    *
+    * @access public
+    *
+    * @param array $options The "options" portion of the token (second
+    * element).
+    *
+    * @return string The text rendered from the token options.
+    *
+    */
+
+    function token($options)
+    {
+        $css = $this->formatConf(' class="%s"', 'css');
+        return "<br$css />\n";
+    }
+}
+
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml/Center.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,52 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Center rule end renderer for Xhtml
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Center.php,v 1.7 2005/07/30 08:03:28 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class renders centered content in XHTML.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Xhtml_Center extends Text_Wiki_Render {
+
+    /**
+    *
+    * Renders a token into text matching the requested format.
+    *
+    * @access public
+    *
+    * @param array $options The "options" portion of the token (second
+    * element).
+    *
+    * @return string The text rendered from the token options.
+    *
+    */
+
+    function token($options)
+    {
+        if ($options['type'] == 'start') {
+            return '<div style="text-align: center;">';
+        }
+
+        if ($options['type'] == 'end') {
+            return '</div>';
+        }
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml/Code.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,133 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Code rule end renderer for Xhtml
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Code.php,v 1.13 2006/02/10 23:07:03 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class renders code blocks in XHTML.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Xhtml_Code extends Text_Wiki_Render {
+
+    var $conf = array(
+        'css'      => null, // class for <pre>
+        'css_code' => null, // class for generic <code>
+        'css_php'  => null, // class for PHP <code>
+        'css_html' => null, // class for HTML <code>
+        'css_filename' => null // class for optional filename <div>
+    );
+
+    /**
+    *
+    * Renders a token into text matching the requested format.
+    *
+    * @access public
+    *
+    * @param array $options The "options" portion of the token (second
+    * element).
+    *
+    * @return string The text rendered from the token options.
+    *
+    */
+
+    function token($options)
+    {
+        $text = $options['text'];
+        $attr = $options['attr'];
+        $type = strtolower($attr['type']);
+
+        $css      = $this->formatConf(' class="%s"', 'css');
+        $css_code = $this->formatConf(' class="%s"', 'css_code');
+        $css_php  = $this->formatConf(' class="%s"', 'css_php');
+        $css_html = $this->formatConf(' class="%s"', 'css_html');
+        $css_filename = $this->formatConf(' class="%s"', 'css_filename');
+
+        if ($type == 'php') {
+            if (substr($options['text'], 0, 5) != '<?php') {
+                // PHP code example:
+                // add the PHP tags
+                $text = "<?php\n" . $options['text'] . "\n?>"; // <?php
+            }
+
+            // convert tabs to four spaces
+            $text = str_replace("\t", "    ", $text);
+
+            // colorize the code block (also converts HTML entities and adds
+            // <code>...</code> tags)
+            ob_start();
+            highlight_string($text);
+            $text = ob_get_contents();
+            ob_end_clean();
+
+            // replace <br /> tags with simple newlines.
+            // replace non-breaking space with simple spaces.
+            // translate HTML <font> and color to XHTML <span> and style.
+            // courtesy of research by A. Kalin :-).
+            $map = array(
+                '<br />'  => "\n",
+                '&nbsp;'  => ' ',
+                '<font'   => '<span',
+                '</font>' => '</span>',
+                'color="' => 'style="color:'
+            );
+            $text = strtr($text, $map);
+
+            // get rid of the last newline inside the code block
+            // (becuase higlight_string puts one there)
+            if (substr($text, -8) == "\n</code>") {
+                $text = substr($text, 0, -8) . "</code>";
+            }
+
+            // replace all <code> tags with classed tags
+            if ($css_php) {
+                $text = str_replace('<code>', "<code$css_php>", $text);
+            }
+
+            // done
+            $text = "<pre$css>$text</pre>";
+
+        } elseif ($type == 'html' || $type == 'xhtml') {
+
+            // HTML code example:
+            // add <html> opening and closing tags,
+            // convert tabs to four spaces,
+            // convert entities.
+            $text = str_replace("\t", "    ", $text);
+            $text = "<html>\n$text\n</html>";
+            $text = $this->textEncode($text);
+            $text = "<pre$css><code$css_html>$text</code></pre>";
+
+        } else {
+            // generic code example:
+            // convert tabs to four spaces,
+            // convert entities.
+            $text = str_replace("\t", "    ", $text);
+            $text = $this->textEncode($text);
+            $text = "<pre$css><code$css_code>$text</code></pre>";
+        }
+
+        if ($css_filename && isset($attr['filename'])) {
+            $text = "<div$css_filename>" .
+                $attr['filename'] . '</div>' . $text;
+        }
+
+        return "\n$text\n\n";
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml/Colortext.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,79 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Colortext rule end renderer for Xhtml
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Colortext.php,v 1.6 2005/07/30 08:03:28 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class renders colored text in XHTML.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Xhtml_Colortext extends Text_Wiki_Render {
+
+    var $colors = array(
+        'aqua',
+        'black',
+        'blue',
+        'fuchsia',
+        'gray',
+        'green',
+        'lime',
+        'maroon',
+        'navy',
+        'olive',
+        'purple',
+        'red',
+        'silver',
+        'teal',
+        'white',
+        'yellow'
+    );
+
+
+    /**
+    *
+    * Renders a token into text matching the requested format.
+    *
+    * @access public
+    *
+    * @param array $options The "options" portion of the token (second
+    * element).
+    *
+    * @return string The text rendered from the token options.
+    *
+    */
+
+    function token($options)
+    {
+        $type = $options['type'];
+        $color = $options['color'];
+
+        if (! in_array($color, $this->colors) && $color{0} != '#') {
+            $color = '#' . $color;
+        }
+
+        if ($type == 'start') {
+            return "<span style=\"color: $color;\">";
+        }
+
+        if ($options['type'] == 'end') {
+            return '</span>';
+        }
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml/Deflist.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,87 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Deflist rule end renderer for Xhtml
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Deflist.php,v 1.8 2005/07/30 08:03:28 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class renders definition lists in XHTML.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Xhtml_Deflist extends Text_Wiki_Render {
+
+    var $conf = array(
+        'css_dl' => null,
+        'css_dt' => null,
+        'css_dd' => null
+    );
+
+    /**
+    *
+    * Renders a token into text matching the requested format.
+    *
+    * @access public
+    *
+    * @param array $options The "options" portion of the token (second
+    * element).
+    *
+    * @return string The text rendered from the token options.
+    *
+    */
+
+    function token($options)
+    {
+        $type = $options['type'];
+        $pad = "    ";
+
+        switch ($type) {
+
+        case 'list_start':
+            $css = $this->formatConf(' class="%s"', 'css_dl');
+            return "<dl$css>\n";
+            break;
+
+        case 'list_end':
+            return "</dl>\n\n";
+            break;
+
+        case 'term_start':
+            $css = $this->formatConf(' class="%s"', 'css_dt');
+            return $pad . "<dt$css>";
+            break;
+
+        case 'term_end':
+            return "</dt>\n";
+            break;
+
+        case 'narr_start':
+            $css = $this->formatConf(' class="%s"', 'css_dd');
+            return $pad . $pad . "<dd$css>";
+            break;
+
+        case 'narr_end':
+            return "</dd>\n";
+            break;
+
+        default:
+            return '';
+
+        }
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml/Delimiter.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,46 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Delimiter rule end renderer for Xhtml
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Delimiter.php,v 1.5 2005/07/30 08:03:28 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class set back the replaced delimiters in XHTML.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Xhtml_Delimiter extends Text_Wiki_Render {
+
+    /**
+    *
+    * Renders a token into text matching the requested format.
+    *
+    * @access public
+    *
+    * @param array $options The "options" portion of the token (second
+    * element).
+    *
+    * @return string The text rendered from the token options.
+    *
+    */
+
+    function token($options)
+    {
+        return $options['text'];
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml/Embed.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,46 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Embed rule end renderer for Xhtml
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Embed.php,v 1.7 2005/07/30 08:03:28 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class replaces the embedded php output in XHTML.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Xhtml_Embed extends Text_Wiki_Render {
+
+    /**
+    *
+    * Renders a token into text matching the requested format.
+    *
+    * @access public
+    *
+    * @param array $options The "options" portion of the token (second
+    * element).
+    *
+    * @return string The text rendered from the token options.
+    *
+    */
+
+    function token($options)
+    {
+        return $options['text'];
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml/Emphasis.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,58 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Emphasis rule end renderer for Xhtml
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Emphasis.php,v 1.7 2005/07/30 08:03:28 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class renders emphasized text in XHTML.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Xhtml_Emphasis extends Text_Wiki_Render {
+
+    var $conf = array(
+        'css' => null
+    );
+
+
+    /**
+    *
+    * Renders a token into text matching the requested format.
+    *
+    * @access public
+    *
+    * @param array $options The "options" portion of the token (second
+    * element).
+    *
+    * @return string The text rendered from the token options.
+    *
+    */
+
+    function token($options)
+    {
+        if ($options['type'] == 'start') {
+            $css = $this->formatConf(' class="%s"', 'css');
+            return "<em$css>";
+        }
+
+        if ($options['type'] == 'end') {
+            return '</em>';
+        }
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml/Font.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,83 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * BBCode: extra Font rules renderer to size the text
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Bertrand Gugger <bertrand@toggg.com>
+ * @copyright  2005 bertrand Gugger
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Font.php,v 1.1 2005/08/06 11:36:45 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * Font rule render class (used for BBCode)
+ * 
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Bertrand Gugger <bertrand@toggg.com>
+ * @copyright  2005 bertrand Gugger
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ * @see        Text_Wiki::Text_Wiki_Render()
+ */
+class Text_Wiki_Render_Xhtml_Font extends Text_Wiki_Render {
+    
+/*    var $size = array(
+        'xx-small',
+        'x-small',
+        'small',
+        'medium',
+        'large',
+        'x-large',
+        'xx-large',
+        'larger',
+        'smaller'
+    );
+    var $units = array(
+        'em',
+        'ex',
+        'px',
+        'in',
+        'cm',
+        'mm',
+        'pt',
+        'pc'
+    );
+*/    
+    
+    /**
+      * Renders a token into text matching the requested format.
+      * process the font size option 
+      *
+      * @access public
+      * @param array $options The "options" portion of the token (second element).
+      * @return string The text rendered from the token options.
+      */
+    function token($options)
+    {
+        if ($options['type'] == 'end') {
+            return '</span>';
+        }
+        if ($options['type'] != 'start') {
+            return '';
+        }
+
+        $ret = '<span style="';
+        if (isset($options['size'])) {
+            $size = trim($options['size']);
+            if (is_numeric($size)) {
+                $size .= 'px';
+            }
+            $ret .= "font-size: $size;";
+        }
+        
+        return $ret.'">';
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml/Freelink.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,35 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Freelink rule end renderer for Xhtml
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Freelink.php,v 1.7 2005/07/30 08:03:28 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * The wikilink render class.
+ */
+require_once 'Text/Wiki/Render/Xhtml/Wikilink.php';
+
+/**
+ * This class renders free links in XHTML.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Xhtml_Freelink extends Text_Wiki_Render_Xhtml_Wikilink {
+    // renders identically to wikilinks, only the parsing is different :-)
+}
+
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml/Function.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,108 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Function rule end renderer for Xhtml
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Function.php,v 1.5 2006/02/10 23:07:03 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class renders a function description in XHTML.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Xhtml_Function extends Text_Wiki_Render {
+
+    var $conf = array(
+    	// list separator for params and throws
+        'list_sep' => ', ',
+
+        // the "main" format string
+        'format_main' => '%access %return <b>%name</b> ( %params ) %throws',
+
+        // the looped format string for required params
+        'format_param' => '%type <i>%descr</i>',
+
+        // the looped format string for params with default values
+        'format_paramd' => '[%type <i>%descr</i> default %default]',
+
+        // the looped format string for throws
+        'format_throws' => '<b>throws</b> %type <i>%descr</i>'
+    );
+
+    /**
+    *
+    * Renders a token into text matching the requested format.
+    *
+    * @access public
+    *
+    * @param array $options The "options" portion of the token (second
+    * element).
+    *
+    * @return string The text rendered from the token options.
+    *
+    */
+
+    function token($options)
+    {
+        extract($options); // name, access, return, params, throws
+
+        // build the baseline output
+        $output = $this->conf['format_main'];
+        $output = str_replace('%access', $this->textEncode($access), $output);
+        $output = str_replace('%return', $this->textEncode($return), $output);
+        $output = str_replace('%name', $this->textEncode($name), $output);
+
+        // build the set of params
+        $list = array();
+        foreach ($params as $key => $val) {
+
+            // is there a default value?
+            if ($val['default']) {
+                $tmp = $this->conf['format_paramd'];
+            } else {
+                $tmp = $this->conf['format_param'];
+            }
+
+            // add the param elements
+            $tmp = str_replace('%type', $this->textEncode($val['type']), $tmp);
+            $tmp = str_replace('%descr', $this->textEncode($val['descr']), $tmp);
+            $tmp = str_replace('%default', $this->textEncode($val['default']), $tmp);
+            $list[] = $tmp;
+        }
+
+        // insert params into output
+        $tmp = implode($this->conf['list_sep'], $list);
+        $output = str_replace('%params', $tmp, $output);
+
+        // build the set of throws
+        $list = array();
+        foreach ($throws as $key => $val) {
+               $tmp = $this->conf['format_throws'];
+            $tmp = str_replace('%type', $this->textEncode($val['type']), $tmp);
+            $tmp = str_replace('%descr', $this->textEncode($val['descr']), $tmp);
+            $list[] = $tmp;
+        }
+
+        // insert throws into output
+        $tmp = implode($this->conf['list_sep'], $list);
+        $output = str_replace('%throws', $tmp, $output);
+
+        // close the div and return the output
+        $output .= '</div>';
+        return "\n$output\n\n";
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml/Heading.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,88 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Heading rule end renderer for Xhtml
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Heading.php,v 1.10 2005/09/18 13:39:39 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class renders headings in XHTML.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Xhtml_Heading extends Text_Wiki_Render {
+
+    var $conf = array(
+        'css_h1' => null,
+        'css_h2' => null,
+        'css_h3' => null,
+        'css_h4' => null,
+        'css_h5' => null,
+        'css_h6' => null
+    );
+
+    function token($options)
+    {
+    	$collapse = null;
+        static $jsOutput = false;
+        // get nice variable names (id, type, level)
+        extract($options);
+
+        switch($type) {
+        case 'start':
+            $css = $this->formatConf(' class="%s"', "css_h$level");
+            return '
+<h'.$level.$css.' id="'.$id.'"'.($collapse !== null ? ' onclick="hideTOC(\''.$id.'\');"' : '').'>';
+
+        case 'end':
+            return '</h'.$level.'>
+'.($collapse !== null ? '<a id="'.$id.'__link" href="javascript:void();" onclick="hideTOC(\''.$id.'\')">['.($collapse ? '+' : '-').']</a>
+' : '');
+        case 'startContent':
+            if ($collapse !== null) {
+                if ($jsOutput) {
+                    $js = '';
+                } else {
+                    $js = '
+<script language="javascript">
+function hideTOC(id) {
+    div = document.getElementById(id+"__content");
+    link = document.getElementById(id+"__link");
+    if (div.style.display == "none") {
+        div.style.display = "";
+        link.innerHTML = "[-]";
+    } else {
+        div.style.display = "none";
+        link.innerHTML = "[+]";
+    }
+}
+</script>
+';
+                }
+            } else {
+                $js = '';
+            }
+            return  $js.'
+<div style="'.($collapse === true ? 'display: none; ' : '').'padding: 0px; margin: 0px; border: none;" id="'.$id.'__content">
+';
+        case 'endContent':
+            return '
+</div>
+';
+        }
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml/Horiz.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,51 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Horiz rule end renderer for Xhtml
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Horiz.php,v 1.7 2005/07/30 08:03:28 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class renders an horizontal bar in XHTML.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Xhtml_Horiz extends Text_Wiki_Render {
+
+    var $conf = array(
+        'css' => null
+    );
+
+    /**
+    *
+    * Renders a token into text matching the requested format.
+    *
+    * @access public
+    *
+    * @param array $options The "options" portion of the token (second
+    * element).
+    *
+    * @return string The text rendered from the token options.
+    *
+    */
+
+    function token($options)
+    {
+        $css = $this->formatConf(' class="%s"', 'css');
+        return "<hr$css />\n";
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml/Html.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,47 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Html rule end renderer for Xhtml
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Html.php,v 1.5 2005/07/30 08:03:28 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class renders preformated html in XHTML.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Xhtml_Html extends Text_Wiki_Render {
+
+
+    /**
+    *
+    * Renders a token into text matching the requested format.
+    *
+    * @access public
+    *
+    * @param array $options The "options" portion of the token (second
+    * element).
+    *
+    * @return string The text rendered from the token options.
+    *
+    */
+
+    function token($options)
+    {
+        return $options['text'];
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml/Image.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,180 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Image rule end renderer for Xhtml
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Image.php,v 1.16 2006/02/10 23:07:03 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class inserts an image in XHTML.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Xhtml_Image extends Text_Wiki_Render {
+
+    var $conf = array(
+        'base' => '/',
+        'url_base' => null,
+        'css'  => null,
+        'css_link' => null
+    );
+
+
+    /**
+    *
+    * Renders a token into text matching the requested format.
+    *
+    * @access public
+    *
+    * @param array $options The "options" portion of the token (second
+    * element).
+    *
+    * @return string The text rendered from the token options.
+    *
+    */
+
+    function token($options)
+    {
+        // note the image source
+        $src = $options['src'];
+
+        // is the source a local file or URL?
+        if (strpos($src, '://') === false) {
+            // the source refers to a local file.
+            // add the URL base to it.
+            $src = $this->getConf('base', '/') . $src;
+        }
+
+        // stephane@metacites.net
+        // is the image clickable?
+        if (isset($options['attr']['link'])) {
+            // yes, the image is clickable.
+            // are we linked to a URL or a wiki page?
+            if (strpos($options['attr']['link'], '://')) {
+                // it's a URL, prefix the URL base
+                $href = $this->getConf('url_base') . $options['attr']['link'];
+            } else {
+                // it's a WikiPage; assume it exists.
+                /** @todo This needs to honor sprintf wikilinks (pmjones) */
+                /** @todo This needs to honor interwiki (pmjones) */
+                /** @todo This needs to honor freelinks (pmjones) */
+                $href = $this->wiki->getRenderConf('xhtml', 'wikilink', 'view_url') .
+                    $options['attr']['link'];
+            }
+        } else {
+            // image is not clickable.
+            $href = null;
+        }
+        // unset so it won't show up as an attribute
+        unset($options['attr']['link']);
+
+        // stephane@metacites.net -- 25/07/2004
+        // we make up an align="center" value for the <img> tag.
+        if (isset($options['attr']['align']) &&
+            $options['attr']['align'] == 'center') {
+
+            // unset so it won't show up as an attribute
+            unset($options['attr']['align']);
+
+            // make sure we have a style attribute
+            if (! isset($options['attr']['style'])) {
+                // no style, set up a blank one
+                $options['attr']['style'] = '';
+            } else {
+                // style exists, add a space
+                $options['attr']['style'] .= ' ';
+            }
+
+            // add a "center" style to the existing style.
+            $options['attr']['style'] .=
+                'display: block; margin-left: auto; margin-right: auto;';
+        }
+
+        // stephane@metacites.net -- 25/07/2004
+        // try to guess width and height
+        if (! isset($options['attr']['width']) &&
+            ! isset($options['attr']['height'])) {
+
+            // does the source refer to a local file or a URL?
+            if (strpos($src,'://')) {
+                // is a URL link
+                $imageFile = $src;
+            } elseif ($src[0] == '.') {
+            	// reg at dav-muz dot net -- 2005-03-07
+				// is a local file on relative path.
+				$imageFile = $src; # ...don't do anything because it's perfect!
+			} else {
+                // is a local file on absolute path.
+                $imageFile = $_SERVER['DOCUMENT_ROOT'] . $src;
+            }
+
+            // attempt to get the image size
+            $imageSize = @getimagesize($imageFile);
+
+            if (is_array($imageSize)) {
+                $options['attr']['width'] = $imageSize[0];
+                $options['attr']['height'] = $imageSize[1];
+            }
+
+        }
+
+        // start the HTML output
+        $output = '<img src="' . $this->textEncode($src) . '"';
+
+        // get the CSS class but don't add it yet
+        $css = $this->formatConf(' class="%s"', 'css');
+
+        // add the attributes to the output, and be sure to
+        // track whether or not we find an "alt" attribute
+        $alt = false;
+        foreach ($options['attr'] as $key => $val) {
+
+            // track the 'alt' attribute
+            if (strtolower($key) == 'alt') {
+                $alt = true;
+            }
+
+            // the 'class' attribute overrides the CSS class conf
+            if (strtolower($key) == 'class') {
+                $css = null;
+            }
+
+            $key = $this->textEncode($key);
+            $val = $this->textEncode($val);
+            $output .= " $key=\"$val\"";
+        }
+
+        // always add an "alt" attribute per Stephane Solliec
+        if (! $alt) {
+            $alt = $this->textEncode(basename($options['src']));
+            $output .= " alt=\"$alt\"";
+        }
+
+        // end the image tag with the automatic CSS class (if any)
+        $output .= "$css />";
+
+        // was the image clickable?
+        if ($href) {
+            // yes, add the href and return
+            $href = $this->textEncode($href);
+            $css = $this->formatConf(' class="%s"', 'css_link');
+            $output = "<a$css href=\"$href\">$output</a>";
+        }
+
+        return $output;
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml/Include.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,32 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Include rule end renderer for Xhtml
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Include.php,v 1.6 2005/07/30 08:03:28 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class renders included maekup in XHTML. (empty)
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Xhtml_Include extends Text_Wiki_Render {
+    function token()
+    {
+        return '';
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml/Interwiki.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,103 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Interwiki rule end renderer for Xhtml
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Interwiki.php,v 1.14 2006/02/25 05:03:13 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class renders inter wikis links in XHTML.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Xhtml_Interwiki extends Text_Wiki_Render {
+
+    var $conf = array(
+        'sites' => array(
+            'MeatBall' => 'http://www.usemod.com/cgi-bin/mb.pl?%s',
+            'Advogato' => 'http://advogato.org/%s',
+            'Wiki'       => 'http://c2.com/cgi/wiki?%s'
+        ),
+        'target' => '_blank',
+        'css' => null
+    );
+
+
+    /**
+    *
+    * Renders a token into text matching the requested format.
+    *
+    * @access public
+    *
+    * @param array $options The "options" portion of the token (second
+    * element).
+    *
+    * @return string The text rendered from the token options.
+    *
+    */
+
+    function token($options)
+    {
+        $text = $options['text'];
+        if (isset($options['url'])) {
+            // calculated by the parser (e.g. Mediawiki)
+            $href = $options['url'];
+        } else {
+            $site = $options['site'];
+            // toggg 2006/02/05 page name must be url encoded (e.g. may contain spaces)
+            $page = $this->urlEncode($options['page']);
+
+            if (isset($this->conf['sites'][$site])) {
+                $href = $this->conf['sites'][$site];
+            } else {
+                return $text;
+            }
+
+            // old form where page is at end,
+            // or new form with %s placeholder for sprintf()?
+            if (strpos($href, '%s') === false) {
+                // use the old form
+                $href = $href . $page;
+            } else {
+                // use the new form
+                $href = sprintf($href, $page);
+            }
+        }
+
+        // allow for alternative targets
+        $target = $this->getConf('target');
+
+        // build base link
+        $css = $this->formatConf(' class="%s"', 'css');
+        $text = $this->textEncode($text);
+        $output = "<a$css href=\"$href\"";
+
+        // are we targeting a specific window?
+        if ($target) {
+            // this is XHTML compliant, suggested by Aaron Kalin.
+            // code tip is actually from youngpup.net, and it
+            // uses the $target as the new window name.
+            $target = $this->textEncode($target);
+            $output .= " onclick=\"window.open(this.href, '$target');";
+            $output .= " return false;\"";
+        }
+
+        $output .= ">$text</a>";
+
+        return $output;
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml/Italic.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,57 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Italic rule end renderer for Xhtml
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Italic.php,v 1.7 2005/07/30 08:03:28 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class renders italic text in XHTML.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Xhtml_Italic extends Text_Wiki_Render {
+
+    var $conf = array(
+        'css' => null
+    );
+
+    /**
+    *
+    * Renders a token into text matching the requested format.
+    *
+    * @access public
+    *
+    * @param array $options The "options" portion of the token (second
+    * element).
+    *
+    * @return string The text rendered from the token options.
+    *
+    */
+
+    function token($options)
+    {
+        if ($options['type'] == 'start') {
+            $css = $this->formatConf(' class="%s"', 'css');
+            return "<i$css>";
+        }
+
+        if ($options['type'] == 'end') {
+            return '</i>';
+        }
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml/List.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,172 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * List rule end renderer for Xhtml
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: List.php,v 1.9 2005/11/06 10:38:22 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class renders bullet and ordered lists in XHTML.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Xhtml_List extends Text_Wiki_Render {
+
+    var $conf = array(
+        'css_ol' => null,
+        'css_ol_li' => null,
+        'css_ul' => null,
+        'css_ul_li' => null
+    );
+
+    /**
+    *
+    * Renders a token into text matching the requested format.
+    *
+    * This rendering method is syntactically and semantically compliant
+    * with XHTML 1.1 in that sub-lists are part of the previous list item.
+    *
+    * @access public
+    *
+    * @param array $options The "options" portion of the token (second
+    * element).
+    *
+    * @return string The text rendered from the token options.
+    *
+    */
+
+    function token($options)
+    {
+        // make nice variables (type, level, count)
+        extract($options);
+
+        // set up indenting so that the results look nice; we do this
+        // in two steps to avoid str_pad mathematics.  ;-)
+        $pad = str_pad('', $level, "\t");
+        $pad = str_replace("\t", '    ', $pad);
+
+        switch ($type) {
+
+        case 'bullet_list_start':
+
+            // build the base HTML
+            $css = $this->formatConf(' class="%s"', 'css_ul');
+            $html = "<ul$css>";
+
+            /*
+            // if this is the opening block for the list,
+            // put an extra newline in front of it so the
+            // output looks nice.
+            if ($level == 0) {
+                $html = "\n$html";
+            }
+            */
+
+            // done!
+            return $html;
+            break;
+
+        case 'bullet_list_end':
+
+            // build the base HTML
+            $html = "</li>\n$pad</ul>";
+
+            // if this is the closing block for the list,
+            // put extra newlines after it so the output
+            // looks nice.
+            if ($level == 0) {
+                $html .= "\n\n";
+            }
+
+            // done!
+            return $html;
+            break;
+
+        case 'number_list_start':
+            if (isset($format)) {
+                $format = ' type="' . $format . '"';
+            } else  {
+                $format = '';
+            }
+            // build the base HTML
+            $css = $this->formatConf(' class="%s"', 'css_ol');
+            $html = "<ol{$format}{$css}>";
+
+            /*
+            // if this is the opening block for the list,
+            // put an extra newline in front of it so the
+            // output looks nice.
+            if ($level == 0) {
+                $html = "\n$html";
+            }
+            */
+
+            // done!
+            return $html;
+            break;
+
+        case 'number_list_end':
+
+            // build the base HTML
+            $html = "</li>\n$pad</ol>";
+
+            // if this is the closing block for the list,
+            // put extra newlines after it so the output
+            // looks nice.
+            if ($level == 0) {
+                $html .= "\n\n";
+            }
+
+            // done!
+            return $html;
+            break;
+
+        case 'bullet_item_start':
+        case 'number_item_start':
+
+            // pick the proper CSS class
+            if ($type == 'bullet_item_start') {
+                $css = $this->formatConf(' class="%s"', 'css_ul_li');
+            } else {
+                $css = $this->formatConf(' class="%s"', 'css_ol_li');
+            }
+
+            // build the base HTML
+            $html = "\n$pad<li$css>";
+
+            // for the very first item in the list, do nothing.
+            // but for additional items, be sure to close the
+            // previous item.
+            if ($count > 0) {
+                $html = "</li>$html";
+            }
+
+            // done!
+            return $html;
+            break;
+
+        case 'bullet_item_end':
+        case 'number_item_end':
+        default:
+            // ignore item endings and all other types.
+            // item endings are taken care of by the other types
+            // depending on their place in the list.
+            return '';
+            break;
+        }
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml/Newline.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,35 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Newline rule end renderer for Xhtml
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Newline.php,v 1.5 2005/07/30 08:03:29 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class renders new lines in XHTML.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Xhtml_Newline extends Text_Wiki_Render {
+
+
+    function token($options)
+    {
+        return "<br />\n";
+    }
+}
+
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml/Page.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,46 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Page rule end renderer for Xhtml
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Page.php,v 1.2 2005/07/30 08:03:29 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class renders page markers in XHTML.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Xhtml_Page extends Text_Wiki_Render {
+
+    /**
+    *
+    * Renders a token into text matching the requested format.
+    *
+    * @access public
+    *
+    * @param array $options The "options" portion of the token (second
+    * element).
+    *
+    * @return string The text rendered from the token options.
+    *
+    */
+
+    function token($options)
+    {
+        return 'PAGE MARKER HERE*&^%$#^$%*PAGEMARKERHERE';
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml/Paragraph.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,59 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Paragraph rule end renderer for Xhtml
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Paragraph.php,v 1.7 2005/07/30 08:03:29 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class renders paragraphs in XHTML.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Xhtml_Paragraph extends Text_Wiki_Render {
+
+    var $conf = array(
+        'css' => null
+    );
+
+    /**
+    *
+    * Renders a token into text matching the requested format.
+    *
+    * @access public
+    *
+    * @param array $options The "options" portion of the token (second
+    * element).
+    *
+    * @return string The text rendered from the token options.
+    *
+    */
+
+    function token($options)
+    {
+        extract($options); //type
+
+        if ($type == 'start') {
+            $css = $this->formatConf(' class="%s"', 'css');
+            return "<p$css>";
+        }
+
+        if ($type == 'end') {
+            return "</p>\n\n";
+        }
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml/Phplookup.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,81 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Phplookup rule end renderer for Xhtml
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Phplookup.php,v 1.11 2006/02/10 23:07:03 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class renders a link to php functions description in XHTML.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Xhtml_Phplookup extends Text_Wiki_Render {
+
+    var $conf = array(
+        'target' => '_blank',
+        'css' => null
+    );
+
+
+    /**
+    *
+    * Renders a token into text matching the requested format.
+    *
+    * @access public
+    *
+    * @param array $options The "options" portion of the token (second
+    * element).
+    *
+    * @return string The text rendered from the token options.
+    *
+    */
+
+    function token($options)
+    {
+        $text = trim($options['text']);
+        $css = $this->formatConf(' class="%s"', 'css');
+
+        // start the html
+        $output = "<a$css";
+
+        // are we targeting another window?
+        $target = $this->getConf('target', '');
+        if ($target) {
+            // use a "popup" window.  this is XHTML compliant, suggested by
+            // Aaron Kalin.  uses the $target as the new window name.
+            $target = $this->textEncode($target);
+            $output .= " onclick=\"window.open(this.href, '$target');";
+            $output .= " return false;\"";
+        }
+
+        // take off the final parens for functions
+        if (substr($text, -2) == '()') {
+            $q = substr($text, 0, -2);
+        } else {
+            $q = $text;
+        }
+
+        // toggg 2006/02/05 page name must be url encoded (e.g. may contain spaces)
+        $q = $this->urlEncode($q);
+        $text = $this->textEncode($text);
+
+        // finish and return
+        $output .= " href=\"http://php.net/$q\">$text</a>";
+        return $output;
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml/Plugin.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,47 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Plugin rule end renderer for Xhtml
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Plugin.php,v 1.2 2005/07/30 08:03:29 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class renders wiki plugins in XHTML. (empty)
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Xhtml_Plugin extends Text_Wiki_Render {
+
+    /**
+    *
+    * Renders a token into text matching the requested format.
+    * Plugins produce wiki markup so are processed by parsing, no tokens produced
+    *
+    * @access public
+    *
+    * @param array $options The "options" portion of the token (second
+    * element).
+    *
+    * @return string The text rendered from the token options.
+    *
+    */
+
+    function token($options)
+    {
+        return '';
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml/Prefilter.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,34 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Prefilter rule end renderer for Xhtml
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Prefilter.php,v 1.7 2005/07/30 08:03:29 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class implements a Text_Wiki_Render_Xhtml to "pre-filter" source text so
+ * that line endings are consistently \n, lines ending in a backslash \
+ * are concatenated with the next line, and tabs are converted to spaces.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Xhtml_Prefilter extends Text_Wiki_Render {
+    function token()
+    {
+        return '';
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml/Preformatted.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,46 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Preformatted rule end renderer for Xhtml
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Preformatted.php,v 1.2 2005/07/30 08:03:29 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class renders preformated text in XHTML.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Xhtml_Preformatted extends Text_Wiki_Render {
+
+    /**
+    *
+    * Renders a token into text matching the requested format.
+    *
+    * @access public
+    *
+    * @param array $options The "options" portion of the token (second
+    * element).
+    *
+    * @return string The text rendered from the token options.
+    *
+    */
+
+    function token($options)
+    {
+        return '<pre>'.$options['text'].'</pre>';
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml/Raw.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,46 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Raw rule end renderer for Xhtml
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Raw.php,v 1.5 2005/07/30 08:03:29 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class renders not processed blocks in XHTML.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Xhtml_Raw extends Text_Wiki_Render {
+
+    /**
+    *
+    * Renders a token into text matching the requested format.
+    *
+    * @access public
+    *
+    * @param array $options The "options" portion of the token (second
+    * element).
+    *
+    * @return string The text rendered from the token options.
+    *
+    */
+
+    function token($options)
+    {
+        return $options['text'];
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml/Revise.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,68 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Revise rule end renderer for Xhtml
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Revise.php,v 1.7 2005/07/30 08:03:29 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class renders revision marks in XHTML.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Xhtml_Revise extends Text_Wiki_Render {
+
+    var $conf = array(
+        'css_ins' => null,
+        'css_del' => null
+    );
+
+
+    /**
+    *
+    * Renders a token into text matching the requested format.
+    *
+    * @access public
+    *
+    * @param array $options The "options" portion of the token (second
+    * element).
+    *
+    * @return string The text rendered from the token options.
+    *
+    */
+
+    function token($options)
+    {
+        if ($options['type'] == 'del_start') {
+            $css = $this->formatConf(' class="%s"', 'css_del');
+            return "<del$css>";
+        }
+
+        if ($options['type'] == 'del_end') {
+            return "</del>";
+        }
+
+        if ($options['type'] == 'ins_start') {
+            $css = $this->formatConf(' class="%s"', 'css_ins');
+            return "<ins$css>";
+        }
+
+        if ($options['type'] == 'ins_end') {
+            return "</ins>";
+        }
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml/Smiley.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,74 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Smiley rule Xhtml renderer
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Bertrand Gugger <bertrand@toggg.com>
+ * @copyright  2005 bertrand Gugger
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Smiley.php,v 1.2 2006/02/10 23:07:03 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * Smiley rule Xhtml render class
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Bertrand Gugger <bertrand@toggg.com>
+ * @copyright  2005 bertrand Gugger
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ * @see        Text_Wiki::Text_Wiki_Render()
+ */
+class Text_Wiki_Render_Xhtml_Smiley extends Text_Wiki_Render {
+
+    /**
+     * Configuration keys for this rule
+     * 'prefix' => the path to smileys images inclusive file name prefix,
+     *             starts with '/' ==> abolute reference
+     *             if no file names prefix but some folder, terminates with '/'
+     * 'extension' => the file extension (inclusive '.'), e.g. :
+     *       if prefix 'smileys/icon_' and extension '.gif'
+     *       ':)' whose name is 'smile' will give relative file 'smileys/icon_smile.gif'
+     *       if prefix '/image/smileys/' and extension '.png': absolute '/image/smileys/smile.gif'
+     * 'css' => optional style applied to smileys
+     *
+     * @access public
+     * @var array 'config-key' => mixed config-value
+     */
+    var $conf = array(
+        'prefix' => 'images/smiles/icon_',
+        'extension' => '.gif',
+        'css' => null
+    );
+
+    /**
+      * Renders a token into text matching the requested format.
+      * process the Smileys
+      *
+      * @access public
+      * @param array $options The "options" portion of the token (second element).
+      * @return string The text rendered from the token options.
+      */
+    function token($options)
+    {
+        $imageFile = $this->getConf('prefix') . $options['name'] . $this->getConf('extension');
+
+        // attempt to get the image size
+        $imageSize = @getimagesize($imageFile);
+
+        // return the HTML output
+        return '<img src="' . $this->textEncode($imageFile) . '"' .
+            (is_array($imageSize) ?
+                ' width="' . $imageSize[0] . '" height="' . $imageSize[1] .'"' : '') .
+            ' alt="' . $options['desc'] . '"' .
+            $this->formatConf(' class="%s"', 'css') . ' />';
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml/Specialchar.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,52 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Specialchar rule end renderer for Xhtml
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Specialchar.php,v 1.2 2005/07/30 08:03:29 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class renders special characters in XHTML.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Xhtml_SpecialChar extends Text_Wiki_Render {
+
+    var $types = array('~bs~' => '&#92;',
+                       '~hs~' => '&nbsp;',
+                       '~amp~' => '&amp;',
+                       '~ldq~' => '&ldquo;',
+                       '~rdq~' => '&rdquo;',
+                       '~lsq~' => '&lsquo;',
+                       '~rsq~' => '&rsquo;',
+                       '~c~' => '&copy;',
+                       '~--~' => '&mdash;',
+                       '" -- "' => '&mdash;',
+                       '&quot; -- &quot;' => '&mdash;',
+                       '~lt~' => '&lt;',
+                       '~gt~' => '&gt;');
+
+    function token($options)
+    {
+        if (isset($this->types[$options['char']])) {
+            return $this->types[$options['char']];
+        } else {
+            return '&#'.substr($options['char'], 1, -1).';';
+        }
+    }
+}
+
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml/Strong.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,58 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Strong rule end renderer for Xhtml
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Strong.php,v 1.7 2005/07/30 08:03:29 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class renders text marked as strong in XHTML.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Xhtml_Strong extends Text_Wiki_Render {
+
+
+    var $conf = array(
+        'css' => null
+    );
+
+    /**
+    *
+    * Renders a token into text matching the requested format.
+    *
+    * @access public
+    *
+    * @param array $options The "options" portion of the token (second
+    * element).
+    *
+    * @return string The text rendered from the token options.
+    *
+    */
+
+    function token($options)
+    {
+        if ($options['type'] == 'start') {
+            $css = $this->formatConf(' class="%s"', 'css');
+            return "<strong$css>";
+        }
+
+        if ($options['type'] == 'end') {
+            return '</strong>';
+        }
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml/Subscript.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,57 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Subscript rule end renderer for Xhtml
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Subscript.php,v 1.2 2005/07/30 08:03:29 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class renders subscript text in XHTML.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Xhtml_Subscript extends Text_Wiki_Render {
+
+    var $conf = array(
+        'css' => null
+    );
+
+    /**
+    *
+    * Renders a token into text matching the requested format.
+    *
+    * @access public
+    *
+    * @param array $options The "options" portion of the token (second
+    * element).
+    *
+    * @return string The text rendered from the token options.
+    *
+    */
+
+    function token($options)
+    {
+        if ($options['type'] == 'start') {
+            $css = $this->formatConf(' class="%s"', 'css');
+            return "<sub$css>";
+        }
+
+        if ($options['type'] == 'end') {
+            return '</sub>';
+        }
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml/Superscript.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,57 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Superscript rule end renderer for Xhtml
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Superscript.php,v 1.7 2005/07/30 08:03:29 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class renders superscript text in XHTML.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Xhtml_Superscript extends Text_Wiki_Render {
+
+    var $conf = array(
+        'css' => null
+    );
+
+    /**
+    *
+    * Renders a token into text matching the requested format.
+    *
+    * @access public
+    *
+    * @param array $options The "options" portion of the token (second
+    * element).
+    *
+    * @return string The text rendered from the token options.
+    *
+    */
+
+    function token($options)
+    {
+        if ($options['type'] == 'start') {
+            $css = $this->formatConf(' class="%s"', 'css');
+            return "<sup$css>";
+        }
+
+        if ($options['type'] == 'end') {
+            return '</sup>';
+        }
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml/Table.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,140 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Table rule end renderer for Xhtml
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Table.php,v 1.12 2005/12/06 15:29:29 ritzmo Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class renders tables in XHTML.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Xhtml_Table extends Text_Wiki_Render {
+
+    var $conf = array(
+        'css_table' => null,
+        'css_caption' => null,
+        'css_tr' => null,
+        'css_th' => null,
+        'css_td' => null
+    );
+
+
+    /**
+    *
+    * Renders a token into text matching the requested format.
+    *
+    * @access public
+    *
+    * @param array $options The "options" portion of the token (second
+    * element).
+    *
+    * @return string The text rendered from the token options.
+    *
+    */
+
+    function token($options)
+    {
+        // make nice variable names (type, attr, span)
+        $span = $rowspan = 1;
+        extract($options);
+
+        // free format
+        $format = isset($format) ? ' '. $format : '';
+
+        $pad = '    ';
+
+        switch ($type) {
+
+        case 'table_start':
+            $css = $this->formatConf(' class="%s"', 'css_table');
+            return "\n\n<table$css$format>\n";
+            break;
+
+        case 'table_end':
+            return "</table>\n\n";
+            break;
+
+        case 'caption_start':
+            $css = $this->formatConf(' class="%s"', 'css_caption');
+            return "<caption$css$format>\n";
+            break;
+
+        case 'caption_end':
+            return "</caption>\n";
+            break;
+
+        case 'row_start':
+            $css = $this->formatConf(' class="%s"', 'css_tr');
+            return "$pad<tr$css$format>\n";
+            break;
+
+        case 'row_end':
+            return "$pad</tr>\n";
+            break;
+
+        case 'cell_start':
+
+            // base html
+            $html = $pad . $pad;
+
+            // is this a TH or TD cell?
+            if ($attr == 'header') {
+                // start a header cell
+                $css = $this->formatConf(' class="%s"', 'css_th');
+                $html .= "<th$css";
+            } else {
+                // start a normal cell
+                $css = $this->formatConf(' class="%s"', 'css_td');
+                $html .= "<td$css";
+            }
+
+            // add the column span
+            if ($span > 1) {
+                $html .= " colspan=\"$span\"";
+            }
+
+            // add the row span
+            if ($rowspan > 1) {
+                $html .= " rowspan=\"$rowspan\"";
+            }
+
+            // add alignment
+            if ($attr != 'header' && $attr != '') {
+                $html .= " style=\"text-align: $attr;\"";
+            }
+
+            // done!
+            $html .= "$format>";
+            return $html;
+            break;
+
+        case 'cell_end':
+            if ($attr == 'header') {
+                return "</th>\n";
+            } else {
+                return "</td>\n";
+            }
+            break;
+
+        default:
+            return '';
+
+        }
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml/Tighten.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,34 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Tighten rule end renderer for Xhtml
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Tighten.php,v 1.6 2005/07/30 08:03:29 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class makes the tightening in XHTML. (empty)
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Xhtml_Tighten extends Text_Wiki_Render {
+
+
+    function token()
+    {
+        return '';
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml/Titlebar.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,57 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Titlebar rule end renderer for Xhtml
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Titlebar.php,v 1.2 2005/07/30 08:03:29 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class renders a title bar in XHTML.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Xhtml_Titlebar extends Text_Wiki_Render {
+
+    var $conf = array(
+        'css' => 'titlebar'
+    );
+
+    /**
+    *
+    * Renders a token into text matching the requested format.
+    *
+    * @access public
+    *
+    * @param array $options The "options" portion of the token (second
+    * element).
+    *
+    * @return string The text rendered from the token options.
+    *
+    */
+
+    function token($options)
+    {
+        if ($options['type'] == 'start') {
+            $css = $this->formatConf(' class="%s"', 'css');
+            return "<div$css>";
+        }
+
+        if ($options['type'] == 'end') {
+            return '</div>';
+        }
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml/Toc.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,115 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Toc rule end renderer for Xhtml
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Toc.php,v 1.9 2005/07/30 08:03:29 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class inserts a table of content in XHTML.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Xhtml_Toc extends Text_Wiki_Render {
+
+    var $conf = array(
+        'css_list' => null,
+        'css_item' => null,
+        'title' => '<strong>Table of Contents</strong>',
+        'div_id' => 'toc',
+        'collapse' => true
+    );
+
+    var $min = 2;
+
+    /**
+    *
+    * Renders a token into text matching the requested format.
+    *
+    * @access public
+    *
+    * @param array $options The "options" portion of the token (second
+    * element).
+    *
+    * @return string The text rendered from the token options.
+    *
+    */
+
+    function token($options)
+    {
+        // type, id, level, count, attr
+        extract($options);
+
+        switch ($type) {
+
+        case 'list_start':
+
+            $css = $this->getConf('css_list');
+            $html = '';
+
+            // collapse div within a table?
+            if ($this->getConf('collapse')) {
+                $html .= '<table border="0" cellspacing="0" cellpadding="0">';
+                $html .= "<tr><td>\n";
+            }
+
+            // add the div, class, and id
+            $html .= '<div';
+            if ($css) {
+                $html .= " class=\"$css\"";
+            }
+
+            $div_id = $this->getConf('div_id');
+            if ($div_id) {
+                $html .= " id=\"$div_id\"";
+            }
+
+            // add the title, and done
+            $html .= '>';
+            $html .= $this->getConf('title');
+            return $html;
+            break;
+
+        case 'list_end':
+        	if ($this->getConf('collapse')) {
+        	    return "\n</div>\n</td></tr></table>\n\n";
+        	} else {
+                return "\n</div>\n\n";
+            }
+            break;
+
+        case 'item_start':
+            $html = "\n\t<div";
+
+            $css = $this->getConf('css_item');
+            if ($css) {
+                $html .= " class=\"$css\"";
+            }
+
+            $pad = ($level - $this->min);
+            $html .= " style=\"margin-left: {$pad}em;\">";
+
+            $html .= "<a href=\"#$id\">";
+            return $html;
+            break;
+
+        case 'item_end':
+            return "</a></div>";
+            break;
+        }
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml/Tt.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,58 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Tt rule end renderer for Xhtml
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Tt.php,v 1.7 2005/07/30 08:03:29 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class renders monospaced text in XHTML.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Xhtml_Tt extends Text_Wiki_Render {
+
+
+    var $conf = array(
+        'css' => null
+    );
+
+    /**
+    *
+    * Renders a token into text matching the requested format.
+    *
+    * @access public
+    *
+    * @param array $options The "options" portion of the token (second
+    * element).
+    *
+    * @return string The text rendered from the token options.
+    *
+    */
+
+    function token($options)
+    {
+        if ($options['type'] == 'start') {
+            $css = $this->formatConf(' class="%s"', 'css');
+            return "<tt$css>";
+        }
+
+        if ($options['type'] == 'end') {
+            return '</tt>';
+        }
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml/Underline.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,57 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Underline rule end renderer for Xhtml
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Underline.php,v 1.2 2005/07/30 08:03:29 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class renders underlined text in XHTML.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Xhtml_Underline extends Text_Wiki_Render {
+
+    var $conf = array(
+        'css' => null
+    );
+
+    /**
+    *
+    * Renders a token into text matching the requested format.
+    *
+    * @access public
+    *
+    * @param array $options The "options" portion of the token (second
+    * element).
+    *
+    * @return string The text rendered from the token options.
+    *
+    */
+
+    function token($options)
+    {
+        if ($options['type'] == 'start') {
+            $css = $this->formatConf(' class="%s"', 'css');
+            return "<u$css>";
+        }
+
+        if ($options['type'] == 'end') {
+            return '</u>';
+        }
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml/Url.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,128 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Url rule end renderer for Xhtml
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Url.php,v 1.13 2006/02/10 23:07:03 toggg Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class renders URL links in XHTML.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Xhtml_Url extends Text_Wiki_Render {
+
+
+    var $conf = array(
+        'target' => '_blank',
+        'images' => true,
+        'img_ext' => array('jpg', 'jpeg', 'gif', 'png'),
+        'css_inline' => null,
+        'css_footnote' => null,
+        'css_descr' => null,
+        'css_img' => null
+    );
+
+    /**
+    *
+    * Renders a token into text matching the requested format.
+    *
+    * @access public
+    *
+    * @param array $options The "options" portion of the token (second
+    * element).
+    *
+    * @return string The text rendered from the token options.
+    *
+    */
+
+    function token($options)
+    {
+      global $email;
+        // create local variables from the options array (text,
+        // href, type)
+        extract($options);
+        
+        $quote = '"';
+
+        // find the rightmost dot and determine the filename
+        // extension.
+        $pos = strrpos($href, '.');
+        $ext = strtolower(substr($href, $pos + 1));
+        
+        if(substr($href, 0, 7) == 'mailto:')
+        {
+          $a = substr($href, 7);
+          $code = $email->encryptEmail($a, '', '', $text);
+          return $code;
+        }
+        
+        $href = $this->textEncode($href);
+
+        // does the filename extension indicate an image file?
+        if ($this->getConf('images') &&
+            in_array($ext, $this->getConf('img_ext', array()))) {
+
+            // create alt text for the image
+            if (! isset($text) || $text == '') {
+                $text = basename($href);
+                $text = $this->textEncode($text);
+            }
+
+            // generate an image tag
+            $css = $this->formatConf(' class="%s"', 'css_img');
+            $output = "<img$css src={$quote}$href{$quote} alt={$quote}$text{$quote} />";
+
+        } else {
+          
+            // should we build a target clause?
+            if ($href{0} == '#' ||
+            	strtolower(substr($href, 0, 7)) == 'mailto:') {
+            	// targets not allowed for on-page anchors
+            	// and mailto: links.
+                $target = '';
+            } else {
+				// allow targets on non-anchor non-mailto links
+                $target = $this->getConf('target');
+            }
+
+            // generate a regular link (not an image)
+            $text = $this->textEncode($text);
+            $css = $this->formatConf(' class="%s"', "css_$type");
+            $output = "<a$css href={$quote}$href{$quote}";
+
+            if ($target) {
+                // use a "popup" window.  this is XHTML compliant, suggested by
+                // Aaron Kalin.  uses the $target as the new window name.
+                $target = $this->textEncode($target);
+                $output .= " onclick={$quote}window.open(this.href, '$target');";
+                $output .= " return false;{$quote}";
+            }
+
+            // finish up output
+            $output .= ">$text</a>";
+
+            // make numbered references look like footnotes when no
+            // CSS class specified, make them superscript by default
+            if ($type == 'footnote' && ! $css) {
+                $output = '<sup>' . $output . '</sup>';
+            }
+        }
+
+        return $output;
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Render/Xhtml/Wikilink.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,163 @@
+<?php
+// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+/**
+ * Wikilink rule end renderer for Xhtml
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    CVS: $Id: Wikilink.php,v 1.17 2006/02/28 03:15:09 justinpatrin Exp $
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+
+/**
+ * This class renders wiki links in XHTML.
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
+ * @version    Release: @package_version@
+ * @link       http://pear.php.net/package/Text_Wiki
+ */
+class Text_Wiki_Render_Xhtml_Wikilink extends Text_Wiki_Render {
+
+  var $conf;
+  
+  function Text_Wiki_Render_Xhtml_Wikilink() {
+    $_utemp = contentPath.'%s';
+    $this->conf = array(
+        'pages' => array(), // set to null or false to turn off page checks
+        'view_url' => $_utemp,
+        'new_url'  => $_utemp,
+        'new_text' => ' [x]',
+        'new_text_pos' => false, // 'before', 'after', or null/false
+        'css' => null,
+        'css_new' => null,
+        'exists_callback' => 'isPage' // call_user_func() callback
+    );
+  }
+
+    /**
+    *
+    * Renders a token into XHTML.
+    *
+    * @access public
+    *
+    * @param array $options The "options" portion of the token (second
+    * element).
+    *
+    * @return string The text rendered from the token options.
+    *
+    */
+
+    function token($options)
+    {
+        global $session;
+        if($session->sid_super) $as = htmlspecialchars(urlSeparator).'auth='.$session->sid_super;
+        else $as = '';
+        // make nice variable names (page, anchor, text)
+        extract($options);
+
+        // is there a "page existence" callback?
+        // we need to access it directly instead of through
+        // getConf() because we'll need a reference (for
+        // object instance method callbacks).
+        if (isset($this->conf['exists_callback'])) {
+            $callback =& $this->conf['exists_callback'];
+        } else {
+        	$callback = false;
+        }
+
+        if ($callback) {
+            // use the callback function
+            $exists = call_user_func($callback, $page);
+        } else {
+            // no callback, go to the naive page array.
+            $list = $this->getConf('pages');
+            if (is_array($list)) {
+                // yes, check against the page list
+                $exists = in_array($page, $list);
+            } else {
+                // no, assume it exists
+                $exists = true;
+            }
+        }
+
+        // convert *after* checking against page names so as not to mess
+        // up what the user typed and what we're checking.
+        //$page = $this->urlEncode($page);
+        $anchor = $this->urlEncode($anchor);
+        $text = $this->textEncode($text);
+
+        // does the page exist?
+        if ($exists) {
+
+            // PAGE EXISTS.
+
+            // link to the page view, but we have to build
+            // the HREF.  we support both the old form where
+            // the page always comes at the end, and the new
+            // form that uses %s for sprintf()
+            $href = $this->getConf('view_url');
+
+            if (strpos($href, '%s') === false) {
+                // use the old form (page-at-end)
+                $href = $href . $page . $anchor;
+            } else {
+                // use the new form (sprintf format string)
+                $href = sprintf($href, $page . $anchor);
+            }
+
+            // get the CSS class and generate output
+            $css = $this->formatConf(' class="%s"', 'css');
+
+            $start = '<a'.$css.' href="'.$href.$as.'">';
+            $end = '</a>';
+        } else {
+
+            // PAGE DOES NOT EXIST.
+
+            // link to the page view, but we have to build
+            // the HREF.  we support both the old form where
+            // the page always comes at the end, and the new
+            // form that uses %s for sprintf()
+            $href = $this->getConf('view_url');
+
+            if (strpos($href, '%s') === false) {
+                // use the old form (page-at-end)
+                $href = $href . $page . $anchor;
+            } else {
+                // use the new form (sprintf format string)
+                $href = sprintf($href, $page . $anchor);
+            }
+
+            // get the CSS class and generate output
+            $css = $this->formatConf(' class="%s"', 'css');
+
+            $start = '<a'.$css.' href="'.$href.$as.'" class="wikilink-nonexistent">';
+            $end = '</a>';
+            
+        }
+        if (!strlen($text)) {
+            $start .= $this->textEncode($options['page']);
+        }
+        if (isset($type)) {
+            switch ($type) {
+            case 'start':
+                $output = $start;
+                break;
+            case 'end':
+                $output = $end;
+                break;
+            }
+        } else {
+            $output = $start.$text.$end;
+        }
+        return $output;
+    }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiengine/Tables.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,997 @@
+<?php
+
+/**
+ * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
+ * Version 1.0 (Banshee)
+ * Copyright (C) 2006-2007 Dan Fuhry
+ *
+ * This program is Free Software; you can redistribute 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 details.
+ *
+ * This script contains code originally found in MediaWiki (http://www.mediawiki.org). MediaWiki is also licensed under
+ * the GPLv2; see the file GPL included with this package for details.
+ *
+ * We're using the MW parser because the Text_Wiki version simply refused to work under PHP 5.2.0. Porting this was
+ * _not_ easy. <leaves to get cup of coffee>
+ */
+
+  global $mStripState, $wgRandomKey;
+  $mStripState = Array();
+  
+  $attrib = '[a-zA-Z0-9]';
+  $space = '[\x09\x0a\x0d\x20]';
+  
+  define( 'MW_CHAR_REFS_REGEX',
+	'/&([A-Za-z0-9]+);
+	 |&\#([0-9]+);
+	 |&\#x([0-9A-Za-z]+);
+	 |&\#X([0-9A-Za-z]+);
+	 |(&)/x' );
+  
+  define( 'MW_ATTRIBS_REGEX',
+    "/(?:^|$space)($attrib+)
+      ($space*=$space*
+      (?:
+       # The attribute value: quoted or alone
+        ".'"'."([^<".'"'."]*)".'"'."
+       | '([^<']*)'
+       |  ([a-zA-Z0-9!#$%&()*,\\-.\\/:;<>?@[\\]^_`{|}~]+)
+       |  (\#[0-9a-fA-F]+) # Technically wrong, but lots of
+                 # colors are specified like this.
+                 # We'll be normalizing it.
+      )
+       )?(?=$space|\$)/sx" );
+  
+  /**
+   * emulate mediawiki parser, including stripping, etc.
+   *
+   * @param string $text the text to parse
+   * @return string
+   * @access public
+   */
+   
+  function process_tables( $text )
+  {
+    // include some globals, do some parser stuff that would normally be done in the parent parser function
+    global $mStripState;
+    $x =& $mStripState;
+		//$text = mwStrip( $text, $x );
+    
+    // parse the text
+    $text = doTableStuff($text);
+    
+    // Unstrip it
+    // $text = unstrip( $text, $mStripState );
+    // $text = unstripNoWiki( $text, $mStripState );
+    //die('<pre>'.print_r($mStripState, true).'</pre>');
+    return $text;
+  }
+
+  /**
+	 * parse the wiki syntax used to render tables
+	 *
+   * @param string $t the text to parse
+   * @return string
+	 * @access private
+	 */
+	function doTableStuff( $t ) {
+    
+		$t = explode ( "\n" , $t ) ;
+		$td = array () ; # Is currently a td tag open?
+		$ltd = array () ; # Was it TD or TH?
+		$tr = array () ; # Is currently a tr tag open?
+		$ltr = array () ; # tr attributes
+		$has_opened_tr = array(); # Did this table open a <tr> element?
+		$indent_level = 0; # indent level of the table
+		foreach ( $t AS $k => $x )
+		{
+			$x = trim ( $x ) ;
+			$fc = substr ( $x , 0 , 1 ) ;
+			if ( preg_match( '/^(:*)\{\|(.*)$/', $x, $matches ) ) {
+				$indent_level = strlen( $matches[1] );
+
+				$attributes = unstripForHTML( $matches[2] );
+
+				$t[$k] = str_repeat( '<dl><dd>', $indent_level ) .
+					'<nowiki><table' . fixTagAttributes( $attributes, 'table' ) . '></nowiki>' ;
+				array_push ( $td , false ) ;
+				array_push ( $ltd , '' ) ;
+				array_push ( $tr , false ) ;
+				array_push ( $ltr , '' ) ;
+				array_push ( $has_opened_tr, false );
+			}
+			else if ( count ( $td ) == 0 ) { } # Don't do any of the following
+			else if ( '|}' == substr ( $x , 0 , 2 ) ) {
+				$z = "<nowiki></table></nowiki>" . substr ( $x , 2);
+				$l = array_pop ( $ltd ) ;
+				if ( !array_pop ( $has_opened_tr ) ) $z = "<nowiki><tr><td></td></tr></nowiki>" . $z ;
+				if ( array_pop ( $tr ) ) $z = '<nowiki></tr></nowiki>' . $z ;
+				if ( array_pop ( $td ) ) $z = '<nowiki></'.$l.'></nowiki>' . $z ;
+				array_pop ( $ltr ) ;
+				$t[$k] = $z . str_repeat( '<nowiki></dd></dl></nowiki>', $indent_level );
+			}
+			else if ( '|-' == substr ( $x , 0 , 2 ) ) { # Allows for |---------------
+				$x = substr ( $x , 1 ) ;
+				while ( $x != '' && substr ( $x , 0 , 1 ) == '-' ) $x = substr ( $x , 1 ) ;
+				$z = '' ;
+				$l = array_pop ( $ltd ) ;
+				array_pop ( $has_opened_tr );
+				array_push ( $has_opened_tr , true ) ;
+				if ( array_pop ( $tr ) ) $z = '<nowiki></tr></nowiki>' . $z ;
+				if ( array_pop ( $td ) ) $z = '<nowiki></'.$l.'></nowiki>' . $z ;
+				array_pop ( $ltr ) ;
+				$t[$k] = $z ;
+				array_push ( $tr , false ) ;
+				array_push ( $td , false ) ;
+				array_push ( $ltd , '' ) ;
+				$attributes = unstripForHTML( $x );
+				array_push ( $ltr , fixTagAttributes( $attributes, 'tr' ) ) ;
+			}
+			else if ( '|' == $fc || '!' == $fc || '|+' == substr ( $x , 0 , 2 ) ) { # Caption
+				# $x is a table row
+				if ( '|+' == substr ( $x , 0 , 2 ) ) {
+					$fc = '+' ;
+					$x = substr ( $x , 1 ) ;
+				}
+				$after = substr ( $x , 1 ) ;
+				if ( $fc == '!' ) $after = str_replace ( '!!' , '||' , $after ) ;
+
+				// Split up multiple cells on the same line.
+				// FIXME: This can result in improper nesting of tags processed
+				// by earlier parser steps, but should avoid splitting up eg
+				// attribute values containing literal "||".
+				$after = wfExplodeMarkup( '||', $after );
+
+				$t[$k] = '' ;
+
+				# Loop through each table cell
+				foreach ( $after AS $theline )
+				{
+					$z = '' ;
+					if ( $fc != '+' )
+					{
+						$tra = array_pop ( $ltr ) ;
+						if ( !array_pop ( $tr ) ) $z = '<nowiki><tr'.$tra."></nowiki>\n" ;
+						array_push ( $tr , true ) ;
+						array_push ( $ltr , '' ) ;
+						array_pop ( $has_opened_tr );
+						array_push ( $has_opened_tr , true ) ;
+					}
+
+					$l = array_pop ( $ltd ) ;
+					if ( array_pop ( $td ) ) $z = '<nowiki></'.$l.'></nowiki>' . $z ;
+					if ( $fc == '|' ) $l = 'td' ;
+					else if ( $fc == '!' ) $l = 'th' ;
+					else if ( $fc == '+' ) $l = 'caption' ;
+					else $l = '' ;
+					array_push ( $ltd , $l ) ;
+
+					# Cell parameters
+					$y = explode ( '|' , $theline , 2 ) ;
+					# Note that a '|' inside an invalid link should not
+					# be mistaken as delimiting cell parameters
+					if ( strpos( $y[0], '[[' ) !== false ) {
+						$y = array ($theline);
+					}
+					if ( count ( $y ) == 1 )
+						$y = "{$z}<nowiki><{$l}></nowiki>{$y[0]}" ;
+					else {
+						$attributes = unstripForHTML( $y[0] );
+						$y = "{$z}<nowiki><{$l}".fixTagAttributes($attributes, $l)."></nowiki>{$y[1]}" ;
+					}
+					$t[$k] .= $y ;
+					array_push ( $td , true ) ;
+				}
+			}
+		}
+
+		# Closing open td, tr && table
+		while ( count ( $td ) > 0 )
+		{
+			$l = array_pop ( $ltd ) ;
+			if ( array_pop ( $td ) ) $t[] = '<nowiki></td></nowiki>' ;
+			if ( array_pop ( $tr ) ) $t[] = '<nowiki></tr></nowiki>' ;
+			if ( !array_pop ( $has_opened_tr ) ) $t[] = "<nowiki><tr><td></td></tr></nowiki>" ;
+			$t[] = '<nowiki></table></nowiki>' ;
+		}
+
+		$t = implode ( "\n" , $t ) ;
+    
+		# special case: don't return empty table
+		if($t == "<nowiki><table></nowiki>\n<nowiki><tr><td></td></tr></nowiki>\n<nowiki></table></nowiki>")
+			$t = '';
+		return $t ;
+	}
+  
+  /**
+	 * Take a tag soup fragment listing an HTML element's attributes
+	 * and normalize it to well-formed XML, discarding unwanted attributes.
+	 * Output is safe for further wikitext processing, with escaping of
+	 * values that could trigger problems.
+	 *
+	 * - Normalizes attribute names to lowercase
+	 * - Discards attributes not on a whitelist for the given element
+	 * - Turns broken or invalid entities into plaintext
+	 * - Double-quotes all attribute values
+	 * - Attributes without values are given the name as attribute
+	 * - Double attributes are discarded
+	 * - Unsafe style attributes are discarded
+	 * - Prepends space if there are attributes.
+	 *
+	 * @param string $text
+	 * @param string $element
+	 * @return string
+	 */
+	function fixTagAttributes( $text, $element ) {
+		if( trim( $text ) == '' ) {
+			return '';
+		}
+		
+		$stripped = validateTagAttributes(
+			decodeTagAttributes( $text ), $element );
+		
+		$attribs = array();
+		foreach( $stripped as $attribute => $value ) {
+			$encAttribute = htmlspecialchars( $attribute );
+			$encValue = safeEncodeAttribute( $value );
+			
+			$attribs[] = "$encAttribute=".'"'."$encValue".'"'.""; // "
+		}
+		return count( $attribs ) ? ' ' . implode( ' ', $attribs ) : '';
+	}
+  
+  /**
+	 * Encode an attribute value for HTML tags, with extra armoring
+	 * against further wiki processing.
+	 * @param $text
+	 * @return HTML-encoded text fragment
+	 */
+	function safeEncodeAttribute( $text ) {
+		$encValue= encodeAttribute( $text );
+		
+		# Templates and links may be expanded in later parsing,
+		# creating invalid or dangerous output. Suppress this.
+		$encValue = strtr( $encValue, array(
+			'<'    => '&lt;',   // This should never happen,
+			'>'    => '&gt;',   // we've received invalid input
+			'"'    => '&quot;', // which should have been escaped.
+			'{'    => '&#123;',
+			'['    => '&#91;',
+			"''"   => '&#39;&#39;',
+			'ISBN' => '&#73;SBN',
+			'RFC'  => '&#82;FC',
+			'PMID' => '&#80;MID',
+			'|'    => '&#124;',
+			'__'   => '&#95;_',
+		) );
+
+		return $encValue;
+	}
+  
+  /**
+	 * Encode an attribute value for HTML output.
+	 * @param $text
+	 * @return HTML-encoded text fragment
+	 */
+	function encodeAttribute( $text ) {
+		$encValue = htmlspecialchars( $text );
+		
+		// Whitespace is normalized during attribute decoding,
+		// so if we've been passed non-spaces we must encode them
+		// ahead of time or they won't be preserved.
+		$encValue = strtr( $encValue, array(
+			"\n" => '&#10;',
+			"\r" => '&#13;',
+			"\t" => '&#9;',
+		) );
+		
+		return $encValue;
+	}
+  
+  function unstripForHTML( $text ) {
+    global $mStripState;
+		$text = unstrip( $text, $mStripState );
+		$text = unstripNoWiki( $text, $mStripState );
+		return $text;
+	}
+  
+  /**
+	 * Always call this after unstrip() to preserve the order
+	 *
+	 * @private
+	 */
+	function unstripNoWiki( $text, &$state ) {
+		if ( !isset( $state['nowiki'] ) ) {
+			return $text;
+		}
+
+		# TODO: good candidate for FSS
+		$text = strtr( $text, $state['nowiki'] );
+		
+		return $text;
+	}
+  
+  /**
+	 * Take an array of attribute names and values and normalize or discard
+	 * illegal values for the given element type.
+	 *
+	 * - Discards attributes not on a whitelist for the given element
+	 * - Unsafe style attributes are discarded
+	 *
+	 * @param array $attribs
+	 * @param string $element
+	 * @return array
+	 *
+	 * @todo Check for legal values where the DTD limits things.
+	 * @todo Check for unique id attribute :P
+	 */
+	function validateTagAttributes( $attribs, $element ) {
+		$whitelist = array_flip( attributeWhitelist( $element ) );
+		$out = array();
+		foreach( $attribs as $attribute => $value ) {
+			if( !isset( $whitelist[$attribute] ) ) {
+				continue;
+			}
+			# Strip javascript "expression" from stylesheets.
+			# http://msdn.microsoft.com/workshop/author/dhtml/overview/recalc.asp
+			if( $attribute == 'style' ) {
+				$value = checkCss( $value );
+				if( $value === false ) {
+					# haxx0r
+					continue;
+				}
+			}
+
+			if ( $attribute === 'id' )
+				$value = escapeId( $value );
+
+			// If this attribute was previously set, override it.
+			// Output should only have one attribute of each name.
+			$out[$attribute] = $value;
+		}
+		return $out;
+	}
+  
+  /**
+	 * Pick apart some CSS and check it for forbidden or unsafe structures.
+	 * Returns a sanitized string, or false if it was just too evil.
+	 *
+	 * Currently URL references, 'expression', 'tps' are forbidden.
+	 *
+	 * @param string $value
+	 * @return mixed
+	 */
+	function checkCss( $value ) {
+		$stripped = decodeCharReferences( $value );
+
+		// Remove any comments; IE gets token splitting wrong
+		$stripped = preg_replace( '!/\\*.*?\\*/!S', '', $stripped );
+		$value = $stripped;
+
+		// ... and continue checks
+		$stripped = preg_replace( '!\\\\([0-9A-Fa-f]{1,6})[ \\n\\r\\t\\f]?!e',
+			'codepointToUtf8(hexdec("$1"))', $stripped );
+		$stripped = str_replace( '\\', '', $stripped );
+		if( preg_match( '/(expression|tps*:\/\/|url\\s*\().*/is',
+				$stripped ) ) {
+			# haxx0r
+			return false;
+		}
+		
+		return $value;
+	}
+  
+  /**
+	 * Decode any character references, numeric or named entities,
+	 * in the text and return a UTF-8 string.
+	 *
+	 * @param string $text
+	 * @return string
+	 * @access public
+	 * @static
+	 */
+	function decodeCharReferences( $text ) {
+		return preg_replace_callback(
+			MW_CHAR_REFS_REGEX,
+			'decodeCharReferencesCallback',
+			$text );
+	}
+  
+  /**
+	 * Fetch the whitelist of acceptable attributes for a given
+	 * element name.
+	 *
+	 * @param string $element
+	 * @return array
+	 */
+	function attributeWhitelist( $element ) {
+		static $list;
+		if( !isset( $list ) ) {
+			$list = setupAttributeWhitelist();
+		}
+		return isset( $list[$element] )
+			? $list[$element]
+			: array();
+	}
+  
+  /**
+	 * @todo Document it a bit
+	 * @return array
+	 */
+	function setupAttributeWhitelist() {
+		$common = array( 'id', 'class', 'lang', 'dir', 'title', 'style' );
+		$block = array_merge( $common, array( 'align' ) );
+		$tablealign = array( 'align', 'char', 'charoff', 'valign' );
+		$tablecell = array( 'abbr',
+		                    'axis',
+		                    'headers',
+		                    'scope',
+		                    'rowspan',
+		                    'colspan',
+		                    'nowrap', # deprecated
+		                    'width',  # deprecated
+		                    'height', # deprecated
+		                    'bgcolor' # deprecated
+		                    );
+
+		# Numbers refer to sections in HTML 4.01 standard describing the element.
+		# See: http://www.w3.org/TR/html4/
+		$whitelist = array (
+			# 7.5.4
+			'div'        => $block,
+			'center'     => $common, # deprecated
+			'span'       => $block, # ??
+
+			# 7.5.5
+			'h1'         => $block,
+			'h2'         => $block,
+			'h3'         => $block,
+			'h4'         => $block,
+			'h5'         => $block,
+			'h6'         => $block,
+
+			# 7.5.6
+			# address
+
+			# 8.2.4
+			# bdo
+
+			# 9.2.1
+			'em'         => $common,
+			'strong'     => $common,
+			'cite'       => $common,
+			# dfn
+			'code'       => $common,
+			# samp
+			# kbd
+			'var'        => $common,
+			# abbr
+			# acronym
+
+			# 9.2.2
+			'blockquote' => array_merge( $common, array( 'cite' ) ),
+			# q
+
+			# 9.2.3
+			'sub'        => $common,
+			'sup'        => $common,
+
+			# 9.3.1
+			'p'          => $block,
+
+			# 9.3.2
+			'br'         => array( 'id', 'class', 'title', 'style', 'clear' ),
+
+			# 9.3.4
+			'pre'        => array_merge( $common, array( 'width' ) ),
+
+			# 9.4
+			'ins'        => array_merge( $common, array( 'cite', 'datetime' ) ),
+			'del'        => array_merge( $common, array( 'cite', 'datetime' ) ),
+
+			# 10.2
+			'ul'         => array_merge( $common, array( 'type' ) ),
+			'ol'         => array_merge( $common, array( 'type', 'start' ) ),
+			'li'         => array_merge( $common, array( 'type', 'value' ) ),
+
+			# 10.3
+			'dl'         => $common,
+			'dd'         => $common,
+			'dt'         => $common,
+
+			# 11.2.1
+			'table'      => array_merge( $common,
+								array( 'summary', 'width', 'border', 'frame',
+										'rules', 'cellspacing', 'cellpadding',
+										'align', 'bgcolor',
+								) ),
+
+			# 11.2.2
+			'caption'    => array_merge( $common, array( 'align' ) ),
+
+			# 11.2.3
+			'thead'      => array_merge( $common, $tablealign ),
+			'tfoot'      => array_merge( $common, $tablealign ),
+			'tbody'      => array_merge( $common, $tablealign ),
+
+			# 11.2.4
+			'colgroup'   => array_merge( $common, array( 'span', 'width' ), $tablealign ),
+			'col'        => array_merge( $common, array( 'span', 'width' ), $tablealign ),
+
+			# 11.2.5
+			'tr'         => array_merge( $common, array( 'bgcolor' ), $tablealign ),
+
+			# 11.2.6
+			'td'         => array_merge( $common, $tablecell, $tablealign ),
+			'th'         => array_merge( $common, $tablecell, $tablealign ),
+      
+      # 12.2
+      # added by dan
+      'a'          => array_merge( $common, array( 'href', 'name' ) ),
+      
+      # 13.2
+      # added by dan
+      'img'        => array_merge( $common, array( 'src', 'width', 'height', 'alt' ) ),
+
+			# 15.2.1
+			'tt'         => $common,
+			'b'          => $common,
+			'i'          => $common,
+			'big'        => $common,
+			'small'      => $common,
+			'strike'     => $common,
+			's'          => $common,
+			'u'          => $common,
+
+			# 15.2.2
+			'font'       => array_merge( $common, array( 'size', 'color', 'face' ) ),
+			# basefont
+
+			# 15.3
+			'hr'         => array_merge( $common, array( 'noshade', 'size', 'width' ) ),
+
+			# XHTML Ruby annotation text module, simple ruby only.
+			# http://www.w3c.org/TR/ruby/
+			'ruby'       => $common,
+			# rbc
+			# rtc
+			'rb'         => $common,
+			'rt'         => $common, #array_merge( $common, array( 'rbspan' ) ),
+			'rp'         => $common,
+      
+      # For compatibility with the XHTML parser.
+      'nowiki'     => array(),
+      'noinclude'  => array(),
+      'nodisplay'  => array(),
+      
+      # XHTML stuff
+      'acronym'    => $common
+			);
+		return $whitelist;
+	}
+  
+  /**
+	 * Given a value escape it so that it can be used in an id attribute and
+	 * return it, this does not validate the value however (see first link)
+	 *
+	 * @link http://www.w3.org/TR/html401/types.html#type-name Valid characters
+	 *                                                          in the id and
+	 *                                                          name attributes
+	 * @link http://www.w3.org/TR/html401/struct/links.html#h-12.2.3 Anchors with the id attribute
+	 *
+	 * @bug 4461
+	 *
+	 * @static
+	 *
+	 * @param string $id
+	 * @return string
+	 */
+	function escapeId( $id ) {
+		static $replace = array(
+			'%3A' => ':',
+			'%' => '.'
+		);
+
+		$id = urlencode( decodeCharReferences( strtr( $id, ' ', '_' ) ) );
+
+		return str_replace( array_keys( $replace ), array_values( $replace ), $id );
+	}
+  
+  /**
+   * More or less "markup-safe" explode()
+   * Ignores any instances of the separator inside <...>
+   * @param string $separator
+   * @param string $text
+   * @return array
+   */
+  function wfExplodeMarkup( $separator, $text ) {
+    $placeholder = "\x00";
+    
+    // Just in case...
+    $text = str_replace( $placeholder, '', $text );
+    
+    // Trim stuff
+    $replacer = new ReplacerCallback( $separator, $placeholder );
+    $cleaned = preg_replace_callback( '/(<.*?>)/', array( $replacer, 'go' ), $text );
+    
+    $items = explode( $separator, $cleaned );
+    foreach( $items as $i => $str ) {
+      $items[$i] = str_replace( $placeholder, $separator, $str );
+    }
+    
+    return $items;
+  }
+  
+  class ReplacerCallback {
+    function ReplacerCallback( $from, $to ) {
+      $this->from = $from;
+      $this->to = $to;
+    }
+    
+    function go( $matches ) {
+      return str_replace( $this->from, $this->to, $matches[1] );
+    }
+  }
+  
+  /**
+	 * Return an associative array of attribute names and values from
+	 * a partial tag string. Attribute names are forces to lowercase,
+	 * character references are decoded to UTF-8 text.
+	 *
+	 * @param string
+	 * @return array
+	 */
+	function decodeTagAttributes( $text ) {
+		$attribs = array();
+
+		if( trim( $text ) == '' ) {
+			return $attribs;
+		}
+
+		$pairs = array();
+		if( !preg_match_all(
+			MW_ATTRIBS_REGEX,
+			$text,
+			$pairs,
+			PREG_SET_ORDER ) ) {
+			return $attribs;
+		}
+
+		foreach( $pairs as $set ) {
+			$attribute = strtolower( $set[1] );
+			$value = getTagAttributeCallback( $set );
+			
+			// Normalize whitespace
+			$value = preg_replace( '/[\t\r\n ]+/', ' ', $value );
+			$value = trim( $value );
+			
+			// Decode character references
+			$attribs[$attribute] = decodeCharReferences( $value );
+		}
+		return $attribs;
+	}
+  
+  /**
+	 * Pick the appropriate attribute value from a match set from the
+	 * MW_ATTRIBS_REGEX matches.
+	 *
+	 * @param array $set
+	 * @return string
+	 * @access private
+	 */
+	function getTagAttributeCallback( $set ) {
+		if( isset( $set[6] ) ) {
+			# Illegal #XXXXXX color with no quotes.
+			return $set[6];
+		} elseif( isset( $set[5] ) ) {
+			# No quotes.
+			return $set[5];
+		} elseif( isset( $set[4] ) ) {
+			# Single-quoted
+			return $set[4];
+		} elseif( isset( $set[3] ) ) {
+			# Double-quoted
+			return $set[3];
+		} elseif( !isset( $set[2] ) ) {
+			# In XHTML, attributes must have a value.
+			# For 'reduced' form, return explicitly the attribute name here.
+			return $set[1];
+		} else {
+			die_friendly('Parser error', "<p>Tag conditions not met. This should never happen and is a bug.</p>" );
+		}
+	}
+  
+  /**
+	 * Strips and renders nowiki, pre, math, hiero
+	 * If $render is set, performs necessary rendering operations on plugins
+	 * Returns the text, and fills an array with data needed in unstrip()
+	 * If the $state is already a valid strip state, it adds to the state
+	 *
+	 * @param bool $stripcomments when set, HTML comments <!-- like this -->
+	 *  will be stripped in addition to other tags. This is important
+	 *  for section editing, where these comments cause confusion when
+	 *  counting the sections in the wikisource
+	 * 
+	 * @param array dontstrip contains tags which should not be stripped;
+	 *  used to prevent stipping of <gallery> when saving (fixes bug 2700)
+	 *
+	 * @access private
+	 */
+	function mwStrip( $text, &$state, $stripcomments = false , $dontstrip = array () ) {
+    global $wgRandomKey;
+		$render = true;
+
+		$wgRandomKey = "\x07UNIQ" . dechex(mt_rand(0, 0x7fffffff)) . dechex(mt_rand(0, 0x7fffffff));
+    $uniq_prefix =& $wgRandomKey;
+		$commentState = array();
+		
+		$elements = array( 'nowiki', 'gallery' );
+		
+    # Removing $dontstrip tags from $elements list (currently only 'gallery', fixing bug 2700)
+		foreach ( $elements AS $k => $v ) {
+			if ( !in_array ( $v , $dontstrip ) ) continue;
+			unset ( $elements[$k] );
+		}
+		
+		$matches = array();
+		$text = extractTagsAndParams( $elements, $text, $matches, $uniq_prefix );
+
+		foreach( $matches as $marker => $data ) {
+			list( $element, $content, $params, $tag ) = $data;
+			if( $render ) {
+				$tagName = strtolower( $element );
+				switch( $tagName ) {
+				case '!--':
+					// Comment
+					if( substr( $tag, -3 ) == '-->' ) {
+						$output = $tag;
+					} else {
+						// Unclosed comment in input.
+						// Close it so later stripping can remove it
+						$output = "$tag-->";
+					}
+					break;
+				case 'html':
+					if( $wgRawHtml ) {
+						$output = $content;
+						break;
+					}
+					// Shouldn't happen otherwise. :)
+				case 'nowiki':
+					$output = wfEscapeHTMLTagsOnly( $content );
+					break;
+				default:
+				}
+			} else {
+				// Just stripping tags; keep the source
+				$output = $tag;
+			}
+
+			// Unstrip the output, because unstrip() is no longer recursive so 
+			// it won't do it itself
+			$output = unstrip( $output, $state );
+
+			if( !$stripcomments && $element == '!--' ) {
+				$commentState[$marker] = $output;
+			} elseif ( $element == 'html' || $element == 'nowiki' ) {
+				$state['nowiki'][$marker] = $output;
+			} else {
+				$state['general'][$marker] = $output;
+			}
+		}
+
+		# Unstrip comments unless explicitly told otherwise.
+		# (The comments are always stripped prior to this point, so as to
+		# not invoke any extension tags / parser hooks contained within
+		# a comment.)
+		if ( !$stripcomments ) {
+			// Put them all back and forget them
+			$text = strtr( $text, $commentState );
+		}
+
+		return $text;
+	}
+  
+  /**
+	 * Replaces all occurrences of HTML-style comments and the given tags
+	 * in the text with a random marker and returns teh next text. The output
+	 * parameter $matches will be an associative array filled with data in
+	 * the form:
+	 *   'UNIQ-xxxxx' => array(
+	 *     'element',
+	 *     'tag content',
+	 *     array( 'param' => 'x' ),
+	 *     '<element param="x">tag content</element>' ) )
+	 *
+	 * @param $elements list of element names. Comments are always extracted.
+	 * @param $text Source text string.
+	 * @param $uniq_prefix
+	 *
+	 * @access private
+	 * @static
+	 */
+	function extractTagsAndParams($elements, $text, &$matches, $uniq_prefix = ''){
+		static $n = 1;
+		$stripped = '';
+		$matches = array();
+
+		$taglist = implode( '|', $elements );
+		$start = "/<($taglist)(\\s+[^>]*?|\\s*?)(\/?>)|<(!--)/i";
+
+		while ( '' != $text ) {
+			$p = preg_split( $start, $text, 2, PREG_SPLIT_DELIM_CAPTURE );
+			$stripped .= $p[0];
+			if( count( $p ) < 5 ) {
+				break;
+			}
+			if( count( $p ) > 5 ) {
+				// comment
+				$element    = $p[4];
+				$attributes = '';
+				$close      = '';
+				$inside     = $p[5];
+			} else {
+				// tag
+				$element    = $p[1];
+				$attributes = $p[2];
+				$close      = $p[3];
+				$inside     = $p[4];
+			}
+
+			$marker = "$uniq_prefix-$element-" . sprintf('%08X', $n++) . '-QINU';
+			$stripped .= $marker;
+
+			if ( $close === '/>' ) {
+				// Empty element tag, <tag />
+				$content = null;
+				$text = $inside;
+				$tail = null;
+			} else {
+				if( $element == '!--' ) {
+					$end = '/(-->)/';
+				} else {
+					$end = "/(<\\/$element\\s*>)/i";
+				}
+				$q = preg_split( $end, $inside, 2, PREG_SPLIT_DELIM_CAPTURE );
+				$content = $q[0];
+				if( count( $q ) < 3 ) {
+					# No end tag -- let it run out to the end of the text.
+					$tail = '';
+					$text = '';
+				} else {
+					$tail = $q[1];
+					$text = $q[2];
+				}
+			}
+			
+			$matches[$marker] = array( $element,
+				$content,
+				decodeTagAttributes( $attributes ),
+				"<$element$attributes$close$content$tail" );
+		}
+		return $stripped;
+	}
+  
+  /**
+   * Escape html tags
+   * Basically replacing " > and < with HTML entities ( &quot;, &gt;, &lt;)
+   *
+   * @param $in String: text that might contain HTML tags.
+   * @return string Escaped string
+   */
+  function wfEscapeHTMLTagsOnly( $in ) {
+    return str_replace(
+      array( '"', '>', '<' ),
+      array( '&quot;', '&gt;', '&lt;' ),
+      $in );
+  }
+  
+  /**
+	 * Restores pre, math, and other extensions removed by strip()
+	 *
+	 * always call unstripNoWiki() after this one
+	 * @private
+	 */
+	function unstrip( $text, &$state ) {
+		if ( !isset( $state['general'] ) ) {
+			return $text;
+		}
+
+		# TODO: good candidate for FSS
+		$text = strtr( $text, $state['general'] );
+    
+		return $text;
+	}
+  
+  /**
+	 * Return UTF-8 string for a codepoint if that is a valid
+	 * character reference, otherwise U+FFFD REPLACEMENT CHARACTER.
+	 * @param int $codepoint
+	 * @return string
+	 * @private
+	 */
+	function decodeChar( $codepoint ) {
+		if( validateCodepoint( $codepoint ) ) {
+			return codepointToUtf8( $codepoint );
+		} else {
+			return UTF8_REPLACEMENT;
+		}
+	}
+
+	/**
+	 * If the named entity is defined in the HTML 4.0/XHTML 1.0 DTD,
+	 * return the UTF-8 encoding of that character. Otherwise, returns
+	 * pseudo-entity source (eg &foo;)
+	 *
+	 * @param string $name
+	 * @return string
+	 */
+	function decodeEntity( $name ) {
+		global $wgHtmlEntities;
+		if( isset( $wgHtmlEntities[$name] ) ) {
+			return codepointToUtf8( $wgHtmlEntities[$name] );
+		} else {
+			return "&$name;";
+		}
+	}
+  
+  /**
+	 * Returns true if a given Unicode codepoint is a valid character in XML.
+	 * @param int $codepoint
+	 * @return bool
+	 */
+	function validateCodepoint( $codepoint ) {
+		return ($codepoint ==    0x09)
+			|| ($codepoint ==    0x0a)
+			|| ($codepoint ==    0x0d)
+			|| ($codepoint >=    0x20 && $codepoint <=   0xd7ff)
+			|| ($codepoint >=  0xe000 && $codepoint <=   0xfffd)
+			|| ($codepoint >= 0x10000 && $codepoint <= 0x10ffff);
+	}
+  
+/**
+ * Return UTF-8 sequence for a given Unicode code point.
+ * May die if fed out of range data.
+ *
+ * @param $codepoint Integer:
+ * @return String
+ * @public
+ */
+function codepointToUtf8( $codepoint ) {
+	if($codepoint <		0x80) return chr($codepoint);
+	if($codepoint <    0x800) return chr($codepoint >>	6 & 0x3f | 0xc0) .
+									 chr($codepoint		  & 0x3f | 0x80);
+	if($codepoint <  0x10000) return chr($codepoint >> 12 & 0x0f | 0xe0) .
+									 chr($codepoint >>	6 & 0x3f | 0x80) .
+									 chr($codepoint		  & 0x3f | 0x80);
+	if($codepoint < 0x110000) return chr($codepoint >> 18 & 0x07 | 0xf0) .
+									 chr($codepoint >> 12 & 0x3f | 0x80) .
+									 chr($codepoint >>	6 & 0x3f | 0x80) .
+									 chr($codepoint		  & 0x3f | 0x80);
+
+	echo "Asked for code outside of range ($codepoint)\n";
+	die( -1 );
+}
+
+  /**
+	 * @param string $matches
+	 * @return string
+	 */
+	function decodeCharReferencesCallback( $matches ) {
+		if( $matches[1] != '' ) {
+			return Sanitizer::decodeEntity( $matches[1] );
+		} elseif( $matches[2] != '' ) {
+			return  Sanitizer::decodeChar( intval( $matches[2] ) );
+		} elseif( $matches[3] != ''  ) {
+			return  Sanitizer::decodeChar( hexdec( $matches[3] ) );
+		} elseif( $matches[4] != '' ) {
+			return  Sanitizer::decodeChar( hexdec( $matches[4] ) );
+		}
+		# Last case should be an ampersand by itself
+		return $matches[0];
+	}
+  
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/wikiformat.php	Wed Jun 13 16:07:17 2007 -0400
@@ -0,0 +1,615 @@
+<?php
+/**
+ * Parse structured wiki text and render into arbitrary formats such as XHTML.
+ *
+ * PHP versions 4 and 5
+ *
+ * @category   Text
+ * @package    Text_Wiki
+ * @author     Paul M. Jones <pmjones@php.net>
+ * @license    http://www.gnu.org/licenses/lgpl.html
+ * @version    CVS: $Id: Wiki.php,v 1.44 2006/03/02 04:04:59 justinpatrin Exp $
+ * @link       http://wiki.ciaweb.net/yawiki/index.php?area=Text_Wiki
+ *
+ * This code was modified for use in Enano. The Text_Wiki engine is licensed
+ * under the GNU Lesser General Public License; see
+ * http://www.gnu.org/licenses/lgpl.html for details.
+ *
+ */
+
+require_once ENANO_ROOT.'/includes/wikiengine/Parse.php';
+require_once ENANO_ROOT.'/includes/wikiengine/Render.php';
+
+class Text_Wiki {
+
+  var $rules = array(
+        'Prefilter',
+        'Delimiter',
+        'Code',
+        'Function',
+        'Html',
+        'Raw',
+        'Include',
+        'Embed',
+        'Anchor',
+        'Heading',
+        'Toc',
+        'Horiz',
+        'Break',
+        'Blockquote',
+        'List',
+        'Deflist',
+        'Table',
+        'Image',
+        'Phplookup',
+        'Center',
+        'Newline',
+        'Paragraph',
+        'Url',
+        'Freelink',
+        'Interwiki',
+        'Wikilink',
+        'Colortext',
+        'Strong',
+        'Bold',
+        'Emphasis',
+        'Italic',
+        'Underline',
+        'Tt',
+        'Superscript',
+        'Subscript',
+        'Revise',
+        'Tighten'
+    );
+
+    var $disable = array(
+        'Html',
+        'Include',
+        'Embed'
+    );
+
+    var $parseConf = array();
+
+    var $renderConf = array(
+        'Docbook' => array(),
+        'Latex' => array(),
+        'Pdf' => array(),
+        'Plain' => array(),
+        'Rtf' => array(),
+        'Xhtml' => array()
+    );
+
+    var $formatConf = array(
+        'Docbook' => array(),
+        'Latex' => array(),
+        'Pdf' => array(),
+        'Plain' => array(),
+        'Rtf' => array(),
+        'Xhtml' => array()
+    );
+    var $delim = "\xFF";
+    var $tokens = array();
+    var $_countRulesTokens = array();
+    var $source = '';
+    var $parseObj = array();
+    var $renderObj = array();
+    var $formatObj = array();
+    var $path = array(
+        'parse' => array(),
+        'render' => array()
+    );
+    var $_dirSep = DIRECTORY_SEPARATOR;
+    function Text_Wiki($rules = null)
+    {
+        if (is_array($rules)) {
+            $this->rules = $rules;
+        }
+
+        $this->addPath(
+            'parse',
+            $this->fixPath(ENANO_ROOT) . 'includes/wikiengine/Parse/Default/'
+        );
+        $this->addPath(
+            'render',
+            $this->fixPath(ENANO_ROOT) . 'includes/wikiengine/Render/'
+        );
+
+    }
+
+    function &singleton($parser = 'Default', $rules = null)
+    {
+        static $only = array();
+        if (!isset($only[$parser])) {
+            $ret =& Text_Wiki::factory($parser, $rules);
+            if (!$ret) {
+                return $ret;
+            }
+            $only[$parser] =& $ret;
+        }
+        return $only[$parser];
+    }
+
+    function &factory($parser = 'Default', $rules = null)
+    {
+        $d=getcwd();
+        chdir(ENANO_ROOT);
+        
+        $class = 'Text_Wiki_' . $parser;
+        $c2 = '._includes_wikiengine_' . $parser;
+        $file = str_replace('_', '/', $c2).'.php';
+        if (!class_exists($class)) {
+            $fp = @fopen($file, 'r', true);
+            if ($fp === false) {
+                die_semicritical('Wiki formatting engine error', '<p>Could not find file '.$file.' in include_path</p>');
+            }
+            fclose($fp);
+            include_once($file);
+            if (!class_exists($class)) {
+                die_semicritical('Wiki formatting engine error', '<p>Class '.$class.' does not exist after including '.$file.'</p>');
+            }
+        }
+        
+        chdir($d);
+
+        $obj =& new $class($rules);
+        return $obj;
+    }
+
+    function setParseConf($rule, $arg1, $arg2 = null)
+    {
+        $rule = ucwords(strtolower($rule));
+
+        if (! isset($this->parseConf[$rule])) {
+            $this->parseConf[$rule] = array();
+        }
+
+                                if (is_array($arg1)) {
+            $this->parseConf[$rule] = $arg1;
+        } else {
+            $this->parseConf[$rule][$arg1] = $arg2;
+        }
+    }
+
+    function getParseConf($rule, $key = null)
+    {
+        $rule = ucwords(strtolower($rule));
+
+                if (! isset($this->parseConf[$rule])) {
+            return null;
+        }
+
+                if (is_null($key)) {
+            return $this->parseConf[$rule];
+        }
+
+                if (isset($this->parseConf[$rule][$key])) {
+                        return $this->parseConf[$rule][$key];
+        } else {
+                        return null;
+        }
+    }
+
+    function setRenderConf($format, $rule, $arg1, $arg2 = null)
+    {
+        $format = ucwords(strtolower($format));
+        $rule = ucwords(strtolower($rule));
+
+        if (! isset($this->renderConf[$format])) {
+            $this->renderConf[$format] = array();
+        }
+
+        if (! isset($this->renderConf[$format][$rule])) {
+            $this->renderConf[$format][$rule] = array();
+        }
+
+                                if (is_array($arg1)) {
+            $this->renderConf[$format][$rule] = $arg1;
+        } else {
+            $this->renderConf[$format][$rule][$arg1] = $arg2;
+        }
+    }
+
+    function getRenderConf($format, $rule, $key = null)
+    {
+        $format = ucwords(strtolower($format));
+        $rule = ucwords(strtolower($rule));
+
+        if (! isset($this->renderConf[$format]) ||
+            ! isset($this->renderConf[$format][$rule])) {
+          return null;
+        }
+
+        if (is_null($key)) {
+          return $this->renderConf[$format][$rule];
+        }
+
+        if (isset($this->renderConf[$format][$rule][$key])) {
+          return $this->renderConf[$format][$rule][$key];
+        } else {
+          return null;
+        }
+
+    }
+
+    function setFormatConf($format, $arg1, $arg2 = null)
+    {
+      if (! is_array($this->formatConf[$format])) {
+        $this->formatConf[$format] = array();
+      }
+
+      if (is_array($arg1)) {
+        $this->formatConf[$format] = $arg1;
+      } else {
+        $this->formatConf[$format][$arg1] = $arg2;
+      }
+    }
+
+    function getFormatConf($format, $key = null)
+    {
+      if (! isset($this->formatConf[$format])) {
+        return null;
+      }
+
+      if (is_null($key)) {
+        return $this->formatConf[$format];
+      }
+
+      if (isset($this->formatConf[$format][$key])) {
+        return $this->formatConf[$format][$key];
+      } else {
+        return null;
+      }
+    }
+
+    function insertRule($name, $tgt = null)
+    {
+      $name = ucwords(strtolower($name));
+      if (! is_null($tgt)) {
+        $tgt = ucwords(strtolower($tgt));
+      }
+      if (in_array($name, $this->rules)) {
+        return null;
+      }
+
+      if (! is_null($tgt) && $tgt != '' &&
+        ! in_array($tgt, $this->rules)) {
+        return false;
+      }
+
+      if (is_null($tgt)) {
+        $this->rules[] = $name;
+        return true;
+      }
+
+      if ($tgt == '') {
+        array_unshift($this->rules, $name);
+        return true;
+      }
+
+      $tmp = $this->rules;
+      $this->rules = array();
+
+      foreach ($tmp as $val) {
+        $this->rules[] = $val;
+        if ($val == $tgt) {
+          $this->rules[] = $name;
+        }
+      }
+
+      return true;
+    }
+
+    function deleteRule($name)
+    {
+      $name = ucwords(strtolower($name));
+      $key = array_search($name, $this->rules);
+      if ($key !== false) {
+        unset($this->rules[$key]);
+      }
+    }
+
+    function changeRule($old, $new)
+    {
+      $old = ucwords(strtolower($old));
+      $new = ucwords(strtolower($new));
+      $key = array_search($old, $this->rules);
+      if ($key !== false) {
+        $this->deleteRule($new);
+        $this->rules[$key] = $new;
+      }
+    }
+
+    function enableRule($name)
+    {
+      $name = ucwords(strtolower($name));
+      $key = array_search($name, $this->disable);
+      if ($key !== false) {
+        unset($this->disable[$key]);
+      }
+    }
+
+    function disableRule($name)
+    {
+      $name = ucwords(strtolower($name));
+      $key = array_search($name, $this->disable);
+      if ($key === false) {
+        $this->disable[] = $name;
+      }
+    }
+
+    function transform($text, $format = 'Xhtml')
+    {
+      $this->parse($text);
+      return $this->render($format);
+    }
+
+    function parse($text)
+    {
+      $this->source = $text;
+
+      $this->tokens = array();
+      $this->_countRulesTokens = array();
+
+      foreach ($this->rules as $name) {
+        if (! in_array($name, $this->disable)) {
+          $this->loadParseObj($name);
+
+          if (is_object($this->parseObj[$name])) {
+            $this->parseObj[$name]->parse();
+          }
+        }
+      }
+    }
+
+    function render($format = 'Xhtml')
+    {
+      $format = ucwords(strtolower($format));
+
+      $output = '';
+
+      $in_delim = false;
+
+      $key = '';
+
+      $result = $this->loadFormatObj($format);
+      if ($this->isError($result)) {
+        return $result;
+      }
+
+      if (is_object($this->formatObj[$format])) {
+        $output .= $this->formatObj[$format]->pre();
+      }
+
+      foreach (array_keys($this->_countRulesTokens) as $rule) {
+        $this->loadRenderObj($format, $rule);
+      }
+
+      $k = strlen($this->source);
+      for ($i = 0; $i < $k; $i++) {
+
+        $char = $this->source{$i};
+
+        if ($in_delim) {
+
+          if ($char == $this->delim) {
+
+            $key = (int)$key;
+            $rule = $this->tokens[$key][0];
+            $opts = $this->tokens[$key][1];
+            $output .= $this->renderObj[$rule]->token($opts);
+            $in_delim = false;
+
+          } else {
+
+            $key .= $char;
+
+          }
+
+        } else {
+
+          if ($char == $this->delim) {
+            $key = '';
+            $in_delim = true;
+          } else {
+            $output .= $char;
+          }
+        }
+      }
+
+      if (is_object($this->formatObj[$format])) {
+        $output .= $this->formatObj[$format]->post();
+      }
+
+      return $output;
+    }
+
+    function getSource()
+    {
+      return $this->source;
+    }
+
+    function getTokens($rules = null)
+    {
+        if (is_null($rules)) {
+            return $this->tokens;
+        } else {
+            settype($rules, 'array');
+            $result = array();
+            foreach ($this->tokens as $key => $val) {
+                if (in_array($val[0], $rules)) {
+                    $result[$key] = $val;
+                }
+            }
+            return $result;
+        }
+    }
+
+    function addToken($rule, $options = array(), $id_only = false)
+    {
+                                static $id;
+        if (! isset($id)) {
+            $id = 0;
+        } else {
+            $id ++;
+        }
+
+                settype($options, 'array');
+
+                $this->tokens[$id] = array(
+            0 => $rule,
+            1 => $options
+        );
+        if (!isset($this->_countRulesTokens[$rule])) {
+            $this->_countRulesTokens[$rule] = 1;
+        } else {
+            ++$this->_countRulesTokens[$rule];
+        }
+
+                if ($id_only) {
+                        return $id;
+        } else {
+                        return $this->delim . $id . $this->delim;
+        }
+    }
+
+    function setToken($id, $rule, $options = array())
+    {
+        $oldRule = $this->tokens[$id][0];
+                $this->tokens[$id] = array(
+            0 => $rule,
+            1 => $options
+        );
+        if ($rule != $oldRule) {
+            if (!($this->_countRulesTokens[$oldRule]--)) {
+                unset($this->_countRulesTokens[$oldRule]);
+            }
+            if (!isset($this->_countRulesTokens[$rule])) {
+                $this->_countRulesTokens[$rule] = 1;
+            } else {
+                ++$this->_countRulesTokens[$rule];
+            }
+        }
+    }
+
+    function loadParseObj($rule)
+    {
+        $rule = ucwords(strtolower($rule));
+        $file = $rule . '.php';
+        $class = "Text_Wiki_Parse_$rule";
+
+        if (! class_exists($class)) {
+            $loc = $this->findFile('parse', $file);
+            if ($loc) {
+                                include_once $loc;
+            } else {
+                                $this->parseObj[$rule] = null;
+                                return $this->error(
+                    "Parse rule '$rule' not found"
+                );
+            }
+        }
+
+        $this->parseObj[$rule] =& new $class($this);
+
+    }
+
+    function loadRenderObj($format, $rule)
+    {
+        $format = ucwords(strtolower($format));
+        $rule = ucwords(strtolower($rule));
+        $file = "$format/$rule.php";
+        $class = "Text_Wiki_Render_$format" . "_$rule";
+
+        if (! class_exists($class)) {
+                        $loc = $this->findFile('render', $file);
+            if ($loc) {
+                                include_once $loc;
+            } else {
+                return $this->error(
+                    "Render rule '$rule' in format '$format' not found"
+                );
+            }
+        }
+
+        $this->renderObj[$rule] =& new $class($this);
+    }
+
+    function loadFormatObj($format)
+    {
+        $format = ucwords(strtolower($format));
+        $file = $format . '.php';
+        $class = "Text_Wiki_Render_$format";
+
+        if (! class_exists($class)) {
+            $loc = $this->findFile('render', $file);
+            if ($loc) {
+                include_once $loc;
+            } else {
+                return $this->error(
+                    "Rendering format class '$class' not found"
+                );
+            }
+        }
+
+        $this->formatObj[$format] =& new $class($this);
+    }
+
+    function addPath($type, $dir)
+    {
+        $dir = $this->fixPath($dir);
+        if (! isset($this->path[$type])) {
+            $this->path[$type] = array($dir);
+        } else {
+            array_unshift($this->path[$type], $dir);
+        }
+    }
+
+    function getPath($type = null)
+    {
+        if (is_null($type)) {
+            return $this->path;
+        } elseif (! isset($this->path[$type])) {
+            return array();
+        } else {
+            return $this->path[$type];
+        }
+    }
+
+    function findFile($type, $file)
+    {
+      $set = $this->getPath($type);
+
+      foreach ($set as $path) {
+            $fullname = $path . $file;
+            if (file_exists($fullname) && is_readable($fullname)) {
+                return $fullname;
+            }
+        }
+
+      return false;
+    }
+
+    function fixPath($path)
+    {
+        $len = strlen($this->_dirSep);
+
+        if (! empty($path) &&
+            substr($path, -1 * $len, $len) != $this->_dirSep)    {
+            return $path . $this->_dirSep;
+        } else {
+            return $path;
+        }
+    }
+
+    function &error($message)
+    {
+        die($message);
+    }
+
+    function isError(&$obj)
+    {
+        return is_a($obj, 'PEAR_Error');
+    }
+}
+
+?>